Problem with P-values

  • What gives mixed-effects models their ability to handle complex designs (e.g., nested, crossed, nested & crossed, partially nested and crossed) is in part what does not allow them to calculate p-values
  • Remember, \(t = \frac{M-\mu}{SE}\), where, \(SE = \sqrt\frac{\sigma^2}{n}\), \(df = n-1\)
  • GLM uses standard error to determine significance: Required degrees of freedom to correct z-distribution for “sampling error” to produce \(t\) and \(F\) tables.
  • But mixed models do not actually produce \(t\) or \(t^2=F\) values as they are not calculating the \(SE\) using the equation above, which uses observed - expected [mean square = \(\sigma^2 = \frac{SS}{N-1}\), where \(SS = (M-\mu)^2\)
  • Instead, they estimate the \(SE\) using ML or REML function
  • ML is a way of finding the value of one or more parameters in mixed model for a given statistic which makes the known likelihood distribution a maximum
    • likelihood is “a hypothetical probability that an event that has already occurred would yield a specific outcome” (http://mathworld.wolfram.com/Likelihood.html)
    • maximum is the largest value the function can produce
    • We will iterate through parameters until we maximize our likelihood
    • There are different ML (or just L) functions that can be used and they can apply to most distributions
  • Problem 1: SE is not the one used in \(t\) and \(F\) (it does not use N)
  • Problem 2: The estimate we get is not via OLS either, it’s via ML or REML (so what is the proper distribution to test against?)
  • Problem 3: What is our \(DF\) even if we want to assume \(t\) and \(F\)?

Problem 3: DF Conceptual Issues

  • Sample 500, 11the graders take the SAT from 3 schools partially nested in 2 economic districts

  • Random sampling of 500 total from 3 schools [Note: school 3 is twice as large school 1 and 2]
  • ANOVA Design: 1 factor: School OR district [they provide an unbalanced design so they can only be analyzed one at time]
  • Assume homogeneity of variance of SAT score across schools and districts
  • ANOVA can only ask 1 basic question: Are the means between the schools or districts different

ANOVA problem?

  • Why is ANOVA bad here?
    • School 1 is predominately poor vs School 2 which is rich, so school 1 has less funding, larger classrooms sizes, more social issues at home and in school, fewer teachers, etc.
  • This could impact both mean test scores and variance of test scores
    • Students from the poor district might have more diverse scores [high variance]
    • Student from rich district might have more similar scores, but higher average scores [low variance]
    • Poor students in the Rich school might also have changes in variance or mean test scores, which look very different from the poor or mixed school.

Mixed vs. ANOVA Solution

ANOVA Logic

  • If we assume ANOVA that would mean we calculate mean/variance relative to their classification based on school and district [at the level we are examining only]
  • In the case when all the variables are categorical, the DF “seems” logical, in that the proper MSerror terms could be calculated. However, in the mixed models, the random factors have been nested (kids in schools in districts).
    • So we cannot know how many of the people went into parsing the variance for each level of the random error term.
      • We could make assumptions, but some statisticians say over their dead bodies.
    • ANOVA is assumed to be robust against many violations, but that’s mostly only true in well-controlled balanced designs.
    • When ANOVA is stretched into the mixed model territory, it can result in unreasonable levels of type 1 error.

Mixed Logic

    1. Fixed factors: School and District [student belongs to]
    • SAT score MEANS could be different depending on the school a kid goes to and what district they are from.
    1. Random Factors: District, School, [Student]
    • SAT score VARIANCES could be different depending on the school a kid goes to and what district they are from.
    • So are the kids the DF, or the School or the district? What do with kids who are mismatched (poor but in richer schools or vice versa?)
    1. Random Slopes: The impact of SES could be different depending on the school a kid goes to and what district they are from,
    • In the rich school, the SES of the student might not matter as much as the poor or mixed school
      • When we add random slopes, how many measurements of the effect of SES are we making - is it based on the number of students, schools or districts?
  • Which level do we count the degrees of freedom for each fixed and random factor? Students, schools, or districts? How do we count DF for random factors?

Getting P-values

Path A: Don’t push your assumptions on me!

  1. Modeling Fitting testing
  • Likelihood ratio test [chi-square distribution]
  • D = 2 - ln (Likelihood of null model / Likelihood of alternative model]
  • Add/Remove fixed factors and test to see if model “fits the data better”
  • Suggested by Bates and Bolker [least assumptions]
  • FAST and well accepted [a bit anti-conservative some argue]
    • To do this you simply have to anova(model.1, model.2)
  1. Bootstrapping
  • Non-parametric: Re-sampling method where you resample with replacement from your own data
    • Common method in modern stats: A much better method then assuming normality and t-distributions
    • Example: You build your final model and you then take the subjects, resample them with replacement, and refit your model
      • You do this over and over again to build a distribution for each parameter in your model
        • You than calcuate the 95th percentile and see if contains zero, if not you have a significant effect
  • Semi-parametric: Adds noise to the Non-parametric (assumes your measurements are randomly sampled from all possible measurements)
    • So you sample from your data, add parametric noise, rinse and repeat like above
  • Parametric: You assume your data follows a specific distribution, you use your model to estimate the parameters, and then you simulate the study based on those parameters to estimate the CI. You than calcuate the 95th percentile and see if contains zero.
  • So far we can only do Semi-parametric & Parametric because of the random effects
    • However, Semi-parametric is not fully implemented yet
  • VERY, VERY SLOW.
  • This procedure can fail because your model is unstable (probably means your model is bad anyway)
  • You can also bootstrap Model fit testing (95th percentile method)

Path B: Let’s hold hands, put our fingers in our ears, and assume!

  1. Assume z distributions to get p-values
  • If you number of observations is high, just assume DF -> inf [so \(t > |2|\), is significant]
    • This is possible because you assume your random effects have controlled for the random variations in the populations and your values good estimates of the population
  • Simulation studies by Barr et al. 2013 show this to be a reasonable assumption IF and ONLY OF random structure is MAXIMAL
    • This is debated by Bates et al, 2015 and we will come back to this in a few weeks
  1. Estimate degrees of freedom
  • SAS/SPSS uses Satterthwaite approximations
    • However, there are also Kenward-Roger approximations [see Westfall, Kenny, & Judd, 2014]
    • Either is acceptable, but KR is recommended (but does not always work)
  • Makes a number of assumptions, will mirror results of traditional ANOVA fairly closely [as you would expect when you make similar assumptions about DF]
    • This method can also fail to work because your model is unstable/convergence problems

Path C: Go Bayesian

  • There use to be a way to get pvalues based on Markov-chain Monte-carlo methods (MCMC), but has been hard to implement in complex designs
    • Currently does not work for lme4 package we are using
  • You have to refit the model as Bayesian using rstanarm and get CIs
    • We will not do this (see Gelman & Hill textbook on Multilevel models for Bayesian approach)

Practical solution

  • Practically, when you add factors in stepwise and model fit shows a significant improvement (Path 1A) you will see the new factors has a t > 2. (Path 2A)
  • That does not always agree with bootstrapping (Path 1B) or ANOVA-like degrees of freedom (Path 2B)
    • This is because LME4 package we are using does not allow us to control for the heterogeneous variance problem. The older package LME will allow you control for it.
      • Note LME uses Satterthwaite approximations and will always give you DF and pvalues
    • Also, there could be other problems with your assumptions that bootstrapping is picking up on the other paths will not pick up
  • Recommendation: Based on current trends:
    1. Always do Path 1A to say the model is better
    2. To test the parameters add Path 1B, Path 2A or 2B.
      • I usually pick 1B or 2A
      • But some fields might demand DF, so you have to do 2B

Multi-Level Model Design Example

  • Same as Last Week Simulation (version 2)
  • Let’s examine our paths!

Design Reminder

  • You want to measure how students respond to a new type of active learning method (computer-based) in math class
  • You measure students math scores (DV) and the proportion of time (IV) they spend using the computer (which you assign)
  • You also measure how supportive (control and/or moderator) each student feels the teacher is about this new method.
    • Also, maybe if the students feel the teacher approves of the new method, they might engage with it more
  • You tell two the teachers that the active learning method works and the other two its experimental [Told level 2 variable]
  • You have access to different classrooms with 50 students per class

Simulation Details

  • Set the different slope of proportion of time (plus noise)
  • Different intercept per class (plus noise) [which will implicitly correlate with supportive]
  • Different slope per class on supportive (plus noise)
  • Set same interaction between proportion of time and supportive
  • Teachers in Classrooms 1 and 2 were Told the program works and 3 & 4 that it is experimental
  • [Note: I have not shown the simulation ‘echo=FALSE’ does not print it]

Plot our Clusters

  • Students nested in classrooms

  • Let’s center the data just as before, but layer fixed effects (keep random effects constant)

Path 1A & 2A

Null Model

library(plyr)
library(lme4)
MLM.Data.2$ActiveTime.GM<-scale(MLM.Data.2$ActiveTime,scale=F)
MLM.Data.2<-ddply(MLM.Data.2,.(Classroom), mutate, ClassSupport = mean(Support))
MLM.Data.2$Support.CC<-MLM.Data.2$Support-MLM.Data.2$ClassSupport

MLM.Model.1<-lmer(Math ~ 1+(1+Support.CC||Classroom),  
              data=MLM.Data.2, REML=FALSE)

Main effects

MLM.Model.2<-lmer(Math ~ ActiveTime.GM+Support.CC+(1+Support.CC||Classroom),  
              data=MLM.Data.2, REML=FALSE)

Interaction

MLM.Model.3<-lmer(Math ~ ActiveTime.GM*Support.CC+(1+Support.CC||Classroom),  
              data=MLM.Data.2, REML=FALSE)

Devience testing [Assume Chi-Square distrobution]

anova(MLM.Model.1,MLM.Model.2,MLM.Model.3)
## Data: MLM.Data.2
## Models:
## MLM.Model.1: Math ~ 1 + (1 + Support.CC || Classroom)
## MLM.Model.2: Math ~ ActiveTime.GM + Support.CC + (1 + Support.CC || Classroom)
## MLM.Model.3: Math ~ ActiveTime.GM * Support.CC + (1 + Support.CC || Classroom)
##             npar    AIC    BIC  logLik deviance   Chisq Df Pr(>Chisq)    
## MLM.Model.1    4 1241.5 1254.6 -616.72   1233.5                          
## MLM.Model.2    6 1112.3 1132.0 -550.13   1100.3 133.192  2  < 2.2e-16 ***
## MLM.Model.3    7 1096.8 1119.9 -541.42   1082.8  17.422  1  2.994e-05 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Deviance testing [Bootstrapped]

  • You only do this two at a time
  • You have to follow this syntax PBmodcomp(largeModel, smallModel, nsims)
    • LRT: Assuming that LRT has a chi-square distribution (what we did above)
    • PBtest: The fraction of simulated LRT-values that are larger or equal to the observed LRT value.
      • Conservative relative to LRT
  • SLLOOOWWWWWWW [you might want to reduce the sims when you run this on your laptops]
    • Yes the number of simulations make a difference (go for 1-2K when you publish just to be sure)
library(pbkrtest)
PBmodcomp(MLM.Model.2,MLM.Model.1,nsim=500)
## Bootstrap test; time: 10.08 sec; samples: 500; extremes: 0;
## large : Math ~ ActiveTime.GM + Support.CC + ((1 | Classroom) + (0 + Support.CC | 
##     Classroom))
## Math ~ 1 + ((1 | Classroom) + (0 + Support.CC | Classroom))
##          stat df   p.value    
## LRT    133.19  2 < 2.2e-16 ***
## PBtest 133.19     0.001996 ** 
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
PBmodcomp(MLM.Model.3,MLM.Model.2,nsim=500)
## Bootstrap test; time: 9.83 sec; samples: 500; extremes: 0;
## large : Math ~ ActiveTime.GM * Support.CC + ((1 | Classroom) + (0 + Support.CC | 
##     Classroom))
## Math ~ ActiveTime.GM + Support.CC + ((1 | Classroom) + (0 + Support.CC | 
##     Classroom))
##          stat df   p.value    
## LRT    17.422  1 2.994e-05 ***
## PBtest 17.422     0.001996 ** 
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Bootstrap Final Model

Parametric Version

  • Take bootstrap distribution and find percentiles (usually, .025 and .975)
Model.Final.CI.boot <- confint(MLM.Model.3, method="boot",nsim=500,boot.type = c("perc")) 
Model.Final.CI.boot
##                               2.5 %    97.5 %
## .sig01                    1.9481106 13.404665
## .sig02                    0.0000000  6.524522
## .sigma                    2.9991435  3.654218
## (Intercept)              64.7011766 82.241833
## ActiveTime.GM            10.0468297 13.219119
## Support.CC               -0.2783821  8.181753
## ActiveTime.GM:Support.CC  6.7860989 19.128069
  • Lets visualize the bootstrapping on the fixed effects
bfixed <- bootMer(MLM.Model.3, FUN=fixef,nsim=500)

library(ggplot2)
library(tidyr)
bfixed$t %>%
  data.frame()%>%
  gather()%>%
  ggplot(aes(value))+
  stat_density(alpha = 0.6, color = "black")+
  geom_vline(xintercept = 0, linetype = 2)+
  facet_wrap(~key, scales = "free")+
  theme_bw()

Path 2B

Satterthwaite Degrees of freedom

  • We need to refit out model using a new package
library(lmerTest)
MLM.Model.3.LTest<-lmerTest::lmer(Math ~ ActiveTime.GM*Support.CC+(1+Support.CC||Classroom),  
              data=MLM.Data.2, REML=FALSE)
summary(MLM.Model.3.LTest)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: Math ~ ActiveTime.GM * Support.CC + (1 + Support.CC || Classroom)
##    Data: MLM.Data.2
## 
##      AIC      BIC   logLik deviance df.resid 
##   1096.8   1119.9   -541.4   1082.8      193 
## 
## Scaled residuals: 
##      Min       1Q   Median       3Q      Max 
## -2.80667 -0.61518  0.09629  0.58731  3.15071 
## 
## Random effects:
##  Groups      Name        Variance Std.Dev.
##  Classroom   (Intercept) 76.44    8.743   
##  Classroom.1 Support.CC  14.87    3.857   
##  Residual                11.28    3.358   
## Number of obs: 200, groups:  Classroom, 4
## 
## Fixed effects:
##                          Estimate Std. Error      df t value Pr(>|t|)    
## (Intercept)                73.611      4.378   4.000  16.814 7.34e-05 ***
## ActiveTime.GM              11.579      0.812 193.715  14.260  < 2e-16 ***
## Support.CC                  3.836      2.104   3.838   1.823    0.145    
## ActiveTime.GM:Support.CC   12.770      2.982 192.911   4.283 2.90e-05 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) AcT.GM Spp.CC
## ActiveTm.GM  0.000              
## Support.CC   0.000  0.018       
## AcT.GM:S.CC  0.003 -0.022  0.022
  • Because Support.CC is random slope, we only have 4 schools, thus DF changes to match how many slopes we measured
  • If we want the model in ANOVA style format we can get that as well
library(lmerTest)
anova(MLM.Model.3.LTest)
## Type III Analysis of Variance Table with Satterthwaite's method
##                           Sum Sq Mean Sq NumDF   DenDF  F value    Pr(>F)    
## ActiveTime.GM            2293.12 2293.12     1 193.715 203.3439 < 2.2e-16 ***
## Support.CC                 37.49   37.49     1   3.838   3.3246    0.1453    
## ActiveTime.GM:Support.CC  206.89  206.89     1 192.911  18.3463 2.903e-05 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Notice DF changes

  • No random slopes
MLM.Model.4.LTest<-lmerTest::lmer(Math ~ ActiveTime.GM*Support.CC+(1|Classroom),  
              data=MLM.Data.2, REML=FALSE)
summary(MLM.Model.4.LTest)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: Math ~ ActiveTime.GM * Support.CC + (1 | Classroom)
##    Data: MLM.Data.2
## 
##      AIC      BIC   logLik deviance df.resid 
##   1105.8   1125.6   -546.9   1093.8      194 
## 
## Scaled residuals: 
##     Min      1Q  Median      3Q     Max 
## -3.0219 -0.5960  0.0471  0.5869  3.3549 
## 
## Random effects:
##  Groups    Name        Variance Std.Dev.
##  Classroom (Intercept) 76.64    8.755   
##  Residual              12.38    3.519   
## Number of obs: 200, groups:  Classroom, 4
## 
## Fixed effects:
##                          Estimate Std. Error       df t value Pr(>|t|)    
## (Intercept)               73.6058     4.3844   3.9996  16.788 7.38e-05 ***
## ActiveTime.GM             11.9604     0.8398 196.0048  14.243  < 2e-16 ***
## Support.CC                 4.0951     0.8725 195.9998   4.693 5.04e-06 ***
## ActiveTime.GM:Support.CC  11.5995     3.0999 196.0423   3.742  0.00024 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) AcT.GM Spp.CC
## ActiveTm.GM  0.000              
## Support.CC   0.000  0.053       
## AcT.GM:S.CC  0.003 -0.022  0.073
  • You will notice the degrees of freedom change

Kenward-Roger Degrees of freedom

  • These might be SLOW and might fail in large data sets
  • Must be fit with REML
library(pbkrtest)

MLM.Model.3.LTest.REML<-lmerTest::lmer(Math ~ ActiveTime.GM*Support.CC+(1+Support.CC||Classroom),  
              data=MLM.Data.2, REML=TRUE)
summary(MLM.Model.3.LTest.REML, ddf="Kenward-Roger")
## Linear mixed model fit by REML. t-tests use Kenward-Roger's method [
## lmerModLmerTest]
## Formula: Math ~ ActiveTime.GM * Support.CC + (1 + Support.CC || Classroom)
##    Data: MLM.Data.2
## 
## REML criterion at convergence: 1069
## 
## Scaled residuals: 
##      Min       1Q   Median       3Q      Max 
## -2.80023 -0.60826  0.09906  0.58608  3.11201 
## 
## Random effects:
##  Groups      Name        Variance Std.Dev.
##  Classroom   (Intercept) 101.99   10.099  
##  Classroom.1 Support.CC   21.03    4.586  
##  Residual                 11.39    3.375  
## Number of obs: 200, groups:  Classroom, 4
## 
## Fixed effects:
##                          Estimate Std. Error      df t value Pr(>|t|)    
## (Intercept)                73.612      5.055   3.000  14.562 0.000702 ***
## ActiveTime.GM              11.558      0.819 191.349  14.113  < 2e-16 ***
## Support.CC                  3.823      2.445   2.990   1.564 0.216108    
## ActiveTime.GM:Support.CC   12.817      3.002 190.767   4.269 3.09e-05 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) AcT.GM Spp.CC
## ActiveTm.GM  0.000              
## Support.CC   0.000  0.015       
## AcT.GM:S.CC  0.003 -0.022  0.019

Practical Issues

  • The effects package will generate CIs for mixed models, but will approximate them as below:
Model.Final.CI.Wald <- confint(MLM.Model.3, method="Wald") 
  • You can force the effects package to do them as KR, buts its slow (and you’re probably cannot see the difference anyway)
  • Visualizing the bootstrapped ones is difficult and takes a fair bit of code work
    • I will try to find a function that does this, but so far no luck
  • I usually just graph the effects version and either show SE or CI
    • There is not a perfect solution, but the point is just to give your reader some idea of the error
    • These may not always match your “significance” and this will be a bigger problem later when we have repeated designs
LS0tDQp0aXRsZTogJ0RlZ3JlZXMgb2YgRnJlZWRvbSBhbmQgUHZhbHVlcycNCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDoNCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMNCiAgICBmb250c2l6ZTogOHB0DQogICAgaGlnaGxpZ2h0OiB0ZXh0bWF0ZQ0KICAgIG51bWJlcl9zZWN0aW9uczogbm8NCiAgICB0aGVtZTogZmxhdGx5DQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZmxvYXQ6DQogICAgICBjb2xsYXBzZWQ6IG5vDQotLS0NCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoY2FjaGU9VFJVRSkNCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkNCmtuaXRyOjpvcHRzX2NodW5rJHNldChtZXNzYWdlID0gRkFMU0UpDQprbml0cjo6b3B0c19jaHVuayRzZXQod2FybmluZyA9ICBGQUxTRSkNCmtuaXRyOjpvcHRzX2NodW5rJHNldChmaWcud2lkdGg9NC4yNSkNCmtuaXRyOjpvcHRzX2NodW5rJHNldChmaWcuaGVpZ2h0PTQuMCkNCmtuaXRyOjpvcHRzX2NodW5rJHNldChmaWcuYWxpZ249J2NlbnRlcicpIA0KYGBgDQoNCg0KIyBQcm9ibGVtIHdpdGggUC12YWx1ZXMNCi0gV2hhdCBnaXZlcyBtaXhlZC1lZmZlY3RzIG1vZGVscyB0aGVpciBhYmlsaXR5IHRvIGhhbmRsZSBjb21wbGV4IGRlc2lnbnMgKGUuZy4sIG5lc3RlZCwgY3Jvc3NlZCwgbmVzdGVkICYgY3Jvc3NlZCwgcGFydGlhbGx5IG5lc3RlZCBhbmQgY3Jvc3NlZCkgaXMgaW4gcGFydCB3aGF0IGRvZXMgbm90IGFsbG93IHRoZW0gdG8gY2FsY3VsYXRlIHAtdmFsdWVzDQotIFJlbWVtYmVyLCAkdCA9IFxmcmFje00tXG11fXtTRX0kLCB3aGVyZSwgJFNFID0gXHNxcnRcZnJhY3tcc2lnbWFeMn17bn0kLCAkZGYgPSBuLTEkDQotIEdMTSB1c2VzIHN0YW5kYXJkIGVycm9yIHRvIGRldGVybWluZSBzaWduaWZpY2FuY2U6IFJlcXVpcmVkIGRlZ3JlZXMgb2YgZnJlZWRvbSB0byBjb3JyZWN0IHotZGlzdHJpYnV0aW9uIGZvciAic2FtcGxpbmcgZXJyb3IiIHRvIHByb2R1Y2UgJHQkIGFuZCAkRiQgdGFibGVzLiAgDQotIEJ1dCBtaXhlZCBtb2RlbHMgZG8gbm90IGFjdHVhbGx5IHByb2R1Y2UgJHQkIG9yICR0XjI9RiQgdmFsdWVzIGFzIHRoZXkgYXJlIG5vdCBjYWxjdWxhdGluZyB0aGUgJFNFJCB1c2luZyB0aGUgZXF1YXRpb24gYWJvdmUsIHdoaWNoIHVzZXMgb2JzZXJ2ZWQgLSBleHBlY3RlZCBbbWVhbiBzcXVhcmUgPSAkXHNpZ21hXjIgPSBcZnJhY3tTU317Ti0xfSQsIHdoZXJlICRTUyA9IChNLVxtdSleMiQNCi0gSW5zdGVhZCwgdGhleSBlc3RpbWF0ZSB0aGUgJFNFJCB1c2luZyBNTCBvciBSRU1MIGZ1bmN0aW9uDQotIE1MIGlzIGEgd2F5IG9mIGZpbmRpbmcgdGhlIHZhbHVlIG9mIG9uZSBvciBtb3JlIHBhcmFtZXRlcnMgaW4gbWl4ZWQgbW9kZWwgZm9yIGEgZ2l2ZW4gc3RhdGlzdGljIHdoaWNoIG1ha2VzIHRoZSBrbm93biAqbGlrZWxpaG9vZCogZGlzdHJpYnV0aW9uIGEgKm1heGltdW0qDQogICAgLSAqbGlrZWxpaG9vZCogaXMgImEgaHlwb3RoZXRpY2FsIHByb2JhYmlsaXR5IHRoYXQgYW4gZXZlbnQgdGhhdCBoYXMgKiphbHJlYWR5Kiogb2NjdXJyZWQgd291bGQgeWllbGQgYSBzcGVjaWZpYyBvdXRjb21lIiAoaHR0cDovL21hdGh3b3JsZC53b2xmcmFtLmNvbS9MaWtlbGlob29kLmh0bWwpDQogICAgLSAqbWF4aW11bSogaXMgdGhlIGxhcmdlc3QgdmFsdWUgdGhlIGZ1bmN0aW9uIGNhbiBwcm9kdWNlDQogICAgLSBXZSB3aWxsIGl0ZXJhdGUgdGhyb3VnaCBwYXJhbWV0ZXJzIHVudGlsIHdlIG1heGltaXplIG91ciBsaWtlbGlob29kDQogICAgLSBUaGVyZSBhcmUgZGlmZmVyZW50IE1MIChvciBqdXN0IEwpIGZ1bmN0aW9ucyB0aGF0IGNhbiBiZSB1c2VkIGFuZCB0aGV5IGNhbiBhcHBseSB0byBtb3N0IGRpc3RyaWJ1dGlvbnMNCi0gKipQcm9ibGVtIDE6KiogU0UgaXMgbm90IHRoZSBvbmUgdXNlZCBpbiAkdCQgYW5kICRGJCAoaXQgZG9lcyBub3QgdXNlIE4pDQotICoqUHJvYmxlbSAyOioqIFRoZSBlc3RpbWF0ZSB3ZSBnZXQgaXMgbm90IHZpYSBPTFMgZWl0aGVyLCBpdCdzIHZpYSBNTCBvciBSRU1MIChzbyB3aGF0IGlzIHRoZSBwcm9wZXIgZGlzdHJpYnV0aW9uIHRvIHRlc3QgYWdhaW5zdD8pDQotICoqUHJvYmxlbSAzOioqIFdoYXQgaXMgb3VyICRERiQgZXZlbiBpZiB3ZSB3YW50IHRvIGFzc3VtZSAkdCQgYW5kICRGJD8NCg0KIyMgUHJvYmxlbSAzOiBERiBDb25jZXB0dWFsIElzc3Vlcw0KLSBTYW1wbGUgNTAwLCAxMXRoZSBncmFkZXJzIHRha2UgdGhlIFNBVCBmcm9tIDMgc2Nob29scyBwYXJ0aWFsbHkgbmVzdGVkIGluIDIgZWNvbm9taWMgZGlzdHJpY3RzICANCg0KYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0LndpZHRoID0gIjMwMHB4In0NCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJNaXhlZC9WZW5uU2Nob29scy5qcGciKQ0KYGBgDQoNCg0KLSBSYW5kb20gc2FtcGxpbmcgb2YgNTAwIHRvdGFsIGZyb20gMyBzY2hvb2xzIFtOb3RlOiBzY2hvb2wgMyBpcyB0d2ljZSBhcyBsYXJnZSBzY2hvb2wgMSBhbmQgMl0gDQotIEFOT1ZBIERlc2lnbjogMSBmYWN0b3I6IFNjaG9vbCBPUiBkaXN0cmljdCBbdGhleSBwcm92aWRlIGFuIHVuYmFsYW5jZWQgZGVzaWduIHNvIHRoZXkgY2FuIG9ubHkgYmUgYW5hbHl6ZWQgb25lIGF0IHRpbWVdDQotIEFzc3VtZSBob21vZ2VuZWl0eSBvZiB2YXJpYW5jZSBvZiBTQVQgc2NvcmUgYWNyb3NzIHNjaG9vbHMgYW5kIGRpc3RyaWN0cw0KLSBBTk9WQSBjYW4gb25seSBhc2sgMSBiYXNpYyBxdWVzdGlvbjogQXJlIHRoZSBtZWFucyBiZXR3ZWVuIHRoZSBzY2hvb2xzIG9yIGRpc3RyaWN0cyBkaWZmZXJlbnQNCg0KIyMjIEFOT1ZBIHByb2JsZW0/DQotIFdoeSBpcyBBTk9WQSBiYWQgaGVyZT8gDQogICAgLSBTY2hvb2wgMSBpcyBwcmVkb21pbmF0ZWx5IHBvb3IgdnMgU2Nob29sIDIgd2hpY2ggaXMgcmljaCwgc28gc2Nob29sIDEgaGFzIGxlc3MgZnVuZGluZywgbGFyZ2VyIGNsYXNzcm9vbXMgc2l6ZXMsIG1vcmUgc29jaWFsIGlzc3VlcyBhdCBob21lIGFuZCBpbiBzY2hvb2wsIGZld2VyIHRlYWNoZXJzLCBldGMuIA0KLSBUaGlzIGNvdWxkIGltcGFjdCBib3RoIG1lYW4gdGVzdCBzY29yZXMgYW5kIHZhcmlhbmNlIG9mIHRlc3Qgc2NvcmVzICANCiAgICAtIFN0dWRlbnRzIGZyb20gdGhlIHBvb3IgZGlzdHJpY3QgbWlnaHQgaGF2ZSBtb3JlIGRpdmVyc2Ugc2NvcmVzIFtoaWdoIHZhcmlhbmNlXQ0KICAgIC0gU3R1ZGVudCBmcm9tIHJpY2ggZGlzdHJpY3QgbWlnaHQgaGF2ZSBtb3JlIHNpbWlsYXIgc2NvcmVzLCBidXQgaGlnaGVyIGF2ZXJhZ2Ugc2NvcmVzIFtsb3cgdmFyaWFuY2VdDQogICAgLSBQb29yIHN0dWRlbnRzIGluIHRoZSBSaWNoIHNjaG9vbCBtaWdodCBhbHNvIGhhdmUgY2hhbmdlcyBpbiB2YXJpYW5jZSBvciBtZWFuIHRlc3Qgc2NvcmVzLCB3aGljaCBsb29rIHZlcnkgZGlmZmVyZW50IGZyb20gdGhlIHBvb3Igb3IgbWl4ZWQgc2Nob29sLiAgDQoNCiMjIyBNaXhlZCB2cy4gQU5PVkEgU29sdXRpb24NCg0KIyMjIyBBTk9WQSBMb2dpYw0KDQotIElmIHdlIGFzc3VtZSBBTk9WQSB0aGF0IHdvdWxkIG1lYW4gd2UgY2FsY3VsYXRlIG1lYW4vdmFyaWFuY2UgcmVsYXRpdmUgdG8gdGhlaXIgY2xhc3NpZmljYXRpb24gYmFzZWQgb24gc2Nob29sIGFuZCBkaXN0cmljdCBbYXQgdGhlIGxldmVsIHdlIGFyZSBleGFtaW5pbmcgb25seV0gDQotIEluIHRoZSBjYXNlIHdoZW4gYWxsIHRoZSB2YXJpYWJsZXMgYXJlIGNhdGVnb3JpY2FsLCB0aGUgREYgInNlZW1zIiBsb2dpY2FsLCBpbiB0aGF0IHRoZSBwcm9wZXIgTVNlcnJvciB0ZXJtcyBjb3VsZCBiZSBjYWxjdWxhdGVkLiBIb3dldmVyLCBpbiB0aGUgbWl4ZWQgbW9kZWxzLCB0aGUgcmFuZG9tIGZhY3RvcnMgaGF2ZSBiZWVuIG5lc3RlZCAoa2lkcyBpbiBzY2hvb2xzIGluIGRpc3RyaWN0cykuIA0KICAgIC0gU28gd2UgY2Fubm90IGtub3cgaG93IG1hbnkgb2YgdGhlIHBlb3BsZSB3ZW50IGludG8gcGFyc2luZyB0aGUgdmFyaWFuY2UgZm9yIGVhY2ggbGV2ZWwgb2YgdGhlIHJhbmRvbSBlcnJvciB0ZXJtLiAgDQogICAgICAgIC0gV2UgY291bGQgbWFrZSBhc3N1bXB0aW9ucywgYnV0IHNvbWUgc3RhdGlzdGljaWFucyBzYXkgb3ZlciB0aGVpciBkZWFkIGJvZGllcy4gDQogICAgLSBBTk9WQSBpcyBhc3N1bWVkIHRvIGJlIHJvYnVzdCBhZ2FpbnN0IG1hbnkgdmlvbGF0aW9ucywgYnV0IHRoYXQncyBtb3N0bHkgb25seSB0cnVlIGluIHdlbGwtY29udHJvbGxlZCBiYWxhbmNlZCBkZXNpZ25zLg0KICAgIC0gV2hlbiBBTk9WQSBpcyBzdHJldGNoZWQgaW50byB0aGUgbWl4ZWQgbW9kZWwgdGVycml0b3J5LCBpdCBjYW4gcmVzdWx0IGluIHVucmVhc29uYWJsZSBsZXZlbHMgb2YgdHlwZSAxIGVycm9yLiAgDQogICAgDQojIyMjIE1peGVkIExvZ2ljDQoNCi0gMS4gRml4ZWQgZmFjdG9yczogIFNjaG9vbCBhbmQgRGlzdHJpY3QgW3N0dWRlbnQgYmVsb25ncyB0b10NCiAgICAtIFNBVCBzY29yZSBNRUFOUyBjb3VsZCBiZSBkaWZmZXJlbnQgZGVwZW5kaW5nIG9uIHRoZSBzY2hvb2wgYSBraWQgZ29lcyB0byBhbmQgd2hhdCBkaXN0cmljdCB0aGV5IGFyZSBmcm9tLiAgIA0KLSAyLiBSYW5kb20gRmFjdG9yczogIERpc3RyaWN0LCBTY2hvb2wsIFtTdHVkZW50XQ0KICAgIC0gU0FUIHNjb3JlIFZBUklBTkNFUyBjb3VsZCBiZSBkaWZmZXJlbnQgZGVwZW5kaW5nIG9uIHRoZSBzY2hvb2wgYSBraWQgZ29lcyB0byBhbmQgd2hhdCBkaXN0cmljdCB0aGV5IGFyZSBmcm9tLiAgIA0KICAgIC0gU28gYXJlIHRoZSBraWRzIHRoZSBERiwgb3IgdGhlIFNjaG9vbCBvciB0aGUgZGlzdHJpY3Q/IFdoYXQgZG8gd2l0aCBraWRzIHdobyBhcmUgbWlzbWF0Y2hlZCAocG9vciBidXQgaW4gcmljaGVyIHNjaG9vbHMgb3IgdmljZSB2ZXJzYT8pDQotIDMuIFJhbmRvbSBTbG9wZXM6IFRoZSBpbXBhY3Qgb2YgU0VTIGNvdWxkIGJlIGRpZmZlcmVudCBkZXBlbmRpbmcgb24gdGhlIHNjaG9vbCBhIGtpZCBnb2VzIHRvIGFuZCB3aGF0IGRpc3RyaWN0IHRoZXkgYXJlIGZyb20sDQogICAgLSBJbiB0aGUgcmljaCBzY2hvb2wsIHRoZSBTRVMgb2YgdGhlIHN0dWRlbnQgbWlnaHQgbm90IG1hdHRlciBhcyBtdWNoIGFzIHRoZSBwb29yIG9yIG1peGVkIHNjaG9vbCANCiAgICAgICAgLSBXaGVuIHdlIGFkZCByYW5kb20gc2xvcGVzLCBob3cgbWFueSBtZWFzdXJlbWVudHMgb2YgdGhlIGVmZmVjdCBvZiBTRVMgYXJlIHdlIG1ha2luZyAtIGlzIGl0IGJhc2VkIG9uIHRoZSBudW1iZXIgb2Ygc3R1ZGVudHMsIHNjaG9vbHMgb3IgZGlzdHJpY3RzPw0KLSBXaGljaCBsZXZlbCBkbyB3ZSBjb3VudCB0aGUgZGVncmVlcyBvZiBmcmVlZG9tIGZvciBlYWNoIGZpeGVkIGFuZCByYW5kb20gZmFjdG9yPyBTdHVkZW50cywgc2Nob29scywgb3IgZGlzdHJpY3RzPyBIb3cgZG8gd2UgY291bnQgREYgZm9yIHJhbmRvbSBmYWN0b3JzPyAgDQoNCiMgR2V0dGluZyBQLXZhbHVlcw0KIyMgUGF0aCBBOiBEb24ndCBwdXNoIHlvdXIgYXNzdW1wdGlvbnMgb24gbWUhDQoNCjEuICBNb2RlbGluZyBGaXR0aW5nIHRlc3RpbmcgDQotIExpa2VsaWhvb2QgcmF0aW8gdGVzdCBbY2hpLXNxdWFyZSBkaXN0cmlidXRpb25dDQotIEQgPSAyIC0gbG4gKExpa2VsaWhvb2Qgb2YgbnVsbCBtb2RlbCAvIExpa2VsaWhvb2Qgb2YgYWx0ZXJuYXRpdmUgbW9kZWxdIA0KLSBBZGQvUmVtb3ZlIGZpeGVkIGZhY3RvcnMgYW5kIHRlc3QgdG8gc2VlIGlmIG1vZGVsICJmaXRzIHRoZSBkYXRhIGJldHRlciIgDQotIFN1Z2dlc3RlZCBieSBCYXRlcyBhbmQgQm9sa2VyIFtsZWFzdCBhc3N1bXB0aW9uc10NCi0gRkFTVCBhbmQgd2VsbCBhY2NlcHRlZCBbYSBiaXQgYW50aS1jb25zZXJ2YXRpdmUgc29tZSBhcmd1ZV0NCiAgICAtIFRvIGRvIHRoaXMgeW91IHNpbXBseSBoYXZlIHRvIGBhbm92YShtb2RlbC4xLCBtb2RlbC4yKWANCg0KMi4gQm9vdHN0cmFwcGluZyANCi0gTm9uLXBhcmFtZXRyaWM6IFJlLXNhbXBsaW5nIG1ldGhvZCB3aGVyZSB5b3UgcmVzYW1wbGUgd2l0aCByZXBsYWNlbWVudCBmcm9tIHlvdXIgb3duIGRhdGEgICAgIA0KICAgIC0gQ29tbW9uIG1ldGhvZCBpbiBtb2Rlcm4gc3RhdHM6IEEgbXVjaCBiZXR0ZXIgbWV0aG9kIHRoZW4gYXNzdW1pbmcgbm9ybWFsaXR5IGFuZCB0LWRpc3RyaWJ1dGlvbnMgDQogICAgLSBFeGFtcGxlOiBZb3UgYnVpbGQgeW91ciBmaW5hbCBtb2RlbCBhbmQgeW91IHRoZW4gdGFrZSB0aGUgc3ViamVjdHMsIHJlc2FtcGxlIHRoZW0gd2l0aCByZXBsYWNlbWVudCwgYW5kIHJlZml0IHlvdXIgbW9kZWwNCiAgICAgICAgLSBZb3UgZG8gdGhpcyBvdmVyIGFuZCBvdmVyIGFnYWluIHRvIGJ1aWxkIGEgZGlzdHJpYnV0aW9uIGZvciBlYWNoIHBhcmFtZXRlciBpbiB5b3VyIG1vZGVsDQogICAgICAgICAgICAtIFlvdSB0aGFuIGNhbGN1YXRlIHRoZSA5NXRoIHBlcmNlbnRpbGUgYW5kIHNlZSBpZiBjb250YWlucyB6ZXJvLCBpZiBub3QgeW91IGhhdmUgYSAqc2lnbmlmaWNhbnQqIGVmZmVjdCANCi0gU2VtaS1wYXJhbWV0cmljOiBBZGRzIG5vaXNlIHRvIHRoZSBOb24tcGFyYW1ldHJpYyAoYXNzdW1lcyB5b3VyIG1lYXN1cmVtZW50cyBhcmUgcmFuZG9tbHkgc2FtcGxlZCBmcm9tIGFsbCBwb3NzaWJsZSBtZWFzdXJlbWVudHMpDQogICAgLSBTbyB5b3Ugc2FtcGxlIGZyb20geW91ciBkYXRhLCBhZGQgcGFyYW1ldHJpYyBub2lzZSwgcmluc2UgYW5kIHJlcGVhdCBsaWtlIGFib3ZlDQotIFBhcmFtZXRyaWM6IFlvdSBhc3N1bWUgeW91ciBkYXRhIGZvbGxvd3MgYSBzcGVjaWZpYyBkaXN0cmlidXRpb24sIHlvdSB1c2UgeW91ciBtb2RlbCB0byBlc3RpbWF0ZSB0aGUgcGFyYW1ldGVycywgYW5kIHRoZW4geW91IHNpbXVsYXRlIHRoZSBzdHVkeSBiYXNlZCBvbiB0aG9zZSBwYXJhbWV0ZXJzIHRvIGVzdGltYXRlIHRoZSBDSS4gWW91IHRoYW4gY2FsY3VhdGUgdGhlIDk1dGggcGVyY2VudGlsZSBhbmQgc2VlIGlmIGNvbnRhaW5zIHplcm8uDQotIFNvIGZhciB3ZSBjYW4gb25seSBkbyBTZW1pLXBhcmFtZXRyaWMgJiBQYXJhbWV0cmljIGJlY2F1c2Ugb2YgdGhlIHJhbmRvbSBlZmZlY3RzDQogICAgLSBIb3dldmVyLCAgU2VtaS1wYXJhbWV0cmljIGlzIG5vdCBmdWxseSBpbXBsZW1lbnRlZCB5ZXQgDQotIFZFUlksIFZFUlkgU0xPVy4NCi0gVGhpcyBwcm9jZWR1cmUgY2FuIGZhaWwgYmVjYXVzZSB5b3VyIG1vZGVsIGlzIHVuc3RhYmxlIChwcm9iYWJseSBtZWFucyB5b3VyIG1vZGVsIGlzIGJhZCBhbnl3YXkpDQotIFlvdSBjYW4gYWxzbyBib290c3RyYXAgTW9kZWwgZml0IHRlc3RpbmcgKDk1dGggcGVyY2VudGlsZSBtZXRob2QpDQoNCg0KDQojIyBQYXRoIEI6ICBMZXQncyBob2xkIGhhbmRzLCBwdXQgb3VyIGZpbmdlcnMgaW4gb3VyIGVhcnMsIGFuZCBhc3N1bWUhIA0KDQozLiBBc3N1bWUgeiBkaXN0cmlidXRpb25zIHRvIGdldCBwLXZhbHVlcw0KLSBJZiB5b3UgbnVtYmVyIG9mIG9ic2VydmF0aW9ucyBpcyBoaWdoLCBqdXN0IGFzc3VtZSBERiAtPiBpbmYgW3NvICR0ID4gfDJ8JCwgaXMgc2lnbmlmaWNhbnRdDQogICAgLSBUaGlzIGlzIHBvc3NpYmxlIGJlY2F1c2UgeW91IGFzc3VtZSB5b3VyIHJhbmRvbSBlZmZlY3RzIGhhdmUgY29udHJvbGxlZCBmb3IgdGhlIHJhbmRvbSB2YXJpYXRpb25zIGluIHRoZSBwb3B1bGF0aW9ucyBhbmQgeW91ciB2YWx1ZXMgZ29vZCBlc3RpbWF0ZXMgb2YgdGhlIHBvcHVsYXRpb24NCi0gU2ltdWxhdGlvbiBzdHVkaWVzIGJ5IEJhcnIgZXQgYWwuIDIwMTMgc2hvdyB0aGlzIHRvIGJlIGEgcmVhc29uYWJsZSBhc3N1bXB0aW9uIElGIGFuZCBPTkxZIE9GIHJhbmRvbSBzdHJ1Y3R1cmUgaXMgTUFYSU1BTA0KICAgIC0gVGhpcyBpcyBkZWJhdGVkIGJ5IEJhdGVzIGV0IGFsLCAyMDE1IGFuZCB3ZSB3aWxsIGNvbWUgYmFjayB0byB0aGlzIGluIGEgZmV3IHdlZWtzDQoNCg0KNC4gRXN0aW1hdGUgZGVncmVlcyBvZiBmcmVlZG9tDQotIFNBUy9TUFNTIHVzZXMgU2F0dGVydGh3YWl0ZSBhcHByb3hpbWF0aW9ucyANCiAgICAtIEhvd2V2ZXIsIHRoZXJlIGFyZSBhbHNvIEtlbndhcmQtUm9nZXIgYXBwcm94aW1hdGlvbnMgW3NlZSBXZXN0ZmFsbCwgS2VubnksICYgSnVkZCwgMjAxNF0NCiAgICAtIEVpdGhlciBpcyBhY2NlcHRhYmxlLCBidXQgS1IgaXMgcmVjb21tZW5kZWQgKGJ1dCBkb2VzIG5vdCBhbHdheXMgd29yaykgDQotIE1ha2VzIGEgbnVtYmVyIG9mIGFzc3VtcHRpb25zLCB3aWxsIG1pcnJvciByZXN1bHRzIG9mIHRyYWRpdGlvbmFsIEFOT1ZBIGZhaXJseSBjbG9zZWx5IFthcyB5b3Ugd291bGQgZXhwZWN0IHdoZW4geW91IG1ha2Ugc2ltaWxhciBhc3N1bXB0aW9ucyBhYm91dCBERl0NCiAgICAtIFRoaXMgbWV0aG9kIGNhbiBhbHNvIGZhaWwgdG8gd29yayBiZWNhdXNlIHlvdXIgbW9kZWwgaXMgdW5zdGFibGUvY29udmVyZ2VuY2UgcHJvYmxlbXMNCg0KIyMgUGF0aCBDOiBHbyBCYXllc2lhbg0KLSBUaGVyZSB1c2UgdG8gYmUgYSB3YXkgdG8gZ2V0IHB2YWx1ZXMgYmFzZWQgb24gTWFya292LWNoYWluIE1vbnRlLWNhcmxvIG1ldGhvZHMgKE1DTUMpLCBidXQgaGFzIGJlZW4gaGFyZCB0byBpbXBsZW1lbnQgaW4gY29tcGxleCBkZXNpZ25zDQogICAgLSBDdXJyZW50bHkgZG9lcyBub3Qgd29yayBmb3IgbG1lNCBwYWNrYWdlIHdlIGFyZSB1c2luZw0KLSBZb3UgaGF2ZSB0byByZWZpdCB0aGUgbW9kZWwgYXMgQmF5ZXNpYW4gdXNpbmcgYHJzdGFuYXJtYCBhbmQgZ2V0IENJcw0KICAgIC0gV2Ugd2lsbCBub3QgZG8gdGhpcyAoc2VlIEdlbG1hbiAmIEhpbGwgdGV4dGJvb2sgb24gTXVsdGlsZXZlbCBtb2RlbHMgZm9yIEJheWVzaWFuIGFwcHJvYWNoKQ0KICAgIA0KIyMjIFByYWN0aWNhbCBzb2x1dGlvbg0KLSBQcmFjdGljYWxseSwgd2hlbiB5b3UgYWRkIGZhY3RvcnMgaW4gc3RlcHdpc2UgYW5kIG1vZGVsIGZpdCBzaG93cyBhIHNpZ25pZmljYW50IGltcHJvdmVtZW50IChQYXRoIDFBKSB5b3Ugd2lsbCBzZWUgdGhlIG5ldyBmYWN0b3JzIGhhcyBhIHQgPiAyLiAoUGF0aCAyQSkNCi0gVGhhdCBkb2VzIG5vdCBhbHdheXMgYWdyZWUgd2l0aCBib290c3RyYXBwaW5nIChQYXRoIDFCKSBvciBBTk9WQS1saWtlIGRlZ3JlZXMgb2YgZnJlZWRvbSAoUGF0aCAyQikNCiAgICAtIFRoaXMgaXMgYmVjYXVzZSBMTUU0IHBhY2thZ2Ugd2UgYXJlIHVzaW5nIGRvZXMgbm90IGFsbG93IHVzIHRvIGNvbnRyb2wgZm9yIHRoZSBoZXRlcm9nZW5lb3VzIHZhcmlhbmNlIHByb2JsZW0uIFRoZSBvbGRlciBwYWNrYWdlIExNRSB3aWxsIGFsbG93IHlvdSBjb250cm9sIGZvciBpdC4NCiAgICAgICAgLSBOb3RlIExNRSB1c2VzIFNhdHRlcnRod2FpdGUgYXBwcm94aW1hdGlvbnMgYW5kIHdpbGwgYWx3YXlzIGdpdmUgeW91IERGIGFuZCBwdmFsdWVzDQogICAgLSBBbHNvLCB0aGVyZSBjb3VsZCBiZSBvdGhlciBwcm9ibGVtcyB3aXRoIHlvdXIgYXNzdW1wdGlvbnMgdGhhdCBib290c3RyYXBwaW5nIGlzIHBpY2tpbmcgdXAgb24gdGhlIG90aGVyIHBhdGhzIHdpbGwgbm90IHBpY2sgdXANCi0gKlJlY29tbWVuZGF0aW9uOiogQmFzZWQgb24gY3VycmVudCB0cmVuZHM6DQogICAgMS4gQWx3YXlzIGRvIFBhdGggMUEgdG8gc2F5IHRoZSBtb2RlbCBpcyBiZXR0ZXIgDQogICAgMi4gVG8gdGVzdCB0aGUgcGFyYW1ldGVycyBhZGQgUGF0aCAxQiwgUGF0aCAyQSBvciAyQi4NCiAgICAgICAgLSBJIHVzdWFsbHkgcGljayAxQiBvciAyQSANCiAgICAgICAgLSBCdXQgc29tZSBmaWVsZHMgbWlnaHQgZGVtYW5kIERGLCBzbyB5b3UgaGF2ZSB0byBkbyAyQg0KICAgIA0KDQojIyBNdWx0aS1MZXZlbCBNb2RlbCBEZXNpZ24gRXhhbXBsZQ0KLSBTYW1lIGFzIExhc3QgV2VlayBTaW11bGF0aW9uICh2ZXJzaW9uIDIpDQotIExldCdzIGV4YW1pbmUgb3VyIHBhdGhzIQ0KDQojIyMgRGVzaWduIFJlbWluZGVyDQotIFlvdSB3YW50IHRvIG1lYXN1cmUgaG93IHN0dWRlbnRzIHJlc3BvbmQgdG8gYSBuZXcgdHlwZSBvZiBhY3RpdmUgbGVhcm5pbmcgbWV0aG9kIChjb21wdXRlci1iYXNlZCkgaW4gbWF0aCBjbGFzcw0KLSBZb3UgbWVhc3VyZSBzdHVkZW50cyAqKm1hdGggc2NvcmVzKiogKERWKSBhbmQgdGhlICoqcHJvcG9ydGlvbiBvZiB0aW1lKiogKElWKSB0aGV5IHNwZW5kIHVzaW5nIHRoZSBjb21wdXRlciAod2hpY2ggeW91IGFzc2lnbikNCi0gWW91IGFsc28gbWVhc3VyZSBob3cgKipzdXBwb3J0aXZlKiogKGNvbnRyb2wgYW5kL29yIG1vZGVyYXRvcikgZWFjaCBzdHVkZW50IGZlZWxzIHRoZSB0ZWFjaGVyIGlzIGFib3V0IHRoaXMgbmV3IG1ldGhvZC4gIA0KICAgIC0gQWxzbywgbWF5YmUgaWYgdGhlIHN0dWRlbnRzIGZlZWwgdGhlIHRlYWNoZXIgYXBwcm92ZXMgb2YgdGhlIG5ldyBtZXRob2QsIHRoZXkgbWlnaHQgZW5nYWdlIHdpdGggaXQgbW9yZQ0KLSBZb3UgdGVsbCB0d28gdGhlIHRlYWNoZXJzIHRoYXQgdGhlIGFjdGl2ZSBsZWFybmluZyBtZXRob2Qgd29ya3MgYW5kIHRoZSBvdGhlciB0d28gaXRzIGV4cGVyaW1lbnRhbCBbKipUb2xkKiogbGV2ZWwgMiB2YXJpYWJsZV0NCi0gWW91IGhhdmUgYWNjZXNzIHRvIGRpZmZlcmVudCBjbGFzc3Jvb21zIHdpdGggKio1MCoqIHN0dWRlbnRzIHBlciBjbGFzcw0KDQojIyMjIFNpbXVsYXRpb24gRGV0YWlscw0KLSBTZXQgdGhlIGRpZmZlcmVudCBzbG9wZSBvZiAqKnByb3BvcnRpb24gb2YgdGltZSoqIChwbHVzIG5vaXNlKSANCi0gKkRpZmZlcmVudCogaW50ZXJjZXB0IHBlciBjbGFzcyAocGx1cyBub2lzZSkgW3doaWNoIHdpbGwgaW1wbGljaXRseSBjb3JyZWxhdGUgd2l0aCAqKnN1cHBvcnRpdmUqKl0NCi0gKkRpZmZlcmVudCogc2xvcGUgcGVyIGNsYXNzIG9uICoqc3VwcG9ydGl2ZSoqIChwbHVzIG5vaXNlKQ0KLSBTZXQgc2FtZSBpbnRlcmFjdGlvbiBiZXR3ZWVuICoqcHJvcG9ydGlvbiBvZiB0aW1lKiogYW5kICoqc3VwcG9ydGl2ZSoqDQotIFRlYWNoZXJzIGluIENsYXNzcm9vbXMgMSBhbmQgMiB3ZXJlICoqVG9sZCoqIHRoZSBwcm9ncmFtICp3b3JrcyogYW5kIDMgJiA0IHRoYXQgaXQgaXMgKmV4cGVyaW1lbnRhbCoNCi0gW05vdGU6IEkgaGF2ZSBub3Qgc2hvd24gdGhlIHNpbXVsYXRpb24gJ2VjaG89RkFMU0UnIGRvZXMgbm90IHByaW50IGl0XQ0KYGBge3IsIGVjaG89RkFMU0V9DQojU2V0IHNlZWQgc28geW91ciBhbnN3ZXJzIGFyZSBhbGwgdGhlIHNhbWUNCnNldC5zZWVkKDkpDQojIFNhbXBsZSBQZXIgY2xhc3Mgcm9vbSBwZW9wbGUNCm4xIDwtIDUwOyBuMiA8LSA1MDsgbjMgPC0gNTA7IG40IDwtIDUwDQpOPC1uMStuMituMytuNCAjIFRvdGFsIE4NCiMgVW5pZm9ybSBkaXN0cm9idXRpb24gb2YgQWN0aXZlVGltZSBwZXIgY2xhc3Nyb29tDQpYMSA8LSBydW5pZihuMSwgMCwgMSk7IFgyIDwtIHJ1bmlmKG4yLCAwLCAxKQ0KWDMgPC0gcnVuaWYobjMsIDAsIDEpOyBYNCA8LSBydW5pZihuNCwgMCwgMSkNCiMgVW5pZm9ybSBkaXN0cm9idXRpb24gb2Ygc3VwcG9ydCBwZXIgY2xhc3Nyb29tDQpaMSA8LSBydW5pZihuMSwgMCwgMSk7IFoyIDwtIHJ1bmlmKG4yLCAwLCAxKQ0KWjMgPC0gcnVuaWYobjMsIDAsIDEpOyBaNCA8LSBydW5pZihuNCwgMCwgMSkNCiMgSW50ZXJjZXB0cyBwZXIgY2xhc3Nyb29tDQpCMC4xIDwtIDgwOyBCMC4yIDwtIDc1DQpCMC4zIDwtIDY1OyBCMC40IDwtIDY4DQojIFNhbWUgc2xvcGUgZm9yIEFjdGl2ZVRpbWUgcGVyIGNsYXNzcm9vbSArIE5vaXNlDQpCMSA8LSBybm9ybShuMSwgMTcsIHNkPTIuNSk7IEIyIDwtIHJub3JtKG4yLCAxMiwgc2Q9Mi41KQ0KQjMgPC0gcm5vcm0objMsIDgsIHNkPTIuNSk7IEI0IDwtIHJub3JtKG40LCA0LCBzZD0yLjUpDQojIGRpZmZlcmVudCBzbG9wZSBmb3Igc3VwcG9ydCBwZXIgY2xhc3Nyb29tICsgTm9pc2UNCmcxIDwtIHJub3JtKG4xLCAxMCwgc2Q9Mi41KTsgZzIgPC0gcm5vcm0objIsIDUsIHNkPTIuNSkNCmczIDwtIHJub3JtKG4zLCAtNSwgc2Q9Mi41KTsgZzQgPC0gcm5vcm0objQsIDIsIHNkPTIuNSkNCiMgU2FtZSBpbnRlcmFjdGlvbiBiZXR3ZWVuIEFjdGl2ZVRpbWUqc3VwcG9ydCBzdXBwb3J0IHBlciBjbGFzc3Jvb20gKyBOb2lzZQ0KZjE8LSBybm9ybShuMywgMTUsIHNkPTIuNSk7IGYyPC0gcm5vcm0objMsIDE1LCBzZD0yLjUpDQpmMzwtIHJub3JtKG4zLCAxNSwgc2Q9Mi41KTsgZjQ8LSBybm9ybShuMywgMTUsIHNkPTIuNSkNCiMgbm9pc2UgcGVyIHN0dWRlbnQgd2l0aGluIGVhY2ggY2xhc3Nyb29tDQplMSA8LSBybm9ybShuMSwgMCwgc2Q9Mi41KTsgZTIgPC0gcm5vcm0objIsIDAsIHNkPTIuNSkNCmUzIDwtIHJub3JtKG4zLCAwLCBzZD0yLjUpOyBlNCA8LSBybm9ybShuNCwgMCwgc2Q9Mi41KQ0KDQojIE91ciBlcXVhdGlvbiB0byAgY3JlYXRlIFkgZm9yIGVhY2ggY2xhc3Nyb29tDQpZMSA9IEIxKnNjYWxlKFgxLHNjYWxlPUYpK2cxKloxK2YxKnNjYWxlKFgxLHNjYWxlPUYpKnNjYWxlKFoxLHNjYWxlPUYpICsgQjAuMSArIGUxDQpZMiA9IEIyKnNjYWxlKFgyLHNjYWxlPUYpK2cyKloyK2YyKnNjYWxlKFgyLHNjYWxlPUYpKnNjYWxlKFoyLHNjYWxlPUYpICsgQjAuMiArIGUyDQpZMyA9IEIzKnNjYWxlKFgzLHNjYWxlPUYpK2czKlozK2YzKnNjYWxlKFgzLHNjYWxlPUYpKnNjYWxlKFozLHNjYWxlPUYpICsgQjAuMyArIGUzDQpZNCA9IEI0KnNjYWxlKFg0LHNjYWxlPUYpK2c0Klo0K2Y0KnNjYWxlKFg0LHNjYWxlPUYpKnNjYWxlKFo0LHNjYWxlPUYpICsgQjAuNCArIGU0DQojIE1lcmdlIGNsYXNzcm9vbXMgaW50byAxIGRhdGEuZnJhbWUNCk1MTS5EYXRhLjI8LWRhdGEuZnJhbWUoTWF0aD1jKFkxLFkyLFkzLFk0KSxBY3RpdmVUaW1lPWMoWDEsWDIsWDMsWDQpLFN1cHBvcnQ9YyhaMSxaMixaMyxaNCksDQogICAgICAgICAgICAgICAgICAgICBDbGFzc3Jvb209YyhyZXAoIkMxIixuMSkscmVwKCJDMiIsbjIpLHJlcCgiQzMiLG4zKSxyZXAoIkM0IixuNCkpLA0KICAgICAgICAgICAgICAgICAgICAgVG9sZD1jKHJlcCgiV29ya3MiLG4xKSxyZXAoIldvcmtzIixuMiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVwKCJFeHBlcmltZW50YWwiLG4zKSxyZXAoIkV4cGVyaW1lbnRhbCIsbjQpKSwNCiAgICAgICAgICAgICAgICAgICAgIFN0dWRlbnRJRD1hcy5mYWN0b3IoMTpOKSkNCmBgYA0KDQojIyMjIFBsb3Qgb3VyIENsdXN0ZXJzDQotIFN0dWRlbnRzIG5lc3RlZCBpbiBjbGFzc3Jvb21zDQoNCmBgYHtyLCBlY2hvPUZBTFNFLCBvdXQud2lkdGg9Jy40OVxcbGluZXdpZHRoJywgZmlnLndpZHRoPTMuMjUsIGZpZy5oZWlnaHQ9My4yNSxmaWcuc2hvdz0naG9sZCcsZmlnLmFsaWduPSdjZW50ZXInfQ0KbGlicmFyeShnZ3Bsb3QyKQ0KdGhlbWVfc2V0KHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDEyLCBiYXNlX2ZhbWlseSA9ICIiKSkgDQoNCkNsYXNzUm9vbS5BY3RpdmUuMiA8LWdncGxvdChkYXRhID0gTUxNLkRhdGEuMiwgYWVzKHggPSBBY3RpdmVUaW1lLCB5PU1hdGgsZ3JvdXA9Q2xhc3Nyb29tKSkrDQogIGZhY2V0X2dyaWQoVG9sZH4uKSsNCiAgZ2VvbV9wb2ludChhZXMoY29sb3VyID0gQ2xhc3Nyb29tKSkrDQogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gVFJVRSwgYWVzKGNvbG91ciA9IENsYXNzcm9vbSkpKw0KICB4bGFiKCJBY3RpdmUgTGVhcm5pbmcgVGltZSIpK3lsYWIoIk1hdGggU2NvcmUiKSsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KQ2xhc3NSb29tLkFjdGl2ZS4yDQoNCkNsYXNzUm9vbS5TdXBwb3J0LjIgPC1nZ3Bsb3QoZGF0YSA9IE1MTS5EYXRhLjIsIGFlcyh4ID0gU3VwcG9ydCwgeT1NYXRoLGdyb3VwPUNsYXNzcm9vbSkpKw0KICBmYWNldF9ncmlkKFRvbGR+LikrDQogIGdlb21fcG9pbnQoYWVzKGNvbG91ciA9IENsYXNzcm9vbSkpKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IFRSVUUsIGFlcyhjb2xvdXIgPSBDbGFzc3Jvb20pKSsNCiAgeGxhYigiU3VwcG9ydCIpK3lsYWIoIk1hdGggU2NvcmUiKSsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KQ2xhc3NSb29tLlN1cHBvcnQuMg0KYGBgDQoNCi0gTGV0J3MgY2VudGVyIHRoZSBkYXRhIGp1c3QgYXMgYmVmb3JlLCBidXQgbGF5ZXIgZml4ZWQgZWZmZWN0cyAoa2VlcCByYW5kb20gZWZmZWN0cyBjb25zdGFudCkNCg0KIyMgUGF0aCAxQSAmIDJBDQojIyMgTnVsbCBNb2RlbA0KYGBge3J9DQpsaWJyYXJ5KHBseXIpDQpsaWJyYXJ5KGxtZTQpDQpNTE0uRGF0YS4yJEFjdGl2ZVRpbWUuR008LXNjYWxlKE1MTS5EYXRhLjIkQWN0aXZlVGltZSxzY2FsZT1GKQ0KTUxNLkRhdGEuMjwtZGRwbHkoTUxNLkRhdGEuMiwuKENsYXNzcm9vbSksIG11dGF0ZSwgQ2xhc3NTdXBwb3J0ID0gbWVhbihTdXBwb3J0KSkNCk1MTS5EYXRhLjIkU3VwcG9ydC5DQzwtTUxNLkRhdGEuMiRTdXBwb3J0LU1MTS5EYXRhLjIkQ2xhc3NTdXBwb3J0DQoNCk1MTS5Nb2RlbC4xPC1sbWVyKE1hdGggfiAxKygxK1N1cHBvcnQuQ0N8fENsYXNzcm9vbSksICANCiAgICAgICAgICAgICAgZGF0YT1NTE0uRGF0YS4yLCBSRU1MPUZBTFNFKQ0KYGBgDQoNCiMjIyBNYWluIGVmZmVjdHMNCmBgYHtyfQ0KTUxNLk1vZGVsLjI8LWxtZXIoTWF0aCB+IEFjdGl2ZVRpbWUuR00rU3VwcG9ydC5DQysoMStTdXBwb3J0LkNDfHxDbGFzc3Jvb20pLCAgDQogICAgICAgICAgICAgIGRhdGE9TUxNLkRhdGEuMiwgUkVNTD1GQUxTRSkNCmBgYA0KDQojIyMgSW50ZXJhY3Rpb24NCmBgYHtyfQ0KTUxNLk1vZGVsLjM8LWxtZXIoTWF0aCB+IEFjdGl2ZVRpbWUuR00qU3VwcG9ydC5DQysoMStTdXBwb3J0LkNDfHxDbGFzc3Jvb20pLCAgDQogICAgICAgICAgICAgIGRhdGE9TUxNLkRhdGEuMiwgUkVNTD1GQUxTRSkNCmBgYA0KDQojIyMgRGV2aWVuY2UgdGVzdGluZyBbQXNzdW1lIENoaS1TcXVhcmUgZGlzdHJvYnV0aW9uXQ0KYGBge3J9DQphbm92YShNTE0uTW9kZWwuMSxNTE0uTW9kZWwuMixNTE0uTW9kZWwuMykNCmBgYA0KDQojIyMgRGV2aWFuY2UgdGVzdGluZyBbQm9vdHN0cmFwcGVkXQ0KLSBZb3Ugb25seSBkbyB0aGlzIHR3byBhdCBhIHRpbWUNCi0gWW91IGhhdmUgdG8gZm9sbG93IHRoaXMgc3ludGF4IGBQQm1vZGNvbXAobGFyZ2VNb2RlbCwgc21hbGxNb2RlbCwgbnNpbXMpYA0KICAgIC0gTFJUOiBBc3N1bWluZyB0aGF0IExSVCBoYXMgYSBjaGktc3F1YXJlIGRpc3RyaWJ1dGlvbiAod2hhdCB3ZSBkaWQgYWJvdmUpDQogICAgLSBQQnRlc3Q6IFRoZSBmcmFjdGlvbiBvZiBzaW11bGF0ZWQgTFJULXZhbHVlcyB0aGF0IGFyZSBsYXJnZXIgb3IgZXF1YWwgdG8gdGhlIG9ic2VydmVkIExSVCB2YWx1ZS4NCiAgICAgICAgLSBDb25zZXJ2YXRpdmUgcmVsYXRpdmUgdG8gTFJUIA0KLSBTTExPT09XV1dXV1dXIFt5b3UgbWlnaHQgd2FudCB0byByZWR1Y2UgdGhlIHNpbXMgd2hlbiB5b3UgcnVuIHRoaXMgb24geW91ciBsYXB0b3BzXQ0KICAgIC0gWWVzIHRoZSBudW1iZXIgb2Ygc2ltdWxhdGlvbnMgbWFrZSBhIGRpZmZlcmVuY2UgKGdvIGZvciAxLTJLIHdoZW4geW91IHB1Ymxpc2gganVzdCB0byBiZSBzdXJlKQ0KICAgIA0KYGBge3J9DQpsaWJyYXJ5KHBia3J0ZXN0KQ0KUEJtb2Rjb21wKE1MTS5Nb2RlbC4yLE1MTS5Nb2RlbC4xLG5zaW09NTAwKQ0KUEJtb2Rjb21wKE1MTS5Nb2RlbC4zLE1MTS5Nb2RlbC4yLG5zaW09NTAwKQ0KYGBgDQoNCiMjIyBCb290c3RyYXAgRmluYWwgTW9kZWwNCiMjIyMgUGFyYW1ldHJpYyBWZXJzaW9uIA0KLSBUYWtlIGJvb3RzdHJhcCBkaXN0cmlidXRpb24gYW5kIGZpbmQgcGVyY2VudGlsZXMgKHVzdWFsbHksIC4wMjUgYW5kIC45NzUpDQogDQpgYGB7cn0NCk1vZGVsLkZpbmFsLkNJLmJvb3QgPC0gY29uZmludChNTE0uTW9kZWwuMywgbWV0aG9kPSJib290Iixuc2ltPTUwMCxib290LnR5cGUgPSBjKCJwZXJjIikpIA0KTW9kZWwuRmluYWwuQ0kuYm9vdA0KYGBgDQoNCi0gTGV0cyB2aXN1YWxpemUgdGhlIGJvb3RzdHJhcHBpbmcgb24gdGhlIGZpeGVkIGVmZmVjdHMNCmBgYHtyfQ0KYmZpeGVkIDwtIGJvb3RNZXIoTUxNLk1vZGVsLjMsIEZVTj1maXhlZixuc2ltPTUwMCkNCg0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeSh0aWR5cikNCmJmaXhlZCR0ICU+JQ0KICBkYXRhLmZyYW1lKCklPiUNCiAgZ2F0aGVyKCklPiUNCiAgZ2dwbG90KGFlcyh2YWx1ZSkpKw0KICBzdGF0X2RlbnNpdHkoYWxwaGEgPSAwLjYsIGNvbG9yID0gImJsYWNrIikrDQogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gMikrDQogIGZhY2V0X3dyYXAofmtleSwgc2NhbGVzID0gImZyZWUiKSsNCiAgdGhlbWVfYncoKQ0KYGBgDQoNCg0KIyMgUGF0aCAyQg0KDQojIyMgU2F0dGVydGh3YWl0ZSBEZWdyZWVzIG9mIGZyZWVkb20gDQotIFdlIG5lZWQgdG8gcmVmaXQgb3V0IG1vZGVsIHVzaW5nIGEgbmV3IHBhY2thZ2UNCmBgYHtyfQ0KbGlicmFyeShsbWVyVGVzdCkNCk1MTS5Nb2RlbC4zLkxUZXN0PC1sbWVyVGVzdDo6bG1lcihNYXRoIH4gQWN0aXZlVGltZS5HTSpTdXBwb3J0LkNDKygxK1N1cHBvcnQuQ0N8fENsYXNzcm9vbSksICANCiAgICAgICAgICAgICAgZGF0YT1NTE0uRGF0YS4yLCBSRU1MPUZBTFNFKQ0Kc3VtbWFyeShNTE0uTW9kZWwuMy5MVGVzdCkNCmBgYA0KDQotIEJlY2F1c2UgU3VwcG9ydC5DQyBpcyByYW5kb20gc2xvcGUsIHdlIG9ubHkgaGF2ZSA0IHNjaG9vbHMsIHRodXMgREYgY2hhbmdlcyB0byBtYXRjaCBob3cgbWFueSBzbG9wZXMgd2UgbWVhc3VyZWQNCi0gSWYgd2Ugd2FudCB0aGUgbW9kZWwgaW4gQU5PVkEgc3R5bGUgZm9ybWF0IHdlIGNhbiBnZXQgdGhhdCBhcyB3ZWxsDQoNCmBgYHtyfQ0KbGlicmFyeShsbWVyVGVzdCkNCmFub3ZhKE1MTS5Nb2RlbC4zLkxUZXN0KQ0KYGBgDQogICAgICAgIA0KIyMjIE5vdGljZSBERiBjaGFuZ2VzDQotIE5vIHJhbmRvbSBzbG9wZXMNCmBgYHtyfQ0KTUxNLk1vZGVsLjQuTFRlc3Q8LWxtZXJUZXN0OjpsbWVyKE1hdGggfiBBY3RpdmVUaW1lLkdNKlN1cHBvcnQuQ0MrKDF8Q2xhc3Nyb29tKSwgIA0KICAgICAgICAgICAgICBkYXRhPU1MTS5EYXRhLjIsIFJFTUw9RkFMU0UpDQpzdW1tYXJ5KE1MTS5Nb2RlbC40LkxUZXN0KQ0KYGBgDQoNCi0gWW91IHdpbGwgbm90aWNlIHRoZSBkZWdyZWVzIG9mIGZyZWVkb20gY2hhbmdlDQoNCiMjIyBLZW53YXJkLVJvZ2VyIERlZ3JlZXMgb2YgZnJlZWRvbSANCi0gVGhlc2UgbWlnaHQgYmUgU0xPVyBhbmQgbWlnaHQgZmFpbCBpbiBsYXJnZSBkYXRhIHNldHMNCi0gKk11c3QgYmUgZml0IHdpdGggUkVNTCoNCg0KYGBge3J9DQpsaWJyYXJ5KHBia3J0ZXN0KQ0KDQpNTE0uTW9kZWwuMy5MVGVzdC5SRU1MPC1sbWVyVGVzdDo6bG1lcihNYXRoIH4gQWN0aXZlVGltZS5HTSpTdXBwb3J0LkNDKygxK1N1cHBvcnQuQ0N8fENsYXNzcm9vbSksICANCiAgICAgICAgICAgICAgZGF0YT1NTE0uRGF0YS4yLCBSRU1MPVRSVUUpDQpzdW1tYXJ5KE1MTS5Nb2RlbC4zLkxUZXN0LlJFTUwsIGRkZj0iS2Vud2FyZC1Sb2dlciIpDQpgYGAgICANCg0KIyBQcmFjdGljYWwgSXNzdWVzDQotIFRoZSBgZWZmZWN0c2AgcGFja2FnZSB3aWxsIGdlbmVyYXRlIENJcyBmb3IgbWl4ZWQgbW9kZWxzLCBidXQgd2lsbCBhcHByb3hpbWF0ZSB0aGVtIGFzIGJlbG93Og0KDQpgYGB7cn0NCk1vZGVsLkZpbmFsLkNJLldhbGQgPC0gY29uZmludChNTE0uTW9kZWwuMywgbWV0aG9kPSJXYWxkIikgDQpgYGANCg0KLSBZb3UgY2FuIGZvcmNlIHRoZSBlZmZlY3RzIHBhY2thZ2UgdG8gZG8gdGhlbSBhcyBLUiwgYnV0cyBpdHMgc2xvdyAoYW5kIHlvdSdyZSBwcm9iYWJseSBjYW5ub3Qgc2VlIHRoZSBkaWZmZXJlbmNlIGFueXdheSkNCi0gVmlzdWFsaXppbmcgdGhlIGJvb3RzdHJhcHBlZCBvbmVzIGlzIGRpZmZpY3VsdCBhbmQgdGFrZXMgYSBmYWlyIGJpdCBvZiBjb2RlIHdvcmsNCiAgICAtIEkgd2lsbCB0cnkgdG8gZmluZCBhIGZ1bmN0aW9uIHRoYXQgZG9lcyB0aGlzLCBidXQgc28gZmFyIG5vIGx1Y2sNCi0gSSB1c3VhbGx5IGp1c3QgZ3JhcGggdGhlIGBlZmZlY3RzYCB2ZXJzaW9uIGFuZCBlaXRoZXIgc2hvdyBTRSBvciBDSQ0KICAgIC0gVGhlcmUgaXMgbm90IGEgcGVyZmVjdCBzb2x1dGlvbiwgYnV0IHRoZSBwb2ludCBpcyBqdXN0IHRvIGdpdmUgeW91ciByZWFkZXIgc29tZSBpZGVhIG9mIHRoZSBlcnJvciANCiAgICAtIFRoZXNlIG1heSBub3QgYWx3YXlzIG1hdGNoIHlvdXIgInNpZ25pZmljYW5jZSIgYW5kIHRoaXMgd2lsbCBiZSBhIGJpZ2dlciBwcm9ibGVtIGxhdGVyIHdoZW4gd2UgaGF2ZSByZXBlYXRlZCBkZXNpZ25zDQoNCg0KPHNjcmlwdD4NCiAgKGZ1bmN0aW9uKGkscyxvLGcscixhLG0pe2lbJ0dvb2dsZUFuYWx5dGljc09iamVjdCddPXI7aVtyXT1pW3JdfHxmdW5jdGlvbigpew0KICAoaVtyXS5xPWlbcl0ucXx8W10pLnB1c2goYXJndW1lbnRzKX0saVtyXS5sPTEqbmV3IERhdGUoKTthPXMuY3JlYXRlRWxlbWVudChvKSwNCiAgbT1zLmdldEVsZW1lbnRzQnlUYWdOYW1lKG8pWzBdO2EuYXN5bmM9MTthLnNyYz1nO20ucGFyZW50Tm9kZS5pbnNlcnRCZWZvcmUoYSxtKQ0KICB9KSh3aW5kb3csZG9jdW1lbnQsJ3NjcmlwdCcsJ2h0dHBzOi8vd3d3Lmdvb2dsZS1hbmFseXRpY3MuY29tL2FuYWx5dGljcy5qcycsJ2dhJyk7DQoNCiAgZ2EoJ2NyZWF0ZScsICdVQS05MDQxNTE2MC0xJywgJ2F1dG8nKTsNCiAgZ2EoJ3NlbmQnLCAncGFnZXZpZXcnKTsNCg0KPC9zY3JpcHQ+