1 Theory

  • Baron & Kenny, 1986 (citations as of 3/27/17 = 66,271)
  • See Kenny’s website for useful information: http://davidakenny.net/cm/mediate.htm
  • Extremely common and popular method in social, but now used throughout psychology

  • Baron & Kenny define moderator and mediator for us:

“The moderator function of third variables, which partitions a focal independent variable into subgroups that establish its domains of maximal effectiveness regarding a given dependent variable”

“The mediator function of a third variable, which represents the generative mechanism through which the focal independent variable can influence the dependent variable of interest”"

  • In short, the mediator explains why X->Y, and it’s through M
  • Having one mediator is called simple mediation.
Simple Mediation

Simple Mediation

Preacher & Hayes, 2008 explain this figure as:

“X’s causal effect into its indirect effect on Y through M and its direct effect on Y (path c’). Path c’ a represents the effect of X on the proposed mediator, whereas path b is the effect of M on Y partialling out the effect of X. The indirect effect of X on Y through M can then be quantified as the product of a and b (i.e., ab)”

  • The mediation is trying explain the direct path seen in the total effect (the analysis without the mediation term)
Total Effect

Total Effect

  • So we can connect the total effect back the simple moderation: \[c = c' + ab\]

\[total = direct + indirect \]

1.1 A hypothetical example of mediation

  • Children with the ability to delay gratification tend to be more success in life (Marshmallow test)
  • You hypothesize that it is their respect/trust in of authority figures to keep their promises that is intermediating in the causal chain for success in later life
  • You collect 268 4-year-olds, give them the Marshmallow test (measure their time to eat the marshmallow). Rather than waiting 20 years, you operationalize success as how they did at the end of the year on kindergarten entrance exam. You also measure how must trust they have in authority figures (1-10 scale through an established battery for children)
library(car)
set.seed(42)
# For simulation of mediation steps see Hallgren, 2013
# path a strength
a=.4
# path b strength
b=.4
# path c' strength
cp=.01
# people
n <- 268
# Normal distribution of time (mins)
X <- rnorm(n, 5, 2)
# Mediator
M <- a*X+rnorm(n, 0, 1)
# Our equation to  create Y
Y <- cp*X + b*M + rnorm(n, sd=1)
#Built our data frame
Marshmallow.Data<-data.frame(Success=Y,Time=X,Trust=M)

1.1.1 Baron and Kenny Steps to testing mediation

  • Step 1: Test Y~X
  • Is there a relationship? If yes you can proceed (if not stop as you have no total effect path to try to mediate)
library(stargazer)
Model.1<-lm(Success~Time, data= Marshmallow.Data)
stargazer(Model.1,type="html",
          intercept.bottom = FALSE,
          single.row=FALSE, 
          notes.append = FALSE,
          header=FALSE)
Dependent variable:
Success
Constant 0.027
(0.169)
Time 0.143***
(0.032)
Observations 268
R2 0.070
Adjusted R2 0.067
Residual Std. Error 1.010 (df = 266)
F Statistic 20.096*** (df = 1; 266)
Note: p<0.1; p<0.05; p<0.01
  • Step 2: Test M~X
  • Is there a relationship? If yes you can proceed (if not stop as you have no path a)
Model.2<-lm(Trust~Time, data= Marshmallow.Data)
stargazer(Model.2,type="html",
          intercept.bottom = FALSE,
          single.row=FALSE, 
          notes.append = FALSE,
          header=FALSE)
Dependent variable:
Trust
Constant 0.305*
(0.168)
Time 0.334***
(0.032)
Observations 268
R2 0.296
Adjusted R2 0.294
Residual Std. Error 1.001 (df = 266)
F Statistic 112.073*** (df = 1; 266)
Note: p<0.1; p<0.05; p<0.01
  • Step 3: Test Y ~ M + X
  • Is there a relationship? If yes you can proceed (if not stop as you have no path b)
  • X is now here as an control for M to predict X (some people say leave it out, Kenny says leave it in)
Model.3<-lm(Success~Trust+Time, data= Marshmallow.Data)
stargazer(Model.3,type="html",
          intercept.bottom = FALSE,
          single.row=FALSE, 
          notes.append = FALSE,
          header=FALSE)
Dependent variable:
Success
Constant -0.086
(0.159)
Trust 0.369***
(0.058)
Time 0.019
(0.035)
Observations 268
R2 0.195
Adjusted R2 0.189
Residual Std. Error 0.942 (df = 265)
F Statistic 32.059*** (df = 2; 265)
Note: p<0.1; p<0.05; p<0.01
  • Step 4: Test X ~ Y + M
  • Estabilish complete mediation
  • Reverse path: M is now here as an control for Y to predict X
  • If there is complete mediation path c’ will go to zero
  • If there is partial mediation path c’ will remain (but should get smaller) if paths a and b were meaningful
Model.4<-lm(Time~Success+Trust, data= Marshmallow.Data)
stargazer(Model.4,type="html",
          intercept.bottom = FALSE,
          single.row=FALSE, 
          notes.append = FALSE,
          header=FALSE)
Dependent variable:
Time
Constant 3.212***
(0.192)
Success 0.058
(0.106)
Trust 0.864***
(0.093)
Observations 268
R2 0.297
Adjusted R2 0.292
Residual Std. Error 1.632 (df = 265)
F Statistic 56.039*** (df = 2; 265)
Note: p<0.1; p<0.05; p<0.01

1.1.2 Interpretation

  • So we have complete mediation, the c’ prime path went to nearly zero
  • In this case time was not significant, but it could be with larger samples…
  • The variance of time was explained by the mediator, path ab
  • but how do we test the significance of the mediator, path ab?

1.1.3 Significance of indirect path

  • Well in our case, both path a and b were strong and significant (joint significance)
  • Joint significance is an indirect test of the indirect path and is mostly holds up more modern methods (but you probably cannot publish just by showing significance on paths a and b)
  • We need a direct test the significance of the indirect path (ab)
  • The Baron and Kenny method was to use the Sobel’s test, which estimates the SE on terms ab of our equation, \(c = c' + ab\) and tests it against zero
  • Sobel assumes of paths a and b as independent, it’s very conservative and very low powered (see http://davidakenny.net/cm/mediate.htm for details)
  • There are other tests, but Sobel was the most common in its day
library(bda)
mediation.test(Marshmallow.Data$Trust,Marshmallow.Data$Time,Marshmallow.Data$Success)
##                Sobel       Aroian      Goodman
## z.value 5.478920e+00 5.461111e+00 5.496905e+00
## p.value 4.279292e-08 4.731637e-08 3.865154e-08
  • Bootstrapping has replaced the Sobel’s test so we will focus on using that test in the examples
  • There are two type of bootstrapping, BCa and percentile methods (remember we covered them at the start of the term)
  • BCa can be a bit anti-conservative but more powerful, percentile method is less powerful more conservative

1.1.3.1 Mediation package in R

  • You will only need Model.2 (M~X) and Model.3 (Y~M+X) from above
  • but the language changes a bit in the way we talk about these things as this package can handle larger designs with control variables and many different types of regressions (linear, generalized, and mixed, mixture, censored and survival)
library(mediation)
Med.Boot.BCa <- mediate(Model.2, Model.3, boot = TRUE, 
                        boot.ci.type = "bca", sims=200, treat="Time", mediator="Trust")
summary(Med.Boot.BCa)
## 
## Causal Mediation Analysis 
## 
## Nonparametric Bootstrap Confidence Intervals with the BCa Method
## 
##                Estimate 95% CI Lower 95% CI Upper p-value    
## ACME             0.1235       0.0876         0.17  <2e-16 ***
## ADE              0.0194      -0.0308         0.09    0.56    
## Total Effect     0.1429       0.0926         0.21  <2e-16 ***
## Prop. Mediated   0.8644       0.5683         1.53  <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Sample Size Used: 268 
## 
## 
## Simulations: 200
plot(Med.Boot.BCa)

  • ACME: Average Causal Mediation Effects (ACME) [total effect - direct effect]
  • ADE: Average Direct Effects [total effect - indirect effect]
  • Total Effect = Direct (ADE) + Indirect (ACME)
  • These are unstandardized effects Prop. Mediated: conceptually ACME / Total effect
  • Note: I did 200 simulations for time, but 2000 is best if you are doing BCa.

  • By changing the code we can get percentile method over BCa

Med.Boot.perc <- mediate(Model.2, Model.3, boot = TRUE, 
                         boot.ci.type = "perc", sims=200, treat="Time", mediator="Trust")
summary(Med.Boot.perc)
## 
## Causal Mediation Analysis 
## 
## Nonparametric Bootstrap Confidence Intervals with the Percentile Method
## 
##                Estimate 95% CI Lower 95% CI Upper p-value    
## ACME             0.1235       0.0857         0.16  <2e-16 ***
## ADE              0.0194      -0.0366         0.08    0.59    
## Total Effect     0.1429       0.0860         0.20  <2e-16 ***
## Prop. Mediated   0.8644       0.5165         1.39  <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Sample Size Used: 268 
## 
## 
## Simulations: 200
plot(Med.Boot.perc)

  • These results match Baron and Kenny and the process macro in SPSS
  • The benefit here is you test mediator in glm or mixed (cannot be done so easily in SPSS)
  • The drawback in R is you want to test things like multi-mediation you need to program it yourself (for now)

1.1.4 Testing the mediator as moderator?

  • Could it be that our mediator is really just a moderator?

1.2 Power

  • When you plan to run mediation you must carefully think about the power you might need.
  • Because the M is basically collinear X you will need more subjects than you would normally think
  • Kenny has worked out an easy app to estimate power for simple designs
  • https://davidakenny.shinyapps.io/MedPower/
  • For larger designs you need to build custom simulations and the Mediation package can help

1.3 Partial Mediation

  • When the direct effect and indirect effect are both real
  • Many times you don’t have the power for complete mediation and you might think its partial mediation
  • Kenny suggests using Hayes (2013) recommendation: never drawing the conclusion that its complete or partial
  • Below I have created a well-powered (power = .8) examine both the direct and indirect effects
library(car)
set.seed(42)
# For simulation of mediation steps see Hallgren, 2013
# path a strength
a=.4
# path b strength
b=.4
# path c' strength
cp=.2
# people
n <- 177
# Normal distribution of time (mins)
X <- rnorm(n, 5, 2)
# Mediator
M <- a*X+rnorm(n, 0, 1)
# Our equation to  create Y
Y <- cp*X + b*M + rnorm(n, sd=1)
#Built our data frame
Marshmallow.Data.Part<-data.frame(Success=Y,Time=X,Trust=M)

Part.Model.2<-lm(Trust~Time, data= Marshmallow.Data.Part)

Part.Model.3<-lm(Success~Trust+Time, data= Marshmallow.Data.Part)

Part.Med.Boot.BCa <- mediate(Part.Model.2, Part.Model.3, boot = TRUE,
                             boot.ci.type = "bca", sims=200, treat="Time", mediator="Trust")
summary(Part.Med.Boot.BCa)
## 
## Causal Mediation Analysis 
## 
## Nonparametric Bootstrap Confidence Intervals with the BCa Method
## 
##                Estimate 95% CI Lower 95% CI Upper p-value    
## ACME             0.1726       0.0956         0.26  <2e-16 ***
## ADE              0.1724       0.0994         0.29  <2e-16 ***
## Total Effect     0.3450       0.2676         0.42  <2e-16 ***
## Prop. Mediated   0.5002       0.2584         0.71  <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Sample Size Used: 177 
## 
## 
## Simulations: 200
plot(Part.Med.Boot.BCa)

1.4 Moderated-Mediated

  • Moderation is trying to figure out the factors they influence the strength of the relationship between X to Y
  • Mediation is trying to figure out the intermediating factors involved into getting from X to Y
  • Moderated-Mediated is that effect of the mediator is moderated
  • In practical terms, what if our mediation above (respect/trust in authority) was moderated by parenting styles of parents
  • Strict parents created respect of the authority, while permissive parents create opposition to authority
  • Measurement scale from -3 to 3 (permissive to authoritative)
  • Thus our mediation of respect/trust is stronger for kids with authoritative than permissive parents
  • but it could also be that children from authoritative parents will be much more well-behaved in general
  • We will examine different types of models to examine this effect
set.seed(42)
# path a strength
a=.4
# path b strength
b=.4
# path c' strength
cp=.01
#  people
n <- 268
# Normal distribution of time (mins)
X <- rnorm(n, 5, 2)
# Moderator
Mod<-runif(n, -3, 3)
# Mediator
M <- a*X*Mod+rnorm(n, 0, 1)
# Our equation to  create Y
Y <- cp*X*Mod + b*M + M*Mod + rnorm(n, sd=1)
#Built our data frame
Marshmallow.Mod<-data.frame(Success=Y,Time=X,Trust=M,Parents=Mod)

1.4.1 Moderation on Path a, b, c’

  • In this case we think the direct (c’) and indirect path (a,b) is moderated by Parenting style
  • So we have to interact it in Model 2 and Model 3
  • Model 2 from Kenny becomes, \(M ~ X*Mod\)
  • Model 3 from Kenny becomes, \(Y ~ M*Mod+X*Mod\)
  • Note this is Hayes’ process model 59
Mod.Med.Model.2<-lm(Trust~Time*Parents, data= Marshmallow.Mod)

stargazer(Mod.Med.Model.2,type="html",
          intercept.bottom = FALSE,
          single.row=FALSE, 
          notes.append = FALSE,
          header=FALSE)
Dependent variable:
Trust
Constant -0.065
(0.173)
Time 0.002
(0.033)
Parents -0.281***
(0.100)
Time:Parents 0.455***
(0.020)
Observations 268
R2 0.922
Adjusted R2 0.922
Residual Std. Error 1.022 (df = 264)
F Statistic 1,047.406*** (df = 3; 264)
Note: p<0.1; p<0.05; p<0.01
Mod.Med.Model.3<-lm(Success~Trust*Parents+Time*Parents, data= Marshmallow.Mod)
stargazer(Mod.Med.Model.3,type="html",
          intercept.bottom = FALSE,
          single.row=FALSE, 
          notes.append = FALSE,
          header=FALSE)
Dependent variable:
Success
Constant -0.055
(0.165)
Trust 0.383***
(0.058)
Parents 0.024
(0.097)
Time -0.014
(0.032)
Trust:Parents 1.009***
(0.011)
Parents:Time 0.013
(0.032)
Observations 268
R2 0.977
Adjusted R2 0.976
Residual Std. Error 0.971 (df = 262)
F Statistic 2,202.624*** (df = 5; 262)
Note: p<0.1; p<0.05; p<0.01
  • In this moderation package we list the moderator as a covariate and set the levels we wish to control for
  • We can use the +/- 1SD from the mean (also we can use zero if wanted to see the average parent)
  • This allows us to view impact of the moderator on the direct and indirect effect
  • Lets look at permissive parents first
  • Still no direct effect, but an effect for ACME
Permissive<-mean(Marshmallow.Mod$Parents)-sd(Marshmallow.Mod$Parents)
Permissive
## [1] -1.680635
Mod.Med.Boot.BCa.1 <- mediate(Mod.Med.Model.2, Mod.Med.Model.3, 
                              covariates = list(Parents = Permissive), boot = TRUE, 
                              boot.ci.type = "bca", sims=200, treat="Time", mediator="Trust")
summary(Mod.Med.Boot.BCa.1)
## 
## 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             1.0028       0.9030         1.11  <2e-16 ***
## ADE             -0.0355      -0.1340         0.08    0.47    
## Total Effect     0.9673       0.8658         1.06  <2e-16 ***
## Prop. Mediated   1.0367       0.9165         1.15  <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Sample Size Used: 268 
## 
## 
## Simulations: 200
plot(Mod.Med.Boot.BCa.1)

  • Lets let look at authoritative parents
  • Still no direct effect, but a stonger effect for ACME
Authoritative<-mean(Marshmallow.Mod$Parents)+sd(Marshmallow.Mod$Parents)
Authoritative
## [1] 1.71852
Mod.Med.Boot.BCa.2 <- mediate(Mod.Med.Model.2, Mod.Med.Model.3, 
                              covariates = list(Parents = Authoritative), boot = TRUE, 
                              boot.ci.type = "bca", sims=200, treat="Time", mediator="Trust")
summary(Mod.Med.Boot.BCa.2)
## 
## 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              1.659        1.449         1.90  <2e-16 ***
## ADE               0.007       -0.129         0.10    0.87    
## Total Effect      1.666        1.481         1.91  <2e-16 ***
## Prop. Mediated    0.996        0.943         1.08  <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Sample Size Used: 268 
## 
## 
## Simulations: 200
plot(Mod.Med.Boot.BCa.2)

  • To get a significance test on if the moderator is causing a difference in the direct or indirect effects we can use this code
  • Note:
Mod.Med.Boot.BCa.3 <- mediate(Mod.Med.Model.2, Mod.Med.Model.3, boot = TRUE, 
                              boot.ci.type = "bca", sims=5, treat="Time", mediator="Trust")
test.modmed(Mod.Med.Boot.BCa.3, covariates.1 = list(Parents = Permissive),
            covariates.2 = list(Parents = Authoritative), sims = 200)
## 
##  Test of ACME(covariates.1) - ACME(covariates.2) = 0
## 
## data:  estimates from Mod.Med.Boot.BCa.3
## ACME(covariates.1) - ACME(covariates.2) = -0.65647, p-value <
## 2.2e-16
## alternative hypothesis: true ACME(covariates.1) - ACME(covariates.2) is not equal to 0
## 95 percent confidence interval:
##  -0.9168896 -0.4100557
## 
## 
##  Test of ADE(covariates.1) - ADE(covariates.2) = 0
## 
## data:  estimates from Mod.Med.Boot.BCa.3
## ADE(covariates.1) - ADE(covariates.2) = -0.042516, p-value = 0.58
## alternative hypothesis: true ADE(covariates.1) - ADE(covariates.2) is not equal to 0
## 95 percent confidence interval:
##  -0.2575408  0.1494442
  • So we see the indirect effects differ, but the direct effects do not
  • So it seems the indirect effect is moderated by parenting style in the direction we predict
LS0tDQp0aXRsZTogJ01lZGlhdGlvbicNCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDoNCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMNCiAgICBmb250c2l6ZTogOHB0DQogICAgaGlnaGxpZ2h0OiB0ZXh0bWF0ZQ0KICAgIG51bWJlcl9zZWN0aW9uczogeWVzDQogICAgdGhlbWU6IGZsYXRseQ0KICAgIHRvYzogeWVzDQogICAgdG9jX2Zsb2F0Og0KICAgICAgY29sbGFwc2VkOiBubw0KLS0tDQoNCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpDQprbml0cjo6b3B0c19jaHVuayRzZXQobWVzc2FnZSA9IEZBTFNFKQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGZpZy53aWR0aD01KQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGZpZy5oZWlnaHQ9My43NSkNCmtuaXRyOjpvcHRzX2NodW5rJHNldChmaWcuYWxpZ249J2NlbnRlcicpIA0KYGBgDQoNCiMgVGhlb3J5DQotIEJhcm9uICYgS2VubnksIDE5ODYgKGNpdGF0aW9ucyBhcyBvZiAzLzI3LzE3ID0gNjYsMjcxKQ0KLSBTZWUgS2VubnkncyB3ZWJzaXRlIGZvciB1c2VmdWwgaW5mb3JtYXRpb246IGh0dHA6Ly9kYXZpZGFrZW5ueS5uZXQvY20vbWVkaWF0ZS5odG0NCi0gRXh0cmVtZWx5IGNvbW1vbiBhbmQgcG9wdWxhciBtZXRob2QgaW4gc29jaWFsLCBidXQgbm93IHVzZWQgdGhyb3VnaG91dCBwc3ljaG9sb2d5DQoNCi0gQmFyb24gJiBLZW5ueSBkZWZpbmUgbW9kZXJhdG9yIGFuZCBtZWRpYXRvciBmb3IgdXM6DQoNCj4gIlRoZSBtb2RlcmF0b3IgZnVuY3Rpb24gb2YgdGhpcmQgdmFyaWFibGVzLCB3aGljaCBwYXJ0aXRpb25zIGEgZm9jYWwgaW5kZXBlbmRlbnQgdmFyaWFibGUgaW50byBzdWJncm91cHMgdGhhdCBlc3RhYmxpc2ggaXRzIGRvbWFpbnMgb2YgbWF4aW1hbCBlZmZlY3RpdmVuZXNzIHJlZ2FyZGluZyBhIGdpdmVuIGRlcGVuZGVudCB2YXJpYWJsZSINCg0KPiAiVGhlIG1lZGlhdG9yIGZ1bmN0aW9uIG9mIGEgdGhpcmQNCnZhcmlhYmxlLCB3aGljaCByZXByZXNlbnRzIHRoZSBnZW5lcmF0aXZlIG1lY2hhbmlzbSB0aHJvdWdoDQp3aGljaCB0aGUgZm9jYWwgaW5kZXBlbmRlbnQgdmFyaWFibGUgY2FuIGluZmx1ZW5jZSB0aGUNCmRlcGVuZGVudCB2YXJpYWJsZSBvZiBpbnRlcmVzdCIiDQoNCi0gSW4gc2hvcnQsIHRoZSBtZWRpYXRvciBleHBsYWlucyB3aHkgWC0+WSwgYW5kIGl0J3MgdGhyb3VnaCBNDQotIEhhdmluZyBvbmUgbWVkaWF0b3IgaXMgY2FsbGVkIHNpbXBsZSBtZWRpYXRpb24uDQoNCiFbU2ltcGxlIE1lZGlhdGlvbl0oUmVncmVzc2lvbkNsYXNzL0wxMF9NZWRpYXRpb24xL0ZpZ3VyZTEucG5nKQ0KDQpQcmVhY2hlciAmIEhheWVzLCAyMDA4IGV4cGxhaW4gdGhpcyBmaWd1cmUgYXM6IA0KDQo+ICJYJ3MgY2F1c2FsIGVmZmVjdCBpbnRvIGl0cyBpbmRpcmVjdCBlZmZlY3Qgb24gWSB0aHJvdWdoIE0gYW5kIGl0cyBkaXJlY3QgZWZmZWN0IG9uIFkgKHBhdGggYycpLiBQYXRoIGMnIGEgcmVwcmVzZW50cyB0aGUgZWZmZWN0IG9mIFggb24gdGhlIHByb3Bvc2VkIG1lZGlhdG9yLCB3aGVyZWFzIHBhdGggYiBpcyB0aGUgZWZmZWN0IG9mIE0gb24gWSBwYXJ0aWFsbGluZyBvdXQgdGhlIGVmZmVjdCBvZiBYLiBUaGUgaW5kaXJlY3QgZWZmZWN0IG9mIFggb24gWSB0aHJvdWdoIE0gY2FuIHRoZW4gYmUgcXVhbnRpZmllZCBhcyB0aGUgcHJvZHVjdCBvZiBhIGFuZCBiIChpLmUuLCBhYikiDQoNCi0gVGhlIG1lZGlhdGlvbiBpcyB0cnlpbmcgZXhwbGFpbiB0aGUgZGlyZWN0IHBhdGggc2VlbiBpbiB0aGUgdG90YWwgZWZmZWN0ICh0aGUgYW5hbHlzaXMgd2l0aG91dCB0aGUgbWVkaWF0aW9uIHRlcm0pDQoNCiFbVG90YWwgRWZmZWN0XShSZWdyZXNzaW9uQ2xhc3MvTDEwX01lZGlhdGlvbjEvRmlndXJlMi5wbmcpDQoNCi0gU28gd2UgY2FuIGNvbm5lY3QgdGhlIHRvdGFsIGVmZmVjdCBiYWNrIHRoZSBzaW1wbGUgbW9kZXJhdGlvbjoNCiQkYyA9IGMnICsgYWIkJA0KDQokJHRvdGFsID0gZGlyZWN0ICsgaW5kaXJlY3QgJCQNCg0KIyMgQSBoeXBvdGhldGljYWwgZXhhbXBsZSBvZiBtZWRpYXRpb24NCi0gQ2hpbGRyZW4gd2l0aCB0aGUgYWJpbGl0eSB0byBkZWxheSBncmF0aWZpY2F0aW9uIHRlbmQgdG8gYmUgbW9yZSBzdWNjZXNzIGluIGxpZmUgKE1hcnNobWFsbG93IHRlc3QpDQotIFlvdSBoeXBvdGhlc2l6ZSB0aGF0IGl0IGlzIHRoZWlyIHJlc3BlY3QvdHJ1c3QgaW4gb2YgYXV0aG9yaXR5IGZpZ3VyZXMgdG8ga2VlcCB0aGVpciBwcm9taXNlcyB0aGF0IGlzIGludGVybWVkaWF0aW5nIGluIHRoZSBjYXVzYWwgY2hhaW4gZm9yIHN1Y2Nlc3MgaW4gbGF0ZXIgbGlmZQ0KLSBZb3UgY29sbGVjdCAyNjggNC15ZWFyLW9sZHMsIGdpdmUgdGhlbSB0aGUgTWFyc2htYWxsb3cgdGVzdCAobWVhc3VyZSB0aGVpciB0aW1lIHRvIGVhdCB0aGUgbWFyc2htYWxsb3cpLiBSYXRoZXIgdGhhbiB3YWl0aW5nIDIwIHllYXJzLCB5b3Ugb3BlcmF0aW9uYWxpemUgc3VjY2VzcyBhcyBob3cgdGhleSBkaWQgYXQgdGhlIGVuZCBvZiB0aGUgeWVhciBvbiBraW5kZXJnYXJ0ZW4gZW50cmFuY2UgZXhhbS4gWW91IGFsc28gbWVhc3VyZSBob3cgbXVzdCB0cnVzdCB0aGV5IGhhdmUgaW4gYXV0aG9yaXR5IGZpZ3VyZXMgKDEtMTAgc2NhbGUgdGhyb3VnaCBhbiBlc3RhYmxpc2hlZCBiYXR0ZXJ5IGZvciBjaGlsZHJlbikNCg0KDQpgYGB7ciwgZWNobz1UUlVFLCB3YXJuaW5nPUZBTFNFfQ0KbGlicmFyeShjYXIpDQpzZXQuc2VlZCg0MikNCiMgRm9yIHNpbXVsYXRpb24gb2YgbWVkaWF0aW9uIHN0ZXBzIHNlZSBIYWxsZ3JlbiwgMjAxMw0KIyBwYXRoIGEgc3RyZW5ndGgNCmE9LjQNCiMgcGF0aCBiIHN0cmVuZ3RoDQpiPS40DQojIHBhdGggYycgc3RyZW5ndGgNCmNwPS4wMQ0KIyBwZW9wbGUNCm4gPC0gMjY4DQojIE5vcm1hbCBkaXN0cmlidXRpb24gb2YgdGltZSAobWlucykNClggPC0gcm5vcm0obiwgNSwgMikNCiMgTWVkaWF0b3INCk0gPC0gYSpYK3Jub3JtKG4sIDAsIDEpDQojIE91ciBlcXVhdGlvbiB0byAgY3JlYXRlIFkNClkgPC0gY3AqWCArIGIqTSArIHJub3JtKG4sIHNkPTEpDQojQnVpbHQgb3VyIGRhdGEgZnJhbWUNCk1hcnNobWFsbG93LkRhdGE8LWRhdGEuZnJhbWUoU3VjY2Vzcz1ZLFRpbWU9WCxUcnVzdD1NKQ0KYGBgDQoNCiMjIyBCYXJvbiBhbmQgS2VubnkgU3RlcHMgdG8gdGVzdGluZyBtZWRpYXRpb24NCi0gU3RlcCAxOiBUZXN0IFl+WA0KLSBJcyB0aGVyZSBhIHJlbGF0aW9uc2hpcD8gSWYgeWVzIHlvdSBjYW4gcHJvY2VlZCAoaWYgbm90IHN0b3AgYXMgeW91IGhhdmUgbm8gdG90YWwgZWZmZWN0IHBhdGggdG8gdHJ5IHRvIG1lZGlhdGUpDQoNCmBgYHtyLCBlY2hvPVRSVUUsIHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRSxyZXN1bHRzPSdhc2lzJ30NCmxpYnJhcnkoc3RhcmdhemVyKQ0KTW9kZWwuMTwtbG0oU3VjY2Vzc35UaW1lLCBkYXRhPSBNYXJzaG1hbGxvdy5EYXRhKQ0Kc3RhcmdhemVyKE1vZGVsLjEsdHlwZT0iaHRtbCIsDQogICAgICAgICAgaW50ZXJjZXB0LmJvdHRvbSA9IEZBTFNFLA0KICAgICAgICAgIHNpbmdsZS5yb3c9RkFMU0UsIA0KICAgICAgICAgIG5vdGVzLmFwcGVuZCA9IEZBTFNFLA0KICAgICAgICAgIGhlYWRlcj1GQUxTRSkNCmBgYA0KDQotIFN0ZXAgMjogVGVzdCBNflgNCi0gSXMgdGhlcmUgYSByZWxhdGlvbnNoaXA/IElmIHllcyB5b3UgY2FuIHByb2NlZWQgKGlmIG5vdCBzdG9wIGFzIHlvdSBoYXZlIG5vIHBhdGggYSkNCg0KYGBge3IsIGVjaG89VFJVRSwgd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFLHJlc3VsdHM9J2FzaXMnfQ0KTW9kZWwuMjwtbG0oVHJ1c3R+VGltZSwgZGF0YT0gTWFyc2htYWxsb3cuRGF0YSkNCnN0YXJnYXplcihNb2RlbC4yLHR5cGU9Imh0bWwiLA0KICAgICAgICAgIGludGVyY2VwdC5ib3R0b20gPSBGQUxTRSwNCiAgICAgICAgICBzaW5nbGUucm93PUZBTFNFLCANCiAgICAgICAgICBub3Rlcy5hcHBlbmQgPSBGQUxTRSwNCiAgICAgICAgICBoZWFkZXI9RkFMU0UpDQpgYGANCg0KLSBTdGVwIDM6IFRlc3QgWSB+IE0gKyBYDQotIElzIHRoZXJlIGEgcmVsYXRpb25zaGlwPyBJZiB5ZXMgeW91IGNhbiBwcm9jZWVkIChpZiBub3Qgc3RvcCBhcyB5b3UgaGF2ZSBubyBwYXRoIGIpDQotIFggaXMgbm93IGhlcmUgYXMgYW4gY29udHJvbCBmb3IgTSB0byBwcmVkaWN0IFggKHNvbWUgcGVvcGxlIHNheSBsZWF2ZSBpdCBvdXQsIEtlbm55IHNheXMgbGVhdmUgaXQgaW4pDQoNCmBgYHtyLCBlY2hvPVRSVUUsIHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRSxyZXN1bHRzPSdhc2lzJ30NCk1vZGVsLjM8LWxtKFN1Y2Nlc3N+VHJ1c3QrVGltZSwgZGF0YT0gTWFyc2htYWxsb3cuRGF0YSkNCnN0YXJnYXplcihNb2RlbC4zLHR5cGU9Imh0bWwiLA0KICAgICAgICAgIGludGVyY2VwdC5ib3R0b20gPSBGQUxTRSwNCiAgICAgICAgICBzaW5nbGUucm93PUZBTFNFLCANCiAgICAgICAgICBub3Rlcy5hcHBlbmQgPSBGQUxTRSwNCiAgICAgICAgICBoZWFkZXI9RkFMU0UpDQpgYGANCg0KLSBTdGVwIDQ6IFRlc3QgWCB+IFkgKyBNDQotIEVzdGFiaWxpc2ggY29tcGxldGUgbWVkaWF0aW9uDQotIFJldmVyc2UgcGF0aDogTSBpcyBub3cgaGVyZSBhcyBhbiBjb250cm9sIGZvciBZIHRvIHByZWRpY3QgWA0KLSBJZiB0aGVyZSBpcyAqY29tcGxldGUqIG1lZGlhdGlvbiBwYXRoIGMnIHdpbGwgZ28gdG8gemVybw0KLSBJZiB0aGVyZSBpcyAqcGFydGlhbCogbWVkaWF0aW9uIHBhdGggYycgd2lsbCByZW1haW4gKGJ1dCBzaG91bGQgZ2V0IHNtYWxsZXIpIGlmIHBhdGhzIGEgYW5kIGIgd2VyZSBtZWFuaW5nZnVsDQoNCmBgYHtyLCBlY2hvPVRSVUUsIHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRSxyZXN1bHRzPSdhc2lzJ30NCk1vZGVsLjQ8LWxtKFRpbWV+U3VjY2VzcytUcnVzdCwgZGF0YT0gTWFyc2htYWxsb3cuRGF0YSkNCnN0YXJnYXplcihNb2RlbC40LHR5cGU9Imh0bWwiLA0KICAgICAgICAgIGludGVyY2VwdC5ib3R0b20gPSBGQUxTRSwNCiAgICAgICAgICBzaW5nbGUucm93PUZBTFNFLCANCiAgICAgICAgICBub3Rlcy5hcHBlbmQgPSBGQUxTRSwNCiAgICAgICAgICBoZWFkZXI9RkFMU0UpDQpgYGANCg0KIyMjIEludGVycHJldGF0aW9uDQotIFNvIHdlIGhhdmUgY29tcGxldGUgbWVkaWF0aW9uLCB0aGUgYycgcHJpbWUgcGF0aCB3ZW50IHRvIG5lYXJseSB6ZXJvIA0KLSBJbiB0aGlzIGNhc2UgdGltZSB3YXMgbm90IHNpZ25pZmljYW50LCBidXQgaXQgY291bGQgYmUgd2l0aCBsYXJnZXIgc2FtcGxlcy4uLg0KLSBUaGUgdmFyaWFuY2Ugb2YgdGltZSB3YXMgZXhwbGFpbmVkIGJ5IHRoZSBtZWRpYXRvciwgcGF0aCBhYg0KLSBidXQgaG93IGRvIHdlIHRlc3QgdGhlIHNpZ25pZmljYW5jZSBvZiB0aGUgbWVkaWF0b3IsIHBhdGggYWI/DQoNCiMjIyBTaWduaWZpY2FuY2Ugb2YgaW5kaXJlY3QgcGF0aA0KLSBXZWxsIGluIG91ciBjYXNlLCBib3RoIHBhdGggYSBhbmQgYiB3ZXJlIHN0cm9uZyBhbmQgc2lnbmlmaWNhbnQgKGpvaW50IHNpZ25pZmljYW5jZSkgDQotIEpvaW50IHNpZ25pZmljYW5jZSBpcyBhbiBpbmRpcmVjdCB0ZXN0IG9mIHRoZSBpbmRpcmVjdCBwYXRoIGFuZCBpcyBtb3N0bHkgaG9sZHMgdXAgbW9yZSBtb2Rlcm4gbWV0aG9kcyAoYnV0IHlvdSBwcm9iYWJseSBjYW5ub3QgcHVibGlzaCBqdXN0IGJ5IHNob3dpbmcgc2lnbmlmaWNhbmNlIG9uIHBhdGhzIGEgYW5kIGIpDQotIFdlIG5lZWQgYSBkaXJlY3QgdGVzdCB0aGUgc2lnbmlmaWNhbmNlIG9mIHRoZSBpbmRpcmVjdCBwYXRoIChhYikNCi0gVGhlIEJhcm9uIGFuZCBLZW5ueSBtZXRob2Qgd2FzIHRvIHVzZSB0aGUgU29iZWwncyB0ZXN0LCB3aGljaCBlc3RpbWF0ZXMgdGhlIFNFIG9uIHRlcm1zIGFiIG9mIG91ciBlcXVhdGlvbiwgJGMgPSBjJyArIGFiJCBhbmQgdGVzdHMgaXQgYWdhaW5zdCB6ZXJvDQotIFNvYmVsIGFzc3VtZXMgb2YgcGF0aHMgYSBhbmQgYiBhcyBpbmRlcGVuZGVudCwgaXQncyB2ZXJ5IGNvbnNlcnZhdGl2ZSBhbmQgdmVyeSBsb3cgcG93ZXJlZCAoc2VlIGh0dHA6Ly9kYXZpZGFrZW5ueS5uZXQvY20vbWVkaWF0ZS5odG0gZm9yIGRldGFpbHMpDQotIFRoZXJlIGFyZSBvdGhlciB0ZXN0cywgYnV0IFNvYmVsIHdhcyB0aGUgbW9zdCBjb21tb24gaW4gaXRzIGRheQ0KDQpgYGB7ciwgZWNobz1UUlVFLCB3YXJuaW5nPUZBTFNFfQ0KbGlicmFyeShiZGEpDQptZWRpYXRpb24udGVzdChNYXJzaG1hbGxvdy5EYXRhJFRydXN0LE1hcnNobWFsbG93LkRhdGEkVGltZSxNYXJzaG1hbGxvdy5EYXRhJFN1Y2Nlc3MpDQpgYGANCg0KLSBCb290c3RyYXBwaW5nIGhhcyByZXBsYWNlZCB0aGUgU29iZWwncyB0ZXN0IHNvIHdlIHdpbGwgZm9jdXMgb24gdXNpbmcgdGhhdCB0ZXN0IGluIHRoZSBleGFtcGxlcw0KLSBUaGVyZSBhcmUgdHdvIHR5cGUgb2YgYm9vdHN0cmFwcGluZywgQkNhIGFuZCBwZXJjZW50aWxlIG1ldGhvZHMgKHJlbWVtYmVyIHdlIGNvdmVyZWQgdGhlbSBhdCB0aGUgc3RhcnQgb2YgdGhlIHRlcm0pDQotIEJDYSBjYW4gYmUgYSBiaXQgYW50aS1jb25zZXJ2YXRpdmUgYnV0IG1vcmUgcG93ZXJmdWwsIHBlcmNlbnRpbGUgbWV0aG9kIGlzIGxlc3MgcG93ZXJmdWwgbW9yZSBjb25zZXJ2YXRpdmUgDQoNCiMjIyMgTWVkaWF0aW9uIHBhY2thZ2UgaW4gUg0KLSBZb3Ugd2lsbCBvbmx5IG5lZWQgTW9kZWwuMiAoTX5YKSBhbmQgTW9kZWwuMyAoWX5NK1gpIGZyb20gYWJvdmUNCi0gYnV0IHRoZSBsYW5ndWFnZSBjaGFuZ2VzIGEgYml0IGluIHRoZSB3YXkgd2UgdGFsayBhYm91dCB0aGVzZSB0aGluZ3MgYXMgdGhpcyBwYWNrYWdlIGNhbiBoYW5kbGUgbGFyZ2VyIGRlc2lnbnMgd2l0aCBjb250cm9sIHZhcmlhYmxlcyBhbmQgbWFueSBkaWZmZXJlbnQgdHlwZXMgb2YgcmVncmVzc2lvbnMgKGxpbmVhciwgZ2VuZXJhbGl6ZWQsIGFuZCBtaXhlZCwgbWl4dHVyZSwgY2Vuc29yZWQgYW5kIHN1cnZpdmFsKQ0KIA0KYGBge3IsIGVjaG89VFJVRSwgd2FybmluZz1GQUxTRX0NCmxpYnJhcnkobWVkaWF0aW9uKQ0KTWVkLkJvb3QuQkNhIDwtIG1lZGlhdGUoTW9kZWwuMiwgTW9kZWwuMywgYm9vdCA9IFRSVUUsIA0KICAgICAgICAgICAgICAgICAgICAgICAgYm9vdC5jaS50eXBlID0gImJjYSIsIHNpbXM9MjAwLCB0cmVhdD0iVGltZSIsIG1lZGlhdG9yPSJUcnVzdCIpDQpzdW1tYXJ5KE1lZC5Cb290LkJDYSkNCnBsb3QoTWVkLkJvb3QuQkNhKQ0KYGBgDQoNCi0gQUNNRTogQXZlcmFnZSBDYXVzYWwgTWVkaWF0aW9uIEVmZmVjdHMgKEFDTUUpIFt0b3RhbCBlZmZlY3QgLSBkaXJlY3QgZWZmZWN0XQ0KLSBBREU6IEF2ZXJhZ2UgRGlyZWN0IEVmZmVjdHMgW3RvdGFsIGVmZmVjdCAtIGluZGlyZWN0IGVmZmVjdF0NCi0gVG90YWwgRWZmZWN0ID0gRGlyZWN0IChBREUpICsgSW5kaXJlY3QgKEFDTUUpIA0KLSBUaGVzZSBhcmUgdW5zdGFuZGFyZGl6ZWQgZWZmZWN0cw0KUHJvcC4gTWVkaWF0ZWQ6ICBjb25jZXB0dWFsbHkgQUNNRSAvIFRvdGFsIGVmZmVjdA0KLSBOb3RlOiBJIGRpZCAyMDAgc2ltdWxhdGlvbnMgZm9yIHRpbWUsIGJ1dCAyMDAwIGlzIGJlc3QgaWYgeW91IGFyZSBkb2luZyBCQ2EuDQoNCi0gQnkgY2hhbmdpbmcgdGhlIGNvZGUgd2UgY2FuIGdldCBwZXJjZW50aWxlIG1ldGhvZCBvdmVyIEJDYQ0KDQpgYGB7ciwgZWNobz1UUlVFLCB3YXJuaW5nPUZBTFNFfQ0KTWVkLkJvb3QucGVyYyA8LSBtZWRpYXRlKE1vZGVsLjIsIE1vZGVsLjMsIGJvb3QgPSBUUlVFLCANCiAgICAgICAgICAgICAgICAgICAgICAgICBib290LmNpLnR5cGUgPSAicGVyYyIsIHNpbXM9MjAwLCB0cmVhdD0iVGltZSIsIG1lZGlhdG9yPSJUcnVzdCIpDQpzdW1tYXJ5KE1lZC5Cb290LnBlcmMpDQpwbG90KE1lZC5Cb290LnBlcmMpDQpgYGANCg0KLSBUaGVzZSByZXN1bHRzIG1hdGNoIEJhcm9uIGFuZCBLZW5ueSBhbmQgdGhlIHByb2Nlc3MgbWFjcm8gaW4gU1BTUw0KLSBUaGUgYmVuZWZpdCBoZXJlIGlzIHlvdSB0ZXN0IG1lZGlhdG9yIGluIGdsbSBvciBtaXhlZCAoY2Fubm90IGJlIGRvbmUgc28gZWFzaWx5IGluIFNQU1MpDQotIFRoZSBkcmF3YmFjayBpbiBSIGlzIHlvdSB3YW50IHRvIHRlc3QgdGhpbmdzIGxpa2UgbXVsdGktbWVkaWF0aW9uIHlvdSBuZWVkIHRvIHByb2dyYW0gaXQgeW91cnNlbGYgKGZvciBub3cpDQoNCiMjIyBUZXN0aW5nIHRoZSBtZWRpYXRvciBhcyBtb2RlcmF0b3I/DQotIENvdWxkIGl0IGJlIHRoYXQgb3VyIG1lZGlhdG9yIGlzIHJlYWxseSBqdXN0IGEgbW9kZXJhdG9yPw0KDQojIyBQb3dlcg0KLSBXaGVuIHlvdSBwbGFuIHRvIHJ1biBtZWRpYXRpb24geW91IG11c3QgY2FyZWZ1bGx5IHRoaW5rIGFib3V0IHRoZSBwb3dlciB5b3UgbWlnaHQgbmVlZC4gDQotIEJlY2F1c2UgdGhlIE0gaXMgYmFzaWNhbGx5IGNvbGxpbmVhciBYIHlvdSB3aWxsIG5lZWQgbW9yZSBzdWJqZWN0cyB0aGFuIHlvdSB3b3VsZCBub3JtYWxseSB0aGluayANCi0gS2VubnkgaGFzIHdvcmtlZCBvdXQgYW4gZWFzeSBhcHAgdG8gZXN0aW1hdGUgcG93ZXIgZm9yIHNpbXBsZSBkZXNpZ25zDQotIGh0dHBzOi8vZGF2aWRha2Vubnkuc2hpbnlhcHBzLmlvL01lZFBvd2VyLw0KLSBGb3IgbGFyZ2VyIGRlc2lnbnMgeW91IG5lZWQgdG8gYnVpbGQgY3VzdG9tIHNpbXVsYXRpb25zIGFuZCB0aGUgTWVkaWF0aW9uIHBhY2thZ2UgY2FuIGhlbHAgDQoNCiMjIFBhcnRpYWwgTWVkaWF0aW9uDQotIFdoZW4gdGhlIGRpcmVjdCBlZmZlY3QgYW5kIGluZGlyZWN0IGVmZmVjdCBhcmUgYm90aCByZWFsDQotIE1hbnkgdGltZXMgeW91IGRvbid0IGhhdmUgdGhlIHBvd2VyIGZvciBjb21wbGV0ZSBtZWRpYXRpb24gYW5kIHlvdSBtaWdodCB0aGluayBpdHMgcGFydGlhbCBtZWRpYXRpb24NCi0gS2Vubnkgc3VnZ2VzdHMgdXNpbmcgSGF5ZXMgKDIwMTMpIHJlY29tbWVuZGF0aW9uOiBuZXZlciBkcmF3aW5nIHRoZSBjb25jbHVzaW9uIHRoYXQgaXRzIGNvbXBsZXRlIG9yIHBhcnRpYWwgDQotIEJlbG93IEkgaGF2ZSBjcmVhdGVkIGEgd2VsbC1wb3dlcmVkIChwb3dlciA9IC44KSBleGFtaW5lIGJvdGggdGhlIGRpcmVjdCBhbmQgaW5kaXJlY3QgZWZmZWN0cyANCg0KYGBge3IsIGVjaG89VFJVRSwgd2FybmluZz1GQUxTRX0NCmxpYnJhcnkoY2FyKQ0Kc2V0LnNlZWQoNDIpDQojIEZvciBzaW11bGF0aW9uIG9mIG1lZGlhdGlvbiBzdGVwcyBzZWUgSGFsbGdyZW4sIDIwMTMNCiMgcGF0aCBhIHN0cmVuZ3RoDQphPS40DQojIHBhdGggYiBzdHJlbmd0aA0KYj0uNA0KIyBwYXRoIGMnIHN0cmVuZ3RoDQpjcD0uMg0KIyBwZW9wbGUNCm4gPC0gMTc3DQojIE5vcm1hbCBkaXN0cmlidXRpb24gb2YgdGltZSAobWlucykNClggPC0gcm5vcm0obiwgNSwgMikNCiMgTWVkaWF0b3INCk0gPC0gYSpYK3Jub3JtKG4sIDAsIDEpDQojIE91ciBlcXVhdGlvbiB0byAgY3JlYXRlIFkNClkgPC0gY3AqWCArIGIqTSArIHJub3JtKG4sIHNkPTEpDQojQnVpbHQgb3VyIGRhdGEgZnJhbWUNCk1hcnNobWFsbG93LkRhdGEuUGFydDwtZGF0YS5mcmFtZShTdWNjZXNzPVksVGltZT1YLFRydXN0PU0pDQoNClBhcnQuTW9kZWwuMjwtbG0oVHJ1c3R+VGltZSwgZGF0YT0gTWFyc2htYWxsb3cuRGF0YS5QYXJ0KQ0KDQpQYXJ0Lk1vZGVsLjM8LWxtKFN1Y2Nlc3N+VHJ1c3QrVGltZSwgZGF0YT0gTWFyc2htYWxsb3cuRGF0YS5QYXJ0KQ0KDQpQYXJ0Lk1lZC5Cb290LkJDYSA8LSBtZWRpYXRlKFBhcnQuTW9kZWwuMiwgUGFydC5Nb2RlbC4zLCBib290ID0gVFJVRSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYm9vdC5jaS50eXBlID0gImJjYSIsIHNpbXM9MjAwLCB0cmVhdD0iVGltZSIsIG1lZGlhdG9yPSJUcnVzdCIpDQpzdW1tYXJ5KFBhcnQuTWVkLkJvb3QuQkNhKQ0KcGxvdChQYXJ0Lk1lZC5Cb290LkJDYSkNCmBgYA0KDQoNCg0KIyMgTW9kZXJhdGVkLU1lZGlhdGVkDQotIE1vZGVyYXRpb24gaXMgdHJ5aW5nIHRvIGZpZ3VyZSBvdXQgdGhlIGZhY3RvcnMgdGhleSBpbmZsdWVuY2UgdGhlIHN0cmVuZ3RoIG9mIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBYIHRvIFkNCi0gTWVkaWF0aW9uIGlzIHRyeWluZyB0byBmaWd1cmUgb3V0IHRoZSBpbnRlcm1lZGlhdGluZyBmYWN0b3JzIGludm9sdmVkIGludG8gZ2V0dGluZyBmcm9tIFggdG8gWQ0KLSBNb2RlcmF0ZWQtTWVkaWF0ZWQgaXMgdGhhdCBlZmZlY3Qgb2YgdGhlIG1lZGlhdG9yIGlzIG1vZGVyYXRlZCANCi0gSW4gcHJhY3RpY2FsIHRlcm1zLCB3aGF0IGlmIG91ciBtZWRpYXRpb24gYWJvdmUgKHJlc3BlY3QvdHJ1c3QgaW4gYXV0aG9yaXR5KSB3YXMgbW9kZXJhdGVkIGJ5IHBhcmVudGluZyBzdHlsZXMgb2YgcGFyZW50cw0KLSBTdHJpY3QgcGFyZW50cyBjcmVhdGVkIHJlc3BlY3Qgb2YgdGhlIGF1dGhvcml0eSwgd2hpbGUgcGVybWlzc2l2ZSBwYXJlbnRzIGNyZWF0ZSBvcHBvc2l0aW9uIHRvIGF1dGhvcml0eQ0KLSBNZWFzdXJlbWVudCBzY2FsZSBmcm9tIC0zIHRvIDMgKHBlcm1pc3NpdmUgdG8gYXV0aG9yaXRhdGl2ZSkNCi0gVGh1cyBvdXIgbWVkaWF0aW9uIG9mIHJlc3BlY3QvdHJ1c3QgaXMgc3Ryb25nZXIgZm9yIGtpZHMgd2l0aCBhdXRob3JpdGF0aXZlIHRoYW4gcGVybWlzc2l2ZSBwYXJlbnRzDQotIGJ1dCBpdCBjb3VsZCBhbHNvIGJlIHRoYXQgY2hpbGRyZW4gZnJvbSBhdXRob3JpdGF0aXZlIHBhcmVudHMgd2lsbCBiZSBtdWNoIG1vcmUgd2VsbC1iZWhhdmVkIGluIGdlbmVyYWwNCi0gV2Ugd2lsbCBleGFtaW5lIGRpZmZlcmVudCB0eXBlcyBvZiBtb2RlbHMgdG8gZXhhbWluZSB0aGlzIGVmZmVjdA0KDQpgYGB7ciwgZWNobz1UUlVFLCB3YXJuaW5nPUZBTFNFfQ0Kc2V0LnNlZWQoNDIpDQojIHBhdGggYSBzdHJlbmd0aA0KYT0uNA0KIyBwYXRoIGIgc3RyZW5ndGgNCmI9LjQNCiMgcGF0aCBjJyBzdHJlbmd0aA0KY3A9LjAxDQojICBwZW9wbGUNCm4gPC0gMjY4DQojIE5vcm1hbCBkaXN0cmlidXRpb24gb2YgdGltZSAobWlucykNClggPC0gcm5vcm0obiwgNSwgMikNCiMgTW9kZXJhdG9yDQpNb2Q8LXJ1bmlmKG4sIC0zLCAzKQ0KIyBNZWRpYXRvcg0KTSA8LSBhKlgqTW9kK3Jub3JtKG4sIDAsIDEpDQojIE91ciBlcXVhdGlvbiB0byAgY3JlYXRlIFkNClkgPC0gY3AqWCpNb2QgKyBiKk0gKyBNKk1vZCArIHJub3JtKG4sIHNkPTEpDQojQnVpbHQgb3VyIGRhdGEgZnJhbWUNCk1hcnNobWFsbG93Lk1vZDwtZGF0YS5mcmFtZShTdWNjZXNzPVksVGltZT1YLFRydXN0PU0sUGFyZW50cz1Nb2QpDQpgYGANCg0KIyMjIE1vZGVyYXRpb24gb24gUGF0aCBhLCBiLCBjJyAgDQoNCi0gSW4gdGhpcyBjYXNlIHdlIHRoaW5rIHRoZSBkaXJlY3QgKGMnKSBhbmQgaW5kaXJlY3QgcGF0aCAoYSxiKSBpcyBtb2RlcmF0ZWQgYnkgUGFyZW50aW5nIHN0eWxlDQotIFNvIHdlIGhhdmUgdG8gaW50ZXJhY3QgaXQgaW4gTW9kZWwgMiBhbmQgTW9kZWwgMw0KLSBNb2RlbCAyIGZyb20gS2VubnkgYmVjb21lcywgJE0gfiBYKk1vZCQNCi0gTW9kZWwgMyBmcm9tIEtlbm55IGJlY29tZXMsICRZIH4gTSpNb2QrWCpNb2QkDQotIE5vdGUgdGhpcyBpcyBIYXllcycgcHJvY2VzcyBtb2RlbCA1OQ0KDQpgYGB7ciwgZWNobz1UUlVFLCB3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0UscmVzdWx0cz0nYXNpcyd9DQpNb2QuTWVkLk1vZGVsLjI8LWxtKFRydXN0flRpbWUqUGFyZW50cywgZGF0YT0gTWFyc2htYWxsb3cuTW9kKQ0KDQpzdGFyZ2F6ZXIoTW9kLk1lZC5Nb2RlbC4yLHR5cGU9Imh0bWwiLA0KICAgICAgICAgIGludGVyY2VwdC5ib3R0b20gPSBGQUxTRSwNCiAgICAgICAgICBzaW5nbGUucm93PUZBTFNFLCANCiAgICAgICAgICBub3Rlcy5hcHBlbmQgPSBGQUxTRSwNCiAgICAgICAgICBoZWFkZXI9RkFMU0UpDQoNCk1vZC5NZWQuTW9kZWwuMzwtbG0oU3VjY2Vzc35UcnVzdCpQYXJlbnRzK1RpbWUqUGFyZW50cywgZGF0YT0gTWFyc2htYWxsb3cuTW9kKQ0Kc3RhcmdhemVyKE1vZC5NZWQuTW9kZWwuMyx0eXBlPSJodG1sIiwNCiAgICAgICAgICBpbnRlcmNlcHQuYm90dG9tID0gRkFMU0UsDQogICAgICAgICAgc2luZ2xlLnJvdz1GQUxTRSwgDQogICAgICAgICAgbm90ZXMuYXBwZW5kID0gRkFMU0UsDQogICAgICAgICAgaGVhZGVyPUZBTFNFKQ0KYGBgDQoNCi0gSW4gdGhpcyBtb2RlcmF0aW9uIHBhY2thZ2Ugd2UgbGlzdCB0aGUgbW9kZXJhdG9yIGFzIGEgY292YXJpYXRlIGFuZCBzZXQgdGhlIGxldmVscyB3ZSB3aXNoIHRvIGNvbnRyb2wgZm9yDQotIFdlIGNhbiB1c2UgdGhlICsvLSAxU0QgZnJvbSB0aGUgbWVhbiAoYWxzbyB3ZSBjYW4gdXNlIHplcm8gaWYgd2FudGVkIHRvIHNlZSB0aGUgYXZlcmFnZSBwYXJlbnQpDQotIFRoaXMgYWxsb3dzIHVzIHRvIHZpZXcgaW1wYWN0IG9mIHRoZSBtb2RlcmF0b3Igb24gdGhlIGRpcmVjdCBhbmQgaW5kaXJlY3QgZWZmZWN0DQotIExldHMgbG9vayBhdCBwZXJtaXNzaXZlIHBhcmVudHMgZmlyc3QNCi0gU3RpbGwgbm8gZGlyZWN0IGVmZmVjdCwgYnV0IGFuIGVmZmVjdCBmb3IgQUNNRQ0KDQpgYGB7ciwgZWNobz1UUlVFLCB3YXJuaW5nPUZBTFNFfQ0KUGVybWlzc2l2ZTwtbWVhbihNYXJzaG1hbGxvdy5Nb2QkUGFyZW50cyktc2QoTWFyc2htYWxsb3cuTW9kJFBhcmVudHMpDQpQZXJtaXNzaXZlDQpNb2QuTWVkLkJvb3QuQkNhLjEgPC0gbWVkaWF0ZShNb2QuTWVkLk1vZGVsLjIsIE1vZC5NZWQuTW9kZWwuMywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb3ZhcmlhdGVzID0gbGlzdChQYXJlbnRzID0gUGVybWlzc2l2ZSksIGJvb3QgPSBUUlVFLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJvb3QuY2kudHlwZSA9ICJiY2EiLCBzaW1zPTIwMCwgdHJlYXQ9IlRpbWUiLCBtZWRpYXRvcj0iVHJ1c3QiKQ0Kc3VtbWFyeShNb2QuTWVkLkJvb3QuQkNhLjEpDQpwbG90KE1vZC5NZWQuQm9vdC5CQ2EuMSkNCmBgYA0KDQotIExldHMgbGV0IGxvb2sgYXQgYXV0aG9yaXRhdGl2ZSBwYXJlbnRzIA0KLSBTdGlsbCBubyBkaXJlY3QgZWZmZWN0LCBidXQgYSBzdG9uZ2VyIGVmZmVjdCBmb3IgQUNNRQ0KDQpgYGB7ciwgZWNobz1UUlVFLCB3YXJuaW5nPUZBTFNFfQ0KQXV0aG9yaXRhdGl2ZTwtbWVhbihNYXJzaG1hbGxvdy5Nb2QkUGFyZW50cykrc2QoTWFyc2htYWxsb3cuTW9kJFBhcmVudHMpDQpBdXRob3JpdGF0aXZlDQpNb2QuTWVkLkJvb3QuQkNhLjIgPC0gbWVkaWF0ZShNb2QuTWVkLk1vZGVsLjIsIE1vZC5NZWQuTW9kZWwuMywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb3ZhcmlhdGVzID0gbGlzdChQYXJlbnRzID0gQXV0aG9yaXRhdGl2ZSksIGJvb3QgPSBUUlVFLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJvb3QuY2kudHlwZSA9ICJiY2EiLCBzaW1zPTIwMCwgdHJlYXQ9IlRpbWUiLCBtZWRpYXRvcj0iVHJ1c3QiKQ0Kc3VtbWFyeShNb2QuTWVkLkJvb3QuQkNhLjIpDQpwbG90KE1vZC5NZWQuQm9vdC5CQ2EuMikNCmBgYA0KDQoNCi0gVG8gZ2V0IGEgc2lnbmlmaWNhbmNlIHRlc3Qgb24gaWYgdGhlIG1vZGVyYXRvciBpcyBjYXVzaW5nIGEgZGlmZmVyZW5jZSBpbiB0aGUgZGlyZWN0IG9yIGluZGlyZWN0IGVmZmVjdHMgd2UgY2FuIHVzZSB0aGlzIGNvZGUNCi0gTm90ZTogDQpgYGB7ciwgZWNobz1UUlVFLCB3YXJuaW5nPUZBTFNFfQ0KTW9kLk1lZC5Cb290LkJDYS4zIDwtIG1lZGlhdGUoTW9kLk1lZC5Nb2RlbC4yLCBNb2QuTWVkLk1vZGVsLjMsIGJvb3QgPSBUUlVFLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJvb3QuY2kudHlwZSA9ICJiY2EiLCBzaW1zPTUsIHRyZWF0PSJUaW1lIiwgbWVkaWF0b3I9IlRydXN0IikNCnRlc3QubW9kbWVkKE1vZC5NZWQuQm9vdC5CQ2EuMywgY292YXJpYXRlcy4xID0gbGlzdChQYXJlbnRzID0gUGVybWlzc2l2ZSksDQogICAgICAgICAgICBjb3ZhcmlhdGVzLjIgPSBsaXN0KFBhcmVudHMgPSBBdXRob3JpdGF0aXZlKSwgc2ltcyA9IDIwMCkNCg0KYGBgDQoNCi0gU28gd2Ugc2VlIHRoZSBpbmRpcmVjdCBlZmZlY3RzIGRpZmZlciwgYnV0IHRoZSBkaXJlY3QgZWZmZWN0cyBkbyBub3QNCi0gU28gaXQgc2VlbXMgdGhlIGluZGlyZWN0IGVmZmVjdCBpcyBtb2RlcmF0ZWQgYnkgcGFyZW50aW5nIHN0eWxlIGluIHRoZSBkaXJlY3Rpb24gd2UgcHJlZGljdA0KDQoNCg0KPHNjcmlwdD4NCiAgKGZ1bmN0aW9uKGkscyxvLGcscixhLG0pe2lbJ0dvb2dsZUFuYWx5dGljc09iamVjdCddPXI7aVtyXT1pW3JdfHxmdW5jdGlvbigpew0KICAoaVtyXS5xPWlbcl0ucXx8W10pLnB1c2goYXJndW1lbnRzKX0saVtyXS5sPTEqbmV3IERhdGUoKTthPXMuY3JlYXRlRWxlbWVudChvKSwNCiAgbT1zLmdldEVsZW1lbnRzQnlUYWdOYW1lKG8pWzBdO2EuYXN5bmM9MTthLnNyYz1nO20ucGFyZW50Tm9kZS5pbnNlcnRCZWZvcmUoYSxtKQ0KICB9KSh3aW5kb3csZG9jdW1lbnQsJ3NjcmlwdCcsJ2h0dHBzOi8vd3d3Lmdvb2dsZS1hbmFseXRpY3MuY29tL2FuYWx5dGljcy5qcycsJ2dhJyk7DQoNCiAgZ2EoJ2NyZWF0ZScsICdVQS05MDQxNTE2MC0xJywgJ2F1dG8nKTsNCiAgZ2EoJ3NlbmQnLCAncGFnZXZpZXcnKTsNCg0KPC9zY3JpcHQ+