3.1 Introduction

This chapter will teach you how to visualise your data using gplot2. R has several systems for making graphs, but gplot2 is one of the most elegant and most versatile. ggplot2 implements the grammar of graphics, a coherent system for describing and building graphs. With gplot2, you can do more faster by learning one system and applying it in many places.

3.1.1 Prerequisites

This chapter focusses on ggplot2, one of the core members of the tidyverse.

3.2 First steps

Let’s use our first graph to answer a question: Do cars with big engines use more fuel than cars with small engines? You probably already have an answer, but try to make your answer precise. What does the relationship between engine size and fuel efficiency look like? Is it positive? Negative? Linear? Nonlinear?

3.2.1 The mpg data frame

You can test your answer with the mpg data frame found in ggplot2 (aka ggplot2::mpg).

To learn more about mpg, open it’s help page by running

rr ?mpg

3.2.2 Creating a ggplot

To plot mpg, run this code to put displ on the x-axis and hwy on the y-axis.

rr ## Ordinary method (not using ggplot) plot(mpg\(displ,mpg\)hwy)

rr ## Using ggplot() ggplot(mpg) + geom_point(mapping=aes(displ,hwy))

As you can see, ggplots are much nicer.

The plot shows a negative relationship between engine size (displ = displacement) and fuel efficiency (hwy = fuel economy on the highway). In other words, cars with big engines use more fuel.

With ggplot2, you begin a plot with the function ggplot(). The function geom_point() adds a layer of points to your plot, which creates a scatterplot. ggplot2 comes with many geom functions that each add a different type of layer to a plot. You’ll learn a whole bunch of them throughout this chapter.

Each geom function in ggplot2 takes a mapping argument. This defines how variables in your dataset are mapped to visual properties. The mapping argument is always paired with aes(), and the x and y arguments of aes() specify which variables to map to the x and y axes. ggplot2 looks for the mapped variables in the data argument, in this case, mpg.

3.2.3 A graphing template

Let’s turn this code into a reusable template for making graphs with ggplot2. To make a graph, replace the bracketed sections in the code below with a dataset, a geom function, or a collection of mappings.

rr ggplot(data = ) +

Error: unexpected '<' in \ggplot(data = <\

3.2.4 Exercises

  1. Run ggplot(data = mpg). What do you see?

rr ggplot(data=mpg)

Running ggplot(data=mpg) just produces a large grey rectangle. This is because we haven’t actually given it any points to plot or variables to map.

  1. How many rows are in mpg? How many columns?

rr dim(mpg)

[1] 234  11

There are 234 rows and 11 columns.

  1. What does the drv variable describe? Read the help for ?mpg to find out.

rr ?mpg

drv - the type of drive train, where f = front-wheel drive, r = rear wheel drive, 4 = 4wd

  1. Make a scatterplot of hwy vs cyl

rr ggplot(mpg) + geom_point(mapping = aes(cyl,hwy))

As we can see from the above scatterplot of hwy vs cyl, vehicles with more cylinders have lower fuel economy on the highway.

  1. What happens if you make a scatterplot of class vs drv? Why is the plot not useful?

rr ggplot(mpg) + geom_point(mapping = aes(class,drv))

If you make a scatterplot of class vs drv you get a graph that shows the type of drive train for the vehicle classes in the dataset. However, it does not plot the distribution of these, only tells you that the dataset had at least one instance of a “2seater with rear wheel drive” or “a pickup with 4-wheel drive”. It does not provide any insight into the data. A scatterplot most likely is not the best way to display this data.

3.3 Aesthetic mappings

You can add a third variable, like class, to a two dimensional scatterplot by mapping it to an aesthetic. An aesthetic is a visual property of the objects in your plot. Aesthetics include things like the size, the shape, or the color of your points. You can display a point (like the one below) in different ways by changing the values of its aesthetic properties. Since we already use the word “value” to describe data, let’s use the word “level” to describe aesthetic properties.

You can convey informationg about your data by mapping the aesthetics in your plot to the variables in your dataset. For example, you can map the colors of your points to the class variable to reveal the class of each car.

rr ggplot(mpg) + geom_point(mapping = aes(x = displ,y = hwy, color = class))

To map an aesthetic to a variable, associate the name of the aesthetic to the name of the variable inside aes(). ggplot2 will automatically assign a unique level of the aesthetic (here a unique color) to each unique level of the variable, a process known as scaling. ggplot2 will also add a legend that explains which levels correspond to which values.

The colors reveal that many of the unusual points are two-seater cars. These cars don’t seem like hybrids, and are, in fact, sports cars! Sports cars have large engines like SUVs and pickup trucks, but small bodies like midsize and compact cars, which improves their gas mileage. In hindsight, these cars were unlikely to be hybrids since they have large engines.

In the above example, we mapped class to the color aesthetic, but we could have mapped class to the size aesthetic in the same way. In this case, the exact size of each point would reveal its class affiliation. We get a warning here, because mapping an unordered variable (class) to an ordered aesthetic (size) is not a good idea.

rr ggplot(mpg) + geom_point(mapping = aes(displ,hwy,size=class))

Or we could have mapped class to the alpha aesthetic, which controls the transparency of the points, or to the shape aesthetic, which controls the shape of the points.

rr # Left ggplot(data = mpg) + geom_point(mapping = aes(x = displ, y = hwy, alpha = class))

rr

Right

ggplot(mpg) + geom_point(mapping = aes(x = displ, y = hwy)) + facet_grid(year ~ cty)

If you facet on a continuous variable, the plot will create facets according to each level of the continuous variable (categorize them).

  1. What do the empty cells in plot with facet_grid(drv~cyl) mean? How do they relate to this plot?

rr # Left ggplot(mpg) + geom_point(mapping = aes(x = displ, y = hwy)) + facet_grid(drv ~ cyl)

rr

Right

ggplot(mpg, mapping = aes(x = drv, y = cyl)) + geom_point()

The facet grid compartmentalizes data according to their drive type and number of cylinders. The empty facets indicate categories which have no data points. For example, there were no “4-cylinder rear-wheel drive” vehicles.

Geom point produces a scatterplot of the data and works best with two continuous variables. Drv is a categorical variable and although cyl is labeled as an integer and we previously said it was a continuous variable - it really should be treated as a categorical (nominal) variable as it only takes on five possible values and there is no meaningful zero (no automobile has 0 cylinders). Thus, the plot is basically simply indicating whether that combination of number of cylinders and drive type is represented in the data (similar to our first graph).

  1. What plots does the following code make? What does . do?

rr # Left ggplot(data = mpg) + geom_point(mapping = aes(x = displ, y = hwy)) + facet_grid(drv ~ .)

rr

Right

ggplot(mpg) + geom_point(mapping = aes(x = displ, y = hwy)) + facet_grid(. ~ cyl)

  1. Take the first faceted plot in this section:

rr # Left ggplot(data = mpg) + geom_point(mapping = aes(x = displ, y = hwy)) + facet_wrap(~ class, nrow = 2)

rr

Right

ggplot(data = mpg, mapping = aes(x = displ, y = hwy, color = class)) + geom_point()

The advantage of faceting as opposed to using the color aesthetic is that it separates out the data and helps one understand the relationship between the two mapping variables within the context of its respective class. The disadvantage is that it makes it more difficult to see the overarching trend in the data.

Another advantage is that it makes it easier to understand the relationship between class and vehicle class. Above, it is very noticeable that 2seaters generally get about 25mpg on the hwy and have displacements > 5 while pickups get <= 20 mpg on the highway and have displacements between 2-6.

Faceting is recommended when the number of points and categories increase. As the number of categories increase, differentiating between colors will become increasingly difficult when using a color aesthetic. Furthermore, when there are greater points, there is likely to be more overlap. Faceting will pull these values out and separate the data better.

. serves as a placeholder, indicating two leave that facet undefined (to not facet by anything in that location).

  1. Read ?facet_wrap. What does nrow do? What does ncol do? What other options control the layout of the individual panels? Why doesn’t facet_grid() have nrow and ncol arguments?

rr ?facet_wrap

nrows indicates how many rows in the faceted wrap, and ncols indicates how many columns.

  1. When using facet_grid() you should usually put the variable with more unique levels in the columns. Why?

rr # Left ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) + geom_point() + facet_grid(fl ~ class)

rr

Right

ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) + geom_point() + facet_grid(class ~ fl)

As you can see from the above two examples, it is better to put the variable with more unique levels in the columns because when they are laid out vertically the labels get “squished”.

3.6 Geometric objects

A geom is the geometrical object that a plot uses to represent data. People often descripe plots by the type of geom that the plot uses. For example, bar charts use bar geoms, line charts use line geoms, boxplots use boxplot geoms, and so on. Scatterplots break the trend, they use the point geom.

rr # Left ggplot(mpg, mapping = aes(x = displ, y = hwy)) + geom_point()

rr

Right

ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) + geom_smooth()

Every geom function in ggplot2 takes a mapping argument. However, not every aesthetic works with every geom. You could set the shape of a point, but you couldn’t set the “shape” of a line. On the other hand, you could set the linetype of a line. geom_smooth() will draw a different line, with a different linetype, for each unique value of the variable that you map to linetype.

rr ggplot(data = mpg) + geom_smooth(mapping = aes(x = displ, y = hwy, linetype = drv))

Here geom_smooth() separates the cars into three lines based on their drv value, which describes a car’s drivetrain.

rr ggplot(data = mpg, mapping = aes(x = displ, y = hwy, color = drv, linetype = drv)) + geom_point() + geom_smooth()

The above plot shows the smooth lines layered on top of the scattered plots and both the lines and points colored by their respective drive type.

ggplo2 provides over 40 geoms, and extension packages provide een more (see https://exts.ggplot2.tidyverse.org/gallery/ for a samping). The best way to get a comprehensive overview is the ggplot2 cheatsheet, which you can find at https://rstudio.com/resources/cheatsheets. To learn more about any single geom, use help: ?geom_smooth.

Many geoms, like geom_smooth(), use a single geometric object to display multiple rows of data. For these geoms, you can set the group aesthetic to a categorical variable to draw multiple objects. ggplot2 will draw a separate object for each unique value of the grouping variable. In practice, ggplot2 will automatically group the data for these geoms whenever you map an aesthetic to a discrete variable (as in the linetype example). It is convenient to rely on this feature because the group aesthetic by itself does not add a legend or distinguishing features to the geoms.

rr # Left ggplot(data = mpg) + geom_smooth(mapping = aes(x = displ, y = hwy))

rr

Center

ggplot(data = mpg) + geom_smooth(mapping = aes(x = displ, y = hwy, group = drv))

rr

Right

ggplot(data = mpg) + geom_smooth(mapping = aes(x = displ, y = hwy, color = drv), show.legend = FALSE)

To display multiple geoms in the same plot, add multiple geom functions to ggplot():

rr ggplot(data = mpg) + geom_point(mapping = aes(x = displ, y = hwy, color = drv)) + geom_smooth(mapping = aes(x = displ, y = hwy, group = drv, linetype = drv))

This, however, introduces some duplication in our code. Imagine if you wanted to change the y-axis to display cty instead of hwy. You’d need to change the variable in two places, and you might forget to update one. You can avoid this type of repetition by passing a set of mappings to ggplot(). ggplot2 will treat these mappings as global mappings that apply to each geom in the graph. In other words, this code will produce the same plot as the previous code:

rr ggplot(data = mpg, aes(x = displ, y = cty)) + geom_point() + geom_smooth()

If you place mappings in a geom function, ggplot2 will treat them as local mappings for the layer. It will use these mappings to extend or overwrite the global mappings for that layer only. This makes it possible to display different aesethetics in different layers.

rr ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) + geom_point(mapping = aes(color = drv)) + geom_smooth(mapping = aes(group = drv, linetype = drv))

rr ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) + geom_point(mapping = aes(color = class)) + geom_smooth()

You can use the same idea to specify different data for each layer. Here, our smooth line displays just a subset of the mpg dataset, the subcompact cars. The local data argument in geom_smooth() overrides the global data argument in ggplot() for that layer only.

rr ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) + geom_point(mapping = aes(color = class)) + geom_smooth(data = filter(mpg, class == ), se = FALSE)

(You’ll learn how filter() works in the chapter on data transformations: for now, just know that this command selects only the subcompact cars.)

3.6.1 Exercises

  1. What geom would you use to draw a line chat? A boxplot? A histogram? An area chart?

rr # Line ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) + geom_line()

rr

Boxplot

ggplot(data = mpg, mapping = aes(x = class , y = hwy)) + geom_boxplot()

rr

Histogram

ggplot(data = mpg, mapping = aes(x = hwy)) + geom_histogram()

rr

Area chart

ggplot(data = mpg, mapping = aes(x = hwy, y = displ)) + geom_area()

The above graphs show how to make the different charts. Note that the mapping aesthetics don’t exactly make sense for each graph. For example, the line chart would make more sense with x as a continuous time variable and y being something such as “avg mileage on the hwy”.

  1. Run this code in your head and predict what the output will look like. Then, run the code in R and check your predications.

rr ggplot(data = mpg, mapping = aes(x = displ, y = hwy, color = drv)) + geom_point() + geom_smooth(se = FALSE)

The above code will produce a scatterplot of displacement (on the x-axis) and hwy (on the y-axis). Points will be distinguished according to their respective drv types via color assignment and a y ~ x lines will be drawn through the points (the line that minimizes the residiuals), but the smoothing effect (the shaded area outlining the regression line) will be off.

I predicted only one line, when I should have predicted a line for each drv type. This is because the aesthetic of color has been passed down to all of the geom functions.

  1. What does show.legend = FALSE do? What happens if you remove it? Why do you think I used it earlier in this chapter?

Show.legend defaults to showing the legend of the aesthetic assigned in the mapping argument. For example, in the previous question, the legend shows the color assignment. If you indicate show.legend = FALSE then the legend will be turned off. Below, we must specify the legend to be FALSE for both geoms.

It was likely introduced because we will be working with it later.

rr ggplot(data = mpg, mapping = aes(x = displ, y = hwy, color = drv)) + geom_point(show.legend = FALSE) + geom_smooth(se = FALSE, show.legend = FALSE)

rr ggplot(data = mpg, mapping = aes(x = displ, y = hwy, color = drv)) + geom_point() + geom_smooth(se = FALSE)

  1. what does the se argument to geom_smooth() do?

The se argument provides (if TRUE) the standard error intervals of the y ~ x lines.

  1. Will these two graphs look different? Why/why not?

rr # Left ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) + geom_point() + geom_smooth()

rr

Right

ggplot() + geom_point(data = mpg, mapping = aes(x = displ, y = hwy)) + geom_smooth(data = mpg, mapping = aes(x = displ, y = hwy))

They shouldn’t look different no. The first one is just more efficient because we don’t have to specify the data source or the x and y mapping components twice. In either case, ggplot just produces the coordinates and the geom functions produce the respective geom aesthetics of the data.

  1. Recreate the R code necessary to generate the following graphs.

rr # Top Left ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) + geom_point() + geom_smooth(se = FALSE)

rr

Top Right

ggplot(data = mpg, mapping = aes(x = displ, y = hwy, line = drv)) + geom_point() + geom_smooth(se = FALSE)

rr

Middle Left

ggplot(data = mpg, mapping = aes(x = displ, y = hwy, color = drv)) + geom_point() + geom_smooth(se = FALSE)

rr

Middle Right

ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) + geom_point(mapping = aes(color = drv)) + geom_smooth(se = FALSE)

rr

Bottom Left

ggplot(data = mpg, mapping = aes(x = displ, y = hwy, linetype = drv)) + geom_point(mapping = aes(color = drv)) + geom_smooth(se = FALSE)

rr

Bottom Right

ggplot(data = mpg, mapping = aes(x = displ, y = hwy)) + geom_point(color = , size = 4) + geom_point(aes(color = drv))

The final plot is tricky, but it basically works by plotting the points twice, but plotting the smaller colored points on top of the larger white points (which effectively become the stroke).

3.7 Statistical Transformations

Next, let’s take a look at a bar chart. Bar charts seem simple, but they are interesting because they reveal something subtle about plots. Consider a basic bar chart, as drawn with geom_bar(). The following chart displays the total number of diamonds in the diamonds dataset, grouped by cut. The diamonds dataset comes in ggplot2 and contains information about ~ 54,000 diamonds, including the price, carat, color, and cut of each diamond. The chart shows that more diamonds are available with high quality cuts than with low quality cuts.

rr ggplot(data = diamonds) + geom_bar(mapping = aes(x = cut))

On the x-axis, the chart displays cut, a variable from diamonds. On the y-axis, it displays count, but count is not a variable in diamonds! Where does it come from? Many graphs, like scatterplots, plot the raw values of your dataset. Other graphs, like bar charcts, calculate new values to plot:

  • bar charts, histograms, and frequency polygons bin your data and then plot bin counts, the number of points that fall in each bin.
  • smoothers fit a model to your data and then plot predictions from the model.
  • boxplots compute a robust summary of the distribution and ten display a specially formatted box.

The algorithm used to calculate new values for a graph is called a stat, short for statistical transformation.

Essentially,

  1. geom_bar() begins with the diamonds data set.
  2. geom_bar() transforms the data with the “count” stat, which returns a data set of cut values and counts.
  3. geom_bar() uses the transformed data to build the plot. cut is mapped to the xa xis, count is mapped to the y axis.

You can learn which stat a geom uses by inspecting the default value for the stat argument. For example, ?geom_bar shows that the default value for stat is “count”, which means that geom_bar() uses stat_count(). stat_count() is documented on the same page as geom_bar(), and if you scroll down you can find a section called “Computed variables”. That describes how it computes two new variables: count and prop.

You can generally use geoms and stats interchangeably. For example, you can recreate the previous plot using stat_count() instead of geom_bar():

rr ggplot(data = diamonds) + stat_count(mapping = aes(x = cut))

This works because every geom has a default stat; and every stat has a default geom. This means that you can typically use geoms without worrying about the underlying statistical transformation. There are three reasons you might need to use a stat explicitly:

  1. You might want to override the default stat. In the code below, I change the stat of geom_bar() from count (the default) to identity. This lets me map the height of the bars to the raw values of a y variable. Unfortunately when people talk about bar charts casually, they might be referring to this type of bar chart, where the height of the bar is already present in the data, or the previous bar chart where the height of the bar is generated by counting rows.

rr demo <- tribble( ~cut, ~freq, , 1610, , 4906, Good, 12082, , 13791, , 21551 )

ggplot(data = demo) + geom_bar(mapping = aes(x = cut, y = freq), stat = )

  1. You might want to override the default mapping from transformed variables to aesthetics. For example, you might want to display a bar chart of proportion, rather than count:

rr ggplot(data = diamonds) + geom_bar(mapping = aes(x = cut, y = stat(prop), group = 1))

To find the variables computed by the stat, look for the help section titled “computed variables”.

  1. You might want to draw greater attention to the statistical tranformation in your code. For example, you might use stat_summary(), which summarises the y values for each unique x value, to draw attention to the summary that you’re computing:

rr ggplot(data = diamonds) + stat_summary(mapping = aes(x = cut, y = depth), fun.min = min, fun.max = max, fun = median )

ggplot2 provides over 20 stats for you to use. Each stat is a function, so you can get help in the usual way, e.g. ?stat_bin. FTo see a complete list of stats, try the ggplot2 cheatsheet.

3.7.1 Exercises

  1. What is the default geom associated with stat_summary()? How could you rewite previous plot to use that geom function instead of the stat function?

rr ?stat_summary ggplot(data = diamonds) + geom_pointrange(mapping = aes(x = cut, y = depth), stat =
)

The default geom associated with stat_summary is “pointrange”. A message pops up indicating that no summary function has been supplied so the mean standard errors are provided as the summary function. We can include our y functions to provide the summary and recreate the earlier graph where we used stat_summary.

rr ggplot(data = diamonds) + geom_pointrange(mapping = aes(x = cut, y = depth), stat = , fun.min = min, fun.max = max, fun = median)

  1. What does geom_col() do? How is it different to geom_bar()?

geom_col() differs from geom_bar() in that geom_col assumes the actual values of the data. The default stat for geom_col() is identity which means that it performs no transformation on the data, rather it simply pulls the value associated with the corresponding x-value and plots it accordingly.

Inversely, geom_bar() has a default stat of count meaning no y-mapping is required, rather all of the x’s will be counted and plotted accordingly.

rr # Geom_bar ggplot(data = diamonds) + geom_bar(mapping = aes(x = cut))

Geom_col

ggplot(data = demo) + geom_col(mapping = aes(x = cut, y = freq))

  1. Most geoms and stats come in pairs that are almost always used in concert. Read through the documentation and make a list of all the pairs. What do they have in common?

(skipped for now)

  1. What variables does stat_smooth() compute? What paramaters control its behavior?

Stat_smooth computes:

These are found in the “Computed variables” section of ?stat_smooth.

Position, method, formula, se, na.rm, orientation, n, span, fullrange, level all control its behavior.

rr # Geom_smooth ggplot(data = diamonds) + geom_smooth(mapping = aes(x = carat, y = depth))

Stat_smooth

ggplot(data = diamonds) + stat_smooth(mapping = aes(x = carat, y = depth))

  1. In our proportion bar chart, we need to set group = 1. Why? In other words what is the problem with these two graphs?

The problem with the two graphs is that the mapping aesthetic has not been told as a proportion of what. For example, in the second bar plot, since the paramater has not been assigned that the data should be mapped as a proportion of the total count of cuts, it simply assumes that each respective level of cut is the guiding proportion.

With respect to the third bar plot, it is treating each level as its own equally sized proportion across all of the cuts. Below cleans up the data.

rr # Original ggplot(data = diamonds) + geom_bar(mapping = aes(x = cut, y = stat(prop), group = 1))

rr

ggplot(data = diamonds) + geom_bar(mapping = aes(x = cut, y = after_stat(prop), group = 1))

rr

ggplot(data = diamonds) + geom_bar(mapping = aes(x = cut, y = after_stat(count/sum(count)), fill = color))

3.8 Position adjustments

There’s one more piece of magic associated with bar chats. You can color a bar chart using either the color aesthetic, or, more usefully, fill:

rr ggplot(data = diamonds) + geom_bar(mapping = aes(x = cut, color = cut))

rr ggplot(data = diamonds) + geom_bar(mapping = aes(x = cut, fill = cut))

Note what happens if you map the fill aesthetic to another variable, like clarity: the bars are automaticaly stacked. Each colored rectangle represents a combination of cut and clarity.

rr ggplot(data = diamonds) + geom_bar(mapping = aes(x = cut, fill = clarity))

The stacking is performed automatically by the position adjustment specified by the position argument. If you don’t want a stacked bar chart, you can use one of three other options:

“identity”, “dodge” or “fill”.

  • position = “identity” will place each object exactly where it falls in the context of the graph. This is not very useful for bars, because it overlaps them. To see that overlapping we either need to make the bars slightly transparent by setting alpha to a small value, or completely transparent by setting fill = NA.

rr ggplot(data = diamonds, mapping = aes(x = cut, fill = clarity)) + geom_bar(alpha = 1/5, position = )

rr ggplot(data = diamonds, mapping = aes(x = cut, color = clarity)) + geom_bar(position = ,fill = NA)

The identity position adjustment is more useful for 2d geoms, like points, where it is the default.

  • position = “fill” works like stacking, but makes each set of stacked bars the same height. This makes it easier to compare proportions across groups.

rr ggplot(data = diamonds) + geom_bar(mapping = aes(x = cut, fill = clarity), position = )

  • position = “dodge” places overlapping objects directly beside one another. This makes it easier to compare individual values.

rr ggplot(data = diamonds) + geom_bar(mapping = aes(x = cut, color = clarity), position = , fill = NA)

rr ggplot(data = diamonds) + geom_bar(mapping = aes(x = cut, fill = clarity), position = )

There’s one other type of adjustment that’s not useful for bar charts, but it can be very useful for scatterplots. Recall our first scatterplot. Did you notice that the plot displays only 126 points, even though there are 234 observations in the dataset?

rr ggplot(data = mpg) + geom_point(mapping = aes(x = displ, y = hwy))

The values of hwy and displ are rounded so the points appear on a grid and many points overlap each other. The problem is known as overplotting. This arrangment makes it hard to see where the mass of the data is. Are the data points spread equally throughout the graph, or is there one special combination of hwy and displ that contains 109 values?

You can avoid this gridding by setting the position adjustment to “jitter”. position = “jitter” adds a small amount of random noise to each point. This spreads the points out because no two points are likely to receive the same amount of random noise.

rr ggplot(data = mpg) + geom_point(mapping = aes(x = displ, y = hwy), position = )

Adding randomness seems like a strange way to improve your plot, but while it makes your graph less accurate at small scales, it makes your graph more revealing at large scales. Because this is such a useful operation, ggplot2 comes with a shorthand for geom_point(position = “jitter”) : geom_jitter().

ggplot(data = mpg) +
  geom_jitter(mapping = aes(x = displ, y = hwy))

To learn more about a position adjustment, look up the help page associated with each adjustment: ?position_dodge, ?position_fill, ?position_identity, ?position_jitter, and ?position_stack.

3.8.1 Exercises

  1. What is the problem with this plot? How could you improve it?
ggplot(data = mpg, mapping = aes(x = cty, y = hwy)) +
  geom_point()

The problem with this plot is that overplotting is occuring. The values of hwy and cty are rounded so many points are stacked on top of each other making it difficult to see the true shape of the data. We can jitter the plot to add a little randomness and add the values.

ggplot(data = mpg) +
  geom_jitter(mapping = aes(x = cty, y = hwy))
  1. What parameters to geom_jitter() control the amount of jittering?
?geom_jitter

width and height control the amount of jittering.

  1. Compare and contrast geom_jitter() with geom_count().
?geom_jitter
?geom_count
ggplot(data = mpg) +
  geom_jitter(mapping = aes(x = cty, y = displ))
ggplot(data = mpg) +
  geom_count(mapping = aes(x = cty, y = displ))

Both geom_jitter and __geom__count__ are used to address the issue of overlapping in point (scatter) plots. However, they address the issue in different ways. Jitter adds a little bit of randomness to each point to further scatter the plot (basically “declump” them). Whereas geom_count essentially assigns proportions to a location and maps the count to point area. It basically creates bigger points in areas where points are more closely clustered.

  1. What’s the default position adjustment for geom_boxplot()? Create a visualisation of the mpg dataset that demonstrates it.
?geom_boxplot

The default position adjustment for geom_boxplot() is dodge2.

ggplot(data = mpg) +
  geom_boxplot(mapping = aes(x = drv, y = hwy, color = class))

3.9 Coordinate systems

Coordinate systems are probably the most complicated part of ggplot2. The default coordinate system is the Cartesian coordinate system where the x and y positions act independently to determine the location of each point. There are a number of other coordinate systems that are occasionally helpful.

  • coord_flip() switches the x and y axes. This is useful (for example), if you want horizontal boxplots. It’s also useful for long labels: it’s hard to get them to fit without overlapping on the x-axis.
ggplot(data = mpg, mapping = aes(x = class, y = hwy)) +
  geom_boxplot()
ggplot(data = mpg, mapping = aes(x = class,  y = hwy)) +
  geom_boxplot() +
  coord_flip()
  • coord_quickmap() sets the aspect ratio correctly for maps. This is very important if you’re plotting spatial data with ggplot2 (which unfortunately we don’t have the space to cover in this book).
nz <- map_data("nz")

ggplot(nz, aes(long, lat, group = group)) +
  geom_polygon(fill = "white", color = "black")

ggplot(nz, aes(long, lat, group = group)) +
  geom_polygon(fill = "white", color = "black") +
  coord_quickmap()
  • coord_polar() uses polar coordinates. Polar coordinates reveal an interesting connection between a bar chart and a Coxcomb chart.
bar <- ggplot(data = diamonds) +
  geom_bar(
    mapping = aes(x = cut, fill = cut),
    show.legend = FALSE,
    width = 1
  ) +
  theme(aspect.ratio = 1) +
  labs(x = NULL, y = NULL)

bar + coord_flip()
bar + coord_polar()

3.9.1 Exercises

  1. Turn a stacked bar chart into a pie chart using coord_polar().
ggplot(data = diamonds) +
  geom_bar(mapping = aes(x = cut, fill = cut)) +
  coord_polar()
  1. What does labs() do? Read the documentation.
?labs()

labs() modifies axes, legends, and plot labels.

  1. What’s the difference between coord_quickmap() and coord_map()?

(skip)

  1. What does the plot below tell you about the relationship between city and highway mpg? Why is coord_fixed() important? What does geom_abline() do?
ggplot(data = mpg, mapping = aes(x = cty, y = hwy)) +
  geom_point() +
  geom_abline()
ggplot(data = mpg, mapping = aes(x = cty, y = hwy)) +
  geom_point() +
  geom_abline() +
  coord_fixed()

The plot above tells us that there is a positive linear relationship between city and highway miles per gallon. As either of the two variables increases, the other increases at a constant rate with it.

?geom_abline

geom_abline adds a reference line.

?coord_fixed

coord_fixed is important because it assigns a fixed scale to the coordinate systems specified by the ration between the physical representation of data units on the axes. The ratio represents the number of units on the y-axis equivalent to one unit on the x-axis.

It thus provides an easier interpretation of the slope of the coefficient of the abline or more specifically the relationship between cty and hwy miles per gallon.

LS0tCnRpdGxlOiAiQ2ggMyAtIERhdGEgdmlzdWFsaXNhdGlvbiIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyMjIDMuMSBJbnRyb2R1Y3Rpb24KClRoaXMgY2hhcHRlciB3aWxsIHRlYWNoIHlvdSBob3cgdG8gdmlzdWFsaXNlIHlvdXIgZGF0YSB1c2luZyBfX2dwbG90Ml9fLiBSIGhhcyBzZXZlcmFsIHN5c3RlbXMgZm9yIG1ha2luZyBncmFwaHMsIGJ1dCBfX2dwbG90Ml9fIGlzIG9uZSBvZiB0aGUgbW9zdCBlbGVnYW50IGFuZCBtb3N0IHZlcnNhdGlsZS4gX19nZ3Bsb3QyX18gaW1wbGVtZW50cyB0aGUgX19ncmFtbWFyIG9mIGdyYXBoaWNzX18sIGEgY29oZXJlbnQgc3lzdGVtIGZvciBkZXNjcmliaW5nIGFuZCBidWlsZGluZyBncmFwaHMuIFdpdGggX19ncGxvdDJfXywgeW91IGNhbiBkbyBtb3JlIGZhc3RlciBieSBsZWFybmluZyBvbmUgc3lzdGVtIGFuZCBhcHBseWluZyBpdCBpbiBtYW55IHBsYWNlcy4KCiMjIyMgMy4xLjEgUHJlcmVxdWlzaXRlcwoKVGhpcyBjaGFwdGVyIGZvY3Vzc2VzIG9uIGdncGxvdDIsIG9uZSBvZiB0aGUgY29yZSBtZW1iZXJzIG9mIHRoZSB0aWR5dmVyc2UuCgojIyMjIDMuMiBGaXJzdCBzdGVwcwoKTGV0J3MgdXNlIG91ciBmaXJzdCBncmFwaCB0byBhbnN3ZXIgYSBxdWVzdGlvbjogRG8gY2FycyB3aXRoIGJpZyBlbmdpbmVzIHVzZSBtb3JlIGZ1ZWwgdGhhbiBjYXJzIHdpdGggc21hbGwgZW5naW5lcz8gWW91IHByb2JhYmx5IGFscmVhZHkgaGF2ZSBhbiBhbnN3ZXIsIGJ1dCB0cnkgdG8gbWFrZSB5b3VyIGFuc3dlciBwcmVjaXNlLiBXaGF0IGRvZXMgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGVuZ2luZSBzaXplIGFuZCBmdWVsIGVmZmljaWVuY3kgbG9vayBsaWtlPyBJcyBpdCBwb3NpdGl2ZT8gTmVnYXRpdmU/IExpbmVhcj8gTm9ubGluZWFyPwoKIyMjIyAzLjIuMSBUaGUgKm1wZyogZGF0YSBmcmFtZQoKWW91IGNhbiB0ZXN0IHlvdXIgYW5zd2VyIHdpdGggdGhlICptcGcqIF9fZGF0YSBmcmFtZV9fIGZvdW5kIGluIGdncGxvdDIgKGFrYSBnZ3Bsb3QyOjptcGcpLiAKClRvIGxlYXJuIG1vcmUgYWJvdXQgbXBnLCBvcGVuIGl0J3MgaGVscCBwYWdlIGJ5IHJ1bm5pbmcKCmBgYHtyfQo/bXBnCmBgYAoKIyMjIyAzLjIuMiBDcmVhdGluZyBhIGdncGxvdAoKVG8gcGxvdCBfX21wZ19fLCBydW4gdGhpcyBjb2RlIHRvIHB1dCBfX2Rpc3BsX18gb24gdGhlIHgtYXhpcyBhbmQgX19od3lfXyBvbiB0aGUgeS1heGlzLgoKYGBge3J9CiMjIE9yZGluYXJ5IG1ldGhvZCAobm90IHVzaW5nIGdncGxvdCkKcGxvdChtcGckZGlzcGwsbXBnJGh3eSkKYGBgCgpgYGB7cn0KIyMgVXNpbmcgZ2dwbG90KCkKZ2dwbG90KG1wZykgKwpnZW9tX3BvaW50KG1hcHBpbmc9YWVzKGRpc3BsLGh3eSkpCmBgYAoKQXMgeW91IGNhbiBzZWUsIGdncGxvdHMgYXJlIG11Y2ggbmljZXIuCgpUaGUgcGxvdCBzaG93cyBhIG5lZ2F0aXZlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGVuZ2luZSBzaXplIChkaXNwbCA9IGRpc3BsYWNlbWVudCkgYW5kIGZ1ZWwgZWZmaWNpZW5jeSAoaHd5ID0gZnVlbCBlY29ub215IG9uIHRoZSBoaWdod2F5KS4gSW4gb3RoZXIgd29yZHMsIGNhcnMgd2l0aCBiaWcgZW5naW5lcyB1c2UgbW9yZSBmdWVsLiAKCldpdGggX19nZ3Bsb3QyX18sIHlvdSBiZWdpbiBhIHBsb3Qgd2l0aCB0aGUgZnVuY3Rpb24gX19nZ3Bsb3QoKV9fLiBUaGUgZnVuY3Rpb24gX19nZW9tX3BvaW50KClfXyBhZGRzIGEgbGF5ZXIgb2YgcG9pbnRzIHRvIHlvdXIgcGxvdCwgd2hpY2ggY3JlYXRlcyBhIHNjYXR0ZXJwbG90LiBfX2dncGxvdDJfXyBjb21lcyB3aXRoIG1hbnkgZ2VvbSBmdW5jdGlvbnMgdGhhdCBlYWNoIGFkZCBhIGRpZmZlcmVudCB0eXBlIG9mIGxheWVyIHRvIGEgcGxvdC4gWW91J2xsIGxlYXJuIGEgd2hvbGUgYnVuY2ggb2YgdGhlbSB0aHJvdWdob3V0IHRoaXMgY2hhcHRlci4KCkVhY2ggZ2VvbSBmdW5jdGlvbiBpbiBnZ3Bsb3QyIHRha2VzIGEgX19tYXBwaW5nX18gYXJndW1lbnQuIFRoaXMgZGVmaW5lcyBob3cgdmFyaWFibGVzIGluIHlvdXIgZGF0YXNldCBhcmUgbWFwcGVkIHRvIHZpc3VhbCBwcm9wZXJ0aWVzLiBUaGUgX19tYXBwaW5nX18gYXJndW1lbnQgaXMgYWx3YXlzIHBhaXJlZCB3aXRoIF9fYWVzKClfXywgYW5kIHRoZSBfX3hfXyBhbmQgX195X18gYXJndW1lbnRzIG9mIF9fYWVzKClfXyBzcGVjaWZ5IHdoaWNoIHZhcmlhYmxlcyB0byBtYXAgdG8gdGhlIHggYW5kIHkgYXhlcy4gX19nZ3Bsb3QyX18gbG9va3MgZm9yIHRoZSBtYXBwZWQgdmFyaWFibGVzIGluIHRoZSBfX2RhdGFfXyBhcmd1bWVudCwgaW4gdGhpcyBjYXNlLCBfX21wZ19fLgoKIyMjIyAzLjIuMyBBIGdyYXBoaW5nIHRlbXBsYXRlCgpMZXQncyB0dXJuIHRoaXMgY29kZSBpbnRvIGEgcmV1c2FibGUgdGVtcGxhdGUgZm9yIG1ha2luZyBncmFwaHMgd2l0aCBnZ3Bsb3QyLiBUbyBtYWtlIGEgZ3JhcGgsIHJlcGxhY2UgdGhlIGJyYWNrZXRlZCBzZWN0aW9ucyBpbiB0aGUgY29kZSBiZWxvdyB3aXRoIGEgZGF0YXNldCwgYSBnZW9tIGZ1bmN0aW9uLCBvciBhIGNvbGxlY3Rpb24gb2YgbWFwcGluZ3MuCgpgYGB7cn0KZ2dwbG90KGRhdGEgPSA8REFUQT4pICsKICA8R0VPTV9GVU5DVElPTj4obWFwcGluZyA9IGFlcyg8TUFQUElOR1M+KSkKYGBgCgojIyMjIDMuMi40IEV4ZXJjaXNlcwoKMS4gUnVuIF9fZ2dwbG90KGRhdGEgPSBtcGcpX18uIFdoYXQgZG8geW91IHNlZT8KCmBgYHtyfQpnZ3Bsb3QoZGF0YT1tcGcpCmBgYAoKUnVubmluZyBfX2dncGxvdChkYXRhPW1wZylfXyBqdXN0IHByb2R1Y2VzIGEgbGFyZ2UgZ3JleSByZWN0YW5nbGUuIFRoaXMgaXMgYmVjYXVzZSB3ZSBoYXZlbid0IGFjdHVhbGx5IGdpdmVuIGl0IGFueSBwb2ludHMgdG8gcGxvdCBvciB2YXJpYWJsZXMgdG8gbWFwLgoKMi4gSG93IG1hbnkgcm93cyBhcmUgaW4gX19tcGdfXz8gSG93IG1hbnkgY29sdW1ucz8KCmBgYHtyfQpkaW0obXBnKQpgYGAKClRoZXJlIGFyZSAyMzQgcm93cyBhbmQgMTEgY29sdW1ucy4KCjMuIFdoYXQgZG9lcyB0aGUgX19kcnZfXyB2YXJpYWJsZSBkZXNjcmliZT8gUmVhZCB0aGUgaGVscCBmb3IgP21wZyB0byBmaW5kIG91dC4KCmBgYHtyfQo/bXBnCmBgYAoKZHJ2IC0gdGhlIHR5cGUgb2YgZHJpdmUgdHJhaW4sIHdoZXJlIGYgPSBmcm9udC13aGVlbCBkcml2ZSwgciA9IHJlYXIgd2hlZWwgZHJpdmUsIDQgPSA0d2QKCjQuIE1ha2UgYSBzY2F0dGVycGxvdCBvZiBfX2h3eV9fIHZzIF9fY3lsX18KCmBgYHtyfQpnZ3Bsb3QobXBnKSArCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKGN5bCxod3kpKQpgYGAKCkFzIHdlIGNhbiBzZWUgZnJvbSB0aGUgYWJvdmUgc2NhdHRlcnBsb3Qgb2YgaHd5IHZzIGN5bCwgdmVoaWNsZXMgd2l0aCBtb3JlIGN5bGluZGVycyBoYXZlIGxvd2VyIGZ1ZWwgZWNvbm9teSBvbiB0aGUgaGlnaHdheS4KCjUuIFdoYXQgaGFwcGVucyBpZiB5b3UgbWFrZSBhIHNjYXR0ZXJwbG90IG9mIF9fY2xhc3NfXyB2cyBfX2Rydl9fPyBXaHkgaXMgdGhlIHBsb3Qgbm90IHVzZWZ1bD8KCmBgYHtyfQpnZ3Bsb3QobXBnKSArCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKGNsYXNzLGRydikpCmBgYAoKSWYgeW91IG1ha2UgYSBzY2F0dGVycGxvdCBvZiBfX2NsYXNzX18gdnMgX19kcnZfXyB5b3UgZ2V0IGEgZ3JhcGggdGhhdCBzaG93cyB0aGUgdHlwZSBvZiBkcml2ZSB0cmFpbiBmb3IgdGhlIHZlaGljbGUgY2xhc3NlcyBpbiB0aGUgZGF0YXNldC4gSG93ZXZlciwgaXQgZG9lcyBub3QgcGxvdCB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZXNlLCBvbmx5IHRlbGxzIHlvdSB0aGF0IHRoZSBkYXRhc2V0IGhhZCBhdCBsZWFzdCBvbmUgaW5zdGFuY2Ugb2YgYSAiMnNlYXRlciB3aXRoIHJlYXIgd2hlZWwgZHJpdmUiIG9yICJhIHBpY2t1cCB3aXRoIDQtd2hlZWwgZHJpdmUiLiBJdCBkb2VzIG5vdCBwcm92aWRlIGFueSBpbnNpZ2h0IGludG8gdGhlIGRhdGEuIEEgc2NhdHRlcnBsb3QgbW9zdCBsaWtlbHkgaXMgbm90IHRoZSBiZXN0IHdheSB0byBkaXNwbGF5IHRoaXMgZGF0YS4KCiMjIyAzLjMgQWVzdGhldGljIG1hcHBpbmdzCgpZb3UgY2FuIGFkZCBhIHRoaXJkIHZhcmlhYmxlLCBsaWtlIF9fY2xhc3NfXywgdG8gYSB0d28gZGltZW5zaW9uYWwgc2NhdHRlcnBsb3QgYnkgbWFwcGluZyBpdCB0byBhbiBfX2Flc3RoZXRpY19fLiBBbiBhZXN0aGV0aWMgaXMgYSB2aXN1YWwgcHJvcGVydHkgb2YgdGhlIG9iamVjdHMgaW4geW91ciBwbG90LiBBZXN0aGV0aWNzIGluY2x1ZGUgdGhpbmdzIGxpa2UgdGhlIHNpemUsIHRoZSBzaGFwZSwgb3IgdGhlIGNvbG9yIG9mIHlvdXIgcG9pbnRzLiBZb3UgY2FuIGRpc3BsYXkgYSBwb2ludCAobGlrZSB0aGUgb25lIGJlbG93KSBpbiBkaWZmZXJlbnQgd2F5cyBieSBjaGFuZ2luZyB0aGUgdmFsdWVzIG9mIGl0cyBhZXN0aGV0aWMgcHJvcGVydGllcy4gU2luY2Ugd2UgYWxyZWFkeSB1c2UgdGhlIHdvcmQgInZhbHVlIiB0byBkZXNjcmliZSBkYXRhLCBsZXQncyB1c2UgdGhlIHdvcmQgImxldmVsIiB0byBkZXNjcmliZSBhZXN0aGV0aWMgcHJvcGVydGllcy4KCllvdSBjYW4gY29udmV5IGluZm9ybWF0aW9uZyBhYm91dCB5b3VyIGRhdGEgYnkgbWFwcGluZyB0aGUgYWVzdGhldGljcyBpbiB5b3VyIHBsb3QgdG8gdGhlIHZhcmlhYmxlcyBpbiB5b3VyIGRhdGFzZXQuIEZvciBleGFtcGxlLCB5b3UgY2FuIG1hcCB0aGUgY29sb3JzIG9mIHlvdXIgcG9pbnRzIHRvIHRoZSBfX2NsYXNzX18gdmFyaWFibGUgdG8gcmV2ZWFsIHRoZSBjbGFzcyBvZiBlYWNoIGNhci4KCmBgYHtyfQpnZ3Bsb3QobXBnKSArCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSBkaXNwbCx5ID0gaHd5LCBjb2xvciA9IGNsYXNzKSkKYGBgCgpUbyBtYXAgYW4gYWVzdGhldGljIHRvIGEgdmFyaWFibGUsIGFzc29jaWF0ZSB0aGUgbmFtZSBvZiB0aGUgYWVzdGhldGljIHRvIHRoZSBuYW1lIG9mIHRoZSB2YXJpYWJsZSBpbnNpZGUgX19hZXMoKV9fLiBnZ3Bsb3QyIHdpbGwgYXV0b21hdGljYWxseSBhc3NpZ24gYSB1bmlxdWUgbGV2ZWwgb2YgdGhlIGFlc3RoZXRpYyAoaGVyZSBhIHVuaXF1ZSBjb2xvcikgdG8gZWFjaCB1bmlxdWUgbGV2ZWwgb2YgdGhlIHZhcmlhYmxlLCBhIHByb2Nlc3Mga25vd24gYXMgX19zY2FsaW5nX18uIGdncGxvdDIgd2lsbCBhbHNvIGFkZCBhIGxlZ2VuZCB0aGF0IGV4cGxhaW5zIHdoaWNoIGxldmVscyBjb3JyZXNwb25kIHRvIHdoaWNoIHZhbHVlcy4KClRoZSBjb2xvcnMgcmV2ZWFsIHRoYXQgbWFueSBvZiB0aGUgdW51c3VhbCBwb2ludHMgYXJlIHR3by1zZWF0ZXIgY2Fycy4gVGhlc2UgY2FycyBkb24ndCBzZWVtIGxpa2UgaHlicmlkcywgYW5kIGFyZSwgaW4gZmFjdCwgc3BvcnRzIGNhcnMhIFNwb3J0cyBjYXJzIGhhdmUgbGFyZ2UgZW5naW5lcyBsaWtlIFNVVnMgYW5kIHBpY2t1cCB0cnVja3MsIGJ1dCBzbWFsbCBib2RpZXMgbGlrZSBtaWRzaXplIGFuZCBjb21wYWN0IGNhcnMsIHdoaWNoIGltcHJvdmVzIHRoZWlyIGdhcyBtaWxlYWdlLiBJbiBoaW5kc2lnaHQsIHRoZXNlIGNhcnMgd2VyZSB1bmxpa2VseSB0byBiZSBoeWJyaWRzIHNpbmNlIHRoZXkgaGF2ZSBsYXJnZSBlbmdpbmVzLgoKSW4gdGhlIGFib3ZlIGV4YW1wbGUsIHdlIG1hcHBlZCBfX2NsYXNzX18gdG8gdGhlIGNvbG9yIGFlc3RoZXRpYywgYnV0IHdlIGNvdWxkIGhhdmUgbWFwcGVkIF9fY2xhc3NfXyB0byB0aGUgc2l6ZSBhZXN0aGV0aWMgaW4gdGhlIHNhbWUgd2F5LiBJbiB0aGlzIGNhc2UsIHRoZSBleGFjdCBzaXplIG9mIGVhY2ggcG9pbnQgd291bGQgcmV2ZWFsIGl0cyBjbGFzcyBhZmZpbGlhdGlvbi4gV2UgZ2V0IGEgKndhcm5pbmcqIGhlcmUsIGJlY2F1c2UgbWFwcGluZyBhbiB1bm9yZGVyZWQgdmFyaWFibGUgX18oY2xhc3MpX18gdG8gYW4gb3JkZXJlZCBhZXN0aGV0aWMgX18oc2l6ZSlfXyBpcyBub3QgYSBnb29kIGlkZWEuCgpgYGB7cn0KZ2dwbG90KG1wZykgKwogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyhkaXNwbCxod3ksc2l6ZT1jbGFzcykpCmBgYAoKT3Igd2UgY291bGQgaGF2ZSBtYXBwZWQgX19jbGFzc19fIHRvIHRoZSAqYWxwaGEqIGFlc3RoZXRpYywgd2hpY2ggY29udHJvbHMgdGhlIHRyYW5zcGFyZW5jeSBvZiB0aGUgcG9pbnRzLCBvciB0byB0aGUgc2hhcGUgYWVzdGhldGljLCB3aGljaCBjb250cm9scyB0aGUgc2hhcGUgb2YgdGhlIHBvaW50cy4KCmBgYHtyfQojIExlZnQKZ2dwbG90KGRhdGEgPSBtcGcpICsKICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5LCBhbHBoYSA9IGNsYXNzKSkKCiMgUmlnaHQKZ2dwbG90KGRhdGEgPSBtcGcpICsKICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5LCBzaGFwZSA9IGNsYXNzKSkKYGBgCgpnZ3Bsb3QyIHdpbGwgb25seSB1c2Ugc2l4IHNoYXBlcyBhdCBhIHRpbWUuIEJ5IGRlYXVsdCwgYWRkaXRpb25hbCBncm91cHMgd2lsbCBnbyB1bnBsb3R0ZWQgd2hlbiB5b3UgdXNlIHRoZSBzaGFwZSBhZXN0aGV0aWMuCgpGb3IgZWFjaCBhZXN0aGV0aWMsIHlvdSB1c2UgX19hZXMoKV9fIHRvIGFzc29jaWF0ZSB0aGUgbmFtZSBvZiB0aGUgYWVzdGhldGljIHdpdGggYSB2YXJpYWJsZSB0byBkaXNwbGF5LiBUaGUgX19hZXMoKV9fIGZ1bmN0aW9uIGdhdGhlcnMgdG9nZXRoZXIgZWFjaCBvZiB0aGUgYWVzdGhldGljIG1hcHBpbmdzIHVzZWQgYnkgYSBsYXllciBhbmQgcGFzc2VzIHRoZW0gdG8gdGhlIGxheWVyJ3MgbWFwcGluZyBhcmd1bWVudC4gVGhlIHN5bnRheCBoaWdobGlnaHRzIGEgdXNlZnVsIGluc2lnaHQgYWJvdXQgX194X18gYW5kIF9feV9fOiB0aGUgKngqIGFuZCAqeSogbG9jYXRpb25zIG9mIGEgcG9pbnQgYXJlIHRoZW1zZWx2ZXMgYWVzdGhldGljcywgdmlzdWFsIHByb3BlcnRpZXMgdGhhdCB5b3UgY2FuIG1hcCB0byB2YXJpYWJsZXMgdG8gZGlzcGxheSBpbmZvcm1hdGlvbiBhYm91dCB0aGUgZGF0YS4KCk9uY2UgeW91IG1hcCBhbiBhZXN0aGV0aWMsIGdncGxvdDIgdGFrZXMgY2FyZSBvZiB0aGUgcmVzdC4gSXQgc2VsZWN0cyBhIHJlYXNvbmFibGUgc2NhbGUgdG8gdXNlIHdpdGggdGhlIGFlc3RoZXRpYywgYW5kIGl0IGNvbnN0cnVjdHMgYSBsZWdlbmQgdGhhdCBleHBsYWlucyB0aGUgbWFwcGluZyBiZXR3ZWVuIGxldmVscyBhbmQgdmFsdWVzLiBGb3IgKngqIGFuZCAqeSogYWVzdGhldGljcywgZ2dwbG90MiBkb2VzIG5vdCBjcmVhdGUgYSBsZWdlbmQsIGJ1dCBpdCBjcmVhdGVzIGFuIGF4aXMgbGluZSB3aXRoIHRpY2sgbWFya3MgYW5kIGEgbGFiZWwuIFRoZSBheGlzIGxpbmUgYWN0cyBhcyBhIGxlZ2VuZDsgaXQgZXhwbGFpbnMgdGhlIG1hcHBpbmcgYmV0d2VlbiBsb2NhdGlvbnMgYW5kIHZhbHVlcy4KCllvdSBjYW4gYWxzbyBzZXQgdGhlIGFlc3RoZXRpYyBwcm9wZXJ0aWVzIG9mIHlvdXIgZ2VvbSBtYW51YWxseS4gRm9yIGV4YW1wbGUsIHdlIGNhbiBtYWtlIGFsbCBvZiB0aGUgcG9pbnRzIGluIG91ciBwbG90IGJsdWU6CgpgYGB7cn0KZ2dwbG90KG1wZykgKwogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4PWRpc3BsLCB5PWh3eSksIGNvbG9yPSJibHVlIikKYGBgCgpIZXJlLCB0aGUgY29sb3IgZG9lc24ndCBjb252ZXkgaW5mb3JtYXRpb24gYWJvdXQgYSB2YXJpYWJsZSwgYnV0IG9ubHkgY2hhbmdlcyB0aGUgYXBwZWFyYW5jZSBvZiB0aGUgcGxvdC4gVG8gc2V0IGFuIGFlc3RoZXRpYyBtYW51YWxseSwgc2V0IHRoZSBhZXN0aGV0aWMgYnkgbmFtZSBhcyBhbiBhcmd1bWVudCBvZiB5b3VyIGdlb20gZnVuY3Rpb247IGkuZS4gaXQgZ29lcyAqb3V0c2lkZSogb2YgX19hZXMoKV9fLiBZb3UnbGwgbmVlZCB0byBwaWNrIGEgbGV2ZWwgdGhhdCBtYWtlcyBzZW5zZSBmb3IgdGhhdCBhZXN0aGV0aWM6CgoqIFRoZSBuYW1lIG9mIGEgY29sb3IgYXMgYSBjaGFyYWN0ZXIgc3RyaW5nLgoqIFRoZSBzaXplIG9mIGEgcG9pbnQgaW4gbW0uCiogVGhlIHNoYXBlIG9mIGEgcG9pbnQgYXMgYSBudW1iZXIsIGFzIHNob3duIGluIEZpZ3VyZSAzLjEKCiMjIyMgMy4zLjEgRXhlcmNpc2VzCgoxLiBXaGF0J3MgZ29uZSB3cm9uZyB3aXRoIHRoaXMgY29kZT8gV2h5IGFyZSB0aGUgcG9pbnRzIG5vdCBibHVlPyBUaGUgcG9pbnRzIGFyZSBub3QgYmx1ZSBiZWNhdXNlIHRoZSB0aGUgYWVzdGhldGljIC0gY29sb3IgLSBpcyBub3Qgc2V0IGFzIGFuIGFyZ3VtZW50IG9mIHRoZSBnZW9tIGZ1bmN0aW9uLiAiQ29sb3IgPSAiYmx1ZSIgbmVlZHMgdG8gYmUgc2V0IG91dHNpZGUgdGhlIHBhcmVudGhlc2VzIGZvciBfX2FlcygpX18uCgpgYGB7cn0KZ2dwbG90KG1wZykgKwogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3ksIGNvbG9yID0gImJsdWUiKSkKYGBgCgoyLiBXaGljaCB2YXJpYWJsZXMgaW4gX19tcGdfXyBhcmUgY2F0ZWdvcmljYWw/IFdoaWNoIHZhcmlhYmxlcyBhcmUgY29udGludW91cz8gKEhpbnQ6IHR5cGUgX18/bXBnX18gdG8gcmVhZCB0aGUgZG9jdW1lbnRhdGlvbiBmb3IgdGhlIGRhdGFzZXQpLiBIb3cgY2FuIHlvdXNlIHNlZSB0aGlzIGluZm9ybWF0aW9uIHdoZW4geW91IHJ1biBfX21wZ19fPwoKYGBge3J9Cj9tcGcKYGBgCgpDYXRlZ29yaWNhbCB2YXJpYWJsZXMgLSBtYW51ZmFjdHVyZXIsIG1vZGVsLCBjeWwsIHRyYW5zLCBmbCwgY2xhc3MKCkNvbnRpbnVvdXMgdmFyaWFibGVzIC0gZGlzcGwsIGN0eSwgaHd5LCB5ZWFyLCBkcnYKClByaW50aW5nIHRoZSBkYXRhIGdpdmVzIHVzIGEgc2FtcGxlIG9mIHRoZSBkYXRhIGFuZCBzaG93cyB0aGUgbW9kZSBvZiBlYWNoIHZhcmlhYmxlLiBUaG9zZSB3aXRoIG1vZGVzIG9mIDxjaHI+IGZvciBjaGFyYWN0ZXIgYXJlIGNhdGVnb3JpY2FsLCBhbmQgdGhvc2Ugdy8gbW9kZSA8ZGJsPiBvciA8aW50PiBhcmUgY29udGludW91cy4gVGhlIGFib3ZlIGlzIGEgc2ltcGxlIGV4cGxhbmF0aW9uIG9mLiBNb3JlIGNvdWxkIGJlIHNhaWQgYWJvdXQgdGhlIHZhcmlhYmxlcyBfX3llYXJfXyBhbmQgX19jeWxfXyBhcyB0aG91Z2ggdGhlaXIgbW9kZXMgYXJlIGRlZmluZWQgYXMgaW50ZWdlciwgdGhlIGRhdGEgc2VlbXMgbW9yZSBjYXRlZ29yaWNhbCBvciBub21pbmFsIGluIG5hdHVyZS4gSG93ZXZlciwgaXQgaXMgaW1wb3J0YW50IHRvIG5vdGUgdGhhdCB0aGUgbW9kZSBhc3NvY2lhdGVkIHdpdGggdGhlIHZhcmlhYmxlcyBpbiB0aGUgZGF0YSBmcmFtZSBpcyBpbXBvcnRhbnQgYmVjYXVzZSBpdCBkZWZpbmVzIHdoYXQga2luZHMgb2Ygb3BlcmF0aW9ucy9hbmFseXNpcyBjYW4gYmUgcGVyZm9ybWVkLgoKYGBge3J9Cm1wZwpgYGAKCjMuIE1hcCBhIGNvbnRpbnVvdXMgdmFyaWFibGUgdG8gX19jb2xvcl9fLCBfX3NpemVfXywgYW5kIF9fc2hhcGVfXy4gSG93IGRvIHRoZXNlIGFlc3RoZXRpY3MgYmVoYXZlIGRpZmZlcmVudGx5IGZvciBjYXRlZ29yaWNhbCB2cy4gY29udGludW91cyB2YXJpYWJsZXMuCgpgYGB7cn0KZ2dwbG90KG1wZykgKwogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3ksIGNvbG9yID0geWVhcikpCgpnZ3Bsb3QobXBnKSArCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgeSA9IGh3eSwgc2l6ZSA9IHllYXIpKQoKZ2dwbG90KG1wZykgKwogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3ksIHNoYXBlID0geWVhcikpCmBgYAoKV2hlbiB3ZSBtYXAgYSBjb250aW51b3VzIHZhcmlhYmxlLCBhIGxlZ2VuZCBpcyBzaW1pbGFybHkgY3JlYXRlZCBhcyB0byB3aGVuIHdlIG1hcCBhIGNhdGVnb3JpY2FsIHZhcmlhYmxlLCBidXQgdGhlIHZhbHVlcyBvZiB0aGUgbGVnZW5kIGFyZSBub3QgZGlzY3JldGUgdmFsdWVzLCBidXQgdGFrZSBvbiBhIGNvbnRpbnVvdXMgc2NhbGUuIAoKNC4gV2hhdCBoYXBwZW5zIGlmIHlvdSBtYXAgdGhlIHNhbWUgdmFyaWFibGUgdG8gbXVsdGlwbGUgYWVzdGhldGljcz8KCmBgYHtyfQpnZ3Bsb3QobXBnKSArCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgeSA9IGh3eSwgY29sb3IgPSBod3ksIHNpemUgPSBkaXNwbCkpCmBgYAoKV2hlbiB3ZSBtYXAgdGhlIHNhbWUgdmFyaWFibGUgdG8gbXVsdGlwbGUgYWVzdGhldGljcywgYSBncmFwaGljIGlzIHByb2R1Y2VkLCBidXQgaXQgYmVjb21lcyBtdWNoIG1vcmUgZGlmZmljdWx0IHRvIGludGVycHJldC4gQWxzbywgbm90IG11Y2ggdmFsdWUgaXMgcHJvdmlkZWQuIEFib3ZlLCBkaXNwbCBpcyBtYXBwZWQgb24gdGhlIHktYXhpcyBhbmQgYnkgc2l6ZSB3aGljaCBpcyByZWR1bmRhbnQgaW5mb3JtYXRpb24uIEhlcmUgLSBsZXNzIGlzIG1vcmUuCgo1LiBXaGF0IGRvZXMgdGhlIF9fc3Ryb2tlX18gYWVzdGhldGljIGRvPyBXaGF0IHNoYXBlcyBkb2VzIGl0IHdvcmsgd2l0aD8gKEhpbnQ6IHVzZSBfXz9nZW9tX3BvaW50X18pCgpgYGB7cn0KP2dlb21fcG9pbnQKYGBgCgpgYGB7cn0KZ2dwbG90KG1wZywgbWFwcGluZyA9IGFlcyh4PWNsYXNzLHk9ZGlzcGwpKSArCiAgZ2VvbV9wb2ludChzaGFwZSA9IDIxLCBjb2xvciA9ICJibGFjayIsIGZpbGwgPSAid2hpdGUiLCBzaXplID0gMSwgc3Ryb2tlID0gMikKYGBgCgpUaGUgc3Ryb2tlIGFlc3RoZXRpYyBtb2RpZmllcyB0aGUgd2lkdGggb2YgdGhlIGJvcmRlci4gTm90ZSAtIHRoaXMgY2FuIG9ubHkgYmUgdXNlZCBmb3IgcGxvdHMgd2l0aCAic2hhcGVzIiwgdGhlcmVmb3JlIGFsdGhvdWdoIGl0IGNhbiBiZSB1c2VkIGluIGFuIG9wZXJhdGlvbiB3aXRoIHR3byBjb250aW51b3VzIHZhcmlhYmxlcyAoUiB3aWxsIGFsbG93IGl0KSwgaXQgd2lsbCBiZSB1c2VsZXNzIGFzIGl0IHdpbGwgbm90IHByb2R1Y2UgYW55dGhpbmcuCgpZb3UgY2FuIG9ubHkgYXBwbHkgc3Ryb2tlIHRvIHNoYXBlcyAyMS0yNS4KCjYuIFdoYXQgaGFwcGVucyBpZiB5b3UgbWFwIGFuIGFlc3RoZXRpYyB0byBzb21ldGhpbmcgb3RoZXIgdGhhbiBhIHZhcmlhYmxlIG5hbWUsIGxpa2UgX19hZXMoY29sb3IgPSBkaXNwbCA8IDUpX18/IE5vdGUsIHlvdSdsbCBhbHNvIG5lZWQgdG8gc3BlY2lmeSAqeCogYW5kICp5Ki4KCmBgYHtyfQpnZ3Bsb3QobXBnLCBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5LCBjb2xvciA9IGRpc3BsIDwgNSkpICsKZ2VvbV9wb2ludCgpCmBgYAoKV2hlbiB5b3UgbWFwIGEgY29uZGl0aW9uIHN1Y2ggYXMgImRpc3BsIDwgNSIsIGEgbGVnZW5kIHdpbGwgYmUgY3JlYXRlZCBkaWZmZXJlbnRpYXRpbmcgd2hlcmUgdGhlIGNvbmRpdGlvbiBpcyB0cnVlIGFuZCBmYWxzZS4gSW4gb3VyIGV4YW1wbGUsIHRoZSBhZXN0aGV0aWMgY29sb3IgY29vcmRpbmF0ZXMgd2hlcmUgdGhlIGNvbmRpdGlvbiBpcyBhbmQgaXMgbm90IG1ldC4KCiMjIyAzLjQgQ29tbW9uIHByb2JsZW1zCgpQcm9ibGVtcyBpbiBydW5uaW5nIFIgY29kZSBhcmUgbm9ybWFsLCB0aGV5IGhhcHBlbiBhbGwgdGhlIHRpbWUhCgpPbmUgY29tbW9uIHByb2JsZW0gd2hlbiBjcmVhdGluZyBnZ3Bsb3QyIGdyYXBoaWNzIGlzIHRvIHB1dCB0aGUgX18rX18gaW4gdGhlIHdyb25nIHBsYWNlOiBpdCBoYXMgdG8gY29tZSBhdCB0aGUgZW5kIG9mIHRoZSBsaW5lLCBub3QgdGhlIHN0YXJ0LiBJbiBvdGhlciB3b3JkcywgbWFrZSB5b3UgaGF2ZW4ndCBhY2NpZGVudGx5IHdyaXR0ZW4gY29kZSBsaWtlIHRoaXM6CgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBtcGcpCisgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgeSA9IGh3eSkpCmBgYAoKIyMjIDMuNSBGYWNldHMKCk9uZSB3YXkgdG8gYWRkIGFkZGl0aW9uYWwgdmFyaWFibGVzIGlzIHdpdGggYWVzdGhldGljcy4gQW5vdGhlciB3YXksIHBhcnRpY3VsYXJseSB1c2VmdWwgZm9yIGNhdGVnb3JpY2FsIHZhcmlhYmxlcywgaXMgdG8gc3BsaXQgeW91ciBwbG90cyBpbnRvIF9fZmFjZXRzX18sIHN1YnBsb3RzIHRoYXQgZWFjaCBkaXNwbGF5IG9uZSBzdWJldCBvZiB0aGUgZGF0YS4KCmBgYHtyfQpnZ3Bsb3QobXBnKSArCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgeSA9IGh3eSkpICsKICBmYWNldF93cmFwKH4gY2xhc3MsIG5yb3c9MikKYGBgCgpUbyBmYWNldCB5b3VyIHBsb3Qgb24gdGhlIGNvbWJpbmF0aW9uIG9mIHR3byB2YXJpYWJsZXMsIGFkZCBfX2ZhY2V0X2dyaWQoKV9fIHRvIHlvdXIgcGxvdCBjYWxsLiBUaGUgZmlyc3QgYXJndW1lbnQgb2YgX19mYWNldF9ncmlkKClfXyBpcyBhbHNvIGEgZm9ybXVsYS4gVGhpcyB0aW1lIHRoZSBmb3JtdWxhIHNob3VsZCBjb250YWluIHZhcmlhYmxlIG5hbWVzIHNlcGFyYXRlZCBieSBhIH4uCgpgYGB7cn0KZ2dwbG90KG1wZykgKwogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3kpKSArCiAgZmFjZXRfZ3JpZChjeWwgfiBkcnYpCmBgYAoKIyMjIyAzLjUuMSBFeGVyY2lzZXMKCjEuIFdoYXQgaGFwcGVucyBpZiB5b3UgZmFjZXQgb24gYSBjb250aW51b3VzIHZhcmlhYmxlPwoKYGBge3J9CiMgTGVmdApnZ3Bsb3QobXBnKSArCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgeSA9IGh3eSkpICsKICBmYWNldF93cmFwKH4gY3R5LCBucm93PTIpCgojIFJpZ2h0CmdncGxvdChtcGcpICsKICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5KSkgKwogIGZhY2V0X2dyaWQoeWVhciB+IGN0eSkKYGBgCgpJZiB5b3UgZmFjZXQgb24gYSBjb250aW51b3VzIHZhcmlhYmxlLCB0aGUgcGxvdCB3aWxsIGNyZWF0ZSBmYWNldHMgYWNjb3JkaW5nIHRvIGVhY2ggbGV2ZWwgb2YgdGhlIGNvbnRpbnVvdXMgdmFyaWFibGUgKGNhdGVnb3JpemUgdGhlbSkuIAoKMi4gV2hhdCBkbyB0aGUgZW1wdHkgY2VsbHMgaW4gcGxvdCB3aXRoIF9fZmFjZXRfZ3JpZChkcnZ+Y3lsKV9fIG1lYW4/IEhvdyBkbyB0aGV5IHJlbGF0ZSB0byB0aGlzIHBsb3Q/CgpgYGB7cn0KIyBMZWZ0CmdncGxvdChtcGcpICsKICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5KSkgKwogIGZhY2V0X2dyaWQoZHJ2IH4gY3lsKQoKIyBSaWdodApnZ3Bsb3QobXBnLCBtYXBwaW5nID0gYWVzKHggPSBkcnYsIHkgPSBjeWwpKSArCiAgZ2VvbV9wb2ludCgpCmBgYAoKVGhlIGZhY2V0IGdyaWQgY29tcGFydG1lbnRhbGl6ZXMgZGF0YSBhY2NvcmRpbmcgdG8gdGhlaXIgZHJpdmUgdHlwZSBhbmQgbnVtYmVyIG9mIGN5bGluZGVycy4gVGhlIGVtcHR5IGZhY2V0cyBpbmRpY2F0ZSBjYXRlZ29yaWVzIHdoaWNoIGhhdmUgbm8gZGF0YSBwb2ludHMuIEZvciBleGFtcGxlLCB0aGVyZSB3ZXJlIG5vICI0LWN5bGluZGVyIHJlYXItd2hlZWwgZHJpdmUiIHZlaGljbGVzLgoKR2VvbSBwb2ludCBwcm9kdWNlcyBhIHNjYXR0ZXJwbG90IG9mIHRoZSBkYXRhIGFuZCB3b3JrcyBiZXN0IHdpdGggdHdvIGNvbnRpbnVvdXMgdmFyaWFibGVzLiBfX0Rydl9fIGlzIGEgY2F0ZWdvcmljYWwgdmFyaWFibGUgYW5kIGFsdGhvdWdoIF9fY3lsX18gaXMgbGFiZWxlZCBhcyBhbiBpbnRlZ2VyIGFuZCB3ZSBwcmV2aW91c2x5IHNhaWQgaXQgd2FzIGEgY29udGludW91cyB2YXJpYWJsZSAtIGl0IHJlYWxseSBzaG91bGQgYmUgdHJlYXRlZCBhcyBhIGNhdGVnb3JpY2FsIChub21pbmFsKSB2YXJpYWJsZSBhcyBpdCBvbmx5IHRha2VzIG9uIGZpdmUgcG9zc2libGUgdmFsdWVzIGFuZCB0aGVyZSBpcyBubyBtZWFuaW5nZnVsIHplcm8gKG5vIGF1dG9tb2JpbGUgaGFzIDAgY3lsaW5kZXJzKS4gVGh1cywgdGhlIHBsb3QgaXMgYmFzaWNhbGx5IHNpbXBseSBpbmRpY2F0aW5nIHdoZXRoZXIgdGhhdCBjb21iaW5hdGlvbiBvZiBudW1iZXIgb2YgY3lsaW5kZXJzIGFuZCBkcml2ZSB0eXBlIGlzIHJlcHJlc2VudGVkIGluIHRoZSBkYXRhIChzaW1pbGFyIHRvIG91ciBmaXJzdCBncmFwaCkuCgozLiBXaGF0IHBsb3RzIGRvZXMgdGhlIGZvbGxvd2luZyBjb2RlIG1ha2U/IFdoYXQgZG9lcyBfXy5fXyBkbz8KCmBgYHtyfQojIExlZnQKZ2dwbG90KGRhdGEgPSBtcGcpICsKICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5KSkgKwogIGZhY2V0X2dyaWQoZHJ2IH4gLikKCiMgUmlnaHQKZ2dwbG90KG1wZykgKwogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3kpKSArCiAgZmFjZXRfZ3JpZCguIH4gY3lsKQpgYGAKCjQuIFRha2UgdGhlIGZpcnN0IGZhY2V0ZWQgcGxvdCBpbiB0aGlzIHNlY3Rpb246CgpgYGB7cn0KIyBMZWZ0CmdncGxvdChkYXRhID0gbXBnKSArCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgeSA9IGh3eSkpICsKICBmYWNldF93cmFwKH4gY2xhc3MsIG5yb3cgPSAyKQoKIyBSaWdodApnZ3Bsb3QoZGF0YSA9IG1wZywgbWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3ksIGNvbG9yID0gY2xhc3MpKSArCiAgZ2VvbV9wb2ludCgpCmBgYAoKVGhlIGFkdmFudGFnZSBvZiBmYWNldGluZyBhcyBvcHBvc2VkIHRvIHVzaW5nIHRoZSBjb2xvciBhZXN0aGV0aWMgaXMgdGhhdCBpdCBzZXBhcmF0ZXMgb3V0IHRoZSBkYXRhIGFuZCBoZWxwcyBvbmUgdW5kZXJzdGFuZCB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIHR3byBtYXBwaW5nIHZhcmlhYmxlcyB3aXRoaW4gdGhlIGNvbnRleHQgb2YgaXRzIHJlc3BlY3RpdmUgY2xhc3MuIFRoZSBkaXNhZHZhbnRhZ2UgaXMgdGhhdCBpdCBtYWtlcyBpdCBtb3JlIGRpZmZpY3VsdCB0byBzZWUgdGhlIG92ZXJhcmNoaW5nIHRyZW5kIGluIHRoZSBkYXRhLgoKQW5vdGhlciBhZHZhbnRhZ2UgaXMgdGhhdCBpdCBtYWtlcyBpdCBlYXNpZXIgdG8gdW5kZXJzdGFuZCB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gY2xhc3MgYW5kIHZlaGljbGUgY2xhc3MuIEFib3ZlLCBpdCBpcyB2ZXJ5IG5vdGljZWFibGUgdGhhdCAyc2VhdGVycyBnZW5lcmFsbHkgZ2V0IGFib3V0IDI1bXBnIG9uIHRoZSBod3kgYW5kIGhhdmUgZGlzcGxhY2VtZW50cyA+IDUgd2hpbGUgcGlja3VwcyBnZXQgPD0gMjAgbXBnIG9uIHRoZSBoaWdod2F5IGFuZCBoYXZlIGRpc3BsYWNlbWVudHMgYmV0d2VlbiAyLTYuCgpGYWNldGluZyBpcyByZWNvbW1lbmRlZCB3aGVuIHRoZSBudW1iZXIgb2YgcG9pbnRzIGFuZCBjYXRlZ29yaWVzIGluY3JlYXNlLiBBcyB0aGUgbnVtYmVyIG9mIGNhdGVnb3JpZXMgaW5jcmVhc2UsIGRpZmZlcmVudGlhdGluZyBiZXR3ZWVuIGNvbG9ycyB3aWxsIGJlY29tZSBpbmNyZWFzaW5nbHkgZGlmZmljdWx0IHdoZW4gdXNpbmcgYSBjb2xvciBhZXN0aGV0aWMuIEZ1cnRoZXJtb3JlLCB3aGVuIHRoZXJlIGFyZSBncmVhdGVyIHBvaW50cywgdGhlcmUgaXMgbGlrZWx5IHRvIGJlIG1vcmUgb3ZlcmxhcC4gRmFjZXRpbmcgd2lsbCBwdWxsIHRoZXNlIHZhbHVlcyBvdXQgYW5kIHNlcGFyYXRlIHRoZSBkYXRhIGJldHRlci4KCl9fLl9fIHNlcnZlcyBhcyBhIHBsYWNlaG9sZGVyLCBpbmRpY2F0aW5nIHR3byBsZWF2ZSB0aGF0IGZhY2V0IHVuZGVmaW5lZCAodG8gbm90IGZhY2V0IGJ5IGFueXRoaW5nIGluIHRoYXQgbG9jYXRpb24pLgoKNS4gUmVhZCBfXz9mYWNldF93cmFwX18uIFdoYXQgZG9lcyBfX25yb3dfXyBkbz8gV2hhdCBkb2VzIF9fbmNvbF9fIGRvPyBXaGF0IG90aGVyIG9wdGlvbnMgY29udHJvbCB0aGUgbGF5b3V0IG9mIHRoZSBpbmRpdmlkdWFsIHBhbmVscz8gV2h5IGRvZXNuJ3QgX19mYWNldF9ncmlkKClfXyBoYXZlIF9fbnJvd19fIGFuZCBfX25jb2xfXyBhcmd1bWVudHM/CgpgYGB7cn0KP2ZhY2V0X3dyYXAKYGBgCgpucm93cyBpbmRpY2F0ZXMgaG93IG1hbnkgcm93cyBpbiB0aGUgZmFjZXRlZCB3cmFwLCBhbmQgbmNvbHMgaW5kaWNhdGVzIGhvdyBtYW55IGNvbHVtbnMuIAoKNi4gV2hlbiB1c2luZyBfX2ZhY2V0X2dyaWQoKV9fIHlvdSBzaG91bGQgdXN1YWxseSBwdXQgdGhlIHZhcmlhYmxlIHdpdGggbW9yZSB1bmlxdWUgbGV2ZWxzIGluIHRoZSBjb2x1bW5zLiBXaHk/CgpgYGB7cn0KIyBMZWZ0CmdncGxvdChkYXRhID0gbXBnLCBtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgeSA9IGh3eSkpICsKICBnZW9tX3BvaW50KCkgKwogIGZhY2V0X2dyaWQoZmwgfiBjbGFzcykKCiMgUmlnaHQKZ2dwbG90KGRhdGEgPSBtcGcsIG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5KSkgKwogIGdlb21fcG9pbnQoKSArCiAgZmFjZXRfZ3JpZChjbGFzcyB+IGZsKQpgYGAKCkFzIHlvdSBjYW4gc2VlIGZyb20gdGhlIGFib3ZlIHR3byBleGFtcGxlcywgaXQgaXMgYmV0dGVyIHRvIHB1dCB0aGUgdmFyaWFibGUgd2l0aCBtb3JlIHVuaXF1ZSBsZXZlbHMgaW4gdGhlIGNvbHVtbnMgYmVjYXVzZSB3aGVuIHRoZXkgYXJlIGxhaWQgb3V0IHZlcnRpY2FsbHkgdGhlIGxhYmVscyBnZXQgInNxdWlzaGVkIi4KCiMjIyAzLjYgR2VvbWV0cmljIG9iamVjdHMKCkEgX19nZW9tX18gaXMgdGhlIGdlb21ldHJpY2FsIG9iamVjdCB0aGF0IGEgcGxvdCB1c2VzIHRvIHJlcHJlc2VudCBkYXRhLiBQZW9wbGUgb2Z0ZW4gZGVzY3JpcGUgcGxvdHMgYnkgdGhlIHR5cGUgb2YgZ2VvbSB0aGF0IHRoZSBwbG90IHVzZXMuIEZvciBleGFtcGxlLCBiYXIgY2hhcnRzIHVzZSBiYXIgZ2VvbXMsIGxpbmUgY2hhcnRzIHVzZSBsaW5lIGdlb21zLCBib3hwbG90cyB1c2UgYm94cGxvdCBnZW9tcywgYW5kIHNvIG9uLiBTY2F0dGVycGxvdHMgYnJlYWsgdGhlIHRyZW5kLCB0aGV5IHVzZSB0aGUgcG9pbnQgZ2VvbS4gCgpgYGB7cn0KIyBMZWZ0CmdncGxvdChtcGcsIG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5KSkgKwogIGdlb21fcG9pbnQoKQoKIyBSaWdodApnZ3Bsb3QoZGF0YSA9IG1wZywgbWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3kpKSArCiAgZ2VvbV9zbW9vdGgoKQpgYGAKCkV2ZXJ5IGdlb20gZnVuY3Rpb24gaW4gZ2dwbG90MiB0YWtlcyBhIF9fbWFwcGluZ19fIGFyZ3VtZW50LiBIb3dldmVyLCBub3QgZXZlcnkgYWVzdGhldGljIHdvcmtzIHdpdGggZXZlcnkgZ2VvbS4gWW91IGNvdWxkIHNldCB0aGUgc2hhcGUgb2YgYSBwb2ludCwgYnV0IHlvdSBjb3VsZG4ndCBzZXQgdGhlICJzaGFwZSIgb2YgYSBsaW5lLiBPbiB0aGUgb3RoZXIgaGFuZCwgeW91ICpjb3VsZCogc2V0IHRoZSBsaW5ldHlwZSBvZiBhIGxpbmUuIF9fZ2VvbV9zbW9vdGgoKV9fIHdpbGwgZHJhdyBhIGRpZmZlcmVudCBsaW5lLCB3aXRoIGEgZGlmZmVyZW50IGxpbmV0eXBlLCBmb3IgZWFjaCB1bmlxdWUgdmFsdWUgb2YgdGhlIHZhcmlhYmxlIHRoYXQgeW91IG1hcCB0byBsaW5ldHlwZS4gCgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBtcGcpICsKICBnZW9tX3Ntb290aChtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgeSA9IGh3eSwgbGluZXR5cGUgPSBkcnYpKQpgYGAKCkhlcmUgX19nZW9tX3Ntb290aCgpX18gc2VwYXJhdGVzIHRoZSBjYXJzIGludG8gdGhyZWUgbGluZXMgYmFzZWQgb24gdGhlaXIgX19kcnZfXyB2YWx1ZSwgd2hpY2ggZGVzY3JpYmVzIGEgY2FyJ3MgZHJpdmV0cmFpbi4KCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IG1wZywgbWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3ksIGNvbG9yID0gZHJ2LCBsaW5ldHlwZSA9IGRydikpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fc21vb3RoKCkKYGBgCgpUaGUgYWJvdmUgcGxvdCBzaG93cyB0aGUgc21vb3RoIGxpbmVzIGxheWVyZWQgb24gdG9wIG9mIHRoZSBzY2F0dGVyZWQgcGxvdHMgYW5kIGJvdGggdGhlIGxpbmVzIGFuZCBwb2ludHMgY29sb3JlZCBieSB0aGVpciByZXNwZWN0aXZlIGRyaXZlIHR5cGUuCgpnZ3BsbzIgcHJvdmlkZXMgb3ZlciA0MCBnZW9tcywgYW5kIGV4dGVuc2lvbiBwYWNrYWdlcyBwcm92aWRlIGVlbiBtb3JlIChzZWUgaHR0cHM6Ly9leHRzLmdncGxvdDIudGlkeXZlcnNlLm9yZy9nYWxsZXJ5LyBmb3IgYSBzYW1waW5nKS4gVGhlIGJlc3Qgd2F5IHRvIGdldCBhIGNvbXByZWhlbnNpdmUgb3ZlcnZpZXcgaXMgdGhlIGdncGxvdDIgY2hlYXRzaGVldCwgd2hpY2ggeW91IGNhbiBmaW5kIGF0IGh0dHBzOi8vcnN0dWRpby5jb20vcmVzb3VyY2VzL2NoZWF0c2hlZXRzLiBUbyBsZWFybiBtb3JlIGFib3V0IGFueSBzaW5nbGUgZ2VvbSwgdXNlIGhlbHA6IF9fP2dlb21fc21vb3RoX18uCgpNYW55IGdlb21zLCBsaWtlIF9fZ2VvbV9zbW9vdGgoKV9fLCB1c2UgYSBzaW5nbGUgZ2VvbWV0cmljIG9iamVjdCB0byBkaXNwbGF5IG11bHRpcGxlIHJvd3Mgb2YgZGF0YS4gRm9yIHRoZXNlIGdlb21zLCB5b3UgY2FuIHNldCB0aGUgX19ncm91cF9fIGFlc3RoZXRpYyB0byBhIGNhdGVnb3JpY2FsIHZhcmlhYmxlIHRvIGRyYXcgbXVsdGlwbGUgb2JqZWN0cy4gZ2dwbG90MiB3aWxsIGRyYXcgYSBzZXBhcmF0ZSBvYmplY3QgZm9yIGVhY2ggdW5pcXVlIHZhbHVlIG9mIHRoZSBncm91cGluZyB2YXJpYWJsZS4gSW4gcHJhY3RpY2UsIGdncGxvdDIgd2lsbCBhdXRvbWF0aWNhbGx5IGdyb3VwIHRoZSBkYXRhIGZvciB0aGVzZSBnZW9tcyB3aGVuZXZlciB5b3UgbWFwIGFuIGFlc3RoZXRpYyB0byBhIGRpc2NyZXRlIHZhcmlhYmxlIChhcyBpbiB0aGUgX19saW5ldHlwZV9fIGV4YW1wbGUpLiBJdCBpcyBjb252ZW5pZW50IHRvIHJlbHkgb24gdGhpcyBmZWF0dXJlIGJlY2F1c2UgdGhlIGdyb3VwIGFlc3RoZXRpYyBieSBpdHNlbGYgZG9lcyBub3QgYWRkIGEgbGVnZW5kIG9yIGRpc3Rpbmd1aXNoaW5nIGZlYXR1cmVzIHRvIHRoZSBnZW9tcy4KCmBgYHtyfQojIExlZnQKZ2dwbG90KGRhdGEgPSBtcGcpICsKICBnZW9tX3Ntb290aChtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgeSA9IGh3eSkpCgojIENlbnRlcgpnZ3Bsb3QoZGF0YSA9IG1wZykgKwogIGdlb21fc21vb3RoKG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5LCBncm91cCA9IGRydikpCgojIFJpZ2h0CmdncGxvdChkYXRhID0gbXBnKSArCiAgZ2VvbV9zbW9vdGgobWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3ksIGNvbG9yID0gZHJ2KSwKICAgICAgICAgICAgICBzaG93LmxlZ2VuZCA9IEZBTFNFKQpgYGAKClRvIGRpc3BsYXkgbXVsdGlwbGUgZ2VvbXMgaW4gdGhlIHNhbWUgcGxvdCwgYWRkIG11bHRpcGxlIGdlb20gZnVuY3Rpb25zIHRvIF9fZ2dwbG90KClfXzoKCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IG1wZykgKwogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3ksIGNvbG9yID0gZHJ2KSkgKwogIGdlb21fc21vb3RoKG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5LCBncm91cCA9IGRydiwgbGluZXR5cGUgPSBkcnYpKQpgYGAKClRoaXMsIGhvd2V2ZXIsIGludHJvZHVjZXMgc29tZSBkdXBsaWNhdGlvbiBpbiBvdXIgY29kZS4gSW1hZ2luZSBpZiB5b3Ugd2FudGVkIHRvIGNoYW5nZSB0aGUgeS1heGlzIHRvIGRpc3BsYXkgX19jdHlfXyBpbnN0ZWFkIG9mIF9faHd5X18uIFlvdSdkIG5lZWQgdG8gY2hhbmdlIHRoZSB2YXJpYWJsZSBpbiB0d28gcGxhY2VzLCBhbmQgeW91IG1pZ2h0IGZvcmdldCB0byB1cGRhdGUgb25lLiBZb3UgY2FuIGF2b2lkIHRoaXMgdHlwZSBvZiByZXBldGl0aW9uIGJ5IHBhc3NpbmcgYSBzZXQgb2YgbWFwcGluZ3MgdG8gX19nZ3Bsb3QoKV9fLiBfX2dncGxvdDJfXyB3aWxsIHRyZWF0IHRoZXNlIG1hcHBpbmdzIGFzIGdsb2JhbCBtYXBwaW5ncyB0aGF0IGFwcGx5IHRvIGVhY2ggZ2VvbSBpbiB0aGUgZ3JhcGguIEluIG90aGVyIHdvcmRzLCB0aGlzIGNvZGUgd2lsbCBwcm9kdWNlIHRoZSBzYW1lIHBsb3QgYXMgdGhlIHByZXZpb3VzIGNvZGU6CgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBtcGcsIGFlcyh4ID0gZGlzcGwsIHkgPSBjdHkpKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX3Ntb290aCgpCmBgYAoKSWYgeW91IHBsYWNlIG1hcHBpbmdzIGluIGEgZ2VvbSBmdW5jdGlvbiwgZ2dwbG90MiB3aWxsIHRyZWF0IHRoZW0gYXMgbG9jYWwgbWFwcGluZ3MgZm9yIHRoZSBsYXllci4gSXQgd2lsbCB1c2UgdGhlc2UgbWFwcGluZ3MgdG8gZXh0ZW5kIG9yIG92ZXJ3cml0ZSB0aGUgZ2xvYmFsIG1hcHBpbmdzICpmb3IgdGhhdCBsYXllciBvbmx5Ki4gVGhpcyBtYWtlcyBpdCBwb3NzaWJsZSB0byBkaXNwbGF5IGRpZmZlcmVudCBhZXNldGhldGljcyBpbiBkaWZmZXJlbnQgbGF5ZXJzLgoKYGBge3J9CmdncGxvdChkYXRhID0gbXBnLCBtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgeSA9IGh3eSkpICsKICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoY29sb3IgPSBkcnYpKSArCiAgZ2VvbV9zbW9vdGgobWFwcGluZyA9IGFlcyhncm91cCA9IGRydiwgbGluZXR5cGUgPSBkcnYpKQpgYGAKCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IG1wZywgbWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3kpKSArCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKGNvbG9yID0gY2xhc3MpKSArCiAgZ2VvbV9zbW9vdGgoKQpgYGAKCllvdSBjYW4gdXNlIHRoZSBzYW1lIGlkZWEgdG8gc3BlY2lmeSBkaWZmZXJlbnQgX19kYXRhX18gZm9yIGVhY2ggbGF5ZXIuIEhlcmUsIG91ciBzbW9vdGggbGluZSBkaXNwbGF5cyBqdXN0IGEgc3Vic2V0IG9mIHRoZSBfX21wZ19fIGRhdGFzZXQsIHRoZSBzdWJjb21wYWN0IGNhcnMuIFRoZSBsb2NhbCBkYXRhIGFyZ3VtZW50IGluIF9fZ2VvbV9zbW9vdGgoKV9fIG92ZXJyaWRlcyB0aGUgZ2xvYmFsIGRhdGEgYXJndW1lbnQgaW4gX19nZ3Bsb3QoKV9fIGZvciB0aGF0IGxheWVyIG9ubHkuCgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBtcGcsIG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5KSkgKwogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyhjb2xvciA9IGNsYXNzKSkgKwogIGdlb21fc21vb3RoKGRhdGEgPSBmaWx0ZXIobXBnLCBjbGFzcyA9PSAic3ViY29tcGFjdCIpLCBzZSA9IEZBTFNFKQpgYGAKCihZb3UnbGwgbGVhcm4gaG93IF9fZmlsdGVyKClfXyB3b3JrcyBpbiB0aGUgY2hhcHRlciBvbiBkYXRhIHRyYW5zZm9ybWF0aW9uczogZm9yIG5vdywganVzdCBrbm93IHRoYXQgdGhpcyBjb21tYW5kIHNlbGVjdHMgb25seSB0aGUgc3ViY29tcGFjdCBjYXJzLikKCiMjIyMgMy42LjEgRXhlcmNpc2VzCgoxLiBXaGF0IGdlb20gd291bGQgeW91IHVzZSB0byBkcmF3IGEgbGluZSBjaGF0PyBBIGJveHBsb3Q/IEEgaGlzdG9ncmFtPyBBbiBhcmVhIGNoYXJ0PwoKYGBge3J9CiMgTGluZQpnZ3Bsb3QoZGF0YSA9IG1wZywgbWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3kpKSArCiAgZ2VvbV9saW5lKCkKCiMgQm94cGxvdApnZ3Bsb3QoZGF0YSA9IG1wZywgbWFwcGluZyA9IGFlcyh4ID0gY2xhc3MgLCB5ID0gaHd5KSkgKwogIGdlb21fYm94cGxvdCgpCgojIEhpc3RvZ3JhbQpnZ3Bsb3QoZGF0YSA9IG1wZywgbWFwcGluZyA9IGFlcyh4ID0gaHd5KSkgKwogIGdlb21faGlzdG9ncmFtKCkKCiMgQXJlYSBjaGFydApnZ3Bsb3QoZGF0YSA9IG1wZywgbWFwcGluZyA9IGFlcyh4ID0gaHd5LCB5ID0gZGlzcGwpKSArCiAgZ2VvbV9hcmVhKCkKYGBgCgpUaGUgYWJvdmUgZ3JhcGhzIHNob3cgaG93IHRvIG1ha2UgdGhlIGRpZmZlcmVudCBjaGFydHMuIE5vdGUgdGhhdCB0aGUgbWFwcGluZyBhZXN0aGV0aWNzIGRvbid0IGV4YWN0bHkgbWFrZSBzZW5zZSBmb3IgZWFjaCBncmFwaC4gRm9yIGV4YW1wbGUsIHRoZSBsaW5lIGNoYXJ0IHdvdWxkIG1ha2UgbW9yZSBzZW5zZSB3aXRoIHggYXMgYSBjb250aW51b3VzIHRpbWUgdmFyaWFibGUgYW5kIHkgYmVpbmcgc29tZXRoaW5nIHN1Y2ggYXMgImF2ZyBtaWxlYWdlIG9uIHRoZSBod3kiLiAKCjIuIFJ1biB0aGlzIGNvZGUgaW4geW91ciBoZWFkIGFuZCBwcmVkaWN0IHdoYXQgdGhlIG91dHB1dCB3aWxsIGxvb2sgbGlrZS4gVGhlbiwgcnVuIHRoZSBjb2RlIGluIFIgYW5kIGNoZWNrIHlvdXIgcHJlZGljYXRpb25zLgoKYGBge3J9CmdncGxvdChkYXRhID0gbXBnLCBtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgeSA9IGh3eSwgIGNvbG9yID0gZHJ2KSkgKwogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9zbW9vdGgoc2UgPSBGQUxTRSkKYGBgCgpUaGUgYWJvdmUgY29kZSB3aWxsIHByb2R1Y2UgYSBzY2F0dGVycGxvdCBvZiBkaXNwbGFjZW1lbnQgKG9uIHRoZSB4LWF4aXMpIGFuZCBod3kgKG9uIHRoZSB5LWF4aXMpLiBQb2ludHMgd2lsbCBiZSBkaXN0aW5ndWlzaGVkIGFjY29yZGluZyB0byB0aGVpciByZXNwZWN0aXZlIGRydiB0eXBlcyB2aWEgY29sb3IgYXNzaWdubWVudCBhbmQgYSB5IH4geCBsaW5lcyB3aWxsIGJlIGRyYXduIHRocm91Z2ggdGhlIHBvaW50cyAodGhlIGxpbmUgdGhhdCBtaW5pbWl6ZXMgdGhlIHJlc2lkaXVhbHMpLCBidXQgdGhlIHNtb290aGluZyBlZmZlY3QgKHRoZSBzaGFkZWQgYXJlYSBvdXRsaW5pbmcgdGhlIHJlZ3Jlc3Npb24gbGluZSkgd2lsbCBiZSBvZmYuCgpJIHByZWRpY3RlZCBvbmx5IG9uZSBsaW5lLCB3aGVuIEkgc2hvdWxkIGhhdmUgcHJlZGljdGVkIGEgbGluZSBmb3IgZWFjaCBkcnYgdHlwZS4gVGhpcyBpcyBiZWNhdXNlIHRoZSBhZXN0aGV0aWMgb2YgY29sb3IgaGFzIGJlZW4gcGFzc2VkIGRvd24gdG8gYWxsIG9mIHRoZSBnZW9tIGZ1bmN0aW9ucy4gCgozLiBXaGF0IGRvZXMgX19zaG93LmxlZ2VuZCA9IEZBTFNFX18gZG8/IFdoYXQgaGFwcGVucyBpZiB5b3UgcmVtb3ZlIGl0PyBXaHkgZG8geW91IHRoaW5rIEkgdXNlZCBpdCBlYXJsaWVyIGluIHRoaXMgY2hhcHRlcj8KCl9fU2hvdy5sZWdlbmRfXyBkZWZhdWx0cyB0byBzaG93aW5nIHRoZSBsZWdlbmQgb2YgdGhlIGFlc3RoZXRpYyBhc3NpZ25lZCBpbiB0aGUgbWFwcGluZyBhcmd1bWVudC4gRm9yIGV4YW1wbGUsIGluIHRoZSBwcmV2aW91cyBxdWVzdGlvbiwgdGhlIGxlZ2VuZCBzaG93cyB0aGUgY29sb3IgYXNzaWdubWVudC4gSWYgeW91IGluZGljYXRlIF9fc2hvdy5sZWdlbmQgPSBGQUxTRV9fIHRoZW4gdGhlIGxlZ2VuZCB3aWxsIGJlIHR1cm5lZCBvZmYuIEJlbG93LCB3ZSBtdXN0IHNwZWNpZnkgdGhlIGxlZ2VuZCB0byBiZSBGQUxTRSBmb3IgYm90aCBnZW9tcy4KCkl0IHdhcyBsaWtlbHkgaW50cm9kdWNlZCBiZWNhdXNlIHdlIHdpbGwgYmUgd29ya2luZyB3aXRoIGl0IGxhdGVyLgoKYGBge3J9CmdncGxvdChkYXRhID0gbXBnLCBtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgeSA9IGh3eSwgIGNvbG9yID0gZHJ2KSkgKwogIGdlb21fcG9pbnQoc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIGdlb21fc21vb3RoKHNlID0gRkFMU0UsIHNob3cubGVnZW5kID0gRkFMU0UpCmBgYAoKYGBge3J9CmdncGxvdChkYXRhID0gbXBnLCBtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgeSA9IGh3eSwgIGNvbG9yID0gZHJ2KSkgKwogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9zbW9vdGgoc2UgPSBGQUxTRSkKYGBgCgo0LiB3aGF0IGRvZXMgdGhlIF9fc2VfXyBhcmd1bWVudCB0byBfX2dlb21fc21vb3RoKClfXyBkbz8KClRoZSBfX3NlX18gYXJndW1lbnQgcHJvdmlkZXMgKGlmIFRSVUUpIHRoZSBzdGFuZGFyZCBlcnJvciBpbnRlcnZhbHMgb2YgdGhlIHkgfiB4IGxpbmVzLiAKCjUuIFdpbGwgdGhlc2UgdHdvIGdyYXBocyBsb29rIGRpZmZlcmVudD8gV2h5L3doeSBub3Q/CgpgYGB7cn0KIyBMZWZ0CmdncGxvdChkYXRhID0gbXBnLCBtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgeSA9IGh3eSkpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fc21vb3RoKCkKCiMgUmlnaHQKZ2dwbG90KCkgKwogIGdlb21fcG9pbnQoZGF0YSA9IG1wZywgbWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3kpKSArCiAgZ2VvbV9zbW9vdGgoZGF0YSA9IG1wZywgbWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3kpKQpgYGAKClRoZXkgc2hvdWxkbid0IGxvb2sgZGlmZmVyZW50IG5vLiBUaGUgZmlyc3Qgb25lIGlzIGp1c3QgbW9yZSBlZmZpY2llbnQgYmVjYXVzZSB3ZSBkb24ndCBoYXZlIHRvIHNwZWNpZnkgdGhlIGRhdGEgc291cmNlIG9yIHRoZSB4IGFuZCB5IG1hcHBpbmcgY29tcG9uZW50cyB0d2ljZS4gSW4gZWl0aGVyIGNhc2UsIGdncGxvdCBqdXN0IHByb2R1Y2VzIHRoZSBjb29yZGluYXRlcyBhbmQgdGhlIGdlb20gZnVuY3Rpb25zIHByb2R1Y2UgdGhlIHJlc3BlY3RpdmUgZ2VvbSBhZXN0aGV0aWNzIG9mIHRoZSBkYXRhLgoKNi4gUmVjcmVhdGUgdGhlIFIgY29kZSBuZWNlc3NhcnkgdG8gZ2VuZXJhdGUgdGhlIGZvbGxvd2luZyBncmFwaHMuCgpgYGB7cn0KIyBUb3AgTGVmdApnZ3Bsb3QoZGF0YSA9IG1wZywgbWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3kpKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX3Ntb290aChzZSA9IEZBTFNFKQoKIyBUb3AgUmlnaHQKZ2dwbG90KGRhdGEgPSBtcGcsIG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5LCBsaW5lID0gZHJ2KSkgKwogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9zbW9vdGgoc2UgPSBGQUxTRSkKCiMgTWlkZGxlIExlZnQKZ2dwbG90KGRhdGEgPSBtcGcsIG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5LCBjb2xvciA9IGRydikpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fc21vb3RoKHNlID0gRkFMU0UpCgojIE1pZGRsZSBSaWdodApnZ3Bsb3QoZGF0YSA9IG1wZywgbWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3kpKSArCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKGNvbG9yID0gZHJ2KSkgKwogIGdlb21fc21vb3RoKHNlID0gRkFMU0UpCgojIEJvdHRvbSBMZWZ0CmdncGxvdChkYXRhID0gbXBnLCBtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgeSA9IGh3eSwgbGluZXR5cGUgPSBkcnYpKSArCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKGNvbG9yID0gZHJ2KSkgKwogIGdlb21fc21vb3RoKHNlID0gRkFMU0UpCgojIEJvdHRvbSBSaWdodApnZ3Bsb3QoZGF0YSA9IG1wZywgbWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3kpKSArCiAgZ2VvbV9wb2ludChjb2xvciA9ICJ3aGl0ZSIsIHNpemUgPSA0KSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBkcnYpKQpgYGAKClRoZSBmaW5hbCBwbG90IGlzIHRyaWNreSwgYnV0IGl0IGJhc2ljYWxseSB3b3JrcyBieSBwbG90dGluZyB0aGUgcG9pbnRzIHR3aWNlLCBidXQgcGxvdHRpbmcgdGhlIHNtYWxsZXIgY29sb3JlZCBwb2ludHMgb24gdG9wIG9mIHRoZSBsYXJnZXIgd2hpdGUgcG9pbnRzICh3aGljaCBlZmZlY3RpdmVseSBiZWNvbWUgdGhlIHN0cm9rZSkuCgojIyMgMy43IFN0YXRpc3RpY2FsIFRyYW5zZm9ybWF0aW9ucwoKTmV4dCwgbGV0J3MgdGFrZSBhIGxvb2sgYXQgYSBiYXIgY2hhcnQuIEJhciBjaGFydHMgc2VlbSBzaW1wbGUsIGJ1dCB0aGV5IGFyZSBpbnRlcmVzdGluZyBiZWNhdXNlIHRoZXkgcmV2ZWFsIHNvbWV0aGluZyBzdWJ0bGUgYWJvdXQgcGxvdHMuIENvbnNpZGVyIGEgYmFzaWMgYmFyIGNoYXJ0LCBhcyBkcmF3biB3aXRoIF9fZ2VvbV9iYXIoKV9fLiBUaGUgZm9sbG93aW5nIGNoYXJ0IGRpc3BsYXlzIHRoZSB0b3RhbCBudW1iZXIgb2YgZGlhbW9uZHMgaW4gdGhlIF9fZGlhbW9uZHNfXyBkYXRhc2V0LCBncm91cGVkIGJ5IF9fY3V0X18uIFRoZSBfX2RpYW1vbmRzX18gZGF0YXNldCBjb21lcyBpbiBnZ3Bsb3QyIGFuZCBjb250YWlucyBpbmZvcm1hdGlvbiBhYm91dCB+IDU0LDAwMCBkaWFtb25kcywgaW5jbHVkaW5nIHRoZSBfX3ByaWNlX18sIF9fY2FyYXRfXywgX19jb2xvcl9fLCBhbmQgX19jdXRfXyBvZiBlYWNoIGRpYW1vbmQuIFRoZSBjaGFydCBzaG93cyB0aGF0IG1vcmUgZGlhbW9uZHMgYXJlIGF2YWlsYWJsZSB3aXRoIGhpZ2ggcXVhbGl0eSBjdXRzIHRoYW4gd2l0aCBsb3cgcXVhbGl0eSBjdXRzLgoKYGBge3J9CmdncGxvdChkYXRhID0gZGlhbW9uZHMpICsKICBnZW9tX2JhcihtYXBwaW5nID0gYWVzKHggPSBjdXQpKQpgYGAKCk9uIHRoZSB4LWF4aXMsIHRoZSBjaGFydCBkaXNwbGF5cyBfX2N1dF9fLCBhIHZhcmlhYmxlIGZyb20gX19kaWFtb25kc19fLiBPbiB0aGUgeS1heGlzLCBpdCBkaXNwbGF5cyBjb3VudCwgYnV0IGNvdW50IGlzIG5vdCBhIHZhcmlhYmxlIGluIF9fZGlhbW9uZHNfXyEgV2hlcmUgZG9lcyBpdCBjb21lIGZyb20/IE1hbnkgZ3JhcGhzLCBsaWtlIHNjYXR0ZXJwbG90cywgcGxvdCB0aGUgcmF3IHZhbHVlcyBvZiB5b3VyIGRhdGFzZXQuIE90aGVyIGdyYXBocywgbGlrZSBiYXIgY2hhcmN0cywgY2FsY3VsYXRlIG5ldyB2YWx1ZXMgdG8gcGxvdDoKCiogYmFyIGNoYXJ0cywgaGlzdG9ncmFtcywgYW5kIGZyZXF1ZW5jeSBwb2x5Z29ucyBiaW4geW91ciBkYXRhIGFuZCB0aGVuIHBsb3QgYmluIGNvdW50cywgdGhlIG51bWJlciBvZiBwb2ludHMgdGhhdCBmYWxsIGluIGVhY2ggYmluLgoqIHNtb290aGVycyBmaXQgYSBtb2RlbCB0byB5b3VyIGRhdGEgYW5kIHRoZW4gcGxvdCBwcmVkaWN0aW9ucyBmcm9tIHRoZSBtb2RlbC4KKiBib3hwbG90cyBjb21wdXRlIGEgcm9idXN0IHN1bW1hcnkgb2YgdGhlIGRpc3RyaWJ1dGlvbiBhbmQgdGVuIGRpc3BsYXkgYSBzcGVjaWFsbHkgZm9ybWF0dGVkIGJveC4KClRoZSBhbGdvcml0aG0gdXNlZCB0byBjYWxjdWxhdGUgbmV3IHZhbHVlcyBmb3IgYSBncmFwaCBpcyBjYWxsZWQgYSBfX3N0YXRfXywgc2hvcnQgZm9yIHN0YXRpc3RpY2FsIHRyYW5zZm9ybWF0aW9uLgoKRXNzZW50aWFsbHksCgoxLiBfX2dlb21fYmFyKClfXyBiZWdpbnMgd2l0aCB0aGUgX19kaWFtb25kc19fIGRhdGEgc2V0LgoyLiBfX2dlb21fYmFyKClfXyB0cmFuc2Zvcm1zIHRoZSBkYXRhIHdpdGggdGhlICJjb3VudCIgc3RhdCwgd2hpY2ggcmV0dXJucyBhIGRhdGEgc2V0IG9mIGN1dCB2YWx1ZXMgYW5kIGNvdW50cy4KMy4gX19nZW9tX2JhcigpX18gdXNlcyB0aGUgdHJhbnNmb3JtZWQgZGF0YSB0byBidWlsZCB0aGUgcGxvdC4gY3V0IGlzIG1hcHBlZCB0byB0aGUgeGEgeGlzLCBjb3VudCBpcyBtYXBwZWQgdG8gdGhlIHkgYXhpcy4KCllvdSBjYW4gbGVhcm4gd2hpY2ggc3RhdCBhIGdlb20gdXNlcyBieSBpbnNwZWN0aW5nIHRoZSBkZWZhdWx0IHZhbHVlIGZvciB0aGUgX19zdGF0X18gYXJndW1lbnQuIEZvciBleGFtcGxlLCBfXz9nZW9tX2Jhcl9fIHNob3dzIHRoYXQgdGhlIGRlZmF1bHQgdmFsdWUgZm9yIF9fc3RhdF9fIGlzICJjb3VudCIsIHdoaWNoIG1lYW5zIHRoYXQgX19nZW9tX2JhcigpX18gdXNlcyBfX3N0YXRfY291bnQoKV9fLiBfX3N0YXRfY291bnQoKV9fIGlzIGRvY3VtZW50ZWQgb24gdGhlIHNhbWUgcGFnZSBhcyBfX2dlb21fYmFyKClfXywgYW5kIGlmIHlvdSBzY3JvbGwgZG93biB5b3UgY2FuIGZpbmQgYSBzZWN0aW9uIGNhbGxlZCAiQ29tcHV0ZWQgdmFyaWFibGVzIi4gVGhhdCBkZXNjcmliZXMgaG93IGl0IGNvbXB1dGVzIHR3byBuZXcgdmFyaWFibGVzOiBfX2NvdW50X18gYW5kIF9fcHJvcF9fLiAKCllvdSBjYW4gZ2VuZXJhbGx5IHVzZSBnZW9tcyBhbmQgc3RhdHMgaW50ZXJjaGFuZ2VhYmx5LiBGb3IgZXhhbXBsZSwgeW91IGNhbiByZWNyZWF0ZSB0aGUgcHJldmlvdXMgcGxvdCB1c2luZyBfX3N0YXRfY291bnQoKV9fIGluc3RlYWQgb2YgX19nZW9tX2JhcigpX186CgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBkaWFtb25kcykgKwogIHN0YXRfY291bnQobWFwcGluZyA9IGFlcyh4ID0gY3V0KSkKYGBgCgpUaGlzIHdvcmtzIGJlY2F1c2UgZXZlcnkgZ2VvbSBoYXMgYSBkZWZhdWx0IHN0YXQ7IGFuZCBldmVyeSBzdGF0IGhhcyBhIGRlZmF1bHQgZ2VvbS4gVGhpcyBtZWFucyB0aGF0IHlvdSBjYW4gdHlwaWNhbGx5IHVzZSBnZW9tcyB3aXRob3V0IHdvcnJ5aW5nIGFib3V0IHRoZSB1bmRlcmx5aW5nIHN0YXRpc3RpY2FsIHRyYW5zZm9ybWF0aW9uLiBUaGVyZSBhcmUgdGhyZWUgcmVhc29ucyB5b3UgbWlnaHQgbmVlZCB0byB1c2UgYSBzdGF0IGV4cGxpY2l0bHk6CgoxLiBZb3UgbWlnaHQgd2FudCB0byBvdmVycmlkZSB0aGUgZGVmYXVsdCBzdGF0LiBJbiB0aGUgY29kZSBiZWxvdywgSSBjaGFuZ2UgdGhlIHN0YXQgb2YgX19nZW9tX2JhcigpX18gZnJvbSBjb3VudCAodGhlIGRlZmF1bHQpIHRvIGlkZW50aXR5LiBUaGlzIGxldHMgbWUgbWFwIHRoZSBoZWlnaHQgb2YgdGhlIGJhcnMgdG8gdGhlIHJhdyB2YWx1ZXMgb2YgYSAqeSogdmFyaWFibGUuIFVuZm9ydHVuYXRlbHkgd2hlbiBwZW9wbGUgdGFsayBhYm91dCBiYXIgY2hhcnRzIGNhc3VhbGx5LCB0aGV5IG1pZ2h0IGJlIHJlZmVycmluZyB0byB0aGlzIHR5cGUgb2YgYmFyIGNoYXJ0LCB3aGVyZSB0aGUgaGVpZ2h0IG9mIHRoZSBiYXIgaXMgYWxyZWFkeSBwcmVzZW50IGluIHRoZSBkYXRhLCBvciB0aGUgcHJldmlvdXMgYmFyIGNoYXJ0IHdoZXJlIHRoZSBoZWlnaHQgb2YgdGhlIGJhciBpcyBnZW5lcmF0ZWQgYnkgY291bnRpbmcgcm93cy4KCmBgYHtyfQpkZW1vIDwtIHRyaWJibGUoCiAgfmN1dCwgICAgICAgfmZyZXEsCiAgIkZhaXIiLCAgICAgIDE2MTAsCiAgIkdvb2QiLCAgICAgIDQ5MDYsCiAgIlZlcnkgR29vZCIsIDEyMDgyLAogICJQcmVtaXVtIiwgICAxMzc5MSwKICAiSWRlYWwiLCAgICAgMjE1NTEKKQoKZ2dwbG90KGRhdGEgPSBkZW1vKSArCiAgZ2VvbV9iYXIobWFwcGluZyA9IGFlcyh4ID0gY3V0LCB5ID0gZnJlcSksIHN0YXQgPSAiaWRlbnRpdHkiKQpgYGAKCjIuIFlvdSBtaWdodCB3YW50IHRvIG92ZXJyaWRlIHRoZSBkZWZhdWx0IG1hcHBpbmcgZnJvbSB0cmFuc2Zvcm1lZCB2YXJpYWJsZXMgdG8gYWVzdGhldGljcy4gRm9yIGV4YW1wbGUsIHlvdSBtaWdodCB3YW50IHRvIGRpc3BsYXkgYSBiYXIgY2hhcnQgb2YgcHJvcG9ydGlvbiwgcmF0aGVyIHRoYW4gY291bnQ6CgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBkaWFtb25kcykgKwogIGdlb21fYmFyKG1hcHBpbmcgPSBhZXMoeCA9IGN1dCwgeSA9IHN0YXQocHJvcCksIGdyb3VwID0gMSkpCmBgYAoKVG8gZmluZCB0aGUgdmFyaWFibGVzIGNvbXB1dGVkIGJ5IHRoZSBzdGF0LCBsb29rIGZvciB0aGUgaGVscCBzZWN0aW9uIHRpdGxlZCAiY29tcHV0ZWQgdmFyaWFibGVzIi4KCjMuIFlvdSBtaWdodCB3YW50IHRvIGRyYXcgZ3JlYXRlciBhdHRlbnRpb24gdG8gdGhlIHN0YXRpc3RpY2FsIHRyYW5mb3JtYXRpb24gaW4geW91ciBjb2RlLiBGb3IgZXhhbXBsZSwgeW91IG1pZ2h0IHVzZSBfX3N0YXRfc3VtbWFyeSgpX18sIHdoaWNoIHN1bW1hcmlzZXMgdGhlIHkgdmFsdWVzIGZvciBlYWNoIHVuaXF1ZSB4IHZhbHVlLCB0byBkcmF3IGF0dGVudGlvbiB0byB0aGUgc3VtbWFyeSB0aGF0IHlvdSdyZSBjb21wdXRpbmc6CgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBkaWFtb25kcykgKwogIHN0YXRfc3VtbWFyeShtYXBwaW5nID0gYWVzKHggPSBjdXQsIHkgPSBkZXB0aCksCiAgICAgICAgICAgICAgIGZ1bi5taW4gPSBtaW4sCiAgICAgICAgICAgICAgIGZ1bi5tYXggPSBtYXgsCiAgICAgICAgICAgICAgIGZ1biA9IG1lZGlhbgogICAgICAgICAgICAgICApCmBgYAoKZ2dwbG90MiBwcm92aWRlcyBvdmVyIDIwIHN0YXRzIGZvciB5b3UgdG8gdXNlLiBFYWNoIHN0YXQgaXMgYSBmdW5jdGlvbiwgc28geW91IGNhbiBnZXQgaGVscCBpbiB0aGUgdXN1YWwgd2F5LCBlLmcuIF9fP3N0YXRfYmluX18uIEZUbyBzZWUgYSBjb21wbGV0ZSBsaXN0IG9mIHN0YXRzLCB0cnkgdGhlIGdncGxvdDIgY2hlYXRzaGVldC4KCiMjIyMgMy43LjEgRXhlcmNpc2VzCgoxLiBXaGF0IGlzIHRoZSBkZWZhdWx0IGdlb20gYXNzb2NpYXRlZCB3aXRoIF9fc3RhdF9zdW1tYXJ5KClfXz8gSG93IGNvdWxkIHlvdSByZXdpdGUgcHJldmlvdXMgcGxvdCB0byB1c2UgdGhhdCBnZW9tIGZ1bmN0aW9uIGluc3RlYWQgb2YgdGhlIHN0YXQgZnVuY3Rpb24/CgpgYGB7cn0KP3N0YXRfc3VtbWFyeQpnZ3Bsb3QoZGF0YSA9IGRpYW1vbmRzKSArCiAgZ2VvbV9wb2ludHJhbmdlKG1hcHBpbmcgPSBhZXMoeCA9IGN1dCwgeSA9IGRlcHRoKSwKICAgICAgICAgICAgICAgICAgc3RhdCA9ICJzdW1tYXJ5IgogICAgICAgICAgICAgICAgICApCmBgYAoKVGhlIGRlZmF1bHQgZ2VvbSBhc3NvY2lhdGVkIHdpdGggX19zdGF0X3N1bW1hcnlfXyBpcyAicG9pbnRyYW5nZSIuIEEgbWVzc2FnZSBwb3BzIHVwIGluZGljYXRpbmcgdGhhdCBubyBzdW1tYXJ5IGZ1bmN0aW9uIGhhcyBiZWVuIHN1cHBsaWVkIHNvIHRoZSBtZWFuIHN0YW5kYXJkIGVycm9ycyBhcmUgcHJvdmlkZWQgYXMgdGhlIHN1bW1hcnkgZnVuY3Rpb24uIFdlIGNhbiBpbmNsdWRlIG91ciB5IGZ1bmN0aW9ucyB0byBwcm92aWRlIHRoZSBzdW1tYXJ5IGFuZCByZWNyZWF0ZSB0aGUgZWFybGllciBncmFwaCB3aGVyZSB3ZSB1c2VkIF9fc3RhdF9zdW1tYXJ5X18uCgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBkaWFtb25kcykgKwogIGdlb21fcG9pbnRyYW5nZShtYXBwaW5nID0gYWVzKHggPSBjdXQsIHkgPSBkZXB0aCksCiAgICAgICAgICAgICAgICAgIHN0YXQgPSAic3VtbWFyeSIsCiAgICAgICAgICAgICAgICAgIGZ1bi5taW4gPSBtaW4sCiAgICAgICAgICAgICAgICAgIGZ1bi5tYXggPSBtYXgsCiAgICAgICAgICAgICAgICAgIGZ1biA9IG1lZGlhbikKYGBgCgoyLiBXaGF0IGRvZXMgX19nZW9tX2NvbCgpX18gZG8/IEhvdyBpcyBpdCBkaWZmZXJlbnQgdG8gX19nZW9tX2JhcigpX18/CgpfX2dlb21fY29sKClfXyBkaWZmZXJzIGZyb20gX19nZW9tX2JhcigpX18gaW4gdGhhdCBfX2dlb21fY29sX18gYXNzdW1lcyB0aGUgYWN0dWFsIHZhbHVlcyBvZiB0aGUgZGF0YS4gVGhlIGRlZmF1bHQgc3RhdCBmb3IgX19nZW9tX2NvbCgpX18gaXMgaWRlbnRpdHkgd2hpY2ggbWVhbnMgdGhhdCBpdCBwZXJmb3JtcyBubyB0cmFuc2Zvcm1hdGlvbiBvbiB0aGUgZGF0YSwgcmF0aGVyIGl0IHNpbXBseSBwdWxscyB0aGUgdmFsdWUgYXNzb2NpYXRlZCB3aXRoIHRoZSBjb3JyZXNwb25kaW5nIHgtdmFsdWUgYW5kIHBsb3RzIGl0IGFjY29yZGluZ2x5LgoKSW52ZXJzZWx5LCBfX2dlb21fYmFyKClfXyBoYXMgYSBkZWZhdWx0IHN0YXQgb2YgX19jb3VudF9fIG1lYW5pbmcgbm8geS1tYXBwaW5nIGlzIHJlcXVpcmVkLCByYXRoZXIgYWxsIG9mIHRoZSB4J3Mgd2lsbCBiZSBjb3VudGVkIGFuZCBwbG90dGVkIGFjY29yZGluZ2x5LgoKYGBge3J9CiMgR2VvbV9iYXIKZ2dwbG90KGRhdGEgPSBkaWFtb25kcykgKwogIGdlb21fYmFyKG1hcHBpbmcgPSBhZXMoeCA9IGN1dCkpCgojIEdlb21fY29sCmdncGxvdChkYXRhID0gZGVtbykgKwogIGdlb21fY29sKG1hcHBpbmcgPSBhZXMoeCA9IGN1dCwgeSA9IGZyZXEpKQpgYGAKCjMuIE1vc3QgZ2VvbXMgYW5kIHN0YXRzIGNvbWUgaW4gcGFpcnMgdGhhdCBhcmUgYWxtb3N0IGFsd2F5cyB1c2VkIGluIGNvbmNlcnQuIFJlYWQgdGhyb3VnaCB0aGUgZG9jdW1lbnRhdGlvbiBhbmQgbWFrZSBhIGxpc3Qgb2YgYWxsIHRoZSBwYWlycy4gV2hhdCBkbyB0aGV5IGhhdmUgaW4gY29tbW9uPwoKKHNraXBwZWQgZm9yIG5vdykKCjQuIFdoYXQgdmFyaWFibGVzIGRvZXMgX19zdGF0X3Ntb290aCgpX18gY29tcHV0ZT8gV2hhdCBwYXJhbWF0ZXJzIGNvbnRyb2wgaXRzIGJlaGF2aW9yPwoKU3RhdF9zbW9vdGggY29tcHV0ZXM6CgoqIHkgKm9yKiB4IC0gcHJlZGljdGVkIHZhbHVlCiogeW1pbiAqb3IqIHhtaW4gLSBsb3dlciBwb2ludHdpc2UgY29uZmlkZW5jZSBpbnRlcnZhbCBhcm91bmQgdGhlIG1lYW4KKiB5bWF4ICpvciogeG1heCAtIHVwcGVyIHBvaW50d2lzZSBjb25maWRlbmNlIGludGVydmFsIGFyb3VuZCB0aGUgbWVhbgoqIHNlIC0gc3RhbmRhcmQgZXJyb3IKClRoZXNlIGFyZSBmb3VuZCBpbiB0aGUgIkNvbXB1dGVkIHZhcmlhYmxlcyIgc2VjdGlvbiBvZiBfXz9zdGF0X3Ntb290aF9fLgoKX19Qb3NpdGlvbiwgbWV0aG9kLCBmb3JtdWxhLCBzZSwgbmEucm0sIG9yaWVudGF0aW9uLCBuLCBzcGFuLCBmdWxscmFuZ2UsIGxldmVsX18gYWxsIGNvbnRyb2wgaXRzIGJlaGF2aW9yLgoKYGBge3J9CiMgR2VvbV9zbW9vdGgKZ2dwbG90KGRhdGEgPSBkaWFtb25kcykgKwogIGdlb21fc21vb3RoKG1hcHBpbmcgPSBhZXMoeCA9IGNhcmF0LCB5ID0gZGVwdGgpKQoKIyBTdGF0X3Ntb290aApnZ3Bsb3QoZGF0YSA9IGRpYW1vbmRzKSArCiAgc3RhdF9zbW9vdGgobWFwcGluZyA9IGFlcyh4ID0gY2FyYXQsIHkgPSBkZXB0aCkpCmBgYAoKNS4gSW4gb3VyIHByb3BvcnRpb24gYmFyIGNoYXJ0LCB3ZSBuZWVkIHRvIHNldCBfX2dyb3VwID0gMV9fLiBXaHk/IEluIG90aGVyIHdvcmRzIHdoYXQgaXMgdGhlIHByb2JsZW0gd2l0aCB0aGVzZSB0d28gZ3JhcGhzPwoKVGhlIHByb2JsZW0gd2l0aCB0aGUgdHdvIGdyYXBocyBpcyB0aGF0IHRoZSBtYXBwaW5nIGFlc3RoZXRpYyBoYXMgbm90IGJlZW4gdG9sZCBhcyBhIHByb3BvcnRpb24gb2Ygd2hhdC4gRm9yIGV4YW1wbGUsIGluIHRoZSBzZWNvbmQgYmFyIHBsb3QsIHNpbmNlIHRoZSBwYXJhbWF0ZXIgaGFzIG5vdCBiZWVuIGFzc2lnbmVkIHRoYXQgdGhlIGRhdGEgc2hvdWxkIGJlIG1hcHBlZCBhcyBhIHByb3BvcnRpb24gb2YgdGhlIHRvdGFsIGNvdW50IG9mIGN1dHMsIGl0IHNpbXBseSBhc3N1bWVzIHRoYXQgZWFjaCByZXNwZWN0aXZlIGxldmVsIG9mIGN1dCBpcyB0aGUgZ3VpZGluZyBwcm9wb3J0aW9uLgoKV2l0aCByZXNwZWN0IHRvIHRoZSB0aGlyZCBiYXIgcGxvdCwgaXQgaXMgdHJlYXRpbmcgZWFjaCBsZXZlbCBhcyBpdHMgb3duIGVxdWFsbHkgc2l6ZWQgcHJvcG9ydGlvbiBhY3Jvc3MgYWxsIG9mIHRoZSBjdXRzLiBCZWxvdyBjbGVhbnMgdXAgdGhlIGRhdGEuCgpgYGB7cn0KIyBPcmlnaW5hbApnZ3Bsb3QoZGF0YSA9IGRpYW1vbmRzKSArCiAgZ2VvbV9iYXIobWFwcGluZyA9IGFlcyh4ID0gY3V0LCB5ID0gc3RhdChwcm9wKSwgZ3JvdXAgPSAxKSkKCmdncGxvdChkYXRhID0gZGlhbW9uZHMpICsKICBnZW9tX2JhcihtYXBwaW5nID0gYWVzKHggPSBjdXQsIHkgPSBhZnRlcl9zdGF0KHByb3ApLCBncm91cCA9IDEpKQoKZ2dwbG90KGRhdGEgPSBkaWFtb25kcykgKwogIGdlb21fYmFyKG1hcHBpbmcgPSBhZXMoeCA9IGN1dCwgeSA9IGFmdGVyX3N0YXQoY291bnQvc3VtKGNvdW50KSksIGZpbGwgPSBjb2xvcikpCmBgYAoKIyMjIDMuOCBQb3NpdGlvbiBhZGp1c3RtZW50cwoKVGhlcmUncyBvbmUgbW9yZSBwaWVjZSBvZiBtYWdpYyBhc3NvY2lhdGVkIHdpdGggYmFyIGNoYXRzLiBZb3UgY2FuIGNvbG9yIGEgYmFyIGNoYXJ0IHVzaW5nIGVpdGhlciB0aGUgX19jb2xvcl9fIGFlc3RoZXRpYywgb3IsIG1vcmUgdXNlZnVsbHksIF9fZmlsbF9fOgoKYGBge3J9CmdncGxvdChkYXRhID0gZGlhbW9uZHMpICsKICBnZW9tX2JhcihtYXBwaW5nID0gYWVzKHggPSBjdXQsIGNvbG9yID0gY3V0KSkKZ2dwbG90KGRhdGEgPSBkaWFtb25kcykgKwogIGdlb21fYmFyKG1hcHBpbmcgPSBhZXMoeCA9IGN1dCwgZmlsbCA9IGN1dCkpCmBgYAoKTm90ZSB3aGF0IGhhcHBlbnMgaWYgeW91IG1hcCB0aGUgZmlsbCBhZXN0aGV0aWMgdG8gYW5vdGhlciB2YXJpYWJsZSwgbGlrZSBfX2NsYXJpdHlfXzogdGhlIGJhcnMgYXJlIGF1dG9tYXRpY2FseSBzdGFja2VkLiBFYWNoIGNvbG9yZWQgcmVjdGFuZ2xlIHJlcHJlc2VudHMgYSBjb21iaW5hdGlvbiBvZiBfX2N1dF9fIGFuZCBfX2NsYXJpdHlfXy4KCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IGRpYW1vbmRzKSArCiAgZ2VvbV9iYXIobWFwcGluZyA9IGFlcyh4ID0gY3V0LCBmaWxsID0gY2xhcml0eSkpCmBgYAoKVGhlIHN0YWNraW5nIGlzIHBlcmZvcm1lZCBhdXRvbWF0aWNhbGx5IGJ5IHRoZSBfX3Bvc2l0aW9uIGFkanVzdG1lbnRfXyBzcGVjaWZpZWQgYnkgdGhlIF9fcG9zaXRpb25fXyBhcmd1bWVudC4gSWYgeW91IGRvbid0IHdhbnQgYSBzdGFja2VkIGJhciBjaGFydCwgeW91IGNhbiB1c2Ugb25lIG9mIHRocmVlIG90aGVyIG9wdGlvbnM6CgpfXyJpZGVudGl0eSJfXywgX18iZG9kZ2UiX18gb3IgX18iZmlsbCJfXy4KCiogX19wb3NpdGlvbiA9ICJpZGVudGl0eSJfXyB3aWxsIHBsYWNlIGVhY2ggb2JqZWN0IGV4YWN0bHkgd2hlcmUgaXQgZmFsbHMgaW4gdGhlIGNvbnRleHQgb2YgdGhlIGdyYXBoLiBUaGlzIGlzIG5vdCB2ZXJ5IHVzZWZ1bCBmb3IgYmFycywgYmVjYXVzZSBpdCBvdmVybGFwcyB0aGVtLiBUbyBzZWUgdGhhdCBvdmVybGFwcGluZyB3ZSBlaXRoZXIgbmVlZCB0byBtYWtlIHRoZSBiYXJzIHNsaWdodGx5IHRyYW5zcGFyZW50IGJ5IHNldHRpbmcgX19hbHBoYV9fIHRvIGEgc21hbGwgdmFsdWUsIG9yIGNvbXBsZXRlbHkgdHJhbnNwYXJlbnQgYnkgc2V0dGluZyBfX2ZpbGwgPSBOQV9fLgoKYGBge3J9CmdncGxvdChkYXRhID0gZGlhbW9uZHMsIG1hcHBpbmcgPSBhZXMoeCA9IGN1dCwgZmlsbCA9IGNsYXJpdHkpKSArCiAgZ2VvbV9iYXIoYWxwaGEgPSAxLzUsIHBvc2l0aW9uID0gImlkZW50aXR5IikKZ2dwbG90KGRhdGEgPSBkaWFtb25kcywgbWFwcGluZyA9IGFlcyh4ID0gY3V0LCBjb2xvciA9IGNsYXJpdHkpKSArCiAgZ2VvbV9iYXIocG9zaXRpb24gPSAiaWRlbnRpdHkiLCBmaWxsID0gTkEpCmBgYAoKVGhlIGlkZW50aXR5IHBvc2l0aW9uIGFkanVzdG1lbnQgaXMgbW9yZSB1c2VmdWwgZm9yIDJkIGdlb21zLCBsaWtlIHBvaW50cywgd2hlcmUgaXQgaXMgdGhlIGRlZmF1bHQuCgoqIF9fcG9zaXRpb24gPSAiZmlsbCJfXyB3b3JrcyBsaWtlIHN0YWNraW5nLCBidXQgbWFrZXMgZWFjaCBzZXQgb2Ygc3RhY2tlZCBiYXJzIHRoZSBzYW1lIGhlaWdodC4gVGhpcyBtYWtlcyBpdCBlYXNpZXIgdG8gY29tcGFyZSBwcm9wb3J0aW9ucyBhY3Jvc3MgZ3JvdXBzLgoKYGBge3J9CmdncGxvdChkYXRhID0gZGlhbW9uZHMpICsKICBnZW9tX2JhcihtYXBwaW5nID0gYWVzKHggPSBjdXQsIGZpbGwgPSBjbGFyaXR5KSwgcG9zaXRpb24gPSAiZmlsbCIpCmBgYAoKKiBfX3Bvc2l0aW9uID0gImRvZGdlIl9fIHBsYWNlcyBvdmVybGFwcGluZyBvYmplY3RzIGRpcmVjdGx5ICpiZXNpZGUqIG9uZSBhbm90aGVyLiBUaGlzIG1ha2VzIGl0IGVhc2llciB0byBjb21wYXJlIGluZGl2aWR1YWwgdmFsdWVzLgoKYGBge3J9CmdncGxvdChkYXRhID0gZGlhbW9uZHMpICsKICBnZW9tX2JhcihtYXBwaW5nID0gYWVzKHggPSBjdXQsIGNvbG9yID0gY2xhcml0eSksIHBvc2l0aW9uID0gImRvZGdlIiwgZmlsbCA9IE5BKQpnZ3Bsb3QoZGF0YSA9IGRpYW1vbmRzKSArCiAgZ2VvbV9iYXIobWFwcGluZyA9IGFlcyh4ID0gY3V0LCBmaWxsID0gY2xhcml0eSksIHBvc2l0aW9uID0gImRvZGdlIikKYGBgCgpUaGVyZSdzIG9uZSBvdGhlciB0eXBlIG9mIGFkanVzdG1lbnQgdGhhdCdzIG5vdCB1c2VmdWwgZm9yIGJhciBjaGFydHMsIGJ1dCBpdCBjYW4gYmUgdmVyeSB1c2VmdWwgZm9yIHNjYXR0ZXJwbG90cy4gUmVjYWxsIG91ciBmaXJzdCBzY2F0dGVycGxvdC4gRGlkIHlvdSBub3RpY2UgdGhhdCB0aGUgcGxvdCBkaXNwbGF5cyBvbmx5IDEyNiBwb2ludHMsIGV2ZW4gdGhvdWdoIHRoZXJlIGFyZSAyMzQgb2JzZXJ2YXRpb25zIGluIHRoZSBkYXRhc2V0PwoKYGBge3J9CmdncGxvdChkYXRhID0gbXBnKSArCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgeSA9IGh3eSkpCmBgYAoKVGhlIHZhbHVlcyBvZiBfX2h3eV9fIGFuZCBfX2Rpc3BsX18gYXJlIHJvdW5kZWQgc28gdGhlIHBvaW50cyBhcHBlYXIgb24gYSBncmlkIGFuZCBtYW55IHBvaW50cyBvdmVybGFwIGVhY2ggb3RoZXIuIFRoZSBwcm9ibGVtIGlzIGtub3duIGFzIF9fb3ZlcnBsb3R0aW5nX18uIFRoaXMgYXJyYW5nbWVudCBtYWtlcyBpdCBoYXJkIHRvIHNlZSB3aGVyZSB0aGUgbWFzcyBvZiB0aGUgZGF0YSBpcy4gQXJlIHRoZSBkYXRhIHBvaW50cyBzcHJlYWQgZXF1YWxseSB0aHJvdWdob3V0IHRoZSBncmFwaCwgb3IgaXMgdGhlcmUgb25lIHNwZWNpYWwgY29tYmluYXRpb24gb2YgX19od3lfXyBhbmQgX19kaXNwbF9fIHRoYXQgY29udGFpbnMgMTA5IHZhbHVlcz8KCllvdSBjYW4gYXZvaWQgdGhpcyBncmlkZGluZyBieSBzZXR0aW5nIHRoZSBwb3NpdGlvbiBhZGp1c3RtZW50IHRvICJqaXR0ZXIiLiBfX3Bvc2l0aW9uID0gImppdHRlciJfXyBhZGRzIGEgc21hbGwgYW1vdW50IG9mIHJhbmRvbSBub2lzZSB0byBlYWNoIHBvaW50LiBUaGlzIHNwcmVhZHMgdGhlIHBvaW50cyBvdXQgYmVjYXVzZSBubyB0d28gcG9pbnRzIGFyZSBsaWtlbHkgdG8gcmVjZWl2ZSB0aGUgc2FtZSBhbW91bnQgb2YgcmFuZG9tIG5vaXNlLgoKYGBge3J9CmdncGxvdChkYXRhID0gbXBnKSArCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgeSA9IGh3eSksIHBvc2l0aW9uID0gImppdHRlciIpCmBgYAoKQWRkaW5nIHJhbmRvbW5lc3Mgc2VlbXMgbGlrZSBhIHN0cmFuZ2Ugd2F5IHRvIGltcHJvdmUgeW91ciBwbG90LCBidXQgd2hpbGUgaXQgbWFrZXMgeW91ciBncmFwaCBsZXNzIGFjY3VyYXRlIGF0IHNtYWxsIHNjYWxlcywgaXQgbWFrZXMgeW91ciBncmFwaCAqbW9yZSogcmV2ZWFsaW5nIGF0IGxhcmdlIHNjYWxlcy4gQmVjYXVzZSB0aGlzIGlzIHN1Y2ggYSB1c2VmdWwgb3BlcmF0aW9uLCBnZ3Bsb3QyIGNvbWVzIHdpdGggYSBzaG9ydGhhbmQgZm9yIF9fZ2VvbV9wb2ludChwb3NpdGlvbiA9ICJqaXR0ZXIiKSA6IGdlb21faml0dGVyKClfXy4KCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IG1wZykgKwogIGdlb21faml0dGVyKG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5KSkKYGBgCgpUbyBsZWFybiBtb3JlIGFib3V0IGEgcG9zaXRpb24gYWRqdXN0bWVudCwgbG9vayB1cCB0aGUgaGVscCBwYWdlIGFzc29jaWF0ZWQgd2l0aCBlYWNoIGFkanVzdG1lbnQ6IF9fP3Bvc2l0aW9uX2RvZGdlX18sIF9fP3Bvc2l0aW9uX2ZpbGxfXywgX18/cG9zaXRpb25faWRlbnRpdHlfXywgX18/cG9zaXRpb25faml0dGVyX18sIGFuZCBfXz9wb3NpdGlvbl9zdGFja19fLgoKIyMjIyAzLjguMSBFeGVyY2lzZXMKCjEuIFdoYXQgaXMgdGhlIHByb2JsZW0gd2l0aCB0aGlzIHBsb3Q/IEhvdyBjb3VsZCB5b3UgaW1wcm92ZSBpdD8KCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IG1wZywgbWFwcGluZyA9IGFlcyh4ID0gY3R5LCB5ID0gaHd5KSkgKwogIGdlb21fcG9pbnQoKQpgYGAKClRoZSBwcm9ibGVtIHdpdGggdGhpcyBwbG90IGlzIHRoYXQgX19vdmVycGxvdHRpbmdfXyBpcyBvY2N1cmluZy4gVGhlIHZhbHVlcyBvZiBod3kgYW5kIGN0eSBhcmUgcm91bmRlZCBzbyBtYW55IHBvaW50cyBhcmUgc3RhY2tlZCBvbiB0b3Agb2YgZWFjaCBvdGhlciBtYWtpbmcgaXQgZGlmZmljdWx0IHRvIHNlZSB0aGUgKnRydWUgc2hhcGUgb2YgdGhlIGRhdGEqLiBXZSBjYW4gX19qaXR0ZXJfXyB0aGUgcGxvdCB0byBhZGQgYSBsaXR0bGUgcmFuZG9tbmVzcyBhbmQgYWRkIHRoZSB2YWx1ZXMuCgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBtcGcpICsKICBnZW9tX2ppdHRlcihtYXBwaW5nID0gYWVzKHggPSBjdHksIHkgPSBod3kpKQpgYGAKCjIuIFdoYXQgcGFyYW1ldGVycyB0byBfX2dlb21faml0dGVyKClfXyBjb250cm9sIHRoZSBhbW91bnQgb2Ygaml0dGVyaW5nPwoKYGBge3J9Cj9nZW9tX2ppdHRlcgpgYGAKCl9fd2lkdGhfXyBhbmQgX19oZWlnaHRfXyBjb250cm9sIHRoZSBhbW91bnQgb2Ygaml0dGVyaW5nLgoKMy4gQ29tcGFyZSBhbmQgY29udHJhc3QgX19nZW9tX2ppdHRlcigpX18gd2l0aCBfX2dlb21fY291bnQoKV9fLgoKYGBge3J9Cj9nZW9tX2ppdHRlcgpgYGAKCmBgYHtyfQo/Z2VvbV9jb3VudApgYGAKCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IG1wZykgKwogIGdlb21faml0dGVyKG1hcHBpbmcgPSBhZXMoeCA9IGN0eSwgeSA9IGRpc3BsKSkKZ2dwbG90KGRhdGEgPSBtcGcpICsKICBnZW9tX2NvdW50KG1hcHBpbmcgPSBhZXMoeCA9IGN0eSwgeSA9IGRpc3BsKSkKYGBgCgpCb3RoIF9fZ2VvbV9qaXR0ZXJfXyBhbmQgX19nZW9tX19jb3VudF9fIGFyZSB1c2VkIHRvIGFkZHJlc3MgdGhlIGlzc3VlIG9mIG92ZXJsYXBwaW5nIGluIHBvaW50IChzY2F0dGVyKSBwbG90cy4gSG93ZXZlciwgdGhleSBhZGRyZXNzIHRoZSBpc3N1ZSBpbiBkaWZmZXJlbnQgd2F5cy4gSml0dGVyIGFkZHMgYSBsaXR0bGUgYml0IG9mIHJhbmRvbW5lc3MgdG8gZWFjaCBwb2ludCB0byBmdXJ0aGVyIHNjYXR0ZXIgdGhlIHBsb3QgKGJhc2ljYWxseSAiZGVjbHVtcCIgdGhlbSkuIFdoZXJlYXMgX19nZW9tX2NvdW50X18gZXNzZW50aWFsbHkgYXNzaWducyBwcm9wb3J0aW9ucyB0byBhIGxvY2F0aW9uIGFuZCBtYXBzIHRoZSBjb3VudCB0byBwb2ludCBhcmVhLiBJdCBiYXNpY2FsbHkgY3JlYXRlcyBiaWdnZXIgcG9pbnRzIGluIGFyZWFzIHdoZXJlIHBvaW50cyBhcmUgbW9yZSBjbG9zZWx5IGNsdXN0ZXJlZC4KCjQuIFdoYXQncyB0aGUgZGVmYXVsdCBwb3NpdGlvbiBhZGp1c3RtZW50IGZvciBfX2dlb21fYm94cGxvdCgpX18/IENyZWF0ZSBhIHZpc3VhbGlzYXRpb24gb2YgdGhlIF9fbXBnX18gZGF0YXNldCB0aGF0IGRlbW9uc3RyYXRlcyBpdC4KCmBgYHtyfQo/Z2VvbV9ib3hwbG90CmBgYAoKVGhlIGRlZmF1bHQgcG9zaXRpb24gYWRqdXN0bWVudCBmb3IgX19nZW9tX2JveHBsb3QoKV9fIGlzICpkb2RnZTIqLgoKYGBge3J9CmdncGxvdChkYXRhID0gbXBnKSArCiAgZ2VvbV9ib3hwbG90KG1hcHBpbmcgPSBhZXMoeCA9IGRydiwgeSA9IGh3eSwgY29sb3IgPSBjbGFzcykpCmBgYAoKIyMjIDMuOSBDb29yZGluYXRlIHN5c3RlbXMKCkNvb3JkaW5hdGUgc3lzdGVtcyBhcmUgcHJvYmFibHkgdGhlIG1vc3QgY29tcGxpY2F0ZWQgcGFydCBvZiBnZ3Bsb3QyLiBUaGUgZGVmYXVsdCBjb29yZGluYXRlIHN5c3RlbSBpcyB0aGUgQ2FydGVzaWFuIGNvb3JkaW5hdGUgc3lzdGVtIHdoZXJlIHRoZSBfX3hfXyBhbmQgX195X18gcG9zaXRpb25zIGFjdCBpbmRlcGVuZGVudGx5IHRvIGRldGVybWluZSB0aGUgbG9jYXRpb24gb2YgZWFjaCBwb2ludC4gVGhlcmUgYXJlIGEgbnVtYmVyIG9mIG90aGVyIGNvb3JkaW5hdGUgc3lzdGVtcyB0aGF0IGFyZSBvY2Nhc2lvbmFsbHkgaGVscGZ1bC4KCiogX19jb29yZF9mbGlwKClfXyBzd2l0Y2hlcyB0aGUgeCBhbmQgeSBheGVzLiBUaGlzIGlzIHVzZWZ1bCAoZm9yIGV4YW1wbGUpLCBpZiB5b3Ugd2FudCBob3Jpem9udGFsIGJveHBsb3RzLiBJdCdzIGFsc28gdXNlZnVsIGZvciBsb25nIGxhYmVsczogaXQncyBoYXJkIHRvIGdldCB0aGVtIHRvIGZpdCB3aXRob3V0IG92ZXJsYXBwaW5nIG9uIHRoZSB4LWF4aXMuCgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBtcGcsIG1hcHBpbmcgPSBhZXMoeCA9IGNsYXNzLCB5ID0gaHd5KSkgKwogIGdlb21fYm94cGxvdCgpCmdncGxvdChkYXRhID0gbXBnLCBtYXBwaW5nID0gYWVzKHggPSBjbGFzcywgIHkgPSBod3kpKSArCiAgZ2VvbV9ib3hwbG90KCkgKwogIGNvb3JkX2ZsaXAoKQpgYGAKCiogX19jb29yZF9xdWlja21hcCgpX18gc2V0cyB0aGUgYXNwZWN0IHJhdGlvIGNvcnJlY3RseSBmb3IgbWFwcy4gVGhpcyBpcyB2ZXJ5IGltcG9ydGFudCBpZiB5b3UncmUgcGxvdHRpbmcgc3BhdGlhbCBkYXRhIHdpdGggZ2dwbG90MiAod2hpY2ggdW5mb3J0dW5hdGVseSB3ZSBkb24ndCBoYXZlIHRoZSBzcGFjZSB0byBjb3ZlciBpbiB0aGlzIGJvb2spLgoKYGBge3J9Cm56IDwtIG1hcF9kYXRhKCJueiIpCgpnZ3Bsb3QobnosIGFlcyhsb25nLCBsYXQsIGdyb3VwID0gZ3JvdXApKSArCiAgZ2VvbV9wb2x5Z29uKGZpbGwgPSAid2hpdGUiLCBjb2xvciA9ICJibGFjayIpCgpnZ3Bsb3QobnosIGFlcyhsb25nLCBsYXQsIGdyb3VwID0gZ3JvdXApKSArCiAgZ2VvbV9wb2x5Z29uKGZpbGwgPSAid2hpdGUiLCBjb2xvciA9ICJibGFjayIpICsKICBjb29yZF9xdWlja21hcCgpCmBgYAoKKiBfX2Nvb3JkX3BvbGFyKClfXyB1c2VzIHBvbGFyIGNvb3JkaW5hdGVzLiBQb2xhciBjb29yZGluYXRlcyByZXZlYWwgYW4gaW50ZXJlc3RpbmcgY29ubmVjdGlvbiBiZXR3ZWVuIGEgYmFyIGNoYXJ0IGFuZCBhIENveGNvbWIgY2hhcnQuCgpgYGB7cn0KYmFyIDwtIGdncGxvdChkYXRhID0gZGlhbW9uZHMpICsKICBnZW9tX2JhcigKICAgIG1hcHBpbmcgPSBhZXMoeCA9IGN1dCwgZmlsbCA9IGN1dCksCiAgICBzaG93LmxlZ2VuZCA9IEZBTFNFLAogICAgd2lkdGggPSAxCiAgKSArCiAgdGhlbWUoYXNwZWN0LnJhdGlvID0gMSkgKwogIGxhYnMoeCA9IE5VTEwsIHkgPSBOVUxMKQoKYmFyICsgY29vcmRfZmxpcCgpCmJhciArIGNvb3JkX3BvbGFyKCkKYGBgCgojIyMjIDMuOS4xIEV4ZXJjaXNlcwoKMS4gVHVybiBhIHN0YWNrZWQgYmFyIGNoYXJ0IGludG8gYSBwaWUgY2hhcnQgdXNpbmcgX19jb29yZF9wb2xhcigpX18uCgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBkaWFtb25kcykgKwogIGdlb21fYmFyKG1hcHBpbmcgPSBhZXMoeCA9IGN1dCwgZmlsbCA9IGN1dCkpICsKICBjb29yZF9wb2xhcigpCmBgYAoKMi4gV2hhdCBkb2VzIF9fbGFicygpX18gZG8/IFJlYWQgdGhlIGRvY3VtZW50YXRpb24uCgpgYGB7cn0KP2xhYnMoKQpgYGAKCl9fbGFicygpX18gbW9kaWZpZXMgYXhlcywgbGVnZW5kcywgYW5kIHBsb3QgbGFiZWxzLgoKMy4gV2hhdCdzIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gX19jb29yZF9xdWlja21hcCgpX18gYW5kIF9fY29vcmRfbWFwKClfXz8KCihza2lwKQoKNC4gV2hhdCBkb2VzIHRoZSBwbG90IGJlbG93IHRlbGwgeW91IGFib3V0IHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBjaXR5IGFuZCBoaWdod2F5IG1wZz8gV2h5IGlzIF9fY29vcmRfZml4ZWQoKV9fIGltcG9ydGFudD8gV2hhdCBkb2VzIF9fZ2VvbV9hYmxpbmUoKV9fIGRvPwoKYGBge3J9CmdncGxvdChkYXRhID0gbXBnLCBtYXBwaW5nID0gYWVzKHggPSBjdHksIHkgPSBod3kpKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX2FibGluZSgpCmBgYAoKYGBge3J9CmdncGxvdChkYXRhID0gbXBnLCBtYXBwaW5nID0gYWVzKHggPSBjdHksIHkgPSBod3kpKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX2FibGluZSgpICsKICBjb29yZF9maXhlZCgpCmBgYAoKVGhlIHBsb3QgYWJvdmUgdGVsbHMgdXMgdGhhdCB0aGVyZSBpcyBhIHBvc2l0aXZlIGxpbmVhciByZWxhdGlvbnNoaXAgYmV0d2VlbiBjaXR5IGFuZCBoaWdod2F5IG1pbGVzIHBlciBnYWxsb24uIEFzIGVpdGhlciBvZiB0aGUgdHdvIHZhcmlhYmxlcyBpbmNyZWFzZXMsIHRoZSBvdGhlciBpbmNyZWFzZXMgYXQgYSBjb25zdGFudCByYXRlIHdpdGggaXQuIAoKYGBge3J9Cj9nZW9tX2FibGluZQpgYGAKCl9fZ2VvbV9hYmxpbmVfXyBhZGRzIGEgcmVmZXJlbmNlIGxpbmUuCgpgYGB7cn0KP2Nvb3JkX2ZpeGVkCmBgYAoKX19jb29yZF9maXhlZF9fIGlzIGltcG9ydGFudCBiZWNhdXNlIGl0IGFzc2lnbnMgYSBmaXhlZCBzY2FsZSB0byB0aGUgY29vcmRpbmF0ZSBzeXN0ZW1zIHNwZWNpZmllZCBieSB0aGUgcmF0aW9uIGJldHdlZW4gdGhlIHBoeXNpY2FsIHJlcHJlc2VudGF0aW9uIG9mIGRhdGEgdW5pdHMgb24gdGhlIGF4ZXMuIFRoZSByYXRpbyByZXByZXNlbnRzIHRoZSBudW1iZXIgb2YgdW5pdHMgb24gdGhlIHktYXhpcyBlcXVpdmFsZW50IHRvIG9uZSB1bml0IG9uIHRoZSB4LWF4aXMuCgpJdCB0aHVzIHByb3ZpZGVzIGFuIGVhc2llciBpbnRlcnByZXRhdGlvbiBvZiB0aGUgc2xvcGUgb2YgdGhlIGNvZWZmaWNpZW50IG9mIHRoZSBhYmxpbmUgb3IgbW9yZSBzcGVjaWZpY2FsbHkgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIF9fY3R5X18gYW5kIF9faHd5X18gbWlsZXMgcGVyIGdhbGxvbi4g