Simple Slopes With One Categorical and One Continuous Variable
Interactions
- Interactions have the same meaning they did in ANOVA
- there is a synergistic effect between two variables
- However now we can examine interactions between continuous variables
- Additive Effects:
\[Y = B_1X + B_2Z + B_0\]
- Interactive Effects: \[Y = B_1X + B_2Z + B_3XZ + B_0\]
Example of Interaction
- DV: Reading Speed, IVs: Age + IQ
- Simulation: \(Y = 3X + .2Z + .4XZ +100 +\epsilon\)
- So what we mean is: \(ReadingSpeed = 3*Age + .2*IQ + .4*Age*IQ +100 +Noise\)
- Set age to be uniform distribution between 7-17
- Set IQ to be normal, \(M\)=100 and \(S\)=15
- Set \(\epsilon\) = 15 (normal distribution of noise)
- Note: For our regression simulation to match our equation, we should center our X and Z variables first, but we will save out the raw score
set.seed(42) n <- 200 # Uniform distribution of Ages X <- runif(n, 7, 17) Xc<-scale(X,scale=F) # normal distrobution of IQ (100 +-15) Z <- rnorm(n, 100, 15) Zc<-scale(Z,scale=F) # Our equation to create Y Y <- 3*Xc + .2*Zc + .4*Xc*Zc +100 + rnorm(n, sd=15) #Built our data frame Reading.Data<-data.frame(Age=X,IQ=Z,ReadingSpeed=Y)
Scatterplot & correlate our predictors
- We will use a useful diagnostic tool (GGally)
- We will visualize the density, scatterplot and correlation all at once
library(GGally) DiagPlot <- ggpairs(Reading.Data, lower = list(continuous = "smooth")) DiagPlot
- Predictors have some heteroskedastic issues, but the correlations seem to make sense
Let's test for an interaction
- Center your variables
- Model 1: Examine a main-effects model (X + Z) [not necessary but useful]
- Model 2: Examine a main-effects + Interaction model (X + Z + X:Z)
- Note: You can simply code it as X*Z in r, as it will automatically do (X + Z + X:Z)
#Center Reading.Data$Age.C<-scale(Reading.Data$Age, center = TRUE, scale = FALSE)[,] Reading.Data$IQ.C<-scale(Reading.Data$IQ, center = TRUE, scale = FALSE)[,] # Regressions Centered.Read.1<-lm(ReadingSpeed~Age.C+IQ.C,Reading.Data) Centered.Read.2<-lm(ReadingSpeed~Age.C*IQ.C,Reading.Data) # Show results library(stargazer) stargazer(Centered.Read.1,Centered.Read.2,type="html", column.labels = c("Main Effects", "Interaction"), intercept.bottom = FALSE, single.row=TRUE, notes.append = FALSE, header=FALSE)
Dependent variable: | ||
ReadingSpeed | ||
Main Effects | Interaction | |
(1) | (2) | |
Constant | 99.441*** (1.616) | 99.363*** (1.009) |
Age.C | 2.287*** (0.555) | 2.412*** (0.346) |
IQ.C | 0.213* (0.112) | 0.234*** (0.070) |
Age.C:IQ.C | 0.402*** (0.023) | |
Observations | 200 | 200 |
R2 | 0.095 | 0.649 |
Adjusted R2 | 0.086 | 0.644 |
Residual Std. Error | 22.858 (df = 197) | 14.267 (df = 196) |
F Statistic | 10.326*** (df = 2; 197) | 120.907*** (df = 3; 196) |
Note: | p<0.1; p<0.05; p<0.01 |
- Also, change in \(R^2\) is significant, as we might expect
ChangeInR<-anova(Centered.Read.1,Centered.Read.2) knitr::kable(ChangeInR, digits=4)
Res.Df | RSS | Df | Sum of Sq | F | Pr(>F) |
---|---|---|---|---|---|
197 | 102930.36 | NA | NA | NA | NA |
196 | 39893.42 | 1 | 63036.93 | 309.7062 | 0 |
Examine residuals
- Main Effects Model
library(ggfortify) autoplot(Centered.Read.1, which = 1:2, label.size = 1) + theme_bw()
- Interactions Model
autoplot(Centered.Read.2, which = 1:2, label.size = 1) + theme_bw()
Understanding the Interaction
- Let's examine a 3d scatter plot of the raw data and plot against it the predicted results of each model (additive and interaction model)
- Once we have a "model" of the data, we can generate predictions for all possible Ages at every possible IQ (within the absolute boundary limits for our data)
- With 2 predictors that generates a "3D surface plane."
- You go past 2 predictors with these types of plots
- With 2 predictors that generates a "3D surface plane."
- Let's examine Model 1 (additive effects) as a 3D scatter/surface plot
- Scatter dots = Raw data points
- Surface = Model 1 Predicted Results
- How well does the surface fit the dots?
- Let's examine Model 2 (interaction effects) as a 3d scatter/surface plot
- Scatter dots = Raw data points
- Surface = Model 2 Predicted Results
- How well does the surface fit the dots?
How visualize this for Papers?
- Well, there are some options
- We can do our fancy-pants surface plot, but that is hard to put into a paper
- More common this is to examine slope of one factor at different levels of the other (Simple Slopes)
- What we need to decide is at which levels
Hand picking
- Manually select the what levels of each you are going to examine
- For tracking values of interest
- here I picked -3 to 3 for age (mix and max) and -15, 0 15 for IQ (theoretical 1 SD and mean)
library(effects) Inter.1a<-effect(c("Age.C*IQ.C"), Centered.Read.2, xlevels=list(Age.C=seq(-3,3, 1), IQ.C=c(-15,0,15)))
knitr::kable(summary(Inter.1a)$effect, digits=4) plot(Inter.1a, multiline = TRUE)
-15 | 0 | 15 | |
---|---|---|---|
-3 | 106.7108 | 92.1283 | 77.5458 |
-2 | 103.0896 | 94.5398 | 85.9900 |
-1 | 99.4684 | 96.9513 | 94.4343 |
0 | 95.8471 | 99.3629 | 102.8786 |
1 | 92.2259 | 101.7744 | 111.3229 |
2 | 88.6047 | 104.1859 | 119.7671 |
3 | 84.9835 | 106.5974 | 128.2114 |
Quantile
- Examine the levels based on quantiles (bins based on probability)
- We will do this into 5 equal bins based on probability cut-offs
- Does not assume normality for IV
IQ.Quantile<-quantile(Reading.Data$IQ.C,probs=c(0,.25,.50,.75,1)) IQ.Quantile<-round(IQ.Quantile,2) Inter.1b<-effect(c("Age.C*IQ.C"), Centered.Read.2, xlevels=list(Age.C=seq(-3,3, 1), IQ.C=IQ.Quantile)) plot(Inter.1b, multiline = TRUE)
Based on the SD
- We select 3 values: \(M-1SD\), \(M\), \(M+1SD\)
- Not it does not have to be 1 SD, it can be 1.5 ,2 or 3
- Assumes normality for IV
IQ.SD<-c(mean(Reading.Data$IQ.C)-sd(Reading.Data$IQ.C), mean(Reading.Data$IQ.C), mean(Reading.Data$IQ.C)+sd(Reading.Data$IQ.C)) IQ.SD<-round(IQ.SD,2) Inter.1c<-effect(c("Age.C*IQ.C"), Centered.Read.2, xlevels=list(Age.C=seq(-3,3, 1), IQ.C=IQ.SD)) plot(Inter.1c, multiline = TRUE)
Why center your IVs?
- The center of each IV represents the mean of that IV
- Thus when you interact them \(X*Z\), that means \(0*0 = 0\)
- Also, this can reduce multicollinearity issues
- This is because if \(X*Z\) creates a line, it means you have added a new predictor (XZ) that strongly correlates with X and Z
X<-c(0,2,4,6,8,10) Z<-c(0,2,4,6,8,10) XZ<-X*Z plot(XZ)
- Correlations: \(r_{x,z}\) = 1, \(r_{x,xz}\) = 0.96, \(r_{z,xz}\) = 0.96 -But if you center them, now you will make a U-shaped interaction which will be orthogonal to X and Z!
X.C<-scale(X, center = TRUE, scale = FALSE)[,] Z.C<-scale(Z, center = TRUE, scale = FALSE)[,] XZ.C<-X.C*Z.C plot(XZ.C)
-
Correlations: \(r_{x_c,z_c}\) = 1, \(r_{x_c,xz_c}\) = 0, \(r_{z_c,xz_c}\) = 0
-
Let's apply this to our class example
-
See below where I manually multiply the values and you can see a very strong positive slope
-
Left = Raw Score, Right plot = Centered Score
Let's run an uncentered regression
- as you can see the terms have changed from centered models
Uncentered.Read.1<-lm(ReadingSpeed~IQ+Age,Reading.Data) Uncentered.Read.2<-lm(ReadingSpeed~IQ*Age,Reading.Data)
Dependent variable: | ||
ReadingSpeed | ||
Main Effects | Interaction | |
(1) | (2) | |
Constant | 50.328*** (13.134) | 534.570*** (28.711) |
IQ | 0.213* (0.112) | -4.681*** (0.287) |
Age | 2.287*** (0.555) | -37.512*** (2.288) |
IQ:Age | 0.402*** (0.023) | |
Observations | 200 | 200 |
R2 | 0.095 | 0.649 |
Adjusted R2 | 0.086 | 0.644 |
Residual Std. Error | 22.858 (df = 197) | 14.267 (df = 196) |
F Statistic | 10.326*** (df = 2; 197) | 120.907*** (df = 3; 196) |
Note: | p<0.1; p<0.05; p<0.01 |
Multicollinearity of the Interaction
- Multicollinearity of the uncentered model
vif(Uncentered.Read.2)
## IQ Age IQ:Age ## 16.70086 43.64111 59.58237
- We lost our main effect of Age as the variances got all inflated
- We did not have this problem in the centered model
vif(Centered.Read.2)
## Age.C IQ.C Age.C:IQ.C ## 1.000440 1.000316 1.000716
- Note: Its OK to plot the uncentered version, but run the analysis on the centered data
Testing Simple Slopes
- The goal here is to figure out when the slope at a given level of another variable is different from zero
- We chop up the interaction at specific places as we did with the interactions plots (-1 SD, M, +1 SD) on the moderating variable (a third variable that affects the strength of the relationship between a dependent and independent variable)
- Next, we test the slopes on the predictor variable (IV of main interest)
- Example: Performance on a task, predicted by Level of training, moderated by how hard the challenge is
Example of Interaction
- DV: Performance, IVs: Training (X) + Challenge (Z)
- Simulation: \(Y = 2.2X + 2.46Z + .75XZ +16 +\epsilon\)
- Set Training to be uniform distribution between -10 to 10
- Set Challenge to be normal, \(M\)=0 and \(S\)=15
- Set \(\epsilon\) = 50 (normal distribution of noise)
- Note: For our regression simulation we will set means to about zero (so are not forced to center them)
set.seed(42) # 250 people n <- 250 #Training (low to high) X <- runif(n, -10, 10) # normal distribution of Challenge Difficulty Z <- rnorm(n, 0, 15) # Our equation to create Y Y <- 2.2*X + 2.46*Z + .75*X*Z + 16 + rnorm(n, sd=50) #Built our data frame Skill.Data<-data.frame(Training=X,Challenge=Z,Performance=Y) #run our regression Skill.Model.1<-lm(Performance~Training+Challenge,Skill.Data) Skill.Model.2<-lm(Performance~Training*Challenge,Skill.Data)
Dependent variable: | ||
Performance | ||
Main Effects | Interaction | |
(1) | (2) | |
Constant | 14.238*** (4.909) | 16.173*** (3.268) |
Training | 0.895 (0.843) | 1.542*** (0.562) |
Challenge | 2.855*** (0.354) | 2.600*** (0.236) |
Training:Challenge | 0.762*** (0.043) | |
Observations | 250 | 250 |
R2 | 0.210 | 0.652 |
Adjusted R2 | 0.204 | 0.648 |
Residual Std. Error | 77.510 (df = 247) | 51.571 (df = 246) |
F Statistic | 32.867*** (df = 2; 247) | 153.486*** (df = 3; 246) |
Note: | p<0.1; p<0.05; p<0.01 |
Plotting
- We will use the
rockchalk
library to visualize our interaction and test our simple slopes
library(rockchalk) m1ps <- plotSlopes(Skill.Model.2, modx = "Challenge", plotx = "Training", n=3, modxVals="std.dev") m1psts <- testSlopes(m1ps) round(m1psts$hypotests,4)
## Values of Challenge OUTSIDE this interval: ## lo hi ## -3.5050807 -0.5730182 ## cause the slope of (b1 + b2*Challenge)Training to be statistically significant ## "Challenge" slope Std. Error t value Pr(>|t|) ## (m-sd) -14.50 -9.5013 0.8131 -11.6848 0.0000 ## (m) -0.61 1.0771 0.5611 1.9196 0.0561 ## (m+sd) 13.28 11.6554 0.8282 14.0737 0.0000
- We see the slope at the mean is not significant,
- The +1SD and -1SD are significant, this is what is driving the interaction
- Well trained people at low levels of challenge get worse with more training, while high levels of challenge with more training get better
- The bonus using rockchalk is that you can change the number of lines (change \(n=3\)) you want to see or you can test quantiles as well (change modxVals="quantile")
m1pQ <- plotSlopes(Skill.Model.2, modx = "Challenge", plotx = "Training", n=5, modxVals="quantile") m1pQts <- testSlopes(m1pQ) round(m1pQts$hypotests,4)
## Values of Challenge OUTSIDE this interval: ## lo hi ## -3.5050807 -0.5730182 ## cause the slope of (b1 + b2*Challenge)Training to be statistically significant ## "Challenge" slope Std. Error t value Pr(>|t|) ## 0% -40.4989 -29.3016 1.7993 -16.2847 0.0000 ## 25% -10.5190 -6.4694 0.6990 -9.2555 0.0000 ## 50% -0.7985 0.9335 0.5610 1.6640 0.0974 ## 75% 8.8382 8.2726 0.6994 11.8278 0.0000 ## 100% 36.8939 29.6394 1.7214 17.2183 0.0000
Notes
- You often don't need to run the t-tests on the simple slopes, but they can useful to test very specific hypotheses
- You can run simple slopes analysis on three-way interactions, but let's leave that aside for now as you would have to use a different R-package
Non-Linear interactions
- You can have non-linear terms interacting with other linear and non-linear terms
- Example: Quit smoking, X = Fear of your health, Z = moderated by Self-Efficacy for quitting
Example of Polynomial Interaction
- DV: Quit smoking, IVs: Fear (X) + Self-Efficacy (Z)
- Simulation: \(Y = -.18X - .15X^2 + Z + .16XZ + .07X^2Z +20 +\epsilon\)
- Set Fear of your health to be uniform distribution between 1 to 9 (centered)
- Set Self-Efficacy to be normal, \(M\)=0 and \(S\)=15
- Set \(\epsilon\) = 10 (normal distribution of noise)
set.seed(42) n <- 250 #Fear of Health X <- scale(runif(n, 1, 9), scale=F) #Centered Self-Efficacy Z <- scale(runif(n, 0, 15), scale=F) # Our equation to create Y Y <- -.05*X - .20*X^2 + .15*X*Z + .22*(X^2)*Z+ 35 + rnorm(n, sd=10) #Built our data frame Smoke.Data<-data.frame(Smoking=Y,Health=X,SelfEfficacy=Z) #run our regression Smoke.Model.1<-lm(Smoking~poly(Health,2)+SelfEfficacy,Smoke.Data) Smoke.Model.2<-lm(Smoking~poly(Health,2)*SelfEfficacy,Smoke.Data) Smoke.Model.1.R<-lm(Smoking~poly(Health,2, raw=T)+SelfEfficacy,Smoke.Data) Smoke.Model.2.R<-lm(Smoking~poly(Health,2, raw=T)*SelfEfficacy,Smoke.Data)
- Orthogonal Polynomials
Dependent variable: | ||
Smoking | ||
Main Effects | Interaction | |
(1) | (2) | |
Constant | 33.263*** (0.680) | 33.493*** (0.621) |
poly(Health, 2)1 | 1.010 (10.786) | 3.083 (9.813) |
poly(Health, 2)2 | -9.037 (10.766) | -6.505 (9.795) |
SelfEfficacy | 1.188*** (0.155) | 1.189*** (0.141) |
poly(Health, 2)1:SelfEfficacy | 3.042 (2.218) | |
poly(Health, 2)2:SelfEfficacy | 16.361*** (2.288) | |
Observations | 250 | 250 |
R2 | 0.197 | 0.341 |
Adjusted R2 | 0.187 | 0.328 |
Residual Std. Error | 10.759 (df = 246) | 9.781 (df = 244) |
F Statistic | 20.058*** (df = 3; 246) | 25.297*** (df = 5; 244) |
Note: | p<0.1; p<0.05; p<0.01 |
- Power Polynomials
Dependent variable: | ||
Smoking | ||
Main Effects Non-Ortho | Interaction Non-Ortho | |
(1) | (2) | |
Constant | 33.909*** (1.027) | 33.958*** (0.934) |
poly(Health, 2, raw = T)1 | 0.009 (0.294) | 0.070 (0.268) |
poly(Health, 2, raw = T)2 | -0.119 (0.142) | -0.086 (0.129) |
SelfEfficacy | 1.188*** (0.155) | 0.020 (0.217) |
poly(Health, 2, raw = T)1:SelfEfficacy | 0.116* (0.060) | |
poly(Health, 2, raw = T)2:SelfEfficacy | 0.216*** (0.030) | |
Observations | 250 | 250 |
R2 | 0.197 | 0.341 |
Adjusted R2 | 0.187 | 0.328 |
Residual Std. Error | 10.759 (df = 246) | 9.781 (df = 244) |
F Statistic | 20.058*** (df = 3; 246) | 25.297*** (df = 5; 244) |
Note: | p<0.1; p<0.05; p<0.01 |
- Note how different the results might look when you examine that as power polynomials
Plotting the Simple Slopes when there are Curves
- These can be done with the
effects
package as I showed you above and last week - We will work with the orthogonal polynomial models
- or we can simply use the plotCurves function from the 'rockchalk' package
SmokeInterPlot <- plotCurves(Smoke.Model.2, modx = "SelfEfficacy", plotx = "Health", n=3,modxVals="std.dev")
- Lets plot just the main effect (and think about what it means relative the power)
plotCurves(Smoke.Model.1, plotx = "Health")
- Does not look very quadratic, does it? In other words, you cannot see the higher order effects as they can be hidden by the moderating variable
- How to find these hidden things?
- You have to test for interactions and changes in \(R^2\)
- You have to try to add higher order terms, but they should be motivated by some theory
- What if you did not know the second order term was in the model above.
Smoke.Model.1.L<-lm(Smoking~Health+SelfEfficacy,Smoke.Data) Smoke.Model.2.L<-lm(Smoking~Health*SelfEfficacy,Smoke.Data)
Dependent variable: | ||
Smoking | ||
Main Effects | Interaction | |
(1) | (2) | |
Constant | 33.263*** (0.680) | 33.334*** (0.680) |
Health | 0.028 (0.293) | 0.042 (0.292) |
SelfEfficacy | 1.193*** (0.155) | 1.207*** (0.155) |
Health:SelfEfficacy | 0.097 (0.066) | |
Observations | 250 | 250 |
R2 | 0.194 | 0.201 |
Adjusted R2 | 0.188 | 0.192 |
Residual Std. Error | 10.752 (df = 247) | 10.727 (df = 246) |
F Statistic | 29.770*** (df = 2; 247) | 20.666*** (df = 3; 246) |
Note: | p<0.1; p<0.05; p<0.01 |
ChangeInR.Smoke<-anova(Smoke.Model.1.L,Smoke.Model.2.L) knitr::kable(ChangeInR.Smoke, digits=4)
Res.Df | RSS | Df | Sum of Sq | F | Pr(>F) |
---|---|---|---|---|---|
247 | 28557.09 | NA | NA | NA | NA |
246 | 28306.63 | 1 | 250.4599 | 2.1766 | 0.1414 |
- There is no significant interaction, but let's plot it anyway.
- Replotting as linear interaction
SmokeInterPlot.Linear <- plotSlopes(Smoke.Model.2.L, modx = "SelfEfficacy", plotx = "Health", n=3, modxVals="std.dev")
- Let's check the change in \(R^2\) from Linear interaction model to poly interaction model now
stargazer(Smoke.Model.2.L,Smoke.Model.2,type="html", column.labels = c("Linear", "Poly"), intercept.bottom = FALSE, single.row=TRUE, notes.append = FALSE, header=FALSE)
Dependent variable: | ||
Smoking | ||
Linear | Poly | |
(1) | (2) | |
Constant | 33.334*** (0.680) | 33.493*** (0.621) |
Health | 0.042 (0.292) | |
poly(Health, 2)1 | 3.083 (9.813) | |
poly(Health, 2)2 | -6.505 (9.795) | |
SelfEfficacy | 1.207*** (0.155) | 1.189*** (0.141) |
Health:SelfEfficacy | 0.097 (0.066) | |
poly(Health, 2)1:SelfEfficacy | 3.042 (2.218) | |
poly(Health, 2)2:SelfEfficacy | 16.361*** (2.288) | |
Observations | 250 | 250 |
R2 | 0.201 | 0.341 |
Adjusted R2 | 0.192 | 0.328 |
Residual Std. Error | 10.727 (df = 246) | 9.781 (df = 244) |
F Statistic | 20.666*** (df = 3; 246) | 25.297*** (df = 5; 244) |
Note: | p<0.1; p<0.05; p<0.01 |
ChangeInR.Smoke.2<-anova(Smoke.Model.2,Smoke.Model.2.L) knitr::kable(ChangeInR.Smoke.2, digits=4)
Res.Df | RSS | Df | Sum of Sq | F | Pr(>F) |
---|---|---|---|---|---|
244 | 23341.19 | NA | NA | NA | NA |
246 | 28306.63 | -2 | -4965.442 | 25.9534 | 0 |
Notes
- So, model with poly is a significantly better fit
- Would it change the story by much? In this case YES, but not always!
- Sometimes the improvement in fit is minor and does not change the story
- Often ignoring the higher order term can make it easier to test simple slopes and tell a story
- However, ignoring the higher order terms can violate your assumptions when the results, let's compare our linear vs poly models residuals
- Sometimes the improvement in fit is minor and does not change the story
- Linear Model
autoplot(Smoke.Model.2, which = 1:2, label.size = 1) + theme_bw()
- Quadtradic Model
autoplot(Smoke.Model.2.L, which = 1:2, label.size = 1) + theme_bw()
LS0tDQp0aXRsZTogJ0ludGVyYWN0aW9ucyBhbmQgU2ltcGxlIFNsb3BlcycNCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDoNCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMNCiAgICBmb250c2l6ZTogOHB0DQogICAgaGlnaGxpZ2h0OiB0ZXh0bWF0ZQ0KICAgIG51bWJlcl9zZWN0aW9uczogbm8NCiAgICB0aGVtZTogZmxhdGx5DQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZmxvYXQ6DQogICAgICBjb2xsYXBzZWQ6IG5vDQotLS0NCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoY2FjaGU9VFJVRSkNCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkgI1Nob3cgYWxsIHNjcmlwdCBieSBkZWZhdWx0DQprbml0cjo6b3B0c19jaHVuayRzZXQobWVzc2FnZSA9IEZBTFNFKSAjaGlkZSBtZXNzYWdlcyANCmtuaXRyOjpvcHRzX2NodW5rJHNldCh3YXJuaW5nID0gIEZBTFNFKSAjaGlkZSBwYWNrYWdlIHdhcm5pbmdzIA0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGZpZy53aWR0aD01KSAjU2V0IGRlZmF1bHQgZmlndXJlIHNpemVzDQprbml0cjo6b3B0c19jaHVuayRzZXQoZmlnLmhlaWdodD00LjUpICNTZXQgZGVmYXVsdCBmaWd1cmUgc2l6ZXMNCmtuaXRyOjpvcHRzX2NodW5rJHNldChmaWcuYWxpZ249J2NlbnRlcicpICNTZXQgZGVmYXVsdCBmaWd1cmUNCmtuaXRyOjpvcHRzX2NodW5rJHNldChmaWcuc2hvdyA9ICJob2xkIikgI1NldCBkZWZhdWx0IGZpZ3VyZQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KHJlc3VsdHMgPSAiaG9sZCIpICNTZXQgZGVmYXVsdCBmaWd1cmUNCmBgYA0KDQojIEludGVyYWN0aW9ucw0KLSBJbnRlcmFjdGlvbnMgaGF2ZSB0aGUgc2FtZSBtZWFuaW5nIHRoZXkgZGlkIGluIEFOT1ZBDQogICAgLSB0aGVyZSBpcyBhIHN5bmVyZ2lzdGljIGVmZmVjdCBiZXR3ZWVuIHR3byB2YXJpYWJsZXMNCiAgICAtIEhvd2V2ZXIgbm93IHdlIGNhbiBleGFtaW5lIGludGVyYWN0aW9ucyBiZXR3ZWVuIGNvbnRpbnVvdXMgdmFyaWFibGVzDQotIEFkZGl0aXZlIEVmZmVjdHM6DQoNCiQkWSA9IEJfMVggKyBCXzJaICsgQl8wJCQNCg0KLSBJbnRlcmFjdGl2ZSBFZmZlY3RzOiANCiQkWSA9IEJfMVggKyBCXzJaICsgQl8zWFogKyBCXzAkJA0KDQoNCiMjIEV4YW1wbGUgb2YgSW50ZXJhY3Rpb24NCi0gRFY6IFJlYWRpbmcgU3BlZWQsIElWczogQWdlICsgSVEgDQotIFNpbXVsYXRpb246ICRZID0gM1ggKyAuMlogKyAuNFhaICsxMDAgK1xlcHNpbG9uJA0KLSBTbyB3aGF0IHdlIG1lYW4gaXM6ICRSZWFkaW5nU3BlZWQgPSAzKkFnZSArIC4yKklRICsgLjQqQWdlKklRICsxMDAgK05vaXNlJA0KICAgIC0gU2V0IGFnZSB0byBiZSB1bmlmb3JtIGRpc3RyaWJ1dGlvbiBiZXR3ZWVuIDctMTcgDQogICAgLSBTZXQgSVEgdG8gYmUgbm9ybWFsLCAkTSQ9MTAwIGFuZCAkUyQ9MTUNCiAgICAtIFNldCAkXGVwc2lsb24kID0gMTUgKG5vcm1hbCBkaXN0cmlidXRpb24gb2Ygbm9pc2UpDQogICAgLSBOb3RlOiBGb3Igb3VyIHJlZ3Jlc3Npb24gc2ltdWxhdGlvbiB0byBtYXRjaCBvdXIgZXF1YXRpb24sIHdlIHNob3VsZCBjZW50ZXIgb3VyIFggYW5kIFogdmFyaWFibGVzIGZpcnN0LCBidXQgd2Ugd2lsbCBzYXZlIG91dCB0aGUgcmF3IHNjb3JlIA0KYGBge3IsIGVjaG89VFJVRSwgd2FybmluZz1GQUxTRX0NCnNldC5zZWVkKDQyKQ0KbiA8LSAyMDANCiMgVW5pZm9ybSBkaXN0cmlidXRpb24gb2YgQWdlcyANClggPC0gcnVuaWYobiwgNywgMTcpDQpYYzwtc2NhbGUoWCxzY2FsZT1GKQ0KIyBub3JtYWwgZGlzdHJvYnV0aW9uIG9mIElRICgxMDAgKy0xNSkgDQpaIDwtIHJub3JtKG4sIDEwMCwgMTUpDQpaYzwtc2NhbGUoWixzY2FsZT1GKQ0KIyBPdXIgZXF1YXRpb24gdG8gIGNyZWF0ZSBZDQpZIDwtIDMqWGMgKyAuMipaYyArIC40KlhjKlpjICsxMDAgKyBybm9ybShuLCBzZD0xNSkNCiNCdWlsdCBvdXIgZGF0YSBmcmFtZQ0KUmVhZGluZy5EYXRhPC1kYXRhLmZyYW1lKEFnZT1YLElRPVosUmVhZGluZ1NwZWVkPVkpDQpgYGANCg0KIyMgU2NhdHRlcnBsb3QgJiBjb3JyZWxhdGUgb3VyIHByZWRpY3RvcnMNCi0gV2Ugd2lsbCB1c2UgYSB1c2VmdWwgZGlhZ25vc3RpYyB0b29sIChHR2FsbHkpDQotIFdlIHdpbGwgdmlzdWFsaXplIHRoZSBkZW5zaXR5LCBzY2F0dGVycGxvdCBhbmQgY29ycmVsYXRpb24gYWxsIGF0IG9uY2UNCg0KYGBge3IsZmlnLndpZHRoPTQuNSxmaWcuaGVpZ2h0PTQuNX0NCmxpYnJhcnkoR0dhbGx5KQ0KRGlhZ1Bsb3QgPC0gZ2dwYWlycyhSZWFkaW5nLkRhdGEsICANCiAgICAgICAgICAgICAgbG93ZXIgPSBsaXN0KGNvbnRpbnVvdXMgPSAic21vb3RoIikpDQpEaWFnUGxvdA0KYGBgDQoNCi0gUHJlZGljdG9ycyBoYXZlIHNvbWUgaGV0ZXJvc2tlZGFzdGljIGlzc3VlcywgYnV0IHRoZSBjb3JyZWxhdGlvbnMgc2VlbSB0byBtYWtlIHNlbnNlDQoNCg0KIyMgTGV0J3MgdGVzdCBmb3IgYW4gaW50ZXJhY3Rpb24NCjEuIENlbnRlciB5b3VyIHZhcmlhYmxlcw0KMi4gTW9kZWwgMTogRXhhbWluZSBhIG1haW4tZWZmZWN0cyBtb2RlbCAoWCArIFopIFtub3QgbmVjZXNzYXJ5IGJ1dCB1c2VmdWxdDQozLiBNb2RlbCAyOiBFeGFtaW5lIGEgbWFpbi1lZmZlY3RzICsgSW50ZXJhY3Rpb24gbW9kZWwgKFggKyBaICsgWDpaKQ0KDQotIE5vdGU6IFlvdSBjYW4gc2ltcGx5IGNvZGUgaXQgYXMgWCpaIGluIHIsIGFzIGl0IHdpbGwgYXV0b21hdGljYWxseSBkbyAoWCArIFogKyBYOlopDQoNCmBgYHtyLCBlY2hvPVRSVUUsIHJlc3VsdHM9J2FzaXMnfQ0KI0NlbnRlcg0KUmVhZGluZy5EYXRhJEFnZS5DPC1zY2FsZShSZWFkaW5nLkRhdGEkQWdlLCBjZW50ZXIgPSBUUlVFLCBzY2FsZSA9IEZBTFNFKVssXQ0KUmVhZGluZy5EYXRhJElRLkM8LXNjYWxlKFJlYWRpbmcuRGF0YSRJUSwgY2VudGVyID0gVFJVRSwgc2NhbGUgPSBGQUxTRSlbLF0NCiMgUmVncmVzc2lvbnMNCkNlbnRlcmVkLlJlYWQuMTwtbG0oUmVhZGluZ1NwZWVkfkFnZS5DK0lRLkMsUmVhZGluZy5EYXRhKQ0KQ2VudGVyZWQuUmVhZC4yPC1sbShSZWFkaW5nU3BlZWR+QWdlLkMqSVEuQyxSZWFkaW5nLkRhdGEpDQojIFNob3cgcmVzdWx0cw0KbGlicmFyeShzdGFyZ2F6ZXIpDQpzdGFyZ2F6ZXIoQ2VudGVyZWQuUmVhZC4xLENlbnRlcmVkLlJlYWQuMix0eXBlPSJodG1sIiwNCiAgICAgICAgICBjb2x1bW4ubGFiZWxzID0gYygiTWFpbiBFZmZlY3RzIiwgIkludGVyYWN0aW9uIiksDQogICAgICAgICAgaW50ZXJjZXB0LmJvdHRvbSA9IEZBTFNFLCBzaW5nbGUucm93PVRSVUUsIA0KICAgICAgICAgIG5vdGVzLmFwcGVuZCA9IEZBTFNFLCBoZWFkZXI9RkFMU0UpDQpgYGANCg0KLSBBbHNvLCBjaGFuZ2UgaW4gJFJeMiQgaXMgc2lnbmlmaWNhbnQsIGFzIHdlIG1pZ2h0IGV4cGVjdA0KDQpgYGB7cn0NCkNoYW5nZUluUjwtYW5vdmEoQ2VudGVyZWQuUmVhZC4xLENlbnRlcmVkLlJlYWQuMikNCmtuaXRyOjprYWJsZShDaGFuZ2VJblIsIGRpZ2l0cz00KQ0KYGBgDQoNCiMjIyBFeGFtaW5lIHJlc2lkdWFscw0KLSBNYWluIEVmZmVjdHMgTW9kZWwNCmBgYHtyLCBmaWcud2lkdGg9Nn0NCmxpYnJhcnkoZ2dmb3J0aWZ5KQ0KYXV0b3Bsb3QoQ2VudGVyZWQuUmVhZC4xLCB3aGljaCA9IDE6MiwgbGFiZWwuc2l6ZSA9IDEpICsgdGhlbWVfYncoKQ0KYGBgDQoNCi0gSW50ZXJhY3Rpb25zIE1vZGVsDQoNCmBgYHtyLCBmaWcud2lkdGg9Nn0NCmF1dG9wbG90KENlbnRlcmVkLlJlYWQuMiwgd2hpY2ggPSAxOjIsIGxhYmVsLnNpemUgPSAxKSArIHRoZW1lX2J3KCkNCmBgYA0KDQojIyBVbmRlcnN0YW5kaW5nIHRoZSBJbnRlcmFjdGlvbiANCi0gTGV0J3MgZXhhbWluZSBhIDNkIHNjYXR0ZXIgcGxvdCBvZiB0aGUgcmF3IGRhdGEgYW5kIHBsb3QgYWdhaW5zdCBpdCB0aGUgcHJlZGljdGVkIHJlc3VsdHMgb2YgZWFjaCBtb2RlbCAoYWRkaXRpdmUgYW5kIGludGVyYWN0aW9uIG1vZGVsKQ0KLSBPbmNlIHdlIGhhdmUgYSAibW9kZWwiIG9mIHRoZSBkYXRhLCB3ZSBjYW4gZ2VuZXJhdGUgcHJlZGljdGlvbnMgZm9yICoqYWxsIHBvc3NpYmxlIEFnZXMqKiBhdCAqKmV2ZXJ5IHBvc3NpYmxlIElRKiogKHdpdGhpbiB0aGUgYWJzb2x1dGUgYm91bmRhcnkgbGltaXRzIGZvciBvdXIgZGF0YSkNCiAgICAtIFdpdGggMiBwcmVkaWN0b3JzIHRoYXQgZ2VuZXJhdGVzIGEgIjNEIHN1cmZhY2UgcGxhbmUuIg0KICAgICAgICAtIFlvdSBnbyBwYXN0IDIgcHJlZGljdG9ycyB3aXRoIHRoZXNlIHR5cGVzIG9mIHBsb3RzDQotIExldCdzIGV4YW1pbmUgTW9kZWwgMSAoYWRkaXRpdmUgZWZmZWN0cykgYXMgYSAzRCBzY2F0dGVyL3N1cmZhY2UgcGxvdA0KICAgIC0gU2NhdHRlciBkb3RzID0gUmF3IGRhdGEgcG9pbnRzDQogICAgLSBTdXJmYWNlID0gTW9kZWwgMSBQcmVkaWN0ZWQgUmVzdWx0cw0KICAgICAgICAtIEhvdyB3ZWxsIGRvZXMgdGhlIHN1cmZhY2UgZml0IHRoZSBkb3RzPyANCg0KYGBge3IsIGVjaG8gPSBGQUxTRX0NCmxpYnJhcnkocGxvdGx5KQ0KbGlicmFyeShkcGx5cikNClJlYWQuMTwtbG0oUmVhZGluZ1NwZWVkfkFnZStJUSxSZWFkaW5nLkRhdGEpDQpSZWFkLjI8LWxtKFJlYWRpbmdTcGVlZH5BZ2UqSVEsUmVhZGluZy5EYXRhKQ0KIyBwcmVkaWN0IG92ZXIgc2Vuc2libGUgZ3JpZCBvZiB2YWx1ZXMNCmdyYXBoX3Jlc28gPC0gLjUNCkFnZS5QTCA8LSBzZXEobWluKFJlYWRpbmcuRGF0YSRBZ2UpLCBtYXgoUmVhZGluZy5EYXRhJEFnZSksIGJ5ID0gZ3JhcGhfcmVzbykNCklRLlBMIDwtIHNlcShtaW4oUmVhZGluZy5EYXRhJElRKSwgbWF4KFJlYWRpbmcuRGF0YSRJUSksIGJ5ID0gZ3JhcGhfcmVzbykNCmQgPC0gc2V0TmFtZXMoZGF0YS5mcmFtZShleHBhbmQuZ3JpZChBZ2UuUEwsIElRLlBMKSksYygiQWdlIiwgIklRIikpDQp2YWxzMSA8LSBwcmVkaWN0KFJlYWQuMSwgbmV3ZGF0YSA9IGQpDQp2YWxzMiA8LSBwcmVkaWN0KFJlYWQuMiwgbmV3ZGF0YSA9IGQpDQojIGZvcm0gbWF0cml4IGFuZCBnaXZlIHRvIHBsb3RseQ0KbTEgPC0gbWF0cml4KHZhbHMxLCBucm93ID0gbGVuZ3RoKHVuaXF1ZShkJEFnZSkpLCBuY29sID0gbGVuZ3RoKHVuaXF1ZShkJElRKSkpDQptMiA8LSBtYXRyaXgodmFsczIsIG5yb3cgPSBsZW5ndGgodW5pcXVlKGQkQWdlKSksIG5jb2wgPSBsZW5ndGgodW5pcXVlKGQkSVEpKSkNCmBgYA0KDQpgYGB7ciwgZWNobyA9IEZBTFNFLCBmaWcud2lkdGg9NS41LGZpZy5oZWlnaHQ9NS41fQ0KcDEgPC0gcGxvdF9seShSZWFkaW5nLkRhdGEsIHggPSB+SVEsIHkgPSB+QWdlLCB6ID0gflJlYWRpbmdTcGVlZCkgJT4lDQogIGFkZF9tYXJrZXJzKG1hcmtlciA9IGxpc3Qoc2l6ZSA9IDQpKSAgJT4lIA0KICBhZGRfc3VyZmFjZSh4ID0gfklRLlBMLCB5ID0gfkFnZS5QTCwgeiA9IH5tMSxzaG93c2NhbGUgPSBGQUxTRSwgb3BhY2l0eT0uNzUpDQpwMQ0KYGBgDQoNCi0gTGV0J3MgZXhhbWluZSBNb2RlbCAyIChpbnRlcmFjdGlvbiBlZmZlY3RzKSBhcyBhIDNkIHNjYXR0ZXIvc3VyZmFjZSBwbG90DQogICAgLSBTY2F0dGVyIGRvdHMgPSBSYXcgZGF0YSBwb2ludHMNCiAgICAtIFN1cmZhY2UgPSBNb2RlbCAyIFByZWRpY3RlZCBSZXN1bHRzDQogICAgICAgIC0gSG93IHdlbGwgZG9lcyB0aGUgc3VyZmFjZSBmaXQgdGhlIGRvdHM/IA0KDQpgYGB7ciwgZWNobyA9IEZBTFNFLCBmaWcud2lkdGg9NS41LGZpZy5oZWlnaHQ9NS41fQ0KcDIgPC0gcGxvdF9seShSZWFkaW5nLkRhdGEsIHggPSB+SVEsIHkgPSB+QWdlLCB6ID0gflJlYWRpbmdTcGVlZCkgJT4lDQogIGFkZF9tYXJrZXJzKG1hcmtlciA9IGxpc3Qoc2l6ZSA9IDQpKSAgJT4lIA0KICBhZGRfc3VyZmFjZSh4ID0gfklRLlBMLCB5ID0gfkFnZS5QTCwgeiA9IH5tMixzaG93c2NhbGUgPSBGQUxTRSwgb3BhY2l0eT0uNzUpDQpwMg0KYGBgDQoNCg0KIyMgSG93IHZpc3VhbGl6ZSB0aGlzIGZvciBQYXBlcnM/DQotIFdlbGwsIHRoZXJlIGFyZSBzb21lIG9wdGlvbnMNCi0gV2UgY2FuIGRvIG91ciBmYW5jeS1wYW50cyBzdXJmYWNlIHBsb3QsIGJ1dCB0aGF0IGlzIGhhcmQgdG8gcHV0IGludG8gYSBwYXBlcg0KLSBNb3JlIGNvbW1vbiB0aGlzIGlzIHRvIGV4YW1pbmUgc2xvcGUgb2Ygb25lIGZhY3RvciBhdCBkaWZmZXJlbnQgbGV2ZWxzIG9mIHRoZSBvdGhlciAoU2ltcGxlIFNsb3BlcykgDQotIFdoYXQgd2UgbmVlZCB0byBkZWNpZGUgaXMgYXQgd2hpY2ggbGV2ZWxzDQoNCiMjIyBIYW5kIHBpY2tpbmcNCi0gTWFudWFsbHkgc2VsZWN0IHRoZSB3aGF0IGxldmVscyBvZiBlYWNoIHlvdSBhcmUgZ29pbmcgdG8gZXhhbWluZQ0KLSBGb3IgdHJhY2tpbmcgdmFsdWVzIG9mIGludGVyZXN0DQotIGhlcmUgSSBwaWNrZWQgLTMgdG8gMyBmb3IgYWdlIChtaXggYW5kIG1heCkgYW5kIC0xNSwgMCAxNSBmb3IgSVEgKHRoZW9yZXRpY2FsIDEgU0QgYW5kIG1lYW4pDQoNCmBgYHtyfQ0KbGlicmFyeShlZmZlY3RzKQ0KSW50ZXIuMWE8LWVmZmVjdChjKCJBZ2UuQypJUS5DIiksIENlbnRlcmVkLlJlYWQuMiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHhsZXZlbHM9bGlzdChBZ2UuQz1zZXEoLTMsMywgMSksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIElRLkM9YygtMTUsMCwxNSkpKQ0KYGBgDQoNCg0KYGBge3J9DQprbml0cjo6a2FibGUoc3VtbWFyeShJbnRlci4xYSkkZWZmZWN0LCBkaWdpdHM9NCkNCnBsb3QoSW50ZXIuMWEsIG11bHRpbGluZSA9IFRSVUUpDQpgYGANCg0KIyMjIFF1YW50aWxlDQotIEV4YW1pbmUgdGhlIGxldmVscyBiYXNlZCBvbiBxdWFudGlsZXMgKGJpbnMgYmFzZWQgb24gcHJvYmFiaWxpdHkpDQotIFdlIHdpbGwgZG8gdGhpcyBpbnRvIDUgZXF1YWwgYmlucyBiYXNlZCBvbiBwcm9iYWJpbGl0eSBjdXQtb2ZmcyANCi0gRG9lcyBub3QgYXNzdW1lIG5vcm1hbGl0eSBmb3IgSVYNCg0KYGBge3J9DQpJUS5RdWFudGlsZTwtcXVhbnRpbGUoUmVhZGluZy5EYXRhJElRLkMscHJvYnM9YygwLC4yNSwuNTAsLjc1LDEpKQ0KSVEuUXVhbnRpbGU8LXJvdW5kKElRLlF1YW50aWxlLDIpDQoNCkludGVyLjFiPC1lZmZlY3QoYygiQWdlLkMqSVEuQyIpLCBDZW50ZXJlZC5SZWFkLjIsDQogICAgICAgICAgICAgICAgIHhsZXZlbHM9bGlzdChBZ2UuQz1zZXEoLTMsMywgMSksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgSVEuQz1JUS5RdWFudGlsZSkpDQpwbG90KEludGVyLjFiLCBtdWx0aWxpbmUgPSBUUlVFKQ0KYGBgDQoNCiMjIyBCYXNlZCBvbiB0aGUgU0QgDQotIFdlIHNlbGVjdCAzIHZhbHVlczogJE0tMVNEJCwgJE0kLCAkTSsxU0QkDQotIE5vdCBpdCBkb2VzIG5vdCBoYXZlIHRvIGJlIDEgU0QsIGl0IGNhbiBiZSAxLjUgLDIgb3IgMw0KLSBBc3N1bWVzIG5vcm1hbGl0eSBmb3IgSVYNCg0KYGBge3J9DQpJUS5TRDwtYyhtZWFuKFJlYWRpbmcuRGF0YSRJUS5DKS1zZChSZWFkaW5nLkRhdGEkSVEuQyksDQogICAgICAgICBtZWFuKFJlYWRpbmcuRGF0YSRJUS5DKSwNCiAgICAgICAgIG1lYW4oUmVhZGluZy5EYXRhJElRLkMpK3NkKFJlYWRpbmcuRGF0YSRJUS5DKSkNCklRLlNEPC1yb3VuZChJUS5TRCwyKQ0KDQpJbnRlci4xYzwtZWZmZWN0KGMoIkFnZS5DKklRLkMiKSwgQ2VudGVyZWQuUmVhZC4yLA0KICAgICAgICAgICAgICAgICB4bGV2ZWxzPWxpc3QoQWdlLkM9c2VxKC0zLDMsIDEpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIElRLkM9SVEuU0QpKQ0KcGxvdChJbnRlci4xYywgbXVsdGlsaW5lID0gVFJVRSkNCmBgYA0KDQojIyBXaHkgY2VudGVyIHlvdXIgSVZzPw0KLSBUaGUgY2VudGVyIG9mIGVhY2ggSVYgcmVwcmVzZW50cyB0aGUgbWVhbiBvZiB0aGF0IElWDQotIFRodXMgd2hlbiB5b3UgaW50ZXJhY3QgdGhlbSAkWCpaJCwgdGhhdCBtZWFucyAkMCowID0gMCQNCi0gQWxzbywgdGhpcyBjYW4gcmVkdWNlIG11bHRpY29sbGluZWFyaXR5IGlzc3Vlcw0KLSBUaGlzIGlzIGJlY2F1c2UgaWYgJFgqWiQgY3JlYXRlcyBhIGxpbmUsIGl0IG1lYW5zIHlvdSBoYXZlIGFkZGVkIGEgbmV3IHByZWRpY3RvciAoWFopIHRoYXQgc3Ryb25nbHkgY29ycmVsYXRlcyB3aXRoIFggYW5kIFoNCg0KYGBge3J9DQpYPC1jKDAsMiw0LDYsOCwxMCkNClo8LWMoMCwyLDQsNiw4LDEwKQ0KWFo8LVgqWg0KcGxvdChYWikNCmBgYA0KDQotIENvcnJlbGF0aW9uczogJHJfe3gsen0kID0gYHIgcm91bmQoY29yKFgsWiksMilgLCAkcl97eCx4en0kID0gYHIgcm91bmQoY29yKFgsWFopLDIpYCwgJHJfe3oseHp9JCA9IGByIHJvdW5kKGNvcihaLFhaKSwyKWANCi1CdXQgaWYgeW91IGNlbnRlciB0aGVtLCBub3cgeW91IHdpbGwgbWFrZSBhIFUtc2hhcGVkIGludGVyYWN0aW9uIHdoaWNoIHdpbGwgYmUgb3J0aG9nb25hbCB0byBYIGFuZCBaIQ0KDQpgYGB7ciwgZWNobz1UUlVFLCB3YXJuaW5nPUZBTFNFfQ0KWC5DPC1zY2FsZShYLCBjZW50ZXIgPSBUUlVFLCBzY2FsZSA9IEZBTFNFKVssXQ0KWi5DPC1zY2FsZShaLCBjZW50ZXIgPSBUUlVFLCBzY2FsZSA9IEZBTFNFKVssXQ0KWFouQzwtWC5DKlouQw0KcGxvdChYWi5DKQ0KYGBgDQoNCi0gQ29ycmVsYXRpb25zOiAkcl97eF9jLHpfY30kID0gYHIgcm91bmQoY29yKFguQyxaLkMpLDIpYCwgJHJfe3hfYyx4el9jfSQgPSBgciByb3VuZChjb3IoWC5DLFhaLkMpLDIpYCwgJHJfe3pfYyx4el9jfSQgPSBgciByb3VuZChjb3IoWi5DLFhaLkMpLDIpYA0KDQotIExldCdzIGFwcGx5IHRoaXMgdG8gb3VyIGNsYXNzIGV4YW1wbGUNCi0gU2VlIGJlbG93IHdoZXJlIEkgbWFudWFsbHkgbXVsdGlwbHkgdGhlIHZhbHVlcyBhbmQgeW91IGNhbiBzZWUgYSB2ZXJ5IHN0cm9uZyBwb3NpdGl2ZSBzbG9wZQ0KLSBMZWZ0ID0gUmF3IFNjb3JlLCBSaWdodCBwbG90ID0gQ2VudGVyZWQgU2NvcmUNCg0KYGBge3IsIGVjaG89RkFMU0UsIGZpZy53aWR0aD0zLjI1LCBmaWcuaGVpZ2h0PTMuMjUsZmlnLnNob3c9J2hvbGQnLGZpZy5hbGlnbj0nY2VudGVyJ30NCmxpYnJhcnkoY2FyKQ0KUmVhZGluZy5EYXRhJEFnZS5YLklRPC1SZWFkaW5nLkRhdGEkQWdlKlJlYWRpbmcuRGF0YSRJUQ0KUmVhZGluZy5EYXRhJEFnZS5YLklRLkM8LVJlYWRpbmcuRGF0YSRBZ2UuQypSZWFkaW5nLkRhdGEkSVEuQw0Kc2NhdHRlcnBsb3QoUmVhZGluZ1NwZWVkfkFnZS5YLklRLCBkYXRhPSBSZWFkaW5nLkRhdGEsIHJlZy5saW5lPUZBTFNFLCBzbW9vdGhlcj1sb2Vzc0xpbmUpDQpzY2F0dGVycGxvdChSZWFkaW5nU3BlZWR+QWdlLlguSVEuQywgZGF0YT0gUmVhZGluZy5EYXRhLCByZWcubGluZT1GQUxTRSwgc21vb3RoZXI9bG9lc3NMaW5lKQ0KYGBgDQoNCiMjIyBMZXQncyBydW4gYW4gdW5jZW50ZXJlZCByZWdyZXNzaW9uDQotIGFzIHlvdSBjYW4gc2VlIHRoZSB0ZXJtcyBoYXZlIGNoYW5nZWQgZnJvbSBjZW50ZXJlZCBtb2RlbHMNCg0KYGBge3IsIGVjaG89VFJVRX0NClVuY2VudGVyZWQuUmVhZC4xPC1sbShSZWFkaW5nU3BlZWR+SVErQWdlLFJlYWRpbmcuRGF0YSkNClVuY2VudGVyZWQuUmVhZC4yPC1sbShSZWFkaW5nU3BlZWR+SVEqQWdlLFJlYWRpbmcuRGF0YSkNCmBgYA0KDQpgYGB7ciwgZWNobz1GQUxTRSwgcmVzdWx0cz0nYXNpcyd9DQpzdGFyZ2F6ZXIoVW5jZW50ZXJlZC5SZWFkLjEsVW5jZW50ZXJlZC5SZWFkLjIsdHlwZT0iaHRtbCIsDQogICAgICAgICAgY29sdW1uLmxhYmVscyA9IGMoIk1haW4gRWZmZWN0cyIsICJJbnRlcmFjdGlvbiIpLA0KICAgICAgICAgIGludGVyY2VwdC5ib3R0b20gPSBGQUxTRSwgc2luZ2xlLnJvdz1UUlVFLCANCiAgICAgICAgICBub3Rlcy5hcHBlbmQgPSBGQUxTRSwgaGVhZGVyPUZBTFNFKQ0KYGBgDQoNCiMjIyMgTXVsdGljb2xsaW5lYXJpdHkgb2YgdGhlIEludGVyYWN0aW9uDQotIE11bHRpY29sbGluZWFyaXR5IG9mIHRoZSB1bmNlbnRlcmVkIG1vZGVsDQoNCmBgYHtyLCBlY2hvPVRSVUUsIHdhcm5pbmc9RkFMU0V9DQp2aWYoVW5jZW50ZXJlZC5SZWFkLjIpDQpgYGANCg0KLSBXZSBsb3N0IG91ciBtYWluIGVmZmVjdCBvZiAqKkFnZSoqIGFzIHRoZSB2YXJpYW5jZXMgZ290IGFsbCBpbmZsYXRlZA0KLSBXZSBkaWQgbm90IGhhdmUgdGhpcyBwcm9ibGVtIGluIHRoZSBjZW50ZXJlZCBtb2RlbA0KDQpgYGB7ciwgZWNobz1UUlVFLCB3YXJuaW5nPUZBTFNFfQ0KdmlmKENlbnRlcmVkLlJlYWQuMikNCmBgYA0KDQotIE5vdGU6IEl0cyBPSyB0byBwbG90IHRoZSB1bmNlbnRlcmVkIHZlcnNpb24sIGJ1dCBydW4gdGhlIGFuYWx5c2lzIG9uIHRoZSBjZW50ZXJlZCBkYXRhDQoNCiMgVGVzdGluZyBTaW1wbGUgU2xvcGVzIA0KLSBUaGUgZ29hbCBoZXJlIGlzIHRvIGZpZ3VyZSBvdXQgd2hlbiB0aGUgc2xvcGUgYXQgYSBnaXZlbiBsZXZlbCBvZiBhbm90aGVyIHZhcmlhYmxlIGlzIGRpZmZlcmVudCBmcm9tIHplcm8NCi0gV2UgY2hvcCB1cCB0aGUgaW50ZXJhY3Rpb24gYXQgc3BlY2lmaWMgcGxhY2VzIGFzIHdlIGRpZCB3aXRoIHRoZSBpbnRlcmFjdGlvbnMgcGxvdHMgKC0xIFNELCBNLCArMSBTRCkgb24gdGhlICptb2RlcmF0aW5nKiB2YXJpYWJsZSAoYSB0aGlyZCB2YXJpYWJsZSB0aGF0IGFmZmVjdHMgdGhlIHN0cmVuZ3RoIG9mIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBhIGRlcGVuZGVudCBhbmQgaW5kZXBlbmRlbnQgdmFyaWFibGUpIA0KLSBOZXh0LCB3ZSB0ZXN0IHRoZSBzbG9wZXMgb24gdGhlICpwcmVkaWN0b3IqIHZhcmlhYmxlIChJViBvZiBtYWluIGludGVyZXN0KQ0KLSBFeGFtcGxlOiBQZXJmb3JtYW5jZSBvbiBhIHRhc2ssIHByZWRpY3RlZCBieSBMZXZlbCBvZiB0cmFpbmluZywgbW9kZXJhdGVkIGJ5IGhvdyBoYXJkIHRoZSBjaGFsbGVuZ2UgaXMNCg0KIyMgRXhhbXBsZSBvZiBJbnRlcmFjdGlvbg0KLSBEVjogUGVyZm9ybWFuY2UsIElWczogVHJhaW5pbmcgKFgpICsgQ2hhbGxlbmdlIChaKQ0KLSBTaW11bGF0aW9uOiAkWSA9IDIuMlggKyAyLjQ2WiArIC43NVhaICsxNiArXGVwc2lsb24kDQogICAgLSBTZXQgVHJhaW5pbmcgdG8gYmUgdW5pZm9ybSBkaXN0cmlidXRpb24gYmV0d2VlbiAtMTAgdG8gMTAgDQogICAgLSBTZXQgQ2hhbGxlbmdlIHRvIGJlIG5vcm1hbCwgJE0kPTAgYW5kICRTJD0xNQ0KICAgIC0gU2V0ICRcZXBzaWxvbiQgPSA1MCAobm9ybWFsIGRpc3RyaWJ1dGlvbiBvZiBub2lzZSkNCiAgICAtIE5vdGU6IEZvciBvdXIgcmVncmVzc2lvbiBzaW11bGF0aW9uIHdlIHdpbGwgc2V0IG1lYW5zIHRvIGFib3V0IHplcm8gKHNvIGFyZSBub3QgZm9yY2VkIHRvIGNlbnRlciB0aGVtKQ0KICAgIA0KYGBge3J9DQpzZXQuc2VlZCg0MikNCiMgMjUwIHBlb3BsZQ0KbiA8LSAyNTANCiNUcmFpbmluZyAobG93IHRvIGhpZ2gpDQpYIDwtIHJ1bmlmKG4sIC0xMCwgMTApDQojIG5vcm1hbCBkaXN0cmlidXRpb24gb2YgQ2hhbGxlbmdlIERpZmZpY3VsdHkNClogPC0gcm5vcm0obiwgMCwgMTUpDQojIE91ciBlcXVhdGlvbiB0byAgY3JlYXRlIFkNClkgPC0gMi4yKlggKyAyLjQ2KlogKyAuNzUqWCpaICsgMTYgKyBybm9ybShuLCBzZD01MCkNCiNCdWlsdCBvdXIgZGF0YSBmcmFtZQ0KU2tpbGwuRGF0YTwtZGF0YS5mcmFtZShUcmFpbmluZz1YLENoYWxsZW5nZT1aLFBlcmZvcm1hbmNlPVkpDQojcnVuIG91ciByZWdyZXNzaW9uDQpTa2lsbC5Nb2RlbC4xPC1sbShQZXJmb3JtYW5jZX5UcmFpbmluZytDaGFsbGVuZ2UsU2tpbGwuRGF0YSkNClNraWxsLk1vZGVsLjI8LWxtKFBlcmZvcm1hbmNlflRyYWluaW5nKkNoYWxsZW5nZSxTa2lsbC5EYXRhKQ0KYGBgDQoNCmBgYHtyLGVjaG89RkFMU0UsZmlnLndpZHRoPTQuNSxmaWcuaGVpZ2h0PTQuNX0NCkRpYWdQbG90MiA8LSBnZ3BhaXJzKFNraWxsLkRhdGEsICANCiAgICAgICAgICAgICAgbG93ZXIgPSBsaXN0KGNvbnRpbnVvdXMgPSAic21vb3RoIikpDQpEaWFnUGxvdDINCmBgYA0KDQpgYGB7cixlY2hvPUZBTFNFLCByZXN1bHRzPSdhc2lzJ30NCnN0YXJnYXplcihTa2lsbC5Nb2RlbC4xLFNraWxsLk1vZGVsLjIsdHlwZT0iaHRtbCIsDQogICAgICAgICAgY29sdW1uLmxhYmVscyA9IGMoIk1haW4gRWZmZWN0cyIsICJJbnRlcmFjdGlvbiIpLA0KICAgICAgICAgIGludGVyY2VwdC5ib3R0b20gPSBGQUxTRSwgc2luZ2xlLnJvdz1UUlVFLCANCiAgICAgICAgICBub3Rlcy5hcHBlbmQgPSBGQUxTRSwgaGVhZGVyPUZBTFNFKQ0KYGBgDQoNCg0KIyMgUGxvdHRpbmcgDQotIFdlIHdpbGwgdXNlIHRoZSBgcm9ja2NoYWxrYCBsaWJyYXJ5IHRvIHZpc3VhbGl6ZSBvdXIgaW50ZXJhY3Rpb24gYW5kIHRlc3Qgb3VyIHNpbXBsZSBzbG9wZXMNCg0KYGBge3J9DQpsaWJyYXJ5KHJvY2tjaGFsaykNCm0xcHMgPC0gcGxvdFNsb3BlcyhTa2lsbC5Nb2RlbC4yLCBtb2R4ID0gIkNoYWxsZW5nZSIsIHBsb3R4ID0gIlRyYWluaW5nIiwgbj0zLCBtb2R4VmFscz0ic3RkLmRldiIpDQptMXBzdHMgPC0gdGVzdFNsb3BlcyhtMXBzKQ0Kcm91bmQobTFwc3RzJGh5cG90ZXN0cyw0KQ0KYGBgDQoNCi0gV2Ugc2VlIHRoZSBzbG9wZSBhdCB0aGUgbWVhbiBpcyBub3Qgc2lnbmlmaWNhbnQsIA0KLSBUaGUgKzFTRCBhbmQgLTFTRCBhcmUgc2lnbmlmaWNhbnQsIHRoaXMgaXMgd2hhdCBpcyBkcml2aW5nIHRoZSBpbnRlcmFjdGlvbg0KLSBXZWxsIHRyYWluZWQgcGVvcGxlIGF0IGxvdyBsZXZlbHMgb2YgY2hhbGxlbmdlIGdldCB3b3JzZSB3aXRoIG1vcmUgdHJhaW5pbmcsIHdoaWxlIGhpZ2ggbGV2ZWxzIG9mIGNoYWxsZW5nZSB3aXRoIG1vcmUgdHJhaW5pbmcgZ2V0IGJldHRlcg0KLSBUaGUgYm9udXMgdXNpbmcgcm9ja2NoYWxrIGlzIHRoYXQgeW91IGNhbiBjaGFuZ2UgdGhlIG51bWJlciBvZiBsaW5lcyAoY2hhbmdlICRuPTMkKSB5b3Ugd2FudCB0byBzZWUgb3IgeW91IGNhbiB0ZXN0IHF1YW50aWxlcyBhcyB3ZWxsIChjaGFuZ2UgbW9keFZhbHM9InF1YW50aWxlIikNCg0KYGBge3J9DQptMXBRIDwtIHBsb3RTbG9wZXMoU2tpbGwuTW9kZWwuMiwgbW9keCA9ICJDaGFsbGVuZ2UiLCBwbG90eCA9ICJUcmFpbmluZyIsIG49NSwgbW9keFZhbHM9InF1YW50aWxlIikNCm0xcFF0cyA8LSB0ZXN0U2xvcGVzKG0xcFEpDQpyb3VuZChtMXBRdHMkaHlwb3Rlc3RzLDQpDQpgYGANCg0KIyMjIE5vdGVzDQotIFlvdSBvZnRlbiBkb24ndCBuZWVkIHRvIHJ1biB0aGUgKnQqLXRlc3RzIG9uIHRoZSBzaW1wbGUgc2xvcGVzLCBidXQgdGhleSBjYW4gdXNlZnVsIHRvIHRlc3QgdmVyeSBzcGVjaWZpYyBoeXBvdGhlc2VzDQotIFlvdSBjYW4gcnVuIHNpbXBsZSBzbG9wZXMgYW5hbHlzaXMgb24gdGhyZWUtd2F5IGludGVyYWN0aW9ucywgYnV0IGxldCdzIGxlYXZlIHRoYXQgYXNpZGUgZm9yIG5vdyBhcyB5b3Ugd291bGQgaGF2ZSB0byB1c2UgYSBkaWZmZXJlbnQgUi1wYWNrYWdlDQoNCiMgTm9uLUxpbmVhciBpbnRlcmFjdGlvbnMNCi0gWW91IGNhbiBoYXZlIG5vbi1saW5lYXIgdGVybXMgaW50ZXJhY3Rpbmcgd2l0aCBvdGhlciBsaW5lYXIgYW5kIG5vbi1saW5lYXIgdGVybXMNCi0gRXhhbXBsZTogUXVpdCBzbW9raW5nLCBYID0gRmVhciBvZiB5b3VyIGhlYWx0aCwgWiA9IG1vZGVyYXRlZCBieSBTZWxmLUVmZmljYWN5IGZvciBxdWl0dGluZw0KDQojIyBFeGFtcGxlIG9mIFBvbHlub21pYWwgSW50ZXJhY3Rpb24NCi0gRFY6IFF1aXQgc21va2luZywgSVZzOiBGZWFyIChYKSArIFNlbGYtRWZmaWNhY3kgKFopDQotIFNpbXVsYXRpb246ICRZID0gLS4xOFggLSAuMTVYXjIgKyBaICsgLjE2WFogKyAuMDdYXjJaICArMjAgK1xlcHNpbG9uJA0KICAgIC0gU2V0IEZlYXIgb2YgeW91ciBoZWFsdGggdG8gYmUgdW5pZm9ybSBkaXN0cmlidXRpb24gYmV0d2VlbiAxIHRvIDkgKGNlbnRlcmVkKSANCiAgICAtIFNldCBTZWxmLUVmZmljYWN5IHRvIGJlIG5vcm1hbCwgJE0kPTAgYW5kICRTJD0xNQ0KICAgIC0gU2V0ICRcZXBzaWxvbiQgPSAxMCAobm9ybWFsIGRpc3RyaWJ1dGlvbiBvZiBub2lzZSkNCiAgICANCmBgYHtyfQ0Kc2V0LnNlZWQoNDIpDQpuIDwtIDI1MA0KI0ZlYXIgb2YgSGVhbHRoDQpYIDwtIHNjYWxlKHJ1bmlmKG4sIDEsIDkpLCBzY2FsZT1GKQ0KI0NlbnRlcmVkIFNlbGYtRWZmaWNhY3kNClogPC0gc2NhbGUocnVuaWYobiwgMCwgMTUpLCBzY2FsZT1GKQ0KIyBPdXIgZXF1YXRpb24gdG8gIGNyZWF0ZSBZDQpZIDwtIC0uMDUqWCAtIC4yMCpYXjIgKyAuMTUqWCpaICsgLjIyKihYXjIpKlorIDM1ICsgcm5vcm0obiwgc2Q9MTApDQojQnVpbHQgb3VyIGRhdGEgZnJhbWUNClNtb2tlLkRhdGE8LWRhdGEuZnJhbWUoU21va2luZz1ZLEhlYWx0aD1YLFNlbGZFZmZpY2FjeT1aKQ0KI3J1biBvdXIgcmVncmVzc2lvbg0KU21va2UuTW9kZWwuMTwtbG0oU21va2luZ35wb2x5KEhlYWx0aCwyKStTZWxmRWZmaWNhY3ksU21va2UuRGF0YSkNClNtb2tlLk1vZGVsLjI8LWxtKFNtb2tpbmd+cG9seShIZWFsdGgsMikqU2VsZkVmZmljYWN5LFNtb2tlLkRhdGEpDQpTbW9rZS5Nb2RlbC4xLlI8LWxtKFNtb2tpbmd+cG9seShIZWFsdGgsMiwgcmF3PVQpK1NlbGZFZmZpY2FjeSxTbW9rZS5EYXRhKQ0KU21va2UuTW9kZWwuMi5SPC1sbShTbW9raW5nfnBvbHkoSGVhbHRoLDIsIHJhdz1UKSpTZWxmRWZmaWNhY3ksU21va2UuRGF0YSkNCmBgYA0KDQotIE9ydGhvZ29uYWwgUG9seW5vbWlhbHMNCmBgYHtyLCBlY2hvPUZBTFNFLCByZXN1bHRzPSdhc2lzJ30NCnN0YXJnYXplcihTbW9rZS5Nb2RlbC4xLFNtb2tlLk1vZGVsLjIsdHlwZT0iaHRtbCIsDQogICAgICAgICAgY29sdW1uLmxhYmVscyA9IGMoIk1haW4gRWZmZWN0cyIsICJJbnRlcmFjdGlvbiIpLA0KICAgICAgICAgIGludGVyY2VwdC5ib3R0b20gPSBGQUxTRSwgc2luZ2xlLnJvdz1UUlVFLCANCiAgICAgICAgICBub3Rlcy5hcHBlbmQgPSBGQUxTRSwgaGVhZGVyPUZBTFNFKQ0KYGBgDQoNCi0gUG93ZXIgUG9seW5vbWlhbHMNCg0KYGBge3IsIGVjaG89RkFMU0UsIHJlc3VsdHM9J2FzaXMnfQ0Kc3RhcmdhemVyKFNtb2tlLk1vZGVsLjEuUixTbW9rZS5Nb2RlbC4yLlIsdHlwZT0iaHRtbCIsDQogICAgICAgICAgY29sdW1uLmxhYmVscyA9IGMoIk1haW4gRWZmZWN0cyBOb24tT3J0aG8iLCAiSW50ZXJhY3Rpb24gTm9uLU9ydGhvIiksDQogICAgICAgICAgaW50ZXJjZXB0LmJvdHRvbSA9IEZBTFNFLCBzaW5nbGUucm93PVRSVUUsIA0KICAgICAgICAgIG5vdGVzLmFwcGVuZCA9IEZBTFNFLCBoZWFkZXI9RkFMU0UpDQpgYGANCg0KLSBOb3RlIGhvdyBkaWZmZXJlbnQgdGhlIHJlc3VsdHMgbWlnaHQgbG9vayB3aGVuIHlvdSBleGFtaW5lIHRoYXQgYXMgcG93ZXIgcG9seW5vbWlhbHMNCg0KDQojIyBQbG90dGluZyB0aGUgU2ltcGxlIFNsb3BlcyB3aGVuIHRoZXJlIGFyZSBDdXJ2ZXMNCi0gVGhlc2UgY2FuIGJlIGRvbmUgd2l0aCB0aGUgYGVmZmVjdHNgIHBhY2thZ2UgYXMgSSBzaG93ZWQgeW91IGFib3ZlIGFuZCBsYXN0IHdlZWsNCi0gV2Ugd2lsbCB3b3JrIHdpdGggdGhlIG9ydGhvZ29uYWwgcG9seW5vbWlhbCBtb2RlbHMNCiAgICAtIG9yIHdlIGNhbiBzaW1wbHkgdXNlIHRoZSBwbG90Q3VydmVzIGZ1bmN0aW9uIGZyb20gdGhlICdyb2NrY2hhbGsnIHBhY2thZ2UNCg0KYGBge3J9DQpTbW9rZUludGVyUGxvdCA8LSBwbG90Q3VydmVzKFNtb2tlLk1vZGVsLjIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2R4ID0gIlNlbGZFZmZpY2FjeSIsIHBsb3R4ID0gIkhlYWx0aCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIG49Myxtb2R4VmFscz0ic3RkLmRldiIpDQpgYGANCg0KLSBMZXRzIHBsb3QganVzdCB0aGUgbWFpbiBlZmZlY3QgKGFuZCB0aGluayBhYm91dCB3aGF0IGl0IG1lYW5zIHJlbGF0aXZlIHRoZSBwb3dlcikNCg0KYGBge3IsIGVjaG89VFJVRSwgd2FybmluZz1GQUxTRX0NCnBsb3RDdXJ2ZXMoU21va2UuTW9kZWwuMSwgcGxvdHggPSAiSGVhbHRoIikNCmBgYA0KDQotIERvZXMgbm90IGxvb2sgdmVyeSBxdWFkcmF0aWMsIGRvZXMgaXQ/IEluIG90aGVyIHdvcmRzLCB5b3UgY2Fubm90IHNlZSB0aGUgaGlnaGVyIG9yZGVyIGVmZmVjdHMgYXMgdGhleSBjYW4gYmUgaGlkZGVuIGJ5IHRoZSBtb2RlcmF0aW5nIHZhcmlhYmxlDQotIEhvdyB0byBmaW5kIHRoZXNlIGhpZGRlbiB0aGluZ3M/IA0KLSBZb3UgaGF2ZSB0byB0ZXN0IGZvciBpbnRlcmFjdGlvbnMgYW5kIGNoYW5nZXMgaW4gJFJeMiQNCi0gWW91IGhhdmUgdG8gdHJ5IHRvIGFkZCBoaWdoZXIgb3JkZXIgdGVybXMsIGJ1dCB0aGV5IHNob3VsZCBiZSBtb3RpdmF0ZWQgYnkgc29tZSB0aGVvcnkNCi0gV2hhdCBpZiB5b3UgZGlkIG5vdCBrbm93IHRoZSBzZWNvbmQgb3JkZXIgdGVybSB3YXMgaW4gdGhlIG1vZGVsIGFib3ZlLiANCg0KYGBge3IsIGVjaG89VFJVRSwgd2FybmluZz1GQUxTRX0NClNtb2tlLk1vZGVsLjEuTDwtbG0oU21va2luZ35IZWFsdGgrU2VsZkVmZmljYWN5LFNtb2tlLkRhdGEpDQpTbW9rZS5Nb2RlbC4yLkw8LWxtKFNtb2tpbmd+SGVhbHRoKlNlbGZFZmZpY2FjeSxTbW9rZS5EYXRhKQ0KYGBgDQoNCmBgYHtyLCBlY2hvPUZBTFNFLCByZXN1bHRzPSdhc2lzJ30NCnN0YXJnYXplcihTbW9rZS5Nb2RlbC4xLkwsU21va2UuTW9kZWwuMi5MLHR5cGU9Imh0bWwiLA0KICAgICAgICAgIGNvbHVtbi5sYWJlbHMgPSBjKCJNYWluIEVmZmVjdHMiLCAiSW50ZXJhY3Rpb24iKSwNCiAgICAgICAgICBpbnRlcmNlcHQuYm90dG9tID0gRkFMU0UsDQogICAgICAgICAgc2luZ2xlLnJvdz1UUlVFLCANCiAgICAgICAgICBub3Rlcy5hcHBlbmQgPSBGQUxTRSwNCiAgICAgICAgICBoZWFkZXI9RkFMU0UpDQoNCmBgYA0KDQpgYGB7cn0NCkNoYW5nZUluUi5TbW9rZTwtYW5vdmEoU21va2UuTW9kZWwuMS5MLFNtb2tlLk1vZGVsLjIuTCkNCmtuaXRyOjprYWJsZShDaGFuZ2VJblIuU21va2UsIGRpZ2l0cz00KQ0KYGBgDQoNCi0gVGhlcmUgaXMgbm8gc2lnbmlmaWNhbnQgaW50ZXJhY3Rpb24sIGJ1dCBsZXQncyBwbG90IGl0IGFueXdheS4NCi0gUmVwbG90dGluZyBhcyBsaW5lYXIgaW50ZXJhY3Rpb24NCg0KYGBge3J9DQpTbW9rZUludGVyUGxvdC5MaW5lYXIgPC0gcGxvdFNsb3BlcyhTbW9rZS5Nb2RlbC4yLkwsIG1vZHggPSAiU2VsZkVmZmljYWN5IiwgcGxvdHggPSAiSGVhbHRoIiwgbj0zLCBtb2R4VmFscz0ic3RkLmRldiIpDQpgYGANCg0KDQotIExldCdzIGNoZWNrIHRoZSBjaGFuZ2UgaW4gJFJeMiQgZnJvbSBMaW5lYXIgaW50ZXJhY3Rpb24gbW9kZWwgdG8gcG9seSBpbnRlcmFjdGlvbiBtb2RlbCBub3cNCg0KYGBge3IsIGVjaG89VFJVRSwgcmVzdWx0cz0nYXNpcyd9DQpzdGFyZ2F6ZXIoU21va2UuTW9kZWwuMi5MLFNtb2tlLk1vZGVsLjIsdHlwZT0iaHRtbCIsDQogICAgICAgICAgY29sdW1uLmxhYmVscyA9IGMoIkxpbmVhciIsICJQb2x5IiksDQogICAgICAgICAgaW50ZXJjZXB0LmJvdHRvbSA9IEZBTFNFLA0KICAgICAgICAgIHNpbmdsZS5yb3c9VFJVRSwgDQogICAgICAgICAgbm90ZXMuYXBwZW5kID0gRkFMU0UsDQogICAgICAgICAgaGVhZGVyPUZBTFNFKQ0KYGBgDQoNCmBgYHtyfQ0KQ2hhbmdlSW5SLlNtb2tlLjI8LWFub3ZhKFNtb2tlLk1vZGVsLjIsU21va2UuTW9kZWwuMi5MKQ0Ka25pdHI6OmthYmxlKENoYW5nZUluUi5TbW9rZS4yLCBkaWdpdHM9NCkNCmBgYA0KDQojIyBOb3Rlcw0KLSBTbywgbW9kZWwgd2l0aCBwb2x5IGlzIGEgc2lnbmlmaWNhbnRseSBiZXR0ZXIgZml0DQotIFdvdWxkIGl0IGNoYW5nZSB0aGUgc3RvcnkgYnkgbXVjaD8gSW4gdGhpcyBjYXNlIFlFUywgYnV0IG5vdCBhbHdheXMhIA0KICAgIC0gU29tZXRpbWVzIHRoZSBpbXByb3ZlbWVudCBpbiBmaXQgaXMgbWlub3IgYW5kIGRvZXMgbm90IGNoYW5nZSB0aGUgc3RvcnkNCiAgICAgICAgLSBPZnRlbiBpZ25vcmluZyB0aGUgaGlnaGVyIG9yZGVyIHRlcm0gY2FuIG1ha2UgaXQgZWFzaWVyIHRvIHRlc3Qgc2ltcGxlIHNsb3BlcyBhbmQgdGVsbCBhIHN0b3J5DQogICAgLSBIb3dldmVyLCBpZ25vcmluZyB0aGUgaGlnaGVyIG9yZGVyIHRlcm1zIGNhbiB2aW9sYXRlIHlvdXIgYXNzdW1wdGlvbnMgd2hlbiB0aGUgcmVzdWx0cywgbGV0J3MgY29tcGFyZSBvdXIgbGluZWFyIHZzIHBvbHkgbW9kZWxzIHJlc2lkdWFscw0KDQotIExpbmVhciBNb2RlbA0KYGBge3IsIGZpZy53aWR0aD02fQ0KYXV0b3Bsb3QoU21va2UuTW9kZWwuMiwgd2hpY2ggPSAxOjIsIGxhYmVsLnNpemUgPSAxKSArIHRoZW1lX2J3KCkNCmBgYA0KDQotIFF1YWR0cmFkaWMgTW9kZWwNCmBgYHtyLCBmaWcud2lkdGg9Nn0NCmF1dG9wbG90KFNtb2tlLk1vZGVsLjIuTCwgd2hpY2ggPSAxOjIsIGxhYmVsLnNpemUgPSAxKSArIHRoZW1lX2J3KCkNCmBgYA0KDQo8c2NyaXB0Pg0KICAoZnVuY3Rpb24oaSxzLG8sZyxyLGEsbSl7aVsnR29vZ2xlQW5hbHl0aWNzT2JqZWN0J109cjtpW3JdPWlbcl18fGZ1bmN0aW9uKCl7DQogIChpW3JdLnE9aVtyXS5xfHxbXSkucHVzaChhcmd1bWVudHMpfSxpW3JdLmw9MSpuZXcgRGF0ZSgpO2E9cy5jcmVhdGVFbGVtZW50KG8pLA0KICBtPXMuZ2V0RWxlbWVudHNCeVRhZ05hbWUobylbMF07YS5hc3luYz0xO2Euc3JjPWc7bS5wYXJlbnROb2RlLmluc2VydEJlZm9yZShhLG0pDQogIH0pKHdpbmRvdyxkb2N1bWVudCwnc2NyaXB0JywnaHR0cHM6Ly93d3cuZ29vZ2xlLWFuYWx5dGljcy5jb20vYW5hbHl0aWNzLmpzJywnZ2EnKTsNCg0KICBnYSgnY3JlYXRlJywgJ1VBLTkwNDE1MTYwLTEnLCAnYXV0bycpOw0KICBnYSgnc2VuZCcsICdwYWdldmlldycpOw0KDQo8L3NjcmlwdD4NCg==
Source: http://alexanderdemos.org/Class6.html
0 Response to "Simple Slopes With One Categorical and One Continuous Variable"
Post a Comment