Making the intercept and slopes makes sense!
- When to use depends on your questions. However, centering is safest
to do (and is often recommended)
- You need to decide on whether it makes sense to transform both DV
and IVs or one or the other.
- Let’s make a practice dataset to explore
- We will transform just the IVs for now:
library(car) #graph data
library(stargazer)
# IQ scores of 5 people
Y<-c(85, 90, 100, 120, 140)
# Likert scale rating of liking of reading books (1 hate to 7 love)
X1<-c(1,2,4,6,7)
scatterplot(Y~X1, smooth=FALSE)
Mr<-lm(Y~X1)
stargazer(Mr,type="html",
intercept.bottom = FALSE, notes.append = FALSE, header=FALSE)
|
|
Dependent variable:
|
|
|
|
Y
|
|
Constant
|
72.385***
|
|
(6.010)
|
|
|
X1
|
8.654***
|
|
(1.305)
|
|
|
|
Observations
|
5
|
R2
|
0.936
|
Adjusted R2
|
0.915
|
Residual Std. Error
|
6.655 (df = 3)
|
F Statistic
|
43.958*** (df = 1; 3)
|
|
Note:
|
p<0.1; p<0.05;
p<0.01
|
Center
- \(Center = {X - M}\)
- Intercept is not at the MEAN of IV (no 0 of IV)
- Does NOT changes meaning of slope
- R:
scale(Data,scale=FALSE)[,]
- scale add a dimension to our new variable, and we can remove it
using [,]
- We usually don’t need this, but it can mess up sometime down the
road
X1.C<-scale(X1,scale=FALSE)[,]
scatterplot(Y~X1.C, smooth=FALSE)
Mc<-lm(Y~X1.C)
stargazer(Mc,type="html",
intercept.bottom = FALSE, notes.append = FALSE, header=FALSE)
|
|
Dependent variable:
|
|
|
|
Y
|
|
Constant
|
107.000***
|
|
(2.976)
|
|
|
X1.C
|
8.654***
|
|
(1.305)
|
|
|
|
Observations
|
5
|
R2
|
0.936
|
Adjusted R2
|
0.915
|
Residual Std. Error
|
6.655 (df = 3)
|
F Statistic
|
43.958*** (df = 1; 3)
|
|
Note:
|
p<0.1; p<0.05;
p<0.01
|
Zscore
- \(Z = \frac{X - M}{s}\)
- Intercept is not at the MEAN of IV (no 0 of IV)
- Slope changes meaning: no longer in unites of original DV, now in
sd units
- R:
scale(data)[,]
#Zscore
X1.Z<-scale(X1)[,]
scatterplot(Y~X1.Z, smooth=FALSE)
Mz<-lm(Y~X1.Z)
stargazer(Mz,type="html",
intercept.bottom = FALSE, notes.append = FALSE, header=FALSE)
|
|
Dependent variable:
|
|
|
|
Y
|
|
Constant
|
107.000***
|
|
(2.976)
|
|
|
X1.Z
|
22.063***
|
|
(3.328)
|
|
|
|
Observations
|
5
|
R2
|
0.936
|
Adjusted R2
|
0.915
|
Residual Std. Error
|
6.655 (df = 3)
|
F Statistic
|
43.958*** (df = 1; 3)
|
|
Note:
|
p<0.1; p<0.05;
p<0.01
|
POMP
- \(POMP = \frac{X - MinX}{Max_X -
Min_X}*100\)
- Note: I like to X 100 cause I find it easier to think in percent
(not proportion)
- Useful when data are bounded (or scaled funny)
- Intercept is again at 0 of IV [but the slopes is different, so the
intercept changes a bit]
- Does changes meaning of slope: is now a function of percent change
of IV
X1_POMP = (X1 - min(X1)) / (max(X1) - min(X1))*100
scatterplot(Y~X1_POMP, smooth=FALSE)
Mp<-lm(Y~X1_POMP)
stargazer(Mp,type="html",
intercept.bottom = FALSE, notes.append = FALSE, header=FALSE)
|
|
Dependent variable:
|
|
|
|
Y
|
|
Constant
|
81.038***
|
|
(4.919)
|
|
|
X1_POMP
|
0.519***
|
|
(0.078)
|
|
|
|
Observations
|
5
|
R2
|
0.936
|
Adjusted R2
|
0.915
|
Residual Std. Error
|
6.655 (df = 3)
|
F Statistic
|
43.958*** (df = 1; 3)
|
|
Note:
|
p<0.1; p<0.05;
p<0.01
|
Simultaneous Regression (standard approach)
- Put all your variables in and see what the effect is of each
term
- Very conservative approach
- Does not allow you to understand additive effects very easily
- You noticed this problem when we were trying to explain Health ~
Years married + Age
- Had you only looked at this final model you might never have
understood that Years married acted as a good predictor on its own.
- Also what if you have a theory you want to test? You need to see the
additive effects.
Hierarchical Modeling
- Is the change in \(R^2\),
meaningful (Model 2 \(R^2\) - Model 1
\(R^2\))?
- The order in which models are run are meaningful
- Terms in models do not need to be analyzed one at a time, but can be
entered as ‘sets’
- a set of variables are theoretically or experimentally driven
- So Model 2 \(R^2\) - Model 1 \(R^2\) meaningful?
Hierarchical Modeling driven by the researcher
- Forward selection: Start with simple models and get more complex
nested models
- Backward selection: Start with complex nested models and get more
simple
- Stepwise selection: can be viewed as a variation of the forward
selection method (one predictor at a time) but predictors are deleted in
subsequent steps if they no longer contribute appreciable unique
prediction
- Which you choose is can depend on how you like to ask questions
Forward Selection of nested models
- A common approach “model building”
- Again let’s make up our dummy data
library(MASS) #create data
py1 =.6 #Cor between X1 (ice cream) and happiness
py2 =.4 #Cor between X2 (Brownies) and happiness
p12= .2 #Cor between X1 (ice cream) and X2 (Brownies)
Means.X1X2Y<- c(10,10,10) #set the means of X and Y variables
CovMatrix.X1X2Y <- matrix(c(1,p12,py1, p12,1,py2, py1,py2,1),3,3) # creates the covariate matrix
set.seed(42)
CorrDataT<-mvrnorm(n=100, mu=Means.X1X2Y,Sigma=CovMatrix.X1X2Y, empirical=TRUE)
CorrDataT<-as.data.frame(CorrDataT)
colnames(CorrDataT) <- c("IceCream","Brownies","Happiness")
library(corrplot)
corrplot(cor(CorrDataT), method = "number")
First alittle side track…
- Remember the \(R2\) values are
reported as F values right?
- This means you can actually get an ANOVA like table for the
model
- for example:
###############Model 1
Ice.Model<-lm(Happiness~ IceCream, data = CorrDataT)
anova(Ice.Model)
## 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
- The \(R2\) this is explained to
unexplained variance (like in our ANOVA)
- \(R^2 =
\frac{SS_{explained}}{SS_{explained}+SS_{residual}}\)
- just to check: anova(Ice.Model) 64.36
- which matched the \(R^2\) that R
gives us 0.36
- When we check to see which model is best we actually test the
differences
Lets forward-fit our models
Ice.Model<-lm(Happiness~ IceCream, data = CorrDataT)
R2.Model.1<-summary(Ice.Model)$r.squared
###############Model 1
Ice.Brown.Model<-lm(Happiness~ IceCream+Brownies, data = CorrDataT)
R2.Model.2<-summary(Ice.Brown.Model)$r.squared
library(stargazer)
stargazer(Ice.Model,Ice.Brown.Model,type="html",
column.labels = c("Model 1", "Model 2"),
intercept.bottom = FALSE,
single.row=FALSE,
star.cutoffs = c(0.1, 0.05, 0.01, 0.001),
star.char = c("@", "*", "**", "***"),
notes= c("@p < .1 *p < .05 **p < .01 ***p < .001"),
notes.append = FALSE, header=FALSE)
|
|
Dependent variable:
|
|
|
|
Happiness
|
|
Model 1
|
Model 2
|
|
(1)
|
(2)
|
|
Constant
|
4.000***
|
1.667@
|
|
(0.812)
|
(0.982)
|
|
|
|
IceCream
|
0.600***
|
0.542***
|
|
(0.081)
|
(0.077)
|
|
|
|
Brownies
|
|
0.292***
|
|
|
(0.077)
|
|
|
|
|
Observations
|
100
|
100
|
R2
|
0.360
|
0.442
|
Adjusted R2
|
0.353
|
0.430
|
Residual Std. Error
|
0.804 (df = 98)
|
0.755 (df = 97)
|
F Statistic
|
55.125*** (df = 1; 98)
|
38.366*** (df = 2; 97)
|
|
Note:
|
@p < .1 p < .05 p <
.01 p < .001
|
- Let’s the difference in \(R^2\)
- \(R_{Change}^2\) =\(R_{Larger}^2\) - \(R_{Smaller}^2\)
- In R, we call for function
anova
and use an \(F\) where the degrees of freedom is the
number of parameter differences between Larger and Smaller model
R2.Change<-R2.Model.2-R2.Model.1
anova(Ice.Model,Ice.Brown.Model)
## Analysis of Variance Table
##
## Model 1: Happiness ~ IceCream
## Model 2: Happiness ~ IceCream + Brownies
## Res.Df RSS Df Sum of Sq F Pr(>F)
## 1 98 63.360
## 2 97 55.275 1 8.085 14.188 0.0002838 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
- The \(R_{Change}^2\) = 0.0816667 is
significant
- So, in other words, we see model 2 fit the data better than
model 1.
Backward-fitting of nested models
- You as does taking away variables reduce my \(R^2\) significantly
- Sometimes used to validate you have a parsimonious model
- You might forward-fit a set of variables and backward fit
critical ones to test a specific hypothesis
- Using the same data as above, we will get the same values (just
negative)
- \(R_{Change}^2\) =\(R_{smaller}^2\) - \(R_{Larger}^2\)
###############Model 1.B
Ice.Brown.Model<-lm(Happiness~ IceCream+Brownies, data = CorrDataT)
R2.Model.1.B<-summary(Ice.Brown.Model)$r.squared
###############Model 2.B
Ice.Model<-lm(Happiness~ IceCream, data = CorrDataT)
R2.Model.2.B<-summary(Ice.Model)$r.squared
R2.Change.B<-R2.Model.2.B-R2.Model.1.B
anova(Ice.Brown.Model,Ice.Model)
## Analysis of Variance Table
##
## Model 1: Happiness ~ IceCream + Brownies
## Model 2: Happiness ~ IceCream
## Res.Df RSS Df Sum of Sq F Pr(>F)
## 1 97 55.275
## 2 98 63.360 -1 -8.085 14.188 0.0002838 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
- The \(R_{Change}^2\) = -0.0816667
is significant
- So, in other words, we see model 1 is a worse fit of the data than
model 2
Stepwise modeling by Computer
- Stepwise with many predicts is often done by computer and it does
not always assume nested models (you can add and remove at the
same)
- Exploratory: you have too many predictors and have no idea where to
start
- You give the computer a larger number of predictors, and the
computer decides the best fit model
- Sounds good, right? No, as the results can be unstable
- Change one variable in the set and the final model can change
- High chance of type I and type II error
- The computer makes decisions based on Akaike information criterion
(AIC) not selected based on a change in \(R^2\), because models are not nested
- also computer makes decisions purely on fit values and has nothing
do with a theory
- Solutions are often unique to that particular dataset
- The best model is often the one that parses a theory and only a
human can do that at present
- Not really publishable because of these problems
Parsing influence
- As models get bigger and bigger its becomes a challenge to figure
out the unique contribution to \(R^2\)
of each variable
- There are many computation solutions that you can select from, but
we will use one called lmg
- you can read about all the different ones here: https://core.ac.uk/download/pdf/6305006.pdf
- these methods are not well known in psychology, but can be very
useful when people ask you what the relative importance of each variable
is
- two approaches: show absolute \(R^2\) for each term or the relative % of
\(R^2\) for each term
library(relaimpo)
# In terms of R2
calc.relimp(Ice.Brown.Model)
## Response variable: Happiness
## Total response variance: 1
## Analysis based on 100 observations
##
## 2 Regressors:
## IceCream Brownies
## Proportion of variance explained by model: 44.17%
## Metrics are not normalized (rela=FALSE).
##
## Relative importance metrics:
##
## lmg
## IceCream 0.3208333
## Brownies 0.1208333
##
## Average coefficients for different model sizes:
##
## 1X 2Xs
## IceCream 0.6 0.5416667
## Brownies 0.4 0.2916667
# as % of R2
calc.relimp(Ice.Brown.Model,rela = TRUE)
## Response variable: Happiness
## Total response variance: 1
## Analysis based on 100 observations
##
## 2 Regressors:
## IceCream Brownies
## Proportion of variance explained by model: 44.17%
## Metrics are normalized to sum to 100% (rela=TRUE).
##
## Relative importance metrics:
##
## lmg
## IceCream 0.7264151
## Brownies 0.2735849
##
## Average coefficients for different model sizes:
##
## 1X 2Xs
## IceCream 0.6 0.5416667
## Brownies 0.4 0.2916667
Final notes:
If you play with lots of predictors and do lots of models,
something will be significant
Type I error is a big problem because of the ‘researcher degree
of freedom problem’
Type II increases as a function of the number of predictors. a)
you slice too much pie, b) each variable might try to each eat someone
else’s slice
Less is more: ask targeted questions with as orthogonal a set of
variables as you can
LS0tDQp0aXRsZTogIlN0ZXB3aXNlIGFuZCBIaWVyYXJjaGljYWwiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgY29kZV9kb3dubG9hZDogeWVzDQogICAgZm9udHNpemU6IDhwdA0KICAgIGhpZ2hsaWdodDogdGV4dG1hdGUNCiAgICBudW1iZXJfc2VjdGlvbnM6IG5vDQogICAgdGhlbWU6IGZsYXRseQ0KICAgIHRvYzogeWVzDQogICAgdG9jX2Zsb2F0Og0KICAgICAgY29sbGFwc2VkOiBubw0KLS0tDQpgYGB7ciwgZWNobz1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiNzZXR3ZCgnQzovVXNlcnMvQWxleFVJQy9Cb3ggU3luYy81NDUgUmVncmVzc2lvbiBTcHJpbmcgMjAxOC9XZWVrIDMgLSBNUicpDQojc2V0d2QoJ0M6L0FsZXhGaWxlcy9TdWdlclN5bmMvVUlDL1RlYWNoaW5nL0dyYWR1YXRlLzU0NS1TcHJpbmcyMDE4L1dlZWsgNSAtIFN0ZXAgYW5kIEhpZXJhcmNoaWNhbCcpDQpgYGANCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQojIHNldHVwIGZvciBSbm90ZWJvb2tzDQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpICNTaG93IGFsbCBzY3JpcHQgYnkgZGVmYXVsdA0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KG1lc3NhZ2UgPSBGQUxTRSkgI2hpZGUgbWVzc2FnZXMgDQprbml0cjo6b3B0c19jaHVuayRzZXQod2FybmluZyA9ICBGQUxTRSkgI2hpZGUgcGFja2FnZSB3YXJuaW5ncyANCmtuaXRyOjpvcHRzX2NodW5rJHNldChmaWcud2lkdGg9My41KSAjU2V0IGRlZmF1bHQgZmlndXJlIHNpemVzDQprbml0cjo6b3B0c19jaHVuayRzZXQoZmlnLmhlaWdodD0zLjUpICNTZXQgZGVmYXVsdCBmaWd1cmUgc2l6ZXMNCmtuaXRyOjpvcHRzX2NodW5rJHNldChmaWcuYWxpZ249J2NlbnRlcicpICNTZXQgZGVmYXVsdCBmaWd1cmUNCmtuaXRyOjpvcHRzX2NodW5rJHNldChmaWcuc2hvdyA9ICJob2xkIikgI1NldCBkZWZhdWx0IGZpZ3VyZQ0KYGBgDQoNClxwYWdlYnJlYWsNCg0KIyBNYWtpbmcgdGhlIGludGVyY2VwdCBhbmQgc2xvcGVzIG1ha2VzIHNlbnNlIQ0KLSBXaGVuIHRvIHVzZSBkZXBlbmRzIG9uIHlvdXIgcXVlc3Rpb25zLiBIb3dldmVyLCBjZW50ZXJpbmcgaXMgc2FmZXN0IHRvIGRvIChhbmQgaXMgb2Z0ZW4gcmVjb21tZW5kZWQpIA0KICAgIC0gQ2VudGVyaW5nIA0KICAgIC0gWnNjb3JlIA0KICAgIC0gUE9NUA0KLSBZb3UgbmVlZCB0byBkZWNpZGUgb24gd2hldGhlciBpdCBtYWtlcyBzZW5zZSB0byB0cmFuc2Zvcm0gYm90aCBEViBhbmQgSVZzIG9yIG9uZSBvciB0aGUgb3RoZXIuIA0KLSBMZXQncyBtYWtlIGEgcHJhY3RpY2UgZGF0YXNldCB0byBleHBsb3JlDQotIFdlIHdpbGwgdHJhbnNmb3JtIGp1c3QgdGhlIElWcyBmb3Igbm93OiANCg0KYGBge3IsIHJlc3VsdHM9J2FzaXMnfQ0KbGlicmFyeShjYXIpICNncmFwaCBkYXRhDQpsaWJyYXJ5KHN0YXJnYXplcikNCiMgSVEgc2NvcmVzIG9mIDUgcGVvcGxlDQpZPC1jKDg1LCA5MCwgMTAwLCAxMjAsIDE0MCkNCiMgTGlrZXJ0IHNjYWxlIHJhdGluZyBvZiBsaWtpbmcgb2YgcmVhZGluZyBib29rcyAoMSBoYXRlIHRvIDcgbG92ZSkNClgxPC1jKDEsMiw0LDYsNykNCnNjYXR0ZXJwbG90KFl+WDEsIHNtb290aD1GQUxTRSkNCk1yPC1sbShZflgxKQ0Kc3RhcmdhemVyKE1yLHR5cGU9Imh0bWwiLA0KICAgICAgICAgIGludGVyY2VwdC5ib3R0b20gPSBGQUxTRSwgbm90ZXMuYXBwZW5kID0gRkFMU0UsIGhlYWRlcj1GQUxTRSkNCmBgYA0KDQojIyBDZW50ZXINCi0gJENlbnRlciA9IHtYIC0gTX0kDQotIEludGVyY2VwdCBpcyBub3QgYXQgdGhlIE1FQU4gb2YgSVYgKG5vIDAgb2YgSVYpDQotIERvZXMgTk9UIGNoYW5nZXMgbWVhbmluZyBvZiBzbG9wZQ0KLSBSOiBgc2NhbGUoRGF0YSxzY2FsZT1GQUxTRSlbLF1gDQogICAgLSBzY2FsZSBhZGQgYSBkaW1lbnNpb24gdG8gb3VyIG5ldyB2YXJpYWJsZSwgYW5kIHdlIGNhbiByZW1vdmUgaXQgdXNpbmcgWyxdDQogICAgICAgIC0gV2UgdXN1YWxseSBkb24ndCBuZWVkIHRoaXMsIGJ1dCBpdCBjYW4gbWVzcyB1cCBzb21ldGltZSBkb3duIHRoZSByb2FkDQoNCmBgYHtyLCByZXN1bHRzPSdhc2lzJ30NClgxLkM8LXNjYWxlKFgxLHNjYWxlPUZBTFNFKVssXQ0Kc2NhdHRlcnBsb3QoWX5YMS5DLCBzbW9vdGg9RkFMU0UpDQpNYzwtbG0oWX5YMS5DKQ0Kc3RhcmdhemVyKE1jLHR5cGU9Imh0bWwiLA0KICAgICAgICAgIGludGVyY2VwdC5ib3R0b20gPSBGQUxTRSwgbm90ZXMuYXBwZW5kID0gRkFMU0UsIGhlYWRlcj1GQUxTRSkNCmBgYA0KDQojIyBac2NvcmUNCi0gJFogPSBcZnJhY3tYIC0gTX17c30kDQotIEludGVyY2VwdCBpcyBub3QgYXQgdGhlIE1FQU4gb2YgSVYgKG5vIDAgb2YgSVYpDQotIFNsb3BlIGNoYW5nZXMgbWVhbmluZzogbm8gbG9uZ2VyIGluIHVuaXRlcyBvZiBvcmlnaW5hbCBEViwgbm93IGluICpzZCogdW5pdHMNCi0gUjogYHNjYWxlKGRhdGEpWyxdYA0KDQpgYGB7ciwgcmVzdWx0cz0nYXNpcyd9DQojWnNjb3JlDQpYMS5aPC1zY2FsZShYMSlbLF0gDQpzY2F0dGVycGxvdChZflgxLlosIHNtb290aD1GQUxTRSkNCk16PC1sbShZflgxLlopDQpzdGFyZ2F6ZXIoTXosdHlwZT0iaHRtbCIsDQogICAgICAgICAgaW50ZXJjZXB0LmJvdHRvbSA9IEZBTFNFLCBub3Rlcy5hcHBlbmQgPSBGQUxTRSwgaGVhZGVyPUZBTFNFKQ0KYGBgDQoNCiMjIFBPTVANCi0gJFBPTVAgPSBcZnJhY3tYIC0gTWluWH17TWF4X1ggLSBNaW5fWH0qMTAwJA0KLSBOb3RlOiBJIGxpa2UgdG8gWCAxMDAgY2F1c2UgSSBmaW5kIGl0IGVhc2llciB0byB0aGluayBpbiBwZXJjZW50IChub3QgcHJvcG9ydGlvbikNCi0gVXNlZnVsIHdoZW4gZGF0YSBhcmUgYm91bmRlZCAob3Igc2NhbGVkIGZ1bm55KQ0KLSBJbnRlcmNlcHQgaXMgYWdhaW4gYXQgMCBvZiBJViBbYnV0IHRoZSBzbG9wZXMgaXMgZGlmZmVyZW50LCBzbyB0aGUgaW50ZXJjZXB0IGNoYW5nZXMgYSBiaXRdIA0KLSBEb2VzIGNoYW5nZXMgbWVhbmluZyBvZiBzbG9wZTogaXMgbm93IGEgZnVuY3Rpb24gb2YgcGVyY2VudCBjaGFuZ2Ugb2YgSVYgDQoNCmBgYHtyLCByZXN1bHRzPSdhc2lzJ30NClgxX1BPTVAgPSAoWDEgLSBtaW4oWDEpKSAvIChtYXgoWDEpIC0gbWluKFgxKSkqMTAwDQpzY2F0dGVycGxvdChZflgxX1BPTVAsIHNtb290aD1GQUxTRSkNCk1wPC1sbShZflgxX1BPTVApDQpzdGFyZ2F6ZXIoTXAsdHlwZT0iaHRtbCIsDQogICAgICAgICAgaW50ZXJjZXB0LmJvdHRvbSA9IEZBTFNFLCBub3Rlcy5hcHBlbmQgPSBGQUxTRSwgaGVhZGVyPUZBTFNFKQ0KYGBgDQoNClxwYWdlYnJlYWsNCg0KIyBTaW11bHRhbmVvdXMgUmVncmVzc2lvbiAoc3RhbmRhcmQgYXBwcm9hY2gpDQotIFB1dCBhbGwgeW91ciB2YXJpYWJsZXMgaW4gYW5kIHNlZSB3aGF0IHRoZSBlZmZlY3QgaXMgb2YgZWFjaCB0ZXJtDQotIFZlcnkgY29uc2VydmF0aXZlIGFwcHJvYWNoDQotIERvZXMgbm90IGFsbG93IHlvdSB0byB1bmRlcnN0YW5kIGFkZGl0aXZlIGVmZmVjdHMgdmVyeSBlYXNpbHkNCi0gWW91IG5vdGljZWQgdGhpcyBwcm9ibGVtIHdoZW4gd2Ugd2VyZSB0cnlpbmcgdG8gZXhwbGFpbiBIZWFsdGggfiBZZWFycyBtYXJyaWVkICsgQWdlDQotIEhhZCB5b3Ugb25seSBsb29rZWQgYXQgdGhpcyBmaW5hbCBtb2RlbCB5b3UgbWlnaHQgbmV2ZXIgaGF2ZSB1bmRlcnN0b29kIHRoYXQgWWVhcnMgbWFycmllZCBhY3RlZCBhcyBhIGdvb2QgcHJlZGljdG9yIG9uIGl0cyBvd24uIA0KLSBBbHNvIHdoYXQgaWYgeW91IGhhdmUgYSB0aGVvcnkgeW91IHdhbnQgdG8gdGVzdD8gWW91IG5lZWQgdG8gc2VlIHRoZSBhZGRpdGl2ZSBlZmZlY3RzLiANCg0KIyBIaWVyYXJjaGljYWwgTW9kZWxpbmcNCi0gSXMgdGhlIGNoYW5nZSBpbiAkUl4yJCwgbWVhbmluZ2Z1bCAoTW9kZWwgMiAkUl4yJCAtIE1vZGVsIDEgJFJeMiQpPw0KLSBUaGUgb3JkZXIgaW4gd2hpY2ggbW9kZWxzIGFyZSBydW4gYXJlIG1lYW5pbmdmdWwNCi0gVGVybXMgaW4gbW9kZWxzIGRvIG5vdCBuZWVkIHRvIGJlIGFuYWx5emVkIG9uZSBhdCBhIHRpbWUsIGJ1dCBjYW4gYmUgZW50ZXJlZCBhcyAnc2V0cycNCi0gYSBzZXQgb2YgdmFyaWFibGVzIGFyZSB0aGVvcmV0aWNhbGx5IG9yIGV4cGVyaW1lbnRhbGx5IGRyaXZlbiANCi0gU28gTW9kZWwgMiAkUl4yJCAtIE1vZGVsIDEgJFJeMiQgIG1lYW5pbmdmdWw/DQoNCiMjIEhpZXJhcmNoaWNhbCBNb2RlbGluZyBkcml2ZW4gYnkgdGhlIHJlc2VhcmNoZXINCi0gRm9yd2FyZCBzZWxlY3Rpb246IFN0YXJ0IHdpdGggc2ltcGxlIG1vZGVscyBhbmQgZ2V0IG1vcmUgY29tcGxleCBuZXN0ZWQgbW9kZWxzDQotIEJhY2t3YXJkIHNlbGVjdGlvbjogU3RhcnQgd2l0aCBjb21wbGV4IG5lc3RlZCBtb2RlbHMgYW5kIGdldCBtb3JlIHNpbXBsZQ0KLSBTdGVwd2lzZSBzZWxlY3Rpb246IGNhbiBiZSB2aWV3ZWQgYXMgYSB2YXJpYXRpb24gb2YgdGhlIGZvcndhcmQgc2VsZWN0aW9uIG1ldGhvZCAob25lIHByZWRpY3RvciBhdCBhIHRpbWUpIGJ1dCBwcmVkaWN0b3JzIGFyZSBkZWxldGVkIGluIHN1YnNlcXVlbnQgc3RlcHMgaWYgdGhleSBubyBsb25nZXIgY29udHJpYnV0ZSBhcHByZWNpYWJsZSB1bmlxdWUgcHJlZGljdGlvbg0KLSBXaGljaCB5b3UgY2hvb3NlIGlzIGNhbiBkZXBlbmQgb24gaG93IHlvdSBsaWtlIHRvIGFzayBxdWVzdGlvbnMNCg0KIyMjIEZvcndhcmQgU2VsZWN0aW9uIG9mIG5lc3RlZCBtb2RlbHMNCi0gQSBjb21tb24gYXBwcm9hY2ggIm1vZGVsIGJ1aWxkaW5nIg0KLSBBZ2FpbiBsZXQncyBtYWtlIHVwIG91ciBkdW1teSBkYXRhDQoNCmBgYHtyfQ0KbGlicmFyeShNQVNTKSAjY3JlYXRlIGRhdGENCnB5MSA9LjYgI0NvciBiZXR3ZWVuIFgxIChpY2UgY3JlYW0pIGFuZCBoYXBwaW5lc3MNCnB5MiA9LjQgI0NvciBiZXR3ZWVuIFgyIChCcm93bmllcykgYW5kIGhhcHBpbmVzcw0KcDEyPSAuMiAjQ29yIGJldHdlZW4gWDEgKGljZSBjcmVhbSkgYW5kIFgyIChCcm93bmllcykNCk1lYW5zLlgxWDJZPC0gYygxMCwxMCwxMCkgI3NldCB0aGUgbWVhbnMgb2YgWCBhbmQgWSB2YXJpYWJsZXMNCkNvdk1hdHJpeC5YMVgyWSA8LSBtYXRyaXgoYygxLHAxMixweTEsIHAxMiwxLHB5MiwgcHkxLHB5MiwxKSwzLDMpICMgY3JlYXRlcyB0aGUgY292YXJpYXRlIG1hdHJpeCANCnNldC5zZWVkKDQyKQ0KQ29yckRhdGFUPC1tdnJub3JtKG49MTAwLCBtdT1NZWFucy5YMVgyWSxTaWdtYT1Db3ZNYXRyaXguWDFYMlksIGVtcGlyaWNhbD1UUlVFKQ0KQ29yckRhdGFUPC1hcy5kYXRhLmZyYW1lKENvcnJEYXRhVCkNCmNvbG5hbWVzKENvcnJEYXRhVCkgPC0gYygiSWNlQ3JlYW0iLCJCcm93bmllcyIsIkhhcHBpbmVzcyIpDQpgYGANCg0KDQpgYGB7cn0NCmxpYnJhcnkoY29ycnBsb3QpDQpjb3JycGxvdChjb3IoQ29yckRhdGFUKSwgbWV0aG9kID0gIm51bWJlciIpDQpgYGANCg0KDQojIyMjIEZpcnN0IGFsaXR0bGUgc2lkZSB0cmFjay4uLg0KLSBSZW1lbWJlciB0aGUgJFIyJCB2YWx1ZXMgYXJlIHJlcG9ydGVkIGFzIEYgdmFsdWVzIHJpZ2h0Pw0KLSBUaGlzIG1lYW5zIHlvdSBjYW4gYWN0dWFsbHkgZ2V0IGFuIEFOT1ZBIGxpa2UgdGFibGUgZm9yIHRoZSBtb2RlbA0KLSBmb3IgZXhhbXBsZTogDQoNCmBgYHtyfQ0KIyMjIyMjIyMjIyMjIyMjTW9kZWwgMSANCkljZS5Nb2RlbDwtbG0oSGFwcGluZXNzfiBJY2VDcmVhbSwgZGF0YSA9IENvcnJEYXRhVCkNCmFub3ZhKEljZS5Nb2RlbCkNCmBgYA0KDQotIFRoZSAkUjIkIHRoaXMgaXMgZXhwbGFpbmVkIHRvIHVuZXhwbGFpbmVkIHZhcmlhbmNlIChsaWtlIGluIG91ciBBTk9WQSkNCi0gJFJeMiA9IFxmcmFje1NTX3tleHBsYWluZWR9fXtTU197ZXhwbGFpbmVkfStTU197cmVzaWR1YWx9fSQNCi0ganVzdCB0byBjaGVjazogYW5vdmEoSWNlLk1vZGVsKSBgciBhbm92YShJY2UuTW9kZWwpJCdTdW0gU3EnWzFdIC8gYW5vdmEoSWNlLk1vZGVsKSQnU3VtIFNxJ1sxXSArIGFub3ZhKEljZS5Nb2RlbCkkJ1N1bSBTcSdbMl1gDQotIHdoaWNoIG1hdGNoZWQgdGhlICRSXjIkIHRoYXQgUiBnaXZlcyB1cyBgciBzdW1tYXJ5KEljZS5Nb2RlbCkkci5zcXVhcmVkYA0KLSBXaGVuIHdlIGNoZWNrIHRvIHNlZSB3aGljaCBtb2RlbCBpcyBiZXN0IHdlIGFjdHVhbGx5IHRlc3QgdGhlIGRpZmZlcmVuY2VzDQoNCiMjIyBMZXRzIGZvcndhcmQtZml0IG91ciBtb2RlbHMNCi0gTW9kZWwgMSAoU21hbGxlciBtb2RlbCkNCg0KYGBge3J9DQpJY2UuTW9kZWw8LWxtKEhhcHBpbmVzc34gSWNlQ3JlYW0sIGRhdGEgPSBDb3JyRGF0YVQpDQpSMi5Nb2RlbC4xPC1zdW1tYXJ5KEljZS5Nb2RlbCkkci5zcXVhcmVkDQpgYGANCg0KLSBNb2RlbCAyIChMYXJnZXIgbW9kZWwpDQoNCmBgYHtyfQ0KIyMjIyMjIyMjIyMjIyMjTW9kZWwgMSANCkljZS5Ccm93bi5Nb2RlbDwtbG0oSGFwcGluZXNzfiBJY2VDcmVhbStCcm93bmllcywgZGF0YSA9IENvcnJEYXRhVCkNClIyLk1vZGVsLjI8LXN1bW1hcnkoSWNlLkJyb3duLk1vZGVsKSRyLnNxdWFyZWQNCmBgYA0KDQoNCmBgYHtyLCByZXN1bHRzPSdhc2lzJ30NCmxpYnJhcnkoc3RhcmdhemVyKQ0Kc3RhcmdhemVyKEljZS5Nb2RlbCxJY2UuQnJvd24uTW9kZWwsdHlwZT0iaHRtbCIsDQogICAgICAgICAgY29sdW1uLmxhYmVscyA9IGMoIk1vZGVsIDEiLCAiTW9kZWwgMiIpLA0KICAgICAgICAgIGludGVyY2VwdC5ib3R0b20gPSBGQUxTRSwNCiAgICAgICAgICBzaW5nbGUucm93PUZBTFNFLCANCiAgICAgICAgICBzdGFyLmN1dG9mZnMgPSBjKDAuMSwgMC4wNSwgMC4wMSwgMC4wMDEpLA0KICAgICAgICAgIHN0YXIuY2hhciA9IGMoIkAiLCAiKiIsICIqKiIsICIqKioiKSwgDQogICAgICAgICAgbm90ZXM9IGMoIkBwIDwgLjEgKnAgPCAuMDUgKipwIDwgLjAxICoqKnAgPCAuMDAxIiksDQogICAgICAgICAgbm90ZXMuYXBwZW5kID0gRkFMU0UsIGhlYWRlcj1GQUxTRSkNCmBgYA0KDQotIExldCdzIHRoZSBkaWZmZXJlbmNlIGluICRSXjIkDQogICAgLSAkUl97Q2hhbmdlfV4yJCA9JFJfe0xhcmdlcn1eMiQgLSAkUl97U21hbGxlcn1eMiQNCi0gSW4gUiwgd2UgY2FsbCBmb3IgZnVuY3Rpb24gYGFub3ZhYCBhbmQgdXNlIGFuICRGJCB3aGVyZSB0aGUgZGVncmVlcyBvZiBmcmVlZG9tIGlzIHRoZSBudW1iZXIgb2YgcGFyYW1ldGVyIGRpZmZlcmVuY2VzIGJldHdlZW4gTGFyZ2VyIGFuZCBTbWFsbGVyIG1vZGVsDQoNCmBgYHtyLCBlY2hvPVRSVUUsIHdhcm5pbmc9RkFMU0V9DQpSMi5DaGFuZ2U8LVIyLk1vZGVsLjItUjIuTW9kZWwuMQ0KYW5vdmEoSWNlLk1vZGVsLEljZS5Ccm93bi5Nb2RlbCkNCmBgYA0KDQotIFRoZSAkUl97Q2hhbmdlfV4yJCA9IGByIFIyLkNoYW5nZWAgaXMgc2lnbmlmaWNhbnQgIA0KLSBTbywgaW4gb3RoZXIgd29yZHMsIHdlIHNlZSBtb2RlbCAyICpmaXQqIHRoZSBkYXRhIGJldHRlciB0aGFuIG1vZGVsIDEuIA0KDQoNCiMjIyBCYWNrd2FyZC1maXR0aW5nIG9mIG5lc3RlZCBtb2RlbHMNCi0gWW91IGFzIGRvZXMgdGFraW5nIGF3YXkgdmFyaWFibGVzIHJlZHVjZSBteSAkUl4yJCBzaWduaWZpY2FudGx5IA0KLSBTb21ldGltZXMgdXNlZCB0byB2YWxpZGF0ZSB5b3UgaGF2ZSBhIHBhcnNpbW9uaW91cyBtb2RlbA0KLSBZb3UgbWlnaHQgZm9yd2FyZC1maXQgYSAqc2V0KiBvZiB2YXJpYWJsZXMgYW5kIGJhY2t3YXJkIGZpdCBjcml0aWNhbCBvbmVzIHRvIHRlc3QgYSBzcGVjaWZpYyBoeXBvdGhlc2lzDQotIFVzaW5nIHRoZSBzYW1lIGRhdGEgYXMgYWJvdmUsIHdlIHdpbGwgZ2V0IHRoZSBzYW1lIHZhbHVlcyAoanVzdCBuZWdhdGl2ZSkNCiAgICAtICRSX3tDaGFuZ2V9XjIkID0kUl97c21hbGxlcn1eMiQgLSAkUl97TGFyZ2VyfV4yJA0KDQpgYGB7cn0NCiMjIyMjIyMjIyMjIyMjI01vZGVsIDEuQiANCkljZS5Ccm93bi5Nb2RlbDwtbG0oSGFwcGluZXNzfiBJY2VDcmVhbStCcm93bmllcywgZGF0YSA9IENvcnJEYXRhVCkNClIyLk1vZGVsLjEuQjwtc3VtbWFyeShJY2UuQnJvd24uTW9kZWwpJHIuc3F1YXJlZA0KIyMjIyMjIyMjIyMjIyMjTW9kZWwgMi5CDQpJY2UuTW9kZWw8LWxtKEhhcHBpbmVzc34gSWNlQ3JlYW0sIGRhdGEgPSBDb3JyRGF0YVQpDQpSMi5Nb2RlbC4yLkI8LXN1bW1hcnkoSWNlLk1vZGVsKSRyLnNxdWFyZWQNClIyLkNoYW5nZS5CPC1SMi5Nb2RlbC4yLkItUjIuTW9kZWwuMS5CDQphbm92YShJY2UuQnJvd24uTW9kZWwsSWNlLk1vZGVsKQ0KYGBgDQoNCi0gVGhlICRSX3tDaGFuZ2V9XjIkID0gYHIgUjIuQ2hhbmdlLkJgIGlzIHNpZ25pZmljYW50ICANCi0gU28sIGluIG90aGVyIHdvcmRzLCB3ZSBzZWUgbW9kZWwgMSBpcyBhIHdvcnNlIGZpdCBvZiB0aGUgZGF0YSB0aGFuIG1vZGVsIDIgDQoNCg0KIyMgU3RlcHdpc2UgbW9kZWxpbmcgYnkgQ29tcHV0ZXINCi0gU3RlcHdpc2Ugd2l0aCBtYW55IHByZWRpY3RzIGlzIG9mdGVuIGRvbmUgYnkgY29tcHV0ZXIgYW5kIGl0IGRvZXMgbm90IGFsd2F5cyBhc3N1bWUgbmVzdGVkIG1vZGVscyAoeW91IGNhbiBhZGQgYW5kIHJlbW92ZSBhdCB0aGUgc2FtZSkNCi0gRXhwbG9yYXRvcnk6IHlvdSBoYXZlIHRvbyBtYW55IHByZWRpY3RvcnMgYW5kIGhhdmUgbm8gaWRlYSB3aGVyZSB0byBzdGFydA0KLSBZb3UgZ2l2ZSB0aGUgY29tcHV0ZXIgYSBsYXJnZXIgbnVtYmVyIG9mIHByZWRpY3RvcnMsIGFuZCB0aGUgY29tcHV0ZXIgZGVjaWRlcyB0aGUgYmVzdCBmaXQgbW9kZWwNCi0gU291bmRzIGdvb2QsIHJpZ2h0PyBObywgYXMgdGhlIHJlc3VsdHMgY2FuIGJlIHVuc3RhYmxlDQogICAgLSBDaGFuZ2Ugb25lIHZhcmlhYmxlIGluIHRoZSBzZXQgYW5kIHRoZSBmaW5hbCBtb2RlbCBjYW4gY2hhbmdlDQogICAgLSBIaWdoIGNoYW5jZSBvZiB0eXBlIEkgYW5kIHR5cGUgSUkgZXJyb3INCiAgICAtIFRoZSBjb21wdXRlciBtYWtlcyBkZWNpc2lvbnMgYmFzZWQgb24gQWthaWtlIGluZm9ybWF0aW9uIGNyaXRlcmlvbiAoQUlDKSBub3Qgc2VsZWN0ZWQgYmFzZWQgb24gYSBjaGFuZ2UgaW4gJFJeMiQsIGJlY2F1c2UgbW9kZWxzIGFyZSBub3QgbmVzdGVkDQogICAgLSBhbHNvIGNvbXB1dGVyIG1ha2VzIGRlY2lzaW9ucyBwdXJlbHkgb24gZml0IHZhbHVlcyBhbmQgaGFzIG5vdGhpbmcgZG8gd2l0aCBhIHRoZW9yeQ0KICAgIC0gU29sdXRpb25zIGFyZSBvZnRlbiB1bmlxdWUgdG8gdGhhdCBwYXJ0aWN1bGFyIGRhdGFzZXQNCiAgICAtIFRoZSBiZXN0IG1vZGVsIGlzIG9mdGVuIHRoZSBvbmUgdGhhdCBwYXJzZXMgYSB0aGVvcnkgYW5kIG9ubHkgYSBodW1hbiBjYW4gZG8gdGhhdCBhdCBwcmVzZW50DQotIE5vdCByZWFsbHkgcHVibGlzaGFibGUgYmVjYXVzZSBvZiB0aGVzZSBwcm9ibGVtcw0KDQojIFBhcnNpbmcgaW5mbHVlbmNlDQotIEFzIG1vZGVscyBnZXQgYmlnZ2VyIGFuZCBiaWdnZXIgaXRzIGJlY29tZXMgYSBjaGFsbGVuZ2UgdG8gZmlndXJlIG91dCB0aGUgdW5pcXVlIGNvbnRyaWJ1dGlvbiB0byAkUl4yJCBvZiBlYWNoIHZhcmlhYmxlDQotIFRoZXJlIGFyZSBtYW55IGNvbXB1dGF0aW9uIHNvbHV0aW9ucyB0aGF0IHlvdSBjYW4gc2VsZWN0IGZyb20sIGJ1dCB3ZSB3aWxsIHVzZSBvbmUgY2FsbGVkICoqbG1nKioNCi0geW91IGNhbiByZWFkIGFib3V0IGFsbCB0aGUgZGlmZmVyZW50IG9uZXMgaGVyZTogPGh0dHBzOi8vY29yZS5hYy51ay9kb3dubG9hZC9wZGYvNjMwNTAwNi5wZGY+DQotIHRoZXNlIG1ldGhvZHMgYXJlIG5vdCB3ZWxsIGtub3duIGluIHBzeWNob2xvZ3ksIGJ1dCBjYW4gYmUgdmVyeSB1c2VmdWwgd2hlbiBwZW9wbGUgYXNrIHlvdSB3aGF0IHRoZSByZWxhdGl2ZSBpbXBvcnRhbmNlIG9mIGVhY2ggdmFyaWFibGUgaXMNCi0gdHdvIGFwcHJvYWNoZXM6IHNob3cgYWJzb2x1dGUgJFJeMiQgZm9yIGVhY2ggdGVybSBvciB0aGUgcmVsYXRpdmUgJSBvZiAkUl4yJCBmb3IgZWFjaCB0ZXJtDQoNCmBgYHtyLCBlY2hvPVRSVUUsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9DQpsaWJyYXJ5KHJlbGFpbXBvKQ0KIyBJbiB0ZXJtcyBvZiBSMg0KY2FsYy5yZWxpbXAoSWNlLkJyb3duLk1vZGVsKSANCiMgYXMgJSBvZiBSMg0KY2FsYy5yZWxpbXAoSWNlLkJyb3duLk1vZGVsLHJlbGEgPSBUUlVFKSANCmBgYA0KDQoNCiMgRmluYWwgbm90ZXM6IA0KLSBJZiB5b3UgcGxheSB3aXRoIGxvdHMgb2YgcHJlZGljdG9ycyBhbmQgZG8gbG90cyBvZiBtb2RlbHMsIHNvbWV0aGluZyB3aWxsIGJlIHNpZ25pZmljYW50DQotIFR5cGUgSSBlcnJvciBpcyBhIGJpZyBwcm9ibGVtIGJlY2F1c2Ugb2YgdGhlICdyZXNlYXJjaGVyIGRlZ3JlZSBvZiBmcmVlZG9tIHByb2JsZW0nDQotIFR5cGUgSUkgaW5jcmVhc2VzIGFzIGEgZnVuY3Rpb24gb2YgdGhlIG51bWJlciBvZiBwcmVkaWN0b3JzLiBhKSB5b3Ugc2xpY2UgdG9vIG11Y2ggcGllLCBiKSBlYWNoIHZhcmlhYmxlIG1pZ2h0IHRyeSB0byBlYWNoIGVhdCBzb21lb25lIGVsc2UncyBzbGljZQ0KLSBMZXNzIGlzIG1vcmU6IGFzayB0YXJnZXRlZCBxdWVzdGlvbnMgd2l0aCBhcyBvcnRob2dvbmFsIGEgc2V0IG9mIHZhcmlhYmxlcyBhcyB5b3UgY2FuIA0KPHNjcmlwdD4NCiAgKGZ1bmN0aW9uKGkscyxvLGcscixhLG0pe2lbJ0dvb2dsZUFuYWx5dGljc09iamVjdCddPXI7aVtyXT1pW3JdfHxmdW5jdGlvbigpew0KICAoaVtyXS5xPWlbcl0ucXx8W10pLnB1c2goYXJndW1lbnRzKX0saVtyXS5sPTEqbmV3IERhdGUoKTthPXMuY3JlYXRlRWxlbWVudChvKSwNCiAgbT1zLmdldEVsZW1lbnRzQnlUYWdOYW1lKG8pWzBdO2EuYXN5bmM9MTthLnNyYz1nO20ucGFyZW50Tm9kZS5pbnNlcnRCZWZvcmUoYSxtKQ0KICB9KSh3aW5kb3csZG9jdW1lbnQsJ3NjcmlwdCcsJ2h0dHBzOi8vd3d3Lmdvb2dsZS1hbmFseXRpY3MuY29tL2FuYWx5dGljcy5qcycsJ2dhJyk7DQoNCiAgZ2EoJ2NyZWF0ZScsICdVQS05MDQxNTE2MC0xJywgJ2F1dG8nKTsNCiAgZ2EoJ3NlbmQnLCAncGFnZXZpZXcnKTsNCg0KPC9zY3JpcHQ+DQo=