Introduction
Exploring ggplot2
, part 1
To get a first feel for ggplot2
, let’s try to run some basic ggplot2
commands. Together, they build a plot of the mtcars
dataset that contains information about 32 cars from a 1973 Motor Trend magazine. This dataset is small, intuitive, and contains a variety of continuous and categorical variables.
Instructions
- Load the
ggplot2
package using library()
.
- Use
str()
to explore the structure of the mtcars
dataset.
- Execute the example code below. See if you can understand what ggplot does with the data.
Exploring ggplot2
, part 2
The plot from the previous exercise wasn’t really satisfying. Although cyl
(the number of cylinders) is categorical, it is classified as numeric in mtcars
. You’ll have to explicitly tell ggplot2
that cyl
is a categorical variable.
Instructions
- Change the
ggplot()
command by wrapping factor()
around cyl
.
- Executer and see if the resulting plot is better this time.
Exploring ggplot2
, part 3
We’ll use several datasets throughout the courses to showcase the concepts discussed in the videos. In the previous exercises, you already got to know mtcars
. Let’s dive a little deeper to explore the three main topics in this course: The data, aesthetics, and geom layers.
The mtcars
dataset contains information about 32 cars from 1973 Motor Trend magazine. This dataset is small, intuitive, and contains a variety of continuous and categorical variables.
You’re encouraged to think about how the examples and concepts we discuss throughout these data viz courses apply to your own data-sets!
Instructions
ggplot2
has already been loaded for you. Take a look at the first command. It plots the mpg
(miles per galon) against the weight
(in thousands of pounds). You don’t have to change anything about this command.
- In the second call of
ggplot()
change the color
argument in aes()
(which stands for aesthetics). The color should be dependent on the displacement of the car engine, found in disp
.
- In the third call of
ggplot()
change the size
argument in aes()
(which stands for aesthetics). The size should be dependent on the displacement of the car engine, found in disp
.
Understanding Variables
In the previous exercise you saw that disp
can be mapped onto a color gradient or onto a continuous size scale.
Another argument of aes()
is the shape of the points. There are a finite number of shapes which ggplot()
can automatically assign to the points. However, if you try this command in the console to the right:
It gives an error. What does this mean?
Instructions
Possible Answers
- shape is not a defined argument.
- shape only makes sense with categorical data, and disp is continuous.
- shape only makes sense with continuous data, and disp is categorical.
- shape is not a variable in your dataset.
- shape has to be defined as a function.
Exploring ggplot2
, part 4
The diamonds
data frame contains information on the prices and various metrics of 50,000 diamonds. Among the variables included are carat
(a measurement of the size of the diamond) and price. For the next exercises, you’ll be using a subset of 1,000 diamonds.
Here you’ll use two common geom layer functions: geom_point()
and geom_smooth()
. We already saw in the earlier exercises how these are added using the +
operator.
Instructions
- Explore the
diamonds
data frame with the str()
function.
- Use the
+
operator to add geom_point()
to the first ggplot()
command. This will tell ggplot2
to draw points on the plot.
- Use the
+
operator to add geom_point()
and geom_smooth()
. These just stack on each other! geom_smooth()
will draw a smoothed line over the points.
Exploring ggplot2
, part 5
The code for last plot of the previous exercise is available in the script on the right. It builds a scatter plot of the diamonds
dataset, with carat
on the x-axis and price
on the y-axis. geom_smooth()
is used to add a smooth line.
With this plot as a starting point, let’s explore some more possibilities of combining geoms.
Instructions
- Plot 2 - Copy and paste plot 1, but show only the smooth line, no points.
- Plot 3 - Show only the smooth line, but color according to clarity by placing the argument
color = clarity
in the aes()
function of your ggplot()
call.
- Plot 4 - Draw translucent colored points.
- Copy the
ggplot()
command from plot 3 (with clarity
mapped to color
).
- Remove the smooth layer.
- Add the points layer back in.
- Set
alpha = 0.4
inside geom_point()
. This will make the points 40% transparent.
Understanding the grammar, part 1
Here you’ll explore some of the different grammatical elements. Throughout this course, you’ll discover how they can be combined in all sorts of ways to develop unique plots.
In the following instructions, you’ll start by creating a ggplot
object from the diamonds dataset. Next, you’ll add layers onto this object to build beautiful & informative plots.
Instructions
- Define the data (
diamonds
) and aesthetics layers. Map carat
on the x axis and price
on the y axis. Assign it to an object: dia_plot
.
- Using
+
, add a geom_point()
layer (with no arguments), to the dia_plot
object. This can be in a single or multiple lines.
- Note that you can also call
aes()
within the geom_point()
function. Map clarity
to the color
argument in this way.
Understanding the grammar, part 2
Continuing with the previous exercise, here you’ll explore mixing arguments and aesthetics in a single geometry.
You’re still working on the diamonds
dataset.
Instructions
- The
dia_plot
object has been created for you.
- Update
dia_plot
so that it contains all the functions to make a scatter plot by using geom_point()
for the geom layer. Set alpha = 0.2
.
- Using
+
, plot the dia_plot
object with a geom_smooth()
layer on top. You don’t want any error shading, which can be achieved by setting the se = FALSE
in geom_smooth()
.
- Modify the
geom_smooth()
function from the previous instruction so that it contains aes()
and map clarity
to the col
argument.
Data
base
package and ggplot2
, part 1 - plot
These courses are about understanding data visualization in the context of the grammar of graphics. To gain a better appreciation of ggplot2
and to understand how it operates differently from base
package, it’s useful to make some comparisons.
First, let’s focus on base package. You want to make a plot of mpg
(miles per gallon) against wt
(weight in thousands of pounds) in the mtcars
data frame, but this time you want the dots colored according to the number of cylinders, cyl
. How would you do that in base package? You can use a little trick to color the dots by specifying a factor
variable as a color. This works because factors are just a special class of the integer
type.
Instructions
- Using the
base
package plot()
, make a scatter plot with mtcars$wt
on the x-axis and mtcars$mpg
on the y-axis, colored according to mtcars$cyl
(use the col
argument). You can specify data =
but you’ll just do it the long way here.
- Add a new column,
fcyl
, to the mtcars
data frame. This should be cyl
converted to a factor.
- Create a similar plot to instruction 1, but this time, use
fcyl
(which is cyl
as a factor) to set the col
.
base
package and ggplot2
, part 2 - lm
If you want to add a linear model to your plot, shown right, you can define it with lm()
and then plot the resulting linear model with abline()
. However, if you want a model for each subgroup, according to cylinders, then you have a couple of options.
You can subset your data, and then calculate the lm()
and plot each subset separately. Alternatively, you can vectorize over the cyl
variable using lapply()
and combine this all in one step. This option is already prepared for you.
The code below contains a call to the function lapply()
, which you might not have seen before. This function takes as input a vector and a function. Then lapply()
applies the function it was given to each element of the vector and returns the results in a list. In this case, lapply()
takes each element of mtcars$cyl
and calls the function defined in the second argument. This function takes a value of mtcars$cyl
and then subsets the data so that only rows with cyl == x
are used. Then it fits a linear model to the filtered dataset and uses that model to add a line to the plot with the abline()
function.
Now that you have an interesting plot, there is a very important aspect missing - the legend!
In base package you have to take care of this using the legend()
function. This has been done for you in the predefined code.
Instructions
- Fill in the
lm()
function to calculate a linear model of mpg
described by wt
and save it as an object called carModel
.
- Draw the linear model on the scatterplot.
- Write code that calls
abline()
with carModel
as the first argument. Set the line type by passing the argument lty = 2
.
- Run the code that generates the basic plot and the call to
abline()
all at once by highlighting both parts of the script and hitting control/command
+ enter
on your keyboard. These lines must all be run together in the console so that R will be able to find the plot you want to add a line to.
- Run the code already given to generate the plot with a different model for each group. You don’t need to modify any of this.
# Use lm() to calculate a linear model and save it as carModel
___ <- lm(___ ~ ___, data = mtcars)
# Basic plot
mtcars$cyl <- as.factor(mtcars$cyl)
plot(mtcars$wt, mtcars$mpg, col = mtcars$cyl)
# Call abline() with carModel as first argument and set lty to 2
___(___, lty = ___)
# Plot each subset efficiently with lapply
# You don't have to edit this code
plot(mtcars$wt, mtcars$mpg, col = mtcars$cyl)
lapply(mtcars$cyl, function(x) {
abline(lm(mpg ~ wt, mtcars, subset = (cyl == x)), col = x)
})
# This code will draw the legend of the plot
# You don't have to edit this code
legend(x = 5, y = 33, legend = levels(mtcars$cyl),
col = 1:3, pch = 1, bty = "n")
base
package and ggplot2
, part 3
In this exercise you’ll recreate the base package plot in ggplot2
.
The code for base R plotting is given at the top. The first line of code already converts the cyl
variable of mtcars
to a factor.
Instructions
- Plot 1: add
geom_point()
in order to make a scatter plot.
- Plot 2: copy and paste Plot 1
- Add a linear model for each subset according to
cyl
by adding a geom_smooth()
layer
- Inside this
geom_smooth()
, set method to "lm"
and se
to FALSE
. Note: geom_smooth()
will automatically draw a line per cyl
subset. It recognizes the groups you want to identify by color
in the aes()
call within the ggplot()
command.
- Plot 3: copy and paste Plot 2
- Plot a linear model for the entire dataset, do this by adding another
geom_smooth()
layer
- Set the
group
aesthetic inside this geom_smooth()
layer to 1
. This has to be set within the aes()
function.
- Set
method
to "lm"
, se
to FALSE
and linetype
to 2
. These have to be set outside aes()
of the geom_smooth()
.
Note: the group
aesthetic will tell ggplot()
to draw a single linear model through all the points.
# Convert cyl to factor (don't need to change)
mtcars$cyl <- as.factor(mtcars$cyl)
# Example from base R (don't need to change)
plot(mtcars$wt, mtcars$mpg, col = mtcars$cyl)
abline(lm(mpg ~ wt, data = mtcars), lty = 2)
lapply(mtcars$cyl, function(x) {
abline(lm(mpg ~ wt, mtcars, subset = (cyl == x)), col = x)
})
legend(x = 5, y = 33, legend = levels(mtcars$cyl),
col = 1:3, pch = 1, bty = "n")
# Plot 1: add geom_point() to this command to create a scatter plot
ggplot(mtcars, aes(x = wt, y = mpg, col = cyl)) +
___ # Fill in using instructions Plot 1
# Plot 2: include the lines of the linear models, per cyl
ggplot(mtcars, aes(x = wt, y = mpg, col = cyl)) +
___ + # Copy from Plot 1
___ # Fill in using instructions Plot 2
# Plot 3: include a lm for the entire dataset in its whole
ggplot(mtcars, aes(x = wt, y = mpg, col = cyl)) +
___ + # Copy from Plot 2
___ + # Copy from Plot 2
___ # Fill in using instructions Plot 3
ggplot2
compared to base
package
ggplot2
has become very popular and for many people it’s the go-to plotting package in R. What does ggplot2
do that base
package doesn’t?
Answer the question
Possible Answers
ggplot2
creates plotting objects, which can be manipulated.
ggplot2
takes care of a lot of the leg work for you, such as choosing nice color pallettes and making legends.
ggplot2
is built upon the grammar of graphics plotting philosophy, making it more flexible and intuitive for understanding the relationship between your visuals and your data.
- Options 1, 2, and 3.
ggplot2
is effectively a replacement for all base-package plotting functions.
Plotting the ggplot2 way
There are different ggplot2
calls to plot two groups of data onto the same plot:
# Option 1
ggplot(iris, aes(x = Sepal.Length, y = Sepal.Width)) +
geom_point() +
geom_point(aes(x = Petal.Length, y = Petal.Width), col = "red")
iris.wide <- rbind(data.frame(Species = iris$Species, Part = "Sepal", Length = iris$Sepal.Length, Width = iris$Sepal.Width), data.frame(Species = iris$Species, Part = "Petal", Length = iris$Petal.Length, Width = iris$Petal.Width))
# Option 2
ggplot(iris.wide, aes(x = Length, y = Width, col = Part)) +
geom_point()
Which one is preferable? Both iris
and iris.wide
are available in the workspace, so you can experiment in the R Console straight away!
Instructions
Possible Answers
- Option 1.
- Option 2.
- Both are equally preferable.
Variables to visuals, part 1
iris.wide2 <- rbind(
data.frame(Measure = "Length", Part = "Petal", Setosa = iris[iris$Species == "setosa","Petal.Length"], Versicolor = iris[iris$Species == "versicolor","Petal.Length"], Virginica = iris[iris$Species == "virginica","Petal.Length"]),
data.frame(Measure = "Width", Part = "Petal", Setosa = iris[iris$Species == "setosa","Petal.Width"], Versicolor = iris[iris$Species == "versicolor","Petal.Width"], Virginica = iris[iris$Species == "virginica","Petal.Width"]),
data.frame(Measure = "Length", Part = "Sepal", Setosa = iris[iris$Species == "setosa","Sepal.Length"], Versicolor = iris[iris$Species == "versicolor","Sepal.Length"], Virginica = iris[iris$Species == "virginica","Sepal.Length"]),
data.frame(Measure = "Width", Part = "Sepal", Setosa = iris[iris$Species == "setosa","Sepal.Width"], Versicolor = iris[iris$Species == "versicolor","Sepal.Width"], Virginica = iris[iris$Species == "virginica","Sepal.Width"]))
iris.tidy <- rbind(
data.frame(Species = iris$Species, Part = "Sepal", Measure = "Length", Value = iris$Sepal.Length),
data.frame(Species = iris$Species, Part = "Sepal", Measure = "Width", Value = iris$Sepal.Length),
data.frame(Species = iris$Species, Part = "Petal", Measure = "Length", Value = iris$Petal.Length),
data.frame(Species = iris$Species, Part = "Petal", Measure = "Width", Value = iris$Petal.Width))
So far you’ve seen four different forms of the iris dataset: iris
, iris.wide
, iris.wide2
and iris.tidy
. Don’t let all these different forms confuse you! It’s exactly the same data, just rearranged so that your plotting functions become easier.
To see this in action, consider the plot in the graphics device at right. Which form of the dataset would be the most appropriate to use here?
Instructions
- Look at the structures of
iris
, iris.wide
and iris.tidy
using str()
.
- Fill in the
ggplot
function with the appropriate data frame and variable names. The variable names of the aesthetics of the plot will match the ones you found using the str()
command in the previous step.
Variables to visuals, part 1b
In the last exercise you saw how iris.tidy
was used to make a specific plot. It’s important to know how to rearrange your data in this way so that your plotting functions become easier. In this exercise you’ll use functions from the tidyr
package to convert iris
to iris.tidy
.
The resulting iris.tidy
data should look as follows:
Species Part Measure Value
1 setosa Sepal Length 5.1
2 setosa Sepal Length 4.9
3 setosa Sepal Length 4.7
4 setosa Sepal Length 4.6
5 setosa Sepal Length 5.0
6 setosa Sepal Length 5.4
...
You can have a look at the iris
dataset by typing head(iris)
in the console.
Note: If you’re not familiar with %>%
, gather()
and separate()
, you may want to take the Cleaning Data
in R course. In a nutshell, a dataset is called tidy when every row is an observation and every column is a variable. The gather()
function moves information from the columns to the rows. It takes multiple columns and gathers them into a single column by adding rows. The separate()
function splits one column into two or more columns according to a pattern you define. Lastly, the %>%
(or “pipe”) operator passes the result of the left-hand side as the first argument of the function on the right-hand side.
Instructions
You’ll use two functions from the tidyr
package:
gather()
rearranges the data frame by specifying the columns that are categorical variables with a - notation. Complete the command. Notice that only one variable is categorical in iris.
separate()
splits up the new key column, which contains the former headers, according to .
. The new column names “Part” and “Measure” are given in a character vector. Don’t forget the quotes.
Variables to visuals, part 2
Here you’ll take a look at another plot variant. Which of your data frames would be used to produce this plot?

Instructions
- Look at the heads of
iris
, iris.wide
and iris.tidy
using head()
.
- Fill in the
ggplot
function with the appropriate data frame and variable names. The names of the aesthetics of the plot will match with variable names in your dataset. The previous instruction will help you match variable names in datasets with the ones in the plot.
Variables to visuals, part 2b
You saw previously how you can derive iris.tidy
from iris
. Now you’ll move on to produce iris.wide
.
The head of the iris.wide
should look like this in the end:
Species Part Length Width
1 setosa Petal 1.4 0.2
2 setosa Petal 1.4 0.2
3 setosa Petal 1.3 0.2
4 setosa Petal 1.5 0.2
5 setosa Petal 1.4 0.2
6 setosa Petal 1.7 0.4
...
You can have a look at the iris
dataset by typing head(iris)
in the console.
Instructions
- Before you begin, you need to add a new column called
Flower
that contains a unique identifier for each row in the data frame. This is because you’ll rearrange the data frame afterwards and you need to keep track of which row, or which specific flower, each value came from. It’s done for you, no need to add anything yourself.
gather()
rearranges the data frame by specifying the columns that are categorical variables with a - notation. In this case, Species
and Flower
are categorical. Complete the command.
separate()
splits up the new key column, which contains the former headers, according to .
. The new column names "Part"
and "Measure"
are given in a character vector.
- The last step is to use
spread()
to distribute the new Measure
column and associated value
column into two columns.
Aesthetics
All about aesthetics, part 1
There are 9 different aesthetics that can be mapped:
x
: the X-axis position
y
: the Y-axis position
color
: the color of dots and the outline of other shapes
fill
: fill color
size
: diameter of points, thickness of lines
alpha
: the transparency, 0-transparent, 1-opaque
linetype
: line dash pattern
labels
: text on a plot or axes
shape
: the shape
Let’s apply them to a categorical variable - the cylinders in mtcars
, cyl
.
(You’ll consider line type when you encounter line plots in the next chapter).
These are the aesthetics you can consider within aes()
in this chapter: x
, y
, color
, fill
, size
, alpha
, labels
and shape
.
In the following exercise you can assume that the cyl
column is categorical. It has already been transformed into a factor
for you.
Instructions
The mtcars
data frame is available in your workspace. For each of the following four plots, use geom_point()
:
- Map
mpg
onto the x
aesthetic, and cyl
onto the y
.
- Reverse the mappings of the first plot.
- Map
wt
onto x,,
mpgonto
y, and
cylonto
color`.
- Modify the previous plot by changing the
shape
argument of the geom to 1
and increase the size
to 4
. These are attributes that you should specify inside geom_point()
.
library(datasets)
mtcars$cyl <- as.factor(mtcars$cyl)
# 1 - Map mpg to x and cyl to y
ggplot(___, aes(___, ___)) +
geom_point()
# 2 - Reverse: Map cyl to x and mpg to y
ggplot(___, aes(___, ___)) +
geom_point()
# 3 - Map wt to x, mpg to y and cyl to col
ggplot(___, aes(___, ___, ___)) +
geom_point()
# 4 - Change shape and size of the points in the above plot
ggplot(mtcars, aes(___, ___, ___)) +
geom_point(___, ___)
All about aesthetics, part 2
The color
aesthetic typically changes the outside outline of an object and the fill
aesthetic is typically the inside shading. However, as you saw in the last exercise, geom_point()
is an exception. Here you use color
, instead of fill
for the inside of the point. But it’s a bit subtler than that.
Which shape to use? The default geom_point()
uses shape = 19
(a solid circle with an outline the same colour as the inside). Good alternatives are shape = 1
(hollow) and shape = 16
(solid, no outline). These all use the col
aesthetic (don’t forget to set alpha
for solid points).
A really nice alternative is shape = 21
which allows you to use both fill for the inside and col for the outline! This is a great little trick for when you want to map two aesthetics to a dot.
What happens when you use the wrong aesthetic mapping? This is a very common mistake! The code from the previous exercise is in the editor. Using this as your starting point complete the instructions.
Instructions
Note: In the mtcars
dataset, cyl
and am
have been converted to factor for you.
- Copy & paste the first plot’s code. Change the aesthetics so that
cyl
maps to fill
rather than col
.
- Copy & paste the second plot’s code. In
geom_point()
change the shape
argument to 21
and add an alpha
argument set to 0.6
.
- Copy & paste the third plot’s code. In the
ggplot()
aesthetics, map am
to col
.
All about aesthetics, part 3
Now that you’ve got some practice with incrementally building up plots, you can try to do it from scratch! The mtcars
dataset is pre-loaded in the workspace.
Instructions
Use ggplot()
to create a basic scatter plot. Inside aes()
, map wt
onto x
and mpg
onto y
. Typically, you would say “mpg described by wt” or “mpg vs wt”, but in aes()
, it’s x
first, y
second. Use geom_point()
to make three scatter plots:
cyl
on size
cyl
on alpha
cyl
on shape
Try this last variant:
cyl
on label
. In order to correctly show the test (i.e. label
), use geom_text()
.
All about attributes, part 1
You can use all the aesthetics as attributes. Let’s see how this works with the aesthetics you used in the previous exercises: x
, y
, color
, fill
, size
, alpha
, label
and shape
.
This time you’ll use these arguments to set attributes of the plot, not aesthetics. However, there are some pitfalls you’ll have to watch out for: these attributes can overwrite the aesthetics of your plot!
A word about shapes: In the exercise “All about aesthetics, part 2”, you saw that shape = 21
results in a point that has a fill and an outline. Shapes in R can have a value from 1-25. Shapes 1-20 can only accept a color aesthetic, but shapes 21-25 have both a color and a fill aesthetic. See the pch
argument in par()
for further discussion.
A word about hexadecimal colours: Hexadecimal, literally “related to 16”, is a base-16 alphanumeric counting system. Individual values come from the ranges 0-9 and A-F. This means there are 256 possible two-digit values (i.e. 00 - FF). Hexadecimal colours use this system to specify a six-digit code for Red, Green and Blue values (“#RRGGBB”) of a colour (i.e. Pure blue: “#0000FF”, black: “#000000”, white: “#FFFFFF”). R can accept hex codes as valid colours.
Instructions
- You will continue to work with
mtcars
. Use ggplot()
to create a basic scatter plot: map wt
onto x
, mpg
onto y
and cyl
onto color
.
- Overwrite the color of the points inside
geom_point()
to my_color
. Notice how this cancels out the colors given to the points by the number of cylinders!
- Starting with plot 2, map
cyl
to fill
instead of col
and set the attributes size
to 10
, shape
to 23
and color
to my_color
inside geom_point()
.
All about attributes, part 2
You can use all the aesthetics as attributes. Let’s see how this works with the aesthetics you used in the previous exercises: x
, y
, color
, fill
, size
, alpha
, label
and shape
.
In this exercise you will set all kinds of attributes of the points!
You will continue to work with mtcars
.
Instructions
- Add to the first command: draw points with
alpha
set to 0.5
.
- Add to the second command: draw points of shape
24
in the color yellow
.
- Add to the third command: draw text with label
rownames(mtcars)
in the color red
. Don’t use geom_point()
here! You should get a scatter plot with the names of the cars instead of points.
Note: Remember to specify characters with quotation marks ("yellow"
, not yellow
).
Going all out
In this exercise, you will gradually add more aesthetics layers to the plot. You’re still working with the mtcars
dataset, but this time you’re using more features of the cars. For completeness, here is a list of all the features of the observations in mtcars
:
mpg
– Miles/(US) gallon
cyl
– Number of cylinders
disp
– Displacement (cu.in.)
hp
– Gross horsepower
drat
– Rear axle ratio
wt
– Weight (lb/1000)
qsec
– 1/4 mile time
vs
– V/S engine.
am
– Transmission (0 = automatic, 1 = manual)
gear
– Number of forward gears
carb
– Number of carburetors
Notice that adding more aesthetics to your plot is not always a good idea. Adding aesthetic mappings to a plot will increase its complexity, and thus decrease its readability.
Instructions
Note: In this chapter you saw aesthetics and attributes. Variables in a data frame are mapped to aesthetics in aes()
. (e.g. aes(col = cyl)
) within ggplot()
. Visual elements are set by attributes in specific geom layers (geom_point(col = "red")
). Don’t confuse these two things - here you’re focusing on aesthetic mappings.
- Draw a scatter plot of
mtcars
with mpg
on the x-axis, qsec
on the y-axis and factor(cyl)
as colors.
- Expand the previous plot to include
factor(am)
as the shape
of the points.
- Expand the previous plot to include the ratio of horsepower to weight (i.e.
(hp/wt)
) as the size of the points.
Aesthetics for categorical and continuous variables
Many of the aesthetics can be mapped onto continuous or categorical variables, but some are restricted to categorical data. Which aesthetics are they?
Instructions
Possible Answers
- color & fill
- alpha & size
- label & shape
- alpha & label
- x & y
Position
Bar plots suffer from their own issues of overplotting, as you’ll see here. Use the "stack"
, "fill"
and "dodge"
positions to reproduce the plot in the viewer.
The ggplot2
base layers (data and aesthetics) have already been coded; they’re stored in a variable cyl.am
. It looks like this:
Instructions
- Add a
geom_bar()
call to cyl.am
. By default, the position
will be set to "stack"
.
- Fill in the second
ggplot
command. Explicitly set position
to "fill"
inside geom_bar()
.
- Fill in the third
ggplot
command. Set position
to "dodge"
.
- The
position = "dodge"
version seems most appropriate. Finish off the fourth ggplot
command by completing the three scale_
functions:
scale_x_discrete()
takes as its only argument the x-axis label: "Cylinders"
.
scale_y_continuous()
takes as its only argument the y-axis label: "Number"
.
scale_fill_manual()
fixes the legend. The first argument is the title of the legend: "Transmission"
. Next, values
and labels
are set to predefined values for you. These are the colors and the labels in the legend.
Setting a dummy aesthetic
In the last chapter you saw that all the visible aesthetics can serve as attributes and aesthetics, but I very conveniently left out x
and y
. That’s because although you can make univariate plots (such as histograms, which you’ll get to in the next chapter), a y-axis will always be provided, even if you didn’t ask for it.
In the base package you can make univariate plots with stripchart()
directly and it will take care of a fake y
axis for us. Since this is univariate data, there is no real y
axis.
You can get the same thing in ggplot2
, but it’s a bit more cumbersome. The only reason you’d really want to do this is if you were making many plots and you wanted them to be in the same style, or you wanted to take advantage of an aesthetic mapping (e.g. colour
).
Instructions
- Try to run
ggplot(mtcars, aes(x = mpg)) + geom_point()
in the console. x
is only one of the two essential aesthetics for geom_point()
, which is why you get an error message.
- 1 - To fix this, map a value, e.g. 0, instead of a variable, onto
y
. Use geom_jitter()
to avoid having all the points on a horizontal line.
- 2 - To make everything look nicer, copy & paste the code for plot 1 and change the limits of the
y
axis using the appropriate scale_y_...()
function. Set the limits
argument to c(-2, 2)
.
Overplotting 1 - Point shape and transparency
In the previous section you saw that there are lots of ways to use aesthetics. Perhaps too many, because although they are possible, they are not all recommended. Let’s take a look at what works and what doesn’t.
So far you’ve focused on scatter plots since they are intuitive, easily understood and very common. A major consideration in any scatter plot is dealing with overplotting. You’ll encounter this topic again in the geometries layer, but you can already make some adjustments here.
You’ll have to deal with overplotting when you have:
- Large datasets,
- Imprecise data and so points are not clearly separated on your plot (you saw this in the video with the
iris
dataset),
- Interval data (i.e. data appears at fixed values), or
- Aligned data values on a single axis.
One very common technique that I’d recommend to always use when you have solid shapes it to use alpha blending (i.e. adding transparency). An alternative is to use hollow shapes. These are adjustments to make before even worrying about positioning. This addresses the first point as above, which you’ll see again in the next exercise.
Instructions
- Begin by making a basic scatter plot of
mpg
(y) vs. wt
(x), map cyl
to color
and make the size = 4
. cyl
has already been converted to a factor variable for you.
- Modify the above plot to set
shape
to 1
. This allows for hollow circles.
- Modify the first plot to set
alpha
to 0.6
.
Overplotting 2 - alpha with large datasets
In a previous exercise we defined four situations in which you’d have to adjust for overplotting. You’ll consider the last two here with the diamonds dataset:
- Large datasets.
- Aligned data values on a single axis
Instructions
- The
diamonds
data frame is available in the ggplot2()
package. Begin by making a basic scatter plot of price
(y) vs. carat
(x) and map clarity
onto color
.
- Copy the above functions and set the
alpha
to 0.5
. This is a good start to dealing with the large dataset.
- Align all the diamonds within a clarity class, by plotting
carat
(y) vs. clarity
(x). Map price
onto color
. alpha
should still be 0.5
.
- In the previous plot, all the individual values line up on a single axis within each clarity category, so you have not overcome overplotting. Modify the above plot to use the
position = "jitter"
inside geom_point()
.
Geometries
Scatter plots and jittering (1)
You already saw a few examples using geom_point()
where the result was not a scatter plot. For example, in the plot given below, a continuous variable, wt
, is mapped to the y
aesthetic, and a categorical variable, cyl
, is mapped to the x
aesthetic. This also leads to over-plotting, since the points are arranged on a single x position. You previously dealt with overplotting by setting the position = jitter
inside geom_point()
. Let’s look at some other solutions here.
Instructions
Beginning with the code for the plot in the viewer (given), make these modifications
- Use a shortcut geom,
geom_jitter()
, instead of geom_point()
.
- Unfortunately, the width of the jitter is a bit too wide to be useful. Adjust this by setting the argument
width = 0.1
inside geom_jitter()
.
- Finally, return to
geom_point()
and set the position argument here to position_jitter(0.1)
, which will set the jittering width directly inside a points layer.
Note: For convenience, you could have saved the data and aesthetic layers as a ggplot2 object and re-used it in all solutions. We’ve made each plot explicit so that you can see all plotting instructions.
Scatter plots and jittering (2)
In the chapter on aesthetics you saw different ways in which you will have to compensate for overplotting.
Another issue is when you have interval data. This can be continuous data measured on an interval (i.e. 1 ,2, 3 …), as opposed to numeric (i.e. 1.1, 1.4, 1.5, …), scale, or two categorical (e.g. factor) variables, which are just type interval under-the-hood.
In such a case you’ll have a small, defined number of intersections between the two variables.
You will be using the Vocab
dataset. The Vocab
dataset contains information about the years of education and integer score on a vocabulary test for over 21,000 individuals based on US General Social Surveys from 1972-2004.
Instructions
- The
Vocab
data frame has been loaded for you. Both the education and vocabulary variables are classified as integers. You can imagine these as factor variables, but here, integers are more convenient to work with. First, get familiar with the dataset by looking at its structure with str()
.
- Make a basic scatter plot of
vocabulary
(y) vs. education
(x). Here it becomes apparent that you have issues with overplotting because of the integer scales.
- Use
geom_jitter()
instead of geom_point()
.
- Using the jittered plot, set
alpha
to 0.2
(very low).
- Using the jittered plot, set
shape
to 1
.
Histograms
Histograms are one of the most common and intuitive ways of showing distributions. In this exercise you’ll use the mtcars
data frame to explore typical variations of simple histograms. But first, some background:
The x axis/aesthetic: The documentation for geom_histogram()
states the argument stat = "bin"
as a default. Recall that histograms cut up a continuous variable into discrete bins - thats what the stat “bin” is doing. You always get 30 evenly-sized bins by default, which is specified with the default argument binwidth = range/30
. This is a pretty good starting point if you don’t know anything about the variable being ploted and want to start exploring.
The y axis/aesthetic: geom_histogram()
only requires one aesthetic: x
. But there is clearly a y
axis on your plot, so where does it come from? Actually, there is a variable mapped to the y aesthetic, it’s called ..count..
. When geom_histogram()
executed the binning statistic (see above), it not only cut up the data into discrete bins, but it also counted how many values are in each bin. So there is an internal data frame where this information is stored. The .. calls the variable count from this internal data frame. This is what appears on the y
aesthetic. But it gets better! The density has also been calculated. This is the proportional frequency of this bin in relation to the whole data set. You use ..density..
to access this information.
Instructions
- Use the
mtcars
data frame and make a univariate histogram by mapping mpg
onto the x
aesthetic. Use geom_histogram()
for the geom layer.
- Take plot 1 and manually create 1-unit wide bins with the
binwidth = 1
argument in geom_histogram()
.
- Take plot 2, and map
..density..
onto the y
aesthetic (i.e. inside an aes()
) inside geom_histogram()
. You’ll have two aes()
functions: one inside ggplot()
and another inside geom_histogram()
. (See the intro text for a discussion of ..density..
).
- Take plot 3 and set the attribute
fill
, the inside of the bars, to the value "#377EB8"
in geom_histogram()
. This should not appear in aes()
, since it’s an attribute, not an aesthetic mapping.
Position
In the previous chapter you saw that there are lots of ways to position scatter plots. Likewise, the geom_bar()
and geom_histogram()
geoms also have a position
argument, which you can use to specify how to draw the bars of the plot.
Three position
arguments will be introduced here:
stack
: place the bars on top of each other. Counts are used. This is the default position.
fill
: place the bars on top of each other, but this time use proportions.
dodge
: place the bars next to each other. Counts are used.
In this exercise you’ll draw the total count of cars having a given number of cylinders
(cyl), according to manual or automatic transmission type (am
).
Since, in the built-in mtcars
data set, cyl
and am
are integers, you have to convert them into factor variables.
Instructions
- Using
mtcars
, map cyl
onto the x
aesthetic and am
onto fill
. Use geom_bar()
to make a bar plot.
- Take plot 1 and explicitly set
position = "stack"
in geom_bar()
. This doesn’t change anything, does it? It was mentioned above that "stack"
is the default.
- Take plot 2 and set
position = "fill"
in geom_bar()
.
- Take plot 3 and set
position = "dodge"
in geom_bar()
.
Overlapping bar plots
So far you’ve seen three different positions for bar plots: stack
(the default), dodge
(preferred), and fill
(to show proportions).
However, you can go one step further by adjusting the dodging, so that your bars partially overlap each other. For this example you’ll again use the mtcars
dataset. Like last time you have to convert cyl
and am
into factors inside mtcars
.
Instead of using position = "dodge"
you’re going to use position_dodge()
, like you did with position_jitter()
in the Scatter plots and jittering (1) exercise. Here, you’ll save this as an object, posn_d
, so that you can easily reuse it.
Remember, the reason you want to use position_dodge()
(and position_jitter()
) is to specify how much dodging (or jittering) you want.
Instructions
- The last plot from the last exercise has been provided for you.
- Define a new object called
posn_d
by calling position_dodge()
with the argument width = 0.2
.
- Take plot 1 and make slightly overlapping bars by using the
position = posn_d
argument.
- Take plot 3 and set
alpha = 0.6
to see the overlap in bars.
Overlapping histograms
Overlapping histograms pose similar problems to overlapping bar plots, but there is a unique solution here: a frequency polygon.
This is a geom specific to binned data that draws a line connecting the value of each bin. Like geom_histogram()
, it takes a binwidth
argument and by default stat = "bin"
and position = "identity"
.
Instructions
- The code for a basic histogram of
mpg
, which you’ve already seen, is provided. Extend the code to map cyl
onto fill
inside aes()
.
- The default position for histograms is
"stack"
. Copy your solution to the first exercise and set the position
for the histogram bars to "identity"
.
- Using the same data and base layers as in the previous two plots, create a plot with a
geom_freqpoly()
. Because you’re no longer working with bars, change the aes()
function: cyl
should be mapped onto col
, not onto fill
. This will correctly color the geom.
Bar plots with color ramp, part 1
In this example of a bar plot, you’ll fill each segment according to an ordinal variable. The best way to do that is with a sequential color series.
You’ll be using the Vocab
dataset from earlier. Since this is a much larger dataset with more categories, you’ll also compare it to a simpler dataset, mtcars
. Both datasets are ordinal.
Instructions
- The bar plot from the previous exercise is provided -
cyl
is on the x-axis and filled according to transmission type, am
. Notice how you can set the color palette used to fill the bars with scale_fill_brewer()
. For a full list of possible color sets, have a look at ?brewer.pal
.
- Explore
Vocab
with str()
. Notice that the education
and vocabulary
variables have already been converted to factor variables for you.
- Make a filled bar chart with the
Vocab
dataset.
- Map
education
to x
and vocabulary
to fill
.
- Inside
geom_bar()
, make sure to set position = "fill"
.
- Allow color brewer to choose a default color palette by using the appropriate scale function, without arguments. Notice how this generates a warning message and an incomplete plot.
Bar plots with color ramp, part 2
In the previous exercise, you ended up with an incomplete bar plot. This was because for continuous data, the default RColorBrewer
palette that scale_fill_brewer()
calls is "Blues"
. There are only 9 colours in the palette, and since you have 11 categories, your plot looked strange.
In this exercise, you’ll manually create a color palette that can generate all the colours you need. To do this you’ll use a function called colorRampPalette()
.
The input is a character vector of 2 or more colour values, e.g. "#FFFFFF"
(white) and "#0000FF"
(pure blue). (See All about attributes, part 1 for a discussion on hexadecimal codes).
The output is itself a function! So when you assign it to an object, that object should be used as a function. To see what we mean, execute the following three lines:
new_col()
is a function that takes one argument: the number of colours you want to extrapolate. You want to use nicer colours, so we’ve assigned the entire "Blues"
colour palette from the RColorBrewer
package to the character vector blues
.
Instructions
- Like in the example code above, create a new function called
blue_range
that uses colorRampPalette()
to extrapolate over all 9 values of the blues
character vector.
- Take the plot code from the last exercise (provided), and change
scale_fill_brewer()
to be scale_fill_manual()
. Set the argument values = blue_range(11)
inside scale_fill_manual()
.
Overlapping histograms (2)
As a last example of bar plots, you’ll return to histograms (which you now see are just a special type of bar plot). You saw a nice trick in a previous exercise of how to slightly overlap bars, but now you’ll see how to overlap them completely. This would be nice for multiple histograms, as long as there are not too many different overlaps!
You’ll make a histogram using the mpg
variable in the mtcars
data frame.
Instructions
- A basic histogram plot is provided.
- Take plot 1 and map
am
onto fill
within the aes()
function. The default position is "stack"
.
- Take plot 2 and add the
position
argument within geom_histogram()
. Set it to "dodge"
.
- Take plot 3 and change the
position
argument to "fill"
. In this case, none of these positions really work well, because it’s difficult to compare the distributions directly.
- Take plot 4 and change the
position
argument to "identity"
and set alpha = 0.4
. This produces overlapping bars.
- Take plot 5 and change the aesthetic mapping. Map
cyl onto fill
.
Line plots
In the video you saw how to make line plots using time series data. To explore this topic, you’ll use the economics
data frame, which contains time series for unemployment and population statistics from the Federal Reserve Bank of St. Louis in the US. The data is contained in the ggplot2
package.
To begin with, you can look at how the median unemployment time and the unemployment rate (the number of unemployed people as a proportion of the population) change over time.
In the next exercises, you’ll explore to how add embellishments to the line plots, such as recession periods.
Instructions
- Print out the
head()
of the economics
data frame.
- Use the
economics
data frame to plot date
on the x
axis and unemploy
on the y
axis. Use geom_line()
.
- Copy, paste and adjust the code for the previous instruction: instead of
unemploy
, plot unemploy/pop
to represent the fraction of the total population that is unemployed.
Periods of recession
By themselves, time series often contain enough valuable information, but you always want to maximize the number of variables you can show in a plot. This allows you (and your viewers) to begin making comparisons between those variables that would otherwise be difficult or impossible.
Here, you’ll add shaded regions to the background to indicate recession periods. How do unemployment rate and recession period interact with each other?
In addition to the economics
dataset from before, you’ll also use the recess
dataset for the periods of recession. The recess
data frame contains 2 variables: the begin
period of the recession and the end
. It’s already available in your workspace.
Instructions
Expand the command from the previous exercise with geom_rect()
. You will use this geom layer to draw rectangles across the recession periods. There a few pitfalls here:
geom_rect()
uses the recess dataset
, so pass this directly as data = recess
inside geom_rect()
.
- The
geom_rect()
command shouldn’t inherit aesthetics from the base ggplot()
command it belongs to. It would result in an error, since you’re using a different dataset and it doesn’t contain unemploy
or pop
. That’s why you should specify inherit.aes = FALSE
in geom_rect()
.
geom_rect()
needs four aesthetics: xmin
, xmax
, ymin
and ymax
. These should be set to begin
, end
and -Inf
, +Inf
, respectively. Define them within aes()
.
- The rectangles you add will be black and opaque by default. Set
fill
to "red"
and alpha
to 0.2
to improve this. Define them outside aes()
.
recess <- data.frame(
begin = c("1969-12-01","1973-11-01","1980-01-01","1981-07-01","1990-07-01","2001-03-01"),
end = c("1970-11-01","1975-03-01","1980-07-01","1982-11-01","1991-03-01","2001-11-01"),
stringsAsFactors = F
)
library(lubridate)
recess$begin <- ymd (recess$begin)
recess$end <- ymd (recess$end)
# Basic line plot
ggplot(economics, aes(x = date, y = unemploy/pop)) +
geom_line()
# Expand the following command with geom_rect() to draw the recess periods
ggplot(economics, aes(x = date, y = unemploy/pop)) +
___(___ = ___,
aes(___ = ___, ___ = ___, ___ = ___, ___ = ___),
___ = FALSE, ___ = "red", ___ = 0.2) +
geom_line()
LS0tCnRpdGxlOiAiVmlzdWFsaXphdGlvbiB3aXRoIGBnZ3Bsb3QyYCIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICBoaWdobGlnaHQ6IGhhZGRvY2sKICAgIG51bWJlcl9zZWN0aW9uczogeWVzCiAgICB0aGVtZTogY2VydWxlYW4KICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6IDIKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiB5ZXMKICAgIHRvY19kZXB0aDogMgotLS0KCmBgYHtyIHNldHVwLCBlY2hvID0gRkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChldmFsID0gRkFMU0UpCmBgYAoKIyBJbnRyb2R1Y3Rpb24KCiMjIEV4cGxvcmluZyBgZ2dwbG90MmAsIHBhcnQgMQoKVG8gZ2V0IGEgZmlyc3QgZmVlbCBmb3IgYGdncGxvdDJgLCBsZXQncyB0cnkgdG8gcnVuIHNvbWUgYmFzaWMgYGdncGxvdDJgIGNvbW1hbmRzLiBUb2dldGhlciwgdGhleSBidWlsZCBhIHBsb3Qgb2YgdGhlIGBtdGNhcnNgIGRhdGFzZXQgdGhhdCBjb250YWlucyBpbmZvcm1hdGlvbiBhYm91dCAzMiBjYXJzIGZyb20gYSAxOTczIE1vdG9yIFRyZW5kIG1hZ2F6aW5lLiBUaGlzIGRhdGFzZXQgaXMgc21hbGwsIGludHVpdGl2ZSwgYW5kIGNvbnRhaW5zIGEgdmFyaWV0eSBvZiBjb250aW51b3VzIGFuZCBjYXRlZ29yaWNhbCB2YXJpYWJsZXMuCgojIyMgSW5zdHJ1Y3Rpb25zCgotIExvYWQgdGhlIGBnZ3Bsb3QyYCBwYWNrYWdlIHVzaW5nIGBsaWJyYXJ5KClgLiAKLSBVc2UgYHN0cigpYCB0byBleHBsb3JlIHRoZSBzdHJ1Y3R1cmUgb2YgdGhlIGBtdGNhcnNgIGRhdGFzZXQuCi0gRXhlY3V0ZSB0aGUgZXhhbXBsZSBjb2RlIGJlbG93LiBTZWUgaWYgeW91IGNhbiB1bmRlcnN0YW5kIHdoYXQgZ2dwbG90IGRvZXMgd2l0aCB0aGUgZGF0YS4KCmBgYHtyfQojIExvYWQgdGhlIGdncGxvdDIgcGFja2FnZQoKCiMgRXhwbG9yZSB0aGUgbXRjYXJzIGRhdGEgZnJhbWUgd2l0aCBzdHIoKQoKCiMgRXhlY3V0ZSB0aGUgZm9sbG93aW5nIGNvbW1hbmQKZ2dwbG90KG10Y2FycywgYWVzKHggPSBjeWwsIHkgPSBtcGcpKSArCiAgZ2VvbV9wb2ludCgpCmBgYAoKCiMjIEV4cGxvcmluZyBgZ2dwbG90MmAsIHBhcnQgMgoKVGhlIHBsb3QgZnJvbSB0aGUgcHJldmlvdXMgZXhlcmNpc2Ugd2Fzbid0IHJlYWxseSBzYXRpc2Z5aW5nLiBBbHRob3VnaCBgY3lsYCAodGhlIG51bWJlciBvZiBjeWxpbmRlcnMpIGlzIGNhdGVnb3JpY2FsLCBpdCBpcyBjbGFzc2lmaWVkIGFzIG51bWVyaWMgaW4gYG10Y2Fyc2AuIFlvdSdsbCBoYXZlIHRvIGV4cGxpY2l0bHkgdGVsbCBgZ2dwbG90MmAgdGhhdCBgY3lsYCBpcyBhIGNhdGVnb3JpY2FsIHZhcmlhYmxlLgoKIyMjIEluc3RydWN0aW9ucwoKLSBDaGFuZ2UgdGhlIGBnZ3Bsb3QoKWAgY29tbWFuZCBieSB3cmFwcGluZyBgZmFjdG9yKClgIGFyb3VuZCBgY3lsYC4KLSBFeGVjdXRlciBhbmQgc2VlIGlmIHRoZSByZXN1bHRpbmcgcGxvdCBpcyBiZXR0ZXIgdGhpcyB0aW1lLgoKYGBge3J9CiMgTG9hZCB0aGUgZ2dwbG90MiBwYWNrYWdlCmxpYnJhcnkoZ2dwbG90MikKCiMgQ2hhbmdlIHRoZSBjb21tYW5kIGJlbG93IHNvIHRoYXQgY3lsIGlzIHRyZWF0ZWQgYXMgZmFjdG9yCmdncGxvdChtdGNhcnMsIGFlcyh4ID0gY3lsLCB5ID0gbXBnKSkgKwogIGdlb21fcG9pbnQoKQpgYGAKCgojIyBFeHBsb3JpbmcgYGdncGxvdDJgLCBwYXJ0IDMKCldlJ2xsIHVzZSBzZXZlcmFsIGRhdGFzZXRzIHRocm91Z2hvdXQgdGhlIGNvdXJzZXMgdG8gc2hvd2Nhc2UgdGhlIGNvbmNlcHRzIGRpc2N1c3NlZCBpbiB0aGUgdmlkZW9zLiBJbiB0aGUgcHJldmlvdXMgZXhlcmNpc2VzLCB5b3UgYWxyZWFkeSBnb3QgdG8ga25vdyBgbXRjYXJzYC4gTGV0J3MgZGl2ZSBhIGxpdHRsZSBkZWVwZXIgdG8gZXhwbG9yZSB0aGUgdGhyZWUgbWFpbiB0b3BpY3MgaW4gdGhpcyBjb3Vyc2U6IFRoZSBkYXRhLCBhZXN0aGV0aWNzLCBhbmQgZ2VvbSBsYXllcnMuCgpUaGUgYG10Y2Fyc2AgZGF0YXNldCBjb250YWlucyBpbmZvcm1hdGlvbiBhYm91dCAzMiBjYXJzIGZyb20gMTk3MyBNb3RvciBUcmVuZCBtYWdhemluZS4gVGhpcyBkYXRhc2V0IGlzIHNtYWxsLCBpbnR1aXRpdmUsIGFuZCBjb250YWlucyBhIHZhcmlldHkgb2YgY29udGludW91cyBhbmQgY2F0ZWdvcmljYWwgdmFyaWFibGVzLgoKWW91J3JlIGVuY291cmFnZWQgdG8gdGhpbmsgYWJvdXQgaG93IHRoZSBleGFtcGxlcyBhbmQgY29uY2VwdHMgd2UgZGlzY3VzcyB0aHJvdWdob3V0IHRoZXNlIGRhdGEgdml6IGNvdXJzZXMgYXBwbHkgdG8geW91ciBvd24gZGF0YS1zZXRzIQoKIyMjIEluc3RydWN0aW9ucwoKLSBgZ2dwbG90MmAgaGFzIGFscmVhZHkgYmVlbiBsb2FkZWQgZm9yIHlvdS4gVGFrZSBhIGxvb2sgYXQgdGhlIGZpcnN0IGNvbW1hbmQuIEl0IHBsb3RzIHRoZSBgbXBnYCAobWlsZXMgcGVyIGdhbG9uKSBhZ2FpbnN0IHRoZSBgd2VpZ2h0YCAoaW4gdGhvdXNhbmRzIG9mIHBvdW5kcykuIFlvdSBkb24ndCBoYXZlIHRvIGNoYW5nZSBhbnl0aGluZyBhYm91dCB0aGlzIGNvbW1hbmQuCi0gSW4gdGhlIHNlY29uZCBjYWxsIG9mIGBnZ3Bsb3QoKWAgY2hhbmdlIHRoZSBgY29sb3JgIGFyZ3VtZW50IGluIGBhZXMoKWAgKHdoaWNoIHN0YW5kcyBmb3IgYWVzdGhldGljcykuIFRoZSBjb2xvciBzaG91bGQgYmUgZGVwZW5kZW50IG9uIHRoZSBkaXNwbGFjZW1lbnQgb2YgdGhlIGNhciBlbmdpbmUsIGZvdW5kIGluIGBkaXNwYC4KLSBJbiB0aGUgdGhpcmQgY2FsbCBvZiBgZ2dwbG90KClgIGNoYW5nZSB0aGUgYHNpemVgIGFyZ3VtZW50IGluIGBhZXMoKWAgKHdoaWNoIHN0YW5kcyBmb3IgYWVzdGhldGljcykuIFRoZSBzaXplIHNob3VsZCBiZSBkZXBlbmRlbnQgb24gdGhlIGRpc3BsYWNlbWVudCBvZiB0aGUgY2FyIGVuZ2luZSwgZm91bmQgaW4gYGRpc3BgLgoKYGBge3J9CiMgQSBzY2F0dGVyIHBsb3QgaGFzIGJlZW4gbWFkZSBmb3IgeW91CmdncGxvdChtdGNhcnMsIGFlcyh4ID0gd3QsIHkgPSBtcGcpKSArCiAgZ2VvbV9wb2ludCgpCgojIFJlcGxhY2UgX19fIHdpdGggdGhlIGNvcnJlY3QgY29sdW1uCmdncGxvdChtdGNhcnMsIGFlcyh4ID0gd3QsIHkgPSBtcGcsIGNvbG9yID0gX19fKSkgKwogIGdlb21fcG9pbnQoKQoKIyBSZXBsYWNlIF9fXyB3aXRoIHRoZSBjb3JyZWN0IGNvbHVtbgpnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IHd0LCB5ID0gbXBnLCBzaXplID0gX19fKSkgKwogIGdlb21fcG9pbnQoKQoKYGBgCgoKIyMgVW5kZXJzdGFuZGluZyBWYXJpYWJsZXMKCkluIHRoZSBwcmV2aW91cyBleGVyY2lzZSB5b3Ugc2F3IHRoYXQgYGRpc3BgIGNhbiBiZSBtYXBwZWQgb250byBhIGNvbG9yIGdyYWRpZW50IG9yIG9udG8gYSBjb250aW51b3VzIHNpemUgc2NhbGUuCgpBbm90aGVyIGFyZ3VtZW50IG9mIGBhZXMoKWAgaXMgdGhlIHNoYXBlIG9mIHRoZSBwb2ludHMuIFRoZXJlIGFyZSBhIGZpbml0ZSBudW1iZXIgb2Ygc2hhcGVzIHdoaWNoIGBnZ3Bsb3QoKWAgY2FuIGF1dG9tYXRpY2FsbHkgYXNzaWduIHRvIHRoZSBwb2ludHMuIEhvd2V2ZXIsIGlmIHlvdSB0cnkgdGhpcyBjb21tYW5kIGluIHRoZSBjb25zb2xlIHRvIHRoZSByaWdodDoKCmBgYHtyfQpnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IHd0LCB5ID0gbXBnLCBzaGFwZSA9IGRpc3ApKSArCiAgZ2VvbV9wb2ludCgpCmBgYAoKSXQgZ2l2ZXMgYW4gZXJyb3IuIFdoYXQgZG9lcyB0aGlzIG1lYW4/CgojIyMgSW5zdHJ1Y3Rpb25zCgpQb3NzaWJsZSBBbnN3ZXJzCgotIHNoYXBlIGlzIG5vdCBhIGRlZmluZWQgYXJndW1lbnQuCi0gc2hhcGUgb25seSBtYWtlcyBzZW5zZSB3aXRoIGNhdGVnb3JpY2FsIGRhdGEsIGFuZCBkaXNwIGlzIGNvbnRpbnVvdXMuCi0gc2hhcGUgb25seSBtYWtlcyBzZW5zZSB3aXRoIGNvbnRpbnVvdXMgZGF0YSwgYW5kIGRpc3AgaXMgY2F0ZWdvcmljYWwuCi0gc2hhcGUgaXMgbm90IGEgdmFyaWFibGUgaW4geW91ciBkYXRhc2V0LgotIHNoYXBlIGhhcyB0byBiZSBkZWZpbmVkIGFzIGEgZnVuY3Rpb24uCgoKIyMgRXhwbG9yaW5nIGBnZ3Bsb3QyYCwgcGFydCA0CgpUaGUgYGRpYW1vbmRzYCBkYXRhIGZyYW1lIGNvbnRhaW5zIGluZm9ybWF0aW9uIG9uIHRoZSBwcmljZXMgYW5kIHZhcmlvdXMgbWV0cmljcyBvZiA1MCwwMDAgZGlhbW9uZHMuIEFtb25nIHRoZSB2YXJpYWJsZXMgaW5jbHVkZWQgYXJlIGBjYXJhdGAgKGEgbWVhc3VyZW1lbnQgb2YgdGhlIHNpemUgb2YgdGhlIGRpYW1vbmQpIGFuZCBwcmljZS4gRm9yIHRoZSBuZXh0IGV4ZXJjaXNlcywgeW91J2xsIGJlIHVzaW5nIGEgc3Vic2V0IG9mIDEsMDAwIGRpYW1vbmRzLgoKSGVyZSB5b3UnbGwgdXNlIHR3byBjb21tb24gZ2VvbSBsYXllciBmdW5jdGlvbnM6IGBnZW9tX3BvaW50KClgIGFuZCBgZ2VvbV9zbW9vdGgoKWAuIFdlIGFscmVhZHkgc2F3IGluIHRoZSBlYXJsaWVyIGV4ZXJjaXNlcyBob3cgdGhlc2UgYXJlIGFkZGVkIHVzaW5nIHRoZSBgK2Agb3BlcmF0b3IuCgojIyMgSW5zdHJ1Y3Rpb25zCgotIEV4cGxvcmUgdGhlIGBkaWFtb25kc2AgZGF0YSBmcmFtZSB3aXRoIHRoZSBgc3RyKClgIGZ1bmN0aW9uLgotIFVzZSB0aGUgYCtgIG9wZXJhdG9yIHRvIGFkZCBgZ2VvbV9wb2ludCgpYCB0byB0aGUgZmlyc3QgYGdncGxvdCgpYCBjb21tYW5kLiBUaGlzIHdpbGwgdGVsbCBgZ2dwbG90MmAgdG8gZHJhdyBwb2ludHMgb24gdGhlIHBsb3QuCi0gVXNlIHRoZSBgK2Agb3BlcmF0b3IgdG8gYWRkIGBnZW9tX3BvaW50KClgIGFuZCBgZ2VvbV9zbW9vdGgoKWAuIFRoZXNlIGp1c3Qgc3RhY2sgb24gZWFjaCBvdGhlciEgYGdlb21fc21vb3RoKClgIHdpbGwgZHJhdyBhIHNtb290aGVkIGxpbmUgb3ZlciB0aGUgcG9pbnRzLgoKYGBge3J9CiMgRXhwbG9yZSB0aGUgZGlhbW9uZHMgZGF0YSBmcmFtZSB3aXRoIHN0cigpCgoKIyBBZGQgZ2VvbV9wb2ludCgpIHdpdGggKwpnZ3Bsb3QoZGlhbW9uZHMsIGFlcyh4ID0gY2FyYXQsIHkgPSBwcmljZSkpCgoKIyBBZGQgZ2VvbV9wb2ludCgpIGFuZCBnZW9tX3Ntb290aCgpIHdpdGggKwpnZ3Bsb3QoZGlhbW9uZHMsIGFlcyh4ID0gY2FyYXQsIHkgPSBwcmljZSkpCgoKYGBgCgoKIyMgRXhwbG9yaW5nIGBnZ3Bsb3QyYCwgcGFydCA1CgpUaGUgY29kZSBmb3IgbGFzdCBwbG90IG9mIHRoZSBwcmV2aW91cyBleGVyY2lzZSBpcyBhdmFpbGFibGUgaW4gdGhlIHNjcmlwdCBvbiB0aGUgcmlnaHQuIEl0IGJ1aWxkcyBhIHNjYXR0ZXIgcGxvdCBvZiB0aGUgYGRpYW1vbmRzYCBkYXRhc2V0LCB3aXRoIGBjYXJhdGAgb24gdGhlIHgtYXhpcyBhbmQgYHByaWNlYCBvbiB0aGUgeS1heGlzLiBgZ2VvbV9zbW9vdGgoKWAgaXMgdXNlZCB0byBhZGQgYSBzbW9vdGggbGluZS4KCldpdGggdGhpcyBwbG90IGFzIGEgc3RhcnRpbmcgcG9pbnQsIGxldCdzIGV4cGxvcmUgc29tZSBtb3JlIHBvc3NpYmlsaXRpZXMgb2YgY29tYmluaW5nIGdlb21zLgoKIyMjIEluc3RydWN0aW9ucwoKLSBQbG90IDIgLSBDb3B5IGFuZCBwYXN0ZSBwbG90IDEsIGJ1dCBzaG93IG9ubHkgdGhlIHNtb290aCBsaW5lLCBubyBwb2ludHMuCi0gUGxvdCAzIC0gU2hvdyBvbmx5IHRoZSBzbW9vdGggbGluZSwgYnV0IGNvbG9yIGFjY29yZGluZyB0byBjbGFyaXR5IGJ5IHBsYWNpbmcgdGhlIGFyZ3VtZW50IGBjb2xvciA9IGNsYXJpdHlgIGluIHRoZSBgYWVzKClgIGZ1bmN0aW9uIG9mIHlvdXIgYGdncGxvdCgpYCBjYWxsLgotIFBsb3QgNCAtIERyYXcgdHJhbnNsdWNlbnQgY29sb3JlZCBwb2ludHMuCiAgIC0gQ29weSB0aGUgYGdncGxvdCgpYCBjb21tYW5kIGZyb20gcGxvdCAzICh3aXRoIGBjbGFyaXR5YCBtYXBwZWQgdG8gYGNvbG9yYCkuCiAgIC0gUmVtb3ZlIHRoZSBzbW9vdGggbGF5ZXIuCiAgIC0gQWRkIHRoZSBwb2ludHMgbGF5ZXIgYmFjayBpbi4KICAgLSBTZXQgYGFscGhhID0gMC40YCBpbnNpZGUgYGdlb21fcG9pbnQoKWAuIFRoaXMgd2lsbCBtYWtlIHRoZSBwb2ludHMgNDAlIHRyYW5zcGFyZW50LgoKYGBge3J9CiMgMSAtIFRoZSBwbG90IHlvdSBjcmVhdGVkIGluIHRoZSBwcmV2aW91cyBleGVyY2lzZQpnZ3Bsb3QoZGlhbW9uZHMsIGFlcyh4ID0gY2FyYXQsIHkgPSBwcmljZSkpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fc21vb3RoKCkKCiMgMiAtIENvcHkgdGhlIGFib3ZlIGNvbW1hbmQgYnV0IHNob3cgb25seSB0aGUgc21vb3RoIGxpbmUKCgoKIyAzIC0gQ29weSB0aGUgYWJvdmUgY29tbWFuZCBhbmQgYXNzaWduIHRoZSBjb3JyZWN0IHZhbHVlIHRvIGNvbCBpbiBhZXMoKQoKCgojIDQgLSBLZWVwIHRoZSBjb2xvciBzZXR0aW5ncyBmcm9tIHByZXZpb3VzIGNvbW1hbmQuIFBsb3Qgb25seSB0aGUgcG9pbnRzIHdpdGggYXJndW1lbnQgYWxwaGEuCgoKYGBgCgoKIyMgVW5kZXJzdGFuZGluZyB0aGUgZ3JhbW1hciwgcGFydCAxCgpIZXJlIHlvdSdsbCBleHBsb3JlIHNvbWUgb2YgdGhlIGRpZmZlcmVudCBncmFtbWF0aWNhbCBlbGVtZW50cy4gVGhyb3VnaG91dCB0aGlzIGNvdXJzZSwgeW91J2xsIGRpc2NvdmVyIGhvdyB0aGV5IGNhbiBiZSBjb21iaW5lZCBpbiBhbGwgc29ydHMgb2Ygd2F5cyB0byBkZXZlbG9wIHVuaXF1ZSBwbG90cy4KCkluIHRoZSBmb2xsb3dpbmcgaW5zdHJ1Y3Rpb25zLCB5b3UnbGwgc3RhcnQgYnkgY3JlYXRpbmcgYSBgZ2dwbG90YCBvYmplY3QgZnJvbSB0aGUgZGlhbW9uZHMgZGF0YXNldC4gTmV4dCwgeW91J2xsIGFkZCBsYXllcnMgb250byB0aGlzIG9iamVjdCB0byBidWlsZCBiZWF1dGlmdWwgJiBpbmZvcm1hdGl2ZSBwbG90cy4KCiMjIyBJbnN0cnVjdGlvbnMKCi0gRGVmaW5lIHRoZSBkYXRhIChgZGlhbW9uZHNgKSBhbmQgYWVzdGhldGljcyBsYXllcnMuIE1hcCBgY2FyYXRgIG9uIHRoZSB4IGF4aXMgYW5kIGBwcmljZWAgb24gdGhlIHkgYXhpcy4gQXNzaWduIGl0IHRvIGFuIG9iamVjdDogYGRpYV9wbG90YC4KLSBVc2luZyBgK2AsIGFkZCBhIGBnZW9tX3BvaW50KClgIGxheWVyICh3aXRoIG5vIGFyZ3VtZW50cyksIHRvIHRoZSBgZGlhX3Bsb3RgIG9iamVjdC4gVGhpcyBjYW4gYmUgaW4gYSBzaW5nbGUgb3IgbXVsdGlwbGUgbGluZXMuCi0gTm90ZSB0aGF0IHlvdSBjYW4gYWxzbyBjYWxsIGBhZXMoKWAgd2l0aGluIHRoZSBgZ2VvbV9wb2ludCgpYCBmdW5jdGlvbi4gTWFwIGBjbGFyaXR5YCB0byB0aGUgYGNvbG9yYCBhcmd1bWVudCBpbiB0aGlzIHdheS4KCmBgYHtyfQojIENyZWF0ZSB0aGUgb2JqZWN0IGNvbnRhaW5pbmcgdGhlIGRhdGEgYW5kIGFlcyBsYXllcnM6IGRpYV9wbG90Cl9fXyA8LSBnZ3Bsb3QoX19fLCBhZXMoeCA9IF9fXywgeSA9IF9fXykKCiMgQWRkIGEgZ2VvbSBsYXllciB3aXRoICsgYW5kIGdlb21fcG9pbnQoKQpfX18gKyBfX18oKQoKIyBBZGQgdGhlIHNhbWUgZ2VvbSBsYXllciwgYnV0IHdpdGggYWVzKCkgaW5zaWRlCl9fXyArIF9fXyhhZXMoY29sb3IgPSBfX18pCgpgYGAKCgojIyBVbmRlcnN0YW5kaW5nIHRoZSBncmFtbWFyLCBwYXJ0IDIKCkNvbnRpbnVpbmcgd2l0aCB0aGUgcHJldmlvdXMgZXhlcmNpc2UsIGhlcmUgeW91J2xsIGV4cGxvcmUgbWl4aW5nIGFyZ3VtZW50cyBhbmQgYWVzdGhldGljcyBpbiBhIHNpbmdsZSBnZW9tZXRyeS4KCllvdSdyZSBzdGlsbCB3b3JraW5nIG9uIHRoZSBgZGlhbW9uZHNgIGRhdGFzZXQuCgojIyMgSW5zdHJ1Y3Rpb25zCgotIFRoZSBgZGlhX3Bsb3RgIG9iamVjdCBoYXMgYmVlbiBjcmVhdGVkIGZvciB5b3UuCi0gVXBkYXRlIGBkaWFfcGxvdGAgc28gdGhhdCBpdCBjb250YWlucyBhbGwgdGhlIGZ1bmN0aW9ucyB0byBtYWtlIGEgc2NhdHRlciBwbG90IGJ5IHVzaW5nIGBnZW9tX3BvaW50KClgIGZvciB0aGUgZ2VvbSBsYXllci4gU2V0IGBhbHBoYSA9IDAuMmAuCi0gVXNpbmcgYCtgLCBwbG90IHRoZSBgZGlhX3Bsb3RgIG9iamVjdCB3aXRoIGEgYGdlb21fc21vb3RoKClgIGxheWVyIG9uIHRvcC4gWW91IGRvbid0IHdhbnQgYW55IGVycm9yIHNoYWRpbmcsIHdoaWNoIGNhbiBiZSBhY2hpZXZlZCBieSBzZXR0aW5nIHRoZSBgc2UgPSBGQUxTRWAgaW4gYGdlb21fc21vb3RoKClgLgotIE1vZGlmeSB0aGUgYGdlb21fc21vb3RoKClgIGZ1bmN0aW9uIGZyb20gdGhlIHByZXZpb3VzIGluc3RydWN0aW9uIHNvIHRoYXQgaXQgY29udGFpbnMgYGFlcygpYCBhbmQgbWFwIGBjbGFyaXR5YCB0byB0aGUgYGNvbGAgYXJndW1lbnQuCgpgYGB7cn0KIyAxIC0gVGhlIGRpYV9wbG90IG9iamVjdCBoYXMgYmVlbiBjcmVhdGVkIGZvciB5b3UKZGlhX3Bsb3QgPC0gZ2dwbG90KGRpYW1vbmRzLCBhZXMoeCA9IGNhcmF0LCB5ID0gcHJpY2UpKQoKIyAyIC0gRXhwYW5kIGRpYV9wbG90IGJ5IGFkZGluZyBnZW9tX3BvaW50KCkgd2l0aCBhbHBoYSBzZXQgdG8gMC4yCmRpYV9wbG90IDwtIGRpYV9wbG90ICsgX19fKCkKCiMgMyAtIFBsb3QgZGlhX3Bsb3Qgd2l0aCBhZGRpdGlvbmFsIGdlb21fc21vb3RoKCkgd2l0aCBzZSBzZXQgdG8gRkFMU0UKZGlhX3Bsb3QgKyBfX18oX19fID0gX19fKQoKIyA0IC0gQ29weSB0aGUgY29tbWFuZCBmcm9tIGFib3ZlIGFuZCBhZGQgYWVzKCkgd2l0aCB0aGUgY29ycmVjdCBtYXBwaW5nIHRvIGdlb21fc21vb3RoKCkKZGlhX3Bsb3QgKyBfX18oYWVzKF9fXyA9IF9fXyksIF9fXyA9IF9fXykKCmBgYAoKCiMgRGF0YQoKIyMgYGJhc2VgIHBhY2thZ2UgYW5kIGBnZ3Bsb3QyYCwgcGFydCAxIC0gYHBsb3RgCgpUaGVzZSBjb3Vyc2VzIGFyZSBhYm91dCB1bmRlcnN0YW5kaW5nIGRhdGEgdmlzdWFsaXphdGlvbiBpbiB0aGUgY29udGV4dCBvZiB0aGUgZ3JhbW1hciBvZiBncmFwaGljcy4gVG8gZ2FpbiBhIGJldHRlciBhcHByZWNpYXRpb24gb2YgYGdncGxvdDJgIGFuZCB0byB1bmRlcnN0YW5kIGhvdyBpdCBvcGVyYXRlcyBkaWZmZXJlbnRseSBmcm9tIGBiYXNlYCBwYWNrYWdlLCBpdCdzIHVzZWZ1bCB0byBtYWtlIHNvbWUgY29tcGFyaXNvbnMuCgpGaXJzdCwgbGV0J3MgZm9jdXMgb24gYmFzZSBwYWNrYWdlLiBZb3Ugd2FudCB0byBtYWtlIGEgcGxvdCBvZiBgbXBnYCAobWlsZXMgcGVyIGdhbGxvbikgYWdhaW5zdCBgd3RgICh3ZWlnaHQgaW4gdGhvdXNhbmRzIG9mIHBvdW5kcykgaW4gdGhlIGBtdGNhcnNgIGRhdGEgZnJhbWUsIGJ1dCB0aGlzIHRpbWUgeW91IHdhbnQgdGhlIGRvdHMgY29sb3JlZCBhY2NvcmRpbmcgdG8gdGhlIG51bWJlciBvZiBjeWxpbmRlcnMsIGBjeWxgLiBIb3cgd291bGQgeW91IGRvIHRoYXQgaW4gYmFzZSBwYWNrYWdlPyBZb3UgY2FuIHVzZSBhIGxpdHRsZSB0cmljayB0byBjb2xvciB0aGUgZG90cyBieSBzcGVjaWZ5aW5nIGEgYGZhY3RvcmAgdmFyaWFibGUgYXMgYSBjb2xvci4gVGhpcyB3b3JrcyBiZWNhdXNlIGZhY3RvcnMgYXJlIGp1c3QgYSBzcGVjaWFsIGNsYXNzIG9mIHRoZSBgaW50ZWdlcmAgdHlwZS4KCiMjIyBJbnN0cnVjdGlvbnMKCi0gVXNpbmcgdGhlIGBiYXNlYCBwYWNrYWdlIGBwbG90KClgLCBtYWtlIGEgc2NhdHRlciBwbG90IHdpdGggYG10Y2FycyR3dGAgb24gdGhlIHgtYXhpcyBhbmQgYG10Y2FycyRtcGdgIG9uIHRoZSB5LWF4aXMsIGNvbG9yZWQgYWNjb3JkaW5nIHRvIGBtdGNhcnMkY3lsYCAodXNlIHRoZSBgY29sYCBhcmd1bWVudCkuIFlvdSBjYW4gc3BlY2lmeSBgZGF0YSA9YCBidXQgeW91J2xsIGp1c3QgZG8gaXQgdGhlIGxvbmcgd2F5IGhlcmUuCi0gQWRkIGEgbmV3IGNvbHVtbiwgYGZjeWxgLCB0byB0aGUgYG10Y2Fyc2AgZGF0YSBmcmFtZS4gVGhpcyBzaG91bGQgYmUgYGN5bGAgY29udmVydGVkIHRvIGEgZmFjdG9yLgotIENyZWF0ZSBhIHNpbWlsYXIgcGxvdCB0byBpbnN0cnVjdGlvbiAxLCBidXQgdGhpcyB0aW1lLCB1c2UgYGZjeWxgICh3aGljaCBpcyBgY3lsYCBhcyBhIGZhY3RvcikgdG8gc2V0IHRoZSBgY29sYC4KCmBgYHtyfQojIFBsb3QgdGhlIGNvcnJlY3QgdmFyaWFibGVzIG9mIG10Y2FycwpwbG90KG10Y2FycyRfX18sIG10Y2FycyRfX18sIF9fXyA9IG10Y2FycyRfX18pCgojIENoYW5nZSBjeWwgaW5zaWRlIG10Y2FycyB0byBhIGZhY3RvcgptdGNhcnMkZmN5bCA8LSBhcy5mYWN0b3IoX19fJF9fXykKCiMgTWFrZSB0aGUgc2FtZSBwbG90IGFzIGluIHRoZSBmaXJzdCBpbnN0cnVjdGlvbgoKYGBgCgoKIyMgYGJhc2VgIHBhY2thZ2UgYW5kIGBnZ3Bsb3QyYCwgcGFydCAyIC0gYGxtYAoKSWYgeW91IHdhbnQgdG8gYWRkIGEgbGluZWFyIG1vZGVsIHRvIHlvdXIgcGxvdCwgc2hvd24gcmlnaHQsIHlvdSBjYW4gZGVmaW5lIGl0IHdpdGggYGxtKClgIGFuZCB0aGVuIHBsb3QgdGhlIHJlc3VsdGluZyBsaW5lYXIgbW9kZWwgd2l0aCBgYWJsaW5lKClgLiBIb3dldmVyLCBpZiB5b3Ugd2FudCBhIG1vZGVsIGZvciBlYWNoIHN1Ymdyb3VwLCBhY2NvcmRpbmcgdG8gY3lsaW5kZXJzLCB0aGVuIHlvdSBoYXZlIGEgY291cGxlIG9mIG9wdGlvbnMuCgpZb3UgY2FuIHN1YnNldCB5b3VyIGRhdGEsIGFuZCB0aGVuIGNhbGN1bGF0ZSB0aGUgYGxtKClgIGFuZCBwbG90IGVhY2ggc3Vic2V0IHNlcGFyYXRlbHkuIEFsdGVybmF0aXZlbHksIHlvdSBjYW4gdmVjdG9yaXplIG92ZXIgdGhlIGBjeWxgIHZhcmlhYmxlIHVzaW5nIGBsYXBwbHkoKWAgYW5kIGNvbWJpbmUgdGhpcyBhbGwgaW4gb25lIHN0ZXAuIFRoaXMgb3B0aW9uIGlzIGFscmVhZHkgcHJlcGFyZWQgZm9yIHlvdS4KClRoZSBjb2RlIGJlbG93IGNvbnRhaW5zIGEgY2FsbCB0byB0aGUgZnVuY3Rpb24gYGxhcHBseSgpYCwgd2hpY2ggeW91IG1pZ2h0IG5vdCBoYXZlIHNlZW4gYmVmb3JlLiBUaGlzIGZ1bmN0aW9uIHRha2VzIGFzIGlucHV0IGEgdmVjdG9yIGFuZCBhIGZ1bmN0aW9uLiBUaGVuIGBsYXBwbHkoKWAgYXBwbGllcyB0aGUgZnVuY3Rpb24gaXQgd2FzIGdpdmVuIHRvIGVhY2ggZWxlbWVudCBvZiB0aGUgdmVjdG9yIGFuZCByZXR1cm5zIHRoZSByZXN1bHRzIGluIGEgbGlzdC4gSW4gdGhpcyBjYXNlLCBgbGFwcGx5KClgIHRha2VzIGVhY2ggZWxlbWVudCBvZiBgbXRjYXJzJGN5bGAgYW5kIGNhbGxzIHRoZSBmdW5jdGlvbiBkZWZpbmVkIGluIHRoZSBzZWNvbmQgYXJndW1lbnQuIFRoaXMgZnVuY3Rpb24gdGFrZXMgYSB2YWx1ZSBvZiBgbXRjYXJzJGN5bGAgYW5kIHRoZW4gc3Vic2V0cyB0aGUgZGF0YSBzbyB0aGF0IG9ubHkgcm93cyB3aXRoIGBjeWwgPT0geGAgYXJlIHVzZWQuIFRoZW4gaXQgZml0cyBhIGxpbmVhciBtb2RlbCB0byB0aGUgZmlsdGVyZWQgZGF0YXNldCBhbmQgdXNlcyB0aGF0IG1vZGVsIHRvIGFkZCBhIGxpbmUgdG8gdGhlIHBsb3Qgd2l0aCB0aGUgYGFibGluZSgpYCBmdW5jdGlvbi4KCk5vdyB0aGF0IHlvdSBoYXZlIGFuIGludGVyZXN0aW5nIHBsb3QsIHRoZXJlIGlzIGEgdmVyeSBpbXBvcnRhbnQgYXNwZWN0IG1pc3NpbmcgLSB0aGUgbGVnZW5kIQoKSW4gYmFzZSBwYWNrYWdlIHlvdSBoYXZlIHRvIHRha2UgY2FyZSBvZiB0aGlzIHVzaW5nIHRoZSBgbGVnZW5kKClgIGZ1bmN0aW9uLiBUaGlzIGhhcyBiZWVuIGRvbmUgZm9yIHlvdSBpbiB0aGUgcHJlZGVmaW5lZCBjb2RlLgoKIyMjIEluc3RydWN0aW9ucwoKLSBGaWxsIGluIHRoZSBgbG0oKWAgZnVuY3Rpb24gdG8gY2FsY3VsYXRlIGEgbGluZWFyIG1vZGVsIG9mIGBtcGdgIGRlc2NyaWJlZCBieSBgd3RgIGFuZCBzYXZlIGl0IGFzIGFuIG9iamVjdCBjYWxsZWQgYGNhck1vZGVsYC4KLSBEcmF3IHRoZSBsaW5lYXIgbW9kZWwgb24gdGhlIHNjYXR0ZXJwbG90LgogICAtIFdyaXRlIGNvZGUgdGhhdCBjYWxscyBgYWJsaW5lKClgIHdpdGggYGNhck1vZGVsYCBhcyB0aGUgZmlyc3QgYXJndW1lbnQuIFNldCB0aGUgbGluZSB0eXBlIGJ5IHBhc3NpbmcgdGhlIGFyZ3VtZW50IGBsdHkgPSAyYC4KICAgLSBSdW4gdGhlIGNvZGUgdGhhdCBnZW5lcmF0ZXMgdGhlIGJhc2ljIHBsb3QgYW5kIHRoZSBjYWxsIHRvIGBhYmxpbmUoKWAgYWxsIGF0IG9uY2UgYnkgaGlnaGxpZ2h0aW5nIGJvdGggcGFydHMgb2YgdGhlIHNjcmlwdCBhbmQgaGl0dGluZyBgY29udHJvbC9jb21tYW5kYCArIGBlbnRlcmAgb24geW91ciBrZXlib2FyZC4gVGhlc2UgbGluZXMgbXVzdCBhbGwgYmUgcnVuIHRvZ2V0aGVyIGluIHRoZSBjb25zb2xlIHNvIHRoYXQgUiB3aWxsIGJlIGFibGUgdG8gZmluZCB0aGUgcGxvdCB5b3Ugd2FudCB0byBhZGQgYSBsaW5lIHRvLgotIFJ1biB0aGUgY29kZSBhbHJlYWR5IGdpdmVuIHRvIGdlbmVyYXRlIHRoZSBwbG90IHdpdGggYSBkaWZmZXJlbnQgbW9kZWwgZm9yIGVhY2ggZ3JvdXAuIFlvdSBkb24ndCBuZWVkIHRvIG1vZGlmeSBhbnkgb2YgdGhpcy4KCmBgYHtyfQojIFVzZSBsbSgpIHRvIGNhbGN1bGF0ZSBhIGxpbmVhciBtb2RlbCBhbmQgc2F2ZSBpdCBhcyBjYXJNb2RlbApfX18gPC0gbG0oX19fIH4gX19fLCBkYXRhID0gbXRjYXJzKQoKIyBCYXNpYyBwbG90Cm10Y2FycyRjeWwgPC0gYXMuZmFjdG9yKG10Y2FycyRjeWwpCnBsb3QobXRjYXJzJHd0LCBtdGNhcnMkbXBnLCBjb2wgPSBtdGNhcnMkY3lsKQoKIyBDYWxsIGFibGluZSgpIHdpdGggY2FyTW9kZWwgYXMgZmlyc3QgYXJndW1lbnQgYW5kIHNldCBsdHkgdG8gMgpfX18oX19fLCBsdHkgPSBfX18pCgojIFBsb3QgZWFjaCBzdWJzZXQgZWZmaWNpZW50bHkgd2l0aCBsYXBwbHkKIyBZb3UgZG9uJ3QgaGF2ZSB0byBlZGl0IHRoaXMgY29kZQpwbG90KG10Y2FycyR3dCwgbXRjYXJzJG1wZywgY29sID0gbXRjYXJzJGN5bCkKbGFwcGx5KG10Y2FycyRjeWwsIGZ1bmN0aW9uKHgpIHsKICBhYmxpbmUobG0obXBnIH4gd3QsIG10Y2Fycywgc3Vic2V0ID0gKGN5bCA9PSB4KSksIGNvbCA9IHgpCiAgfSkKCiMgVGhpcyBjb2RlIHdpbGwgZHJhdyB0aGUgbGVnZW5kIG9mIHRoZSBwbG90CiMgWW91IGRvbid0IGhhdmUgdG8gZWRpdCB0aGlzIGNvZGUKbGVnZW5kKHggPSA1LCB5ID0gMzMsIGxlZ2VuZCA9IGxldmVscyhtdGNhcnMkY3lsKSwKICAgICAgIGNvbCA9IDE6MywgcGNoID0gMSwgYnR5ID0gIm4iKQpgYGAKCgojIyBgYmFzZWAgcGFja2FnZSBhbmQgYGdncGxvdDJgLCBwYXJ0IDMKCkluIHRoaXMgZXhlcmNpc2UgeW91J2xsIHJlY3JlYXRlIHRoZSBiYXNlIHBhY2thZ2UgcGxvdCBpbiBgZ2dwbG90MmAuCgpUaGUgY29kZSBmb3IgYmFzZSBSIHBsb3R0aW5nIGlzIGdpdmVuIGF0IHRoZSB0b3AuIFRoZSBmaXJzdCBsaW5lIG9mIGNvZGUgYWxyZWFkeSBjb252ZXJ0cyB0aGUgYGN5bGAgdmFyaWFibGUgb2YgYG10Y2Fyc2AgdG8gYSBmYWN0b3IuCgojIyMgSW5zdHJ1Y3Rpb25zCgotIFBsb3QgMTogYWRkIGBnZW9tX3BvaW50KClgIGluIG9yZGVyIHRvIG1ha2UgYSBzY2F0dGVyIHBsb3QuCi0gUGxvdCAyOiBjb3B5IGFuZCBwYXN0ZSBQbG90IDEKLSBBZGQgYSBsaW5lYXIgbW9kZWwgZm9yIGVhY2ggc3Vic2V0IGFjY29yZGluZyB0byBgY3lsYCBieSBhZGRpbmcgYSBgZ2VvbV9zbW9vdGgoKWAgbGF5ZXIKLSBJbnNpZGUgdGhpcyBgZ2VvbV9zbW9vdGgoKWAsIHNldCBtZXRob2QgdG8gYCJsbSJgIGFuZCBgc2VgIHRvIGBGQUxTRWAuIE5vdGU6IGBnZW9tX3Ntb290aCgpYCB3aWxsIGF1dG9tYXRpY2FsbHkgZHJhdyBhIGxpbmUgcGVyIGBjeWxgIHN1YnNldC4gSXQgcmVjb2duaXplcyB0aGUgZ3JvdXBzIHlvdSB3YW50IHRvIGlkZW50aWZ5IGJ5IGBjb2xvcmAgaW4gdGhlIGBhZXMoKWAgY2FsbCB3aXRoaW4gdGhlIGBnZ3Bsb3QoKWAgY29tbWFuZC4KLSBQbG90IDM6IGNvcHkgYW5kIHBhc3RlIFBsb3QgMgotIFBsb3QgYSBsaW5lYXIgbW9kZWwgZm9yIHRoZSBlbnRpcmUgZGF0YXNldCwgZG8gdGhpcyBieSBhZGRpbmcgYW5vdGhlciBgZ2VvbV9zbW9vdGgoKWAgbGF5ZXIKLSBTZXQgdGhlIGBncm91cGAgYWVzdGhldGljIGluc2lkZSB0aGlzIGBnZW9tX3Ntb290aCgpYCBsYXllciB0byBgMWAuIFRoaXMgaGFzIHRvIGJlIHNldCB3aXRoaW4gdGhlIGBhZXMoKWAgZnVuY3Rpb24uCi0gU2V0IGBtZXRob2RgIHRvIGAibG0iYCwgYHNlYCB0byBgRkFMU0VgIGFuZCBgbGluZXR5cGVgIHRvIGAyYC4gVGhlc2UgaGF2ZSB0byBiZSBzZXQgb3V0c2lkZSBgYWVzKClgIG9mIHRoZSBgZ2VvbV9zbW9vdGgoKWAuCgpOb3RlOiB0aGUgYGdyb3VwYCBhZXN0aGV0aWMgd2lsbCB0ZWxsIGBnZ3Bsb3QoKWAgdG8gZHJhdyBhIHNpbmdsZSBsaW5lYXIgbW9kZWwgdGhyb3VnaCBhbGwgdGhlIHBvaW50cy4KCmBgYHtyfQojIENvbnZlcnQgY3lsIHRvIGZhY3RvciAoZG9uJ3QgbmVlZCB0byBjaGFuZ2UpCm10Y2FycyRjeWwgPC0gYXMuZmFjdG9yKG10Y2FycyRjeWwpCgojIEV4YW1wbGUgZnJvbSBiYXNlIFIgKGRvbid0IG5lZWQgdG8gY2hhbmdlKQpwbG90KG10Y2FycyR3dCwgbXRjYXJzJG1wZywgY29sID0gbXRjYXJzJGN5bCkKYWJsaW5lKGxtKG1wZyB+IHd0LCBkYXRhID0gbXRjYXJzKSwgbHR5ID0gMikKbGFwcGx5KG10Y2FycyRjeWwsIGZ1bmN0aW9uKHgpIHsKICBhYmxpbmUobG0obXBnIH4gd3QsIG10Y2Fycywgc3Vic2V0ID0gKGN5bCA9PSB4KSksIGNvbCA9IHgpCiAgfSkKbGVnZW5kKHggPSA1LCB5ID0gMzMsIGxlZ2VuZCA9IGxldmVscyhtdGNhcnMkY3lsKSwKICAgICAgIGNvbCA9IDE6MywgcGNoID0gMSwgYnR5ID0gIm4iKQoKIyBQbG90IDE6IGFkZCBnZW9tX3BvaW50KCkgdG8gdGhpcyBjb21tYW5kIHRvIGNyZWF0ZSBhIHNjYXR0ZXIgcGxvdApnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IHd0LCB5ID0gbXBnLCBjb2wgPSBjeWwpKSArCiAgX19fICAjIEZpbGwgaW4gdXNpbmcgaW5zdHJ1Y3Rpb25zIFBsb3QgMQoKIyBQbG90IDI6IGluY2x1ZGUgdGhlIGxpbmVzIG9mIHRoZSBsaW5lYXIgbW9kZWxzLCBwZXIgY3lsCmdncGxvdChtdGNhcnMsIGFlcyh4ID0gd3QsIHkgPSBtcGcsIGNvbCA9IGN5bCkpICsKICBfX18gKyAjIENvcHkgZnJvbSBQbG90IDEKICBfX18gICAjIEZpbGwgaW4gdXNpbmcgaW5zdHJ1Y3Rpb25zIFBsb3QgMgoKIyBQbG90IDM6IGluY2x1ZGUgYSBsbSBmb3IgdGhlIGVudGlyZSBkYXRhc2V0IGluIGl0cyB3aG9sZQpnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IHd0LCB5ID0gbXBnLCBjb2wgPSBjeWwpKSArCiAgX19fICsgIyBDb3B5IGZyb20gUGxvdCAyCiAgX19fICsgIyBDb3B5IGZyb20gUGxvdCAyCiAgX19fICAgIyBGaWxsIGluIHVzaW5nIGluc3RydWN0aW9ucyBQbG90IDMKYGBgCgoKIyMgYGdncGxvdDJgIGNvbXBhcmVkIHRvIGBiYXNlYCBwYWNrYWdlCgpgZ2dwbG90MmAgaGFzIGJlY29tZSB2ZXJ5IHBvcHVsYXIgYW5kIGZvciBtYW55IHBlb3BsZSBpdCdzIHRoZSBnby10byBwbG90dGluZyBwYWNrYWdlIGluIFIuIFdoYXQgZG9lcyBgZ2dwbG90MmAgZG8gdGhhdCBgYmFzZWAgcGFja2FnZSBkb2Vzbid0PwoKIyMjIEFuc3dlciB0aGUgcXVlc3Rpb24KClBvc3NpYmxlIEFuc3dlcnMKCjEuIGBnZ3Bsb3QyYCBjcmVhdGVzIHBsb3R0aW5nIG9iamVjdHMsIHdoaWNoIGNhbiBiZSBtYW5pcHVsYXRlZC4KMi4gYGdncGxvdDJgIHRha2VzIGNhcmUgb2YgYSBsb3Qgb2YgdGhlIGxlZyB3b3JrIGZvciB5b3UsIHN1Y2ggYXMgY2hvb3NpbmcgbmljZSBjb2xvciBwYWxsZXR0ZXMgYW5kIG1ha2luZyBsZWdlbmRzLgozLiBgZ2dwbG90MmAgaXMgYnVpbHQgdXBvbiB0aGUgZ3JhbW1hciBvZiBncmFwaGljcyBwbG90dGluZyBwaGlsb3NvcGh5LCBtYWtpbmcgaXQgbW9yZSBmbGV4aWJsZSBhbmQgaW50dWl0aXZlIGZvciB1bmRlcnN0YW5kaW5nIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB5b3VyIHZpc3VhbHMgYW5kIHlvdXIgZGF0YS4KNC4gT3B0aW9ucyAxLCAyLCBhbmQgMy4KNS4gYGdncGxvdDJgIGlzIGVmZmVjdGl2ZWx5IGEgcmVwbGFjZW1lbnQgZm9yIGFsbCBiYXNlLXBhY2thZ2UgcGxvdHRpbmcgZnVuY3Rpb25zLgoKCiMjIFBsb3R0aW5nIHRoZSBnZ3Bsb3QyIHdheQoKVGhlcmUgYXJlIGRpZmZlcmVudCBgZ2dwbG90MmAgY2FsbHMgdG8gcGxvdCB0d28gZ3JvdXBzIG9mIGRhdGEgb250byB0aGUgc2FtZSBwbG90OgoKYGBge3J9CiMgT3B0aW9uIDEKZ2dwbG90KGlyaXMsIGFlcyh4ID0gU2VwYWwuTGVuZ3RoLCB5ID0gU2VwYWwuV2lkdGgpKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX3BvaW50KGFlcyh4ID0gUGV0YWwuTGVuZ3RoLCB5ID0gUGV0YWwuV2lkdGgpLCBjb2wgPSAicmVkIikKCmlyaXMud2lkZSA8LSByYmluZChkYXRhLmZyYW1lKFNwZWNpZXMgPSBpcmlzJFNwZWNpZXMsIFBhcnQgPSAiU2VwYWwiLCBMZW5ndGggPSBpcmlzJFNlcGFsLkxlbmd0aCwgV2lkdGggPSBpcmlzJFNlcGFsLldpZHRoKSwgZGF0YS5mcmFtZShTcGVjaWVzID0gaXJpcyRTcGVjaWVzLCBQYXJ0ID0gIlBldGFsIiwgTGVuZ3RoID0gaXJpcyRQZXRhbC5MZW5ndGgsIFdpZHRoID0gaXJpcyRQZXRhbC5XaWR0aCkpCgojIE9wdGlvbiAyCmdncGxvdChpcmlzLndpZGUsIGFlcyh4ID0gTGVuZ3RoLCB5ID0gV2lkdGgsIGNvbCA9IFBhcnQpKSArCiAgZ2VvbV9wb2ludCgpCmBgYAoKCldoaWNoIG9uZSBpcyBwcmVmZXJhYmxlPyBCb3RoIGBpcmlzYCBhbmQgYGlyaXMud2lkZWAgYXJlIGF2YWlsYWJsZSBpbiB0aGUgd29ya3NwYWNlLCBzbyB5b3UgY2FuIGV4cGVyaW1lbnQgaW4gdGhlIFIgQ29uc29sZSBzdHJhaWdodCBhd2F5IQoKIyMjIEluc3RydWN0aW9ucwoKUG9zc2libGUgQW5zd2VycwoKLSBPcHRpb24gMS4KLSBPcHRpb24gMi4KLSBCb3RoIGFyZSBlcXVhbGx5IHByZWZlcmFibGUuCgoKIyMgVmFyaWFibGVzIHRvIHZpc3VhbHMsIHBhcnQgMQoKYGBge3J9CmlyaXMud2lkZTIgPC0gcmJpbmQoCiAgIGRhdGEuZnJhbWUoTWVhc3VyZSA9ICJMZW5ndGgiLCBQYXJ0ID0gIlBldGFsIiwgU2V0b3NhID0gaXJpc1tpcmlzJFNwZWNpZXMgPT0gInNldG9zYSIsIlBldGFsLkxlbmd0aCJdLCBWZXJzaWNvbG9yID0gaXJpc1tpcmlzJFNwZWNpZXMgPT0gInZlcnNpY29sb3IiLCJQZXRhbC5MZW5ndGgiXSwgVmlyZ2luaWNhID0gaXJpc1tpcmlzJFNwZWNpZXMgPT0gInZpcmdpbmljYSIsIlBldGFsLkxlbmd0aCJdKSwKICAgZGF0YS5mcmFtZShNZWFzdXJlID0gIldpZHRoIiwgUGFydCA9ICJQZXRhbCIsIFNldG9zYSA9IGlyaXNbaXJpcyRTcGVjaWVzID09ICJzZXRvc2EiLCJQZXRhbC5XaWR0aCJdLCBWZXJzaWNvbG9yID0gaXJpc1tpcmlzJFNwZWNpZXMgPT0gInZlcnNpY29sb3IiLCJQZXRhbC5XaWR0aCJdLCBWaXJnaW5pY2EgPSBpcmlzW2lyaXMkU3BlY2llcyA9PSAidmlyZ2luaWNhIiwiUGV0YWwuV2lkdGgiXSksCiAgIGRhdGEuZnJhbWUoTWVhc3VyZSA9ICJMZW5ndGgiLCBQYXJ0ID0gIlNlcGFsIiwgU2V0b3NhID0gaXJpc1tpcmlzJFNwZWNpZXMgPT0gInNldG9zYSIsIlNlcGFsLkxlbmd0aCJdLCBWZXJzaWNvbG9yID0gaXJpc1tpcmlzJFNwZWNpZXMgPT0gInZlcnNpY29sb3IiLCJTZXBhbC5MZW5ndGgiXSwgVmlyZ2luaWNhID0gaXJpc1tpcmlzJFNwZWNpZXMgPT0gInZpcmdpbmljYSIsIlNlcGFsLkxlbmd0aCJdKSwKICAgZGF0YS5mcmFtZShNZWFzdXJlID0gIldpZHRoIiwgUGFydCA9ICJTZXBhbCIsIFNldG9zYSA9IGlyaXNbaXJpcyRTcGVjaWVzID09ICJzZXRvc2EiLCJTZXBhbC5XaWR0aCJdLCBWZXJzaWNvbG9yID0gaXJpc1tpcmlzJFNwZWNpZXMgPT0gInZlcnNpY29sb3IiLCJTZXBhbC5XaWR0aCJdLCBWaXJnaW5pY2EgPSBpcmlzW2lyaXMkU3BlY2llcyA9PSAidmlyZ2luaWNhIiwiU2VwYWwuV2lkdGgiXSkpCgppcmlzLnRpZHkgPC0gcmJpbmQoCiAgIGRhdGEuZnJhbWUoU3BlY2llcyA9IGlyaXMkU3BlY2llcywgUGFydCA9ICJTZXBhbCIsIE1lYXN1cmUgPSAiTGVuZ3RoIiwgVmFsdWUgPSBpcmlzJFNlcGFsLkxlbmd0aCksCiAgIGRhdGEuZnJhbWUoU3BlY2llcyA9IGlyaXMkU3BlY2llcywgUGFydCA9ICJTZXBhbCIsIE1lYXN1cmUgPSAiV2lkdGgiLCBWYWx1ZSA9IGlyaXMkU2VwYWwuTGVuZ3RoKSwKICAgZGF0YS5mcmFtZShTcGVjaWVzID0gaXJpcyRTcGVjaWVzLCBQYXJ0ID0gIlBldGFsIiwgTWVhc3VyZSA9ICJMZW5ndGgiLCBWYWx1ZSA9IGlyaXMkUGV0YWwuTGVuZ3RoKSwKICAgZGF0YS5mcmFtZShTcGVjaWVzID0gaXJpcyRTcGVjaWVzLCBQYXJ0ID0gIlBldGFsIiwgTWVhc3VyZSA9ICJXaWR0aCIsIFZhbHVlID0gaXJpcyRQZXRhbC5XaWR0aCkpCmBgYAoKClNvIGZhciB5b3UndmUgc2VlbiBmb3VyIGRpZmZlcmVudCBmb3JtcyBvZiB0aGUgaXJpcyBkYXRhc2V0OiBgaXJpc2AsIGBpcmlzLndpZGVgLCBgaXJpcy53aWRlMmAgYW5kIGBpcmlzLnRpZHlgLiBEb24ndCBsZXQgYWxsIHRoZXNlIGRpZmZlcmVudCBmb3JtcyBjb25mdXNlIHlvdSEgSXQncyBleGFjdGx5IHRoZSBzYW1lIGRhdGEsIGp1c3QgcmVhcnJhbmdlZCBzbyB0aGF0IHlvdXIgcGxvdHRpbmcgZnVuY3Rpb25zIGJlY29tZSBlYXNpZXIuCgpUbyBzZWUgdGhpcyBpbiBhY3Rpb24sIGNvbnNpZGVyIHRoZSBwbG90IGluIHRoZSBncmFwaGljcyBkZXZpY2UgYXQgcmlnaHQuIFdoaWNoIGZvcm0gb2YgdGhlIGRhdGFzZXQgd291bGQgYmUgdGhlIG1vc3QgYXBwcm9wcmlhdGUgdG8gdXNlIGhlcmU/CgojIyMgSW5zdHJ1Y3Rpb25zCgotIExvb2sgYXQgdGhlIHN0cnVjdHVyZXMgb2YgYGlyaXNgLCBgaXJpcy53aWRlYCBhbmQgYGlyaXMudGlkeWAgdXNpbmcgYHN0cigpYC4KLSBGaWxsIGluIHRoZSBgZ2dwbG90YCBmdW5jdGlvbiB3aXRoIHRoZSBhcHByb3ByaWF0ZSBkYXRhIGZyYW1lIGFuZCB2YXJpYWJsZSBuYW1lcy4gVGhlIHZhcmlhYmxlIG5hbWVzIG9mIHRoZSBhZXN0aGV0aWNzIG9mIHRoZSBwbG90IHdpbGwgbWF0Y2ggdGhlIG9uZXMgeW91IGZvdW5kIHVzaW5nIHRoZSBgc3RyKClgIGNvbW1hbmQgaW4gdGhlIHByZXZpb3VzIHN0ZXAuCgpgYGB7cn0KIyBDb25zaWRlciB0aGUgc3RydWN0dXJlIG9mIGlyaXMsIGlyaXMud2lkZSBhbmQgaXJpcy50aWR5IChpbiB0aGF0IG9yZGVyKQoKCgoKIyBUaGluayBhYm91dCB3aGljaCBkYXRhc2V0IHlvdSB3b3VsZCB1c2UgdG8gZ2V0IHRoZSBwbG90IHNob3duIHJpZ2h0CiMgRmlsbCBpbiB0aGUgX19fIHRvIHByb2R1Y2UgdGhlIHBsb3QgZ2l2ZW4gdG8gdGhlIHJpZ2h0CmdncGxvdChfX18sIGFlcyh4ID0gX19fLCB5ID0gX19fLCBjb2wgPSBfX18pKSArCiAgZ2VvbV9qaXR0ZXIoKSArCiAgZmFjZXRfZ3JpZCguIH4gX19fKQpgYGAKCgojIyBWYXJpYWJsZXMgdG8gdmlzdWFscywgcGFydCAxYgoKSW4gdGhlIGxhc3QgZXhlcmNpc2UgeW91IHNhdyBob3cgYGlyaXMudGlkeWAgd2FzIHVzZWQgdG8gbWFrZSBhIHNwZWNpZmljIHBsb3QuIEl0J3MgaW1wb3J0YW50IHRvIGtub3cgaG93IHRvIHJlYXJyYW5nZSB5b3VyIGRhdGEgaW4gdGhpcyB3YXkgc28gdGhhdCB5b3VyIHBsb3R0aW5nIGZ1bmN0aW9ucyBiZWNvbWUgZWFzaWVyLiBJbiB0aGlzIGV4ZXJjaXNlIHlvdSdsbCB1c2UgZnVuY3Rpb25zIGZyb20gdGhlIGB0aWR5cmAgcGFja2FnZSB0byBjb252ZXJ0IGBpcmlzYCB0byBgaXJpcy50aWR5YC4KClRoZSByZXN1bHRpbmcgYGlyaXMudGlkeWAgZGF0YSBzaG91bGQgbG9vayBhcyBmb2xsb3dzOgoKYGBgCiAgIFNwZWNpZXMgIFBhcnQgTWVhc3VyZSBWYWx1ZQogMSAgc2V0b3NhIFNlcGFsICBMZW5ndGggICA1LjEKIDIgIHNldG9zYSBTZXBhbCAgTGVuZ3RoICAgNC45CiAzICBzZXRvc2EgU2VwYWwgIExlbmd0aCAgIDQuNwogNCAgc2V0b3NhIFNlcGFsICBMZW5ndGggICA0LjYKIDUgIHNldG9zYSBTZXBhbCAgTGVuZ3RoICAgNS4wCiA2ICBzZXRvc2EgU2VwYWwgIExlbmd0aCAgIDUuNAogICAgLi4uCmBgYAoKWW91IGNhbiBoYXZlIGEgbG9vayBhdCB0aGUgYGlyaXNgIGRhdGFzZXQgYnkgdHlwaW5nIGBoZWFkKGlyaXMpYCBpbiB0aGUgY29uc29sZS4KCk5vdGU6IElmIHlvdSdyZSBub3QgZmFtaWxpYXIgd2l0aCBgJT4lYCwgYGdhdGhlcigpYCBhbmQgYHNlcGFyYXRlKClgLCB5b3UgbWF5IHdhbnQgdG8gdGFrZSB0aGUgYENsZWFuaW5nIERhdGFgIGluIFIgY291cnNlLiBJbiBhIG51dHNoZWxsLCBhIGRhdGFzZXQgaXMgY2FsbGVkIHRpZHkgd2hlbiBldmVyeSByb3cgaXMgYW4gb2JzZXJ2YXRpb24gYW5kIGV2ZXJ5IGNvbHVtbiBpcyBhIHZhcmlhYmxlLiBgVGhlIGdhdGhlcigpYCBmdW5jdGlvbiBtb3ZlcyBpbmZvcm1hdGlvbiBmcm9tIHRoZSBjb2x1bW5zIHRvIHRoZSByb3dzLiBJdCB0YWtlcyBtdWx0aXBsZSBjb2x1bW5zIGFuZCBnYXRoZXJzIHRoZW0gaW50byBhIHNpbmdsZSBjb2x1bW4gYnkgYWRkaW5nIHJvd3MuIFRoZSBgc2VwYXJhdGUoKWAgZnVuY3Rpb24gc3BsaXRzIG9uZSBjb2x1bW4gaW50byB0d28gb3IgbW9yZSBjb2x1bW5zIGFjY29yZGluZyB0byBhIHBhdHRlcm4geW91IGRlZmluZS4gTGFzdGx5LCB0aGUgYCU+JWAgKG9yICJwaXBlIikgb3BlcmF0b3IgcGFzc2VzIHRoZSByZXN1bHQgb2YgdGhlIGxlZnQtaGFuZCBzaWRlIGFzIHRoZSBmaXJzdCBhcmd1bWVudCBvZiB0aGUgZnVuY3Rpb24gb24gdGhlIHJpZ2h0LWhhbmQgc2lkZS4KCiMjIyBJbnN0cnVjdGlvbnMKCllvdSdsbCB1c2UgdHdvIGZ1bmN0aW9ucyBmcm9tIHRoZSBgdGlkeXJgIHBhY2thZ2U6CgotIGBnYXRoZXIoKWAgcmVhcnJhbmdlcyB0aGUgZGF0YSBmcmFtZSBieSBzcGVjaWZ5aW5nIHRoZSBjb2x1bW5zIHRoYXQgYXJlIGNhdGVnb3JpY2FsIHZhcmlhYmxlcyB3aXRoIGEgLSBub3RhdGlvbi4gQ29tcGxldGUgdGhlIGNvbW1hbmQuIE5vdGljZSB0aGF0IG9ubHkgb25lIHZhcmlhYmxlIGlzIGNhdGVnb3JpY2FsIGluIGlyaXMuCi0gYHNlcGFyYXRlKClgIHNwbGl0cyB1cCB0aGUgbmV3IGtleSBjb2x1bW4sIHdoaWNoIGNvbnRhaW5zIHRoZSBmb3JtZXIgaGVhZGVycywgYWNjb3JkaW5nIHRvIGAuYC4gVGhlIG5ldyBjb2x1bW4gbmFtZXMgIlBhcnQiIGFuZCAiTWVhc3VyZSIgYXJlIGdpdmVuIGluIGEgY2hhcmFjdGVyIHZlY3Rvci4gRG9uJ3QgZm9yZ2V0IHRoZSBxdW90ZXMuCgpgYGB7cn0KIyBMb2FkIHRoZSB0aWR5ciBwYWNrYWdlCmxpYnJhcnkodGlkeXIpCgojIEZpbGwgaW4gdGhlIF9fXyB0byBwcm9kdWNlIHRvIHRoZSBjb3JyZWN0IGlyaXMudGlkeSBkYXRhc2V0CmlyaXMudGlkeSA8LSBpcmlzICU+JQogIGdhdGhlcihrZXksIHZhbHVlLCAtX19fKSAlPiUKICBzZXBhcmF0ZShrZXksIGMoIl9fXyIsICJfX18iKSwgIlxcLiIpCmBgYAoKCiMjIFZhcmlhYmxlcyB0byB2aXN1YWxzLCBwYXJ0IDIKCkhlcmUgeW91J2xsIHRha2UgYSBsb29rIGF0IGFub3RoZXIgcGxvdCB2YXJpYW50LiBXaGljaCBvZiB5b3VyIGRhdGEgZnJhbWVzIHdvdWxkIGJlIHVzZWQgdG8gcHJvZHVjZSB0aGlzIHBsb3Q/CgohW10oaW1hZ2VzL3Bsb3QxLnBuZykKCiMjIyBJbnN0cnVjdGlvbnMKCi0gTG9vayBhdCB0aGUgaGVhZHMgb2YgYGlyaXNgLCBgaXJpcy53aWRlYCBhbmQgYGlyaXMudGlkeWAgdXNpbmcgYGhlYWQoKWAuCi0gRmlsbCBpbiB0aGUgYGdncGxvdGAgZnVuY3Rpb24gd2l0aCB0aGUgYXBwcm9wcmlhdGUgZGF0YSBmcmFtZSBhbmQgdmFyaWFibGUgbmFtZXMuIFRoZSBuYW1lcyBvZiB0aGUgYWVzdGhldGljcyBvZiB0aGUgcGxvdCB3aWxsIG1hdGNoIHdpdGggdmFyaWFibGUgbmFtZXMgaW4geW91ciBkYXRhc2V0LiBUaGUgcHJldmlvdXMgaW5zdHJ1Y3Rpb24gd2lsbCBoZWxwIHlvdSBtYXRjaCB2YXJpYWJsZSBuYW1lcyBpbiBkYXRhc2V0cyB3aXRoIHRoZSBvbmVzIGluIHRoZSBwbG90LgoKYGBge3J9CiMgVGhlIDMgZGF0YSBmcmFtZXMgKGlyaXMsIGlyaXMud2lkZSBhbmQgaXJpcy50aWR5KSBhcmUgYXZhaWxhYmxlIGluIHlvdXIgZW52aXJvbm1lbnQKIyBFeGVjdXRlIGhlYWQoKSBvbiBpcmlzLCBpcmlzLndpZGUgYW5kIGlyaXMudGlkeSAoaW4gdGhhdCBvcmRlcikKCgoKCiMgVGhpbmsgYWJvdXQgd2hpY2ggZGF0YXNldCB5b3Ugd291bGQgdXNlIHRvIGdldCB0aGUgcGxvdCBzaG93biByaWdodAojIEZpbGwgaW4gdGhlIF9fXyB0byBwcm9kdWNlIHRoZSBwbG90IGdpdmVuIHRvIHRoZSByaWdodApnZ3Bsb3QoX19fLCBhZXMoeCA9IF9fXywgeSA9IF9fXywgY29sb3IgPSBfX18pKSArCiAgZ2VvbV9qaXR0ZXIoKSArCiAgZmFjZXRfZ3JpZCguIH4gX19fKQpgYGAKCgojIyBWYXJpYWJsZXMgdG8gdmlzdWFscywgcGFydCAyYgoKWW91IHNhdyBwcmV2aW91c2x5IGhvdyB5b3UgY2FuIGRlcml2ZSBgaXJpcy50aWR5YCBmcm9tIGBpcmlzYC4gTm93IHlvdSdsbCBtb3ZlIG9uIHRvIHByb2R1Y2UgYGlyaXMud2lkZWAuCgpUaGUgaGVhZCBvZiB0aGUgYGlyaXMud2lkZWAgc2hvdWxkIGxvb2sgbGlrZSB0aGlzIGluIHRoZSBlbmQ6CgpgYGAKICBTcGVjaWVzICBQYXJ0IExlbmd0aCBXaWR0aAoxICBzZXRvc2EgUGV0YWwgICAgMS40ICAgMC4yCjIgIHNldG9zYSBQZXRhbCAgICAxLjQgICAwLjIKMyAgc2V0b3NhIFBldGFsICAgIDEuMyAgIDAuMgo0ICBzZXRvc2EgUGV0YWwgICAgMS41ICAgMC4yCjUgIHNldG9zYSBQZXRhbCAgICAxLjQgICAwLjIKNiAgc2V0b3NhIFBldGFsICAgIDEuNyAgIDAuNAouLi4KYGBgCgpZb3UgY2FuIGhhdmUgYSBsb29rIGF0IHRoZSBgaXJpc2AgZGF0YXNldCBieSB0eXBpbmcgYGhlYWQoaXJpcylgIGluIHRoZSBjb25zb2xlLgoKIyMjIEluc3RydWN0aW9ucwoKLSBCZWZvcmUgeW91IGJlZ2luLCB5b3UgbmVlZCB0byBhZGQgYSBuZXcgY29sdW1uIGNhbGxlZCBgRmxvd2VyYCB0aGF0IGNvbnRhaW5zIGEgdW5pcXVlIGlkZW50aWZpZXIgZm9yIGVhY2ggcm93IGluIHRoZSBkYXRhIGZyYW1lLiBUaGlzIGlzIGJlY2F1c2UgeW91J2xsIHJlYXJyYW5nZSB0aGUgZGF0YSBmcmFtZSBhZnRlcndhcmRzIGFuZCB5b3UgbmVlZCB0byBrZWVwIHRyYWNrIG9mIHdoaWNoIHJvdywgb3Igd2hpY2ggc3BlY2lmaWMgZmxvd2VyLCBlYWNoIHZhbHVlIGNhbWUgZnJvbS4gSXQncyBkb25lIGZvciB5b3UsIG5vIG5lZWQgdG8gYWRkIGFueXRoaW5nIHlvdXJzZWxmLgotIGBnYXRoZXIoKWAgcmVhcnJhbmdlcyB0aGUgZGF0YSBmcmFtZSBieSBzcGVjaWZ5aW5nIHRoZSBjb2x1bW5zIHRoYXQgYXJlIGNhdGVnb3JpY2FsIHZhcmlhYmxlcyB3aXRoIGEgLSBub3RhdGlvbi4gSW4gdGhpcyBjYXNlLCBgU3BlY2llc2AgYW5kIGBGbG93ZXJgIGFyZSBjYXRlZ29yaWNhbC4gQ29tcGxldGUgdGhlIGNvbW1hbmQuCi0gYHNlcGFyYXRlKClgIHNwbGl0cyB1cCB0aGUgbmV3IGtleSBjb2x1bW4sIHdoaWNoIGNvbnRhaW5zIHRoZSBmb3JtZXIgaGVhZGVycywgYWNjb3JkaW5nIHRvIGAuYC4gVGhlIG5ldyBjb2x1bW4gbmFtZXMgYCJQYXJ0ImAgYW5kIGAiTWVhc3VyZSJgIGFyZSBnaXZlbiBpbiBhIGNoYXJhY3RlciB2ZWN0b3IuCi0gVGhlIGxhc3Qgc3RlcCBpcyB0byB1c2UgYHNwcmVhZCgpYCB0byBkaXN0cmlidXRlIHRoZSBuZXcgYE1lYXN1cmVgIGNvbHVtbiBhbmQgYXNzb2NpYXRlZCBgdmFsdWVgIGNvbHVtbiBpbnRvIHR3byBjb2x1bW5zLgoKYGBge3J9CiMgTG9hZCB0aGUgdGlkeXIgcGFja2FnZQpsaWJyYXJ5KHRpZHlyKQoKIyBBZGQgY29sdW1uIHdpdGggdW5pcXVlIGlkcyAoZG9uJ3QgbmVlZCB0byBjaGFuZ2UpCmlyaXMkRmxvd2VyIDwtIDE6bnJvdyhpcmlzKQoKIyBGaWxsIGluIHRoZSBfX18gdG8gcHJvZHVjZSB0byB0aGUgY29ycmVjdCBpcmlzLndpZGUgZGF0YXNldAppcmlzLndpZGUgPC0gaXJpcyAlPiUKICBnYXRoZXIoa2V5LCB2YWx1ZSwgLVNwZWNpZXMsIC1GbG93ZXIpICU+JQogIHNlcGFyYXRlKGtleSwgYygiX19fIiwgX19fKSwgIlxcLiIpICU+JQogIHNwcmVhZChfX18sIHZhbHVlKQpgYGAKCgoKIyBBZXN0aGV0aWNzCgojIyBBbGwgYWJvdXQgYWVzdGhldGljcywgcGFydCAxClRoZXJlIGFyZSA5IGRpZmZlcmVudCBhZXN0aGV0aWNzIHRoYXQgY2FuIGJlIG1hcHBlZDoKCi0gYHhgOiB0aGUgWC1heGlzIHBvc2l0aW9uCi0gYHlgOiB0aGUgWS1heGlzIHBvc2l0aW9uCi0gYGNvbG9yYDogdGhlIGNvbG9yIG9mIGRvdHMgYW5kIHRoZSBvdXRsaW5lIG9mIG90aGVyIHNoYXBlcwotIGBmaWxsYDogZmlsbCBjb2xvcgotIGBzaXplYDogZGlhbWV0ZXIgb2YgcG9pbnRzLCB0aGlja25lc3Mgb2YgbGluZXMKLSBgYWxwaGFgOiB0aGUgdHJhbnNwYXJlbmN5LCAwLXRyYW5zcGFyZW50LCAxLW9wYXF1ZQotIGBsaW5ldHlwZWA6IGxpbmUgZGFzaCBwYXR0ZXJuCi0gYGxhYmVsc2A6IHRleHQgb24gYSBwbG90IG9yIGF4ZXMKLSBgc2hhcGVgOiB0aGUgc2hhcGUKCkxldCdzIGFwcGx5IHRoZW0gdG8gYSBjYXRlZ29yaWNhbCB2YXJpYWJsZSAtIHRoZSBjeWxpbmRlcnMgaW4gYG10Y2Fyc2AsIGBjeWxgLgoKKFlvdSdsbCBjb25zaWRlciBsaW5lIHR5cGUgd2hlbiB5b3UgZW5jb3VudGVyIGxpbmUgcGxvdHMgaW4gdGhlIG5leHQgY2hhcHRlcikuCgpUaGVzZSBhcmUgdGhlIGFlc3RoZXRpY3MgeW91IGNhbiBjb25zaWRlciB3aXRoaW4gYGFlcygpYCBpbiB0aGlzIGNoYXB0ZXI6IGB4YCwgYHlgLCBgY29sb3JgLCBgZmlsbGAsIGBzaXplYCwgYGFscGhhYCwgYGxhYmVsc2AgYW5kIGBzaGFwZWAuCgpJbiB0aGUgZm9sbG93aW5nIGV4ZXJjaXNlIHlvdSBjYW4gYXNzdW1lIHRoYXQgdGhlIGBjeWxgIGNvbHVtbiBpcyBjYXRlZ29yaWNhbC4gSXQgaGFzIGFscmVhZHkgYmVlbiB0cmFuc2Zvcm1lZCBpbnRvIGEgYGZhY3RvcmAgZm9yIHlvdS4KCiMjIyBJbnN0cnVjdGlvbnMKVGhlIGBtdGNhcnNgIGRhdGEgZnJhbWUgaXMgYXZhaWxhYmxlIGluIHlvdXIgd29ya3NwYWNlLiBGb3IgZWFjaCBvZiB0aGUgZm9sbG93aW5nIGZvdXIgcGxvdHMsIHVzZSBgZ2VvbV9wb2ludCgpYDoKCi0gTWFwIGBtcGdgIG9udG8gdGhlIGB4YCBhZXN0aGV0aWMsIGFuZCBgY3lsYCBvbnRvIHRoZSBgeWAuCi0gUmV2ZXJzZSB0aGUgbWFwcGluZ3Mgb2YgdGhlIGZpcnN0IHBsb3QuCi0gTWFwIGB3dGAgb250byBgeCwsIGBtcGdgIG9udG8gYHlgLCBhbmQgYGN5bGAgb250byBgY29sb3JgLgotIE1vZGlmeSB0aGUgcHJldmlvdXMgcGxvdCBieSBjaGFuZ2luZyB0aGUgYHNoYXBlYCBhcmd1bWVudCBvZiB0aGUgZ2VvbSB0byBgMWAgYW5kIGluY3JlYXNlIHRoZSBgc2l6ZWAgdG8gYDRgLiBUaGVzZSBhcmUgYXR0cmlidXRlcyB0aGF0IHlvdSBzaG91bGQgc3BlY2lmeSBpbnNpZGUgYGdlb21fcG9pbnQoKWAuCgoKYGBge3J9CmxpYnJhcnkoZGF0YXNldHMpCm10Y2FycyRjeWwgPC0gYXMuZmFjdG9yKG10Y2FycyRjeWwpCgojIDEgLSBNYXAgbXBnIHRvIHggYW5kIGN5bCB0byB5CmdncGxvdChfX18sIGFlcyhfX18sIF9fXykpICsKICBnZW9tX3BvaW50KCkKICAKIyAyIC0gUmV2ZXJzZTogTWFwIGN5bCB0byB4IGFuZCBtcGcgdG8geQpnZ3Bsb3QoX19fLCBhZXMoX19fLCBfX18pKSArCiAgZ2VvbV9wb2ludCgpCgojIDMgLSBNYXAgd3QgdG8geCwgbXBnIHRvIHkgYW5kIGN5bCB0byBjb2wKZ2dwbG90KF9fXywgYWVzKF9fXywgX19fLCBfX18pKSArCiAgZ2VvbV9wb2ludCgpCgojIDQgLSBDaGFuZ2Ugc2hhcGUgYW5kIHNpemUgb2YgdGhlIHBvaW50cyBpbiB0aGUgYWJvdmUgcGxvdApnZ3Bsb3QobXRjYXJzLCBhZXMoX19fLCBfX18sIF9fXykpICsKICBnZW9tX3BvaW50KF9fXywgX19fKQoKYGBgCgoKIyMgQWxsIGFib3V0IGFlc3RoZXRpY3MsIHBhcnQgMgpUaGUgYGNvbG9yYCBhZXN0aGV0aWMgdHlwaWNhbGx5IGNoYW5nZXMgdGhlIG91dHNpZGUgb3V0bGluZSBvZiBhbiBvYmplY3QgYW5kIHRoZSBgZmlsbGAgYWVzdGhldGljIGlzIHR5cGljYWxseSB0aGUgaW5zaWRlIHNoYWRpbmcuIEhvd2V2ZXIsIGFzIHlvdSBzYXcgaW4gdGhlIGxhc3QgZXhlcmNpc2UsIGBnZW9tX3BvaW50KClgIGlzIGFuIGV4Y2VwdGlvbi4gSGVyZSB5b3UgdXNlIGBjb2xvcmAsIGluc3RlYWQgb2YgYGZpbGxgIGZvciB0aGUgaW5zaWRlIG9mIHRoZSBwb2ludC4gQnV0IGl0J3MgYSBiaXQgc3VidGxlciB0aGFuIHRoYXQuCgpXaGljaCBzaGFwZSB0byB1c2U/IFRoZSBkZWZhdWx0IGBnZW9tX3BvaW50KClgIHVzZXMgYHNoYXBlID0gMTlgIChhIHNvbGlkIGNpcmNsZSB3aXRoIGFuIG91dGxpbmUgdGhlIHNhbWUgY29sb3VyIGFzIHRoZSBpbnNpZGUpLiBHb29kIGFsdGVybmF0aXZlcyBhcmUgYHNoYXBlID0gMWAgKGhvbGxvdykgYW5kIGBzaGFwZSA9IDE2YCAoc29saWQsIG5vIG91dGxpbmUpLiBUaGVzZSBhbGwgdXNlIHRoZSBgY29sYCBhZXN0aGV0aWMgKGRvbid0IGZvcmdldCB0byBzZXQgYGFscGhhYCBmb3Igc29saWQgcG9pbnRzKS4KCkEgcmVhbGx5IG5pY2UgYWx0ZXJuYXRpdmUgaXMgYHNoYXBlID0gMjFgIHdoaWNoIGFsbG93cyB5b3UgdG8gdXNlIGJvdGggZmlsbCBmb3IgdGhlIGluc2lkZSBhbmQgY29sIGZvciB0aGUgb3V0bGluZSEgVGhpcyBpcyBhIGdyZWF0IGxpdHRsZSB0cmljayBmb3Igd2hlbiB5b3Ugd2FudCB0byBtYXAgdHdvIGFlc3RoZXRpY3MgdG8gYSBkb3QuCgpXaGF0IGhhcHBlbnMgd2hlbiB5b3UgdXNlIHRoZSB3cm9uZyBhZXN0aGV0aWMgbWFwcGluZz8gVGhpcyBpcyBhIHZlcnkgY29tbW9uIG1pc3Rha2UhIFRoZSBjb2RlIGZyb20gdGhlIHByZXZpb3VzIGV4ZXJjaXNlIGlzIGluIHRoZSBlZGl0b3IuIFVzaW5nIHRoaXMgYXMgeW91ciBzdGFydGluZyBwb2ludCBjb21wbGV0ZSB0aGUgaW5zdHJ1Y3Rpb25zLgoKIyMjIEluc3RydWN0aW9ucwoKTm90ZTogSW4gdGhlIGBtdGNhcnNgIGRhdGFzZXQsIGBjeWxgIGFuZCBgYW1gIGhhdmUgYmVlbiBjb252ZXJ0ZWQgdG8gZmFjdG9yIGZvciB5b3UuCgotIENvcHkgJiBwYXN0ZSB0aGUgZmlyc3QgcGxvdCdzIGNvZGUuIENoYW5nZSB0aGUgYWVzdGhldGljcyBzbyB0aGF0IGBjeWxgIG1hcHMgdG8gYGZpbGxgIHJhdGhlciB0aGFuIGBjb2xgLgotIENvcHkgJiBwYXN0ZSB0aGUgc2Vjb25kIHBsb3QncyBjb2RlLiBJbiBgZ2VvbV9wb2ludCgpYCBjaGFuZ2UgdGhlIGBzaGFwZWAgYXJndW1lbnQgdG8gYDIxYCBhbmQgYWRkIGFuIGBhbHBoYWAgYXJndW1lbnQgc2V0IHRvIGAwLjZgLgotIENvcHkgJiBwYXN0ZSB0aGUgdGhpcmQgcGxvdCdzIGNvZGUuIEluIHRoZSBgZ2dwbG90KClgIGFlc3RoZXRpY3MsIG1hcCBgYW1gIHRvIGBjb2xgLgoKYGBge3J9Cm10Y2FycyRhbSA8LSBhcy5mYWN0b3IobXRjYXJzJGFtKQptdGNhcnMkY3lsIDwtIGFzLmZhY3RvcihtdGNhcnMkY3lsKQoKIyBhbSBhbmQgY3lsIGFyZSBmYWN0b3JzLCB3dCBpcyBudW1lcmljCmNsYXNzKG10Y2FycyRhbSkKY2xhc3MobXRjYXJzJGN5bCkKY2xhc3MobXRjYXJzJHd0KQoKIyBGcm9tIHRoZSBwcmV2aW91cyBleGVyY2lzZQpnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IHd0LCB5ID0gbXBnLCBjb2wgPSBjeWwpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDEsIHNpemUgPSA0KQoKIyAxIC0gTWFwIGN5bCB0byBmaWxsCgoKCiMgMiAtIENoYW5nZSBzaGFwZSBhbmQgYWxwaGEgb2YgdGhlIHBvaW50cyBpbiB0aGUgYWJvdmUgcGxvdAoKCgojIDMgLSBNYXAgYW0gdG8gY29sIGluIHRoZSBhYm92ZSBwbG90CgoKYGBgCgoKIyMgQWxsIGFib3V0IGFlc3RoZXRpY3MsIHBhcnQgMwpOb3cgdGhhdCB5b3UndmUgZ290IHNvbWUgcHJhY3RpY2Ugd2l0aCBpbmNyZW1lbnRhbGx5IGJ1aWxkaW5nIHVwIHBsb3RzLCB5b3UgY2FuIHRyeSB0byBkbyBpdCBmcm9tIHNjcmF0Y2ghIFRoZSBgbXRjYXJzYCBkYXRhc2V0IGlzIHByZS1sb2FkZWQgaW4gdGhlIHdvcmtzcGFjZS4KCiMjIyBJbnN0cnVjdGlvbnMKVXNlIGBnZ3Bsb3QoKWAgdG8gY3JlYXRlIGEgYmFzaWMgc2NhdHRlciBwbG90LiBJbnNpZGUgYGFlcygpYCwgbWFwIGB3dGAgb250byBgeGAgYW5kIGBtcGdgIG9udG8gYHlgLiBUeXBpY2FsbHksIHlvdSB3b3VsZCBzYXkgIm1wZyBkZXNjcmliZWQgYnkgd3QiIG9yICJtcGcgdnMgd3QiLCBidXQgaW4gYGFlcygpYCwgaXQncyBgeGAgZmlyc3QsIGB5YCBzZWNvbmQuIFVzZSBgZ2VvbV9wb2ludCgpYCB0byBtYWtlIHRocmVlIHNjYXR0ZXIgcGxvdHM6CgotIGBjeWxgIG9uIGBzaXplYAotIGBjeWxgIG9uIGBhbHBoYWAKLSBgY3lsYCBvbiBgc2hhcGVgCgpUcnkgdGhpcyBsYXN0IHZhcmlhbnQ6CgotIGBjeWxgIG9uIGBsYWJlbGAuIEluIG9yZGVyIHRvIGNvcnJlY3RseSBzaG93IHRoZSB0ZXN0IChpLmUuIGBsYWJlbGApLCB1c2UgYGdlb21fdGV4dCgpYC4KCgpgYGB7cn0KIyBNYXAgY3lsIHRvIHNpemUKCgojIE1hcCBjeWwgdG8gYWxwaGEKCgoKIyBNYXAgY3lsIHRvIHNoYXBlIAoKCgojIE1hcCBjeWwgdG8gbGFiZWwKCgpgYGAKCgojIyBBbGwgYWJvdXQgYXR0cmlidXRlcywgcGFydCAxCgpZb3UgY2FuIHVzZSBhbGwgdGhlIGFlc3RoZXRpY3MgYXMgYXR0cmlidXRlcy4gTGV0J3Mgc2VlIGhvdyB0aGlzIHdvcmtzIHdpdGggdGhlIGFlc3RoZXRpY3MgeW91IHVzZWQgaW4gdGhlIHByZXZpb3VzIGV4ZXJjaXNlczogYHhgLCBgeWAsIGBjb2xvcmAsIGBmaWxsYCwgYHNpemVgLCBgYWxwaGFgLCBgbGFiZWxgIGFuZCBgc2hhcGVgLgoKVGhpcyB0aW1lIHlvdSdsbCB1c2UgdGhlc2UgYXJndW1lbnRzIHRvIHNldCBhdHRyaWJ1dGVzIG9mIHRoZSBwbG90LCBub3QgYWVzdGhldGljcy4gSG93ZXZlciwgdGhlcmUgYXJlIHNvbWUgcGl0ZmFsbHMgeW91J2xsIGhhdmUgdG8gd2F0Y2ggb3V0IGZvcjogdGhlc2UgYXR0cmlidXRlcyBjYW4gb3ZlcndyaXRlIHRoZSBhZXN0aGV0aWNzIG9mIHlvdXIgcGxvdCEKCkEgd29yZCBhYm91dCBzaGFwZXM6IEluIHRoZSBleGVyY2lzZSAiQWxsIGFib3V0IGFlc3RoZXRpY3MsIHBhcnQgMiIsIHlvdSBzYXcgdGhhdCBgc2hhcGUgPSAyMWAgcmVzdWx0cyBpbiBhIHBvaW50IHRoYXQgaGFzIGEgZmlsbCBhbmQgYW4gb3V0bGluZS4gU2hhcGVzIGluIFIgY2FuIGhhdmUgYSB2YWx1ZSBmcm9tIDEtMjUuIFNoYXBlcyAxLTIwIGNhbiBvbmx5IGFjY2VwdCBhIGNvbG9yIGFlc3RoZXRpYywgYnV0IHNoYXBlcyAyMS0yNSBoYXZlIGJvdGggYSBjb2xvciBhbmQgYSBmaWxsIGFlc3RoZXRpYy4gU2VlIHRoZSBgcGNoYCBhcmd1bWVudCBpbiBgcGFyKClgIGZvciBmdXJ0aGVyIGRpc2N1c3Npb24uCgpBIHdvcmQgYWJvdXQgaGV4YWRlY2ltYWwgY29sb3VyczogSGV4YWRlY2ltYWwsIGxpdGVyYWxseSAicmVsYXRlZCB0byAxNiIsIGlzIGEgYmFzZS0xNiBhbHBoYW51bWVyaWMgY291bnRpbmcgc3lzdGVtLiBJbmRpdmlkdWFsIHZhbHVlcyBjb21lIGZyb20gdGhlIHJhbmdlcyAwLTkgYW5kIEEtRi4gVGhpcyBtZWFucyB0aGVyZSBhcmUgMjU2IHBvc3NpYmxlIHR3by1kaWdpdCB2YWx1ZXMgKGkuZS4gMDAgLSBGRikuIEhleGFkZWNpbWFsIGNvbG91cnMgdXNlIHRoaXMgc3lzdGVtIHRvIHNwZWNpZnkgYSBzaXgtZGlnaXQgY29kZSBmb3IgUmVkLCBHcmVlbiBhbmQgQmx1ZSB2YWx1ZXMgKCIjUlJHR0JCIikgb2YgYSBjb2xvdXIgKGkuZS4gUHVyZSBibHVlOiAiIzAwMDBGRiIsIGJsYWNrOiAiIzAwMDAwMCIsIHdoaXRlOiAiI0ZGRkZGRiIpLiBSIGNhbiBhY2NlcHQgaGV4IGNvZGVzIGFzIHZhbGlkIGNvbG91cnMuCgojIyMgSW5zdHJ1Y3Rpb25zCgotIFlvdSB3aWxsIGNvbnRpbnVlIHRvIHdvcmsgd2l0aCBgbXRjYXJzYC4gVXNlIGBnZ3Bsb3QoKWAgdG8gY3JlYXRlIGEgYmFzaWMgc2NhdHRlciBwbG90OiBtYXAgYHd0YCBvbnRvIGB4YCwgYG1wZ2Agb250byBgeWAgYW5kIGBjeWxgIG9udG8gYGNvbG9yYC4KLSBPdmVyd3JpdGUgdGhlIGNvbG9yIG9mIHRoZSBwb2ludHMgaW5zaWRlIGBnZW9tX3BvaW50KClgIHRvIGBteV9jb2xvcmAuIE5vdGljZSBob3cgdGhpcyBjYW5jZWxzIG91dCB0aGUgY29sb3JzIGdpdmVuIHRvIHRoZSBwb2ludHMgYnkgdGhlIG51bWJlciBvZiBjeWxpbmRlcnMhCi0gU3RhcnRpbmcgd2l0aCBwbG90IDIsIG1hcCBgY3lsYCB0byBgZmlsbGAgaW5zdGVhZCBvZiBgY29sYCBhbmQgc2V0IHRoZSBhdHRyaWJ1dGVzIGBzaXplYCB0byBgMTBgLCBgc2hhcGVgIHRvIGAyM2AgYW5kIGBjb2xvcmAgdG8gYG15X2NvbG9yYCBpbnNpZGUgYGdlb21fcG9pbnQoKWAuCgoKYGBge3J9CiMgRGVmaW5lIGEgaGV4YWRlY2ltYWwgY29sb3IKbXlfY29sb3IgPC0gIiM0QUJFRkYiCgojIDEgLSBGaXJzdCBzY2F0dGVyIHBsb3QsIHdpdGggY29sIGFlc3RoZXRpYzoKCgoKIyAyIC0gUGxvdCAxLCBidXQgc2V0IGNvbCBhdHRyaWJ1dGVzIGluIGdlb20gbGF5ZXI6CgoKCiMgMyAtIFBsb3QgMiwgd2l0aCBmaWxsIGluc3RlYWQgb2YgY29sIGFlc3RoZXRpYywgcGx1dCBzaGFwZSBhbmQgc2l6ZSBhdHRyaWJ1dGVzIGluIGdlb20gbGF5ZXIuCgoKCmBgYAoKCiMjIEFsbCBhYm91dCBhdHRyaWJ1dGVzLCBwYXJ0IDIKWW91IGNhbiB1c2UgYWxsIHRoZSBhZXN0aGV0aWNzIGFzIGF0dHJpYnV0ZXMuIExldCdzIHNlZSBob3cgdGhpcyB3b3JrcyB3aXRoIHRoZSBhZXN0aGV0aWNzIHlvdSB1c2VkIGluIHRoZSBwcmV2aW91cyBleGVyY2lzZXM6IGB4YCwgYHlgLCBgY29sb3JgLCBgZmlsbGAsIGBzaXplYCwgYGFscGhhYCwgYGxhYmVsYCBhbmQgYHNoYXBlYC4KCkluIHRoaXMgZXhlcmNpc2UgeW91IHdpbGwgc2V0IGFsbCBraW5kcyBvZiBhdHRyaWJ1dGVzIG9mIHRoZSBwb2ludHMhCgpZb3Ugd2lsbCBjb250aW51ZSB0byB3b3JrIHdpdGggYG10Y2Fyc2AuCgojIyMgSW5zdHJ1Y3Rpb25zCgotIEFkZCB0byB0aGUgZmlyc3QgY29tbWFuZDogZHJhdyBwb2ludHMgd2l0aCBgYWxwaGFgIHNldCB0byBgMC41YC4KLSBBZGQgdG8gdGhlIHNlY29uZCBjb21tYW5kOiBkcmF3IHBvaW50cyBvZiBzaGFwZSBgMjRgIGluIHRoZSBjb2xvciBgeWVsbG93YC4KLSBBZGQgdG8gdGhlIHRoaXJkIGNvbW1hbmQ6IGRyYXcgdGV4dCB3aXRoIGxhYmVsIGByb3duYW1lcyhtdGNhcnMpYCBpbiB0aGUgY29sb3IgYHJlZGAuIERvbid0IHVzZSBgZ2VvbV9wb2ludCgpYCBoZXJlISBZb3Ugc2hvdWxkIGdldCBhIHNjYXR0ZXIgcGxvdCB3aXRoIHRoZSBuYW1lcyBvZiB0aGUgY2FycyBpbnN0ZWFkIG9mIHBvaW50cy4KCk5vdGU6IFJlbWVtYmVyIHRvIHNwZWNpZnkgY2hhcmFjdGVycyB3aXRoIHF1b3RhdGlvbiBtYXJrcyAoYCJ5ZWxsb3ciYCwgbm90IGB5ZWxsb3dgKS4KCmBgYHtyfQojIEV4cGFuZCB0byBkcmF3IHBvaW50cyB3aXRoIGFscGhhIDAuNQpnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IHd0LCB5ID0gbXBnLCBmaWxsID0gY3lsKSkgCgogIAojIEV4cGFuZCB0byBkcmF3IHBvaW50cyB3aXRoIHNoYXBlIDI0IGFuZCBjb2xvciB5ZWxsb3cKZ2dwbG90KG10Y2FycywgYWVzKHggPSB3dCwgeSA9IG1wZywgZmlsbCA9IGN5bCkpIAoKICAKIyBFeHBhbmQgdG8gZHJhdyB0ZXh0IHdpdGggbGFiZWwgcm93bmFtZXMobXRjYXJzKSBhbmQgY29sb3IgcmVkCmdncGxvdChtdGNhcnMsIGFlcyh4ID0gd3QsIHkgPSBtcGcsIGZpbGwgPSBjeWwpKSAKCmBgYAoKCiMjIEdvaW5nIGFsbCBvdXQKSW4gdGhpcyBleGVyY2lzZSwgeW91IHdpbGwgZ3JhZHVhbGx5IGFkZCBtb3JlIGFlc3RoZXRpY3MgbGF5ZXJzIHRvIHRoZSBwbG90LiBZb3UncmUgc3RpbGwgd29ya2luZyB3aXRoIHRoZSBgbXRjYXJzYCBkYXRhc2V0LCBidXQgdGhpcyB0aW1lIHlvdSdyZSB1c2luZyBtb3JlIGZlYXR1cmVzIG9mIHRoZSBjYXJzLiBGb3IgY29tcGxldGVuZXNzLCBoZXJlIGlzIGEgbGlzdCBvZiBhbGwgdGhlIGZlYXR1cmVzIG9mIHRoZSBvYnNlcnZhdGlvbnMgaW4gYG10Y2Fyc2A6CgotIGBtcGdgIC0tIE1pbGVzLyhVUykgZ2FsbG9uCi0gYGN5bGAgLS0gTnVtYmVyIG9mIGN5bGluZGVycwotIGBkaXNwYCAtLSBEaXNwbGFjZW1lbnQgKGN1LmluLikKLSBgaHBgIC0tIEdyb3NzIGhvcnNlcG93ZXIKLSBgZHJhdGAgLS0gUmVhciBheGxlIHJhdGlvCi0gYHd0YCAtLSBXZWlnaHQgKGxiLzEwMDApCi0gYHFzZWNgIC0tIDEvNCBtaWxlIHRpbWUKLSBgdnNgIC0tIFYvUyBlbmdpbmUuCi0gYGFtYCAtLSBUcmFuc21pc3Npb24gKDAgPSBhdXRvbWF0aWMsIDEgPSBtYW51YWwpCi0gYGdlYXJgIC0tIE51bWJlciBvZiBmb3J3YXJkIGdlYXJzCi0gYGNhcmJgIC0tIE51bWJlciBvZiBjYXJidXJldG9ycwoKTm90aWNlIHRoYXQgYWRkaW5nIG1vcmUgYWVzdGhldGljcyB0byB5b3VyIHBsb3QgaXMgbm90IGFsd2F5cyBhIGdvb2QgaWRlYS4gQWRkaW5nIGFlc3RoZXRpYyBtYXBwaW5ncyB0byBhIHBsb3Qgd2lsbCBpbmNyZWFzZSBpdHMgY29tcGxleGl0eSwgYW5kIHRodXMgZGVjcmVhc2UgaXRzIHJlYWRhYmlsaXR5LgoKIyMjIEluc3RydWN0aW9ucwpOb3RlOiBJbiB0aGlzIGNoYXB0ZXIgeW91IHNhdyBhZXN0aGV0aWNzIGFuZCBhdHRyaWJ1dGVzLiBWYXJpYWJsZXMgaW4gYSBkYXRhIGZyYW1lIGFyZSBtYXBwZWQgdG8gYWVzdGhldGljcyBpbiBgYWVzKClgLiAoZS5nLiBgYWVzKGNvbCA9IGN5bClgKSB3aXRoaW4gYGdncGxvdCgpYC4gVmlzdWFsIGVsZW1lbnRzIGFyZSBzZXQgYnkgYXR0cmlidXRlcyBpbiBzcGVjaWZpYyBnZW9tIGxheWVycyAoYGdlb21fcG9pbnQoY29sID0gInJlZCIpYCkuIERvbid0IGNvbmZ1c2UgdGhlc2UgdHdvIHRoaW5ncyAtIGhlcmUgeW91J3JlIGZvY3VzaW5nIG9uIGFlc3RoZXRpYyBtYXBwaW5ncy4KCi0gRHJhdyBhIHNjYXR0ZXIgcGxvdCBvZiBgbXRjYXJzYCB3aXRoIGBtcGdgIG9uIHRoZSB4LWF4aXMsIGBxc2VjYCBvbiB0aGUgeS1heGlzIGFuZCBgZmFjdG9yKGN5bClgIGFzIGNvbG9ycy4KLSBFeHBhbmQgdGhlIHByZXZpb3VzIHBsb3QgdG8gaW5jbHVkZSBgZmFjdG9yKGFtKWAgYXMgdGhlIGBzaGFwZWAgb2YgdGhlIHBvaW50cy4KLSBFeHBhbmQgdGhlIHByZXZpb3VzIHBsb3QgdG8gaW5jbHVkZSB0aGUgcmF0aW8gb2YgaG9yc2Vwb3dlciB0byB3ZWlnaHQgKGkuZS4gYChocC93dClgKSBhcyB0aGUgc2l6ZSBvZiB0aGUgcG9pbnRzLgoKCmBgYHtyfQojIE1hcCBtcGcgb250byB4LCBxc2VjIG9udG8geSBhbmQgZmFjdG9yKGN5bCkgb250byBjb2wKCgoKIyBBZGQgbWFwcGluZzogZmFjdG9yKGFtKSBvbnRvIHNoYXBlCgoKCiMgQWRkIG1hcHBpbmc6IChocC93dCkgb250byBzaXplCgoKYGBgCgoKIyMgQWVzdGhldGljcyBmb3IgY2F0ZWdvcmljYWwgYW5kIGNvbnRpbnVvdXMgdmFyaWFibGVzCk1hbnkgb2YgdGhlIGFlc3RoZXRpY3MgY2FuIGJlIG1hcHBlZCBvbnRvIGNvbnRpbnVvdXMgb3IgY2F0ZWdvcmljYWwgdmFyaWFibGVzLCBidXQgc29tZSBhcmUgcmVzdHJpY3RlZCB0byBjYXRlZ29yaWNhbCBkYXRhLiBXaGljaCBhZXN0aGV0aWNzIGFyZSB0aGV5PwoKIyMjIEluc3RydWN0aW9ucwpQb3NzaWJsZSBBbnN3ZXJzCgotIGNvbG9yICYgZmlsbAotIGFscGhhICYgc2l6ZQotIGxhYmVsICYgc2hhcGUKLSBhbHBoYSAmIGxhYmVsCi0geCAmIHkKCiMjIFBvc2l0aW9uCgpCYXIgcGxvdHMgc3VmZmVyIGZyb20gdGhlaXIgb3duIGlzc3VlcyBvZiBvdmVycGxvdHRpbmcsIGFzIHlvdSdsbCBzZWUgaGVyZS4gVXNlIHRoZSBgInN0YWNrImAsIGAiZmlsbCJgIGFuZCBgImRvZGdlImAgcG9zaXRpb25zIHRvIHJlcHJvZHVjZSB0aGUgcGxvdCBpbiB0aGUgdmlld2VyLgoKVGhlIGBnZ3Bsb3QyYCBiYXNlIGxheWVycyAoZGF0YSBhbmQgYWVzdGhldGljcykgaGF2ZSBhbHJlYWR5IGJlZW4gY29kZWQ7IHRoZXkncmUgc3RvcmVkIGluIGEgdmFyaWFibGUgYGN5bC5hbWAuIEl0IGxvb2tzIGxpa2UgdGhpczoKCmBgYHtyfQpjeWwuYW0gPC0gZ2dwbG90KG10Y2FycywgYWVzKHggPSBmYWN0b3IoY3lsKSwgZmlsbCA9IGZhY3RvcihhbSkpKQpgYGAKCgojIyMgSW5zdHJ1Y3Rpb25zCgotIEFkZCBhIGBnZW9tX2JhcigpYCBjYWxsIHRvIGBjeWwuYW1gLiBCeSBkZWZhdWx0LCB0aGUgYHBvc2l0aW9uYCB3aWxsIGJlIHNldCB0byBgInN0YWNrImAuCi0gRmlsbCBpbiB0aGUgc2Vjb25kIGBnZ3Bsb3RgIGNvbW1hbmQuIEV4cGxpY2l0bHkgc2V0IGBwb3NpdGlvbmAgdG8gYCJmaWxsImAgaW5zaWRlIGBnZW9tX2JhcigpYC4KLSBGaWxsIGluIHRoZSB0aGlyZCBgZ2dwbG90YCBjb21tYW5kLiBTZXQgYHBvc2l0aW9uYCB0byBgImRvZGdlImAuCi0gVGhlIGBwb3NpdGlvbiA9ICJkb2RnZSJgIHZlcnNpb24gc2VlbXMgbW9zdCBhcHByb3ByaWF0ZS4gRmluaXNoIG9mZiB0aGUgZm91cnRoIGBnZ3Bsb3RgIGNvbW1hbmQgYnkgY29tcGxldGluZyB0aGUgdGhyZWUgYHNjYWxlX2AgZnVuY3Rpb25zOgogICAtIGBzY2FsZV94X2Rpc2NyZXRlKClgIHRha2VzIGFzIGl0cyBvbmx5IGFyZ3VtZW50IHRoZSB4LWF4aXMgbGFiZWw6IGAiQ3lsaW5kZXJzImAuCiAgIC0gYHNjYWxlX3lfY29udGludW91cygpYCB0YWtlcyBhcyBpdHMgb25seSBhcmd1bWVudCB0aGUgeS1heGlzIGxhYmVsOiBgIk51bWJlciJgLgogICAtIGBzY2FsZV9maWxsX21hbnVhbCgpYCBmaXhlcyB0aGUgbGVnZW5kLiBUaGUgZmlyc3QgYXJndW1lbnQgaXMgdGhlIHRpdGxlIG9mIHRoZSBsZWdlbmQ6IGAiVHJhbnNtaXNzaW9uImAuIE5leHQsIGB2YWx1ZXNgIGFuZCBgbGFiZWxzYCBhcmUgc2V0IHRvIHByZWRlZmluZWQgdmFsdWVzIGZvciB5b3UuIFRoZXNlIGFyZSB0aGUgY29sb3JzIGFuZCB0aGUgbGFiZWxzIGluIHRoZSBsZWdlbmQuCgpgYGB7cn0KIyBUaGUgYmFzZSBsYXllciwgY3lsLmFtLCBpcyBhdmFpbGFibGUgZm9yIHlvdQojIEFkZCBnZW9tIChwb3NpdGlvbiA9ICJzdGFjayIgYnkgZGVmYXVsdCkKY3lsLmFtICsgCiAgX19fCgojIEZpbGwgLSBzaG93IHByb3BvcnRpb24KY3lsLmFtICsgCiAgZ2VvbV9iYXIocG9zaXRpb24gPSBfX18pICAKCiMgRG9kZ2luZyAtIHByaW5jaXBsZXMgb2Ygc2ltaWxhcml0eSBhbmQgcHJveGltaXR5CmN5bC5hbSArCiAgZ2VvbV9iYXIocG9zaXRpb24gPSBfX18pIAoKIyBDbGVhbiB1cCB0aGUgYXhlcyB3aXRoIHNjYWxlXyBmdW5jdGlvbnMKdmFsID0gYygiI0U0MUExQyIsICIjMzc3RUI4IikKbGFiID0gYygiTWFudWFsIiwgIkF1dG9tYXRpYyIpCmN5bC5hbSArCiAgZ2VvbV9iYXIocG9zaXRpb24gPSAiZG9kZ2UiKSArCiAgc2NhbGVfeF9kaXNjcmV0ZShfX18pICsgCiAgc2NhbGVfeV9jb250aW51b3VzKF9fXykgKwogIHNjYWxlX2ZpbGxfbWFudWFsKF9fXywgCiAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gdmFsLAogICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGxhYikKYGBgCgoKIyMgU2V0dGluZyBhIGR1bW15IGFlc3RoZXRpYwoKSW4gdGhlIGxhc3QgY2hhcHRlciB5b3Ugc2F3IHRoYXQgYWxsIHRoZSB2aXNpYmxlIGFlc3RoZXRpY3MgY2FuIHNlcnZlIGFzIGF0dHJpYnV0ZXMgYW5kIGFlc3RoZXRpY3MsIGJ1dCBJIHZlcnkgY29udmVuaWVudGx5IGxlZnQgb3V0IGB4YCBhbmQgYHlgLiBUaGF0J3MgYmVjYXVzZSBhbHRob3VnaCB5b3UgY2FuIG1ha2UgdW5pdmFyaWF0ZSBwbG90cyAoc3VjaCBhcyBoaXN0b2dyYW1zLCB3aGljaCB5b3UnbGwgZ2V0IHRvIGluIHRoZSBuZXh0IGNoYXB0ZXIpLCBhIHktYXhpcyB3aWxsIGFsd2F5cyBiZSBwcm92aWRlZCwgZXZlbiBpZiB5b3UgZGlkbid0IGFzayBmb3IgaXQuCgpJbiB0aGUgYmFzZSBwYWNrYWdlIHlvdSBjYW4gbWFrZSB1bml2YXJpYXRlIHBsb3RzIHdpdGggYHN0cmlwY2hhcnQoKWAgZGlyZWN0bHkgYW5kIGl0IHdpbGwgdGFrZSBjYXJlIG9mIGEgZmFrZSBgeWAgYXhpcyBmb3IgdXMuIFNpbmNlIHRoaXMgaXMgdW5pdmFyaWF0ZSBkYXRhLCB0aGVyZSBpcyBubyByZWFsIGB5YCBheGlzLgoKWW91IGNhbiBnZXQgdGhlIHNhbWUgdGhpbmcgaW4gYGdncGxvdDJgLCBidXQgaXQncyBhIGJpdCBtb3JlIGN1bWJlcnNvbWUuIFRoZSBvbmx5IHJlYXNvbiB5b3UnZCByZWFsbHkgd2FudCB0byBkbyB0aGlzIGlzIGlmIHlvdSB3ZXJlIG1ha2luZyBtYW55IHBsb3RzIGFuZCB5b3Ugd2FudGVkIHRoZW0gdG8gYmUgaW4gdGhlIHNhbWUgc3R5bGUsIG9yIHlvdSB3YW50ZWQgdG8gdGFrZSBhZHZhbnRhZ2Ugb2YgYW4gYWVzdGhldGljIG1hcHBpbmcgKGUuZy4gYGNvbG91cmApLgoKIyMjIEluc3RydWN0aW9ucwoKLSBUcnkgdG8gcnVuIGBnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IG1wZykpICsgZ2VvbV9wb2ludCgpYCBpbiB0aGUgY29uc29sZS4gYHhgIGlzIG9ubHkgb25lIG9mIHRoZSB0d28gZXNzZW50aWFsIGFlc3RoZXRpY3MgZm9yIGBnZW9tX3BvaW50KClgLCB3aGljaCBpcyB3aHkgeW91IGdldCBhbiBlcnJvciBtZXNzYWdlLgogICAtIDEgLSBUbyBmaXggdGhpcywgbWFwIGEgdmFsdWUsIGUuZy4gMCwgaW5zdGVhZCBvZiBhIHZhcmlhYmxlLCBvbnRvIGB5YC4gVXNlIGBnZW9tX2ppdHRlcigpYCB0byBhdm9pZCBoYXZpbmcgYWxsIHRoZSBwb2ludHMgb24gYSBob3Jpem9udGFsIGxpbmUuCiAgIC0gMiAtIFRvIG1ha2UgZXZlcnl0aGluZyBsb29rIG5pY2VyLCBjb3B5ICYgcGFzdGUgdGhlIGNvZGUgZm9yIHBsb3QgMSBhbmQgY2hhbmdlIHRoZSBsaW1pdHMgb2YgdGhlIGB5YCBheGlzIHVzaW5nIHRoZSBhcHByb3ByaWF0ZSBgc2NhbGVfeV8uLi4oKWAgZnVuY3Rpb24uIFNldCB0aGUgYGxpbWl0c2AgYXJndW1lbnQgdG8gYGMoLTIsIDIpYC4KCmBgYHtyfQojIDEgLSBDcmVhdGUgaml0dGVyZWQgcGxvdCBvZiBtdGNhcnMsIG1wZyBvbnRvIHgsIDAgb250byB5CmdncGxvdChfX18sIGFlcyh4ID0gX19fLCB5ID0gX19fKSkgKwogIGdlb21faml0dGVyKCkKCiMgMiAtIEFkZCBmdW5jdGlvbiB0byBjaGFuZ2UgeSBheGlzIGxpbWl0cwoKCmBgYAoKCiMjIE92ZXJwbG90dGluZyAxIC0gUG9pbnQgc2hhcGUgYW5kIHRyYW5zcGFyZW5jeQoKSW4gdGhlIHByZXZpb3VzIHNlY3Rpb24geW91IHNhdyB0aGF0IHRoZXJlIGFyZSBsb3RzIG9mIHdheXMgdG8gdXNlIGFlc3RoZXRpY3MuIFBlcmhhcHMgdG9vIG1hbnksIGJlY2F1c2UgYWx0aG91Z2ggdGhleSBhcmUgcG9zc2libGUsIHRoZXkgYXJlIG5vdCBhbGwgcmVjb21tZW5kZWQuIExldCdzIHRha2UgYSBsb29rIGF0IHdoYXQgd29ya3MgYW5kIHdoYXQgZG9lc24ndC4KClNvIGZhciB5b3UndmUgZm9jdXNlZCBvbiBzY2F0dGVyIHBsb3RzIHNpbmNlIHRoZXkgYXJlIGludHVpdGl2ZSwgZWFzaWx5IHVuZGVyc3Rvb2QgYW5kIHZlcnkgY29tbW9uLiBBIG1ham9yIGNvbnNpZGVyYXRpb24gaW4gYW55IHNjYXR0ZXIgcGxvdCBpcyBkZWFsaW5nIHdpdGggb3ZlcnBsb3R0aW5nLiBZb3UnbGwgZW5jb3VudGVyIHRoaXMgdG9waWMgYWdhaW4gaW4gdGhlIGdlb21ldHJpZXMgbGF5ZXIsIGJ1dCB5b3UgY2FuIGFscmVhZHkgbWFrZSBzb21lIGFkanVzdG1lbnRzIGhlcmUuCgpZb3UnbGwgaGF2ZSB0byBkZWFsIHdpdGggb3ZlcnBsb3R0aW5nIHdoZW4geW91IGhhdmU6CgotIExhcmdlIGRhdGFzZXRzLAotIEltcHJlY2lzZSBkYXRhIGFuZCBzbyBwb2ludHMgYXJlIG5vdCBjbGVhcmx5IHNlcGFyYXRlZCBvbiB5b3VyIHBsb3QgKHlvdSBzYXcgdGhpcyBpbiB0aGUgdmlkZW8gd2l0aCB0aGUgYGlyaXNgIGRhdGFzZXQpLAotIEludGVydmFsIGRhdGEgKGkuZS4gZGF0YSBhcHBlYXJzIGF0IGZpeGVkIHZhbHVlcyksIG9yCi0gQWxpZ25lZCBkYXRhIHZhbHVlcyBvbiBhIHNpbmdsZSBheGlzLgoKT25lIHZlcnkgY29tbW9uIHRlY2huaXF1ZSB0aGF0IEknZCByZWNvbW1lbmQgdG8gYWx3YXlzIHVzZSB3aGVuIHlvdSBoYXZlIHNvbGlkIHNoYXBlcyBpdCB0byB1c2UgYWxwaGEgYmxlbmRpbmcgKGkuZS4gYWRkaW5nIHRyYW5zcGFyZW5jeSkuIEFuIGFsdGVybmF0aXZlIGlzIHRvIHVzZSBob2xsb3cgc2hhcGVzLiBUaGVzZSBhcmUgYWRqdXN0bWVudHMgdG8gbWFrZSBiZWZvcmUgZXZlbiB3b3JyeWluZyBhYm91dCBwb3NpdGlvbmluZy4gVGhpcyBhZGRyZXNzZXMgdGhlIGZpcnN0IHBvaW50IGFzIGFib3ZlLCB3aGljaCB5b3UnbGwgc2VlIGFnYWluIGluIHRoZSBuZXh0IGV4ZXJjaXNlLgoKIyMjIEluc3RydWN0aW9ucwoKLSBCZWdpbiBieSBtYWtpbmcgYSBiYXNpYyBzY2F0dGVyIHBsb3Qgb2YgYG1wZ2AgKHkpIHZzLiBgd3RgICh4KSwgbWFwIGBjeWxgIHRvIGBjb2xvcmAgYW5kIG1ha2UgdGhlIGBzaXplID0gNGAuIGBjeWxgIGhhcyBhbHJlYWR5IGJlZW4gY29udmVydGVkIHRvIGEgZmFjdG9yIHZhcmlhYmxlIGZvciB5b3UuCi0gTW9kaWZ5IHRoZSBhYm92ZSBwbG90IHRvIHNldCBgc2hhcGVgIHRvIGAxYC4gVGhpcyBhbGxvd3MgZm9yIGhvbGxvdyBjaXJjbGVzLgotIE1vZGlmeSB0aGUgZmlyc3QgcGxvdCB0byBzZXQgYGFscGhhYCB0byBgMC42YC4KCmBgYHtyfQojIEJhc2ljIHNjYXR0ZXIgcGxvdDogd3Qgb24geC1heGlzIGFuZCBtcGcgb24geS1heGlzOyBtYXAgY3lsIHRvIGNvbAoKCgojIEhvbGxvdyBjaXJjbGVzIC0gYW4gaW1wcm92ZW1lbnQKCgoKIyBBZGQgdHJhbnNwYXJlbmN5IC0gdmVyeSBuaWNlCgoKYGBgCgoKIyMgT3ZlcnBsb3R0aW5nIDIgLSBhbHBoYSB3aXRoIGxhcmdlIGRhdGFzZXRzCgpJbiBhIHByZXZpb3VzIGV4ZXJjaXNlIHdlIGRlZmluZWQgZm91ciBzaXR1YXRpb25zIGluIHdoaWNoIHlvdSdkIGhhdmUgdG8gYWRqdXN0IGZvciBvdmVycGxvdHRpbmcuIFlvdSdsbCBjb25zaWRlciB0aGUgbGFzdCB0d28gaGVyZSB3aXRoIHRoZSBkaWFtb25kcyBkYXRhc2V0OgoKLSBMYXJnZSBkYXRhc2V0cy4KLSBBbGlnbmVkIGRhdGEgdmFsdWVzIG9uIGEgc2luZ2xlIGF4aXMKCiMjIyBJbnN0cnVjdGlvbnMKCi0gVGhlIGBkaWFtb25kc2AgZGF0YSBmcmFtZSBpcyBhdmFpbGFibGUgaW4gdGhlIGBnZ3Bsb3QyKClgIHBhY2thZ2UuIEJlZ2luIGJ5IG1ha2luZyBhIGJhc2ljIHNjYXR0ZXIgcGxvdCBvZiBgcHJpY2VgICh5KSB2cy4gYGNhcmF0YCAoeCkgYW5kIG1hcCBgY2xhcml0eWAgb250byBgY29sb3JgLgotIENvcHkgdGhlIGFib3ZlIGZ1bmN0aW9ucyBhbmQgc2V0IHRoZSBgYWxwaGFgIHRvIGAwLjVgLiBUaGlzIGlzIGEgZ29vZCBzdGFydCB0byBkZWFsaW5nIHdpdGggdGhlIGxhcmdlIGRhdGFzZXQuCi0gQWxpZ24gYWxsIHRoZSBkaWFtb25kcyB3aXRoaW4gYSBjbGFyaXR5IGNsYXNzLCBieSBwbG90dGluZyBgY2FyYXRgICh5KSB2cy4gYGNsYXJpdHlgICh4KS4gTWFwIGBwcmljZWAgb250byBgY29sb3JgLiBgYWxwaGFgIHNob3VsZCBzdGlsbCBiZSBgMC41YC4KLSBJbiB0aGUgcHJldmlvdXMgcGxvdCwgYWxsIHRoZSBpbmRpdmlkdWFsIHZhbHVlcyBsaW5lIHVwIG9uIGEgc2luZ2xlIGF4aXMgd2l0aGluIGVhY2ggY2xhcml0eSBjYXRlZ29yeSwgc28geW91IGhhdmUgbm90IG92ZXJjb21lIG92ZXJwbG90dGluZy4gTW9kaWZ5IHRoZSBhYm92ZSBwbG90IHRvIHVzZSB0aGUgYHBvc2l0aW9uID0gImppdHRlciJgIGluc2lkZSBgZ2VvbV9wb2ludCgpYC4KCmBgYHtyfQojIFNjYXR0ZXIgcGxvdDogY2FyYXQgKHgpLCBwcmljZSAoeSksIGNsYXJpdHkgKGNvbG9yKQoKCgojIEFkanVzdCBmb3Igb3ZlcnBsb3R0aW5nCgoKCiMgU2NhdHRlciBwbG90OiBjbGFyaXR5ICh4KSwgY2FyYXQgKHkpLCBwcmljZSAoY29sb3IpCgoKCiMgRG90IHBsb3Qgd2l0aCBqaXR0ZXJpbmcKCgpgYGAKCgojIEdlb21ldHJpZXMKCiMjIFNjYXR0ZXIgcGxvdHMgYW5kIGppdHRlcmluZyAoMSkKCllvdSBhbHJlYWR5IHNhdyBhIGZldyBleGFtcGxlcyB1c2luZyBgZ2VvbV9wb2ludCgpYCB3aGVyZSB0aGUgcmVzdWx0IHdhcyBub3QgYSBzY2F0dGVyIHBsb3QuIEZvciBleGFtcGxlLCBpbiB0aGUgcGxvdCBnaXZlbiBiZWxvdywgYSBjb250aW51b3VzIHZhcmlhYmxlLCBgd3RgLCBpcyBtYXBwZWQgdG8gdGhlIGB5YCBhZXN0aGV0aWMsIGFuZCBhIGNhdGVnb3JpY2FsIHZhcmlhYmxlLCBgY3lsYCwgaXMgbWFwcGVkIHRvIHRoZSBgeGAgYWVzdGhldGljLiBUaGlzIGFsc28gbGVhZHMgdG8gb3Zlci1wbG90dGluZywgc2luY2UgdGhlIHBvaW50cyBhcmUgYXJyYW5nZWQgb24gYSBzaW5nbGUgeCBwb3NpdGlvbi4gWW91IHByZXZpb3VzbHkgZGVhbHQgd2l0aCBvdmVycGxvdHRpbmcgYnkgc2V0dGluZyB0aGUgYHBvc2l0aW9uID0gaml0dGVyYCBpbnNpZGUgYGdlb21fcG9pbnQoKWAuIExldCdzIGxvb2sgYXQgc29tZSBvdGhlciBzb2x1dGlvbnMgaGVyZS4KCiMjIyBJbnN0cnVjdGlvbnMKCkJlZ2lubmluZyB3aXRoIHRoZSBjb2RlIGZvciB0aGUgcGxvdCBpbiB0aGUgdmlld2VyIChnaXZlbiksIG1ha2UgdGhlc2UgbW9kaWZpY2F0aW9ucwoKLSBVc2UgYSBzaG9ydGN1dCBnZW9tLCBgZ2VvbV9qaXR0ZXIoKWAsIGluc3RlYWQgb2YgYGdlb21fcG9pbnQoKWAuCi0gVW5mb3J0dW5hdGVseSwgdGhlIHdpZHRoIG9mIHRoZSBqaXR0ZXIgaXMgYSBiaXQgdG9vIHdpZGUgdG8gYmUgdXNlZnVsLiBBZGp1c3QgdGhpcyBieSBzZXR0aW5nIHRoZSBhcmd1bWVudCBgd2lkdGggPSAwLjFgIGluc2lkZSBgZ2VvbV9qaXR0ZXIoKWAuCi0gRmluYWxseSwgcmV0dXJuIHRvIGBnZW9tX3BvaW50KClgIGFuZCBzZXQgdGhlIHBvc2l0aW9uIGFyZ3VtZW50IGhlcmUgdG8gYHBvc2l0aW9uX2ppdHRlcigwLjEpYCwgd2hpY2ggd2lsbCBzZXQgdGhlIGppdHRlcmluZyB3aWR0aCBkaXJlY3RseSBpbnNpZGUgYSBwb2ludHMgbGF5ZXIuCgpOb3RlOiBGb3IgY29udmVuaWVuY2UsIHlvdSBjb3VsZCBoYXZlIHNhdmVkIHRoZSBkYXRhIGFuZCBhZXN0aGV0aWMgbGF5ZXJzIGFzIGEgZ2dwbG90MiBvYmplY3QgYW5kIHJlLXVzZWQgaXQgaW4gYWxsIHNvbHV0aW9ucy4gV2UndmUgbWFkZSBlYWNoIHBsb3QgZXhwbGljaXQgc28gdGhhdCB5b3UgY2FuIHNlZSBhbGwgcGxvdHRpbmcgaW5zdHJ1Y3Rpb25zLgoKYGBge3J9CiMgU2hvd24gaW4gdGhlIHZpZXdlcjoKZ2dwbG90KG10Y2FycywgYWVzKHggPSBjeWwsIHkgPSB3dCkpICsKICBnZW9tX3BvaW50KCkKCiMgU29sdXRpb25zOgojIDEgLSBXaXRoIGdlb21faml0dGVyKCkKZ2dwbG90KG10Y2FycywgYWVzKHggPSBjeWwsIHkgPSB3dCkpICsKICBfX18oKQoKIyAyIC0gU2V0IHdpZHRoIGluIGdlb21faml0dGVyKCkKZ2dwbG90KG10Y2FycywgYWVzKHggPSBjeWwsIHkgPSB3dCkpICsKICBfX18oX19fKQoKIyAzIC0gU2V0IHBvc2l0aW9uID0gcG9zaXRpb25faml0dGVyKCkgaW4gZ2VvbV9wb2ludCgpICgpCmdncGxvdChtdGNhcnMsIGFlcyh4ID0gY3lsLCB5ID0gd3QpKSArCiAgX19fKF9fXyA9IF9fXygpKQoKYGBgCgoKIyMgU2NhdHRlciBwbG90cyBhbmQgaml0dGVyaW5nICgyKQoKSW4gdGhlIGNoYXB0ZXIgb24gYWVzdGhldGljcyB5b3Ugc2F3IGRpZmZlcmVudCB3YXlzIGluIHdoaWNoIHlvdSB3aWxsIGhhdmUgdG8gY29tcGVuc2F0ZSBmb3Igb3ZlcnBsb3R0aW5nLiAKCkFub3RoZXIgaXNzdWUgaXMgd2hlbiB5b3UgaGF2ZSBpbnRlcnZhbCBkYXRhLiBUaGlzIGNhbiBiZSBjb250aW51b3VzIGRhdGEgbWVhc3VyZWQgb24gYW4gaW50ZXJ2YWwgKGkuZS4gMSAsMiwgMyAuLi4pLCBhcyBvcHBvc2VkIHRvIG51bWVyaWMgKGkuZS4gMS4xLCAxLjQsIDEuNSwgLi4uKSwgc2NhbGUsIG9yIHR3byBjYXRlZ29yaWNhbCAoZS5nLiBmYWN0b3IpIHZhcmlhYmxlcywgd2hpY2ggYXJlIGp1c3QgdHlwZSBpbnRlcnZhbCB1bmRlci10aGUtaG9vZC4KCkluIHN1Y2ggYSBjYXNlIHlvdSdsbCBoYXZlIGEgc21hbGwsIGRlZmluZWQgbnVtYmVyIG9mIGludGVyc2VjdGlvbnMgYmV0d2VlbiB0aGUgdHdvIHZhcmlhYmxlcy4KCllvdSB3aWxsIGJlIHVzaW5nIHRoZSBgVm9jYWJgIGRhdGFzZXQuIFRoZSBgVm9jYWJgIGRhdGFzZXQgY29udGFpbnMgaW5mb3JtYXRpb24gYWJvdXQgdGhlIHllYXJzIG9mIGVkdWNhdGlvbiBhbmQgaW50ZWdlciBzY29yZSBvbiBhIHZvY2FidWxhcnkgdGVzdCBmb3Igb3ZlciAyMSwwMDAgaW5kaXZpZHVhbHMgYmFzZWQgb24gVVMgR2VuZXJhbCBTb2NpYWwgU3VydmV5cyBmcm9tIDE5NzItMjAwNC4KCiMjIyBJbnN0cnVjdGlvbnMKCi0gVGhlIGBWb2NhYmAgZGF0YSBmcmFtZSBoYXMgYmVlbiBsb2FkZWQgZm9yIHlvdS4gQm90aCB0aGUgZWR1Y2F0aW9uIGFuZCB2b2NhYnVsYXJ5IHZhcmlhYmxlcyBhcmUgY2xhc3NpZmllZCBhcyBpbnRlZ2Vycy4gWW91IGNhbiBpbWFnaW5lIHRoZXNlIGFzIGZhY3RvciB2YXJpYWJsZXMsIGJ1dCBoZXJlLCBpbnRlZ2VycyBhcmUgbW9yZSBjb252ZW5pZW50IHRvIHdvcmsgd2l0aC4gRmlyc3QsIGdldCBmYW1pbGlhciB3aXRoIHRoZSBkYXRhc2V0IGJ5IGxvb2tpbmcgYXQgaXRzIHN0cnVjdHVyZSB3aXRoIGBzdHIoKWAuCi0gTWFrZSBhIGJhc2ljIHNjYXR0ZXIgcGxvdCBvZiBgdm9jYWJ1bGFyeWAgKHkpIHZzLiBgZWR1Y2F0aW9uYCAoeCkuIEhlcmUgaXQgYmVjb21lcyBhcHBhcmVudCB0aGF0IHlvdSBoYXZlIGlzc3VlcyB3aXRoIG92ZXJwbG90dGluZyBiZWNhdXNlIG9mIHRoZSBpbnRlZ2VyIHNjYWxlcy4KLSBVc2UgYGdlb21faml0dGVyKClgIGluc3RlYWQgb2YgYGdlb21fcG9pbnQoKWAuCi0gVXNpbmcgdGhlIGppdHRlcmVkIHBsb3QsIHNldCBgYWxwaGFgIHRvIGAwLjJgICh2ZXJ5IGxvdykuCi0gVXNpbmcgdGhlIGppdHRlcmVkIHBsb3QsIHNldCBgc2hhcGVgIHRvIGAxYC4KCgpgYGB7cn0KaW5zdGFsbC5wYWNrYWdlcygiY2FyRGF0YSIpCmxpYnJhcnkoY2FyRGF0YSkKIyBFeGFtaW5lIHRoZSBzdHJ1Y3R1cmUgb2YgVm9jYWIKCgojIEJhc2ljIHNjYXR0ZXIgcGxvdCBvZiB2b2NhYnVsYXJ5ICh5KSBhZ2FpbnN0IGVkdWNhdGlvbiAoeCkuIFVzZSBnZW9tX3BvaW50KCkKCgoKIyBVc2UgZ2VvbV9qaXR0ZXIoKSBpbnN0ZWFkIG9mIGdlb21fcG9pbnQoKQoKCgojIFVzaW5nIHRoZSBhYm92ZSBwbG90dGluZyBjb21tYW5kLCBzZXQgYWxwaGEgdG8gYSB2ZXJ5IGxvdyAwLjIKCgoKIyBVc2luZyB0aGUgYWJvdmUgcGxvdHRpbmcgY29tbWFuZCwgc2V0IHRoZSBzaGFwZSB0byAxCgoKYGBgCgoKIyMgSGlzdG9ncmFtcwoKSGlzdG9ncmFtcyBhcmUgb25lIG9mIHRoZSBtb3N0IGNvbW1vbiBhbmQgaW50dWl0aXZlIHdheXMgb2Ygc2hvd2luZyBkaXN0cmlidXRpb25zLiBJbiB0aGlzIGV4ZXJjaXNlIHlvdSdsbCB1c2UgdGhlIGBtdGNhcnNgIGRhdGEgZnJhbWUgdG8gZXhwbG9yZSB0eXBpY2FsIHZhcmlhdGlvbnMgb2Ygc2ltcGxlIGhpc3RvZ3JhbXMuIEJ1dCBmaXJzdCwgc29tZSBiYWNrZ3JvdW5kOgoKKipUaGUgeCBheGlzL2Flc3RoZXRpYyoqOiBUaGUgZG9jdW1lbnRhdGlvbiBmb3IgYGdlb21faGlzdG9ncmFtKClgIHN0YXRlcyB0aGUgYXJndW1lbnQgYHN0YXQgPSAiYmluImAgYXMgYSBkZWZhdWx0LiBSZWNhbGwgdGhhdCBoaXN0b2dyYW1zIGN1dCB1cCBhIGNvbnRpbnVvdXMgdmFyaWFibGUgaW50byBkaXNjcmV0ZSBiaW5zIC0gdGhhdHMgd2hhdCB0aGUgc3RhdCAiYmluIiBpcyBkb2luZy4gWW91IGFsd2F5cyBnZXQgMzAgZXZlbmx5LXNpemVkIGJpbnMgYnkgZGVmYXVsdCwgd2hpY2ggaXMgc3BlY2lmaWVkIHdpdGggdGhlIGRlZmF1bHQgYXJndW1lbnQgYGJpbndpZHRoID0gcmFuZ2UvMzBgLiBUaGlzIGlzIGEgcHJldHR5IGdvb2Qgc3RhcnRpbmcgcG9pbnQgaWYgeW91IGRvbid0IGtub3cgYW55dGhpbmcgYWJvdXQgdGhlIHZhcmlhYmxlIGJlaW5nIHBsb3RlZCBhbmQgd2FudCB0byBzdGFydCBleHBsb3JpbmcuCgoqKlRoZSB5IGF4aXMvYWVzdGhldGljKio6IGBnZW9tX2hpc3RvZ3JhbSgpYCBvbmx5IHJlcXVpcmVzIG9uZSBhZXN0aGV0aWM6IGB4YC4gQnV0IHRoZXJlIGlzIGNsZWFybHkgYSBgeWAgYXhpcyBvbiB5b3VyIHBsb3QsIHNvIHdoZXJlIGRvZXMgaXQgY29tZSBmcm9tPyBBY3R1YWxseSwgdGhlcmUgaXMgYSB2YXJpYWJsZSBtYXBwZWQgdG8gdGhlIHkgYWVzdGhldGljLCBpdCdzIGNhbGxlZCBgLi5jb3VudC4uYC4gV2hlbiBgZ2VvbV9oaXN0b2dyYW0oKWAgZXhlY3V0ZWQgdGhlIGJpbm5pbmcgc3RhdGlzdGljIChzZWUgYWJvdmUpLCBpdCBub3Qgb25seSBjdXQgdXAgdGhlIGRhdGEgaW50byBkaXNjcmV0ZSBiaW5zLCBidXQgaXQgYWxzbyAqY291bnRlZCogaG93IG1hbnkgdmFsdWVzIGFyZSBpbiBlYWNoIGJpbi4gU28gdGhlcmUgaXMgYW4gKmludGVybmFsKiBkYXRhIGZyYW1lIHdoZXJlIHRoaXMgaW5mb3JtYXRpb24gaXMgc3RvcmVkLiBUaGUgLi4gY2FsbHMgdGhlIHZhcmlhYmxlIGNvdW50IGZyb20gdGhpcyAqaW50ZXJuYWwqIGRhdGEgZnJhbWUuIFRoaXMgaXMgd2hhdCBhcHBlYXJzIG9uIHRoZSBgeWAgYWVzdGhldGljLiBCdXQgaXQgZ2V0cyBiZXR0ZXIhIFRoZSAqZGVuc2l0eSogaGFzIGFsc28gYmVlbiBjYWxjdWxhdGVkLiBUaGlzIGlzIHRoZSAqcHJvcG9ydGlvbmFsIGZyZXF1ZW5jeSogb2YgdGhpcyBiaW4gaW4gcmVsYXRpb24gdG8gdGhlIHdob2xlIGRhdGEgc2V0LiBZb3UgdXNlIGAuLmRlbnNpdHkuLmAgdG8gYWNjZXNzIHRoaXMgaW5mb3JtYXRpb24uCgojIyMgSW5zdHJ1Y3Rpb25zCgotIFVzZSB0aGUgYG10Y2Fyc2AgZGF0YSBmcmFtZSBhbmQgbWFrZSBhIHVuaXZhcmlhdGUgaGlzdG9ncmFtIGJ5IG1hcHBpbmcgYG1wZ2Agb250byB0aGUgYHhgIGFlc3RoZXRpYy4gVXNlIGBnZW9tX2hpc3RvZ3JhbSgpYCBmb3IgdGhlIGdlb20gbGF5ZXIuCi0gVGFrZSBwbG90IDEgYW5kIG1hbnVhbGx5IGNyZWF0ZSAxLXVuaXQgd2lkZSBiaW5zIHdpdGggdGhlIGBiaW53aWR0aCA9IDFgIGFyZ3VtZW50IGluIGBnZW9tX2hpc3RvZ3JhbSgpYC4KLSBUYWtlIHBsb3QgMiwgYW5kIG1hcCBgLi5kZW5zaXR5Li5gIG9udG8gdGhlIGB5YCBhZXN0aGV0aWMgKGkuZS4gaW5zaWRlIGFuIGBhZXMoKWApIGluc2lkZSBgZ2VvbV9oaXN0b2dyYW0oKWAuIFlvdSdsbCBoYXZlIHR3byBgYWVzKClgIGZ1bmN0aW9uczogb25lIGluc2lkZSBgZ2dwbG90KClgIGFuZCBhbm90aGVyIGluc2lkZSBgZ2VvbV9oaXN0b2dyYW0oKWAuIChTZWUgdGhlIGludHJvIHRleHQgZm9yIGEgZGlzY3Vzc2lvbiBvZiBgLi5kZW5zaXR5Li5gKS4KLSBUYWtlIHBsb3QgMyBhbmQgc2V0IHRoZSBhdHRyaWJ1dGUgYGZpbGxgLCB0aGUgaW5zaWRlIG9mIHRoZSBiYXJzLCB0byB0aGUgdmFsdWUgYCIjMzc3RUI4ImAgaW4gYGdlb21faGlzdG9ncmFtKClgLiBUaGlzIHNob3VsZCBub3QgYXBwZWFyIGluIGBhZXMoKWAsIHNpbmNlIGl0J3MgYW4gYXR0cmlidXRlLCBub3QgYW4gYWVzdGhldGljIG1hcHBpbmcuCgoKYGBge3J9CiMgMSAtIE1ha2UgYSB1bml2YXJpYXRlIGhpc3RvZ3JhbQpnZ3Bsb3QoX19fLCBhZXMoeCA9IF9fXykpICsKICBfX18oKQoKIyAyIC0gUGxvdCAxLCBwbHVzIHNldCBiaW53aWR0aCB0byAxIGluIHRoZSBnZW9tIGxheWVyCgoKCiMgMyAtIFBsb3QgMiwgcGx1cyBNQVAgLi5kZW5zaXR5Li4gdG8gdGhlIHkgYWVzdGhldGljIChpLmUuIGluIGEgc2Vjb25kIGFlcygpIGZ1bmN0aW9uKQoKCgojIDQgLSBwbG90IDMsIHBsdXMgU0VUIHRoZSBmaWxsIGF0dHJpYnV0ZSB0byAiIzM3N0VCOCIKCgoKYGBgCgoKIyMgUG9zaXRpb24KCkluIHRoZSBwcmV2aW91cyBjaGFwdGVyIHlvdSBzYXcgdGhhdCB0aGVyZSBhcmUgbG90cyBvZiB3YXlzIHRvIHBvc2l0aW9uIHNjYXR0ZXIgcGxvdHMuIExpa2V3aXNlLCB0aGUgYGdlb21fYmFyKClgIGFuZCBgZ2VvbV9oaXN0b2dyYW0oKWAgZ2VvbXMgYWxzbyBoYXZlIGEgYHBvc2l0aW9uYCBhcmd1bWVudCwgd2hpY2ggeW91IGNhbiB1c2UgdG8gc3BlY2lmeSBob3cgdG8gZHJhdyB0aGUgYmFycyBvZiB0aGUgcGxvdC4KClRocmVlIGBwb3NpdGlvbmAgYXJndW1lbnRzIHdpbGwgYmUgaW50cm9kdWNlZCBoZXJlOgoKLSBgc3RhY2tgOiBwbGFjZSB0aGUgYmFycyBvbiB0b3Agb2YgZWFjaCBvdGhlci4gQ291bnRzIGFyZSB1c2VkLiBUaGlzIGlzIHRoZSBkZWZhdWx0IHBvc2l0aW9uLgotIGBmaWxsYDogcGxhY2UgdGhlIGJhcnMgb24gdG9wIG9mIGVhY2ggb3RoZXIsIGJ1dCB0aGlzIHRpbWUgdXNlIHByb3BvcnRpb25zLgotIGBkb2RnZWA6IHBsYWNlIHRoZSBiYXJzIG5leHQgdG8gZWFjaCBvdGhlci4gQ291bnRzIGFyZSB1c2VkLgoKSW4gdGhpcyBleGVyY2lzZSB5b3UnbGwgZHJhdyB0aGUgdG90YWwgY291bnQgb2YgY2FycyBoYXZpbmcgYSBnaXZlbiBudW1iZXIgb2YgYGN5bGluZGVyc2AgKGN5bCksIGFjY29yZGluZyB0byBtYW51YWwgb3IgYXV0b21hdGljIHRyYW5zbWlzc2lvbiB0eXBlIChgYW1gKS4KClNpbmNlLCBpbiB0aGUgYnVpbHQtaW4gYG10Y2Fyc2AgZGF0YSBzZXQsIGBjeWxgIGFuZCBgYW1gIGFyZSBpbnRlZ2VycywgeW91IGhhdmUgdG8gY29udmVydCB0aGVtIGludG8gZmFjdG9yIHZhcmlhYmxlcy4KCiMjIyBJbnN0cnVjdGlvbnMKCi0gVXNpbmcgYG10Y2Fyc2AsIG1hcCBgY3lsYCBvbnRvIHRoZSBgeGAgYWVzdGhldGljIGFuZCBgYW1gIG9udG8gYGZpbGxgLiBVc2UgYGdlb21fYmFyKClgIHRvIG1ha2UgYSBiYXIgcGxvdC4KLSBUYWtlIHBsb3QgMSBhbmQgZXhwbGljaXRseSBzZXQgYHBvc2l0aW9uID0gInN0YWNrImAgaW4gYGdlb21fYmFyKClgLiBUaGlzIGRvZXNuJ3QgY2hhbmdlIGFueXRoaW5nLCBkb2VzIGl0PyBJdCB3YXMgbWVudGlvbmVkIGFib3ZlIHRoYXQgYCJzdGFjayJgIGlzIHRoZSBkZWZhdWx0LgotIFRha2UgcGxvdCAyIGFuZCBzZXQgYHBvc2l0aW9uID0gImZpbGwiYCBpbiBgZ2VvbV9iYXIoKWAuCi0gVGFrZSBwbG90IDMgYW5kIHNldCBgcG9zaXRpb24gPSAiZG9kZ2UiYCBpbiBgZ2VvbV9iYXIoKWAuCgpgYGB7cn0KIyBEcmF3IGEgYmFyIHBsb3Qgb2YgY3lsLCBmaWxsZWQgYWNjb3JkaW5nIHRvIGFtCmdncGxvdChfX18sIGFlcyh4ID0gX19fLCBmaWxsID0gX19fKSkgKwogIF9fXygpCgojIENoYW5nZSB0aGUgcG9zaXRpb24gYXJndW1lbnQgdG8gc3RhY2sKCgoKIyBDaGFuZ2UgdGhlIHBvc2l0aW9uIGFyZ3VtZW50IHRvIGZpbGwKCgoKIyBDaGFuZ2UgdGhlIHBvc2l0aW9uIGFyZ3VtZW50IHRvIGRvZGdlCgoKYGBgCgoKIyMgT3ZlcmxhcHBpbmcgYmFyIHBsb3RzCgpTbyBmYXIgeW91J3ZlIHNlZW4gdGhyZWUgZGlmZmVyZW50IHBvc2l0aW9ucyBmb3IgYmFyIHBsb3RzOiBgc3RhY2tgICh0aGUgZGVmYXVsdCksIGBkb2RnZWAgKHByZWZlcnJlZCksIGFuZCBgZmlsbGAgKHRvIHNob3cgcHJvcG9ydGlvbnMpLgoKSG93ZXZlciwgeW91IGNhbiBnbyBvbmUgc3RlcCBmdXJ0aGVyIGJ5IGFkanVzdGluZyB0aGUgZG9kZ2luZywgc28gdGhhdCB5b3VyIGJhcnMgcGFydGlhbGx5IG92ZXJsYXAgZWFjaCBvdGhlci4gRm9yIHRoaXMgZXhhbXBsZSB5b3UnbGwgYWdhaW4gdXNlIHRoZSBgbXRjYXJzYCBkYXRhc2V0LiBMaWtlIGxhc3QgdGltZSB5b3UgaGF2ZSB0byBjb252ZXJ0IGBjeWxgIGFuZCBgYW1gIGludG8gZmFjdG9ycyBpbnNpZGUgYG10Y2Fyc2AuCgpJbnN0ZWFkIG9mIHVzaW5nIGBwb3NpdGlvbiA9ICJkb2RnZSJgIHlvdSdyZSBnb2luZyB0byB1c2UgYHBvc2l0aW9uX2RvZGdlKClgLCBsaWtlIHlvdSBkaWQgd2l0aCBgcG9zaXRpb25faml0dGVyKClgIGluIHRoZSAqU2NhdHRlciBwbG90cyBhbmQgaml0dGVyaW5nICgxKSogZXhlcmNpc2UuIEhlcmUsIHlvdSdsbCBzYXZlIHRoaXMgYXMgYW4gb2JqZWN0LCBgcG9zbl9kYCwgc28gdGhhdCB5b3UgY2FuIGVhc2lseSByZXVzZSBpdC4KClJlbWVtYmVyLCB0aGUgcmVhc29uIHlvdSB3YW50IHRvIHVzZSBgcG9zaXRpb25fZG9kZ2UoKWAgKGFuZCBgcG9zaXRpb25faml0dGVyKClgKSBpcyB0byBzcGVjaWZ5IGhvdyBtdWNoIGRvZGdpbmcgKG9yIGppdHRlcmluZykgeW91IHdhbnQuCgojIyMgSW5zdHJ1Y3Rpb25zCgotIFRoZSBsYXN0IHBsb3QgZnJvbSB0aGUgbGFzdCBleGVyY2lzZSBoYXMgYmVlbiBwcm92aWRlZCBmb3IgeW91LgotIERlZmluZSBhIG5ldyBvYmplY3QgY2FsbGVkIGBwb3NuX2RgIGJ5IGNhbGxpbmcgYHBvc2l0aW9uX2RvZGdlKClgIHdpdGggdGhlIGFyZ3VtZW50IGB3aWR0aCA9IDAuMmAuCi0gVGFrZSBwbG90IDEgYW5kIG1ha2Ugc2xpZ2h0bHkgb3ZlcmxhcHBpbmcgYmFycyBieSB1c2luZyB0aGUgYHBvc2l0aW9uID0gcG9zbl9kYCBhcmd1bWVudC4KLSBUYWtlIHBsb3QgMyBhbmQgc2V0IGBhbHBoYSA9IDAuNmAgdG8gc2VlIHRoZSBvdmVybGFwIGluIGJhcnMuCgpgYGB7cn0KIyAxIC0gVGhlIGxhc3QgcGxvdCBmb3JtIHRoZSBwcmV2aW91cyBleGVyY2lzZQpnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IGN5bCwgZmlsbCA9IGFtKSkgKwogIGdlb21fYmFyKHBvc2l0aW9uID0gImRvZGdlIikKCiMgMiAtIERlZmluZSBwb3NuX2Qgd2l0aCBwb3NpdGlvbl9kb2RnZSgpCnBvc25fZCA8LSBfX18oKQoKIyAzIC0gQ2hhbmdlIHRoZSBwb3NpdGlvbiBhcmd1bWVudCB0byBwb3NuX2QKCgoKIyA0IC0gVXNlIHBvc25fZCBhcyBwb3NpdGlvbiBhbmQgYWRqdXN0IGFscGhhIHRvIDAuNgoKCgpgYGAKCgojIyBPdmVybGFwcGluZyBoaXN0b2dyYW1zCgpPdmVybGFwcGluZyBoaXN0b2dyYW1zIHBvc2Ugc2ltaWxhciBwcm9ibGVtcyB0byBvdmVybGFwcGluZyBiYXIgcGxvdHMsIGJ1dCB0aGVyZSBpcyBhIHVuaXF1ZSBzb2x1dGlvbiBoZXJlOiBhIGZyZXF1ZW5jeSBwb2x5Z29uLgoKVGhpcyBpcyBhIGdlb20gc3BlY2lmaWMgdG8gYmlubmVkIGRhdGEgdGhhdCBkcmF3cyBhIGxpbmUgY29ubmVjdGluZyB0aGUgdmFsdWUgb2YgZWFjaCBiaW4uIExpa2UgYGdlb21faGlzdG9ncmFtKClgLCBpdCB0YWtlcyBhIGBiaW53aWR0aGAgYXJndW1lbnQgYW5kIGJ5IGRlZmF1bHQgYHN0YXQgPSAiYmluImAgYW5kIGBwb3NpdGlvbiA9ICJpZGVudGl0eSJgLgoKIyMjIEluc3RydWN0aW9ucwoKLSBUaGUgY29kZSBmb3IgYSBiYXNpYyBoaXN0b2dyYW0gb2YgYG1wZ2AsIHdoaWNoIHlvdSd2ZSBhbHJlYWR5IHNlZW4sIGlzIHByb3ZpZGVkLiBFeHRlbmQgdGhlIGNvZGUgdG8gbWFwIGBjeWxgIG9udG8gYGZpbGxgIGluc2lkZSBgYWVzKClgLgotIFRoZSBkZWZhdWx0IHBvc2l0aW9uIGZvciBoaXN0b2dyYW1zIGlzIGAic3RhY2siYC4gQ29weSB5b3VyIHNvbHV0aW9uIHRvIHRoZSBmaXJzdCBleGVyY2lzZSBhbmQgc2V0IHRoZSBgcG9zaXRpb25gIGZvciB0aGUgaGlzdG9ncmFtIGJhcnMgdG8gYCJpZGVudGl0eSJgLgotIFVzaW5nIHRoZSBzYW1lIGRhdGEgYW5kIGJhc2UgbGF5ZXJzIGFzIGluIHRoZSBwcmV2aW91cyB0d28gcGxvdHMsIGNyZWF0ZSBhIHBsb3Qgd2l0aCBhIGBnZW9tX2ZyZXFwb2x5KClgLiBCZWNhdXNlIHlvdSdyZSBubyBsb25nZXIgd29ya2luZyB3aXRoIGJhcnMsIGNoYW5nZSB0aGUgYGFlcygpYCBmdW5jdGlvbjogYGN5bGAgc2hvdWxkIGJlIG1hcHBlZCBvbnRvIGBjb2xgLCBub3Qgb250byBgZmlsbGAuIFRoaXMgd2lsbCBjb3JyZWN0bHkgY29sb3IgdGhlIGdlb20uCgpgYGB7cn0KIyBBIGJhc2ljIGhpc3RvZ3JhbSwgYWRkIGNvbG9yaW5nIGRlZmluZWQgYnkgY3lsCmdncGxvdChtdGNhcnMsIGFlcyhtcGcpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAxKQoKIyBDaGFuZ2UgcG9zaXRpb24gdG8gaWRlbnRpdHkKCgoKIyBDaGFuZ2UgZ2VvbSB0byBmcmVxcG9seSAocG9zaXRpb24gaXMgaWRlbnRpdHkgYnkgZGVmYXVsdCkKCgpgYGAKCiMjIEJhciBwbG90cyB3aXRoIGNvbG9yIHJhbXAsIHBhcnQgMQoKSW4gdGhpcyBleGFtcGxlIG9mIGEgYmFyIHBsb3QsIHlvdSdsbCBmaWxsIGVhY2ggc2VnbWVudCBhY2NvcmRpbmcgdG8gYW4gb3JkaW5hbCB2YXJpYWJsZS4gVGhlIGJlc3Qgd2F5IHRvIGRvIHRoYXQgaXMgd2l0aCBhIHNlcXVlbnRpYWwgY29sb3Igc2VyaWVzLgoKWW91J2xsIGJlIHVzaW5nIHRoZSBgVm9jYWJgIGRhdGFzZXQgZnJvbSBlYXJsaWVyLiBTaW5jZSB0aGlzIGlzIGEgbXVjaCBsYXJnZXIgZGF0YXNldCB3aXRoIG1vcmUgY2F0ZWdvcmllcywgeW91J2xsIGFsc28gY29tcGFyZSBpdCB0byBhIHNpbXBsZXIgZGF0YXNldCwgYG10Y2Fyc2AuIEJvdGggZGF0YXNldHMgYXJlIG9yZGluYWwuCgojIyMgSW5zdHJ1Y3Rpb25zCgotIFRoZSBiYXIgcGxvdCBmcm9tIHRoZSBwcmV2aW91cyBleGVyY2lzZSBpcyBwcm92aWRlZCAtIGBjeWxgIGlzIG9uIHRoZSB4LWF4aXMgYW5kIGZpbGxlZCBhY2NvcmRpbmcgdG8gdHJhbnNtaXNzaW9uIHR5cGUsIGBhbWAuIE5vdGljZSBob3cgeW91IGNhbiBzZXQgdGhlIGNvbG9yIHBhbGV0dGUgdXNlZCB0byBmaWxsIHRoZSBiYXJzIHdpdGggYHNjYWxlX2ZpbGxfYnJld2VyKClgLiBGb3IgYSBmdWxsIGxpc3Qgb2YgcG9zc2libGUgY29sb3Igc2V0cywgaGF2ZSBhIGxvb2sgYXQgYD9icmV3ZXIucGFsYC4KLSBFeHBsb3JlIGBWb2NhYmAgd2l0aCBgc3RyKClgLiBOb3RpY2UgdGhhdCB0aGUgYGVkdWNhdGlvbmAgYW5kIGB2b2NhYnVsYXJ5YCB2YXJpYWJsZXMgaGF2ZSBhbHJlYWR5IGJlZW4gY29udmVydGVkIHRvIGZhY3RvciB2YXJpYWJsZXMgZm9yIHlvdS4KLSBNYWtlIGEgZmlsbGVkIGJhciBjaGFydCB3aXRoIHRoZSBgVm9jYWJgIGRhdGFzZXQuCiAgIC0gTWFwIGBlZHVjYXRpb25gIHRvIGB4YCBhbmQgYHZvY2FidWxhcnlgIHRvIGBmaWxsYC4KICAgLSBJbnNpZGUgYGdlb21fYmFyKClgLCBtYWtlIHN1cmUgdG8gc2V0IGBwb3NpdGlvbiA9ICJmaWxsImAuCiAgIC0gQWxsb3cgY29sb3IgYnJld2VyIHRvIGNob29zZSBhIGRlZmF1bHQgY29sb3IgcGFsZXR0ZSBieSB1c2luZyB0aGUgYXBwcm9wcmlhdGUgc2NhbGUgZnVuY3Rpb24sIHdpdGhvdXQgYXJndW1lbnRzLiBOb3RpY2UgaG93IHRoaXMgZ2VuZXJhdGVzIGEgd2FybmluZyBtZXNzYWdlIGFuZCBhbiBpbmNvbXBsZXRlIHBsb3QuCgpgYGB7cn0KIyBFeGFtcGxlIG9mIGhvdyB0byB1c2UgYSBicmV3ZWQgY29sb3IgcGFsZXR0ZQpnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IGN5bCwgZmlsbCA9IGFtKSkgKwogIGdlb21fYmFyKCkgKwogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiU2V0MSIpCgojIFVzZSBzdHIoKSBvbiBWb2NhYiB0byBjaGVjayBvdXQgdGhlIHN0cnVjdHVyZQoKCiMgUGxvdCBlZHVjYXRpb24gb24geCBhbmQgdm9jYWJ1bGFyeSBvbiBmaWxsCiMgVXNlIHRoZSBkZWZhdWx0IGJyZXdlZCBjb2xvciBwYWxldHRlCgoKYGBgCgoKIyMgQmFyIHBsb3RzIHdpdGggY29sb3IgcmFtcCwgcGFydCAyCgpJbiB0aGUgcHJldmlvdXMgZXhlcmNpc2UsIHlvdSBlbmRlZCB1cCB3aXRoIGFuIGluY29tcGxldGUgYmFyIHBsb3QuIFRoaXMgd2FzIGJlY2F1c2UgZm9yIGNvbnRpbnVvdXMgZGF0YSwgdGhlIGRlZmF1bHQgYFJDb2xvckJyZXdlcmAgcGFsZXR0ZSB0aGF0IGBzY2FsZV9maWxsX2JyZXdlcigpYCBjYWxscyBpcyBgIkJsdWVzImAuIFRoZXJlIGFyZSBvbmx5IDkgY29sb3VycyBpbiB0aGUgcGFsZXR0ZSwgYW5kIHNpbmNlIHlvdSBoYXZlIDExIGNhdGVnb3JpZXMsIHlvdXIgcGxvdCBsb29rZWQgc3RyYW5nZS4KCkluIHRoaXMgZXhlcmNpc2UsIHlvdSdsbCBtYW51YWxseSBjcmVhdGUgYSBjb2xvciBwYWxldHRlIHRoYXQgY2FuIGdlbmVyYXRlIGFsbCB0aGUgY29sb3VycyB5b3UgbmVlZC4gVG8gZG8gdGhpcyB5b3UnbGwgdXNlIGEgZnVuY3Rpb24gY2FsbGVkIGBjb2xvclJhbXBQYWxldHRlKClgLgoKVGhlIGlucHV0IGlzIGEgY2hhcmFjdGVyIHZlY3RvciBvZiAyIG9yIG1vcmUgY29sb3VyIHZhbHVlcywgZS5nLiBgIiNGRkZGRkYiYCAod2hpdGUpIGFuZCBgIiMwMDAwRkYiYCAocHVyZSBibHVlKS4gKFNlZSAqQWxsIGFib3V0IGF0dHJpYnV0ZXMsIHBhcnQgMSogZm9yIGEgZGlzY3Vzc2lvbiBvbiBoZXhhZGVjaW1hbCBjb2RlcykuCgpUaGUgb3V0cHV0IGlzIGl0c2VsZiBhIGZ1bmN0aW9uISBTbyB3aGVuIHlvdSBhc3NpZ24gaXQgdG8gYW4gb2JqZWN0LCB0aGF0IG9iamVjdCBzaG91bGQgYmUgdXNlZCBhcyBhIGZ1bmN0aW9uLiBUbyBzZWUgd2hhdCB3ZSBtZWFuLCBleGVjdXRlIHRoZSBmb2xsb3dpbmcgdGhyZWUgbGluZXM6CgpgYGB7cn0KbmV3X2NvbCA8LSBjb2xvclJhbXBQYWxldHRlKGMoIiNGRkZGRkYiLCAiIzAwMDBGRiIpKQpuZXdfY29sKDQpICMgdGhlIG5ld2x5IGV4dHJhcG9sYXRlZCBjb2xvdXJzCm11bnNlbGw6OnBsb3RfaGV4KG5ld19jb2woNCkpICMgUXVpY2sgYW5kIGRpcnR5IHBsb3QKYGBgCgoKYG5ld19jb2woKWAgaXMgYSBmdW5jdGlvbiB0aGF0IHRha2VzIG9uZSBhcmd1bWVudDogdGhlIG51bWJlciBvZiBjb2xvdXJzIHlvdSB3YW50IHRvIGV4dHJhcG9sYXRlLiBZb3Ugd2FudCB0byB1c2UgbmljZXIgY29sb3Vycywgc28gd2UndmUgYXNzaWduZWQgdGhlIGVudGlyZSBgIkJsdWVzImAgY29sb3VyIHBhbGV0dGUgZnJvbSB0aGUgYFJDb2xvckJyZXdlcmAgcGFja2FnZSB0byB0aGUgY2hhcmFjdGVyIHZlY3RvciBgYmx1ZXNgLgoKIyMjIEluc3RydWN0aW9ucwoKLSBMaWtlIGluIHRoZSBleGFtcGxlIGNvZGUgYWJvdmUsIGNyZWF0ZSBhIG5ldyBmdW5jdGlvbiBjYWxsZWQgYGJsdWVfcmFuZ2VgIHRoYXQgdXNlcyBgY29sb3JSYW1wUGFsZXR0ZSgpYCB0byBleHRyYXBvbGF0ZSBvdmVyIGFsbCA5IHZhbHVlcyBvZiB0aGUgYGJsdWVzYCBjaGFyYWN0ZXIgdmVjdG9yLgotIFRha2UgdGhlIHBsb3QgY29kZSBmcm9tIHRoZSBsYXN0IGV4ZXJjaXNlIChwcm92aWRlZCksIGFuZCBjaGFuZ2UgYHNjYWxlX2ZpbGxfYnJld2VyKClgIHRvIGJlIGBzY2FsZV9maWxsX21hbnVhbCgpYC4gU2V0IHRoZSBhcmd1bWVudCBgdmFsdWVzID0gYmx1ZV9yYW5nZSgxMSlgIGluc2lkZSBgc2NhbGVfZmlsbF9tYW51YWwoKWAuCgpgYGB7cn0KIyBGaW5hbCBwbG90IG9mIGxhc3QgZXhlcmNpc2UKZ2dwbG90KFZvY2FiLCBhZXMoeCA9IGVkdWNhdGlvbiwgZmlsbCA9IHZvY2FidWxhcnkpKSArCiAgZ2VvbV9iYXIocG9zaXRpb24gPSAiZmlsbCIpICsKICBzY2FsZV9maWxsX2JyZXdlcigpCgojIERlZmluaXRpb24gb2YgYSBzZXQgb2YgYmx1ZSBjb2xvcnMKYmx1ZXMgPC0gYnJld2VyLnBhbCg5LCAiQmx1ZXMiKSAjIGZyb20gdGhlIFJDb2xvckJyZXdlciBwYWNrYWdlCgojIDEgLSBNYWtlIGEgY29sb3IgcmFuZ2UgdXNpbmcgY29sb3JSYW1wUGFsZXR0ZSgpIGFuZCB0aGUgc2V0IG9mIGJsdWVzCl9fXyA8LSBfX18oX19fKQoKIyAyIC0gVXNlIGJsdWVfcmFuZ2UgdG8gYWRqdXN0IHRoZSBjb2xvciBvZiB0aGUgYmFycywgdXNlIHNjYWxlX2ZpbGxfbWFudWFsKCkKCgoKYGBgCgoKIyMgT3ZlcmxhcHBpbmcgaGlzdG9ncmFtcyAoMikKCkFzIGEgbGFzdCBleGFtcGxlIG9mIGJhciBwbG90cywgeW91J2xsIHJldHVybiB0byBoaXN0b2dyYW1zICh3aGljaCB5b3Ugbm93IHNlZSBhcmUganVzdCBhIHNwZWNpYWwgdHlwZSBvZiBiYXIgcGxvdCkuIFlvdSBzYXcgYSBuaWNlIHRyaWNrIGluIGEgcHJldmlvdXMgZXhlcmNpc2Ugb2YgaG93IHRvIHNsaWdodGx5IG92ZXJsYXAgYmFycywgYnV0IG5vdyB5b3UnbGwgc2VlIGhvdyB0byBvdmVybGFwIHRoZW0gY29tcGxldGVseS4gVGhpcyB3b3VsZCBiZSBuaWNlIGZvciBtdWx0aXBsZSBoaXN0b2dyYW1zLCBhcyBsb25nIGFzIHRoZXJlIGFyZSBub3QgdG9vIG1hbnkgZGlmZmVyZW50IG92ZXJsYXBzIQoKWW91J2xsIG1ha2UgYSBoaXN0b2dyYW0gdXNpbmcgdGhlIGBtcGdgIHZhcmlhYmxlIGluIHRoZSBgbXRjYXJzYCBkYXRhIGZyYW1lLgoKIyMjIEluc3RydWN0aW9ucwoKLSBBIGJhc2ljIGhpc3RvZ3JhbSBwbG90IGlzIHByb3ZpZGVkLgotIFRha2UgcGxvdCAxIGFuZCBtYXAgYGFtYCBvbnRvIGBmaWxsYCB3aXRoaW4gdGhlIGBhZXMoKWAgZnVuY3Rpb24uIFRoZSBkZWZhdWx0IHBvc2l0aW9uIGlzIGAic3RhY2siYC4KLSBUYWtlIHBsb3QgMiBhbmQgYWRkIHRoZSBgcG9zaXRpb25gIGFyZ3VtZW50IHdpdGhpbiBgZ2VvbV9oaXN0b2dyYW0oKWAuIFNldCBpdCB0byBgImRvZGdlImAuCi0gVGFrZSBwbG90IDMgYW5kIGNoYW5nZSB0aGUgYHBvc2l0aW9uYCBhcmd1bWVudCB0byBgImZpbGwiYC4gSW4gdGhpcyBjYXNlLCBub25lIG9mIHRoZXNlIHBvc2l0aW9ucyByZWFsbHkgd29yayB3ZWxsLCBiZWNhdXNlIGl0J3MgZGlmZmljdWx0IHRvIGNvbXBhcmUgdGhlIGRpc3RyaWJ1dGlvbnMgZGlyZWN0bHkuCi0gVGFrZSBwbG90IDQgYW5kIGNoYW5nZSB0aGUgYHBvc2l0aW9uYCBhcmd1bWVudCB0byBgImlkZW50aXR5ImAgYW5kIHNldCBgYWxwaGEgPSAwLjRgLiBUaGlzIHByb2R1Y2VzIG92ZXJsYXBwaW5nIGJhcnMuCi0gVGFrZSBwbG90IDUgYW5kIGNoYW5nZSB0aGUgYWVzdGhldGljIG1hcHBpbmcuIE1hcCBgY3lsIG9udG8gZmlsbGAuCgoKYGBge3J9CiMgMSAtIEJhc2ljIGhpc3RvZ3JhbSBwbG90IGNvbW1hbmQKZ2dwbG90KG10Y2FycywgYWVzKG1wZykpICsKICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDEpCgojIDIgLSBQbG90IDEsIEV4cGFuZCBhZXN0aGV0aWNzOiBhbSBvbnRvIGZpbGwKCgoKIyAzIC0gUGxvdCAyLCBjaGFuZ2UgcG9zaXRpb24gPSAiZG9kZ2UiCgoKCiMgNCAtIFBsb3QgMywgY2hhbmdlIHBvc2l0aW9uID0gImZpbGwiCgoKCiMgNSAtIFBsb3QgNCwgcGx1cyBjaGFuZ2UgcG9zaXRpb24gPSAiaWRlbnRpdHkiIGFuZCBhbHBoYSA9IDAuNAoKCgojIDYgLSBQbG90IDUsIHBsdXMgY2hhbmdlIG1hcHBpbmc6IGN5bCBvbnRvIGZpbGwKCgpgYGAKCgojIyBMaW5lIHBsb3RzCgpJbiB0aGUgdmlkZW8geW91IHNhdyBob3cgdG8gbWFrZSBsaW5lIHBsb3RzIHVzaW5nIHRpbWUgc2VyaWVzIGRhdGEuIFRvIGV4cGxvcmUgdGhpcyB0b3BpYywgeW91J2xsIHVzZSB0aGUgYGVjb25vbWljc2AgZGF0YSBmcmFtZSwgd2hpY2ggY29udGFpbnMgdGltZSBzZXJpZXMgZm9yIHVuZW1wbG95bWVudCBhbmQgcG9wdWxhdGlvbiBzdGF0aXN0aWNzIGZyb20gdGhlIEZlZGVyYWwgUmVzZXJ2ZSBCYW5rIG9mIFN0LiBMb3VpcyBpbiB0aGUgVVMuIFRoZSBkYXRhIGlzIGNvbnRhaW5lZCBpbiB0aGUgYGdncGxvdDJgIHBhY2thZ2UuCgpUbyBiZWdpbiB3aXRoLCB5b3UgY2FuIGxvb2sgYXQgaG93IHRoZSBtZWRpYW4gdW5lbXBsb3ltZW50IHRpbWUgYW5kIHRoZSB1bmVtcGxveW1lbnQgcmF0ZSAodGhlIG51bWJlciBvZiB1bmVtcGxveWVkIHBlb3BsZSBhcyBhIHByb3BvcnRpb24gb2YgdGhlIHBvcHVsYXRpb24pIGNoYW5nZSBvdmVyIHRpbWUuCgpJbiB0aGUgbmV4dCBleGVyY2lzZXMsIHlvdSdsbCBleHBsb3JlIHRvIGhvdyBhZGQgZW1iZWxsaXNobWVudHMgdG8gdGhlIGxpbmUgcGxvdHMsIHN1Y2ggYXMgcmVjZXNzaW9uIHBlcmlvZHMuCgojIyMgSW5zdHJ1Y3Rpb25zCgotIFByaW50IG91dCB0aGUgYGhlYWQoKWAgb2YgdGhlIGBlY29ub21pY3NgIGRhdGEgZnJhbWUuCi0gVXNlIHRoZSBgZWNvbm9taWNzYCBkYXRhIGZyYW1lIHRvIHBsb3QgYGRhdGVgIG9uIHRoZSBgeGAgYXhpcyBhbmQgYHVuZW1wbG95YCBvbiB0aGUgYHlgIGF4aXMuIFVzZSBgZ2VvbV9saW5lKClgLgotIENvcHksIHBhc3RlIGFuZCBhZGp1c3QgdGhlIGNvZGUgZm9yIHRoZSBwcmV2aW91cyBpbnN0cnVjdGlvbjogaW5zdGVhZCBvZiBgdW5lbXBsb3lgLCBwbG90IGB1bmVtcGxveS9wb3BgIHRvIHJlcHJlc2VudCB0aGUgZnJhY3Rpb24gb2YgdGhlIHRvdGFsIHBvcHVsYXRpb24gdGhhdCBpcyB1bmVtcGxveWVkLgoKYGBge3J9CiMgUHJpbnQgb3V0IGhlYWQgb2YgZWNvbm9taWNzCgoKIyBQbG90IHVuZW1wbG95IGFzIGEgZnVuY3Rpb24gb2YgZGF0ZSB1c2luZyBhIGxpbmUgcGxvdApnZ3Bsb3QoX19fLCBhZXMoeCA9IF9fXywgeSA9IF9fXykpICsKCgojIEFkanVzdCBwbG90IHRvIHJlcHJlc2VudCB0aGUgZnJhY3Rpb24gb2YgdG90YWwgcG9wdWxhdGlvbiB0aGF0IGlzIHVuZW1wbG95ZWQKCmBgYAoKCiMjIFBlcmlvZHMgb2YgcmVjZXNzaW9uCgpCeSB0aGVtc2VsdmVzLCB0aW1lIHNlcmllcyBvZnRlbiBjb250YWluIGVub3VnaCB2YWx1YWJsZSBpbmZvcm1hdGlvbiwgYnV0IHlvdSBhbHdheXMgd2FudCB0byBtYXhpbWl6ZSB0aGUgbnVtYmVyIG9mIHZhcmlhYmxlcyB5b3UgY2FuIHNob3cgaW4gYSBwbG90LiBUaGlzIGFsbG93cyB5b3UgKGFuZCB5b3VyIHZpZXdlcnMpIHRvIGJlZ2luIG1ha2luZyBjb21wYXJpc29ucyBiZXR3ZWVuIHRob3NlIHZhcmlhYmxlcyB0aGF0IHdvdWxkIG90aGVyd2lzZSBiZSBkaWZmaWN1bHQgb3IgaW1wb3NzaWJsZS4KCkhlcmUsIHlvdSdsbCBhZGQgc2hhZGVkIHJlZ2lvbnMgdG8gdGhlIGJhY2tncm91bmQgdG8gaW5kaWNhdGUgcmVjZXNzaW9uIHBlcmlvZHMuIEhvdyBkbyB1bmVtcGxveW1lbnQgcmF0ZSBhbmQgcmVjZXNzaW9uIHBlcmlvZCBpbnRlcmFjdCB3aXRoIGVhY2ggb3RoZXI/CgpJbiBhZGRpdGlvbiB0byB0aGUgYGVjb25vbWljc2AgZGF0YXNldCBmcm9tIGJlZm9yZSwgeW91J2xsIGFsc28gdXNlIHRoZSBgcmVjZXNzYCBkYXRhc2V0IGZvciB0aGUgcGVyaW9kcyBvZiByZWNlc3Npb24uIFRoZSBgcmVjZXNzYCBkYXRhIGZyYW1lIGNvbnRhaW5zIDIgdmFyaWFibGVzOiB0aGUgYGJlZ2luYCBwZXJpb2Qgb2YgdGhlIHJlY2Vzc2lvbiBhbmQgdGhlIGBlbmRgLiBJdCdzIGFscmVhZHkgYXZhaWxhYmxlIGluIHlvdXIgd29ya3NwYWNlLgoKIyMjIEluc3RydWN0aW9ucwoKRXhwYW5kIHRoZSBjb21tYW5kIGZyb20gdGhlIHByZXZpb3VzIGV4ZXJjaXNlIHdpdGggYGdlb21fcmVjdCgpYC4gWW91IHdpbGwgdXNlIHRoaXMgZ2VvbSBsYXllciB0byBkcmF3IHJlY3RhbmdsZXMgYWNyb3NzIHRoZSByZWNlc3Npb24gcGVyaW9kcy4gVGhlcmUgYSBmZXcgcGl0ZmFsbHMgaGVyZToKCi0gYGdlb21fcmVjdCgpYCB1c2VzIHRoZSBgcmVjZXNzIGRhdGFzZXRgLCBzbyBwYXNzIHRoaXMgZGlyZWN0bHkgYXMgYGRhdGEgPSByZWNlc3NgIGluc2lkZSBgZ2VvbV9yZWN0KClgLgotIFRoZSBgZ2VvbV9yZWN0KClgIGNvbW1hbmQgc2hvdWxkbid0IGluaGVyaXQgYWVzdGhldGljcyBmcm9tIHRoZSBiYXNlIGBnZ3Bsb3QoKWAgY29tbWFuZCBpdCBiZWxvbmdzIHRvLiBJdCB3b3VsZCByZXN1bHQgaW4gYW4gZXJyb3IsIHNpbmNlIHlvdSdyZSB1c2luZyBhIGRpZmZlcmVudCBkYXRhc2V0IGFuZCBpdCBkb2Vzbid0IGNvbnRhaW4gYHVuZW1wbG95YCBvciBgcG9wYC4gVGhhdCdzIHdoeSB5b3Ugc2hvdWxkIHNwZWNpZnkgYGluaGVyaXQuYWVzID0gRkFMU0VgIGluIGBnZW9tX3JlY3QoKWAuCi0gYGdlb21fcmVjdCgpYCBuZWVkcyBmb3VyIGFlc3RoZXRpY3M6IGB4bWluYCwgYHhtYXhgLCBgeW1pbmAgYW5kIGB5bWF4YC4gVGhlc2Ugc2hvdWxkIGJlIHNldCB0byBgYmVnaW5gLCBgZW5kYCBhbmQgYC1JbmZgLCBgK0luZmAsIHJlc3BlY3RpdmVseS4gRGVmaW5lIHRoZW0gd2l0aGluIGBhZXMoKWAuCi0gVGhlIHJlY3RhbmdsZXMgeW91IGFkZCB3aWxsIGJlIGJsYWNrIGFuZCBvcGFxdWUgYnkgZGVmYXVsdC4gU2V0IGBmaWxsYCB0byBgInJlZCJgIGFuZCBgYWxwaGFgIHRvIGAwLjJgIHRvIGltcHJvdmUgdGhpcy4gRGVmaW5lIHRoZW0gb3V0c2lkZSBgYWVzKClgLgoKYGBge3J9CnJlY2VzcyA8LSBkYXRhLmZyYW1lKAogIGJlZ2luID0gYygiMTk2OS0xMi0wMSIsIjE5NzMtMTEtMDEiLCIxOTgwLTAxLTAxIiwiMTk4MS0wNy0wMSIsIjE5OTAtMDctMDEiLCIyMDAxLTAzLTAxIiksIAogIGVuZCA9IGMoIjE5NzAtMTEtMDEiLCIxOTc1LTAzLTAxIiwiMTk4MC0wNy0wMSIsIjE5ODItMTEtMDEiLCIxOTkxLTAzLTAxIiwiMjAwMS0xMS0wMSIpLAogIHN0cmluZ3NBc0ZhY3RvcnMgPSBGCiAgKQoKbGlicmFyeShsdWJyaWRhdGUpCnJlY2VzcyRiZWdpbiA8LSB5bWQgKHJlY2VzcyRiZWdpbikKcmVjZXNzJGVuZCA8LSB5bWQgKHJlY2VzcyRlbmQpCgojIEJhc2ljIGxpbmUgcGxvdApnZ3Bsb3QoZWNvbm9taWNzLCBhZXMoeCA9IGRhdGUsIHkgPSB1bmVtcGxveS9wb3ApKSArCiAgZ2VvbV9saW5lKCkKCiMgRXhwYW5kIHRoZSBmb2xsb3dpbmcgY29tbWFuZCB3aXRoIGdlb21fcmVjdCgpIHRvIGRyYXcgdGhlIHJlY2VzcyBwZXJpb2RzCmdncGxvdChlY29ub21pY3MsIGFlcyh4ID0gZGF0ZSwgeSA9IHVuZW1wbG95L3BvcCkpICsKICBfX18oX19fID0gX19fLAogICAgICAgICBhZXMoX19fID0gX19fLCBfX18gPSBfX18sIF9fXyA9IF9fXywgX19fID0gX19fKSwKICAgICAgICAgX19fID0gRkFMU0UsIF9fXyA9ICJyZWQiLCBfX18gPSAwLjIpICsKICBnZW9tX2xpbmUoKQoKYGBgCgoK