Nominal Variables
- Things like gender or color (what we would have as factors in ANOVA)
- We will assume (for now) that a subject can be a member of only
one level of a factor a variable (i.e., you can blue or red, but
not both)
- Decisions have to made on how to treat these variables in a
regression
- There are three basic methods we will cover and how to interpret
their effects and interactions
- Key to remember you are basically doing to t-tests, so you are
always just comparing two things, but what those two things are will
change as you change your coding (think the concept of contrasts in
ANOVA from last semester)
Models with no Interactions (1 Nominal variable)
Dummy Coding
- The most common and basic type used (default in R if it senses a
categorical variable)
- For each variable, you must assign a reference group (a baseline)
for each variable
- Each group is compared to the reference group
- We ask the question, how much does each group deviate from the
reference
- Here are two levels of one factor
- Here are Three levels, but now you have to make 2 new variables
- Happy is the reference group
Happy |
0 |
0 |
Sad |
0 |
1 |
Mad |
1 |
0 |
- Sad is the reference group
Happy |
0 |
1 |
Sad |
0 |
0 |
Mad |
1 |
0 |
- Here are Four levels, but now you have to make 3 new variables
- Happy is the reference group
Happy |
0 |
0 |
0 |
Sad |
0 |
0 |
1 |
Mad |
0 |
1 |
0 |
Grumpy |
1 |
0 |
0 |
Regression equation
- Two Levels: \(Y = B_1C1 +
B_0\)
- Three Levels: \(Y = B_1C1 +B_2C2+
B_0\)
- Four Levels: \(Y = B_1C1 + B_2C2 + B_2C3 +
B_0\)
Creating Dummy Variables
- In SPSS you would have to create dummy variables using Recode, but
it R its a little easier
- In R, we have to convert our variable into a factor
- R will default to alphabetical order
- Sometimes easier to convert all your words into numbers (start with
0)
- Next, convert your variable into a factor (as.factor)
- Note: R calls dummy coding as contr.treatment
- First, let’s simulate a simple factor to work with
- Emotion rating ~ Expressive intentions of the actor (0 = Flat, 1 =
Normal, 2 = Exaggerated )
- Three Levels: \(Emotion Rating = 0*Flat +
5*Normal +10*Exaggerated + 50 + \epsilon\)
Flat |
0 |
0 |
Normal |
1 |
0 |
Exaggerated |
0 |
1 |
library(ggplot2)
#Set up simulation
set.seed(42)
N <- 200
X<- sample(rep(c(0,1,2),N),N,replace = FALSE)
Y <- 5*X + 50 + rnorm(N, sd=10)
Emotion.Data<-data.frame(Emotion=Y,Style=X)
qplot(Style,Emotion, data = Emotion.Data, colour = I("red"))+theme_bw()+geom_smooth(method='lm')
- If the data is already coded as 0, 1, 2 all we have to do is:
Emotion.Data$StyleF <- factor(Emotion.Data$Style,
level=c(0,1,2),
labels=c("Flat", "Normal", "Exaggerated"))
- We can re-plot it as violin/box plot to see our distributions (its a
double-sided density plot [smoothed histogram])
ggplot(data = Emotion.Data,aes(StyleF,Emotion))+
xlab("")+
geom_violin(aes(fill=StyleF), trim = FALSE,adjust=1.5)+
geom_boxplot(width=.1)+
theme_bw()+
theme(legend.position = "none")
Interpret Regression
- Order of the factors matters
- Remember you are making each level of the variable a term in the
equation as you have made a new variable for each level (except
baseline)
- R make these dummy coded automatically so its easy to forget
this
- for 3 levels we will have 3 terms: intercept and StyleFNormal and
StyleFExaggerated.
Model.1<-lm(Emotion ~ StyleF, data = Emotion.Data)
|
|
Dependent variable:
|
|
|
|
Emotion
|
|
Constant
|
50.798*** (1.273)
|
StyleFNormal
|
2.182 (1.828)
|
StyleFExaggerated
|
7.961*** (1.780)
|
|
Observations
|
200
|
R2
|
0.098
|
Adjusted R2
|
0.089
|
F Statistic
|
10.705*** (df = 2; 197)
|
|
Note:
|
p<0.05; p<0.01;
p<0.001
|
Coefficients
- Intercept = Intercept of the equation (Which is the mean of
Flat)
- StyleFNormal = coefficient (slope of Normal) from baseline
(Flat)
- StyleFExaggerated = coefficient (slope of Exaggerated) from baseline
(Flat)
Means per Condition
- Flat = Intercept
- Normal = Intercept + StyleFNormal
- Exaggerated = Intercept + StyleFExaggerated
Pvalues
- The pvalue on the intercept asks if the baseline (Flat)
condition different from zero
- The pvalue on the slopes asks if each of the other levels is
different from baseline (Flat)
Rotate the matrix
- What if we want to know if Normal is different from
Exaggerated?
- We need to relevel (aka change what is zero)
Flat |
1 |
0 |
Normal |
0 |
0 |
Exaggerated |
0 |
1 |
- We can fix that manually change what the baseline line level is with
the
relevel
command in car
package
Emotion.Data$StyleN<- relevel(Emotion.Data$StyleF, ref = "Normal")
Model.1.N<-lm(Emotion ~ StyleN, data = Emotion.Data)
- Notice in the table the labels and values have changed
|
|
Dependent variable:
|
|
|
|
Emotion
|
|
Constant
|
52.979*** (1.312)
|
StyleNFlat
|
-2.182 (1.828)
|
StyleNExaggerated
|
5.779** (1.809)
|
|
Observations
|
200
|
R2
|
0.098
|
Adjusted R2
|
0.089
|
F Statistic
|
10.705*** (df = 2; 197)
|
|
Note:
|
p<0.05; p<0.01;
p<0.001
|
Contrast Coding
- Same contrasts as in our ANOVAs but there are two versions
(unweighted and weighted) and both need to sum to zero
- We ask now a different question: How much does each group
deviate from the mean of all groups
- I will review only the most common see for the others:
- I will not show you the weighted version as not often used
Deviation Coding
- Note: R calls them Contrast Sums
- Let’s make the Flat the reference again
Normal |
1 |
0 |
Exaggerated |
0 |
1 |
Flat |
-1 |
-1 |
- For deviatation code, R will use the LAST variable
as references so we need to recode it by hand to be first as to match
the order we want in the above table
Emotion.Data$Style.C.S <- factor(Emotion.Data$Style,
level=c(1,2,0),
labels=c("Normal", "Exaggerated", "Flat"))
- Then we will create our new contrast
contr.sum
with
three levels (3)
contr.sum(3)
## [,1] [,2]
## 1 1 0
## 2 0 1
## 3 -1 -1
- We will add that code to our
lm
function, by adding the
parameters list(Style.C.S=contr.sum(3))
Model.1.CS<-lm(Emotion ~ Style.C.S, data = Emotion.Data,
contrasts=list(Style.C.S=contr.sum(3)))
- Let’s look at how things differ from the mean of all conditions
(grand mean)
|
|
Dependent variable:
|
|
|
|
Emotion
|
|
Constant
|
54.178*** (0.737)
|
Style.C.S1
|
-1.199 (1.057)
|
Style.C.S2
|
4.580*** (1.030)
|
|
Observations
|
200
|
R2
|
0.098
|
Adjusted R2
|
0.089
|
F Statistic
|
10.705*** (df = 2; 197)
|
|
Note:
|
p<0.05; p<0.01;
p<0.001
|
- Intercept = Mean of means (grand mean)
- Mean of each condition calculated below
Mean.Interaction<-aggregate(Emotion~StyleF,data = Emotion.Data, FUN=mean)
Flat |
50.79758 |
Normal |
52.97930 |
Exaggerated |
58.75829 |
- Grand mean calculated below
sum(aggregate(Emotion~StyleF,data = Emotion.Data, FUN=mean)[2])/3
## [1] 54.17839
Coefficients
- Style.C.S1 = coefficient on Normal as it differs from grand
mean
- Style.C.S2 = coefficient on Exaggerated as it differs from grand
mean
- To get the means for each condition:
Means per Condition
- Flat = Cannot get from this model
- Normal = Intercept + Style.C.S1
- Exaggerated = Intercept + Style.C.S2
Pvalues
- The pvalue on the intercept asks if the grand mean
different from zero
- The pvalue on the slopes asks if each of the other levels is
different from grand mean
- Note: We have lost the ability to ask about Flat condition,
to get it back we would have to rotate the baseline and do it again
Simple Coding
- They must sum to zero, and the abs(values) must sum to 1
- Like in ANOVA you can design these to ask specific questions by
merging conditions (or not)
- We will use the contr.treatment treatment (which R is using to
automatically convert your categorical variables already)
- Just like dummy coding but we change the meaning of the
intercept
- The reference level is First again
Flat |
-1/3 |
-1/3 |
Normal |
2/3 |
-1/3 |
Exaggerated |
-1/3 |
2/3 |
Emotion.Data$Style.Simple <- factor(Emotion.Data$Style,
level=c(0,1,2),
labels=c("Flat", "Normal", "Exaggerated"))
Levels<-3
Simple.1<-contr.treatment(Levels) # Dummy code
#Make your codes
my.coding<-matrix(rep(1/Levels, Levels*(Levels-1)), ncol=Levels-1)
my.simple<-Simple.1-my.coding
my.simple
## 2 3
## 1 -0.3333333 -0.3333333
## 2 0.6666667 -0.3333333
## 3 -0.3333333 0.6666667
- We will add that code to our
lm
function, by adding the
parameters list(Style.Simple=my.simple)
Model.1.Simple<-lm(Emotion ~ Style.Simple, data = Emotion.Data,
contrasts=list(Style.Simple=my.simple))
|
|
Dependent variable:
|
|
|
|
Emotion
|
|
Constant
|
54.178*** (0.737)
|
Style.Simple2
|
2.182 (1.828)
|
Style.Simple3
|
7.961*** (1.780)
|
|
Observations
|
200
|
R2
|
0.098
|
Adjusted R2
|
0.089
|
F Statistic
|
10.705*** (df = 2; 197)
|
|
Note:
|
p<0.05; p<0.01;
p<0.001
|
Coefficients
- This merges the dummy and deviance codings thus:
- Intercept = Mean of means (grand mean)
- StyleFNormal = slope of Normal from baseline (Flat)
- StyleFExaggerated = slope of Exaggerated from baseline (Flat)
Means per Condition
- You cannot get means of each condition from this model
Pvalues
- The pvalue on the intercept asks if the grand mean
different from zero
- The pvalue on the slopes asks if each of the other levels is
different from baseline (Flat)
Other types of contrast coding
- Helmert: compares each level to the mean of the subsequent levels
[can be reversed]
- Forward Difference coding: one level is compared to the next
(adjacent) level. (level 1 vs. 2. level 2 vs. 3) [can be reversed]
- Custom: Merge and compare levels at will
Center variables and test slopes
- There is no reason why you cannot treat the variables as continuous
is they are ordinal
- just center them and treat like a continuous variable
Models with Interactions (2 Nominal variables)
- Interactions can be tricky as the interpretation depends on how you
code IVs
- First, let’s try some categorical vs. categorical interactions
- We will add a variable to our experiment from above; we will add the
location where the actors work (Movie vs. Theatre)
- Emotion rating ~ Expressive intentions*location of the actor
\(Emotion = -3*Flat + 0*Normal +3*Exag
+0*Movie - 1.5*Theatre - 0*Flat*Movie + 0*Normal*Movie +0*Exag*Movie -
10*Flat*Theatre +0*Normal*Theatre +10*Exag*Theatre + 50 +
\epsilon\)
set.seed(42)
N <- 200
X <- sample(rep(c(-1,0,1),N),N,replace = FALSE)
Z <- sample(rep(c(0,1),N*3/2),N,replace = FALSE)
# Our equation to create Y
Y <- 3*X -1.5*Z+10*X*Z+ 50 + rnorm(N, sd=10)
#Built our data frame
Emotion.Data.2<-data.frame(Emotion=Y,Style=X,Location=Z)
Emotion.Data.2$Style<-Emotion.Data.2$Style+1
Dummy coding
- Lets dummy code all of them: convert them to a label in the other we
want
# Convert all our factors
Emotion.Data.2$StyleF <- factor(Emotion.Data.2$Style,
level=c(0,1,2),
labels=c("Flat", "Normal", "Exaggerated"))
Emotion.Data.2$LocationF <- factor(Emotion.Data.2$Location,
level=c(0,1),
labels=c("Movie Set", "Theatre"))
-Let’s look at the collapsed means and the means per cell
Mean.Style<-aggregate(Emotion~StyleF,data = Emotion.Data.2, FUN=mean)
kable(Mean.Style)
Flat |
43.13791 |
Normal |
47.56490 |
Exaggerated |
58.39412 |
Mean.Location<-aggregate(Emotion~LocationF,data = Emotion.Data.2, FUN=mean)
kable(Mean.Location)
Movie Set |
49.75709 |
Theatre |
49.99666 |
Mean.Interaction<-aggregate(Emotion~StyleF*LocationF,data = Emotion.Data.2, FUN=mean)
kable(Mean.Interaction)
Flat |
Movie Set |
49.69693 |
Normal |
Movie Set |
45.80954 |
Exaggerated |
Movie Set |
53.42534 |
Flat |
Theatre |
34.00214 |
Normal |
Theatre |
49.26539 |
Exaggerated |
Theatre |
63.08686 |
- Let examine our regression, but we need to examine a main effects
and interaction model
Model.I1.Dummy<-lm(Emotion ~ StyleF+LocationF, data = Emotion.Data.2)
Model.I2.Dummy<-lm(Emotion ~ StyleF*LocationF, data = Emotion.Data.2)
|
|
Dependent variable:
|
|
|
|
Emotion
|
|
Main Effects
|
Interaction
|
|
(1)
|
(2)
|
|
Constant
|
43.412*** (1.534)
|
49.697*** (1.592)
|
StyleFNormal
|
4.486* (1.987)
|
-3.887 (2.392)
|
StyleFExaggerated
|
15.319*** (1.936)
|
3.728 (2.333)
|
LocationFTheatre
|
-0.655 (1.604)
|
-15.695*** (2.462)
|
StyleFNormal:LocationFTheatre
|
|
19.151*** (3.513)
|
StyleFExaggerated:LocationFTheatre
|
|
25.356*** (3.423)
|
|
Observations
|
200
|
200
|
R2
|
0.253
|
0.427
|
Adjusted R2
|
0.242
|
0.412
|
F Statistic
|
22.170*** (df = 3; 196)
|
28.924*** (df = 5; 194)
|
|
Note:
|
p<0.05; p<0.01;
p<0.001
|
- You will notice a large difference between the main effects and
interaction model
- This is because the meaning coefficients in the interaction differ
from the main effects model
- The main effects were explained above, but they change meaning a
little because there is second variable
Main Effects
Coefficients
These do not connect back to the individual cells as you are
assuming the two factors have independent effects
- Thus these are hypothetical values (not connected to the individual
cells)
Intercept = Estimate of the mean, assuming the two factors have
independent effects at their 0 points [baseline]
StyleFNormal = Normal - Flat (assuming the two factors are
independent)
StyleFExaggerated = Exaggerated - Flat (assuming the two factors
are independent)
LocationFTheatre = Theatre - Movie(assuming the two factors are
independent)
We can see the main effect models results
library(effects)
allEffects(Model.I1.Dummy)
## model: Emotion ~ StyleF + LocationF
##
## StyleF effect
## StyleF
## Flat Normal Exaggerated
## 43.09724 47.58320 58.41658
##
## LocationF effect
## LocationF
## Movie Set Theatre
## 50.18653 49.53144
Pvalues
- The pvalue on the intercept asks if the baseline is different from
zero
- The pvalue on the differences asks if they are from different from
baseline
Interactions
Coefficients
- These cells connect back to experimental cells
- Intercept = Location(0) @ Style(0) aka Movie @ Flat [real
value]
- StyleFNormal = Differnce of [Location(0) @ Style(1)] - [Location(0)
@ Style(0)]
- StyleFExaggerated = Differnce of [Location(0) @ Style(2)] -
[Location(0) @ Style(0)]
- LocationFTheatre = Differnce of [Location(1) @ Style(0)] -
[Location(0) @ Style(0)]
- StyleFNormal:LocationFTheatre = Differnce of [Location(1) @
Style(1)] - [Location(0) @ Style(1) - Location(0) @ Style(0) +
[Location(1) @ Style(0)] - [Location(0) @ Style(0)]
- StyleFExaggerated:LocationFTheatre = Differnce of [Location(1) @
Style(2)] - [Location(0) @ Style(2) - Location(0) @ Style(0) +
[Location(2) @ Style(0)] - [Location(0) @ Style(0)]
Means per Condition
- You can find all means for all cells!
- Flat @ Movie = Intercept
- Normal @ Movie = Intercept + StyleFNormal
- Exaggerated @ Movie = Intercept + StyleFExaggerated
- Flat @ Theatre = Intercept + LocationFTheatre
- Normal @ Theatre = Intercept +
LocationFTheatre+StyleFNormal+StyleFNormal:LocationFTheatre
- Exaggerated @ Theatre = Intercept + LocationFTheatre +
StyleFExaggerated + StyleFExaggerated:LocationFTheatre
Pvalues
- The pvalue on the intercept asks if the baseline is different from
zero
- The pvalue on the differences asks if they are from different from
baseline
- But these are now are now simple effects
Main effect model vs. Interaction model
- Since the results are not additive, the main effect model is useful
only in which to understand how the terms have changed
- Gives some insight into the interaction
Graph Model
Inter.1<-effect("StyleF*LocationF", Model.I2.Dummy)
plot(Inter.1, multiline = TRUE)
Connection to between-subject ANOVA
- Regression with only categorical variables can be converted into an
ANOVA very easily
- Thus it can be treated just like ANOVA
- but the regression makes the ANOVA process moot as you can now the
regression can be coded in such a way that you can test follow up tests
in a way you want to test them all
library(car)
Anova(Model.I2.Dummy, type="III")
## Anova Table (Type III tests)
##
## Response: Emotion
## Sum Sq Df F value Pr(>F)
## (Intercept) 96322 1 974.6213 < 2.2e-16 ***
## StyleF 941 2 4.7593 0.009598 **
## LocationF 4015 1 40.6229 1.316e-09 ***
## StyleF:LocationF 5814 2 29.4130 6.967e-12 ***
## Residuals 19173 194
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
- Note, we have to call for a Type III sum of squares to match SPSS
output as R would default to Type I
Contrast Coding
Deviation Coding
- Lets code each variable as we did above
Emotion.Data.2$Style.C.S <- factor(Emotion.Data.2$Style,
level=c(1,2,0),
labels=c("Normal", "Exaggerated", "Flat"))
Emotion.Data.2$Location.C.S <- factor(Emotion.Data.2$Location,
level=c(1,0),
labels=c("Theatre", "Movie Set"))
Model.I1.C.S<-lm(Emotion ~ Style.C.S+Location.C.S, data = Emotion.Data.2,
contrasts=list(Style.C.S=contr.sum(3),Location.C.S=contr.sum(2)))
Model.I2.C.S<-lm(Emotion ~ Style.C.S*Location.C.S, data = Emotion.Data.2,
contrasts=list(Style.C.S=contr.sum(3),Location.C.S=contr.sum(2)))
- Let’s look at how things differ from the mean of all conditions
(grand mean)
|
|
Dependent variable:
|
|
|
|
Emotion
|
|
Main Effects
|
Interaction
|
|
(1)
|
(2)
|
|
Constant
|
49.686*** (0.800)
|
49.214*** (0.707)
|
Style.C.S1
|
-2.116 (1.147)
|
-1.677 (1.011)
|
Style.C.S2
|
8.718*** (1.117)
|
9.042*** (0.985)
|
Location.C.S1
|
-0.328 (0.802)
|
-0.430 (0.707)
|
Style.C.S1:Location.C.S1
|
|
2.157* (1.011)
|
Style.C.S2:Location.C.S1
|
|
5.260*** (0.985)
|
|
Observations
|
200
|
200
|
R2
|
0.253
|
0.427
|
Adjusted R2
|
0.242
|
0.412
|
F Statistic
|
22.170*** (df = 3; 196)
|
28.924*** (df = 5; 194)
|
|
Note:
|
p<0.05; p<0.01;
p<0.001
|
- Again we are testing between the grand mean and the individual
terms
Main Effects
Coefficients
- These do not connect back to the individual cells as you are
assuming the two factors have independent effects
- Thus these are hypothetical Grand mean values
- Intercept = Grand Mean, but assuming the two factors have
independent effects
- Style.C.S1 = Normal (averaged over location) - Grand Mean
(assuming the two factors are independent)
- Style.C.S2 = Exaggerated (averaged over location) - Grand
Mean (assuming the two factors are independent)
- Location.C.S1 = Theatre (averaged over Style) - Grand Mean
(assuming the two factors are independent)
Means per Condition
- Cannot get from this model
Pvalues
- The pvalue on the intercept asks if the baseline (Grand
Mean) is different from zero
- The pvalue on the slopes asks if each of the other levels is
different from the baseline (Grand Mean)
- Note we are missing tests on Flat and Movie cell, we would need to
rotate the matrix and run again
Interactions
Coefficients
- Intercept = Grand Mean (all 6 cells mean averaged)
- Style.C.S1 = Normal (averaged over location) from Grand
Mean
- Style.C.S2 = Exaggerated (averaged over location) from Grand
Mean
- Location.C.S1 = Theatre (averaged over Style) from Grand
Mean
- Style.C.S1:Location.C.S1 = difference of Normal @ Theatre from
Grand Mean
- Style.C.S2:Location.C.S1 = difference of Exaggerated @ Theatre from
Grand Mean
Means per Condition
- Cannot get from this model
Pvalues
- The pvalue on the intercept asks if the baseline (Grand
Mean) is different from zero
- The pvalue on the differences asks if each of the other levels is
from the (Grand Mean)
- Note we are missing tests on Flat and movie cell, we would need to
rotate the matrix and run again
Models with Interactions (1 Nominal and 1 Continuous Variable)
- We will change our experiment from above, we will add a likert scale
which the actor rates how “good” they think the performance was [-3
terrible to 3 excellent]
- Emotion rating ~ Quality Rating X location of the actor (i.e.,
Movie Set, Theatre)
#Set up simulation
set.seed(42)
N <- 200
X <- runif(N,-3,3)
Z <- sample(rep(c(0,1),N/2),N,replace = FALSE)
# Our equation to create Y
Y <- 4*X +2*Z+8*X*Z+ 50 + rnorm(N, sd=10)
#Built our data frame
Emotion.Data.3<-data.frame(Emotion=Y,Quality=X,Location=Z)
Center the continuous variable
- Best to center as its will help us interpret
# Convert all our factors
Emotion.Data.3$Quality.C <- scale(Emotion.Data.3$Quality, scale = FALSE)[,]
Dummy coding of our nominal variable
- Make Location into a factor
# Convert all our factors
Emotion.Data.3$LocationF <- factor(Emotion.Data.3$Location,
level=c(0,1),
labels=c("Movie Set","Theatre"))
- First to understand what the interaction will yield lets us run two
regressions where we seperate our factor to see what the slopes would be
just for actors at Movie Set vs at the Theatre
Movie Set ONLY vs Theatre Only
- We will subset the data and test for the Quality slopes
Model.Movie<-lm(Emotion ~ Quality.C,
data = subset(Emotion.Data.3,LocationF=="Movie Set"))
Model.Theatre<-lm(Emotion ~ Quality.C,
data = subset(Emotion.Data.3,LocationF=="Theatre"))
|
|
Dependent variable:
|
|
|
|
Emotion
|
|
Movie Set ONLY
|
Theatre Only
|
|
(1)
|
(2)
|
|
Constant
|
50.468*** (0.976)
|
52.426*** (1.051)
|
Quality.C
|
4.551*** (0.593)
|
12.083*** (0.569)
|
|
Observations
|
100
|
100
|
R2
|
0.375
|
0.821
|
Adjusted R2
|
0.369
|
0.819
|
F Statistic (df = 1; 98)
|
58.842***
|
450.430***
|
|
Note:
|
p<0.05; p<0.01;
p<0.001
|
- Ignore the intercepts and pay attention to the slopes:
- Quality @ the Movie Set ONLY is \(b\)= 4.551
- The pvalues tells you if the slope of quality is differnet from a
slope of 0
- Quality @ the Theatre Only ONLY is \(b\)= 12.083
- The pvalues tells you if the slope of quality is differnet from a
slope of 0
- What we really want to test is if there is a difference in slopes
between quality at Movies sets VS Theatre
Testing the Interaction
- We will test a main effects model,
Quality+Location
and
compare it to an interaction model Quality*Location
Model.E3.1<-lm(Emotion ~ Quality.C+LocationF, data = Emotion.Data.3)
Model.E3.2<-lm(Emotion ~ Quality.C*LocationF, data = Emotion.Data.3)
- Does model interaction improve the model fit? (Just like we did with
hierarchical testing)
Model.Fit.E3<-anova(Model.E3.1,Model.E3.2)
library(knitr)
kable(Model.Fit.E3)
197 |
28691.61 |
NA |
NA |
NA |
NA |
196 |
20141.73 |
1 |
8549.886 |
83.19931 |
0 |
- Yes! The interaction is significant improvement
- Let’s go examine the individual regression paramaters:
Interpret Regression
|
|
Dependent variable:
|
|
|
|
Emotion
|
|
Main Effects
|
Interaction
|
|
(1)
|
(2)
|
|
Constant
|
50.513*** (1.207)
|
50.468*** (1.014)
|
Quality.C
|
8.749*** (0.488)
|
4.551*** (0.616)
|
LocationFTheatre
|
1.948 (1.707)
|
1.958 (1.434)
|
Quality.C:LocationFTheatre
|
|
7.532*** (0.826)
|
|
Observations
|
200
|
200
|
R2
|
0.621
|
0.734
|
Adjusted R2
|
0.617
|
0.730
|
F Statistic
|
161.308*** (df = 2; 197)
|
180.143*** (df = 3; 196)
|
|
Note:
|
p<0.05; p<0.01;
p<0.001
|
Main Effects Model
- Intercept = Mean of Quality @ Movies [p = Is the intercept
different from 0]
- Quality.C = Quality.C slope averaged across Movies & *
Threatre*
- This is a Main Effect [p = Is slope
different from 0 slope]
- This would almost be like averaging the slopes from our Movie
Set ONLY and Theatre Only Models
- \(b\) = (4.551 + 12.083)/2 =
8.317
- LocationFTheatre = Threatre difference from intercept [p = Is mean
of Theatre different from Movies @ mean of quality]
Interaction Model
- Intercept = Mean of Quality @ Movies [p = Is the intercept
different from 0]
- Quality.C = Quality.C slope @ Movies
- This is a Simple Slope [p = Is slope
different from 0 slope]
- To prove it we can see it matches the slopes from our Movie Set
ONLY Model, \(b\)= 4.551
- LocationFTheatre = Threatre difference from intercept [p =
Is mean of Theatre different from movies @ mean of quality]
- Quality.C:LocationFTheatre= slope difference between Movie
and Theatre [p = Is the slope of quality @ Theatre different
from slope at ]
- This is an Interaction
- To prove it we can see it matches the slopes of Theatre
Only - Movie Set ONLY Model
- \(b\)= (12.083 - 4.551) =
7.532
- If you wanted to know the simple slope of Theatre Only you
would have to relevel Location and make Theatre = 0 (i.e., the
reference)
Emotion.Data.3$LocationT<- relevel(Emotion.Data.3$LocationF, ref = "Theatre")
Model.E3.2.ReLevel<-lm(Emotion ~ Quality.C*LocationT, data = Emotion.Data.3)
|
|
Dependent variable:
|
|
|
|
Emotion
|
|
Theatre is Ref
|
|
Constant
|
52.426*** (1.014)
|
Quality.C
|
12.083*** (0.549)
|
LocationTMovie Set
|
-1.958 (1.434)
|
Quality.C:LocationTMovie Set
|
-7.532*** (0.826)
|
|
Observations
|
200
|
R2
|
0.734
|
Adjusted R2
|
0.730
|
F Statistic
|
180.143*** (df = 3; 196)
|
|
Note:
|
p<0.05; p<0.01;
p<0.001
|
- You will notice the interaction flipped direction and now the
Quality.C coefficient \(b\) = 12.083 =
the Theatre Only model \(b\) =
12.083
Plotting Interaction
- Often times you will need to use the effects package and plot by
hand
- The rockchalk package will work for simple models like this one
library(rockchalk)
plotSlopes(Model.E3.2, plotx = "Quality.C", modx = "LocationF")
Deviation coding of our nominal variable
- We will still center quality
- This creates a more ANOVA like interpretation of the
interaction
Emotion.Data.3$LocationD <- factor(Emotion.Data.3$Location,
level=c(1,0),
labels=c("Theatre","Movie Set"))
Model.E3.D1<-lm(Emotion ~ Quality.C+LocationD, data = Emotion.Data.3,
contrasts=list(LocationD=contr.sum(2)))
Model.E3.D2<-lm(Emotion ~ Quality.C*LocationD, data = Emotion.Data.3,
contrasts=list(LocationD=contr.sum(2)))
Interpret Regression
|
|
Dependent variable:
|
|
|
|
Emotion
|
|
Main Effects
|
Interaction
|
|
(1)
|
(2)
|
|
Constant
|
51.487*** (0.853)
|
51.447*** (0.717)
|
Quality.C
|
8.749*** (0.488)
|
8.317*** (0.413)
|
LocationD1
|
0.974 (0.853)
|
0.979 (0.717)
|
Quality.C:LocationD1
|
|
3.766*** (0.413)
|
|
Observations
|
200
|
200
|
R2
|
0.621
|
0.734
|
Adjusted R2
|
0.617
|
0.730
|
F Statistic
|
161.308*** (df = 2; 197)
|
180.143*** (df = 3; 196)
|
|
Note:
|
p<0.05; p<0.01;
p<0.001
|
Main Effects
Coefficients & Pvalues
- Intercept = Mean of Quality @ mean of Movie & Theatre
(imaginary) [p = Is the intercept different from 0]
- Quality.C = Quality.C slope [p = Is slope different from 0]
- LocationFTheatre = Threatre difference from 0 (not - 1) thus is 1/2
the slope of the dummy code [p = Is mean of Theatre different from
movies @ mean of quality]
Interactions
Coefficients & Pvalues
- Intercept = Mean of Quality @ mean of Movie & Theatre
(imaginary) [p = Is the intercept different from 0]
- Quality.C = Quality.C slope @ mean of Movie & Theatre
(imaginary) [p = Is the Main effect of quality @ mean of Movie &
Theatre]
- LocationFTheatre = Threatre difference from intercept [p =
Is the Main effect of Location @ mean of quality]
- Quality.C:LocationFTheatre= Quality.C slope difference between Movie
and theatre [p = Is the interaction]
- Note all coefficients are 1/2 of the size they should be!
Simple coding of our nominal variable
- We will still center quality
- This creates a more ANOVA-like interpretation of the interaction,
- Most importantly it does not screw up our coefficients as they match
the dummy code values (which make the most sense)
- This time I will hand code it into a factor (easy with only 2
levels)
Emotion.Data.3$LocationS<-as.numeric(Emotion.Data.3$Location)-.5
Model.E3.S1<-lm(Emotion ~ Quality.C+LocationS, data = Emotion.Data.3)
Model.E3.S2<-lm(Emotion ~ Quality.C*LocationS, data = Emotion.Data.3)
Interpret Regression
|
|
Dependent variable:
|
|
|
|
Emotion
|
|
Main Effects
|
Interaction
|
|
(1)
|
(2)
|
|
Constant
|
51.487*** (0.853)
|
51.447*** (0.717)
|
Quality.C
|
8.749*** (0.488)
|
8.317*** (0.413)
|
LocationS
|
1.948 (1.707)
|
1.958 (1.434)
|
Quality.C:LocationS
|
|
7.532*** (0.826)
|
|
Observations
|
200
|
200
|
R2
|
0.621
|
0.734
|
Adjusted R2
|
0.617
|
0.730
|
F Statistic
|
161.308*** (df = 2; 197)
|
180.143*** (df = 3; 196)
|
|
Note:
|
p<0.05; p<0.01;
p<0.001
|
Main Effects
Coefficients & Pvalues
- Intercept = Mean of Quality @ mean of Movie & Theatre (imaginary
thing) [p = Is the intercept different from 0]
- Quality.C = Quality.C slope [p = Is slope different from 0]
- LocationFTheatre = Threatre difference from 0 [p = Is mean of
Theatre different from movies @ mean of quality]
Interactions
Coefficients & Pvalues
- Intercept = Mean of Quality @ mean of Movie & Theatre (imaginary
thing) [p = Is the intercept different from 0]
- Quality.C = Quality.C slope @ mean of Movie & Theatre (imaginary
thing) [p = Is the Main effect of quality @ mean of Movie &
Theatre]
- LocationS = Threatre difference from intercept [p = Is the Main
effect of Location @ mean of quality]
- Quality.C:LocationS= Quality.C slope difference between Movie and
theatre [p = Is their an interaction]
- Note all coefficients are their proper size now (to match true
differences)
- Best option is often dummy or simple, deviation here is weird
LS0tDQp0aXRsZTogJ0NhdGVnb3JpY2FsIFZhcmlhYmxlcycNCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDoNCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMNCiAgICBmb250c2l6ZTogOHB0DQogICAgaGlnaGxpZ2h0OiB0ZXh0bWF0ZQ0KICAgIG51bWJlcl9zZWN0aW9uczogbm8NCiAgICB0aGVtZTogZmxhdGx5DQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZmxvYXQ6DQogICAgICBjb2xsYXBzZWQ6IG5vDQotLS0NCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoY2FjaGU9VFJVRSkNCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkNCmtuaXRyOjpvcHRzX2NodW5rJHNldChtZXNzYWdlID0gRkFMU0UpDQprbml0cjo6b3B0c19jaHVuayRzZXQod2FybmluZyA9ICBGQUxTRSkNCmtuaXRyOjpvcHRzX2NodW5rJHNldChmaWcud2lkdGg9NC4yNSkNCmtuaXRyOjpvcHRzX2NodW5rJHNldChmaWcuaGVpZ2h0PTQuMCkNCmtuaXRyOjpvcHRzX2NodW5rJHNldChmaWcuYWxpZ249J2NlbnRlcicpIA0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KHJlc3VsdHM9J2hvbGQnKSANCmBgYA0KDQoNCiMgTm9taW5hbCBWYXJpYWJsZXMgDQotIFRoaW5ncyBsaWtlIGdlbmRlciBvciBjb2xvciAod2hhdCB3ZSB3b3VsZCBoYXZlIGFzIGZhY3RvcnMgaW4gQU5PVkEpDQogICAgLSBXZSB3aWxsIGFzc3VtZSAoZm9yIG5vdykgdGhhdCBhIHN1YmplY3QgY2FuIGJlIGEgbWVtYmVyIG9mICpvbmx5IG9uZSogbGV2ZWwgb2YgYSBmYWN0b3IgYSB2YXJpYWJsZSAoaS5lLiwgeW91IGNhbiBibHVlIG9yIHJlZCwgYnV0IG5vdCBib3RoKQ0KLSBEZWNpc2lvbnMgaGF2ZSB0byBtYWRlIG9uIGhvdyB0byB0cmVhdCB0aGVzZSB2YXJpYWJsZXMgaW4gYSByZWdyZXNzaW9uDQotIFRoZXJlIGFyZSB0aHJlZSBiYXNpYyBtZXRob2RzIHdlIHdpbGwgY292ZXIgYW5kIGhvdyB0byBpbnRlcnByZXQgdGhlaXIgZWZmZWN0cyBhbmQgaW50ZXJhY3Rpb25zDQotIEtleSB0byByZW1lbWJlciB5b3UgYXJlIGJhc2ljYWxseSBkb2luZyB0byB0LXRlc3RzLCBzbyB5b3UgYXJlIGFsd2F5cyBqdXN0IGNvbXBhcmluZyB0d28gdGhpbmdzLCBidXQgd2hhdCB0aG9zZSB0d28gdGhpbmdzIGFyZSB3aWxsIGNoYW5nZSBhcyB5b3UgY2hhbmdlIHlvdXIgY29kaW5nICh0aGluayB0aGUgY29uY2VwdCBvZiBjb250cmFzdHMgaW4gQU5PVkEgZnJvbSBsYXN0IHNlbWVzdGVyKQ0KDQoNCiMgTW9kZWxzIHdpdGggbm8gSW50ZXJhY3Rpb25zICgxIE5vbWluYWwgdmFyaWFibGUpDQoNCiMjIER1bW15IENvZGluZw0KLSBUaGUgbW9zdCBjb21tb24gYW5kIGJhc2ljIHR5cGUgdXNlZCAoZGVmYXVsdCBpbiBSIGlmIGl0IHNlbnNlcyBhIGNhdGVnb3JpY2FsIHZhcmlhYmxlKQ0KLSBGb3IgZWFjaCB2YXJpYWJsZSwgeW91IG11c3QgYXNzaWduIGEgcmVmZXJlbmNlIGdyb3VwIChhIGJhc2VsaW5lKSBmb3IgZWFjaCB2YXJpYWJsZQ0KLSBFYWNoIGdyb3VwIGlzIGNvbXBhcmVkIHRvIHRoZSByZWZlcmVuY2UgZ3JvdXANCi0gV2UgYXNrIHRoZSBxdWVzdGlvbiwgKmhvdyBtdWNoIGRvZXMgZWFjaCBncm91cCBkZXZpYXRlIGZyb20gdGhlIHJlZmVyZW5jZSoNCi0gSGVyZSBhcmUgdHdvIGxldmVscyBvZiBvbmUgZmFjdG9yDQoNCg0KVmFyaWFibGUgfCBDMSANCi0tLS0tLS0tLXwgLS0tDQpIYXBweSAgICB8IDANClNhZCAgICAgIHwgMQ0KDQotIEhlcmUgYXJlIFRocmVlIGxldmVscywgYnV0IG5vdyB5b3UgaGF2ZSB0byBtYWtlIDIgbmV3IHZhcmlhYmxlcyANCi0gSGFwcHkgaXMgdGhlIHJlZmVyZW5jZSBncm91cA0KDQpWYXJpYWJsZXwgQzF8IEMyDQotLS0tLS0tLXwgLS18IC0tDQpIYXBweSAgIHwgMCB8IDANClNhZCAgICAgfCAwIHwgMQ0KTWFkICAgICB8IDEgfCAwDQoNCi0gU2FkIGlzIHRoZSByZWZlcmVuY2UgZ3JvdXANCg0KVmFyaWFibGV8IEMxfCBDMg0KLS0tLS0tLS18IC0tfCAtLQ0KSGFwcHkgICB8IDAgfCAxDQpTYWQgICAgIHwgMCB8IDANCk1hZCAgICAgfCAxIHwgMA0KDQotIEhlcmUgYXJlIEZvdXIgbGV2ZWxzLCBidXQgbm93IHlvdSBoYXZlIHRvIG1ha2UgMyBuZXcgdmFyaWFibGVzIA0KLSBIYXBweSBpcyB0aGUgcmVmZXJlbmNlIGdyb3VwDQoNClZhcmlhYmxlICAgICB8IEMxIHwgQzIgfCBDMw0KLS0tLS0tLS0tLS0tLXwgLS0gfCAtLSB8IC0tIA0KSGFwcHkgICAgICAgIHwgMCAgfCAwICB8IDANClNhZCAgICAgICAgICB8IDAgIHwgMCAgfCAxDQpNYWQgICAgICAgICAgfCAwICB8IDEgIHwgMA0KR3J1bXB5ICAgICAgIHwgMSAgfCAwICB8IDANCg0KDQojIyMgUmVncmVzc2lvbiBlcXVhdGlvbg0KLSBUd28gTGV2ZWxzOiAkWSA9IEJfMUMxICsgQl8wJA0KLSBUaHJlZSBMZXZlbHM6ICRZID0gQl8xQzEgK0JfMkMyKyBCXzAkDQotIEZvdXIgTGV2ZWxzOiAkWSA9IEJfMUMxICsgQl8yQzIgKyBCXzJDMyArIEJfMCQNCg0KIyMjIENyZWF0aW5nIER1bW15IFZhcmlhYmxlcw0KLSBJbiBTUFNTIHlvdSB3b3VsZCBoYXZlIHRvIGNyZWF0ZSBkdW1teSB2YXJpYWJsZXMgdXNpbmcgUmVjb2RlLCBidXQgaXQgUiBpdHMgYSBsaXR0bGUgZWFzaWVyDQotIEluIFIsIHdlIGhhdmUgdG8gY29udmVydCBvdXIgdmFyaWFibGUgaW50byBhIGZhY3Rvcg0KICAgIC0gUiB3aWxsIGRlZmF1bHQgdG8gYWxwaGFiZXRpY2FsIG9yZGVyDQogICAgICAgIC0gU29tZXRpbWVzIGVhc2llciB0byBjb252ZXJ0IGFsbCB5b3VyIHdvcmRzIGludG8gbnVtYmVycyAoc3RhcnQgd2l0aCAwKQ0KICAgIC0gTmV4dCwgY29udmVydCB5b3VyIHZhcmlhYmxlIGludG8gYSBmYWN0b3IgKGFzLmZhY3RvcikNCiAgICAgICAgLSBOb3RlOiBSIGNhbGxzIGR1bW15IGNvZGluZyBhcyBjb250ci50cmVhdG1lbnQNCi0gRmlyc3QsIGxldCdzIHNpbXVsYXRlIGEgc2ltcGxlIGZhY3RvciB0byB3b3JrIHdpdGgNCiAgICAtIEVtb3Rpb24gcmF0aW5nIH4gRXhwcmVzc2l2ZSBpbnRlbnRpb25zIG9mIHRoZSBhY3RvciAoMCA9IEZsYXQsIDEgPSBOb3JtYWwsIDIgPSBFeGFnZ2VyYXRlZCApDQogICAgLSBUaHJlZSBMZXZlbHM6ICRFbW90aW9uIFJhdGluZyA9IDAqRmxhdCArIDUqTm9ybWFsICsxMCpFeGFnZ2VyYXRlZCArIDUwICsgXGVwc2lsb24kDQoNCg0KVmFyaWFibGUgICAgfCBDMXwgQzINCi0tLS0tLS0tLS0tLXwgLS18IC0tLQ0KRmxhdCAgICAgICAgfCAwIHwgMA0KTm9ybWFsICAgICAgfCAxIHwgMA0KRXhhZ2dlcmF0ZWQgfCAwIHwgMQ0KDQoNCmBgYHtyfQ0KbGlicmFyeShnZ3Bsb3QyKQ0KI1NldCB1cCBzaW11bGF0aW9uDQpzZXQuc2VlZCg0MikNCk4gPC0gMjAwDQpYPC0gc2FtcGxlKHJlcChjKDAsMSwyKSxOKSxOLHJlcGxhY2UgPSBGQUxTRSkNClkgPC0gNSpYICsgNTAgKyBybm9ybShOLCBzZD0xMCkNCkVtb3Rpb24uRGF0YTwtZGF0YS5mcmFtZShFbW90aW9uPVksU3R5bGU9WCkNCnFwbG90KFN0eWxlLEVtb3Rpb24sIGRhdGEgPSBFbW90aW9uLkRhdGEsIGNvbG91ciA9IEkoInJlZCIpKSt0aGVtZV9idygpK2dlb21fc21vb3RoKG1ldGhvZD0nbG0nKQ0KYGBgDQoNCi0gSWYgdGhlIGRhdGEgaXMgYWxyZWFkeSBjb2RlZCBhcyAwLCAxLCAyIGFsbCB3ZSBoYXZlIHRvIGRvIGlzOiANCg0KYGBge3J9DQpFbW90aW9uLkRhdGEkU3R5bGVGIDwtIGZhY3RvcihFbW90aW9uLkRhdGEkU3R5bGUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbD1jKDAsMSwyKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscz1jKCJGbGF0IiwgIk5vcm1hbCIsICJFeGFnZ2VyYXRlZCIpKQ0KYGBgDQoNCi0gV2UgY2FuIHJlLXBsb3QgaXQgYXMgdmlvbGluL2JveCBwbG90IHRvIHNlZSBvdXIgZGlzdHJpYnV0aW9ucyAoaXRzIGEgZG91YmxlLXNpZGVkIGRlbnNpdHkgcGxvdCBbc21vb3RoZWQgaGlzdG9ncmFtXSkNCg0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IEVtb3Rpb24uRGF0YSxhZXMoU3R5bGVGLEVtb3Rpb24pKSsNCiAgeGxhYigiIikrDQogIGdlb21fdmlvbGluKGFlcyhmaWxsPVN0eWxlRiksIHRyaW0gPSBGQUxTRSxhZGp1c3Q9MS41KSsNCiAgZ2VvbV9ib3hwbG90KHdpZHRoPS4xKSsNCiAgdGhlbWVfYncoKSsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KYGBgDQoNCg0KIyMjIEludGVycHJldCBSZWdyZXNzaW9uDQotIE9yZGVyIG9mIHRoZSBmYWN0b3JzIG1hdHRlcnMNCi0gUmVtZW1iZXIgeW91IGFyZSBtYWtpbmcgZWFjaCBsZXZlbCBvZiB0aGUgdmFyaWFibGUgYSB0ZXJtIGluIHRoZSBlcXVhdGlvbiBhcyB5b3UgaGF2ZSBtYWRlIGEgbmV3IHZhcmlhYmxlIGZvciBlYWNoIGxldmVsIChleGNlcHQgYmFzZWxpbmUpDQotICpSIG1ha2UgdGhlc2UgZHVtbXkgY29kZWQgYXV0b21hdGljYWxseSBzbyBpdHMgZWFzeSB0byBmb3JnZXQgdGhpcyoNCiAgICAtIGZvciAzIGxldmVscyB3ZSB3aWxsIGhhdmUgMyB0ZXJtczogaW50ZXJjZXB0IGFuZCBTdHlsZUZOb3JtYWwgYW5kIFN0eWxlRkV4YWdnZXJhdGVkLg0KDQpgYGB7cn0NCk1vZGVsLjE8LWxtKEVtb3Rpb24gfiBTdHlsZUYsIGRhdGEgPSBFbW90aW9uLkRhdGEpDQpgYGANCg0KDQpgYGB7ciwgZWNobz1GQUxTRSxyZXN1bHRzPSdhc2lzJ30NCmxpYnJhcnkoc3RhcmdhemVyKQ0Kc3RhcmdhemVyKE1vZGVsLjEsdHlwZT0iaHRtbCIsDQogICAgICAgICAgaW50ZXJjZXB0LmJvdHRvbSA9IEZBTFNFLCAgc2luZ2xlLnJvdz1UUlVFLCBub3Rlcy5hcHBlbmQgPSBGQUxTRSwNCiAgICAgICAgICBvbWl0LnN0YXQ9Yygic2VyIiksIHN0YXIuY3V0b2ZmcyA9IGMoMC4wNSwgMC4wMSwgMC4wMDEpLA0KICAgICAgICAgIGhlYWRlcj1GQUxTRSkNCmBgYA0KDQojIyMjIENvZWZmaWNpZW50cw0KLSBJbnRlcmNlcHQgPSBJbnRlcmNlcHQgb2YgdGhlIGVxdWF0aW9uIChXaGljaCBpcyB0aGUgbWVhbiBvZiBGbGF0KQ0KLSBTdHlsZUZOb3JtYWwgPSBjb2VmZmljaWVudCAoc2xvcGUgb2YgTm9ybWFsKSBmcm9tIGJhc2VsaW5lIChGbGF0KQ0KLSBTdHlsZUZFeGFnZ2VyYXRlZCA9IGNvZWZmaWNpZW50IChzbG9wZSBvZiBFeGFnZ2VyYXRlZCkgZnJvbSBiYXNlbGluZSAoRmxhdCkNCg0KIyMjIyBNZWFucyBwZXIgQ29uZGl0aW9uDQoNCi0gKkZsYXQgPSBJbnRlcmNlcHQqDQotICpOb3JtYWwgPSBJbnRlcmNlcHQgKyBTdHlsZUZOb3JtYWwqDQotICpFeGFnZ2VyYXRlZCA9IEludGVyY2VwdCArIFN0eWxlRkV4YWdnZXJhdGVkKg0KDQojIyMjIFB2YWx1ZXMNCi0gVGhlIHB2YWx1ZSBvbiB0aGUgaW50ZXJjZXB0IGFza3MgaWYgdGhlIGJhc2VsaW5lICgqRmxhdCopIGNvbmRpdGlvbiBkaWZmZXJlbnQgZnJvbSB6ZXJvDQotIFRoZSBwdmFsdWUgb24gdGhlIHNsb3BlcyBhc2tzIGlmIGVhY2ggb2YgdGhlIG90aGVyIGxldmVscyBpcyBkaWZmZXJlbnQgZnJvbSBiYXNlbGluZSAoKkZsYXQqKQ0KDQoNCiMjIyBSb3RhdGUgdGhlIG1hdHJpeA0KLSBXaGF0IGlmIHdlIHdhbnQgdG8ga25vdyBpZiBOb3JtYWwgaXMgZGlmZmVyZW50IGZyb20gRXhhZ2dlcmF0ZWQ/DQotIFdlIG5lZWQgdG8gcmVsZXZlbCAoYWthIGNoYW5nZSB3aGF0IGlzICoqemVybyoqKQ0KDQpWYXJpYWJsZSAgICB8IEMxfCBDMg0KLS0tLS0tLS0tLS0tfCAtLXwgLS0tDQpGbGF0ICAgICAgICB8IDEgfCAwDQpOb3JtYWwgICAgICB8IDAgfCAwDQpFeGFnZ2VyYXRlZCB8IDAgfCAxDQoNCi0gV2UgY2FuIGZpeCB0aGF0IG1hbnVhbGx5IGNoYW5nZSB3aGF0IHRoZSBiYXNlbGluZSBsaW5lIGxldmVsIGlzIHdpdGggdGhlIGByZWxldmVsYCBjb21tYW5kIGluIGBjYXJgIHBhY2thZ2UNCg0KYGBge3J9DQpFbW90aW9uLkRhdGEkU3R5bGVOPC0gcmVsZXZlbChFbW90aW9uLkRhdGEkU3R5bGVGLCByZWYgPSAiTm9ybWFsIikNCk1vZGVsLjEuTjwtbG0oRW1vdGlvbiB+IFN0eWxlTiwgZGF0YSA9IEVtb3Rpb24uRGF0YSkNCmBgYA0KDQotIE5vdGljZSBpbiB0aGUgdGFibGUgdGhlIGxhYmVscyBhbmQgdmFsdWVzIGhhdmUgY2hhbmdlZA0KDQpgYGB7ciwgZWNobz1GQUxTRSwgcmVzdWx0cz0nYXNpcyd9DQpzdGFyZ2F6ZXIoTW9kZWwuMS5OLHR5cGU9Imh0bWwiLA0KICAgICAgICAgIGludGVyY2VwdC5ib3R0b20gPSBGQUxTRSxzaW5nbGUucm93PVRSVUUsIG5vdGVzLmFwcGVuZCA9IEZBTFNFLCANCiAgICAgICAgICBvbWl0LnN0YXQ9Yygic2VyIiksIHN0YXIuY3V0b2ZmcyA9IGMoMC4wNSwgMC4wMSwgMC4wMDEpLA0KICAgICAgICAgIGhlYWRlcj1GQUxTRSkNCmBgYA0KDQoNCiMjIENvbnRyYXN0IENvZGluZw0KLSBTYW1lIGNvbnRyYXN0cyBhcyBpbiBvdXIgQU5PVkFzIGJ1dCB0aGVyZSBhcmUgdHdvIHZlcnNpb25zICh1bndlaWdodGVkIGFuZCB3ZWlnaHRlZCkgYW5kIGJvdGggbmVlZCB0byBzdW0gdG8gemVybw0KLSBXZSBhc2sgbm93IGEgZGlmZmVyZW50IHF1ZXN0aW9uOiAqSG93IG11Y2ggZG9lcyBlYWNoIGdyb3VwIGRldmlhdGUgZnJvbSB0aGUgbWVhbiBvZiBhbGwgZ3JvdXBzKg0KLSBJIHdpbGwgcmV2aWV3IG9ubHkgdGhlIG1vc3QgY29tbW9uIHNlZSBmb3IgdGhlIG90aGVyczoNCiAgICAtIGh0dHA6Ly9zdGF0cy5pZHJlLnVjbGEuZWR1L3IvbGlicmFyeS9yLWxpYnJhcnktY29udHJhc3QtY29kaW5nLXN5c3RlbXMtZm9yLWNhdGVnb3JpY2FsLXZhcmlhYmxlcy8NCi0gSSB3aWxsIG5vdCBzaG93IHlvdSB0aGUgd2VpZ2h0ZWQgdmVyc2lvbiBhcyBub3Qgb2Z0ZW4gdXNlZA0KDQojIyMgRGV2aWF0aW9uIENvZGluZyANCi0gTm90ZTogUiBjYWxscyB0aGVtIENvbnRyYXN0IFN1bXMNCi0gTGV0J3MgbWFrZSB0aGUgRmxhdCB0aGUgcmVmZXJlbmNlIGFnYWluDQoNClZhcmlhYmxlICAgIHwgQzF8IEMyDQotLS0tLS0tLS0tLS18IC0tfCAtLS0NCk5vcm1hbCAgICAgIHwgMSB8IDANCkV4YWdnZXJhdGVkIHwgMCB8IDENCkZsYXQgICAgICAgIHwtMSB8IC0xDQoNCi0gRm9yIGRldmlhdGF0aW9uIGNvZGUsIFIgd2lsbCB1c2UgdGhlICoqTEFTVCoqIHZhcmlhYmxlIGFzIHJlZmVyZW5jZXMgc28gd2UgbmVlZCB0byByZWNvZGUgaXQgYnkgaGFuZCB0byBiZSBmaXJzdCBhcyB0byBtYXRjaCB0aGUgb3JkZXIgd2Ugd2FudCBpbiB0aGUgYWJvdmUgdGFibGUNCg0KYGBge3IsIGVjaG89VFJVRSwgd2FybmluZz1GQUxTRX0NCkVtb3Rpb24uRGF0YSRTdHlsZS5DLlMgPC0gZmFjdG9yKEVtb3Rpb24uRGF0YSRTdHlsZSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVsPWMoMSwyLDApLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzPWMoIk5vcm1hbCIsICJFeGFnZ2VyYXRlZCIsICJGbGF0IikpDQpgYGANCg0KLSBUaGVuIHdlIHdpbGwgY3JlYXRlIG91ciBuZXcgY29udHJhc3QgYGNvbnRyLnN1bWAgd2l0aCB0aHJlZSBsZXZlbHMgYCgzKWAgIA0KDQpgYGB7cn0NCmNvbnRyLnN1bSgzKQ0KYGBgDQoNCi0gV2Ugd2lsbCBhZGQgdGhhdCBjb2RlIHRvIG91ciBgbG1gIGZ1bmN0aW9uLCBieSBhZGRpbmcgdGhlIHBhcmFtZXRlcnMgYGxpc3QoU3R5bGUuQy5TPWNvbnRyLnN1bSgzKSlgICANCg0KYGBge3IsIGVjaG89VFJVRSwgd2FybmluZz1GQUxTRX0NCk1vZGVsLjEuQ1M8LWxtKEVtb3Rpb24gfiBTdHlsZS5DLlMsIGRhdGEgPSBFbW90aW9uLkRhdGEsDQogICAgICAgICAgICAgICBjb250cmFzdHM9bGlzdChTdHlsZS5DLlM9Y29udHIuc3VtKDMpKSkNCmBgYA0KDQotIExldCdzIGxvb2sgYXQgaG93IHRoaW5ncyBkaWZmZXIgZnJvbSB0aGUgbWVhbiBvZiBhbGwgY29uZGl0aW9ucyAoZ3JhbmQgbWVhbikNCg0KYGBge3IsIGVjaG89RkFMU0UsIHJlc3VsdHM9J2FzaXMnfQ0Kc3RhcmdhemVyKE1vZGVsLjEuQ1MsdHlwZT0iaHRtbCIsDQogICAgICAgICAgaW50ZXJjZXB0LmJvdHRvbSA9IEZBTFNFLA0KICAgICAgICAgIHNpbmdsZS5yb3c9VFJVRSwgbm90ZXMuYXBwZW5kID0gRkFMU0UsDQogICAgICAgICAgb21pdC5zdGF0PWMoInNlciIpLCBzdGFyLmN1dG9mZnMgPSBjKDAuMDUsIDAuMDEsIDAuMDAxKSwNCiAgICAgICAgICBoZWFkZXI9RkFMU0UpDQpgYGANCg0KLSBJbnRlcmNlcHQgPSBNZWFuIG9mIG1lYW5zIChncmFuZCBtZWFuKQ0KLSBNZWFuIG9mIGVhY2ggY29uZGl0aW9uIGNhbGN1bGF0ZWQgYmVsb3cNCg0KYGBge3J9DQpNZWFuLkludGVyYWN0aW9uPC1hZ2dyZWdhdGUoRW1vdGlvbn5TdHlsZUYsZGF0YSA9IEVtb3Rpb24uRGF0YSwgRlVOPW1lYW4pDQpgYGANCg0KYGBge3IsIGVjaG89RkFMU0UsIHJlc3VsdHM9J2FzaXMnfQ0KbGlicmFyeShrbml0cikNCmthYmxlKE1lYW4uSW50ZXJhY3Rpb24pDQpgYGANCg0KLSBHcmFuZCBtZWFuIGNhbGN1bGF0ZWQgYmVsb3cNCg0KYGBge3J9DQpzdW0oYWdncmVnYXRlKEVtb3Rpb25+U3R5bGVGLGRhdGEgPSBFbW90aW9uLkRhdGEsIEZVTj1tZWFuKVsyXSkvMw0KYGBgDQoNCiMjIyMgQ29lZmZpY2llbnRzDQotIFN0eWxlLkMuUzEgPSBjb2VmZmljaWVudCBvbiBOb3JtYWwgYXMgaXQgZGlmZmVycyBmcm9tIGdyYW5kIG1lYW4NCi0gU3R5bGUuQy5TMiA9IGNvZWZmaWNpZW50IG9uIEV4YWdnZXJhdGVkIGFzIGl0IGRpZmZlcnMgZnJvbSBncmFuZCBtZWFuDQotIFRvIGdldCB0aGUgbWVhbnMgZm9yIGVhY2ggY29uZGl0aW9uOiANCg0KIyMjIyBNZWFucyBwZXIgQ29uZGl0aW9uDQotICpGbGF0ID0gQ2Fubm90IGdldCBmcm9tIHRoaXMgbW9kZWwqDQotICpOb3JtYWwgPSBJbnRlcmNlcHQgKyBTdHlsZS5DLlMxKg0KLSAqRXhhZ2dlcmF0ZWQgPSBJbnRlcmNlcHQgKyBTdHlsZS5DLlMyKg0KDQojIyMjIFB2YWx1ZXMNCi0gVGhlIHB2YWx1ZSBvbiB0aGUgaW50ZXJjZXB0IGFza3MgaWYgdGhlICpncmFuZCBtZWFuKiBkaWZmZXJlbnQgZnJvbSB6ZXJvDQotIFRoZSBwdmFsdWUgb24gdGhlIHNsb3BlcyBhc2tzIGlmIGVhY2ggb2YgdGhlIG90aGVyIGxldmVscyBpcyBkaWZmZXJlbnQgZnJvbSAqZ3JhbmQgbWVhbioNCi0gKk5vdGUqOiBXZSBoYXZlIGxvc3QgdGhlIGFiaWxpdHkgdG8gYXNrIGFib3V0IEZsYXQgY29uZGl0aW9uLCB0byBnZXQgaXQgYmFjayB3ZSB3b3VsZCBoYXZlIHRvIHJvdGF0ZSB0aGUgYmFzZWxpbmUgYW5kIGRvIGl0IGFnYWluDQoNCiMjIyAgU2ltcGxlIENvZGluZw0KLSBUaGV5IG11c3Qgc3VtIHRvIHplcm8sIGFuZCB0aGUgYWJzKHZhbHVlcykgbXVzdCBzdW0gdG8gMQ0KLSBMaWtlIGluIEFOT1ZBIHlvdSBjYW4gZGVzaWduIHRoZXNlIHRvIGFzayBzcGVjaWZpYyBxdWVzdGlvbnMgYnkgbWVyZ2luZyBjb25kaXRpb25zIChvciBub3QpDQotIFdlIHdpbGwgdXNlIHRoZSBjb250ci50cmVhdG1lbnQgdHJlYXRtZW50ICh3aGljaCBSIGlzIHVzaW5nIHRvIGF1dG9tYXRpY2FsbHkgY29udmVydCB5b3VyIGNhdGVnb3JpY2FsIHZhcmlhYmxlcyBhbHJlYWR5KQ0KLSAqKkp1c3QgbGlrZSBkdW1teSBjb2RpbmcgYnV0IHdlIGNoYW5nZSB0aGUgbWVhbmluZyBvZiB0aGUgaW50ZXJjZXB0KioNCi0gVGhlIHJlZmVyZW5jZSBsZXZlbCBpcyAqKkZpcnN0KiogYWdhaW4NCg0KVmFyaWFibGUgICAgfCBDMSAgIHwgQzINCi0tLS0tLS0tLS0tLXwgLS0tLSB8IC0tLQ0KRmxhdCAgICAgICAgfCAtMS8zIHwgLTEvMw0KTm9ybWFsICAgICAgfCAgMi8zIHwgLTEvMw0KRXhhZ2dlcmF0ZWQgfCAtMS8zIHwgIDIvMw0KDQpgYGB7ciwgZWNobz1UUlVFLCB3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0V9DQpFbW90aW9uLkRhdGEkU3R5bGUuU2ltcGxlIDwtIGZhY3RvcihFbW90aW9uLkRhdGEkU3R5bGUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbD1jKDAsMSwyKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscz1jKCJGbGF0IiwgIk5vcm1hbCIsICJFeGFnZ2VyYXRlZCIpKQ0KDQpMZXZlbHM8LTMNClNpbXBsZS4xPC1jb250ci50cmVhdG1lbnQoTGV2ZWxzKSAjIER1bW15IGNvZGUNCiNNYWtlIHlvdXIgY29kZXMNCm15LmNvZGluZzwtbWF0cml4KHJlcCgxL0xldmVscywgTGV2ZWxzKihMZXZlbHMtMSkpLCBuY29sPUxldmVscy0xKQ0KbXkuc2ltcGxlPC1TaW1wbGUuMS1teS5jb2RpbmcNCm15LnNpbXBsZQ0KYGBgDQoNCi0gV2Ugd2lsbCBhZGQgdGhhdCBjb2RlIHRvIG91ciBgbG1gIGZ1bmN0aW9uLCBieSBhZGRpbmcgdGhlIHBhcmFtZXRlcnMgYGxpc3QoU3R5bGUuU2ltcGxlPW15LnNpbXBsZSlgICANCg0KYGBge3J9DQpNb2RlbC4xLlNpbXBsZTwtbG0oRW1vdGlvbiB+IFN0eWxlLlNpbXBsZSwgZGF0YSA9IEVtb3Rpb24uRGF0YSwgDQogICAgICAgICAgICAgICAgICAgY29udHJhc3RzPWxpc3QoU3R5bGUuU2ltcGxlPW15LnNpbXBsZSkpDQpgYGANCg0KYGBge3IsIGVjaG89RkFMU0UsIHJlc3VsdHM9J2FzaXMnfQ0Kc3RhcmdhemVyKE1vZGVsLjEuU2ltcGxlLHR5cGU9Imh0bWwiLA0KICAgICAgICAgIGludGVyY2VwdC5ib3R0b20gPSBGQUxTRSwNCiAgICAgICAgICBzaW5nbGUucm93PVRSVUUsICBub3Rlcy5hcHBlbmQgPSBGQUxTRSwNCiAgICAgICAgICBvbWl0LnN0YXQ9Yygic2VyIiksIHN0YXIuY3V0b2ZmcyA9IGMoMC4wNSwgMC4wMSwgMC4wMDEpLA0KICAgICAgICAgIGhlYWRlcj1GQUxTRSkNCmBgYA0KDQojIyMjIENvZWZmaWNpZW50cw0KLSBUaGlzIG1lcmdlcyB0aGUgZHVtbXkgYW5kIGRldmlhbmNlIGNvZGluZ3MgdGh1czogDQotIEludGVyY2VwdCA9IE1lYW4gb2YgbWVhbnMgKGdyYW5kIG1lYW4pDQotIFN0eWxlRk5vcm1hbCA9ICBzbG9wZSBvZiBOb3JtYWwgZnJvbSBiYXNlbGluZSAoRmxhdCkNCi0gU3R5bGVGRXhhZ2dlcmF0ZWQgPSBzbG9wZSBvZiBFeGFnZ2VyYXRlZCBmcm9tIGJhc2VsaW5lIChGbGF0KQ0KDQojIyMjIE1lYW5zIHBlciBDb25kaXRpb24NCi0gKllvdSBjYW5ub3QgZ2V0IG1lYW5zIG9mIGVhY2ggY29uZGl0aW9uIGZyb20gdGhpcyBtb2RlbCoNCg0KIyMjIyBQdmFsdWVzDQotIFRoZSBwdmFsdWUgb24gdGhlIGludGVyY2VwdCBhc2tzIGlmIHRoZSAqZ3JhbmQgbWVhbiogZGlmZmVyZW50IGZyb20gemVybw0KLSBUaGUgcHZhbHVlIG9uIHRoZSBzbG9wZXMgYXNrcyBpZiBlYWNoIG9mIHRoZSBvdGhlciBsZXZlbHMgaXMgZGlmZmVyZW50IGZyb20gYmFzZWxpbmUgKCpGbGF0KikNCg0KIyMjIE90aGVyIHR5cGVzIG9mIGNvbnRyYXN0IGNvZGluZw0KLSBIZWxtZXJ0OiBjb21wYXJlcyBlYWNoIGxldmVsIHRvIHRoZSBtZWFuIG9mIHRoZSBzdWJzZXF1ZW50IGxldmVscyBbY2FuIGJlIHJldmVyc2VkXQ0KLSBGb3J3YXJkIERpZmZlcmVuY2UgY29kaW5nOiBvbmUgbGV2ZWwgaXMgY29tcGFyZWQgdG8gdGhlIG5leHQgKGFkamFjZW50KSBsZXZlbC4gKGxldmVsIDEgdnMuIDIuIGxldmVsIDIgdnMuIDMpIFtjYW4gYmUgcmV2ZXJzZWRdDQotIEN1c3RvbTogTWVyZ2UgYW5kIGNvbXBhcmUgbGV2ZWxzIGF0IHdpbGwNCg0KIyMjIyBDZW50ZXIgdmFyaWFibGVzIGFuZCB0ZXN0IHNsb3Blcw0KLSBUaGVyZSBpcyBubyByZWFzb24gd2h5IHlvdSBjYW5ub3QgdHJlYXQgdGhlIHZhcmlhYmxlcyBhcyBjb250aW51b3VzIGlzIHRoZXkgYXJlICpvcmRpbmFsKg0KLSBqdXN0IGNlbnRlciB0aGVtIGFuZCB0cmVhdCBsaWtlIGEgY29udGludW91cyB2YXJpYWJsZQ0KDQoNCiMgTW9kZWxzIHdpdGggSW50ZXJhY3Rpb25zICgyIE5vbWluYWwgdmFyaWFibGVzKQ0KLSBJbnRlcmFjdGlvbnMgY2FuIGJlIHRyaWNreSBhcyB0aGUgaW50ZXJwcmV0YXRpb24gZGVwZW5kcyBvbiBob3cgeW91IGNvZGUgSVZzDQogICAgLSBGaXJzdCwgbGV0J3MgdHJ5IHNvbWUgY2F0ZWdvcmljYWwgdnMuIGNhdGVnb3JpY2FsIGludGVyYWN0aW9ucw0KLSBXZSB3aWxsIGFkZCBhIHZhcmlhYmxlIHRvIG91ciBleHBlcmltZW50IGZyb20gYWJvdmU7IHdlIHdpbGwgYWRkIHRoZSBsb2NhdGlvbiB3aGVyZSB0aGUgYWN0b3JzIHdvcmsgKE1vdmllIHZzLiBUaGVhdHJlKQ0KLSBFbW90aW9uIHJhdGluZyB+IEV4cHJlc3NpdmUgaW50ZW50aW9ucypsb2NhdGlvbiBvZiB0aGUgYWN0b3IgDQoNCiRFbW90aW9uID0gLTMqRmxhdCArIDAqTm9ybWFsICszKkV4YWcgKzAqTW92aWUgLSAxLjUqVGhlYXRyZSAtIDAqRmxhdCpNb3ZpZSArIDAqTm9ybWFsKk1vdmllICswKkV4YWcqTW92aWUgLSAxMCpGbGF0KlRoZWF0cmUgKzAqTm9ybWFsKlRoZWF0cmUgKzEwKkV4YWcqVGhlYXRyZSArIDUwICsgXGVwc2lsb24kDQoNCg0KYGBge3J9DQpzZXQuc2VlZCg0MikNCk4gPC0gMjAwDQpYIDwtIHNhbXBsZShyZXAoYygtMSwwLDEpLE4pLE4scmVwbGFjZSA9IEZBTFNFKQ0KWiA8LSBzYW1wbGUocmVwKGMoMCwxKSxOKjMvMiksTixyZXBsYWNlID0gRkFMU0UpDQoNCiMgT3VyIGVxdWF0aW9uIHRvIGNyZWF0ZSBZDQpZIDwtIDMqWCAtMS41KlorMTAqWCpaKyA1MCArIHJub3JtKE4sIHNkPTEwKQ0KI0J1aWx0IG91ciBkYXRhIGZyYW1lDQpFbW90aW9uLkRhdGEuMjwtZGF0YS5mcmFtZShFbW90aW9uPVksU3R5bGU9WCxMb2NhdGlvbj1aKQ0KRW1vdGlvbi5EYXRhLjIkU3R5bGU8LUVtb3Rpb24uRGF0YS4yJFN0eWxlKzENCmBgYA0KDQoNCiMjIER1bW15IGNvZGluZw0KLSBMZXRzIGR1bW15IGNvZGUgYWxsIG9mIHRoZW06IGNvbnZlcnQgdGhlbSB0byBhIGxhYmVsIGluIHRoZSBvdGhlciB3ZSB3YW50DQoNCmBgYHtyLCBlY2hvPVRSVUUsIHdhcm5pbmc9RkFMU0V9DQojIENvbnZlcnQgYWxsIG91ciBmYWN0b3JzDQpFbW90aW9uLkRhdGEuMiRTdHlsZUYgPC0gZmFjdG9yKEVtb3Rpb24uRGF0YS4yJFN0eWxlLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWw9YygwLDEsMiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHM9YygiRmxhdCIsICJOb3JtYWwiLCAiRXhhZ2dlcmF0ZWQiKSkNCg0KRW1vdGlvbi5EYXRhLjIkTG9jYXRpb25GIDwtIGZhY3RvcihFbW90aW9uLkRhdGEuMiRMb2NhdGlvbiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVsPWMoMCwxKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscz1jKCJNb3ZpZSBTZXQiLCAiVGhlYXRyZSIpKQ0KDQpgYGANCg0KLUxldCdzIGxvb2sgYXQgdGhlIGNvbGxhcHNlZCBtZWFucyBhbmQgdGhlIG1lYW5zIHBlciBjZWxsDQoNCmBgYHtyLCBlY2hvPVRSVUUsIHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRSxyZXN1bHRzPSdhc2lzJ30NCk1lYW4uU3R5bGU8LWFnZ3JlZ2F0ZShFbW90aW9uflN0eWxlRixkYXRhID0gRW1vdGlvbi5EYXRhLjIsIEZVTj1tZWFuKQ0Ka2FibGUoTWVhbi5TdHlsZSkNCk1lYW4uTG9jYXRpb248LWFnZ3JlZ2F0ZShFbW90aW9ufkxvY2F0aW9uRixkYXRhID0gRW1vdGlvbi5EYXRhLjIsIEZVTj1tZWFuKQ0Ka2FibGUoTWVhbi5Mb2NhdGlvbikNCk1lYW4uSW50ZXJhY3Rpb248LWFnZ3JlZ2F0ZShFbW90aW9uflN0eWxlRipMb2NhdGlvbkYsZGF0YSA9IEVtb3Rpb24uRGF0YS4yLCBGVU49bWVhbikNCmthYmxlKE1lYW4uSW50ZXJhY3Rpb24pDQpgYGANCg0KLSBMZXQgZXhhbWluZSBvdXIgcmVncmVzc2lvbiwgYnV0IHdlIG5lZWQgdG8gZXhhbWluZSBhIG1haW4gZWZmZWN0cyBhbmQgaW50ZXJhY3Rpb24gbW9kZWwNCg0KYGBge3J9DQpNb2RlbC5JMS5EdW1teTwtbG0oRW1vdGlvbiB+IFN0eWxlRitMb2NhdGlvbkYsIGRhdGEgPSBFbW90aW9uLkRhdGEuMikNCk1vZGVsLkkyLkR1bW15PC1sbShFbW90aW9uIH4gU3R5bGVGKkxvY2F0aW9uRiwgZGF0YSA9IEVtb3Rpb24uRGF0YS4yKQ0KYGBgDQoNCg0KYGBge3IsIGVjaG89RkFMU0UscmVzdWx0cz0nYXNpcyd9DQpzdGFyZ2F6ZXIoTW9kZWwuSTEuRHVtbXksTW9kZWwuSTIuRHVtbXksdHlwZT0iaHRtbCIsDQogICAgICAgICAgY29sdW1uLmxhYmVscyA9IGMoIk1haW4gRWZmZWN0cyIsICJJbnRlcmFjdGlvbiIpLA0KICAgICAgICAgIGludGVyY2VwdC5ib3R0b20gPSBGQUxTRSwNCiAgICAgICAgICBzaW5nbGUucm93PVRSVUUsbm90ZXMuYXBwZW5kID0gRkFMU0UsDQogICAgICAgICAgb21pdC5zdGF0PWMoInNlciIpLCBzdGFyLmN1dG9mZnMgPSBjKDAuMDUsIDAuMDEsIDAuMDAxKSwNCiAgICAgICAgICBoZWFkZXI9RkFMU0UpDQpgYGANCg0KDQotIFlvdSB3aWxsIG5vdGljZSBhIGxhcmdlIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgbWFpbiBlZmZlY3RzIGFuZCBpbnRlcmFjdGlvbiBtb2RlbA0KLSBUaGlzIGlzIGJlY2F1c2UgdGhlIG1lYW5pbmcgY29lZmZpY2llbnRzIGluIHRoZSBpbnRlcmFjdGlvbiBkaWZmZXIgZnJvbSB0aGUgbWFpbiBlZmZlY3RzIG1vZGVsDQotIFRoZSBtYWluIGVmZmVjdHMgd2VyZSBleHBsYWluZWQgYWJvdmUsIGJ1dCB0aGV5IGNoYW5nZSBtZWFuaW5nIGEgbGl0dGxlIGJlY2F1c2UgdGhlcmUgaXMgc2Vjb25kIHZhcmlhYmxlDQoNCiMjIyBNYWluIEVmZmVjdHMNCg0KIyMjIyBDb2VmZmljaWVudHMNCi0gVGhlc2UgZG8gbm90IGNvbm5lY3QgYmFjayB0byB0aGUgaW5kaXZpZHVhbCBjZWxscyBhcyB5b3UgYXJlIGFzc3VtaW5nIHRoZSB0d28gZmFjdG9ycyBoYXZlIGluZGVwZW5kZW50IGVmZmVjdHMNCiAgICAtIFRodXMgdGhlc2UgYXJlIGh5cG90aGV0aWNhbCB2YWx1ZXMgKG5vdCBjb25uZWN0ZWQgdG8gdGhlIGluZGl2aWR1YWwgY2VsbHMpDQotIEludGVyY2VwdCA9IEVzdGltYXRlIG9mIHRoZSBtZWFuLCBhc3N1bWluZyB0aGUgdHdvIGZhY3RvcnMgaGF2ZSBpbmRlcGVuZGVudCBlZmZlY3RzIGF0IHRoZWlyIDAgcG9pbnRzIFtiYXNlbGluZV0NCi0gU3R5bGVGTm9ybWFsID0gTm9ybWFsIC0gRmxhdCAoYXNzdW1pbmcgdGhlIHR3byBmYWN0b3JzIGFyZSBpbmRlcGVuZGVudCkNCi0gU3R5bGVGRXhhZ2dlcmF0ZWQgPSBFeGFnZ2VyYXRlZCAtIEZsYXQgKGFzc3VtaW5nIHRoZSB0d28gZmFjdG9ycyBhcmUgaW5kZXBlbmRlbnQpDQotIExvY2F0aW9uRlRoZWF0cmUgPSBUaGVhdHJlIC0gTW92aWUoYXNzdW1pbmcgdGhlIHR3byBmYWN0b3JzIGFyZSBpbmRlcGVuZGVudCkNCg0KLSBXZSBjYW4gc2VlIHRoZSBtYWluIGVmZmVjdCBtb2RlbHMgcmVzdWx0cw0KDQpgYGB7cn0NCmxpYnJhcnkoZWZmZWN0cykNCmFsbEVmZmVjdHMoTW9kZWwuSTEuRHVtbXkpDQpgYGANCg0KIyMjIyBNZWFucyBwZXIgQ29uZGl0aW9uIA0KLSBZb3UgY2Fubm90IGdldCB0aGVtDQoNCiMjIyMgUHZhbHVlcw0KLSBUaGUgcHZhbHVlIG9uIHRoZSBpbnRlcmNlcHQgYXNrcyBpZiB0aGUgYmFzZWxpbmUgaXMgZGlmZmVyZW50IGZyb20gemVybw0KLSBUaGUgcHZhbHVlIG9uIHRoZSBkaWZmZXJlbmNlcyBhc2tzIGlmIHRoZXkgYXJlIGZyb20gZGlmZmVyZW50IGZyb20gYmFzZWxpbmUgDQoNCiMjIyBJbnRlcmFjdGlvbnMNCg0KIyMjIyBDb2VmZmljaWVudHMNCi0gVGhlc2UgY2VsbHMgY29ubmVjdCBiYWNrIHRvIGV4cGVyaW1lbnRhbCBjZWxscw0KLSBJbnRlcmNlcHQgPSBMb2NhdGlvbigwKSBAIFN0eWxlKDApIGFrYSBNb3ZpZSBAIEZsYXQgW3JlYWwgdmFsdWVdDQotIFN0eWxlRk5vcm1hbCA9IERpZmZlcm5jZSBvZiBbTG9jYXRpb24oMCkgQCBTdHlsZSgxKV0gLSBbTG9jYXRpb24oMCkgQCBTdHlsZSgwKV0NCi0gU3R5bGVGRXhhZ2dlcmF0ZWQgPSBEaWZmZXJuY2Ugb2YgW0xvY2F0aW9uKDApIEAgU3R5bGUoMildIC0gW0xvY2F0aW9uKDApIEAgU3R5bGUoMCldDQotIExvY2F0aW9uRlRoZWF0cmUgPSBEaWZmZXJuY2Ugb2YgW0xvY2F0aW9uKDEpIEAgU3R5bGUoMCldIC0gW0xvY2F0aW9uKDApIEAgU3R5bGUoMCldDQotIFN0eWxlRk5vcm1hbDpMb2NhdGlvbkZUaGVhdHJlID0gRGlmZmVybmNlIG9mIFtMb2NhdGlvbigxKSBAIFN0eWxlKDEpXSAtIFtMb2NhdGlvbigwKSBAIFN0eWxlKDEpIC0gTG9jYXRpb24oMCkgQCBTdHlsZSgwKSArIFtMb2NhdGlvbigxKSBAIFN0eWxlKDApXSAtIFtMb2NhdGlvbigwKSBAIFN0eWxlKDApXQ0KLSBTdHlsZUZFeGFnZ2VyYXRlZDpMb2NhdGlvbkZUaGVhdHJlID0gRGlmZmVybmNlIG9mIFtMb2NhdGlvbigxKSBAIFN0eWxlKDIpXSAtIFtMb2NhdGlvbigwKSBAIFN0eWxlKDIpIC0gTG9jYXRpb24oMCkgQCBTdHlsZSgwKSArIFtMb2NhdGlvbigyKSBAIFN0eWxlKDApXSAtIFtMb2NhdGlvbigwKSBAIFN0eWxlKDApXQ0KDQoNCiMjIyMgTWVhbnMgcGVyIENvbmRpdGlvbg0KLSBZb3UgY2FuIGZpbmQgYWxsIG1lYW5zIGZvciBhbGwgY2VsbHMhIA0KLSAqRmxhdCBAIE1vdmllID0gSW50ZXJjZXB0Kg0KLSAqTm9ybWFsIEAgTW92aWUgPSBJbnRlcmNlcHQgKyBTdHlsZUZOb3JtYWwqIA0KLSAqRXhhZ2dlcmF0ZWQgQCBNb3ZpZSA9IEludGVyY2VwdCArIFN0eWxlRkV4YWdnZXJhdGVkKiANCi0gKkZsYXQgQCBUaGVhdHJlID0gSW50ZXJjZXB0ICsgTG9jYXRpb25GVGhlYXRyZSoNCi0gKk5vcm1hbCBAIFRoZWF0cmUgPSBJbnRlcmNlcHQgKyBMb2NhdGlvbkZUaGVhdHJlK1N0eWxlRk5vcm1hbCtTdHlsZUZOb3JtYWw6TG9jYXRpb25GVGhlYXRyZSogDQotICpFeGFnZ2VyYXRlZCBAIFRoZWF0cmUgPSAgSW50ZXJjZXB0ICsgTG9jYXRpb25GVGhlYXRyZSArIFN0eWxlRkV4YWdnZXJhdGVkICsgU3R5bGVGRXhhZ2dlcmF0ZWQ6TG9jYXRpb25GVGhlYXRyZSAqIA0KDQojIyMjIFB2YWx1ZXMNCi0gVGhlIHB2YWx1ZSBvbiB0aGUgaW50ZXJjZXB0IGFza3MgaWYgdGhlIGJhc2VsaW5lIGlzIGRpZmZlcmVudCBmcm9tIHplcm8NCi0gVGhlIHB2YWx1ZSBvbiB0aGUgZGlmZmVyZW5jZXMgYXNrcyBpZiB0aGV5IGFyZSBmcm9tIGRpZmZlcmVudCBmcm9tIGJhc2VsaW5lIA0KLSBCdXQgdGhlc2UgYXJlIG5vdyBhcmUgbm93IHNpbXBsZSBlZmZlY3RzIA0KDQoNCiMjIyBNYWluIGVmZmVjdCBtb2RlbCB2cy4gSW50ZXJhY3Rpb24gbW9kZWwNCi0gU2luY2UgdGhlIHJlc3VsdHMgYXJlIG5vdCBhZGRpdGl2ZSwgdGhlIG1haW4gZWZmZWN0IG1vZGVsIGlzIHVzZWZ1bCBvbmx5IGluIHdoaWNoIHRvIHVuZGVyc3RhbmQgaG93IHRoZSB0ZXJtcyBoYXZlIGNoYW5nZWQNCi0gR2l2ZXMgc29tZSBpbnNpZ2h0IGludG8gdGhlIGludGVyYWN0aW9uDQoNCiMjIyBHcmFwaCBNb2RlbA0KDQpgYGB7cn0NCkludGVyLjE8LWVmZmVjdCgiU3R5bGVGKkxvY2F0aW9uRiIsIE1vZGVsLkkyLkR1bW15KQ0KcGxvdChJbnRlci4xLCBtdWx0aWxpbmUgPSBUUlVFKQ0KYGBgDQoNCiMjIyBDb25uZWN0aW9uIHRvIGJldHdlZW4tc3ViamVjdCBBTk9WQQ0KLSBSZWdyZXNzaW9uIHdpdGggb25seSBjYXRlZ29yaWNhbCB2YXJpYWJsZXMgY2FuIGJlIGNvbnZlcnRlZCBpbnRvIGFuIEFOT1ZBIHZlcnkgZWFzaWx5IA0KLSBUaHVzIGl0IGNhbiBiZSB0cmVhdGVkIGp1c3QgbGlrZSBBTk9WQQ0KLSBidXQgdGhlIHJlZ3Jlc3Npb24gbWFrZXMgdGhlIEFOT1ZBIHByb2Nlc3MgbW9vdCBhcyB5b3UgY2FuIG5vdyB0aGUgcmVncmVzc2lvbiBjYW4gYmUgY29kZWQgaW4gc3VjaCBhIHdheSB0aGF0IHlvdSBjYW4gdGVzdCBmb2xsb3cgdXAgdGVzdHMgaW4gYSB3YXkgeW91IHdhbnQgdG8gdGVzdCB0aGVtIGFsbCANCg0KYGBge3J9DQpsaWJyYXJ5KGNhcikNCkFub3ZhKE1vZGVsLkkyLkR1bW15LCB0eXBlPSJJSUkiKQ0KYGBgDQoNCi0gTm90ZSwgd2UgaGF2ZSB0byBjYWxsIGZvciBhIFR5cGUgSUlJIHN1bSBvZiBzcXVhcmVzIHRvIG1hdGNoIFNQU1Mgb3V0cHV0IGFzIFIgd291bGQgZGVmYXVsdCB0byBUeXBlIEkNCg0KIyMgQ29udHJhc3QgQ29kaW5nDQoNCiMjIyBEZXZpYXRpb24gQ29kaW5nDQotIExldHMgY29kZSBlYWNoIHZhcmlhYmxlIGFzIHdlIGRpZCBhYm92ZQ0KDQpgYGB7ciwgZWNobz1UUlVFLCB3YXJuaW5nPUZBTFNFfQ0KRW1vdGlvbi5EYXRhLjIkU3R5bGUuQy5TIDwtIGZhY3RvcihFbW90aW9uLkRhdGEuMiRTdHlsZSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVsPWMoMSwyLDApLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzPWMoIk5vcm1hbCIsICJFeGFnZ2VyYXRlZCIsICJGbGF0IikpDQpFbW90aW9uLkRhdGEuMiRMb2NhdGlvbi5DLlMgPC0gZmFjdG9yKEVtb3Rpb24uRGF0YS4yJExvY2F0aW9uLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWw9YygxLDApLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzPWMoIlRoZWF0cmUiLCAiTW92aWUgU2V0IikpDQoNCk1vZGVsLkkxLkMuUzwtbG0oRW1vdGlvbiB+IFN0eWxlLkMuUytMb2NhdGlvbi5DLlMsIGRhdGEgPSBFbW90aW9uLkRhdGEuMiwgDQogICAgICAgICAgICAgICAgIGNvbnRyYXN0cz1saXN0KFN0eWxlLkMuUz1jb250ci5zdW0oMyksTG9jYXRpb24uQy5TPWNvbnRyLnN1bSgyKSkpDQpNb2RlbC5JMi5DLlM8LWxtKEVtb3Rpb24gfiBTdHlsZS5DLlMqTG9jYXRpb24uQy5TLCBkYXRhID0gRW1vdGlvbi5EYXRhLjIsDQogICAgICAgICAgICAgICAgY29udHJhc3RzPWxpc3QoU3R5bGUuQy5TPWNvbnRyLnN1bSgzKSxMb2NhdGlvbi5DLlM9Y29udHIuc3VtKDIpKSkNCmBgYA0KDQotIExldCdzIGxvb2sgYXQgaG93IHRoaW5ncyBkaWZmZXIgZnJvbSB0aGUgbWVhbiBvZiBhbGwgY29uZGl0aW9ucyAoZ3JhbmQgbWVhbikNCg0KYGBge3IsIGVjaG89RkFMU0UsIHJlc3VsdHM9J2FzaXMnfQ0Kc3RhcmdhemVyKE1vZGVsLkkxLkMuUyxNb2RlbC5JMi5DLlMsdHlwZT0iaHRtbCIsDQogICAgICAgICAgY29sdW1uLmxhYmVscyA9IGMoIk1haW4gRWZmZWN0cyIsICJJbnRlcmFjdGlvbiIpLA0KICAgICAgICAgIGludGVyY2VwdC5ib3R0b20gPSBGQUxTRSwNCiAgICAgICAgICBzaW5nbGUucm93PVRSVUUsIG5vdGVzLmFwcGVuZCA9IEZBTFNFLA0KICAgICAgICAgIG9taXQuc3RhdD1jKCJzZXIiKSwgc3Rhci5jdXRvZmZzID0gYygwLjA1LCAwLjAxLCAwLjAwMSksDQogICAgICAgICAgaGVhZGVyPUZBTFNFKQ0KYGBgDQoNCi0gQWdhaW4gd2UgYXJlIHRlc3RpbmcgYmV0d2VlbiB0aGUgZ3JhbmQgbWVhbiBhbmQgdGhlIGluZGl2aWR1YWwgdGVybXMNCg0KIyMjIyBNYWluIEVmZmVjdHMNCg0KIyMjIyMgQ29lZmZpY2llbnRzDQotIFRoZXNlIGRvIG5vdCBjb25uZWN0IGJhY2sgdG8gdGhlIGluZGl2aWR1YWwgY2VsbHMgYXMgeW91IGFyZSBhc3N1bWluZyB0aGUgdHdvIGZhY3RvcnMgaGF2ZSBpbmRlcGVuZGVudCBlZmZlY3RzDQotIFRodXMgdGhlc2UgYXJlIGh5cG90aGV0aWNhbCAqR3JhbmQgbWVhbiogdmFsdWVzIA0KLSBJbnRlcmNlcHQgPSAqR3JhbmQgTWVhbiosIGJ1dCBhc3N1bWluZyB0aGUgdHdvIGZhY3RvcnMgaGF2ZSBpbmRlcGVuZGVudCBlZmZlY3RzDQotIFN0eWxlLkMuUzEgID0gTm9ybWFsIChhdmVyYWdlZCBvdmVyIGxvY2F0aW9uKSAtICpHcmFuZCBNZWFuKiAoYXNzdW1pbmcgdGhlIHR3byBmYWN0b3JzIGFyZSBpbmRlcGVuZGVudCkNCi0gU3R5bGUuQy5TMiA9IEV4YWdnZXJhdGVkIChhdmVyYWdlZCBvdmVyIGxvY2F0aW9uKSAtICpHcmFuZCBNZWFuKiAoYXNzdW1pbmcgdGhlIHR3byBmYWN0b3JzIGFyZSBpbmRlcGVuZGVudCkNCi0gTG9jYXRpb24uQy5TMSA9IFRoZWF0cmUgKGF2ZXJhZ2VkIG92ZXIgU3R5bGUpIC0gICpHcmFuZCBNZWFuKiAoYXNzdW1pbmcgdGhlIHR3byBmYWN0b3JzIGFyZSBpbmRlcGVuZGVudCkNCg0KIyMjIyMgTWVhbnMgcGVyIENvbmRpdGlvbg0KLSAqQ2Fubm90IGdldCBmcm9tIHRoaXMgbW9kZWwqDQoNCiMjIyMjIFB2YWx1ZXMNCi0gVGhlIHB2YWx1ZSBvbiB0aGUgaW50ZXJjZXB0IGFza3MgaWYgdGhlIGJhc2VsaW5lICgqR3JhbmQgTWVhbiopIGlzIGRpZmZlcmVudCBmcm9tIHplcm8NCi0gVGhlIHB2YWx1ZSBvbiB0aGUgc2xvcGVzIGFza3MgaWYgZWFjaCBvZiB0aGUgb3RoZXIgbGV2ZWxzIGlzIGRpZmZlcmVudCBmcm9tIHRoZSBiYXNlbGluZSAoKkdyYW5kIE1lYW4qKQ0KLSBOb3RlIHdlIGFyZSBtaXNzaW5nIHRlc3RzIG9uIEZsYXQgYW5kIE1vdmllIGNlbGwsIHdlIHdvdWxkIG5lZWQgdG8gcm90YXRlIHRoZSBtYXRyaXggYW5kIHJ1biBhZ2Fpbg0KDQojIyMjIEludGVyYWN0aW9ucw0KIyMjIyMgQ29lZmZpY2llbnRzDQotIEludGVyY2VwdCA9ICAqR3JhbmQgTWVhbiogKGFsbCA2IGNlbGxzIG1lYW4gYXZlcmFnZWQpDQotIFN0eWxlLkMuUzEgPSBOb3JtYWwgKGF2ZXJhZ2VkIG92ZXIgbG9jYXRpb24pIGZyb20gKkdyYW5kIE1lYW4qDQotIFN0eWxlLkMuUzIgPSBFeGFnZ2VyYXRlZCAoYXZlcmFnZWQgb3ZlciBsb2NhdGlvbikgZnJvbSAqR3JhbmQgTWVhbioNCi0gTG9jYXRpb24uQy5TMSA9IFRoZWF0cmUgKGF2ZXJhZ2VkIG92ZXIgU3R5bGUpIGZyb20gKkdyYW5kIE1lYW4qDQotIFN0eWxlLkMuUzE6TG9jYXRpb24uQy5TMSA9IGRpZmZlcmVuY2Ugb2YgTm9ybWFsIEAgVGhlYXRyZSBmcm9tICpHcmFuZCBNZWFuKg0KLSBTdHlsZS5DLlMyOkxvY2F0aW9uLkMuUzEgPSBkaWZmZXJlbmNlIG9mIEV4YWdnZXJhdGVkIEAgVGhlYXRyZSBmcm9tICpHcmFuZCBNZWFuKg0KIA0KIyMjIyMgTWVhbnMgcGVyIENvbmRpdGlvbg0KLSAqQ2Fubm90IGdldCBmcm9tIHRoaXMgbW9kZWwqDQoNCiMjIyMjIFB2YWx1ZXMNCi0gVGhlIHB2YWx1ZSBvbiB0aGUgaW50ZXJjZXB0IGFza3MgaWYgdGhlIGJhc2VsaW5lICgqR3JhbmQgTWVhbiopIGlzIGRpZmZlcmVudCBmcm9tIHplcm8NCi0gVGhlIHB2YWx1ZSBvbiB0aGUgZGlmZmVyZW5jZXMgYXNrcyBpZiBlYWNoIG9mIHRoZSBvdGhlciBsZXZlbHMgaXMgZnJvbSB0aGUgKCpHcmFuZCBNZWFuKikNCi0gTm90ZSB3ZSBhcmUgbWlzc2luZyB0ZXN0cyBvbiBGbGF0IGFuZCBtb3ZpZSBjZWxsLCB3ZSB3b3VsZCBuZWVkIHRvIHJvdGF0ZSB0aGUgbWF0cml4IGFuZCBydW4gYWdhaW4NCg0KDQojIE1vZGVscyB3aXRoIEludGVyYWN0aW9ucyAoMSBOb21pbmFsIGFuZCAxIENvbnRpbnVvdXMgVmFyaWFibGUpDQotIFdlIHdpbGwgY2hhbmdlIG91ciBleHBlcmltZW50IGZyb20gYWJvdmUsIHdlIHdpbGwgYWRkIGEgbGlrZXJ0IHNjYWxlIHdoaWNoIHRoZSBhY3RvciByYXRlcyBob3cgImdvb2QiIHRoZXkgdGhpbmsgdGhlIHBlcmZvcm1hbmNlIHdhcyBbLTMgdGVycmlibGUgdG8gMyBleGNlbGxlbnRdDQotICpFbW90aW9uIHJhdGluZyB+IFF1YWxpdHkgUmF0aW5nIFggbG9jYXRpb24gb2YgdGhlIGFjdG9yIChpLmUuLCBNb3ZpZSBTZXQsIFRoZWF0cmUpKiANCg0KYGBge3IsIGVjaG89VFJVRSwgd2FybmluZz1GQUxTRX0NCiNTZXQgdXAgc2ltdWxhdGlvbg0Kc2V0LnNlZWQoNDIpDQpOIDwtIDIwMA0KWCA8LSBydW5pZihOLC0zLDMpDQpaIDwtIHNhbXBsZShyZXAoYygwLDEpLE4vMiksTixyZXBsYWNlID0gRkFMU0UpDQojIE91ciBlcXVhdGlvbiB0byBjcmVhdGUgWQ0KWSA8LSA0KlggKzIqWis4KlgqWisgNTAgKyBybm9ybShOLCBzZD0xMCkNCiNCdWlsdCBvdXIgZGF0YSBmcmFtZQ0KRW1vdGlvbi5EYXRhLjM8LWRhdGEuZnJhbWUoRW1vdGlvbj1ZLFF1YWxpdHk9WCxMb2NhdGlvbj1aKQ0KYGBgDQoNCiMjIENlbnRlciB0aGUgY29udGludW91cyB2YXJpYWJsZQ0KLSBCZXN0IHRvIGNlbnRlciBhcyBpdHMgd2lsbCBoZWxwIHVzIGludGVycHJldCANCg0KYGBge3IsIGVjaG89VFJVRSwgd2FybmluZz1GQUxTRX0NCiMgQ29udmVydCBhbGwgb3VyIGZhY3RvcnMNCkVtb3Rpb24uRGF0YS4zJFF1YWxpdHkuQyA8LSBzY2FsZShFbW90aW9uLkRhdGEuMyRRdWFsaXR5LCBzY2FsZSA9IEZBTFNFKVssXQ0KYGBgDQoNCiMjIER1bW15IGNvZGluZyBvZiBvdXIgbm9taW5hbCB2YXJpYWJsZQ0KLSBNYWtlIExvY2F0aW9uIGludG8gYSBmYWN0b3INCg0KYGBge3IsIGVjaG89VFJVRSwgd2FybmluZz1GQUxTRX0NCiMgQ29udmVydCBhbGwgb3VyIGZhY3RvcnMNCkVtb3Rpb24uRGF0YS4zJExvY2F0aW9uRiA8LSBmYWN0b3IoRW1vdGlvbi5EYXRhLjMkTG9jYXRpb24sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVsPWMoMCwxKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzPWMoIk1vdmllIFNldCIsIlRoZWF0cmUiKSkNCmBgYA0KDQotIEZpcnN0IHRvIHVuZGVyc3RhbmQgd2hhdCB0aGUgaW50ZXJhY3Rpb24gd2lsbCB5aWVsZCBsZXRzIHVzIHJ1biB0d28gcmVncmVzc2lvbnMgd2hlcmUgd2Ugc2VwZXJhdGUgb3VyIGZhY3RvciB0byBzZWUgd2hhdCB0aGUgc2xvcGVzIHdvdWxkIGJlIGp1c3QgZm9yIGFjdG9ycyBhdCAqTW92aWUgU2V0KiB2cyBhdCB0aGUgKlRoZWF0cmUqDQoNCiMjIyBNb3ZpZSBTZXQgT05MWSB2cyBUaGVhdHJlIE9ubHkNCi0gV2Ugd2lsbCBzdWJzZXQgdGhlIGRhdGEgYW5kIHRlc3QgZm9yIHRoZSBRdWFsaXR5IHNsb3Blcw0KDQpgYGB7cn0NCk1vZGVsLk1vdmllPC1sbShFbW90aW9uIH4gUXVhbGl0eS5DLCANCiAgICAgICAgICAgICAgICBkYXRhID0gc3Vic2V0KEVtb3Rpb24uRGF0YS4zLExvY2F0aW9uRj09Ik1vdmllIFNldCIpKQ0KTW9kZWwuVGhlYXRyZTwtbG0oRW1vdGlvbiB+IFF1YWxpdHkuQywgDQogICAgICAgICAgICAgICAgZGF0YSA9IHN1YnNldChFbW90aW9uLkRhdGEuMyxMb2NhdGlvbkY9PSJUaGVhdHJlIikpDQpgYGANCg0KYGBge3IsIGVjaG89RkFMU0UscmVzdWx0cz0nYXNpcyd9DQpsaWJyYXJ5KHN0YXJnYXplcikNCnN0YXJnYXplcihNb2RlbC5Nb3ZpZSxNb2RlbC5UaGVhdHJlLHR5cGU9Imh0bWwiLA0KICAgICAgICAgIGNvbHVtbi5sYWJlbHMgPSBjKCJNb3ZpZSBTZXQgT05MWSIsICJUaGVhdHJlIE9ubHkiKSwNCiAgICAgICAgICBpbnRlcmNlcHQuYm90dG9tID0gRkFMU0UsDQogICAgICAgICAgc2luZ2xlLnJvdz1UUlVFLCAgbm90ZXMuYXBwZW5kID0gRkFMU0UsDQogICAgICAgICAgb21pdC5zdGF0PWMoInNlciIpLA0KICAgICAgICAgIHN0YXIuY3V0b2ZmcyA9IGMoMC4wNSwgMC4wMSwgMC4wMDEpLA0KICAgICAgICAgIGhlYWRlcj1GQUxTRSkNCmBgYA0KDQotIElnbm9yZSB0aGUgaW50ZXJjZXB0cyBhbmQgcGF5IGF0dGVudGlvbiB0byB0aGUgc2xvcGVzOiANCiAgICAtIFF1YWxpdHkgQCB0aGUgKk1vdmllIFNldCBPTkxZKiBpcyAkYiQ9IGByIHJvdW5kKE1vZGVsLk1vdmllJGNvZWZmaWNpZW50c1syXSwzKWANCiAgICAgICAgLSBUaGUgcHZhbHVlcyB0ZWxscyB5b3UgaWYgdGhlIHNsb3BlIG9mIHF1YWxpdHkgaXMgZGlmZmVybmV0IGZyb20gYSBzbG9wZSBvZiAwICAgDQogICAgLSBRdWFsaXR5IEAgdGhlICpUaGVhdHJlIE9ubHkqIE9OTFkgaXMgJGIkPSBgciByb3VuZChNb2RlbC5UaGVhdHJlJGNvZWZmaWNpZW50c1syXSwzKWANCiAgICAgICAgLSBUaGUgcHZhbHVlcyB0ZWxscyB5b3UgaWYgdGhlIHNsb3BlIG9mIHF1YWxpdHkgaXMgZGlmZmVybmV0IGZyb20gYSBzbG9wZSBvZiAwICAgICAgICAgDQotIFdoYXQgd2UgcmVhbGx5IHdhbnQgdG8gdGVzdCBpcyBpZiB0aGVyZSBpcyBhIGRpZmZlcmVuY2UgaW4gc2xvcGVzIGJldHdlZW4gcXVhbGl0eSBhdCAqTW92aWVzIHNldHMqIFZTICpUaGVhdHJlKg0KDQojIyMgVGVzdGluZyB0aGUgSW50ZXJhY3Rpb24NCi0gV2Ugd2lsbCB0ZXN0IGEgbWFpbiBlZmZlY3RzIG1vZGVsLCBgUXVhbGl0eStMb2NhdGlvbmAgYW5kIGNvbXBhcmUgaXQgdG8gYW4gaW50ZXJhY3Rpb24gbW9kZWwgYFF1YWxpdHkqTG9jYXRpb25gDQoNCmBgYHtyfQ0KTW9kZWwuRTMuMTwtbG0oRW1vdGlvbiB+IFF1YWxpdHkuQytMb2NhdGlvbkYsIGRhdGEgPSBFbW90aW9uLkRhdGEuMykNCk1vZGVsLkUzLjI8LWxtKEVtb3Rpb24gfiBRdWFsaXR5LkMqTG9jYXRpb25GLCBkYXRhID0gRW1vdGlvbi5EYXRhLjMpDQpgYGANCg0KLSBEb2VzIG1vZGVsIGludGVyYWN0aW9uIGltcHJvdmUgdGhlIG1vZGVsIGZpdD8gKEp1c3QgbGlrZSB3ZSBkaWQgd2l0aCBoaWVyYXJjaGljYWwgdGVzdGluZykNCmBgYHtyfQ0KTW9kZWwuRml0LkUzPC1hbm92YShNb2RlbC5FMy4xLE1vZGVsLkUzLjIpDQpgYGANCg0KYGBge3IsIGVjaD1GQUxTRX0NCmxpYnJhcnkoa25pdHIpDQprYWJsZShNb2RlbC5GaXQuRTMpDQpgYGANCg0KLSBZZXMhIFRoZSBpbnRlcmFjdGlvbiBpcyBzaWduaWZpY2FudCBpbXByb3ZlbWVudA0KLSBMZXQncyBnbyBleGFtaW5lIHRoZSBpbmRpdmlkdWFsIHJlZ3Jlc3Npb24gcGFyYW1hdGVyczoNCg0KIyMjIEludGVycHJldCBSZWdyZXNzaW9uDQoNCmBgYHtyLCBlY2hvPUZBTFNFLHJlc3VsdHM9J2FzaXMnfQ0Kc3RhcmdhemVyKE1vZGVsLkUzLjEsTW9kZWwuRTMuMix0eXBlPSJodG1sIiwNCiAgICAgICAgICBjb2x1bW4ubGFiZWxzID0gYygiTWFpbiBFZmZlY3RzIiwgIkludGVyYWN0aW9uIiksDQogICAgICAgICAgaW50ZXJjZXB0LmJvdHRvbSA9IEZBTFNFLA0KICAgICAgICAgIHNpbmdsZS5yb3c9VFJVRSwgIG5vdGVzLmFwcGVuZCA9IEZBTFNFLA0KICAgICAgICAgIG9taXQuc3RhdD1jKCJzZXIiKSwNCiAgICAgICAgICBzdGFyLmN1dG9mZnMgPSBjKDAuMDUsIDAuMDEsIDAuMDAxKSwNCiAgICAgICAgICBoZWFkZXI9RkFMU0UpDQpgYGANCg0KDQoNCiMjIyMgTWFpbiBFZmZlY3RzIE1vZGVsDQotIEludGVyY2VwdCA9IE1lYW4gb2YgUXVhbGl0eSBAIE1vdmllcyBbKnAqID0gSXMgdGhlIGludGVyY2VwdCBkaWZmZXJlbnQgZnJvbSAwXQ0KLSBRdWFsaXR5LkMgID0gUXVhbGl0eS5DIHNsb3BlIGF2ZXJhZ2VkIGFjcm9zcyAqTW92aWVzKiAmICogVGhyZWF0cmUqICAgDQogICAgLSBUaGlzIGlzIGEgKipNYWluIEVmZmVjdCoqIFsqcCogPSBJcyBzbG9wZSBkaWZmZXJlbnQgZnJvbSAwIHNsb3BlXSANCiAgICAgICAgLSBUaGlzIHdvdWxkIGFsbW9zdCBiZSBsaWtlIGF2ZXJhZ2luZyB0aGUgc2xvcGVzIGZyb20gb3VyICpNb3ZpZSBTZXQgT05MWSogYW5kICpUaGVhdHJlIE9ubHkqIE1vZGVscw0KICAgICAgICAgICAgLSAkYiQgPSAoYHIgcm91bmQoTW9kZWwuTW92aWUkY29lZmZpY2llbnRzWzJdLDMpYCArICBgciByb3VuZChNb2RlbC5UaGVhdHJlJGNvZWZmaWNpZW50c1syXSwzKWApLzIgPSBgciByb3VuZCgoKE1vZGVsLk1vdmllJGNvZWZmaWNpZW50c1syXStNb2RlbC5UaGVhdHJlJGNvZWZmaWNpZW50c1syXSkvMiksMylgIA0KLSBMb2NhdGlvbkZUaGVhdHJlID0gVGhyZWF0cmUgZGlmZmVyZW5jZSBmcm9tIGludGVyY2VwdCBbcCA9IElzIG1lYW4gb2YgKlRoZWF0cmUqIGRpZmZlcmVudCBmcm9tICpNb3ZpZXMqIEAgbWVhbiBvZiBxdWFsaXR5XSANCiAgICAtIFRoaXMgaXMgYSAqKlNpbXBsZSBFZmZlY3QqKg0KDQojIyMjIEludGVyYWN0aW9uIE1vZGVsDQotIEludGVyY2VwdCA9IE1lYW4gb2YgUXVhbGl0eSBAIE1vdmllcyBbKnAqID0gSXMgdGhlIGludGVyY2VwdCBkaWZmZXJlbnQgZnJvbSAwXQ0KLSBRdWFsaXR5LkMgID0gUXVhbGl0eS5DIHNsb3BlIEAgTW92aWVzIA0KICAgIC0gVGhpcyBpcyBhICoqU2ltcGxlIFNsb3BlKiogWypwKiA9IElzIHNsb3BlIGRpZmZlcmVudCBmcm9tIDAgc2xvcGVdIA0KICAgICAgICAtIFRvIHByb3ZlIGl0IHdlIGNhbiBzZWUgaXQgbWF0Y2hlcyB0aGUgc2xvcGVzIGZyb20gb3VyICpNb3ZpZSBTZXQgT05MWSogTW9kZWwsICRiJD0gYHIgcm91bmQoTW9kZWwuTW92aWUkY29lZmZpY2llbnRzWzJdLDMpYA0KLSBMb2NhdGlvbkZUaGVhdHJlID0gVGhyZWF0cmUgZGlmZmVyZW5jZSBmcm9tIGludGVyY2VwdCBbKnAqID0gSXMgbWVhbiBvZiAqVGhlYXRyZSogZGlmZmVyZW50IGZyb20gbW92aWVzIEAgbWVhbiBvZiBxdWFsaXR5XQ0KICAgIC0gVGhpcyBpcyBhICoqU2ltcGxlIEVmZmVjdCoqDQotIFF1YWxpdHkuQzpMb2NhdGlvbkZUaGVhdHJlPSBzbG9wZSBkaWZmZXJlbmNlIGJldHdlZW4gKk1vdmllKiBhbmQgKlRoZWF0cmUqIFtwID0gSXMgdGhlIHNsb3BlIG9mIHF1YWxpdHkgQCBUaGVhdHJlIGRpZmZlcmVudCBmcm9tIHNsb3BlIGF0IF0NCiAgICAtIFRoaXMgaXMgYW4gKipJbnRlcmFjdGlvbioqDQogICAgICAgIC0gVG8gcHJvdmUgaXQgd2UgY2FuIHNlZSBpdCBtYXRjaGVzIHRoZSBzbG9wZXMgb2YgKlRoZWF0cmUgT25seSogLSAqTW92aWUgU2V0IE9OTFkqIE1vZGVsDQogICAgICAgICAgICAtICRiJD0gKGByIHJvdW5kKE1vZGVsLlRoZWF0cmUkY29lZmZpY2llbnRzWzJdLDMpYCAtICBgciByb3VuZChNb2RlbC5Nb3ZpZSRjb2VmZmljaWVudHNbMl0sMylgKSA9IGByIHJvdW5kKChNb2RlbC5UaGVhdHJlJGNvZWZmaWNpZW50c1syXS1Nb2RlbC5Nb3ZpZSRjb2VmZmljaWVudHNbMl0pLDMpYA0KICAgICAgICAgICAgDQotIElmIHlvdSB3YW50ZWQgdG8ga25vdyB0aGUgc2ltcGxlIHNsb3BlIG9mICpUaGVhdHJlIE9ubHkqIHlvdSB3b3VsZCBoYXZlIHRvIHJlbGV2ZWwgTG9jYXRpb24gYW5kIG1ha2UgVGhlYXRyZSA9IDAgKGkuZS4sIHRoZSByZWZlcmVuY2UpDQoNCmBgYHtyfQ0KRW1vdGlvbi5EYXRhLjMkTG9jYXRpb25UPC0gcmVsZXZlbChFbW90aW9uLkRhdGEuMyRMb2NhdGlvbkYsIHJlZiA9ICJUaGVhdHJlIikNCk1vZGVsLkUzLjIuUmVMZXZlbDwtbG0oRW1vdGlvbiB+IFF1YWxpdHkuQypMb2NhdGlvblQsIGRhdGEgPSBFbW90aW9uLkRhdGEuMykNCmBgYA0KICAgDQpgYGB7ciwgZWNobz1GQUxTRSxyZXN1bHRzPSdhc2lzJ30NCnN0YXJnYXplcihNb2RlbC5FMy4yLlJlTGV2ZWwsdHlwZT0iaHRtbCIsDQogICAgICAgICAgY29sdW1uLmxhYmVscyA9IGMoIlRoZWF0cmUgaXMgUmVmIiksDQogICAgICAgICAgaW50ZXJjZXB0LmJvdHRvbSA9IEZBTFNFLA0KICAgICAgICAgIHNpbmdsZS5yb3c9VFJVRSwgIG5vdGVzLmFwcGVuZCA9IEZBTFNFLA0KICAgICAgICAgIG9taXQuc3RhdD1jKCJzZXIiKSwNCiAgICAgICAgICBzdGFyLmN1dG9mZnMgPSBjKDAuMDUsIDAuMDEsIDAuMDAxKSwNCiAgICAgICAgICBoZWFkZXI9RkFMU0UpDQpgYGAgICANCg0KLSBZb3Ugd2lsbCBub3RpY2UgdGhlIGludGVyYWN0aW9uIGZsaXBwZWQgZGlyZWN0aW9uIGFuZCBub3cgdGhlIFF1YWxpdHkuQyBjb2VmZmljaWVudCAkYiQgPSBgciByb3VuZChNb2RlbC5FMy4yLlJlTGV2ZWwkY29lZmZpY2llbnRzWzJdLDMpYCA9ICB0aGUgKlRoZWF0cmUgT25seSogbW9kZWwgJGIkID0gYHIgcm91bmQoTW9kZWwuVGhlYXRyZSRjb2VmZmljaWVudHNbMl0sMylgICAgICAgICAgICANCg0KIyMjIFBsb3R0aW5nIEludGVyYWN0aW9uDQotIE9mdGVuIHRpbWVzIHlvdSB3aWxsIG5lZWQgdG8gdXNlIHRoZSBlZmZlY3RzIHBhY2thZ2UgYW5kIHBsb3QgYnkgaGFuZA0KLSBUaGUgcm9ja2NoYWxrIHBhY2thZ2Ugd2lsbCB3b3JrIGZvciBzaW1wbGUgbW9kZWxzIGxpa2UgdGhpcyBvbmUNCg0KYGBge3J9DQpsaWJyYXJ5KHJvY2tjaGFsaykNCnBsb3RTbG9wZXMoTW9kZWwuRTMuMiwgcGxvdHggPSAiUXVhbGl0eS5DIiwgbW9keCA9ICJMb2NhdGlvbkYiKQ0KYGBgDQoNCiMjIERldmlhdGlvbiBjb2Rpbmcgb2Ygb3VyIG5vbWluYWwgdmFyaWFibGUNCi0gV2Ugd2lsbCBzdGlsbCBjZW50ZXIgcXVhbGl0eQ0KLSBUaGlzIGNyZWF0ZXMgYSBtb3JlIEFOT1ZBIGxpa2UgaW50ZXJwcmV0YXRpb24gb2YgdGhlIGludGVyYWN0aW9uIA0KYGBge3IsIGVjaG89VFJVRSwgd2FybmluZz1GQUxTRX0NCkVtb3Rpb24uRGF0YS4zJExvY2F0aW9uRCA8LSBmYWN0b3IoRW1vdGlvbi5EYXRhLjMkTG9jYXRpb24sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVsPWMoMSwwKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzPWMoIlRoZWF0cmUiLCJNb3ZpZSBTZXQiKSkNCk1vZGVsLkUzLkQxPC1sbShFbW90aW9uIH4gUXVhbGl0eS5DK0xvY2F0aW9uRCwgZGF0YSA9IEVtb3Rpb24uRGF0YS4zLA0KICAgICAgICAgICAgICAgICBjb250cmFzdHM9bGlzdChMb2NhdGlvbkQ9Y29udHIuc3VtKDIpKSkNCk1vZGVsLkUzLkQyPC1sbShFbW90aW9uIH4gUXVhbGl0eS5DKkxvY2F0aW9uRCwgZGF0YSA9IEVtb3Rpb24uRGF0YS4zLA0KICAgICAgICAgICAgICAgICBjb250cmFzdHM9bGlzdChMb2NhdGlvbkQ9Y29udHIuc3VtKDIpKSkNCmBgYA0KDQojIyMgSW50ZXJwcmV0IFJlZ3Jlc3Npb24NCg0KYGBge3IsIGVjaG89RkFMU0UsIHJlc3VsdHM9J2FzaXMnfQ0Kc3RhcmdhemVyKE1vZGVsLkUzLkQxLE1vZGVsLkUzLkQyLHR5cGU9Imh0bWwiLA0KICAgICAgICAgIGNvbHVtbi5sYWJlbHMgPSBjKCJNYWluIEVmZmVjdHMiLCAiSW50ZXJhY3Rpb24iKSwNCiAgICAgICAgICBpbnRlcmNlcHQuYm90dG9tID0gRkFMU0UsDQogICAgICAgICAgc2luZ2xlLnJvdz1UUlVFLG5vdGVzLmFwcGVuZCA9IEZBTFNFLCAgb21pdC5zdGF0PWMoInNlciIpLA0KICAgICAgICAgIHN0YXIuY3V0b2ZmcyA9IGMoMC4wNSwgMC4wMSwgMC4wMDEpLA0KICAgICAgICAgIGhlYWRlcj1GQUxTRSkNCmBgYA0KDQoNCiMjIyBNYWluIEVmZmVjdHMNCg0KIyMjIyBDb2VmZmljaWVudHMgJiBQdmFsdWVzDQotIEludGVyY2VwdCA9IE1lYW4gb2YgUXVhbGl0eSBAIG1lYW4gb2YgTW92aWUgJiBUaGVhdHJlIChpbWFnaW5hcnkpIFtwID0gSXMgdGhlIGludGVyY2VwdCBkaWZmZXJlbnQgZnJvbSAwXQ0KLSBRdWFsaXR5LkMgID0gUXVhbGl0eS5DIHNsb3BlIFtwID0gSXMgc2xvcGUgZGlmZmVyZW50IGZyb20gMF0NCi0gTG9jYXRpb25GVGhlYXRyZSA9IFRocmVhdHJlIGRpZmZlcmVuY2UgZnJvbSAwIChub3QgLSAxKSB0aHVzIGlzIDEvMiB0aGUgc2xvcGUgb2YgdGhlIGR1bW15IGNvZGUgW3AgPSBJcyBtZWFuIG9mIFRoZWF0cmUgZGlmZmVyZW50IGZyb20gbW92aWVzIEAgbWVhbiBvZiBxdWFsaXR5XQ0KDQojIyMgSW50ZXJhY3Rpb25zDQojIyMjIENvZWZmaWNpZW50cyAmIFB2YWx1ZXMgDQotIEludGVyY2VwdCA9IE1lYW4gb2YgUXVhbGl0eSBAIG1lYW4gb2YgTW92aWUgJiBUaGVhdHJlIChpbWFnaW5hcnkpIFtwID0gSXMgdGhlIGludGVyY2VwdCBkaWZmZXJlbnQgZnJvbSAwXQ0KLSBRdWFsaXR5LkMgID0gUXVhbGl0eS5DIHNsb3BlIEAgbWVhbiBvZiBNb3ZpZSAmIFRoZWF0cmUgKGltYWdpbmFyeSkgW3AgPSBJcyB0aGUgTWFpbiBlZmZlY3Qgb2YgcXVhbGl0eSBAIG1lYW4gb2YgTW92aWUgJiBUaGVhdHJlXQ0KLSBMb2NhdGlvbkZUaGVhdHJlID0gVGhyZWF0cmUgZGlmZmVyZW5jZSBmcm9tIGludGVyY2VwdCBbKnAqID0gSXMgdGhlIE1haW4gZWZmZWN0IG9mIExvY2F0aW9uIEAgbWVhbiBvZiBxdWFsaXR5XQ0KLSBRdWFsaXR5LkM6TG9jYXRpb25GVGhlYXRyZT0gUXVhbGl0eS5DIHNsb3BlIGRpZmZlcmVuY2UgYmV0d2VlbiBNb3ZpZSBhbmQgdGhlYXRyZSBbKnAqID0gSXMgdGhlIGludGVyYWN0aW9uXQ0KLSBOb3RlIGFsbCBjb2VmZmljaWVudHMgYXJlIDEvMiBvZiB0aGUgc2l6ZSB0aGV5IHNob3VsZCBiZSEgDQogDQogDQojIyBTaW1wbGUgY29kaW5nIG9mIG91ciBub21pbmFsIHZhcmlhYmxlDQotIFdlIHdpbGwgc3RpbGwgY2VudGVyIHF1YWxpdHkNCi0gVGhpcyBjcmVhdGVzIGEgbW9yZSBBTk9WQS1saWtlIGludGVycHJldGF0aW9uIG9mIHRoZSBpbnRlcmFjdGlvbiwNCiAgICAtIE1vc3QgaW1wb3J0YW50bHkgaXQgZG9lcyBub3Qgc2NyZXcgdXAgb3VyIGNvZWZmaWNpZW50cyBhcyB0aGV5IG1hdGNoIHRoZSBkdW1teSBjb2RlIHZhbHVlcyAod2hpY2ggbWFrZSB0aGUgbW9zdCBzZW5zZSkNCi0gVGhpcyB0aW1lIEkgd2lsbCBoYW5kIGNvZGUgaXQgaW50byBhIGZhY3RvciAoZWFzeSB3aXRoIG9ubHkgMiBsZXZlbHMpDQoNCmBgYHtyfQ0KRW1vdGlvbi5EYXRhLjMkTG9jYXRpb25TPC1hcy5udW1lcmljKEVtb3Rpb24uRGF0YS4zJExvY2F0aW9uKS0uNQ0KTW9kZWwuRTMuUzE8LWxtKEVtb3Rpb24gfiBRdWFsaXR5LkMrTG9jYXRpb25TLCBkYXRhID0gRW1vdGlvbi5EYXRhLjMpDQpNb2RlbC5FMy5TMjwtbG0oRW1vdGlvbiB+IFF1YWxpdHkuQypMb2NhdGlvblMsIGRhdGEgPSBFbW90aW9uLkRhdGEuMykNCmBgYA0KDQojIyMgSW50ZXJwcmV0IFJlZ3Jlc3Npb24NCg0KYGBge3IsIGVjaG89RkFMU0UscmVzdWx0cz0nYXNpcyd9DQpzdGFyZ2F6ZXIoTW9kZWwuRTMuUzEsTW9kZWwuRTMuUzIsdHlwZT0iaHRtbCIsDQogICAgICAgICAgY29sdW1uLmxhYmVscyA9IGMoIk1haW4gRWZmZWN0cyIsICJJbnRlcmFjdGlvbiIpLA0KICAgICAgICAgIGludGVyY2VwdC5ib3R0b20gPSBGQUxTRSwNCiAgICAgICAgICBzaW5nbGUucm93PVRSVUUsIA0KICAgICAgICAgIG5vdGVzLmFwcGVuZCA9IEZBTFNFLA0KICAgICAgICAgIG9taXQuc3RhdD1jKCJzZXIiKSwNCiAgICAgICAgICBzdGFyLmN1dG9mZnMgPSBjKDAuMDUsIDAuMDEsIDAuMDAxKSwNCiAgICAgICAgICBoZWFkZXI9RkFMU0UpDQpgYGANCg0KDQojIyMgTWFpbiBFZmZlY3RzDQoNCiMjIyMgQ29lZmZpY2llbnRzICYgUHZhbHVlcw0KLSBJbnRlcmNlcHQgPSBNZWFuIG9mIFF1YWxpdHkgQCBtZWFuIG9mIE1vdmllICYgVGhlYXRyZSAoaW1hZ2luYXJ5IHRoaW5nKSBbcCA9IElzIHRoZSBpbnRlcmNlcHQgZGlmZmVyZW50IGZyb20gMF0NCi0gUXVhbGl0eS5DICA9IFF1YWxpdHkuQyBzbG9wZSBbcCA9IElzIHNsb3BlIGRpZmZlcmVudCBmcm9tIDBdDQotIExvY2F0aW9uRlRoZWF0cmUgPSBUaHJlYXRyZSBkaWZmZXJlbmNlIGZyb20gMCBbcCA9IElzIG1lYW4gb2YgVGhlYXRyZSBkaWZmZXJlbnQgZnJvbSBtb3ZpZXMgQCBtZWFuIG9mIHF1YWxpdHldDQoNCiMjIyBJbnRlcmFjdGlvbnMNCg0KIyMjIyBDb2VmZmljaWVudHMgJiBQdmFsdWVzIA0KLSBJbnRlcmNlcHQgPSBNZWFuIG9mIFF1YWxpdHkgQCBtZWFuIG9mIE1vdmllICYgVGhlYXRyZSAoaW1hZ2luYXJ5IHRoaW5nKSBbcCA9IElzIHRoZSBpbnRlcmNlcHQgZGlmZmVyZW50IGZyb20gMF0NCi0gUXVhbGl0eS5DICA9IFF1YWxpdHkuQyBzbG9wZSBAIG1lYW4gb2YgTW92aWUgJiBUaGVhdHJlIChpbWFnaW5hcnkgdGhpbmcpIFtwID0gSXMgdGhlIE1haW4gZWZmZWN0IG9mIHF1YWxpdHkgQCBtZWFuIG9mIE1vdmllICYgVGhlYXRyZV0NCi0gTG9jYXRpb25TID0gVGhyZWF0cmUgZGlmZmVyZW5jZSBmcm9tIGludGVyY2VwdCBbcCA9IElzIHRoZSBNYWluIGVmZmVjdCBvZiBMb2NhdGlvbiBAIG1lYW4gb2YgcXVhbGl0eV0NCi0gUXVhbGl0eS5DOkxvY2F0aW9uUz0gUXVhbGl0eS5DIHNsb3BlIGRpZmZlcmVuY2UgYmV0d2VlbiBNb3ZpZSBhbmQgdGhlYXRyZSBbcCA9IElzIHRoZWlyIGFuIGludGVyYWN0aW9uXQ0KLSBOb3RlIGFsbCBjb2VmZmljaWVudHMgYXJlIHRoZWlyIHByb3BlciBzaXplIG5vdyAodG8gbWF0Y2ggdHJ1ZSBkaWZmZXJlbmNlcykNCi0gQmVzdCBvcHRpb24gaXMgb2Z0ZW4gZHVtbXkgb3Igc2ltcGxlLCBkZXZpYXRpb24gaGVyZSBpcyB3ZWlyZCANCg0K