1 A Quick Introduction to Base R Graphics

1.1 Creating an exploratory plot array

In this exercise, you’ll construct a simple exploratory plot from a data frame that gives values for three variables, recorded over two winter heating seasons. The variables are:

  • Temp: a measure of the outside temperature during one week
  • Gas: the amount of heating gas consumed during that week
  • Insul: a categorical variable with two values, indicating whether the measurements were made before or after an insulation upgrade was made to the house

1.1.1 Instructions

  • Load the MASS package to make the whiteside data frame available.
  • Apply the plot() function to the whiteside data frame.

1.2 Creating an explanatory scatterplot

In constrast to the exploratory analysis plot you created in the previous exercise, this exercise asks you to create a simple explanatory scatterplot, suitable for sharing with others.

Here, it is important to make editorial choices in constructing this plot, rather than depending entirely on default options. In particular, the important editorial aspects of this plot are: first, the variables to be plotted, and second, the axis labels, which are specified as strings to the xlab and ylab arguments to the plot() function.

1.2.1 Instructions

  • Use the plot() function to construct a scatterplot of the heating gas consumption, Gas, versus the outside temperature, Temp, from the whiteside data frame. Label the x- and y-axes to indicate the variables in the plot (i.e. "Outside temperature" and "Heating gas consumption", respectively.)

1.3 The plot() function is generic

One of the key features of the plot() function is that it is generic, meaning that the results of applying the function depend on the nature of the object to which it is applied.

In the first exercise of this chapter, applying the plot() function to the whiteside data frame resulted in a plot array. Here, we obtain a fundamentally different kind of result when we apply the same function to Insul, a factor variable from the same data frame.

1.3.1 Instructions

  • Apply the plot() function to the Insul variable from the whiteside data frame.

1.4 Adding details to a plot using point shapes, color, and reference lines

Adding additional details to your explanatory plots can help emphasize certain aspects of your data. For example, by specifying the pch and col arguments to the plot() function, you can add different point shapes and colors to show how different variables or subsets of your data relate to each other. In addition, you can add a new set of points to your existing scatterplot with the points() function, and add reference lines with the abline() function.

This exercise asks you to use these methods to create an enhanced scatterplot that effectively shows how three variables in the Cars93 data frame relate to each other. These variables are:

  • Price: the average sale price for a car
  • Max.Price: the highest recorded price for that car
  • Min.Price: the lowest recorded price for that car

1.4.1 Instructions

  • Load the MASS package to make the Cars93 data frame available.
  • Use the plot() function to create a scatterplot of the Max.Price variable versus the Price variable, specifying the pch and col parameters so the data points are represented as red solid triangles. The pch value to plot solid triangles is 17.
  • Use the points() function to add a second set of points to your scatterplot, representing Min.Price versus Price, where the new data points are represented as blue solid circles. The pch value for solid circles is 16.
  • Use the abline() function to add a dashed equality reference line (i.e., a line with y-intercept 0 and slope 1). See abline() to learn what arguments a and b refer to.

1.5 Creating multiple plot arrays

You can plot multiple graphs on a single pane using the par() function with its mfrow parameter. For example, par(mfrow = c(1, 2)) creates a plot array with 1 row and 2 columns, allowing you to view two graphs side-by-side. This way, you can compare and contrast different datasets or different views of the same dataset. This exercise asks you to compare two views of the Animals2 dataset from the robustbase package, differing in how its variables are represented.

The objective of this exercise is to emphasize that the original representation of the variables that we have in a dataset is not always the best one for visualization or analysis. By representing the original variables in log scale, for example, we can better see and understand the data.

1.5.1 Instructions

  • Load the robustbase package to make the Animals2 data frame available.
  • Use the par() function and set the mfrow parameter to create a side-by-side plot array with 1 row and 2 columns.
  • Use the plot() function to create a scatterplot of the variables brain versus body from this data frame, without specifying additional arguments.
  • See what happens when you run title("Original representation") after your first call to plot().
  • Use the plot() function again, but this time with log = "xy", to generate a plot of both the x and y variables in log scale.
  • Use the title() function to add "Log-log plot" as the title to the second plot.

1.6 Avoid pie charts

The same dataset can be displayed or summarized in many different ways, but some are much more suitable than others.

Despite their general popularity, pie charts are often a poor choice. Though R allows pie charts with the pie() function, even the help file for this function argues against their use. Specifically, the help file includes a “Note” that begins with the words: “Pie charts are a very bad way of displaying information.”

Bar charts are a recommended alternative and, in this exercise, you’ll see why.

1.6.1 Instructions

  • Load the insuranceData package and use the data() function to load the dataCar data frame from this package.
  • Use the par() function and set the mfrow parameter to create a side-by-side plot array with 1 row and 2 columns.
  • Use the table() function and the sort() function to create a table of counts of the distinct levels of the veh_body variable in the dataCar data frame, in decreasing order. Call this table tbl.
  • Pass tbl to the pie() function to create a pie chart representation of this data as the left-hand plot. Use title() to title this plot "Pie chart".
  • Similarly, use the barplot() and title() functions to create a barplot representation of the same data, specifying las = 2 to make both sets of labels perpendicular to the axes, and using cex.names = 0.5 to make the name labels half the default size. Title this plot "Bar chart".

2 Different Plot Types

2.1 The hist() and truehist() functions

Histograms are probably the best-known way of looking at how the values of a numerical variable are distributed over their range, and R provides several different histogram implementations.

The purpose of this exercise is to introduce two of these:

  • hist() is part of base R and its default option yields a histogram based on the number of times a record falls into each of the bins on which the histogram is based.
  • truehist() is from the MASS package and scales these counts to give an estimate of the probability density.

2.1.1 Instructions

  • Use the par() function to set the mfrow parameter for a side-by-side array of two plots.
  • Use the hist() function to generate a histogram of the Horsepower variable from the Cars93 data frame. Set its main argument equal to the title of the plot, "hist() plot".
  • Use the truehist() function to generate an alternative histogram of the same variable. Title this plot, "truehist() plot" by specifying its main argument accordingly.

2.2 Density plots as smoothed histograms

While they are probably not as well known as the histogram, density estimates may be regarded as smoothed histograms, designed to give a better estimate of the density function for a random variable.

In this exercise, you’ll use the ChickWeight dataset, which contains a collection of chicks’ weights. You will first select for the chicks that are 16 weeks old. Then, you’ll create a histogram using the truehist() function, and add its density plot on top, using the lines() and density() functions with their default options. The density plot of this type of variable is often expected to conform approximately to the bell-shaped curve, otherwise known as the Gaussian distribution. Let’s find out whether that’s the case for this dataset.

2.2.1 Instructions

  • Create the variable index16 using the which() function that selects records from the ChickWeight data frame with Time equal to 16.
  • Create the variable weights that gives the weights of the 16-week old chicks.
  • Use the truehist() function to generate a histogram from weights.
  • Use the lines() and density() functions to overlay a density plot of the weights values on the histogram.

2.3 Using the qqPlot() function to see many details in data

A practical limitation of both histograms and density estimates is that, if we want to know whether the Gaussian distribution assumption is reasonable for our data, it is difficult to tell.

The quantile-quantile plot, or QQ-plot, is a useful alternative: we sort our data, plot it against a specially-designed x-axis based on our reference distribution (e.g., the Gaussian “bell curve”), and look to see whether the points lie approximately on a straight line. In R, several QQ-plot implementations are available, but the most convenient one is the qqPlot() function in the car package.

The first part of this exercise applies this function to the 16-week chick weight data considered in the last exercise, to show that the Gaussian distribution appears to be reasonable here. The second part of the exercise applies this function to another variable where the Gaussian distribution is obviously a poor fit, but the results also show the presence of repeated values (flat stretches in the plot) and portions of the data range where there are no observations (vertical “jumps” in the plot).

2.3.1 Instructions

  • Load the car package to make the qqPlot() function available for use.
  • Create the variable index16 using the which() function that selects records from the ChickWeight data frame with Time equal to 16.
  • Create the variable weights that gives the weights of the 16-week old chicks.
  • Apply the qqPlot() function to the weights data, noting that almost all of the points fall within the confidence intervals around the reference line, indicating a reasonable conformance with the Gaussian distribution for this data sequence.
  • Apply the qqPlot() function to the tax variable from the Boston data frame in the MASS package.

2.4 The sunflowerplot() function for repeated numerical data

A scatterplot represents each (x, y) pair in a dataset by a single point. If some of these pairs are repeated (i.e. if the same combination of x and y values appears more than once and thus lie on top of each other), we can’t see this in a scatterplot. Several approaches have been developed to deal with this problem, including jittering, which adds small random values to each x and y value, so repeated points will appear as clusters of nearby points.

A useful alternative that is equally effective in representing repeated data points is the sunflowerplot, which represents each repeated point by a “sunflower,” with one “petal” for each repetition of a data point.

This exercise asks you to construct both a scatterplot and a sunflowerplot from the same dataset, one that contains repeated data points. Comparing these plots allows you to see how much information can be lost in a standard scatterplot when some data points appear many times.

2.4.1 Instructions

  • Use the par() function to set the mfrow parameter for a side-by-side plot array.
  • For the left-hand plot, use the plot() function to construct a scatterplot of the rad variable versus the zn variable, both from the Boston data frame in the MASS package.
  • Use the title() function to add the title "Standard scatterplot" to this plot.
  • For the right-hand plot, apply the sunflowerplot() function to the same data to see the presence of repeated data points, not evident from the scatterplot on the left.
  • Use the title() function to add the title "Sunflower plot".

2.5 Useful options for the boxplot() function

The boxplot() function shows how the distribution of a numerical variable y differs across the unique levels of a second variable, x. To be effective, this second variable should not have too many unique levels (e.g., 10 or fewer is good; many more than this makes the plot difficult to interpret).

The boxplot() function also has a number of optional parameters and this exercise asks you to use three of them to obtain a more informative plot:

  • varwidth allows for variable-width boxplots that show the different sizes of the data subsets.
  • log allows for log-transformed y-values.
  • las allows for more readable axis labels.

This exercise also illustrates the use of the formula interface: y ~ x indicates that we want a boxplot of the y variable across the different levels of the x variable. See ?boxplot for more details.

2.5.1 Instructions

  • Using the formula interface, create a boxplot showing the distribution of numerical crim values over the different distinct rad values from the Boston data frame. Use the varwidth parameter to obtain variable-width boxplots, specify a log-transformed y-axis, and set the las parameter equal to 1 to obtain horizontal labels for both the x- and y-axes.
  • Use the title() function to add the title "Crime rate vs. radial highway index".

2.6 Using the mosaicplot() function

A mosaic plot may be viewed as a scatterplot between categorical variables and it is supported in R with the mosaicplot() function.

As this example shows, in addition to categorical variables, this plot can also be useful in understanding the relationship between numerical variables, either integer- or real-valued, that take only a few distinct values.

More specifically, this exercise asks you to construct a mosaic plot showing the relationship between the numerical carb and cyl variables from the mtcars data frame, variables that exhibit 6 and 3 unique values, respectively.

2.6.1 Instructions

  • Apply the mosaicplot() function with the formula interface to see how the levels of the carb variable vary with the levels of the cyl variable from the mtcars data frame.

2.7 Using the bagplot() function

A single box plot gives a graphical representation of the range of variation in a numerical variable, based on five numbers:

  • The minimum and maximum values
  • The median (or “middle”) value
  • Two intermediate values called the lower and upper quartiles

In addition, the standard box plot computes a nominal data range from three of these numbers and flags points falling outside this range as outliers, representing them as distinct points.

The bag plot extends this representation to two numerical variables, showing their relationship, both within two-dimensional “bags” corresponding to the “box” in the standard boxplot, and indicating outlying points outside these limits.

This exercise asks you to construct, first, side-by-side box plots of the Min.Price and Max.Price variables from the mtcars dataset, and then to use the bagplot() function from the aplpack package to construct the corresponding bag plot.

2.7.1 Instructions

  • Use the boxplot() function to construct side-by-side box plots for Min.Price and Max.Price from the Cars93 data frame.
  • Load the aplpack package to make the bagplot() function available.
  • Construct the bag plot showing the relationship between the Min.Price and Max.Price variables from the Cars93 data frame. Use the cex parameter to make the point sizes in this plot 20 percent larger than the default size.
  • Use the abline() function to add a dashed equality reference line with intercept 0 and slope 1.

2.8 Plotting correlation matrices with the corrplot() function

Correlation matrices were introduced in the video as a useful tool for obtaining a preliminary view of the relationships between multiple numerical variables.

This exercise asks you to use the corrplot() function from the corrplot package to visualize this correlation matrix for the numerical variables from the UScereal data frame in the MASS package. Recall that in this version of these plots, ellipses that are thin and elongated indicate a large correlation value between the indicated variables, while ellipses that are nearly circular indicate correlations near zero.

2.8.1 Instructions

  • Create a subset of the UScereal data frame that contains only the 9 numerical (i.e., non-factor) variables. Save the result as numericalVars.
  • Apply the cor() function to this subset to compute the correlation matrix containing the correlation coefficients between all variable pairs. Save the result as corrMat.
  • Apply the corrplot() function to display this correlation matrix, using the "ellipse" method.
  • Which two variables are most highly correlated with potassium?

2.9 Building and plotting rpart() models

It was noted in the video that decision trees represent a popular form of predictive model because they are easy to visualize and explain. It was also noted that the rpart package is probably the most popular of several R packages that can be used to build and visualize these models.

This exercise asks you to, first, build a decision tree model using the rpart() function from this package, and then display the resulting model structure using the generic functions plot() and text().

2.9.1 Instructions

  • Load the rpart package to make the rpart() modeling function and the associated methods for generic functions like plot() available.
  • Use the rpart() function to fit a decision tree model tree_model that predicts medv in the Boston data frame from all of the other variables in this data frame.
  • Apply the plot() function to tree_model to obtain an unlabelled plot of the structure of this decision tree model.
  • Apply the text() function to tree_model to label this plot. To make the labels easier to read, use the cex parameter to reduce the text to 70% of the default size.

3 Adding Details to Plots

3.1 Introduction to the par() function

You already saw how the mfrow parameter to the par() function could be used to plot multiple graphs in one pane. The par() function also allows you to set many other graphics parameters, whose values will remain in effect until they are reset by a subsequent par() call.

Specifically, a call to the par() function with no parameters specified will return a list whose element names each specify a graphics parameter and whose element values specify the corresponding default values of these parameters. These parameters may be set by a call in the form par(name = value) where name is the name of the parameter to be set and value is the value to be assigned to this parameter.

The purpose of this exercise is to give an idea of what these graphics parameters are. In the subsequent exercises we’ll show how some of these parameters can be used to enhance plot results.

3.1.1 Instructions

  • Capture the return from the par() function as the character vector plot_pars.
  • Show the names of these graphics parameters by calling names() on plot_pars.
  • Show the number of parameters in this list by calling length().

3.2 Exploring the type option

One of the important graphics parameters that can be set with the par() function is mfrow, which specifies the numbers of rows and columns in an array of plots. Valid values for this parameter are two-element numerical vectors, whose first element specifies the number of rows in the plot array and the second element specifies the number of rows.

A more detailed discussion of using the mfrow parameter is given in Chapter 4 of this course. For now, note that to specify a plot array with three rows and one column, the command would be par(mfrow = c(3, 1)).

The following exercise also introduces the type parameter for the plot() command, which specifies how the plot is drawn. The specific type values used here are:

  • "p" for “points”
  • "l" for “lines”
  • "o" for “overlaid” (i.e., lines overlaid with points)
  • "s" for “steps”

3.2.1 Instructions

  • Use the par() function to set the mfrow parameter for a two-by-two plot array.
  • Generate a plot of brain weights from the Animals2 data frame, with observations plotted as points and the title "points" by calling the title() function.
  • Repeat, with observations plotted as lines and the title "lines".
  • Repeat, with observations plotted as overlaid points and lines and the title "overlaid".
  • Repeat, with observations plotted as steps and the title "steps".

3.3 The surprising utility of the type “n” option

The type = "n" option was discussed in the video and this exercise provides a simple example. This option is especially useful is when we are plotting data from multiple sources on a common set of axes. In such cases, we can compute ranges for the x- and y-axes so that all data points will appear on the plot, and then add the data with subsequent calls to points() or lines() as appropriate.

This exercise asks you to generate a plot that compares mileage vs. horsepower data from two different sources: the mtcars data frame in the datasets package and the Cars93 data frame in the MASS package. To distinguish the different results from these data sources, the graphics parameter pch is used to specify point shapes. See ?points for a comprehensive list of some pch values and their corresponding point shapes.

3.3.1 Instructions

  • Compute max_hp as the maximum of Horsepower from the Cars93 data frame and hp from the mtcars data frame.
  • Compute max_mpg as the maximum of MPG.city from the Cars93 data frame, MPG.highway from this data frame, and mpg from the mtcars data frame.
  • Using the type = "n" option, set up a plot with an x-axis that runs from zero to max_hp and a y-axis that runs from zero to max_mpg, with labels Horsepower and Miles per gallon.
  • Using the points() function, add mpg vs. hp from the mtcars data frame to the plot as open circles (pch = 1).
  • Using the points() function, add MPG.city vs. Horsepower to the plot as solid squares (refer to the plot of pch values).
  • Using the points() function, add MPG.highway vs. Horsepower to the plot as open triangles pointing upwards (refer to the plot of pch values).

3.4 The lines() function and line types

As noted in Chapter 2, numerical data is often assumed to conform approximately to a Gaussian probability distribution, characterized by the bell curve. One point of this exercise is to show what this bell curve looks like for exactly Gaussian data and the other is to show how the lines() function can be used to add lines to an existing plot.

The curves you are asked to draw here have the same basic shape but differ in their details (specifically, the means and standard deviations of these Gaussian distributions are different). For this reason, it is useful to draw these curves with different line types to help us distinguish them.

Note that line types are set by the lty argument, with the default value lty = 1 specifying solid lines, lty = 2 specifying dashed lines, and lty = 3 specifying dotted lines. Also note that the lwd argument specifies the relative width.

3.4.1 Instructions

  • Create a numerical variable x with 200 evenly-spaced values from 0 to 10.
  • Using the dnorm() function, generate a vector gauss1 of Gaussian probability densities for this range of x values, with mean 2 and standard deviation 0.2.
  • Using the dnorm() function, generate a vector gauss2 of Gaussian probability densities for this range of x values, with mean 4 and standard deviation 0.5.
  • Generate a plot of gauss1 vs. x with lines and a y-axis label "Gaussian probability density".
  • Using the lines() function, add a second dashed line for gauss2 vs. x with relative width 3 (refer to the line type plot to select the lty parameter).

3.5 The points() function and point types

One advantage of specifying the pch argument locally is that, in a call to functions like plot() or points(), local specification allows us to make pch depend on a variable in our dataset. This provides a simple way of indicating different data subsets with different point shapes or symbols.

This exercise asks you to generate two plots of mpg vs. hp from the mtcars data frame in the datasets package. The first plot specifies the point shapes using numerical values of the pch argument defined by the cyl variable in the mtcars data frame. The second plot illustrates the fact that pch can also be specified as a vector of single characters, causing each point to be drawn as the corresponding character.

3.5.1 Instructions

  • Create an empty plot of mpg vs. hp using the type = "n" option from the mtcars data frame, with axis labels "Horsepower" and `“Gas mileage”,.
  • Using the points() function, add the mpg vs. hp data, with pch specified by the numeric values of cyl.
  • Repeat both of the previous steps, except with pch specified by the character values of cyl.

3.6 Adding trend lines from linear regression models

The low-level plot function abline() adds a straight line to an existing plot. This line is specified by an intercept parameter a and a slope parameter b, and the simplest way to set these parameters is directly. For example, the command abline(a = 0, b = 1) adds an equality reference line with zero intercept and unit (i.e. 1) slope: points for which y = x fall on this reference line, while points with y > x fall above it, and points with y < x fall below it.

An alternative way of specifying these parameters is through a linear regression model that determines them from data. One common application is to generate a scatterplot of y versus x, then fit a linear model that predicts y from x, and finally call abline() to add this best fit line to the plot.

This exercise asks you to do this for the Gas versus Temp data from the whiteside data frame in the MASS package. The standard R function that fits linear regression models is lm(), which supports the formula interface. Thus, to fit a linear model that predicts y from x in the data frame df, the call would be lm(y ~ x, data = df). This call returns a linear model object, which can then be passed as an argument to the abline() function to draw the desired line on our plot.

3.6.1 Instructions

  • Use the lm() function to create linear_model, a linear regression model that predicts Gas from Temp from the whiteside data frame.
  • Generate a scatterplot of Gas vs. Temp.
  • Using the abline() function, add a dashed reference line that shows the predictions of linear_model.

3.7 Using the text() function to label plot features

One of the main uses of the text() function is to add informative labels to a data plot. The text() function takes three arguments:

  • x, which specifies the value for the x variable,
  • y, which specifies the value for the y variable, and
  • label, which specifies the label for the x-y value pair.

This exercise asks you to first create a scatterplot of city gas mileage versus horsepower from the Cars93 data, then identify an interesting subset of the data (i.e. the 3-cylinder cars) and label these points. You will find that assigning a vector to the x, y, and label arguments to text() will result in labeling multiple points at once.

3.7.1 Instructions

  • Create a scatterplot of MPG.city vs. Horsepower from the Cars93 data frame, with points represented as solid squares. Recall that the pch value for solid squares is 15.
  • Create the variable index3 using the which() function that identifies all 3-cylinder cars.
  • Label the Make of each 3-cylinder car in the Cars93 data frame using the text() function. Use the adj argument to specify left-justified text in your labels.
  • Use the zoom feature in the Plots window to see this plot more clearly.

3.8 Adjusting text position, size, and font

The previous exercise added explanatory text to a scatterplot. The purpose of this exercise is to improve this plot by modifying the text placement, increasing the text size, and displaying the text in boldface.

It was noted that the adj argument to the text() function determines the horizontal placement of the text and it can take any value between 0 and 1. In fact, this argument can take values outside this range. That is, making this value negative causes the text to start to the right of the specified x position. Similarly, making adj greater than 1 causes the text to end to the left of the x position.

Another useful optional argument for the text() function is cex, which scales the default text size. As a specific example, setting cex = 1.5 increases the text size by 50 percent, relative to the default value. Similarly, specifying cex = 0.8 reduces the text size by 20 percent.

Finally, the third optional parameter used here is font, which can be used to specify one of four text fonts: font = 1 is the default text font (neither italic nor bold), font = 2 specifies bold face text, font = 3 specifies italic text, and font = 4 specifies both bold and italic text.

3.8.1 Instructions

  • Create a plot of MPG.city vs. Horsepower from the Cars93 data frame, with data represented as open circles.
  • Construct the variable index3 using the which() function that identifies the row numbers containing all 3-cylinder cars.
  • Use the points() function to overlay solid circles on top of all points in the plot that represent 3-cylinder cars.
  • Use the text() function with the Make variable as before to add labels to the right of the 3-cylinder cars, but now use adj = -0.2 to move the labels further to the right, use the cex argument to increase the label size by 20 percent, and use the font argument to make the labels bold italic.

3.9 Rotating text with the srt argument

In addition to the optional arguments used in the previous exercises, the text() function also supports a number of other optional arguments that can be used to enhance the text. This exercise uses the cex argument to reduce the text size and introduces two new arguments. The first is the col argument that specifies the color used to display the text, and the second is the srt argument that allows us to rotate the text.

Color has been used in several of the previous exercises to specify point colors, and the effective use of color is discussed further in Chapter 5. One of the points of this exercise is to show that the specification of text color with the text() function is essentially the same as the specification of point color with the plot() function. As a specific example, setting col = "green" in the text() function causes the text to appear in green. If col is not specified, the text appears in the default color set by the par() function, which is typically black.

The srt parameter allows us to rotate the text through an angle specified in degrees. The typical default value (set by the par() function) is 0, causing the text to appear horizontally, reading from left to right. Specifying srt = 90 causes the text to be rotated 90 degrees counter-clockwise so that it reads from bottom to top instead of left to right.

3.9.1 Instructions

  • Create a scatterplot of Gas vs. Temp from the whiteside data frame, as solid triangles.
  • Use the which() function to create a vector indexB that points to all data observations with Insul having the value "Before".
  • Use the which() function to create a vector indexA that points to all data observations with Insul having the value "After".
  • Use the text() function to overlay the text "Before" on the appropriate points, in blue, rotated 30 degrees, reducing the text size to 80 percent of the default.
  • Use the text() function to overlay the text "After" on the appropriate points, in red, rotated -20 degrees, reducing the text size to 80 percent of the default.

3.10 Using the legend() function

The video described and illustrated the use of the legend() function to add explanatory text to a plot.

This exercise asks you to first create a scatterplot and then use this function to add explanatory text for the point shapes that identify two different data subsets.

3.10.1 Instructions

  • Set up a scatterplot of Gas vs. Temp from the whiteside data frame using type = "n" option in the plot() call. Label the x-axis "Outside temperature" by specifying the xlab argument and the y-axis "Heating gas consumption" by specifying the ylab argument.
  • Use the which() function to create a vector indexB that points to all data observations with Insul having the value "Before".
  • Use the which() function to create a vector indexA that points to all data observations with Insul having the value "After".
  • Using the points() function, add the "Before" points to the plot, represented as solid triangles.
  • Using the points() function, add the "After" points to the plot, represented as open circles.
  • Using the legend() function, add a legend in the upper right corner of the plot with the names "Before" and "After" and the appropriate point shapes indicated.

3.11 Adding custom axes with the axis() function

Typical base graphics functions like boxplot() provide x- and y-axes by default, with a label for the x-axis below the plot and one for the y-axis label to the left of the plot. These labels are generated automatically from the variable names used to generate the plot. Sometimes, we want to provide our own axes labels, and R makes this possible in two steps: first, we suppress the default axes when we create the plot by specifying axes = FALSE; then, we call the low-level graphics function axis() to create the axes we want.

In this exercise, you’re asked to create your own labels using the axis() function with the side, at, and labels arguments. The side argument tells the function which axis to create: a value of 1 adds an axis below the plot; 2 adds an axis on the left; 3 puts it across the top; and 4 puts it on the right side. The second argument, at, is a vector that defines points where tick-marks will be drawn on the axis. The third argument, labels, is a vector that defines labels at each of these tick-marks.

One example of a boxplot with custom axes was presented in the video. This exercise asks you to create another example showing the relationship between the sugars variable and the shelf variable from the UScereal data frame in the MASS package.

3.11.1 Instructions

  • Use the boxplot() function to create a boxplot of sugars vs. shelf from the UScereal data frame in the MASS package, with axes suppressed.
  • Use the axis() function with the side parameter specified to add a y-axis label to the left of the box plot showing the range of sugars values.
  • In your second call to axis(), add an x-axis label on the bottom side and specify the at parameter to add tick-marks at the numerical shelf values labelled 1, 2, and 3.
  • In your third call to axis(), add another x-axis label at the top and specify the labels parameter to show the physical shelf locations ("floor", "middle", "top").

3.12 Using the supsmu() function to add smooth trend curves

Some scatterplots exhibit fairly obvious trends that are not linear. In such cases, we may want to add a curved trend line that highlights this behavior of the data and the supsmu() function represents one way of doing this.

To use this function, we need to specify values for the required arguments x and y, but it also has a number of optional arguments. Here, we consider the optional bass argument, which controls the degree of smoothness in the resulting trend curve. The default value is 0, but specifying larger values (up to a maximum of 10) results in a smoother curve. This exercise asks you to use the supsmu() function to add two trend lines to a scatterplot, one using the default parameters and the other with increased smoothness.

3.12.1 Instructions

  • Create a scatterplot of MPG.city vs. Horsepower from the Cars93 data frame.
  • Create a supsmu() object named trend1 with the bass parameter at its minimum (default) value, 1.
  • Use the lines() function to add the trend1 curve to the plot as a solid line. There is no need to provide additional arguments.
  • Create a supsmu() object named trend2 with the bass parameter at its maximum value, 10.
  • Use the lines() function to add the trend2 curve to the plot as a dotted line of twice standard width.

4 How Much is Too Much?

4.1 Too much is too much

The first example presented in Chapter 1 applied the plot() function to a data frame, yielding an array of scatterplots with one for each pair of columns in the data frame. Thus, the number of plots in this array is equal to the square of the number of columns in the data frame.

This means that if we apply the plot() function to a data frame with many columns, we will generate an enormous array of scatterplots, each of which will be too small to be useful. The purpose of this exercise is to provide a memorable example.

4.1.1 Instructions

Applying the plot() function to a data frame with k columns will create a k by k array of scatterplots.

  • Use the ncol() function to compute the number of plots in this array for the Cars93 data frame. Just print the result to the console.
  • Call plot() on Cars93 to generate the scatterplot array. Can you verify that your calculation was correct?

4.2 Deciding how many scatterplots is too many

The matplot() function can be used to easily generate a plot with several scatterplots on the same set of axes. By default, the points in these scatterplots are represented by the numbers 1 through n, where n is the total number of scatterplots included, but most of the options available with the plot() function are also possible by specifying the appropriate arguments.

This exercise asks you to set up a plot array with four of these multiple scatterplot displays, each including one more scatterplot than the previous one. The point of this exercise is to encourage you to judge for yourself how many scatterplots is too many?.

4.2.1 Instructions

  • Run the first line of sample code provided to construct a character vector called keep_vars that names six variables from the UScereal data frame.
  • Using this vector of variable names, extract the data frame df containing only these variables from the UScereal data frame.
  • Use the par() function to set up the mfrow parameter to generate a two-by-two plot array.
  • Use the matplot() function to construct a two-scatterplot display of
    • protein and fat versus calories. Give this plot the title "Two scatterplots" using the title() function. Label the x-axis "calories" and the y-axis "" to get rid of the default y-axis label.
    • protein, fat and fibre versus calories. Give this plot the title "Three scatterplots". Similarly, label the x-axis "calories" and the y-axis "".
    • protein, fat, fibre and carbo versus calories. Give this plot the title "Four scatterplots". Again, label the x-axis "calories" and the y-axis "".
    • protein, fat, fibre, carbo, and sugars versus calories. Give this plot the title "Five scatterplots". Be sure to label the x-axis "calories" and the y-axis "" again.

4.3 How many words is too many?

The main point of the previous two exercises has been to show that scatterplot arrays lose their utility if they are allowed to become too complex, either including too many plots, or attempting to include too many scatterplots on one set of axes. More generally, any data visualization loses its utility if it becomes too complex.

This exercise asks you to consider this problem with wordclouds, displays that present words in varying sizes depending on their frequency. That is, more frequent words appear larger in the display, while rarer words appear in a smaller font.

In R, wordclouds are easy to generate with the wordcloud() function in the wordcloud package. This function is called with a character vector of words, and a second numerical vector giving the number of times each word appears in the collection used to generate the wordcloud.

Two other useful arguments for this function are scale and min.freq. The scale argument is a two-component numerical vector giving the relative size of the largest word in the display and that of the smallest word. The wordcloud only includes those words that occur at least min.freq times in the collection and the default value for this argument is 3.

4.3.1 Instructions

Load the wordcloud package in your workspace.

  • Use the table() function to create the variable mfr_table that tabulates the number of times each level of the Manufacturer variable appears in the Cars93 data frame.
  • Use the wordcloud() function to display this manufacturer data, setting the scale argument to c(2, 0.25) to make the wordcloud fit in the display window.
  • By default, the wordcloud() function shows only those words that appear 3 or more times. Use the min.freq argument to obtain a display with all Manufacturer values in the wordcloud.
  • Use the table() function to create the variable model_table that tabulates the number of times each level of the Model variable appears in the Cars93 data frame.
  • Use the wordcloud() function with the scale argument set to c(0.75, 0.25) and the min.freq argument set to display all Model values. Use the zoom feature in the ‘Plots’ window to see this wordcloud more clearly. Does it convey useful information?

4.4 The Anscombe quartet

This exercise and the next one are based on the Anscombe quartet, a collection of four datasets that appear to be essentially identical on the basis of simple summary statistics like means and standard deviations. For example, the mean x-values for these datasets are identical to three digits, while the mean y-values differ only in the third digit.

In spite of these apparent similarities, the behavior of the four datasets is quite different and this becomes immediately apparent when we plot them.

4.4.1 Instructions

  • Use the par() function to set up a two-by-two plot array.
  • Using plot(), create 4 separate plots from the anscombe data frame:
    • y1 vs. x1
    • y2 vs. x2
    • y3 vs. x3
    • y4 vs. x4

4.5 The utility of common scaling and individual titles

The plots you generated in the previous exercise showed that the four Anscombe quartet datasets have very different appearances, but a careful examination of these plots reveals that they exhibit different ranges of x and y values.

The point of this exercise is to illustrate how much more clearly we can see the differences in these datasets if we plot all of them with the same x and y ranges. This exercise also illustrates the utility of improving the x- and y-axis labels and of adding informative plot titles.

4.5.1 Instructions

  • Examine the range of x and y values from the previous four plots to determine a common range that covers the ranges of all four of these plots. Use integer values to keep things simple.
  • Set up a two-by-two plot array using the par() function.
  • Plot the y1 variable against the x1 variable using these common ranges, with x-axis label "x value" and y-axis label "y value", and use the main, argument to add the title“First dataset”`.
  • Repeat for the other three Anscombe data pairs, adding the appropriate titles.

4.6 Using multiple plots to give multiple views of a dataset

Another useful application of multiple plot arrays besides comparison is presenting multiple related views of the same dataset.

This exercise illustrates this idea, giving four views of the same dataset: a plot of the raw data values themselves, a histogram of these data values, a density plot, and a normal QQ-plot.

4.6.1 Instructions

  • Note that the MASS and car packages have been pre-loaded, making the geyser data and the truehist() and qqPlot() fuctions available for your use.
  • Use the par() function to set the mfrow parameter for a two-by-two plot array.
  • In the upper left, use the plot() function to show the values of the duration variable from the geyser dataset, using the main argument to specify the plot title as "Raw data".
  • In the upper right, use the truehist() function to generate a histogram of the duration data, using the main argument to give this plot the title "Histogram".
  • In the lower left, use the plot() and density() functions to display the density of the duration values, using the main argument to give this plot the title "Density".
  • In the lower right, use the qqPlot() function from the car package to display a normal QQ-plot of the duration data, using the main argument to give this plot the title "QQ-plot".

4.7 Constructing and displaying layout matrices

You can think of the layout matrix as the plot pane, where a 0 represents empty space and other numbers represent the plot number, which is determined by the sequence of visualization function calls. For example, a 1 in the layout matrix refers to the visualization that was first called, a 2 refers to the plot of the second visualization call, etc. This exercise asks you to create your own 3 x 2 layout matrix, using the c() function to concatenate numbers into vectors that will form the rows of the matrix.

You will then use the matrix() function to convert these rows into a matrix and apply the layout() function to set up the desired plot array. The convenience function layout.show() can then be used to verify that the plot array has the shape you want.

4.7.1 Instructions

  • Using the matrix() function, create a matrix called layoutMatrix with three rows and two columns:
    • the first row designates an empty plot to the left and plot 1 to the right.
    • the second row designates plot 2 to the left and an empty plot to the right.
    • the third row designates an empty plot to the left and plot 3 to the right.
  • Use the layout() function to set up the desired plot array.
  • Use the layout.show() function to show the arrangement of all three plots.

4.8 Creating a triangular array of plots

The previous exercise asked you to create a plot array using the layout() function. Recall the layout matrix from the previous exercise:

> layoutMatrix
     [,1] [,2]
[1,]    0    1
[2,]    2    0
[3,]    0    3

This exercise asks you to use this array to give three different views of the whiteside data frame.

The first plot, on the upper right of the plot array, shows the relationship of Gas and Temp using all data from whiteside. The second plot, in the center left of the plot array, shows the relationship of the two variables using data where Insul is equal to "Before". Finally, the third plot, on the lower left of the plot array, shows the relationship using data where Insul is equal to "After".

The primary motivation for this exercise is that it is not possible to construct a plot array in this format using the mfrow parameter, since the array is not rectangular.

4.8.1 Instructions

The layout matrix you set up in the previous exercise is available in your workspace as layoutMatrix. The whiteside data frame is already available in your workspace as well.

  • Call the layout() function on layoutMatrix to set up the plot array.
  • Construct a vector indexB that points to only those records with the Insul value "Before" and a vector indexA that points to only those records with the Insul value "After".
  • Plot the Gas versus Temp values from the indexB data in the upper right plot in your array, using the y-axis limits c(0, 8). Give this plot the title "Before data only".
  • Plot the Gas versus Temp values from the complete dataset in the center left plot, using the same y-axis limits as the first plot. Give this plot the title "Complete dataset".
  • Plot the Gas versus Temp values from the indexA data in the lower right plot, again using the same y-axis limits. Give this plot the title "After data only".

4.9 Creating arrays with different sized plots

Besides creating non-rectangular arrays, the layout() function can be used to create plot arrays with different sized component plots – something else that is not possible by setting the par() function’s mfrow parameter.

This exercise illustrates the point, asking you to create a standard scatterplot of the zn versus rad variables from the Boston data frame as a smaller plot in the upper left, with a larger sunflower plot of the same data in the lower right.

4.9.1 Instructions

The Boston data frame in the MASS package is already available in your workspace.

  • Using the c() function:
    • Create the three-element vector row1 with values (1, 0, 0).
    • Create the three-element vector row2 with values (0, 2, 2).
  • Combine the first vector with two copies of the second vector into layoutVector, a vector of length 9.
  • Using the matrix() function, convert layoutVector into the 3-by-3 matrix layoutMatrix, whose first row isrow1and whose second and third rows arerow2`.
  • Use the layout() function with layoutMatrix to configure a two-element plot array.
  • In the first (smaller) plot, create a standard scatterplot of the zn variable versus the rad variable from the Boston data frame.
  • In the second (larger) plot, create a sunflower plot using the sunflowerplot() function and the same variables.

5 Advanced Plot Customization and Beyond

5.1 Some plot functions also return useful information

Calling the barplot() function has the side effect of creating the plot we want, but it also returns a numerical vector with the center positions of each bar in the plot. This value is returned invisibly so we don’t normally see it, but we can capture it with an assignment statement.

These return values can be especially useful when we want to overlay text on the bars of a horizontal barplot. Then, we capture the return values and use them as the y parameter in a subsequent call to the text() function, allowing us to place the text at whatever x position we want but overlaid in the middle of each horizontal bar. This exercise asks you to construct a horizontal barplot that exploits these possibilities.

5.1.1 Instructions

The Cars93 data frame from the MASS package is already available in your workspace.

  • Use the table() function to generate the object tbl summarizing the number of records listing each value of the Cylinders variable from the Cars93 data frame.
  • Use the barplot() function with the horiz argument set to TRUE to construct a horizontal barplot of this record summary, specifying the color of the bars to be "transparent" and returning the vector mids giving the vertical positions of the centers of each bar in the plot. Specify the names.arg argument as "" to suppress the y-axis legend on this plot.
  • Use the text() function to label the Cylinders value for each bar in the barplot at the horizontal position 20. The names() function may prove useful here.
  • Use the text() function to list the counts for each cylinders value at the horizontal position 35. Here, the as.numeric() function may prove useful.

5.2 Using the symbols() function to display relations between more than two variables

The scatterplot allows us to see how one numerical variable changes with the values of a second numerical variable. The symbols() function allows us to extend scatterplots to show the influence of other variables.

This function is called with the variables x and y that define a scatterplot, along with another argument that specifies one of several possible shapes. Here, you are asked to use the circles argument to create a bubbleplot where each data point is represented by a circle whose radius depends on the third variable specified by the value of this argument.

5.2.1 Instructions

The Cars93 data frame from the MASS package is already available in your workspace.

  • Use the symbols() function with its default settings and the appropriate arguments to create a bubble plot of MPG.city versus Horsepower from the Cars93 data frame, with the bubble area by the Price variable. Note that this means the bubble radius should be proportional to the square root of Price.
  • Re-create the first plot, but with the optional argument inches set to 0.1.

5.3 Saving plot results as files

In an interactive R session, we typically generate a collection of different plots, often using the results to help us decide how to proceed with our analysis. This is particularly true in the early phases of an exploratory data analysis, but once we have generated a plot we want to share with others, it is important to save it in an external file.

R provides support for saving graphical results in several different external file formats, including jpeg, png, tiff, or pdf files. In addition, we can incorporate graphical results into external documents, using tools like the Sweave() function or the knitr package. One particularly convenient way of doing this is to create an R Markdown document, an approach that forms the basis for another course.

Because png files can be easily shared and viewed as e-mail attachments and incorporated into many slide preparation packages (e.g. Microsoft Powerpoint), this exercise asks you to create a plot and save it as a png file. The basis for this process is the png() function, which specifies the name of the png file to be generated and sets up a special environment that captures all graphical output until we exit this environment with the dev.off() command.

5.3.1 Instructions

  • Use the png() function to direct all subsequent plot results to the external file bubbleplot.png.
  • Run the code to re-create the second bubble plot from the previous exercise.
  • Exit the png() environment to return graphics control to your session by calling dev.off().
  • Use the list.files() code provided to verify that bubbleplot.png was created. To do this, you need to specify "png" as the value to the pattern argument to list.files().

5.5 Using color to enhance a bubbleplot

In a previous exercise, you saw how the symbols() function could be used to generate a bubbleplot showing the relationship between three variables (specifically, Horsepower, MPG.city, and Price from the Cars93 data frame). There, the basic format was a scatterplot of MPG.city versus Horsepower, with points represented as bubbles, sized by Price.

Here, you are asked to create a variation on this plot, using the factor variable Cylinders to determine both the size and the color of the bubbles. To do this, note that as.numeric(Cars93$Cylinders) generates a sequence of numerical values from 1 to 6 that specify the six unique levels of the Cylinders factor.

The point of this exercise is to show that, in cases where color is an option, the clarity of this bubbleplot can be improved substantially through the use of color in addition to symbol size. Since the Cylinders variable exhibits six unique values, six colors are required to make this enhancement, so the top six colors recommended by Iliinsky and Steele are used here.

5.5.1 Instructions

Exercise objective is to create this plot.

Exercise objective is to create this plot.

The Cars93 data frame in the MASS package is available in your workspace, and the vector IScolors of color names is created in the code included at the beginning of the exercise.

  • Create the vector cylinderLevels giving numerical labels to the unique values of the Cylinders variable.
  • Using the symbols() function, recreate the bubbleplot of MPG.city vs. Horsepower shown below with the bubbles sized by the cylinderLevels variable.
    • Specify a maximum circle radius of 0.2 inches.
    • Use the bg parameter to color each bubble according to the numerical level of the Cylinders factor variable (i.e., the cylinderLevels values), using the first six recommended colors from Iliinsky and Steele (e.g. the first Cylinder level should be colored “red”, the second level colored “green”, etc.)

5.6 Using color to enhance stacked barplots

The most common barplot consists of a collection of vertical bars, each representing some characteristic of one of a finite number of datasets or data subsets. Several previous exercises have illustrated the utility of the somewhat less common horizontal barplot, useful in part because it allows text to be displayed horizontally across the bars, as illustrated in Exercise 1.

Another useful variant of the standard bar plot is the stacked bar plot, where each bar in the plot is partitioned into segments characterizing portions of the data characterized by the bar. Stacked bar plots can also be generated using the barplot() function. Here, each bar is specified by a matrix whose columns specify the heights of the segments in each bar.

By default, the barplot() function generates stacked bar plots using different shades of gray for the different segments of each bar in the plot. The point of this exercise is to show that, if we can use it, color can be a more effective alternative.

5.6.1 Instructions

Your colored plot should look like this.

Your colored plot should look like this.

The character vector IScolors from the previous exercises is still available in your workspace.

  • Create the table tbl giving the record counts for each Cylinders value at each Origin value (this table should have 6 rows and 2 columns).
  • Using the barplot() function, create a stacked barplot that summarizes this information using shades of gray.
  • Recreate this first plot, but using the first six Iliinsky and Steele colors for the six Cylinders levels.

5.7 The tabplot package and grid graphics

The tabplot package allows you to tap into the power of grid graphics without explicit knowledge of how the system works under the hood. The main function in tabplot is tableplot(), developed to visualize data distributions and relationships between variables in large datasets.

Specifically, the tableplot() function constructs a set of side-by-side horizontal barplots, one for each variable. This function works best when viewing up to about 10 variables at a time, for datasets with arbitrarily many records. In this exercise, you are asked to apply this function to a dataset with just under 68,000 records and 11 variables.

The tableplot() function is called with a data frame and, if no optional arguments are specified, it selects the first data column as the reference variable. This variable can be of any type, but the display is easiest to explain when it’s numeric, as in the example considered here.

For further details, refer to the vignette Visualization of large datasets with tabplot that accompanies the help files for the tabplot package.

5.7.1 Instructions

  • Load the insuranceData package.
  • Use the data() function to load the dataCar data frame.
  • Load the tabplot package the normal way, but surround your call to library() with the suppressPackageStartupMessages() function to avoid a bunch of unncessary output from printing to the console.
  • Apply the tableplot() function to the dataCar data frame.

5.8 A lattice graphics example

Another package built on grid graphics is lattice, but unlike tabplot, lattice is a general-purpose graphics package that provides alternative implementations of many of the plotting functions available in base graphics. Specific examples include scatterplots with the xyplot() function, bar charts with the barchart() function, and boxplots with the bwplot() function.

One important difference between lattice graphics and base graphics is that similar functions available in both graphics systems often produce very different results when applied to the same data. As a specific example, the bwplot() function creates horizontal boxplots, while the default result of the boxplot() is a vertical boxplot display.

Another more important difference between lattice and base graphics is that lattice graphics supports conditional plots that show the separate relationships between variables within different groups. This capability is illustrated in this exercise, where you are asked to construct a plot showing the relationship between the variables calories and sugars from the UScereal data frame, conditional on the value of the shelf variable.

5.8.1 Instructions

  • Load the lattice package to make the function xyplot() available.
  • Using the conditional formula format "y ~ x | z" (scatterplot of y vs. x, conditioned on z), construct a conditional scatterplot of calories vs. sugars conditional on shelf from the UScereal data frame in the MASS package. Make sure to convert shelf to a factor.

5.9 A ggplot2 graphics example

This final exercise provides an introduction to the ggplot2 graphics package. Like the lattice package, the ggplot2 package is also based on grid graphics and it also represents a general purpose graphics package.

The unique feature of the ggplot2 package is that it is based on the grammar of graphics, a systematic approach to building and modifying graphical displays, starting with a basic graphics element and refining it through the addition of successive modifiers.

This exercise provides a simple illustration of the approach. Specifically, you are asked to use ggplot2 to, first, create a simple scatterplot of MPG.city versus Horsepower from the Cars93 data frame. Next, you are asked to add a simple modifier that adds color based on the value of the Cylinders variable. Finally, you are asked to convert this result into a colored bubble plot, with both bubble sizes and colors determined by the Cylinders variable.

The primary purpose of this exercise is to give you a flavor of the ggplot2 package.

5.9.1 Instructions

The character vector IScolors from the previous exercises is still available in your workspace.

  • Load the ggplot2 package.
  • Create basePlot as the ggplot object based on the Cars93 data frame from the MASS package and the scatterplot aesthetic with x as the Horsepower variable and y as the MPG.city variable. When passing the variable names to x and y, they should be unquoted (e.g. x = var_name). (Note that this definition does not render the scatterplot.)
  • Make a simple rendering of basePlot with the geom_point() function.
  • Make a second rendering using the color parameter of geom_point() to specify the first six Iliinsky-Steele colors for the six Cylinders levels.
  • Make a third rendering with the same coloring as the second one, but with the point sizes corresponding to the levels of the Cylinders factor variable.
LS0tCnRpdGxlOiAiRGF0YSBWaXN1YWxpemF0aW9uIGluIFIiCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgaGlnaGxpZ2h0OiBoYWRkb2NrCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcwogICAgdGhlbWU6IGNlcnVsZWFuCiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiAyCiAgaHRtbF9kb2N1bWVudDoKICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6IDIKLS0tCgpgYGB7ciBzZXR1cCwgZWNobyA9IEZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZXZhbCA9IEZBTFNFKQpgYGAKCiMgQSBRdWljayBJbnRyb2R1Y3Rpb24gdG8gQmFzZSBSIEdyYXBoaWNzCgojIyBDcmVhdGluZyBhbiBleHBsb3JhdG9yeSBwbG90IGFycmF5CgpJbiB0aGlzIGV4ZXJjaXNlLCB5b3UnbGwgY29uc3RydWN0IGEgc2ltcGxlIGV4cGxvcmF0b3J5IHBsb3QgZnJvbSBhIGRhdGEgZnJhbWUgdGhhdCBnaXZlcyB2YWx1ZXMgZm9yIHRocmVlIHZhcmlhYmxlcywgcmVjb3JkZWQgb3ZlciB0d28gd2ludGVyIGhlYXRpbmcgc2Vhc29ucy4gVGhlIHZhcmlhYmxlcyBhcmU6CgotIGBUZW1wYDogYSBtZWFzdXJlIG9mIHRoZSBvdXRzaWRlIHRlbXBlcmF0dXJlIGR1cmluZyBvbmUgd2VlawotIGBHYXNgOiB0aGUgYW1vdW50IG9mIGhlYXRpbmcgZ2FzIGNvbnN1bWVkIGR1cmluZyB0aGF0IHdlZWsKLSBgSW5zdWxgOiBhIGNhdGVnb3JpY2FsIHZhcmlhYmxlIHdpdGggdHdvIHZhbHVlcywgaW5kaWNhdGluZyB3aGV0aGVyIHRoZSBtZWFzdXJlbWVudHMgd2VyZSBtYWRlIGJlZm9yZSBvciBhZnRlciBhbiBpbnN1bGF0aW9uIHVwZ3JhZGUgd2FzIG1hZGUgdG8gdGhlIGhvdXNlCgojIyMgSW5zdHJ1Y3Rpb25zCgotIExvYWQgdGhlIGBNQVNTYCBwYWNrYWdlIHRvIG1ha2UgdGhlIGB3aGl0ZXNpZGVgIGRhdGEgZnJhbWUgYXZhaWxhYmxlLgotIEFwcGx5IHRoZSBgcGxvdCgpYCBmdW5jdGlvbiB0byB0aGUgYHdoaXRlc2lkZWAgZGF0YSBmcmFtZS4KCmBgYHtyfQojIExvYWQgTUFTUyBwYWNrYWdlCgoKIyBQbG90IHdoaXRlc2lkZSBkYXRhCgpgYGAKCgojIyBDcmVhdGluZyBhbiBleHBsYW5hdG9yeSBzY2F0dGVycGxvdAoKSW4gY29uc3RyYXN0IHRvIHRoZSBleHBsb3JhdG9yeSBhbmFseXNpcyBwbG90IHlvdSBjcmVhdGVkIGluIHRoZSBwcmV2aW91cyBleGVyY2lzZSwgdGhpcyBleGVyY2lzZSBhc2tzIHlvdSB0byBjcmVhdGUgYSBzaW1wbGUgZXhwbGFuYXRvcnkgc2NhdHRlcnBsb3QsIHN1aXRhYmxlIGZvciBzaGFyaW5nIHdpdGggb3RoZXJzLgoKSGVyZSwgaXQgaXMgaW1wb3J0YW50IHRvIG1ha2UgZWRpdG9yaWFsIGNob2ljZXMgaW4gY29uc3RydWN0aW5nIHRoaXMgcGxvdCwgcmF0aGVyIHRoYW4gZGVwZW5kaW5nIGVudGlyZWx5IG9uIGRlZmF1bHQgb3B0aW9ucy4gSW4gcGFydGljdWxhciwgdGhlIGltcG9ydGFudCBlZGl0b3JpYWwgYXNwZWN0cyBvZiB0aGlzIHBsb3QgYXJlOiBmaXJzdCwgdGhlIHZhcmlhYmxlcyB0byBiZSBwbG90dGVkLCBhbmQgc2Vjb25kLCB0aGUgYXhpcyBsYWJlbHMsIHdoaWNoIGFyZSBzcGVjaWZpZWQgYXMgc3RyaW5ncyB0byB0aGUgYHhsYWJgIGFuZCBgeWxhYmAgYXJndW1lbnRzIHRvIHRoZSBgcGxvdCgpYCBmdW5jdGlvbi4KCiMjIyBJbnN0cnVjdGlvbnMKCi0gVXNlIHRoZSBgcGxvdCgpYCBmdW5jdGlvbiB0byBjb25zdHJ1Y3QgYSBzY2F0dGVycGxvdCBvZiB0aGUgaGVhdGluZyBnYXMgY29uc3VtcHRpb24sIGBHYXNgLCB2ZXJzdXMgdGhlIG91dHNpZGUgdGVtcGVyYXR1cmUsIGBUZW1wYCwgZnJvbSB0aGUgYHdoaXRlc2lkZWAgZGF0YSBmcmFtZS4gTGFiZWwgdGhlIHgtIGFuZCB5LWF4ZXMgdG8gaW5kaWNhdGUgdGhlIHZhcmlhYmxlcyBpbiB0aGUgcGxvdCAoaS5lLiBgIk91dHNpZGUgdGVtcGVyYXR1cmUiYCBhbmQgYCJIZWF0aW5nIGdhcyBjb25zdW1wdGlvbiJgLCByZXNwZWN0aXZlbHkuKQoKYGBge3J9CiMgUGxvdCBHYXMgdnMuIFRlbXAKCmBgYAoKCiMjIFRoZSBwbG90KCkgZnVuY3Rpb24gaXMgZ2VuZXJpYwoKT25lIG9mIHRoZSBrZXkgZmVhdHVyZXMgb2YgdGhlIGBwbG90KClgIGZ1bmN0aW9uIGlzIHRoYXQgaXQgaXMgZ2VuZXJpYywgbWVhbmluZyB0aGF0IHRoZSByZXN1bHRzIG9mIGFwcGx5aW5nIHRoZSBmdW5jdGlvbiBkZXBlbmQgb24gdGhlIG5hdHVyZSBvZiB0aGUgb2JqZWN0IHRvIHdoaWNoIGl0IGlzIGFwcGxpZWQuCgpJbiB0aGUgZmlyc3QgZXhlcmNpc2Ugb2YgdGhpcyBjaGFwdGVyLCBhcHBseWluZyB0aGUgYHBsb3QoKWAgZnVuY3Rpb24gdG8gdGhlIHdoaXRlc2lkZSBkYXRhIGZyYW1lIHJlc3VsdGVkIGluIGEgcGxvdCBhcnJheS4gSGVyZSwgd2Ugb2J0YWluIGEgZnVuZGFtZW50YWxseSBkaWZmZXJlbnQga2luZCBvZiByZXN1bHQgd2hlbiB3ZSBhcHBseSB0aGUgc2FtZSBmdW5jdGlvbiB0byBgSW5zdWxgLCBhIGZhY3RvciB2YXJpYWJsZSBmcm9tIHRoZSBzYW1lIGRhdGEgZnJhbWUuCgojIyMgSW5zdHJ1Y3Rpb25zCgotIEFwcGx5IHRoZSBgcGxvdCgpYCBmdW5jdGlvbiB0byB0aGUgYEluc3VsYCB2YXJpYWJsZSBmcm9tIHRoZSBgd2hpdGVzaWRlYCBkYXRhIGZyYW1lLgoKYGBge3J9CiMgQXBwbHkgdGhlIHBsb3QoKSBmdW5jdGlvbiB0byBJbnN1bAoKYGBgCgoKIyMgQWRkaW5nIGRldGFpbHMgdG8gYSBwbG90IHVzaW5nIHBvaW50IHNoYXBlcywgY29sb3IsIGFuZCByZWZlcmVuY2UgbGluZXMKCkFkZGluZyBhZGRpdGlvbmFsIGRldGFpbHMgdG8geW91ciBleHBsYW5hdG9yeSBwbG90cyBjYW4gaGVscCBlbXBoYXNpemUgY2VydGFpbiBhc3BlY3RzIG9mIHlvdXIgZGF0YS4gRm9yIGV4YW1wbGUsIGJ5IHNwZWNpZnlpbmcgdGhlIGBwY2hgIGFuZCBgY29sYCBhcmd1bWVudHMgdG8gdGhlIGBwbG90KClgIGZ1bmN0aW9uLCB5b3UgY2FuIGFkZCBkaWZmZXJlbnQgcG9pbnQgc2hhcGVzIGFuZCBjb2xvcnMgdG8gc2hvdyBob3cgZGlmZmVyZW50IHZhcmlhYmxlcyBvciBzdWJzZXRzIG9mIHlvdXIgZGF0YSByZWxhdGUgdG8gZWFjaCBvdGhlci4gSW4gYWRkaXRpb24sIHlvdSBjYW4gYWRkIGEgbmV3IHNldCBvZiBwb2ludHMgdG8geW91ciBleGlzdGluZyBzY2F0dGVycGxvdCB3aXRoIHRoZSBgcG9pbnRzKClgIGZ1bmN0aW9uLCBhbmQgYWRkIHJlZmVyZW5jZSBsaW5lcyB3aXRoIHRoZSBgYWJsaW5lKClgIGZ1bmN0aW9uLgoKVGhpcyBleGVyY2lzZSBhc2tzIHlvdSB0byB1c2UgdGhlc2UgbWV0aG9kcyB0byBjcmVhdGUgYW4gZW5oYW5jZWQgc2NhdHRlcnBsb3QgdGhhdCBlZmZlY3RpdmVseSBzaG93cyBob3cgdGhyZWUgdmFyaWFibGVzIGluIHRoZSBgQ2FyczkzYCBkYXRhIGZyYW1lIHJlbGF0ZSB0byBlYWNoIG90aGVyLiBUaGVzZSB2YXJpYWJsZXMgYXJlOgoKLSBgUHJpY2VgOiB0aGUgYXZlcmFnZSBzYWxlIHByaWNlIGZvciBhIGNhcgotIGBNYXguUHJpY2VgOiB0aGUgaGlnaGVzdCByZWNvcmRlZCBwcmljZSBmb3IgdGhhdCBjYXIKLSBgTWluLlByaWNlYDogdGhlIGxvd2VzdCByZWNvcmRlZCBwcmljZSBmb3IgdGhhdCBjYXIKCiMjIyBJbnN0cnVjdGlvbnMKCi0gTG9hZCB0aGUgYE1BU1NgIHBhY2thZ2UgdG8gbWFrZSB0aGUgYENhcnM5M2AgZGF0YSBmcmFtZSBhdmFpbGFibGUuCi0gVXNlIHRoZSBgcGxvdCgpYCBmdW5jdGlvbiB0byBjcmVhdGUgYSBzY2F0dGVycGxvdCBvZiB0aGUgYE1heC5QcmljZWAgdmFyaWFibGUgdmVyc3VzIHRoZSBgUHJpY2VgIHZhcmlhYmxlLCBzcGVjaWZ5aW5nIHRoZSBgcGNoYCBhbmQgYGNvbGAgcGFyYW1ldGVycyBzbyB0aGUgZGF0YSBwb2ludHMgYXJlIHJlcHJlc2VudGVkIGFzIHJlZCBzb2xpZCB0cmlhbmdsZXMuIFRoZSBgcGNoYCB2YWx1ZSB0byBwbG90IHNvbGlkIHRyaWFuZ2xlcyBpcyAxNy4KLSBVc2UgdGhlIGBwb2ludHMoKWAgZnVuY3Rpb24gdG8gYWRkIGEgc2Vjb25kIHNldCBvZiBwb2ludHMgdG8geW91ciBzY2F0dGVycGxvdCwgcmVwcmVzZW50aW5nIGBNaW4uUHJpY2VgIHZlcnN1cyBgUHJpY2VgLCB3aGVyZSB0aGUgbmV3IGRhdGEgcG9pbnRzIGFyZSByZXByZXNlbnRlZCBhcyBibHVlIHNvbGlkIGNpcmNsZXMuIFRoZSBgcGNoYCB2YWx1ZSBmb3Igc29saWQgY2lyY2xlcyBpcyAxNi4KLSBVc2UgdGhlIGBhYmxpbmUoKWAgZnVuY3Rpb24gdG8gYWRkIGEgZGFzaGVkIGVxdWFsaXR5IHJlZmVyZW5jZSBsaW5lIChpLmUuLCBhIGxpbmUgd2l0aCB5LWludGVyY2VwdCAwIGFuZCBzbG9wZSAxKS4gU2VlIGBhYmxpbmUoKWAgdG8gbGVhcm4gd2hhdCBhcmd1bWVudHMgYSBhbmQgYiByZWZlciB0by4KCmBgYHtyfQojIExvYWQgdGhlIE1BU1MgcGFja2FnZQoKCiMgUGxvdCBNYXguUHJpY2UgdnMuIFByaWNlIGFzIHJlZCB0cmlhbmdsZXMKCgojIEFkZCBNaW4uUHJpY2UgdnMuIFByaWNlIGFzIGJsdWUgY2lyY2xlcwoKCiMgQWRkIGFuIGVxdWFsaXR5IHJlZmVyZW5jZSBsaW5lIHdpdGggYWJsaW5lKCkKYWJsaW5lKGEgPSBfX18sIGIgPSBfX18sIGx0eSA9IDIpCgpgYGAKCgojIyBDcmVhdGluZyBtdWx0aXBsZSBwbG90IGFycmF5cwoKWW91IGNhbiBwbG90IG11bHRpcGxlIGdyYXBocyBvbiBhIHNpbmdsZSBwYW5lIHVzaW5nIHRoZSBgcGFyKClgIGZ1bmN0aW9uIHdpdGggaXRzIGBtZnJvd2AgcGFyYW1ldGVyLiBGb3IgZXhhbXBsZSwgYHBhcihtZnJvdyA9IGMoMSwgMikpYCBjcmVhdGVzIGEgcGxvdCBhcnJheSB3aXRoIDEgcm93IGFuZCAyIGNvbHVtbnMsIGFsbG93aW5nIHlvdSB0byB2aWV3IHR3byBncmFwaHMgc2lkZS1ieS1zaWRlLiBUaGlzIHdheSwgeW91IGNhbiBjb21wYXJlIGFuZCBjb250cmFzdCBkaWZmZXJlbnQgZGF0YXNldHMgb3IgZGlmZmVyZW50IHZpZXdzIG9mIHRoZSBzYW1lIGRhdGFzZXQuIFRoaXMgZXhlcmNpc2UgYXNrcyB5b3UgdG8gY29tcGFyZSB0d28gdmlld3Mgb2YgdGhlIGBBbmltYWxzMmAgZGF0YXNldCBmcm9tIHRoZSBgcm9idXN0YmFzZWAgcGFja2FnZSwgZGlmZmVyaW5nIGluIGhvdyBpdHMgdmFyaWFibGVzIGFyZSByZXByZXNlbnRlZC4KClRoZSBvYmplY3RpdmUgb2YgdGhpcyBleGVyY2lzZSBpcyB0byBlbXBoYXNpemUgdGhhdCB0aGUgb3JpZ2luYWwgcmVwcmVzZW50YXRpb24gb2YgdGhlIHZhcmlhYmxlcyB0aGF0IHdlIGhhdmUgaW4gYSBkYXRhc2V0IGlzIG5vdCBhbHdheXMgdGhlIGJlc3Qgb25lIGZvciB2aXN1YWxpemF0aW9uIG9yIGFuYWx5c2lzLiBCeSByZXByZXNlbnRpbmcgdGhlIG9yaWdpbmFsIHZhcmlhYmxlcyBpbiBsb2cgc2NhbGUsIGZvciBleGFtcGxlLCB3ZSBjYW4gYmV0dGVyIHNlZSBhbmQgdW5kZXJzdGFuZCB0aGUgZGF0YS4KCiMjIyBJbnN0cnVjdGlvbnMKCi0gTG9hZCB0aGUgYHJvYnVzdGJhc2VgIHBhY2thZ2UgdG8gbWFrZSB0aGUgYEFuaW1hbHMyYCBkYXRhIGZyYW1lIGF2YWlsYWJsZS4KLSBVc2UgdGhlIGBwYXIoKWAgZnVuY3Rpb24gYW5kIHNldCB0aGUgYG1mcm93YCBwYXJhbWV0ZXIgdG8gY3JlYXRlIGEgc2lkZS1ieS1zaWRlIHBsb3QgYXJyYXkgd2l0aCAxIHJvdyBhbmQgMiBjb2x1bW5zLgotIFVzZSB0aGUgYHBsb3QoKWAgZnVuY3Rpb24gdG8gY3JlYXRlIGEgc2NhdHRlcnBsb3Qgb2YgdGhlIHZhcmlhYmxlcyBgYnJhaW5gIHZlcnN1cyBgYm9keWAgZnJvbSB0aGlzIGRhdGEgZnJhbWUsIHdpdGhvdXQgc3BlY2lmeWluZyBhZGRpdGlvbmFsIGFyZ3VtZW50cy4KLSBTZWUgd2hhdCBoYXBwZW5zIHdoZW4geW91IHJ1biBgdGl0bGUoIk9yaWdpbmFsIHJlcHJlc2VudGF0aW9uIilgIGFmdGVyIHlvdXIgZmlyc3QgY2FsbCB0byBgcGxvdCgpYC4KLSBVc2UgdGhlIGBwbG90KClgIGZ1bmN0aW9uIGFnYWluLCBidXQgdGhpcyB0aW1lIHdpdGggYGxvZyA9ICJ4eSJgLCB0byBnZW5lcmF0ZSBhIHBsb3Qgb2YgYm90aCB0aGUgYHhgIGFuZCBgeWAgdmFyaWFibGVzIGluIGxvZyBzY2FsZS4KLSBVc2UgdGhlIGB0aXRsZSgpYCBmdW5jdGlvbiB0byBhZGQgYCJMb2ctbG9nIHBsb3QiYCBhcyB0aGUgdGl0bGUgdG8gdGhlIHNlY29uZCBwbG90LgoKYGBge3J9CiMgTG9hZCB0aGUgcm9idXN0YmFzZSBwYWNrYWdlCgoKIyBTZXQgdXAgdGhlIHNpZGUtYnktc2lkZSBwbG90IGFycmF5CgoKIyBGaXJzdCBwbG90OiBicmFpbiB2cy4gYm9keSBpbiBpdHMgb3JpZ2luYWwgZm9ybQoKCiMgQWRkIHRoZSBmaXJzdCB0aXRsZQoKCiMgU2Vjb25kIHBsb3Q6IGxvZy1sb2cgcGxvdCBvZiBicmFpbiB2cy4gYm9keQoKCiMgQWRkIHRoZSBzZWNvbmQgdGl0bGUKCmBgYAoKIyMgQXZvaWQgcGllIGNoYXJ0cwoKVGhlIHNhbWUgZGF0YXNldCBjYW4gYmUgZGlzcGxheWVkIG9yIHN1bW1hcml6ZWQgaW4gbWFueSBkaWZmZXJlbnQgd2F5cywgYnV0IHNvbWUgYXJlIG11Y2ggbW9yZSBzdWl0YWJsZSB0aGFuIG90aGVycy4KCkRlc3BpdGUgdGhlaXIgZ2VuZXJhbCBwb3B1bGFyaXR5LCBwaWUgY2hhcnRzIGFyZSBvZnRlbiBhIHBvb3IgY2hvaWNlLiBUaG91Z2ggUiBhbGxvd3MgcGllIGNoYXJ0cyB3aXRoIHRoZSBgcGllKClgIGZ1bmN0aW9uLCBldmVuIHRoZSBoZWxwIGZpbGUgZm9yIHRoaXMgZnVuY3Rpb24gYXJndWVzIGFnYWluc3QgdGhlaXIgdXNlLiBTcGVjaWZpY2FsbHksIHRoZSBoZWxwIGZpbGUgaW5jbHVkZXMgYSAiTm90ZSIgdGhhdCBiZWdpbnMgd2l0aCB0aGUgd29yZHM6ICJQaWUgY2hhcnRzIGFyZSBhIHZlcnkgYmFkIHdheSBvZiBkaXNwbGF5aW5nIGluZm9ybWF0aW9uLiIKCkJhciBjaGFydHMgYXJlIGEgcmVjb21tZW5kZWQgYWx0ZXJuYXRpdmUgYW5kLCBpbiB0aGlzIGV4ZXJjaXNlLCB5b3UnbGwgc2VlIHdoeS4KCiMjIyBJbnN0cnVjdGlvbnMKCi0gTG9hZCB0aGUgYGluc3VyYW5jZURhdGFgIHBhY2thZ2UgYW5kIHVzZSB0aGUgYGRhdGEoKWAgZnVuY3Rpb24gdG8gbG9hZCB0aGUgYGRhdGFDYXJgIGRhdGEgZnJhbWUgZnJvbSB0aGlzIHBhY2thZ2UuCi0gVXNlIHRoZSBgcGFyKClgIGZ1bmN0aW9uIGFuZCBzZXQgdGhlIGBtZnJvd2AgcGFyYW1ldGVyIHRvIGNyZWF0ZSBhIHNpZGUtYnktc2lkZSBwbG90IGFycmF5IHdpdGggMSByb3cgYW5kIDIgY29sdW1ucy4KLSBVc2UgdGhlIGB0YWJsZSgpYCBmdW5jdGlvbiBhbmQgdGhlIGBzb3J0KClgIGZ1bmN0aW9uIHRvIGNyZWF0ZSBhIHRhYmxlIG9mIGNvdW50cyBvZiB0aGUgZGlzdGluY3QgbGV2ZWxzIG9mIHRoZSBgdmVoX2JvZHlgIHZhcmlhYmxlIGluIHRoZSBgZGF0YUNhcmAgZGF0YSBmcmFtZSwgaW4gZGVjcmVhc2luZyBvcmRlci4gQ2FsbCB0aGlzIHRhYmxlIGB0YmxgLgotIFBhc3MgYHRibGAgdG8gdGhlIGBwaWUoKWAgZnVuY3Rpb24gdG8gY3JlYXRlIGEgcGllIGNoYXJ0IHJlcHJlc2VudGF0aW9uIG9mIHRoaXMgZGF0YSBhcyB0aGUgbGVmdC1oYW5kIHBsb3QuIFVzZSBgdGl0bGUoKWAgdG8gdGl0bGUgdGhpcyBwbG90IGAiUGllIGNoYXJ0ImAuCi0gU2ltaWxhcmx5LCB1c2UgdGhlIGBiYXJwbG90KClgIGFuZCBgdGl0bGUoKWAgZnVuY3Rpb25zIHRvIGNyZWF0ZSBhIGJhcnBsb3QgcmVwcmVzZW50YXRpb24gb2YgdGhlIHNhbWUgZGF0YSwgc3BlY2lmeWluZyBgbGFzID0gMmAgdG8gbWFrZSBib3RoIHNldHMgb2YgbGFiZWxzIHBlcnBlbmRpY3VsYXIgdG8gdGhlIGF4ZXMsIGFuZCB1c2luZyBgY2V4Lm5hbWVzID0gMC41YCB0byBtYWtlIHRoZSBuYW1lIGxhYmVscyBoYWxmIHRoZSBkZWZhdWx0IHNpemUuIFRpdGxlIHRoaXMgcGxvdCBgIkJhciBjaGFydCJgLgoKYGBge3J9CiMgTG9hZCB0aGUgaW5zdXJhbmNlRGF0YSBwYWNrYWdlCgoKIyBVc2UgdGhlIGRhdGEoKSBmdW5jdGlvbiB0byBnZXQgdGhlIGRhdGFDYXIgZGF0YSBmcmFtZQoKCiMgU2V0IHVwIGEgc2lkZS1ieS1zaWRlIHBsb3QgYXJyYXkKCgojIENyZWF0ZSBhIHRhYmxlIG9mIHZlaF9ib2R5IHJlY29yZCBjb3VudHMgYW5kIHNvcnQKdGJsIDwtIHNvcnQodGFibGUoX19fKSwgZGVjcmVhc2luZyA9IF9fXykKCiMgQ3JlYXRlIHRoZSBwaWUgY2hhcnQgYW5kIGdpdmUgaXQgYSB0aXRsZQoKCiMgQ3JlYXRlIHRoZSBiYXJwbG90IHdpdGggcGVycGVuZGljdWxhciwgaGFsZi1zaXplZCBsYWJlbHMKYmFycGxvdChfX18sIGxhcyA9IF9fXywgY2V4Lm5hbWVzID0gX19fKQoKIyBBZGQgYSB0aXRsZQoKYGBgCgoKIyBEaWZmZXJlbnQgUGxvdCBUeXBlcwoKIyMgVGhlIGhpc3QoKSBhbmQgdHJ1ZWhpc3QoKSBmdW5jdGlvbnMKCkhpc3RvZ3JhbXMgYXJlIHByb2JhYmx5IHRoZSBiZXN0LWtub3duIHdheSBvZiBsb29raW5nIGF0IGhvdyB0aGUgdmFsdWVzIG9mIGEgbnVtZXJpY2FsIHZhcmlhYmxlIGFyZSBkaXN0cmlidXRlZCBvdmVyIHRoZWlyIHJhbmdlLCBhbmQgUiBwcm92aWRlcyBzZXZlcmFsIGRpZmZlcmVudCBoaXN0b2dyYW0gaW1wbGVtZW50YXRpb25zLgoKVGhlIHB1cnBvc2Ugb2YgdGhpcyBleGVyY2lzZSBpcyB0byBpbnRyb2R1Y2UgdHdvIG9mIHRoZXNlOgoKLSBgaGlzdCgpYCBpcyBwYXJ0IG9mIGJhc2UgUiBhbmQgaXRzIGRlZmF1bHQgb3B0aW9uIHlpZWxkcyBhIGhpc3RvZ3JhbSBiYXNlZCBvbiB0aGUgbnVtYmVyIG9mIHRpbWVzIGEgcmVjb3JkIGZhbGxzIGludG8gZWFjaCBvZiB0aGUgYmlucyBvbiB3aGljaCB0aGUgaGlzdG9ncmFtIGlzIGJhc2VkLgotIGB0cnVlaGlzdCgpYCBpcyBmcm9tIHRoZSBgTUFTU2AgcGFja2FnZSBhbmQgc2NhbGVzIHRoZXNlIGNvdW50cyB0byBnaXZlIGFuIGVzdGltYXRlIG9mIHRoZSBwcm9iYWJpbGl0eSBkZW5zaXR5LgoKIyMjIEluc3RydWN0aW9ucwoKLSBVc2UgdGhlIGBwYXIoKWAgZnVuY3Rpb24gdG8gc2V0IHRoZSBgbWZyb3dgIHBhcmFtZXRlciBmb3IgYSBzaWRlLWJ5LXNpZGUgYXJyYXkgb2YgdHdvIHBsb3RzLgotIFVzZSB0aGUgYGhpc3QoKWAgZnVuY3Rpb24gdG8gZ2VuZXJhdGUgYSBoaXN0b2dyYW0gb2YgdGhlIGBIb3JzZXBvd2VyYCB2YXJpYWJsZSBmcm9tIHRoZSBgQ2FyczkzYCBkYXRhIGZyYW1lLiBTZXQgaXRzIGBtYWluYCBhcmd1bWVudCBlcXVhbCB0byB0aGUgdGl0bGUgb2YgdGhlIHBsb3QsIGAiaGlzdCgpIHBsb3QiYC4KLSBVc2UgdGhlIGB0cnVlaGlzdCgpYCBmdW5jdGlvbiB0byBnZW5lcmF0ZSBhbiBhbHRlcm5hdGl2ZSBoaXN0b2dyYW0gb2YgdGhlIHNhbWUgdmFyaWFibGUuIFRpdGxlIHRoaXMgcGxvdCwgYCJ0cnVlaGlzdCgpIHBsb3QiYCBieSBzcGVjaWZ5aW5nIGl0cyBgbWFpbmAgYXJndW1lbnQgYWNjb3JkaW5nbHkuCgpgYGB7cn0KIyBTZXQgdXAgYSBzaWRlLWJ5LXNpZGUgcGxvdCBhcnJheQoKCiMgQ3JlYXRlIGEgaGlzdG9ncmFtIG9mIGNvdW50cyB3aXRoIGhpc3QoKQoKCiMgQ3JlYXRlIGEgbm9ybWFsaXplZCBoaXN0b2dyYW0gd2l0aCB0cnVlaGlzdCgpCgpgYGAKCgojIyBEZW5zaXR5IHBsb3RzIGFzIHNtb290aGVkIGhpc3RvZ3JhbXMKCldoaWxlIHRoZXkgYXJlIHByb2JhYmx5IG5vdCBhcyB3ZWxsIGtub3duIGFzIHRoZSBoaXN0b2dyYW0sIGRlbnNpdHkgZXN0aW1hdGVzIG1heSBiZSByZWdhcmRlZCBhcyBzbW9vdGhlZCBoaXN0b2dyYW1zLCBkZXNpZ25lZCB0byBnaXZlIGEgYmV0dGVyIGVzdGltYXRlIG9mIHRoZSBkZW5zaXR5IGZ1bmN0aW9uIGZvciBhIHJhbmRvbSB2YXJpYWJsZS4KCkluIHRoaXMgZXhlcmNpc2UsIHlvdSdsbCB1c2UgdGhlIGBDaGlja1dlaWdodGAgZGF0YXNldCwgd2hpY2ggY29udGFpbnMgYSBjb2xsZWN0aW9uIG9mIGNoaWNrcycgd2VpZ2h0cy4gWW91IHdpbGwgZmlyc3Qgc2VsZWN0IGZvciB0aGUgY2hpY2tzIHRoYXQgYXJlIDE2IHdlZWtzIG9sZC4gVGhlbiwgeW91J2xsIGNyZWF0ZSBhIGhpc3RvZ3JhbSB1c2luZyB0aGUgYHRydWVoaXN0KClgIGZ1bmN0aW9uLCBhbmQgYWRkIGl0cyBkZW5zaXR5IHBsb3Qgb24gdG9wLCB1c2luZyB0aGUgYGxpbmVzKClgIGFuZCBgZGVuc2l0eSgpYCBmdW5jdGlvbnMgd2l0aCB0aGVpciBkZWZhdWx0IG9wdGlvbnMuIFRoZSBkZW5zaXR5IHBsb3Qgb2YgdGhpcyB0eXBlIG9mIHZhcmlhYmxlIGlzIG9mdGVuIGV4cGVjdGVkIHRvIGNvbmZvcm0gYXBwcm94aW1hdGVseSB0byB0aGUgYmVsbC1zaGFwZWQgY3VydmUsIG90aGVyd2lzZSBrbm93biBhcyB0aGUgR2F1c3NpYW4gZGlzdHJpYnV0aW9uLiBMZXQncyBmaW5kIG91dCB3aGV0aGVyIHRoYXQncyB0aGUgY2FzZSBmb3IgdGhpcyBkYXRhc2V0LgoKIyMjIEluc3RydWN0aW9ucwoKLSBDcmVhdGUgdGhlIHZhcmlhYmxlIGBpbmRleDE2YCB1c2luZyB0aGUgYHdoaWNoKClgIGZ1bmN0aW9uIHRoYXQgc2VsZWN0cyByZWNvcmRzIGZyb20gdGhlIGBDaGlja1dlaWdodGAgZGF0YSBmcmFtZSB3aXRoIGBUaW1lYCBlcXVhbCB0byAxNi4KLSBDcmVhdGUgdGhlIHZhcmlhYmxlIGB3ZWlnaHRzYCB0aGF0IGdpdmVzIHRoZSB3ZWlnaHRzIG9mIHRoZSAxNi13ZWVrIG9sZCBjaGlja3MuCi0gVXNlIHRoZSBgdHJ1ZWhpc3QoKWAgZnVuY3Rpb24gdG8gZ2VuZXJhdGUgYSBoaXN0b2dyYW0gZnJvbSBgd2VpZ2h0c2AuCi0gVXNlIHRoZSBgbGluZXMoKWAgYW5kIGBkZW5zaXR5KClgIGZ1bmN0aW9ucyB0byBvdmVybGF5IGEgZGVuc2l0eSBwbG90IG9mIHRoZSBgd2VpZ2h0c2AgdmFsdWVzIG9uIHRoZSBoaXN0b2dyYW0uCgpgYGB7cn0KIyBDcmVhdGUgaW5kZXgxNiwgcG9pbnRpbmcgdG8gMTYtd2VlayBjaGlja3MKCgojIEdldCB0aGUgMTYtd2VlayBjaGljayB3ZWlnaHRzCgoKIyBQbG90IHRoZSBub3JtYWxpemVkIGhpc3RvZ3JhbQoKCiMgQWRkIHRoZSBkZW5zaXR5IGN1cnZlIHRvIHRoZSBoaXN0b2dyYW0KCmBgYAoKCiMjIFVzaW5nIHRoZSBxcVBsb3QoKSBmdW5jdGlvbiB0byBzZWUgbWFueSBkZXRhaWxzIGluIGRhdGEKCkEgcHJhY3RpY2FsIGxpbWl0YXRpb24gb2YgYm90aCBoaXN0b2dyYW1zIGFuZCBkZW5zaXR5IGVzdGltYXRlcyBpcyB0aGF0LCBpZiB3ZSB3YW50IHRvIGtub3cgd2hldGhlciB0aGUgR2F1c3NpYW4gZGlzdHJpYnV0aW9uIGFzc3VtcHRpb24gaXMgcmVhc29uYWJsZSBmb3Igb3VyIGRhdGEsIGl0IGlzIGRpZmZpY3VsdCB0byB0ZWxsLgoKVGhlIHF1YW50aWxlLXF1YW50aWxlIHBsb3QsIG9yIFFRLXBsb3QsIGlzIGEgdXNlZnVsIGFsdGVybmF0aXZlOiB3ZSBzb3J0IG91ciBkYXRhLCBwbG90IGl0IGFnYWluc3QgYSBzcGVjaWFsbHktZGVzaWduZWQgeC1heGlzIGJhc2VkIG9uIG91ciByZWZlcmVuY2UgZGlzdHJpYnV0aW9uIChlLmcuLCB0aGUgR2F1c3NpYW4gImJlbGwgY3VydmUiKSwgYW5kIGxvb2sgdG8gc2VlIHdoZXRoZXIgdGhlIHBvaW50cyBsaWUgYXBwcm94aW1hdGVseSBvbiBhIHN0cmFpZ2h0IGxpbmUuIEluIFIsIHNldmVyYWwgUVEtcGxvdCBpbXBsZW1lbnRhdGlvbnMgYXJlIGF2YWlsYWJsZSwgYnV0IHRoZSBtb3N0IGNvbnZlbmllbnQgb25lIGlzIHRoZSBgcXFQbG90KClgIGZ1bmN0aW9uIGluIHRoZSBgY2FyYCBwYWNrYWdlLgoKVGhlIGZpcnN0IHBhcnQgb2YgdGhpcyBleGVyY2lzZSBhcHBsaWVzIHRoaXMgZnVuY3Rpb24gdG8gdGhlIDE2LXdlZWsgY2hpY2sgd2VpZ2h0IGRhdGEgY29uc2lkZXJlZCBpbiB0aGUgbGFzdCBleGVyY2lzZSwgdG8gc2hvdyB0aGF0IHRoZSBHYXVzc2lhbiBkaXN0cmlidXRpb24gYXBwZWFycyB0byBiZSByZWFzb25hYmxlIGhlcmUuIFRoZSBzZWNvbmQgcGFydCBvZiB0aGUgZXhlcmNpc2UgYXBwbGllcyB0aGlzIGZ1bmN0aW9uIHRvIGFub3RoZXIgdmFyaWFibGUgd2hlcmUgdGhlIEdhdXNzaWFuIGRpc3RyaWJ1dGlvbiBpcyBvYnZpb3VzbHkgYSBwb29yIGZpdCwgYnV0IHRoZSByZXN1bHRzIGFsc28gc2hvdyB0aGUgcHJlc2VuY2Ugb2YgcmVwZWF0ZWQgdmFsdWVzIChmbGF0IHN0cmV0Y2hlcyBpbiB0aGUgcGxvdCkgYW5kIHBvcnRpb25zIG9mIHRoZSBkYXRhIHJhbmdlIHdoZXJlIHRoZXJlIGFyZSBubyBvYnNlcnZhdGlvbnMgKHZlcnRpY2FsICJqdW1wcyIgaW4gdGhlIHBsb3QpLgoKIyMjIEluc3RydWN0aW9ucwoKLSBMb2FkIHRoZSBgY2FyYCBwYWNrYWdlIHRvIG1ha2UgdGhlIGBxcVBsb3QoKWAgZnVuY3Rpb24gYXZhaWxhYmxlIGZvciB1c2UuCi0gQ3JlYXRlIHRoZSB2YXJpYWJsZSBgaW5kZXgxNmAgdXNpbmcgdGhlIGB3aGljaCgpYCBmdW5jdGlvbiB0aGF0IHNlbGVjdHMgcmVjb3JkcyBmcm9tIHRoZSBgQ2hpY2tXZWlnaHRgIGRhdGEgZnJhbWUgd2l0aCBgVGltZWAgZXF1YWwgdG8gMTYuCi0gQ3JlYXRlIHRoZSB2YXJpYWJsZSBgd2VpZ2h0c2AgdGhhdCBnaXZlcyB0aGUgd2VpZ2h0cyBvZiB0aGUgMTYtd2VlayBvbGQgY2hpY2tzLgotIEFwcGx5IHRoZSBgcXFQbG90KClgIGZ1bmN0aW9uIHRvIHRoZSBgd2VpZ2h0c2AgZGF0YSwgbm90aW5nIHRoYXQgYWxtb3N0IGFsbCBvZiB0aGUgcG9pbnRzIGZhbGwgd2l0aGluIHRoZSBjb25maWRlbmNlIGludGVydmFscyBhcm91bmQgdGhlIHJlZmVyZW5jZSBsaW5lLCBpbmRpY2F0aW5nIGEgcmVhc29uYWJsZSBjb25mb3JtYW5jZSB3aXRoIHRoZSBHYXVzc2lhbiBkaXN0cmlidXRpb24gZm9yIHRoaXMgZGF0YSBzZXF1ZW5jZS4KLSBBcHBseSB0aGUgYHFxUGxvdCgpYCBmdW5jdGlvbiB0byB0aGUgYHRheGAgdmFyaWFibGUgZnJvbSB0aGUgYEJvc3RvbmAgZGF0YSBmcmFtZSBpbiB0aGUgYE1BU1NgIHBhY2thZ2UuCgpgYGB7cn0KIyBMb2FkIHRoZSBjYXIgcGFja2FnZSB0byBtYWtlIHFxUGxvdCgpIGF2YWlsYWJsZQoKCiMgQ3JlYXRlIGluZGV4MTYsIHBvaW50aW5nIHRvIDE2LXdlZWsgY2hpY2tzCgoKIyBHZXQgdGhlIDE2LXdlZWsgY2hpY2sgd2VpZ2h0cwoKCiMgU2hvdyB0aGUgbm9ybWFsIFFRLXBsb3Qgb2YgdGhlIGNoaWNrIHdlaWdodHMKCgojIFNob3cgdGhlIG5vcm1hbCBRUS1wbG90IG9mIHRoZSBCb3N0b24kdGF4IGRhdGEKCmBgYAoKCiMjIFRoZSBzdW5mbG93ZXJwbG90KCkgZnVuY3Rpb24gZm9yIHJlcGVhdGVkIG51bWVyaWNhbCBkYXRhCgpBIHNjYXR0ZXJwbG90IHJlcHJlc2VudHMgZWFjaCAoeCwgeSkgcGFpciBpbiBhIGRhdGFzZXQgYnkgYSBzaW5nbGUgcG9pbnQuIElmIHNvbWUgb2YgdGhlc2UgcGFpcnMgYXJlIHJlcGVhdGVkIChpLmUuIGlmIHRoZSBzYW1lIGNvbWJpbmF0aW9uIG9mIHggYW5kIHkgdmFsdWVzIGFwcGVhcnMgbW9yZSB0aGFuIG9uY2UgYW5kIHRodXMgbGllIG9uIHRvcCBvZiBlYWNoIG90aGVyKSwgd2UgY2FuJ3Qgc2VlIHRoaXMgaW4gYSBzY2F0dGVycGxvdC4gU2V2ZXJhbCBhcHByb2FjaGVzIGhhdmUgYmVlbiBkZXZlbG9wZWQgdG8gZGVhbCB3aXRoIHRoaXMgcHJvYmxlbSwgaW5jbHVkaW5nIGppdHRlcmluZywgd2hpY2ggYWRkcyBzbWFsbCByYW5kb20gdmFsdWVzIHRvIGVhY2ggeCBhbmQgeSB2YWx1ZSwgc28gcmVwZWF0ZWQgcG9pbnRzIHdpbGwgYXBwZWFyIGFzIGNsdXN0ZXJzIG9mIG5lYXJieSBwb2ludHMuCgpBIHVzZWZ1bCBhbHRlcm5hdGl2ZSB0aGF0IGlzIGVxdWFsbHkgZWZmZWN0aXZlIGluIHJlcHJlc2VudGluZyByZXBlYXRlZCBkYXRhIHBvaW50cyBpcyB0aGUgc3VuZmxvd2VycGxvdCwgd2hpY2ggcmVwcmVzZW50cyBlYWNoIHJlcGVhdGVkIHBvaW50IGJ5IGEgInN1bmZsb3dlciwiIHdpdGggb25lICJwZXRhbCIgZm9yIGVhY2ggcmVwZXRpdGlvbiBvZiBhIGRhdGEgcG9pbnQuCgpUaGlzIGV4ZXJjaXNlIGFza3MgeW91IHRvIGNvbnN0cnVjdCBib3RoIGEgc2NhdHRlcnBsb3QgYW5kIGEgc3VuZmxvd2VycGxvdCBmcm9tIHRoZSBzYW1lIGRhdGFzZXQsIG9uZSB0aGF0IGNvbnRhaW5zIHJlcGVhdGVkIGRhdGEgcG9pbnRzLiBDb21wYXJpbmcgdGhlc2UgcGxvdHMgYWxsb3dzIHlvdSB0byBzZWUgaG93IG11Y2ggaW5mb3JtYXRpb24gY2FuIGJlIGxvc3QgaW4gYSBzdGFuZGFyZCBzY2F0dGVycGxvdCB3aGVuIHNvbWUgZGF0YSBwb2ludHMgYXBwZWFyIG1hbnkgdGltZXMuCgojIyMgSW5zdHJ1Y3Rpb25zCgotIFVzZSB0aGUgYHBhcigpYCBmdW5jdGlvbiB0byBzZXQgdGhlIGBtZnJvd2AgcGFyYW1ldGVyIGZvciBhIHNpZGUtYnktc2lkZSBwbG90IGFycmF5LgotIEZvciB0aGUgbGVmdC1oYW5kIHBsb3QsIHVzZSB0aGUgYHBsb3QoKWAgZnVuY3Rpb24gdG8gY29uc3RydWN0IGEgc2NhdHRlcnBsb3Qgb2YgdGhlIGByYWRgIHZhcmlhYmxlIHZlcnN1cyB0aGUgYHpuYCB2YXJpYWJsZSwgYm90aCBmcm9tIHRoZSBgQm9zdG9uYCBkYXRhIGZyYW1lIGluIHRoZSBgTUFTU2AgcGFja2FnZS4KLSBVc2UgdGhlIGB0aXRsZSgpYCBmdW5jdGlvbiB0byBhZGQgdGhlIHRpdGxlIGAiU3RhbmRhcmQgc2NhdHRlcnBsb3QiYCB0byB0aGlzIHBsb3QuCi0gRm9yIHRoZSByaWdodC1oYW5kIHBsb3QsIGFwcGx5IHRoZSBgc3VuZmxvd2VycGxvdCgpYCBmdW5jdGlvbiB0byB0aGUgc2FtZSBkYXRhIHRvIHNlZSB0aGUgcHJlc2VuY2Ugb2YgcmVwZWF0ZWQgZGF0YSBwb2ludHMsIG5vdCBldmlkZW50IGZyb20gdGhlIHNjYXR0ZXJwbG90IG9uIHRoZSBsZWZ0LgotIFVzZSB0aGUgYHRpdGxlKClgIGZ1bmN0aW9uIHRvIGFkZCB0aGUgdGl0bGUgYCJTdW5mbG93ZXIgcGxvdCJgLgoKYGBge3J9CiMgU2V0IHVwIGEgc2lkZS1ieS1zaWRlIHBsb3QgYXJyYXkKCgojIENyZWF0ZSB0aGUgc3RhbmRhcmQgc2NhdHRlcnBsb3QKCgojIEFkZCB0aGUgdGl0bGUKCgojIENyZWF0ZSB0aGUgc3VuZmxvd2VycGxvdAoKCiMgQWRkIHRoZSB0aXRsZQoKYGBgCgoKIyMgVXNlZnVsIG9wdGlvbnMgZm9yIHRoZSBgYm94cGxvdCgpYCBmdW5jdGlvbgoKVGhlIGBib3hwbG90KClgIGZ1bmN0aW9uIHNob3dzIGhvdyB0aGUgZGlzdHJpYnV0aW9uIG9mIGEgbnVtZXJpY2FsIHZhcmlhYmxlIGB5YCBkaWZmZXJzIGFjcm9zcyB0aGUgdW5pcXVlIGxldmVscyBvZiBhIHNlY29uZCB2YXJpYWJsZSwgYHhgLiBUbyBiZSBlZmZlY3RpdmUsIHRoaXMgc2Vjb25kIHZhcmlhYmxlIHNob3VsZCBub3QgaGF2ZSB0b28gbWFueSB1bmlxdWUgbGV2ZWxzIChlLmcuLCAxMCBvciBmZXdlciBpcyBnb29kOyBtYW55IG1vcmUgdGhhbiB0aGlzIG1ha2VzIHRoZSBwbG90IGRpZmZpY3VsdCB0byBpbnRlcnByZXQpLgoKVGhlIGBib3hwbG90KClgIGZ1bmN0aW9uIGFsc28gaGFzIGEgbnVtYmVyIG9mIG9wdGlvbmFsIHBhcmFtZXRlcnMgYW5kIHRoaXMgZXhlcmNpc2UgYXNrcyB5b3UgdG8gdXNlIHRocmVlIG9mIHRoZW0gdG8gb2J0YWluIGEgbW9yZSBpbmZvcm1hdGl2ZSBwbG90OgoKLSBgdmFyd2lkdGhgIGFsbG93cyBmb3IgdmFyaWFibGUtd2lkdGggYm94cGxvdHMgdGhhdCBzaG93IHRoZSBkaWZmZXJlbnQgc2l6ZXMgb2YgdGhlIGRhdGEgc3Vic2V0cy4KLSBgbG9nYCBhbGxvd3MgZm9yIGxvZy10cmFuc2Zvcm1lZCB5LXZhbHVlcy4KLSBgbGFzYCBhbGxvd3MgZm9yIG1vcmUgcmVhZGFibGUgYXhpcyBsYWJlbHMuCgpUaGlzIGV4ZXJjaXNlIGFsc28gaWxsdXN0cmF0ZXMgdGhlIHVzZSBvZiB0aGUgZm9ybXVsYSBpbnRlcmZhY2U6IGB5IH4geGAgaW5kaWNhdGVzIHRoYXQgd2Ugd2FudCBhIGJveHBsb3Qgb2YgdGhlIGB5YCB2YXJpYWJsZSBhY3Jvc3MgdGhlIGRpZmZlcmVudCBsZXZlbHMgb2YgdGhlIGB4YCB2YXJpYWJsZS4gU2VlIGA/Ym94cGxvdGAgZm9yIG1vcmUgZGV0YWlscy4KCiMjIyBJbnN0cnVjdGlvbnMKCi0gVXNpbmcgdGhlIGZvcm11bGEgaW50ZXJmYWNlLCBjcmVhdGUgYSBib3hwbG90IHNob3dpbmcgdGhlIGRpc3RyaWJ1dGlvbiBvZiBudW1lcmljYWwgYGNyaW1gIHZhbHVlcyBvdmVyIHRoZSBkaWZmZXJlbnQgZGlzdGluY3QgYHJhZGAgdmFsdWVzIGZyb20gdGhlIGBCb3N0b25gIGRhdGEgZnJhbWUuIFVzZSB0aGUgYHZhcndpZHRoYCBwYXJhbWV0ZXIgdG8gb2J0YWluIHZhcmlhYmxlLXdpZHRoIGJveHBsb3RzLCBzcGVjaWZ5IGEgbG9nLXRyYW5zZm9ybWVkIHktYXhpcywgYW5kIHNldCB0aGUgYGxhc2AgcGFyYW1ldGVyIGVxdWFsIHRvIDEgdG8gb2J0YWluIGhvcml6b250YWwgbGFiZWxzIGZvciBib3RoIHRoZSB4LSBhbmQgeS1heGVzLgotIFVzZSB0aGUgYHRpdGxlKClgIGZ1bmN0aW9uIHRvIGFkZCB0aGUgdGl0bGUgYCJDcmltZSByYXRlIHZzLiByYWRpYWwgaGlnaHdheSBpbmRleCJgLgoKYGBge3J9CiMgQ3JlYXRlIGEgdmFyaWFibGUtd2lkdGggYm94cGxvdCB3aXRoIGxvZyB5LWF4aXMgJiBob3Jpem9udGFsIGxhYmVscwoKCiMgQWRkIGEgdGl0bGUKCmBgYAoKCiMjIFVzaW5nIHRoZSBtb3NhaWNwbG90KCkgZnVuY3Rpb24KCkEgbW9zYWljIHBsb3QgbWF5IGJlIHZpZXdlZCBhcyBhIHNjYXR0ZXJwbG90IGJldHdlZW4gY2F0ZWdvcmljYWwgdmFyaWFibGVzIGFuZCBpdCBpcyBzdXBwb3J0ZWQgaW4gUiB3aXRoIHRoZSBgbW9zYWljcGxvdCgpYCBmdW5jdGlvbi4KCkFzIHRoaXMgZXhhbXBsZSBzaG93cywgaW4gYWRkaXRpb24gdG8gY2F0ZWdvcmljYWwgdmFyaWFibGVzLCB0aGlzIHBsb3QgY2FuIGFsc28gYmUgdXNlZnVsIGluIHVuZGVyc3RhbmRpbmcgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIG51bWVyaWNhbCB2YXJpYWJsZXMsIGVpdGhlciBpbnRlZ2VyLSBvciByZWFsLXZhbHVlZCwgdGhhdCB0YWtlIG9ubHkgYSBmZXcgZGlzdGluY3QgdmFsdWVzLgoKTW9yZSBzcGVjaWZpY2FsbHksIHRoaXMgZXhlcmNpc2UgYXNrcyB5b3UgdG8gY29uc3RydWN0IGEgbW9zYWljIHBsb3Qgc2hvd2luZyB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIG51bWVyaWNhbCBgY2FyYmAgYW5kIGBjeWxgIHZhcmlhYmxlcyBmcm9tIHRoZSBgbXRjYXJzYCBkYXRhIGZyYW1lLCB2YXJpYWJsZXMgdGhhdCBleGhpYml0IDYgYW5kIDMgdW5pcXVlIHZhbHVlcywgcmVzcGVjdGl2ZWx5LgoKIyMjIEluc3RydWN0aW9ucwoKLSBBcHBseSB0aGUgYG1vc2FpY3Bsb3QoKWAgZnVuY3Rpb24gd2l0aCB0aGUgZm9ybXVsYSBpbnRlcmZhY2UgdG8gc2VlIGhvdyB0aGUgbGV2ZWxzIG9mIHRoZSBgY2FyYmAgdmFyaWFibGUgdmFyeSB3aXRoIHRoZSBsZXZlbHMgb2YgdGhlIGBjeWxgIHZhcmlhYmxlIGZyb20gdGhlIGBtdGNhcnNgIGRhdGEgZnJhbWUuCgpgYGB7cn0KIyBDcmVhdGUgYSBtb3NhaWMgcGxvdCB1c2luZyB0aGUgZm9ybXVsYSBpbnRlcmZhY2UKCmBgYAoKIyMgVXNpbmcgdGhlIGJhZ3Bsb3QoKSBmdW5jdGlvbgoKQSBzaW5nbGUgYm94IHBsb3QgZ2l2ZXMgYSBncmFwaGljYWwgcmVwcmVzZW50YXRpb24gb2YgdGhlIHJhbmdlIG9mIHZhcmlhdGlvbiBpbiBhIG51bWVyaWNhbCB2YXJpYWJsZSwgYmFzZWQgb24gZml2ZSBudW1iZXJzOgoKLSBUaGUgbWluaW11bSBhbmQgbWF4aW11bSB2YWx1ZXMKLSBUaGUgbWVkaWFuIChvciAibWlkZGxlIikgdmFsdWUKLSBUd28gaW50ZXJtZWRpYXRlIHZhbHVlcyBjYWxsZWQgdGhlIGxvd2VyIGFuZCB1cHBlciBxdWFydGlsZXMKCkluIGFkZGl0aW9uLCB0aGUgc3RhbmRhcmQgYm94IHBsb3QgY29tcHV0ZXMgYSBub21pbmFsIGRhdGEgcmFuZ2UgZnJvbSB0aHJlZSBvZiB0aGVzZSBudW1iZXJzIGFuZCBmbGFncyBwb2ludHMgZmFsbGluZyBvdXRzaWRlIHRoaXMgcmFuZ2UgYXMgb3V0bGllcnMsIHJlcHJlc2VudGluZyB0aGVtIGFzIGRpc3RpbmN0IHBvaW50cy4KClRoZSBiYWcgcGxvdCBleHRlbmRzIHRoaXMgcmVwcmVzZW50YXRpb24gdG8gdHdvIG51bWVyaWNhbCB2YXJpYWJsZXMsIHNob3dpbmcgdGhlaXIgcmVsYXRpb25zaGlwLCBib3RoIHdpdGhpbiB0d28tZGltZW5zaW9uYWwgImJhZ3MiIGNvcnJlc3BvbmRpbmcgdG8gdGhlICJib3giIGluIHRoZSBzdGFuZGFyZCBib3hwbG90LCBhbmQgaW5kaWNhdGluZyBvdXRseWluZyBwb2ludHMgb3V0c2lkZSB0aGVzZSBsaW1pdHMuCgpUaGlzIGV4ZXJjaXNlIGFza3MgeW91IHRvIGNvbnN0cnVjdCwgZmlyc3QsIHNpZGUtYnktc2lkZSBib3ggcGxvdHMgb2YgdGhlIGBNaW4uUHJpY2VgIGFuZCBgTWF4LlByaWNlYCB2YXJpYWJsZXMgZnJvbSB0aGUgYG10Y2Fyc2AgZGF0YXNldCwgYW5kIHRoZW4gdG8gdXNlIHRoZSBgYmFncGxvdCgpYCBmdW5jdGlvbiBmcm9tIHRoZSBgYXBscGFja2AgcGFja2FnZSB0byBjb25zdHJ1Y3QgdGhlIGNvcnJlc3BvbmRpbmcgYmFnIHBsb3QuCgojIyMgSW5zdHJ1Y3Rpb25zCgotIFVzZSB0aGUgYGJveHBsb3QoKWAgZnVuY3Rpb24gdG8gY29uc3RydWN0IHNpZGUtYnktc2lkZSBib3ggcGxvdHMgZm9yIGBNaW4uUHJpY2VgIGFuZCBgTWF4LlByaWNlYCBmcm9tIHRoZSBgQ2FyczkzYCBkYXRhIGZyYW1lLgotIExvYWQgdGhlIGBhcGxwYWNrYCBwYWNrYWdlIHRvIG1ha2UgdGhlIGBiYWdwbG90KClgIGZ1bmN0aW9uIGF2YWlsYWJsZS4KLSBDb25zdHJ1Y3QgdGhlIGJhZyBwbG90IHNob3dpbmcgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZSBgTWluLlByaWNlYCBhbmQgYE1heC5QcmljZWAgdmFyaWFibGVzIGZyb20gdGhlIGBDYXJzOTNgIGRhdGEgZnJhbWUuIFVzZSB0aGUgYGNleGAgcGFyYW1ldGVyIHRvIG1ha2UgdGhlIHBvaW50IHNpemVzIGluIHRoaXMgcGxvdCAyMCBwZXJjZW50IGxhcmdlciB0aGFuIHRoZSBkZWZhdWx0IHNpemUuCi0gVXNlIHRoZSBgYWJsaW5lKClgIGZ1bmN0aW9uIHRvIGFkZCBhIGRhc2hlZCBlcXVhbGl0eSByZWZlcmVuY2UgbGluZSB3aXRoIGludGVyY2VwdCAwIGFuZCBzbG9wZSAxLgoKYGBge3J9CiMgQ3JlYXRlIGEgc2lkZS1ieS1zaWRlIGJveHBsb3Qgc3VtbWFyeQoKIyBMb2FkIGFwbHBhY2sgdG8gbWFrZSB0aGUgYmFncGxvdCgpIGZ1bmN0aW9uIGF2YWlsYWJsZQoKCiMgQ3JlYXRlIGEgYmFncGxvdCBmb3IgdGhlIHNhbWUgdHdvIHZhcmlhYmxlcwoKIyBBZGQgYW4gZXF1YWxpdHkgcmVmZXJlbmNlIGxpbmUKCmBgYAoKCiMjIFBsb3R0aW5nIGNvcnJlbGF0aW9uIG1hdHJpY2VzIHdpdGggdGhlIGNvcnJwbG90KCkgZnVuY3Rpb24KCkNvcnJlbGF0aW9uIG1hdHJpY2VzIHdlcmUgaW50cm9kdWNlZCBpbiB0aGUgdmlkZW8gYXMgYSB1c2VmdWwgdG9vbCBmb3Igb2J0YWluaW5nIGEgcHJlbGltaW5hcnkgdmlldyBvZiB0aGUgcmVsYXRpb25zaGlwcyBiZXR3ZWVuIG11bHRpcGxlIG51bWVyaWNhbCB2YXJpYWJsZXMuCgpUaGlzIGV4ZXJjaXNlIGFza3MgeW91IHRvIHVzZSB0aGUgYGNvcnJwbG90KClgIGZ1bmN0aW9uIGZyb20gdGhlIGBjb3JycGxvdGAgcGFja2FnZSB0byB2aXN1YWxpemUgdGhpcyBjb3JyZWxhdGlvbiBtYXRyaXggZm9yIHRoZSBudW1lcmljYWwgdmFyaWFibGVzIGZyb20gdGhlIGBVU2NlcmVhbGAgZGF0YSBmcmFtZSBpbiB0aGUgYE1BU1NgIHBhY2thZ2UuIFJlY2FsbCB0aGF0IGluIHRoaXMgdmVyc2lvbiBvZiB0aGVzZSBwbG90cywgZWxsaXBzZXMgdGhhdCBhcmUgdGhpbiBhbmQgZWxvbmdhdGVkIGluZGljYXRlIGEgbGFyZ2UgY29ycmVsYXRpb24gdmFsdWUgYmV0d2VlbiB0aGUgaW5kaWNhdGVkIHZhcmlhYmxlcywgd2hpbGUgZWxsaXBzZXMgdGhhdCBhcmUgbmVhcmx5IGNpcmN1bGFyIGluZGljYXRlIGNvcnJlbGF0aW9ucyBuZWFyIHplcm8uCgojIyMgSW5zdHJ1Y3Rpb25zCgotIENyZWF0ZSBhIHN1YnNldCBvZiB0aGUgYFVTY2VyZWFsYCBkYXRhIGZyYW1lIHRoYXQgY29udGFpbnMgb25seSB0aGUgOSBudW1lcmljYWwgKGkuZS4sIG5vbi1mYWN0b3IpIHZhcmlhYmxlcy4gU2F2ZSB0aGUgcmVzdWx0IGFzIGBudW1lcmljYWxWYXJzYC4KLSBBcHBseSB0aGUgYGNvcigpYCBmdW5jdGlvbiB0byB0aGlzIHN1YnNldCB0byBjb21wdXRlIHRoZSBjb3JyZWxhdGlvbiBtYXRyaXggY29udGFpbmluZyB0aGUgY29ycmVsYXRpb24gY29lZmZpY2llbnRzIGJldHdlZW4gYWxsIHZhcmlhYmxlIHBhaXJzLiBTYXZlIHRoZSByZXN1bHQgYXMgYGNvcnJNYXRgLgotIEFwcGx5IHRoZSBgY29ycnBsb3QoKWAgZnVuY3Rpb24gdG8gZGlzcGxheSB0aGlzIGNvcnJlbGF0aW9uIG1hdHJpeCwgdXNpbmcgdGhlIGAiZWxsaXBzZSJgIG1ldGhvZC4KLSBXaGljaCB0d28gdmFyaWFibGVzIGFyZSBtb3N0IGhpZ2hseSBjb3JyZWxhdGVkIHdpdGggcG90YXNzaXVtPwoKYGBge3J9CiMgTG9hZCB0aGUgY29ycnBsb3QgbGlicmFyeSBmb3IgdGhlIGNvcnJwbG90KCkgZnVuY3Rpb24KCgojIEV4dHJhY3QgdGhlIG51bWVyaWNhbCB2YXJpYWJsZXMgZnJvbSBVU2NlcmVhbAoKCiMgQ29tcHV0ZSB0aGUgY29ycmVsYXRpb24gbWF0cml4IGZvciB0aGVzZSB2YXJpYWJsZXMKCgojIEdlbmVyYXRlIHRoZSBjb3JyZWxhdGlvbiBlbGxpcHNlIHBsb3QKCmBgYAoKCiMjIEJ1aWxkaW5nIGFuZCBwbG90dGluZyBycGFydCgpIG1vZGVscwoKSXQgd2FzIG5vdGVkIGluIHRoZSB2aWRlbyB0aGF0IGRlY2lzaW9uIHRyZWVzIHJlcHJlc2VudCBhIHBvcHVsYXIgZm9ybSBvZiBwcmVkaWN0aXZlIG1vZGVsIGJlY2F1c2UgdGhleSBhcmUgZWFzeSB0byB2aXN1YWxpemUgYW5kIGV4cGxhaW4uIEl0IHdhcyBhbHNvIG5vdGVkIHRoYXQgdGhlIGBycGFydGAgcGFja2FnZSBpcyBwcm9iYWJseSB0aGUgbW9zdCBwb3B1bGFyIG9mIHNldmVyYWwgUiBwYWNrYWdlcyB0aGF0IGNhbiBiZSB1c2VkIHRvIGJ1aWxkIGFuZCB2aXN1YWxpemUgdGhlc2UgbW9kZWxzLgoKVGhpcyBleGVyY2lzZSBhc2tzIHlvdSB0bywgZmlyc3QsIGJ1aWxkIGEgZGVjaXNpb24gdHJlZSBtb2RlbCB1c2luZyB0aGUgYHJwYXJ0KClgIGZ1bmN0aW9uIGZyb20gdGhpcyBwYWNrYWdlLCBhbmQgdGhlbiBkaXNwbGF5IHRoZSByZXN1bHRpbmcgbW9kZWwgc3RydWN0dXJlIHVzaW5nIHRoZSBnZW5lcmljIGZ1bmN0aW9ucyBgcGxvdCgpYCBhbmQgYHRleHQoKWAuCgojIyMgSW5zdHJ1Y3Rpb25zCgotIExvYWQgdGhlIGBycGFydGAgcGFja2FnZSB0byBtYWtlIHRoZSBgcnBhcnQoKWAgbW9kZWxpbmcgZnVuY3Rpb24gYW5kIHRoZSBhc3NvY2lhdGVkIG1ldGhvZHMgZm9yIGdlbmVyaWMgZnVuY3Rpb25zIGxpa2UgYHBsb3QoKWAgYXZhaWxhYmxlLgotIFVzZSB0aGUgYHJwYXJ0KClgIGZ1bmN0aW9uIHRvIGZpdCBhIGRlY2lzaW9uIHRyZWUgbW9kZWwgYHRyZWVfbW9kZWxgIHRoYXQgcHJlZGljdHMgYG1lZHZgIGluIHRoZSBgQm9zdG9uYCBkYXRhIGZyYW1lIGZyb20gYWxsIG9mIHRoZSBvdGhlciB2YXJpYWJsZXMgaW4gdGhpcyBkYXRhIGZyYW1lLgotIEFwcGx5IHRoZSBgcGxvdCgpYCBmdW5jdGlvbiB0byBgdHJlZV9tb2RlbGAgdG8gb2J0YWluIGFuIHVubGFiZWxsZWQgcGxvdCBvZiB0aGUgc3RydWN0dXJlIG9mIHRoaXMgZGVjaXNpb24gdHJlZSBtb2RlbC4KLSBBcHBseSB0aGUgYHRleHQoKWAgZnVuY3Rpb24gdG8gYHRyZWVfbW9kZWxgIHRvIGxhYmVsIHRoaXMgcGxvdC4gVG8gbWFrZSB0aGUgbGFiZWxzIGVhc2llciB0byByZWFkLCB1c2UgdGhlIGBjZXhgIHBhcmFtZXRlciB0byByZWR1Y2UgdGhlIHRleHQgdG8gNzAlIG9mIHRoZSBkZWZhdWx0IHNpemUuCgpgYGB7cn0KIyBMb2FkIHRoZSBycGFydCBsaWJyYXJ5CgoKIyBGaXQgYW4gcnBhcnQgbW9kZWwgdG8gcHJlZGljdCBtZWR2IGZyb20gYWxsIG90aGVyIEJvc3RvbiB2YXJpYWJsZXMKCgojIFBsb3QgdGhlIHN0cnVjdHVyZSBvZiB0aGlzIGRlY2lzaW9uIHRyZWUgbW9kZWwKCgojIEFkZCBsYWJlbHMgdG8gdGhpcyBwbG90CgpgYGAKCgojIEFkZGluZyBEZXRhaWxzIHRvIFBsb3RzCgojIyBJbnRyb2R1Y3Rpb24gdG8gdGhlIHBhcigpIGZ1bmN0aW9uCgpZb3UgYWxyZWFkeSBzYXcgaG93IHRoZSBgbWZyb3dgIHBhcmFtZXRlciB0byB0aGUgYHBhcigpYCBmdW5jdGlvbiBjb3VsZCBiZSB1c2VkIHRvIHBsb3QgbXVsdGlwbGUgZ3JhcGhzIGluIG9uZSBwYW5lLiBUaGUgYHBhcigpYCBmdW5jdGlvbiBhbHNvIGFsbG93cyB5b3UgdG8gc2V0IG1hbnkgb3RoZXIgZ3JhcGhpY3MgcGFyYW1ldGVycywgd2hvc2UgdmFsdWVzIHdpbGwgcmVtYWluIGluIGVmZmVjdCB1bnRpbCB0aGV5IGFyZSByZXNldCBieSBhIHN1YnNlcXVlbnQgYHBhcigpYCBjYWxsLgoKU3BlY2lmaWNhbGx5LCBhIGNhbGwgdG8gdGhlIGBwYXIoKWAgZnVuY3Rpb24gd2l0aCBubyBwYXJhbWV0ZXJzIHNwZWNpZmllZCB3aWxsIHJldHVybiBhIGxpc3Qgd2hvc2UgZWxlbWVudCBuYW1lcyBlYWNoIHNwZWNpZnkgYSBncmFwaGljcyBwYXJhbWV0ZXIgYW5kIHdob3NlIGVsZW1lbnQgdmFsdWVzIHNwZWNpZnkgdGhlIGNvcnJlc3BvbmRpbmcgZGVmYXVsdCB2YWx1ZXMgb2YgdGhlc2UgcGFyYW1ldGVycy4gVGhlc2UgcGFyYW1ldGVycyBtYXkgYmUgc2V0IGJ5IGEgY2FsbCBpbiB0aGUgZm9ybSBgcGFyKG5hbWUgPSB2YWx1ZSlgIHdoZXJlIG5hbWUgaXMgdGhlIG5hbWUgb2YgdGhlIHBhcmFtZXRlciB0byBiZSBzZXQgYW5kIHZhbHVlIGlzIHRoZSB2YWx1ZSB0byBiZSBhc3NpZ25lZCB0byB0aGlzIHBhcmFtZXRlci4KClRoZSBwdXJwb3NlIG9mIHRoaXMgZXhlcmNpc2UgaXMgdG8gZ2l2ZSBhbiBpZGVhIG9mIHdoYXQgdGhlc2UgZ3JhcGhpY3MgcGFyYW1ldGVycyBhcmUuIEluIHRoZSBzdWJzZXF1ZW50IGV4ZXJjaXNlcyB3ZSdsbCBzaG93IGhvdyBzb21lIG9mIHRoZXNlIHBhcmFtZXRlcnMgY2FuIGJlIHVzZWQgdG8gZW5oYW5jZSBwbG90IHJlc3VsdHMuCgojIyMgSW5zdHJ1Y3Rpb25zCgotIENhcHR1cmUgdGhlIHJldHVybiBmcm9tIHRoZSBgcGFyKClgIGZ1bmN0aW9uIGFzIHRoZSBjaGFyYWN0ZXIgdmVjdG9yIGBwbG90X3BhcnNgLgotIFNob3cgdGhlIG5hbWVzIG9mIHRoZXNlIGdyYXBoaWNzIHBhcmFtZXRlcnMgYnkgY2FsbGluZyBgbmFtZXMoKWAgb24gYHBsb3RfcGFyc2AuCi0gU2hvdyB0aGUgbnVtYmVyIG9mIHBhcmFtZXRlcnMgaW4gdGhpcyBsaXN0IGJ5IGNhbGxpbmcgYGxlbmd0aCgpYC4KCmBgYHtyfQojIEFzc2lnbiB0aGUgcmV0dXJuIHZhbHVlIGZyb20gdGhlIHBhcigpIGZ1bmN0aW9uIHRvIHBsb3RfcGFycwoKCiMgRGlzcGxheSB0aGUgbmFtZXMgb2YgdGhlIHBhcigpIGZ1bmN0aW9uJ3MgbGlzdCBlbGVtZW50cwoKCiMgRGlzcGxheSB0aGUgbnVtYmVyIG9mIHBhcigpIGZ1bmN0aW9uIGxpc3QgZWxlbWVudHMKCmBgYAoKCiMjIEV4cGxvcmluZyB0aGUgdHlwZSBvcHRpb24KCk9uZSBvZiB0aGUgaW1wb3J0YW50IGdyYXBoaWNzIHBhcmFtZXRlcnMgdGhhdCBjYW4gYmUgc2V0IHdpdGggdGhlIGBwYXIoKWAgZnVuY3Rpb24gaXMgYG1mcm93YCwgd2hpY2ggc3BlY2lmaWVzIHRoZSBudW1iZXJzIG9mIHJvd3MgYW5kIGNvbHVtbnMgaW4gYW4gYXJyYXkgb2YgcGxvdHMuIFZhbGlkIHZhbHVlcyBmb3IgdGhpcyBwYXJhbWV0ZXIgYXJlIHR3by1lbGVtZW50IG51bWVyaWNhbCB2ZWN0b3JzLCB3aG9zZSBmaXJzdCBlbGVtZW50IHNwZWNpZmllcyB0aGUgbnVtYmVyIG9mIHJvd3MgaW4gdGhlIHBsb3QgYXJyYXkgYW5kIHRoZSBzZWNvbmQgZWxlbWVudCBzcGVjaWZpZXMgdGhlIG51bWJlciBvZiByb3dzLgoKQSBtb3JlIGRldGFpbGVkIGRpc2N1c3Npb24gb2YgdXNpbmcgdGhlIGBtZnJvd2AgcGFyYW1ldGVyIGlzIGdpdmVuIGluIENoYXB0ZXIgNCBvZiB0aGlzIGNvdXJzZS4gRm9yIG5vdywgbm90ZSB0aGF0IHRvIHNwZWNpZnkgYSBwbG90IGFycmF5IHdpdGggdGhyZWUgcm93cyBhbmQgb25lIGNvbHVtbiwgdGhlIGNvbW1hbmQgd291bGQgYmUgYHBhcihtZnJvdyA9IGMoMywgMSkpYC4KClRoZSBmb2xsb3dpbmcgZXhlcmNpc2UgYWxzbyBpbnRyb2R1Y2VzIHRoZSB0eXBlIHBhcmFtZXRlciBmb3IgdGhlIGBwbG90KClgIGNvbW1hbmQsIHdoaWNoIHNwZWNpZmllcyBob3cgdGhlIHBsb3QgaXMgZHJhd24uIFRoZSBzcGVjaWZpYyB0eXBlIHZhbHVlcyB1c2VkIGhlcmUgYXJlOgoKLSBgInAiYCBmb3IgInBvaW50cyIKLSBgImwiYCBmb3IgImxpbmVzIgotIGAibyJgIGZvciAib3ZlcmxhaWQiIChpLmUuLCBsaW5lcyBvdmVybGFpZCB3aXRoIHBvaW50cykKLSBgInMiYCBmb3IgInN0ZXBzIgoKIyMjIEluc3RydWN0aW9ucwoKLSBVc2UgdGhlIGBwYXIoKWAgZnVuY3Rpb24gdG8gc2V0IHRoZSBgbWZyb3dgIHBhcmFtZXRlciBmb3IgYSB0d28tYnktdHdvIHBsb3QgYXJyYXkuCi0gR2VuZXJhdGUgYSBwbG90IG9mIGJyYWluIHdlaWdodHMgZnJvbSB0aGUgYEFuaW1hbHMyYCBkYXRhIGZyYW1lLCB3aXRoIG9ic2VydmF0aW9ucyBwbG90dGVkIGFzIHBvaW50cyBhbmQgdGhlIHRpdGxlIGAicG9pbnRzImAgYnkgY2FsbGluZyB0aGUgYHRpdGxlKClgIGZ1bmN0aW9uLgotIFJlcGVhdCwgd2l0aCBvYnNlcnZhdGlvbnMgcGxvdHRlZCBhcyBsaW5lcyBhbmQgdGhlIHRpdGxlIGAibGluZXMiYC4KLSBSZXBlYXQsIHdpdGggb2JzZXJ2YXRpb25zIHBsb3R0ZWQgYXMgb3ZlcmxhaWQgcG9pbnRzIGFuZCBsaW5lcyBhbmQgdGhlIHRpdGxlIGAib3ZlcmxhaWQiYC4KLSBSZXBlYXQsIHdpdGggb2JzZXJ2YXRpb25zIHBsb3R0ZWQgYXMgc3RlcHMgYW5kIHRoZSB0aXRsZSBgInN0ZXBzImAuCgpgYGB7cn0KIyBTZXQgdXAgYSAyLWJ5LTIgcGxvdCBhcnJheQoKCiMgUGxvdCB0aGUgQW5pbWFsczIgYnJhaW4gd2VpZ2h0IGRhdGEgYXMgcG9pbnRzCgoKIyBBZGQgdGhlIHRpdGxlCgoKIyBQbG90IHRoZSBicmFpbiB3ZWlnaHRzIHdpdGggbGluZXMKCgojIEFkZCB0aGUgdGl0bGUKCgojIFBsb3QgdGhlIGJyYWluIHdlaWdodHMgYXMgbGluZXMgb3ZlcmxhaWQgd2l0aCBwb2ludHMKCgojIEFkZCB0aGUgdGl0bGUKCmBgYAoKCiMjIFRoZSBzdXJwcmlzaW5nIHV0aWxpdHkgb2YgdGhlIHR5cGUgIm4iIG9wdGlvbgoKVGhlIGB0eXBlID0gIm4iYCBvcHRpb24gd2FzIGRpc2N1c3NlZCBpbiB0aGUgdmlkZW8gYW5kIHRoaXMgZXhlcmNpc2UgcHJvdmlkZXMgYSBzaW1wbGUgZXhhbXBsZS4gVGhpcyBvcHRpb24gaXMgZXNwZWNpYWxseSB1c2VmdWwgaXMgd2hlbiB3ZSBhcmUgcGxvdHRpbmcgZGF0YSBmcm9tIG11bHRpcGxlIHNvdXJjZXMgb24gYSBjb21tb24gc2V0IG9mIGF4ZXMuIEluIHN1Y2ggY2FzZXMsIHdlIGNhbiBjb21wdXRlIHJhbmdlcyBmb3IgdGhlIHgtIGFuZCB5LWF4ZXMgc28gdGhhdCBhbGwgZGF0YSBwb2ludHMgd2lsbCBhcHBlYXIgb24gdGhlIHBsb3QsIGFuZCB0aGVuIGFkZCB0aGUgZGF0YSB3aXRoIHN1YnNlcXVlbnQgY2FsbHMgdG8gYHBvaW50cygpYCBvciBgbGluZXMoKWAgYXMgYXBwcm9wcmlhdGUuCgpUaGlzIGV4ZXJjaXNlIGFza3MgeW91IHRvIGdlbmVyYXRlIGEgcGxvdCB0aGF0IGNvbXBhcmVzIG1pbGVhZ2UgdnMuIGhvcnNlcG93ZXIgZGF0YSBmcm9tIHR3byBkaWZmZXJlbnQgc291cmNlczogdGhlIGBtdGNhcnNgIGRhdGEgZnJhbWUgaW4gdGhlIGBkYXRhc2V0c2AgcGFja2FnZSBhbmQgdGhlIGBDYXJzOTNgIGRhdGEgZnJhbWUgaW4gdGhlIGBNQVNTYCBwYWNrYWdlLiBUbyBkaXN0aW5ndWlzaCB0aGUgZGlmZmVyZW50IHJlc3VsdHMgZnJvbSB0aGVzZSBkYXRhIHNvdXJjZXMsIHRoZSBncmFwaGljcyBwYXJhbWV0ZXIgYHBjaGAgaXMgdXNlZCB0byBzcGVjaWZ5IHBvaW50IHNoYXBlcy4gU2VlIGA/cG9pbnRzYCBmb3IgYSBjb21wcmVoZW5zaXZlIGxpc3Qgb2Ygc29tZSBgcGNoYCB2YWx1ZXMgYW5kIHRoZWlyIGNvcnJlc3BvbmRpbmcgcG9pbnQgc2hhcGVzLgoKIyMjIEluc3RydWN0aW9ucwoKLSBDb21wdXRlIGBtYXhfaHBgIGFzIHRoZSBtYXhpbXVtIG9mIGBIb3JzZXBvd2VyYCBmcm9tIHRoZSBgQ2FyczkzYCBkYXRhIGZyYW1lIGFuZCBgaHBgIGZyb20gdGhlIGBtdGNhcnNgIGRhdGEgZnJhbWUuCi0gQ29tcHV0ZSBgbWF4X21wZ2AgYXMgdGhlIG1heGltdW0gb2YgYE1QRy5jaXR5YCBmcm9tIHRoZSBgQ2FyczkzYCBkYXRhIGZyYW1lLCBgTVBHLmhpZ2h3YXlgIGZyb20gdGhpcyBkYXRhIGZyYW1lLCBhbmQgYG1wZ2AgZnJvbSB0aGUgYG10Y2Fyc2AgZGF0YSBmcmFtZS4KLSBVc2luZyB0aGUgYHR5cGUgPSAibiJgIG9wdGlvbiwgc2V0IHVwIGEgcGxvdCB3aXRoIGFuIHgtYXhpcyB0aGF0IHJ1bnMgZnJvbSBgemVyb2AgdG8gYG1heF9ocGAgYW5kIGEgeS1heGlzIHRoYXQgcnVucyBmcm9tIGB6ZXJvYCB0byBgbWF4X21wZ2AsIHdpdGggbGFiZWxzIGBIb3JzZXBvd2VyYCBhbmQgYE1pbGVzIHBlciBnYWxsb25gLgotIFVzaW5nIHRoZSBgcG9pbnRzKClgIGZ1bmN0aW9uLCBhZGQgYG1wZ2AgdnMuIGBocGAgZnJvbSB0aGUgYG10Y2Fyc2AgZGF0YSBmcmFtZSB0byB0aGUgcGxvdCBhcyBvcGVuIGNpcmNsZXMgKGBwY2ggPSAxYCkuCi0gVXNpbmcgdGhlIGBwb2ludHMoKWAgZnVuY3Rpb24sIGFkZCBgTVBHLmNpdHlgIHZzLiBgSG9yc2Vwb3dlcmAgdG8gdGhlIHBsb3QgYXMgc29saWQgc3F1YXJlcyAocmVmZXIgdG8gdGhlIHBsb3Qgb2YgYHBjaGAgdmFsdWVzKS4KLSBVc2luZyB0aGUgYHBvaW50cygpYCBmdW5jdGlvbiwgYWRkIGBNUEcuaGlnaHdheWAgdnMuIGBIb3JzZXBvd2VyYCB0byB0aGUgcGxvdCBhcyBvcGVuIHRyaWFuZ2xlcyBwb2ludGluZyB1cHdhcmRzIChyZWZlciB0byB0aGUgcGxvdCBvZiBgcGNoYCB2YWx1ZXMpLgoKYGBge3J9CiMgQ29tcHV0ZSBtYXhfaHAKbWF4X2hwIDwtIG1heChfX18sIF9fXykKCiMgQ29tcHV0ZSBtYXhfbXBnCm1heF9tcGcgPC0gbWF4KF9fXywgX19fLCBfX18pCgojIENyZWF0ZSBwbG90IHdpdGggdHlwZSA9ICJuIiAgICAgICAgICAgICAgIApwbG90KF9fXywgX19fLAogICAgIHR5cGUgPSBfX18sIHhsaW0gPSBjKDAsIG1heF9ocCksCiAgICAgeWxpbSA9IF9fXywgeGxhYiA9IF9fXywKICAgICB5bGFiID0gX19fKQoKIyBBZGQgb3BlbiBjaXJjbGVzIHRvIHBsb3QKcG9pbnRzKF9fXywgX19fLCBwY2ggPSBfX18pCgojIEFkZCBzb2xpZCBzcXVhcmVzIHRvIHBsb3QKCgojIEFkZCBvcGVuIHRyaWFuZ2xlcyB0byBwbG90CgpgYGAKCgojIyBUaGUgbGluZXMoKSBmdW5jdGlvbiBhbmQgbGluZSB0eXBlcwoKQXMgbm90ZWQgaW4gQ2hhcHRlciAyLCBudW1lcmljYWwgZGF0YSBpcyBvZnRlbiBhc3N1bWVkIHRvIGNvbmZvcm0gYXBwcm94aW1hdGVseSB0byBhIEdhdXNzaWFuIHByb2JhYmlsaXR5IGRpc3RyaWJ1dGlvbiwgY2hhcmFjdGVyaXplZCBieSB0aGUgYmVsbCBjdXJ2ZS4gT25lIHBvaW50IG9mIHRoaXMgZXhlcmNpc2UgaXMgdG8gc2hvdyB3aGF0IHRoaXMgYmVsbCBjdXJ2ZSBsb29rcyBsaWtlIGZvciBleGFjdGx5IEdhdXNzaWFuIGRhdGEgYW5kIHRoZSBvdGhlciBpcyB0byBzaG93IGhvdyB0aGUgYGxpbmVzKClgIGZ1bmN0aW9uIGNhbiBiZSB1c2VkIHRvIGFkZCBsaW5lcyB0byBhbiBleGlzdGluZyBwbG90LgoKVGhlIGN1cnZlcyB5b3UgYXJlIGFza2VkIHRvIGRyYXcgaGVyZSBoYXZlIHRoZSBzYW1lIGJhc2ljIHNoYXBlIGJ1dCBkaWZmZXIgaW4gdGhlaXIgZGV0YWlscyAoc3BlY2lmaWNhbGx5LCB0aGUgbWVhbnMgYW5kIHN0YW5kYXJkIGRldmlhdGlvbnMgb2YgdGhlc2UgR2F1c3NpYW4gZGlzdHJpYnV0aW9ucyBhcmUgZGlmZmVyZW50KS4gRm9yIHRoaXMgcmVhc29uLCBpdCBpcyB1c2VmdWwgdG8gZHJhdyB0aGVzZSBjdXJ2ZXMgd2l0aCBkaWZmZXJlbnQgbGluZSB0eXBlcyB0byBoZWxwIHVzIGRpc3Rpbmd1aXNoIHRoZW0uCgpOb3RlIHRoYXQgbGluZSB0eXBlcyBhcmUgc2V0IGJ5IHRoZSBgbHR5YCBhcmd1bWVudCwgd2l0aCB0aGUgZGVmYXVsdCB2YWx1ZSBgbHR5ID0gMWAgc3BlY2lmeWluZyBzb2xpZCBsaW5lcywgYGx0eSA9IDJgIHNwZWNpZnlpbmcgZGFzaGVkIGxpbmVzLCBhbmQgYGx0eSA9IDNgIHNwZWNpZnlpbmcgZG90dGVkIGxpbmVzLiBBbHNvIG5vdGUgdGhhdCB0aGUgYGx3ZGAgYXJndW1lbnQgc3BlY2lmaWVzIHRoZSByZWxhdGl2ZSB3aWR0aC4KCiMjIyBJbnN0cnVjdGlvbnMKCi0gQ3JlYXRlIGEgbnVtZXJpY2FsIHZhcmlhYmxlIGB4YCB3aXRoIGAyMDBgIGV2ZW5seS1zcGFjZWQgdmFsdWVzIGZyb20gYDBgIHRvIGAxMGAuCi0gVXNpbmcgdGhlIGBkbm9ybSgpYCBmdW5jdGlvbiwgZ2VuZXJhdGUgYSB2ZWN0b3IgYGdhdXNzMWAgb2YgR2F1c3NpYW4gcHJvYmFiaWxpdHkgZGVuc2l0aWVzIGZvciB0aGlzIHJhbmdlIG9mIGB4YCB2YWx1ZXMsIHdpdGggbWVhbiBgMmAgYW5kIHN0YW5kYXJkIGRldmlhdGlvbiBgMC4yYC4KLSBVc2luZyB0aGUgYGRub3JtKClgIGZ1bmN0aW9uLCBnZW5lcmF0ZSBhIHZlY3RvciBgZ2F1c3MyYCBvZiBHYXVzc2lhbiBwcm9iYWJpbGl0eSBkZW5zaXRpZXMgZm9yIHRoaXMgcmFuZ2Ugb2YgYHhgIHZhbHVlcywgd2l0aCBtZWFuIGA0YCBhbmQgc3RhbmRhcmQgZGV2aWF0aW9uIGAwLjVgLgotIEdlbmVyYXRlIGEgcGxvdCBvZiBgZ2F1c3MxYCB2cy4gYHhgIHdpdGggbGluZXMgYW5kIGEgeS1heGlzIGxhYmVsIGAiR2F1c3NpYW4gcHJvYmFiaWxpdHkgZGVuc2l0eSJgLgotIFVzaW5nIHRoZSBgbGluZXMoKWAgZnVuY3Rpb24sIGFkZCBhIHNlY29uZCBkYXNoZWQgbGluZSBmb3IgYGdhdXNzMmAgdnMuIGB4YCB3aXRoIHJlbGF0aXZlIHdpZHRoIDMgKHJlZmVyIHRvIHRoZSBsaW5lIHR5cGUgcGxvdCB0byBzZWxlY3QgdGhlIGBsdHlgIHBhcmFtZXRlcikuCgpgYGB7cn0KIyBDcmVhdGUgdGhlIG51bWVyaWNhbCB2ZWN0b3IgeAp4IDwtIHNlcShfX18sIF9fXywgbGVuZ3RoID0gX19fKQoKIyBDb21wdXRlIHRoZSBHYXVzc2lhbiBkZW5zaXR5IGZvciB4IHdpdGggbWVhbiAyIGFuZCBzdGFuZGFyZCBkZXZpYXRpb24gMC4yCmdhdXNzMSA8LSBkbm9ybShfX18sIG1lYW4gPSBfX18sIHNkID0gX19fKQoKIyBDb21wdXRlIHRoZSBHYXVzc2lhbiBkZW5zaXR5IHdpdGggbWVhbiA0IGFuZCBzdGFuZGFyZCBkZXZpYXRpb24gMC41CgoKIyBQbG90IHRoZSBmaXJzdCBHYXVzc2lhbiBkZW5zaXR5CgoKIyBBZGQgbGluZXMgZm9yIHRoZSBzZWNvbmQgR2F1c3NpYW4gZGVuc2l0eQoKYGBgCgojIyBUaGUgcG9pbnRzKCkgZnVuY3Rpb24gYW5kIHBvaW50IHR5cGVzCgpPbmUgYWR2YW50YWdlIG9mIHNwZWNpZnlpbmcgdGhlIGBwY2hgIGFyZ3VtZW50IGxvY2FsbHkgaXMgdGhhdCwgaW4gYSBjYWxsIHRvIGZ1bmN0aW9ucyBsaWtlIHBsb3QoKSBvciBwb2ludHMoKSwgbG9jYWwgc3BlY2lmaWNhdGlvbiBhbGxvd3MgdXMgdG8gbWFrZSBwY2ggZGVwZW5kIG9uIGEgdmFyaWFibGUgaW4gb3VyIGRhdGFzZXQuIFRoaXMgcHJvdmlkZXMgYSBzaW1wbGUgd2F5IG9mIGluZGljYXRpbmcgZGlmZmVyZW50IGRhdGEgc3Vic2V0cyB3aXRoIGRpZmZlcmVudCBwb2ludCBzaGFwZXMgb3Igc3ltYm9scy4KClRoaXMgZXhlcmNpc2UgYXNrcyB5b3UgdG8gZ2VuZXJhdGUgdHdvIHBsb3RzIG9mIGBtcGdgIHZzLiBgaHBgIGZyb20gdGhlIGBtdGNhcnNgIGRhdGEgZnJhbWUgaW4gdGhlIGBkYXRhc2V0c2AgcGFja2FnZS4gVGhlIGZpcnN0IHBsb3Qgc3BlY2lmaWVzIHRoZSBwb2ludCBzaGFwZXMgdXNpbmcgbnVtZXJpY2FsIHZhbHVlcyBvZiB0aGUgYHBjaGAgYXJndW1lbnQgZGVmaW5lZCBieSB0aGUgYGN5bGAgdmFyaWFibGUgaW4gdGhlIGBtdGNhcnNgIGRhdGEgZnJhbWUuIFRoZSBzZWNvbmQgcGxvdCBpbGx1c3RyYXRlcyB0aGUgZmFjdCB0aGF0IGBwY2hgIGNhbiBhbHNvIGJlIHNwZWNpZmllZCBhcyBhIHZlY3RvciBvZiBzaW5nbGUgY2hhcmFjdGVycywgY2F1c2luZyBlYWNoIHBvaW50IHRvIGJlIGRyYXduIGFzIHRoZSBjb3JyZXNwb25kaW5nIGNoYXJhY3Rlci4KCiMjIyBJbnN0cnVjdGlvbnMKCi0gQ3JlYXRlIGFuIGVtcHR5IHBsb3Qgb2YgYG1wZ2AgdnMuIGBocGAgdXNpbmcgdGhlIGB0eXBlID0gIm4iYCBvcHRpb24gZnJvbSB0aGUgYG10Y2Fyc2AgZGF0YSBmcmFtZSwgd2l0aCBheGlzIGxhYmVscyBgIkhvcnNlcG93ZXIiYCBhbmQgYCJHYXMgbWlsZWFnZSIsLgotIFVzaW5nIHRoZSBgcG9pbnRzKClgIGZ1bmN0aW9uLCBhZGQgdGhlIGBtcGdgIHZzLiBgaHBgIGRhdGEsIHdpdGggYHBjaGAgc3BlY2lmaWVkIGJ5IHRoZSBudW1lcmljIHZhbHVlcyBvZiBgY3lsYC4KLSBSZXBlYXQgYm90aCBvZiB0aGUgcHJldmlvdXMgc3RlcHMsIGV4Y2VwdCB3aXRoIGBwY2hgIHNwZWNpZmllZCBieSB0aGUgY2hhcmFjdGVyIHZhbHVlcyBvZiBgY3lsYC4KCmBgYHtyfQojIENyZWF0ZSBhbiBlbXB0eSBwbG90IHVzaW5nIHR5cGUgPSAibiIKCgojIEFkZCBwb2ludHMgd2l0aCBzaGFwZXMgZGV0ZXJtaW5lZCBieSBjeWxpbmRlciBudW1iZXIKcG9pbnRzKF9fXywgX19fLCBwY2ggPSBfX18pCgojIENyZWF0ZSBhIHNlY29uZCBlbXB0eSBwbG90CgoKIyBBZGQgcG9pbnRzIHdpdGggc2hhcGVzIGFzIGN5bGluZGVyIGNoYXJhY3RlcnMKCmBgYAoKCiMjIEFkZGluZyB0cmVuZCBsaW5lcyBmcm9tIGxpbmVhciByZWdyZXNzaW9uIG1vZGVscwoKVGhlIGxvdy1sZXZlbCBwbG90IGZ1bmN0aW9uIGBhYmxpbmUoKWAgYWRkcyBhIHN0cmFpZ2h0IGxpbmUgdG8gYW4gZXhpc3RpbmcgcGxvdC4gVGhpcyBsaW5lIGlzIHNwZWNpZmllZCBieSBhbiBpbnRlcmNlcHQgcGFyYW1ldGVyIGBhYCBhbmQgYSBzbG9wZSBwYXJhbWV0ZXIgYGJgLCBhbmQgdGhlIHNpbXBsZXN0IHdheSB0byBzZXQgdGhlc2UgcGFyYW1ldGVycyBpcyBkaXJlY3RseS4gRm9yIGV4YW1wbGUsIHRoZSBjb21tYW5kIGBhYmxpbmUoYSA9IDAsIGIgPSAxKWAgYWRkcyBhbiBlcXVhbGl0eSByZWZlcmVuY2UgbGluZSB3aXRoIHplcm8gaW50ZXJjZXB0IGFuZCB1bml0IChpLmUuIDEpIHNsb3BlOiBwb2ludHMgZm9yIHdoaWNoIGB5ID0geGAgZmFsbCBvbiB0aGlzIHJlZmVyZW5jZSBsaW5lLCB3aGlsZSBwb2ludHMgd2l0aCBgeSA+IHhgIGZhbGwgYWJvdmUgaXQsIGFuZCBwb2ludHMgd2l0aCBgeSA8IHhgIGZhbGwgYmVsb3cgaXQuCgpBbiBhbHRlcm5hdGl2ZSB3YXkgb2Ygc3BlY2lmeWluZyB0aGVzZSBwYXJhbWV0ZXJzIGlzIHRocm91Z2ggYSBsaW5lYXIgcmVncmVzc2lvbiBtb2RlbCB0aGF0IGRldGVybWluZXMgdGhlbSBmcm9tIGRhdGEuIE9uZSBjb21tb24gYXBwbGljYXRpb24gaXMgdG8gZ2VuZXJhdGUgYSBzY2F0dGVycGxvdCBvZiBgeWAgdmVyc3VzIGB4YCwgdGhlbiBmaXQgYSBsaW5lYXIgbW9kZWwgdGhhdCBwcmVkaWN0cyBgeWAgZnJvbSBgeGAsIGFuZCBmaW5hbGx5IGNhbGwgYGFibGluZSgpYCB0byBhZGQgdGhpcyBiZXN0IGZpdCBsaW5lIHRvIHRoZSBwbG90LgoKVGhpcyBleGVyY2lzZSBhc2tzIHlvdSB0byBkbyB0aGlzIGZvciB0aGUgYEdhc2AgdmVyc3VzIGBUZW1wYCBkYXRhIGZyb20gdGhlIGB3aGl0ZXNpZGVgIGRhdGEgZnJhbWUgaW4gdGhlIGBNQVNTYCBwYWNrYWdlLiBUaGUgc3RhbmRhcmQgUiBmdW5jdGlvbiB0aGF0IGZpdHMgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWxzIGlzIGBsbSgpYCwgd2hpY2ggc3VwcG9ydHMgdGhlIGZvcm11bGEgaW50ZXJmYWNlLiBUaHVzLCB0byBmaXQgYSBsaW5lYXIgbW9kZWwgdGhhdCBwcmVkaWN0cyBgeWAgZnJvbSBgeGAgaW4gdGhlIGRhdGEgZnJhbWUgYGRmYCwgdGhlIGNhbGwgd291bGQgYmUgYGxtKHkgfiB4LCBkYXRhID0gZGYpYC4gVGhpcyBjYWxsIHJldHVybnMgYSBsaW5lYXIgbW9kZWwgb2JqZWN0LCB3aGljaCBjYW4gdGhlbiBiZSBwYXNzZWQgYXMgYW4gYXJndW1lbnQgdG8gdGhlIGBhYmxpbmUoKWAgZnVuY3Rpb24gdG8gZHJhdyB0aGUgZGVzaXJlZCBsaW5lIG9uIG91ciBwbG90LgoKIyMjIEluc3RydWN0aW9ucwoKLSBVc2UgdGhlIGBsbSgpYCBmdW5jdGlvbiB0byBjcmVhdGUgYGxpbmVhcl9tb2RlbGAsIGEgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWwgdGhhdCBwcmVkaWN0cyBgR2FzYCBmcm9tIGBUZW1wYCBmcm9tIHRoZSBgd2hpdGVzaWRlYCBkYXRhIGZyYW1lLgotIEdlbmVyYXRlIGEgc2NhdHRlcnBsb3Qgb2YgYEdhc2AgdnMuIGBUZW1wYC4KLSBVc2luZyB0aGUgYGFibGluZSgpYCBmdW5jdGlvbiwgYWRkIGEgZGFzaGVkIHJlZmVyZW5jZSBsaW5lIHRoYXQgc2hvd3MgdGhlIHByZWRpY3Rpb25zIG9mIGBsaW5lYXJfbW9kZWxgLgoKYGBge3J9CiMgQnVpbGQgYSBsaW5lYXIgcmVncmVzc2lvbiBtb2RlbCBmb3IgdGhlIHdoaXRlc2lkZSBkYXRhCgoKIyBDcmVhdGUgYSBHYXMgdnMuIFRlbXAgc2NhdHRlcnBsb3QgZnJvbSB0aGUgd2hpdGVzaWRlIGRhdGEKCgojIFVzZSBhYmxpbmUoKSB0byBhZGQgdGhlIGxpbmVhciByZWdyZXNzaW9uIGxpbmUKCmBgYAoKCiMjIFVzaW5nIHRoZSBgdGV4dCgpYCBmdW5jdGlvbiB0byBsYWJlbCBwbG90IGZlYXR1cmVzCgpPbmUgb2YgdGhlIG1haW4gdXNlcyBvZiB0aGUgYHRleHQoKWAgZnVuY3Rpb24gaXMgdG8gYWRkIGluZm9ybWF0aXZlIGxhYmVscyB0byBhIGRhdGEgcGxvdC4gVGhlIGB0ZXh0KClgIGZ1bmN0aW9uIHRha2VzIHRocmVlIGFyZ3VtZW50czoKCi0gYHhgLCB3aGljaCBzcGVjaWZpZXMgdGhlIHZhbHVlIGZvciB0aGUgYHhgIHZhcmlhYmxlLAotIGB5YCwgd2hpY2ggc3BlY2lmaWVzIHRoZSB2YWx1ZSBmb3IgdGhlIGB5YCB2YXJpYWJsZSwgYW5kCi0gYGxhYmVsYCwgd2hpY2ggc3BlY2lmaWVzIHRoZSBsYWJlbCBmb3IgdGhlIGB4LXlgIHZhbHVlIHBhaXIuCgpUaGlzIGV4ZXJjaXNlIGFza3MgeW91IHRvIGZpcnN0IGNyZWF0ZSBhIHNjYXR0ZXJwbG90IG9mIGNpdHkgZ2FzIG1pbGVhZ2UgdmVyc3VzIGhvcnNlcG93ZXIgZnJvbSB0aGUgQ2FyczkzIGRhdGEsIHRoZW4gaWRlbnRpZnkgYW4gaW50ZXJlc3Rpbmcgc3Vic2V0IG9mIHRoZSBkYXRhIChpLmUuIHRoZSAzLWN5bGluZGVyIGNhcnMpIGFuZCBsYWJlbCB0aGVzZSBwb2ludHMuIFlvdSB3aWxsIGZpbmQgdGhhdCBhc3NpZ25pbmcgYSB2ZWN0b3IgdG8gdGhlIGB4YCwgYHlgLCBhbmQgYGxhYmVsYCBhcmd1bWVudHMgdG8gYHRleHQoKWAgd2lsbCByZXN1bHQgaW4gbGFiZWxpbmcgbXVsdGlwbGUgcG9pbnRzIGF0IG9uY2UuCgojIyMgSW5zdHJ1Y3Rpb25zCgotIENyZWF0ZSBhIHNjYXR0ZXJwbG90IG9mIGBNUEcuY2l0eWAgdnMuIGBIb3JzZXBvd2VyYCBmcm9tIHRoZSBgQ2FyczkzYCBkYXRhIGZyYW1lLCB3aXRoIHBvaW50cyByZXByZXNlbnRlZCBhcyBzb2xpZCBzcXVhcmVzLiBSZWNhbGwgdGhhdCB0aGUgYHBjaGAgdmFsdWUgZm9yIHNvbGlkIHNxdWFyZXMgaXMgYDE1YC4KLSBDcmVhdGUgdGhlIHZhcmlhYmxlIGBpbmRleDNgIHVzaW5nIHRoZSBgd2hpY2goKWAgZnVuY3Rpb24gdGhhdCBpZGVudGlmaWVzIGFsbCAzLWN5bGluZGVyIGNhcnMuCi0gTGFiZWwgdGhlIGBNYWtlYCBvZiBlYWNoIDMtY3lsaW5kZXIgY2FyIGluIHRoZSBgQ2FyczkzYCBkYXRhIGZyYW1lIHVzaW5nIHRoZSBgdGV4dCgpYCBmdW5jdGlvbi4gVXNlIHRoZSBgYWRqYCBhcmd1bWVudCB0byBzcGVjaWZ5IGxlZnQtanVzdGlmaWVkIHRleHQgaW4geW91ciBsYWJlbHMuCi0gVXNlIHRoZSB6b29tIGZlYXR1cmUgaW4gdGhlIFBsb3RzIHdpbmRvdyB0byBzZWUgdGhpcyBwbG90IG1vcmUgY2xlYXJseS4KCmBgYHtyfQojIENyZWF0ZSBNUEcuY2l0eSB2cy4gSG9yc2Vwb3dlciBwbG90IHdpdGggc29saWQgc3F1YXJlcwoKCiMgQ3JlYXRlIGluZGV4MywgcG9pbnRpbmcgdG8gMy1jeWxpbmRlciBjYXJzCgoKIyBBZGQgdGV4dCBnaXZpbmcgbmFtZXMgb2YgY2FycyBuZXh0IHRvIGRhdGEgcG9pbnRzCnRleHQoeCA9IF9fXywgCiAgICAgeSA9IF9fXywKICAgICBsYWJlbHMgPSBfX18sIGFkaiA9IF9fXykKYGBgCgoKIyMgQWRqdXN0aW5nIHRleHQgcG9zaXRpb24sIHNpemUsIGFuZCBmb250CgpUaGUgcHJldmlvdXMgZXhlcmNpc2UgYWRkZWQgZXhwbGFuYXRvcnkgdGV4dCB0byBhIHNjYXR0ZXJwbG90LiBUaGUgcHVycG9zZSBvZiB0aGlzIGV4ZXJjaXNlIGlzIHRvIGltcHJvdmUgdGhpcyBwbG90IGJ5IG1vZGlmeWluZyB0aGUgdGV4dCBwbGFjZW1lbnQsIGluY3JlYXNpbmcgdGhlIHRleHQgc2l6ZSwgYW5kIGRpc3BsYXlpbmcgdGhlIHRleHQgaW4gYm9sZGZhY2UuCgpJdCB3YXMgbm90ZWQgdGhhdCB0aGUgYGFkamAgYXJndW1lbnQgdG8gdGhlIGB0ZXh0KClgIGZ1bmN0aW9uIGRldGVybWluZXMgdGhlIGhvcml6b250YWwgcGxhY2VtZW50IG9mIHRoZSB0ZXh0IGFuZCBpdCBjYW4gdGFrZSBhbnkgdmFsdWUgYmV0d2VlbiAwIGFuZCAxLiBJbiBmYWN0LCB0aGlzIGFyZ3VtZW50IGNhbiB0YWtlIHZhbHVlcyBvdXRzaWRlIHRoaXMgcmFuZ2UuIFRoYXQgaXMsIG1ha2luZyB0aGlzIHZhbHVlIG5lZ2F0aXZlIGNhdXNlcyB0aGUgdGV4dCB0byBzdGFydCB0byB0aGUgcmlnaHQgb2YgdGhlIHNwZWNpZmllZCBgeGAgcG9zaXRpb24uIFNpbWlsYXJseSwgbWFraW5nIGBhZGpgIGdyZWF0ZXIgdGhhbiAxIGNhdXNlcyB0aGUgdGV4dCB0byBlbmQgdG8gdGhlIGxlZnQgb2YgdGhlIGB4YCBwb3NpdGlvbi4KCkFub3RoZXIgdXNlZnVsIG9wdGlvbmFsIGFyZ3VtZW50IGZvciB0aGUgYHRleHQoKWAgZnVuY3Rpb24gaXMgYGNleGAsIHdoaWNoIHNjYWxlcyB0aGUgZGVmYXVsdCB0ZXh0IHNpemUuIEFzIGEgc3BlY2lmaWMgZXhhbXBsZSwgc2V0dGluZyBgY2V4ID0gMS41YCBpbmNyZWFzZXMgdGhlIHRleHQgc2l6ZSBieSA1MCBwZXJjZW50LCByZWxhdGl2ZSB0byB0aGUgZGVmYXVsdCB2YWx1ZS4gU2ltaWxhcmx5LCBzcGVjaWZ5aW5nIGBjZXggPSAwLjhgIHJlZHVjZXMgdGhlIHRleHQgc2l6ZSBieSAyMCBwZXJjZW50LgoKRmluYWxseSwgdGhlIHRoaXJkIG9wdGlvbmFsIHBhcmFtZXRlciB1c2VkIGhlcmUgaXMgYGZvbnRgLCB3aGljaCBjYW4gYmUgdXNlZCB0byBzcGVjaWZ5IG9uZSBvZiBmb3VyIHRleHQgZm9udHM6IGBmb250ID0gMWAgaXMgdGhlIGRlZmF1bHQgdGV4dCBmb250IChuZWl0aGVyIGl0YWxpYyBub3IgYm9sZCksIGBmb250ID0gMmAgc3BlY2lmaWVzIGJvbGQgZmFjZSB0ZXh0LCBgZm9udCA9IDNgIHNwZWNpZmllcyBpdGFsaWMgdGV4dCwgYW5kIGBmb250ID0gNGAgc3BlY2lmaWVzIGJvdGggYm9sZCBhbmQgaXRhbGljIHRleHQuCgojIyMgSW5zdHJ1Y3Rpb25zCgotIENyZWF0ZSBhIHBsb3Qgb2YgYE1QRy5jaXR5YCB2cy4gYEhvcnNlcG93ZXJgIGZyb20gdGhlIGBDYXJzOTNgIGRhdGEgZnJhbWUsIHdpdGggZGF0YSByZXByZXNlbnRlZCBhcyBvcGVuIGNpcmNsZXMuCi0gQ29uc3RydWN0IHRoZSB2YXJpYWJsZSBgaW5kZXgzYCB1c2luZyB0aGUgYHdoaWNoKClgIGZ1bmN0aW9uIHRoYXQgaWRlbnRpZmllcyB0aGUgcm93IG51bWJlcnMgY29udGFpbmluZyBhbGwgMy1jeWxpbmRlciBjYXJzLgotIFVzZSB0aGUgYHBvaW50cygpYCBmdW5jdGlvbiB0byBvdmVybGF5IHNvbGlkIGNpcmNsZXMgb24gdG9wIG9mIGFsbCBwb2ludHMgaW4gdGhlIHBsb3QgdGhhdCByZXByZXNlbnQgMy1jeWxpbmRlciBjYXJzLgotIFVzZSB0aGUgYHRleHQoKWAgZnVuY3Rpb24gd2l0aCB0aGUgYE1ha2VgIHZhcmlhYmxlIGFzIGJlZm9yZSB0byBhZGQgbGFiZWxzIHRvIHRoZSByaWdodCBvZiB0aGUgMy1jeWxpbmRlciBjYXJzLCBidXQgbm93IHVzZSBgYWRqID0gLTAuMmAgdG8gbW92ZSB0aGUgbGFiZWxzIGZ1cnRoZXIgdG8gdGhlIHJpZ2h0LCB1c2UgdGhlIGBjZXhgIGFyZ3VtZW50IHRvIGluY3JlYXNlIHRoZSBsYWJlbCBzaXplIGJ5IDIwIHBlcmNlbnQsIGFuZCB1c2UgdGhlIGBmb250YCBhcmd1bWVudCB0byBtYWtlIHRoZSBsYWJlbHMgYm9sZCBpdGFsaWMuCgpgYGB7cn0KIyBQbG90IE1QRy5jaXR5IHZzLiBIb3JzZXBvd2VyIGFzIG9wZW4gY2lyY2xlcwoKCiMgQ3JlYXRlIGluZGV4MywgcG9pbnRpbmcgdG8gMy1jeWxpbmRlciBjYXJzCgoKIyBIaWdobGlnaHQgMy1jeWxpbmRlciBjYXJzIGFzIHNvbGlkIGNpcmNsZXMKCgojIEFkZCBjYXIgbmFtZXMsIG9mZnNldCBmcm9tIHBvaW50cywgd2l0aCBsYXJnZXIgYm9sZCB0ZXh0CgpgYGAKCgojIyBSb3RhdGluZyB0ZXh0IHdpdGggdGhlIHNydCBhcmd1bWVudAoKSW4gYWRkaXRpb24gdG8gdGhlIG9wdGlvbmFsIGFyZ3VtZW50cyB1c2VkIGluIHRoZSBwcmV2aW91cyBleGVyY2lzZXMsIHRoZSBgdGV4dCgpYCBmdW5jdGlvbiBhbHNvIHN1cHBvcnRzIGEgbnVtYmVyIG9mIG90aGVyIG9wdGlvbmFsIGFyZ3VtZW50cyB0aGF0IGNhbiBiZSB1c2VkIHRvIGVuaGFuY2UgdGhlIHRleHQuIFRoaXMgZXhlcmNpc2UgdXNlcyB0aGUgYGNleGAgYXJndW1lbnQgdG8gcmVkdWNlIHRoZSB0ZXh0IHNpemUgYW5kIGludHJvZHVjZXMgdHdvIG5ldyBhcmd1bWVudHMuIFRoZSBmaXJzdCBpcyB0aGUgYGNvbGAgYXJndW1lbnQgdGhhdCBzcGVjaWZpZXMgdGhlIGNvbG9yIHVzZWQgdG8gZGlzcGxheSB0aGUgdGV4dCwgYW5kIHRoZSBzZWNvbmQgaXMgdGhlIGBzcnRgIGFyZ3VtZW50IHRoYXQgYWxsb3dzIHVzIHRvIHJvdGF0ZSB0aGUgdGV4dC4KCkNvbG9yIGhhcyBiZWVuIHVzZWQgaW4gc2V2ZXJhbCBvZiB0aGUgcHJldmlvdXMgZXhlcmNpc2VzIHRvIHNwZWNpZnkgcG9pbnQgY29sb3JzLCBhbmQgdGhlIGVmZmVjdGl2ZSB1c2Ugb2YgY29sb3IgaXMgZGlzY3Vzc2VkIGZ1cnRoZXIgaW4gQ2hhcHRlciA1LiBPbmUgb2YgdGhlIHBvaW50cyBvZiB0aGlzIGV4ZXJjaXNlIGlzIHRvIHNob3cgdGhhdCB0aGUgc3BlY2lmaWNhdGlvbiBvZiB0ZXh0IGNvbG9yIHdpdGggdGhlIGB0ZXh0KClgIGZ1bmN0aW9uIGlzIGVzc2VudGlhbGx5IHRoZSBzYW1lIGFzIHRoZSBzcGVjaWZpY2F0aW9uIG9mIHBvaW50IGNvbG9yIHdpdGggdGhlIGBwbG90KClgIGZ1bmN0aW9uLiBBcyBhIHNwZWNpZmljIGV4YW1wbGUsIHNldHRpbmcgYGNvbCA9ICJncmVlbiJgIGluIHRoZSBgdGV4dCgpYCBmdW5jdGlvbiBjYXVzZXMgdGhlIHRleHQgdG8gYXBwZWFyIGluIGdyZWVuLiBJZiBgY29sYCBpcyBub3Qgc3BlY2lmaWVkLCB0aGUgdGV4dCBhcHBlYXJzIGluIHRoZSBkZWZhdWx0IGNvbG9yIHNldCBieSB0aGUgYHBhcigpYCBmdW5jdGlvbiwgd2hpY2ggaXMgdHlwaWNhbGx5IGJsYWNrLgoKVGhlIGBzcnRgIHBhcmFtZXRlciBhbGxvd3MgdXMgdG8gcm90YXRlIHRoZSB0ZXh0IHRocm91Z2ggYW4gYW5nbGUgc3BlY2lmaWVkIGluIGRlZ3JlZXMuIFRoZSB0eXBpY2FsIGRlZmF1bHQgdmFsdWUgKHNldCBieSB0aGUgYHBhcigpYCBmdW5jdGlvbikgaXMgYDBgLCBjYXVzaW5nIHRoZSB0ZXh0IHRvIGFwcGVhciBob3Jpem9udGFsbHksIHJlYWRpbmcgZnJvbSBsZWZ0IHRvIHJpZ2h0LiBTcGVjaWZ5aW5nIGBzcnQgPSA5MGAgY2F1c2VzIHRoZSB0ZXh0IHRvIGJlIHJvdGF0ZWQgYDkwYCBkZWdyZWVzIGNvdW50ZXItY2xvY2t3aXNlIHNvIHRoYXQgaXQgcmVhZHMgZnJvbSBib3R0b20gdG8gdG9wIGluc3RlYWQgb2YgbGVmdCB0byByaWdodC4KCiMjIyBJbnN0cnVjdGlvbnMKCi0gQ3JlYXRlIGEgc2NhdHRlcnBsb3Qgb2YgYEdhc2AgdnMuIGBUZW1wYCBmcm9tIHRoZSBgd2hpdGVzaWRlYCBkYXRhIGZyYW1lLCBhcyBzb2xpZCB0cmlhbmdsZXMuCi0gVXNlIHRoZSBgd2hpY2goKWAgZnVuY3Rpb24gdG8gY3JlYXRlIGEgdmVjdG9yIGBpbmRleEJgIHRoYXQgcG9pbnRzIHRvIGFsbCBkYXRhIG9ic2VydmF0aW9ucyB3aXRoIGBJbnN1bGAgaGF2aW5nIHRoZSB2YWx1ZSBgIkJlZm9yZSJgLgotIFVzZSB0aGUgYHdoaWNoKClgIGZ1bmN0aW9uIHRvIGNyZWF0ZSBhIHZlY3RvciBgaW5kZXhBYCB0aGF0IHBvaW50cyB0byBhbGwgZGF0YSBvYnNlcnZhdGlvbnMgd2l0aCBgSW5zdWxgIGhhdmluZyB0aGUgdmFsdWUgYCJBZnRlciJgLgotIFVzZSB0aGUgYHRleHQoKWAgZnVuY3Rpb24gdG8gb3ZlcmxheSB0aGUgdGV4dCBgIkJlZm9yZSJgIG9uIHRoZSBhcHByb3ByaWF0ZSBwb2ludHMsIGluIGJsdWUsIHJvdGF0ZWQgYDMwYCBkZWdyZWVzLCByZWR1Y2luZyB0aGUgdGV4dCBzaXplIHRvIGA4MGAgcGVyY2VudCBvZiB0aGUgZGVmYXVsdC4KLSBVc2UgdGhlIGB0ZXh0KClgIGZ1bmN0aW9uIHRvIG92ZXJsYXkgdGhlIHRleHQgYCJBZnRlciJgIG9uIHRoZSBhcHByb3ByaWF0ZSBwb2ludHMsIGluIHJlZCwgcm90YXRlZCBgLTIwYCBkZWdyZWVzLCByZWR1Y2luZyB0aGUgdGV4dCBzaXplIHRvIGA4MGAgcGVyY2VudCBvZiB0aGUgZGVmYXVsdC4KCmBgYHtyfQojIFBsb3QgR2FzIHZzLiBUZW1wIGFzIHNvbGlkIHRyaWFuZ2xlcwoKCiMgQ3JlYXRlIGluZGV4QiwgcG9pbnRpbmcgdG8gIkJlZm9yZSIgZGF0YQoKCiMgQ3JlYXRlIGluZGV4QSwgcG9pbnRpbmcgdG8gIkFmdGVyIiBkYXRhCgoKIyBBZGQgIkJlZm9yZSIgdGV4dCBpbiBibHVlLCByb3RhdGVkIDMwIGRlZ3JlZXMsIDgwJSBzaXplCnRleHQoeCA9IF9fXywgeSA9IF9fXywKICAgICBsYWJlbHMgPSBfX18sIGNvbCA9IF9fXywgc3J0ID0gX19fLCBjZXggPSBfX18pCgojIEFkZCAiQWZ0ZXIiIHRleHQgaW4gcmVkLCByb3RhdGVkIC0yMCBkZWdyZWVzLCA4MCUgc2l6ZQoKYGBgCgoKIyMgVXNpbmcgdGhlIGBsZWdlbmQoKWAgZnVuY3Rpb24KClRoZSB2aWRlbyBkZXNjcmliZWQgYW5kIGlsbHVzdHJhdGVkIHRoZSB1c2Ugb2YgdGhlIGBsZWdlbmQoKWAgZnVuY3Rpb24gdG8gYWRkIGV4cGxhbmF0b3J5IHRleHQgdG8gYSBwbG90LgoKVGhpcyBleGVyY2lzZSBhc2tzIHlvdSB0byBmaXJzdCBjcmVhdGUgYSBzY2F0dGVycGxvdCBhbmQgdGhlbiB1c2UgdGhpcyBmdW5jdGlvbiB0byBhZGQgZXhwbGFuYXRvcnkgdGV4dCBmb3IgdGhlIHBvaW50IHNoYXBlcyB0aGF0IGlkZW50aWZ5IHR3byBkaWZmZXJlbnQgZGF0YSBzdWJzZXRzLgoKIyMjIEluc3RydWN0aW9ucwoKLSBTZXQgdXAgYSBzY2F0dGVycGxvdCBvZiBgR2FzYCB2cy4gYFRlbXBgIGZyb20gdGhlIGB3aGl0ZXNpZGVgIGRhdGEgZnJhbWUgdXNpbmcgYHR5cGUgPSAibiJgIG9wdGlvbiBpbiB0aGUgYHBsb3QoKWAgY2FsbC4gTGFiZWwgdGhlIHgtYXhpcyBgIk91dHNpZGUgdGVtcGVyYXR1cmUiYCBieSBzcGVjaWZ5aW5nIHRoZSBgeGxhYmAgYXJndW1lbnQgYW5kIHRoZSB5LWF4aXMgYCJIZWF0aW5nIGdhcyBjb25zdW1wdGlvbiJgIGJ5IHNwZWNpZnlpbmcgdGhlIGB5bGFiYCBhcmd1bWVudC4KLSBVc2UgdGhlIGB3aGljaCgpYCBmdW5jdGlvbiB0byBjcmVhdGUgYSB2ZWN0b3IgYGluZGV4QmAgdGhhdCBwb2ludHMgdG8gYWxsIGRhdGEgb2JzZXJ2YXRpb25zIHdpdGggYEluc3VsYCBoYXZpbmcgdGhlIHZhbHVlIGAiQmVmb3JlImAuCi0gVXNlIHRoZSBgd2hpY2goKWAgZnVuY3Rpb24gdG8gY3JlYXRlIGEgdmVjdG9yIGBpbmRleEFgIHRoYXQgcG9pbnRzIHRvIGFsbCBkYXRhIG9ic2VydmF0aW9ucyB3aXRoIGBJbnN1bGAgaGF2aW5nIHRoZSB2YWx1ZSBgIkFmdGVyImAuCi0gVXNpbmcgdGhlIGBwb2ludHMoKWAgZnVuY3Rpb24sIGFkZCB0aGUgYCJCZWZvcmUiYCBwb2ludHMgdG8gdGhlIHBsb3QsIHJlcHJlc2VudGVkIGFzIHNvbGlkIHRyaWFuZ2xlcy4KLSBVc2luZyB0aGUgYHBvaW50cygpYCBmdW5jdGlvbiwgYWRkIHRoZSBgIkFmdGVyImAgcG9pbnRzIHRvIHRoZSBwbG90LCByZXByZXNlbnRlZCBhcyBvcGVuIGNpcmNsZXMuCi0gVXNpbmcgdGhlIGBsZWdlbmQoKWAgZnVuY3Rpb24sIGFkZCBhIGxlZ2VuZCBpbiB0aGUgdXBwZXIgcmlnaHQgY29ybmVyIG9mIHRoZSBwbG90IHdpdGggdGhlIG5hbWVzIGAiQmVmb3JlImAgYW5kIGAiQWZ0ZXIiYCBhbmQgdGhlIGFwcHJvcHJpYXRlIHBvaW50IHNoYXBlcyBpbmRpY2F0ZWQuCgpgYGB7cn0KIyBTZXQgdXAgYW5kIGxhYmVsIGVtcHR5IHBsb3Qgb2YgR2FzIHZzLiBUZW1wCnBsb3QoX19fLCBfX18sIHR5cGUgPSBfX18sIHhsYWIgPSBfX18sIHlsYWIgPSBfX18pCgojIENyZWF0ZSBpbmRleEIsIHBvaW50aW5nIHRvICJCZWZvcmUiIGRhdGEKaW5kZXhCIDwtIF9fXwoKIyBDcmVhdGUgaW5kZXhBLCBwb2ludGluZyB0byAiQWZ0ZXIiIGRhdGEKaW5kZXhBIDwtIF9fXwoKIyBBZGQgIkJlZm9yZSIgZGF0YSBhcyBzb2xpZCB0cmlhbmdsZXMKCgojIEFkZCAiQWZ0ZXIiIGRhdGEgYXMgb3BlbiBjaXJjbGVzCgoKIyBBZGQgbGVnZW5kIHRoYXQgaWRlbnRpZmllcyBwb2ludHMgYXMgIkJlZm9yZSIgYW5kICJBZnRlciIKbGVnZW5kKCJ0b3ByaWdodCIsIHBjaCA9IF9fXywgbGVnZW5kID0gYyhfX18sIF9fXykpCmBgYAoKCiMjIEFkZGluZyBjdXN0b20gYXhlcyB3aXRoIHRoZSBgYXhpcygpYCBmdW5jdGlvbgoKVHlwaWNhbCBiYXNlIGdyYXBoaWNzIGZ1bmN0aW9ucyBsaWtlIGBib3hwbG90KClgIHByb3ZpZGUgeC0gYW5kIHktYXhlcyBieSBkZWZhdWx0LCB3aXRoIGEgbGFiZWwgZm9yIHRoZSB4LWF4aXMgYmVsb3cgdGhlIHBsb3QgYW5kIG9uZSBmb3IgdGhlIHktYXhpcyBsYWJlbCB0byB0aGUgbGVmdCBvZiB0aGUgcGxvdC4gVGhlc2UgbGFiZWxzIGFyZSBnZW5lcmF0ZWQgYXV0b21hdGljYWxseSBmcm9tIHRoZSB2YXJpYWJsZSBuYW1lcyB1c2VkIHRvIGdlbmVyYXRlIHRoZSBwbG90LiBTb21ldGltZXMsIHdlIHdhbnQgdG8gcHJvdmlkZSBvdXIgb3duIGF4ZXMgbGFiZWxzLCBhbmQgUiBtYWtlcyB0aGlzIHBvc3NpYmxlIGluIHR3byBzdGVwczogZmlyc3QsIHdlIHN1cHByZXNzIHRoZSBkZWZhdWx0IGF4ZXMgd2hlbiB3ZSBjcmVhdGUgdGhlIHBsb3QgYnkgc3BlY2lmeWluZyBgYXhlcyA9IEZBTFNFYDsgdGhlbiwgd2UgY2FsbCB0aGUgbG93LWxldmVsIGdyYXBoaWNzIGZ1bmN0aW9uIGBheGlzKClgIHRvIGNyZWF0ZSB0aGUgYXhlcyB3ZSB3YW50LgoKSW4gdGhpcyBleGVyY2lzZSwgeW91J3JlIGFza2VkIHRvIGNyZWF0ZSB5b3VyIG93biBsYWJlbHMgdXNpbmcgdGhlIGBheGlzKClgIGZ1bmN0aW9uIHdpdGggdGhlIGBzaWRlYCwgYGF0YCwgYW5kIGBsYWJlbHNgIGFyZ3VtZW50cy4gVGhlIGBzaWRlYCBhcmd1bWVudCB0ZWxscyB0aGUgZnVuY3Rpb24gd2hpY2ggYXhpcyB0byBjcmVhdGU6IGEgdmFsdWUgb2YgMSBhZGRzIGFuIGF4aXMgYmVsb3cgdGhlIHBsb3Q7IDIgYWRkcyBhbiBheGlzIG9uIHRoZSBsZWZ0OyAzIHB1dHMgaXQgYWNyb3NzIHRoZSB0b3A7IGFuZCA0IHB1dHMgaXQgb24gdGhlIHJpZ2h0IHNpZGUuIFRoZSBzZWNvbmQgYXJndW1lbnQsIGBhdGAsIGlzIGEgdmVjdG9yIHRoYXQgZGVmaW5lcyBwb2ludHMgd2hlcmUgdGljay1tYXJrcyB3aWxsIGJlIGRyYXduIG9uIHRoZSBheGlzLiBUaGUgdGhpcmQgYXJndW1lbnQsIGBsYWJlbHNgLCBpcyBhIHZlY3RvciB0aGF0IGRlZmluZXMgbGFiZWxzIGF0IGVhY2ggb2YgdGhlc2UgdGljay1tYXJrcy4KCk9uZSBleGFtcGxlIG9mIGEgYm94cGxvdCB3aXRoIGN1c3RvbSBheGVzIHdhcyBwcmVzZW50ZWQgaW4gdGhlIHZpZGVvLiBUaGlzIGV4ZXJjaXNlIGFza3MgeW91IHRvIGNyZWF0ZSBhbm90aGVyIGV4YW1wbGUgc2hvd2luZyB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIGBzdWdhcnNgIHZhcmlhYmxlIGFuZCB0aGUgYHNoZWxmYCB2YXJpYWJsZSBmcm9tIHRoZSBgVVNjZXJlYWxgIGRhdGEgZnJhbWUgaW4gdGhlIGBNQVNTYCBwYWNrYWdlLgoKIyMjIEluc3RydWN0aW9ucwoKLSBVc2UgdGhlIGBib3hwbG90KClgIGZ1bmN0aW9uIHRvIGNyZWF0ZSBhIGJveHBsb3Qgb2YgYHN1Z2Fyc2AgdnMuIGBzaGVsZmAgZnJvbSB0aGUgYFVTY2VyZWFsYCBkYXRhIGZyYW1lIGluIHRoZSBgTUFTU2AgcGFja2FnZSwgd2l0aCBheGVzIHN1cHByZXNzZWQuCi0gVXNlIHRoZSBgYXhpcygpYCBmdW5jdGlvbiB3aXRoIHRoZSBgc2lkZWAgcGFyYW1ldGVyIHNwZWNpZmllZCB0byBhZGQgYSB5LWF4aXMgbGFiZWwgdG8gdGhlIGxlZnQgb2YgdGhlIGJveCBwbG90IHNob3dpbmcgdGhlIHJhbmdlIG9mIGBzdWdhcnNgIHZhbHVlcy4KLSBJbiB5b3VyIHNlY29uZCBjYWxsIHRvIGBheGlzKClgLCBhZGQgYW4geC1heGlzIGxhYmVsIG9uIHRoZSBib3R0b20gc2lkZSBhbmQgc3BlY2lmeSB0aGUgYGF0YCBwYXJhbWV0ZXIgdG8gYWRkIHRpY2stbWFya3MgYXQgdGhlIG51bWVyaWNhbCBzaGVsZiB2YWx1ZXMgbGFiZWxsZWQgMSwgMiwgYW5kIDMuCi0gSW4geW91ciB0aGlyZCBjYWxsIHRvIGBheGlzKClgLCBhZGQgYW5vdGhlciB4LWF4aXMgbGFiZWwgYXQgdGhlIHRvcCBhbmQgc3BlY2lmeSB0aGUgYGxhYmVsc2AgcGFyYW1ldGVyIHRvIHNob3cgdGhlIHBoeXNpY2FsIGBzaGVsZmAgbG9jYXRpb25zIChgImZsb29yImAsIGAibWlkZGxlImAsIGAidG9wImApLgoKYGBge3J9CiMgQ3JlYXRlIGEgYm94cGxvdCBvZiBzdWdhcnMgYnkgc2hlbGYgdmFsdWUsIHdpdGhvdXQgYXhlcwoKCiMgQWRkIGEgZGVmYXVsdCB5LWF4aXMgdG8gdGhlIGxlZnQgb2YgdGhlIGJveHBsb3QKYXhpcyhzaWRlID0gX19fKQoKIyBBZGQgYW4geC1heGlzIGJlbG93IHRoZSBwbG90LCBsYWJlbGxlZCAxLCAyLCBhbmQgMwpheGlzKHNpZGUgPSBfX18sIGF0ID0gX19fKQoKIyBBZGQgYSBzZWNvbmQgeC1heGlzIGFib3ZlIHRoZSBwbG90CmF4aXMoc2lkZSA9IF9fXywgYXQgPSBfX18sIGxhYmVscyA9IF9fXykKYGBgCgoKIyMgVXNpbmcgdGhlIGBzdXBzbXUoKWAgZnVuY3Rpb24gdG8gYWRkIHNtb290aCB0cmVuZCBjdXJ2ZXMKClNvbWUgc2NhdHRlcnBsb3RzIGV4aGliaXQgZmFpcmx5IG9idmlvdXMgdHJlbmRzIHRoYXQgYXJlIG5vdCBsaW5lYXIuIEluIHN1Y2ggY2FzZXMsIHdlIG1heSB3YW50IHRvIGFkZCBhIGN1cnZlZCB0cmVuZCBsaW5lIHRoYXQgaGlnaGxpZ2h0cyB0aGlzIGJlaGF2aW9yIG9mIHRoZSBkYXRhIGFuZCB0aGUgYHN1cHNtdSgpYCBmdW5jdGlvbiByZXByZXNlbnRzIG9uZSB3YXkgb2YgZG9pbmcgdGhpcy4KClRvIHVzZSB0aGlzIGZ1bmN0aW9uLCB3ZSBuZWVkIHRvIHNwZWNpZnkgdmFsdWVzIGZvciB0aGUgcmVxdWlyZWQgYXJndW1lbnRzIGB4YCBhbmQgYHlgLCBidXQgaXQgYWxzbyBoYXMgYSBudW1iZXIgb2Ygb3B0aW9uYWwgYXJndW1lbnRzLiBIZXJlLCB3ZSBjb25zaWRlciB0aGUgb3B0aW9uYWwgYGJhc3NgIGFyZ3VtZW50LCB3aGljaCBjb250cm9scyB0aGUgZGVncmVlIG9mIHNtb290aG5lc3MgaW4gdGhlIHJlc3VsdGluZyB0cmVuZCBjdXJ2ZS4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgMCwgYnV0IHNwZWNpZnlpbmcgbGFyZ2VyIHZhbHVlcyAodXAgdG8gYSBtYXhpbXVtIG9mIDEwKSByZXN1bHRzIGluIGEgc21vb3RoZXIgY3VydmUuIFRoaXMgZXhlcmNpc2UgYXNrcyB5b3UgdG8gdXNlIHRoZSBgc3Vwc211KClgIGZ1bmN0aW9uIHRvIGFkZCB0d28gdHJlbmQgbGluZXMgdG8gYSBzY2F0dGVycGxvdCwgb25lIHVzaW5nIHRoZSBkZWZhdWx0IHBhcmFtZXRlcnMgYW5kIHRoZSBvdGhlciB3aXRoIGluY3JlYXNlZCBzbW9vdGhuZXNzLgoKIyMjIEluc3RydWN0aW9ucwoKLSBDcmVhdGUgYSBzY2F0dGVycGxvdCBvZiBgTVBHLmNpdHlgIHZzLiBgSG9yc2Vwb3dlcmAgZnJvbSB0aGUgYENhcnM5M2AgZGF0YSBmcmFtZS4KLSBDcmVhdGUgYSBgc3Vwc211KClgIG9iamVjdCBuYW1lZCBgdHJlbmQxYCB3aXRoIHRoZSBgYmFzc2AgcGFyYW1ldGVyIGF0IGl0cyBtaW5pbXVtIChkZWZhdWx0KSB2YWx1ZSwgMS4KLSBVc2UgdGhlIGBsaW5lcygpYCBmdW5jdGlvbiB0byBhZGQgdGhlIGB0cmVuZDFgIGN1cnZlIHRvIHRoZSBwbG90IGFzIGEgc29saWQgbGluZS4gVGhlcmUgaXMgbm8gbmVlZCB0byBwcm92aWRlIGFkZGl0aW9uYWwgYXJndW1lbnRzLgotIENyZWF0ZSBhIGBzdXBzbXUoKWAgb2JqZWN0IG5hbWVkIGB0cmVuZDJgIHdpdGggdGhlIGBiYXNzYCBwYXJhbWV0ZXIgYXQgaXRzIG1heGltdW0gdmFsdWUsIDEwLgotIFVzZSB0aGUgYGxpbmVzKClgIGZ1bmN0aW9uIHRvIGFkZCB0aGUgYHRyZW5kMmAgY3VydmUgdG8gdGhlIHBsb3QgYXMgYSBkb3R0ZWQgbGluZSBvZiB0d2ljZSBzdGFuZGFyZCB3aWR0aC4KCmBgYHtyfQojIENyZWF0ZSBhIHNjYXR0ZXJwbG90IG9mIE1QRy5jaXR5IHZzLiBIb3JzZXBvd2VyCgoKIyBDYWxsIHN1cHNtdSgpIHRvIGdlbmVyYXRlIGEgc21vb3RoIHRyZW5kIGN1cnZlLCB3aXRoIGRlZmF1bHQgYmFzcwoKCiMgQWRkIHRoaXMgdHJlbmQgY3VydmUgdG8gdGhlIHBsb3QKCgojIENhbGwgc3Vwc211KCkgZm9yIGEgc2Vjb25kIHRyZW5kIGN1cnZlLCB3aXRoIGJhc3MgPSAxMAoKCiMgQWRkIHRoaXMgdHJlbmQgY3VydmUgYXMgYSBoZWF2eSwgZG90dGVkIGxpbmUKCmBgYAoKCgojIEhvdyBNdWNoIGlzIFRvbyBNdWNoPwoKIyMgVG9vIG11Y2ggaXMgdG9vIG11Y2gKClRoZSBmaXJzdCBleGFtcGxlIHByZXNlbnRlZCBpbiBDaGFwdGVyIDEgYXBwbGllZCB0aGUgYHBsb3QoKWAgZnVuY3Rpb24gdG8gYSBkYXRhIGZyYW1lLCB5aWVsZGluZyBhbiBhcnJheSBvZiBzY2F0dGVycGxvdHMgd2l0aCBvbmUgZm9yIGVhY2ggcGFpciBvZiBjb2x1bW5zIGluIHRoZSBkYXRhIGZyYW1lLiBUaHVzLCB0aGUgbnVtYmVyIG9mIHBsb3RzIGluIHRoaXMgYXJyYXkgaXMgZXF1YWwgdG8gdGhlIHNxdWFyZSBvZiB0aGUgbnVtYmVyIG9mIGNvbHVtbnMgaW4gdGhlIGRhdGEgZnJhbWUuCgpUaGlzIG1lYW5zIHRoYXQgaWYgd2UgYXBwbHkgdGhlIGBwbG90KClgIGZ1bmN0aW9uIHRvIGEgZGF0YSBmcmFtZSB3aXRoIG1hbnkgY29sdW1ucywgd2Ugd2lsbCBnZW5lcmF0ZSBhbiBlbm9ybW91cyBhcnJheSBvZiBzY2F0dGVycGxvdHMsIGVhY2ggb2Ygd2hpY2ggd2lsbCBiZSB0b28gc21hbGwgdG8gYmUgdXNlZnVsLiBUaGUgcHVycG9zZSBvZiB0aGlzIGV4ZXJjaXNlIGlzIHRvIHByb3ZpZGUgYSBtZW1vcmFibGUgZXhhbXBsZS4KCiMjIyBJbnN0cnVjdGlvbnMKCkFwcGx5aW5nIHRoZSBgcGxvdCgpYCBmdW5jdGlvbiB0byBhIGRhdGEgZnJhbWUgd2l0aCBga2AgY29sdW1ucyB3aWxsIGNyZWF0ZSBhIGBrYCBieSBga2AgYXJyYXkgb2Ygc2NhdHRlcnBsb3RzLgoKLSBVc2UgdGhlIGBuY29sKClgIGZ1bmN0aW9uIHRvIGNvbXB1dGUgdGhlIG51bWJlciBvZiBwbG90cyBpbiB0aGlzIGFycmF5IGZvciB0aGUgYENhcnM5M2AgZGF0YSBmcmFtZS4gSnVzdCBwcmludCB0aGUgcmVzdWx0IHRvIHRoZSBjb25zb2xlLgotIENhbGwgYHBsb3QoKWAgb24gYENhcnM5M2AgdG8gZ2VuZXJhdGUgdGhlIHNjYXR0ZXJwbG90IGFycmF5LiBDYW4geW91IHZlcmlmeSB0aGF0IHlvdXIgY2FsY3VsYXRpb24gd2FzIGNvcnJlY3Q/CgpgYGB7cn0KIyBDb21wdXRlIHRoZSBudW1iZXIgb2YgcGxvdHMgdG8gYmUgZGlzcGxheWVkCm5jb2woX19fKV5fX18KCiMgUGxvdCB0aGUgYXJyYXkgb2Ygc2NhdHRlcnBsb3RzCgpgYGAKCgojIyBEZWNpZGluZyBob3cgbWFueSBzY2F0dGVycGxvdHMgaXMgdG9vIG1hbnkKClRoZSBgbWF0cGxvdCgpYCBmdW5jdGlvbiBjYW4gYmUgdXNlZCB0byBlYXNpbHkgZ2VuZXJhdGUgYSBwbG90IHdpdGggc2V2ZXJhbCBzY2F0dGVycGxvdHMgb24gdGhlIHNhbWUgc2V0IG9mIGF4ZXMuIEJ5IGRlZmF1bHQsIHRoZSBwb2ludHMgaW4gdGhlc2Ugc2NhdHRlcnBsb3RzIGFyZSByZXByZXNlbnRlZCBieSB0aGUgbnVtYmVycyAxIHRocm91Z2ggbiwgd2hlcmUgbiBpcyB0aGUgdG90YWwgbnVtYmVyIG9mIHNjYXR0ZXJwbG90cyBpbmNsdWRlZCwgYnV0IG1vc3Qgb2YgdGhlIG9wdGlvbnMgYXZhaWxhYmxlIHdpdGggdGhlIGBwbG90KClgIGZ1bmN0aW9uIGFyZSBhbHNvIHBvc3NpYmxlIGJ5IHNwZWNpZnlpbmcgdGhlIGFwcHJvcHJpYXRlIGFyZ3VtZW50cy4KClRoaXMgZXhlcmNpc2UgYXNrcyB5b3UgdG8gc2V0IHVwIGEgcGxvdCBhcnJheSB3aXRoIGZvdXIgb2YgdGhlc2UgbXVsdGlwbGUgc2NhdHRlcnBsb3QgZGlzcGxheXMsIGVhY2ggaW5jbHVkaW5nIG9uZSBtb3JlIHNjYXR0ZXJwbG90IHRoYW4gdGhlIHByZXZpb3VzIG9uZS4gVGhlIHBvaW50IG9mIHRoaXMgZXhlcmNpc2UgaXMgdG8gZW5jb3VyYWdlIHlvdSB0byBqdWRnZSBmb3IgeW91cnNlbGYgaG93IG1hbnkgc2NhdHRlcnBsb3RzIGlzIHRvbyBtYW55Py4KCiMjIyBJbnN0cnVjdGlvbnMKCi0gUnVuIHRoZSBmaXJzdCBsaW5lIG9mIHNhbXBsZSBjb2RlIHByb3ZpZGVkIHRvIGNvbnN0cnVjdCBhIGNoYXJhY3RlciB2ZWN0b3IgY2FsbGVkIGBrZWVwX3ZhcnNgIHRoYXQgbmFtZXMgc2l4IHZhcmlhYmxlcyBmcm9tIHRoZSBgVVNjZXJlYWxgIGRhdGEgZnJhbWUuCi0gVXNpbmcgdGhpcyB2ZWN0b3Igb2YgdmFyaWFibGUgbmFtZXMsIGV4dHJhY3QgdGhlIGRhdGEgZnJhbWUgYGRmYCBjb250YWluaW5nIG9ubHkgdGhlc2UgdmFyaWFibGVzIGZyb20gdGhlIGBVU2NlcmVhbGAgZGF0YSBmcmFtZS4KLSBVc2UgdGhlIGBwYXIoKWAgZnVuY3Rpb24gdG8gc2V0IHVwIHRoZSBgbWZyb3dgIHBhcmFtZXRlciB0byBnZW5lcmF0ZSBhIHR3by1ieS10d28gcGxvdCBhcnJheS4KLSBVc2UgdGhlIGBtYXRwbG90KClgIGZ1bmN0aW9uIHRvIGNvbnN0cnVjdCBhIHR3by1zY2F0dGVycGxvdCBkaXNwbGF5IG9mIAogICAtIGBwcm90ZWluYCBhbmQgYGZhdGAgdmVyc3VzIGBjYWxvcmllc2AuIEdpdmUgdGhpcyBwbG90IHRoZSB0aXRsZSBgIlR3byBzY2F0dGVycGxvdHMiYCB1c2luZyB0aGUgYHRpdGxlKClgIGZ1bmN0aW9uLiBMYWJlbCB0aGUgeC1heGlzIGAiY2Fsb3JpZXMiYCBhbmQgdGhlIHktYXhpcyBgIiJgIHRvIGdldCByaWQgb2YgdGhlIGRlZmF1bHQgeS1heGlzIGxhYmVsLgogICAtIGBwcm90ZWluYCwgYGZhdGAgYW5kIGBmaWJyZWAgdmVyc3VzIGBjYWxvcmllc2AuIEdpdmUgdGhpcyBwbG90IHRoZSB0aXRsZSBgIlRocmVlIHNjYXR0ZXJwbG90cyJgLiBTaW1pbGFybHksIGxhYmVsIHRoZSB4LWF4aXMgYCJjYWxvcmllcyJgIGFuZCB0aGUgeS1heGlzIGAiImAuCiAgIC0gYHByb3RlaW5gLCBgZmF0YCwgYGZpYnJlYCBhbmQgYGNhcmJvYCB2ZXJzdXMgYGNhbG9yaWVzYC4gR2l2ZSB0aGlzIHBsb3QgdGhlIHRpdGxlIGAiRm91ciBzY2F0dGVycGxvdHMiYC4gQWdhaW4sIGxhYmVsIHRoZSB4LWF4aXMgYCJjYWxvcmllcyJgIGFuZCB0aGUgeS1heGlzIGAiImAuCiAgIC0gYHByb3RlaW5gLCBgZmF0YCwgYGZpYnJlYCwgYGNhcmJvYCwgYW5kIGBzdWdhcnNgIHZlcnN1cyBgY2Fsb3JpZXNgLiBHaXZlIHRoaXMgcGxvdCB0aGUgdGl0bGUgYCJGaXZlIHNjYXR0ZXJwbG90cyJgLiBCZSBzdXJlIHRvIGxhYmVsIHRoZSB4LWF4aXMgYCJjYWxvcmllcyJgIGFuZCB0aGUgeS1heGlzIGAiImAgYWdhaW4uCgpgYGB7cn0KIyBDb25zdHJ1Y3QgdGhlIHZlY3RvciBrZWVwX3ZhcnMKa2VlcF92YXJzIDwtIGMoImNhbG9yaWVzIiwgInByb3RlaW4iLCAiZmF0IiwKICAgICAgICAgICAgICAgImZpYnJlIiwgImNhcmJvIiwgInN1Z2FycyIpCgojIFVzZSBrZWVwX3ZhcnMgdG8gZXh0cmFjdCB0aGUgZGVzaXJlZCBzdWJzZXQgb2YgVVNjZXJlYWwKZGYgPC0gX19fWywgX19fXQoKIyBTZXQgdXAgYSB0d28tYnktdHdvIHBsb3QgYXJyYXkKCgojIFVzZSBtYXRwbG90KCkgdG8gZ2VuZXJhdGUgYW4gYXJyYXkgb2YgdHdvIHNjYXR0ZXJwbG90cwoKCiMgQWRkIGEgdGl0bGUKCgojIFVzZSBtYXRwbG90KCkgdG8gZ2VuZXJhdGUgYW4gYXJyYXkgb2YgdGhyZWUgc2NhdHRlcnBsb3RzCgoKIyBBZGQgYSB0aXRsZQoKCiMgVXNlIG1hdHBsb3QoKSB0byBnZW5lcmF0ZSBhbiBhcnJheSBvZiBmb3VyIHNjYXR0ZXJwbG90cwoKCiMgQWRkIGEgdGl0bGUKCgojIFVzZSBtYXRwbG90KCkgdG8gZ2VuZXJhdGUgYW4gYXJyYXkgb2YgZml2ZSBzY2F0dGVycGxvdHMKCgojIEFkZCBhIHRpdGxlCgpgYGAKCgojIyBIb3cgbWFueSB3b3JkcyBpcyB0b28gbWFueT8KClRoZSBtYWluIHBvaW50IG9mIHRoZSBwcmV2aW91cyB0d28gZXhlcmNpc2VzIGhhcyBiZWVuIHRvIHNob3cgdGhhdCBzY2F0dGVycGxvdCBhcnJheXMgbG9zZSB0aGVpciB1dGlsaXR5IGlmIHRoZXkgYXJlIGFsbG93ZWQgdG8gYmVjb21lIHRvbyBjb21wbGV4LCBlaXRoZXIgaW5jbHVkaW5nIHRvbyBtYW55IHBsb3RzLCBvciBhdHRlbXB0aW5nIHRvIGluY2x1ZGUgdG9vIG1hbnkgc2NhdHRlcnBsb3RzIG9uIG9uZSBzZXQgb2YgYXhlcy4gTW9yZSBnZW5lcmFsbHksICphbnkqIGRhdGEgdmlzdWFsaXphdGlvbiBsb3NlcyBpdHMgdXRpbGl0eSBpZiBpdCBiZWNvbWVzIHRvbyBjb21wbGV4LgoKVGhpcyBleGVyY2lzZSBhc2tzIHlvdSB0byBjb25zaWRlciB0aGlzIHByb2JsZW0gd2l0aCAqd29yZGNsb3VkcyosIGRpc3BsYXlzIHRoYXQgcHJlc2VudCB3b3JkcyBpbiB2YXJ5aW5nIHNpemVzIGRlcGVuZGluZyBvbiB0aGVpciBmcmVxdWVuY3kuIFRoYXQgaXMsIG1vcmUgZnJlcXVlbnQgd29yZHMgYXBwZWFyIGxhcmdlciBpbiB0aGUgZGlzcGxheSwgd2hpbGUgcmFyZXIgd29yZHMgYXBwZWFyIGluIGEgc21hbGxlciBmb250LgoKSW4gUiwgd29yZGNsb3VkcyBhcmUgZWFzeSB0byBnZW5lcmF0ZSB3aXRoIHRoZSBgd29yZGNsb3VkKClgIGZ1bmN0aW9uIGluIHRoZSBgd29yZGNsb3VkYCBwYWNrYWdlLiBUaGlzIGZ1bmN0aW9uIGlzIGNhbGxlZCB3aXRoIGEgY2hhcmFjdGVyIHZlY3RvciBvZiB3b3JkcywgYW5kIGEgc2Vjb25kIG51bWVyaWNhbCB2ZWN0b3IgZ2l2aW5nIHRoZSBudW1iZXIgb2YgdGltZXMgZWFjaCB3b3JkIGFwcGVhcnMgaW4gdGhlIGNvbGxlY3Rpb24gdXNlZCB0byBnZW5lcmF0ZSB0aGUgd29yZGNsb3VkLgoKVHdvIG90aGVyIHVzZWZ1bCBhcmd1bWVudHMgZm9yIHRoaXMgZnVuY3Rpb24gYXJlIGBzY2FsZWAgYW5kIGBtaW4uZnJlcWAuIFRoZSBgc2NhbGVgIGFyZ3VtZW50IGlzIGEgdHdvLWNvbXBvbmVudCBudW1lcmljYWwgdmVjdG9yIGdpdmluZyB0aGUgcmVsYXRpdmUgc2l6ZSBvZiB0aGUgbGFyZ2VzdCB3b3JkIGluIHRoZSBkaXNwbGF5IGFuZCB0aGF0IG9mIHRoZSBzbWFsbGVzdCB3b3JkLiBUaGUgd29yZGNsb3VkIG9ubHkgaW5jbHVkZXMgdGhvc2Ugd29yZHMgdGhhdCBvY2N1ciBhdCBsZWFzdCBgbWluLmZyZXFgIHRpbWVzIGluIHRoZSBjb2xsZWN0aW9uIGFuZCB0aGUgZGVmYXVsdCB2YWx1ZSBmb3IgdGhpcyBhcmd1bWVudCBpcyAzLgoKIyMjIEluc3RydWN0aW9ucwoKTG9hZCB0aGUgYHdvcmRjbG91ZGAgcGFja2FnZSBpbiB5b3VyIHdvcmtzcGFjZS4KCi0gVXNlIHRoZSBgdGFibGUoKWAgZnVuY3Rpb24gdG8gY3JlYXRlIHRoZSB2YXJpYWJsZSBgbWZyX3RhYmxlYCB0aGF0IHRhYnVsYXRlcyB0aGUgbnVtYmVyIG9mIHRpbWVzIGVhY2ggbGV2ZWwgb2YgdGhlIGBNYW51ZmFjdHVyZXJgIHZhcmlhYmxlIGFwcGVhcnMgaW4gdGhlIGBDYXJzOTNgIGRhdGEgZnJhbWUuCi0gVXNlIHRoZSBgd29yZGNsb3VkKClgIGZ1bmN0aW9uIHRvIGRpc3BsYXkgdGhpcyBtYW51ZmFjdHVyZXIgZGF0YSwgc2V0dGluZyB0aGUgYHNjYWxlYCBhcmd1bWVudCB0byBgYygyLCAwLjI1KWAgdG8gbWFrZSB0aGUgd29yZGNsb3VkIGZpdCBpbiB0aGUgZGlzcGxheSB3aW5kb3cuCi0gQnkgZGVmYXVsdCwgdGhlIGB3b3JkY2xvdWQoKWAgZnVuY3Rpb24gc2hvd3Mgb25seSB0aG9zZSB3b3JkcyB0aGF0IGFwcGVhciAzIG9yIG1vcmUgdGltZXMuIFVzZSB0aGUgYG1pbi5mcmVxYCBhcmd1bWVudCB0byBvYnRhaW4gYSBkaXNwbGF5IHdpdGggYWxsIGBNYW51ZmFjdHVyZXJgIHZhbHVlcyBpbiB0aGUgd29yZGNsb3VkLgotIFVzZSB0aGUgYHRhYmxlKClgIGZ1bmN0aW9uIHRvIGNyZWF0ZSB0aGUgdmFyaWFibGUgYG1vZGVsX3RhYmxlYCB0aGF0IHRhYnVsYXRlcyB0aGUgbnVtYmVyIG9mIHRpbWVzIGVhY2ggbGV2ZWwgb2YgdGhlIGBNb2RlbGAgdmFyaWFibGUgYXBwZWFycyBpbiB0aGUgYENhcnM5M2AgZGF0YSBmcmFtZS4KLSBVc2UgdGhlIGB3b3JkY2xvdWQoKWAgZnVuY3Rpb24gd2l0aCB0aGUgYHNjYWxlYCBhcmd1bWVudCBzZXQgdG8gYGMoMC43NSwgMC4yNSlgIGFuZCB0aGUgYG1pbi5mcmVxYCBhcmd1bWVudCBzZXQgdG8gZGlzcGxheSBhbGwgYE1vZGVsYCB2YWx1ZXMuIFVzZSB0aGUgem9vbSBmZWF0dXJlIGluIHRoZSAnUGxvdHMnIHdpbmRvdyB0byBzZWUgdGhpcyB3b3JkY2xvdWQgbW9yZSBjbGVhcmx5LiBEb2VzIGl0IGNvbnZleSB1c2VmdWwgaW5mb3JtYXRpb24/CgpgYGB7cn0KIyBDcmVhdGUgbWZyX3RhYmxlIG9mIG1hbnVmYWN0dXJlciBmcmVxdWVuY2llcwptZnJfdGFibGUgPC0gX19fCgojIENyZWF0ZSB0aGUgZGVmYXVsdCB3b3JkY2xvdWQgZnJvbSB0aGlzIHRhYmxlCndvcmRjbG91ZCh3b3JkcyA9IG5hbWVzKF9fXyksIAogICAgICAgICAgZnJlcSA9IGFzLm51bWVyaWMoX19fKSwgCiAgICAgICAgICBzY2FsZSA9IF9fXykKCiMgQ2hhbmdlIHRoZSBtaW5pbXVtIHdvcmQgZnJlcXVlbmN5CndvcmRjbG91ZCh3b3JkcyA9IG5hbWVzKF9fXyksIAogICAgICAgICAgZnJlcSA9IGFzLm51bWVyaWMoX19fKSwgCiAgICAgICAgICBzY2FsZSA9IF9fXywgCiAgICAgICAgICBtaW4uZnJlcSA9IF9fXykKCiMgQ3JlYXRlIG1vZGVsX3RhYmxlIG9mIG1vZGVsIGZyZXF1ZW5jaWVzCm1vZGVsX3RhYmxlIDwtIF9fXwoKIyBDcmVhdGUgdGhlIHdvcmRjbG91ZCBvZiBhbGwgbW9kZWwgbmFtZXMgd2l0aCBzbWFsbGVyIHNjYWxpbmcKd29yZGNsb3VkKHdvcmRzID0gbmFtZXMoX19fKSwgCiAgICAgICAgICBmcmVxID0gYXMubnVtZXJpYyhfX18pLCAKICAgICAgICAgIHNjYWxlID0gX19fLCAKICAgICAgICAgIG1pbi5mcmVxID0gX19fKQpgYGAKIAoKIyMgVGhlIEFuc2NvbWJlIHF1YXJ0ZXQKClRoaXMgZXhlcmNpc2UgYW5kIHRoZSBuZXh0IG9uZSBhcmUgYmFzZWQgb24gdGhlIEFuc2NvbWJlIHF1YXJ0ZXQsIGEgY29sbGVjdGlvbiBvZiBmb3VyIGRhdGFzZXRzIHRoYXQgYXBwZWFyIHRvIGJlIGVzc2VudGlhbGx5IGlkZW50aWNhbCBvbiB0aGUgYmFzaXMgb2Ygc2ltcGxlIHN1bW1hcnkgc3RhdGlzdGljcyBsaWtlIG1lYW5zIGFuZCBzdGFuZGFyZCBkZXZpYXRpb25zLiBGb3IgZXhhbXBsZSwgdGhlIG1lYW4geC12YWx1ZXMgZm9yIHRoZXNlIGRhdGFzZXRzIGFyZSBpZGVudGljYWwgdG8gdGhyZWUgZGlnaXRzLCB3aGlsZSB0aGUgbWVhbiB5LXZhbHVlcyBkaWZmZXIgb25seSBpbiB0aGUgdGhpcmQgZGlnaXQuCgpJbiBzcGl0ZSBvZiB0aGVzZSBhcHBhcmVudCBzaW1pbGFyaXRpZXMsIHRoZSBiZWhhdmlvciBvZiB0aGUgZm91ciBkYXRhc2V0cyBpcyBxdWl0ZSBkaWZmZXJlbnQgYW5kIHRoaXMgYmVjb21lcyBpbW1lZGlhdGVseSBhcHBhcmVudCB3aGVuIHdlIHBsb3QgdGhlbS4KCiMjIyBJbnN0cnVjdGlvbnMKCi0gVXNlIHRoZSBgcGFyKClgIGZ1bmN0aW9uIHRvIHNldCB1cCBhIHR3by1ieS10d28gcGxvdCBhcnJheS4KLSBVc2luZyBgcGxvdCgpYCwgY3JlYXRlIDQgc2VwYXJhdGUgcGxvdHMgZnJvbSB0aGUgYGFuc2NvbWJlYCBkYXRhIGZyYW1lOgogICAtIGB5MWAgdnMuIGB4MWAKICAgLSBgeTJgIHZzLiBgeDJgCiAgIC0gYHkzYCB2cy4gYHgzYAogICAtIGB5NGAgdnMuIGB4NGAKCmBgYHtyfQojIFNldCB1cCBhIHR3by1ieS10d28gcGxvdCBhcnJheQoKCiMgUGxvdCB5MSB2cy4geDEgCnBsb3QoYW5zY29tYmUkX19fLCBhbnNjb21iZSRfX18pCgojIFBsb3QgeTIgdnMuIHgyCgoKIyBQbG90IHkzIHZzLiB4MwoKCiMgUGxvdCB5NCB2cy4geDQKCmBgYAoKCiMjIFRoZSB1dGlsaXR5IG9mIGNvbW1vbiBzY2FsaW5nIGFuZCBpbmRpdmlkdWFsIHRpdGxlcwoKVGhlIHBsb3RzIHlvdSBnZW5lcmF0ZWQgaW4gdGhlIHByZXZpb3VzIGV4ZXJjaXNlIHNob3dlZCB0aGF0IHRoZSBmb3VyIEFuc2NvbWJlIHF1YXJ0ZXQgZGF0YXNldHMgaGF2ZSB2ZXJ5IGRpZmZlcmVudCBhcHBlYXJhbmNlcywgYnV0IGEgY2FyZWZ1bCBleGFtaW5hdGlvbiBvZiB0aGVzZSBwbG90cyByZXZlYWxzIHRoYXQgdGhleSBleGhpYml0IGRpZmZlcmVudCByYW5nZXMgb2YgeCBhbmQgeSB2YWx1ZXMuCgpUaGUgcG9pbnQgb2YgdGhpcyBleGVyY2lzZSBpcyB0byBpbGx1c3RyYXRlIGhvdyBtdWNoIG1vcmUgY2xlYXJseSB3ZSBjYW4gc2VlIHRoZSBkaWZmZXJlbmNlcyBpbiB0aGVzZSBkYXRhc2V0cyBpZiB3ZSBwbG90IGFsbCBvZiB0aGVtIHdpdGggdGhlIHNhbWUgeCBhbmQgeSByYW5nZXMuIFRoaXMgZXhlcmNpc2UgYWxzbyBpbGx1c3RyYXRlcyB0aGUgdXRpbGl0eSBvZiBpbXByb3ZpbmcgdGhlIHgtIGFuZCB5LWF4aXMgbGFiZWxzIGFuZCBvZiBhZGRpbmcgaW5mb3JtYXRpdmUgcGxvdCB0aXRsZXMuCgojIyMgSW5zdHJ1Y3Rpb25zCgotIEV4YW1pbmUgdGhlIHJhbmdlIG9mIHggYW5kIHkgdmFsdWVzIGZyb20gdGhlIHByZXZpb3VzIGZvdXIgcGxvdHMgdG8gZGV0ZXJtaW5lIGEgY29tbW9uIHJhbmdlIHRoYXQgY292ZXJzIHRoZSByYW5nZXMgb2YgYWxsIGZvdXIgb2YgdGhlc2UgcGxvdHMuIFVzZSBpbnRlZ2VyIHZhbHVlcyB0byBrZWVwIHRoaW5ncyBzaW1wbGUuCi0gU2V0IHVwIGEgdHdvLWJ5LXR3byBwbG90IGFycmF5IHVzaW5nIHRoZSBgcGFyKClgIGZ1bmN0aW9uLgotIFBsb3QgdGhlIGB5MWAgdmFyaWFibGUgYWdhaW5zdCB0aGUgYHgxYCB2YXJpYWJsZSB1c2luZyB0aGVzZSBjb21tb24gcmFuZ2VzLCB3aXRoIHgtYXhpcyBsYWJlbCBgInggdmFsdWUiYCBhbmQgeS1heGlzIGxhYmVsIGAieSB2YWx1ZSJgLCBhbmQgdXNlIHRoZSBgbWFpbiwgYXJndW1lbnQgdG8gYWRkIHRoZSB0aXRsZSBgIkZpcnN0IGRhdGFzZXQiYC4KLSBSZXBlYXQgZm9yIHRoZSBvdGhlciB0aHJlZSBBbnNjb21iZSBkYXRhIHBhaXJzLCBhZGRpbmcgdGhlIGFwcHJvcHJpYXRlIHRpdGxlcy4KCmBgYHtyfQojIERlZmluZSBjb21tb24geCBhbmQgeSBsaW1pdHMgZm9yIHRoZSBmb3VyIHBsb3RzCnhtaW4gPC0gX19fCnhtYXggPC0gX19fCnltaW4gPC0gX19fCnltYXggPC0gX19fCgojIFNldCB1cCBhIHR3by1ieS10d28gcGxvdCBhcnJheQoKCiMgUGxvdCB5MSB2cy4geDEgd2l0aCBjb21tb24geCBhbmQgeSBsaW1pdHMsIGxhYmVscyAmIHRpdGxlCnBsb3QoYW5zY29tYmUkX19fLCBhbnNjb21iZSRfX18sCiAgICAgeGxpbSA9IGMoeG1pbiwgeG1heCksCiAgICAgeWxpbSA9IGMoeW1pbiwgeW1heCksCiAgICAgeGxhYiA9ICJ4IHZhbHVlIiwgeWxhYiA9ICJ5IHZhbHVlIiwKICAgICBtYWluID0gX19fKQoKIyBEbyB0aGUgc2FtZSBmb3IgdGhlIHkyIHZzLiB4MiBwbG90CnBsb3QoYW5zY29tYmUkX19fLCBhbnNjb21iZSRfX18sCiAgICAgeGxpbSA9IGMoeG1pbiwgeG1heCksCiAgICAgeWxpbSA9IGMoeW1pbiwgeW1heCksCiAgICAgeGxhYiA9ICJ4IHZhbHVlIiwgeWxhYiA9ICJ5IHZhbHVlIiwKICAgICBtYWluID0gX19fKQoKIyBEbyB0aGUgc2FtZSBmb3IgdGhlIHkzIHZzLiB4MyBwbG90CnBsb3QoYW5zY29tYmUkX19fLCBhbnNjb21iZSRfX18sCiAgICAgeGxpbSA9IGMoeG1pbiwgeG1heCksCiAgICAgeWxpbSA9IGMoeW1pbiwgeW1heCksCiAgICAgeGxhYiA9ICJ4IHZhbHVlIiwgeWxhYiA9ICJ5IHZhbHVlIiwKICAgICBtYWluID0gX19fKQoKIyBEbyB0aGUgc2FtZSBmb3IgdGhlIHk0IHZzLiB4NCBwbG90CnBsb3QoYW5zY29tYmUkX19fLCBhbnNjb21iZSRfX18sCiAgICAgeGxpbSA9IGMoeG1pbiwgeG1heCksCiAgICAgeWxpbSA9IGMoeW1pbiwgeW1heCksCiAgICAgeGxhYiA9ICJ4IHZhbHVlIiwgeWxhYiA9ICJ5IHZhbHVlIiwKICAgICBtYWluID0gX19fKQpgYGAKCgoKIyMgVXNpbmcgbXVsdGlwbGUgcGxvdHMgdG8gZ2l2ZSBtdWx0aXBsZSB2aWV3cyBvZiBhIGRhdGFzZXQKCkFub3RoZXIgdXNlZnVsIGFwcGxpY2F0aW9uIG9mIG11bHRpcGxlIHBsb3QgYXJyYXlzIGJlc2lkZXMgY29tcGFyaXNvbiBpcyBwcmVzZW50aW5nIG11bHRpcGxlIHJlbGF0ZWQgdmlld3Mgb2YgdGhlIHNhbWUgZGF0YXNldC4KClRoaXMgZXhlcmNpc2UgaWxsdXN0cmF0ZXMgdGhpcyBpZGVhLCBnaXZpbmcgZm91ciB2aWV3cyBvZiB0aGUgc2FtZSBkYXRhc2V0OiBhIHBsb3Qgb2YgdGhlIHJhdyBkYXRhIHZhbHVlcyB0aGVtc2VsdmVzLCBhIGhpc3RvZ3JhbSBvZiB0aGVzZSBkYXRhIHZhbHVlcywgYSBkZW5zaXR5IHBsb3QsIGFuZCBhIG5vcm1hbCBRUS1wbG90LgoKIyMjIEluc3RydWN0aW9ucwoKLSBOb3RlIHRoYXQgdGhlIGBNQVNTYCBhbmQgYGNhcmAgcGFja2FnZXMgaGF2ZSBiZWVuIHByZS1sb2FkZWQsIG1ha2luZyB0aGUgYGdleXNlcmAgZGF0YSBhbmQgdGhlIGB0cnVlaGlzdCgpYCBhbmQgYHFxUGxvdCgpYCBmdWN0aW9ucyBhdmFpbGFibGUgZm9yIHlvdXIgdXNlLgotIFVzZSB0aGUgYHBhcigpYCBmdW5jdGlvbiB0byBzZXQgdGhlIGBtZnJvd2AgcGFyYW1ldGVyIGZvciBhIHR3by1ieS10d28gcGxvdCBhcnJheS4KLSBJbiB0aGUgdXBwZXIgbGVmdCwgdXNlIHRoZSBgcGxvdCgpYCBmdW5jdGlvbiB0byBzaG93IHRoZSB2YWx1ZXMgb2YgdGhlIGBkdXJhdGlvbmAgdmFyaWFibGUgZnJvbSB0aGUgYGdleXNlcmAgZGF0YXNldCwgdXNpbmcgdGhlIGBtYWluYCBhcmd1bWVudCB0byBzcGVjaWZ5IHRoZSBwbG90IHRpdGxlIGFzIGAiUmF3IGRhdGEiYC4KLSBJbiB0aGUgdXBwZXIgcmlnaHQsIHVzZSB0aGUgYHRydWVoaXN0KClgIGZ1bmN0aW9uIHRvIGdlbmVyYXRlIGEgaGlzdG9ncmFtIG9mIHRoZSBgZHVyYXRpb25gIGRhdGEsIHVzaW5nIHRoZSBgbWFpbmAgYXJndW1lbnQgdG8gZ2l2ZSB0aGlzIHBsb3QgdGhlIHRpdGxlIGAiSGlzdG9ncmFtImAuCi0gSW4gdGhlIGxvd2VyIGxlZnQsIHVzZSB0aGUgYHBsb3QoKWAgYW5kIGBkZW5zaXR5KClgIGZ1bmN0aW9ucyB0byBkaXNwbGF5IHRoZSBkZW5zaXR5IG9mIHRoZSBgZHVyYXRpb25gIHZhbHVlcywgdXNpbmcgdGhlIGBtYWluYCBhcmd1bWVudCB0byBnaXZlIHRoaXMgcGxvdCB0aGUgdGl0bGUgYCJEZW5zaXR5ImAuCi0gSW4gdGhlIGxvd2VyIHJpZ2h0LCB1c2UgdGhlIGBxcVBsb3QoKWAgZnVuY3Rpb24gZnJvbSB0aGUgYGNhcmAgcGFja2FnZSB0byBkaXNwbGF5IGEgbm9ybWFsIFFRLXBsb3Qgb2YgdGhlIGBkdXJhdGlvbmAgZGF0YSwgdXNpbmcgdGhlIGBtYWluYCBhcmd1bWVudCB0byBnaXZlIHRoaXMgcGxvdCB0aGUgdGl0bGUgYCJRUS1wbG90ImAuCgpgYGB7cn0KIyBTZXQgdXAgYSB0d28tYnktdHdvIHBsb3QgYXJyYXkKCgojIFBsb3QgdGhlIHJhdyBkdXJhdGlvbiBkYXRhCgoKIyBQbG90IHRoZSBub3JtYWxpemVkIGhpc3RvZ3JhbSBvZiB0aGUgZHVyYXRpb24gZGF0YQoKCiMgUGxvdCB0aGUgZGVuc2l0eSBvZiB0aGUgZHVyYXRpb24gZGF0YQoKCiMgQ29uc3RydWN0IHRoZSBub3JtYWwgUVEtcGxvdCBvZiB0aGUgZHVyYXRpb24gZGF0YQoKYGBgCgoKIyMgQ29uc3RydWN0aW5nIGFuZCBkaXNwbGF5aW5nIGxheW91dCBtYXRyaWNlcwoKWW91IGNhbiB0aGluayBvZiB0aGUgbGF5b3V0IG1hdHJpeCBhcyB0aGUgcGxvdCBwYW5lLCB3aGVyZSBhIDAgcmVwcmVzZW50cyBlbXB0eSBzcGFjZSBhbmQgb3RoZXIgbnVtYmVycyByZXByZXNlbnQgdGhlIHBsb3QgbnVtYmVyLCB3aGljaCBpcyBkZXRlcm1pbmVkIGJ5IHRoZSBzZXF1ZW5jZSBvZiB2aXN1YWxpemF0aW9uIGZ1bmN0aW9uIGNhbGxzLiBGb3IgZXhhbXBsZSwgYSAxIGluIHRoZSBsYXlvdXQgbWF0cml4IHJlZmVycyB0byB0aGUgdmlzdWFsaXphdGlvbiB0aGF0IHdhcyBmaXJzdCBjYWxsZWQsIGEgMiByZWZlcnMgdG8gdGhlIHBsb3Qgb2YgdGhlIHNlY29uZCB2aXN1YWxpemF0aW9uIGNhbGwsIGV0Yy4gVGhpcyBleGVyY2lzZSBhc2tzIHlvdSB0byBjcmVhdGUgeW91ciBvd24gMyB4IDIgbGF5b3V0IG1hdHJpeCwgdXNpbmcgdGhlIGBjKClgIGZ1bmN0aW9uIHRvIGNvbmNhdGVuYXRlIG51bWJlcnMgaW50byB2ZWN0b3JzIHRoYXQgd2lsbCBmb3JtIHRoZSByb3dzIG9mIHRoZSBtYXRyaXguCgpZb3Ugd2lsbCB0aGVuIHVzZSB0aGUgYG1hdHJpeCgpYCBmdW5jdGlvbiB0byBjb252ZXJ0IHRoZXNlIHJvd3MgaW50byBhIG1hdHJpeCBhbmQgYXBwbHkgdGhlIGBsYXlvdXQoKWAgZnVuY3Rpb24gdG8gc2V0IHVwIHRoZSBkZXNpcmVkIHBsb3QgYXJyYXkuIFRoZSBjb252ZW5pZW5jZSBmdW5jdGlvbiBgbGF5b3V0LnNob3coKWAgY2FuIHRoZW4gYmUgdXNlZCB0byB2ZXJpZnkgdGhhdCB0aGUgcGxvdCBhcnJheSBoYXMgdGhlIHNoYXBlIHlvdSB3YW50LgoKIyMjIEluc3RydWN0aW9ucwoKLSBVc2luZyB0aGUgYG1hdHJpeCgpYCBmdW5jdGlvbiwgY3JlYXRlIGEgbWF0cml4IGNhbGxlZCBgbGF5b3V0TWF0cml4YCB3aXRoIHRocmVlIHJvd3MgYW5kIHR3byBjb2x1bW5zOgogICAtIHRoZSBmaXJzdCByb3cgZGVzaWduYXRlcyBhbiBlbXB0eSBwbG90IHRvIHRoZSBsZWZ0IGFuZCBwbG90IDEgdG8gdGhlIHJpZ2h0LgogICAtIHRoZSBzZWNvbmQgcm93IGRlc2lnbmF0ZXMgcGxvdCAyIHRvIHRoZSBsZWZ0IGFuZCBhbiBlbXB0eSBwbG90IHRvIHRoZSByaWdodC4KICAgLSB0aGUgdGhpcmQgcm93IGRlc2lnbmF0ZXMgYW4gZW1wdHkgcGxvdCB0byB0aGUgbGVmdCBhbmQgcGxvdCAzIHRvIHRoZSByaWdodC4KLSBVc2UgdGhlIGBsYXlvdXQoKWAgZnVuY3Rpb24gdG8gc2V0IHVwIHRoZSBkZXNpcmVkIHBsb3QgYXJyYXkuCi0gVXNlIHRoZSBgbGF5b3V0LnNob3coKWAgZnVuY3Rpb24gdG8gc2hvdyB0aGUgYXJyYW5nZW1lbnQgb2YgYWxsIHRocmVlIHBsb3RzLgoKYGBge3J9CiMgVXNlIHRoZSBtYXRyaXggZnVuY3Rpb24gdG8gY3JlYXRlIGEgbWF0cml4IHdpdGggdGhyZWUgcm93cyBhbmQgdHdvIGNvbHVtbnMKbGF5b3V0TWF0cml4IDwtIG1hdHJpeCgKICBjKAogICAgX19fLCBfX18sCiAgICBfX18sIF9fXywKICAgIF9fXywgX19fCiAgKSwgCiAgYnlyb3cgPSBfX18sIAogIG5yb3cgPSBfX18KKQoKIyBDYWxsIHRoZSBsYXlvdXQoKSBmdW5jdGlvbiB0byBzZXQgdXAgdGhlIHBsb3QgYXJyYXkKCgojIFNob3cgd2hlcmUgdGhlIHRocmVlIHBsb3RzIHdpbGwgZ28gCgpgYGAKCgojIyBDcmVhdGluZyBhIHRyaWFuZ3VsYXIgYXJyYXkgb2YgcGxvdHMKClRoZSBwcmV2aW91cyBleGVyY2lzZSBhc2tlZCB5b3UgdG8gY3JlYXRlIGEgcGxvdCBhcnJheSB1c2luZyB0aGUgYGxheW91dCgpYCBmdW5jdGlvbi4gUmVjYWxsIHRoZSBsYXlvdXQgbWF0cml4IGZyb20gdGhlIHByZXZpb3VzIGV4ZXJjaXNlOgoKYGBgCj4gbGF5b3V0TWF0cml4CiAgICAgWywxXSBbLDJdClsxLF0gICAgMCAgICAxClsyLF0gICAgMiAgICAwClszLF0gICAgMCAgICAzCmBgYAoKVGhpcyBleGVyY2lzZSBhc2tzIHlvdSB0byB1c2UgdGhpcyBhcnJheSB0byBnaXZlIHRocmVlIGRpZmZlcmVudCB2aWV3cyBvZiB0aGUgYHdoaXRlc2lkZWAgZGF0YSBmcmFtZS4KClRoZSBmaXJzdCBwbG90LCBvbiB0aGUgdXBwZXIgcmlnaHQgb2YgdGhlIHBsb3QgYXJyYXksIHNob3dzIHRoZSByZWxhdGlvbnNoaXAgb2YgYEdhc2AgYW5kIGBUZW1wYCB1c2luZyBhbGwgZGF0YSBmcm9tIGB3aGl0ZXNpZGVgLiBUaGUgc2Vjb25kIHBsb3QsIGluIHRoZSBjZW50ZXIgbGVmdCBvZiB0aGUgcGxvdCBhcnJheSwgc2hvd3MgdGhlIHJlbGF0aW9uc2hpcCBvZiB0aGUgdHdvIHZhcmlhYmxlcyB1c2luZyBkYXRhIHdoZXJlIGBJbnN1bGAgaXMgZXF1YWwgdG8gYCJCZWZvcmUiYC4gRmluYWxseSwgdGhlIHRoaXJkIHBsb3QsIG9uIHRoZSBsb3dlciBsZWZ0IG9mIHRoZSBwbG90IGFycmF5LCBzaG93cyB0aGUgcmVsYXRpb25zaGlwIHVzaW5nIGRhdGEgd2hlcmUgYEluc3VsYCBpcyBlcXVhbCB0byBgIkFmdGVyImAuCgpUaGUgcHJpbWFyeSBtb3RpdmF0aW9uIGZvciB0aGlzIGV4ZXJjaXNlIGlzIHRoYXQgaXQgaXMgbm90IHBvc3NpYmxlIHRvIGNvbnN0cnVjdCBhIHBsb3QgYXJyYXkgaW4gdGhpcyBmb3JtYXQgdXNpbmcgdGhlIGBtZnJvd2AgcGFyYW1ldGVyLCBzaW5jZSB0aGUgYXJyYXkgaXMgbm90IHJlY3Rhbmd1bGFyLgoKIyMjIEluc3RydWN0aW9ucwoKVGhlIGxheW91dCBtYXRyaXggeW91IHNldCB1cCBpbiB0aGUgcHJldmlvdXMgZXhlcmNpc2UgaXMgYXZhaWxhYmxlIGluIHlvdXIgd29ya3NwYWNlIGFzIGBsYXlvdXRNYXRyaXhgLiBUaGUgYHdoaXRlc2lkZWAgZGF0YSBmcmFtZSBpcyBhbHJlYWR5IGF2YWlsYWJsZSBpbiB5b3VyIHdvcmtzcGFjZSBhcyB3ZWxsLgoKLSBDYWxsIHRoZSBgbGF5b3V0KClgIGZ1bmN0aW9uIG9uIGBsYXlvdXRNYXRyaXhgIHRvIHNldCB1cCB0aGUgcGxvdCBhcnJheS4KLSBDb25zdHJ1Y3QgYSB2ZWN0b3IgYGluZGV4QmAgdGhhdCBwb2ludHMgdG8gb25seSB0aG9zZSByZWNvcmRzIHdpdGggdGhlIGBJbnN1bGAgdmFsdWUgYCJCZWZvcmUiYCBhbmQgYSB2ZWN0b3IgYGluZGV4QWAgdGhhdCBwb2ludHMgdG8gb25seSB0aG9zZSByZWNvcmRzIHdpdGggdGhlIGBJbnN1bGAgdmFsdWUgYCJBZnRlciJgLgotIFBsb3QgdGhlIGBHYXNgIHZlcnN1cyBgVGVtcGAgdmFsdWVzIGZyb20gdGhlIGBpbmRleEJgIGRhdGEgaW4gdGhlIHVwcGVyIHJpZ2h0IHBsb3QgaW4geW91ciBhcnJheSwgdXNpbmcgdGhlIHktYXhpcyBsaW1pdHMgYGMoMCwgOClgLiBHaXZlIHRoaXMgcGxvdCB0aGUgdGl0bGUgYCJCZWZvcmUgZGF0YSBvbmx5ImAuCi0gUGxvdCB0aGUgYEdhc2AgdmVyc3VzIGBUZW1wYCB2YWx1ZXMgZnJvbSB0aGUgY29tcGxldGUgZGF0YXNldCBpbiB0aGUgY2VudGVyIGxlZnQgcGxvdCwgdXNpbmcgdGhlIHNhbWUgeS1heGlzIGxpbWl0cyBhcyB0aGUgZmlyc3QgcGxvdC4gR2l2ZSB0aGlzIHBsb3QgdGhlIHRpdGxlIGAiQ29tcGxldGUgZGF0YXNldCJgLgotIFBsb3QgdGhlIGBHYXNgIHZlcnN1cyBgVGVtcGAgdmFsdWVzIGZyb20gdGhlIGBpbmRleEFgIGRhdGEgaW4gdGhlIGxvd2VyIHJpZ2h0IHBsb3QsIGFnYWluIHVzaW5nIHRoZSBzYW1lIHktYXhpcyBsaW1pdHMuIEdpdmUgdGhpcyBwbG90IHRoZSB0aXRsZSBgIkFmdGVyIGRhdGEgb25seSJgLgoKYGBge3J9CiMgU2V0IHVwIHRoZSBwbG90IGFycmF5CgoKIyBDb25zdHJ1Y3QgdmVjdG9ycyBpbmRleEIgYW5kIGluZGV4QQppbmRleEIgPC0gd2hpY2goX19fKQppbmRleEEgPC0gd2hpY2goX19fKQoKIyBDcmVhdGUgcGxvdCAxIGFuZCBhZGQgdGl0bGUKcGxvdCh3aGl0ZXNpZGUkX19fW19fX10sIHdoaXRlc2lkZSRfX19bX19fXSwKICAgICB5bGltID0gX19fKQp0aXRsZShfX18pCgojIENyZWF0ZSBwbG90IDIgYW5kIGFkZCB0aXRsZQoKCgoKIyBDcmVhdGUgcGxvdCAzIGFuZCBhZGQgdGl0bGUKYGBgCgoKIyMgQ3JlYXRpbmcgYXJyYXlzIHdpdGggZGlmZmVyZW50IHNpemVkIHBsb3RzCgpCZXNpZGVzIGNyZWF0aW5nIG5vbi1yZWN0YW5ndWxhciBhcnJheXMsIHRoZSBgbGF5b3V0KClgIGZ1bmN0aW9uIGNhbiBiZSB1c2VkIHRvIGNyZWF0ZSBwbG90IGFycmF5cyB3aXRoIGRpZmZlcmVudCBzaXplZCBjb21wb25lbnQgcGxvdHMgLS0gc29tZXRoaW5nIGVsc2UgdGhhdCBpcyBub3QgcG9zc2libGUgYnkgc2V0dGluZyB0aGUgYHBhcigpYCBmdW5jdGlvbidzIGBtZnJvd2AgcGFyYW1ldGVyLgoKVGhpcyBleGVyY2lzZSBpbGx1c3RyYXRlcyB0aGUgcG9pbnQsIGFza2luZyB5b3UgdG8gY3JlYXRlIGEgc3RhbmRhcmQgc2NhdHRlcnBsb3Qgb2YgdGhlIGB6bmAgdmVyc3VzIGByYWRgIHZhcmlhYmxlcyBmcm9tIHRoZSBgQm9zdG9uYCBkYXRhIGZyYW1lIGFzIGEgc21hbGxlciBwbG90IGluIHRoZSB1cHBlciBsZWZ0LCB3aXRoIGEgbGFyZ2VyIHN1bmZsb3dlciBwbG90IG9mIHRoZSBzYW1lIGRhdGEgaW4gdGhlIGxvd2VyIHJpZ2h0LgoKIyMjIEluc3RydWN0aW9ucwoKVGhlIGBCb3N0b25gIGRhdGEgZnJhbWUgaW4gdGhlIGBNQVNTYCBwYWNrYWdlIGlzIGFscmVhZHkgYXZhaWxhYmxlIGluIHlvdXIgd29ya3NwYWNlLgoKLSBVc2luZyB0aGUgYGMoKWAgZnVuY3Rpb246CiAgIC0gQ3JlYXRlIHRoZSB0aHJlZS1lbGVtZW50IHZlY3RvciBgcm93MWAgd2l0aCB2YWx1ZXMgYCgxLCAwLCAwKWAuCiAgIC0gQ3JlYXRlIHRoZSB0aHJlZS1lbGVtZW50IHZlY3RvciBgcm93MmAgd2l0aCB2YWx1ZXMgYCgwLCAyLCAyKWAuCi0gQ29tYmluZSB0aGUgZmlyc3QgdmVjdG9yIHdpdGggdHdvIGNvcGllcyBvZiB0aGUgc2Vjb25kIHZlY3RvciBpbnRvIGBsYXlvdXRWZWN0b3JgLCBhIHZlY3RvciBvZiBsZW5ndGggOS4KLSBVc2luZyB0aGUgYG1hdHJpeCgpYCBmdW5jdGlvbiwgY29udmVydCBgbGF5b3V0VmVjdG9yYCBpbnRvIHRoZSAzLWJ5LTMgbWF0cml4IGBsYXlvdXRNYXRyaXgsIHdob3NlIGZpcnN0IHJvdyBpcyBgcm93MWAgYW5kIHdob3NlIHNlY29uZCBhbmQgdGhpcmQgcm93cyBhcmUgYHJvdzJgLgotIFVzZSB0aGUgYGxheW91dCgpYCBmdW5jdGlvbiB3aXRoIGBsYXlvdXRNYXRyaXhgIHRvIGNvbmZpZ3VyZSBhIHR3by1lbGVtZW50IHBsb3QgYXJyYXkuCi0gSW4gdGhlIGZpcnN0IChzbWFsbGVyKSBwbG90LCBjcmVhdGUgYSBzdGFuZGFyZCBzY2F0dGVycGxvdCBvZiB0aGUgYHpuYCB2YXJpYWJsZSB2ZXJzdXMgdGhlIGByYWRgIHZhcmlhYmxlIGZyb20gdGhlIGBCb3N0b25gIGRhdGEgZnJhbWUuCi0gSW4gdGhlIHNlY29uZCAobGFyZ2VyKSBwbG90LCBjcmVhdGUgYSBzdW5mbG93ZXIgcGxvdCB1c2luZyB0aGUgYHN1bmZsb3dlcnBsb3QoKWAgZnVuY3Rpb24gYW5kIHRoZSBzYW1lIHZhcmlhYmxlcy4KCmBgYHtyfQojIENyZWF0ZSByb3cxLCByb3cyLCBhbmQgbGF5b3V0VmVjdG9yCnJvdzEgPC0gX19fCnJvdzIgPC0gX19fCmxheW91dFZlY3RvciA8LSBfX18KCiMgQ29udmVydCBsYXlvdXRWZWN0b3IgaW50byBsYXlvdXRNYXRyaXgKbGF5b3V0TWF0cml4IDwtIG1hdHJpeChfX18sIGJ5cm93ID0gX19fLCBucm93ID0gX19fKQoKIyBTZXQgdXAgdGhlIHBsb3QgYXJyYXkKCgojIFBsb3Qgc2NhdHRlcnBsb3QKCgojIFBsb3Qgc3VuZmxvd2VyIHBsb3QKCmBgYAoKCiMgQWR2YW5jZWQgUGxvdCBDdXN0b21pemF0aW9uIGFuZCBCZXlvbmQKCiMjIFNvbWUgcGxvdCBmdW5jdGlvbnMgYWxzbyByZXR1cm4gdXNlZnVsIGluZm9ybWF0aW9uCgpDYWxsaW5nIHRoZSBgYmFycGxvdCgpYCBmdW5jdGlvbiBoYXMgdGhlIHNpZGUgZWZmZWN0IG9mIGNyZWF0aW5nIHRoZSBwbG90IHdlIHdhbnQsIGJ1dCBpdCBhbHNvIHJldHVybnMgYSBudW1lcmljYWwgdmVjdG9yIHdpdGggdGhlIGNlbnRlciBwb3NpdGlvbnMgb2YgZWFjaCBiYXIgaW4gdGhlIHBsb3QuIFRoaXMgdmFsdWUgaXMgcmV0dXJuZWQgaW52aXNpYmx5IHNvIHdlIGRvbid0IG5vcm1hbGx5IHNlZSBpdCwgYnV0IHdlIGNhbiBjYXB0dXJlIGl0IHdpdGggYW4gYXNzaWdubWVudCBzdGF0ZW1lbnQuCgpUaGVzZSByZXR1cm4gdmFsdWVzIGNhbiBiZSBlc3BlY2lhbGx5IHVzZWZ1bCB3aGVuIHdlIHdhbnQgdG8gb3ZlcmxheSB0ZXh0IG9uIHRoZSBiYXJzIG9mIGEgaG9yaXpvbnRhbCBiYXJwbG90LiBUaGVuLCB3ZSBjYXB0dXJlIHRoZSByZXR1cm4gdmFsdWVzIGFuZCB1c2UgdGhlbSBhcyB0aGUgYHlgIHBhcmFtZXRlciBpbiBhIHN1YnNlcXVlbnQgY2FsbCB0byB0aGUgYHRleHQoKWAgZnVuY3Rpb24sIGFsbG93aW5nIHVzIHRvIHBsYWNlIHRoZSB0ZXh0IGF0IHdoYXRldmVyIGB4YCBwb3NpdGlvbiB3ZSB3YW50IGJ1dCBvdmVybGFpZCBpbiB0aGUgbWlkZGxlIG9mIGVhY2ggaG9yaXpvbnRhbCBiYXIuIFRoaXMgZXhlcmNpc2UgYXNrcyB5b3UgdG8gY29uc3RydWN0IGEgaG9yaXpvbnRhbCBiYXJwbG90IHRoYXQgZXhwbG9pdHMgdGhlc2UgcG9zc2liaWxpdGllcy4KCiMjIyBJbnN0cnVjdGlvbnMKClRoZSBgQ2FyczkzYCBkYXRhIGZyYW1lIGZyb20gdGhlIGBNQVNTYCBwYWNrYWdlIGlzIGFscmVhZHkgYXZhaWxhYmxlIGluIHlvdXIgd29ya3NwYWNlLgoKLSBVc2UgdGhlIGB0YWJsZSgpYCBmdW5jdGlvbiB0byBnZW5lcmF0ZSB0aGUgb2JqZWN0IGB0YmxgIHN1bW1hcml6aW5nIHRoZSBudW1iZXIgb2YgcmVjb3JkcyBsaXN0aW5nIGVhY2ggdmFsdWUgb2YgdGhlIGBDeWxpbmRlcnNgIHZhcmlhYmxlIGZyb20gdGhlIGBDYXJzOTNgIGRhdGEgZnJhbWUuCi0gVXNlIHRoZSBgYmFycGxvdCgpYCBmdW5jdGlvbiB3aXRoIHRoZSBgaG9yaXpgIGFyZ3VtZW50IHNldCB0byBgVFJVRWAgdG8gY29uc3RydWN0IGEgaG9yaXpvbnRhbCBiYXJwbG90IG9mIHRoaXMgcmVjb3JkIHN1bW1hcnksIHNwZWNpZnlpbmcgdGhlIGNvbG9yIG9mIHRoZSBiYXJzIHRvIGJlIGAidHJhbnNwYXJlbnQiYCBhbmQgcmV0dXJuaW5nIHRoZSB2ZWN0b3IgbWlkcyBnaXZpbmcgdGhlIHZlcnRpY2FsIHBvc2l0aW9ucyBvZiB0aGUgY2VudGVycyBvZiBlYWNoIGJhciBpbiB0aGUgcGxvdC4gU3BlY2lmeSB0aGUgYG5hbWVzLmFyZ2AgYXJndW1lbnQgYXMgYCIiYCB0byBzdXBwcmVzcyB0aGUgeS1heGlzIGxlZ2VuZCBvbiB0aGlzIHBsb3QuCi0gVXNlIHRoZSBgdGV4dCgpYCBmdW5jdGlvbiB0byBsYWJlbCB0aGUgYEN5bGluZGVyc2AgdmFsdWUgZm9yIGVhY2ggYmFyIGluIHRoZSBiYXJwbG90IGF0IHRoZSBob3Jpem9udGFsIHBvc2l0aW9uIGAyMGAuIFRoZSBgbmFtZXMoKWAgZnVuY3Rpb24gbWF5IHByb3ZlIHVzZWZ1bCBoZXJlLgotIFVzZSB0aGUgYHRleHQoKWAgZnVuY3Rpb24gdG8gbGlzdCB0aGUgY291bnRzIGZvciBlYWNoIGN5bGluZGVycyB2YWx1ZSBhdCB0aGUgaG9yaXpvbnRhbCBwb3NpdGlvbiBgMzVgLiBIZXJlLCB0aGUgYGFzLm51bWVyaWMoKWAgZnVuY3Rpb24gbWF5IHByb3ZlIHVzZWZ1bC4KCmBgYHtyfQojIENyZWF0ZSBhIHRhYmxlIG9mIEN5bGluZGVycyBmcmVxdWVuY2llcwp0YmwgPC0gX19fCgojIEdlbmVyYXRlIGEgaG9yaXpvbnRhbCBiYXJwbG90IG9mIHRoZXNlIGZyZXF1ZW5jaWVzCm1pZHMgPC0gYmFycGxvdChfX18sIGhvcml6ID0gX19fLAogICAgICAgICAgICAgICAgY29sID0gX19fLAogICAgICAgICAgICAgICAgbmFtZXMuYXJnID0gX19fKQoKIyBBZGQgbmFtZXMgbGFiZWxzIHdpdGggdGV4dCgpCnRleHQoX19fLCBtaWRzLCBfX18pCgojIEFkZCBjb3VudCBsYWJlbHMgd2l0aCB0ZXh0KCkKdGV4dChfX18sIG1pZHMsIF9fXykKYGBgCgoKIyMgVXNpbmcgdGhlIGBzeW1ib2xzKClgIGZ1bmN0aW9uIHRvIGRpc3BsYXkgcmVsYXRpb25zIGJldHdlZW4gbW9yZSB0aGFuIHR3byB2YXJpYWJsZXMKClRoZSBzY2F0dGVycGxvdCBhbGxvd3MgdXMgdG8gc2VlIGhvdyBvbmUgbnVtZXJpY2FsIHZhcmlhYmxlIGNoYW5nZXMgd2l0aCB0aGUgdmFsdWVzIG9mIGEgc2Vjb25kIG51bWVyaWNhbCB2YXJpYWJsZS4gVGhlIGBzeW1ib2xzKClgIGZ1bmN0aW9uIGFsbG93cyB1cyB0byBleHRlbmQgc2NhdHRlcnBsb3RzIHRvIHNob3cgdGhlIGluZmx1ZW5jZSBvZiBvdGhlciB2YXJpYWJsZXMuCgpUaGlzIGZ1bmN0aW9uIGlzIGNhbGxlZCB3aXRoIHRoZSB2YXJpYWJsZXMgYHhgIGFuZCBgeWAgdGhhdCBkZWZpbmUgYSBzY2F0dGVycGxvdCwgYWxvbmcgd2l0aCBhbm90aGVyIGFyZ3VtZW50IHRoYXQgc3BlY2lmaWVzIG9uZSBvZiBzZXZlcmFsIHBvc3NpYmxlIHNoYXBlcy4gSGVyZSwgeW91IGFyZSBhc2tlZCB0byB1c2UgdGhlIGBjaXJjbGVzYCBhcmd1bWVudCB0byBjcmVhdGUgYSAqYnViYmxlcGxvdCogd2hlcmUgZWFjaCBkYXRhIHBvaW50IGlzIHJlcHJlc2VudGVkIGJ5IGEgY2lyY2xlIHdob3NlIHJhZGl1cyBkZXBlbmRzIG9uIHRoZSB0aGlyZCB2YXJpYWJsZSBzcGVjaWZpZWQgYnkgdGhlIHZhbHVlIG9mIHRoaXMgYXJndW1lbnQuCgojIyMgSW5zdHJ1Y3Rpb25zCgpUaGUgYENhcnM5M2AgZGF0YSBmcmFtZSBmcm9tIHRoZSBgTUFTU2AgcGFja2FnZSBpcyBhbHJlYWR5IGF2YWlsYWJsZSBpbiB5b3VyIHdvcmtzcGFjZS4KCi0gVXNlIHRoZSBgc3ltYm9scygpYCBmdW5jdGlvbiB3aXRoIGl0cyBkZWZhdWx0IHNldHRpbmdzIGFuZCB0aGUgYXBwcm9wcmlhdGUgYXJndW1lbnRzIHRvIGNyZWF0ZSBhIGJ1YmJsZSBwbG90IG9mIGBNUEcuY2l0eWAgdmVyc3VzIGBIb3JzZXBvd2VyYCBmcm9tIHRoZSBgQ2FyczkzYCBkYXRhIGZyYW1lLCB3aXRoIHRoZSBidWJibGUgYXJlYSBieSB0aGUgYFByaWNlYCB2YXJpYWJsZS4gTm90ZSB0aGF0IHRoaXMgbWVhbnMgdGhlIGJ1YmJsZSByYWRpdXMgc2hvdWxkIGJlIHByb3BvcnRpb25hbCB0byB0aGUgc3F1YXJlIHJvb3Qgb2YgYFByaWNlYC4KLSBSZS1jcmVhdGUgdGhlIGZpcnN0IHBsb3QsIGJ1dCB3aXRoIHRoZSBvcHRpb25hbCBhcmd1bWVudCBgaW5jaGVzYCBzZXQgdG8gYDAuMWAuCgpgYGB7cn0KIyBDYWxsIHN5bWJvbHMoKSB0byBjcmVhdGUgdGhlIGRlZmF1bHQgYnViYmxlcGxvdApzeW1ib2xzKF9fXywgX19fLAogICAgICAgIGNpcmNsZXMgPSBfX18pCgojIFJlcGVhdCwgd2l0aCB0aGUgaW5jaGVzIGFyZ3VtZW50IHNwZWNpZmllZApzeW1ib2xzKF9fXywgX19fLAogICAgICAgIGNpcmNsZXMgPSBfX18sCiAgICAgICAgaW5jaGVzID0gX19fKQpgYGAKCgojIyBTYXZpbmcgcGxvdCByZXN1bHRzIGFzIGZpbGVzCgpJbiBhbiBpbnRlcmFjdGl2ZSBSIHNlc3Npb24sIHdlIHR5cGljYWxseSBnZW5lcmF0ZSBhIGNvbGxlY3Rpb24gb2YgZGlmZmVyZW50IHBsb3RzLCBvZnRlbiB1c2luZyB0aGUgcmVzdWx0cyB0byBoZWxwIHVzIGRlY2lkZSBob3cgdG8gcHJvY2VlZCB3aXRoIG91ciBhbmFseXNpcy4gVGhpcyBpcyBwYXJ0aWN1bGFybHkgdHJ1ZSBpbiB0aGUgZWFybHkgcGhhc2VzIG9mIGFuIGV4cGxvcmF0b3J5IGRhdGEgYW5hbHlzaXMsIGJ1dCBvbmNlIHdlIGhhdmUgZ2VuZXJhdGVkIGEgcGxvdCB3ZSB3YW50IHRvIHNoYXJlIHdpdGggb3RoZXJzLCBpdCBpcyBpbXBvcnRhbnQgdG8gc2F2ZSBpdCBpbiBhbiBleHRlcm5hbCBmaWxlLgoKUiBwcm92aWRlcyBzdXBwb3J0IGZvciBzYXZpbmcgZ3JhcGhpY2FsIHJlc3VsdHMgaW4gc2V2ZXJhbCBkaWZmZXJlbnQgZXh0ZXJuYWwgZmlsZSBmb3JtYXRzLCBpbmNsdWRpbmcganBlZywgcG5nLCB0aWZmLCBvciBwZGYgZmlsZXMuIEluIGFkZGl0aW9uLCB3ZSBjYW4gaW5jb3Jwb3JhdGUgZ3JhcGhpY2FsIHJlc3VsdHMgaW50byBleHRlcm5hbCBkb2N1bWVudHMsIHVzaW5nIHRvb2xzIGxpa2UgdGhlIGBTd2VhdmUoKWAgZnVuY3Rpb24gb3IgdGhlIGBrbml0cmAgcGFja2FnZS4gT25lIHBhcnRpY3VsYXJseSBjb252ZW5pZW50IHdheSBvZiBkb2luZyB0aGlzIGlzIHRvIGNyZWF0ZSBhbiBSIE1hcmtkb3duIGRvY3VtZW50LCBhbiBhcHByb2FjaCB0aGF0IGZvcm1zIHRoZSBiYXNpcyBmb3IgYW5vdGhlciBjb3Vyc2UuCgpCZWNhdXNlIHBuZyBmaWxlcyBjYW4gYmUgZWFzaWx5IHNoYXJlZCBhbmQgdmlld2VkIGFzIGUtbWFpbCBhdHRhY2htZW50cyBhbmQgaW5jb3Jwb3JhdGVkIGludG8gbWFueSBzbGlkZSBwcmVwYXJhdGlvbiBwYWNrYWdlcyAoZS5nLiBNaWNyb3NvZnQgUG93ZXJwb2ludCksIHRoaXMgZXhlcmNpc2UgYXNrcyB5b3UgdG8gY3JlYXRlIGEgcGxvdCBhbmQgc2F2ZSBpdCBhcyBhIHBuZyBmaWxlLiBUaGUgYmFzaXMgZm9yIHRoaXMgcHJvY2VzcyBpcyB0aGUgYHBuZygpYCBmdW5jdGlvbiwgd2hpY2ggc3BlY2lmaWVzIHRoZSBuYW1lIG9mIHRoZSBwbmcgZmlsZSB0byBiZSBnZW5lcmF0ZWQgYW5kIHNldHMgdXAgYSBzcGVjaWFsIGVudmlyb25tZW50IHRoYXQgY2FwdHVyZXMgYWxsIGdyYXBoaWNhbCBvdXRwdXQgdW50aWwgd2UgZXhpdCB0aGlzIGVudmlyb25tZW50IHdpdGggdGhlIGBkZXYub2ZmKClgIGNvbW1hbmQuCgojIyMgSW5zdHJ1Y3Rpb25zCgotIFVzZSB0aGUgYHBuZygpYCBmdW5jdGlvbiB0byBkaXJlY3QgYWxsIHN1YnNlcXVlbnQgcGxvdCByZXN1bHRzIHRvIHRoZSBleHRlcm5hbCBmaWxlIGBidWJibGVwbG90LnBuZ2AuCi0gUnVuIHRoZSBjb2RlIHRvIHJlLWNyZWF0ZSB0aGUgc2Vjb25kIGJ1YmJsZSBwbG90IGZyb20gdGhlIHByZXZpb3VzIGV4ZXJjaXNlLgotIEV4aXQgdGhlIGBwbmcoKWAgZW52aXJvbm1lbnQgdG8gcmV0dXJuIGdyYXBoaWNzIGNvbnRyb2wgdG8geW91ciBzZXNzaW9uIGJ5IGNhbGxpbmcgYGRldi5vZmYoKWAuCi0gVXNlIHRoZSBgbGlzdC5maWxlcygpYCBjb2RlIHByb3ZpZGVkIHRvIHZlcmlmeSB0aGF0IGBidWJibGVwbG90LnBuZ2Agd2FzIGNyZWF0ZWQuIFRvIGRvIHRoaXMsIHlvdSBuZWVkIHRvIHNwZWNpZnkgYCJwbmciYCBhcyB0aGUgdmFsdWUgdG8gdGhlIHBhdHRlcm4gYXJndW1lbnQgdG8gYGxpc3QuZmlsZXMoKWAuCgpgYGB7cn0KIyBDYWxsIHBuZygpIHdpdGggdGhlIG5hbWUgb2YgdGhlIGZpbGUgd2Ugd2FudCB0byBjcmVhdGUKCgojIFJlLWNyZWF0ZSB0aGUgcGxvdCBmcm9tIHRoZSBsYXN0IGV4ZXJjaXNlCnN5bWJvbHMoQ2FyczkzJEhvcnNlcG93ZXIsIENhcnM5MyRNUEcuY2l0eSwKICAgICAgICBjaXJjbGVzID0gc3FydChDYXJzOTMkUHJpY2UpLAogICAgICAgIGluY2hlcyA9IDAuMSkKCiMgU2F2ZSBvdXIgZmlsZSBhbmQgcmV0dXJuIHRvIG91ciBpbnRlcmFjdGl2ZSBzZXNzaW9uCgoKIyBWZXJpZnkgdGhhdCB3ZSBoYXZlIGNyZWF0ZWQgdGhlIGZpbGUKbGlzdC5maWxlcyhwYXR0ZXJuID0gInBuZyIpCmBgYAoKCiMjIElsaWluc2t5IGFuZCBTdGVlbGUncyAxMiByZWNvbW1lbmRlZCBjb2xvcnMKClRoaXMgZXhlcmNpc2UgYXNrcyB5b3UgdG8gY3JlYXRlIGEgaG9yaXpvbnRhbCBiYXJwbG90IHRoYXQgc2hvd3MgSWxpaW5za3kgYW5kIFN0ZWVsZSdzIHNldCBvZiByZWNvbW1lbmRlZCAxMiBjb2xvcnMsIGluIGRlc2NlbmRpbmcgb3JkZXIgb2YgZGVzaXJhYmlsaXR5IGZyb20gdGhlIHRvcCBvZiB0aGUgcGxvdCB0byB0aGUgYm90dG9tLiBBbHNvLCB0aGUgZmlyc3Qgc2l4ICJtb3JlIHByZWZlcnJlZCIgY29sb3JzIGFyZSBkaXNwbGF5ZWQgd2l0aCBsb25nZXIgYmFycyB0byB2aXN1YWxseSBlbXBoYXNpemUgdGhlaXIgcHJlZmVycmVkIHN0YXR1cyBvdmVyIHRoZSBvdGhlciBzaXguCgpDb2RlIGlzIHByb3ZpZGVkIHRvIGNyZWF0ZSB0aGUgY2hhcmFjdGVyIHZlY3RvciBgSVNjb2xvcnNgIHdpdGggdGhlIG5hbWVzIG9mIHRoZSAxMiBjb2xvcnMgcmVjb21tZW5kZWQgYnkgSWxpaW5za3kgYW5kIFN0ZWVsZSwgaW4gdGhlaXIgcmVjb21tZW5kZWQgb3JkZXIuIFdlJ3ZlIGFsc28gY3JlYXRlZCB0aGUgbnVtZXJpYyB2ZWN0b3IgYGJhcldpZHRoc2AgY29udGFpbmluZyB0aGUgdmFsdWUgMiBmb3IgdGhlIGZpcnN0IHNpeCBJbGlpbnNreSBhbmQgU3RlZWxlIGNvbG9ycyBhbmQgdGhlIHZhbHVlIDEgZm9yIHRoZSBuZXh0IHNpeC4KCkluIHRoaXMgZXhlcmNpc2UsIHlvdSdsbCB1c2UgdGhlIGBiYXJwbG90KClgIGZ1bmN0aW9uIHRvIGNyZWF0ZSB0aGUgaG9yaXpvbnRhbCBiYXJwbG90IHNob3duIGluIHRoZSBmaWd1cmUgYmVsb3csIHdpdGggdGhlIGNvbG9yIG5hbWVzIHRvIHRoZSBsZWZ0IG9mIHRoZSBiYXJzIGFuZCBlYWNoIGJhciBkcmF3biBpbiB0aGUgaW5kaWNhdGVkIGNvbG9yLgoKIVtSZWNvbW1lbmRlZCBwbG90IGNvbG9ycyBieSBJbGlpbnNreSBhbmQgU3RlZWxlLl0oaW1hZ2VzL3Bsb3Rjb2xvcnMucG5nKQoKIyMjIEluc3RydWN0aW9ucwoKLSBOb3RpY2UgaG93IHRoZSBgYmFyV2lkdGhzYCB2ZWN0b3Igb2YgbGVuZ3RoIDEyIGNvbnRhaW5zIHRoZSBsZW5ndGggb2YgZWFjaCBiYXIgc2hvd24uCiAgIC0gVGhlIDYgbG9uZ2VyIGJhcnMgaGF2ZSBhIHZhbHVlIG9mIDIuCiAgIC0gVGhlIDYgc2hvcnRlciBvbmVzIGhhdmUgYSB2YWx1ZSBvZiAxLgotIFJlY3JlYXRlIHRoZSBob3Jpem9udGFsIGJhcnBsb3QgeW91IHNlZSBhYm92ZSwgdXNpbmcgdGhlIGBob3JpemAsIGBjb2xgLCBgYXhlc2AsIGBuYW1lcy5hcmdgLCBhbmQgYGxhc2AgYXJndW1lbnRzIHRvIGBiYXJwbG90KClgLiBOb3RlIHRoYXQgc2luY2UgdGhlIGhvcml6b250YWwgYmFycGxvdCBpcyBjb25zdHJ1Y3RlZCBmcm9tIHRoZSBib3R0b20gdXAsIGl0IGlzIG5lY2Vzc2FyeSB0byByZXZlcnNlIHRoZSBgSVNjb2xvcnNgIGFuZCBgYmFyV2lkdGhzYCB2ZWN0b3JzIGluIHRoZSBgYmFycGxvdCgpYCBmdW5jdGlvbiBjYWxsLCB1c2luZyB0aGUgYHJldigpYCBmdW5jdGlvbi4KCmBgYHtyfQojIElsaWluc2t5IGFuZCBTdGVlbGUgY29sb3IgbmFtZSB2ZWN0b3IKSVNjb2xvcnMgPC0gYygicmVkIiwgImdyZWVuIiwgInllbGxvdyIsICJibHVlIiwKICAgICAgICAgICAgICAiYmxhY2siLCAid2hpdGUiLCAicGluayIsICJjeWFuIiwKICAgICAgICAgICAgICAiZ3JheSIsICJvcmFuZ2UiLCAiYnJvd24iLCAicHVycGxlIikKCiMgQ3JlYXRlIHRoZSBkYXRhIGZvciB0aGUgYmFycGxvdApiYXJXaWR0aHMgPC0gYyhyZXAoMiwgNiksIHJlcCgxLCA2KSkKCiMgUmVjcmVhdGUgdGhlIGhvcml6b250YWwgYmFycGxvdCB3aXRoIGNvbG9yZWQgYmFycwpiYXJwbG90KF9fXywgaG9yaXogPSBfX18sCiAgICAgICAgY29sID0gX19fLCBheGVzID0gX19fLAogICAgICAgIG5hbWVzLmFyZyA9IF9fXywgbGFzID0gMSkKYGBgCgoKIyMgVXNpbmcgY29sb3IgdG8gZW5oYW5jZSBhIGJ1YmJsZXBsb3QKCkluIGEgcHJldmlvdXMgZXhlcmNpc2UsIHlvdSBzYXcgaG93IHRoZSBgc3ltYm9scygpYCBmdW5jdGlvbiBjb3VsZCBiZSB1c2VkIHRvIGdlbmVyYXRlIGEgYnViYmxlcGxvdCBzaG93aW5nIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aHJlZSB2YXJpYWJsZXMgKHNwZWNpZmljYWxseSwgYEhvcnNlcG93ZXJgLCBgTVBHLmNpdHlgLCBhbmQgYFByaWNlYCBmcm9tIHRoZSBgQ2FyczkzYCBkYXRhIGZyYW1lKS4gVGhlcmUsIHRoZSBiYXNpYyBmb3JtYXQgd2FzIGEgc2NhdHRlcnBsb3Qgb2YgYE1QRy5jaXR5YCB2ZXJzdXMgYEhvcnNlcG93ZXJgLCB3aXRoIHBvaW50cyByZXByZXNlbnRlZCBhcyBidWJibGVzLCBzaXplZCBieSBgUHJpY2VgLgoKSGVyZSwgeW91IGFyZSBhc2tlZCB0byBjcmVhdGUgYSB2YXJpYXRpb24gb24gdGhpcyBwbG90LCB1c2luZyB0aGUgZmFjdG9yIHZhcmlhYmxlIGBDeWxpbmRlcnNgIHRvIGRldGVybWluZSBib3RoIHRoZSBzaXplIGFuZCB0aGUgY29sb3Igb2YgdGhlIGJ1YmJsZXMuIFRvIGRvIHRoaXMsIG5vdGUgdGhhdCBgYXMubnVtZXJpYyhDYXJzOTMkQ3lsaW5kZXJzKWAgZ2VuZXJhdGVzIGEgc2VxdWVuY2Ugb2YgbnVtZXJpY2FsIHZhbHVlcyBmcm9tIDEgdG8gNiB0aGF0IHNwZWNpZnkgdGhlIHNpeCB1bmlxdWUgbGV2ZWxzIG9mIHRoZSBgQ3lsaW5kZXJzYCBmYWN0b3IuCgpUaGUgcG9pbnQgb2YgdGhpcyBleGVyY2lzZSBpcyB0byBzaG93IHRoYXQsIGluIGNhc2VzIHdoZXJlIGNvbG9yIGlzIGFuIG9wdGlvbiwgdGhlIGNsYXJpdHkgb2YgdGhpcyBidWJibGVwbG90IGNhbiBiZSBpbXByb3ZlZCBzdWJzdGFudGlhbGx5IHRocm91Z2ggdGhlIHVzZSBvZiBjb2xvciBpbiBhZGRpdGlvbiB0byBzeW1ib2wgc2l6ZS4gU2luY2UgdGhlIGBDeWxpbmRlcnNgIHZhcmlhYmxlIGV4aGliaXRzIHNpeCB1bmlxdWUgdmFsdWVzLCBzaXggY29sb3JzIGFyZSByZXF1aXJlZCB0byBtYWtlIHRoaXMgZW5oYW5jZW1lbnQsIHNvIHRoZSB0b3Agc2l4IGNvbG9ycyByZWNvbW1lbmRlZCBieSBJbGlpbnNreSBhbmQgU3RlZWxlIGFyZSB1c2VkIGhlcmUuCgoKIyMjIEluc3RydWN0aW9ucwoKIVtFeGVyY2lzZSBvYmplY3RpdmUgaXMgdG8gY3JlYXRlIHRoaXMgcGxvdC5dKGltYWdlcy9idWJibGVwbG90LnBuZykKClRoZSBgQ2FyczkzYCBkYXRhIGZyYW1lIGluIHRoZSBgTUFTU2AgcGFja2FnZSBpcyBhdmFpbGFibGUgaW4geW91ciB3b3Jrc3BhY2UsIGFuZCB0aGUgdmVjdG9yIGBJU2NvbG9yc2Agb2YgY29sb3IgbmFtZXMgaXMgY3JlYXRlZCBpbiB0aGUgY29kZSBpbmNsdWRlZCBhdCB0aGUgYmVnaW5uaW5nIG9mIHRoZSBleGVyY2lzZS4KCi0gQ3JlYXRlIHRoZSB2ZWN0b3IgYGN5bGluZGVyTGV2ZWxzYCBnaXZpbmcgbnVtZXJpY2FsIGxhYmVscyB0byB0aGUgdW5pcXVlIHZhbHVlcyBvZiB0aGUgYEN5bGluZGVyc2AgdmFyaWFibGUuCi0gVXNpbmcgdGhlIGBzeW1ib2xzKClgIGZ1bmN0aW9uLCByZWNyZWF0ZSB0aGUgYnViYmxlcGxvdCBvZiBgTVBHLmNpdHlgIHZzLiBgSG9yc2Vwb3dlcmAgc2hvd24gYmVsb3cgd2l0aCB0aGUgYnViYmxlcyBzaXplZCBieSB0aGUgYGN5bGluZGVyTGV2ZWxzYCB2YXJpYWJsZS4KICAgLSBTcGVjaWZ5IGEgbWF4aW11bSBjaXJjbGUgcmFkaXVzIG9mIDAuMiBpbmNoZXMuCiAgIC0gVXNlIHRoZSBgYmdgIHBhcmFtZXRlciB0byBjb2xvciBlYWNoIGJ1YmJsZSBhY2NvcmRpbmcgdG8gdGhlIG51bWVyaWNhbCBsZXZlbCBvZiB0aGUgYEN5bGluZGVyc2AgZmFjdG9yIHZhcmlhYmxlIChpLmUuLCB0aGUgYGN5bGluZGVyTGV2ZWxzYCB2YWx1ZXMpLCB1c2luZyB0aGUgZmlyc3Qgc2l4IHJlY29tbWVuZGVkIGNvbG9ycyBmcm9tIElsaWluc2t5IGFuZCBTdGVlbGUgKGUuZy4gdGhlIGZpcnN0IEN5bGluZGVyIGxldmVsIHNob3VsZCBiZSBjb2xvcmVkICJyZWQiLCB0aGUgc2Vjb25kIGxldmVsIGNvbG9yZWQgImdyZWVuIiwgZXRjLikKCmBgYHtyfQojIElsaWluc2t5IGFuZCBTdGVlbGUgY29sb3IgbmFtZSB2ZWN0b3IKSVNjb2xvcnMgPC0gYygicmVkIiwgImdyZWVuIiwgInllbGxvdyIsICJibHVlIiwKICAgICAgICAgICAgICAiYmxhY2siLCAid2hpdGUiLCAicGluayIsICJjeWFuIiwKICAgICAgICAgICAgICAiZ3JheSIsICJvcmFuZ2UiLCAiYnJvd24iLCAicHVycGxlIikKCiMgQ3JlYXRlIHRoZSBgY3lsaW5kZXJMZXZlbGAgdmFyaWFibGUKCgojIENyZWF0ZSB0aGUgY29sb3JlZCBidWJibGVwbG90CnN5bWJvbHMoX19fLCBfX18sIAogICAgICAgIGNpcmNsZXMgPSBfX18sIGluY2hlcyA9IF9fXywgCiAgICAgICAgYmcgPSBfX19bX19fXSkKYGBgCgoKIyMgVXNpbmcgY29sb3IgdG8gZW5oYW5jZSBzdGFja2VkIGJhcnBsb3RzCgpUaGUgbW9zdCBjb21tb24gYmFycGxvdCBjb25zaXN0cyBvZiBhIGNvbGxlY3Rpb24gb2YgdmVydGljYWwgYmFycywgZWFjaCByZXByZXNlbnRpbmcgc29tZSBjaGFyYWN0ZXJpc3RpYyBvZiBvbmUgb2YgYSBmaW5pdGUgbnVtYmVyIG9mIGRhdGFzZXRzIG9yIGRhdGEgc3Vic2V0cy4gU2V2ZXJhbCBwcmV2aW91cyBleGVyY2lzZXMgaGF2ZSBpbGx1c3RyYXRlZCB0aGUgdXRpbGl0eSBvZiB0aGUgc29tZXdoYXQgbGVzcyBjb21tb24gaG9yaXpvbnRhbCBiYXJwbG90LCB1c2VmdWwgaW4gcGFydCBiZWNhdXNlIGl0IGFsbG93cyB0ZXh0IHRvIGJlIGRpc3BsYXllZCBob3Jpem9udGFsbHkgYWNyb3NzIHRoZSBiYXJzLCBhcyBpbGx1c3RyYXRlZCBpbiBFeGVyY2lzZSAxLgoKQW5vdGhlciB1c2VmdWwgdmFyaWFudCBvZiB0aGUgc3RhbmRhcmQgYmFyIHBsb3QgaXMgdGhlIHN0YWNrZWQgYmFyIHBsb3QsIHdoZXJlIGVhY2ggYmFyIGluIHRoZSBwbG90IGlzIHBhcnRpdGlvbmVkIGludG8gc2VnbWVudHMgY2hhcmFjdGVyaXppbmcgcG9ydGlvbnMgb2YgdGhlIGRhdGEgY2hhcmFjdGVyaXplZCBieSB0aGUgYmFyLiBTdGFja2VkIGJhciBwbG90cyBjYW4gYWxzbyBiZSBnZW5lcmF0ZWQgdXNpbmcgdGhlIGBiYXJwbG90KClgIGZ1bmN0aW9uLiBIZXJlLCBlYWNoIGJhciBpcyBzcGVjaWZpZWQgYnkgYSBtYXRyaXggd2hvc2UgY29sdW1ucyBzcGVjaWZ5IHRoZSBoZWlnaHRzIG9mIHRoZSBzZWdtZW50cyBpbiBlYWNoIGJhci4KCkJ5IGRlZmF1bHQsIHRoZSBgYmFycGxvdCgpYCBmdW5jdGlvbiBnZW5lcmF0ZXMgc3RhY2tlZCBiYXIgcGxvdHMgdXNpbmcgZGlmZmVyZW50IHNoYWRlcyBvZiBncmF5IGZvciB0aGUgZGlmZmVyZW50IHNlZ21lbnRzIG9mIGVhY2ggYmFyIGluIHRoZSBwbG90LiBUaGUgcG9pbnQgb2YgdGhpcyBleGVyY2lzZSBpcyB0byBzaG93IHRoYXQsIGlmIHdlIGNhbiB1c2UgaXQsIGNvbG9yIGNhbiBiZSBhIG1vcmUgZWZmZWN0aXZlIGFsdGVybmF0aXZlLgoKCiMjIyBJbnN0cnVjdGlvbnMKCiFbWW91ciBjb2xvcmVkIHBsb3Qgc2hvdWxkIGxvb2sgbGlrZSB0aGlzLl0oaW1hZ2VzL2JhcnBsb3QucG5nKQoKVGhlIGNoYXJhY3RlciB2ZWN0b3IgYElTY29sb3JzYCBmcm9tIHRoZSBwcmV2aW91cyBleGVyY2lzZXMgaXMgc3RpbGwgYXZhaWxhYmxlIGluIHlvdXIgd29ya3NwYWNlLgoKLSBDcmVhdGUgdGhlIHRhYmxlIGB0YmxgIGdpdmluZyB0aGUgcmVjb3JkIGNvdW50cyBmb3IgZWFjaCBgQ3lsaW5kZXJzYCB2YWx1ZSBhdCBlYWNoIGBPcmlnaW5gIHZhbHVlICh0aGlzIHRhYmxlIHNob3VsZCBoYXZlIDYgcm93cyBhbmQgMiBjb2x1bW5zKS4KLSBVc2luZyB0aGUgYGJhcnBsb3QoKWAgZnVuY3Rpb24sIGNyZWF0ZSBhIHN0YWNrZWQgYmFycGxvdCB0aGF0IHN1bW1hcml6ZXMgdGhpcyBpbmZvcm1hdGlvbiB1c2luZyBzaGFkZXMgb2YgZ3JheS4KLSBSZWNyZWF0ZSB0aGlzIGZpcnN0IHBsb3QsIGJ1dCB1c2luZyB0aGUgZmlyc3Qgc2l4IElsaWluc2t5IGFuZCBTdGVlbGUgY29sb3JzIGZvciB0aGUgc2l4IGBDeWxpbmRlcnNgIGxldmVscy4KCmBgYHtyfQojIENyZWF0ZSBhIHRhYmxlIG9mIEN5bGluZGVycyBieSBPcmlnaW4KCgojIENyZWF0ZSB0aGUgZGVmYXVsdCBzdGFja2VkIGJhcnBsb3QKCgojIEVuaGFuY2UgdGhpcyBwbG90IHdpdGggY29sb3IKCmBgYAoKCiMjIFRoZSB0YWJwbG90IHBhY2thZ2UgYW5kIGdyaWQgZ3JhcGhpY3MKClRoZSBgdGFicGxvdGAgcGFja2FnZSBhbGxvd3MgeW91IHRvIHRhcCBpbnRvIHRoZSBwb3dlciBvZiBncmlkIGdyYXBoaWNzIHdpdGhvdXQgZXhwbGljaXQga25vd2xlZGdlIG9mIGhvdyB0aGUgc3lzdGVtIHdvcmtzIHVuZGVyIHRoZSBob29kLiBUaGUgbWFpbiBmdW5jdGlvbiBpbiBgdGFicGxvdGAgaXMgYHRhYmxlcGxvdCgpYCwgZGV2ZWxvcGVkIHRvIHZpc3VhbGl6ZSBkYXRhIGRpc3RyaWJ1dGlvbnMgYW5kIHJlbGF0aW9uc2hpcHMgYmV0d2VlbiB2YXJpYWJsZXMgaW4gbGFyZ2UgZGF0YXNldHMuCgpTcGVjaWZpY2FsbHksIHRoZSBgdGFibGVwbG90KClgIGZ1bmN0aW9uIGNvbnN0cnVjdHMgYSBzZXQgb2Ygc2lkZS1ieS1zaWRlIGhvcml6b250YWwgYmFycGxvdHMsIG9uZSBmb3IgZWFjaCB2YXJpYWJsZS4gVGhpcyBmdW5jdGlvbiB3b3JrcyBiZXN0IHdoZW4gdmlld2luZyB1cCB0byBhYm91dCAxMCB2YXJpYWJsZXMgYXQgYSB0aW1lLCBmb3IgZGF0YXNldHMgd2l0aCBhcmJpdHJhcmlseSBtYW55IHJlY29yZHMuIEluIHRoaXMgZXhlcmNpc2UsIHlvdSBhcmUgYXNrZWQgdG8gYXBwbHkgdGhpcyBmdW5jdGlvbiB0byBhIGRhdGFzZXQgd2l0aCBqdXN0IHVuZGVyIDY4LDAwMCByZWNvcmRzIGFuZCAxMSB2YXJpYWJsZXMuCgpUaGUgYHRhYmxlcGxvdCgpYCBmdW5jdGlvbiBpcyBjYWxsZWQgd2l0aCBhIGRhdGEgZnJhbWUgYW5kLCBpZiBubyBvcHRpb25hbCBhcmd1bWVudHMgYXJlIHNwZWNpZmllZCwgaXQgc2VsZWN0cyB0aGUgZmlyc3QgZGF0YSBjb2x1bW4gYXMgdGhlIHJlZmVyZW5jZSB2YXJpYWJsZS4gVGhpcyB2YXJpYWJsZSBjYW4gYmUgb2YgYW55IHR5cGUsIGJ1dCB0aGUgZGlzcGxheSBpcyBlYXNpZXN0IHRvIGV4cGxhaW4gd2hlbiBpdCdzIG51bWVyaWMsIGFzIGluIHRoZSBleGFtcGxlIGNvbnNpZGVyZWQgaGVyZS4KCkZvciBmdXJ0aGVyIGRldGFpbHMsIHJlZmVyIHRvIHRoZSB2aWduZXR0ZSAqVmlzdWFsaXphdGlvbiBvZiBsYXJnZSBkYXRhc2V0cyB3aXRoIHRhYnBsb3QqIHRoYXQgYWNjb21wYW5pZXMgdGhlIGhlbHAgZmlsZXMgZm9yIHRoZSBgdGFicGxvdGAgcGFja2FnZS4KCiMjIyBJbnN0cnVjdGlvbnMKCi0gTG9hZCB0aGUgYGluc3VyYW5jZURhdGFgIHBhY2thZ2UuCi0gVXNlIHRoZSBgZGF0YSgpYCBmdW5jdGlvbiB0byBsb2FkIHRoZSBgZGF0YUNhcmAgZGF0YSBmcmFtZS4KLSBMb2FkIHRoZSBgdGFicGxvdGAgcGFja2FnZSB0aGUgbm9ybWFsIHdheSwgYnV0IHN1cnJvdW5kIHlvdXIgY2FsbCB0byBgbGlicmFyeSgpYCB3aXRoIHRoZSBgc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKClgIGZ1bmN0aW9uIHRvIGF2b2lkIGEgYnVuY2ggb2YgdW5uY2Vzc2FyeSBvdXRwdXQgZnJvbSBwcmludGluZyB0byB0aGUgY29uc29sZS4KLSBBcHBseSB0aGUgYHRhYmxlcGxvdCgpYCBmdW5jdGlvbiB0byB0aGUgYGRhdGFDYXJgIGRhdGEgZnJhbWUuCgpgYGB7cn0KIyBMb2FkIHRoZSBpbnN1cmFuY2VEYXRhIHBhY2thZ2UKCgojIFVzZSB0aGUgZGF0YSgpIGZ1bmN0aW9uIHRvIGxvYWQgdGhlIGRhdGFDYXIgZGF0YSBmcmFtZQoKCiMgTG9hZCB0aGUgdGFicGxvdCBwYWNrYWdlCnN1cHByZXNzUGFja2FnZVN0YXJ0dXBNZXNzYWdlcyhfX18pCgojIEdlbmVyYXRlIHRoZSBkZWZhdWx0IHRhYmxlcGxvdCgpIGRpc3BsYXkKCmBgYAoKCiMjIEEgbGF0dGljZSBncmFwaGljcyBleGFtcGxlCgpBbm90aGVyIHBhY2thZ2UgYnVpbHQgb24gZ3JpZCBncmFwaGljcyBpcyBgbGF0dGljZWAsIGJ1dCB1bmxpa2UgYHRhYnBsb3RgLCBgbGF0dGljZWAgaXMgYSBnZW5lcmFsLXB1cnBvc2UgZ3JhcGhpY3MgcGFja2FnZSB0aGF0IHByb3ZpZGVzIGFsdGVybmF0aXZlIGltcGxlbWVudGF0aW9ucyBvZiBtYW55IG9mIHRoZSBwbG90dGluZyBmdW5jdGlvbnMgYXZhaWxhYmxlIGluIGJhc2UgZ3JhcGhpY3MuIFNwZWNpZmljIGV4YW1wbGVzIGluY2x1ZGUgc2NhdHRlcnBsb3RzIHdpdGggdGhlIGB4eXBsb3QoKWAgZnVuY3Rpb24sIGJhciBjaGFydHMgd2l0aCB0aGUgYGJhcmNoYXJ0KClgIGZ1bmN0aW9uLCBhbmQgYm94cGxvdHMgd2l0aCB0aGUgYGJ3cGxvdCgpYCBmdW5jdGlvbi4KCk9uZSBpbXBvcnRhbnQgZGlmZmVyZW5jZSBiZXR3ZWVuIGxhdHRpY2UgZ3JhcGhpY3MgYW5kIGJhc2UgZ3JhcGhpY3MgaXMgdGhhdCBzaW1pbGFyIGZ1bmN0aW9ucyBhdmFpbGFibGUgaW4gYm90aCBncmFwaGljcyBzeXN0ZW1zIG9mdGVuIHByb2R1Y2UgdmVyeSBkaWZmZXJlbnQgcmVzdWx0cyB3aGVuIGFwcGxpZWQgdG8gdGhlIHNhbWUgZGF0YS4gQXMgYSBzcGVjaWZpYyBleGFtcGxlLCB0aGUgYGJ3cGxvdCgpYCBmdW5jdGlvbiBjcmVhdGVzIGhvcml6b250YWwgYm94cGxvdHMsIHdoaWxlIHRoZSBkZWZhdWx0IHJlc3VsdCBvZiB0aGUgYGJveHBsb3QoKWAgaXMgYSB2ZXJ0aWNhbCBib3hwbG90IGRpc3BsYXkuCgpBbm90aGVyIG1vcmUgaW1wb3J0YW50IGRpZmZlcmVuY2UgYmV0d2VlbiBsYXR0aWNlIGFuZCBiYXNlIGdyYXBoaWNzIGlzIHRoYXQgbGF0dGljZSBncmFwaGljcyBzdXBwb3J0cyBjb25kaXRpb25hbCBwbG90cyB0aGF0IHNob3cgdGhlIHNlcGFyYXRlIHJlbGF0aW9uc2hpcHMgYmV0d2VlbiB2YXJpYWJsZXMgd2l0aGluIGRpZmZlcmVudCBncm91cHMuIFRoaXMgY2FwYWJpbGl0eSBpcyBpbGx1c3RyYXRlZCBpbiB0aGlzIGV4ZXJjaXNlLCB3aGVyZSB5b3UgYXJlIGFza2VkIHRvIGNvbnN0cnVjdCBhIHBsb3Qgc2hvd2luZyB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIHZhcmlhYmxlcyBgY2Fsb3JpZXNgIGFuZCBgc3VnYXJzYCBmcm9tIHRoZSBgVVNjZXJlYWxgIGRhdGEgZnJhbWUsIGNvbmRpdGlvbmFsIG9uIHRoZSB2YWx1ZSBvZiB0aGUgYHNoZWxmYCB2YXJpYWJsZS4KCiMjIyBJbnN0cnVjdGlvbnMKCi0gTG9hZCB0aGUgYGxhdHRpY2VgIHBhY2thZ2UgdG8gbWFrZSB0aGUgZnVuY3Rpb24gYHh5cGxvdCgpYCBhdmFpbGFibGUuCi0gVXNpbmcgdGhlIGNvbmRpdGlvbmFsIGZvcm11bGEgZm9ybWF0IGAieSB+IHggfCB6ImAgKHNjYXR0ZXJwbG90IG9mIHkgdnMuIHgsIGNvbmRpdGlvbmVkIG9uIHopLCBjb25zdHJ1Y3QgYSBjb25kaXRpb25hbCBzY2F0dGVycGxvdCBvZiBgY2Fsb3JpZXNgIHZzLiBgc3VnYXJzYCBjb25kaXRpb25hbCBvbiBgc2hlbGZgIGZyb20gdGhlIGBVU2NlcmVhbGAgZGF0YSBmcmFtZSBpbiB0aGUgYE1BU1NgIHBhY2thZ2UuIE1ha2Ugc3VyZSB0byBjb252ZXJ0IGBzaGVsZmAgdG8gYSBmYWN0b3IuCgpgYGB7cn0KIyBMb2FkIHRoZSBsYXR0aWNlIHBhY2thZ2UKCgojIFVzZSB4eXBsb3QoKSB0byBjb25zdHJ1Y3QgdGhlIGNvbmRpdGlvbmFsIHNjYXR0ZXJwbG90CgpgYGAKCgojIyBBIGdncGxvdDIgZ3JhcGhpY3MgZXhhbXBsZQoKVGhpcyBmaW5hbCBleGVyY2lzZSBwcm92aWRlcyBhbiBpbnRyb2R1Y3Rpb24gdG8gdGhlIGBnZ3Bsb3QyYCBncmFwaGljcyBwYWNrYWdlLiBMaWtlIHRoZSBgbGF0dGljZWAgcGFja2FnZSwgdGhlIGBnZ3Bsb3QyYCBwYWNrYWdlIGlzIGFsc28gYmFzZWQgb24gZ3JpZCBncmFwaGljcyBhbmQgaXQgYWxzbyByZXByZXNlbnRzIGEgZ2VuZXJhbCBwdXJwb3NlIGdyYXBoaWNzIHBhY2thZ2UuCgpUaGUgdW5pcXVlIGZlYXR1cmUgb2YgdGhlIGBnZ3Bsb3QyYCBwYWNrYWdlIGlzIHRoYXQgaXQgaXMgYmFzZWQgb24gdGhlICpncmFtbWFyIG9mIGdyYXBoaWNzKiwgYSBzeXN0ZW1hdGljIGFwcHJvYWNoIHRvIGJ1aWxkaW5nIGFuZCBtb2RpZnlpbmcgZ3JhcGhpY2FsIGRpc3BsYXlzLCBzdGFydGluZyB3aXRoIGEgYmFzaWMgZ3JhcGhpY3MgZWxlbWVudCBhbmQgcmVmaW5pbmcgaXQgdGhyb3VnaCB0aGUgYWRkaXRpb24gb2Ygc3VjY2Vzc2l2ZSBtb2RpZmllcnMuCgpUaGlzIGV4ZXJjaXNlIHByb3ZpZGVzIGEgc2ltcGxlIGlsbHVzdHJhdGlvbiBvZiB0aGUgYXBwcm9hY2guIFNwZWNpZmljYWxseSwgeW91IGFyZSBhc2tlZCB0byB1c2UgYGdncGxvdDJgIHRvLCBmaXJzdCwgY3JlYXRlIGEgc2ltcGxlIHNjYXR0ZXJwbG90IG9mIGBNUEcuY2l0eWAgdmVyc3VzIGBIb3JzZXBvd2VyYCBmcm9tIHRoZSBgQ2FyczkzYCBkYXRhIGZyYW1lLiBOZXh0LCB5b3UgYXJlIGFza2VkIHRvIGFkZCBhIHNpbXBsZSBtb2RpZmllciB0aGF0IGFkZHMgY29sb3IgYmFzZWQgb24gdGhlIHZhbHVlIG9mIHRoZSBgQ3lsaW5kZXJzYCB2YXJpYWJsZS4gRmluYWxseSwgeW91IGFyZSBhc2tlZCB0byBjb252ZXJ0IHRoaXMgcmVzdWx0IGludG8gYSBjb2xvcmVkIGJ1YmJsZSBwbG90LCB3aXRoIGJvdGggYnViYmxlIHNpemVzIGFuZCBjb2xvcnMgZGV0ZXJtaW5lZCBieSB0aGUgYEN5bGluZGVyc2AgdmFyaWFibGUuCgpUaGUgcHJpbWFyeSBwdXJwb3NlIG9mIHRoaXMgZXhlcmNpc2UgaXMgdG8gZ2l2ZSB5b3UgYSBmbGF2b3Igb2YgdGhlIGBnZ3Bsb3QyYCBwYWNrYWdlLiAKCiMjIyBJbnN0cnVjdGlvbnMKClRoZSBjaGFyYWN0ZXIgdmVjdG9yIGBJU2NvbG9yc2AgZnJvbSB0aGUgcHJldmlvdXMgZXhlcmNpc2VzIGlzIHN0aWxsIGF2YWlsYWJsZSBpbiB5b3VyIHdvcmtzcGFjZS4KCi0gTG9hZCB0aGUgYGdncGxvdDJgIHBhY2thZ2UuCi0gQ3JlYXRlIGBiYXNlUGxvdGAgYXMgdGhlIGBnZ3Bsb3RgIG9iamVjdCBiYXNlZCBvbiB0aGUgYENhcnM5M2AgZGF0YSBmcmFtZSBmcm9tIHRoZSBgTUFTU2AgcGFja2FnZSBhbmQgdGhlIHNjYXR0ZXJwbG90IGFlc3RoZXRpYyB3aXRoIGB4YCBhcyB0aGUgYEhvcnNlcG93ZXJgIHZhcmlhYmxlIGFuZCBgeWAgYXMgdGhlIGBNUEcuY2l0eWAgdmFyaWFibGUuIFdoZW4gcGFzc2luZyB0aGUgdmFyaWFibGUgbmFtZXMgdG8gYHhgIGFuZCBgeWAsIHRoZXkgc2hvdWxkIGJlIHVucXVvdGVkIChlLmcuIGB4ID0gdmFyX25hbWVgKS4gKE5vdGUgdGhhdCB0aGlzIGRlZmluaXRpb24gZG9lcyBub3QgcmVuZGVyIHRoZSBzY2F0dGVycGxvdC4pCi0gTWFrZSBhIHNpbXBsZSByZW5kZXJpbmcgb2YgYGJhc2VQbG90YCB3aXRoIHRoZSBgZ2VvbV9wb2ludCgpYCBmdW5jdGlvbi4KLSBNYWtlIGEgc2Vjb25kIHJlbmRlcmluZyB1c2luZyB0aGUgYGNvbG9yYCBwYXJhbWV0ZXIgb2YgYGdlb21fcG9pbnQoKWAgdG8gc3BlY2lmeSB0aGUgZmlyc3Qgc2l4IElsaWluc2t5LVN0ZWVsZSBjb2xvcnMgZm9yIHRoZSBzaXggYEN5bGluZGVyc2AgbGV2ZWxzLgotIE1ha2UgYSB0aGlyZCByZW5kZXJpbmcgd2l0aCB0aGUgc2FtZSBjb2xvcmluZyBhcyB0aGUgc2Vjb25kIG9uZSwgYnV0IHdpdGggdGhlIHBvaW50IHNpemVzIGNvcnJlc3BvbmRpbmcgdG8gdGhlIGxldmVscyBvZiB0aGUgYEN5bGluZGVyc2AgZmFjdG9yIHZhcmlhYmxlLgo=