II. Statistical Learning
2.1 What is Statistical Learning?
Input variables also referred to as: predictors, independent variables, features. Typically denoted X
Output variable often called the: response or dependent variable. Typically denoted Y
Assuming there is some relationship between our predictors and response Y = f(X) + E
Where f is some fixed but unknown function of X1, … , Xp
And E is a random error term which is independent of X and has mean zero.
In this formula, f represents the systematic information that X provides about Y.
"In essence, statistical learning refers to a set of approaches for estimating f. In this chapter we outline some of the key theoretical concepts that arise in estimating f, as well as tools for evaluating the estimates obtained.
2.1.1 Why Estimate f?
2 main reasons: prediction and inference
Prediction
We are not typically concerned with the exact form of the predicted funtion of x, rather more that it yields accurate predictions of Y.
The accuracy of the predicted value of Y depends on two quantities: the reducible error and the irreducible error.
The reducible error can potentially be reduced by improving the accuracy of the predicted-fby using the most appropriate statistical learning technique to estimate f.
However, there is always some irreducible error because Y is also a function of E, which, by definition, cannot be predicted using X. Thus, no matter how well we estimate f, we cannot reduce the error introduced by E.
The quantity E may contain unmeasured variables that are useful in predicting Y: since we don’t measure them, f cannot use them for its prediction.
The quantity E may also contain unmeasurable variation.
The focus of this book is on techniques for estimating f with the aim of minimizing the reducible error.
Inference
The goal is to understand the relationship between X and Y via our approximations for f. More specifically, to understand how Y changes as a function of X1, … , Xp.
Now we are interested in the form of the predicted function of f.
We would thus be curious about:
- Which predictors are associated with the response?
- What is the relationship between the response and each predictor?
- Can the relationship between Y and each predictor be adequately summarized using a linear equation, or is the relationship more complicated?
Depending on whether our ultimate goal is prediction, inference, or a combination of the two, different methods for estimating f may be appropriate.
2.1.2 How Do We Estimate f?
Training data is our observed set of n different data points we use to train, or teach, our method how to estimate f.
Parametric Methods
Parametric methods involve a two-step model-based approach.
1.) First, we make an assumption about the functional form, or shape, of f. Assuming f(X) is linear:
- f(X) = B0 + B1X1 + B2X2 + … + BpXp.
2.) After a model has been selected, we need a procedure that uses the training data to fit or train the model. In the case of the linear model, we need to estimate the paramaters B0, B1, … , Bp. That is, we want to find values of these paramaters such that
- Y = B0 + B1X1 + B2X2 + … + BpXp.
Parametric modeling thus reduces the problem of estimating f down to one of estimating a set of parameters.
"Assuming a parametric form for f simplifies the problem of estimating f because it is generally much easier to estimate a set of paramaters, such as B0, B1, … , Bp in the linear model, than it is to fit an entirely arbitrary function f. The potential disadvantage of a parametric approach is that the model we choose will usually not match the true unknown form of f. If the chosen model is too far from the true f, then our estimate will be poor. We can try to address this problem by choosing flexible models that can fit many different possible functional forms for f. But in general, fitting a more flexible model requires estimating a greater number of parameters. These more complex models can lead to a phenomenon known as overfitting the data, which essentially means they follow the errors, or noise, too closely.
Non-Parametric Methods
“Non-parametric methods do not make explicit assumptions about the functional form of f. Insteady they seek an estimate of f that gets as close to the data points as possible without being too rough or wiggly. Such approaches can have a major advantage over parametric approaches: by avoiding the assumption of a particular functional form for f, they have the potential to accurately fit a wider range of possible shapes for f. Any parametric approach brings with it the possibility that the functional form used to estimate f is very different from the true f, in which case the resulting model will not fit the data well. In costrast, non-parametric approaches completely avoid this danger, since essentially no assumption about the form of f is made. But non-parametric approaches do suffer from a major disadvantage: since they do not reduce the problem of estimating f to a small number of parameters, a very large number of observations (far more than is typically needed for a parametric approach) is required in order to obtain an accurate estimate for f.”
Overfitting the data is undesirable because the fit obtained will not yield accurate estimates of the response on new observations that were not part of the original training data set.
2.1.3 The Trade-Off Between Prediction Accuracy and Model Interpretability?
Why would we ever choose to use a more restrictive method instead of a very flexible approach?
-More restrictive models are more interpretable and are thus better for inference problems.
-In settings where the interpretability of the predictive model is not of interest, as in the case of prediction problems, relatively more flexible techniques are more advantageous. However, more flexible methods often run the risk of overfitting
2.1.4 Supervised Versus Unsupervised Learning?
The methods we have already discussed are all examples of Supervised Learning. Essentially, we have inputs and are trying to either predict response value based on our inputs or make some inference as to the likelihood of our output given our inputs.
Unsupervised learning is not concerned with the response yi. “We lack a response variable that can supervise our analysis.” One such example is cluster analysis which seeks to ascentain, on the basis of x1, … , xn, whether the observations fall into relatively distinct groups.
2.1.5 Regression Versus Classification Problems
Quantitative variables take on numerical values.
Qualitative variables take on values in one of K different classes.
Problems with a quantitative response are typically referred to as regression problems.
Problems with a qualitative response are typically referred to as classification problems.
2.2 Assessing Model Accuracy?
Before undertaking any kind of statistical analysis, ask the question, “Which specific method works best for the particular data set”.
2.2.1 Measuring the Quality of Fit
The mean squared error (MSE) quantifies the extent to which the predicted response value for a given observation is close to the true response value for that observation.
“The MSE will be small if the predicted responses are very close to the true responses, and will be large if for some of the observations, the predicted and true responses differ substantially.”
Remember: we are not really interested in how our predicted functional form f(x) fits our response value in the training data. Rather, we are more interested in how our functional form f(x) fits a previously unseen test observation not used to train the statistical learning method.
Thus, we want to select the method with the lowest test MSE.
Degrees of freedom is a quantity that summarizes the flexibility of a curve.
As model flexibility increases, training MSE will decrease, but the test MSE may not.
When a given method yields a small training MSE but a large test MSE, we are said to be overfitting the data. Overfitting refers specifically to the case in which a less flexible model would have yielded a smaller test MSE.
Cross-validation: a method for estimating test MSE using the training data.
2.2.2 The Bias-Variance Trade-Off
The expected test MSE, for a given value of x0 can be decomposed into three fundamental quantities:
- The variance of the predicted functional form of f(x0)
- The squared bias of the predicted functional form of f(x0)
- The variance of the error terms E
Thus, in order to minimize the expected test error, we need to select a statistical learning method that simultaneously achies low variance* and low bias.*
Variance refers to the amount by which the predicted funtional form of f would change if we estimated it using a different training data set.
In general, more flexible statistical methods have higher variance.
Bias refers to the error that is introduced by approximating a real-life problem, which may be extrememly complicated, by a much simpler model.
Generally, more flexible methods result in less bias.
As a general rule, as we use more flexible methods, the variance will increase and the bias will decrease.
The relative rate of change of these two quantities determines whether the test MSE increases or decreases.
As we increase the flexibility of a class of methods, the bias tends to initially decrease faster than the variance increases. Consequently, the expected test MSE declines. However, at some point increasing flexibility has little impact on the bias but starts to significantly increase the variance. When this happens the test MSE increases.
__The relationship between bias, variance, and test set MSE outlined above is referred to as the bias-variance trade-off. The challenge lies in finding a method for which both the variance and the squared bias are low.
2.2.3 The Classification Setting
"The most common approach for quantifying the accuracy of our estimate of the functional form of f is the training error rate, the proportion of mistakes that are made if we apply our estimate of the functional form f* to the training observations.
Essentially, the rate of incorrect classifications.
The Bayes Classifier
The test error rate given is minimized, on average, by a very simple classifier that assigns each observation to the most likely class, given its predictor values.
The Bayes Classifier uses a conditional probability for a 2 class predictor function assigning each observation to class x if its probability of belonging to that class is > .5.
Bayes decision boundary the line representing the points where the boundary is exactly 50%.
K-Nearest Neighbors
Many approaches attempt to estimate the conditional distribution of Y given X, and then classify a given observation to the class with highest estimated probability.
K-nearest neighbors (KNN) is one such method.
Thus, you specify how many “K’s”. With too many, the model is too rigid, with too few it is too flexible.
2.3 Lab: Introduction to R
2.3.1 Basic Commands
1.) Defines a vector 2.) Views it
x = c(1,3,2,5)
x
[1] 1 3 2 5
Defines, lists, shows the lengths and sums the vectors.
x = c(1,6,2)
x
y=c(1,4,3)
y
length(x)
[1] 3
length(y)
[1] 3
x+y
[1] 2 10 5
Lists the vectors
ls()
[1] "x" "y"
Removes the specified vector
rm(x,y)
ls()
character(0)
Removes all vectors in the list at once.
rm(list=ls())
Creates a matrix w/ 3 dimensions: the data, # of rows, and # of columns.Note it fills in the columns first.
x=matrix(data=c(1,2,3,4), nrow=2, ncol=2)
x
[,1] [,2]
[1,] 1 3
[2,] 2 4
Again, creates a matrix, but fills in the rows first.
x=matrix(data=c(1,2,3,4), nrow=2, ncol=2,byrow=T)
x
[,1] [,2]
[1,] 1 2
[2,] 3 4
Returns the square root of each element of a vector or matrix
sqrt(x)
[,1] [,2]
[1,] 1.000000 1.414214
[2,] 1.732051 2.000000
x
[,1] [,2]
[1,] 1 2
[2,] 3 4
x^2
[,1] [,2]
[1,] 1 4
[2,] 9 16
Generates a vector of random normal variables. First argument is n sample size. Then, derives the correlation between the two vectors.
x=rnorm(50)
y=x+rnorm(50,mean=50,sd=.1)
cor(x,y)
[1] 0.9942175
Sets a random vector for use later by defining the previously generated random variables.
set.seed(1303)
rnorm(50)
[1] -1.1439763145 1.3421293656 2.1853904757
[4] 0.5363925179 0.0631929665 0.5022344825
[7] -0.0004167247 0.5658198405 -0.5725226890
[10] -1.1102250073 -0.0486871234 -0.6956562176
[13] 0.8289174803 0.2066528551 -0.2356745091
[16] -0.5563104914 -0.3647543571 0.8623550343
[19] -0.6307715354 0.3136021252 -0.9314953177
[22] 0.8238676185 0.5233707021 0.7069214120
[25] 0.4202043256 -0.2690521547 -1.5103172999
[28] -0.6902124766 -0.1434719524 -1.0135274099
[31] 1.5732737361 0.0127465055 0.8726470499
[34] 0.4220661905 -0.0188157917 2.6157489689
[37] -0.6931401748 -0.2663217810 -0.7206364412
[40] 1.3677342065 0.2640073322 0.6321868074
[43] -1.3306509858 0.0268888182 1.0406363208
[46] 1.3120237985 -0.0300020767 -0.2500257125
[49] 0.0234144857 1.6598706557
Sets the random variables for replicability by defining a vector of 100 random observations (the same as in the book) and then calculating the mean.
set.seed(3)
y=rnorm(100)
mean(y)
[1] 0.01103557
Calculates the variance of y.
var(y)
[1] 0.7328675
Calculates the square root of the variance of y (the standard deviation).
sqrt(var(y))
[1] 0.8560768
A simpler method of calculating the standard deviation of y.
sd(y)
[1] 0.8560768
2.3.2 Graphics
Defines vectors x and y by a series of 100 random normal observations then plots them. Finally, plots them with specific labels on the corresponding axis and a Header.
x=rnorm(100)
y=rnorm(100)
plot(x,y)

plot(x,y,xlab="This is the X axis",ylab="This is the Y axis",main="Plot of X and Y")

__Creates a pdf of the graphic we create. First we specify the type of file we wish to create and name it. Then we create it. Finally we specify that we are done creating it. Saves it in the location of the current working directory.
pdf("Figure.pdf")
plot(x,y,col="green")
dev.off()
null device
1
Creates a sequence of numbers. If you specify two points it creates a vector of numbers between those two points. You can also specify length to give a sequence of equally spaced numbers between the two points by that length.
x=seq(1,10)
x
[1] 1 2 3 4 5 6 7 8 9 10
More sophisticated form
x=seq(-pi,pi,length=50)
x
[1] -3.14159265 -3.01336438 -2.88513611
[4] -2.75690784 -2.62867957 -2.50045130
[7] -2.37222302 -2.24399475 -2.11576648
[10] -1.98753821 -1.85930994 -1.73108167
[13] -1.60285339 -1.47462512 -1.34639685
[16] -1.21816858 -1.08994031 -0.96171204
[19] -0.83348377 -0.70525549 -0.57702722
[22] -0.44879895 -0.32057068 -0.19234241
[25] -0.06411414 0.06411414 0.19234241
[28] 0.32057068 0.44879895 0.57702722
[31] 0.70525549 0.83348377 0.96171204
[34] 1.08994031 1.21816858 1.34639685
[37] 1.47462512 1.60285339 1.73108167
[40] 1.85930994 1.98753821 2.11576648
[43] 2.24399475 2.37222302 2.50045130
[46] 2.62867957 2.75690784 2.88513611
[49] 3.01336438 3.14159265
2.3.3 Indexing Data
Creates a matrix of values between 1 and 16 with 4 rows and 4 columns.
A=matrix(1:16,4,4)
A
[,1] [,2] [,3] [,4]
[1,] 1 5 9 13
[2,] 2 6 10 14
[3,] 3 7 11 15
[4,] 4 8 12 16
Returns the value corresponding to row 2 column 3.
A[2,3]
[1] 10
Selects multiple rows and columns at a time, by providing vectors as the indices.
Returns the values at the intersection of rows 1 and 3 and columns 2 and 4.
A[c(1,3),c(2,4)]
[,1] [,2]
[1,] 5 13
[2,] 7 15
Returns all the values that correspond to the intersection of rows 1 though 3 and columns 2 through 4.
A[1:3,2:4]
[,1] [,2] [,3]
[1,] 5 9 13
[2,] 6 10 14
[3,] 7 11 15
Returns all values in rows 1 and 2.
A[1:2,]
[,1] [,2] [,3] [,4]
[1,] 1 5 9 13
[2,] 2 6 10 14
Returns all values in columns 1 and 2.
A[,1:2]
[,1] [,2]
[1,] 1 5
[2,] 2 6
[3,] 3 7
[4,] 4 8
Returns the vector row 1.
A[1,]
[1] 1 5 9 13
Returns all values except rows 1 and 3.
A[-c(1,3),]
[,1] [,2] [,3] [,4]
[1,] 2 6 10 14
[2,] 4 8 12 16
Returns only the values not in rows 1 and 3 and not in columns 1, 3, and 4. Basically only the values in rows 2 and 4 and column 2 of the previously specified matrix.
A[-c(1,3),-c(1,3,4)]
[1] 6 8
2.3.4 Loading Data
Loads the data from the present working directory named “Auto.data” and defines it in the environment as “Auto”. Note the variables are not currently defined. Fix causes the data to be displayed in a pop out viewer.
Auto=read.table("Auto.data")
fix(Auto)
Reloads the data, but specifies that the values in the first row are the header and that values with a question mark are missing values.
Auto=read.table("Auto.data",header=T,na.string="?")
fix(Auto)
Generates an external viewer of the data and then describes how many rows by how many colums.
fix(Auto)
dim(Auto)
[1] 398 9
Lists the first four rows of data across the nine variables.
Auto[(1:4),]
Removes the rows with missing observations and then gives the new dimensions
Auto=na.omit(Auto)
dim(Auto)
[1] 392 9
Lists the variable names.
names(Auto)
[1] "mpg" "cylinders" "displacement"
[4] "horsepower" "weight" "acceleration"
[7] "year" "origin" "name"
2.3.5 Additional Graphical and Numerical Summaries
plot(cylinders,mpg)
Error in plot(cylinders, mpg) : object 'cylinders' not found
__Note:__ cannot plot because the variables are not yet properly defined. Thus, R has no idea what cylinder* or mpg are.
__By joining the data frame with the variable via a dollar sign R knows that cylinders and mpg are variables linked to that data table.
plot(Auto$cylinders,Auto$mpg)

__However, by “attaching” Auto, we can tell R that the values in the header are linked to that data table and are our inputs.
attach(Auto)
plot(cylinders,mpg)

Converts quantitative data into qualitative. Converts cylinders which was previously quantiative with only 6 possible values into a variable with 5 factors. It is 5 factors because as you note from the plot above; there are no corresponding values for “7”.
cylinders=as.factor(cylinders)
Now that the data is categorical, it generates a boxplot. Here are a few boxplots with different options.
plot(cylinders,mpg)

plot(cylinders,mpg,xlab="Cylinders",ylab="mpg",main="Mileage by # of Cylinders",col="red")

plot(cylinders,mpg,xlab="Cylinders",ylab="mpg",main="Mileage by # of Cylinders",col="red",varwidth=T)

Creates a histogram of the data. Here are a few with different options.
hist(mpg)

hist(mpg,col=2)

hist(mpg,col=2,breaks=15)

Creates a scatterplot matrix. The second also creates a scatterplot matrix, but only for the five variables we specified.
pairs(Auto)

pairs(~mpg+displacement+horsepower+weight+acceleration,Auto)

Plots the data and then enables a click tool in the plots console which prints the values of points you select. Note does not work in R notebook, only in the console.
plot(horsepower,mpg)
identify(horsepower,mpg,name)
integer(0)

Produces a numerical summary of each variable in a particular data set.
summary(Auto)
mpg cylinders
Min. : 9.00 Min. :3.000
1st Qu.:17.00 1st Qu.:4.000
Median :22.75 Median :4.000
Mean :23.45 Mean :5.472
3rd Qu.:29.00 3rd Qu.:8.000
Max. :46.60 Max. :8.000
displacement horsepower weight
Min. : 68.0 Min. : 46.0 Min. :1613
1st Qu.:105.0 1st Qu.: 75.0 1st Qu.:2225
Median :151.0 Median : 93.5 Median :2804
Mean :194.4 Mean :104.5 Mean :2978
3rd Qu.:275.8 3rd Qu.:126.0 3rd Qu.:3615
Max. :455.0 Max. :230.0 Max. :5140
acceleration year
Min. : 8.00 Min. :70.00
1st Qu.:13.78 1st Qu.:73.00
Median :15.50 Median :76.00
Mean :15.54 Mean :75.98
3rd Qu.:17.02 3rd Qu.:79.00
Max. :24.80 Max. :82.00
origin name
Min. :1.000 amc matador : 5
1st Qu.:1.000 ford pinto : 5
Median :1.000 toyota corolla : 5
Mean :1.577 amc gremlin : 4
3rd Qu.:2.000 amc hornet : 4
Max. :3.000 chevrolet chevette: 4
(Other) :365
2.4 Exercises
Conceptual
- For each of parts (a) through (d), indicate whether we would generally expect the performance of a flexible statistical learning method to be better or worse than an inflexible method. Justify your answer.
- The sample size n is extremely large, and the number of predictors p is small. If we have few predictors then our bias is likely to be larger. Also, given the large sample size, a more flexible method would likely reduce the bias and thus fit the data better.
- The number of predictors p is extremely large, and the number of observations n is small. Likely worse. With a large number of predictors we run the risk of overfitting the data. By increasing the flexibility, we only exacerbate this risk by approximating that may too closely fit the training data, but not necessarily work in practice.
- The relationship between the predictors and response is highly non-linear. Better. If the data is highly non-linear that it is fairly obvious that an inflexible model will not capture the function form of f very well at all.
- The variance of the error terms, i.e. σ2 = Var(E), is extremely high. Worse. Again, we run the risk of overfitting if we fit a model that is too flexible and functionally mirrors the residuals.
- Explain whether each scenario is a classification or regression problem, and indicate whether we are most interested in inference or prediction. Finally, provide n and p.
+(a) We collect a set of data on the top 500 firms in the US. For each firm we record profit, number of employees, industry and the CEO salary. We are interested in understanding which factors affect CEO salary. Regression-Inference. n=500 p=4
+(b) We are considering launching a new product and wish to know whether it will be a success or a failure. We collect data on 20 similar products that were previously launched. For each product we have recorded whether it was a success or failure, price charged for the product, marketing budget, competition price, and ten other variables. Classification-prediction. n=20 p=14
+(c) We are interested in predicting the % change in the USD/Euro exchange rate in relation to the weekly changes in the world stock markets. Hence we collect weekly data for all of 2012. For each week we record the % change in the USD/Euro, the % change in the US market, the % change in the British market, and the % change in the German market. Regression-Inference. n=52 p=3
- We now revisit the bias-variance decomposition.
+(a) Provide a sketch of typical (squared) bias, variance, training error, test error, and Bayes (or irreducible) error curves, on a single plot, as we go from less flexible statistical learning methods towards more flexible approaches. The x-axis should represent the amount of flexibility in the method, and the y-axis should represent the values for each curve. There should be five curves. Make sure to label each one. __See attached jpeg.
+(b) Explain why each of the five curves has the shape displayed in part (a).
As we approximate a more flexible model, at first the bias decreases at a rate greater than the variance is increasing. However, eventually as we add flexibility past the optimal functional form the variance increases at a rate greater than the bias is decreasing. At this point, although our training MSE may be decreasing we are beginning to overfit the data. Thus, it is unlikely that our training set will fit our test set very well and past the optimal level of flexibility for our particular data and question our training MSE and test MSE deviate; the former decreasing and the latter increasing. The irreducible error is fundamentally unknowable and is just represented by a horizontal line independent of the other factors, but always below our test MSE because the test MSE contains the irreducible error.
Skipped
What are the advantages and disadvantages of a very flexible (versus a less flexible) approach for regression or classification? Under what circumstances might a more flexible approach be preferred to a less flexible approach? When might a less flexible approach be preferred?
Advantages: better fits the values if the true functional form of the data is not linear and reduces the bias of our estimated parameters.
Disadvantages: if the data is linear, then a more flexible approach runs the risk of overfitting the data. It also requires more parameters and increases the variance.
If the data is non-linear a more flexible approach is preferred. If the tradeoff is one such that a more flexible model leads to a significant reduction in the bias and only a small increase in the variance; a more flexible approach is preferable.
if the data is very linear, a more rigid approach is preffered. If the tradeoff is one such that a less flexible model only increases the bias slightly, but greatly reduces the variance; a less flexible approach is preferable.
A more flexible approach is preferred when we more interested in power of prediction as opposed to interpretability the results.
A less flexible approach would be preferred if we were more interested in interpreting the paramaters as opposed to simply predicting a response.
6.) Describe the differences between a parametric and a non-parametric statistical learning approach. What are the advantages of a parametric approach to regression or classification (as opposed to a non-parametric approach)? What are its disadvantages?
A parametric approach assumes a functional form of f and thus reduces regression and classification problems down to approximating a set of parameters and then interpreting the results or predicting a response. It requires fewer observations than do non-parametric approaches.
A non-parametric approach does not make any assumption about the functional form of f. Rather it requires a large n to accurately estimate the functional form of f.
Advantages of parametric approach to regression or classification: does not require as great an n and can be estimated with relatively fewer parameters.
Disadvantages of parametric approach to regression or classification: run the risk of approximating a functional form of f that is far from the true f. Also, run the risk of overfitting the model via the use of more flexible models when not appropriate.
7.) Skipped
__*Applied__
8.) This exercise relates to the College data set, which can be found in the file College.csv. It contains a number of variables for 777 different universities and colleges in the US.
Load the data
College=read.csv("College.csv",header=T)
Add a new column for all rows in column one. View the data
rownames(College)=College[,1]
fix(College)
Eliminates the first column in the data where the names are stored. Note the actual row of college names is not a stored data colum.
College=College[,-1]
fix(College)
Summarize the data. Note the college names are not stored as a data column.
summary(College)
X Private
Abilene Christian University: 1 No :212
Adelphi University : 1 Yes:565
Adrian College : 1
Agnes Scott College : 1
Alaska Pacific University : 1
Albertson College : 1
(Other) :771
Apps Accept Enroll
Min. : 81 Min. : 72 Min. : 35
1st Qu.: 776 1st Qu.: 604 1st Qu.: 242
Median : 1558 Median : 1110 Median : 434
Mean : 3002 Mean : 2019 Mean : 780
3rd Qu.: 3624 3rd Qu.: 2424 3rd Qu.: 902
Max. :48094 Max. :26330 Max. :6392
Top10perc Top25perc
Min. : 1.00 Min. : 9.0
1st Qu.:15.00 1st Qu.: 41.0
Median :23.00 Median : 54.0
Mean :27.56 Mean : 55.8
3rd Qu.:35.00 3rd Qu.: 69.0
Max. :96.00 Max. :100.0
F.Undergrad P.Undergrad
Min. : 139 Min. : 1.0
1st Qu.: 992 1st Qu.: 95.0
Median : 1707 Median : 353.0
Mean : 3700 Mean : 855.3
3rd Qu.: 4005 3rd Qu.: 967.0
Max. :31643 Max. :21836.0
Outstate Room.Board
Min. : 2340 Min. :1780
1st Qu.: 7320 1st Qu.:3597
Median : 9990 Median :4200
Mean :10441 Mean :4358
3rd Qu.:12925 3rd Qu.:5050
Max. :21700 Max. :8124
Books Personal
Min. : 96.0 Min. : 250
1st Qu.: 470.0 1st Qu.: 850
Median : 500.0 Median :1200
Mean : 549.4 Mean :1341
3rd Qu.: 600.0 3rd Qu.:1700
Max. :2340.0 Max. :6800
PhD Terminal
Min. : 8.00 Min. : 24.0
1st Qu.: 62.00 1st Qu.: 71.0
Median : 75.00 Median : 82.0
Mean : 72.66 Mean : 79.7
3rd Qu.: 85.00 3rd Qu.: 92.0
Max. :103.00 Max. :100.0
S.F.Ratio perc.alumni
Min. : 2.50 Min. : 0.00
1st Qu.:11.50 1st Qu.:13.00
Median :13.60 Median :21.00
Mean :14.09 Mean :22.74
3rd Qu.:16.50 3rd Qu.:31.00
Max. :39.80 Max. :64.00
Expend Grad.Rate
Min. : 3186 Min. : 10.00
1st Qu.: 6751 1st Qu.: 53.00
Median : 8377 Median : 65.00
Mean : 9660 Mean : 65.46
3rd Qu.:10830 3rd Qu.: 78.00
Max. :56233 Max. :118.00
Create a scatterplot of the first ten variables of the data.
pairs(College[,1:10])

Plot Outstate vs. Private
plot(College$Outstate,col="green")

plot(College$Private,col="red")

Create a new qualitative variable “Elite”
Elite=rep("No",nrow(College))
Elite[College$Top10perc >50]="Yes"
Elite=as.factor(Elite)
College=data.frame(College,Elite)
Summary of how many Elite vs non-elite colleges
summary(Elite)
No Yes
699 78
Boxplots of Elite vs Outstate tuition
plot(College$Elite,College$Outstate)

Histograms of different quantiative variables with different bins
par(mfrow=c(2,2))
hist(College$Apps,col="red",breaks=7)
hist(College$Accept,col="green",breaks=4)
hist(College$Enroll,col="orange",breaks=5)

9. This exercise involves the Auto data set studied in the lab. Make sure that the missing values have been removed from the data.
Import the data, specify headers in the top row and define missing variables as “NA”.
Auto=read.table("Auto.data",header=T,na.strings="?")
Auto=na.omit(Auto)
dim(Auto)
[1] 392 9
summary(Auto)
mpg cylinders displacement horsepower weight acceleration year
Min. : 9.00 Min. :3.000 Min. : 68.0 Min. : 46.0 Min. :1613 Min. : 8.00 Min. :70.00
1st Qu.:17.00 1st Qu.:4.000 1st Qu.:105.0 1st Qu.: 75.0 1st Qu.:2225 1st Qu.:13.78 1st Qu.:73.00
Median :22.75 Median :4.000 Median :151.0 Median : 93.5 Median :2804 Median :15.50 Median :76.00
Mean :23.45 Mean :5.472 Mean :194.4 Mean :104.5 Mean :2978 Mean :15.54 Mean :75.98
3rd Qu.:29.00 3rd Qu.:8.000 3rd Qu.:275.8 3rd Qu.:126.0 3rd Qu.:3615 3rd Qu.:17.02 3rd Qu.:79.00
Max. :46.60 Max. :8.000 Max. :455.0 Max. :230.0 Max. :5140 Max. :24.80 Max. :82.00
origin name
Min. :1.000 amc matador : 5
1st Qu.:1.000 ford pinto : 5
Median :1.000 toyota corolla : 5
Mean :1.577 amc gremlin : 4
3rd Qu.:2.000 amc hornet : 4
Max. :3.000 chevrolet chevette: 4
(Other) :365
Quantitative: mpg, displacement, horsepower, weight, acceleration and year
Qualitative: cylinders and origin
Range of quantitative variables
Range=apply(Auto[,-c(2,8,9)],2,range)
row.names(Range)=c("Min","Max")
Range
mpg displacement horsepower weight
Min 9.0 68 46 1613
Max 46.6 455 230 5140
acceleration year
Min 8.0 70
Max 24.8 82
rm(Range)
Mean and Standard Deviation of Quantiative Variables
SD_Mean=apply(Auto[,-c(2,8,9)],2,function(x){c(mean(x),sd(x))})
row.names(SD_Mean)=c("Mean","Standard Deviation")
SD_Mean
mpg displacement
Mean 23.445918 194.412
Standard Deviation 7.805007 104.644
horsepower weight
Mean 104.46939 2977.5842
Standard Deviation 38.49116 849.4026
acceleration year
Mean 15.541327 75.979592
Standard Deviation 2.758864 3.683737
rm(SD)
Range excluding rows 10-65
Range2=apply(Auto[-c(10:85),-c(2,8,9)],2,range)
row.names(Range2)=c("Min","Max")
Range2
mpg displacement horsepower weight
Min 11.0 68 46 1649
Max 46.6 455 230 4997
acceleration year
Min 8.5 70
Max 24.8 82
_Mean excluding rows 10-85__
Mean2=apply(Auto[-c(10:85),-c(2,8,9)],2,mean)
Mean2
mpg displacement horsepower
24.40443 187.24051 100.72152
weight acceleration year
2935.97152 15.72690 77.14557
Standard Deviation excluding rows 10-85
SD2=apply(Auto[-c(10:85),-c(2,8,9)],2,sd)
SD2
mpg displacement horsepower
7.867283 99.678367 35.708853
weight acceleration year
811.300208 2.693721 3.106217
Now joining mean and SD
MEAN_SD2=apply(Auto[-c(10:85),-c(2,8,9)],2,function(x){c(mean(x),sd(x))})
row.names(MEAN_SD2)=c("Mean","Standard_Deviation")
MEAN_SD2
mpg displacement
Mean 24.404430 187.24051
Standard_Deviation 7.867283 99.67837
horsepower weight
Mean 100.72152 2935.9715
Standard_Deviation 35.70885 811.3002
acceleration year
Mean 15.726899 77.145570
Standard_Deviation 2.693721 3.106217
Graphical depictions of the data
boxplot(Auto$mpg~Auto$cylinders,col="red",xlab="Cylinders",ylab="MPG",main="MPG by # of Cylinders")

scatter.smooth(Auto$year,Auto$mpg,col="green",xlab="Year",ylab="MPG",main="Mpg by Year")

pairs(Auto)

boxplot(Auto$mpg~Auto$origin,col="grey",xlab="Country of Origin",ylab="MPG",main="MPG by Country of Origin",names=c("American","European","Japanese"))

10. This exercise involves the Boston housing data set.
library(MASS)
Boston
?Boston
dim(Boston)
[1] 506 14
fix(Boston)
Finding indicate that predominantly African American towns have lower crime rates.
par(mfrow=c(2,2))
scatter.smooth(Boston$ptratio,Boston$lstat,xlab="Pupil-to-teacher Ratio",ylab="% of Lower Class Pop",main="PT Ratio by % of Lower Status",col="blue")
boxplot(Boston$medv~Boston$rad,col="green",xlab="Index of Accessibility to Radial Highways",ylab="Median Home Value",main="Median Home Value")
scatter.smooth(Boston$crim,Boston$black,col="red",xlab="Crime Rate",ylab="Proportion of Blacks by Town",main="Crime Rate by Proportion of Blacks")
Also, it seems that areas with higher percentages of the population classified as “lower status” also have higher pupil-to-teacher ratios. This means that teachers in more “impoverished” areas are having to do more.
I am not sure what the index of accessibility to radial highways is, but it seems clear that in the case of “24” it is linked to lower median home values. However, the dispersion of values is of some note.
plot(Boston$crim)
identify(Boston$crim)
warning: nearest point already identified
warning: nearest point already identified
[1] 375 376 379 380 381 385 387 388 399 401 404 405 406 407 411 413 414 415 416 418 419 426 428 441
The above values are all town codes that have extremely high crime rates.
selection = Boston[,"chas"]
nrow(Boston[selection,])
[1] 35
median(Boston$ptratio)
[1] 19.05
plot(Boston$medv)
identify(Boston$medv)
integer(0)

print(Boston[399,])
Range3=apply(Boston[,],2,range)
row.names(Range3)=c("Min","Max")
Range3
crim zn indus chas nox rm age
Min 0.00632 0 0.46 0 0.385 3.561 2.9
Max 88.97620 100 27.74 1 0.871 8.780 100.0
dis rad tax ptratio black lstat medv
Min 1.1296 1 187 12.6 0.32 1.73 5
Max 12.1265 24 711 22.0 396.90 37.97 50
summary(Boston$MoreThanSeven)
No Yes
442 64
summary(Boston$morethaneight)
No Yes
493 13
LS0tDQp0aXRsZTogIlIgTm90ZWJvb2sgLSBDaGFwdGVyIDI6IFN0YXRpc3RpY2FsIExlYXJuaW5nIg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KIyBfX0lJLiBTdGF0aXN0aWNhbCBMZWFybmluZ19fDQoNCiMjIF9fMi4xIFdoYXQgaXMgU3RhdGlzdGljYWwgTGVhcm5pbmc/X18NCg0KX19JbnB1dCB2YXJpYWJsZXNfXyBhbHNvIHJlZmVycmVkIHRvIGFzOiAqcHJlZGljdG9ycywgaW5kZXBlbmRlbnQgdmFyaWFibGVzLCBmZWF0dXJlcyouIFR5cGljYWxseSBkZW5vdGVkIF9fWF9fDQoNCl9fT3V0cHV0IHZhcmlhYmxlX18gb2Z0ZW4gY2FsbGVkIHRoZTogKnJlc3BvbnNlKiBvciAqZGVwZW5kZW50IHZhcmlhYmxlKi4gVHlwaWNhbGx5IGRlbm90ZWQgX19ZX18NCg0KQXNzdW1pbmcgdGhlcmUgaXMgc29tZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBvdXIgcHJlZGljdG9ycyBhbmQgcmVzcG9uc2UNCl9fWSA9ICpmKihYKSArICpFKl9fDQoNCldoZXJlICpmKiBpcyBzb21lIGZpeGVkIGJ1dCB1bmtub3duIGZ1bmN0aW9uIG9mIFh+MX4sIC4uLiAsIFh+cH4NCg0KQW5kICpFKiBpcyBhIHJhbmRvbSAqZXJyb3IgdGVybSogd2hpY2ggaXMgaW5kZXBlbmRlbnQgb2YgWCBhbmQgaGFzIG1lYW4gemVyby4NCg0KSW4gdGhpcyBmb3JtdWxhLCAqZiogcmVwcmVzZW50cyB0aGUgKnN5c3RlbWF0aWMqIGluZm9ybWF0aW9uIHRoYXQgWCBwcm92aWRlcyBhYm91dCBZLg0KDQoiSW4gZXNzZW5jZSwgc3RhdGlzdGljYWwgbGVhcm5pbmcgcmVmZXJzIHRvIGEgc2V0IG9mIGFwcHJvYWNoZXMgZm9yIGVzdGltYXRpbmcgKmYqLiBJbiB0aGlzIGNoYXB0ZXIgd2Ugb3V0bGluZSBzb21lIG9mIHRoZSBrZXkgdGhlb3JldGljYWwgY29uY2VwdHMgdGhhdCBhcmlzZSBpbiBlc3RpbWF0aW5nICpmKiwgYXMgd2VsbCBhcyB0b29scyBmb3IgZXZhbHVhdGluZyB0aGUgZXN0aW1hdGVzIG9idGFpbmVkLg0KDQojIyMgX18qMi4xLjEgV2h5IEVzdGltYXRlIGY/Kl9fDQoNCjIgbWFpbiByZWFzb25zOiBfXypwcmVkaWN0aW9uKl9fIGFuZCBfXyppbmZlcmVuY2UqX18NCg0KX19QcmVkaWN0aW9uX18NCg0KV2UgYXJlIG5vdCB0eXBpY2FsbHkgY29uY2VybmVkIHdpdGggdGhlIGV4YWN0IGZvcm0gb2YgdGhlIHByZWRpY3RlZCBmdW50aW9uIG9mIHgsIHJhdGhlciBtb3JlIHRoYXQgaXQgeWllbGRzIGFjY3VyYXRlIHByZWRpY3Rpb25zIG9mIFkuDQoNClRoZSBhY2N1cmFjeSBvZiB0aGUgcHJlZGljdGVkIHZhbHVlIG9mIFkgZGVwZW5kcyBvbiB0d28gcXVhbnRpdGllczogdGhlIF9fKnJlZHVjaWJsZSBlcnJvcipfXyBhbmQgdGhlIF9fKmlycmVkdWNpYmxlIGVycm9yKl9fLg0KDQpUaGUgX18qcmVkdWNpYmxlIGVycm9yKl9fIGNhbiBwb3RlbnRpYWxseSBiZSByZWR1Y2VkIGJ5IGltcHJvdmluZyB0aGUgYWNjdXJhY3kgb2YgdGhlIHByZWRpY3RlZC0qZipieSB1c2luZyB0aGUgbW9zdCBhcHByb3ByaWF0ZSBzdGF0aXN0aWNhbCBsZWFybmluZyB0ZWNobmlxdWUgdG8gZXN0aW1hdGUgKmYqLg0KDQpIb3dldmVyLCB0aGVyZSBpcyBhbHdheXMgc29tZSBfXyppcnJlZHVjaWJsZSBlcnJvcipfXyBiZWNhdXNlIFkgaXMgYWxzbyBhIGZ1bmN0aW9uIG9mICpFKiwgd2hpY2gsIGJ5IGRlZmluaXRpb24sIGNhbm5vdCBiZSBwcmVkaWN0ZWQgdXNpbmcgWC4gVGh1cywgbm8gbWF0dGVyIGhvdyB3ZWxsIHdlIGVzdGltYXRlICpmKiwgd2UgY2Fubm90IHJlZHVjZSB0aGUgZXJyb3IgaW50cm9kdWNlZCBieSAqRSouDQoNClRoZSBxdWFudGl0eSAqRSogbWF5IGNvbnRhaW4gdW5tZWFzdXJlZCB2YXJpYWJsZXMgdGhhdCBhcmUgdXNlZnVsIGluIHByZWRpY3RpbmcgWTogc2luY2Ugd2UgZG9uJ3QgbWVhc3VyZSB0aGVtLCAqZiogY2Fubm90IHVzZSB0aGVtIGZvciBpdHMgcHJlZGljdGlvbi4NCg0KVGhlIHF1YW50aXR5ICpFKiBtYXkgYWxzbyBjb250YWluIHVubWVhc3VyYWJsZSB2YXJpYXRpb24uDQoNClRoZSBmb2N1cyBvZiB0aGlzIGJvb2sgaXMgb24gdGVjaG5pcXVlcyBmb3IgZXN0aW1hdGluZyAqZiogd2l0aCB0aGUgYWltIG9mIG1pbmltaXppbmcgdGhlIHJlZHVjaWJsZSBlcnJvci4NCg0KX19JbmZlcmVuY2VfXw0KDQpUaGUgZ29hbCBpcyB0byB1bmRlcnN0YW5kIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBYIGFuZCBZIHZpYSBvdXIgYXBwcm94aW1hdGlvbnMgZm9yICpmKi4gTW9yZSBzcGVjaWZpY2FsbHksIHRvIHVuZGVyc3RhbmQgaG93IFkgY2hhbmdlcyBhcyBhIGZ1bmN0aW9uIG9mIFh+MX4sIC4uLiAsIFh+cH4uDQoNCk5vdyB3ZSBhcmUgaW50ZXJlc3RlZCBpbiB0aGUgZm9ybSBvZiB0aGUgcHJlZGljdGVkIGZ1bmN0aW9uIG9mICpmKi4NCg0KV2Ugd291bGQgdGh1cyBiZSBjdXJpb3VzIGFib3V0Og0KDQoxLiAqV2hpY2ggcHJlZGljdG9ycyBhcmUgYXNzb2NpYXRlZCB3aXRoIHRoZSByZXNwb25zZT8qDQoyLiAqV2hhdCBpcyB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIHJlc3BvbnNlIGFuZCBlYWNoIHByZWRpY3Rvcj8qDQozLiAqQ2FuIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBZIGFuZCBlYWNoIHByZWRpY3RvciBiZSBhZGVxdWF0ZWx5IHN1bW1hcml6ZWQgdXNpbmcgYSBsaW5lYXIgZXF1YXRpb24sIG9yIGlzIHRoZSByZWxhdGlvbnNoaXAgbW9yZSBjb21wbGljYXRlZD8qDQoNCl9fRGVwZW5kaW5nIG9uIHdoZXRoZXIgb3VyIHVsdGltYXRlIGdvYWwgaXMgcHJlZGljdGlvbiwgaW5mZXJlbmNlLCBvciBhIGNvbWJpbmF0aW9uIG9mIHRoZSB0d28sIGRpZmZlcmVudCBtZXRob2RzIGZvciBlc3RpbWF0aW5nICpmKiBtYXkgYmUgYXBwcm9wcmlhdGUuX18NCg0KIyMgX18yLjEuMiBIb3cgRG8gV2UgRXN0aW1hdGUgZj9fXw0KDQpfXypUcmFpbmluZyBkYXRhKl9fIGlzIG91ciBvYnNlcnZlZCBzZXQgb2YgKm4qIGRpZmZlcmVudCBkYXRhIHBvaW50cyB3ZSB1c2UgdG8gdHJhaW4sIG9yIHRlYWNoLCBvdXIgbWV0aG9kIGhvdyB0byBlc3RpbWF0ZSAqZiouDQoNCiMjIyMgX19QYXJhbWV0cmljIE1ldGhvZHNfXw0KDQpQYXJhbWV0cmljIG1ldGhvZHMgaW52b2x2ZSBhIHR3by1zdGVwIG1vZGVsLWJhc2VkIGFwcHJvYWNoLg0KDQoxLikgRmlyc3QsIHdlIG1ha2UgYW4gYXNzdW1wdGlvbiBhYm91dCB0aGUgZnVuY3Rpb25hbCBmb3JtLCBvciBzaGFwZSwgb2YgKmYqLiBfX0Fzc3VtaW5nICpmKihYKSBpcyBsaW5lYXI6X18NCg0KKyAqZiooWCkgPSAqQip+MH4gKyAqQip+MX5YfjF+ICsgKkIqfjJ+WH4yfiArIC4uLiArICpCKn5wflh+cH4uDQoNCjIuKSBBZnRlciBhIG1vZGVsIGhhcyBiZWVuIHNlbGVjdGVkLCB3ZSBuZWVkIGEgcHJvY2VkdXJlIHRoYXQgdXNlcyB0aGUgdHJhaW5pbmcgZGF0YSB0byAqZml0KiBvciAqdHJhaW4qIHRoZSBtb2RlbC4gSW4gdGhlIGNhc2Ugb2YgdGhlIGxpbmVhciBtb2RlbCwgd2UgbmVlZCB0byBlc3RpbWF0ZSB0aGUgcGFyYW1hdGVycyAqQip+MH4sICpCKn4xfiwgLi4uICwgKkIqfnB+Lg0KVGhhdCBpcywgd2Ugd2FudCB0byBmaW5kIHZhbHVlcyBvZiB0aGVzZSBwYXJhbWF0ZXJzIHN1Y2ggdGhhdA0KDQorIFkgPSAqQip+MH4gKyAqQip+MX5YfjF+ICsgKkIqfjJ+WH4yfiArIC4uLiArICpCKn5wflh+cH4uDQoNCl9fKlBhcmFtZXRyaWMgbW9kZWxpbmcqX18gdGh1cyByZWR1Y2VzIHRoZSBwcm9ibGVtIG9mIGVzdGltYXRpbmcgKmYqIGRvd24gdG8gb25lIG9mIGVzdGltYXRpbmcgYSBzZXQgb2YgcGFyYW1ldGVycy4NCg0KPiAiQXNzdW1pbmcgYSBwYXJhbWV0cmljIGZvcm0gZm9yICpmKiBzaW1wbGlmaWVzIHRoZSBwcm9ibGVtIG9mIGVzdGltYXRpbmcgKmYqIGJlY2F1c2UgaXQgaXMgZ2VuZXJhbGx5IG11Y2ggZWFzaWVyIHRvIGVzdGltYXRlIGEgc2V0IG9mIHBhcmFtYXRlcnMsIHN1Y2ggYXMgKkIqfjB+LCAqQip+MX4sIC4uLiAsICpCKn5wfiBpbiB0aGUgbGluZWFyIG1vZGVsLCB0aGFuIGl0IGlzIHRvIGZpdCBhbiBlbnRpcmVseSBhcmJpdHJhcnkgZnVuY3Rpb24gKmYqLiBfX1RoZSBwb3RlbnRpYWwgZGlzYWR2YW50YWdlIG9mIGEgcGFyYW1ldHJpYyBhcHByb2FjaCBpcyB0aGF0IHRoZSBtb2RlbCB3ZSBjaG9vc2Ugd2lsbCB1c3VhbGx5IG5vdCBtYXRjaCB0aGUgdHJ1ZSB1bmtub3duIGZvcm0gb2YgKmYqLl9fIElmIHRoZSBjaG9zZW4gbW9kZWwgaXMgdG9vIGZhciBmcm9tIHRoZSB0cnVlICpmKiwgdGhlbiBvdXIgZXN0aW1hdGUgd2lsbCBiZSBwb29yLiBXZSBjYW4gdHJ5IHRvIGFkZHJlc3MgdGhpcyBwcm9ibGVtIGJ5IGNob29zaW5nICpmbGV4aWJsZSogbW9kZWxzIHRoYXQgY2FuIGZpdCBtYW55IGRpZmZlcmVudCBwb3NzaWJsZSBmdW5jdGlvbmFsIGZvcm1zIGZvciAqZiouIEJ1dCBpbiBnZW5lcmFsLCBmaXR0aW5nIGEgbW9yZSBmbGV4aWJsZSBtb2RlbCByZXF1aXJlcyBlc3RpbWF0aW5nIGEgZ3JlYXRlciBudW1iZXIgb2YgcGFyYW1ldGVycy4gVGhlc2UgbW9yZSBjb21wbGV4IG1vZGVscyBjYW4gbGVhZCB0byBhIHBoZW5vbWVub24ga25vd24gYXMgKm92ZXJmaXR0aW5nKiB0aGUgZGF0YSwgd2hpY2ggZXNzZW50aWFsbHkgbWVhbnMgdGhleSBmb2xsb3cgdGhlIGVycm9ycywgb3IgKm5vaXNlKiwgdG9vIGNsb3NlbHkuDQoNCiMjIyMgX19Ob24tUGFyYW1ldHJpYyBNZXRob2RzX18NCg0KPiAiTm9uLXBhcmFtZXRyaWMgbWV0aG9kcyBkbyBub3QgbWFrZSBleHBsaWNpdCBhc3N1bXB0aW9ucyBhYm91dCB0aGUgZnVuY3Rpb25hbCBmb3JtIG9mICpmKi4gSW5zdGVhZHkgdGhleSBzZWVrIGFuIGVzdGltYXRlIG9mICpmKiB0aGF0IGdldHMgYXMgY2xvc2UgdG8gdGhlIGRhdGEgcG9pbnRzIGFzIHBvc3NpYmxlIHdpdGhvdXQgYmVpbmcgdG9vIHJvdWdoIG9yIHdpZ2dseS4gU3VjaCBhcHByb2FjaGVzIGNhbiBoYXZlIGEgbWFqb3IgYWR2YW50YWdlIG92ZXIgcGFyYW1ldHJpYyBhcHByb2FjaGVzOiBieSBhdm9pZGluZyB0aGUgYXNzdW1wdGlvbiBvZiBhIHBhcnRpY3VsYXIgZnVuY3Rpb25hbCBmb3JtIGZvciAqZiosIHRoZXkgaGF2ZSB0aGUgcG90ZW50aWFsIHRvIGFjY3VyYXRlbHkgZml0IGEgd2lkZXIgcmFuZ2Ugb2YgcG9zc2libGUgc2hhcGVzIGZvciAqZiouIEFueSBwYXJhbWV0cmljIGFwcHJvYWNoIGJyaW5ncyB3aXRoIGl0IHRoZSBwb3NzaWJpbGl0eSB0aGF0IHRoZSBmdW5jdGlvbmFsIGZvcm0gdXNlZCB0byBlc3RpbWF0ZSAqZiogaXMgdmVyeSBkaWZmZXJlbnQgZnJvbSB0aGUgdHJ1ZSAqZiosIGluIHdoaWNoIGNhc2UgdGhlIHJlc3VsdGluZyBtb2RlbCB3aWxsIG5vdCBmaXQgdGhlIGRhdGEgd2VsbC4gSW4gY29zdHJhc3QsIG5vbi1wYXJhbWV0cmljIGFwcHJvYWNoZXMgY29tcGxldGVseSBhdm9pZCB0aGlzIGRhbmdlciwgc2luY2UgZXNzZW50aWFsbHkgbm8gYXNzdW1wdGlvbiBhYm91dCB0aGUgZm9ybSBvZiAqZiogaXMgbWFkZS4gX19CdXQgbm9uLXBhcmFtZXRyaWMgYXBwcm9hY2hlcyBkbyBzdWZmZXIgZnJvbSBhIG1ham9yIGRpc2FkdmFudGFnZTogc2luY2UgdGhleSBkbyBub3QgcmVkdWNlIHRoZSBwcm9ibGVtIG9mIGVzdGltYXRpbmcgKmYqIHRvIGEgc21hbGwgbnVtYmVyIG9mIHBhcmFtZXRlcnMsIGEgdmVyeSBsYXJnZSBudW1iZXIgb2Ygb2JzZXJ2YXRpb25zIChmYXIgbW9yZSB0aGFuIGlzIHR5cGljYWxseSBuZWVkZWQgZm9yIGEgcGFyYW1ldHJpYyBhcHByb2FjaCkgaXMgcmVxdWlyZWQgaW4gb3JkZXIgdG8gb2J0YWluIGFuIGFjY3VyYXRlIGVzdGltYXRlIGZvciAqZiouX18iDQoNCipPdmVyZml0dGluZyogdGhlIGRhdGEgaXMgdW5kZXNpcmFibGUgYmVjYXVzZSB0aGUgZml0IG9idGFpbmVkIHdpbGwgbm90IHlpZWxkIGFjY3VyYXRlIGVzdGltYXRlcyBvZiB0aGUgcmVzcG9uc2Ugb24gbmV3IG9ic2VydmF0aW9ucyB0aGF0IHdlcmUgbm90IHBhcnQgb2YgdGhlIG9yaWdpbmFsIHRyYWluaW5nIGRhdGEgc2V0Lg0KDQojIyBfXzIuMS4zIFRoZSBUcmFkZS1PZmYgQmV0d2VlbiBQcmVkaWN0aW9uIEFjY3VyYWN5IGFuZCBNb2RlbCBJbnRlcnByZXRhYmlsaXR5P19fDQoNCl9fKldoeSB3b3VsZCB3ZSBldmVyIGNob29zZSB0byB1c2UgYSBtb3JlIHJlc3RyaWN0aXZlIG1ldGhvZCBpbnN0ZWFkIG9mIGEgdmVyeSBmbGV4aWJsZSBhcHByb2FjaD8qX18NCg0KLU1vcmUgcmVzdHJpY3RpdmUgbW9kZWxzIGFyZSBtb3JlIGludGVycHJldGFibGUgYW5kIGFyZSB0aHVzIGJldHRlciBmb3IgaW5mZXJlbmNlIHByb2JsZW1zLg0KDQotSW4gc2V0dGluZ3Mgd2hlcmUgdGhlIGludGVycHJldGFiaWxpdHkgb2YgdGhlIHByZWRpY3RpdmUgbW9kZWwgaXMgbm90IG9mIGludGVyZXN0LCBhcyBpbiB0aGUgY2FzZSBvZiBwcmVkaWN0aW9uIHByb2JsZW1zLCByZWxhdGl2ZWx5IG1vcmUgZmxleGlibGUgdGVjaG5pcXVlcyBhcmUgbW9yZSBhZHZhbnRhZ2VvdXMuIEhvd2V2ZXIsIG1vcmUgZmxleGlibGUgbWV0aG9kcyBvZnRlbiBydW4gdGhlIHJpc2sgb2YgKm92ZXJmaXR0aW5nKiANCg0KIyMgX18yLjEuNCBTdXBlcnZpc2VkIFZlcnN1cyBVbnN1cGVydmlzZWQgTGVhcm5pbmc/X18NCg0KVGhlIG1ldGhvZHMgd2UgaGF2ZSBhbHJlYWR5IGRpc2N1c3NlZCBhcmUgYWxsIGV4YW1wbGVzIG9mIF9fKlN1cGVydmlzZWQgTGVhcm5pbmcqX18uIEVzc2VudGlhbGx5LCB3ZSBoYXZlIGlucHV0cyBhbmQgYXJlIHRyeWluZyB0byBlaXRoZXIgcHJlZGljdCByZXNwb25zZSB2YWx1ZSBiYXNlZCBvbiBvdXIgaW5wdXRzIG9yIG1ha2Ugc29tZSBpbmZlcmVuY2UgYXMgdG8gdGhlIGxpa2VsaWhvb2Qgb2Ygb3VyIG91dHB1dCBnaXZlbiBvdXIgaW5wdXRzLg0KDQpfXypVbnN1cGVydmlzZWQgbGVhcm5pbmcqX18gaXMgbm90IGNvbmNlcm5lZCB3aXRoIHRoZSByZXNwb25zZSAqeSp+aX4uICJXZSBsYWNrIGEgcmVzcG9uc2UgdmFyaWFibGUgdGhhdCBjYW4gc3VwZXJ2aXNlIG91ciBhbmFseXNpcy4iIE9uZSBzdWNoIGV4YW1wbGUgaXMgKmNsdXN0ZXIgYW5hbHlzaXMqIHdoaWNoIHNlZWtzIHRvIGFzY2VudGFpbiwgb24gdGhlIGJhc2lzIG9mICp4Kn4xfiwgLi4uICwgKngqfm5+LCB3aGV0aGVyIHRoZSBvYnNlcnZhdGlvbnMgZmFsbCBpbnRvIHJlbGF0aXZlbHkgZGlzdGluY3QgZ3JvdXBzLg0KDQojIyBfXzIuMS41IFJlZ3Jlc3Npb24gVmVyc3VzIENsYXNzaWZpY2F0aW9uIFByb2JsZW1zX18NCg0KKlF1YW50aXRhdGl2ZSogdmFyaWFibGVzIHRha2Ugb24gbnVtZXJpY2FsIHZhbHVlcy4NCg0KKlF1YWxpdGF0aXZlKiB2YXJpYWJsZXMgdGFrZSBvbiB2YWx1ZXMgaW4gb25lIG9mIEsgZGlmZmVyZW50ICpjbGFzc2VzKi4NCg0KUHJvYmxlbXMgd2l0aCBhIF9fcXVhbnRpdGF0aXZlX18gcmVzcG9uc2UgYXJlIHR5cGljYWxseSByZWZlcnJlZCB0byBhcyAqcmVncmVzc2lvbiogcHJvYmxlbXMuDQoNClByb2JsZW1zIHdpdGggYSBfX3F1YWxpdGF0aXZlX18gcmVzcG9uc2UgYXJlIHR5cGljYWxseSByZWZlcnJlZCB0byBhcyAqY2xhc3NpZmljYXRpb24qIHByb2JsZW1zLg0KDQojIyBfXzIuMiBBc3Nlc3NpbmcgTW9kZWwgQWNjdXJhY3k/X18NCg0KQmVmb3JlIHVuZGVydGFraW5nIGFueSBraW5kIG9mIHN0YXRpc3RpY2FsIGFuYWx5c2lzLCBhc2sgdGhlIHF1ZXN0aW9uLCAiKldoaWNoIHNwZWNpZmljIG1ldGhvZCB3b3JrcyBiZXN0IGZvciB0aGUgcGFydGljdWxhciBkYXRhIHNldCoiLg0KDQojIyBfXzIuMi4xIE1lYXN1cmluZyB0aGUgUXVhbGl0eSBvZiBGaXRfXw0KDQpUaGUgKm1lYW4gc3F1YXJlZCBlcnJvciogKF9fTVNFX18pIHF1YW50aWZpZXMgdGhlIGV4dGVudCB0byB3aGljaCB0aGUgcHJlZGljdGVkIHJlc3BvbnNlIHZhbHVlIGZvciBhIGdpdmVuIG9ic2VydmF0aW9uIGlzIGNsb3NlIHRvIHRoZSB0cnVlIHJlc3BvbnNlIHZhbHVlIGZvciB0aGF0IG9ic2VydmF0aW9uLg0KDQo+ICJUaGUgX19NU0VfXyB3aWxsIGJlIHNtYWxsIGlmIHRoZSBwcmVkaWN0ZWQgcmVzcG9uc2VzIGFyZSB2ZXJ5IGNsb3NlIHRvIHRoZSB0cnVlIHJlc3BvbnNlcywgYW5kIHdpbGwgYmUgbGFyZ2UgaWYgZm9yIHNvbWUgb2YgdGhlIG9ic2VydmF0aW9ucywgdGhlIHByZWRpY3RlZCBhbmQgdHJ1ZSByZXNwb25zZXMgZGlmZmVyIHN1YnN0YW50aWFsbHkuIg0KDQpSZW1lbWJlcjogd2UgYXJlIG5vdCByZWFsbHkgaW50ZXJlc3RlZCBpbiBob3cgb3VyIHByZWRpY3RlZCBmdW5jdGlvbmFsIGZvcm0gKmYqKHgpIGZpdHMgb3VyIHJlc3BvbnNlIHZhbHVlIGluIHRoZSB0cmFpbmluZyBkYXRhLiBSYXRoZXIsIHdlIGFyZSBtb3JlIGludGVyZXN0ZWQgaW4gaG93IG91ciBmdW5jdGlvbmFsIGZvcm0gKmYqKHgpIGZpdHMgYSAqcHJldmlvdXNseSB1bnNlZW4gdGVzdCBvYnNlcnZhdGlvbiBub3QgdXNlZCB0byB0cmFpbiB0aGUgc3RhdGlzdGljYWwgbGVhcm5pbmcgbWV0aG9kKi4NCg0KVGh1cywgd2Ugd2FudCB0byBzZWxlY3QgdGhlIG1ldGhvZCB3aXRoIHRoZSBsb3dlc3QgKnRlc3QgTVNFKi4NCg0KX18qRGVncmVlcyBvZiBmcmVlZG9tKl9fIGlzIGEgcXVhbnRpdHkgdGhhdCBzdW1tYXJpemVzIHRoZSBmbGV4aWJpbGl0eSBvZiBhIGN1cnZlLg0KDQoqQXMgbW9kZWwgZmxleGliaWxpdHkgaW5jcmVhc2VzLCB0cmFpbmluZyBNU0Ugd2lsbCBkZWNyZWFzZSwgYnV0IHRoZSB0ZXN0IE1TRSBtYXkgbm90LioNCg0KKldoZW4gYSBnaXZlbiBtZXRob2QgeWllbGRzIGEgc21hbGwgdHJhaW5pbmcgTVNFIGJ1dCBhIGxhcmdlIHRlc3QgTVNFLCB3ZSBhcmUgc2FpZCB0byBiZSBfX292ZXJmaXR0aW5nX18gdGhlIGRhdGEuIE92ZXJmaXR0aW5nIHJlZmVycyBzcGVjaWZpY2FsbHkgdG8gdGhlIGNhc2UgaW4gd2hpY2ggYSBsZXNzIGZsZXhpYmxlIG1vZGVsIHdvdWxkIGhhdmUgeWllbGRlZCBhIHNtYWxsZXIgdGVzdCBNU0UuKg0KDQoqQ3Jvc3MtdmFsaWRhdGlvbio6IGEgbWV0aG9kIGZvciBlc3RpbWF0aW5nIHRlc3QgTVNFIHVzaW5nIHRoZSB0cmFpbmluZyBkYXRhLg0KDQojIyBfXzIuMi4yIFRoZSBCaWFzLVZhcmlhbmNlIFRyYWRlLU9mZl9fDQoNClRoZSBleHBlY3RlZCB0ZXN0IE1TRSwgZm9yIGEgZ2l2ZW4gdmFsdWUgb2YgKngqfjB+IGNhbiBiZSBkZWNvbXBvc2VkIGludG8gdGhyZWUgZnVuZGFtZW50YWwgcXVhbnRpdGllczoNCg0KKiBfX1RoZSB2YXJpYW5jZSBvZiB0aGUgcHJlZGljdGVkIGZ1bmN0aW9uYWwgZm9ybSBvZiBmKCp4Kn4wfilfXw0KKiBfX1RoZSBzcXVhcmVkICpiaWFzKiBvZiB0aGUgcHJlZGljdGVkIGZ1bmN0aW9uYWwgZm9ybSBvZiBmKCp4Kn4wfilfXw0KKiBfX1RoZSB2YXJpYW5jZSBvZiB0aGUgZXJyb3IgdGVybXMgKkUqX18NCg0KIyMjIyMgKlRodXMsIGluIG9yZGVyIHRvIG1pbmltaXplIHRoZSBleHBlY3RlZCB0ZXN0IGVycm9yLCB3ZSBuZWVkIHRvIHNlbGVjdCBhIHN0YXRpc3RpY2FsIGxlYXJuaW5nIG1ldGhvZCB0aGF0IHNpbXVsdGFuZW91c2x5IGFjaGllcyAqbG93IHZhcmlhbmNlKiBhbmQgKmxvdyBiaWFzKi4qDQoNCl9fKlZhcmlhbmNlKl9fIHJlZmVycyB0byB0aGUgYW1vdW50IGJ5IHdoaWNoIHRoZSBwcmVkaWN0ZWQgZnVudGlvbmFsIGZvcm0gb2YgKmYqIHdvdWxkIGNoYW5nZSBpZiB3ZSBlc3RpbWF0ZWQgaXQgdXNpbmcgYSBkaWZmZXJlbnQgdHJhaW5pbmcgZGF0YSBzZXQuDQoNCkluIGdlbmVyYWwsIG1vcmUgZmxleGlibGUgc3RhdGlzdGljYWwgbWV0aG9kcyBoYXZlIGhpZ2hlciB2YXJpYW5jZS4NCg0KX18qQmlhcypfXyByZWZlcnMgdG8gdGhlIGVycm9yIHRoYXQgaXMgaW50cm9kdWNlZCBieSBhcHByb3hpbWF0aW5nIGEgcmVhbC1saWZlIHByb2JsZW0sIHdoaWNoIG1heSBiZSBleHRyZW1lbWx5IGNvbXBsaWNhdGVkLCBieSBhIG11Y2ggc2ltcGxlciBtb2RlbC4NCg0KR2VuZXJhbGx5LCBtb3JlIGZsZXhpYmxlIG1ldGhvZHMgcmVzdWx0IGluIGxlc3MgYmlhcy4NCg0KQXMgYSBnZW5lcmFsIHJ1bGUsIGFzIHdlIHVzZSBtb3JlIGZsZXhpYmxlIG1ldGhvZHMsIHRoZSB2YXJpYW5jZSB3aWxsIGluY3JlYXNlIGFuZCB0aGUgYmlhcyB3aWxsIGRlY3JlYXNlLg0KDQojIyMjIyBfX1RoZSByZWxhdGl2ZSByYXRlIG9mIGNoYW5nZSBvZiB0aGVzZSB0d28gcXVhbnRpdGllcyBkZXRlcm1pbmVzIHdoZXRoZXIgdGhlIHRlc3QgTVNFIGluY3JlYXNlcyBvciBkZWNyZWFzZXMuX18NCg0KPiBBcyB3ZSBpbmNyZWFzZSB0aGUgZmxleGliaWxpdHkgb2YgYSBjbGFzcyBvZiBtZXRob2RzLCB0aGUgYmlhcyB0ZW5kcyB0byBpbml0aWFsbHkgZGVjcmVhc2UgZmFzdGVyIHRoYW4gdGhlIHZhcmlhbmNlIGluY3JlYXNlcy4gQ29uc2VxdWVudGx5LCB0aGUgZXhwZWN0ZWQgdGVzdCBNU0UgZGVjbGluZXMuIEhvd2V2ZXIsIGF0IHNvbWUgcG9pbnQgaW5jcmVhc2luZyBmbGV4aWJpbGl0eSBoYXMgbGl0dGxlIGltcGFjdCBvbiB0aGUgYmlhcyBidXQgc3RhcnRzIHRvIHNpZ25pZmljYW50bHkgaW5jcmVhc2UgdGhlIHZhcmlhbmNlLiBXaGVuIHRoaXMgaGFwcGVucyB0aGUgdGVzdCBNU0UgaW5jcmVhc2VzLiANCg0KX19UaGUgcmVsYXRpb25zaGlwIGJldHdlZW4gYmlhcywgdmFyaWFuY2UsIGFuZCB0ZXN0IHNldCBNU0Ugb3V0bGluZWQgYWJvdmUgaXMgcmVmZXJyZWQgdG8gYXMgdGhlICpiaWFzLXZhcmlhbmNlIHRyYWRlLW9mZiouIF9fVGhlIGNoYWxsZW5nZSBsaWVzIGluIGZpbmRpbmcgYSBtZXRob2QgZm9yIHdoaWNoIGJvdGggdGhlIHZhcmlhbmNlIGFuZCB0aGUgc3F1YXJlZCBiaWFzIGFyZSBsb3cuX18NCg0KIyMgX18yLjIuMyBUaGUgQ2xhc3NpZmljYXRpb24gU2V0dGluZ19fDQoNCiJUaGUgbW9zdCBjb21tb24gYXBwcm9hY2ggZm9yIHF1YW50aWZ5aW5nIHRoZSBhY2N1cmFjeSBvZiBvdXIgZXN0aW1hdGUgb2YgdGhlIGZ1bmN0aW9uYWwgZm9ybSBvZiAqZiogaXMgdGhlIHRyYWluaW5nIF9fZXJyb3IgcmF0ZV9fLCAqdGhlIHByb3BvcnRpb24gb2YgbWlzdGFrZXMgdGhhdCBhcmUgbWFkZSBpZiB3ZSBhcHBseSBvdXIgZXN0aW1hdGUgb2YgdGhlIGZ1bmN0aW9uYWwgZm9ybSAqZiogdG8gdGhlIHRyYWluaW5nIG9ic2VydmF0aW9ucy4NCg0KRXNzZW50aWFsbHksIHRoZSByYXRlIG9mIGluY29ycmVjdCBjbGFzc2lmaWNhdGlvbnMuDQoNCl9fKlRoZSBCYXllcyBDbGFzc2lmaWVyKl9fDQoNClRoZSB0ZXN0IGVycm9yIHJhdGUgZ2l2ZW4gaXMgbWluaW1pemVkLCBvbiBhdmVyYWdlLCBieSBhIHZlcnkgc2ltcGxlIGNsYXNzaWZpZXIgdGhhdCAqYXNzaWducyBlYWNoIG9ic2VydmF0aW9uIHRvIHRoZSBtb3N0IGxpa2VseSBjbGFzcywgZ2l2ZW4gaXRzIHByZWRpY3RvciB2YWx1ZXMqLg0KDQpUaGUgX18qQmF5ZXMgQ2xhc3NpZmllcipfXyB1c2VzIGEgY29uZGl0aW9uYWwgcHJvYmFiaWxpdHkgZm9yIGEgMiBjbGFzcyBwcmVkaWN0b3IgZnVuY3Rpb24gYXNzaWduaW5nIGVhY2ggb2JzZXJ2YXRpb24gdG8gY2xhc3MgeCBpZiBpdHMgcHJvYmFiaWxpdHkgb2YgYmVsb25naW5nIHRvIHRoYXQgY2xhc3MgaXMgPiAuNS4NCg0KX18qQmF5ZXMgZGVjaXNpb24gYm91bmRhcnkqX18gdGhlIGxpbmUgcmVwcmVzZW50aW5nIHRoZSBwb2ludHMgd2hlcmUgdGhlIGJvdW5kYXJ5IGlzIGV4YWN0bHkgNTAlLg0KDQpfX0stTmVhcmVzdCBOZWlnaGJvcnNfXw0KDQpNYW55IGFwcHJvYWNoZXMgYXR0ZW1wdCB0byBlc3RpbWF0ZSB0aGUgY29uZGl0aW9uYWwgZGlzdHJpYnV0aW9uIG9mIFkgZ2l2ZW4gWCwgYW5kIHRoZW4gY2xhc3NpZnkgYSBnaXZlbiBvYnNlcnZhdGlvbiB0byB0aGUgY2xhc3Mgd2l0aCBoaWdoZXN0ICplc3RpbWF0ZWQqIHByb2JhYmlsaXR5LiANCg0KX18qSy1uZWFyZXN0IG5laWdoYm9ycyogKEtOTilfXyBpcyBvbmUgc3VjaCBtZXRob2QuDQoNClRodXMsIHlvdSBzcGVjaWZ5IGhvdyBtYW55ICJfX0snc19fIi4gV2l0aCB0b28gbWFueSwgdGhlIG1vZGVsIGlzIHRvbyByaWdpZCwgd2l0aCB0b28gZmV3IGl0IGlzIHRvbyBmbGV4aWJsZS4NCg0KIyMgX18yLjMgTGFiOiBJbnRyb2R1Y3Rpb24gdG8gUl9fDQoNCiMjIF9fKjIuMy4xIEJhc2ljIENvbW1hbmRzKl9fIA0KDQpfXzEuKSBEZWZpbmVzIGEgdmVjdG9yIDIuKSBWaWV3cyBpdF9fDQpgYGB7cn0NCnggPSBjKDEsMywyLDUpDQp4DQpgYGANCl9fRGVmaW5lcywgbGlzdHMsIHNob3dzIHRoZSBsZW5ndGhzIGFuZCBzdW1zIHRoZSB2ZWN0b3JzLl9fDQpgYGB7cn0NCnggPSBjKDEsNiwyKQ0KeA0KeT1jKDEsNCwzKQ0KeQ0KYGBgDQpgYGB7cn0NCmxlbmd0aCh4KQ0KbGVuZ3RoKHkpDQp4K3kNCmBgYA0KX19MaXN0cyB0aGUgdmVjdG9yc19fDQpgYGB7cn0NCmxzKCkNCmBgYA0KX19SZW1vdmVzIHRoZSBzcGVjaWZpZWQgdmVjdG9yX18NCmBgYHtyfQ0Kcm0oeCx5KQ0KbHMoKQ0KYGBgDQpfX1JlbW92ZXMgYWxsIHZlY3RvcnMgaW4gdGhlIGxpc3QgYXQgb25jZS5fXw0KYGBge3J9DQpybShsaXN0PWxzKCkpDQpgYGANCl9fQ3JlYXRlcyBhIG1hdHJpeCB3LyAzIGRpbWVuc2lvbnM6IHRoZSBkYXRhLCAjIG9mIHJvd3MsIGFuZCAjIG9mIGNvbHVtbnMuKk5vdGUqIGl0IGZpbGxzIGluIHRoZSBjb2x1bW5zIGZpcnN0Ll9fDQpgYGB7cn0NCng9bWF0cml4KGRhdGE9YygxLDIsMyw0KSwgbnJvdz0yLCBuY29sPTIpDQp4DQpgYGANCl9fQWdhaW4sIGNyZWF0ZXMgYSBtYXRyaXgsIGJ1dCBmaWxscyBpbiB0aGUgcm93cyBmaXJzdC5fXw0KYGBge3J9DQp4PW1hdHJpeChkYXRhPWMoMSwyLDMsNCksIG5yb3c9MiwgbmNvbD0yLGJ5cm93PVQpDQp4DQpgYGANCl9fUmV0dXJucyB0aGUgc3F1YXJlIHJvb3Qgb2YgZWFjaCBlbGVtZW50IG9mIGEgdmVjdG9yIG9yIG1hdHJpeF9fDQpgYGB7cn0NCnNxcnQoeCkNCngNCnheMg0KYGBgDQpfX0dlbmVyYXRlcyBhIHZlY3RvciBvZiByYW5kb20gbm9ybWFsIHZhcmlhYmxlcy4gRmlyc3QgYXJndW1lbnQgaXMgKm4qIHNhbXBsZSBzaXplLiBUaGVuLCBkZXJpdmVzIHRoZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZSB0d28gdmVjdG9ycy5fXw0KYGBge3J9DQp4PXJub3JtKDUwKQ0KeT14K3Jub3JtKDUwLG1lYW49NTAsc2Q9LjEpDQpjb3IoeCx5KQ0KYGBgDQpfX1NldHMgYSByYW5kb20gdmVjdG9yIGZvciB1c2UgbGF0ZXIgYnkgZGVmaW5pbmcgdGhlIHByZXZpb3VzbHkgZ2VuZXJhdGVkIHJhbmRvbSB2YXJpYWJsZXMuX18NCmBgYHtyfQ0Kc2V0LnNlZWQoMTMwMykNCnJub3JtKDUwKQ0KYGBgDQpfX1NldHMgdGhlIHJhbmRvbSB2YXJpYWJsZXMgZm9yIHJlcGxpY2FiaWxpdHkgYnkgZGVmaW5pbmcgYSB2ZWN0b3Igb2YgMTAwIHJhbmRvbSBvYnNlcnZhdGlvbnMgKHRoZSBzYW1lIGFzIGluIHRoZSBib29rKSBhbmQgdGhlbiBjYWxjdWxhdGluZyB0aGUgbWVhbi5fXw0KYGBge3J9DQpzZXQuc2VlZCgzKQ0KeT1ybm9ybSgxMDApDQptZWFuKHkpDQpgYGANCl9fQ2FsY3VsYXRlcyB0aGUgdmFyaWFuY2Ugb2YgeS5fXw0KYGBge3J9DQp2YXIoeSkNCmBgYA0KX19DYWxjdWxhdGVzIHRoZSBzcXVhcmUgcm9vdCBvZiB0aGUgdmFyaWFuY2Ugb2YgeSAodGhlIHN0YW5kYXJkIGRldmlhdGlvbikuX18NCmBgYHtyfQ0Kc3FydCh2YXIoeSkpDQpgYGANCl9fQSBzaW1wbGVyIG1ldGhvZCBvZiBjYWxjdWxhdGluZyB0aGUgc3RhbmRhcmQgZGV2aWF0aW9uIG9mIHkuX18NCmBgYHtyfQ0Kc2QoeSkNCmBgYA0KDQojIyBfXyoyLjMuMiBHcmFwaGljcypfXyANCg0KX19EZWZpbmVzIHZlY3RvcnMgKngqIGFuZCAqeSogYnkgYSBzZXJpZXMgb2YgMTAwIHJhbmRvbSBub3JtYWwgb2JzZXJ2YXRpb25zIHRoZW4gcGxvdHMgdGhlbS4gRmluYWxseSwgcGxvdHMgdGhlbSB3aXRoIHNwZWNpZmljIGxhYmVscyBvbiB0aGUgY29ycmVzcG9uZGluZyBheGlzIGFuZCBhIEhlYWRlci5fXw0KYGBge3J9DQp4PXJub3JtKDEwMCkNCnk9cm5vcm0oMTAwKQ0KcGxvdCh4LHkpDQpwbG90KHgseSx4bGFiPSJUaGlzIGlzIHRoZSBYIGF4aXMiLHlsYWI9IlRoaXMgaXMgdGhlIFkgYXhpcyIsbWFpbj0iUGxvdCBvZiBYIGFuZCBZIikNCmBgYA0KX19DcmVhdGVzIGEgcGRmIG9mIHRoZSBncmFwaGljIHdlIGNyZWF0ZS4gRmlyc3Qgd2Ugc3BlY2lmeSB0aGUgdHlwZSBvZiBmaWxlIHdlIHdpc2ggdG8gY3JlYXRlIGFuZCBuYW1lIGl0LiBUaGVuIHdlIGNyZWF0ZSBpdC4gRmluYWxseSB3ZSBzcGVjaWZ5IHRoYXQgd2UgYXJlIGRvbmUgY3JlYXRpbmcgaXQuIFNhdmVzIGl0IGluIHRoZSBsb2NhdGlvbiBvZiB0aGUgY3VycmVudCB3b3JraW5nIGRpcmVjdG9yeS4NCmBgYHtyfQ0KcGRmKCJGaWd1cmUucGRmIikNCnBsb3QoeCx5LGNvbD0iZ3JlZW4iKQ0KZGV2Lm9mZigpDQpgYGANCl9fQ3JlYXRlcyBhIHNlcXVlbmNlIG9mIG51bWJlcnMuIElmIHlvdSBzcGVjaWZ5IHR3byBwb2ludHMgaXQgY3JlYXRlcyBhIHZlY3RvciBvZiBudW1iZXJzIGJldHdlZW4gdGhvc2UgdHdvIHBvaW50cy4gWW91IGNhbiBhbHNvIHNwZWNpZnkgbGVuZ3RoIHRvIGdpdmUgYSBzZXF1ZW5jZSBvZiBlcXVhbGx5IHNwYWNlZCBudW1iZXJzIGJldHdlZW4gdGhlIHR3byBwb2ludHMgYnkgdGhhdCBsZW5ndGguX18NCmBgYHtyfQ0KeD1zZXEoMSwxMCkNCngNCmBgYA0KX19Nb3JlIHNvcGhpc3RpY2F0ZWQgZm9ybV9fDQpgYGB7cn0NCng9c2VxKC1waSxwaSxsZW5ndGg9NTApDQp4DQpgYGANCg0KIyMgX18qMi4zLjMgSW5kZXhpbmcgRGF0YSpfXw0KDQpfX0NyZWF0ZXMgYSBtYXRyaXggb2YgdmFsdWVzIGJldHdlZW4gMSBhbmQgMTYgd2l0aCA0IHJvd3MgYW5kIDQgY29sdW1ucy5fXw0KYGBge3J9DQpBPW1hdHJpeCgxOjE2LDQsNCkNCkENCmBgYA0KUmV0dXJucyB0aGUgdmFsdWUgY29ycmVzcG9uZGluZyB0byBfX3JvdyAyIGNvbHVtbiAzX18uDQpgYGB7cn0NCkFbMiwzXQ0KYGBgDQpfX1NlbGVjdHMgbXVsdGlwbGUgcm93cyBhbmQgY29sdW1ucyBhdCBhIHRpbWUsIGJ5IHByb3ZpZGluZyB2ZWN0b3JzIGFzIHRoZSBpbmRpY2VzLl9fDQoNClJldHVybnMgdGhlIHZhbHVlcyBhdCB0aGUgaW50ZXJzZWN0aW9uIG9mICpyb3dzKiBfXzFfXyBhbmQgX18zX18gYW5kICpjb2x1bW5zKiBfXzJfXyBhbmQgX180X18uDQpgYGB7cn0NCkFbYygxLDMpLGMoMiw0KV0NCmBgYA0KUmV0dXJucyBhbGwgdGhlIHZhbHVlcyB0aGF0IGNvcnJlc3BvbmQgdG8gdGhlIGludGVyc2VjdGlvbiBvZiAqcm93cyogX18xX18gdGhvdWdoIF9fM19fIGFuZCAqY29sdW1ucyogX18yX18gdGhyb3VnaCBfXzRfXy4gDQpgYGB7cn0NCkFbMTozLDI6NF0NCmBgYA0KUmV0dXJucyBhbGwgdmFsdWVzIGluIHJvd3MgX18xX18gYW5kIF9fMl9fLg0KYGBge3J9DQpBWzE6MixdDQpgYGANClJldHVybnMgYWxsIHZhbHVlcyBpbiBjb2x1bW5zIF9fMV9fIGFuZCBfXzJfXy4NCmBgYHtyfQ0KQVssMToyXQ0KYGBgDQpSZXR1cm5zIHRoZSB2ZWN0b3IgX19yb3cgMV9fLg0KYGBge3J9DQpBWzEsXQ0KYGBgDQpSZXR1cm5zIGFsbCB2YWx1ZXMgZXhjZXB0IHJvd3MgX18xX18gYW5kIF9fM19fLg0KYGBge3J9DQpBWy1jKDEsMyksXQ0KYGBgDQpSZXR1cm5zIG9ubHkgdGhlIHZhbHVlcyBub3QgaW4gcm93cyBfXzFfXyBhbmQgX18zX18gYW5kIG5vdCBpbiBjb2x1bW5zIF9fMV9fLCBfXzNfXywgYW5kIF9fNF9fLiBCYXNpY2FsbHkgb25seSB0aGUgdmFsdWVzIGluIHJvd3MgX18yX18gYW5kIF9fNF9fIGFuZCBjb2x1bW4gX18yX18gb2YgdGhlIHByZXZpb3VzbHkgc3BlY2lmaWVkIG1hdHJpeC4NCmBgYHtyfQ0KQVstYygxLDMpLC1jKDEsMyw0KV0NCmBgYA0KDQojIyBfXyoyLjMuNCBMb2FkaW5nIERhdGEqX18NCg0KTG9hZHMgdGhlIGRhdGEgZnJvbSB0aGUgcHJlc2VudCB3b3JraW5nIGRpcmVjdG9yeSBuYW1lZCAiQXV0by5kYXRhIiBhbmQgZGVmaW5lcyBpdCBpbiB0aGUgZW52aXJvbm1lbnQgYXMgIkF1dG8iLiBfX05vdGVfXyAqdGhlIHZhcmlhYmxlcyBhcmUgbm90IGN1cnJlbnRseSBkZWZpbmVkKi4gRml4IGNhdXNlcyB0aGUgZGF0YSB0byBiZSBkaXNwbGF5ZWQgaW4gYSBwb3Agb3V0IHZpZXdlci4NCmBgYHtyfQ0KQXV0bz1yZWFkLnRhYmxlKCJBdXRvLmRhdGEiKQ0KZml4KEF1dG8pDQpgYGANCg0KUmVsb2FkcyB0aGUgZGF0YSwgYnV0IHNwZWNpZmllcyB0aGF0IHRoZSB2YWx1ZXMgaW4gdGhlIGZpcnN0IHJvdyBhcmUgdGhlIGhlYWRlciBhbmQgdGhhdCB2YWx1ZXMgd2l0aCBhIHF1ZXN0aW9uIG1hcmsgYXJlIG1pc3NpbmcgdmFsdWVzLg0KYGBge3J9DQpBdXRvPXJlYWQudGFibGUoIkF1dG8uZGF0YSIsaGVhZGVyPVQsbmEuc3RyaW5nPSI/IikNCmZpeChBdXRvKQ0KYGBgDQoNCl9fR2VuZXJhdGVzIGFuIGV4dGVybmFsIHZpZXdlciBvZiB0aGUgZGF0YSBhbmQgdGhlbiBkZXNjcmliZXMgaG93IG1hbnkgcm93cyBieSBob3cgbWFueSBjb2x1bXMuX18NCmBgYHtyfQ0KZml4KEF1dG8pDQpkaW0oQXV0bykNCmBgYA0KX19MaXN0cyB0aGUgZmlyc3QgZm91ciByb3dzIG9mIGRhdGEgYWNyb3NzIHRoZSBuaW5lIHZhcmlhYmxlcy5fXw0KYGBge3J9DQpBdXRvWygxOjQpLF0NCmBgYA0KX19SZW1vdmVzIHRoZSByb3dzIHdpdGggbWlzc2luZyBvYnNlcnZhdGlvbnMgYW5kIHRoZW4gZ2l2ZXMgdGhlIG5ldyBkaW1lbnNpb25zX18NCmBgYHtyfQ0KQXV0bz1uYS5vbWl0KEF1dG8pDQpkaW0oQXV0bykNCmBgYA0KX19MaXN0cyB0aGUgdmFyaWFibGUgbmFtZXNfXy4NCmBgYHtyfQ0KbmFtZXMoQXV0bykNCmBgYA0KDQojIyBfXyoyLjMuNSBBZGRpdGlvbmFsIEdyYXBoaWNhbCBhbmQgTnVtZXJpY2FsIFN1bW1hcmllcypfXw0KDQpgYGB7cn0NCnBsb3QoY3lsaW5kZXJzLG1wZykNCmBgYA0KX18qTm90ZTpfXyBjYW5ub3QgcGxvdCBiZWNhdXNlIHRoZSB2YXJpYWJsZXMgYXJlIG5vdCB5ZXQgcHJvcGVybHkgZGVmaW5lZC4gVGh1cywgUiBoYXMgbm8gaWRlYSB3aGF0ICpjeWxpbmRlciogb3IgKm1wZyogYXJlLg0KDQpfX0J5IGpvaW5pbmcgdGhlIGRhdGEgZnJhbWUgd2l0aCB0aGUgdmFyaWFibGUgdmlhIGEgZG9sbGFyIHNpZ24gUiBrbm93cyB0aGF0IGN5bGluZGVycyBhbmQgbXBnIGFyZSB2YXJpYWJsZXMgbGlua2VkIHRvIHRoYXQgZGF0YSB0YWJsZS4NCmBgYHtyfQ0KcGxvdChBdXRvJGN5bGluZGVycyxBdXRvJG1wZykNCmBgYA0KDQpfX0hvd2V2ZXIsIGJ5ICoiYXR0YWNoaW5nIiogQXV0bywgd2UgY2FuIHRlbGwgUiB0aGF0IHRoZSB2YWx1ZXMgaW4gdGhlIGhlYWRlciBhcmUgbGlua2VkIHRvIHRoYXQgZGF0YSB0YWJsZSBhbmQgYXJlIG91ciBpbnB1dHMuDQpgYGB7cn0NCmF0dGFjaChBdXRvKQ0KYGBgDQpgYGB7cn0NCnBsb3QoY3lsaW5kZXJzLG1wZykNCmBgYA0KDQpfX0NvbnZlcnRzIHF1YW50aXRhdGl2ZSBkYXRhIGludG8gcXVhbGl0YXRpdmUuIENvbnZlcnRzIGN5bGluZGVycyB3aGljaCB3YXMgcHJldmlvdXNseSBxdWFudGlhdGl2ZSB3aXRoIG9ubHkgNiBwb3NzaWJsZSB2YWx1ZXMgaW50byBhIHZhcmlhYmxlIHdpdGggNSBmYWN0b3JzLiBJdCBpcyA1IGZhY3RvcnMgYmVjYXVzZSBhcyB5b3Ugbm90ZSBmcm9tIHRoZSBwbG90IGFib3ZlOyB0aGVyZSBhcmUgbm8gY29ycmVzcG9uZGluZyB2YWx1ZXMgZm9yICI3Ii5fXw0KYGBge3J9DQpjeWxpbmRlcnM9YXMuZmFjdG9yKGN5bGluZGVycykNCmBgYA0KDQpfX05vdyB0aGF0IHRoZSBkYXRhIGlzIGNhdGVnb3JpY2FsLCBpdCBnZW5lcmF0ZXMgYSAqYm94cGxvdCouIEhlcmUgYXJlIGEgZmV3IGJveHBsb3RzIHdpdGggZGlmZmVyZW50IG9wdGlvbnMuX18NCmBgYHtyfQ0KcGxvdChjeWxpbmRlcnMsbXBnKQ0KcGxvdChjeWxpbmRlcnMsbXBnLHhsYWI9IkN5bGluZGVycyIseWxhYj0ibXBnIixtYWluPSJNaWxlYWdlIGJ5ICMgb2YgQ3lsaW5kZXJzIixjb2w9InJlZCIpDQpwbG90KGN5bGluZGVycyxtcGcseGxhYj0iQ3lsaW5kZXJzIix5bGFiPSJtcGciLG1haW49Ik1pbGVhZ2UgYnkgIyBvZiBDeWxpbmRlcnMiLGNvbD0icmVkIix2YXJ3aWR0aD1UKQ0KYGBgDQpfX0NyZWF0ZXMgYSBoaXN0b2dyYW0gb2YgdGhlIGRhdGEuIEhlcmUgYXJlIGEgZmV3IHdpdGggZGlmZmVyZW50IG9wdGlvbnMuX18NCmBgYHtyfQ0KaGlzdChtcGcpDQpoaXN0KG1wZyxjb2w9MikNCmhpc3QobXBnLGNvbD0yLGJyZWFrcz0xNSkNCmBgYA0KX19DcmVhdGVzIGEgc2NhdHRlcnBsb3QgbWF0cml4LiBUaGUgc2Vjb25kIGFsc28gY3JlYXRlcyBhIHNjYXR0ZXJwbG90IG1hdHJpeCwgYnV0IG9ubHkgZm9yIHRoZSBmaXZlIHZhcmlhYmxlcyB3ZSBzcGVjaWZpZWQuX18NCmBgYHtyfQ0KcGFpcnMoQXV0bykNCnBhaXJzKH5tcGcrZGlzcGxhY2VtZW50K2hvcnNlcG93ZXIrd2VpZ2h0K2FjY2VsZXJhdGlvbixBdXRvKQ0KYGBgDQpQbG90cyB0aGUgZGF0YSBhbmQgdGhlbiBlbmFibGVzIGEgY2xpY2sgdG9vbCBpbiB0aGUgcGxvdHMgY29uc29sZSB3aGljaCBwcmludHMgdGhlIHZhbHVlcyBvZiBwb2ludHMgeW91IHNlbGVjdC4gX18qTm90ZSogZG9lcyBub3Qgd29yayBpbiBSIG5vdGVib29rLCBvbmx5IGluIHRoZSBjb25zb2xlLl9fDQpgYGB7cn0NCnBsb3QoaG9yc2Vwb3dlcixtcGcpDQppZGVudGlmeShob3JzZXBvd2VyLG1wZyxuYW1lKQ0KYGBgDQpfX1Byb2R1Y2VzIGEgbnVtZXJpY2FsIHN1bW1hcnkgb2YgZWFjaCB2YXJpYWJsZSBpbiBhIHBhcnRpY3VsYXIgZGF0YSBzZXQuX18NCmBgYHtyfQ0Kc3VtbWFyeShBdXRvKQ0KYGBgDQoNCiMjIF9fMi40IEV4ZXJjaXNlc19fDQoNCl9fKkNvbmNlcHR1YWwqX18NCg0KMS4gRm9yIGVhY2ggb2YgcGFydHMgKGEpIHRocm91Z2ggKGQpLCBpbmRpY2F0ZSB3aGV0aGVyIHdlIHdvdWxkIGdlbmVyYWxseSBleHBlY3QgdGhlIHBlcmZvcm1hbmNlIG9mIGEgZmxleGlibGUgc3RhdGlzdGljYWwgbGVhcm5pbmcgbWV0aG9kIHRvIGJlIGJldHRlciBvciB3b3JzZSB0aGFuIGFuIGluZmxleGlibGUgbWV0aG9kLiBKdXN0aWZ5IHlvdXIgYW5zd2VyLg0KKyAoYSkgVGhlIHNhbXBsZSBzaXplICpuKiBpcyBleHRyZW1lbHkgbGFyZ2UsIGFuZCB0aGUgbnVtYmVyIG9mIHByZWRpY3RvcnMgKnAqIGlzIHNtYWxsLiBfX0lmIHdlIGhhdmUgZmV3IHByZWRpY3RvcnMgdGhlbiBvdXIgYmlhcyBpcyBsaWtlbHkgdG8gYmUgbGFyZ2VyLiBBbHNvLCBnaXZlbiB0aGUgbGFyZ2Ugc2FtcGxlIHNpemUsIGEgbW9yZSBmbGV4aWJsZSBtZXRob2Qgd291bGQgbGlrZWx5IHJlZHVjZSB0aGUgYmlhcyBhbmQgdGh1cyBmaXQgdGhlIGRhdGEgYmV0dGVyLl9fDQorIChiKSBUaGUgbnVtYmVyIG9mIHByZWRpY3RvcnMgKnAqIGlzIGV4dHJlbWVseSBsYXJnZSwgYW5kIHRoZSBudW1iZXIgb2Ygb2JzZXJ2YXRpb25zICpuKiBpcyBzbWFsbC4gX19MaWtlbHkgd29yc2UuIFdpdGggYSBsYXJnZSBudW1iZXIgb2YgcHJlZGljdG9ycyB3ZSBydW4gdGhlIHJpc2sgb2YgKm92ZXJmaXR0aW5nKiB0aGUgZGF0YS4gQnkgaW5jcmVhc2luZyB0aGUgZmxleGliaWxpdHksIHdlIG9ubHkgZXhhY2VyYmF0ZSB0aGlzIHJpc2sgYnkgYXBwcm94aW1hdGluZyB0aGF0IG1heSB0b28gY2xvc2VseSBmaXQgdGhlIHRyYWluaW5nIGRhdGEsIGJ1dCBub3QgbmVjZXNzYXJpbHkgd29yayBpbiBwcmFjdGljZS5fXw0KKyAoYykgVGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZSBwcmVkaWN0b3JzIGFuZCByZXNwb25zZSBpcyBoaWdobHkgbm9uLWxpbmVhci4gX19CZXR0ZXIuIElmIHRoZSBkYXRhIGlzIGhpZ2hseSBub24tbGluZWFyIHRoYXQgaXQgaXMgZmFpcmx5IG9idmlvdXMgdGhhdCBhbiBpbmZsZXhpYmxlIG1vZGVsIHdpbGwgbm90IGNhcHR1cmUgdGhlIGZ1bmN0aW9uIGZvcm0gb2YgKmYqIHZlcnkgd2VsbCBhdCBhbGwuX18NCisgKGQpIFRoZSB2YXJpYW5jZSBvZiB0aGUgZXJyb3IgdGVybXMsIGkuZS4gz4MyID0gVmFyKCpFKiksIGlzIGV4dHJlbWVseSBoaWdoLiBfX1dvcnNlLiBBZ2Fpbiwgd2UgcnVuIHRoZSByaXNrIG9mIG92ZXJmaXR0aW5nIGlmIHdlIGZpdCBhIG1vZGVsIHRoYXQgaXMgdG9vIGZsZXhpYmxlIGFuZCBmdW5jdGlvbmFsbHkgbWlycm9ycyB0aGUgcmVzaWR1YWxzLl9fDQoNCjIuIEV4cGxhaW4gd2hldGhlciBlYWNoIHNjZW5hcmlvIGlzIGEgKmNsYXNzaWZpY2F0aW9uKiBvciAqcmVncmVzc2lvbiogcHJvYmxlbSwNCmFuZCBpbmRpY2F0ZSB3aGV0aGVyIHdlIGFyZSBtb3N0IGludGVyZXN0ZWQgaW4gKmluZmVyZW5jZSogb3IgKnByZWRpY3Rpb24qLiBGaW5hbGx5LCBwcm92aWRlICpuKiBhbmQgKnAqLg0KDQorKGEpIFdlIGNvbGxlY3QgYSBzZXQgb2YgZGF0YSBvbiB0aGUgdG9wIDUwMCBmaXJtcyBpbiB0aGUgVVMuIEZvciBlYWNoIGZpcm0gd2UgcmVjb3JkIHByb2ZpdCwgbnVtYmVyIG9mIGVtcGxveWVlcywgaW5kdXN0cnkgYW5kIHRoZSBDRU8gc2FsYXJ5LiBXZSBhcmUgaW50ZXJlc3RlZCBpbiB1bmRlcnN0YW5kaW5nIHdoaWNoIGZhY3RvcnMgYWZmZWN0IENFTyBzYWxhcnkuIF9fUmVncmVzc2lvbi1JbmZlcmVuY2UuICpuKj01MDAgKnAqPTRfXw0KDQorKGIpIFdlIGFyZSBjb25zaWRlcmluZyBsYXVuY2hpbmcgYSBuZXcgcHJvZHVjdCBhbmQgd2lzaCB0byBrbm93IHdoZXRoZXIgaXQgd2lsbCBiZSBhIHN1Y2Nlc3Mgb3IgYSBmYWlsdXJlLiBXZSBjb2xsZWN0IGRhdGEgb24gMjAgc2ltaWxhciBwcm9kdWN0cyB0aGF0IHdlcmUgcHJldmlvdXNseSBsYXVuY2hlZC4gRm9yIGVhY2ggcHJvZHVjdA0Kd2UgaGF2ZSByZWNvcmRlZCB3aGV0aGVyIGl0IHdhcyBhIHN1Y2Nlc3Mgb3IgZmFpbHVyZSwgcHJpY2UgY2hhcmdlZCBmb3IgdGhlIHByb2R1Y3QsIG1hcmtldGluZyBidWRnZXQsIGNvbXBldGl0aW9uIHByaWNlLCBhbmQgdGVuIG90aGVyIHZhcmlhYmxlcy4gX19DbGFzc2lmaWNhdGlvbi1wcmVkaWN0aW9uLiAqbio9MjAgKnAqPTE0X18NCg0KKyhjKSBXZSBhcmUgaW50ZXJlc3RlZCBpbiBwcmVkaWN0aW5nIHRoZSAlIGNoYW5nZSBpbiB0aGUgVVNEL0V1cm8gZXhjaGFuZ2UgcmF0ZSBpbiByZWxhdGlvbiB0byB0aGUgd2Vla2x5IGNoYW5nZXMgaW4gdGhlIHdvcmxkIHN0b2NrIG1hcmtldHMuIEhlbmNlIHdlIGNvbGxlY3Qgd2Vla2x5IGRhdGEgZm9yIGFsbCBvZiAyMDEyLiBGb3IgZWFjaCB3ZWVrIHdlIHJlY29yZCB0aGUgJSBjaGFuZ2UgaW4gdGhlIFVTRC9FdXJvLCB0aGUgJSBjaGFuZ2UgaW4gdGhlIFVTIG1hcmtldCwgdGhlICUgY2hhbmdlIGluIHRoZSBCcml0aXNoIG1hcmtldCwNCmFuZCB0aGUgJSBjaGFuZ2UgaW4gdGhlIEdlcm1hbiBtYXJrZXQuIF9fUmVncmVzc2lvbi1JbmZlcmVuY2UuICpuKj01MiAqcCo9M19fDQoNCjMuIFdlIG5vdyByZXZpc2l0IHRoZSBiaWFzLXZhcmlhbmNlIGRlY29tcG9zaXRpb24uDQoNCisoYSkgUHJvdmlkZSBhIHNrZXRjaCBvZiB0eXBpY2FsIChzcXVhcmVkKSBiaWFzLCB2YXJpYW5jZSwgdHJhaW5pbmcgZXJyb3IsIHRlc3QgZXJyb3IsIGFuZCBCYXllcyAob3IgaXJyZWR1Y2libGUpIGVycm9yIGN1cnZlcywgb24gYSBzaW5nbGUNCnBsb3QsIGFzIHdlIGdvIGZyb20gbGVzcyBmbGV4aWJsZSBzdGF0aXN0aWNhbCBsZWFybmluZyBtZXRob2RzIHRvd2FyZHMgbW9yZSBmbGV4aWJsZSBhcHByb2FjaGVzLiBUaGUgeC1heGlzIHNob3VsZCByZXByZXNlbnQgdGhlIGFtb3VudCBvZiBmbGV4aWJpbGl0eSBpbiB0aGUgbWV0aG9kLCBhbmQgdGhlIHktYXhpcyBzaG91bGQNCnJlcHJlc2VudCB0aGUgdmFsdWVzIGZvciBlYWNoIGN1cnZlLiBUaGVyZSBzaG91bGQgYmUgZml2ZSBjdXJ2ZXMuIE1ha2Ugc3VyZSB0byBsYWJlbCBlYWNoIG9uZS4gX19TZWUgYXR0YWNoZWQganBlZy4NCg0KKyhiKSBFeHBsYWluIHdoeSBlYWNoIG9mIHRoZSBmaXZlIGN1cnZlcyBoYXMgdGhlIHNoYXBlIGRpc3BsYXllZCBpbiBwYXJ0IChhKS4gDQoNCj4gX19BcyB3ZSBhcHByb3hpbWF0ZSBhIG1vcmUgZmxleGlibGUgbW9kZWwsIGF0IGZpcnN0IHRoZSBiaWFzIGRlY3JlYXNlcyBhdCBhIHJhdGUgZ3JlYXRlciB0aGFuIHRoZSB2YXJpYW5jZSBpcyBpbmNyZWFzaW5nLiBIb3dldmVyLCBldmVudHVhbGx5IGFzIHdlIGFkZCBmbGV4aWJpbGl0eSBwYXN0IHRoZSBvcHRpbWFsIGZ1bmN0aW9uYWwgZm9ybSB0aGUgdmFyaWFuY2UgaW5jcmVhc2VzIGF0IGEgcmF0ZSBncmVhdGVyIHRoYW4gdGhlIGJpYXMgaXMgZGVjcmVhc2luZy4gQXQgdGhpcyBwb2ludCwgYWx0aG91Z2ggb3VyIHRyYWluaW5nIE1TRSBtYXkgYmUgZGVjcmVhc2luZyB3ZSBhcmUgYmVnaW5uaW5nIHRvIG92ZXJmaXQgdGhlIGRhdGEuIFRodXMsIGl0IGlzIHVubGlrZWx5IHRoYXQgb3VyIHRyYWluaW5nIHNldCB3aWxsIGZpdCBvdXIgdGVzdCBzZXQgdmVyeSB3ZWxsIGFuZCBwYXN0IHRoZSBvcHRpbWFsIGxldmVsIG9mIGZsZXhpYmlsaXR5IGZvciBvdXIgcGFydGljdWxhciBkYXRhIGFuZCBxdWVzdGlvbiBvdXIgdHJhaW5pbmcgTVNFIGFuZCB0ZXN0IE1TRSBkZXZpYXRlOyB0aGUgZm9ybWVyIGRlY3JlYXNpbmcgYW5kIHRoZSBsYXR0ZXIgaW5jcmVhc2luZy4gVGhlIGlycmVkdWNpYmxlIGVycm9yIGlzIGZ1bmRhbWVudGFsbHkgdW5rbm93YWJsZSBhbmQgaXMganVzdCByZXByZXNlbnRlZCBieSBhIGhvcml6b250YWwgbGluZSBpbmRlcGVuZGVudCBvZiB0aGUgb3RoZXIgZmFjdG9ycywgYnV0IGFsd2F5cyBiZWxvdyBvdXIgdGVzdCBNU0UgYmVjYXVzZSB0aGUgdGVzdCBNU0UgY29udGFpbnMgdGhlIGlycmVkdWNpYmxlIGVycm9yLl9fDQoNCjQuIF9fU2tpcHBlZF9fDQoNCjUuIFdoYXQgYXJlIHRoZSBhZHZhbnRhZ2VzIGFuZCBkaXNhZHZhbnRhZ2VzIG9mIGEgdmVyeSBmbGV4aWJsZSAodmVyc3VzIGEgbGVzcyBmbGV4aWJsZSkgYXBwcm9hY2ggZm9yIHJlZ3Jlc3Npb24gb3IgY2xhc3NpZmljYXRpb24/IFVuZGVyIHdoYXQgY2lyY3Vtc3RhbmNlcyBtaWdodCBhIG1vcmUgZmxleGlibGUgYXBwcm9hY2ggYmUgcHJlZmVycmVkIHRvIGEgbGVzcyBmbGV4aWJsZSBhcHByb2FjaD8gV2hlbiBtaWdodCBhIGxlc3MgZmxleGlibGUgYXBwcm9hY2ggYmUgcHJlZmVycmVkPyANCg0KX19BZHZhbnRhZ2VzOiBiZXR0ZXIgZml0cyB0aGUgdmFsdWVzIGlmIHRoZSB0cnVlIGZ1bmN0aW9uYWwgZm9ybSBvZiB0aGUgZGF0YSBpcyBub3QgbGluZWFyIGFuZCByZWR1Y2VzIHRoZSBiaWFzIG9mIG91ciBlc3RpbWF0ZWQgcGFyYW1ldGVycy5fXyANCg0KX19EaXNhZHZhbnRhZ2VzOiBpZiB0aGUgZGF0YSBpcyBsaW5lYXIsIHRoZW4gYSBtb3JlIGZsZXhpYmxlIGFwcHJvYWNoIHJ1bnMgdGhlIHJpc2sgb2Ygb3ZlcmZpdHRpbmcgdGhlIGRhdGEuIEl0IGFsc28gcmVxdWlyZXMgbW9yZSBwYXJhbWV0ZXJzIGFuZCBpbmNyZWFzZXMgdGhlIHZhcmlhbmNlLl9fDQoNCl9fSWYgdGhlIGRhdGEgaXMgbm9uLWxpbmVhciBhIG1vcmUgZmxleGlibGUgYXBwcm9hY2ggaXMgcHJlZmVycmVkLiBJZiB0aGUgdHJhZGVvZmYgaXMgb25lIHN1Y2ggdGhhdCBhIG1vcmUgZmxleGlibGUgbW9kZWwgbGVhZHMgdG8gYSBzaWduaWZpY2FudCByZWR1Y3Rpb24gaW4gdGhlIGJpYXMgYW5kIG9ubHkgYSBzbWFsbCBpbmNyZWFzZSBpbiB0aGUgdmFyaWFuY2U7IGEgbW9yZSBmbGV4aWJsZSBhcHByb2FjaCBpcyBwcmVmZXJhYmxlLl9fDQoNCl9faWYgdGhlIGRhdGEgaXMgdmVyeSBsaW5lYXIsIGEgbW9yZSByaWdpZCBhcHByb2FjaCBpcyBwcmVmZmVyZWQuIElmIHRoZSB0cmFkZW9mZiBpcyBvbmUgc3VjaCB0aGF0IGEgbGVzcyBmbGV4aWJsZSBtb2RlbCBvbmx5IGluY3JlYXNlcyB0aGUgYmlhcyBzbGlnaHRseSwgYnV0IGdyZWF0bHkgcmVkdWNlcyB0aGUgdmFyaWFuY2U7IGEgbGVzcyBmbGV4aWJsZSBhcHByb2FjaCBpcyBwcmVmZXJhYmxlLl9fDQoNCl9fQSBtb3JlIGZsZXhpYmxlIGFwcHJvYWNoIGlzIHByZWZlcnJlZCB3aGVuIHdlIG1vcmUgaW50ZXJlc3RlZCBpbiBwb3dlciBvZiBwcmVkaWN0aW9uIGFzIG9wcG9zZWQgdG8gaW50ZXJwcmV0YWJpbGl0eSB0aGUgcmVzdWx0cy5fXw0KDQpfX0EgbGVzcyBmbGV4aWJsZSBhcHByb2FjaCB3b3VsZCBiZSBwcmVmZXJyZWQgaWYgd2Ugd2VyZSBtb3JlIGludGVyZXN0ZWQgaW4gaW50ZXJwcmV0aW5nIHRoZSBwYXJhbWF0ZXJzIGFzIG9wcG9zZWQgdG8gc2ltcGx5IHByZWRpY3RpbmcgYSByZXNwb25zZS5fXw0KDQo2LikgRGVzY3JpYmUgdGhlIGRpZmZlcmVuY2VzIGJldHdlZW4gYSBwYXJhbWV0cmljIGFuZCBhIG5vbi1wYXJhbWV0cmljIHN0YXRpc3RpY2FsIGxlYXJuaW5nIGFwcHJvYWNoLiBXaGF0IGFyZSB0aGUgYWR2YW50YWdlcyBvZiBhIHBhcmFtZXRyaWMgYXBwcm9hY2ggdG8gcmVncmVzc2lvbiBvciBjbGFzc2lmaWNhdGlvbiAoYXMgb3Bwb3NlZCB0byBhIG5vbi1wYXJhbWV0cmljIGFwcHJvYWNoKT8gV2hhdCBhcmUgaXRzIGRpc2FkdmFudGFnZXM/DQoNCl9fQSBwYXJhbWV0cmljIGFwcHJvYWNoIGFzc3VtZXMgYSBmdW5jdGlvbmFsIGZvcm0gb2YgKmYqIGFuZCB0aHVzIHJlZHVjZXMgcmVncmVzc2lvbiBhbmQgY2xhc3NpZmljYXRpb24gcHJvYmxlbXMgZG93biB0byBhcHByb3hpbWF0aW5nIGEgc2V0IG9mIHBhcmFtZXRlcnMgYW5kIHRoZW4gaW50ZXJwcmV0aW5nIHRoZSByZXN1bHRzIG9yIHByZWRpY3RpbmcgYSByZXNwb25zZS4gSXQgcmVxdWlyZXMgZmV3ZXIgb2JzZXJ2YXRpb25zIHRoYW4gZG8gbm9uLXBhcmFtZXRyaWMgYXBwcm9hY2hlcy5fXw0KDQpfX0Egbm9uLXBhcmFtZXRyaWMgYXBwcm9hY2ggZG9lcyBub3QgbWFrZSBhbnkgYXNzdW1wdGlvbiBhYm91dCB0aGUgZnVuY3Rpb25hbCBmb3JtIG9mICpmKi4gUmF0aGVyIGl0IHJlcXVpcmVzIGEgbGFyZ2UgKm4qIHRvIGFjY3VyYXRlbHkgZXN0aW1hdGUgdGhlIGZ1bmN0aW9uYWwgZm9ybSBvZiAqZiouX18NCg0KX19BZHZhbnRhZ2VzIG9mIHBhcmFtZXRyaWMgYXBwcm9hY2ggdG8gcmVncmVzc2lvbiBvciBjbGFzc2lmaWNhdGlvbjogZG9lcyBub3QgcmVxdWlyZSBhcyBncmVhdCBhbiAqbiogYW5kIGNhbiBiZSBlc3RpbWF0ZWQgd2l0aCByZWxhdGl2ZWx5IGZld2VyIHBhcmFtZXRlcnMuX18NCg0KX19EaXNhZHZhbnRhZ2VzIG9mIHBhcmFtZXRyaWMgYXBwcm9hY2ggdG8gcmVncmVzc2lvbiBvciBjbGFzc2lmaWNhdGlvbjogcnVuIHRoZSByaXNrIG9mIGFwcHJveGltYXRpbmcgYSBmdW5jdGlvbmFsIGZvcm0gb2YgKmYqIHRoYXQgaXMgZmFyIGZyb20gdGhlIHRydWUgKmYqLiBBbHNvLCBydW4gdGhlIHJpc2sgb2Ygb3ZlcmZpdHRpbmcgdGhlIG1vZGVsIHZpYSB0aGUgdXNlIG9mIG1vcmUgZmxleGlibGUgbW9kZWxzIHdoZW4gbm90IGFwcHJvcHJpYXRlLl9fDQoNCjcuKSBfX1NraXBwZWRfXw0KDQojIyMjIF9fKkFwcGxpZWRfXw0KDQo4LikgVGhpcyBleGVyY2lzZSByZWxhdGVzIHRvIHRoZSAqQ29sbGVnZSogZGF0YSBzZXQsIHdoaWNoIGNhbiBiZSBmb3VuZCBpbiB0aGUgZmlsZSAqQ29sbGVnZS5jc3YqLiBJdCBjb250YWlucyBhIG51bWJlciBvZiB2YXJpYWJsZXMgZm9yIDc3NyBkaWZmZXJlbnQgdW5pdmVyc2l0aWVzIGFuZCBjb2xsZWdlcyBpbiB0aGUgVVMuDQoNCl9fTG9hZCB0aGUgZGF0YV9fDQpgYGB7cn0NCkNvbGxlZ2U9cmVhZC5jc3YoIkNvbGxlZ2UuY3N2IixoZWFkZXI9VCkNCmBgYA0KX19BZGQgYSBuZXcgY29sdW1uIGZvciBhbGwgcm93cyBpbiBjb2x1bW4gb25lLiBWaWV3IHRoZSBkYXRhX18NCmBgYHtyfQ0Kcm93bmFtZXMoQ29sbGVnZSk9Q29sbGVnZVssMV0NCmZpeChDb2xsZWdlKQ0KYGBgDQpfX0VsaW1pbmF0ZXMgdGhlIGZpcnN0IGNvbHVtbiBpbiB0aGUgZGF0YSB3aGVyZSB0aGUgbmFtZXMgYXJlIHN0b3JlZC4gKk5vdGUqIHRoZSBhY3R1YWwgcm93IG9mIGNvbGxlZ2UgbmFtZXMgaXMgbm90IGEgc3RvcmVkIGRhdGEgY29sdW0uX18NCmBgYHtyfQ0KQ29sbGVnZT1Db2xsZWdlWywtMV0NCmZpeChDb2xsZWdlKQ0KYGBgDQpfX1N1bW1hcml6ZSB0aGUgZGF0YS4gKk5vdGUgdGhlIGNvbGxlZ2UgbmFtZXMgYXJlIG5vdCBzdG9yZWQgYXMgYSBkYXRhIGNvbHVtbi4qX18NCmBgYHtyfQ0Kc3VtbWFyeShDb2xsZWdlKQ0KYGBgDQpfX0NyZWF0ZSBhIHNjYXR0ZXJwbG90IG9mIHRoZSBmaXJzdCB0ZW4gdmFyaWFibGVzIG9mIHRoZSBkYXRhLl9fDQpgYGB7cn0NCnBhaXJzKENvbGxlZ2VbLDE6MTBdKQ0KYGBgDQpfX1Bsb3QgT3V0c3RhdGUgdnMuIFByaXZhdGVfXw0KYGBge3J9DQpwbG90KENvbGxlZ2UkT3V0c3RhdGUsY29sPSJncmVlbiIpDQpwbG90KENvbGxlZ2UkUHJpdmF0ZSxjb2w9InJlZCIpDQpgYGANCl9fQ3JlYXRlIGEgbmV3IHF1YWxpdGF0aXZlIHZhcmlhYmxlICJFbGl0ZSJfXw0KYGBge3J9DQpFbGl0ZT1yZXAoIk5vIixucm93KENvbGxlZ2UpKQ0KRWxpdGVbQ29sbGVnZSRUb3AxMHBlcmMgPjUwXT0iWWVzIg0KRWxpdGU9YXMuZmFjdG9yKEVsaXRlKQ0KQ29sbGVnZT1kYXRhLmZyYW1lKENvbGxlZ2UsRWxpdGUpDQpgYGANCl9fU3VtbWFyeSBvZiBob3cgbWFueSBFbGl0ZSB2cyBub24tZWxpdGUgY29sbGVnZXNfXw0KYGBge3J9DQpzdW1tYXJ5KEVsaXRlKQ0KYGBgDQpfX0JveHBsb3RzIG9mIEVsaXRlIHZzIE91dHN0YXRlIHR1aXRpb25fXw0KYGBge3J9DQpwbG90KENvbGxlZ2UkRWxpdGUsQ29sbGVnZSRPdXRzdGF0ZSkNCmBgYA0KX19IaXN0b2dyYW1zIG9mIGRpZmZlcmVudCBxdWFudGlhdGl2ZSB2YXJpYWJsZXMgd2l0aCBkaWZmZXJlbnQgYmluc19fDQpgYGB7cn0NCnBhcihtZnJvdz1jKDIsMikpDQpoaXN0KENvbGxlZ2UkQXBwcyxjb2w9InJlZCIsYnJlYWtzPTcpDQpoaXN0KENvbGxlZ2UkQWNjZXB0LGNvbD0iZ3JlZW4iLGJyZWFrcz00KQ0KaGlzdChDb2xsZWdlJEVucm9sbCxjb2w9Im9yYW5nZSIsYnJlYWtzPTUpDQpgYGANCg0KIyMjIyBfXzkuIFRoaXMgZXhlcmNpc2UgaW52b2x2ZXMgdGhlIEF1dG8gZGF0YSBzZXQgc3R1ZGllZCBpbiB0aGUgbGFiLiBNYWtlIHN1cmUgdGhhdCB0aGUgbWlzc2luZyB2YWx1ZXMgaGF2ZSBiZWVuIHJlbW92ZWQgZnJvbSB0aGUgZGF0YS5fXw0KX19JbXBvcnQgdGhlIGRhdGEsIHNwZWNpZnkgaGVhZGVycyBpbiB0aGUgdG9wIHJvdyBhbmQgZGVmaW5lIG1pc3NpbmcgdmFyaWFibGVzIGFzICJOQSJfXy4NCmBgYHtyfQ0KQXV0bz1yZWFkLnRhYmxlKCJBdXRvLmRhdGEiLGhlYWRlcj1ULG5hLnN0cmluZ3M9Ij8iKQ0KQXV0bz1uYS5vbWl0KEF1dG8pDQpkaW0oQXV0bykNCnN1bW1hcnkoQXV0bykNCmBgYA0KDQpfXypRdWFudGl0YXRpdmUqX186IG1wZywgZGlzcGxhY2VtZW50LCBob3JzZXBvd2VyLCB3ZWlnaHQsIGFjY2VsZXJhdGlvbiBhbmQgeWVhcg0KDQpfXypRdWFsaXRhdGl2ZSpfXzogY3lsaW5kZXJzIGFuZCBvcmlnaW4NCg0KX19SYW5nZSBvZiBxdWFudGl0YXRpdmUgdmFyaWFibGVzX18NCmBgYHtyfQ0KUmFuZ2U9YXBwbHkoQXV0b1ssLWMoMiw4LDkpXSwyLHJhbmdlKQ0Kcm93Lm5hbWVzKFJhbmdlKT1jKCJNaW4iLCJNYXgiKQ0KUmFuZ2UNCmBgYA0KDQpfX01lYW4gYW5kIFN0YW5kYXJkIERldmlhdGlvbiBvZiBRdWFudGlhdGl2ZSBWYXJpYWJsZXNfXw0KYGBge3J9DQpTRF9NZWFuPWFwcGx5KEF1dG9bLC1jKDIsOCw5KV0sMixmdW5jdGlvbih4KXtjKG1lYW4oeCksc2QoeCkpfSkNCnJvdy5uYW1lcyhTRF9NZWFuKT1jKCJNZWFuIiwiU3RhbmRhcmQgRGV2aWF0aW9uIikNClNEX01lYW4NCmBgYA0KX19SYW5nZSBleGNsdWRpbmcgcm93cyAxMC02NV9fDQpgYGB7cn0NClJhbmdlMj1hcHBseShBdXRvWy1jKDEwOjg1KSwtYygyLDgsOSldLDIscmFuZ2UpDQpyb3cubmFtZXMoUmFuZ2UyKT1jKCJNaW4iLCJNYXgiKQ0KUmFuZ2UyDQpgYGANCl9NZWFuIGV4Y2x1ZGluZyByb3dzIDEwLTg1X18NCmBgYHtyfQ0KTWVhbjI9YXBwbHkoQXV0b1stYygxMDo4NSksLWMoMiw4LDkpXSwyLG1lYW4pDQpNZWFuMg0KYGBgDQpfX1N0YW5kYXJkIERldmlhdGlvbiBleGNsdWRpbmcgcm93cyAxMC04NV9fDQpgYGB7cn0NClNEMj1hcHBseShBdXRvWy1jKDEwOjg1KSwtYygyLDgsOSldLDIsc2QpDQpTRDINCmBgYA0KX19Ob3cgam9pbmluZyBtZWFuIGFuZCBTRF9fDQpgYGB7cn0NCk1FQU5fU0QyPWFwcGx5KEF1dG9bLWMoMTA6ODUpLC1jKDIsOCw5KV0sMixmdW5jdGlvbih4KXtjKG1lYW4oeCksc2QoeCkpfSkNCnJvdy5uYW1lcyhNRUFOX1NEMik9YygiTWVhbiIsIlN0YW5kYXJkX0RldmlhdGlvbiIpDQpNRUFOX1NEMg0KYGBgDQoNCl9fR3JhcGhpY2FsIGRlcGljdGlvbnMgb2YgdGhlIGRhdGFfXw0KYGBge3J9DQpib3hwbG90KEF1dG8kbXBnfkF1dG8kY3lsaW5kZXJzLGNvbD0icmVkIix4bGFiPSJDeWxpbmRlcnMiLHlsYWI9Ik1QRyIsbWFpbj0iTVBHIGJ5ICMgb2YgQ3lsaW5kZXJzIikNCnNjYXR0ZXIuc21vb3RoKEF1dG8keWVhcixBdXRvJG1wZyxjb2w9ImdyZWVuIix4bGFiPSJZZWFyIix5bGFiPSJNUEciLG1haW49Ik1wZyBieSBZZWFyIikNCnBhaXJzKEF1dG8pDQpib3hwbG90KEF1dG8kbXBnfkF1dG8kb3JpZ2luLGNvbD0iZ3JleSIseGxhYj0iQ291bnRyeSBvZiBPcmlnaW4iLHlsYWI9Ik1QRyIsbWFpbj0iTVBHIGJ5IENvdW50cnkgb2YgT3JpZ2luIixuYW1lcz1jKCJBbWVyaWNhbiIsIkV1cm9wZWFuIiwiSmFwYW5lc2UiKSkNCmBgYA0KDQojIyMjIF9fMTAuIFRoaXMgZXhlcmNpc2UgaW52b2x2ZXMgdGhlICpCb3N0b24qIGhvdXNpbmcgZGF0YSBzZXQuX18NCg0KYGBge3J9DQpsaWJyYXJ5KE1BU1MpDQpCb3N0b24NCj9Cb3N0b24NCmBgYA0KDQpgYGB7cn0NCmRpbShCb3N0b24pDQpgYGANCg0KKkZpbmRpbmcgaW5kaWNhdGUgdGhhdCBwcmVkb21pbmFudGx5IEFmcmljYW4gQW1lcmljYW4gdG93bnMgaGF2ZSBsb3dlciBjcmltZSByYXRlcy4qDQpgYGB7cn0NCnBhcihtZnJvdz1jKDIsMikpDQpzY2F0dGVyLnNtb290aChCb3N0b24kcHRyYXRpbyxCb3N0b24kbHN0YXQseGxhYj0iUHVwaWwtdG8tdGVhY2hlciBSYXRpbyIseWxhYj0iJSBvZiBMb3dlciBDbGFzcyBQb3AiLG1haW49IlBUIFJhdGlvIGJ5ICUgb2YgTG93ZXIgU3RhdHVzIixjb2w9ImJsdWUiKQ0KYm94cGxvdChCb3N0b24kbWVkdn5Cb3N0b24kcmFkLGNvbD0iZ3JlZW4iLHhsYWI9IkluZGV4IG9mIEFjY2Vzc2liaWxpdHkgdG8gUmFkaWFsIEhpZ2h3YXlzIix5bGFiPSJNZWRpYW4gSG9tZSBWYWx1ZSIsbWFpbj0iTWVkaWFuIEhvbWUgVmFsdWUiKQ0Kc2NhdHRlci5zbW9vdGgoQm9zdG9uJGNyaW0sQm9zdG9uJGJsYWNrLGNvbD0icmVkIix4bGFiPSJDcmltZSBSYXRlIix5bGFiPSJQcm9wb3J0aW9uIG9mIEJsYWNrcyBieSBUb3duIixtYWluPSJDcmltZSBSYXRlIGJ5IFByb3BvcnRpb24gb2YgQmxhY2tzIikNCmBgYA0KKkFsc28sIGl0IHNlZW1zIHRoYXQgYXJlYXMgd2l0aCBoaWdoZXIgcGVyY2VudGFnZXMgb2YgdGhlIHBvcHVsYXRpb24gY2xhc3NpZmllZCBhcyAibG93ZXIgc3RhdHVzIiBhbHNvIGhhdmUgaGlnaGVyIHB1cGlsLXRvLXRlYWNoZXIgcmF0aW9zLiBUaGlzIG1lYW5zIHRoYXQgdGVhY2hlcnMgaW4gbW9yZSAiaW1wb3ZlcmlzaGVkIiBhcmVhcyBhcmUgaGF2aW5nIHRvIGRvIG1vcmUuKg0KDQoqSSBhbSBub3Qgc3VyZSB3aGF0IHRoZSBpbmRleCBvZiBhY2Nlc3NpYmlsaXR5IHRvIHJhZGlhbCBoaWdod2F5cyBpcywgYnV0IGl0IHNlZW1zIGNsZWFyIHRoYXQgaW4gdGhlIGNhc2Ugb2YgIjI0IiBpdCBpcyBsaW5rZWQgdG8gbG93ZXIgbWVkaWFuIGhvbWUgdmFsdWVzLiBIb3dldmVyLCB0aGUgZGlzcGVyc2lvbiBvZiB2YWx1ZXMgaXMgb2Ygc29tZSBub3RlLioNCg0KYGBge3J9DQpwbG90KEJvc3RvbiRjcmltKQ0KaWRlbnRpZnkoQm9zdG9uJGNyaW0pDQpgYGANCl9fVGhlIGFib3ZlIHZhbHVlcyBhcmUgYWxsIHRvd24gY29kZXMgdGhhdCBoYXZlIGV4dHJlbWVseSBoaWdoIGNyaW1lIHJhdGVzLl9fDQoNCmBgYHtyfQ0Kc2VsZWN0aW9uID0gQm9zdG9uWywiY2hhcyJdDQpucm93KEJvc3RvbltzZWxlY3Rpb24sXSkNCmBgYA0KDQpgYGB7cn0NCm1lZGlhbihCb3N0b24kcHRyYXRpbykNCmBgYA0KDQpgYGB7cn0NCnBsb3QoQm9zdG9uJG1lZHYpDQppZGVudGlmeShCb3N0b24kbWVkdikNCmBgYA0KDQpgYGB7cn0NCnByaW50KEJvc3RvblszOTksXSkNCmBgYA0KDQpgYGB7cn0NClJhbmdlMz1hcHBseShCb3N0b25bLF0sMixyYW5nZSkNCnJvdy5uYW1lcyhSYW5nZTMpPWMoIk1pbiIsIk1heCIpDQpSYW5nZTMNCmBgYA0KDQpgYGB7cn0NCk1vcmVUaGFuU2V2ZW49cmVwKCJObyIsbnJvdyhCb3N0b24pKQ0KTW9yZVRoYW5TZXZlbltCb3N0b24kcm0+N109IlllcyINCmFzLmZhY3RvcihNb3JlVGhhblNldmVuKQ0KQm9zdG9uPWRhdGEuZnJhbWUoQm9zdG9uLE1vcmVUaGFuU2V2ZW4pDQpzdW1tYXJ5KEJvc3RvbiRNb3JlVGhhblNldmVuKQ0KYGBgDQoNCmBgYHtyfQ0KbW9yZXRoYW5laWdodD1yZXAoIk5vIixucm93KEJvc3RvbikpDQptb3JldGhhbmVpZ2h0W0Jvc3RvbiRybT44XT0iWWVzIg0KYXMuZmFjdG9yKG1vcmV0aGFuZWlnaHQpDQpCb3N0b249ZGF0YS5mcmFtZShCb3N0b24sbW9yZXRoYW5laWdodCkNCnN1bW1hcnkoQm9zdG9uJG1vcmV0aGFuZWlnaHQpDQpgYGANCg0KDQoNCg0KDQoNCg==