Our goal in this module is to understand some basic ways of visualizing data with graphics β bar-charts, histograms, box-plots, and so on. We will skip base R
commands and instead just work with ggplot2
, the most popular visualization package in the {tidyverse}
universe as of now.
We can then ratchet up as we need to.
I will use two data-sets to walk through the initial examples in this module, the first being this IMDB data-set
The {ggplot2}
package has a special syntax and I will point out things you should note as we move through this module. First up, the library is called ggplot2
but the command starts with ggplot
so donβt let that throw you off-track.
Second, you need to have a data-set to work with. In the code below I start by loading the library and then specifying the data-set to be used.
library(ggplot2)
ggplot(
data = starwars
)
Nothing results from these commands because we have not yet specified anything about what should go on the x-axis, what should go on the y-axis. Well, let us do that then by asking for the column eye_color
to be put on the x-axis.
ggplot(
data = starwars,
mapping = aes(
x = eye_color
)
)
geom_bar()
β¦ the bar-chart
This results in a gray canvas with the eye colors on the x-axis but nothing else has been drawn since we have not specified the geometry
β¦ do you want a bar-chart? histogram? dot-plot? line-chart? This is a categorical variable and hence a bar-chart would be appropriate. We call for a bar-chart with the geom_bar()
command.
ggplot(
data = starwars,
mapping = aes(
x = eye_color
)
) +
geom_bar()
color
versus fill
The aes()
refers to the aesthetics of the chart, and many other aesthetics
can be added, such as group
, color
, fill
, size
, alpha
, etc. We will see some of these in due course but for now I want to focus on two of these, both involving coloring of the geom_
. Specifically, there are two commands for adding colors β (1) color
or colour
, and (2) fill
β to a chart.
ggplot(
data = starwars,
mapping = aes(
x = eye_color,
color = eye_color
)
) +
geom_bar()
Note what the color = eye_color
command did β¦ it drew a colored border for the bars, and an accompanying legend. What if we had used fill = eye_color
instead?
ggplot(
data = starwars,
mapping = aes(
x = eye_color,
fill = eye_color
)
) +
geom_bar()
Aha! Now the bars are filled with colors and an accompanying legend is drawn as well. So fill =
and color =
behave very differently, bear this in mind.
Adding labels with labs
One of the nice things about this software environment is that there are plenty of coloring schemes available to us and we will play with some of these shortly, but before we do that, let us look at one more improvement β adding titles, subtitles, captions, and axis labels to our chart. This is done with the labs = ()
command.
ggplot(
data = starwars,
mapping = aes(
x = eye_color,
fill = eye_color
)
) +
geom_bar() +
labs(
x = "Eye Color",
y = "Frequency (n)",
title = "Bar-chart of Eye Colors",
subtitle = "(of Star Wars characters)",
caption = "My little work of art!!"
)
Notice the text that now appears as a result of what has been specified in the labs()
command.
Controlling the chart legend with theme()
In this bar-chart, do we really need the legend? No, because the colors and color names show up in the chart itself. How can we hide the legend? Turns out there is a neat command that will allow you to move the legend around and even to hide it.
ggplot(
data = starwars,
mapping = aes(
x = eye_color,
fill = eye_color
)
) +
geom_bar() +
labs(
x = "Eye Color",
y = "Frequency (n)",
title = "Bar-chart of Eye Colors",
subtitle = "(of Star Wars characters)",
caption = "My little work of art!!"
) +
theme(legend.position = "none")
Voila! The legend is gone. Instead of βnoneβ you could have specified βbottomβ, βleftβ, βtopβ, βrightβ to place the legend in a particular direction.
Customizing colors
Of course, it would be good to have the colors match the eye-color so let us do that next. The way we can do this is by calling specific colors by name. I have tried to order the lineup of the colors to match, as closely as I can, the eye colors.
c(
"black", "blue", "slategray", "brown", "gray34", "gold",
"greenyellow", "navajowhite1", "orange", "pink", "red",
"magenta", "thistle3", "white", "yellow"
) -> mycolors
ggplot(
data = starwars,
mapping = aes(
x = eye_color
)
) +
geom_bar(
fill = mycolors
) +
labs(
x = "Eye Color",
y = "Frequency (n)",
title = "Bar-chart of Eye Colors",
subtitle = "(of Star Wars characters)",
caption = "My little work of art!!"
) +
theme(legend.position = "none")
These colors are from this source but see also this source. Colors can be customized by generating your own palettes via the Color Brewer here. But donβt get carried away: Remember to read the materials on choosing colors wisely, particularly the point about qualitative palettes, divergent palettes, and then palettes that work well even with colorblind audiences.
Selected color palettes
I had mentioned the existence of a number of color palettes so let us look at a few, but we will do this with a different variable. First up, the Pastel1
palette.
ggplot(
data = starwars,
mapping = aes(
x = gender
)
) +
geom_bar(
aes(fill = gender)
) +
labs(
x = "Gender",
y = "Frequency",
title = "Bar-chart of Gender",
subttitle = "(of Star Wars characters)",
caption = "(Source: The dplyr package)") +
scale_fill_brewer(
palette = "Pastel1"
)
Not bad but doesnβt work too well here. How about trying another palette, Set
?
ggplot(
data = starwars,
mapping = aes(
x = gender
)
) +
geom_bar(
aes(fill = gender)
) +
labs(
x = "Gender",
y = "Frequency",
title = "Bar-chart of Gender",
subttitle = "(of Star Wars characters)",
caption = "(Source: The dplyr package)") +
scale_fill_brewer(
palette = "Set1"
)
Nice! But what is also noticeable here is that there are some characters in the data-set whose gender data is missing. These are the NA
values. By default, you will see NA
values showing up in some types of charts and so it is always good to exclude them from the chart. Here is one way of doing that.
ggplot(
data = subset(starwars, !is.na(gender)),
mapping = aes(
x = gender
)
) +
geom_bar(
aes(fill = gender)
) +
labs(
x = "Gender",
y = "Frequency",
title = "Bar-chart of Gender",
subttitle = "(of Star Wars characters)",
caption = "(Source: The dplyr package)") +
scale_fill_brewer(
palette = "Set1"
)
Notice what is different here: data = subset(starwars, !is.na(gender))
and that this command is effectively saying subset the starwars data to only include those cases where gender is not missing (this is the !is.na()
portion of the command).
Another way to do the same thing would have been to use filter()
and create a cleaned up copy of the data. If you take this route, be careful not to overwrite the original data-set; note how I am giving a new name (my.data)
after filter()
to save the results in. Then we lean on this data-set via data = my.data
.
starwars %>%
filter(!is.na(gender)) -> my.data
ggplot(
data = my.data,
mapping = aes(
x = gender
)
) +
geom_bar(
aes(fill = gender)
) +
labs(
x = "Gender",
y = "Frequency",
title = "Bar-chart of Gender",
subttitle = "(of Star Wars characters)",
caption = "(Source: The dplyr package)") +
scale_fill_brewer(
palette = "Set1"
)
There is one color palette you should remember, and this is the {viridis}
color scheme that works around varying types of color blindness in the population. Here come the palettes:
ggplot(
data = my.data,
mapping = aes(
x = gender
)
) +
geom_bar(
aes(fill = gender)
) +
labs(
x = "Gender",
y = "Frequency",
title = "Bar-chart of Gender",
subttitle = "(of Star Wars characters)",
caption = "(Source: The dplyr package)") +
scale_fill_viridis_d(
option = "viridis"
)
ggplot(
data = my.data,
mapping = aes(
x = gender
)
) +
geom_bar(
aes(fill = gender)
) +
labs(
x = "Gender",
y = "Frequency",
title = "Bar-chart of Gender",
subttitle = "(of Star Wars characters)",
caption = "(Source: The dplyr package)") +
scale_fill_viridis_d(
option = "magma"
)
ggplot(
data = my.data,
mapping = aes(
x = gender
)
) +
geom_bar(
aes(fill = gender)
) +
labs(
x = "Gender",
y = "Frequency",
title = "Bar-chart of Gender",
subttitle = "(of Star Wars characters)",
caption = "(Source: The dplyr package)") +
scale_fill_viridis_d(
option = "plasma"
)
ggplot(
data = my.data,
mapping = aes(
x = gender
)
) +
geom_bar(
aes(fill = gender)
) +
labs(
x = "Gender",
y = "Frequency",
title = "Bar-chart of Gender",
subttitle = "(of Star Wars characters)",
caption = "(Source: The dplyr package)") +
scale_fill_viridis_d(
option = "cividis"
)
Themes with {ggthemes}
One can also lean on various plotting themes as shown below. These themes mimic the style of graphics popularized by some data visualization experts (for e.g., Stephen Few, Edward Tufte), news-media houses (Fivethirtyeight, The Economist, The Wall Street Journal), some software packages (Excel, Stata, Google docs), and a few others. Below I show you just a handful.
library(ggthemes)
ggplot(
data = starwars,
mapping = aes(
x = eye_color
)
) +
geom_bar() +
theme_tufte()
ggplot(
data = starwars,
mapping = aes(
x = eye_color
)
) +
geom_bar() +
theme_economist()
ggplot(
data = starwars,
mapping = aes(
x = eye_color
)
) +
geom_bar() +
theme_fivethirtyeight()
Later on you will learn these & other ways to build advanced visualizations. For now we get to work more with ggplot2
.
More with bar-charts
I want to show a few things with bar-charts now. First, we can specify things a bit differently without altering the result. For example, compare the following two pieces of code.
ggplot(
data = movies,
mapping = aes(
x = mpaa
)
) +
geom_bar()
ggplot() +
geom_bar(
data = movies,
mapping = aes(x = mpaa)
)
Notice that we switched the data =
and the aes()
pieces of the code but that made no difference; this is important to bear in mind because it will come in handy down the road when we need to build some advanced visualizations.
The plot is sub-optimal since MPAA ratings are missing for a lot of movies and should be eliminated from the plot via subset(mpa != "")
or by running dplyrβs filter()
to create another data-set. I will lean on filter()
.
movies %>%
filter(mpaa != "") -> movies2
ggplot() +
geom_bar(
data = movies2,
mapping = aes(x = mpaa)
)
The order of the bars here is fortuitous in that it goes from the smallest frequency to the highest frequency, drawing the readerβs eye. I said fortuitous because {ggplot2}
defaults to drawing the bars in an ascending alphabetic/alphanumeric order if the variable is a character. See below for an example.
df = tibble(x = c(rep("A", 2), rep("B", 4), rep("C", 1)))
ggplot() +
geom_bar(
data = df,
mapping = aes(x = x)
)
Notice the bars here do not follow in ascending/descending order of frequencies. Later on weβll learn how to order the bars with ascending/descending frequencies or by some other logic.
What about plotting relative frequencies
on the y-axis rather than the frequencies?
library(scales)
ggplot() +
geom_bar(
data = movies2,
mapping = aes(
x = mpaa,
y = (..count..)/sum(..count..)
)
) +
scale_y_continuous(labels = percent) +
labs(
x = "MPAA Rating",
y = "Relative Frequency (%)"
)
Note the addition of
y = (..count..)/sum(..count..)
to change the y-axis to reflect the relative frequency as a proportion, and
scale_y_continuous(labels = percent)
to then multiply these proportions by 100 to get percentages as the labels rather than 0.2, 0.4, 0.6, etc.
Disaggregating bar-charts for groups
Let us build a simple bar-chart with the hsb2
data we saw in Module 01. Here we first download it, label the values, save it, and then start charting it.
read.table(
'https://stats.idre.ucla.edu/stat/data/hsb2.csv',
header = TRUE,
sep = ","
) -> hsb2
factor(hsb2$female,
levels = c(0, 1),
labels = c("Male", "Female")
) -> hsb2$female
factor(hsb2$race,
levels = c(1:4),
labels = c("Hispanic", "Asian", "African American", "White")
) -> hsb2$race
factor(hsb2$ses,
levels = c(1:3),
labels = c("Low", "Middle", "High")
) -> hsb2$ses
factor(hsb2$schtyp,
levels = c(1:2),
labels = c("Public", "Private")
) -> hsb2$schtyp
factor(hsb2$prog,
levels = c(1:3),
labels = c("General", "Academic", "Vocational")
) -> hsb2$prog
save(
hsb2, file = here::here("data", "hsb2.RData")
)
ggplot() +
geom_bar(
data = hsb2,
mapping = aes(x = ses)) +
labs(x = "Socioeconomic Status")
Okay, fair enough. But what if I wanted to see how socioeconomic status varies across male and female students?
ggplot() +
geom_bar(
data = hsb2,
mapping = aes(
x = ses,
group = female,
fill = female
)
) +
labs(
x = "Socioeconomic Status",
y = "Frequency"
)
This is not very useful since the viewer has to estimate the relative sizes of the two colors within any given bar. That can be fixed with position = "dodge"
, juxtaposing the bars for the groups as a result, and the end product is much better. But note: position = "dodge"
has to be put outside the aes()
but still inside geom_bar()
so be careful.
ggplot() +
geom_bar(
data = hsb2,
mapping = aes(
x = ses,
group = female,
fill = female
),
position = "dodge"
) +
labs(
x = "Socioeconomic Status",
y = "Frequency"
)
What if you wanted to calculate percentages within each sex? That is, what percent of male students fall within a particular ses category, and the same thing for female students?
ggplot() +
geom_bar(
data = hsb2,
aes(
x = ses,
group = female,
fill = female,
y = ..prop..
),
position = "dodge") +
scale_y_continuous(labels = scales::percent) +
labs(
x = "Socioeconomic Status",
y = "Relative Frequency (%)"
)
What about within each ses instead of within gender? That is, what if we wanted percent of Low ses that is Male versus Female, and so on?
ggplot() +
geom_bar(
data = hsb2,
aes(
x = female,
group = ses,
fill = ses,
y = ..prop..
),
position = "dodge") +
scale_y_continuous(labels = scales::percent) +
labs(
x = "Socioeconomic Status",
y = "Relative Frequency (%)"
)
ggplot() +
geom_bar(
data = hsb2,
aes(
x = female,
group = ses,
fill = ses,
y = ..prop..
),
position = "dodge") +
scale_y_continuous(labels = scales::percent) +
labs(
x = "Socioeconomic Status",
y = "Relative Frequency (%)"
)
There is some more we will do with bar-charts but for now let us set them aside and instead look at a few other charts β histograms, box-plots, and line-charts.
Histograms
If youβve forgotten what these are, see histogram, or then Yauβs piece here and here. There is a short video available as well.
For histograms in ggplot2, geom_histogram()
is the geometry needed but note that the default number of bins is not very useful and can be tweaked, along with other embellishments that are possible as well.
ggplot() +
geom_histogram(
data = hsb2,
aes(x = read),
fill = "cornflowerblue",
color = "white"
) +
labs(
title = "Histogram of Reading Scores",
x = "Reading Score",
y = "Frequency"
)
Note the warning stat_bin()
using bins = 30
. Pick better value with binwidth
. This is because numerical variables need to be grouped in order to have meaningful histograms we can make sense of. How do you define the bins (aka the groups)? We could set bins = 5
and we could also experiment with binwidth =
. Let us do bins = 5
which will say give us 5 groups, and go ahead and calculate them yourself.
ggplot() +
geom_histogram(
data = hsb2,
aes(x = read),
fill = "cornflowerblue",
color = "white",
bins = 5
) +
labs(
title = "Histogram of Reading Scores",
subtitle = "(with bins = )",
x = "Reading Score",
y = "Frequency"
)
If we wanted more/fewer bins we could tweak it up or down as needed. What about binwidth? This will specify how wide each group must be.
ggplot() +
geom_histogram(
data = hsb2,
aes(x = read),
fill = "cornflowerblue",
color = "white",
binwidth = 5
) +
labs(
title = "Histogram of Reading Scores",
subtitle = "(with binwidth = )",
x = "Reading Score",
y = "Frequency"
)
If we wanted to disaggregate the histogram by one or more categorical variables, we could do so quite easily:
ggplot() +
geom_histogram(
data = hsb2,
aes(x = read),
fill = "cornflowerblue",
color = "white",
bins = 5
) +
labs(
title = "Histogram of Reading Scores",
subtitle = "(broken out for Male vs. Female students)",
x = "Reading Score",
y = "Frequency"
) +
facet_wrap(~ female)
When we do this, it is often useful to organize them so that only one histogram shows up in a row. This is done with the ncol = 1
command.
ggplot() +
geom_histogram(
data = hsb2,
aes(x = read),
fill = "cornflowerblue",
color = "white",
bins = 5
) +
labs(
title = "Histogram of Reading Scores",
subtitle = "(broken out for Male vs. Female students)",
x = "Reading Score",
y = "Frequency"
) +
facet_wrap(~ female, ncol = 1)
ggplot() +
geom_histogram(
data = hsb2,
aes(x = read),
fill = "cornflowerblue",
color = "white",
bins = 5
) +
labs(
title = "Histogram of Reading Scores",
subtitle = "(broken out by Socioeconomic Status)",
x = "Reading Score",
y = "Frequency"
) +
facet_wrap(~ ses, ncol = 1)
Now the distributions are stacked above each, easing comparisons; do they have the same average? Do they vary the same? Are they similarly skewed/symmetric?.
For breakouts with two categorical variables we could do
ggplot() +
geom_histogram(
data = hsb2,
aes(x = read),
fill = "cornflowerblue",
color = "white",
bins = 5
) +
labs(
title = "Histogram of Reading Scores",
subtitle = "(broken out by Socioeconomic Status and School Type)",
x = "Reading Score",
y = "Frequency"
) +
facet_wrap(ses ~ schtyp, ncol = 2)
Note that ses ~ schtyp
renders the panels for the first category of ses
by all categories of schtyp and then repeats for the other categories in rows 2 and 3. If we did facet_wrap(schtype ~ ses, ncol = 3)
we would have a different result:
ggplot() +
geom_histogram(
data = hsb2,
aes(x = read),
fill = "cornflowerblue",
color = "white",
bins = 5
) +
labs(
title = "Histogram of Reading Scores",
subtitle = "(broken out by Socioeconomic Status and School Type)",
x = "Reading Score",
y = "Frequency"
) +
facet_wrap(schtyp ~ ses, ncol = 3) +
ylim(c(0, 23))
Notice that here I also add a ylim(c(...))
command to set the minimum and maximum values of the y-axis. This is useful, and I suggest you do not forget to set the y limit to start at 0 or then make a note in the plot for readers so they donβt assume it is at 0 when in fact it has been truncated for ease of data presentation. This misstates the pattern in the data, do not do it or then, again, annotate the plot to that effect so nobody is misled. Bar-charts and histograms will have 0 as the minimum y-limit but this is not true for some other plots.
Box-plots
Remember these, our friends from MPA 6010? These can be useful for studying the distribution of a continuous variable. See this video. Let us see these in action with the cmhflights
data.
load(
here::here("data", "cmhflights_01092017.RData")
)
ggplot() +
geom_boxplot(
data = cmhflights,
mapping = aes(
y = ArrDelay,
x = ""
),
fill = "cornflowerblue"
)
Note:
- the
x = ""
is in aes()
because otherwise with a single group the box-plot will not build up nicely
But, I prefer to see them running horizontally, so how can I do that? With coord_flip()
since this just flips the columns.
ggplot() +
geom_boxplot(
data = cmhflights,
mapping = aes(
y = ArrDelay,
x = ""
),
fill = "cornflowerblue"
) +
coord_flip()
And now for a slightly different data-set, one that measures male adultsβ hemoglobin concentration for a few populations.
read_csv(
"http://whitlockschluter.zoology.ubc.ca/wp-content/data/chapter02/chap02e3cHumanHemoglobinElevation.csv"
) -> hemoglobin
ggplot() +
geom_boxplot(
data = hemoglobin,
mapping = aes(
x = population,
y = hemoglobin,
fill = population
)
) +
coord_flip() +
labs(
x = "Population",
y = "Hemoglobin Concentration",
title = "Hemoglobin Concentration in Adult Males",
subtitle = "(Andes, Ethiopia, Tibet, USA)"
) +
theme(legend.position = "none")
Notice the need for no legend with fill = population
Notice also how fill =
is inside aes(...)
here because we are asking that each unique value seen in a variable called population
be mapped to a unique color.
Could we use our facet_wrap(...)
here too? Of course.
ggplot() +
geom_boxplot(
data = cmhflights,
mapping = aes(
y = ArrDelay,
x = Carrier
),
fill = "cornflowerblue"
) +
coord_flip() +
facet_wrap(~ Month)
Line-charts
If we have data over time for one or more units, then line-charts work really well to exhibit trends. A classic, current example would be the number of confirmed COVID-19 cases per country per date. For example, say we have data on the unemployment rate for the country. These data are coming from the {plotly}
library so we have to make sure it is installed and load it.
library(plotly)
data(economics)
names(economics)
## [1] "date" "pce" "pop" "psavert" "uempmed" "unemploy"
ggplot() +
geom_line(
data = economics,
mapping = aes(
x = date,
y = uempmed
)
) +
labs(
x = "Date",
y = "Unemployment Rate"
)
They can look very plain and aesthetically unappealing unless you dress them up. See the one below and then the one that follows.
load(
here::here("data", "gap.df.RData")
)
ggplot() +
geom_line(
data = gap.df,
mapping = aes(
x = year,
y = LifeExp,
group = continent,
color = continent
)
) +
geom_point(
data = gap.df,
mapping = aes(
x = year,
y = LifeExp,
group = continent,
color = continent
)
) +
labs(
x = "Year",
y = "Median Life Expectancy (in years)",
color = ""
) +
theme(legend.position = "bottom")
Scatter-plots
These work well if we have two or more continuous variables, and work well to highlight the nature and strength of a relationship between the two variables β¦. what happens to y
as x
increases? s
ggplot() +
geom_point(
data = hsb2,
mapping = aes(
x = write,
y = science
)
) +
labs(
x = "Writing Scores",
y = "Science Scores"
)
We could highlight the different ses
groups, to see if there is any difference in the relationship between writing scores and science scores by the different ses levels.
ggplot() +
geom_point(
data = hsb2,
mapping = aes(
x = write,
y = science,
color = ses
)
) +
labs(
x = "Writing Scores",
y = "Science Scores",
color = ""
) +
theme(legend.position = "bottom")
This is not very helpful so why not breakout ses for ease of interpretation?
ggplot() +
geom_point(
data = hsb2,
mapping = aes(
x = write,
y = science
)
) +
labs(
x = "Writing Scores",
y = "Science Scores"
) +
facet_wrap(~ ses)
Could we add another layer, perhaps female
?
ggplot() +
geom_point(
data = hsb2,
mapping = aes(
x = write,
y = science
)
) +
labs(
x = "Writing Scores",
y = "Science Scores"
) +
facet_wrap(ses ~ female, ncol = 2)
And finally, a few suggestion about how to build up your visualizations:
- π start with pencil and paper, sketch prototypes of desired visualization(s)
- π graphics are relatively easy to generate with base R & with
ggplot2
- π common-sense:
number
& type
of variable(s) guide plotting
- π stay
color conscious
: sensible colors & sensitive to color blindness
- π° experiment, experiment, experiment until you are happy
- use the π learning resources available online
- π if you learn something new in R, write it down
LS0tCnRpdGxlOiAiTVBBIDU4MzAgLSBNb2R1bGUgMDUiCnN1YnRpdGxlOiAiU3ByaW5nIDIwMjAiCmF1dGhvcjogIlByb2Zlc3NvciBSdWhpbCIKZGF0ZTogIlVwZGF0ZWQgb24gYHIgU3lzLkRhdGUoKWAiCm91dHB1dDogCiAgaHRtbF9kb2N1bWVudDogCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMKICAgIGZpZ19jYXB0aW9uOiB5ZXMKICAgIGhpZ2hsaWdodDogemVuYnVybgogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMKICAgIHRoZW1lOiBmbGF0bHkKICAgIHRvYzogeWVzCiAgICB0b2NfZmxvYXQ6IHllcwplZGl0b3Jfb3B0aW9uczogCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGNvbnNvbGUKLS0tCgo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPgoKYm9keXsgLyogTm9ybWFsICAqLwovKiAgICBmb250LWZhbWlseTogTGF0bywgc2Fucy1zZXJpZjsgIAogICAgICBmb250LWZhbWlseTogTXVrdGEsIHNhbnMtc2VyaWY7IAogICAgICBmb250LWZhbWlseTogJ051bml0byBTYW5zJywgc2Fucy1zZXJpZjsKICAgICAgZm9udC1mYW1pbHk6IEthcmxhLCBzYW5zLXNlcmlmOyAgKi8KICAgICAgZm9udC1mYW1pbHk6ICdNZXJyaXdlYXRoZXIgU2FucycsIHNhbnMtc2VyaWY7IAogICAgICBmb250LXNpemU6IDE4cHg7CiAgfQoKaDEudGl0bGUgewogIGZvbnQtc2l6ZTogMzhweDsKICBjb2xvcjogRGFya1JlZDsKfQoKaDEgeyAvKiBIZWFkZXIgMSAqLwogIGZvbnQtc2l6ZTogMjhweDsKICBjb2xvcjogRGFya0JsdWU7Cn0KCmgyIHsgLyogSGVhZGVyIDIgKi8KICAgIGZvbnQtc2l6ZTogMjJweDsKICBjb2xvcjogRGFya0JsdWU7Cn0KCmgzIHsgLyogSGVhZGVyIDMgKi8KICBmb250LXNpemU6IDE4cHg7CiAgY29sb3I6IERhcmtCbHVlOwp9Cgpjb2RlLnJ7IC8qIENvZGUgYmxvY2sgKi8KICAgIGZvbnQtZmFtaWx5OiBNdWt0YSwgc2Fucy1zZXJpZjsgCiAgICBmb250LXdlaWdodDogNjAwOyAgCiAgICBmb250LXNpemU6IDE2cHg7Cn0KCi8qIHByZSB7IC8qIENvZGUgYmxvY2sgLSBkZXRlcm1pbmVzIGNvZGUgc3BhY2luZyBiZXR3ZWVuIGxpbmVzICovCiAgICBmb250LXNpemU6IDE2cHg7Cn0gKi8KPC9zdHlsZT4KCgpgYGB7ciBrbGlwcHksIGVjaG8gPSBGQUxTRSwgaW5jbHVkZSA9IFRSVUV9CmtsaXBweTo6a2xpcHB5KHRvb2x0aXBfbWVzc2FnZSA9ICdDbGljayB0byBjb3B5JywgdG9vbHRpcF9zdWNjZXNzID0gJ0RvbmUnLCBjb2xvciA9ICdjb3JuZmxvd2VyYmx1ZScsIHBvc2l0aW9uID0gYygndG9wJywgJ3JpZ2h0JykpCmBgYAoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0UsIGRwaSA9IDMwMCwgY2FjaGUgPSBUUlVFLCBmaWcuYWxpZ24gPSAiY2VudGVyIiwgZmlnLndpZHRoID0gNywgZmlnLmhlaWdodCA9IDUsIG91dC53aWR0aCA9ICIxMDAlIiwgaGlnaGxpZ2h0ID0gVFJVRSkgCmBgYAoKT3VyIGdvYWwgaW4gdGhpcyBtb2R1bGUgaXMgdG8gdW5kZXJzdGFuZCBzb21lIGJhc2ljIHdheXMgb2YgdmlzdWFsaXppbmcgZGF0YSB3aXRoIGdyYXBoaWNzIC0tIGJhci1jaGFydHMsIGhpc3RvZ3JhbXMsIGJveC1wbG90cywgYW5kIHNvIG9uLiBXZSB3aWxsIHNraXAgYGJhc2UgUmAgY29tbWFuZHMgYW5kIGluc3RlYWQganVzdCB3b3JrIHdpdGggYGdncGxvdDJgLCB0aGUgbW9zdCBwb3B1bGFyIHZpc3VhbGl6YXRpb24gcGFja2FnZSBpbiB0aGUgYHt0aWR5dmVyc2V9YCB1bml2ZXJzZSBhcyBvZiBub3cuIAoKSWYgeW91IHJlbWVtYmVyIE1QQSA2MDEwLCByZWNhbGwgdGhlIHVzdWFsIG9wdGlvbnMuLi4gCgotIG9uZSBxdWFsaXRhdGl2ZS9jYXRlZ29yaWNhbCB2YXJpYWJsZXM6IGBiYXItY2hhcnRgIAotIG9uZSBxdWFudGl0YXRpdmUvY29udGludW91cyB2YXJpYWJsZXM6IGBoaXN0b2dyYW0vYm94LXBsb3QvYXJlYS1jaGFydGAgIAotIHR3byBxdWFudGl0YXRpdmUvY29udGludW91cyB2YXJpYWJsZXM6IGBzY2F0dGVyLXBsb3QvaGV4LWJpbmAgCgpXZSBjYW4gdGhlbiByYXRjaGV0IHVwIGFzIHdlIG5lZWQgdG8uIAoKSSB3aWxsIHVzZSB0d28gZGF0YS1zZXRzIHRvIHdhbGsgdGhyb3VnaCB0aGUgaW5pdGlhbCBleGFtcGxlcyBpbiB0aGlzIG1vZHVsZSwgdGhlIGZpcnN0IGJlaW5nIHRoaXMgW0lNREIgZGF0YS1zZXRdKGh0dHA6Ly9pbWRiLmNvbS8pCgo+IFRoZSBpbnRlcm5ldCBtb3ZpZSBkYXRhYmFzZSwgaHR0cDovL2ltZGIuY29tLywgaXMgYSB3ZWJzaXRlIGRldm90ZWQgdG8gY29sbGVjdGluZyBtb3ZpZSBkYXRhIHN1cHBsaWVkIGJ5IHN0dWRpb3MgYW5kIGZhbnMuIEl0IGNsYWltcyB0byBiZSB0aGUgYmlnZ2VzdCBtb3ZpZSBkYXRhYmFzZSBvbiB0aGUgd2ViIGFuZCBpcyBydW4gYnkgYW1hem9uLiBNb3JlIGFib3V0IGluZm9ybWF0aW9uIGltZGIuY29tIGNhbiBiZSBmb3VuZCBvbmxpbmUsIGh0dHA6Ly9pbWRiLmNvbS9oZWxwL3Nob3dfIGxlYWY/YWJvdXQsIGluY2x1ZGluZyBpbmZvcm1hdGlvbiBhYm91dCB0aGUgZGF0YSBjb2xsZWN0aW9uIHByb2Nlc3MsIGh0dHA6Ly9pbWRiLmNvbS9oZWxwL3Nob3dfbGVhZj9pbmZvc291cmNlLgoKYGBge3IgbW92aWVzfQpsaWJyYXJ5KGdncGxvdDJtb3ZpZXMpCmRhdGEobW92aWVzKQpuYW1lcyhtb3ZpZXMpCmBgYAoKQSBkYXRhIGZyYW1lIHdpdGggMjg4MTkgcm93cyBhbmQgMjQgdmFyaWFibGVzIAoKfCBWYXJpYWJsZSB8IERlc2NyaXB0aW9uIHwKfCA6LS0gfCA6LS0gfAp8IHRpdGxlIHwgVGl0bGUgb2YgdGhlIG1vdmllIHwKfCB5ZWFyIHwgWWVhciBvZiByZWxlYXNlIHwKfCBidWRnZXQgfCBUb3RhbCBidWRnZXQgKGlmIGtub3duKSBpbiBVUyBkb2xsYXJzIHwKfCBsZW5ndGggfCBMZW5ndGggaW4gbWludXRlcyB8CnwgcmF0aW5nIHwgQXZlcmFnZSBJTURCIHVzZXIgcmF0aW5nIHwKfCB2b3RlcyB8IE51bWJlciBvZiBJTURCIHVzZXJzIHdobyByYXRlZCB0aGlzIG1vdmllIHwKfCByMS0xMCB8IE11bHRpcGx5aW5nIGJ5IHRlbiBnaXZlcyBwZXJjZW50aWxlICh0byBuZWFyZXN0IDEwJSkgb2YgdXNlcnMgd2hvIHJhdGVkIHRoaXMgbW92aWUgYSAxIHwKfCBtcGFhIHwgTVBBQSByYXRpbmcgKG1pc3NpbmcgZm9yIGEgbG90IG9mIG1vdmllcykgfAp8IGFjdGlvbiwgYW5pbWF0aW9uLCBjb21lZHksIGRyYW1hLCBkb2N1bWVudGFyeSwgcm9tYW5jZSwgc2hvcnQgfCBCaW5hcnkgdmFyaWFibGVzIHJlcHJlc2VudGluZyBpZiBtb3ZpZSB3YXMgY2xhc3NpZmllZCBhcyBiZWxvbmdpbmcgdG8gdGhhdCBnZW5yZSB8CgoKVGhlIHNlY29uZCBkYXRhLXNldCBpcyB0aGUgW1N0YXIgV2FycyBkYXRhc2V0XShodHRwczovL3N3YXBpLmNvKSwgYSBgdGliYmxlYCB3aXRoIDg3IHJvd3MgYW5kIDEzIHZhcmlhYmxlczoKCmBgYHtyIHN0YXJ3YXJzfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKZGF0YShzdGFyd2FycykKbmFtZXMoc3RhcndhcnMpCiMgc3RyKHN0YXJ3YXJzKQpgYGAKCnwgVmFyaWFibGUgfCBEZXNjcmlwdGlvbiB8CnwgOi0tIHwgOi0tIHwKfCBuYW1lIHwgTmFtZSBvZiB0aGUgY2hhcmFjdGVyIHwKfCBoZWlnaHQgfCBIZWlnaHQgKGNtKSB8CnwgbWFzcyB8IFdlaWdodCAoa2cpIHwKfCBoYWlyX2NvbG9yLCBza2luX2NvbG9yLCBleWVfY29sb3IgfCBIYWlyLCBza2luLCBhbmQgZXllIGNvbG9ycyB8CnwgYmlydGhfeWVhciB8IFllYXIgYm9ybiAoQkJZID0gQmVmb3JlIEJhdHRsZSBvZiBZYXZpbikgfAp8IGdlbmRlciB8IG1hbGUsIGZlbWFsZSwgaGVybWFwaHJvZGl0ZSwgb3Igbm9uZSB8CnwgaG9tZXdvcmxkIHwgTmFtZSBvZiBob21ld29ybGQgfAp8IHNwZWNpZXMgfCBOYW1lIG9mIHNwZWNpZXMgfAp8IGZpbG1zIHwgTGlzdCBvZiBmaWxtcyB0aGUgY2hhcmFjdGVyIGFwcGVhcmVkIGluIHwKfCB2ZWhpY2xlcyB8IExpc3Qgb2YgdmVoaWNsZXMgdGhlIGNoYXJhY3RlciBoYXMgcGlsb3RlZCB8Cnwgc3RhcnNoaXBzIHwgTGlzdCBvZiBzdGFyc2hpcHMgdGhlIGNoYXJhY3RlciBoYXMgcGlsb3RlZCB8CgoKIyBgZ2dwbG90MmAgYW5kIHRoZSBbZ3JhbW1hciBvZiBncmFwaGljc10oaHR0cDovL3ZpdGEuaGFkLmNvLm56L3BhcGVycy9sYXllcmVkLWdyYW1tYXIuaHRtbCkKClRoZSBge2dncGxvdDJ9YCBwYWNrYWdlIGhhcyBhIHNwZWNpYWwgc3ludGF4IGFuZCBJIHdpbGwgcG9pbnQgb3V0IHRoaW5ncyB5b3Ugc2hvdWxkIG5vdGUgYXMgd2UgbW92ZSB0aHJvdWdoIHRoaXMgbW9kdWxlLiBGaXJzdCB1cCwgdGhlIGxpYnJhcnkgaXMgY2FsbGVkIGBnZ3Bsb3QyYCBidXQgdGhlIGNvbW1hbmQgc3RhcnRzIHdpdGggYGdncGxvdGAgc28gZG9uJ3QgbGV0IHRoYXQgdGhyb3cgeW91IG9mZi10cmFjay4gCgpTZWNvbmQsIHlvdSBuZWVkIHRvIGhhdmUgYSBkYXRhLXNldCB0byB3b3JrIHdpdGguIEluIHRoZSBjb2RlIGJlbG93IEkgc3RhcnQgYnkgbG9hZGluZyB0aGUgbGlicmFyeSBhbmQgdGhlbiBzcGVjaWZ5aW5nIHRoZSBkYXRhLXNldCB0byBiZSB1c2VkLiAKCmBgYHtyIGdnMDAwfQpsaWJyYXJ5KGdncGxvdDIpCmdncGxvdCgKICBkYXRhID0gc3RhcndhcnMKICApCmBgYAoKTm90aGluZyByZXN1bHRzIGZyb20gdGhlc2UgY29tbWFuZHMgYmVjYXVzZSB3ZSBoYXZlIG5vdCB5ZXQgc3BlY2lmaWVkIGFueXRoaW5nIGFib3V0IHdoYXQgc2hvdWxkIGdvIG9uIHRoZSB4LWF4aXMsIHdoYXQgc2hvdWxkIGdvIG9uIHRoZSB5LWF4aXMuIFdlbGwsIGxldCB1cyBkbyB0aGF0IHRoZW4gYnkgYXNraW5nIGZvciB0aGUgY29sdW1uIGBleWVfY29sb3JgIHRvIGJlIHB1dCBvbiB0aGUgeC1heGlzLiAKCmBgYHtyIGdnMDAxfQpnZ3Bsb3QoCiAgZGF0YSA9IHN0YXJ3YXJzLAogIG1hcHBpbmcgPSBhZXMoCiAgICB4ID0gZXllX2NvbG9yCiAgICApCiAgKSAKYGBgCgojIyBgZ2VvbV9iYXIoKWAgLi4uIHRoZSBiYXItY2hhcnQgClRoaXMgcmVzdWx0cyBpbiBhIGdyYXkgY2FudmFzIHdpdGggdGhlIGV5ZSBjb2xvcnMgb24gdGhlIHgtYXhpcyBidXQgbm90aGluZyBlbHNlIGhhcyBiZWVuIGRyYXduIHNpbmNlIHdlIGhhdmUgbm90IHNwZWNpZmllZCB0aGUgYGdlb21ldHJ5YCAuLi4gZG8geW91IHdhbnQgYSBiYXItY2hhcnQ/IGhpc3RvZ3JhbT8gZG90LXBsb3Q/IGxpbmUtY2hhcnQ/IFRoaXMgaXMgYSBjYXRlZ29yaWNhbCB2YXJpYWJsZSBhbmQgaGVuY2UgYSBiYXItY2hhcnQgd291bGQgYmUgYXBwcm9wcmlhdGUuIFdlIGNhbGwgZm9yIGEgYmFyLWNoYXJ0IHdpdGggdGhlIGBnZW9tX2JhcigpYCBjb21tYW5kLiAKCmBgYHtyIGdnMDAyYX0KZ2dwbG90KAogIGRhdGEgPSBzdGFyd2FycywKICBtYXBwaW5nID0gYWVzKAogICAgeCA9IGV5ZV9jb2xvcgogICAgKQogICkgKwogIGdlb21fYmFyKCkKYGBgCgojIyBgY29sb3JgIHZlcnN1cyBgZmlsbGAgClRoZSBgYWVzKClgIHJlZmVycyB0byB0aGUgKiphZXN0aGV0aWNzKiogb2YgdGhlIGNoYXJ0LCBhbmQgbWFueSBvdGhlciBgYWVzdGhldGljc2AgY2FuIGJlIGFkZGVkLCBzdWNoIGFzIGBncm91cGAsIGBjb2xvcmAsIGBmaWxsYCwgYHNpemVgLCBgYWxwaGFgLCBldGMuIFdlIHdpbGwgc2VlIHNvbWUgb2YgdGhlc2UgaW4gZHVlIGNvdXJzZSBidXQgZm9yIG5vdyBJIHdhbnQgdG8gZm9jdXMgb24gdHdvIG9mIHRoZXNlLCBib3RoIGludm9sdmluZyBjb2xvcmluZyBvZiB0aGUgYGdlb21fYC4gU3BlY2lmaWNhbGx5LCB0aGVyZSBhcmUgdHdvIGNvbW1hbmRzIGZvciBhZGRpbmcgY29sb3JzIC0tICgxKSBgY29sb3JgIG9yIGBjb2xvdXJgLCBhbmQgKDIpIGBmaWxsYCAtLSB0byBhIGNoYXJ0LiAKCmBgYHtyIGNvbDFhfQpnZ3Bsb3QoCiAgZGF0YSA9IHN0YXJ3YXJzLAogIG1hcHBpbmcgPSBhZXMoCiAgICB4ID0gZXllX2NvbG9yLAogICAgY29sb3IgPSBleWVfY29sb3IKICAgICkKICApICsKICBnZW9tX2JhcigpCmBgYAoKTm90ZSB3aGF0IHRoZSBgY29sb3IgPSBleWVfY29sb3JgIGNvbW1hbmQgZGlkIC4uLiBpdCBkcmV3IGEgY29sb3JlZCBib3JkZXIgZm9yIHRoZSBiYXJzLCBhbmQgYW4gYWNjb21wYW55aW5nIGxlZ2VuZC4gV2hhdCBpZiB3ZSBoYWQgdXNlZCBgZmlsbCA9IGV5ZV9jb2xvcmAgaW5zdGVhZD8gIAoKYGBge3IgY29sMWJ9CmdncGxvdCgKICBkYXRhID0gc3RhcndhcnMsCiAgbWFwcGluZyA9IGFlcygKICAgIHggPSBleWVfY29sb3IsCiAgICBmaWxsID0gZXllX2NvbG9yCiAgICApCiAgKSArCiAgZ2VvbV9iYXIoKQpgYGAKCkFoYSEgTm93IHRoZSBiYXJzIGFyZSBmaWxsZWQgd2l0aCBjb2xvcnMgYW5kIGFuIGFjY29tcGFueWluZyBsZWdlbmQgaXMgZHJhd24gYXMgd2VsbC4gU28gYGZpbGwgPWAgYW5kIGBjb2xvciA9YCBiZWhhdmUgdmVyeSBkaWZmZXJlbnRseSwgYmVhciB0aGlzIGluIG1pbmQuIAoKIyMgQWRkaW5nIGxhYmVscyB3aXRoIGBsYWJzYCAKT25lIG9mIHRoZSBuaWNlIHRoaW5ncyBhYm91dCB0aGlzIHNvZnR3YXJlIGVudmlyb25tZW50IGlzIHRoYXQgdGhlcmUgYXJlIHBsZW50eSBvZiBjb2xvcmluZyBzY2hlbWVzIGF2YWlsYWJsZSB0byB1cyBhbmQgd2Ugd2lsbCBwbGF5IHdpdGggc29tZSBvZiB0aGVzZSBzaG9ydGx5LCBidXQgYmVmb3JlIHdlIGRvIHRoYXQsIGxldCB1cyBsb29rIGF0IG9uZSBtb3JlIGltcHJvdmVtZW50IC0tIGFkZGluZyB0aXRsZXMsIHN1YnRpdGxlcywgY2FwdGlvbnMsIGFuZCBheGlzIGxhYmVscyB0byBvdXIgY2hhcnQuIFRoaXMgaXMgZG9uZSB3aXRoIHRoZSBgbGFicyA9ICgpYCBjb21tYW5kLgoKYGBge3IgY29sMWIyfQpnZ3Bsb3QoCiAgZGF0YSA9IHN0YXJ3YXJzLAogIG1hcHBpbmcgPSBhZXMoCiAgICB4ID0gZXllX2NvbG9yLAogICAgZmlsbCA9IGV5ZV9jb2xvcgogICAgKQogICkgKwogIGdlb21fYmFyKCkgKwogIGxhYnMoCiAgICB4ID0gIkV5ZSBDb2xvciIsCiAgICB5ID0gIkZyZXF1ZW5jeSAobikiLAogICAgdGl0bGUgPSAiQmFyLWNoYXJ0IG9mIEV5ZSBDb2xvcnMiLAogICAgc3VidGl0bGUgPSAiKG9mIFN0YXIgV2FycyBjaGFyYWN0ZXJzKSIsCiAgICBjYXB0aW9uID0gIk15IGxpdHRsZSB3b3JrIG9mIGFydCEhIgogICAgKQpgYGAKCk5vdGljZSB0aGUgdGV4dCB0aGF0IG5vdyBhcHBlYXJzIGFzIGEgcmVzdWx0IG9mIHdoYXQgaGFzIGJlZW4gc3BlY2lmaWVkIGluIHRoZSBgbGFicygpYCBjb21tYW5kLiAKCiMjIENvbnRyb2xsaW5nIHRoZSBjaGFydCBsZWdlbmQgd2l0aCBgdGhlbWUoKWAKSW4gdGhpcyBiYXItY2hhcnQsIGRvIHdlIHJlYWxseSBuZWVkIHRoZSBsZWdlbmQ/IE5vLCBiZWNhdXNlIHRoZSBjb2xvcnMgYW5kIGNvbG9yIG5hbWVzIHNob3cgdXAgaW4gdGhlIGNoYXJ0IGl0c2VsZi4gSG93IGNhbiB3ZSBoaWRlIHRoZSBsZWdlbmQ/IFR1cm5zIG91dCB0aGVyZSBpcyBhIG5lYXQgY29tbWFuZCB0aGF0IHdpbGwgYWxsb3cgeW91IHRvIG1vdmUgdGhlIGxlZ2VuZCBhcm91bmQgYW5kIGV2ZW4gdG8gaGlkZSBpdC4gCgpgYGB7ciBjb2wxY30KZ2dwbG90KAogIGRhdGEgPSBzdGFyd2FycywKICBtYXBwaW5nID0gYWVzKAogICAgeCA9IGV5ZV9jb2xvciwKICAgIGZpbGwgPSBleWVfY29sb3IKICAgICkKICApICsKICBnZW9tX2JhcigpICsKICBsYWJzKAogICAgeCA9ICJFeWUgQ29sb3IiLAogICAgeSA9ICJGcmVxdWVuY3kgKG4pIiwKICAgIHRpdGxlID0gIkJhci1jaGFydCBvZiBFeWUgQ29sb3JzIiwKICAgIHN1YnRpdGxlID0gIihvZiBTdGFyIFdhcnMgY2hhcmFjdGVycykiLAogICAgY2FwdGlvbiA9ICJNeSBsaXR0bGUgd29yayBvZiBhcnQhISIKICAgICkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKYGBgCgpWb2lsYSEgVGhlIGxlZ2VuZCBpcyBnb25lLiBJbnN0ZWFkIG9mICJub25lIiB5b3UgY291bGQgaGF2ZSBzcGVjaWZpZWQgImJvdHRvbSIsICJsZWZ0IiwgInRvcCIsICJyaWdodCIgdG8gcGxhY2UgdGhlIGxlZ2VuZCBpbiBhIHBhcnRpY3VsYXIgZGlyZWN0aW9uLgoKIyMgQ3VzdG9taXppbmcgY29sb3JzIApPZiBjb3Vyc2UsIGl0IHdvdWxkIGJlIGdvb2QgdG8gaGF2ZSB0aGUgY29sb3JzIG1hdGNoIHRoZSBleWUtY29sb3Igc28gbGV0IHVzIGRvIHRoYXQgbmV4dC4gVGhlIHdheSB3ZSBjYW4gZG8gdGhpcyBpcyBieSBjYWxsaW5nIHNwZWNpZmljIGNvbG9ycyBieSBuYW1lLiBJIGhhdmUgdHJpZWQgdG8gb3JkZXIgdGhlIGxpbmV1cCBvZiB0aGUgY29sb3JzIHRvIG1hdGNoLCBhcyBjbG9zZWx5IGFzIEkgY2FuLCB0aGUgZXllIGNvbG9ycy4gCgpgYGB7ciBjb2wzfQpjKAogICJibGFjayIsICJibHVlIiwgInNsYXRlZ3JheSIsICJicm93biIsICJncmF5MzQiLCAiZ29sZCIsCiAgImdyZWVueWVsbG93IiwgIm5hdmFqb3doaXRlMSIsICJvcmFuZ2UiLCAicGluayIsICJyZWQiLAogICJtYWdlbnRhIiwgInRoaXN0bGUzIiwgIndoaXRlIiwgInllbGxvdyIKICApIC0+IG15Y29sb3JzCgpnZ3Bsb3QoCiAgZGF0YSA9IHN0YXJ3YXJzLAogIG1hcHBpbmcgPSBhZXMoCiAgICB4ID0gZXllX2NvbG9yCiAgICApCiAgKSArIAogIGdlb21fYmFyKAogICAgZmlsbCA9IG15Y29sb3JzCiAgICApICsgCiAgbGFicygKICAgIHggPSAiRXllIENvbG9yIiwKICAgIHkgPSAiRnJlcXVlbmN5IChuKSIsCiAgICB0aXRsZSA9ICJCYXItY2hhcnQgb2YgRXllIENvbG9ycyIsCiAgICBzdWJ0aXRsZSA9ICIob2YgU3RhciBXYXJzIGNoYXJhY3RlcnMpIiwKICAgIGNhcHRpb24gPSAiTXkgbGl0dGxlIHdvcmsgb2YgYXJ0ISEiCiAgICApICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCmBgYAoKVGhlc2UgY29sb3JzIGFyZSBmcm9tIFt0aGlzIHNvdXJjZV0oaHR0cDovL3d3dy5zdGF0LmNvbHVtYmlhLmVkdS9+dHpoZW5nL2ZpbGVzL1Jjb2xvci5wZGYpIGJ1dCBzZWUgYWxzbyBbdGhpcyBzb3VyY2VdKGh0dHBzOi8vd3d3Lm5jZWFzLnVjc2IuZWR1L35mcmF6aWVyL1JTcGF0aWFsR3VpZGVzL2NvbG9yUGFsZXR0ZUNoZWF0c2hlZXQucGRmKS4gQ29sb3JzIGNhbiBiZSBjdXN0b21pemVkIGJ5IGdlbmVyYXRpbmcgeW91ciBvd24gcGFsZXR0ZXMgdmlhIHRoZSBbQ29sb3IgQnJld2VyIGhlcmVdKGh0dHA6Ly9jb2xvcmJyZXdlcjIub3JnLyN0eXBlPXNlcXVlbnRpYWwmc2NoZW1lPVlsR25CdSZuPTMpLiBCdXQgZG9uJ3QgZ2V0IGNhcnJpZWQgYXdheTogUmVtZW1iZXIgdG8gcmVhZCB0aGUgbWF0ZXJpYWxzIG9uIGNob29zaW5nIGNvbG9ycyB3aXNlbHksIHBhcnRpY3VsYXJseSB0aGUgcG9pbnQgYWJvdXQgcXVhbGl0YXRpdmUgcGFsZXR0ZXMsIGRpdmVyZ2VudCBwYWxldHRlcywgYW5kIHRoZW4gcGFsZXR0ZXMgdGhhdCB3b3JrIHdlbGwgZXZlbiB3aXRoIGNvbG9yYmxpbmQgYXVkaWVuY2VzLgoKIyMgU2VsZWN0ZWQgY29sb3IgcGFsZXR0ZXMKSSBoYWQgbWVudGlvbmVkIHRoZSBleGlzdGVuY2Ugb2YgYSBudW1iZXIgb2YgY29sb3IgcGFsZXR0ZXMgc28gbGV0IHVzIGxvb2sgYXQgYSBmZXcsIGJ1dCB3ZSB3aWxsIGRvIHRoaXMgd2l0aCBhIGRpZmZlcmVudCB2YXJpYWJsZS4gRmlyc3QgdXAsIHRoZSBgUGFzdGVsMWAgcGFsZXR0ZS4gCgpgYGB7ciBjb2xmaWxsYjF9CmdncGxvdCgKICBkYXRhID0gc3RhcndhcnMsCiAgbWFwcGluZyA9IGFlcygKICAgIHggPSBnZW5kZXIKICAgICkKICApICsgCiAgZ2VvbV9iYXIoCiAgICBhZXMoZmlsbCA9IGdlbmRlcikKICAgICkgKyAKICBsYWJzKAogICAgeCA9ICJHZW5kZXIiLAogICAgeSA9ICJGcmVxdWVuY3kiLAogICAgdGl0bGUgPSAiQmFyLWNoYXJ0IG9mIEdlbmRlciIsCiAgICBzdWJ0dGl0bGUgPSAiKG9mIFN0YXIgV2FycyBjaGFyYWN0ZXJzKSIsCiAgICBjYXB0aW9uID0gIihTb3VyY2U6IFRoZSBkcGx5ciBwYWNrYWdlKSIpICsKICBzY2FsZV9maWxsX2JyZXdlcigKICAgIHBhbGV0dGUgPSAiUGFzdGVsMSIKICAgICkKYGBgCgpOb3QgYmFkIGJ1dCBkb2Vzbid0IHdvcmsgdG9vIHdlbGwgaGVyZS4gSG93IGFib3V0IHRyeWluZyBhbm90aGVyIHBhbGV0dGUsIGBTZXRgPwoKYGBge3IgY29sZmlsbGIyfQpnZ3Bsb3QoCiAgZGF0YSA9IHN0YXJ3YXJzLAogIG1hcHBpbmcgPSBhZXMoCiAgICB4ID0gZ2VuZGVyCiAgICApCiAgKSArIAogIGdlb21fYmFyKAogICAgYWVzKGZpbGwgPSBnZW5kZXIpCiAgICApICsgCiAgbGFicygKICAgIHggPSAiR2VuZGVyIiwKICAgIHkgPSAiRnJlcXVlbmN5IiwKICAgIHRpdGxlID0gIkJhci1jaGFydCBvZiBHZW5kZXIiLAogICAgc3VidHRpdGxlID0gIihvZiBTdGFyIFdhcnMgY2hhcmFjdGVycykiLAogICAgY2FwdGlvbiA9ICIoU291cmNlOiBUaGUgZHBseXIgcGFja2FnZSkiKSArCiAgc2NhbGVfZmlsbF9icmV3ZXIoCiAgICBwYWxldHRlID0gIlNldDEiCiAgICApCmBgYAoKTmljZSEgQnV0IHdoYXQgaXMgYWxzbyBub3RpY2VhYmxlIGhlcmUgaXMgdGhhdCB0aGVyZSBhcmUgc29tZSBjaGFyYWN0ZXJzIGluIHRoZSBkYXRhLXNldCB3aG9zZSBnZW5kZXIgZGF0YSBpcyBtaXNzaW5nLiBUaGVzZSBhcmUgdGhlIGBOQWAgdmFsdWVzLiBCeSBkZWZhdWx0LCB5b3Ugd2lsbCBzZWUgYE5BYCB2YWx1ZXMgc2hvd2luZyB1cCBpbiBzb21lIHR5cGVzIG9mIGNoYXJ0cyBhbmQgc28gaXQgaXMgYWx3YXlzIGdvb2QgdG8gZXhjbHVkZSB0aGVtIGZyb20gdGhlIGNoYXJ0LiBIZXJlIGlzIG9uZSB3YXkgb2YgZG9pbmcgdGhhdC4gCgpgYGB7ciBjb2xmaWxsYjN9CmdncGxvdCgKICBkYXRhID0gc3Vic2V0KHN0YXJ3YXJzLCAhaXMubmEoZ2VuZGVyKSksCiAgbWFwcGluZyA9IGFlcygKICAgIHggPSBnZW5kZXIKICAgICkKICApICsgCiAgZ2VvbV9iYXIoCiAgICBhZXMoZmlsbCA9IGdlbmRlcikKICAgICkgKyAKICBsYWJzKAogICAgeCA9ICJHZW5kZXIiLAogICAgeSA9ICJGcmVxdWVuY3kiLAogICAgdGl0bGUgPSAiQmFyLWNoYXJ0IG9mIEdlbmRlciIsCiAgICBzdWJ0dGl0bGUgPSAiKG9mIFN0YXIgV2FycyBjaGFyYWN0ZXJzKSIsCiAgICBjYXB0aW9uID0gIihTb3VyY2U6IFRoZSBkcGx5ciBwYWNrYWdlKSIpICsKICBzY2FsZV9maWxsX2JyZXdlcigKICAgIHBhbGV0dGUgPSAiU2V0MSIKICAgICkKYGBgCgpOb3RpY2Ugd2hhdCBpcyBkaWZmZXJlbnQgaGVyZTogYGRhdGEgPSBzdWJzZXQoc3RhcndhcnMsICFpcy5uYShnZW5kZXIpKWAgYW5kIHRoYXQgdGhpcyBjb21tYW5kIGlzIGVmZmVjdGl2ZWx5IHNheWluZyBzdWJzZXQgdGhlIHN0YXJ3YXJzIGRhdGEgdG8gb25seSBpbmNsdWRlIHRob3NlIGNhc2VzIHdoZXJlIGdlbmRlciBpcyBub3QgbWlzc2luZyAodGhpcyBpcyB0aGUgYCFpcy5uYSgpYCBwb3J0aW9uIG9mIHRoZSBjb21tYW5kKS4gCgpBbm90aGVyIHdheSB0byBkbyB0aGUgc2FtZSB0aGluZyB3b3VsZCBoYXZlIGJlZW4gdG8gdXNlIGBmaWx0ZXIoKWAgYW5kIGNyZWF0ZSBhIGNsZWFuZWQgdXAgY29weSBvZiB0aGUgZGF0YS4gSWYgeW91IHRha2UgdGhpcyByb3V0ZSwgYmUgY2FyZWZ1bCBub3QgdG8gb3ZlcndyaXRlIHRoZSBvcmlnaW5hbCBkYXRhLXNldDsgbm90ZSBob3cgSSBhbSBnaXZpbmcgYSBuZXcgbmFtZSBgKG15LmRhdGEpYCBhZnRlciBgZmlsdGVyKClgIHRvIHNhdmUgdGhlIHJlc3VsdHMgaW4uIFRoZW4gd2UgbGVhbiBvbiB0aGlzIGRhdGEtc2V0IHZpYSBgZGF0YSA9IG15LmRhdGFgLgoKYGBge3IgY29sZmlsbGI0fQpzdGFyd2FycyAlPiUKICBmaWx0ZXIoIWlzLm5hKGdlbmRlcikpIC0+IG15LmRhdGEKCmdncGxvdCgKICBkYXRhID0gbXkuZGF0YSwKICBtYXBwaW5nID0gYWVzKAogICAgeCA9IGdlbmRlcgogICAgKQogICkgKyAKICBnZW9tX2JhcigKICAgIGFlcyhmaWxsID0gZ2VuZGVyKQogICAgKSArIAogIGxhYnMoCiAgICB4ID0gIkdlbmRlciIsCiAgICB5ID0gIkZyZXF1ZW5jeSIsCiAgICB0aXRsZSA9ICJCYXItY2hhcnQgb2YgR2VuZGVyIiwKICAgIHN1YnR0aXRsZSA9ICIob2YgU3RhciBXYXJzIGNoYXJhY3RlcnMpIiwKICAgIGNhcHRpb24gPSAiKFNvdXJjZTogVGhlIGRwbHlyIHBhY2thZ2UpIikgKwogIHNjYWxlX2ZpbGxfYnJld2VyKAogICAgcGFsZXR0ZSA9ICJTZXQxIgogICAgKQpgYGAKClRoZXJlIGlzIG9uZSBjb2xvciBwYWxldHRlIHlvdSBzaG91bGQgcmVtZW1iZXIsIGFuZCB0aGlzIGlzIHRoZSBge3ZpcmlkaXN9YCBjb2xvciBzY2hlbWUgdGhhdCB3b3JrcyBhcm91bmQgdmFyeWluZyB0eXBlcyBvZiBjb2xvciBibGluZG5lc3MgaW4gdGhlIHBvcHVsYXRpb24uIEhlcmUgY29tZSB0aGUgcGFsZXR0ZXM6CgpgYGB7ciBjb2xmaWxsdjF9CmdncGxvdCgKICBkYXRhID0gbXkuZGF0YSwKICBtYXBwaW5nID0gYWVzKAogICAgeCA9IGdlbmRlcgogICAgKQogICkgKyAKICBnZW9tX2JhcigKICAgIGFlcyhmaWxsID0gZ2VuZGVyKQogICAgKSArIAogIGxhYnMoCiAgICB4ID0gIkdlbmRlciIsCiAgICB5ID0gIkZyZXF1ZW5jeSIsCiAgICB0aXRsZSA9ICJCYXItY2hhcnQgb2YgR2VuZGVyIiwKICAgIHN1YnR0aXRsZSA9ICIob2YgU3RhciBXYXJzIGNoYXJhY3RlcnMpIiwKICAgIGNhcHRpb24gPSAiKFNvdXJjZTogVGhlIGRwbHlyIHBhY2thZ2UpIikgKwogIHNjYWxlX2ZpbGxfdmlyaWRpc19kKAogICAgb3B0aW9uID0gInZpcmlkaXMiCiAgICApCmBgYAoKYGBge3IgY29sZmlsbHYyfQpnZ3Bsb3QoCiAgZGF0YSA9IG15LmRhdGEsCiAgbWFwcGluZyA9IGFlcygKICAgIHggPSBnZW5kZXIKICAgICkKICApICsgCiAgZ2VvbV9iYXIoCiAgICBhZXMoZmlsbCA9IGdlbmRlcikKICAgICkgKyAKICBsYWJzKAogICAgeCA9ICJHZW5kZXIiLAogICAgeSA9ICJGcmVxdWVuY3kiLAogICAgdGl0bGUgPSAiQmFyLWNoYXJ0IG9mIEdlbmRlciIsCiAgICBzdWJ0dGl0bGUgPSAiKG9mIFN0YXIgV2FycyBjaGFyYWN0ZXJzKSIsCiAgICBjYXB0aW9uID0gIihTb3VyY2U6IFRoZSBkcGx5ciBwYWNrYWdlKSIpICsKICBzY2FsZV9maWxsX3ZpcmlkaXNfZCgKICAgIG9wdGlvbiA9ICJtYWdtYSIKICAgICkKYGBgCgpgYGB7ciBjb2xmaWxsdjN9CmdncGxvdCgKICBkYXRhID0gbXkuZGF0YSwKICBtYXBwaW5nID0gYWVzKAogICAgeCA9IGdlbmRlcgogICAgKQogICkgKyAKICBnZW9tX2JhcigKICAgIGFlcyhmaWxsID0gZ2VuZGVyKQogICAgKSArIAogIGxhYnMoCiAgICB4ID0gIkdlbmRlciIsCiAgICB5ID0gIkZyZXF1ZW5jeSIsCiAgICB0aXRsZSA9ICJCYXItY2hhcnQgb2YgR2VuZGVyIiwKICAgIHN1YnR0aXRsZSA9ICIob2YgU3RhciBXYXJzIGNoYXJhY3RlcnMpIiwKICAgIGNhcHRpb24gPSAiKFNvdXJjZTogVGhlIGRwbHlyIHBhY2thZ2UpIikgKwogIHNjYWxlX2ZpbGxfdmlyaWRpc19kKAogICAgb3B0aW9uID0gInBsYXNtYSIKICAgICkKYGBgCgpgYGB7ciBjb2xmaWxsdjR9CmdncGxvdCgKICBkYXRhID0gbXkuZGF0YSwKICBtYXBwaW5nID0gYWVzKAogICAgeCA9IGdlbmRlcgogICAgKQogICkgKyAKICBnZW9tX2JhcigKICAgIGFlcyhmaWxsID0gZ2VuZGVyKQogICAgKSArIAogIGxhYnMoCiAgICB4ID0gIkdlbmRlciIsCiAgICB5ID0gIkZyZXF1ZW5jeSIsCiAgICB0aXRsZSA9ICJCYXItY2hhcnQgb2YgR2VuZGVyIiwKICAgIHN1YnR0aXRsZSA9ICIob2YgU3RhciBXYXJzIGNoYXJhY3RlcnMpIiwKICAgIGNhcHRpb24gPSAiKFNvdXJjZTogVGhlIGRwbHlyIHBhY2thZ2UpIikgKwogIHNjYWxlX2ZpbGxfdmlyaWRpc19kKAogICAgb3B0aW9uID0gImNpdmlkaXMiCiAgICApCmBgYAoKIyMgVGhlbWVzIHdpdGggYHtnZ3RoZW1lc31gCk9uZSBjYW4gYWxzbyBsZWFuIG9uIHZhcmlvdXMgcGxvdHRpbmcgdGhlbWVzIGFzIHNob3duIGJlbG93LiBUaGVzZSB0aGVtZXMgbWltaWMgdGhlIHN0eWxlIG9mIGdyYXBoaWNzIHBvcHVsYXJpemVkIGJ5IHNvbWUgZGF0YSB2aXN1YWxpemF0aW9uIGV4cGVydHMgKGZvciBlLmcuLCBTdGVwaGVuIEZldywgRWR3YXJkIFR1ZnRlKSwgbmV3cy1tZWRpYSBob3VzZXMgKEZpdmV0aGlydHllaWdodCwgVGhlIEVjb25vbWlzdCwgVGhlIFdhbGwgU3RyZWV0IEpvdXJuYWwpLCBzb21lIHNvZnR3YXJlIHBhY2thZ2VzIChFeGNlbCwgU3RhdGEsIEdvb2dsZSBkb2NzKSwgYW5kIGEgZmV3IG90aGVycy4gQmVsb3cgSSBzaG93IHlvdSBqdXN0IGEgaGFuZGZ1bC4gIAoKYGBge3IgZ2d0MX0KbGlicmFyeShnZ3RoZW1lcykKCmdncGxvdCgKICBkYXRhID0gc3RhcndhcnMsCiAgbWFwcGluZyA9IGFlcygKICAgIHggPSBleWVfY29sb3IKICAgICkKICApICsKICBnZW9tX2JhcigpICsKICB0aGVtZV90dWZ0ZSgpIApgYGAKCmBgYHtyIGdndDJ9CmdncGxvdCgKICBkYXRhID0gc3RhcndhcnMsCiAgbWFwcGluZyA9IGFlcygKICAgIHggPSBleWVfY29sb3IKICAgICkKICApICsKICBnZW9tX2JhcigpICsKICB0aGVtZV9lY29ub21pc3QoKSAKYGBgCgpgYGB7ciBnZ3QzfQpnZ3Bsb3QoCiAgZGF0YSA9IHN0YXJ3YXJzLAogIG1hcHBpbmcgPSBhZXMoCiAgICB4ID0gZXllX2NvbG9yCiAgICApCiAgKSArCiAgZ2VvbV9iYXIoKSArCiAgdGhlbWVfZml2ZXRoaXJ0eWVpZ2h0KCkgCmBgYAoKTGF0ZXIgb24geW91IHdpbGwgbGVhcm4gdGhlc2UgJiBvdGhlciB3YXlzIHRvIGJ1aWxkIGFkdmFuY2VkIHZpc3VhbGl6YXRpb25zLiBGb3Igbm93IHdlIGdldCB0byB3b3JrIG1vcmUgd2l0aCBgZ2dwbG90MmAuIAoKIyMgTW9yZSB3aXRoIGJhci1jaGFydHMKCkkgd2FudCB0byBzaG93IGEgZmV3IHRoaW5ncyB3aXRoIGJhci1jaGFydHMgbm93LiBGaXJzdCwgd2UgY2FuIHNwZWNpZnkgdGhpbmdzIGEgYml0IGRpZmZlcmVudGx5IHdpdGhvdXQgYWx0ZXJpbmcgdGhlIHJlc3VsdC4gRm9yIGV4YW1wbGUsIGNvbXBhcmUgdGhlIGZvbGxvd2luZyB0d28gcGllY2VzIG9mIGNvZGUuIAoKYGBge3IgYmFyMDF9CmdncGxvdCgKICBkYXRhID0gbW92aWVzLAogIG1hcHBpbmcgPSBhZXMoCiAgICB4ID0gbXBhYQogICAgKQogICkgKyAKICBnZW9tX2JhcigpCmBgYAoKYGBge3IgYmFyMDJ9CmdncGxvdCgpICsgCiAgZ2VvbV9iYXIoCiAgICBkYXRhID0gbW92aWVzLAogICAgbWFwcGluZyA9IGFlcyh4ID0gbXBhYSkKICAgICkKYGBgCgpOb3RpY2UgdGhhdCB3ZSBzd2l0Y2hlZCB0aGUgYGRhdGEgPWAgYW5kIHRoZSBgYWVzKClgIHBpZWNlcyBvZiB0aGUgY29kZSBidXQgdGhhdCBtYWRlIG5vIGRpZmZlcmVuY2U7IHRoaXMgaXMgaW1wb3J0YW50IHRvIGJlYXIgaW4gbWluZCBiZWNhdXNlIGl0IHdpbGwgY29tZSBpbiBoYW5keSBkb3duIHRoZSByb2FkIHdoZW4gd2UgbmVlZCB0byBidWlsZCBzb21lIGFkdmFuY2VkIHZpc3VhbGl6YXRpb25zLiAKClRoZSBwbG90IGlzIHN1Yi1vcHRpbWFsIHNpbmNlIE1QQUEgcmF0aW5ncyBhcmUgbWlzc2luZyBmb3IgYSBsb3Qgb2YgbW92aWVzIGFuZCBzaG91bGQgYmUgIGVsaW1pbmF0ZWQgZnJvbSB0aGUgcGxvdCB2aWEgYHN1YnNldChtcGEgIT0gIiIpYCAgb3IgYnkgcnVubmluZyBkcGx5cidzIGBmaWx0ZXIoKWAgIHRvIGNyZWF0ZSBhbm90aGVyIGRhdGEtc2V0LiBJIHdpbGwgbGVhbiBvbiBgZmlsdGVyKClgLiAKCmBgYHtyIGJhcjJ9Cm1vdmllcyAlPiUgCiAgZmlsdGVyKG1wYWEgIT0gIiIpIC0+IG1vdmllczIgCgpnZ3Bsb3QoKSArIAogIGdlb21fYmFyKAogICAgZGF0YSA9IG1vdmllczIsCiAgICBtYXBwaW5nID0gYWVzKHggPSBtcGFhKQogICAgKQpgYGAKClRoZSBvcmRlciBvZiB0aGUgYmFycyBoZXJlIGlzIGZvcnR1aXRvdXMgaW4gdGhhdCBpdCBnb2VzIGZyb20gdGhlIHNtYWxsZXN0IGZyZXF1ZW5jeSB0byB0aGUgaGlnaGVzdCBmcmVxdWVuY3ksIGRyYXdpbmcgdGhlIHJlYWRlcidzIGV5ZS4gSSBzYWlkIGZvcnR1aXRvdXMgYmVjYXVzZSBge2dncGxvdDJ9YCBkZWZhdWx0cyB0byBkcmF3aW5nIHRoZSBiYXJzIGluIGFuIGFzY2VuZGluZyBhbHBoYWJldGljL2FscGhhbnVtZXJpYyBvcmRlciBpZiB0aGUgdmFyaWFibGUgaXMgYSAqKmNoYXJhY3RlcioqLiBTZWUgYmVsb3cgZm9yIGFuIGV4YW1wbGUuIAoKYGBge3IgYmFyM30KZGYgPSB0aWJibGUoeCA9IGMocmVwKCJBIiwgMiksIHJlcCgiQiIsIDQpLCByZXAoIkMiLCAxKSkpCgpnZ3Bsb3QoKSArIAogIGdlb21fYmFyKAogICAgZGF0YSA9IGRmLCAKICAgIG1hcHBpbmcgPSBhZXMoeCA9IHgpCiAgKQpgYGAKCk5vdGljZSB0aGUgYmFycyBoZXJlIGRvIG5vdCBmb2xsb3cgaW4gYXNjZW5kaW5nL2Rlc2NlbmRpbmcgb3JkZXIgb2YgZnJlcXVlbmNpZXMuIExhdGVyIG9uIHdlJ2xsIGxlYXJuIGhvdyB0byBvcmRlciB0aGUgYmFycyB3aXRoIGFzY2VuZGluZy9kZXNjZW5kaW5nIGZyZXF1ZW5jaWVzIG9yIGJ5IHNvbWUgb3RoZXIgbG9naWMuIAoKV2hhdCBhYm91dCBwbG90dGluZyBgcmVsYXRpdmUgZnJlcXVlbmNpZXNgIG9uIHRoZSB5LWF4aXMgcmF0aGVyIHRoYW4gdGhlIGZyZXF1ZW5jaWVzPyAKCmBgYHtyIGJhcjR9CmxpYnJhcnkoc2NhbGVzKQoKZ2dwbG90KCkgKyAKICBnZW9tX2JhcigKICAgIGRhdGEgPSBtb3ZpZXMyLAogICAgbWFwcGluZyA9IGFlcygKICAgICAgeCA9IG1wYWEsCiAgICAgIHkgPSAoLi5jb3VudC4uKS9zdW0oLi5jb3VudC4uKQogICAgICApCiAgICApICsgCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHBlcmNlbnQpICsgCiAgbGFicygKICAgIHggPSAiTVBBQSBSYXRpbmciLAogICAgeSAgPSAiUmVsYXRpdmUgRnJlcXVlbmN5ICglKSIKICAgICkgCmBgYAoKTm90ZSB0aGUgYWRkaXRpb24gb2YgCgorIGB5ID0gKC4uY291bnQuLikvc3VtKC4uY291bnQuLilgIHRvIGNoYW5nZSB0aGUgeS1heGlzIHRvIHJlZmxlY3QgdGhlIHJlbGF0aXZlIGZyZXF1ZW5jeSBhcyBhIHByb3BvcnRpb24sIGFuZCAgCisgYHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBwZXJjZW50KWAgdG8gdGhlbiBtdWx0aXBseSB0aGVzZSBwcm9wb3J0aW9ucyBieSAxMDAgdG8gZ2V0IHBlcmNlbnRhZ2VzIGFzIHRoZSBsYWJlbHMgcmF0aGVyIHRoYW4gMC4yLCAwLjQsIDAuNiwgZXRjLiAKCiMjIERpc2FnZ3JlZ2F0aW5nIGJhci1jaGFydHMgZm9yIGdyb3VwcyAKTGV0IHVzIGJ1aWxkIGEgc2ltcGxlIGJhci1jaGFydCB3aXRoIHRoZSBgaHNiMmAgZGF0YSB3ZSBzYXcgaW4gTW9kdWxlIDAxLiBIZXJlIHdlIGZpcnN0IGRvd25sb2FkIGl0LCBsYWJlbCB0aGUgdmFsdWVzLCBzYXZlIGl0LCBhbmQgdGhlbiBzdGFydCBjaGFydGluZyBpdC4gIAoKYGBge3IgaHNiMi1kYXRhaW59CnJlYWQudGFibGUoCiAgJ2h0dHBzOi8vc3RhdHMuaWRyZS51Y2xhLmVkdS9zdGF0L2RhdGEvaHNiMi5jc3YnLAogIGhlYWRlciA9IFRSVUUsCiAgc2VwID0gIiwiCiAgKSAtPiBoc2IyCgpmYWN0b3IoaHNiMiRmZW1hbGUsCiAgICAgICBsZXZlbHMgPSBjKDAsIDEpLAogICAgICAgbGFiZWxzID0gYygiTWFsZSIsICJGZW1hbGUiKQogICAgICAgKSAtPiBoc2IyJGZlbWFsZSAKCmZhY3Rvcihoc2IyJHJhY2UsCiAgICAgICBsZXZlbHMgPSBjKDE6NCksCiAgICAgICBsYWJlbHMgPSBjKCJIaXNwYW5pYyIsICJBc2lhbiIsICJBZnJpY2FuIEFtZXJpY2FuIiwgIldoaXRlIikKICAgICAgICkgLT4gaHNiMiRyYWNlCgpmYWN0b3IoaHNiMiRzZXMsCiAgICAgICBsZXZlbHMgPSBjKDE6MyksCiAgICAgICBsYWJlbHMgPSBjKCJMb3ciLCAiTWlkZGxlIiwgIkhpZ2giKQogICAgICAgKSAtPiBoc2IyJHNlcwoKZmFjdG9yKGhzYjIkc2NodHlwLAogICAgICAgbGV2ZWxzID0gYygxOjIpLAogICAgICAgbGFiZWxzID0gYygiUHVibGljIiwgIlByaXZhdGUiKQogICAgICAgKSAtPiBoc2IyJHNjaHR5cAoKZmFjdG9yKGhzYjIkcHJvZywKICAgICAgIGxldmVscyA9IGMoMTozKSwKICAgICAgIGxhYmVscyA9IGMoIkdlbmVyYWwiLCAiQWNhZGVtaWMiLCAiVm9jYXRpb25hbCIpCiAgICAgICApIC0+IGhzYjIkcHJvZwoKc2F2ZSgKICBoc2IyLCBmaWxlID0gaGVyZTo6aGVyZSgiZGF0YSIsICJoc2IyLlJEYXRhIikKICApCmBgYAoKYGBge3IgYmFyNS1iYXNlfQpnZ3Bsb3QoKSArIAogIGdlb21fYmFyKAogICAgZGF0YSA9IGhzYjIsCiAgICBtYXBwaW5nID0gYWVzKHggPSBzZXMpKSArCiAgbGFicyh4ID0gIlNvY2lvZWNvbm9taWMgU3RhdHVzIikKYGBgCgpPa2F5LCBmYWlyIGVub3VnaC4gQnV0IHdoYXQgaWYgSSB3YW50ZWQgdG8gc2VlIGhvdyBzb2Npb2Vjb25vbWljIHN0YXR1cyB2YXJpZXMgYWNyb3NzIG1hbGUgYW5kIGZlbWFsZSBzdHVkZW50cz8gIAoKYGBge3IgYmFyNX0KZ2dwbG90KCkgKyAKICBnZW9tX2JhcigKICAgIGRhdGEgPSBoc2IyLAogICAgbWFwcGluZyA9IGFlcygKICAgICAgeCA9IHNlcywKICAgICAgZ3JvdXAgPSBmZW1hbGUsIAogICAgICBmaWxsID0gZmVtYWxlCiAgICAgICkKICAgICkgKwogIGxhYnMoCiAgICB4ID0gIlNvY2lvZWNvbm9taWMgU3RhdHVzIiwKICAgIHkgPSAiRnJlcXVlbmN5IgogICkKYGBgCgpUaGlzIGlzIG5vdCB2ZXJ5IHVzZWZ1bCBzaW5jZSB0aGUgdmlld2VyIGhhcyB0byBlc3RpbWF0ZSB0aGUgcmVsYXRpdmUgc2l6ZXMgb2YgdGhlIHR3byBjb2xvcnMgd2l0aGluIGFueSBnaXZlbiBiYXIuIFRoYXQgY2FuIGJlIGZpeGVkIHdpdGggYHBvc2l0aW9uID0gImRvZGdlImAsIGp1eHRhcG9zaW5nIHRoZSBiYXJzIGZvciB0aGUgZ3JvdXBzIGFzIGEgcmVzdWx0LCBhbmQgdGhlIGVuZCBwcm9kdWN0IGlzIG11Y2ggYmV0dGVyLiBCdXQgbm90ZTogYHBvc2l0aW9uID0gImRvZGdlImAgaGFzIHRvIGJlIHB1dCBvdXRzaWRlIHRoZSBgYWVzKClgIGJ1dCBzdGlsbCBpbnNpZGUgYGdlb21fYmFyKClgIHNvIGJlIGNhcmVmdWwuIAoKYGBge3IgYmFyNn0KZ2dwbG90KCkgKyAKICBnZW9tX2JhcigKICAgIGRhdGEgPSBoc2IyLAogICAgbWFwcGluZyA9IGFlcygKICAgICAgeCA9IHNlcywKICAgICAgZ3JvdXAgPSBmZW1hbGUsIAogICAgICBmaWxsID0gZmVtYWxlCiAgICAgICksCiAgICBwb3NpdGlvbiA9ICJkb2RnZSIKICAgICkgKwogIGxhYnMoCiAgICB4ID0gIlNvY2lvZWNvbm9taWMgU3RhdHVzIiwKICAgIHkgPSAiRnJlcXVlbmN5IgogICkKYGBgCgpXaGF0IGlmIHlvdSB3YW50ZWQgdG8gY2FsY3VsYXRlIHBlcmNlbnRhZ2VzIHdpdGhpbiBlYWNoIHNleD8gVGhhdCBpcywgd2hhdCBwZXJjZW50IG9mIG1hbGUgc3R1ZGVudHMgZmFsbCB3aXRoaW4gYSBwYXJ0aWN1bGFyIHNlcyBjYXRlZ29yeSwgYW5kIHRoZSBzYW1lIHRoaW5nIGZvciBmZW1hbGUgc3R1ZGVudHM/IAoKYGBge3IgYmFyN30KZ2dwbG90KCkgKyAKICBnZW9tX2JhcigKICAgIGRhdGEgPSBoc2IyLCAKICAgIGFlcygKICAgICAgeCA9IHNlcywgCiAgICAgIGdyb3VwID0gZmVtYWxlLAogICAgICBmaWxsID0gZmVtYWxlLCAKICAgICAgeSA9IC4ucHJvcC4uCiAgICAgICksCiAgICBwb3NpdGlvbiA9ICJkb2RnZSIpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50KSArIAogIGxhYnMoCiAgICB4ID0gIlNvY2lvZWNvbm9taWMgU3RhdHVzIiwKICAgIHkgPSAiUmVsYXRpdmUgRnJlcXVlbmN5ICglKSIKICAgICkKYGBgCgpXaGF0IGFib3V0IHdpdGhpbiBlYWNoIHNlcyBpbnN0ZWFkIG9mIHdpdGhpbiBnZW5kZXI/IFRoYXQgaXMsIHdoYXQgaWYgd2Ugd2FudGVkIHBlcmNlbnQgb2YgTG93IHNlcyB0aGF0IGlzIE1hbGUgdmVyc3VzIEZlbWFsZSwgYW5kIHNvIG9uPwoKYGBge3IgYmFyOH0KZ2dwbG90KCkgKyAKICBnZW9tX2JhcigKICAgIGRhdGEgPSBoc2IyLCAKICAgIGFlcygKICAgICAgeCA9IGZlbWFsZSwgCiAgICAgIGdyb3VwID0gc2VzLAogICAgICBmaWxsID0gc2VzLCAKICAgICAgeSA9IC4ucHJvcC4uCiAgICAgICksCiAgICBwb3NpdGlvbiA9ICJkb2RnZSIpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50KSArIAogIGxhYnMoCiAgICB4ID0gIlNvY2lvZWNvbm9taWMgU3RhdHVzIiwKICAgIHkgPSAiUmVsYXRpdmUgRnJlcXVlbmN5ICglKSIKICAgICkKYGBgCgpgYGB7ciBiYXI5fQpnZ3Bsb3QoKSArIAogIGdlb21fYmFyKAogICAgZGF0YSA9IGhzYjIsIAogICAgYWVzKAogICAgICB4ID0gZmVtYWxlLCAKICAgICAgZ3JvdXAgPSBzZXMsCiAgICAgIGZpbGwgPSBzZXMsIAogICAgICB5ID0gLi5wcm9wLi4KICAgICAgKSwKICAgIHBvc2l0aW9uID0gImRvZGdlIikgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnQpICsgCiAgbGFicygKICAgIHggPSAiU29jaW9lY29ub21pYyBTdGF0dXMiLAogICAgeSA9ICJSZWxhdGl2ZSBGcmVxdWVuY3kgKCUpIgogICAgKSAKYGBgCgpUaGVyZSBpcyBzb21lIG1vcmUgd2Ugd2lsbCBkbyB3aXRoIGJhci1jaGFydHMgYnV0IGZvciBub3cgbGV0IHVzIHNldCB0aGVtIGFzaWRlIGFuZCBpbnN0ZWFkIGxvb2sgYXQgYSBmZXcgb3RoZXIgY2hhcnRzIC0tIGhpc3RvZ3JhbXMsIGJveC1wbG90cywgYW5kIGxpbmUtY2hhcnRzLiAKCiMjIEhpc3RvZ3JhbXMgCklmIHlvdSd2ZSBmb3Jnb3R0ZW4gd2hhdCB0aGVzZSBhcmUsIHNlZSBbaGlzdG9ncmFtXShodHRwOi8vdGlubGl6emllLm9yZy9oaXN0b2dyYW1zLyksIG9yIHRoZW4gW1lhdSdzIHBpZWNlIGhlcmVdKGh0dHBzOi8vZmxvd2luZ2RhdGEuY29tLzIwMTQvMDIvMjcvaG93LXRvLXJlYWQtaGlzdG9ncmFtcy1hbmQtdXNlLXRoZW0taW4tci8pIGFuZCBbaGVyZV0oaHR0cHM6Ly9mbG93aW5nZGF0YS5jb20vMjAxNy8wNi8wNy9ob3ctaGlzdG9ncmFtcy13b3JrLykuIFtUaGVyZSBpcyBhIHNob3J0IHZpZGVvIGF2YWlsYWJsZSBhcyB3ZWxsXShodHRwczovL3ZpbWVvLmNvbS8yMjE2MDczNDEpLiAKCkZvciBoaXN0b2dyYW1zIGluIGdncGxvdDIsIGBnZW9tX2hpc3RvZ3JhbSgpYCBpcyB0aGUgZ2VvbWV0cnkgbmVlZGVkIGJ1dCBub3RlIHRoYXQgdGhlIGRlZmF1bHQgbnVtYmVyIG9mIGJpbnMgaXMgbm90IHZlcnkgdXNlZnVsIGFuZCBjYW4gYmUgdHdlYWtlZCwgYWxvbmcgd2l0aCBvdGhlciBlbWJlbGxpc2htZW50cyB0aGF0IGFyZSBwb3NzaWJsZSBhcyB3ZWxsLiAKCmBgYHtyIGdnMmF9CmdncGxvdCgpICsgCiAgZ2VvbV9oaXN0b2dyYW0oCiAgICBkYXRhID0gaHNiMiwKICAgIGFlcyh4ID0gcmVhZCksIAogICAgZmlsbCA9ICJjb3JuZmxvd2VyYmx1ZSIsCiAgICBjb2xvciA9ICJ3aGl0ZSIKICAgICkgKyAKICBsYWJzKAogICAgdGl0bGUgPSAiSGlzdG9ncmFtIG9mIFJlYWRpbmcgU2NvcmVzIiwKICAgIHggPSAiUmVhZGluZyBTY29yZSIsCiAgICB5ID0gIkZyZXF1ZW5jeSIKICAgICkKYGBgCgpOb3RlIHRoZSB3YXJuaW5nIGBzdGF0X2JpbigpYCB1c2luZyBgYmlucyA9IDMwYC4gUGljayBiZXR0ZXIgdmFsdWUgd2l0aCBgYmlud2lkdGhgLiBUaGlzIGlzIGJlY2F1c2UgbnVtZXJpY2FsIHZhcmlhYmxlcyBuZWVkIHRvIGJlIGdyb3VwZWQgaW4gb3JkZXIgdG8gaGF2ZSBtZWFuaW5nZnVsIGhpc3RvZ3JhbXMgd2UgY2FuIG1ha2Ugc2Vuc2Ugb2YuIEhvdyBkbyB5b3UgZGVmaW5lIHRoZSBiaW5zIChha2EgdGhlIGdyb3Vwcyk/IFdlIGNvdWxkIHNldCBgYmlucyA9IDVgIGFuZCB3ZSBjb3VsZCBhbHNvIGV4cGVyaW1lbnQgd2l0aCBgYmlud2lkdGggPWAuIExldCB1cyBkbyBgYmlucyA9IDVgIHdoaWNoIHdpbGwgc2F5IGdpdmUgdXMgNSBncm91cHMsIGFuZCBnbyBhaGVhZCBhbmQgY2FsY3VsYXRlIHRoZW0geW91cnNlbGYuIAoKYGBge3IgZ2cyYn0KZ2dwbG90KCkgKyAKICBnZW9tX2hpc3RvZ3JhbSgKICAgIGRhdGEgPSBoc2IyLAogICAgYWVzKHggPSByZWFkKSwgCiAgICBmaWxsID0gImNvcm5mbG93ZXJibHVlIiwKICAgIGNvbG9yID0gIndoaXRlIiwKICAgIGJpbnMgPSA1CiAgICApICsgCiAgbGFicygKICAgIHRpdGxlID0gIkhpc3RvZ3JhbSBvZiBSZWFkaW5nIFNjb3JlcyIsCiAgICBzdWJ0aXRsZSA9ICIod2l0aCBiaW5zID0gKSIsCiAgICB4ID0gIlJlYWRpbmcgU2NvcmUiLAogICAgeSA9ICJGcmVxdWVuY3kiCiAgICApCmBgYAoKSWYgd2Ugd2FudGVkIG1vcmUvZmV3ZXIgYmlucyB3ZSBjb3VsZCB0d2VhayBpdCB1cCBvciBkb3duIGFzIG5lZWRlZC4gCldoYXQgYWJvdXQgYmlud2lkdGg/IFRoaXMgd2lsbCBzcGVjaWZ5IGhvdyB3aWRlIGVhY2ggZ3JvdXAgbXVzdCBiZS4gCgpgYGB7ciBnZzJjfQpnZ3Bsb3QoKSArIAogIGdlb21faGlzdG9ncmFtKAogICAgZGF0YSA9IGhzYjIsCiAgICBhZXMoeCA9IHJlYWQpLCAKICAgIGZpbGwgPSAiY29ybmZsb3dlcmJsdWUiLAogICAgY29sb3IgPSAid2hpdGUiLAogICAgYmlud2lkdGggPSA1CiAgICApICsgCiAgbGFicygKICAgIHRpdGxlID0gIkhpc3RvZ3JhbSBvZiBSZWFkaW5nIFNjb3JlcyIsCiAgICBzdWJ0aXRsZSA9ICIod2l0aCBiaW53aWR0aCA9ICkiLAogICAgeCA9ICJSZWFkaW5nIFNjb3JlIiwKICAgIHkgPSAiRnJlcXVlbmN5IgogICAgKQpgYGAKCklmIHdlIHdhbnRlZCB0byBkaXNhZ2dyZWdhdGUgdGhlIGhpc3RvZ3JhbSBieSBvbmUgb3IgbW9yZSBjYXRlZ29yaWNhbCB2YXJpYWJsZXMsIHdlIGNvdWxkIGRvIHNvIHF1aXRlIGVhc2lseTogCgpgYGB7ciBnZzN9CmdncGxvdCgpICsgCiAgZ2VvbV9oaXN0b2dyYW0oCiAgICBkYXRhID0gaHNiMiwKICAgIGFlcyh4ID0gcmVhZCksIAogICAgZmlsbCA9ICJjb3JuZmxvd2VyYmx1ZSIsCiAgICBjb2xvciA9ICJ3aGl0ZSIsCiAgICBiaW5zID0gNQogICAgKSArIAogIGxhYnMoCiAgICB0aXRsZSA9ICJIaXN0b2dyYW0gb2YgUmVhZGluZyBTY29yZXMiLAogICAgc3VidGl0bGUgPSAiKGJyb2tlbiBvdXQgZm9yIE1hbGUgdnMuIEZlbWFsZSBzdHVkZW50cykiLAogICAgeCA9ICJSZWFkaW5nIFNjb3JlIiwKICAgIHkgPSAiRnJlcXVlbmN5IgogICAgKSArCiAgZmFjZXRfd3JhcCh+IGZlbWFsZSkKYGBgCgpXaGVuIHdlIGRvIHRoaXMsIGl0IGlzIG9mdGVuIHVzZWZ1bCB0byBvcmdhbml6ZSB0aGVtIHNvIHRoYXQgb25seSBvbmUgaGlzdG9ncmFtIHNob3dzIHVwIGluIGEgcm93LiBUaGlzIGlzIGRvbmUgd2l0aCB0aGUgYG5jb2wgPSAxYCBjb21tYW5kLiAKCmBgYHtyIGdnNGF9CmdncGxvdCgpICsgCiAgZ2VvbV9oaXN0b2dyYW0oCiAgICBkYXRhID0gaHNiMiwKICAgIGFlcyh4ID0gcmVhZCksIAogICAgZmlsbCA9ICJjb3JuZmxvd2VyYmx1ZSIsCiAgICBjb2xvciA9ICJ3aGl0ZSIsCiAgICBiaW5zID0gNQogICAgKSArIAogIGxhYnMoCiAgICB0aXRsZSA9ICJIaXN0b2dyYW0gb2YgUmVhZGluZyBTY29yZXMiLAogICAgc3VidGl0bGUgPSAiKGJyb2tlbiBvdXQgZm9yIE1hbGUgdnMuIEZlbWFsZSBzdHVkZW50cykiLAogICAgeCA9ICJSZWFkaW5nIFNjb3JlIiwKICAgIHkgPSAiRnJlcXVlbmN5IgogICAgKSArCiAgZmFjZXRfd3JhcCh+IGZlbWFsZSwgbmNvbCA9IDEpCmBgYAoKYGBge3IgZ2c0Yn0KZ2dwbG90KCkgKyAKICBnZW9tX2hpc3RvZ3JhbSgKICAgIGRhdGEgPSBoc2IyLAogICAgYWVzKHggPSByZWFkKSwgCiAgICBmaWxsID0gImNvcm5mbG93ZXJibHVlIiwKICAgIGNvbG9yID0gIndoaXRlIiwKICAgIGJpbnMgPSA1CiAgICApICsgCiAgbGFicygKICAgIHRpdGxlID0gIkhpc3RvZ3JhbSBvZiBSZWFkaW5nIFNjb3JlcyIsCiAgICBzdWJ0aXRsZSA9ICIoYnJva2VuIG91dCBieSBTb2Npb2Vjb25vbWljIFN0YXR1cykiLAogICAgeCA9ICJSZWFkaW5nIFNjb3JlIiwKICAgIHkgPSAiRnJlcXVlbmN5IgogICAgKSArCiAgZmFjZXRfd3JhcCh+IHNlcywgbmNvbCA9IDEpCmBgYAoKTm93IHRoZSBkaXN0cmlidXRpb25zIGFyZSBzdGFja2VkIGFib3ZlIGVhY2gsIGVhc2luZyBjb21wYXJpc29uczsgZG8gdGhleSBoYXZlIHRoZSBzYW1lIGF2ZXJhZ2U/IERvIHRoZXkgdmFyeSB0aGUgc2FtZT8gQXJlIHRoZXkgc2ltaWxhcmx5IHNrZXdlZC9zeW1tZXRyaWM/LiAKCkZvciBicmVha291dHMgd2l0aCB0d28gY2F0ZWdvcmljYWwgdmFyaWFibGVzIHdlIGNvdWxkIGRvIAoKYGBge3IgZ2c1YX0KZ2dwbG90KCkgKyAKICBnZW9tX2hpc3RvZ3JhbSgKICAgIGRhdGEgPSBoc2IyLAogICAgYWVzKHggPSByZWFkKSwgCiAgICBmaWxsID0gImNvcm5mbG93ZXJibHVlIiwKICAgIGNvbG9yID0gIndoaXRlIiwKICAgIGJpbnMgPSA1CiAgICApICsgCiAgbGFicygKICAgIHRpdGxlID0gIkhpc3RvZ3JhbSBvZiBSZWFkaW5nIFNjb3JlcyIsCiAgICBzdWJ0aXRsZSA9ICIoYnJva2VuIG91dCBieSBTb2Npb2Vjb25vbWljIFN0YXR1cyBhbmQgU2Nob29sIFR5cGUpIiwKICAgIHggPSAiUmVhZGluZyBTY29yZSIsCiAgICB5ID0gIkZyZXF1ZW5jeSIKICAgICkgKwogIGZhY2V0X3dyYXAoc2VzIH4gc2NodHlwLCBuY29sID0gMikKYGBgCgpOb3RlIHRoYXQgYHNlcyB+IHNjaHR5cGAgcmVuZGVycyB0aGUgcGFuZWxzIGZvciB0aGUgZmlyc3QgY2F0ZWdvcnkgb2YgYHNlc2AgYnkgYWxsIGNhdGVnb3JpZXMgb2Ygc2NodHlwIGFuZCB0aGVuIHJlcGVhdHMgZm9yIHRoZSBvdGhlciBjYXRlZ29yaWVzIGluIHJvd3MgMiBhbmQgMy4gSWYgd2UgZGlkIGBmYWNldF93cmFwKHNjaHR5cGUgfiBzZXMsIG5jb2wgPSAzKWAgd2Ugd291bGQgaGF2ZSBhIGRpZmZlcmVudCByZXN1bHQ6CgpgYGB7ciBnZzVifQpnZ3Bsb3QoKSArIAogIGdlb21faGlzdG9ncmFtKAogICAgZGF0YSA9IGhzYjIsCiAgICBhZXMoeCA9IHJlYWQpLCAKICAgIGZpbGwgPSAiY29ybmZsb3dlcmJsdWUiLAogICAgY29sb3IgPSAid2hpdGUiLAogICAgYmlucyA9IDUKICAgICkgKyAKICBsYWJzKAogICAgdGl0bGUgPSAiSGlzdG9ncmFtIG9mIFJlYWRpbmcgU2NvcmVzIiwKICAgIHN1YnRpdGxlID0gIihicm9rZW4gb3V0IGJ5IFNvY2lvZWNvbm9taWMgU3RhdHVzIGFuZCBTY2hvb2wgVHlwZSkiLAogICAgeCA9ICJSZWFkaW5nIFNjb3JlIiwKICAgIHkgPSAiRnJlcXVlbmN5IgogICAgKSArCiAgZmFjZXRfd3JhcChzY2h0eXAgfiBzZXMsIG5jb2wgPSAzKSArCiAgeWxpbShjKDAsIDIzKSkKYGBgCgpOb3RpY2UgdGhhdCBoZXJlIEkgYWxzbyBhZGQgYSBgeWxpbShjKC4uLikpYCBjb21tYW5kIHRvIHNldCB0aGUgbWluaW11bSBhbmQgbWF4aW11bSB2YWx1ZXMgb2YgdGhlIHktYXhpcy4gVGhpcyBpcyB1c2VmdWwsIGFuZCBJIHN1Z2dlc3QgeW91IGRvIG5vdCBmb3JnZXQgdG8gc2V0IHRoZSB5IGxpbWl0IHRvIHN0YXJ0IGF0IDAgb3IgdGhlbiBtYWtlIGEgbm90ZSBpbiB0aGUgcGxvdCBmb3IgcmVhZGVycyBzbyB0aGV5IGRvbid0IGFzc3VtZSBpdCBpcyBhdCAwIHdoZW4gaW4gZmFjdCBpdCBoYXMgYmVlbiB0cnVuY2F0ZWQgZm9yIGVhc2Ugb2YgZGF0YSBwcmVzZW50YXRpb24uIFRoaXMgbWlzc3RhdGVzIHRoZSBwYXR0ZXJuIGluIHRoZSBkYXRhLCBkbyBub3QgZG8gaXQgb3IgdGhlbiwgYWdhaW4sIGFubm90YXRlIHRoZSBwbG90IHRvIHRoYXQgZWZmZWN0IHNvIG5vYm9keSBpcyBtaXNsZWQuIEJhci1jaGFydHMgYW5kIGhpc3RvZ3JhbXMgd2lsbCBoYXZlIDAgYXMgdGhlIG1pbmltdW0geS1saW1pdCBidXQgdGhpcyBpcyBub3QgdHJ1ZSBmb3Igc29tZSBvdGhlciBwbG90cy4gCgoKIyMgQm94LXBsb3RzIApSZW1lbWJlciB0aGVzZSwgb3VyIGZyaWVuZHMgZnJvbSBNUEEgNjAxMD8gVGhlc2UgY2FuIGJlIHVzZWZ1bCBmb3Igc3R1ZHlpbmcgdGhlIGRpc3RyaWJ1dGlvbiBvZiBhIGNvbnRpbnVvdXMgdmFyaWFibGUuIFtTZWUgdGhpcyB2aWRlb10oaHR0cHM6Ly92aW1lby5jb20vMjIyMzU4MDM0KS4gTGV0IHVzIHNlZSB0aGVzZSBpbiBhY3Rpb24gd2l0aCB0aGUgYGNtaGZsaWdodHNgIGRhdGEuIAoKYGBge3IgYm94MWF9CmxvYWQoCiAgaGVyZTo6aGVyZSgiZGF0YSIsICJjbWhmbGlnaHRzXzAxMDkyMDE3LlJEYXRhIikKICApCgpnZ3Bsb3QoKSArIAogIGdlb21fYm94cGxvdCgKICAgIGRhdGEgPSBjbWhmbGlnaHRzLAogICAgbWFwcGluZyA9IGFlcygKICAgICAgeSA9IEFyckRlbGF5LAogICAgICB4ID0gIiIKICAgICAgKSwKICAgIGZpbGwgPSAiY29ybmZsb3dlcmJsdWUiCiAgICApIApgYGAKCk5vdGU6IAoKKyB0aGUgYHggPSAiImAgaXMgaW4gYGFlcygpYCBiZWNhdXNlIG90aGVyd2lzZSB3aXRoIGEgc2luZ2xlIGdyb3VwIHRoZSBib3gtcGxvdCB3aWxsIG5vdCBidWlsZCB1cCBuaWNlbHkKCkJ1dCwgSSBwcmVmZXIgdG8gc2VlIHRoZW0gcnVubmluZyBob3Jpem9udGFsbHksIHNvIGhvdyBjYW4gSSBkbyB0aGF0PyBXaXRoIGBjb29yZF9mbGlwKClgIHNpbmNlIHRoaXMganVzdCBmbGlwcyB0aGUgY29sdW1ucy4gCgpgYGB7ciBib3gxYn0KZ2dwbG90KCkgKyAKICBnZW9tX2JveHBsb3QoCiAgICBkYXRhID0gY21oZmxpZ2h0cywKICAgIG1hcHBpbmcgPSBhZXMoCiAgICAgIHkgPSBBcnJEZWxheSwKICAgICAgeCA9ICIiCiAgICAgICksCiAgICBmaWxsID0gImNvcm5mbG93ZXJibHVlIgogICAgKSArCiAgY29vcmRfZmxpcCgpCmBgYAoKQW5kIG5vdyBmb3IgYSBzbGlnaHRseSBkaWZmZXJlbnQgZGF0YS1zZXQsIG9uZSB0aGF0IG1lYXN1cmVzIG1hbGUgYWR1bHRzJyBoZW1vZ2xvYmluIGNvbmNlbnRyYXRpb24gZm9yIGEgZmV3IHBvcHVsYXRpb25zLiAKCmBgYHtyIGJveDJ9CnJlYWRfY3N2KAogICJodHRwOi8vd2hpdGxvY2tzY2hsdXRlci56b29sb2d5LnViYy5jYS93cC1jb250ZW50L2RhdGEvY2hhcHRlcjAyL2NoYXAwMmUzY0h1bWFuSGVtb2dsb2JpbkVsZXZhdGlvbi5jc3YiCiAgKSAtPiBoZW1vZ2xvYmluCgpnZ3Bsb3QoKSArCiAgZ2VvbV9ib3hwbG90KAogICAgZGF0YSA9IGhlbW9nbG9iaW4sCiAgICBtYXBwaW5nID0gYWVzKAogICAgICB4ID0gcG9wdWxhdGlvbiwKICAgICAgeSA9IGhlbW9nbG9iaW4sCiAgICAgIGZpbGwgPSBwb3B1bGF0aW9uCiAgICAgICkKICAgICkgKwogIGNvb3JkX2ZsaXAoKSArCiAgbGFicygKICAgIHggPSAiUG9wdWxhdGlvbiIsCiAgICB5ID0gIkhlbW9nbG9iaW4gQ29uY2VudHJhdGlvbiIsCiAgICB0aXRsZSA9ICJIZW1vZ2xvYmluIENvbmNlbnRyYXRpb24gaW4gQWR1bHQgTWFsZXMiLAogICAgc3VidGl0bGUgPSAiKEFuZGVzLCBFdGhpb3BpYSwgVGliZXQsIFVTQSkiCiAgICApICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCmBgYAoKTm90aWNlIHRoZSBuZWVkIGZvciBubyBsZWdlbmQgd2l0aCBgZmlsbCA9IHBvcHVsYXRpb25gIE5vdGljZSBhbHNvIGhvdyBgZmlsbCA9IGAgaXMgaW5zaWRlIGBhZXMoLi4uKWAgaGVyZSBiZWNhdXNlIHdlIGFyZSBhc2tpbmcgdGhhdCBlYWNoIHVuaXF1ZSB2YWx1ZSBzZWVuIGluIGEgdmFyaWFibGUgY2FsbGVkIGBwb3B1bGF0aW9uYCBiZSBtYXBwZWQgdG8gYSB1bmlxdWUgY29sb3IuIAoKQ291bGQgd2UgdXNlIG91ciBgZmFjZXRfd3JhcCguLi4pYCBoZXJlIHRvbz8gT2YgY291cnNlLiAKCmBgYHtyIGJveDFjfQpnZ3Bsb3QoKSArIAogIGdlb21fYm94cGxvdCgKICAgIGRhdGEgPSBjbWhmbGlnaHRzLAogICAgbWFwcGluZyA9IGFlcygKICAgICAgeSA9IEFyckRlbGF5LAogICAgICB4ID0gQ2FycmllcgogICAgICApLAogICAgZmlsbCA9ICJjb3JuZmxvd2VyYmx1ZSIKICAgICkgKwogIGNvb3JkX2ZsaXAoKSArCiAgZmFjZXRfd3JhcCh+IE1vbnRoKQpgYGAKCgojIyBMaW5lLWNoYXJ0cyAKSWYgd2UgaGF2ZSBkYXRhIG92ZXIgdGltZSBmb3Igb25lIG9yIG1vcmUgdW5pdHMsIHRoZW4gbGluZS1jaGFydHMgd29yayByZWFsbHkgd2VsbCB0byBleGhpYml0IHRyZW5kcy4gQSBjbGFzc2ljLCBjdXJyZW50IGV4YW1wbGUgd291bGQgYmUgdGhlIG51bWJlciBvZiBjb25maXJtZWQgQ09WSUQtMTkgY2FzZXMgcGVyIGNvdW50cnkgcGVyIGRhdGUuIEZvciBleGFtcGxlLCBzYXkgd2UgaGF2ZSBkYXRhIG9uIHRoZSB1bmVtcGxveW1lbnQgcmF0ZSBmb3IgdGhlIGNvdW50cnkuIFRoZXNlIGRhdGEgYXJlIGNvbWluZyBmcm9tIHRoZSBge3Bsb3RseX1gIGxpYnJhcnkgc28gd2UgaGF2ZSB0byBtYWtlIHN1cmUgaXQgaXMgaW5zdGFsbGVkIGFuZCBsb2FkIGl0LgoKYGBge3IgbGluZTF9CmxpYnJhcnkocGxvdGx5KQpkYXRhKGVjb25vbWljcykKbmFtZXMoZWNvbm9taWNzKQpnZ3Bsb3QoKSArCiAgZ2VvbV9saW5lKAogICAgZGF0YSA9IGVjb25vbWljcywgCiAgICBtYXBwaW5nID0gYWVzKAogICAgICB4ID0gZGF0ZSwKICAgICAgeSA9IHVlbXBtZWQKICAgICAgKQogICAgKSArIAogIGxhYnMoCiAgICB4ID0gIkRhdGUiLAogICAgeSA9ICJVbmVtcGxveW1lbnQgUmF0ZSIKICApCmBgYAoKVGhleSBjYW4gbG9vayB2ZXJ5IHBsYWluIGFuZCBhZXN0aGV0aWNhbGx5IHVuYXBwZWFsaW5nIHVubGVzcyB5b3UgZHJlc3MgdGhlbSB1cC4gU2VlIHRoZSBvbmUgYmVsb3cgYW5kIHRoZW4gdGhlIG9uZSB0aGF0IGZvbGxvd3MuIAoKYGBge3IgbGluZTJ9CmxvYWQoCiAgaGVyZTo6aGVyZSgiZGF0YSIsICJnYXAuZGYuUkRhdGEiKQogICkKCmdncGxvdCgpICsKICBnZW9tX2xpbmUoCiAgICBkYXRhID0gZ2FwLmRmLCAKICAgIG1hcHBpbmcgPSBhZXMoCiAgICAgIHggPSB5ZWFyLAogICAgICB5ID0gTGlmZUV4cCwKICAgICAgZ3JvdXAgPSBjb250aW5lbnQsCiAgICAgIGNvbG9yID0gY29udGluZW50CiAgICAgICkKICAgICkgKyAKICBnZW9tX3BvaW50KAogICAgZGF0YSA9IGdhcC5kZiwgCiAgICBtYXBwaW5nID0gYWVzKAogICAgICB4ID0geWVhciwKICAgICAgeSA9IExpZmVFeHAsCiAgICAgIGdyb3VwID0gY29udGluZW50LAogICAgICBjb2xvciA9IGNvbnRpbmVudAogICAgICApCiAgICApICsgCiAgbGFicygKICAgIHggPSAiWWVhciIsCiAgICB5ID0gIk1lZGlhbiBMaWZlIEV4cGVjdGFuY3kgKGluIHllYXJzKSIsCiAgICBjb2xvciA9ICIiCiAgKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKSAKYGBgCgojIyBTY2F0dGVyLXBsb3RzIApUaGVzZSB3b3JrIHdlbGwgaWYgd2UgaGF2ZSB0d28gb3IgbW9yZSBjb250aW51b3VzIHZhcmlhYmxlcywgYW5kIHdvcmsgd2VsbCB0byBoaWdobGlnaHQgdGhlIG5hdHVyZSBhbmQgc3RyZW5ndGggb2YgYSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgdHdvIHZhcmlhYmxlcyAuLi4uIHdoYXQgaGFwcGVucyB0byBgeWAgYXMgYHhgIGluY3JlYXNlcz8gcwoKYGBge3Igc2MxfQpnZ3Bsb3QoKSArIAogIGdlb21fcG9pbnQoCiAgICBkYXRhID0gaHNiMiwgCiAgICBtYXBwaW5nID0gYWVzKAogICAgICB4ID0gd3JpdGUsCiAgICAgIHkgPSBzY2llbmNlCiAgICAgICkKICAgICkgKwogIGxhYnMoCiAgICB4ID0gIldyaXRpbmcgU2NvcmVzIiwgCiAgICB5ID0gIlNjaWVuY2UgU2NvcmVzIgogICAgKSAKYGBgCgpXZSBjb3VsZCBoaWdobGlnaHQgdGhlIGRpZmZlcmVudCBgc2VzYCBncm91cHMsIHRvIHNlZSBpZiB0aGVyZSBpcyBhbnkgZGlmZmVyZW5jZSBpbiB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gd3JpdGluZyBzY29yZXMgYW5kIHNjaWVuY2Ugc2NvcmVzIGJ5IHRoZSBkaWZmZXJlbnQgc2VzIGxldmVscy4gCgpgYGB7ciBzYzJ9CmdncGxvdCgpICsKICBnZW9tX3BvaW50KAogICAgZGF0YSA9IGhzYjIsCiAgICBtYXBwaW5nID0gYWVzKAogICAgICB4ID0gd3JpdGUsCiAgICAgIHkgPSBzY2llbmNlLAogICAgICBjb2xvciA9IHNlcwogICAgICApCiAgICApICsgCiAgbGFicygKICAgIHggPSAiV3JpdGluZyBTY29yZXMiLCAKICAgIHkgPSAiU2NpZW5jZSBTY29yZXMiLAogICAgY29sb3IgPSAiIgogICAgKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKSAKYGBgCgpUaGlzIGlzIG5vdCB2ZXJ5IGhlbHBmdWwgc28gd2h5IG5vdCBicmVha291dCBzZXMgZm9yIGVhc2Ugb2YgaW50ZXJwcmV0YXRpb24/IAoKYGBge3Igc2MzfQpnZ3Bsb3QoKSArCiAgZ2VvbV9wb2ludCgKICAgIGRhdGEgPSBoc2IyLAogICAgbWFwcGluZyA9IGFlcygKICAgICAgeCA9IHdyaXRlLAogICAgICB5ID0gc2NpZW5jZQogICAgICApCiAgICApICsgCiAgbGFicygKICAgIHggPSAiV3JpdGluZyBTY29yZXMiLCAKICAgIHkgPSAiU2NpZW5jZSBTY29yZXMiCiAgICApICsgCiAgZmFjZXRfd3JhcCh+IHNlcykgCmBgYAoKQ291bGQgd2UgYWRkIGFub3RoZXIgbGF5ZXIsIHBlcmhhcHMgYGZlbWFsZWA/IAoKYGBge3Igc2M0fQpnZ3Bsb3QoKSArCiAgZ2VvbV9wb2ludCgKICAgIGRhdGEgPSBoc2IyLAogICAgbWFwcGluZyA9IGFlcygKICAgICAgeCA9IHdyaXRlLAogICAgICB5ID0gc2NpZW5jZQogICAgICApCiAgICApICsgCiAgbGFicygKICAgIHggPSAiV3JpdGluZyBTY29yZXMiLCAKICAgIHkgPSAiU2NpZW5jZSBTY29yZXMiCiAgICApICsgCiAgZmFjZXRfd3JhcChzZXMgfiBmZW1hbGUsIG5jb2wgPSAyKSAKYGBgCgpBbmQgZmluYWxseSwgYSBmZXcgc3VnZ2VzdGlvbiBhYm91dCBob3cgdG8gYnVpbGQgdXAgeW91ciB2aXN1YWxpemF0aW9uczogCgotIGByIGVtb2ppZm9udDo6ZW1vamkoJ3JlcGVhdCcpYCBzdGFydCB3aXRoIHBlbmNpbCBhbmQgcGFwZXIsIHNrZXRjaCBwcm90b3R5cGVzIG9mIGRlc2lyZWQgdmlzdWFsaXphdGlvbihzKQotIGByIGVtb2ppZm9udDo6ZW1vamkoJ3NtaWxlJylgIGdyYXBoaWNzIGFyZSByZWxhdGl2ZWx5IGVhc3kgdG8gZ2VuZXJhdGUgd2l0aCBiYXNlIFIgJiB3aXRoIGBnZ3Bsb3QyYCAKLSBgciBlbW9qaWZvbnQ6OmVtb2ppKCdjbGFwJylgIGNvbW1vbi1zZW5zZTogYG51bWJlcmAgJiBgdHlwZWAgb2YgdmFyaWFibGUocykgZ3VpZGUgcGxvdHRpbmcgCi0gYHIgZW1vamlmb250OjplbW9qaSgnc3BhcmtsZXInKWAgc3RheSBgY29sb3IgY29uc2Npb3VzYDogc2Vuc2libGUgY29sb3JzICYgc2Vuc2l0aXZlIHRvIGNvbG9yIGJsaW5kbmVzcwotIGByIGVtb2ppZm9udDo6ZW1vamkoJ2JlZ2lubmVyJylgIGV4cGVyaW1lbnQsIGV4cGVyaW1lbnQsIGV4cGVyaW1lbnQgdW50aWwgeW91IGFyZSBoYXBweSAKLSB1c2UgdGhlIGByIGVtb2ppZm9udDo6ZW1vamkoJ2ZyZWUnKWAgbGVhcm5pbmcgcmVzb3VyY2VzIGF2YWlsYWJsZSBvbmxpbmUgCi0gYHIgZW1vamlmb250OjplbW9qaSgnbGVkZ2VyJylgIGlmIHlvdSBsZWFybiBzb21ldGhpbmcgbmV3IGluIFIsIHdyaXRlIGl0IGRvd24gCgotLS0tLS0tLS0tCgojIFByYWN0aWNlIEV4ZXJjaXNlcyAKCiMjIE5vYmVsIFByaXplIFdpbm5lcnMgCkdlb3JnaW9zIEthcmFtYW5pcyBnYXRoZXJlZCBhbmQgc2hhcmVkIGRhdGEgb24gTm9iZWwgcHJpemUgd2lubmVycyBvdmVyIHRoZSB5ZWFycywgd2l0aCBhIGZhaXIgYW1vdW50IG9mIGRldGFpbCwgYW5kIHVzZWQgaW4gdGhlIGB0aWR5dHVlc2RheWAgc2VyaWVzIGEgd2hpbGUgYmFjay4gVGhlc2UgZGF0YSBhcmUgdG8gYmUgdXNlZCBmb3IgdGhlIHF1ZXN0aW9ucyB0aGF0IGZvbGxvdy4gCgpgYGB7ciBub2JlbC13aW5uZXJzfQpyZWFkcjo6cmVhZF9jc3YoImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9yZm9yZGF0YXNjaWVuY2UvdGlkeXR1ZXNkYXkvbWFzdGVyL2RhdGEvMjAxOS8yMDE5LTA1LTE0L25vYmVsX3dpbm5lcnMuY3N2IikgLT4gbm9iZWxfd2lubmVycyAKYGBgCgp8dmFyaWFibGUgICAgICAgICAgICAgfGNsYXNzICAgICB8ZGVzY3JpcHRpb24gfAp8Oi0tLXw6LS0tfDotLS0tLS0tLS0tLXwKfHByaXplX3llYXIgICAgICAgICAgIHxkb3VibGUgICAgfCBZZWFyIHRoYXQgTm9iZWwgUHJpemUgd2FzIGF3YXJkZWR8CnxjYXRlZ29yeSAgICAgICAgICAgICB8Y2hhcmFjdGVyIHwgRmllbGQgb2Ygc3R1ZHkvY2F0ZWdvcnl8Cnxwcml6ZSAgICAgICAgICAgICAgICB8Y2hhcmFjdGVyIHwgUHJpemUgTmFtZSB8Cnxtb3RpdmF0aW9uICAgICAgICAgICB8Y2hhcmFjdGVyIHwgTW90aXZhdGlvbiBvZiB0aGUgYXdhcmQgfAp8cHJpemVfc2hhcmUgICAgICAgICAgfGNoYXJhY3RlciB8IFNoYXJlIGVnIDEgb2YgMSwgMSBvZiAyLCAxIG9mIDQsIGV0YyB8CnxsYXVyZWF0ZV9pZCAgICAgICAgICB8ZG91YmxlICAgIHwgSUQgYXNzaWduZWQgdG8gZWFjaCB3aW5uZXIgfAp8bGF1cmVhdGVfdHlwZSAgICAgICAgfGNoYXJhY3RlciB8IEluZGl2aWR1YWwgb3Igb3JnYW5pemF0aW9uICB8CnxmdWxsX25hbWUgICAgICAgICAgICB8Y2hhcmFjdGVyIHwgbmFtZSBvZiB0aGUgd2lubmVyfAp8YmlydGhfZGF0ZSAgICAgICAgICAgfGRvdWJsZSAgICB8IGJpcnRoIGRhdGUgb2Ygd2lubmVyIHwKfGJpcnRoX2NpdHkgICAgICAgICAgIHxjaGFyYWN0ZXIgfCBiaXJ0aCBjaXR5L3N0YXRlIG9mIHdpbm5lciB8CnxiaXJ0aF9jb3VudHJ5ICAgICAgICB8Y2hhcmFjdGVyIHwgYmlydGggY291bnRyeSBvZiB3aW5uZXIgfAp8Z2VuZGVyICAgICAgICAgICAgICAgfGNoYXJhY3RlciB8IGJpbmFyeSBnZW5kZXIgb2YgdGhlIHdpbm5lciB8Cnxvcmdhbml6YXRpb25fbmFtZSAgICB8Y2hhcmFjdGVyIHwgb3JnYW5pemF0aW9uIG5hbWUgfAp8b3JnYW5pemF0aW9uX2NpdHkgICAgfGNoYXJhY3RlciB8IG9yZ2FuaXphdGlvbiBjaXR5IHwKfG9yZ2FuaXphdGlvbl9jb3VudHJ5IHxjaGFyYWN0ZXIgfCBvcmdhbml6YXRpb24gY291bnRyeSB8CnxkZWF0aF9kYXRlICAgICAgICAgICB8ZG91YmxlICAgIHwgZGVhdGggZGF0ZSBvZiB0aGUgd2lubmVyIChpZiBkZWFkKSB8CnxkZWF0aF9jaXR5ICAgICAgICAgICB8Y2hhcmFjdGVyIHwgZGVhdGggY2l0eSAoaWYgZGVhZCkgfAp8ZGVhdGhfY291bnRyeSAgICAgICAgfGNoYXJhY3RlciB8IGRlYXRoIGNvdW50cnkgKGlmIGRlYWQpIHwKCgooYSkgRmlyc3QgY3JlYXRlIGBub2JlbC5kZmAgdGhhdCBrZWVwcyBvbmx5IHJlY29yZHMgc3RhcnRpbmcgaW4gdGhlIHllYXIgMTk2MCwgYW5kIG9ubHkgZm9yIHRoZSAiUGh5c2ljcyIgY2F0ZWdvcnkuIE5vdyBnZW5lcmF0ZSBhbiBhcHByb3ByaWF0ZSBjaGFydCB0aGF0IHNob3dzIHRoZSBkaXN0cmlidXRpb24gb2Ygd2lubmVycyBieSBgYmlydGhfY291bnRyeWAgCgooYikgTm93IGJyZWFrIHRoaXMgZGlzdHJpYnV0aW9uIG91dCBieSBgZ2VuZGVyYCB0byBzZWUgaG93IHdpbm5lcnMgYnkgY291bnRyeSBkaWZmZXJzIGFjcm9zcyBnZW5kZXIgCgooYykgTm93IGdvIGJhY2sgdG8gYG5vYmxlX3dpbm5lcnNgLCB0aGUgZnVsbCBkYXRhLXNldCwgYW5kIGNyZWF0ZSBhIHNpbXBsZSBwbG90IHRoYXQgc2hvd3MgdGhlIGRpc3RyaWJ1dGlvbiBvZiBwcml6ZSB3aW5uZXJzIGJ5IGBkZWF0aF9jb3VudHJ5YCwgYGdlbmRlcmAsIGFuZCBgY2F0ZWdvcnlgICAKCgojIyBXYXRlciBsZXZlbHMgaW4gdGhlIEdyZWF0IExha2VzCgpEb3dubG9hZCB0aGUgbW9udGhseSBHcmVhdCBMYWtlcyB3YXRlciBsZXZlbCBkYXRhLXNldCBbU1BTUyBmb3JtYXQgZnJvbSBoZXJlXShodHRwczovL2FuaXJ1aGlsLmdpdGh1Yi5pby9hdnNyL3RlYWNoaW5nL2RhdGF2aXovZ3JlYXRsYWtlcy5zYXYpIGFuZCBbRXhjZWwgZm9ybWF0IGZyb20gaGVyZV0oaHR0cHM6Ly9hbmlydWhpbC5naXRodWIuaW8vYXZzci90ZWFjaGluZy9kYXRhdml6L2dyZWF0bGFrZXMueGxzeCkuICpOb3RlIHRoYXQgd2F0ZXIgbGV2ZWwgaXMgaW4gbWV0ZXJzLiogCgpZb3UgbWF5IHVzZSB0aGUgZm9sbG93aW5nIGNvbW1hbmQgdG8gcmVhZCBpbiB0aGUgZXhjZWwgZmlsZTogCgpgYGB7ciwgZXZhbD1GQUxTRX0KbGlicmFyeShyZWFkeGwpCnVybCA8LSAiaHR0cHM6Ly9hbmlydWhpbC5naXRodWIuaW8vYXZzci90ZWFjaGluZy9kYXRhdml6L2dyZWF0bGFrZXMueGxzeCIKZGVzdGZpbGUgPC0gImdyZWF0bGFrZXMueGxzeCIKY3VybDo6Y3VybF9kb3dubG9hZCh1cmwsIGRlc3RmaWxlKQpyZWFkX2V4Y2VsKGRlc3RmaWxlLCBjb2xfdHlwZXMgPSBjKCJkYXRlIiwgCiAgICAgIm51bWVyaWMiLCAibnVtZXJpYyIsICJudW1lcmljIiwgIm51bWVyaWMiLCAKICAgICAibnVtZXJpYyIpKSAtPiBncmVhdGxha2VzIApgYGAKCk5vdyB1c2UgYW4gYXBwcm9wcmlhdGUgY2hhcnQgdG8gc2hvdyB0aGUgd2F0ZXIgbGV2ZWwgZm9yIExha2UgU3VwZXJpb3IuIAoKIyMgQ291bnR5IEhlYWx0aCBSYW5raW5ncwpEb3dubG9hZCB0aGUgMjAxNyBDb3VudHkgSGVhbHRoIFJhbmtpbmdzIGRhdGEgW1NQU1MgZm9ybWF0IGZyb20gaGVyZV0oaHR0cHM6Ly9hbmlydWhpbC5naXRodWIuaW8vYXZzci90ZWFjaGluZy9kYXRhdml6L0NvdW50eUhlYWx0aFJhbmtpbmdzMjAxNy5zYXYpLCBbRXhjZWwgZm9ybWF0IGZyb20gaGVyZV0oaHR0cHM6Ly9hbmlydWhpbC5naXRodWIuaW8vYXZzci90ZWFjaGluZy9kYXRhdml6L0NvdW50eUhlYWx0aFJhbmtpbmdzMjAxNy54bHN4KSBhbmQgdGhlIFthY2NvbXBhbnlpbmcgY29kZWJvb2tdKGh0dHA6Ly93d3cuY291bnR5aGVhbHRocmFua2luZ3Mub3JnL3NpdGVzL2RlZmF1bHQvZmlsZXMvMjAxN1RyZW5kc0RvY3VtZW50YXRpb24ucGRmKS4gCgpUaGVzZSBkYXRhIGNhbiBiZSBkb3dubG9hZGVkIHdpdGggdGhlIGNvZGUgcHJvdmlkZWQgYmVsb3c6IAoKYGBge3IgZ3JlYXQtbGFrZXN9CmxpYnJhcnkocmVhZHhsKQp1cmwgPC0gImh0dHBzOi8vYW5pcnVoaWwuZ2l0aHViLmlvL2F2c3IvdGVhY2hpbmcvZGF0YXZpei9Db3VudHlIZWFsdGhSYW5raW5nczIwMTcueGxzeCIKZGVzdGZpbGUgPC0gIkNvdW50eUhlYWx0aFJhbmtpbmdzMjAxNy54bHN4IgpjdXJsOjpjdXJsX2Rvd25sb2FkKHVybCwgZGVzdGZpbGUpCnJlYWRfZXhjZWwoZGVzdGZpbGUpIC0+IGNoci5kZiAKYGBgCgpDb25zdHJ1Y3QgYXBwcm9wcmlhdGUgcGxvdHMgdGhhdCBzaG93cyB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIGZvbGxvd2luZyBwYWlycyBvZiB2YXJpYWJsZXMgCgooYSkgQWR1bHQgb2Jlc2l0eSBhbmQgSGlnaCBzY2hvb2wgZ3JhZHVhdGlvbiAKCihiKSBDaGlsZHJlbiBpbiBwb3ZlcnR5IGFuZCBIaWdoIHNjaG9vbCBncmFkdWF0aW9uIAoKKGMpIFByZXZlbnRhYmxlIGhvc3BpdGFsIHN0YXlzIGFuZCBVbmVtcGxveW1lbnQgcmF0ZSAKCgojIyBVbmVtcGxveW1lbnQgUmF0ZXMKVXNlIHRoZSB1bmVtcGxveW1lbnQgZGF0YSBnaXZlbiB0byB5b3UgYCh1bmVtcHJhdGUuUkRhdGEpYCBhbmQgY29uc3RydWN0IGFwcHJvcHJpYXRlIHBsb3RzIHRoYXQgc2hvdyB0aGUgZGlzdHJpYnV0aW9uIG9mIHVuZW1wbG95bWVudCByYXRlcyBhY3Jvc3MgeWVhcnMgZm9yIGVhY2ggb2YgdGhlIGZvdXIgZWR1Y2F0aW9uYWwgYXR0YWlubWVudCBncm91cHMuIAoKYGBge3J9CmxvYWQoCiAgaGVyZTo6aGVyZSgiZGF0YSIsICJ1bmVtcHJhdGUuUkRhdGEiKQogICkgLT4gdXJhdGUgCmBgYAoKQmUgc3VyZSB0byB1c2UgYSB1bmlxdWUgY29sb3IgZm9yIGVhY2ggZWR1Y2F0aW9uYWwgYXR0YWlubWVudCBncm91cAoK