Moderated mediation analyses using “mediation” package
We will first create two regression models, one looking at the effect of our IVs (time spent in grad school, time spent with Alex, and their interaction) on our mediator (number of publications), and one looking at the effect of our IVs and mediator on our DV (number of job offers).
Next, we will examine the influence of our moderating variable (time spent with Alex) on the mediation effect of time spent in grad school on number of job offers, through number of publications. To do this, we will examine the mediation effect for those who spend a lot of time with Alex versus those who spend little time with Alex.
Create the necessary regression models
We need two regression models to use the mediation package
One model specifies the effect of our IV (time spent in grad school) on our Mediator (number of publications) [and in our case, our moderator (time spent with Alex) and the interaction]
The other model specifies the effect of the IV (time spent in grad school) and Mediator (number of publications) (and possibly moderator as well) on our DV (number of job offers)
install.packages("mediation") #install this first if not already installed
library(mediation)
mediate <- mediation::mediate #A mediate function is in both the "psych" and "mediation" packages. This allows us to use the correct mediate function from the "mediation" package
Mod.Med.Model.1<-lm(pubs ~ time.c*alex.c, data = Success.ModMed) #This model predicts number of publications from time spent in grad school, time spent with alex, and the interaction between the two
summary(Mod.Med.Model.1)
##
## Call:
## lm(formula = pubs ~ time.c * alex.c, data = Success.ModMed)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.24019 -0.06563 -0.00220 0.07089 0.32256
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 5.162911 0.007308 706.49 <2e-16 ***
## time.c 0.857893 0.007518 114.12 <2e-16 ***
## alex.c 1.854224 0.007957 233.02 <2e-16 ***
## time.c:alex.c 0.309273 0.007948 38.91 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.103 on 196 degrees of freedom
## Multiple R-squared: 0.9973, Adjusted R-squared: 0.9973
## F-statistic: 2.418e+04 on 3 and 196 DF, p-value: < 2.2e-16
- Significant main effect of time spent in grad school on number of publications
- Significant main effect of time spent with Alex on number of publications
- Significant interaction between time spent in grad school and time spent with Alex on number of publications
Mod.Med.Model.2<-lm(jobs ~ time.c*alex.c + pubs, data = Success.ModMed) #This model predicts number of job offers from time spent in grad school, time spent with alex, number of publications, and the interaction between time spent in grad school and time spent with alex
summary(Mod.Med.Model.2)
##
## Call:
## lm(formula = jobs ~ time.c * alex.c + pubs, data = Success.ModMed)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.294627 -0.061596 0.003638 0.073073 0.226142
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1.601513 0.335390 4.775 3.52e-06 ***
## time.c 0.219265 0.056137 3.906 0.000129 ***
## alex.c -0.048126 0.120647 -0.399 0.690404
## pubs 0.583970 0.064949 8.991 < 2e-16 ***
## time.c:alex.c -0.009457 0.021347 -0.443 0.658260
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.09367 on 195 degrees of freedom
## Multiple R-squared: 0.9941, Adjusted R-squared: 0.994
## F-statistic: 8191 on 4 and 195 DF, p-value: < 2.2e-16
- Significant main effect of time spent in grad school on number of job offers
- No effect of time spent with Alex on number of job offers
- Significant main effect of number of publications on number of job offers
- No interaction between time spent in grad school and time spent with Alex on number of job offers
Examine the effect of our moderator on the mediation effect
In this mediation package we list the moderator as a covariate and set the levels to what we want
We can use the +/- 1SD from the mean (or another value that is theoretically important)
This allows us to view impact of the moderator on the direct and indirect effects
Lets look at grad students who spend little time with Alex first
#Moderator must be in both models for mediate to work.
low.alex<-mean(Success.ModMed$alex.c)-sd(Success.ModMed$alex.c) #Sets our level for 1 SD below mean of alex.c
low.alex #Check value of variable
## [1] -0.9470806
Mod.Med.LowAlex <- mediate(Mod.Med.Model.1, Mod.Med.Model.2,
covariates = list(alex.c = low.alex), boot = TRUE,
boot.ci.type = "bca", sims = 10, treat="time.c", mediator="pubs")
#The mediate function can handle different types of CI estimation. Here we are asking for bias-corrected and accelerated confidence intervals because this gives us more accurate confident interval estimates and corrects for deviation from normality
#We also have to specify our IV (treat) and Mediator(pubs)
#For demonstration I am only doing 10 simulations, but in reality you'd want to do at least 2,000
For a review on bootstrapping techniques, see Efron, 2003
- ACME: Average Causal Mediation Effect [total effect - direct effect]
- ADE: Average Direct Effect [total effect - indirect effect]
- Total Effect: Direct (ADE) + Indirect (ACME)
- Prop. Mediated: Conceptually ACME / Total effect (This tells us how much of the total effect our indirect effect is “explaining”)
summary(Mod.Med.LowAlex)
##
## Causal Mediation Analysis
##
## Nonparametric Bootstrap Confidence Intervals with the BCa Method
##
## (Inference Conditional on the Covariate Values Specified in `covariates')
##
## Estimate 95% CI Lower 95% CI Upper p-value
## ACME 0.330 0.263 0.39 <2e-16 ***
## ADE 0.228 0.166 0.30 <2e-16 ***
## Total Effect 0.558 0.532 0.57 <2e-16 ***
## Prop. Mediated 0.591 0.467 0.70 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Sample Size Used: 200
##
##
## Simulations: 10
plot(Mod.Med.LowAlex, xlim = 0:1)
- Significant direct effect of time spent in grad school on job offers (for those who don’t spend a lot of time with Alex)
- Significant indirect effect of time spent in grad school on job offers through publications (for those who don’t spend a lot of time with Alex)
Now let’s look at grad students who spend a lot of time with Alex
high.alex<-mean(Success.ModMed$alex.c)+sd(Success.ModMed$alex.c)
high.alex
## [1] 0.9470806
Mod.Med.HighAlex <- mediate(Mod.Med.Model.1, Mod.Med.Model.2,
covariates = list(alex.c = high.alex), boot = TRUE,
boot.ci.type = "bca", sims = 10, treat="time.c", mediator="pubs")
summary(Mod.Med.HighAlex)
##
## Causal Mediation Analysis
##
## Nonparametric Bootstrap Confidence Intervals with the BCa Method
##
## (Inference Conditional on the Covariate Values Specified in `covariates')
##
## Estimate 95% CI Lower 95% CI Upper p-value
## ACME 0.672 0.565 0.75 <2e-16 ***
## ADE 0.210 0.100 0.32 <2e-16 ***
## Total Effect 0.882 0.873 0.89 <2e-16 ***
## Prop. Mediated 0.762 0.641 0.89 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Sample Size Used: 200
##
##
## Simulations: 10
plot(Mod.Med.HighAlex, xlim = 0:1)
- Significant direct effect of time spent in grad school on job offers (for those who spend a lot of time with Alex)
- Significant indirect effect of time spent in grad school on job offers through publications (for those who spend a lot of time with Alex)
- The indirect effect looks larger for those who spend a lot of time with Alex compared to those who don’t, but we can test this to make sure
The following code tests whether the difference between indirect effects at each level of the moderator is significantly different from zero
Mod.Med.TestAlex <- mediate(Mod.Med.Model.1, Mod.Med.Model.2, boot = TRUE,
boot.ci.type = "bca", sims = 10, treat="time.c", mediator="pubs") #We don't specify anything about the moderator in this code yet
test.modmed(Mod.Med.TestAlex, covariates.1 = list(alex.c = low.alex),
covariates.2 = list(alex.c = high.alex), sims = 10) #Here we specify both levels of the moderator that we want to test
##
## Test of ACME(covariates.1) - ACME(covariates.2) = 0
##
## data: estimates from Mod.Med.TestAlex
## ACME(covariates.1) - ACME(covariates.2) = -0.3421, p-value <
## 2.2e-16
## alternative hypothesis: true ACME(covariates.1) - ACME(covariates.2) is not equal to 0
## 95 percent confidence interval:
## -0.5540589 -0.2094565
##
##
## Test of ADE(covariates.1) - ADE(covariates.2) = 0
##
## data: estimates from Mod.Med.TestAlex
## ADE(covariates.1) - ADE(covariates.2) = 0.017913, p-value = 0.6
## alternative hypothesis: true ADE(covariates.1) - ADE(covariates.2) is not equal to 0
## 95 percent confidence interval:
## -0.1190875 0.2212338
- We can see that the indirect effects are significantly different such that the effect of spending time in graduate school on getting job offers through publications is stronger for those students who spend a lot of time with Alex compared to those who do not
- There is no different in the size of the direct effects, however
Moderated mediation analyses using “lavaan” package
In “lavaan” we specify all regressions and relationships between our variables in one object
We can specify the effects we want to see in our output (e.g., direct, indirect, etc.)
We can also compute means and standard deviations for use in simple slopes analyses
After specifying all the necessary components, we fit the model using an SEM function
install.packages("lavaan") #install this first if not already installed
library(lavaan)
Mod.Med.Lavaan <- '
#Regressions
#These are the same regression equations from our previous example
#Except in this code we are naming the coefficients that are produced from the regression equations
#E.g., the regression coefficient for the effect of time on pubs is named "a1"
pubs ~ a1*time.c + a2*alex.c + a3*time.c:alex.c
jobs ~ cdash1*time.c + cdash2*alex.c + cdash3*time.c:alex.c + b1*pubs
#Mean of centered alex (for use in simple slopes)
#This is making a coefficient labeled "alex.c.mean" which equals the intercept because of the "1"
#(Y~1) gives you the intercept, which is the mean for our alex.c variable
alex.c ~ alex.c.mean*1
#Variance of centered alex (for use in simple slopes)
#This is making a coefficient labeled "alex.c.var" which equals the variance because of the "~~"
#Two tildes separating the same variable gives you the variance
alex.c ~~ alex.c.var*alex.c
#Indirect effects conditional on moderator (a1 + a3*ModValue)*b1
indirect.SDbelow := (a1 + a3*(alex.c.mean-sqrt(alex.c.var)))*b1
indirect.SDabove := (a1 + a3*(alex.c.mean+sqrt(alex.c.var)))*b1
#Direct effects conditional on moderator (cdash1 + cdash3*ModValue)
#We have to do it this way because you cannot call the mean and sd functions in lavaan package
direct.SDbelow := cdash1 + cdash3*(alex.c.mean-sqrt(alex.c.var))
direct.SDabove := cdash1 + cdash3*(alex.c.mean+sqrt(alex.c.var))
#Total effects conditional on moderator
total.SDbelow := direct.SDbelow + indirect.SDbelow
total.SDabove := direct.SDabove + indirect.SDabove
#Proportion mediated conditional on moderator
#To match the output of "mediate" package
prop.mediated.SDbelow := indirect.SDbelow / total.SDbelow
prop.mediated.SDabove := indirect.SDabove / total.SDabove
#Index of moderated mediation
#An alternative way of testing if conditional indirect effects are significantly different from each other
index.mod.med := a3*b1
'
Now we take the specified models and all of the effects we want to estimate and run them through the SEM function. The SEM function allows a completely user-defined model to be fit to the data, like our specifically defined moderated mediation model (the SEM function was designed to fit structural equation models, but can also fit “regular” regression models as well).
#Fit model
Mod.Med.SEM <- sem(model = Mod.Med.Lavaan,
data = Success.ModMed,
se = "bootstrap",
bootstrap = 10)
#Fit measures
summary(Mod.Med.SEM,
fit.measures = FALSE,
standardize = TRUE,
rsquare = TRUE)
- The first chunk of the output show fit indices related to SEM (not really applicable for our purposes)
- The second part of the output shows our regression formulas
- The end of the output shows the specified direct, indirect, total, proportion mediated effects
## lavaan (0.5-23.1097) converged normally after 107 iterations
##
## Number of observations 200
##
## Estimator ML
## Minimum Function Test Statistic 12.599
## Degrees of freedom 2
## P-value (Chi-square) 0.002
##
## Parameter Estimates:
##
## Information Observed
## Standard Errors Bootstrap
## Number of requested bootstrap draws 10
## Number of successful bootstrap draws 10
##
## Regressions:
## Estimate Std.Err z-value P(>|z|) Std.lv Std.all
## pubs ~
## time.c (a1) 0.858 0.007 123.187 0.000 0.858 0.425
## alex.c (a2) 1.854 0.007 283.790 0.000 1.854 0.892
## tm.c:l. (a3) 0.309 0.009 35.101 0.000 0.309 0.149
## jobs ~
## time.c (cds1) 0.219 0.070 3.154 0.002 0.219 0.175
## alex.c (cds2) -0.048 0.151 -0.319 0.750 -0.048 -0.037
## tm.c:l. (cds3) -0.009 0.024 -0.389 0.697 -0.009 -0.007
## pubs (b1) 0.584 0.081 7.217 0.000 0.584 0.942
##
## Covariances:
## Estimate Std.Err z-value P(>|z|) Std.lv Std.all
## time.c ~~
## time.c:alex.c -0.008 0.117 -0.067 0.947 -0.008 -0.009
##
## Intercepts:
## Estimate Std.Err z-value P(>|z|) Std.lv Std.all
## alex.c (al..) -0.000 0.087 -0.000 1.000 -0.000 -0.000
## .pubs 5.163 0.007 780.718 0.000 5.163 2.629
## .jobs 1.602 0.419 3.825 0.000 1.602 1.316
## time.c -0.000 0.057 -0.000 1.000 -0.000 -0.000
## tm.c:l. -0.074 0.062 -1.195 0.232 -0.074 -0.078
##
## Variances:
## Estimate Std.Err z-value P(>|z|) Std.lv Std.all
## alex.c (al..) 0.892 0.041 21.967 0.000 0.892 1.000
## .pubs 0.010 0.001 9.366 0.000 0.010 0.003
## .jobs 0.009 0.001 8.741 0.000 0.009 0.006
## time.c 0.945 0.106 8.919 0.000 0.945 1.000
## tm.c:l. 0.889 0.141 6.309 0.000 0.889 1.000
##
## R-Square:
## Estimate
## pubs 0.997
## jobs 0.994
##
## Defined Parameters:
## Estimate Std.Err z-value P(>|z|) Std.lv Std.all
## indirect.SDblw 0.330 0.060 5.526 0.000 0.330 0.260
## indirect.SDabv 0.672 0.106 6.355 0.000 0.672 0.540
## direct.SDbelow 0.228 0.050 4.529 0.000 0.228 0.182
## direct.SDabove 0.210 0.096 2.183 0.029 0.210 0.168
## total.SDbelow 0.559 0.015 36.414 0.000 0.559 0.443
## total.SDabove 0.882 0.015 59.084 0.000 0.882 0.708
## prp.mdtd.SDblw 0.591 0.095 6.217 0.000 0.591 0.588
## prop.mdtd.SDbv 0.762 0.113 6.741 0.000 0.762 0.763
## index.mod.med 0.181 0.028 6.381 0.000 0.181 0.140
We can also call for bootstrapped confidence interval parameter estimates of all of our effects
#Bootstraps
parameterEstimates(Mod.Med.SEM,
boot.ci.type = "bca.simple",
level = .95, ci = TRUE,
standardized = FALSE)[c(19:27),c(4:10)] #We index the matrix to only display columns we are interested in
## label est se z pvalue ci.lower ci.upper
## 19 indirect.SDbelow 0.330 0.060 5.526 0.000 0.229 0.439
## 20 indirect.SDabove 0.672 0.106 6.355 0.000 0.471 0.837
## 21 direct.SDbelow 0.228 0.050 4.529 0.000 0.141 0.322
## 22 direct.SDabove 0.210 0.096 2.183 0.029 0.046 0.386
## 23 total.SDbelow 0.559 0.015 36.414 0.000 0.546 0.575
## 24 total.SDabove 0.882 0.015 59.084 0.000 0.852 0.892
## 25 prop.mediated.SDbelow 0.591 0.095 6.217 0.000 0.415 0.757
## 26 prop.mediated.SDabove 0.762 0.113 6.741 0.000 0.549 0.948
## 27 index.mod.med 0.181 0.028 6.381 0.000 0.131 0.221
- Our estimates and confidence intervals are almost identical to the “mediation” package estimates
- The difference is most likely a result of bootstrap estimation differences (e.g., lavaan uses bias-corrected but not accelerated bootstrapping for their confidence intervals)
Strengths and limitations of “lavaan” package
- Extremely customizable
- Can also model latent variables if your measurement model requires it
- Tedious! It took me several hours to figure out how the naming conventions worked
- A lot of up front coding required meaning you kind of need to know exactly what you’re looking for in your model
References and Links
References
Hayes, A. F. (2013). Introduction to mediation, moderation, and conditional process analysis: A regression-based approach. New York: The Guilford Press.
Michalak, N. (2016, July 29). Reproducing Hayes’ PROCESS models’ results in R. Retrieved from https://nickmichalak.blogspot.com/2016/07/reproducing-hayess-process-models.html
Rosseel, Y. (2017, February 24). Package ‘lavaan’. Retrieved from https://cran.r-project.org/web/packages/lavaan/lavaan.pdf
Sales, A. C. (2017). Review: Mediation package in R. Journal of Educational and Behavioral Statistics, 42, 1, 69-84.
Tingley, D., Yamamoto, T., Hirose, K., Keele, L., & Imai, K. (2014). Mediation: R package for causal mediation analysis.
LS0tDQp0aXRsZTogJ0NoYXB0ZXIgMTU6IE1vZGVyYXRlZCBNZWRpYXRpb24nDQphdXRob3I6ICJBbnRob255IE4uIFdhc2hidXJuIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIHRoZW1lOiBjZXJ1bGVhbg0KICAgIGhpZ2hsaWdodDogdGV4dG1hdGUNCiAgICBmb250c2l6ZTogOHB0DQogICAgdG9jOiB0cnVlDQogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlDQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KICAgIHRvY19mbG9hdDoNCiAgICAgIGNvbGxhcHNlZDogZmFsc2UNCi0tLQ0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkNCmBgYA0KDQojIFF1aWNrIHJldmlldyBvZiBtb2RlcmF0aW9uIGFuZCBtZWRpYXRpb24NCiMjIE1vZGVyYXRpb24NCg0KIVtCYXNpYyBNb2RlcmF0aW9uIE1vZGVsXShodHRwczovL2Fud2FzaGJ1cm4uZmlsZXMud29yZHByZXNzLmNvbS8yMDE3LzA0L21vZGVyYXRpb24ucG5nICJNb2RlcmF0aW9uIEltYWdlIikNCg0KLSBNb2RlcmF0aW9uIHRlc3RzIHRoZSBpbmZsdWVuY2Ugb2YgYSB0aGlyZCB2YXJpYWJsZSAoWikgb24gdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIFggdG8gWQ0KLSBYIC0+IFkgKGRlcGVuZGluZyBvbiBaKQ0KLSBGb3IgYSByZXZpZXcgc2VlIFtDaGFwdGVyIDE0OiBNZWRpYXRpb24gYW5kIE1vZGVyYXRpb25dKGh0dHA6Ly9hZGVtb3MucGVvcGxlLnVpYy5lZHUvQ2hhcHRlcjE0Lmh0bWwpDQoNCg0KIyMgTWVkaWF0aW9uDQoNCiFbQmFzaWMgTWVkaWF0aW9uIE1vZGVsXShodHRwczovL2Fud2FzaGJ1cm4uZmlsZXMud29yZHByZXNzLmNvbS8yMDE3LzA0L21lZGlhdGlvbi5wbmcgIk1lZGlhdGlvbiBJbWFnZSIpDQoNCi0gTWVkaWF0aW9uIHRlc3RzIGEgaHlwb3RoZXRpY2FsIGNhdXNhbCBjaGFpbiB3aGVyZSB0aGUgZWZmZWN0IG9mIG9uZSB2YXJpYWJsZSAoWCkgb24gYW5vdGhlciB2YXJpYWJsZSAoWSkgaXMgbWVkaWF0ZWQsIG9yIGV4cGxhaW5lZCwgYnkgYSB0aGlyZCB2YXJpYWJsZSAoTSkNCi0gWCAtPiBNIC0+IFkNCi0gRm9yIGEgcmV2aWV3IHNlZSBbQ2hhcHRlciAxNDogTWVkaWF0aW9uIGFuZCBNb2RlcmF0aW9uXShodHRwOi8vYWRlbW9zLnBlb3BsZS51aWMuZWR1L0NoYXB0ZXIxNC5odG1sKQ0KDQojIFdoYXQgaXMgbW9kZXJhdGVkIG1lZGlhdGlvbj8NCiMjIENvbmNlcHR1YWwgZGVmaW5pdGlvbg0KDQohW0Jhc2ljIE1vZGVyYXRlZCBNZWRpYXRpb24gTW9kZWxdKGh0dHBzOi8vYW53YXNoYnVybi5maWxlcy53b3JkcHJlc3MuY29tLzIwMTcvMDQvbW9kbWVkaW1hZ2UyLnBuZyAiTW9kZXJhdGVkIE1lZGlhdGlvbiBJbWFnZSIpDQoNCi0gTW9kZXJhdGVkIG1lZGlhdGlvbiB0ZXN0cyB0aGUgaW5mbHVlbmNlIG9mIGEgZm91cnRoIChvciBtb3JlKSB2YXJpYWJsZSBvbiB0aGUgbWVkaWF0ZWQgcmVsYXRpb25zaGlwIGJldHdlZW4gWCBhbmQgWQ0KLSBUaGUgZWZmZWN0IG9mIHRoZSBtZWRpYXRvciBpcyBtb2RlcmF0ZWQgYnkgYW5vdGhlciB2YXJpYWJsZQ0KLSBYIC0+IE0gLT4gWSAoZGVwZW5kaW5nIG9uIFopDQotIFRoZSBtb2RlcmF0aW9uIGNhbiBvY2N1ciBvbiBhbnkgYW5kIGFsbCBwYXRocyBpbiB0aGUgbWVkaWF0aW9uIG1vZGVsIChlLmcuLCBhIHBhdGgsIGIgcGF0aCwgYyBwYXRoLCBvciBhbnkgY29tYmluYXRpb24gb2YgdGhlIHRocmVlKQ0KDQojIyBQcmFjdGljYWwgZGVmaW5pdGlvbiBhbmQgZXhhbXBsZQ0KLSBUaGUgbW9yZSB0aW1lIG9uZSBzcGVuZHMgaW4gZ3JhZHVhdGUgc2Nob29sLCB0aGUgbW9yZSBqb2Igb2ZmZXJzIHRoZXkgaGF2ZSB3aGVuIHRoZXkgZ3JhZHVhdGUNCi0gVGhpcyByZWxhdGlvbnNoaXAgaXMgZXhwbGFpbmVkIGJ5IGluY3JlYXNlZCBwdWJsaWNhdGlvbnMgKGkuZS4sIHRoZSBtb3JlIHRpbWUgc3BlbnQgaW4gZ3JhZCBzY2hvb2wsIHRoZSBtb3JlIHB1YmxpY2F0aW9ucyBvbmUgaGFzLCBhbmQgdGhlIG1vcmUgcHVibGljYXRpb25zIG9uZSBoYXMsIHRoZSBtb3JlIGpvYiBvZmZlcnMgdGhleSBnZXQpDQotIEhvd2V2ZXIsIHRoaXMgY2F1c2FsIGNoYWluIG1heSBvbmx5IHdvcmsgZm9yIHBlb3BsZSB3aG8gc3BlbmQgdGhlaXIgdGltZSBpbiBncmFkdWF0ZSBzY2hvb2wgd2lzZWx5IChpLmUuLCBzcGVuZCB0aW1lIHdpdGggUHJvZmVzc29yIERlbW9zKQ0KLSBIb3cgZG9lcyBzcGVuZGluZyB0aW1lIHdpdGggUHJvZmVzc29yIERlbW9zIGltcGFjdCB0aGUgY2F1c2FsIGNoYWluIGJldHdlZW4gdGltZSBzcGVudCBpbiBncmFkdWF0ZSBzY2hvb2wsIHB1YmxpY2F0aW9ucywgYW5kIGpvYiBvZmZlcnM/IExldCdzIGZpbmQgb3V0Li4uDQoNCiMgTW9kZXJhdGVkIG1lZGlhdGlvbiBkYXRhIGV4YW1wbGUNCiMjIERlc2NyaWJlIHRoZSBkYXRhc2V0DQpXZSBhcmUgZ29pbmcgdG8gc2ltdWxhdGUgYSBkYXRhc2V0IHRoYXQgbWVhc3VyZWQgdGhlIGZvbGxvd2luZzoNCg0KLSBYID0gVGltZSBzcGVudCBpbiBncmFkdWF0ZSBzY2hvb2wgKHdlIHdpbGwgY2hhbmdlIHRoZSBuYW1lIHRvICJ0aW1lIiB3aGVuIHdlIGNyZWF0ZSB0aGUgZGF0YSBmcmFtZSkNCi0gWiA9IFRpbWUgc3BlbnQgKGhvdXJzIHBlciB3ZWVrKSB3aXRoIFByb2Zlc3NvciBEZW1vcyBpbiBjbGFzcyBvciBpbiBvZmZpY2UgaG91cnMNCi0gTSA9IE51bWJlciBvZiBwdWJsaWNhdGlvbnMgaW4gZ3JhZCBzY2hvb2wNCi0gWSA9IE51bWJlciBvZiBqb2Igb2ZmZXJzDQoNCiFbT3VyIEV4YW1wbGUgTW9kZXJhdGVkIE1lZGlhdGlvbiBNb2RlbF0oaHR0cHM6Ly9hbndhc2hidXJuLmZpbGVzLndvcmRwcmVzcy5jb20vMjAxNy8wNC9tb2RtZWRpbWFnZWV4YW1wbGUucG5nICJNb2RlcmF0ZWQgTWVkaWF0aW9uIEV4YW1wbGUgSW1hZ2UiKQ0KDQoNCiMjIENyZWF0ZSB0aGUgZGF0YXNldA0KV2UgYXJlIGludGVudGlvbmFsbHkgY3JlYXRpbmcgYSBtb2RlcmF0ZWQgbWVkaWF0aW9uIGVmZmVjdCBoZXJlIGFuZCB3ZSBkbyBzbyBiZWxvdyBieSBzZXR0aW5nIHRoZSByZWxhdGlvbnNoaXBzICh0aGUgcGF0aHMpIGJldHdlZW4gb3VyIGNhdXNhbCBjaGFpbiB2YXJpYWJsZXMgYW5kIHNldHRpbmcgdGhlIHJlbGF0aW9uc2hpcHMgZm9yIG91ciBpbnRlcmFjdGlvbiB0ZXJtcw0KDQpgc2V0d2QoInBhdGggb2Ygd29ya2luZyBkaXJlY3RvcnkgaGVyZSIpYA0KYGBgIHtyLCBtZXNzYWdlPUZBTFNFLCBlY2hvPVRSVUV9DQpzZXQuc2VlZCg0MikgI1RoaXMgbWFrZXMgc3VyZSB0aGF0IGV2ZXJ5b25lIGdldHMgdGhlIHNhbWUgbnVtYmVycyBnZW5lcmF0ZWQgdGhyb3VnaCBybm9ybSBmdW5jdGlvbg0KDQphMSA9IC0uNTkgI1NldCB0aGUgcGF0aCBhMSBzdHJlbmd0aCAoZWZmZWN0IG9mIFggb24gTSkNCg0KYTIgPSAtLjE3ICNTZXQgcGF0aCBhMiBzdHJlbmd0aCAoZWZmZWN0IG9mIFogb24gTSkNCg0KYTMgPSAuMjkgI1NldCBwYXRoIGEzIHN0cmVuZ3RoIChpbnRlcmFjdGlvbiBiZXR3ZWVuIFggYW5kIFogb24gTSkNCg0KYiA9IC41OSAjU2V0IHBhdGggYiBzdHJlbmd0aCAoZWZmZWN0IG9mIE0gb24gWSkNCg0KY2Rhc2gxID0gLjI3ICNTZXQgcGF0aCBjJzEgc3RyZW5ndGgJKGVmZmVjdCBvZiBYIG9uIFkpDQoNCmNkYXNoMiA9IC4wMSAjU2V0IHBhdGggYycyIHN0cmVuZ3RoIChlZmZlY3Qgb2YgWiBvbiBZKQ0KDQpjZGFzaDMgPSAtLjAxICNTZXQgcGF0aCBjJzMgc3RyZW5ndGggKGludGVyYWN0aW9uIGJldHdlZSBYIGFuZCBaIG9uIFkpDQpgYGANCkhlcmUgd2UgYXJlIGNyZWF0aW5nIHRoZSB2YWx1ZXMgb2Ygb3VyIHZhcmlhYmxlcyBmb3IgZWFjaCBzdWJqZWN0DQpgYGAge3IsIG1lc3NhZ2U9RkFMU0UsIGVjaG89VFJVRX0NCm4gPC0gMjAwICNTZXQgc2FtcGxlIHNpemUNCg0KWCA8LSBybm9ybShuLCA3LCAxKSAjSVY6IFRpbWUgc3BlbnQgaW4gZ3JhZCBzY2hvb2wgKE0gPSA3LCBTRCA9IDEpDQoNClogPC0gcm5vcm0obiwgNSwgMSkgI01vZGVyYXRvcjogVGltZSBzcGVudCAoaG91cnMgcGVyIHdlZWspIHdpdGggUHJvZmVzc29yIERlbW9zIGluIGNsYXNzIG9yIGluIG9mZmljZSBob3VycyAoTSA9IDUsIFNEID0gMSkNCg0KTSA8LSBhMSpYICsgYTIqWiArIGEzKlgqWiArIHJub3JtKG4sIDAsIC4xKSAjTWVkaWF0b3I6IE51bWJlciBvZiBwdWJsaWNhdGlvbnMgaW4gZ3JhZCBzY2hvb2wNCiNUaGUgbWVkaWF0b3IgdmFyaWFibGUgaXMgY3JlYXRlZCBhcyBhIGZ1bmN0aW9uIG9mIHRoZSBJViwgbW9kZXJhdG9yLCBhbmQgdGhlaXIgaW50ZXJhY3Rpb24gd2l0aCBzb21lIHJhbmRvbSBub2lzZSB0aHJvd24gaW4gdGhlIG1peA0KDQpZIDwtIGNkYXNoMSpYICsgY2Rhc2gyKlogKyBjZGFzaDMqWCpaICsgYipNICsgcm5vcm0obiwgMCwgLjEpICNEVjogTnVtYmVyIG9mIGpvYiBvZmZlcnMNCiNTaW1pbGFyIHRvIHRoZSBtZWRpYXRvciwgdGhlIERWIGlzIGEgZnVuY3Rpb24gb2YgdGhlIElWLCBtb2RlcmF0b3IsIHRoZWlyIGludGVyYWN0aW9uLCBhbmQgdGhlIG1lZGlhdG9yIHdpdGggc29tZSByYW5kb20gbm9pc2UgdGhyb3duIGluIHRoZSBtaXgNCmBgYA0KTm93IHdlIHB1dCBpdCBhbGwgdG9nZXRoZXIgYW5kIG1ha2Ugb3VyIGRhdGEgZnJhbWUNCmBgYCB7ciwgbWVzc2FnZT1GQUxTRSwgZWNobz1UUlVFfQ0KU3VjY2Vzcy5Nb2RNZWQgPC0gZGF0YS5mcmFtZShqb2JzID0gWSwgdGltZSA9IFgsIHB1YnMgPSBNLCBhbGV4ID0gWikgI0J1aWxkIG91ciBkYXRhIGZyYW1lIGFuZCBnaXZlIGl0IHJlY29nbml6YWJsZSB2YXJpYWJsZSBuYW1lcw0KYGBgDQoNCiMjIEV4YW1pbmUgdGhlIGRhdGFzZXQgYW5kIHByZXBhcmUgZm9yIHJlZ3Jlc3Npb24gYW5hbHlzZXMNCg0KYGluc3RhbGwucGFja2FnZXMoInBzeWNoIikgI2luc3RhbGwgdGhpcyBwYWNrYWdlIGlmIG5vdCBhbHJlYWR5IGluc3RhbGxlZGANCmBgYCB7ciwgbWVzc2FnZT1GQUxTRSwgZWNobz1UUlVFfQ0KbGlicmFyeShwc3ljaCkgI0hlbHBmdWwgZm9yIGNvbW1vbiBwc3ljaCBkZXNjcmlwdGl2ZSBzdGF0aXN0aWNzDQoNCnN0cihTdWNjZXNzLk1vZE1lZCkgI0V4YW1pbmUgdGhlIHN0cnVjdHVyZSBvZiB0aGUgZGF0YXNldA0KDQpyb3VuZChkZXNjcmliZShTdWNjZXNzLk1vZE1lZClbLGMoMjo1LDgsOSwxMyldLCAyKSAjUHV0IGRlc2NyaXB0aXZlIHN0YXRzIHN1bW1hcnkgaW50byB0YWJsZSB3aXRoIG9ubHkgdGhlIGNvbHVtbnMgb2YgaW5mb3JtYXRpb24gdGhhdCB3ZSBjYXJlIGFib3V0DQpgYGANCkJlY2F1c2Ugd2UgaGF2ZSBpbnRlcmFjdGlvbiB0ZXJtcyBpbiBvdXIgcmVncmVzc2lvbiBhbmFseXNlcywgd2UgbmVlZCB0byBtZWFuIGNlbnRlciBvdXIgSVYgYW5kIE1vZGVyYXRvciAoWikNCmBgYCB7ciwgbWVzc2FnZT1GQUxTRSwgZWNobz1UUlVFfQ0KU3VjY2Vzcy5Nb2RNZWQkdGltZS5jIDwtIHNjYWxlKFN1Y2Nlc3MuTW9kTWVkJHRpbWUsIGNlbnRlciA9IFRSVUUsIHNjYWxlID0gRkFMU0UpWyxdICNTY2FsZSByZXR1cm5zIGEgbWF0cml4IHNvIHdlIGhhdmUgdG8gbWFrZSBpdCBhIHZlY3RvciBieSBpbmRleGluZyBvbmUgY29sdW1uDQoNClN1Y2Nlc3MuTW9kTWVkJGFsZXguYyA8LSBzY2FsZShTdWNjZXNzLk1vZE1lZCRhbGV4LCBjZW50ZXIgPSBUUlVFLCBzY2FsZSA9IEZBTFNFKVssXQ0KYGBgDQoNCiMgTW9kZXJhdGVkIG1lZGlhdGlvbiBhbmFseXNlcyB1c2luZyAibWVkaWF0aW9uIiBwYWNrYWdlDQpXZSB3aWxsIGZpcnN0IGNyZWF0ZSB0d28gcmVncmVzc2lvbiBtb2RlbHMsIG9uZSBsb29raW5nIGF0IHRoZSBlZmZlY3Qgb2Ygb3VyIElWcyAodGltZSBzcGVudCBpbiBncmFkIHNjaG9vbCwgdGltZSBzcGVudCB3aXRoIEFsZXgsIGFuZCB0aGVpciBpbnRlcmFjdGlvbikgb24gb3VyIG1lZGlhdG9yIChudW1iZXIgb2YgcHVibGljYXRpb25zKSwgYW5kIG9uZSBsb29raW5nIGF0IHRoZSBlZmZlY3Qgb2Ygb3VyIElWcyBhbmQgbWVkaWF0b3Igb24gb3VyIERWIChudW1iZXIgb2Ygam9iIG9mZmVycykuDQoNCk5leHQsIHdlIHdpbGwgZXhhbWluZSB0aGUgaW5mbHVlbmNlIG9mIG91ciBtb2RlcmF0aW5nIHZhcmlhYmxlICh0aW1lIHNwZW50IHdpdGggQWxleCkgb24gdGhlIG1lZGlhdGlvbiBlZmZlY3Qgb2YgdGltZSBzcGVudCBpbiBncmFkIHNjaG9vbCBvbiBudW1iZXIgb2Ygam9iIG9mZmVycywgdGhyb3VnaCBudW1iZXIgb2YgcHVibGljYXRpb25zLiBUbyBkbyB0aGlzLCB3ZSB3aWxsIGV4YW1pbmUgdGhlIG1lZGlhdGlvbiBlZmZlY3QgZm9yIHRob3NlIHdobyBzcGVuZCBhIGxvdCBvZiB0aW1lIHdpdGggQWxleCB2ZXJzdXMgdGhvc2Ugd2hvIHNwZW5kIGxpdHRsZSB0aW1lIHdpdGggQWxleC4NCg0KIyMgQ3JlYXRlIHRoZSBuZWNlc3NhcnkgcmVncmVzc2lvbiBtb2RlbHMNCldlIG5lZWQgdHdvIHJlZ3Jlc3Npb24gbW9kZWxzIHRvIHVzZSB0aGUgbWVkaWF0aW9uIHBhY2thZ2UNCg0KT25lIG1vZGVsIHNwZWNpZmllcyB0aGUgZWZmZWN0IG9mIG91ciBJViAodGltZSBzcGVudCBpbiBncmFkIHNjaG9vbCkgb24gb3VyIE1lZGlhdG9yIChudW1iZXIgb2YgcHVibGljYXRpb25zKSBbYW5kIGluIG91ciBjYXNlLCBvdXIgbW9kZXJhdG9yICh0aW1lIHNwZW50IHdpdGggQWxleCkgYW5kIHRoZSBpbnRlcmFjdGlvbl0NCg0KVGhlIG90aGVyIG1vZGVsIHNwZWNpZmllcyB0aGUgZWZmZWN0IG9mIHRoZSBJViAodGltZSBzcGVudCBpbiBncmFkIHNjaG9vbCkgYW5kIE1lZGlhdG9yIChudW1iZXIgb2YgcHVibGljYXRpb25zKSAoYW5kIHBvc3NpYmx5IG1vZGVyYXRvciBhcyB3ZWxsKSBvbiBvdXIgRFYgKG51bWJlciBvZiBqb2Igb2ZmZXJzKQ0KDQpgaW5zdGFsbC5wYWNrYWdlcygibWVkaWF0aW9uIikgI2luc3RhbGwgdGhpcyBmaXJzdCBpZiBub3QgYWxyZWFkeSBpbnN0YWxsZWRgDQpgYGAge3IsIG1lc3NhZ2U9RkFMU0UsIGVjaG89VFJVRX0NCmxpYnJhcnkobWVkaWF0aW9uKQ0KDQptZWRpYXRlIDwtIG1lZGlhdGlvbjo6bWVkaWF0ZSAjQSBtZWRpYXRlIGZ1bmN0aW9uIGlzIGluIGJvdGggdGhlICJwc3ljaCIgYW5kICJtZWRpYXRpb24iIHBhY2thZ2VzLiBUaGlzIGFsbG93cyB1cyB0byB1c2UgdGhlIGNvcnJlY3QgbWVkaWF0ZSBmdW5jdGlvbiBmcm9tIHRoZSAibWVkaWF0aW9uIiBwYWNrYWdlDQoNCk1vZC5NZWQuTW9kZWwuMTwtbG0ocHVicyB+IHRpbWUuYyphbGV4LmMsIGRhdGEgPSBTdWNjZXNzLk1vZE1lZCkgI1RoaXMgbW9kZWwgcHJlZGljdHMgbnVtYmVyIG9mIHB1YmxpY2F0aW9ucyBmcm9tIHRpbWUgc3BlbnQgaW4gZ3JhZCBzY2hvb2wsIHRpbWUgc3BlbnQgd2l0aCBhbGV4LCBhbmQgdGhlIGludGVyYWN0aW9uIGJldHdlZW4gdGhlIHR3bw0KDQpzdW1tYXJ5KE1vZC5NZWQuTW9kZWwuMSkNCmBgYA0KLSBTaWduaWZpY2FudCBtYWluIGVmZmVjdCBvZiB0aW1lIHNwZW50IGluIGdyYWQgc2Nob29sIG9uIG51bWJlciBvZiBwdWJsaWNhdGlvbnMNCi0gU2lnbmlmaWNhbnQgbWFpbiBlZmZlY3Qgb2YgdGltZSBzcGVudCB3aXRoIEFsZXggb24gbnVtYmVyIG9mIHB1YmxpY2F0aW9ucw0KLSBTaWduaWZpY2FudCBpbnRlcmFjdGlvbiBiZXR3ZWVuIHRpbWUgc3BlbnQgaW4gZ3JhZCBzY2hvb2wgYW5kIHRpbWUgc3BlbnQgd2l0aCBBbGV4IG9uIG51bWJlciBvZiBwdWJsaWNhdGlvbnMNCmBgYCB7ciwgbWVzc2FnZT1GQUxTRSwgZWNobz1UUlVFfQ0KTW9kLk1lZC5Nb2RlbC4yPC1sbShqb2JzIH4gdGltZS5jKmFsZXguYyArIHB1YnMsIGRhdGEgPSBTdWNjZXNzLk1vZE1lZCkgI1RoaXMgbW9kZWwgcHJlZGljdHMgbnVtYmVyIG9mIGpvYiBvZmZlcnMgZnJvbSB0aW1lIHNwZW50IGluIGdyYWQgc2Nob29sLCB0aW1lIHNwZW50IHdpdGggYWxleCwgbnVtYmVyIG9mIHB1YmxpY2F0aW9ucywgYW5kIHRoZSBpbnRlcmFjdGlvbiBiZXR3ZWVuIHRpbWUgc3BlbnQgaW4gZ3JhZCBzY2hvb2wgYW5kIHRpbWUgc3BlbnQgd2l0aCBhbGV4DQoNCnN1bW1hcnkoTW9kLk1lZC5Nb2RlbC4yKQ0KYGBgDQotIFNpZ25pZmljYW50IG1haW4gZWZmZWN0IG9mIHRpbWUgc3BlbnQgaW4gZ3JhZCBzY2hvb2wgb24gbnVtYmVyIG9mIGpvYiBvZmZlcnMNCi0gTm8gZWZmZWN0IG9mIHRpbWUgc3BlbnQgd2l0aCBBbGV4IG9uIG51bWJlciBvZiBqb2Igb2ZmZXJzDQotIFNpZ25pZmljYW50IG1haW4gZWZmZWN0IG9mIG51bWJlciBvZiBwdWJsaWNhdGlvbnMgb24gbnVtYmVyIG9mIGpvYiBvZmZlcnMNCi0gTm8gaW50ZXJhY3Rpb24gYmV0d2VlbiB0aW1lIHNwZW50IGluIGdyYWQgc2Nob29sIGFuZCB0aW1lIHNwZW50IHdpdGggQWxleCBvbiBudW1iZXIgb2Ygam9iIG9mZmVycw0KDQojIyBFeGFtaW5lIHRoZSBlZmZlY3Qgb2Ygb3VyIG1vZGVyYXRvciBvbiB0aGUgbWVkaWF0aW9uIGVmZmVjdA0KSW4gdGhpcyBtZWRpYXRpb24gcGFja2FnZSB3ZSBsaXN0IHRoZSBtb2RlcmF0b3IgYXMgYSBjb3ZhcmlhdGUgYW5kIHNldCB0aGUgbGV2ZWxzIHRvIHdoYXQgd2Ugd2FudA0KDQpXZSBjYW4gdXNlIHRoZSArLy0gMVNEIGZyb20gdGhlIG1lYW4gKG9yIGFub3RoZXIgdmFsdWUgdGhhdCBpcyB0aGVvcmV0aWNhbGx5IGltcG9ydGFudCkNCg0KVGhpcyBhbGxvd3MgdXMgdG8gdmlldyBpbXBhY3Qgb2YgdGhlIG1vZGVyYXRvciBvbiB0aGUgZGlyZWN0IGFuZCBpbmRpcmVjdCBlZmZlY3RzDQoNCkxldHMgbG9vayBhdCBncmFkIHN0dWRlbnRzIHdobyBzcGVuZCBsaXR0bGUgdGltZSB3aXRoIEFsZXggZmlyc3QNCmBgYCB7ciwgbWVzc2FnZT1GQUxTRSwgZWNobz1UUlVFfQ0KI01vZGVyYXRvciBtdXN0IGJlIGluIGJvdGggbW9kZWxzIGZvciBtZWRpYXRlIHRvIHdvcmsuDQpsb3cuYWxleDwtbWVhbihTdWNjZXNzLk1vZE1lZCRhbGV4LmMpLXNkKFN1Y2Nlc3MuTW9kTWVkJGFsZXguYykJI1NldHMgb3VyIGxldmVsIGZvciAxIFNEIGJlbG93IG1lYW4gb2YgYWxleC5jDQoNCmxvdy5hbGV4ICNDaGVjayB2YWx1ZSBvZiB2YXJpYWJsZQ0KTW9kLk1lZC5Mb3dBbGV4IDwtIG1lZGlhdGUoTW9kLk1lZC5Nb2RlbC4xLCBNb2QuTWVkLk1vZGVsLjIsIAkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvdmFyaWF0ZXMgPSBsaXN0KGFsZXguYyA9IGxvdy5hbGV4KSwgYm9vdCA9IFRSVUUsIAkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGJvb3QuY2kudHlwZSA9ICJiY2EiLCBzaW1zID0gMTAsIHRyZWF0PSJ0aW1lLmMiLCBtZWRpYXRvcj0icHVicyIpDQojVGhlIG1lZGlhdGUgZnVuY3Rpb24gY2FuIGhhbmRsZSBkaWZmZXJlbnQgdHlwZXMgb2YgQ0kgZXN0aW1hdGlvbi4gSGVyZSB3ZSBhcmUgYXNraW5nIGZvciBiaWFzLWNvcnJlY3RlZCBhbmQgYWNjZWxlcmF0ZWQgY29uZmlkZW5jZSBpbnRlcnZhbHMgYmVjYXVzZSB0aGlzIGdpdmVzIHVzIG1vcmUgYWNjdXJhdGUgY29uZmlkZW50IGludGVydmFsIGVzdGltYXRlcyBhbmQgY29ycmVjdHMgZm9yIGRldmlhdGlvbiBmcm9tIG5vcm1hbGl0eSANCiNXZSBhbHNvIGhhdmUgdG8gc3BlY2lmeSBvdXIgSVYgKHRyZWF0KSBhbmQgTWVkaWF0b3IocHVicykNCiNGb3IgZGVtb25zdHJhdGlvbiBJIGFtIG9ubHkgZG9pbmcgMTAgc2ltdWxhdGlvbnMsIGJ1dCBpbiByZWFsaXR5IHlvdSdkIHdhbnQgdG8gZG8gYXQgbGVhc3QgMiwwMDANCmBgYA0KRm9yIGEgcmV2aWV3IG9uIGJvb3RzdHJhcHBpbmcgdGVjaG5pcXVlcywgc2VlIFtFZnJvbiwgMjAwM10oaHR0cDovL3Byb2plY3RldWNsaWQub3JnL2Rvd25sb2FkL3BkZl8xL2V1Y2xpZC5zcy8xMDYzOTk0OTY4KQ0KDQotIEFDTUU6IEF2ZXJhZ2UgQ2F1c2FsIE1lZGlhdGlvbiBFZmZlY3QgW3RvdGFsIGVmZmVjdCAtIGRpcmVjdCBlZmZlY3RdCQ0KLSBBREU6IEF2ZXJhZ2UgRGlyZWN0IEVmZmVjdCBbdG90YWwgZWZmZWN0IC0gaW5kaXJlY3QgZWZmZWN0XQkNCi0gVG90YWwgRWZmZWN0OiBEaXJlY3QgKEFERSkgKyBJbmRpcmVjdCAoQUNNRSkgCQ0KLSBQcm9wLiBNZWRpYXRlZDogIENvbmNlcHR1YWxseSBBQ01FIC8gVG90YWwgZWZmZWN0IChUaGlzIHRlbGxzIHVzIGhvdyBtdWNoIG9mIHRoZSB0b3RhbCBlZmZlY3Qgb3VyIGluZGlyZWN0IGVmZmVjdCBpcyAiZXhwbGFpbmluZyIpDQpgYGAge3IsIG1lc3NhZ2U9RkFMU0UsIGVjaG89VFJVRX0NCnN1bW1hcnkoTW9kLk1lZC5Mb3dBbGV4KQ0KYGBgDQoNCmBgYCB7ciwgbWVzc2FnZT1GQUxTRSwgZWNobz1UUlVFfQ0KcGxvdChNb2QuTWVkLkxvd0FsZXgsIHhsaW0gPSAwOjEpDQpgYGANCg0KLSBTaWduaWZpY2FudCBkaXJlY3QgZWZmZWN0IG9mIHRpbWUgc3BlbnQgaW4gZ3JhZCBzY2hvb2wgb24gam9iIG9mZmVycyAoZm9yIHRob3NlIHdobyBkb24ndCBzcGVuZCBhIGxvdCBvZiB0aW1lIHdpdGggQWxleCkNCi0gU2lnbmlmaWNhbnQgaW5kaXJlY3QgZWZmZWN0IG9mIHRpbWUgc3BlbnQgaW4gZ3JhZCBzY2hvb2wgb24gam9iIG9mZmVycyB0aHJvdWdoIHB1YmxpY2F0aW9ucyAoZm9yIHRob3NlIHdobyBkb24ndCBzcGVuZCBhIGxvdCBvZiB0aW1lIHdpdGggQWxleCkNCg0KTm93IGxldCdzIGxvb2sgYXQgZ3JhZCBzdHVkZW50cyB3aG8gc3BlbmQgYSBsb3Qgb2YgdGltZSB3aXRoIEFsZXgNCmBgYCB7ciwgbWVzc2FnZT1GQUxTRSwgZWNobz1UUlVFfQ0KaGlnaC5hbGV4PC1tZWFuKFN1Y2Nlc3MuTW9kTWVkJGFsZXguYykrc2QoU3VjY2Vzcy5Nb2RNZWQkYWxleC5jKQ0KDQpoaWdoLmFsZXgNCk1vZC5NZWQuSGlnaEFsZXggPC0gbWVkaWF0ZShNb2QuTWVkLk1vZGVsLjEsIE1vZC5NZWQuTW9kZWwuMiwgCQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvdmFyaWF0ZXMgPSBsaXN0KGFsZXguYyA9IGhpZ2guYWxleCksIGJvb3QgPSBUUlVFLCAJDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgYm9vdC5jaS50eXBlID0gImJjYSIsIHNpbXMgPSAxMCwgdHJlYXQ9InRpbWUuYyIsIG1lZGlhdG9yPSJwdWJzIikNCg0Kc3VtbWFyeShNb2QuTWVkLkhpZ2hBbGV4KQkNCnBsb3QoTW9kLk1lZC5IaWdoQWxleCwgeGxpbSA9IDA6MSkNCmBgYA0KDQotIFNpZ25pZmljYW50IGRpcmVjdCBlZmZlY3Qgb2YgdGltZSBzcGVudCBpbiBncmFkIHNjaG9vbCBvbiBqb2Igb2ZmZXJzIChmb3IgdGhvc2Ugd2hvIHNwZW5kIGEgbG90IG9mIHRpbWUgd2l0aCBBbGV4KQ0KLSBTaWduaWZpY2FudCBpbmRpcmVjdCBlZmZlY3Qgb2YgdGltZSBzcGVudCBpbiBncmFkIHNjaG9vbCBvbiBqb2Igb2ZmZXJzIHRocm91Z2ggcHVibGljYXRpb25zIChmb3IgdGhvc2Ugd2hvIHNwZW5kIGEgbG90IG9mIHRpbWUgd2l0aCBBbGV4KQ0KLSBUaGUgaW5kaXJlY3QgZWZmZWN0IGxvb2tzIGxhcmdlciBmb3IgdGhvc2Ugd2hvIHNwZW5kIGEgbG90IG9mIHRpbWUgd2l0aCBBbGV4IGNvbXBhcmVkIHRvIHRob3NlIHdobyBkb24ndCwgYnV0IHdlIGNhbiB0ZXN0IHRoaXMgdG8gbWFrZSBzdXJlDQoNCg0KVGhlIGZvbGxvd2luZyBjb2RlIHRlc3RzIHdoZXRoZXIgdGhlIGRpZmZlcmVuY2UgYmV0d2VlbiBpbmRpcmVjdCBlZmZlY3RzIGF0IGVhY2ggbGV2ZWwgb2YgdGhlIG1vZGVyYXRvciBpcyBzaWduaWZpY2FudGx5IGRpZmZlcmVudCBmcm9tIHplcm8NCmBgYCB7ciwgbWVzc2FnZT1GQUxTRSwgZWNobz1UUlVFfQ0KTW9kLk1lZC5UZXN0QWxleCA8LSBtZWRpYXRlKE1vZC5NZWQuTW9kZWwuMSwgTW9kLk1lZC5Nb2RlbC4yLCBib290ID0gVFJVRSwgCQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJvb3QuY2kudHlwZSA9ICJiY2EiLCBzaW1zID0gMTAsIHRyZWF0PSJ0aW1lLmMiLCBtZWRpYXRvcj0icHVicyIpCSNXZSBkb24ndCBzcGVjaWZ5IGFueXRoaW5nIGFib3V0IHRoZSBtb2RlcmF0b3IgaW4gdGhpcyBjb2RlIHlldA0KDQp0ZXN0Lm1vZG1lZChNb2QuTWVkLlRlc3RBbGV4LCBjb3ZhcmlhdGVzLjEgPSBsaXN0KGFsZXguYyA9IGxvdy5hbGV4KSwJDQogICAgICAgICAgICBjb3ZhcmlhdGVzLjIgPSBsaXN0KGFsZXguYyA9IGhpZ2guYWxleCksIHNpbXMgPSAxMCkJI0hlcmUgd2Ugc3BlY2lmeSBib3RoIGxldmVscyBvZiB0aGUgbW9kZXJhdG9yIHRoYXQgd2Ugd2FudCB0byB0ZXN0DQpgYGANCg0KLSBXZSBjYW4gc2VlIHRoYXQgdGhlIGluZGlyZWN0IGVmZmVjdHMgYXJlIHNpZ25pZmljYW50bHkgZGlmZmVyZW50IHN1Y2ggdGhhdCB0aGUgZWZmZWN0IG9mIHNwZW5kaW5nIHRpbWUgaW4gZ3JhZHVhdGUgc2Nob29sIG9uIGdldHRpbmcgam9iIG9mZmVycyB0aHJvdWdoIHB1YmxpY2F0aW9ucyBpcyBzdHJvbmdlciBmb3IgdGhvc2Ugc3R1ZGVudHMgd2hvIHNwZW5kIGEgbG90IG9mIHRpbWUgd2l0aCBBbGV4IGNvbXBhcmVkIHRvIHRob3NlIHdobyBkbyBub3QNCi0gVGhlcmUgaXMgbm8gZGlmZmVyZW50IGluIHRoZSBzaXplIG9mIHRoZSBkaXJlY3QgZWZmZWN0cywgaG93ZXZlcg0KDQojIyBTdHJlbmd0aHMgYW5kIGxpbWl0YXRpb25zIG9mICJtZWRpYXRpb24iIHBhY2thZ2UNCi0gQ29kZSBpcyBmYWlybHkgc3RyYWlnaHRmb3J3YXJkIGFuZCBtYWtlcyBpbnR1aXRpdmUgc2Vuc2UgaW4gaG93IHRvIHNwZWNpZnkgbGV2ZWxzIG9mIG1vZGVyYXRvcnMNCi0gQ29tcGF0aWJsZSB3aXRoIG1hbnkgdHlwZXMgb2YgcmVncmVzc2lvbiwgaW5jbHVkaW5nIGxpbmVhciwgZ2xtLCBvcmRlcmVkLCBjZW5zb3JlZCwgcXVhbnRpbGUsIEdBTSwgYW5kIHN1cnZpdmFsDQotIExpbWl0ZWQgaW4gdGhlIHR5cGVzIG9mIG1vZGVyYXRlZCBtZWRpYXRpb24gbW9kZWxzIGl0IGNhbiBlc3RpbWF0ZQ0KLSBNdXN0IGluY2x1ZGUgbW9kZXJhdG9yIGluIGJvdGggbW9kZWxzIChtZWFuaW5nIHRoYXQgeW91IGNhbm5vdCBtb2RlbCB0d28gb2YgdGhlIG1vc3QgcG9wdWxhciBtb2RlcmF0ZWQgbWVkaWF0aW9uIG1vZGVscywgSGF5ZXMnIE1vZGVsIDcgYW5kIE1vZGVsIDE0KQ0KLSBDYW5ub3QgaGFuZGxlIGhpZ2hseSBjb21wbGV4IG1lZGlhdGlvbmFsIG1vZGVscyB3aXRoIHNldmVyYWwgY2F1c2FsbHkgZGVwZW5kZW50IG1lZGlhdG9ycyBhbmQgbW9kZXJhdG9ycw0KLSBIb3dldmVyLCBzdHJ1Y3R1cmFsIGVxdWF0aW9uIG1vZGVsIChTRU0pIHByb2dyYW1zIGNhbiBtb2RlbCBtb3JlIGNvbXBsZXggbW9kZWxzLCB3aGljaCB3ZSB0dXJuIHRvIG5leHQNCg0KIyBNb2RlcmF0ZWQgbWVkaWF0aW9uIGFuYWx5c2VzIHVzaW5nICJsYXZhYW4iIHBhY2thZ2UNCkluICJsYXZhYW4iIHdlIHNwZWNpZnkgYWxsIHJlZ3Jlc3Npb25zIGFuZCByZWxhdGlvbnNoaXBzIGJldHdlZW4gb3VyIHZhcmlhYmxlcyBpbiBvbmUgb2JqZWN0DQoNCldlIGNhbiBzcGVjaWZ5IHRoZSBlZmZlY3RzIHdlIHdhbnQgdG8gc2VlIGluIG91ciBvdXRwdXQgKGUuZy4sIGRpcmVjdCwgaW5kaXJlY3QsIGV0Yy4pDQoNCldlIGNhbiBhbHNvIGNvbXB1dGUgbWVhbnMgYW5kIHN0YW5kYXJkIGRldmlhdGlvbnMgZm9yIHVzZSBpbiBzaW1wbGUgc2xvcGVzIGFuYWx5c2VzDQoNCkFmdGVyIHNwZWNpZnlpbmcgYWxsIHRoZSBuZWNlc3NhcnkgY29tcG9uZW50cywgd2UgZml0IHRoZSBtb2RlbCB1c2luZyBhbiBTRU0gZnVuY3Rpb24NCg0KYGluc3RhbGwucGFja2FnZXMoImxhdmFhbiIpICNpbnN0YWxsIHRoaXMgZmlyc3QgaWYgbm90IGFscmVhZHkgaW5zdGFsbGVkYA0KYGBgIHtyLCBtZXNzYWdlPUZBTFNFLCBlY2hvPVRSVUV9DQpsaWJyYXJ5KGxhdmFhbikNCg0KTW9kLk1lZC5MYXZhYW4gPC0gJw0KI1JlZ3Jlc3Npb25zDQojVGhlc2UgYXJlIHRoZSBzYW1lIHJlZ3Jlc3Npb24gZXF1YXRpb25zIGZyb20gb3VyIHByZXZpb3VzIGV4YW1wbGUNCiNFeGNlcHQgaW4gdGhpcyBjb2RlIHdlIGFyZSBuYW1pbmcgdGhlIGNvZWZmaWNpZW50cyB0aGF0IGFyZSBwcm9kdWNlZCBmcm9tIHRoZSByZWdyZXNzaW9uIGVxdWF0aW9ucw0KI0UuZy4sIHRoZSByZWdyZXNzaW9uIGNvZWZmaWNpZW50IGZvciB0aGUgZWZmZWN0IG9mIHRpbWUgb24gcHVicyBpcyBuYW1lZCAiYTEiDQpwdWJzIH4gYTEqdGltZS5jICsgYTIqYWxleC5jICsgYTMqdGltZS5jOmFsZXguYw0Kam9icyB+IGNkYXNoMSp0aW1lLmMgKyBjZGFzaDIqYWxleC5jICsgY2Rhc2gzKnRpbWUuYzphbGV4LmMgKyBiMSpwdWJzDQoNCiNNZWFuIG9mIGNlbnRlcmVkIGFsZXggKGZvciB1c2UgaW4gc2ltcGxlIHNsb3BlcykNCiNUaGlzIGlzIG1ha2luZyBhIGNvZWZmaWNpZW50IGxhYmVsZWQgImFsZXguYy5tZWFuIiB3aGljaCBlcXVhbHMgdGhlIGludGVyY2VwdCBiZWNhdXNlIG9mIHRoZSAiMSINCiMoWX4xKSBnaXZlcyB5b3UgdGhlIGludGVyY2VwdCwgd2hpY2ggaXMgdGhlIG1lYW4gZm9yIG91ciBhbGV4LmMgdmFyaWFibGUNCmFsZXguYyB+IGFsZXguYy5tZWFuKjENCg0KI1ZhcmlhbmNlIG9mIGNlbnRlcmVkIGFsZXggKGZvciB1c2UgaW4gc2ltcGxlIHNsb3BlcykNCiNUaGlzIGlzIG1ha2luZyBhIGNvZWZmaWNpZW50IGxhYmVsZWQgImFsZXguYy52YXIiIHdoaWNoIGVxdWFscyB0aGUgdmFyaWFuY2UgYmVjYXVzZSBvZiB0aGUgIn5+Ig0KI1R3byB0aWxkZXMgc2VwYXJhdGluZyB0aGUgc2FtZSB2YXJpYWJsZSBnaXZlcyB5b3UgdGhlIHZhcmlhbmNlDQphbGV4LmMgfn4gYWxleC5jLnZhciphbGV4LmMNCg0KI0luZGlyZWN0IGVmZmVjdHMgY29uZGl0aW9uYWwgb24gbW9kZXJhdG9yIChhMSArIGEzKk1vZFZhbHVlKSpiMQ0KaW5kaXJlY3QuU0RiZWxvdyA6PSAoYTEgKyBhMyooYWxleC5jLm1lYW4tc3FydChhbGV4LmMudmFyKSkpKmIxDQppbmRpcmVjdC5TRGFib3ZlIDo9IChhMSArIGEzKihhbGV4LmMubWVhbitzcXJ0KGFsZXguYy52YXIpKSkqYjENCg0KI0RpcmVjdCBlZmZlY3RzIGNvbmRpdGlvbmFsIG9uIG1vZGVyYXRvciAoY2Rhc2gxICsgY2Rhc2gzKk1vZFZhbHVlKQ0KI1dlIGhhdmUgdG8gZG8gaXQgdGhpcyB3YXkgYmVjYXVzZSB5b3UgY2Fubm90IGNhbGwgdGhlIG1lYW4gYW5kIHNkIGZ1bmN0aW9ucyBpbiBsYXZhYW4gcGFja2FnZQ0KZGlyZWN0LlNEYmVsb3cgOj0gY2Rhc2gxICsgY2Rhc2gzKihhbGV4LmMubWVhbi1zcXJ0KGFsZXguYy52YXIpKSANCmRpcmVjdC5TRGFib3ZlIDo9IGNkYXNoMSArIGNkYXNoMyooYWxleC5jLm1lYW4rc3FydChhbGV4LmMudmFyKSkNCg0KI1RvdGFsIGVmZmVjdHMgY29uZGl0aW9uYWwgb24gbW9kZXJhdG9yDQp0b3RhbC5TRGJlbG93IDo9IGRpcmVjdC5TRGJlbG93ICsgaW5kaXJlY3QuU0RiZWxvdw0KdG90YWwuU0RhYm92ZSA6PSBkaXJlY3QuU0RhYm92ZSArIGluZGlyZWN0LlNEYWJvdmUNCg0KI1Byb3BvcnRpb24gbWVkaWF0ZWQgY29uZGl0aW9uYWwgb24gbW9kZXJhdG9yDQojVG8gbWF0Y2ggdGhlIG91dHB1dCBvZiAibWVkaWF0ZSIgcGFja2FnZQ0KcHJvcC5tZWRpYXRlZC5TRGJlbG93IDo9IGluZGlyZWN0LlNEYmVsb3cgLyB0b3RhbC5TRGJlbG93DQpwcm9wLm1lZGlhdGVkLlNEYWJvdmUgOj0gaW5kaXJlY3QuU0RhYm92ZSAvIHRvdGFsLlNEYWJvdmUNCg0KI0luZGV4IG9mIG1vZGVyYXRlZCBtZWRpYXRpb24NCiNBbiBhbHRlcm5hdGl2ZSB3YXkgb2YgdGVzdGluZyBpZiBjb25kaXRpb25hbCBpbmRpcmVjdCBlZmZlY3RzIGFyZSBzaWduaWZpY2FudGx5IGRpZmZlcmVudCBmcm9tIGVhY2ggb3RoZXINCmluZGV4Lm1vZC5tZWQgOj0gYTMqYjENCicNCmBgYA0KDQpOb3cgd2UgdGFrZSB0aGUgc3BlY2lmaWVkIG1vZGVscyBhbmQgYWxsIG9mIHRoZSBlZmZlY3RzIHdlIHdhbnQgdG8gZXN0aW1hdGUgYW5kIHJ1biB0aGVtIHRocm91Z2ggdGhlIFNFTSBmdW5jdGlvbi4gVGhlIFNFTSBmdW5jdGlvbiBhbGxvd3MgYSBjb21wbGV0ZWx5IHVzZXItZGVmaW5lZCBtb2RlbCB0byBiZSBmaXQgdG8gdGhlIGRhdGEsIGxpa2Ugb3VyIHNwZWNpZmljYWxseSBkZWZpbmVkIG1vZGVyYXRlZCBtZWRpYXRpb24gbW9kZWwgKHRoZSBTRU0gZnVuY3Rpb24gd2FzIGRlc2lnbmVkIHRvIGZpdCBzdHJ1Y3R1cmFsIGVxdWF0aW9uIG1vZGVscywgYnV0IGNhbiBhbHNvIGZpdCAicmVndWxhciIgcmVncmVzc2lvbiBtb2RlbHMgYXMgd2VsbCkuDQpgYGAge3IsIG1lc3NhZ2U9RkFMU0UsIGVjaG89VFJVRSwgd2FybmluZyA9IEZBTFNFfQ0KI0ZpdCBtb2RlbA0KTW9kLk1lZC5TRU0gPC0gc2VtKG1vZGVsID0gTW9kLk1lZC5MYXZhYW4sDQogICAgICAgICAgICAgICAgICAgZGF0YSA9IFN1Y2Nlc3MuTW9kTWVkLA0KICAgICAgICAgICAgICAgICAgIHNlID0gImJvb3RzdHJhcCIsDQogICAgICAgICAgICAgICAgICAgYm9vdHN0cmFwID0gMTApDQpgYGANCg0KYGBgIHtyLCBtZXNzYWdlPUZBTFNFLCBlY2hvPVRSVUUsIGV2YWwgPSBGQUxTRX0NCiNGaXQgbWVhc3VyZXMNCnN1bW1hcnkoTW9kLk1lZC5TRU0sDQogICAgICAgIGZpdC5tZWFzdXJlcyA9IEZBTFNFLA0KICAgICAgICBzdGFuZGFyZGl6ZSA9IFRSVUUsDQogICAgICAgIHJzcXVhcmUgPSBUUlVFKQ0KYGBgDQoNCi0gVGhlIGZpcnN0IGNodW5rIG9mIHRoZSBvdXRwdXQgc2hvdyBmaXQgaW5kaWNlcyByZWxhdGVkIHRvIFNFTSAobm90IHJlYWxseSBhcHBsaWNhYmxlIGZvciBvdXIgcHVycG9zZXMpDQotIFRoZSBzZWNvbmQgcGFydCBvZiB0aGUgb3V0cHV0IHNob3dzIG91ciByZWdyZXNzaW9uIGZvcm11bGFzDQotIFRoZSBlbmQgb2YgdGhlIG91dHB1dCBzaG93cyB0aGUgc3BlY2lmaWVkIGRpcmVjdCwgaW5kaXJlY3QsIHRvdGFsLCBwcm9wb3J0aW9uIG1lZGlhdGVkIGVmZmVjdHMNCmBgYCB7ciwgbWVzc2FnZT1GQUxTRSwgZWNobz1GQUxTRSwgd2FybmluZyA9IEZBTFNFfQ0KI0ZpdCBtZWFzdXJlcw0Kc3VtbWFyeShNb2QuTWVkLlNFTSwNCiAgICAgICAgZml0Lm1lYXN1cmVzID0gRkFMU0UsDQogICAgICAgIHN0YW5kYXJkaXplID0gVFJVRSwNCiAgICAgICAgcnNxdWFyZSA9IFRSVUUpDQpgYGANCg0KV2UgY2FuIGFsc28gY2FsbCBmb3IgYm9vdHN0cmFwcGVkIGNvbmZpZGVuY2UgaW50ZXJ2YWwgcGFyYW1ldGVyIGVzdGltYXRlcyBvZiBhbGwgb2Ygb3VyIGVmZmVjdHMNCmBgYCB7ciwgbWVzc2FnZT1GQUxTRSwgZWNobz1UUlVFLCB3YXJuaW5nID0gRkFMU0V9DQojQm9vdHN0cmFwcw0KcGFyYW1ldGVyRXN0aW1hdGVzKE1vZC5NZWQuU0VNLA0KICAgICAgICAgICAgICAgICAgIGJvb3QuY2kudHlwZSA9ICJiY2Euc2ltcGxlIiwNCiAgICAgICAgICAgICAgICAgICBsZXZlbCA9IC45NSwgY2kgPSBUUlVFLA0KICAgICAgICAgICAgICAgICAgIHN0YW5kYXJkaXplZCA9IEZBTFNFKVtjKDE5OjI3KSxjKDQ6MTApXSAjV2UgaW5kZXggdGhlIG1hdHJpeCB0byBvbmx5IGRpc3BsYXkgY29sdW1ucyB3ZSBhcmUgaW50ZXJlc3RlZCBpbg0KYGBgDQoNCi0gT3VyIGVzdGltYXRlcyBhbmQgY29uZmlkZW5jZSBpbnRlcnZhbHMgYXJlIGFsbW9zdCBpZGVudGljYWwgdG8gdGhlICJtZWRpYXRpb24iIHBhY2thZ2UgZXN0aW1hdGVzDQotIFRoZSBkaWZmZXJlbmNlIGlzIG1vc3QgbGlrZWx5IGEgcmVzdWx0IG9mIGJvb3RzdHJhcCBlc3RpbWF0aW9uIGRpZmZlcmVuY2VzIChlLmcuLCBsYXZhYW4gdXNlcyBiaWFzLWNvcnJlY3RlZCBidXQgbm90IGFjY2VsZXJhdGVkIGJvb3RzdHJhcHBpbmcgZm9yIHRoZWlyIGNvbmZpZGVuY2UgaW50ZXJ2YWxzKQ0KDQojIyBTdHJlbmd0aHMgYW5kIGxpbWl0YXRpb25zIG9mICJsYXZhYW4iIHBhY2thZ2UNCi0gRXh0cmVtZWx5IGN1c3RvbWl6YWJsZQ0KLSBDYW4gYWxzbyBtb2RlbCBsYXRlbnQgdmFyaWFibGVzIGlmIHlvdXIgbWVhc3VyZW1lbnQgbW9kZWwgcmVxdWlyZXMgaXQNCi0gVGVkaW91cyEgSXQgdG9vayBtZSBzZXZlcmFsIGhvdXJzIHRvIGZpZ3VyZSBvdXQgaG93IHRoZSBuYW1pbmcgY29udmVudGlvbnMgd29ya2VkDQotIEEgbG90IG9mIHVwIGZyb250IGNvZGluZyByZXF1aXJlZCBtZWFuaW5nIHlvdSBraW5kIG9mIG5lZWQgdG8ga25vdyBleGFjdGx5IHdoYXQgeW91J3JlIGxvb2tpbmcgZm9yIGluIHlvdXIgbW9kZWwNCg0KIyBSZWZlcmVuY2VzIGFuZCBMaW5rcw0KIyMgUmVmZXJlbmNlcw0KSGF5ZXMsIEEuIEYuICgyMDEzKS4gKkludHJvZHVjdGlvbiB0byBtZWRpYXRpb24sIG1vZGVyYXRpb24sIGFuZCBjb25kaXRpb25hbCBwcm9jZXNzIGFuYWx5c2lzOiBBIHJlZ3Jlc3Npb24tYmFzZWQgYXBwcm9hY2gqLiBOZXcgWW9yazogVGhlIEd1aWxmb3JkIFByZXNzLg0KDQpNaWNoYWxhaywgTi4gKDIwMTYsIEp1bHkgMjkpLiAqUmVwcm9kdWNpbmcgSGF5ZXMnIFBST0NFU1MgbW9kZWxzJyByZXN1bHRzIGluIFIqLiBSZXRyaWV2ZWQgZnJvbSBodHRwczovL25pY2ttaWNoYWxhay5ibG9nc3BvdC5jb20vMjAxNi8wNy9yZXByb2R1Y2luZy1oYXllc3MtcHJvY2Vzcy1tb2RlbHMuaHRtbA0KDQpSb3NzZWVsLCBZLiAoMjAxNywgRmVicnVhcnkgMjQpLiAqUGFja2FnZSAnbGF2YWFuJyouIFJldHJpZXZlZCBmcm9tIGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9sYXZhYW4vbGF2YWFuLnBkZg0KDQpTYWxlcywgQS4gQy4gKDIwMTcpLiBSZXZpZXc6IE1lZGlhdGlvbiBwYWNrYWdlIGluIFIuICpKb3VybmFsIG9mIEVkdWNhdGlvbmFsIGFuZCBCZWhhdmlvcmFsIFN0YXRpc3RpY3MsIDQyKiwgMSwgNjktODQuDQoNClRpbmdsZXksIEQuLCBZYW1hbW90bywgVC4sIEhpcm9zZSwgSy4sIEtlZWxlLCBMLiwgJiBJbWFpLCBLLiAoMjAxNCkuICpNZWRpYXRpb246IFIgcGFja2FnZSBmb3IgY2F1c2FsIG1lZGlhdGlvbiBhbmFseXNpcyouDQoNCiMjIEhlbHBmdWwgTGlua3MNCltUaGUgTGF2YWFuIFBhY2thZ2UgV2Vic2l0ZV0oaHR0cDovL2xhdmFhbi51Z2VudC5iZSkNCg0KW1IgTWFya2Rvd24gQ2hlYXRzaGVldF0oaHR0cHM6Ly9naXRodWIuY29tL2FkYW0tcC9tYXJrZG93bi1oZXJlL3dpa2kvTWFya2Rvd24tQ2hlYXRzaGVldCNlbXBoYXNpcykNCg0KW1IgTWFya2Rvd24gR2FsbGVyeV0oaHR0cDovL3JtYXJrZG93bi5yc3R1ZGlvLmNvbS9hcnRpY2xlcy5odG1sKQ0KDQoNCg0KPHNjcmlwdD4NCiAgKGZ1bmN0aW9uKGkscyxvLGcscixhLG0pe2lbJ0dvb2dsZUFuYWx5dGljc09iamVjdCddPXI7aVtyXT1pW3JdfHxmdW5jdGlvbigpew0KICAoaVtyXS5xPWlbcl0ucXx8W10pLnB1c2goYXJndW1lbnRzKX0saVtyXS5sPTEqbmV3IERhdGUoKTthPXMuY3JlYXRlRWxlbWVudChvKSwNCiAgbT1zLmdldEVsZW1lbnRzQnlUYWdOYW1lKG8pWzBdO2EuYXN5bmM9MTthLnNyYz1nO20ucGFyZW50Tm9kZS5pbnNlcnRCZWZvcmUoYSxtKQ0KICB9KSh3aW5kb3csZG9jdW1lbnQsJ3NjcmlwdCcsJ2h0dHBzOi8vd3d3Lmdvb2dsZS1hbmFseXRpY3MuY29tL2FuYWx5dGljcy5qcycsJ2dhJyk7DQoNCiAgZ2EoJ2NyZWF0ZScsICdVQS05ODg3ODc5My0xJywgJ2F1dG8nKTsNCiAgZ2EoJ3NlbmQnLCAncGFnZXZpZXcnKTsNCg0KPC9zY3JpcHQ+DQo=