Note: Much the code used to generate the results
seen to today appears in the rmd file, but not in here. You can dowload
the rmd file to see the code, you will see echo=FALSE
,
which hides the code.
Crossed Designs
- The simplest design is 1 factor (2 levels) where each person
responds to both levels (1 time)
- For example, everyone sees 1 stimulus and is told that person is A)
friend and B) Foe
These are analyzed typically as paired samples t-test
A more complex design is 1 factor (2 levels) where each person
responds to both levels (A & B) but with multiple stimuli (to test
multiple trials):
Fully Crossed Design - As above, all subjects
see all experimental conditions (A & B) and stimuli (1 &
2)
What if we have order effects? There are lots of
solutions:
Counterbalanced Designs - As above, all subjects
saw all experimental conditions (A & B), and stimuli (1 & 2) but
balanced across condition (the idea is that when we take means across
our stimuli carryover washout)
Classical Solutions
- As designs get more and more complex (more conditions, more stimuli,
repeated trials of stimuli within conditions), we have to be careful
about how we design studies so we can track condition vs stimuli
effects
- The main problem is that subject scores tend to correlate with
themselves (which is the whole point of repeated designs), but they also
tend to change over repeated trials (fatigue, boredom, order effects,
etc)
- In GLM (ANOVA/t-tests) we simply averaged over stimuli because most
of us were taught to use a Latin squares designs (balanced type of
counterbalancing) to average out all these problems
- Now it seems because of the ease of randomizing trials, often
researchers just prefer to run lot of random trials in random orders
hoping things will wash out
- Randomization is not a subsite for counterbalancing simply because
you cannot “know” what is causing the variance.
Mixed Models Solutions
- Mixed models allow for you to start to deal with more complex
designs and track order effects or other issues
- To benefit from these statistics you need to start collecting
multiple trials, stimuli or both!
- You also open up more designs, as we can start to control for
stimuli (or trial order effects)
Stimuli-within-condition design - As above,
all subjects see all experimental conditions (A & B), and stimuli (1
& 2) but stimuli are nested into condition. You will have carry-over
effects, but you can have stimuli level random effects
1 |
A |
A |
B |
B |
2 |
A |
A |
B |
B |
3 |
B |
B |
A |
A |
4 |
B |
B |
A |
A |
- We will return to item/stimuli/trial effects in a few weeks. today
we will focus on first step of dealing with repeated measure data
See Westfall, Kenny, & Judd, 2014 for a more detailed
explanation and for discussion about power for mixed models. I have
summarized the some of the designs of interest they talk about
1 Factor: 2 Level Designs
- Normally we collect 1 trial per condition and test between the
means, or we collect multiple trials and average between trials and run
the paired sample t-test above
- Let’s run a simulation of that kind of study
- Also, we must assume a specific covariance matrix, where, \(\sigma^2 = 4\)
\[
\mathbf{Cov} = \sigma^2\left[\begin{array}
{rrr}
1 & .4 \\
.4 & 1 \\
\end{array}\right]
\]
- We will set \(n\) = 12, \(r\) =.4, \(M_1\) = 2 and \(M_2\) = 4, \(\sigma^2\) = 4
set.seed(666)
library(tidyr)
library(dplyr)
library(MASS)
n = 12 ; r = .4 ; M1=2; M2=4; S2=4
# Generate Cov matrix
SigmaMatrix<-matrix(c(1,r,
r,1), nrow=2, ncol=2)*S2
DataSim1 = mvrnorm(n=n, mu=c(M1, M2), Sigma=SigmaMatrix, empirical=TRUE)
colnames(DataSim1) <- c("None","Some")
DataSim1<-gather(data.frame(DataSim1),key = "Chocolate", value = "Attention")
DataSim1$SS<-as.factor(rep(seq(1:n),2))
Plot of Simulation 1
Paired t-test
T1<-t.test(Attention~Chocolate, paired=TRUE,DataSim1)
library(apa)
cat(apa(T1, format = "rmarkdown", print = FALSE))
t(11) = -3.16, p = .009, d = -0.91
- Note: t-test in R does M1-M2 (so it reported it negative),
- Also, our \(r\) = .4 between None
and Some Chocolate, had we set it to zero, this paired test would be
equal to a between-subjects t-test [in a perfect world (with no
variance) \(r\) = 1]
Mixed: Random Intercepts
- We can mirror this result using our mixed regression
- In this case, to match the paired-sample t-test, we need to let the
intercept vary per subject
library(lme4)
Model.1<-lmer(Attention~Chocolate
+(1|SS),
data=DataSim1, REML=FALSE)
summary(Model.1, correlation=FALSE)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
## method [lmerModLmerTest]
## Formula: Attention ~ Chocolate + (1 | SS)
## Data: DataSim1
##
## AIC BIC logLik deviance df.resid
## 105.2 109.9 -48.6 97.2 20
##
## Scaled residuals:
## Min 1Q Median 3Q Max
## -2.00520 -0.55683 0.02367 0.75042 1.38076
##
## Random effects:
## Groups Name Variance Std.Dev.
## SS (Intercept) 1.467 1.211
## Residual 2.200 1.483
## Number of obs: 24, groups: SS, 12
##
## Fixed effects:
## Estimate Std. Error df t value Pr(>|t|)
## (Intercept) 2.0000 0.5528 20.6897 3.618 0.00164 **
## ChocolateSome 2.0000 0.6055 12.0000 3.303 0.00631 **
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
- You will notice that the t-values pretty much match
- The model is removing the intercept differences between the
subjects
- We can plot the prediction of the model per person for both fixed +
random and fixed alone
DataSim1$FR<-predict(Model.1) #Fixed + random
DataSim1$Fixed<-predict(Model.1,re.form=NA) # Fixed only
- You will notice that we did not account for the random slopes
Rm.t.test.plot <-ggplot(data = DataSim1, aes(x = Chocolate, y=Attention,group=SS))+
facet_wrap(~SS)+
geom_point(aes(colour = SS))+
geom_smooth(method = "lm", se = FALSE, aes(group=SS,colour = SS))+
ylab("Attention")+xlab("Chocolate")+
theme(legend.position = "none")
Rm.t.test.plot
- Its clear that each subject is affected by Chocolate in a different
way, so we should try to account for the slope differences - We did with
this school in MLM, so we must be able to do it here!
Model.1a<-lmer(Attention~Chocolate
+(1+Chocolate|SS),
data=DataSim1, REML=FALSE)
Error: number of observations (=24) <= number of random
effects (=24) for term (1 + Chocolate | SS); the random-effects
parameters and the residual variance (or scale parameter) are probably
unidentifiable
- What is this crazy message? Well, it’s telling us we are trying we
cannot do this. Why?
- Well, how variance do you have round the estimate of the slope do
you have per subject?
- How can you estimate any variance around the slope if you have only
1 slope per subject?
- You need to have multiple estimates per subject per condition!
- The more trials we have per subject, the better estimate of the
slope and we can calculate the variance around that slope!
Mixed: Random Intercepts & Slopes
- Let’s add more trials per condition: Simulation 2
- However, things get more complicated
- How much measurement error is there when re-measurement of the same
condition per subject?
- Could that value differ per trial or condition?
- Is it the same stimulus or a new one?
- Could the new stimulus be having an effect?
- We will assume a repeat of the same stimulus per condition
- What is the variance of each condition?
- They can differ (ANOVA assumptions say they cannot)
- If we did have multiple stimuli per condition could they vary as a
function of the condition?
- To understand all the levels of variance let’s simulate the
chocolate study with 4 trials of two conditions:
Simulation 2a: No Variance
- We will set \(n\) = 4, Trials=4,
\(r\) = .6, \(M_1\) = 2 and \(M_2\) = 4, \(\sigma^2_{M1}\) = 0, \(\sigma^2_{M2}\) = 0, \(\sigma^2_{measurement}\) = 0
Simulation 2b: Measurement Error
- We will set \(n\) = 4, Trials=4,
\(r\) = .6, \(M_1\) = 2 and \(M_2\) = 4, \(\sigma^2_{M1}\) = 0, \(\sigma^2_{M2}\) = 0, \(\sigma^2_{measurement}\) = 4
Simulation 2c: Intercept Variance
- We will set \(n\) = 4, Trials=4,
\(r\) = NA, \(M_1\) = 2 and \(M_2\) = 4, \(\sigma^2_{M1}\) = 4, \(\sigma^2_{M2}\) = 0, \(\sigma^2_{measurement}\) = 0
Simulation 2d: Slope Variance
- We will set \(n\) = 4, Trials=4,
\(r\) = NA, \(M_1\) = 2 and \(M_2\) = 4, \(\sigma^2_{M1}\) = 0, \(\sigma^2_{M2}\) = 4, \(\sigma^2_{measurement}\) = 0
Simulation 2e: Intercept + Slope Variance
- We will set \(n\) = 4, Trials=4,
\(r\) = NA, \(M_1\) = 2 and \(M_2\) = 4, \(\sigma^2_{M1}\) = 4, \(\sigma^2_{M2}\) = 4, \(\sigma^2_{measurement}\) = 0
Simulation 2f: Intercept + Slope Variance + Measurement Noise
- We will set \(n\) = 4, Trials=4,
\(r\) = .6, \(M_1\) = 2 and \(M_2\) = 4, \(\sigma^2_{M1}\) = 4, \(\sigma^2_{M2}\) = 4, \(\sigma^2_{measurement}\) = 4
Simulation 2g: Fitting Mixed Model
We will set \(n\) = 12,
Trials=4, \(r\) = .6, \(M_1\) = 2 and \(M_2\) = 4, \(\sigma^2_{M1}\) = 4, \(\sigma^2_{M2}\) = 4, \(\sigma^2_{measurement}\) = 4
Spaghetti plot
Test Random Intercepts & Slopes
- Model 2a: Random intercepts
- Model 2b: Random intercepts & Slopes (correlated)
Model.2a<-lmer(Attention~Chocolate
+(1|SS),
data=DataSim2g, REML=FALSE)
Model.2b<-lmer(Attention~Chocolate
+(1+Chocolate|SS),
data=DataSim2g, REML=FALSE)
<!DOCTYPE html>
|
Model 1
|
Model 2
|
(Intercept)
|
2.17 (1.03)*
|
2.17 (0.75)**
|
ChocolateSome
|
4.67 (0.53)***
|
4.67 (0.99)***
|
AIC
|
494.75
|
467.40
|
BIC
|
505.01
|
482.78
|
Log Likelihood
|
-243.38
|
-227.70
|
Num. obs.
|
96
|
96
|
Num. groups: SS
|
12
|
12
|
Var: SS (Intercept)
|
11.03
|
5.75
|
Var: Residual
|
6.69
|
3.90
|
Var: SS ChocolateSome
|
|
9.76
|
Cov: SS (Intercept) ChocolateSome
|
|
3.19
|
***p < 0.001; **p < 0.01; *p <
0.05
|
Test Random Slope
- Just as we did in MLM, we will test to see if the random slope
improves the fit,
anova(Model.2a,Model.2b)
|
npar
|
AIC
|
BIC
|
logLik
|
deviance
|
Chisq
|
Df
|
Pr(>Chisq)
|
Model.2a
|
4
|
494.7545
|
505.0119
|
-243.3772
|
486.7545
|
NA
|
NA
|
NA
|
Model.2b
|
6
|
467.3984
|
482.7845
|
-227.6992
|
455.3984
|
31.35608
|
2
|
2e-07
|
Plot Predicted Results
DataSim2g$FRa<-predict(Model.2a) #Fixed + random
DataSim2g$FRb<-predict(Model.2b) #Fixed + random
Notes
- Watch the correlation between them random slopes and intercept
carefully (make sure they are not correlated at 1)
- The more trials, the better and the more stable from measurement to
measurement the better
- The stronger the correlation between experimental condition the
higher your power will be
2 Factors: 2 X 3 Level Designs
- Not only do we have to deal with all the parameters we had before,
but we would also have understood the correlations within subjects
across factors
- The question for today is how to deal with a factor that has 3
levels
- Examine this I heavily manipulated data from my paper (Demos &
Chaffin, in press)
- Listeners were asked to listen (and move their bodies) relative to
recorded solo trombone music played by 2 different performers at 3
levels of expression. As part of the study, they were asked to report
how expressive they though the music was. Note: I have simplified
the design and edited the data: thus, results will not match the
paper.
- We will assume a fully crossed design where every
subject heard each performer play at each expressive level, 2 times.
\(n\) = 16, Ratings were 1-6 on
expression.
- Read in the data:
MP.Data<-read.csv("Mixed/MusicPerception.csv")
MP.Data$Perf<-factor(MP.Data$Performer,
levels=c(0,1),
labels=c("M1","M2"))
MP.Data$Level<-factor(MP.Data$Condition,
levels=c(0,1,2),
labels=c("Normal","Exp","Non-Exp"))
MP.Data$SS<-as.factor(MP.Data$SS)
Plot Study
This is categorical data, so can do box plots/violin plots
[helpful for when we want to see the variance]
We can also try to our spaghetti plots in different ways
Random Categorical Factor
- Let’s treat the data as categorical
- We will examine Level as a fixed and random effects only
First
M0<-lmer(Rating~ Level+ (1|SS), data=MP.Data, REML=TRUE)
M1<-lmer(Rating~ Level+ (1+Level|SS), data=MP.Data, REML=TRUE)
summary(M1, correlation=FALSE)
## Linear mixed model fit by REML. t-tests use Satterthwaite's method [
## lmerModLmerTest]
## Formula: Rating ~ Level + (1 + Level | SS)
## Data: MP.Data
##
## REML criterion at convergence: 554.2
##
## Scaled residuals:
## Min 1Q Median 3Q Max
## -2.69937 -0.64286 -0.01363 0.54687 2.36725
##
## Random effects:
## Groups Name Variance Std.Dev. Corr
## SS (Intercept) 0.1043 0.3229
## LevelExp 0.1559 0.3949 -0.90
## LevelNon-Exp 0.2758 0.5251 -0.01 0.45
## Residual 0.9235 0.9610
## Number of obs: 192, groups: SS, 16
##
## Fixed effects:
## Estimate Std. Error df t value Pr(>|t|)
## (Intercept) 3.5000 0.1447 16.6830 24.182 2.01e-14 ***
## LevelExp 1.1406 0.1965 16.9206 5.805 2.15e-05 ***
## LevelNon-Exp -0.7656 0.2147 17.1144 -3.566 0.00236 **
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## optimizer (nloptwrap) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
- Let’s examine the random effects in more detail:
Rm1<-ranef(M1)
(Intercept)
|
LevelExp
|
LevelNon-Exp
|
0.1783985
|
-0.1029686
|
0.2792666
|
-0.0360456
|
-0.1430073
|
-0.5537304
|
-0.2549083
|
0.1466367
|
-0.4005292
|
0.0118790
|
-0.0201604
|
-0.0217933
|
-0.1354541
|
-0.0456614
|
-0.5880064
|
-0.0212470
|
-0.0207507
|
-0.1334851
|
- The random intercept now represents random effect at Level = Normal
for each subject and the differences for the other conditions
Plot Predicted Results
MP.Data$FRa<-predict(M0) #Fixed + random
MP.Data$FRb<-predict(M1) #Fixed + random
- This captured the differences between Levels, but we still
have to work on the other factor to deal with
- Let’s add fixed and random effect of Performer
2 Random Categorical Factors
M2<-lmer(Rating~ Level+Perf+ (1+Level|SS), data=MP.Data, REML=TRUE)
M3<-lmer(Rating~ Level+Perf+ (1+Level+Perf|SS), data=MP.Data, REML=TRUE)
summary(M3, correlation=FALSE)
## Linear mixed model fit by REML. t-tests use Satterthwaite's method [
## lmerModLmerTest]
## Formula: Rating ~ Level + Perf + (1 + Level + Perf | SS)
## Data: MP.Data
##
## REML criterion at convergence: 553.1
##
## Scaled residuals:
## Min 1Q Median 3Q Max
## -2.70103 -0.60603 -0.06199 0.52791 2.32239
##
## Random effects:
## Groups Name Variance Std.Dev. Corr
## SS (Intercept) 0.1552 0.3939
## LevelExp 0.1759 0.4195 -0.98
## LevelNon-Exp 0.2814 0.5304 -0.39 0.47
## PerfM2 0.1227 0.3503 -0.55 0.51 0.82
## Residual 0.8894 0.9431
## Number of obs: 192, groups: SS, 16
##
## Fixed effects:
## Estimate Std. Error df t value Pr(>|t|)
## (Intercept) 3.4375 0.1680 16.3744 20.461 4.31e-13 ***
## LevelExp 1.1406 0.1970 16.9756 5.791 2.18e-05 ***
## LevelNon-Exp -0.7656 0.2130 16.7482 -3.594 0.00228 **
## PerfM2 0.1250 0.1619 15.1948 0.772 0.45178
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## optimizer (nloptwrap) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
- Let’s examine the random effects in more detail (shortened
version):
R.M3<-ranef(M3)
(Intercept)
|
LevelExp
|
LevelNon-Exp
|
PerfM2
|
0.3110008
|
-0.2768702
|
0.0644461
|
-0.1089660
|
0.0061816
|
-0.0635005
|
-0.4362016
|
-0.1603991
|
-0.0384346
|
0.0356336
|
-0.5536842
|
-0.3538819
|
0.1269346
|
-0.1172792
|
-0.1440845
|
-0.1483003
|
-0.0295522
|
-0.0151833
|
-0.5375279
|
-0.2485711
|
-0.0887203
|
0.0674438
|
-0.0170347
|
0.0585761
|
Plot Predicted Results
MP.Data$FRc<-predict(M2) #Fixed + random
MP.Data$FRd<-predict(M3) #Fixed + random
- This captured the differences between Levels and
Performer, but is it possible that they interact?
- Let’s add fixed and random effect of interaction
2 Random Categorical Factors Interacted
M4<-lmer(Rating~ Level*Perf+ (1+Level+Perf|SS), data=MP.Data, REML=TRUE)
M5<-lmer(Rating~ Level*Perf+ (1+Level*Perf|SS), data=MP.Data, REML=TRUE)
summary(M5)
## Linear mixed model fit by REML. t-tests use Satterthwaite's method [
## lmerModLmerTest]
## Formula: Rating ~ Level * Perf + (1 + Level * Perf | SS)
## Data: MP.Data
##
## REML criterion at convergence: 509.2
##
## Scaled residuals:
## Min 1Q Median 3Q Max
## -2.5652 -0.6345 0.1111 0.5689 2.7334
##
## Random effects:
## Groups Name Variance Std.Dev. Corr
## SS (Intercept) 0.6194 0.7870
## LevelExp 2.2437 1.4979 -0.99
## LevelNon-Exp 1.2875 1.1347 -0.69 0.75
## PerfM2 1.0747 1.0367 -0.84 0.85 0.92
## LevelExp:PerfM2 3.7986 1.9490 0.93 -0.97 -0.88 -0.91
## LevelNon-Exp:PerfM2 1.2807 1.1317 0.36 -0.46 -0.89 -0.64 0.66
## Residual 0.5699 0.7549
## Number of obs: 192, groups: SS, 16
##
## Fixed effects:
## Estimate Std. Error df t value Pr(>|t|)
## (Intercept) 3.7187 0.2377 15.0942 15.642 9.78e-11 ***
## LevelExp 0.6563 0.4193 15.0473 1.565 0.13838
## LevelNon-Exp -1.1250 0.3407 15.3179 -3.302 0.00473 **
## PerfM2 -0.4375 0.3206 15.5291 -1.365 0.19183
## LevelExp:PerfM2 0.9687 0.5556 15.1891 1.744 0.10140
## LevelNon-Exp:PerfM2 0.7187 0.3889 15.2653 1.848 0.08408 .
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Correlation of Fixed Effects:
## (Intr) LvlExp LvlN-E PerfM2 LE:PM2
## LevelExp -0.908
## LevelNn-Exp -0.695 0.679
## PerfM2 -0.797 0.743 0.783
## LvlExp:PrM2 0.810 -0.911 -0.740 -0.845
## LvlNn-E:PM2 0.410 -0.406 -0.806 -0.664 0.583
## optimizer (nloptwrap) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
- Let’s examine the random effects in more detail (shortened
version):
R.M5<-ranef(M5)
(Intercept)
|
LevelExp
|
LevelNon-Exp
|
PerfM2
|
LevelExp:PerfM2
|
LevelNon-Exp:PerfM2
|
-0.0925771
|
0.4910901
|
1.0818923
|
0.4822347
|
-1.2236641
|
-1.4530276
|
0.9465210
|
-2.0637509
|
-2.0927606
|
-1.5701238
|
3.2370158
|
2.0782845
|
-0.2187872
|
0.5661589
|
-0.3028806
|
-0.4769871
|
-0.4368355
|
0.0360365
|
0.1202466
|
-0.0866788
|
0.0818598
|
-0.1796201
|
-0.0362446
|
-0.3646549
|
0.1335468
|
-0.3095779
|
-0.8671259
|
-0.7380190
|
0.8022893
|
0.7472702
|
-0.0273855
|
-0.0785710
|
-0.2937242
|
-0.0511187
|
0.3036436
|
0.4865756
|
Plot Predicted Results
MP.Data$FRe<-predict(M4) #Fixed + random
MP.Data$FRf<-predict(M5) #Fixed + random
|
npar
|
AIC
|
BIC
|
logLik
|
deviance
|
Chisq
|
Df
|
Pr(>Chisq)
|
M0
|
5
|
564.8267
|
581.1142
|
-277.4134
|
554.8267
|
NA
|
NA
|
NA
|
M1
|
10
|
568.3399
|
600.9149
|
-274.1700
|
548.3399
|
6.4867941
|
5
|
0.2616889
|
M2
|
11
|
569.5206
|
605.3531
|
-273.7603
|
547.5206
|
0.8192972
|
1
|
0.3653857
|
M3
|
15
|
575.2012
|
624.0636
|
-272.6006
|
545.2012
|
2.3194254
|
4
|
0.6772346
|
M4
|
17
|
569.7327
|
625.1101
|
-267.8664
|
535.7327
|
9.4685068
|
2
|
0.0087890
|
M5
|
28
|
556.2594
|
647.4693
|
-250.1297
|
500.2594
|
35.4733040
|
11
|
0.0002070
|
- The models seem to support the conclusion that we should fully cross
the random effects and account for the random variance on both their
main effects and interactions, what Barr et al. 2013 call a
maximal random structure
- We will come back to this concept next week and talk in more details
about the process of fitting complex random structures
- We will also talk about how to do post-hoc testing
Notes:
- Note: The final model was 28 degrees of freedom, and I only had 16
subjects (but I had 192 observations)
- This a highly parameterized model given the small amount of data I
had.
- The final model had 15 random correlations between terms.
- You will rarely get a fit with such a complex model with such little
data
LS0tDQp0aXRsZTogJ1JlcGVhdGVkIEZhY3RvcnMnDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgY29kZV9kb3dubG9hZDogeWVzDQogICAgZm9udHNpemU6IDhwdA0KICAgIGhpZ2hsaWdodDogdGV4dG1hdGUNCiAgICBudW1iZXJfc2VjdGlvbnM6IG5vDQogICAgdGhlbWU6IGZsYXRseQ0KICAgIHRvYzogeWVzDQogICAgdG9jX2Zsb2F0Og0KICAgICAgY29sbGFwc2VkOiBubw0KLS0tDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGNhY2hlPVRSVUUpDQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpDQprbml0cjo6b3B0c19jaHVuayRzZXQobWVzc2FnZSA9IEZBTFNFKQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KHdhcm5pbmcgPSAgRkFMU0UpDQprbml0cjo6b3B0c19jaHVuayRzZXQoZmlnLndpZHRoPTQuMjUpDQprbml0cjo6b3B0c19jaHVuayRzZXQoZmlnLmhlaWdodD00LjApDQprbml0cjo6b3B0c19jaHVuayRzZXQoZmlnLmFsaWduPSdjZW50ZXInKSANCmtuaXRyOjpvcHRzX2NodW5rJHNldChyZXN1bHRzPSdob2xkJykgDQpgYGANCg0KKipOb3RlKio6IE11Y2ggdGhlIGNvZGUgdXNlZCB0byBnZW5lcmF0ZSB0aGUgcmVzdWx0cyBzZWVuIHRvIHRvZGF5IGFwcGVhcnMgaW4gdGhlIHJtZCBmaWxlLCBidXQgbm90IGluIGhlcmUuICBZb3UgY2FuIGRvd2xvYWQgdGhlIHJtZCBmaWxlIHRvIHNlZSB0aGUgY29kZSwgeW91IHdpbGwgc2VlIGBlY2hvPUZBTFNFYCwgd2hpY2ggaGlkZXMgdGhlIGNvZGUuIA0KDQojICBDcm9zc2VkIERlc2lnbnMNCi0gIFRoZSBzaW1wbGVzdCBkZXNpZ24gaXMgMSBmYWN0b3IgKDIgbGV2ZWxzKSB3aGVyZSBlYWNoIHBlcnNvbiByZXNwb25kcyB0byBib3RoIGxldmVscyAoMSB0aW1lKQ0KLSBGb3IgZXhhbXBsZSwgZXZlcnlvbmUgc2VlcyAxIHN0aW11bHVzIGFuZCBpcyB0b2xkIHRoYXQgcGVyc29uIGlzIEEpICBmcmllbmQgYW5kIEIpIEZvZQ0KDQpTdWJqZWN0IHwgU3RpbXVsaSAxDQotLS0tLS0tIHwgLS0tLS0tLQ0KMSAgICAgICB8IEFCDQoyICAgICAgIHwgQUINCg0KLSBUaGVzZSBhcmUgYW5hbHl6ZWQgdHlwaWNhbGx5IGFzIHBhaXJlZCBzYW1wbGVzIHQtdGVzdA0KDQotICBBIG1vcmUgY29tcGxleCBkZXNpZ24gaXMgMSBmYWN0b3IgKDIgbGV2ZWxzKSB3aGVyZSBlYWNoIHBlcnNvbiByZXNwb25kcyB0byBib3RoIGxldmVscyAoQSAmIEIpIGJ1dCB3aXRoIG11bHRpcGxlIHN0aW11bGkgKHRvIHRlc3QgbXVsdGlwbGUgdHJpYWxzKTogDQoNCi0gKipGdWxseSBDcm9zc2VkIERlc2lnbioqIC0gQXMgYWJvdmUsIGFsbCBzdWJqZWN0cyBzZWUgYWxsIGV4cGVyaW1lbnRhbCBjb25kaXRpb25zIChBICYgQikgYW5kIHN0aW11bGkgKDEgJiAyKSAgDQoNClN1YmplY3QgfCBTdGltdWxpIDF8IFN0aW11bGkgMg0KLS0tLS0tLSB8IC0tLS0tLS0tIHwgLS0tLS0tLS0NCjEgICAgICAgfCBBQiAgICAgICB8IEFCDQoyICAgICAgIHwgQUIgICAgICAgfCBBQg0KDQotIFdoYXQgaWYgd2UgaGF2ZSBvcmRlciBlZmZlY3RzPyBUaGVyZSBhcmUgbG90cyBvZiBzb2x1dGlvbnM6IA0KDQotICoqQ291bnRlcmJhbGFuY2VkIERlc2lnbnMqKiAtIEFzIGFib3ZlLCBhbGwgc3ViamVjdHMgc2F3IGFsbCBleHBlcmltZW50YWwgY29uZGl0aW9ucyAoQSAmIEIpLCBhbmQgc3RpbXVsaSAoMSAmIDIpIGJ1dCBiYWxhbmNlZCBhY3Jvc3MgY29uZGl0aW9uICh0aGUgaWRlYSBpcyB0aGF0IHdoZW4gd2UgdGFrZSBtZWFucyBhY3Jvc3Mgb3VyIHN0aW11bGkgY2FycnlvdmVyIHdhc2hvdXQpDQoNClN1YmplY3QgfCBTdGltdWxpIDF8IFN0aW11bGkgMg0KLS0tLS0tLSB8IC0tLS0tLS0tIHwgLS0tLS0tLS0NCjEgICAgICAgfCBBICAgICAgICB8IEINCjIgICAgICAgfCBCICAgICAgICB8IEENCg0KIyMgQ2xhc3NpY2FsIFNvbHV0aW9ucw0KLSBBcyBkZXNpZ25zIGdldCBtb3JlIGFuZCBtb3JlIGNvbXBsZXggKG1vcmUgY29uZGl0aW9ucywgbW9yZSBzdGltdWxpLCByZXBlYXRlZCB0cmlhbHMgb2Ygc3RpbXVsaSB3aXRoaW4gY29uZGl0aW9ucyksIHdlIGhhdmUgdG8gYmUgY2FyZWZ1bCBhYm91dCBob3cgd2UgZGVzaWduIHN0dWRpZXMgc28gd2UgY2FuIHRyYWNrIGNvbmRpdGlvbiB2cyBzdGltdWxpIGVmZmVjdHMNCi0gVGhlIG1haW4gcHJvYmxlbSBpcyB0aGF0IHN1YmplY3Qgc2NvcmVzIHRlbmQgdG8gY29ycmVsYXRlIHdpdGggdGhlbXNlbHZlcyAod2hpY2ggaXMgdGhlIHdob2xlIHBvaW50IG9mIHJlcGVhdGVkIGRlc2lnbnMpLCBidXQgdGhleSBhbHNvIHRlbmQgdG8gY2hhbmdlIG92ZXIgcmVwZWF0ZWQgdHJpYWxzIChmYXRpZ3VlLCBib3JlZG9tLCBvcmRlciBlZmZlY3RzLCBldGMpDQogICAgLSBJbiBHTE0gKEFOT1ZBL3QtdGVzdHMpIHdlIHNpbXBseSBhdmVyYWdlZCBvdmVyIHN0aW11bGkgYmVjYXVzZSBtb3N0IG9mIHVzIHdlcmUgdGF1Z2h0IHRvIHVzZSBhIExhdGluIHNxdWFyZXMgZGVzaWducyAoYmFsYW5jZWQgdHlwZSBvZiBjb3VudGVyYmFsYW5jaW5nKSB0byBhdmVyYWdlIG91dCBhbGwgdGhlc2UgcHJvYmxlbXMNCiAgICAtIE5vdyBpdCBzZWVtcyBiZWNhdXNlIG9mIHRoZSBlYXNlIG9mIHJhbmRvbWl6aW5nIHRyaWFscywgb2Z0ZW4gcmVzZWFyY2hlcnMganVzdCBwcmVmZXIgdG8gcnVuIGxvdCBvZiByYW5kb20gdHJpYWxzIGluIHJhbmRvbSBvcmRlcnMgaG9waW5nIHRoaW5ncyB3aWxsIHdhc2ggb3V0IA0KICAgIC0gUmFuZG9taXphdGlvbiBpcyBub3QgYSBzdWJzaXRlIGZvciBjb3VudGVyYmFsYW5jaW5nIHNpbXBseSBiZWNhdXNlIHlvdSBjYW5ub3QgImtub3ciIHdoYXQgaXMgY2F1c2luZyB0aGUgdmFyaWFuY2UuICAgDQoNCiMjIE1peGVkIE1vZGVscyBTb2x1dGlvbnMNCi0gTWl4ZWQgbW9kZWxzIGFsbG93IGZvciB5b3UgdG8gc3RhcnQgdG8gZGVhbCB3aXRoIG1vcmUgY29tcGxleCBkZXNpZ25zIGFuZCB0cmFjayBvcmRlciBlZmZlY3RzIG9yIG90aGVyIGlzc3Vlcw0KLSBUbyBiZW5lZml0IGZyb20gdGhlc2Ugc3RhdGlzdGljcyB5b3UgbmVlZCB0byBzdGFydCBjb2xsZWN0aW5nIG11bHRpcGxlIHRyaWFscywgc3RpbXVsaSBvciBib3RoIQ0KLSBZb3UgYWxzbyBvcGVuIHVwIG1vcmUgZGVzaWducywgYXMgd2UgY2FuIHN0YXJ0IHRvIGNvbnRyb2wgZm9yIHN0aW11bGkgKG9yIHRyaWFsIG9yZGVyIGVmZmVjdHMpIA0KDQo6ICoqU3RpbXVsaS13aXRoaW4tY29uZGl0aW9uIGRlc2lnbioqIC0gQXMgYWJvdmUsIGFsbCBzdWJqZWN0cyBzZWUgYWxsIGV4cGVyaW1lbnRhbCBjb25kaXRpb25zIChBICYgQiksIGFuZCBzdGltdWxpICgxICYgMikgYnV0IHN0aW11bGkgYXJlIG5lc3RlZCBpbnRvIGNvbmRpdGlvbi4gWW91IHdpbGwgaGF2ZSBjYXJyeS1vdmVyIGVmZmVjdHMsIGJ1dCB5b3UgY2FuIGhhdmUgc3RpbXVsaSBsZXZlbCByYW5kb20gZWZmZWN0cw0KDQpTdWJqZWN0IHwgU3RpbXVsaSAxfCBTdGltdWxpIDIgfCBTdGltdWxpIDMgfCBTdGltdWxpIDQNCi0tLS0tLS0gfCAtLS0tLS0tLSB8IC0tLS0tLS0tLSB8IC0tLS0tLS0tLSB8IC0tLS0tLS0tLSANCjEgICAgICAgfCBBICAgICAgICB8IEEgICAgICAgICB8IEIgICAgICAgICB8IEINCjIgICAgICAgfCBBICAgICAgICB8IEEgICAgICAgICB8IEIgICAgICAgICB8IEINCjMgICAgICAgfCBCICAgICAgICB8IEIgICAgICAgICB8IEEgICAgICAgICB8IEENCjQgICAgICAgfCBCICAgICAgICB8IEIgICAgICAgICB8IEEgICAgICAgICB8IEENCg0KLSBXZSB3aWxsIHJldHVybiB0byBpdGVtL3N0aW11bGkvdHJpYWwgZWZmZWN0cyBpbiBhIGZldyB3ZWVrcy4gdG9kYXkgd2Ugd2lsbCBmb2N1cyBvbiBmaXJzdCBzdGVwIG9mIGRlYWxpbmcgd2l0aCByZXBlYXRlZCBtZWFzdXJlIGRhdGENCg0KKlNlZSBXZXN0ZmFsbCwgS2VubnksICYgSnVkZCwgMjAxNCBmb3IgYSBtb3JlIGRldGFpbGVkIGV4cGxhbmF0aW9uIGFuZCBmb3IgZGlzY3Vzc2lvbiBhYm91dCBwb3dlciBmb3IgbWl4ZWQgbW9kZWxzLiBJIGhhdmUgc3VtbWFyaXplZCB0aGUgc29tZSBvZiB0aGUgZGVzaWducyBvZiBpbnRlcmVzdCB0aGV5IHRhbGsgYWJvdXQqDQoNCg0KIyMgQ29ycmVsYXRlZCBNZWFzdXJlcw0KLSBXaGVuIHN1YmplY3RzIHJlcGVhdCB0cmlhbHMgb3IgZG8gbXVsdGlwbGUgY29uZGl0aW9ucywgdGhlaXIgc2NvcmVzIHRlbmQgdG8gYmUgY29ycmVsYXRlZA0KICAgIC0gV2Ugd2FudCB0byBjb250cm9sIGZvciBpbmRpdmlkdWFsIHN1YmplY3QgdmFyaWFiaWxpdHkgDQogICAgLSBJbiB0aGUgZm9ybXVsYSBiZWxvdywgd2UgcmVtb3ZlIHRoZSBzaGFyZWQgdmFyaWFuY2UgZnJvbSB0aGUgc3RhbmRhcmQgZXJyb3IgYXMgbWVhc3VyZWQgYnkgUGVhcnNvbidzIHIgYmV0d2VlbiBjb25kaXRpb25zDQoNCiQkdCA9IFxmcmFje01fMS1NXzJ9e1xzcXJ0e1xmcmFje1NfMV4yICsgU18yXjJ9e259LVxmcmFjezJyU18xU18yfXtufX19JCQNCg0KIyAxIEZhY3RvcjogMiBMZXZlbCBEZXNpZ25zIA0KLSBOb3JtYWxseSB3ZSBjb2xsZWN0IDEgdHJpYWwgcGVyIGNvbmRpdGlvbiBhbmQgdGVzdCBiZXR3ZWVuIHRoZSBtZWFucywgb3Igd2UgY29sbGVjdCBtdWx0aXBsZSB0cmlhbHMgYW5kIGF2ZXJhZ2UgYmV0d2VlbiB0cmlhbHMgYW5kIHJ1biB0aGUgcGFpcmVkIHNhbXBsZSB0LXRlc3QgYWJvdmUNCi0gTGV0J3MgcnVuIGEgc2ltdWxhdGlvbiBvZiB0aGF0IGtpbmQgb2Ygc3R1ZHkNCi0gQWxzbywgd2UgbXVzdCBhc3N1bWUgYSBzcGVjaWZpYyBjb3ZhcmlhbmNlIG1hdHJpeCwgd2hlcmUsICRcc2lnbWFeMiA9IDQkDQoNCiQkDQpcbWF0aGJme0Nvdn0gPSBcc2lnbWFeMlxsZWZ0W1xiZWdpbnthcnJheX0NCiAgICAgICAgICB7cnJyfQ0KICAgICAgICAgIDEgJiAuNCAgXFwNCiAgICAgICAgICAuNCAmIDEgIFxcDQogICAgICAgICAgXGVuZHthcnJheX1ccmlnaHRdDQokJA0KDQotIFdlIHdpbGwgc2V0ICRuJCA9IDEyLCAkciQgPS40LCAkTV8xJCA9IDIgYW5kICRNXzIkID0gNCwgJFxzaWdtYV4yJCA9IDQNCg0KYGBge3J9DQpzZXQuc2VlZCg2NjYpDQpsaWJyYXJ5KHRpZHlyKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkoTUFTUykNCm4gPSAxMiA7IHIgPSAuNCA7IE0xPTI7IE0yPTQ7IFMyPTQNCiMgR2VuZXJhdGUgQ292IG1hdHJpeA0KU2lnbWFNYXRyaXg8LW1hdHJpeChjKDEsciwgDQogICAgICAgICAgICAgICAgICAgICAgciwxKSwgbnJvdz0yLCBuY29sPTIpKlMyDQoNCkRhdGFTaW0xID0gbXZybm9ybShuPW4sIG11PWMoTTEsIE0yKSwgU2lnbWE9U2lnbWFNYXRyaXgsIGVtcGlyaWNhbD1UUlVFKQ0KY29sbmFtZXMoRGF0YVNpbTEpIDwtIGMoIk5vbmUiLCJTb21lIikNCkRhdGFTaW0xPC1nYXRoZXIoZGF0YS5mcmFtZShEYXRhU2ltMSksa2V5ID0gIkNob2NvbGF0ZSIsIHZhbHVlID0gIkF0dGVudGlvbiIpDQpEYXRhU2ltMSRTUzwtYXMuZmFjdG9yKHJlcChzZXEoMTpuKSwyKSkNCmBgYA0KDQojIyAgUGxvdCBvZiBTaW11bGF0aW9uIDENCi0gU3BhZ2V0dGkgcGxvdCBwZXIgcGVyc29uDQoNCmBgYHtyLCBlY2hvPUZBTFNFfQ0KbGlicmFyeShnZ3Bsb3QyKQ0KdGhlbWVfc2V0KHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDEyLCBiYXNlX2ZhbWlseSA9ICIiKSkgDQpSbS50LnRlc3QucGxvdCA8LWdncGxvdChkYXRhID0gRGF0YVNpbTEsIGFlcyh4ID0gQ2hvY29sYXRlLCB5PUF0dGVudGlvbikpKw0KICBnZW9tX3BvaW50KGFlcyhjb2xvdXIgPSBTUykpKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFLCBhZXMoZ3JvdXA9U1MsY29sb3VyID0gU1MpKSsNCiAgeWxhYigiQXR0ZW50aW9uIikreGxhYigiQ2hvY29sYXRlIikrDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikNClJtLnQudGVzdC5wbG90DQpgYGANCg0KIyMgIFBhaXJlZCB0LXRlc3QNCg0KYGBge3IscmVzdWx0cz0iYXNpcyJ9DQpUMTwtdC50ZXN0KEF0dGVudGlvbn5DaG9jb2xhdGUsIHBhaXJlZD1UUlVFLERhdGFTaW0xKQ0KbGlicmFyeShhcGEpDQpjYXQoYXBhKFQxLCBmb3JtYXQgPSAicm1hcmtkb3duIiwgcHJpbnQgPSBGQUxTRSkpDQpgYGANCg0KLSBOb3RlOiB0LXRlc3QgaW4gUiBkb2VzIE0xLU0yIChzbyBpdCByZXBvcnRlZCBpdCBuZWdhdGl2ZSksIA0KLSBBbHNvLCBvdXIgJHIkID0gLjQgYmV0d2VlbiBOb25lIGFuZCBTb21lIENob2NvbGF0ZSwgaGFkIHdlIHNldCBpdCB0byB6ZXJvLCB0aGlzIHBhaXJlZCB0ZXN0IHdvdWxkIGJlIGVxdWFsIHRvIGEgYmV0d2Vlbi1zdWJqZWN0cyB0LXRlc3QgW2luIGEgcGVyZmVjdCB3b3JsZCAod2l0aCBubyB2YXJpYW5jZSkgJHIkID0gMV0NCg0KIyMgIE1peGVkOiBSYW5kb20gSW50ZXJjZXB0cw0KLSBXZSBjYW4gbWlycm9yIHRoaXMgcmVzdWx0IHVzaW5nIG91ciBtaXhlZCByZWdyZXNzaW9uDQotIEluIHRoaXMgY2FzZSwgdG8gbWF0Y2ggdGhlIHBhaXJlZC1zYW1wbGUgdC10ZXN0LCB3ZSBuZWVkIHRvIGxldCB0aGUgaW50ZXJjZXB0IHZhcnkgcGVyIHN1YmplY3QNCg0KYGBge3J9DQpsaWJyYXJ5KGxtZTQpDQpNb2RlbC4xPC1sbWVyKEF0dGVudGlvbn5DaG9jb2xhdGUNCiAgICAgICAgICAgICAgICsoMXxTUyksDQogICAgICAgICAgICAgICBkYXRhPURhdGFTaW0xLCBSRU1MPUZBTFNFKQ0Kc3VtbWFyeShNb2RlbC4xLCBjb3JyZWxhdGlvbj1GQUxTRSkNCmBgYA0KDQotIFlvdSB3aWxsIG5vdGljZSB0aGF0IHRoZSB0LXZhbHVlcyBwcmV0dHkgbXVjaCBtYXRjaA0KLSBUaGUgbW9kZWwgaXMgcmVtb3ZpbmcgdGhlIGludGVyY2VwdCBkaWZmZXJlbmNlcyBiZXR3ZWVuIHRoZSBzdWJqZWN0cw0KLSBXZSBjYW4gcGxvdCB0aGUgcHJlZGljdGlvbiBvZiB0aGUgbW9kZWwgcGVyIHBlcnNvbiBmb3IgYm90aCBmaXhlZCArIHJhbmRvbSBhbmQgZml4ZWQgYWxvbmUNCg0KYGBge3J9DQpEYXRhU2ltMSRGUjwtcHJlZGljdChNb2RlbC4xKSAgI0ZpeGVkICsgcmFuZG9tDQpEYXRhU2ltMSRGaXhlZDwtcHJlZGljdChNb2RlbC4xLHJlLmZvcm09TkEpICMgRml4ZWQgb25seQ0KYGBgDQoNCmBgYHtyLCBlY2hvPUZBTFNFLG91dC53aWR0aD0nMTAwJScsIGZpZy5oZWlnaHQ9MixmaWcuc2hvdz0naG9sZCcsZmlnLmFsaWduPSdjZW50ZXInfQ0KbGlicmFyeShncmlkRXh0cmEpDQp0aGVtZV9zZXQodGhlbWVfYncoYmFzZV9zaXplID0gNywgYmFzZV9mYW1pbHkgPSAiIikpDQoNClJtLm1peGVkIDwtZ2dwbG90KGRhdGEgPSBEYXRhU2ltMSwgYWVzKHggPSBDaG9jb2xhdGUsIHk9RlIsZ3JvdXA9U1MpKSsNCiAgZ2VvbV9wb2ludChhZXMoY29sb3VyID0gU1MpKSsNCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSwgYWVzKGdyb3VwPVNTLGNvbG91ciA9IFNTKSkrDQogIHlsYWIoIkF0dGVudGlvbiIpK3hsYWIoIkNob2NvbGF0ZSIpKw0KICAgIGdndGl0bGUoJ0ZpeGVkICsgUmFuZG9tIEVmZmVjdHMnKSsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KDQpSbS5taXhlZC5GIDwtZ2dwbG90KGRhdGEgPSBEYXRhU2ltMSwgYWVzKHggPSBGaXhlZCwgeT1GaXhlZCkpKw0KICBnZW9tX3BvaW50KCkrDQogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UpKw0KICB5bGFiKCJBdHRlbnRpb24iKSt4bGFiKCJDaG9jb2xhdGUiKSsNCiAgZ2d0aXRsZSgnRml4ZWQgRWZmZWN0cyBPbmx5JykrDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikNCg0KZ3JpZC5hcnJhbmdlKFJtLm1peGVkLFJtLm1peGVkLkYsIG5jb2w9MikNCg0KYGBgDQoNCi0gWW91IHdpbGwgbm90aWNlIHRoYXQgd2UgZGlkIG5vdCBhY2NvdW50IGZvciB0aGUgcmFuZG9tIHNsb3Blcw0KDQpgYGB7cn0NClJtLnQudGVzdC5wbG90IDwtZ2dwbG90KGRhdGEgPSBEYXRhU2ltMSwgYWVzKHggPSBDaG9jb2xhdGUsIHk9QXR0ZW50aW9uLGdyb3VwPVNTKSkrDQogIGZhY2V0X3dyYXAoflNTKSsNCiAgZ2VvbV9wb2ludChhZXMoY29sb3VyID0gU1MpKSsNCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSwgYWVzKGdyb3VwPVNTLGNvbG91ciA9IFNTKSkrDQogIHlsYWIoIkF0dGVudGlvbiIpK3hsYWIoIkNob2NvbGF0ZSIpKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpDQpSbS50LnRlc3QucGxvdA0KYGBgDQotIEl0cyBjbGVhciB0aGF0IGVhY2ggc3ViamVjdCBpcyBhZmZlY3RlZCBieSBDaG9jb2xhdGUgaW4gYSBkaWZmZXJlbnQgd2F5LCBzbyB3ZSBzaG91bGQgdHJ5IHRvIGFjY291bnQgZm9yIHRoZSBzbG9wZSBkaWZmZXJlbmNlcw0KLSBXZSBkaWQgd2l0aCB0aGlzIHNjaG9vbCBpbiBNTE0sIHNvIHdlIG11c3QgYmUgYWJsZSB0byBkbyBpdCBoZXJlIQ0KDQpgYGB7cixldmFsPUZBTFNFfQ0KTW9kZWwuMWE8LWxtZXIoQXR0ZW50aW9ufkNob2NvbGF0ZQ0KICAgICAgICAgICAgICAgKygxK0Nob2NvbGF0ZXxTUyksDQogICAgICAgICAgICAgICBkYXRhPURhdGFTaW0xLCBSRU1MPUZBTFNFKQ0KYGBgDQoNCj4gKkVycm9yOiBudW1iZXIgb2Ygb2JzZXJ2YXRpb25zICg9MjQpIDw9IG51bWJlciBvZiByYW5kb20gZWZmZWN0cyAoPTI0KSBmb3IgdGVybSAoMSArIENob2NvbGF0ZSB8IFNTKTsgdGhlIHJhbmRvbS1lZmZlY3RzIHBhcmFtZXRlcnMgYW5kIHRoZSByZXNpZHVhbCB2YXJpYW5jZSAob3Igc2NhbGUgcGFyYW1ldGVyKSBhcmUgcHJvYmFibHkgdW5pZGVudGlmaWFibGUqDQoNCi0gV2hhdCBpcyB0aGlzIGNyYXp5IG1lc3NhZ2U/IFdlbGwsIGl0J3MgdGVsbGluZyB1cyB3ZSBhcmUgdHJ5aW5nIHdlIGNhbm5vdCBkbyB0aGlzLiBXaHk/DQogICAgLSBXZWxsLCBob3cgdmFyaWFuY2UgZG8geW91IGhhdmUgcm91bmQgdGhlIGVzdGltYXRlIG9mIHRoZSBzbG9wZSBkbyB5b3UgaGF2ZSBwZXIgc3ViamVjdD8gDQotIEhvdyBjYW4geW91IGVzdGltYXRlIGFueSB2YXJpYW5jZSBhcm91bmQgdGhlIHNsb3BlIGlmIHlvdSBoYXZlIG9ubHkgMSBzbG9wZSBwZXIgc3ViamVjdD8NCiAgICAtIFlvdSBuZWVkIHRvIGhhdmUgbXVsdGlwbGUgZXN0aW1hdGVzIHBlciBzdWJqZWN0IHBlciBjb25kaXRpb24hDQogICAgICAgIC0gVGhlIG1vcmUgdHJpYWxzIHdlIGhhdmUgcGVyIHN1YmplY3QsIHRoZSBiZXR0ZXIgZXN0aW1hdGUgb2YgdGhlIHNsb3BlIGFuZCB3ZSBjYW4gY2FsY3VsYXRlIHRoZSB2YXJpYW5jZSBhcm91bmQgdGhhdCBzbG9wZSENCg0KIyMgIE1peGVkOiBSYW5kb20gSW50ZXJjZXB0cyAmIFNsb3Blcw0KDQotIExldCdzIGFkZCBtb3JlIHRyaWFscyBwZXIgY29uZGl0aW9uOiBTaW11bGF0aW9uIDINCi0gSG93ZXZlciwgdGhpbmdzIGdldCBtb3JlIGNvbXBsaWNhdGVkDQogICAgLSBIb3cgbXVjaCBtZWFzdXJlbWVudCBlcnJvciBpcyB0aGVyZSB3aGVuIHJlLW1lYXN1cmVtZW50IG9mIHRoZSBzYW1lIGNvbmRpdGlvbiBwZXIgc3ViamVjdD8gDQogICAgICAgIC0gQ291bGQgdGhhdCB2YWx1ZSBkaWZmZXIgcGVyIHRyaWFsIG9yIGNvbmRpdGlvbj8NCiAgICAgICAgLSBJcyBpdCB0aGUgc2FtZSBzdGltdWx1cyBvciBhIG5ldyBvbmU/IA0KICAgICAgICAgICAgLSBDb3VsZCB0aGUgbmV3IHN0aW11bHVzIGJlIGhhdmluZyBhbiBlZmZlY3Q/DQogICAgICAgICAgICAtIFdlIHdpbGwgYXNzdW1lIGEgcmVwZWF0IG9mIHRoZSBzYW1lIHN0aW11bHVzIHBlciBjb25kaXRpb24NCiAgICAtIFdoYXQgaXMgdGhlIHZhcmlhbmNlIG9mIGVhY2ggY29uZGl0aW9uPw0KICAgICAgICAtIFRoZXkgY2FuIGRpZmZlciAoQU5PVkEgYXNzdW1wdGlvbnMgc2F5IHRoZXkgY2Fubm90KSANCiAgICAgICAgICAgIC0gSWYgd2UgZGlkIGhhdmUgbXVsdGlwbGUgc3RpbXVsaSBwZXIgY29uZGl0aW9uIGNvdWxkIHRoZXkgdmFyeSBhcyBhIGZ1bmN0aW9uIG9mIHRoZSBjb25kaXRpb24/ICANCiAgICAgIA0KYGBge3IsIGVjaG8gPSBGQUxTRX0NCmxpYnJhcnkobXZ0bm9ybSkNCk1peGVkU2ltMkxldmVsID0gZnVuY3Rpb24obiwgaywgbm9pc2UsIEksIHZJLEEsIHZBLCBySUEpew0KICBzZXQuc2VlZCg0MikNCiAgI0Z1bmN0aW9uIGFkYXB0ZWQgZnJvbSBodHRwczovL2dpc3QuZ2l0aHViLmNvbS9taWtlLWxhd3JlbmNlLzEzNzAwMzINCiAgU2lnbWEgPSBjKHZJICwgc3FydCh2SSp2QSkqcklBLCBzcXJ0KHZJKnZBKSpySUEgLCB2QSkNCiAgU2lnbWEgPSBtYXRyaXgoU2lnbWEsMiwyKQ0KICBtZWFucyA9IHJtdm5vcm0obixjKEksQSksU2lnbWEpDQogIHRlbXAgPSBleHBhbmQuZ3JpZChBPWMoJ05vbmUnLCdTb21lJyksdmFsdWU9MCkNCiAgdGVtcCRBID0gZmFjdG9yKHRlbXAkQSkNCiAgZnJvbV90ZXJtcyA9IHRlcm1zKHZhbHVlfkEpDQogIG1tID0gbW9kZWwubWF0cml4KGZyb21fdGVybXMsdGVtcCkNCiAgZGF0YSA9IGV4cGFuZC5ncmlkKEE9YygnTm9uZScsJ1NvbWUnKSxTUz0xOm4sdHJpYWw9MTprKQ0KICBmb3IoaSBpbiAxOm4pew0KICAgIGRhdGEkdmFsdWVbZGF0YSRTUz09aV0gPSBhcy5udW1lcmljKG1tICUqJSBtZWFuc1tpLF0pICsgcm5vcm0oayoyLDAsc3FydChub2lzZSkpDQogIH0NCiAgZGF0YSRTUyA9IGZhY3RvcihkYXRhJFNTKQ0KICBkYXRhJEEgPSBmYWN0b3IoZGF0YSRBKQ0KICBuYW1lcyhkYXRhKSA8LSBjKCJDaG9jb2xhdGUiLCJTUyIsIlRyaWFsIiwgIkF0dGVudGlvbiIpDQogIGRhdGEkQ2hvY29sYXRlPC1mYWN0b3IoZGF0YSRDaG9jb2xhdGUsIGxldmVscz1jKCdOb25lJywnU29tZScpLCBsYWJlbHM9YygiTm9uZSIsIlNvbWUiKSkNCiAgcmV0dXJuKGRhdGEpDQp9DQpgYGANCg0KLSBUbyB1bmRlcnN0YW5kIGFsbCB0aGUgbGV2ZWxzIG9mIHZhcmlhbmNlIGxldCdzIHNpbXVsYXRlIHRoZSBjaG9jb2xhdGUgc3R1ZHkgd2l0aCA0IHRyaWFscyBvZiB0d28gY29uZGl0aW9uczoNCg0KIyMjIFNpbXVsYXRpb24gMmE6IE5vIFZhcmlhbmNlDQoNCi0gV2Ugd2lsbCBzZXQgJG4kID0gNCwgVHJpYWxzPTQsICRyJCA9IC42LCAkTV8xJCA9IDIgYW5kICRNXzIkID0gNCwgJFxzaWdtYV4yX3tNMX0kID0gMCwgJFxzaWdtYV4yX3tNMn0kID0gMCwgICRcc2lnbWFeMl97bWVhc3VyZW1lbnR9JCA9IDAgDQoNCmBgYHtyLCBlY2hvPUZBTFNFfQ0KRGF0YVNpbTJhID0gTWl4ZWRTaW0yTGV2ZWwoDQogICAgbiA9IDQgIyBudW1iZXIgb2YgU1MNCiAgLCBrID0gNCAjIG51bWJlciBvZiB0cmlhbHMgd2l0aGluIGVhY2ggY29uZGl0aW9uIHdpdGhpbiBlYWNoIFNTDQogICwgbm9pc2UgPSAwICMgbWVhc3VyZW1lbnQgbm9pc2UgDQogICMgRmlyc3QgQ29uZGl0aW9uDQogICwgSSA9IDIgIyBwb3B1bGF0aW9uIGludGVyY2VwdCANCiAgLCB2SSA9IDAgIyBhY3Jvc3MtU1MgdmFyaWFuY2Ugb2YgaW50ZXJjZXB0cw0KICAjIFNlY29uZCBDb25kaXRpb24NCiAgLCBBID0gNCAjIHBvcHVsYXRpb24gQSBlZmZlY3QgKFNlY29uZCBDb25kaXRpb24pDQogICwgdkEgPSAwICMgYWNyb3NzLVNTIHZhcmlhbmNlIG9mIEEgZWZmZWN0cw0KICAsIHJJQSA9IC42ICMgYWNyb3NzLVNTIGNvcnJlbGF0aW9uIGJldHdlZW4gaW50ZXJjZXB0cyBhbmQgQSBlZmZlY3RzDQopDQojIE5vdGU6IEZ1bmN0aW9uIGFkYXB0ZWQgZnJvbSBodHRwczovL2dpc3QuZ2l0aHViLmNvbS9taWtlLWxhd3JlbmNlLzEzNzAwMzINCmBgYA0KDQpgYGB7ciwgZWNobz1GQUxTRSxmaWcud2lkdGg9Ni41LGZpZy5oZWlnaHQ9Mi41fQ0KRGF0YVNpbTJhLlBsb3QgPC1nZ3Bsb3QoZGF0YSA9IERhdGFTaW0yYSwgYWVzKHggPSBDaG9jb2xhdGUsIHk9QXR0ZW50aW9uLGdyb3VwPVNTKSkrDQogIGZhY2V0X3dyYXAoflNTLCBucm93PTEpKw0KICBnZW9tX3BvaW50KGFlcyhjb2xvdXIgPSBTUykpKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFLCBhZXMoZ3JvdXA9VHJpYWwsY29sb3VyID0gU1MpKSsNCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSwgbGluZXR5cGU9MykrDQogIHlsYWIoIkF0dGVudGlvbiIpK3hsYWIoIkNob2NvbGF0ZSIpKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpDQpEYXRhU2ltMmEuUGxvdA0KYGBgDQoNCiMjIyBTaW11bGF0aW9uIDJiOiBNZWFzdXJlbWVudCBFcnJvcg0KLSBXZSB3aWxsIHNldCAkbiQgPSA0LCBUcmlhbHM9NCwgJHIkID0gLjYsICRNXzEkID0gMiBhbmQgJE1fMiQgPSA0LCAkXHNpZ21hXjJfe00xfSQgPSAwLCAkXHNpZ21hXjJfe00yfSQgPSAwLCAgJFxzaWdtYV4yX3ttZWFzdXJlbWVudH0kID0gNA0KDQpgYGB7ciwgZWNobz1GQUxTRX0NCkRhdGFTaW0yYiA9IE1peGVkU2ltMkxldmVsKA0KICAgIG4gPSA0ICMgbnVtYmVyIG9mIFNTDQogICwgayA9IDQgIyBudW1iZXIgb2YgdHJpYWxzIHdpdGhpbiBlYWNoIGNvbmRpdGlvbiB3aXRoaW4gZWFjaCBTUw0KICAsIG5vaXNlID0gNCAjIG1lYXN1cmVtZW50IG5vaXNlIA0KICAjIEZpcnN0IENvbmRpdGlvbg0KICAsIEkgPSAyICMgcG9wdWxhdGlvbiBpbnRlcmNlcHQgDQogICwgdkkgPSAwICMgYWNyb3NzLVNTIHZhcmlhbmNlIG9mIGludGVyY2VwdHMNCiAgIyBTZWNvbmQgQ29uZGl0aW9uDQogICwgQSA9IDQgIyBwb3B1bGF0aW9uIEEgZWZmZWN0IChTZWNvbmQgQ29uZGl0aW9uKQ0KICAsIHZBID0gMCAjIGFjcm9zcy1TUyB2YXJpYW5jZSBvZiBBIGVmZmVjdHMNCiAgLCBySUEgPSAuNiAjIGFjcm9zcy1TUyBjb3JyZWxhdGlvbiBiZXR3ZWVuIGludGVyY2VwdHMgYW5kIEEgZWZmZWN0cw0KKQ0KIyBOb3RlOiBGdW5jdGlvbiBhZGFwdGVkIGZyb20gaHR0cHM6Ly9naXN0LmdpdGh1Yi5jb20vbWlrZS1sYXdyZW5jZS8xMzcwMDMyDQpgYGANCg0KYGBge3IsIGVjaG89RkFMU0UsZmlnLndpZHRoPTYuNSxmaWcuaGVpZ2h0PTIuNX0NCkRhdGFTaW0yYi5QbG90IDwtZ2dwbG90KGRhdGEgPSBEYXRhU2ltMmIsIGFlcyh4ID0gQ2hvY29sYXRlLCB5PUF0dGVudGlvbixncm91cD1TUykpKw0KICBmYWNldF93cmFwKH5TUywgbnJvdz0xKSsNCiAgZ2VvbV9wb2ludChhZXMoY29sb3VyID0gU1MpKSsNCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSwgYWVzKGdyb3VwPVRyaWFsLGNvbG91ciA9IFNTKSkrDQogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UsIGxpbmV0eXBlPTMpKw0KICB5bGFiKCJBdHRlbnRpb24iKSt4bGFiKCJDaG9jb2xhdGUiKSsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KRGF0YVNpbTJiLlBsb3QNCmBgYA0KDQojIyMgU2ltdWxhdGlvbiAyYzogSW50ZXJjZXB0IFZhcmlhbmNlDQotIFdlIHdpbGwgc2V0ICRuJCA9IDQsIFRyaWFscz00LCAkciQgPSBOQSwgJE1fMSQgPSAyIGFuZCAkTV8yJCA9IDQsICRcc2lnbWFeMl97TTF9JCA9IDQsICRcc2lnbWFeMl97TTJ9JCA9IDAsICAkXHNpZ21hXjJfe21lYXN1cmVtZW50fSQgPSAwDQoNCmBgYHtyLCBlY2hvPUZBTFNFfQ0KRGF0YVNpbTJjID0gTWl4ZWRTaW0yTGV2ZWwoDQogICAgbiA9IDQgIyBudW1iZXIgb2YgU1MNCiAgLCBrID0gNCAjIG51bWJlciBvZiB0cmlhbHMgd2l0aGluIGVhY2ggY29uZGl0aW9uIHdpdGhpbiBlYWNoIFNTDQogICwgbm9pc2UgPSAwICMgbWVhc3VyZW1lbnQgbm9pc2UNCiAgIyBGaXJzdCBDb25kaXRpb24NCiAgLCBJID0gMiAjIHBvcHVsYXRpb24gaW50ZXJjZXB0IA0KICAsIHZJID0gNCAjIGFjcm9zcy1TUyB2YXJpYW5jZSBvZiBpbnRlcmNlcHRzDQogICMgU2Vjb25kIENvbmRpdGlvbg0KICAsIEEgPSA0ICMgcG9wdWxhdGlvbiBBIGVmZmVjdCAoU2Vjb25kIENvbmRpdGlvbikNCiAgLCB2QSA9IDAgIyBhY3Jvc3MtU1MgdmFyaWFuY2Ugb2YgQSBlZmZlY3RzDQogICwgcklBID0gLjYgIyBhY3Jvc3MtU1MgY29ycmVsYXRpb24gYmV0d2VlbiBpbnRlcmNlcHRzIGFuZCBBIGVmZmVjdHMNCikNCiMgTm90ZTogRnVuY3Rpb24gYWRhcHRlZCBmcm9tIGh0dHBzOi8vZ2lzdC5naXRodWIuY29tL21pa2UtbGF3cmVuY2UvMTM3MDAzMg0KYGBgDQoNCmBgYHtyLCBlY2hvPUZBTFNFLGZpZy53aWR0aD02LjUsZmlnLmhlaWdodD0yLjV9DQpEYXRhU2ltMmMuUGxvdCA8LWdncGxvdChkYXRhID0gRGF0YVNpbTJjLCBhZXMoeCA9IENob2NvbGF0ZSwgeT1BdHRlbnRpb24sZ3JvdXA9U1MpKSsNCiAgZmFjZXRfd3JhcCh+U1MsIG5yb3c9MSkrDQogIGdlb21fcG9pbnQoYWVzKGNvbG91ciA9IFNTKSkrDQogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UsIGFlcyhncm91cD1UcmlhbCxjb2xvdXIgPSBTUykpKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFLCBsaW5ldHlwZT0zKSsNCiAgeWxhYigiQXR0ZW50aW9uIikreGxhYigiQ2hvY29sYXRlIikrDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikNCkRhdGFTaW0yYy5QbG90DQpgYGANCg0KDQojIyMgU2ltdWxhdGlvbiAyZDogU2xvcGUgVmFyaWFuY2UNCi0gV2Ugd2lsbCBzZXQgJG4kID0gNCwgVHJpYWxzPTQsICRyJCA9IE5BLCAkTV8xJCA9IDIgYW5kICRNXzIkID0gNCwgJFxzaWdtYV4yX3tNMX0kID0gMCwgJFxzaWdtYV4yX3tNMn0kID0gNCwgICRcc2lnbWFeMl97bWVhc3VyZW1lbnR9JCA9IDANCg0KYGBge3IsIGVjaG89RkFMU0V9DQpEYXRhU2ltMmQgPSBNaXhlZFNpbTJMZXZlbCgNCiAgICBuID0gNCAjIG51bWJlciBvZiBTUw0KICAsIGsgPSA0ICMgbnVtYmVyIG9mIHRyaWFscyB3aXRoaW4gZWFjaCBjb25kaXRpb24gd2l0aGluIGVhY2ggU1MNCiAgLCBub2lzZSA9IDAgIyBtZWFzdXJlbWVudCBub2lzZQ0KICAjIEZpcnN0IENvbmRpdGlvbg0KICAsIEkgPSAyICMgcG9wdWxhdGlvbiBpbnRlcmNlcHQgDQogICwgdkkgPSAwICMgYWNyb3NzLVNTIHZhcmlhbmNlIG9mIGludGVyY2VwdHMNCiAgIyBTZWNvbmQgQ29uZGl0aW9uDQogICwgQSA9IDQgIyBwb3B1bGF0aW9uIEEgZWZmZWN0IChTZWNvbmQgQ29uZGl0aW9uKQ0KICAsIHZBID0gNCAjIGFjcm9zcy1TUyB2YXJpYW5jZSBvZiBBIGVmZmVjdHMNCiAgLCBySUEgPSAuNiAjIGFjcm9zcy1TUyBjb3JyZWxhdGlvbiBiZXR3ZWVuIGludGVyY2VwdHMgYW5kIEEgZWZmZWN0cw0KKQ0KIyBOb3RlOiBGdW5jdGlvbiBhZGFwdGVkIGZyb20gaHR0cHM6Ly9naXN0LmdpdGh1Yi5jb20vbWlrZS1sYXdyZW5jZS8xMzcwMDMyDQpgYGANCg0KYGBge3IsIGVjaG89RkFMU0UsZmlnLndpZHRoPTYuNSxmaWcuaGVpZ2h0PTIuNX0NCkRhdGFTaW0yZC5QbG90IDwtZ2dwbG90KGRhdGEgPSBEYXRhU2ltMmQsIGFlcyh4ID0gQ2hvY29sYXRlLCB5PUF0dGVudGlvbixncm91cD1TUykpKw0KICBmYWNldF93cmFwKH5TUywgbnJvdz0xKSsNCiAgZ2VvbV9wb2ludChhZXMoY29sb3VyID0gU1MpKSsNCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSwgYWVzKGdyb3VwPVRyaWFsLGNvbG91ciA9IFNTKSkrDQogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UsIGxpbmV0eXBlPTMpKw0KICB5bGFiKCJBdHRlbnRpb24iKSt4bGFiKCJDaG9jb2xhdGUiKSsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KRGF0YVNpbTJkLlBsb3QNCmBgYA0KDQojIyMgU2ltdWxhdGlvbiAyZTogSW50ZXJjZXB0ICsgU2xvcGUgVmFyaWFuY2UNCi0gV2Ugd2lsbCBzZXQgJG4kID0gNCwgVHJpYWxzPTQsICRyJCA9IE5BLCAkTV8xJCA9IDIgYW5kICRNXzIkID0gNCwgJFxzaWdtYV4yX3tNMX0kID0gNCwgJFxzaWdtYV4yX3tNMn0kID0gNCwgICRcc2lnbWFeMl97bWVhc3VyZW1lbnR9JCA9IDANCg0KYGBge3IsIGVjaG89RkFMU0V9DQpEYXRhU2ltMmUgPSBNaXhlZFNpbTJMZXZlbCgNCiAgICBuID0gNCAjIG51bWJlciBvZiBTUw0KICAsIGsgPSA0ICMgbnVtYmVyIG9mIHRyaWFscyB3aXRoaW4gZWFjaCBjb25kaXRpb24gd2l0aGluIGVhY2ggU1MNCiAgLCBub2lzZSA9IDAgIyBtZWFzdXJlbWVudCBub2lzZQ0KICAjIEZpcnN0IENvbmRpdGlvbg0KICAsIEkgPSAyICMgcG9wdWxhdGlvbiBpbnRlcmNlcHQgDQogICwgdkkgPSA0ICMgYWNyb3NzLVNTIHZhcmlhbmNlIG9mIGludGVyY2VwdHMNCiAgIyBTZWNvbmQgQ29uZGl0aW9uDQogICwgQSA9IDQgIyBwb3B1bGF0aW9uIEEgZWZmZWN0IChTZWNvbmQgQ29uZGl0aW9uKQ0KICAsIHZBID0gNCAjIGFjcm9zcy1TUyB2YXJpYW5jZSBvZiBBIGVmZmVjdHMNCiAgLCBySUEgPSAuNiAjIGFjcm9zcy1TUyBjb3JyZWxhdGlvbiBiZXR3ZWVuIGludGVyY2VwdHMgYW5kIEEgZWZmZWN0cw0KKQ0KIyBOb3RlOiBGdW5jdGlvbiBhZGFwdGVkIGZyb20gaHR0cHM6Ly9naXN0LmdpdGh1Yi5jb20vbWlrZS1sYXdyZW5jZS8xMzcwMDMyDQpgYGANCg0KYGBge3IsIGVjaG89RkFMU0UsZmlnLndpZHRoPTYuNSxmaWcuaGVpZ2h0PTIuNX0NCkRhdGFTaW0yZS5QbG90IDwtZ2dwbG90KGRhdGEgPSBEYXRhU2ltMmUsIGFlcyh4ID0gQ2hvY29sYXRlLCB5PUF0dGVudGlvbixncm91cD1TUykpKw0KICBmYWNldF93cmFwKH5TUywgbnJvdz0xKSsNCiAgZ2VvbV9wb2ludChhZXMoY29sb3VyID0gU1MpKSsNCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSwgYWVzKGdyb3VwPVRyaWFsLGNvbG91ciA9IFNTKSkrDQogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UsIGxpbmV0eXBlPTMpKw0KICB5bGFiKCJBdHRlbnRpb24iKSt4bGFiKCJDaG9jb2xhdGUiKSsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KRGF0YVNpbTJlLlBsb3QNCmBgYA0KDQojIyMgU2ltdWxhdGlvbiAyZjogSW50ZXJjZXB0ICsgU2xvcGUgVmFyaWFuY2UgKyBNZWFzdXJlbWVudCBOb2lzZQ0KLSBXZSB3aWxsIHNldCAkbiQgPSA0LCBUcmlhbHM9NCwgJHIkID0gLjYsICRNXzEkID0gMiBhbmQgJE1fMiQgPSA0LCAkXHNpZ21hXjJfe00xfSQgPSA0LCAkXHNpZ21hXjJfe00yfSQgPSA0LCAgJFxzaWdtYV4yX3ttZWFzdXJlbWVudH0kID0gNA0KDQpgYGB7ciwgZWNobz1GQUxTRX0NCkRhdGFTaW0yZiA9IE1peGVkU2ltMkxldmVsKA0KICAgIG4gPSA0ICMgbnVtYmVyIG9mIFNTDQogICwgayA9IDQgIyBudW1iZXIgb2YgdHJpYWxzIHdpdGhpbiBlYWNoIGNvbmRpdGlvbiB3aXRoaW4gZWFjaCBTUw0KICAsIG5vaXNlID0gNCAjIG1lYXN1cmVtZW50IG5vaXNlIA0KICAjIEZpcnN0IENvbmRpdGlvbg0KICAsIEkgPSAyICMgcG9wdWxhdGlvbiBpbnRlcmNlcHQgDQogICwgdkkgPSA0ICMgYWNyb3NzLVNTIHZhcmlhbmNlIG9mIGludGVyY2VwdHMNCiAgIyBTZWNvbmQgQ29uZGl0aW9uDQogICwgQSA9IDQgIyBwb3B1bGF0aW9uIEEgZWZmZWN0IChTZWNvbmQgQ29uZGl0aW9uKQ0KICAsIHZBID0gNCAjIGFjcm9zcy1TUyB2YXJpYW5jZSBvZiBBIGVmZmVjdHMNCiAgLCBySUEgPSAuNiAjIGFjcm9zcy1TUyBjb3JyZWxhdGlvbiBiZXR3ZWVuIGludGVyY2VwdHMgYW5kIEEgZWZmZWN0cw0KKQ0KIyBOb3RlOiBGdW5jdGlvbiBhZGFwdGVkIGZyb20gaHR0cHM6Ly9naXN0LmdpdGh1Yi5jb20vbWlrZS1sYXdyZW5jZS8xMzcwMDMyDQpgYGANCg0KYGBge3IsIGVjaG89RkFMU0UsZmlnLndpZHRoPTYuNSxmaWcuaGVpZ2h0PTIuNX0NCkRhdGFTaW0yZi5QbG90IDwtZ2dwbG90KGRhdGEgPSBEYXRhU2ltMmYsIGFlcyh4ID0gQ2hvY29sYXRlLCB5PUF0dGVudGlvbixncm91cD1TUykpKw0KICBmYWNldF93cmFwKH5TUywgbnJvdz0xKSsNCiAgZ2VvbV9wb2ludChhZXMoY29sb3VyID0gU1MpKSsNCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSwgYWVzKGdyb3VwPVRyaWFsLGNvbG91ciA9IFNTKSkrDQogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UsIGxpbmV0eXBlPTMpKw0KICB5bGFiKCJBdHRlbnRpb24iKSt4bGFiKCJDaG9jb2xhdGUiKSsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KRGF0YVNpbTJmLlBsb3QNCmBgYA0KDQoNCiMjIyBTaW11bGF0aW9uIDJnOiBGaXR0aW5nIE1peGVkIE1vZGVsDQotIFdlIHdpbGwgc2V0ICRuJCA9IDEyLCBUcmlhbHM9NCwgJHIkID0gLjYsICRNXzEkID0gMiBhbmQgJE1fMiQgPSA0LCAkXHNpZ21hXjJfe00xfSQgPSA0LCAkXHNpZ21hXjJfe00yfSQgPSA0LCAgJFxzaWdtYV4yX3ttZWFzdXJlbWVudH0kID0gNA0KDQpgYGB7ciwgZWNobz1GQUxTRX0NCkRhdGFTaW0yZyA9IE1peGVkU2ltMkxldmVsKA0KICAgIG4gPSAxMiAjIG51bWJlciBvZiBTUw0KICAsIGsgPSA0ICMgbnVtYmVyIG9mIHRyaWFscyB3aXRoaW4gZWFjaCBjb25kaXRpb24gd2l0aGluIGVhY2ggU1MNCiAgLCBub2lzZSA9IDQgIyBtZWFzdXJlbWVudCBub2lzZQ0KICAjIEZpcnN0IENvbmRpdGlvbg0KICAsIEkgPSAyICMgcG9wdWxhdGlvbiBpbnRlcmNlcHQgDQogICwgdkkgPSA0ICMgYWNyb3NzLVNTIHZhcmlhbmNlIG9mIGludGVyY2VwdHMNCiAgIyBTZWNvbmQgQ29uZGl0aW9uDQogICwgQSA9IDQgIyBwb3B1bGF0aW9uIEEgZWZmZWN0IChTZWNvbmQgQ29uZGl0aW9uKQ0KICAsIHZBID0gNCAjIGFjcm9zcy1TUyB2YXJpYW5jZSBvZiBBIGVmZmVjdHMNCiAgLCBySUEgPSAuNiAjIGFjcm9zcy1TUyBjb3JyZWxhdGlvbiBiZXR3ZWVuIGludGVyY2VwdHMgYW5kIEEgZWZmZWN0cw0KKQ0KIyBOb3RlOiBGdW5jdGlvbiBhZGFwdGVkIGZyb20gaHR0cHM6Ly9naXN0LmdpdGh1Yi5jb20vbWlrZS1sYXdyZW5jZS8xMzcwMDMyDQpgYGANCg0KLSBTcGFnaGV0dGkgcGxvdA0KDQpgYGB7ciwgZWNobz1GQUxTRSxmaWcud2lkdGg9Ni41LGZpZy5oZWlnaHQ9NC41fQ0KRGF0YVNpbTJnLlBsb3QgPC1nZ3Bsb3QoZGF0YSA9IERhdGFTaW0yZywgYWVzKHggPSBDaG9jb2xhdGUsIHk9QXR0ZW50aW9uLGdyb3VwPVNTKSkrDQogIGZhY2V0X3dyYXAoflNTLCBucm93PTMpKw0KICBnZW9tX3BvaW50KGFlcyhjb2xvdXIgPSBTUykpKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFLCBhZXMoZ3JvdXA9VHJpYWwsY29sb3VyID0gU1MpKSsNCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSwgbGluZXR5cGU9MykrDQogIHlsYWIoIkF0dGVudGlvbiIpK3hsYWIoIkNob2NvbGF0ZSIpKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpDQpEYXRhU2ltMmcuUGxvdA0KYGBgDQoNCiMjIyBUZXN0IFJhbmRvbSBJbnRlcmNlcHRzICYgU2xvcGVzIA0KLSBNb2RlbCAyYTogUmFuZG9tIGludGVyY2VwdHMNCi0gTW9kZWwgMmI6IFJhbmRvbSBpbnRlcmNlcHRzICYgU2xvcGVzIChjb3JyZWxhdGVkKQ0KDQpgYGB7cn0NCk1vZGVsLjJhPC1sbWVyKEF0dGVudGlvbn5DaG9jb2xhdGUNCiAgICAgICAgICAgICAgICsoMXxTUyksDQogICAgICAgICAgICAgICBkYXRhPURhdGFTaW0yZywgUkVNTD1GQUxTRSkNCg0KTW9kZWwuMmI8LWxtZXIoQXR0ZW50aW9ufkNob2NvbGF0ZQ0KICAgICAgICAgICAgICAgKygxK0Nob2NvbGF0ZXxTUyksDQogICAgICAgICAgICAgICBkYXRhPURhdGFTaW0yZywgUkVNTD1GQUxTRSkNCmBgYA0KDQpgYGB7ciwgZWNobz1GQUxTRSwgcmVzdWx0cz0nYXNpcyd9DQpsaWJyYXJ5KHRleHJlZykNCmh0bWxyZWcobGlzdChNb2RlbC4yYSxNb2RlbC4yYiksc2luZ2xlLnJvdyA9IFRSVUUsDQogICAgICAgIGNlbnRlciA9IFRSVUUsIHN0YXIuc3ltYm9sID0gIlxcKiIsYm9sZD1UUlVFLA0KICAgICAgICBjYXB0aW9uID0gIiIsaW5saW5lLmNzcyA9IFRSVUUsIGRvY3R5cGUgPSBUUlVFLCANCiAgICAgICAgaHRtbC50YWcgPSBGQUxTRSwgaGVhZC50YWcgPSBGQUxTRSwgYm9keS50YWcgPSBGQUxTRSkNCmBgYA0KDQoNCiMjIyBUZXN0IFJhbmRvbSBTbG9wZQ0KLSBKdXN0IGFzIHdlIGRpZCBpbiBNTE0sIHdlIHdpbGwgdGVzdCB0byBzZWUgaWYgdGhlIHJhbmRvbSBzbG9wZSBpbXByb3ZlcyB0aGUgZml0LCBgYW5vdmEoTW9kZWwuMmEsTW9kZWwuMmIpYA0KDQpgYGB7ciwgZWNobz1GQUxTRX0NCmxpYnJhcnkoa2FibGVFeHRyYSkNCmthYmxlKGFub3ZhKE1vZGVsLjJhLE1vZGVsLjJiKSklPiUNCiAga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG92ZXIiLCAiY29uZGVuc2VkIiwgInJlc3BvbnNpdmUiLCBmdWxsX3dpZHRoID0gRikpDQpgYGANCg0KIyMgUGxvdCBQcmVkaWN0ZWQgUmVzdWx0cw0KYGBge3J9DQpEYXRhU2ltMmckRlJhPC1wcmVkaWN0KE1vZGVsLjJhKSAgI0ZpeGVkICsgcmFuZG9tDQpEYXRhU2ltMmckRlJiPC1wcmVkaWN0KE1vZGVsLjJiKSAgI0ZpeGVkICsgcmFuZG9tDQpgYGANCg0KYGBge3IsIGVjaG89RkFMU0Usb3V0LndpZHRoPScxMDAlJywgZmlnLmhlaWdodD0yLGZpZy5zaG93PSdob2xkJyxmaWcuYWxpZ249J2NlbnRlcid9DQpsaWJyYXJ5KGdyaWRFeHRyYSkNCnRoZW1lX3NldCh0aGVtZV9idyhiYXNlX3NpemUgPSA3LCBiYXNlX2ZhbWlseSA9ICIiKSkNClJtLm1peGVkLjJhIDwtZ2dwbG90KGRhdGEgPSBEYXRhU2ltMmcsIGFlcyh4ID0gQ2hvY29sYXRlLCB5PUZSYSxncm91cD1TUykpKw0KICBjb29yZF9jYXJ0ZXNpYW4oeWxpbT1jKC01LDE1KSkrDQogIGZhY2V0X3dyYXAoflNTKSsNCiAgZ2VvbV9wb2ludChhZXMoY29sb3VyID0gU1MpKSsNCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSwgYWVzKGdyb3VwPVNTLGNvbG91ciA9IFNTKSkrDQogIHlsYWIoIkF0dGVudGlvbiIpK3hsYWIoIkNob2NvbGF0ZSIpKw0KICBnZ3RpdGxlKCdNb2RlbCAyYTogRml4ZWQgKyBSYW5kb20gRWZmZWN0cycpKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpDQoNClJtLm1peGVkLjJiIDwtZ2dwbG90KGRhdGEgPSBEYXRhU2ltMmcsIGFlcyh4ID0gQ2hvY29sYXRlLCB5PUZSYixncm91cD1TUykpKw0KICBjb29yZF9jYXJ0ZXNpYW4oeWxpbT1jKC01LDE1KSkrDQogIGZhY2V0X3dyYXAoflNTKSsNCiAgZ2VvbV9wb2ludChhZXMoY29sb3VyID0gU1MpKSsNCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSwgYWVzKGdyb3VwPVNTLGNvbG91ciA9IFNTKSkrDQogIHlsYWIoIkF0dGVudGlvbiIpK3hsYWIoIkNob2NvbGF0ZSIpKw0KICBnZ3RpdGxlKCdNb2RlbCAyYjogRml4ZWQgKyBSYW5kb20gRWZmZWN0cycpKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpDQoNCmdyaWQuYXJyYW5nZShSbS5taXhlZC4yYSxSbS5taXhlZC4yYiwgbmNvbD0yKQ0KYGBgDQoNCiMjIE5vdGVzDQotIFdhdGNoIHRoZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZW0gcmFuZG9tIHNsb3BlcyBhbmQgaW50ZXJjZXB0IGNhcmVmdWxseSAobWFrZSBzdXJlIHRoZXkgYXJlIG5vdCBjb3JyZWxhdGVkIGF0IDEpDQotIFRoZSBtb3JlIHRyaWFscywgdGhlIGJldHRlciBhbmQgdGhlIG1vcmUgc3RhYmxlIGZyb20gbWVhc3VyZW1lbnQgdG8gbWVhc3VyZW1lbnQgdGhlIGJldHRlcg0KLSBUaGUgc3Ryb25nZXIgdGhlIGNvcnJlbGF0aW9uIGJldHdlZW4gZXhwZXJpbWVudGFsIGNvbmRpdGlvbiB0aGUgaGlnaGVyIHlvdXIgcG93ZXIgd2lsbCBiZSANCg0KDQojIDIgRmFjdG9yczogMiBYIDMgTGV2ZWwgRGVzaWducw0KLSBOb3Qgb25seSBkbyB3ZSBoYXZlIHRvIGRlYWwgd2l0aCBhbGwgdGhlIHBhcmFtZXRlcnMgd2UgaGFkIGJlZm9yZSwgYnV0IHdlIHdvdWxkIGFsc28gaGF2ZSB1bmRlcnN0b29kIHRoZSBjb3JyZWxhdGlvbnMgd2l0aGluIHN1YmplY3RzIGFjcm9zcyBmYWN0b3JzDQotIFRoZSBxdWVzdGlvbiBmb3IgdG9kYXkgaXMgaG93IHRvIGRlYWwgd2l0aCBhIGZhY3RvciB0aGF0IGhhcyAzIGxldmVscw0KICAgIC0gRXhhbWluZSB0aGlzIEkgaGVhdmlseSBtYW5pcHVsYXRlZCBkYXRhIGZyb20gbXkgcGFwZXIgKERlbW9zICYgQ2hhZmZpbiwgaW4gcHJlc3MpDQotIExpc3RlbmVycyB3ZXJlIGFza2VkIHRvIGxpc3RlbiAoYW5kIG1vdmUgdGhlaXIgYm9kaWVzKSByZWxhdGl2ZSB0byByZWNvcmRlZCBzb2xvIHRyb21ib25lIG11c2ljIHBsYXllZCBieSAyIGRpZmZlcmVudCBwZXJmb3JtZXJzIGF0IDMgbGV2ZWxzIG9mIGV4cHJlc3Npb24uIEFzIHBhcnQgb2YgdGhlIHN0dWR5LCB0aGV5IHdlcmUgYXNrZWQgdG8gcmVwb3J0IGhvdyBleHByZXNzaXZlIHRoZXkgdGhvdWdoIHRoZSBtdXNpYyB3YXMuICpOb3RlOiBJIGhhdmUgc2ltcGxpZmllZCB0aGUgZGVzaWduIGFuZCBlZGl0ZWQgdGhlIGRhdGE6IHRodXMsIHJlc3VsdHMgd2lsbCBub3QgbWF0Y2ggdGhlIHBhcGVyKi4NCiAgICAtIFdlIHdpbGwgYXNzdW1lIGEgKipmdWxseSBjcm9zc2VkIGRlc2lnbioqIHdoZXJlIGV2ZXJ5IHN1YmplY3QgaGVhcmQgZWFjaCBwZXJmb3JtZXIgcGxheSBhdCBlYWNoIGV4cHJlc3NpdmUgbGV2ZWwsIDIgdGltZXMuICRuJCA9IDE2LCBSYXRpbmdzIHdlcmUgMS02IG9uIGV4cHJlc3Npb24uDQoNCi0gUmVhZCBpbiB0aGUgZGF0YToNCmBgYHtyfQ0KTVAuRGF0YTwtcmVhZC5jc3YoIk1peGVkL011c2ljUGVyY2VwdGlvbi5jc3YiKQ0KTVAuRGF0YSRQZXJmPC1mYWN0b3IoTVAuRGF0YSRQZXJmb3JtZXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscz1jKDAsMSksDQogICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscz1jKCJNMSIsIk0yIikpDQpNUC5EYXRhJExldmVsPC1mYWN0b3IoTVAuRGF0YSRDb25kaXRpb24sDQogICAgICAgICAgICAgICAgICAgICBsZXZlbHM9YygwLDEsMiksDQogICAgICAgICAgICAgICAgICAgICBsYWJlbHM9YygiTm9ybWFsIiwiRXhwIiwiTm9uLUV4cCIpKQ0KTVAuRGF0YSRTUzwtYXMuZmFjdG9yKE1QLkRhdGEkU1MpDQpgYGANCg0KIyMgUGxvdCBTdHVkeQ0KLSBUaGlzIGlzIGNhdGVnb3JpY2FsIGRhdGEsIHNvIGNhbiBkbyBib3ggcGxvdHMvdmlvbGluIHBsb3RzIFtoZWxwZnVsIGZvciB3aGVuIHdlIHdhbnQgdG8gc2VlIHRoZSB2YXJpYW5jZV0NCmBgYHtyLCBlY2hvPUZBTFNFLGZpZy53aWR0aD02LjI1fQ0KTVAuUGxvdDEgPC1nZ3Bsb3QoZGF0YSA9IE1QLkRhdGEsIGFlcyh4ID0gTGV2ZWwsIHk9UmF0aW5nKSkrDQogIGZhY2V0X2dyaWQoLn5QZXJmKSsNCiAgZ2VvbV92aW9saW4oKSsNCiAgZ2VvbV9ib3hwbG90KHdpZHRoPS4yKSsNCiAgZ2VvbV9qaXR0ZXIoYWVzKGNvbG91ciA9IFNTKSx3aWR0aCA9IDAuMDUpKw0KICB5bGFiKCJSYXRpbmciKSt4bGFiKCJDb25kaXRpb24iKSsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KTVAuUGxvdDENCmBgYA0KDQotIFdlIGNhbiBhbHNvIHRyeSB0byBvdXIgc3BhZ2hldHRpIHBsb3RzIGluIGRpZmZlcmVudCB3YXlzDQoNCmBgYHtyLCBlY2hvPUZBTFNFLGZpZy53aWR0aD02LjUsZmlnLmhlaWdodD01LjB9DQpNUC5QbG90MiA8LWdncGxvdChkYXRhID0gTVAuRGF0YSwgYWVzKHggPSBQZXJmLCB5PVJhdGluZywgZ3JvdXA9TGV2ZWwpKSsNCiAgZmFjZXRfd3JhcCh+U1MsIG5yb3c9NCkrDQogIGdlb21faml0dGVyKGFlcyhjb2xvdXIgPSBMZXZlbCksIHdpZHRoPS4xKSsNCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSwgYWVzKGdyb3VwPUxldmVsLGNvbG91ciA9IExldmVsKSkrDQogIHlsYWIoIlJhdGluZyIpK3hsYWIoIlBlcmZvcm1lciIpKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpDQpNUC5QbG90Mg0KYGBgDQoNCmBgYHtyLCBlY2hvPUZBTFNFLGZpZy53aWR0aD02LjUsZmlnLmhlaWdodD0zLjV9DQpNUC5QbG90MyA8LWdncGxvdChkYXRhID0gTVAuRGF0YSwgYWVzKHggPSBQZXJmLCB5PVJhdGluZywgZ3JvdXA9U1MpKSsNCiAgZmFjZXRfd3JhcCh+TGV2ZWwsIG5yb3c9MSkrDQogIGdlb21faml0dGVyKGFlcyhjb2xvdXIgPSBTUyksIHdpZHRoPS4xKSsNCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSwgYWVzKGdyb3VwPVNTLGNvbG91ciA9IFNTKSkrDQogIHlsYWIoIlJhdGluZyIpK3hsYWIoIlBlcmZvcm1lciIpKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpDQpNUC5QbG90Mw0KYGBgDQoNCiMjIFJhbmRvbSBDYXRlZ29yaWNhbCBGYWN0b3INCi0gTGV0J3MgdHJlYXQgdGhlIGRhdGEgYXMgY2F0ZWdvcmljYWwNCi0gV2Ugd2lsbCBleGFtaW5lICpMZXZlbCogYXMgYSBmaXhlZCBhbmQgcmFuZG9tIGVmZmVjdHMgb25seSBGaXJzdA0KYGBge3J9DQoNCk0wPC1sbWVyKFJhdGluZ34gTGV2ZWwrICgxfFNTKSwgZGF0YT1NUC5EYXRhLCBSRU1MPVRSVUUpDQpNMTwtbG1lcihSYXRpbmd+IExldmVsKyAoMStMZXZlbHxTUyksIGRhdGE9TVAuRGF0YSwgUkVNTD1UUlVFKQ0Kc3VtbWFyeShNMSwgY29ycmVsYXRpb249RkFMU0UpDQpgYGANCg0KLSBMZXQncyBleGFtaW5lIHRoZSByYW5kb20gZWZmZWN0cyBpbiBtb3JlIGRldGFpbDoNCg0KYGBge3J9DQpSbTE8LXJhbmVmKE0xKQ0KYGBgDQoNCmBgYHtyLCBlY2hvPUZBTFNFfQ0KbGlicmFyeShrYWJsZUV4dHJhKQ0KUm0xLkg8LWhlYWQoUm0xJFNTKQ0Ka2FibGUoUm0xLkgpICU+JQ0KICBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJob3ZlciIsICJjb25kZW5zZWQiLCAicmVzcG9uc2l2ZSIpKQ0KYGBgDQoNCg0KLSBUaGUgcmFuZG9tIGludGVyY2VwdCBub3cgcmVwcmVzZW50cyByYW5kb20gZWZmZWN0IGF0IExldmVsID0gTm9ybWFsIGZvciBlYWNoIHN1YmplY3QgYW5kIHRoZSBkaWZmZXJlbmNlcyBmb3IgdGhlIG90aGVyIGNvbmRpdGlvbnMNCg0KIyMjIFBsb3QgUHJlZGljdGVkIFJlc3VsdHMgDQpgYGB7cn0NCk1QLkRhdGEkRlJhPC1wcmVkaWN0KE0wKSAgI0ZpeGVkICsgcmFuZG9tDQpNUC5EYXRhJEZSYjwtcHJlZGljdChNMSkgICNGaXhlZCArIHJhbmRvbQ0KYGBgDQoNCmBgYHtyLCBlY2hvPUZBTFNFLG91dC53aWR0aD0nMTAwJScsIGZpZy5oZWlnaHQ9MixmaWcuc2hvdz0naG9sZCcsZmlnLmFsaWduPSdjZW50ZXInfQ0KbGlicmFyeShncmlkRXh0cmEpDQp0aGVtZV9zZXQodGhlbWVfYncoYmFzZV9zaXplID0gNywgYmFzZV9mYW1pbHkgPSAiIikpDQpNUC5GaXR0ZWQuTTBhIDwtZ2dwbG90KGRhdGEgPSBNUC5EYXRhLCBhZXMoeCA9IFBlcmYsIHk9RlJhLCBncm91cD1TUykpKw0KICBjb29yZF9jYXJ0ZXNpYW4oeWxpbT1jKDAsNykpKw0KICBmYWNldF93cmFwKH5MZXZlbCwgbnJvdz0xKSsNCiAgZ2VvbV9qaXR0ZXIoYWVzKGNvbG91ciA9IFNTKSwgd2lkdGg9LjEpKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFLCBhZXMoZ3JvdXA9U1MsY29sb3VyID0gU1MpKSsNCiAgeWxhYigiUmF0aW5nOiBGaXR0ZWQiKSt4bGFiKCJQZXJmb3JtZXIiKSsNCiAgZ2d0aXRsZSgnRml4ZWQgKyBcblJhbmRvbSBJbnRlcmNlcHRzIG9mIFNTJykrDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikNCg0KTVAuRml0dGVkLk0wYiA8LWdncGxvdChkYXRhID0gTVAuRGF0YSwgYWVzKHggPSBQZXJmLCB5PUZSYiwgZ3JvdXA9U1MpKSsNCiAgICBjb29yZF9jYXJ0ZXNpYW4oeWxpbT1jKDAsNykpKw0KICBmYWNldF93cmFwKH5MZXZlbCwgbnJvdz0xKSsNCiAgZ2VvbV9qaXR0ZXIoYWVzKGNvbG91ciA9IFNTKSwgd2lkdGg9LjEpKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFLCBhZXMoZ3JvdXA9U1MsY29sb3VyID0gU1MpKSsNCiAgeWxhYigiUmF0aW5nOiBGaXR0ZWQiKSt4bGFiKCJQZXJmb3JtZXIiKSsNCiAgICBnZ3RpdGxlKCdGaXhlZCArIFxuUmFuZG9tIEludGVyY2VwdHMvU2xvcGUgb2YgTGV2ZWwgYnkgU1MnKSsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KDQpncmlkLmFycmFuZ2UoTVAuRml0dGVkLk0wYSxNUC5GaXR0ZWQuTTBiLCBuY29sPTIpDQpgYGANCg0KLSBUaGlzIGNhcHR1cmVkIHRoZSBkaWZmZXJlbmNlcyBiZXR3ZWVuICpMZXZlbHMqLCBidXQgd2Ugc3RpbGwgaGF2ZSB0byB3b3JrIG9uIHRoZSBvdGhlciBmYWN0b3IgdG8gZGVhbCB3aXRoDQotIExldCdzIGFkZCBmaXhlZCBhbmQgcmFuZG9tIGVmZmVjdCBvZiBQZXJmb3JtZXINCg0KIyMgMiBSYW5kb20gQ2F0ZWdvcmljYWwgRmFjdG9ycw0KDQpgYGB7cn0NCk0yPC1sbWVyKFJhdGluZ34gTGV2ZWwrUGVyZisgKDErTGV2ZWx8U1MpLCBkYXRhPU1QLkRhdGEsIFJFTUw9VFJVRSkNCk0zPC1sbWVyKFJhdGluZ34gTGV2ZWwrUGVyZisgKDErTGV2ZWwrUGVyZnxTUyksIGRhdGE9TVAuRGF0YSwgUkVNTD1UUlVFKQ0Kc3VtbWFyeShNMywgY29ycmVsYXRpb249RkFMU0UpDQpgYGANCg0KLSBMZXQncyBleGFtaW5lIHRoZSByYW5kb20gZWZmZWN0cyBpbiBtb3JlIGRldGFpbCAoc2hvcnRlbmVkIHZlcnNpb24pOg0KDQpgYGB7cn0NClIuTTM8LXJhbmVmKE0zKQ0KYGBgDQoNCmBgYHtyLCBlY2hvPUZBTFNFfQ0KbGlicmFyeShrYWJsZUV4dHJhKQ0KUi5NMy5IPC1oZWFkKFIuTTMkU1MpDQprYWJsZShSLk0zLkgpICU+JQ0KICBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJob3ZlciIsICJjb25kZW5zZWQiLCAicmVzcG9uc2l2ZSIpKQ0KYGBgDQoNCg0KIyMjIFBsb3QgUHJlZGljdGVkIFJlc3VsdHMgDQpgYGB7cn0NCk1QLkRhdGEkRlJjPC1wcmVkaWN0KE0yKSAgI0ZpeGVkICsgcmFuZG9tDQpNUC5EYXRhJEZSZDwtcHJlZGljdChNMykgICNGaXhlZCArIHJhbmRvbQ0KYGBgDQoNCmBgYHtyLCBlY2hvPUZBTFNFLG91dC53aWR0aD0nMTAwJScsIGZpZy5oZWlnaHQ9MixmaWcuc2hvdz0naG9sZCcsZmlnLmFsaWduPSdjZW50ZXInfQ0KbGlicmFyeShncmlkRXh0cmEpDQp0aGVtZV9zZXQodGhlbWVfYncoYmFzZV9zaXplID0gNywgYmFzZV9mYW1pbHkgPSAiIikpDQpNUC5GaXR0ZWQuTTBjIDwtZ2dwbG90KGRhdGEgPSBNUC5EYXRhLCBhZXMoeCA9IFBlcmYsIHk9RlJjLCBncm91cD1TUykpKw0KICBjb29yZF9jYXJ0ZXNpYW4oeWxpbT1jKDAsNykpKw0KICBmYWNldF93cmFwKH5MZXZlbCwgbnJvdz0xKSsNCiAgZ2VvbV9qaXR0ZXIoYWVzKGNvbG91ciA9IFNTKSwgd2lkdGg9LjEpKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFLCBhZXMoZ3JvdXA9U1MsY29sb3VyID0gU1MpKSsNCiAgeWxhYigiUmF0aW5nOiBGaXR0ZWQiKSt4bGFiKCJQZXJmb3JtZXIiKSsNCiAgICBnZ3RpdGxlKCdGaXhlZCArIFJhbmRvbSBJbnRlcmNlcHRzL1xuU2xvcGUgb2YgTGV2ZWwgYnkgU1MnKSsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KDQoNCk1QLkZpdHRlZC5NMGQgPC1nZ3Bsb3QoZGF0YSA9IE1QLkRhdGEsIGFlcyh4ID0gUGVyZiwgeT1GUmQsIGdyb3VwPVNTKSkrDQogICAgY29vcmRfY2FydGVzaWFuKHlsaW09YygwLDcpKSsNCiAgZmFjZXRfd3JhcCh+TGV2ZWwsIG5yb3c9MSkrDQogIGdlb21faml0dGVyKGFlcyhjb2xvdXIgPSBTUyksIHdpZHRoPS4xKSsNCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSwgYWVzKGdyb3VwPVNTLGNvbG91ciA9IFNTKSkrDQogIHlsYWIoIlJhdGluZzogRml0dGVkIikreGxhYigiUGVyZm9ybWVyIikrDQogICAgZ2d0aXRsZSgnRml4ZWQgKyBSYW5kb20gSW50ZXJjZXB0cy9cblNsb3BlIG9mIExldmVsK1BlcmYgYnkgU1MnKSsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KDQpncmlkLmFycmFuZ2UoTVAuRml0dGVkLk0wYyxNUC5GaXR0ZWQuTTBkLCBuY29sPTIpDQpgYGANCg0KLSBUaGlzIGNhcHR1cmVkIHRoZSBkaWZmZXJlbmNlcyBiZXR3ZWVuICpMZXZlbHMqIGFuZCAqUGVyZm9ybWVyKiwgYnV0IGlzIGl0IHBvc3NpYmxlIHRoYXQgdGhleSBpbnRlcmFjdD8NCi0gTGV0J3MgYWRkIGZpeGVkIGFuZCByYW5kb20gZWZmZWN0IG9mIGludGVyYWN0aW9uDQoNCiMjIDIgUmFuZG9tIENhdGVnb3JpY2FsIEZhY3RvcnMgSW50ZXJhY3RlZA0KDQpgYGB7cn0NCg0KTTQ8LWxtZXIoUmF0aW5nfiBMZXZlbCpQZXJmKyAoMStMZXZlbCtQZXJmfFNTKSwgZGF0YT1NUC5EYXRhLCBSRU1MPVRSVUUpDQpNNTwtbG1lcihSYXRpbmd+IExldmVsKlBlcmYrICgxK0xldmVsKlBlcmZ8U1MpLCBkYXRhPU1QLkRhdGEsIFJFTUw9VFJVRSkNCnN1bW1hcnkoTTUpDQpgYGANCg0KLSBMZXQncyBleGFtaW5lIHRoZSByYW5kb20gZWZmZWN0cyBpbiBtb3JlIGRldGFpbCAoc2hvcnRlbmVkIHZlcnNpb24pOg0KDQpgYGB7cn0NClIuTTU8LXJhbmVmKE01KQ0KYGBgDQoNCmBgYHtyLCBlY2hvPUZBTFNFfQ0KUi5NNS5IPC1oZWFkKFIuTTUkU1MpDQprYWJsZShSLk01LkgpICU+JQ0KICBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJob3ZlciIsICJjb25kZW5zZWQiLCAicmVzcG9uc2l2ZSIpKQ0KYGBgDQoNCiMjIyBQbG90IFByZWRpY3RlZCBSZXN1bHRzIA0KYGBge3J9DQpNUC5EYXRhJEZSZTwtcHJlZGljdChNNCkgICNGaXhlZCArIHJhbmRvbQ0KTVAuRGF0YSRGUmY8LXByZWRpY3QoTTUpICAjRml4ZWQgKyByYW5kb20NCmBgYA0KDQpgYGB7ciwgZWNobz1GQUxTRSxvdXQud2lkdGg9JzEwMCUnLCBmaWcuaGVpZ2h0PTIsZmlnLnNob3c9J2hvbGQnLGZpZy5hbGlnbj0nY2VudGVyJ30NCmxpYnJhcnkoZ3JpZEV4dHJhKQ0KdGhlbWVfc2V0KHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDcsIGJhc2VfZmFtaWx5ID0gIiIpKQ0KTVAuRml0dGVkLk0wYyA8LWdncGxvdChkYXRhID0gTVAuRGF0YSwgYWVzKHggPSBQZXJmLCB5PUZSZSwgZ3JvdXA9U1MpKSsNCiAgY29vcmRfY2FydGVzaWFuKHlsaW09YygwLDcpKSsNCiAgZmFjZXRfd3JhcCh+TGV2ZWwsIG5yb3c9MSkrDQogIGdlb21faml0dGVyKGFlcyhjb2xvdXIgPSBTUyksIHdpZHRoPS4xKSsNCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSwgYWVzKGdyb3VwPVNTLGNvbG91ciA9IFNTKSkrDQogIHlsYWIoIlJhdGluZzogRml0dGVkIikreGxhYigiUGVyZm9ybWVyIikrDQogICAgZ2d0aXRsZSgnRml4ZWQgKyBSYW5kb20gSW50ZXJjZXB0cy9cblNsb3BlIG9mIExldmVsK1BlcmYgYnkgU1MnKSsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KDQpNUC5GaXR0ZWQuTTBkIDwtZ2dwbG90KGRhdGEgPSBNUC5EYXRhLCBhZXMoeCA9IFBlcmYsIHk9RlJmLCBncm91cD1TUykpKw0KICAgIGNvb3JkX2NhcnRlc2lhbih5bGltPWMoMCw3KSkrDQogIGZhY2V0X3dyYXAofkxldmVsLCBucm93PTEpKw0KICBnZW9tX2ppdHRlcihhZXMoY29sb3VyID0gU1MpLCB3aWR0aD0uMSkrDQogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UsIGFlcyhncm91cD1TUyxjb2xvdXIgPSBTUykpKw0KICB5bGFiKCJSYXRpbmc6IEZpdHRlZCIpK3hsYWIoIlBlcmZvcm1lciIpKw0KICAgIGdndGl0bGUoJ0ZpeGVkICsgUmFuZG9tIEludGVyY2VwdHMvXG5TbG9wZSBvZiBMZXZlbCpQZXJmIGJ5IFNTJykrDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikNCg0KZ3JpZC5hcnJhbmdlKE1QLkZpdHRlZC5NMGMsTVAuRml0dGVkLk0wZCwgbmNvbD0yKQ0KYGBgDQoNCi0gQ2hlY2sgZml0DQoNCmBgYHtyLCBlY2hvPUZBTFNFfQ0KbGlicmFyeShrYWJsZUV4dHJhKQ0Ka2FibGUoYW5vdmEoTTAsTTEsTTIsTTMsTTQsTTUpKSU+JQ0KICBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJob3ZlciIsICJjb25kZW5zZWQiLCAicmVzcG9uc2l2ZSIsIGZ1bGxfd2lkdGggPSBGKSkNCmBgYA0KDQotIFRoZSBtb2RlbHMgc2VlbSB0byBzdXBwb3J0IHRoZSBjb25jbHVzaW9uIHRoYXQgd2Ugc2hvdWxkIGZ1bGx5IGNyb3NzIHRoZSByYW5kb20gZWZmZWN0cyBhbmQgYWNjb3VudCBmb3IgdGhlIHJhbmRvbSB2YXJpYW5jZSBvbiBib3RoIHRoZWlyIG1haW4gZWZmZWN0cyBhbmQgaW50ZXJhY3Rpb25zLCB3aGF0IEJhcnIgZXQgYWwuIDIwMTMgY2FsbCAqKmEgbWF4aW1hbCByYW5kb20gc3RydWN0dXJlKioNCi0gV2Ugd2lsbCBjb21lIGJhY2sgdG8gdGhpcyBjb25jZXB0IG5leHQgd2VlayBhbmQgdGFsayBpbiBtb3JlIGRldGFpbHMgYWJvdXQgdGhlIHByb2Nlc3Mgb2YgZml0dGluZyBjb21wbGV4IHJhbmRvbSBzdHJ1Y3R1cmVzDQotIFdlIHdpbGwgYWxzbyB0YWxrIGFib3V0IGhvdyB0byBkbyBwb3N0LWhvYyB0ZXN0aW5nIA0KDQojIyBOb3RlczoNCi0gTm90ZTogVGhlIGZpbmFsIG1vZGVsIHdhcyAyOCBkZWdyZWVzIG9mIGZyZWVkb20sIGFuZCBJIG9ubHkgaGFkIDE2IHN1YmplY3RzIChidXQgSSBoYWQgMTkyIG9ic2VydmF0aW9ucykNCiAgICAtIFRoaXMgYSBoaWdobHkgcGFyYW1ldGVyaXplZCBtb2RlbCBnaXZlbiB0aGUgc21hbGwgYW1vdW50IG9mIGRhdGEgSSBoYWQuIA0KICAgICAgICAtIFRoZSBmaW5hbCBtb2RlbCBoYWQgMTUgcmFuZG9tIGNvcnJlbGF0aW9ucyBiZXR3ZWVuIHRlcm1zLiANCiAgICAtIFlvdSB3aWxsIHJhcmVseSBnZXQgYSBmaXQgd2l0aCBzdWNoIGEgY29tcGxleCBtb2RlbCB3aXRoIHN1Y2ggbGl0dGxlIGRhdGENCg0KDQoNCjxzY3JpcHQ+DQogIChmdW5jdGlvbihpLHMsbyxnLHIsYSxtKXtpWydHb29nbGVBbmFseXRpY3NPYmplY3QnXT1yO2lbcl09aVtyXXx8ZnVuY3Rpb24oKXsNCiAgKGlbcl0ucT1pW3JdLnF8fFtdKS5wdXNoKGFyZ3VtZW50cyl9LGlbcl0ubD0xKm5ldyBEYXRlKCk7YT1zLmNyZWF0ZUVsZW1lbnQobyksDQogIG09cy5nZXRFbGVtZW50c0J5VGFnTmFtZShvKVswXTthLmFzeW5jPTE7YS5zcmM9ZzttLnBhcmVudE5vZGUuaW5zZXJ0QmVmb3JlKGEsbSkNCiAgfSkod2luZG93LGRvY3VtZW50LCdzY3JpcHQnLCdodHRwczovL3d3dy5nb29nbGUtYW5hbHl0aWNzLmNvbS9hbmFseXRpY3MuanMnLCdnYScpOw0KDQogIGdhKCdjcmVhdGUnLCAnVUEtOTA0MTUxNjAtMScsICdhdXRvJyk7DQogIGdhKCdzZW5kJywgJ3BhZ2V2aWV3Jyk7DQoNCjwvc2NyaXB0Pg0K