Longitudinal Designs

  • Longitudinal generally means you measure a person over time. Thus, the person is the level 2 (the cluster) and Time is the level 1.
    • At least 3 measurements for that person: Longitudinal can be defined in seconds, minutes, days, weeks, years, or decades.
    • Time is repeated measure on the subject, but you are interested in charting how they change over time

Mixed Model framework for Longitudinal

  • Mixed models have some major advantages over RM ANOVA approach to dealing with time
      1. Intercept differences: do different treatments have different baselines
      1. Slope differences between treatments
      1. Growth curves: Are slopes linear or curvilinear
      • 3a) Each subject can have a different slope and slope shape
      1. Time measurements do not need to be the same for each subject: Subject 1: Month 1,2,4,6, Subject 2: Month 2,3,5,7
      • 4a) This because you can have missing data in your measurements: in RM ANOVA this would mean you lose the whole subject
      1. You test for discontinuities in time: For example, treatment changes during the measurements (think elbow shaped slope)
      • Subjects have 3 baselines: Month 1, 2, 3 and at Month 4 they start treatment, and you have two more measurements. Thus you want to see if the slope during no treatment for that subject changes after treatment
      1. We can measure Time Fixed Covariates: Covariate does not change over the measurement period (DV = Depression score at each treatment, Covariate = Trait Anxiety level)
      1. We can measure Time Variable Covariates: Covariate that change over the measurement period (DV = Depression score at each treatment, Covariate = State Anxiety level during a therapy session)
      1. Interact Time Fixed and Time Variable covariates
      1. You can control the covariance structure and use autoregressive structures (but not in lme4)
      1. Deal with nested forms of Time: For example, month to month change in Anxiety levels, but you can also examine hour to hour Anxiety levels (nested in the month they were collected)

Simplest Type of Longitudinal Model

Children with ASD typically have difficulty with motor skill and poor interpersonal coordination. Their reduced ability to coordinate with people maybe be causing them to be left out of play with other children isolating them. Past efforts to improve their interpersonal coordination have often failed because children with ASD are overwhelmed by people. So training sessions often fail. However, children with ASD gravitate towards electronics and have been observed to be interested and comfortable with robots. Srinivasan et al., (2015) hypothesized that children with ASD might be better at coordinating with robots because a) children with ASD love robots, and b) robots are less threatening as they convey less information (not overwhelming the child). Srinivasan et al., (2015) found that having children “dance” with dancing robots improved their interpersonal coordination ability.

Today we will examine a simulated study of interpersonal coordination on 12 children with ASD. Each child underwent 6 training sessions (including the baseline where they had an ASD assessment to see where they were on the spectrum; Chlebowski et al. 2010). The children were asked to “dance” with an instructor and their parent in each of the 6 sessions. In the last part of the session their degree of coordination (from 0 - 1) with the new instructor who was in the room during the session, but did not dance. For half the children the instructor was human, and for the other half, the instructor was a robot.

Data

  • As with all our other analysis, the data is in long format (for Longitudinal you might see it called period-period data)
    • Time is coded to start at 0 (baseline or first measurement).
    • Instructor (0,1): 0: Human; 1: Robot
    • Coordination (0-1): Degree of coordination (DV)
    • ASD: ASD spectrum score (possible covariate)
    • Download data
LongSim<-read.csv("Mixed/LongData1.csv")
Subject Time Instructor Coordination ASD
1 0 0 0.2220880 26.07486
1 1 0 0.2780595 26.07486
1 2 0 0.2701741 26.07486
1 3 0 0.1431913 26.07486
1 4 0 0.4037957 26.07486
1 5 0 0.3261772 26.07486

Coding

  • Decisions have to be made about how to code Instructor
    • Dummy or effects code it? For today lets just dummy code our treatment
#Dummy
LongSim$Instructor.D<-factor(LongSim$Instructor,
                             levels = c(0,1),
                             labels = c("Human","Robot"))
  • Decisions have to be made about how to code Time. Each again will change how we interpret our model. We will code it out now for later:
    • We can leave Time as is: it starts at 0 and progresses in the units of measurements
    • Center time Time: So there are 6 sessions (0-5), thus center is 2.5: So Session # - 2.5
    • (Note: yes you can Zscore time or Zscore and NOT center as well)
# Centered
LongSim$Time.C<-scale(LongSim$Time, scale=F, center=T)[,]

Spaghetti Plots

  • Longitudinal Models are best assessed with spaghetti plots. When you have a small number of subjects, you can plot it as “facets.”
  • We will plot each person in a facet and add their linear model for each subject
# Make sure that subject is a factor
LongSim$Subject<-as.factor(LongSim$Subject)

Speg.1<-ggplot(data = LongSim, aes(x=Time,y=Coordination))+
  facet_wrap(~Subject)+
  geom_point(aes(color=Instructor.D))+
  geom_smooth(method='lm', se=FALSE,aes(color=Instructor.D))+
  xlab("Time")+ylab("Coordination")+
  theme_bw()+
  theme(legend.position = "top")
Speg.1

  • If you have too many subjects, you can plot the results like this instead
  • On the left, you can fit a regression per subject, on the right you plot lines instead of the slope
theme_set(theme_bw(base_size = 7, base_family = ""))

Speg.2<-ggplot(data = LongSim, aes(x=Time,y=Coordination, group=Subject, color=Subject))+
  facet_wrap(~Instructor.D)+
  geom_point()+
  geom_smooth(method='lm', se=FALSE)+
  xlab("Time")+ylab("Coordination")+
  theme(legend.position = "none")
Speg.2

Speg.3<-ggplot(data = LongSim, aes(x=Time,y=Coordination, group=Subject, color=Subject))+
  facet_wrap(~Instructor.D)+
  geom_point()+
  geom_line()+
  xlab("Time")+ylab("Coordination")+
  theme(legend.position = "none")
Speg.3

Modeling to Examine Random Structure

  • The subject is the Level 2 variable (just like in our repeated measures mixed models)
  • We can show that via our ICC analysis

Intercepts only model

Null<-lmer(Coordination ~ 1+(1|Subject), data=LongSim, REML=FALSE)
sjstats::icc(Null)
## # Intraclass Correlation Coefficient
## 
##     Adjusted ICC: 0.420
##   Unadjusted ICC: 0.420

Intercepts only plot

  • Predict out the model results
  • Dots = Real data
  • Line = Predicted result
theme_set(theme_bw(base_size = 7, base_family = ""))

LongSim$Null<-predict(Null, newdata=LongSim)

Speg.Null.1<-ggplot(data = LongSim)+
  facet_wrap(~Subject)+
  geom_point(aes(x=Time,y=Coordination,color=Instructor.D))+
  geom_line(aes(x=Time,y=Null, color=Instructor.D))+
  xlab("Time")+ylab("Coordination")+
  theme(legend.position = "top")
Speg.Null.1

Speg.Null.2<-ggplot(data = LongSim)+
  facet_wrap(~Instructor.D)+
  geom_point(aes(x=Time,y=Coordination, group=Subject,color=Subject))+
  geom_line(aes(x=Time,y=Null,group=Subject,color=Subject))+
  xlab("Time")+ylab("Coordination")+
  theme(legend.position = "none")
Speg.Null.2

- Notice that each subject has their own intercept, but no slope

Random Intercepts and Slopes Model

  • We will let the intercept and Time vary relative to each subject: (1+Time|Subject)
    • Note you can block the correlation between the slope/intercept like before if the correlation is -1/1: (1+Time||Subject)
RISlope<-lmer(Coordination ~ 1+(1+Time|Subject), data=LongSim, REML=FALSE)
summary(RISlope)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: Coordination ~ 1 + (1 + Time | Subject)
##    Data: LongSim
## 
##      AIC      BIC   logLik deviance df.resid 
##   -102.0    -90.6     56.0   -112.0       67 
## 
## Scaled residuals: 
##      Min       1Q   Median       3Q      Max 
## -2.21989 -0.52703  0.01245  0.55970  2.00199 
## 
## Random effects:
##  Groups   Name        Variance Std.Dev. Corr
##  Subject  (Intercept) 0.004804 0.06931      
##           Time        0.004751 0.06893  0.42
##  Residual             0.005488 0.07408      
## Number of obs: 72, groups:  Subject, 12
## 
## Fixed effects:
##             Estimate Std. Error       df t value Pr(>|t|)    
## (Intercept)  0.26005    0.02481 12.00035   10.48 2.15e-07 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Random Intercept and Slopes Plot

  • Predict out the model results
  • Dots = Real data
  • Line = Predicted result
theme_set(theme_bw(base_size = 7, base_family = ""))

LongSim$RISlope<-predict(RISlope, newdata=LongSim)
Speg.R.I.Slope.1<-ggplot(data = LongSim)+
  facet_wrap(~Subject)+
  geom_point(aes(x=Time,y=Coordination, color=Instructor.D))+
  geom_line(aes(x=Time,y=RISlope, color=Instructor.D))+
  xlab("Time")+ylab("Coordination")+
  theme(legend.position = "top")
Speg.R.I.Slope.1

Speg.R.I.Slope.2<-ggplot(data = LongSim)+
  facet_wrap(~Instructor.D)+
  geom_point(aes(x=Time,y=Coordination, group=Subject,color=Subject))+
  geom_line(aes(x=Time,y=RISlope,group=Subject,color=Subject))+
  xlab("Time")+ylab("Coordination")+
  theme(legend.position = "none")
Speg.R.I.Slope.2

Random Slopes Only Model

  • It could be there is no random intercept, so you can remove it (but you need to have a reason)
  • We will let Time vary relative to each subject: (0+Time|Subject)
RSlope<-lmer(Coordination ~ 1+(0+Time|Subject), data=LongSim, REML=FALSE)
summary(RSlope)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: Coordination ~ 1 + (0 + Time | Subject)
##    Data: LongSim
## 
##      AIC      BIC   logLik deviance df.resid 
##    -99.3    -92.5     52.6   -105.3       69 
## 
## Scaled residuals: 
##      Min       1Q   Median       3Q      Max 
## -2.54802 -0.53178 -0.00811  0.59543  2.92944 
## 
## Random effects:
##  Groups   Name Variance Std.Dev.
##  Subject  Time 0.005376 0.07332 
##  Residual      0.007289 0.08538 
## Number of obs: 72, groups:  Subject, 12
## 
## Fixed effects:
##             Estimate Std. Error       df t value Pr(>|t|)    
## (Intercept)  0.28463    0.01739 65.05840   16.36   <2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Random Slopes Only Plot

  • Predict out the model results
  • Dots = Real data
  • Line = Predicted result
theme_set(theme_bw(base_size = 7, base_family = ""))

LongSim$RSlope<-predict(RSlope, newdata=LongSim)

Speg.R.Slope.1<-ggplot(data = LongSim)+
  facet_wrap(Instructor.D~Subject)+
  geom_point(aes(x=Time,y=Coordination, color=Instructor.D))+
  geom_line(aes(x=Time,y=RSlope, color=Instructor.D))+
  xlab("Time")+ylab("Coordination")+
  theme(legend.position = "top")
Speg.R.Slope.1

Speg.R.Slope.2<-ggplot(data = LongSim)+
  facet_wrap(~Instructor.D)+
  geom_point(aes(x=Time,y=Coordination, group=Subject,color=Subject))+
  geom_line(aes(x=Time,y=RSlope,group=Subject,color=Subject))+
  xlab("Time")+ylab("Coordination")+
  theme(legend.position = "none")
Speg.R.Slope.2

  • Note: The intercepts for each subject are the same.
  • You can also guess that this model will not be a good fit as the last one, which we can test:
anova(RSlope,RISlope)
## Data: LongSim
## Models:
## RSlope: Coordination ~ 1 + (0 + Time | Subject)
## RISlope: Coordination ~ 1 + (1 + Time | Subject)
##         npar      AIC     BIC logLik deviance  Chisq Df Pr(>Chisq)  
## RSlope     3  -99.287 -92.457 52.643  -105.29                       
## RISlope    5 -102.000 -90.617 56.000  -112.00 6.7134  2    0.03485 *
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Modeling for Results

  • The goal above was to understand the random effects. This is useful if you want to understand your data, but when you move to modeling for publication you will want to set your random effects and move to fixed effect testing
  • The most obvious structure for most longitudinal (2 level) data is to use random slopes and intercepts (watch that correlation between them)
  • We will now also explore the different coding schemes to understand the models

Non-Centered Time & Dummy coded Instructor

  • Note: because Instructor is 0/1 coded you can also enter that into the model instead of it as a factor (you will get the same answer)

Main effects

MainEffect.1<-lmer(Coordination ~ Time+Instructor.D+(1+Time|Subject), data=LongSim, REML=FALSE)
summary(MainEffect.1, correlation=FALSE)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: Coordination ~ Time + Instructor.D + (1 + Time | Subject)
##    Data: LongSim
## 
##      AIC      BIC   logLik deviance df.resid 
##   -113.8    -97.9     63.9   -127.8       65 
## 
## Scaled residuals: 
##      Min       1Q   Median       3Q      Max 
## -2.15774 -0.56020  0.04558  0.61775  1.91569 
## 
## Random effects:
##  Groups   Name        Variance Std.Dev. Corr
##  Subject  (Intercept) 0.003360 0.05796      
##           Time        0.001327 0.03642  0.15
##  Residual             0.005488 0.07408      
## Number of obs: 72, groups:  Subject, 12
## 
## Fixed effects:
##                   Estimate Std. Error       df t value Pr(>|t|)    
## (Intercept)        0.23232    0.03206 12.08500   7.247  9.8e-06 ***
## Time               0.05852    0.01169 11.99995   5.005 0.000307 ***
## Instructor.DRobot  0.08358    0.04509 11.99994   1.854 0.088498 .  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Interpretation
  • Time: After each session, the kids get are better at coordinating regardless of Instruction (the estimate is the slope over sessions)
  • Instructor.DRobot: t < 1.96 (so not significant). Had it been significant it would mean that kids who had the robot instructor had overall higher coordination [averaged over all session] (the estimate reported is the difference between human and robot)

Interaction

Interaction.1<-lmer(Coordination ~ Time*Instructor.D+(1+Time|Subject), data=LongSim, REML=FALSE)
summary(Interaction.1, correlation=F)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: Coordination ~ Time * Instructor.D + (1 + Time | Subject)
##    Data: LongSim
## 
##      AIC      BIC   logLik deviance df.resid 
##   -115.5    -97.3     65.7   -131.5       64 
## 
## Scaled residuals: 
##      Min       1Q   Median       3Q      Max 
## -2.17344 -0.56178  0.04976  0.64212  2.08058 
## 
## Random effects:
##  Groups   Name        Variance  Std.Dev. Corr
##  Subject  (Intercept) 0.0033241 0.05766      
##           Time        0.0008965 0.02994  0.25
##  Residual             0.0054877 0.07408      
## Number of obs: 72, groups:  Subject, 12
## 
## Fixed effects:
##                        Estimate Std. Error       df t value Pr(>|t|)    
## (Intercept)             0.23829    0.03214 12.00007   7.414 8.12e-06 ***
## Time                    0.03777    0.01420 11.99972   2.660   0.0208 *  
## Instructor.DRobot       0.07163    0.04546 12.00007   1.576   0.1411    
## Time:Instructor.DRobot  0.04148    0.02008 11.99972   2.065   0.0612 .  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Interpretation
  • Time: slope over sessions for kids who had the human instructor.
  • Instructor.DRobot: It is the difference between human and robot when Time = 0 [Baseline].
    • To prove this we can fit the model and subtract the fitted values: Robot @ Time 0 - Human @ Time 0
library(effects)
effect(c("Time*Instructor.D"),Interaction.1)
Time Instructor.D fit se lower upper
0 Human 0.2383 0.0321 0.1742 0.3024
1 Human 0.2761 0.0334 0.2093 0.3428
2 Human 0.3138 0.0401 0.2338 0.3938
4 Human 0.3894 0.0616 0.2665 0.5123
5 Human 0.4272 0.0741 0.2793 0.5751
0 Robot 0.3099 0.0321 0.2458 0.3741
1 Robot 0.3892 0.0334 0.3224 0.4559
2 Robot 0.4684 0.0401 0.3884 0.5484
4 Robot 0.6269 0.0616 0.5040 0.7499
5 Robot 0.7062 0.0741 0.5583 0.8541
- Estimate of **Instructor.DRobot**: 0.3099211 - 0.2382928 = 0.0716283
    - Note: *You are missing the simple effect of Human @ Time 0*. Relevel instructor to test if you need to know.
  • Time:Instructor.DRobot: slope over sessions difference = slope @ robot instructor - slope @ human instructor

Centered Time & Dummy coded Instructor

  • Note: Because Instructor is 0/1 coded you can also enter that into the model instead of it as factor (you will get the same answer)

Main effects

MainEffect.2<-lmer(Coordination ~ Time.C+Instructor.D+(1+Time|Subject), data=LongSim, REML=FALSE)
summary(MainEffect.2, correlation=F)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: Coordination ~ Time.C + Instructor.D + (1 + Time | Subject)
##    Data: LongSim
## 
##      AIC      BIC   logLik deviance df.resid 
##   -113.8    -97.9     63.9   -127.8       65 
## 
## Scaled residuals: 
##      Min       1Q   Median       3Q      Max 
## -2.15774 -0.56020  0.04558  0.61775  1.91569 
## 
## Random effects:
##  Groups   Name        Variance Std.Dev. Corr
##  Subject  (Intercept) 0.003360 0.05796      
##           Time        0.001327 0.03642  0.15
##  Residual             0.005488 0.07408      
## Number of obs: 72, groups:  Subject, 12
## 
## Fixed effects:
##                   Estimate Std. Error       df t value Pr(>|t|)    
## (Intercept)        0.37861    0.04105 14.18874   9.223 2.26e-07 ***
## Time.C             0.05852    0.01169 11.99995   5.005 0.000307 ***
## Instructor.DRobot  0.08358    0.04509 11.99994   1.854 0.088498 .  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Interpretation
  • Same as non-centered

Interaction

  • Now things will change because the zero-point in time is now the middle of the session (not the baseline)
Interaction.2<-lmer(Coordination ~ Time.C*Instructor.D+(1+Time|Subject), data=LongSim, REML=FALSE)
summary(Interaction.2, correlation=F)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: Coordination ~ Time.C * Instructor.D + (1 + Time | Subject)
##    Data: LongSim
## 
##      AIC      BIC   logLik deviance df.resid 
##   -115.5    -97.3     65.7   -131.5       64 
## 
## Scaled residuals: 
##      Min       1Q   Median       3Q      Max 
## -2.17344 -0.56178  0.04976  0.64212  2.08058 
## 
## Random effects:
##  Groups   Name        Variance  Std.Dev. Corr
##  Subject  (Intercept) 0.0033241 0.05766      
##           Time        0.0008965 0.02994  0.25
##  Residual             0.0054877 0.07408      
## Number of obs: 72, groups:  Subject, 12
## 
## Fixed effects:
##                          Estimate Std. Error       df t value Pr(>|t|)    
## (Intercept)               0.33273    0.04476 11.99999   7.434  7.9e-06 ***
## Time.C                    0.03777    0.01420 11.99972   2.660   0.0208 *  
## Instructor.DRobot         0.17533    0.06329 11.99999   2.770   0.0170 *  
## Time.C:Instructor.DRobot  0.04148    0.02008 11.99972   2.065   0.0612 .  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Interpretation
  • Time: slope for kids who had the human instructor.
  • Instructor.DRobot: It is the difference between human and robot when Time = 0. But remember Time 0 equals the Middle Session!
    • To prove this, we can fit the model and subtract the fitted values: Robot @ Time 0 - Human @ Time 0 [Middle session]
effect(c("Time.C*Instructor.D"),Interaction.2)
Time.C Instructor.D fit se lower upper
-2 Human 0.2572 0.0320 0.1933 0.3211
-1 Human 0.2950 0.0362 0.2227 0.3672
0 Human 0.3327 0.0448 0.2434 0.4220
1 Human 0.3705 0.0556 0.2595 0.4816
2 Human 0.4083 0.0678 0.2730 0.5435
-2 Robot 0.3495 0.0320 0.2857 0.4134
-1 Robot 0.4288 0.0362 0.3565 0.5011
0 Robot 0.5081 0.0448 0.4188 0.5974
1 Robot 0.5873 0.0556 0.4763 0.6984
2 Robot 0.6666 0.0678 0.5313 0.8018
- Estimate of **Instructor.DRobot**: 0.5080641 - 0.3327298 = 0.1753344
  • Time:Instructor.DRobot: slope over sessions difference = slope @ robot instructor - slope @ human instructor

Summary

  • To center time or not center time?
  • This all depends on what story you need to tell
  • In the interaction model:
    • if you don’t center time, you are talking about the baseline. In this case, it seems very useful to be able to say the kids with ASD started out at the same level of coordination and over time their slopes changed
    • if you center time you are talking about the middle session, I find this less useful for the question at hand, but keep it in mind that you can examine it this way

Plot our Final Model

  • We can use the effects package and ggplot to plot the fitted model
library(effects)
Fitted.I1<-effect(c("Time*Instructor.D"),Interaction.1)
Fitted.I1<-as.data.frame(Fitted.I1)

Fitted.Plot<-ggplot(data = Fitted.I1, aes(x=Time,y=fit, group=Instructor.D))+
  geom_line(aes(color=Instructor.D))+
  geom_ribbon(aes(ymin=lower,ymax=upper,fill=Instructor.D),alpha=.2)+
  xlab("Session")+ylab("Coordination")+
  scale_y_continuous(lim=c(0,1),breaks = seq(0, 1,.2)) +
  theme_bw()+
  theme(legend.position = c(.85,.875),
        legend.title = element_blank(),
        panel.grid.major = element_line(linetype = "blank"),
        panel.grid.minor = element_line(linetype = "blank"))
Fitted.Plot

Fixed Covariates

  • We had a covariate: each kids autism spectrum score.
  • We can simply add it to our model if we want to control for it, but you really should center it so you intercept does not change.
LongSim$ASD.C<-scale(LongSim$ASD, scale=F, center=T)[,]
  • You can add it to your model just as any regression
Cov1.Model<-lmer(Coordination ~ Time*Instructor.D+ASD.C
                +(1+Time|Subject), data=LongSim, REML=FALSE)
summary(Cov1.Model, correlation=F)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: Coordination ~ Time * Instructor.D + ASD.C + (1 + Time | Subject)
##    Data: LongSim
## 
##      AIC      BIC   logLik deviance df.resid 
##   -125.0   -104.5     71.5   -143.0       63 
## 
## Scaled residuals: 
##      Min       1Q   Median       3Q      Max 
## -2.13957 -0.60777  0.05259  0.66668  1.77972 
## 
## Random effects:
##  Groups   Name        Variance Std.Dev. Corr
##  Subject  (Intercept) 0.001085 0.03294      
##           Time        0.001052 0.03244  1.00
##  Residual             0.004844 0.06960      
## Number of obs: 72, groups:  Subject, 12
## 
## Fixed effects:
##                          Estimate Std. Error         df t value Pr(>|t|)    
## (Intercept)             0.2739315  0.0261886 18.4814776  10.460 3.39e-09 ***
## Time                    0.0377748  0.0148838 12.3504929   2.538 0.025558 *  
## Instructor.DRobot       0.0003509  0.0391905 19.1578812   0.009 0.992948    
## ASD.C                  -0.0657266  0.0167110 25.5959845  -3.933 0.000569 ***
## Time:Instructor.DRobot  0.0414824  0.0210488 12.3504929   1.971 0.071583 .  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## optimizer (nloptwrap) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')

Note: the correlation between the intercept and slope = 1, so we should block that moving forward and we would go back and block it in prior models to they are all have the same random structure. For now we will ignore it and move on

anova(Interaction.1,Cov1.Model)
## Data: LongSim
## Models:
## Interaction.1: Coordination ~ Time * Instructor.D + (1 + Time | Subject)
## Cov1.Model: Coordination ~ Time * Instructor.D + ASD.C + (1 + Time | Subject)
##               npar     AIC      BIC logLik deviance  Chisq Df Pr(>Chisq)    
## Interaction.1    8 -115.48  -97.265 65.739  -131.48                         
## Cov1.Model       9 -124.95 -104.462 71.476  -142.95 11.474  1  0.0007059 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
  • Our slope is no longer significant, meaning the covariate might be explaining some of our interaction at the mean level of ASD score. This is suggestive of 3-way interaction.
Cov2.Model<-lmer(Coordination ~ Time*Instructor.D*ASD.C
                +(1+Time|Subject), data=LongSim, REML=FALSE)
summary(Cov2.Model, correlation=F)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: Coordination ~ Time * Instructor.D * ASD.C + (1 + Time | Subject)
##    Data: LongSim
## 
##      AIC      BIC   logLik deviance df.resid 
##   -127.7   -100.4     75.9   -151.7       60 
## 
## Scaled residuals: 
##      Min       1Q   Median       3Q      Max 
## -2.25728 -0.53957 -0.00054  0.73048  1.68226 
## 
## Random effects:
##  Groups   Name        Variance  Std.Dev. Corr
##  Subject  (Intercept) 0.0005812 0.02411      
##           Time        0.0004871 0.02207  1.00
##  Residual             0.0047984 0.06927      
## Number of obs: 72, groups:  Subject, 12
## 
## Fixed effects:
##                               Estimate Std. Error        df t value Pr(>|t|)
## (Intercept)                   0.290973   0.027451 25.063026  10.600 9.49e-11
## Time                          0.042820   0.013615 13.221798   3.145  0.00761
## Instructor.DRobot            -0.005657   0.037056 25.063026  -0.153  0.87989
## ASD.C                        -0.097154   0.028438 25.063026  -3.416  0.00217
## Time:Instructor.DRobot        0.051314   0.018379 13.221798   2.792  0.01506
## Time:ASD.C                   -0.009305   0.014105 13.221798  -0.660  0.52075
## Instructor.DRobot:ASD.C       0.051776   0.034086 25.063026   1.519  0.14128
## Time:Instructor.DRobot:ASD.C  0.036742   0.016906 13.221798   2.173  0.04849
##                                 
## (Intercept)                  ***
## Time                         ** 
## Instructor.DRobot               
## ASD.C                        ** 
## Time:Instructor.DRobot       *  
## Time:ASD.C                      
## Instructor.DRobot:ASD.C         
## Time:Instructor.DRobot:ASD.C *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## optimizer (nloptwrap) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
anova(Cov1.Model,Cov2.Model)
## Data: LongSim
## Models:
## Cov1.Model: Coordination ~ Time * Instructor.D + ASD.C + (1 + Time | Subject)
## Cov2.Model: Coordination ~ Time * Instructor.D * ASD.C + (1 + Time | Subject)
##            npar     AIC     BIC logLik deviance  Chisq Df Pr(>Chisq)  
## Cov1.Model    9 -124.95 -104.46 71.476  -142.95                       
## Cov2.Model   12 -127.74 -100.42 75.872  -151.74 8.7914  3     0.0322 *
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
  • The three way improved the model fit.
  • Time:Instructor.DRobot: is the slope over sessions difference = slope @ robot instructor - slope @ human instructor [@ at the average ASD level]
  • Time:Instructor.DRobot:ASD.C: is the slope over sessions difference = slope @ robot instructor - slope @ human instructor [as a function of ASD score]
    • So the slope difference between robot and human instructor is getting larger as ASD level increases. See the plot below to understand this:

Plot 3-Way

  • We will plot it like any other interaction in a regression involving two continuous variables
  • We will need to find 1 SD above/below the mean of the covariate (which was mean centered)
SDN1<- -sd(LongSim$ASD.C)
SDP1<- +sd(LongSim$ASD.C)

Fitted.Cov2<-effect(c("Time*Instructor.D*ASD.C"),Cov2.Model, 
                    xlevel=list(Time=seq(0,5,1),
                                ASD.C=c(SDN1,0,SDP1)))
Fitted.Cov2<-as.data.frame(Fitted.Cov2)

Fitted.Cov2$ASD<-factor(Fitted.Cov2$ASD.C, 
                           levels=c(SDN1,0,SDP1),
                           labels=c("-1 SD ASD","Mean ASD","+1 SD ASD"))

Fitted.Plot.2<-ggplot(data = Fitted.Cov2, aes(x=Time,y=fit, group=Instructor.D))+
  facet_grid(~ASD)+
  geom_line(aes(color=Instructor.D))+
  geom_ribbon(aes(ymin=lower,ymax=upper,fill=Instructor.D),alpha=.2)+
  xlab("Session")+ylab("Coordination")+
  scale_y_continuous(lim=c(0,1),breaks = seq(0, 1,.2)) +
  theme_bw()+
  theme(legend.position = c(.15,.85),
        legend.title = element_blank(),
        panel.grid.major = element_line(linetype = "blank"),
        panel.grid.minor = element_line(linetype = "blank"))
Fitted.Plot.2

Test of Simple Interactions

  • If you want to know if the interaction is significant at each level of ASD score, you simply have to re-center the ASD. We already know the middle plot was significant. We are going to watch the Time:Instructor.DRobot terms as we change the center point at ASD.C

Test -1 SD of ASD

  • We move the center to be -1 SD by adding 1 SD
LongSim$ASD.N1sd<-LongSim$ASD.C+sd(LongSim$ASD.C)
Cov2.Model.Simple.N1sd<-lmer(Coordination ~ Time*Instructor.D*ASD.N1sd
                +(1+Time|Subject), data=LongSim, REML=FALSE)
summary(Cov2.Model.Simple.N1sd, correlation=F)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: Coordination ~ Time * Instructor.D * ASD.N1sd + (1 + Time | Subject)
##    Data: LongSim
## 
##      AIC      BIC   logLik deviance df.resid 
##   -127.7   -100.4     75.9   -151.7       60 
## 
## Scaled residuals: 
##      Min       1Q   Median       3Q      Max 
## -2.25728 -0.53957 -0.00054  0.73048  1.68226 
## 
## Random effects:
##  Groups   Name        Variance  Std.Dev. Corr
##  Subject  (Intercept) 0.0005812 0.02411      
##           Time        0.0004871 0.02207  1.00
##  Residual             0.0047984 0.06927      
## Number of obs: 72, groups:  Subject, 12
## 
## Fixed effects:
##                                  Estimate Std. Error        df t value Pr(>|t|)
## (Intercept)                      0.404358   0.053652 25.063026   7.537 6.74e-08
## Time                             0.053680   0.026610 13.221798   2.017  0.06444
## Instructor.DRobot               -0.066083   0.059432 25.063026  -1.112  0.27673
## ASD.N1sd                        -0.097154   0.028438 25.063026  -3.416  0.00217
## Time:Instructor.DRobot           0.008433   0.029477 13.221798   0.286  0.77924
## Time:ASD.N1sd                   -0.009305   0.014105 13.221798  -0.660  0.52075
## Instructor.DRobot:ASD.N1sd       0.051776   0.034086 25.063026   1.519  0.14128
## Time:Instructor.DRobot:ASD.N1sd  0.036742   0.016906 13.221798   2.173  0.04849
##                                    
## (Intercept)                     ***
## Time                            .  
## Instructor.DRobot                  
## ASD.N1sd                        ** 
## Time:Instructor.DRobot             
## Time:ASD.N1sd                      
## Instructor.DRobot:ASD.N1sd         
## Time:Instructor.DRobot:ASD.N1sd *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## optimizer (nloptwrap) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
  • Time:Instructor.DRobot is not significant. So the left panel is our graph is not an interaction

Test +1 SD of ASD

  • We move the center to be +1 SD by subtracting 1 SD
LongSim$ASD.P1sd<-LongSim$ASD.C-sd(LongSim$ASD.C)
Cov2.Model.Simple.P1sd<-lmer(Coordination ~ Time*Instructor.D*ASD.P1sd
                +(1+Time|Subject), data=LongSim, REML=FALSE)
summary(Cov2.Model.Simple.P1sd, correlation=F)
## Linear mixed model fit by maximum likelihood . t-tests use Satterthwaite's
##   method [lmerModLmerTest]
## Formula: Coordination ~ Time * Instructor.D * ASD.P1sd + (1 + Time | Subject)
##    Data: LongSim
## 
##      AIC      BIC   logLik deviance df.resid 
##   -127.7   -100.4     75.9   -151.7       60 
## 
## Scaled residuals: 
##      Min       1Q   Median       3Q      Max 
## -2.25728 -0.53957 -0.00054  0.73048  1.68226 
## 
## Random effects:
##  Groups   Name        Variance  Std.Dev. Corr
##  Subject  (Intercept) 0.0005812 0.02411      
##           Time        0.0004871 0.02207  1.00
##  Residual             0.0047984 0.06927      
## Number of obs: 72, groups:  Subject, 12
## 
## Fixed effects:
##                                  Estimate Std. Error        df t value Pr(>|t|)
## (Intercept)                      0.177587   0.028836 25.063027   6.159 1.92e-06
## Time                             0.031961   0.014302 13.221798   2.235  0.04330
## Instructor.DRobot                0.054770   0.048776 25.063027   1.123  0.27213
## ASD.P1sd                        -0.097154   0.028438 25.063027  -3.416  0.00217
## Time:Instructor.DRobot           0.094195   0.024192 13.221798   3.894  0.00179
## Time:ASD.P1sd                   -0.009305   0.014105 13.221798  -0.660  0.52075
## Instructor.DRobot:ASD.P1sd       0.051776   0.034086 25.063027   1.519  0.14128
## Time:Instructor.DRobot:ASD.P1sd  0.036742   0.016906 13.221798   2.173  0.04849
##                                    
## (Intercept)                     ***
## Time                            *  
## Instructor.DRobot                  
## ASD.P1sd                        ** 
## Time:Instructor.DRobot          ** 
## Time:ASD.P1sd                      
## Instructor.DRobot:ASD.P1sd         
## Time:Instructor.DRobot:ASD.P1sd *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## optimizer (nloptwrap) convergence code: 0 (OK)
## boundary (singular) fit: see help('isSingular')
  • Time:Instructor.DRobot is significant (as it has to be). So the right panel in our graph is an interaction.
  • In summary, our two way interaction changes as function of ASD score

References

Chlebowski, C., Green, J. A., Barton, M. L., & Fein, D. (2010). Using the childhood autism rating scale to diagnose autism spectrum disorders. Journal of autism and developmental disorders, 40(7), 787-799.

Srinivasan, S. M., Kaur, M., Park, I. K., Gifford, T. D., Marsh, K. L., & Bhat, A. N. (2015). The effects of rhythm and robotic interventions on the imitation/praxis, interpersonal synchrony, and motor performance of children with autism spectrum disorder (ASD): a pilot randomized controlled trial. Autism research and treatment.

LS0tDQp0aXRsZTogJ0xvbmdpdHVkaW5hbCcNCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDoNCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMNCiAgICBmb250c2l6ZTogOHB0DQogICAgaGlnaGxpZ2h0OiB0ZXh0bWF0ZQ0KICAgIG51bWJlcl9zZWN0aW9uczogbm8NCiAgICB0aGVtZTogZmxhdGx5DQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZmxvYXQ6DQogICAgICBjb2xsYXBzZWQ6IG5vDQotLS0NCg0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChjYWNoZSA9IFRSVUUpDQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpDQprbml0cjo6b3B0c19jaHVuayRzZXQobWVzc2FnZSA9IEZBTFNFKQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KHdhcm5pbmcgPSAgRkFMU0UpDQprbml0cjo6b3B0c19jaHVuayRzZXQoZmlnLndpZHRoPTQuMjUpDQprbml0cjo6b3B0c19jaHVuayRzZXQoZmlnLmhlaWdodD00LjApDQprbml0cjo6b3B0c19jaHVuayRzZXQoZmlnLmFsaWduPSdjZW50ZXInKSANCmtuaXRyOjpvcHRzX2NodW5rJHNldChyZXN1bHRzPSdob2xkJykgDQpgYGANCg0KYGBge3IsIGVjaG89RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KGxtZTQpDQpgYGANCg0KIyBMb25naXR1ZGluYWwgRGVzaWducw0KLSBMb25naXR1ZGluYWwgZ2VuZXJhbGx5IG1lYW5zIHlvdSBtZWFzdXJlIGEgcGVyc29uIG92ZXIgdGltZS4gVGh1cywgdGhlIHBlcnNvbiBpcyB0aGUgbGV2ZWwgMiAodGhlIGNsdXN0ZXIpIGFuZCBUaW1lIGlzIHRoZSBsZXZlbCAxLg0KICAgIC0gQXQgbGVhc3QgMyBtZWFzdXJlbWVudHMgZm9yIHRoYXQgcGVyc29uOiBMb25naXR1ZGluYWwgY2FuIGJlIGRlZmluZWQgaW4gc2Vjb25kcywgbWludXRlcywgZGF5cywgd2Vla3MsIHllYXJzLCBvciBkZWNhZGVzLg0KICAgIC0gVGltZSBpcyByZXBlYXRlZCBtZWFzdXJlIG9uIHRoZSBzdWJqZWN0LCBidXQgeW91IGFyZSBpbnRlcmVzdGVkIGluIGNoYXJ0aW5nIGhvdyB0aGV5IGNoYW5nZSBvdmVyIHRpbWUNCiAgICANCiMgTWl4ZWQgTW9kZWwgZnJhbWV3b3JrIGZvciBMb25naXR1ZGluYWwNCi0gTWl4ZWQgbW9kZWxzIGhhdmUgc29tZSBtYWpvciBhZHZhbnRhZ2VzIG92ZXIgUk0gQU5PVkEgYXBwcm9hY2ggdG8gZGVhbGluZyB3aXRoIHRpbWUNCiAgICAtIDEpIEludGVyY2VwdCBkaWZmZXJlbmNlczogZG8gZGlmZmVyZW50IHRyZWF0bWVudHMgaGF2ZSBkaWZmZXJlbnQgYmFzZWxpbmVzIA0KICAgIC0gMikgU2xvcGUgZGlmZmVyZW5jZXMgYmV0d2VlbiB0cmVhdG1lbnRzDQogICAgLSAzKSBHcm93dGggY3VydmVzOiBBcmUgc2xvcGVzIGxpbmVhciBvciBjdXJ2aWxpbmVhcg0KICAgICAgICAtIDNhKSBFYWNoIHN1YmplY3QgY2FuIGhhdmUgYSBkaWZmZXJlbnQgc2xvcGUgYW5kIHNsb3BlIHNoYXBlIA0KICAgIC0gNCkgVGltZSBtZWFzdXJlbWVudHMgZG8gbm90IG5lZWQgdG8gYmUgdGhlIHNhbWUgZm9yIGVhY2ggc3ViamVjdDogU3ViamVjdCAxOiBNb250aCAxLDIsNCw2LCBTdWJqZWN0IDI6IE1vbnRoIDIsMyw1LDcNCiAgICAgICAgLSA0YSkgKlRoaXMgYmVjYXVzZSB5b3UgY2FuIGhhdmUgbWlzc2luZyBkYXRhIGluIHlvdXIgbWVhc3VyZW1lbnRzOiBpbiBSTSBBTk9WQSB0aGlzIHdvdWxkIG1lYW4geW91IGxvc2UgdGhlIHdob2xlIHN1YmplY3QqIA0KICAgIC0gNSkgWW91IHRlc3QgZm9yIGRpc2NvbnRpbnVpdGllcyBpbiB0aW1lOiBGb3IgZXhhbXBsZSwgdHJlYXRtZW50IGNoYW5nZXMgZHVyaW5nIHRoZSBtZWFzdXJlbWVudHMgKHRoaW5rIGVsYm93IHNoYXBlZCBzbG9wZSkgDQogICAgICAgIC0gU3ViamVjdHMgaGF2ZSAzIGJhc2VsaW5lczogTW9udGggMSwgMiwgMyBhbmQgYXQgTW9udGggNCB0aGV5IHN0YXJ0IHRyZWF0bWVudCwgYW5kIHlvdSBoYXZlIHR3byBtb3JlIG1lYXN1cmVtZW50cy4gVGh1cyB5b3Ugd2FudCB0byBzZWUgaWYgdGhlIHNsb3BlIGR1cmluZyBubyB0cmVhdG1lbnQgZm9yIHRoYXQgc3ViamVjdCBjaGFuZ2VzIGFmdGVyIHRyZWF0bWVudCAgICAgICAgIA0KICAgIC0gNikgV2UgY2FuIG1lYXN1cmUgKipUaW1lIEZpeGVkIENvdmFyaWF0ZXMqKjogQ292YXJpYXRlIGRvZXMgbm90IGNoYW5nZSBvdmVyIHRoZSBtZWFzdXJlbWVudCBwZXJpb2QgKERWID0gRGVwcmVzc2lvbiBzY29yZSBhdCBlYWNoIHRyZWF0bWVudCwgQ292YXJpYXRlID0gVHJhaXQgQW54aWV0eSBsZXZlbCkNCiAgICAtIDcpIFdlIGNhbiBtZWFzdXJlICoqVGltZSBWYXJpYWJsZSBDb3ZhcmlhdGVzKio6IENvdmFyaWF0ZSB0aGF0IGNoYW5nZSBvdmVyIHRoZSBtZWFzdXJlbWVudCBwZXJpb2QgKERWID0gRGVwcmVzc2lvbiBzY29yZSBhdCBlYWNoIHRyZWF0bWVudCwgQ292YXJpYXRlID0gU3RhdGUgQW54aWV0eSBsZXZlbCBkdXJpbmcgYSB0aGVyYXB5IHNlc3Npb24pDQogICAgLSA4KSBJbnRlcmFjdCBUaW1lIEZpeGVkIGFuZCBUaW1lIFZhcmlhYmxlIGNvdmFyaWF0ZXMNCiAgICAtIDkpIFlvdSBjYW4gY29udHJvbCB0aGUgY292YXJpYW5jZSBzdHJ1Y3R1cmUgYW5kIHVzZSBhdXRvcmVncmVzc2l2ZSBzdHJ1Y3R1cmVzIChidXQgbm90IGluIGxtZTQpDQogICAgLSAxMCkgRGVhbCB3aXRoIG5lc3RlZCBmb3JtcyBvZiBUaW1lOiBGb3IgZXhhbXBsZSwgbW9udGggdG8gbW9udGggY2hhbmdlIGluIEFueGlldHkgbGV2ZWxzLCBidXQgeW91IGNhbiBhbHNvIGV4YW1pbmUgaG91ciB0byBob3VyIEFueGlldHkgbGV2ZWxzIChuZXN0ZWQgaW4gdGhlIG1vbnRoIHRoZXkgd2VyZSBjb2xsZWN0ZWQpICANCg0KIyBTaW1wbGVzdCBUeXBlIG9mIExvbmdpdHVkaW5hbCBNb2RlbA0KQ2hpbGRyZW4gd2l0aCBBU0QgdHlwaWNhbGx5IGhhdmUgZGlmZmljdWx0eSB3aXRoIG1vdG9yIHNraWxsIGFuZCBwb29yIGludGVycGVyc29uYWwgY29vcmRpbmF0aW9uLiBUaGVpciByZWR1Y2VkIGFiaWxpdHkgdG8gY29vcmRpbmF0ZSB3aXRoIHBlb3BsZSBtYXliZSBiZSBjYXVzaW5nIHRoZW0gdG8gYmUgbGVmdCBvdXQgb2YgcGxheSB3aXRoIG90aGVyIGNoaWxkcmVuIGlzb2xhdGluZyB0aGVtLiBQYXN0IGVmZm9ydHMgdG8gaW1wcm92ZSB0aGVpciBpbnRlcnBlcnNvbmFsIGNvb3JkaW5hdGlvbiBoYXZlIG9mdGVuIGZhaWxlZCBiZWNhdXNlIGNoaWxkcmVuIHdpdGggQVNEIGFyZSBvdmVyd2hlbG1lZCBieSBwZW9wbGUuIFNvIHRyYWluaW5nIHNlc3Npb25zIG9mdGVuIGZhaWwuIEhvd2V2ZXIsIGNoaWxkcmVuIHdpdGggQVNEIGdyYXZpdGF0ZSB0b3dhcmRzIGVsZWN0cm9uaWNzIGFuZCBoYXZlIGJlZW4gb2JzZXJ2ZWQgdG8gYmUgaW50ZXJlc3RlZCBhbmQgY29tZm9ydGFibGUgd2l0aCByb2JvdHMuIFNyaW5pdmFzYW4gZXQgYWwuLCAoMjAxNSkgaHlwb3RoZXNpemVkIHRoYXQgY2hpbGRyZW4gd2l0aCBBU0QgbWlnaHQgYmUgYmV0dGVyIGF0IGNvb3JkaW5hdGluZyB3aXRoIHJvYm90cyBiZWNhdXNlIGEpIGNoaWxkcmVuIHdpdGggQVNEIGxvdmUgcm9ib3RzLCBhbmQgYikgcm9ib3RzIGFyZSBsZXNzIHRocmVhdGVuaW5nIGFzIHRoZXkgY29udmV5IGxlc3MgaW5mb3JtYXRpb24gKG5vdCBvdmVyd2hlbG1pbmcgdGhlIGNoaWxkKS4gIFNyaW5pdmFzYW4gZXQgYWwuLCAoMjAxNSkgZm91bmQgdGhhdCBoYXZpbmcgY2hpbGRyZW4gImRhbmNlIiB3aXRoIGRhbmNpbmcgcm9ib3RzIGltcHJvdmVkIHRoZWlyIGludGVycGVyc29uYWwgY29vcmRpbmF0aW9uIGFiaWxpdHkuICANCg0KVG9kYXkgd2Ugd2lsbCBleGFtaW5lIGEgc2ltdWxhdGVkIHN0dWR5IG9mIGludGVycGVyc29uYWwgY29vcmRpbmF0aW9uIG9uIDEyIGNoaWxkcmVuIHdpdGggQVNELiBFYWNoIGNoaWxkIHVuZGVyd2VudCA2IHRyYWluaW5nIHNlc3Npb25zIChpbmNsdWRpbmcgdGhlIGJhc2VsaW5lIHdoZXJlIHRoZXkgaGFkIGFuIEFTRCBhc3Nlc3NtZW50IHRvIHNlZSB3aGVyZSB0aGV5IHdlcmUgb24gdGhlIHNwZWN0cnVtOyBDaGxlYm93c2tpIGV0IGFsLiAyMDEwKS4gVGhlIGNoaWxkcmVuIHdlcmUgYXNrZWQgdG8gImRhbmNlIiB3aXRoIGFuIGluc3RydWN0b3IgYW5kIHRoZWlyIHBhcmVudCBpbiBlYWNoIG9mIHRoZSA2IHNlc3Npb25zLiBJbiB0aGUgbGFzdCBwYXJ0IG9mIHRoZSBzZXNzaW9uIHRoZWlyIGRlZ3JlZSBvZiBjb29yZGluYXRpb24gKGZyb20gMCAtIDEpIHdpdGggdGhlIG5ldyBpbnN0cnVjdG9yIHdobyB3YXMgaW4gdGhlIHJvb20gZHVyaW5nIHRoZSBzZXNzaW9uLCBidXQgZGlkIG5vdCBkYW5jZS4gRm9yIGhhbGYgdGhlIGNoaWxkcmVuIHRoZSBpbnN0cnVjdG9yIHdhcyBodW1hbiwgYW5kIGZvciB0aGUgb3RoZXIgaGFsZiwgdGhlIGluc3RydWN0b3Igd2FzIGEgcm9ib3QuDQoNCiMjIERhdGENCi0gQXMgd2l0aCBhbGwgb3VyIG90aGVyIGFuYWx5c2lzLCB0aGUgZGF0YSBpcyBpbiBsb25nIGZvcm1hdCAoZm9yIExvbmdpdHVkaW5hbCB5b3UgbWlnaHQgc2VlIGl0IGNhbGxlZCBwZXJpb2QtcGVyaW9kIGRhdGEpDQogICAgLSBUaW1lIGlzIGNvZGVkIHRvIHN0YXJ0IGF0IDAgKGJhc2VsaW5lIG9yIGZpcnN0IG1lYXN1cmVtZW50KS4gDQogICAgLSBJbnN0cnVjdG9yICgwLDEpOiAwOiBIdW1hbjsgIDE6IFJvYm90IA0KICAgIC0gQ29vcmRpbmF0aW9uICgwLTEpOiBEZWdyZWUgb2YgY29vcmRpbmF0aW9uIChEVikNCiAgICAtIEFTRDogQVNEIHNwZWN0cnVtIHNjb3JlIChwb3NzaWJsZSBjb3ZhcmlhdGUpDQogICAgLSBbRG93bmxvYWQgZGF0YV0oL01peGVkL0xvbmdEYXRhMS5jc3YpDQogICAgDQpgYGB7cn0NCkxvbmdTaW08LXJlYWQuY3N2KCJNaXhlZC9Mb25nRGF0YTEuY3N2IikNCmBgYA0KDQpgYGB7ciwgZWNobz1GQUxTRX0NCmxpYnJhcnkoa25pdHIpOyBsaWJyYXJ5KGthYmxlRXh0cmEpIA0Ka2FibGUoaGVhZChMb25nU2ltKSwgImh0bWwiLCBib29rdGFicyA9IFQpICU+JQ0KICBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gInN0cmlwZWQiLCBmdWxsX3dpZHRoID0gRikNCmBgYA0KDQojIyMgQ29kaW5nDQotIERlY2lzaW9ucyBoYXZlIHRvIGJlIG1hZGUgYWJvdXQgaG93IHRvIGNvZGUgKkluc3RydWN0b3IqDQogICAgLSBEdW1teSBvciBlZmZlY3RzIGNvZGUgaXQ/IEZvciB0b2RheSBsZXRzIGp1c3QgZHVtbXkgY29kZSBvdXIgdHJlYXRtZW50DQogICAgDQpgYGB7cn0NCiNEdW1teQ0KTG9uZ1NpbSRJbnN0cnVjdG9yLkQ8LWZhY3RvcihMb25nU2ltJEluc3RydWN0b3IsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoMCwxKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiSHVtYW4iLCJSb2JvdCIpKQ0KYGBgDQoNCi0gRGVjaXNpb25zIGhhdmUgdG8gYmUgbWFkZSBhYm91dCBob3cgdG8gY29kZSAqVGltZSouIEVhY2ggYWdhaW4gd2lsbCBjaGFuZ2UgaG93IHdlIGludGVycHJldCBvdXIgbW9kZWwuIFdlIHdpbGwgY29kZSBpdCBvdXQgbm93IGZvciBsYXRlcjoNCiAgICAtIFdlIGNhbiBsZWF2ZSAqVGltZSogYXMgaXM6IGl0IHN0YXJ0cyBhdCAwIGFuZCBwcm9ncmVzc2VzIGluIHRoZSB1bml0cyBvZiBtZWFzdXJlbWVudHMNCiAgICAtIENlbnRlciB0aW1lICpUaW1lKjogU28gdGhlcmUgYXJlIDYgc2Vzc2lvbnMgKDAtNSksIHRodXMgY2VudGVyIGlzIDIuNTogU28gU2Vzc2lvbiAjIC0gMi41DQogICAgLSAoTm90ZTogKnllcyB5b3UgY2FuIFpzY29yZSB0aW1lIG9yIFpzY29yZSBhbmQgTk9UIGNlbnRlciBhcyB3ZWxsKikNCg0KYGBge3J9DQojIENlbnRlcmVkDQpMb25nU2ltJFRpbWUuQzwtc2NhbGUoTG9uZ1NpbSRUaW1lLCBzY2FsZT1GLCBjZW50ZXI9VClbLF0NCmBgYCAgICAgICAgDQogIA0KIyMgU3BhZ2hldHRpIFBsb3RzDQotIExvbmdpdHVkaW5hbCBNb2RlbHMgYXJlIGJlc3QgYXNzZXNzZWQgd2l0aCBzcGFnaGV0dGkgcGxvdHMuIFdoZW4geW91IGhhdmUgYSBzbWFsbCBudW1iZXIgb2Ygc3ViamVjdHMsIHlvdSBjYW4gcGxvdCBpdCBhcyAiZmFjZXRzLiINCi0gV2Ugd2lsbCBwbG90IGVhY2ggcGVyc29uIGluIGEgZmFjZXQgYW5kIGFkZCB0aGVpciBsaW5lYXIgbW9kZWwgZm9yIGVhY2ggc3ViamVjdA0KYGBge3IsZmlnLndpZHRoPTMuNSwgZmlnLmhlaWdodD0zLjV9DQojIE1ha2Ugc3VyZSB0aGF0IHN1YmplY3QgaXMgYSBmYWN0b3INCkxvbmdTaW0kU3ViamVjdDwtYXMuZmFjdG9yKExvbmdTaW0kU3ViamVjdCkNCg0KU3BlZy4xPC1nZ3Bsb3QoZGF0YSA9IExvbmdTaW0sIGFlcyh4PVRpbWUseT1Db29yZGluYXRpb24pKSsNCiAgZmFjZXRfd3JhcCh+U3ViamVjdCkrDQogIGdlb21fcG9pbnQoYWVzKGNvbG9yPUluc3RydWN0b3IuRCkpKw0KICBnZW9tX3Ntb290aChtZXRob2Q9J2xtJywgc2U9RkFMU0UsYWVzKGNvbG9yPUluc3RydWN0b3IuRCkpKw0KICB4bGFiKCJUaW1lIikreWxhYigiQ29vcmRpbmF0aW9uIikrDQogIHRoZW1lX2J3KCkrDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKQ0KU3BlZy4xDQpgYGANCg0KLSBJZiB5b3UgaGF2ZSB0b28gbWFueSBzdWJqZWN0cywgeW91IGNhbiBwbG90IHRoZSByZXN1bHRzIGxpa2UgdGhpcyBpbnN0ZWFkDQotIE9uIHRoZSBsZWZ0LCB5b3UgY2FuIGZpdCBhIHJlZ3Jlc3Npb24gcGVyIHN1YmplY3QsIG9uIHRoZSByaWdodCB5b3UgcGxvdCBsaW5lcyBpbnN0ZWFkIG9mIHRoZSBzbG9wZQ0KDQpgYGB7ciwgZWNobz1UUlVFLCBvdXQud2lkdGg9JzUwJScsIGZpZy5oZWlnaHQ9Mi41LGZpZy5zaG93PSdob2xkJyxmaWcuYWxpZ249J2NlbnRlcid9DQp0aGVtZV9zZXQodGhlbWVfYncoYmFzZV9zaXplID0gNywgYmFzZV9mYW1pbHkgPSAiIikpDQoNClNwZWcuMjwtZ2dwbG90KGRhdGEgPSBMb25nU2ltLCBhZXMoeD1UaW1lLHk9Q29vcmRpbmF0aW9uLCBncm91cD1TdWJqZWN0LCBjb2xvcj1TdWJqZWN0KSkrDQogIGZhY2V0X3dyYXAofkluc3RydWN0b3IuRCkrDQogIGdlb21fcG9pbnQoKSsNCiAgZ2VvbV9zbW9vdGgobWV0aG9kPSdsbScsIHNlPUZBTFNFKSsNCiAgeGxhYigiVGltZSIpK3lsYWIoIkNvb3JkaW5hdGlvbiIpKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpDQpTcGVnLjINCg0KU3BlZy4zPC1nZ3Bsb3QoZGF0YSA9IExvbmdTaW0sIGFlcyh4PVRpbWUseT1Db29yZGluYXRpb24sIGdyb3VwPVN1YmplY3QsIGNvbG9yPVN1YmplY3QpKSsNCiAgZmFjZXRfd3JhcCh+SW5zdHJ1Y3Rvci5EKSsNCiAgZ2VvbV9wb2ludCgpKw0KICBnZW9tX2xpbmUoKSsNCiAgeGxhYigiVGltZSIpK3lsYWIoIkNvb3JkaW5hdGlvbiIpKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpDQpTcGVnLjMNCmBgYA0KDQojIyBNb2RlbGluZyB0byBFeGFtaW5lIFJhbmRvbSBTdHJ1Y3R1cmUgDQotIFRoZSBzdWJqZWN0IGlzIHRoZSBMZXZlbCAyIHZhcmlhYmxlIChqdXN0IGxpa2UgaW4gb3VyIHJlcGVhdGVkIG1lYXN1cmVzIG1peGVkIG1vZGVscykNCi0gV2UgY2FuIHNob3cgdGhhdCB2aWEgb3VyIElDQyBhbmFseXNpcyANCg0KIyMjIEludGVyY2VwdHMgb25seSBtb2RlbCANCmBgYHtyfQ0KTnVsbDwtbG1lcihDb29yZGluYXRpb24gfiAxKygxfFN1YmplY3QpLCBkYXRhPUxvbmdTaW0sIFJFTUw9RkFMU0UpDQpzanN0YXRzOjppY2MoTnVsbCkNCmBgYA0KDQojIyMjIEludGVyY2VwdHMgb25seSBwbG90DQotIFByZWRpY3Qgb3V0IHRoZSBtb2RlbCByZXN1bHRzIA0KLSBEb3RzID0gUmVhbCBkYXRhDQotIExpbmUgPSBQcmVkaWN0ZWQgcmVzdWx0DQpgYGB7ciwgZWNobz1UUlVFLG91dC53aWR0aD0nNTAlJywgZmlnLmhlaWdodD0yLjUsZmlnLnNob3c9J2hvbGQnLGZpZy5hbGlnbj0nY2VudGVyJ30NCnRoZW1lX3NldCh0aGVtZV9idyhiYXNlX3NpemUgPSA3LCBiYXNlX2ZhbWlseSA9ICIiKSkNCg0KTG9uZ1NpbSROdWxsPC1wcmVkaWN0KE51bGwsIG5ld2RhdGE9TG9uZ1NpbSkNCg0KU3BlZy5OdWxsLjE8LWdncGxvdChkYXRhID0gTG9uZ1NpbSkrDQogIGZhY2V0X3dyYXAoflN1YmplY3QpKw0KICBnZW9tX3BvaW50KGFlcyh4PVRpbWUseT1Db29yZGluYXRpb24sY29sb3I9SW5zdHJ1Y3Rvci5EKSkrDQogIGdlb21fbGluZShhZXMoeD1UaW1lLHk9TnVsbCwgY29sb3I9SW5zdHJ1Y3Rvci5EKSkrDQogIHhsYWIoIlRpbWUiKSt5bGFiKCJDb29yZGluYXRpb24iKSsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpDQpTcGVnLk51bGwuMQ0KDQpTcGVnLk51bGwuMjwtZ2dwbG90KGRhdGEgPSBMb25nU2ltKSsNCiAgZmFjZXRfd3JhcCh+SW5zdHJ1Y3Rvci5EKSsNCiAgZ2VvbV9wb2ludChhZXMoeD1UaW1lLHk9Q29vcmRpbmF0aW9uLCBncm91cD1TdWJqZWN0LGNvbG9yPVN1YmplY3QpKSsNCiAgZ2VvbV9saW5lKGFlcyh4PVRpbWUseT1OdWxsLGdyb3VwPVN1YmplY3QsY29sb3I9U3ViamVjdCkpKw0KICB4bGFiKCJUaW1lIikreWxhYigiQ29vcmRpbmF0aW9uIikrDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikNClNwZWcuTnVsbC4yDQoNCmBgYA0KLSBOb3RpY2UgdGhhdCBlYWNoIHN1YmplY3QgaGFzIHRoZWlyIG93biBpbnRlcmNlcHQsIGJ1dCBubyBzbG9wZQ0KDQojIyMgUmFuZG9tIEludGVyY2VwdHMgYW5kIFNsb3BlcyBNb2RlbCANCi0gV2Ugd2lsbCBsZXQgdGhlIGludGVyY2VwdCBhbmQgVGltZSB2YXJ5IHJlbGF0aXZlIHRvIGVhY2ggc3ViamVjdDogYCgxK1RpbWV8U3ViamVjdClgDQogICAgLSBOb3RlIHlvdSBjYW4gYmxvY2sgdGhlIGNvcnJlbGF0aW9uIGJldHdlZW4gdGhlIHNsb3BlL2ludGVyY2VwdCBsaWtlIGJlZm9yZSBpZiB0aGUgY29ycmVsYXRpb24gaXMgLTEvMTogYCgxK1RpbWV8fFN1YmplY3QpYA0KYGBge3J9DQpSSVNsb3BlPC1sbWVyKENvb3JkaW5hdGlvbiB+IDErKDErVGltZXxTdWJqZWN0KSwgZGF0YT1Mb25nU2ltLCBSRU1MPUZBTFNFKQ0Kc3VtbWFyeShSSVNsb3BlKQ0KYGBgDQoNCiMjIyMgUmFuZG9tIEludGVyY2VwdCBhbmQgU2xvcGVzIFBsb3QNCi0gUHJlZGljdCBvdXQgdGhlIG1vZGVsIHJlc3VsdHMgDQotIERvdHMgPSBSZWFsIGRhdGENCi0gTGluZSA9IFByZWRpY3RlZCByZXN1bHQNCg0KYGBge3IsIGVjaG89VFJVRSxvdXQud2lkdGg9JzUwJScsIGZpZy5oZWlnaHQ9Mi41LGZpZy5zaG93PSdob2xkJyxmaWcuYWxpZ249J2NlbnRlcid9DQp0aGVtZV9zZXQodGhlbWVfYncoYmFzZV9zaXplID0gNywgYmFzZV9mYW1pbHkgPSAiIikpDQoNCkxvbmdTaW0kUklTbG9wZTwtcHJlZGljdChSSVNsb3BlLCBuZXdkYXRhPUxvbmdTaW0pDQpTcGVnLlIuSS5TbG9wZS4xPC1nZ3Bsb3QoZGF0YSA9IExvbmdTaW0pKw0KICBmYWNldF93cmFwKH5TdWJqZWN0KSsNCiAgZ2VvbV9wb2ludChhZXMoeD1UaW1lLHk9Q29vcmRpbmF0aW9uLCBjb2xvcj1JbnN0cnVjdG9yLkQpKSsNCiAgZ2VvbV9saW5lKGFlcyh4PVRpbWUseT1SSVNsb3BlLCBjb2xvcj1JbnN0cnVjdG9yLkQpKSsNCiAgeGxhYigiVGltZSIpK3lsYWIoIkNvb3JkaW5hdGlvbiIpKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikNClNwZWcuUi5JLlNsb3BlLjENCg0KU3BlZy5SLkkuU2xvcGUuMjwtZ2dwbG90KGRhdGEgPSBMb25nU2ltKSsNCiAgZmFjZXRfd3JhcCh+SW5zdHJ1Y3Rvci5EKSsNCiAgZ2VvbV9wb2ludChhZXMoeD1UaW1lLHk9Q29vcmRpbmF0aW9uLCBncm91cD1TdWJqZWN0LGNvbG9yPVN1YmplY3QpKSsNCiAgZ2VvbV9saW5lKGFlcyh4PVRpbWUseT1SSVNsb3BlLGdyb3VwPVN1YmplY3QsY29sb3I9U3ViamVjdCkpKw0KICB4bGFiKCJUaW1lIikreWxhYigiQ29vcmRpbmF0aW9uIikrDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikNClNwZWcuUi5JLlNsb3BlLjINCmBgYA0KDQojIyMgUmFuZG9tIFNsb3BlcyBPbmx5IE1vZGVsIA0KLSBJdCBjb3VsZCBiZSB0aGVyZSBpcyBubyByYW5kb20gaW50ZXJjZXB0LCBzbyB5b3UgY2FuIHJlbW92ZSBpdCAoYnV0IHlvdSBuZWVkIHRvIGhhdmUgYSByZWFzb24pDQotIFdlIHdpbGwgbGV0IFRpbWUgdmFyeSByZWxhdGl2ZSB0byBlYWNoIHN1YmplY3Q6IGAoMCtUaW1lfFN1YmplY3QpYA0KYGBge3J9DQpSU2xvcGU8LWxtZXIoQ29vcmRpbmF0aW9uIH4gMSsoMCtUaW1lfFN1YmplY3QpLCBkYXRhPUxvbmdTaW0sIFJFTUw9RkFMU0UpDQpzdW1tYXJ5KFJTbG9wZSkNCmBgYA0KDQojIyMjIFJhbmRvbSBTbG9wZXMgT25seSBQbG90DQotIFByZWRpY3Qgb3V0IHRoZSBtb2RlbCByZXN1bHRzIA0KLSBEb3RzID0gUmVhbCBkYXRhDQotIExpbmUgPSBQcmVkaWN0ZWQgcmVzdWx0DQoNCmBgYHtyLCBlY2hvPVRSVUUsb3V0LndpZHRoPSc1MCUnLCBmaWcuaGVpZ2h0PTIuNSxmaWcuc2hvdz0naG9sZCcsZmlnLmFsaWduPSdjZW50ZXInfQ0KdGhlbWVfc2V0KHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDcsIGJhc2VfZmFtaWx5ID0gIiIpKQ0KDQpMb25nU2ltJFJTbG9wZTwtcHJlZGljdChSU2xvcGUsIG5ld2RhdGE9TG9uZ1NpbSkNCg0KU3BlZy5SLlNsb3BlLjE8LWdncGxvdChkYXRhID0gTG9uZ1NpbSkrDQogIGZhY2V0X3dyYXAoSW5zdHJ1Y3Rvci5EflN1YmplY3QpKw0KICBnZW9tX3BvaW50KGFlcyh4PVRpbWUseT1Db29yZGluYXRpb24sIGNvbG9yPUluc3RydWN0b3IuRCkpKw0KICBnZW9tX2xpbmUoYWVzKHg9VGltZSx5PVJTbG9wZSwgY29sb3I9SW5zdHJ1Y3Rvci5EKSkrDQogIHhsYWIoIlRpbWUiKSt5bGFiKCJDb29yZGluYXRpb24iKSsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpDQpTcGVnLlIuU2xvcGUuMQ0KDQpTcGVnLlIuU2xvcGUuMjwtZ2dwbG90KGRhdGEgPSBMb25nU2ltKSsNCiAgZmFjZXRfd3JhcCh+SW5zdHJ1Y3Rvci5EKSsNCiAgZ2VvbV9wb2ludChhZXMoeD1UaW1lLHk9Q29vcmRpbmF0aW9uLCBncm91cD1TdWJqZWN0LGNvbG9yPVN1YmplY3QpKSsNCiAgZ2VvbV9saW5lKGFlcyh4PVRpbWUseT1SU2xvcGUsZ3JvdXA9U3ViamVjdCxjb2xvcj1TdWJqZWN0KSkrDQogIHhsYWIoIlRpbWUiKSt5bGFiKCJDb29yZGluYXRpb24iKSsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KU3BlZy5SLlNsb3BlLjINCmBgYA0KDQotIE5vdGU6IFRoZSBpbnRlcmNlcHRzIGZvciBlYWNoIHN1YmplY3QgYXJlIHRoZSBzYW1lLg0KLSBZb3UgY2FuIGFsc28gZ3Vlc3MgdGhhdCB0aGlzIG1vZGVsIHdpbGwgbm90IGJlIGEgZ29vZCBmaXQgYXMgdGhlIGxhc3Qgb25lLCB3aGljaCB3ZSBjYW4gdGVzdDogDQoNCmBgYHtyLCBldmFsPVRSVUV9DQphbm92YShSU2xvcGUsUklTbG9wZSkNCmBgYA0KDQojIyBNb2RlbGluZyBmb3IgUmVzdWx0cw0KLSBUaGUgZ29hbCBhYm92ZSB3YXMgdG8gdW5kZXJzdGFuZCB0aGUgcmFuZG9tIGVmZmVjdHMuIFRoaXMgaXMgdXNlZnVsIGlmIHlvdSB3YW50IHRvIHVuZGVyc3RhbmQgeW91ciBkYXRhLCBidXQgd2hlbiB5b3UgbW92ZSB0byBtb2RlbGluZyBmb3IgcHVibGljYXRpb24geW91IHdpbGwgd2FudCB0byAqc2V0KiB5b3VyIHJhbmRvbSBlZmZlY3RzIGFuZCBtb3ZlIHRvIGZpeGVkIGVmZmVjdCB0ZXN0aW5nDQotIFRoZSBtb3N0IG9idmlvdXMgc3RydWN0dXJlIGZvciBtb3N0IGxvbmdpdHVkaW5hbCAoMiBsZXZlbCkgZGF0YSBpcyB0byB1c2UgcmFuZG9tIHNsb3BlcyBhbmQgaW50ZXJjZXB0cyAod2F0Y2ggdGhhdCBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZW0pDQotIFdlIHdpbGwgbm93IGFsc28gZXhwbG9yZSB0aGUgZGlmZmVyZW50IGNvZGluZyBzY2hlbWVzIHRvIHVuZGVyc3RhbmQgdGhlIG1vZGVscw0KDQojIyMgTm9uLUNlbnRlcmVkIFRpbWUgJiBEdW1teSBjb2RlZCBJbnN0cnVjdG9yIA0KLSBOb3RlOiBiZWNhdXNlIEluc3RydWN0b3IgaXMgMC8xIGNvZGVkIHlvdSBjYW4gYWxzbyBlbnRlciB0aGF0IGludG8gdGhlIG1vZGVsIGluc3RlYWQgb2YgaXQgYXMgYSBmYWN0b3IgKHlvdSB3aWxsIGdldCB0aGUgc2FtZSBhbnN3ZXIpDQoNCiMjIyMgTWFpbiBlZmZlY3RzDQpgYGB7cn0NCk1haW5FZmZlY3QuMTwtbG1lcihDb29yZGluYXRpb24gfiBUaW1lK0luc3RydWN0b3IuRCsoMStUaW1lfFN1YmplY3QpLCBkYXRhPUxvbmdTaW0sIFJFTUw9RkFMU0UpDQpzdW1tYXJ5KE1haW5FZmZlY3QuMSwgY29ycmVsYXRpb249RkFMU0UpDQpgYGANCg0KIyMjIyMgSW50ZXJwcmV0YXRpb24NCi0gKipUaW1lKio6IEFmdGVyIGVhY2ggc2Vzc2lvbiwgdGhlIGtpZHMgZ2V0IGFyZSBiZXR0ZXIgYXQgY29vcmRpbmF0aW5nIF9yZWdhcmRsZXNzXyBvZiBJbnN0cnVjdGlvbiAodGhlIGVzdGltYXRlIGlzIHRoZSBzbG9wZSBvdmVyIHNlc3Npb25zKQ0KLSAqKkluc3RydWN0b3IuRFJvYm90Kio6IHQgPCAxLjk2IChzbyBub3Qgc2lnbmlmaWNhbnQpLiBIYWQgaXQgYmVlbiBzaWduaWZpY2FudCBpdCB3b3VsZCBtZWFuIHRoYXQga2lkcyB3aG8gaGFkIHRoZSByb2JvdCBpbnN0cnVjdG9yIGhhZCBvdmVyYWxsIGhpZ2hlciBjb29yZGluYXRpb24gWyoqYXZlcmFnZWQgb3ZlciBhbGwgc2Vzc2lvbioqXSAodGhlIGVzdGltYXRlIHJlcG9ydGVkIGlzIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gaHVtYW4gYW5kIHJvYm90KQ0KDQojIyMjIEludGVyYWN0aW9uIA0KYGBge3J9DQpJbnRlcmFjdGlvbi4xPC1sbWVyKENvb3JkaW5hdGlvbiB+IFRpbWUqSW5zdHJ1Y3Rvci5EKygxK1RpbWV8U3ViamVjdCksIGRhdGE9TG9uZ1NpbSwgUkVNTD1GQUxTRSkNCnN1bW1hcnkoSW50ZXJhY3Rpb24uMSwgY29ycmVsYXRpb249RikNCmBgYA0KDQojIyMjIyBJbnRlcnByZXRhdGlvbg0KLSAqKlRpbWUqKjogc2xvcGUgb3ZlciBzZXNzaW9ucyBmb3Iga2lkcyB3aG8gaGFkIHRoZSAqaHVtYW4gaW5zdHJ1Y3RvciouICANCi0gKipJbnN0cnVjdG9yLkRSb2JvdCoqOiBJdCBpcyB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIGh1bWFuIGFuZCByb2JvdCB3aGVuIFRpbWUgPSAwIFsqKkJhc2VsaW5lKipdLiANCiAgICAtIFRvIHByb3ZlIHRoaXMgd2UgY2FuIGZpdCB0aGUgbW9kZWwgYW5kIHN1YnRyYWN0IHRoZSBmaXR0ZWQgdmFsdWVzOiAqUm9ib3QgQCBUaW1lIDAgLSBIdW1hbiBAIFRpbWUgMCAqDQoNCmBgYHtyLCBldmFsPUZBTFNFfQ0KbGlicmFyeShlZmZlY3RzKQ0KZWZmZWN0KGMoIlRpbWUqSW5zdHJ1Y3Rvci5EIiksSW50ZXJhY3Rpb24uMSkNCmBgYA0KDQpgYGB7ciwgZWNobz1GQUxTRX0NCmxpYnJhcnkoZWZmZWN0cykNCiMgRmFuY3kgdmVyc2lvbiBvZiBhYm92ZTogSWdub3JlIG1lIQ0Ka2FibGUoYXMuZGF0YS5mcmFtZShlZmZlY3QoYygiVGltZSpJbnN0cnVjdG9yLkQiKSxJbnRlcmFjdGlvbi4xKSksIGRpZ2l0cz00LCJodG1sIiwgYm9va3RhYnMgPSBUKSAlPiUNCiAga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9ICJzdHJpcGVkIiwgZnVsbF93aWR0aCA9IEYpDQpJbnRlci4xLkVmZmVjdHM8LWFzLmRhdGEuZnJhbWUoZWZmZWN0KGMoIlRpbWUqSW5zdHJ1Y3Rvci5EIiksSW50ZXJhY3Rpb24uMSkpDQpgYGANCiAgICAtIEVzdGltYXRlIG9mICoqSW5zdHJ1Y3Rvci5EUm9ib3QqKjogYHIgSW50ZXIuMS5FZmZlY3RzJGZpdFs2XWAgLSBgciBJbnRlci4xLkVmZmVjdHMkZml0WzFdYCA9IGByIEludGVyLjEuRWZmZWN0cyRmaXRbNl0gLSBJbnRlci4xLkVmZmVjdHMkZml0WzFdYA0KICAgICAgICAtIE5vdGU6ICpZb3UgYXJlIG1pc3NpbmcgdGhlIHNpbXBsZSBlZmZlY3Qgb2YgSHVtYW4gQCBUaW1lIDAqLiBSZWxldmVsIGluc3RydWN0b3IgdG8gdGVzdCBpZiB5b3UgbmVlZCB0byBrbm93Lg0KLSAqKlRpbWU6SW5zdHJ1Y3Rvci5EUm9ib3QqKjogc2xvcGUgb3ZlciBzZXNzaW9ucyBkaWZmZXJlbmNlID0gIHNsb3BlIEAgKnJvYm90IGluc3RydWN0b3IqIC0gc2xvcGUgQCAqaHVtYW4gaW5zdHJ1Y3RvcioNCg0KIyMjIENlbnRlcmVkIFRpbWUgJiBEdW1teSBjb2RlZCBJbnN0cnVjdG9yIA0KLSBOb3RlOiBCZWNhdXNlIEluc3RydWN0b3IgaXMgMC8xIGNvZGVkIHlvdSBjYW4gYWxzbyBlbnRlciB0aGF0IGludG8gdGhlIG1vZGVsIGluc3RlYWQgb2YgaXQgYXMgZmFjdG9yICh5b3Ugd2lsbCBnZXQgdGhlIHNhbWUgYW5zd2VyKQ0KDQojIyMjIE1haW4gZWZmZWN0cw0KYGBge3J9DQpNYWluRWZmZWN0LjI8LWxtZXIoQ29vcmRpbmF0aW9uIH4gVGltZS5DK0luc3RydWN0b3IuRCsoMStUaW1lfFN1YmplY3QpLCBkYXRhPUxvbmdTaW0sIFJFTUw9RkFMU0UpDQpzdW1tYXJ5KE1haW5FZmZlY3QuMiwgY29ycmVsYXRpb249RikNCmBgYA0KDQojIyMjIyBJbnRlcnByZXRhdGlvbg0KLSBTYW1lIGFzIG5vbi1jZW50ZXJlZA0KDQojIyMjIEludGVyYWN0aW9uIA0KLSBOb3cgdGhpbmdzIHdpbGwgY2hhbmdlIGJlY2F1c2UgdGhlIHplcm8tcG9pbnQgaW4gdGltZSBpcyBub3cgdGhlIG1pZGRsZSBvZiB0aGUgc2Vzc2lvbiAobm90IHRoZSBiYXNlbGluZSkNCmBgYHtyfQ0KSW50ZXJhY3Rpb24uMjwtbG1lcihDb29yZGluYXRpb24gfiBUaW1lLkMqSW5zdHJ1Y3Rvci5EKygxK1RpbWV8U3ViamVjdCksIGRhdGE9TG9uZ1NpbSwgUkVNTD1GQUxTRSkNCnN1bW1hcnkoSW50ZXJhY3Rpb24uMiwgY29ycmVsYXRpb249RikNCmBgYA0KDQojIyMjIyBJbnRlcnByZXRhdGlvbg0KLSAqKlRpbWUqKjogc2xvcGUgZm9yIGtpZHMgd2hvIGhhZCB0aGUgaHVtYW4gaW5zdHJ1Y3Rvci4gIA0KLSAqKkluc3RydWN0b3IuRFJvYm90Kio6IEl0IGlzIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gaHVtYW4gYW5kIHJvYm90IHdoZW4gVGltZSA9IDAuIF8qKkJ1dCByZW1lbWJlciBUaW1lIDAgZXF1YWxzIHRoZSBNaWRkbGUgU2Vzc2lvbiEqKl8gDQogICAgLSBUbyBwcm92ZSB0aGlzLCB3ZSBjYW4gZml0IHRoZSBtb2RlbCBhbmQgc3VidHJhY3QgdGhlIGZpdHRlZCB2YWx1ZXM6ICpSb2JvdCBAIFRpbWUgMCAtIEh1bWFuIEAgVGltZSAwKiBbKipNaWRkbGUgc2Vzc2lvbioqXQ0KDQpgYGB7ciwgZXZhbD1GQUxTRX0NCmVmZmVjdChjKCJUaW1lLkMqSW5zdHJ1Y3Rvci5EIiksSW50ZXJhY3Rpb24uMikNCmBgYA0KYGBge3IsIGVjaG89RkFMU0V9DQojIEZhbmN5IHZlcnNpb24gb2YgYWJvdmU6IElnbm9yZSBtZSENCmthYmxlKGFzLmRhdGEuZnJhbWUoZWZmZWN0KGMoIlRpbWUuQypJbnN0cnVjdG9yLkQiKSxJbnRlcmFjdGlvbi4yKSksIGRpZ2l0cz00LCJodG1sIiwgYm9va3RhYnMgPSBUKSAlPiUNCiAga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9ICJzdHJpcGVkIiwgZnVsbF93aWR0aCA9IEYpDQpJbnRlci4yLkVmZmVjdHM8LWFzLmRhdGEuZnJhbWUoZWZmZWN0KGMoIlRpbWUuQypJbnN0cnVjdG9yLkQiKSxJbnRlcmFjdGlvbi4yKSkNCmBgYA0KICAgIC0gRXN0aW1hdGUgb2YgKipJbnN0cnVjdG9yLkRSb2JvdCoqOiBgciBJbnRlci4yLkVmZmVjdHMkZml0WzhdYCAtIGByIEludGVyLjIuRWZmZWN0cyRmaXRbM11gID0gYHIgSW50ZXIuMi5FZmZlY3RzJGZpdFs4XSAtIEludGVyLjIuRWZmZWN0cyRmaXRbM11gDQotICoqVGltZTpJbnN0cnVjdG9yLkRSb2JvdCoqOiBzbG9wZSBvdmVyIHNlc3Npb25zIGRpZmZlcmVuY2UgPSAgc2xvcGUgQCAqcm9ib3QgaW5zdHJ1Y3RvciogLSBzbG9wZSBAICpodW1hbiBpbnN0cnVjdG9yKg0KDQoNCiMjIyBTdW1tYXJ5DQotIFRvIGNlbnRlciB0aW1lIG9yIG5vdCBjZW50ZXIgdGltZT8gDQotIFRoaXMgYWxsIGRlcGVuZHMgb24gd2hhdCBzdG9yeSB5b3UgbmVlZCB0byB0ZWxsDQotIEluIHRoZSBpbnRlcmFjdGlvbiBtb2RlbDoNCiAgICAtIGlmIHlvdSBkb24ndCBjZW50ZXIgdGltZSwgeW91IGFyZSB0YWxraW5nIGFib3V0IHRoZSBiYXNlbGluZS4gSW4gdGhpcyBjYXNlLCBpdCBzZWVtcyB2ZXJ5IHVzZWZ1bCB0byBiZSBhYmxlIHRvIHNheSB0aGUga2lkcyB3aXRoIEFTRCBzdGFydGVkIG91dCBhdCB0aGUgc2FtZSBsZXZlbCBvZiBjb29yZGluYXRpb24gYW5kIG92ZXIgdGltZSB0aGVpciBzbG9wZXMgY2hhbmdlZA0KICAgICAtIGlmIHlvdSBjZW50ZXIgdGltZSB5b3UgYXJlIHRhbGtpbmcgYWJvdXQgdGhlIG1pZGRsZSBzZXNzaW9uLCBJIGZpbmQgdGhpcyBsZXNzIHVzZWZ1bCBmb3IgdGhlIHF1ZXN0aW9uIGF0IGhhbmQsIGJ1dCBrZWVwIGl0IGluIG1pbmQgdGhhdCB5b3UgY2FuIGV4YW1pbmUgaXQgdGhpcyB3YXkNCiAgICAgDQogICAgIA0KIyBQbG90IG91ciBGaW5hbCBNb2RlbA0KLSBXZSBjYW4gdXNlIHRoZSBlZmZlY3RzIHBhY2thZ2UgYW5kIGdncGxvdCB0byBwbG90IHRoZSBmaXR0ZWQgbW9kZWwNCmBgYHtyLGZpZy53aWR0aD0zLjUsIGZpZy5oZWlnaHQ9My41fQ0KbGlicmFyeShlZmZlY3RzKQ0KRml0dGVkLkkxPC1lZmZlY3QoYygiVGltZSpJbnN0cnVjdG9yLkQiKSxJbnRlcmFjdGlvbi4xKQ0KRml0dGVkLkkxPC1hcy5kYXRhLmZyYW1lKEZpdHRlZC5JMSkNCg0KRml0dGVkLlBsb3Q8LWdncGxvdChkYXRhID0gRml0dGVkLkkxLCBhZXMoeD1UaW1lLHk9Zml0LCBncm91cD1JbnN0cnVjdG9yLkQpKSsNCiAgZ2VvbV9saW5lKGFlcyhjb2xvcj1JbnN0cnVjdG9yLkQpKSsNCiAgZ2VvbV9yaWJib24oYWVzKHltaW49bG93ZXIseW1heD11cHBlcixmaWxsPUluc3RydWN0b3IuRCksYWxwaGE9LjIpKw0KICB4bGFiKCJTZXNzaW9uIikreWxhYigiQ29vcmRpbmF0aW9uIikrDQogIHNjYWxlX3lfY29udGludW91cyhsaW09YygwLDEpLGJyZWFrcyA9IHNlcSgwLCAxLC4yKSkgKw0KICB0aGVtZV9idygpKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSBjKC44NSwuODc1KSwNCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9saW5lKGxpbmV0eXBlID0gImJsYW5rIiksDQogICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2xpbmUobGluZXR5cGUgPSAiYmxhbmsiKSkNCkZpdHRlZC5QbG90DQpgYGANCg0KIyBGaXhlZCBDb3ZhcmlhdGVzDQotIFdlIGhhZCBhIGNvdmFyaWF0ZTogZWFjaCBraWRzIGF1dGlzbSBzcGVjdHJ1bSBzY29yZS4gDQotIFdlIGNhbiBzaW1wbHkgYWRkIGl0IHRvIG91ciBtb2RlbCBpZiB3ZSB3YW50IHRvIGNvbnRyb2wgZm9yIGl0LCBidXQgeW91IHJlYWxseSBzaG91bGQgY2VudGVyIGl0IHNvIHlvdSBpbnRlcmNlcHQgZG9lcyBub3QgY2hhbmdlLiANCg0KYGBge3J9DQpMb25nU2ltJEFTRC5DPC1zY2FsZShMb25nU2ltJEFTRCwgc2NhbGU9RiwgY2VudGVyPVQpWyxdDQpgYGANCg0KLSBZb3UgY2FuIGFkZCBpdCB0byB5b3VyIG1vZGVsIGp1c3QgYXMgYW55IHJlZ3Jlc3Npb24NCmBgYHtyfQ0KQ292MS5Nb2RlbDwtbG1lcihDb29yZGluYXRpb24gfiBUaW1lKkluc3RydWN0b3IuRCtBU0QuQw0KICAgICAgICAgICAgICAgICsoMStUaW1lfFN1YmplY3QpLCBkYXRhPUxvbmdTaW0sIFJFTUw9RkFMU0UpDQpzdW1tYXJ5KENvdjEuTW9kZWwsIGNvcnJlbGF0aW9uPUYpDQpgYGANCg0KKipOb3RlOiB0aGUgY29ycmVsYXRpb24gYmV0d2VlbiB0aGUgaW50ZXJjZXB0IGFuZCBzbG9wZSA9IDEsIHNvIHdlIHNob3VsZCBibG9jayB0aGF0IG1vdmluZyBmb3J3YXJkIGFuZCB3ZSB3b3VsZCBnbyBiYWNrIGFuZCBibG9jayBpdCBpbiBwcmlvciBtb2RlbHMgdG8gdGhleSBhcmUgYWxsIGhhdmUgdGhlIHNhbWUgcmFuZG9tIHN0cnVjdHVyZS4gRm9yIG5vdyB3ZSB3aWxsIGlnbm9yZSBpdCBhbmQgbW92ZSBvbioqDQoNCmBgYHtyLCBldmFsPVRSVUV9DQphbm92YShJbnRlcmFjdGlvbi4xLENvdjEuTW9kZWwpDQpgYGANCg0KDQotIE91ciBzbG9wZSBpcyBubyBsb25nZXIgc2lnbmlmaWNhbnQsIG1lYW5pbmcgdGhlIGNvdmFyaWF0ZSBtaWdodCBiZSBleHBsYWluaW5nIHNvbWUgb2Ygb3VyIGludGVyYWN0aW9uIGF0IHRoZSBtZWFuIGxldmVsIG9mIEFTRCBzY29yZS4gVGhpcyBpcyBzdWdnZXN0aXZlIG9mIDMtd2F5IGludGVyYWN0aW9uLg0KDQpgYGB7cn0NCkNvdjIuTW9kZWw8LWxtZXIoQ29vcmRpbmF0aW9uIH4gVGltZSpJbnN0cnVjdG9yLkQqQVNELkMNCiAgICAgICAgICAgICAgICArKDErVGltZXxTdWJqZWN0KSwgZGF0YT1Mb25nU2ltLCBSRU1MPUZBTFNFKQ0Kc3VtbWFyeShDb3YyLk1vZGVsLCBjb3JyZWxhdGlvbj1GKQ0KYGBgDQoNCmBgYHtyfQ0KYW5vdmEoQ292MS5Nb2RlbCxDb3YyLk1vZGVsKQ0KYGBgDQoNCg0KLSBUaGUgdGhyZWUgd2F5IGltcHJvdmVkIHRoZSBtb2RlbCBmaXQuIA0KLSAqKlRpbWU6SW5zdHJ1Y3Rvci5EUm9ib3QqKjogaXMgdGhlIHNsb3BlIG92ZXIgc2Vzc2lvbnMgZGlmZmVyZW5jZSA9ICBzbG9wZSBAICpyb2JvdCBpbnN0cnVjdG9yKiAtIHNsb3BlIEAgKmh1bWFuIGluc3RydWN0b3IqIFtAIGF0IHRoZSBhdmVyYWdlIEFTRCBsZXZlbF0NCi0gKipUaW1lOkluc3RydWN0b3IuRFJvYm90OkFTRC5DKio6IGlzIHRoZSBzbG9wZSBvdmVyIHNlc3Npb25zIGRpZmZlcmVuY2UgPSAgc2xvcGUgQCAqcm9ib3QgaW5zdHJ1Y3RvciogLSBzbG9wZSBAICpodW1hbiBpbnN0cnVjdG9yKiBbYXMgYSBmdW5jdGlvbiBvZiBBU0Qgc2NvcmVdDQogICAgLSBTbyB0aGUgc2xvcGUgZGlmZmVyZW5jZSBiZXR3ZWVuIHJvYm90IGFuZCBodW1hbiBpbnN0cnVjdG9yIGlzIGdldHRpbmcgbGFyZ2VyIGFzIEFTRCBsZXZlbCBpbmNyZWFzZXMuIFNlZSB0aGUgcGxvdCBiZWxvdyB0byB1bmRlcnN0YW5kIHRoaXM6IA0KDQojIyBQbG90IDMtV2F5DQotIFdlIHdpbGwgcGxvdCBpdCBsaWtlIGFueSBvdGhlciBpbnRlcmFjdGlvbiBpbiBhIHJlZ3Jlc3Npb24gaW52b2x2aW5nIHR3byBjb250aW51b3VzIHZhcmlhYmxlcw0KLSBXZSB3aWxsIG5lZWQgdG8gZmluZCAxIFNEIGFib3ZlL2JlbG93IHRoZSBtZWFuIG9mIHRoZSBjb3ZhcmlhdGUgKHdoaWNoIHdhcyBtZWFuIGNlbnRlcmVkKQ0KDQpgYGB7cixmaWcud2lkdGg9NS41LCBmaWcuaGVpZ2h0PTMuNX0NClNETjE8LSAtc2QoTG9uZ1NpbSRBU0QuQykNClNEUDE8LSArc2QoTG9uZ1NpbSRBU0QuQykNCg0KRml0dGVkLkNvdjI8LWVmZmVjdChjKCJUaW1lKkluc3RydWN0b3IuRCpBU0QuQyIpLENvdjIuTW9kZWwsIA0KICAgICAgICAgICAgICAgICAgICB4bGV2ZWw9bGlzdChUaW1lPXNlcSgwLDUsMSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFTRC5DPWMoU0ROMSwwLFNEUDEpKSkNCkZpdHRlZC5Db3YyPC1hcy5kYXRhLmZyYW1lKEZpdHRlZC5Db3YyKQ0KDQpGaXR0ZWQuQ292MiRBU0Q8LWZhY3RvcihGaXR0ZWQuQ292MiRBU0QuQywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHM9YyhTRE4xLDAsU0RQMSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHM9YygiLTEgU0QgQVNEIiwiTWVhbiBBU0QiLCIrMSBTRCBBU0QiKSkNCg0KRml0dGVkLlBsb3QuMjwtZ2dwbG90KGRhdGEgPSBGaXR0ZWQuQ292MiwgYWVzKHg9VGltZSx5PWZpdCwgZ3JvdXA9SW5zdHJ1Y3Rvci5EKSkrDQogIGZhY2V0X2dyaWQofkFTRCkrDQogIGdlb21fbGluZShhZXMoY29sb3I9SW5zdHJ1Y3Rvci5EKSkrDQogIGdlb21fcmliYm9uKGFlcyh5bWluPWxvd2VyLHltYXg9dXBwZXIsZmlsbD1JbnN0cnVjdG9yLkQpLGFscGhhPS4yKSsNCiAgeGxhYigiU2Vzc2lvbiIpK3lsYWIoIkNvb3JkaW5hdGlvbiIpKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGltPWMoMCwxKSxicmVha3MgPSBzZXEoMCwgMSwuMikpICsNCiAgdGhlbWVfYncoKSsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gYyguMTUsLjg1KSwNCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9saW5lKGxpbmV0eXBlID0gImJsYW5rIiksDQogICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2xpbmUobGluZXR5cGUgPSAiYmxhbmsiKSkNCkZpdHRlZC5QbG90LjINCmBgYA0KDQoNCiMjIFRlc3Qgb2YgU2ltcGxlIEludGVyYWN0aW9ucw0KLSBJZiB5b3Ugd2FudCB0byBrbm93IGlmIHRoZSBpbnRlcmFjdGlvbiBpcyBzaWduaWZpY2FudCBhdCBlYWNoIGxldmVsIG9mIEFTRCBzY29yZSwgeW91IHNpbXBseSBoYXZlIHRvIHJlLWNlbnRlciB0aGUgQVNELiAgV2UgYWxyZWFkeSBrbm93IHRoZSBtaWRkbGUgcGxvdCB3YXMgc2lnbmlmaWNhbnQuIFdlIGFyZSBnb2luZyB0byB3YXRjaCB0aGUgKipUaW1lOkluc3RydWN0b3IuRFJvYm90KiogdGVybXMgYXMgd2UgY2hhbmdlIHRoZSBjZW50ZXIgcG9pbnQgYXQgQVNELkMNCg0KIyMjIFRlc3QgLTEgU0Qgb2YgQVNEDQotIFdlIG1vdmUgdGhlIGNlbnRlciB0byBiZSAtMSBTRCBieSBhZGRpbmcgMSBTRA0KYGBge3J9DQpMb25nU2ltJEFTRC5OMXNkPC1Mb25nU2ltJEFTRC5DK3NkKExvbmdTaW0kQVNELkMpDQpDb3YyLk1vZGVsLlNpbXBsZS5OMXNkPC1sbWVyKENvb3JkaW5hdGlvbiB+IFRpbWUqSW5zdHJ1Y3Rvci5EKkFTRC5OMXNkDQogICAgICAgICAgICAgICAgKygxK1RpbWV8U3ViamVjdCksIGRhdGE9TG9uZ1NpbSwgUkVNTD1GQUxTRSkNCnN1bW1hcnkoQ292Mi5Nb2RlbC5TaW1wbGUuTjFzZCwgY29ycmVsYXRpb249RikNCmBgYA0KDQotICoqVGltZTpJbnN0cnVjdG9yLkRSb2JvdCoqIGlzIG5vdCBzaWduaWZpY2FudC4gU28gdGhlIGxlZnQgcGFuZWwgaXMgb3VyIGdyYXBoIGlzIG5vdCBhbiBpbnRlcmFjdGlvbg0KDQojIyMgVGVzdCArMSBTRCBvZiBBU0QNCi0gV2UgbW92ZSB0aGUgY2VudGVyIHRvIGJlICsxIFNEIGJ5IHN1YnRyYWN0aW5nIDEgU0QNCmBgYHtyfQ0KTG9uZ1NpbSRBU0QuUDFzZDwtTG9uZ1NpbSRBU0QuQy1zZChMb25nU2ltJEFTRC5DKQ0KQ292Mi5Nb2RlbC5TaW1wbGUuUDFzZDwtbG1lcihDb29yZGluYXRpb24gfiBUaW1lKkluc3RydWN0b3IuRCpBU0QuUDFzZA0KICAgICAgICAgICAgICAgICsoMStUaW1lfFN1YmplY3QpLCBkYXRhPUxvbmdTaW0sIFJFTUw9RkFMU0UpDQpzdW1tYXJ5KENvdjIuTW9kZWwuU2ltcGxlLlAxc2QsIGNvcnJlbGF0aW9uPUYpDQpgYGANCg0KLSAqKlRpbWU6SW5zdHJ1Y3Rvci5EUm9ib3QqKiBpcyBzaWduaWZpY2FudCAoYXMgaXQgaGFzIHRvIGJlKS4gU28gdGhlIHJpZ2h0IHBhbmVsIGluIG91ciBncmFwaCBpcyBhbiBpbnRlcmFjdGlvbi4gDQotIEluIHN1bW1hcnksIG91ciB0d28gd2F5IGludGVyYWN0aW9uIGNoYW5nZXMgYXMgZnVuY3Rpb24gb2YgQVNEIHNjb3JlDQoNCiMgUmVmZXJlbmNlcw0KQ2hsZWJvd3NraSwgQy4sIEdyZWVuLCBKLiBBLiwgQmFydG9uLCBNLiBMLiwgJiBGZWluLCBELiAoMjAxMCkuIFVzaW5nIHRoZSBjaGlsZGhvb2QgYXV0aXNtIHJhdGluZyBzY2FsZSB0byBkaWFnbm9zZSBhdXRpc20gc3BlY3RydW0gZGlzb3JkZXJzLiAqSm91cm5hbCBvZiBhdXRpc20gYW5kIGRldmVsb3BtZW50YWwgZGlzb3JkZXJzKiwgNDAoNyksIDc4Ny03OTkuDQoNClNyaW5pdmFzYW4sIFMuIE0uLCBLYXVyLCBNLiwgUGFyaywgSS4gSy4sIEdpZmZvcmQsIFQuIEQuLCBNYXJzaCwgSy4gTC4sICYgQmhhdCwgQS4gTi4gKDIwMTUpLiBUaGUgZWZmZWN0cyBvZiByaHl0aG0gYW5kIHJvYm90aWMgaW50ZXJ2ZW50aW9ucyBvbiB0aGUgaW1pdGF0aW9uL3ByYXhpcywgaW50ZXJwZXJzb25hbCBzeW5jaHJvbnksIGFuZCBtb3RvciBwZXJmb3JtYW5jZSBvZiBjaGlsZHJlbiB3aXRoIGF1dGlzbSBzcGVjdHJ1bSBkaXNvcmRlciAoQVNEKTogYSBwaWxvdCByYW5kb21pemVkIGNvbnRyb2xsZWQgdHJpYWwuICpBdXRpc20gcmVzZWFyY2ggYW5kIHRyZWF0bWVudCouDQoNCjxzY3JpcHQ+DQogIChmdW5jdGlvbihpLHMsbyxnLHIsYSxtKXtpWydHb29nbGVBbmFseXRpY3NPYmplY3QnXT1yO2lbcl09aVtyXXx8ZnVuY3Rpb24oKXsNCiAgKGlbcl0ucT1pW3JdLnF8fFtdKS5wdXNoKGFyZ3VtZW50cyl9LGlbcl0ubD0xKm5ldyBEYXRlKCk7YT1zLmNyZWF0ZUVsZW1lbnQobyksDQogIG09cy5nZXRFbGVtZW50c0J5VGFnTmFtZShvKVswXTthLmFzeW5jPTE7YS5zcmM9ZzttLnBhcmVudE5vZGUuaW5zZXJ0QmVmb3JlKGEsbSkNCiAgfSkod2luZG93LGRvY3VtZW50LCdzY3JpcHQnLCdodHRwczovL3d3dy5nb29nbGUtYW5hbHl0aWNzLmNvbS9hbmFseXRpY3MuanMnLCdnYScpOw0KDQogIGdhKCdjcmVhdGUnLCAnVUEtOTA0MTUxNjAtMScsICdhdXRvJyk7DQogIGdhKCdzZW5kJywgJ3BhZ2V2aWV3Jyk7DQoNCjwvc2NyaXB0Pg0K