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.

Report them in APA format

The cor_apa function in the APA package will report it in APA format for you. Note: r(df) = pearson r, pvalue. DF here is N-2, as we have two variables we are comparing. There are lots of options regarding how to output the format.

library(apa)
cor_apa(Corr.Result.1,format ="rmarkdown")

r(98) = .60, p < .001

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

Regression

  • Correlation and regression are similar
  • Correlation determines the standardized relationship between X and Y
  • Linear regression = 1 DV and 1 IV, where the relationship is a straight line
  • Linear regression determines how X predicts Y
  • Multiple (linear) regression = 1 DV and 2+ IV (also straight lines)
  • Multiple regression determines how X,z, and etc, predict Y [next week]

Basic Regression Equation

  • Linear Regression equation you learned when younger was probably \(y = MX + b\)
  • \(y\) = predict value
  • \(M\) = slope
  • \(X\) = Variable used to predict Y
  • \(b\) = intercept

Modern Regression Equation

  • \(Y=B_{YX}X + B_0 + e\)
  • \(Y\) = predict value
  • \(B_{YX}\) = slope
  • \(B_{0}\) = intercept
  • \(e\) = error term (observed - predicted). Also called the residual.

Ice Cream example

  • Specify the model with the lm function.
  • We are going to predict happiness scores from ice cream!
Happy.Model.1<-lm(Happiness~IceCream,data = CorrData)
summary(Happy.Model.1)
## 
## Call:
## lm(formula = Happiness ~ IceCream, data = CorrData)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -2.24894 -0.43244 -0.05275  0.44217  2.43434 
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  2.00000    0.41198   4.855 4.56e-06 ***
## IceCream     0.60000    0.08081   7.425 4.19e-11 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.8041 on 98 degrees of freedom
## Multiple R-squared:   0.36,  Adjusted R-squared:  0.3535 
## F-statistic: 55.13 on 1 and 98 DF,  p-value: 4.193e-11

Intercept

  • 2 is where the line hit the y-intercept (when happiness = 0).

Slope

  • 0.6 is the rise over run
  • for each 0.6 change in ice cream value, there is a corresponding change in happiness!
  • so we can predict happiness from ice cream score:

(0.6 * 5 spoons of ice cream + baseline happiness intercept: 2) = 5

  • This is your predicted happiness score if you had 5 spoons of ice cream

Error for this prediction?

R will do all the prediction for us for each value of ice cream residuals = observed - predicted

  • Red dots = observed above predictor line
  • Blue dots = observed below predictor line
  • the stronger the color, the more an impact that point has in pulling the line in its direction
  • Hollow dots = predicted
  • The gray lines are the distance between observed and predicted values!

What should the mean of the residuals equal?

CorrData$predicted <- predict(Happy.Model.1)   # Save the predicted values with our real data
CorrData$residuals <- residuals(Happy.Model.1) # Save the residual values

library(ggplot2) 
ggplot(data = CorrData, aes(x = IceCream, y = Happiness)) +
  geom_smooth(method = "lm", se = FALSE, color = "lightgrey") +  # Plot regression slope
  geom_point(aes(color = residuals)) +  # Color mapped here
  scale_color_gradient2(low = "blue", mid = "white", high = "red") +  # Colors to use here
  guides(color = FALSE) +
  geom_segment(aes(xend = IceCream, yend = predicted), alpha = .2) +  # alpha to fade lines
  geom_point(aes(y = predicted), shape = 1) +
  theme_bw()  # Add theme for cleaner look

Ordinary least squares (OLS)

  • Linear regression finds the best fit line by trying to minimize the sum of the squares of the differences between the observed responses those predicted by the line.
  • OLS computationally simple to get the slope value, but is inaccurate

\[B_{YX}=\frac{\sum{XY}-\frac{1}{n}\sum{X}\sum{Y}}{\sum{x^2}-\frac{1}{n}\sum{x}^2} = \frac{Cov_{XY}}{var_x}\]

  • Modern methods use an alternative (ML, REML) we will examine later when we get to GLM

SE on the terms in the models (how good is the fit?)

  • Residual Standard error = \(\sqrt\frac{\sum{e^2}}{n-2}\)
  • in R language:
n=length(CorrData$residuals)

RSE = sqrt(sum(CorrData$residuals^2) / (n-2))
RSE
## [1] 0.8040713
  • So, our error on the prediction is 0.8040713 happiness points based on our model.

SE on the Intercept

  • Intercept Standard error = \(RSE\sqrt {\frac{1}{n}+\frac{M_x^2}{(n-1)var_x}}\)
  • in R language:
ISE = RSE*(sqrt( 1 / n + mean(CorrData$IceCream)^2 / (n - 1)*var(CorrData$IceCream)))
ISE
## [1] 0.4119838

SE on the Slope

  • Slope Standard error = \(\frac{sd_y}{sd_x}\sqrt{\frac{1 - r_{YX}^2}{n-2}}\)
  • in R language:
#lets extract the r2 from the model
r2.model<-summary(Happy.Model.1)$r.squared

SSE = sd(CorrData$Happiness)/sd(CorrData$IceCream) * sqrt((1- r2.model)/ (n - 2))
SSE
## [1] 0.0808122

t-tests on slope and intercept and \(r^2\) value

  • Values are tested against 0, so its all one sample t-tests
  • slope: \(t = \frac{B_{YX} - H_0}{SE_{B_{YX}}}\)
  • intercept: \(t = \frac{B_{0} - H_0}{SE_{B_{0}}}\)

\(r^2\) is a little different as its a correlation value

  • correlations are not normally distributed
  • Fisher created a conversion for r to make it a z (called Fishers’ \(r\) to \(Z\))
  • \(r^2\): \(t = \frac{r_{XY}\sqrt{n-2}-H_0}{\sqrt{1-r_{XY}^2}}\) , where \(df = n - 2\)
  • its often given for as an F value, remember \(t^2 = F\)
#intercept
t.I= Happy.Model.1$coefficients[1]/ISE
t.I
## (Intercept) 
##     4.85456
#Slope
t.S= Happy.Model.1$coefficients[2]/SSE
t.S
## IceCream 
## 7.424621
# For r-squared
t.r2xy = r2.model^.5*sqrt(n-2)/sqrt(1-r2.model)
F.r2xy = t.r2xy^2
F.r2xy
## [1] 55.125

Note: We are testing null hypothesis value for slope, i.e., null = 0. But it’s a terrible guess. Everything correlates with everything, so it’s important to keep this in mind moving forward. So that would be the NILL hypothesis. NILL can be tested better with bootstrapping.

Regression in ANOVA format

  • You can also report the results of all the predictors (if you have multiple) in ANOVA style format (F-test we calculated above on \(r^2\))
  • This is useful in multiple regression as it tell your if your overall set of predictors is significant
anova(Happy.Model.1)
## Analysis of Variance Table
## 
## Response: Happiness
##           Df Sum Sq Mean Sq F value    Pr(>F)    
## IceCream   1  35.64  35.640  55.125 4.193e-11 ***
## Residuals 98  63.36   0.647                      
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

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

Final Notes

  • Testing between correlations using old fashion Fisher’s test is old fashion (Cohen et al., p. 49). The modern approach is the bootstrap, as the old method is underpowered.
  • Your book is a little out of date: CIs are better but bootstrapped CIs are becoming more standard. We will cover that later in the semester.

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+