1 Multi-Level Models

  • Hierarchical designs: Students nested in classrooms [Clustered data] with student-level predictors
  • Multilevel designs: Students nested in classrooms with student-level and classroom-level predictors
  • Problem: Clustering means each student’s scores within each classroom might be correlated because they all have the same teacher (for example)

Levels

  • Level 1 = Smallest level (often subjects/students)
  • Level 2 = The group/cluster the students belong too (classrooms)
  • You can have high levels as well, such as Level 3 = Classrooms nested in schools

2 HLM with only Level 1 predictors

  • Controlling for classroom differences, but making predictions about students

2.1 Equations (two level model)

OLS Regression

\[ Y_i = \beta_1X_1 +\beta_0 + \epsilon\]

2.1.1 Level 1

  • Within each Group/Cluster (Students = \(i\) within Classroom 1 = \(j\), and we would replace \(j\) with \(g\) for Classroom 2 and so forth for each classroom!) \[y_{ij} = B_{1j}X_{ij} + B_{0j} + r_{ij} \]

  • Where \(B_{0j}\) = intercept in group j
  • Where \(B_{ij}\) = slope of students in group j
  • Where \(r_{ij}\) = residuals of each i (student) within group j

2.1.2 Level 2

  • Each Group/Cluster (Students = \(i\) within Classroom 1 = \(j\), Classroom 2 = \(g\), and so forth for each classroom)

Level 2 Intercept

\[B_{0j} = \gamma_{00}+u_{0j} \] - Where \(\gamma_{00}\) = intercept of the classroom - Where \(u_{0j}\) = random deviation of the classroom intercept from fixed population intercept - We assume students will vary randomly around the population intercept of classroom

Level 2 Slope

\[B_{1j} = \gamma_{10}+u_{1j} \]

  • Where \(\gamma_{10}\) = slope of the classroom
  • Where \(u_{1j}\) = random deviation of the classroom slope from fixed population slope
  • We assume students will vary randomly around the population intercept of classroom
  • Note: We would repeat this for each level of classroom we have (g, etc)

2.1.3 Mixed Equation

  • We put level 1 and level 2 together \[y_{ij} = (\gamma_{10}+u_{1j})X_{ij} + (\gamma_{00}+u_{0j})+ r_{ij} \]

2.1.3.1 Variance Components

  • We now have multiple sources of error in our equation
  • \(\sigma^2\) = variance of \(r_{ij}\), AKA variance due to error at level 1
  • \(\tau_{00}\) = variance of \(u_{0j}\), AKA variance of random intercepts at level 2
  • \(\tau_{11}\) = variance of \(u_{1j}\), AKA variance of random slopes at level 2
  • \(\tau_{01}\) = co-variance of \(u_{0j}\) and \(u_{1j}\), AKA random slopes and random intercept can correlate

2.2 ICC

  • The degree of clustering is measured via the inter-class correlation ICC
  • The proportion of total variance that is between the groups \[ ICC = \frac{\tau}{\tau + \sigma^2}\]

  • \(\tau\) = variance in a variable due to differences between a group
  • \(\sigma^2\) = total variance across groups
  • We would fit this on the null model (no level 1 predictors)
  • OLS regression would assumes, ICC = 0: each classroom is unrelated to the others, but MLM/HLM does not
  • If this value is large, it means that variance can be attributed to level 2

2.3 Example

  • 1 measurement per of math score of student in 4 classrooms
  • An unbalanced proportion of student in each classroom [prob = .7,.6,.4,.25], regardless of classroom, were told tell themselves they were special every day
  • Click here for the file that generated the simulation to generate the HLM.
  • Click here for the csv file
MLM.Data<-read.csv("RegressionClass/L13_MLM/HLM.csv")

2.3.1 Analysis

  • Note: dont forget to center your variable
  • When we center relative to all people and all groups, we will call this grand mean centering
library(lme4)     #mixed model package by Douglas Bates
library(ggplot2)  #GGplot package for visualizing data
### Center variable 
MLM.Data$SelfAff.C <- scale(MLM.Data$SelfAff, center=TRUE, scale=FALSE)[,]
#for plots we will also label it
MLM.Data$SelfAff <- factor(MLM.Data$SelfAff, 
                           levels=c(0,1),
                           labels=c("No","Yes"))

Let’s plot

theme_set(theme_bw(base_size = 12, base_family = "")) 
ClassRoom.Plot <-ggplot(data = MLM.Data, aes(x = SelfAff, y=Math,group=Classroom))+
  facet_grid( ~ Classroom)+
  geom_point(aes(colour = Classroom))+
  geom_smooth(method = "lm", se = TRUE, aes(colour = Classroom))+
  xlab("Self-affirmations")+ylab("Math Score")+
  theme(legend.position = "none")
ClassRoom.Plot

2.3.2 Modeling

Null Model

Model.Null<-lmer(Math ~1+(1|Classroom),  
                   data=MLM.Data, REML=FALSE)
summary(Model.Null)
## Linear mixed model fit by maximum likelihood  ['lmerMod']
## Formula: Math ~ 1 + (1 | Classroom)
##    Data: MLM.Data
## 
##      AIC      BIC   logLik deviance df.resid 
##   2135.9   2147.9  -1065.0   2129.9      397 
## 
## Scaled residuals: 
##     Min      1Q  Median      3Q     Max 
## -2.6200 -0.6457 -0.0375  0.7427  3.9849 
## 
## Random effects:
##  Groups    Name        Variance Std.Dev.
##  Classroom (Intercept) 24.21    4.921   
##  Residual              11.40    3.376   
## Number of obs: 400, groups:  Classroom, 4
## 
## Fixed effects:
##             Estimate Std. Error t value
## (Intercept)   28.517      2.466   11.56
  • Next we examine the intercepts for each person
ranef(Model.Null)
## $Classroom
##    (Intercept)
## C1   -6.948231
## C2   -1.527141
## C3    2.016522
## C4    6.458850
  • Look at ICC: The var and sd of these values are what was seen in the table above
  • I wrote it as a function for you to use in the future, just enter the model name
ICC.Model<-function(Model.Name) {
  tau.Null<-as.numeric(lapply(summary(Model.Name)$varcor, diag))
  sigma.Null <- as.numeric(attr(summary(Model.Name)$varcor, "sc")^2)
  ICC.Null <- tau.Null/(tau.Null+sigma.Null)
  return(ICC.Null)
}
  • The ICC = 0.6799378 > 0, meaning we were correct to think of this as MLM/HLM problem

Test Model

Model.1<-lmer(Math ~ SelfAff.C+(1|Classroom),  
                   data=MLM.Data, REML=FALSE)
summary(Model.1)
## Linear mixed model fit by maximum likelihood  ['lmerMod']
## Formula: Math ~ SelfAff.C + (1 | Classroom)
##    Data: MLM.Data
## 
##      AIC      BIC   logLik deviance df.resid 
##   2084.0   2099.9  -1038.0   2076.0      396 
## 
## Scaled residuals: 
##     Min      1Q  Median      3Q     Max 
## -2.9293 -0.6462 -0.0109  0.6702  3.9940 
## 
## Random effects:
##  Groups    Name        Variance Std.Dev.
##  Classroom (Intercept) 27.255   5.221   
##  Residual               9.933   3.152   
## Number of obs: 400, groups:  Classroom, 4
## 
## Fixed effects:
##             Estimate Std. Error t value
## (Intercept)  28.5175     2.6151  10.905
## SelfAff.C     2.4902     0.3272   7.612
## 
## Correlation of Fixed Effects:
##           (Intr)
## SelfAff.C 0.000

2.3.2.1 Ignored classroom random variable?

  • Then we are doing a t-test/simple linear regression

Plot

Overall.Plot <-ggplot(data = MLM.Data, aes(x = as.factor(SelfAff.C), y=Math))+
  geom_boxplot()+
  geom_jitter(aes(colour = Classroom))+
  xlab("Self-affirmations")+ylab("Math Score")+
  theme(legend.position = "none")
Overall.Plot

Test Model

Model.LM<-lm(Math ~SelfAff.C,  
                   data=MLM.Data)
summary(Model.LM)
## 
## Call:
## lm(formula = Math ~ SelfAff.C, data = MLM.Data)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -14.4019  -4.4070   0.6187   4.1174  13.6849 
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)    
## (Intercept) 28.51750    0.29911  95.340   <2e-16 ***
## SelfAff.C   -0.02765    0.59931  -0.046    0.963    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 5.982 on 398 degrees of freedom
## Multiple R-squared:  5.347e-06,  Adjusted R-squared:  -0.002507 
## F-statistic: 0.002128 on 1 and 398 DF,  p-value: 0.9632
  • The effect goes negative and near zero, as it seems that self-affirmations does not help kids do better on math!
  • This flip does not always occur (this is a special case), more often you can get the effect to look much bigger than it really is
  • Regardless you always needs model the levels if you know them

3 MLM with Level 1 and Level 2 predictors

  • Making predictions about students (Level 1) and how known differences in classroom (level 2) can affect or even interact with Level 1

3.1 Equations

Level 1 remains the same as above

Level 2 Intercept

\[B_{0j} = \gamma_{01}W_j+\gamma_{00}+u_{0j} \]

  • Where \(W_j\) = predictor of level 2 (classroom)
  • Where \(\gamma_{10}\) = new fixed effect on the level 2 predictor of the classroom
  • Where \(\gamma_{00}\) = intercept of the classroom
  • Where \(u_{0j}\) = random deviation of the classroom intercept from fixed population intercept
  • We assume students will vary randomly around the population intercept of classroom

Level 2 Slope

\[B_{1j} = \gamma_{11}W_j+\gamma_{10}+u_{1j} \]

  • Where \(W_j\) = predictor of level 2 (classroom)
  • Where \(\gamma_{11}\) = new fixed effect on the level 2 predictor of the classroom
  • Where \(\gamma_{10}\) = slope of the classroom
  • Where \(u_{1j}\) = random deviation of the classroom slope from fixed population slope
  • We assume students will vary randomly around the population intercept of classroom
  • Note: We would repeat this for each level of classroom we have (g, etc)

3.1.1 Mixed Equation

  • We put level 1 and level 2 together \[y_{ij} = (\gamma_{11}W_j+\gamma_{10}+u_{1j})X_{ij} + (\gamma_{01}W_j+\gamma_{00}+u_{0j})+ r_{ij} \]

3.2 Example

  • Same study as before, but there is a level 2 variable we can example
  • Each kid reported how supported they felt in their classroom
  • Lets examine the new variable
ClassRoom.Support <-ggplot(data = MLM.Data, aes(x = Support, y=Math,group=Classroom))+
  facet_grid(SelfAff ~ Classroom)+
  geom_point(aes(colour = Classroom))+
  geom_smooth(method = "lm", se = TRUE, aes(colour = Classroom))+
  xlab("Support")+ylab("Math Score")+
  theme(legend.position = "none")
ClassRoom.Support

  • Problem seems that class support changes as a function of the classroom.
  • Basically it presents a potential problem: Might the difference in schools be the product of how supported they feel or vice versa?
  • So its not simply a level 1 predictor, its actually might be a level 2 predictor!
  • In other words if we try to use it as it (a level 1 predictor) its nested by classroom
  • Lets try to model it simply a level 1 and see what get

Null Model (same as before)

Model.0<-lmer(Math ~ SelfAff.C+(1|Classroom),  
              data=MLM.Data, REML=FALSE)
summary(Model.0)
## Linear mixed model fit by maximum likelihood  ['lmerMod']
## Formula: Math ~ SelfAff.C + (1 | Classroom)
##    Data: MLM.Data
## 
##      AIC      BIC   logLik deviance df.resid 
##   2084.0   2099.9  -1038.0   2076.0      396 
## 
## Scaled residuals: 
##     Min      1Q  Median      3Q     Max 
## -2.9293 -0.6462 -0.0109  0.6702  3.9940 
## 
## Random effects:
##  Groups    Name        Variance Std.Dev.
##  Classroom (Intercept) 27.255   5.221   
##  Residual               9.933   3.152   
## Number of obs: 400, groups:  Classroom, 4
## 
## Fixed effects:
##             Estimate Std. Error t value
## (Intercept)  28.5175     2.6151  10.905
## SelfAff.C     2.4902     0.3272   7.612
## 
## Correlation of Fixed Effects:
##           (Intr)
## SelfAff.C 0.000

Test Model 1 Level 1 Variables

### Center variable
MLM.Data$Support.C <- scale(MLM.Data$Support, center=TRUE, scale=FALSE)

Model.1<-lmer(Math ~ SelfAff.C*Support.C+(1|Classroom),  
              data=MLM.Data, REML=FALSE)
summary(Model.1)
## Linear mixed model fit by maximum likelihood  ['lmerMod']
## Formula: Math ~ SelfAff.C * Support.C + (1 | Classroom)
##    Data: MLM.Data
## 
##      AIC      BIC   logLik deviance df.resid 
##   2061.5   2085.4  -1024.7   2049.5      394 
## 
## Scaled residuals: 
##     Min      1Q  Median      3Q     Max 
## -2.7464 -0.6571  0.0162  0.6893  3.9025 
## 
## Random effects:
##  Groups    Name        Variance Std.Dev.
##  Classroom (Intercept) 32.617   5.711   
##  Residual               9.274   3.045   
## Number of obs: 400, groups:  Classroom, 4
## 
## Fixed effects:
##                     Estimate Std. Error t value
## (Intercept)          28.3405     2.8599   9.910
## SelfAff.C             2.4220     0.3170   7.640
## Support.C             0.4919     0.1557   3.160
## SelfAff.C:Support.C   0.8946     0.2007   4.458
## 
## Correlation of Fixed Effects:
##             (Intr) SlfA.C Sppr.C
## SelfAff.C    0.000              
## Support.C   -0.001 -0.074       
## SlfAf.C:S.C -0.014 -0.004  0.093
  • But the problem is we know that Support changes a function of the classroom, so could it be that effect of support is not about the differences how kids feel supported but really that on average the kids in the different schools all feel supported on average differently?
  • So lets control the random slopes of Support at the level 2: Control for support as a function of classroom
  • We can do this is because each person’s slope is believed to measuring the distribution around the population slope
  • Basically think of each person a repeated measurement of each group

Test Model 2 Level 1 Variables and level 2 Variable

Model.2<-lmer(Math ~ SelfAff.C*Support.C+(1+Support.C|Classroom),  
              data=MLM.Data, REML=FALSE)
summary(Model.2)
## Linear mixed model fit by maximum likelihood  ['lmerMod']
## Formula: Math ~ SelfAff.C * Support.C + (1 + Support.C | Classroom)
##    Data: MLM.Data
## 
##      AIC      BIC   logLik deviance df.resid 
##   2065.2   2097.1  -1024.6   2049.2      392 
## 
## Scaled residuals: 
##     Min      1Q  Median      3Q     Max 
## -2.7603 -0.6692  0.0178  0.6928  3.9138 
## 
## Random effects:
##  Groups    Name        Variance  Std.Dev. Corr
##  Classroom (Intercept) 32.942043 5.73952      
##            Support.C    0.007699 0.08775  1.00
##  Residual               9.266165 3.04404      
## Number of obs: 400, groups:  Classroom, 4
## 
## Fixed effects:
##                     Estimate Std. Error t value
## (Intercept)          28.4399     2.8741   9.895
## SelfAff.C             2.4015     0.3168   7.581
## Support.C             0.5028     0.1621   3.102
## SelfAff.C:Support.C   0.9226     0.2006   4.600
## 
## Correlation of Fixed Effects:
##             (Intr) SlfA.C Sppr.C
## SelfAff.C    0.000              
## Support.C    0.270 -0.072       
## SlfAf.C:S.C -0.014 -0.003  0.094
  • Wait there is a problem with this, the correlation between support and classroom intercept is 1.
  • This means that the two variables are predicting the same thing
  • Thus our level 2 predictor is confounded with intercept
  • We can fix this by “centering” the level 2 variable relative to the classroom
  • In other words, how much deviation does each student have from the mean of the other students
  • If the class centered support variable predicts math score, we can be sure it isa unique predictor
  • Now we ask: how much to they differ from their cohort
  • We will call this procedure, Group Centering
library(plyr)
# Create a new variable in the data which is the mean of support per class room (at each subject)
MLM.Data<-ddply(MLM.Data,.(Classroom), mutate, ClassSupport = mean(Support))
# next we center relative to each student relative to their class mean (how much to they differ from their cohort)
MLM.Data$Support.Class.Centered<-MLM.Data$Support-MLM.Data$ClassSupport

Test Model 3 Level 1 Variables and level 2 Variable (group centered)

Model.3<-lmer(Math ~ SelfAff.C*Support.Class.Centered+(1+Support.Class.Centered|Classroom),  
              data=MLM.Data, REML=FALSE)
summary(Model.3)
## Linear mixed model fit by maximum likelihood  ['lmerMod']
## Formula: 
## Math ~ SelfAff.C * Support.Class.Centered + (1 + Support.Class.Centered |  
##     Classroom)
##    Data: MLM.Data
## 
##      AIC      BIC   logLik deviance df.resid 
##   2077.7   2109.7  -1030.9   2061.7      392 
## 
## Scaled residuals: 
##     Min      1Q  Median      3Q     Max 
## -3.0079 -0.6497 -0.0203  0.6786  3.9855 
## 
## Random effects:
##  Groups    Name                   Variance Std.Dev. Corr
##  Classroom (Intercept)            26.7293  5.170        
##            Support.Class.Centered  0.0169  0.130    0.24
##  Residual                          9.5701  3.094        
## Number of obs: 400, groups:  Classroom, 4
## 
## Fixed effects:
##                                  Estimate Std. Error t value
## (Intercept)                       28.4893     2.5897  11.001
## SelfAff.C                          2.4011     0.3224   7.448
## Support.Class.Centered             0.4654     0.1710   2.721
## SelfAff.C:Support.Class.Centered   0.8122     0.3197   2.541
## 
## Correlation of Fixed Effects:
##             (Intr) SlfA.C Sp.C.C
## SelfAff.C    0.000              
## Spprt.Cls.C  0.091 -0.069       
## SlA.C:S.C.C -0.004 -0.016  0.045
  • Now we see smaller effects of support, but significant and and a significant interaction
  • Let’s plot it up

Plot

library(effects)
Results.Model.3<-Effect(c("SelfAff.C","Support.Class.Centered"),Model.3,
     xlevels=list(SelfAff.C=c(min(MLM.Data$SelfAff.C),max(MLM.Data$SelfAff.C)),
                  Support.Class.Centered=c(-sd(MLM.Data$Support.Class.Centered),
                                           sd(MLM.Data$Support.Class.Centered))))
Results.Model.3<-as.data.frame(Results.Model.3)
Results.Model.3$SelfAff.C<-factor(Results.Model.3$SelfAff.C,
                              levels=c(min(MLM.Data$SelfAff.C),max(MLM.Data$SelfAff.C)),
                              labels=c("No Self-A", "Yes Self-A"))
Final.Fixed.Plot <-ggplot(data = Results.Model.3, aes(x = Support.Class.Centered, y =fit, group=SelfAff.C))+
  geom_line(aes(color=SelfAff.C), size=2)+
  geom_ribbon(aes(ymin=fit-se, ymax=fit+se,fill=SelfAff.C),alpha=.2)+
  xlab("Support")+
  ylab("Math Score")+
  scale_color_manual(values=c("blue", "red"))+
  scale_fill_manual(values=c("blue", "red"))+
  theme_bw()+
  theme(text=element_text(face="bold", size=12),
        panel.grid.major = element_blank(), 
        panel.grid.minor = element_blank(), 
        panel.border = element_rect(fill = NA, colour = "NA"),
        axis.line = element_line(size = 1, colour = "grey80"),
        legend.title=element_blank(),
        legend.position = "top")
Final.Fixed.Plot

3.2.1 Grand mean vs group centering

  • When to center at the grand mean or the group
  • This depends on your question and the data
  • You may want to ask a grand mean question (how all people are impacted by the predictor regardless of group), but the data many not allow that question to be asked (if the predictor is confounded with group)
  • The problem in this study is a result of the problem that we had too few classrooms, however, even in large data sets this problem can remain
  • Group centering asks how does the within group variation of the predictor predict the outcome
  • This is often a very interesting question and may not always differ in story from the grand mean
  • However, technically its meaning has changed! So, you must think about what it means for your data to have centered within group
LS0tDQp0aXRsZTogJ011bHRpLUxldmVsIE1vZGVscycNCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDoNCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMNCiAgICBmb250c2l6ZTogOHB0DQogICAgaGlnaGxpZ2h0OiB0ZXh0bWF0ZQ0KICAgIG51bWJlcl9zZWN0aW9uczogeWVzDQogICAgdGhlbWU6IGZsYXRseQ0KICAgIHRvYzogeWVzDQogICAgdG9jX2Zsb2F0Og0KICAgICAgY29sbGFwc2VkOiBubw0KLS0tDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KG1lc3NhZ2UgPSBGQUxTRSkNCmtuaXRyOjpvcHRzX2NodW5rJHNldCh3YXJuaW5nID0gIEZBTFNFKQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGZpZy53aWR0aD0zLjI1KQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGZpZy5oZWlnaHQ9My4wKQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGZpZy5hbGlnbj0nY2VudGVyJykgDQpgYGANCg0KDQojIE11bHRpLUxldmVsIE1vZGVscw0KLSBIaWVyYXJjaGljYWwgZGVzaWduczogU3R1ZGVudHMgbmVzdGVkIGluIGNsYXNzcm9vbXMgW0NsdXN0ZXJlZCBkYXRhXSB3aXRoIHN0dWRlbnQtbGV2ZWwgcHJlZGljdG9ycyANCi0gTXVsdGlsZXZlbCBkZXNpZ25zOiBTdHVkZW50cyBuZXN0ZWQgaW4gY2xhc3Nyb29tcyB3aXRoIHN0dWRlbnQtbGV2ZWwgYW5kIGNsYXNzcm9vbS1sZXZlbCBwcmVkaWN0b3JzIA0KLSBQcm9ibGVtOiBDbHVzdGVyaW5nIG1lYW5zIGVhY2ggc3R1ZGVudCdzIHNjb3JlcyB3aXRoaW4gZWFjaCBjbGFzc3Jvb20gbWlnaHQgYmUgY29ycmVsYXRlZCBiZWNhdXNlIHRoZXkgYWxsIGhhdmUgdGhlIHNhbWUgdGVhY2hlciAoZm9yIGV4YW1wbGUpDQoNCipMZXZlbHMqDQoNCi0gTGV2ZWwgMSA9IFNtYWxsZXN0IGxldmVsIChvZnRlbiBzdWJqZWN0cy9zdHVkZW50cykNCi0gTGV2ZWwgMiA9IFRoZSBncm91cC9jbHVzdGVyIHRoZSBzdHVkZW50cyBiZWxvbmcgdG9vIChjbGFzc3Jvb21zKQ0KLSBZb3UgY2FuIGhhdmUgaGlnaCBsZXZlbHMgYXMgd2VsbCwgc3VjaCBhcyBMZXZlbCAzID0gQ2xhc3Nyb29tcyBuZXN0ZWQgaW4gc2Nob29scw0KDQojIEhMTSB3aXRoIG9ubHkgKipMZXZlbCAxKiogcHJlZGljdG9ycyANCi0gQ29udHJvbGxpbmcgZm9yIGNsYXNzcm9vbSBkaWZmZXJlbmNlcywgYnV0IG1ha2luZyBwcmVkaWN0aW9ucyBhYm91dCBzdHVkZW50cw0KDQojIyBFcXVhdGlvbnMgKHR3byBsZXZlbCBtb2RlbCkNCg0KKk9MUyBSZWdyZXNzaW9uKg0KDQokJCBZX2kgPSBcYmV0YV8xWF8xICtcYmV0YV8wICsgXGVwc2lsb24kJA0KDQoNCg0KDQoNCiMjIyAqKkxldmVsIDEqKiANCi0gV2l0aGluIGVhY2ggR3JvdXAvQ2x1c3RlciAoU3R1ZGVudHMgPSAkaSQgd2l0aGluIENsYXNzcm9vbSAxID0gJGokLCBhbmQgd2Ugd291bGQgcmVwbGFjZSAkaiQgd2l0aCAkZyQgZm9yIENsYXNzcm9vbSAyIGFuZCBzbyBmb3J0aCBmb3IgZWFjaCBjbGFzc3Jvb20hKQ0KJCR5X3tpan0gPSBCX3sxan1YX3tpan0gKyBCX3swan0gKyByX3tpan0gJCQNCg0KLSBXaGVyZSAkQl97MGp9JCA9IGludGVyY2VwdCBpbiBncm91cCBqDQotIFdoZXJlICRCX3tpan0kID0gc2xvcGUgb2Ygc3R1ZGVudHMgaW4gZ3JvdXAgag0KLSBXaGVyZSAkcl97aWp9JCA9IHJlc2lkdWFscyBvZiBlYWNoIGkgKHN0dWRlbnQpIHdpdGhpbiBncm91cCBqDQoNCiMjIyAqKkxldmVsIDIqKiANCi0gRWFjaCBHcm91cC9DbHVzdGVyIChTdHVkZW50cyA9ICRpJCB3aXRoaW4gQ2xhc3Nyb29tIDEgPSAkaiQsIENsYXNzcm9vbSAyID0gJGckLCBhbmQgc28gZm9ydGggZm9yIGVhY2ggY2xhc3Nyb29tKQ0KDQoqTGV2ZWwgMiBJbnRlcmNlcHQqIA0KDQokJEJfezBqfSA9IFxnYW1tYV97MDB9K3VfezBqfSAkJA0KLSBXaGVyZSAkXGdhbW1hX3swMH0kID0gaW50ZXJjZXB0IG9mIHRoZSBjbGFzc3Jvb20NCi0gV2hlcmUgJHVfezBqfSQgPSByYW5kb20gZGV2aWF0aW9uIG9mIHRoZSBjbGFzc3Jvb20gaW50ZXJjZXB0IGZyb20gZml4ZWQgcG9wdWxhdGlvbiBpbnRlcmNlcHQNCi0gV2UgYXNzdW1lIHN0dWRlbnRzIHdpbGwgdmFyeSByYW5kb21seSBhcm91bmQgdGhlIHBvcHVsYXRpb24gaW50ZXJjZXB0IG9mIGNsYXNzcm9vbQ0KIA0KKkxldmVsIDIgU2xvcGUqIA0KDQokJEJfezFqfSA9IFxnYW1tYV97MTB9K3VfezFqfSAkJA0KDQotIFdoZXJlICRcZ2FtbWFfezEwfSQgPSBzbG9wZSBvZiB0aGUgY2xhc3Nyb29tDQotIFdoZXJlICR1X3sxan0kID0gcmFuZG9tIGRldmlhdGlvbiBvZiB0aGUgY2xhc3Nyb29tIHNsb3BlIGZyb20gZml4ZWQgcG9wdWxhdGlvbiBzbG9wZQ0KLSBXZSBhc3N1bWUgc3R1ZGVudHMgd2lsbCB2YXJ5IHJhbmRvbWx5IGFyb3VuZCB0aGUgcG9wdWxhdGlvbiBpbnRlcmNlcHQgb2YgY2xhc3Nyb29tDQotIE5vdGU6IFdlIHdvdWxkIHJlcGVhdCB0aGlzIGZvciBlYWNoIGxldmVsIG9mIGNsYXNzcm9vbSB3ZSBoYXZlIChnLCBldGMpDQoNCiMjIyBNaXhlZCBFcXVhdGlvbg0KLSBXZSBwdXQgbGV2ZWwgMSBhbmQgbGV2ZWwgMiB0b2dldGhlcg0KJCR5X3tpan0gPSAoXGdhbW1hX3sxMH0rdV97MWp9KVhfe2lqfSArICAoXGdhbW1hX3swMH0rdV97MGp9KSsgcl97aWp9ICQkDQoNCiMjIyMgVmFyaWFuY2UgQ29tcG9uZW50cw0KLSBXZSBub3cgaGF2ZSBtdWx0aXBsZSBzb3VyY2VzIG9mIGVycm9yIGluIG91ciBlcXVhdGlvbg0KLSAkXHNpZ21hXjIkID0gdmFyaWFuY2Ugb2YgJHJfe2lqfSQsIEFLQSB2YXJpYW5jZSBkdWUgdG8gZXJyb3IgYXQgbGV2ZWwgMQ0KLSAkXHRhdV97MDB9JCA9IHZhcmlhbmNlIG9mICR1X3swan0kLCBBS0EgdmFyaWFuY2Ugb2YgcmFuZG9tIGludGVyY2VwdHMgYXQgbGV2ZWwgMg0KLSAkXHRhdV97MTF9JCA9IHZhcmlhbmNlIG9mICR1X3sxan0kLCBBS0EgdmFyaWFuY2Ugb2YgcmFuZG9tIHNsb3BlcyBhdCBsZXZlbCAyDQotICRcdGF1X3swMX0kID0gY28tdmFyaWFuY2Ugb2YgJHVfezBqfSQgYW5kICR1X3sxan0kLCBBS0EgcmFuZG9tIHNsb3BlcyBhbmQgcmFuZG9tIGludGVyY2VwdCBjYW4gY29ycmVsYXRlDQoNCiMjIElDQw0KLSBUaGUgZGVncmVlIG9mIGNsdXN0ZXJpbmcgaXMgbWVhc3VyZWQgdmlhIHRoZSBpbnRlci1jbGFzcyBjb3JyZWxhdGlvbiAqKklDQyoqDQotIFRoZSBwcm9wb3J0aW9uIG9mIHRvdGFsIHZhcmlhbmNlIHRoYXQgaXMgYmV0d2VlbiB0aGUgZ3JvdXBzDQokJCBJQ0MgPSBcZnJhY3tcdGF1fXtcdGF1ICsgXHNpZ21hXjJ9JCQNCg0KLSAkXHRhdSQgPSB2YXJpYW5jZSBpbiBhIHZhcmlhYmxlIGR1ZSB0byBkaWZmZXJlbmNlcyBiZXR3ZWVuIGEgZ3JvdXANCi0gJFxzaWdtYV4yJCA9IHRvdGFsIHZhcmlhbmNlIGFjcm9zcyBncm91cHMNCi0gV2Ugd291bGQgZml0IHRoaXMgb24gdGhlIG51bGwgbW9kZWwgKG5vIGxldmVsIDEgcHJlZGljdG9ycykNCi0gT0xTIHJlZ3Jlc3Npb24gd291bGQgYXNzdW1lcywgSUNDID0gMDogIGVhY2ggY2xhc3Nyb29tIGlzIHVucmVsYXRlZCB0byB0aGUgb3RoZXJzLCBidXQgTUxNL0hMTSBkb2VzIG5vdA0KLSBJZiB0aGlzIHZhbHVlIGlzIGxhcmdlLCBpdCBtZWFucyB0aGF0IHZhcmlhbmNlIGNhbiBiZSBhdHRyaWJ1dGVkIHRvIGxldmVsIDIgDQoNCiMjIEV4YW1wbGUNCi0gMSBtZWFzdXJlbWVudCBwZXIgb2YgbWF0aCBzY29yZSBvZiBzdHVkZW50IGluIDQgY2xhc3Nyb29tcw0KLSBBbiB1bmJhbGFuY2VkIHByb3BvcnRpb24gb2Ygc3R1ZGVudCBpbiBlYWNoIGNsYXNzcm9vbSBbcHJvYiA9IC43LC42LC40LC4yNV0sIHJlZ2FyZGxlc3Mgb2YgY2xhc3Nyb29tLCB3ZXJlIHRvbGQgdGVsbCB0aGVtc2VsdmVzIHRoZXkgd2VyZSBzcGVjaWFsIGV2ZXJ5IGRheQ0KLSBbQ2xpY2sgaGVyZV0oUmVncmVzc2lvbkNsYXNzL0wxM19NTE0vU2ltdWxhdGlvbi5SKSBmb3IgdGhlIGZpbGUgdGhhdCBnZW5lcmF0ZWQgdGhlIHNpbXVsYXRpb24gdG8gZ2VuZXJhdGUgdGhlIEhMTS4gDQotIFtDbGljayBoZXJlIGZvciB0aGUgY3N2IGZpbGVdKFJlZ3Jlc3Npb25DbGFzcy9MMTNfTUxNL0hMTS5jc3YpDQoNCmBgYHtyfQ0KTUxNLkRhdGE8LXJlYWQuY3N2KCJSZWdyZXNzaW9uQ2xhc3MvTDEzX01MTS9ITE0uY3N2IikNCmBgYA0KDQojIyMgQW5hbHlzaXMNCi0gTm90ZTogZG9udCBmb3JnZXQgdG8gY2VudGVyIHlvdXIgdmFyaWFibGUNCi0gV2hlbiB3ZSBjZW50ZXIgcmVsYXRpdmUgdG8gYWxsIHBlb3BsZSBhbmQgYWxsIGdyb3Vwcywgd2Ugd2lsbCBjYWxsIHRoaXMgKipncmFuZCBtZWFuKiogY2VudGVyaW5nDQoNCmBgYHtyfQ0KbGlicmFyeShsbWU0KSAgICAgI21peGVkIG1vZGVsIHBhY2thZ2UgYnkgRG91Z2xhcyBCYXRlcw0KbGlicmFyeShnZ3Bsb3QyKSAgI0dHcGxvdCBwYWNrYWdlIGZvciB2aXN1YWxpemluZyBkYXRhDQojIyMgQ2VudGVyIHZhcmlhYmxlIA0KTUxNLkRhdGEkU2VsZkFmZi5DIDwtIHNjYWxlKE1MTS5EYXRhJFNlbGZBZmYsIGNlbnRlcj1UUlVFLCBzY2FsZT1GQUxTRSlbLF0NCiNmb3IgcGxvdHMgd2Ugd2lsbCBhbHNvIGxhYmVsIGl0DQpNTE0uRGF0YSRTZWxmQWZmIDwtIGZhY3RvcihNTE0uRGF0YSRTZWxmQWZmLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscz1jKDAsMSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHM9YygiTm8iLCJZZXMiKSkNCmBgYA0KDQoqTGV0J3MgcGxvdCoNCg0KYGBge3J9DQp0aGVtZV9zZXQodGhlbWVfYncoYmFzZV9zaXplID0gMTIsIGJhc2VfZmFtaWx5ID0gIiIpKSANCkNsYXNzUm9vbS5QbG90IDwtZ2dwbG90KGRhdGEgPSBNTE0uRGF0YSwgYWVzKHggPSBTZWxmQWZmLCB5PU1hdGgsZ3JvdXA9Q2xhc3Nyb29tKSkrDQogIGZhY2V0X2dyaWQoIH4gQ2xhc3Nyb29tKSsNCiAgZ2VvbV9wb2ludChhZXMoY29sb3VyID0gQ2xhc3Nyb29tKSkrDQogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gVFJVRSwgYWVzKGNvbG91ciA9IENsYXNzcm9vbSkpKw0KICB4bGFiKCJTZWxmLWFmZmlybWF0aW9ucyIpK3lsYWIoIk1hdGggU2NvcmUiKSsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KQ2xhc3NSb29tLlBsb3QNCmBgYA0KDQojIyMgTW9kZWxpbmcNCg0KKk51bGwgTW9kZWwqDQoNCmBgYHtyfQ0KTW9kZWwuTnVsbDwtbG1lcihNYXRoIH4xKygxfENsYXNzcm9vbSksICANCiAgICAgICAgICAgICAgICAgICBkYXRhPU1MTS5EYXRhLCBSRU1MPUZBTFNFKQ0Kc3VtbWFyeShNb2RlbC5OdWxsKQ0KYGBgDQoNCi0gTmV4dCB3ZSBleGFtaW5lIHRoZSBpbnRlcmNlcHRzIGZvciBlYWNoIHBlcnNvbg0KDQpgYGB7cn0NCnJhbmVmKE1vZGVsLk51bGwpDQpgYGANCg0KLSBMb29rIGF0IElDQzogVGhlIHZhciBhbmQgc2Qgb2YgdGhlc2UgdmFsdWVzIGFyZSB3aGF0IHdhcyBzZWVuIGluIHRoZSB0YWJsZSBhYm92ZQ0KLSBJIHdyb3RlIGl0IGFzIGEgZnVuY3Rpb24gZm9yIHlvdSB0byB1c2UgaW4gdGhlIGZ1dHVyZSwganVzdCBlbnRlciB0aGUgbW9kZWwgbmFtZQ0KDQpgYGB7cn0NCklDQy5Nb2RlbDwtZnVuY3Rpb24oTW9kZWwuTmFtZSkgew0KICB0YXUuTnVsbDwtYXMubnVtZXJpYyhsYXBwbHkoc3VtbWFyeShNb2RlbC5OYW1lKSR2YXJjb3IsIGRpYWcpKQ0KICBzaWdtYS5OdWxsIDwtIGFzLm51bWVyaWMoYXR0cihzdW1tYXJ5KE1vZGVsLk5hbWUpJHZhcmNvciwgInNjIileMikNCiAgSUNDLk51bGwgPC0gdGF1Lk51bGwvKHRhdS5OdWxsK3NpZ21hLk51bGwpDQogIHJldHVybihJQ0MuTnVsbCkNCn0NCmBgYA0KDQotIFRoZSBJQ0MgPSBgciBJQ0MuTW9kZWwoTW9kZWwuTnVsbClgID4gMCwgbWVhbmluZyB3ZSB3ZXJlIGNvcnJlY3QgdG8gdGhpbmsgb2YgdGhpcyBhcyBNTE0vSExNIHByb2JsZW0NCg0KKlRlc3QgTW9kZWwqDQpgYGB7cn0NCk1vZGVsLjE8LWxtZXIoTWF0aCB+IFNlbGZBZmYuQysoMXxDbGFzc3Jvb20pLCAgDQogICAgICAgICAgICAgICAgICAgZGF0YT1NTE0uRGF0YSwgUkVNTD1GQUxTRSkNCnN1bW1hcnkoTW9kZWwuMSkNCmBgYA0KDQojIyMjIElnbm9yZWQgY2xhc3Nyb29tIHJhbmRvbSB2YXJpYWJsZT8gDQotIFRoZW4gd2UgYXJlIGRvaW5nIGEgdC10ZXN0L3NpbXBsZSBsaW5lYXIgcmVncmVzc2lvbg0KDQoqUGxvdCoNCmBgYHtyfQ0KT3ZlcmFsbC5QbG90IDwtZ2dwbG90KGRhdGEgPSBNTE0uRGF0YSwgYWVzKHggPSBhcy5mYWN0b3IoU2VsZkFmZi5DKSwgeT1NYXRoKSkrDQogIGdlb21fYm94cGxvdCgpKw0KICBnZW9tX2ppdHRlcihhZXMoY29sb3VyID0gQ2xhc3Nyb29tKSkrDQogIHhsYWIoIlNlbGYtYWZmaXJtYXRpb25zIikreWxhYigiTWF0aCBTY29yZSIpKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpDQpPdmVyYWxsLlBsb3QNCmBgYA0KDQoqVGVzdCBNb2RlbCoNCmBgYHtyfQ0KTW9kZWwuTE08LWxtKE1hdGggflNlbGZBZmYuQywgIA0KICAgICAgICAgICAgICAgICAgIGRhdGE9TUxNLkRhdGEpDQpzdW1tYXJ5KE1vZGVsLkxNKQ0KYGBgDQoNCi0gVGhlIGVmZmVjdCBnb2VzIG5lZ2F0aXZlIGFuZCBuZWFyIHplcm8sIGFzIGl0IHNlZW1zIHRoYXQgc2VsZi1hZmZpcm1hdGlvbnMgZG9lcyBub3QgaGVscCBraWRzIGRvIGJldHRlciBvbiBtYXRoISANCi0gVGhpcyBmbGlwIGRvZXMgbm90IGFsd2F5cyBvY2N1ciAodGhpcyBpcyBhIHNwZWNpYWwgY2FzZSksIG1vcmUgb2Z0ZW4geW91IGNhbiBnZXQgdGhlIGVmZmVjdCB0byBsb29rIG11Y2ggYmlnZ2VyIHRoYW4gaXQgcmVhbGx5IGlzDQotIFJlZ2FyZGxlc3MgeW91IGFsd2F5cyBuZWVkcyBtb2RlbCB0aGUgbGV2ZWxzIGlmIHlvdSBrbm93IHRoZW0NCg0KIyBNTE0gd2l0aCAqKkxldmVsIDEqKiBhbmQgKipMZXZlbCAyKiogcHJlZGljdG9ycw0KDQotIE1ha2luZyBwcmVkaWN0aW9ucyBhYm91dCBzdHVkZW50cyAoKipMZXZlbCAxKiopIGFuZCBob3cga25vd24gZGlmZmVyZW5jZXMgaW4gY2xhc3Nyb29tICgqKmxldmVsIDIqKikgY2FuIGFmZmVjdCBvciBldmVuIGludGVyYWN0IHdpdGggKipMZXZlbCAxKioNCg0KIyMgRXF1YXRpb25zDQoqTGV2ZWwgMSogcmVtYWlucyB0aGUgc2FtZSBhcyBhYm92ZQ0KDQoqTGV2ZWwgMiBJbnRlcmNlcHQqIA0KDQokJEJfezBqfSA9IFxnYW1tYV97MDF9V19qK1xnYW1tYV97MDB9K3VfezBqfSAkJA0KDQotIFdoZXJlICRXX2okID0gcHJlZGljdG9yIG9mIGxldmVsIDIgKGNsYXNzcm9vbSkNCi0gV2hlcmUgJFxnYW1tYV97MTB9JCA9IG5ldyBmaXhlZCBlZmZlY3Qgb24gdGhlIGxldmVsIDIgcHJlZGljdG9yIG9mIHRoZSBjbGFzc3Jvb20NCi0gV2hlcmUgJFxnYW1tYV97MDB9JCA9IGludGVyY2VwdCBvZiB0aGUgY2xhc3Nyb29tDQotIFdoZXJlICR1X3swan0kID0gcmFuZG9tIGRldmlhdGlvbiBvZiB0aGUgY2xhc3Nyb29tIGludGVyY2VwdCBmcm9tIGZpeGVkIHBvcHVsYXRpb24gaW50ZXJjZXB0DQotIFdlIGFzc3VtZSBzdHVkZW50cyB3aWxsIHZhcnkgcmFuZG9tbHkgYXJvdW5kIHRoZSBwb3B1bGF0aW9uIGludGVyY2VwdCBvZiBjbGFzc3Jvb20NCiANCipMZXZlbCAyIFNsb3BlKiANCg0KJCRCX3sxan0gPSBcZ2FtbWFfezExfVdfaitcZ2FtbWFfezEwfSt1X3sxan0gJCQNCg0KLSBXaGVyZSAkV19qJCA9IHByZWRpY3RvciBvZiBsZXZlbCAyIChjbGFzc3Jvb20pDQotIFdoZXJlICRcZ2FtbWFfezExfSQgPSBuZXcgZml4ZWQgZWZmZWN0IG9uIHRoZSBsZXZlbCAyIHByZWRpY3RvciBvZiB0aGUgY2xhc3Nyb29tDQotIFdoZXJlICRcZ2FtbWFfezEwfSQgPSBzbG9wZSBvZiB0aGUgY2xhc3Nyb29tDQotIFdoZXJlICR1X3sxan0kID0gcmFuZG9tIGRldmlhdGlvbiBvZiB0aGUgY2xhc3Nyb29tIHNsb3BlIGZyb20gZml4ZWQgcG9wdWxhdGlvbiBzbG9wZQ0KLSBXZSBhc3N1bWUgc3R1ZGVudHMgd2lsbCB2YXJ5IHJhbmRvbWx5IGFyb3VuZCB0aGUgcG9wdWxhdGlvbiBpbnRlcmNlcHQgb2YgY2xhc3Nyb29tDQotIE5vdGU6IFdlIHdvdWxkIHJlcGVhdCB0aGlzIGZvciBlYWNoIGxldmVsIG9mIGNsYXNzcm9vbSB3ZSBoYXZlIChnLCBldGMpDQoNCiMjIyBNaXhlZCBFcXVhdGlvbg0KLSBXZSBwdXQgbGV2ZWwgMSBhbmQgbGV2ZWwgMiB0b2dldGhlcg0KJCR5X3tpan0gPSAoXGdhbW1hX3sxMX1XX2orXGdhbW1hX3sxMH0rdV97MWp9KVhfe2lqfSArICAoXGdhbW1hX3swMX1XX2orXGdhbW1hX3swMH0rdV97MGp9KSsgcl97aWp9ICQkDQoNCiMjIEV4YW1wbGUNCi0gU2FtZSBzdHVkeSBhcyBiZWZvcmUsIGJ1dCB0aGVyZSBpcyBhIGxldmVsIDIgdmFyaWFibGUgd2UgY2FuIGV4YW1wbGUNCi0gRWFjaCBraWQgcmVwb3J0ZWQgaG93IHN1cHBvcnRlZCB0aGV5IGZlbHQgaW4gdGhlaXIgY2xhc3Nyb29tDQotIExldHMgZXhhbWluZSB0aGUgbmV3IHZhcmlhYmxlIA0KDQpgYGB7cn0NCkNsYXNzUm9vbS5TdXBwb3J0IDwtZ2dwbG90KGRhdGEgPSBNTE0uRGF0YSwgYWVzKHggPSBTdXBwb3J0LCB5PU1hdGgsZ3JvdXA9Q2xhc3Nyb29tKSkrDQogIGZhY2V0X2dyaWQoU2VsZkFmZiB+IENsYXNzcm9vbSkrDQogIGdlb21fcG9pbnQoYWVzKGNvbG91ciA9IENsYXNzcm9vbSkpKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IFRSVUUsIGFlcyhjb2xvdXIgPSBDbGFzc3Jvb20pKSsNCiAgeGxhYigiU3VwcG9ydCIpK3lsYWIoIk1hdGggU2NvcmUiKSsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KQ2xhc3NSb29tLlN1cHBvcnQNCg0KYGBgDQoNCi0gUHJvYmxlbSBzZWVtcyB0aGF0IGNsYXNzIHN1cHBvcnQgY2hhbmdlcyBhcyBhIGZ1bmN0aW9uIG9mIHRoZSBjbGFzc3Jvb20uDQotIEJhc2ljYWxseSBpdCBwcmVzZW50cyBhIHBvdGVudGlhbCBwcm9ibGVtOiBNaWdodCB0aGUgZGlmZmVyZW5jZSBpbiBzY2hvb2xzIGJlIHRoZSBwcm9kdWN0IG9mIGhvdyBzdXBwb3J0ZWQgdGhleSBmZWVsIG9yIHZpY2UgdmVyc2E/DQotIFNvIGl0cyBub3Qgc2ltcGx5IGEgbGV2ZWwgMSBwcmVkaWN0b3IsIGl0cyBhY3R1YWxseSBtaWdodCBiZSBhIGxldmVsIDIgcHJlZGljdG9yIQ0KLSBJbiBvdGhlciB3b3JkcyBpZiB3ZSB0cnkgdG8gdXNlIGl0IGFzIGl0IChhIGxldmVsIDEgcHJlZGljdG9yKSBpdHMgbmVzdGVkIGJ5IGNsYXNzcm9vbQ0KLSBMZXRzIHRyeSB0byBtb2RlbCBpdCBzaW1wbHkgYSBsZXZlbCAxIGFuZCBzZWUgd2hhdCBnZXQNCg0KKk51bGwgTW9kZWwqIChzYW1lIGFzIGJlZm9yZSkNCg0KYGBge3J9DQpNb2RlbC4wPC1sbWVyKE1hdGggfiBTZWxmQWZmLkMrKDF8Q2xhc3Nyb29tKSwgIA0KICAgICAgICAgICAgICBkYXRhPU1MTS5EYXRhLCBSRU1MPUZBTFNFKQ0Kc3VtbWFyeShNb2RlbC4wKQ0KYGBgDQoNCipUZXN0IE1vZGVsIDEqIExldmVsIDEgVmFyaWFibGVzDQoNCmBgYHtyfQ0KIyMjIENlbnRlciB2YXJpYWJsZQ0KTUxNLkRhdGEkU3VwcG9ydC5DIDwtIHNjYWxlKE1MTS5EYXRhJFN1cHBvcnQsIGNlbnRlcj1UUlVFLCBzY2FsZT1GQUxTRSkNCg0KTW9kZWwuMTwtbG1lcihNYXRoIH4gU2VsZkFmZi5DKlN1cHBvcnQuQysoMXxDbGFzc3Jvb20pLCAgDQogICAgICAgICAgICAgIGRhdGE9TUxNLkRhdGEsIFJFTUw9RkFMU0UpDQpzdW1tYXJ5KE1vZGVsLjEpDQpgYGANCg0KLSBCdXQgdGhlIHByb2JsZW0gaXMgd2Uga25vdyB0aGF0IFN1cHBvcnQgY2hhbmdlcyBhIGZ1bmN0aW9uIG9mIHRoZSBjbGFzc3Jvb20sIHNvIGNvdWxkIGl0IGJlIHRoYXQgZWZmZWN0IG9mIHN1cHBvcnQgaXMgbm90IGFib3V0IHRoZSBkaWZmZXJlbmNlcyBob3cga2lkcyBmZWVsIHN1cHBvcnRlZCBidXQgcmVhbGx5IHRoYXQgb24gYXZlcmFnZSB0aGUga2lkcyBpbiB0aGUgZGlmZmVyZW50IHNjaG9vbHMgYWxsIGZlZWwgc3VwcG9ydGVkIG9uIGF2ZXJhZ2UgZGlmZmVyZW50bHk/DQotIFNvIGxldHMgY29udHJvbCB0aGUgcmFuZG9tIHNsb3BlcyBvZiBTdXBwb3J0IGF0IHRoZSBsZXZlbCAyOiBDb250cm9sIGZvciBzdXBwb3J0IGFzIGEgZnVuY3Rpb24gb2YgY2xhc3Nyb29tDQotIFdlIGNhbiBkbyB0aGlzIGlzIGJlY2F1c2UgZWFjaCBwZXJzb24ncyBzbG9wZSBpcyBiZWxpZXZlZCB0byBtZWFzdXJpbmcgdGhlIGRpc3RyaWJ1dGlvbiBhcm91bmQgdGhlIHBvcHVsYXRpb24gc2xvcGUgDQotIEJhc2ljYWxseSB0aGluayBvZiBlYWNoIHBlcnNvbiBhIHJlcGVhdGVkIG1lYXN1cmVtZW50IG9mIGVhY2ggZ3JvdXANCg0KKlRlc3QgTW9kZWwgMiogTGV2ZWwgMSBWYXJpYWJsZXMgYW5kIGxldmVsIDIgVmFyaWFibGUNCg0KYGBge3J9DQpNb2RlbC4yPC1sbWVyKE1hdGggfiBTZWxmQWZmLkMqU3VwcG9ydC5DKygxK1N1cHBvcnQuQ3xDbGFzc3Jvb20pLCAgDQogICAgICAgICAgICAgIGRhdGE9TUxNLkRhdGEsIFJFTUw9RkFMU0UpDQpzdW1tYXJ5KE1vZGVsLjIpDQpgYGANCg0KLSBXYWl0IHRoZXJlIGlzIGEgcHJvYmxlbSB3aXRoIHRoaXMsIHRoZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHN1cHBvcnQgYW5kIGNsYXNzcm9vbSBpbnRlcmNlcHQgaXMgMS4gDQotIFRoaXMgbWVhbnMgdGhhdCB0aGUgdHdvIHZhcmlhYmxlcyBhcmUgcHJlZGljdGluZyB0aGUgc2FtZSB0aGluZw0KLSBUaHVzIG91ciBsZXZlbCAyIHByZWRpY3RvciBpcyBjb25mb3VuZGVkIHdpdGggaW50ZXJjZXB0DQotIFdlIGNhbiBmaXggdGhpcyBieSAiY2VudGVyaW5nIiB0aGUgbGV2ZWwgMiB2YXJpYWJsZSByZWxhdGl2ZSB0byB0aGUgY2xhc3Nyb29tDQotIEluIG90aGVyIHdvcmRzLCBob3cgbXVjaCBkZXZpYXRpb24gZG9lcyBlYWNoIHN0dWRlbnQgaGF2ZSBmcm9tIHRoZSBtZWFuIG9mIHRoZSBvdGhlciBzdHVkZW50cw0KLSBJZiB0aGUgY2xhc3MgY2VudGVyZWQgc3VwcG9ydCB2YXJpYWJsZSBwcmVkaWN0cyBtYXRoIHNjb3JlLCB3ZSBjYW4gYmUgc3VyZSBpdCBpc2EgdW5pcXVlIHByZWRpY3Rvcg0KLSBOb3cgd2UgYXNrOiBob3cgbXVjaCB0byB0aGV5IGRpZmZlciBmcm9tIHRoZWlyIGNvaG9ydA0KLSBXZSB3aWxsIGNhbGwgdGhpcyBwcm9jZWR1cmUsICoqR3JvdXAgQ2VudGVyaW5nKioNCg0KYGBge3J9DQpsaWJyYXJ5KHBseXIpDQojIENyZWF0ZSBhIG5ldyB2YXJpYWJsZSBpbiB0aGUgZGF0YSB3aGljaCBpcyB0aGUgbWVhbiBvZiBzdXBwb3J0IHBlciBjbGFzcyByb29tIChhdCBlYWNoIHN1YmplY3QpDQpNTE0uRGF0YTwtZGRwbHkoTUxNLkRhdGEsLihDbGFzc3Jvb20pLCBtdXRhdGUsIENsYXNzU3VwcG9ydCA9IG1lYW4oU3VwcG9ydCkpDQojIG5leHQgd2UgY2VudGVyIHJlbGF0aXZlIHRvIGVhY2ggc3R1ZGVudCByZWxhdGl2ZSB0byB0aGVpciBjbGFzcyBtZWFuIChob3cgbXVjaCB0byB0aGV5IGRpZmZlciBmcm9tIHRoZWlyIGNvaG9ydCkNCk1MTS5EYXRhJFN1cHBvcnQuQ2xhc3MuQ2VudGVyZWQ8LU1MTS5EYXRhJFN1cHBvcnQtTUxNLkRhdGEkQ2xhc3NTdXBwb3J0DQpgYGANCg0KKlRlc3QgTW9kZWwgMyogTGV2ZWwgMSBWYXJpYWJsZXMgYW5kIGxldmVsIDIgVmFyaWFibGUgKGdyb3VwIGNlbnRlcmVkKQ0KDQpgYGB7cn0NCk1vZGVsLjM8LWxtZXIoTWF0aCB+IFNlbGZBZmYuQypTdXBwb3J0LkNsYXNzLkNlbnRlcmVkKygxK1N1cHBvcnQuQ2xhc3MuQ2VudGVyZWR8Q2xhc3Nyb29tKSwgIA0KICAgICAgICAgICAgICBkYXRhPU1MTS5EYXRhLCBSRU1MPUZBTFNFKQ0Kc3VtbWFyeShNb2RlbC4zKQ0KYGBgDQoNCi0gTm93IHdlIHNlZSBzbWFsbGVyIGVmZmVjdHMgb2Ygc3VwcG9ydCwgYnV0IHNpZ25pZmljYW50IGFuZCBhbmQgYSBzaWduaWZpY2FudCBpbnRlcmFjdGlvbg0KLSBMZXQncyBwbG90IGl0IHVwDQoNCipQbG90Kg0KDQpgYGB7cn0NCmxpYnJhcnkoZWZmZWN0cykNClJlc3VsdHMuTW9kZWwuMzwtRWZmZWN0KGMoIlNlbGZBZmYuQyIsIlN1cHBvcnQuQ2xhc3MuQ2VudGVyZWQiKSxNb2RlbC4zLA0KICAgICB4bGV2ZWxzPWxpc3QoU2VsZkFmZi5DPWMobWluKE1MTS5EYXRhJFNlbGZBZmYuQyksbWF4KE1MTS5EYXRhJFNlbGZBZmYuQykpLA0KICAgICAgICAgICAgICAgICAgU3VwcG9ydC5DbGFzcy5DZW50ZXJlZD1jKC1zZChNTE0uRGF0YSRTdXBwb3J0LkNsYXNzLkNlbnRlcmVkKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZChNTE0uRGF0YSRTdXBwb3J0LkNsYXNzLkNlbnRlcmVkKSkpKQ0KUmVzdWx0cy5Nb2RlbC4zPC1hcy5kYXRhLmZyYW1lKFJlc3VsdHMuTW9kZWwuMykNClJlc3VsdHMuTW9kZWwuMyRTZWxmQWZmLkM8LWZhY3RvcihSZXN1bHRzLk1vZGVsLjMkU2VsZkFmZi5DLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzPWMobWluKE1MTS5EYXRhJFNlbGZBZmYuQyksbWF4KE1MTS5EYXRhJFNlbGZBZmYuQykpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzPWMoIk5vIFNlbGYtQSIsICJZZXMgU2VsZi1BIikpDQpGaW5hbC5GaXhlZC5QbG90IDwtZ2dwbG90KGRhdGEgPSBSZXN1bHRzLk1vZGVsLjMsIGFlcyh4ID0gU3VwcG9ydC5DbGFzcy5DZW50ZXJlZCwgeSA9Zml0LCBncm91cD1TZWxmQWZmLkMpKSsNCiAgZ2VvbV9saW5lKGFlcyhjb2xvcj1TZWxmQWZmLkMpLCBzaXplPTIpKw0KICBnZW9tX3JpYmJvbihhZXMoeW1pbj1maXQtc2UsIHltYXg9Zml0K3NlLGZpbGw9U2VsZkFmZi5DKSxhbHBoYT0uMikrDQogIHhsYWIoIlN1cHBvcnQiKSsNCiAgeWxhYigiTWF0aCBTY29yZSIpKw0KICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoImJsdWUiLCAicmVkIikpKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YygiYmx1ZSIsICJyZWQiKSkrDQogIHRoZW1lX2J3KCkrDQogIHRoZW1lKHRleHQ9ZWxlbWVudF90ZXh0KGZhY2U9ImJvbGQiLCBzaXplPTEyKSwNCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwgDQogICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksIA0KICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoZmlsbCA9IE5BLCBjb2xvdXIgPSAiTkEiKSwNCiAgICAgICAgYXhpcy5saW5lID0gZWxlbWVudF9saW5lKHNpemUgPSAxLCBjb2xvdXIgPSAiZ3JleTgwIiksDQogICAgICAgIGxlZ2VuZC50aXRsZT1lbGVtZW50X2JsYW5rKCksDQogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQ0KRmluYWwuRml4ZWQuUGxvdA0KYGBgDQoNCiMjIyBHcmFuZCBtZWFuIHZzIGdyb3VwIGNlbnRlcmluZw0KLSBXaGVuIHRvIGNlbnRlciBhdCB0aGUgZ3JhbmQgbWVhbiBvciB0aGUgZ3JvdXANCi0gVGhpcyBkZXBlbmRzIG9uIHlvdXIgcXVlc3Rpb24gYW5kIHRoZSBkYXRhDQotIFlvdSBtYXkgd2FudCB0byBhc2sgYSBncmFuZCBtZWFuIHF1ZXN0aW9uIChob3cgYWxsIHBlb3BsZSBhcmUgaW1wYWN0ZWQgYnkgdGhlIHByZWRpY3RvciByZWdhcmRsZXNzIG9mIGdyb3VwKSwgYnV0IHRoZSBkYXRhIG1hbnkgbm90IGFsbG93IHRoYXQgcXVlc3Rpb24gdG8gYmUgYXNrZWQgKGlmIHRoZSBwcmVkaWN0b3IgaXMgY29uZm91bmRlZCB3aXRoIGdyb3VwKQ0KLSBUaGUgcHJvYmxlbSBpbiB0aGlzIHN0dWR5IGlzIGEgcmVzdWx0IG9mIHRoZSBwcm9ibGVtIHRoYXQgd2UgaGFkIHRvbyBmZXcgY2xhc3Nyb29tcywgaG93ZXZlciwgZXZlbiBpbiBsYXJnZSBkYXRhIHNldHMgdGhpcyBwcm9ibGVtIGNhbiByZW1haW4NCi0gR3JvdXAgY2VudGVyaW5nIGFza3MgaG93IGRvZXMgdGhlIHdpdGhpbiBncm91cCB2YXJpYXRpb24gb2YgdGhlIHByZWRpY3RvciBwcmVkaWN0IHRoZSBvdXRjb21lDQotIFRoaXMgaXMgb2Z0ZW4gYSB2ZXJ5IGludGVyZXN0aW5nIHF1ZXN0aW9uIGFuZCBtYXkgbm90IGFsd2F5cyBkaWZmZXIgaW4gc3RvcnkgZnJvbSB0aGUgZ3JhbmQgbWVhbg0KLSBIb3dldmVyLCB0ZWNobmljYWxseSBpdHMgbWVhbmluZyBoYXMgY2hhbmdlZCEgU28sIHlvdSBtdXN0IHRoaW5rIGFib3V0IHdoYXQgaXQgbWVhbnMgZm9yIHlvdXIgZGF0YSB0byBoYXZlIGNlbnRlcmVkIHdpdGhpbiBncm91cA0KDQoNCg0KPHNjcmlwdD4NCiAgKGZ1bmN0aW9uKGkscyxvLGcscixhLG0pe2lbJ0dvb2dsZUFuYWx5dGljc09iamVjdCddPXI7aVtyXT1pW3JdfHxmdW5jdGlvbigpew0KICAoaVtyXS5xPWlbcl0ucXx8W10pLnB1c2goYXJndW1lbnRzKX0saVtyXS5sPTEqbmV3IERhdGUoKTthPXMuY3JlYXRlRWxlbWVudChvKSwNCiAgbT1zLmdldEVsZW1lbnRzQnlUYWdOYW1lKG8pWzBdO2EuYXN5bmM9MTthLnNyYz1nO20ucGFyZW50Tm9kZS5pbnNlcnRCZWZvcmUoYSxtKQ0KICB9KSh3aW5kb3csZG9jdW1lbnQsJ3NjcmlwdCcsJ2h0dHBzOi8vd3d3Lmdvb2dsZS1hbmFseXRpY3MuY29tL2FuYWx5dGljcy5qcycsJ2dhJyk7DQoNCiAgZ2EoJ2NyZWF0ZScsICdVQS05MDQxNTE2MC0xJywgJ2F1dG8nKTsNCiAgZ2EoJ3NlbmQnLCAncGFnZXZpZXcnKTsNCg0KPC9zY3JpcHQ+DQo=