1 One Way Anova

In this exercise you have to consider data set named PlantGrowth from R environment. It contains the weight of plants obtained under a control and two different treatment conditions. Please consider the following steps:

1.1 Data Preparation (One-way ANOVA)

Here we use the built-in R dataset named PlantGrowth. It contains the weight of plants obtained under a control and two different treatment conditions.

##   weight group
## 1   4.17  ctrl
## 2   5.58  ctrl
## 3   5.18  ctrl
## 4   6.11  ctrl
## 5   4.50  ctrl
## 6   4.61  ctrl

Show the levels of the grouping variable:

## [1] "ctrl" "trt1" "trt2"

Where, ctrl = Control, trt1 = Treatment 1 ,trt2 = Treatment 2

1.2 Summary statistics

Compute some summary statistics (count, mean and sd) of the variable weight organized by groups:

## # A tibble: 3 x 5
##   group variable     n  mean    sd
##   <fct> <chr>    <dbl> <dbl> <dbl>
## 1 ctrl  weight      10  5.03 0.583
## 2 trt1  weight      10  4.66 0.794
## 3 trt2  weight      10  5.53 0.443

1.4 Outliers

Outliers can be easily identified using box plot methods, implemented in the R function identify_outliers() [rstatix package].

## # A tibble: 2 x 4
##   group weight is.outlier is.extreme
##   <fct>  <dbl> <lgl>      <lgl>     
## 1 trt1    5.87 TRUE       FALSE     
## 2 trt1    6.03 TRUE       FALSE

There were no extreme outliers.

1.5 One-way ANOVA Test

The aov() function is used to obtain the relevant sums of squares. Using the summary() function on the output from aov() creates the desired ANOVA table. (Without the unneeded row for total).

## ANOVA Table (type II tests)
## 
##   Effect DFn DFd     F     p p<.05   ges
## 1  group   2  27 4.846 0.016     * 0.264
##             Df Sum Sq Mean Sq F value Pr(>F)  
## group        2  3.766  1.8832   4.846 0.0159 *
## Residuals   27 10.492  0.3886                 
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

in the table above, the column ges corresponds to the generalized eta squared (effect size). It measures the proportion of the variability in the outcome variable (here plant weight) that can be explained in terms of the predictor (here, treatment group). An effect size of 0.264 (26.4%) means that 26.4% of the change in the weight can be accounted for the treatment conditions. From the above ANOVA table, it can be seen that there are significant differences between groups (p=0.016), which are highlighted with “*“, \(F(2,27)=4.85\), \(p=0.16\), \(eta2[g]=0.26\).

where, F indicates that we are comparing to an F-distribution (F-test); (2, 27) indicates the degrees of freedom in the numerator (DFn) and the denominator (DFd), respectively; 4.85 indicates the obtained F-statistic value p specifies the p-value *ges is the generalized effect size (amount of variability due to the factor)

1.6 Check Assumptions (One-way ANOVA)

The ANOVA test assumes that, the data are normally distributed and the variance across groups are homogeneous. We can check that with some diagnostic plots.

The normality assumption can be checked by using one of the following two approaches:

Analyzing the ANOVA model residuals to check the normality for all groups together. This approach is easier and it’s very handy when you have many groups or if there are few data points per group. Check normality for each group separately. This approach might be used when you have only a few groups and many data points per group.

This section will show how to proceed for both option 1 and 2.

Check normality assumption by analyzing the model residuals. QQ plot and Shapiro-Wilk test of normality are used. QQ plot draws the correlation between a given data and the normal distribution.

In the plot above, there is no evident to show relationships between residuals and fitted values (the mean of each groups), which is good. So, we can assume the homogenity of variances.

Check normality assumption by groups. Computing Shapiro-Wilk test for each group level. If the data is normally distributed, the p-value should be greater than 0.05.

## # A tibble: 3 x 4
##   group variable statistic     p
##   <fct> <chr>        <dbl> <dbl>
## 1 ctrl  weight       0.957 0.747
## 2 trt1  weight       0.930 0.452
## 3 trt2  weight       0.941 0.564

The score were normally distributed (p>0.05

) for each group, as assessed by Shapiro-Wilk’s test of normality. Note : if sample size is greater than 50, the normal QQ plot is preferred because at larger sample sizes the Shapiro-Wilk test becomes very sensitive even to a minor deviation from normality.

QQ plot draws the correlation between a given data and the normal distribution. Create QQ plots for each group level:

Points 4, 15, 17 are detected as outliers since it is far from the linearity, which can severely affect normality and homogeneity of variance. It can be useful to remove outliers to meet the test assumptions. I recommend Levene’s test, which is less sensitive to departures from normal distribution. From the Shapiro-Wilk test on the ANOVA residuals (W=0.97, p=0.8) which finds no indication that normality is violated.

## # A tibble: 1 x 4
##     df1   df2 statistic     p
##   <int> <int>     <dbl> <dbl>
## 1     2    27      1.12 0.341
## 
##  One-way analysis of means (not assuming equal variances)
## 
## data:  weight and group
## F = 5.181, num df = 2.000, denom df = 17.128, p-value = 0.01739

From the output above, we can see that the p-value is >0.05, which is not significant. This means that, there is not significant difference between variances across groups. Therefore, we can assume the homogenity of variances in the different treatment groups.

1.7 Pairwise-comparison (One-way ANOVA)

A significant one-way ANOVA is generally followed up by Tukey post-hoc tests to perform multiple pairwise comparisons between groups. Key R function: tukey_hsd() [rstatix].

## # A tibble: 3 x 9
##   term  group1 group2 null.value estimate conf.low conf.high p.adj p.adj.signif
## * <chr> <chr>  <chr>       <dbl>    <dbl>    <dbl>     <dbl> <dbl> <chr>       
## 1 group ctrl   trt1            0   -0.371   -1.06      0.320 0.391 ns          
## 2 group ctrl   trt2            0    0.494   -0.197     1.19  0.198 ns          
## 3 group trt1   trt2            0    0.865    0.174     1.56  0.012 *

The output contains the following columns:

estimate: estimate of the difference between means of the two groups conf.low, conf.high: the lower and the upper end point of the confidence interval at 95% (default) p.adj: p-value after adjustment for the multiple comparisons. It can be seen from the output, that only the difference between trt2 and trt1 is significant (adjusted p-value = 0.012).

1.8 Tukey HSD (One-way ANOVA)

Tukey’s Honest Significance difference can be applied directly to an object which was created using aov(). It will adjust the p-values of the pairwise comparisons of the means to control the FWER, in this case, for 0.05. Notice it also gives confidence intervals for the difference of the means.

##   Tukey multiple comparisons of means
##     95% family-wise confidence level
## 
## Fit: aov(formula = weight ~ group, data = PlantGrowth)
## 
## $group
##             diff        lwr       upr     p adj
## trt1-ctrl -0.371 -1.0622161 0.3202161 0.3908711
## trt2-ctrl  0.494 -0.1972161 1.1852161 0.1979960
## trt2-trt1  0.865  0.1737839 1.5562161 0.0120064

Based on these results, we see the control is causing treatment to change either control towards treatment 1 or control towards treatment 2. But not between treatments.

1.9 Report

We could report the results of one-way ANOVA as follow:

  • A one-way ANOVA was performed to evaluate if the plant growth was different for the 3 different treatment groups: ctr, trt1 and trt2 all have n=10.

  • Data is presented as mean +/- standard deviation. Plant growth was statistically significantly different between different treatment groups, F(2, 27) = 4.85, p = 0.016, generalized eta squared = 0.26.

  • Plant growth decreased in trt1 group (4.66 +/- 0.79) compared to ctr group (5.03 +/- 0.58). It increased in trt2 group (5.53 +/- 0.44) compared to trt1 and ctr group.

  • Tukey post-hoc analyses revealed that the increase from trt1 to trt2 (0.87, 95% CI (0.17 to 1.56)) was statistically significant (p = 0.012), but no other group differences were statistically significant.

2 Two-way ANOVA

Please apply Two-way ANOVA procedures to the rats data from the faraway package. There are two factors here: poison and treat. You can use the levels() function to extract the levels of a factor variable. Give your opinions accordingly!

##       time        poison   treat 
##  Min.   :0.1800   I  :16   A:12  
##  1st Qu.:0.3000   II :16   B:12  
##  Median :0.4000   III:16   C:12  
##  Mean   :0.4794            D:12  
##  3rd Qu.:0.6225                  
##  Max.   :1.2400
## [1] "I"   "II"  "III"
## [1] "A" "B" "C" "D"

Here, 48 rats were randomly assigned both one of three poisons and one of four possible treatments. The experimenters then measures their survival time in tens of hours. A total of 12 groups, each with 4 replicates.

Before running any tests, we should first look at the data. We will create interaction plots, which will help us visualize the effect of one factor, as we move through the levels of another factor.

If there is not interaction, thus an additive model, we would expect to see parallel lines. That means when the factor level is changed, there can be an effect on the response. However, the difference between the levels of the other factor should still be the same.

The obvious indication of interaction would be lines that cross while heading in different directions. We can’t really see it but the lines aren’t strictly parallel, and there is some overlap on the right panel. However, is this interaction effect significant?

Let’s fit each of the possible models, then investigate their estimates for each of the group means.

To get the estimates, we’ll create a table which we will predict on.

##    poison treat
## 1       I     A
## 2      II     A
## 3     III     A
## 4       I     B
## 5      II     B
## 6     III     B
## 7       I     C
## 8      II     C
## 9     III     C
## 10      I     D
## 11     II     D
## 12    III     D
##      [,1]  [,2]   [,3]   
## [1,] "I-A" "II-A" "III-A"
## [2,] "I-B" "II-B" "III-B"
## [3,] "I-C" "II-C" "III-C"
## [4,] "I-D" "II-D" "III-D"

Since repeating ourselves a number of times, so write a function to perform the prediction. Some housekeeping is done to keep the estimates in order and provide row and column names. Above, it is shown where each of the estimates will be placed in the resulting matrix.

First, we obtain the estimates from the interaction model. Note that each cell has a different value.

I II III
A 0.4125 0.3200 0.210
B 0.8800 0.8150 0.335
C 0.5675 0.3750 0.235
D 0.6100 0.6675 0.325

Next, we obtain the estimates from the additive model. Again, each cell has a different value. We also see that these estimates are somewhat close to those from the interaction model.

I II III
A 0.4522917 0.3791667 0.1110417
B 0.8147917 0.7416667 0.4735417
C 0.5306250 0.4575000 0.1893750
D 0.6722917 0.5991667 0.3310417

To understand the difference, let’s consider the effect of the treatments.

##       I      II     III 
## -0.3625 -0.3625 -0.3625
##       I      II     III 
## -0.4675 -0.4950 -0.1250

This is the key difference between the interaction and additive models. The difference between the effect of treatments A and B is the same for each poison in the additive model. They are different in the interaction model.

The remaining three models are much simpler, having either only row or only column effects. Or no effects in the case of the null model.

I II III
A 0.6175 0.544375 0.27625
B 0.6175 0.544375 0.27625
C 0.6175 0.544375 0.27625
D 0.6175 0.544375 0.27625
I II III
A 0.3141667 0.3141667 0.3141667
B 0.6766667 0.6766667 0.6766667
C 0.3925000 0.3925000 0.3925000
D 0.5341667 0.5341667 0.5341667
I II III
A 0.479375 0.479375 0.479375
B 0.479375 0.479375 0.479375
C 0.479375 0.479375 0.479375
D 0.479375 0.479375 0.479375
##              Df Sum Sq Mean Sq F value   Pr(>F)    
## poison        2 1.0330  0.5165  23.222 3.33e-07 ***
## treat         3 0.9212  0.3071  13.806 3.78e-06 ***
## poison:treat  6 0.2501  0.0417   1.874    0.112    
## Residuals    36 0.8007  0.0222                     
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Using a significance level of \(α=0.05\) , we see that the interaction is not significant. Within the additive model, both factors are significant, so we select the additive model. Within the additive model, we could do further testing about the main effects.

##   Tukey multiple comparisons of means
##     95% family-wise confidence level
## 
## Fit: aov(formula = time ~ poison + treat, data = rats)
## 
## $poison
##             diff        lwr        upr     p adj
## II-I   -0.073125 -0.2089936  0.0627436 0.3989657
## III-I  -0.341250 -0.4771186 -0.2053814 0.0000008
## III-II -0.268125 -0.4039936 -0.1322564 0.0000606
## 
## $treat
##            diff         lwr         upr     p adj
## B-A  0.36250000  0.18976135  0.53523865 0.0000083
## C-A  0.07833333 -0.09440532  0.25107198 0.6221729
## D-A  0.22000000  0.04726135  0.39273865 0.0076661
## C-B -0.28416667 -0.45690532 -0.11142802 0.0004090
## D-B -0.14250000 -0.31523865  0.03023865 0.1380432
## D-C  0.14166667 -0.03107198  0.31440532 0.1416151

For an example with interaction, we investigate the warpbreaks dataset, a default dataset in R.

Either plot makes it rather clear that the wool and tensions factors interact.

##              Df Sum Sq Mean Sq F value   Pr(>F)    
## wool          1    451   450.7   3.765 0.058213 .  
## tension       2   2034  1017.1   8.498 0.000693 ***
## wool:tension  2   1003   501.4   4.189 0.021044 *  
## Residuals    48   5745   119.7                     
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Using an \(α\) of \(0.05\) the ANOVA test finds that the interaction is significant, so we use the interaction model here.

3 Three-way ANOVA

We’ll use the headache dataset [datarium package], which contains the measures of migraine headache episode pain score in 72 participants treated with three different treatments. The participants include 36 males and 36 females. Males and females were further subdivided into whether they were at low or high risk of migraine. We want to understand how each independent variable (type of treatments, risk of migraine and gender) interact to predict the pain score.

3.1 Data preparation

Load the data and inspect one random row by group combinations:

In this example, the effect of the treatment types is our focal variable, that is our primary concern. It is thought that the effect of treatments will depend on two other factors, “gender” and “risk” level of migraine, which are called moderator variables.

3.2 Summary statistics

Compute the mean and the standard deviation (SD) of pain_score by groups:

## # A tibble: 12 x 7
##    gender risk  treatment variable       n  mean    sd
##    <fct>  <fct> <fct>     <chr>      <dbl> <dbl> <dbl>
##  1 male   high  X         pain_score     6  92.7  5.12
##  2 male   high  Y         pain_score     6  82.3  5.00
##  3 male   high  Z         pain_score     6  79.7  4.05
##  4 male   low   X         pain_score     6  76.1  3.86
##  5 male   low   Y         pain_score     6  73.1  4.76
##  6 male   low   Z         pain_score     6  74.5  4.89
##  7 female high  X         pain_score     6  78.9  5.32
##  8 female high  Y         pain_score     6  81.2  4.62
##  9 female high  Z         pain_score     6  81.0  3.98
## 10 female low   X         pain_score     6  74.2  3.69
## 11 female low   Y         pain_score     6  68.4  4.08
## 12 female low   Z         pain_score     6  69.8  2.72

3.3 Visualization

Create a box plot of pain_score by treatment, color lines by risk groups and facet the plot by gender:

3.4 Check assumptions

Identify outliers by groups:

## # A tibble: 4 x 7
##   gender risk  treatment    id pain_score is.outlier is.extreme
##   <fct>  <fct> <fct>     <int>      <dbl> <lgl>      <lgl>     
## 1 female high  X            57       68.4 TRUE       TRUE      
## 2 female high  Y            62       73.1 TRUE       FALSE     
## 3 female high  Z            67       75.0 TRUE       FALSE     
## 4 female high  Z            71       87.1 TRUE       FALSE

It can be seen that, the data contain one extreme outlier (id = 57, female at high risk of migraine taking drug X)

3.5 Normality assumption

Check normality assumption by analyzing the model residuals. QQ plot and Shapiro-Wilk test of normality are used.

## # A tibble: 1 x 3
##   variable         statistic p.value
##   <chr>                <dbl>   <dbl>
## 1 residuals(model)     0.982   0.398

In the QQ plot, as all the points fall approximately along the reference line, we can assume normality. This conclusion is supported by the Shapiro-Wilk test. The p-value is not significant (p = 0.4), so we can assume normality. Check normality assumption by groups. Computing Shapiro-Wilk test for each combinations of factor levels.

## # A tibble: 12 x 6
##    gender risk  treatment variable   statistic       p
##    <fct>  <fct> <fct>     <chr>          <dbl>   <dbl>
##  1 male   high  X         pain_score     0.958 0.808  
##  2 male   high  Y         pain_score     0.902 0.384  
##  3 male   high  Z         pain_score     0.955 0.784  
##  4 male   low   X         pain_score     0.982 0.962  
##  5 male   low   Y         pain_score     0.920 0.507  
##  6 male   low   Z         pain_score     0.924 0.535  
##  7 female high  X         pain_score     0.714 0.00869
##  8 female high  Y         pain_score     0.939 0.654  
##  9 female high  Z         pain_score     0.971 0.901  
## 10 female low   X         pain_score     0.933 0.600  
## 11 female low   Y         pain_score     0.927 0.555  
## 12 female low   Z         pain_score     0.958 0.801

The pain scores were normally distributed (p > 0.05) except for one group (female at high risk of migraine taking drug X, p = 0.0086), as assessed by Shapiro-Wilk’s test of normality.

Create QQ plot for each cell of design:

approximately along the reference line, except for one group (female at high risk of migraine taking drug X), where we already identified an extreme outlier.

3.6 Homogneity of variance assumption

This can be checked using the Levene’s test:

## # A tibble: 1 x 4
##     df1   df2 statistic     p
##   <int> <int>     <dbl> <dbl>
## 1    11    60     0.179 0.998

The Levene’s test is not significant (p > 0.05). Therefore, we can assume the homogeneity of variances in the different groups.

3.7 Computation

## ANOVA Table (type II tests)
## 
##                  Effect DFn DFd      F        p p<.05   ges
## 1                gender   1  60 16.196 1.63e-04     * 0.213
## 2                  risk   1  60 92.699 8.80e-14     * 0.607
## 3             treatment   2  60  7.318 1.00e-03     * 0.196
## 4           gender:risk   1  60  0.141 7.08e-01       0.002
## 5      gender:treatment   2  60  3.338 4.20e-02     * 0.100
## 6        risk:treatment   2  60  0.713 4.94e-01       0.023
## 7 gender:risk:treatment   2  60  7.406 1.00e-03     * 0.198

There was a statistically significant three-way interaction between gender, risk and treatment, \(F(2, 60) = 7.41\), \(p = 0.001\).

3.8 Post-hoc tests

If there is a significant three-way interaction effect, you can decompose it into:

Simple two-way interaction: run two-way interaction at each level of third variable, Simple simple main effect: run one-way model at each level of second variable, and *Simple simple pairwise comparisons: run pairwise or other post-hoc comparisons if necessary.

If you do not have a statistically significant three-way interaction, you need to determine whether you have any statistically significant two-way interaction from the ANOVA output. You can follow up a significant two-way interaction by simple main effects analyses and pairwise comparisons between groups if necessary.

In this section we’ll describe the procedure for a significant three-way interaction.

3.9 Compute simple two-way interactions

we are free to decide which two variables will form the simple two-way interactions and which variable will act as the third (moderator) variable. In our example, we want to evaluate the effect of risk*treatment interaction on pain_score at each level of gender.

In the R code below, i’ll group the data by gender and fit the treatment*risk two-way interaction. The argument error is used to specify the three-way ANOVA model from which the pooled error sum of squares and degrees of freedom are to be calculated.

## # A tibble: 6 x 8
##   gender Effect           DFn   DFd      F             p `p<.05`   ges
##   <fct>  <chr>          <dbl> <dbl>  <dbl>         <dbl> <chr>   <dbl>
## 1 male   risk               1    60 50.0   0.00000000187 "*"     0.455
## 2 male   treatment          2    60 10.2   0.000157      "*"     0.253
## 3 male   risk:treatment     2    60  5.25  0.008         "*"     0.149
## 4 female risk               1    60 42.8   0.0000000150  "*"     0.416
## 5 female treatment          2    60  0.482 0.62          ""      0.016
## 6 female risk:treatment     2    60  2.87  0.065         ""      0.087

There was a statistically significant simple two-way interaction between risk and treatment (risk:treatment) for males, F(2, 60) = 5.25, p = 0.008, but not for females, F(2, 60) = 2.87, p = 0.065.

For males, this result suggests that the effect of treatment on “pain_score” depends on one’s “risk” of migraine. In other words, the risk moderates the effect of the type of treatment on pain_score.

3.10 Compute simple main effects

A statistically significant simple two-way interaction can be followed up with simple simple main effects. In our example, you could therefore investigate the effect of treatment on pain_score at every level of risk or investigate the effect of risk at every level of treatment. Group the data by gender and risk and analyze the simple simple main effects of treatment on pain_score:

## # A tibble: 2 x 9
##   gender risk  Effect      DFn   DFd     F         p `p<.05`   ges
##   <fct>  <fct> <chr>     <dbl> <dbl> <dbl>     <dbl> <chr>   <dbl>
## 1 male   high  treatment     2    60 14.8  0.0000061 "*"     0.33 
## 2 male   low   treatment     2    60  0.66 0.521     ""      0.022

There was a statistically significant simple simple main effect of treatment for males at high risk of migraine, \(F(2, 60) = 14.8\), \(p < 0.0001)\), but not for males at low risk of migraine, \(F(2, 60) = 0.66\), \(p = 0.521\).

This analysis indicates that, the type of treatment taken has a statistically significant effect on pain_score in males who are at high risk.

In other words, the mean pain_score in the treatment X, Y and Z groups was statistically significantly different for males who at high risk, but not for males at low risk.

3.11 Compute simple simple comparisons

A statistically significant simple simple main effect can be followed up by multiple pairwise comparisons to determine which group means are different. This can be easily done using the function emmeans_test() [rstatix package] described in the previous section.

Compare the different treatments by gender and risk variables:

## # A tibble: 3 x 8
##   gender risk  term      .y.        group1 group2      p.adj p.adj.signif
##   <chr>  <chr> <chr>     <chr>      <chr>  <chr>       <dbl> <chr>       
## 1 male   high  treatment pain_score X      Y      0.000386   ***         
## 2 male   high  treatment pain_score X      Z      0.00000942 ****        
## 3 male   high  treatment pain_score Y      Z      0.897      ns
## # A tibble: 3 x 9
##   gender risk  treatment emmean    se    df conf.low conf.high method      
##   <fct>  <fct> <fct>      <dbl> <dbl> <dbl>    <dbl>     <dbl> <chr>       
## 1 male   high  X           92.7  1.80    60     89.1      96.3 Emmeans test
## 2 male   high  Y           82.3  1.80    60     78.7      85.9 Emmeans test
## 3 male   high  Z           79.7  1.80    60     76.1      83.3 Emmeans test

In the pairwise comparisons table above, we are interested only in the simple simple comparisons for males at a high risk of a migraine headache. In our example, there are three possible combinations of group differences.

For male at high risk, there was a statistically significant mean difference between treatment X and treatment Y of \(10.4\) \((p.adj < 0.001)\), and between treatment X and treatment Z of \(13.1\) \((p.adj < 0.0001)\).

However, the difference between treatment Y and treatment Z \((2.66)\) was not statistically significant, \(p.adj = 0.897\).

3.12 Report

A three-way ANOVA was conducted to determine the effects of gender, risk and treatment on migraine headache episode pain_score.

Residual analysis was performed to test for the assumptions of the three-way ANOVA. Normality was assessed using Shapiro-Wilk’s normality test and homogeneity of variances was assessed by Levene’s test.

Residuals were normally distributed (p > 0.05) and there was homogeneity of variances (p > 0.05).

There was a statistically significant three-way interaction between gender, risk and treatment, F(2, 60) = 7.41, p = 0.001.

Statistical significance was accepted at the p < 0.025 level for simple two-way interactions and simple simple main effects. There was a statistically significant simple two-way interaction between risk and treatment for males, F(2, 60) = 5.2, p = 0.008, but not for females, F(2, 60) = 2.8, p = 0.065.

There was a statistically significant simple simple main effect of treatment for males at high risk of migraine, F(2, 60) = 14.8, p < 0.0001), but not for males at low risk of migraine, F(2, 60) = 0.66, p = 0.521.

All simple simple pairwise comparisons, between the different treatment groups, were run for males at high risk of migraine with a Bonferroni adjustment applied.

There was a statistically significant mean difference between treatment X and treatment Y. However, the difference between treatment Y and treatment Z, was not statistically significant.

LS0tDQp0aXRsZTogIkFOT1ZBIg0KYXV0aG9yOiAiTmljaG9sYXMgQW5kcmlhbiINCmRhdGU6ICJgciBmb3JtYXQoU3lzLkRhdGUoKSwgJyVCICVkLCAlWScpYCINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDoNCiAgICBoaWdobGlnaHQ6IHB5Z21lbnRzDQogICAgdGhlbWU6IHNwYWNlbGFiDQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgICB0b2M6IHllcw0KICAgIHRvY19mbG9hdDogeWVzDQogICAgY29kZV9kb3dubG9hZDogeWVzDQogICAgY29kZV9mb2xkaW5nOiBoaWRlDQotLS0NCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQobWVzc2FnZSA9IEZBTFNFKQ0KYGBgDQoNCiMgT25lIFdheSBBbm92YQ0KSW4gdGhpcyBleGVyY2lzZSB5b3UgaGF2ZSB0byBjb25zaWRlciBkYXRhIHNldCBuYW1lZCBQbGFudEdyb3d0aCBmcm9tIFIgZW52aXJvbm1lbnQuIEl0IGNvbnRhaW5zIHRoZSB3ZWlnaHQgb2YgcGxhbnRzIG9idGFpbmVkIHVuZGVyIGEgY29udHJvbCBhbmQgdHdvIGRpZmZlcmVudCB0cmVhdG1lbnQgY29uZGl0aW9ucy4gUGxlYXNlIGNvbnNpZGVyIHRoZSBmb2xsb3dpbmcgc3RlcHM6DQoNCiMjIERhdGEgUHJlcGFyYXRpb24gKE9uZS13YXkgQU5PVkEpDQpIZXJlIHdlIHVzZSB0aGUgYnVpbHQtaW4gUiBkYXRhc2V0IG5hbWVkIFBsYW50R3Jvd3RoLiBJdCBjb250YWlucyB0aGUgd2VpZ2h0IG9mIHBsYW50cyBvYnRhaW5lZCB1bmRlciBhIGNvbnRyb2wgYW5kIHR3byBkaWZmZXJlbnQgdHJlYXRtZW50IGNvbmRpdGlvbnMuDQpgYGB7cix3YXJuaW5nID0gRkFMU0UsbWVzc2FnZSA9IEZBTFNFfQ0KbGlicmFyeSh0aWR5dmVyc2UpICAgICAgICAgICAgICAgICAgICAjIGZvciBkYXRhIG1hbmlwdWxhdGlvbiBhbmQgdmlzdWFsaXphdGlvbg0KbGlicmFyeSh0aWR5cikgICAgICAgICAgICAgICAgICAgICAgICAjIHRvIGNyZWF0ZSB0aWR5IGRhdGENCmxpYnJhcnkocnN0YXRpeCkgICAgICAgICAgICAgICAgICAgICAgIyB1c2UgZm9yIGJhc2ljIEFub3ZhL3N0YXRpc3RpY2FsIHRlc3RzDQpsaWJyYXJ5KGdncGxvdDIpICAgICAgICAgICAgICAgICAgICAgICMgdG8gdmlzdWFsaXppbmcgZGF0YQ0KbGlicmFyeShnZ3B1YnIpICAgICAgICAgICAgICAgICAgICAgICAjIGZvciBjcmVhdGluZyBlYXNpbHkgcHVibGljYXRpb24gcmVhZHkgcGxvdHMNCmxpYnJhcnkoZW1tZWFucykgICAgICAgICAgICAgICAgICAgICAgIyB0byBFc3RpbWF0ZWQgTWFyZ2luYWwgTWVhbnMgDQpsaWJyYXJ5KGZhcmF3YXkpICAgICAgICAgICAgICAgICAgICAgICMgdG8gZ2V0IHJhdHMgZGF0YQ0KYGBgDQoNCmBgYHtyfQ0KZGF0YSgiUGxhbnRHcm93dGgiKSAgICAgICAgICAgICAgICAgICAjIHRvIGNyZWF0ZSB0aWR5IGRhdGENCnNldC5zZWVkKDEyMzQpDQpoZWFkKFBsYW50R3Jvd3RoKQ0KYGBgDQoNClNob3cgdGhlIGxldmVscyBvZiB0aGUgZ3JvdXBpbmcgdmFyaWFibGU6DQpgYGB7cn0NCmxldmVscyhQbGFudEdyb3d0aCRncm91cCkgICAgICAgICAgICAgIyBnZXQgdG8ga25vdyB0aGUgbGV2ZWxzIG9mIGdyb3VwDQpgYGANCldoZXJlLCBjdHJsID0gQ29udHJvbCwgdHJ0MSA9IFRyZWF0bWVudCAxICx0cnQyID0gVHJlYXRtZW50IDINCg0KIyMgU3VtbWFyeSBzdGF0aXN0aWNzDQpDb21wdXRlIHNvbWUgc3VtbWFyeSBzdGF0aXN0aWNzIChjb3VudCwgbWVhbiBhbmQgc2QpIG9mIHRoZSB2YXJpYWJsZSB3ZWlnaHQgb3JnYW5pemVkIGJ5IGdyb3VwczoNCmBgYHtyfQ0KUGxhbnRHcm93dGggJT4lDQogIGdyb3VwX2J5KGdyb3VwKSAlPiUNCiAgZ2V0X3N1bW1hcnlfc3RhdHMod2VpZ2h0LCB0eXBlID0gIm1lYW5fc2QiKQ0KYGBgDQoNCiMjIHZpc3VhbGl6YXRpb24NCkNyZWF0ZSBhIGJveCBwbG90IG9mIHdlaWdodCBieSBncm91cDoNCmBgYHtyfQ0KZ2dwbG90KFBsYW50R3Jvd3RoLCBhZXMoeCA9IGdyb3VwLCB5ID0gd2VpZ2h0LCBmaWxsID0gZ3JvdXApKSArDQogICAgZ2VvbV9ib3hwbG90KCkgKw0KICAgIGdlb21faml0dGVyKHNoYXBlID0gMTUsDQogICAgICAgIGNvbG9yID0gInN0ZWVsYmx1ZSIsDQogICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25faml0dGVyKDAuMjEpKSArDQogICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KDQojIyBPdXRsaWVycw0KT3V0bGllcnMgY2FuIGJlIGVhc2lseSBpZGVudGlmaWVkIHVzaW5nIGJveCBwbG90IG1ldGhvZHMsIGltcGxlbWVudGVkIGluIHRoZSBSIGZ1bmN0aW9uIGlkZW50aWZ5X291dGxpZXJzKCkgW3JzdGF0aXggcGFja2FnZV0uDQpgYGB7cn0NClBsYW50R3Jvd3RoICU+JSANCiAgZ3JvdXBfYnkoZ3JvdXApICU+JQ0KICBpZGVudGlmeV9vdXRsaWVycyh3ZWlnaHQpDQpgYGANClRoZXJlIHdlcmUgbm8gZXh0cmVtZSBvdXRsaWVycy4NCg0KIyMgT25lLXdheSBBTk9WQSBUZXN0DQpUaGUgYW92KCkgZnVuY3Rpb24gaXMgdXNlZCB0byBvYnRhaW4gdGhlIHJlbGV2YW50IHN1bXMgb2Ygc3F1YXJlcy4gVXNpbmcgdGhlIHN1bW1hcnkoKSBmdW5jdGlvbiBvbiB0aGUgb3V0cHV0IGZyb20gYW92KCkgY3JlYXRlcyB0aGUgZGVzaXJlZCBBTk9WQSB0YWJsZS4gKFdpdGhvdXQgdGhlIHVubmVlZGVkIHJvdyBmb3IgdG90YWwpLg0KDQpgYGB7cn0NCnJlcy5hb3YgPC0gUGxhbnRHcm93dGggJT4lIGFub3ZhX3Rlc3Qod2VpZ2h0IH4gZ3JvdXApDQpgYGANCg0KYGBge3J9DQpyZXMuYW92DQpgYGANCg0KYGBge3J9DQp3ZWlnaHRfYW92ID0gYW92KHdlaWdodCB+IGdyb3VwLCBkYXRhID0gUGxhbnRHcm93dGgpDQpzdW1tYXJ5KHdlaWdodF9hb3YpDQpgYGANCg0KaW4gdGhlIHRhYmxlIGFib3ZlLCB0aGUgY29sdW1uIGdlcyBjb3JyZXNwb25kcyB0byB0aGUgZ2VuZXJhbGl6ZWQgZXRhIHNxdWFyZWQgKGVmZmVjdCBzaXplKS4gSXQgbWVhc3VyZXMgdGhlIHByb3BvcnRpb24gb2YgdGhlIHZhcmlhYmlsaXR5IGluIHRoZSBvdXRjb21lIHZhcmlhYmxlIChoZXJlIHBsYW50IHdlaWdodCkgdGhhdCBjYW4gYmUgZXhwbGFpbmVkIGluIHRlcm1zIG9mIHRoZSBwcmVkaWN0b3IgKGhlcmUsIHRyZWF0bWVudCBncm91cCkuIEFuIGVmZmVjdCBzaXplIG9mIDAuMjY0ICgyNi40JSkgbWVhbnMgdGhhdCAyNi40JSBvZiB0aGUgY2hhbmdlIGluIHRoZSB3ZWlnaHQgY2FuIGJlIGFjY291bnRlZCBmb3IgdGhlIHRyZWF0bWVudCBjb25kaXRpb25zLiBGcm9tIHRoZSBhYm92ZSBBTk9WQSB0YWJsZSwgaXQgY2FuIGJlIHNlZW4gdGhhdCB0aGVyZSBhcmUgc2lnbmlmaWNhbnQgZGlmZmVyZW5jZXMgYmV0d2VlbiBncm91cHMgKHA9MC4wMTYpLCB3aGljaCBhcmUgaGlnaGxpZ2h0ZWQgd2l0aCDigJwq4oCcLCAkRigyLDI3KT00Ljg1JCwgJHA9MC4xNiQsICRldGEyW2ddPTAuMjYkLg0KDQp3aGVyZSwNCkYgaW5kaWNhdGVzIHRoYXQgd2UgYXJlIGNvbXBhcmluZyB0byBhbiBGLWRpc3RyaWJ1dGlvbiAoRi10ZXN0KTsgKDIsIDI3KSBpbmRpY2F0ZXMgdGhlIGRlZ3JlZXMgb2YgZnJlZWRvbSBpbiB0aGUgbnVtZXJhdG9yIChERm4pIGFuZCB0aGUgZGVub21pbmF0b3IgKERGZCksIHJlc3BlY3RpdmVseTsgNC44NSBpbmRpY2F0ZXMgdGhlIG9idGFpbmVkIEYtc3RhdGlzdGljIHZhbHVlIHAgc3BlY2lmaWVzIHRoZSBwLXZhbHVlICpnZXMgaXMgdGhlIGdlbmVyYWxpemVkIGVmZmVjdCBzaXplIChhbW91bnQgb2YgdmFyaWFiaWxpdHkgZHVlIHRvIHRoZSBmYWN0b3IpDQoNCiMjIENoZWNrIEFzc3VtcHRpb25zIChPbmUtd2F5IEFOT1ZBKQ0KVGhlIEFOT1ZBIHRlc3QgYXNzdW1lcyB0aGF0LCB0aGUgZGF0YSBhcmUgbm9ybWFsbHkgZGlzdHJpYnV0ZWQgYW5kIHRoZSB2YXJpYW5jZSBhY3Jvc3MgZ3JvdXBzIGFyZSBob21vZ2VuZW91cy4gV2UgY2FuIGNoZWNrIHRoYXQgd2l0aCBzb21lIGRpYWdub3N0aWMgcGxvdHMuDQoNClRoZSBub3JtYWxpdHkgYXNzdW1wdGlvbiBjYW4gYmUgY2hlY2tlZCBieSB1c2luZyBvbmUgb2YgdGhlIGZvbGxvd2luZyB0d28gYXBwcm9hY2hlczoNCg0KQW5hbHl6aW5nIHRoZSBBTk9WQSBtb2RlbCByZXNpZHVhbHMgdG8gY2hlY2sgdGhlIG5vcm1hbGl0eSBmb3IgYWxsIGdyb3VwcyB0b2dldGhlci4gVGhpcyBhcHByb2FjaCBpcyBlYXNpZXIgYW5kIGl04oCZcyB2ZXJ5IGhhbmR5IHdoZW4geW91IGhhdmUgbWFueSBncm91cHMgb3IgaWYgdGhlcmUgYXJlIGZldyBkYXRhIHBvaW50cyBwZXIgZ3JvdXAuIENoZWNrIG5vcm1hbGl0eSBmb3IgZWFjaCBncm91cCBzZXBhcmF0ZWx5LiBUaGlzIGFwcHJvYWNoIG1pZ2h0IGJlIHVzZWQgd2hlbiB5b3UgaGF2ZSBvbmx5IGEgZmV3IGdyb3VwcyBhbmQgbWFueSBkYXRhIHBvaW50cyBwZXIgZ3JvdXAuDQoNClRoaXMgc2VjdGlvbiB3aWxsIHNob3cgaG93IHRvIHByb2NlZWQgZm9yIGJvdGggb3B0aW9uIDEgYW5kIDIuDQoNCkNoZWNrIG5vcm1hbGl0eSBhc3N1bXB0aW9uIGJ5IGFuYWx5emluZyB0aGUgbW9kZWwgcmVzaWR1YWxzLiBRUSBwbG90IGFuZCBTaGFwaXJvLVdpbGsgdGVzdCBvZiBub3JtYWxpdHkgYXJlIHVzZWQuIFFRIHBsb3QgZHJhd3MgdGhlIGNvcnJlbGF0aW9uIGJldHdlZW4gYSBnaXZlbiBkYXRhIGFuZCB0aGUgbm9ybWFsIGRpc3RyaWJ1dGlvbi4NCg0KYGBge3J9DQpwbG90KHdlaWdodF9hb3YsIDEpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyAxLiBIb21vZ2VuZWl0eSBvZiB2YXJpYW5jZXMNCmBgYA0KSW4gdGhlIHBsb3QgYWJvdmUsIHRoZXJlIGlzIG5vIGV2aWRlbnQgdG8gc2hvdyByZWxhdGlvbnNoaXBzIGJldHdlZW4gcmVzaWR1YWxzIGFuZCBmaXR0ZWQgdmFsdWVzICh0aGUgbWVhbiBvZiBlYWNoIGdyb3VwcyksIHdoaWNoIGlzIGdvb2QuIFNvLCB3ZSBjYW4gYXNzdW1lIHRoZSBob21vZ2VuaXR5IG9mIHZhcmlhbmNlcy4NCg0KQ2hlY2sgbm9ybWFsaXR5IGFzc3VtcHRpb24gYnkgZ3JvdXBzLiBDb21wdXRpbmcgU2hhcGlyby1XaWxrIHRlc3QgZm9yIGVhY2ggZ3JvdXAgbGV2ZWwuIElmIHRoZSBkYXRhIGlzIG5vcm1hbGx5IGRpc3RyaWJ1dGVkLCB0aGUgcC12YWx1ZSBzaG91bGQgYmUgZ3JlYXRlciB0aGFuIDAuMDUuDQoNCmBgYHtyfQ0KUGxhbnRHcm93dGggJT4lDQogIGdyb3VwX2J5KGdyb3VwKSAlPiUNCiAgc2hhcGlyb190ZXN0KHdlaWdodCkNCmBgYA0KDQpUaGUgc2NvcmUgd2VyZSBub3JtYWxseSBkaXN0cmlidXRlZCAocD4wLjA1DQoNCikgZm9yIGVhY2ggZ3JvdXAsIGFzIGFzc2Vzc2VkIGJ5IFNoYXBpcm8tV2lsa+KAmXMgdGVzdCBvZiBub3JtYWxpdHkuIE5vdGUgOiBpZiBzYW1wbGUgc2l6ZSBpcyBncmVhdGVyIHRoYW4gNTAsIHRoZSBub3JtYWwgUVEgcGxvdCBpcyBwcmVmZXJyZWQgYmVjYXVzZSBhdCBsYXJnZXIgc2FtcGxlIHNpemVzIHRoZSBTaGFwaXJvLVdpbGsgdGVzdCBiZWNvbWVzIHZlcnkgc2Vuc2l0aXZlIGV2ZW4gdG8gYSBtaW5vciBkZXZpYXRpb24gZnJvbSBub3JtYWxpdHkuDQoNClFRIHBsb3QgZHJhd3MgdGhlIGNvcnJlbGF0aW9uIGJldHdlZW4gYSBnaXZlbiBkYXRhIGFuZCB0aGUgbm9ybWFsIGRpc3RyaWJ1dGlvbi4gQ3JlYXRlIFFRIHBsb3RzIGZvciBlYWNoIGdyb3VwIGxldmVsOg0KDQpgYGB7cn0NCnBsb3Qod2VpZ2h0X2FvdiwgMikgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyAyLiBOb3JtYWxpdHkNCmBgYA0KUG9pbnRzIDQsIDE1LCAxNyBhcmUgZGV0ZWN0ZWQgYXMgb3V0bGllcnMgc2luY2UgaXQgaXMgZmFyIGZyb20gdGhlIGxpbmVhcml0eSwgd2hpY2ggY2FuIHNldmVyZWx5IGFmZmVjdCBub3JtYWxpdHkgYW5kIGhvbW9nZW5laXR5IG9mIHZhcmlhbmNlLiBJdCBjYW4gYmUgdXNlZnVsIHRvIHJlbW92ZSBvdXRsaWVycyB0byBtZWV0IHRoZSB0ZXN0IGFzc3VtcHRpb25zLiBJIHJlY29tbWVuZCBMZXZlbmXigJlzIHRlc3QsIHdoaWNoIGlzIGxlc3Mgc2Vuc2l0aXZlIHRvIGRlcGFydHVyZXMgZnJvbSBub3JtYWwgZGlzdHJpYnV0aW9uLiBGcm9tIHRoZSBTaGFwaXJvLVdpbGsgdGVzdCBvbiB0aGUgQU5PVkEgcmVzaWR1YWxzIChXPTAuOTcsIHA9MC44KSB3aGljaCBmaW5kcyBubyBpbmRpY2F0aW9uIHRoYXQgbm9ybWFsaXR5IGlzIHZpb2xhdGVkLg0KDQpgYGB7cn0NClBsYW50R3Jvd3RoICU+JSBsZXZlbmVfdGVzdCh3ZWlnaHQgfiBncm91cCkgDQpgYGANCg0KYGBge3J9DQpvbmV3YXkudGVzdCh3ZWlnaHQgfiBncm91cCwgZGF0YSA9IFBsYW50R3Jvd3RoKSAgICMgbm8gYXNzdW1wdGlvbiBvZiBlcXVhbCB2YXJpYW5jZXMNCmBgYA0KRnJvbSB0aGUgb3V0cHV0IGFib3ZlLCB3ZSBjYW4gc2VlIHRoYXQgdGhlIHAtdmFsdWUgaXMgPjAuMDUsIHdoaWNoIGlzIG5vdCBzaWduaWZpY2FudC4gVGhpcyBtZWFucyB0aGF0LCB0aGVyZSBpcyBub3Qgc2lnbmlmaWNhbnQgZGlmZmVyZW5jZSBiZXR3ZWVuIHZhcmlhbmNlcyBhY3Jvc3MgZ3JvdXBzLiBUaGVyZWZvcmUsIHdlIGNhbiBhc3N1bWUgdGhlIGhvbW9nZW5pdHkgb2YgdmFyaWFuY2VzIGluIHRoZSBkaWZmZXJlbnQgdHJlYXRtZW50IGdyb3Vwcy4NCg0KIyMgUGFpcndpc2UtY29tcGFyaXNvbiAoT25lLXdheSBBTk9WQSkNCkEgc2lnbmlmaWNhbnQgb25lLXdheSBBTk9WQSBpcyBnZW5lcmFsbHkgZm9sbG93ZWQgdXAgYnkgVHVrZXkgcG9zdC1ob2MgdGVzdHMgdG8gcGVyZm9ybSBtdWx0aXBsZSBwYWlyd2lzZSBjb21wYXJpc29ucyBiZXR3ZWVuIGdyb3Vwcy4gS2V5IFIgZnVuY3Rpb246IHR1a2V5X2hzZCgpIFtyc3RhdGl4XS4NCg0KYGBge3J9DQojIFBhaXJ3aXNlIGNvbXBhcmlzb25zDQpwd2MgPC0gUGxhbnRHcm93dGggJT4lIHR1a2V5X2hzZCh3ZWlnaHQgfiBncm91cCkNCnB3Yw0KYGBgDQpUaGUgb3V0cHV0IGNvbnRhaW5zIHRoZSBmb2xsb3dpbmcgY29sdW1uczoNCg0KZXN0aW1hdGU6IGVzdGltYXRlIG9mIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gbWVhbnMgb2YgdGhlIHR3byBncm91cHMgY29uZi5sb3csIGNvbmYuaGlnaDogdGhlIGxvd2VyIGFuZCB0aGUgdXBwZXIgZW5kIHBvaW50IG9mIHRoZSBjb25maWRlbmNlIGludGVydmFsIGF0IDk1JSAoZGVmYXVsdCkgcC5hZGo6IHAtdmFsdWUgYWZ0ZXIgYWRqdXN0bWVudCBmb3IgdGhlIG11bHRpcGxlIGNvbXBhcmlzb25zLiBJdCBjYW4gYmUgc2VlbiBmcm9tIHRoZSBvdXRwdXQsIHRoYXQgb25seSB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIHRydDIgYW5kIHRydDEgaXMgc2lnbmlmaWNhbnQgKGFkanVzdGVkIHAtdmFsdWUgPSAwLjAxMikuDQoNCiMjIFR1a2V5IEhTRCAoT25lLXdheSBBTk9WQSkNClR1a2V54oCZcyBIb25lc3QgU2lnbmlmaWNhbmNlIGRpZmZlcmVuY2UgY2FuIGJlIGFwcGxpZWQgZGlyZWN0bHkgdG8gYW4gb2JqZWN0IHdoaWNoIHdhcyBjcmVhdGVkIHVzaW5nIGFvdigpLiBJdCB3aWxsIGFkanVzdCB0aGUgcC12YWx1ZXMgb2YgdGhlIHBhaXJ3aXNlIGNvbXBhcmlzb25zIG9mIHRoZSBtZWFucyB0byBjb250cm9sIHRoZSBGV0VSLCBpbiB0aGlzIGNhc2UsIGZvciAwLjA1LiBOb3RpY2UgaXQgYWxzbyBnaXZlcyBjb25maWRlbmNlIGludGVydmFscyBmb3IgdGhlIGRpZmZlcmVuY2Ugb2YgdGhlIG1lYW5zLg0KDQpgYGB7cn0NClR1a2V5SFNEKHdlaWdodF9hb3YsIGNvbmYubGV2ZWwgPSAwLjk1KQ0KYGBgDQoNCmBgYHtyfQ0KcGxvdChUdWtleUhTRCh3ZWlnaHRfYW92LCBjb25mLmxldmVsID0gMC45NSkpDQpgYGANCkJhc2VkIG9uIHRoZXNlIHJlc3VsdHMsIHdlIHNlZSB0aGUgY29udHJvbCBpcyBjYXVzaW5nIHRyZWF0bWVudCB0byBjaGFuZ2UgZWl0aGVyIGNvbnRyb2wgdG93YXJkcyB0cmVhdG1lbnQgMSBvciBjb250cm9sIHRvd2FyZHMgdHJlYXRtZW50IDIuIEJ1dCBub3QgYmV0d2VlbiB0cmVhdG1lbnRzLg0KDQojIyAgUmVwb3J0DQpXZSBjb3VsZCByZXBvcnQgdGhlIHJlc3VsdHMgb2Ygb25lLXdheSBBTk9WQSBhcyBmb2xsb3c6DQoNCi0gQSBvbmUtd2F5IEFOT1ZBIHdhcyBwZXJmb3JtZWQgdG8gZXZhbHVhdGUgaWYgdGhlIHBsYW50IGdyb3d0aCB3YXMgZGlmZmVyZW50IGZvciB0aGUgMyBkaWZmZXJlbnQgdHJlYXRtZW50IGdyb3VwczogY3RyLCB0cnQxIGFuZCB0cnQyIGFsbCBoYXZlIG49MTAuDQoNCi0gRGF0YSBpcyBwcmVzZW50ZWQgYXMgbWVhbiArLy0gc3RhbmRhcmQgZGV2aWF0aW9uLiBQbGFudCBncm93dGggd2FzIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnRseSBkaWZmZXJlbnQgYmV0d2VlbiBkaWZmZXJlbnQgdHJlYXRtZW50IGdyb3VwcywgRigyLCAyNykgPSA0Ljg1LCBwID0gMC4wMTYsIGdlbmVyYWxpemVkIGV0YSBzcXVhcmVkID0gMC4yNi4NCg0KLSBQbGFudCBncm93dGggZGVjcmVhc2VkIGluIHRydDEgZ3JvdXAgKDQuNjYgKy8tIDAuNzkpIGNvbXBhcmVkIHRvIGN0ciBncm91cCAoNS4wMyArLy0gMC41OCkuIEl0IGluY3JlYXNlZCBpbiB0cnQyIGdyb3VwICg1LjUzICsvLSAwLjQ0KSBjb21wYXJlZCB0byB0cnQxIGFuZCBjdHIgZ3JvdXAuDQoNCi0gVHVrZXkgcG9zdC1ob2MgYW5hbHlzZXMgcmV2ZWFsZWQgdGhhdCB0aGUgaW5jcmVhc2UgZnJvbSB0cnQxIHRvIHRydDIgKDAuODcsIDk1JSBDSSAoMC4xNyB0byAxLjU2KSkgd2FzIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgKHAgPSAwLjAxMiksIGJ1dCBubyBvdGhlciBncm91cCBkaWZmZXJlbmNlcyB3ZXJlIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQuDQoNCiMgVHdvLXdheSBBTk9WQQ0KUGxlYXNlIGFwcGx5IFR3by13YXkgQU5PVkEgcHJvY2VkdXJlcyB0byB0aGUgcmF0cyBkYXRhIGZyb20gdGhlIGZhcmF3YXkgcGFja2FnZS4gVGhlcmUgYXJlIHR3byBmYWN0b3JzIGhlcmU6IHBvaXNvbiBhbmQgdHJlYXQuIFlvdSBjYW4gdXNlIHRoZSBsZXZlbHMoKSBmdW5jdGlvbiB0byBleHRyYWN0IHRoZSBsZXZlbHMgb2YgYSBmYWN0b3IgdmFyaWFibGUuIEdpdmUgeW91ciBvcGluaW9ucyBhY2NvcmRpbmdseSENCg0KYGBge3J9DQpzdW1tYXJ5KHJhdHMpDQpgYGANCg0KYGBge3J9DQpsZXZlbHMocmF0cyRwb2lzb24pDQpgYGANCg0KYGBge3J9DQpsZXZlbHMocmF0cyR0cmVhdCkNCmBgYA0KSGVyZSwgNDggcmF0cyB3ZXJlIHJhbmRvbWx5IGFzc2lnbmVkIGJvdGggb25lIG9mIHRocmVlIHBvaXNvbnMgYW5kIG9uZSBvZiBmb3VyIHBvc3NpYmxlIHRyZWF0bWVudHMuIFRoZSBleHBlcmltZW50ZXJzIHRoZW4gbWVhc3VyZXMgdGhlaXIgc3Vydml2YWwgdGltZSBpbiB0ZW5zIG9mIGhvdXJzLiBBIHRvdGFsIG9mIDEyIGdyb3VwcywgZWFjaCB3aXRoIDQgcmVwbGljYXRlcy4NCg0KQmVmb3JlIHJ1bm5pbmcgYW55IHRlc3RzLCB3ZSBzaG91bGQgZmlyc3QgbG9vayBhdCB0aGUgZGF0YS4gV2Ugd2lsbCBjcmVhdGUgaW50ZXJhY3Rpb24gcGxvdHMsIHdoaWNoIHdpbGwgaGVscCB1cyB2aXN1YWxpemUgdGhlIGVmZmVjdCBvZiBvbmUgZmFjdG9yLCBhcyB3ZSBtb3ZlIHRocm91Z2ggdGhlIGxldmVscyBvZiBhbm90aGVyIGZhY3Rvci4NCg0KYGBge3J9DQpwYXIobWZyb3cgPSBjKDEsIDIpKQ0Kd2l0aChyYXRzLCBpbnRlcmFjdGlvbi5wbG90KHBvaXNvbiwgdHJlYXQsIHRpbWUsIGx3ZCA9IDIsIGNvbCA9IDE6NCkpDQp3aXRoKHJhdHMsIGludGVyYWN0aW9uLnBsb3QodHJlYXQsIHBvaXNvbiwgdGltZSwgbHdkID0gMiwgY29sID0gMTozKSkNCmBgYA0KSWYgdGhlcmUgaXMgbm90IGludGVyYWN0aW9uLCB0aHVzIGFuIGFkZGl0aXZlIG1vZGVsLCB3ZSB3b3VsZCBleHBlY3QgdG8gc2VlIHBhcmFsbGVsIGxpbmVzLiBUaGF0IG1lYW5zIHdoZW4gdGhlIGZhY3RvciBsZXZlbCBpcyBjaGFuZ2VkLCB0aGVyZSBjYW4gYmUgYW4gZWZmZWN0IG9uIHRoZSByZXNwb25zZS4gSG93ZXZlciwgdGhlIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgbGV2ZWxzIG9mIHRoZSBvdGhlciBmYWN0b3Igc2hvdWxkIHN0aWxsIGJlIHRoZSBzYW1lLg0KDQpUaGUgb2J2aW91cyBpbmRpY2F0aW9uIG9mIGludGVyYWN0aW9uIHdvdWxkIGJlIGxpbmVzIHRoYXQgY3Jvc3Mgd2hpbGUgaGVhZGluZyBpbiBkaWZmZXJlbnQgZGlyZWN0aW9ucy4gV2UgY2Fu4oCZdCByZWFsbHkgc2VlIGl0IGJ1dCB0aGUgbGluZXMgYXJlbuKAmXQgc3RyaWN0bHkgcGFyYWxsZWwsIGFuZCB0aGVyZSBpcyBzb21lIG92ZXJsYXAgb24gdGhlIHJpZ2h0IHBhbmVsLiBIb3dldmVyLCBpcyB0aGlzIGludGVyYWN0aW9uIGVmZmVjdCBzaWduaWZpY2FudD8NCg0KTGV04oCZcyBmaXQgZWFjaCBvZiB0aGUgcG9zc2libGUgbW9kZWxzLCB0aGVuIGludmVzdGlnYXRlIHRoZWlyIGVzdGltYXRlcyBmb3IgZWFjaCBvZiB0aGUgZ3JvdXAgbWVhbnMuDQoNCmBgYHtyfQ0KcmF0c19pbnQgICA9IGFvdih0aW1lIH4gcG9pc29uICogdHJlYXQsIGRhdGEgPSByYXRzKSAjIGludGVyYWN0aW9uIG1vZGVsDQpyYXRzX2FkZCAgID0gYW92KHRpbWUgfiBwb2lzb24gKyB0cmVhdCwgZGF0YSA9IHJhdHMpICMgYWRkaXRpdmUgbW9kZWwNCnJhdHNfcG9pcyAgPSBhb3YodGltZSB+IHBvaXNvbiAsIGRhdGEgPSByYXRzKSAgICAgICAgIyBzaW5nbGUgZmFjdG9yIG1vZGVsICAgDQpyYXRzX3RyZWF0ID0gYW92KHRpbWUgfiB0cmVhdCwgZGF0YSA9IHJhdHMpICAgICAgICAgICMgc2luZ2xlIGZhY3RvciBtb2RlbA0KcmF0c19udWxsICA9IGFvdih0aW1lIH4gMSwgZGF0YSA9IHJhdHMpICAgICAgICAgICAgICAjIG51bGwgbW9kZWwNCmBgYA0KVG8gZ2V0IHRoZSBlc3RpbWF0ZXMsIHdl4oCZbGwgY3JlYXRlIGEgdGFibGUgd2hpY2ggd2Ugd2lsbCBwcmVkaWN0IG9uLg0KDQpgYGB7cn0NCnJhdHNfdGFibGUgPSBleHBhbmQuZ3JpZChwb2lzb24gPSB1bmlxdWUocmF0cyRwb2lzb24pLCB0cmVhdCA9IHVuaXF1ZShyYXRzJHRyZWF0KSkNCnJhdHNfdGFibGUNCmBgYA0KDQpgYGB7cn0NCm1hdHJpeChwYXN0ZTAocmF0c190YWJsZSRwb2lzb24sICItIiwgcmF0c190YWJsZSR0cmVhdCksIDQsIDMsIGJ5cm93ID0gVFJVRSkNCmBgYA0KU2luY2UgcmVwZWF0aW5nIG91cnNlbHZlcyBhIG51bWJlciBvZiB0aW1lcywgc28gd3JpdGUgYSBmdW5jdGlvbiB0byBwZXJmb3JtIHRoZSBwcmVkaWN0aW9uLiBTb21lIGhvdXNla2VlcGluZyBpcyBkb25lIHRvIGtlZXAgdGhlIGVzdGltYXRlcyBpbiBvcmRlciBhbmQgcHJvdmlkZSByb3cgYW5kIGNvbHVtbiBuYW1lcy4gQWJvdmUsIGl0IGlzIHNob3duIHdoZXJlIGVhY2ggb2YgdGhlIGVzdGltYXRlcyB3aWxsIGJlIHBsYWNlZCBpbiB0aGUgcmVzdWx0aW5nIG1hdHJpeC4NCg0KYGBge3J9DQpnZXRfZXN0X21lYW5zID0gZnVuY3Rpb24obW9kZWwsIHRhYmxlKSB7DQogIG1hdCA9IG1hdHJpeChwcmVkaWN0KG1vZGVsLCB0YWJsZSksIG5yb3cgPSA0LCBuY29sID0gMywgYnlyb3cgPSBUUlVFKQ0KICBjb2xuYW1lcyhtYXQpID0gYygiSSIsICJJSSIsICJJSUkiKQ0KICByb3duYW1lcyhtYXQpID0gYygiQSIsICJCIiwgIkMiLCAiRCIpDQogIG1hdA0KfQ0KYGBgDQpGaXJzdCwgd2Ugb2J0YWluIHRoZSBlc3RpbWF0ZXMgZnJvbSB0aGUgaW50ZXJhY3Rpb24gbW9kZWwuIE5vdGUgdGhhdCBlYWNoIGNlbGwgaGFzIGEgZGlmZmVyZW50IHZhbHVlLg0KDQpgYGB7cn0NCmtuaXRyOjprYWJsZShnZXRfZXN0X21lYW5zKG1vZGVsID0gcmF0c19pbnQsIHRhYmxlID0gcmF0c190YWJsZSkpDQpgYGANCk5leHQsIHdlIG9idGFpbiB0aGUgZXN0aW1hdGVzIGZyb20gdGhlIGFkZGl0aXZlIG1vZGVsLiBBZ2FpbiwgZWFjaCBjZWxsIGhhcyBhIGRpZmZlcmVudCB2YWx1ZS4gV2UgYWxzbyBzZWUgdGhhdCB0aGVzZSBlc3RpbWF0ZXMgYXJlIHNvbWV3aGF0IGNsb3NlIHRvIHRob3NlIGZyb20gdGhlIGludGVyYWN0aW9uIG1vZGVsLg0KDQpgYGB7cn0NCmtuaXRyOjprYWJsZShnZXRfZXN0X21lYW5zKG1vZGVsID0gcmF0c19hZGQsIHRhYmxlID0gcmF0c190YWJsZSkpDQpgYGANClRvIHVuZGVyc3RhbmQgdGhlIGRpZmZlcmVuY2UsIGxldOKAmXMgY29uc2lkZXIgdGhlIGVmZmVjdCBvZiB0aGUgdHJlYXRtZW50cy4NCg0KYGBge3J9DQphZGRpdGl2ZV9tZWFucyA9IGdldF9lc3RfbWVhbnMobW9kZWwgPSByYXRzX2FkZCwgdGFibGUgPSByYXRzX3RhYmxlKQ0KYWRkaXRpdmVfbWVhbnNbIkEiLF0gLSBhZGRpdGl2ZV9tZWFuc1siQiIsXQ0KYGBgDQoNCmBgYHtyfQ0KaW50ZXJhY3Rpb25fbWVhbnMgPSBnZXRfZXN0X21lYW5zKG1vZGVsID0gcmF0c19pbnQsIHRhYmxlID0gcmF0c190YWJsZSkNCmludGVyYWN0aW9uX21lYW5zWyJBIixdIC0gaW50ZXJhY3Rpb25fbWVhbnNbIkIiLF0NCmBgYA0KVGhpcyBpcyB0aGUga2V5IGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgaW50ZXJhY3Rpb24gYW5kIGFkZGl0aXZlIG1vZGVscy4gVGhlIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgZWZmZWN0IG9mIHRyZWF0bWVudHMgQSBhbmQgQiBpcyB0aGUgc2FtZSBmb3IgZWFjaCBwb2lzb24gaW4gdGhlIGFkZGl0aXZlIG1vZGVsLiBUaGV5IGFyZSBkaWZmZXJlbnQgaW4gdGhlIGludGVyYWN0aW9uIG1vZGVsLg0KDQpUaGUgcmVtYWluaW5nIHRocmVlIG1vZGVscyBhcmUgbXVjaCBzaW1wbGVyLCBoYXZpbmcgZWl0aGVyIG9ubHkgcm93IG9yIG9ubHkgY29sdW1uIGVmZmVjdHMuIE9yIG5vIGVmZmVjdHMgaW4gdGhlIGNhc2Ugb2YgdGhlIG51bGwgbW9kZWwuDQoNCmBgYHtyfQ0Ka25pdHI6OmthYmxlKGdldF9lc3RfbWVhbnMobW9kZWwgPSByYXRzX3BvaXMsIHRhYmxlID0gcmF0c190YWJsZSkpDQpgYGANCg0KYGBge3J9DQprbml0cjo6a2FibGUoZ2V0X2VzdF9tZWFucyhtb2RlbCA9IHJhdHNfdHJlYXQsIHRhYmxlID0gcmF0c190YWJsZSkpDQpgYGANCg0KYGBge3J9DQprbml0cjo6a2FibGUoZ2V0X2VzdF9tZWFucyhtb2RlbCA9IHJhdHNfbnVsbCwgdGFibGUgPSByYXRzX3RhYmxlKSkNCmBgYA0KDQpgYGB7cn0NCnN1bW1hcnkoYW92KHRpbWUgfiBwb2lzb24gKiB0cmVhdCwgZGF0YSA9IHJhdHMpKQ0KYGBgDQpVc2luZyBhIHNpZ25pZmljYW5jZSBsZXZlbCBvZiAkzrE9MC4wNSQgLCB3ZSBzZWUgdGhhdCB0aGUgaW50ZXJhY3Rpb24gaXMgbm90IHNpZ25pZmljYW50LiBXaXRoaW4gdGhlIGFkZGl0aXZlIG1vZGVsLCBib3RoIGZhY3RvcnMgYXJlIHNpZ25pZmljYW50LCBzbyB3ZSBzZWxlY3QgdGhlIGFkZGl0aXZlIG1vZGVsLg0KV2l0aGluIHRoZSBhZGRpdGl2ZSBtb2RlbCwgd2UgY291bGQgZG8gZnVydGhlciB0ZXN0aW5nIGFib3V0IHRoZSBtYWluIGVmZmVjdHMuDQoNCmBgYHtyfQ0KVHVrZXlIU0QoYW92KHRpbWUgfiBwb2lzb24gKyB0cmVhdCwgZGF0YSA9IHJhdHMpKQ0KYGBgDQpGb3IgYW4gZXhhbXBsZSB3aXRoIGludGVyYWN0aW9uLCB3ZSBpbnZlc3RpZ2F0ZSB0aGUgd2FycGJyZWFrcyBkYXRhc2V0LCBhIGRlZmF1bHQgZGF0YXNldCBpbiBSLg0KDQpgYGB7cn0NCnBhcihtZnJvdyA9IGMoMSwgMikpDQp3aXRoKHdhcnBicmVha3MsIGludGVyYWN0aW9uLnBsb3Qod29vbCwgdGVuc2lvbiwgYnJlYWtzLCBsd2QgPSAyLCBjb2wgPSAyOjQpKQ0Kd2l0aCh3YXJwYnJlYWtzLCBpbnRlcmFjdGlvbi5wbG90KHRlbnNpb24sIHdvb2wsIGJyZWFrcywgbHdkID0gMiwgY29sID0gMjozKSkNCmBgYA0KRWl0aGVyIHBsb3QgbWFrZXMgaXQgcmF0aGVyIGNsZWFyIHRoYXQgdGhlIHdvb2wgYW5kIHRlbnNpb25zIGZhY3RvcnMgaW50ZXJhY3QuDQoNCmBgYHtyfQ0Kc3VtbWFyeShhb3YoYnJlYWtzIH4gd29vbCAqIHRlbnNpb24sIGRhdGEgPSB3YXJwYnJlYWtzKSkNCmBgYA0KVXNpbmcgYW4gJM6xJCBvZiAkMC4wNSQgdGhlIEFOT1ZBIHRlc3QgZmluZHMgdGhhdCB0aGUgaW50ZXJhY3Rpb24gaXMgc2lnbmlmaWNhbnQsIHNvIHdlIHVzZSB0aGUgaW50ZXJhY3Rpb24gbW9kZWwgaGVyZS4NCg0KIyBUaHJlZS13YXkgQU5PVkENCldl4oCZbGwgdXNlIHRoZSBoZWFkYWNoZSBkYXRhc2V0IFtkYXRhcml1bSBwYWNrYWdlXSwgd2hpY2ggY29udGFpbnMgdGhlIG1lYXN1cmVzIG9mIG1pZ3JhaW5lIGhlYWRhY2hlIGVwaXNvZGUgcGFpbiBzY29yZSBpbiA3MiBwYXJ0aWNpcGFudHMgdHJlYXRlZCB3aXRoIHRocmVlIGRpZmZlcmVudCB0cmVhdG1lbnRzLiBUaGUgcGFydGljaXBhbnRzIGluY2x1ZGUgMzYgbWFsZXMgYW5kIDM2IGZlbWFsZXMuIE1hbGVzIGFuZCBmZW1hbGVzIHdlcmUgZnVydGhlciBzdWJkaXZpZGVkIGludG8gd2hldGhlciB0aGV5IHdlcmUgYXQgbG93IG9yIGhpZ2ggcmlzayBvZiBtaWdyYWluZS4gV2Ugd2FudCB0byB1bmRlcnN0YW5kIGhvdyBlYWNoIGluZGVwZW5kZW50IHZhcmlhYmxlICh0eXBlIG9mIHRyZWF0bWVudHMsIHJpc2sgb2YgbWlncmFpbmUgYW5kIGdlbmRlcikgaW50ZXJhY3QgdG8gcHJlZGljdCB0aGUgcGFpbiBzY29yZS4NCg0KIyMgRGF0YSBwcmVwYXJhdGlvbg0KTG9hZCB0aGUgZGF0YSBhbmQgaW5zcGVjdCBvbmUgcmFuZG9tIHJvdyBieSBncm91cCBjb21iaW5hdGlvbnM6DQpgYGB7cn0NCiMgTG9hZCBhbmQgc2hvdyBvbmUgcmFuZG9tIHJvdyBieSBncm91cDoNCnNldC5zZWVkKDEyMykNCmRhdGEoImhlYWRhY2hlIiwgcGFja2FnZSA9ICJkYXRhcml1bSIpDQpgYGANCg0KSW4gdGhpcyBleGFtcGxlLCB0aGUgZWZmZWN0IG9mIHRoZSB0cmVhdG1lbnQgdHlwZXMgaXMgb3VyIGZvY2FsIHZhcmlhYmxlLCB0aGF0IGlzIG91ciBwcmltYXJ5IGNvbmNlcm4uIEl0IGlzIHRob3VnaHQgdGhhdCB0aGUgZWZmZWN0IG9mIHRyZWF0bWVudHMgd2lsbCBkZXBlbmQgb24gdHdvIG90aGVyIGZhY3RvcnMsIOKAnGdlbmRlcuKAnSBhbmQg4oCccmlza+KAnSBsZXZlbCBvZiBtaWdyYWluZSwgd2hpY2ggYXJlIGNhbGxlZCBtb2RlcmF0b3IgdmFyaWFibGVzLg0KDQojIyBTdW1tYXJ5IHN0YXRpc3RpY3MNCkNvbXB1dGUgdGhlIG1lYW4gYW5kIHRoZSBzdGFuZGFyZCBkZXZpYXRpb24gKFNEKSBvZiBwYWluX3Njb3JlIGJ5IGdyb3VwczoNCmBgYHtyfQ0KaGVhZGFjaGUgJT4lDQogIGdyb3VwX2J5KGdlbmRlciwgcmlzaywgdHJlYXRtZW50KSAlPiUNCiAgZ2V0X3N1bW1hcnlfc3RhdHMocGFpbl9zY29yZSwgdHlwZSA9ICJtZWFuX3NkIikNCmBgYA0KDQojIyBWaXN1YWxpemF0aW9uDQpDcmVhdGUgYSBib3ggcGxvdCBvZiBwYWluX3Njb3JlIGJ5IHRyZWF0bWVudCwgY29sb3IgbGluZXMgYnkgcmlzayBncm91cHMgYW5kIGZhY2V0IHRoZSBwbG90IGJ5IGdlbmRlcjoNCmBgYHtyfQ0KYnhwIDwtIGdnYm94cGxvdCgNCiAgaGVhZGFjaGUsIHggPSAidHJlYXRtZW50IiwgeSA9ICJwYWluX3Njb3JlIiwgDQogIGNvbG9yID0gInJpc2siLCBwYWxldHRlID0gImpjbyIsIGZhY2V0LmJ5ID0gImdlbmRlciINCiAgKQ0KYnhwDQpgYGANCg0KIyMgQ2hlY2sgYXNzdW1wdGlvbnMNCklkZW50aWZ5IG91dGxpZXJzIGJ5IGdyb3VwczoNCmBgYHtyfQ0KaGVhZGFjaGUgJT4lDQogIGdyb3VwX2J5KGdlbmRlciwgcmlzaywgdHJlYXRtZW50KSAlPiUNCiAgaWRlbnRpZnlfb3V0bGllcnMocGFpbl9zY29yZSkNCmBgYA0KDQpJdCBjYW4gYmUgc2VlbiB0aGF0LCB0aGUgZGF0YSBjb250YWluIG9uZSBleHRyZW1lIG91dGxpZXIgKGlkID0gNTcsIGZlbWFsZSBhdCBoaWdoIHJpc2sgb2YgbWlncmFpbmUgdGFraW5nIGRydWcgWCkNCg0KIyMgTm9ybWFsaXR5IGFzc3VtcHRpb24NCkNoZWNrIG5vcm1hbGl0eSBhc3N1bXB0aW9uIGJ5IGFuYWx5emluZyB0aGUgbW9kZWwgcmVzaWR1YWxzLiBRUSBwbG90IGFuZCBTaGFwaXJvLVdpbGsgdGVzdCBvZiBub3JtYWxpdHkgYXJlIHVzZWQuDQoNCmBgYHtyfQ0KbW9kZWwgIDwtIGxtKHBhaW5fc2NvcmUgfiBnZW5kZXIqcmlzayp0cmVhdG1lbnQsIGRhdGEgPSBoZWFkYWNoZSkNCiMgQ3JlYXRlIGEgUVEgcGxvdCBvZiByZXNpZHVhbHMNCmdncXFwbG90KHJlc2lkdWFscyhtb2RlbCkpDQpgYGANCg0KYGBge3J9DQojIENvbXB1dGUgU2hhcGlyby1XaWxrIHRlc3Qgb2Ygbm9ybWFsaXR5DQpzaGFwaXJvX3Rlc3QocmVzaWR1YWxzKG1vZGVsKSkNCmBgYA0KDQpJbiB0aGUgUVEgcGxvdCwgYXMgYWxsIHRoZSBwb2ludHMgZmFsbCBhcHByb3hpbWF0ZWx5IGFsb25nIHRoZSByZWZlcmVuY2UgbGluZSwgd2UgY2FuIGFzc3VtZSBub3JtYWxpdHkuIFRoaXMgY29uY2x1c2lvbiBpcyBzdXBwb3J0ZWQgYnkgdGhlIFNoYXBpcm8tV2lsayB0ZXN0LiBUaGUgcC12YWx1ZSBpcyBub3Qgc2lnbmlmaWNhbnQgKHAgPSAwLjQpLCBzbyB3ZSBjYW4gYXNzdW1lIG5vcm1hbGl0eS4NCkNoZWNrIG5vcm1hbGl0eSBhc3N1bXB0aW9uIGJ5IGdyb3Vwcy4gQ29tcHV0aW5nIFNoYXBpcm8tV2lsayB0ZXN0IGZvciBlYWNoIGNvbWJpbmF0aW9ucyBvZiBmYWN0b3IgbGV2ZWxzLg0KDQpgYGB7cn0NCmhlYWRhY2hlICU+JQ0KICBncm91cF9ieShnZW5kZXIsIHJpc2ssIHRyZWF0bWVudCkgJT4lDQogIHNoYXBpcm9fdGVzdChwYWluX3Njb3JlKQ0KYGBgDQoNClRoZSBwYWluIHNjb3JlcyB3ZXJlIG5vcm1hbGx5IGRpc3RyaWJ1dGVkIChwID4gMC4wNSkgZXhjZXB0IGZvciBvbmUgZ3JvdXAgKGZlbWFsZSBhdCBoaWdoIHJpc2sgb2YgbWlncmFpbmUgdGFraW5nIGRydWcgWCwgcCA9IDAuMDA4NiksIGFzIGFzc2Vzc2VkIGJ5IFNoYXBpcm8tV2lsa+KAmXMgdGVzdCBvZiBub3JtYWxpdHkuDQoNCkNyZWF0ZSBRUSBwbG90IGZvciBlYWNoIGNlbGwgb2YgZGVzaWduOg0KYGBge3J9DQpnZ3FxcGxvdChoZWFkYWNoZSwgInBhaW5fc2NvcmUiLCBnZ3RoZW1lID0gdGhlbWVfYncoKSkgKw0KICBmYWNldF9ncmlkKGdlbmRlciArIHJpc2sgfiB0cmVhdG1lbnQsIGxhYmVsbGVyID0gImxhYmVsX2JvdGgiKQ0KYGBgDQoNCmFwcHJveGltYXRlbHkgYWxvbmcgdGhlIHJlZmVyZW5jZSBsaW5lLCBleGNlcHQgZm9yIG9uZSBncm91cCAoZmVtYWxlIGF0IGhpZ2ggcmlzayBvZiBtaWdyYWluZSB0YWtpbmcgZHJ1ZyBYKSwgd2hlcmUgd2UgYWxyZWFkeSBpZGVudGlmaWVkIGFuIGV4dHJlbWUgb3V0bGllci4NCg0KIyMgSG9tb2duZWl0eSBvZiB2YXJpYW5jZSBhc3N1bXB0aW9uDQpUaGlzIGNhbiBiZSBjaGVja2VkIHVzaW5nIHRoZSBMZXZlbmXigJlzIHRlc3Q6DQpgYGB7cn0NCmhlYWRhY2hlICU+JSBsZXZlbmVfdGVzdChwYWluX3Njb3JlIH4gZ2VuZGVyKnJpc2sqdHJlYXRtZW50KQ0KYGBgDQoNClRoZSBMZXZlbmXigJlzIHRlc3QgaXMgbm90IHNpZ25pZmljYW50IChwID4gMC4wNSkuIFRoZXJlZm9yZSwgd2UgY2FuIGFzc3VtZSB0aGUgaG9tb2dlbmVpdHkgb2YgdmFyaWFuY2VzIGluIHRoZSBkaWZmZXJlbnQgZ3JvdXBzLg0KDQojIyBDb21wdXRhdGlvbg0KYGBge3J9DQpyZXMuYW92IDwtIGhlYWRhY2hlICU+JSBhbm92YV90ZXN0KHBhaW5fc2NvcmUgfiBnZW5kZXIqcmlzayp0cmVhdG1lbnQpDQpgYGANCg0KYGBge3J9DQpyZXMuYW92DQpgYGANCg0KVGhlcmUgd2FzIGEgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCB0aHJlZS13YXkgaW50ZXJhY3Rpb24gYmV0d2VlbiBnZW5kZXIsIHJpc2sgYW5kIHRyZWF0bWVudCwgJEYoMiwgNjApID0gNy40MSQsICRwID0gMC4wMDEkLg0KDQojIyBQb3N0LWhvYyB0ZXN0cw0KSWYgdGhlcmUgaXMgYSBzaWduaWZpY2FudCB0aHJlZS13YXkgaW50ZXJhY3Rpb24gZWZmZWN0LCB5b3UgY2FuIGRlY29tcG9zZSBpdCBpbnRvOg0KDQpTaW1wbGUgdHdvLXdheSBpbnRlcmFjdGlvbjogcnVuIHR3by13YXkgaW50ZXJhY3Rpb24gYXQgZWFjaCBsZXZlbCBvZiB0aGlyZCB2YXJpYWJsZSwgU2ltcGxlIHNpbXBsZSBtYWluIGVmZmVjdDogcnVuIG9uZS13YXkgbW9kZWwgYXQgZWFjaCBsZXZlbCBvZiBzZWNvbmQgdmFyaWFibGUsIGFuZCAqU2ltcGxlIHNpbXBsZSBwYWlyd2lzZSBjb21wYXJpc29uczogcnVuIHBhaXJ3aXNlIG9yIG90aGVyIHBvc3QtaG9jIGNvbXBhcmlzb25zIGlmIG5lY2Vzc2FyeS4NCg0KSWYgeW91IGRvIG5vdCBoYXZlIGEgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCB0aHJlZS13YXkgaW50ZXJhY3Rpb24sIHlvdSBuZWVkIHRvIGRldGVybWluZSB3aGV0aGVyIHlvdSBoYXZlIGFueSBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50IHR3by13YXkgaW50ZXJhY3Rpb24gZnJvbSB0aGUgQU5PVkEgb3V0cHV0LiBZb3UgY2FuIGZvbGxvdyB1cCBhIHNpZ25pZmljYW50IHR3by13YXkgaW50ZXJhY3Rpb24gYnkgc2ltcGxlIG1haW4gZWZmZWN0cyBhbmFseXNlcyBhbmQgcGFpcndpc2UgY29tcGFyaXNvbnMgYmV0d2VlbiBncm91cHMgaWYgbmVjZXNzYXJ5Lg0KDQpJbiB0aGlzIHNlY3Rpb24gd2XigJlsbCBkZXNjcmliZSB0aGUgcHJvY2VkdXJlIGZvciBhIHNpZ25pZmljYW50IHRocmVlLXdheSBpbnRlcmFjdGlvbi4NCg0KIyMgQ29tcHV0ZSBzaW1wbGUgdHdvLXdheSBpbnRlcmFjdGlvbnMNCndlIGFyZSBmcmVlIHRvIGRlY2lkZSB3aGljaCB0d28gdmFyaWFibGVzIHdpbGwgZm9ybSB0aGUgc2ltcGxlIHR3by13YXkgaW50ZXJhY3Rpb25zIGFuZCB3aGljaCB2YXJpYWJsZSB3aWxsIGFjdCBhcyB0aGUgdGhpcmQgKG1vZGVyYXRvcikgdmFyaWFibGUuIEluIG91ciBleGFtcGxlLCB3ZSB3YW50IHRvIGV2YWx1YXRlIHRoZSBlZmZlY3Qgb2Ygcmlzayp0cmVhdG1lbnQgaW50ZXJhY3Rpb24gb24gcGFpbl9zY29yZSBhdCBlYWNoIGxldmVsIG9mIGdlbmRlci4NCg0KSW4gdGhlIFIgY29kZSBiZWxvdywgaeKAmWxsIGdyb3VwIHRoZSBkYXRhIGJ5IGdlbmRlciBhbmQgZml0IHRoZSB0cmVhdG1lbnQqcmlzayB0d28td2F5IGludGVyYWN0aW9uLiBUaGUgYXJndW1lbnQgZXJyb3IgaXMgdXNlZCB0byBzcGVjaWZ5IHRoZSB0aHJlZS13YXkgQU5PVkEgbW9kZWwgZnJvbSB3aGljaCB0aGUgcG9vbGVkIGVycm9yIHN1bSBvZiBzcXVhcmVzIGFuZCBkZWdyZWVzIG9mIGZyZWVkb20gYXJlIHRvIGJlIGNhbGN1bGF0ZWQuDQoNCmBgYHtyfQ0KIyBHcm91cCB0aGUgZGF0YSBieSBnZW5kZXIgYW5kIA0KIyBmaXQgc2ltcGxlIHR3by13YXkgaW50ZXJhY3Rpb24gDQptb2RlbCAgPC0gbG0ocGFpbl9zY29yZSB+IGdlbmRlcipyaXNrKnRyZWF0bWVudCwgZGF0YSA9IGhlYWRhY2hlKQ0KaGVhZGFjaGUgJT4lDQogIGdyb3VwX2J5KGdlbmRlcikgJT4lDQogIGFub3ZhX3Rlc3QocGFpbl9zY29yZSB+IHJpc2sqdHJlYXRtZW50LCBlcnJvciA9IG1vZGVsKQ0KYGBgDQoNClRoZXJlIHdhcyBhIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgc2ltcGxlIHR3by13YXkgaW50ZXJhY3Rpb24gYmV0d2VlbiByaXNrIGFuZCB0cmVhdG1lbnQgKHJpc2s6dHJlYXRtZW50KSBmb3IgbWFsZXMsIEYoMiwgNjApID0gNS4yNSwgcCA9IDAuMDA4LCBidXQgbm90IGZvciBmZW1hbGVzLCBGKDIsIDYwKSA9IDIuODcsIHAgPSAwLjA2NS4NCg0KRm9yIG1hbGVzLCB0aGlzIHJlc3VsdCBzdWdnZXN0cyB0aGF0IHRoZSBlZmZlY3Qgb2YgdHJlYXRtZW50IG9uIOKAnHBhaW5fc2NvcmXigJ0gZGVwZW5kcyBvbiBvbmXigJlzIOKAnHJpc2vigJ0gb2YgbWlncmFpbmUuIEluIG90aGVyIHdvcmRzLCB0aGUgcmlzayBtb2RlcmF0ZXMgdGhlIGVmZmVjdCBvZiB0aGUgdHlwZSBvZiB0cmVhdG1lbnQgb24gcGFpbl9zY29yZS4NCg0KIyMgQ29tcHV0ZSBzaW1wbGUgbWFpbiBlZmZlY3RzDQpBIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgc2ltcGxlIHR3by13YXkgaW50ZXJhY3Rpb24gY2FuIGJlIGZvbGxvd2VkIHVwIHdpdGggc2ltcGxlIHNpbXBsZSBtYWluIGVmZmVjdHMuIEluIG91ciBleGFtcGxlLCB5b3UgY291bGQgdGhlcmVmb3JlIGludmVzdGlnYXRlIHRoZSBlZmZlY3Qgb2YgdHJlYXRtZW50IG9uIHBhaW5fc2NvcmUgYXQgZXZlcnkgbGV2ZWwgb2YgcmlzayBvciBpbnZlc3RpZ2F0ZSB0aGUgZWZmZWN0IG9mIHJpc2sgYXQgZXZlcnkgbGV2ZWwgb2YgdHJlYXRtZW50LiBHcm91cCB0aGUgZGF0YSBieSBnZW5kZXIgYW5kIHJpc2sgYW5kIGFuYWx5emUgdGhlIHNpbXBsZSBzaW1wbGUgbWFpbiBlZmZlY3RzIG9mIHRyZWF0bWVudCBvbiBwYWluX3Njb3JlOg0KDQpgYGB7cn0NCiMgR3JvdXAgdGhlIGRhdGEgYnkgZ2VuZGVyIGFuZCByaXNrLCBhbmQgZml0ICBhbm92YQ0KdHJlYXRtZW50LmVmZmVjdCA8LSBoZWFkYWNoZSAlPiUNCiAgZ3JvdXBfYnkoZ2VuZGVyLCByaXNrKSAlPiUNCiAgYW5vdmFfdGVzdChwYWluX3Njb3JlIH4gdHJlYXRtZW50LCBlcnJvciA9IG1vZGVsKQ0KYGBgDQoNCmBgYHtyfQ0KdHJlYXRtZW50LmVmZmVjdCAlPiUgZmlsdGVyKGdlbmRlciA9PSAibWFsZSIpDQpgYGANCg0KVGhlcmUgd2FzIGEgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCBzaW1wbGUgc2ltcGxlIG1haW4gZWZmZWN0IG9mIHRyZWF0bWVudCBmb3IgbWFsZXMgYXQgaGlnaCByaXNrIG9mIG1pZ3JhaW5lLCAkRigyLCA2MCkgPSAxNC44JCwgJHAgPCAwLjAwMDEpJCwgYnV0IG5vdCBmb3IgbWFsZXMgYXQgbG93IHJpc2sgb2YgbWlncmFpbmUsICRGKDIsIDYwKSA9IDAuNjYkLCAkcCA9IDAuNTIxJC4NCg0KVGhpcyBhbmFseXNpcyBpbmRpY2F0ZXMgdGhhdCwgdGhlIHR5cGUgb2YgdHJlYXRtZW50IHRha2VuIGhhcyBhIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgZWZmZWN0IG9uIHBhaW5fc2NvcmUgaW4gbWFsZXMgd2hvIGFyZSBhdCBoaWdoIHJpc2suDQoNCkluIG90aGVyIHdvcmRzLCB0aGUgbWVhbiBwYWluX3Njb3JlIGluIHRoZSB0cmVhdG1lbnQgWCwgWSBhbmQgWiBncm91cHMgd2FzIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnRseSBkaWZmZXJlbnQgZm9yIG1hbGVzIHdobyBhdCBoaWdoIHJpc2ssIGJ1dCBub3QgZm9yIG1hbGVzIGF0IGxvdyByaXNrLg0KDQojIyBDb21wdXRlIHNpbXBsZSBzaW1wbGUgY29tcGFyaXNvbnMNCkEgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCBzaW1wbGUgc2ltcGxlIG1haW4gZWZmZWN0IGNhbiBiZSBmb2xsb3dlZCB1cCBieSBtdWx0aXBsZSBwYWlyd2lzZSBjb21wYXJpc29ucyB0byBkZXRlcm1pbmUgd2hpY2ggZ3JvdXAgbWVhbnMgYXJlIGRpZmZlcmVudC4gVGhpcyBjYW4gYmUgZWFzaWx5IGRvbmUgdXNpbmcgdGhlIGZ1bmN0aW9uIGVtbWVhbnNfdGVzdCgpIFtyc3RhdGl4IHBhY2thZ2VdIGRlc2NyaWJlZCBpbiB0aGUgcHJldmlvdXMgc2VjdGlvbi4NCg0KQ29tcGFyZSB0aGUgZGlmZmVyZW50IHRyZWF0bWVudHMgYnkgZ2VuZGVyIGFuZCByaXNrIHZhcmlhYmxlczoNCmBgYHtyfQ0KIyBQYWlyd2lzZSBjb21wYXJpc29ucw0KcHdjIDwtIGhlYWRhY2hlICU+JQ0KICBncm91cF9ieShnZW5kZXIsIHJpc2spICU+JQ0KICBlbW1lYW5zX3Rlc3QocGFpbl9zY29yZSB+IHRyZWF0bWVudCwgcC5hZGp1c3QubWV0aG9kID0gImJvbmZlcnJvbmkiKSAlPiUNCiAgc2VsZWN0KC1kZiwgLXN0YXRpc3RpYywgLXApICMgUmVtb3ZlIGRldGFpbHMNCiMgU2hvdyBjb21wYXJpc29uIHJlc3VsdHMgZm9yIG1hbGUgYXQgaGlnaCByaXNrDQpwd2MgJT4lIGZpbHRlcihnZW5kZXIgPT0gIm1hbGUiLCByaXNrID09ICJoaWdoIikNCmBgYA0KDQpgYGB7cn0NCiMgRXN0aW1hdGVkIG1hcmdpbmFsIG1lYW5zIChpLmUuIGFkanVzdGVkIG1lYW5zKSANCiMgd2l0aCA5NSUgY29uZmlkZW5jZSBpbnRlcnZhbA0KZ2V0X2VtbWVhbnMocHdjKSAlPiUgZmlsdGVyKGdlbmRlciA9PSAibWFsZSIsIHJpc2sgPT0gImhpZ2giKQ0KYGBgDQpJbiB0aGUgcGFpcndpc2UgY29tcGFyaXNvbnMgdGFibGUgYWJvdmUsIHdlIGFyZSBpbnRlcmVzdGVkIG9ubHkgaW4gdGhlIHNpbXBsZSBzaW1wbGUgY29tcGFyaXNvbnMgZm9yIG1hbGVzIGF0IGEgaGlnaCByaXNrIG9mIGEgbWlncmFpbmUgaGVhZGFjaGUuIEluIG91ciBleGFtcGxlLCB0aGVyZSBhcmUgdGhyZWUgcG9zc2libGUgY29tYmluYXRpb25zIG9mIGdyb3VwIGRpZmZlcmVuY2VzLg0KDQpGb3IgbWFsZSBhdCBoaWdoIHJpc2ssIHRoZXJlIHdhcyBhIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgbWVhbiBkaWZmZXJlbmNlIGJldHdlZW4gdHJlYXRtZW50IFggYW5kIHRyZWF0bWVudCBZIG9mICQxMC40JCAkKHAuYWRqIDwgMC4wMDEpJCwgYW5kIGJldHdlZW4gdHJlYXRtZW50IFggYW5kIHRyZWF0bWVudCBaIG9mICQxMy4xJCAkKHAuYWRqIDwgMC4wMDAxKSQuDQoNCkhvd2V2ZXIsIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gdHJlYXRtZW50IFkgYW5kIHRyZWF0bWVudCBaICQoMi42NikkIHdhcyBub3Qgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCwgJHAuYWRqID0gMC44OTckLg0KDQojIyBSZXBvcnQNCkEgdGhyZWUtd2F5IEFOT1ZBIHdhcyBjb25kdWN0ZWQgdG8gZGV0ZXJtaW5lIHRoZSBlZmZlY3RzIG9mIGdlbmRlciwgcmlzayBhbmQgdHJlYXRtZW50IG9uIG1pZ3JhaW5lIGhlYWRhY2hlIGVwaXNvZGUgcGFpbl9zY29yZS4NCg0KUmVzaWR1YWwgYW5hbHlzaXMgd2FzIHBlcmZvcm1lZCB0byB0ZXN0IGZvciB0aGUgYXNzdW1wdGlvbnMgb2YgdGhlIHRocmVlLXdheSBBTk9WQS4gTm9ybWFsaXR5IHdhcyBhc3Nlc3NlZCB1c2luZyBTaGFwaXJvLVdpbGvigJlzIG5vcm1hbGl0eSB0ZXN0IGFuZCBob21vZ2VuZWl0eSBvZiB2YXJpYW5jZXMgd2FzIGFzc2Vzc2VkIGJ5IExldmVuZeKAmXMgdGVzdC4NCg0KUmVzaWR1YWxzIHdlcmUgbm9ybWFsbHkgZGlzdHJpYnV0ZWQgKHAgPiAwLjA1KSBhbmQgdGhlcmUgd2FzIGhvbW9nZW5laXR5IG9mIHZhcmlhbmNlcyAocCA+IDAuMDUpLg0KDQpUaGVyZSB3YXMgYSBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50IHRocmVlLXdheSBpbnRlcmFjdGlvbiBiZXR3ZWVuIGdlbmRlciwgcmlzayBhbmQgdHJlYXRtZW50LCBGKDIsIDYwKSA9IDcuNDEsIHAgPSAwLjAwMS4NCg0KU3RhdGlzdGljYWwgc2lnbmlmaWNhbmNlIHdhcyBhY2NlcHRlZCBhdCB0aGUgcCA8IDAuMDI1IGxldmVsIGZvciBzaW1wbGUgdHdvLXdheSBpbnRlcmFjdGlvbnMgYW5kIHNpbXBsZSBzaW1wbGUgbWFpbiBlZmZlY3RzLiBUaGVyZSB3YXMgYSBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50IHNpbXBsZSB0d28td2F5IGludGVyYWN0aW9uIGJldHdlZW4gcmlzayBhbmQgdHJlYXRtZW50IGZvciBtYWxlcywgRigyLCA2MCkgPSA1LjIsIHAgPSAwLjAwOCwgYnV0IG5vdCBmb3IgZmVtYWxlcywgRigyLCA2MCkgPSAyLjgsIHAgPSAwLjA2NS4NCg0KVGhlcmUgd2FzIGEgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCBzaW1wbGUgc2ltcGxlIG1haW4gZWZmZWN0IG9mIHRyZWF0bWVudCBmb3IgbWFsZXMgYXQgaGlnaCByaXNrIG9mIG1pZ3JhaW5lLCBGKDIsIDYwKSA9IDE0LjgsIHAgPCAwLjAwMDEpLCBidXQgbm90IGZvciBtYWxlcyBhdCBsb3cgcmlzayBvZiBtaWdyYWluZSwgRigyLCA2MCkgPSAwLjY2LCBwID0gMC41MjEuDQoNCkFsbCBzaW1wbGUgc2ltcGxlIHBhaXJ3aXNlIGNvbXBhcmlzb25zLCBiZXR3ZWVuIHRoZSBkaWZmZXJlbnQgdHJlYXRtZW50IGdyb3Vwcywgd2VyZSBydW4gZm9yIG1hbGVzIGF0IGhpZ2ggcmlzayBvZiBtaWdyYWluZSB3aXRoIGEgQm9uZmVycm9uaSBhZGp1c3RtZW50IGFwcGxpZWQuDQoNClRoZXJlIHdhcyBhIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgbWVhbiBkaWZmZXJlbmNlIGJldHdlZW4gdHJlYXRtZW50IFggYW5kIHRyZWF0bWVudCBZLiBIb3dldmVyLCB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIHRyZWF0bWVudCBZIGFuZCB0cmVhdG1lbnQgWiwgd2FzIG5vdCBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50Lg0KDQpgYGB7cn0NCiMgVmlzdWFsaXphdGlvbjogYm94IHBsb3RzIHdpdGggcC12YWx1ZXMNCnB3YyA8LSBwd2MgJT4lIGFkZF94eV9wb3NpdGlvbih4ID0gInRyZWF0bWVudCIpDQpwd2MuZmlsdGVyZWQgPC0gcHdjICU+JSBmaWx0ZXIoZ2VuZGVyID09ICJtYWxlIiwgcmlzayA9PSAiaGlnaCIpDQpieHAgKw0KICBzdGF0X3B2YWx1ZV9tYW51YWwoDQogICAgcHdjLmZpbHRlcmVkLCBjb2xvciA9ICJyaXNrIiwgbGluZXR5cGUgPSAicmlzayIsIGhpZGUubnMgPSBUUlVFLA0KICAgIHRpcC5sZW5ndGggPSAwLCBzdGVwLmluY3JlYXNlID0gMC4xLCBzdGVwLmdyb3VwLmJ5ID0gImdlbmRlciINCiAgKSArDQogIGxhYnMoDQogICAgc3VidGl0bGUgPSBnZXRfdGVzdF9sYWJlbChyZXMuYW92LCBkZXRhaWxlZCA9IFRSVUUpLA0KICAgIGNhcHRpb24gPSBnZXRfcHdjX2xhYmVsKHB3YykNCiAgICApDQpgYGANCg0K