Colour vs fill
aesthetic
Fill and colour scales in ggplot2 can use the same palettes. Some
shapes such as lines only accept the colour
aesthetic,
while others, such as polygons, accept both colour
and
fill
aesthetics. In the latter case, the
colour
refers to the border of the shape, and the
fill
to the interior.
All symbols have a foreground colour, so if we add
color = "navy"
, they all are affected.
s + geom_point(aes(shape = z), size = 4, colour = "navy")
While all symbols have a foreground colour, symbols 21-25 also take a
background colour (fill). So if we add fill = "orchid"
,
only the last row of symbols are affected.
s + geom_point(aes(shape = z), size = 4, colour = "navy", fill = "orchid")
Data
For the rest of today, we’ll play with the sounds
dataset. This data was derived from the R package wordbankr
,
an R interface to access Wordbank- an open source
database of children’s vocabulary development. The tool used to measure
children’s language and communicative development in this database is
the MacArthur-Bates Communicative
Development Inventories (MB-CDI). The MD-CDI is a parent-reported
questionnaire.
Here is a glimpse of the data:
glimpse(sounds)
Rows: 33
Columns: 7
$ age <dbl> 8, 8, 8, 9, 9, 9, 10, 10, 10, 11, 11, 11, 12, 12, 12, …
$ sound <chr> "cockadoodledoo", "meow", "woof woof", "cockadoodledoo…
$ kids_produce <dbl> 1, 0, 3, 0, 2, 2, 0, 5, 4, 0, 5, 12, 0, 12, 28, 9, 125…
$ kids_understand <dbl> 3, 10, 12, 2, 21, 22, 9, 41, 40, 4, 36, 32, 16, 59, 59…
$ kids_respond <dbl> 35, 35, 35, 91, 93, 93, 139, 145, 143, 94, 94, 94, 141…
$ prop_produce <dbl> 0.02857143, 0.00000000, 0.08571429, 0.00000000, 0.0215…
$ prop_understand <dbl> 0.08571429, 0.28571429, 0.34285714, 0.02197802, 0.2258…
Note that the unit of observation here is
one-row-per-age-group/animal sound.
Variables you need for this lab:
age
: child age in months
sound
: a string describing a type of animal sound
kids_produce
: the number of parents who answered “yes,
my child produces this animal sound” (note that if the child produces a
sound it is assumed that they understand it as well)
kids_respond
: the number of parents who responded to
this question at all
prop_produce
: the proportion of kids whose parents
endorsed that their child produces this animal sound, out of all
questionnaires administered (i.e.,
kids_produce / kids_respond
)
Other variables in this dataset:
kids_understand
: the number of parents who answered
“yes, my child understands what this animal sound means” (note that a
child can understand the sound but not produce it)
prop_understand
: the proportion of kids whose parents
endorsed that their child understands this animal sound, out of all
questionnaires administered (i.e.,
kids_understand / kids_respond
)
Know your data
Challenge #1:
How many variables?
- Which variables are continuous?
- Which ones are categorical or ordinal?
How many total kids do we have data for?
How many ages (in months)?
How many types of animal sounds? What are they?
Let’s start just by getting a feel for how many kids produce each
kind of sound, across the full age range. We could make a table:
sounds %>%
group_by(sound) %>%
summarize(total_produce = sum(kids_produce)) %>%
knitr::kable()
cockadoodledoo |
148 |
meow |
681 |
woof woof |
940 |
Or we could make a simple bar plot:
ggplot(sounds, aes(x = sound, y = kids_produce)) +
geom_col() +
labs(x = "Sound", y = "Total Children Producing")
For this kind of plot, we don’t really need color. What if we want to
see how the number of kids who produce each sound varies by age? We’ll
change the x-axis to age and instead facet_wrap
by
sound
, and make the y-axis a proportion instead of
counts.
ggplot(sounds, aes(x = age, y = prop_produce)) +
geom_col() +
labs(x = "Age (mos)", y = "Proportion of Children Producing") +
facet_wrap(~sound)
The bar geom makes this a little hard to read and compare across
facets though. Let’s try points instead.
ggplot(sounds, aes(x = age, y = prop_produce)) +
geom_point() +
labs(x = "Age (mos)", y = "Proportion of Children Producing") +
facet_wrap(~sound)
That is a little better! Facets allow us to parse the relationship
between two quantitative variables (here, age and proportion of kids
producing) by a qualitative variable (here, type of sound). Another way
we could do this, instead of facetting, is to use color. This would make
it easier to compare proportions at each age.
Discrete colors
Let’s start with a base plot with age (in months) along the x-axis
and the proportion of children producing each word along the y-axis,
using points as the geometric object. Set the size of the points to 2
and change the x- and y-axis labels to “Age (months)” and “Proportion of
Children Producing”, respectively.
ggplot(sounds, aes(x = age, y = prop_produce)) +
geom_point(size = 2) +
labs(x = "Age (months)", y = "Proportion of Children Producing")
Default discrete
palette
Challenge #2:
Take the plot we just made, and edit the code to map the color of the
points to the type of sound produced at the geom level. The
colors that show up are the default discrete palette in
ggplot2
.
ggplot(sounds, aes(x = age, y = prop_produce)) +
geom_point(aes(color = sound), size = 2) +
labs(x = "Age (months)", y = "Proportion of Children Producing")
Challenge #3:
Try adding geom_line()
to this plot to connect the dots.
Does this look right? Use ?geom_line
to figure out how this
geom connects the dots by default, and which aesthetic can be used to
connect cases together. Try editing your code to draw 3 black lines- one
for each sound.
# Does this look right? no!
ggplot(sounds, aes(x = age, y = prop_produce)) +
geom_line() +
geom_point(aes(color = sound), size = 2) +
labs(x = "Age (months)", y = "Proportion of Children Producing")
# A possible solution
ggplot(sounds, aes(x = age, y = prop_produce)) +
geom_line(aes(group = sound)) +
geom_point(aes(color = sound), size = 2) +
labs(x = "Age (months)", y = "Proportion of Children Producing")
Challenge #4:
Make two plots:
Recreate the plot above, but this time map color to the type of
sound produced for both the point and line geoms. Pay attention to the
order of the layers you are adding- you may wish to place
geom_line
before geom_point
so the
lines are always “painted” underneath the points.
Instead of geom_line
, add a loess line using
geom_smooth
. Use ?geom_smooth
to figure out
how to get rid of the grey standard error ribbon. You may also want to
increase the line width.
# Does this look right? yes!
ggplot(sounds, aes(x = age, y = prop_produce, color = sound)) +
geom_line() +
geom_point(size = 2) +
labs(x = "Age (months)", y = "Proportion of Children Producing")
ggplot(sounds, aes(x = age,
y = prop_produce,
color = sound)) +
geom_smooth(se = FALSE, lwd = .5) +
geom_point(size = 2) +
labs(x = "Age (months)", y = "Proportion of Children Producing")
Why does this work? To tell geom_line
how to connect
your dots, you can either:
- Map the
group
aesthetic (so
aes(group = sound)
), or
- Map the
color
aesthetic globally
(aes(color = sound)
.
Because geom_line
understands the color
aesthetic, it will try to draw separate lines for each color. Here that
translates to three lines, one for each sound, which is what we
want!
Brief aside:
factors
At this point, our plot is looking pretty good. But you may have
noticed that the legend order doesn’t match the order of the lines in
the plot. Question: why is this an issue?
What determines the order of levels in the legend? The order of
levels in the underlying factor:
levels(as.factor(sounds$sound))
[1] "cockadoodledoo" "meow" "woof woof"
In this case, since we haven’t set them, R will pick an order for
us.
We could manually re-order the levels of the factor, but
different plots might necessitate different factor ordering, and if we
have more than two or three levels, typing them repeatedly gets tedious
fast. Instead, let’s have R do it!
The forcats
package, is for
cat
egorical variables and
has lots of useful functions, including some for re-ordering levels.
There are lots of functions in forcats
, and you can install
& load it separately, although forcats
is loaded with
the tidyverse
.
install.packages("forcats")
library(forcats)
We’ll use the fct_reorder2
function, which by default
will re-order the levels of a factor based on the order of occurrence of
one variable (y
in the docs) when the dataframe is
sorted by another variable (x
in the docs):
# "Sort the dataframe by age, find the last occurrence of each level of sounds$sound in order of prop_produce
fct_reorder2(
as.factor(sounds$sound),
sounds$age, # variable "x"
sounds$prop_produce # varible "y"
) %>% levels
[1] "woof woof" "meow" "cockadoodledoo"
This (somehwat convoluted) procedure is very useful for when you have
a line chart of two quantitative variables, colored by a factor
variable. Let’s see the difference:
sounds <- sounds %>%
mutate(sound = as.factor(sound))
sound_traj <- ggplot(sounds, aes(x = age,
y = prop_produce,
color = fct_reorder2(sound, age, prop_produce))) +
geom_smooth(se = FALSE, lwd = .5) +
geom_point(size = 2) +
labs(x = "Age (months)",
y = "Proportion of Children Producing",
color = "sound")
sound_traj
MUCH BETTER! Save your plot object as sound_traj
. Now we
can start playing with the actual colors.
Set luminance and
saturation (chromaticity)
The default qualitative palette works fine here. The addition of scale_color_hue
changes nothing.
sound_traj +
scale_color_hue()
We can also change these settings within the default color palette,
where the arguments are:
h
= range of hues to use, in [0, 360]
l
= luminance (lightness)
c
= chroma (intensity of color)
# Change hue (l and c are defaults)
sound_traj +
scale_color_hue(h = c(0, 90), l = 65, c = 100)
# Use luminance=45, instead of default 65
sound_traj +
scale_color_hue(l = 45)
# Reduce saturation (chroma) from 100 to 50, and increase luminance
sound_traj +
scale_color_hue(l = 75, c = 50)
Set discrete
colors
We can change the actual colors used by adding the layer
scale_color_manual
or scale_fill_manual
.
Confusion between which to use when is often the cause of much
frustration!
To name more than one color, which you often want to do, use
c()
. In the parentheses, named colors and hex colors are
always in quotes.
sound_traj +
scale_color_manual(values = c("cornflowerblue",
"seagreen", "coral"))
There are many named
colors available in R!
Challenge #5:
View the code blocks below. Copy and paste the code to run them in
your own file. Why do neither of the following code blocks change the
colors of the points and lines? Use your words :) (the answer is
below the challenge, but try to trouble-shoot on your own
first)
ggplot(sounds, aes(x = age,
y = prop_produce,
color = fct_reorder2(sound, age, prop_produce))) +
geom_smooth(se = FALSE, lwd = .5) +
geom_point(size = 2) +
labs(x = "Age (months)",
y = "Proportion of Children Producing",
color = "sound") +
scale_fill_manual(values = c("cornflowerblue",
"seagreen", "coral"))
ggplot(sounds, aes(x = age,
y = prop_produce,
fill = fct_reorder2(sound, age, prop_produce))) +
geom_smooth(se = FALSE, lwd = .5) +
geom_point(size = 2) +
labs(x = "Age (months)",
y = "Proportion of Children Producing",
fill = "sound") +
scale_fill_manual(values = c("cornflowerblue",
"seagreen", "coral"))
Answers:
- In the first, we used
scale_fill_manual
, but the in the
global aesthetics, we mapped the color
, not
fill
, aesthetic onto the sound
variable.
- In the second, we did define the
fill
aesthetic and
used scale_fill_manual
, so that is good. But
geom_line
only understands the color
aesthetic, not fill
. And for geom_point
, the
default shape for is 19, which does not understand the fill
aesthetic.
Challenge #6:
Start with this plot:
sound_traj
Add a black outline to the points, and color the inside of the points
and the lines by sound
using the default discrete color
palette. You may also wish to edit the legends on this plot:
geom_smooth
has an argument called
show.legend = FALSE
. See if you prefer the plot with this
change.
If this was easy, try applying the same custom color palette to the
inside of the points and to the lines.
ggplot(sounds, aes(x = age,
y = prop_produce,
fill = fct_reorder2(sound, age, prop_produce))) +
geom_smooth(aes(color = fct_reorder2(sound, age, prop_produce)),
se = FALSE, lwd = .5, show.legend = FALSE) +
geom_point(size = 2, shape = 21) +
labs(x = "Age (months)",
y = "Proportion of Children Producing",
fill = "sound")
ggplot(sounds, aes(x = age,
y = prop_produce,
fill = fct_reorder2(sound, age, prop_produce))) +
geom_smooth(aes(color = fct_reorder2(sound, age, prop_produce)),
se = FALSE, lwd = .5, show.legend = FALSE) +
geom_point(size = 2, shape = 21) +
labs(x = "Age (months)",
y = "Proportion of Children Producing",
fill = "sound") +
scale_fill_manual(values = c("cornflowerblue",
"seagreen", "coral")) +
scale_color_manual(values = c("cornflowerblue",
"seagreen", "coral"))
You can also define your color palette as a vector outside of
ggplot2
. Below, I made an object called
my_colors
outside of ggplot2
. To use it, we
call that object within the scale_colour_manual
function.
my_colors <- c("cadetblue", "steelblue", "salmon") # quote color names
sound_traj +
scale_color_manual(values = my_colors) # note: not in quotes
Challenge #7:
Define a custom color palette using hexadecimal colors (#rrggbb), and
apply it using scale_color_manual
to your
sound_traj
plot. Some basic ones are here:
https://sashat.me/2017/01/11/list-of-20-simple-distinct-colors/
Parse the hexadecimal string like so: #rrggbb, where rr, gg, and bb
refer to color intensity in the red, green, and blue channels,
respectively.
# from https://github.com/mwaskom/seaborn/blob/master/seaborn/palettes.py
sb_colorblind <- c("#0072B2", "#009E73", "#D55E00",
"#CC79A7", "#F0E442", "#56B4E9")
sound_traj +
scale_colour_manual(values = sb_colorblind)
Built-in discrete
palettes
Colorbrewer
To use Colorbrewer palettes, you’ll need to install the
RColorBrewer
package from CRAN. This chunk of code tells
you how:
install.packages("RColorBrewer")
library(RColorBrewer)
Colorbrewer has a few qualitative palettes named: Accent, Dark2,
Paired, Pastel1, Pastel2, Set1, Set2, Set3. Here is how to view
them:
brewer.pal(5, "Dark2") # list 5 hex colors
[1] "#1B9E77" "#D95F02" "#7570B3" "#E7298A" "#66A61E"
display.brewer.pal(5, "Dark2") # view 5 hex colors
And here is how you use them:
sound_traj +
scale_color_brewer(palette = "Dark2")
Wes Anderson
palettes
My favorite! To use Wes Anderson palettes, you’ll need to install the
wesanderson
package from CRAN. This chunk of code tells you
how:
install.packages("wesanderson")
library(wesanderson)
names(wes_palettes) # all the palette names
[1] "BottleRocket1" "BottleRocket2" "Rushmore1" "Rushmore"
[5] "Royal1" "Royal2" "Zissou1" "Darjeeling1"
[9] "Darjeeling2" "Chevalier1" "FantasticFox1" "Moonrise1"
[13] "Moonrise2" "Moonrise3" "Cavalcanti1" "GrandBudapest1"
[17] "GrandBudapest2" "IsleofDogs1" "IsleofDogs2"
wes_palette("GrandBudapest2") # view named palette
wes_palette("GrandBudapest2")[1:4] # list first 4 hex colors
[1] "#E6A0C4" "#C6CDF7" "#D8A499" "#7294D4"
wes_palette("GrandBudapest2")[c(1,4)] # list colors 1 and 4
[1] "#E6A0C4" "#7294D4"
To use these palettes, use scale_color_manual
where
values
is set to wes_palette("name")
. For
example:
sound_traj +
scale_color_manual(values = wes_palette("Darjeeling1"))
sound_traj +
scale_color_manual(values = wes_palette("FantasticFox1"))
Challenge #8:
What if you just don’t want to use the colors in the order they are
in? Use a wes_palette
of your choice. Using our code from
above, try picking the last 3 colors of a palette. Add it to your
sound_traj
plot.
If this was easy, try using colors 2, 3, and 5 instead.
sound_traj +
scale_color_manual(values = wes_palette("Darjeeling1")[3:5])
sound_traj +
scale_color_manual(values = wes_palette("FantasticFox1")[c(2, 3, 5)])
ggthemes
palettes
To use these palettes, you’ll need to install the
ggthemes
package from CRAN. This chunk of code tells you
how:
install.packages("ggthemes")
library(ggthemes)
sound_traj +
scale_color_fivethirtyeight()
sound_traj +
scale_color_economist()
ggsci
Palettes
ggsci
provides
color palettes designed to match with the aesthetics of a wide variety
of scientific publishers:
library(ggsci)
sound_traj + scale_color_nejm()
Palettes from the
Queen Bee
To use Beyonce
palettes, you’ll need to install the beyonce
package
from GitHub using devtools::install_github()
. This chunk of
code tells you how:
install.packages("devtools")
devtools::install_github("dill/beyonce")
library(beyonce)
Note that a number of students had installation problems with this
package! Move on if you do.
beyonce_palette(18)
sound_traj +
scale_color_manual(values = beyonce_palette(18)[3:5])
Here we’ll only use the first, fourth, and fifth colors in the
palette.
sound_traj +
scale_color_manual(values = beyonce_palette(18)[c(1, 4, 5)])
Viridis
palettes
“Use the color scales in this package to make plots that are pretty,
better represent your data, easier to read by those with colorblindness,
and print well in grey scale.”
To use, you’ll need to install the viridis
package from
CRAN. This chunk of code tells you how:
install.packages("viridis")
library(viridis)
Read more here in the viridis
vignette. The default argument for discrete
is FALSE,
so to use the discrete palettes you need to set
discrete = TRUE
. There are four colormap options
available:
- “magma” (or “A”),
- “inferno” (or “B”),
- “plasma” (or “C”),
- “viridis” (or “D”, the default option).
sound_traj +
scale_color_viridis(discrete = TRUE) +
theme_minimal()
sound_traj +
scale_color_viridis(discrete = TRUE, option = "plasma") +
theme_minimal()
Challenge #9:
Use the viridis
package to color the points by and the
lines by sound
; make the outline of the points
“midnightblue”. Pick any colormap option, and play with
theme_bw
or theme_minimal
to see what you
like.
ggplot(sounds, aes(x = age,
y = prop_produce,
fill = fct_reorder2(sound, age, prop_produce))) +
geom_smooth(aes(color = fct_reorder2(sound, age, prop_produce)),
se = FALSE, lwd = .5, show.legend = FALSE) +
geom_point(size = 2, shape = 21, colour = "midnightblue") +
labs(x = "Age (months)",
y = "Proportion of Children Producing",
fill = "sound") +
scale_fill_viridis(discrete = TRUE) +
scale_color_viridis(discrete = TRUE) +
theme_minimal()
Greyscale for
discrete
Use scale_color_grey
or scale_fill_grey
, or
sometimes both depending on your geoms and the aesthetics they
understand.
sound_traj +
scale_color_grey() +
theme_minimal()
Set start and end
sound_traj +
scale_color_grey(start = 0.2, end = .8)
Make the same plot but make points outlined in black
ggplot(sounds, aes(x = age,
y = prop_produce,
fill = fct_reorder2(sound, age, prop_produce))) +
geom_smooth(aes(color = fct_reorder2(sound, age, prop_produce)),
se = FALSE, lwd = .5, show.legend = FALSE) +
geom_point(size = 2, shape = 21) +
labs(x = "Age (months)",
y = "Proportion of Children Producing",
fill = "sound") +
scale_fill_grey(start = 0.3, end = 1) +
scale_color_grey(start = 0.3, end = 1)
Suggest redundancy in greyscale- try changing line type instead of
line (or in addition to) line color.
Change line type by sound
, set color to black.
ggplot(sounds, aes(x = age,
y = prop_produce,
fill = fct_reorder2(sound, age, prop_produce))) +
geom_smooth(aes(lty = fct_reorder2(sound, age, prop_produce)), color = "black",
se = FALSE, lwd = .5, show.legend = FALSE) +
geom_point(size = 2, shape = 21) +
labs(x = "Age (months)",
y = "Proportion of Children Producing",
fill = "sound") +
scale_fill_grey(start = 0.3, end = 1)
Change both!
ggplot(sounds, aes(x = age,
y = prop_produce,
fill = fct_reorder2(sound, age, prop_produce))) +
geom_smooth(aes(color = fct_reorder2(sound, age, prop_produce),
lty = fct_reorder2(sound, age, prop_produce)),
se = FALSE, lwd = .5, show.legend = FALSE) +
geom_point(size = 2, shape = 21) +
labs(x = "Age (months)",
y = "Proportion of Children Producing",
fill = "sound") +
scale_fill_grey(start = 0.3, end = .8) +
scale_color_grey(start = 0.3, end = .8)
Colorblind-friendly
palettes
The colorblindr
package can be used to “simulate colorblindness in production-ready
R figures.” To use this package, you’ll need to first install the
cowplot
package from GitHub using
devtools::install_github()
. You’ll also need to install the
colorspace
package from CRAN. Finally, you can then use
devtools::install_github()
again to install the
colorblindr
package. This code chunk shows you how to do
all 3 installs to use the colorblindr
package:
devtools::install_github("wilkelab/cowplot")
install.packages("colorspace", repos = "http://R-Forge.R-project.org")
devtools::install_github("clauswilke/colorblindr")
To use:
# save a ggplot object
my_sound_traj <- sound_traj +
scale_color_manual(values = beyonce_palette(18)[c(1, 4, 5)])
View that figure after color-vision-deficiency simulation:
# remotes::install_github("clauswilke/colorblindr")
library(colorblindr)
Error in library(colorblindr): there is no package called 'colorblindr'
cvd_grid(my_sound_traj)
Error in cvd_grid(my_sound_traj): could not find function "cvd_grid"
You can also use the colorblind-friendly palette in this package
using scale_color_OkabeIto
and
scale_fill_OkabeIto
:
cb_sound_traj <- sound_traj +
scale_color_OkabeIto()
Error in scale_color_OkabeIto(): could not find function "scale_color_OkabeIto"
cb_sound_traj
Error in eval(expr, envir, enclos): object 'cb_sound_traj' not found
cvd_grid(cb_sound_traj)
Error in cvd_grid(cb_sound_traj): could not find function "cvd_grid"
You can still use this colorblind-friendly palette without the
colorblindr
package though. Here are the colors!
The Cookbook
for R provided the matching hex colors too to make life easier:
cbbPalette <- c("#000000", "#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2", "#D55E00", "#CC79A7")
# To use for line and point colors, add
sound_traj +
scale_colour_manual(values = cbbPalette[c(3, 7, 8)])
Repel labels
library(ggrepel)
sounds <- sounds %>%
mutate(label = case_when(
age == max(age) ~ sound))
ggplot(sounds, aes(x = age,
y = prop_produce,
color = fct_reorder2(sound, age, prop_produce))) +
geom_smooth(se = FALSE, lwd = .5) +
geom_point(size = 2) +
labs(x = "Age (months)",
y = "Proportion of Children Producing") +
geom_text_repel(aes(label = label),
nudge_x = 1,
direction = "y",
na.rm = TRUE) +
guides(color = FALSE)
Continuous colors
N.B. All of the example plots below are great examples of how
not to use continuous colors. I’m showing these so you
can see how to work with continuous color palettes, and to make this
topic flow easier for you I’m sticking with original dataset.
Default continuous
palette
Let’s map color to a continuous variable. For this, we are returning
to geom_line
instead of geom_smooth
, because
the latter doesn’t respond to continuous color palettes.
sound_by_age <- ggplot(sounds, aes(x = age,
y = prop_produce,
color = age)) +
geom_line(aes(group = sound), lwd = .5) +
geom_point(size = 2) +
labs(x = "Age (months)",
y = "Proportion of Children Producing")
sound_by_age
Color choice with
continuous variables
With discrete colors, we used either scale_color_manual
or scale_fill_manual
(and sometimes both were needed!). For
continuous colors, we use either scale_color_gradient
or
scale_fill_gradient
.
sound_by_age +
scale_color_gradient()
You can reverse the gradient scale…
sound_by_age +
scale_color_gradient(trans = "reverse")
sound_by_age +
scale_color_gradient(low = "white", high = "red")
We can make this same plot using a custom greyscale gradient.
sound_by_age +
scale_color_gradient(low = "grey90", high = "black")
So scale_color_gradient
gives you a sequential gradient,
but you may want a diverging color scheme instead. For that, you can use
scale_color_gradient2
# Diverging color scheme
med_age <- sounds %>%
summarize(mos = median(age)) %>%
pull()
sound_by_age +
scale_color_gradient2(midpoint = med_age,
low="blue", mid="white", high="red" )
Built-in continuous
palettes
Use
RColorBrewer
Again, to use you need to install and load the
RColorBrewer
palette.
library(RColorBrewer)
Then use scale_color_gradientn
.
sound_by_age +
scale_color_gradientn(colours = brewer.pal(n=5, name="PuBuGn"))
Reverse the colors…
sound_by_age +
scale_color_gradientn(colours = rev(brewer.pal(n=5, name="PuBuGn")))
Viridis
Read more here in the viridis
vignette
library(viridis)
The default is the viridis
palette within the
viridis
package!
Note! For discrete == FALSE (the default) all other arguments are as
to scale_fill_gradientn
or
scale_color_gradientn
. (Also note that
_gradient_n_
is not a typo- the n versions of
those functions allow multi-color gradients).
sound_by_age +
scale_color_viridis()
sound_by_age +
scale_color_viridis(option = "magma")
Read the help function for ?scale_color_viridis
. We’ll
use the “inferno” palette in reverse.
sound_by_age +
scale_color_viridis(option = "inferno", begin = 1, end = 0)
LS0tCnRpdGxlOiAiTGFiIDAzOiBDb2xvcnMgd2l0aCBBbmltYWwgU291bmRzIgpzdWJ0aXRsZTogIkJNSSA1LzYyNSIKYXV0aG9yOiAiQWxpc29uIEhpbGwgdy8gbWlub3IgdHdlYWtzIGJ5IFN0ZXZlbiBCZWRyaWNrIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIHRoZW1lOiBmbGF0bHkKICAgIHRvYzogVFJVRQogICAgdG9jX2Zsb2F0OiBUUlVFCiAgICB0b2NfZGVwdGg6IDIKICAgIG51bWJlcl9zZWN0aW9uczogVFJVRQogICAgY29kZV9mb2xkaW5nOiBoaWRlCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCi0tLQpgYGB7ciBzZXR1cCwgaW5jbHVkZSA9IEZBTFNFLCBjYWNoZSA9IEZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZXJyb3IgPSBUUlVFLCBjb21tZW50ID0gTkEsIHdhcm5pbmcgPSBGQUxTRSwgZXJyb3JzID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRSwgdGlkeSA9IEZBTFNFLCBjYWNoZSA9IEZBTFNFKQpsaWJyYXJ5KFJDb2xvckJyZXdlcikKbGlicmFyeSh3ZXNhbmRlcnNvbikKbGlicmFyeShnZ3RoZW1lcykKbGlicmFyeShiZXlvbmNlKQpsaWJyYXJ5KHZpcmlkaXMpCmBgYAoKIyBPdmVydmlldwoKVGhlcmUgYXJlIDEwIGNoYWxsZW5nZXMgdG90YWwtIG5vbmUgYXJlIGluIHRoZSAiY29udGludW91cyBjb2xvcnMiIHNlY3Rpb24sIGJ1dCB5b3UgY2FuIHVzZSB0aGF0IHNlY3Rpb24gdG8gY29tcGxldGUgdGhlIHRlbnRoIGNoYWxsZW5nZSBvbiB5b3VyIG93bi4gVXBsb2FkIHlvdXIga25pdHRlZCBodG1sIGRvY3VtZW50IGJ5IG5leHQgV2VkbmVzZGF5IHRvIFNha2FpIQoKTm90ZSB0aGF0IHRoaXMgbGFiIGRlcGVuZHMgb24gX21hbnlfIHBhY2thZ2VzOyBvbiB0aGUgUlN0dWRpbyBDbG91ZCBwcm9qZWN0IGZvciB0aGUgbGFiIGRlbGl2ZXJhYmxlLCBJIGhhdmUgcHJlLWluc3RhbGxlZCB0aGVtIGFsbCAoSSB0aGluaykuIFdlJ3ZlIGxlZnQgdGhlIGluc3RhbGxhdGlvbiBpbnN0cnVjdGlvbnMgaGVyZSBpbiB0aGUgbGFiIGRvY3VtZW50IGZvciBkZW1vbnN0cmF0aW9uIHB1cnBvc2VzLgoKIyBTbGlkZXMgZm9yIHRvZGF5CgpgYGB7cn0Ka25pdHI6OmluY2x1ZGVfdXJsKCJzbGlkZXMvMDMtc2xpZGVzLmh0bWwiKQpgYGAKCiMgUGFja2FnZXMKCk90aGVyIHBhY2thZ2VzIHdpbGwgYmUgbmVlZGVkIHRvIGJlIGluc3RhbGxlZCBhcyB5b3UgZ28tIHJldmVhbCB0aGUgZmlyc3QgY29kZSBjaHVua3Mgd2hlbiBpbiBkb3VidCEKCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKYGBgCgojIFJlYWQgaW4gdGhlIGRhdGEKCmBgYHtyfQpzb3VuZHMgPC0gcmVhZF9jc3YoaGVyZTo6aGVyZSgiZGF0YSIsICJhbmltYWxfc291bmRzX3N1bW1hcnkuY3N2IikpCmBgYAoKIyBDb2xvdXIgdnMgZmlsbCBhZXN0aGV0aWMKCkZpbGwgYW5kIGNvbG91ciBzY2FsZXMgaW4gZ2dwbG90MiBjYW4gdXNlIHRoZSBzYW1lIHBhbGV0dGVzLiBTb21lIHNoYXBlcyBzdWNoIGFzIGxpbmVzIG9ubHkgYWNjZXB0IHRoZSBgY29sb3VyYCBhZXN0aGV0aWMsIHdoaWxlIG90aGVycywgc3VjaCBhcyBwb2x5Z29ucywgYWNjZXB0IGJvdGggYGNvbG91cmAgYW5kIGBmaWxsYCBhZXN0aGV0aWNzLiBJbiB0aGUgbGF0dGVyIGNhc2UsIHRoZSBgY29sb3VyYCByZWZlcnMgdG8gdGhlIGJvcmRlciBvZiB0aGUgc2hhcGUsIGFuZCB0aGUgYGZpbGxgIHRvIHRoZSBpbnRlcmlvci4KCgoKYGBge3IgZWNobyA9IEZBTFNFfQojIyBBIGxvb2sgYXQgYWxsIDI1IHN5bWJvbHMKZGYgPC0gZGF0YS5mcmFtZSh4ID0gMTo1LCAKICAgICAgICAgICAgICAgICAgeSA9IHJlcChyZXYoc2VxKDAsIDI0LCBieSA9IDUpKSwgZWFjaCA9IDUpLCAKICAgICAgICAgICAgICAgICAgeiA9IDE6MjUpCnMgPC0gZ2dwbG90KGRmLCBhZXMoeCA9IHgsIHkgPSB5KSkgKyAKICBzY2FsZV9zaGFwZV9pZGVudGl0eSgpICsgCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHosIHkgPSB5IC0gMSkpICsgCiAgdGhlbWVfdm9pZCgpCnMgKyBnZW9tX3BvaW50KGFlcyhzaGFwZSA9IHopLCBzaXplID0gNCkgCmBgYAoKLS0tCgpBbGwgc3ltYm9scyBoYXZlIGEgZm9yZWdyb3VuZCBjb2xvdXIsIHNvIGlmIHdlIGFkZCBgY29sb3IgPSAibmF2eSJgLCB0aGV5IGFsbCBhcmUgYWZmZWN0ZWQuCgpgYGB7cn0KcyArIGdlb21fcG9pbnQoYWVzKHNoYXBlID0geiksIHNpemUgPSA0LCBjb2xvdXIgPSAibmF2eSIpIApgYGAKCi0tLQoKV2hpbGUgYWxsIHN5bWJvbHMgaGF2ZSBhIGZvcmVncm91bmQgY29sb3VyLCBzeW1ib2xzIDIxLTI1IGFsc28gdGFrZSBhIGJhY2tncm91bmQgY29sb3VyIChmaWxsKS4gU28gaWYgd2UgYWRkIGBmaWxsID0gIm9yY2hpZCJgLCBvbmx5IHRoZSBsYXN0IHJvdyBvZiBzeW1ib2xzIGFyZSBhZmZlY3RlZC4KCmBgYHtyfQpzICsgZ2VvbV9wb2ludChhZXMoc2hhcGUgPSB6KSwgc2l6ZSA9IDQsIGNvbG91ciA9ICJuYXZ5IiwgZmlsbCA9ICJvcmNoaWQiKSAKYGBgCgoKIyBEYXRhCgpGb3IgdGhlIHJlc3Qgb2YgdG9kYXksIHdlJ2xsIHBsYXkgd2l0aCB0aGUgYHNvdW5kc2AgZGF0YXNldC4gVGhpcyBkYXRhIHdhcyBkZXJpdmVkIGZyb20gdGhlIFIgcGFja2FnZSBbYHdvcmRiYW5rcmBdKGh0dHA6Ly9sYW5nY29nLmdpdGh1Yi5pby93b3JkYmFua3IvKSwgYW4gUiBpbnRlcmZhY2UgdG8gYWNjZXNzIFtXb3JkYmFua10oaHR0cDovL3dvcmRiYW5rLnN0YW5mb3JkLmVkdSktIGFuIG9wZW4gc291cmNlIGRhdGFiYXNlIG9mIGNoaWxkcmVuJ3Mgdm9jYWJ1bGFyeSBkZXZlbG9wbWVudC4gVGhlIHRvb2wgdXNlZCB0byBtZWFzdXJlIGNoaWxkcmVuJ3MgbGFuZ3VhZ2UgYW5kIGNvbW11bmljYXRpdmUgZGV2ZWxvcG1lbnQgaW4gdGhpcyBkYXRhYmFzZSBpcyB0aGUgW01hY0FydGh1ci1CYXRlcyBDb21tdW5pY2F0aXZlIERldmVsb3BtZW50IEludmVudG9yaWVzIChNQi1DREkpXShodHRwOi8vbWItY2RpLnN0YW5mb3JkLmVkdSkuIFRoZSBNRC1DREkgaXMgYSBwYXJlbnQtcmVwb3J0ZWQgcXVlc3Rpb25uYWlyZS4KCkhlcmUgaXMgYSBnbGltcHNlIG9mIHRoZSBkYXRhOgoKYGBge3J9CmdsaW1wc2Uoc291bmRzKQpgYGAKCgpOb3RlIHRoYXQgdGhlIHVuaXQgb2Ygb2JzZXJ2YXRpb24gaGVyZSBpcyBvbmUtcm93LXBlci1hZ2UtZ3JvdXAvYW5pbWFsIHNvdW5kLgoKClZhcmlhYmxlcyB5b3UgbmVlZCBmb3IgdGhpcyBsYWI6CgotIGBhZ2VgOiBjaGlsZCBhZ2UgaW4gbW9udGhzCi0gYHNvdW5kYDogYSBzdHJpbmcgZGVzY3JpYmluZyBhIHR5cGUgb2YgYW5pbWFsIHNvdW5kCi0gYGtpZHNfcHJvZHVjZWA6IHRoZSBudW1iZXIgb2YgcGFyZW50cyB3aG8gYW5zd2VyZWQgInllcywgbXkgY2hpbGQgcHJvZHVjZXMgdGhpcyBhbmltYWwgc291bmQiIChub3RlIHRoYXQgaWYgdGhlIGNoaWxkIHByb2R1Y2VzIGEgc291bmQgaXQgaXMgYXNzdW1lZCB0aGF0IHRoZXkgdW5kZXJzdGFuZCBpdCBhcyB3ZWxsKQotIGBraWRzX3Jlc3BvbmRgOiB0aGUgbnVtYmVyIG9mIHBhcmVudHMgd2hvIHJlc3BvbmRlZCB0byB0aGlzIHF1ZXN0aW9uIGF0IGFsbAotIGBwcm9wX3Byb2R1Y2VgOiB0aGUgcHJvcG9ydGlvbiBvZiBraWRzIHdob3NlIHBhcmVudHMgZW5kb3JzZWQgdGhhdCB0aGVpciBjaGlsZCBwcm9kdWNlcyB0aGlzIGFuaW1hbCBzb3VuZCwgb3V0IG9mIGFsbCBxdWVzdGlvbm5haXJlcyBhZG1pbmlzdGVyZWQgKGkuZS4sIGBraWRzX3Byb2R1Y2UgLyBraWRzX3Jlc3BvbmRgKQoKT3RoZXIgdmFyaWFibGVzIGluIHRoaXMgZGF0YXNldDoKCi0gYGtpZHNfdW5kZXJzdGFuZGA6IHRoZSBudW1iZXIgb2YgcGFyZW50cyB3aG8gYW5zd2VyZWQgInllcywgbXkgY2hpbGQgdW5kZXJzdGFuZHMgd2hhdCB0aGlzIGFuaW1hbCBzb3VuZCBtZWFucyIgKG5vdGUgdGhhdCBhIGNoaWxkIGNhbiB1bmRlcnN0YW5kIHRoZSBzb3VuZCBidXQgbm90IHByb2R1Y2UgaXQpCi0gYHByb3BfdW5kZXJzdGFuZGA6IHRoZSBwcm9wb3J0aW9uIG9mIGtpZHMgd2hvc2UgcGFyZW50cyBlbmRvcnNlZCB0aGF0IHRoZWlyIGNoaWxkIHVuZGVyc3RhbmRzIHRoaXMgYW5pbWFsIHNvdW5kLCBvdXQgb2YgYWxsIHF1ZXN0aW9ubmFpcmVzIGFkbWluaXN0ZXJlZCAoaS5lLiwgYGtpZHNfdW5kZXJzdGFuZCAvIGtpZHNfcmVzcG9uZGApCgoKCiMgRGlzY3JldGUgdnMgY29udGludW91cyB2YXJpYWJsZXMKCjxkaXYgY2xhc3M9InBhbmVsIHBhbmVsLXByaW1hcnkiPgogIDxkaXYgY2xhc3M9InBhbmVsLWhlYWRpbmciPlJlZnJlc2hlciBDb250ZW50OjwvZGl2PgogIDxkaXYgY2xhc3M9InBhbmVsLWJvZHkiPgpGb3IgYSByZWZyZXNoZXIgKGFuZCBtb3JlIGRldGFpbGVkIGRlZXAtZGl2ZSksIGNoZWNrIG91dDogWyJXSEFUIElTIFRIRSBESUZGRVJFTkNFIEJFVFdFRU4gQ0FURUdPUklDQUwsIE9SRElOQUwgQU5EIE5VTUVSSUNBTCBWQVJJQUJMRVM/Il0oaHR0cHM6Ly9zdGF0cy5pZHJlLnVjbGEuZWR1L290aGVyL211bHQtcGtnL3doYXRzdGF0L3doYXQtaXMtdGhlLWRpZmZlcmVuY2UtYmV0d2Vlbi1jYXRlZ29yaWNhbC1vcmRpbmFsLWFuZC1udW1lcmljYWwtdmFyaWFibGVzLykKPC9kaXY+CjwvZGl2PgoKSW4gb3JkZXIgdG8gdXNlIGNvbG9yIHdpdGggeW91ciBkYXRhLCBtb3N0IGltcG9ydGFudGx5LCB5b3UgbmVlZCB0byBrbm93IGlmIHlvdeKAmXJlIGRlYWxpbmcgd2l0aCBkaXNjcmV0ZSBvciBjb250aW51b3VzIHZhcmlhYmxlcy4gCgojIyBEaXNjcmV0ZSBjb2xvciBwYWxldHRlcwoKRGlzY3JldGUgY29sb3IgcGFsZXR0ZXMgd29yayBiZXN0IHdoZW4geW91IHdhbnQgdG8gY29sb3IgYnkgYSBxdWFsaXRhdGl2ZSB2YXJpYWJsZS4gUXVhbGl0YXRpdmUgdmFyaWFibGVzIHRlbmQgdG8gYmUgZWl0aGVyIGNhdGVnb3JpY2FsIG9yIG9yZGluYWwuIERpZmZlcmVudCB2YXJpYWJsZXMgY2FuIGJlIHF1YWxpdGF0aXZlIG9yIHF1YW50aXRhdGl2ZSBkZXBlbmRpbmcgb24gY29udGV4dC4gCgpJbiB0aGlzIGRhdGFzZXQsIGBzb3VuZGAgaXMgYSBjYXRlZ29yaWNhbCB2YXJpYWJsZSB3aXRoIDMgcG9zc2libGUgdmFsdWVzOgpgYGB7cn0Kc291bmRzICU+JSAKICBkaXN0aW5jdChzb3VuZCkgJT4lIAogIGtuaXRyOjprYWJsZSgpCmBgYAoKV2UgY291bGQgbWFwIGFyYml0cmFyeSBudW1iZXJzIG9udG8gZWFjaCBvZiB0aGVzZSBzb3VuZHMsIGxpa2UgMSwgMiwgYW5kIDMtIGJ1dCB0aGUgbnVtYmVycyBzdGlsbCB3b3VsZCBub3QgbWVhbiBhbnl0aGluZy4gVGhhdCBpcywgdGhlcmUgaXMgbm8gaW50cmluc2ljIG9yZGVyaW5nIHRvIHRoZXNlIGNhdGVnb3JpZXMuIEV4YW1wbGVzIG9mIGNvbW1vbiBwdXJlIGNhdGVnb3JpY2FsIHZhcmlhYmxlcyBhcmUgcmFjZSBvciBldGhuaWNpdHksIGdlbmRlciwgaGFpciBjb2xvciwgZXllIGNvbG9yLCBldGMuIENvbG9yaW5nIGJ5IHNvdW5kIGlzIHVzZWQgYXMgYSB3YXkgdG8gKmRpc3Rpbmd1aXNoKiB0aGUgZGF0YSBmb3IgZGlmZmVyZW50IHNvdW5kcyBmcm9tIGVhY2ggb3RoZXIgKHJlYWQgbW9yZSBoZXJlOiBodHRwOi8vc2VyaWFsbWVudG9yLmNvbS9kYXRhdml6L2NvbG9yLWJhc2ljcy5odG1sI2NvbG9yLWFzLWEtdG9vbC10by1kaXN0aW5ndWlzaCkKCiMjIENvbnRpbnVvdXMgY29sb3IgcGFsZXR0ZXMKCkNvbnRpbnVvdXMgY29sb3IgcGFsZXR0ZXMgd29yayBiZXN0IHdoZW4geW91IHdhbnQgdG8gY29sb3IgYnkgYSBxdWFudGl0YXRpdmUgdmFyaWFibGUuIFF1YW50aXRhdGl2ZSB2YXJpYWJsZXMgdGVuZCB0byBiZSBlaXRoZXIgb3JkaW5hbCBvciBjb250aW51b3VzLiBJbiB0aGlzIGRhdGFzZXQsIGBhZ2VgIChpbiBtb250aHMpIGNhbiBvbmx5IHRha2Ugb24gYSBsaW1pdGVkIHNldCBvZiB2YWx1ZXM6CgpgYGB7cn0Kc291bmRzICU+JSAKICBkaXN0aW5jdChhZ2UpICU+JSAKICBwdWxsCmBgYAoKSG93ZXZlciwgaW4gdGhlIGZvbGxvd2luZyBwbG90cywgd2UnbGwgdHJlYXQgYWdlIGFzIGEgY29udGludW91cyB2YXJpYWJsZSBwbG90dGVkIGFjcm9zcyB0aGUgeC1heGlzLiBJbiBzb21lIGNvbnRleHRzLCB0aGlzIGtpbmQgb2YgdmFyaWFibGUgY291bGQgYmUgdHJlYXRlZCBhcyBhIG9yZGluYWwgdmFyaWFibGUuIEhvd2V2ZXIsIGZvciBjb2xvciBwdXJwb3NlcywgdGhpcyB3b3VsZCBub3QgaWRlYWwgaGVyZSBzaW5jZSB0aGVyZSBhcmUgMTEgImNhdGVnb3JpZXMiIChzZWUgaHR0cDovL3NlcmlhbG1lbnRvci5jb20vZGF0YXZpei9jb2xvci1waXRmYWxscy5odG1sKS4gQWdlIGhhcyBhIG5hdHVyYWwgYW5kIG1lYW5pbmdmdWwgb3JkZXI6IGEgY2hpbGQgd2hvIGlzIDkgbW9udGhzIG9sZCBpcyAxIG1vbnRoIG9sZGVyIHRoYW4gb25lIHdobyBpcyA4IG1vbnRocyBvbGQuIFNvLCB3ZSdsbCB1c2UgdGhhdCBuYXR1cmFsIG9yZGVyaW5nIHRvIG91ciBhZHZhbnRhZ2UgYW5kIG5vdCB1c2UgY29sb3IgdG8gcmVwcmVzZW50IGFnZSBhcyBhIHZhcmlhYmxlLiBXaGVuIHlvdSAqZG8qIGFwcGx5IGEgY29udGludW91cyBjb2xvciBwYWxldHRlLCB5b3UnbGwgd2FudCB0byB1c2UgY29sb3IgdG8geW91ciBhZHZhbnRhZ2UgdG8gW3JlcHJlc2VudCBkYXRhIHZhbHVlc10oaHR0cDovL3NlcmlhbG1lbnRvci5jb20vZGF0YXZpei9jb2xvci1iYXNpY3MuaHRtbCNjb2xvci10by1yZXByZXNlbnQtZGF0YS12YWx1ZXMpLgoKIyBLbm93IHlvdXIgZGF0YQoKPGRpdiBjbGFzcz0icGFuZWwgcGFuZWwtc3VjY2VzcyI+CiAgPGRpdiBjbGFzcz0icGFuZWwtaGVhZGluZyI+Q2hhbGxlbmdlICMxOjwvZGl2PgogIDxkaXYgY2xhc3M9InBhbmVsLWJvZHkiPgotIEhvdyBtYW55IHZhcmlhYmxlcz8KICAgIC0gV2hpY2ggdmFyaWFibGVzIGFyZSBjb250aW51b3VzPwogICAgLSBXaGljaCBvbmVzIGFyZSBjYXRlZ29yaWNhbCBvciBvcmRpbmFsPwotIEhvdyBtYW55IHRvdGFsIGtpZHMgZG8gd2UgaGF2ZSBkYXRhIGZvcj8KLSBIb3cgbWFueSBhZ2VzIChpbiBtb250aHMpPwogIC0gSG93IG1hbnkga2lkcyBwZXIgYWdlPwotIEhvdyBtYW55IHR5cGVzIG9mIGFuaW1hbCBzb3VuZHM/IFdoYXQgYXJlIHRoZXk/CiAgPC9kaXY+CjwvZGl2PgoKTGV0J3Mgc3RhcnQganVzdCBieSBnZXR0aW5nIGEgZmVlbCBmb3IgaG93IG1hbnkga2lkcyBwcm9kdWNlIGVhY2gga2luZCBvZiBzb3VuZCwgYWNyb3NzIHRoZSBmdWxsIGFnZSByYW5nZS4gV2UgY291bGQgbWFrZSBhIHRhYmxlOgoKYGBge3J9CnNvdW5kcyAlPiUgCiAgZ3JvdXBfYnkoc291bmQpICU+JSAKICBzdW1tYXJpemUodG90YWxfcHJvZHVjZSA9IHN1bShraWRzX3Byb2R1Y2UpKSAlPiUgCiAga25pdHI6OmthYmxlKCkKYGBgCgpPciB3ZSBjb3VsZCBtYWtlIGEgc2ltcGxlIGJhciBwbG90OgoKYGBge3J9CmdncGxvdChzb3VuZHMsIGFlcyh4ID0gc291bmQsIHkgPSBraWRzX3Byb2R1Y2UpKSArIAogIGdlb21fY29sKCkgKwogIGxhYnMoeCA9ICJTb3VuZCIsIHkgPSAiVG90YWwgQ2hpbGRyZW4gUHJvZHVjaW5nIikKYGBgCgpGb3IgdGhpcyBraW5kIG9mIHBsb3QsIHdlIGRvbid0IHJlYWxseSBuZWVkIGNvbG9yLiBXaGF0IGlmIHdlIHdhbnQgdG8gc2VlIGhvdyB0aGUgbnVtYmVyIG9mIGtpZHMgd2hvIHByb2R1Y2UgZWFjaCBzb3VuZCB2YXJpZXMgYnkgYWdlPyBXZSdsbCBjaGFuZ2UgdGhlIHgtYXhpcyB0byBhZ2UgYW5kIGluc3RlYWQgYGZhY2V0X3dyYXBgIGJ5IGBzb3VuZGAsIGFuZCBtYWtlIHRoZSB5LWF4aXMgYSBwcm9wb3J0aW9uIGluc3RlYWQgb2YgY291bnRzLgoKYGBge3J9CmdncGxvdChzb3VuZHMsIGFlcyh4ID0gYWdlLCB5ID0gcHJvcF9wcm9kdWNlKSkgKyAKICBnZW9tX2NvbCgpICsKICBsYWJzKHggPSAiQWdlIChtb3MpIiwgeSA9ICJQcm9wb3J0aW9uIG9mIENoaWxkcmVuIFByb2R1Y2luZyIpICsKICBmYWNldF93cmFwKH5zb3VuZCkKYGBgCgpUaGUgYmFyIGdlb20gbWFrZXMgdGhpcyBhIGxpdHRsZSBoYXJkIHRvIHJlYWQgYW5kIGNvbXBhcmUgYWNyb3NzIGZhY2V0cyB0aG91Z2guIExldCdzIHRyeSBwb2ludHMgaW5zdGVhZC4KCmBgYHtyfQpnZ3Bsb3Qoc291bmRzLCBhZXMoeCA9IGFnZSwgeSA9IHByb3BfcHJvZHVjZSkpICsgCiAgZ2VvbV9wb2ludCgpICsKICBsYWJzKHggPSAiQWdlIChtb3MpIiwgeSA9ICJQcm9wb3J0aW9uIG9mIENoaWxkcmVuIFByb2R1Y2luZyIpICsKICBmYWNldF93cmFwKH5zb3VuZCkKYGBgCgpUaGF0IGlzIGEgbGl0dGxlIGJldHRlciEgRmFjZXRzIGFsbG93IHVzIHRvIHBhcnNlIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0d28gcXVhbnRpdGF0aXZlIHZhcmlhYmxlcyAoaGVyZSwgYWdlIGFuZCBwcm9wb3J0aW9uIG9mIGtpZHMgcHJvZHVjaW5nKSBieSBhIHF1YWxpdGF0aXZlIHZhcmlhYmxlIChoZXJlLCB0eXBlIG9mIHNvdW5kKS4gQW5vdGhlciB3YXkgd2UgY291bGQgZG8gdGhpcywgaW5zdGVhZCBvZiBmYWNldHRpbmcsIGlzIHRvIHVzZSBjb2xvci4gVGhpcyB3b3VsZCBtYWtlIGl0IGVhc2llciB0byBjb21wYXJlIHByb3BvcnRpb25zIGF0IGVhY2ggYWdlLgoKCgoKIyBEaXNjcmV0ZSBjb2xvcnMKCkxldCdzIHN0YXJ0IHdpdGggYSBiYXNlIHBsb3Qgd2l0aCBhZ2UgKGluIG1vbnRocykgYWxvbmcgdGhlIHgtYXhpcyBhbmQgdGhlIHByb3BvcnRpb24gb2YgY2hpbGRyZW4gcHJvZHVjaW5nIGVhY2ggd29yZCBhbG9uZyB0aGUgeS1heGlzLCB1c2luZyBwb2ludHMgYXMgdGhlIGdlb21ldHJpYyBvYmplY3QuIFNldCB0aGUgc2l6ZSBvZiB0aGUgcG9pbnRzIHRvIDIgYW5kIGNoYW5nZSB0aGUgeC0gYW5kIHktYXhpcyBsYWJlbHMgdG8gIkFnZSAobW9udGhzKSIgYW5kICJQcm9wb3J0aW9uIG9mIENoaWxkcmVuIFByb2R1Y2luZyIsIHJlc3BlY3RpdmVseS4gCgpgYGB7cn0KZ2dwbG90KHNvdW5kcywgYWVzKHggPSBhZ2UsIHkgPSBwcm9wX3Byb2R1Y2UpKSArIAogIGdlb21fcG9pbnQoc2l6ZSA9IDIpICsKICBsYWJzKHggPSAiQWdlIChtb250aHMpIiwgeSA9ICJQcm9wb3J0aW9uIG9mIENoaWxkcmVuIFByb2R1Y2luZyIpCmBgYAoKCgojIyBEZWZhdWx0IGRpc2NyZXRlIHBhbGV0dGUKCjxkaXYgY2xhc3M9InBhbmVsIHBhbmVsLXN1Y2Nlc3MiPgogIDxkaXYgY2xhc3M9InBhbmVsLWhlYWRpbmciPkNoYWxsZW5nZSAjMjo8L2Rpdj4KICA8ZGl2IGNsYXNzPSJwYW5lbC1ib2R5Ij4KVGFrZSB0aGUgcGxvdCB3ZSBqdXN0IG1hZGUsIGFuZCBlZGl0IHRoZSBjb2RlIHRvIG1hcCB0aGUgY29sb3Igb2YgdGhlIHBvaW50cyB0byB0aGUgdHlwZSBvZiBzb3VuZCBwcm9kdWNlZCAqYXQgdGhlIGdlb20gbGV2ZWwqLiBUaGUgY29sb3JzIHRoYXQgc2hvdyB1cCBhcmUgdGhlIGRlZmF1bHQgZGlzY3JldGUgcGFsZXR0ZSBpbiBgZ2dwbG90MmAuCgpgYGB7cn0KZ2dwbG90KHNvdW5kcywgYWVzKHggPSBhZ2UsIHkgPSBwcm9wX3Byb2R1Y2UpKSArIAogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gc291bmQpLCBzaXplID0gMikgKwogIGxhYnMoeCA9ICJBZ2UgKG1vbnRocykiLCB5ID0gIlByb3BvcnRpb24gb2YgQ2hpbGRyZW4gUHJvZHVjaW5nIikKYGBgCiAgPC9kaXY+CjwvZGl2PgoKCjxkaXYgY2xhc3M9InBhbmVsIHBhbmVsLXN1Y2Nlc3MiPgogIDxkaXYgY2xhc3M9InBhbmVsLWhlYWRpbmciPkNoYWxsZW5nZSAjMzo8L2Rpdj4KICA8ZGl2IGNsYXNzPSJwYW5lbC1ib2R5Ij4KVHJ5IGFkZGluZyBgZ2VvbV9saW5lKClgIHRvIHRoaXMgcGxvdCB0byBjb25uZWN0IHRoZSBkb3RzLiBEb2VzIHRoaXMgbG9vayByaWdodD8gVXNlIGA/Z2VvbV9saW5lYCB0byBmaWd1cmUgb3V0IGhvdyB0aGlzIGdlb20gY29ubmVjdHMgdGhlIGRvdHMgYnkgZGVmYXVsdCwgYW5kIHdoaWNoIGFlc3RoZXRpYyBjYW4gYmUgdXNlZCB0byBjb25uZWN0IGNhc2VzIHRvZ2V0aGVyLiBUcnkgZWRpdGluZyB5b3VyIGNvZGUgdG8gZHJhdyAzIGJsYWNrIGxpbmVzLSBvbmUgZm9yIGVhY2ggc291bmQuCgoKYGBge3J9CiMgRG9lcyB0aGlzIGxvb2sgcmlnaHQ/IG5vIQpnZ3Bsb3Qoc291bmRzLCBhZXMoeCA9IGFnZSwgeSA9IHByb3BfcHJvZHVjZSkpICsgCiAgZ2VvbV9saW5lKCkgKwogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gc291bmQpLCBzaXplID0gMikgKwogIGxhYnMoeCA9ICJBZ2UgKG1vbnRocykiLCB5ID0gIlByb3BvcnRpb24gb2YgQ2hpbGRyZW4gUHJvZHVjaW5nIikgCmBgYAoKCmBgYHtyfQojIEEgcG9zc2libGUgc29sdXRpb24KZ2dwbG90KHNvdW5kcywgYWVzKHggPSBhZ2UsIHkgPSBwcm9wX3Byb2R1Y2UpKSArIAogIGdlb21fbGluZShhZXMoZ3JvdXAgPSBzb3VuZCkpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IHNvdW5kKSwgc2l6ZSA9IDIpICsKICBsYWJzKHggPSAiQWdlIChtb250aHMpIiwgeSA9ICJQcm9wb3J0aW9uIG9mIENoaWxkcmVuIFByb2R1Y2luZyIpIApgYGAKCiAgPC9kaXY+CjwvZGl2PgoKPGRpdiBjbGFzcz0icGFuZWwgcGFuZWwtc3VjY2VzcyI+CiAgPGRpdiBjbGFzcz0icGFuZWwtaGVhZGluZyI+Q2hhbGxlbmdlICM0OjwvZGl2PgogIDxkaXYgY2xhc3M9InBhbmVsLWJvZHkiPgpNYWtlIHR3byBwbG90czoKCjEuIFJlY3JlYXRlIHRoZSBwbG90IGFib3ZlLCBidXQgdGhpcyB0aW1lIG1hcCBjb2xvciB0byB0aGUgdHlwZSBvZiBzb3VuZCBwcm9kdWNlZCBmb3IgYm90aCB0aGUgcG9pbnQgYW5kIGxpbmUgZ2VvbXMuIFBheSBhdHRlbnRpb24gdG8gdGhlIG9yZGVyIG9mIHRoZSBsYXllcnMgeW91IGFyZSBhZGRpbmctIHlvdSBtYXkgd2lzaCB0byBwbGFjZSBgZ2VvbV9saW5lYCAqYmVmb3JlKiBgZ2VvbV9wb2ludGAgc28gdGhlIGxpbmVzIGFyZSBhbHdheXMgInBhaW50ZWQiIHVuZGVybmVhdGggdGhlIHBvaW50cy4KCjIuIEluc3RlYWQgb2YgYGdlb21fbGluZWAsIGFkZCBhIGxvZXNzIGxpbmUgdXNpbmcgYGdlb21fc21vb3RoYC4gVXNlIGA/Z2VvbV9zbW9vdGhgIHRvIGZpZ3VyZSBvdXQgaG93IHRvIGdldCByaWQgb2YgdGhlIGdyZXkgc3RhbmRhcmQgZXJyb3IgcmliYm9uLiBZb3UgbWF5IGFsc28gd2FudCB0byBpbmNyZWFzZSB0aGUgbGluZSB3aWR0aC4gCgpgYGB7cn0KIyBEb2VzIHRoaXMgbG9vayByaWdodD8geWVzIQpnZ3Bsb3Qoc291bmRzLCBhZXMoeCA9IGFnZSwgeSA9IHByb3BfcHJvZHVjZSwgY29sb3IgPSBzb3VuZCkpICsgCiAgZ2VvbV9saW5lKCkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDIpICsKICBsYWJzKHggPSAiQWdlIChtb250aHMpIiwgeSA9ICJQcm9wb3J0aW9uIG9mIENoaWxkcmVuIFByb2R1Y2luZyIpIAoKZ2dwbG90KHNvdW5kcywgYWVzKHggPSBhZ2UsIAogICAgICAgICAgICAgICAgICAgICAgICAgeSA9IHByb3BfcHJvZHVjZSwgCiAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IHNvdW5kKSkgKyAKICBnZW9tX3Ntb290aChzZSA9IEZBTFNFLCBsd2QgPSAuNSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDIpICArCiAgbGFicyh4ID0gIkFnZSAobW9udGhzKSIsIHkgPSAiUHJvcG9ydGlvbiBvZiBDaGlsZHJlbiBQcm9kdWNpbmciKSAKYGBgCgogIDwvZGl2Pgo8L2Rpdj4KCldoeSBkb2VzIHRoaXMgd29yaz8gVG8gdGVsbCBgZ2VvbV9saW5lYCBob3cgdG8gY29ubmVjdCB5b3VyIGRvdHMsIHlvdSBjYW4gZWl0aGVyOgoKLSBNYXAgdGhlIGBncm91cGAgYWVzdGhldGljIChzbyBgYWVzKGdyb3VwID0gc291bmQpYCksIG9yIAotIE1hcCB0aGUgYGNvbG9yYCBhZXN0aGV0aWMgZ2xvYmFsbHkgKGBhZXMoY29sb3IgPSBzb3VuZClgLiAKCkJlY2F1c2UgYGdlb21fbGluZWAgdW5kZXJzdGFuZHMgdGhlIGBjb2xvcmAgYWVzdGhldGljLCBpdCB3aWxsIHRyeSB0byBkcmF3IHNlcGFyYXRlIGxpbmVzIGZvciBlYWNoIGNvbG9yLiBIZXJlIHRoYXQgdHJhbnNsYXRlcyB0byB0aHJlZSBsaW5lcywgb25lIGZvciBlYWNoIHNvdW5kLCB3aGljaCBpcyB3aGF0IHdlIHdhbnQhCgojIyBCcmllZiBhc2lkZTogZmFjdG9ycwoKQXQgdGhpcyBwb2ludCwgb3VyIHBsb3QgaXMgbG9va2luZyBwcmV0dHkgZ29vZC4gQnV0IHlvdSBtYXkgaGF2ZSBub3RpY2VkIHRoYXQgdGhlIGxlZ2VuZCBvcmRlciBkb2Vzbid0IG1hdGNoIHRoZSBvcmRlciBvZiB0aGUgbGluZXMgaW4gdGhlIHBsb3QuICoqUXVlc3Rpb246Kiogd2h5IGlzIHRoaXMgYW4gaXNzdWU/CgpXaGF0IGRldGVybWluZXMgdGhlIG9yZGVyIG9mIGxldmVscyBpbiB0aGUgbGVnZW5kPyBUaGUgb3JkZXIgb2YgbGV2ZWxzIGluIHRoZSB1bmRlcmx5aW5nIGZhY3RvcjoKCmBgYHtyfQpsZXZlbHMoYXMuZmFjdG9yKHNvdW5kcyRzb3VuZCkpCmBgYAoKSW4gdGhpcyBjYXNlLCBzaW5jZSB3ZSBoYXZlbid0IHNldCB0aGVtLCBSIHdpbGwgcGljayBhbiBvcmRlciBmb3IgdXMuCgpXZSBfY291bGRfIG1hbnVhbGx5IHJlLW9yZGVyIHRoZSBsZXZlbHMgb2YgdGhlIGZhY3RvciwgYnV0IGRpZmZlcmVudCBwbG90cyBtaWdodCBuZWNlc3NpdGF0ZSBkaWZmZXJlbnQgZmFjdG9yIG9yZGVyaW5nLCBhbmQgaWYgd2UgaGF2ZSBtb3JlIHRoYW4gdHdvIG9yIHRocmVlIGxldmVscywgdHlwaW5nIHRoZW0gcmVwZWF0ZWRseSBnZXRzIHRlZGlvdXMgZmFzdC4gSW5zdGVhZCwgbGV0J3MgaGF2ZSBSIGRvIGl0IQoKVGhlIFtgZm9yY2F0c2AgcGFja2FnZV0oaHR0cDovL2ZvcmNhdHMudGlkeXZlcnNlLm9yZyksIGlzIGBmb3JgIGBjYXRgZWdvcmljYWwgdmFyaWFibGVzIGFuZCBoYXMgbG90cyBvZiB1c2VmdWwgZnVuY3Rpb25zLCBpbmNsdWRpbmcgc29tZSBmb3IgcmUtb3JkZXJpbmcgbGV2ZWxzLiBUaGVyZSBhcmUgbG90cyBvZiBmdW5jdGlvbnMgaW4gYGZvcmNhdHNgLCBhbmQgeW91IGNhbiBpbnN0YWxsICYgbG9hZCBpdCBzZXBhcmF0ZWx5LCBhbHRob3VnaCBgZm9yY2F0c2AgaXMgbG9hZGVkIHdpdGggdGhlIGB0aWR5dmVyc2VgLgoKYGBge3IgZXZhbCA9IEZBTFNFfQppbnN0YWxsLnBhY2thZ2VzKCJmb3JjYXRzIikKbGlicmFyeShmb3JjYXRzKQpgYGAKCldlJ2xsIHVzZSB0aGUgYGZjdF9yZW9yZGVyMmAgZnVuY3Rpb24sIHdoaWNoIGJ5IGRlZmF1bHQgd2lsbCByZS1vcmRlciB0aGUgbGV2ZWxzIG9mIGEgZmFjdG9yIGJhc2VkIG9uIHRoZSBvcmRlciBvZiBvY2N1cnJlbmNlIG9mIG9uZSB2YXJpYWJsZSAoYHlgIGluIHRoZSBkb2NzKSB3aGVuIHRoZSBkYXRhZnJhbWUgaXMgX3NvcnRlZF8gYnkgYW5vdGhlciB2YXJpYWJsZSAoYHhgIGluIHRoZSBkb2NzKToKCmBgYHtyfQojICJTb3J0IHRoZSBkYXRhZnJhbWUgYnkgYWdlLCBmaW5kIHRoZSBsYXN0IG9jY3VycmVuY2Ugb2YgZWFjaCBsZXZlbCBvZiBzb3VuZHMkc291bmQgaW4gb3JkZXIgb2YgcHJvcF9wcm9kdWNlCmZjdF9yZW9yZGVyMigKICBhcy5mYWN0b3Ioc291bmRzJHNvdW5kKSwgCiAgc291bmRzJGFnZSwgIyB2YXJpYWJsZSAieCIKICBzb3VuZHMkcHJvcF9wcm9kdWNlICMgdmFyaWJsZSAieSIKKSAlPiUgbGV2ZWxzCmBgYAoKCgpUaGlzIChzb21laHdhdCBjb252b2x1dGVkKSBwcm9jZWR1cmUgaXMgdmVyeSB1c2VmdWwgZm9yIHdoZW4geW91IGhhdmUgYSBsaW5lIGNoYXJ0IG9mIHR3byBxdWFudGl0YXRpdmUgdmFyaWFibGVzLCBjb2xvcmVkIGJ5IGEgZmFjdG9yIHZhcmlhYmxlLiBMZXQncyBzZWUgdGhlIGRpZmZlcmVuY2U6CgpgYGB7cn0Kc291bmRzIDwtIHNvdW5kcyAlPiUgCiAgbXV0YXRlKHNvdW5kID0gYXMuZmFjdG9yKHNvdW5kKSkKCnNvdW5kX3RyYWogPC0gZ2dwbG90KHNvdW5kcywgYWVzKHggPSBhZ2UsIAogICAgICAgICAgICAgICAgICAgICAgICAgeSA9IHByb3BfcHJvZHVjZSwgCiAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IGZjdF9yZW9yZGVyMihzb3VuZCwgYWdlLCBwcm9wX3Byb2R1Y2UpKSkgKwogIGdlb21fc21vb3RoKHNlID0gRkFMU0UsIGx3ZCA9IC41KSArCiAgZ2VvbV9wb2ludChzaXplID0gMikgKwogIGxhYnMoeCA9ICJBZ2UgKG1vbnRocykiLCAKICAgICAgIHkgPSAiUHJvcG9ydGlvbiBvZiBDaGlsZHJlbiBQcm9kdWNpbmciLCAKICAgICAgIGNvbG9yID0gInNvdW5kIikKc291bmRfdHJhagpgYGAKCk1VQ0ggQkVUVEVSISBTYXZlIHlvdXIgcGxvdCBvYmplY3QgYXMgYHNvdW5kX3RyYWpgLiBOb3cgd2UgY2FuIHN0YXJ0IHBsYXlpbmcgd2l0aCB0aGUgYWN0dWFsIGNvbG9ycy4KCiMjIFNldCBsdW1pbmFuY2UgYW5kIHNhdHVyYXRpb24gKGNocm9tYXRpY2l0eSkKClRoZSBkZWZhdWx0IHF1YWxpdGF0aXZlIHBhbGV0dGUgd29ya3MgZmluZSBoZXJlLiBUaGUgYWRkaXRpb24gb2YgW2BzY2FsZV9jb2xvcl9odWVgXShodHRwOi8vZ2dwbG90Mi50aWR5dmVyc2Uub3JnL3JlZmVyZW5jZS9zY2FsZV9odWUuaHRtbCkgY2hhbmdlcyBub3RoaW5nLgoKYGBge3J9CnNvdW5kX3RyYWogKwogIHNjYWxlX2NvbG9yX2h1ZSgpCmBgYAoKV2UgY2FuIGFsc28gY2hhbmdlIHRoZXNlIHNldHRpbmdzIHdpdGhpbiB0aGUgZGVmYXVsdCBjb2xvciBwYWxldHRlLCB3aGVyZSB0aGUgYXJndW1lbnRzIGFyZToKCi0gYGhgID0gcmFuZ2Ugb2YgaHVlcyB0byB1c2UsIGluIFswLCAzNjBdCi0gYGxgID0gbHVtaW5hbmNlIChsaWdodG5lc3MpCi0gYGNgID0gY2hyb21hIChpbnRlbnNpdHkgb2YgY29sb3IpCgpgYGB7cn0KIyBDaGFuZ2UgaHVlIChsIGFuZCBjIGFyZSBkZWZhdWx0cykKc291bmRfdHJhaiArCiAgc2NhbGVfY29sb3JfaHVlKGggPSBjKDAsIDkwKSwgbCA9IDY1LCBjID0gMTAwKQoKIyBVc2UgbHVtaW5hbmNlPTQ1LCBpbnN0ZWFkIG9mIGRlZmF1bHQgNjUKc291bmRfdHJhaiArCiAgc2NhbGVfY29sb3JfaHVlKGwgPSA0NSkKCiMgUmVkdWNlIHNhdHVyYXRpb24gKGNocm9tYSkgZnJvbSAxMDAgdG8gNTAsIGFuZCBpbmNyZWFzZSBsdW1pbmFuY2UKc291bmRfdHJhaiArCiAgc2NhbGVfY29sb3JfaHVlKGwgPSA3NSwgYyA9IDUwKQpgYGAKCiMjIFNldCBkaXNjcmV0ZSBjb2xvcnMKCldlIGNhbiBjaGFuZ2UgdGhlIGFjdHVhbCBjb2xvcnMgdXNlZCBieSBhZGRpbmcgdGhlIGxheWVyIGBzY2FsZV9jb2xvcl9tYW51YWxgIG9yIGBzY2FsZV9maWxsX21hbnVhbGAuIENvbmZ1c2lvbiBiZXR3ZWVuIHdoaWNoIHRvIHVzZSB3aGVuIGlzIG9mdGVuIHRoZSBjYXVzZSBvZiBtdWNoIGZydXN0cmF0aW9uIQoKVG8gbmFtZSBtb3JlIHRoYW4gb25lIGNvbG9yLCB3aGljaCB5b3Ugb2Z0ZW4gd2FudCB0byBkbywgdXNlIGBjKClgLiBJbiB0aGUgcGFyZW50aGVzZXMsIG5hbWVkIGNvbG9ycyBhbmQgaGV4IGNvbG9ycyBhcmUgYWx3YXlzIGluIHF1b3Rlcy4KCmBgYHtyfQpzb3VuZF90cmFqICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYygiY29ybmZsb3dlcmJsdWUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAic2VhZ3JlZW4iLCAiY29yYWwiKSkKYGBgCgpUaGVyZSBhcmUgbWFueSBbbmFtZWQgY29sb3JzXShodHRwOi8vd3d3LnN0YXQuY29sdW1iaWEuZWR1L350emhlbmcvZmlsZXMvUmNvbG9yLnBkZikgYXZhaWxhYmxlIGluIFIhCgo8ZGl2IGNsYXNzPSJwYW5lbCBwYW5lbC1zdWNjZXNzIj4KICA8ZGl2IGNsYXNzPSJwYW5lbC1oZWFkaW5nIj5DaGFsbGVuZ2UgIzU6PC9kaXY+CiAgPGRpdiBjbGFzcz0icGFuZWwtYm9keSI+ClZpZXcgdGhlIGNvZGUgYmxvY2tzIGJlbG93LiBDb3B5IGFuZCBwYXN0ZSB0aGUgY29kZSB0byBydW4gdGhlbSBpbiB5b3VyIG93biBmaWxlLiBXaHkgZG8gbmVpdGhlciBvZiB0aGUgZm9sbG93aW5nIGNvZGUgYmxvY2tzIGNoYW5nZSB0aGUgY29sb3JzIG9mIHRoZSBwb2ludHMgYW5kIGxpbmVzPyBVc2UgeW91ciB3b3JkcyA6KSAqKHRoZSBhbnN3ZXIgaXMgYmVsb3cgdGhlIGNoYWxsZW5nZSwgYnV0IHRyeSB0byB0cm91YmxlLXNob290IG9uIHlvdXIgb3duIGZpcnN0KSoKCmBgYHtyfQpnZ3Bsb3Qoc291bmRzLCBhZXMoeCA9IGFnZSwgCiAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gcHJvcF9wcm9kdWNlLCAKICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gZmN0X3Jlb3JkZXIyKHNvdW5kLCBhZ2UsIHByb3BfcHJvZHVjZSkpKSArIAogIGdlb21fc21vb3RoKHNlID0gRkFMU0UsIGx3ZCA9IC41KSArCiAgZ2VvbV9wb2ludChzaXplID0gMikgKwogIGxhYnMoeCA9ICJBZ2UgKG1vbnRocykiLCAKICAgICAgIHkgPSAiUHJvcG9ydGlvbiBvZiBDaGlsZHJlbiBQcm9kdWNpbmciLCAKICAgICAgIGNvbG9yID0gInNvdW5kIikgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoImNvcm5mbG93ZXJibHVlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJzZWFncmVlbiIsICJjb3JhbCIpKQpgYGAKCgoKYGBge3J9CmdncGxvdChzb3VuZHMsIGFlcyh4ID0gYWdlLCAKICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBwcm9wX3Byb2R1Y2UsIAogICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IGZjdF9yZW9yZGVyMihzb3VuZCwgYWdlLCBwcm9wX3Byb2R1Y2UpKSkgKyAKICBnZW9tX3Ntb290aChzZSA9IEZBTFNFLCBsd2QgPSAuNSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDIpICsKICBsYWJzKHggPSAiQWdlIChtb250aHMpIiwgCiAgICAgICB5ID0gIlByb3BvcnRpb24gb2YgQ2hpbGRyZW4gUHJvZHVjaW5nIiwgCiAgICAgICBmaWxsID0gInNvdW5kIikgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoImNvcm5mbG93ZXJibHVlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAic2VhZ3JlZW4iLCAiY29yYWwiKSkKYGBgCiAgPC9kaXY+CjwvZGl2PgoKQW5zd2VyczogCgotIEluIHRoZSBmaXJzdCwgd2UgdXNlZCBgc2NhbGVfZmlsbF9tYW51YWxgLCBidXQgdGhlIGluIHRoZSBnbG9iYWwgYWVzdGhldGljcywgd2UgbWFwcGVkIHRoZSBgY29sb3JgLCBub3QgYGZpbGxgLCBhZXN0aGV0aWMgb250byB0aGUgYHNvdW5kYCB2YXJpYWJsZS4KLSBJbiB0aGUgc2Vjb25kLCB3ZSBkaWQgZGVmaW5lIHRoZSBgZmlsbGAgYWVzdGhldGljIGFuZCB1c2VkIGBzY2FsZV9maWxsX21hbnVhbGAsIHNvIHRoYXQgaXMgZ29vZC4gQnV0IGBnZW9tX2xpbmVgIG9ubHkgdW5kZXJzdGFuZHMgdGhlIGBjb2xvcmAgYWVzdGhldGljLCBub3QgYGZpbGxgLiBBbmQgZm9yIGBnZW9tX3BvaW50YCwgdGhlIGRlZmF1bHQgc2hhcGUgZm9yIGlzIDE5LCB3aGljaCBkb2VzIG5vdCB1bmRlcnN0YW5kIHRoZSBgZmlsbGAgYWVzdGhldGljLgoKPGRpdiBjbGFzcz0icGFuZWwgcGFuZWwtc3VjY2VzcyI+CiAgPGRpdiBjbGFzcz0icGFuZWwtaGVhZGluZyI+Q2hhbGxlbmdlICM2OjwvZGl2PgogIDxkaXYgY2xhc3M9InBhbmVsLWJvZHkiPgpTdGFydCB3aXRoIHRoaXMgcGxvdDoKCmBgYHtyfQpzb3VuZF90cmFqCmBgYAoKQWRkIGEgYmxhY2sgb3V0bGluZSB0byB0aGUgcG9pbnRzLCBhbmQgY29sb3IgdGhlIGluc2lkZSBvZiB0aGUgcG9pbnRzIGFuZCB0aGUgbGluZXMgYnkgYHNvdW5kYCB1c2luZyB0aGUgZGVmYXVsdCBkaXNjcmV0ZSBjb2xvciBwYWxldHRlLiBZb3UgbWF5IGFsc28gd2lzaCB0byBlZGl0IHRoZSBsZWdlbmRzIG9uIHRoaXMgcGxvdDogYGdlb21fc21vb3RoYCBoYXMgYW4gYXJndW1lbnQgY2FsbGVkIGBzaG93LmxlZ2VuZCA9IEZBTFNFYC4gU2VlIGlmIHlvdSBwcmVmZXIgdGhlIHBsb3Qgd2l0aCB0aGlzIGNoYW5nZS4gCgpJZiB0aGlzIHdhcyBlYXN5LCB0cnkgYXBwbHlpbmcgdGhlIHNhbWUgY3VzdG9tIGNvbG9yIHBhbGV0dGUgdG8gdGhlIGluc2lkZSBvZiB0aGUgcG9pbnRzIGFuZCB0byB0aGUgbGluZXMuIAoKYGBge3J9CmdncGxvdChzb3VuZHMsIGFlcyh4ID0gYWdlLCAKICAgICAgICAgICAgICAgICAgIHkgPSBwcm9wX3Byb2R1Y2UsIAogICAgICAgICAgICAgICAgICAgZmlsbCA9IGZjdF9yZW9yZGVyMihzb3VuZCwgYWdlLCBwcm9wX3Byb2R1Y2UpKSkgKyAKICBnZW9tX3Ntb290aChhZXMoY29sb3IgPSBmY3RfcmVvcmRlcjIoc291bmQsIGFnZSwgcHJvcF9wcm9kdWNlKSksCiAgICAgICAgICAgICAgc2UgPSBGQUxTRSwgbHdkID0gLjUsIHNob3cubGVnZW5kID0gRkFMU0UpICsKICBnZW9tX3BvaW50KHNpemUgPSAyLCBzaGFwZSA9IDIxKSArCiAgbGFicyh4ID0gIkFnZSAobW9udGhzKSIsIAogICAgICAgeSA9ICJQcm9wb3J0aW9uIG9mIENoaWxkcmVuIFByb2R1Y2luZyIsIAogICAgICAgZmlsbCA9ICJzb3VuZCIpCmBgYAoKCgpgYGB7cn0KZ2dwbG90KHNvdW5kcywgYWVzKHggPSBhZ2UsIAogICAgICAgICAgICAgICAgICAgeSA9IHByb3BfcHJvZHVjZSwgCiAgICAgICAgICAgICAgICAgICBmaWxsID0gZmN0X3Jlb3JkZXIyKHNvdW5kLCBhZ2UsIHByb3BfcHJvZHVjZSkpKSArIAogIGdlb21fc21vb3RoKGFlcyhjb2xvciA9IGZjdF9yZW9yZGVyMihzb3VuZCwgYWdlLCBwcm9wX3Byb2R1Y2UpKSwKICAgICAgICAgICAgICBzZSA9IEZBTFNFLCBsd2QgPSAuNSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDIsIHNoYXBlID0gMjEpICsKICBsYWJzKHggPSAiQWdlIChtb250aHMpIiwgCiAgICAgICB5ID0gIlByb3BvcnRpb24gb2YgQ2hpbGRyZW4gUHJvZHVjaW5nIiwgCiAgICAgICBmaWxsID0gInNvdW5kIikgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoImNvcm5mbG93ZXJibHVlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAic2VhZ3JlZW4iLCAiY29yYWwiKSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCJjb3JuZmxvd2VyYmx1ZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInNlYWdyZWVuIiwgImNvcmFsIikpCmBgYAoKCiAgPC9kaXY+CjwvZGl2PgoKWW91IGNhbiBhbHNvIGRlZmluZSB5b3VyIGNvbG9yIHBhbGV0dGUgYXMgYSB2ZWN0b3Igb3V0c2lkZSBvZiBgZ2dwbG90MmAuIEJlbG93LCBJIG1hZGUgYW4gb2JqZWN0IGNhbGxlZCBgbXlfY29sb3JzYCBvdXRzaWRlIG9mIGBnZ3Bsb3QyYC4gVG8gdXNlIGl0LCB3ZSBjYWxsIHRoYXQgb2JqZWN0IHdpdGhpbiB0aGUgYHNjYWxlX2NvbG91cl9tYW51YWxgIGZ1bmN0aW9uLgoKYGBge3J9Cm15X2NvbG9ycyA8LSBjKCJjYWRldGJsdWUiLCAic3RlZWxibHVlIiwgInNhbG1vbiIpICMgcXVvdGUgY29sb3IgbmFtZXMKc291bmRfdHJhaiArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IG15X2NvbG9ycykgIyBub3RlOiBub3QgaW4gcXVvdGVzCmBgYAoKCjxkaXYgY2xhc3M9InBhbmVsIHBhbmVsLXN1Y2Nlc3MiPgogIDxkaXYgY2xhc3M9InBhbmVsLWhlYWRpbmciPkNoYWxsZW5nZSAjNzo8L2Rpdj4KICA8ZGl2IGNsYXNzPSJwYW5lbC1ib2R5Ij4KRGVmaW5lIGEgY3VzdG9tIGNvbG9yIHBhbGV0dGUgdXNpbmcgaGV4YWRlY2ltYWwgY29sb3JzICgjcnJnZ2JiKSwgYW5kIGFwcGx5IGl0IHVzaW5nIGBzY2FsZV9jb2xvcl9tYW51YWxgIHRvIHlvdXIgYHNvdW5kX3RyYWpgIHBsb3QuIFNvbWUgYmFzaWMgb25lcyBhcmUgaGVyZTogCgpodHRwczovL3Nhc2hhdC5tZS8yMDE3LzAxLzExL2xpc3Qtb2YtMjAtc2ltcGxlLWRpc3RpbmN0LWNvbG9ycy8KClBhcnNlIHRoZSBoZXhhZGVjaW1hbCBzdHJpbmcgbGlrZSBzbzogI3JyZ2diYiwgd2hlcmUgcnIsIGdnLCBhbmQgYmIgcmVmZXIgdG8gY29sb3IgaW50ZW5zaXR5IGluIHRoZSByZWQsIGdyZWVuLCBhbmQgYmx1ZSBjaGFubmVscywgcmVzcGVjdGl2ZWx5LiAKCgpgYGB7cn0KIyBmcm9tIGh0dHBzOi8vZ2l0aHViLmNvbS9td2Fza29tL3NlYWJvcm4vYmxvYi9tYXN0ZXIvc2VhYm9ybi9wYWxldHRlcy5weQpzYl9jb2xvcmJsaW5kIDwtIGMoIiMwMDcyQjIiLCAiIzAwOUU3MyIsICIjRDU1RTAwIiwKICAgICAgICAgICAgICAgICAgICAgICAgIiNDQzc5QTciLCAiI0YwRTQ0MiIsICIjNTZCNEU5IikKc291bmRfdHJhaiArCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBzYl9jb2xvcmJsaW5kKQpgYGAKCiAgPC9kaXY+CjwvZGl2PgoKIyMgQnVpbHQtaW4gZGlzY3JldGUgcGFsZXR0ZXMKCiMjIyBDb2xvcmJyZXdlcgoKVG8gdXNlIENvbG9yYnJld2VyIHBhbGV0dGVzLCB5b3UnbGwgbmVlZCB0byBpbnN0YWxsIHRoZSBgUkNvbG9yQnJld2VyYCBwYWNrYWdlIGZyb20gQ1JBTi4gVGhpcyBjaHVuayBvZiBjb2RlIHRlbGxzIHlvdSBob3c6CgpgYGB7ciBldmFsID0gRkFMU0V9Cmluc3RhbGwucGFja2FnZXMoIlJDb2xvckJyZXdlciIpCmxpYnJhcnkoUkNvbG9yQnJld2VyKQpgYGAKCkNvbG9yYnJld2VyIGhhcyBhIGZldyBxdWFsaXRhdGl2ZSBwYWxldHRlcyBuYW1lZDogQWNjZW50LCBEYXJrMiwgUGFpcmVkLCBQYXN0ZWwxLCBQYXN0ZWwyLCBTZXQxLCBTZXQyLCBTZXQzLiBIZXJlIGlzIGhvdyB0byB2aWV3IHRoZW06CgpgYGB7cn0KYnJld2VyLnBhbCg1LCAiRGFyazIiKSAjIGxpc3QgNSBoZXggY29sb3JzCmRpc3BsYXkuYnJld2VyLnBhbCg1LCAiRGFyazIiKSAjIHZpZXcgNSBoZXggY29sb3JzCmBgYAoKQW5kIGhlcmUgaXMgaG93IHlvdSB1c2UgdGhlbToKCmBgYHtyfQpzb3VuZF90cmFqICsKICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZSA9ICJEYXJrMiIpCmBgYAoKCiMjIyBXZXMgQW5kZXJzb24gcGFsZXR0ZXMgCgpNeSBmYXZvcml0ZSEgVG8gdXNlIFdlcyBBbmRlcnNvbiBwYWxldHRlcywgeW91J2xsIG5lZWQgdG8gaW5zdGFsbCB0aGUgYHdlc2FuZGVyc29uYCBwYWNrYWdlIGZyb20gQ1JBTi4gVGhpcyBjaHVuayBvZiBjb2RlIHRlbGxzIHlvdSBob3c6CgpgYGB7ciBldmFsID0gRkFMU0V9Cmluc3RhbGwucGFja2FnZXMoIndlc2FuZGVyc29uIikKbGlicmFyeSh3ZXNhbmRlcnNvbikKYGBgCgoKCmBgYHtyfQpuYW1lcyh3ZXNfcGFsZXR0ZXMpICMgYWxsIHRoZSBwYWxldHRlIG5hbWVzCndlc19wYWxldHRlKCJHcmFuZEJ1ZGFwZXN0MiIpICMgdmlldyBuYW1lZCBwYWxldHRlCndlc19wYWxldHRlKCJHcmFuZEJ1ZGFwZXN0MiIpWzE6NF0gIyBsaXN0IGZpcnN0IDQgaGV4IGNvbG9ycwp3ZXNfcGFsZXR0ZSgiR3JhbmRCdWRhcGVzdDIiKVtjKDEsNCldICMgbGlzdCBjb2xvcnMgMSBhbmQgNApgYGAKClRvIHVzZSB0aGVzZSBwYWxldHRlcywgdXNlIGBzY2FsZV9jb2xvcl9tYW51YWxgIHdoZXJlIGB2YWx1ZXNgIGlzIHNldCB0byBgd2VzX3BhbGV0dGUoIm5hbWUiKWAuIEZvciBleGFtcGxlOgoKYGBge3J9CnNvdW5kX3RyYWogKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSB3ZXNfcGFsZXR0ZSgiRGFyamVlbGluZzEiKSkKCnNvdW5kX3RyYWogKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSB3ZXNfcGFsZXR0ZSgiRmFudGFzdGljRm94MSIpKQpgYGAKCgo8ZGl2IGNsYXNzPSJwYW5lbCBwYW5lbC1zdWNjZXNzIj4KICA8ZGl2IGNsYXNzPSJwYW5lbC1oZWFkaW5nIj5DaGFsbGVuZ2UgIzg6PC9kaXY+CiAgPGRpdiBjbGFzcz0icGFuZWwtYm9keSI+CldoYXQgaWYgeW91IGp1c3QgZG9uJ3Qgd2FudCB0byB1c2UgdGhlIGNvbG9ycyBpbiB0aGUgb3JkZXIgdGhleSBhcmUgaW4/IFVzZSBhIGB3ZXNfcGFsZXR0ZWAgb2YgeW91ciBjaG9pY2UuIFVzaW5nIG91ciBjb2RlIGZyb20gYWJvdmUsIHRyeSBwaWNraW5nIHRoZSBsYXN0IDMgY29sb3JzIG9mIGEgcGFsZXR0ZS4gQWRkIGl0IHRvIHlvdXIgYHNvdW5kX3RyYWpgIHBsb3QuCgpJZiB0aGlzIHdhcyBlYXN5LCB0cnkgdXNpbmcgY29sb3JzIDIsIDMsIGFuZCA1IGluc3RlYWQuCgpgYGB7cn0Kc291bmRfdHJhaiArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHdlc19wYWxldHRlKCJEYXJqZWVsaW5nMSIpWzM6NV0pCgpzb3VuZF90cmFqICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gd2VzX3BhbGV0dGUoIkZhbnRhc3RpY0ZveDEiKVtjKDIsIDMsIDUpXSkKYGBgCiAgPC9kaXY+CjwvZGl2PgoKCiMjIyBgZ2d0aGVtZXNgIHBhbGV0dGVzCgpUbyB1c2UgdGhlc2UgcGFsZXR0ZXMsIHlvdSdsbCBuZWVkIHRvIGluc3RhbGwgdGhlIGBnZ3RoZW1lc2AgcGFja2FnZSBmcm9tIENSQU4uIFRoaXMgY2h1bmsgb2YgY29kZSB0ZWxscyB5b3UgaG93OgoKYGBge3IgZXZhbCA9IEZBTFNFfQppbnN0YWxsLnBhY2thZ2VzKCJnZ3RoZW1lcyIpCmxpYnJhcnkoZ2d0aGVtZXMpCmBgYAoKCgpgYGB7cn0Kc291bmRfdHJhaiArCiAgc2NhbGVfY29sb3JfZml2ZXRoaXJ0eWVpZ2h0KCkKCnNvdW5kX3RyYWogKwogIHNjYWxlX2NvbG9yX2Vjb25vbWlzdCgpCmBgYAoKIyMjIGBnZ3NjaWAgUGFsZXR0ZXMKCltgZ2dzY2lgXShodHRwczovL25hbngubWUvZ2dzY2kvKSBwcm92aWRlcyBjb2xvciBwYWxldHRlcyBkZXNpZ25lZCB0byBtYXRjaCB3aXRoIHRoZSBhZXN0aGV0aWNzIG9mIGEgd2lkZSB2YXJpZXR5IG9mIHNjaWVudGlmaWMgcHVibGlzaGVyczoKCmBgYHtyfQpsaWJyYXJ5KGdnc2NpKQoKc291bmRfdHJhaiArIHNjYWxlX2NvbG9yX25lam0oKQpgYGAKCgojIyMgUGFsZXR0ZXMgZnJvbSB0aGUgUXVlZW4gQmVlCgpUbyB1c2UgW0JleW9uY2UgcGFsZXR0ZXNdKGh0dHBzOi8vZ2l0aHViLmNvbS9kaWxsL2JleW9uY2UpLCB5b3UnbGwgbmVlZCB0byBpbnN0YWxsIHRoZSBgYmV5b25jZWAgcGFja2FnZSBmcm9tIEdpdEh1YiB1c2luZyBgZGV2dG9vbHM6Omluc3RhbGxfZ2l0aHViKClgLiBUaGlzIGNodW5rIG9mIGNvZGUgdGVsbHMgeW91IGhvdzoKCmBgYHtyIGV2YWwgPSBGQUxTRX0KaW5zdGFsbC5wYWNrYWdlcygiZGV2dG9vbHMiKQpkZXZ0b29sczo6aW5zdGFsbF9naXRodWIoImRpbGwvYmV5b25jZSIpCmxpYnJhcnkoYmV5b25jZSkKYGBgCgpOb3RlIHRoYXQgYSBudW1iZXIgb2Ygc3R1ZGVudHMgaGFkIGluc3RhbGxhdGlvbiBwcm9ibGVtcyB3aXRoIHRoaXMgcGFja2FnZSEgTW92ZSBvbiBpZiB5b3UgZG8uCgpgYGB7cn0KYmV5b25jZV9wYWxldHRlKDE4KQpgYGAKCmBgYHtyfQpzb3VuZF90cmFqICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gYmV5b25jZV9wYWxldHRlKDE4KVszOjVdKQpgYGAKCkhlcmUgd2UnbGwgb25seSB1c2UgdGhlIGZpcnN0LCBmb3VydGgsIGFuZCBmaWZ0aCBjb2xvcnMgaW4gdGhlIHBhbGV0dGUuCgpgYGB7cn0Kc291bmRfdHJhaiArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGJleW9uY2VfcGFsZXR0ZSgxOClbYygxLCA0LCA1KV0pCmBgYAoKIyMjIFZpcmlkaXMgcGFsZXR0ZXMKCj4gIlVzZSB0aGUgY29sb3Igc2NhbGVzIGluIHRoaXMgcGFja2FnZSB0byBtYWtlIHBsb3RzIHRoYXQgYXJlIHByZXR0eSwgYmV0dGVyIHJlcHJlc2VudCB5b3VyIGRhdGEsIGVhc2llciB0byByZWFkIGJ5IHRob3NlIHdpdGggY29sb3JibGluZG5lc3MsIGFuZCBwcmludCB3ZWxsIGluIGdyZXkgc2NhbGUuIgoKVG8gdXNlLCB5b3UnbGwgbmVlZCB0byBpbnN0YWxsIHRoZSBgdmlyaWRpc2AgcGFja2FnZSBmcm9tIENSQU4uIFRoaXMgY2h1bmsgb2YgY29kZSB0ZWxscyB5b3UgaG93OgoKYGBge3IgZXZhbCA9IEZBTFNFfQppbnN0YWxsLnBhY2thZ2VzKCJ2aXJpZGlzIikKbGlicmFyeSh2aXJpZGlzKQpgYGAKClJlYWQgbW9yZSBoZXJlIGluIHRoZSBbdmlyaWRpcyB2aWduZXR0ZV0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL3ZpcmlkaXMvdmlnbmV0dGVzL2ludHJvLXRvLXZpcmlkaXMuaHRtbCkuIFRoZSBkZWZhdWx0IGFyZ3VtZW50IGZvciBgZGlzY3JldGVgIGlzIEZBTFNFLCBzbyB0byB1c2UgdGhlIGRpc2NyZXRlIHBhbGV0dGVzIHlvdSBuZWVkIHRvIHNldCBgZGlzY3JldGUgPSBUUlVFYC4gVGhlcmUgYXJlIGZvdXIgY29sb3JtYXAgb3B0aW9ucyBhdmFpbGFibGU6CgotICJtYWdtYSIgKG9yICJBIiksCi0gImluZmVybm8iIChvciAiQiIpLAotICJwbGFzbWEiIChvciAiQyIpLAotICJ2aXJpZGlzIiAob3IgIkQiLCB0aGUgZGVmYXVsdCBvcHRpb24pLgoKYGBge3J9CnNvdW5kX3RyYWogKwogIHNjYWxlX2NvbG9yX3ZpcmlkaXMoZGlzY3JldGUgPSBUUlVFKSArCiAgdGhlbWVfbWluaW1hbCgpCgpzb3VuZF90cmFqICsKICBzY2FsZV9jb2xvcl92aXJpZGlzKGRpc2NyZXRlID0gVFJVRSwgb3B0aW9uID0gInBsYXNtYSIpICsKICB0aGVtZV9taW5pbWFsKCkKYGBgCgo8ZGl2IGNsYXNzPSJwYW5lbCBwYW5lbC1zdWNjZXNzIj4KICA8ZGl2IGNsYXNzPSJwYW5lbC1oZWFkaW5nIj5DaGFsbGVuZ2UgIzk6PC9kaXY+CiAgPGRpdiBjbGFzcz0icGFuZWwtYm9keSI+ClVzZSB0aGUgYHZpcmlkaXNgIHBhY2thZ2UgdG8gY29sb3IgdGhlIHBvaW50cyBieSBhbmQgdGhlIGxpbmVzIGJ5IGBzb3VuZGA7IG1ha2UgdGhlIG91dGxpbmUgb2YgdGhlIHBvaW50cyAibWlkbmlnaHRibHVlIi4gUGljayBhbnkgY29sb3JtYXAgb3B0aW9uLCBhbmQgcGxheSB3aXRoIGB0aGVtZV9id2Agb3IgYHRoZW1lX21pbmltYWxgIHRvIHNlZSB3aGF0IHlvdSBsaWtlLgoKYGBge3J9CmdncGxvdChzb3VuZHMsIGFlcyh4ID0gYWdlLCAKICAgICAgICAgICAgICAgICAgIHkgPSBwcm9wX3Byb2R1Y2UsIAogICAgICAgICAgICAgICAgICAgZmlsbCA9IGZjdF9yZW9yZGVyMihzb3VuZCwgYWdlLCBwcm9wX3Byb2R1Y2UpKSkgKyAKICBnZW9tX3Ntb290aChhZXMoY29sb3IgPSBmY3RfcmVvcmRlcjIoc291bmQsIGFnZSwgcHJvcF9wcm9kdWNlKSksCiAgICAgICAgICAgICAgc2UgPSBGQUxTRSwgbHdkID0gLjUsIHNob3cubGVnZW5kID0gRkFMU0UpICsKICBnZW9tX3BvaW50KHNpemUgPSAyLCBzaGFwZSA9IDIxLCBjb2xvdXIgPSAibWlkbmlnaHRibHVlIikgKwogIGxhYnMoeCA9ICJBZ2UgKG1vbnRocykiLCAKICAgICAgIHkgPSAiUHJvcG9ydGlvbiBvZiBDaGlsZHJlbiBQcm9kdWNpbmciLCAKICAgICAgIGZpbGwgPSAic291bmQiKSArCiAgc2NhbGVfZmlsbF92aXJpZGlzKGRpc2NyZXRlID0gVFJVRSkgKwogIHNjYWxlX2NvbG9yX3ZpcmlkaXMoZGlzY3JldGUgPSBUUlVFKSArCiAgdGhlbWVfbWluaW1hbCgpCmBgYAogIDwvZGl2Pgo8L2Rpdj4KCgoKCiMjIEdyZXlzY2FsZSBmb3IgZGlzY3JldGUKClVzZSBgc2NhbGVfY29sb3JfZ3JleWAgb3IgYHNjYWxlX2ZpbGxfZ3JleWAsIG9yIHNvbWV0aW1lcyBib3RoIGRlcGVuZGluZyBvbiB5b3VyIGdlb21zIGFuZCB0aGUgYWVzdGhldGljcyB0aGV5IHVuZGVyc3RhbmQuCgpgYGB7cn0Kc291bmRfdHJhaiArCiAgc2NhbGVfY29sb3JfZ3JleSgpICsKICB0aGVtZV9taW5pbWFsKCkKYGBgCgpTZXQgc3RhcnQgYW5kIGVuZAoKYGBge3J9CnNvdW5kX3RyYWogKwogIHNjYWxlX2NvbG9yX2dyZXkoc3RhcnQgPSAwLjIsIGVuZCA9IC44KSAKYGBgCgoKTWFrZSB0aGUgc2FtZSBwbG90IGJ1dCBtYWtlIHBvaW50cyBvdXRsaW5lZCBpbiBibGFjawoKYGBge3J9CmdncGxvdChzb3VuZHMsIGFlcyh4ID0gYWdlLCAKICAgICAgICAgICAgICAgICAgIHkgPSBwcm9wX3Byb2R1Y2UsIAogICAgICAgICAgICAgICAgICAgZmlsbCA9IGZjdF9yZW9yZGVyMihzb3VuZCwgYWdlLCBwcm9wX3Byb2R1Y2UpKSkgKyAKICBnZW9tX3Ntb290aChhZXMoY29sb3IgPSBmY3RfcmVvcmRlcjIoc291bmQsIGFnZSwgcHJvcF9wcm9kdWNlKSksCiAgICAgICAgICAgICAgc2UgPSBGQUxTRSwgbHdkID0gLjUsIHNob3cubGVnZW5kID0gRkFMU0UpICsKICBnZW9tX3BvaW50KHNpemUgPSAyLCBzaGFwZSA9IDIxKSArCiAgbGFicyh4ID0gIkFnZSAobW9udGhzKSIsIAogICAgICAgeSA9ICJQcm9wb3J0aW9uIG9mIENoaWxkcmVuIFByb2R1Y2luZyIsIAogICAgICAgZmlsbCA9ICJzb3VuZCIpICsKICBzY2FsZV9maWxsX2dyZXkoc3RhcnQgPSAwLjMsIGVuZCA9IDEpICsKICBzY2FsZV9jb2xvcl9ncmV5KHN0YXJ0ID0gMC4zLCBlbmQgPSAxKSAKYGBgCgpTdWdnZXN0IHJlZHVuZGFuY3kgaW4gZ3JleXNjYWxlLSB0cnkgY2hhbmdpbmcgbGluZSB0eXBlIGluc3RlYWQgb2YgbGluZSAob3IgaW4gYWRkaXRpb24gdG8pIGxpbmUgY29sb3IuCgoKQ2hhbmdlIGxpbmUgdHlwZSBieSBgc291bmRgLCBzZXQgY29sb3IgdG8gYmxhY2suCgpgYGB7cn0KZ2dwbG90KHNvdW5kcywgYWVzKHggPSBhZ2UsIAogICAgICAgICAgICAgICAgICAgeSA9IHByb3BfcHJvZHVjZSwgCiAgICAgICAgICAgICAgICAgICBmaWxsID0gZmN0X3Jlb3JkZXIyKHNvdW5kLCBhZ2UsIHByb3BfcHJvZHVjZSkpKSArIAogIGdlb21fc21vb3RoKGFlcyhsdHkgPSBmY3RfcmVvcmRlcjIoc291bmQsIGFnZSwgcHJvcF9wcm9kdWNlKSksIGNvbG9yID0gImJsYWNrIiwKICAgICAgICAgICAgICBzZSA9IEZBTFNFLCBsd2QgPSAuNSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDIsIHNoYXBlID0gMjEpICsKICBsYWJzKHggPSAiQWdlIChtb250aHMpIiwgCiAgICAgICB5ID0gIlByb3BvcnRpb24gb2YgQ2hpbGRyZW4gUHJvZHVjaW5nIiwgCiAgICAgICBmaWxsID0gInNvdW5kIikgKwogIHNjYWxlX2ZpbGxfZ3JleShzdGFydCA9IDAuMywgZW5kID0gMSkgCmBgYAoKQ2hhbmdlIGJvdGghCgpgYGB7cn0KZ2dwbG90KHNvdW5kcywgYWVzKHggPSBhZ2UsIAogICAgICAgICAgICAgICAgICAgeSA9IHByb3BfcHJvZHVjZSwgCiAgICAgICAgICAgICAgICAgICBmaWxsID0gZmN0X3Jlb3JkZXIyKHNvdW5kLCBhZ2UsIHByb3BfcHJvZHVjZSkpKSArIAogIGdlb21fc21vb3RoKGFlcyhjb2xvciA9IGZjdF9yZW9yZGVyMihzb3VuZCwgYWdlLCBwcm9wX3Byb2R1Y2UpLAogICAgICAgICAgICAgICAgICBsdHkgPSBmY3RfcmVvcmRlcjIoc291bmQsIGFnZSwgcHJvcF9wcm9kdWNlKSksCiAgICAgICAgICAgICAgc2UgPSBGQUxTRSwgbHdkID0gLjUsIHNob3cubGVnZW5kID0gRkFMU0UpICsKICBnZW9tX3BvaW50KHNpemUgPSAyLCBzaGFwZSA9IDIxKSArCiAgbGFicyh4ID0gIkFnZSAobW9udGhzKSIsIAogICAgICAgeSA9ICJQcm9wb3J0aW9uIG9mIENoaWxkcmVuIFByb2R1Y2luZyIsIAogICAgICAgZmlsbCA9ICJzb3VuZCIpICsKICBzY2FsZV9maWxsX2dyZXkoc3RhcnQgPSAwLjMsIGVuZCA9IC44KSArCiAgc2NhbGVfY29sb3JfZ3JleShzdGFydCA9IDAuMywgZW5kID0gLjgpIApgYGAKCiMjIENvbG9yYmxpbmQtZnJpZW5kbHkgcGFsZXR0ZXMKClRoZSBbYGNvbG9yYmxpbmRyYCBwYWNrYWdlXShodHRwczovL2dpdGh1Yi5jb20vY2xhdXN3aWxrZS9jb2xvcmJsaW5kcikgY2FuIGJlIHVzZWQgdG8gInNpbXVsYXRlIGNvbG9yYmxpbmRuZXNzIGluIHByb2R1Y3Rpb24tcmVhZHkgUiBmaWd1cmVzLiIgVG8gdXNlIHRoaXMgcGFja2FnZSwgeW91J2xsIG5lZWQgdG8gZmlyc3QgaW5zdGFsbCB0aGUgYGNvd3Bsb3RgIHBhY2thZ2UgZnJvbSBHaXRIdWIgdXNpbmcgYGRldnRvb2xzOjppbnN0YWxsX2dpdGh1YigpYC4gWW91J2xsIGFsc28gbmVlZCB0byBpbnN0YWxsIHRoZSBgY29sb3JzcGFjZWAgcGFja2FnZSBmcm9tIENSQU4uIEZpbmFsbHksIHlvdSBjYW4gdGhlbiB1c2UgYGRldnRvb2xzOjppbnN0YWxsX2dpdGh1YigpYCBhZ2FpbiB0byBpbnN0YWxsIHRoZSBgY29sb3JibGluZHJgIHBhY2thZ2UuIFRoaXMgY29kZSBjaHVuayBzaG93cyB5b3UgaG93IHRvIGRvIGFsbCAzIGluc3RhbGxzIHRvIHVzZSB0aGUgYGNvbG9yYmxpbmRyYCBwYWNrYWdlOgoKYGBge3IgZXZhbCA9IEZBTFNFfQpkZXZ0b29sczo6aW5zdGFsbF9naXRodWIoIndpbGtlbGFiL2Nvd3Bsb3QiKQppbnN0YWxsLnBhY2thZ2VzKCJjb2xvcnNwYWNlIiwgcmVwb3MgPSAiaHR0cDovL1ItRm9yZ2UuUi1wcm9qZWN0Lm9yZyIpCmRldnRvb2xzOjppbnN0YWxsX2dpdGh1YigiY2xhdXN3aWxrZS9jb2xvcmJsaW5kciIpCmBgYAoKVG8gdXNlOgpgYGB7cn0KIyBzYXZlIGEgZ2dwbG90IG9iamVjdApteV9zb3VuZF90cmFqIDwtIHNvdW5kX3RyYWogKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBiZXlvbmNlX3BhbGV0dGUoMTgpW2MoMSwgNCwgNSldKQpgYGAKClZpZXcgdGhhdCBmaWd1cmUgYWZ0ZXIgY29sb3ItdmlzaW9uLWRlZmljaWVuY3kgc2ltdWxhdGlvbjoKCmBgYHtyfQojIHJlbW90ZXM6Omluc3RhbGxfZ2l0aHViKCJjbGF1c3dpbGtlL2NvbG9yYmxpbmRyIikKbGlicmFyeShjb2xvcmJsaW5kcikKY3ZkX2dyaWQobXlfc291bmRfdHJhaikKYGBgCgpZb3UgY2FuIGFsc28gdXNlIHRoZSBjb2xvcmJsaW5kLWZyaWVuZGx5IHBhbGV0dGUgaW4gdGhpcyBwYWNrYWdlIHVzaW5nIGBzY2FsZV9jb2xvcl9Pa2FiZUl0b2AgYW5kIGBzY2FsZV9maWxsX09rYWJlSXRvYDoKCmBgYHtyfQpjYl9zb3VuZF90cmFqIDwtIHNvdW5kX3RyYWogKwogIHNjYWxlX2NvbG9yX09rYWJlSXRvKCkKCmNiX3NvdW5kX3RyYWoKY3ZkX2dyaWQoY2Jfc291bmRfdHJhaikKYGBgCgpZb3UgY2FuIHN0aWxsIHVzZSB0aGlzIGNvbG9yYmxpbmQtZnJpZW5kbHkgcGFsZXR0ZSB3aXRob3V0IHRoZSBgY29sb3JibGluZHJgIHBhY2thZ2UgdGhvdWdoLiBbSGVyZV0oaHR0cDovL2pmbHkuaWFtLnUtdG9reW8uYWMuanAvY29sb3IvKSBhcmUgdGhlIGNvbG9ycyEKCiFbXShodHRwOi8vamZseS5pYW0udS10b2t5by5hYy5qcC9jb2xvci9pbWFnZS9wYWxsZXRlLmpwZykKClRoZSBbQ29va2Jvb2sgZm9yIFJdKGh0dHA6Ly93d3cuY29va2Jvb2stci5jb20vR3JhcGhzL0NvbG9yc18oZ2dwbG90MikvI2EtY29sb3JibGluZC1mcmllbmRseS1wYWxldHRlKSBwcm92aWRlZCB0aGUgbWF0Y2hpbmcgaGV4IGNvbG9ycyB0b28gdG8gbWFrZSBsaWZlIGVhc2llcjoKYGBge3J9CmNiYlBhbGV0dGUgPC0gYygiIzAwMDAwMCIsICIjRTY5RjAwIiwgIiM1NkI0RTkiLCAiIzAwOUU3MyIsICIjRjBFNDQyIiwgIiMwMDcyQjIiLCAiI0Q1NUUwMCIsICIjQ0M3OUE3IikKCiMgVG8gdXNlIGZvciBsaW5lIGFuZCBwb2ludCBjb2xvcnMsIGFkZApzb3VuZF90cmFqICsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGNiYlBhbGV0dGVbYygzLCA3LCA4KV0pCmBgYAoKIyMgUmVwZWwgbGFiZWxzCgpgYGB7cn0KbGlicmFyeShnZ3JlcGVsKQoKc291bmRzIDwtIHNvdW5kcyAlPiUKICBtdXRhdGUobGFiZWwgPSBjYXNlX3doZW4oCiAgICBhZ2UgPT0gbWF4KGFnZSkgfiBzb3VuZCkpCgpnZ3Bsb3Qoc291bmRzLCBhZXMoeCA9IGFnZSwgCiAgICAgICAgICAgICAgICAgICB5ID0gcHJvcF9wcm9kdWNlLCAKICAgICAgICAgICAgICAgICAgIGNvbG9yID0gZmN0X3Jlb3JkZXIyKHNvdW5kLCBhZ2UsIHByb3BfcHJvZHVjZSkpKSArCiAgZ2VvbV9zbW9vdGgoc2UgPSBGQUxTRSwgbHdkID0gLjUpICsKICBnZW9tX3BvaW50KHNpemUgPSAyKSArCiAgbGFicyh4ID0gIkFnZSAobW9udGhzKSIsIAogICAgICAgeSA9ICJQcm9wb3J0aW9uIG9mIENoaWxkcmVuIFByb2R1Y2luZyIpICsKICBnZW9tX3RleHRfcmVwZWwoYWVzKGxhYmVsID0gbGFiZWwpLAogICAgICAgICAgICAgICAgICBudWRnZV94ID0gMSwKICAgICAgICAgICAgICAgICAgZGlyZWN0aW9uID0gInkiLAogICAgICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUpICsKICBndWlkZXMoY29sb3IgPSBGQUxTRSkKYGBgCgoKCiMgQ29udGludW91cyBjb2xvcnMKCipOLkIuIEFsbCBvZiB0aGUgZXhhbXBsZSBwbG90cyBiZWxvdyBhcmUgZ3JlYXQgZXhhbXBsZXMgb2YgaG93ICoqbm90KiogdG8gdXNlIGNvbnRpbnVvdXMgY29sb3JzLiBJJ20gc2hvd2luZyB0aGVzZSBzbyB5b3UgY2FuIHNlZSBob3cgdG8gd29yayB3aXRoIGNvbnRpbnVvdXMgY29sb3IgcGFsZXR0ZXMsIGFuZCB0byBtYWtlIHRoaXMgdG9waWMgZmxvdyBlYXNpZXIgZm9yIHlvdSBJJ20gc3RpY2tpbmcgd2l0aCBvcmlnaW5hbCBkYXRhc2V0LioKCiMjIERlZmF1bHQgY29udGludW91cyBwYWxldHRlCgpMZXTigJlzIG1hcCBjb2xvciB0byBhIGNvbnRpbnVvdXMgdmFyaWFibGUuIEZvciB0aGlzLCB3ZSBhcmUgcmV0dXJuaW5nIHRvIGBnZW9tX2xpbmVgIGluc3RlYWQgb2YgYGdlb21fc21vb3RoYCwgYmVjYXVzZSB0aGUgbGF0dGVyIGRvZXNuJ3QgcmVzcG9uZCB0byBjb250aW51b3VzIGNvbG9yIHBhbGV0dGVzLgoKYGBge3J9CnNvdW5kX2J5X2FnZSA8LSBnZ3Bsb3Qoc291bmRzLCBhZXMoeCA9IGFnZSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IHByb3BfcHJvZHVjZSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBhZ2UpKSArCiAgZ2VvbV9saW5lKGFlcyhncm91cCA9IHNvdW5kKSwgbHdkID0gLjUpICsKICBnZW9tX3BvaW50KHNpemUgPSAyKSArCiAgbGFicyh4ID0gIkFnZSAobW9udGhzKSIsIAogICAgICAgeSA9ICJQcm9wb3J0aW9uIG9mIENoaWxkcmVuIFByb2R1Y2luZyIpCnNvdW5kX2J5X2FnZQpgYGAKCgoKIyMgQ29sb3IgY2hvaWNlIHdpdGggY29udGludW91cyB2YXJpYWJsZXMgCgpXaXRoIGRpc2NyZXRlIGNvbG9ycywgd2UgdXNlZCBlaXRoZXIgYHNjYWxlX2NvbG9yX21hbnVhbGAgb3IgYHNjYWxlX2ZpbGxfbWFudWFsYCAoYW5kIHNvbWV0aW1lcyBib3RoIHdlcmUgbmVlZGVkISkuIEZvciBjb250aW51b3VzIGNvbG9ycywgd2UgdXNlIGVpdGhlciBgc2NhbGVfY29sb3JfZ3JhZGllbnRgIG9yIGBzY2FsZV9maWxsX2dyYWRpZW50YC4KCmBgYHtyfQpzb3VuZF9ieV9hZ2UgKwogIHNjYWxlX2NvbG9yX2dyYWRpZW50KCkKYGBgCgpZb3UgY2FuIHJldmVyc2UgdGhlIGdyYWRpZW50IHNjYWxlLi4uCgpgYGB7cn0Kc291bmRfYnlfYWdlICsKICBzY2FsZV9jb2xvcl9ncmFkaWVudCh0cmFucyA9ICJyZXZlcnNlIikKYGBgCgoKYGBge3J9CnNvdW5kX2J5X2FnZSArCiAgc2NhbGVfY29sb3JfZ3JhZGllbnQobG93ID0gIndoaXRlIiwgaGlnaCA9ICJyZWQiKQpgYGAKCldlIGNhbiBtYWtlIHRoaXMgc2FtZSBwbG90IHVzaW5nIGEgY3VzdG9tIGdyZXlzY2FsZSBncmFkaWVudC4KCmBgYHtyfQpzb3VuZF9ieV9hZ2UgKwogIHNjYWxlX2NvbG9yX2dyYWRpZW50KGxvdyA9ICJncmV5OTAiLCBoaWdoID0gImJsYWNrIikKYGBgCgoKClNvIGBzY2FsZV9jb2xvcl9ncmFkaWVudGAgZ2l2ZXMgeW91IGEgc2VxdWVudGlhbCBncmFkaWVudCwgYnV0IHlvdSBtYXkgd2FudCBhIGRpdmVyZ2luZyBjb2xvciBzY2hlbWUgaW5zdGVhZC4gRm9yIHRoYXQsIHlvdSBjYW4gdXNlIGBzY2FsZV9jb2xvcl9ncmFkaWVudDJgCgoKYGBge3J9CiMgRGl2ZXJnaW5nIGNvbG9yIHNjaGVtZQptZWRfYWdlIDwtIHNvdW5kcyAlPiUgCiAgc3VtbWFyaXplKG1vcyA9IG1lZGlhbihhZ2UpKSAlPiUgCiAgcHVsbCgpCnNvdW5kX2J5X2FnZSArCiAgc2NhbGVfY29sb3JfZ3JhZGllbnQyKG1pZHBvaW50ID0gbWVkX2FnZSwKICAgICAgICAgICAgICAgICAgICAgIGxvdz0iYmx1ZSIsIG1pZD0id2hpdGUiLCBoaWdoPSJyZWQiICkKYGBgCgojIyBCdWlsdC1pbiBjb250aW51b3VzIHBhbGV0dGVzCgojIyMgVXNlIGBSQ29sb3JCcmV3ZXJgIAoKQWdhaW4sIHRvIHVzZSB5b3UgbmVlZCB0byBpbnN0YWxsIGFuZCBsb2FkIHRoZSBgUkNvbG9yQnJld2VyYCBwYWxldHRlLiAKCmBgYHtyIGV2YWwgPSBGQUxTRX0KbGlicmFyeShSQ29sb3JCcmV3ZXIpCmBgYAoKVGhlbiB1c2UgYHNjYWxlX2NvbG9yX2dyYWRpZW50bmAuCgpgYGB7cn0Kc291bmRfYnlfYWdlICsKICBzY2FsZV9jb2xvcl9ncmFkaWVudG4oY29sb3VycyA9IGJyZXdlci5wYWwobj01LCBuYW1lPSJQdUJ1R24iKSkKYGBgCgpSZXZlcnNlIHRoZSBjb2xvcnMuLi4KCmBgYHtyfQpzb3VuZF9ieV9hZ2UgKwogIHNjYWxlX2NvbG9yX2dyYWRpZW50bihjb2xvdXJzID0gcmV2KGJyZXdlci5wYWwobj01LCBuYW1lPSJQdUJ1R24iKSkpCmBgYAoKIyMjIFZpcmlkaXMKClJlYWQgbW9yZSBoZXJlIGluIHRoZSBbdmlyaWRpcyB2aWduZXR0ZV0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL3ZpcmlkaXMvdmlnbmV0dGVzL2ludHJvLXRvLXZpcmlkaXMuaHRtbCkKCmBgYHtyIGV2YWwgPSBGQUxTRX0KbGlicmFyeSh2aXJpZGlzKQpgYGAKClRoZSBkZWZhdWx0IGlzIHRoZSBgdmlyaWRpc2AgcGFsZXR0ZSB3aXRoaW4gdGhlIGB2aXJpZGlzYCBwYWNrYWdlIQoKTm90ZSEgRm9yIGRpc2NyZXRlID09IEZBTFNFICh0aGUgZGVmYXVsdCkgYWxsIG90aGVyIGFyZ3VtZW50cyBhcmUgYXMgdG8gYHNjYWxlX2ZpbGxfZ3JhZGllbnRuYCBvciBgc2NhbGVfY29sb3JfZ3JhZGllbnRuYC4gKEFsc28gbm90ZSB0aGF0IGBfZ3JhZGllbnRfbl9gIGlzIG5vdCBhIHR5cG8tIHRoZSBfbl8gdmVyc2lvbnMgb2YgdGhvc2UgZnVuY3Rpb25zIGFsbG93IG11bHRpLWNvbG9yIGdyYWRpZW50cykuCgpgYGB7cn0Kc291bmRfYnlfYWdlICsKICBzY2FsZV9jb2xvcl92aXJpZGlzKCkKYGBgCgpgYGB7cn0Kc291bmRfYnlfYWdlICsKICBzY2FsZV9jb2xvcl92aXJpZGlzKG9wdGlvbiA9ICJtYWdtYSIpCmBgYAoKUmVhZCB0aGUgaGVscCBmdW5jdGlvbiBmb3IgYD9zY2FsZV9jb2xvcl92aXJpZGlzYC4gV2UnbGwgdXNlIHRoZSAiaW5mZXJubyIgcGFsZXR0ZSBfaW4gcmV2ZXJzZV8uCgpgYGB7cn0Kc291bmRfYnlfYWdlICsKICBzY2FsZV9jb2xvcl92aXJpZGlzKG9wdGlvbiA9ICJpbmZlcm5vIiwgYmVnaW4gPSAxLCBlbmQgPSAwKQpgYGAKCgoKIyBGaW5hbCBjaGFsbGVuZ2UgKCMxMCkKCjxkaXYgY2xhc3M9InBhbmVsIHBhbmVsLXN1Y2Nlc3MiPgogIDxkaXYgY2xhc3M9InBhbmVsLWhlYWRpbmciPkNoYWxsZW5nZSAjMTA6PC9kaXY+CiAgPGRpdiBjbGFzcz0icGFuZWwtYm9keSI+ClVzaW5nIG5ldyBkYXRhLCBtYWtlIHRocmVlIG5ldyBwbG90cy4gVXNlIGFueSBgZ2VvbWAgdGhhdCBtYWtlcyBzZW5zZS4gVGhlIHBsb3RzIHNob3VsZDoKCi0gSGF2ZSB4LSBhbmQgeS1heGVzIHRoYXQgYXJlIGVhY2ggcXVhbnRpdGF0aXZlIHZhcmlhYmxlcy4KLSBBcHBseSBhIG5vbi1kZWZhdWx0IGNvbG9yIHBhbGV0dGUsIGVpdGhlciBjb2xvcmluZyBieSBhIHF1YWxpdGF0aXZlIHZhcmlhYmxlIChkaXNjcmV0ZSBjb2xvcnMpIG9yIGEgcXVhbnRpdGF0aXZlIHZhcmlhYmxlIChjb250aW51b3VzIGNvbG9ycykuIFRoaXMgbGlzdCBvZiBbUiBjb2xvciBwYWxldHRlc10oaHR0cHM6Ly9naXRodWIuY29tL0VtaWxIdml0ZmVsZHQvci1jb2xvci1wYWxldHRlcykgaGFzIGV2ZW4gbW9yZSBpZGVhcyB0aGFuIHdlIGNvdWxkIGNvdmVyIGluIGNsYXNzLgoKCjEuIEluIHRoZSBmaXJzdCBwbG90LCB5b3UgbXVzdCAqKndpZWxkIGNvbG9yIGNhcmVmdWxseSBhbmQgZWZmZWN0aXZlbHkqKi4gVGhlIGFkZGl0aW9uIG9mIHRoZSBjb2xvci9maWxsIGFlc3RoZXRpY3MgbXVzdCBiZSBkb25lIGluIGEgd2F5IHRoYXQgdGhlIGludGVycHJldGF0aW9uIG9mIHRoZSBwbG90IGltcHJvdmVzLiBBbHNvLCB5b3UgbXVzdCBzaG93IGhvdyB5b3VyIGNvbG9ycyBmYXJlIGZvciBjb2xvcmJsaW5kIHZpZXdlcnMuIEluY2x1ZGUgMi0zIHNlbnRlbmNlcyBhYm91dCB3aHkgeW91IG1hZGUgdGhlIHBsb3QgdGhhdCB5b3UgZGlkLiBXaGF0IHF1ZXN0aW9ucyBkb2VzIHlvdXIgcGxvdCBhbnN3ZXJzIChvciBwZXJoYXBzIHdoYXQgcXVlc3Rpb25zIGRvZXMgeW91ciBwbG90IHJhaXNlKT8KCjIuIEluIHRoZSBzZWNvbmQgcGxvdCwgeW91IG11c3QgKiptYWtlIGEgZ3JleXNjYWxlIHZlcnNpb24gb2YgeW91ciBmaXJzdCBwbG90ISoqIEFuZCBhZ2FpbiwgaXQgbXVzdCBsb29rIGdvb2QgYW5kIG1ha2Ugc2Vuc2UuCgozLiBJbiB0aGUgdGhpcmQgcGxvdCwgeW91IG11c3QgKip1c2UgY29sb3IgYmFkbHkqKi4gTWFrZSBhIHBsb3Qgd2hlcmUgdGhlIGNvbG9ycyBhcmUgZWl0aGVyIHJlZHVuZGFudCwgY29uZnVzaW5nLCBvciBqdXN0IGdlbmVyYWxseSBub24tc2Vuc2ljYWwuIEV4cGxhaW4gd2h5IHRoaXMgbGFzdCB2aXN1YWxpemF0aW9uIGZhaWxzLgoKICAgIAogICAgPC9kaXY+CjwvZGl2PgoKU29tZSBkYXRhIGlkZWFzOgoKLSBNYWNBcnRodXItQmF0ZXMgQ29tbXVuaWNhdGl2ZSBEZXZlbG9wbWVudCBJbnZlbnRvcnkgKE1CLUNESSksIGEgZmFtaWx5IG9mIHBhcmVudC1yZXBvcnQgcXVlc3Rpb25uYWlyZXMgbWVhc3VyaW5nIGNoaWxkcmVuJ3Mgdm9jYWJ1bGFyeSB1bmRlcnN0YW5kaW5nIGFuZCBwcm9kdWN0aW9uCiAgICAtIFtSIHBhY2thZ2UgYHdvcmRiYW5rcmBdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy93b3JkYmFua3IvaW5kZXguaHRtbCkKICAgIC0gU2VlIG15IGNvZGUgW2hlcmVdKDAzYS1tZW93LWNsZWFuaW5nLmh0bWwpCi0gUE9UVVMgRXhlY3V0aXZlIE9yZGVycwogICAgLSBbRGF0YV0oaHR0cHM6Ly93d3cuZmVkZXJhbHJlZ2lzdGVyLmdvdi9leGVjdXRpdmUtb3JkZXJzKQogICAgLSBGb2xsb3cgQm9iIFJ1ZGlzJyBjb2RlLXRocm91Z2ggW2hlcmVdKGh0dHBzOi8vcnVkLmlzL2IvMjAxOC8wNC8xOC9leGFtaW5pbmctcG90dXMtZXhlY3V0aXZlLW9yZGVycy8pCi0gTmF0aW9uYWwgRWxlY3Ryb25pYyBJbmp1cnkgU3VydmVpbGxhbmNlIFN5c3RlbSAoTkVJU1MpCiAgICAtIFtSIHBhY2thZ2UgYG5laXNzYF0oaHR0cHM6Ly9naXRodWIuY29tL2hhZGxleS9uZWlzcykKICAgIC0gRm9sbG93IEp1bGlhIFNpbGdlJ3MgY29kZS10aHJvdWdoIFtoZXJlXShodHRwczovL2p1bGlhc2lsZ2UuY29tL2Jsb2cveW91ci1mbG9vci8pCi0gRmxpZ2h0cwogICAgLSBbUiBwYWNrYWdlIGBwbndmbGlnaHRzMTRgXShodHRwczovL2dpdGh1Yi5jb20vaXNtYXljL3Bud2ZsaWdodHMxNCkKICAgIC0gW1IgcGFja2FnZSBgbnljZmxpZ2h0czEzYF0oaHR0cHM6Ly9naXRodWIuY29tL2hhZGxleS9ueWNmbGlnaHRzMTMpCi0gQnVpbGRpbmcgUGVybWl0cwogICAgLSBTZWUgY29kZSBbaGVyZV0oaHR0cHM6Ly9naXRodWIuY29tL2hhZGxleS9idWlsZGluZy1wZXJtaXRzKQogICAgLSBXYXRjaCBZb3VUdWJlIGNvZGUtdGhyb3VnaCBbaGVyZV0oaHR0cHM6Ly93d3cueW91dHViZS5jb20vd2F0Y2g/dj1nbzVBdTAxSnJ2cykKLSBDb2NrdGFpbCBCYWxhbmNlCiAgICAtIFtEYXRhXShodHRwczovL2dpdGh1Yi5jb20va2FybmVza3kvY29ja3RhaWwtYmFsYW5jZSkKLSBOQVNBIFdlYXRoZXIKICAgIC0gW0RhdGFdKGh0dHBzOi8vZ2l0aHViLmNvbS9oYWRsZXkvbmFzYXdlYXRoZXIpCi0gU29jaWFsIFNlY3VyaXR5IEFkbWluaXN0cmF0aW9uIEJhYnkgTmFtZXMKICAgIC0gW1IgcGFja2FnZSBgYmFieW5hbWVzYF0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL2JhYnluYW1lcy9pbmRleC5odG1sKQogICAgLSBGb2xsb3cgSnVsaWEgU2lsZ2UgKidNeSBCYWJ5IEJvb21lciBOYW1lIE1pZ2h0IEhhdmUgQmVlbiAiRGViYmllIicqOiBodHRwczovL2p1bGlhc2lsZ2UuY29tL2Jsb2cvbXktYmFieS1ib29tZXItbmFtZS8KICAgIC0gRm9sbG93IEhpbGFyeSBQYXJrZXI6ICpIaWxhcnk6IFRoZSBNb3N0IFBvaXNvbmVkIEJhYnkgTmFtZSBpbiBVUyBIaXN0b3J5KjogaHR0cHM6Ly9oaWxhcnlwYXJrZXIuY29tLzIwMTMvMDEvMzAvaGlsYXJ5LXRoZS1tb3N0LXBvaXNvbmVkLWJhYnktbmFtZS1pbi11cy1oaXN0b3J5LwotIFlvdXRoIEJlaGF2aW9yIFJpc2sgU3VydmVpbGxhbmNlIFN5c3RlbQogICAgLSBbUiBwYWNrYWdlIGB5cmJzc2BdKGh0dHBzOi8vZ2l0aHViLmNvbS9oYWRsZXkveXJic3MpCiAgICAtIFNvbWUgW2dvb2QgaWRlYXMgaGVyZV0oaHR0cHM6Ly93d3cuY2RjLmdvdi9uY2hoc3RwL25ld3Nyb29tLzIwMTIveXJicy1ncmFwaGljczIwMTIuaHRtbCkKLSBHdW4gc2FsZXMKICAgIC0gW0RhdGFdKGh0dHBzOi8vZ2l0aHViLmNvbS9oYWRsZXkvZ3VuLXNhbGVzKQogICAgLSBTb21lIFtleGFtcGxlIHBsb3RzIGhlcmVdKGh0dHBzOi8vZ2l0aHViLmNvbS9OWVRpbWVzL2d1bnNhbGVzL2Jsb2IvbWFzdGVyL291dC9wbG90cy5wZGYpCi0gR2FwbWluZGVyCiAgICAtIFtSIHBhY2thZ2UgYGdhcG1pbmRlcmBdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9nYXBtaW5kZXIvaW5kZXguaHRtbCkKICAgIC0gU29tZSBbZXhhbXBsZSBwbG90cyBoZXJlXShodHRwczovL2dpdGh1Yi5jb20vamVubnliYy9nZ3Bsb3QyLXR1dG9yaWFsL2Jsb2IvbWFzdGVyL2dhcG1pbmRlci1nZ3Bsb3QyLXNjYXR0ZXJwbG90Lm1kKQoKCgoK