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:

  1. Which predictors are associated with the response?
  2. What is the relationship between the response and each predictor?
  3. 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

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

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

  1. Skipped

  2. 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==