Data exploration and Descriptive Statistics
captopril <- read_csv("https://raw.githubusercontent.com/GTPB/PSLS20/master/data/captopril.txt")
head(captopril)
# A tibble: 6 x 5
id SBPb DBPb SBPa DBPa
<dbl> <dbl> <dbl> <dbl> <dbl>
1 1 210 130 201 125
2 2 169 122 165 121
3 3 187 124 166 121
4 4 160 104 157 106
5 5 167 112 147 101
6 6 176 101 145 85
id SBPb DBPb SBPa
Min. : 1.0 Min. :146.0 Min. : 98.0 Min. :129
1st Qu.: 4.5 1st Qu.:163.5 1st Qu.:103.0 1st Qu.:146
Median : 8.0 Median :174.0 Median :112.0 Median :157
Mean : 8.0 Mean :176.9 Mean :112.3 Mean :158
3rd Qu.:11.5 3rd Qu.:192.5 3rd Qu.:121.5 3rd Qu.:168
Max. :15.0 Max. :210.0 Max. :130.0 Max. :201
DBPa
Min. : 82.0
1st Qu.: 98.0
Median :103.0
Mean :103.1
3rd Qu.:108.0
Max. :125.0
captoprilTidy <- captopril %>% gather(type,bp,-id)
captoprilTidy %>%
group_by(type) %>%
summarize_at("bp",list(mean=~mean(.,na.rm=TRUE),
sd=~sd(.,na.rm=TRUE),
n=function(x) x%>%is.na%>%`!`%>%sum)) %>%
mutate(se=sd/sqrt(n))
# A tibble: 4 x 5
type mean sd n se
<chr> <dbl> <dbl> <int> <dbl>
1 DBPa 103. 12.6 15 3.24
2 DBPb 112. 10.5 15 2.70
3 SBPa 158 20.0 15 5.16
4 SBPb 177. 20.6 15 5.31
captoprilTidy %>%
group_by(type) %>%
summarize_at("bp",list(mean=~mean(.,na.rm=TRUE),
sd=~sd(.,na.rm=TRUE),
n=function(x) x%>%is.na%>%`!`%>%sum)) %>%
mutate(se=sd/sqrt(n)) %>%
ggplot(aes(x=type,y=mean)) +
geom_bar(stat="identity") +
geom_errorbar(aes(ymin=mean-se, ymax=mean+se),width=.2) +
ylim(0,210) +
ylab("blood pressure (mmHg)")
- This figure is not informative! It does not show the raw data.
captoprilTidy %>%
ggplot(aes(x=type,y=bp)) +
geom_boxplot(outlier.shape=NA) +
geom_point(position="jitter") +
ylim(0,210)
We see that a lot of the space that was taken by the barplot does not contain data!
captoprilTidy %>%
ggplot(aes(x=type,y=bp)) +
geom_boxplot(outlier.shape=NA) +
geom_point(position="jitter")
This plot would have been informative if the data was gathered on different individuals.
However, the blood pressures are measured op the same subject!
We will make a plot by filtering the systolic blood pressures
captoprilTidy %>%
filter(type%in%c("SBPa","SBPb")) %>%
mutate(type=factor(type,levels=c("SBPb","SBPa"))) %>%
ggplot(aes(x=type,y=bp)) +
geom_line(aes(group = id)) +
geom_point()
- We have paired data. So we might estimate the effect of the treatment directly by comparing the blood pressure after treatment to the blood pressure before the treatment.
captopril$deltaSBP<-captopril$SBPa-captopril$SBPb
captopril%>%
ggplot(aes(x="Systolic blood pressure",y=deltaSBP)) +
geom_boxplot(outlier.shape=NA) +
geom_point(position="jitter")+
ylab("Difference (mm mercury)") +
xlab("")
captopril %>%
summarize_at("deltaSBP",list(mean=~mean(.,na.rm=TRUE),
sd=~sd(.,na.rm=TRUE),
n=function(x) x%>%is.na%>%`!`%>%sum)) %>%
mutate(se=sd/sqrt(n))
# A tibble: 1 x 4
mean sd n se
<dbl> <dbl> <int> <dbl>
1 -18.9 9.03 15 2.33
captopril%>%
ggplot(aes(sample=deltaSBP)) +
stat_qq() +
stat_qq_line()
The systolic blood pressure differences are approximately normally distributed.
Interval estimators
\(\bar X\) varies around \(\mu\)
Here we will develop an interval around \(\bar X\) that will contain the value of \(\mu\) with a probability of 95% for a random sample.
We first assume \(\sigma^2\) to be known and we will later relax this assumption.
Normally distributed data with known variance
\(X\sim N(\mu,\sigma^2) \rightarrow \bar X\sim N\left(\mu,\frac{\sigma^2}{n}\right)\)
95% reference-interval for sample mean
\[\begin{equation*}
\left[\mu - 1.96 \frac{\sigma}{\sqrt{n}},\mu + 1.96 \frac{\sigma}{\sqrt{n}}%
\right]
\end{equation*}\]
The interval contains the sample mean of a random sample with a probability of 95%.
We can not calculate it because \(\mu\) is unknown.
- Estimate \(\mu\) by \(\bar X\).
\[\begin{equation*}
\left[\bar X - 1.96 \frac{\sigma}{\sqrt{n}},\bar X + 1.96 \frac{\sigma}{\sqrt{n}}\right]
\end{equation*}\]
- More useful interpretation:
Rewrite \(\mu - 1.96 \ \sigma/\sqrt{n} < \bar{X}\) as \(\mu < \bar{X} + 1.96 \ \sigma/\sqrt{n}\).
So that we can write
\[\begin{eqnarray*}
95\% &=& P( \mu - 1.96 \ \sigma/\sqrt{n} < \bar{X} < \mu + 1.96 \ \sigma/\sqrt{n} ) \\
&=&P( \bar{X} - 1.96 \ \sigma/\sqrt{n} < \mu < \bar{X} + 1.96 \ \sigma/\sqrt{n} )
\end{eqnarray*}\]
Definition of 95% confidence interval on mean For a random sample, the interval
\[\begin{equation}
[\bar{X} - 1.96 \ \sigma/\sqrt{n} , \bar{X} + 1.96 \ \sigma/\sqrt{n} ],
\end{equation}\]
contains the population mean \(\mu\) with a probability of 95%.
The probability that the CI for a random sample contains the population parameter \(\mu\), i.e. 95%, is also referred to as the confidence level.
Note, that the lower and upper limit of the interval are also random variables that vary from sample to sample. Different samples indeed result in different confidence intervals because they are based on different observation.
So they are stochastic intervals
95% of the samples will produce a 95% confidence interval that will contain the population mean \(\mu\). The remaining 5% will produce intervals that do not contain the population mean.
Based on one interval you cannot conclude that it contains the real population parameter, because its value is unknown.
Generally the standard deviation is unknown and has to be estimated e.g. by \(S\)
- For large \(n\) \([\bar{X} - 1.96 \ s/\sqrt{n} , \bar{X} + 1.96 \ s/\sqrt{n} ]\) will contain the population mean with a probability of approximately 95%.
NHANES log2 cholesterol example
One sample
samp50<-sample(fem$DirectChol,50)
ll<-mean(samp50 %>% log2) - 1.96*sd(samp50 %>% log2)/sqrt(50)
ul<-mean(samp50 %>% log2) + 1.96*sd(samp50 %>% log2)/sqrt(50)
popMean<-mean(fem$DirectChol%>%log2)
c(ll=ll,ul=ul,popMean=popMean)
ll ul popMean
0.4364753 0.6350546 0.5142563
Repeated sampling
res$ll<-res$mean-1.96*res$se
res$ul<-res$mean+1.96*res$se
mu<-fem$DirectChol%>%log2%>%mean
res$inside<-res$ll<=mu & mu<=res$ul
res$n <- as.factor(res$n)
res %>%
group_by(n) %>%
summarize(coverage=mean(inside)) %>%
spread(n,coverage)
# A tibble: 1 x 3
`10` `50` `100`
<dbl> <dbl> <dbl>
1 0.928 0.938 0.954
Note, that the coverage in the samples with 10 observations is too low because we do not account for the uncertainty in the estimation of the standard deviation.
If we look to the first 20 intervals, 2 out of 20 do not contain the population mean.
res %>%
filter(n==10) %>%
slice(1:20) %>%
ggplot(aes(x=sample,y=mean,color=inside)) +
geom_point() +
geom_errorbar(aes(ymin=mean-1.96*se,ymax=mean+1.96*se))+
geom_hline(yintercept = fem$DirectChol%>% log2 %>% mean) +
ggtitle("20 CI for N=10") +
ylim(range(fem$DirectChol %>% log2))
- For large sample sizes (100) the coverage is fine because we can estimate the standard deviation with a relative high precision.
res %>%
filter(n==50) %>%
slice(1:20) %>%
ggplot(aes(x=sample,y=mean,color=inside)) +
geom_point() +
geom_errorbar(aes(ymin=mean-1.96*se,ymax=mean+1.96*se))+
geom_hline(yintercept = fem$DirectChol%>% log2 %>% mean) +
ggtitle("20 CI for N=50") +
ylim(range(fem$DirectChol %>% log2))
res %>%
filter(n==100) %>%
slice(1:20) %>%
ggplot(aes(x=sample,y=mean,color=inside)) +
geom_point() +
geom_errorbar(aes(ymin=mean-1.96*se,ymax=mean+1.96*se))+
geom_hline(yintercept = fem$DirectChol%>% log2 %>% mean) +
ggtitle("20 CI for N=100") +
ylim(range(fem$DirectChol %>% log2))
- What have you observed for the interval width?
Other confidence levels
We can replace the \(z_{2.5\%}=1.96\) by another quantile of the normal distribution $z_{/2} to obtain an interval with another confidence level \(1-\alpha\).
Confidence intervals are not only used for the mean but also for other population parameters.
Unknown variance
In real examples \(\sigma\) is unknown and estimated based on the sample using the sample standard deviation \(S\).
The previous intervals were a bit to small because they did not account for the uncertainty on the estimation of \(S\).
When \(n\) is large, \(S\) is close to \(\sigma\).
- Hence, \({(\bar{X} - \mu)}/{(S/\sqrt{n}) }\) is approximately standard normal and
\[\begin{equation*}
\left[\bar{X} - z_{\alpha/2} \ \frac{S}{\sqrt{n}} , \bar{X} + z_{\alpha/2} \
\frac{S}{\sqrt{n}}\right]
\end{equation*}\]
is an approximate \((1- \alpha)100\%\) CI for \(\mu\).
For small samples this no longer holds (e.g. n=10)
The estimation of \(S\) introduces additional uncertainty in the standardized value \({(\bar{X} - \mu)}/{(S/\sqrt{n})}\). Its distribution
is still symmetric but has heavier tails that the normal distribution.
it depends on \(n\) how much heavier the tails are
is a (Student) \(t\)-distribution with \(n-1\) degrees of freedom.
T-distribution
More formally: Let \(X_1, X_2, ..., X_n\) be an independent random sample from a Normal distribution \(N(\mu, \sigma^2)\), then \((\bar{X} - \mu)/(S/\sqrt{n})\) follows a \(t\)-distribution with \(n-1\) degrees of freedom.
The density of a t-distribution can be calculated in R using the function dt
. It has arguments x
for the quantile and df
for the degrees of freedom.
grid <- seq(-5,5,.1)
densDist<-cbind(grid,dnorm(grid), sapply(c(2,5,10),dt,x=grid))
colnames(densDist)<-c("x","normal",paste0("t",c(2,5,10)))
densDist %>% as.data.frame %>% gather(dist,dens,-x) %>%
ggplot(aes(x=x,y=dens,color=dist)) +
geom_line() +
ylab("Density")
t-distributions have heavier tails then the normal distribution \(\rightarrow\) larger quantiles so broader intervals for the same confidence level.
This captures the additional uncertainty for estimating \(S\).
If \(n \rightarrow \infty\) then \(t(df) \rightarrow N(0,1)\)
quantiles of the \(t\)-distribution can be calculated in R using qt
. e.g. 95%, 97.5%, 99.5% quantile for a t-distribution with 14 degrees of freedom:
[1] 2.144787
qt(c(.95,.975,.995),df=14)
[1] 1.761310 2.144787 2.976843
These quantiles can be used to calculate 90%, 95% and 99% CI.
97.5% quantile2.14 of a t-distribution with \(n-1=14\) degrees of freedom is indeed larger than that of a standard Normal distribution 1.96.
Confidence interval based on the t-distribution
The \(100\% (1-\alpha)\) CI for the mean \(\mu\) of a Normal distributed random variable \(X\) with unknown variance is
\[\begin{equation*}
\left[\bar{X} - t_{n-1, \alpha/2} \frac{s}{\sqrt{n}} , \bar{X} + t_{n-1,
\alpha/2} \frac{s}{\sqrt{n}}\right]
\end{equation*}\]
- We simply replace the \((1-\alpha/2)100\%\) quantile of the Normal distribution by that of the t-distribution with \(n-1\) degrees of freedom.
Captopril example
95% CI for the average blood pressure change becomes
mean(captopril$deltaSBP) - qt(.975,df=14)*sd(captopril$deltaSBP)/sqrt(15)
[1] -23.93258
mean(captopril$deltaSBP) + qt(.975,df=14)*sd(captopril$deltaSBP)/sqrt(15)
[1] -13.93409
The 99% CI is given by
mean(captopril$deltaSBP) - qt(.995,df=14)*sd(captopril$deltaSBP)/sqrt(15)
[1] -25.87201
mean(captopril$deltaSBP) + qt(.995,df=14)*sd(captopril$deltaSBP)/sqrt(15)
[1] -11.99466
Note, that zero is outside the interval and that the entire interval is negative indicating that there is on average a large effect by administrating captopril on the blood pressure of patients with hypertension.
Interpretation of the confidence interval
- We will revisit the results for sampling log2 cholesterol levels from the large NHANES study. We first focus on the repeated experiments with sample size 10.
res$n<-as.character(res$n) %>% as.double(res$n)
res$ll<-res$mean-qt(0.975,df=res$n-1)*res$se
res$ul<-res$mean+qt(0.975,df=res$n-1)*res$se
mu<-fem$DirectChol%>%log2%>%mean
res$inside<-res$ll<=mu & mu<=res$ul
res$n <- as.factor(res$n)
res %>% group_by(n) %>% summarize(coverage=mean(inside)) %>% spread(n,coverage)
# A tibble: 1 x 3
`10` `50` `100`
<dbl> <dbl> <dbl>
1 0.956 0.944 0.957
We observe that all the coverages of the intervals are now controlled at their nominal 95% confidence level.
res %>%
filter(n==10) %>%
slice(1:20) %>%
ggplot(aes(x=sample,y=mean,color=inside)) +
geom_point() +
geom_errorbar(aes(ymin=mean-qt(0.975,df=9)*se,ymax=mean+qt(0.975,df=9)*se))+
geom_hline(yintercept = fem$DirectChol%>% log2 %>% mean) +
ggtitle("20 CI for N=10") +
ylim(range(fem$DirectChol %>% log2))
Reporting?
Always report the uncertainty on the results!
Conclusions based on a point estimate can be very misleading.
Upon a statistical analysis we therefore always report confidence intervals
They are small enough to be informative but almost never misleading
They form a good trade-off between statistical significance and biological relevance.
We conclude that the population parameter lays in the interval and know that this statement holds with a probability of 95% for random samples.
Captopril example
We conclude that the blood pressure decreases on average with 18.9mmHg upon administering captopril (95% CI [-23.9,-13.9]mmHg).
Based on these results it is obvious that the treatment causes a strong blood pressure drop for patients with hypertension.
Hypothesis tests
Captopril Example:
Researchers want to assess if the drug captopril decreases the blood pressure for patients with hypertension.
Is there no/an effect of administering captopril on the systolic blood pressure?
It is not obvious to draw such conclusions based on a small sample
It is uncertain if we can generalized the observations in the sample towards the population!
Is the apparent beneficial effect systematic or random?
captoprilTidy %>%
filter(type%in%c("SBPa","SBPb")) %>%
mutate(type=factor(type,levels=c("SBPb","SBPa")))%>%
ggplot(aes(x=type,y=bp)) +
geom_line(aes(group = id)) +
geom_point()
captopril$deltaSBP<-captopril$SBPa-captopril$SBPb
captopril%>%
ggplot(aes(x="Systolic blood pressure",y=deltaSBP)) +
geom_boxplot(outlier.shape=NA) +
geom_point(position="jitter")+
ylab("Difference (mm mercury)") +
xlab("")
- The average blood pressure difference \(\bar X\) is a natural basis to base our decision on.
\[\bar x\text{=-18.93 (s=9.03, SE=2.33)}\]
It is not enough that \(\bar{x}< 0\) to conclude that the systolic blood pressure is on average lower upon administrating captopril at the level of the entire population.
To generalize the effect we observe in the sample to the population it has to be sufficiently large.
But, how large?
Hypothesis tests
Captopril
Based on the sample we cannot prove that there is an effect of administering captopril (\(H_1\) , alternative hypothesis).
We therefore suppose that there is no effect of captopril.
We refer to this as the null hypothesis \(H_0\).
Falsify (“try to reject”) the \(H_0\).
How likely is it to observe an effect that is at least as large as what we have seen in the sample in a random sample when \(H_0\) is true?
Permutation test
Under \(H_0\) the blood pressure measurements before and after administering captopril are two base line blood pressure measurements for a patient
Under H\(_0\) we can shuffle (permute) the blood pressure measurements for each patient.
captoprilSamp<-captopril
perm<-sample(c(FALSE,TRUE),15,replace=TRUE)
captoprilSamp$SBPa[perm]<-captopril$SBPb[perm]
captoprilSamp$SBPb[perm]<-captopril$SBPa[perm]
captoprilSamp$deltaSBP <- captoprilSamp$SBPa-captoprilSamp$SBPb
captoprilSamp %>%
gather(type,bp,-id) %>%
filter(type%in%c("SBPa","SBPb")) %>%
mutate(type=factor(type,levels=c("SBPb","SBPa")))%>%
ggplot(aes(x=type,y=bp)) +
geom_line(aes(group = id)) +
geom_point()
data.frame(deltaSBP=c(captopril$deltaSBP,captoprilSamp$deltaSBP),shuffled=rep(c(FALSE,TRUE),each=15)) %>%
ggplot(aes(x=shuffled,y=deltaSBP)) +
geom_boxplot(outlier.shape=NA) +
geom_point(position="jitter")+
stat_summary(fun.y=mean, geom="point", shape=19, size=3, color="red", fill="red") +
ylab("Difference (mm mercury)")
And we permute again
captoprilSamp<-captopril
perm<-sample(c(FALSE,TRUE),15,replace=TRUE)
captoprilSamp$SBPa[perm]<-captopril$SBPb[perm]
captoprilSamp$SBPb[perm]<-captopril$SBPa[perm]
captoprilSamp$deltaSBP <- captoprilSamp$SBPa-captoprilSamp$SBPb
captoprilSamp %>%
gather(type,bp,-id) %>%
filter(type%in%c("SBPa","SBPb")) %>%
mutate(type=factor(type,levels=c("SBPb","SBPa")))%>%
ggplot(aes(x=type,y=bp)) +
geom_line(aes(group = id)) +
geom_point()
data.frame(deltaSBP=c(captopril$deltaSBP,captoprilSamp$deltaSBP),shuffled=rep(c(FALSE,TRUE),each=15)) %>%
ggplot(aes(x=shuffled,y=deltaSBP)) +
geom_boxplot(outlier.shape=NA) +
geom_point(position="jitter")+
stat_summary(fun.y=mean, geom="point", shape=19, size=3, color="red", fill="red") +
ylab("Difference (mm mercury)")
- We will do this 10000 times and we will keep track of the mean.
- We basically only have to swap the signs of the observed blood pressure differences \(x\) when we shuffle.
#generate a matrix with 15 rows and 10000 columns which consist of -1 and 1
permH<-sample(c(-1,1),150000,replace=TRUE)
dim(permH)<-c(15,10000)
#calculate the means for the permuted data
muPerm<-colMeans(permH*captopril$deltaSBP)
muPerm %>%
as.data.frame %>%
ggplot(aes(x=.)) +
geom_histogram() +
geom_vline(xintercept=mean(captopril$deltaSBP),col="blue")
We observe that not one of the means that were obtained under \(H_0\) (by permutation) were as extreme as the sample mean we observed in the captopril study.
So the probability to observe a blood pressure drop that is larger then the one in the captopril study in a random sample generated under the null hypothesis is smaller then 1 out of 10000.
So we have strong evidence that \(H_0\) is incorrect and we thus we reject it and conclude \(H_1\): There is an effect of administering captopril on the blood pressure of patients with hypertension.
Pivot
In practice we always use statistics that balance the effect size (average difference) to the noise (standard error)
When we falsify the null hypothesis, we standardize the mean around \(\mu_0=0\) the mean under \(H_0\)
\[t=\frac{\bar X-\mu_0}{se_{\bar X}}\]
- for the captopril example this becomes: \[\frac{-18.93-0}{2.33}=-8.12\]
We now determine the null distribution of test statistic t with permutation.
deltaPerms<-permH*captopril$deltaSBP
tPerm<-colMeans(deltaPerms)/(apply(deltaPerms,2,sd)/sqrt(15))
tOrig<-mean(captopril$deltaSBP)/sd(captopril$deltaSBP)*sqrt(15)
tPermPlot<- tPerm %>%
as.data.frame %>% ggplot(aes(x=.)) +
geom_histogram(aes(y=..density.., fill=..count..)) +
geom_vline(xintercept=tOrig,col="blue")
tPermPlot
- Again, none of the permutations gives a t-statistic as extreme as the one observed in the captopril study.
When there is no effect of captopril it is nearly impossible to obtain a test statistic as extreme as the one that was observed ( t=-8.12).
The probability to observe a larger blood pressure drop then the one we observed in our sample in a random sample under \(H_0\) is smaller 1/10000.
We refer to this probability with the p-value.
It measures the strength of the evidence against the null: the smaller the p-value the more evidence we have that the null is not true.
The distribution has a nice bell shape.
How do we decide?
When is the p-value sufficiently small to conclude that there is strong evidence against the null hypothesis?
Permutation tests are computationally demanding
Can we assess how extreme the blood pressure drop was without permutation?
We know that the blood pressure differences are approximately Normally distributed, so
\[t=\frac{\bar X - \mu}{se_{\bar X}}\]
follows a t-distribution (with 14 df for the captopril example).
- Under H\(_0\) \(\mu=0\) and \[t=\frac{\bar X-0}{se_{\bar X}}\sim f_{T,14}\]
tPermPlot +
stat_function(fun=dt,color="red",args=list(df=14))
Note, the permutation null distribution indeed corresponds to a t-distribution with 14 degrees of freedom.
So we can conduct the statistical test using statistical modelling of the data.
We need to make assumptions for this, which we verify in the data exploration phase.
Hypotheses
Click to see more formal details
Translate the research question to a null hypothesis (\(H_0\)) and an alternative hypothesis (\(H_1\))
First the we need to translate the research question to a parameterized statistical model.
From the experimental design it follows that \[X_1,...,X_n \text{ i.i.d } f(X),\] with \(f(X)\) the density function of blood pressure differences.
- Simplify: assume that \(f(X)\) is known except for an finite dimensional set of parameters \(\mathbf{\theta}\) that still has to be estimated (parametric statistic model).
Captopril example
Click to see more formal details
\(X \sim N(\mu,\sigma^2)\) with \(\mathbf{\theta}=(\mu,\sigma^2)\), the mean \(\mu\) and variance \(\sigma^2\).
The research question is now translated in terms of the average blood pressure drop: \(\mu=E_f[X]\).
The alternative hypothesis is formulated in terms of a parameter of \(f(X)\) and has to express what the researchers want to prove with the study.
- Here: \[H_1: \mu<0.\] On average the blood pressure of patients with hypertension decreases upon administering captopril.
The null hypothesis generally expresses a null condition, i.e. when notting exceptional happens.
Researchers typically aim to prove via empirical research that observing the data under the null is highly unlikely so that they can reject the null hypothesis: Falsification principle.
The null hypothesis is typically expressed with the same model parameter as the one used for \(H_1\).
Here: \[H_0 : \mu=0\] i.e. on average the systolic blood pressure remains unchanged upon administering captopril.
Test-statistic
Click to see more formal details
Once the population, the parameters, and, \(H_0\) and \(H_1\) are determined the concept of hypothesis testing is as follows:
Construct a test statistic so that it
- measures evidence in the sample,
- against the null hypothesis, and
- in favour of the alternative hypothesis.
A test statistic thus has to be a function of the observations in the sample.
Captopril example
Click to see more formal details
\[T=\frac{\bar{X}-\mu_0}{\text{SE}_{\bar X}}\] With \(\mu_0=0\) under \(H_0\)
Again
If \(H_0\) holds there is no effect of captopril on the blood pressure in the population and then we expect test statistic \(T\) close to 0.
If \(H_1\) is true we expect \(T<0\).
In the captopril example we observe \(t=(-18.93-0)/2.33=-8.12\).
Is \(t = -8.12\) large enough in absolute value to conclude that \(\mu < 0\) and with which confidence can we make this conclusion?
We known that t follows a t-distribution with 14 d.f. under \(H_0\)
p-value
The p-value is the probability to balance between \(H_0\) and \(H_1\).
The way how we calculate it is context dependent
- For the captopril example we have \[
p = P\left[T \leq t \mid H_0\right] = \text{P}_0\left[T\leq t\right],
\] with the index “0” in \(\text{P}_0\left[.\right]\) indicates that the probability is calculated under \(H_0\).
It gives the probability to observe a test statistic \(T\) lower or equal to the value observed in the current sample in a random sample under \(H_0\) - i.e. a test statistic \(T\) in the random sample under \(H_0\) with a value that is more extreme, more in the direction of \(H_1\) then the one observed in the current sample.
Captopril example
Click to see more formal details
- The \(p\)-value for the captopril example is calculated as follows \[p= \text{P}_0\left[T\leq -8.12\right]=F_t(-8.12;14) = 0.6\ 10^{-6}.\]
with \(F_t(;14)\) the cumulative distribution function of a t-distribution with 14 degrees of freedom:
\[F_t(x;14)=\int\limits_{-\infty}^{x} f_t(x;14).\]
and \(f_t(.;14)\) the density function of the t-distribution.
We calculate this probability in R with pt(x,df)
- the value of the observed test statistic
x
en
- the number of degrees of freedom of the t-distribution
df
.
pt(x,df)
calculates the probability to observe a value smaller or equal to x when we would draw a random sample from a t-distribution with df degrees of freedom.
n <- length(captopril$deltaSBP)
stat<-(mean(captopril$deltaSBP)-0)/(sd(captopril$deltaSBP)/sqrt(n))
stat
[1] -8.122816
[1] 5.731936e-07
In practice we will not calculate the test ourself, but we will use the function t.test:
t.test(captopril$deltaSBP, alternative = "less")
One Sample t-test
data: captopril$deltaSBP
t = -8.1228, df = 14, p-value = 5.732e-07
alternative hypothesis: true mean is less than 0
95 percent confidence interval:
-Inf -14.82793
sample estimates:
mean of x
-18.93333
Note, that we need to specify the argument alternative="less"
so that the p-value would be calculated in the left tail.
The function also gives a one-sided interval because we test in one direction.
Definition of the p-value
The p-value (also referred to as the observed significance level) is the probability to observe a test statistic in a random sample under the null hypothesis that is as or more extreme then the test statistic observed in the current sample.
The smaller the probability the more evidence against \(H_0\).
Note, that the p-value is not the probability that null hypothesis is true!
The word “extreme” indicates on the direction in which the test statistic is more likely under the alternative hypothesis.
In the example \(H_1: \mu < 0\) and we thus expect very negative values for \(t\) under \(H_1\).
From the definition small \(p\)-values indicate that observed test statistic is unlikely under the assumption that \(H_0\) is correct.
Thus a small value of \(p\)-value means that we have to reject \(H_0\) in favour of \(H_1\).
The threshold that we use to compare the \(p\)-value with is referred to as the significance level and is denoted with \(\alpha\).
A statistical test conducted on the \(\alpha\) significance level is also referred to as a level-\(\alpha\) test.
A test result is statistically significant if \(p<\alpha\)
\(\alpha\) is commonly set at 5%.
The smaller the p-value the more `significant’ the test result deviates from what can be expected under \(H_0\).
It summarizes the evidence against the null.
\[\begin{array}{cl}>0.10 & \text{ non significant (no evidence)}\\0.05-0.10 & \text{ marginal significant, weak evidence (do not use this yourself)}\\0.01-0.05 & \text{ significant}\\0.001-0.01 & \text{strongly significant}\\<0.001 & \text{ extremely significant}\end{array}\]
Critical value
Decision Errors
The decision to accept or reject \(H_0\) is made based on a single sample. A wrong decision could have been made.
|
Reality
|
Conclusion
|
H0
|
H1
|
Accept H0
|
OK
|
Type II (\(\beta\))
|
Reject H0
|
Type I (\(\alpha\))
|
OK
|
- Type I error, \(\alpha\): wrongly reject the null hypothesis (false positive)
Type II error, \(\beta\): wrongly accept the null hypothesis
Decision is also stochastic! See first chapter of the course
Captopril Example
\(H_0\): administering captopril has no effect on the systolic blood pressure
\(H_1\): administering captopril an average leads to a decrease in blood pressure
- Type I error: there is on average no blood pressure drop upon administering captopril, but we conclude that there is an effect of captopril.
Type II error: there is on average a blood pressure drop upon administering captopril, but it is not picked up by the statistical test.
Type I error is controlled
The type I error is controlled by the construction of the statistical test.
\[\text{P}\left[\text{type I error}\right]=\text{P}\left[\text{reject }H_0 \mid H_0\right] = \text{P}_0\left[T<t_{n-1;1-\alpha}\right]=\alpha \]
The significance-level \(\alpha\) is the probability to make a type I error.
The statistical test ensures that the probability on a type I error is controlled at the significance level \(\alpha\).
The probability to correctly accept \(H_0\) is \(1-\alpha\).
We can show that the p-value under \(H_0\) is uniform distributed.
So statistical hypothesis testing leads to a uniform decision strategy.
We will illustrate this in a simulation study
- n=15
- \(\mu=0\) mmHg
- \(\sigma =9\) mmHg
- number of simulations 1000
nsim <- 10000
n <- 15
sigma <- 9
mu <- 0
mu0 <- 0
alpha=0.05
#simulate nsim samples of size n
deltaSim <- matrix(rnorm(n*nsim,mu,sigma),nrow=n,ncol=nsim)
pSim <- apply(deltaSim,2,function(x,mu,alternative) t.test(x,mu=mu,alternative=alternative)$p.value,mu=mu0,alternative="less")
mean(pSim<alpha)
[1] 0.0565
pSim %>%
as.data.frame %>%
ggplot(aes(x=.)) +
geom_histogram() +
xlim(0,1)
- The type I error is indeed about 0.05
- The p-values are uniform
Type II error
\[H_1(\delta): \mu=0-\delta \text{ for }\delta>0.\]
e.g. a blood pressure difference of 2 mmHg
1-type II is also referred to as the power. It is the probability to pick up the alternative.
It is not guaranteed by the design of the test
It depends on the experimental design of the study
nsim <- 10000
n <- 15
sigma <- 9
mu <- -2
mu0 <- 0
alpha=0.05
#simulate nsim samples of size n
deltaSim <- matrix(rnorm(n*nsim,mu,sigma),nrow=n,ncol=nsim)
pSim <- apply(deltaSim,2,function(x,mu,alternative) t.test(x,mu=mu,alternative=alternative)$p.value,mu=mu0,alternative="less")
mean(pSim<alpha)
[1] 0.2079
pSim %>%
as.data.frame %>%
ggplot(aes(x=.)) +
geom_histogram() +
xlim(0,1)
- We observe that a power of 0.2079 or a type II error of 0.7921.
- When we increase the sample size
nsim <- 10000
n <- 30
sigma <- 9
mu <- -2
mu0 <- 0
alpha=0.05
#simulate nsim samples of size n
deltaSim <- matrix(rnorm(n*nsim,mu,sigma),nrow=n,ncol=nsim)
pSim <- apply(deltaSim,2,function(x,mu,alternative) t.test(x,mu=mu,alternative=alternative)$p.value,mu=mu0,alternative="less")
mean(pSim<alpha)
[1] 0.3264
pSim %>%
as.data.frame %>%
ggplot(aes(x=.)) +
geom_histogram() +
xlim(0,1)
- Increasing the sample size leads to a higher power.
- Still the power to pick up such a small blood pressure drop remains very low.
- A drop of 2 mmHg is also not relevant for drug companies.
Interpretation
Suppose that given a particular sample \(p<\alpha\), i.e. reject \(H_0\)
On the other hand, when \(p\geq\alpha\) and we do not reject \(H_0\) we also have two options:
- Correct decision,
- or we made a type II error.
The probability on a type II error (\(\beta\)) is not controlled at a specific value.
Statistical test is constructed to only control the probability on a type I error at \(\alpha\).
To be scientifically correct we have to take a pessimistic attitude and we have to admit that \(\beta\) can be large (i.e. a small power to detect the alternative).
Hence,
Conclusions captopril example
The test we have performed is referred to as
the one sample t-test on the difference or
a paired t-test. Indeed we dispose of paired observations for each patient!
The test is done one-sided because we test against the alternative of a blood pressure drop.
Both tests (one sample t-test on the difference and paired t-test) give the same results:
t.test(captopril$deltaSBP,alternative="less")
One Sample t-test
data: captopril$deltaSBP
t = -8.1228, df = 14, p-value = 5.732e-07
alternative hypothesis: true mean is less than 0
95 percent confidence interval:
-Inf -14.82793
sample estimates:
mean of x
-18.93333
t.test(captopril$SBPa,captopril$SBPb,paired=TRUE,alternative="less")
Paired t-test
data: captopril$SBPa and captopril$SBPb
t = -8.1228, df = 14, p-value = 5.732e-07
alternative hypothesis: true difference in means is less than 0
95 percent confidence interval:
-Inf -14.82793
sample estimates:
mean of the differences
-18.93333
Conclusion
There is on average an extremely significant blood pressure drop upon administering captopril to patients with hypertension. The systolic blood pressure decreases on average with 18.9 mmHg upon the treatment with captopril (95% CI [\(-\infty,-14.82\)] mmHg).
Note that
A one-sided interval is reported because we are only interested in a blood pressure drop.
Because of the pre-test/post-test design we cannot distinguish between the effect of the treatment and a placebo effect. There was no good control! The lack of a good control typically occurs in pre-test/post-test designs. How could we have improved the design?
One-sided or two-side testing?
De test in the captopril example was a one-sided test. We only aim to detect if the captopril treatment on average reduces the blood pressure.
Suppose that we defined the blood pressure difference as \(X_{i}^\prime=Y_{i}^\text{before}-Y_{i}^\text{after}\)
Now, a positive value indicates a blood pressure drop
The average change in blood pressure is now denote as \(\mu^\prime=\text{E}[X^\prime]\).
So now we should use a one-sided test to assess \(H_0: \mu^\prime=0\) against \(H_1: \mu^\prime>0\).
p-value now becomes: \[p=\text{P}_0\left[T\geq t\right].\]
Analysis based on \(X^\prime\): Argument alternative="greater"
so that we use \(H_1: \mu^\prime>0\):
t.test(captopril$SBPb-captopril$SBPa,alternative="greater")
One Sample t-test
data: captopril$SBPb - captopril$SBPa
t = 8.1228, df = 14, p-value = 5.732e-07
alternative hypothesis: true mean is greater than 0
95 percent confidence interval:
14.82793 Inf
sample estimates:
mean of x
18.93333
Of course we obtain the same results. Only the sign is swapped.
Two-sided test
Suppose that researchers wanted to assess the mode of action of the new drug captopril in the design phase and suppose that healthy subjects were used in an early phase of the drug development.
In this case it would have been interesting to observe blood pressure drops as well as gains.
Then we would require a two-sided test strategy
\[H_0: \mu=0\] against the alternative hypothesis
\[H_1: \mu\neq0,\]
so that the mean under the alternative is different from zero.
It can be positive as well as negative changes and we did not know upfront in which direction the real mean will deviate from \(H_1\).
We can conduct a two-sided test on the \(\alpha=5\%\) significance level by
The argument alternative
of the t.test
function is by default alternative="two.sided"
.
t.test(captopril$deltaSBP)
One Sample t-test
data: captopril$deltaSBP
t = -8.1228, df = 14, p-value = 1.146e-06
alternative hypothesis: true mean is not equal to 0
95 percent confidence interval:
-23.93258 -13.93409
sample estimates:
mean of x
-18.93333
- We still obtain an extremely significant result.
- The p-value is double as large because we test two-sided.
Indeed
\[p=P_0[T \leq -\vert t \vert] + P_0[T \geq \vert t \vert] = P_0[\vert T \vert \geq \vert t \vert] = 2 \times P_0[T \geq \vert t \vert]\]
- We also obtain a two-sided confidence interval
One-sided or two-sided test?
With a one-sided test we can more easily reject \(H_0\) on condition that \(H_1\) is true than with a two-sided test.
All information is used to test into one direction
The decision to test one-sided has to be done in the design phase before the experiment is conducted
Even if we have strong a priori presumptions, we are not entirely sure otherwise we would have no reason to do the research.
If we propose a one-sided test in the design phase and we observe a result in the opposite direction that would be statistically significant we can not draw conclusions from the experiment.
In the design phase we have excluded this result because it is so unexpected that it has to be a false positive.
Hence, one-sided tests are not recommended.
A two-sided test can always be defended and allows you to detect any deviation of \(H_0\) and is highly recommended.
It is never allowed to change a two-sided test into a one-sided test based on what has been observed in the sample! Otherwise the type I error of the test strategy is not correctly controlled.
We illustrate this in the simulation study below:
- correct two-sided test and
- one-sided test with its sign based on what was observed in the sample.
mu <- 0
sigma <- 9.0
nSim <- 1000
alpha <- 0.05
n <- 15
pvalsCor <- pvalsInCor<-array(0,nSim)
for (i in 1:nSim)
{
x <- rnorm(n,mean=mu,sd=sigma)
pvalsCor[i] <- t.test(x)$p.value
if (mean(x)<0)
pvalsInCor[i] <- t.test(x,alternative="less")$p.value else
pvalsInCor[i] <- t.test(x,alternative="greater")$p.value
}
mean(pvalsCor<0.05)
[1] 0.043
[1] 0.098
- Type I error correctly controlled at \(\alpha\) for two-sided test.
- Type I error not correctly controlled when we test one-sided based on what we observed in the sample.
LS0tCnRpdGxlOiAiNS4gU3RhdGlzdGljYWwgSW5mZXJlbmNlIiAKYXV0aG9yOiAiTGlldmVuIENsZW1lbnQiCmRhdGU6ICJzdGF0T21pY3MsIEdoZW50IFVuaXZlcnNpdHkgKGh0dHBzOi8vc3RhdG9taWNzLmdpdGh1Yi5pbykiCm91dHB1dDoKICAgIGh0bWxfZG9jdW1lbnQ6CiAgICAgIGNvZGVfZG93bmxvYWQ6IHRydWUgICAgCiAgICAgIHRoZW1lOiBjb3NtbwogICAgICB0b2M6IHRydWUKICAgICAgdG9jX2Zsb2F0OiB0cnVlCiAgICAgIGhpZ2hsaWdodDogdGFuZ28KICAgICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChpbmNsdWRlID0gVFJVRSwgY29tbWVudCA9IE5BLCBlY2hvID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKYGBgCgoKYGBge3IgaW5jbHVkZT1GQUxTRX0KI0RvIG5vdCBydW4gZHVyaW5nIHRoZSBsZWN0dXJlIHdoZW4gd2Ugd29yayBpbnRlcmFjdGl2ZWx5CnNldC5zZWVkKDEzMTQpCmBgYAoKIyBJbnRyb2R1Y3Rpb24KIyMgUG9wdWxhdGlvbgoKLSBUaGUgYWltIG9mIGEgc2NpZW50aWZpYyBzdHVkeSBpcyB0byBkcmF3IGNvbmNsdXNpb25zIG9uIHRoZSBnZW5lcmFsIHBvcHVsYXRpb24uIAoKLSBIZXJlLCB3ZSBzdHVkeSB0aGUgZWZmZWN0IG9mIGNhcHRvcHJpbCBvbiB0aGUgYmxvb2QgcHJlc3N1cmUgb2YgcGF0aWVudHMgd2l0aCBoeXBlcnRlbnNpb24uIAoKLSBXZSB3aWxsIGNvbGxlY3QgZGF0YSBhbmQgd2Ugd2lsbCBtb2RlbCB0aGUgZGF0YQoKLSBUaGVyZWZvcmUsIHdlIGFsd2F5cyBoYXZlIHRvIHRyYW5zbGF0ZSB0aGUgcmVzZWFyY2ggcXVlc3Rpb24gd2l0aCByZXNwZWN0IHRvIG1vZGVsIHBhcmFtZXRlciBvciBhIGNvbWJpbmF0aW9uIG9mIG1vZGVsIHBhcmFtZXRlcnMuIAoKLSBlLmcuIHRoZSBwb3B1bGF0aW9uIG1lYW4KICAgJCRFKFgpPVxtdSQkCgotIERvZXMgdGhlIGJsb29kIHByZXNzdXJlIGRlY3JlYXNlcyBvbiBhdmVyYWdlIGFmdGVyIGFkbWluaXN0ZXJpbmcgY2FwdG9wcmlsIHRvIHBhdGllbnRzIHdpdGggaHlwZXJ0ZW5zaW9uPyAgIAoKLS0tCgojIyBPdmVydmlldyAKCi0gRXhwZXJpbWVudGFsIERlc2lnbiAmIERhdGEgRXhwbG9yYXRpb24KLSBQb2ludCBlc3RpbWF0b3JzIChFc3RpbWF0aW9uKQotIEludGVydmFsIGVzdGltYXRvcnMgKFN0YXRpc3RpY2FsIGluZmVyZW5jZSkKLSBIeXBvdGhlc2lzIHRlc3RzIChTdGF0aXN0aWNhbCBpbmZlcmVuY2UpCgotLS0KCiMgRXhwZXJpbWVudGFsIERlc2lnbgoKLSAxNSBwYXRpZW50cyB3ZXJlIGRyYXduIGF0IHJhbmRvbSBmcm9tIHRoZSBwb3B1bGF0aW9uIG9mIHBhdGllbnRzIHdpdGggaHlwZXJ0ZW5zaW9uCi0gcHJlLXRlc3QvcG9zdC10ZXN0IGRlc2lnbjogdGhlIHN5c3RvbGljIGFuZCBkaWFzeXN0b2xpYyBibG9vZCBwcmVzc3VyZSBhcmUgbWVhc3VyZWQgYmVmb3JlIGFuZCBhZnRlciBhZG1pbmlzdGVyaW5nIGNhcHRvcHJpbAotIEFkdmFudGFnZTogd2UgY2FuIGFzc2VzcyB0aGUgZWZmZWN0IG9mIGFkbWluaXN0ZXJpbmcgY2FwdG9wcmlsIG9uIHRoZSBibG9vZCBwcmVzc3VyZSBmb3IgZWFjaCBpbmRpdmlkdWFsIHBhdGllbnQuCi0gRGlzYWR2YW50YWdlPyAKCmBgYHtyIHBvcDJTYW1wMlBvcCxmaWcuYXNwPS44LCBmaWcuYWxpZ249J2NlbnRlcicsZWNobz1GQUxTRX0KaWYgKCJwaSIlaW4lbHMoKSkgcm0oInBpIikKa29wdm9ldGVyPC1mdW5jdGlvbih4LHksYW5nbGU9MCxsPS4yLGNleC5kb3Q9LjUscGNoPTE5LGNvbD0iYmxhY2siKQp7CmFuZ2xlPWFuZ2xlLzE4MCpwaQpwb2ludHMoeCx5LGNleD1jZXguZG90LHBjaD1wY2gsY29sPWNvbCkKbGluZXMoYyh4LHgrbCpjb3MoLXBpLzIrYW5nbGUpKSxjKHkseStsKnNpbigtcGkvMithbmdsZSkpLGNvbD1jb2wpCmxpbmVzKGMoeCtsLzIqY29zKC1waS8yK2FuZ2xlKSx4K2wvMipjb3MoLXBpLzIrYW5nbGUpK2wvNCpjb3MoYW5nbGUpKSxjKHkrbC8yKnNpbigtcGkvMithbmdsZSkseStsLzIqc2luKC1waS8yK2FuZ2xlKStsLzQqc2luKGFuZ2xlKSksY29sPWNvbCkKbGluZXMoYyh4K2wvMipjb3MoLXBpLzIrYW5nbGUpLHgrbC8yKmNvcygtcGkvMithbmdsZSkrbC80KmNvcyhwaSthbmdsZSkpLGMoeStsLzIqc2luKC1waS8yK2FuZ2xlKSx5K2wvMipzaW4oLXBpLzIrYW5nbGUpK2wvNCpzaW4ocGkrYW5nbGUpKSxjb2w9Y29sKQpsaW5lcyhjKHgrbCpjb3MoLXBpLzIrYW5nbGUpLHgrbCpjb3MoLXBpLzIrYW5nbGUpK2wvMipjb3MoLXBpLzIrcGkvNCthbmdsZSkpLGMoeStsKnNpbigtcGkvMithbmdsZSkseStsKnNpbigtcGkvMithbmdsZSkrbC8yKnNpbigtcGkvMitwaS80K2FuZ2xlKSksY29sPWNvbCkKbGluZXMoYyh4K2wqY29zKC1waS8yK2FuZ2xlKSx4K2wqY29zKC1waS8yK2FuZ2xlKStsLzIqY29zKC1waS8yLXBpLzQrYW5nbGUpKSxjKHkrbCpzaW4oLXBpLzIrYW5nbGUpLHkrbCpzaW4oLXBpLzIrYW5nbGUpK2wvMipzaW4oLXBpLzItcGkvNCthbmdsZSkpLGNvbD1jb2wpCn0KCnBhcihtYXI9YygwLDAsMCwwKSxtYWk9YygwLDAsMCwwKSkKcGxvdCgwLDAseGxhYj0iIix5bGFiPSIiLHhsaW09YygwLDEwKSx5bGltPWMoMCwxMCksY29sPTAseGF4dD0ibm9uZSIseWF4dD0ibm9uZSIsYXhlcz1GQUxTRSkKcmVjdCgwLDYsMTAsMTAsYm9yZGVyPSJyZWQiLGx3ZD0yKQp0ZXh0KC41LDgsInBvcHVsYXRpb24iLHNydD05MCxjb2w9InJlZCIsY2V4PTIpCnN5bWJvbHMgKDMsIDgsIGNpcmNsZXM9MS41LCBjb2w9InJlZCIsYWRkPVRSVUUsZmc9InJlZCIsaW5jaGVzPUZBTFNFLGx3ZD0yKQpncmlkPXNlcSgwLDEuMywuMDEpCgpmb3IgKGkgaW4gMTo1MCkKewoJYW5nbGUxPXJ1bmlmKG49MSxtaW49MCxtYXg9MzYwKQoJYW5nbGUyPXJ1bmlmKG49MSxtaW49MCxtYXg9MzYwKQoJcmFkaXVzPXNhbXBsZShncmlkLHByb2I9Z3JpZF4yKnBpL3N1bShncmlkXjIqcGkpLHNpemU9MSkKCWtvcHZvZXRlcigzK3JhZGl1cypjb3MoYW5nbGUxLzE4MCpwaSksOCtyYWRpdXMqc2luKGFuZ2xlMS8xODAqcGkpLGFuZ2xlPWFuZ2xlMikKfQp0ZXh0KDcuNSw4LCJFZmZlY3Qgb2YgY2FwdG9wcmlsIGluIHBvcHVsYXRpb24iLGNvbD0icmVkIixjZXg9MS4yKQoKcmVjdCgwLDAsMTAsNCxib3JkZXI9ImJsdWUiLGx3ZD0yKQp0ZXh0KC41LDIsInNhbXBsZSIsc3J0PTkwLGNvbD0iYmx1ZSIsY2V4PTIpCnN5bWJvbHMgKDMsIDIsIGNpcmNsZXM9MS41LCBjb2w9InJlZCIsYWRkPVRSVUUsZmc9ImJsdWUiLGluY2hlcz1GQUxTRSxsd2Q9MikKZm9yIChpIGluIDA6MikKCWZvciAoaiBpbiAwOjQpCnsKCglrb3B2b2V0ZXIoMi4xK2oqKDMuOS0yLjEpLzQsMS4xK2kpCn0KdGV4dCg3LjUsMiwiRWZmZWN0IG9mIGNhcHRvcHJpbCBpbiBzYW1wbGUiLGNvbD0iYmx1ZSIsY2V4PTEuMikKCmFycm93cygzLDUuOSwzLDQuMSxjb2w9ImJsYWNrIixsd2Q9MykKYXJyb3dzKDcsNC4xLDcsNS45LGNvbD0iYmxhY2siLGx3ZD0zKQp0ZXh0KDEuNSw1LCJFWFAuIERFU0lHTiAoMSkiLGNvbD0iYmxhY2siLGNleD0xLjIpCnRleHQoOC41LDUsIkVTVElNQVRJT04gJlxuSU5GRVJFTkNFICgzKSIsY29sPSJibGFjayIsY2V4PTEuMikKdGV4dCg3LjUsLjUsIkRBVEEgRVhQTE9SQVRJT04gJlxuREVTQ1JJUFRJVkUgU1RBVElTVElDUyAoMikiLGNvbD0iYmxhY2siLGNleD0xLjIpCmBgYAoKLS0tCgojIERhdGEgZXhwbG9yYXRpb24gYW5kIERlc2NyaXB0aXZlIFN0YXRpc3RpY3MgCgpgYGB7cn0KY2FwdG9wcmlsIDwtIHJlYWRfY3N2KCJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vR1RQQi9QU0xTMjAvbWFzdGVyL2RhdGEvY2FwdG9wcmlsLnR4dCIpCmhlYWQoY2FwdG9wcmlsKQpzdW1tYXJ5KGNhcHRvcHJpbCkKYGBgCgpgYGB7cn0KY2FwdG9wcmlsVGlkeSA8LSBjYXB0b3ByaWwgJT4lIGdhdGhlcih0eXBlLGJwLC1pZCkgCmNhcHRvcHJpbFRpZHkgJT4lIAogIGdyb3VwX2J5KHR5cGUpICU+JQogIHN1bW1hcml6ZV9hdCgiYnAiLGxpc3QobWVhbj1+bWVhbiguLG5hLnJtPVRSVUUpLAogICAgICAgICAgICAgICAgICAgIHNkPX5zZCguLG5hLnJtPVRSVUUpLAogICAgICAgICAgICAgICAgICAgIG49ZnVuY3Rpb24oeCkgeCU+JWlzLm5hJT4lYCFgJT4lc3VtKSkgJT4lCiAgbXV0YXRlKHNlPXNkL3NxcnQobikpIAoKY2FwdG9wcmlsVGlkeSAlPiUgCiAgZ3JvdXBfYnkodHlwZSkgJT4lCiAgc3VtbWFyaXplX2F0KCJicCIsbGlzdChtZWFuPX5tZWFuKC4sbmEucm09VFJVRSksCiAgICAgICAgICAgICAgICAgICAgc2Q9fnNkKC4sbmEucm09VFJVRSksCiAgICAgICAgICAgICAgICAgICAgbj1mdW5jdGlvbih4KSB4JT4laXMubmElPiVgIWAlPiVzdW0pKSAlPiUKICBtdXRhdGUoc2U9c2Qvc3FydChuKSkgJT4lCiAgZ2dwbG90KGFlcyh4PXR5cGUseT1tZWFuKSkgKyAKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIpICsKICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluPW1lYW4tc2UsIHltYXg9bWVhbitzZSksd2lkdGg9LjIpICsKICB5bGltKDAsMjEwKSArCiAgeWxhYigiYmxvb2QgcHJlc3N1cmUgKG1tSGcpIikKYGBgCgotIFRoaXMgZmlndXJlIGlzIG5vdCBpbmZvcm1hdGl2ZSEgSXQgZG9lcyBub3Qgc2hvdyB0aGUgcmF3IGRhdGEuIAoKYGBge3J9CmNhcHRvcHJpbFRpZHkgJT4lIAogIGdncGxvdChhZXMoeD10eXBlLHk9YnApKSArCiAgZ2VvbV9ib3hwbG90KG91dGxpZXIuc2hhcGU9TkEpICsKICBnZW9tX3BvaW50KHBvc2l0aW9uPSJqaXR0ZXIiKSArIAogIHlsaW0oMCwyMTApCmBgYAoKV2Ugc2VlIHRoYXQgYSBsb3Qgb2YgdGhlIHNwYWNlIHRoYXQgd2FzIHRha2VuIGJ5IHRoZSBiYXJwbG90IGRvZXMgbm90IGNvbnRhaW4gZGF0YSEKCmBgYHtyfQpjYXB0b3ByaWxUaWR5ICU+JSAKICBnZ3Bsb3QoYWVzKHg9dHlwZSx5PWJwKSkgKwogIGdlb21fYm94cGxvdChvdXRsaWVyLnNoYXBlPU5BKSArCiAgZ2VvbV9wb2ludChwb3NpdGlvbj0iaml0dGVyIikgCmBgYAoKLSBUaGlzIHBsb3Qgd291bGQgaGF2ZSBiZWVuIGluZm9ybWF0aXZlIGlmIHRoZSBkYXRhIHdhcyBnYXRoZXJlZCBvbiBkaWZmZXJlbnQgaW5kaXZpZHVhbHMuIAoKLSBIb3dldmVyLCB0aGUgYmxvb2QgcHJlc3N1cmVzIGFyZSBtZWFzdXJlZCBvcCB0aGUgc2FtZSBzdWJqZWN0IQoKLSBXZSB3aWxsIG1ha2UgYSBwbG90IGJ5IGZpbHRlcmluZyB0aGUgc3lzdG9saWMgYmxvb2QgcHJlc3N1cmVzCgpgYGB7cn0KY2FwdG9wcmlsVGlkeSAlPiUKICBmaWx0ZXIodHlwZSVpbiVjKCJTQlBhIiwiU0JQYiIpKSAlPiUKICBtdXRhdGUodHlwZT1mYWN0b3IodHlwZSxsZXZlbHM9YygiU0JQYiIsIlNCUGEiKSkpICU+JQogIGdncGxvdChhZXMoeD10eXBlLHk9YnApKSArCiAgZ2VvbV9saW5lKGFlcyhncm91cCA9IGlkKSkgKwogIGdlb21fcG9pbnQoKQpgYGAKCi0gV2UgaGF2ZSBwYWlyZWQgZGF0YS4gU28gd2UgbWlnaHQgZXN0aW1hdGUgdGhlIGVmZmVjdCBvZiB0aGUgdHJlYXRtZW50IGRpcmVjdGx5IGJ5IGNvbXBhcmluZyB0aGUgYmxvb2QgcHJlc3N1cmUgYWZ0ZXIgdHJlYXRtZW50IHRvIHRoZSBibG9vZCBwcmVzc3VyZSBiZWZvcmUgdGhlIHRyZWF0bWVudC4gCgpgYGB7cn0KY2FwdG9wcmlsJGRlbHRhU0JQPC1jYXB0b3ByaWwkU0JQYS1jYXB0b3ByaWwkU0JQYgpjYXB0b3ByaWwlPiUKICBnZ3Bsb3QoYWVzKHg9IlN5c3RvbGljIGJsb29kIHByZXNzdXJlIix5PWRlbHRhU0JQKSkgKwogIGdlb21fYm94cGxvdChvdXRsaWVyLnNoYXBlPU5BKSArIAogIGdlb21fcG9pbnQocG9zaXRpb249ImppdHRlciIpKwogIHlsYWIoIkRpZmZlcmVuY2UgKG1tIG1lcmN1cnkpIikgKwogIHhsYWIoIiIpCmBgYAoKYGBge3J9CmNhcHRvcHJpbCAlPiUKICBzdW1tYXJpemVfYXQoImRlbHRhU0JQIixsaXN0KG1lYW49fm1lYW4oLixuYS5ybT1UUlVFKSwKICAgICAgICAgICAgICBzZD1+c2QoLixuYS5ybT1UUlVFKSwKICAgICAgICAgICAgICBuPWZ1bmN0aW9uKHgpIHglPiVpcy5uYSU+JWAhYCU+JXN1bSkpICU+JQogIG11dGF0ZShzZT1zZC9zcXJ0KG4pKQpgYGAKCgotIFByZS10ZXN0L3Bvc3QtdGVzdCBkZXNpZ246IEVmZmVjdCBvZiBjYXB0b3ByaWwgaW4gc2FtcGxlIHVzaW5nICAkWD1cRGVsdGFfXHRleHR7YWZ0ZXItYmVmb3JlfSQhCgotIEhvdyB3aWxsIHdlIG1vZGVsICRYPVxEZWx0YV9cdGV4dHthZnRlci1uYX0kIGFuZCBlc3RpbWF0ZSB0aGUgZWZmZWN0IG9mIGNhcHRvcHJpbD8gCgpgYGB7cn0KY2FwdG9wcmlsJT4lCiAgZ2dwbG90KGFlcyhzYW1wbGU9ZGVsdGFTQlApKSArCiAgc3RhdF9xcSgpICsKICBzdGF0X3FxX2xpbmUoKQpgYGAKClRoZSBzeXN0b2xpYyBibG9vZCBwcmVzc3VyZSBkaWZmZXJlbmNlcyBhcmUgYXBwcm94aW1hdGVseSBub3JtYWxseSBkaXN0cmlidXRlZC4gCgotLS0KCiMgRXN0aW1hdGlvbgoKCi0gTm8gc3Vic3RhbnRpYWwgZGV2aWF0aW9ucyBmcm9tIG5vcm1hbGl0eQoKLSBXZSBjYW4gYXNzdW1lIHRoYXQgdGhlIGRpZmZlcmVuY2VzICAkWCBcc2ltIE4oXG11LCBcc2lnbWFeMikkLgoKLSBFZmZlY3Qgb2YgY2FwdG9wcmlsIGluIHRoZSBwb3B1bGF0aW9uIGlzIGNhcHR1cmVkIGJ5IHRoZSBhdmVyYWdlIGJsb29kIHByZXNzdXJlIGRpZmZlcmVuY2UgJFxtdSQuCgotIFRoZSBhdmVyYWdlIGJsb29kIHByZXNzdXJlICRcbXUkIGluIHRoZSBwb3B1bGF0aW9uIGNhbiBiZSBlc3RpbWF0ZWQgdXNpbmcgdGhlIHNhbXBsZSBtZWFuICRcYmFyIHgkPWByIHJvdW5kKG1lYW4oY2FwdG9wcmlsJGRlbHRhU0JQKSwyKWAKCi0gVGhlIHN0YW5kYXJkIGRldmlhdGlvbiAkXHNpZ21hJCB3aXRoIHRoZSBzYW1wbGUgc3RhbmRhcmQgZGV2aWF0aW9uICRcdGV4dHtTfSQ9YHIgcm91bmQoc2QoY2FwdG9wcmlsJGRlbHRhU0JQKSwyKWAuCgotIElzIHRoZSBlZmZlY3QgdGhhdCB3ZSBvYnNlcnZlIGluIHRoZSBzYW1wbGUgbGFyZ2UgZW5vdWdoIHRvIGNvbmNsdWRlIHRoYXQgdGhlcmUgaXMgYW4gZWZmZWN0IG9mIHRoZSBjYXB0b3ByaWwgdHJlYXRtZW50IG9uIHRoZSBibG9vZCBwcmVzc3VyZSBhdCBwb3B1bGF0aW9uIGxldmVsPyAKCi0gT3VyIGVzdGltYXRlcyB3aWxsIGNoYW5nZSBmcm9tIHNhbXBsZSB0byBzYW1wbGUhCgotIEhvdyBhcmUgdGhlIGVzdGltYXRvcnMgJFxiYXIgWCQgYW5kICRTJCBkaXN0cmlidXRlZD8gCgoKIyMgUG9pbnQgZXN0aW1hdG9yIHRoZSBzYW1wbGUgbWVhbgoKLSBTdXBwb3NlIHRoYXQgJFgkIGlzIGEgcmFuZG9tIHNhbXBsZSBmcm9tIHRoZSBwb3B1bGF0aW9uIGFuZCBhc3N1bWUgdGhhdCAkWCBcc2ltIE4oXG11LFxzaWdtYV4yKSQKCi0gRXN0aW1hdGUgJFxtdSQgYmFzZWQgb24gc2FtcGxlICRYXzEsLi4uLFhfbiQsIHVzaW5nIHRoZSBzYW1wbGUgbWVhbiAKICAkJFxiYXIgWCA9IFxmcmFje1hfMSsgWF8yKyAuLi4gKyBYX259e259ID0gXGZyYWN7XHN1bV97aT0xfV57bn0gWF9pfXtufSQkIG9mIHJhbmRvbSB2YXJpYWJsZXMgJFhfMSxYXzIsIC4uLiwgWF9uJC4KCi0gU2FtcGxlIG1lYW4gJFxiYXIgWCQgaXMgYSByYW5kb20gdmFyaWFibGUgdGhhdCB2YXJpZXMgZnJvbSBzYW1wbGUgdG8gc2FtcGxlIAoKLSBTdHVkeSB0aGUgdGhlb3JldGljYWwgZGlzdHJpYnV0aW9uIG9mIHRoZSBzYW1wbGUgbWVhbiB0byBnZXQgaW5zaWdodCAKICAgIAogICAgMS4gaW4gaG93IHRoZSBzYW1wbGUgbWVhbiBjYW4gdmFyeSBpbiBhIG5ldyBzaW1pbGFyIHN0dWR5CiAgICAyLiBob3cgZmFyICRcYmFyIFgkIGNhbiBiZSBmcm9tIHRoZSBwb3B1bGF0aW9uIG1lYW4gJFxtdSQKCi0tLQoKIyMjIE92ZXJ2aWV3CgoxLiBUaGUgc2FtcGxlIG1lYW4gaXMgdW5iaWFzZWQgCjIuIFByZWNpc2lvbiBvZiBzYW1wbGUgbWVhbiAKMy4gRGlzdHJpYnV0aW9uIG9mIHNhbXBsZSBtZWFuCgotLS0KCiMjIyBUaGUgc2FtcGxlIG1lYW4gaXMgdW5iaWFzZWQgCgotIFdlIGNhbiBnZW5lcmFsaXplIG91ciBvYnNlcnZhdGlvbnMgYmFzZWQgb24gdGhlIHNhbXBsZSB0b3dhcmRzIHRoZSBwb3B1bGF0aW9uIGlmIHRoZSBlc3RpbWF0ZSBpcyBnb29kIGFwcHJveGltYXRpb24gb2YgdGhlIHBvcHVsYXRpb24gdmFsdWUuIAoKLSBBIHJlcHJlc2VudGF0aXZlIHNhbXBsZSBpcyByZXF1aXJlZCB0byBnZW5lcmFsaXplIHRoZSByZXN1bHRzIGZyb20gdGhlIHNhbXBsZSB0b3dhcmRzIHRoZSBwb3B1bGF0aW9uCgotIEF2b2lkIGJpYXMgKHNvIHRoYXQgdGhlIHBvcHVsYXRpb24gbWVhbiBpcyBub3Qgc3lzdGVtYXRpY2FsbHkgdW5kZXIgb3Igb3ZlcmVzdGltYXRlZCkgCgotIFJlcG9ydCBob3cgdGhlIHNhbXBsZSBpcyB0YWtlbiEgCgotIFJhbmRvbWlzYXRpb24hCgotIERyYXcgdGhlIHN1YmplY3RzIGF0IHJhbmRvbSBmcm9tIHBvcHVsYXRpb24gc28gZXZlcnkgc3ViamVjdCBoYXMgdGhlIHNhbWUgcHJvYmFiaWxpdHkgdG8gZW5kIHVwIGluIHRoZSBzYW1wbGUuICAKCi0gU3ViamVjdHMgd2l0aCBoeXBlcnRlbnNpb24gYXJlIHNhbXBsZWQgYXQgcmFuZG9tIGZyb20gdGhlIHBvcHVsYXRpb24KCgotIFNpbXBsZSByYW5kb20gc2FtcGxlOiAgJFhfMSwuLi4sWF9uJCBmb3IgY2hhcmFjdGVyaXN0aWMgJFgkCgotICRYXzEsLi4uLFhfbiQgaGF2ZSBzYW1lIGRpc3RyaWJ1dGlvbgotIFRoZXkgaGF2ZSBzYW1lIG1lYW4gJFxtdSQgYW5kIHZhcmlhbmNlICRcc2lnbWFeMiQKCi0gJEUoWF8xKT0uLi49RShYX24pPVxtdSQgYW5kICRcdGV4dHtWYXJ9KFhfMSk9Li4uPVx0ZXh0e1Zhcn0oWF9uKT1cc2lnbWFeMiQKCi0gJFxiYXIgWCQgaXMgYW4gKnVuYmlhc2VkIGVzdGltYXRvciogZm9yICRcbXUkIAoKPGRldGFpbHM+PHN1bW1hcnk+Q2xpY2sgdG8gc2VlIHByb29mPC9zdW1tYXJ5PjxwPgpcYmVnaW57ZXFuYXJyYXkqfQpFKFxiYXIgWCkgJj0mIEUgXGxlZnQoXGZyYWN7WF8xKyBYXzIrIC4uLiArIFhfbn17bn1ccmlnaHQpIFxcCiY9ICYgXGZyYWN7RShYXzEpKyBFKFhfMikrIC4uLiArIEUoWF9uKX17bn0gXFwKJj0mIFxmcmFje1xtdSArIFxtdSArIC4uLiArXG11fXtufSBcXAomPSAmIFxtdQpcZW5ke2VxbmFycmF5Kn0KPC9wPjwvZGV0YWlscz4KCi0tLQoKIyMjIEltcHJlY2lzaW9uL3N0YW5kYXJkIGVycm9yCgotIEFsc28gZm9yIHJlcHJlc2VudGF0aXZlIHNhbXBsZXMgdGhlIHJlc3VsdHMgYXJlIGltcHJlY2lzZS4gClx2c3BhY2V7MTBwdH0KLSBEaWZmZXJlbnQgc2FtcGxlcyBmcm9tIHRoZSBzYW1lIHBvcHVsYXRpb24gZ2l2ZSBkaWZmZXJlbnQgcmVzdWx0cy4KCi0gV2UgaWxsdXN0cmF0ZWQgdGhpcyBieSB1c2luZyB0aGUgTkhBTkVTIAoKICAgIC0gV2Ugd2lsbCBkcmF3IDE1IGZlbWFsZXMgYXQgcmFuZG9tIGZyb20gdGhlIE5IQU5FUyBzdHVkeSBhbmQgd2Ugd2lsbCByZWdpc3RlciB0aGVpciBsb2cyIGRpcmVjdCBjaG9sZXN0ZXJvbCB2YWx1ZXMKICAgIC0gV2UgcmVwZWF0IHRoaXMgNTAgdGltZXMgdG8gYXNzZXNzIHRoZSB2YXJpYXRpb24gZnJvbSBzYW1wbGUgdG8gc2FtcGxlCiAgICAtIFdlIHdpbGwgcGxvdCB0aGUgYm94cGxvdCBmb3IgZWFjaCBzYW1wbGUgYW5kIHdpbGwgaW5kaWNhdGUgdGhlIG1lYW4gCgpgYGB7cn0KbGlicmFyeShOSEFORVMpCgpmZW0gPC0gTkhBTkVTICU+JSAKICBmaWx0ZXIoR2VuZGVyPT0iZmVtYWxlIiAmICFpcy5uYShEaXJlY3RDaG9sKSkgJT4lCiAgc2VsZWN0KCJEaXJlY3RDaG9sIikKCm48LTE1ICMgbnVtYmVyIG9mIHN1YmplY3RzIHBlciBzYW1wbGUKblNpbT01MCAjIG51bWJlciBvZiBzaW11bGF0aW9ucwoKZmVtU2FtcDwtbWF0cml4KG5yb3c9bixuY29sPW5TaW0pCmZvciAoaiBpbiAxOm5TaW0pCnsKICBmZW1TYW1wWyxqXTwtc2FtcGxlKGZlbSREaXJlY3RDaG9sLDE1KQogIGlmIChqPDQpIHsKICAgIHAgPC0gZmVtU2FtcCAlPiUgCiAgICAgIGxvZzIgJT4lCiAgICAgIGRhdGEuZnJhbWUgJT4lIAogICAgICBnYXRoZXIoInNhbXBsZSIsImxvZzJjaG9sZXN0ZXJvbCIpICU+JQogICAgICBnZ3Bsb3QoYWVzKHg9c2FtcGxlLHk9bG9nMmNob2xlc3Rlcm9sKSkgKwogICAgICBnZW9tX2JveHBsb3QoKSArIAogICAgICBzdGF0X3N1bW1hcnkoZnVuLnk9bWVhbiwgZ2VvbT0icG9pbnQiLCBzaGFwZT0xOSwgc2l6ZT0zLCBjb2xvcj0icmVkIiwgZmlsbD0icmVkIikgKwogICAgICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBtZWFuKGZlbSREaXJlY3RDaG9sICU+JSBsb2cyKSkgKwogICAgICB5bGFiKCJjaG9sZXN0ZXJvbCAobG9nMikiKSAKICAgIHByaW50KHApCiAgfQp9CgpmZW1TYW1wICU+JSAKICBsb2cyICU+JSAKICBkYXRhLmZyYW1lICU+JSAKICBnYXRoZXIoInNhbXBsZSIsImxvZzJjaG9sZXN0ZXJvbCIpICU+JQogIGdncGxvdChhZXMoeD1zYW1wbGUseT1sb2cyY2hvbGVzdGVyb2wpKSArCiAgZ2VvbV9ib3hwbG90KCkgKyAKICBzdGF0X3N1bW1hcnkoZnVuLnk9bWVhbiwgZ2VvbT0icG9pbnQiLCBzaGFwZT0xOSwgc2l6ZT0zLCBjb2xvcj0icmVkIiwgZmlsbD0icmVkIikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IG1lYW4oZmVtJERpcmVjdENob2wgJT4lIGxvZzIpKSArCiAgeWxhYigiY2hvbGVzdGVyb2wgKGxvZzIpIikKYGBgCgpXZSBvYnNlcnZlIHRoYXQgdGhlIG1lYW4gbmljZWx5IGZsdWN0dWF0ZXMgYXJvdW5kIHRoZSBwb3B1bGF0aW9uIG1lYW4uIAoKQ29weSB0aGUgY29kZSwgaW5jcmVhc2UgdGhlIHNhbXBsZSBzaXplIHRvIDEwMCBzdWJqZWN0cyBhbmQgb2JzZXJ2ZSB3aGF0IGhhcHBlbnMhCgotLS0KCiMjIyBIb3cgdG8gZG8gdGhpcyBiYXNlZCBvbiBhIHNpbmdsZSBzYW1wbGU/CgotIEluc2lnaHQgaW4gaG93IGNsb3NlIHdlIGNhbiBleHBlY3QgJFxiYXIgWCQgdG8gJFxtdSQ/CgotIEhvdyB2YXJpZXMgJFxiYXIgWCQgZnJvbSBzYW1wbGUgdG8gc2FtcGxlPyAKCi0gVmFyaWFiaWxpdHkgb24gJFxiYXIgWCQKCi0gV2UgaGF2ZSB0byBkZXRlcm1pbmUgdGhpcyBiYXNlZCBvbiBhIHNpbmdsZSBzYW1wbGUhCgotIFdlIG5lZWQgdG8gbWFrZSBhc3N1bXB0aW9ucyAKCi0gV2UgYXNzdW1lIHRoYXQgdGhlIHJhbmRvbSB2YXJpYWJsZXMgJFhfMSwgWF8yLCAuLi4sIFhfbiQgb3JpZ2luYXRlIGZyb20gJG4kICppbmRlcGVuZGVudCogc3ViamVjdHMuIAoKLSBGb3IgdGhlIGNhcHRvcHJpbCBzdHVkeSB3ZSBoYWQgZGVwZW5kZW50IG9ic2VydmF0aW9ucy4gCiAgICAKICAgIC0gQmxvb2QgcHJlc3N1cmUgbWVhc3VyZW1lbnRzIGJlZm9yZSAoJFlfe2ksYmVmb3JlfSQpIGFuZCAgYWZ0ZXIgKCRZX3tpLGFmdGVyfSQpIGFkbWluaXN0ZXJpbmcgY2FwdG9wcmlsIGZvciB0aGUgc2FtZSBzdWJqZWN0ICRpPTEsXGxkb3RzLG4kLgogICAgLSBXZSB0dXJuZWQgdGhlbSBpbnRvIG4gaW5kZXBlbmRlbnQgbWVhc3VyZW1lbnRzIGJ5IHRha2luZyB0aGUgZGlmZmVyZW5jZSAkWV97aSxhZnRlcn0tWV97aSxiZWZvcmV9JAoKLS0tCgojIyMgVmFyaWFuY2UgZXN0aW1hdG9yIGZvciAkXGJhciBYJAoKJCRcc2lnbWFeMl97XGJhciBYfT1cZnJhY3tcc2lnbWFeMn17bn0kJAoKLSBUaGUgc3RhbmRhcmQgZGV2aWF0aW9uIG9mICRcYmFyIFgkIGFyb3VuZCAkXG11JCBpcyAkXHNxcnR7bn0kIHRpbWVzIHNtYWxsZXIgdGhhdCB0aGUgZGV2aWF0aW9uIGFyb3VuZCB0aGUgb3JpZ2luYWwgb2JzZXJ2YXRpb25zICRYJC4KCi0gVGhlIG1vcmUgb2JzZXJ2YXRpb25zIHdlIGhhdmUgdGhlIG1vcmUgcHJlY2lzZSAkXGJhciBYJC4KCgo8ZGV0YWlscz48c3VtbWFyeT5DbGljayB0byBzZWUgcHJvb2Y8L3N1bW1hcnk+PHA+ClxiZWdpbntlcW5hcnJheSp9Clx0ZXh0e1Zhcn0oXGJhciBYKSY9Jlx0ZXh0e1Zhcn0gXGxlZnQoXGZyYWN7WF8xKyBYXzIrIC4uLiArIFhfbn17bn1ccmlnaHQpIFxcCiY9ICYgXGZyYWN7XHRleHR7VmFyfSAoWF8xKyBYXzIrIC4uLiArIFhfbil9e25eMn0gXFwKJlxvdmVyc2V0eyp9ez19ICYgXGZyYWN7XHRleHR7VmFyfShYXzEpKyBcdGV4dHtWYXJ9KFhfMikrIC4uLiArIFx0ZXh0e1Zhcn0oWF9uKX17bl4yfSBcXAomPSYgXGZyYWN7XHNpZ21hXjIgKyBcc2lnbWFeMiArIC4uLiBcc2lnbWFeMn17bl4yfSBcXAomPSAmIFxmcmFje1xzaWdtYV4yfXtufS4KXGVuZHtlcW5hcnJheSp9CgotICgqKSB0aGlzIGlzIGJhc2VkIG9uIHRoZSBhc3N1bXB0aW9uIG9mIGluZGVwZW5kZW5jZS4gCiQkXHRleHR7VmFyfVtYXzEgKyBYXzJdID0gXHRleHR7VmFyfVtYXzFdICsgXHRleHR7VmFyfVtYXzJdICsgMiBcdGV4dHtDb3Zhcn1bWF8xLFhfMl0kJAoKICAgIC0gV2l0aCAkQ292YXJbWF8xLFhfMl09MCQgd2hlbiAkWF8xJCBhbmQgJFhfMiQgYXJlIGluZGVwZW5kZW50LiAKPC9wPjwvZGV0YWlscz4KCioqRGVmaW5pdGlvbjogc3RhbmRhcmQgZXJyb3IqKgoKVGhlIHN0YW5kYXJkIGRldmlhdGlvbiBvZiAkXGJhcntYfSQgaXMgJFxzaWdtYS9cc3FydHtufSQgYW5kIGlzIGFsc28gcmVmZXJyZWQgdG8gYXMgdGhlICoqc3RhbmRhcmQgZXJyb3IqKiBvZiB0aGUgbWVhbi4gCkdlbmVyYWxseSBvbmUgcmVmZXJzIHRvIHRoZSBzdGFuZGFyZCBkZXZpYXRpb24gb2YgYW4gZXN0aW1hdG9yIGZvciBhIHBhcnRpY3VsYXIgcGFyYW1ldGVyICRcdGhldGEkIHdpdGggdGhlIHRlcm0gKipzdGFuZGFyZCBlcnJvcioqIG9mIHRoZSBlc3RpbWF0b3IsIHdoaWNoIGlzIGRlbm90ZWQgYXMgJFNFJC4KCi0tLQoKIyMjIENhcHRvcHJpbCBleGFtcGxlIAoKCi0gJG4gPSAxNSQgZGlmZmVyZW5jZXMgaW4gc3lzdG9saWMgYmxvb2QgcHJlc3N1cmUKCi0gU3VwcG9zZSB0aGF0IHRoZSBzdGFuZGFyZCBkZXZpYXRpb24gb2YgdGhlIGJsb29kIHByZXNzdXJlIGRpZmZlcmVuY2VzIGluIHRoZSBwb3B1bGF0aW9uIGlzICRcc2lnbWEgPSA5LjAkIG1tSGcKCi0gVGhlbiwgdGhlIHN0YW5kYXJkIGVycm9yIChTRSkgb24gdGhlIGF2ZXJhZ2Ugc3lzdG9saWMgYmxvb2QgcHJlc3N1cmUgZGlmZmVycyAkXGJhciBYJCBiZWNvbWVzOgoKJCQKU0U9IFxmcmFjezkuMH17XHNxcnR7MTV9fT0yLjMyXHRleHR7bW1IZy59CiQkCgotIEdlbmVyYWxseSAkXHNpZ21hJCwgYW5kIHRodXMgdGhlIFNFIG9uIHRoZSBzYW1wbGUgbWVhbiBhcmUgdW5rbm93bi4gCi0gU28gd2UgYWxzbyBoYXZlIHRvIGVzdGltYXRlIHRoZSBzdGFuZGFyZCBkZXZpYXRpb24gb2YgdGhlIHNhbXBsZSB0byBvYnRhaW4gdGhlIHN0YW5kYXJkIGVycm9yCi0gRXN0aW1hdG9yOiAkU0U9Uy9cc3FydHtufSwkCi0gd2l0aCAkU14yJCB0aGUgc2FtcGxlIHZhcmlhbmNlIG9mICRYXzEsLi4uLFhfbiQgIGFuZCAkUyQgdGhlIHNhbXBsZSBzdGFuZGFyZCBkZXZpYXRpb24gCgotIEZvciB0aGUgY2FwdG9wcmlsIGV4YW1wbGUgd2Ugb2J0YWluOgoKYGBge3J9Cm49bGVuZ3RoKGNhcHRvcHJpbCRkZWx0YVNCUCkKc2U9c2QoY2FwdG9wcmlsJGRlbHRhU0JQKS9zcXJ0KG4pCnNlCmBgYAoKLS0tCgojIyMgc3RhbmRhcmQgZGV2aWF0aW9uIHZzIHN0YW5kYXJkIGVycm9yCgojIyMjIElsbHVzdHJhdGUgdmlhIHJlcGVhdGVkIHNhbXBsaW5nCgotIERpZmZlcmVudCBzYW1wbGUgc2l6ZXM6IDEwLCA1MCwgMTAwCi0gRHJhdyAxMDAwIHNhbXBsZXMgcGVyIHNhbXBsZSBzaXplIGZyb20gdGhlIE5IQU5FUyBzdHVkeSwgZm9yIGVhY2ggc2FtcGxlIHdlIGNhbGN1bGF0ZQogICAgLSBUaGUgbWVhbgogICAgLSBUaGUgc2FtcGxlIHN0YW5kYXJkIGRldmlhdGlvbiAKICAgIC0gVGhlIHN0YW5kYXJkIGVycm9yCi0gV2UgbWFrZSBhIGJveHBsb3Qgb2YgdGhlIHNhbXBsZSBzdGFuZGFyZCBkZXZpYXRpb25zIGFuZCB0aGUgc3RhbmRhcmQgZXJyb3JzIGZvciB0aGUgZGlmZmVyZW50IHNhbXBsZSBzaXplcwoKLSBJbnN0ZWFkIG9mIHVzaW5nIGEgZm9yIGxvb3Agd2Ugd2lsbCB1c2UgdGhlIHNhcHBseSBmdW5jdGlvbiB3aGljaCBpcyBtb3JlIGVmZmljaWVudC4gSXQgdGFrZXMgYSB2ZWN0b3Igb3IgYSBsaXN0IGFzIGlucHV0IGFuZCBhcHBsaWVzIGEgZnVuY3Rpb24gb24gZWFjaCBlbGVtZW50IG9mIHRoZSB2ZWN0b3Igb3Igb24gZWFjaCBsaXN0IGVsZW1lbnQuIAoKYGBge3J9CmZlbVNhbXAxMDwtc2FwcGx5KDE6MTAwMCxmdW5jdGlvbihqLHgsc2l6ZSkgc2FtcGxlKHgsc2l6ZSksc2l6ZT0xMCx4PWZlbSREaXJlY3RDaG9sKSAKCmZlbVNhbXA1MDwtc2FwcGx5KDE6MTAwMCxmdW5jdGlvbihqLHgsc2l6ZSkgc2FtcGxlKHgsc2l6ZSksc2l6ZT01MCx4PWZlbSREaXJlY3RDaG9sKSAKCmZlbVNhbXAxMDA8LXNhcHBseSgxOjEwMDAsZnVuY3Rpb24oaix4LHNpemUpIHNhbXBsZSh4LHNpemUpLHNpemU9MTAwLHg9ZmVtJERpcmVjdENob2wpIAoKcmVzPC1yYmluZCgKZmVtU2FtcDEwICU+JSAKICBsb2cyJT4lCiAgYXMuZGF0YS5mcmFtZSAlPiUgCiAgZ2F0aGVyKHNhbXBsZSxsb2cyQ2hvbCkgJT4lIAogIGdyb3VwX2J5KHNhbXBsZSklPiUKICBzdW1tYXJpemVfYXQoImxvZzJDaG9sIiwKICAgICAgICAgICAgICAgbGlzdChtZWRpYW49fm1lZGlhbiguLG5hLnJtPVRSVUUpLAogICAgICAgICAgICAgICAgICAgIG1lYW49fm1lYW4oLixuYS5ybT1UUlVFKSwKICAgICAgICAgICAgICAgICAgICBzZD1+c2QoLixuYS5ybT1UUlVFKSwKICAgICAgICAgICAgICAgICAgICBuPWZ1bmN0aW9uKHgpIHglPiVpcy5uYSU+JWAhYCU+JXN1bSkpICU+JQogIG11dGF0ZShzZT1zZC9zcXJ0KG4pKSAsCgpmZW1TYW1wNTAgJT4lIAogIGxvZzIgJT4lICAKICBhcy5kYXRhLmZyYW1lICU+JQogIGdhdGhlcihzYW1wbGUsbG9nMkNob2wpICU+JQogIGdyb3VwX2J5KHNhbXBsZSklPiUKICBzdW1tYXJpemVfYXQoImxvZzJDaG9sIiwKICAgICAgICAgICAgICAgbGlzdChtZWRpYW49fm1lZGlhbiguLG5hLnJtPVRSVUUpLAogICAgICAgICAgICAgICAgICAgIG1lYW49fm1lYW4oLixuYS5ybT1UUlVFKSwKICAgICAgICAgICAgICAgICAgICBzZD1+c2QoLixuYS5ybT1UUlVFKSwKICAgICAgICAgICAgICAgICAgICBuPWZ1bmN0aW9uKHgpIHglPiVpcy5uYSU+JWAhYCU+JXN1bSkpICU+JQogIG11dGF0ZShzZT1zZC9zcXJ0KG4pKSwKCmZlbVNhbXAxMDAgJT4lIAogIGxvZzIgJT4lIAogIGFzLmRhdGEuZnJhbWUgJT4lIAogIGdhdGhlcihzYW1wbGUsbG9nMkNob2wpICU+JSAKICBncm91cF9ieShzYW1wbGUpJT4lCiAgc3VtbWFyaXplX2F0KCJsb2cyQ2hvbCIsCiAgICAgICAgICAgICAgIGxpc3QobWVkaWFuPX5tZWRpYW4oLixuYS5ybT1UUlVFKSwKICAgICAgICAgICAgICAgICAgICBtZWFuPX5tZWFuKC4sbmEucm09VFJVRSksCiAgICAgICAgICAgICAgICAgICAgc2Q9fnNkKC4sbmEucm09VFJVRSksCiAgICAgICAgICAgICAgICAgICAgbj1mdW5jdGlvbih4KSB4JT4laXMubmElPiVgIWAlPiVzdW0pKSAlPiUKICBtdXRhdGUoc2U9c2Qvc3FydChuKSkKKQpgYGAKCiMjIyMjIE1lYW5zCgpXZSBmaXJzdCBpbGx1c3RyYXRlIHRoZSBpbXBhY3Qgb2Ygc2FtcGxlIHNpemUgb24gdGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgbWVhbnMgb2YgdGhlIGRpZmZlcmVudCBzYW1wbGVzCgpgYGB7cn0KcmVzICU+JSAKZ2dwbG90KGFlcyh4PW4lPiVhcy5mYWN0b3IseT1tZWFuKSkgKwpnZW9tX2JveHBsb3QoKSArCnlsYWIoIkRpcmVjdCBjaG9sZXN0ZXJvbCAobG9nMikiKSArIAp4bGFiKCJzYW1wbGUgc2l6ZSIpCmBgYAoKLSBOb3RlLCB0aGF0IHRoZSB2YXJpYXRpb24gb2YgdGhlIHNhbXBsZSBtZWFucyBpbmRlZWQgcmVkdWNlcyBhcyB0aGUgc2FtcGxlIHNpemUgaW5jcmVhc2VzLiBTbyB0aGUgZXN0aW1hdGlvbiBnZXRzIG1vcmUgcHJlY2lzZSB3aXRoIGluY3JlYXNpbmcgc2FtcGxlIHNpemUuIAoKLS0tCgojIyMjIyBTdGFuZGFyZCBkZXZpYXRpb24gCgpXZSBub3cgaWxsdXN0cmF0ZSB0aGUgaW1wYWN0IG9mIHNhbXBsZSBzaXplIG9uIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIHN0YW5kYXJkIGRldmlhdGlvbiBvZiB0aGUgZGlmZmVyZW50IHNhbXBsZXMKCmBgYHtyfQpyZXMgJT4lIApnZ3Bsb3QoYWVzKHg9biU+JWFzLmZhY3Rvcix5PXNkKSkgKwpnZW9tX2JveHBsb3QoKSArCnlsYWIoInN0YW5kYXJkIGRldmlhdGlvbiIpICsgCnhsYWIoInNhbXBsZSBzaXplIikKYGBgCgoKLSBUaGUgc3RhbmRhcmQgZGV2aWF0aW9uIHJlbWFpbnMgc2ltaWxhciBhY3Jvc3Mgc2FtcGxlIHNpemUuCkl0IGlzIGNlbnRyZWQgYXJvdW5kIHRoZSBzYW1lIHZhbHVlOiB0aGUgc3RhbmRhcmQgZGV2aWF0aW9uIGluIHRoZSBwb3B1bGF0aW9uLiBJbmRlZWQgaW5jcmVhc2luZyB0aGUgc2FtcGxlIHNpemUgZG9lcyBhZmZlY3QgdGhlIHZhcmlhYmlsaXR5IGluIHRoZSBwb3B1bGF0aW9uIQoKLSBBZ2FpbiB3ZSBzZWUgdGhhdCB0aGUgdmFyaWFiaWxpdHkgb2YgdGhlIHN0YW5kYXJkIGRldmlhdGlvbiByZWR1Y2VzIHdpdGggaW5jcmVhc2luZyBzYW1wbGUgc2l6ZS4gU28gdGhlIHN0YW5kYXJkIGRldmlhdGlvbiBjYW4gYWxzbyBiZSBlc3RpbWF0ZWQgbW9yZSBwcmVjaXNlIHdpdGggaW5jcmVhc2luZyBzYW1wbGUgc2l6ZS4gCgotLS0KCiMjIyMjIFN0YW5kYXJkIGVycm9yIG9uIHRoZSBtZWFuIAoKRmluYWxseSwgd2UgaWxsdXN0cmF0ZSB0aGUgaW1wYWN0IG9mIHNhbXBsZSBzaXplIG9uIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIHN0YW5kYXJkIGRldmlhdGlvbiBvbiB0aGUgbWVhbiBvZiB0aGUgZGlmZmVyZW50IHNhbXBsZXMKCmBgYHtyfQpyZXMgJT4lIApnZ3Bsb3QoYWVzKHg9biU+JWFzLmZhY3Rvcix5PXNlKSkgKwpnZW9tX2JveHBsb3QoKSArCnlsYWIoInN0YW5kYXJkIGVycm9yIikgKyAKeGxhYigic2FtcGxlIHNpemUiKQpgYGAKCi0gVGhlIHN0YW5kYXJkIGVycm9yLCB0aGUgZXN0aW1hdG9yIGZvciB0aGUgcHJlY2lzaW9uIG9mIHRoZSBzYW1wbGUgbWVhbiwgaG93ZXZlciwgcmVkdWNlcyBjb25zaWRlcmFibHkgd2l0aCBpbmNyZWFzaW5nIHNhbXBsZSBzaXplIGFnYWluIGNvbmZpcm1pbmcgdGhhdCB0aGUgZXN0aW1hdGlvbiBvZiB0aGUgc2FtcGxlIG1lYW4gZ2V0cyBtb3JlIHByZWNpc2UuIAoKLS0tCgojIyMgTm9ybWFsbHkgZGlzdHJpYnV0ZWQgZGF0YQoKLSBGb3Igbm9ybWFsbHkgZGlzdHJpYnV0ZWQgZGF0YSB3ZSBoYXZlIG11bHRpcGxlIGVzdGltYXRvcnMgZm9yIHRoZSBwb3B1bGF0aW9uIG1lYW4gJFxtdSQgZS5nIG1lYW4gYW5kIG1lZGlhbi4KCi0gQnV0LCAkXGJhcntYfSQgaXMgdGhlIHVuYmlhc2VkIGVzdGltYXRvciBvZiAkXG11JCB3aXRoIHRoZSBzbWFsbGVzdCBzdGFuZGFyZCBlcnJvciAKCi0gICRcYmFye1h9JCBkZXZpYXRlcyBsZXNzIGZyb20gdGhlIG1lYW4gJFxtdSQgdGhhbiB0aGUgbWVkaWFuCgotIFdlIGlsbHVzdHJhdGUgdGhpcyBmb3IgcmVwZWF0ZWQgc2FtcGxpbmcgd2l0aCBzYW1wbGUgc2l6ZSAxMApgYGB7cn0KcmVzICU+JQogIGZpbHRlcihuPT0xMCkgJT4lCiAgc2VsZWN0KG1lYW4sbWVkaWFuKSAlPiUKICBnYXRoZXIodHlwZSxlc3RpbWF0ZSkgJT4lCiAgZ2dwbG90KGFlcyh4PXR5cGUseT1lc3RpbWF0ZSkpICsKICBnZW9tX2JveHBsb3QoKSsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQ9ZmVtJERpcmVjdENob2wlPiVsb2cyJT4lbWVhbikgKwogIGdndGl0bGUoIjEwIHN1YmplY3RzIikKYGBgCgpOZXh0LCB3ZSBjb21wYXJlIHRoZSBkaXN0cmlidXRpb24gb2YgbWVhbiBhbmQgbWVkaWFuIGluIHJlcGVhdGVkIHNhbXBsZXMgb2Ygc2FtcGxlIHNpemUgNTAuCgpgYGB7cn0KcmVzICU+JQogIGZpbHRlcihuPT01MCkgJT4lCiAgc2VsZWN0KG1lYW4sbWVkaWFuKSAlPiUKICBnYXRoZXIodHlwZSxlc3RpbWF0ZSkgJT4lCiAgZ2dwbG90KGFlcyh4PXR5cGUseT1lc3RpbWF0ZSkpICsKICBnZW9tX2JveHBsb3QoKSsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQ9ZmVtJERpcmVjdENob2wlPiVsb2cyJT4lbWVhbikgKwogIGdndGl0bGUoIjUwIHN1YmplY3RzIikKYGBgCgojIyMgRGlzdHJpYnV0aW9uIG9mIHNhbXBsZSBtZWFuCgoKLSBIb3cgdmFyaWVzICRcYmFyIFgkIGZyb20gc2FtcGxlIHRvIHNhbXBsZT8gCi0gRGlzdHJpYnV0aW9uIG9mICRcYmFyIFgkPwotIElmICRcYmFyIFgkIGlzIG5vcm1hbGx5IGRpc3RyaWJ1dGVkIHRoZSBzdGFuZGFyZCBlcnJvciBoYXMgYSBnb29kIGludGVycHJldGF0aW9uOiB0aGUgcy5lLiBpcyB0aGUgc3RhbmRhcmQgZGV2aWF0aW9uIG9mIHRoZSBzYW1wbGUgbWVhbi4KLSBJZiB0aGUgZGF0YSAkWF9pJCBhcmUgbm9ybWFsbHkgZGlzdHJpYnV0ZWQsIHRoZSBzYW1wbGUgbWVhbiBpcyBhbHNvIG5vcm1hbGx5IGRpc3RyaWJ1dGVkLiAKCiQkWF9pIFxzaW0gTihcbXUsXHNpZ21hXjIpIFxyaWdodGFycm93ICBcYmFyIFggXHNpbSBOKFxtdSwgIFxzaWdtYV4yL24pJCQKCi0tLQoKIyMjIyBOSEFORVM6IGNob2xlc3Rlcm9sCgpXZSBpbGx1c3RyYXRlIHRoaXMgYWdhaW4gd2l0aCBzaW11bGF0aW9uIHVzaW5nIHRoZSBOSEFORVMgc3R1ZHkuIApUaGUgbG9nMiBjaG9sZXN0ZXJvbCBsZXZlbHMgd2VyZSBub3JtYWxseSBkaXN0cmlidXRlZC4gCgpgYGB7cn0KIGZlbSAlPiUgCiAgZ2dwbG90KGFlcyh4PURpcmVjdENob2wlPiVsb2cyKSkrCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKHk9Li5kZW5zaXR5Li4sIGZpbGw9Li5jb3VudC4uKSkgKwogIHhsYWIoIkRpcmVjdCBjaG9sZXN0ZXJvbCAobG9nMikiKSArCiAgc3RhdF9mdW5jdGlvbihmdW49ZG5vcm0sY29sb3I9InJlZCIsYXJncz1saXN0KG1lYW49bWVhbihmZW0kRGlyZWN0Q2hvbCU+JWxvZzIpLCBzZD1zZChmZW0kRGlyZWN0Q2hvbCU+JWxvZzIpKSkgKwogIGdndGl0bGUoIkFsbCBmZW1hbGVzIGluIE5oYW5lcyBzdHVkeSIpCiAgCmZlbSAlPiUgCiAgZ2dwbG90KGFlcyhzYW1wbGU9RGlyZWN0Q2hvbCU+JWxvZzIpKSArCiAgc3RhdF9xcSgpICsKICBzdGF0X3FxX2xpbmUoKSArCiAgZ2d0aXRsZSgiQWxsIGZlbWFsZXMgaW4gTmhhbmVzIHN0dWR5IikKYGBgCgotLS0KCiMjIyMjIEV2YWx1YXRlIGRpc3RyaWJ1dGlvbiBmb3Igc2FtcGxlcyB3aXRoIDUgc3ViamVjdHMKCmBgYHtyfQpmZW1TYW1wNTwtc2FwcGx5KDE6MTAwMCxmdW5jdGlvbihqLHgsc2l6ZSkKICBzYW1wbGUoeCxzaXplKSxzaXplPTUseD1mZW0kRGlyZWN0Q2hvbCkKCmZlbVNhbXA1WywxXSAlPiUgCiAgbG9nMiAlPiUgCiAgYXMuZGF0YS5mcmFtZSAlPiUKICBnZ3Bsb3QoYWVzKHg9LikpKwogIGdlb21faGlzdG9ncmFtKGFlcyh5PS4uZGVuc2l0eS4uLCBmaWxsPS4uY291bnQuLiksYmlucz0xMCkgKwogIHhsYWIoIkRpcmVjdCBjaG9sZXN0ZXJvbCAobG9nMikiKSArCiAgc3RhdF9mdW5jdGlvbihmdW49ZG5vcm0sY29sb3I9InJlZCIsYXJncz1saXN0KG1lYW49ZmVtU2FtcDVbLDFdJT4lbG9nMiU+JW1lYW4sIHNkPWZlbVNhbXA1WywxXSU+JWxvZzIlPiVzZCkpICsKICBnZ3RpdGxlKCI1IHJhbmRvbSBmZW1hbGVzIikgKyAKICB4bGltKGZlbSREaXJlY3RDaG9sICU+JSBsb2cyICU+JSByYW5nZSkKCiAgCmZlbVNhbXA1ICU+JSAKICBsb2cyICU+JSAKICBjb2xNZWFucyAlPiUgCiAgYXMuZGF0YS5mcmFtZSAlPiUgCiAgZ2dwbG90KGFlcyh4PS4pKSArCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKHk9Li5kZW5zaXR5Li4sIGZpbGw9Li5jb3VudC4uKSxiaW5zPTE1KSArCiAgeGxhYigiTWVhbiBjaG9sZXN0ZXJvbCAobG9nMikiKSArCiAgc3RhdF9mdW5jdGlvbihmdW49ZG5vcm0sY29sb3I9InJlZCIsYXJncz1saXN0KG1lYW49ZmVtU2FtcDUlPiVsb2cyJT4lIGNvbE1lYW5zICU+JSBtZWFuLCBzZD1mZW1TYW1wNSU+JWxvZzIlPiUgY29sTWVhbnMgJT4lIHNkKSkgKwpnZ3RpdGxlKCJNZWFucyBvbiA1IGZlbWFsZXMiKSAKCmZlbVNhbXA1ICU+JSAKICBsb2cyICU+JSAKICBjb2xNZWFucyAlPiUgCiAgYXMuZGF0YS5mcmFtZSAlPiUgIAogIGdncGxvdChhZXMoc2FtcGxlPS4pKSArCiAgc3RhdF9xcSgpICsKICBzdGF0X3FxX2xpbmUoKSArCiAgZ2d0aXRsZSgiTWVhbnMgb24gNSBmZW1hbGVzIikKYGBgCgotLS0KCiMjIyMjIEV4cGxvcmUgdGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgbWVhbiBmb3Igc2FtcGxlcyBvZiBzaXplIDEwCgpOb3cgd2UgZXhwbG9yZSB0aGUgcmVzdWx0cyBmb3IgdGhlIHNhbXBsZSBzaXplIG9mIDEwLgoKV2UgZmlyc3QgaWxsdXN0cmF0ZSB0aGUgcGxvdCBmb3IgdGhlIGZpcnN0IHNhbXBsZS4gCgpgYGB7cn0KZmVtU2FtcDEwWywxXSAlPiUgbG9nMiAlPiUgYXMuZGF0YS5mcmFtZSAlPiUKZ2dwbG90KGFlcyh4PS4pKSsKICBnZW9tX2hpc3RvZ3JhbShhZXMoeT0uLmRlbnNpdHkuLiwgZmlsbD0uLmNvdW50Li4pLGJpbnM9MTApICsKICB4bGFiKCJEaXJlY3QgY2hvbGVzdGVyb2wgKGxvZzIpIikgKwogIHN0YXRfZnVuY3Rpb24oZnVuPWRub3JtLGNvbG9yPSJyZWQiLGFyZ3M9bGlzdChtZWFuPWZlbVNhbXAxMFssMV0lPiVsb2cyJT4lbWVhbiwgc2Q9ZmVtU2FtcDEwWywxXSU+JWxvZzIlPiVzZCkpICsKZ2d0aXRsZSgiMTAgcmFuZG9tIGZlbWFsZXMiKSArIAp4bGltKGZlbSREaXJlY3RDaG9sICU+JSBsb2cyICU+JSByYW5nZSkKYGBgCgpOZXh0IHdlIGxvb2sgYXQgdGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgc2FtcGxlIG1lYW4gb3ZlciAxMDAwIHNhbXBsZXMgb2Ygc2FtcGxlIHNpemUgMTAuIAoKYGBge3J9CmZlbVNhbXAxMCAlPiUgbG9nMiAlPiUgY29sTWVhbnMgJT4lIGFzLmRhdGEuZnJhbWUgJT4lIGdncGxvdChhZXMoeD0uKSkgKwogIGdlb21faGlzdG9ncmFtKGFlcyh5PS4uZGVuc2l0eS4uLCBmaWxsPS4uY291bnQuLiksYmlucz0xNSkgKwogIHhsYWIoIk1lYW4gY2hvbGVzdGVyb2wgKGxvZzIpIikgKwogIHN0YXRfZnVuY3Rpb24oZnVuPWRub3JtLGNvbG9yPSJyZWQiLGFyZ3M9bGlzdChtZWFuPWZlbVNhbXAxMCU+JWxvZzIlPiUgY29sTWVhbnMgJT4lIG1lYW4sIHNkPWZlbVNhbXAxMCU+JWxvZzIlPiUgY29sTWVhbnMgJT4lIHNkKSkgKwpnZ3RpdGxlKCJNZWFucyBvbiAxMCBmZW1hbGVzIikgCgpmZW1TYW1wMTAgJT4lIGxvZzIlPiUgY29sTWVhbnMgJT4lIGFzLmRhdGEuZnJhbWUgJT4lICBnZ3Bsb3QoYWVzKHNhbXBsZT0uKSkgKwpzdGF0X3FxKCkgKwpzdGF0X3FxX2xpbmUoKSArCmdndGl0bGUoIk1lYW5zIG9uIDEwIGZlbWFsZXMiKQpgYGAKCioqU28gd2UgY29uZmlybWVkIHRoYXQgdGhlIG1lYW4gaXMgYXBwcm94aW1hdGVseSBub3JtYWxseSBkaXN0cmlidXRlZCBmb3Igc3R1ZGllcyB3aXRoIDUgYW5kIDEwIGZlbWFsZXMgd2hlbiB0aGUgb3JpZ2luYWwgZGF0YSBhcmUgYXBwcm94aW1hdGVseSBub3JtYWxseSBkaXN0cmlidXRlZC4qKiAKCi0tLQoKIyMjIyBDYXB0b3ByaWwgc3R1ZHkKCi0gRm9yIENhcHRvcHJpbCBzdHVkeSB0aGUgc3lzdG9saWMgYmxvb2QgcHJlc3N1cmUgZGlmZmVyZW5jZXMgYXJlIGFwcHJveGltYXRpdmVseSBub3JtYWxseSBkaXN0cmlidXRlZC4gIAoKLSBzLmUuPSAyLjMyIG1tIEhnCgotIEluIDk1IG91dCBvZiAxMDAgc3R1ZGllcyB3aXRoIG4gPSAxNSBzdWJqZWN0cyB3ZSBleHBlY3QgdGhlIHNhbXBsZSBtZWFuIG9mIHRoZSBzeXN0b2xpYyBibG9vZCBwcmVzc3VyZSBkaWZmZXJlbmNlcyAoJFxiYXIgWCQpIG9uIGxlc3MgdGhlbiAkMiBcdGltZXMgMi4zMiA9IDQuNjQkbW0gSGcgb2YgdGhlIHJlYWwgcG9wdWxhdGlvbiBtZWFuIG9mIHRoZSBibG9vZCBwcmVzc3VyZSBkaWZmZXJlbmNlcyAoJFxtdSQpLgoKLS0tCgojIyMgTm9uLW5vcm1hbGx5IGRpc3RyaWJ1dGVkIGRhdGEKCi0gV2hlbiBpbmRpdmlkdWFsIG9ic2VydmF0aW9ucyBkbyBub3QgaGF2ZSBhIG5vcm1hbCBkaXN0cmlidXRpb24sICAgJFxiYXIgWCQgaXMgc3RpbGwgXHRleHRpdHthcHByb3hpbWF0ZWx5fSBOb3JtYWxseSBkaXN0cmlidXRlZCAKd2hlbiB0aGUgbnVtYmVyIG9ic2VydmF0aW9ucyBhcmUgbGFyZ2UgZW5vdWdoLgoKLSBIb3cgbGFyZ2UgZG9lcyB0aGUgc2FtcGxlIG5lZWRzIHRvIGJlIGZvciB0aGUgTm9ybWFsIGFwcHJveGltYXRpb24gdG8gd29yaz8gIAoKLSBUaGlzIGRlcGVuZHMgb24gdGhlIHNrZXduZXNzIG9mIHRoZSBkaXN0cmlidXRpb24hCgotLS0KCiMjIyMgTkhBTkVTOiBjaG9sZXN0ZXJvbAoKLSBXaGVuIGNhbiBldmFsdWF0ZWQgdGhpcyBpbiB0aGUgTkhhbmVzIHN0dWR5IGlmIHdlIGRvIG5vdCBsb2cyIHRyYW5zZm9ybSB0aGUgZGF0YS4KCmBgYHtyfQpmZW0gJT4lIGdncGxvdChhZXMoeD1EaXJlY3RDaG9sKSkrCiAgIGdlb21faGlzdG9ncmFtKGFlcyh5PS4uZGVuc2l0eS4uLCBmaWxsPS4uY291bnQuLikpICsKICAgeGxhYigiRGlyZWN0IGNob2xlc3Rlcm9sIikgKwogICBzdGF0X2Z1bmN0aW9uKGZ1bj1kbm9ybSxjb2xvcj0icmVkIixhcmdzPWxpc3QobWVhbj1tZWFuKGZlbSREaXJlY3RDaG9sKSwgc2Q9c2QoZmVtJERpcmVjdENob2wpKSkgKwogICBnZ3RpdGxlKCJBbGwgZmVtYWxlcyBpbiBOaGFuZXMgc3R1ZHkiKQoKIGZlbSAlPiUgZ2dwbG90KGFlcyhzYW1wbGU9RGlyZWN0Q2hvbCkpICsKIHN0YXRfcXEoKSArCiBzdGF0X3FxX2xpbmUoKSArCiBnZ3RpdGxlKCJBbGwgZmVtYWxlcyBpbiBOaGFuZXMgc3R1ZHkiKQpgYGAKClRoZSBjaG9sZXN0ZXJvbCBkYXRhIGlzIGNsZWFybHkgbm9uLU5vcm1hbGx5IGRpc3RyaWJ1dGVkLgoKIyMjIyMgRGlzdHJpYnV0aW9uIG9mIHRoZSBzYW1wbGUgbWVhbiBmb3IgZGlmZmVyZW50IHNhbXBsZSBzaXplcyAKCmBgYHtyfQpmZW1TYW1wNSAlPiUgY29sTWVhbnMgJT4lIGFzLmRhdGEuZnJhbWUgJT4lIGdncGxvdChhZXMoeD0uKSkgKwogIGdlb21faGlzdG9ncmFtKGFlcyh5PS4uZGVuc2l0eS4uLCBmaWxsPS4uY291bnQuLiksYmlucz0xNSkgKwogIHhsYWIoIk1lYW4gY2hvbGVzdGVyb2wiKSArCiAgc3RhdF9mdW5jdGlvbihmdW49ZG5vcm0sY29sb3I9InJlZCIsYXJncz1saXN0KG1lYW49ZmVtU2FtcDUlPiUgY29sTWVhbnMgJT4lIG1lYW4sIHNkPWZlbVNhbXA1JT4lIGNvbE1lYW5zICU+JSBzZCkpICsKZ2d0aXRsZSgiTWVhbnMgb24gNSBmZW1hbGVzIikgCgpmZW1TYW1wNSAlPiUgY29sTWVhbnMgJT4lIGFzLmRhdGEuZnJhbWUgJT4lICBnZ3Bsb3QoYWVzKHNhbXBsZT0uKSkgKwpzdGF0X3FxKCkgKwpzdGF0X3FxX2xpbmUoKSArCmdndGl0bGUoIk1lYW5zIG9uIDUgZmVtYWxlcyIpCgoKZmVtU2FtcDEwICU+JSBjb2xNZWFucyAlPiUgYXMuZGF0YS5mcmFtZSAlPiUgZ2dwbG90KGFlcyh4PS4pKSArCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKHk9Li5kZW5zaXR5Li4sIGZpbGw9Li5jb3VudC4uKSxiaW5zPTE1KSArCiAgeGxhYigiTWVhbiBjaG9sZXN0ZXJvbCIpICsKICBzdGF0X2Z1bmN0aW9uKGZ1bj1kbm9ybSxjb2xvcj0icmVkIixhcmdzPWxpc3QobWVhbj1mZW1TYW1wMTAlPiUgY29sTWVhbnMgJT4lIG1lYW4sIHNkPWZlbVNhbXAxMCU+JSBjb2xNZWFucyAlPiUgc2QpKSArCmdndGl0bGUoIk1lYW5zIG9uIDEwIGZlbWFsZXMiKSAKCmZlbVNhbXAxMCAlPiUgY29sTWVhbnMgJT4lIGFzLmRhdGEuZnJhbWUgJT4lICBnZ3Bsb3QoYWVzKHNhbXBsZT0uKSkgKwpzdGF0X3FxKCkgKwpzdGF0X3FxX2xpbmUoKSArCmdndGl0bGUoIk1lYW5zIG9uIDEwIGZlbWFsZXMiKQoKZmVtU2FtcDUwICU+JSBjb2xNZWFucyAlPiUgYXMuZGF0YS5mcmFtZSAlPiUgIGdncGxvdChhZXMoc2FtcGxlPS4pKSArCnN0YXRfcXEoKSArCnN0YXRfcXFfbGluZSgpICsKZ2d0aXRsZSgiTWVhbnMgb24gNTAgZmVtYWxlcyIpCgpmZW1TYW1wMTAwICU+JSBjb2xNZWFucyAlPiUgYXMuZGF0YS5mcmFtZSAlPiUgIGdncGxvdChhZXMoc2FtcGxlPS4pKSArCnN0YXRfcXEoKSArCnN0YXRfcXFfbGluZSgpICsKZ2d0aXRsZSgiTWVhbnMgb24gMTAwIGZlbWFsZXMiKQpgYGAKCi0gKipXZSBvYnNlcnZlIHRoYXQgd2hlbiB0aGUgZGF0YSBhcmUgbm90IG5vcm1hbGx5IGRpc3RyaWJ1dGVkIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIHNhbXBsZSBtZWFuIGlzIG5vdCBub3JtYWxseSBkaXN0cmlidXRlZCBpbiBzbWFsbCBzYW1wbGVzKiogCgotICoqRm9yIGxhcmdlIHNhbXBsZXMsIGhvd2V2ZXIsIHRoZSBzYW1wbGUgbWVhbiBvZiBub24gbm9ybWFsIGRhdGEgaXMgc3RpbGwgYXBwcm94aW1hdGVseSBub3JtYWxseSBkaXN0cmlidXRlZC4qKgoKLS0tCgojIyMgQ2VudHJhbGUgTGltaXQgVGhlb3JlbQoKTGV0ICRYXzEsIFxsZG90cywgWF9uJCBhcmUgc2VxdWVuY2Ugb2YgcmFuZG9tIHZhcmlhYmxlcyB0aGF0IGFyZSBkcmF3biBpbmRlcGVuZGVudGx5IGZyb20gdGhlIHNhbWUgZGlzdHJpYnV0aW9uIChwb3B1bGF0aW9uKS4KQXMgbG9uZyBhcyB0aGUgc2FtcGxlIHNpemUgbiBpcyBzdWZmaWNpZW50bHkgbGFyZ2UsIHRoZSBzYW1wbGUgbWVhbiAkXGJhciBYJCBpcyBhcHByb3hpbWF0ZWx5IG5vcm1hbGx5IGRpc3RyaWJ1dGVkLCBpcnJlc3BlY3RpdmUgb2YgdGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgb2JzZXJ2YXRpb25zICRYX2kkLgoKIyMjIE92ZXJ2aWV3IG9uIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIG1lYW4KCiFbXShodHRwczovL3d3dy5uYXR1cmUuY29tL2FydGljbGVzL25tZXRoLjI2MTMucGRmKXt3aWR0aD0xMDAlfQoKLS0tCgojSW50ZXJ2YWwgZXN0aW1hdG9ycwoKLSAkXGJhciBYJCB2YXJpZXMgYXJvdW5kICRcbXUkIAoKLSBIZXJlIHdlIHdpbGwgZGV2ZWxvcCBhbiBpbnRlcnZhbCBhcm91bmQgJFxiYXIgWCQgdGhhdCB3aWxsIGNvbnRhaW4gdGhlIHZhbHVlIG9mICRcbXUkIHdpdGggYSBwcm9iYWJpbGl0eSBvZiA5NSUgZm9yIGEgcmFuZG9tIHNhbXBsZS4gCgotIFdlIGZpcnN0IGFzc3VtZSAkXHNpZ21hXjIkIHRvIGJlIGtub3duIGFuZCB3ZSB3aWxsIGxhdGVyIHJlbGF4IHRoaXMgYXNzdW1wdGlvbi4gCgotLS0KCiMjIE5vcm1hbGx5IGRpc3RyaWJ1dGVkIGRhdGEgd2l0aCBrbm93biB2YXJpYW5jZQoKLSAkWFxzaW0gTihcbXUsXHNpZ21hXjIpIFxyaWdodGFycm93IFxiYXIgWFxzaW0gTlxsZWZ0KFxtdSxcZnJhY3tcc2lnbWFeMn17bn1ccmlnaHQpJAoKLSA5NSUgcmVmZXJlbmNlLWludGVydmFsIGZvciBzYW1wbGUgbWVhbgoKXGJlZ2lue2VxdWF0aW9uKn0KXGxlZnRbXG11IC0gMS45NiBcZnJhY3tcc2lnbWF9e1xzcXJ0e259fSxcbXUgKyAxLjk2IFxmcmFje1xzaWdtYX17XHNxcnR7bn19JQpccmlnaHRdClxlbmR7ZXF1YXRpb24qfQoKLSBUaGUgaW50ZXJ2YWwgY29udGFpbnMgdGhlIHNhbXBsZSBtZWFuIG9mIGEgcmFuZG9tIHNhbXBsZSB3aXRoIGEgcHJvYmFiaWxpdHkgb2YgOTUlLiAKCi0gV2UgY2FuIG5vdCBjYWxjdWxhdGUgaXQgYmVjYXVzZSAkXG11JCBpcyB1bmtub3duLgoKLSBFc3RpbWF0ZSAkXG11JCBieSAkXGJhciBYJC4gIApcYmVnaW57ZXF1YXRpb24qfQpcbGVmdFtcYmFyIFggLSAxLjk2IFxmcmFje1xzaWdtYX17XHNxcnR7bn19LFxiYXIgWCArIDEuOTYgXGZyYWN7XHNpZ21hfXtcc3FydHtufX1ccmlnaHRdClxlbmR7ZXF1YXRpb24qfQoKCi0gTW9yZSB1c2VmdWwgaW50ZXJwcmV0YXRpb246Clx2c3BhY2V7MTVwdH0KLSBSZXdyaXRlICRcbXUgLSAxLjk2IFwgXHNpZ21hL1xzcXJ0e259IDwgXGJhcntYfSQgYXMgJFxtdSA8IFxiYXJ7WH0gKyAxLjk2IFwgXHNpZ21hL1xzcXJ0e259JC4KClNvIHRoYXQgd2UgY2FuIHdyaXRlClxiZWdpbntlcW5hcnJheSp9Cjk1XCUgJj0mIFAoIFxtdSAtIDEuOTYgXCBcc2lnbWEvXHNxcnR7bn0gPCBcYmFye1h9IDwgXG11ICsgMS45NiBcIFxzaWdtYS9cc3FydHtufSApIFxcCiY9JlAoIFxiYXJ7WH0gLSAxLjk2IFwgXHNpZ21hL1xzcXJ0e259IDwgXG11IDwgXGJhcntYfSArIDEuOTYgXCBcc2lnbWEvXHNxcnR7bn0gKQpcZW5ke2VxbmFycmF5Kn0KCi0tLQoKKipEZWZpbml0aW9uIG9mIDk1JSBjb25maWRlbmNlIGludGVydmFsIG9uIG1lYW4qKgpGb3IgYSByYW5kb20gc2FtcGxlLCB0aGUgaW50ZXJ2YWwKXGJlZ2lue2VxdWF0aW9ufSAgCltcYmFye1h9IC0gMS45NiBcIFxzaWdtYS9cc3FydHtufSAsIFxiYXJ7WH0gKyAxLjk2IFwgXHNpZ21hL1xzcXJ0e259IF0sClxlbmR7ZXF1YXRpb259CmNvbnRhaW5zIHRoZSBwb3B1bGF0aW9uIG1lYW4gJFxtdSQgd2l0aCBhIHByb2JhYmlsaXR5IG9mIDk1JS4KCi0tLQoKLSBUaGUgcHJvYmFiaWxpdHkgdGhhdCB0aGUgQ0kgZm9yIGEgcmFuZG9tIHNhbXBsZSBjb250YWlucyB0aGUgcG9wdWxhdGlvbiBwYXJhbWV0ZXIgJFxtdSQsIGkuZS4gOTUlLCBpcyBhbHNvIHJlZmVycmVkIHRvIGFzIHRoZSAqKmNvbmZpZGVuY2UgbGV2ZWwqKi4KCi0gTm90ZSwgdGhhdCB0aGUgbG93ZXIgYW5kIHVwcGVyIGxpbWl0IG9mIHRoZSBpbnRlcnZhbCBhcmUgYWxzbyByYW5kb20gdmFyaWFibGVzIHRoYXQgdmFyeSBmcm9tIHNhbXBsZSB0byBzYW1wbGUuIERpZmZlcmVudCBzYW1wbGVzIGluZGVlZCByZXN1bHQgaW4gZGlmZmVyZW50IGNvbmZpZGVuY2UgaW50ZXJ2YWxzIGJlY2F1c2UgdGhleSBhcmUgYmFzZWQgb24gZGlmZmVyZW50IG9ic2VydmF0aW9uLiAKCi0gU28gdGhleSBhcmUgKnN0b2NoYXN0aWMgaW50ZXJ2YWxzKgoKLSA5NSUgb2YgdGhlIHNhbXBsZXMgd2lsbCBwcm9kdWNlIGEgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWwgdGhhdCB3aWxsIGNvbnRhaW4gdGhlIHBvcHVsYXRpb24gbWVhbiAkXG11JC4gVGhlIHJlbWFpbmluZyA1JSB3aWxsIHByb2R1Y2UgaW50ZXJ2YWxzIHRoYXQgZG8gbm90IGNvbnRhaW4gdGhlIHBvcHVsYXRpb24gbWVhbi4gCgotIEJhc2VkIG9uIG9uZSBpbnRlcnZhbCB5b3UgY2Fubm90IGNvbmNsdWRlIHRoYXQgaXQgY29udGFpbnMgdGhlIHJlYWwgcG9wdWxhdGlvbiBwYXJhbWV0ZXIsIGJlY2F1c2UgaXRzIHZhbHVlIGlzIHVua25vd24uIAoKR2VuZXJhbGx5IHRoZSBzdGFuZGFyZCBkZXZpYXRpb24gaXMgdW5rbm93biBhbmQgaGFzIHRvIGJlIGVzdGltYXRlZCBlLmcuIGJ5ICRTJAoKLSBGb3IgbGFyZ2UgJG4kICRbXGJhcntYfSAtIDEuOTYgXCBzL1xzcXJ0e259ICwgXGJhcntYfSArIDEuOTYgXCBzL1xzcXJ0e259IF0kIHdpbGwgY29udGFpbiB0aGUgcG9wdWxhdGlvbiBtZWFuIHdpdGggYSBwcm9iYWJpbGl0eSBvZiBhcHByb3hpbWF0ZWx5IDk1JS4gCgotLS0KCiMjIyBOSEFORVMgbG9nMiBjaG9sZXN0ZXJvbCBleGFtcGxlCgojIyMjIE9uZSBzYW1wbGUKYGBge3J9CnNhbXA1MDwtc2FtcGxlKGZlbSREaXJlY3RDaG9sLDUwKQoKbGw8LW1lYW4oc2FtcDUwICU+JSBsb2cyKSAtIDEuOTYqc2Qoc2FtcDUwICU+JSBsb2cyKS9zcXJ0KDUwKQp1bDwtbWVhbihzYW1wNTAgJT4lIGxvZzIpICsgMS45NipzZChzYW1wNTAgJT4lIGxvZzIpL3NxcnQoNTApCnBvcE1lYW48LW1lYW4oZmVtJERpcmVjdENob2wlPiVsb2cyKQoKYyhsbD1sbCx1bD11bCxwb3BNZWFuPXBvcE1lYW4pCmBgYAoKIyMjIyBSZXBlYXRlZCBzYW1wbGluZwpgYGB7cn0KcmVzJGxsPC1yZXMkbWVhbi0xLjk2KnJlcyRzZQpyZXMkdWw8LXJlcyRtZWFuKzEuOTYqcmVzJHNlCm11PC1mZW0kRGlyZWN0Q2hvbCU+JWxvZzIlPiVtZWFuCnJlcyRpbnNpZGU8LXJlcyRsbDw9bXUgJiBtdTw9cmVzJHVsCnJlcyRuIDwtIGFzLmZhY3RvcihyZXMkbikKcmVzICU+JSAKICBncm91cF9ieShuKSAlPiUgCiAgc3VtbWFyaXplKGNvdmVyYWdlPW1lYW4oaW5zaWRlKSkgJT4lIAogIHNwcmVhZChuLGNvdmVyYWdlKSAKYGBgCgotIE5vdGUsIHRoYXQgdGhlIGNvdmVyYWdlIGluIHRoZSBzYW1wbGVzIHdpdGggMTAgb2JzZXJ2YXRpb25zIGlzIHRvbyBsb3cgYmVjYXVzZSB3ZSBkbyBub3QgYWNjb3VudCBmb3IgdGhlIHVuY2VydGFpbnR5IGluIHRoZSBlc3RpbWF0aW9uIG9mIHRoZSBzdGFuZGFyZCBkZXZpYXRpb24uIAoKLSBJZiB3ZSBsb29rIHRvIHRoZSBmaXJzdCAyMCBpbnRlcnZhbHMsIGByIHN1bSgoIXJlc1tyZXMkbj09MTAsImluc2lkZSJdKVsxOjIwXSlgICBvdXQgb2YgMjAgZG8gbm90IGNvbnRhaW4gdGhlIHBvcHVsYXRpb24gbWVhbi4KCmBgYHtyfQpyZXMgJT4lIAogIGZpbHRlcihuPT0xMCkgJT4lIAogIHNsaWNlKDE6MjApICU+JQogIGdncGxvdChhZXMoeD1zYW1wbGUseT1tZWFuLGNvbG9yPWluc2lkZSkpICsgCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluPW1lYW4tMS45NipzZSx5bWF4PW1lYW4rMS45NipzZSkpKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IGZlbSREaXJlY3RDaG9sJT4lIGxvZzIgJT4lIG1lYW4pICsgCiAgZ2d0aXRsZSgiMjAgQ0kgZm9yIE49MTAiKSArIAogIHlsaW0ocmFuZ2UoZmVtJERpcmVjdENob2wgJT4lIGxvZzIpKQpgYGAKCi0tLQoKLSBGb3IgbGFyZ2Ugc2FtcGxlIHNpemVzICgxMDApIHRoZSBjb3ZlcmFnZSBpcyBmaW5lIGJlY2F1c2Ugd2UgY2FuIGVzdGltYXRlIHRoZSBzdGFuZGFyZCBkZXZpYXRpb24gd2l0aCBhIHJlbGF0aXZlIGhpZ2ggcHJlY2lzaW9uLiAgCgpgYGB7cn0KcmVzICU+JSAKICBmaWx0ZXIobj09NTApICU+JSAKICBzbGljZSgxOjIwKSAlPiUKICBnZ3Bsb3QoYWVzKHg9c2FtcGxlLHk9bWVhbixjb2xvcj1pbnNpZGUpKSArIAogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbj1tZWFuLTEuOTYqc2UseW1heD1tZWFuKzEuOTYqc2UpKSsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBmZW0kRGlyZWN0Q2hvbCU+JSBsb2cyICU+JSBtZWFuKSArCiAgZ2d0aXRsZSgiMjAgQ0kgZm9yIE49NTAiKSArCiAgeWxpbShyYW5nZShmZW0kRGlyZWN0Q2hvbCAlPiUgbG9nMikpCgpyZXMgJT4lIAogIGZpbHRlcihuPT0xMDApICU+JSAKICBzbGljZSgxOjIwKSAlPiUKICBnZ3Bsb3QoYWVzKHg9c2FtcGxlLHk9bWVhbixjb2xvcj1pbnNpZGUpKSArIAogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbj1tZWFuLTEuOTYqc2UseW1heD1tZWFuKzEuOTYqc2UpKSsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBmZW0kRGlyZWN0Q2hvbCU+JSBsb2cyICU+JSBtZWFuKSArCiAgZ2d0aXRsZSgiMjAgQ0kgZm9yIE49MTAwIikgKwogIHlsaW0ocmFuZ2UoZmVtJERpcmVjdENob2wgJT4lIGxvZzIpKQpgYGAKCi0gV2hhdCBoYXZlIHlvdSBvYnNlcnZlZCBmb3IgdGhlIGludGVydmFsIHdpZHRoPyAKCi0tLQoKIyMjIE90aGVyIGNvbmZpZGVuY2UgbGV2ZWxzIAoKLSBXZSBjYW4gcmVwbGFjZSB0aGUgJHpfezIuNVwlfT0xLjk2JCBieSBhbm90aGVyIHF1YW50aWxlIG9mIHRoZSBub3JtYWwgZGlzdHJpYnV0aW9uICR6X3tcYWxwaGEvMn0gdG8gb2J0YWluIGFuIGludGVydmFsIHdpdGggYW5vdGhlciBjb25maWRlbmNlIGxldmVsICQxLVxhbHBoYSQuIAoKLSBDb25maWRlbmNlIGludGVydmFscyBhcmUgbm90IG9ubHkgdXNlZCBmb3IgdGhlIG1lYW4gYnV0IGFsc28gZm9yIG90aGVyIHBvcHVsYXRpb24gcGFyYW1ldGVycy4gCgotLS0KCiMjIFVua25vd24gdmFyaWFuY2UKCkluIHJlYWwgZXhhbXBsZXMgJFxzaWdtYSQgaXMgdW5rbm93biBhbmQgZXN0aW1hdGVkIGJhc2VkIG9uIHRoZSBzYW1wbGUgdXNpbmcgdGhlIHNhbXBsZSBzdGFuZGFyZCBkZXZpYXRpb24gJFMkLiAKCi0gVGhlIHByZXZpb3VzIGludGVydmFscyB3ZXJlIGEgYml0IHRvIHNtYWxsIGJlY2F1c2UgdGhleSBkaWQgbm90IGFjY291bnQgZm9yIHRoZSB1bmNlcnRhaW50eSBvbiB0aGUgZXN0aW1hdGlvbiBvZiAkUyQuIAoKLSBXaGVuICRuJCBpcyBsYXJnZSwgJFMkIGlzIGNsb3NlIHRvICRcc2lnbWEkLiAKCi0gSGVuY2UsICR7KFxiYXJ7WH0gLSBcbXUpfS97KFMvXHNxcnR7bn0pIH0kIGlzIGFwcHJveGltYXRlbHkgc3RhbmRhcmQgbm9ybWFsIGFuZCAKXGJlZ2lue2VxdWF0aW9uKn0KXGxlZnRbXGJhcntYfSAtIHpfe1xhbHBoYS8yfSBcIFxmcmFje1N9e1xzcXJ0e259fSAsIFxiYXJ7WH0gKyB6X3tcYWxwaGEvMn0gXApcZnJhY3tTfXtcc3FydHtufX1ccmlnaHRdClxlbmR7ZXF1YXRpb24qfQppcyBhbiBhcHByb3hpbWF0ZSAkKDEtIFxhbHBoYSkxMDBcJSQgQ0kgZm9yICRcbXUkLgoKLSBGb3Igc21hbGwgc2FtcGxlcyB0aGlzIG5vIGxvbmdlciBob2xkcyAoZS5nLiBuPTEwKSAKClRoZSBlc3RpbWF0aW9uIG9mICRTJCBpbnRyb2R1Y2VzIGFkZGl0aW9uYWwgdW5jZXJ0YWludHkgaW4gdGhlIHN0YW5kYXJkaXplZCB2YWx1ZSAkeyhcYmFye1h9IC0gXG11KX0veyhTL1xzcXJ0e259KX0kLiBJdHMgZGlzdHJpYnV0aW9uCgotIGlzIHN0aWxsIHN5bW1ldHJpYyBidXQgaGFzIGhlYXZpZXIgdGFpbHMgdGhhdCB0aGUgbm9ybWFsIGRpc3RyaWJ1dGlvbi4gCgotIGl0IGRlcGVuZHMgb24gJG4kIGhvdyBtdWNoIGhlYXZpZXIgdGhlIHRhaWxzIGFyZSAgCgotIGlzIGEgKFN0dWRlbnQpICR0JC1kaXN0cmlidXRpb24gd2l0aCAkbi0xJCAqZGVncmVlcyBvZiBmcmVlZG9tKi4KCi0tLQoKIyMjIFQtZGlzdHJpYnV0aW9uCgpNb3JlIGZvcm1hbGx5OiBMZXQgJFhfMSwgWF8yLCAuLi4sIFhfbiQgYmUgYW4gaW5kZXBlbmRlbnQgcmFuZG9tIHNhbXBsZSBmcm9tIGEgTm9ybWFsIGRpc3RyaWJ1dGlvbiAkTihcbXUsIFxzaWdtYV4yKSQsIHRoZW4gJChcYmFye1h9IC0gXG11KS8oUy9cc3FydHtufSkkIGZvbGxvd3MgYSAkdCQtZGlzdHJpYnV0aW9uIHdpdGggJG4tMSQgZGVncmVlcyBvZiBmcmVlZG9tLgoKVGhlIGRlbnNpdHkgb2YgYSB0LWRpc3RyaWJ1dGlvbiBjYW4gYmUgY2FsY3VsYXRlZCBpbiBSIHVzaW5nIHRoZSBmdW5jdGlvbiBgZHRgLiBJdCBoYXMgYXJndW1lbnRzIGB4YCBmb3IgdGhlIHF1YW50aWxlIGFuZCBgZGZgIGZvciB0aGUgZGVncmVlcyBvZiBmcmVlZG9tLiAKCmBgYHtyIGV2YWw9RkFMU0V9CmdyaWQgPC0gc2VxKC01LDUsLjEpCmRlbnNEaXN0PC1jYmluZChncmlkLGRub3JtKGdyaWQpLCBzYXBwbHkoYygyLDUsMTApLGR0LHg9Z3JpZCkpCmNvbG5hbWVzKGRlbnNEaXN0KTwtYygieCIsIm5vcm1hbCIscGFzdGUwKCJ0IixjKDIsNSwxMCkpKQoKZGVuc0Rpc3QgJT4lIGFzLmRhdGEuZnJhbWUgJT4lIGdhdGhlcihkaXN0LGRlbnMsLXgpICU+JQpnZ3Bsb3QoYWVzKHg9eCx5PWRlbnMsY29sb3I9ZGlzdCkpICsKZ2VvbV9saW5lKCkgKwp5bGFiKCJEZW5zaXR5IikKYGBgCgoKdC1kaXN0cmlidXRpb25zIGhhdmUgaGVhdmllciB0YWlscyB0aGVuIHRoZSBub3JtYWwgZGlzdHJpYnV0aW9uICRccmlnaHRhcnJvdyQgbGFyZ2VyIHF1YW50aWxlcyBzbyBicm9hZGVyIGludGVydmFscyBmb3IgdGhlIHNhbWUgY29uZmlkZW5jZSBsZXZlbC4gCgotIFRoaXMgY2FwdHVyZXMgdGhlIGFkZGl0aW9uYWwgdW5jZXJ0YWludHkgZm9yIGVzdGltYXRpbmcgJFMkLiAKCi0gSWYgJG4gXHJpZ2h0YXJyb3cgXGluZnR5JCB0aGVuICR0KGRmKSBccmlnaHRhcnJvdyBOKDAsMSkkCgoKLSBxdWFudGlsZXMgb2YgdGhlICR0JC1kaXN0cmlidXRpb24gY2FuIGJlIGNhbGN1bGF0ZWQgaW4gUiB1c2luZyBgcXRgLiBlLmcuIDk1JSwgOTcuNSUsIDk5LjUlIHF1YW50aWxlIGZvciBhIHQtZGlzdHJpYnV0aW9uIHdpdGggMTQgZGVncmVlcyBvZiBmcmVlZG9tOiAKYGBge3J9CnF0KC45NzUsZGY9MTQpCnF0KGMoLjk1LC45NzUsLjk5NSksZGY9MTQpCmBgYAoKLSBUaGVzZSBxdWFudGlsZXMgY2FuIGJlIHVzZWQgdG8gY2FsY3VsYXRlIDkwJSwgOTUlIGFuZCA5OSUgQ0kuIAoKLSA5Ny41JSBxdWFudGlsZWByIHJvdW5kKHF0KC45NzUsZGY9MTQpLDIpYCBvZiBhIHQtZGlzdHJpYnV0aW9uIHdpdGggJG4tMT0xNCQgZGVncmVlcyBvZiBmcmVlZG9tIGlzIGluZGVlZCBsYXJnZXIgdGhhbiB0aGF0IG9mIGEgc3RhbmRhcmQgTm9ybWFsIGRpc3RyaWJ1dGlvbiBgciByb3VuZChxbm9ybSguOTc1KSwyKWAuCgotLS0KCiMjIyBDb25maWRlbmNlIGludGVydmFsIGJhc2VkIG9uIHRoZSB0LWRpc3RyaWJ1dGlvbgoKVGhlICQxMDBcJSAoMS1cYWxwaGEpJCBDSSBmb3IgdGhlIG1lYW4gJFxtdSQgb2YgYSAKTm9ybWFsIGRpc3RyaWJ1dGVkIHJhbmRvbSB2YXJpYWJsZSAkWCQgd2l0aCB1bmtub3duIHZhcmlhbmNlIGlzCgpcYmVnaW57ZXF1YXRpb24qfQpcbGVmdFtcYmFye1h9IC0gdF97bi0xLCBcYWxwaGEvMn0gXGZyYWN7c317XHNxcnR7bn19ICwgXGJhcntYfSArIHRfe24tMSwKXGFscGhhLzJ9IFxmcmFje3N9e1xzcXJ0e259fVxyaWdodF0KXGVuZHtlcXVhdGlvbip9CgotIFdlIHNpbXBseSByZXBsYWNlIHRoZSAkKDEtXGFscGhhLzIpMTAwXCUkIHF1YW50aWxlIG9mIHRoZSBOb3JtYWwgZGlzdHJpYnV0aW9uIGJ5IHRoYXQgb2YgdGhlIHQtZGlzdHJpYnV0aW9uIHdpdGggJG4tMSQgZGVncmVlcyBvZiBmcmVlZG9tLgoKIyMjIyBDYXB0b3ByaWwgZXhhbXBsZQoKCjk1JSBDSSBmb3IgdGhlIGF2ZXJhZ2UgYmxvb2QgcHJlc3N1cmUgY2hhbmdlIGJlY29tZXMKCmBgYHtyfQptZWFuKGNhcHRvcHJpbCRkZWx0YVNCUCkgLSAgcXQoLjk3NSxkZj0xNCkqc2QoY2FwdG9wcmlsJGRlbHRhU0JQKS9zcXJ0KDE1KQptZWFuKGNhcHRvcHJpbCRkZWx0YVNCUCkgKyBxdCguOTc1LGRmPTE0KSpzZChjYXB0b3ByaWwkZGVsdGFTQlApL3NxcnQoMTUpCmBgYAoKVGhlIDk5JSBDSSBpcyBnaXZlbiBieQpgYGB7cn0KbWVhbihjYXB0b3ByaWwkZGVsdGFTQlApIC0gIHF0KC45OTUsZGY9MTQpKnNkKGNhcHRvcHJpbCRkZWx0YVNCUCkvc3FydCgxNSkKbWVhbihjYXB0b3ByaWwkZGVsdGFTQlApICsgcXQoLjk5NSxkZj0xNCkqc2QoY2FwdG9wcmlsJGRlbHRhU0JQKS9zcXJ0KDE1KQpgYGAKCk5vdGUsIHRoYXQgemVybyBpcyBvdXRzaWRlIHRoZSBpbnRlcnZhbCBhbmQgdGhhdCB0aGUgZW50aXJlIGludGVydmFsIGlzIG5lZ2F0aXZlIGluZGljYXRpbmcgdGhhdCB0aGVyZSBpcyBvbiBhdmVyYWdlIGEgbGFyZ2UgZWZmZWN0IGJ5IGFkbWluaXN0cmF0aW5nIGNhcHRvcHJpbCBvbiB0aGUgYmxvb2QgcHJlc3N1cmUgb2YgcGF0aWVudHMgd2l0aCBoeXBlcnRlbnNpb24uIAoKLS0tCgojIyMgSW50ZXJwcmV0YXRpb24gb2YgdGhlIGNvbmZpZGVuY2UgaW50ZXJ2YWwgCgotIFdlIHdpbGwgcmV2aXNpdCB0aGUgcmVzdWx0cyBmb3Igc2FtcGxpbmcgbG9nMiBjaG9sZXN0ZXJvbCBsZXZlbHMgZnJvbSB0aGUgbGFyZ2UgTkhBTkVTIHN0dWR5LiBXZSBmaXJzdCBmb2N1cyBvbiB0aGUgcmVwZWF0ZWQgZXhwZXJpbWVudHMgd2l0aCBzYW1wbGUgc2l6ZSAxMC4gCgpgYGB7cn0KcmVzJG48LWFzLmNoYXJhY3RlcihyZXMkbikgJT4lIGFzLmRvdWJsZShyZXMkbikKcmVzJGxsPC1yZXMkbWVhbi1xdCgwLjk3NSxkZj1yZXMkbi0xKSpyZXMkc2UKcmVzJHVsPC1yZXMkbWVhbitxdCgwLjk3NSxkZj1yZXMkbi0xKSpyZXMkc2UKbXU8LWZlbSREaXJlY3RDaG9sJT4lbG9nMiU+JW1lYW4KcmVzJGluc2lkZTwtcmVzJGxsPD1tdSAmIG11PD1yZXMkdWwKcmVzJG4gPC0gYXMuZmFjdG9yKHJlcyRuKQpyZXMgJT4lIGdyb3VwX2J5KG4pICU+JSBzdW1tYXJpemUoY292ZXJhZ2U9bWVhbihpbnNpZGUpKSAlPiUgc3ByZWFkKG4sY292ZXJhZ2UpIApgYGAKCldlIG9ic2VydmUgdGhhdCBhbGwgdGhlIGNvdmVyYWdlcyBvZiB0aGUgaW50ZXJ2YWxzIGFyZSBub3cgY29udHJvbGxlZCBhdCB0aGVpciBub21pbmFsIDk1JSBjb25maWRlbmNlIGxldmVsLgoKYGBge3J9CnJlcyAlPiUgCiAgZmlsdGVyKG49PTEwKSAlPiUgCiAgc2xpY2UoMToyMCkgJT4lCiAgZ2dwbG90KGFlcyh4PXNhbXBsZSx5PW1lYW4sY29sb3I9aW5zaWRlKSkgKyAKICBnZW9tX3BvaW50KCkgKwogIGdlb21fZXJyb3JiYXIoYWVzKHltaW49bWVhbi1xdCgwLjk3NSxkZj05KSpzZSx5bWF4PW1lYW4rcXQoMC45NzUsZGY9OSkqc2UpKSsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSBmZW0kRGlyZWN0Q2hvbCU+JSBsb2cyICU+JSBtZWFuKSArIAogIGdndGl0bGUoIjIwIENJIGZvciBOPTEwIikgKyAKICB5bGltKHJhbmdlKGZlbSREaXJlY3RDaG9sICU+JSBsb2cyKSkKYGBgCgohW10oaHR0cHM6Ly93d3cubmF0dXJlLmNvbS9hcnRpY2xlcy9ubWV0aC4yNjU5LnBkZil7d2lkdGg9MTAwJX0KCi0tLQoKIyMgUmVwb3J0aW5nPwoKLSBBbHdheXMgcmVwb3J0IHRoZSB1bmNlcnRhaW50eSBvbiB0aGUgcmVzdWx0cyEKCi0gQ29uY2x1c2lvbnMgYmFzZWQgb24gYSBwb2ludCBlc3RpbWF0ZSBjYW4gYmUgdmVyeSBtaXNsZWFkaW5nLiAKCi0gVXBvbiBhIHN0YXRpc3RpY2FsIGFuYWx5c2lzIHdlIHRoZXJlZm9yZSBhbHdheXMgcmVwb3J0IGNvbmZpZGVuY2UgaW50ZXJ2YWxzCgotIFRoZXkgYXJlIHNtYWxsIGVub3VnaCB0byBiZSBpbmZvcm1hdGl2ZSBidXQgYWxtb3N0IG5ldmVyIG1pc2xlYWRpbmcKCi0gVGhleSBmb3JtIGEgZ29vZCB0cmFkZS1vZmYgYmV0d2VlbiBzdGF0aXN0aWNhbCBzaWduaWZpY2FuY2UgYW5kIGJpb2xvZ2ljYWwgcmVsZXZhbmNlLiAKCi0gV2UgY29uY2x1ZGUgdGhhdCB0aGUgcG9wdWxhdGlvbiBwYXJhbWV0ZXIgbGF5cyBpbiB0aGUgaW50ZXJ2YWwgYW5kIGtub3cgdGhhdCB0aGlzIHN0YXRlbWVudCBob2xkcyB3aXRoIGEgcHJvYmFiaWxpdHkgb2YgOTUlIGZvciByYW5kb20gc2FtcGxlcy4gCgojIyMgQ2FwdG9wcmlsIGV4YW1wbGUKCldlIGNvbmNsdWRlIHRoYXQgdGhlIGJsb29kIHByZXNzdXJlIGRlY3JlYXNlcyBvbiBhdmVyYWdlIHdpdGggCmByIGFicyhyb3VuZChtZWFuKGNhcHRvcHJpbCRkZWx0YVNCUCksMSkpYG1tSGcgdXBvbiBhZG1pbmlzdGVyaW5nIGNhcHRvcHJpbCAoOTUlIENJIFtgciBwYXN0ZShyb3VuZChtZWFuKGNhcHRvcHJpbCRkZWx0YVNCUCkrcXQoYygwLjAyNSwuOTc1KSxuLTEpKnNkKGNhcHRvcHJpbCRkZWx0YVNCUCkvc3FydChuKSwxKSxjb2xsYXBzZT0iLCIpYF1tbUhnKS4KCkJhc2VkIG9uIHRoZXNlIHJlc3VsdHMgaXQgaXMgb2J2aW91cyB0aGF0IHRoZSB0cmVhdG1lbnQgY2F1c2VzIGEgc3Ryb25nIGJsb29kIHByZXNzdXJlIGRyb3AgZm9yIHBhdGllbnRzIHdpdGggaHlwZXJ0ZW5zaW9uLiAKCiMgSHlwb3RoZXNpcyB0ZXN0cwoKIyMgQ2FwdG9wcmlsIEV4YW1wbGU6ClJlc2VhcmNoZXJzIHdhbnQgdG8gYXNzZXNzIGlmIHRoZSBkcnVnIGNhcHRvcHJpbCBkZWNyZWFzZXMgdGhlIGJsb29kIHByZXNzdXJlIGZvciBwYXRpZW50cyB3aXRoIGh5cGVydGVuc2lvbi4gIAoKLSBJcyB0aGVyZSBuby9hbiBlZmZlY3Qgb2YgYWRtaW5pc3RlcmluZyBjYXB0b3ByaWwgb24gdGhlIHN5c3RvbGljIGJsb29kIHByZXNzdXJlPyAKCi0gSXQgaXMgbm90IG9idmlvdXMgdG8gZHJhdyBzdWNoIGNvbmNsdXNpb25zIGJhc2VkIG9uIGEgc21hbGwgc2FtcGxlCgotIEl0IGlzIHVuY2VydGFpbiBpZiB3ZSBjYW4gZ2VuZXJhbGl6ZWQgdGhlIG9ic2VydmF0aW9ucyBpbiB0aGUgc2FtcGxlIHRvd2FyZHMgdGhlIHBvcHVsYXRpb24hIAoKLSBJcyB0aGUgYXBwYXJlbnQgYmVuZWZpY2lhbCBlZmZlY3Qgc3lzdGVtYXRpYyBvciByYW5kb20/IAoKYGBge3J9CmNhcHRvcHJpbFRpZHkgJT4lIAogIGZpbHRlcih0eXBlJWluJWMoIlNCUGEiLCJTQlBiIikpICU+JQogIG11dGF0ZSh0eXBlPWZhY3Rvcih0eXBlLGxldmVscz1jKCJTQlBiIiwiU0JQYSIpKSklPiUKICBnZ3Bsb3QoYWVzKHg9dHlwZSx5PWJwKSkgKwogIGdlb21fbGluZShhZXMoZ3JvdXAgPSBpZCkpICsKICBnZW9tX3BvaW50KCkKYGBgCgpgYGB7cn0KY2FwdG9wcmlsJGRlbHRhU0JQPC1jYXB0b3ByaWwkU0JQYS1jYXB0b3ByaWwkU0JQYgpjYXB0b3ByaWwlPiUKICBnZ3Bsb3QoYWVzKHg9IlN5c3RvbGljIGJsb29kIHByZXNzdXJlIix5PWRlbHRhU0JQKSkgKwogIGdlb21fYm94cGxvdChvdXRsaWVyLnNoYXBlPU5BKSArCiAgZ2VvbV9wb2ludChwb3NpdGlvbj0iaml0dGVyIikrCiAgeWxhYigiRGlmZmVyZW5jZSAobW0gbWVyY3VyeSkiKSArCiAgeGxhYigiIikKYGBgCgoKLSBUaGUgYXZlcmFnZSBibG9vZCBwcmVzc3VyZSBkaWZmZXJlbmNlICRcYmFyIFgkIGlzIGEgbmF0dXJhbCBiYXNpcyB0byBiYXNlIG91ciBkZWNpc2lvbiBvbi4gCgokJFxiYXIgeFx0ZXh0ez1gciByb3VuZChtZWFuKGNhcHRvcHJpbCRkZWx0YVNCUCksMilgIChzPWByIHJvdW5kKHNkKGNhcHRvcHJpbCRkZWx0YVNCUCksMilgLCBTRT1gciByb3VuZChzZChjYXB0b3ByaWwkZGVsdGFTQlApL3NxcnQoMTUpLDIpYCl9JCQKCi0gSXQgaXMgbm90IGVub3VnaCB0aGF0ICRcYmFye3h9PCAwJCB0byBjb25jbHVkZSB0aGF0IHRoZSBzeXN0b2xpYyBibG9vZCBwcmVzc3VyZSBpcyBvbiBhdmVyYWdlIGxvd2VyIHVwb24gYWRtaW5pc3RyYXRpbmcgY2FwdG9wcmlsICphdCB0aGUgbGV2ZWwgb2YgdGhlIGVudGlyZSBwb3B1bGF0aW9uKi4KCi0gVG8gZ2VuZXJhbGl6ZSB0aGUgZWZmZWN0IHdlIG9ic2VydmUgaW4gdGhlIHNhbXBsZSB0byB0aGUgcG9wdWxhdGlvbiBpdCBoYXMgdG8gYmUgc3VmZmljaWVudGx5IGxhcmdlLgoKLSBCdXQsIGhvdyBsYXJnZT8gCgotLS0KCiMjIyBIeXBvdGhlc2lzIHRlc3RzIAoKLSBGb3IgdGhpcyBwdXJwb3NlIHN0YXRpc3RpY2FsIGh5cG90aGVzaXMgdGVzdHMgaGF2ZSBiZWVuIGRldmVsb3BlZAotIFRoZXkgZ2l2ZSBhIGJsYWNrL3doaXRlIGFuc3dlciAKLSBJdCBpcyBhbG1vc3QgaW1wb3NzaWJsZSB0byByZWFkIGEgc2NpZW50aWZpYyBwdWJsaWNhdGlvbiB3aXRob3V0IHJlc3VsdHMgb2Ygc3RhdGlzdGljYWwgdGVzdHMuCi0gQWNjb3JkaW5nIHRvIHRoZSAqZmFsc2lmaWNhdGlvbiBwcmluY2lwbGUqIG9mIFBvcHBlciB3ZSBjYW4gbmV2ZXIgcHJvdmUgYSBoeXBvdGhlc2lzIGJhc2VkIG9uIGRhdGEuIAoKICAgIC0gSGVuY2Ugd2Ugd2lsbCBpbnRyb2R1Y2UgdHdvIGh5cG90aGVzZXM6IGEgbnVsbCBoeXBvdGhlc2lzICRIXzAkIGFuZCBhbiBhbHRlcm5hdGl2ZSBoeXBvdGhlc2lzICRIXzEkLgogICAgCiAgICAtIFdlIHdpbGwgdHJ5IHRvIGZhbHNpZnkgdGhlIG51bGwgaHlwb3RoZXNpcyBiYXNlZCBvbiB0aGUgc3RhdGlzdGljYWwgdGVzdC4gCiAgIAojIyMjIENhcHRvcHJpbCAKCi0gQmFzZWQgb24gdGhlIHNhbXBsZSB3ZSBjYW5ub3QgcHJvdmUgdGhhdCB0aGVyZSBpcyBhbiBlZmZlY3Qgb2YgYWRtaW5pc3RlcmluZyBjYXB0b3ByaWwgKCRIXzEkICwgYWx0ZXJuYXRpdmUgaHlwb3RoZXNpcykuCgotIFdlIHRoZXJlZm9yZSBzdXBwb3NlIHRoYXQgdGhlcmUgaXMgbm8gZWZmZWN0IG9mIGNhcHRvcHJpbC4KCiAgICAtIFdlIHJlZmVyIHRvIHRoaXMgYXMgdGhlIG51bGwgaHlwb3RoZXNpcyAkSF8wJC4KCiAgICAtIEZhbHNpZnkgKCJ0cnkgdG8gcmVqZWN0IikgdGhlICRIXzAkLiAKICAgIAogICAgLSBIb3cgbGlrZWx5IGlzIGl0IHRvIG9ic2VydmUgYW4gZWZmZWN0IHRoYXQgaXMgYXQgbGVhc3QgYXMgbGFyZ2UgYXMgd2hhdCB3ZSBoYXZlIHNlZW4gaW4gdGhlIHNhbXBsZSBpbiBhIHJhbmRvbSBzYW1wbGUgd2hlbiAgJEhfMCQgaXMgdHJ1ZT8gICAKICAgIAotLS0KCiAgICAKIyMjIyBQZXJtdXRhdGlvbiB0ZXN0IAoKCi0gVW5kZXIgJEhfMCQgdGhlIGJsb29kIHByZXNzdXJlIG1lYXN1cmVtZW50cyBiZWZvcmUgYW5kIGFmdGVyIGFkbWluaXN0ZXJpbmcgY2FwdG9wcmlsIGFyZSB0d28gYmFzZSBsaW5lIGJsb29kIHByZXNzdXJlIG1lYXN1cmVtZW50cyBmb3IgYSBwYXRpZW50CgotIFVuZGVyIEgkXzAkIHdlIGNhbiBzaHVmZmxlIChwZXJtdXRlKSB0aGUgYmxvb2QgcHJlc3N1cmUgbWVhc3VyZW1lbnRzIGZvciBlYWNoIHBhdGllbnQuIAoKCmBgYHtyfQpjYXB0b3ByaWxTYW1wPC1jYXB0b3ByaWwKcGVybTwtc2FtcGxlKGMoRkFMU0UsVFJVRSksMTUscmVwbGFjZT1UUlVFKQpjYXB0b3ByaWxTYW1wJFNCUGFbcGVybV08LWNhcHRvcHJpbCRTQlBiW3Blcm1dCmNhcHRvcHJpbFNhbXAkU0JQYltwZXJtXTwtY2FwdG9wcmlsJFNCUGFbcGVybV0KY2FwdG9wcmlsU2FtcCRkZWx0YVNCUCA8LSBjYXB0b3ByaWxTYW1wJFNCUGEtY2FwdG9wcmlsU2FtcCRTQlBiCmNhcHRvcHJpbFNhbXAgJT4lIAogIGdhdGhlcih0eXBlLGJwLC1pZCkgJT4lCiAgZmlsdGVyKHR5cGUlaW4lYygiU0JQYSIsIlNCUGIiKSkgJT4lCiAgbXV0YXRlKHR5cGU9ZmFjdG9yKHR5cGUsbGV2ZWxzPWMoIlNCUGIiLCJTQlBhIikpKSU+JQogIGdncGxvdChhZXMoeD10eXBlLHk9YnApKSArCiAgZ2VvbV9saW5lKGFlcyhncm91cCA9IGlkKSkgKwogIGdlb21fcG9pbnQoKQpgYGAKCgoKCmBgYHtyfQpkYXRhLmZyYW1lKGRlbHRhU0JQPWMoY2FwdG9wcmlsJGRlbHRhU0JQLGNhcHRvcHJpbFNhbXAkZGVsdGFTQlApLHNodWZmbGVkPXJlcChjKEZBTFNFLFRSVUUpLGVhY2g9MTUpKSAlPiUKICBnZ3Bsb3QoYWVzKHg9c2h1ZmZsZWQseT1kZWx0YVNCUCkpICsKICBnZW9tX2JveHBsb3Qob3V0bGllci5zaGFwZT1OQSkgKwogIGdlb21fcG9pbnQocG9zaXRpb249ImppdHRlciIpKwogIHN0YXRfc3VtbWFyeShmdW4ueT1tZWFuLCBnZW9tPSJwb2ludCIsIHNoYXBlPTE5LCBzaXplPTMsIGNvbG9yPSJyZWQiLCBmaWxsPSJyZWQiKSArCiAgeWxhYigiRGlmZmVyZW5jZSAobW0gbWVyY3VyeSkiKSAKYGBgCgpBbmQgd2UgcGVybXV0ZSBhZ2FpbgoKCmBgYHtyfQpjYXB0b3ByaWxTYW1wPC1jYXB0b3ByaWwKcGVybTwtc2FtcGxlKGMoRkFMU0UsVFJVRSksMTUscmVwbGFjZT1UUlVFKQpjYXB0b3ByaWxTYW1wJFNCUGFbcGVybV08LWNhcHRvcHJpbCRTQlBiW3Blcm1dCmNhcHRvcHJpbFNhbXAkU0JQYltwZXJtXTwtY2FwdG9wcmlsJFNCUGFbcGVybV0KY2FwdG9wcmlsU2FtcCRkZWx0YVNCUCA8LSBjYXB0b3ByaWxTYW1wJFNCUGEtY2FwdG9wcmlsU2FtcCRTQlBiCgpjYXB0b3ByaWxTYW1wICU+JSAKICBnYXRoZXIodHlwZSxicCwtaWQpICU+JQogIGZpbHRlcih0eXBlJWluJWMoIlNCUGEiLCJTQlBiIikpICU+JQogIG11dGF0ZSh0eXBlPWZhY3Rvcih0eXBlLGxldmVscz1jKCJTQlBiIiwiU0JQYSIpKSklPiUKICBnZ3Bsb3QoYWVzKHg9dHlwZSx5PWJwKSkgKwogIGdlb21fbGluZShhZXMoZ3JvdXAgPSBpZCkpICsKICBnZW9tX3BvaW50KCkKCmRhdGEuZnJhbWUoZGVsdGFTQlA9YyhjYXB0b3ByaWwkZGVsdGFTQlAsY2FwdG9wcmlsU2FtcCRkZWx0YVNCUCksc2h1ZmZsZWQ9cmVwKGMoRkFMU0UsVFJVRSksZWFjaD0xNSkpICU+JQogIGdncGxvdChhZXMoeD1zaHVmZmxlZCx5PWRlbHRhU0JQKSkgKwogIGdlb21fYm94cGxvdChvdXRsaWVyLnNoYXBlPU5BKSArCiAgZ2VvbV9wb2ludChwb3NpdGlvbj0iaml0dGVyIikrCiAgc3RhdF9zdW1tYXJ5KGZ1bi55PW1lYW4sIGdlb209InBvaW50Iiwgc2hhcGU9MTksIHNpemU9MywgY29sb3I9InJlZCIsIGZpbGw9InJlZCIpICsKICB5bGFiKCJEaWZmZXJlbmNlIChtbSBtZXJjdXJ5KSIpIApgYGAKCgotIFdlIHdpbGwgZG8gdGhpcyAxMDAwMCB0aW1lcyBhbmQgd2Ugd2lsbCBrZWVwIHRyYWNrIG9mIHRoZSBtZWFuLgotIFdlIGJhc2ljYWxseSBvbmx5IGhhdmUgdG8gc3dhcCB0aGUgc2lnbnMgb2YgdGhlIG9ic2VydmVkIGJsb29kIHByZXNzdXJlIGRpZmZlcmVuY2VzICR4JCB3aGVuIHdlIHNodWZmbGUuICAKCmBgYHtyfQojZ2VuZXJhdGUgYSBtYXRyaXggd2l0aCAxNSByb3dzIGFuZCAxMDAwMCBjb2x1bW5zIHdoaWNoIGNvbnNpc3Qgb2YgLTEgYW5kIDEKcGVybUg8LXNhbXBsZShjKC0xLDEpLDE1MDAwMCxyZXBsYWNlPVRSVUUpCmRpbShwZXJtSCk8LWMoMTUsMTAwMDApCgojY2FsY3VsYXRlIHRoZSBtZWFucyBmb3IgdGhlIHBlcm11dGVkIGRhdGEKbXVQZXJtPC1jb2xNZWFucyhwZXJtSCpjYXB0b3ByaWwkZGVsdGFTQlApCm11UGVybSAlPiUgCiAgYXMuZGF0YS5mcmFtZSAlPiUgCiAgZ2dwbG90KGFlcyh4PS4pKSArCiAgZ2VvbV9oaXN0b2dyYW0oKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0PW1lYW4oY2FwdG9wcmlsJGRlbHRhU0JQKSxjb2w9ImJsdWUiKQpgYGAKCi0gV2Ugb2JzZXJ2ZSB0aGF0IG5vdCBvbmUgb2YgdGhlIG1lYW5zIHRoYXQgd2VyZSBvYnRhaW5lZCB1bmRlciAkSF8wJCAoYnkgcGVybXV0YXRpb24pIHdlcmUgYXMgZXh0cmVtZSBhcyB0aGUgc2FtcGxlIG1lYW4gd2Ugb2JzZXJ2ZWQgaW4gdGhlIGNhcHRvcHJpbCBzdHVkeS4gCgotIFNvIHRoZSBwcm9iYWJpbGl0eSB0byBvYnNlcnZlIGEgYmxvb2QgcHJlc3N1cmUgZHJvcCB0aGF0IGlzIGxhcmdlciB0aGVuIHRoZSBvbmUgaW4gdGhlIGNhcHRvcHJpbCBzdHVkeSBpbiBhIHJhbmRvbSBzYW1wbGUgZ2VuZXJhdGVkIHVuZGVyIHRoZSBudWxsIGh5cG90aGVzaXMgaXMgIHNtYWxsZXIgdGhlbiAxIG91dCBvZiAxMDAwMC4gCgpTbyB3ZSBoYXZlIHN0cm9uZyBldmlkZW5jZSB0aGF0ICRIXzAkIGlzIGluY29ycmVjdCBhbmQgd2UgdGh1cyB3ZSByZWplY3QgaXQgYW5kIGNvbmNsdWRlICRIXzEkOiBUaGVyZSBpcyBhbiBlZmZlY3Qgb2YgYWRtaW5pc3RlcmluZyBjYXB0b3ByaWwgb24gdGhlIGJsb29kIHByZXNzdXJlIG9mIHBhdGllbnRzIHdpdGggaHlwZXJ0ZW5zaW9uLgoKLS0tCgojIyMgUGl2b3QKCi0gSW4gcHJhY3RpY2Ugd2UgYWx3YXlzIHVzZSBzdGF0aXN0aWNzIHRoYXQgYmFsYW5jZSB0aGUgZWZmZWN0IHNpemUgKGF2ZXJhZ2UgZGlmZmVyZW5jZSkgdG8gdGhlIG5vaXNlIChzdGFuZGFyZCBlcnJvcikgCgotIFdoZW4gd2UgZmFsc2lmeSB0aGUgbnVsbCBoeXBvdGhlc2lzLCB3ZSBzdGFuZGFyZGl6ZSB0aGUgbWVhbiBhcm91bmQgJFxtdV8wPTAkIHRoZSBtZWFuIHVuZGVyICRIXzAkICAKCiQkdD1cZnJhY3tcYmFyIFgtXG11XzB9e3NlX3tcYmFyIFh9fSQkCgotIGZvciB0aGUgY2FwdG9wcmlsIGV4YW1wbGUgdGhpcyBiZWNvbWVzOiAKJCRcZnJhY3tgciByb3VuZChtZWFuKGNhcHRvcHJpbCRkZWx0YVNCUCksMilgLTB9e2ByIHJvdW5kKHNkKGNhcHRvcHJpbCRkZWx0YVNCUCkvc3FydCgxNSksMilgfT1gciByb3VuZChtZWFuKGNhcHRvcHJpbCRkZWx0YVNCUCkvKHNkKGNhcHRvcHJpbCRkZWx0YVNCUCkvc3FydCgxNSkpLDIpYCQkCgoKV2Ugbm93IGRldGVybWluZSB0aGUgbnVsbCBkaXN0cmlidXRpb24gb2YgdGVzdCBzdGF0aXN0aWMgdCB3aXRoIHBlcm11dGF0aW9uLgoKYGBge3J9CmRlbHRhUGVybXM8LXBlcm1IKmNhcHRvcHJpbCRkZWx0YVNCUAp0UGVybTwtY29sTWVhbnMoZGVsdGFQZXJtcykvKGFwcGx5KGRlbHRhUGVybXMsMixzZCkvc3FydCgxNSkpCnRPcmlnPC1tZWFuKGNhcHRvcHJpbCRkZWx0YVNCUCkvc2QoY2FwdG9wcmlsJGRlbHRhU0JQKSpzcXJ0KDE1KQoKdFBlcm1QbG90PC0gdFBlcm0gJT4lIAogIGFzLmRhdGEuZnJhbWUgJT4lIGdncGxvdChhZXMoeD0uKSkgKwogIGdlb21faGlzdG9ncmFtKGFlcyh5PS4uZGVuc2l0eS4uLCBmaWxsPS4uY291bnQuLikpICsgCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0PXRPcmlnLGNvbD0iYmx1ZSIpCnRQZXJtUGxvdApgYGAKCi0gQWdhaW4sIG5vbmUgb2YgdGhlIHBlcm11dGF0aW9ucyBnaXZlcyBhIHQtc3RhdGlzdGljIGFzIGV4dHJlbWUgYXMgdGhlIG9uZSBvYnNlcnZlZCBpbiB0aGUgY2FwdG9wcmlsIHN0dWR5LiAKCldoZW4gdGhlcmUgaXMgbm8gZWZmZWN0IG9mIGNhcHRvcHJpbCBpdCBpcyBuZWFybHkgaW1wb3NzaWJsZSB0byBvYnRhaW4gYSB0ZXN0IHN0YXRpc3RpYyBhcyBleHRyZW1lIGFzIHRoZSBvbmUgdGhhdCB3YXMgb2JzZXJ2ZWQgKCAgdD1gciByb3VuZCh0T3JpZywyKWApLgoKLSBUaGUgcHJvYmFiaWxpdHkgdG8gb2JzZXJ2ZSBhIGxhcmdlciBibG9vZCBwcmVzc3VyZSBkcm9wIHRoZW4gdGhlIG9uZSB3ZSBvYnNlcnZlZCBpbiBvdXIgc2FtcGxlIGluIGEgcmFuZG9tIHNhbXBsZSB1bmRlciAkSF8wJCBpcyBzbWFsbGVyIDEvMTAwMDAuCgotIFdlIHJlZmVyIHRvIHRoaXMgcHJvYmFiaWxpdHkgd2l0aCB0aGUgKnAtdmFsdWUqLgoKLSBJdCBtZWFzdXJlcyB0aGUgc3RyZW5ndGggb2YgdGhlIGV2aWRlbmNlIGFnYWluc3QgdGhlIG51bGw6IHRoZSBzbWFsbGVyIHRoZSBwLXZhbHVlIHRoZSBtb3JlIGV2aWRlbmNlIHdlIGhhdmUgdGhhdCB0aGUgbnVsbCBpcyBub3QgdHJ1ZS4gCgotIFRoZSBkaXN0cmlidXRpb24gaGFzIGEgbmljZSBiZWxsIHNoYXBlLgoKLS0tCgojIyMgSG93IGRvIHdlIGRlY2lkZT8KCldoZW4gaXMgdGhlIHAtdmFsdWUgc3VmZmljaWVudGx5IHNtYWxsIHRvIGNvbmNsdWRlIHRoYXQgdGhlcmUgaXMgc3Ryb25nIGV2aWRlbmNlIGFnYWluc3QgdGhlIG51bGwgaHlwb3RoZXNpcz8gCgotIFdlIHR5cGljYWxseSB3b3JrIGF0IGEgc2lnbmlmaWNhbmNlIGxldmVsIG9mICRcYWxwaGE9MC4wNSQKCi0gV2Ugc3RhdGUgdGhhdCB3ZSBjb25kdWN0ZWQgdGhlIHRlc3QgYXQgdGhlIDUlIHNpZ25pZmljYW5jZSBsZXZlbAoKLS0tCgojIyMgUGVybXV0YXRpb24gdGVzdHMgYXJlIGNvbXB1dGF0aW9uYWxseSBkZW1hbmRpbmcgCgotIENhbiB3ZSBhc3Nlc3MgaG93IGV4dHJlbWUgdGhlIGJsb29kIHByZXNzdXJlIGRyb3Agd2FzIHdpdGhvdXQgcGVybXV0YXRpb24/IAoKLSBXZSBrbm93IHRoYXQgdGhlIGJsb29kIHByZXNzdXJlIGRpZmZlcmVuY2VzIGFyZSBhcHByb3hpbWF0ZWx5IE5vcm1hbGx5IGRpc3RyaWJ1dGVkLCBzbwoKJCR0PVxmcmFje1xiYXIgWCAtIFxtdX17c2Vfe1xiYXIgWH19JCQKCmZvbGxvd3MgYSB0LWRpc3RyaWJ1dGlvbiAod2l0aCAxNCBkZiBmb3IgdGhlIGNhcHRvcHJpbCBleGFtcGxlKS4gCgoKLSBVbmRlciBIJF8wJCAkXG11PTAkIGFuZCAkJHQ9XGZyYWN7XGJhciBYLTB9e3NlX3tcYmFyIFh9fVxzaW0gZl97VCwxNH0kJAoKYGBge3J9CnRQZXJtUGxvdCArIAogIHN0YXRfZnVuY3Rpb24oZnVuPWR0LGNvbG9yPSJyZWQiLGFyZ3M9bGlzdChkZj0xNCkpCmBgYAoKLSBOb3RlLCB0aGUgcGVybXV0YXRpb24gbnVsbCBkaXN0cmlidXRpb24gaW5kZWVkIGNvcnJlc3BvbmRzIHRvIGEgdC1kaXN0cmlidXRpb24gd2l0aCAxNCBkZWdyZWVzIG9mIGZyZWVkb20uIAoKLSBTbyB3ZSBjYW4gY29uZHVjdCB0aGUgc3RhdGlzdGljYWwgdGVzdCB1c2luZyBzdGF0aXN0aWNhbCBtb2RlbGxpbmcgb2YgdGhlIGRhdGEuIAoKLSBXZSBuZWVkIHRvIG1ha2UgYXNzdW1wdGlvbnMgZm9yIHRoaXMsIHdoaWNoIHdlIHZlcmlmeSBpbiB0aGUgZGF0YSBleHBsb3JhdGlvbiBwaGFzZS4gCgoKLS0tCgoKIyMgSHlwb3RoZXNlcwoKPGRldGFpbHM+PHN1bW1hcnk+Q2xpY2sgdG8gc2VlIG1vcmUgZm9ybWFsIGRldGFpbHMgPC9zdW1tYXJ5PjxwPgoKVHJhbnNsYXRlIHRoZSByZXNlYXJjaCBxdWVzdGlvbiB0byBhIG51bGwgaHlwb3RoZXNpcyAoJEhfMCQpIGFuZCBhbiBhbHRlcm5hdGl2ZSBoeXBvdGhlc2lzICgkSF8xJCkKCkZpcnN0IHRoZSB3ZSBuZWVkIHRvIHRyYW5zbGF0ZSB0aGUgcmVzZWFyY2ggcXVlc3Rpb24gdG8gYSBwYXJhbWV0ZXJpemVkIHN0YXRpc3RpY2FsIG1vZGVsLiAgCgotIEZyb20gdGhlIGV4cGVyaW1lbnRhbCBkZXNpZ24gaXQgZm9sbG93cyB0aGF0ICAkJFhfMSwuLi4sWF9uIFx0ZXh0eyBpLmkuZCB9IGYoWCksJCQgd2l0aCAkZihYKSQgdGhlIGRlbnNpdHkgZnVuY3Rpb24gb2YgYmxvb2QgcHJlc3N1cmUgZGlmZmVyZW5jZXMuCgotICoqU2ltcGxpZnkqKjogYXNzdW1lIHRoYXQgJGYoWCkkIGlzIGtub3duIGV4Y2VwdCBmb3IgYW4gZmluaXRlIGRpbWVuc2lvbmFsIHNldCBvZiBwYXJhbWV0ZXJzICRcbWF0aGJme1x0aGV0YX0kIHRoYXQgc3RpbGwgaGFzIHRvIGJlIGVzdGltYXRlZCAocGFyYW1ldHJpYyBzdGF0aXN0aWMgbW9kZWwpLgo8L3A+PC9kZXRhaWxzPgoKIyMjIENhcHRvcHJpbCBleGFtcGxlIAoKPGRldGFpbHM+PHN1bW1hcnk+Q2xpY2sgdG8gc2VlIG1vcmUgZm9ybWFsIGRldGFpbHMgPC9zdW1tYXJ5PjxwPgokWCBcc2ltIE4oXG11LFxzaWdtYV4yKSQgd2l0aCAkXG1hdGhiZntcdGhldGF9PShcbXUsXHNpZ21hXjIpJCwgdGhlIG1lYW4gJFxtdSQgYW5kIHZhcmlhbmNlICRcc2lnbWFeMiQuCgpUaGUgcmVzZWFyY2ggcXVlc3Rpb24gaXMgbm93IHRyYW5zbGF0ZWQgaW4gdGVybXMgb2YgdGhlIGF2ZXJhZ2UgYmxvb2QgcHJlc3N1cmUgZHJvcDogJFxtdT1FX2ZbWF0kLgoKVGhlICoqYWx0ZXJuYXRpdmUgaHlwb3RoZXNpcyoqIGlzIGZvcm11bGF0ZWQgaW4gdGVybXMgb2YgYSBwYXJhbWV0ZXIgb2YgJGYoWCkkIGFuZCBoYXMgdG8gZXhwcmVzcyB3aGF0IHRoZSByZXNlYXJjaGVycyB3YW50IHRvIHByb3ZlIHdpdGggdGhlIHN0dWR5LgoKLSBIZXJlOgokJEhfMTogXG11PDAuJCQgT24gYXZlcmFnZSB0aGUgYmxvb2QgcHJlc3N1cmUgb2YgcGF0aWVudHMgd2l0aCBoeXBlcnRlbnNpb24gZGVjcmVhc2VzIHVwb24gYWRtaW5pc3RlcmluZyBjYXB0b3ByaWwuIAoKClRoZSAqKm51bGwgaHlwb3RoZXNpcyoqIGdlbmVyYWxseSBleHByZXNzZXMgYSBudWxsIGNvbmRpdGlvbiwgaS5lLiB3aGVuIG5vdHRpbmcgZXhjZXB0aW9uYWwgaGFwcGVucy4gCgotIFJlc2VhcmNoZXJzIHR5cGljYWxseSBhaW0gdG8gcHJvdmUgdmlhIGVtcGlyaWNhbCByZXNlYXJjaCB0aGF0IG9ic2VydmluZyB0aGUgZGF0YSB1bmRlciB0aGUgbnVsbCBpcyBoaWdobHkgdW5saWtlbHkgc28gdGhhdCB0aGV5IGNhbiByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpczoKKipGYWxzaWZpY2F0aW9uIHByaW5jaXBsZSoqLgoKLSBUaGUgKipudWxsIGh5cG90aGVzaXMgaXMgdHlwaWNhbGx5IGV4cHJlc3NlZCB3aXRoIHRoZSBzYW1lIG1vZGVsIHBhcmFtZXRlciBhcyB0aGUgb25lIHVzZWQgZm9yICRIXzEkLioqCgotIEhlcmU6CiQkSF8wIDogXG11PTAkJCBpLmUuIG9uIGF2ZXJhZ2UgdGhlIHN5c3RvbGljIGJsb29kIHByZXNzdXJlIHJlbWFpbnMgdW5jaGFuZ2VkIHVwb24gYWRtaW5pc3RlcmluZyBjYXB0b3ByaWwuIAoKPC9wPjwvZGV0YWlscz4KCi0tLQoKIyMgVGVzdC1zdGF0aXN0aWMKCjxkZXRhaWxzPjxzdW1tYXJ5PkNsaWNrIHRvIHNlZSBtb3JlIGZvcm1hbCBkZXRhaWxzIDwvc3VtbWFyeT48cD4KCk9uY2UgdGhlIHBvcHVsYXRpb24sIHRoZSBwYXJhbWV0ZXJzLCBhbmQsICRIXzAkIGFuZCAkSF8xJCBhcmUgZGV0ZXJtaW5lZCB0aGUgY29uY2VwdCBvZiBoeXBvdGhlc2lzIHRlc3RpbmcgaXMgYXMgZm9sbG93czogCgoKQ29uc3RydWN0IGEgdGVzdCBzdGF0aXN0aWMgc28gdGhhdCBpdAoKMS4gbWVhc3VyZXMgZXZpZGVuY2UgaW4gdGhlIHNhbXBsZSwKXHZzcGFjZXsxMHB0fQoyLiBhZ2FpbnN0IHRoZSBudWxsIGh5cG90aGVzaXMsIGFuZApcdnNwYWNlezEwcHR9CjMuIGluIGZhdm91ciBvZiB0aGUgYWx0ZXJuYXRpdmUgaHlwb3RoZXNpcy4KCkEgdGVzdCBzdGF0aXN0aWMgdGh1cyBoYXMgdG8gYmUgYSBmdW5jdGlvbiBvZiB0aGUgb2JzZXJ2YXRpb25zIGluIHRoZSBzYW1wbGUuIAoKPC9wPjwvZGV0YWlscz4KCiMjIyBDYXB0b3ByaWwgZXhhbXBsZQoKPGRldGFpbHM+PHN1bW1hcnk+Q2xpY2sgdG8gc2VlIG1vcmUgZm9ybWFsIGRldGFpbHMgPC9zdW1tYXJ5PjxwPgoKJCRUPVxmcmFje1xiYXJ7WH0tXG11XzB9e1x0ZXh0e1NFfV97XGJhciBYfX0kJApXaXRoICRcbXVfMD0wJCB1bmRlciAkSF8wJCAKCkFnYWluIAoKLSBJZiAkSF8wJCBob2xkcyB0aGVyZSBpcyBubyBlZmZlY3Qgb2YgY2FwdG9wcmlsIG9uIHRoZSBibG9vZCBwcmVzc3VyZSBpbiB0aGUgcG9wdWxhdGlvbiBhbmQgdGhlbiB3ZSBleHBlY3QgdGVzdCBzdGF0aXN0aWMgJFQkIGNsb3NlIHRvIDAuCgotIElmICRIXzEkIGlzIHRydWUgd2UgZXhwZWN0ICRUPDAkLgoKLSBJbiB0aGUgY2FwdG9wcmlsIGV4YW1wbGUgd2Ugb2JzZXJ2ZSAkdD0oLTE4LjkzLTApLzIuMzM9LTguMTIkLgoKLSBJcyAkdCA9IC04LjEyJCBsYXJnZSBlbm91Z2ggaW4gYWJzb2x1dGUgdmFsdWUgdG8gY29uY2x1ZGUgdGhhdCAgJFxtdSA8IDAkIGFuZCB3aXRoIHdoaWNoIGNvbmZpZGVuY2UgY2FuIHdlIG1ha2UgdGhpcyBjb25jbHVzaW9uPyAKCi0gV2Uga25vd24gdGhhdCB0IGZvbGxvd3MgYSB0LWRpc3RyaWJ1dGlvbiB3aXRoIDE0IGQuZi4gdW5kZXIgJEhfMCQgIAoKPC9wPjwvZGV0YWlscz4KCi0tLQoKIyMgcC12YWx1ZQoKVGhlIHAtdmFsdWUgaXMgdGhlIHByb2JhYmlsaXR5IHRvIGJhbGFuY2UgYmV0d2VlbiAkSF8wJCBhbmQgJEhfMSQuCgpUaGUgd2F5IGhvdyB3ZSBjYWxjdWxhdGUgaXQgaXMgY29udGV4dCBkZXBlbmRlbnQgCgotIEZvciB0aGUgY2FwdG9wcmlsIGV4YW1wbGUgd2UgaGF2ZQogICQkCiAgICBwID0gUFxsZWZ0W1QgXGxlcSB0IFxtaWQgSF8wXHJpZ2h0XSA9IFx0ZXh0e1B9XzBcbGVmdFtUXGxlcSB0XHJpZ2h0XSwKICAkJAp3aXRoIHRoZSBpbmRleCAiMCIgaW4gJFx0ZXh0e1B9XzBcbGVmdFsuXHJpZ2h0XSQgaW5kaWNhdGVzIHRoYXQgdGhlIHByb2JhYmlsaXR5IGlzIGNhbGN1bGF0ZWQgdW5kZXIgJEhfMCQuIAoKSXQgZ2l2ZXMgdGhlIHByb2JhYmlsaXR5IHRvIG9ic2VydmUgYSB0ZXN0IHN0YXRpc3RpYyAkVCQgbG93ZXIgb3IgZXF1YWwgdG8gdGhlIHZhbHVlIG9ic2VydmVkIGluIHRoZSBjdXJyZW50IHNhbXBsZSBpbiBhIHJhbmRvbSBzYW1wbGUgdW5kZXIgJEhfMCQKICAgIC0gaS5lLiBhIHRlc3Qgc3RhdGlzdGljICRUJCBpbiB0aGUgcmFuZG9tIHNhbXBsZSB1bmRlciAkSF8wJCB3aXRoIGEgdmFsdWUgdGhhdCBpcyBtb3JlIGV4dHJlbWUsIG1vcmUgaW4gdGhlIGRpcmVjdGlvbiBvZiAkSF8xJCB0aGVuIHRoZSBvbmUgb2JzZXJ2ZWQgaW4gdGhlIGN1cnJlbnQgc2FtcGxlLiAKICAgIAojIyMgQ2FwdG9wcmlsIGV4YW1wbGUKCjxkZXRhaWxzPjxzdW1tYXJ5PkNsaWNrIHRvIHNlZSBtb3JlIGZvcm1hbCBkZXRhaWxzIDwvc3VtbWFyeT48cD4KCi0gVGhlICRwJC12YWx1ZSBmb3IgdGhlIGNhcHRvcHJpbCBleGFtcGxlIGlzIGNhbGN1bGF0ZWQgYXMgZm9sbG93cyAKICAkJHA9IFx0ZXh0e1B9XzBcbGVmdFtUXGxlcSAtOC4xMlxyaWdodF09Rl90KC04LjEyOzE0KSA9IDAuNlwgMTBeey02fS4kJAoKICB3aXRoICRGX3QoOzE0KSQgdGhlIGN1bXVsYXRpdmUgZGlzdHJpYnV0aW9uIGZ1bmN0aW9uIG9mIGEgdC1kaXN0cmlidXRpb24gd2l0aCAxNCBkZWdyZWVzIG9mIGZyZWVkb206CiAgCiQkRl90KHg7MTQpPVxpbnRcbGltaXRzX3stXGluZnR5fV57eH0gZl90KHg7MTQpLiQkCgphbmQgJGZfdCguOzE0KSQgdGhlIGRlbnNpdHkgZnVuY3Rpb24gb2YgdGhlIHQtZGlzdHJpYnV0aW9uLiAKCgotIFdlIGNhbGN1bGF0ZSB0aGlzIHByb2JhYmlsaXR5IGluIFIgd2l0aCBgcHQoeCxkZilgCgogICAgLSB0aGUgdmFsdWUgb2YgdGhlIG9ic2VydmVkIHRlc3Qgc3RhdGlzdGljIGB4YCBlbgogICAgLSB0aGUgbnVtYmVyIG9mIGRlZ3JlZXMgb2YgZnJlZWRvbSBvZiB0aGUgdC1kaXN0cmlidXRpb24gYGRmYC4KCi0gYHB0KHgsZGYpYCBjYWxjdWxhdGVzIHRoZSBwcm9iYWJpbGl0eSB0byBvYnNlcnZlIGEgdmFsdWUgc21hbGxlciBvciBlcXVhbCB0byB4IHdoZW4gd2Ugd291bGQgZHJhdyBhIHJhbmRvbSBzYW1wbGUgZnJvbSBhIHQtZGlzdHJpYnV0aW9uIHdpdGggZGYgZGVncmVlcyBvZiBmcmVlZG9tLiAKCmBgYHtyfQpuIDwtIGxlbmd0aChjYXB0b3ByaWwkZGVsdGFTQlApCnN0YXQ8LShtZWFuKGNhcHRvcHJpbCRkZWx0YVNCUCktMCkvKHNkKGNhcHRvcHJpbCRkZWx0YVNCUCkvc3FydChuKSkKc3RhdApwdChzdGF0LG4tMSkKYGBgCgo8L3A+PC9kZXRhaWxzPgoKSW4gcHJhY3RpY2Ugd2Ugd2lsbCBub3QgY2FsY3VsYXRlIHRoZSB0ZXN0IG91cnNlbGYsIGJ1dCB3ZSB3aWxsIHVzZSB0aGUgZnVuY3Rpb24gdC50ZXN0OiAKCmBgYHtyfQp0LnRlc3QoY2FwdG9wcmlsJGRlbHRhU0JQLCBhbHRlcm5hdGl2ZSA9ICJsZXNzIikKYGBgCgpOb3RlLCB0aGF0IHdlIG5lZWQgdG8gc3BlY2lmeSB0aGUgYXJndW1lbnQgYGFsdGVybmF0aXZlPSJsZXNzImAgc28gdGhhdCB0aGUgcC12YWx1ZSB3b3VsZCBiZSBjYWxjdWxhdGVkIGluIHRoZSBsZWZ0IHRhaWwuIAoKVGhlIGZ1bmN0aW9uIGFsc28gZ2l2ZXMgYSBvbmUtc2lkZWQgaW50ZXJ2YWwgYmVjYXVzZSB3ZSB0ZXN0IGluIG9uZSBkaXJlY3Rpb24uCgotLS0KCiMjIyBEZWZpbml0aW9uIG9mIHRoZSBwLXZhbHVlCgpUaGUgKipwLXZhbHVlKiogKGFsc28gcmVmZXJyZWQgdG8gYXMgdGhlICoqb2JzZXJ2ZWQgc2lnbmlmaWNhbmNlIGxldmVsKiopIGlzIHRoZSBwcm9iYWJpbGl0eSB0byBvYnNlcnZlIGEgdGVzdCBzdGF0aXN0aWMgaW4gYSByYW5kb20gc2FtcGxlIHVuZGVyIHRoZSBudWxsIGh5cG90aGVzaXMgdGhhdCBpcyBhcyBvciBtb3JlIGV4dHJlbWUgdGhlbiB0aGUgdGVzdCBzdGF0aXN0aWMgb2JzZXJ2ZWQgaW4gdGhlIGN1cnJlbnQgc2FtcGxlLiAKCi0gVGhlIHNtYWxsZXIgdGhlIHByb2JhYmlsaXR5IHRoZSBtb3JlIGV2aWRlbmNlIGFnYWluc3QgJEhfMCQuIAoKLSBOb3RlLCB0aGF0IHRoZSBwLXZhbHVlIGlzICoqbm90KiogdGhlIHByb2JhYmlsaXR5IHRoYXQgbnVsbCBoeXBvdGhlc2lzIGlzIHRydWUhCgotIFRoZSB3b3JkICJleHRyZW1lIiBpbmRpY2F0ZXMgb24gdGhlIGRpcmVjdGlvbiBpbiB3aGljaCB0aGUgdGVzdCBzdGF0aXN0aWMgaXMgbW9yZSBsaWtlbHkgdW5kZXIgdGhlIGFsdGVybmF0aXZlIGh5cG90aGVzaXMuIAoKLSBJbiB0aGUgZXhhbXBsZSAkSF8xOiBcbXUgPCAwJCBhbmQgd2UgdGh1cyBleHBlY3QgdmVyeSBuZWdhdGl2ZSB2YWx1ZXMgZm9yICR0JCB1bmRlciAkSF8xJC4KCi0gRnJvbSB0aGUgZGVmaW5pdGlvbiBzbWFsbCAkcCQtdmFsdWVzIGluZGljYXRlIHRoYXQgb2JzZXJ2ZWQgdGVzdCBzdGF0aXN0aWMgaXMgdW5saWtlbHkgdW5kZXIgdGhlIGFzc3VtcHRpb24gdGhhdCAkSF8wJCBpcyBjb3JyZWN0LgoKLSBUaHVzIGEgc21hbGwgdmFsdWUgb2YgJHAkLXZhbHVlIG1lYW5zIHRoYXQgd2UgaGF2ZSB0byAqKnJlamVjdCAgJEhfMCQqKiBpbiBmYXZvdXIgb2YgJEhfMSQuCgotIFRoZSB0aHJlc2hvbGQgdGhhdCB3ZSB1c2UgdG8gY29tcGFyZSB0aGUgJHAkLXZhbHVlIHdpdGggaXMgcmVmZXJyZWQgdG8gYXMgdGhlICoqc2lnbmlmaWNhbmNlIGxldmVsKiogYW5kIGlzIGRlbm90ZWQgd2l0aCAkXGFscGhhJC4gCgotIEEgc3RhdGlzdGljYWwgdGVzdCBjb25kdWN0ZWQgb24gdGhlICRcYWxwaGEkIHNpZ25pZmljYW5jZSBsZXZlbCBpcyBhbHNvIHJlZmVycmVkIHRvIGFzIGEgKipsZXZlbC0kXGFscGhhJCB0ZXN0KiouCgpBIHRlc3QgcmVzdWx0IGlzICpzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50KiBpZiAkcDxcYWxwaGEkCgotICRcYWxwaGEkIGlzIGNvbW1vbmx5IHNldCBhdCA1XCUuCgotIFRoZSBzbWFsbGVyIHRoZSBwLXZhbHVlIHRoZSBtb3JlIGBzaWduaWZpY2FudCcgdGhlIHRlc3QgcmVzdWx0IGRldmlhdGVzIGZyb20gd2hhdCBjYW4gYmUgZXhwZWN0ZWQgdW5kZXIgJEhfMCQuIAoKLSBJdCBzdW1tYXJpemVzIHRoZSBldmlkZW5jZSBhZ2FpbnN0IHRoZSBudWxsLiAgCgokJFxiZWdpbnthcnJheX17Y2x9PjAuMTAgJiBcdGV4dHsgbm9uIHNpZ25pZmljYW50IChubyBldmlkZW5jZSl9XFwwLjA1LTAuMTAgJiBcdGV4dHsgbWFyZ2luYWwgc2lnbmlmaWNhbnQsIHdlYWsgZXZpZGVuY2UgKGRvIG5vdCB1c2UgdGhpcyB5b3Vyc2VsZil9XFwwLjAxLTAuMDUgJiBcdGV4dHsgc2lnbmlmaWNhbnR9XFwwLjAwMS0wLjAxICYgXHRleHR7c3Ryb25nbHkgc2lnbmlmaWNhbnR9XFw8MC4wMDEgJiBcdGV4dHsgZXh0cmVtZWx5IHNpZ25pZmljYW50fVxlbmR7YXJyYXl9JCQKCi0tLQoKIyMgQ3JpdGljYWwgdmFsdWUKCmBgYHtyICBvdXQud2lkdGg9JzEwMCUnLCBmaWcuYXNwPS44LCBmaWcuYWxpZ249J2NlbnRlcicsZWNobz1GQUxTRX0KcGFyKG1hcj1jKDYsNiw2LDIpKQpncmlkIDwtc2VxKC0xMCwxMCwuMDEpCnRjcml0IDwtIHF0KDAuMDUsbi0xKQpyZWplY3QgPC0gYyhncmlkW2dyaWQ8dGNyaXRdLHRjcml0KQpwbG90KGdyaWQsZHQoZ3JpZCxuLTEpLHR5cGU9ImwiLGx3ZD0yLHhsYWI9InQtc3RhdGlzdGljIix5bGFiPSJkZW5zaXR5IixjZXgubGFiPTIsY2V4LmF4aXM9MixjZXgubWFpbj0yKQphYmxpbmUodj1tZWFuKGNhcHRvcHJpbCRkZWx0YVNCUCkvc2UsY29sPTIsbHdkPTIsbHR5PTIpCmFibGluZSh2PXF0KGMoLjA1KSxuLTEpLGNvbD0yLGx0eT0xLGx3ZD0yKQp0ZXh0KGMoLTUsLTUsNSw1KSxjKC4yMSwuMTksLjIxLC4xOSksbGFiZWw9YygicmVqZWN0aW9uLSIsInJlZ2lvbiIsImFjY2VwdGlvbi0iLCJyZWdpb24iKSxjb2w9YygyLDIsNCw0KSkKYXJyb3dzKC0xMDAsLjQsbWVhbihjYXB0b3ByaWwkZGVsdGFTQlApL3NlLC40LGx3ZD0yLGNvbD0yLGFuZ2xlPTIwLGxlbmd0aD0uMSkKdGV4dCgtMTAsLjM1LGxhYmVsPSJwLXZhbHVlIixzcnQ9OTAsY29sPTIpCmFycm93cygtMTAwLC4yLHRjcml0LC4yLGx3ZD0yLGNvbD0yLGFuZ2xlPTIwLGxlbmd0aD0uMSkKdGV4dChwb3M9NCxtZWFuKGNhcHRvcHJpbCRkZWx0YVNCUCkvc2UsLjAyLGxhYmVsPXBhc3RlKCJ0PSIscm91bmQobWVhbihjYXB0b3ByaWwkZGVsdGFTQlApL3NlLDIpKSxjb2w9MikKYXJyb3dzKDEwMCwuMix0Y3JpdCwuMixsd2Q9Mixjb2w9NCxhbmdsZT0yMCxsZW5ndGg9LjEpCnRleHQocG9zPTQsdGNyaXQsLjAyLGxhYmVsPXBhc3RlKCJ0LWNyaXQ9Iixyb3VuZCh0Y3JpdCwyKSksY29sPTIpCnBvbHlnb24oYyhyZWplY3QsdGNyaXQsLTEwKSxjKGR0KHJlamVjdCxuLTEpLDAsMCksY29sPTIsYm9yZGVyPTIpCnRleHQoLTMuNSwuMDUsbGFiZWw9ZXhwcmVzc2lvbihwYXN0ZShhbHBoYSwiPTAuMDUiKSksY29sPTIpCmFycm93cygtMiwwLjAyLC0zLjUsLjA0LGNvbD0yLGx3ZD0yLGFuZ2xlPTIwLGxlbmd0aD0uMSkKYGBgCgotLS0KCiMjIERlY2lzaW9uIEVycm9ycwoKVGhlIGRlY2lzaW9uIHRvIGFjY2VwdCBvciByZWplY3QgJEhfMCQgaXMgbWFkZSBiYXNlZCBvbiBhIHNpbmdsZSBzYW1wbGUuIApBIHdyb25nIGRlY2lzaW9uIGNvdWxkIGhhdmUgYmVlbiBtYWRlLiAKCmBgYHtyLGVjaG89RkFMU0V9CmxpYnJhcnkoImthYmxlRXh0cmEiKQpEZWNpc2lvbkVycm9ycz1kYXRhLmZyYW1lKENvbmNsdXNpb249YygiQWNjZXB0IEgwIiwiUmVqZWN0IEgwIiksIkgwIj1jKCJPSyIsIlR5cGUgSSAoJFxcYWxwaGEkKSIpLCJIMSI9YygiVHlwZSBJSSAoJFxcYmV0YSQpIiwiT0siKSkKa25pdHI6OmthYmxlKERlY2lzaW9uRXJyb3JzLCxhbGlnbj0iYyIpJT4lCiAga2FibGVfc3R5bGluZyggcG9zaXRpb24gPSAiY2VudGVyIikgJT4lCiAgYWRkX2hlYWRlcl9hYm92ZShjKCIgIiA9IDEsICJSZWFsaXR5IiA9IDIpKQpgYGAKIC0gVHlwZSBJIGVycm9yLCAkXGFscGhhJDogd3JvbmdseSByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcyAoZmFsc2UgcG9zaXRpdmUpCiBcdnNwYWNlezEwcHR9CiAtIFR5cGUgSUkgZXJyb3IsICRcYmV0YSQ6IHdyb25nbHkgYWNjZXB0IHRoZSBudWxsIGh5cG90aGVzaXMgCgogLSBEZWNpc2lvbiBpcyBhbHNvIHN0b2NoYXN0aWMhIFNlZSBmaXJzdCBjaGFwdGVyIG9mIHRoZSBjb3Vyc2UgCiAKIyMjIENhcHRvcHJpbCBFeGFtcGxlCgotICRIXzAkOiBhZG1pbmlzdGVyaW5nIGNhcHRvcHJpbCBoYXMgbm8gZWZmZWN0IG9uIHRoZSBzeXN0b2xpYyBibG9vZCBwcmVzc3VyZQoKLSAkSF8xJDogYWRtaW5pc3RlcmluZyBjYXB0b3ByaWwgYW4gYXZlcmFnZSBsZWFkcyB0byBhIGRlY3JlYXNlIGluIGJsb29kIHByZXNzdXJlCgotICoqVHlwZSBJIGVycm9yKio6IHRoZXJlIGlzIG9uIGF2ZXJhZ2Ugbm8gYmxvb2QgcHJlc3N1cmUgZHJvcCB1cG9uIGFkbWluaXN0ZXJpbmcgY2FwdG9wcmlsLCBidXQgd2UgY29uY2x1ZGUgdGhhdCB0aGVyZSBpcyBhbiBlZmZlY3Qgb2YgY2FwdG9wcmlsLiAKLSAqKlR5cGUgSUkgZXJyb3IqKjogdGhlcmUgaXMgb24gYXZlcmFnZSBhIGJsb29kIHByZXNzdXJlIGRyb3AgdXBvbiBhZG1pbmlzdGVyaW5nIGNhcHRvcHJpbCwgYnV0IGl0IGlzIG5vdCBwaWNrZWQgdXAgYnkgdGhlIHN0YXRpc3RpY2FsIHRlc3QuIAoKLS0tCgojIyMgVHlwZSBJIGVycm9yIGlzIGNvbnRyb2xsZWQKClRoZSB0eXBlIEkgZXJyb3IgaXMgY29udHJvbGxlZCBieSB0aGUgY29uc3RydWN0aW9uIG9mIHRoZSBzdGF0aXN0aWNhbCB0ZXN0LiAKCiQkXHRleHR7UH1cbGVmdFtcdGV4dHt0eXBlIEkgZXJyb3J9XHJpZ2h0XT1cdGV4dHtQfVxsZWZ0W1x0ZXh0e3JlamVjdCB9SF8wIFxtaWQgSF8wXHJpZ2h0XSA9IFx0ZXh0e1B9XzBcbGVmdFtUPHRfe24tMTsxLVxhbHBoYX1ccmlnaHRdPVxhbHBoYSAkJAoKCi0gVGhlIHNpZ25pZmljYW5jZS1sZXZlbCAkXGFscGhhJCBpcyB0aGUgcHJvYmFiaWxpdHkgdG8gbWFrZSBhIHR5cGUgSSBlcnJvci4KCi0gVGhlIHN0YXRpc3RpY2FsIHRlc3QgZW5zdXJlcyB0aGF0IHRoZSBwcm9iYWJpbGl0eSBvbiBhIHR5cGUgSSBlcnJvciBpcyBjb250cm9sbGVkIGF0IHRoZSBzaWduaWZpY2FuY2UgbGV2ZWwgJFxhbHBoYSQuCgotIFRoZSBwcm9iYWJpbGl0eSB0byBjb3JyZWN0bHkgYWNjZXB0ICRIXzAkIGlzICQxLVxhbHBoYSQuCgotIFdlIGNhbiBzaG93IHRoYXQgdGhlIHAtdmFsdWUgdW5kZXIgJEhfMCQgaXMgdW5pZm9ybSBkaXN0cmlidXRlZC4gCgotIFNvIHN0YXRpc3RpY2FsIGh5cG90aGVzaXMgdGVzdGluZyBsZWFkcyB0byBhIHVuaWZvcm0gZGVjaXNpb24gc3RyYXRlZ3kuIAoKV2Ugd2lsbCBpbGx1c3RyYXRlIHRoaXMgaW4gYSBzaW11bGF0aW9uIHN0dWR5CgotIG49MTUKLSAkXG11PTAkIG1tSGcKLSAkXHNpZ21hID05JCBtbUhnCi0gbnVtYmVyIG9mIHNpbXVsYXRpb25zIDEwMDAKCmBgYHtyfQpuc2ltIDwtIDEwMDAwCm4gPC0gMTUKc2lnbWEgPC0gOQptdSA8LSAwCm11MCA8LSAwCmFscGhhPTAuMDUKCiNzaW11bGF0ZSBuc2ltIHNhbXBsZXMgb2Ygc2l6ZSBuCmRlbHRhU2ltIDwtIG1hdHJpeChybm9ybShuKm5zaW0sbXUsc2lnbWEpLG5yb3c9bixuY29sPW5zaW0pCnBTaW0gPC0gYXBwbHkoZGVsdGFTaW0sMixmdW5jdGlvbih4LG11LGFsdGVybmF0aXZlKSB0LnRlc3QoeCxtdT1tdSxhbHRlcm5hdGl2ZT1hbHRlcm5hdGl2ZSkkcC52YWx1ZSxtdT1tdTAsYWx0ZXJuYXRpdmU9Imxlc3MiKQoKbWVhbihwU2ltPGFscGhhKQpwU2ltICU+JSAKICBhcy5kYXRhLmZyYW1lICU+JSAKICBnZ3Bsb3QoYWVzKHg9LikpICsKICBnZW9tX2hpc3RvZ3JhbSgpICsgCiAgeGxpbSgwLDEpCmBgYAoKLSBUaGUgdHlwZSBJIGVycm9yIGlzIGluZGVlZCBhYm91dCAwLjA1IAotIFRoZSBwLXZhbHVlcyBhcmUgdW5pZm9ybQoKLS0tCgojIyMgVHlwZSBJSSBlcnJvcgoKLSBEZXRlcm1pbmUgdGhlIHR5cGUgSUkgZXJyb3IgaXMgbGVzcyBldmlkZW50LiAKLSBXZSBoYXZlIHRvIHJlYXNvbiB1bmRlciAkSF8xJAotIEluIHRoZSBjYXB0b3ByaWwgdm9vcmJlZWxkIGlzICRIXzE6IFxtdTwwJAotIE1hbnkgYWx0ZXJuYXRpdmVzIGFyZSBwb3NzaWJsZQotIFRoZSBkaXN0cmlidXRpb24gdW5kZXIgJEhfMSQgaXMgbm90IGZ1bGx5IHNwZWNpZmllZAoKLSAqd29yay1hcm91bmQ6KiBjaG9vc2Ugb25lIHNwZWNpZmljIGRpc3RyaWJ1dGlvbiB1bmRlciAkSF8xJC4KCiAkJEhfMShcZGVsdGEpOiBcbXU9MC1cZGVsdGEgXHRleHR7IGZvciB9XGRlbHRhPjAuJCQKIAotIGUuZy4gYSBibG9vZCBwcmVzc3VyZSBkaWZmZXJlbmNlIG9mIDIgbW1IZwoKLSAxLXR5cGUgSUkgaXMgYWxzbyByZWZlcnJlZCB0byBhcyB0aGUgcG93ZXIuIEl0IGlzIHRoZSBwcm9iYWJpbGl0eSB0byBwaWNrIHVwIHRoZSBhbHRlcm5hdGl2ZS4gCgotIEl0IGlzIG5vdCBndWFyYW50ZWVkIGJ5IHRoZSBkZXNpZ24gb2YgdGhlIHRlc3QKCi0gSXQgZGVwZW5kcyBvbiB0aGUgZXhwZXJpbWVudGFsIGRlc2lnbiBvZiB0aGUgc3R1ZHkKCgpgYGB7cn0KbnNpbSA8LSAxMDAwMApuIDwtIDE1CnNpZ21hIDwtIDkKbXUgPC0gLTIKbXUwIDwtIDAKYWxwaGE9MC4wNQoKI3NpbXVsYXRlIG5zaW0gc2FtcGxlcyBvZiBzaXplIG4KZGVsdGFTaW0gPC0gbWF0cml4KHJub3JtKG4qbnNpbSxtdSxzaWdtYSksbnJvdz1uLG5jb2w9bnNpbSkKcFNpbSA8LSBhcHBseShkZWx0YVNpbSwyLGZ1bmN0aW9uKHgsbXUsYWx0ZXJuYXRpdmUpIHQudGVzdCh4LG11PW11LGFsdGVybmF0aXZlPWFsdGVybmF0aXZlKSRwLnZhbHVlLG11PW11MCxhbHRlcm5hdGl2ZT0ibGVzcyIpCgptZWFuKHBTaW08YWxwaGEpCnBTaW0gJT4lIAogIGFzLmRhdGEuZnJhbWUgJT4lIAogIGdncGxvdChhZXMoeD0uKSkgKwogIGdlb21faGlzdG9ncmFtKCkgKyAKICB4bGltKDAsMSkKYGBgCi0gV2Ugb2JzZXJ2ZSB0aGF0IGEgcG93ZXIgb2YgYHIgbWVhbihwU2ltPGFscGhhKWAgb3IgYSB0eXBlIElJIGVycm9yIG9mIGByIDEtbWVhbihwU2ltPGFscGhhKWAuCgotLS0KCi0gV2hlbiB3ZSBpbmNyZWFzZSB0aGUgc2FtcGxlIHNpemUKCmBgYHtyfQpuc2ltIDwtIDEwMDAwCm4gPC0gMzAKc2lnbWEgPC0gOQptdSA8LSAtMgptdTAgPC0gMAphbHBoYT0wLjA1Cgojc2ltdWxhdGUgbnNpbSBzYW1wbGVzIG9mIHNpemUgbgpkZWx0YVNpbSA8LSBtYXRyaXgocm5vcm0obipuc2ltLG11LHNpZ21hKSxucm93PW4sbmNvbD1uc2ltKQpwU2ltIDwtIGFwcGx5KGRlbHRhU2ltLDIsZnVuY3Rpb24oeCxtdSxhbHRlcm5hdGl2ZSkgdC50ZXN0KHgsbXU9bXUsYWx0ZXJuYXRpdmU9YWx0ZXJuYXRpdmUpJHAudmFsdWUsbXU9bXUwLGFsdGVybmF0aXZlPSJsZXNzIikKCm1lYW4ocFNpbTxhbHBoYSkKcFNpbSAlPiUgCiAgYXMuZGF0YS5mcmFtZSAlPiUgCiAgZ2dwbG90KGFlcyh4PS4pKSArCiAgZ2VvbV9oaXN0b2dyYW0oKSArIAogIHhsaW0oMCwxKQpgYGAKCi0gSW5jcmVhc2luZyB0aGUgc2FtcGxlIHNpemUgbGVhZHMgdG8gYSBoaWdoZXIgcG93ZXIuIAotIFN0aWxsIHRoZSBwb3dlciB0byBwaWNrIHVwIHN1Y2ggYSBzbWFsbCBibG9vZCBwcmVzc3VyZSBkcm9wIHJlbWFpbnMgdmVyeSBsb3cuCi0gQSBkcm9wIG9mIDIgbW1IZyBpcyBhbHNvIG5vdCByZWxldmFudCBmb3IgZHJ1ZyBjb21wYW5pZXMuIAoKIVtdKGh0dHBzOi8vd3d3Lm5hdHVyZS5jb20vYXJ0aWNsZXMvbm1ldGguMjczOC5wZGYpe3dpZHRoPTEwMCV9CgotLS0KCiMjIyBJbnRlcnByZXRhdGlvbgoKU3VwcG9zZSB0aGF0IGdpdmVuIGEgcGFydGljdWxhciBzYW1wbGUgJHA8XGFscGhhJCwgaS5lLiByZWplY3QgJEhfMCQgCgotIFR3byBwb3NzaWJpbGl0aWVzCgogICAgLSBjb3JyZWN0IGRlY2lzaW9uLAoJICAtIG9yIHR5cGUgSSBlcnJvci4KCi0gV2Uga25vd24gdGhhdCB0aGUgcHJvYmFiaWxpdHkgb24gYSB0eXBlIGVycm9yIGlzIGxvdywgaS5lLiAkXGFscGhhPTAuMDUkLgoKCk9uIHRoZSBvdGhlciBoYW5kLCB3aGVuICRwXGdlcVxhbHBoYSQgYW5kIHdlIGRvIG5vdCByZWplY3QgJEhfMCQgd2UgYWxzbyBoYXZlIHR3byBvcHRpb25zOgoKICAtIENvcnJlY3QgZGVjaXNpb24sCiAgLSBvciB3ZSBtYWRlIGEgdHlwZSBJSSBlcnJvci4KClRoZSBwcm9iYWJpbGl0eSBvbiBhIHR5cGUgSUkgZXJyb3IgKCRcYmV0YSQpIGlzIG5vdCBjb250cm9sbGVkIGF0IGEgc3BlY2lmaWMgdmFsdWUuIAoKU3RhdGlzdGljYWwgdGVzdCBpcyBjb25zdHJ1Y3RlZCB0byBvbmx5IGNvbnRyb2wgdGhlIHByb2JhYmlsaXR5IG9uIGEgdHlwZSBJIGVycm9yIGF0ICAkXGFscGhhJC4KClRvIGJlIHNjaWVudGlmaWNhbGx5IGNvcnJlY3Qgd2UgaGF2ZSB0byB0YWtlIGEgcGVzc2ltaXN0aWMgYXR0aXR1ZGUgYW5kIHdlIGhhdmUgdG8gYWRtaXQgdGhhdCAkXGJldGEkIGNhbiBiZSBsYXJnZSAoaS5lLiBhIHNtYWxsIHBvd2VyIHRvIGRldGVjdCB0aGUgYWx0ZXJuYXRpdmUpLgoKSGVuY2UsIAoKLSAkcCA8IFxhbHBoYSQgd2UgcmVqZWN0ICRIXzAkCgogICAgLSBXZSBjb25jbHVkZSB0aGF0ICRIXzEkIGlzIHByb2JhYmx5IGNvcnJlY3QuCgkgIC0gV2UgcmVmZXIgdG8gdGhpcyBhcyBhIHN0cm9uZyBjb25jbHVzaW9uLiAKCSAgCi0gJHAgXGdlcSBcYWxwaGEkIGFjY2VwdCAkSF8wJCAgCgoJICAtIERvZXMgbm90IGltcGx5IHRoYXQgd2UgYWNjZXB0ICRIXzAkIGNvcnJlY3RseS4KICAJLSBXZSBjYW4gb25seSBjb25jbHVkZSB0aGF0IHRoZSBkYXRhIGRvIG5vdCBoYXZlIGVub3VnaCBldmlkZW5jZSBhZ2FpbnN0IHRoZSAkSF8wJCBpbiBmYXZvdXIgb2YgJEhfMSQuCiAgICAtIFdlIHJlZmVyIHRvIHRoaXMgYXMgYSB3ZWFrIGNvbmNsdXNpb24uCiAgICAtIFdlIHR5cGljYWxseSBjb25jbHVkZSB0aGF0IHRoZSBlZmZlY3Qgb2YgdGhlIHRyZWF0bWVudCBpcyBub3Qgc2lnbmlmaWNhbnQuCgotLS0KICAgIAojIyBDb25jbHVzaW9ucyBjYXB0b3ByaWwgZXhhbXBsZQoKVGhlIHRlc3Qgd2UgaGF2ZSBwZXJmb3JtZWQgaXMgcmVmZXJyZWQgdG8gYXMKCi0gdGhlICoqb25lIHNhbXBsZSB0LXRlc3QqKiBvbiB0aGUgZGlmZmVyZW5jZSBvcgogIAotIGEgKipwYWlyZWQgdC10ZXN0KiouIEluZGVlZCB3ZSBkaXNwb3NlIG9mIHBhaXJlZCBvYnNlcnZhdGlvbnMgZm9yIGVhY2ggcGF0aWVudCEKCi0gVGhlIHRlc3QgaXMgZG9uZSBvbmUtc2lkZWQgYmVjYXVzZSB3ZSB0ZXN0IGFnYWluc3QgdGhlIGFsdGVybmF0aXZlIG9mIGEgYmxvb2QgcHJlc3N1cmUgZHJvcC4gCgotIEJvdGggdGVzdHMgKG9uZSBzYW1wbGUgdC10ZXN0IG9uIHRoZSBkaWZmZXJlbmNlIGFuZCBwYWlyZWQgdC10ZXN0KSBnaXZlIHRoZSBzYW1lIHJlc3VsdHM6IAoKYGBge3J9CnQudGVzdChjYXB0b3ByaWwkZGVsdGFTQlAsYWx0ZXJuYXRpdmU9Imxlc3MiKQpgYGAKCmBgYHtyfQp0LnRlc3QoY2FwdG9wcmlsJFNCUGEsY2FwdG9wcmlsJFNCUGIscGFpcmVkPVRSVUUsYWx0ZXJuYXRpdmU9Imxlc3MiKQpgYGAKCi0tLQoKIyMjIENvbmNsdXNpb24KClRoZXJlIGlzIG9uIGF2ZXJhZ2UgYW4gZXh0cmVtZWx5IHNpZ25pZmljYW50IGJsb29kIHByZXNzdXJlIGRyb3AgdXBvbiBhZG1pbmlzdGVyaW5nIGNhcHRvcHJpbCB0byBwYXRpZW50cyB3aXRoIGh5cGVydGVuc2lvbi4gVGhlIHN5c3RvbGljIGJsb29kIHByZXNzdXJlIGRlY3JlYXNlcyBvbiBhdmVyYWdlIHdpdGggMTguOSBtbUhnIHVwb24gdGhlIHRyZWF0bWVudCB3aXRoIGNhcHRvcHJpbCAoOTUlIENJIFskLVxpbmZ0eSwtMTQuODIkXSBtbUhnKS4KCk5vdGUgdGhhdAoKMS4gQSBvbmUtc2lkZWQgaW50ZXJ2YWwgaXMgcmVwb3J0ZWQgYmVjYXVzZSB3ZSBhcmUgb25seSBpbnRlcmVzdGVkIGluIGEgYmxvb2QgcHJlc3N1cmUgZHJvcC4gCgoyLiBCZWNhdXNlIG9mIHRoZSBwcmUtdGVzdC9wb3N0LXRlc3QgZGVzaWduIHdlIGNhbm5vdCBkaXN0aW5ndWlzaCBiZXR3ZWVuIHRoZSBlZmZlY3Qgb2YgdGhlIHRyZWF0bWVudCBhbmQgYSBwbGFjZWJvIGVmZmVjdC4gVGhlcmUgd2FzIG5vIGdvb2QgY29udHJvbCEgVGhlIGxhY2sgb2YgYSBnb29kIGNvbnRyb2wgdHlwaWNhbGx5IG9jY3VycyBpbiAgcHJlLXRlc3QvcG9zdC10ZXN0IGRlc2lnbnMuIEhvdyBjb3VsZCB3ZSBoYXZlIGltcHJvdmVkIHRoZSBkZXNpZ24/IAoKLS0tCgojIyBPbmUtc2lkZWQgb3IgdHdvLXNpZGUgdGVzdGluZz8gCgpEZSB0ZXN0IGluIHRoZSBjYXB0b3ByaWwgZXhhbXBsZSB3YXMgYSBvbmUtc2lkZWQgdGVzdC4gV2Ugb25seSBhaW0gdG8gZGV0ZWN0IGlmIHRoZSBjYXB0b3ByaWwgdHJlYXRtZW50IG9uIGF2ZXJhZ2UgcmVkdWNlcyB0aGUgYmxvb2QgcHJlc3N1cmUuIAoKU3VwcG9zZSB0aGF0IHdlIGRlZmluZWQgdGhlIGJsb29kIHByZXNzdXJlIGRpZmZlcmVuY2UgYXMgICRYX3tpfV5ccHJpbWU9WV97aX1eXHRleHR7YmVmb3JlfS1ZX3tpfV5cdGV4dHthZnRlcn0kCgotIE5vdywgYSBwb3NpdGl2ZSB2YWx1ZSBpbmRpY2F0ZXMgYSBibG9vZCBwcmVzc3VyZSBkcm9wIAoKLSBUaGUgYXZlcmFnZSBjaGFuZ2UgaW4gYmxvb2QgcHJlc3N1cmUgaXMgbm93IGRlbm90ZSBhcyAkXG11XlxwcmltZT1cdGV4dHtFfVtYXlxwcmltZV0kLgoKLSBTbyBub3cgd2Ugc2hvdWxkIHVzZSBhIG9uZS1zaWRlZCB0ZXN0IHRvIGFzc2VzcyAkSF8wOiBcbXVeXHByaW1lPTAkIGFnYWluc3QgJEhfMTogXG11XlxwcmltZT4wJC4KCi0gcC12YWx1ZSBub3cgYmVjb21lczogCiQkcD1cdGV4dHtQfV8wXGxlZnRbVFxnZXEgdFxyaWdodF0uJCQKCi0tLQoKQW5hbHlzaXMgYmFzZWQgb24gJFheXHByaW1lJDogQXJndW1lbnQgYGFsdGVybmF0aXZlPSJncmVhdGVyImAgc28gdGhhdCB3ZSB1c2UgJEhfMTogXG11XlxwcmltZT4wJDoKYGBge3J9CnQudGVzdChjYXB0b3ByaWwkU0JQYi1jYXB0b3ByaWwkU0JQYSxhbHRlcm5hdGl2ZT0iZ3JlYXRlciIpCmBgYAoKT2YgY291cnNlIHdlIG9idGFpbiB0aGUgc2FtZSByZXN1bHRzLiBPbmx5IHRoZSBzaWduIGlzIHN3YXBwZWQuIAoKLS0tCgojIyMgVHdvLXNpZGVkIHRlc3QKClN1cHBvc2UgdGhhdCByZXNlYXJjaGVycyB3YW50ZWQgdG8gYXNzZXNzIHRoZSBtb2RlIG9mIGFjdGlvbiBvZiB0aGUgbmV3IGRydWcgY2FwdG9wcmlsIGluIHRoZSBkZXNpZ24gcGhhc2UgYW5kIHN1cHBvc2UgdGhhdCBoZWFsdGh5IHN1YmplY3RzIHdlcmUgdXNlZCBpbiBhbiBlYXJseSBwaGFzZSBvZiB0aGUgZHJ1ZyBkZXZlbG9wbWVudC4gCgpJbiB0aGlzIGNhc2UgaXQgd291bGQgaGF2ZSBiZWVuIGludGVyZXN0aW5nIHRvIG9ic2VydmUgYmxvb2QgcHJlc3N1cmUgZHJvcHMgYXMgd2VsbCBhcyBnYWlucy4KClRoZW4gd2Ugd291bGQgcmVxdWlyZSBhIHR3by1zaWRlZCB0ZXN0IHN0cmF0ZWd5CgokJEhfMDogXG11PTAkJAphZ2FpbnN0IHRoZSBhbHRlcm5hdGl2ZSBoeXBvdGhlc2lzCgokJEhfMTogXG11XG5lcTAsJCQKCnNvIHRoYXQgdGhlIG1lYW4gdW5kZXIgdGhlIGFsdGVybmF0aXZlIGlzIGRpZmZlcmVudCBmcm9tIHplcm8uIAoKSXQgY2FuIGJlIHBvc2l0aXZlIGFzIHdlbGwgYXMgbmVnYXRpdmUgY2hhbmdlcyBhbmQgd2UgZGlkIG5vdCBrbm93IHVwZnJvbnQgaW4gd2hpY2ggZGlyZWN0aW9uIHRoZSByZWFsIG1lYW4gd2lsbCBkZXZpYXRlIGZyb20gJEhfMSQuCgoKV2UgY2FuIGNvbmR1Y3QgYSB0d28tc2lkZWQgdGVzdCBvbiB0aGUgJFxhbHBoYT01XCUkIHNpZ25pZmljYW5jZSBsZXZlbCBieQoKYGBge3Igb3V0LndpZHRoPScxMDAlJywgZmlnLmFzcD0uOCwgZmlnLmFsaWduPSdjZW50ZXInLGVjaG89RkFMU0V9CmdyaWQgPC1zZXEoLTEwLDEwLC4wMSkKdGNyaXQgPC0gcXQoMC45NzUsbi0xKQpyZWplY3QxIDwtIGMoZ3JpZFtncmlkPCAtdGNyaXRdLC10Y3JpdCkKcmVqZWN0MiA8LSBjKHRjcml0LGdyaWRbZ3JpZD50Y3JpdF0pCgpwbG90KGdyaWQsZHQoZ3JpZCxuLTEpLHR5cGU9ImwiLGx3ZD0yLHhsYWI9InQtc3RhdGlzdGljIix5bGFiPSJkZW5zaXR5Iix5bGltPWMoLS4wNSwuNCkpCmFibGluZSh2PWMoLTEsMSkqbWVhbihjYXB0b3ByaWwkZGVsdGFTQlApL3NlLGNvbD0yLGx3ZD0yLGx0eT0yKQphYmxpbmUodj1jKC0xLDEpKnRjcml0LGNvbD0yLGx0eT0xLGx3ZD0yKQp0ZXh0KGMoLTUsLTUsNSw1KSxjKC0uMDMsLS4wNSwtLjAzLC0uMDUpLGxhYmVsPWMoInJlamVjdGlvbi0iLCJyZWdpb24iLCJyZWplY3Rpb24tIiwicmVnaW9uIiksY29sPWMoMiwyLDIsMikpCnRleHQoYygwLDApLGMoLS4wMywtLjA1KSxsYWJlbD1jKCJhY2NlcHRpb24tIiwicmVnaW8iKSxjb2w9Yyg0LDQpKQoKYXJyb3dzKC0xMDAsLjQsLWFicyhtZWFuKGNhcHRvcHJpbCRkZWx0YVNCUCkvc2UpLC40LGx3ZD0yLGNvbD0yLGFuZ2xlPTIwLGxlbmd0aD0uMSkKYXJyb3dzKDEwMCwuNCxhYnMobWVhbihjYXB0b3ByaWwkZGVsdGFTQlApL3NlKSwuNCxsd2Q9Mixjb2w9MixhbmdsZT0yMCxsZW5ndGg9LjEpCnRleHQoLTEwLC4zNSxsYWJlbD0icC12YWx1ZSIsc3J0PTkwLGNvbD0yKQp0ZXh0KDEwLC4zNSxsYWJlbD0icC12YWx1ZSIsc3J0PTkwLGNvbD0yKQoKYXJyb3dzKC0xMDAsLS4wNCwtdGNyaXQsLS4wNCxsd2Q9Mixjb2w9MixhbmdsZT0yMCxsZW5ndGg9LjEpCmFycm93cygxMDAsLS4wNCx0Y3JpdCwtLjA0LGx3ZD0yLGNvbD0yLGFuZ2xlPTIwLGxlbmd0aD0uMSkKCnBvbHlnb24oYyhyZWplY3QxLC10Y3JpdCwtMTApLGMoZHQocmVqZWN0MSxuLTEpLDAsMCksY29sPTIsYm9yZGVyPTIpCnBvbHlnb24oYyh0Y3JpdCxyZWplY3QyLHRjcml0KSxjKDAsZHQocmVqZWN0MixuLTEpLDApLGNvbD0yLGJvcmRlcj0yKQoKdGV4dCgtMy41LC4wNSxsYWJlbD1leHByZXNzaW9uKHBhc3RlKGFscGhhLCIvMj0yLjUlIikpLGNvbD0yKQp0ZXh0KDMuNiwuMDUsbGFiZWw9ZXhwcmVzc2lvbihwYXN0ZShhbHBoYSwiLzI9Mi41JSIpKSxjb2w9MikKYXJyb3dzKC0zLDAuMDIsLTMuNSwuMDQsY29sPTIsbHdkPTIsYW5nbGU9MjAsbGVuZ3RoPS4xKQphcnJvd3MoMywwLjAyLDMuNSwuMDQsY29sPTIsbHdkPTIsYW5nbGU9MjAsbGVuZ3RoPS4xKQpgYGAKCi0tLQoKVGhlIGFyZ3VtZW50IGBhbHRlcm5hdGl2ZWAgb2YgdGhlIGB0LnRlc3RgIGZ1bmN0aW9uIGlzIGJ5IGRlZmF1bHQgYGFsdGVybmF0aXZlPSJ0d28uc2lkZWQiYC4KCmBgYHtyfQp0LnRlc3QoY2FwdG9wcmlsJGRlbHRhU0JQKQpgYGAKCi0gV2Ugc3RpbGwgb2J0YWluIGFuIGV4dHJlbWVseSBzaWduaWZpY2FudCByZXN1bHQuCi0gVGhlIHAtdmFsdWUgaXMgZG91YmxlIGFzIGxhcmdlIGJlY2F1c2Ugd2UgdGVzdCB0d28tc2lkZWQuIAoKSW5kZWVkIAoKJCRwPVBfMFtUIFxsZXEgLVx2ZXJ0IHQgXHZlcnRdICsgUF8wW1QgXGdlcSBcdmVydCB0IFx2ZXJ0XSA9IFBfMFtcdmVydCBUIFx2ZXJ0IFxnZXEgXHZlcnQgdCBcdmVydF0gPSAyIFx0aW1lcyBQXzBbVCBcZ2VxIFx2ZXJ0IHQgXHZlcnRdJCQKCi0gV2UgYWxzbyBvYnRhaW4gYSAgdHdvLXNpZGVkIGNvbmZpZGVuY2UgaW50ZXJ2YWwgCgotLS0KCiMjIyBPbmUtc2lkZWQgb3IgdHdvLXNpZGVkIHRlc3Q/CgpXaXRoIGEgb25lLXNpZGVkIHRlc3Qgd2UgY2FuIG1vcmUgZWFzaWx5IHJlamVjdCAkSF8wJCBvbiBjb25kaXRpb24gdGhhdCAkSF8xJCBpcyB0cnVlIHRoYW4gd2l0aCBhIHR3by1zaWRlZCB0ZXN0LiAKCi0gQWxsIGluZm9ybWF0aW9uIGlzIHVzZWQgdG8gdGVzdCBpbnRvIG9uZSBkaXJlY3Rpb24KCi0gVGhlIGRlY2lzaW9uIHRvIHRlc3Qgb25lLXNpZGVkIGhhcyB0byBiZSBkb25lIGluIHRoZSBkZXNpZ24gcGhhc2UgYmVmb3JlIHRoZSBleHBlcmltZW50IGlzIGNvbmR1Y3RlZAoKLSBFdmVuIGlmIHdlIGhhdmUgc3Ryb25nIGEgcHJpb3JpIHByZXN1bXB0aW9ucywgd2UgYXJlIG5vdCBlbnRpcmVseSBzdXJlIG90aGVyd2lzZSB3ZSB3b3VsZCBoYXZlIG5vIHJlYXNvbiB0byBkbyB0aGUgcmVzZWFyY2guIAoKLSBJZiB3ZSBwcm9wb3NlIGEgb25lLXNpZGVkIHRlc3QgaW4gdGhlIGRlc2lnbiBwaGFzZSBhbmQgd2Ugb2JzZXJ2ZSBhIHJlc3VsdCBpbiB0aGUgb3Bwb3NpdGUgZGlyZWN0aW9uIHRoYXQgd291bGQgYmUgc3RhdGlzdGljYWxseSBzaWduaWZpY2FudCB3ZSBjYW4gbm90IGRyYXcgY29uY2x1c2lvbnMgZnJvbSB0aGUgZXhwZXJpbWVudC4gCgotIEluIHRoZSBkZXNpZ24gcGhhc2Ugd2UgaGF2ZSBleGNsdWRlZCB0aGlzIHJlc3VsdCBiZWNhdXNlIGl0IGlzIHNvIHVuZXhwZWN0ZWQgdGhhdCBpdCBoYXMgdG8gYmUgYSBmYWxzZSBwb3NpdGl2ZS4gCgotIEhlbmNlLCBvbmUtc2lkZWQgdGVzdHMgYXJlIG5vdCByZWNvbW1lbmRlZC4gCgpBIHR3by1zaWRlZCB0ZXN0IGNhbiBhbHdheXMgYmUgZGVmZW5kZWQgYW5kIGFsbG93cyB5b3UgdG8gZGV0ZWN0IGFueSBkZXZpYXRpb24gb2YgJEhfMCQgYW5kIGlzIGhpZ2hseSByZWNvbW1lbmRlZC4gCgoKSXQgaXMgKipuZXZlciBhbGxvd2VkKiogdG8gY2hhbmdlIGEgdHdvLXNpZGVkIHRlc3QgaW50byBhIG9uZS1zaWRlZCB0ZXN0IGJhc2VkIG9uIHdoYXQgaGFzIGJlZW4gb2JzZXJ2ZWQgaW4gdGhlIHNhbXBsZSEgT3RoZXJ3aXNlIHRoZSB0eXBlIEkgZXJyb3Igb2YgdGhlIHRlc3Qgc3RyYXRlZ3kgaXMgbm90IGNvcnJlY3RseSBjb250cm9sbGVkLiAKCi0tLQoKV2UgaWxsdXN0cmF0ZSB0aGlzIGluIHRoZSBzaW11bGF0aW9uIHN0dWR5IGJlbG93OiAKCjEuIGNvcnJlY3QgdHdvLXNpZGVkIHRlc3QgYW5kCjIuIG9uZS1zaWRlZCB0ZXN0IHdpdGggaXRzIHNpZ24gYmFzZWQgb24gd2hhdCB3YXMgb2JzZXJ2ZWQgaW4gdGhlIHNhbXBsZS4gCgoKYGBge3J9Cm11IDwtIDAKc2lnbWEgPC0gOS4wCm5TaW0gPC0gMTAwMAphbHBoYSA8LSAwLjA1Cm4gPC0gMTUKcHZhbHNDb3IgPC0gcHZhbHNJbkNvcjwtYXJyYXkoMCxuU2ltKQpmb3IgKGkgaW4gMTpuU2ltKQp7Cgl4IDwtIHJub3JtKG4sbWVhbj1tdSxzZD1zaWdtYSkKCXB2YWxzQ29yW2ldIDwtIHQudGVzdCh4KSRwLnZhbHVlCglpZiAobWVhbih4KTwwKQoJCXB2YWxzSW5Db3JbaV0gPC0gdC50ZXN0KHgsYWx0ZXJuYXRpdmU9Imxlc3MiKSRwLnZhbHVlIGVsc2UKCQlwdmFsc0luQ29yW2ldIDwtIHQudGVzdCh4LGFsdGVybmF0aXZlPSJncmVhdGVyIikkcC52YWx1ZQp9CgptZWFuKHB2YWxzQ29yPDAuMDUpCm1lYW4ocHZhbHNJbkNvcjwwLjA1KQpgYGAKCi0gVHlwZSBJIGVycm9yIGNvcnJlY3RseSBjb250cm9sbGVkIGF0ICRcYWxwaGEkIGZvciB0d28tc2lkZWQgdGVzdC4KLSBUeXBlIEkgZXJyb3Igbm90IGNvcnJlY3RseSBjb250cm9sbGVkIHdoZW4gd2UgdGVzdCBvbmUtc2lkZWQgYmFzZWQgb24gd2hhdCB3ZSBvYnNlcnZlZCBpbiB0aGUgc2FtcGxlLiAKCiMgTmF0dXJlIGNvbHVtbiBvbiB0ZXN0aW5nCgohW10oaHR0cHM6Ly93d3cubmF0dXJlLmNvbS9hcnRpY2xlcy9ubWV0aC4yNjk4LnBkZil7d2lkdGg9MTAwJX0KCgoKLS0tCgojIFtIb21lXShodHRwczovL2d0cGIuZ2l0aHViLmlvL1BTTFMyMC8pIHstfQoK