1 Loading packages

In this session, we will look at basic functions in R that will help us in running some inferential statistics. These will help us to evaluate the relationship between one (or more) predictor(s) (independent variable) and an outcome (dependent variable).

It is important to know the class of the outcome before doing any pre-data analyses or inferential statistics. Outcome classes can be one of:

  1. Numeric: As an example, we have length/width of leaf; height of mountain; fundamental frequency of the voice; etc. These are true numbers and we can use summaries, t-tests, linear models, etc.

  2. Categorical (Unordered): Observations for two or more categories. As an example, we can have gender of a speaker (male or female); responses to a True vs False perception tests; Colour (unordered) categorisation, e.g., red, blue, yellow, orange, etc.. For these we can use a Generalised Linear Model (binomial or multinomial) or a simple chi-square test. Count data are numbers related to a category. But these should be analysed using a poisson logistic regression

  3. Categorical (Ordered): When you run a rating experiment, where the outcome is either numeric (i.e., 1, 2, 3, 4, 5) or categories (i.e., disagree, neutral, agree). The numeric option is NOT a true number as for the participant, these are categories. Cumulative Logit models (or Generalised Linear Model with a cumulative function) are used. The mean is meaningless here, and the median is a preferred descriptive statistic.

The content will be split into 5 sections. Some of you will only ever look at some of these, while others may need to use all. Look at the section that works best for your data.

  1. Pre-data analyses: We will look at summaries, plotting, correlations, checking normality of distribution and homogeneity of variance (for t-tests)

  2. Statistical Analyses: from t-test and ANOVA, to Linear Models: model estimation, understanding coefficients, residuals, and predictions

  3. We then move to Generalised Linear Models, with Logistic Regression (with a binomial categorical outcome) and touch upon Signal Detection Theory for estimating accuracy, biases, with sensitivity and specificity measures.

  4. Dealing with rating data using Generalised Linear Models, with a Cumulative Logit function

  5. Linear Mixed effects Models: Introduction to random effects and how to deal with these.

2 Pre-data analsyes

2.1 Built-in datasets

We will use one of the built in R. You can check all available datasets in R using the following:

We will use the iris dataset from the package MASS

2.2 Checking structure and summaries

2.2.1 Structure

'data.frame':   150 obs. of  5 variables:
 $ Sepal.Length: num  5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
 $ Sepal.Width : num  3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
 $ Petal.Length: num  1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
 $ Petal.Width : num  0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
 $ Species     : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...

We have a dataframe with 150 observations and 5 variables; 4 numeric and 1 factor with 3 levels.

2.2.2 Summary

We summarise the data to see the trends:

  Sepal.Length    Sepal.Width     Petal.Length    Petal.Width   
 Min.   :4.300   Min.   :2.000   Min.   :1.000   Min.   :0.100  
 1st Qu.:5.100   1st Qu.:2.800   1st Qu.:1.600   1st Qu.:0.300  
 Median :5.800   Median :3.000   Median :4.350   Median :1.300  
 Mean   :5.843   Mean   :3.057   Mean   :3.758   Mean   :1.199  
 3rd Qu.:6.400   3rd Qu.:3.300   3rd Qu.:5.100   3rd Qu.:1.800  
 Max.   :7.900   Max.   :4.400   Max.   :6.900   Max.   :2.500  
       Species  
 setosa    :50  
 versicolor:50  
 virginica :50  
                
                
                

So we have an equal dataframe (50 observations under each level of the factor Species), with no missing values (aka NA).

2.2.3 Advanced

2.2.3.1 For a specific variable

What if you want to summarise the data and get the mean, SD, by each level of the factor for Sepal.Length?

2.2.3.2 For all variables

2.2.4 Up to you

Do some additional summaries.. You may want to check the median, range, etc..

2.3 Plot

We can make a boxplot of the data and add a trend line. This allows us to visualise the median, and quantiles in addition to the standard deviation and any outliers… All in the same plot!

Here I have used the variable Sepal.Length. You can use any of the additional variables to plot the data.

2.4 Correlation tests

2.4.1 Basic correlations

We use the function cor to obtain the pearson correlation and cor.test to run a basic correlation test on our data with significance testing

[1] 0.8717538

    Pearson's product-moment correlation

data:  iris$Sepal.Length and iris$Petal.Length
t = 21.646, df = 148, p-value < 2.2e-16
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 0.8270363 0.9055080
sample estimates:
      cor 
0.8717538 

2.4.1.1 Up to you

Can you check whether there is a correlation between the Sepal.Length and the Petal.Width? What about Petal.Length and Petal.Width?

2.4.2 Using the package corrplot

Above, we did a correlation test on two predictors. We run multiple correlations on multiple predictors.

2.4.2.1 Correlations

             Sepal.Length Sepal.Width Petal.Length Petal.Width
Sepal.Length         1.00       -0.12         0.87        0.82
Sepal.Width         -0.12        1.00        -0.43       -0.37
Petal.Length         0.87       -0.43         1.00        0.96
Petal.Width          0.82       -0.37         0.96        1.00

n= 150 


P
             Sepal.Length Sepal.Width Petal.Length Petal.Width
Sepal.Length              0.1519      0.0000       0.0000     
Sepal.Width  0.1519                   0.0000       0.0000     
Petal.Length 0.0000       0.0000                   0.0000     
Petal.Width  0.0000       0.0000      0.0000                  

2.4.2.2 Up to you

Look into the corrplot specification, using ?corrplot and amend some of the criteria. Run a correlation plot while filtering the data according to the species.

Up to now, we have done some basic summaries and checked the correlations in the data. The pearson correlations we have done provided us with significance levels related to the correlations between two numeric outcomes. We continue by examining the normality of distribution of our data.

2.5 Normality of distribution

2.5.1 Subsetting data

In the iris dataset, we have a categorical predictor: Species which has three levels

[1] "setosa"     "versicolor" "virginica" 

Let’s subset the data to setosa and versicolor. We will also check the normality and homogeneity of variance in the data

2.5.2 Shapiro test

To check normality of distribution, we use the shapiro.test on the numeric outcome. Given that our predictor now has two levels. We need to subset the data again to check normality of the outcome Sepal.Length for each level of our factor Species


    Shapiro-Wilk normality test

data:  irisSubSet$Sepal.Length
W = 0.9777, p-value = 0.4595

    Shapiro-Wilk normality test

data:  irisSubVers$Sepal.Length
W = 0.97784, p-value = 0.4647

How to interpret this non-statistically significant result? This tells us that the distribution of the data is not statistically different from a normal distribution.

2.5.3 Density plot

We can also use a density plot to evaluate normality. The results show that both levels have bell shaped distributions.

2.5.4 Homogeneity of variance

Because our data is normally distributed, we can use the bartlett test. If our data were non-normally distributed, we would use the Levene Test (either with var.test from base-R or leveneTest from the car package We can check both.

2.5.4.1 Bartlett test


    Bartlett test of homogeneity of variances

data:  Sepal.Length by Species
Bartlett's K-squared = 6.8917, df = 1, p-value = 0.00866

2.5.4.2 Levene test


    F test to compare two variances

data:  Sepal.Length by Species
F = 0.46634, num df = 49, denom df = 49, p-value = 0.008657
alternative hypothesis: true ratio of variances is not equal to 1
95 percent confidence interval:
 0.2646385 0.8217841
sample estimates:
ratio of variances 
         0.4663429 
Levene's Test for Homogeneity of Variance (center = median)
      Df F value   Pr(>F)   
group  1  8.1727 0.005196 **
      98                    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

In all cases, the statistically significant result indicates that there is evidence that the variance of two levels of the factor Species is statistically significant; i.e., the variances are not equal. This is important as we will use this in our t-test later on

3 Linear Models

Up to now, we have looked at descriptive statistics, and evaluated summaries, correlations in the data (with p values), and checked the normality of distribution of our data.

We are now interested in looking at group differences.

Let us start with a simple t-test

3.1 First steps

3.1.1 T-test

We then run a t-test on the data. We specify the formula as y ~ x and add var.equal = FALSE (based on the normality tests above)


    Welch Two Sample t-test

data:  Sepal.Length by Species
t = -10.521, df = 86.538, p-value < 2.2e-16
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 -1.1057074 -0.7542926
sample estimates:
    mean in group setosa mean in group versicolor 
                   5.006                    5.936 

To interpret the t-test, we say that there is evidence for a statistically significant difference between the two groups: setosa and versicolor: t(86) = -10.521, p < 2.2e-16. The mean of setosa is significantly lower than that of versicolor.

3.1.2 Linear Model

Let us run a linear model on the same data


Call:
lm(formula = Sepal.Length ~ Species, data = .)

Residuals:
    Min      1Q  Median      3Q     Max 
-1.0360 -0.3135 -0.0060  0.2715  1.0640 

Coefficients:
                  Estimate Std. Error t value Pr(>|t|)    
(Intercept)        5.00600    0.06250   80.09   <2e-16 ***
Speciesversicolor  0.93000    0.08839   10.52   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.442 on 98 degrees of freedom
Multiple R-squared:  0.5304,    Adjusted R-squared:  0.5256 
F-statistic: 110.7 on 1 and 98 DF,  p-value: < 2.2e-16

Any comments? discuss with your neighbour.

The results of the linear model are exactly the same, albeit with a difference in the sign of the difference. This indicates that the \(\beta\) coefficient for versicolor is significantly higher than that of setosa by 0.93000: t(98) = 10.52, p < <2e-16.

The dataset iris contains three species. We will run an ANOVA and a linear model on the data.

3.1.3 Basic ANOVA

We can use the function aov to run an Analysis of Variance on the full dataset

             Df Sum Sq Mean Sq F value Pr(>F)    
Species       2  63.21  31.606   119.3 <2e-16 ***
Residuals   147  38.96   0.265                   
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

3.1.4 Linear model

We can use the function lm to run a linear model


Call:
lm(formula = Sepal.Length ~ Species, data = .)

Residuals:
    Min      1Q  Median      3Q     Max 
-1.6880 -0.3285 -0.0060  0.3120  1.3120 

Coefficients:
                  Estimate Std. Error t value Pr(>|t|)    
(Intercept)         5.0060     0.0728  68.762  < 2e-16 ***
Speciesversicolor   0.9300     0.1030   9.033 8.77e-16 ***
Speciesvirginica    1.5820     0.1030  15.366  < 2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.5148 on 147 degrees of freedom
Multiple R-squared:  0.6187,    Adjusted R-squared:  0.6135 
F-statistic: 119.3 on 2 and 147 DF,  p-value: < 2.2e-16

But wait… How is the linear model comparable to the analysis of variance we ran above? This linear model derives the analysis of variance we saw above, use anova on your linear model..

Here are the results of the initial Analysis of variance:

             Df Sum Sq Mean Sq F value Pr(>F)    
Species       2  63.21  31.606   119.3 <2e-16 ***
Residuals   147  38.96   0.265                   
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

And here are the results of the linear model with the anova function

Analysis of Variance Table

Response: Sepal.Length
           Df Sum Sq Mean Sq F value    Pr(>F)    
Species     2 63.212  31.606  119.26 < 2.2e-16 ***
Residuals 147 38.956   0.265                      
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

They are exactly the same… The underlying of an Analysis of variance is a linear model. We will continue with a linear model to understand it better

3.2 Linear Model

The basic assumption of a Linear model is to create a regression analysis on the data. We have an outcome (or dependent variable) and a predictor (or an independent variable). The formula of a linear model is as follows outcome ~ predictor that can be read as “outcome as a function of the predictor”. We can add “1” to specify an intercept, but this is by default added to the model

3.2.1 Model estimation


Call:
lm(formula = Sepal.Length ~ Species, data = .)

Coefficients:
      (Intercept)  Speciesversicolor   Speciesvirginica  
            5.006              0.930              1.582  

Call:
lm(formula = Sepal.Length ~ Species, data = .)

Residuals:
    Min      1Q  Median      3Q     Max 
-1.6880 -0.3285 -0.0060  0.3120  1.3120 

Coefficients:
                  Estimate Std. Error t value Pr(>|t|)    
(Intercept)         5.0060     0.0728  68.762  < 2e-16 ***
Speciesversicolor   0.9300     0.1030   9.033 8.77e-16 ***
Speciesvirginica    1.5820     0.1030  15.366  < 2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.5148 on 147 degrees of freedom
Multiple R-squared:  0.6187,    Adjusted R-squared:  0.6135 
F-statistic: 119.3 on 2 and 147 DF,  p-value: < 2.2e-16

3.2.2 Tidying the output

To interpret the model, we need look at the coefficients. The Intercept (=Setosa) is 5.006 and the coefficients for Versicolor and for Virginica are respectively 5.936 and 6.588 This tells us that compared to Setosa, moving from this category to Versicolor leads to a significant increase by 5.936, and for Virginica, there is a significant increase by 6.588.

3.2.3 Obtaining our “true” coefficients

But where are our actual values based on the means in the table above?

We run a model that suppresses the intercept (i.e., adding 0 instead of 1) and this will allow us to obtain the “true” coefficients for each level of our predictor. This is also known as a saturated model


Call:
lm(formula = Sepal.Length ~ 0 + Species, data = .)

Residuals:
    Min      1Q  Median      3Q     Max 
-1.6880 -0.3285 -0.0060  0.3120  1.3120 

Coefficients:
                  Estimate Std. Error t value Pr(>|t|)    
Speciessetosa       5.0060     0.0728   68.76   <2e-16 ***
Speciesversicolor   5.9360     0.0728   81.54   <2e-16 ***
Speciesvirginica    6.5880     0.0728   90.49   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.5148 on 147 degrees of freedom
Multiple R-squared:  0.9925,    Adjusted R-squared:  0.9924 
F-statistic:  6522 on 3 and 147 DF,  p-value: < 2.2e-16

This matches the original data. Setosa has a mean of 5.006, Versicolor 10.942, and Virginica 10.942. See table above and coefficients below

[1] 5.006
[1] 5.936
[1] 6.588

The same as

[1] 5.006
[1] 5.936
[1] 6.588

3.2.4 Nice table of our model summary

We can also obtain a nice table of our model summary. We can use the package knitr or xtable

3.2.4.1 Directly from model summary

Estimate Std. Error t value Pr(>|t|)
(Intercept) 5.006 0.073 68.762 0
Speciesversicolor 0.930 0.103 9.033 0
Speciesvirginica 1.582 0.103 15.366 0

3.2.4.2 From the tidy output

term estimate std.error statistic p.value
(Intercept) 5.006 0.073 68.762 0
Speciesversicolor 0.930 0.103 9.033 0
Speciesvirginica 1.582 0.103 15.366 0

3.2.5 Dissecting the model

Let us dissect the model. If you use “str”, you will be able to see what is available under our linear model. To access some info from the model

3.2.5.1 “str” and “coef”

List of 13
 $ coefficients : Named num [1:3] 5.01 0.93 1.58
  ..- attr(*, "names")= chr [1:3] "(Intercept)" "Speciesversicolor" "Speciesvirginica"
 $ residuals    : Named num [1:150] 0.094 -0.106 -0.306 -0.406 -0.006 ...
  ..- attr(*, "names")= chr [1:150] "1" "2" "3" "4" ...
 $ effects      : Named num [1:150] -71.5659 0.8025 7.91 -0.3826 0.0174 ...
  ..- attr(*, "names")= chr [1:150] "(Intercept)" "Speciesversicolor" "Speciesvirginica" "" ...
 $ rank         : int 3
 $ fitted.values: Named num [1:150] 5.01 5.01 5.01 5.01 5.01 ...
  ..- attr(*, "names")= chr [1:150] "1" "2" "3" "4" ...
 $ assign       : int [1:3] 0 1 1
 $ qr           :List of 5
  ..$ qr   : num [1:150, 1:3] -12.2474 0.0816 0.0816 0.0816 0.0816 ...
  .. ..- attr(*, "dimnames")=List of 2
  .. .. ..$ : chr [1:150] "1" "2" "3" "4" ...
  .. .. ..$ : chr [1:3] "(Intercept)" "Speciesversicolor" "Speciesvirginica"
  .. ..- attr(*, "assign")= int [1:3] 0 1 1
  .. ..- attr(*, "contrasts")=List of 1
  .. .. ..$ Species: chr "contr.treatment"
  ..$ qraux: num [1:3] 1.08 1.05 1.09
  ..$ pivot: int [1:3] 1 2 3
  ..$ tol  : num 1e-07
  ..$ rank : int 3
  ..- attr(*, "class")= chr "qr"
 $ df.residual  : int 147
 $ contrasts    :List of 1
  ..$ Species: chr "contr.treatment"
 $ xlevels      :List of 1
  ..$ Species: chr [1:3] "setosa" "versicolor" "virginica"
 $ call         : language lm(formula = Sepal.Length ~ Species, data = .)
 $ terms        :Classes 'terms', 'formula'  language Sepal.Length ~ Species
  .. ..- attr(*, "variables")= language list(Sepal.Length, Species)
  .. ..- attr(*, "factors")= int [1:2, 1] 0 1
  .. .. ..- attr(*, "dimnames")=List of 2
  .. .. .. ..$ : chr [1:2] "Sepal.Length" "Species"
  .. .. .. ..$ : chr "Species"
  .. ..- attr(*, "term.labels")= chr "Species"
  .. ..- attr(*, "order")= int 1
  .. ..- attr(*, "intercept")= int 1
  .. ..- attr(*, "response")= int 1
  .. ..- attr(*, ".Environment")=<environment: 0x000002715c292770> 
  .. ..- attr(*, "predvars")= language list(Sepal.Length, Species)
  .. ..- attr(*, "dataClasses")= Named chr [1:2] "numeric" "factor"
  .. .. ..- attr(*, "names")= chr [1:2] "Sepal.Length" "Species"
 $ model        :'data.frame':  150 obs. of  2 variables:
  ..$ Sepal.Length: num [1:150] 5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
  ..$ Species     : Factor w/ 3 levels "setosa","versicolor",..: 1 1 1 1 1 1 1 1 1 1 ...
  ..- attr(*, "terms")=Classes 'terms', 'formula'  language Sepal.Length ~ Species
  .. .. ..- attr(*, "variables")= language list(Sepal.Length, Species)
  .. .. ..- attr(*, "factors")= int [1:2, 1] 0 1
  .. .. .. ..- attr(*, "dimnames")=List of 2
  .. .. .. .. ..$ : chr [1:2] "Sepal.Length" "Species"
  .. .. .. .. ..$ : chr "Species"
  .. .. ..- attr(*, "term.labels")= chr "Species"
  .. .. ..- attr(*, "order")= int 1
  .. .. ..- attr(*, "intercept")= int 1
  .. .. ..- attr(*, "response")= int 1
  .. .. ..- attr(*, ".Environment")=<environment: 0x000002715c292770> 
  .. .. ..- attr(*, "predvars")= language list(Sepal.Length, Species)
  .. .. ..- attr(*, "dataClasses")= Named chr [1:2] "numeric" "factor"
  .. .. .. ..- attr(*, "names")= chr [1:2] "Sepal.Length" "Species"
 - attr(*, "class")= chr "lm"
      (Intercept) Speciesversicolor  Speciesvirginica 
            5.006             0.930             1.582 

3.2.5.2 “coef” and “coefficients”

What if I want to obtain the “Intercept”? Or the coefficient for distance? What if I want the full row for distance?

(Intercept) 
      5.006 
Speciesversicolor 
             0.93 
    Estimate   Std. Error      t value     Pr(>|t|) 
9.300000e-01 1.029579e-01 9.032819e+00 8.770194e-16 
[1] 8.770194e-16

3.2.5.3 Up to you

Play around with the model summary and obtain the t values for the three levels. You can do this by referring to the coefficient as above

3.2.5.4 Residuals

What about residuals (difference between the observed value and the estimated value of the quantity) and fitted values?

3.2.5.5 Goodness of fit?

[1] 231.452
[1] 243.4945
'log Lik.' -111.726 (df=4)

Or use the following from broom

3.2.5.6 Significance testing

Are the above informative? of course not directly. If we want to test for overall significance of model. We run a null model (aka intercept only) and compare models.

Analysis of Variance Table

Model 1: Sepal.Length ~ 1
Model 2: Sepal.Length ~ Species
  Res.Df     RSS Df Sum of Sq      F    Pr(>F)    
1    149 102.168                                  
2    147  38.956  2    63.212 119.26 < 2.2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

The results show that adding the factor “Species” improves the model fit. We can write this as follows: Model comparison showed that the addition of Species improved the model fit when compared with an intercept only model (\(F\)(2) = 119.26, p < 1.669669210^{-31})

3.2.5.7 Plotting fitted values

3.2.5.7.1 Trend line

Let’s plot our fitted values but only for the trend line

This allows us to plot the fitted values from our model with the predicted linear trend. This is exactly the same as our original data.

3.2.6 What about pairwise comparison?

Based on our model’s summary, can you tell me if there is a difference between Versicolor and Virginica?


Call:
lm(formula = Sepal.Length ~ Species, data = .)

Residuals:
    Min      1Q  Median      3Q     Max 
-1.6880 -0.3285 -0.0060  0.3120  1.3120 

Coefficients:
                  Estimate Std. Error t value Pr(>|t|)    
(Intercept)         5.0060     0.0728  68.762  < 2e-16 ***
Speciesversicolor   0.9300     0.1030   9.033 8.77e-16 ***
Speciesvirginica    1.5820     0.1030  15.366  < 2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.5148 on 147 degrees of freedom
Multiple R-squared:  0.6187,    Adjusted R-squared:  0.6135 
F-statistic: 119.3 on 2 and 147 DF,  p-value: < 2.2e-16
$emmeans
 Species    emmean     SE  df lower.CL upper.CL
 setosa       5.01 0.0728 147     4.86     5.15
 versicolor   5.94 0.0728 147     5.79     6.08
 virginica    6.59 0.0728 147     6.44     6.73

Confidence level used: 0.95 

$contrasts
 contrast               estimate    SE  df t.ratio p.value
 setosa - versicolor      -0.930 0.103 147  -9.033 <.0001 
 setosa - virginica       -1.582 0.103 147 -15.366 <.0001 
 versicolor - virginica   -0.652 0.103 147  -6.333 <.0001 

P value adjustment: fdr method for 3 tests 

How to interpret the output? Discuss with your neighbour and share with the group.

Hint… Look at the emmeans values for each level of our factor “Species” and the contrasts.

3.3 Other outcomes?

So far, we only looked at “Sepal.Length”. What about the other outcomes? how informative are they? Do we have statistical difference between the three levels of our predictor? You can do this in your spare time.

3.4 Conclusion

We have so far looked at the Linear Model. The underlying assumption about linear models is that we have a normal (Gaussian) distribution. This is the model to be used when we have a numeric outcome. What if our outcome is not numeric? What if we have two categories, i.e., black vs white? correct vs incorrect? yes vs no? These are categorical binary outcome. We look in the next section at Logistic Regression

4 Generalised Linear Models

Here we will look at an example when the outcome is binary. This simulated data is structured as follows. We asked one participant to listen to 165 sentences, and to judge whether these are “grammatical” or “ungrammatical”. There were 105 sentences that were “grammatical” and 60 “ungrammatical”. This fictitious example can apply in any other situation. Let’s think Geography: 165 lands: 105 “flat” and 60 “non-flat”, etc. This applies to any case where you need to “categorise” the outcome into two groups.

4.1 Load and summaries

Let’s load in the data and do some basic summaries

spec_tbl_df [165 x 2] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
 $ grammaticality: chr [1:165] "grammatical" "grammatical" "grammatical" "grammatical" ...
 $ response      : chr [1:165] "yes" "yes" "yes" "yes" ...
 - attr(*, "spec")=
  .. cols(
  ..   grammaticality = col_character(),
  ..   response = col_character()
  .. )

4.2 GLM

Let’s run a first GLM (Generalised Linear Model). A GLM uses a special family “binomial” as it assumes the outcome has a binomial distribution. In general, results from a Logistic Regression are close to what we get from SDT (see above).

To run the results, we will change the reference level for both response and grammaticality. The basic assumption about GLM is that we start with our reference level being the “no” responses to the “ungrammatical” category. Any changes to this reference will be seen in the coefficients as “yes” responses to the “grammatical” category.

4.2.1 Model estimation and results

The results below show the logodds for our model.

               response
grammaticality   no yes
  ungrammatical  50  10
  grammatical     5 100

Call:
glm(formula = response ~ grammaticality, family = binomial, data = .)

Deviance Residuals: 
    Min       1Q   Median       3Q      Max  
-2.4676  -0.6039   0.3124   0.3124   1.8930  

Coefficients:
                          Estimate Std. Error z value Pr(>|z|)    
(Intercept)                -1.6094     0.3464  -4.646 3.38e-06 ***
grammaticalitygrammatical   4.6052     0.5744   8.017 1.08e-15 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

(Dispersion parameter for binomial family taken to be 1)

    Null deviance: 210.050  on 164  degrees of freedom
Residual deviance:  94.271  on 163  degrees of freedom
AIC: 98.271

Number of Fisher Scoring iterations: 5

The results show that for one unit increase in the response (i.e., from no to yes), the logodds of being “grammatical” is increased by 4.6051702 (the intercept shows that when the response is “no”, the logodds are -1.6094379). The actual logodds for the response “yes” to grammatical is 2.9957323

4.2.2 Logodds to Odd ratios

Logodds can be modified to talk about the odds of an event. For our model above, the odds of “grammatical” receiving a “no” response is a mere 0.2; the odds of “grammatical” to receive a “yes” is a 20; i.e., 20 times more likely

[1] 0.2
[1] 20

4.2.3 LogOdds to proportions

If you want to talk about the percentage “accuracy” of our model, then we can transform our loggodds into proportions. This shows that the proportion of “grammatical” receiving a “yes” response increases by 99% (or 95% based on our “true” coefficients)

[1] 0.1666667
[1] 0.952381

4.3 Accuracy and Signal Detection Theory

4.3.1 Rationale

We are generally interested in performance, i.e., whether the we have “accurately” categorised the outcome or not and at the same time want to evaluate our biases in responses. When deciding on categories, we are usually biased in our selection.

Let’s ask the question: How many of you have a Mac laptop and how many a Windows laptop? For those with a Mac, what was the main reason for choosing it? Are you biased in anyway by your decision?

To correct for these biases, we use some variants from Signal Detection Theory to obtain the true estimates without being influenced by the biases.

4.3.2 Running stats

Let’s do some stats on this

Yes No Total
Grammatical (Yes Actual) TP = 100 FN = 5 (Yes Actual) 105
Ungrammatical (No Actual) FP = 10 TN = 50 (No Actual) 60
Total (Yes Response) 110 (No Response) 55 165
[1] 100
[1] 5
[1] 10
[1] 50
[1] 165
[1] 0.9090909
[1] 0.09090909
[1] 0.952381
[1] 0.1666667
[1] 0.8333333
[1] 0.9090909
$dprime
[1] 2.635813

$beta
[1] 0.3970026

$aprime
[1] 0.9419643

$bppd
[1] -0.5076923

$c
[1] -0.3504848

The most important from above, is d-prime. This is modelling the difference between the rate of “True Positive” responses and “False Positive” responses in standard unit (or z-scores). The formula can be written as:

d' (d prime) = Z(True Positive Rate) - Z(False Positive Rate)

4.3.3 GLM as a classification tool

The code below demonstrates the links between our GLM model and what we had obtained above from SDT. The predictions’ table shows that our GLM was successful at obtaining prediction that are identical to our initial data setup. Look at the table here and the table above. Once we have created our table of outcome, we can compute percent correct, the specificity, the sensitivity, the Kappa score, etc.. this yields the actual value with the SD that is related to variations in responses.

     
      grammatical ungrammatical
  yes         100            10
  no            5            50

If you look at the results from SDT above, these results are the same as the following

Accuracy: (TP+TN)/Total (0.9090909)

True Positive Rate (or Specificity) TP/(TP+FN) (0.952381)

True Negative Rate (or Sensitivity) TN/(FP+TN) (0.8333333)

4.3.4 GLM and d prime

The values obtained here match those obtained from SDT. For d prime, the difference stems from the use of the logit variant of the Binomial family. By using a probit variant, one obtains the same values (see here for more details). A probit variant models the z-score differences in the outcome and is evaluated in change in 1-standard unit. This is modelling the change from “ungrammatical” “no” responses into “grammatical” “yes” responses in z-scores. The same conceptual underpinnings of d-prime from Signal Detection Theory.

[1] 2.635813
grammaticalityungrammatical 
                   2.635813 

4.4 GLM: Other distributions

If your data does not fit a binomial distribution, and is a multinomial (i.e., three or more response categories) or poisson (count data), then you need to use the glm function with a specific family function.

6 Linear Mixed-effects Models. Why random effects matter

Let’s generate a new dataframe that we will use later on for our mixed models

6.1 Plots

Let’s start by doing a correlation test and plotting the data. Our results show that there is a negative correlation between duration and LogFrequency, and the plot shows this decrease.

        logFreq   dur
logFreq    1.00 -0.54
dur       -0.54  1.00

n= 120 


P
        logFreq dur
logFreq          0 
dur      0         

6.2 Linear model

Let’s run a simple linear model on the data. As we can see below, there are some issues with the “simple” linear model: we had set our SD for subjects to be 40, but this was picked up as 120 (see histogram of residuals). The QQ Plot is not “normal”.


Call:
lm(formula = dur ~ logFreq, data = .)

Residuals:
    Min      1Q  Median      3Q     Max 
-94.322 -35.465  -4.364  33.020 123.955 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept) 337.9730     6.2494  54.081  < 2e-16 ***
logFreq      -5.4601     0.7846  -6.959 2.06e-10 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 48.29 on 118 degrees of freedom
Multiple R-squared:  0.291, Adjusted R-squared:  0.285 
F-statistic: 48.43 on 1 and 118 DF,  p-value: 2.057e-10

6.3 Linear Mixed Model

Our Linear Mixed effects Model will take into account the random effects we added and also our model specifications. We use a Maximum Likelihood estimate (REML = FALSE) as this is what we will use for model comparison. The Linear Mixed Model is reflecting our model specifications The SD of our subjects is picked up correctly. The model results are “almost” the same as our linear model above. The coefficient for the “Intercept” is at 337.973 and the coefficient for LogFrequency is at -5.460. This indicates that for each unit of increase in the LogFrequency, there is a decrease by 5.460 (ms).

Linear mixed model fit by maximum likelihood . t-tests use
  Satterthwaite's method [lmerModLmerTest]
Formula: dur ~ logFreq + (1 | subjects) + (1 | items)
   Data: .

     AIC      BIC   logLik deviance df.resid 
  1105.8   1119.8   -547.9   1095.8      115 

Scaled residuals: 
     Min       1Q   Median       3Q      Max 
-2.06735 -0.60675  0.07184  0.61122  2.39854 

Random effects:
 Groups   Name        Variance Std.Dev.
 items    (Intercept)  589.8   24.29   
 subjects (Intercept) 1471.7   38.36   
 Residual              284.0   16.85   
Number of obs: 120, groups:  items, 20; subjects, 6

Fixed effects:
            Estimate Std. Error      df t value Pr(>|t|)    
(Intercept)  337.973     17.587   9.126  19.218 1.08e-08 ***
logFreq       -5.460      1.004  19.215  -5.436 2.92e-05 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Correlation of Fixed Effects:
        (Intr)
logFreq -0.322

6.4 Our second Mixed model

This second model add a by-subject random slope. Random slopes allow for the variation that exists in the random effects to be taken into account. An intercept only model provides an averaged values to our participants.

Linear mixed model fit by maximum likelihood . t-tests use
  Satterthwaite's method [lmerModLmerTest]
Formula: dur ~ logFreq + (logFreq | subjects) + (1 | items)
   Data: .

     AIC      BIC   logLik deviance df.resid 
  1109.5   1129.0   -547.7   1095.5      113 

Scaled residuals: 
    Min      1Q  Median      3Q     Max 
-2.1087 -0.6067  0.0623  0.5828  2.4564 

Random effects:
 Groups   Name        Variance  Std.Dev. Corr
 items    (Intercept) 5.897e+02 24.2838      
 subjects (Intercept) 1.400e+03 37.4229      
          logFreq     2.902e-02  0.1704  1.00
 Residual             2.829e+02 16.8196      
Number of obs: 120, groups:  items, 20; subjects, 6

Fixed effects:
            Estimate Std. Error      df t value Pr(>|t|)    
(Intercept)  337.973     17.245   9.093  19.598 9.50e-09 ***
logFreq       -5.460      1.007  19.361  -5.424 2.92e-05 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Correlation of Fixed Effects:
        (Intr)
logFreq -0.267
optimizer (nloptwrap) convergence code: 0 (OK)
boundary (singular) fit: see ?isSingular

6.5 Model comparison

But where are our p values? The lme4 developers decided not to include p values due to various issues with estimating df. What we can do instead is to compare models. We need to create a null model to allow for significance testing. As expected our predictor is significantly contributing to the difference.

Data: .
Models:
mdl.lmer.xreal.Null: dur ~ 1 + (logFreq | subjects) + (1 | items)
mdl.lmer.xreal.2: dur ~ logFreq + (logFreq | subjects) + (1 | items)
                    npar    AIC    BIC  logLik deviance  Chisq Df
mdl.lmer.xreal.Null    6 1125.4 1142.1 -556.68   1113.4          
mdl.lmer.xreal.2       7 1109.5 1129.0 -547.73   1095.5 17.892  1
                    Pr(>Chisq)    
mdl.lmer.xreal.Null               
mdl.lmer.xreal.2     2.339e-05 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Also, do we really need random slopes? From the result below, we don’t seem to need random slopes at all, given that adding random slopes does not improve the model fit. I always recommend testing this. Most of the time I keep random slopes.

Data: .
Models:
mdl.lmer.xreal: dur ~ logFreq + (1 | subjects) + (1 | items)
mdl.lmer.xreal.2: dur ~ logFreq + (logFreq | subjects) + (1 | items)
                 npar    AIC    BIC  logLik deviance  Chisq Df
mdl.lmer.xreal      5 1105.8 1119.8 -547.92   1095.8          
mdl.lmer.xreal.2    7 1109.5 1129.0 -547.73   1095.5 0.3788  2
                 Pr(>Chisq)
mdl.lmer.xreal             
mdl.lmer.xreal.2     0.8274

But if you are really (really!!!) obsessed by p values, then you can also use lmerTest. BUT use after comparing models to evaluate contribution of predictors

Linear mixed model fit by REML. t-tests use Satterthwaite's method [
lmerModLmerTest]
Formula: dur ~ logFreq + (logFreq | subjects) + (1 | items)
   Data: .

REML criterion at convergence: 1086.1

Scaled residuals: 
     Min       1Q   Median       3Q      Max 
-2.09691 -0.60118  0.06418  0.58483  2.46245 

Random effects:
 Groups   Name        Variance  Std.Dev. Corr
 items    (Intercept)  629.5679 25.0912      
 subjects (Intercept) 1651.2357 40.6354      
          logFreq        0.0342  0.1849  1.00
 Residual              282.8593 16.8184      
Number of obs: 120, groups:  items, 20; subjects, 6

Fixed effects:
            Estimate Std. Error      df t value Pr(>|t|)    
(Intercept)  337.973     18.526   7.396   18.24 2.03e-07 ***
logFreq       -5.460      1.038  18.136   -5.26 5.18e-05 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Correlation of Fixed Effects:
        (Intr)
logFreq -0.250
optimizer (nloptwrap) convergence code: 0 (OK)
boundary (singular) fit: see ?isSingular

6.6 Our final Mixed model

Our final model uses REML (or Restricted Maximum Likelihood Estimate of Variance Component) to estimate the model.

Linear mixed model fit by REML ['lmerMod']
Formula: dur ~ logFreq + (logFreq | subjects) + (1 | items)
   Data: .

REML criterion at convergence: 1086.1

Scaled residuals: 
     Min       1Q   Median       3Q      Max 
-2.09691 -0.60118  0.06418  0.58483  2.46245 

Random effects:
 Groups   Name        Variance  Std.Dev. Corr
 items    (Intercept)  629.5679 25.0912      
 subjects (Intercept) 1651.2357 40.6354      
          logFreq        0.0342  0.1849  1.00
 Residual              282.8593 16.8184      
Number of obs: 120, groups:  items, 20; subjects, 6

Fixed effects:
            Estimate Std. Error t value
(Intercept)  337.973     18.526   18.24
logFreq       -5.460      1.038   -5.26

Correlation of Fixed Effects:
        (Intr)
logFreq -0.250
optimizer (nloptwrap) convergence code: 0 (OK)
boundary (singular) fit: see ?isSingular
Analysis of Variance Table
        npar Sum Sq Mean Sq F value
logFreq    1 7826.9  7826.9  27.671

6.7 Dissecting the model

$items
       (Intercept)   logFreq
Item1     352.3567 -5.460115
Item10    331.7618 -5.460115
Item11    324.7269 -5.460115
Item12    350.2318 -5.460115
Item13    353.1174 -5.460115
Item14    311.8355 -5.460115
Item15    354.0591 -5.460115
Item16    353.9389 -5.460115
Item17    288.7843 -5.460115
Item18    362.4702 -5.460115
Item19    338.1424 -5.460115
Item2     325.1855 -5.460115
Item20    359.7414 -5.460115
Item3     370.1804 -5.460115
Item4     302.4265 -5.460115
Item5     350.0499 -5.460115
Item6     338.9482 -5.460115
Item7     362.8402 -5.460115
Item8     295.5943 -5.460115
Item9     333.0693 -5.460115

$subjects
   (Intercept)   logFreq
S1    314.4694 -5.567073
S2    303.9037 -5.615155
S3    314.2920 -5.567881
S4    318.4282 -5.549058
S5    373.3006 -5.299350
S6    403.4443 -5.162175

attr(,"class")
[1] "coef.mer"
(Intercept)     logFreq 
 337.973044   -5.460115 
(Intercept) 
    337.973 
  logFreq 
-5.460115 

7 session info

R version 4.0.3 (2020-10-10)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 10 x64 (build 19041)

Matrix products: default

locale:
[1] LC_COLLATE=English_United Kingdom.1252 
[2] LC_CTYPE=English_United Kingdom.1252   
[3] LC_MONETARY=English_United Kingdom.1252
[4] LC_NUMERIC=C                           
[5] LC_TIME=English_United Kingdom.1252    

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods  
[7] base     

other attached packages:
 [1] PresenceAbsence_1.1.9 psycho_0.6.1          corrplot_0.84        
 [4] Hmisc_4.5-0           Formula_1.2-4         survival_3.2-7       
 [7] lattice_0.20-41       knitr_1.31            emmeans_1.5.4        
[10] broom_0.7.5           ordinal_2019.12-10    ggsignif_0.6.1       
[13] palmerpenguins_0.1.0  forcats_0.5.1         stringr_1.4.0        
[16] dplyr_1.0.5           purrr_0.3.4           readr_1.4.0          
[19] tidyr_1.1.3           tibble_3.1.0          ggplot2_3.3.3        
[22] tidyverse_1.3.0       lme4_1.1-26           Matrix_1.3-2         

loaded via a namespace (and not attached):
 [1] TH.data_1.0-10      minqa_1.2.4         colorspace_2.0-0   
 [4] ellipsis_0.3.1      rio_0.5.26          htmlTable_2.1.0    
 [7] estimability_1.3    base64enc_0.1-3     fs_1.5.0           
[10] rstudioapi_0.13     farver_2.1.0        fansi_0.4.2        
[13] mvtnorm_1.1-1       lubridate_1.7.10    xml2_1.3.2         
[16] codetools_0.2-18    splines_4.0.3       jsonlite_1.7.2     
[19] nloptr_1.2.2.2      cluster_2.1.1       dbplyr_2.1.0       
[22] png_0.1-7           compiler_4.0.3      httr_1.4.2         
[25] backports_1.2.1     assertthat_0.2.1    cli_2.3.1          
[28] htmltools_0.5.1.1   tools_4.0.3         gtable_0.3.0       
[31] glue_1.4.2          Rcpp_1.0.6          carData_3.0-4      
[34] jquerylib_0.1.3     cellranger_1.1.0    vctrs_0.3.6        
[37] nlme_3.1-152        xfun_0.21           openxlsx_4.2.3     
[40] rvest_0.3.6         lifecycle_1.0.0     pacman_0.5.1       
[43] statmod_1.4.35      MASS_7.3-53.1       zoo_1.8-8          
[46] scales_1.1.1        hms_1.0.0           sandwich_3.0-0     
[49] RColorBrewer_1.1-2  yaml_2.2.1          curl_4.3           
[52] gridExtra_2.3       sass_0.3.1          rpart_4.1-15       
[55] latticeExtra_0.6-29 stringi_1.5.3       highr_0.8          
[58] ucminf_1.1-4        checkmate_2.0.0     boot_1.3-27        
[61] zip_2.1.1           rlang_0.4.10        pkgconfig_2.0.3    
[64] evaluate_0.14       htmlwidgets_1.5.3   labeling_0.4.2     
[67] tidyselect_1.1.0    plyr_1.8.6          magrittr_2.0.1     
[70] R6_2.5.0            generics_0.1.0      multcomp_1.4-16    
[73] DBI_1.1.1           pillar_1.5.1        haven_2.3.1        
[76] foreign_0.8-81      withr_2.4.1         mgcv_1.8-34        
[79] abind_1.4-5         nnet_7.3-15         modelr_0.1.8       
[82] crayon_1.4.1        car_3.0-10          utf8_1.1.4         
[85] rmarkdown_2.7       jpeg_0.1-8.1        grid_4.0.3         
[88] readxl_1.3.1        data.table_1.14.0   reprex_1.0.0       
[91] digest_0.6.27       xtable_1.8-4        numDeriv_2016.8-1.1
[94] munsell_0.5.0       bslib_0.2.4        
LS0tDQp0aXRsZTogIlNlc3Npb25fMy1BbmFseXNpbmdEYXRhIg0Kb3V0cHV0OiANCiAgaHRtbF9ub3RlYm9vazoNCiAgICBoaWdobGlnaHQ6IHB5Z21lbnRzDQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogNg0KICAgIHRvY19mbG9hdDoNCiAgICAgIGNvbGxhcHNlZDogeWVzDQogIA0KLS0tDQoNCg0KIyBMb2FkaW5nIHBhY2thZ2VzIA0KDQpgYGB7ciB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBlcnJvcj1GQUxTRX0NCiMjIFVzZSB0aGUgY29kZSBiZWxvdyB0byBjaGVjayBpZiB5b3UgaGF2ZSBhbGwgcmVxdWlyZWQgcGFja2FnZXMgaW5zdGFsbGVkLiBJZiBzb21lIGFyZSBub3QgaW5zdGFsbGVkIGFscmVhZHksIHRoZSBjb2RlIGJlbG93IHdpbGwgaW5zdGFsbCB0aGVzZS4gSWYgeW91IGhhdmUgYWxsIHBhY2thZ2VzIGluc3RhbGxlZCwgdGhlbiB5b3UgY291bGQgbG9hZCB0aGVtIHdpdGggdGhlIHNlY29uZCBjb2RlLg0KcmVxdWlyZWRQYWNrYWdlcyA9IGMoJ3RpZHl2ZXJzZScsICdvcmRpbmFsJywgJ2Jyb29tJywgJ2VtbWVhbnMnLCAna25pdHInLCAnSG1pc2MnLCAnY29ycnBsb3QnLCAncHN5Y2hvJywgJ1ByZXNlbmNlQWJzZW5jZScsICdsbWU0JywgJ2xtZXJUZXN0JywgJ2dnc2lnbmlmJykNCmZvcihwIGluIHJlcXVpcmVkUGFja2FnZXMpew0KICBpZighcmVxdWlyZShwLGNoYXJhY3Rlci5vbmx5ID0gVFJVRSkpIGluc3RhbGwucGFja2FnZXMocCkNCiAgbGlicmFyeShwLGNoYXJhY3Rlci5vbmx5ID0gVFJVRSkNCn0NCmBgYA0KDQoNCkluIHRoaXMgc2Vzc2lvbiwgd2Ugd2lsbCBsb29rIGF0IGJhc2ljIGZ1bmN0aW9ucyBpbiBSIHRoYXQgd2lsbCBoZWxwIHVzIGluIHJ1bm5pbmcgc29tZSBpbmZlcmVudGlhbCBzdGF0aXN0aWNzLiBUaGVzZSB3aWxsIGhlbHAgdXMgdG8gZXZhbHVhdGUgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIG9uZSAob3IgbW9yZSkgcHJlZGljdG9yKHMpIChpbmRlcGVuZGVudCB2YXJpYWJsZSkgYW5kIGFuIG91dGNvbWUgKGRlcGVuZGVudCB2YXJpYWJsZSkuIA0KDQpJdCBpcyBpbXBvcnRhbnQgdG8ga25vdyB0aGUgY2xhc3Mgb2YgdGhlIG91dGNvbWUgYmVmb3JlIGRvaW5nIGFueSBwcmUtZGF0YSBhbmFseXNlcyBvciBpbmZlcmVudGlhbCBzdGF0aXN0aWNzLiBPdXRjb21lIGNsYXNzZXMgY2FuIGJlIG9uZSBvZjoNCg0KMS4gYE51bWVyaWNgOiBBcyBhbiBleGFtcGxlLCB3ZSBoYXZlIGxlbmd0aC93aWR0aCBvZiBsZWFmOyBoZWlnaHQgb2YgbW91bnRhaW47IGZ1bmRhbWVudGFsIGZyZXF1ZW5jeSBvZiB0aGUgdm9pY2U7IGV0Yy4gVGhlc2UgYXJlIGB0cnVlYCBudW1iZXJzIGFuZCB3ZSBjYW4gdXNlIHN1bW1hcmllcywgdC10ZXN0cywgbGluZWFyIG1vZGVscywgZXRjLiANCg0KMi4gYENhdGVnb3JpY2FsYCAoVW5vcmRlcmVkKTogT2JzZXJ2YXRpb25zIGZvciB0d28gb3IgbW9yZSBjYXRlZ29yaWVzLiBBcyBhbiBleGFtcGxlLCB3ZSBjYW4gaGF2ZSBnZW5kZXIgb2YgYSBzcGVha2VyIChtYWxlIG9yIGZlbWFsZSk7IHJlc3BvbnNlcyB0byBhIFRydWUgdnMgRmFsc2UgcGVyY2VwdGlvbiB0ZXN0czsgQ29sb3VyICh1bm9yZGVyZWQpIGNhdGVnb3Jpc2F0aW9uLCBlLmcuLCByZWQsIGJsdWUsIHllbGxvdywgb3JhbmdlLCBldGMuLiBGb3IgdGhlc2Ugd2UgY2FuIHVzZSBhIEdlbmVyYWxpc2VkIExpbmVhciBNb2RlbCAoYmlub21pYWwgb3IgbXVsdGlub21pYWwpIG9yIGEgc2ltcGxlIGNoaS1zcXVhcmUgdGVzdC4gQ291bnQgZGF0YSBhcmUgbnVtYmVycyByZWxhdGVkIHRvIGEgY2F0ZWdvcnkuIEJ1dCB0aGVzZSBzaG91bGQgYmUgYW5hbHlzZWQgdXNpbmcgYSBwb2lzc29uIGxvZ2lzdGljIHJlZ3Jlc3Npb24NCg0KMy4gYENhdGVnb3JpY2FsYCAoT3JkZXJlZCk6IFdoZW4geW91IHJ1biBhIHJhdGluZyBleHBlcmltZW50LCB3aGVyZSB0aGUgb3V0Y29tZSBpcyBlaXRoZXIgYG51bWVyaWNgIChpLmUuLCAxLCAyLCAzLCA0LCA1KSBvciBgY2F0ZWdvcmllc2AgKGkuZS4sIGRpc2FncmVlLCBuZXV0cmFsLCBhZ3JlZSkuIFRoZSBgbnVtZXJpY2Agb3B0aW9uIGlzIE5PVCBhIHRydWUgbnVtYmVyIGFzIGZvciB0aGUgcGFydGljaXBhbnQsIHRoZXNlIGFyZSBjYXRlZ29yaWVzLiBDdW11bGF0aXZlIExvZ2l0IG1vZGVscyAob3IgR2VuZXJhbGlzZWQgTGluZWFyIE1vZGVsIHdpdGggYSBjdW11bGF0aXZlIGZ1bmN0aW9uKSBhcmUgdXNlZC4gVGhlIG1lYW4gaXMgbWVhbmluZ2xlc3MgaGVyZSwgYW5kIHRoZSBtZWRpYW4gaXMgYSBwcmVmZXJyZWQgZGVzY3JpcHRpdmUgc3RhdGlzdGljLg0KDQpUaGUgY29udGVudCB3aWxsIGJlIHNwbGl0IGludG8gNSBzZWN0aW9ucy4gU29tZSBvZiB5b3Ugd2lsbCBvbmx5IGV2ZXIgbG9vayBhdCBzb21lIG9mIHRoZXNlLCB3aGlsZSBvdGhlcnMgbWF5IG5lZWQgdG8gdXNlIGFsbC4gTG9vayBhdCB0aGUgc2VjdGlvbiB0aGF0IHdvcmtzIGJlc3QgZm9yIHlvdXIgZGF0YS4NCg0KMS4gUHJlLWRhdGEgYW5hbHlzZXM6IFdlIHdpbGwgbG9vayBhdCBzdW1tYXJpZXMsIHBsb3R0aW5nLCBjb3JyZWxhdGlvbnMsIGNoZWNraW5nIG5vcm1hbGl0eSBvZiBkaXN0cmlidXRpb24gYW5kIGhvbW9nZW5laXR5IG9mIHZhcmlhbmNlIChmb3IgdC10ZXN0cykNCg0KMi4gU3RhdGlzdGljYWwgQW5hbHlzZXM6IGZyb20gdC10ZXN0IGFuZCBBTk9WQSwgdG8gTGluZWFyIE1vZGVsczogbW9kZWwgZXN0aW1hdGlvbiwgdW5kZXJzdGFuZGluZyBjb2VmZmljaWVudHMsIHJlc2lkdWFscywgYW5kIHByZWRpY3Rpb25zDQoNCjMuIFdlIHRoZW4gbW92ZSB0byBHZW5lcmFsaXNlZCBMaW5lYXIgTW9kZWxzLCB3aXRoIExvZ2lzdGljIFJlZ3Jlc3Npb24gKHdpdGggYSBiaW5vbWlhbCBjYXRlZ29yaWNhbCBvdXRjb21lKSBhbmQgdG91Y2ggdXBvbiBTaWduYWwgRGV0ZWN0aW9uIFRoZW9yeSBmb3IgZXN0aW1hdGluZyBhY2N1cmFjeSwgYmlhc2VzLCB3aXRoIHNlbnNpdGl2aXR5IGFuZCBzcGVjaWZpY2l0eSBtZWFzdXJlcy4NCg0KNC4gRGVhbGluZyB3aXRoIHJhdGluZyBkYXRhIHVzaW5nIEdlbmVyYWxpc2VkIExpbmVhciBNb2RlbHMsIHdpdGggYSBDdW11bGF0aXZlIExvZ2l0IGZ1bmN0aW9uDQoNCjUuIExpbmVhciBNaXhlZCBlZmZlY3RzIE1vZGVsczogSW50cm9kdWN0aW9uIHRvIHJhbmRvbSBlZmZlY3RzIGFuZCBob3cgdG8gZGVhbCB3aXRoIHRoZXNlLiANCg0KDQojIFByZS1kYXRhIGFuYWxzeWVzDQoNCiMjIEJ1aWx0LWluIGRhdGFzZXRzDQoNCldlIHdpbGwgdXNlIG9uZSBvZiB0aGUgYnVpbHQgaW4gYFJgLiBZb3UgY2FuIGNoZWNrIGFsbCBhdmFpbGFibGUgZGF0YXNldHMgaW4gYFJgIHVzaW5nIHRoZSBmb2xsb3dpbmc6DQoNCmBgYHtyfQ0KZGF0YSgpDQojIG9yIGJlbG93IGZvciBhbGwgZGF0YXNldHMgYXZhaWxhYmxlIGluIGFsbCBpbnN0YWxsZWQgcGFja2FnZXMNCmRhdGEocGFja2FnZSA9IC5wYWNrYWdlcyhhbGwuYXZhaWxhYmxlID0gVFJVRSkpDQpgYGANCg0KV2Ugd2lsbCB1c2UgdGhlIGBpcmlzYCBkYXRhc2V0IGZyb20gdGhlIHBhY2thZ2UgYE1BU1NgDQoNCiMjIENoZWNraW5nIHN0cnVjdHVyZSBhbmQgc3VtbWFyaWVzDQoNCiMjIyBTdHJ1Y3R1cmUNCg0KYGBge3J9DQppcmlzICU+JSANCiAgc3RyKCkgIA0KYGBgDQoNCldlIGhhdmUgYSBkYXRhZnJhbWUgd2l0aCAxNTAgb2JzZXJ2YXRpb25zIGFuZCA1IHZhcmlhYmxlczsgNCBudW1lcmljIGFuZCAxIGZhY3RvciB3aXRoIDMgbGV2ZWxzLiANCg0KIyMjIFN1bW1hcnkNCg0KV2Ugc3VtbWFyaXNlIHRoZSBkYXRhIHRvIHNlZSB0aGUgdHJlbmRzOg0KDQpgYGB7cn0NCmlyaXMgJT4lIA0KICBzdW1tYXJ5KCkNCmBgYA0KDQpTbyB3ZSBoYXZlIGFuIGVxdWFsIGRhdGFmcmFtZSAoNTAgb2JzZXJ2YXRpb25zIHVuZGVyIGVhY2ggbGV2ZWwgb2YgdGhlIGZhY3RvciBgU3BlY2llc2ApLCB3aXRoIG5vIG1pc3NpbmcgdmFsdWVzIChha2EgYE5BYCkuDQoNCg0KIyMjIEFkdmFuY2VkDQoNCg0KIyMjIyBGb3IgYSBzcGVjaWZpYyB2YXJpYWJsZQ0KDQpXaGF0IGlmIHlvdSB3YW50IHRvIHN1bW1hcmlzZSB0aGUgZGF0YSBhbmQgZ2V0IHRoZSBtZWFuLCBTRCwgYnkgZWFjaCBsZXZlbCBvZiB0aGUgZmFjdG9yIGZvciBgU2VwYWwuTGVuZ3RoYD8gDQoNCmBgYHtyfQ0KaXJpcyAlPiUgDQogIGdyb3VwX2J5KFNwZWNpZXMpICU+JSANCiAgc3VtbWFyaXNlKA0KICBTTC5NZWFuID0gbWVhbihTZXBhbC5MZW5ndGgpLA0KICBTTC5TRCA9IHNkKFNlcGFsLkxlbmd0aCkNCiAgKQ0KYGBgDQoNCiMjIyMgRm9yIGFsbCB2YXJpYWJsZXMNCg0KYGBge3J9DQppcmlzICU+JSANCiAgZ3JvdXBfYnkoU3BlY2llcykgJT4lIA0KICBzdW1tYXJpc2VfYWxsKGxpc3QobWVhbiA9IG1lYW4sIHNkID0gc2QpDQogICkNCmBgYA0KDQoNCiMjIyBVcCB0byB5b3UNCg0KRG8gc29tZSBhZGRpdGlvbmFsIHN1bW1hcmllcy4uIFlvdSBtYXkgd2FudCB0byBjaGVjayB0aGUgYG1lZGlhbmAsIGByYW5nZWAsIGV0Yy4uDQoNCmBgYHtyfQ0KDQpgYGANCg0KDQojIyBQbG90DQoNCldlIGNhbiBtYWtlIGEgYm94cGxvdCBvZiB0aGUgZGF0YSBhbmQgYWRkIGEgdHJlbmQgbGluZS4gVGhpcyBhbGxvd3MgdXMgdG8gdmlzdWFsaXNlIHRoZSBtZWRpYW4sIGFuZCBxdWFudGlsZXMgaW4gYWRkaXRpb24gdG8gdGhlIHN0YW5kYXJkIGRldmlhdGlvbiBhbmQgYW55IG91dGxpZXJzLi4uIEFsbCBpbiB0aGUgc2FtZSBwbG90IQ0KDQpgYGB7cix3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0V9DQppcmlzICU+JSANCiAgZ2dwbG90KGFlcyh4ID0gU3BlY2llcywgeSA9IFNlcGFsLkxlbmd0aCkpICsNCiAgZ2VvbV9ib3hwbG90KCkgKw0KICBnZW9tX3Ntb290aChhZXMoeCA9IGFzLm51bWVyaWMoU3BlY2llcyksIHkgPSBTZXBhbC5MZW5ndGgpLCBtZXRob2QgPSAibG0iKSArDQogIGxhYnMoeCA9ICJTcGVjaWVzIiwgeSA9ICJMZW5ndGgiLCB0aXRsZSA9ICJCb3hwbG90IGFuZCB0cmVuZCBsaW5lIiwgc3VidGl0bGUgPSAid2l0aCBnZ3Bsb3QyIikgKyANCiAgdGhlbWVfYncoKSArIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1KSkNCmBgYA0KDQpIZXJlIEkgaGF2ZSB1c2VkIHRoZSB2YXJpYWJsZSBgU2VwYWwuTGVuZ3RoYC4gWW91IGNhbiB1c2UgYW55IG9mIHRoZSBhZGRpdGlvbmFsIHZhcmlhYmxlcyB0byBwbG90IHRoZSBkYXRhLg0KDQojIyBDb3JyZWxhdGlvbiB0ZXN0cw0KDQojIyMgQmFzaWMgY29ycmVsYXRpb25zDQoNCldlIHVzZSB0aGUgZnVuY3Rpb24gYGNvcmAgdG8gb2J0YWluIHRoZSBwZWFyc29uIGNvcnJlbGF0aW9uIGFuZCBgY29yLnRlc3RgIHRvIHJ1biBhIGJhc2ljIGNvcnJlbGF0aW9uIHRlc3Qgb24gb3VyIGRhdGEgd2l0aCBzaWduaWZpY2FuY2UgdGVzdGluZw0KDQpgYGB7cn0NCmNvcihpcmlzJFNlcGFsLkxlbmd0aCwgaXJpcyRQZXRhbC5MZW5ndGgsIG1ldGhvZCA9ICJwZWFyc29uIikNCmNvci50ZXN0KGlyaXMkU2VwYWwuTGVuZ3RoLCBpcmlzJFBldGFsLkxlbmd0aCkNCmBgYA0KDQojIyMjIFVwIHRvIHlvdQ0KDQpDYW4geW91IGNoZWNrIHdoZXRoZXIgdGhlcmUgaXMgYSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZSBgU2VwYWwuTGVuZ3RoYCBhbmQgdGhlIGBQZXRhbC5XaWR0aGA/IFdoYXQgYWJvdXQgYFBldGFsLkxlbmd0aGAgYW5kIGBQZXRhbC5XaWR0aGA/IA0KDQoNCmBgYHtyfQ0KDQpgYGANCg0KDQoNCiMjIyBVc2luZyB0aGUgcGFja2FnZSBgY29ycnBsb3RgDQoNCkFib3ZlLCB3ZSBkaWQgYSBjb3JyZWxhdGlvbiB0ZXN0IG9uIHR3byBwcmVkaWN0b3JzLiBXZSBydW4gbXVsdGlwbGUgY29ycmVsYXRpb25zIG9uIG11bHRpcGxlIHByZWRpY3RvcnMuIA0KDQojIyMjIENvcnJlbGF0aW9ucw0KDQpgYGB7cn0NCiMjIGNvcnJlbGF0aW9uIHVzaW5nICJjb3JycGxvdCINCiMjIGJhc2VkIG9uIHRoZSBmdW5jdGlvbiBgcmNvcnInIGZyb20gdGhlIGBIbWlzY2AgcGFja2FnZQ0KIyMgTmVlZCB0byBjaGFuZ2UgZGF0YWZyYW1lIGludG8gYSBtYXRyaXgNCmNvcnIgPC0gYXMubWF0cml4KGlyaXNbLTVdKSAlPiUgDQogIHJjb3JyKHR5cGU9InBlYXJzb24iKQ0KcHJpbnQoY29ycikNCmNvcnJwbG90KGNvcnIkciwgcC5tYXQgPSBjb3JyJFAsDQogICAgICAgICBhZGRDb2VmLmNvbCA9ICJibGFjayIsIGRpYWcgPSBGQUxTRSwgdHlwZSA9ICJ1cHBlciIsIHRsLnNydCA9IDU1KQ0KYGBgDQoNCg0KDQoNCiMjIyMgVXAgdG8geW91DQoNCkxvb2sgaW50byB0aGUgYGNvcnJwbG90YCBzcGVjaWZpY2F0aW9uLCB1c2luZyBgP2NvcnJwbG90YCBhbmQgYW1lbmQgc29tZSBvZiB0aGUgY3JpdGVyaWEuIFJ1biBhIGNvcnJlbGF0aW9uIHBsb3Qgd2hpbGUgZmlsdGVyaW5nIHRoZSBkYXRhIGFjY29yZGluZyB0byB0aGUgYHNwZWNpZXNgLg0KDQpgYGB7cn0NCiMgaGludCANCiMgY3JlYXRlIGEgbmV3IGRhdGFmcmFtZSBieSBmaWx0ZXJpbmcgYFNwZWNpZXNgLCB0aGVuIGNvbXB1dGUgY29ycmVsYXRpb25zIGFuZCBwbG90DQogIA0KDQpgYGANCg0KDQpVcCB0byBub3csIHdlIGhhdmUgZG9uZSBzb21lIGJhc2ljIHN1bW1hcmllcyBhbmQgY2hlY2tlZCB0aGUgY29ycmVsYXRpb25zIGluIHRoZSBkYXRhLiBUaGUgcGVhcnNvbiBjb3JyZWxhdGlvbnMgd2UgaGF2ZSBkb25lIHByb3ZpZGVkIHVzIHdpdGggc2lnbmlmaWNhbmNlIGxldmVscyByZWxhdGVkIHRvIHRoZSBjb3JyZWxhdGlvbnMgYmV0d2VlbiB0d28gKm51bWVyaWMqIG91dGNvbWVzLiBXZSBjb250aW51ZSBieSBleGFtaW5pbmcgdGhlIG5vcm1hbGl0eSBvZiBkaXN0cmlidXRpb24gb2Ygb3VyIGRhdGEuIA0KDQojIyBOb3JtYWxpdHkgb2YgZGlzdHJpYnV0aW9uDQoNCiMjIyBTdWJzZXR0aW5nIGRhdGENCg0KSW4gdGhlIGBpcmlzYCBkYXRhc2V0LCB3ZSBoYXZlIGEgY2F0ZWdvcmljYWwgcHJlZGljdG9yOiBgU3BlY2llc2Agd2hpY2ggaGFzIHRocmVlIGxldmVscw0KDQpgYGB7cn0NCmxldmVscyhpcmlzJFNwZWNpZXMpDQpgYGANCg0KTGV0J3Mgc3Vic2V0IHRoZSBkYXRhIHRvIGBzZXRvc2FgIGFuZCBgdmVyc2ljb2xvcmAuIFdlIHdpbGwgYWxzbyBjaGVjayB0aGUgbm9ybWFsaXR5IGFuZCBob21vZ2VuZWl0eSBvZiB2YXJpYW5jZSBpbiB0aGUgZGF0YQ0KDQoNCmBgYHtyfQ0KaXJpc1N1YiA8LSBpcmlzICU+JSANCiAgZmlsdGVyKFNwZWNpZXMgJWluJSBjKCJzZXRvc2EiLCAidmVyc2ljb2xvciIpKQ0KYGBgDQoNCg0KIyMjIFNoYXBpcm8gdGVzdA0KDQpUbyBjaGVjayBub3JtYWxpdHkgb2YgZGlzdHJpYnV0aW9uLCB3ZSB1c2UgdGhlIGBzaGFwaXJvLnRlc3RgIG9uIHRoZSBudW1lcmljIG91dGNvbWUuIEdpdmVuIHRoYXQgb3VyIHByZWRpY3RvciBub3cgaGFzIHR3byBsZXZlbHMuIFdlIG5lZWQgdG8gc3Vic2V0IHRoZSBkYXRhIGFnYWluIHRvIGNoZWNrIG5vcm1hbGl0eSBvZiB0aGUgb3V0Y29tZSBgU2VwYWwuTGVuZ3RoYCBmb3IgZWFjaCBsZXZlbCBvZiBvdXIgZmFjdG9yIGBTcGVjaWVzYA0KDQpgYGB7cn0NCmlyaXNTdWJTZXQgPC0gaXJpcyAlPiUgDQogIGZpbHRlcihTcGVjaWVzID09ICJzZXRvc2EiKQ0KaXJpc1N1YlZlcnMgPC0gaXJpcyAlPiUgDQogIGZpbHRlcihTcGVjaWVzID09ICJ2ZXJzaWNvbG9yIikNCiAgDQpzaGFwaXJvLnRlc3QoaXJpc1N1YlNldCRTZXBhbC5MZW5ndGgpDQpzaGFwaXJvLnRlc3QoaXJpc1N1YlZlcnMkU2VwYWwuTGVuZ3RoKQ0KYGBgDQoNCkhvdyB0byBpbnRlcnByZXQgdGhpcyBub24tc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCByZXN1bHQ/IFRoaXMgdGVsbHMgdXMgdGhhdCB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSBkYXRhIGlzIG5vdCBzdGF0aXN0aWNhbGx5IGRpZmZlcmVudCBmcm9tIGEgbm9ybWFsIGRpc3RyaWJ1dGlvbi4NCg0KIyMjIERlbnNpdHkgcGxvdA0KDQpXZSBjYW4gYWxzbyB1c2UgYSBkZW5zaXR5IHBsb3QgdG8gZXZhbHVhdGUgbm9ybWFsaXR5LiBUaGUgcmVzdWx0cyBzaG93IHRoYXQgYm90aCBsZXZlbHMgaGF2ZSBiZWxsIHNoYXBlZCBkaXN0cmlidXRpb25zLg0KDQpgYGB7cn0NCmlyaXNTdWIgJT4lIA0KICBnZ3Bsb3QoYWVzKHggPSBTZXBhbC5MZW5ndGgpKSsNCiAgZ2VvbV9kZW5zaXR5KCkrDQogIGZhY2V0X3dyYXAoflNwZWNpZXMsIHNjYWxlcyA9ICJmcmVlX3giKQ0KYGBgDQoNCg0KIyMjIEhvbW9nZW5laXR5IG9mIHZhcmlhbmNlDQoNCkJlY2F1c2Ugb3VyIGRhdGEgaXMgbm9ybWFsbHkgZGlzdHJpYnV0ZWQsIHdlIGNhbiB1c2UgdGhlIGBiYXJ0bGV0dGAgdGVzdC4gSWYgb3VyIGRhdGEgd2VyZSBub24tbm9ybWFsbHkgZGlzdHJpYnV0ZWQsIHdlIHdvdWxkIHVzZSB0aGUgTGV2ZW5lIFRlc3QgKGVpdGhlciB3aXRoIGB2YXIudGVzdGAgZnJvbSBiYXNlLVIgb3IgYGxldmVuZVRlc3RgIGZyb20gdGhlIGNhciBwYWNrYWdlIFdlIGNhbiBjaGVjayBib3RoLg0KDQojIyMjIEJhcnRsZXR0IHRlc3QNCg0KYGBge3J9DQppcmlzU3ViICU+JSANCiAgYmFydGxldHQudGVzdChTZXBhbC5MZW5ndGggfiBTcGVjaWVzLCBkYXRhID0gLikNCmBgYA0KDQojIyMjIExldmVuZSB0ZXN0DQoNCmBgYHtyfQ0KaXJpc1N1YiAlPiUgDQogIHZhci50ZXN0KFNlcGFsLkxlbmd0aCB+IFNwZWNpZXMsIGRhdGEgPSAuKQ0KaXJpc1N1YiAlPiUgDQogIGNhcjo6bGV2ZW5lVGVzdChTZXBhbC5MZW5ndGggfiBTcGVjaWVzLCBkYXRhID0gLikNCmBgYA0KDQpJbiBhbGwgY2FzZXMsIHRoZSBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50IHJlc3VsdCBpbmRpY2F0ZXMgdGhhdCB0aGVyZSBpcyBldmlkZW5jZSB0aGF0IHRoZSB2YXJpYW5jZSBvZiB0d28gbGV2ZWxzIG9mIHRoZSBmYWN0b3IgYFNwZWNpZXNgIGlzIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQ7IGkuZS4sIHRoZSB2YXJpYW5jZXMgYXJlIG5vdCBlcXVhbC4gVGhpcyBpcyBpbXBvcnRhbnQgYXMgd2Ugd2lsbCB1c2UgdGhpcyBpbiBvdXIgdC10ZXN0IGxhdGVyIG9uDQoNCiMgTGluZWFyIE1vZGVscw0KDQpVcCB0byBub3csIHdlIGhhdmUgbG9va2VkIGF0IGRlc2NyaXB0aXZlIHN0YXRpc3RpY3MsIGFuZCBldmFsdWF0ZWQgc3VtbWFyaWVzLCBjb3JyZWxhdGlvbnMgaW4gdGhlIGRhdGEgKHdpdGggcCB2YWx1ZXMpLCBhbmQgY2hlY2tlZCB0aGUgbm9ybWFsaXR5IG9mIGRpc3RyaWJ1dGlvbiBvZiBvdXIgZGF0YS4NCg0KV2UgYXJlIG5vdyBpbnRlcmVzdGVkIGluIGxvb2tpbmcgYXQgZ3JvdXAgZGlmZmVyZW5jZXMuIA0KDQpMZXQgdXMgc3RhcnQgd2l0aCBhIHNpbXBsZSB0LXRlc3QNCg0KIyMgRmlyc3Qgc3RlcHMNCg0KIyMjIFQtdGVzdA0KDQpXZSB0aGVuIHJ1biBhIHQtdGVzdCBvbiB0aGUgZGF0YS4gV2Ugc3BlY2lmeSB0aGUgZm9ybXVsYSBhcyBgeSB+IHhgIGFuZCBhZGQgYHZhci5lcXVhbCA9IEZBTFNFYCAoYmFzZWQgb24gdGhlIG5vcm1hbGl0eSB0ZXN0cyBhYm92ZSkNCg0KYGBge3J9DQppcmlzU3ViICU+JSANCiAgdC50ZXN0KFNlcGFsLkxlbmd0aCB+IFNwZWNpZXMsIGRhdGEgPSAuLCB2YXIuZXF1YWwgPSBGQUxTRSkNCmBgYA0KDQpUbyBpbnRlcnByZXQgdGhlIHQtdGVzdCwgd2Ugc2F5IHRoYXQgdGhlcmUgaXMgZXZpZGVuY2UgZm9yIGEgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIHR3byBncm91cHM6IGBzZXRvc2FgIGFuZCBgdmVyc2ljb2xvcmA6IGB0KDg2KSA9IC0xMC41MjEsIHAgPCAyLjJlLTE2YC4gVGhlIG1lYW4gb2YgYHNldG9zYWAgaXMgc2lnbmlmaWNhbnRseSBsb3dlciB0aGFuIHRoYXQgb2YgYHZlcnNpY29sb3JgLg0KDQojIyMgTGluZWFyIE1vZGVsDQoNCkxldCB1cyBydW4gYSBsaW5lYXIgbW9kZWwgb24gdGhlIHNhbWUgZGF0YQ0KDQoNCmBgYHtyfQ0KaXJpc1N1YiAlPiUgDQogIGxtKFNlcGFsLkxlbmd0aCB+IFNwZWNpZXMsIGRhdGEgPSAuKSAlPiUgDQogIHN1bW1hcnkoKQ0KYGBgDQoNCkFueSBjb21tZW50cz8gZGlzY3VzcyB3aXRoIHlvdXIgbmVpZ2hib3VyLg0KDQpUaGUgcmVzdWx0cyBvZiB0aGUgbGluZWFyIG1vZGVsIGFyZSBleGFjdGx5IHRoZSBzYW1lLCBhbGJlaXQgd2l0aCBhIGRpZmZlcmVuY2UgaW4gdGhlIHNpZ24gb2YgdGhlIGRpZmZlcmVuY2UuIFRoaXMgaW5kaWNhdGVzIHRoYXQgdGhlICRcYmV0YSQgY29lZmZpY2llbnQgZm9yIGB2ZXJzaWNvbG9yYCBpcyBzaWduaWZpY2FudGx5IGhpZ2hlciB0aGFuIHRoYXQgb2YgYHNldG9zYWAgYnkgYDAuOTMwMDBgOiBgdCg5OCkgPSAxMC41MiwgcCA8IDwyZS0xNmAuDQoNCg0KVGhlIGRhdGFzZXQgYGlyaXNgIGNvbnRhaW5zIHRocmVlIHNwZWNpZXMuIFdlIHdpbGwgcnVuIGFuIEFOT1ZBIGFuZCBhIGxpbmVhciBtb2RlbCBvbiB0aGUgZGF0YS4NCg0KIyMjIEJhc2ljIEFOT1ZBDQoNCldlIGNhbiB1c2UgdGhlIGZ1bmN0aW9uIGBhb3ZgIHRvIHJ1biBhbiBBbmFseXNpcyBvZiBWYXJpYW5jZSBvbiB0aGUgZnVsbCBkYXRhc2V0DQoNCmBgYHtyfQ0KaXJpcyAlPiUgDQogIGFvdihTZXBhbC5MZW5ndGggfiBTcGVjaWVzLCBkYXRhID0gLikgJT4lIA0KICBzdW1tYXJ5KCkNCmBgYA0KDQojIyMgTGluZWFyIG1vZGVsDQoNCldlIGNhbiB1c2UgdGhlIGZ1bmN0aW9uIGBsbWAgdG8gcnVuIGEgbGluZWFyIG1vZGVsDQoNCmBgYHtyfQ0KaXJpcyAlPiUgDQogIGxtKFNlcGFsLkxlbmd0aCB+IFNwZWNpZXMsIGRhdGEgPSAuKSAlPiUgDQogIHN1bW1hcnkoKQ0KYGBgDQoNCkJ1dCB3YWl0Li4uIEhvdyBpcyB0aGUgbGluZWFyIG1vZGVsIGNvbXBhcmFibGUgdG8gdGhlIGFuYWx5c2lzIG9mIHZhcmlhbmNlIHdlIHJhbiBhYm92ZT8gVGhpcyBsaW5lYXIgbW9kZWwgZGVyaXZlcyB0aGUgYW5hbHlzaXMgb2YgdmFyaWFuY2Ugd2Ugc2F3IGFib3ZlLCB1c2UgYGFub3ZhYCBvbiB5b3VyIGxpbmVhciBtb2RlbC4uDQoNCkhlcmUgYXJlIHRoZSByZXN1bHRzIG9mIHRoZSBpbml0aWFsIEFuYWx5c2lzIG9mIHZhcmlhbmNlOg0KDQpgYGB7cn0NCmlyaXMgJT4lIA0KICBhb3YoU2VwYWwuTGVuZ3RoIH4gU3BlY2llcywgZGF0YSA9IC4pICU+JSANCiAgc3VtbWFyeSgpDQpgYGANCg0KQW5kIGhlcmUgYXJlIHRoZSByZXN1bHRzIG9mIHRoZSBsaW5lYXIgbW9kZWwgd2l0aCB0aGUgYGFub3ZhYCBmdW5jdGlvbg0KDQpgYGB7cn0NCmlyaXMgJT4lIA0KICBsbShTZXBhbC5MZW5ndGggfiBTcGVjaWVzLCBkYXRhID0gLikgJT4lIA0KICBhbm92YSgpDQpgYGANCg0KVGhleSBhcmUgZXhhY3RseSB0aGUgc2FtZS4uLiBUaGUgdW5kZXJseWluZyBvZiBhbiBBbmFseXNpcyBvZiB2YXJpYW5jZSBpcyBhIGxpbmVhciBtb2RlbC4gV2Ugd2lsbCBjb250aW51ZSB3aXRoIGEgbGluZWFyIG1vZGVsIHRvIHVuZGVyc3RhbmQgaXQgYmV0dGVyDQoNCiMjIExpbmVhciBNb2RlbA0KDQpUaGUgYmFzaWMgYXNzdW1wdGlvbiBvZiBhIExpbmVhciBtb2RlbCBpcyB0byBjcmVhdGUgYSByZWdyZXNzaW9uIGFuYWx5c2lzIG9uIHRoZSBkYXRhLiBXZSBoYXZlIGFuIG91dGNvbWUgKG9yIGRlcGVuZGVudCB2YXJpYWJsZSkgYW5kIGEgcHJlZGljdG9yIChvciBhbiBpbmRlcGVuZGVudCB2YXJpYWJsZSkuIFRoZSBmb3JtdWxhIG9mIGEgbGluZWFyIG1vZGVsIGlzIGFzIGZvbGxvd3MgYG91dGNvbWUgfiBwcmVkaWN0b3JgIHRoYXQgY2FuIGJlIHJlYWQgYXMgIm91dGNvbWUgYXMgYSBmdW5jdGlvbiBvZiB0aGUgcHJlZGljdG9yIi4gV2UgY2FuIGFkZCAiMSIgdG8gc3BlY2lmeSBhbiBpbnRlcmNlcHQsIGJ1dCB0aGlzIGlzIGJ5IGRlZmF1bHQgYWRkZWQgdG8gdGhlIG1vZGVsDQoNCiMjIyBNb2RlbCBlc3RpbWF0aW9uDQoNCmBgYHtyIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGVycm9yPUZBTFNFfQ0KbWRsLmxtIDwtIGlyaXMgJT4lIA0KICBsbShTZXBhbC5MZW5ndGggfiBTcGVjaWVzLCBkYXRhID0gLikNCiMgc2FtZSBhcyBiZWxvdy4NCiNtZGwubG0gPC0gbG0oU2VwYWwuTGVuZ3RoIH4gMSArIFNwZWNpZXMsIGRhdGEgPSBpcmlzKQ0KbWRsLmxtICNhbHNvIHByaW50KG1kbC5sbSkNCnN1bW1hcnkobWRsLmxtKQ0KYGBgDQoNCiMjIyBUaWR5aW5nIHRoZSBvdXRwdXQNCg0KYGBge3J9DQojIGZyb20gbGlicmFyeShicm9vbSkNCnRpZHkobWRsLmxtKSAlPiUgDQogIHNlbGVjdCh0ZXJtLCBlc3RpbWF0ZSkgJT4lIA0KICBtdXRhdGUoZXN0aW1hdGUgPSByb3VuZChlc3RpbWF0ZSwgMykpDQpteWNvZWZFIDwtIHRpZHkobWRsLmxtKSAlPiUgcHVsbChlc3RpbWF0ZSkNCg0KYGBgDQoNCg0KDQpUbyBpbnRlcnByZXQgdGhlIG1vZGVsLCB3ZSBuZWVkIGxvb2sgYXQgdGhlIGNvZWZmaWNpZW50cy4gVGhlIGBJbnRlcmNlcHRgICg9U2V0b3NhKSBpcyBgciBteWNvZWZFWzFdYCBhbmQgdGhlIGNvZWZmaWNpZW50cyBmb3IgYFZlcnNpY29sb3JgIGFuZCBmb3IgYFZpcmdpbmljYWAgYXJlIHJlc3BlY3RpdmVseSBgciBteWNvZWZFWzJdYCBhbmQgYHIgbXljb2VmRVszXWAgVGhpcyB0ZWxscyB1cyB0aGF0IGNvbXBhcmVkIHRvIGBTZXRvc2FgLCBtb3ZpbmcgZnJvbSB0aGlzIGNhdGVnb3J5IHRvIGBWZXJzaWNvbG9yYCBsZWFkcyB0byBhIHNpZ25pZmljYW50IGluY3JlYXNlIGJ5IGByIG15Y29lZkVbMl1gLCBhbmQgZm9yIGBWaXJnaW5pY2FgLCB0aGVyZSBpcyBhIHNpZ25pZmljYW50IGluY3JlYXNlIGJ5IGByIG15Y29lZkVbM11gLiANCg0KIyMjIE9idGFpbmluZyBvdXIgInRydWUiIGNvZWZmaWNpZW50cw0KDQpCdXQgd2hlcmUgYXJlIG91ciBhY3R1YWwgdmFsdWVzIGJhc2VkIG9uIHRoZSBtZWFucyBpbiB0aGUgdGFibGUgYWJvdmU/DQoNCldlIHJ1biBhIG1vZGVsIHRoYXQgc3VwcHJlc3NlcyB0aGUgaW50ZXJjZXB0IChpLmUuLCBhZGRpbmcgMCBpbnN0ZWFkIG9mIDEpIGFuZCB0aGlzIHdpbGwgYWxsb3cgdXMgdG8gb2J0YWluIHRoZSAidHJ1ZSIgY29lZmZpY2llbnRzIGZvciBlYWNoIGxldmVsIG9mIG91ciBwcmVkaWN0b3IuIFRoaXMgaXMgYWxzbyBrbm93biBhcyBhIGBzYXR1cmF0ZWRgIG1vZGVsDQoNCmBgYHtyfQ0KbWRsLmxtLjIgPC0gaXJpcyAlPiUgDQogIGxtKFNlcGFsLkxlbmd0aCB+IDAgKyBTcGVjaWVzLCBkYXRhID0gLikNCnN1bW1hcnkobWRsLmxtLjIpDQpgYGANCg0KVGhpcyBtYXRjaGVzIHRoZSBvcmlnaW5hbCBkYXRhLiBgU2V0b3NhYCBoYXMgYSBtZWFuIG9mIGByIG15Y29lZkVbMV1gLCBgVmVyc2ljb2xvcmAgYHIgbXljb2VmRVsxXSArIG15Y29lZkVbMl1gLCBhbmQgYFZpcmdpbmljYWAgYHIgbXljb2VmRVsxXSArIG15Y29lZkVbMl1gLiBTZWUgdGFibGUgYWJvdmUgYW5kIGNvZWZmaWNpZW50cyBiZWxvdyANCg0KYGBge3J9DQojU2V0b3NhDQpteWNvZWZFWzFdDQojVmVyc2ljb2xvcg0KbXljb2VmRVsxXSArIG15Y29lZkVbMl0NCiNWaXJnaW5pY2ENCm15Y29lZkVbMV0gKyBteWNvZWZFWzNdDQpgYGANCg0KVGhlIHNhbWUgYXMNCg0KYGBge3J9DQp0aWR5KG1kbC5sbS4yKSAlPiUgDQogIHNlbGVjdCh0ZXJtLCBlc3RpbWF0ZSkgJT4lIA0KICBtdXRhdGUoZXN0aW1hdGUgPSByb3VuZChlc3RpbWF0ZSwgMykpDQpteWNvZWZFIDwtIHRpZHkobWRsLmxtLjIpICU+JQ0KICBwdWxsKGVzdGltYXRlKQ0KDQojU2V0b3NhDQpteWNvZWZFWzFdDQojVmVyc2ljb2xvcg0KbXljb2VmRVsyXQ0KI1ZpcmdpbmljYQ0KbXljb2VmRVszXQ0KYGBgDQoNCg0KIyMjIE5pY2UgdGFibGUgb2Ygb3VyIG1vZGVsIHN1bW1hcnkNCg0KV2UgY2FuIGFsc28gb2J0YWluIGEgbmljZSB0YWJsZSBvZiBvdXIgbW9kZWwgc3VtbWFyeS4gV2UgY2FuIHVzZSB0aGUgcGFja2FnZSBga25pdHJgIG9yIGB4dGFibGVgDQoNCiMjIyMgRGlyZWN0bHkgZnJvbSBtb2RlbCBzdW1tYXJ5DQoNCmBgYHtyfQ0Ka2FibGUoc3VtbWFyeShtZGwubG0pJGNvZWYsIGRpZ2l0cyA9IDMpDQoNCmBgYA0KDQojIyMjIEZyb20gdGhlIGB0aWR5YCBvdXRwdXQNCg0KYGBge3J9DQptZGwubG1UIDwtIHRpZHkobWRsLmxtKQ0Ka2FibGUobWRsLmxtVCwgZGlnaXRzID0gMykNCmBgYA0KDQoNCiMjIyBEaXNzZWN0aW5nIHRoZSBtb2RlbA0KDQpMZXQgdXMgZGlzc2VjdCB0aGUgbW9kZWwuIElmIHlvdSB1c2UgInN0ciIsIHlvdSB3aWxsIGJlIGFibGUgdG8gc2VlIHdoYXQgaXMgYXZhaWxhYmxlIHVuZGVyIG91ciBsaW5lYXIgbW9kZWwuIFRvIGFjY2VzcyBzb21lIGluZm8gZnJvbSB0aGUgbW9kZWwNCg0KIyMjIyAic3RyIiBhbmQgImNvZWYiDQoNCmBgYHtyIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGVycm9yPUZBTFNFfQ0Kc3RyKG1kbC5sbSkNCmNvZWYobWRsLmxtKQ0KIyMgc2FtZSBhcyANCiMjIG1kbC5sbSRjb2VmZmljaWVudHMNCmBgYA0KDQojIyMjICJjb2VmIiBhbmQgImNvZWZmaWNpZW50cyINCg0KV2hhdCBpZiBJIHdhbnQgdG8gb2J0YWluIHRoZSAiSW50ZXJjZXB0Ij8gT3IgdGhlIGNvZWZmaWNpZW50IGZvciBkaXN0YW5jZT8gV2hhdCBpZiBJIHdhbnQgdGhlIGZ1bGwgcm93IGZvciBkaXN0YW5jZT8NCg0KYGBge3Igd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgZXJyb3I9RkFMU0V9DQpjb2VmKG1kbC5sbSlbMV0gIyBzYW1lIGFzIG1kbC5sbSRjb2VmZmljaWVudHNbMV0NCmNvZWYobWRsLmxtKVsyXSAjIHNhbWUgYXMgbWRsLmxtJGNvZWZmaWNpZW50c1syXQ0KDQpzdW1tYXJ5KG1kbC5sbSkkY29lZmZpY2llbnRzWzIsIF0gIyBmdWxsIHJvdw0Kc3VtbWFyeShtZGwubG0pJGNvZWZmaWNpZW50c1syLCA0XSAjZm9yIHAgdmFsdWUNCg0KYGBgDQoNCg0KIyMjIyBVcCB0byB5b3UNCg0KUGxheSBhcm91bmQgd2l0aCB0aGUgbW9kZWwgc3VtbWFyeSBhbmQgb2J0YWluIHRoZSB0IHZhbHVlcyBmb3IgdGhlIHRocmVlIGxldmVscy4gWW91IGNhbiBkbyB0aGlzIGJ5IHJlZmVycmluZyB0byB0aGUgY29lZmZpY2llbnQgYXMgYWJvdmUNCg0KYGBge3J9DQoNCmBgYA0KDQoNCiMjIyMgUmVzaWR1YWxzDQoNCldoYXQgYWJvdXQgcmVzaWR1YWxzIChkaWZmZXJlbmNlIGJldHdlZW4gdGhlIG9ic2VydmVkIHZhbHVlIGFuZCB0aGUgZXN0aW1hdGVkIHZhbHVlIG9mIHRoZSBxdWFudGl0eSkgYW5kIGZpdHRlZCB2YWx1ZXM/DQoNCmBgYHtyIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGVycm9yPUZBTFNFfQ0KaGlzdChyZXNpZHVhbHMobWRsLmxtKSkNCnFxbm9ybShyZXNpZHVhbHMobWRsLmxtKSk7IHFxbGluZShyZXNpZHVhbHMobWRsLmxtKSkNCnBsb3QoZml0dGVkKG1kbC5sbSksIHJlc2lkdWFscyhtZGwubG0pLCBjZXggPSA0KQ0KYGBgDQoNCiMjIyMgR29vZG5lc3Mgb2YgZml0Pw0KDQpgYGB7ciB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBlcnJvcj1GQUxTRX0NCkFJQyhtZGwubG0pCSMgQWthaWtlJ3MgSW5mb3JtYXRpb24gQ3JpdGVyaW9uLCBsb3dlciB2YWx1ZXMgYXJlIGJldHRlcg0KQklDKG1kbC5sbSkJIyBCYXllc2lhbiBBSUMNCmxvZ0xpayhtZGwubG0pCSMgbG9nIGxpa2VsaWhvb2QNCmBgYA0KDQoNCk9yIHVzZSB0aGUgZm9sbG93aW5nIGZyb20gYGJyb29tYA0KDQpgYGB7cn0NCmdsYW5jZShtZGwubG0pDQpgYGANCg0KDQojIyMjIFNpZ25pZmljYW5jZSB0ZXN0aW5nDQoNCkFyZSB0aGUgYWJvdmUgaW5mb3JtYXRpdmU/IG9mIGNvdXJzZSBub3QgZGlyZWN0bHkuIElmIHdlIHdhbnQgdG8gdGVzdCBmb3Igb3ZlcmFsbCBzaWduaWZpY2FuY2Ugb2YgbW9kZWwuIFdlIHJ1biBhIG51bGwgbW9kZWwgKGFrYSBpbnRlcmNlcHQgb25seSkgYW5kIGNvbXBhcmUgbW9kZWxzLg0KDQpgYGB7ciB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBlcnJvcj1GQUxTRX0NCm1kbC5sbS5OdWxsIDwtIGlyaXMgJT4lIA0KICBsbShTZXBhbC5MZW5ndGggfiAxLCBkYXRhID0gLikNCm1kbC5jb21wIDwtIGFub3ZhKG1kbC5sbS5OdWxsLCBtZGwubG0pDQptZGwuY29tcA0KYGBgDQoNClRoZSByZXN1bHRzIHNob3cgdGhhdCBhZGRpbmcgdGhlIGZhY3RvciAiU3BlY2llcyIgaW1wcm92ZXMgdGhlIG1vZGVsIGZpdC4gV2UgY2FuIHdyaXRlIHRoaXMgYXMgZm9sbG93czogTW9kZWwgY29tcGFyaXNvbiBzaG93ZWQgdGhhdCB0aGUgYWRkaXRpb24gb2YgU3BlY2llcyBpbXByb3ZlZCB0aGUgbW9kZWwgZml0IHdoZW4gY29tcGFyZWQgd2l0aCBhbiBpbnRlcmNlcHQgb25seSBtb2RlbCAoJEYkKGByIG1kbC5jb21wWzIsM11gKSA9IGByIHJvdW5kKG1kbC5jb21wWzIsNV0sIDIpYCwgKnAqIDwgYHIgbWRsLmNvbXBbMiw2XWApIA0KDQojIyMjIFBsb3R0aW5nIGZpdHRlZCB2YWx1ZXMNCg0KIyMjIyMgVHJlbmQgbGluZQ0KDQpMZXQncyBwbG90IG91ciBmaXR0ZWQgdmFsdWVzIGJ1dCBvbmx5IGZvciB0aGUgdHJlbmQgbGluZQ0KDQpgYGB7ciB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBlcnJvcj1GQUxTRX0NCmlyaXMgJT4lIA0KICBnZ3Bsb3QoYWVzKHggPSBTcGVjaWVzLCB5ID0gU2VwYWwuTGVuZ3RoKSkrDQogIGdlb21fYm94cGxvdCgpICsNCiAgbGFicyh4ID0gIlNwZWNpZXMiLCB5ID0gIkxlbmd0aCIsIHRpdGxlID0gIkJveHBsb3QgYW5kIHByZWRpY3RlZCB0cmVuZCBsaW5lIiwgc3VidGl0bGUgPSAid2l0aCBnZ3Bsb3QyIikgKyANCiAgdGhlbWVfYncoKSArIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1KSkrDQogIGdlb21fc21vb3RoKGFlcyh4ID0gYXMubnVtZXJpYyhTcGVjaWVzKSwgeSA9IHByZWRpY3QobWRsLmxtKSksIG1ldGhvZCA9ICJsbSIsIGNvbG9yID0gImJsdWUiKQ0KYGBgDQoNClRoaXMgYWxsb3dzIHVzIHRvIHBsb3QgdGhlIGZpdHRlZCB2YWx1ZXMgZnJvbSBvdXIgbW9kZWwgd2l0aCB0aGUgcHJlZGljdGVkIGxpbmVhciB0cmVuZC4gVGhpcyBpcyBleGFjdGx5IHRoZSBzYW1lIGFzIG91ciBvcmlnaW5hbCBkYXRhLg0KDQojIyMjIyBQcmVkaWN0ZWQgbWVhbnMgYW5kIHRoZSB0cmVuZCBsaW5lDQoNCldlIGNhbiBhbHNvIHBsb3QgdGhlIHByZWRpY3RlZCBtZWFucyBhbmQgbGluZWFyIHRyZW5kDQoNCmBgYHtyIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGVycm9yPUZBTFNFfQ0KaXJpcyAlPiUgDQogIGdncGxvdChhZXMoeCA9IFNwZWNpZXMsIHkgPSBwcmVkaWN0KG1kbC5sbSkpKSsNCiAgZ2VvbV9ib3hwbG90KGNvbG9yID0gImJsdWUiKSArDQogIGxhYnMoeCA9ICJTcGVjaWVzIiwgeSA9ICJMZW5ndGgiLCB0aXRsZSA9ICJQcmVkaWN0ZWQgbWVhbnMgYW5kIHRyZW5kIGxpbmUiLCBzdWJ0aXRsZSA9ICJ3aXRoIGdncGxvdDIiKSArIA0KICB0aGVtZV9idygpICsgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUpKSsNCiAgZ2VvbV9zbW9vdGgoYWVzKHggPSBhcy5udW1lcmljKFNwZWNpZXMpLCB5ID0gcHJlZGljdChtZGwubG0pKSwgbWV0aG9kID0gImxtIiwgY29sb3IgPSAiYmx1ZSIpDQpgYGANCg0KDQojIyMjIyBSYXcgZGF0YSwgcHJlZGljdGVkIG1lYW5zIGFuZCB0aGUgdHJlbmQgbGluZQ0KDQpXZSBjYW4gYWxzbyBwbG90IHRoZSBhY3R1YWwgZGF0YSwgdGhlIHByZWRpY3RlZCBtZWFucyBhbmQgbGluZWFyIHRyZW5kDQoNCmBgYHtyIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGVycm9yPUZBTFNFfQ0KaXJpcyAlPiUgDQogIGdncGxvdChhZXMoeCA9IFNwZWNpZXMsIHkgPSBTZXBhbC5MZW5ndGgpKSsNCiAgZ2VvbV9ib3hwbG90KCkrDQogIGdlb21fYm94cGxvdChhZXMoeCA9IFNwZWNpZXMsIHkgPSBwcmVkaWN0KG1kbC5sbSkpLCBjb2xvciA9ICJibHVlIikgKw0KICBsYWJzKHggPSAiU3BlY2llcyIsIHkgPSAiTGVuZ3RoIiwgdGl0bGUgPSAiQm94cGxvdCByYXcgZGF0YSwgcHJlZGljdGVkIG1lYW5zIChpbiBibHVlKSBhbmQgdHJlbmQgbGluZSIsIHN1YnRpdGxlID0gIndpdGggZ2dwbG90MiIpICsgDQogIHRoZW1lX2J3KCkgKyB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSkpKw0KICBnZW9tX3Ntb290aChhZXMoeCA9IGFzLm51bWVyaWMoU3BlY2llcyksIHkgPSBwcmVkaWN0KG1kbC5sbSkpLCBtZXRob2QgPSAibG0iLCBjb2xvciA9ICJibHVlIikNCmBgYA0KDQoNCiMjIyBXaGF0IGFib3V0IHBhaXJ3aXNlIGNvbXBhcmlzb24/DQoNCkJhc2VkIG9uIG91ciBtb2RlbCdzIHN1bW1hcnksIGNhbiB5b3UgdGVsbCBtZSBpZiB0aGVyZSBpcyBhIGRpZmZlcmVuY2UgYmV0d2VlbiBWZXJzaWNvbG9yIGFuZCBWaXJnaW5pY2E/DQoNCmBgYHtyfQ0Kc3VtbWFyeShtZGwubG0pDQpgYGANCg0KDQpgYGB7cn0NCm1kbC5sbSAlPiUgZW1tZWFucyhwYWlyd2lzZSB+IFNwZWNpZXMsIGFkanVzdCA9ICJmZHIiKSAtPiBtZGwuZW1tZWFucw0KbWRsLmVtbWVhbnMNCmBgYA0KDQpIb3cgdG8gaW50ZXJwcmV0IHRoZSBvdXRwdXQ/IERpc2N1c3Mgd2l0aCB5b3VyIG5laWdoYm91ciBhbmQgc2hhcmUgd2l0aCB0aGUgZ3JvdXAuDQoNCkhpbnQuLi4gTG9vayBhdCB0aGUgZW1tZWFucyB2YWx1ZXMgZm9yIGVhY2ggbGV2ZWwgb2Ygb3VyIGZhY3RvciAiU3BlY2llcyIgYW5kIHRoZSBjb250cmFzdHMuIA0KDQojIyMjIEFkZCBzaWduaWZpY2FuY2UgbGV2ZWxzIG9uIGEgcGxvdD8NCg0KV2UgY2FuIHVzZSB0aGUgcCB2YWx1ZXMgZ2VuZXJhdGVkIGZyb20gZWl0aGVyIG91ciBsaW5lYXIgbW9kZWwgb3IgdGhlIHBhaXJ3aXNlIGNvbXBhcmlzb24gdG8gYWRkIHNpZ25pZmljYW5jZSBsZXZlbHMgb24gYSBwbG90LiBXZSB1c2UgdGhlIGNvZGUgZnJvbSBhYm92ZSBhbmQgYWRkIHRoZSBzaWduaWZpY2FuY2UgbGV2ZWwNCg0KDQpgYGB7ciB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBlcnJvcj1GQUxTRX0NCmlyaXMgJT4lIA0KICBnZ3Bsb3QoYWVzKHggPSBTcGVjaWVzLCB5ID0gU2VwYWwuTGVuZ3RoKSkrDQogIGdlb21fYm94cGxvdCgpKw0KICBnZW9tX2JveHBsb3QoYWVzKHggPSBTcGVjaWVzLCB5ID0gcHJlZGljdChtZGwubG0pKSwgY29sb3IgPSAiYmx1ZSIpICsNCiAgbGFicyh4ID0gIlNwZWNpZXMiLCB5ID0gIkxlbmd0aCIsIHRpdGxlID0gIkJveHBsb3QgcmF3IGRhdGEsIHByZWRpY3RlZCBtZWFucyAoaW4gYmx1ZSkgYW5kIHRyZW5kIGxpbmUiLCBzdWJ0aXRsZSA9ICJ3aXRoIGdncGxvdDIiKSArIA0KICB0aGVtZV9idygpICsgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUpKSsNCiAgZ2VvbV9zbW9vdGgoYWVzKHggPSBhcy5udW1lcmljKFNwZWNpZXMpLCB5ID0gcHJlZGljdChtZGwubG0pKSwgbWV0aG9kID0gImxtIiwgY29sb3IgPSAiYmx1ZSIpICsgDQogIGdlb21fc2lnbmlmKGNvbXBhcmlzb24gPSBsaXN0KGMoInNldG9zYSIsICJ2ZXJzaWNvbG9yIikpLCANCiAgICAgICAgICAgICAgbWFwX3NpZ25pZl9sZXZlbCA9IFRSVUUsIHRlc3QgPSBmdW5jdGlvbihhLCBiKSB7DQogICAgICAgICAgICAgICAgbGlzdChwLnZhbHVlID0gc3VtbWFyeShtZGwuZW1tZWFucykkY29udHJhc3RzWzEsIDZdKX0pICsgDQogIGdlb21fc2lnbmlmKGNvbXBhcmlzb24gPSBsaXN0KGMoInZlcnNpY29sb3IiLCAidmlyZ2luaWNhIikpLCANCiAgICAgICAgICAgICAgbWFwX3NpZ25pZl9sZXZlbCA9IFRSVUUsIHRlc3QgPSBmdW5jdGlvbihhLCBiKSB7DQogICAgICAgICAgICAgICAgbGlzdChwLnZhbHVlID0gc3VtbWFyeShtZGwuZW1tZWFucykkY29udHJhc3RzWzMsIDZdKX0pDQpgYGANCg0KDQoNCiMjIE90aGVyIG91dGNvbWVzPw0KDQpTbyBmYXIsIHdlIG9ubHkgbG9va2VkIGF0ICJTZXBhbC5MZW5ndGgiLiBXaGF0IGFib3V0IHRoZSBvdGhlciBvdXRjb21lcz8gaG93IGluZm9ybWF0aXZlIGFyZSB0aGV5PyBEbyB3ZSBoYXZlIHN0YXRpc3RpY2FsIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgdGhyZWUgbGV2ZWxzIG9mIG91ciBwcmVkaWN0b3I/IFlvdSBjYW4gZG8gdGhpcyBpbiB5b3VyIHNwYXJlIHRpbWUuDQoNCiMjIENvbmNsdXNpb24NCg0KV2UgaGF2ZSBzbyBmYXIgbG9va2VkIGF0IHRoZSBMaW5lYXIgTW9kZWwuIFRoZSB1bmRlcmx5aW5nIGFzc3VtcHRpb24gYWJvdXQgbGluZWFyIG1vZGVscyBpcyB0aGF0IHdlIGhhdmUgYSBub3JtYWwgKEdhdXNzaWFuKSBkaXN0cmlidXRpb24uIFRoaXMgaXMgdGhlIG1vZGVsIHRvIGJlIHVzZWQgd2hlbiB3ZSBoYXZlIGEgYG51bWVyaWNgIG91dGNvbWUuIFdoYXQgaWYgb3VyIG91dGNvbWUgaXMgbm90IG51bWVyaWM/IFdoYXQgaWYgd2UgaGF2ZSB0d28gY2F0ZWdvcmllcywgaS5lLiwgYmxhY2sgdnMgd2hpdGU/IGNvcnJlY3QgdnMgaW5jb3JyZWN0PyB5ZXMgdnMgbm8/IFRoZXNlIGFyZSBjYXRlZ29yaWNhbCAqKmJpbmFyeSoqIG91dGNvbWUuIFdlIGxvb2sgaW4gdGhlIG5leHQgc2VjdGlvbiBhdCBMb2dpc3RpYyBSZWdyZXNzaW9uDQoNCiMgR2VuZXJhbGlzZWQgTGluZWFyIE1vZGVscw0KDQpIZXJlIHdlIHdpbGwgbG9vayBhdCBhbiBleGFtcGxlIHdoZW4gdGhlIG91dGNvbWUgaXMgYmluYXJ5LiBUaGlzIHNpbXVsYXRlZCBkYXRhIGlzIHN0cnVjdHVyZWQgYXMgZm9sbG93cy4gV2UgYXNrZWQgb25lIHBhcnRpY2lwYW50IHRvIGxpc3RlbiB0byAxNjUgc2VudGVuY2VzLCBhbmQgdG8ganVkZ2Ugd2hldGhlciB0aGVzZSBhcmUgImdyYW1tYXRpY2FsIiBvciAidW5ncmFtbWF0aWNhbCIuIFRoZXJlIHdlcmUgMTA1IHNlbnRlbmNlcyB0aGF0IHdlcmUgImdyYW1tYXRpY2FsIiBhbmQgNjAgInVuZ3JhbW1hdGljYWwiLiBUaGlzIGZpY3RpdGlvdXMgZXhhbXBsZSBjYW4gYXBwbHkgaW4gYW55IG90aGVyIHNpdHVhdGlvbi4gTGV0J3MgdGhpbmsgR2VvZ3JhcGh5OiAxNjUgbGFuZHM6IDEwNSAiZmxhdCIgYW5kIDYwICJub24tZmxhdCIsIGV0Yy4gVGhpcyBhcHBsaWVzIHRvIGFueSBjYXNlIHdoZXJlIHlvdSBuZWVkIHRvICJjYXRlZ29yaXNlIiB0aGUgb3V0Y29tZSBpbnRvIHR3byBncm91cHMuIA0KDQojIyBMb2FkIGFuZCBzdW1tYXJpZXMNCg0KTGV0J3MgbG9hZCBpbiB0aGUgZGF0YSBhbmQgZG8gc29tZSBiYXNpYyBzdW1tYXJpZXMNCg0KYGBge3Igd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgZXJyb3I9RkFMU0V9DQpncmFtbWF0aWNhbCA8LSByZWFkX2NzdigiZ3JhbW1hdGljYWwuY3N2IikNCmdyYW1tYXRpY2FsDQpzdHIoZ3JhbW1hdGljYWwpDQpoZWFkKGdyYW1tYXRpY2FsKQ0KYGBgDQoNCiMjIEdMTQ0KDQpMZXQncyBydW4gYSBmaXJzdCBHTE0gKEdlbmVyYWxpc2VkIExpbmVhciBNb2RlbCkuIEEgR0xNIHVzZXMgYSBzcGVjaWFsIGZhbWlseSAiYmlub21pYWwiIGFzIGl0IGFzc3VtZXMgdGhlIG91dGNvbWUgaGFzIGEgYmlub21pYWwgZGlzdHJpYnV0aW9uLiBJbiBnZW5lcmFsLCByZXN1bHRzIGZyb20gYSBMb2dpc3RpYyBSZWdyZXNzaW9uIGFyZSBjbG9zZSB0byB3aGF0IHdlIGdldCBmcm9tIFNEVCAoc2VlIGFib3ZlKS4NCg0KVG8gcnVuIHRoZSByZXN1bHRzLCB3ZSB3aWxsIGNoYW5nZSB0aGUgcmVmZXJlbmNlIGxldmVsIGZvciBib3RoIHJlc3BvbnNlIGFuZCBncmFtbWF0aWNhbGl0eS4gVGhlIGJhc2ljIGFzc3VtcHRpb24gYWJvdXQgR0xNIGlzIHRoYXQgd2Ugc3RhcnQgd2l0aCBvdXIgcmVmZXJlbmNlIGxldmVsIGJlaW5nIHRoZSAibm8iIHJlc3BvbnNlcyB0byB0aGUgInVuZ3JhbW1hdGljYWwiIGNhdGVnb3J5LiBBbnkgY2hhbmdlcyB0byB0aGlzIHJlZmVyZW5jZSB3aWxsIGJlIHNlZW4gaW4gdGhlIGNvZWZmaWNpZW50cyBhcyAieWVzIiByZXNwb25zZXMgdG8gdGhlICJncmFtbWF0aWNhbCIgY2F0ZWdvcnkuDQoNCiMjIyBNb2RlbCBlc3RpbWF0aW9uIGFuZCByZXN1bHRzDQoNClRoZSByZXN1bHRzIGJlbG93IHNob3cgdGhlIGxvZ29kZHMgZm9yIG91ciBtb2RlbC4gDQoNCmBgYHtyIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGVycm9yPUZBTFNFfQ0KZ3JhbW1hdGljYWwgPC0gZ3JhbW1hdGljYWwgJT4lIA0KICBtdXRhdGUocmVzcG9uc2UgPSBmYWN0b3IocmVzcG9uc2UsIGxldmVscyA9IGMoIm5vIiwgInllcyIpKSwNCiAgICAgICAgIGdyYW1tYXRpY2FsaXR5ID0gZmFjdG9yKGdyYW1tYXRpY2FsaXR5LCBsZXZlbHMgPSBjKCJ1bmdyYW1tYXRpY2FsIiwgImdyYW1tYXRpY2FsIikpKQ0KDQpncmFtbWF0aWNhbCAlPiUgDQogIGdyb3VwX2J5KGdyYW1tYXRpY2FsaXR5LCByZXNwb25zZSkgJT4lIA0KICB0YWJsZSgpDQoNCm1kbC5nbG0gPC0gZ3JhbW1hdGljYWwgJT4lIA0KICBnbG0ocmVzcG9uc2UgfiBncmFtbWF0aWNhbGl0eSwgZGF0YSA9IC4sIGZhbWlseSA9IGJpbm9taWFsKQ0Kc3VtbWFyeShtZGwuZ2xtKQ0KDQp0aWR5KG1kbC5nbG0pICU+JSANCiAgc2VsZWN0KHRlcm0sIGVzdGltYXRlKSAlPiUgDQogIG11dGF0ZShlc3RpbWF0ZSA9IHJvdW5kKGVzdGltYXRlLCAzKSkNCiMgdG8gb25seSBnZXQgdGhlIGNvZWZmaWNpZW50cw0KbXljb2VmMiA8LSB0aWR5KG1kbC5nbG0pICU+JSBwdWxsKGVzdGltYXRlKQ0KYGBgDQoNCg0KVGhlIHJlc3VsdHMgc2hvdyB0aGF0IGZvciBvbmUgdW5pdCBpbmNyZWFzZSBpbiB0aGUgcmVzcG9uc2UgKGkuZS4sIGZyb20gbm8gdG8geWVzKSwgdGhlIGxvZ29kZHMgb2YgYmVpbmcgImdyYW1tYXRpY2FsIiBpcyBpbmNyZWFzZWQgYnkgYHIgbXljb2VmMlsyXWAgKHRoZSBpbnRlcmNlcHQgc2hvd3MgdGhhdCB3aGVuIHRoZSByZXNwb25zZSBpcyAibm8iLCB0aGUgbG9nb2RkcyBhcmUgYHIgbXljb2VmMlsxXWApLiBUaGUgYWN0dWFsIGxvZ29kZHMgZm9yIHRoZSByZXNwb25zZSAieWVzIiB0byBncmFtbWF0aWNhbCBpcyBgciBteWNvZWYyWzFdK215Y29lZjJbMl1gIA0KDQojIyMgTG9nb2RkcyB0byBPZGQgcmF0aW9zDQoNCkxvZ29kZHMgY2FuIGJlIG1vZGlmaWVkIHRvIHRhbGsgYWJvdXQgdGhlIG9kZHMgb2YgYW4gZXZlbnQuIEZvciBvdXIgbW9kZWwgYWJvdmUsIHRoZSBvZGRzIG9mICJncmFtbWF0aWNhbCIgcmVjZWl2aW5nIGEgIm5vIiByZXNwb25zZSBpcyBhIG1lcmUgMC4yOyB0aGUgb2RkcyBvZiAiZ3JhbW1hdGljYWwiIHRvIHJlY2VpdmUgYSAieWVzIiBpcyBhIDIwOyBpLmUuLCAyMCB0aW1lcyBtb3JlIGxpa2VseSANCg0KDQpgYGB7ciB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBlcnJvcj1GQUxTRX0NCmV4cChteWNvZWYyWzFdKQ0KZXhwKG15Y29lZjJbMV0gKyBteWNvZWYyWzJdKQ0KDQpgYGANCg0KIyMjIExvZ09kZHMgdG8gcHJvcG9ydGlvbnMNCg0KSWYgeW91IHdhbnQgdG8gdGFsayBhYm91dCB0aGUgcGVyY2VudGFnZSAiYWNjdXJhY3kiIG9mIG91ciBtb2RlbCwgdGhlbiB3ZSBjYW4gdHJhbnNmb3JtIG91ciBsb2dnb2RkcyBpbnRvIHByb3BvcnRpb25zLiBUaGlzIHNob3dzIHRoYXQgdGhlIHByb3BvcnRpb24gb2YgImdyYW1tYXRpY2FsIiByZWNlaXZpbmcgYSAieWVzIiByZXNwb25zZSBpbmNyZWFzZXMgYnkgOTklIChvciA5NSUgYmFzZWQgb24gb3VyICJ0cnVlIiBjb2VmZmljaWVudHMpDQoNCmBgYHtyIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGVycm9yPUZBTFNFfQ0KcGxvZ2lzKG15Y29lZjJbMV0pDQpwbG9naXMobXljb2VmMlsxXSArIG15Y29lZjJbMl0pDQpgYGANCg0KIyMjIFBsb3R0aW5nDQoNCmBgYHtyIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGVycm9yPUZBTFNFfQ0KZ3JhbW1hdGljYWwgPC0gZ3JhbW1hdGljYWwgJT4lIA0KICBtdXRhdGUocHJvYiA9IHByZWRpY3QobWRsLmdsbSwgdHlwZSA9ICJyZXNwb25zZSIpKQ0KZ3JhbW1hdGljYWwgJT4lIA0KICBnZ3Bsb3QoYWVzKHggPSBhcy5udW1lcmljKGdyYW1tYXRpY2FsaXR5KSwgeSA9IHByb2IpKSArDQogIGdlb21fcG9pbnQoKSArDQogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJnbG0iLCANCiAgICBtZXRob2QuYXJncyA9IGxpc3QoZmFtaWx5ID0gImJpbm9taWFsIiksIA0KICAgIHNlID0gVCkgKyB0aGVtZV9idyhiYXNlX3NpemUgPSAyMCkrDQogICAgbGFicyh5ID0gIlByb2JhYmlsaXR5IiwgeCA9ICIiKSsNCiAgICBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoMCwxKSkrDQogICAgc2NhbGVfeF9kaXNjcmV0ZShsaW1pdHMgPSBjKCJVbmdyYW1tYXRpY2FsIiwgIkdyYW1tYXRpY2FsIikpDQpgYGANCg0KIyMgQWNjdXJhY3kgYW5kIFNpZ25hbCBEZXRlY3Rpb24gVGhlb3J5DQoNCiMjIyBSYXRpb25hbGUNCg0KV2UgYXJlIGdlbmVyYWxseSBpbnRlcmVzdGVkIGluIHBlcmZvcm1hbmNlLCBpLmUuLCB3aGV0aGVyIHRoZSB3ZSBoYXZlICJhY2N1cmF0ZWx5IiBjYXRlZ29yaXNlZCB0aGUgb3V0Y29tZSBvciBub3QgYW5kIGF0IHRoZSBzYW1lIHRpbWUgd2FudCB0byBldmFsdWF0ZSBvdXIgYmlhc2VzIGluIHJlc3BvbnNlcy4gV2hlbiBkZWNpZGluZyBvbiBjYXRlZ29yaWVzLCB3ZSBhcmUgdXN1YWxseSBiaWFzZWQgaW4gb3VyIHNlbGVjdGlvbi4gDQoNCkxldCdzIGFzayB0aGUgcXVlc3Rpb246IEhvdyBtYW55IG9mIHlvdSBoYXZlIGEgTWFjIGxhcHRvcCBhbmQgaG93IG1hbnkgYSBXaW5kb3dzIGxhcHRvcD8gRm9yIHRob3NlIHdpdGggYSBNYWMsIHdoYXQgd2FzIHRoZSBtYWluIHJlYXNvbiBmb3IgY2hvb3NpbmcgaXQ/IEFyZSB5b3UgYmlhc2VkIGluIGFueXdheSBieSB5b3VyIGRlY2lzaW9uPyANCg0KVG8gY29ycmVjdCBmb3IgdGhlc2UgYmlhc2VzLCB3ZSB1c2Ugc29tZSB2YXJpYW50cyBmcm9tIFNpZ25hbCBEZXRlY3Rpb24gVGhlb3J5IHRvIG9idGFpbiB0aGUgdHJ1ZSBlc3RpbWF0ZXMgd2l0aG91dCBiZWluZyBpbmZsdWVuY2VkIGJ5IHRoZSBiaWFzZXMuIA0KDQojIyMgUnVubmluZyBzdGF0cw0KDQpMZXQncyBkbyBzb21lIHN0YXRzIG9uIHRoaXMgDQoNCnwgIHwgWWVzIHwgTm8gfCBUb3RhbCB8DQp8LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tLS0tfA0KfCBHcmFtbWF0aWNhbCAoWWVzIEFjdHVhbCkgfCBUUCA9IDEwMCB8IEZOID0gNSB8IChZZXMgQWN0dWFsKSAxMDUgfA0KfCBVbmdyYW1tYXRpY2FsIChObyBBY3R1YWwpICB8IEZQID0gMTAgfCBUTiA9IDUwIHwgKE5vIEFjdHVhbCkgNjAgfA0KfCBUb3RhbCB8IChZZXMgUmVzcG9uc2UpIDExMCB8IChObyBSZXNwb25zZSkgNTUgfCAxNjUgfA0KDQpgYGB7ciB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBlcnJvcj1GQUxTRX0NCmdyYW1tYXRpY2FsIDwtIGdyYW1tYXRpY2FsICU+JSANCiAgbXV0YXRlKHJlc3BvbnNlID0gZmFjdG9yKHJlc3BvbnNlLCBsZXZlbHMgPSBjKCJ5ZXMiLCAibm8iKSksDQogICAgICAgICBncmFtbWF0aWNhbGl0eSA9IGZhY3RvcihncmFtbWF0aWNhbGl0eSwgbGV2ZWxzID0gYygiZ3JhbW1hdGljYWwiLCAidW5ncmFtbWF0aWNhbCIpKSkNCg0KIyMgVFAgPSBUcnVlIFBvc2l0aXZlIChIaXQpOyBGUCA9IEZhbHNlIFBvc2l0aXZlOyBGTiA9IEZhbHNlIE5lZ2F0aXZlOyBUTiA9IFRydWUgTmVnYXRpdmUNCg0KDQpUUCA8LSBucm93KGdyYW1tYXRpY2FsICU+JSANCiAgICAgICAgICAgICBmaWx0ZXIoZ3JhbW1hdGljYWxpdHkgPT0gImdyYW1tYXRpY2FsIiAmDQogICAgICAgICAgICAgICAgICAgICAgcmVzcG9uc2UgPT0gInllcyIpKQ0KRk4gPC0gbnJvdyhncmFtbWF0aWNhbCAlPiUgDQogICAgICAgICAgICAgZmlsdGVyKGdyYW1tYXRpY2FsaXR5ID09ICJncmFtbWF0aWNhbCIgJg0KICAgICAgICAgICAgICAgICAgICAgIHJlc3BvbnNlID09ICJubyIpKQ0KRlAgPC0gbnJvdyhncmFtbWF0aWNhbCAlPiUgDQogICAgICAgICAgICAgZmlsdGVyKGdyYW1tYXRpY2FsaXR5ID09ICJ1bmdyYW1tYXRpY2FsIiAmDQogICAgICAgICAgICAgICAgICAgICAgcmVzcG9uc2UgPT0gInllcyIpKQ0KVE4gPC0gbnJvdyhncmFtbWF0aWNhbCAlPiUgDQogICAgICAgICAgICAgZmlsdGVyKGdyYW1tYXRpY2FsaXR5ID09ICJ1bmdyYW1tYXRpY2FsIiAmDQogICAgICAgICAgICAgICAgICAgICAgcmVzcG9uc2UgPT0gIm5vIikpDQpUUA0KRk4NCkZQDQpUTg0KDQpUb3RhbCA8LSBucm93KGdyYW1tYXRpY2FsKQ0KVG90YWwNCihUUCtUTikvVG90YWwgIyBhY2N1cmFjeQ0KKEZQK0ZOKS9Ub3RhbCAjIGVycm9yLCBhbHNvIDEtYWNjdXJhY3kNCg0KIyBXaGVuIHN0aW11bHVzID0geWVzLCBob3cgbWFueSB0aW1lcyByZXNwb25zZSA9IHllcz8NClRQLyhUUCtGTikgIyBhbHNvIFRydWUgUG9zaXRpdmUgUmF0ZSBvciBTcGVjaWZpY2l0eQ0KDQojIFdoZW4gc3RpbXVsdXMgPSBubywgaG93IG1hbnkgdGltZXMgcmVzcG9uc2UgPSB5ZXM/DQpGUC8oRlArVE4pICMgRmFsc2UgUG9zaXRpdmUgUmF0ZSwgDQoNCiMgV2hlbiBzdGltdWx1cyA9IG5vLCBob3cgbWFueSB0aW1lcyByZXNwb25zZSA9IG5vPw0KVE4vKEZQK1ROKSAjIFRydWUgTmVnYXRpdmUgUmF0ZSBvciBTZW5zaXRpdml0eSANCg0KIyBXaGVuIHN1YmplY3QgcmVzcG9uZHMgInllcyIgaG93IG1hbnkgdGltZXMgaXMgKHMpaGUgY29ycmVjdD8NClRQLyhUUCtGUCkgIyBwcmVjaXNpb24NCg0KIyBnZXR0aW5nIGRwcmltZSAob3IgdGhlIHNlbnNpdGl2aXR5IGluZGV4KTsgYmV0YSAoYmlhcyBjcml0ZXJpb24sIDAtMSwgbG93ZXI9aW5jcmVhc2UgaW4gInllcyIpOyBBcHJpbWUgKGVzdGltYXRlIG9mIGRpc2NyaW1pbmFiaWxpdHksIDAtMSwgMT1nb29kIGRpc2NyaW1pbmF0aW9uOyAwIGF0IGNoYW5jZSk7IGJwcGQgKGIgcHJpbWUgcHJpbWUgZCwgLTEgdG8gMTsgMCA9IG5vIGJpYXMsIG5lZ2F0aXZlID0gdGVuZGVuY3kgdG8gcmVzcG9uZCAieWVzIiwgcG9zaXRpdmUgPSB0ZW5kZW5jeSB0byByZXNwb25kICJubyIpOyBjIChpbmRleCBvZiBiaWFzLCBlcXVhbHMgdG8gU0QpDQojKHNlZSBhbHNvIGh0dHBzOi8vd3d3LnItYmxvZ2dlcnMuY29tL2NvbXB1dGUtc2lnbmFsLWRldGVjdGlvbi10aGVvcnktaW5kaWNlcy13aXRoLXIvYW1wLykgDQpwc3ljaG86OmRwcmltZShUUCwgRlAsIEZOLCBUTiwgDQogICAgICAgICAgICAgICBuX3RhcmdldHMgPSBUUCtGTiwgDQogICAgICAgICAgICAgICBuX2Rpc3RyYWN0b3JzID0gRlArVE4sDQogICAgICAgICAgICAgICBhZGp1c3Q9RikNCg0KYGBgDQoNClRoZSBtb3N0IGltcG9ydGFudCBmcm9tIGFib3ZlLCBpcyBkLXByaW1lLiBUaGlzIGlzIG1vZGVsbGluZyB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSByYXRlIG9mICJUcnVlIFBvc2l0aXZlIiByZXNwb25zZXMgYW5kICJGYWxzZSBQb3NpdGl2ZSIgcmVzcG9uc2VzIGluIHN0YW5kYXJkIHVuaXQgKG9yIHotc2NvcmVzKS4gVGhlIGZvcm11bGEgY2FuIGJlIHdyaXR0ZW4gYXM6DQoNCmBkJyAoZCBwcmltZSkgPSBaKFRydWUgUG9zaXRpdmUgUmF0ZSkgLSBaKEZhbHNlIFBvc2l0aXZlIFJhdGUpYA0KDQojIyMgR0xNIGFzIGEgY2xhc3NpZmljYXRpb24gdG9vbA0KDQpUaGUgY29kZSBiZWxvdyBkZW1vbnN0cmF0ZXMgdGhlIGxpbmtzIGJldHdlZW4gb3VyIEdMTSBtb2RlbCBhbmQgd2hhdCB3ZSBoYWQgb2J0YWluZWQgYWJvdmUgZnJvbSBTRFQuIFRoZSBwcmVkaWN0aW9ucycgdGFibGUgc2hvd3MgdGhhdCBvdXIgR0xNIHdhcyBzdWNjZXNzZnVsIGF0IG9idGFpbmluZyBwcmVkaWN0aW9uIHRoYXQgYXJlIGlkZW50aWNhbCB0byBvdXIgaW5pdGlhbCBkYXRhIHNldHVwLiBMb29rIGF0IHRoZSB0YWJsZSBoZXJlIGFuZCB0aGUgdGFibGUgYWJvdmUuIE9uY2Ugd2UgaGF2ZSBjcmVhdGVkIG91ciB0YWJsZSBvZiBvdXRjb21lLCB3ZSBjYW4gY29tcHV0ZSBwZXJjZW50IGNvcnJlY3QsIHRoZSBzcGVjaWZpY2l0eSwgdGhlIHNlbnNpdGl2aXR5LCB0aGUgS2FwcGEgc2NvcmUsIGV0Yy4uIHRoaXMgeWllbGRzIHRoZSBhY3R1YWwgdmFsdWUgd2l0aCB0aGUgU0QgdGhhdCBpcyByZWxhdGVkIHRvIHZhcmlhdGlvbnMgaW4gcmVzcG9uc2VzLiANCg0KYGBge3J9DQojIyBwcmVkaWN0KG1kbC5nbG0pPjAuNSBpcyBpZGVudGljYWwgdG8gDQojIyBwcmVkaWN0KGdsbShyZXNwb25zZX5ncmFtbWF0aWNhbGl0eSxkYXRhPWdyYW1tYXRpY2FsLGZhbWlseSA9IGJpbm9taWFsKSx0eXBlPSJyZXNwb25zZSIpDQpncmFtbWF0aWNhbCA8LSBncmFtbWF0aWNhbCAlPiUgDQogIG11dGF0ZShyZXNwb25zZSA9IGZhY3RvcihyZXNwb25zZSwgbGV2ZWxzID0gYygieWVzIiwgIm5vIikpLA0KICAgICAgICAgZ3JhbW1hdGljYWxpdHkgPSBmYWN0b3IoZ3JhbW1hdGljYWxpdHksIGxldmVscyA9IGMoImdyYW1tYXRpY2FsIiwgInVuZ3JhbW1hdGljYWwiKSkpDQoNCg0KDQptZGwuZ2xtLkMgPC0gZ3JhbW1hdGljYWwgJT4lIA0KICBnbG0ocmVzcG9uc2UgfiBncmFtbWF0aWNhbGl0eSwgZGF0YSA9IC4sZmFtaWx5ID0gYmlub21pYWwpDQoNCnRibC5nbG0gPC0gdGFibGUoZ3JhbW1hdGljYWwkcmVzcG9uc2UsIHByZWRpY3QobWRsLmdsbS5DLCB0eXBlID0gInJlc3BvbnNlIik+MC41KQ0KY29sbmFtZXModGJsLmdsbSkgPC0gYygiZ3JhbW1hdGljYWwiLCAidW5ncmFtbWF0aWNhbCIpDQp0YmwuZ2xtDQpQcmVzZW5jZUFic2VuY2U6OnBjYyh0YmwuZ2xtKQ0KUHJlc2VuY2VBYnNlbmNlOjpzcGVjaWZpY2l0eSh0YmwuZ2xtKQ0KUHJlc2VuY2VBYnNlbmNlOjpzZW5zaXRpdml0eSh0YmwuZ2xtKQ0KIyMjZXRjLi4NCmBgYA0KDQpJZiB5b3UgbG9vayBhdCB0aGUgcmVzdWx0cyBmcm9tIFNEVCBhYm92ZSwgdGhlc2UgcmVzdWx0cyBhcmUgdGhlIHNhbWUgYXMNCnRoZSBmb2xsb3dpbmcNCg0KQWNjdXJhY3k6IChUUCtUTikvVG90YWwgKGByIChUUCtUTikvVG90YWxgKSANCg0KVHJ1ZSBQb3NpdGl2ZSBSYXRlIChvciBTcGVjaWZpY2l0eSkgVFAvKFRQK0ZOKSAoYHIgVFAvKFRQK0ZOKWApDQoNClRydWUgTmVnYXRpdmUgUmF0ZSAob3IgU2Vuc2l0aXZpdHkpIFROLyhGUCtUTikgKGByIFROLyhGUCtUTilgKSANCg0KIyMjIEdMTSBhbmQgZCBwcmltZQ0KDQpUaGUgdmFsdWVzIG9idGFpbmVkIGhlcmUgbWF0Y2ggdGhvc2Ugb2J0YWluZWQgZnJvbSBTRFQuIEZvciBkIHByaW1lLCB0aGUgZGlmZmVyZW5jZSBzdGVtcyBmcm9tIHRoZSB1c2Ugb2YgdGhlIGxvZ2l0IHZhcmlhbnQgb2YgdGhlIEJpbm9taWFsIGZhbWlseS4gQnkgdXNpbmcgYSBwcm9iaXQgdmFyaWFudCwgb25lIG9idGFpbnMgdGhlIHNhbWUgdmFsdWVzIChbc2VlIGhlcmVdKGh0dHBzOi8vc3RhdHMuaWRyZS51Y2xhLmVkdS9yL2RhZS9wcm9iaXQtcmVncmVzc2lvbi8pIGZvciBtb3JlIGRldGFpbHMpLiBBIHByb2JpdCB2YXJpYW50IG1vZGVscyB0aGUgei1zY29yZSBkaWZmZXJlbmNlcyBpbiB0aGUgb3V0Y29tZSBhbmQgaXMgZXZhbHVhdGVkIGluIGNoYW5nZSBpbiAxLXN0YW5kYXJkIHVuaXQuIFRoaXMgaXMgbW9kZWxsaW5nIHRoZSBjaGFuZ2UgZnJvbSAidW5ncmFtbWF0aWNhbCIgIm5vIiByZXNwb25zZXMgaW50byAiZ3JhbW1hdGljYWwiICJ5ZXMiIHJlc3BvbnNlcyBpbiB6LXNjb3Jlcy4gVGhlIHNhbWUgY29uY2VwdHVhbCB1bmRlcnBpbm5pbmdzIG9mIGQtcHJpbWUgZnJvbSBTaWduYWwgRGV0ZWN0aW9uIFRoZW9yeS4NCg0KYGBge3J9DQojIyBkIHByaW1lDQpwc3ljaG86OmRwcmltZShUUCwgRlAsIEZOLCBUTiwgDQogICAgICAgICAgICAgICBuX3RhcmdldHMgPSBUUCtGTiwgDQogICAgICAgICAgICAgICBuX2Rpc3RyYWN0b3JzID0gRlArVE4sDQogICAgICAgICAgICAgICBhZGp1c3Q9RikkZHByaW1lDQoNCiMjIEdMTSB3aXRoIHByb2JpdA0KY29lZihnbG0ocmVzcG9uc2UgfiBncmFtbWF0aWNhbGl0eSwgZGF0YSA9IGdyYW1tYXRpY2FsLCBmYW1pbHkgPSBiaW5vbWlhbChwcm9iaXQpKSlbMl0NCg0KYGBgDQoNCg0KDQoNCiMjIEdMTTogT3RoZXIgZGlzdHJpYnV0aW9ucw0KDQpJZiB5b3VyIGRhdGEgZG9lcyBub3QgZml0IGEgYmlub21pYWwgZGlzdHJpYnV0aW9uLCBhbmQgaXMgYSBtdWx0aW5vbWlhbCAoaS5lLiwgdGhyZWUgb3IgbW9yZSByZXNwb25zZSBjYXRlZ29yaWVzKSBvciBwb2lzc29uIChjb3VudCBkYXRhKSwgdGhlbiB5b3UgbmVlZCB0byB1c2UgdGhlIGdsbSBmdW5jdGlvbiB3aXRoIGEgc3BlY2lmaWMgZmFtaWx5IGZ1bmN0aW9uLiANCg0KYGBge3Igd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgZXJyb3I9RkFMU0UsIGVjaG89RkFMU0V9DQojIyBGb3IgYSBtdWx0aW5vbWlhbCAoMyBvciBtb3JlIHJlc3BvbnNlIGNhdGVnb3JpZXMpLCBzZWUgYmVsb3cgYW5kIHVzZSB0aGUgZm9sbG93aW5nIHNwZWNpZmljYXRpb24NCiMjIGh0dHBzOi8vc3RhdHMuaWRyZS51Y2xhLmVkdS9yL2RhZS9tdWx0aW5vbWlhbC1sb2dpc3RpYy1yZWdyZXNzaW9uLw0KIyMgbWRsLm11bHRpIDwtIG5uZXQ6Om11bHRpbm9tKG91dGNvbWV+cHJlZGljdG9yLCBkYXRhPWRhdGEpDQoNCiMjIEZvciBhIHBvaXNzb24gKGNvdW50IGRhdGEpLCBzZWUgYmVsb3cgYW5kIHVzZSB0aGUgZm9sbG93aW5nIHNwZWNpZmljYXRpb24NCiMjIGh0dHBzOi8vc3RhdHMuaWRyZS51Y2xhLmVkdS9yL2RhZS9wb2lzc29uLXJlZ3Jlc3Npb24vDQoNCiMjIG1kbC5wb2lzc29uIDwtIGdsbShvdXRjb21lfnByZWRpY3RvciwgZGF0YSA9IGRhdGEsIGZhbWlseSA9ICJwb2lzc29uIikNCg0KDQpgYGANCg0KDQoNCiMgQ3VtdWxhdGl2ZSBMb2dpdCBMaW5rIE1vZGVscw0KDQpUaGVzZSBtb2RlbHMgd29yayBwZXJmZWN0bHkgd2l0aCByYXRpbmcgZGF0YS4gUmF0aW5ncyBhcmUgaW5oZXJlbnRseSBvcmRlcmVkLCAxLCAyLCAuLi4gbiwgYW5kIGV4cGVjdCB0byBvYnNlcnZlIGFuIGluY3JlYXNlIChvciBkZWNyZWFzZSkgaW4gb3ZlcmFsbCByYXRpbmdzIGZyb20gMSB0byBuLiBUbyBkZW1vbnN0cmF0ZSB0aGlzLCB3ZSB3aWxsIHVzZSBhbiBleGFtcGxlIHVzaW5nIHRoZSBwYWNrYWdlICJvcmRpbmFsIi4gRGF0YSB3ZXJlIGZyb20gYSByYXRpbmcgZXhwZXJpbWVudCB3aGVyZSBzaXggcGFydGljaXBhbnRzIHJhdGVkIHRoZSBwZXJjZXB0IG9mIG5hc2FsaXR5IGluIHRoZSBwcm9kdWN0aW9uIG9mIHBhcnRpY3VsYXIgY29uc29uYW50cyBpbiBBcmFiaWMuIFRoZSBkYXRhIGNhbWUgZnJvbSBuaW5lIHByb2R1Y2luZyBzdWJqZWN0cy4gVGhlIHJhdGluZ3Mgd2VyZSBmcm9tIDEgdG8gNS4gVGhpcyBleGFtcGxlIGNhbiBhcHBseSB0byBhbnkgc3R1ZHksIGUuZy4sIHJhdGluZyBncmFtbWF0aWNhbGl0eSBvZiBzZW50ZW5jZXMsIHJhdGluZyBob3cgcG9zaXRpdmUgdGhlIHNlbnRpbWVudHMgYXJlIGluIGEgYXJ0aWNsZSwgaW50ZXJ2aWV3IHJlc3BvbnNlcywgZXRjLg0KDQojIyBJbXBvcnRpbmcgYW5kIHByZS1wcm9jZXNzaW5nDQoNCldlIHN0YXJ0IGJ5IGltcG9ydGluZyB0aGUgZGF0YSBhbmQgcHJvY2VzcyBpdC4gV2UgY2hhbmdlIHRoZSByZWZlcmVuY2UgbGV2ZWwgaW4gdGhlIHByZWRpY3Rvcg0KDQpgYGB7ciB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBlcnJvcj1GQUxTRX0NCnJhdGluZyA8LSByZWFkX2NzdigicmF0aW5nLmNzdiIpDQpyYXRpbmcNCnJhdGluZyA8LSByYXRpbmcgJT4lIA0KICBtdXRhdGUoUmVzcG9uc2UgPSBmYWN0b3IoUmVzcG9uc2UpLA0KICAgICAgICAgQ29udGV4dCA9IGZhY3RvcihDb250ZXh0KSkgJT4lIA0KICBtdXRhdGUoQ29udGV4dCA9IHJlbGV2ZWwoQ29udGV4dCwgImlzb2xhdGlvbiIpKQ0KcmF0aW5nDQpgYGANCg0KIyMgT3VyIGZpcnN0IG1vZGVsDQoNCldlIHJ1biBvdXIgZmlyc3QgY2xtIG1vZGVsIGFzIGEgc2ltcGxlLCBpLmUuLCB3aXRoIG5vIHJhbmRvbSBlZmZlY3RzDQoNCmBgYHtyIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGVycm9yPUZBTFNFfQ0KbWRsLmNsbSA8LSByYXRpbmcgJT4lIA0KICBjbG0oUmVzcG9uc2UgfiBDb250ZXh0LCBkYXRhID0gLikNCnN1bW1hcnkobWRsLmNsbSkNCmBgYA0KDQoNCiMjIFRlc3Rpbmcgc2lnbmlmaWNhbmNlIA0KDQpXZSBjYW4gZXZhbHVhdGUgd2hldGhlciAiQ29udGV4dCIgaW1wcm92ZXMgdGhlIG1vZGVsIGZpdCwgYnkgY29tcGFyaW5nIGEgbnVsbCBtb2RlbCB3aXRoIG91ciBtb2RlbC4gT2YgY291cnNlICJDb250ZXh0IiBpcyBpbXByb3ZpbmcgdGhlIG1vZGVsIGZpdC4NCg0KYGBge3Igd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgZXJyb3I9RkFMU0V9DQptZGwuY2xtLk51bGwgPC0gcmF0aW5nICU+JSANCiAgY2xtKFJlc3BvbnNlIH4gMSwgZGF0YSA9IC4pDQphbm92YShtZGwuY2xtLCBtZGwuY2xtLk51bGwpDQoNCmBgYA0KDQojIyBJbnRlcnByZXRpbmcgYSBjdW11bGF0aXZlIG1vZGVsDQoNCkFzIGEgd2F5IHRvIGludGVycHJldCB0aGUgbW9kZWwsIHdlIGNhbiBsb29rIGF0IHRoZSBjb2VmZmljaWVudHMgYW5kIG1ha2Ugc2Vuc2Ugb2YgdGhlIHJlc3VsdHMuIEEgQ0xNIG1vZGVsIGlzIGEgTG9naXN0aWMgbW9kZWwgd2l0aCBhIGN1bXVsYXRpdmUgZWZmZWN0LiBUaGUgIkNvZWZmaWNpZW50cyIgYXJlIHRoZSBlc3RpbWF0ZXMgZm9yIGVhY2ggbGV2ZWwgb2YgdGhlIGZpeGVkIGVmZmVjdDsgdGhlICJUaHJlc2hvbGQgY29lZmZpY2llbnRzIiBhcmUgdGhvc2Ugb2YgdGhlIHJlc3BvbnNlLiBGb3IgdGhlIGZvcm1lciwgYSBuZWdhdGl2ZSBjb2VmZmljaWVudCBpbmRpY2F0ZXMgYSBuZWdhdGl2ZSBhc3NvY2lhdGlvbiB3aXRoIHRoZSByZXNwb25zZTsgYW5kIGEgcG9zaXRpdmUgaXMgcG9zaXRpdmVseSBhc3NvY2lhdGVkIHdpdGggdGhlIHJlc3BvbnNlLiBUaGUgcCB2YWx1ZXMgYXJlIGluZGljYXRpbmcgdGhlIHNpZ25pZmljYW5jZSBvZiBlYWNoIGxldmVsLiBGb3IgdGhlICJUaHJlc2hvbGQgY29lZmZpY2llbnRzIiwgd2UgY2FuIHNlZSB0aGUgY3VtdWxhdGl2ZSBlZmZlY3RzIG9mIHJhdGluZ3MgMXwyLCAyfDMsIDN8NCBhbmQgNHw1IHdoaWNoIGluZGljYXRlIGFuIG92ZXJhbGwgaW5jcmVhc2UgaW4gdGhlIHJhdGluZ3MgZnJvbSAxIHRvIDUuIA0KDQojIyBQbG90dGluZyANCg0KV2UgdXNlIGEgbW9kaWZpZWQgdmVyc2lvbiBvZiBhIHBsb3R0aW5nIGZ1bmN0aW9uIHRoYXQgYWxsb3dzIHVzIHRvIHZpc3VhbGlzZSB0aGUgZWZmZWN0cy4gRm9yIHRoaXMsIHdlIHVzZSB0aGUgYmFzZSBSIHBsb3R0aW5nIGZ1bmN0aW9ucw0KDQpgYGB7ciB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBlcnJvcj1GQUxTRX0NCnBhcihvbWE9YygxLCAwLCAwLCAzKSxtZ3A9YygyLCAxLCAwKSkNCnhsaW1OYXMgPSBjKG1pbihtZGwuY2xtJGJldGEpLCBtYXgobWRsLmNsbSRiZXRhKSkNCnlsaW1OYXMgPSBjKDAsMSkNCnBsb3QoMCwwLHhsaW09eGxpbU5hcywgeWxpbT15bGltTmFzLCB0eXBlPSJuIiwgeWxhYj1leHByZXNzaW9uKFByb2JhYmlsaXR5KSwgeGxhYj0iIiwgeGF4dCA9ICJuIixtYWluPSJQcmVkaWN0ZWQgY3VydmVzIC0gTmFzYWxpc2F0aW9uIixjZXg9MixjZXgubGFiPTEuNSxjZXgubWFpbj0xLjUsY2V4LmF4aXM9MS41KQ0KYXhpcyhzaWRlID0gMSwgYXQgPSBjKDAsbWRsLmNsbSRiZXRhKSxsYWJlbHMgPSBsZXZlbHMocmF0aW5nJENvbnRleHQpLCBsYXM9MixjZXg9MixjZXgubGFiPTEuNSxjZXguYXhpcz0xLjUpDQp4c05hcyA9IHNlcSh4bGltTmFzWzFdLCB4bGltTmFzWzJdLCBsZW5ndGgub3V0PTEwMCkNCmxpbmVzKHhzTmFzLCBwbG9naXMobWRsLmNsbSRUaGV0YVsxXSAtIHhzTmFzKSwgY29sPSdibGFjaycpDQpsaW5lcyh4c05hcywgcGxvZ2lzKG1kbC5jbG0kVGhldGFbMl0gLSB4c05hcyktcGxvZ2lzKG1kbC5jbG0kVGhldGFbMV0gLSB4c05hcyksIGNvbD0ncmVkJykNCmxpbmVzKHhzTmFzLCBwbG9naXMobWRsLmNsbSRUaGV0YVszXSAtIHhzTmFzKS1wbG9naXMobWRsLmNsbSRUaGV0YVsyXSAtIHhzTmFzKSwgY29sPSdncmVlbicpDQpsaW5lcyh4c05hcywgcGxvZ2lzKG1kbC5jbG0kVGhldGFbNF0gLSB4c05hcyktcGxvZ2lzKG1kbC5jbG0kVGhldGFbM10gLSB4c05hcyksIGNvbD0nb3JhbmdlJykNCmxpbmVzKHhzTmFzLCAxLShwbG9naXMobWRsLmNsbSRUaGV0YVs0XSAtIHhzTmFzKSksIGNvbD0nYmx1ZScpDQphYmxpbmUodj1jKDAsbWRsLmNsbSRiZXRhKSxsdHk9MykNCmFibGluZShoPTAsIGx0eT0iZGFzaGVkIikNCmFibGluZShoPTEsIGx0eT0iZGFzaGVkIikNCmxlZ2VuZChwYXIoJ3VzcicpWzJdLCBwYXIoJ3VzcicpWzRdLCBidHk9J24nLCB4cGQ9TkEsbHR5PTEsIGNvbD1jKCJibGFjayIsICJyZWQiLCAiZ3JlZW4iLCAib3JhbmdlIiwgImJsdWUiKSwgDQogICAgICAgbGVnZW5kPWMoIk9yYWwiLCAiMiIsICIzIiwgIjQiLCAiTmFzYWwiKSxjZXg9MC43NSkNCg0KYGBgDQoNCiMgTGluZWFyIE1peGVkLWVmZmVjdHMgTW9kZWxzLiBXaHkgcmFuZG9tIGVmZmVjdHMgbWF0dGVyDQoNCkxldCdzIGdlbmVyYXRlIGEgbmV3IGRhdGFmcmFtZSB0aGF0IHdlIHdpbGwgdXNlIGxhdGVyIG9uIGZvciBvdXIgbWl4ZWQgbW9kZWxzDQoNCmBgYHtyIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGVycm9yPUZBTFNFfQ0KIyMgQ291cnRlc3kgb2YgQm9kbyBXaW50ZXINCnNldC5zZWVkKDY2NikNCiN3ZSBjcmVhdGUgNiBzdWJqZWN0cw0Kc3ViamVjdHMgPC0gcGFzdGUwKCdTJywgMTo2KQ0KI2hlcmUgd2UgYWRkIHJlcGV0aXRpb25zIHdpdGhpbiBzcGVha2Vycw0Kc3ViamVjdHMgPC0gcmVwKHN1YmplY3RzLCBlYWNoID0gMjApDQppdGVtcyA8LSBwYXN0ZTAoJ0l0ZW0nLCAxOjIwKQ0KI2JlbG93IHJlcGVhdHMNCml0ZW1zIDwtIHJlcChpdGVtcywgNikNCiNiZWxvdyBpcyB0byBnZW5lcmF0ZSByYW5kb20gbnVtYmVycyB0aGF0IGFyZSBsb2cgdmFsdWVzDQpsb2dGcmVxIDwtIHJvdW5kKHJleHAoMjApKjUsIDIpDQojYmVsb3cgd2UgYXJlIHJlcGVhdGluZyB0aGUgbG9nRnJlcSA2IHRpbWVzIHRvIGZpdCB3aXRoIHRoZSBudW1iZXIgb2Ygc3BlYWtlcnMgYW5kIGl0ZW1zDQpsb2dGcmVxIDwtIHJlcChsb2dGcmVxLCA2KQ0KeGRmIDwtIGRhdGEuZnJhbWUoc3ViamVjdHMsIGl0ZW1zLCBsb2dGcmVxKQ0KI2JlbG93IHJlbW92ZXMgdGhlIGluZGl2aWR1YWwgdmFyaWFibGVzIHdlIGhhZCBjcmVhdGVkIGJlY2F1c2UgdGhleSBhcmUgYWxyZWFkeSBpbiB0aGUgZGF0YWZyYW1lDQpybShzdWJqZWN0cywgaXRlbXMsIGxvZ0ZyZXEpDQoNCnhkZiRJbnRlcmNlcHQgPC0gMzAwDQpzdWJtZWFucyA8LSByZXAocm5vcm0oNiwgc2QgPSA0MCksIDIwKQ0KI3NvcnQgbWFrZSB0aGUgbWVhbnMgZm9yIGVhY2ggc3ViamVjdCBpcyB0aGUgc2FtZS4uLg0Kc3VibWVhbnMgPC0gc29ydChzdWJtZWFucykNCnhkZiRzdWJtZWFucyA8LSBzdWJtZWFucw0KI3dlIGNyZWF0ZSB0aGUgc2FtZSB0aGluZyBmb3IgaXRlbXMuLi4gd2UgYWxsb3cgdGhlIGl0ZW1zIG1lYW4gdG8gdmFyeSBiZXR3ZWVuIHdvcmRzLi4uDQppdHNtZWFucyA8LSByZXAocm5vcm0oMjAsIHNkID0gMjApLCA2KQ0KeGRmJGl0c21lYW5zIDwtIGl0c21lYW5zDQp4ZGYkZXJyb3IgPC0gcm5vcm0oMTIwLCBzZCA9IDIwKQ0KI2hlcmUgd2UgY3JlYXRlIGFuIGVmZmVjdCBjb2x1bW4sICANCiNoZXJlIGZvciBlYWNoIGxvZ0ZyZXEsIHdlIGhhdmUgYSBkZWNyZWFzZSBvZiAtNSBvZiB0aGF0IHBhcnRpY3VsYXIgbG9nRnJlcSANCnhkZiRlZmZlY3QgPC0gLTUgKiB4ZGYkbG9nRnJlcQ0KDQp4ZGYkZHVyIDwtIHhkZiRJbnRlcmNlcHQgKyB4ZGYkc3VibWVhbnMgKyB4ZGYkaXRzbWVhbnMgKyB4ZGYkZXJyb3IgKyB4ZGYkZWZmZWN0DQojYmVsb3cgaXMgdG8gc3Vic2V0IHRoZSBkYXRhIGFuZCBnZXQgb25seSBhIGZldyBjb2x1bW5zLi4gdGhlIC1jKDQ6OCkgcmVtb3ZlcyB0aGUgY29sdW1ucyA0IHRvIDguLg0KeHJlYWwgPC0geGRmWywtYyg0OjgpXQ0KaGVhZCh4cmVhbCkNCnJtKHhkZiwgc3VibWVhbnMsIGl0c21lYW5zKQ0KYGBgDQoNCiMjIFBsb3RzDQpMZXQncyBzdGFydCBieSBkb2luZyBhIGNvcnJlbGF0aW9uIHRlc3QgYW5kIHBsb3R0aW5nIHRoZSBkYXRhLiBPdXIgcmVzdWx0cyBzaG93IHRoYXQgdGhlcmUgaXMgYSBuZWdhdGl2ZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIGR1cmF0aW9uIGFuZCBMb2dGcmVxdWVuY3ksIGFuZCB0aGUgcGxvdCBzaG93cyB0aGlzIGRlY3JlYXNlLiANCg0KYGBge3Igd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgZXJyb3I9RkFMU0V9DQpjb3JyTWl4ZWQgPC0gYXMubWF0cml4KHhyZWFsWy1jKDE6MildKSAlPiUgDQogIHJjb3JyKHR5cGU9InBlYXJzb24iKQ0KcHJpbnQoY29yck1peGVkKQ0KY29ycnBsb3QoY29yck1peGVkJHIsIG1ldGhvZCA9ICJjaXJjbGUiLCB0eXBlID0gInVwcGVyIiwgdGwuc3J0ID0gNDUsDQogICAgICAgICBhZGRDb2VmLmNvbCA9ICJibGFjayIsIGRpYWcgPSBGQUxTRSwNCiAgICAgICAgIHAubWF0ID0gY29yck1peGVkJHAsIHNpZy5sZXZlbCA9IDAuMDUpDQoNCg0KDQpnZ3Bsb3QueHJlYWwgPC0geHJlYWwgJT4lIA0KICBnZ3Bsb3QoYWVzKHggPSBsb2dGcmVxLCB5ID0gZHVyKSkgKw0KICBnZW9tX3BvaW50KCkrIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDIwKSArDQogIGxhYnMoeSA9ICJEdXJhdGlvbiIsIHggPSAiRnJlcXVlbmN5IChMb2cpIikgKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSBsbSwgc2U9RikNCmdncGxvdC54cmVhbA0KYGBgDQoNCg0KIyMgTGluZWFyIG1vZGVsDQoNCkxldCdzIHJ1biBhIHNpbXBsZSBsaW5lYXIgbW9kZWwgb24gdGhlIGRhdGEuIEFzIHdlIGNhbiBzZWUgYmVsb3csIHRoZXJlIGFyZSBzb21lIGlzc3VlcyB3aXRoIHRoZSAic2ltcGxlIiBsaW5lYXIgbW9kZWw6IHdlIGhhZCBzZXQgb3VyIFNEIGZvciBzdWJqZWN0cyB0byBiZSA0MCwgYnV0IHRoaXMgd2FzIHBpY2tlZCB1cCBhcyAxMjAgKHNlZSBoaXN0b2dyYW0gb2YgcmVzaWR1YWxzKS4gVGhlIFFRIFBsb3QgaXMgbm90ICJub3JtYWwiLiANCg0KYGBge3Igd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgZXJyb3I9RkFMU0V9DQptZGwubG0ueHJlYWwgPC0geHJlYWwgJT4lIA0KICBsbShkdXIgfiBsb2dGcmVxLCBkYXRhID0gLikNCnN1bW1hcnkobWRsLmxtLnhyZWFsKQ0KaGlzdChyZXNpZHVhbHMobWRsLmxtLnhyZWFsKSkNCnFxbm9ybShyZXNpZHVhbHMobWRsLmxtLnhyZWFsKSk7IHFxbGluZShyZXNpZHVhbHMobWRsLmxtLnhyZWFsKSkNCnBsb3QoZml0dGVkKG1kbC5sbS54cmVhbCksIHJlc2lkdWFscyhtZGwubG0ueHJlYWwpLCBjZXggPSA0KQ0KYGBgDQoNCiMjIExpbmVhciBNaXhlZCBNb2RlbA0KDQpPdXIgTGluZWFyIE1peGVkIGVmZmVjdHMgTW9kZWwgd2lsbCB0YWtlIGludG8gYWNjb3VudCB0aGUgcmFuZG9tIGVmZmVjdHMgd2UgYWRkZWQgYW5kIGFsc28gb3VyIG1vZGVsIHNwZWNpZmljYXRpb25zLiBXZSB1c2UgYSBNYXhpbXVtIExpa2VsaWhvb2QgZXN0aW1hdGUgKFJFTUwgPSBGQUxTRSkgYXMgdGhpcyBpcyB3aGF0IHdlIHdpbGwgdXNlIGZvciBtb2RlbCBjb21wYXJpc29uLiBUaGUgTGluZWFyIE1peGVkIE1vZGVsIGlzIHJlZmxlY3Rpbmcgb3VyIG1vZGVsIHNwZWNpZmljYXRpb25zIFRoZSBTRCBvZiBvdXIgc3ViamVjdHMgaXMgcGlja2VkIHVwIGNvcnJlY3RseS4gVGhlIG1vZGVsIHJlc3VsdHMgYXJlICJhbG1vc3QiIHRoZSBzYW1lIGFzIG91ciBsaW5lYXIgbW9kZWwgYWJvdmUuIFRoZSBjb2VmZmljaWVudCBmb3IgdGhlICJJbnRlcmNlcHQiIGlzIGF0IDMzNy45NzMgYW5kIHRoZSBjb2VmZmljaWVudCBmb3IgTG9nRnJlcXVlbmN5IGlzIGF0IC01LjQ2MC4gVGhpcyBpbmRpY2F0ZXMgdGhhdCBmb3IgZWFjaCB1bml0IG9mIGluY3JlYXNlIGluIHRoZSBMb2dGcmVxdWVuY3ksIHRoZXJlIGlzIGEgZGVjcmVhc2UgYnkgNS40NjAgKG1zKS4NCg0KYGBge3Igd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgZXJyb3I9RkFMU0V9DQptZGwubG1lci54cmVhbCA8LSB4cmVhbCAlPiUgDQogIGxtZXIoZHVyIH4gbG9nRnJlcSAgKygxfHN1YmplY3RzKSArICgxfGl0ZW1zKSwgZGF0YSA9IC4sIFJFTUwgPSBGQUxTRSkNCnN1bW1hcnkobWRsLmxtZXIueHJlYWwpDQpoaXN0KHJlc2lkdWFscyhtZGwubG1lci54cmVhbCkpDQpxcW5vcm0ocmVzaWR1YWxzKG1kbC5sbWVyLnhyZWFsKSk7IHFxbGluZShyZXNpZHVhbHMobWRsLmxtZXIueHJlYWwpKQ0KcGxvdChmaXR0ZWQobWRsLmxtZXIueHJlYWwpLCByZXNpZHVhbHMobWRsLmxtZXIueHJlYWwpLCBjZXggPSA0KQ0KYGBgDQoNCiMjIE91ciBzZWNvbmQgTWl4ZWQgbW9kZWwNCg0KVGhpcyBzZWNvbmQgbW9kZWwgYWRkIGEgYnktc3ViamVjdCByYW5kb20gc2xvcGUuIFJhbmRvbSBzbG9wZXMgYWxsb3cgZm9yIHRoZSB2YXJpYXRpb24gdGhhdCBleGlzdHMgaW4gdGhlIHJhbmRvbSBlZmZlY3RzIHRvIGJlIHRha2VuIGludG8gYWNjb3VudC4gQW4gaW50ZXJjZXB0IG9ubHkgbW9kZWwgcHJvdmlkZXMgYW4gYXZlcmFnZWQgdmFsdWVzIHRvIG91ciBwYXJ0aWNpcGFudHMuDQoNCmBgYHtyIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGVycm9yPUZBTFNFfQ0KbWRsLmxtZXIueHJlYWwuMiA8LSB4cmVhbCAlPiUgDQogIGxtZXIoZHVyIH4gbG9nRnJlcSArIChsb2dGcmVxfHN1YmplY3RzKSArICgxfGl0ZW1zKSwgZGF0YSA9IC4sIFJFTUwgPSBGQUxTRSkNCnN1bW1hcnkobWRsLmxtZXIueHJlYWwuMikNCmhpc3QocmVzaWR1YWxzKG1kbC5sbWVyLnhyZWFsLjIpKQ0KcXFub3JtKHJlc2lkdWFscyhtZGwubG1lci54cmVhbC4yKSk7IHFxbGluZShyZXNpZHVhbHMobWRsLmxtZXIueHJlYWwuMikpDQpwbG90KGZpdHRlZChtZGwubG1lci54cmVhbC4yKSwgcmVzaWR1YWxzKG1kbC5sbWVyLnhyZWFsLjIpLCBjZXggPSA0KQ0KYGBgDQoNCiMjIE1vZGVsIGNvbXBhcmlzb24NCg0KQnV0IHdoZXJlIGFyZSBvdXIgcCB2YWx1ZXM/IFRoZSBsbWU0IGRldmVsb3BlcnMgZGVjaWRlZCBub3QgdG8gaW5jbHVkZSBwIHZhbHVlcyBkdWUgdG8gdmFyaW91cyBpc3N1ZXMgd2l0aCBlc3RpbWF0aW5nIGRmLiBXaGF0IHdlIGNhbiBkbyBpbnN0ZWFkIGlzIHRvIGNvbXBhcmUgbW9kZWxzLiBXZSBuZWVkIHRvIGNyZWF0ZSBhIG51bGwgbW9kZWwgdG8gYWxsb3cgZm9yIHNpZ25pZmljYW5jZSB0ZXN0aW5nLiBBcyBleHBlY3RlZCBvdXIgcHJlZGljdG9yIGlzIHNpZ25pZmljYW50bHkgY29udHJpYnV0aW5nIHRvIHRoZSBkaWZmZXJlbmNlLiANCg0KYGBge3Igd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgZXJyb3I9RkFMU0V9DQptZGwubG1lci54cmVhbC5OdWxsIDwtIHhyZWFsICU+JSANCiAgbG1lcihkdXIgfiAxICsgKGxvZ0ZyZXF8c3ViamVjdHMpICsgKDF8aXRlbXMpLCBkYXRhID0gLiwgUkVNTCA9IEZBTFNFKQ0KYW5vdmEobWRsLmxtZXIueHJlYWwuTnVsbCwgbWRsLmxtZXIueHJlYWwuMikNCmBgYA0KDQpBbHNvLCBkbyB3ZSByZWFsbHkgbmVlZCByYW5kb20gc2xvcGVzPyBGcm9tIHRoZSByZXN1bHQgYmVsb3csIHdlIGRvbid0IHNlZW0gdG8gbmVlZCByYW5kb20gc2xvcGVzIGF0IGFsbCwgZ2l2ZW4gdGhhdCBhZGRpbmcgcmFuZG9tIHNsb3BlcyBkb2VzIG5vdCBpbXByb3ZlIHRoZSBtb2RlbCBmaXQuIEkgYWx3YXlzIHJlY29tbWVuZCB0ZXN0aW5nIHRoaXMuIE1vc3Qgb2YgdGhlIHRpbWUgSSBrZWVwIHJhbmRvbSBzbG9wZXMuDQoNCmBgYHtyIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGVycm9yPUZBTFNFfQ0KYW5vdmEobWRsLmxtZXIueHJlYWwsIG1kbC5sbWVyLnhyZWFsLjIpDQpgYGANCg0KQnV0IGlmIHlvdSBhcmUgcmVhbGx5IChyZWFsbHkhISEpIG9ic2Vzc2VkIGJ5IHAgdmFsdWVzLCB0aGVuIHlvdSBjYW4gYWxzbyB1c2UgbG1lclRlc3QuIEJVVCB1c2UgYWZ0ZXIgY29tcGFyaW5nIG1vZGVscyB0byBldmFsdWF0ZSBjb250cmlidXRpb24gb2YgcHJlZGljdG9ycw0KDQpgYGB7ciB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBlcnJvcj1GQUxTRX0NCm1kbC5sbWVyLnhyZWFsLmxtZXJUZXN0IDwtIHhyZWFsICU+JSANCiAgbG1lcihkdXIgfiBsb2dGcmVxICsgKGxvZ0ZyZXF8c3ViamVjdHMpICsgKDF8aXRlbXMpLCBkYXRhID0gLiwgUkVNTCA9IFRSVUUpDQpzdW1tYXJ5KG1kbC5sbWVyLnhyZWFsLmxtZXJUZXN0KQ0KZGV0YWNoKCJwYWNrYWdlOmxtZXJUZXN0IiwgdW5sb2FkID0gVFJVRSkNCmBgYA0KDQoNCiMjIE91ciBmaW5hbCBNaXhlZCBtb2RlbA0KDQpPdXIgZmluYWwgbW9kZWwgdXNlcyBSRU1MIChvciBSZXN0cmljdGVkIE1heGltdW0gTGlrZWxpaG9vZCBFc3RpbWF0ZSBvZiBWYXJpYW5jZSBDb21wb25lbnQpIHRvIGVzdGltYXRlIHRoZSBtb2RlbC4gDQoNCmBgYHtyIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGVycm9yPUZBTFNFfQ0KbWRsLmxtZXIueHJlYWwuRnVsbCA8LSB4cmVhbCAlPiUgDQogIGxtZXIoZHVyIH4gbG9nRnJlcSArIChsb2dGcmVxfHN1YmplY3RzKSArICgxfGl0ZW1zKSwgZGF0YSA9IC4sIFJFTUwgPSBUUlVFKQ0Kc3VtbWFyeShtZGwubG1lci54cmVhbC5GdWxsKQ0KYW5vdmEobWRsLmxtZXIueHJlYWwuRnVsbCkNCmhpc3QocmVzaWR1YWxzKG1kbC5sbWVyLnhyZWFsLkZ1bGwpKQ0KcXFub3JtKHJlc2lkdWFscyhtZGwubG1lci54cmVhbC5GdWxsKSk7IHFxbGluZShyZXNpZHVhbHMobWRsLmxtZXIueHJlYWwuRnVsbCkpDQpwbG90KGZpdHRlZChtZGwubG1lci54cmVhbC5GdWxsKSwgcmVzaWR1YWxzKG1kbC5sbWVyLnhyZWFsLkZ1bGwpLCBjZXggPSA0KQ0KYGBgDQoNCg0KIyMgRGlzc2VjdGluZyB0aGUgbW9kZWwNCg0KYGBge3Igd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgZXJyb3I9RkFMU0V9DQpjb2VmKG1kbC5sbWVyLnhyZWFsLkZ1bGwpDQpmaXhlZihtZGwubG1lci54cmVhbC5GdWxsKQ0KZml4ZWYobWRsLmxtZXIueHJlYWwuRnVsbClbMV0NCmZpeGVmKG1kbC5sbWVyLnhyZWFsLkZ1bGwpWzJdDQoNCmNvZWYobWRsLmxtZXIueHJlYWwuRnVsbCkkYHN1YmplY3RzYFsxXQ0KY29lZihtZGwubG1lci54cmVhbC5GdWxsKSRgc3ViamVjdHNgWzJdDQoNCmNvZWYobWRsLmxtZXIueHJlYWwuRnVsbCkkYGl0ZW1zYFsxXQ0KY29lZihtZGwubG1lci54cmVhbC5GdWxsKSRgaXRlbXNgWzJdDQoNCmBgYA0KDQojIyBVc2luZyBwcmVkaWN0aW9ucyBmcm9tIG91ciBtb2RlbA0KSW4gZ2VuZXJhbCwgSSB1c2UgdGhlIHByZWRpY3Rpb24gZnJvbSBteSBmaW5hbCBtb2RlbCBpbiBhbnkgcGxvdHMuIFRvIGdlbmVyYXRlIHRoaXMsIHdlIGNhbiB1c2UgdGhlIGZvbGxvd2luZw0KDQpgYGB7ciB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBlcnJvcj1GQUxTRX0NCnhyZWFsIDwtIHhyZWFsICU+JSANCiAgbXV0YXRlKFByZWRfRHVyID0gcHJlZGljdChtZGwubG1lci54cmVhbC5GdWxsKSkNCg0KeHJlYWwgJT4lIA0KICBnZ3Bsb3QoYWVzKHggPSBsb2dGcmVxLCB5ID0gUHJlZF9EdXIpKSArDQogIGdlb21fcG9pbnQoKSArIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDIwKSArDQogIGxhYnMoeSA9ICJEdXJhdGlvbiIsIHggPSAiRnJlcXVlbmN5IChMb2cpIiwgdGl0bGUgPSAiUHJlZGljdGVkIikgKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSBsbSwgc2UgPSBGKSArIGNvb3JkX2NhcnRlc2lhbih5bGltID0gYygyMDAsNDUwKSkNCg0KIyMgb3JpZ2luYWwgcGxvdA0KeHJlYWwgJT4lIA0KICBnZ3Bsb3QoYWVzKHggPSBsb2dGcmVxICwgeSA9IGR1cikpICsNCiAgZ2VvbV9wb2ludCgpICsgdGhlbWVfYncoYmFzZV9zaXplID0gMjApKw0KICBsYWJzKHkgPSAiRHVyYXRpb24iLCB4ID0gIkZyZXF1ZW5jeSAoTG9nKSIsIHRpdGxlID0gIk9yaWdpbmFsIikrDQogIGdlb21fc21vb3RoKG1ldGhvZCA9IGxtLCBzZSA9IEYpICsgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKDIwMCw0NTApKQ0KDQpgYGANCg0KIyMgR0xNTSBhbmQgQ0xNTQ0KDQpUaGUgY29kZSBhYm92ZSB3YXMgdXNpbmcgYSBMaW5lYXIgTWl4ZWQgRWZmZWN0cyBNb2RlbGxpbmcuIFRoZSBvdXRjb21lIHdhcyBhIG51bWVyaWMgb2JqZWN0LiBJbiBzb21lIGNhc2VzIChhcyB3ZSBoYXZlIHNlZW4gYWJvdmUpLCB3ZSBtYXkgaGF2ZTogDQoNCjEuIEJpbmFyeSBvdXRjb21lIChiaW5vbWlhbCkNCjIuIENvdW50IGRhdGEgKHBvaXNzb24pLCANCjMuIE11bHRpLWNhdGVnb3J5IG91dGNvbWUgKG11bHRpbm9taWFsKQ0KNC4gUmF0aW5nIGRhdGEgKGN1bXVsYXRpdmUgZnVuY3Rpb24pDQoNClRoZSBjb2RlIGJlbG93IGdpdmVzIHlvdSBhbiBpZGVhIG9mIGhvdyB0byBzcGVjaWZ5IHRoZXNlIG1vZGVscw0KDQpgYGB7ciB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBlcnJvcj1GQUxTRX0NCg0KIyMgQmlub21pYWwgZmFtaWx5DQojIyBsbWU0OjpnbG1lcihvdXRjb21lfnByZWRpY3RvcihzKSsoMXxzdWJqZWN0KSsoMXxpdGVtcykuLi4sIGRhdGE9ZGF0YSwgZmFtaWx5PWJpbm9taWFsKQ0KDQojIyBQb2lzc29uIGZhbWlseQ0KIyMgbG1lNDo6Z2xtZXIob3V0Y29tZX5wcmVkaWN0b3IocykrKDF8c3ViamVjdCkrKDF8aXRlbXMpLi4uLCBkYXRhPWRhdGEsIGZhbWlseT1wb2lzc29uKQ0KDQojIyBNdWx0aW5vbWlhbCBmYW1pbHkNCiMjIGEgYml0IGNvbXBsaWNhdGVkIGFzIHRoZXJlIGlzIGEgbmVlZCB0byB1c2UgQmF5ZXNpYW4gYXBwcm9hY2hlcywgc2VlIGUuZy4sIA0KIyMgZ2xtbUFETUINCiMjIG1peGNhdA0KIyMgTUNNQ2dsbW0NCiMjIHNlZSBodHRwczovL2dpc3QuZ2l0aHViLmNvbS9jYXNhbGxhcy84MjYzODE4DQoNCiMjIFJhdGluZyBkYXRhLCB1c2UgZm9sbG93aW5nDQojIyBvcmRpbmFsOjpjbG1tKG91dGNvbWV+cHJlZGljdG9yKHMpKygxfHN1YmplY3QpKygxfGl0ZW1zKS4uLiwgZGF0YT1kYXRhKQ0KDQoNCiMjIFJlbWVtYmVyIHRvIHRlc3QgZm9yIHJhbmRvbSBlZmZlY3RzIGFuZCB3aGV0aGVyIHNsb3BlcyBhcmUgbmVlZGVkLg0KDQpgYGANCg0KDQoNCiMgc2Vzc2lvbiBpbmZvDQoNCmBgYHtyIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGVycm9yPUZBTFNFfQ0Kc2Vzc2lvbkluZm8oKQ0KYGBg