1 Introduction

1.1 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.

1.1.1 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.

1.2 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.

1.2.1 Instructions

  • Change the ggplot() command by wrapping factor() around cyl.
  • Executer and see if the resulting plot is better this time.

1.3 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!

1.3.1 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.

1.4 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?

1.4.1 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.

1.5 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.

1.5.1 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.

1.6 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.

1.6.1 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.

1.7 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.

1.7.1 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.

1.8 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.

1.8.1 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.

2 Data

2.1 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.

2.1.1 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.

2.2 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.

2.2.1 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.

2.3 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.

2.3.1 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.

2.4 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?

2.4.1 Answer the question

Possible Answers

  1. ggplot2 creates plotting objects, which can be manipulated.
  2. ggplot2 takes care of a lot of the leg work for you, such as choosing nice color pallettes and making legends.
  3. 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.
  4. Options 1, 2, and 3.
  5. ggplot2 is effectively a replacement for all base-package plotting functions.

2.5 Plotting the ggplot2 way

There are different ggplot2 calls to plot two groups of data onto the same plot:

Which one is preferable? Both iris and iris.wide are available in the workspace, so you can experiment in the R Console straight away!

2.5.1 Instructions

Possible Answers

  • Option 1.
  • Option 2.
  • Both are equally preferable.

2.6 Variables to visuals, part 1

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?

2.6.1 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.

2.7 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.

2.7.1 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.

2.8 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?

2.8.1 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.

2.9 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.

2.9.1 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.

3 Aesthetics

3.1 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.

3.1.1 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,,mpgontoy, andcylontocolor`.
  • 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().

3.2 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.

3.2.1 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.

3.3 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.

3.3.1 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().

3.4 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.

3.4.1 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().

3.5 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.

3.5.1 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).

3.6 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.

3.6.1 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.

3.7 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?

3.7.1 Instructions

Possible Answers

  • color & fill
  • alpha & size
  • label & shape
  • alpha & label
  • x & y

3.8 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:

3.8.1 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.

3.9 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).

3.9.1 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).

3.10 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.

3.10.1 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.

3.11 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

3.11.1 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().

4 Geometries

4.1 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.

4.1.1 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.

4.2 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.

4.2.1 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.

4.3 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.

4.3.1 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.

4.4 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.

4.4.1 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().

4.5 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.

4.5.1 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.

4.6 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".

4.6.1 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.

4.7 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.

4.7.1 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.

4.8 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.

4.8.1 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().

4.9 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.

4.9.1 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.

4.10 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.

4.10.1 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.

4.11 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.

4.11.1 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().
LS0tCnRpdGxlOiAiVmlzdWFsaXphdGlvbiB3aXRoIGBnZ3Bsb3QyYCIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICBoaWdobGlnaHQ6IGhhZGRvY2sKICAgIG51bWJlcl9zZWN0aW9uczogeWVzCiAgICB0aGVtZTogY2VydWxlYW4KICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6IDIKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiB5ZXMKICAgIHRvY19kZXB0aDogMgotLS0KCmBgYHtyIHNldHVwLCBlY2hvID0gRkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChldmFsID0gRkFMU0UpCmBgYAoKIyBJbnRyb2R1Y3Rpb24KCiMjIEV4cGxvcmluZyBgZ2dwbG90MmAsIHBhcnQgMQoKVG8gZ2V0IGEgZmlyc3QgZmVlbCBmb3IgYGdncGxvdDJgLCBsZXQncyB0cnkgdG8gcnVuIHNvbWUgYmFzaWMgYGdncGxvdDJgIGNvbW1hbmRzLiBUb2dldGhlciwgdGhleSBidWlsZCBhIHBsb3Qgb2YgdGhlIGBtdGNhcnNgIGRhdGFzZXQgdGhhdCBjb250YWlucyBpbmZvcm1hdGlvbiBhYm91dCAzMiBjYXJzIGZyb20gYSAxOTczIE1vdG9yIFRyZW5kIG1hZ2F6aW5lLiBUaGlzIGRhdGFzZXQgaXMgc21hbGwsIGludHVpdGl2ZSwgYW5kIGNvbnRhaW5zIGEgdmFyaWV0eSBvZiBjb250aW51b3VzIGFuZCBjYXRlZ29yaWNhbCB2YXJpYWJsZXMuCgojIyMgSW5zdHJ1Y3Rpb25zCgotIExvYWQgdGhlIGBnZ3Bsb3QyYCBwYWNrYWdlIHVzaW5nIGBsaWJyYXJ5KClgLiAKLSBVc2UgYHN0cigpYCB0byBleHBsb3JlIHRoZSBzdHJ1Y3R1cmUgb2YgdGhlIGBtdGNhcnNgIGRhdGFzZXQuCi0gRXhlY3V0ZSB0aGUgZXhhbXBsZSBjb2RlIGJlbG93LiBTZWUgaWYgeW91IGNhbiB1bmRlcnN0YW5kIHdoYXQgZ2dwbG90IGRvZXMgd2l0aCB0aGUgZGF0YS4KCmBgYHtyfQojIExvYWQgdGhlIGdncGxvdDIgcGFja2FnZQoKCiMgRXhwbG9yZSB0aGUgbXRjYXJzIGRhdGEgZnJhbWUgd2l0aCBzdHIoKQoKCiMgRXhlY3V0ZSB0aGUgZm9sbG93aW5nIGNvbW1hbmQKZ2dwbG90KG10Y2FycywgYWVzKHggPSBjeWwsIHkgPSBtcGcpKSArCiAgZ2VvbV9wb2ludCgpCmBgYAoKCiMjIEV4cGxvcmluZyBgZ2dwbG90MmAsIHBhcnQgMgoKVGhlIHBsb3QgZnJvbSB0aGUgcHJldmlvdXMgZXhlcmNpc2Ugd2Fzbid0IHJlYWxseSBzYXRpc2Z5aW5nLiBBbHRob3VnaCBgY3lsYCAodGhlIG51bWJlciBvZiBjeWxpbmRlcnMpIGlzIGNhdGVnb3JpY2FsLCBpdCBpcyBjbGFzc2lmaWVkIGFzIG51bWVyaWMgaW4gYG10Y2Fyc2AuIFlvdSdsbCBoYXZlIHRvIGV4cGxpY2l0bHkgdGVsbCBgZ2dwbG90MmAgdGhhdCBgY3lsYCBpcyBhIGNhdGVnb3JpY2FsIHZhcmlhYmxlLgoKIyMjIEluc3RydWN0aW9ucwoKLSBDaGFuZ2UgdGhlIGBnZ3Bsb3QoKWAgY29tbWFuZCBieSB3cmFwcGluZyBgZmFjdG9yKClgIGFyb3VuZCBgY3lsYC4KLSBFeGVjdXRlciBhbmQgc2VlIGlmIHRoZSByZXN1bHRpbmcgcGxvdCBpcyBiZXR0ZXIgdGhpcyB0aW1lLgoKYGBge3J9CiMgTG9hZCB0aGUgZ2dwbG90MiBwYWNrYWdlCmxpYnJhcnkoZ2dwbG90MikKCiMgQ2hhbmdlIHRoZSBjb21tYW5kIGJlbG93IHNvIHRoYXQgY3lsIGlzIHRyZWF0ZWQgYXMgZmFjdG9yCmdncGxvdChtdGNhcnMsIGFlcyh4ID0gY3lsLCB5ID0gbXBnKSkgKwogIGdlb21fcG9pbnQoKQpgYGAKCgojIyBFeHBsb3JpbmcgYGdncGxvdDJgLCBwYXJ0IDMKCldlJ2xsIHVzZSBzZXZlcmFsIGRhdGFzZXRzIHRocm91Z2hvdXQgdGhlIGNvdXJzZXMgdG8gc2hvd2Nhc2UgdGhlIGNvbmNlcHRzIGRpc2N1c3NlZCBpbiB0aGUgdmlkZW9zLiBJbiB0aGUgcHJldmlvdXMgZXhlcmNpc2VzLCB5b3UgYWxyZWFkeSBnb3QgdG8ga25vdyBgbXRjYXJzYC4gTGV0J3MgZGl2ZSBhIGxpdHRsZSBkZWVwZXIgdG8gZXhwbG9yZSB0aGUgdGhyZWUgbWFpbiB0b3BpY3MgaW4gdGhpcyBjb3Vyc2U6IFRoZSBkYXRhLCBhZXN0aGV0aWNzLCBhbmQgZ2VvbSBsYXllcnMuCgpUaGUgYG10Y2Fyc2AgZGF0YXNldCBjb250YWlucyBpbmZvcm1hdGlvbiBhYm91dCAzMiBjYXJzIGZyb20gMTk3MyBNb3RvciBUcmVuZCBtYWdhemluZS4gVGhpcyBkYXRhc2V0IGlzIHNtYWxsLCBpbnR1aXRpdmUsIGFuZCBjb250YWlucyBhIHZhcmlldHkgb2YgY29udGludW91cyBhbmQgY2F0ZWdvcmljYWwgdmFyaWFibGVzLgoKWW91J3JlIGVuY291cmFnZWQgdG8gdGhpbmsgYWJvdXQgaG93IHRoZSBleGFtcGxlcyBhbmQgY29uY2VwdHMgd2UgZGlzY3VzcyB0aHJvdWdob3V0IHRoZXNlIGRhdGEgdml6IGNvdXJzZXMgYXBwbHkgdG8geW91ciBvd24gZGF0YS1zZXRzIQoKIyMjIEluc3RydWN0aW9ucwoKLSBgZ2dwbG90MmAgaGFzIGFscmVhZHkgYmVlbiBsb2FkZWQgZm9yIHlvdS4gVGFrZSBhIGxvb2sgYXQgdGhlIGZpcnN0IGNvbW1hbmQuIEl0IHBsb3RzIHRoZSBgbXBnYCAobWlsZXMgcGVyIGdhbG9uKSBhZ2FpbnN0IHRoZSBgd2VpZ2h0YCAoaW4gdGhvdXNhbmRzIG9mIHBvdW5kcykuIFlvdSBkb24ndCBoYXZlIHRvIGNoYW5nZSBhbnl0aGluZyBhYm91dCB0aGlzIGNvbW1hbmQuCi0gSW4gdGhlIHNlY29uZCBjYWxsIG9mIGBnZ3Bsb3QoKWAgY2hhbmdlIHRoZSBgY29sb3JgIGFyZ3VtZW50IGluIGBhZXMoKWAgKHdoaWNoIHN0YW5kcyBmb3IgYWVzdGhldGljcykuIFRoZSBjb2xvciBzaG91bGQgYmUgZGVwZW5kZW50IG9uIHRoZSBkaXNwbGFjZW1lbnQgb2YgdGhlIGNhciBlbmdpbmUsIGZvdW5kIGluIGBkaXNwYC4KLSBJbiB0aGUgdGhpcmQgY2FsbCBvZiBgZ2dwbG90KClgIGNoYW5nZSB0aGUgYHNpemVgIGFyZ3VtZW50IGluIGBhZXMoKWAgKHdoaWNoIHN0YW5kcyBmb3IgYWVzdGhldGljcykuIFRoZSBzaXplIHNob3VsZCBiZSBkZXBlbmRlbnQgb24gdGhlIGRpc3BsYWNlbWVudCBvZiB0aGUgY2FyIGVuZ2luZSwgZm91bmQgaW4gYGRpc3BgLgoKYGBge3J9CiMgQSBzY2F0dGVyIHBsb3QgaGFzIGJlZW4gbWFkZSBmb3IgeW91CmdncGxvdChtdGNhcnMsIGFlcyh4ID0gd3QsIHkgPSBtcGcpKSArCiAgZ2VvbV9wb2ludCgpCgojIFJlcGxhY2UgX19fIHdpdGggdGhlIGNvcnJlY3QgY29sdW1uCmdncGxvdChtdGNhcnMsIGFlcyh4ID0gd3QsIHkgPSBtcGcsIGNvbG9yID0gX19fKSkgKwogIGdlb21fcG9pbnQoKQoKIyBSZXBsYWNlIF9fXyB3aXRoIHRoZSBjb3JyZWN0IGNvbHVtbgpnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IHd0LCB5ID0gbXBnLCBzaXplID0gX19fKSkgKwogIGdlb21fcG9pbnQoKQoKYGBgCgoKIyMgVW5kZXJzdGFuZGluZyBWYXJpYWJsZXMKCkluIHRoZSBwcmV2aW91cyBleGVyY2lzZSB5b3Ugc2F3IHRoYXQgYGRpc3BgIGNhbiBiZSBtYXBwZWQgb250byBhIGNvbG9yIGdyYWRpZW50IG9yIG9udG8gYSBjb250aW51b3VzIHNpemUgc2NhbGUuCgpBbm90aGVyIGFyZ3VtZW50IG9mIGBhZXMoKWAgaXMgdGhlIHNoYXBlIG9mIHRoZSBwb2ludHMuIFRoZXJlIGFyZSBhIGZpbml0ZSBudW1iZXIgb2Ygc2hhcGVzIHdoaWNoIGBnZ3Bsb3QoKWAgY2FuIGF1dG9tYXRpY2FsbHkgYXNzaWduIHRvIHRoZSBwb2ludHMuIEhvd2V2ZXIsIGlmIHlvdSB0cnkgdGhpcyBjb21tYW5kIGluIHRoZSBjb25zb2xlIHRvIHRoZSByaWdodDoKCmBgYHtyfQpnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IHd0LCB5ID0gbXBnLCBzaGFwZSA9IGRpc3ApKSArCiAgZ2VvbV9wb2ludCgpCmBgYAoKSXQgZ2l2ZXMgYW4gZXJyb3IuIFdoYXQgZG9lcyB0aGlzIG1lYW4/CgojIyMgSW5zdHJ1Y3Rpb25zCgpQb3NzaWJsZSBBbnN3ZXJzCgotIHNoYXBlIGlzIG5vdCBhIGRlZmluZWQgYXJndW1lbnQuCi0gc2hhcGUgb25seSBtYWtlcyBzZW5zZSB3aXRoIGNhdGVnb3JpY2FsIGRhdGEsIGFuZCBkaXNwIGlzIGNvbnRpbnVvdXMuCi0gc2hhcGUgb25seSBtYWtlcyBzZW5zZSB3aXRoIGNvbnRpbnVvdXMgZGF0YSwgYW5kIGRpc3AgaXMgY2F0ZWdvcmljYWwuCi0gc2hhcGUgaXMgbm90IGEgdmFyaWFibGUgaW4geW91ciBkYXRhc2V0LgotIHNoYXBlIGhhcyB0byBiZSBkZWZpbmVkIGFzIGEgZnVuY3Rpb24uCgoKIyMgRXhwbG9yaW5nIGBnZ3Bsb3QyYCwgcGFydCA0CgpUaGUgYGRpYW1vbmRzYCBkYXRhIGZyYW1lIGNvbnRhaW5zIGluZm9ybWF0aW9uIG9uIHRoZSBwcmljZXMgYW5kIHZhcmlvdXMgbWV0cmljcyBvZiA1MCwwMDAgZGlhbW9uZHMuIEFtb25nIHRoZSB2YXJpYWJsZXMgaW5jbHVkZWQgYXJlIGBjYXJhdGAgKGEgbWVhc3VyZW1lbnQgb2YgdGhlIHNpemUgb2YgdGhlIGRpYW1vbmQpIGFuZCBwcmljZS4gRm9yIHRoZSBuZXh0IGV4ZXJjaXNlcywgeW91J2xsIGJlIHVzaW5nIGEgc3Vic2V0IG9mIDEsMDAwIGRpYW1vbmRzLgoKSGVyZSB5b3UnbGwgdXNlIHR3byBjb21tb24gZ2VvbSBsYXllciBmdW5jdGlvbnM6IGBnZW9tX3BvaW50KClgIGFuZCBgZ2VvbV9zbW9vdGgoKWAuIFdlIGFscmVhZHkgc2F3IGluIHRoZSBlYXJsaWVyIGV4ZXJjaXNlcyBob3cgdGhlc2UgYXJlIGFkZGVkIHVzaW5nIHRoZSBgK2Agb3BlcmF0b3IuCgojIyMgSW5zdHJ1Y3Rpb25zCgotIEV4cGxvcmUgdGhlIGBkaWFtb25kc2AgZGF0YSBmcmFtZSB3aXRoIHRoZSBgc3RyKClgIGZ1bmN0aW9uLgotIFVzZSB0aGUgYCtgIG9wZXJhdG9yIHRvIGFkZCBgZ2VvbV9wb2ludCgpYCB0byB0aGUgZmlyc3QgYGdncGxvdCgpYCBjb21tYW5kLiBUaGlzIHdpbGwgdGVsbCBgZ2dwbG90MmAgdG8gZHJhdyBwb2ludHMgb24gdGhlIHBsb3QuCi0gVXNlIHRoZSBgK2Agb3BlcmF0b3IgdG8gYWRkIGBnZW9tX3BvaW50KClgIGFuZCBgZ2VvbV9zbW9vdGgoKWAuIFRoZXNlIGp1c3Qgc3RhY2sgb24gZWFjaCBvdGhlciEgYGdlb21fc21vb3RoKClgIHdpbGwgZHJhdyBhIHNtb290aGVkIGxpbmUgb3ZlciB0aGUgcG9pbnRzLgoKYGBge3J9CiMgRXhwbG9yZSB0aGUgZGlhbW9uZHMgZGF0YSBmcmFtZSB3aXRoIHN0cigpCgoKIyBBZGQgZ2VvbV9wb2ludCgpIHdpdGggKwpnZ3Bsb3QoZGlhbW9uZHMsIGFlcyh4ID0gY2FyYXQsIHkgPSBwcmljZSkpCgoKIyBBZGQgZ2VvbV9wb2ludCgpIGFuZCBnZW9tX3Ntb290aCgpIHdpdGggKwpnZ3Bsb3QoZGlhbW9uZHMsIGFlcyh4ID0gY2FyYXQsIHkgPSBwcmljZSkpCgoKYGBgCgoKIyMgRXhwbG9yaW5nIGBnZ3Bsb3QyYCwgcGFydCA1CgpUaGUgY29kZSBmb3IgbGFzdCBwbG90IG9mIHRoZSBwcmV2aW91cyBleGVyY2lzZSBpcyBhdmFpbGFibGUgaW4gdGhlIHNjcmlwdCBvbiB0aGUgcmlnaHQuIEl0IGJ1aWxkcyBhIHNjYXR0ZXIgcGxvdCBvZiB0aGUgYGRpYW1vbmRzYCBkYXRhc2V0LCB3aXRoIGBjYXJhdGAgb24gdGhlIHgtYXhpcyBhbmQgYHByaWNlYCBvbiB0aGUgeS1heGlzLiBgZ2VvbV9zbW9vdGgoKWAgaXMgdXNlZCB0byBhZGQgYSBzbW9vdGggbGluZS4KCldpdGggdGhpcyBwbG90IGFzIGEgc3RhcnRpbmcgcG9pbnQsIGxldCdzIGV4cGxvcmUgc29tZSBtb3JlIHBvc3NpYmlsaXRpZXMgb2YgY29tYmluaW5nIGdlb21zLgoKIyMjIEluc3RydWN0aW9ucwoKLSBQbG90IDIgLSBDb3B5IGFuZCBwYXN0ZSBwbG90IDEsIGJ1dCBzaG93IG9ubHkgdGhlIHNtb290aCBsaW5lLCBubyBwb2ludHMuCi0gUGxvdCAzIC0gU2hvdyBvbmx5IHRoZSBzbW9vdGggbGluZSwgYnV0IGNvbG9yIGFjY29yZGluZyB0byBjbGFyaXR5IGJ5IHBsYWNpbmcgdGhlIGFyZ3VtZW50IGBjb2xvciA9IGNsYXJpdHlgIGluIHRoZSBgYWVzKClgIGZ1bmN0aW9uIG9mIHlvdXIgYGdncGxvdCgpYCBjYWxsLgotIFBsb3QgNCAtIERyYXcgdHJhbnNsdWNlbnQgY29sb3JlZCBwb2ludHMuCiAgIC0gQ29weSB0aGUgYGdncGxvdCgpYCBjb21tYW5kIGZyb20gcGxvdCAzICh3aXRoIGBjbGFyaXR5YCBtYXBwZWQgdG8gYGNvbG9yYCkuCiAgIC0gUmVtb3ZlIHRoZSBzbW9vdGggbGF5ZXIuCiAgIC0gQWRkIHRoZSBwb2ludHMgbGF5ZXIgYmFjayBpbi4KICAgLSBTZXQgYGFscGhhID0gMC40YCBpbnNpZGUgYGdlb21fcG9pbnQoKWAuIFRoaXMgd2lsbCBtYWtlIHRoZSBwb2ludHMgNDAlIHRyYW5zcGFyZW50LgoKYGBge3J9CiMgMSAtIFRoZSBwbG90IHlvdSBjcmVhdGVkIGluIHRoZSBwcmV2aW91cyBleGVyY2lzZQpnZ3Bsb3QoZGlhbW9uZHMsIGFlcyh4ID0gY2FyYXQsIHkgPSBwcmljZSkpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fc21vb3RoKCkKCiMgMiAtIENvcHkgdGhlIGFib3ZlIGNvbW1hbmQgYnV0IHNob3cgb25seSB0aGUgc21vb3RoIGxpbmUKCgoKIyAzIC0gQ29weSB0aGUgYWJvdmUgY29tbWFuZCBhbmQgYXNzaWduIHRoZSBjb3JyZWN0IHZhbHVlIHRvIGNvbCBpbiBhZXMoKQoKCgojIDQgLSBLZWVwIHRoZSBjb2xvciBzZXR0aW5ncyBmcm9tIHByZXZpb3VzIGNvbW1hbmQuIFBsb3Qgb25seSB0aGUgcG9pbnRzIHdpdGggYXJndW1lbnQgYWxwaGEuCgoKYGBgCgoKIyMgVW5kZXJzdGFuZGluZyB0aGUgZ3JhbW1hciwgcGFydCAxCgpIZXJlIHlvdSdsbCBleHBsb3JlIHNvbWUgb2YgdGhlIGRpZmZlcmVudCBncmFtbWF0aWNhbCBlbGVtZW50cy4gVGhyb3VnaG91dCB0aGlzIGNvdXJzZSwgeW91J2xsIGRpc2NvdmVyIGhvdyB0aGV5IGNhbiBiZSBjb21iaW5lZCBpbiBhbGwgc29ydHMgb2Ygd2F5cyB0byBkZXZlbG9wIHVuaXF1ZSBwbG90cy4KCkluIHRoZSBmb2xsb3dpbmcgaW5zdHJ1Y3Rpb25zLCB5b3UnbGwgc3RhcnQgYnkgY3JlYXRpbmcgYSBgZ2dwbG90YCBvYmplY3QgZnJvbSB0aGUgZGlhbW9uZHMgZGF0YXNldC4gTmV4dCwgeW91J2xsIGFkZCBsYXllcnMgb250byB0aGlzIG9iamVjdCB0byBidWlsZCBiZWF1dGlmdWwgJiBpbmZvcm1hdGl2ZSBwbG90cy4KCiMjIyBJbnN0cnVjdGlvbnMKCi0gRGVmaW5lIHRoZSBkYXRhIChgZGlhbW9uZHNgKSBhbmQgYWVzdGhldGljcyBsYXllcnMuIE1hcCBgY2FyYXRgIG9uIHRoZSB4IGF4aXMgYW5kIGBwcmljZWAgb24gdGhlIHkgYXhpcy4gQXNzaWduIGl0IHRvIGFuIG9iamVjdDogYGRpYV9wbG90YC4KLSBVc2luZyBgK2AsIGFkZCBhIGBnZW9tX3BvaW50KClgIGxheWVyICh3aXRoIG5vIGFyZ3VtZW50cyksIHRvIHRoZSBgZGlhX3Bsb3RgIG9iamVjdC4gVGhpcyBjYW4gYmUgaW4gYSBzaW5nbGUgb3IgbXVsdGlwbGUgbGluZXMuCi0gTm90ZSB0aGF0IHlvdSBjYW4gYWxzbyBjYWxsIGBhZXMoKWAgd2l0aGluIHRoZSBgZ2VvbV9wb2ludCgpYCBmdW5jdGlvbi4gTWFwIGBjbGFyaXR5YCB0byB0aGUgYGNvbG9yYCBhcmd1bWVudCBpbiB0aGlzIHdheS4KCmBgYHtyfQojIENyZWF0ZSB0aGUgb2JqZWN0IGNvbnRhaW5pbmcgdGhlIGRhdGEgYW5kIGFlcyBsYXllcnM6IGRpYV9wbG90Cl9fXyA8LSBnZ3Bsb3QoX19fLCBhZXMoeCA9IF9fXywgeSA9IF9fXykKCiMgQWRkIGEgZ2VvbSBsYXllciB3aXRoICsgYW5kIGdlb21fcG9pbnQoKQpfX18gKyBfX18oKQoKIyBBZGQgdGhlIHNhbWUgZ2VvbSBsYXllciwgYnV0IHdpdGggYWVzKCkgaW5zaWRlCl9fXyArIF9fXyhhZXMoY29sb3IgPSBfX18pCgpgYGAKCgojIyBVbmRlcnN0YW5kaW5nIHRoZSBncmFtbWFyLCBwYXJ0IDIKCkNvbnRpbnVpbmcgd2l0aCB0aGUgcHJldmlvdXMgZXhlcmNpc2UsIGhlcmUgeW91J2xsIGV4cGxvcmUgbWl4aW5nIGFyZ3VtZW50cyBhbmQgYWVzdGhldGljcyBpbiBhIHNpbmdsZSBnZW9tZXRyeS4KCllvdSdyZSBzdGlsbCB3b3JraW5nIG9uIHRoZSBgZGlhbW9uZHNgIGRhdGFzZXQuCgojIyMgSW5zdHJ1Y3Rpb25zCgotIFRoZSBgZGlhX3Bsb3RgIG9iamVjdCBoYXMgYmVlbiBjcmVhdGVkIGZvciB5b3UuCi0gVXBkYXRlIGBkaWFfcGxvdGAgc28gdGhhdCBpdCBjb250YWlucyBhbGwgdGhlIGZ1bmN0aW9ucyB0byBtYWtlIGEgc2NhdHRlciBwbG90IGJ5IHVzaW5nIGBnZW9tX3BvaW50KClgIGZvciB0aGUgZ2VvbSBsYXllci4gU2V0IGBhbHBoYSA9IDAuMmAuCi0gVXNpbmcgYCtgLCBwbG90IHRoZSBgZGlhX3Bsb3RgIG9iamVjdCB3aXRoIGEgYGdlb21fc21vb3RoKClgIGxheWVyIG9uIHRvcC4gWW91IGRvbid0IHdhbnQgYW55IGVycm9yIHNoYWRpbmcsIHdoaWNoIGNhbiBiZSBhY2hpZXZlZCBieSBzZXR0aW5nIHRoZSBgc2UgPSBGQUxTRWAgaW4gYGdlb21fc21vb3RoKClgLgotIE1vZGlmeSB0aGUgYGdlb21fc21vb3RoKClgIGZ1bmN0aW9uIGZyb20gdGhlIHByZXZpb3VzIGluc3RydWN0aW9uIHNvIHRoYXQgaXQgY29udGFpbnMgYGFlcygpYCBhbmQgbWFwIGBjbGFyaXR5YCB0byB0aGUgYGNvbGAgYXJndW1lbnQuCgpgYGB7cn0KIyAxIC0gVGhlIGRpYV9wbG90IG9iamVjdCBoYXMgYmVlbiBjcmVhdGVkIGZvciB5b3UKZGlhX3Bsb3QgPC0gZ2dwbG90KGRpYW1vbmRzLCBhZXMoeCA9IGNhcmF0LCB5ID0gcHJpY2UpKQoKIyAyIC0gRXhwYW5kIGRpYV9wbG90IGJ5IGFkZGluZyBnZW9tX3BvaW50KCkgd2l0aCBhbHBoYSBzZXQgdG8gMC4yCmRpYV9wbG90IDwtIGRpYV9wbG90ICsgX19fKCkKCiMgMyAtIFBsb3QgZGlhX3Bsb3Qgd2l0aCBhZGRpdGlvbmFsIGdlb21fc21vb3RoKCkgd2l0aCBzZSBzZXQgdG8gRkFMU0UKZGlhX3Bsb3QgKyBfX18oX19fID0gX19fKQoKIyA0IC0gQ29weSB0aGUgY29tbWFuZCBmcm9tIGFib3ZlIGFuZCBhZGQgYWVzKCkgd2l0aCB0aGUgY29ycmVjdCBtYXBwaW5nIHRvIGdlb21fc21vb3RoKCkKZGlhX3Bsb3QgKyBfX18oYWVzKF9fXyA9IF9fXyksIF9fXyA9IF9fXykKCmBgYAoKCiMgRGF0YQoKIyMgYGJhc2VgIHBhY2thZ2UgYW5kIGBnZ3Bsb3QyYCwgcGFydCAxIC0gYHBsb3RgCgpUaGVzZSBjb3Vyc2VzIGFyZSBhYm91dCB1bmRlcnN0YW5kaW5nIGRhdGEgdmlzdWFsaXphdGlvbiBpbiB0aGUgY29udGV4dCBvZiB0aGUgZ3JhbW1hciBvZiBncmFwaGljcy4gVG8gZ2FpbiBhIGJldHRlciBhcHByZWNpYXRpb24gb2YgYGdncGxvdDJgIGFuZCB0byB1bmRlcnN0YW5kIGhvdyBpdCBvcGVyYXRlcyBkaWZmZXJlbnRseSBmcm9tIGBiYXNlYCBwYWNrYWdlLCBpdCdzIHVzZWZ1bCB0byBtYWtlIHNvbWUgY29tcGFyaXNvbnMuCgpGaXJzdCwgbGV0J3MgZm9jdXMgb24gYmFzZSBwYWNrYWdlLiBZb3Ugd2FudCB0byBtYWtlIGEgcGxvdCBvZiBgbXBnYCAobWlsZXMgcGVyIGdhbGxvbikgYWdhaW5zdCBgd3RgICh3ZWlnaHQgaW4gdGhvdXNhbmRzIG9mIHBvdW5kcykgaW4gdGhlIGBtdGNhcnNgIGRhdGEgZnJhbWUsIGJ1dCB0aGlzIHRpbWUgeW91IHdhbnQgdGhlIGRvdHMgY29sb3JlZCBhY2NvcmRpbmcgdG8gdGhlIG51bWJlciBvZiBjeWxpbmRlcnMsIGBjeWxgLiBIb3cgd291bGQgeW91IGRvIHRoYXQgaW4gYmFzZSBwYWNrYWdlPyBZb3UgY2FuIHVzZSBhIGxpdHRsZSB0cmljayB0byBjb2xvciB0aGUgZG90cyBieSBzcGVjaWZ5aW5nIGEgYGZhY3RvcmAgdmFyaWFibGUgYXMgYSBjb2xvci4gVGhpcyB3b3JrcyBiZWNhdXNlIGZhY3RvcnMgYXJlIGp1c3QgYSBzcGVjaWFsIGNsYXNzIG9mIHRoZSBgaW50ZWdlcmAgdHlwZS4KCiMjIyBJbnN0cnVjdGlvbnMKCi0gVXNpbmcgdGhlIGBiYXNlYCBwYWNrYWdlIGBwbG90KClgLCBtYWtlIGEgc2NhdHRlciBwbG90IHdpdGggYG10Y2FycyR3dGAgb24gdGhlIHgtYXhpcyBhbmQgYG10Y2FycyRtcGdgIG9uIHRoZSB5LWF4aXMsIGNvbG9yZWQgYWNjb3JkaW5nIHRvIGBtdGNhcnMkY3lsYCAodXNlIHRoZSBgY29sYCBhcmd1bWVudCkuIFlvdSBjYW4gc3BlY2lmeSBgZGF0YSA9YCBidXQgeW91J2xsIGp1c3QgZG8gaXQgdGhlIGxvbmcgd2F5IGhlcmUuCi0gQWRkIGEgbmV3IGNvbHVtbiwgYGZjeWxgLCB0byB0aGUgYG10Y2Fyc2AgZGF0YSBmcmFtZS4gVGhpcyBzaG91bGQgYmUgYGN5bGAgY29udmVydGVkIHRvIGEgZmFjdG9yLgotIENyZWF0ZSBhIHNpbWlsYXIgcGxvdCB0byBpbnN0cnVjdGlvbiAxLCBidXQgdGhpcyB0aW1lLCB1c2UgYGZjeWxgICh3aGljaCBpcyBgY3lsYCBhcyBhIGZhY3RvcikgdG8gc2V0IHRoZSBgY29sYC4KCmBgYHtyfQojIFBsb3QgdGhlIGNvcnJlY3QgdmFyaWFibGVzIG9mIG10Y2FycwpwbG90KG10Y2FycyRfX18sIG10Y2FycyRfX18sIF9fXyA9IG10Y2FycyRfX18pCgojIENoYW5nZSBjeWwgaW5zaWRlIG10Y2FycyB0byBhIGZhY3RvcgptdGNhcnMkZmN5bCA8LSBhcy5mYWN0b3IoX19fJF9fXykKCiMgTWFrZSB0aGUgc2FtZSBwbG90IGFzIGluIHRoZSBmaXJzdCBpbnN0cnVjdGlvbgoKYGBgCgoKIyMgYGJhc2VgIHBhY2thZ2UgYW5kIGBnZ3Bsb3QyYCwgcGFydCAyIC0gYGxtYAoKSWYgeW91IHdhbnQgdG8gYWRkIGEgbGluZWFyIG1vZGVsIHRvIHlvdXIgcGxvdCwgc2hvd24gcmlnaHQsIHlvdSBjYW4gZGVmaW5lIGl0IHdpdGggYGxtKClgIGFuZCB0aGVuIHBsb3QgdGhlIHJlc3VsdGluZyBsaW5lYXIgbW9kZWwgd2l0aCBgYWJsaW5lKClgLiBIb3dldmVyLCBpZiB5b3Ugd2FudCBhIG1vZGVsIGZvciBlYWNoIHN1Ymdyb3VwLCBhY2NvcmRpbmcgdG8gY3lsaW5kZXJzLCB0aGVuIHlvdSBoYXZlIGEgY291cGxlIG9mIG9wdGlvbnMuCgpZb3UgY2FuIHN1YnNldCB5b3VyIGRhdGEsIGFuZCB0aGVuIGNhbGN1bGF0ZSB0aGUgYGxtKClgIGFuZCBwbG90IGVhY2ggc3Vic2V0IHNlcGFyYXRlbHkuIEFsdGVybmF0aXZlbHksIHlvdSBjYW4gdmVjdG9yaXplIG92ZXIgdGhlIGBjeWxgIHZhcmlhYmxlIHVzaW5nIGBsYXBwbHkoKWAgYW5kIGNvbWJpbmUgdGhpcyBhbGwgaW4gb25lIHN0ZXAuIFRoaXMgb3B0aW9uIGlzIGFscmVhZHkgcHJlcGFyZWQgZm9yIHlvdS4KClRoZSBjb2RlIGJlbG93IGNvbnRhaW5zIGEgY2FsbCB0byB0aGUgZnVuY3Rpb24gYGxhcHBseSgpYCwgd2hpY2ggeW91IG1pZ2h0IG5vdCBoYXZlIHNlZW4gYmVmb3JlLiBUaGlzIGZ1bmN0aW9uIHRha2VzIGFzIGlucHV0IGEgdmVjdG9yIGFuZCBhIGZ1bmN0aW9uLiBUaGVuIGBsYXBwbHkoKWAgYXBwbGllcyB0aGUgZnVuY3Rpb24gaXQgd2FzIGdpdmVuIHRvIGVhY2ggZWxlbWVudCBvZiB0aGUgdmVjdG9yIGFuZCByZXR1cm5zIHRoZSByZXN1bHRzIGluIGEgbGlzdC4gSW4gdGhpcyBjYXNlLCBgbGFwcGx5KClgIHRha2VzIGVhY2ggZWxlbWVudCBvZiBgbXRjYXJzJGN5bGAgYW5kIGNhbGxzIHRoZSBmdW5jdGlvbiBkZWZpbmVkIGluIHRoZSBzZWNvbmQgYXJndW1lbnQuIFRoaXMgZnVuY3Rpb24gdGFrZXMgYSB2YWx1ZSBvZiBgbXRjYXJzJGN5bGAgYW5kIHRoZW4gc3Vic2V0cyB0aGUgZGF0YSBzbyB0aGF0IG9ubHkgcm93cyB3aXRoIGBjeWwgPT0geGAgYXJlIHVzZWQuIFRoZW4gaXQgZml0cyBhIGxpbmVhciBtb2RlbCB0byB0aGUgZmlsdGVyZWQgZGF0YXNldCBhbmQgdXNlcyB0aGF0IG1vZGVsIHRvIGFkZCBhIGxpbmUgdG8gdGhlIHBsb3Qgd2l0aCB0aGUgYGFibGluZSgpYCBmdW5jdGlvbi4KCk5vdyB0aGF0IHlvdSBoYXZlIGFuIGludGVyZXN0aW5nIHBsb3QsIHRoZXJlIGlzIGEgdmVyeSBpbXBvcnRhbnQgYXNwZWN0IG1pc3NpbmcgLSB0aGUgbGVnZW5kIQoKSW4gYmFzZSBwYWNrYWdlIHlvdSBoYXZlIHRvIHRha2UgY2FyZSBvZiB0aGlzIHVzaW5nIHRoZSBgbGVnZW5kKClgIGZ1bmN0aW9uLiBUaGlzIGhhcyBiZWVuIGRvbmUgZm9yIHlvdSBpbiB0aGUgcHJlZGVmaW5lZCBjb2RlLgoKIyMjIEluc3RydWN0aW9ucwoKLSBGaWxsIGluIHRoZSBgbG0oKWAgZnVuY3Rpb24gdG8gY2FsY3VsYXRlIGEgbGluZWFyIG1vZGVsIG9mIGBtcGdgIGRlc2NyaWJlZCBieSBgd3RgIGFuZCBzYXZlIGl0IGFzIGFuIG9iamVjdCBjYWxsZWQgYGNhck1vZGVsYC4KLSBEcmF3IHRoZSBsaW5lYXIgbW9kZWwgb24gdGhlIHNjYXR0ZXJwbG90LgogICAtIFdyaXRlIGNvZGUgdGhhdCBjYWxscyBgYWJsaW5lKClgIHdpdGggYGNhck1vZGVsYCBhcyB0aGUgZmlyc3QgYXJndW1lbnQuIFNldCB0aGUgbGluZSB0eXBlIGJ5IHBhc3NpbmcgdGhlIGFyZ3VtZW50IGBsdHkgPSAyYC4KICAgLSBSdW4gdGhlIGNvZGUgdGhhdCBnZW5lcmF0ZXMgdGhlIGJhc2ljIHBsb3QgYW5kIHRoZSBjYWxsIHRvIGBhYmxpbmUoKWAgYWxsIGF0IG9uY2UgYnkgaGlnaGxpZ2h0aW5nIGJvdGggcGFydHMgb2YgdGhlIHNjcmlwdCBhbmQgaGl0dGluZyBgY29udHJvbC9jb21tYW5kYCArIGBlbnRlcmAgb24geW91ciBrZXlib2FyZC4gVGhlc2UgbGluZXMgbXVzdCBhbGwgYmUgcnVuIHRvZ2V0aGVyIGluIHRoZSBjb25zb2xlIHNvIHRoYXQgUiB3aWxsIGJlIGFibGUgdG8gZmluZCB0aGUgcGxvdCB5b3Ugd2FudCB0byBhZGQgYSBsaW5lIHRvLgotIFJ1biB0aGUgY29kZSBhbHJlYWR5IGdpdmVuIHRvIGdlbmVyYXRlIHRoZSBwbG90IHdpdGggYSBkaWZmZXJlbnQgbW9kZWwgZm9yIGVhY2ggZ3JvdXAuIFlvdSBkb24ndCBuZWVkIHRvIG1vZGlmeSBhbnkgb2YgdGhpcy4KCmBgYHtyfQojIFVzZSBsbSgpIHRvIGNhbGN1bGF0ZSBhIGxpbmVhciBtb2RlbCBhbmQgc2F2ZSBpdCBhcyBjYXJNb2RlbApfX18gPC0gbG0oX19fIH4gX19fLCBkYXRhID0gbXRjYXJzKQoKIyBCYXNpYyBwbG90Cm10Y2FycyRjeWwgPC0gYXMuZmFjdG9yKG10Y2FycyRjeWwpCnBsb3QobXRjYXJzJHd0LCBtdGNhcnMkbXBnLCBjb2wgPSBtdGNhcnMkY3lsKQoKIyBDYWxsIGFibGluZSgpIHdpdGggY2FyTW9kZWwgYXMgZmlyc3QgYXJndW1lbnQgYW5kIHNldCBsdHkgdG8gMgpfX18oX19fLCBsdHkgPSBfX18pCgojIFBsb3QgZWFjaCBzdWJzZXQgZWZmaWNpZW50bHkgd2l0aCBsYXBwbHkKIyBZb3UgZG9uJ3QgaGF2ZSB0byBlZGl0IHRoaXMgY29kZQpwbG90KG10Y2FycyR3dCwgbXRjYXJzJG1wZywgY29sID0gbXRjYXJzJGN5bCkKbGFwcGx5KG10Y2FycyRjeWwsIGZ1bmN0aW9uKHgpIHsKICBhYmxpbmUobG0obXBnIH4gd3QsIG10Y2Fycywgc3Vic2V0ID0gKGN5bCA9PSB4KSksIGNvbCA9IHgpCiAgfSkKCiMgVGhpcyBjb2RlIHdpbGwgZHJhdyB0aGUgbGVnZW5kIG9mIHRoZSBwbG90CiMgWW91IGRvbid0IGhhdmUgdG8gZWRpdCB0aGlzIGNvZGUKbGVnZW5kKHggPSA1LCB5ID0gMzMsIGxlZ2VuZCA9IGxldmVscyhtdGNhcnMkY3lsKSwKICAgICAgIGNvbCA9IDE6MywgcGNoID0gMSwgYnR5ID0gIm4iKQpgYGAKCgojIyBgYmFzZWAgcGFja2FnZSBhbmQgYGdncGxvdDJgLCBwYXJ0IDMKCkluIHRoaXMgZXhlcmNpc2UgeW91J2xsIHJlY3JlYXRlIHRoZSBiYXNlIHBhY2thZ2UgcGxvdCBpbiBgZ2dwbG90MmAuCgpUaGUgY29kZSBmb3IgYmFzZSBSIHBsb3R0aW5nIGlzIGdpdmVuIGF0IHRoZSB0b3AuIFRoZSBmaXJzdCBsaW5lIG9mIGNvZGUgYWxyZWFkeSBjb252ZXJ0cyB0aGUgYGN5bGAgdmFyaWFibGUgb2YgYG10Y2Fyc2AgdG8gYSBmYWN0b3IuCgojIyMgSW5zdHJ1Y3Rpb25zCgotIFBsb3QgMTogYWRkIGBnZW9tX3BvaW50KClgIGluIG9yZGVyIHRvIG1ha2UgYSBzY2F0dGVyIHBsb3QuCi0gUGxvdCAyOiBjb3B5IGFuZCBwYXN0ZSBQbG90IDEKLSBBZGQgYSBsaW5lYXIgbW9kZWwgZm9yIGVhY2ggc3Vic2V0IGFjY29yZGluZyB0byBgY3lsYCBieSBhZGRpbmcgYSBgZ2VvbV9zbW9vdGgoKWAgbGF5ZXIKLSBJbnNpZGUgdGhpcyBgZ2VvbV9zbW9vdGgoKWAsIHNldCBtZXRob2QgdG8gYCJsbSJgIGFuZCBgc2VgIHRvIGBGQUxTRWAuIE5vdGU6IGBnZW9tX3Ntb290aCgpYCB3aWxsIGF1dG9tYXRpY2FsbHkgZHJhdyBhIGxpbmUgcGVyIGBjeWxgIHN1YnNldC4gSXQgcmVjb2duaXplcyB0aGUgZ3JvdXBzIHlvdSB3YW50IHRvIGlkZW50aWZ5IGJ5IGBjb2xvcmAgaW4gdGhlIGBhZXMoKWAgY2FsbCB3aXRoaW4gdGhlIGBnZ3Bsb3QoKWAgY29tbWFuZC4KLSBQbG90IDM6IGNvcHkgYW5kIHBhc3RlIFBsb3QgMgotIFBsb3QgYSBsaW5lYXIgbW9kZWwgZm9yIHRoZSBlbnRpcmUgZGF0YXNldCwgZG8gdGhpcyBieSBhZGRpbmcgYW5vdGhlciBgZ2VvbV9zbW9vdGgoKWAgbGF5ZXIKLSBTZXQgdGhlIGBncm91cGAgYWVzdGhldGljIGluc2lkZSB0aGlzIGBnZW9tX3Ntb290aCgpYCBsYXllciB0byBgMWAuIFRoaXMgaGFzIHRvIGJlIHNldCB3aXRoaW4gdGhlIGBhZXMoKWAgZnVuY3Rpb24uCi0gU2V0IGBtZXRob2RgIHRvIGAibG0iYCwgYHNlYCB0byBgRkFMU0VgIGFuZCBgbGluZXR5cGVgIHRvIGAyYC4gVGhlc2UgaGF2ZSB0byBiZSBzZXQgb3V0c2lkZSBgYWVzKClgIG9mIHRoZSBgZ2VvbV9zbW9vdGgoKWAuCgpOb3RlOiB0aGUgYGdyb3VwYCBhZXN0aGV0aWMgd2lsbCB0ZWxsIGBnZ3Bsb3QoKWAgdG8gZHJhdyBhIHNpbmdsZSBsaW5lYXIgbW9kZWwgdGhyb3VnaCBhbGwgdGhlIHBvaW50cy4KCmBgYHtyfQojIENvbnZlcnQgY3lsIHRvIGZhY3RvciAoZG9uJ3QgbmVlZCB0byBjaGFuZ2UpCm10Y2FycyRjeWwgPC0gYXMuZmFjdG9yKG10Y2FycyRjeWwpCgojIEV4YW1wbGUgZnJvbSBiYXNlIFIgKGRvbid0IG5lZWQgdG8gY2hhbmdlKQpwbG90KG10Y2FycyR3dCwgbXRjYXJzJG1wZywgY29sID0gbXRjYXJzJGN5bCkKYWJsaW5lKGxtKG1wZyB+IHd0LCBkYXRhID0gbXRjYXJzKSwgbHR5ID0gMikKbGFwcGx5KG10Y2FycyRjeWwsIGZ1bmN0aW9uKHgpIHsKICBhYmxpbmUobG0obXBnIH4gd3QsIG10Y2Fycywgc3Vic2V0ID0gKGN5bCA9PSB4KSksIGNvbCA9IHgpCiAgfSkKbGVnZW5kKHggPSA1LCB5ID0gMzMsIGxlZ2VuZCA9IGxldmVscyhtdGNhcnMkY3lsKSwKICAgICAgIGNvbCA9IDE6MywgcGNoID0gMSwgYnR5ID0gIm4iKQoKIyBQbG90IDE6IGFkZCBnZW9tX3BvaW50KCkgdG8gdGhpcyBjb21tYW5kIHRvIGNyZWF0ZSBhIHNjYXR0ZXIgcGxvdApnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IHd0LCB5ID0gbXBnLCBjb2wgPSBjeWwpKSArCiAgX19fICAjIEZpbGwgaW4gdXNpbmcgaW5zdHJ1Y3Rpb25zIFBsb3QgMQoKIyBQbG90IDI6IGluY2x1ZGUgdGhlIGxpbmVzIG9mIHRoZSBsaW5lYXIgbW9kZWxzLCBwZXIgY3lsCmdncGxvdChtdGNhcnMsIGFlcyh4ID0gd3QsIHkgPSBtcGcsIGNvbCA9IGN5bCkpICsKICBfX18gKyAjIENvcHkgZnJvbSBQbG90IDEKICBfX18gICAjIEZpbGwgaW4gdXNpbmcgaW5zdHJ1Y3Rpb25zIFBsb3QgMgoKIyBQbG90IDM6IGluY2x1ZGUgYSBsbSBmb3IgdGhlIGVudGlyZSBkYXRhc2V0IGluIGl0cyB3aG9sZQpnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IHd0LCB5ID0gbXBnLCBjb2wgPSBjeWwpKSArCiAgX19fICsgIyBDb3B5IGZyb20gUGxvdCAyCiAgX19fICsgIyBDb3B5IGZyb20gUGxvdCAyCiAgX19fICAgIyBGaWxsIGluIHVzaW5nIGluc3RydWN0aW9ucyBQbG90IDMKYGBgCgoKIyMgYGdncGxvdDJgIGNvbXBhcmVkIHRvIGBiYXNlYCBwYWNrYWdlCgpgZ2dwbG90MmAgaGFzIGJlY29tZSB2ZXJ5IHBvcHVsYXIgYW5kIGZvciBtYW55IHBlb3BsZSBpdCdzIHRoZSBnby10byBwbG90dGluZyBwYWNrYWdlIGluIFIuIFdoYXQgZG9lcyBgZ2dwbG90MmAgZG8gdGhhdCBgYmFzZWAgcGFja2FnZSBkb2Vzbid0PwoKIyMjIEFuc3dlciB0aGUgcXVlc3Rpb24KClBvc3NpYmxlIEFuc3dlcnMKCjEuIGBnZ3Bsb3QyYCBjcmVhdGVzIHBsb3R0aW5nIG9iamVjdHMsIHdoaWNoIGNhbiBiZSBtYW5pcHVsYXRlZC4KMi4gYGdncGxvdDJgIHRha2VzIGNhcmUgb2YgYSBsb3Qgb2YgdGhlIGxlZyB3b3JrIGZvciB5b3UsIHN1Y2ggYXMgY2hvb3NpbmcgbmljZSBjb2xvciBwYWxsZXR0ZXMgYW5kIG1ha2luZyBsZWdlbmRzLgozLiBgZ2dwbG90MmAgaXMgYnVpbHQgdXBvbiB0aGUgZ3JhbW1hciBvZiBncmFwaGljcyBwbG90dGluZyBwaGlsb3NvcGh5LCBtYWtpbmcgaXQgbW9yZSBmbGV4aWJsZSBhbmQgaW50dWl0aXZlIGZvciB1bmRlcnN0YW5kaW5nIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB5b3VyIHZpc3VhbHMgYW5kIHlvdXIgZGF0YS4KNC4gT3B0aW9ucyAxLCAyLCBhbmQgMy4KNS4gYGdncGxvdDJgIGlzIGVmZmVjdGl2ZWx5IGEgcmVwbGFjZW1lbnQgZm9yIGFsbCBiYXNlLXBhY2thZ2UgcGxvdHRpbmcgZnVuY3Rpb25zLgoKCiMjIFBsb3R0aW5nIHRoZSBnZ3Bsb3QyIHdheQoKVGhlcmUgYXJlIGRpZmZlcmVudCBgZ2dwbG90MmAgY2FsbHMgdG8gcGxvdCB0d28gZ3JvdXBzIG9mIGRhdGEgb250byB0aGUgc2FtZSBwbG90OgoKYGBge3J9CiMgT3B0aW9uIDEKZ2dwbG90KGlyaXMsIGFlcyh4ID0gU2VwYWwuTGVuZ3RoLCB5ID0gU2VwYWwuV2lkdGgpKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX3BvaW50KGFlcyh4ID0gUGV0YWwuTGVuZ3RoLCB5ID0gUGV0YWwuV2lkdGgpLCBjb2wgPSAicmVkIikKCmlyaXMud2lkZSA8LSByYmluZChkYXRhLmZyYW1lKFNwZWNpZXMgPSBpcmlzJFNwZWNpZXMsIFBhcnQgPSAiU2VwYWwiLCBMZW5ndGggPSBpcmlzJFNlcGFsLkxlbmd0aCwgV2lkdGggPSBpcmlzJFNlcGFsLldpZHRoKSwgZGF0YS5mcmFtZShTcGVjaWVzID0gaXJpcyRTcGVjaWVzLCBQYXJ0ID0gIlBldGFsIiwgTGVuZ3RoID0gaXJpcyRQZXRhbC5MZW5ndGgsIFdpZHRoID0gaXJpcyRQZXRhbC5XaWR0aCkpCgojIE9wdGlvbiAyCmdncGxvdChpcmlzLndpZGUsIGFlcyh4ID0gTGVuZ3RoLCB5ID0gV2lkdGgsIGNvbCA9IFBhcnQpKSArCiAgZ2VvbV9wb2ludCgpCmBgYAoKCldoaWNoIG9uZSBpcyBwcmVmZXJhYmxlPyBCb3RoIGBpcmlzYCBhbmQgYGlyaXMud2lkZWAgYXJlIGF2YWlsYWJsZSBpbiB0aGUgd29ya3NwYWNlLCBzbyB5b3UgY2FuIGV4cGVyaW1lbnQgaW4gdGhlIFIgQ29uc29sZSBzdHJhaWdodCBhd2F5IQoKIyMjIEluc3RydWN0aW9ucwoKUG9zc2libGUgQW5zd2VycwoKLSBPcHRpb24gMS4KLSBPcHRpb24gMi4KLSBCb3RoIGFyZSBlcXVhbGx5IHByZWZlcmFibGUuCgoKIyMgVmFyaWFibGVzIHRvIHZpc3VhbHMsIHBhcnQgMQoKYGBge3J9CmlyaXMud2lkZTIgPC0gcmJpbmQoCiAgIGRhdGEuZnJhbWUoTWVhc3VyZSA9ICJMZW5ndGgiLCBQYXJ0ID0gIlBldGFsIiwgU2V0b3NhID0gaXJpc1tpcmlzJFNwZWNpZXMgPT0gInNldG9zYSIsIlBldGFsLkxlbmd0aCJdLCBWZXJzaWNvbG9yID0gaXJpc1tpcmlzJFNwZWNpZXMgPT0gInZlcnNpY29sb3IiLCJQZXRhbC5MZW5ndGgiXSwgVmlyZ2luaWNhID0gaXJpc1tpcmlzJFNwZWNpZXMgPT0gInZpcmdpbmljYSIsIlBldGFsLkxlbmd0aCJdKSwKICAgZGF0YS5mcmFtZShNZWFzdXJlID0gIldpZHRoIiwgUGFydCA9ICJQZXRhbCIsIFNldG9zYSA9IGlyaXNbaXJpcyRTcGVjaWVzID09ICJzZXRvc2EiLCJQZXRhbC5XaWR0aCJdLCBWZXJzaWNvbG9yID0gaXJpc1tpcmlzJFNwZWNpZXMgPT0gInZlcnNpY29sb3IiLCJQZXRhbC5XaWR0aCJdLCBWaXJnaW5pY2EgPSBpcmlzW2lyaXMkU3BlY2llcyA9PSAidmlyZ2luaWNhIiwiUGV0YWwuV2lkdGgiXSksCiAgIGRhdGEuZnJhbWUoTWVhc3VyZSA9ICJMZW5ndGgiLCBQYXJ0ID0gIlNlcGFsIiwgU2V0b3NhID0gaXJpc1tpcmlzJFNwZWNpZXMgPT0gInNldG9zYSIsIlNlcGFsLkxlbmd0aCJdLCBWZXJzaWNvbG9yID0gaXJpc1tpcmlzJFNwZWNpZXMgPT0gInZlcnNpY29sb3IiLCJTZXBhbC5MZW5ndGgiXSwgVmlyZ2luaWNhID0gaXJpc1tpcmlzJFNwZWNpZXMgPT0gInZpcmdpbmljYSIsIlNlcGFsLkxlbmd0aCJdKSwKICAgZGF0YS5mcmFtZShNZWFzdXJlID0gIldpZHRoIiwgUGFydCA9ICJTZXBhbCIsIFNldG9zYSA9IGlyaXNbaXJpcyRTcGVjaWVzID09ICJzZXRvc2EiLCJTZXBhbC5XaWR0aCJdLCBWZXJzaWNvbG9yID0gaXJpc1tpcmlzJFNwZWNpZXMgPT0gInZlcnNpY29sb3IiLCJTZXBhbC5XaWR0aCJdLCBWaXJnaW5pY2EgPSBpcmlzW2lyaXMkU3BlY2llcyA9PSAidmlyZ2luaWNhIiwiU2VwYWwuV2lkdGgiXSkpCgppcmlzLnRpZHkgPC0gcmJpbmQoCiAgIGRhdGEuZnJhbWUoU3BlY2llcyA9IGlyaXMkU3BlY2llcywgUGFydCA9ICJTZXBhbCIsIE1lYXN1cmUgPSAiTGVuZ3RoIiwgVmFsdWUgPSBpcmlzJFNlcGFsLkxlbmd0aCksCiAgIGRhdGEuZnJhbWUoU3BlY2llcyA9IGlyaXMkU3BlY2llcywgUGFydCA9ICJTZXBhbCIsIE1lYXN1cmUgPSAiV2lkdGgiLCBWYWx1ZSA9IGlyaXMkU2VwYWwuTGVuZ3RoKSwKICAgZGF0YS5mcmFtZShTcGVjaWVzID0gaXJpcyRTcGVjaWVzLCBQYXJ0ID0gIlBldGFsIiwgTWVhc3VyZSA9ICJMZW5ndGgiLCBWYWx1ZSA9IGlyaXMkUGV0YWwuTGVuZ3RoKSwKICAgZGF0YS5mcmFtZShTcGVjaWVzID0gaXJpcyRTcGVjaWVzLCBQYXJ0ID0gIlBldGFsIiwgTWVhc3VyZSA9ICJXaWR0aCIsIFZhbHVlID0gaXJpcyRQZXRhbC5XaWR0aCkpCmBgYAoKClNvIGZhciB5b3UndmUgc2VlbiBmb3VyIGRpZmZlcmVudCBmb3JtcyBvZiB0aGUgaXJpcyBkYXRhc2V0OiBgaXJpc2AsIGBpcmlzLndpZGVgLCBgaXJpcy53aWRlMmAgYW5kIGBpcmlzLnRpZHlgLiBEb24ndCBsZXQgYWxsIHRoZXNlIGRpZmZlcmVudCBmb3JtcyBjb25mdXNlIHlvdSEgSXQncyBleGFjdGx5IHRoZSBzYW1lIGRhdGEsIGp1c3QgcmVhcnJhbmdlZCBzbyB0aGF0IHlvdXIgcGxvdHRpbmcgZnVuY3Rpb25zIGJlY29tZSBlYXNpZXIuCgpUbyBzZWUgdGhpcyBpbiBhY3Rpb24sIGNvbnNpZGVyIHRoZSBwbG90IGluIHRoZSBncmFwaGljcyBkZXZpY2UgYXQgcmlnaHQuIFdoaWNoIGZvcm0gb2YgdGhlIGRhdGFzZXQgd291bGQgYmUgdGhlIG1vc3QgYXBwcm9wcmlhdGUgdG8gdXNlIGhlcmU/CgojIyMgSW5zdHJ1Y3Rpb25zCgotIExvb2sgYXQgdGhlIHN0cnVjdHVyZXMgb2YgYGlyaXNgLCBgaXJpcy53aWRlYCBhbmQgYGlyaXMudGlkeWAgdXNpbmcgYHN0cigpYC4KLSBGaWxsIGluIHRoZSBgZ2dwbG90YCBmdW5jdGlvbiB3aXRoIHRoZSBhcHByb3ByaWF0ZSBkYXRhIGZyYW1lIGFuZCB2YXJpYWJsZSBuYW1lcy4gVGhlIHZhcmlhYmxlIG5hbWVzIG9mIHRoZSBhZXN0aGV0aWNzIG9mIHRoZSBwbG90IHdpbGwgbWF0Y2ggdGhlIG9uZXMgeW91IGZvdW5kIHVzaW5nIHRoZSBgc3RyKClgIGNvbW1hbmQgaW4gdGhlIHByZXZpb3VzIHN0ZXAuCgpgYGB7cn0KIyBDb25zaWRlciB0aGUgc3RydWN0dXJlIG9mIGlyaXMsIGlyaXMud2lkZSBhbmQgaXJpcy50aWR5IChpbiB0aGF0IG9yZGVyKQoKCgoKIyBUaGluayBhYm91dCB3aGljaCBkYXRhc2V0IHlvdSB3b3VsZCB1c2UgdG8gZ2V0IHRoZSBwbG90IHNob3duIHJpZ2h0CiMgRmlsbCBpbiB0aGUgX19fIHRvIHByb2R1Y2UgdGhlIHBsb3QgZ2l2ZW4gdG8gdGhlIHJpZ2h0CmdncGxvdChfX18sIGFlcyh4ID0gX19fLCB5ID0gX19fLCBjb2wgPSBfX18pKSArCiAgZ2VvbV9qaXR0ZXIoKSArCiAgZmFjZXRfZ3JpZCguIH4gX19fKQpgYGAKCgojIyBWYXJpYWJsZXMgdG8gdmlzdWFscywgcGFydCAxYgoKSW4gdGhlIGxhc3QgZXhlcmNpc2UgeW91IHNhdyBob3cgYGlyaXMudGlkeWAgd2FzIHVzZWQgdG8gbWFrZSBhIHNwZWNpZmljIHBsb3QuIEl0J3MgaW1wb3J0YW50IHRvIGtub3cgaG93IHRvIHJlYXJyYW5nZSB5b3VyIGRhdGEgaW4gdGhpcyB3YXkgc28gdGhhdCB5b3VyIHBsb3R0aW5nIGZ1bmN0aW9ucyBiZWNvbWUgZWFzaWVyLiBJbiB0aGlzIGV4ZXJjaXNlIHlvdSdsbCB1c2UgZnVuY3Rpb25zIGZyb20gdGhlIGB0aWR5cmAgcGFja2FnZSB0byBjb252ZXJ0IGBpcmlzYCB0byBgaXJpcy50aWR5YC4KClRoZSByZXN1bHRpbmcgYGlyaXMudGlkeWAgZGF0YSBzaG91bGQgbG9vayBhcyBmb2xsb3dzOgoKYGBgCiAgIFNwZWNpZXMgIFBhcnQgTWVhc3VyZSBWYWx1ZQogMSAgc2V0b3NhIFNlcGFsICBMZW5ndGggICA1LjEKIDIgIHNldG9zYSBTZXBhbCAgTGVuZ3RoICAgNC45CiAzICBzZXRvc2EgU2VwYWwgIExlbmd0aCAgIDQuNwogNCAgc2V0b3NhIFNlcGFsICBMZW5ndGggICA0LjYKIDUgIHNldG9zYSBTZXBhbCAgTGVuZ3RoICAgNS4wCiA2ICBzZXRvc2EgU2VwYWwgIExlbmd0aCAgIDUuNAogICAgLi4uCmBgYAoKWW91IGNhbiBoYXZlIGEgbG9vayBhdCB0aGUgYGlyaXNgIGRhdGFzZXQgYnkgdHlwaW5nIGBoZWFkKGlyaXMpYCBpbiB0aGUgY29uc29sZS4KCk5vdGU6IElmIHlvdSdyZSBub3QgZmFtaWxpYXIgd2l0aCBgJT4lYCwgYGdhdGhlcigpYCBhbmQgYHNlcGFyYXRlKClgLCB5b3UgbWF5IHdhbnQgdG8gdGFrZSB0aGUgYENsZWFuaW5nIERhdGFgIGluIFIgY291cnNlLiBJbiBhIG51dHNoZWxsLCBhIGRhdGFzZXQgaXMgY2FsbGVkIHRpZHkgd2hlbiBldmVyeSByb3cgaXMgYW4gb2JzZXJ2YXRpb24gYW5kIGV2ZXJ5IGNvbHVtbiBpcyBhIHZhcmlhYmxlLiBgVGhlIGdhdGhlcigpYCBmdW5jdGlvbiBtb3ZlcyBpbmZvcm1hdGlvbiBmcm9tIHRoZSBjb2x1bW5zIHRvIHRoZSByb3dzLiBJdCB0YWtlcyBtdWx0aXBsZSBjb2x1bW5zIGFuZCBnYXRoZXJzIHRoZW0gaW50byBhIHNpbmdsZSBjb2x1bW4gYnkgYWRkaW5nIHJvd3MuIFRoZSBgc2VwYXJhdGUoKWAgZnVuY3Rpb24gc3BsaXRzIG9uZSBjb2x1bW4gaW50byB0d28gb3IgbW9yZSBjb2x1bW5zIGFjY29yZGluZyB0byBhIHBhdHRlcm4geW91IGRlZmluZS4gTGFzdGx5LCB0aGUgYCU+JWAgKG9yICJwaXBlIikgb3BlcmF0b3IgcGFzc2VzIHRoZSByZXN1bHQgb2YgdGhlIGxlZnQtaGFuZCBzaWRlIGFzIHRoZSBmaXJzdCBhcmd1bWVudCBvZiB0aGUgZnVuY3Rpb24gb24gdGhlIHJpZ2h0LWhhbmQgc2lkZS4KCiMjIyBJbnN0cnVjdGlvbnMKCllvdSdsbCB1c2UgdHdvIGZ1bmN0aW9ucyBmcm9tIHRoZSBgdGlkeXJgIHBhY2thZ2U6CgotIGBnYXRoZXIoKWAgcmVhcnJhbmdlcyB0aGUgZGF0YSBmcmFtZSBieSBzcGVjaWZ5aW5nIHRoZSBjb2x1bW5zIHRoYXQgYXJlIGNhdGVnb3JpY2FsIHZhcmlhYmxlcyB3aXRoIGEgLSBub3RhdGlvbi4gQ29tcGxldGUgdGhlIGNvbW1hbmQuIE5vdGljZSB0aGF0IG9ubHkgb25lIHZhcmlhYmxlIGlzIGNhdGVnb3JpY2FsIGluIGlyaXMuCi0gYHNlcGFyYXRlKClgIHNwbGl0cyB1cCB0aGUgbmV3IGtleSBjb2x1bW4sIHdoaWNoIGNvbnRhaW5zIHRoZSBmb3JtZXIgaGVhZGVycywgYWNjb3JkaW5nIHRvIGAuYC4gVGhlIG5ldyBjb2x1bW4gbmFtZXMgIlBhcnQiIGFuZCAiTWVhc3VyZSIgYXJlIGdpdmVuIGluIGEgY2hhcmFjdGVyIHZlY3Rvci4gRG9uJ3QgZm9yZ2V0IHRoZSBxdW90ZXMuCgpgYGB7cn0KIyBMb2FkIHRoZSB0aWR5ciBwYWNrYWdlCmxpYnJhcnkodGlkeXIpCgojIEZpbGwgaW4gdGhlIF9fXyB0byBwcm9kdWNlIHRvIHRoZSBjb3JyZWN0IGlyaXMudGlkeSBkYXRhc2V0CmlyaXMudGlkeSA8LSBpcmlzICU+JQogIGdhdGhlcihrZXksIHZhbHVlLCAtX19fKSAlPiUKICBzZXBhcmF0ZShrZXksIGMoIl9fXyIsICJfX18iKSwgIlxcLiIpCmBgYAoKCiMjIFZhcmlhYmxlcyB0byB2aXN1YWxzLCBwYXJ0IDIKCkhlcmUgeW91J2xsIHRha2UgYSBsb29rIGF0IGFub3RoZXIgcGxvdCB2YXJpYW50LiBXaGljaCBvZiB5b3VyIGRhdGEgZnJhbWVzIHdvdWxkIGJlIHVzZWQgdG8gcHJvZHVjZSB0aGlzIHBsb3Q/CgohW10oaW1hZ2VzL3Bsb3QxLnBuZykKCiMjIyBJbnN0cnVjdGlvbnMKCi0gTG9vayBhdCB0aGUgaGVhZHMgb2YgYGlyaXNgLCBgaXJpcy53aWRlYCBhbmQgYGlyaXMudGlkeWAgdXNpbmcgYGhlYWQoKWAuCi0gRmlsbCBpbiB0aGUgYGdncGxvdGAgZnVuY3Rpb24gd2l0aCB0aGUgYXBwcm9wcmlhdGUgZGF0YSBmcmFtZSBhbmQgdmFyaWFibGUgbmFtZXMuIFRoZSBuYW1lcyBvZiB0aGUgYWVzdGhldGljcyBvZiB0aGUgcGxvdCB3aWxsIG1hdGNoIHdpdGggdmFyaWFibGUgbmFtZXMgaW4geW91ciBkYXRhc2V0LiBUaGUgcHJldmlvdXMgaW5zdHJ1Y3Rpb24gd2lsbCBoZWxwIHlvdSBtYXRjaCB2YXJpYWJsZSBuYW1lcyBpbiBkYXRhc2V0cyB3aXRoIHRoZSBvbmVzIGluIHRoZSBwbG90LgoKYGBge3J9CiMgVGhlIDMgZGF0YSBmcmFtZXMgKGlyaXMsIGlyaXMud2lkZSBhbmQgaXJpcy50aWR5KSBhcmUgYXZhaWxhYmxlIGluIHlvdXIgZW52aXJvbm1lbnQKIyBFeGVjdXRlIGhlYWQoKSBvbiBpcmlzLCBpcmlzLndpZGUgYW5kIGlyaXMudGlkeSAoaW4gdGhhdCBvcmRlcikKCgoKCiMgVGhpbmsgYWJvdXQgd2hpY2ggZGF0YXNldCB5b3Ugd291bGQgdXNlIHRvIGdldCB0aGUgcGxvdCBzaG93biByaWdodAojIEZpbGwgaW4gdGhlIF9fXyB0byBwcm9kdWNlIHRoZSBwbG90IGdpdmVuIHRvIHRoZSByaWdodApnZ3Bsb3QoX19fLCBhZXMoeCA9IF9fXywgeSA9IF9fXywgY29sb3IgPSBfX18pKSArCiAgZ2VvbV9qaXR0ZXIoKSArCiAgZmFjZXRfZ3JpZCguIH4gX19fKQpgYGAKCgojIyBWYXJpYWJsZXMgdG8gdmlzdWFscywgcGFydCAyYgoKWW91IHNhdyBwcmV2aW91c2x5IGhvdyB5b3UgY2FuIGRlcml2ZSBgaXJpcy50aWR5YCBmcm9tIGBpcmlzYC4gTm93IHlvdSdsbCBtb3ZlIG9uIHRvIHByb2R1Y2UgYGlyaXMud2lkZWAuCgpUaGUgaGVhZCBvZiB0aGUgYGlyaXMud2lkZWAgc2hvdWxkIGxvb2sgbGlrZSB0aGlzIGluIHRoZSBlbmQ6CgpgYGAKICBTcGVjaWVzICBQYXJ0IExlbmd0aCBXaWR0aAoxICBzZXRvc2EgUGV0YWwgICAgMS40ICAgMC4yCjIgIHNldG9zYSBQZXRhbCAgICAxLjQgICAwLjIKMyAgc2V0b3NhIFBldGFsICAgIDEuMyAgIDAuMgo0ICBzZXRvc2EgUGV0YWwgICAgMS41ICAgMC4yCjUgIHNldG9zYSBQZXRhbCAgICAxLjQgICAwLjIKNiAgc2V0b3NhIFBldGFsICAgIDEuNyAgIDAuNAouLi4KYGBgCgpZb3UgY2FuIGhhdmUgYSBsb29rIGF0IHRoZSBgaXJpc2AgZGF0YXNldCBieSB0eXBpbmcgYGhlYWQoaXJpcylgIGluIHRoZSBjb25zb2xlLgoKIyMjIEluc3RydWN0aW9ucwoKLSBCZWZvcmUgeW91IGJlZ2luLCB5b3UgbmVlZCB0byBhZGQgYSBuZXcgY29sdW1uIGNhbGxlZCBgRmxvd2VyYCB0aGF0IGNvbnRhaW5zIGEgdW5pcXVlIGlkZW50aWZpZXIgZm9yIGVhY2ggcm93IGluIHRoZSBkYXRhIGZyYW1lLiBUaGlzIGlzIGJlY2F1c2UgeW91J2xsIHJlYXJyYW5nZSB0aGUgZGF0YSBmcmFtZSBhZnRlcndhcmRzIGFuZCB5b3UgbmVlZCB0byBrZWVwIHRyYWNrIG9mIHdoaWNoIHJvdywgb3Igd2hpY2ggc3BlY2lmaWMgZmxvd2VyLCBlYWNoIHZhbHVlIGNhbWUgZnJvbS4gSXQncyBkb25lIGZvciB5b3UsIG5vIG5lZWQgdG8gYWRkIGFueXRoaW5nIHlvdXJzZWxmLgotIGBnYXRoZXIoKWAgcmVhcnJhbmdlcyB0aGUgZGF0YSBmcmFtZSBieSBzcGVjaWZ5aW5nIHRoZSBjb2x1bW5zIHRoYXQgYXJlIGNhdGVnb3JpY2FsIHZhcmlhYmxlcyB3aXRoIGEgLSBub3RhdGlvbi4gSW4gdGhpcyBjYXNlLCBgU3BlY2llc2AgYW5kIGBGbG93ZXJgIGFyZSBjYXRlZ29yaWNhbC4gQ29tcGxldGUgdGhlIGNvbW1hbmQuCi0gYHNlcGFyYXRlKClgIHNwbGl0cyB1cCB0aGUgbmV3IGtleSBjb2x1bW4sIHdoaWNoIGNvbnRhaW5zIHRoZSBmb3JtZXIgaGVhZGVycywgYWNjb3JkaW5nIHRvIGAuYC4gVGhlIG5ldyBjb2x1bW4gbmFtZXMgYCJQYXJ0ImAgYW5kIGAiTWVhc3VyZSJgIGFyZSBnaXZlbiBpbiBhIGNoYXJhY3RlciB2ZWN0b3IuCi0gVGhlIGxhc3Qgc3RlcCBpcyB0byB1c2UgYHNwcmVhZCgpYCB0byBkaXN0cmlidXRlIHRoZSBuZXcgYE1lYXN1cmVgIGNvbHVtbiBhbmQgYXNzb2NpYXRlZCBgdmFsdWVgIGNvbHVtbiBpbnRvIHR3byBjb2x1bW5zLgoKYGBge3J9CiMgTG9hZCB0aGUgdGlkeXIgcGFja2FnZQpsaWJyYXJ5KHRpZHlyKQoKIyBBZGQgY29sdW1uIHdpdGggdW5pcXVlIGlkcyAoZG9uJ3QgbmVlZCB0byBjaGFuZ2UpCmlyaXMkRmxvd2VyIDwtIDE6bnJvdyhpcmlzKQoKIyBGaWxsIGluIHRoZSBfX18gdG8gcHJvZHVjZSB0byB0aGUgY29ycmVjdCBpcmlzLndpZGUgZGF0YXNldAppcmlzLndpZGUgPC0gaXJpcyAlPiUKICBnYXRoZXIoa2V5LCB2YWx1ZSwgLVNwZWNpZXMsIC1GbG93ZXIpICU+JQogIHNlcGFyYXRlKGtleSwgYygiX19fIiwgX19fKSwgIlxcLiIpICU+JQogIHNwcmVhZChfX18sIHZhbHVlKQpgYGAKCgoKIyBBZXN0aGV0aWNzCgojIyBBbGwgYWJvdXQgYWVzdGhldGljcywgcGFydCAxClRoZXJlIGFyZSA5IGRpZmZlcmVudCBhZXN0aGV0aWNzIHRoYXQgY2FuIGJlIG1hcHBlZDoKCi0gYHhgOiB0aGUgWC1heGlzIHBvc2l0aW9uCi0gYHlgOiB0aGUgWS1heGlzIHBvc2l0aW9uCi0gYGNvbG9yYDogdGhlIGNvbG9yIG9mIGRvdHMgYW5kIHRoZSBvdXRsaW5lIG9mIG90aGVyIHNoYXBlcwotIGBmaWxsYDogZmlsbCBjb2xvcgotIGBzaXplYDogZGlhbWV0ZXIgb2YgcG9pbnRzLCB0aGlja25lc3Mgb2YgbGluZXMKLSBgYWxwaGFgOiB0aGUgdHJhbnNwYXJlbmN5LCAwLXRyYW5zcGFyZW50LCAxLW9wYXF1ZQotIGBsaW5ldHlwZWA6IGxpbmUgZGFzaCBwYXR0ZXJuCi0gYGxhYmVsc2A6IHRleHQgb24gYSBwbG90IG9yIGF4ZXMKLSBgc2hhcGVgOiB0aGUgc2hhcGUKCkxldCdzIGFwcGx5IHRoZW0gdG8gYSBjYXRlZ29yaWNhbCB2YXJpYWJsZSAtIHRoZSBjeWxpbmRlcnMgaW4gYG10Y2Fyc2AsIGBjeWxgLgoKKFlvdSdsbCBjb25zaWRlciBsaW5lIHR5cGUgd2hlbiB5b3UgZW5jb3VudGVyIGxpbmUgcGxvdHMgaW4gdGhlIG5leHQgY2hhcHRlcikuCgpUaGVzZSBhcmUgdGhlIGFlc3RoZXRpY3MgeW91IGNhbiBjb25zaWRlciB3aXRoaW4gYGFlcygpYCBpbiB0aGlzIGNoYXB0ZXI6IGB4YCwgYHlgLCBgY29sb3JgLCBgZmlsbGAsIGBzaXplYCwgYGFscGhhYCwgYGxhYmVsc2AgYW5kIGBzaGFwZWAuCgpJbiB0aGUgZm9sbG93aW5nIGV4ZXJjaXNlIHlvdSBjYW4gYXNzdW1lIHRoYXQgdGhlIGBjeWxgIGNvbHVtbiBpcyBjYXRlZ29yaWNhbC4gSXQgaGFzIGFscmVhZHkgYmVlbiB0cmFuc2Zvcm1lZCBpbnRvIGEgYGZhY3RvcmAgZm9yIHlvdS4KCiMjIyBJbnN0cnVjdGlvbnMKVGhlIGBtdGNhcnNgIGRhdGEgZnJhbWUgaXMgYXZhaWxhYmxlIGluIHlvdXIgd29ya3NwYWNlLiBGb3IgZWFjaCBvZiB0aGUgZm9sbG93aW5nIGZvdXIgcGxvdHMsIHVzZSBgZ2VvbV9wb2ludCgpYDoKCi0gTWFwIGBtcGdgIG9udG8gdGhlIGB4YCBhZXN0aGV0aWMsIGFuZCBgY3lsYCBvbnRvIHRoZSBgeWAuCi0gUmV2ZXJzZSB0aGUgbWFwcGluZ3Mgb2YgdGhlIGZpcnN0IHBsb3QuCi0gTWFwIGB3dGAgb250byBgeCwsIGBtcGdgIG9udG8gYHlgLCBhbmQgYGN5bGAgb250byBgY29sb3JgLgotIE1vZGlmeSB0aGUgcHJldmlvdXMgcGxvdCBieSBjaGFuZ2luZyB0aGUgYHNoYXBlYCBhcmd1bWVudCBvZiB0aGUgZ2VvbSB0byBgMWAgYW5kIGluY3JlYXNlIHRoZSBgc2l6ZWAgdG8gYDRgLiBUaGVzZSBhcmUgYXR0cmlidXRlcyB0aGF0IHlvdSBzaG91bGQgc3BlY2lmeSBpbnNpZGUgYGdlb21fcG9pbnQoKWAuCgoKYGBge3J9CmxpYnJhcnkoZGF0YXNldHMpCm10Y2FycyRjeWwgPC0gYXMuZmFjdG9yKG10Y2FycyRjeWwpCgojIDEgLSBNYXAgbXBnIHRvIHggYW5kIGN5bCB0byB5CmdncGxvdChfX18sIGFlcyhfX18sIF9fXykpICsKICBnZW9tX3BvaW50KCkKICAKIyAyIC0gUmV2ZXJzZTogTWFwIGN5bCB0byB4IGFuZCBtcGcgdG8geQpnZ3Bsb3QoX19fLCBhZXMoX19fLCBfX18pKSArCiAgZ2VvbV9wb2ludCgpCgojIDMgLSBNYXAgd3QgdG8geCwgbXBnIHRvIHkgYW5kIGN5bCB0byBjb2wKZ2dwbG90KF9fXywgYWVzKF9fXywgX19fLCBfX18pKSArCiAgZ2VvbV9wb2ludCgpCgojIDQgLSBDaGFuZ2Ugc2hhcGUgYW5kIHNpemUgb2YgdGhlIHBvaW50cyBpbiB0aGUgYWJvdmUgcGxvdApnZ3Bsb3QobXRjYXJzLCBhZXMoX19fLCBfX18sIF9fXykpICsKICBnZW9tX3BvaW50KF9fXywgX19fKQoKYGBgCgoKIyMgQWxsIGFib3V0IGFlc3RoZXRpY3MsIHBhcnQgMgpUaGUgYGNvbG9yYCBhZXN0aGV0aWMgdHlwaWNhbGx5IGNoYW5nZXMgdGhlIG91dHNpZGUgb3V0bGluZSBvZiBhbiBvYmplY3QgYW5kIHRoZSBgZmlsbGAgYWVzdGhldGljIGlzIHR5cGljYWxseSB0aGUgaW5zaWRlIHNoYWRpbmcuIEhvd2V2ZXIsIGFzIHlvdSBzYXcgaW4gdGhlIGxhc3QgZXhlcmNpc2UsIGBnZW9tX3BvaW50KClgIGlzIGFuIGV4Y2VwdGlvbi4gSGVyZSB5b3UgdXNlIGBjb2xvcmAsIGluc3RlYWQgb2YgYGZpbGxgIGZvciB0aGUgaW5zaWRlIG9mIHRoZSBwb2ludC4gQnV0IGl0J3MgYSBiaXQgc3VidGxlciB0aGFuIHRoYXQuCgpXaGljaCBzaGFwZSB0byB1c2U/IFRoZSBkZWZhdWx0IGBnZW9tX3BvaW50KClgIHVzZXMgYHNoYXBlID0gMTlgIChhIHNvbGlkIGNpcmNsZSB3aXRoIGFuIG91dGxpbmUgdGhlIHNhbWUgY29sb3VyIGFzIHRoZSBpbnNpZGUpLiBHb29kIGFsdGVybmF0aXZlcyBhcmUgYHNoYXBlID0gMWAgKGhvbGxvdykgYW5kIGBzaGFwZSA9IDE2YCAoc29saWQsIG5vIG91dGxpbmUpLiBUaGVzZSBhbGwgdXNlIHRoZSBgY29sYCBhZXN0aGV0aWMgKGRvbid0IGZvcmdldCB0byBzZXQgYGFscGhhYCBmb3Igc29saWQgcG9pbnRzKS4KCkEgcmVhbGx5IG5pY2UgYWx0ZXJuYXRpdmUgaXMgYHNoYXBlID0gMjFgIHdoaWNoIGFsbG93cyB5b3UgdG8gdXNlIGJvdGggZmlsbCBmb3IgdGhlIGluc2lkZSBhbmQgY29sIGZvciB0aGUgb3V0bGluZSEgVGhpcyBpcyBhIGdyZWF0IGxpdHRsZSB0cmljayBmb3Igd2hlbiB5b3Ugd2FudCB0byBtYXAgdHdvIGFlc3RoZXRpY3MgdG8gYSBkb3QuCgpXaGF0IGhhcHBlbnMgd2hlbiB5b3UgdXNlIHRoZSB3cm9uZyBhZXN0aGV0aWMgbWFwcGluZz8gVGhpcyBpcyBhIHZlcnkgY29tbW9uIG1pc3Rha2UhIFRoZSBjb2RlIGZyb20gdGhlIHByZXZpb3VzIGV4ZXJjaXNlIGlzIGluIHRoZSBlZGl0b3IuIFVzaW5nIHRoaXMgYXMgeW91ciBzdGFydGluZyBwb2ludCBjb21wbGV0ZSB0aGUgaW5zdHJ1Y3Rpb25zLgoKIyMjIEluc3RydWN0aW9ucwoKTm90ZTogSW4gdGhlIGBtdGNhcnNgIGRhdGFzZXQsIGBjeWxgIGFuZCBgYW1gIGhhdmUgYmVlbiBjb252ZXJ0ZWQgdG8gZmFjdG9yIGZvciB5b3UuCgotIENvcHkgJiBwYXN0ZSB0aGUgZmlyc3QgcGxvdCdzIGNvZGUuIENoYW5nZSB0aGUgYWVzdGhldGljcyBzbyB0aGF0IGBjeWxgIG1hcHMgdG8gYGZpbGxgIHJhdGhlciB0aGFuIGBjb2xgLgotIENvcHkgJiBwYXN0ZSB0aGUgc2Vjb25kIHBsb3QncyBjb2RlLiBJbiBgZ2VvbV9wb2ludCgpYCBjaGFuZ2UgdGhlIGBzaGFwZWAgYXJndW1lbnQgdG8gYDIxYCBhbmQgYWRkIGFuIGBhbHBoYWAgYXJndW1lbnQgc2V0IHRvIGAwLjZgLgotIENvcHkgJiBwYXN0ZSB0aGUgdGhpcmQgcGxvdCdzIGNvZGUuIEluIHRoZSBgZ2dwbG90KClgIGFlc3RoZXRpY3MsIG1hcCBgYW1gIHRvIGBjb2xgLgoKYGBge3J9Cm10Y2FycyRhbSA8LSBhcy5mYWN0b3IobXRjYXJzJGFtKQptdGNhcnMkY3lsIDwtIGFzLmZhY3RvcihtdGNhcnMkY3lsKQoKIyBhbSBhbmQgY3lsIGFyZSBmYWN0b3JzLCB3dCBpcyBudW1lcmljCmNsYXNzKG10Y2FycyRhbSkKY2xhc3MobXRjYXJzJGN5bCkKY2xhc3MobXRjYXJzJHd0KQoKIyBGcm9tIHRoZSBwcmV2aW91cyBleGVyY2lzZQpnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IHd0LCB5ID0gbXBnLCBjb2wgPSBjeWwpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDEsIHNpemUgPSA0KQoKIyAxIC0gTWFwIGN5bCB0byBmaWxsCgoKCiMgMiAtIENoYW5nZSBzaGFwZSBhbmQgYWxwaGEgb2YgdGhlIHBvaW50cyBpbiB0aGUgYWJvdmUgcGxvdAoKCgojIDMgLSBNYXAgYW0gdG8gY29sIGluIHRoZSBhYm92ZSBwbG90CgoKYGBgCgoKIyMgQWxsIGFib3V0IGFlc3RoZXRpY3MsIHBhcnQgMwpOb3cgdGhhdCB5b3UndmUgZ290IHNvbWUgcHJhY3RpY2Ugd2l0aCBpbmNyZW1lbnRhbGx5IGJ1aWxkaW5nIHVwIHBsb3RzLCB5b3UgY2FuIHRyeSB0byBkbyBpdCBmcm9tIHNjcmF0Y2ghIFRoZSBgbXRjYXJzYCBkYXRhc2V0IGlzIHByZS1sb2FkZWQgaW4gdGhlIHdvcmtzcGFjZS4KCiMjIyBJbnN0cnVjdGlvbnMKVXNlIGBnZ3Bsb3QoKWAgdG8gY3JlYXRlIGEgYmFzaWMgc2NhdHRlciBwbG90LiBJbnNpZGUgYGFlcygpYCwgbWFwIGB3dGAgb250byBgeGAgYW5kIGBtcGdgIG9udG8gYHlgLiBUeXBpY2FsbHksIHlvdSB3b3VsZCBzYXkgIm1wZyBkZXNjcmliZWQgYnkgd3QiIG9yICJtcGcgdnMgd3QiLCBidXQgaW4gYGFlcygpYCwgaXQncyBgeGAgZmlyc3QsIGB5YCBzZWNvbmQuIFVzZSBgZ2VvbV9wb2ludCgpYCB0byBtYWtlIHRocmVlIHNjYXR0ZXIgcGxvdHM6CgotIGBjeWxgIG9uIGBzaXplYAotIGBjeWxgIG9uIGBhbHBoYWAKLSBgY3lsYCBvbiBgc2hhcGVgCgpUcnkgdGhpcyBsYXN0IHZhcmlhbnQ6CgotIGBjeWxgIG9uIGBsYWJlbGAuIEluIG9yZGVyIHRvIGNvcnJlY3RseSBzaG93IHRoZSB0ZXN0IChpLmUuIGBsYWJlbGApLCB1c2UgYGdlb21fdGV4dCgpYC4KCgpgYGB7cn0KIyBNYXAgY3lsIHRvIHNpemUKCgojIE1hcCBjeWwgdG8gYWxwaGEKCgoKIyBNYXAgY3lsIHRvIHNoYXBlIAoKCgojIE1hcCBjeWwgdG8gbGFiZWwKCgpgYGAKCgojIyBBbGwgYWJvdXQgYXR0cmlidXRlcywgcGFydCAxCgpZb3UgY2FuIHVzZSBhbGwgdGhlIGFlc3RoZXRpY3MgYXMgYXR0cmlidXRlcy4gTGV0J3Mgc2VlIGhvdyB0aGlzIHdvcmtzIHdpdGggdGhlIGFlc3RoZXRpY3MgeW91IHVzZWQgaW4gdGhlIHByZXZpb3VzIGV4ZXJjaXNlczogYHhgLCBgeWAsIGBjb2xvcmAsIGBmaWxsYCwgYHNpemVgLCBgYWxwaGFgLCBgbGFiZWxgIGFuZCBgc2hhcGVgLgoKVGhpcyB0aW1lIHlvdSdsbCB1c2UgdGhlc2UgYXJndW1lbnRzIHRvIHNldCBhdHRyaWJ1dGVzIG9mIHRoZSBwbG90LCBub3QgYWVzdGhldGljcy4gSG93ZXZlciwgdGhlcmUgYXJlIHNvbWUgcGl0ZmFsbHMgeW91J2xsIGhhdmUgdG8gd2F0Y2ggb3V0IGZvcjogdGhlc2UgYXR0cmlidXRlcyBjYW4gb3ZlcndyaXRlIHRoZSBhZXN0aGV0aWNzIG9mIHlvdXIgcGxvdCEKCkEgd29yZCBhYm91dCBzaGFwZXM6IEluIHRoZSBleGVyY2lzZSAiQWxsIGFib3V0IGFlc3RoZXRpY3MsIHBhcnQgMiIsIHlvdSBzYXcgdGhhdCBgc2hhcGUgPSAyMWAgcmVzdWx0cyBpbiBhIHBvaW50IHRoYXQgaGFzIGEgZmlsbCBhbmQgYW4gb3V0bGluZS4gU2hhcGVzIGluIFIgY2FuIGhhdmUgYSB2YWx1ZSBmcm9tIDEtMjUuIFNoYXBlcyAxLTIwIGNhbiBvbmx5IGFjY2VwdCBhIGNvbG9yIGFlc3RoZXRpYywgYnV0IHNoYXBlcyAyMS0yNSBoYXZlIGJvdGggYSBjb2xvciBhbmQgYSBmaWxsIGFlc3RoZXRpYy4gU2VlIHRoZSBgcGNoYCBhcmd1bWVudCBpbiBgcGFyKClgIGZvciBmdXJ0aGVyIGRpc2N1c3Npb24uCgpBIHdvcmQgYWJvdXQgaGV4YWRlY2ltYWwgY29sb3VyczogSGV4YWRlY2ltYWwsIGxpdGVyYWxseSAicmVsYXRlZCB0byAxNiIsIGlzIGEgYmFzZS0xNiBhbHBoYW51bWVyaWMgY291bnRpbmcgc3lzdGVtLiBJbmRpdmlkdWFsIHZhbHVlcyBjb21lIGZyb20gdGhlIHJhbmdlcyAwLTkgYW5kIEEtRi4gVGhpcyBtZWFucyB0aGVyZSBhcmUgMjU2IHBvc3NpYmxlIHR3by1kaWdpdCB2YWx1ZXMgKGkuZS4gMDAgLSBGRikuIEhleGFkZWNpbWFsIGNvbG91cnMgdXNlIHRoaXMgc3lzdGVtIHRvIHNwZWNpZnkgYSBzaXgtZGlnaXQgY29kZSBmb3IgUmVkLCBHcmVlbiBhbmQgQmx1ZSB2YWx1ZXMgKCIjUlJHR0JCIikgb2YgYSBjb2xvdXIgKGkuZS4gUHVyZSBibHVlOiAiIzAwMDBGRiIsIGJsYWNrOiAiIzAwMDAwMCIsIHdoaXRlOiAiI0ZGRkZGRiIpLiBSIGNhbiBhY2NlcHQgaGV4IGNvZGVzIGFzIHZhbGlkIGNvbG91cnMuCgojIyMgSW5zdHJ1Y3Rpb25zCgotIFlvdSB3aWxsIGNvbnRpbnVlIHRvIHdvcmsgd2l0aCBgbXRjYXJzYC4gVXNlIGBnZ3Bsb3QoKWAgdG8gY3JlYXRlIGEgYmFzaWMgc2NhdHRlciBwbG90OiBtYXAgYHd0YCBvbnRvIGB4YCwgYG1wZ2Agb250byBgeWAgYW5kIGBjeWxgIG9udG8gYGNvbG9yYC4KLSBPdmVyd3JpdGUgdGhlIGNvbG9yIG9mIHRoZSBwb2ludHMgaW5zaWRlIGBnZW9tX3BvaW50KClgIHRvIGBteV9jb2xvcmAuIE5vdGljZSBob3cgdGhpcyBjYW5jZWxzIG91dCB0aGUgY29sb3JzIGdpdmVuIHRvIHRoZSBwb2ludHMgYnkgdGhlIG51bWJlciBvZiBjeWxpbmRlcnMhCi0gU3RhcnRpbmcgd2l0aCBwbG90IDIsIG1hcCBgY3lsYCB0byBgZmlsbGAgaW5zdGVhZCBvZiBgY29sYCBhbmQgc2V0IHRoZSBhdHRyaWJ1dGVzIGBzaXplYCB0byBgMTBgLCBgc2hhcGVgIHRvIGAyM2AgYW5kIGBjb2xvcmAgdG8gYG15X2NvbG9yYCBpbnNpZGUgYGdlb21fcG9pbnQoKWAuCgoKYGBge3J9CiMgRGVmaW5lIGEgaGV4YWRlY2ltYWwgY29sb3IKbXlfY29sb3IgPC0gIiM0QUJFRkYiCgojIDEgLSBGaXJzdCBzY2F0dGVyIHBsb3QsIHdpdGggY29sIGFlc3RoZXRpYzoKCgoKIyAyIC0gUGxvdCAxLCBidXQgc2V0IGNvbCBhdHRyaWJ1dGVzIGluIGdlb20gbGF5ZXI6CgoKCiMgMyAtIFBsb3QgMiwgd2l0aCBmaWxsIGluc3RlYWQgb2YgY29sIGFlc3RoZXRpYywgcGx1dCBzaGFwZSBhbmQgc2l6ZSBhdHRyaWJ1dGVzIGluIGdlb20gbGF5ZXIuCgoKCmBgYAoKCiMjIEFsbCBhYm91dCBhdHRyaWJ1dGVzLCBwYXJ0IDIKWW91IGNhbiB1c2UgYWxsIHRoZSBhZXN0aGV0aWNzIGFzIGF0dHJpYnV0ZXMuIExldCdzIHNlZSBob3cgdGhpcyB3b3JrcyB3aXRoIHRoZSBhZXN0aGV0aWNzIHlvdSB1c2VkIGluIHRoZSBwcmV2aW91cyBleGVyY2lzZXM6IGB4YCwgYHlgLCBgY29sb3JgLCBgZmlsbGAsIGBzaXplYCwgYGFscGhhYCwgYGxhYmVsYCBhbmQgYHNoYXBlYC4KCkluIHRoaXMgZXhlcmNpc2UgeW91IHdpbGwgc2V0IGFsbCBraW5kcyBvZiBhdHRyaWJ1dGVzIG9mIHRoZSBwb2ludHMhCgpZb3Ugd2lsbCBjb250aW51ZSB0byB3b3JrIHdpdGggYG10Y2Fyc2AuCgojIyMgSW5zdHJ1Y3Rpb25zCgotIEFkZCB0byB0aGUgZmlyc3QgY29tbWFuZDogZHJhdyBwb2ludHMgd2l0aCBgYWxwaGFgIHNldCB0byBgMC41YC4KLSBBZGQgdG8gdGhlIHNlY29uZCBjb21tYW5kOiBkcmF3IHBvaW50cyBvZiBzaGFwZSBgMjRgIGluIHRoZSBjb2xvciBgeWVsbG93YC4KLSBBZGQgdG8gdGhlIHRoaXJkIGNvbW1hbmQ6IGRyYXcgdGV4dCB3aXRoIGxhYmVsIGByb3duYW1lcyhtdGNhcnMpYCBpbiB0aGUgY29sb3IgYHJlZGAuIERvbid0IHVzZSBgZ2VvbV9wb2ludCgpYCBoZXJlISBZb3Ugc2hvdWxkIGdldCBhIHNjYXR0ZXIgcGxvdCB3aXRoIHRoZSBuYW1lcyBvZiB0aGUgY2FycyBpbnN0ZWFkIG9mIHBvaW50cy4KCk5vdGU6IFJlbWVtYmVyIHRvIHNwZWNpZnkgY2hhcmFjdGVycyB3aXRoIHF1b3RhdGlvbiBtYXJrcyAoYCJ5ZWxsb3ciYCwgbm90IGB5ZWxsb3dgKS4KCmBgYHtyfQojIEV4cGFuZCB0byBkcmF3IHBvaW50cyB3aXRoIGFscGhhIDAuNQpnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IHd0LCB5ID0gbXBnLCBmaWxsID0gY3lsKSkgCgogIAojIEV4cGFuZCB0byBkcmF3IHBvaW50cyB3aXRoIHNoYXBlIDI0IGFuZCBjb2xvciB5ZWxsb3cKZ2dwbG90KG10Y2FycywgYWVzKHggPSB3dCwgeSA9IG1wZywgZmlsbCA9IGN5bCkpIAoKICAKIyBFeHBhbmQgdG8gZHJhdyB0ZXh0IHdpdGggbGFiZWwgcm93bmFtZXMobXRjYXJzKSBhbmQgY29sb3IgcmVkCmdncGxvdChtdGNhcnMsIGFlcyh4ID0gd3QsIHkgPSBtcGcsIGZpbGwgPSBjeWwpKSAKCmBgYAoKCiMjIEdvaW5nIGFsbCBvdXQKSW4gdGhpcyBleGVyY2lzZSwgeW91IHdpbGwgZ3JhZHVhbGx5IGFkZCBtb3JlIGFlc3RoZXRpY3MgbGF5ZXJzIHRvIHRoZSBwbG90LiBZb3UncmUgc3RpbGwgd29ya2luZyB3aXRoIHRoZSBgbXRjYXJzYCBkYXRhc2V0LCBidXQgdGhpcyB0aW1lIHlvdSdyZSB1c2luZyBtb3JlIGZlYXR1cmVzIG9mIHRoZSBjYXJzLiBGb3IgY29tcGxldGVuZXNzLCBoZXJlIGlzIGEgbGlzdCBvZiBhbGwgdGhlIGZlYXR1cmVzIG9mIHRoZSBvYnNlcnZhdGlvbnMgaW4gYG10Y2Fyc2A6CgotIGBtcGdgIC0tIE1pbGVzLyhVUykgZ2FsbG9uCi0gYGN5bGAgLS0gTnVtYmVyIG9mIGN5bGluZGVycwotIGBkaXNwYCAtLSBEaXNwbGFjZW1lbnQgKGN1LmluLikKLSBgaHBgIC0tIEdyb3NzIGhvcnNlcG93ZXIKLSBgZHJhdGAgLS0gUmVhciBheGxlIHJhdGlvCi0gYHd0YCAtLSBXZWlnaHQgKGxiLzEwMDApCi0gYHFzZWNgIC0tIDEvNCBtaWxlIHRpbWUKLSBgdnNgIC0tIFYvUyBlbmdpbmUuCi0gYGFtYCAtLSBUcmFuc21pc3Npb24gKDAgPSBhdXRvbWF0aWMsIDEgPSBtYW51YWwpCi0gYGdlYXJgIC0tIE51bWJlciBvZiBmb3J3YXJkIGdlYXJzCi0gYGNhcmJgIC0tIE51bWJlciBvZiBjYXJidXJldG9ycwoKTm90aWNlIHRoYXQgYWRkaW5nIG1vcmUgYWVzdGhldGljcyB0byB5b3VyIHBsb3QgaXMgbm90IGFsd2F5cyBhIGdvb2QgaWRlYS4gQWRkaW5nIGFlc3RoZXRpYyBtYXBwaW5ncyB0byBhIHBsb3Qgd2lsbCBpbmNyZWFzZSBpdHMgY29tcGxleGl0eSwgYW5kIHRodXMgZGVjcmVhc2UgaXRzIHJlYWRhYmlsaXR5LgoKIyMjIEluc3RydWN0aW9ucwpOb3RlOiBJbiB0aGlzIGNoYXB0ZXIgeW91IHNhdyBhZXN0aGV0aWNzIGFuZCBhdHRyaWJ1dGVzLiBWYXJpYWJsZXMgaW4gYSBkYXRhIGZyYW1lIGFyZSBtYXBwZWQgdG8gYWVzdGhldGljcyBpbiBgYWVzKClgLiAoZS5nLiBgYWVzKGNvbCA9IGN5bClgKSB3aXRoaW4gYGdncGxvdCgpYC4gVmlzdWFsIGVsZW1lbnRzIGFyZSBzZXQgYnkgYXR0cmlidXRlcyBpbiBzcGVjaWZpYyBnZW9tIGxheWVycyAoYGdlb21fcG9pbnQoY29sID0gInJlZCIpYCkuIERvbid0IGNvbmZ1c2UgdGhlc2UgdHdvIHRoaW5ncyAtIGhlcmUgeW91J3JlIGZvY3VzaW5nIG9uIGFlc3RoZXRpYyBtYXBwaW5ncy4KCi0gRHJhdyBhIHNjYXR0ZXIgcGxvdCBvZiBgbXRjYXJzYCB3aXRoIGBtcGdgIG9uIHRoZSB4LWF4aXMsIGBxc2VjYCBvbiB0aGUgeS1heGlzIGFuZCBgZmFjdG9yKGN5bClgIGFzIGNvbG9ycy4KLSBFeHBhbmQgdGhlIHByZXZpb3VzIHBsb3QgdG8gaW5jbHVkZSBgZmFjdG9yKGFtKWAgYXMgdGhlIGBzaGFwZWAgb2YgdGhlIHBvaW50cy4KLSBFeHBhbmQgdGhlIHByZXZpb3VzIHBsb3QgdG8gaW5jbHVkZSB0aGUgcmF0aW8gb2YgaG9yc2Vwb3dlciB0byB3ZWlnaHQgKGkuZS4gYChocC93dClgKSBhcyB0aGUgc2l6ZSBvZiB0aGUgcG9pbnRzLgoKCmBgYHtyfQojIE1hcCBtcGcgb250byB4LCBxc2VjIG9udG8geSBhbmQgZmFjdG9yKGN5bCkgb250byBjb2wKCgoKIyBBZGQgbWFwcGluZzogZmFjdG9yKGFtKSBvbnRvIHNoYXBlCgoKCiMgQWRkIG1hcHBpbmc6IChocC93dCkgb250byBzaXplCgoKYGBgCgoKIyMgQWVzdGhldGljcyBmb3IgY2F0ZWdvcmljYWwgYW5kIGNvbnRpbnVvdXMgdmFyaWFibGVzCk1hbnkgb2YgdGhlIGFlc3RoZXRpY3MgY2FuIGJlIG1hcHBlZCBvbnRvIGNvbnRpbnVvdXMgb3IgY2F0ZWdvcmljYWwgdmFyaWFibGVzLCBidXQgc29tZSBhcmUgcmVzdHJpY3RlZCB0byBjYXRlZ29yaWNhbCBkYXRhLiBXaGljaCBhZXN0aGV0aWNzIGFyZSB0aGV5PwoKIyMjIEluc3RydWN0aW9ucwpQb3NzaWJsZSBBbnN3ZXJzCgotIGNvbG9yICYgZmlsbAotIGFscGhhICYgc2l6ZQotIGxhYmVsICYgc2hhcGUKLSBhbHBoYSAmIGxhYmVsCi0geCAmIHkKCiMjIFBvc2l0aW9uCgpCYXIgcGxvdHMgc3VmZmVyIGZyb20gdGhlaXIgb3duIGlzc3VlcyBvZiBvdmVycGxvdHRpbmcsIGFzIHlvdSdsbCBzZWUgaGVyZS4gVXNlIHRoZSBgInN0YWNrImAsIGAiZmlsbCJgIGFuZCBgImRvZGdlImAgcG9zaXRpb25zIHRvIHJlcHJvZHVjZSB0aGUgcGxvdCBpbiB0aGUgdmlld2VyLgoKVGhlIGBnZ3Bsb3QyYCBiYXNlIGxheWVycyAoZGF0YSBhbmQgYWVzdGhldGljcykgaGF2ZSBhbHJlYWR5IGJlZW4gY29kZWQ7IHRoZXkncmUgc3RvcmVkIGluIGEgdmFyaWFibGUgYGN5bC5hbWAuIEl0IGxvb2tzIGxpa2UgdGhpczoKCmBgYHtyfQpjeWwuYW0gPC0gZ2dwbG90KG10Y2FycywgYWVzKHggPSBmYWN0b3IoY3lsKSwgZmlsbCA9IGZhY3RvcihhbSkpKQpgYGAKCgojIyMgSW5zdHJ1Y3Rpb25zCgotIEFkZCBhIGBnZW9tX2JhcigpYCBjYWxsIHRvIGBjeWwuYW1gLiBCeSBkZWZhdWx0LCB0aGUgYHBvc2l0aW9uYCB3aWxsIGJlIHNldCB0byBgInN0YWNrImAuCi0gRmlsbCBpbiB0aGUgc2Vjb25kIGBnZ3Bsb3RgIGNvbW1hbmQuIEV4cGxpY2l0bHkgc2V0IGBwb3NpdGlvbmAgdG8gYCJmaWxsImAgaW5zaWRlIGBnZW9tX2JhcigpYC4KLSBGaWxsIGluIHRoZSB0aGlyZCBgZ2dwbG90YCBjb21tYW5kLiBTZXQgYHBvc2l0aW9uYCB0byBgImRvZGdlImAuCi0gVGhlIGBwb3NpdGlvbiA9ICJkb2RnZSJgIHZlcnNpb24gc2VlbXMgbW9zdCBhcHByb3ByaWF0ZS4gRmluaXNoIG9mZiB0aGUgZm91cnRoIGBnZ3Bsb3RgIGNvbW1hbmQgYnkgY29tcGxldGluZyB0aGUgdGhyZWUgYHNjYWxlX2AgZnVuY3Rpb25zOgogICAtIGBzY2FsZV94X2Rpc2NyZXRlKClgIHRha2VzIGFzIGl0cyBvbmx5IGFyZ3VtZW50IHRoZSB4LWF4aXMgbGFiZWw6IGAiQ3lsaW5kZXJzImAuCiAgIC0gYHNjYWxlX3lfY29udGludW91cygpYCB0YWtlcyBhcyBpdHMgb25seSBhcmd1bWVudCB0aGUgeS1heGlzIGxhYmVsOiBgIk51bWJlciJgLgogICAtIGBzY2FsZV9maWxsX21hbnVhbCgpYCBmaXhlcyB0aGUgbGVnZW5kLiBUaGUgZmlyc3QgYXJndW1lbnQgaXMgdGhlIHRpdGxlIG9mIHRoZSBsZWdlbmQ6IGAiVHJhbnNtaXNzaW9uImAuIE5leHQsIGB2YWx1ZXNgIGFuZCBgbGFiZWxzYCBhcmUgc2V0IHRvIHByZWRlZmluZWQgdmFsdWVzIGZvciB5b3UuIFRoZXNlIGFyZSB0aGUgY29sb3JzIGFuZCB0aGUgbGFiZWxzIGluIHRoZSBsZWdlbmQuCgpgYGB7cn0KIyBUaGUgYmFzZSBsYXllciwgY3lsLmFtLCBpcyBhdmFpbGFibGUgZm9yIHlvdQojIEFkZCBnZW9tIChwb3NpdGlvbiA9ICJzdGFjayIgYnkgZGVmYXVsdCkKY3lsLmFtICsgCiAgX19fCgojIEZpbGwgLSBzaG93IHByb3BvcnRpb24KY3lsLmFtICsgCiAgZ2VvbV9iYXIocG9zaXRpb24gPSBfX18pICAKCiMgRG9kZ2luZyAtIHByaW5jaXBsZXMgb2Ygc2ltaWxhcml0eSBhbmQgcHJveGltaXR5CmN5bC5hbSArCiAgZ2VvbV9iYXIocG9zaXRpb24gPSBfX18pIAoKIyBDbGVhbiB1cCB0aGUgYXhlcyB3aXRoIHNjYWxlXyBmdW5jdGlvbnMKdmFsID0gYygiI0U0MUExQyIsICIjMzc3RUI4IikKbGFiID0gYygiTWFudWFsIiwgIkF1dG9tYXRpYyIpCmN5bC5hbSArCiAgZ2VvbV9iYXIocG9zaXRpb24gPSAiZG9kZ2UiKSArCiAgc2NhbGVfeF9kaXNjcmV0ZShfX18pICsgCiAgc2NhbGVfeV9jb250aW51b3VzKF9fXykgKwogIHNjYWxlX2ZpbGxfbWFudWFsKF9fXywgCiAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gdmFsLAogICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGxhYikKYGBgCgoKIyMgU2V0dGluZyBhIGR1bW15IGFlc3RoZXRpYwoKSW4gdGhlIGxhc3QgY2hhcHRlciB5b3Ugc2F3IHRoYXQgYWxsIHRoZSB2aXNpYmxlIGFlc3RoZXRpY3MgY2FuIHNlcnZlIGFzIGF0dHJpYnV0ZXMgYW5kIGFlc3RoZXRpY3MsIGJ1dCBJIHZlcnkgY29udmVuaWVudGx5IGxlZnQgb3V0IGB4YCBhbmQgYHlgLiBUaGF0J3MgYmVjYXVzZSBhbHRob3VnaCB5b3UgY2FuIG1ha2UgdW5pdmFyaWF0ZSBwbG90cyAoc3VjaCBhcyBoaXN0b2dyYW1zLCB3aGljaCB5b3UnbGwgZ2V0IHRvIGluIHRoZSBuZXh0IGNoYXB0ZXIpLCBhIHktYXhpcyB3aWxsIGFsd2F5cyBiZSBwcm92aWRlZCwgZXZlbiBpZiB5b3UgZGlkbid0IGFzayBmb3IgaXQuCgpJbiB0aGUgYmFzZSBwYWNrYWdlIHlvdSBjYW4gbWFrZSB1bml2YXJpYXRlIHBsb3RzIHdpdGggYHN0cmlwY2hhcnQoKWAgZGlyZWN0bHkgYW5kIGl0IHdpbGwgdGFrZSBjYXJlIG9mIGEgZmFrZSBgeWAgYXhpcyBmb3IgdXMuIFNpbmNlIHRoaXMgaXMgdW5pdmFyaWF0ZSBkYXRhLCB0aGVyZSBpcyBubyByZWFsIGB5YCBheGlzLgoKWW91IGNhbiBnZXQgdGhlIHNhbWUgdGhpbmcgaW4gYGdncGxvdDJgLCBidXQgaXQncyBhIGJpdCBtb3JlIGN1bWJlcnNvbWUuIFRoZSBvbmx5IHJlYXNvbiB5b3UnZCByZWFsbHkgd2FudCB0byBkbyB0aGlzIGlzIGlmIHlvdSB3ZXJlIG1ha2luZyBtYW55IHBsb3RzIGFuZCB5b3Ugd2FudGVkIHRoZW0gdG8gYmUgaW4gdGhlIHNhbWUgc3R5bGUsIG9yIHlvdSB3YW50ZWQgdG8gdGFrZSBhZHZhbnRhZ2Ugb2YgYW4gYWVzdGhldGljIG1hcHBpbmcgKGUuZy4gYGNvbG91cmApLgoKIyMjIEluc3RydWN0aW9ucwoKLSBUcnkgdG8gcnVuIGBnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IG1wZykpICsgZ2VvbV9wb2ludCgpYCBpbiB0aGUgY29uc29sZS4gYHhgIGlzIG9ubHkgb25lIG9mIHRoZSB0d28gZXNzZW50aWFsIGFlc3RoZXRpY3MgZm9yIGBnZW9tX3BvaW50KClgLCB3aGljaCBpcyB3aHkgeW91IGdldCBhbiBlcnJvciBtZXNzYWdlLgogICAtIDEgLSBUbyBmaXggdGhpcywgbWFwIGEgdmFsdWUsIGUuZy4gMCwgaW5zdGVhZCBvZiBhIHZhcmlhYmxlLCBvbnRvIGB5YC4gVXNlIGBnZW9tX2ppdHRlcigpYCB0byBhdm9pZCBoYXZpbmcgYWxsIHRoZSBwb2ludHMgb24gYSBob3Jpem9udGFsIGxpbmUuCiAgIC0gMiAtIFRvIG1ha2UgZXZlcnl0aGluZyBsb29rIG5pY2VyLCBjb3B5ICYgcGFzdGUgdGhlIGNvZGUgZm9yIHBsb3QgMSBhbmQgY2hhbmdlIHRoZSBsaW1pdHMgb2YgdGhlIGB5YCBheGlzIHVzaW5nIHRoZSBhcHByb3ByaWF0ZSBgc2NhbGVfeV8uLi4oKWAgZnVuY3Rpb24uIFNldCB0aGUgYGxpbWl0c2AgYXJndW1lbnQgdG8gYGMoLTIsIDIpYC4KCmBgYHtyfQojIDEgLSBDcmVhdGUgaml0dGVyZWQgcGxvdCBvZiBtdGNhcnMsIG1wZyBvbnRvIHgsIDAgb250byB5CmdncGxvdChfX18sIGFlcyh4ID0gX19fLCB5ID0gX19fKSkgKwogIGdlb21faml0dGVyKCkKCiMgMiAtIEFkZCBmdW5jdGlvbiB0byBjaGFuZ2UgeSBheGlzIGxpbWl0cwoKCmBgYAoKCiMjIE92ZXJwbG90dGluZyAxIC0gUG9pbnQgc2hhcGUgYW5kIHRyYW5zcGFyZW5jeQoKSW4gdGhlIHByZXZpb3VzIHNlY3Rpb24geW91IHNhdyB0aGF0IHRoZXJlIGFyZSBsb3RzIG9mIHdheXMgdG8gdXNlIGFlc3RoZXRpY3MuIFBlcmhhcHMgdG9vIG1hbnksIGJlY2F1c2UgYWx0aG91Z2ggdGhleSBhcmUgcG9zc2libGUsIHRoZXkgYXJlIG5vdCBhbGwgcmVjb21tZW5kZWQuIExldCdzIHRha2UgYSBsb29rIGF0IHdoYXQgd29ya3MgYW5kIHdoYXQgZG9lc24ndC4KClNvIGZhciB5b3UndmUgZm9jdXNlZCBvbiBzY2F0dGVyIHBsb3RzIHNpbmNlIHRoZXkgYXJlIGludHVpdGl2ZSwgZWFzaWx5IHVuZGVyc3Rvb2QgYW5kIHZlcnkgY29tbW9uLiBBIG1ham9yIGNvbnNpZGVyYXRpb24gaW4gYW55IHNjYXR0ZXIgcGxvdCBpcyBkZWFsaW5nIHdpdGggb3ZlcnBsb3R0aW5nLiBZb3UnbGwgZW5jb3VudGVyIHRoaXMgdG9waWMgYWdhaW4gaW4gdGhlIGdlb21ldHJpZXMgbGF5ZXIsIGJ1dCB5b3UgY2FuIGFscmVhZHkgbWFrZSBzb21lIGFkanVzdG1lbnRzIGhlcmUuCgpZb3UnbGwgaGF2ZSB0byBkZWFsIHdpdGggb3ZlcnBsb3R0aW5nIHdoZW4geW91IGhhdmU6CgotIExhcmdlIGRhdGFzZXRzLAotIEltcHJlY2lzZSBkYXRhIGFuZCBzbyBwb2ludHMgYXJlIG5vdCBjbGVhcmx5IHNlcGFyYXRlZCBvbiB5b3VyIHBsb3QgKHlvdSBzYXcgdGhpcyBpbiB0aGUgdmlkZW8gd2l0aCB0aGUgYGlyaXNgIGRhdGFzZXQpLAotIEludGVydmFsIGRhdGEgKGkuZS4gZGF0YSBhcHBlYXJzIGF0IGZpeGVkIHZhbHVlcyksIG9yCi0gQWxpZ25lZCBkYXRhIHZhbHVlcyBvbiBhIHNpbmdsZSBheGlzLgoKT25lIHZlcnkgY29tbW9uIHRlY2huaXF1ZSB0aGF0IEknZCByZWNvbW1lbmQgdG8gYWx3YXlzIHVzZSB3aGVuIHlvdSBoYXZlIHNvbGlkIHNoYXBlcyBpdCB0byB1c2UgYWxwaGEgYmxlbmRpbmcgKGkuZS4gYWRkaW5nIHRyYW5zcGFyZW5jeSkuIEFuIGFsdGVybmF0aXZlIGlzIHRvIHVzZSBob2xsb3cgc2hhcGVzLiBUaGVzZSBhcmUgYWRqdXN0bWVudHMgdG8gbWFrZSBiZWZvcmUgZXZlbiB3b3JyeWluZyBhYm91dCBwb3NpdGlvbmluZy4gVGhpcyBhZGRyZXNzZXMgdGhlIGZpcnN0IHBvaW50IGFzIGFib3ZlLCB3aGljaCB5b3UnbGwgc2VlIGFnYWluIGluIHRoZSBuZXh0IGV4ZXJjaXNlLgoKIyMjIEluc3RydWN0aW9ucwoKLSBCZWdpbiBieSBtYWtpbmcgYSBiYXNpYyBzY2F0dGVyIHBsb3Qgb2YgYG1wZ2AgKHkpIHZzLiBgd3RgICh4KSwgbWFwIGBjeWxgIHRvIGBjb2xvcmAgYW5kIG1ha2UgdGhlIGBzaXplID0gNGAuIGBjeWxgIGhhcyBhbHJlYWR5IGJlZW4gY29udmVydGVkIHRvIGEgZmFjdG9yIHZhcmlhYmxlIGZvciB5b3UuCi0gTW9kaWZ5IHRoZSBhYm92ZSBwbG90IHRvIHNldCBgc2hhcGVgIHRvIGAxYC4gVGhpcyBhbGxvd3MgZm9yIGhvbGxvdyBjaXJjbGVzLgotIE1vZGlmeSB0aGUgZmlyc3QgcGxvdCB0byBzZXQgYGFscGhhYCB0byBgMC42YC4KCmBgYHtyfQojIEJhc2ljIHNjYXR0ZXIgcGxvdDogd3Qgb24geC1heGlzIGFuZCBtcGcgb24geS1heGlzOyBtYXAgY3lsIHRvIGNvbAoKCgojIEhvbGxvdyBjaXJjbGVzIC0gYW4gaW1wcm92ZW1lbnQKCgoKIyBBZGQgdHJhbnNwYXJlbmN5IC0gdmVyeSBuaWNlCgoKYGBgCgoKIyMgT3ZlcnBsb3R0aW5nIDIgLSBhbHBoYSB3aXRoIGxhcmdlIGRhdGFzZXRzCgpJbiBhIHByZXZpb3VzIGV4ZXJjaXNlIHdlIGRlZmluZWQgZm91ciBzaXR1YXRpb25zIGluIHdoaWNoIHlvdSdkIGhhdmUgdG8gYWRqdXN0IGZvciBvdmVycGxvdHRpbmcuIFlvdSdsbCBjb25zaWRlciB0aGUgbGFzdCB0d28gaGVyZSB3aXRoIHRoZSBkaWFtb25kcyBkYXRhc2V0OgoKLSBMYXJnZSBkYXRhc2V0cy4KLSBBbGlnbmVkIGRhdGEgdmFsdWVzIG9uIGEgc2luZ2xlIGF4aXMKCiMjIyBJbnN0cnVjdGlvbnMKCi0gVGhlIGBkaWFtb25kc2AgZGF0YSBmcmFtZSBpcyBhdmFpbGFibGUgaW4gdGhlIGBnZ3Bsb3QyKClgIHBhY2thZ2UuIEJlZ2luIGJ5IG1ha2luZyBhIGJhc2ljIHNjYXR0ZXIgcGxvdCBvZiBgcHJpY2VgICh5KSB2cy4gYGNhcmF0YCAoeCkgYW5kIG1hcCBgY2xhcml0eWAgb250byBgY29sb3JgLgotIENvcHkgdGhlIGFib3ZlIGZ1bmN0aW9ucyBhbmQgc2V0IHRoZSBgYWxwaGFgIHRvIGAwLjVgLiBUaGlzIGlzIGEgZ29vZCBzdGFydCB0byBkZWFsaW5nIHdpdGggdGhlIGxhcmdlIGRhdGFzZXQuCi0gQWxpZ24gYWxsIHRoZSBkaWFtb25kcyB3aXRoaW4gYSBjbGFyaXR5IGNsYXNzLCBieSBwbG90dGluZyBgY2FyYXRgICh5KSB2cy4gYGNsYXJpdHlgICh4KS4gTWFwIGBwcmljZWAgb250byBgY29sb3JgLiBgYWxwaGFgIHNob3VsZCBzdGlsbCBiZSBgMC41YC4KLSBJbiB0aGUgcHJldmlvdXMgcGxvdCwgYWxsIHRoZSBpbmRpdmlkdWFsIHZhbHVlcyBsaW5lIHVwIG9uIGEgc2luZ2xlIGF4aXMgd2l0aGluIGVhY2ggY2xhcml0eSBjYXRlZ29yeSwgc28geW91IGhhdmUgbm90IG92ZXJjb21lIG92ZXJwbG90dGluZy4gTW9kaWZ5IHRoZSBhYm92ZSBwbG90IHRvIHVzZSB0aGUgYHBvc2l0aW9uID0gImppdHRlciJgIGluc2lkZSBgZ2VvbV9wb2ludCgpYC4KCmBgYHtyfQojIFNjYXR0ZXIgcGxvdDogY2FyYXQgKHgpLCBwcmljZSAoeSksIGNsYXJpdHkgKGNvbG9yKQoKCgojIEFkanVzdCBmb3Igb3ZlcnBsb3R0aW5nCgoKCiMgU2NhdHRlciBwbG90OiBjbGFyaXR5ICh4KSwgY2FyYXQgKHkpLCBwcmljZSAoY29sb3IpCgoKCiMgRG90IHBsb3Qgd2l0aCBqaXR0ZXJpbmcKCgpgYGAKCgojIEdlb21ldHJpZXMKCiMjIFNjYXR0ZXIgcGxvdHMgYW5kIGppdHRlcmluZyAoMSkKCllvdSBhbHJlYWR5IHNhdyBhIGZldyBleGFtcGxlcyB1c2luZyBgZ2VvbV9wb2ludCgpYCB3aGVyZSB0aGUgcmVzdWx0IHdhcyBub3QgYSBzY2F0dGVyIHBsb3QuIEZvciBleGFtcGxlLCBpbiB0aGUgcGxvdCBnaXZlbiBiZWxvdywgYSBjb250aW51b3VzIHZhcmlhYmxlLCBgd3RgLCBpcyBtYXBwZWQgdG8gdGhlIGB5YCBhZXN0aGV0aWMsIGFuZCBhIGNhdGVnb3JpY2FsIHZhcmlhYmxlLCBgY3lsYCwgaXMgbWFwcGVkIHRvIHRoZSBgeGAgYWVzdGhldGljLiBUaGlzIGFsc28gbGVhZHMgdG8gb3Zlci1wbG90dGluZywgc2luY2UgdGhlIHBvaW50cyBhcmUgYXJyYW5nZWQgb24gYSBzaW5nbGUgeCBwb3NpdGlvbi4gWW91IHByZXZpb3VzbHkgZGVhbHQgd2l0aCBvdmVycGxvdHRpbmcgYnkgc2V0dGluZyB0aGUgYHBvc2l0aW9uID0gaml0dGVyYCBpbnNpZGUgYGdlb21fcG9pbnQoKWAuIExldCdzIGxvb2sgYXQgc29tZSBvdGhlciBzb2x1dGlvbnMgaGVyZS4KCiMjIyBJbnN0cnVjdGlvbnMKCkJlZ2lubmluZyB3aXRoIHRoZSBjb2RlIGZvciB0aGUgcGxvdCBpbiB0aGUgdmlld2VyIChnaXZlbiksIG1ha2UgdGhlc2UgbW9kaWZpY2F0aW9ucwoKLSBVc2UgYSBzaG9ydGN1dCBnZW9tLCBgZ2VvbV9qaXR0ZXIoKWAsIGluc3RlYWQgb2YgYGdlb21fcG9pbnQoKWAuCi0gVW5mb3J0dW5hdGVseSwgdGhlIHdpZHRoIG9mIHRoZSBqaXR0ZXIgaXMgYSBiaXQgdG9vIHdpZGUgdG8gYmUgdXNlZnVsLiBBZGp1c3QgdGhpcyBieSBzZXR0aW5nIHRoZSBhcmd1bWVudCBgd2lkdGggPSAwLjFgIGluc2lkZSBgZ2VvbV9qaXR0ZXIoKWAuCi0gRmluYWxseSwgcmV0dXJuIHRvIGBnZW9tX3BvaW50KClgIGFuZCBzZXQgdGhlIHBvc2l0aW9uIGFyZ3VtZW50IGhlcmUgdG8gYHBvc2l0aW9uX2ppdHRlcigwLjEpYCwgd2hpY2ggd2lsbCBzZXQgdGhlIGppdHRlcmluZyB3aWR0aCBkaXJlY3RseSBpbnNpZGUgYSBwb2ludHMgbGF5ZXIuCgpOb3RlOiBGb3IgY29udmVuaWVuY2UsIHlvdSBjb3VsZCBoYXZlIHNhdmVkIHRoZSBkYXRhIGFuZCBhZXN0aGV0aWMgbGF5ZXJzIGFzIGEgZ2dwbG90MiBvYmplY3QgYW5kIHJlLXVzZWQgaXQgaW4gYWxsIHNvbHV0aW9ucy4gV2UndmUgbWFkZSBlYWNoIHBsb3QgZXhwbGljaXQgc28gdGhhdCB5b3UgY2FuIHNlZSBhbGwgcGxvdHRpbmcgaW5zdHJ1Y3Rpb25zLgoKYGBge3J9CiMgU2hvd24gaW4gdGhlIHZpZXdlcjoKZ2dwbG90KG10Y2FycywgYWVzKHggPSBjeWwsIHkgPSB3dCkpICsKICBnZW9tX3BvaW50KCkKCiMgU29sdXRpb25zOgojIDEgLSBXaXRoIGdlb21faml0dGVyKCkKZ2dwbG90KG10Y2FycywgYWVzKHggPSBjeWwsIHkgPSB3dCkpICsKICBfX18oKQoKIyAyIC0gU2V0IHdpZHRoIGluIGdlb21faml0dGVyKCkKZ2dwbG90KG10Y2FycywgYWVzKHggPSBjeWwsIHkgPSB3dCkpICsKICBfX18oX19fKQoKIyAzIC0gU2V0IHBvc2l0aW9uID0gcG9zaXRpb25faml0dGVyKCkgaW4gZ2VvbV9wb2ludCgpICgpCmdncGxvdChtdGNhcnMsIGFlcyh4ID0gY3lsLCB5ID0gd3QpKSArCiAgX19fKF9fXyA9IF9fXygpKQoKYGBgCgoKIyMgU2NhdHRlciBwbG90cyBhbmQgaml0dGVyaW5nICgyKQoKSW4gdGhlIGNoYXB0ZXIgb24gYWVzdGhldGljcyB5b3Ugc2F3IGRpZmZlcmVudCB3YXlzIGluIHdoaWNoIHlvdSB3aWxsIGhhdmUgdG8gY29tcGVuc2F0ZSBmb3Igb3ZlcnBsb3R0aW5nLiAKCkFub3RoZXIgaXNzdWUgaXMgd2hlbiB5b3UgaGF2ZSBpbnRlcnZhbCBkYXRhLiBUaGlzIGNhbiBiZSBjb250aW51b3VzIGRhdGEgbWVhc3VyZWQgb24gYW4gaW50ZXJ2YWwgKGkuZS4gMSAsMiwgMyAuLi4pLCBhcyBvcHBvc2VkIHRvIG51bWVyaWMgKGkuZS4gMS4xLCAxLjQsIDEuNSwgLi4uKSwgc2NhbGUsIG9yIHR3byBjYXRlZ29yaWNhbCAoZS5nLiBmYWN0b3IpIHZhcmlhYmxlcywgd2hpY2ggYXJlIGp1c3QgdHlwZSBpbnRlcnZhbCB1bmRlci10aGUtaG9vZC4KCkluIHN1Y2ggYSBjYXNlIHlvdSdsbCBoYXZlIGEgc21hbGwsIGRlZmluZWQgbnVtYmVyIG9mIGludGVyc2VjdGlvbnMgYmV0d2VlbiB0aGUgdHdvIHZhcmlhYmxlcy4KCllvdSB3aWxsIGJlIHVzaW5nIHRoZSBgVm9jYWJgIGRhdGFzZXQuIFRoZSBgVm9jYWJgIGRhdGFzZXQgY29udGFpbnMgaW5mb3JtYXRpb24gYWJvdXQgdGhlIHllYXJzIG9mIGVkdWNhdGlvbiBhbmQgaW50ZWdlciBzY29yZSBvbiBhIHZvY2FidWxhcnkgdGVzdCBmb3Igb3ZlciAyMSwwMDAgaW5kaXZpZHVhbHMgYmFzZWQgb24gVVMgR2VuZXJhbCBTb2NpYWwgU3VydmV5cyBmcm9tIDE5NzItMjAwNC4KCiMjIyBJbnN0cnVjdGlvbnMKCi0gVGhlIGBWb2NhYmAgZGF0YSBmcmFtZSBoYXMgYmVlbiBsb2FkZWQgZm9yIHlvdS4gQm90aCB0aGUgZWR1Y2F0aW9uIGFuZCB2b2NhYnVsYXJ5IHZhcmlhYmxlcyBhcmUgY2xhc3NpZmllZCBhcyBpbnRlZ2Vycy4gWW91IGNhbiBpbWFnaW5lIHRoZXNlIGFzIGZhY3RvciB2YXJpYWJsZXMsIGJ1dCBoZXJlLCBpbnRlZ2VycyBhcmUgbW9yZSBjb252ZW5pZW50IHRvIHdvcmsgd2l0aC4gRmlyc3QsIGdldCBmYW1pbGlhciB3aXRoIHRoZSBkYXRhc2V0IGJ5IGxvb2tpbmcgYXQgaXRzIHN0cnVjdHVyZSB3aXRoIGBzdHIoKWAuCi0gTWFrZSBhIGJhc2ljIHNjYXR0ZXIgcGxvdCBvZiBgdm9jYWJ1bGFyeWAgKHkpIHZzLiBgZWR1Y2F0aW9uYCAoeCkuIEhlcmUgaXQgYmVjb21lcyBhcHBhcmVudCB0aGF0IHlvdSBoYXZlIGlzc3VlcyB3aXRoIG92ZXJwbG90dGluZyBiZWNhdXNlIG9mIHRoZSBpbnRlZ2VyIHNjYWxlcy4KLSBVc2UgYGdlb21faml0dGVyKClgIGluc3RlYWQgb2YgYGdlb21fcG9pbnQoKWAuCi0gVXNpbmcgdGhlIGppdHRlcmVkIHBsb3QsIHNldCBgYWxwaGFgIHRvIGAwLjJgICh2ZXJ5IGxvdykuCi0gVXNpbmcgdGhlIGppdHRlcmVkIHBsb3QsIHNldCBgc2hhcGVgIHRvIGAxYC4KCgpgYGB7cn0KaW5zdGFsbC5wYWNrYWdlcygiY2FyRGF0YSIpCmxpYnJhcnkoY2FyRGF0YSkKIyBFeGFtaW5lIHRoZSBzdHJ1Y3R1cmUgb2YgVm9jYWIKCgojIEJhc2ljIHNjYXR0ZXIgcGxvdCBvZiB2b2NhYnVsYXJ5ICh5KSBhZ2FpbnN0IGVkdWNhdGlvbiAoeCkuIFVzZSBnZW9tX3BvaW50KCkKCgoKIyBVc2UgZ2VvbV9qaXR0ZXIoKSBpbnN0ZWFkIG9mIGdlb21fcG9pbnQoKQoKCgojIFVzaW5nIHRoZSBhYm92ZSBwbG90dGluZyBjb21tYW5kLCBzZXQgYWxwaGEgdG8gYSB2ZXJ5IGxvdyAwLjIKCgoKIyBVc2luZyB0aGUgYWJvdmUgcGxvdHRpbmcgY29tbWFuZCwgc2V0IHRoZSBzaGFwZSB0byAxCgoKYGBgCgoKIyMgSGlzdG9ncmFtcwoKSGlzdG9ncmFtcyBhcmUgb25lIG9mIHRoZSBtb3N0IGNvbW1vbiBhbmQgaW50dWl0aXZlIHdheXMgb2Ygc2hvd2luZyBkaXN0cmlidXRpb25zLiBJbiB0aGlzIGV4ZXJjaXNlIHlvdSdsbCB1c2UgdGhlIGBtdGNhcnNgIGRhdGEgZnJhbWUgdG8gZXhwbG9yZSB0eXBpY2FsIHZhcmlhdGlvbnMgb2Ygc2ltcGxlIGhpc3RvZ3JhbXMuIEJ1dCBmaXJzdCwgc29tZSBiYWNrZ3JvdW5kOgoKKipUaGUgeCBheGlzL2Flc3RoZXRpYyoqOiBUaGUgZG9jdW1lbnRhdGlvbiBmb3IgYGdlb21faGlzdG9ncmFtKClgIHN0YXRlcyB0aGUgYXJndW1lbnQgYHN0YXQgPSAiYmluImAgYXMgYSBkZWZhdWx0LiBSZWNhbGwgdGhhdCBoaXN0b2dyYW1zIGN1dCB1cCBhIGNvbnRpbnVvdXMgdmFyaWFibGUgaW50byBkaXNjcmV0ZSBiaW5zIC0gdGhhdHMgd2hhdCB0aGUgc3RhdCAiYmluIiBpcyBkb2luZy4gWW91IGFsd2F5cyBnZXQgMzAgZXZlbmx5LXNpemVkIGJpbnMgYnkgZGVmYXVsdCwgd2hpY2ggaXMgc3BlY2lmaWVkIHdpdGggdGhlIGRlZmF1bHQgYXJndW1lbnQgYGJpbndpZHRoID0gcmFuZ2UvMzBgLiBUaGlzIGlzIGEgcHJldHR5IGdvb2Qgc3RhcnRpbmcgcG9pbnQgaWYgeW91IGRvbid0IGtub3cgYW55dGhpbmcgYWJvdXQgdGhlIHZhcmlhYmxlIGJlaW5nIHBsb3RlZCBhbmQgd2FudCB0byBzdGFydCBleHBsb3JpbmcuCgoqKlRoZSB5IGF4aXMvYWVzdGhldGljKio6IGBnZW9tX2hpc3RvZ3JhbSgpYCBvbmx5IHJlcXVpcmVzIG9uZSBhZXN0aGV0aWM6IGB4YC4gQnV0IHRoZXJlIGlzIGNsZWFybHkgYSBgeWAgYXhpcyBvbiB5b3VyIHBsb3QsIHNvIHdoZXJlIGRvZXMgaXQgY29tZSBmcm9tPyBBY3R1YWxseSwgdGhlcmUgaXMgYSB2YXJpYWJsZSBtYXBwZWQgdG8gdGhlIHkgYWVzdGhldGljLCBpdCdzIGNhbGxlZCBgLi5jb3VudC4uYC4gV2hlbiBgZ2VvbV9oaXN0b2dyYW0oKWAgZXhlY3V0ZWQgdGhlIGJpbm5pbmcgc3RhdGlzdGljIChzZWUgYWJvdmUpLCBpdCBub3Qgb25seSBjdXQgdXAgdGhlIGRhdGEgaW50byBkaXNjcmV0ZSBiaW5zLCBidXQgaXQgYWxzbyAqY291bnRlZCogaG93IG1hbnkgdmFsdWVzIGFyZSBpbiBlYWNoIGJpbi4gU28gdGhlcmUgaXMgYW4gKmludGVybmFsKiBkYXRhIGZyYW1lIHdoZXJlIHRoaXMgaW5mb3JtYXRpb24gaXMgc3RvcmVkLiBUaGUgLi4gY2FsbHMgdGhlIHZhcmlhYmxlIGNvdW50IGZyb20gdGhpcyAqaW50ZXJuYWwqIGRhdGEgZnJhbWUuIFRoaXMgaXMgd2hhdCBhcHBlYXJzIG9uIHRoZSBgeWAgYWVzdGhldGljLiBCdXQgaXQgZ2V0cyBiZXR0ZXIhIFRoZSAqZGVuc2l0eSogaGFzIGFsc28gYmVlbiBjYWxjdWxhdGVkLiBUaGlzIGlzIHRoZSAqcHJvcG9ydGlvbmFsIGZyZXF1ZW5jeSogb2YgdGhpcyBiaW4gaW4gcmVsYXRpb24gdG8gdGhlIHdob2xlIGRhdGEgc2V0LiBZb3UgdXNlIGAuLmRlbnNpdHkuLmAgdG8gYWNjZXNzIHRoaXMgaW5mb3JtYXRpb24uCgojIyMgSW5zdHJ1Y3Rpb25zCgotIFVzZSB0aGUgYG10Y2Fyc2AgZGF0YSBmcmFtZSBhbmQgbWFrZSBhIHVuaXZhcmlhdGUgaGlzdG9ncmFtIGJ5IG1hcHBpbmcgYG1wZ2Agb250byB0aGUgYHhgIGFlc3RoZXRpYy4gVXNlIGBnZW9tX2hpc3RvZ3JhbSgpYCBmb3IgdGhlIGdlb20gbGF5ZXIuCi0gVGFrZSBwbG90IDEgYW5kIG1hbnVhbGx5IGNyZWF0ZSAxLXVuaXQgd2lkZSBiaW5zIHdpdGggdGhlIGBiaW53aWR0aCA9IDFgIGFyZ3VtZW50IGluIGBnZW9tX2hpc3RvZ3JhbSgpYC4KLSBUYWtlIHBsb3QgMiwgYW5kIG1hcCBgLi5kZW5zaXR5Li5gIG9udG8gdGhlIGB5YCBhZXN0aGV0aWMgKGkuZS4gaW5zaWRlIGFuIGBhZXMoKWApIGluc2lkZSBgZ2VvbV9oaXN0b2dyYW0oKWAuIFlvdSdsbCBoYXZlIHR3byBgYWVzKClgIGZ1bmN0aW9uczogb25lIGluc2lkZSBgZ2dwbG90KClgIGFuZCBhbm90aGVyIGluc2lkZSBgZ2VvbV9oaXN0b2dyYW0oKWAuIChTZWUgdGhlIGludHJvIHRleHQgZm9yIGEgZGlzY3Vzc2lvbiBvZiBgLi5kZW5zaXR5Li5gKS4KLSBUYWtlIHBsb3QgMyBhbmQgc2V0IHRoZSBhdHRyaWJ1dGUgYGZpbGxgLCB0aGUgaW5zaWRlIG9mIHRoZSBiYXJzLCB0byB0aGUgdmFsdWUgYCIjMzc3RUI4ImAgaW4gYGdlb21faGlzdG9ncmFtKClgLiBUaGlzIHNob3VsZCBub3QgYXBwZWFyIGluIGBhZXMoKWAsIHNpbmNlIGl0J3MgYW4gYXR0cmlidXRlLCBub3QgYW4gYWVzdGhldGljIG1hcHBpbmcuCgoKYGBge3J9CiMgMSAtIE1ha2UgYSB1bml2YXJpYXRlIGhpc3RvZ3JhbQpnZ3Bsb3QoX19fLCBhZXMoeCA9IF9fXykpICsKICBfX18oKQoKIyAyIC0gUGxvdCAxLCBwbHVzIHNldCBiaW53aWR0aCB0byAxIGluIHRoZSBnZW9tIGxheWVyCgoKCiMgMyAtIFBsb3QgMiwgcGx1cyBNQVAgLi5kZW5zaXR5Li4gdG8gdGhlIHkgYWVzdGhldGljIChpLmUuIGluIGEgc2Vjb25kIGFlcygpIGZ1bmN0aW9uKQoKCgojIDQgLSBwbG90IDMsIHBsdXMgU0VUIHRoZSBmaWxsIGF0dHJpYnV0ZSB0byAiIzM3N0VCOCIKCgoKYGBgCgoKIyMgUG9zaXRpb24KCkluIHRoZSBwcmV2aW91cyBjaGFwdGVyIHlvdSBzYXcgdGhhdCB0aGVyZSBhcmUgbG90cyBvZiB3YXlzIHRvIHBvc2l0aW9uIHNjYXR0ZXIgcGxvdHMuIExpa2V3aXNlLCB0aGUgYGdlb21fYmFyKClgIGFuZCBgZ2VvbV9oaXN0b2dyYW0oKWAgZ2VvbXMgYWxzbyBoYXZlIGEgYHBvc2l0aW9uYCBhcmd1bWVudCwgd2hpY2ggeW91IGNhbiB1c2UgdG8gc3BlY2lmeSBob3cgdG8gZHJhdyB0aGUgYmFycyBvZiB0aGUgcGxvdC4KClRocmVlIGBwb3NpdGlvbmAgYXJndW1lbnRzIHdpbGwgYmUgaW50cm9kdWNlZCBoZXJlOgoKLSBgc3RhY2tgOiBwbGFjZSB0aGUgYmFycyBvbiB0b3Agb2YgZWFjaCBvdGhlci4gQ291bnRzIGFyZSB1c2VkLiBUaGlzIGlzIHRoZSBkZWZhdWx0IHBvc2l0aW9uLgotIGBmaWxsYDogcGxhY2UgdGhlIGJhcnMgb24gdG9wIG9mIGVhY2ggb3RoZXIsIGJ1dCB0aGlzIHRpbWUgdXNlIHByb3BvcnRpb25zLgotIGBkb2RnZWA6IHBsYWNlIHRoZSBiYXJzIG5leHQgdG8gZWFjaCBvdGhlci4gQ291bnRzIGFyZSB1c2VkLgoKSW4gdGhpcyBleGVyY2lzZSB5b3UnbGwgZHJhdyB0aGUgdG90YWwgY291bnQgb2YgY2FycyBoYXZpbmcgYSBnaXZlbiBudW1iZXIgb2YgYGN5bGluZGVyc2AgKGN5bCksIGFjY29yZGluZyB0byBtYW51YWwgb3IgYXV0b21hdGljIHRyYW5zbWlzc2lvbiB0eXBlIChgYW1gKS4KClNpbmNlLCBpbiB0aGUgYnVpbHQtaW4gYG10Y2Fyc2AgZGF0YSBzZXQsIGBjeWxgIGFuZCBgYW1gIGFyZSBpbnRlZ2VycywgeW91IGhhdmUgdG8gY29udmVydCB0aGVtIGludG8gZmFjdG9yIHZhcmlhYmxlcy4KCiMjIyBJbnN0cnVjdGlvbnMKCi0gVXNpbmcgYG10Y2Fyc2AsIG1hcCBgY3lsYCBvbnRvIHRoZSBgeGAgYWVzdGhldGljIGFuZCBgYW1gIG9udG8gYGZpbGxgLiBVc2UgYGdlb21fYmFyKClgIHRvIG1ha2UgYSBiYXIgcGxvdC4KLSBUYWtlIHBsb3QgMSBhbmQgZXhwbGljaXRseSBzZXQgYHBvc2l0aW9uID0gInN0YWNrImAgaW4gYGdlb21fYmFyKClgLiBUaGlzIGRvZXNuJ3QgY2hhbmdlIGFueXRoaW5nLCBkb2VzIGl0PyBJdCB3YXMgbWVudGlvbmVkIGFib3ZlIHRoYXQgYCJzdGFjayJgIGlzIHRoZSBkZWZhdWx0LgotIFRha2UgcGxvdCAyIGFuZCBzZXQgYHBvc2l0aW9uID0gImZpbGwiYCBpbiBgZ2VvbV9iYXIoKWAuCi0gVGFrZSBwbG90IDMgYW5kIHNldCBgcG9zaXRpb24gPSAiZG9kZ2UiYCBpbiBgZ2VvbV9iYXIoKWAuCgpgYGB7cn0KIyBEcmF3IGEgYmFyIHBsb3Qgb2YgY3lsLCBmaWxsZWQgYWNjb3JkaW5nIHRvIGFtCmdncGxvdChfX18sIGFlcyh4ID0gX19fLCBmaWxsID0gX19fKSkgKwogIF9fXygpCgojIENoYW5nZSB0aGUgcG9zaXRpb24gYXJndW1lbnQgdG8gc3RhY2sKCgoKIyBDaGFuZ2UgdGhlIHBvc2l0aW9uIGFyZ3VtZW50IHRvIGZpbGwKCgoKIyBDaGFuZ2UgdGhlIHBvc2l0aW9uIGFyZ3VtZW50IHRvIGRvZGdlCgoKYGBgCgoKIyMgT3ZlcmxhcHBpbmcgYmFyIHBsb3RzCgpTbyBmYXIgeW91J3ZlIHNlZW4gdGhyZWUgZGlmZmVyZW50IHBvc2l0aW9ucyBmb3IgYmFyIHBsb3RzOiBgc3RhY2tgICh0aGUgZGVmYXVsdCksIGBkb2RnZWAgKHByZWZlcnJlZCksIGFuZCBgZmlsbGAgKHRvIHNob3cgcHJvcG9ydGlvbnMpLgoKSG93ZXZlciwgeW91IGNhbiBnbyBvbmUgc3RlcCBmdXJ0aGVyIGJ5IGFkanVzdGluZyB0aGUgZG9kZ2luZywgc28gdGhhdCB5b3VyIGJhcnMgcGFydGlhbGx5IG92ZXJsYXAgZWFjaCBvdGhlci4gRm9yIHRoaXMgZXhhbXBsZSB5b3UnbGwgYWdhaW4gdXNlIHRoZSBgbXRjYXJzYCBkYXRhc2V0LiBMaWtlIGxhc3QgdGltZSB5b3UgaGF2ZSB0byBjb252ZXJ0IGBjeWxgIGFuZCBgYW1gIGludG8gZmFjdG9ycyBpbnNpZGUgYG10Y2Fyc2AuCgpJbnN0ZWFkIG9mIHVzaW5nIGBwb3NpdGlvbiA9ICJkb2RnZSJgIHlvdSdyZSBnb2luZyB0byB1c2UgYHBvc2l0aW9uX2RvZGdlKClgLCBsaWtlIHlvdSBkaWQgd2l0aCBgcG9zaXRpb25faml0dGVyKClgIGluIHRoZSAqU2NhdHRlciBwbG90cyBhbmQgaml0dGVyaW5nICgxKSogZXhlcmNpc2UuIEhlcmUsIHlvdSdsbCBzYXZlIHRoaXMgYXMgYW4gb2JqZWN0LCBgcG9zbl9kYCwgc28gdGhhdCB5b3UgY2FuIGVhc2lseSByZXVzZSBpdC4KClJlbWVtYmVyLCB0aGUgcmVhc29uIHlvdSB3YW50IHRvIHVzZSBgcG9zaXRpb25fZG9kZ2UoKWAgKGFuZCBgcG9zaXRpb25faml0dGVyKClgKSBpcyB0byBzcGVjaWZ5IGhvdyBtdWNoIGRvZGdpbmcgKG9yIGppdHRlcmluZykgeW91IHdhbnQuCgojIyMgSW5zdHJ1Y3Rpb25zCgotIFRoZSBsYXN0IHBsb3QgZnJvbSB0aGUgbGFzdCBleGVyY2lzZSBoYXMgYmVlbiBwcm92aWRlZCBmb3IgeW91LgotIERlZmluZSBhIG5ldyBvYmplY3QgY2FsbGVkIGBwb3NuX2RgIGJ5IGNhbGxpbmcgYHBvc2l0aW9uX2RvZGdlKClgIHdpdGggdGhlIGFyZ3VtZW50IGB3aWR0aCA9IDAuMmAuCi0gVGFrZSBwbG90IDEgYW5kIG1ha2Ugc2xpZ2h0bHkgb3ZlcmxhcHBpbmcgYmFycyBieSB1c2luZyB0aGUgYHBvc2l0aW9uID0gcG9zbl9kYCBhcmd1bWVudC4KLSBUYWtlIHBsb3QgMyBhbmQgc2V0IGBhbHBoYSA9IDAuNmAgdG8gc2VlIHRoZSBvdmVybGFwIGluIGJhcnMuCgpgYGB7cn0KIyAxIC0gVGhlIGxhc3QgcGxvdCBmb3JtIHRoZSBwcmV2aW91cyBleGVyY2lzZQpnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IGN5bCwgZmlsbCA9IGFtKSkgKwogIGdlb21fYmFyKHBvc2l0aW9uID0gImRvZGdlIikKCiMgMiAtIERlZmluZSBwb3NuX2Qgd2l0aCBwb3NpdGlvbl9kb2RnZSgpCnBvc25fZCA8LSBfX18oKQoKIyAzIC0gQ2hhbmdlIHRoZSBwb3NpdGlvbiBhcmd1bWVudCB0byBwb3NuX2QKCgoKIyA0IC0gVXNlIHBvc25fZCBhcyBwb3NpdGlvbiBhbmQgYWRqdXN0IGFscGhhIHRvIDAuNgoKCgpgYGAKCgojIyBPdmVybGFwcGluZyBoaXN0b2dyYW1zCgpPdmVybGFwcGluZyBoaXN0b2dyYW1zIHBvc2Ugc2ltaWxhciBwcm9ibGVtcyB0byBvdmVybGFwcGluZyBiYXIgcGxvdHMsIGJ1dCB0aGVyZSBpcyBhIHVuaXF1ZSBzb2x1dGlvbiBoZXJlOiBhIGZyZXF1ZW5jeSBwb2x5Z29uLgoKVGhpcyBpcyBhIGdlb20gc3BlY2lmaWMgdG8gYmlubmVkIGRhdGEgdGhhdCBkcmF3cyBhIGxpbmUgY29ubmVjdGluZyB0aGUgdmFsdWUgb2YgZWFjaCBiaW4uIExpa2UgYGdlb21faGlzdG9ncmFtKClgLCBpdCB0YWtlcyBhIGBiaW53aWR0aGAgYXJndW1lbnQgYW5kIGJ5IGRlZmF1bHQgYHN0YXQgPSAiYmluImAgYW5kIGBwb3NpdGlvbiA9ICJpZGVudGl0eSJgLgoKIyMjIEluc3RydWN0aW9ucwoKLSBUaGUgY29kZSBmb3IgYSBiYXNpYyBoaXN0b2dyYW0gb2YgYG1wZ2AsIHdoaWNoIHlvdSd2ZSBhbHJlYWR5IHNlZW4sIGlzIHByb3ZpZGVkLiBFeHRlbmQgdGhlIGNvZGUgdG8gbWFwIGBjeWxgIG9udG8gYGZpbGxgIGluc2lkZSBgYWVzKClgLgotIFRoZSBkZWZhdWx0IHBvc2l0aW9uIGZvciBoaXN0b2dyYW1zIGlzIGAic3RhY2siYC4gQ29weSB5b3VyIHNvbHV0aW9uIHRvIHRoZSBmaXJzdCBleGVyY2lzZSBhbmQgc2V0IHRoZSBgcG9zaXRpb25gIGZvciB0aGUgaGlzdG9ncmFtIGJhcnMgdG8gYCJpZGVudGl0eSJgLgotIFVzaW5nIHRoZSBzYW1lIGRhdGEgYW5kIGJhc2UgbGF5ZXJzIGFzIGluIHRoZSBwcmV2aW91cyB0d28gcGxvdHMsIGNyZWF0ZSBhIHBsb3Qgd2l0aCBhIGBnZW9tX2ZyZXFwb2x5KClgLiBCZWNhdXNlIHlvdSdyZSBubyBsb25nZXIgd29ya2luZyB3aXRoIGJhcnMsIGNoYW5nZSB0aGUgYGFlcygpYCBmdW5jdGlvbjogYGN5bGAgc2hvdWxkIGJlIG1hcHBlZCBvbnRvIGBjb2xgLCBub3Qgb250byBgZmlsbGAuIFRoaXMgd2lsbCBjb3JyZWN0bHkgY29sb3IgdGhlIGdlb20uCgpgYGB7cn0KIyBBIGJhc2ljIGhpc3RvZ3JhbSwgYWRkIGNvbG9yaW5nIGRlZmluZWQgYnkgY3lsCmdncGxvdChtdGNhcnMsIGFlcyhtcGcpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAxKQoKIyBDaGFuZ2UgcG9zaXRpb24gdG8gaWRlbnRpdHkKCgoKIyBDaGFuZ2UgZ2VvbSB0byBmcmVxcG9seSAocG9zaXRpb24gaXMgaWRlbnRpdHkgYnkgZGVmYXVsdCkKCgpgYGAKCiMjIEJhciBwbG90cyB3aXRoIGNvbG9yIHJhbXAsIHBhcnQgMQoKSW4gdGhpcyBleGFtcGxlIG9mIGEgYmFyIHBsb3QsIHlvdSdsbCBmaWxsIGVhY2ggc2VnbWVudCBhY2NvcmRpbmcgdG8gYW4gb3JkaW5hbCB2YXJpYWJsZS4gVGhlIGJlc3Qgd2F5IHRvIGRvIHRoYXQgaXMgd2l0aCBhIHNlcXVlbnRpYWwgY29sb3Igc2VyaWVzLgoKWW91J2xsIGJlIHVzaW5nIHRoZSBgVm9jYWJgIGRhdGFzZXQgZnJvbSBlYXJsaWVyLiBTaW5jZSB0aGlzIGlzIGEgbXVjaCBsYXJnZXIgZGF0YXNldCB3aXRoIG1vcmUgY2F0ZWdvcmllcywgeW91J2xsIGFsc28gY29tcGFyZSBpdCB0byBhIHNpbXBsZXIgZGF0YXNldCwgYG10Y2Fyc2AuIEJvdGggZGF0YXNldHMgYXJlIG9yZGluYWwuCgojIyMgSW5zdHJ1Y3Rpb25zCgotIFRoZSBiYXIgcGxvdCBmcm9tIHRoZSBwcmV2aW91cyBleGVyY2lzZSBpcyBwcm92aWRlZCAtIGBjeWxgIGlzIG9uIHRoZSB4LWF4aXMgYW5kIGZpbGxlZCBhY2NvcmRpbmcgdG8gdHJhbnNtaXNzaW9uIHR5cGUsIGBhbWAuIE5vdGljZSBob3cgeW91IGNhbiBzZXQgdGhlIGNvbG9yIHBhbGV0dGUgdXNlZCB0byBmaWxsIHRoZSBiYXJzIHdpdGggYHNjYWxlX2ZpbGxfYnJld2VyKClgLiBGb3IgYSBmdWxsIGxpc3Qgb2YgcG9zc2libGUgY29sb3Igc2V0cywgaGF2ZSBhIGxvb2sgYXQgYD9icmV3ZXIucGFsYC4KLSBFeHBsb3JlIGBWb2NhYmAgd2l0aCBgc3RyKClgLiBOb3RpY2UgdGhhdCB0aGUgYGVkdWNhdGlvbmAgYW5kIGB2b2NhYnVsYXJ5YCB2YXJpYWJsZXMgaGF2ZSBhbHJlYWR5IGJlZW4gY29udmVydGVkIHRvIGZhY3RvciB2YXJpYWJsZXMgZm9yIHlvdS4KLSBNYWtlIGEgZmlsbGVkIGJhciBjaGFydCB3aXRoIHRoZSBgVm9jYWJgIGRhdGFzZXQuCiAgIC0gTWFwIGBlZHVjYXRpb25gIHRvIGB4YCBhbmQgYHZvY2FidWxhcnlgIHRvIGBmaWxsYC4KICAgLSBJbnNpZGUgYGdlb21fYmFyKClgLCBtYWtlIHN1cmUgdG8gc2V0IGBwb3NpdGlvbiA9ICJmaWxsImAuCiAgIC0gQWxsb3cgY29sb3IgYnJld2VyIHRvIGNob29zZSBhIGRlZmF1bHQgY29sb3IgcGFsZXR0ZSBieSB1c2luZyB0aGUgYXBwcm9wcmlhdGUgc2NhbGUgZnVuY3Rpb24sIHdpdGhvdXQgYXJndW1lbnRzLiBOb3RpY2UgaG93IHRoaXMgZ2VuZXJhdGVzIGEgd2FybmluZyBtZXNzYWdlIGFuZCBhbiBpbmNvbXBsZXRlIHBsb3QuCgpgYGB7cn0KIyBFeGFtcGxlIG9mIGhvdyB0byB1c2UgYSBicmV3ZWQgY29sb3IgcGFsZXR0ZQpnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IGN5bCwgZmlsbCA9IGFtKSkgKwogIGdlb21fYmFyKCkgKwogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiU2V0MSIpCgojIFVzZSBzdHIoKSBvbiBWb2NhYiB0byBjaGVjayBvdXQgdGhlIHN0cnVjdHVyZQoKCiMgUGxvdCBlZHVjYXRpb24gb24geCBhbmQgdm9jYWJ1bGFyeSBvbiBmaWxsCiMgVXNlIHRoZSBkZWZhdWx0IGJyZXdlZCBjb2xvciBwYWxldHRlCgoKYGBgCgoKIyMgQmFyIHBsb3RzIHdpdGggY29sb3IgcmFtcCwgcGFydCAyCgpJbiB0aGUgcHJldmlvdXMgZXhlcmNpc2UsIHlvdSBlbmRlZCB1cCB3aXRoIGFuIGluY29tcGxldGUgYmFyIHBsb3QuIFRoaXMgd2FzIGJlY2F1c2UgZm9yIGNvbnRpbnVvdXMgZGF0YSwgdGhlIGRlZmF1bHQgYFJDb2xvckJyZXdlcmAgcGFsZXR0ZSB0aGF0IGBzY2FsZV9maWxsX2JyZXdlcigpYCBjYWxscyBpcyBgIkJsdWVzImAuIFRoZXJlIGFyZSBvbmx5IDkgY29sb3VycyBpbiB0aGUgcGFsZXR0ZSwgYW5kIHNpbmNlIHlvdSBoYXZlIDExIGNhdGVnb3JpZXMsIHlvdXIgcGxvdCBsb29rZWQgc3RyYW5nZS4KCkluIHRoaXMgZXhlcmNpc2UsIHlvdSdsbCBtYW51YWxseSBjcmVhdGUgYSBjb2xvciBwYWxldHRlIHRoYXQgY2FuIGdlbmVyYXRlIGFsbCB0aGUgY29sb3VycyB5b3UgbmVlZC4gVG8gZG8gdGhpcyB5b3UnbGwgdXNlIGEgZnVuY3Rpb24gY2FsbGVkIGBjb2xvclJhbXBQYWxldHRlKClgLgoKVGhlIGlucHV0IGlzIGEgY2hhcmFjdGVyIHZlY3RvciBvZiAyIG9yIG1vcmUgY29sb3VyIHZhbHVlcywgZS5nLiBgIiNGRkZGRkYiYCAod2hpdGUpIGFuZCBgIiMwMDAwRkYiYCAocHVyZSBibHVlKS4gKFNlZSAqQWxsIGFib3V0IGF0dHJpYnV0ZXMsIHBhcnQgMSogZm9yIGEgZGlzY3Vzc2lvbiBvbiBoZXhhZGVjaW1hbCBjb2RlcykuCgpUaGUgb3V0cHV0IGlzIGl0c2VsZiBhIGZ1bmN0aW9uISBTbyB3aGVuIHlvdSBhc3NpZ24gaXQgdG8gYW4gb2JqZWN0LCB0aGF0IG9iamVjdCBzaG91bGQgYmUgdXNlZCBhcyBhIGZ1bmN0aW9uLiBUbyBzZWUgd2hhdCB3ZSBtZWFuLCBleGVjdXRlIHRoZSBmb2xsb3dpbmcgdGhyZWUgbGluZXM6CgpgYGB7cn0KbmV3X2NvbCA8LSBjb2xvclJhbXBQYWxldHRlKGMoIiNGRkZGRkYiLCAiIzAwMDBGRiIpKQpuZXdfY29sKDQpICMgdGhlIG5ld2x5IGV4dHJhcG9sYXRlZCBjb2xvdXJzCm11bnNlbGw6OnBsb3RfaGV4KG5ld19jb2woNCkpICMgUXVpY2sgYW5kIGRpcnR5IHBsb3QKYGBgCgoKYG5ld19jb2woKWAgaXMgYSBmdW5jdGlvbiB0aGF0IHRha2VzIG9uZSBhcmd1bWVudDogdGhlIG51bWJlciBvZiBjb2xvdXJzIHlvdSB3YW50IHRvIGV4dHJhcG9sYXRlLiBZb3Ugd2FudCB0byB1c2UgbmljZXIgY29sb3Vycywgc28gd2UndmUgYXNzaWduZWQgdGhlIGVudGlyZSBgIkJsdWVzImAgY29sb3VyIHBhbGV0dGUgZnJvbSB0aGUgYFJDb2xvckJyZXdlcmAgcGFja2FnZSB0byB0aGUgY2hhcmFjdGVyIHZlY3RvciBgYmx1ZXNgLgoKIyMjIEluc3RydWN0aW9ucwoKLSBMaWtlIGluIHRoZSBleGFtcGxlIGNvZGUgYWJvdmUsIGNyZWF0ZSBhIG5ldyBmdW5jdGlvbiBjYWxsZWQgYGJsdWVfcmFuZ2VgIHRoYXQgdXNlcyBgY29sb3JSYW1wUGFsZXR0ZSgpYCB0byBleHRyYXBvbGF0ZSBvdmVyIGFsbCA5IHZhbHVlcyBvZiB0aGUgYGJsdWVzYCBjaGFyYWN0ZXIgdmVjdG9yLgotIFRha2UgdGhlIHBsb3QgY29kZSBmcm9tIHRoZSBsYXN0IGV4ZXJjaXNlIChwcm92aWRlZCksIGFuZCBjaGFuZ2UgYHNjYWxlX2ZpbGxfYnJld2VyKClgIHRvIGJlIGBzY2FsZV9maWxsX21hbnVhbCgpYC4gU2V0IHRoZSBhcmd1bWVudCBgdmFsdWVzID0gYmx1ZV9yYW5nZSgxMSlgIGluc2lkZSBgc2NhbGVfZmlsbF9tYW51YWwoKWAuCgpgYGB7cn0KIyBGaW5hbCBwbG90IG9mIGxhc3QgZXhlcmNpc2UKZ2dwbG90KFZvY2FiLCBhZXMoeCA9IGVkdWNhdGlvbiwgZmlsbCA9IHZvY2FidWxhcnkpKSArCiAgZ2VvbV9iYXIocG9zaXRpb24gPSAiZmlsbCIpICsKICBzY2FsZV9maWxsX2JyZXdlcigpCgojIERlZmluaXRpb24gb2YgYSBzZXQgb2YgYmx1ZSBjb2xvcnMKYmx1ZXMgPC0gYnJld2VyLnBhbCg5LCAiQmx1ZXMiKSAjIGZyb20gdGhlIFJDb2xvckJyZXdlciBwYWNrYWdlCgojIDEgLSBNYWtlIGEgY29sb3IgcmFuZ2UgdXNpbmcgY29sb3JSYW1wUGFsZXR0ZSgpIGFuZCB0aGUgc2V0IG9mIGJsdWVzCl9fXyA8LSBfX18oX19fKQoKIyAyIC0gVXNlIGJsdWVfcmFuZ2UgdG8gYWRqdXN0IHRoZSBjb2xvciBvZiB0aGUgYmFycywgdXNlIHNjYWxlX2ZpbGxfbWFudWFsKCkKCgoKYGBgCgoKIyMgT3ZlcmxhcHBpbmcgaGlzdG9ncmFtcyAoMikKCkFzIGEgbGFzdCBleGFtcGxlIG9mIGJhciBwbG90cywgeW91J2xsIHJldHVybiB0byBoaXN0b2dyYW1zICh3aGljaCB5b3Ugbm93IHNlZSBhcmUganVzdCBhIHNwZWNpYWwgdHlwZSBvZiBiYXIgcGxvdCkuIFlvdSBzYXcgYSBuaWNlIHRyaWNrIGluIGEgcHJldmlvdXMgZXhlcmNpc2Ugb2YgaG93IHRvIHNsaWdodGx5IG92ZXJsYXAgYmFycywgYnV0IG5vdyB5b3UnbGwgc2VlIGhvdyB0byBvdmVybGFwIHRoZW0gY29tcGxldGVseS4gVGhpcyB3b3VsZCBiZSBuaWNlIGZvciBtdWx0aXBsZSBoaXN0b2dyYW1zLCBhcyBsb25nIGFzIHRoZXJlIGFyZSBub3QgdG9vIG1hbnkgZGlmZmVyZW50IG92ZXJsYXBzIQoKWW91J2xsIG1ha2UgYSBoaXN0b2dyYW0gdXNpbmcgdGhlIGBtcGdgIHZhcmlhYmxlIGluIHRoZSBgbXRjYXJzYCBkYXRhIGZyYW1lLgoKIyMjIEluc3RydWN0aW9ucwoKLSBBIGJhc2ljIGhpc3RvZ3JhbSBwbG90IGlzIHByb3ZpZGVkLgotIFRha2UgcGxvdCAxIGFuZCBtYXAgYGFtYCBvbnRvIGBmaWxsYCB3aXRoaW4gdGhlIGBhZXMoKWAgZnVuY3Rpb24uIFRoZSBkZWZhdWx0IHBvc2l0aW9uIGlzIGAic3RhY2siYC4KLSBUYWtlIHBsb3QgMiBhbmQgYWRkIHRoZSBgcG9zaXRpb25gIGFyZ3VtZW50IHdpdGhpbiBgZ2VvbV9oaXN0b2dyYW0oKWAuIFNldCBpdCB0byBgImRvZGdlImAuCi0gVGFrZSBwbG90IDMgYW5kIGNoYW5nZSB0aGUgYHBvc2l0aW9uYCBhcmd1bWVudCB0byBgImZpbGwiYC4gSW4gdGhpcyBjYXNlLCBub25lIG9mIHRoZXNlIHBvc2l0aW9ucyByZWFsbHkgd29yayB3ZWxsLCBiZWNhdXNlIGl0J3MgZGlmZmljdWx0IHRvIGNvbXBhcmUgdGhlIGRpc3RyaWJ1dGlvbnMgZGlyZWN0bHkuCi0gVGFrZSBwbG90IDQgYW5kIGNoYW5nZSB0aGUgYHBvc2l0aW9uYCBhcmd1bWVudCB0byBgImlkZW50aXR5ImAgYW5kIHNldCBgYWxwaGEgPSAwLjRgLiBUaGlzIHByb2R1Y2VzIG92ZXJsYXBwaW5nIGJhcnMuCi0gVGFrZSBwbG90IDUgYW5kIGNoYW5nZSB0aGUgYWVzdGhldGljIG1hcHBpbmcuIE1hcCBgY3lsIG9udG8gZmlsbGAuCgoKYGBge3J9CiMgMSAtIEJhc2ljIGhpc3RvZ3JhbSBwbG90IGNvbW1hbmQKZ2dwbG90KG10Y2FycywgYWVzKG1wZykpICsKICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDEpCgojIDIgLSBQbG90IDEsIEV4cGFuZCBhZXN0aGV0aWNzOiBhbSBvbnRvIGZpbGwKCgoKIyAzIC0gUGxvdCAyLCBjaGFuZ2UgcG9zaXRpb24gPSAiZG9kZ2UiCgoKCiMgNCAtIFBsb3QgMywgY2hhbmdlIHBvc2l0aW9uID0gImZpbGwiCgoKCiMgNSAtIFBsb3QgNCwgcGx1cyBjaGFuZ2UgcG9zaXRpb24gPSAiaWRlbnRpdHkiIGFuZCBhbHBoYSA9IDAuNAoKCgojIDYgLSBQbG90IDUsIHBsdXMgY2hhbmdlIG1hcHBpbmc6IGN5bCBvbnRvIGZpbGwKCgpgYGAKCgojIyBMaW5lIHBsb3RzCgpJbiB0aGUgdmlkZW8geW91IHNhdyBob3cgdG8gbWFrZSBsaW5lIHBsb3RzIHVzaW5nIHRpbWUgc2VyaWVzIGRhdGEuIFRvIGV4cGxvcmUgdGhpcyB0b3BpYywgeW91J2xsIHVzZSB0aGUgYGVjb25vbWljc2AgZGF0YSBmcmFtZSwgd2hpY2ggY29udGFpbnMgdGltZSBzZXJpZXMgZm9yIHVuZW1wbG95bWVudCBhbmQgcG9wdWxhdGlvbiBzdGF0aXN0aWNzIGZyb20gdGhlIEZlZGVyYWwgUmVzZXJ2ZSBCYW5rIG9mIFN0LiBMb3VpcyBpbiB0aGUgVVMuIFRoZSBkYXRhIGlzIGNvbnRhaW5lZCBpbiB0aGUgYGdncGxvdDJgIHBhY2thZ2UuCgpUbyBiZWdpbiB3aXRoLCB5b3UgY2FuIGxvb2sgYXQgaG93IHRoZSBtZWRpYW4gdW5lbXBsb3ltZW50IHRpbWUgYW5kIHRoZSB1bmVtcGxveW1lbnQgcmF0ZSAodGhlIG51bWJlciBvZiB1bmVtcGxveWVkIHBlb3BsZSBhcyBhIHByb3BvcnRpb24gb2YgdGhlIHBvcHVsYXRpb24pIGNoYW5nZSBvdmVyIHRpbWUuCgpJbiB0aGUgbmV4dCBleGVyY2lzZXMsIHlvdSdsbCBleHBsb3JlIHRvIGhvdyBhZGQgZW1iZWxsaXNobWVudHMgdG8gdGhlIGxpbmUgcGxvdHMsIHN1Y2ggYXMgcmVjZXNzaW9uIHBlcmlvZHMuCgojIyMgSW5zdHJ1Y3Rpb25zCgotIFByaW50IG91dCB0aGUgYGhlYWQoKWAgb2YgdGhlIGBlY29ub21pY3NgIGRhdGEgZnJhbWUuCi0gVXNlIHRoZSBgZWNvbm9taWNzYCBkYXRhIGZyYW1lIHRvIHBsb3QgYGRhdGVgIG9uIHRoZSBgeGAgYXhpcyBhbmQgYHVuZW1wbG95YCBvbiB0aGUgYHlgIGF4aXMuIFVzZSBgZ2VvbV9saW5lKClgLgotIENvcHksIHBhc3RlIGFuZCBhZGp1c3QgdGhlIGNvZGUgZm9yIHRoZSBwcmV2aW91cyBpbnN0cnVjdGlvbjogaW5zdGVhZCBvZiBgdW5lbXBsb3lgLCBwbG90IGB1bmVtcGxveS9wb3BgIHRvIHJlcHJlc2VudCB0aGUgZnJhY3Rpb24gb2YgdGhlIHRvdGFsIHBvcHVsYXRpb24gdGhhdCBpcyB1bmVtcGxveWVkLgoKYGBge3J9CiMgUHJpbnQgb3V0IGhlYWQgb2YgZWNvbm9taWNzCgoKIyBQbG90IHVuZW1wbG95IGFzIGEgZnVuY3Rpb24gb2YgZGF0ZSB1c2luZyBhIGxpbmUgcGxvdApnZ3Bsb3QoX19fLCBhZXMoeCA9IF9fXywgeSA9IF9fXykpICsKCgojIEFkanVzdCBwbG90IHRvIHJlcHJlc2VudCB0aGUgZnJhY3Rpb24gb2YgdG90YWwgcG9wdWxhdGlvbiB0aGF0IGlzIHVuZW1wbG95ZWQKCmBgYAoKCiMjIFBlcmlvZHMgb2YgcmVjZXNzaW9uCgpCeSB0aGVtc2VsdmVzLCB0aW1lIHNlcmllcyBvZnRlbiBjb250YWluIGVub3VnaCB2YWx1YWJsZSBpbmZvcm1hdGlvbiwgYnV0IHlvdSBhbHdheXMgd2FudCB0byBtYXhpbWl6ZSB0aGUgbnVtYmVyIG9mIHZhcmlhYmxlcyB5b3UgY2FuIHNob3cgaW4gYSBwbG90LiBUaGlzIGFsbG93cyB5b3UgKGFuZCB5b3VyIHZpZXdlcnMpIHRvIGJlZ2luIG1ha2luZyBjb21wYXJpc29ucyBiZXR3ZWVuIHRob3NlIHZhcmlhYmxlcyB0aGF0IHdvdWxkIG90aGVyd2lzZSBiZSBkaWZmaWN1bHQgb3IgaW1wb3NzaWJsZS4KCkhlcmUsIHlvdSdsbCBhZGQgc2hhZGVkIHJlZ2lvbnMgdG8gdGhlIGJhY2tncm91bmQgdG8gaW5kaWNhdGUgcmVjZXNzaW9uIHBlcmlvZHMuIEhvdyBkbyB1bmVtcGxveW1lbnQgcmF0ZSBhbmQgcmVjZXNzaW9uIHBlcmlvZCBpbnRlcmFjdCB3aXRoIGVhY2ggb3RoZXI/CgpJbiBhZGRpdGlvbiB0byB0aGUgYGVjb25vbWljc2AgZGF0YXNldCBmcm9tIGJlZm9yZSwgeW91J2xsIGFsc28gdXNlIHRoZSBgcmVjZXNzYCBkYXRhc2V0IGZvciB0aGUgcGVyaW9kcyBvZiByZWNlc3Npb24uIFRoZSBgcmVjZXNzYCBkYXRhIGZyYW1lIGNvbnRhaW5zIDIgdmFyaWFibGVzOiB0aGUgYGJlZ2luYCBwZXJpb2Qgb2YgdGhlIHJlY2Vzc2lvbiBhbmQgdGhlIGBlbmRgLiBJdCdzIGFscmVhZHkgYXZhaWxhYmxlIGluIHlvdXIgd29ya3NwYWNlLgoKIyMjIEluc3RydWN0aW9ucwoKRXhwYW5kIHRoZSBjb21tYW5kIGZyb20gdGhlIHByZXZpb3VzIGV4ZXJjaXNlIHdpdGggYGdlb21fcmVjdCgpYC4gWW91IHdpbGwgdXNlIHRoaXMgZ2VvbSBsYXllciB0byBkcmF3IHJlY3RhbmdsZXMgYWNyb3NzIHRoZSByZWNlc3Npb24gcGVyaW9kcy4gVGhlcmUgYSBmZXcgcGl0ZmFsbHMgaGVyZToKCi0gYGdlb21fcmVjdCgpYCB1c2VzIHRoZSBgcmVjZXNzIGRhdGFzZXRgLCBzbyBwYXNzIHRoaXMgZGlyZWN0bHkgYXMgYGRhdGEgPSByZWNlc3NgIGluc2lkZSBgZ2VvbV9yZWN0KClgLgotIFRoZSBgZ2VvbV9yZWN0KClgIGNvbW1hbmQgc2hvdWxkbid0IGluaGVyaXQgYWVzdGhldGljcyBmcm9tIHRoZSBiYXNlIGBnZ3Bsb3QoKWAgY29tbWFuZCBpdCBiZWxvbmdzIHRvLiBJdCB3b3VsZCByZXN1bHQgaW4gYW4gZXJyb3IsIHNpbmNlIHlvdSdyZSB1c2luZyBhIGRpZmZlcmVudCBkYXRhc2V0IGFuZCBpdCBkb2Vzbid0IGNvbnRhaW4gYHVuZW1wbG95YCBvciBgcG9wYC4gVGhhdCdzIHdoeSB5b3Ugc2hvdWxkIHNwZWNpZnkgYGluaGVyaXQuYWVzID0gRkFMU0VgIGluIGBnZW9tX3JlY3QoKWAuCi0gYGdlb21fcmVjdCgpYCBuZWVkcyBmb3VyIGFlc3RoZXRpY3M6IGB4bWluYCwgYHhtYXhgLCBgeW1pbmAgYW5kIGB5bWF4YC4gVGhlc2Ugc2hvdWxkIGJlIHNldCB0byBgYmVnaW5gLCBgZW5kYCBhbmQgYC1JbmZgLCBgK0luZmAsIHJlc3BlY3RpdmVseS4gRGVmaW5lIHRoZW0gd2l0aGluIGBhZXMoKWAuCi0gVGhlIHJlY3RhbmdsZXMgeW91IGFkZCB3aWxsIGJlIGJsYWNrIGFuZCBvcGFxdWUgYnkgZGVmYXVsdC4gU2V0IGBmaWxsYCB0byBgInJlZCJgIGFuZCBgYWxwaGFgIHRvIGAwLjJgIHRvIGltcHJvdmUgdGhpcy4gRGVmaW5lIHRoZW0gb3V0c2lkZSBgYWVzKClgLgoKYGBge3J9CnJlY2VzcyA8LSBkYXRhLmZyYW1lKAogIGJlZ2luID0gYygiMTk2OS0xMi0wMSIsIjE5NzMtMTEtMDEiLCIxOTgwLTAxLTAxIiwiMTk4MS0wNy0wMSIsIjE5OTAtMDctMDEiLCIyMDAxLTAzLTAxIiksIAogIGVuZCA9IGMoIjE5NzAtMTEtMDEiLCIxOTc1LTAzLTAxIiwiMTk4MC0wNy0wMSIsIjE5ODItMTEtMDEiLCIxOTkxLTAzLTAxIiwiMjAwMS0xMS0wMSIpLAogIHN0cmluZ3NBc0ZhY3RvcnMgPSBGCiAgKQoKbGlicmFyeShsdWJyaWRhdGUpCnJlY2VzcyRiZWdpbiA8LSB5bWQgKHJlY2VzcyRiZWdpbikKcmVjZXNzJGVuZCA8LSB5bWQgKHJlY2VzcyRlbmQpCgojIEJhc2ljIGxpbmUgcGxvdApnZ3Bsb3QoZWNvbm9taWNzLCBhZXMoeCA9IGRhdGUsIHkgPSB1bmVtcGxveS9wb3ApKSArCiAgZ2VvbV9saW5lKCkKCiMgRXhwYW5kIHRoZSBmb2xsb3dpbmcgY29tbWFuZCB3aXRoIGdlb21fcmVjdCgpIHRvIGRyYXcgdGhlIHJlY2VzcyBwZXJpb2RzCmdncGxvdChlY29ub21pY3MsIGFlcyh4ID0gZGF0ZSwgeSA9IHVuZW1wbG95L3BvcCkpICsKICBfX18oX19fID0gX19fLAogICAgICAgICBhZXMoX19fID0gX19fLCBfX18gPSBfX18sIF9fXyA9IF9fXywgX19fID0gX19fKSwKICAgICAgICAgX19fID0gRkFMU0UsIF9fXyA9ICJyZWQiLCBfX18gPSAwLjIpICsKICBnZW9tX2xpbmUoKQoKYGBgCgoK