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
- 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.
- 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?)
- 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!
- 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)
- 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!
- 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
- 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:
- Always do Path 1A to say the model is better
- 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
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+