As described in the abstract we have 100 subjects undergoing various tests. The first thing to do is to read in the data Q1 Read in the data make sure that you are in the correct directory to read the data in. You can use the commented out setwd() command to bring you to the correct area if you need to.
#setwd("<YOUR DIRECTORY NAME HERE>")
data = read.csv("d10123132.csv", header = TRUE)
With that done we can begin to look at some of the features of the data Q2 Summarise the data and define types
Age=data$Age
Sex=data$Sex
Height=data$Height
ReactionTime=data$ReactionTime
AgeGroup= data$AGE_GROUP
Lets take a look at the basic data from the group
summary(data)
X Age Sex Height ReactionTime
Min. : 1.00 Min. :20.36 F:48 Min. :153.4 Min. :143.8
1st Qu.: 25.75 1st Qu.:32.14 M:52 1st Qu.:162.6 1st Qu.:376.4
Median : 50.50 Median :46.08 Median :166.6 Median :508.5
Mean : 50.50 Mean :45.47 Mean :168.4 Mean :489.8
3rd Qu.: 75.25 3rd Qu.:58.86 3rd Qu.:173.7 3rd Qu.:593.8
Max. :100.00 Max. :69.77 Max. :190.4 Max. :800.6
AGE_GROUP
20-40:37
40-70:63
Looking for the means and Standard Deviations where Available Q3 Calculate the mean and standard deviation of the Age, Height and Reaction Times of the test group
print(paste("Average Age: ",mean(Age), " years"))
[1] "Average Age: 45.47 years"
print(paste("Standard Deviation Age:", sd(Age)," years" ))
[1] "Standard Deviation Age: 14.6462281144258 years"
print(paste("Average Height: ",mean(Height), " cm"))
[1] "Average Height: 168.4159 cm"
print(paste("Standard Deviation Heigh:", sd(Height), " cm"))
[1] "Standard Deviation Heigh: 8.65580731023509 cm"
print(paste("Average Reaction Time: ",mean(ReactionTime), " ms"))
[1] "Average Reaction Time: 489.813 ms"
print(paste("Standard Deviation Reaction Time:", sd(ReactionTime), " ms"))
[1] "Standard Deviation Reaction Time: 138.382611533196 ms"
Lets see what some of the data looks like Q4A Plot a histogram of the i) reaction time data, ii) age data, and iii) height data
Since there is some plotting to be done here lets write a function to produce some nice plots from given parameters
plotHistogram <- function(data, unit, title, xlab, ylab) {
#data for mean and median
mean=round(mean(data), digits= 2)
median=round(median(data), digits = 2)
# get the legend
Mean <- paste("Mean:", toString(mean), unit, sep=" ")
Median <- paste("Median: ", toString(median), unit, sep=" ")
key <- c(Mean, Median)
color <- c("red", "blue")
#data for scaling
ymax <- max(hist(data, plot = FALSE)$counts)
hist(data, main=title, xlab = xlab, ylab=ylab, labels=TRUE, ylim=c(0, 1.1*ymax), col=rgb(0,0,1,alpha=.25))
#add mean median and legend
abline(v=mean, col= 'red')
abline(v=median, col='blue')
legend('topright',key, fill = color, cex= 0.75)
}
This function takes in the data to be graphed, A unit of measure for the x values of the data, and some labelling information in Title, X-axis label and Y-axis label. It then returns a labelled plot with the mean and median marked in it. Lets call it for Reaction Time data
plotHistogram(data=ReactionTime,
unit="ms",
title= "Frequence of reaction Times",
xlab = "Reaction Times (ms)",
ylab = "Frequecy of occurance")

This histogram shows that the data for the reaction time is roughly symmetrical with a mean at 489.8 ms and median of 508.5 ms. This tightness of mean to median suggests that there are few outliers to the data here. We also see that there is some symmatery to the data suggesting that the data may come from a normal distribution. There a are 2 peaks to the data at about 300-400 ms and at about 500-600 ms which hopefully can be explained with further analysis
plotHistogram(data=Height,
unit="cm",
title= "Frequence of Heights in Sample group",
xlab = "Height(cm)",
ylab = "Frequecy of occurance")

Here we see the data is slightly differently shaped. The mean and median are slightly more seperated and there is a tail to the data at the higher end ( > 190 cm) of the data. This suggests the presence of an outlier ‘pulling’ the data towards that end eg. A really tall person sampled.
plotHistogram(data = Age,
unit = "years",
title = "Plot of the frequency of ages in the sample group",
xlab = "Age in years",
ylab = "Frequecy of ages"
)

Finally this data is quite flat. The mean and median are almost identical suggeting that the data does not have many outliers or extreme values pulling at it. its also shows that the sample group is roughly equally likely to have ages anywhere from 20-70
b. Plot a histogram of the reaction time data for each age group (20-40yrs, 40-70yrs) First we need to group the sample into the age groups looked for then we can plot the data
younger<- subset(data, AGE_GROUP=='20-40')
older <- subset(data, AGE_GROUP=="40-70")
youngReaction <- younger$ReactionTime
olderReaction <- older$ReactionTime
Once that is done we can write some code to prettily plot the graphs side by side
sidebyside<- function(X,Y,title=NULL,xlabel=NULL, ylabel=NULL, legend=NULL){
#set parameters for the scale of the graph
if (max(X) > max(Y)){
xmax <- max(X)
}else{
xmax <- max(Y)
}
xtall <- max(hist(X, plot=FALSE)$counts)
ytall <- max(hist(Y, plot=FALSE)$counts)
if (xtall>ytall){
ymax=xtall
}else{
ymax=ytall
}
#set the legends
key <- legend
color <- c("blue", "red")
meanX<- mean(X)
meanY<- mean(Y)
#plot the 2 graphs side by side
hist(X, col=rgb(0,0,1,alpha=.25),
main=title, xlab=xlabel, ylab=ylabel, xlim = c(0, 1.1*xmax), labels=TRUE, ylim=c(0,1.1*ymax))
hist(Y, col=rgb(1,0,0, alpha=0.25), xlim = c(0, 1.1*xmax), ylim=c(0,1.1*ymax),labels=TRUE, add=TRUE)
#add lines showing mean of each section
abline(v=meanX, col= 'blue')
text(meanX, ymax, paste("mean:", round(meanX, digits=2)) , col = "blue", cex=0.5)
abline(v=meanY, col='red')
text(meanY, (ymax-0.5), paste("mean:", round(meanY, digits=2)) , col = "red", cex=0.5)
#include a legend
legend('topleft',key, fill = color, cex= 0.5 )
}
Finally with all of the prep work done we can plot the data
sidebyside(youngReaction, olderReaction, title="Comparative reaction Times by Age", xlabel = "Reaction Times (ms)", ylabel="counts", legend=c("Age Group 20-40", "Age Group 40-70"))

Here we can see that for younger people the mean reaction is lower than for older people. The older population (in red) tends towars the 300-900 ms range while the younger population tends towards the 100-700 ms. We see a longer tail on the younger population that the corresponding tail on the older one which is slightly more symmaterical. When looking at this graph we see a reason for the 2 peaks meantioned in the previous reaction times graph. The 2 peaks of the combined graph coincide with the means of each of the age groups on this graph.
Given that the populations mean reaction time is 450ms. Conduct a hypothesis test stating the Null H0 and alternative Hα, calculating the test statistics, stating your criteria for rejection, and your conclusion for the reaction time data of the: a.20-40 year old group b. 40-70 year old group
- First lets write a function to calculate some Confidence intervals for the data and we will also use the features of the data to calculate them
findCI <- function(x, alpha){
#set up variables
xbar <- mean(x)
sigma <- sd(x)
n <- length(x)
se <- sigma/sqrt(n)
#calculate t
tn_1_alpha.2 <- qt(1 - alpha/2, df = n - 1)
#return the CI
CI <- c(xbar-tn_1_alpha.2*se,xbar+tn_1_alpha.2*se)
return (CI)
}
This takes a rejection criteria ( in decimal ) and a data set and calculates a confidence interval for the test statistic to fall inside in order for the null hypothesis to be accepted.
findCI(youngReaction,0.05)
[1] 354.5534 437.6536
We would like our null hypothesis to fall within this region if we are to accept the null hypothesis
CItest <- function ( h0, x, alpha){
CI <- findCI( x, alpha)
if(h0 < CI[1]){
ans<-" H0 rejected"
reason <-paste(h0, "falls below the lower limit of our", (1-alpha)*100, "% confidence interval which is found to be: " ,CI[1], sep=" ")
}
else if (h0>CI[2]){
ans<-"H0 rejected"
reason <-paste(h0, "falls above the upper limit of our", (1-alpha)*100, "% confidence interval which is found to be: " ,CI[2], sep=" ")
}
else{
ans <- "H0 Not rejected"
reason <-paste(h0, "falls between the lower and upper limit of our", (1-alpha)*100, "% confidence interval which is found to be between : " ,CI[1],"and",CI[2], sep=" ")
}
return(paste(ans, reason, sep=" : "))
}
Lets call this function to test what we can already see (h0: \(mu\)= 450 does not fit in our confidence interval)
CItest(450, youngReaction, 0.05)
[1] "H0 rejected : 450 falls above the upper limit of our 95 % confidence interval which is found to be: 437.653611494543"
So for this test we reject the null hypothesis. Because h0 falls outside the upper boundary of the the Confidence Interval we can deduce that the real mean is lower than 450.
t.test(youngReaction, mu=450, conf.level = .95)
One Sample t-test
data: youngReaction
t = -2.6307, df = 36, p-value = 0.01246
alternative hypothesis: true mean is not equal to 450
95 percent confidence interval:
354.5534 437.6536
sample estimates:
mean of x
396.1035
This built in function gives some more information, most notably the p-value which here is significantly less than the \(t{a/2},{n-1}\) so once again we can reject the null hypothesis lets graph this on the histogram of ages ( means more functions.)
histCI <- function(data, alpha, title=NULL, xlab=NULL, ylab=NULL, h0) {
ymax=max(hist(data, plot=FALSE)$counts)
hist(data, col=rgb(0,0,1,alpha=.25),
main=paste(title, " with ", ((1-alpha)*100), " Confidence Interval"), xlab=xlab, ylab=ylab, ylim=c(0,1.1*ymax))
abline(v=h0, col= 'blue')
text(h0, ymax, "h0: mean=450ms" , col = "blue", cex=0.5)
CI <- findCI(data,alpha)
CImin <- CI[1]
CImax <- CI[2]
abline(v=CImin, col= 'red')
text(CImin, ymax-5, paste("CI min:", round(CImin, digits=2), " ms") , col = "red", cex=0.5)
abline(v=CImax, col= 'red')
text(CImax, ymax-2.5, paste("CI max:", round(CImax, digits=2), " ms") , col = "red", cex=0.5)
}
histCI(youngReaction, 0.05, "Young reaction times", "Reaction Times (ms)", "counts", 450)

This shows that the hypothesised mean falls ( just) outside the confidence intervals of the distribution b. 40 -70 age group We just repeat this for the older age group
CItest(450, olderReaction, 0.05)
[1] " H0 rejected : 450 falls below the lower limit of our 95 % confidence interval which is found to be: 515.867635752091"
histCI(olderReaction, 0.05, "Older reaction times", "Reaction Times (ms)", "counts", 450)

Here we see that that the Confidence interval is higher for the sample group, so that our mean of 450 is too low for the sample. Lets check the Ttest function to be sure
t.test(olderReaction, mu=450)
One Sample t-test
data: olderReaction
t = 6.5422, df = 62, p-value = 1.324e-08
alternative hypothesis: true mean is not equal to 450
95 percent confidence interval:
515.8676 573.8298
sample estimates:
mean of x
544.8487
Again if we look at the p-value it is far below the 1.96 needed to accept the null hypothesis
SO once again we reject the Null hypothesis that \({mu}= 450ms\)
Linear regression analysis a.Plot a scatterplot of the reaction time data (y-axis) as a function of age(x-axis). Conduct a linear regression analysis of reaction time as a functionage and interpret the results.
First lets plot the data
scatter.smooth(x=Age, y=ReactionTime, main="Reaction Time ~ Age") # scatterplot

Lets see if we can clean this up first
par(mfrow=c(1,2))
boxplot(Age, main="Age", sub=paste("Outlier rows: ", boxplot.stats(Age)$out)) # box plot for 'Age'
boxplot(ReactionTime, main="Reaction Time", sub=paste("Outlier rows: ", boxplot.stats(ReactionTime)$out)) # box plot for 'Reaction'

From these two box plots we see that there are no outliers affecting the graph so there is not a lot of clean up available for this particular data
On its own this gives some information but its quite sparse.We see a line suggesting that the higher the age the higher the reaction time but we have no numbers for this or indeed how close these points come to the line. Lets try to fix that
First the regression line. Ideally we want it to be of the form ( in this simple case) \[ response= {\beta}{_0}+{\beta}{_1}Indicator{_1}\] or \[y=c+mx\] where m is the slope of the line and c the intercept.
linearReg <- lm(ReactionTime ~ Age, data)
Regsummary<-summary(linearReg)
Regsummary
Call:
lm(formula = ReactionTime ~ Age, data = data)
Residuals:
Min 1Q Median 3Q Max
-244.86 -66.97 -13.19 69.96 306.68
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 226.1311 35.9788 6.285 9.09e-09 ***
Age 5.7990 0.7535 7.696 1.12e-11 ***
---
Signif. codes: 0 *** 0.001 ** 0.01 * 0.05 . 0.1 1
Residual standard error: 109.8 on 98 degrees of freedom
Multiple R-squared: 0.3767, Adjusted R-squared: 0.3703
F-statistic: 59.23 on 1 and 98 DF, p-value: 1.123e-11
Taking the data we need we now we can see that the line we want is \[Reaction Time = 226.1311 + 5.7990 * age\] The next thing we want to calculate is how much of this results is explained by the model. For this we use the \(R ^{2}\) value of .3703 which suggests that 37% of the reaction time is related to age.
Finally lets conside the error of the slope and work out a confidence interval for the slope of the regression line. The standard error for the slope of this line is give as 0.7535 and we kknow that the slope is 5.770 so a 95% confidence interval for this is
getCI <- function(xbar, se, n, alpha){
t=qt(1-(alpha/2), df=n-2)
me=t*se
CI=c(xbar-me, xbar+se)
return(CI)
}
CIslope<-getCI(Regsummary$coefficients[2], Regsummary$coefficients[4], 100, 0.05)
CIslope
[1] 4.303709 6.552541
so we have 2 slopes for our line and can do the same for the intercept
CIintercept<-getCI(Regsummary$coefficients[1], Regsummary$coefficients[2], 100, 0.05)
CIintercept
[1] 214.6232 231.9302
Lets use all this information to show a better plot of the data we looked at earlier( another function )
plotregression<- function(X, Y, title, xlab, ylab, c,clow, chigh, m_bar, mlow, mhigh, CI)
{
plot(X, Y, main=title, xlab=xlab, ylab=ylab)
abline(c, m_bar , col="black")
abline(clow, mlow, col= 'red')
abline(chigh, mhigh, col= 'red')
line<- paste(ylab, " = ", round(c, digits=2), " + ",round(m_bar, digits= 2), " * ", xlab )
confidence<- paste(CI, "% condfidence interval for the Regression Line")
key <-c(line, confidence )
color<- c("black", "red")
legend("topleft", key, fill = color, cex=0.5)
}
plotregression(Age, ReactionTime,
"Plot of Reaction Time -V- Age /w regression lines",
"Age(years)", "Reaction Time(ms)",
Regsummary$coefficients[1], CIintercept[1], CIintercept[2],
Regsummary$coefficients[2], CIslope[1], CIslope[2], 95
)

b.Plot a scatterplot of the reaction time data (y-axis) as a function of height(x-axis). Conduct a linear regression analysis of reaction time as a function of height and interpret the results. First lets plot the data
scatter.smooth(x=Height, y=ReactionTime, main="Reaction Time ~ Height") # scatterplot

Here we see a far flatter graph ( again no info provided) and no indication there is any trends bar a reduction in reaction times at the very tallest end of the graph
Lets look for outliers
par(mfrow=c(1,2))
boxplot(Height, main="Height", sub=paste("Outlier rows: ", boxplot.stats(Age)$out)) # box plot for 'Age'
boxplot(ReactionTime, main="Reaction Time", sub=paste("Outlier rows: ", boxplot.stats(ReactionTime)$out)) # box plot for 'Reaction'

Again no huge outliers which is good ( data is ‘clean’ ) so lets move on with the regression analysis
linearReg <- lm(ReactionTime ~ Height, data)
Regsummary<-summary(linearReg)
Regsummary
Call:
lm(formula = ReactionTime ~ Height, data = data)
Residuals:
Min 1Q Median 3Q Max
-320.20 -115.69 25.34 100.50 310.46
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 687.439 271.605 2.531 0.013 *
Height -1.173 1.611 -0.729 0.468
---
Signif. codes: 0 *** 0.001 ** 0.01 * 0.05 . 0.1 1
Residual standard error: 138.7 on 98 degrees of freedom
Multiple R-squared: 0.005387, Adjusted R-squared: -0.004762
F-statistic: 0.5308 on 1 and 98 DF, p-value: 0.468
Here we get the Linear regression formula to be \[Reaction Time(ms) = 687.439 - 1.173*Height( in cm) \] and the \(R^{2}\) value for this is 0.005358 which translates to 0.5% of the reaction time explained by the height, so it would be fair to say that Height has miniscule influence on the reaction time
Lets do Confidence intervals and the prettied up regression line( for what its worth)
CIslope<-getCI(Regsummary$coefficients[2], Regsummary$coefficients[4], 100, 0.05)
CIintercept<-getCI(Regsummary$coefficients[1], Regsummary$coefficients[3], 100, 0.05)
plotregression(Age, ReactionTime,
"Plot of Reaction Time -V- Height /w regression lines",
"Height(cm)", "Reaction Time(ms)",
Regsummary$coefficients[1], CIintercept[1], CIintercept[2],
Regsummary$coefficients[2], CIslope[1], CIslope[2], 95)

To see why the CI lines dont show on the graph lets look at the CI data for the intercept
CIintercept
[1] 148.4473 959.0442
So we see that this does not actually fit onto the graph at the scale we are at showing how little value this regression brings to the data
Logistic regression analysis: a.Conduct a Logistic regression analysis of age group as a function of reaction time and interpret the results. Lets run the regression first
logistic<- glm(formula=AgeGroup~ReactionTime, family=binomial("logit"), data )
summary(logistic)
Call:
glm(formula = AgeGroup ~ ReactionTime, family = binomial("logit"),
data = data)
Deviance Residuals:
Min 1Q Median 3Q Max
-2.2024 -0.8247 0.4806 0.7638 1.6846
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) -4.156989 1.014849 -4.096 4.2e-05 ***
ReactionTime 0.009952 0.002145 4.639 3.5e-06 ***
---
Signif. codes: 0 *** 0.001 ** 0.01 * 0.05 . 0.1 1
(Dispersion parameter for binomial family taken to be 1)
Null deviance: 131.79 on 99 degrees of freedom
Residual deviance: 101.41 on 98 degrees of freedom
AIC: 105.41
Number of Fisher Scoring iterations: 4
From this we see that the logistic regression takes the form of \[Pr(Age Group 40-70|Reaction time)= \frac{e^{\eta_{i}}}{1+e^{\eta_{i}} }\] where \[\eta_{i}=-4.156989+0.009953*Reaction Time\]
and the odds on being in the the40-70 age group given a reaction time are \[e^{\eta_{i}}:1\] With eta as desribed.
Now we can investogate the significance of this model by investigating if a 95% Confidence interval have values either side of zero
CIintercept<-getCI(4.156989,1.014849, 100, 0.05)
CIslope<- getCI( 0.009952,0.002145, 100, 0.05)
CIintercept
[1] 2.143054 5.171838
CIslope
[1] 0.005695317 0.012097000
As we see ofr each of the values in the CI are positive so we can say that this model is significant.
Finally lets plot the regression
# assign 'survival' to these 20 individuals non-randomly... most mortality occurs at smaller body size
dat=as.data.frame(cbind(ReactionTime,AgeGroup)) # saves dataframe with two columns: body size & survival
dat$AgeGroup=dat$AgeGroup-1 # just
plot(dat$ReactionTime,dat$AgeGroup,xlab="Reaction Time",ylab="Probability age between 40-70", main='Logistic regression for Age Group V Reaction Time') # plot with body size on x-axis and survival (0 or 1) on y-axis
curve(predict(logistic,data.frame(ReactionTime=x),type="resp"),add=TRUE, col="red") # draws a curve based on prediction from logistic regression model
key<-c('Value of Reaction Time and Age group', 'Regression line of probability')
col<-c('black', 'red')
legend(600, 0.4, key, fill=col,cex=0.5 )

As we see here the graph is of a typical logistic regression shape so we can summarise that our models fits the data quite well
b.Conduct a Logistic regression analysis of age group as a function of height and interpret the results.
logistic<- glm(formula=AgeGroup~Height, family=binomial("logit"), data )
summary(logistic)
Call:
glm(formula = AgeGroup ~ Height, family = binomial("logit"),
data = data)
Deviance Residuals:
Min 1Q Median 3Q Max
-1.5539 -1.3860 0.8904 0.9689 1.1341
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) 4.24830 4.05677 1.047 0.295
Height -0.02204 0.02400 -0.918 0.358
(Dispersion parameter for binomial family taken to be 1)
Null deviance: 131.79 on 99 degrees of freedom
Residual deviance: 130.95 on 98 degrees of freedom
AIC: 134.95
Number of Fisher Scoring iterations: 4
From this we see that the logistic regression takes the form of \[Pr(Age Group 40-70|Height)= \frac{e^{\eta_{i}}}{1+e^{\eta_{i}} }\]
where \[\eta_{i}=4.24830-0.02204*Height\]
and the odds on being in the the40-70 age group given a reaction time are
\[e^{\eta_{i}}:1\]
With eta as desribed.
Now we can investogate the significance of this model by investigating if a 95% Confidence interval have values either side of zero
CIintercept<-getCI( 4.24830,4.05677 , 100, 0.05)
CIslope<- getCI( -0.02204,0.024005, 100, 0.05)
CIintercept
[1] -3.802228 8.305070
CIslope
[1] -0.06967714 0.00196500
In this case we see that the CI clealy passes over 0 in both cases so we can say that the model is not significant. We can also plot this regression to see what it tells us.
# assign 'survival' to these 20 individuals non-randomly... most mortality occurs at smaller body size
dat=as.data.frame(cbind(Height,AgeGroup)) # saves dataframe with two columns: body size & survival
dat$AgeGroup=dat$AgeGroup-1 # just
plot(dat$Height,dat$AgeGroup,xlab="Height",ylab="Probability age between 40-70", main='Logistic regression for Age Group V Height') # plot with body size on x-axis and survival (0 or 1) on y-axis
curve(predict(logistic,data.frame(Height=x),type="resp"),add=TRUE, col="red") # draws a curve based on prediction from logistic regression model
key<-c('Value of Height and Age group', 'Regression line of probability')
col<-c('black', 'red')
legend(180, 0.4, key, fill=col,cex=0.5 )

Here we see the regression line is flatter and has no real way to predict the age group from the Height given( as we alluded to with the confidence intervals)
LS0tDQp0aXRsZTogIlRha2UgSG9tZSBBc3NpZ25tZW50Ig0Kc3VidGl0bGU6IENpYXJhbiBEYXJjeSBEMTAxMjMxMzIgZDEwMTIzMTMyQG15ZGl0LmllDQpvdXRwdXQ6DQogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQNCiAgcGRmX2RvY3VtZW50OiBkZWZhdWx0DQogIHdvcmRfZG9jdW1lbnQ6IGRlZmF1bHQNCi0tLQ0KDQpBcyBkZXNjcmliZWQgaW4gdGhlIGFic3RyYWN0IHdlIGhhdmUgMTAwIHN1YmplY3RzIHVuZGVyZ29pbmcgdmFyaW91cyB0ZXN0cy4gVGhlIGZpcnN0IHRoaW5nIHRvIGRvIGlzIHRvIHJlYWQgaW4gdGhlIGRhdGEgDQoqKlExICBSZWFkIGluIHRoZSBkYXRhKiogbWFrZSBzdXJlIHRoYXQgeW91IGFyZSBpbiB0aGUgY29ycmVjdCBkaXJlY3RvcnkgdG8gcmVhZCB0aGUgZGF0YSBpbi4gWW91IGNhbiB1c2UgdGhlIGNvbW1lbnRlZCBvdXQgc2V0d2QoKSBjb21tYW5kIHRvIGJyaW5nIHlvdSB0byB0aGUgY29ycmVjdCBhcmVhIGlmIHlvdSBuZWVkIHRvLiANCmBgYHtyfQ0KI3NldHdkKCI8WU9VUiBESVJFQ1RPUlkgTkFNRSBIRVJFPiIpDQpkYXRhID0gcmVhZC5jc3YoImQxMDEyMzEzMi5jc3YiLCBoZWFkZXIgPSBUUlVFKQ0KDQpgYGANCldpdGggdGhhdCBkb25lIHdlIGNhbiBiZWdpbiB0byBsb29rIGF0IHNvbWUgb2YgdGhlIGZlYXR1cmVzIG9mIHRoZSBkYXRhDQoqKlEyIFN1bW1hcmlzZSB0aGUgZGF0YSBhbmQgZGVmaW5lIHR5cGVzKioNCmBgYHtyfQ0KQWdlPWRhdGEkQWdlDQpTZXg9ZGF0YSRTZXgNCkhlaWdodD1kYXRhJEhlaWdodA0KUmVhY3Rpb25UaW1lPWRhdGEkUmVhY3Rpb25UaW1lDQpBZ2VHcm91cD0gZGF0YSRBR0VfR1JPVVANCmBgYA0KTGV0cyB0YWtlIGEgbG9vayBhdCB0aGUgYmFzaWMgZGF0YSBmcm9tIHRoZSBncm91cA0KYGBge3J9DQpzdW1tYXJ5KGRhdGEpDQoNCmBgYA0KTG9va2luZyBmb3IgdGhlIG1lYW5zIGFuZCBTdGFuZGFyZCBEZXZpYXRpb25zIHdoZXJlIEF2YWlsYWJsZQ0KKipRMyBDYWxjdWxhdGUgdGhlIG1lYW4gYW5kIHN0YW5kYXJkIGRldmlhdGlvbiBvZiB0aGUgQWdlLCBIZWlnaHQgYW5kIFJlYWN0aW9uIFRpbWVzIG9mIHRoZSB0ZXN0IGdyb3VwKioNCmBgYHtyfQ0KcHJpbnQocGFzdGUoIkF2ZXJhZ2UgQWdlOiAiLG1lYW4oQWdlKSwgIiB5ZWFycyIpKQ0KcHJpbnQocGFzdGUoIlN0YW5kYXJkIERldmlhdGlvbiBBZ2U6Iiwgc2QoQWdlKSwiIHllYXJzIiApKQ0KICAgICAgIA0KYGBgDQpgYGB7cn0NCnByaW50KHBhc3RlKCJBdmVyYWdlIEhlaWdodDogIixtZWFuKEhlaWdodCksICIgY20iKSkNCnByaW50KHBhc3RlKCJTdGFuZGFyZCBEZXZpYXRpb24gSGVpZ2g6Iiwgc2QoSGVpZ2h0KSwgIiBjbSIpKQ0KYGBgDQpgYGB7cn0NCnByaW50KHBhc3RlKCJBdmVyYWdlIFJlYWN0aW9uIFRpbWU6ICIsbWVhbihSZWFjdGlvblRpbWUpLCAiIG1zIikpDQpwcmludChwYXN0ZSgiU3RhbmRhcmQgRGV2aWF0aW9uIFJlYWN0aW9uIFRpbWU6Iiwgc2QoUmVhY3Rpb25UaW1lKSwgIiBtcyIpKQ0KYGBgDQpMZXRzIHNlZSB3aGF0IHNvbWUgb2YgdGhlIGRhdGEgbG9va3MgbGlrZQ0KKipRNEEgUGxvdCBhIGhpc3RvZ3JhbSBvZiB0aGUgaSkgcmVhY3Rpb24gdGltZSBkYXRhLCBpaSkgYWdlIGRhdGEsIGFuZCBpaWkpIGhlaWdodCBkYXRhKioNCg0KU2luY2UgdGhlcmUgaXMgc29tZSBwbG90dGluZyB0byBiZSBkb25lIGhlcmUgbGV0cyB3cml0ZSBhIGZ1bmN0aW9uIHRvIHByb2R1Y2Ugc29tZSBuaWNlIHBsb3RzIGZyb20gZ2l2ZW4gcGFyYW1ldGVycw0KYGBge3J9DQpwbG90SGlzdG9ncmFtIDwtIGZ1bmN0aW9uKGRhdGEsIHVuaXQsIHRpdGxlLCB4bGFiLCB5bGFiKSB7DQogIA0KICAjZGF0YSBmb3IgbWVhbiBhbmQgbWVkaWFuDQogIG1lYW49cm91bmQobWVhbihkYXRhKSwgZGlnaXRzPSAyKQ0KICBtZWRpYW49cm91bmQobWVkaWFuKGRhdGEpLCBkaWdpdHMgPSAyKQ0KICAjIGdldCB0aGUgbGVnZW5kDQogIA0KICBNZWFuIDwtIHBhc3RlKCJNZWFuOiIsIHRvU3RyaW5nKG1lYW4pLCB1bml0LCBzZXA9IiAiKQ0KICBNZWRpYW4gPC0gIHBhc3RlKCJNZWRpYW46ICIsICB0b1N0cmluZyhtZWRpYW4pLCB1bml0LCBzZXA9IiAiKQ0KICBrZXkgPC0gYyhNZWFuLCBNZWRpYW4pDQogIGNvbG9yIDwtIGMoInJlZCIsICJibHVlIikNCiAgI2RhdGEgZm9yIHNjYWxpbmcgDQogIHltYXggPC0gbWF4KGhpc3QoZGF0YSwgcGxvdCA9IEZBTFNFKSRjb3VudHMpDQogDQogIA0KICBoaXN0KGRhdGEsIG1haW49dGl0bGUsIHhsYWIgPSB4bGFiLCB5bGFiPXlsYWIsIGxhYmVscz1UUlVFLCB5bGltPWMoMCwgMS4xKnltYXgpLCBjb2w9cmdiKDAsMCwxLGFscGhhPS4yNSkpDQoNCg0KICAjYWRkIG1lYW4gbWVkaWFuIGFuZCBsZWdlbmQNCiAgYWJsaW5lKHY9bWVhbiwgY29sPSAncmVkJykNCiAgYWJsaW5lKHY9bWVkaWFuLCBjb2w9J2JsdWUnKQ0KICBsZWdlbmQoJ3RvcHJpZ2h0JyxrZXksIGZpbGwgPSBjb2xvciwgY2V4PSAwLjc1KQ0KfQ0KDQpgYGANClRoaXMgZnVuY3Rpb24gdGFrZXMgaW4gdGhlIGRhdGEgdG8gYmUgZ3JhcGhlZCwgQSB1bml0IG9mIG1lYXN1cmUgZm9yIHRoZSB4IHZhbHVlcyBvZiB0aGUgZGF0YSwgYW5kIHNvbWUgbGFiZWxsaW5nIGluZm9ybWF0aW9uIGluIFRpdGxlLCBYLWF4aXMgbGFiZWwgYW5kIFktYXhpcyBsYWJlbC4gSXQgdGhlbiByZXR1cm5zIGEgbGFiZWxsZWQgcGxvdCB3aXRoIHRoZSBtZWFuIGFuZCBtZWRpYW4gbWFya2VkIGluIGl0Lg0KTGV0cyBjYWxsIGl0IGZvciBSZWFjdGlvbiBUaW1lIGRhdGENCmBgYHtyfQ0KcGxvdEhpc3RvZ3JhbShkYXRhPVJlYWN0aW9uVGltZSwgDQogICAgICAgICAgICAgIHVuaXQ9Im1zIiwgDQogICAgICAgICAgICAgIHRpdGxlPSAiRnJlcXVlbmNlIG9mIHJlYWN0aW9uIFRpbWVzIiwgDQogICAgICAgICAgICAgIHhsYWIgPSAiUmVhY3Rpb24gVGltZXMgKG1zKSIsDQogICAgICAgICAgICAgIHlsYWIgPSAiRnJlcXVlY3kgb2Ygb2NjdXJhbmNlIikNCg0KYGBgDQoNClRoaXMgaGlzdG9ncmFtIHNob3dzIHRoYXQgdGhlIGRhdGEgZm9yIHRoZSByZWFjdGlvbiB0aW1lIGlzIHJvdWdobHkgc3ltbWV0cmljYWwgd2l0aCBhIG1lYW4gYXQgNDg5LjggbXMgYW5kIG1lZGlhbiBvZiA1MDguNSBtcy4gVGhpcyB0aWdodG5lc3Mgb2YgbWVhbiB0byBtZWRpYW4gc3VnZ2VzdHMgdGhhdCB0aGVyZSBhcmUgZmV3IG91dGxpZXJzIHRvIHRoZSBkYXRhIGhlcmUuIFdlIGFsc28gc2VlIHRoYXQgdGhlcmUgaXMgc29tZSBzeW1tYXRlcnkgdG8gdGhlIGRhdGEgc3VnZ2VzdGluZyB0aGF0IHRoZSBkYXRhIG1heSBjb21lIGZyb20gYSBub3JtYWwgZGlzdHJpYnV0aW9uLiBUaGVyZSBhIGFyZSAyIHBlYWtzIHRvIHRoZSBkYXRhIGF0IGFib3V0IDMwMC00MDAgbXMgYW5kIGF0IGFib3V0IDUwMC02MDAgbXMgd2hpY2ggaG9wZWZ1bGx5IGNhbiBiZSBleHBsYWluZWQgd2l0aCBmdXJ0aGVyIGFuYWx5c2lzDQoNCmBgYHtyfQ0KcGxvdEhpc3RvZ3JhbShkYXRhPUhlaWdodCwgDQogICAgICAgICAgICAgIHVuaXQ9ImNtIiwgDQogICAgICAgICAgICAgIHRpdGxlPSAiRnJlcXVlbmNlIG9mIEhlaWdodHMgaW4gU2FtcGxlIGdyb3VwIiwgDQogICAgICAgICAgICAgIHhsYWIgPSAiSGVpZ2h0KGNtKSIsDQogICAgICAgICAgICAgIHlsYWIgPSAiRnJlcXVlY3kgb2Ygb2NjdXJhbmNlIikNCmBgYA0KSGVyZSB3ZSBzZWUgdGhlIGRhdGEgaXMgc2xpZ2h0bHkgZGlmZmVyZW50bHkgc2hhcGVkLiBUaGUgbWVhbiBhbmQgbWVkaWFuIGFyZSBzbGlnaHRseSBtb3JlIHNlcGVyYXRlZCBhbmQgdGhlcmUgaXMgYSB0YWlsIHRvIHRoZSBkYXRhIGF0IHRoZSBoaWdoZXIgZW5kICggPiAxOTAgY20pIG9mIHRoZSBkYXRhLiBUaGlzIHN1Z2dlc3RzIHRoZSBwcmVzZW5jZSBvZiBhbiBvdXRsaWVyICdwdWxsaW5nJyB0aGUgZGF0YSB0b3dhcmRzIHRoYXQgZW5kIGVnLiBBIHJlYWxseSB0YWxsIHBlcnNvbiBzYW1wbGVkLiAgDQpgYGB7cn0NCnBsb3RIaXN0b2dyYW0oZGF0YSA9IEFnZSwgDQogICAgICAgICAgICAgIHVuaXQgPSAieWVhcnMiLA0KICAgICAgICAgICAgICB0aXRsZSA9ICJQbG90IG9mIHRoZSBmcmVxdWVuY3kgb2YgYWdlcyBpbiB0aGUgc2FtcGxlIGdyb3VwIiwNCiAgICAgICAgICAgICAgeGxhYiA9ICJBZ2UgaW4geWVhcnMiLA0KICAgICAgICAgICAgICB5bGFiID0gIkZyZXF1ZWN5IG9mIGFnZXMiDQogICAgICAgICAgICAgICAgKQ0KYGBgDQoNCkZpbmFsbHkgdGhpcyBkYXRhIGlzIHF1aXRlIGZsYXQuIFRoZSBtZWFuIGFuZCBtZWRpYW4gYXJlIGFsbW9zdCBpZGVudGljYWwgc3VnZ2V0aW5nIHRoYXQgdGhlIGRhdGEgZG9lcyBub3QgaGF2ZSBtYW55IG91dGxpZXJzIG9yIGV4dHJlbWUgdmFsdWVzIHB1bGxpbmcgYXQgaXQuIGl0cyBhbHNvIHNob3dzIHRoYXQgdGhlIHNhbXBsZSBncm91cCBpcyByb3VnaGx5IGVxdWFsbHkgbGlrZWx5IHRvIGhhdmUgYWdlcyBhbnl3aGVyZSBmcm9tIDIwLTcwIA0KDQoNCioqYi4gUGxvdCBhIGhpc3RvZ3JhbSBvZiB0aGUgcmVhY3Rpb24gdGltZSBkYXRhIGZvciBlYWNoIGFnZSBncm91cCAoMjAtNDB5cnMsIDQwLTcweXJzKSoqDQpGaXJzdCB3ZSBuZWVkIHRvIGdyb3VwIHRoZSBzYW1wbGUgaW50byB0aGUgYWdlIGdyb3VwcyBsb29rZWQgZm9yIHRoZW4gd2UgY2FuIHBsb3QgdGhlIGRhdGENCmBgYHtyfQ0KeW91bmdlcjwtIHN1YnNldChkYXRhLCBBR0VfR1JPVVA9PScyMC00MCcpDQpvbGRlciA8LSBzdWJzZXQoZGF0YSwgQUdFX0dST1VQPT0iNDAtNzAiKQ0KDQp5b3VuZ1JlYWN0aW9uIDwtIHlvdW5nZXIkUmVhY3Rpb25UaW1lDQpvbGRlclJlYWN0aW9uIDwtIG9sZGVyJFJlYWN0aW9uVGltZQ0KDQpgYGANCk9uY2UgdGhhdCBpcyBkb25lIHdlIGNhbiB3cml0ZSBzb21lIGNvZGUgdG8gcHJldHRpbHkgcGxvdCB0aGUgZ3JhcGhzIHNpZGUgYnkgc2lkZSANCmBgYHtyfQ0Kc2lkZWJ5c2lkZTwtIGZ1bmN0aW9uKFgsWSx0aXRsZT1OVUxMLHhsYWJlbD1OVUxMLCB5bGFiZWw9TlVMTCwgbGVnZW5kPU5VTEwpew0KI3NldCBwYXJhbWV0ZXJzIGZvciB0aGUgc2NhbGUgb2YgdGhlIGdyYXBoDQppZiAobWF4KFgpID4gbWF4KFkpKXsNCiAgeG1heCA8LSBtYXgoWCkNCn1lbHNlew0KICB4bWF4IDwtIG1heChZKQ0KfQ0KDQp4dGFsbCA8LSBtYXgoaGlzdChYLCBwbG90PUZBTFNFKSRjb3VudHMpDQp5dGFsbCA8LSBtYXgoaGlzdChZLCBwbG90PUZBTFNFKSRjb3VudHMpDQoNCmlmICh4dGFsbD55dGFsbCl7DQogIHltYXg9eHRhbGwNCn1lbHNlew0KICB5bWF4PXl0YWxsDQp9DQoNCiNzZXQgdGhlIGxlZ2VuZHMNCmtleSA8LSBsZWdlbmQNCmNvbG9yIDwtIGMoImJsdWUiLCAicmVkIikNCg0KbWVhblg8LSBtZWFuKFgpDQptZWFuWTwtIG1lYW4oWSkNCg0KDQojcGxvdCB0aGUgMiBncmFwaHMgc2lkZSBieSBzaWRlIA0KaGlzdChYLCBjb2w9cmdiKDAsMCwxLGFscGhhPS4yNSksIA0KICAgICBtYWluPXRpdGxlLCB4bGFiPXhsYWJlbCwgeWxhYj15bGFiZWwsIHhsaW0gPSBjKDAsIDEuMSp4bWF4KSwgbGFiZWxzPVRSVUUsICB5bGltPWMoMCwxLjEqeW1heCkpIA0KaGlzdChZLCBjb2w9cmdiKDEsMCwwLCBhbHBoYT0wLjI1KSwgeGxpbSA9IGMoMCwgMS4xKnhtYXgpLCB5bGltPWMoMCwxLjEqeW1heCksbGFiZWxzPVRSVUUsIGFkZD1UUlVFKSANCg0KI2FkZCBsaW5lcyBzaG93aW5nIG1lYW4gb2YgZWFjaCBzZWN0aW9uDQphYmxpbmUodj1tZWFuWCwgY29sPSAnYmx1ZScpDQp0ZXh0KG1lYW5YLCB5bWF4LCBwYXN0ZSgibWVhbjoiLCByb3VuZChtZWFuWCwgZGlnaXRzPTIpKSAsIGNvbCA9ICJibHVlIiwgY2V4PTAuNSkgDQoNCmFibGluZSh2PW1lYW5ZLCBjb2w9J3JlZCcpDQp0ZXh0KG1lYW5ZLCAoeW1heC0wLjUpLCBwYXN0ZSgibWVhbjoiLCByb3VuZChtZWFuWSwgZGlnaXRzPTIpKSAsIGNvbCA9ICJyZWQiLCBjZXg9MC41KSANCg0KI2luY2x1ZGUgYSBsZWdlbmQNCmxlZ2VuZCgndG9wbGVmdCcsa2V5LCBmaWxsID0gY29sb3IsIGNleD0gMC41ICkNCg0KfQ0KYGBgDQoNCkZpbmFsbHkgd2l0aCBhbGwgb2YgdGhlIHByZXAgd29yayBkb25lIHdlIGNhbiBwbG90IHRoZSBkYXRhDQpgYGB7cn0NCnNpZGVieXNpZGUoeW91bmdSZWFjdGlvbiwgb2xkZXJSZWFjdGlvbiwgdGl0bGU9IkNvbXBhcmF0aXZlIHJlYWN0aW9uIFRpbWVzIGJ5IEFnZSIsIHhsYWJlbCA9ICJSZWFjdGlvbiBUaW1lcyAobXMpIiwgeWxhYmVsPSJjb3VudHMiLCBsZWdlbmQ9YygiQWdlIEdyb3VwIDIwLTQwIiwgIkFnZSBHcm91cCA0MC03MCIpKQ0KDQpgYGANCkhlcmUgd2UgY2FuIHNlZSB0aGF0IGZvciB5b3VuZ2VyIHBlb3BsZSB0aGUgbWVhbiByZWFjdGlvbiBpcyBsb3dlciB0aGFuIGZvciBvbGRlciBwZW9wbGUuIFRoZSBvbGRlciBwb3B1bGF0aW9uIChpbiByZWQpIHRlbmRzIHRvd2FycyB0aGUgMzAwLTkwMCBtcyByYW5nZSB3aGlsZSB0aGUgeW91bmdlciBwb3B1bGF0aW9uIHRlbmRzIHRvd2FyZHMgdGhlIDEwMC03MDAgbXMuIFdlIHNlZSBhIGxvbmdlciB0YWlsIG9uIHRoZSB5b3VuZ2VyIHBvcHVsYXRpb24gdGhhdCB0aGUgY29ycmVzcG9uZGluZyB0YWlsIG9uIHRoZSBvbGRlciBvbmUgd2hpY2ggaXMgc2xpZ2h0bHkgbW9yZSBzeW1tYXRlcmljYWwuIFdoZW4gbG9va2luZyBhdCB0aGlzIGdyYXBoIHdlIHNlZSBhIHJlYXNvbiBmb3IgdGhlIDIgcGVha3MgbWVhbnRpb25lZCBpbiB0aGUgcHJldmlvdXMgcmVhY3Rpb24gdGltZXMgZ3JhcGguIFRoZSAyIHBlYWtzIG9mIHRoZSBjb21iaW5lZCBncmFwaCBjb2luY2lkZSB3aXRoIHRoZSBtZWFucyBvZiBlYWNoIG9mIHRoZSBhZ2UgZ3JvdXBzIG9uIHRoaXMgZ3JhcGguIA0KDQoNCioqR2l2ZW4gdGhhdCB0aGUgDQpwb3B1bGF0aW9ucyBtZWFuIHJlYWN0aW9uIHRpbWUgaXMgNDUwbXMuIENvbmR1Y3QgYSBoeXBvdGhlc2lzIHRlc3Qgc3RhdGluZyB0aGUgTnVsbCBIMCBhbmQgYWx0ZXJuYXRpdmUgSM6xLCBjYWxjdWxhdGluZyB0aGUgdGVzdCBzdGF0aXN0aWNzLCBzdGF0aW5nIHlvdXIgY3JpdGVyaWEgZm9yIHJlamVjdGlvbiwgYW5kIHlvdXIgY29uY2x1c2lvbiBmb3IgdGhlIHJlYWN0aW9uIHRpbWUgZGF0YSBvZiB0aGU6DQphLjIwLTQwIHllYXIgb2xkIGdyb3VwDQpiLiA0MC03MCB5ZWFyIG9sZCBncm91cCoqDQoNCmEuIEZpcnN0IGxldHMgd3JpdGUgYSBmdW5jdGlvbiB0byBjYWxjdWxhdGUgc29tZSBDb25maWRlbmNlIGludGVydmFscyBmb3IgdGhlIGRhdGEgYW5kIHdlIHdpbGwgYWxzbyB1c2UgdGhlIGZlYXR1cmVzIG9mIHRoZSBkYXRhIHRvIGNhbGN1bGF0ZSB0aGVtIA0KDQoNCmBgYHtyfQ0KZmluZENJIDwtIGZ1bmN0aW9uKHgsIGFscGhhKXsNCiAgDQogICNzZXQgdXAgdmFyaWFibGVzDQogIHhiYXIgPC0gbWVhbih4KQ0KICBzaWdtYSA8LSBzZCh4KQ0KICBuIDwtIGxlbmd0aCh4KQ0KICBzZSA8LSBzaWdtYS9zcXJ0KG4pDQogIA0KICANCiAgI2NhbGN1bGF0ZSB0DQogIHRuXzFfYWxwaGEuMiA8LSBxdCgxIC0gYWxwaGEvMiwgZGYgPSBuIC0gMSkNCiAgDQogICNyZXR1cm4gdGhlIENJDQogIA0KICBDSSA8LSAgYyh4YmFyLXRuXzFfYWxwaGEuMipzZSx4YmFyK3RuXzFfYWxwaGEuMipzZSkNCiAgcmV0dXJuIChDSSkNCiAgDQp9IA0KDQpgYGANClRoaXMgdGFrZXMgYSByZWplY3Rpb24gY3JpdGVyaWEgKCBpbiBkZWNpbWFsICkgYW5kIGEgZGF0YSBzZXQgYW5kIGNhbGN1bGF0ZXMgYSBjb25maWRlbmNlIGludGVydmFsIGZvciB0aGUgdGVzdCBzdGF0aXN0aWMgdG8gZmFsbCBpbnNpZGUgaW4gb3JkZXIgZm9yIHRoZSBudWxsIGh5cG90aGVzaXMgdG8gYmUgYWNjZXB0ZWQuDQpgYGB7cn0NCmZpbmRDSSh5b3VuZ1JlYWN0aW9uLDAuMDUpDQpgYGANCg0KV2Ugd291bGQgbGlrZSBvdXIgbnVsbCBoeXBvdGhlc2lzIHRvIGZhbGwgd2l0aGluIHRoaXMgcmVnaW9uIGlmIHdlIGFyZSB0byBhY2NlcHQgdGhlIG51bGwgaHlwb3RoZXNpcw0KYGBge3J9DQpDSXRlc3QgPC0gZnVuY3Rpb24gKCBoMCwgeCwgYWxwaGEpew0KICBDSSA8LSBmaW5kQ0koIHgsIGFscGhhKQ0KICBpZihoMCA8IENJWzFdKXsNCiAgICBhbnM8LSIgSDAgcmVqZWN0ZWQiDQogICAgcmVhc29uIDwtcGFzdGUoaDAsICJmYWxscyBiZWxvdyB0aGUgbG93ZXIgbGltaXQgb2Ygb3VyIiwgKDEtYWxwaGEpKjEwMCwgIiUgY29uZmlkZW5jZSBpbnRlcnZhbCB3aGljaCBpcyBmb3VuZCB0byBiZTogIiAsQ0lbMV0sIHNlcD0iICIpDQogIH0NCiAgZWxzZSBpZiAoaDA+Q0lbMl0pew0KICAgIA0KICAgIGFuczwtIkgwIHJlamVjdGVkIg0KICAgIHJlYXNvbiA8LXBhc3RlKGgwLCAiZmFsbHMgYWJvdmUgdGhlIHVwcGVyIGxpbWl0IG9mIG91ciIsICgxLWFscGhhKSoxMDAsICIlIGNvbmZpZGVuY2UgaW50ZXJ2YWwgd2hpY2ggaXMgZm91bmQgdG8gYmU6ICIgLENJWzJdLCBzZXA9IiAiKQ0KICB9DQoNCiAgZWxzZXsNCiAgICBhbnMgPC0gIkgwIE5vdCByZWplY3RlZCINCiAgICByZWFzb24gPC1wYXN0ZShoMCwgImZhbGxzIGJldHdlZW4gdGhlIGxvd2VyIGFuZCB1cHBlciBsaW1pdCBvZiBvdXIiLCAoMS1hbHBoYSkqMTAwLCAiJSBjb25maWRlbmNlIGludGVydmFsIHdoaWNoIGlzIGZvdW5kIHRvIGJlIGJldHdlZW4gOiAiICxDSVsxXSwiYW5kIixDSVsyXSwgc2VwPSIgIikNCiAgfQ0KICANCnJldHVybihwYXN0ZShhbnMsIHJlYXNvbiwgc2VwPSIgOiAiKSkgIA0KfQ0KYGBgDQpMZXRzIGNhbGwgdGhpcyBmdW5jdGlvbiB0byB0ZXN0IHdoYXQgd2UgY2FuIGFscmVhZHkgc2VlIChoMDogJG11JD0gNDUwIGRvZXMgbm90IGZpdCBpbiBvdXIgY29uZmlkZW5jZSBpbnRlcnZhbCkNCmBgYHtyfQ0KDQoNCmBgYA0KDQpgYGB7cn0NCkNJdGVzdCg0NTAsIHlvdW5nUmVhY3Rpb24sIDAuMDUpDQpgYGANCg0KDQpTbyBmb3IgdGhpcyB0ZXN0IHdlIHJlamVjdCB0aGUgbnVsbCBoeXBvdGhlc2lzLiBCZWNhdXNlIGgwIGZhbGxzIG91dHNpZGUgdGhlIHVwcGVyIGJvdW5kYXJ5IG9mIHRoZSB0aGUgQ29uZmlkZW5jZSBJbnRlcnZhbCB3ZSBjYW4gZGVkdWNlIHRoYXQgdGhlIHJlYWwgbWVhbiBpcyBsb3dlciB0aGFuIDQ1MC4gDQpgYGB7cn0NCnQudGVzdCh5b3VuZ1JlYWN0aW9uLCBtdT00NTAsIGNvbmYubGV2ZWwgPSAuOTUpDQoNCmBgYA0KVGhpcyBidWlsdCBpbiBmdW5jdGlvbiBnaXZlcyBzb21lIG1vcmUgaW5mb3JtYXRpb24sIG1vc3Qgbm90YWJseSB0aGUgcC12YWx1ZSB3aGljaCBoZXJlIGlzIHNpZ25pZmljYW50bHkgbGVzcyB0aGFuIHRoZSAkdHthLzJ9LHtuLTF9JCBzbyBvbmNlIGFnYWluIHdlIGNhbiByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcw0KbGV0cyBncmFwaCB0aGlzIG9uIHRoZSBoaXN0b2dyYW0gb2YgYWdlcyAoIG1lYW5zIG1vcmUgZnVuY3Rpb25zLikNCg0KYGBge3J9DQpoaXN0Q0kgPC0gZnVuY3Rpb24oZGF0YSwgYWxwaGEsIHRpdGxlPU5VTEwsIHhsYWI9TlVMTCwgeWxhYj1OVUxMLCBoMCkgew0KICB5bWF4PW1heChoaXN0KGRhdGEsIHBsb3Q9RkFMU0UpJGNvdW50cykNCiAgaGlzdChkYXRhLCBjb2w9cmdiKDAsMCwxLGFscGhhPS4yNSksIA0KICAgICAgIG1haW49cGFzdGUodGl0bGUsICIgd2l0aCAiLCAoKDEtYWxwaGEpKjEwMCksICIgQ29uZmlkZW5jZSBJbnRlcnZhbCIpLCB4bGFiPXhsYWIsIHlsYWI9eWxhYiwgIHlsaW09YygwLDEuMSp5bWF4KSkgDQogIGFibGluZSh2PWgwLCBjb2w9ICdibHVlJykNCiAgdGV4dChoMCwgeW1heCwgImgwOiBtZWFuPTQ1MG1zIiAsIGNvbCA9ICJibHVlIiwgY2V4PTAuNSkgDQogIENJIDwtIGZpbmRDSShkYXRhLGFscGhhKQ0KICBDSW1pbiA8LSBDSVsxXQ0KICBDSW1heCA8LSBDSVsyXQ0KICBhYmxpbmUodj1DSW1pbiwgY29sPSAncmVkJykNCiAgdGV4dChDSW1pbiwgeW1heC01LCBwYXN0ZSgiQ0kgbWluOiIsIHJvdW5kKENJbWluLCBkaWdpdHM9MiksICIgbXMiKSAsIGNvbCA9ICJyZWQiLCBjZXg9MC41KSANCiAgYWJsaW5lKHY9Q0ltYXgsIGNvbD0gJ3JlZCcpDQogIHRleHQoQ0ltYXgsIHltYXgtMi41LCBwYXN0ZSgiQ0kgbWF4OiIsIHJvdW5kKENJbWF4LCBkaWdpdHM9MiksICIgbXMiKSAsIGNvbCA9ICJyZWQiLCBjZXg9MC41KSANCn0NCmBgYA0KDQpgYGB7cn0NCmhpc3RDSSh5b3VuZ1JlYWN0aW9uLCAwLjA1LCAiWW91bmcgcmVhY3Rpb24gdGltZXMiLCAiUmVhY3Rpb24gVGltZXMgKG1zKSIsICJjb3VudHMiLCA0NTApDQpgYGANCg0KDQpUaGlzIHNob3dzIHRoYXQgdGhlIGh5cG90aGVzaXNlZCBtZWFuIGZhbGxzICgganVzdCkgIG91dHNpZGUgdGhlIGNvbmZpZGVuY2UgaW50ZXJ2YWxzIG9mIHRoZSBkaXN0cmlidXRpb24NCioqYi4gNDAgLTcwIGFnZSBncm91cCoqDQpXZSBqdXN0IHJlcGVhdCB0aGlzIGZvciB0aGUgb2xkZXIgYWdlIGdyb3VwDQoNCmBgYHtyfQ0KQ0l0ZXN0KDQ1MCwgb2xkZXJSZWFjdGlvbiwgMC4wNSkNCmBgYA0KDQpgYGB7cn0NCmhpc3RDSShvbGRlclJlYWN0aW9uLCAwLjA1LCAiT2xkZXIgcmVhY3Rpb24gdGltZXMiLCAiUmVhY3Rpb24gVGltZXMgKG1zKSIsICJjb3VudHMiLCA0NTApDQpgYGANCkhlcmUgd2Ugc2VlIHRoYXQgdGhhdCB0aGUgQ29uZmlkZW5jZSBpbnRlcnZhbCBpcyBoaWdoZXIgZm9yIHRoZSBzYW1wbGUgZ3JvdXAsIHNvIHRoYXQgb3VyIG1lYW4gb2YgNDUwIGlzIHRvbyBsb3cgZm9yIHRoZSBzYW1wbGUuIExldHMgY2hlY2sgdGhlIFR0ZXN0IGZ1bmN0aW9uIHRvIGJlIHN1cmUNCg0KYGBge3J9DQp0LnRlc3Qob2xkZXJSZWFjdGlvbiwgbXU9NDUwKQ0KYGBgDQoNCkFnYWluIGlmIHdlIGxvb2sgYXQgdGhlIHAtdmFsdWUgaXQgaXMgZmFyIGJlbG93IHRoZSAxLjk2IG5lZWRlZCB0byBhY2NlcHQgdGhlIG51bGwgaHlwb3RoZXNpcw0KDQpTTyBvbmNlIGFnYWluIHdlIHJlamVjdCB0aGUgTnVsbCBoeXBvdGhlc2lzIHRoYXQgJHttdX09IDQ1MG1zJA0KDQoNCioqTGluZWFyIHJlZ3Jlc3Npb24gYW5hbHlzaXMqKg0KKmEuUGxvdCBhIHNjYXR0ZXJwbG90IG9mIHRoZSByZWFjdGlvbiB0aW1lIGRhdGEgKHktYXhpcykgYXMgYSBmdW5jdGlvbiBvZiBhZ2UoeC1heGlzKS4gQ29uZHVjdCBhIGxpbmVhciByZWdyZXNzaW9uIGFuYWx5c2lzIG9mIHJlYWN0aW9uIHRpbWUgYXMgYSBmdW5jdGlvbmFnZSBhbmQgaW50ZXJwcmV0IHRoZSByZXN1bHRzLioNCg0KRmlyc3QgbGV0cyBwbG90IHRoZSBkYXRhDQpgYGB7cn0NCnNjYXR0ZXIuc21vb3RoKHg9QWdlLCB5PVJlYWN0aW9uVGltZSwgbWFpbj0iUmVhY3Rpb24gVGltZSB+IEFnZSIpICAjIHNjYXR0ZXJwbG90DQpgYGANCg0KDQoNCkxldHMgc2VlIGlmIHdlIGNhbiBjbGVhbiB0aGlzIHVwIGZpcnN0DQoNCmBgYHtyfQ0KcGFyKG1mcm93PWMoMSwyKSkNCmJveHBsb3QoQWdlLCBtYWluPSJBZ2UiLCBzdWI9cGFzdGUoIk91dGxpZXIgcm93czogIiwgYm94cGxvdC5zdGF0cyhBZ2UpJG91dCkpICAjIGJveCBwbG90IGZvciAnQWdlJw0KYm94cGxvdChSZWFjdGlvblRpbWUsIG1haW49IlJlYWN0aW9uIFRpbWUiLCBzdWI9cGFzdGUoIk91dGxpZXIgcm93czogIiwgYm94cGxvdC5zdGF0cyhSZWFjdGlvblRpbWUpJG91dCkpICAjIGJveCBwbG90IGZvciAnUmVhY3Rpb24nDQpgYGANCkZyb20gdGhlc2UgdHdvIGJveCBwbG90cyB3ZSBzZWUgdGhhdCB0aGVyZSBhcmUgbm8gb3V0bGllcnMgYWZmZWN0aW5nIHRoZSBncmFwaCBzbyB0aGVyZSBpcyBub3QgYSBsb3Qgb2YgY2xlYW4gdXAgYXZhaWxhYmxlIGZvciB0aGlzIHBhcnRpY3VsYXIgZGF0YQ0KDQoNCk9uIGl0cyBvd24gdGhpcyBnaXZlcyBzb21lIGluZm9ybWF0aW9uIGJ1dCBpdHMgcXVpdGUgc3BhcnNlLldlIHNlZSBhIGxpbmUgc3VnZ2VzdGluZyB0aGF0IHRoZSBoaWdoZXIgdGhlIGFnZSB0aGUgaGlnaGVyIHRoZSByZWFjdGlvbiB0aW1lIGJ1dCB3ZSBoYXZlIG5vIG51bWJlcnMgZm9yIHRoaXMgb3IgaW5kZWVkIGhvdyBjbG9zZSB0aGVzZSBwb2ludHMgY29tZSB0byB0aGUgbGluZS4gTGV0cyB0cnkgdG8gZml4IHRoYXQgDQoNCkZpcnN0IHRoZSByZWdyZXNzaW9uIGxpbmUuIElkZWFsbHkgd2Ugd2FudCBpdCB0byBiZSBvZiB0aGUgZm9ybSAoIGluIHRoaXMgc2ltcGxlIGNhc2UpIA0KJCQgcmVzcG9uc2U9IHtcYmV0YX17XzB9K3tcYmV0YX17XzF9SW5kaWNhdG9ye18xfSQkDQpvciANCiQkeT1jK214JCQNCndoZXJlIG0gaXMgdGhlIHNsb3BlIG9mIHRoZSBsaW5lIGFuZCBjIHRoZSBpbnRlcmNlcHQuIA0KYGBge3J9DQoNCmxpbmVhclJlZyA8LSBsbShSZWFjdGlvblRpbWUgfiBBZ2UsIGRhdGEpDQpSZWdzdW1tYXJ5PC1zdW1tYXJ5KGxpbmVhclJlZykNClJlZ3N1bW1hcnkNCg0KYGBgDQoNClRha2luZyB0aGUgZGF0YSB3ZSBuZWVkIHdlIG5vdyB3ZSBjYW4gc2VlIHRoYXQgdGhlIGxpbmUgd2Ugd2FudCBpcyANCiQkUmVhY3Rpb24gVGltZSA9IDIyNi4xMzExICsgNS43OTkwICogYWdlJCQNClRoZSBuZXh0IHRoaW5nIHdlIHdhbnQgdG8gY2FsY3VsYXRlIGlzIGhvdyBtdWNoIG9mIHRoaXMgcmVzdWx0cyBpcyBleHBsYWluZWQgYnkgdGhlIG1vZGVsLiBGb3IgdGhpcyB3ZSB1c2UgdGhlICRSIF57Mn0kIHZhbHVlIG9mIC4zNzAzIHdoaWNoIHN1Z2dlc3RzIHRoYXQgKiozNyUqKiBvZiB0aGUgcmVhY3Rpb24gdGltZSBpcyByZWxhdGVkIHRvIGFnZS4gDQoNCkZpbmFsbHkgbGV0cyBjb25zaWRlIHRoZSBlcnJvciBvZiB0aGUgc2xvcGUgYW5kIHdvcmsgb3V0IGEgY29uZmlkZW5jZSBpbnRlcnZhbCBmb3IgdGhlIHNsb3BlIG9mIHRoZSByZWdyZXNzaW9uIGxpbmUuDQpUaGUgc3RhbmRhcmQgZXJyb3IgZm9yIHRoZSBzbG9wZSBvZiB0aGlzIGxpbmUgaXMgZ2l2ZSBhcyAqKjAuNzUzNSoqIGFuZCB3ZSBra25vdyB0aGF0IHRoZSBzbG9wZSBpcyAqKjUuNzcwKiogc28gYSA5NSUgY29uZmlkZW5jZSBpbnRlcnZhbCBmb3IgdGhpcyBpcyANCg0KYGBge3J9DQpnZXRDSSA8LSBmdW5jdGlvbih4YmFyLCBzZSwgbiwgYWxwaGEpew0KICB0PXF0KDEtKGFscGhhLzIpLCBkZj1uLTIpDQogIG1lPXQqc2UNCiAgQ0k9Yyh4YmFyLW1lLCB4YmFyK3NlKQ0KICByZXR1cm4oQ0kpDQp9DQpgYGANCg0KDQpgYGB7cn0NCkNJc2xvcGU8LWdldENJKFJlZ3N1bW1hcnkkY29lZmZpY2llbnRzWzJdLCBSZWdzdW1tYXJ5JGNvZWZmaWNpZW50c1s0XSwgMTAwLCAwLjA1KQ0KQ0lzbG9wZQ0KYGBgDQoNCnNvIHdlIGhhdmUgMiBzbG9wZXMgZm9yIG91ciBsaW5lIGFuZCBjYW4gZG8gdGhlIHNhbWUgZm9yIHRoZSBpbnRlcmNlcHQNCmBgYHtyfQ0KQ0lpbnRlcmNlcHQ8LWdldENJKFJlZ3N1bW1hcnkkY29lZmZpY2llbnRzWzFdLCBSZWdzdW1tYXJ5JGNvZWZmaWNpZW50c1syXSwgMTAwLCAwLjA1KQ0KQ0lpbnRlcmNlcHQNCmBgYA0KDQpMZXRzIHVzZSBhbGwgdGhpcyBpbmZvcm1hdGlvbiB0byBzaG93IGEgYmV0dGVyIHBsb3Qgb2YgdGhlIGRhdGEgd2UgbG9va2VkIGF0IGVhcmxpZXIoIGFub3RoZXIgZnVuY3Rpb24gKQ0KDQpgYGB7cn0NCnBsb3RyZWdyZXNzaW9uPC0gZnVuY3Rpb24oWCwgWSwgdGl0bGUsIHhsYWIsIHlsYWIsIGMsY2xvdywgY2hpZ2gsIG1fYmFyLCBtbG93LCBtaGlnaCwgQ0kpDQp7DQpwbG90KFgsIFksIG1haW49dGl0bGUsIHhsYWI9eGxhYiwgeWxhYj15bGFiKQ0KDQphYmxpbmUoYywgbV9iYXIgLCBjb2w9ImJsYWNrIikNCmFibGluZShjbG93LCBtbG93LCBjb2w9ICdyZWQnKQ0KYWJsaW5lKGNoaWdoLCBtaGlnaCwgY29sPSAncmVkJykNCg0KbGluZTwtIHBhc3RlKHlsYWIsICIgPSAiLCByb3VuZChjLCBkaWdpdHM9MiksICIgKyAiLHJvdW5kKG1fYmFyLCBkaWdpdHM9IDIpLCAiICogIiwgeGxhYiApDQpjb25maWRlbmNlPC0gcGFzdGUoQ0ksICIlIGNvbmRmaWRlbmNlIGludGVydmFsIGZvciB0aGUgUmVncmVzc2lvbiBMaW5lIikNCmtleSA8LWMobGluZSwgY29uZmlkZW5jZSApDQpjb2xvcjwtIGMoImJsYWNrIiwgInJlZCIpDQpsZWdlbmQoInRvcGxlZnQiLCBrZXksIGZpbGwgPSBjb2xvciwgY2V4PTAuNSkNCn0NCmBgYA0KYGBge3J9DQpwbG90cmVncmVzc2lvbihBZ2UsIFJlYWN0aW9uVGltZSwNCiAgICAgICAgICAgICAgICJQbG90IG9mIFJlYWN0aW9uIFRpbWUgLVYtIEFnZSAvdyByZWdyZXNzaW9uIGxpbmVzIiwNCiAgICAgICAgICAgICAgICJBZ2UoeWVhcnMpIiwgIlJlYWN0aW9uIFRpbWUobXMpIiwNCiAgICAgICAgICAgICAgIFJlZ3N1bW1hcnkkY29lZmZpY2llbnRzWzFdLCBDSWludGVyY2VwdFsxXSwgQ0lpbnRlcmNlcHRbMl0sDQogICAgICAgICAgICAgICBSZWdzdW1tYXJ5JGNvZWZmaWNpZW50c1syXSwgQ0lzbG9wZVsxXSwgQ0lzbG9wZVsyXSwgOTUNCiAgICAgICAgICAgICAgICkNCmBgYA0KDQoNCipiLlBsb3QgYSBzY2F0dGVycGxvdCBvZiB0aGUgcmVhY3Rpb24gdGltZSBkYXRhICh5LWF4aXMpIGFzIGEgZnVuY3Rpb24gb2YgaGVpZ2h0KHgtYXhpcykuIENvbmR1Y3QgYSBsaW5lYXIgcmVncmVzc2lvbiBhbmFseXNpcyBvZiByZWFjdGlvbiB0aW1lIGFzIGEgZnVuY3Rpb24gb2YgaGVpZ2h0IGFuZCBpbnRlcnByZXQgdGhlIHJlc3VsdHMuKg0KRmlyc3QgbGV0cyBwbG90IHRoZSBkYXRhDQpgYGB7cn0NCnNjYXR0ZXIuc21vb3RoKHg9SGVpZ2h0LCB5PVJlYWN0aW9uVGltZSwgbWFpbj0iUmVhY3Rpb24gVGltZSB+IEhlaWdodCIpICAjIHNjYXR0ZXJwbG90DQpgYGANCkhlcmUgd2Ugc2VlIGEgZmFyIGZsYXR0ZXIgZ3JhcGggKCBhZ2FpbiBubyBpbmZvIHByb3ZpZGVkKSBhbmQgbm8gaW5kaWNhdGlvbiB0aGVyZSBpcyBhbnkgdHJlbmRzIGJhciBhIHJlZHVjdGlvbiBpbiByZWFjdGlvbiB0aW1lcyBhdCB0aGUgdmVyeSB0YWxsZXN0IGVuZCBvZiB0aGUgZ3JhcGgNCg0KTGV0cyBsb29rIGZvciBvdXRsaWVycw0KDQpgYGB7cn0NCnBhcihtZnJvdz1jKDEsMikpDQpib3hwbG90KEhlaWdodCwgbWFpbj0iSGVpZ2h0Iiwgc3ViPXBhc3RlKCJPdXRsaWVyIHJvd3M6ICIsIGJveHBsb3Quc3RhdHMoQWdlKSRvdXQpKSAgIyBib3ggcGxvdCBmb3IgJ0FnZScNCmJveHBsb3QoUmVhY3Rpb25UaW1lLCBtYWluPSJSZWFjdGlvbiBUaW1lIiwgc3ViPXBhc3RlKCJPdXRsaWVyIHJvd3M6ICIsIGJveHBsb3Quc3RhdHMoUmVhY3Rpb25UaW1lKSRvdXQpKSAgIyBib3ggcGxvdCBmb3IgJ1JlYWN0aW9uJw0KYGBgDQpBZ2FpbiBubyBodWdlIG91dGxpZXJzIHdoaWNoIGlzIGdvb2QgKCBkYXRhIGlzICdjbGVhbicgKSBzbyBsZXRzIG1vdmUgb24gd2l0aCB0aGUgcmVncmVzc2lvbiBhbmFseXNpcw0KYGBge3J9DQpsaW5lYXJSZWcgPC0gbG0oUmVhY3Rpb25UaW1lIH4gSGVpZ2h0LCBkYXRhKQ0KUmVnc3VtbWFyeTwtc3VtbWFyeShsaW5lYXJSZWcpDQpSZWdzdW1tYXJ5DQpgYGANCkhlcmUgd2UgZ2V0IHRoZSBMaW5lYXIgcmVncmVzc2lvbiBmb3JtdWxhIHRvIGJlDQokJFJlYWN0aW9uIFRpbWUobXMpID0gNjg3LjQzOSAtIDEuMTczKkhlaWdodCggaW4gY20pICQkDQphbmQgdGhlICRSXnsyfSQgdmFsdWUgZm9yIHRoaXMgaXMgMC4wMDUzNTggd2hpY2ggdHJhbnNsYXRlcyB0byAqKjAuNSUqKiBvZiB0aGUgcmVhY3Rpb24gdGltZSBleHBsYWluZWQgYnkgdGhlIGhlaWdodCwgc28gaXQgd291bGQgYmUgZmFpciB0byBzYXkgdGhhdCBIZWlnaHQgaGFzIG1pbmlzY3VsZSBpbmZsdWVuY2Ugb24gdGhlIHJlYWN0aW9uIHRpbWUNCg0KDQpMZXRzIGRvIENvbmZpZGVuY2UgaW50ZXJ2YWxzIGFuZCB0aGUgcHJldHRpZWQgdXAgcmVncmVzc2lvbiBsaW5lKCBmb3Igd2hhdCBpdHMgd29ydGgpDQoNCmBgYHtyfQ0KQ0lzbG9wZTwtZ2V0Q0koUmVnc3VtbWFyeSRjb2VmZmljaWVudHNbMl0sIFJlZ3N1bW1hcnkkY29lZmZpY2llbnRzWzRdLCAxMDAsIDAuMDUpDQoNCg0KQ0lpbnRlcmNlcHQ8LWdldENJKFJlZ3N1bW1hcnkkY29lZmZpY2llbnRzWzFdLCBSZWdzdW1tYXJ5JGNvZWZmaWNpZW50c1szXSwgMTAwLCAwLjA1KQ0KDQoNCnBsb3RyZWdyZXNzaW9uKEFnZSwgUmVhY3Rpb25UaW1lLA0KICAgICAgICAgICAgICAgIlBsb3Qgb2YgUmVhY3Rpb24gVGltZSAtVi0gSGVpZ2h0IC93IHJlZ3Jlc3Npb24gbGluZXMiLA0KICAgICAgICAgICAgICAgIkhlaWdodChjbSkiLCAiUmVhY3Rpb24gVGltZShtcykiLA0KICAgICAgICAgICAgICAgUmVnc3VtbWFyeSRjb2VmZmljaWVudHNbMV0sIENJaW50ZXJjZXB0WzFdLCBDSWludGVyY2VwdFsyXSwNCiAgICAgICAgICAgICAgIFJlZ3N1bW1hcnkkY29lZmZpY2llbnRzWzJdLCBDSXNsb3BlWzFdLCBDSXNsb3BlWzJdLCA5NSkNCmBgYA0KVG8gc2VlIHdoeSB0aGUgQ0kgbGluZXMgZG9udCBzaG93IG9uIHRoZSBncmFwaCBsZXRzIGxvb2sgYXQgdGhlIENJIGRhdGEgZm9yIHRoZSBpbnRlcmNlcHQNCmBgYHtyfQ0KDQpDSWludGVyY2VwdA0KYGBgDQpTbyB3ZSBzZWUgdGhhdCB0aGlzIGRvZXMgbm90IGFjdHVhbGx5IGZpdCBvbnRvIHRoZSBncmFwaCBhdCB0aGUgc2NhbGUgd2UgYXJlIGF0IHNob3dpbmcgaG93IGxpdHRsZSB2YWx1ZSB0aGlzIHJlZ3Jlc3Npb24gYnJpbmdzIHRvIHRoZSBkYXRhDQoNCioqTG9naXN0aWMgcmVncmVzc2lvbiBhbmFseXNpczoqKg0KKmEuQ29uZHVjdCBhIExvZ2lzdGljIHJlZ3Jlc3Npb24gYW5hbHlzaXMgb2YgYWdlIGdyb3VwIGFzIGEgZnVuY3Rpb24gb2YgcmVhY3Rpb24gdGltZSBhbmQgaW50ZXJwcmV0IHRoZSByZXN1bHRzLioNCkxldHMgcnVuIHRoZSByZWdyZXNzaW9uIGZpcnN0IA0KDQpgYGB7cn0NCmxvZ2lzdGljPC0gZ2xtKGZvcm11bGE9QWdlR3JvdXB+UmVhY3Rpb25UaW1lLCBmYW1pbHk9Ymlub21pYWwoImxvZ2l0IiksIGRhdGEgICkNCnN1bW1hcnkobG9naXN0aWMpDQpgYGANCkZyb20gdGhpcyB3ZSBzZWUgdGhhdCB0aGUgbG9naXN0aWMgcmVncmVzc2lvbiB0YWtlcyB0aGUgZm9ybSBvZg0KJCRQcihBZ2UgR3JvdXAgNDAtNzB8UmVhY3Rpb24gdGltZSk9IFxmcmFje2Vee1xldGFfe2l9fX17MStlXntcZXRhX3tpfX0gfSQkDQp3aGVyZQ0KJCRcZXRhX3tpfT0tNC4xNTY5ODkrMC4wMDk5NTMqUmVhY3Rpb24gVGltZSQkDQoNCmFuZCB0aGUgb2RkcyBvbiBiZWluZyBpbiB0aGUgdGhlNDAtNzAgYWdlIGdyb3VwIGdpdmVuIGEgcmVhY3Rpb24gdGltZSBhcmUNCiQkZV57XGV0YV97aX19OjEkJA0KV2l0aCBldGEgYXMgZGVzcmliZWQuDQoNCk5vdyB3ZSBjYW4gaW52ZXN0b2dhdGUgdGhlIHNpZ25pZmljYW5jZSBvZiB0aGlzIG1vZGVsIGJ5IGludmVzdGlnYXRpbmcgaWYgYSAgOTUlIENvbmZpZGVuY2UgaW50ZXJ2YWwgaGF2ZSB2YWx1ZXMgZWl0aGVyIHNpZGUgb2YgemVybw0KDQpgYGB7cn0NCkNJaW50ZXJjZXB0PC1nZXRDSSg0LjE1Njk4OSwxLjAxNDg0OSwgMTAwLCAwLjA1KQ0KQ0lzbG9wZTwtIGdldENJKCAwLjAwOTk1MiwwLjAwMjE0NSwgMTAwLCAwLjA1KQ0KDQpDSWludGVyY2VwdA0KQ0lzbG9wZQ0KYGBgDQpBcyB3ZSBzZWUgb2ZyIGVhY2ggb2YgdGhlIHZhbHVlcyBpbiB0aGUgQ0kgYXJlIHBvc2l0aXZlIHNvIHdlIGNhbiBzYXkgdGhhdCB0aGlzIG1vZGVsIGlzIHNpZ25pZmljYW50LiANCg0KRmluYWxseSBsZXRzIHBsb3QgdGhlIHJlZ3Jlc3Npb24NCmBgYHtyfQ0KICMgYXNzaWduICdzdXJ2aXZhbCcgdG8gdGhlc2UgMjAgaW5kaXZpZHVhbHMgbm9uLXJhbmRvbWx5Li4uIG1vc3QgbW9ydGFsaXR5IG9jY3VycyBhdCBzbWFsbGVyIGJvZHkgc2l6ZQ0KZGF0PWFzLmRhdGEuZnJhbWUoY2JpbmQoUmVhY3Rpb25UaW1lLEFnZUdyb3VwKSkgIyBzYXZlcyBkYXRhZnJhbWUgd2l0aCB0d28gY29sdW1uczogYm9keSBzaXplICYgc3Vydml2YWwNCmRhdCRBZ2VHcm91cD1kYXQkQWdlR3JvdXAtMSAjIGp1c3QgDQoNCnBsb3QoZGF0JFJlYWN0aW9uVGltZSxkYXQkQWdlR3JvdXAseGxhYj0iUmVhY3Rpb24gVGltZSIseWxhYj0iUHJvYmFiaWxpdHkgYWdlIGJldHdlZW4gNDAtNzAiLCBtYWluPSdMb2dpc3RpYyByZWdyZXNzaW9uIGZvciBBZ2UgR3JvdXAgViBSZWFjdGlvbiBUaW1lJykgIyBwbG90IHdpdGggYm9keSBzaXplIG9uIHgtYXhpcyBhbmQgc3Vydml2YWwgKDAgb3IgMSkgb24geS1heGlzDQoNCmN1cnZlKHByZWRpY3QobG9naXN0aWMsZGF0YS5mcmFtZShSZWFjdGlvblRpbWU9eCksdHlwZT0icmVzcCIpLGFkZD1UUlVFLCBjb2w9InJlZCIpICMgZHJhd3MgYSBjdXJ2ZSBiYXNlZCBvbiBwcmVkaWN0aW9uIGZyb20gbG9naXN0aWMgcmVncmVzc2lvbiBtb2RlbA0KDQprZXk8LWMoJ1ZhbHVlIG9mIFJlYWN0aW9uIFRpbWUgYW5kIEFnZSBncm91cCcsICdSZWdyZXNzaW9uIGxpbmUgb2YgcHJvYmFiaWxpdHknKQ0KY29sPC1jKCdibGFjaycsICdyZWQnKQ0KDQpsZWdlbmQoNjAwLCAwLjQsIGtleSwgZmlsbD1jb2wsY2V4PTAuNSApDQpgYGANCkFzIHdlIHNlZSBoZXJlIHRoZSBncmFwaCBpcyBvZiBhIHR5cGljYWwgbG9naXN0aWMgcmVncmVzc2lvbiBzaGFwZSBzbyB3ZSBjYW4gc3VtbWFyaXNlIHRoYXQgb3VyIG1vZGVscyBmaXRzIHRoZSBkYXRhIHF1aXRlIHdlbGwNCg0KKmIuQ29uZHVjdCBhIExvZ2lzdGljIHJlZ3Jlc3Npb24gYW5hbHlzaXMgb2YgYWdlIGdyb3VwIGFzIGEgZnVuY3Rpb24gb2YgaGVpZ2h0IGFuZCBpbnRlcnByZXQgdGhlIHJlc3VsdHMuKg0KDQpgYGB7cn0NCmxvZ2lzdGljPC0gZ2xtKGZvcm11bGE9QWdlR3JvdXB+SGVpZ2h0LCBmYW1pbHk9Ymlub21pYWwoImxvZ2l0IiksIGRhdGEgICkNCnN1bW1hcnkobG9naXN0aWMpDQpgYGANCkZyb20gdGhpcyB3ZSBzZWUgdGhhdCB0aGUgbG9naXN0aWMgcmVncmVzc2lvbiB0YWtlcyB0aGUgZm9ybSBvZg0KJCRQcihBZ2UgR3JvdXAgNDAtNzB8SGVpZ2h0KT0gXGZyYWN7ZV57XGV0YV97aX19fXsxK2Vee1xldGFfe2l9fSB9JCQNCg0Kd2hlcmUNCiQkXGV0YV97aX09NC4yNDgzMC0wLjAyMjA0KkhlaWdodCQkDQoNCmFuZCB0aGUgb2RkcyBvbiBiZWluZyBpbiB0aGUgdGhlNDAtNzAgYWdlIGdyb3VwIGdpdmVuIGEgcmVhY3Rpb24gdGltZSBhcmUNCg0KJCRlXntcZXRhX3tpfX06MSQkDQoNCldpdGggZXRhIGFzIGRlc3JpYmVkLg0KDQpOb3cgd2UgY2FuIGludmVzdG9nYXRlIHRoZSBzaWduaWZpY2FuY2Ugb2YgdGhpcyBtb2RlbCBieSBpbnZlc3RpZ2F0aW5nIGlmIGEgIDk1JSBDb25maWRlbmNlIGludGVydmFsIGhhdmUgdmFsdWVzIGVpdGhlciBzaWRlIG9mIHplcm8NCg0KYGBge3J9DQpDSWludGVyY2VwdDwtZ2V0Q0koIDQuMjQ4MzAsNC4wNTY3NyAsIDEwMCwgMC4wNSkNCkNJc2xvcGU8LSBnZXRDSSggLTAuMDIyMDQsMC4wMjQwMDUsIDEwMCwgMC4wNSkNCg0KQ0lpbnRlcmNlcHQNCkNJc2xvcGUNCmBgYA0KSW4gdGhpcyBjYXNlIHdlIHNlZSB0aGF0IHRoZSBDSSBjbGVhbHkgcGFzc2VzIG92ZXIgMCBpbiBib3RoIGNhc2VzIHNvIHdlIGNhbiBzYXkgdGhhdCB0aGUgbW9kZWwgaXMgbm90IHNpZ25pZmljYW50LiBXZSBjYW4gYWxzbyBwbG90IHRoaXMgcmVncmVzc2lvbiB0byBzZWUgd2hhdCBpdCB0ZWxscyB1cy4NCmBgYHtyfQ0KICMgYXNzaWduICdzdXJ2aXZhbCcgdG8gdGhlc2UgMjAgaW5kaXZpZHVhbHMgbm9uLXJhbmRvbWx5Li4uIG1vc3QgbW9ydGFsaXR5IG9jY3VycyBhdCBzbWFsbGVyIGJvZHkgc2l6ZQ0KZGF0PWFzLmRhdGEuZnJhbWUoY2JpbmQoSGVpZ2h0LEFnZUdyb3VwKSkgIyBzYXZlcyBkYXRhZnJhbWUgd2l0aCB0d28gY29sdW1uczogYm9keSBzaXplICYgc3Vydml2YWwNCmRhdCRBZ2VHcm91cD1kYXQkQWdlR3JvdXAtMSAjIGp1c3QgDQoNCnBsb3QoZGF0JEhlaWdodCxkYXQkQWdlR3JvdXAseGxhYj0iSGVpZ2h0Iix5bGFiPSJQcm9iYWJpbGl0eSBhZ2UgYmV0d2VlbiA0MC03MCIsIG1haW49J0xvZ2lzdGljIHJlZ3Jlc3Npb24gZm9yIEFnZSBHcm91cCBWIEhlaWdodCcpICMgcGxvdCB3aXRoIGJvZHkgc2l6ZSBvbiB4LWF4aXMgYW5kIHN1cnZpdmFsICgwIG9yIDEpIG9uIHktYXhpcw0KDQpjdXJ2ZShwcmVkaWN0KGxvZ2lzdGljLGRhdGEuZnJhbWUoSGVpZ2h0PXgpLHR5cGU9InJlc3AiKSxhZGQ9VFJVRSwgY29sPSJyZWQiKSAjIGRyYXdzIGEgY3VydmUgYmFzZWQgb24gcHJlZGljdGlvbiBmcm9tIGxvZ2lzdGljIHJlZ3Jlc3Npb24gbW9kZWwNCg0Ka2V5PC1jKCdWYWx1ZSBvZiBIZWlnaHQgYW5kIEFnZSBncm91cCcsICdSZWdyZXNzaW9uIGxpbmUgb2YgcHJvYmFiaWxpdHknKQ0KY29sPC1jKCdibGFjaycsICdyZWQnKQ0KDQpsZWdlbmQoMTgwLCAwLjQsIGtleSwgZmlsbD1jb2wsY2V4PTAuNSApDQpgYGANCg0KSGVyZSB3ZSBzZWUgdGhlIHJlZ3Jlc3Npb24gbGluZSBpcyBmbGF0dGVyIGFuZCBoYXMgbm8gcmVhbCB3YXkgdG8gcHJlZGljdCB0aGUgYWdlIGdyb3VwIGZyb20gdGhlIEhlaWdodCBnaXZlbiggYXMgd2UgYWxsdWRlZCB0byB3aXRoIHRoZSBjb25maWRlbmNlIGludGVydmFscyk=