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
Subject Stimuli 1
1 AB
2 AB
  • 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)

Subject Stimuli 1 Stimuli 2
1 AB AB
2 AB AB
  • 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)

Subject Stimuli 1 Stimuli 2
1 A B
2 B A

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
Subject Stimuli 1 Stimuli 2 Stimuli 3 Stimuli 4
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

Correlated Measures

  • When subjects repeat trials or do multiple conditions, their scores tend to be correlated
    • We want to control for individual subject variability
    • In the formula below, we remove the shared variance from the standard error as measured by Pearson’s r between conditions

\[t = \frac{M_1-M_2}{\sqrt{\frac{S_1^2 + S_2^2}{n}-\frac{2rS_1S_2}{n}}}\]

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

  • Spagetti plot per person

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

  • Check fit
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