Correlations
Everything correlates with everything, which Paul Meehl calls the
“crud factor” (aka Ambient Correlational Noise) (See Meehl, 1990ab and
Lykken, 1968 cited by Meehl). Our goal is to determine how much and we
will deal with 2 variables at a time, but we will soon explore the
problems with 3 or more variables.
A few popular correlations between two variables:
- Pearson’s r (interval by interval) [for population = \(\rho\), for sample = \(r\)]
- Spearman’s rho (interval by ordinal) [for population = \(\rho_{s}\), for sample = \(r_s\)]
- Kendall’s tau [\(t\)] (interval by
ordinal or ordinal by ordinal) like Spearman’s, but more accurate with
small samples
- Point-by-serial (interval by dichotomous)
- Polychoric (ordinal vs ordinal) [used more in psychometrics or
factor analysis of ordinal by ordinal]
- Tetrachroic (dichotomous vs dichotomous) [used more in psychometrics
or factor analysis of dichotomous by dichotomous]
In general these assume bivariate normality, which means that the two
variables are normally distributed when added together (and
independently). The bivariate normal distribution is a three-dimensional
normal curve.
Pearson’s Correlation
Most common type you will encounter and is a parametric method.
\[r_{xy}=\frac{\sum{(X-M_X)(Y-M_Y)}}{\sqrt{\sum(X-M_X)^2\sum(Y-M_Y)^2}}\]
remember \(SS = (X-M)^2\), so thus,
\[r_{xy}=\frac{SP}{\sqrt{SS_XSS_Y}}\]
- Numerator = How much they vary together (covariance)
- Denominator = The product of how much they vary alone
(variance)
- Values are bounded between -1 and 1
or more simply (see Cohen’s textbook for the derivation):
\[r_{xy}=\frac{\sum{xy}}{\sqrt{\sum{x^2}\sum{y^2}}}\]
Simulate Data
We will use the mvrnorm
function (multivariate normal
distribution) from the MASS package, but to do this we need to
make a covariance matrix with a \(r = .60\) and set the mean values for each
variable (which I will set to 5 for each)
#Set params
Means.XY<- c(5,5) #set the means of X and Y variables
r=.6 #Correlation value
CovMatrix.XY <- matrix(c(1,r,
r,1),2,2) # creates the covariate matrix
# Build the correlated variables using mvrnorm.
# Note: empirical=TRUE means make the correlation EXACTLY r.
# empirical=FALSE, the correlation value would be normally distributed around r
library(MASS) #create data
CorrData<-mvrnorm(n=100, mu=Means.XY,Sigma=CovMatrix.XY, empirical=TRUE)
#Convert them to a "Data.Frame", which is like SPSS data window
CorrData<-as.data.frame(CorrData)
#lets add our labels to the vectors we created
colnames(CorrData) <- c("Happiness","IceCream")
Plot the data
#make the scatter plot
library(ggpubr) #graph data
ggscatter(CorrData, x = "IceCream", y = "Happiness",
add = "reg.line", # Add regressin line
add.params = list(color = "blue", fill = "lightgray"), # Customize reg. line
conf.int = TRUE, # Add confidence interval
cor.coef = FALSE, # Add correlation coefficient. see ?stat_cor
)
Run Pearson’s r
The cor.test
function runs Pearson’s correlation.
Note: You will notice that I have attached the data
frame to each variable.
Corr.Result.1<-cor.test(CorrData$Happiness, CorrData$IceCream,
method = c("pearson"))
Corr.Result.1
##
## Pearson's product-moment correlation
##
## data: CorrData$Happiness and CorrData$IceCream
## t = 7.4246, df = 98, p-value = 4.193e-11
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
## 0.4574985 0.7124547
## sample estimates:
## cor
## 0.6
You can also call the function via a formula command.
Corr.Result.1<-cor.test(~Happiness + IceCream, data= CorrData,
method = c("pearson"))
Pvalue on Pearson’s Correlation
The classical pvalue on Pearson’s correlation is adapted from the
t-distribution. We will come back to later when we cover linear
regression.
Pearson’s correlation is scale-independent!
No matter the mean differences or range of scores, the Pearson’s r
will give the same results. We can also z-score the data and get the
same result. However, if they are scaled non-linearly (sqrt, ^2, log,…)
the correlation will change.
Lets add (change the mean)
CorrData$Happiness.big<-CorrData$Happiness+1000
ggscatter(CorrData, x = "IceCream", y = "Happiness.big",
add = "reg.line", # Add regressin line
add.params = list(color = "blue", fill = "lightgray"), # Customize reg. line
conf.int = TRUE, # Add confidence interval
cor.coef = TRUE, # Add correlation coefficient. see ?stat_cor
)
cor_apa(cor.test(CorrData$Happiness.big, CorrData$IceCream,
method = c("pearson")),format ="text")
## r(98) = .60, p < .001
Z-scored
Remember that, \(Z =
\frac{X-M}{S}\)
CorrData$Happiness.z<-scale(CorrData$Happiness)
CorrData$IceCream.z<-scale(CorrData$IceCream)
ggscatter(CorrData, x = "IceCream.z", y = "Happiness.z",
add = "reg.line", # Add regressin line
add.params = list(color = "blue", fill = "lightgray"), # Customize reg. line
conf.int = TRUE, # Add confidence interval
cor.coef = TRUE, # Add correlation coefficient. see ?stat_cor
)
cor_apa(cor.test(CorrData$Happiness.z, CorrData$IceCream.z,
method = c("pearson")),format ="text")
## r(98) = .60, p < .001
What happens if I LINEARLY scale them differently?
ggscatter(CorrData, x = "IceCream.z", y = "Happiness.big",
add = "reg.line", # Add regressin line
add.params = list(color = "blue", fill = "lightgray"), # Customize reg. line
conf.int = TRUE, # Add confidence interval
cor.coef = TRUE, # Add correlation coefficient. see ?stat_cor
)
cor_apa(cor.test(CorrData$Happiness.big, CorrData$IceCream.z,
method = c("pearson")),format ="text")
## r(98) = .60, p < .001
What happens if I NON-LINEARLY scale them differently?
CorrData$Happiness<-CorrData$Happiness # orginal
CorrData$IceCream.sq4<-(CorrData$IceCream)^4 #Non-linear
ggscatter(CorrData, x = "IceCream.sq4", y = "Happiness",
add = "reg.line", # Add regressin line
add.params = list(color = "blue", fill = "lightgray"), # Customize reg. line
conf.int = TRUE, # Add confidence interval
cor.coef = TRUE, # Add correlation coefficient. see ?stat_cor
)
cor_apa(cor.test(CorrData$Happiness, CorrData$IceCream.sq4,
method = c("pearson")),format ="text")
## r(98) = .54, p < .001
Pearson’s: Let visualize our result
The overlap between the two variables is defined by \(r^2\)
# lets us plot our results (like the book)
library(VennDiagram)
# calculate r-squared
overlap=r^2
Simple.Corr.Venn<-draw.pairwise.venn(1, 1, overlap, c("Happiness", "IceCream"))
grid.draw(Simple.Corr.Venn)
This means that 36% of the variance of happiness overlaps with ice
cream consumption. Can we conclude ice cream causes happiness? No,
because we did not design a study with a control group. We can not infer
causation. It seems to make sense to say “eating ice cream causes me to
be happy”, but the opposite could be true as well “happiness causes me
to eat ice cream”. How do I know which causes which? We cannot without
an experiment.
Non-Parametric Correlations
Spearmen and Kendall correlation can be used for ordinal data, but
should be used if you have a “bend” (non-linear relationship) between
variables.
Spearmen’s Correlation
Spearman is a Pearson Correlation on rank-ordered data. Let’s rank
order our random correlated data. You must rank each variable
independently first (where ties are averaged).
CorrData$Happiness.rank<-rank(CorrData$Happiness)
CorrData$IceCream.rank<-rank(CorrData$IceCream)
ggscatter(CorrData, x = "IceCream.rank", y = "Happiness.rank",
add = "reg.line", # Add regressin line
add.params = list(color = "blue", fill = "lightgray"), # Customize reg. line
conf.int = TRUE, # Add confidence interval
)
cor_apa(cor.test(CorrData$IceCream.rank, CorrData$Happiness.rank, method = c("pearson")))
## r(98) = .61, p < .001
You should use the built-in Spearman correlation
(cor.test
, but pass method =
c(“spearman”)) because the pvalues are calculated differently
and ranks the raw data automatically.
# APA format (note the S should be subscript)
cor_apa(cor.test(CorrData$IceCream, CorrData$Happiness,
method = c("spearman")),format ="text")
## r_s = .61, p < .001
Pearson vs Spearman’s Correlation for slight nonlinearity
Let’s say you get some data and clearly there is a slight
nonlinearity in the relationship between the two variables. Pearson is
designed for linear relationships and we can see the problem in our
fitted line below.
CorrNL<-data.frame(Var1=c(0,1,3,5,7,9,12,15,18),
Var2=c(0,3,12,18,19,20,21,22,23))
ggscatter(CorrNL, x = "Var1", y = "Var2",
add = "reg.line", # Add regressin line
add.params = list(color = "blue", fill = "lightgray"), # Customize reg. line
conf.int = TRUE, # Add confidence interval
)
## r(7) = .86, p = .003
If we switch to a Spearman correlation the data are converted to
ranks and the “bump” is now gone and our correlation gets stronger.
CorrNL$Var1.rank<-rank(CorrNL$Var1)
CorrNL$Var2.rank<-rank(CorrNL$Var2)
ggscatter(CorrNL, x = "Var1.rank", y = "Var2.rank",
add = "reg.line", # Add regressin line
add.params = list(color = "blue", fill = "lightgray"), # Customize reg. line
conf.int = TRUE, # Add confidence interval
)
## r_s = 1.00, p < .001
Kendall’s Tau
Kendall tau will always be more conservative than spearman
correlation and is generally more robust (cor.test
, but
pass method = c(“kendall”)). It is safer to use but
less widely known.
# APA format (note the S should be subscript)
cor_apa(cor.test(CorrNL$Var1, CorrNL$Var2,
method = c("kendall"), exact =TRUE),format ="text")
## r_tau = 1.00, p < .001
Ties
One of the problems with Spearman’s and Kendall’s correlation is that
you need to account for ties in the data (two or more people
have the same score; a not uncommon problem in ordinal data). R and SPSS
automatically account for ties and using the exact pvalue parameter will
account for these issues. Thus while I rank ordered the data manually to
show you how it compared to Pearson correlation let the functions in R
do this work for you.
Point-by-Serial Correlation
This correlation is for interval by dichotomous. See the simulation
below. Note: We use to calculate the these by hand in the old days using
t-test and converting the \(d\) into
\(r\) or by just using the Pearson
formula (but these approaches overestimate the correlations).
set.seed(42)
Ratings<-c(rnorm(25,mean=5,sd = .5),rnorm(25,mean=2,sd = .5))
Flavors<-c(rep(0,25),c(rep(1,25)))
FlavorNames<-c(rep("Cookie Dough",25),c(rep("Rum-Raisin",25)))
#Build data frame
Ice.Cream.Data<-data.frame(
Ratings = Ratings,
Flavors = Flavors,
Names = FlavorNames)
#head(Ice.Cream.Data)
ggscatter(Ice.Cream.Data, x = "Flavors", y = "Ratings",
add = "reg.line", # Add regression line
add.params = list(color = "blue", fill = "lightgray"), # Customize reg. line
conf.int = TRUE, # Add confidence interval
)
Calculation of Point-by Serial
using the polycor
package, we can run
polyserial function using maximum-likelihood estimation
(generally more accurate when the underlying distribution is normal). I
will explain MLE function later in the semester.
library(polycor) #Advanced Correlations
PbySerial<-with(Ice.Cream.Data,
polyserial(Flavors,Ratings, ML=TRUE))
PbySerial
## [1] -0.8091302
Polychoric
Most people will default to using a Pearson/Spearman correlation for
ordinal vs ordinal data, but actually that is an inaccurate analysis.
Pearson’s correlation assumes the variances are unbounded, but in
ordinal data the variances that is not the case. Polychoric correlations
are particularly helpful for when you want an accurate factor analysis
of ordinal scales. However, this is only commonly done by people in
educational psychology. These correlations require more data for the
models to converge than Pearson correlations matrices. We will simulate
1-5 Likert scale with the simstudy
package.
library(simstudy)
baseprobs <- matrix(c(0.10, 0.20, 0.10, 0.40,0.20,
0.20, 0.10, 0.30, 0.10,0.30),
nrow = 2, byrow = TRUE)
# generate the data
set.seed(1234)
Ns=genData(50)
SimOrdData <- genCorOrdCat(Ns, adjVar = NULL, baseprobs = baseprobs,
prefix = "Variable", rho = 0.5, corstr = "cs")
SimOrdData<-as.data.frame(SimOrdData)
ggscatter(SimOrdData, x = "Variable1", y = "Variable2",
add = "reg.line", # Add regression line
add.params = list(color = "blue", fill = "lightgray"), # Customize reg. line
conf.int = TRUE, # Add confidence interval
)
library(polycor) #Advanced Correlations
PolyCorrR<-with(SimOrdData,
polychor(Variable1,Variable2, ML=TRUE))
We get a polychroic correlation of 0.59. Compare that to do the
Pearson, r(48) = .53, p < .001, and Spearman, \(r_s\) = .58, p < .001,
correlations.
Tetrachroic
Like Polychoric, but used for dichotomous vs dichotomous. We will
simulate 2 items on a test (that are right [true] or wrong false]) with
the simstudy
package. These assume the bivariate normality
So here we are predicting how well one item on a test predicts the
others. Note
library(simstudy)
baseprobs1 <- matrix(c(0.35, 0.65,
0.50, 0.50),
nrow = 2, byrow = TRUE)
# generate the data
set.seed(1234)
SimOrdData2 <- genCorOrdCat(Ns, adjVar = NULL, baseprobs = baseprobs1,
prefix = "Variable", rho = 0.6, corstr = "cs")
SimOrdData2<-as.data.frame(SimOrdData2)
ggscatter(SimOrdData2, x = "Variable1", y = "Variable2",
add = "reg.line", # Add regression line
add.params = list(color = "blue", fill = "lightgray"), # Customize reg. line
conf.int = TRUE, # Add confidence interval
)
with(SimOrdData2,
polychor(Variable1,Variable2))
## [1] 0.6575174
Correlation Matrices
When we have multiple variables we can compare them all to each other
at once. First we will simulate a 4 variables and all their bivariate
correlations using the mvrnorm function again.
#Set params
Means.XY<- c(5,5,5,5) #set the means of X and Y variables
r12=.6;r13=.1;r14=.5;r23=.1;r24=.8;r34=0; #Correlation values
CovMatrix.XY <- matrix(c(1,r12,r13,r14,
r12,1,r23,r24,
r13,r23,1,r34,
r14,r24,r34,1),4,4) # creates the covariate matrix
# Build the correlated variables using mvrnorm.
# Note: empirical=TRUE means make the correlation EXACTLY r.
# empirical=FALSE, the correlation value would be normally distributed around r
library(MASS) #create data
CorrData2<-mvrnorm(n=100, mu=Means.XY,Sigma=CovMatrix.XY, empirical=TRUE)
#Convert them to a "Data.Frame", which is like SPSS data window
CorrData2<-as.data.frame(CorrData2)
#lets add our labels to the vectors we created
colnames(CorrData2) <- c("Happiness","IceCream", "Sprinkles","Oreos")
We can use the GGally
package to plot Pearson
correlations quickly in an easy to visualize format once the data are in
a data frame.
library(GGally)
CorrPlot <- ggpairs(CorrData2,
lower = list(continuous = "smooth"))
CorrPlot
Power and Regression
For regression, we will need to convert our \(r^2\) into cohen’s \(f^2\)
\[f^2 = \frac{r^2}{1-r^2}\]
Power Calculation
We will use the pwr
package.
library(pwr) #power analysis
#power for GLM
# u = degrees of freedom for numerator
# v = degrees of freedom for denominator
# f2 = effect size
# sig.level= (Type I error probability)
# power = (1 minus Type II error probability)
f2.icecream <- r^2 / (1-r^2)
pwr.f2.test(u = 1, v = n-2, f2 = f2.icecream, sig.level = 0.05, power = NULL)
##
## Multiple regression power calculation
##
## u = 1
## v = 98
## f2 = 0.5625
## sig.level = 0.05
## power = 1
So we had a power of basically 1 given this sample size and our true
effect size of 0.6
A Priori Power Analysis
- What sample size do I need given a specific \(f^2\)
- Note: Gpower might use \(f\), not
\(f^2\)
#power for GLM
# u = degrees of freedom for numerator
# v = degrees of freedom for denominator
# f2 = effect size
# sig.level= (Type I error probability)
# power = (1 minus Type II error probability)
pwr.f2.test(u = 1, v = NULL, f2 = f2.icecream, sig.level = 0.05, power = .80)
##
## Multiple regression power calculation
##
## u = 1
## v = 14.12059
## f2 = 0.5625
## sig.level = 0.05
## power = 0.8
References
Lykken, D. T. (1968). Statistical significance in psychological
research. Psychological bulletin, 70(3p1), 151.
Meehl, P. E. (1990a). Appraising and amending theories: The strategy
of Lakatosian defense and two principles that warrant it.
Psychological inquiry, 1(2), 108-141.
Meehl, P. E. (1990b). Why summaries of research on psychological
theories are often uninterpretable. Psychological reports,
66(1), 195-244.
LS0tDQp0aXRsZTogIkNvcnJlbGF0aW9uIGFuZCBMaW5lYXIgUmVncmVzc2lvbiINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDoNCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMNCiAgICBmb250c2l6ZTogOHB0DQogICAgaGlnaGxpZ2h0OiB0ZXh0bWF0ZQ0KICAgIG51bWJlcl9zZWN0aW9uczogbm8NCiAgICB0aGVtZTogZmxhdGx5DQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZmxvYXQ6DQogICAgICBjb2xsYXBzZWQ6IG5vDQotLS0NCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpDQprbml0cjo6b3B0c19jaHVuayRzZXQobWVzc2FnZSA9IEZBTFNFKQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KHdhcm5pbmcgPSAgRkFMU0UpDQprbml0cjo6b3B0c19jaHVuayRzZXQoZmlnLndpZHRoPTMuNzUpDQprbml0cjo6b3B0c19jaHVuayRzZXQoZmlnLmhlaWdodD0zLjUpDQprbml0cjo6b3B0c19jaHVuayRzZXQoZmlnLmFsaWduPSdjZW50ZXInKSANCmBgYA0KDQpccGFnZWJyZWFrDQoNCiMgQ29ycmVsYXRpb25zDQoNCkV2ZXJ5dGhpbmcgY29ycmVsYXRlcyB3aXRoIGV2ZXJ5dGhpbmcsIHdoaWNoIFBhdWwgTWVlaGwgY2FsbHMgdGhlICJjcnVkIGZhY3RvciIgKGFrYSBBbWJpZW50IENvcnJlbGF0aW9uYWwgTm9pc2UpIChTZWUgTWVlaGwsIDE5OTBhYiBhbmQgTHlra2VuLCAxOTY4IGNpdGVkIGJ5IE1lZWhsKS4gT3VyIGdvYWwgaXMgdG8gZGV0ZXJtaW5lIGhvdyBtdWNoIGFuZCB3ZSB3aWxsIGRlYWwgd2l0aCAyIHZhcmlhYmxlcyBhdCBhIHRpbWUsIGJ1dCB3ZSB3aWxsIHNvb24gZXhwbG9yZSB0aGUgcHJvYmxlbXMgd2l0aCAzIG9yIG1vcmUgdmFyaWFibGVzLiANCg0KQSBmZXcgcG9wdWxhciBjb3JyZWxhdGlvbnMgYmV0d2VlbiB0d28gdmFyaWFibGVzOiANCg0KLSBQZWFyc29uJ3MgciAoaW50ZXJ2YWwgYnkgaW50ZXJ2YWwpIFtmb3IgcG9wdWxhdGlvbiA9ICRccmhvJCwgZm9yIHNhbXBsZSA9ICRyJF0NCi0gU3BlYXJtYW4ncyByaG8gIChpbnRlcnZhbCBieSBvcmRpbmFsKSBbZm9yIHBvcHVsYXRpb24gPSAkXHJob197c30kLCBmb3Igc2FtcGxlID0gJHJfcyRdDQotIEtlbmRhbGwncyB0YXUgWyR0JF0gKGludGVydmFsIGJ5IG9yZGluYWwgb3Igb3JkaW5hbCBieSBvcmRpbmFsKSBsaWtlIFNwZWFybWFuJ3MsIGJ1dCBtb3JlIGFjY3VyYXRlIHdpdGggc21hbGwgc2FtcGxlcyANCi0gUG9pbnQtYnktc2VyaWFsIChpbnRlcnZhbCBieSBkaWNob3RvbW91cykNCi0gUG9seWNob3JpYyAob3JkaW5hbCB2cyBvcmRpbmFsKSBbdXNlZCBtb3JlIGluIHBzeWNob21ldHJpY3Mgb3IgZmFjdG9yIGFuYWx5c2lzIG9mIG9yZGluYWwgYnkgb3JkaW5hbF0NCi0gVGV0cmFjaHJvaWMgKGRpY2hvdG9tb3VzIHZzIGRpY2hvdG9tb3VzKSBbdXNlZCBtb3JlIGluIHBzeWNob21ldHJpY3Mgb3IgZmFjdG9yIGFuYWx5c2lzIG9mIGRpY2hvdG9tb3VzIGJ5IGRpY2hvdG9tb3VzXQ0KDQoNCkluIGdlbmVyYWwgdGhlc2UgYXNzdW1lIGJpdmFyaWF0ZSBub3JtYWxpdHksIHdoaWNoIG1lYW5zIHRoYXQgdGhlIHR3byB2YXJpYWJsZXMgYXJlIG5vcm1hbGx5IGRpc3RyaWJ1dGVkIHdoZW4gYWRkZWQgdG9nZXRoZXIgKGFuZCBpbmRlcGVuZGVudGx5KS4gVGhlIGJpdmFyaWF0ZSBub3JtYWwgZGlzdHJpYnV0aW9uIGlzIGEgdGhyZWUtZGltZW5zaW9uYWwgbm9ybWFsIGN1cnZlLg0KDQoNCiMjIFBlYXJzb24ncyBDb3JyZWxhdGlvbg0KTW9zdCBjb21tb24gdHlwZSB5b3Ugd2lsbCBlbmNvdW50ZXIgYW5kIGlzIGEgcGFyYW1ldHJpYyBtZXRob2QuIA0KDQokJHJfe3h5fT1cZnJhY3tcc3VteyhYLU1fWCkoWS1NX1kpfX17XHNxcnR7XHN1bShYLU1fWCleMlxzdW0oWS1NX1kpXjJ9fSQkDQpyZW1lbWJlciAkU1MgPSAoWC1NKV4yJCwgc28gdGh1cywNCg0KJCRyX3t4eX09XGZyYWN7U1B9e1xzcXJ0e1NTX1hTU19ZfX0kJA0KDQotIE51bWVyYXRvciA9IEhvdyBtdWNoIHRoZXkgdmFyeSB0b2dldGhlciAoY292YXJpYW5jZSkNCi0gRGVub21pbmF0b3IgPSBUaGUgcHJvZHVjdCBvZiBob3cgbXVjaCB0aGV5IHZhcnkgYWxvbmUgKHZhcmlhbmNlKQ0KLSBWYWx1ZXMgYXJlIGJvdW5kZWQgYmV0d2VlbiAtMSBhbmQgMQ0KDQpvciBtb3JlIHNpbXBseSAoc2VlIENvaGVuJ3MgdGV4dGJvb2sgZm9yIHRoZSBkZXJpdmF0aW9uKTogDQoNCiQkcl97eHl9PVxmcmFje1xzdW17eHl9fXtcc3FydHtcc3Vte3heMn1cc3Vte3leMn19fSQkDQoNCiMjIyBTaW11bGF0ZSBEYXRhDQoNCldlIHdpbGwgdXNlIHRoZSBgbXZybm9ybWAgZnVuY3Rpb24gKG11bHRpdmFyaWF0ZSBub3JtYWwgZGlzdHJpYnV0aW9uKSBmcm9tIHRoZSAqTUFTUyogcGFja2FnZSwgYnV0IHRvIGRvIHRoaXMgd2UgbmVlZCB0byBtYWtlIGEgKipjb3ZhcmlhbmNlKiogbWF0cml4IHdpdGggYSAkciA9IC42MCQgYW5kIHNldCB0aGUgbWVhbiB2YWx1ZXMgZm9yIGVhY2ggdmFyaWFibGUgKHdoaWNoIEkgd2lsbCBzZXQgdG8gNSBmb3IgZWFjaCkNCiANCmBgYHtyfQ0KI1NldCBwYXJhbXMNCk1lYW5zLlhZPC0gYyg1LDUpICNzZXQgdGhlIG1lYW5zIG9mIFggYW5kIFkgdmFyaWFibGVzDQpyPS42ICNDb3JyZWxhdGlvbiB2YWx1ZQ0KQ292TWF0cml4LlhZIDwtIG1hdHJpeChjKDEsciwNCiAgICAgICAgICAgICAgICAgICAgICAgICByLDEpLDIsMikgIyBjcmVhdGVzIHRoZSBjb3ZhcmlhdGUgbWF0cml4IA0KDQojIEJ1aWxkIHRoZSBjb3JyZWxhdGVkIHZhcmlhYmxlcyB1c2luZyBtdnJub3JtLiANCiMgTm90ZTogZW1waXJpY2FsPVRSVUUgbWVhbnMgbWFrZSB0aGUgY29ycmVsYXRpb24gRVhBQ1RMWSByLiANCiMgZW1waXJpY2FsPUZBTFNFLCB0aGUgY29ycmVsYXRpb24gdmFsdWUgd291bGQgYmUgbm9ybWFsbHkgZGlzdHJpYnV0ZWQgYXJvdW5kIHINCmxpYnJhcnkoTUFTUykgI2NyZWF0ZSBkYXRhDQpDb3JyRGF0YTwtbXZybm9ybShuPTEwMCwgbXU9TWVhbnMuWFksU2lnbWE9Q292TWF0cml4LlhZLCBlbXBpcmljYWw9VFJVRSkNCg0KI0NvbnZlcnQgdGhlbSB0byBhICJEYXRhLkZyYW1lIiwgd2hpY2ggaXMgbGlrZSBTUFNTIGRhdGEgd2luZG93DQpDb3JyRGF0YTwtYXMuZGF0YS5mcmFtZShDb3JyRGF0YSkNCiNsZXRzIGFkZCBvdXIgbGFiZWxzIHRvIHRoZSB2ZWN0b3JzIHdlIGNyZWF0ZWQNCmNvbG5hbWVzKENvcnJEYXRhKSA8LSBjKCJIYXBwaW5lc3MiLCJJY2VDcmVhbSIpDQpgYGANCg0KIyMjIFBsb3QgdGhlIGRhdGENCg0KYGBge3J9DQojbWFrZSB0aGUgc2NhdHRlciBwbG90DQpsaWJyYXJ5KGdncHVicikgI2dyYXBoIGRhdGENCmdnc2NhdHRlcihDb3JyRGF0YSwgeCA9ICJJY2VDcmVhbSIsIHkgPSAiSGFwcGluZXNzIiwNCiAgIGFkZCA9ICJyZWcubGluZSIsICAjIEFkZCByZWdyZXNzaW4gbGluZQ0KICAgYWRkLnBhcmFtcyA9IGxpc3QoY29sb3IgPSAiYmx1ZSIsIGZpbGwgPSAibGlnaHRncmF5IiksICMgQ3VzdG9taXplIHJlZy4gbGluZQ0KICAgY29uZi5pbnQgPSBUUlVFLCAjIEFkZCBjb25maWRlbmNlIGludGVydmFsDQogICBjb3IuY29lZiA9IEZBTFNFLCAjIEFkZCBjb3JyZWxhdGlvbiBjb2VmZmljaWVudC4gc2VlID9zdGF0X2Nvcg0KICAgKQ0KDQpgYGANCg0KIyMjIFJ1biBQZWFyc29uJ3Mgcg0KDQpUaGUgYGNvci50ZXN0YCBmdW5jdGlvbiBydW5zIFBlYXJzb27igJlzIGNvcnJlbGF0aW9uLiAqKk5vdGU6KiogWW91IHdpbGwgbm90aWNlIHRoYXQgSSBoYXZlIGF0dGFjaGVkIHRoZSBkYXRhIGZyYW1lIHRvIGVhY2ggdmFyaWFibGUuIA0KDQpgYGB7ciwgZWNobz1UUlVFfQ0KQ29yci5SZXN1bHQuMTwtY29yLnRlc3QoQ29yckRhdGEkSGFwcGluZXNzLCBDb3JyRGF0YSRJY2VDcmVhbSwgDQogICAgICAgICBtZXRob2QgPSBjKCJwZWFyc29uIikpDQpDb3JyLlJlc3VsdC4xDQpgYGANCg0KWW91IGNhbiBhbHNvIGNhbGwgdGhlIGZ1bmN0aW9uIHZpYSBhIGZvcm11bGEgY29tbWFuZC4gDQoNCmBgYHtyLCBlY2hvPVRSVUV9DQpDb3JyLlJlc3VsdC4xPC1jb3IudGVzdCh+SGFwcGluZXNzICsgSWNlQ3JlYW0sIGRhdGE9IENvcnJEYXRhLCAgDQogICAgICAgICBtZXRob2QgPSBjKCJwZWFyc29uIikpDQpgYGANCg0KIyMgUHZhbHVlIG9uIFBlYXJzb24ncyBDb3JyZWxhdGlvbg0KVGhlIGNsYXNzaWNhbCBwdmFsdWUgb24gUGVhcnNvbidzIGNvcnJlbGF0aW9uIGlzIGFkYXB0ZWQgZnJvbSB0aGUgdC1kaXN0cmlidXRpb24uIFdlIHdpbGwgY29tZSBiYWNrIHRvIGxhdGVyIHdoZW4gd2UgY292ZXIgbGluZWFyIHJlZ3Jlc3Npb24uICANCg0KDQojIyMgUmVwb3J0IHRoZW0gaW4gQVBBIGZvcm1hdA0KDQpUaGUgYGNvcl9hcGFgIGZ1bmN0aW9uIGluIHRoZSBBUEEgcGFja2FnZSB3aWxsIHJlcG9ydCBpdCBpbiBBUEEgZm9ybWF0IGZvciB5b3UuIE5vdGU6IHIoZGYpID0gcGVhcnNvbiByLCBwdmFsdWUuIERGIGhlcmUgaXMgTi0yLCBhcyB3ZSBoYXZlIHR3byB2YXJpYWJsZXMgd2UgYXJlIGNvbXBhcmluZy4gVGhlcmUgYXJlIGxvdHMgb2Ygb3B0aW9ucyByZWdhcmRpbmcgaG93IHRvIG91dHB1dCB0aGUgZm9ybWF0LiANCg0KYGBge3IsIHJlc3VsdHM9ImFzaXMifQ0KbGlicmFyeShhcGEpDQpjb3JfYXBhKENvcnIuUmVzdWx0LjEsZm9ybWF0ID0icm1hcmtkb3duIikNCmBgYA0KDQojIyMgUGVhcnNvbidzIGNvcnJlbGF0aW9uIGlzIHNjYWxlLWluZGVwZW5kZW50ISANCk5vIG1hdHRlciB0aGUgbWVhbiBkaWZmZXJlbmNlcyBvciByYW5nZSBvZiBzY29yZXMsIHRoZSBQZWFyc29uJ3MgciB3aWxsIGdpdmUgdGhlIHNhbWUgcmVzdWx0cy4gV2UgY2FuIGFsc28gei1zY29yZSB0aGUgZGF0YSBhbmQgZ2V0IHRoZSBzYW1lIHJlc3VsdC4gSG93ZXZlciwgaWYgdGhleSBhcmUgc2NhbGVkIG5vbi1saW5lYXJseSAoc3FydCwgXjIsIGxvZywuLi4pIHRoZSBjb3JyZWxhdGlvbiB3aWxsIGNoYW5nZS4gDQoNCiMjIyMgTGV0cyBhZGQgKGNoYW5nZSB0aGUgbWVhbikNCg0KYGBge3J9DQpDb3JyRGF0YSRIYXBwaW5lc3MuYmlnPC1Db3JyRGF0YSRIYXBwaW5lc3MrMTAwMA0KDQpnZ3NjYXR0ZXIoQ29yckRhdGEsIHggPSAiSWNlQ3JlYW0iLCB5ID0gIkhhcHBpbmVzcy5iaWciLA0KICAgYWRkID0gInJlZy5saW5lIiwgICMgQWRkIHJlZ3Jlc3NpbiBsaW5lDQogICBhZGQucGFyYW1zID0gbGlzdChjb2xvciA9ICJibHVlIiwgZmlsbCA9ICJsaWdodGdyYXkiKSwgIyBDdXN0b21pemUgcmVnLiBsaW5lDQogICBjb25mLmludCA9IFRSVUUsICMgQWRkIGNvbmZpZGVuY2UgaW50ZXJ2YWwNCiAgIGNvci5jb2VmID0gVFJVRSwgIyBBZGQgY29ycmVsYXRpb24gY29lZmZpY2llbnQuIHNlZSA/c3RhdF9jb3INCiAgICkNCg0KY29yX2FwYShjb3IudGVzdChDb3JyRGF0YSRIYXBwaW5lc3MuYmlnLCBDb3JyRGF0YSRJY2VDcmVhbSwgDQogICAgICAgICBtZXRob2QgPSBjKCJwZWFyc29uIikpLGZvcm1hdCA9InRleHQiKQ0KYGBgDQoNCiMjIyMgWi1zY29yZWQNCg0KUmVtZW1iZXIgdGhhdCwgJFogPSBcZnJhY3tYLU19e1N9JA0KDQpgYGB7cn0NCkNvcnJEYXRhJEhhcHBpbmVzcy56PC1zY2FsZShDb3JyRGF0YSRIYXBwaW5lc3MpDQpDb3JyRGF0YSRJY2VDcmVhbS56PC1zY2FsZShDb3JyRGF0YSRJY2VDcmVhbSkNCg0KZ2dzY2F0dGVyKENvcnJEYXRhLCB4ID0gIkljZUNyZWFtLnoiLCB5ID0gIkhhcHBpbmVzcy56IiwNCiAgIGFkZCA9ICJyZWcubGluZSIsICAjIEFkZCByZWdyZXNzaW4gbGluZQ0KICAgYWRkLnBhcmFtcyA9IGxpc3QoY29sb3IgPSAiYmx1ZSIsIGZpbGwgPSAibGlnaHRncmF5IiksICMgQ3VzdG9taXplIHJlZy4gbGluZQ0KICAgY29uZi5pbnQgPSBUUlVFLCAjIEFkZCBjb25maWRlbmNlIGludGVydmFsDQogICBjb3IuY29lZiA9IFRSVUUsICMgQWRkIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50LiBzZWUgP3N0YXRfY29yDQogICApDQoNCg0KY29yX2FwYShjb3IudGVzdChDb3JyRGF0YSRIYXBwaW5lc3MueiwgQ29yckRhdGEkSWNlQ3JlYW0ueiwgDQogICAgICAgICBtZXRob2QgPSBjKCJwZWFyc29uIikpLGZvcm1hdCA9InRleHQiKQ0KYGBgDQoNCiMjIyMgV2hhdCBoYXBwZW5zIGlmIEkgTElORUFSTFkgc2NhbGUgdGhlbSBkaWZmZXJlbnRseT8NCg0KYGBge3J9DQpnZ3NjYXR0ZXIoQ29yckRhdGEsIHggPSAiSWNlQ3JlYW0ueiIsIHkgPSAiSGFwcGluZXNzLmJpZyIsDQogICBhZGQgPSAicmVnLmxpbmUiLCAgIyBBZGQgcmVncmVzc2luIGxpbmUNCiAgIGFkZC5wYXJhbXMgPSBsaXN0KGNvbG9yID0gImJsdWUiLCBmaWxsID0gImxpZ2h0Z3JheSIpLCAjIEN1c3RvbWl6ZSByZWcuIGxpbmUNCiAgIGNvbmYuaW50ID0gVFJVRSwgIyBBZGQgY29uZmlkZW5jZSBpbnRlcnZhbA0KICAgY29yLmNvZWYgPSBUUlVFLCAjIEFkZCBjb3JyZWxhdGlvbiBjb2VmZmljaWVudC4gc2VlID9zdGF0X2Nvcg0KICAgKQ0KDQpjb3JfYXBhKGNvci50ZXN0KENvcnJEYXRhJEhhcHBpbmVzcy5iaWcsIENvcnJEYXRhJEljZUNyZWFtLnosIA0KICAgICAgICAgbWV0aG9kID0gYygicGVhcnNvbiIpKSxmb3JtYXQgPSJ0ZXh0IikNCmBgYA0KDQojIyMjIFdoYXQgaGFwcGVucyBpZiBJIE5PTi1MSU5FQVJMWSBzY2FsZSB0aGVtIGRpZmZlcmVudGx5Pw0KDQpgYGB7cn0NCkNvcnJEYXRhJEhhcHBpbmVzczwtQ29yckRhdGEkSGFwcGluZXNzICMgb3JnaW5hbA0KQ29yckRhdGEkSWNlQ3JlYW0uc3E0PC0oQ29yckRhdGEkSWNlQ3JlYW0pXjQgI05vbi1saW5lYXINCg0KZ2dzY2F0dGVyKENvcnJEYXRhLCB4ID0gIkljZUNyZWFtLnNxNCIsIHkgPSAiSGFwcGluZXNzIiwNCiAgIGFkZCA9ICJyZWcubGluZSIsICAjIEFkZCByZWdyZXNzaW4gbGluZQ0KICAgYWRkLnBhcmFtcyA9IGxpc3QoY29sb3IgPSAiYmx1ZSIsIGZpbGwgPSAibGlnaHRncmF5IiksICMgQ3VzdG9taXplIHJlZy4gbGluZQ0KICAgY29uZi5pbnQgPSBUUlVFLCAjIEFkZCBjb25maWRlbmNlIGludGVydmFsDQogICBjb3IuY29lZiA9IFRSVUUsICMgQWRkIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50LiBzZWUgP3N0YXRfY29yDQogICApDQoNCmNvcl9hcGEoY29yLnRlc3QoQ29yckRhdGEkSGFwcGluZXNzLCBDb3JyRGF0YSRJY2VDcmVhbS5zcTQsIA0KICAgICAgICAgbWV0aG9kID0gYygicGVhcnNvbiIpKSxmb3JtYXQgPSJ0ZXh0IikNCmBgYA0KDQojIyMgUGVhcnNvbidzOiBMZXQgdmlzdWFsaXplIG91ciByZXN1bHQNClRoZSBvdmVybGFwIGJldHdlZW4gdGhlIHR3byB2YXJpYWJsZXMgaXMgZGVmaW5lZCBieSAkcl4yJA0KDQpgYGB7cixmaWcud2lkdGg9NSwgZmlnLmhlaWdodD00fQ0KICMgbGV0cyB1cyBwbG90IG91ciByZXN1bHRzIChsaWtlIHRoZSBib29rKQ0KbGlicmFyeShWZW5uRGlhZ3JhbSkNCiMgY2FsY3VsYXRlIHItc3F1YXJlZA0Kb3ZlcmxhcD1yXjIgDQoNClNpbXBsZS5Db3JyLlZlbm48LWRyYXcucGFpcndpc2UudmVubigxLCAxLCBvdmVybGFwLCBjKCJIYXBwaW5lc3MiLCAiSWNlQ3JlYW0iKSkNCmdyaWQuZHJhdyhTaW1wbGUuQ29yci5WZW5uKQ0KYGBgDQoNClRoaXMgbWVhbnMgdGhhdCBgciByXjIqMTAwYCUgb2YgdGhlIHZhcmlhbmNlIG9mIGhhcHBpbmVzcyBvdmVybGFwcyB3aXRoIGljZSBjcmVhbSBjb25zdW1wdGlvbi4gQ2FuIHdlIGNvbmNsdWRlIGljZSBjcmVhbSBjYXVzZXMgaGFwcGluZXNzPyBObywgYmVjYXVzZSB3ZSBkaWQgbm90IGRlc2lnbiBhIHN0dWR5IHdpdGggYSBjb250cm9sIGdyb3VwLiBXZSBjYW4gbm90IGluZmVyIGNhdXNhdGlvbi4gIEl0IHNlZW1zIHRvIG1ha2Ugc2Vuc2UgdG8gc2F5IOKAnGVhdGluZyBpY2UgY3JlYW0gY2F1c2VzIG1lIHRvIGJlIGhhcHB54oCdLCBidXQgdGhlIG9wcG9zaXRlIGNvdWxkIGJlIHRydWUgYXMgd2VsbCDigJxoYXBwaW5lc3MgY2F1c2VzIG1lIHRvIGVhdCBpY2UgY3JlYW3igJ0uIEhvdyBkbyBJIGtub3cgd2hpY2ggY2F1c2VzIHdoaWNoPyBXZSBjYW5ub3Qgd2l0aG91dCBhbiBleHBlcmltZW50LiAgDQoNCiMjIE5vbi1QYXJhbWV0cmljIENvcnJlbGF0aW9ucw0KU3BlYXJtZW4gYW5kIEtlbmRhbGwgY29ycmVsYXRpb24gY2FuIGJlIHVzZWQgZm9yIG9yZGluYWwgZGF0YSwgYnV0IHNob3VsZCBiZSB1c2VkIGlmIHlvdSBoYXZlIGEgImJlbmQiIChub24tbGluZWFyIHJlbGF0aW9uc2hpcCkgYmV0d2VlbiB2YXJpYWJsZXMuICANCg0KIyMjIFNwZWFybWVuJ3MgQ29ycmVsYXRpb24NClNwZWFybWFuIGlzIGEgUGVhcnNvbiBDb3JyZWxhdGlvbiBvbiByYW5rLW9yZGVyZWQgZGF0YS4gIExldCdzIHJhbmsgb3JkZXIgb3VyIHJhbmRvbSBjb3JyZWxhdGVkIGRhdGEuICBZb3UgbXVzdCByYW5rIGVhY2ggdmFyaWFibGUgaW5kZXBlbmRlbnRseSBmaXJzdCAod2hlcmUgdGllcyBhcmUgYXZlcmFnZWQpLg0KDQpgYGB7ciwgZWNobz1UUlVFLCB3YXJuaW5nPUZBTFNFfQ0KQ29yckRhdGEkSGFwcGluZXNzLnJhbms8LXJhbmsoQ29yckRhdGEkSGFwcGluZXNzKQ0KQ29yckRhdGEkSWNlQ3JlYW0ucmFuazwtcmFuayhDb3JyRGF0YSRJY2VDcmVhbSkNCg0KZ2dzY2F0dGVyKENvcnJEYXRhLCB4ID0gIkljZUNyZWFtLnJhbmsiLCB5ID0gIkhhcHBpbmVzcy5yYW5rIiwNCiAgIGFkZCA9ICJyZWcubGluZSIsICAjIEFkZCByZWdyZXNzaW4gbGluZQ0KICAgYWRkLnBhcmFtcyA9IGxpc3QoY29sb3IgPSAiYmx1ZSIsIGZpbGwgPSAibGlnaHRncmF5IiksICMgQ3VzdG9taXplIHJlZy4gbGluZQ0KICAgY29uZi5pbnQgPSBUUlVFLCAjIEFkZCBjb25maWRlbmNlIGludGVydmFsDQogICApDQoNCmNvcl9hcGEoY29yLnRlc3QoQ29yckRhdGEkSWNlQ3JlYW0ucmFuaywgQ29yckRhdGEkSGFwcGluZXNzLnJhbmssIG1ldGhvZCA9IGMoInBlYXJzb24iKSkpDQpgYGANCg0KWW91IHNob3VsZCB1c2UgdGhlIGJ1aWx0LWluIFNwZWFybWFuIGNvcnJlbGF0aW9uIChgY29yLnRlc3RgLCBidXQgcGFzcyAqKm1ldGhvZCA9IGMoInNwZWFybWFuIikqKikgYmVjYXVzZSB0aGUgcHZhbHVlcyBhcmUgY2FsY3VsYXRlZCBkaWZmZXJlbnRseSBhbmQgcmFua3MgdGhlIHJhdyBkYXRhIGF1dG9tYXRpY2FsbHkuIA0KDQpgYGB7cn0NCiMgQVBBIGZvcm1hdCAobm90ZSB0aGUgUyBzaG91bGQgYmUgc3Vic2NyaXB0KQ0KY29yX2FwYShjb3IudGVzdChDb3JyRGF0YSRJY2VDcmVhbSwgQ29yckRhdGEkSGFwcGluZXNzLCANCiAgICAgICAgIG1ldGhvZCA9IGMoInNwZWFybWFuIikpLGZvcm1hdCA9InRleHQiKQ0KYGBgDQoNCg0KIyMjIyBQZWFyc29uIHZzIFNwZWFybWFuJ3MgQ29ycmVsYXRpb24gZm9yIHNsaWdodCBub25saW5lYXJpdHkgDQpMZXQncyBzYXkgeW91IGdldCBzb21lIGRhdGEgYW5kIGNsZWFybHkgdGhlcmUgaXMgYSBzbGlnaHQgbm9ubGluZWFyaXR5IGluIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgdHdvIHZhcmlhYmxlcy4gUGVhcnNvbiBpcyBkZXNpZ25lZCBmb3IgbGluZWFyIHJlbGF0aW9uc2hpcHMgYW5kIHdlIGNhbiBzZWUgdGhlIHByb2JsZW0gaW4gb3VyIGZpdHRlZCBsaW5lIGJlbG93LiANCg0KYGBge3J9DQpDb3JyTkw8LWRhdGEuZnJhbWUoVmFyMT1jKDAsMSwzLDUsNyw5LDEyLDE1LDE4KSwNCiAgICAgICAgICAgICAgICAgICBWYXIyPWMoMCwzLDEyLDE4LDE5LDIwLDIxLDIyLDIzKSkNCg0KZ2dzY2F0dGVyKENvcnJOTCwgeCA9ICJWYXIxIiwgeSA9ICJWYXIyIiwNCiAgIGFkZCA9ICJyZWcubGluZSIsICAjIEFkZCByZWdyZXNzaW4gbGluZQ0KICAgYWRkLnBhcmFtcyA9IGxpc3QoY29sb3IgPSAiYmx1ZSIsIGZpbGwgPSAibGlnaHRncmF5IiksICMgQ3VzdG9taXplIHJlZy4gbGluZQ0KICAgY29uZi5pbnQgPSBUUlVFLCAjIEFkZCBjb25maWRlbmNlIGludGVydmFsDQogICApDQpgYGANCg0KYGBge3IsIGVjaG89RkFMU0V9DQpjb3JfYXBhKGNvci50ZXN0KENvcnJOTCRWYXIxLCBDb3JyTkwkVmFyMiwgbWV0aG9kID0gYygicGVhcnNvbiIpKSkNCmBgYA0KDQpJZiB3ZSBzd2l0Y2ggdG8gYSBTcGVhcm1hbiBjb3JyZWxhdGlvbiB0aGUgZGF0YSBhcmUgY29udmVydGVkIHRvIHJhbmtzIGFuZCB0aGUgImJ1bXAiIGlzIG5vdyBnb25lIGFuZCBvdXIgY29ycmVsYXRpb24gZ2V0cyBzdHJvbmdlci4gDQoNCmBgYHtyfQ0KQ29yck5MJFZhcjEucmFuazwtcmFuayhDb3JyTkwkVmFyMSkNCkNvcnJOTCRWYXIyLnJhbms8LXJhbmsoQ29yck5MJFZhcjIpDQoNCmdnc2NhdHRlcihDb3JyTkwsIHggPSAiVmFyMS5yYW5rIiwgeSA9ICJWYXIyLnJhbmsiLA0KICAgYWRkID0gInJlZy5saW5lIiwgICMgQWRkIHJlZ3Jlc3NpbiBsaW5lDQogICBhZGQucGFyYW1zID0gbGlzdChjb2xvciA9ICJibHVlIiwgZmlsbCA9ICJsaWdodGdyYXkiKSwgIyBDdXN0b21pemUgcmVnLiBsaW5lDQogICBjb25mLmludCA9IFRSVUUsICMgQWRkIGNvbmZpZGVuY2UgaW50ZXJ2YWwNCiAgICkNCmBgYA0KDQoNCmBgYHtyLCBlY2hvPUZBTFNFfQ0KY29yX2FwYShjb3IudGVzdChDb3JyTkwkVmFyMSwgQ29yck5MJFZhcjIsIG1ldGhvZCA9IGMoInNwZWFybWFuIiksIGV4YWN0ID1UUlVFKSkgDQojIGV4YWN0ID0gZXhhY3QgcC12YWx1ZSBpcyBjYWxjdWxhdGVkLiBPdGhlcndpc2UgaXQgdXNlcyBhbiBhcHByb3hpbWF0aW9uIChhIHQtZGlzdCkuIFNlZSB0aGUgaGVscCBmb3IgbW9yZSBkZXRhaWxzIG9uIHRoZSBhbGdvcml0aG0uICAgDQpgYGANCg0KIyMgS2VuZGFsbCdzIFRhdQ0KS2VuZGFsbCB0YXUgd2lsbCBhbHdheXMgYmUgbW9yZSBjb25zZXJ2YXRpdmUgdGhhbiBzcGVhcm1hbiBjb3JyZWxhdGlvbiBhbmQgaXMgZ2VuZXJhbGx5IG1vcmUgcm9idXN0IChgY29yLnRlc3RgLCBidXQgcGFzcyAqKm1ldGhvZCA9IGMoImtlbmRhbGwiKSoqKS4gSXQgaXMgc2FmZXIgdG8gdXNlIGJ1dCBsZXNzIHdpZGVseSBrbm93bi4NCg0KYGBge3J9DQojIEFQQSBmb3JtYXQgKG5vdGUgdGhlIFMgc2hvdWxkIGJlIHN1YnNjcmlwdCkNCmNvcl9hcGEoY29yLnRlc3QoQ29yck5MJFZhcjEsIENvcnJOTCRWYXIyLCANCiAgICAgICAgIG1ldGhvZCA9IGMoImtlbmRhbGwiKSwgZXhhY3QgPVRSVUUpLGZvcm1hdCA9InRleHQiKQ0KYGBgDQoNCiMjIyBUaWVzDQpPbmUgb2YgdGhlIHByb2JsZW1zIHdpdGggU3BlYXJtYW4ncyBhbmQgS2VuZGFsbCdzIGNvcnJlbGF0aW9uIGlzIHRoYXQgeW91IG5lZWQgdG8gYWNjb3VudCBmb3IgICp0aWVzKiBpbiB0aGUgZGF0YSAodHdvIG9yIG1vcmUgcGVvcGxlIGhhdmUgdGhlIHNhbWUgc2NvcmU7IGEgbm90IHVuY29tbW9uIHByb2JsZW0gaW4gb3JkaW5hbCBkYXRhKS4gUiBhbmQgU1BTUyBhdXRvbWF0aWNhbGx5IGFjY291bnQgZm9yIHRpZXMgYW5kIHVzaW5nIHRoZSBleGFjdCBwdmFsdWUgcGFyYW1ldGVyIHdpbGwgYWNjb3VudCBmb3IgdGhlc2UgaXNzdWVzLiBUaHVzIHdoaWxlIEkgcmFuayBvcmRlcmVkIHRoZSBkYXRhIG1hbnVhbGx5IHRvIHNob3cgeW91IGhvdyBpdCBjb21wYXJlZCB0byBQZWFyc29uIGNvcnJlbGF0aW9uIGxldCB0aGUgZnVuY3Rpb25zIGluIFIgZG8gdGhpcyB3b3JrIGZvciB5b3UuICANCg0KDQojIyBQb2ludC1ieS1TZXJpYWwgQ29ycmVsYXRpb24NClRoaXMgY29ycmVsYXRpb24gaXMgZm9yIGludGVydmFsIGJ5IGRpY2hvdG9tb3VzLiBTZWUgdGhlIHNpbXVsYXRpb24gYmVsb3cuIE5vdGU6IFdlIHVzZSB0byBjYWxjdWxhdGUgdGhlIHRoZXNlIGJ5IGhhbmQgaW4gdGhlIG9sZCBkYXlzIHVzaW5nIHQtdGVzdCBhbmQgY29udmVydGluZyB0aGUgJGQkIGludG8gJHIkIG9yIGJ5IGp1c3QgdXNpbmcgdGhlIFBlYXJzb24gZm9ybXVsYSAoYnV0IHRoZXNlIGFwcHJvYWNoZXMgb3ZlcmVzdGltYXRlIHRoZSBjb3JyZWxhdGlvbnMpLiANCg0KYGBge3IsIGVjaG89VFJVRSwgd2FybmluZz1GQUxTRX0NCnNldC5zZWVkKDQyKQ0KUmF0aW5nczwtYyhybm9ybSgyNSxtZWFuPTUsc2QgPSAuNSkscm5vcm0oMjUsbWVhbj0yLHNkID0gLjUpKQ0KRmxhdm9yczwtYyhyZXAoMCwyNSksYyhyZXAoMSwyNSkpKQ0KRmxhdm9yTmFtZXM8LWMocmVwKCJDb29raWUgRG91Z2giLDI1KSxjKHJlcCgiUnVtLVJhaXNpbiIsMjUpKSkNCg0KI0J1aWxkIGRhdGEgZnJhbWUNCkljZS5DcmVhbS5EYXRhPC1kYXRhLmZyYW1lKA0KICBSYXRpbmdzID0gUmF0aW5ncywNCiAgRmxhdm9ycyA9IEZsYXZvcnMsDQogIE5hbWVzID0gRmxhdm9yTmFtZXMpDQojaGVhZChJY2UuQ3JlYW0uRGF0YSkNCg0KZ2dzY2F0dGVyKEljZS5DcmVhbS5EYXRhLCB4ID0gIkZsYXZvcnMiLCB5ID0gIlJhdGluZ3MiLA0KICAgYWRkID0gInJlZy5saW5lIiwgICMgQWRkIHJlZ3Jlc3Npb24gbGluZQ0KICAgYWRkLnBhcmFtcyA9IGxpc3QoY29sb3IgPSAiYmx1ZSIsIGZpbGwgPSAibGlnaHRncmF5IiksICMgQ3VzdG9taXplIHJlZy4gbGluZQ0KICAgY29uZi5pbnQgPSBUUlVFLCAjIEFkZCBjb25maWRlbmNlIGludGVydmFsDQogICApDQoNCmBgYA0KDQojIyMgQ2FsY3VsYXRpb24gb2YgUG9pbnQtYnkgU2VyaWFsDQp1c2luZyB0aGUgYHBvbHljb3JgIHBhY2thZ2UsIHdlIGNhbiBydW4gKipwb2x5c2VyaWFsKiogZnVuY3Rpb24gdXNpbmcgbWF4aW11bS1saWtlbGlob29kIGVzdGltYXRpb24gKGdlbmVyYWxseSBtb3JlIGFjY3VyYXRlIHdoZW4gdGhlIHVuZGVybHlpbmcgZGlzdHJpYnV0aW9uIGlzIG5vcm1hbCkuIEkgd2lsbCBleHBsYWluIE1MRSBmdW5jdGlvbiBsYXRlciBpbiB0aGUgc2VtZXN0ZXIuIA0KDQpgYGB7cn0NCmxpYnJhcnkocG9seWNvcikgI0FkdmFuY2VkIENvcnJlbGF0aW9ucw0KUGJ5U2VyaWFsPC13aXRoKEljZS5DcmVhbS5EYXRhLCANCiAgICAgcG9seXNlcmlhbChGbGF2b3JzLFJhdGluZ3MsIE1MPVRSVUUpKQ0KUGJ5U2VyaWFsDQpgYGANCg0KIyMgUG9seWNob3JpYyANCk1vc3QgcGVvcGxlIHdpbGwgZGVmYXVsdCB0byB1c2luZyBhIFBlYXJzb24vU3BlYXJtYW4gY29ycmVsYXRpb24gZm9yIG9yZGluYWwgdnMgb3JkaW5hbCBkYXRhLCBidXQgYWN0dWFsbHkgdGhhdCBpcyBhbiBpbmFjY3VyYXRlIGFuYWx5c2lzLiBQZWFyc29uJ3MgY29ycmVsYXRpb24gYXNzdW1lcyB0aGUgdmFyaWFuY2VzIGFyZSB1bmJvdW5kZWQsIGJ1dCBpbiBvcmRpbmFsIGRhdGEgdGhlIHZhcmlhbmNlcyB0aGF0IGlzIG5vdCB0aGUgY2FzZS4gUG9seWNob3JpYyBjb3JyZWxhdGlvbnMgYXJlIHBhcnRpY3VsYXJseSBoZWxwZnVsIGZvciB3aGVuIHlvdSB3YW50IGFuIGFjY3VyYXRlIGZhY3RvciBhbmFseXNpcyBvZiBvcmRpbmFsIHNjYWxlcy4gSG93ZXZlciwgdGhpcyBpcyBvbmx5IGNvbW1vbmx5IGRvbmUgYnkgcGVvcGxlIGluIGVkdWNhdGlvbmFsIHBzeWNob2xvZ3kuIFRoZXNlIGNvcnJlbGF0aW9ucyByZXF1aXJlIG1vcmUgZGF0YSBmb3IgdGhlIG1vZGVscyB0byBjb252ZXJnZSB0aGFuIFBlYXJzb24gY29ycmVsYXRpb25zIG1hdHJpY2VzLiBXZSB3aWxsIHNpbXVsYXRlIDEtNSBMaWtlcnQgc2NhbGUgd2l0aCB0aGUgYHNpbXN0dWR5YCBwYWNrYWdlLg0KDQpgYGB7cn0NCmxpYnJhcnkoc2ltc3R1ZHkpDQpiYXNlcHJvYnMgPC0gbWF0cml4KGMoMC4xMCwgMC4yMCwgMC4xMCwgMC40MCwwLjIwLA0KICAgICAgICAgICAgICAgICAgICAgIDAuMjAsIDAuMTAsIDAuMzAsIDAuMTAsMC4zMCksDQogICAgICAgICAgICAgICAgICAgIG5yb3cgPSAyLCBieXJvdyA9IFRSVUUpDQoNCiMgZ2VuZXJhdGUgdGhlIGRhdGENCnNldC5zZWVkKDEyMzQpICAgICAgICAgICAgICAgICAgDQpOcz1nZW5EYXRhKDUwKQ0KU2ltT3JkRGF0YSA8LSBnZW5Db3JPcmRDYXQoTnMsIGFkalZhciA9IE5VTEwsIGJhc2Vwcm9icyA9IGJhc2Vwcm9icywgDQogICAgICAgICAgICAgICAgICAgcHJlZml4ID0gIlZhcmlhYmxlIiwgcmhvID0gMC41LCBjb3JzdHIgPSAiY3MiKQ0KDQpTaW1PcmREYXRhPC1hcy5kYXRhLmZyYW1lKFNpbU9yZERhdGEpDQpnZ3NjYXR0ZXIoU2ltT3JkRGF0YSwgeCA9ICJWYXJpYWJsZTEiLCB5ID0gIlZhcmlhYmxlMiIsDQogICBhZGQgPSAicmVnLmxpbmUiLCAgIyBBZGQgcmVncmVzc2lvbiBsaW5lDQogICBhZGQucGFyYW1zID0gbGlzdChjb2xvciA9ICJibHVlIiwgZmlsbCA9ICJsaWdodGdyYXkiKSwgIyBDdXN0b21pemUgcmVnLiBsaW5lDQogICBjb25mLmludCA9IFRSVUUsICMgQWRkIGNvbmZpZGVuY2UgaW50ZXJ2YWwNCiAgICkNCg0KbGlicmFyeShwb2x5Y29yKSAjQWR2YW5jZWQgQ29ycmVsYXRpb25zDQpQb2x5Q29yclI8LXdpdGgoU2ltT3JkRGF0YSwgDQogICAgIHBvbHljaG9yKFZhcmlhYmxlMSxWYXJpYWJsZTIsIE1MPVRSVUUpKQ0KYGBgDQoNCmBgYHtyLCBlY2hvPUZBTFNFfQ0KIyBOb3RlOiBFY2hvID0gZmFsc2UgaXMgdG8gaGlkZSB0aGUgY29kZSBmcm9tIHByaXRuaW5nIG9uIHRoZSBQREZzLiANClAxPC1jb3JfYXBhKGNvci50ZXN0KFNpbU9yZERhdGEkVmFyaWFibGUxLCBTaW1PcmREYXRhJFZhcmlhYmxlMiwgbWV0aG9kID0gYygicGVhcnNvbiIpKSxmb3JtYXQgPSJybWFya2Rvd24iLHByaW50ID0gRkFMU0UpDQpQMjwtc3VwcHJlc3NXYXJuaW5ncyhjb3JfYXBhKGNvci50ZXN0KFNpbU9yZERhdGEkVmFyaWFibGUxLCBTaW1PcmREYXRhJFZhcmlhYmxlMiwgbWV0aG9kID0gYygic3BlYXJtYW4iKSwgZXhhY3QgPVRSVUUpLGZvcm1hdCA9InJtYXJrZG93biIscHJpbnQgPSBGQUxTRSkpDQpgYGANCg0KDQpXZSBnZXQgYSBwb2x5Y2hyb2ljIGNvcnJlbGF0aW9uIG9mIGByIHJvdW5kKFBvbHlDb3JyUiwgMilgLiBDb21wYXJlIHRoYXQgdG8gZG8gdGhlIFBlYXJzb24sIGByIFAxYCwgYW5kIFNwZWFybWFuLCBgciBQMmAsIGNvcnJlbGF0aW9ucy4gDQoNCg0KIyMgVGV0cmFjaHJvaWMNCg0KTGlrZSBQb2x5Y2hvcmljLCBidXQgdXNlZCBmb3IgZGljaG90b21vdXMgdnMgZGljaG90b21vdXMuIFdlIHdpbGwgc2ltdWxhdGUgMiBpdGVtcyBvbiBhIHRlc3QgKHRoYXQgYXJlIHJpZ2h0IFt0cnVlXSBvciB3cm9uZyBmYWxzZV0pIHdpdGggdGhlIGBzaW1zdHVkeWAgcGFja2FnZS4gVGhlc2UgYXNzdW1lIHRoZSBiaXZhcmlhdGUgbm9ybWFsaXR5ICBTbyBoZXJlIHdlIGFyZSBwcmVkaWN0aW5nIGhvdyB3ZWxsIG9uZSBpdGVtIG9uIGEgdGVzdCBwcmVkaWN0cyB0aGUgb3RoZXJzLiBOb3RlIA0KDQoNCmBgYHtyfQ0KbGlicmFyeShzaW1zdHVkeSkNCmJhc2Vwcm9iczEgPC0gbWF0cml4KGMoMC4zNSwgMC42NSwNCiAgICAgICAgICAgICAgICAgICAgICAwLjUwLCAwLjUwKSwNCiAgICAgICAgICAgICAgICAgICAgbnJvdyA9IDIsIGJ5cm93ID0gVFJVRSkNCg0KIyBnZW5lcmF0ZSB0aGUgZGF0YQ0Kc2V0LnNlZWQoMTIzNCkgICAgICAgICAgICAgICAgICANClNpbU9yZERhdGEyIDwtIGdlbkNvck9yZENhdChOcywgYWRqVmFyID0gTlVMTCwgYmFzZXByb2JzID0gYmFzZXByb2JzMSwgDQogICAgICAgICAgICAgICAgICAgcHJlZml4ID0gIlZhcmlhYmxlIiwgcmhvID0gMC42LCBjb3JzdHIgPSAiY3MiKQ0KDQpTaW1PcmREYXRhMjwtYXMuZGF0YS5mcmFtZShTaW1PcmREYXRhMikNCmdnc2NhdHRlcihTaW1PcmREYXRhMiwgeCA9ICJWYXJpYWJsZTEiLCB5ID0gIlZhcmlhYmxlMiIsDQogICBhZGQgPSAicmVnLmxpbmUiLCAgIyBBZGQgcmVncmVzc2lvbiBsaW5lDQogICBhZGQucGFyYW1zID0gbGlzdChjb2xvciA9ICJibHVlIiwgZmlsbCA9ICJsaWdodGdyYXkiKSwgIyBDdXN0b21pemUgcmVnLiBsaW5lDQogICBjb25mLmludCA9IFRSVUUsICMgQWRkIGNvbmZpZGVuY2UgaW50ZXJ2YWwNCiAgICkNCg0Kd2l0aChTaW1PcmREYXRhMiwgDQogICAgIHBvbHljaG9yKFZhcmlhYmxlMSxWYXJpYWJsZTIpKQ0KYGBgDQoNCiMjIENvcnJlbGF0aW9uIE1hdHJpY2VzIA0KV2hlbiB3ZSBoYXZlIG11bHRpcGxlIHZhcmlhYmxlcyB3ZSBjYW4gY29tcGFyZSB0aGVtIGFsbCB0byBlYWNoIG90aGVyIGF0IG9uY2UuICBGaXJzdCB3ZSB3aWxsIHNpbXVsYXRlIGEgNCB2YXJpYWJsZXMgYW5kIGFsbCB0aGVpciBiaXZhcmlhdGUgY29ycmVsYXRpb25zIHVzaW5nIHRoZSBtdnJub3JtIGZ1bmN0aW9uIGFnYWluLiAgDQpgYGB7cn0NCiNTZXQgcGFyYW1zDQpNZWFucy5YWTwtIGMoNSw1LDUsNSkgI3NldCB0aGUgbWVhbnMgb2YgWCBhbmQgWSB2YXJpYWJsZXMNCnIxMj0uNjtyMTM9LjE7cjE0PS41O3IyMz0uMTtyMjQ9Ljg7cjM0PTA7ICNDb3JyZWxhdGlvbiB2YWx1ZXMNCkNvdk1hdHJpeC5YWSA8LSBtYXRyaXgoYygxLHIxMixyMTMscjE0LA0KICAgICAgICAgICAgICAgICAgICAgICAgIHIxMiwxLHIyMyxyMjQsDQogICAgICAgICAgICAgICAgICAgICAgICAgcjEzLHIyMywxLHIzNCwNCiAgICAgICAgICAgICAgICAgICAgICAgICByMTQscjI0LHIzNCwxKSw0LDQpICMgY3JlYXRlcyB0aGUgY292YXJpYXRlIG1hdHJpeCANCg0KIyBCdWlsZCB0aGUgY29ycmVsYXRlZCB2YXJpYWJsZXMgdXNpbmcgbXZybm9ybS4gDQojIE5vdGU6IGVtcGlyaWNhbD1UUlVFIG1lYW5zIG1ha2UgdGhlIGNvcnJlbGF0aW9uIEVYQUNUTFkgci4gDQojIGVtcGlyaWNhbD1GQUxTRSwgdGhlIGNvcnJlbGF0aW9uIHZhbHVlIHdvdWxkIGJlIG5vcm1hbGx5IGRpc3RyaWJ1dGVkIGFyb3VuZCByDQpsaWJyYXJ5KE1BU1MpICNjcmVhdGUgZGF0YQ0KQ29yckRhdGEyPC1tdnJub3JtKG49MTAwLCBtdT1NZWFucy5YWSxTaWdtYT1Db3ZNYXRyaXguWFksIGVtcGlyaWNhbD1UUlVFKQ0KI0NvbnZlcnQgdGhlbSB0byBhICJEYXRhLkZyYW1lIiwgd2hpY2ggaXMgbGlrZSBTUFNTIGRhdGEgd2luZG93DQpDb3JyRGF0YTI8LWFzLmRhdGEuZnJhbWUoQ29yckRhdGEyKQ0KI2xldHMgYWRkIG91ciBsYWJlbHMgdG8gdGhlIHZlY3RvcnMgd2UgY3JlYXRlZA0KY29sbmFtZXMoQ29yckRhdGEyKSA8LSBjKCJIYXBwaW5lc3MiLCJJY2VDcmVhbSIsICJTcHJpbmtsZXMiLCJPcmVvcyIpDQpgYGANCg0KV2UgY2FuIHVzZSB0aGUgYEdHYWxseWAgcGFja2FnZSB0byBwbG90IFBlYXJzb24gY29ycmVsYXRpb25zIHF1aWNrbHkgaW4gYW4gZWFzeSB0byB2aXN1YWxpemUgZm9ybWF0IG9uY2UgdGhlIGRhdGEgYXJlIGluIGEgZGF0YSBmcmFtZS4gIA0KDQpgYGB7cn0gDQpsaWJyYXJ5KEdHYWxseSkNCkNvcnJQbG90IDwtIGdncGFpcnMoQ29yckRhdGEyLCAgDQogICAgICAgICAgICAgIGxvd2VyID0gbGlzdChjb250aW51b3VzID0gInNtb290aCIpKQ0KQ29yclBsb3QNCmBgYA0KDQoNCiMgUmVncmVzc2lvbg0KLSBDb3JyZWxhdGlvbiBhbmQgcmVncmVzc2lvbiBhcmUgc2ltaWxhcg0KLSBDb3JyZWxhdGlvbiBkZXRlcm1pbmVzIHRoZSBzdGFuZGFyZGl6ZWQgcmVsYXRpb25zaGlwIGJldHdlZW4gWCBhbmQgWQ0KLSBMaW5lYXIgcmVncmVzc2lvbiA9IDEgRFYgYW5kIDEgSVYsIHdoZXJlIHRoZSByZWxhdGlvbnNoaXAgaXMgYSBzdHJhaWdodCBsaW5lDQotIExpbmVhciByZWdyZXNzaW9uIGRldGVybWluZXMgaG93IFggcHJlZGljdHMgWQ0KLSBNdWx0aXBsZSAobGluZWFyKSByZWdyZXNzaW9uID0gMSBEViBhbmQgMisgSVYgKGFsc28gc3RyYWlnaHQgbGluZXMpDQotIE11bHRpcGxlIHJlZ3Jlc3Npb24gZGV0ZXJtaW5lcyBob3cgWCx6LCBhbmQgZXRjLCBwcmVkaWN0IFkgW25leHQgd2Vla10NCg0KIyMgQmFzaWMgUmVncmVzc2lvbiBFcXVhdGlvbg0KLSBMaW5lYXIgUmVncmVzc2lvbiBlcXVhdGlvbiB5b3UgbGVhcm5lZCB3aGVuIHlvdW5nZXIgd2FzIHByb2JhYmx5ICR5ID0gTVggKyBiJA0KLSAkeSQgPSBwcmVkaWN0IHZhbHVlDQotICRNJCA9IHNsb3BlDQotICRYJCA9IFZhcmlhYmxlIHVzZWQgdG8gcHJlZGljdCBZDQotICRiJCA9IGludGVyY2VwdA0KDQojIyBNb2Rlcm4gUmVncmVzc2lvbiBFcXVhdGlvbg0KLSAkWT1CX3tZWH1YICsgQl8wICsgZSQNCi0gJFkkID0gcHJlZGljdCB2YWx1ZQ0KLSAkQl97WVh9JCA9IHNsb3BlDQotICRCX3swfSQgPSBpbnRlcmNlcHQNCi0gJGUkID0gZXJyb3IgdGVybSAob2JzZXJ2ZWQgLSBwcmVkaWN0ZWQpLiBBbHNvIGNhbGxlZCB0aGUgcmVzaWR1YWwuDQoNCiMjIEljZSBDcmVhbSBleGFtcGxlDQotIFNwZWNpZnkgdGhlIG1vZGVsIHdpdGggdGhlIGxtIGZ1bmN0aW9uLiANCi0gV2UgYXJlIGdvaW5nIHRvIHByZWRpY3QgaGFwcGluZXNzIHNjb3JlcyBmcm9tIGljZSBjcmVhbSEgDQoNCmBgYHtyLCBlY2hvPVRSVUUsIHdhcm5pbmc9RkFMU0V9DQpIYXBweS5Nb2RlbC4xPC1sbShIYXBwaW5lc3N+SWNlQ3JlYW0sZGF0YSA9IENvcnJEYXRhKQ0Kc3VtbWFyeShIYXBweS5Nb2RlbC4xKQ0KYGBgDQoNCg0KIyMjIEludGVyY2VwdA0KLSBgciBIYXBweS5Nb2RlbC4xJGNvZWZmaWNpZW50c1sxXWAgaXMgd2hlcmUgdGhlIGxpbmUgaGl0IHRoZSB5LWludGVyY2VwdCAod2hlbiBoYXBwaW5lc3MgPSAwKS4gDQoNCiMjIyBTbG9wZQ0KLSBgciBIYXBweS5Nb2RlbC4xJGNvZWZmaWNpZW50c1syXWAgaXMgKip0aGUgcmlzZSBvdmVyIHJ1bioqDQotIGZvciBlYWNoIGByIEhhcHB5Lk1vZGVsLjEkY29lZmZpY2llbnRzWzJdYCBjaGFuZ2UgaW4gaWNlIGNyZWFtIHZhbHVlLCB0aGVyZSBpcyBhIGNvcnJlc3BvbmRpbmcgY2hhbmdlIGluIGhhcHBpbmVzcyENCi0gc28gd2UgY2FuIHByZWRpY3QgaGFwcGluZXNzIGZyb20gaWNlIGNyZWFtIHNjb3JlOiANCg0KPiAoYHIgSGFwcHkuTW9kZWwuMSRjb2VmZmljaWVudHNbMl1gICogNSBzcG9vbnMgb2YgaWNlIGNyZWFtICsgYmFzZWxpbmUgaGFwcGluZXNzIGludGVyY2VwdDogYHIgSGFwcHkuTW9kZWwuMSRjb2VmZmljaWVudHNbMV1gKSANCj0gIGByIEhhcHB5Lk1vZGVsLjEkY29lZmZpY2llbnRzWzJdICogNSArSGFwcHkuTW9kZWwuMSRjb2VmZmljaWVudHNbMV1gDQoNCi0gVGhpcyBpcyB5b3VyICpwcmVkaWN0ZWQqIGhhcHBpbmVzcyBzY29yZSBpZiB5b3UgaGFkIDUgc3Bvb25zIG9mIGljZSBjcmVhbQ0KDQojIyMgRXJyb3IgZm9yIHRoaXMgcHJlZGljdGlvbj8NCg0KUiB3aWxsIGRvIGFsbCB0aGUgcHJlZGljdGlvbiBmb3IgdXMgZm9yIGVhY2ggdmFsdWUgb2YgaWNlIGNyZWFtDQpyZXNpZHVhbHMgPSAgKipvYnNlcnZlZCoqIC0gKipwcmVkaWN0ZWQqKg0KDQotIFJlZCBkb3RzID0gKipvYnNlcnZlZCoqICphYm92ZSogcHJlZGljdG9yIGxpbmUNCi0gQmx1ZSBkb3RzID0gKipvYnNlcnZlZCoqICpiZWxvdyogcHJlZGljdG9yIGxpbmUNCi0gdGhlIHN0cm9uZ2VyIHRoZSBjb2xvciwgdGhlIG1vcmUgYW4gaW1wYWN0IHRoYXQgcG9pbnQgaGFzIGluIHB1bGxpbmcgdGhlIGxpbmUgaW4gaXRzIGRpcmVjdGlvbg0KLSBIb2xsb3cgZG90cyA9ICoqcHJlZGljdGVkKioNCi0gVGhlIGdyYXkgbGluZXMgYXJlIHRoZSBkaXN0YW5jZSBiZXR3ZWVuICoqb2JzZXJ2ZWQqKiBhbmQgKipwcmVkaWN0ZWQqKiB2YWx1ZXMhDQoNCldoYXQgc2hvdWxkIHRoZSBtZWFuIG9mIHRoZSByZXNpZHVhbHMgZXF1YWw/DQoNCg0KYGBge3IsIGVjaG89VFJVRSwgd2FybmluZz1GQUxTRX0NCkNvcnJEYXRhJHByZWRpY3RlZCA8LSBwcmVkaWN0KEhhcHB5Lk1vZGVsLjEpICAgIyBTYXZlIHRoZSBwcmVkaWN0ZWQgdmFsdWVzIHdpdGggb3VyIHJlYWwgZGF0YQ0KQ29yckRhdGEkcmVzaWR1YWxzIDwtIHJlc2lkdWFscyhIYXBweS5Nb2RlbC4xKSAjIFNhdmUgdGhlIHJlc2lkdWFsIHZhbHVlcw0KDQpsaWJyYXJ5KGdncGxvdDIpIA0KZ2dwbG90KGRhdGEgPSBDb3JyRGF0YSwgYWVzKHggPSBJY2VDcmVhbSwgeSA9IEhhcHBpbmVzcykpICsNCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSwgY29sb3IgPSAibGlnaHRncmV5IikgKyAgIyBQbG90IHJlZ3Jlc3Npb24gc2xvcGUNCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSByZXNpZHVhbHMpKSArICAjIENvbG9yIG1hcHBlZCBoZXJlDQogIHNjYWxlX2NvbG9yX2dyYWRpZW50Mihsb3cgPSAiYmx1ZSIsIG1pZCA9ICJ3aGl0ZSIsIGhpZ2ggPSAicmVkIikgKyAgIyBDb2xvcnMgdG8gdXNlIGhlcmUNCiAgZ3VpZGVzKGNvbG9yID0gRkFMU0UpICsNCiAgZ2VvbV9zZWdtZW50KGFlcyh4ZW5kID0gSWNlQ3JlYW0sIHllbmQgPSBwcmVkaWN0ZWQpLCBhbHBoYSA9IC4yKSArICAjIGFscGhhIHRvIGZhZGUgbGluZXMNCiAgZ2VvbV9wb2ludChhZXMoeSA9IHByZWRpY3RlZCksIHNoYXBlID0gMSkgKw0KICB0aGVtZV9idygpICAjIEFkZCB0aGVtZSBmb3IgY2xlYW5lciBsb29rDQoNCmBgYA0KDQojIyMgT3JkaW5hcnkgbGVhc3Qgc3F1YXJlcyAoT0xTKQ0KLSBMaW5lYXIgcmVncmVzc2lvbiBmaW5kcyB0aGUgYmVzdCBmaXQgbGluZSBieSB0cnlpbmcgdG8gbWluaW1pemUgdGhlIHN1bSBvZiB0aGUgc3F1YXJlcyBvZiB0aGUgZGlmZmVyZW5jZXMgYmV0d2VlbiB0aGUgb2JzZXJ2ZWQgcmVzcG9uc2VzIHRob3NlIHByZWRpY3RlZCBieSB0aGUgbGluZS4gDQotIE9MUyBjb21wdXRhdGlvbmFsbHkgc2ltcGxlIHRvIGdldCB0aGUgc2xvcGUgdmFsdWUsIGJ1dCBpcyBpbmFjY3VyYXRlIA0KDQokJEJfe1lYfT1cZnJhY3tcc3Vte1hZfS1cZnJhY3sxfXtufVxzdW17WH1cc3Vte1l9fXtcc3Vte3heMn0tXGZyYWN7MX17bn1cc3Vte3h9XjJ9ID0gXGZyYWN7Q292X3tYWX19e3Zhcl94fSQkDQoNCi0gTW9kZXJuIG1ldGhvZHMgdXNlIGFuIGFsdGVybmF0aXZlIChNTCwgUkVNTCkgd2Ugd2lsbCBleGFtaW5lIGxhdGVyIHdoZW4gd2UgZ2V0IHRvIEdMTQ0KDQoNCiMjIFNFIG9uIHRoZSB0ZXJtcyBpbiB0aGUgbW9kZWxzIChob3cgZ29vZCBpcyB0aGUgZml0PykNCi0gUmVzaWR1YWwgU3RhbmRhcmQgZXJyb3IgPSAkXHNxcnRcZnJhY3tcc3Vte2VeMn19e24tMn0kDQotIGluIFIgbGFuZ3VhZ2U6IA0KDQpgYGB7ciwgZWNobz1UUlVFLCB3YXJuaW5nPUZBTFNFfQ0Kbj1sZW5ndGgoQ29yckRhdGEkcmVzaWR1YWxzKQ0KDQpSU0UgPSBzcXJ0KHN1bShDb3JyRGF0YSRyZXNpZHVhbHNeMikgLyAobi0yKSkNClJTRQ0KYGBgDQoNCi0gU28sIG91ciBlcnJvciBvbiB0aGUgcHJlZGljdGlvbiBpcyBgciBSU0VgIGhhcHBpbmVzcyBwb2ludHMgYmFzZWQgb24gb3VyIG1vZGVsLiAgDQoNCiMjIyBTRSBvbiB0aGUgSW50ZXJjZXB0DQotIEludGVyY2VwdCBTdGFuZGFyZCBlcnJvciA9ICRSU0Vcc3FydCB7XGZyYWN7MX17bn0rXGZyYWN7TV94XjJ9eyhuLTEpdmFyX3h9fSQNCi0gaW4gUiBsYW5ndWFnZTogDQogIA0KYGBge3IsIGVjaG89VFJVRSwgd2FybmluZz1GQUxTRX0NCklTRSA9IFJTRSooc3FydCggMSAvIG4gKyBtZWFuKENvcnJEYXRhJEljZUNyZWFtKV4yIC8gKG4gLSAxKSp2YXIoQ29yckRhdGEkSWNlQ3JlYW0pKSkNCklTRQ0KYGBgDQoNCiMjIyBTRSBvbiB0aGUgU2xvcGUNCi0gU2xvcGUgU3RhbmRhcmQgZXJyb3IgPSAkXGZyYWN7c2RfeX17c2RfeH1cc3FydHtcZnJhY3sxIC0gcl97WVh9XjJ9e24tMn19JA0KLSBpbiBSIGxhbmd1YWdlOiANCiAgDQpgYGB7ciwgZWNobz1UUlVFLCB3YXJuaW5nPUZBTFNFfQ0KI2xldHMgZXh0cmFjdCB0aGUgcjIgZnJvbSB0aGUgbW9kZWwNCnIyLm1vZGVsPC1zdW1tYXJ5KEhhcHB5Lk1vZGVsLjEpJHIuc3F1YXJlZA0KDQpTU0UgPSBzZChDb3JyRGF0YSRIYXBwaW5lc3MpL3NkKENvcnJEYXRhJEljZUNyZWFtKSAqIHNxcnQoKDEtIHIyLm1vZGVsKS8gKG4gLSAyKSkNClNTRQ0KYGBgDQoNCiMjIyB0LXRlc3RzIG9uIHNsb3BlIGFuZCBpbnRlcmNlcHQgYW5kICRyXjIkIHZhbHVlDQotIFZhbHVlcyBhcmUgdGVzdGVkIGFnYWluc3QgMCwgc28gaXRzIGFsbCBvbmUgc2FtcGxlIHQtdGVzdHMNCi0gc2xvcGU6ICR0ID0gXGZyYWN7Ql97WVh9IC0gSF8wfXtTRV97Ql97WVh9fX0kDQotIGludGVyY2VwdDogJHQgPSBcZnJhY3tCX3swfSAtIEhfMH17U0Vfe0JfezB9fX0kDQoNCiRyXjIkIGlzIGEgbGl0dGxlIGRpZmZlcmVudCBhcyBpdHMgYSBjb3JyZWxhdGlvbiB2YWx1ZQ0KDQotIGNvcnJlbGF0aW9ucyBhcmUgbm90IG5vcm1hbGx5IGRpc3RyaWJ1dGVkDQotIEZpc2hlciBjcmVhdGVkIGEgY29udmVyc2lvbiBmb3IgciB0byBtYWtlIGl0IGEgeiAoY2FsbGVkIEZpc2hlcnMnICRyJCB0byAkWiQpDQotICRyXjIkOiAkdCA9IFxmcmFje3Jfe1hZfVxzcXJ0e24tMn0tSF8wfXtcc3FydHsxLXJfe1hZfV4yfX0kICwgd2hlcmUgJGRmID0gbiAtIDIkDQotIGl0cyBvZnRlbiBnaXZlbiBmb3IgYXMgYW4gRiB2YWx1ZSwgcmVtZW1iZXIgJHReMiA9IEYkIA0KDQpgYGB7ciwgZWNobz1UUlVFfQ0KI2ludGVyY2VwdA0KdC5JPSBIYXBweS5Nb2RlbC4xJGNvZWZmaWNpZW50c1sxXS9JU0UNCnQuSQ0KI1Nsb3BlDQp0LlM9IEhhcHB5Lk1vZGVsLjEkY29lZmZpY2llbnRzWzJdL1NTRQ0KdC5TDQoNCiMgRm9yIHItc3F1YXJlZA0KdC5yMnh5ID0gcjIubW9kZWxeLjUqc3FydChuLTIpL3NxcnQoMS1yMi5tb2RlbCkNCkYucjJ4eSA9IHQucjJ4eV4yDQpGLnIyeHkNCmBgYA0KDQpOb3RlOiBXZSBhcmUgdGVzdGluZyBudWxsIGh5cG90aGVzaXMgdmFsdWUgZm9yIHNsb3BlLCBpLmUuLCBudWxsID0gMC4gQnV0IGl0J3MgYSB0ZXJyaWJsZSBndWVzcy4gRXZlcnl0aGluZyBjb3JyZWxhdGVzIHdpdGggZXZlcnl0aGluZywgc28gaXQncyBpbXBvcnRhbnQgdG8ga2VlcCB0aGlzIGluIG1pbmQgbW92aW5nIGZvcndhcmQuIFNvIHRoYXQgd291bGQgYmUgdGhlIE5JTEwgaHlwb3RoZXNpcy4gKk5JTEwgY2FuIGJlIHRlc3RlZCBiZXR0ZXIgd2l0aCBib290c3RyYXBwaW5nKi4gDQoNCiMjIFJlZ3Jlc3Npb24gaW4gQU5PVkEgZm9ybWF0DQoNCi0gWW91IGNhbiBhbHNvIHJlcG9ydCB0aGUgcmVzdWx0cyBvZiBhbGwgdGhlIHByZWRpY3RvcnMgKGlmIHlvdSBoYXZlIG11bHRpcGxlKSBpbiBBTk9WQSBzdHlsZSBmb3JtYXQgKEYtdGVzdCB3ZSBjYWxjdWxhdGVkIGFib3ZlIG9uICRyXjIkKQ0KLSBUaGlzIGlzIHVzZWZ1bCBpbiBtdWx0aXBsZSByZWdyZXNzaW9uIGFzIGl0IHRlbGwgeW91ciBpZiB5b3VyIG92ZXJhbGwgc2V0IG9mIHByZWRpY3RvcnMgaXMgc2lnbmlmaWNhbnQNCg0KYGBge3IsIGVjaG89VFJVRX0NCmFub3ZhKEhhcHB5Lk1vZGVsLjEpDQpgYGANCg0KIyBQb3dlciBhbmQgUmVncmVzc2lvbg0KRm9yIHJlZ3Jlc3Npb24sIHdlIHdpbGwgbmVlZCB0byBjb252ZXJ0IG91ciAkcl4yJCBpbnRvIGNvaGVuJ3MgJGZeMiQNCg0KJCRmXjIgPSBcZnJhY3tyXjJ9ezEtcl4yfSQkDQoNCiMjIFBvd2VyIENhbGN1bGF0aW9uDQoNCldlIHdpbGwgdXNlIHRoZSBgcHdyYCBwYWNrYWdlLg0KDQpgYGB7ciwgZWNobz1UUlVFfQ0KbGlicmFyeShwd3IpICNwb3dlciBhbmFseXNpcw0KI3Bvd2VyIGZvciBHTE0NCiMgdQkgPSBkZWdyZWVzIG9mIGZyZWVkb20gZm9yIG51bWVyYXRvcg0KIyB2CT0gZGVncmVlcyBvZiBmcmVlZG9tIGZvciBkZW5vbWluYXRvcg0KIyBmMiA9IGVmZmVjdCBzaXplDQojIHNpZy5sZXZlbD0gKFR5cGUgSSBlcnJvciBwcm9iYWJpbGl0eSkNCiMgcG93ZXIgPSAoMSBtaW51cyBUeXBlIElJIGVycm9yIHByb2JhYmlsaXR5KQ0KZjIuaWNlY3JlYW0gPC0gcl4yIC8gKDEtcl4yKQ0KDQpwd3IuZjIudGVzdCh1ID0gMSwgdiA9IG4tMiwgZjIgPSBmMi5pY2VjcmVhbSwgc2lnLmxldmVsID0gMC4wNSwgcG93ZXIgPSBOVUxMKQ0KYGBgDQoNClNvIHdlIGhhZCBhIHBvd2VyIG9mIGJhc2ljYWxseSAxIGdpdmVuIHRoaXMgc2FtcGxlIHNpemUgYW5kIG91ciB0cnVlIGVmZmVjdCBzaXplIG9mIGByIHJgDQoNCiMjIEEgUHJpb3JpIFBvd2VyIEFuYWx5c2lzDQotIFdoYXQgc2FtcGxlIHNpemUgZG8gSSBuZWVkIGdpdmVuIGEgc3BlY2lmaWMgJGZeMiQNCi0gTm90ZTogR3Bvd2VyIG1pZ2h0IHVzZSAkZiQsIG5vdCAkZl4yJA0KDQpgYGB7ciwgZWNobz1UUlVFfQ0KI3Bvd2VyIGZvciBHTE0NCiMgdQkgPSBkZWdyZWVzIG9mIGZyZWVkb20gZm9yIG51bWVyYXRvcg0KIyB2CT0gZGVncmVlcyBvZiBmcmVlZG9tIGZvciBkZW5vbWluYXRvcg0KIyBmMiA9IGVmZmVjdCBzaXplDQojIHNpZy5sZXZlbD0gKFR5cGUgSSBlcnJvciBwcm9iYWJpbGl0eSkNCiMgcG93ZXIgPSAoMSBtaW51cyBUeXBlIElJIGVycm9yIHByb2JhYmlsaXR5KQ0KDQpwd3IuZjIudGVzdCh1ID0gMSwgdiA9IE5VTEwsIGYyID0gZjIuaWNlY3JlYW0sIHNpZy5sZXZlbCA9IDAuMDUsIHBvd2VyID0gLjgwKQ0KYGBgDQoNCiMgRmluYWwgTm90ZXMgDQotIFRlc3RpbmcgYmV0d2VlbiBjb3JyZWxhdGlvbnMgdXNpbmcgb2xkIGZhc2hpb24gRmlzaGVyJ3MgdGVzdCBpcyBvbGQgZmFzaGlvbiAoQ29oZW4gZXQgYWwuLCBwLiA0OSkuIFRoZSBtb2Rlcm4gYXBwcm9hY2ggaXMgdGhlIGJvb3RzdHJhcCwgYXMgdGhlIG9sZCBtZXRob2QgaXMgdW5kZXJwb3dlcmVkLiANCi0gWW91ciBib29rIGlzIGEgbGl0dGxlIG91dCBvZiBkYXRlOiBDSXMgYXJlIGJldHRlciBidXQgYm9vdHN0cmFwcGVkIENJcyBhcmUgYmVjb21pbmcgbW9yZSBzdGFuZGFyZC4gV2Ugd2lsbCBjb3ZlciB0aGF0IGxhdGVyIGluIHRoZSBzZW1lc3Rlci4gDQoNCiMgUmVmZXJlbmNlcw0KTHlra2VuLCBELiBULiAoMTk2OCkuIFN0YXRpc3RpY2FsIHNpZ25pZmljYW5jZSBpbiBwc3ljaG9sb2dpY2FsIHJlc2VhcmNoLiAqUHN5Y2hvbG9naWNhbCBidWxsZXRpbiosIDcwKDNwMSksIDE1MS4NCg0KTWVlaGwsIFAuIEUuICgxOTkwYSkuIEFwcHJhaXNpbmcgYW5kIGFtZW5kaW5nIHRoZW9yaWVzOiBUaGUgc3RyYXRlZ3kgb2YgTGFrYXRvc2lhbiBkZWZlbnNlIGFuZCB0d28gcHJpbmNpcGxlcyB0aGF0IHdhcnJhbnQgaXQuICpQc3ljaG9sb2dpY2FsIGlucXVpcnkqLCAxKDIpLCAxMDgtMTQxLg0KDQpNZWVobCwgUC4gRS4gKDE5OTBiKS4gV2h5IHN1bW1hcmllcyBvZiByZXNlYXJjaCBvbiBwc3ljaG9sb2dpY2FsIHRoZW9yaWVzIGFyZSBvZnRlbiB1bmludGVycHJldGFibGUuICpQc3ljaG9sb2dpY2FsIHJlcG9ydHMqLCA2NigxKSwgMTk1LTI0NC4NCg0KPHNjcmlwdD4NCiAgKGZ1bmN0aW9uKGkscyxvLGcscixhLG0pe2lbJ0dvb2dsZUFuYWx5dGljc09iamVjdCddPXI7aVtyXT1pW3JdfHxmdW5jdGlvbigpew0KICAoaVtyXS5xPWlbcl0ucXx8W10pLnB1c2goYXJndW1lbnRzKX0saVtyXS5sPTEqbmV3IERhdGUoKTthPXMuY3JlYXRlRWxlbWVudChvKSwNCiAgbT1zLmdldEVsZW1lbnRzQnlUYWdOYW1lKG8pWzBdO2EuYXN5bmM9MTthLnNyYz1nO20ucGFyZW50Tm9kZS5pbnNlcnRCZWZvcmUoYSxtKQ0KICB9KSh3aW5kb3csZG9jdW1lbnQsJ3NjcmlwdCcsJ2h0dHBzOi8vd3d3Lmdvb2dsZS1hbmFseXRpY3MuY29tL2FuYWx5dGljcy5qcycsJ2dhJyk7DQoNCiAgZ2EoJ2NyZWF0ZScsICdVQS05MDQxNTE2MC0xJywgJ2F1dG8nKTsNCiAgZ2EoJ3NlbmQnLCAncGFnZXZpZXcnKTsNCg0KPC9zY3JpcHQ+