Visualization and Comparison
A visualization of a single value without some comparative context is rarely useful
Useful visualizations almost always involve comparisons.
position of a value on an axis
relative position of two values
relative magnitudes of two values
A simple and common setting: Visualizing a measurement for each of a set of categories.
Some of the more common visualizations:
Some less frequently used visualizations:
Waterfall Charts
Polar Area Charts (Coxcomb Charts)
Dumbbell Charts
Some questions to keep in mind:
Dot Plots
Basics
One of the simplest visualizations of a single numerical variable with a modest number of observations and lables for the observations is a dot plot , or Cleveland dot plot :
library(dplyr)
library(ggplot2)
library(gapminder)
le_am_2007 <- filter(gapminder,
year == 2007,
continent == "Americas")
thm <- theme_minimal() +
theme(text = element_text(size = 16))
ggplot(le_am_2007,
aes(y = country, x = lifeExp)) +
geom_point(color = "deepskyblue3",
size = 2) +
labs(x = "Life Expectancy (years)",
y = NULL) +
thm
This visualization
shows the overall distribution of the data, and
makes it easy to locate the life expectancy of a particular country.
Unless there is a natural order to the categories (e.g. months of the year or days of the week) it is usually better to reorder to make the plot increasing or decreasing:
ggplot(le_am_2007,
aes(y = reorder(country, lifeExp),
x = lifeExp)) +
geom_point(color = "deepskyblue3",
size = 2) +
labs(x = "Life Expectancy (years)",
y = NULL) +
thm
Locating a particular country is a little more difficult.
But the shape of the distribution is more apparent.
Approximate median and quartiles can be read off easily.
Dot plots are particularly appropriate for interval data.
Dot plots are often very useful for group summaries like totals or averages.
For the barley
data, total yield within each site, adding up across all varieties and both years, can be computed as
b_tot_site <-
group_by(barley, site) %>%
summarize(yield = sum(yield))
The totals can then be visualized in a dot plot:
ggplot(b_tot_site, aes(x = yield, y = site)) +
geom_point(color = "deepskyblue3", size = 2.5) +
labs(x = "Total Yield (bushels/acre)", y = NULL) +
thm
Larger Data Sets
For larger data sets, like the citytemps
data with 140 observations, over-plotting of labels becomes a problem:
ggplot(citytemps,
aes(x = temp, y = reorder(city, temp))) +
geom_point(color = "deepskyblue3", size = 0.5) +
labs(x = "Temperature (degrees F)", y = NULL) +
thm
Reducing to 30 or 40, e.g. by taking a sample or a meaningful subset, can help:
ct1 <- filter(citytemps, temp < 32) %>% sample_n(10)
ct2 <- filter(citytemps, temp >= 32) %>% sample_n(20)
ctsamp <- bind_rows(ct1, ct2)
ggplot(ctsamp,
aes(x = temp, y = reorder(city, temp))) +
geom_point(color = "deepskyblue3", size = 2) +
labs(x = "Temperature (degrees F)", y = NULL) +
thm
Some Variations
The size of the dots can be used to encode an additional numeric variable.
This view uses area to encode population size:
ggplot(le_am_2007, aes(y = reorder(country, lifeExp),
x = lifeExp,
size = pop / 1000000)) +
geom_point(col = "deepskyblue3") +
labs(x = "Life Expectancy (years)", y = NULL) +
scale_size_area("Population\n(Millions)",
max_size = 8) +
thm + theme(legend.position = "top")
This is sometimes called a bubble chart .
Repeated measures, such as values for 2002 and 2007, can be shown and distinguished by color, shape, or both.
Using color:
## filter down to data for 2002 and 2007
## for the Americas
le2 <- filter(gapminder,
year >= 2002,
continent == "Americas")
## make a factor Year to get a discrete color
## palette, not a continuous one
le2 <- mutate(le2, Year = factor(year))
ggplot(le2, aes(y = reorder(country, lifeExp),
x = lifeExp,
color = Year)) +
geom_point() +
labs(x = "Life Expectancy (years)", y = NULL) +
thm + theme(legend.position = "top")
Using shape for the barley
data:
b_tot <-
group_by(barley, site, year) %>%
summarize(yield = sum(yield), .groups = "drop")
ggplot(b_tot, aes(x = yield, y = site, shape = year)) +
geom_point(color = "deepskyblue3", size = 3) +
labs(x = "Total Yield (bushels/acre)", y = NULL) +
thm + theme(legend.position = "top")
For repeated two values per class it can help to connect the two dots.
This visually emphasizes the relative sizes of differences.
The result is sometimes called a dumbbell chart .
For the barley yields data:
ggplot(b_tot, aes(x = yield, y = site)) +
geom_line(aes(group = site),
linewidth = 2,
color = "grey") +
geom_point(aes(color = year), size = 4) +
labs(x = "Total Yield (bushels/acre)", y = NULL) +
thm + theme(legend.position = "top")
For the Gapminder life expectancy data:
ggplot(le2, aes(y = reorder(country, lifeExp),
x = lifeExp,
color = Year)) +
geom_line(aes(group = country),
linewidth = 1.5,
color = "grey") +
geom_point(size = 2.5) +
labs(x = "Life Expectancy (years)", y = NULL) +
thm + theme(legend.position = "top")
Variations in Appearance
The dot plots introduced by W. S. Cleveland in his 1993 book Visualizing Data use only horizontal grid lines.
This also corresponds to the dot plots provided by base and lattice graphics and to the dot plot obtained using the Wall Street Journal theme from the ggthemes
package:
ggplot(b_tot_site, aes(x = yield, y = site)) +
geom_point(size = 2) +
labs(x = "Total Yield (bushels/acre)", y = NULL) +
ggthemes::theme_wsj()
A theme to closely match the style used by Cleveland can be defined as
theme_dotplotx <- function() {
theme(
## remove the vertical grid lines
panel.grid.major.x = element_blank(),
panel.grid.minor.x = element_blank(),
## explicitly set the horizontal lines
## (or they will disappear too)
panel.grid.major.y =
element_line(color = "black",
linetype = 3),
axis.text.y = element_text(size = rel(1.2)),
## use a white backgrounsd
panel.background =
element_rect(fill = "white",
color = NA),
panel.border =
element_rect(fill = NA,
color = "grey20"),
## increase text size
text = element_text(size = 16))
}
This produces
ggplot(b_tot_site, aes(x = yield, y = site)) +
geom_point(size = 2) +
labs(x = "Total Yield (bushels/acre)",
y = NULL) +
theme_dotplotx()
Bar Charts
Basics
A basic bar chart:
p <- ggplot(le_am_2007) +
geom_col(aes(y = lifeExp,
x = reorder(country, lifeExp)),
fill = "deepskyblue3") +
labs(y = "Life Expectancy (years)",
x = NULL) +
scale_y_continuous(
expand = expansion(mult = c(0, .1))) +
thm
p
The labels are a mess.
One option is to write labels at an angle, but this makes them hard to read.
Flipping the plot is usually a better option.
To make labels readable we can flip the plot:
## Redoing the plot plot with `x` and `y` aesthetics reversed did not
## work in the past but does work in current ggplot2 versions.
## But as we already have the previous plot we can just use coord_flip(),
p + coord_flip()
Some Notes
Bar charts seem to be used much more than dot plots in the popular media, but they are less widely applicable.
Research on visual perception has shown that viewers of bar charts subconsciously, or pre-attentively , focus on relative lengths of bars.
This means that for a bar chart to be appropriate and work well:
This in turn implies that bar charts should always have a zero base line.
You may need to intervene with your software’s defaults to make this happen.
Creating a bar chart with a non-zero base line is possible in ggplot
but not easy:
baseline <- 60
ticks <- c(0, 10, 20, 30)
ggplot(le_am_2007,
aes(x = lifeExp - baseline,
y = reorder(country, lifeExp))) +
geom_col(fill = "deepskyblue3") +
labs(x = "Life Expectancy (years)",
y = NULL) +
scale_x_continuous(
breaks = ticks,
labels = ticks + baseline,
expand = expansion(mult = c(0, .1))) +
thm + labs(title = "A Bad Bar Chart")
Bar charts always push the viewer to ratio comparisons, whether they are meaningful or not.
Using a non-zero baseline can therefore mislead the viewer .
Some news organizations seem particularly prone to taking advantage of/falling prey to this issue.
A recent blog post discusses a court case in New Zealand about a misleading bar chart with a non-zero baseline.
Another recent blog post may be helpful.
Data With Both Positive and Negative Values
Bar charts can be used for data containing both positive and negative values:
ctsampC <- mutate(ctsamp, temp = round((temp - 32) / 1.8))
p1 <- ggplot(ctsampC, aes(y = city, x = temp)) +
geom_point(color = "deepskyblue3") +
geom_vline(xintercept = 0, lty = 2) +
labs(x = "Temperature (degrees C)", y = NULL) +
thm
p2 <- ggplot(ctsampC, aes(x = temp, y = city)) +
geom_col(fill = "deepskyblue3") +
labs(x = "Temperature (degrees C)", y = NULL) +
thm
library(patchwork)
p1 + p2
This puts a strong emphasis on the base line
This can be useful if the baseline is meaningful, such as
Zero degrees Fahrenheit is not meaningful:
p1 <- ggplot(ctsamp, aes(y = city, x = temp)) +
geom_point(color = "deepskyblue3") +
geom_vline(xintercept = 0, lty = 2) +
labs(x = "Temperature (degrees F)", y = NULL) +
thm
p2 <- ggplot(ctsamp, aes(x = temp, y = city)) +
geom_col(fill = "deepskyblue3") +
labs(x = "Temperature (degrees F)", y = NULL) +
thm
p1 + p2
Grouped Bar Charts
A grouped bar chart can be used to show two measurements, e.g. two times.
ggplot(le2) +
geom_col(aes(x = lifeExp,
y = reorder(country, lifeExp),
fill = Year),
position = "dodge") +
labs(x = "Life Expectancy (years)",
y = NULL) +
scale_x_continuous(
expand = expansion(mult = c(0, .1))) +
thm
This visualization would be more effective for
In this case the dot plot is a much better choice.
For the barley
data looking at total yields for each of the sites and the two years:
ggplot(b_tot) +
geom_col(aes(x = yield, y = site, fill = year),
position = "dodge") +
labs(x = "Total Yield (bushels/acre)",
y = NULL) +
scale_x_continuous(
expand = expansion(mult = c(0, .1))) +
thm
Stacked Bar Charts
A stacked bar chart is appropriate when adding the values within a category to form a total makes sense.
For the barley
data:
ggplot(b_tot) +
geom_col(aes(x = yield, y = site, fill = year),
position = "stack") +
labs(x = "Total Yield (bushels/acre)",
y = NULL) +
scale_x_continuous(
expand = expansion(mult = c(0, .1))) +
thm
The combined bars show the totals.
The bar segments show the contribution of each year within the sites.
Comparing 1931 yields across sites is easy; comparing 1932 values is harder.
A stacked bar chart would make no sense for the two-year life expectancy data.
Category Order
Ordering of categories can change the visual effectiveness of bar charts.
Supermarket Sales
A small data set on multi-national supermarket chain sales:
chains <- read.csv(textConnection("Chain, Total, Foreign
Walmart, 22, 5
Costco, 4.5, 2
Tesco, 3, 0.5
Carrefour, 2.5, 2"))
chains <- mutate(chains, Home = Total - Foreign)
tbl <- select(chains, Chain, Home, Foreign, Total)
kbl <- knitr::kable(tbl, format = "html")
kableExtra::kable_styling(kbl, full_width = FALSE)
Chain
Home
Foreign
Total
Walmart
17.0
5.0
22.0
Costco
2.5
2.0
4.5
Tesco
2.5
0.5
3.0
Carrefour
0.5
2.0
2.5
The default alphabetical ordering of the chains in a bar chart is not ideal:
library(tidyr)
chains <- mutate(chains, Total = NULL)
lchains <- pivot_longer(chains,
-Chain,
names_to = "Type",
values_to = "Sales")
p <- ggplot(lchains,
aes(x = Sales, y = Chain, fill = Type)) +
geom_col() +
ylab(NULL) +
scale_x_continuous(
expand = expansion(mult = c(0, .1))) +
scale_fill_brewer(
palette = "Paired",
guide = guide_legend(title = NULL,
reverse = TRUE)) +
thm + theme(legend.position = "top")
p
Reordering by total sales produces a better result:
lchain_s <-
mutate(lchains,
Chain = reorder(Chain, Sales, FUN = sum))
p %+% lchain_s
With this ordering, comparing the first category of sales, Home
, among chains is easier than comparing the Foreign
sales as the Home
values have a common baseline.
If the goal of the visualization is to emphasize the foreign sales then reversing the order would be better.
lchain_st <-
mutate(lchain_s,
Type = factor(Type,
levels = c("Home", "Foreign")))
p %+% lchain_st +
scale_fill_brewer(palette = "Paired",
guide = guide_legend(title = NULL,
reverse = TRUE),
direction = -1)
This also makes it easy to see that Walmart’s international sales alone exceed the total sales of each of the other chains.
A filled bar chart can be used to help compare the proportions of total sales from foreign stores.
levs <-
levels(with(chains,
reorder(Chain, Foreign / (Foreign + Home))))
mutate(lchain_st, Chain = factor(Chain, levs)) %>%
ggplot(aes(x = Sales, y = Chain, fill = Type)) +
geom_col(position = "fill") +
labs(x = "Proportion of Sales", y = NULL) +
scale_x_continuous(
expand = expansion(mult = c(0, .1))) +
scale_fill_brewer(palette = "Paired",
guide = guide_legend(title = NULL,
reverse = TRUE),
direction = -1) +
thm + theme(legend.position = "top")
2016 Election Results
Another example for filled bar charts is provided by 2016 presidential election results by state.
This is produced by default settings.
The values for Clinton are easy to compare, as they are on a common baseline.
The values for Other are also on a common baseline, but the numbers for Trump are not.
p <- ggplot(geofacet::election,
aes(x = votes,
y = state,
fill = candidate)) +
geom_col(position = "fill") +
scale_x_continuous(expand = c(0, 0)) +
xlab(NULL) +
geom_vline(xintercept = 0.5, linetype = 2)
p
Reordering the categories puts both Clinton and Trump on common baselines and also matches the common color use:
## move 'Other' to middle, align Clinton/Trump with colors
elect <-
mutate(geofacet::election,
candidate = factor(candidate,
c("Trump", "Other", "Clinton")))
p %+% elect
Different orderings of the states can be used to achieve different goals.
Ordering by Clinton’s percentage makes it easier to see where she had an outright majority.
elect_wide <- pivot_wider(select(elect, -votes),
names_from = candidate,
values_from = pct)
## ordered by Clinton pct
slevs <- arrange(elect_wide, Clinton) %>%
pull(state)
p %+% mutate(elect, state = factor(state, slevs))
Another possibility is to order by winning margin between the two major candidates.
## ordered by winning margin
slevs <- arrange(elect_wide, Clinton - Trump) %>%
pull(state)
p %+% mutate(elect, state = factor(state, slevs))
Faceting
Faceting can be used with dot plots and bar charts as well:
ggplot(barley) +
geom_point(aes(x = yield,
y = variety,
color = year)) +
facet_wrap(~ site) +
theme(legend.position = "top")
These plots show lower yields for 1932 than for 1931 for all sites except Morris.
Heat Maps
Heat maps encode a numeric variable as the color of a tile placed at a particular position in a grid.
Heat maps are also called matrix charts or image plots .
Heat maps can be effective in cases where a line plot contains too much over-potting, such as
gma <- filter(gapminder, continent == "Americas")
ggplot(gma) +
geom_line(aes(x = year,
y = lifeExp,
color = country)) +
theme(legend.position = "top",
legend.title = element_blank())
A heat map of these data:
ggplot(gma) +
geom_tile(aes(x = year,
y = reorder(country, lifeExp),
fill = lifeExp)) +
scale_x_continuous(expand = c(0, 0)) +
scale_fill_viridis_c() +
labs(y = NULL,
fill = "Life Expectancy (years)") +
theme(legend.position = "top")
Again it is useful to consider reordering of categories when there is no natural order.
This heat map orders the countries by average life expectancy.
Bubble Charts
A form of chart often seen in the popular press is the bubble chart .
The bubble chart uses ares of circles to represent magnitudes.
Position in the plane is usually not fully used or not used at all for mapping attributes.
In on-line publications further information on each of the bubbles is often provided through interactions, such as a mouse-over tooltip.
Other charts forms are almost always better for encoding the magnitude information.
It is also easy to get the encoding wrong (Corrected version ):
ggplot
bubble charts for the average yield
values from the barley
data and for the 2007 population sizes for the gapminder data:
Waterfall Charts
Also called cascade charts .
These usually show the decomposition of a total into positive and negative contributions from various sources.
New Zealand net immigration by region:
Internet subscribers by month (blog post with ggplot
code ).
Polar Area Charts
Florence Nightingale’s famous chart showing the effect of the sanitation improvements in March/April 1855:
This chart has been called a polar area diagrams or a Coxcomb Chart .
It can be viewed as
a bar chart with the bars positioned in front of each other,
transformed to polar coordinates,
with magnitude mapped to area (i.e. square root of magnitude mapped to radius).
The data are available in the HistData
package as data frame Nightingale
.
Some rearrangement of the data is needed to get it into a form amenable for plotting.
library(forcats)
data(Nightingale, package = "HistData")
Night <-
mutate(Nightingale,
Period =
ifelse(Date < as.Date("1855-04-01"),
"Before",
"After"),
Period =
factor(Period, c("Before", "After")),
Month = factor(Month, month.abb)) %>%
select(Date, Month, Year, Period,
Disease, Wounds, Other) %>%
pivot_longer(5 : 7,
names_to = "Cause",
values_to = "Deaths")
## Rearrange the Month levels to start with April.
Night3 <- mutate(Night, Month = fct_shift(Month, 3))
A standard stacked bar chart of the data:
ggplot(Night3,
aes(x = Month, y = Deaths, fill = Cause)) +
geom_col() +
facet_wrap(~ Period) +
theme(legend.position = "top")
A grouped bar chart of the data:
ggplot(Night3,
aes(x = Month, y = Deaths, fill = Cause)) +
geom_col(position = "dodge") +
facet_wrap(~ Period) +
theme(legend.position = "top")
Using position = "identity"
the bars will be placed in front of each other rather than side by side or stacked.
p <- ggplot(Night3,
aes(x = Month, y = Deaths, fill = Cause)) +
geom_col(position = "identity", ## bars in front of each other
width = 1, ## remove space between bars
color = "black", ## bar border color
linewidth = 0.1) + ## bar border thickness
facet_wrap(~ Period) +
theme(legend.position = "top")
p
Problem: Larger bars may be placed in front of smaller ones.
Reordering the Deaths
values from largest to smallest ensures that larger bars do not cover smaller ones.
p <- ggplot(arrange(Night3, desc(Deaths)),
aes(x = Month, y = Deaths, fill = Cause)) +
geom_col(position = "identity", ## bars in front of each other
width = 1, ## remove space between bars
color = "black", ## bar border color
linewidth = 0.1) + ## bar border thickness
facet_wrap(~ Period) +
theme(legend.position = "top")
p
Changing to polar coordinates and mapping square roots of Deaths
to radius produces the basic polar area chart:
p %+% (arrange(Night3, desc(Deaths)) %>%
mutate(Deaths = sqrt(Deaths))) +
coord_polar()
Some adjustments bring the result closer to the original:
p %+%
(arrange(Night, desc(Deaths)) %>%
mutate(Month = fct_shift(Month, 6),
Period = factor(Period,
c("After", "Before")),
Deaths = sqrt(Deaths))) +
coord_polar() +
scale_fill_manual(
values = c(Wounds = "pink",
Other = "darkgray",
Disease = "lightblue")) +
theme(axis.title = element_blank(),
axis.text.y = element_blank(),
axis.ticks = element_blank(),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
panel.border = element_blank())
Base and Lattice Graphics
Base graphics provides the dotchart()
function for creating dot plots:
with(le_am_2007,
dotchart(sort(lifeExp),
labels = country[order(lifeExp)]))
The lattice
package provides dotplot()
:
library(lattice)
dotplot(reorder(country, lifeExp) ~ lifeExp,
data = le_am_2007)
Most lattice plots support a group
argument that is usually mapped to color:
dotplot(reorder(country, lifeExp) ~ lifeExp,
group = year, data = le2, auto.key = TRUE)
Creating a basic bar chart in lattice
uses the barchart()
function.
## By default lattice creates a bad bar chart with a
## non-zero base line for these data. Fix that by
## specifying xlim = c(0, 85).
barchart(reorder(country, lifeExp) ~ lifeExp,
data = le_am_2007, xlim = c(0, 85))
Base graphics also provides a bar chart with the barplot()
function.
par(mar = c(5, 5, 4, 2) + 0.1)
with(le_am_2007,
barplot(sort(lifeExp),
horiz = TRUE,
names.arg = country[order(lifeExp)],
las = 1,
cex.names = 0.7,
cex.axis = 0.7))
Interactive Tutorial
An interactive learnr
tutorial for these notes is available .
You can run the tutorial with
STAT4580::runTutorial("amounts")
You can install the current version of the STAT4580
package with
remotes::install_gitlab("luke-tierney/STAT4580")
You may need to install the remotes
package from CRAN first.
Exercises
A plot similar to this was featured in a CNN news story several years ago:
Which of the following is approximately correct:
About the same number of democrats as republicans agreed with the court.
About 15% more democrats than republicans agreed with the court.
About tree times as many democrats than republicans agreed with the court.
About two times as many democrats than republicans agreed with the court.
Consider the stacked bar chart produced by the following code:
library(tidyverse)
mpg2 <- mutate(mpg,
class = fct_rev(fct_infreq(class)),
cyl = factor(cyl))
p <- ggplot(mpg2, aes(y = class, fill = cyl)) +
geom_bar()
Which of these modifications makes it easiest to compare the count of 4-cylinder models within the different classes?
p %+% mutate(mpg2, cyl = factor(cyl, c(4, 5, 6, 8)))
p %+% mutate(mpg2, cyl = factor(cyl, c(8, 6, 5, 4)))
p %+% mutate(mpg2, cyl = factor(cyl, c(5, 6, 4, 8)))
p %+% mutate(mpg2, cyl = factor(cyl, c(4, 6, 8, 5)))
The bar chart produced by the following code has x
axis labels that could be improved:
library(gapminder)
library(dplyr)
library(ggplot2)
library(scales)
p <- filter(gapminder, year == 2007) %>%
group_by(continent) %>%
summarize(avgGdpPercap = mean(gdpPercap)) %>%
ggplot(aes(x = avgGdpPercap, y = continent)) +
geom_col() +
labs(x = "Average GDP Per Capita", y = NULL) +
theme_minimal() + theme(text = element_text(size = 16))
There are a number of different options. Which of the following does not provide improved x
axis labels?
p + scale_x_continuous(labels = label_comma())
p + scale_x_continuous(labels = label_dollar())
p + scale_x_continuous(labels = unit_format(scale = 1/1000, unit = "K", prefix = "$"))
p + scale_x_continuous(labels = c("$10,000", "$20,000", "$30,000"))
A stacked bar chart is appropriate if the combined bar heights of the stacked bars have a reasonable interpretation. Consider the following two plots:
library(gapminder)
library(dplyr)
library(ggplot2)
library(patchwork)
p1 <- filter(gapminder, year >= 2000) %>%
group_by(continent, year) %>%
summarize(avgLifeExp = mean(lifeExp), .groups = "drop") %>%
ggplot(aes(x = avgLifeExp, y = continent, fill = factor(year))) +
geom_col() +
theme_minimal() +
theme(text = element_text(size = 12)) +
scale_x_continuous(expand = expansion(mult = c(0, .1))) +
labs(x = "Average Life Expectancy",
y = NULL,
fill = "Year",
title = "Average Life Expectancy\nby Continent for Two Years",
tag = "P1:")
p2 <- count(mpg, class, cyl) %>%
ggplot(aes(x = n, y = class, fill = factor(cyl))) +
geom_col() +
theme_minimal() +
theme(text = element_text(size = 12)) +
scale_x_continuous(expand = expansion(mult = c(0, .1))) +
labs(x = "Number of Models",
y = NULL,
fill = "Cylinders",
title = "Number of Car Models\nby Class and Cylinder Count",
tag = "P2:")
p1 + p2
Which of the following statements is true:
P1 is an appropriate use of a stacked bar chart but P2 is not.
P2 is an appropriate use of a stacked bar chart but P1 is not.
Neither P1 nor P2 is an appropriate use of a stacked bar chart.
Both P1 and P2 are appropriate uses of a stacked bar chart.
LS0tCnRpdGxlOiAiVmlzdWFsaXppbmcgQW1vdW50cyIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IHllcwogICAgY29kZV9mb2xkaW5nOiAiaGlkZSIKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKLS0tCgo8bGluayByZWw9InN0eWxlc2hlZXQiIGhyZWY9InN0YXQ0NTgwLmNzcyIgdHlwZT0idGV4dC9jc3MiIC8+CjwhLS0gdGl0bGUgYmFzZWQgb24gV2lsa2UncyBjaGFwdGVyIC0tPgoKYGBge3Igc2V0dXAsIGluY2x1ZGUgPSBGQUxTRX0Kc291cmNlKGhlcmU6OmhlcmUoInNldHVwLlIiKSkKa25pdHI6Om9wdHNfY2h1bmskc2V0KGNvbGxhcHNlID0gVFJVRSwgbWVzc2FnZSA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgZmlnLmhlaWdodCA9IDUsIGZpZy53aWR0aCA9IDYsIGZpZy5hbGlnbiA9ICJjZW50ZXIiKQoKbGlicmFyeShsYXR0aWNlKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShncmlkRXh0cmEpCmxpYnJhcnkoc2NhbGVzKQpzZXQuc2VlZCgxMjM0NSkKYGBgCgpgYGB7ciwgaW5jbHVkZSA9IEZBTFNFfQpzb3VyY2UoaGVyZTo6aGVyZSgiZGF0YXNldHMuUiIpKQpgYGAKCgojIyBWaXN1YWxpemF0aW9uIGFuZCBDb21wYXJpc29uCgpBIHZpc3VhbGl6YXRpb24gb2YgYSBzaW5nbGUgdmFsdWUgd2l0aG91dCBzb21lIGNvbXBhcmF0aXZlIGNvbnRleHQgaXMKcmFyZWx5IHVzZWZ1bAoKYGBge3IsIGVjaG8gPSBGQUxTRX0KbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHNjYWxlcykKZ2dwbG90KCkgKwogICAgZ2VvbV9wb2ludChhZXMoeCA9IDAsIHkgPSAwKSwKICAgICAgICAgICAgICAgc2hhcGUgPSAyMSwgc2l6ZSA9IDE1MCwgZmlsbCA9IG11dGVkKCJibHVlIikpICsKICAgIGdlb21fdGV4dChhZXMoeCA9IDAsIHkgPSAwLCBsYWJlbCA9IDIwMCksIHNpemUgPSA1MCwgY29sb3IgPSAid2hpdGUiKSArCiAgICB0aGVtZV92b2lkKCkKYGBgCgpVc2VmdWwgdmlzdWFsaXphdGlvbnMgYWxtb3N0IGFsd2F5cyBpbnZvbHZlIGNvbXBhcmlzb25zLgoKKiBwb3NpdGlvbiBvZiBhIHZhbHVlIG9uIGFuIGF4aXMKCiogcmVsYXRpdmUgcG9zaXRpb24gb2YgdHdvIHZhbHVlcwoKKiByZWxhdGl2ZSBtYWduaXR1ZGVzIG9mIHR3byB2YWx1ZXMKCkEgc2ltcGxlIGFuZCBjb21tb24gc2V0dGluZzogVmlzdWFsaXppbmcgYSBtZWFzdXJlbWVudCBmb3IgZWFjaCBvZiBhCnNldCBvZiBjYXRlZ29yaWVzLgoKU29tZSBvZiB0aGUgbW9yZSBjb21tb24gdmlzdWFsaXphdGlvbnM6CgoqIERvdCBDaGFydHMgKGFsc28gY2FsbGVkIENsZXZlbGFuZCBEb3QgQ2hhcnRzKQoKKiBCYXIgQ2hhcnRzCiAgKiBHcm91cGVkIEJhciBDaGFydHMgKENsdXN0ZXJlZCBCYXIgQ2hhcnRzKQogICogU3RhY2tlZCBCYXIgQ2hhcnRzCiAgKiBEaXZlcmdpbmcgQmFyIENoYXJ0cwoKKiBIZWF0IE1hcHMKCiogQnViYmxlIENoYXJ0cwoKU29tZSBsZXNzIGZyZXF1ZW50bHkgdXNlZCB2aXN1YWxpemF0aW9uczoKCiogV2F0ZXJmYWxsIENoYXJ0cwoqIFBvbGFyIEFyZWEgQ2hhcnRzIChDb3hjb21iIENoYXJ0cykKKiBEdW1iYmVsbCBDaGFydHMKClNvbWUgcXVlc3Rpb25zIHRvIGtlZXAgaW4gbWluZDoKCiogV2hhdCBjb21wYXJpc29ucyBhbmQgb3RoZXIgYXNzZXNzbWVudHMgZG8gdGhlc2UgdmlzdWFsaXphdGlvbnMgc3VwcG9ydD8KCiogSG93IGRvIHRoZXNlIHZpc3VhbGl6YXRpb25zIHNjYWxlIHRvIGxhcmdlciBkYXRhIHNldHM/CgoKIyMgRG90IFBsb3RzCgoKIyMjIEJhc2ljcwoKT25lIG9mIHRoZSBzaW1wbGVzdCB2aXN1YWxpemF0aW9ucyBvZiBhIHNpbmdsZSBudW1lcmljYWwgdmFyaWFibGUgd2l0aAphIG1vZGVzdCBudW1iZXIgb2Ygb2JzZXJ2YXRpb25zIGFuZCBsYWJsZXMgZm9yIHRoZSBvYnNlcnZhdGlvbnMgaXMgYQpfZG90IHBsb3RfLCBvciBfQ2xldmVsYW5kIGRvdCBwbG90XzoKCmBgYHtyLCBtZXNzYWdlID0gRkFMU0UsIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUifQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoZ2FwbWluZGVyKQpsZV9hbV8yMDA3IDwtIGZpbHRlcihnYXBtaW5kZXIsCiAgICAgICAgICAgICAgICAgICAgIHllYXIgPT0gMjAwNywKICAgICAgICAgICAgICAgICAgICAgY29udGluZW50ID09ICJBbWVyaWNhcyIpCnRobSA8LSB0aGVtZV9taW5pbWFsKCkgKwogICAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYpKQpnZ3Bsb3QobGVfYW1fMjAwNywKICAgICAgIGFlcyh5ID0gY291bnRyeSwgeCA9IGxpZmVFeHApKSArCiAgICBnZW9tX3BvaW50KGNvbG9yID0gImRlZXBza3libHVlMyIsCiAgICAgICAgICAgICAgIHNpemUgPSAyKSArCiAgICBsYWJzKHggPSAiTGlmZSBFeHBlY3RhbmN5ICh5ZWFycykiLAogICAgICAgICB5ID0gTlVMTCkgKwogICAgdGhtCmBgYApgYGB7ciwgZWNobyA9IEZBTFNFLCBldmFsID0gRkFMU0V9CiMjIHRvIG9yZGVyIGFscGhhYmV0aWNhbGx5IGZyb20gdG9wIHRvIGJvdHRvbToKbGVfYW1fMjAwNyA8LSBtdXRhdGUobGVfYW1fMjAwNywKICAgICAgICAgICAgICAgICAgICAgY291bnRyeSA9IGZhY3Rvcihjb3VudHJ5LCByZXYoc29ydCh1bmlxdWUoY291bnRyeSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVzY2VuZGluZyA9IFRSVSkpKSkKYGBgCgpUaGlzIHZpc3VhbGl6YXRpb24KCiogc2hvd3MgdGhlIG92ZXJhbGwgZGlzdHJpYnV0aW9uIG9mIHRoZSBkYXRhLCBhbmQKCiogbWFrZXMgaXQgZWFzeSB0byBsb2NhdGUgdGhlIGxpZmUgZXhwZWN0YW5jeSBvZiBhIHBhcnRpY3VsYXIgY291bnRyeS4KClVubGVzcyB0aGVyZSBpcyBhIG5hdHVyYWwgb3JkZXIgdG8gdGhlIGNhdGVnb3JpZXMgKGUuZy4gbW9udGhzIG9mIHRoZQp5ZWFyIG9yIGRheXMgb2YgdGhlIHdlZWspIGl0IGlzIHVzdWFsbHkgYmV0dGVyIHRvIHJlb3JkZXIgdG8gbWFrZSB0aGUKcGxvdCBpbmNyZWFzaW5nIG9yIGRlY3JlYXNpbmc6CgpgYGB7ciwgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSJ9CmdncGxvdChsZV9hbV8yMDA3LAogICAgICAgYWVzKHkgPSByZW9yZGVyKGNvdW50cnksIGxpZmVFeHApLAogICAgICAgICAgIHggPSBsaWZlRXhwKSkgKwogICAgZ2VvbV9wb2ludChjb2xvciA9ICJkZWVwc2t5Ymx1ZTMiLAogICAgICAgICAgICAgICBzaXplID0gMikgKwogICAgbGFicyh4ID0gIkxpZmUgRXhwZWN0YW5jeSAoeWVhcnMpIiwKICAgICAgICAgeSA9IE5VTEwpICsKICAgIHRobQpgYGAKCiogTG9jYXRpbmcgYSBwYXJ0aWN1bGFyIGNvdW50cnkgaXMgYSBsaXR0bGUgbW9yZSBkaWZmaWN1bHQuCgoqIEJ1dCB0aGUgc2hhcGUgb2YgdGhlIGRpc3RyaWJ1dGlvbiBpcyBtb3JlIGFwcGFyZW50LgoKKiBBcHByb3hpbWF0ZSBtZWRpYW4gYW5kIHF1YXJ0aWxlcyBjYW4gYmUgcmVhZCBvZmYgZWFzaWx5LgoKRG90IHBsb3RzIGFyZSBwYXJ0aWN1bGFybHkgYXBwcm9wcmlhdGUgZm9yIGludGVydmFsIGRhdGEuCgoqIHRoZXkgb2Z0ZW4gZG8gbm90IHNob3cgdGhlIG9yaWdpbjsKCiogdGhleSBmb2N1cyB0aGUgdmlld2VyJ3MgYXR0ZW50aW9uIG9uIGRpZmZlcmVuY2VzLgoKRG90IHBsb3RzIGFyZSBvZnRlbiB2ZXJ5IHVzZWZ1bCBmb3IgZ3JvdXAgc3VtbWFyaWVzIGxpa2UgdG90YWxzIG9yCmF2ZXJhZ2VzLgoKRm9yIHRoZSBgYmFybGV5YCBkYXRhLCB0b3RhbCB5aWVsZCB3aXRoaW4gZWFjaCBzaXRlLCBhZGRpbmcgdXAKYWNyb3NzIGFsbCB2YXJpZXRpZXMgYW5kIGJvdGggeWVhcnMsIGNhbiBiZSBjb21wdXRlZCBhcwoKYGBge3J9CmJfdG90X3NpdGUgPC0KICAgIGdyb3VwX2J5KGJhcmxleSwgc2l0ZSkgJT4lCiAgICBzdW1tYXJpemUoeWllbGQgPSBzdW0oeWllbGQpKQpgYGAKClRoZSB0b3RhbHMgY2FuIHRoZW4gYmUgdmlzdWFsaXplZCBpbiBhIGRvdCBwbG90OgoKYGBge3IsIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUifQpnZ3Bsb3QoYl90b3Rfc2l0ZSwgYWVzKHggPSB5aWVsZCwgeSA9IHNpdGUpKSArCiAgICBnZW9tX3BvaW50KGNvbG9yID0gImRlZXBza3libHVlMyIsIHNpemUgPSAyLjUpICsKICAgIGxhYnMoeCA9ICJUb3RhbCBZaWVsZCAoYnVzaGVscy9hY3JlKSIsIHkgPSBOVUxMKSArCiAgICB0aG0KYGBgCgoKIyMjIExhcmdlciBEYXRhIFNldHMKCkZvciBsYXJnZXIgZGF0YSBzZXRzLCBsaWtlIHRoZSBgY2l0eXRlbXBzYCBkYXRhIHdpdGggYHIgbnJvdyhjaXR5dGVtcHMpYApvYnNlcnZhdGlvbnMsIG92ZXItcGxvdHRpbmcgb2YgbGFiZWxzIGJlY29tZXMgYSBwcm9ibGVtOgoKYGBge3IsIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUifQpnZ3Bsb3QoY2l0eXRlbXBzLAogICAgICAgYWVzKHggPSB0ZW1wLCB5ID0gcmVvcmRlcihjaXR5LCB0ZW1wKSkpICsKICAgIGdlb21fcG9pbnQoY29sb3IgPSAiZGVlcHNreWJsdWUzIiwgc2l6ZSA9IDAuNSkgKwogICAgbGFicyh4ID0gIlRlbXBlcmF0dXJlIChkZWdyZWVzIEYpIiwgeSA9IE5VTEwpICsKICAgIHRobQpgYGAKClJlZHVjaW5nIHRvIDMwIG9yIDQwLCBlLmcuIGJ5IHRha2luZyBhIHNhbXBsZSBvciBhIG1lYW5pbmdmdWwgc3Vic2V0LApjYW4gaGVscDoKCmBgYHtyLCBjbGFzcy5zb3VyY2UgPSAiZm9sZC1oaWRlIn0KY3QxIDwtIGZpbHRlcihjaXR5dGVtcHMsIHRlbXAgPCAzMikgJT4lIHNhbXBsZV9uKDEwKQpjdDIgPC0gZmlsdGVyKGNpdHl0ZW1wcywgdGVtcCA+PSAzMikgJT4lIHNhbXBsZV9uKDIwKQpjdHNhbXAgPC0gYmluZF9yb3dzKGN0MSwgY3QyKQpnZ3Bsb3QoY3RzYW1wLAogICAgICAgYWVzKHggPSB0ZW1wLCB5ID0gcmVvcmRlcihjaXR5LCB0ZW1wKSkpICsKICAgIGdlb21fcG9pbnQoY29sb3IgPSAiZGVlcHNreWJsdWUzIiwgc2l6ZSA9IDIpICsKICAgIGxhYnMoeCA9ICJUZW1wZXJhdHVyZSAoZGVncmVlcyBGKSIsIHkgPSBOVUxMKSArCiAgICB0aG0KYGBgCgoKIyMjIFNvbWUgVmFyaWF0aW9ucwoKVGhlIHNpemUgb2YgdGhlIGRvdHMgY2FuIGJlIHVzZWQgdG8gZW5jb2RlIGFuIGFkZGl0aW9uYWwgbnVtZXJpYwp2YXJpYWJsZS4KClRoaXMgdmlldyB1c2VzIGFyZWEgdG8gZW5jb2RlIHBvcHVsYXRpb24gc2l6ZToKCmBgYHtyLCBjbGFzcy5zb3VyY2UgPSAiZm9sZC1oaWRlIn0KZ2dwbG90KGxlX2FtXzIwMDcsIGFlcyh5ID0gcmVvcmRlcihjb3VudHJ5LCBsaWZlRXhwKSwKICAgICAgICAgICAgICAgICAgICAgICB4ID0gbGlmZUV4cCwKICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gcG9wIC8gMTAwMDAwMCkpICsKICAgIGdlb21fcG9pbnQoY29sID0gImRlZXBza3libHVlMyIpICsKICAgIGxhYnMoeCA9ICJMaWZlIEV4cGVjdGFuY3kgKHllYXJzKSIsIHkgPSBOVUxMKSArCiAgICBzY2FsZV9zaXplX2FyZWEoIlBvcHVsYXRpb25cbihNaWxsaW9ucykiLAogICAgICAgICAgICAgICAgICAgIG1heF9zaXplID0gOCkgKwogICAgdGhtICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpCmBgYAoKVGhpcyBpcyBzb21ldGltZXMgY2FsbGVkIGEgX2J1YmJsZSBjaGFydF8uCgpSZXBlYXRlZCBtZWFzdXJlcywgc3VjaCBhcyB2YWx1ZXMgZm9yIDIwMDIgYW5kIDIwMDcsIGNhbiBiZSBzaG93biBhbmQKZGlzdGluZ3Vpc2hlZCBieSBjb2xvciwgc2hhcGUsIG9yIGJvdGguCgpVc2luZyBjb2xvcjoKCmBgYHtyIGdhcG1pbmRlci1kb3RwbG90LXR3by15ZWFyLCBlY2hvID0gRkFMU0V9CmBgYAoKYGBge3IgZ2FwbWluZGVyLWRvdHBsb3QtdHdvLXllYXIsIGV2YWwgPSBGQUxTRSwgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSJ9CiMjIGZpbHRlciBkb3duIHRvIGRhdGEgZm9yIDIwMDIgYW5kIDIwMDcKIyMgZm9yIHRoZSBBbWVyaWNhcwpsZTIgPC0gZmlsdGVyKGdhcG1pbmRlciwKICAgICAgICAgICAgICB5ZWFyID49IDIwMDIsCiAgICAgICAgICAgICAgY29udGluZW50ID09ICJBbWVyaWNhcyIpCgojIyBtYWtlIGEgZmFjdG9yIFllYXIgdG8gZ2V0IGEgZGlzY3JldGUgY29sb3IKIyMgcGFsZXR0ZSwgbm90IGEgY29udGludW91cyBvbmUKbGUyIDwtIG11dGF0ZShsZTIsIFllYXIgPSBmYWN0b3IoeWVhcikpCgpnZ3Bsb3QobGUyLCBhZXMoeSA9IHJlb3JkZXIoY291bnRyeSwgbGlmZUV4cCksCiAgICAgICAgICAgICAgICB4ID0gbGlmZUV4cCwKICAgICAgICAgICAgICAgIGNvbG9yID0gWWVhcikpICsKICAgIGdlb21fcG9pbnQoKSArCiAgICBsYWJzKHggPSAiTGlmZSBFeHBlY3RhbmN5ICh5ZWFycykiLCB5ID0gTlVMTCkgKwogICAgdGhtICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpCmBgYAoKKiBBbGwgY291bnRyaWVzIHNob3cgc29tZSBpbXByb3ZlbWVudCBpbiBsaWZlIGV4cGVjdGFuY3kuCgoqIFRoZSBzbWFsbCBpbXByb3ZlbWVudCBmb3IgSmFtYWljYSBfcG9wcyBvdXRfIGEgYml0LgoKVXNpbmcgc2hhcGUgZm9yIHRoZSBgYmFybGV5YCBkYXRhOgoKYGBge3J9CmJfdG90IDwtCiAgICBncm91cF9ieShiYXJsZXksIHNpdGUsIHllYXIpICU+JQogICAgc3VtbWFyaXplKHlpZWxkID0gc3VtKHlpZWxkKSwgLmdyb3VwcyA9ICJkcm9wIikKZ2dwbG90KGJfdG90LCBhZXMoeCA9IHlpZWxkLCB5ID0gc2l0ZSwgc2hhcGUgPSB5ZWFyKSkgKwogICAgZ2VvbV9wb2ludChjb2xvciA9ICJkZWVwc2t5Ymx1ZTMiLCBzaXplID0gMykgKwogICAgbGFicyh4ID0gIlRvdGFsIFlpZWxkIChidXNoZWxzL2FjcmUpIiwgeSA9IE5VTEwpICsKICAgIHRobSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQpgYGAKCkZvciByZXBlYXRlZCB0d28gdmFsdWVzIHBlciBjbGFzcyBpdCBjYW4gaGVscCB0byBjb25uZWN0IHRoZSB0d28gZG90cy4KClRoaXMgdmlzdWFsbHkgZW1waGFzaXplcyB0aGUgcmVsYXRpdmUgc2l6ZXMgb2YgZGlmZmVyZW5jZXMuCgpUaGUgcmVzdWx0IGlzIHNvbWV0aW1lcyBjYWxsZWQgYSBfZHVtYmJlbGwgY2hhcnRfLgoKRm9yIHRoZSBiYXJsZXkgeWllbGRzIGRhdGE6CgpgYGB7ciwgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSJ9CmdncGxvdChiX3RvdCwgYWVzKHggPSB5aWVsZCwgeSA9IHNpdGUpKSArCiAgICBnZW9tX2xpbmUoYWVzKGdyb3VwID0gc2l0ZSksCiAgICAgICAgICAgICAgbGluZXdpZHRoID0gMiwKICAgICAgICAgICAgICBjb2xvciA9ICJncmV5IikgKwogICAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSB5ZWFyKSwgc2l6ZSA9IDQpICsKICAgIGxhYnMoeCA9ICJUb3RhbCBZaWVsZCAoYnVzaGVscy9hY3JlKSIsIHkgPSBOVUxMKSArCiAgICB0aG0gKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikKYGBgCgpGb3IgdGhlIEdhcG1pbmRlciBsaWZlIGV4cGVjdGFuY3kgZGF0YToKCmBgYHtyLCBlY2hvID0gRkFMU0UsIGV2YWwgPSBGQUxTRX0KbGlicmFyeShnZ2FsdCkKbGlicmFyeShzY2FsZXMpCnBpdm90X3dpZGVyKGJfdG90LAogICAgICAgICAgICBuYW1lc19mcm9tID0gInllYXIiLAogICAgICAgICAgICB2YWx1ZXNfZnJvbSA9ICJ5aWVsZCIsCiAgICAgICAgICAgIG5hbWVzX3ByZWZpeCA9ICJYIikgJT4lCiAgICBnZ3Bsb3QoYWVzKHggPSBYMTkzMSwgeSA9IHNpdGUsIHhlbmQgPSBYMTkzMikpICsKICAgIGdlb21fZHVtYmJlbGwoc2l6ZSA9IDMsIGNvbG9yID0gImdyZXkiLAogICAgICAgICAgICAgICAgICBjb2xvcl94ID0gbXV0ZWQoInJlZCIpLCBjb2xvcl94ZW5kID0gbXV0ZWQoImJsdWUiKSwKICAgICAgICAgICAgICAgICAgZG90X2d1aWRlID0gVFJVRSkKYGBgCgpgYGB7ciwgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSJ9CmdncGxvdChsZTIsIGFlcyh5ID0gcmVvcmRlcihjb3VudHJ5LCBsaWZlRXhwKSwKICAgICAgICAgICAgICAgIHggPSBsaWZlRXhwLAogICAgICAgICAgICAgICAgY29sb3IgPSBZZWFyKSkgKwogICAgZ2VvbV9saW5lKGFlcyhncm91cCA9IGNvdW50cnkpLAogICAgICAgICAgICAgIGxpbmV3aWR0aCA9IDEuNSwKICAgICAgICAgICAgICBjb2xvciA9ICJncmV5IikgKwogICAgZ2VvbV9wb2ludChzaXplID0gMi41KSArCiAgICBsYWJzKHggPSAiTGlmZSBFeHBlY3RhbmN5ICh5ZWFycykiLCB5ID0gTlVMTCkgKwogICAgdGhtICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpCmBgYAoKCiMjIyBWYXJpYXRpb25zIGluIEFwcGVhcmFuY2UKClRoZSBkb3QgcGxvdHMgaW50cm9kdWNlZCBieSBXLiBTLiBDbGV2ZWxhbmQgaW4gaGlzIDE5OTMgYm9vawpfVmlzdWFsaXppbmcgRGF0YV8gdXNlIG9ubHkgaG9yaXpvbnRhbCBncmlkIGxpbmVzLgoKVGhpcyBhbHNvIGNvcnJlc3BvbmRzIHRvIHRoZSBkb3QgcGxvdHMgcHJvdmlkZWQgYnkgYmFzZSBhbmQgbGF0dGljZQpncmFwaGljcyBhbmQgdG8gdGhlIGRvdCBwbG90IG9idGFpbmVkIHVzaW5nIHRoZSBXYWxsIFN0cmVldCBKb3VybmFsCnRoZW1lIGZyb20gdGhlIGBnZ3RoZW1lc2BwYWNrYWdlOgoKYGBge3IsIGZpZy5oZWlnaHQgPSA1LjUsIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUifQpnZ3Bsb3QoYl90b3Rfc2l0ZSwgYWVzKHggPSB5aWVsZCwgeSA9IHNpdGUpKSArCiAgICBnZW9tX3BvaW50KHNpemUgPSAyKSArCiAgICBsYWJzKHggPSAiVG90YWwgWWllbGQgKGJ1c2hlbHMvYWNyZSkiLCB5ID0gTlVMTCkgKwogICAgZ2d0aGVtZXM6OnRoZW1lX3dzaigpCmBgYAoKQSB0aGVtZSB0byBjbG9zZWx5IG1hdGNoIHRoZSBzdHlsZSB1c2VkIGJ5IENsZXZlbGFuZCBjYW4gYmUgZGVmaW5lZCBhcwoKPCEtLQoKIyBodHRwOi8vd3d3Lndpbi12ZWN0b3IuY29tL2Jsb2cvMjAxMy8wMi9yZXZpc2l0aW5nLWNsZXZlbGFuZHMtdGhlLWVsZW1lbnRzLW9mLWdyYXBoaW5nLWRhdGEtaW4tZ2dwbG90Mi8KLS0+CgpgYGB7cn0KdGhlbWVfZG90cGxvdHggPC0gZnVuY3Rpb24oKSB7CiAgICB0aGVtZSgKICAgICAgICAjIyByZW1vdmUgdGhlIHZlcnRpY2FsIGdyaWQgbGluZXMKICAgICAgICBwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vci54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICMjIGV4cGxpY2l0bHkgc2V0IHRoZSBob3Jpem9udGFsIGxpbmVzCiAgICAgICAgIyMgKG9yIHRoZXkgd2lsbCBkaXNhcHBlYXIgdG9vKQogICAgICAgIHBhbmVsLmdyaWQubWFqb3IueSA9CiAgICAgICAgICAgIGVsZW1lbnRfbGluZShjb2xvciA9ICJibGFjayIsCiAgICAgICAgICAgICAgICAgICAgICAgICBsaW5ldHlwZSA9IDMpLAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSByZWwoMS4yKSksCiAgICAgICAgIyMgdXNlIGEgd2hpdGUgYmFja2dyb3Vuc2QKICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0KICAgICAgICAgICAgZWxlbWVudF9yZWN0KGZpbGwgPSAid2hpdGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBOQSksCiAgICAgICAgcGFuZWwuYm9yZGVyID0KICAgICAgICAgICAgZWxlbWVudF9yZWN0KGZpbGwgPSBOQSwKICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gImdyZXkyMCIpLAogICAgICAgICMjIGluY3JlYXNlIHRleHQgc2l6ZQogICAgICAgIHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2KSkKfQpgYGAKClRoaXMgcHJvZHVjZXMKCmBgYHtyLCBjbGFzcy5zb3VyY2UgPSAiZm9sZC1oaWRlIn0KZ2dwbG90KGJfdG90X3NpdGUsIGFlcyh4ID0geWllbGQsIHkgPSBzaXRlKSkgKwogICAgZ2VvbV9wb2ludChzaXplID0gMikgKwogICAgbGFicyh4ID0gIlRvdGFsIFlpZWxkIChidXNoZWxzL2FjcmUpIiwKICAgICAgICAgeSA9IE5VTEwpICsKICAgIHRoZW1lX2RvdHBsb3R4KCkKYGBgCgoKIyMgQmFyIENoYXJ0cwoKCiMjIyBCYXNpY3MKCkEgYmFzaWMgYmFyIGNoYXJ0OgoKYGBge3IsIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUifQpwIDwtIGdncGxvdChsZV9hbV8yMDA3KSArCiAgICBnZW9tX2NvbChhZXMoeSA9IGxpZmVFeHAsCiAgICAgICAgICAgICAgICAgeCA9IHJlb3JkZXIoY291bnRyeSwgbGlmZUV4cCkpLAogICAgICAgICAgICAgZmlsbCA9ICJkZWVwc2t5Ymx1ZTMiKSArCiAgICBsYWJzKHkgPSAiTGlmZSBFeHBlY3RhbmN5ICh5ZWFycykiLAogICAgICAgICB4ID0gTlVMTCkgKwogICAgc2NhbGVfeV9jb250aW51b3VzKAogICAgICAgIGV4cGFuZCA9IGV4cGFuc2lvbihtdWx0ID0gYygwLCAuMSkpKSArCiAgICB0aG0KcApgYGAKClRoZSBsYWJlbHMgYXJlIGEgbWVzcy4KCiogT25lIG9wdGlvbiBpcyB0byB3cml0ZSBsYWJlbHMgYXQgYW4gYW5nbGUsIGJ1dCB0aGlzIG1ha2VzIHRoZW0gaGFyZCB0byByZWFkLgoKKiBGbGlwcGluZyB0aGUgcGxvdCBpcyB1c3VhbGx5IGEgYmV0dGVyIG9wdGlvbi4KClRvIG1ha2UgbGFiZWxzIHJlYWRhYmxlIHdlIGNhbiBmbGlwIHRoZSBwbG90OgoKYGBge3IsIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUifQojIyBSZWRvaW5nIHRoZSBwbG90IHBsb3Qgd2l0aCBgeGAgYW5kIGB5YCBhZXN0aGV0aWNzIHJldmVyc2VkIGRpZCBub3QKIyMgd29yayBpbiB0aGUgcGFzdCBidXQgZG9lcyB3b3JrIGluIGN1cnJlbnQgZ2dwbG90MiB2ZXJzaW9ucy4KIyMgQnV0IGFzIHdlIGFscmVhZHkgaGF2ZSB0aGUgcHJldmlvdXMgcGxvdCB3ZSBjYW4ganVzdCB1c2UgY29vcmRfZmxpcCgpLApwICsgY29vcmRfZmxpcCgpCmBgYAoKCiMjIyBTb21lIE5vdGVzCgpCYXIgY2hhcnRzIHNlZW0gdG8gYmUgdXNlZCBtdWNoIG1vcmUgdGhhbiBkb3QgcGxvdHMgaW4gdGhlIHBvcHVsYXIKbWVkaWEsIGJ1dCB0aGV5IGFyZSBsZXNzIHdpZGVseSBhcHBsaWNhYmxlLgoKUmVzZWFyY2ggb24gdmlzdWFsIHBlcmNlcHRpb24gaGFzIHNob3duIHRoYXQgdmlld2VycyBvZiBiYXIgY2hhcnRzCnN1YmNvbnNjaW91c2x5LCBvciBfcHJlLWF0dGVudGl2ZWx5XywgZm9jdXMgb24gcmVsYXRpdmUgbGVuZ3RocyBvZiBiYXJzLgoKVGhpcyBtZWFucyB0aGF0IGZvciBhIGJhciBjaGFydCB0byBiZSBhcHByb3ByaWF0ZSBhbmQgd29yayB3ZWxsOgoKKiBSYXRpbyBjb21wYXJpc29ucyBoYXZlIHRvIG1ha2Ugc2Vuc2UgZm9yIHlvdSBkYXRhLgoKKiBUaGUgcmVsYXRpdmUgYmFyIGxlbmd0aHMgaGF2ZSB0byBhY2N1cmF0ZWx5IHJlZmxlY3QgdGhhdCBkYXRhIHJhdGlvLgoKVGhpcyBpbiB0dXJuIGltcGxpZXMgdGhhdCBiYXIgY2hhcnRzIHNob3VsZCBfYWx3YXlzXyBoYXZlIGEgemVybyBiYXNlIGxpbmUuCgpZb3UgbWF5IG5lZWQgdG8gaW50ZXJ2ZW5lIHdpdGggeW91ciBzb2Z0d2FyZSdzIGRlZmF1bHRzIHRvIG1ha2UgdGhpcwpoYXBwZW4uCgpDcmVhdGluZyBhIGJhciBjaGFydCB3aXRoIGEgbm9uLXplcm8gYmFzZSBsaW5lIGlzIHBvc3NpYmxlIGluIGBnZ3Bsb3RgCmJ1dCBub3QgZWFzeToKCmBgYHtyLCBtZXNzYWdlID0gRkFMU0UsIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUifQpiYXNlbGluZSA8LSA2MAp0aWNrcyA8LSBjKDAsIDEwLCAyMCwgMzApCmdncGxvdChsZV9hbV8yMDA3LAogICAgICAgYWVzKHggPSBsaWZlRXhwIC0gYmFzZWxpbmUsCiAgICAgICAgICAgeSA9IHJlb3JkZXIoY291bnRyeSwgbGlmZUV4cCkpKSArCiAgICBnZW9tX2NvbChmaWxsID0gImRlZXBza3libHVlMyIpICsKICAgIGxhYnMoeCA9ICJMaWZlIEV4cGVjdGFuY3kgKHllYXJzKSIsCiAgICAgICAgIHkgPSBOVUxMKSArCiAgICBzY2FsZV94X2NvbnRpbnVvdXMoCiAgICAgICAgYnJlYWtzID0gdGlja3MsCiAgICAgICAgbGFiZWxzID0gdGlja3MgKyBiYXNlbGluZSwKICAgICAgICBleHBhbmQgPSBleHBhbnNpb24obXVsdCA9IGMoMCwgLjEpKSkgKwogICAgdGhtICsgbGFicyh0aXRsZSA9ICJBIEJhZCBCYXIgQ2hhcnQiKQpgYGAKCiogVGhlIHZpc3VhbCBpbXByZXNzaW9uIGlzIHRoYXQgdGhlIHZhbHVlIGZvciBCb2xpdmlhIGlzIGZpdmUgdGltZXMKICBoaWdoZXIgdGhhbiB0aGUgdmFsdWUgZm9yIEhhaXRpLgoKKiBUaGlzIGlzIF9ub3RfIGFuIGFjY3VyYXRlIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBkYXRhLgoKQmFyIGNoYXJ0cyBhbHdheXMgcHVzaCB0aGUgdmlld2VyIHRvIHJhdGlvIGNvbXBhcmlzb25zLCB3aGV0aGVyCnRoZXkgYXJlIG1lYW5pbmdmdWwgb3Igbm90LgoKVXNpbmcgYSBub24temVybyBiYXNlbGluZSBjYW4gdGhlcmVmb3JlClttaXNsZWFkIHRoZSB2aWV3ZXJdKGh0dHBzOi8vd3d3LnN0b3J5dGVsbGluZ3dpdGhkYXRhLmNvbS9ibG9nLzIwMTIvMDkvYmFyLWNoYXJ0cy1tdXN0LWhhdmUtemVyby1iYXNlbGluZSkuCgpTb21lIG5ld3Mgb3JnYW5pemF0aW9ucyBzZWVtIHBhcnRpY3VsYXJseSBwcm9uZSB0byB0YWtpbmcgYWR2YW50YWdlCm9mL2ZhbGxpbmcgcHJleSB0byB0aGlzIGlzc3VlLgoKYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0LndpZHRoID0gIjcwJSJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKElNRygiYnVzaHRheGJhci5qcGVnIikpCmBgYApgYGB7ciwgZWNobyA9IEZBTFNFLCBvdXQud2lkdGggPSAiNzAlIn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoSU1HKCJvYmFtYWJhci5qcGVnIikpCmBgYAoKQSByZWNlbnQgW2Jsb2cKcG9zdF0oaHR0cHM6Ly93d3cuc3RhdHNjaGF0Lm9yZy5uei8yMDIwLzAyLzAyL2dyYXBocy1kb250LW1hdHRlci8pCmRpc2N1c3NlcyBhIGNvdXJ0IGNhc2UgaW4gTmV3IFplYWxhbmQgYWJvdXQgYSBtaXNsZWFkaW5nIGJhciBjaGFydAp3aXRoIGEgbm9uLXplcm8gYmFzZWxpbmUuCgpBbm90aGVyIHJlY2VudCBbYmxvZwpwb3N0XShodHRwczovL3d3dy5zdG9yeXRlbGxpbmd3aXRoZGF0YS5jb20vYmxvZy8yMDIwLzIvMTkvd2hhdC1pcy1hLWJhci1jaGFydCkKbWF5IGJlIGhlbHBmdWwuCgoKIyMjIERhdGEgV2l0aCBCb3RoIFBvc2l0aXZlIGFuZCBOZWdhdGl2ZSBWYWx1ZXMgCgpCYXIgY2hhcnRzIGNhbiBiZSB1c2VkIGZvciBkYXRhIGNvbnRhaW5pbmcgYm90aCBwb3NpdGl2ZSBhbmQgbmVnYXRpdmUKdmFsdWVzOgoKYGBge3IsIGZpZy53aWR0aCA9IDEwLCB3YXJuaW5nID0gRkFMU0UsIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUifQpjdHNhbXBDIDwtIG11dGF0ZShjdHNhbXAsIHRlbXAgPSByb3VuZCgodGVtcCAtIDMyKSAvIDEuOCkpCnAxIDwtIGdncGxvdChjdHNhbXBDLCBhZXMoeSA9IGNpdHksIHggPSB0ZW1wKSkgKwogICAgZ2VvbV9wb2ludChjb2xvciA9ICJkZWVwc2t5Ymx1ZTMiKSArCiAgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBsdHkgPSAyKSArCiAgICBsYWJzKHggPSAiVGVtcGVyYXR1cmUgKGRlZ3JlZXMgQykiLCB5ID0gTlVMTCkgKwogICAgdGhtCnAyIDwtIGdncGxvdChjdHNhbXBDLCBhZXMoeCA9IHRlbXAsIHkgPSBjaXR5KSkgKwogICAgZ2VvbV9jb2woZmlsbCA9ICJkZWVwc2t5Ymx1ZTMiKSArCiAgICBsYWJzKHggPSAiVGVtcGVyYXR1cmUgKGRlZ3JlZXMgQykiLCB5ID0gTlVMTCkgKwogICAgdGhtCmxpYnJhcnkocGF0Y2h3b3JrKQpwMSArIHAyCmBgYAoKVGhpcyBwdXRzIGEgc3Ryb25nIGVtcGhhc2lzIG9uIHRoZSBiYXNlIGxpbmUKClRoaXMgY2FuIGJlIHVzZWZ1bCBpZiB0aGUgYmFzZWxpbmUgaXMgbWVhbmluZ2Z1bCwgc3VjaCBhcwoKKiBbYW4gYXZlcmFnZSBsZXZlbF0oaHR0cHM6Ly93d3cubmNlaS5ub2FhLmdvdi9hY2Nlc3MvbW9uaXRvcmluZy9jbGltYXRlLWF0LWEtZ2xhbmNlL3RpbWUtc2VyaWVzL2dsb2JhbCkKCiogemVybyBkZWdyZWVzIENlbGNpdXMKClplcm8gZGVncmVlcyBGYWhyZW5oZWl0IGlzIG5vdCBtZWFuaW5nZnVsOgoKYGBge3IsIGZpZy53aWR0aCA9IDEwLCB3YXJuaW5nID0gRkFMU0UsIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUifQpwMSA8LSBnZ3Bsb3QoY3RzYW1wLCBhZXMoeSA9IGNpdHksIHggPSB0ZW1wKSkgKwogICAgZ2VvbV9wb2ludChjb2xvciA9ICJkZWVwc2t5Ymx1ZTMiKSArCiAgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBsdHkgPSAyKSArCiAgICBsYWJzKHggPSAiVGVtcGVyYXR1cmUgKGRlZ3JlZXMgRikiLCB5ID0gTlVMTCkgKwogICAgdGhtCnAyIDwtIGdncGxvdChjdHNhbXAsIGFlcyh4ID0gdGVtcCwgeSA9IGNpdHkpKSArCiAgICBnZW9tX2NvbChmaWxsID0gImRlZXBza3libHVlMyIpICsKICAgIGxhYnMoeCA9ICJUZW1wZXJhdHVyZSAoZGVncmVlcyBGKSIsIHkgPSBOVUxMKSArCiAgICB0aG0KcDEgKyBwMgpgYGAKCgojIyMgR3JvdXBlZCBCYXIgQ2hhcnRzCgpBIF9ncm91cGVkIGJhciBjaGFydF8gY2FuIGJlIHVzZWQgdG8gc2hvdyB0d28gbWVhc3VyZW1lbnRzLCBlLmcuIHR3byB0aW1lcy4KCmBgYHtyLCBjbGFzcy5zb3VyY2UgPSAiZm9sZC1oaWRlIn0KZ2dwbG90KGxlMikgKwogICAgZ2VvbV9jb2woYWVzKHggPSBsaWZlRXhwLAogICAgICAgICAgICAgICAgIHkgPSByZW9yZGVyKGNvdW50cnksIGxpZmVFeHApLAogICAgICAgICAgICAgICAgIGZpbGwgPSBZZWFyKSwKICAgICAgICAgICAgIHBvc2l0aW9uID0gImRvZGdlIikgKwogICAgbGFicyh4ID0gIkxpZmUgRXhwZWN0YW5jeSAoeWVhcnMpIiwKICAgICAgICAgeSA9IE5VTEwpICsKICAgIHNjYWxlX3hfY29udGludW91cygKICAgICAgICBleHBhbmQgPSBleHBhbnNpb24obXVsdCA9IGMoMCwgLjEpKSkgKwogICAgdGhtCmBgYAoKVGhpcyB2aXN1YWxpemF0aW9uIHdvdWxkIGJlIG1vcmUgZWZmZWN0aXZlIGZvcgoKKiBmZXdlciBjb3VudHJpZXMgYW5kIG1vcmUgeWVhcnMKCiogd2l0aCBtb3JlIHZhcmlhdGlvbiBpbiByYXRpb3Mgd2l0aGluIGFuZCBiZXR3ZWVuIGNhdGVnb3JpZXMuCgpJbiB0aGlzIGNhc2UgdGhlIGRvdCBwbG90IGlzIGEgbXVjaCBiZXR0ZXIgY2hvaWNlLgoKRm9yIHRoZSBgYmFybGV5YCBkYXRhIGxvb2tpbmcgYXQgdG90YWwgeWllbGRzIGZvciBlYWNoIG9mIHRoZSBzaXRlcwphbmQgdGhlIHR3byB5ZWFyczoKCmBgYHtyLCBjbGFzcy5zb3VyY2UgPSAiZm9sZC1oaWRlIn0KZ2dwbG90KGJfdG90KSArCiAgICBnZW9tX2NvbChhZXMoeCA9IHlpZWxkLCB5ID0gc2l0ZSwgZmlsbCA9IHllYXIpLAogICAgICAgICAgICAgcG9zaXRpb24gPSAiZG9kZ2UiKSArCiAgICBsYWJzKHggPSAiVG90YWwgWWllbGQgKGJ1c2hlbHMvYWNyZSkiLAogICAgICAgICB5ID0gTlVMTCkgKwogICAgc2NhbGVfeF9jb250aW51b3VzKAogICAgICAgIGV4cGFuZCA9IGV4cGFuc2lvbihtdWx0ID0gYygwLCAuMSkpKSArCiAgICB0aG0KYGBgCgoKIyMjIFN0YWNrZWQgQmFyIENoYXJ0cwoKQSBfc3RhY2tlZCBiYXIgY2hhcnRfIGlzIGFwcHJvcHJpYXRlIHdoZW4gYWRkaW5nIHRoZSB2YWx1ZXMgd2l0aGluIGEKY2F0ZWdvcnkgdG8gZm9ybSBhIHRvdGFsIG1ha2VzIHNlbnNlLgoKRm9yIHRoZSBgYmFybGV5YCBkYXRhOgoKYGBge3IsIGZpZy5oZWlnaHQgPSA0LCBjbGFzcy5zb3VyY2UgPSAiZm9sZC1oaWRlIn0KZ2dwbG90KGJfdG90KSArCiAgICBnZW9tX2NvbChhZXMoeCA9IHlpZWxkLCB5ID0gc2l0ZSwgZmlsbCA9IHllYXIpLAogICAgICAgICAgICAgcG9zaXRpb24gPSAic3RhY2siKSArCiAgICBsYWJzKHggPSAiVG90YWwgWWllbGQgKGJ1c2hlbHMvYWNyZSkiLAogICAgICAgICB5ID0gTlVMTCkgKwogICAgc2NhbGVfeF9jb250aW51b3VzKAogICAgICAgIGV4cGFuZCA9IGV4cGFuc2lvbihtdWx0ID0gYygwLCAuMSkpKSArCiAgICB0aG0KYGBgCgoqIFRoZSBjb21iaW5lZCBiYXJzIHNob3cgdGhlIHRvdGFscy4KCiogVGhlIGJhciBzZWdtZW50cyBzaG93IHRoZSBjb250cmlidXRpb24gb2YgZWFjaCB5ZWFyIHdpdGhpbiB0aGUgc2l0ZXMuCgoqIENvbXBhcmluZyAxOTMxIHlpZWxkcyBhY3Jvc3Mgc2l0ZXMgaXMgZWFzeTsgY29tcGFyaW5nIDE5MzIgdmFsdWVzIGlzIGhhcmRlci4KCkEgc3RhY2tlZCBiYXIgY2hhcnQgd291bGQgbWFrZSBubyBzZW5zZSBmb3IgdGhlIHR3by15ZWFyIGxpZmUKZXhwZWN0YW5jeSBkYXRhLgoKCiMjIyBDYXRlZ29yeSBPcmRlcgoKT3JkZXJpbmcgb2YgY2F0ZWdvcmllcyBjYW4gY2hhbmdlIHRoZSB2aXN1YWwgZWZmZWN0aXZlbmVzcyBvZiBiYXIgY2hhcnRzLgoKCiMjIyMgU3VwZXJtYXJrZXQgU2FsZXMKCkEgc21hbGwgZGF0YSBzZXQgb24gbXVsdGktbmF0aW9uYWwgc3VwZXJtYXJrZXQgY2hhaW4gc2FsZXM6CgpgYGB7ciwgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSJ9CmNoYWlucyA8LSByZWFkLmNzdih0ZXh0Q29ubmVjdGlvbigiQ2hhaW4sIFRvdGFsLCBGb3JlaWduCldhbG1hcnQsIDIyLCA1CkNvc3RjbywgNC41LCAyClRlc2NvLCAzLCAwLjUKQ2FycmVmb3VyLCAyLjUsIDIiKSkKY2hhaW5zIDwtIG11dGF0ZShjaGFpbnMsIEhvbWUgPSBUb3RhbCAtIEZvcmVpZ24pCnRibCA8LSBzZWxlY3QoY2hhaW5zLCBDaGFpbiwgSG9tZSwgRm9yZWlnbiwgVG90YWwpCmtibCA8LSBrbml0cjo6a2FibGUodGJsLCBmb3JtYXQgPSAiaHRtbCIpCmthYmxlRXh0cmE6OmthYmxlX3N0eWxpbmcoa2JsLCBmdWxsX3dpZHRoID0gRkFMU0UpCmBgYAo8IS0tIGh0dHBzOi8vanVua2NoYXJ0cy50eXBlcGFkLmNvbS9qdW5rX2NoYXJ0cy8yMDIwLzAxL3Rha2luZy1zbWFsbC1zdGVwcy10by1icmluZy1vdXQtdGhlLW1lc3NhZ2UuaHRtbCAtLT4KClRoZSBkZWZhdWx0IGFscGhhYmV0aWNhbCBvcmRlcmluZyBvZiB0aGUgY2hhaW5zIGluIGEgYmFyIGNoYXJ0IGlzIG5vdCBpZGVhbDoKCmBgYHtyLCBjbGFzcy5zb3VyY2UgPSAiZm9sZC1oaWRlIn0KbGlicmFyeSh0aWR5cikKY2hhaW5zIDwtIG11dGF0ZShjaGFpbnMsIFRvdGFsID0gTlVMTCkKbGNoYWlucyA8LSBwaXZvdF9sb25nZXIoY2hhaW5zLAogICAgICAgICAgICAgICAgICAgICAgICAtQ2hhaW4sCiAgICAgICAgICAgICAgICAgICAgICAgIG5hbWVzX3RvID0gIlR5cGUiLAogICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXNfdG8gPSAiU2FsZXMiKQpwIDwtIGdncGxvdChsY2hhaW5zLAogICAgICAgICAgICBhZXMoeCA9IFNhbGVzLCB5ID0gQ2hhaW4sIGZpbGwgPSBUeXBlKSkgKwogICAgZ2VvbV9jb2woKSArCiAgICB5bGFiKE5VTEwpICsKICAgIHNjYWxlX3hfY29udGludW91cygKICAgICAgICBleHBhbmQgPSBleHBhbnNpb24obXVsdCA9IGMoMCwgLjEpKSkgKwogICAgc2NhbGVfZmlsbF9icmV3ZXIoCiAgICAgICAgcGFsZXR0ZSA9ICJQYWlyZWQiLAogICAgICAgIGd1aWRlID0gZ3VpZGVfbGVnZW5kKHRpdGxlID0gTlVMTCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXZlcnNlID0gVFJVRSkpICsKICAgIHRobSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQpwCmBgYAoKUmVvcmRlcmluZyBieSB0b3RhbCBzYWxlcyBwcm9kdWNlcyBhIGJldHRlciByZXN1bHQ6CgpgYGB7ciwgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSJ9CmxjaGFpbl9zIDwtCiAgICBtdXRhdGUobGNoYWlucywKICAgICAgICAgICBDaGFpbiA9IHJlb3JkZXIoQ2hhaW4sIFNhbGVzLCBGVU4gPSBzdW0pKQpwICUrJSBsY2hhaW5fcwpgYGAKCldpdGggdGhpcyBvcmRlcmluZywgY29tcGFyaW5nIHRoZSBmaXJzdCBjYXRlZ29yeSBvZiBzYWxlcywgYEhvbWVgLAphbW9uZyBjaGFpbnMgaXMgZWFzaWVyIHRoYW4gY29tcGFyaW5nIHRoZSBgRm9yZWlnbmAgc2FsZXMgYXMgdGhlCmBIb21lYCB2YWx1ZXMgaGF2ZSBhIGNvbW1vbiBiYXNlbGluZS4KCklmIHRoZSBnb2FsIG9mIHRoZSB2aXN1YWxpemF0aW9uIGlzIHRvIGVtcGhhc2l6ZSB0aGUgZm9yZWlnbiBzYWxlcwp0aGVuIHJldmVyc2luZyB0aGUgb3JkZXIgd291bGQgYmUgYmV0dGVyLgoKYGBge3IsIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUifQpsY2hhaW5fc3QgPC0KICAgIG11dGF0ZShsY2hhaW5fcywKICAgICAgICAgICBUeXBlID0gZmFjdG9yKFR5cGUsCiAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSBjKCJIb21lIiwgIkZvcmVpZ24iKSkpCnAgJSslIGxjaGFpbl9zdCArCiAgICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlBhaXJlZCIsCiAgICAgICAgICAgICAgICAgICAgICBndWlkZSA9IGd1aWRlX2xlZ2VuZCh0aXRsZSA9IE5VTEwsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXZlcnNlID0gVFJVRSksCiAgICAgICAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAtMSkKYGBgCgpUaGlzIGFsc28gbWFrZXMgaXQgZWFzeSB0byBzZWUgdGhhdCBXYWxtYXJ0J3MgaW50ZXJuYXRpb25hbCBzYWxlcwphbG9uZSBleGNlZWQgdGhlIHRvdGFsIHNhbGVzIG9mIGVhY2ggb2YgdGhlIG90aGVyIGNoYWlucy4KCkEgX2ZpbGxlZCBiYXIgY2hhcnRfIGNhbiBiZSB1c2VkIHRvIGhlbHAgY29tcGFyZSB0aGUgcHJvcG9ydGlvbnMgb2YKdG90YWwgc2FsZXMgZnJvbSBmb3JlaWduIHN0b3Jlcy4KCmBgYHtyLCBjbGFzcy5zb3VyY2UgPSAiZm9sZC1oaWRlIn0KbGV2cyA8LQogICAgbGV2ZWxzKHdpdGgoY2hhaW5zLAogICAgICAgICAgICAgICAgcmVvcmRlcihDaGFpbiwgRm9yZWlnbiAvIChGb3JlaWduICsgSG9tZSkpKSkKbXV0YXRlKGxjaGFpbl9zdCwgQ2hhaW4gPSBmYWN0b3IoQ2hhaW4sIGxldnMpKSAlPiUKZ2dwbG90KGFlcyh4ID0gU2FsZXMsIHkgPSBDaGFpbiwgZmlsbCA9IFR5cGUpKSArCiAgICBnZW9tX2NvbChwb3NpdGlvbiA9ICJmaWxsIikgKwogICAgbGFicyh4ID0gIlByb3BvcnRpb24gb2YgU2FsZXMiLCB5ID0gTlVMTCkgKwogICAgc2NhbGVfeF9jb250aW51b3VzKAogICAgICAgIGV4cGFuZCA9IGV4cGFuc2lvbihtdWx0ID0gYygwLCAuMSkpKSArCiAgICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlBhaXJlZCIsCiAgICAgICAgICAgICAgICAgICAgICBndWlkZSA9IGd1aWRlX2xlZ2VuZCh0aXRsZSA9IE5VTEwsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXZlcnNlID0gVFJVRSksCiAgICAgICAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAtMSkgKwogICAgdGhtICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpCmBgYAoKCiMjIyMgMjAxNiBFbGVjdGlvbiBSZXN1bHRzCgpBbm90aGVyIGV4YW1wbGUgZm9yIGZpbGxlZCBiYXIgY2hhcnRzIGlzIHByb3ZpZGVkIGJ5IDIwMTYgcHJlc2lkZW50aWFsCmVsZWN0aW9uIHJlc3VsdHMgYnkgc3RhdGUuCgpUaGlzIGlzIHByb2R1Y2VkIGJ5IGRlZmF1bHQgc2V0dGluZ3MuCgpUaGUgdmFsdWVzIGZvciBDbGludG9uIGFyZSBlYXN5IHRvIGNvbXBhcmUsIGFzIHRoZXkgYXJlIG9uIGEgY29tbW9uCmJhc2VsaW5lLgoKVGhlIHZhbHVlcyBmb3IgT3RoZXIgYXJlIGFsc28gb24gYSBjb21tb24gYmFzZWxpbmUsIGJ1dCB0aGUKbnVtYmVycyBmb3IgVHJ1bXAgYXJlIG5vdC4KCmBgYHtyIHByZXMyMDE2LWRmbHQsIGUgPSBGQUxTRSwgZmlnLmhlaWdodCA9IDYuNSwgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSJ9CnAgPC0gZ2dwbG90KGdlb2ZhY2V0OjplbGVjdGlvbiwKICAgICAgICAgICAgYWVzKHggPSB2b3RlcywKICAgICAgICAgICAgICAgIHkgPSBzdGF0ZSwKICAgICAgICAgICAgICAgIGZpbGwgPSBjYW5kaWRhdGUpKSArCiAgICBnZW9tX2NvbChwb3NpdGlvbiA9ICJmaWxsIikgKwogICAgc2NhbGVfeF9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwgMCkpICsKICAgIHhsYWIoTlVMTCkgKwogICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMC41LCBsaW5ldHlwZSA9IDIpCnAKYGBgCgpSZW9yZGVyaW5nIHRoZSBjYXRlZ29yaWVzIHB1dHMgYm90aCBDbGludG9uIGFuZCBUcnVtcCBvbiBjb21tb24KYmFzZWxpbmVzIGFuZCBhbHNvIG1hdGNoZXMgdGhlIGNvbW1vbiBjb2xvciB1c2U6CgpgYGB7ciwgZmlnLmhlaWdodCA9IDYuNSwgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSJ9CiMjIG1vdmUgJ090aGVyJyB0byBtaWRkbGUsIGFsaWduIENsaW50b24vVHJ1bXAgd2l0aCBjb2xvcnMKZWxlY3QgPC0KICAgIG11dGF0ZShnZW9mYWNldDo6ZWxlY3Rpb24sCiAgICAgICAgICAgY2FuZGlkYXRlID0gZmFjdG9yKGNhbmRpZGF0ZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYygiVHJ1bXAiLCAiT3RoZXIiLCAiQ2xpbnRvbiIpKSkKcCAlKyUgZWxlY3QKYGBgCgpEaWZmZXJlbnQgb3JkZXJpbmdzIG9mIHRoZSBzdGF0ZXMgY2FuIGJlIHVzZWQgdG8gYWNoaWV2ZSBkaWZmZXJlbnQgZ29hbHMuCgpPcmRlcmluZyBieSBDbGludG9uJ3MgcGVyY2VudGFnZSBtYWtlcyBpdCBlYXNpZXIgdG8gc2VlIHdoZXJlIHNoZSBoYWQKYW4gb3V0cmlnaHQgbWFqb3JpdHkuCgpgYGB7ciwgZmlnLmhlaWdodCA9IDYuNSwgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSJ9CmVsZWN0X3dpZGUgPC0gcGl2b3Rfd2lkZXIoc2VsZWN0KGVsZWN0LCAtdm90ZXMpLAogICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWVzX2Zyb20gPSBjYW5kaWRhdGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVzX2Zyb20gPSBwY3QpCgojIyBvcmRlcmVkIGJ5IENsaW50b24gcGN0CnNsZXZzIDwtIGFycmFuZ2UoZWxlY3Rfd2lkZSwgQ2xpbnRvbikgJT4lCiAgICBwdWxsKHN0YXRlKQpwICUrJSBtdXRhdGUoZWxlY3QsIHN0YXRlID0gZmFjdG9yKHN0YXRlLCBzbGV2cykpCmBgYAoKQW5vdGhlciBwb3NzaWJpbGl0eSBpcyB0byBvcmRlciBieSB3aW5uaW5nIG1hcmdpbiBiZXR3ZWVuIHRoZSB0d28KbWFqb3IgY2FuZGlkYXRlcy4KCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNi41LCBjbGFzcy5zb3VyY2UgPSAiZm9sZC1oaWRlIn0KIyMgb3JkZXJlZCBieSB3aW5uaW5nIG1hcmdpbgpzbGV2cyA8LSBhcnJhbmdlKGVsZWN0X3dpZGUsIENsaW50b24gLSBUcnVtcCkgJT4lCiAgICBwdWxsKHN0YXRlKQpwICUrJSBtdXRhdGUoZWxlY3QsIHN0YXRlID0gZmFjdG9yKHN0YXRlLCBzbGV2cykpCmBgYAoKCiMjIEZhY2V0aW5nCgpGYWNldGluZyBjYW4gYmUgdXNlZCB3aXRoIGRvdCBwbG90cyBhbmQgYmFyIGNoYXJ0cyBhcyB3ZWxsOgoKYGBge3IsIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUifQpnZ3Bsb3QoYmFybGV5KSArCiAgICBnZW9tX3BvaW50KGFlcyh4ID0geWllbGQsCiAgICAgICAgICAgICAgICAgICB5ID0gdmFyaWV0eSwKICAgICAgICAgICAgICAgICAgIGNvbG9yID0geWVhcikpICsKICAgIGZhY2V0X3dyYXAofiBzaXRlKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikKYGBgCgpUaGVzZSBwbG90cyBzaG93IGxvd2VyIHlpZWxkcyBmb3IgMTkzMiB0aGFuIGZvciAxOTMxIGZvciBhbGwgc2l0ZXMKZXhjZXB0IE1vcnJpcy4KCiogQ2xldmVsYW5kIHN1Z2dlc3QgdGhpcyBtYXkgaW5kaWNhdGUgYSBkYXRhIGVudHJ5IGVycm9yIGZvciBNb3JyaXMuCgoqIEEgW3BhcGVyIGZyb20KMjAxNF0oaHR0cHM6Ly9ibG9nLnJldm9sdXRpb25hbmFseXRpY3MuY29tLzIwMTQvMDcvdGhlcmVzLW5vLW1pc3Rha2UtaW4tdGhlLWJhcmxleS1kYXRhLmh0bWwpCnN1Z2dlc3RzIHRoZXJlIG1heSBiZSBubyBlcnJvci4KCgojIyBIZWF0IE1hcHMKCkhlYXQgbWFwcyBlbmNvZGUgYSBudW1lcmljIHZhcmlhYmxlIGFzIHRoZSBjb2xvciBvZiBhIHRpbGUgcGxhY2VkIGF0IGEKcGFydGljdWxhciBwb3NpdGlvbiBpbiBhIGdyaWQuCgpIZWF0IG1hcHMgYXJlIGFsc28gY2FsbGVkIF9tYXRyaXggY2hhcnRzXyBvciBfaW1hZ2UgcGxvdHNfLgoKSGVhdCBtYXBzIGNhbiBiZSBlZmZlY3RpdmUgaW4gY2FzZXMgd2hlcmUgYSBsaW5lIHBsb3QgY29udGFpbnMgdG9vCm11Y2ggb3Zlci1wb3R0aW5nLCBzdWNoIGFzCgpgYGB7ciwgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSJ9CmdtYSA8LSBmaWx0ZXIoZ2FwbWluZGVyLCBjb250aW5lbnQgPT0gIkFtZXJpY2FzIikKZ2dwbG90KGdtYSkgKwogICAgZ2VvbV9saW5lKGFlcyh4ID0geWVhciwKICAgICAgICAgICAgICAgICAgeSA9IGxpZmVFeHAsCiAgICAgICAgICAgICAgICAgIGNvbG9yID0gY291bnRyeSkpICsKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLAogICAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpgYGAKCkEgaGVhdCBtYXAgb2YgdGhlc2UgZGF0YToKCmBgYHtyLCBjbGFzcy5zb3VyY2UgPSAiZm9sZC1oaWRlIn0KZ2dwbG90KGdtYSkgKwogICAgZ2VvbV90aWxlKGFlcyh4ID0geWVhciwKICAgICAgICAgICAgICAgICAgeSA9IHJlb3JkZXIoY291bnRyeSwgbGlmZUV4cCksCiAgICAgICAgICAgICAgICAgIGZpbGwgPSBsaWZlRXhwKSkgKwogICAgc2NhbGVfeF9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwgMCkpICsKICAgIHNjYWxlX2ZpbGxfdmlyaWRpc19jKCkgKwogICAgbGFicyh5ID0gTlVMTCwKICAgICAgICAgZmlsbCA9ICJMaWZlIEV4cGVjdGFuY3kgKHllYXJzKSIpICsKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQpgYGAKCkFnYWluIGl0IGlzIHVzZWZ1bCB0byBjb25zaWRlciByZW9yZGVyaW5nIG9mIGNhdGVnb3JpZXMgd2hlbiB0aGVyZSBpcwpubyBuYXR1cmFsIG9yZGVyLgoKVGhpcyBoZWF0IG1hcCBvcmRlcnMgdGhlIGNvdW50cmllcyBieSBhdmVyYWdlIGxpZmUgZXhwZWN0YW5jeS4KCgojIyBCdWJibGUgQ2hhcnRzCgpBIGZvcm0gb2YgY2hhcnQgb2Z0ZW4gc2VlbiBpbiB0aGUgcG9wdWxhciBwcmVzcyBpcyB0aGUgX2J1YmJsZSBjaGFydF8uCgpUaGUgYnViYmxlIGNoYXJ0IHVzZXMgYXJlcyBvZiBjaXJjbGVzIHRvIHJlcHJlc2VudCBtYWduaXR1ZGVzLgoKUG9zaXRpb24gaW4gdGhlIHBsYW5lIGlzIHVzdWFsbHkgbm90IGZ1bGx5IHVzZWQgb3Igbm90IHVzZWQgYXQgYWxsIGZvcgptYXBwaW5nIGF0dHJpYnV0ZXMuCgpJbiBvbi1saW5lIHB1YmxpY2F0aW9ucyBmdXJ0aGVyIGluZm9ybWF0aW9uIG9uIGVhY2ggb2YgdGhlIGJ1YmJsZXMgaXMKb2Z0ZW4gcHJvdmlkZWQgdGhyb3VnaCBpbnRlcmFjdGlvbnMsIHN1Y2ggYXMgYSBtb3VzZS1vdmVyIHRvb2x0aXAuCgpPdGhlciBjaGFydHMgZm9ybXMgYXJlIGFsbW9zdCBhbHdheXMgYmV0dGVyIGZvciBlbmNvZGluZyB0aGUgbWFnbml0dWRlCmluZm9ybWF0aW9uLgoKSXQgaXMgYWxzbyBlYXN5IHRvIGdldCB0aGUgZW5jb2Rpbmcgd3JvbmcKKFtDb3JyZWN0ZWQgdmVyc2lvbl0oYHIgSU1HKCJzaHJpbmtpbmctYmFua3MtY29ycmVjdC5qcGciKWApKToKCmBgYHtyLCBlY2hvID0gRkFMU0UsIG91dC53aWR0aCA9ICI2MCUifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhJTUcoInNocmlua2luZy1iYW5rcy1vcmlnLmpwZyIpKQpgYGAKCjwhLS0KICBodHRwOi8vd3d3LnBlcmNlcHR1YWxlZGdlLmNvbS9ibG9nLz9wPTE1MzIKICAhW10oaHR0cDovL3d3dy5wZXJjZXB0dWFsZWRnZS5jb20vYmxvZy93cC1jb250ZW50L3VwbG9hZHMvMjAxMy8wMy9zaG93LW1lLWJ1YmJsZXMucG5nKQogIGh0dHA6Ly9qdW5rY2hhcnRzLnR5cGVwYWQuY29tL2p1bmtfY2hhcnRzLzIwMDkvMDEvcG9wcGluZy10aGUtYnViYmxlLXNvLXRvLXNwZWFrLmh0bWwKICBodHRwczovL2ZsaXBjaGFydGZhaXJ5dGFsZXMuZmlsZXMud29yZHByZXNzLmNvbS8yMDA5LzAxL2JhbmtzMjBtYXJrZXQyMGNhcDIwY29ycmVjdDEuanBnCiAgLS0+CgpgZ2dwbG90YCBidWJibGUgY2hhcnRzIGZvciB0aGUgYXZlcmFnZSBgeWllbGRgIHZhbHVlcyBmcm9tIHRoZSBgYmFybGV5YApkYXRhIGFuZCBmb3IgdGhlIDIwMDcgcG9wdWxhdGlvbiBzaXplcyBmb3IgdGhlIGdhcG1pbmRlciBkYXRhOgoKYGBge3IsIGVjaG8gPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFLCBmaWcud2lkdGggPSAxMH0KIyMgZGVyaXZlZCBmcm9tCiMjIGh0dHA6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvMzg5NTkwOTMvcGFja2VkLWJ1YmJsZS1waWUtY2hhcnRzLWluLXIKbGlicmFyeShwYWNrY2lyY2xlcykKY2lyY2xlcyA8LSBmdW5jdGlvbihyYWQyKSB7CiAgICBzdG9waWZub3QoYWxsKHJhZDIgPiAwKSkKICAgIHJhZCA8LSBzcXJ0KHJhZDIpCiAgICBuIDwtIGxlbmd0aChyYWQpCiAgICBsaW0gPC0gbiAqIG1heChyYWQpCiAgICBsaW1zIDwtIGMoLWxpbSwgbGltKQogICAgb2xkLnNlZWQgPC0geyBydW5pZigxKTsgLlJhbmRvbS5zZWVkIH0gIyBub2xpbnQKICAgIHNldC5zZWVkKDEyMzQ1KQogICAgdiA8LSBjaXJjbGVMYXlvdXQoY2JpbmQocnVuaWYobiksIHJ1bmlmKG4pLCByYWQpLCBsaW1zLCBsaW1zKQogICAgLlJhbmRvbS5zZWVkIDwtIG9sZC5zZWVkCiAgICBsYXlvdXRERiA8LSBhcy5kYXRhLmZyYW1lKHYkbGF5b3V0KQogICAgbmFtZXMobGF5b3V0REYpIDwtIGMoIngiLCAieSIsICJyYWRpdXMiKQogICAgbGlzdChsYXlvdXQgPSBsYXlvdXRERiwgZGF0YSA9IGNpcmNsZVBsb3REYXRhKHYkbGF5b3V0KSkKfQpidWJibGVfdGhlbWUgPC0gZnVuY3Rpb24oKSB7CiAgICBsaXN0KGNvb3JkX2VxdWFsKCksCiAgICB0aGVtZV9idygpLAogICAgdGhlbWUoYXhpcy50ZXh0ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpKQp9CgojIyBiYXJsZXkgeWllbGRzCmFic3kgPC0gZ3JvdXBfYnkoYmFybGV5LCBzaXRlLCB5ZWFyKSAlPiUKICAgIHN1bW1hcmlzZShhdmdfeWllbGQgPSBtZWFuKHlpZWxkKSkKCnYgPC0gY2lyY2xlcyhhYnN5JGF2Z195aWVsZCkKdnYgPC0gdiRkYXRhCnZ2JHllYXIgPC0gYWJzeSR5ZWFyW3Z2JGlkXQpwMSA8LSBnZ3Bsb3QodnYpICsKICAgIGdlb21fcG9seWdvbihhZXMoeCwgeSwgZ3JvdXAgPSBpZCwgZmlsbCA9IHllYXIpKSArCiAgICBnZW9tX3RleHQoYWVzKHggPSB4LCB5ID0geSwgbGFiZWwgPSBhYnN5JHNpdGUpLAogICAgICAgICAgICAgIGRhdGEgPSB2JGxheW91dCwgc2l6ZSA9IDEuNSkgKwogICAgYnViYmxlX3RoZW1lKCkKCiMjIGdhcG1pbmRlciBwb3B1bGF0aW9ucyBmb3IgMjAwNzoKbGlicmFyeShnYXBtaW5kZXIpCmxpYnJhcnkocGF0Y2h3b3JrKQpnbTIwMDcgPC0gZmlsdGVyKGdhcG1pbmRlciwgeWVhciA9PSAyMDA3KQp2IDwtIGNpcmNsZXMoZ20yMDA3JHBvcCkKdnYgPC0gdiRkYXRhCnZ2JGNvbnRpbmVudCA8LSBnbTIwMDckY29udGluZW50W3Z2JGlkXQpwMiA8LSBnZ3Bsb3QodnYpICsKICAgIGdlb21fcG9seWdvbihhZXMoeCwgeSwgZ3JvdXAgPSBpZCwgZmlsbCA9IGNvbnRpbmVudCkpICsgY29vcmRfZXF1YWwoKSArCiAgICBidWJibGVfdGhlbWUoKQoKIyNncmlkLmFycmFuZ2UocDEsIHAyLCBucm93ID0gMSkKcDEgKyBwMgpgYGAKCgojIyBXYXRlcmZhbGwgQ2hhcnRzCgpBbHNvIGNhbGxlZCBfY2FzY2FkZSBjaGFydHNfLgoKVGhlc2UgdXN1YWxseSBzaG93IHRoZSBkZWNvbXBvc2l0aW9uIG9mIGEgdG90YWwgaW50byBwb3NpdGl2ZSBhbmQKbmVnYXRpdmUgY29udHJpYnV0aW9ucyBmcm9tIHZhcmlvdXMgc291cmNlcy4KCjwhLS0gRmlnIDYuNyBmcm9tIEFuZHkgS2lyaydzIF9EYXRhIFZpc3VhbGl6YXRpb24sIDJuZCBFZC5fIC0tPgoKTmV3IFplYWxhbmQgbmV0IGltbWlncmF0aW9uIGJ5IHJlZ2lvbjoKCmBgYHtyLCBlY2hvID0gRkFMU0UsIG91dC53aWR0aCA9ICI3MCUifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhJTUcoIjYuNy5XYXRlcmZhbGwucG5nIikpCmBgYAoKSW50ZXJuZXQgc3Vic2NyaWJlcnMgYnkgbW9udGggKFtibG9nIHBvc3Qgd2l0aCBgZ2dwbG90YApjb2RlXShodHRwczovL3dlYi5hcmNoaXZlLm9yZy93ZWIvMjAxOTA2MjIyMTE5MzgvaHR0cDovL2FuaGhvYW5nZHVjLmNvbS9ibG9nL2NyZWF0ZS13YXRlcmZhbGwtY2hhcnQtd2l0aC1nZ3Bsb3QyLykpLgoKYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0LndpZHRoID0gIjY1JSJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKElNRygid2F0ZXJmYWxsLnBuZyIpKQpgYGAKICAKCgojIyBQb2xhciBBcmVhIENoYXJ0cwoKRmxvcmVuY2UgTmlnaHRpbmdhbGUncyBmYW1vdXMgY2hhcnQgc2hvd2luZyB0aGUgZWZmZWN0IG9mIHRoZQpzYW5pdGF0aW9uIGltcHJvdmVtZW50cyBpbiBNYXJjaC9BcHJpbCAxODU1OgoKPCEtLSBodHRwczovL3VuZGVyc3RhbmRpbmd1bmNlcnRhaW50eS5vcmcvZmlsZXMvQ294Y29tYnMuanBnIC0tPgpgYGB7ciwgZWNobyA9IEZBTFNFLCBvdXQud2lkdGggPSAiOTUlIn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoSU1HKCJDb3hjb21icy5qcGciKSkKYGBgCgpUaGlzIGNoYXJ0IGhhcyBiZWVuIGNhbGxlZCBhIF9wb2xhciBhcmVhIGRpYWdyYW1zXyBvciBhIF9Db3hjb21iCkNoYXJ0Xy4KCkl0IGNhbiBiZSB2aWV3ZWQgYXMKCiogYSBiYXIgY2hhcnQgd2l0aCB0aGUgYmFycyBwb3NpdGlvbmVkIGluIGZyb250IG9mIGVhY2ggb3RoZXIsCgoqIHRyYW5zZm9ybWVkIHRvIHBvbGFyIGNvb3JkaW5hdGVzLAoKKiB3aXRoIG1hZ25pdHVkZSBtYXBwZWQgdG8gYXJlYSAoaS5lLiBzcXVhcmUgcm9vdCBvZiBtYWduaXR1ZGUKICBtYXBwZWQgdG8gcmFkaXVzKS4KClRoZSBkYXRhIGFyZSBhdmFpbGFibGUgaW4gdGhlIGBIaXN0RGF0YWAgcGFja2FnZSBhcyBkYXRhIGZyYW1lIGBOaWdodGluZ2FsZWAuCgpTb21lIHJlYXJyYW5nZW1lbnQgb2YgdGhlIGRhdGEgaXMgbmVlZGVkIHRvIGdldCBpdCBpbnRvIGEgZm9ybQphbWVuYWJsZSBmb3IgcGxvdHRpbmcuCgpgYGB7ciwgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSJ9CmxpYnJhcnkoZm9yY2F0cykKZGF0YShOaWdodGluZ2FsZSwgcGFja2FnZSA9ICJIaXN0RGF0YSIpCk5pZ2h0IDwtCiAgICBtdXRhdGUoTmlnaHRpbmdhbGUsCiAgICAgICAgICAgUGVyaW9kID0KICAgICAgICAgICAgICAgaWZlbHNlKERhdGUgPCBhcy5EYXRlKCIxODU1LTA0LTAxIiksCiAgICAgICAgICAgICAgICAgICAgICAiQmVmb3JlIiwKICAgICAgICAgICAgICAgICAgICAgICJBZnRlciIpLAogICAgICAgICAgIFBlcmlvZCA9CiAgICAgICAgICAgICAgIGZhY3RvcihQZXJpb2QsIGMoIkJlZm9yZSIsICJBZnRlciIpKSwKICAgICAgICAgICBNb250aCA9IGZhY3RvcihNb250aCwgbW9udGguYWJiKSkgJT4lCiAgICBzZWxlY3QoRGF0ZSwgTW9udGgsIFllYXIsIFBlcmlvZCwKICAgICAgICAgICBEaXNlYXNlLCBXb3VuZHMsIE90aGVyKSAlPiUKICAgIHBpdm90X2xvbmdlcig1IDogNywKICAgICAgICAgICAgICAgICBuYW1lc190byA9ICJDYXVzZSIsCiAgICAgICAgICAgICAgICAgdmFsdWVzX3RvID0gIkRlYXRocyIpCgojIyBSZWFycmFuZ2UgdGhlIE1vbnRoIGxldmVscyB0byBzdGFydCB3aXRoIEFwcmlsLgpOaWdodDMgPC0gbXV0YXRlKE5pZ2h0LCBNb250aCA9IGZjdF9zaGlmdChNb250aCwgMykpCmBgYAoKQSBzdGFuZGFyZCBzdGFja2VkIGJhciBjaGFydCBvZiB0aGUgZGF0YToKCmBgYHtyLCBmaWcud2lkdGggPSA4LCBjbGFzcy5zb3VyY2UgPSAiZm9sZC1oaWRlIn0KZ2dwbG90KE5pZ2h0MywKICAgICAgIGFlcyh4ID0gTW9udGgsIHkgPSBEZWF0aHMsIGZpbGwgPSBDYXVzZSkpICsKICAgIGdlb21fY29sKCkgKwogICAgZmFjZXRfd3JhcCh+IFBlcmlvZCkgKwogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpCmBgYAoKQSBncm91cGVkIGJhciBjaGFydCBvZiB0aGUgZGF0YToKCmBgYHtyLCBmaWcud2lkdGggPSA4LCBjbGFzcy5zb3VyY2UgPSAiZm9sZC1oaWRlIn0KZ2dwbG90KE5pZ2h0MywKICAgICAgIGFlcyh4ID0gTW9udGgsIHkgPSBEZWF0aHMsIGZpbGwgPSBDYXVzZSkpICsKICAgIGdlb21fY29sKHBvc2l0aW9uID0gImRvZGdlIikgKwogICAgZmFjZXRfd3JhcCh+IFBlcmlvZCkgKwogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpCmBgYAoKVXNpbmcgYHBvc2l0aW9uID0gImlkZW50aXR5ImAgdGhlIGJhcnMgd2lsbCBiZSBwbGFjZWQgaW4gZnJvbnQgb2YgZWFjaCBvdGhlcgpyYXRoZXIgdGhhbiBzaWRlIGJ5IHNpZGUgb3Igc3RhY2tlZC4KCmBgYHtyLCBmaWcud2lkdGggPSA4LCBjbGFzcy5zb3VyY2UgPSAiZm9sZC1oaWRlIn0KcCA8LSBnZ3Bsb3QoTmlnaHQzLAogICAgICAgICAgICBhZXMoeCA9IE1vbnRoLCB5ID0gRGVhdGhzLCBmaWxsID0gQ2F1c2UpKSArCiAgICBnZW9tX2NvbChwb3NpdGlvbiA9ICJpZGVudGl0eSIsICMjIGJhcnMgaW4gZnJvbnQgb2YgZWFjaCBvdGhlcgogICAgICAgICAgICAgd2lkdGggPSAxLCAgICAgICAgICAgICAjIyByZW1vdmUgc3BhY2UgYmV0d2VlbiBiYXJzCiAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIsICAgICAgICMjIGJhciBib3JkZXIgY29sb3IKICAgICAgICAgICAgIGxpbmV3aWR0aCA9IDAuMSkgKyAgICAgIyMgYmFyIGJvcmRlciB0aGlja25lc3MKICAgIGZhY2V0X3dyYXAofiBQZXJpb2QpICsKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQpwCmBgYAoKUHJvYmxlbTogTGFyZ2VyIGJhcnMgbWF5IGJlIHBsYWNlZCBpbiBmcm9udCBvZiBzbWFsbGVyIG9uZXMuCgpSZW9yZGVyaW5nIHRoZSBgRGVhdGhzYCB2YWx1ZXMgZnJvbSBsYXJnZXN0IHRvIHNtYWxsZXN0IGVuc3VyZXMgdGhhdApsYXJnZXIgYmFycyBkbyBub3QgY292ZXIgc21hbGxlciBvbmVzLgoKYGBge3IsIGZpZy53aWR0aCA9IDgsIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUifQpwIDwtIGdncGxvdChhcnJhbmdlKE5pZ2h0MywgZGVzYyhEZWF0aHMpKSwKICAgICAgICAgICAgYWVzKHggPSBNb250aCwgeSA9IERlYXRocywgZmlsbCA9IENhdXNlKSkgKwogICAgZ2VvbV9jb2wocG9zaXRpb24gPSAiaWRlbnRpdHkiLCAjIyBiYXJzIGluIGZyb250IG9mIGVhY2ggb3RoZXIKICAgICAgICAgICAgIHdpZHRoID0gMSwgICAgICAgICAgICAgIyMgcmVtb3ZlIHNwYWNlIGJldHdlZW4gYmFycwogICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLCAgICAgICAjIyBiYXIgYm9yZGVyIGNvbG9yCiAgICAgICAgICAgICBsaW5ld2lkdGggPSAwLjEpICsgICAgICMjIGJhciBib3JkZXIgdGhpY2tuZXNzCiAgICBmYWNldF93cmFwKH4gUGVyaW9kKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikKcApgYGAKCkNoYW5naW5nIHRvIHBvbGFyIGNvb3JkaW5hdGVzIGFuZCBtYXBwaW5nIHNxdWFyZSByb290cyBvZiBgRGVhdGhzYCB0bwpyYWRpdXMgcHJvZHVjZXMgdGhlIGJhc2ljIHBvbGFyIGFyZWEgY2hhcnQ6CgpgYGB7ciwgZmlnLndpZHRoID0gOCwgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSJ9CnAgJSslIChhcnJhbmdlKE5pZ2h0MywgZGVzYyhEZWF0aHMpKSAlPiUKICAgICAgIG11dGF0ZShEZWF0aHMgPSBzcXJ0KERlYXRocykpKSArCiAgICBjb29yZF9wb2xhcigpCmBgYAoKU29tZSBhZGp1c3RtZW50cyBicmluZyB0aGUgcmVzdWx0IGNsb3NlciB0byB0aGUgb3JpZ2luYWw6CgpgYGB7ciwgZmlnLndpZHRoID0gOH0KcCAlKyUKICAgIChhcnJhbmdlKE5pZ2h0LCBkZXNjKERlYXRocykpICU+JQogICAgIG11dGF0ZShNb250aCA9IGZjdF9zaGlmdChNb250aCwgNiksCiAgICAgICAgICAgIFBlcmlvZCA9IGZhY3RvcihQZXJpb2QsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjKCJBZnRlciIsICJCZWZvcmUiKSksCiAgICAgICAgICAgIERlYXRocyA9IHNxcnQoRGVhdGhzKSkpICsKICAgIGNvb3JkX3BvbGFyKCkgKwogICAgc2NhbGVfZmlsbF9tYW51YWwoCiAgICAgICAgdmFsdWVzID0gYyhXb3VuZHMgPSAicGluayIsCiAgICAgICAgICAgICAgICAgICBPdGhlciA9ICJkYXJrZ3JheSIsCiAgICAgICAgICAgICAgICAgICBEaXNlYXNlID0gImxpZ2h0Ymx1ZSIpKSArCiAgICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICBheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X2JsYW5rKCkpCmBgYAoKCiMjIEJhc2UgYW5kIExhdHRpY2UgR3JhcGhpY3MKCkJhc2UgZ3JhcGhpY3MgcHJvdmlkZXMgdGhlIGBkb3RjaGFydCgpYCBmdW5jdGlvbiBmb3IgY3JlYXRpbmcgZG90IHBsb3RzOgoKYGBge3IsIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUifQp3aXRoKGxlX2FtXzIwMDcsCiAgICAgZG90Y2hhcnQoc29ydChsaWZlRXhwKSwKICAgICAgICAgICAgICBsYWJlbHMgPSBjb3VudHJ5W29yZGVyKGxpZmVFeHApXSkpCmBgYAoKVGhlIGBsYXR0aWNlYCBwYWNrYWdlIHByb3ZpZGVzIGBkb3RwbG90KClgOgpgYGB7ciwgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSJ9CmxpYnJhcnkobGF0dGljZSkKZG90cGxvdChyZW9yZGVyKGNvdW50cnksIGxpZmVFeHApIH4gbGlmZUV4cCwKICAgICAgICBkYXRhID0gbGVfYW1fMjAwNykKYGBgCgpNb3N0IGxhdHRpY2UgcGxvdHMgc3VwcG9ydCBhIGBncm91cGAgYXJndW1lbnQgdGhhdCBpcyB1c3VhbGx5IG1hcHBlZAp0byBjb2xvcjoKCmBgYHtyLCBjbGFzcy5zb3VyY2UgPSAiZm9sZC1oaWRlIn0KZG90cGxvdChyZW9yZGVyKGNvdW50cnksIGxpZmVFeHApIH4gbGlmZUV4cCwKICAgICAgICBncm91cCA9IHllYXIsIGRhdGEgPSBsZTIsIGF1dG8ua2V5ID0gVFJVRSkKYGBgCgpDcmVhdGluZyBhIGJhc2ljIGJhciBjaGFydCBpbiBgbGF0dGljZWAgdXNlcyB0aGUgYGJhcmNoYXJ0KClgIGZ1bmN0aW9uLgoKYGBge3IsIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUifQojIyBCeSBkZWZhdWx0IGxhdHRpY2UgY3JlYXRlcyBhIGJhZCBiYXIgY2hhcnQgd2l0aCBhCiMjIG5vbi16ZXJvIGJhc2UgbGluZSBmb3IgdGhlc2UgZGF0YS4gRml4IHRoYXQgYnkKIyMgc3BlY2lmeWluZyB4bGltID0gYygwLCA4NSkuCmJhcmNoYXJ0KHJlb3JkZXIoY291bnRyeSwgbGlmZUV4cCkgfiBsaWZlRXhwLAogICAgICAgICBkYXRhID0gbGVfYW1fMjAwNywgeGxpbSA9IGMoMCwgODUpKQpgYGAKCkJhc2UgZ3JhcGhpY3MgYWxzbyBwcm92aWRlcyBhIGJhciBjaGFydCB3aXRoIHRoZSBgYmFycGxvdCgpYCBmdW5jdGlvbi4KCmBgYHtyLCBjbGFzcy5zb3VyY2UgPSAiZm9sZC1oaWRlIn0KcGFyKG1hciA9IGMoNSwgNSwgNCwgMikgKyAwLjEpCndpdGgobGVfYW1fMjAwNywKICAgICBiYXJwbG90KHNvcnQobGlmZUV4cCksCiAgICAgICAgICAgICBob3JpeiA9IFRSVUUsCiAgICAgICAgICAgICBuYW1lcy5hcmcgPSBjb3VudHJ5W29yZGVyKGxpZmVFeHApXSwKICAgICAgICAgICAgIGxhcyA9IDEsCiAgICAgICAgICAgICBjZXgubmFtZXMgPSAwLjcsCiAgICAgICAgICAgICBjZXguYXhpcyA9IDAuNykpCmBgYAoKCiMjIFJlYWRpbmcKCkNoYXB0ZXIgW19WaXN1YWxpemluZwogIGFtb3VudHNfXShodHRwczovL2NsYXVzd2lsa2UuY29tL2RhdGF2aXovdmlzdWFsaXppbmctYW1vdW50cy5odG1sKQogIGluIFtfRnVuZGFtZW50YWxzIG9mIERhdGEKICBWaXN1YWxpemF0aW9uX10oaHR0cHM6Ly9jbGF1c3dpbGtlLmNvbS9kYXRhdml6LykuCgoKIyMgSW50ZXJhY3RpdmUgVHV0b3JpYWwKCkFuIGludGVyYWN0aXZlIFtgbGVhcm5yYF0oaHR0cHM6Ly9yc3R1ZGlvLmdpdGh1Yi5pby9sZWFybnIvKSB0dXRvcmlhbApmb3IgdGhlc2Ugbm90ZXMgaXMgW2F2YWlsYWJsZV0oYHIgV0xOSygidHV0b3JpYWxzL2Ftb3VudHMuUm1kIilgKS4KCllvdSBjYW4gcnVuIHRoZSB0dXRvcmlhbCB3aXRoCgpgYGB7ciwgZXZhbCA9IEZBTFNFfQpTVEFUNDU4MDo6cnVuVHV0b3JpYWwoImFtb3VudHMiKQpgYGAKCllvdSBjYW4gaW5zdGFsbCB0aGUgY3VycmVudCB2ZXJzaW9uIG9mIHRoZSBgU1RBVDQ1ODBgIHBhY2thZ2Ugd2l0aAoKYGBge3IsIGV2YWwgPSBGQUxTRX0KcmVtb3Rlczo6aW5zdGFsbF9naXRsYWIoImx1a2UtdGllcm5leS9TVEFUNDU4MCIpCmBgYAoKWW91IG1heSBuZWVkIHRvIGluc3RhbGwgdGhlIGByZW1vdGVzYCBwYWNrYWdlIGZyb20gQ1JBTiBmaXJzdC4KCgojIyBFeGVyY2lzZXMKCjEuIEEgcGxvdCBzaW1pbGFyIHRvIHRoaXMgd2FzIGZlYXR1cmVkIGluIGEgQ05OIG5ld3Mgc3Rvcnkgc2V2ZXJhbCB5ZWFycyBhZ286CgogICAgYGBge3IsIGVjaG8gPSBGQUxTRX0KICAgIGxpYnJhcnkoZ2dwbG90MikKICAgIGxldnMgPC0gYygiRGVtb2NyYXRzIiwgIlJlcHViaWNhbnMiLCAiSW5kZXBlbmRlbnRzIikKICAgIGQgPC0gZGF0YS5mcmFtZShwYXJ0eSA9IGZhY3RvcihsZXZzLCBsZXZzKSwKICAgICAgICAgICAgICAgICAgICBwY3QgPSBjKDYyLCA1NCwgNTQpKQoKICAgIGdncGxvdChkLCBhZXMoeCA9IHBhcnR5LCB5ID0gcGN0IC0gNTApKSArCiAgICAgICAgZ2VvbV9jb2wod2lkdGggPSAwLjUpICsKICAgICAgICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2VxKDUwLCA2NCwgYnkgPSAyKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gc2VxKDAsIDE0LCBieSA9IDIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICBleHBhbmQgPSBleHBhbnNpb24oYygwLCAwLjE4KSkpICsKICAgICAgICBsYWJzKHggPSAiUG9saXRpY2FsIFBhcnR5IiwKICAgICAgICAgICAgIHkgPSBOVUxMLAogICAgICAgICAgICAgdGl0bGUgPSAiUGVyY2VudCBXaG8gQWdyZWVkIFdpdGggQ291cnQiKSArCiAgICAgICAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMjAsIGZhY2UgPSAiYm9sZCIpLAogICAgICAgICAgICAgIHBhbmVsLmdyaWQubWlub3IueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICBwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgcGFuZWwuZ3JpZC5taW5vci55ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgIHBhbmVsLmdyaWQubWFqb3IueSA9IGVsZW1lbnRfbGluZShjb2xvciA9ICJibGFjayIpLAogICAgICAgICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJncmV5IiwgY29sb3IgPSBOQSksCiAgICAgICAgICAgICAgcGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAid2hpdGUiLCBjb2xvciA9ICJibGFjayIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpbmV3aWR0aCA9IDIpLAogICAgICAgICAgICAgIHBsb3QubWFyZ2luID0gbWFyZ2luKDIwLCAyMCwgMjAsIDIwKSkgKwogICAgICAgIGNvb3JkX2ZpeGVkKDAuMSkKICAgIGBgYAoKICAgIFdoaWNoIG9mIHRoZSBmb2xsb3dpbmcgaXMgYXBwcm94aW1hdGVseSBjb3JyZWN0OgogICAgCiAgICAtIEFib3V0IHRoZSBzYW1lIG51bWJlciBvZiBkZW1vY3JhdHMgYXMgcmVwdWJsaWNhbnMgYWdyZWVkIHdpdGgKICAgICAgdGhlIGNvdXJ0LgogICAgLSBBYm91dCAxNSUgbW9yZSBkZW1vY3JhdHMgdGhhbiByZXB1YmxpY2FucyBhZ3JlZWQgd2l0aCB0aGUgY291cnQuCiAgICAtIEFib3V0IHRyZWUgdGltZXMgYXMgbWFueSBkZW1vY3JhdHMgdGhhbiByZXB1YmxpY2FucyBhZ3JlZWQgd2l0aAogICAgICB0aGUgY291cnQuCiAgICAtIEFib3V0IHR3byB0aW1lcyBhcyBtYW55IGRlbW9jcmF0cyB0aGFuIHJlcHVibGljYW5zIGFncmVlZCB3aXRoCiAgICAgIHRoZSBjb3VydC4KCjIuIENvbnNpZGVyIHRoZSBzdGFja2VkIGJhciBjaGFydCBwcm9kdWNlZCBieSB0aGUgZm9sbG93aW5nIGNvZGU6CgogICAgYGBge3IsIGV2YWwgPSBGQUxTRSwgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyJ9CiAgICBsaWJyYXJ5KHRpZHl2ZXJzZSkKICAgIG1wZzIgPC0gbXV0YXRlKG1wZywKICAgICAgICAgICAgICAgICAgIGNsYXNzID0gZmN0X3JldihmY3RfaW5mcmVxKGNsYXNzKSksCiAgICAgICAgICAgICAgICAgICBjeWwgPSBmYWN0b3IoY3lsKSkKICAgIHAgPC0gZ2dwbG90KG1wZzIsIGFlcyh5ID0gY2xhc3MsIGZpbGwgPSBjeWwpKSArCiAgICAgICAgZ2VvbV9iYXIoKQogICAgYGBgCgogICAgV2hpY2ggb2YgdGhlc2UgbW9kaWZpY2F0aW9ucyBtYWtlcyBpdCBlYXNpZXN0IHRvIGNvbXBhcmUgdGhlIGNvdW50CiAgICBvZiA0LWN5bGluZGVyIG1vZGVscyB3aXRoaW4gdGhlIGRpZmZlcmVudCBjbGFzc2VzPwogICAgCiAgICBhLiBgcCAlKyUgbXV0YXRlKG1wZzIsIGN5bCA9IGZhY3RvcihjeWwsIGMoNCwgNSwgNiwgOCkpKWAKICAgIGIuIGBwICUrJSBtdXRhdGUobXBnMiwgY3lsID0gZmFjdG9yKGN5bCwgYyg4LCA2LCA1LCA0KSkpYAogICAgYy4gYHAgJSslIG11dGF0ZShtcGcyLCBjeWwgPSBmYWN0b3IoY3lsLCBjKDUsIDYsIDQsIDgpKSlgCiAgICBkLiBgcCAlKyUgbXV0YXRlKG1wZzIsIGN5bCA9IGZhY3RvcihjeWwsIGMoNCwgNiwgOCwgNSkpKWAKCjMuIFRoZSBiYXIgY2hhcnQgcHJvZHVjZWQgYnkgdGhlIGZvbGxvd2luZyBjb2RlIGhhcyBgeGAgYXhpcyBsYWJlbHMKICAgdGhhdCBjb3VsZCBiZSBpbXByb3ZlZDoKCiAgICBgYGB7ciwgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyJ9CiAgICBsaWJyYXJ5KGdhcG1pbmRlcikKICAgIGxpYnJhcnkoZHBseXIpCiAgICBsaWJyYXJ5KGdncGxvdDIpCiAgICBsaWJyYXJ5KHNjYWxlcykKICAgIHAgPC0gZmlsdGVyKGdhcG1pbmRlciwgeWVhciA9PSAyMDA3KSAlPiUKICAgICAgICBncm91cF9ieShjb250aW5lbnQpICU+JQogICAgICAgIHN1bW1hcml6ZShhdmdHZHBQZXJjYXAgPSBtZWFuKGdkcFBlcmNhcCkpICU+JQogICAgICAgIGdncGxvdChhZXMoeCA9IGF2Z0dkcFBlcmNhcCwgeSA9IGNvbnRpbmVudCkpICsKICAgICAgICBnZW9tX2NvbCgpICsKICAgICAgICAgICAgbGFicyh4ID0gIkF2ZXJhZ2UgR0RQIFBlciBDYXBpdGEiLCB5ID0gTlVMTCkgKwogICAgICAgICAgICB0aGVtZV9taW5pbWFsKCkgKyB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNikpCiAgICBgYGAKCiAgICBUaGVyZSBhcmUgYSBudW1iZXIgb2YgZGlmZmVyZW50IG9wdGlvbnMuIFdoaWNoIG9mIHRoZSBmb2xsb3dpbmcKICAgIGRvZXMgKipub3QqKiBwcm92aWRlIGltcHJvdmVkIGB4YCBheGlzIGxhYmVscz8KCiAgICBhLiBgcCArIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBsYWJlbF9jb21tYSgpKWAKICAgIGIuIGBwICsgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IGxhYmVsX2RvbGxhcigpKWAKICAgIGMuIGBwICsgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHVuaXRfZm9ybWF0KHNjYWxlID0gMS8xMDAwLCB1bml0ID0gIksiLCBwcmVmaXggPSAiJCIpKWAKICAgIGQuIGBwICsgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IGMoIiQxMCwwMDAiLCAiJDIwLDAwMCIsICIkMzAsMDAwIikpYAoKNC4gQSBzdGFja2VkIGJhciBjaGFydCBpcyBhcHByb3ByaWF0ZSBpZiB0aGUgY29tYmluZWQgYmFyIGhlaWdodHMgb2YKICAgdGhlIHN0YWNrZWQgYmFycyBoYXZlIGEgcmVhc29uYWJsZSBpbnRlcnByZXRhdGlvbi4gQ29uc2lkZXIgdGhlCiAgIGZvbGxvd2luZyB0d28gcGxvdHM6CgoKICAgIGBgYHtyLCBmaWcuaGVpZ2h0ID0gNCwgZmlnLndpZHRoID0gOH0KICAgIGxpYnJhcnkoZ2FwbWluZGVyKQogICAgbGlicmFyeShkcGx5cikKICAgIGxpYnJhcnkoZ2dwbG90MikKICAgIGxpYnJhcnkocGF0Y2h3b3JrKQogICAgcDEgPC0gZmlsdGVyKGdhcG1pbmRlciwgeWVhciA+PSAyMDAwKSAlPiUKICAgICAgICBncm91cF9ieShjb250aW5lbnQsIHllYXIpICU+JQogICAgICAgIHN1bW1hcml6ZShhdmdMaWZlRXhwID0gbWVhbihsaWZlRXhwKSwgLmdyb3VwcyA9ICJkcm9wIikgJT4lCiAgICAgICAgZ2dwbG90KGFlcyh4ID0gYXZnTGlmZUV4cCwgeSA9IGNvbnRpbmVudCwgZmlsbCA9IGZhY3Rvcih5ZWFyKSkpICsKICAgICAgICBnZW9tX2NvbCgpICsKICAgICAgICB0aGVtZV9taW5pbWFsKCkgKwogICAgICAgIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSkgKwogICAgICAgIHNjYWxlX3hfY29udGludW91cyhleHBhbmQgPSBleHBhbnNpb24obXVsdCA9IGMoMCwgLjEpKSkgKwogICAgICAgIGxhYnMoeCA9ICJBdmVyYWdlIExpZmUgRXhwZWN0YW5jeSIsCiAgICAgICAgICAgICB5ID0gTlVMTCwKICAgICAgICAgICAgIGZpbGwgPSAiWWVhciIsCiAgICAgICAgICAgICB0aXRsZSA9ICJBdmVyYWdlIExpZmUgRXhwZWN0YW5jeVxuYnkgQ29udGluZW50IGZvciBUd28gWWVhcnMiLAogICAgICAgICAgICAgdGFnID0gIlAxOiIpCiAgICBwMiA8LSBjb3VudChtcGcsIGNsYXNzLCBjeWwpICU+JQogICAgICAgIGdncGxvdChhZXMoeCA9IG4sIHkgPSBjbGFzcywgZmlsbCA9IGZhY3RvcihjeWwpKSkgKwogICAgICAgIGdlb21fY29sKCkgKwogICAgICAgIHRoZW1lX21pbmltYWwoKSArCiAgICAgICAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpKSArCiAgICAgICAgc2NhbGVfeF9jb250aW51b3VzKGV4cGFuZCA9IGV4cGFuc2lvbihtdWx0ID0gYygwLCAuMSkpKSArCiAgICAgICAgbGFicyh4ID0gIk51bWJlciBvZiBNb2RlbHMiLAogICAgICAgICAgICAgeSA9IE5VTEwsCiAgICAgICAgICAgICBmaWxsID0gIkN5bGluZGVycyIsCiAgICAgICAgICAgICB0aXRsZSA9ICJOdW1iZXIgb2YgQ2FyIE1vZGVsc1xuYnkgQ2xhc3MgYW5kIEN5bGluZGVyIENvdW50IiwKICAgICAgICAgICAgIHRhZyA9ICJQMjoiKQogICAgcDEgKyBwMgogICAgYGBgCgogICAgV2hpY2ggb2YgdGhlIGZvbGxvd2luZyBzdGF0ZW1lbnRzIGlzIHRydWU6CgogICAgYS4gUDEgaXMgYW4gYXBwcm9wcmlhdGUgdXNlIG9mIGEgc3RhY2tlZCBiYXIgY2hhcnQgYnV0IFAyIGlzIG5vdC4KICAgIGIuIFAyIGlzIGFuIGFwcHJvcHJpYXRlIHVzZSBvZiBhIHN0YWNrZWQgYmFyIGNoYXJ0IGJ1dCBQMSBpcyBub3QuCiAgICBjLiBOZWl0aGVyIFAxIG5vciBQMiBpcyBhbiBhcHByb3ByaWF0ZSB1c2Ugb2YgYSBzdGFja2VkIGJhciBjaGFydC4KICAgIGQuIEJvdGggUDEgYW5kIFAyIGFyZSBhcHByb3ByaWF0ZSB1c2VzIG9mIGEgc3RhY2tlZCBiYXIgY2hhcnQuCg==