Prostacyclin Example
Researchers study the effect of arachidonic acid on prostacyclin level in blood plasma. They use 3 different concentrations of arachidonic acid:
- low,
- medium and
- high dose
Each treatment is adopted to 12 rats. They measure the prostacyclin levels in blood plasma using an elisa fluorescence measurement.
prostacyclin <- read_tsv("https://raw.githubusercontent.com/GTPB/PSLS20/master/data/prostacyclin.txt")
prostacyclin$dose <- as.factor(prostacyclin$dose)
head(prostacyclin)
# A tibble: 6 x 2
prostac dose
<dbl> <fct>
1 19.2 10
2 10.8 10
3 33.6 10
4 11.9 10
5 15.9 10
6 33.3 10
Data exploration
prostacyclin %>%
ggplot(aes(x=dose,y=prostac,fill=dose)) +
geom_boxplot() +
geom_point(position="jitter") +
ylab("prostacyclin (ng/ml)")
prostacyclin %>%
ggplot(aes(sample=prostac)) +
geom_qq() +
geom_qq_line() +
facet_grid(~dose)
The data in the three groups is approximately Normally distributed with equal variance: \[Y_i \vert \text{group j} \sim N(\mu_j,\sigma^2),\] with \(j= \text{1, 2, 3}\)
Research Question
Research question can translated in the following hypotheses
\(H_0\): the arachidonic acid concentration has no effect on the mean prostacyclin level in blood plasma in rats \[
H_0:\mu_1=\mu_2 = \mu_3
\]
\(H_1\): the arachidonic acid concentration has an effect on the mean prostacyclin level in blood plasma in rats, which implies that the at least two means are different.
In terms of the model parameters this becomes
\[
H_0:\mu_1=\mu_2 = \mu_3
\] and \[H_1: \exists\ j,k \in \{1,\ldots,g\} : \mu_j\neq\mu_k\]
Alternative approach: split null hypothesis in partial hypotheses: \[
H_{0jk}: \mu_j=\mu_k \text{ versus } H_{1jk}: \mu_j \neq \mu_k
\]
Each hypothesis can be tested via two-sample t-tests \(\rightarrow\) multiple testing problem + loss of power.
\(\rightarrow\) assess \(H_0:\mu_1=\mu_2=\mu_3\) with a single test.
Analyse of Variance
Correct solution for testing problem: ANalysis Of VAriance (ANOVA)
- We develop the method for 3 groups (prostacyclin example)
- Model data with linear model by using dummy variables.
- 1 dummy variable less than the number of groups. Here we need 2 dummy variables.
- Generalizing to g groups \(g>3\) is trivial (extra dummy variables)
Model
\[\begin{eqnarray}
Y_i &=& g(x_{i1},x_{i2}) + \epsilon_i\\
Y_i &=& \beta_0+\beta_1 x_{i1} +\beta_2 x_{i2} +\epsilon_i
\end{eqnarray}\]
- \(Y_i\) de outcome for observation \(i\) (\(i=1,\ldots, n\))
- \(\epsilon_i\text{i.i.d.} N(0,\sigma^2)\)
- and dummy variables \[x_{i1} = \left\{ \begin{array}{ll}
1 & \text{ if observation $i$ belongs to middle dose group (M)} \\
0 & \text{ if observation $i$ belongs to other dose group} \end{array}\right.\] \[x_{i2} = \left\{ \begin{array}{ll}
1 & \text{ if observation $i$ belongs to high dose group (H)} \\
0 & \text{if observation $i$ belongs to other dose group} \end{array}\right. .\]
- Low dose group (L) with \(x_{i1}=x_{i2}=0\) is reference group
Regression-model can be rewritten as a model for each group :
\[\begin{eqnarray*}
Y_{i\vert \text{dose=L}} &=& \beta_0+\epsilon_i \\
Y_{i\vert \text{dose=M}} &=& \beta_0+\beta_1+ \epsilon_i \\
Y_{i\vert \text{dose=H}} &=& \beta_0+\beta_2 + \epsilon_i
\end{eqnarray*}\]
with \(\epsilon_i \sim N(0,\sigma^2)\)
Interpretation of model parameters:
\[\begin{eqnarray*}
\beta_0 &=& \text{E}\left[Y_i \mid \text{treatment with low dose group L}\right] \\
\beta_1 &=& (\beta_0+\beta_1)-\beta_0 = \text{E}\left[Y_i \mid \text{treatment M}\right] - \text{E}\left[Y_i \mid \text{treatment L}\right] \\
\beta_2 &=& (\beta_0+\beta_2)-\beta_0 = \text{E}\left[Y_i \mid \text{treatment H}\right]-\text{E}\left[Y_i \mid \text{treatment L}\right].
\end{eqnarray*}\]
- \(\beta_0\) is the mean outcome for group L
- \(\beta_1\) is effect (difference in mean concentration) of group M vs group L
- \(\beta_2\) is effect of group H vs group L
We reformulate the model by using
\(\mu\)-notations:
\[\begin{eqnarray*}
Y_{i\vert \text{dose=L}} &=& \beta_0+\epsilon_i = \mu_1+\epsilon_i \\
Y_{i\vert \text{dose=M}} &=& \beta_0+\beta_1+ \epsilon_i = \mu_2+\epsilon_i \\
Y_{i\vert \text{dose=H}} &=& \beta_0+\beta_2 + \epsilon_i = \mu_3+\epsilon_i .
\end{eqnarray*}\]
with \(\epsilon_i \sim N(0,\sigma^2)\) and \[ \mu_j = \text{E}\left[Y_i \mid \text{treatment group } j\right].\]
Original null hypothese \[H_0:\mu_1=\mu_2=\mu_3\] can be formulated as \[H_0: \beta_1=\beta_2=0.\]
Model allows us to use all methods from linear regression.
- Parameter estimators for means, variances and standard errors
- Inference: Confidence intervals, hypothesis tests
- Test \(H_0: \beta_1=\beta_2=0\) with \(F\)-test.
Prostacyclin example
model1 <- lm(prostac~dose,data=prostacyclin)
summary(model1)
Call:
lm(formula = prostac ~ dose, data = prostacyclin)
Residuals:
Min 1Q Median 3Q Max
-35.167 -17.117 -4.958 17.927 41.133
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 40.108 6.150 6.521 2.10e-07 ***
dose25 8.258 8.698 0.949 0.349
dose50 43.258 8.698 4.974 1.99e-05 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 21.3 on 33 degrees of freedom
Multiple R-squared: 0.458, Adjusted R-squared: 0.4252
F-statistic: 13.94 on 2 and 33 DF, p-value: 4.081e-05
Sum of squares and Anova
Similar to simple linear regression we will use sum of squares to derive the F-test.
\[\begin{eqnarray*}
\text{SSR}&=&\sum\limits_{i=1}^n (\hat Y_i -\bar Y)^2\\
&=& \sum\limits_{i=1}^n (\hat{g} (x_{i1},x_{i2}) - \bar Y)^2\\
&=& \sum\limits_{i=1}^n (\hat\beta_0+\hat\beta_1x_{i1}+\hat\beta_2x_{i2}) - \bar Y)^2\\
&=& \sum\limits_{i=1}^{n_1} (\hat\beta_0 - \bar Y)^2 +\sum\limits_{i=1}^{n_2} (\hat\beta_0 + \hat\beta_1 - \bar Y)^2+\sum\limits_{i=1}^{n_3} (\hat\beta_0 + \hat\beta_2 - \bar Y)^2\\
&=& \sum\limits_{i=1}^{n_1} (\bar Y_1- \bar Y)^2 +\sum\limits_{i=1}^{n_2} (\bar Y_2- \bar Y)^2+\sum\limits_{i=1}^{n_3} (\bar Y_3 - \bar Y)^2\\
\end{eqnarray*}\]
with \(n_1\), \(n_2\) en \(n_3\) the number of observations in each group (here \(n-1=n_2=n_3=12\)).
\[\begin{eqnarray*}
\text{SSR}&=&\sum\limits_{i=1}^n (\hat Y_i -\bar Y)^2
\end{eqnarray*}\]
Decomposition of Total Sum of Squares
- The convention in the Anova setting is to denote the sum of squares as SST, the Sum of Squares of the Treatment (treatment) or as SSBetween.
- The sum of squares of the regression indeed reflects the variability between the groups.
- The corresponding mean sum of squares becomes \(\text{MST}=\text{SST}/2\).
The decomposition of SSTot can be written as \[
\text{SSTot} = \text{SST} + \text{SSE}
\]
SSTot
SST
SSE
Anova test
Test \(H_0: \beta_1=\beta_2=0\) with \(F\)-test. \[
F = \frac{\text{MST}}{\text{MSE}}
\]
with
- \(\text{MST}=\text{SST}/(g-1)\)
- \(\text{MSE}=\text{SSE}/(n-p)\)
- Test statistic compares the variability explained by model (MST) with the residual variability (MSE)
or
- Variability between groups (MST) to variability within groups (MSE)
- Under \(H_0\): \(F \sim F_{g-1,n-g}\), with g=3.
Anova Table
Treatment |
d.f. SST |
SST |
MST |
F-statistiek |
p-waarde |
Error |
d.f. SSE |
SSE |
MSE |
|
|
Analysis of Variance Table
Response: prostac
Df Sum Sq Mean Sq F value Pr(>F)
dose 2 12658 6329.0 13.944 4.081e-05 ***
Residuals 33 14979 453.9
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
F-distribution with critical value (\(\alpha\)=5%) and observed F-statistic for prostacyclin example
F-distributions with different number of degrees of freedom in the nominator and denominator
Prostacyclin example: which groups are different?
Call:
lm(formula = prostac ~ dose, data = prostacyclin)
Residuals:
Min 1Q Median 3Q Max
-35.167 -17.117 -4.958 17.927 41.133
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 40.108 6.150 6.521 2.10e-07 ***
dose25 8.258 8.698 0.949 0.349
dose50 43.258 8.698 4.974 1.99e-05 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 21.3 on 33 degrees of freedom
Multiple R-squared: 0.458, Adjusted R-squared: 0.4252
F-statistic: 13.94 on 2 and 33 DF, p-value: 4.081e-05
With model output we can assess if the mean prostacyclin concentration differs between middle and low dose group (\(\beta_1\): dose25), and, between high and low dose group (\(\beta_2\): dose50).
The p-values do not account for multiple testing.
Post hoc analysis: Multiple comparisons of means
Naive method
In the first part we developed the \(F\)-test to assess
\[ H_0: \mu_1=\cdots = \mu_g \text{ versus } H_1: H_1: \exists\ j,k \in \{1,\ldots,g\} : \mu_j\neq\mu_k\]
- If we reject \(H_0\) we conclude that at least two means are different
- The method does not allow to identify which means are different.
A first naive method is to split \(H_0\) in partial hypotheses \[H_{0jk}: \mu_j=\mu_k \text{ versus } H_{1jk}: \mu_j \neq \mu_k\]
Falsify partial null hypotheses with two-sample \(t\)-testen
Comparison of group \(j\) with group \(k\) with two-sample \(t\)-test under the equality of means: \[T_{jk} = \frac{\bar{Y}_j-\bar{Y}_k}{S_p\sqrt{\frac{1}{n_j}+\frac{1}{n_k}}} \sim t_{n-2}\]
With
\(S_p^2\) the pooled variance estimator, \[S_p^2 = \frac{(n_j-1)S_j^2 + (n_k-1)S_k^2}{n_j+n_k-2}\]
with \(S_j^2\) and \(S_k^2\) the sample variances of group \(j\) en \(k\), respectively.
In ANOVA context we assume that the variance of all \(g\) groups is equal, i.e. the residual variance \(\sigma^2\).
Use of \(S_p^2\) is not efficient because it does not make use of all data
We can gain efficiency by using MSE \[\text{MSE}= \sum_{j=1}^g \frac{(n_j-1)S_j^2}{n-g}\]
The \(t\)-tests are thus best based on \[T_{jk} = \frac{\bar{Y}_j-\bar{Y}_k}{\text{MSE}\sqrt{\frac{1}{n_j}+\frac{1}{n_k}}} \sim t_{n-g}.\]
with(prostacyclin,pairwise.t.test(prostac,dose,"none"))
Pairwise comparisons using t tests with pooled SD
data: prostac and dose
10 25
25 0.34927 -
50 2e-05 0.00031
P value adjustment method: none
When we perform \(m\)-tests on the \(\alpha\) significance level we cannot correctly control the type I error.
We show with simulation that naive method does not work
- We simulate from an ANOVA model with \(g=3\) groups.
- The means in the ANOVA model are equal to each other, so that \[H_0: \mu_1=\mu_2=\mu_3\].
- For each simulated dataset we conduct \(m=3\) pairwise two-sample \(t\)-test
- As soon as one of the \(p\)-values is below significance level \(\alpha=5\%\), we reject \(H_0: \mu_1=\mu_2=\mu_3\) because two means are different according to the \(t\)-tests.
- We rapport the relative frequency of rejection of the global null hypothesis, i.e. the probability on a type I error \(H_0: \mu_1=\mu_2=\mu_3\).
g<-3 # number of treatments (g=3)
ni<-12 # number of observations in each group
n<-g*ni # total number of observation
alpha<-0.05 # significance level of individual test
N=10000 # number of simulations
set.seed(302) #seed to reproduce results exactly
trt=factor(rep(1:g,ni)) #factor
cnt<-0 #counter for erroneous rejections
for(i in 1:N) {
#if (i%%1000==0) cat(i,"/",N,"\n")
y <- rnorm(n)
tests<-pairwise.t.test(y,trt,"none")
reject<-min(tests$p.value,na.rm=T)<alpha
if(reject) cnt<-cnt+1
}
cnt/N
[1] 0.1209
- Probability on the type I error equals 12.1%
- It is more then twice \(\alpha=5\)%.
If we repeat the simulation with g = 5 groups (i.e. 10 pairwise t-tests) we find a type I error of 28.0% instead of the desired 5%.
The simulation study illustrates the multiplicity problem
- Classical p-values can only be compared with the significance level \(\alpha\), if the conclusion is based on a single p-value.
Here the final decision is based on \(m=g\times(g-1)/2\) \(p\)-values.
We first discuss on the extension of the concept of type I errors and then introduce some solutions
Family-wise error rate
- When \(m>1\) tests are used to make one decision it is necessary to correct for the risk on false positive results (type I errors).
Most procedures for multiple testing assume that all \(m\) null hypotheses are true.
So one tries to control the risk on at least 1 false positive on the family wise error rate (FWER) \(\alpha_F\), typical \(\alpha_F=0.05\).
Bonferroni correction
When we conduct
\(m\) independent test each on the significance level
\(\alpha\), then
\[\begin{eqnarray*}
\alpha_F&=&\text{P}[\text{at least 1 Type I fout}]\\
&=&1-(1-\alpha)^m \leq m\alpha
\end{eqnarray*}\]
- If we assess 5 tests on the 5% significance level then the FWER \(\approx 25\%\). {10pt}
By conducting them at the 1% significance level the FWER \(\approx 5\%\).
The Bonferroni correction controls the FWER on \(\alpha_F\) by setting \[\alpha=\alpha_F/m\] for each of the \(m\) pairwise comparisons
An alternative approach is to report
- adjusted p-values that can be compared to the FWER \(\alpha_F\) level: \[\tilde{p}=min(m\times p,1)\]
- and \((1-\alpha_F/m)100\%\) confidence intervals.
prostacyclin example
with(prostacyclin,pairwise.t.test(prostac,dose, data = prostacyclin, p.adjust.method="bonferroni"))
Pairwise comparisons using t tests with pooled SD
data: prostac and dose
10 25
25 1.00000 -
50 6e-05 0.00094
P value adjustment method: bonferroni
- The conclusions remain similar, except that the FWER is now controlled at \(\alpha_F=5\%\) and that the \(\tilde{p}\)-values are larger with a factor 3.
The same analysis can be conducted in the multcomp
R package that is developed for multiple testing in linear models.
model1.mcp<-glht(model1,linfct=mcp(dose="Tukey"))
summary(model1.mcp,test=adjusted("bonferroni"))
Simultaneous Tests for General Linear Hypotheses
Multiple Comparisons of Means: Tukey Contrasts
Fit: lm(formula = prostac ~ dose, data = prostacyclin)
Linear Hypotheses:
Estimate Std. Error t value Pr(>|t|)
25 - 10 == 0 8.258 8.698 0.949 1.000000
50 - 10 == 0 43.258 8.698 4.974 5.98e-05 ***
50 - 25 == 0 35.000 8.698 4.024 0.000943 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
(Adjusted p values reported -- bonferroni method)
Note, that the user has to define custum functions to obtain Bonferonni adjusted confidence intervals.
Bonferonni confidence intervals are not implemented because better methods exist for multiple testing.
The function below is added here merely for completeness, but we will generally use the default method for multiple testing in multcomp.
calpha_bon_t<-function(object,level)
abs(
qt(
(1-level)/2/nrow(object$linfct),
object$df
)
)
confint(model1.mcp,calpha=calpha_bon_t)
Simultaneous Confidence Intervals
Multiple Comparisons of Means: Tukey Contrasts
Fit: lm(formula = prostac ~ dose, data = prostacyclin)
Quantile = 2.5222
95% confidence level
Linear Hypotheses:
Estimate lwr upr
25 - 10 == 0 8.2583 -13.6790 30.1957
50 - 10 == 0 43.2583 21.3210 65.1957
50 - 25 == 0 35.0000 13.0626 56.9374
Evaluate Bonferroni method via simulation
g<-3 # number of treatments (g=3)
ni<-12 # number of observations in each group
n<-g*ni # totaal number observation
alpha<-0.05 # significance level of individual test
N=10000 # number of simulaties
set.seed(302) #seed to reproduce results exactly
trt=factor(rep(1:g,ni)) #factor
cnt<-0 #counter for erroneous rejections
for(i in 1:N) {
#if (i%%1000==0) cat(i,"/",N,"\n")
y <- rnorm(n)
tests<-pairwise.t.test(y,trt,"bonferroni")
reject<-min(tests$p.value,na.rm=T)<alpha
if(reject) cnt<-cnt+1
}
cnt/N
[1] 0.0457
Tukey Method
Captopril example
model1.mcp<-glht(model1,linfct=mcp(dose="Tukey"))
summary(model1.mcp)
Simultaneous Tests for General Linear Hypotheses
Multiple Comparisons of Means: Tukey Contrasts
Fit: lm(formula = prostac ~ dose, data = prostacyclin)
Linear Hypotheses:
Estimate Std. Error t value Pr(>|t|)
25 - 10 == 0 8.258 8.698 0.949 0.613390
50 - 10 == 0 43.258 8.698 4.974 < 1e-04 ***
50 - 25 == 0 35.000 8.698 4.024 0.000835 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
(Adjusted p values reported -- single-step method)
Simultaneous Confidence Intervals
Multiple Comparisons of Means: Tukey Contrasts
Fit: lm(formula = prostac ~ dose, data = prostacyclin)
Quantile = 2.4539
95% family-wise confidence level
Linear Hypotheses:
Estimate lwr upr
25 - 10 == 0 8.2583 -13.0849 29.6016
50 - 10 == 0 43.2583 21.9151 64.6016
50 - 25 == 0 35.0000 13.6567 56.3433
plot(confint(model1.mcp))
Evaluate Tukey method
g<-3 # number of treatments (g=3)
ni<-12 # number of observations in each group
n<-g*ni # totaal number observation
alpha<-0.05 # significance level of individual test
N <- 10000 # number of simulations
set.seed(302) #seed to reproduce results exactly
trt <- factor(rep(1:g,ni)) #factor
cnt<-0 #counter for erroneous rejections
for(i in 1:N) {
#if (i%%1000==0) cat(i,"/",N,"\n")
y <- rnorm(n)
m<-lm(y~trt)
m.mcp<-glht(m,linfct=mcp(trt="Tukey"))
tests<-summary(m.mcp)$test
reject<-min(as.numeric(tests$pvalues),na.rm=T)<alpha
if(reject) cnt<-cnt+1
}
cnt/N
[1] 0.0503
Conclusions: Prostacyclin example
Entire analysis for prostacyclin example
Anova before posthoc tests: F-test has a higher power than pairwise t-test
- F-test uses all data
- For F-test we do not need to correct for multiple testing: one test is conducted for the general omnibus hypothesis
model1 <- lm(prostac~dose,data=prostacyclin)
anova(model1)
Analysis of Variance Table
Response: prostac
Df Sum Sq Mean Sq F value Pr(>F)
dose 2 12658 6329.0 13.944 4.081e-05 ***
Residuals 33 14979 453.9
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
model1.mcp<-glht(model1,linfct=mcp(dose="Tukey"))
summary(model1.mcp)
Simultaneous Tests for General Linear Hypotheses
Multiple Comparisons of Means: Tukey Contrasts
Fit: lm(formula = prostac ~ dose, data = prostacyclin)
Linear Hypotheses:
Estimate Std. Error t value Pr(>|t|)
25 - 10 == 0 8.258 8.698 0.949 0.613433
50 - 10 == 0 43.258 8.698 4.974 < 1e-04 ***
50 - 25 == 0 35.000 8.698 4.024 0.000922 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
(Adjusted p values reported -- single-step method)
Simultaneous Confidence Intervals
Multiple Comparisons of Means: Tukey Contrasts
Fit: lm(formula = prostac ~ dose, data = prostacyclin)
Quantile = 2.4526
95% family-wise confidence level
Linear Hypotheses:
Estimate lwr upr
25 - 10 == 0 8.2583 -13.0736 29.5902
50 - 10 == 0 43.2583 21.9264 64.5902
50 - 25 == 0 35.0000 13.6681 56.3319
- There is an extreme significant effect of arachidonic acid on the average prostacyclin blood concentration in rats (\(p<0.001\)). The average prostacyclin concentration is higher in the high dose group than in the low and moderate dose group (both p-values are smaller than \(p<0.001\)).
- The average concentration in the high dose group is 43.3ng/ml (95% CI [21.9,64.6]ng/ml) and 35ng/ml (95% BI [13.6,56.4]ng/ml) higher than in the low and middle dose group, respectively.
- The difference in average prostacyclin concentration between the moderate and low dose group is not significant (p=0.61). (All p-values and confidence intervals for post-hoc tests are corrected for multiple testing using the Tukey method).
LS0tCnRpdGxlOiAiNy4gQW5hbHlzaXMgb2YgVmFyaWFuY2UiIAphdXRob3I6ICJMaWV2ZW4gQ2xlbWVudCIKZGF0ZTogInN0YXRPbWljcywgR2hlbnQgVW5pdmVyc2l0eSAoaHR0cHM6Ly9zdGF0b21pY3MuZ2l0aHViLmlvKSIKb3V0cHV0OgogICAgaHRtbF9kb2N1bWVudDoKICAgICAgY29kZV9kb3dubG9hZDogdHJ1ZSAgICAKICAgICAgdGhlbWU6IGNvc21vCiAgICAgIHRvYzogdHJ1ZQogICAgICB0b2NfZmxvYXQ6IHRydWUKICAgICAgaGlnaGxpZ2h0OiB0YW5nbwogICAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGluY2x1ZGUgPSBUUlVFLCBjb21tZW50ID0gTkEsIGVjaG8gPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0UpCmxpYnJhcnkoUm1pc2MpCmxpYnJhcnkodGlkeXZlcnNlKQpgYGAKCgojIFByb3N0YWN5Y2xpbiBFeGFtcGxlCgpSZXNlYXJjaGVycyBzdHVkeSB0aGUgZWZmZWN0IG9mIGFyYWNoaWRvbmljIGFjaWQgb24gcHJvc3RhY3ljbGluIGxldmVsIGluIGJsb29kIHBsYXNtYS4gVGhleSB1c2UgMyBkaWZmZXJlbnQgY29uY2VudHJhdGlvbnMgb2YgYXJhY2hpZG9uaWMgYWNpZDogCgotIGxvdywgCi0gbWVkaXVtIGFuZCAKLSBoaWdoIGRvc2UKCkVhY2ggdHJlYXRtZW50IGlzIGFkb3B0ZWQgdG8gMTIgcmF0cy4gVGhleSBtZWFzdXJlIHRoZSBwcm9zdGFjeWNsaW4gbGV2ZWxzIGluIGJsb29kIHBsYXNtYSB1c2luZyBhbiBlbGlzYSBmbHVvcmVzY2VuY2UgbWVhc3VyZW1lbnQuCgoKYGBge3J9CnByb3N0YWN5Y2xpbiA8LSByZWFkX3RzdigiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL0dUUEIvUFNMUzIwL21hc3Rlci9kYXRhL3Byb3N0YWN5Y2xpbi50eHQiKQpwcm9zdGFjeWNsaW4kZG9zZSA8LSBhcy5mYWN0b3IocHJvc3RhY3ljbGluJGRvc2UpCmhlYWQocHJvc3RhY3ljbGluKQpgYGAKCi0tLQoKIyNEYXRhIGV4cGxvcmF0aW9uCgpgYGB7cn0KcHJvc3RhY3ljbGluICU+JSAKICBnZ3Bsb3QoYWVzKHg9ZG9zZSx5PXByb3N0YWMsZmlsbD1kb3NlKSkgKwogIGdlb21fYm94cGxvdCgpICsKICBnZW9tX3BvaW50KHBvc2l0aW9uPSJqaXR0ZXIiKSArCiAgeWxhYigicHJvc3RhY3ljbGluIChuZy9tbCkiKQogIApwcm9zdGFjeWNsaW4gJT4lIAogIGdncGxvdChhZXMoc2FtcGxlPXByb3N0YWMpKSArCiAgZ2VvbV9xcSgpICsKICBnZW9tX3FxX2xpbmUoKSArIAogIGZhY2V0X2dyaWQofmRvc2UpCmBgYAoKClRoZSBkYXRhIGluIHRoZSB0aHJlZSBncm91cHMgaXMgYXBwcm94aW1hdGVseSBOb3JtYWxseSBkaXN0cmlidXRlZCB3aXRoIGVxdWFsIHZhcmlhbmNlOgpcW1lfaSBcdmVydCBcdGV4dHtncm91cCBqfSBcc2ltIE4oXG11X2osXHNpZ21hXjIpLFxdCndpdGggJGo9IFx0ZXh0ezEsIDIsIDN9JAoKIyMgUmVzZWFyY2ggUXVlc3Rpb24KClJlc2VhcmNoIHF1ZXN0aW9uIGNhbiB0cmFuc2xhdGVkIGluIHRoZSBmb2xsb3dpbmcgaHlwb3RoZXNlcyAKCi0gJEhfMCQ6IHRoZSBhcmFjaGlkb25pYyBhY2lkIGNvbmNlbnRyYXRpb24gaGFzIG5vIGVmZmVjdCBvbiB0aGUgbWVhbiBwcm9zdGFjeWNsaW4gbGV2ZWwgaW4gYmxvb2QgcGxhc21hIGluIHJhdHMKXFsKICBIXzA6XG11XzE9XG11XzIgPSBcbXVfMwpcXQoKLSAkSF8xJDogdGhlIGFyYWNoaWRvbmljIGFjaWQgY29uY2VudHJhdGlvbiBoYXMgYW4gZWZmZWN0IG9uIHRoZSBtZWFuIHByb3N0YWN5Y2xpbiBsZXZlbCBpbiBibG9vZCBwbGFzbWEgaW4gcmF0cywgd2hpY2ggaW1wbGllcyB0aGF0IHRoZSBhdCBsZWFzdCB0d28gbWVhbnMgYXJlIGRpZmZlcmVudC4KCkluIHRlcm1zIG9mIHRoZSBtb2RlbCBwYXJhbWV0ZXJzIHRoaXMgYmVjb21lcwoKXFsKICBIXzA6XG11XzE9XG11XzIgPSBcbXVfMwpcXQphbmQKXFtIXzE6IFxleGlzdHNcIGosayBcaW4gXHsxLFxsZG90cyxnXH0gOiBcbXVfalxuZXFcbXVfa1xdCgoKQWx0ZXJuYXRpdmUgYXBwcm9hY2g6IHNwbGl0IG51bGwgaHlwb3RoZXNpcyBpbiBwYXJ0aWFsIGh5cG90aGVzZXM6IApcWwogIEhfezBqa306IFxtdV9qPVxtdV9rIFx0ZXh0eyB2ZXJzdXMgfSBIX3sxamt9OiBcbXVfaiBcbmVxIFxtdV9rClxdCgpFYWNoIGh5cG90aGVzaXMgY2FuIGJlIHRlc3RlZCB2aWEgdHdvLXNhbXBsZSB0LXRlc3RzICRccmlnaHRhcnJvdyQgbXVsdGlwbGUgdGVzdGluZyBwcm9ibGVtICsgbG9zcyBvZiBwb3dlci4KCiRccmlnaHRhcnJvdyQgYXNzZXNzICRIXzA6XG11XzE9XG11XzI9XG11XzMkIHdpdGggYSAqc2luZ2xlIHRlc3QqLgoKCgojIEFuYWx5c2Ugb2YgVmFyaWFuY2UKCkNvcnJlY3Qgc29sdXRpb24gZm9yIHRlc3RpbmcgcHJvYmxlbTogQU5hbHlzaXMgT2YgVkFyaWFuY2UgKEFOT1ZBKQoKLSBXZSBkZXZlbG9wIHRoZSBtZXRob2QgZm9yIDMgZ3JvdXBzIChwcm9zdGFjeWNsaW4gZXhhbXBsZSkKLSBNb2RlbCBkYXRhIHdpdGggbGluZWFyIG1vZGVsIGJ5IHVzaW5nIGR1bW15IHZhcmlhYmxlcy4KLSAxIGR1bW15IHZhcmlhYmxlIGxlc3MgdGhhbiB0aGUgbnVtYmVyIG9mIGdyb3Vwcy4gSGVyZSB3ZSBuZWVkIDIgZHVtbXkgdmFyaWFibGVzLgotIEdlbmVyYWxpemluZyB0byBnIGdyb3VwcyAkZz4zJCBpcyB0cml2aWFsIChleHRyYSBkdW1teSB2YXJpYWJsZXMpCgojIyMgTW9kZWwKClxiZWdpbntlcW5hcnJheX0KICBZX2kgJj0mIGcoeF97aTF9LHhfe2kyfSkgKyBcZXBzaWxvbl9pXFwKICBZX2kgJj0mIFxiZXRhXzArXGJldGFfMSB4X3tpMX0gK1xiZXRhXzIgeF97aTJ9ICtcZXBzaWxvbl9pClxlbmR7ZXFuYXJyYXl9CgotICRZX2kkIGRlIG91dGNvbWUgZm9yIG9ic2VydmF0aW9uICRpJCAoJGk9MSxcbGRvdHMsIG4kKQpcdnNwYWNlezdwdH0KLSAkXGVwc2lsb25faVx0ZXh0e2kuaS5kLn0gTigwLFxzaWdtYV4yKSQKXHZzcGFjZXs3cHR9Ci0gYW5kIGR1bW15IHZhcmlhYmxlcyAKJCR4X3tpMX0gPSBcbGVmdFx7IFxiZWdpbnthcnJheX17bGx9CjEgJiBcdGV4dHsgaWYgb2JzZXJ2YXRpb24gJGkkIGJlbG9uZ3MgdG8gbWlkZGxlIGRvc2UgZ3JvdXAgKE0pfSBcXAowICYgXHRleHR7IGlmIG9ic2VydmF0aW9uICRpJCBiZWxvbmdzIHRvIG90aGVyIGRvc2UgZ3JvdXB9IFxlbmR7YXJyYXl9XHJpZ2h0LiQkCiQkeF97aTJ9ID0gXGxlZnRceyBcYmVnaW57YXJyYXl9e2xsfQoxICYgXHRleHR7IGlmIG9ic2VydmF0aW9uICRpJCBiZWxvbmdzIHRvIGhpZ2ggZG9zZSBncm91cCAoSCl9IFxcCjAgJiBcdGV4dHtpZiBvYnNlcnZhdGlvbiAkaSQgYmVsb25ncyB0byBvdGhlciBkb3NlIGdyb3VwfSBcZW5ke2FycmF5fVxyaWdodC4gLiQkClx2c3BhY2V7N3B0fQogLSBMb3cgZG9zZSBncm91cCAoTCkgd2l0aCAkeF97aTF9PXhfe2kyfT0wJCBpcyAgKnJlZmVyZW5jZSBncm91cCoKClJlZ3Jlc3Npb24tbW9kZWwgY2FuIGJlIHJld3JpdHRlbiBhcyBhIG1vZGVsIGZvciBlYWNoIGdyb3VwIDoKXHZzcGFjZXstMjBwdH0KXGJlZ2lue2VxbmFycmF5Kn0KIFlfe2lcdmVydCBcdGV4dHtkb3NlPUx9fSAmPSYgXGJldGFfMCtcZXBzaWxvbl9pIFxcCiBZX3tpXHZlcnQgXHRleHR7ZG9zZT1NfX0gJj0mIFxiZXRhXzArXGJldGFfMSsgXGVwc2lsb25faSAgXFwKIFlfe2lcdmVydCBcdGV4dHtkb3NlPUh9fSAmPSYgXGJldGFfMCtcYmV0YV8yICsgXGVwc2lsb25faQpcZW5ke2VxbmFycmF5Kn0Kd2l0aCAkXGVwc2lsb25faSBcc2ltIE4oMCxcc2lnbWFeMikkClx2c3BhY2V7MTBwdH0KCkludGVycHJldGF0aW9uIG9mIG1vZGVsIHBhcmFtZXRlcnM6Clx2c3BhY2V7LTIwcHR9CiBcYmVnaW57ZXFuYXJyYXkqfQogICBcYmV0YV8wICY9JiAgXHRleHR7RX1cbGVmdFtZX2kgXG1pZCBcdGV4dHt0cmVhdG1lbnQgd2l0aCBsb3cgZG9zZSBncm91cCBMfVxyaWdodF0gXFwKICAgXGJldGFfMSAmPSYgIChcYmV0YV8wK1xiZXRhXzEpLVxiZXRhXzAgPSBcdGV4dHtFfVxsZWZ0W1lfaSBcbWlkIFx0ZXh0e3RyZWF0bWVudCBNfVxyaWdodF0gLSBcdGV4dHtFfVxsZWZ0W1lfaSBcbWlkIFx0ZXh0e3RyZWF0bWVudCBMfVxyaWdodF0gXFwKICAgXGJldGFfMiAmPSYgIChcYmV0YV8wK1xiZXRhXzIpLVxiZXRhXzAgPSBcdGV4dHtFfVxsZWZ0W1lfaSBcbWlkIFx0ZXh0e3RyZWF0bWVudCBIfVxyaWdodF0tXHRleHR7RX1cbGVmdFtZX2kgXG1pZCBcdGV4dHt0cmVhdG1lbnQgTH1ccmlnaHRdLgogXGVuZHtlcW5hcnJheSp9CgogMS4gICRcYmV0YV8wJCBpcyB0aGUgbWVhbiBvdXRjb21lIGZvciBncm91cCBMCiBcdnNwYWNlezdwdH0KIDIuICAkXGJldGFfMSQgaXMgZWZmZWN0IChkaWZmZXJlbmNlIGluIG1lYW4gIGNvbmNlbnRyYXRpb24pIG9mIGdyb3VwIE0gdnMgZ3JvdXAgTAogXHZzcGFjZXs3cHR9CiAzLiAgJFxiZXRhXzIkIGlzIGVmZmVjdCBvZiBncm91cCBIIHZzIGdyb3VwIEwKCgpXZSByZWZvcm11bGF0ZSB0aGUgbW9kZWwgYnkgdXNpbmcgJFxtdSQtbm90YXRpb25zOgogXHZzcGFjZXstN3B0fQogXGJlZ2lue2VxbmFycmF5Kn0KICBZX3tpXHZlcnQgXHRleHR7ZG9zZT1MfX0gJj0mIFxiZXRhXzArXGVwc2lsb25faSA9IFxtdV8xK1xlcHNpbG9uX2kgXFwKICBZX3tpXHZlcnQgXHRleHR7ZG9zZT1NfX0gJj0mIFxiZXRhXzArXGJldGFfMSsgXGVwc2lsb25faSA9IFxtdV8yK1xlcHNpbG9uX2kgXFwKICBZX3tpXHZlcnQgXHRleHR7ZG9zZT1IfX0gJj0mIFxiZXRhXzArXGJldGFfMiArIFxlcHNpbG9uX2kgPSBcbXVfMytcZXBzaWxvbl9pIC4KIFxlbmR7ZXFuYXJyYXkqfQogd2l0aCAkXGVwc2lsb25faSBcc2ltIE4oMCxcc2lnbWFeMikkIGFuZAogJCQgIFxtdV9qID0gXHRleHR7RX1cbGVmdFtZX2kgXG1pZCBcdGV4dHt0cmVhdG1lbnQgZ3JvdXAgfSBqXHJpZ2h0XS4kJAoKIE9yaWdpbmFsIG51bGwgaHlwb3RoZXNlIAogJCRIXzA6XG11XzE9XG11XzI9XG11XzMkJAogY2FuIGJlIGZvcm11bGF0ZWQgYXMKICQkSF8wOiBcYmV0YV8xPVxiZXRhXzI9MC4kJAoKTW9kZWwgYWxsb3dzIHVzIHRvIHVzZSBhbGwgbWV0aG9kcyBmcm9tIGxpbmVhciByZWdyZXNzaW9uLgoKLSBQYXJhbWV0ZXIgZXN0aW1hdG9ycyBmb3IgbWVhbnMsIHZhcmlhbmNlcyBhbmQgIHN0YW5kYXJkIGVycm9ycwpcdnNwYWNlezEwcHR9Ci0gSW5mZXJlbmNlOiBDb25maWRlbmNlIGludGVydmFscywgaHlwb3RoZXNpcyB0ZXN0cwpcdnNwYWNlezEwcHR9CiAgLSBUZXN0ICRIXzA6IFxiZXRhXzE9XGJldGFfMj0wJCB3aXRoICRGJC10ZXN0LgoKIyMgUHJvc3RhY3ljbGluIGV4YW1wbGUKCmBgYHtyfQptb2RlbDEgPC0gbG0ocHJvc3RhY35kb3NlLGRhdGE9cHJvc3RhY3ljbGluKQpzdW1tYXJ5KG1vZGVsMSkKYGBgCgoKIyBTdW0gb2Ygc3F1YXJlcyBhbmQgQW5vdmEKClNpbWlsYXIgdG8gc2ltcGxlIGxpbmVhciByZWdyZXNzaW9uIHdlIHdpbGwgdXNlIHN1bSBvZiBzcXVhcmVzIHRvIGRlcml2ZSB0aGUgRi10ZXN0LgpcdnNwYWNley0xMHB0fQpcYmVnaW57ZXFuYXJyYXkqfQpcdGV4dHtTU1J9Jj0mXHN1bVxsaW1pdHNfe2k9MX1ebiAoXGhhdCBZX2kgLVxiYXIgWSleMlxcCiY9JiBcc3VtXGxpbWl0c197aT0xfV5uIChcaGF0e2d9ICh4X3tpMX0seF97aTJ9KSAtIFxiYXIgWSleMlxcCiY9JiBcc3VtXGxpbWl0c197aT0xfV5uIChcaGF0XGJldGFfMCtcaGF0XGJldGFfMXhfe2kxfStcaGF0XGJldGFfMnhfe2kyfSkgLSBcYmFyIFkpXjJcXAomPSYgXHN1bVxsaW1pdHNfe2k9MX1ee25fMX0gKFxoYXRcYmV0YV8wIC0gXGJhciBZKV4yICtcc3VtXGxpbWl0c197aT0xfV57bl8yfSAoXGhhdFxiZXRhXzAgKyBcaGF0XGJldGFfMSAtIFxiYXIgWSleMitcc3VtXGxpbWl0c197aT0xfV57bl8zfSAoXGhhdFxiZXRhXzAgKyBcaGF0XGJldGFfMiAtIFxiYXIgWSleMlxcCiY9JiBcc3VtXGxpbWl0c197aT0xfV57bl8xfSAoXGJhciBZXzEtIFxiYXIgWSleMiArXHN1bVxsaW1pdHNfe2k9MX1ee25fMn0gKFxiYXIgWV8yLSBcYmFyIFkpXjIrXHN1bVxsaW1pdHNfe2k9MX1ee25fM30gKFxiYXIgWV8zIC0gXGJhciBZKV4yXFwKXGVuZHtlcW5hcnJheSp9CndpdGggJG5fMSQsICRuXzIkIGVuICRuXzMkIHRoZSBudW1iZXIgb2Ygb2JzZXJ2YXRpb25zIGluIGVhY2ggZ3JvdXAgKGhlcmUgJG4tMT1uXzI9bl8zPTEyJCkuCgoKXGJlZ2lue2VxbmFycmF5Kn0KXHRleHR7U1NSfSY9JlxzdW1cbGltaXRzX3tpPTF9Xm4gKFxoYXQgWV9pIC1cYmFyIFkpXjIKXGVuZHtlcW5hcnJheSp9CgotIFN1bSBvZiBzcXVhcmVzIGlzIGFnYWluIGVxdWl2YWxlbnQgd2l0aCBjb21wYXJpc29uIG9mIG1vZGVsICgxKSBhbmQgcmVkdWNlZCBtb2RlbCB3aXRoIGFuIGludGVyY2VwdCwgb25seS4gCi0gRm9yIHJlZHVjZWQgbW9kZWwgdGhlIGludGVyY2VwdCBpcyBlc3RpbWF0ZWQgYnkgdGhlIHNhbXBsZSBtZWFuLiAgCi0gVGhpcyBzdW0gb2Ygc3F1YXJlcyBoYXMgZy0xPTIgZGVncmVlcyBvZiBmcmVlZG9tOiAgCgogIC0gZz0zIG1vZGVsIHBhcmFtZXRlcnMgLSAxIHBhcmFtZXRlciB0byBlc3RpbWF0ZSBvdmVyYWxsIHNhbXBsZSBtZWFuIG9yCiAgLSBnPTMgcGFyLiBpbiBjb21wbGV4IG1vZGVsIC0gMSBwYXIuIGluIHJlZHVjZWQgbW9kZWwuCgoKIyMgRGVjb21wb3NpdGlvbiBvZiBUb3RhbCBTdW0gb2YgU3F1YXJlcwoKIC0gVGhlIGNvbnZlbnRpb24gaW4gdGhlIEFub3ZhIHNldHRpbmcgaXMgdG8gZGVub3RlIHRoZSBzdW0gb2Ygc3F1YXJlcyBhcyBTU1QsIHRoZSAqKlN1bSBvZiBTcXVhcmVzIG9mIHRoZSBUcmVhdG1lbnQgKHRyZWF0bWVudCkqKiBvciBhcyBTU0JldHdlZW4uCi0gVGhlIHN1bSBvZiBzcXVhcmVzIG9mIHRoZSByZWdyZXNzaW9uIGluZGVlZCByZWZsZWN0cyB0aGUgdmFyaWFiaWxpdHkgYmV0d2VlbiB0aGUgZ3JvdXBzLiAKLSBUaGUgY29ycmVzcG9uZGluZyBtZWFuIHN1bSBvZiBzcXVhcmVzIGJlY29tZXMgICRcdGV4dHtNU1R9PVx0ZXh0e1NTVH0vMiQuCgpUaGUgZGVjb21wb3NpdGlvbiBvZiBTU1RvdCBjYW4gYmUgd3JpdHRlbiBhcyAKXFsKICBcdGV4dHtTU1RvdH0gPSBcdGV4dHtTU1R9ICsgXHRleHR7U1NFfQpcXQoKIyNTU1RvdAoKXHZzcGFjZXsxMHB0fQoKYGBge3IgZWNobz1GQUxTRSwgd2FybmluZz1GQUxTRX0KcGFyKG1mcm93PWMoMSwyKSkKaml0SWs9cnVuaWYoMzYsLS4yLC4yKStyZXAoMTozLGVhY2g9MTIpCnBsb3QocHJvc3RhY35kb3NlLGRhdGE9cHJvc3RhY3ljbGluLHhsYWI9IkFyYWNoaWRvbmljIGFjaWQgZG9zZSAiLHlsYWI9IlByb3N0YWN5Y2xpbiAobmcvbWwpIixjZXguYXhpcz0xLjUsY2V4LmxhYj0xLjUsY2V4Lm1haW49MS41KQpwb2ludHMoaml0SWsscHJvc3RhY3ljbGluJHByb3N0YWMsY29sPWNvbCxwY2g9MTkpCnBvaW50cyhqaXRJayxwcm9zdGFjeWNsaW4kcHJvc3RhYyxjb2w9NCkKcG9pbnRzKDE6MyxwcmVkaWN0KG1vZGVsMSxkYXRhLmZyYW1lKGRvc2U9ZmFjdG9yKGMoMTAsMjUsNTApKSkpLHBjaD0xNyxjb2w9YygiYmlzcXVlIiwiY29yYWwiLCJkYXJrY3lhbiIpLGNleD0xLjUpCnBvaW50cygxOjMscHJlZGljdChtb2RlbDEsZGF0YS5mcmFtZShkb3NlPWZhY3RvcihjKDEwLDI1LDUwKSkpKSxwY2g9Mixjb2w9MSxjZXg9MS41KQphYmxpbmUoaD1tZWFuKHByb3N0YWN5Y2xpbiRwcm9zdGFjKSxsdHk9MSkKZm9yIChpIGluIDE6MzYpIGxpbmVzKHJlcChqaXRJa1tpXSwyKSxjKG1lYW4ocHJvc3RhY3ljbGluJHByb3N0YWMpLHByb3N0YWN5Y2xpbiRwcm9zdGFjW2ldKSxjb2w9NCxsdHk9MikKaml0SWs9cnVuaWYoMzYsLS4yLC4yKStyZXAoMTozLGVhY2g9MTIpCgpwbG90KHJlcCgxLDM2KSxwcm9zdGFjeWNsaW4kcHJvc3RhYy1tZWFuKHByb3N0YWN5Y2xpbiRwcm9zdGFjKSx4YXh0PSJub25lIix5bGFiPSJEZXZpYXRpb25zIixjZXgubGFiPTEuNSxjZXgubWFpbj0xLjUsY2V4LmF4aXM9MS41LGNvbD1hcy5jaGFyYWN0ZXIocHJvc3RhY3ljbGluJGNvbCkseGxpbT1jKDEsMykscGNoPTE5LHhsYWI9IiIpCnBvaW50cyhyZXAoMSwzNikscHJvc3RhY3ljbGluJHByb3N0YWMtbWVhbihwcm9zdGFjeWNsaW4kcHJvc3RhYykscGNoPTEsY29sPTQpCmF4aXMoYXQ9MTozLGxhYmVscz1jKGV4cHJlc3Npb24ocGFzdGUoeVtpXSwiIC0gIixiYXIoeSkpKSxleHByZXNzaW9uKHBhc3RlKGJhcih5KVtqXSwiIC0gIixiYXIoeSkpKSxleHByZXNzaW9uKHBhc3RlKHlbaV0sIiAtICIsYmFyKHkpW2pdKSkpLHNpZGU9MSxjZXguYXhpcz0xLjUpCmBgYAoKCiMjU1NUCgpcdnNwYWNlezEwcHR9CgpgYGB7ciBlY2hvPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpwYXIobWZyb3c9YygxLDIpKQpwbG90KHByb3N0YWN+ZG9zZSxkYXRhPXByb3N0YWN5Y2xpbix4bGFiPSJBcmFjaGlkb25pYyBhY2lkIGRvc2UgIix5bGFiPSJQcm9zdGFjeWNsaW4gKG5nL21sKSIsY2V4LmF4aXM9MS41LGNleC5sYWI9MS41LGNleC5tYWluPTEuNSkKcG9pbnRzKGppdElrLHByb3N0YWN5Y2xpbiRwcm9zdGFjLGNvbD1jb2wscGNoPTE5KQpwb2ludHMoaml0SWsscHJvc3RhY3ljbGluJHByb3N0YWMsY29sPTQpCnBvaW50cygxOjMscHJlZGljdChtb2RlbDEsZGF0YS5mcmFtZShkb3NlPWZhY3RvcihjKDEwLDI1LDUwKSkpKSxwY2g9MTcsY29sPWMoImJpc3F1ZSIsImNvcmFsIiwiZGFya2N5YW4iKSxjZXg9MS41KQpwb2ludHMoMTozLHByZWRpY3QobW9kZWwxLGRhdGEuZnJhbWUoZG9zZT1mYWN0b3IoYygxMCwyNSw1MCkpKSkscGNoPTIsY29sPTIsY2V4PTEuNSkKYWJsaW5lKGg9bWVhbihwcm9zdGFjeWNsaW4kcHJvc3RhYyksbHR5PTEpCmZvciAoaSBpbiAxOjMpIGxpbmVzKHJlcChpLDIpLGMobWVhbihwcm9zdGFjeWNsaW4kcHJvc3RhYykscHJlZGljdChtb2RlbDEsZGF0YS5mcmFtZShkb3NlPWxldmVscyhwcm9zdGFjeWNsaW4kZG9zZSlbaV0pKSksY29sPTIsbHR5PTIpCgpwbG90KHJlcCgxLDM2KSxwcm9zdGFjeWNsaW4kcHJvc3RhYy1tZWFuKHByb3N0YWN5Y2xpbiRwcm9zdGFjKSx4YXh0PSJub25lIix5bGFiPSJEZXZpYXRpb25zIixjZXgubGFiPTEuNSxjZXgubWFpbj0xLjUsY2V4LmF4aXM9MS41LGNvbD1hcy5jaGFyYWN0ZXIocHJvc3RhY3ljbGluJGNvbCkseGxpbT1jKDEsMykscGNoPTE5LHhsYWI9IiIpCnBvaW50cyhyZXAoMSwzNikscHJvc3RhY3ljbGluJHByb3N0YWMtbWVhbihwcm9zdGFjeWNsaW4kcHJvc3RhYykscGNoPTEsY29sPTQpCnBvaW50cyhyZXAoMiwzKSxwcmVkaWN0KG1vZGVsMSxkYXRhLmZyYW1lKGRvc2U9ZmFjdG9yKGMoMTAsMjUsNTApKSkpLW1lYW4ocHJvc3RhY3ljbGluJHByb3N0YWMpLHBjaD0xNyxjb2w9dW5pcXVlKHByb3N0YWN5Y2xpbiRjb2wpLGNleD0xLjUpCnBvaW50cyhyZXAoMiwzKSxwcmVkaWN0KG1vZGVsMSxkYXRhLmZyYW1lKGRvc2U9ZmFjdG9yKGMoMTAsMjUsNTApKSkpLW1lYW4ocHJvc3RhY3ljbGluJHByb3N0YWMpLHBjaD0yLGNleD0xLjUsY29sPTIpCmF4aXMoYXQ9MTozLGxhYmVscz1jKGV4cHJlc3Npb24ocGFzdGUoeVtpXSwiIC0gIixiYXIoeSkpKSxleHByZXNzaW9uKHBhc3RlKGJhcih5KVtqXSwiIC0gIixiYXIoeSkpKSxleHByZXNzaW9uKHBhc3RlKHlbaV0sIiAtICIsYmFyKHkpW2pdKSkpLHNpZGU9MSxjZXguYXhpcz0xLjUpCmBgYAoKIyNTU0UKClx2c3BhY2V7MTBwdH0KCmBgYHtyIGVjaG89RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnBhcihtZnJvdz1jKDEsMikpCnBsb3QocHJvc3RhY35kb3NlLGRhdGE9cHJvc3RhY3ljbGluLHhsYWI9IkFyYWNoaWRvbmljIGFjaWQgZG9zZSAiLHlsYWI9IlByb3N0YWN5Y2xpbiAobmcvbWwpIixjZXguYXhpcz0xLjUsY2V4LmxhYj0xLjUsY2V4Lm1haW49MS41KQpwb2ludHMoaml0SWsscHJvc3RhY3ljbGluJHByb3N0YWMsY29sPWNvbCxwY2g9MTkpCnBvaW50cyhqaXRJayxwcm9zdGFjeWNsaW4kcHJvc3RhYyxjb2w9MSkKcG9pbnRzKDE6MyxwcmVkaWN0KG1vZGVsMSxkYXRhLmZyYW1lKGRvc2U9ZmFjdG9yKGMoMTAsMjUsNTApKSkpLHBjaD0xNyxjb2w9YygiYmlzcXVlIiwiY29yYWwiLCJkYXJrY3lhbiIpLGNleD0xLjUpCnBvaW50cygxOjMscHJlZGljdChtb2RlbDEsZGF0YS5mcmFtZShkb3NlPWZhY3RvcihjKDEwLDI1LDUwKSkpKSxwY2g9Mixjb2w9MixjZXg9MS41KQpmb3IgKGkgaW4gMTozKSBsaW5lcyhjKGktLjIsaSsuMikscmVwKHByZWRpY3QobW9kZWwxLGRhdGEuZnJhbWUoZG9zZT1sZXZlbHMocHJvc3RhY3ljbGluJGRvc2UpW2ldKSksMiksY29sPWMoImJpc3F1ZSIsImNvcmFsIiwiZGFya2N5YW4iKVtpXSkKYWJsaW5lKGg9bWVhbihwcm9zdGFjeWNsaW4kcHJvc3RhYyksbHR5PTEpCmZvciAoaSBpbiAxOjM2KSBsaW5lcyhyZXAoaml0SWtbaV0sMiksYyhwcm9zdGFjeWNsaW4kcHJvc3RhY1tpXSxtb2RlbDEkZml0dGVkW2ldKSxjb2w9MSxsdHk9MikKCnBsb3QocmVwKDEsMzYpLHByb3N0YWN5Y2xpbiRwcm9zdGFjLW1lYW4ocHJvc3RhY3ljbGluJHByb3N0YWMpLHhheHQ9Im5vbmUiLHlsYWI9IkRldmlhdGlvbnMiLGNleC5sYWI9MS41LGNleC5tYWluPTEuNSxjZXguYXhpcz0xLjUsY29sPWFzLmNoYXJhY3Rlcihwcm9zdGFjeWNsaW4kY29sKSx4bGltPWMoMSwzKSxwY2g9MTkseGxhYj0iIikKcG9pbnRzKHJlcCgxLDM2KSxwcm9zdGFjeWNsaW4kcHJvc3RhYy1tZWFuKHByb3N0YWN5Y2xpbiRwcm9zdGFjKSxwY2g9MSxjb2w9NCkKcG9pbnRzKHJlcCgyLDMpLHByZWRpY3QobW9kZWwxLGRhdGEuZnJhbWUoZG9zZT1mYWN0b3IoYygxMCwyNSw1MCkpKSktbWVhbihwcm9zdGFjeWNsaW4kcHJvc3RhYykscGNoPTE3LGNvbD11bmlxdWUocHJvc3RhY3ljbGluJGNvbCksY2V4PTEuNSkKcG9pbnRzKHJlcCgyLDMpLHByZWRpY3QobW9kZWwxLGRhdGEuZnJhbWUoZG9zZT1mYWN0b3IoYygxMCwyNSw1MCkpKSktbWVhbihwcm9zdGFjeWNsaW4kcHJvc3RhYykscGNoPTIsY29sPTIsY2V4PTEuNSkKcG9pbnRzKHJlcCgzLDM2KSxtb2RlbDEkcmVzLHBjaD0xOSxjb2w9YXMuY2hhcmFjdGVyKHByb3N0YWN5Y2xpbiRjb2wpKQpwb2ludHMocmVwKDMsMzYpLG1vZGVsMSRyZXMscGNoPTEpCmF4aXMoYXQ9MTozLGxhYmVscz1jKGV4cHJlc3Npb24ocGFzdGUoeVtpXSwiIC0gIixiYXIoeSkpKSxleHByZXNzaW9uKHBhc3RlKGJhcih5KVtqXSwiIC0gIixiYXIoeSkpKSxleHByZXNzaW9uKHBhc3RlKHlbaV0sIiAtICIsYmFyKHkpW2pdKSkpLHNpZGU9MSxjZXguYXhpcz0xLjUpCmBgYAoKCiMjIEFub3ZhIHRlc3QKClRlc3QgJEhfMDogXGJldGFfMT1cYmV0YV8yPTAkIHdpdGggJEYkLXRlc3QuClxbCiAgRiA9IFxmcmFje1x0ZXh0e01TVH19e1x0ZXh0e01TRX19ClxdCgp3aXRoCgotICRcdGV4dHtNU1R9PVx0ZXh0e1NTVH0vKGctMSkkICAKXHZzcGFjZXsxMHB0fQotICRcdGV4dHtNU0V9PVx0ZXh0e1NTRX0vKG4tcCkkClx2c3BhY2V7MTBwdH0KLSBUZXN0IHN0YXRpc3RpYyBjb21wYXJlcyB0aGUgdmFyaWFiaWxpdHkgZXhwbGFpbmVkIGJ5ICBtb2RlbCAoTVNUKSB3aXRoIHRoZSByZXNpZHVhbCB2YXJpYWJpbGl0eSAoTVNFKQoKb3IKCi0gVmFyaWFiaWxpdHkgYmV0d2VlbiBncm91cHMgKE1TVCkgdG8gdmFyaWFiaWxpdHkgd2l0aGluIGdyb3VwcyAoTVNFKQpcdnNwYWNlezEwcHR9Ci0gVW5kZXIgJEhfMCQ6ICRGIFxzaW0gRl97Zy0xLG4tZ30kLCB3aXRoIGc9My4KCgojIyBBbm92YSBUYWJsZQoKfCB8RGZ8U3VtIFNxfE1lYW4gU3F8RiB2YWx1ZXxQcig+Ril8CnwtLS18LS0tfC0tLXwtLS18LS0tfC0tLXwKfFRyZWF0bWVudHxkLmYuIFNTVHxTU1R8TVNUfEYtc3RhdGlzdGlla3xwLXdhYXJkZXwKfEVycm9yfGQuZi4gU1NFfFNTRXxNU0V8IHwgfAoKYGBge3J9CmFub3ZhKG1vZGVsMSkKYGBgCgoKIyMjIEYtZGlzdHJpYnV0aW9uIHdpdGggY3JpdGljYWwgdmFsdWUgICgkXGFscGhhJD01JSkgYW5kIG9ic2VydmVkIEYtc3RhdGlzdGljIGZvciBwcm9zdGFjeWNsaW4gZXhhbXBsZQpgYGB7ciBwcm9zdGFjRiwgb3V0LndpZHRoPScxMDAlJywgZmlnLmFzcD0uOCwgZmlnLmFsaWduPSdjZW50ZXInLGVjaG89RkFMU0V9CmdyaWQgPC0gc2VxKDAsMTcsLjAxKQpkZjE9YW5vdmEobW9kZWwxKVsxLDFdCmRmMj1hbm92YShtb2RlbDEpWzIsMV0KZnZhbD1hbm92YShtb2RlbDEpWzEsNF0KY3JpdD1xZigwLjk1LGRmMSxkZjIpCnJlamVjdD1jKGNyaXQsZ3JpZFt3aGljaChncmlkPmNyaXQpXSkKYWNjZXB0PWMoZ3JpZFt3aGljaChncmlkPGNyaXQpXSxjcml0KQpwbG90KGdyaWQsZGYoZ3JpZCxkZjEsZGYyKSx0eXBlPSJsIix5bGFiPSJEZW5zaXR5Iix4bGFiPSJGLXN0YXRpc3RpYyIsY2V4LmF4aXM9MS41LGNleC5sYWI9MS41KQpwb2x5Z29uKGMoMCxhY2NlcHQsY3JpdCwwKSxjKDAsZGYoYWNjZXB0LGRmMSxkZjIpLDAsMCksY29sPSJibHVlIixib3JkZXI9ImJsdWUiKQp0ZXh0KGNyaXQvMiwuOTcsbGFiZWxzPSJhY2NlcHRcbjk1JSIsY29sPSJibHVlIixjZXg9MS41KQpwb2x5Z29uKGMoY3JpdCxyZWplY3QsMTUsY3JpdCksYygwLGRmKHJlamVjdCxkZjEsZGYyKSwwLDApLGNvbD0icmVkIixib3JkZXI9InJlZCIpCmFibGluZSh2PWNyaXQsY29sPSJyZWQiLGx3ZD0yKQp0ZXh0KGNyaXQrKGZ2YWwtY3JpdCkvMiwuOTcsbGFiZWxzPSJyZWplY3RcbjUlIixjb2w9InJlZCIsY2V4PTEuNSkKdGV4dChwb3M9NCxjcml0LGRmKGNyaXQsMiwzMyksbGFiZWxzPXBhc3RlMCgiRigwLjA1LCIsZGYxLCIsIixkZjIsIikiKSxjb2w9InJlZCIsY2V4PTEuNSkKdGV4dChwb3M9NCxmdmFsLGRmKGNyaXQsZGYxLGRmMiksbGFiZWxzPXBhc3RlMCgiZj0iLHJvdW5kKGZ2YWwsMSkpLGNvbD0iZGFya29yYW5nZSIsY2V4PTEuNSkKYWJsaW5lKHY9ZnZhbCxjb2w9ImRhcmtvcmFuZ2UiLGx3ZD0yLGx0eT0yKQp0ZXh0KDE1LjUsLjk3LGxhYmVscz1wYXN0ZTAoInAtdmFsdWVcbiIsZm9ybWF0KGFub3ZhKG1vZGVsMSlbMSw1XSxkaWdpdHM9MikpLGNvbD0iZGFya29yYW5nZSIsY2V4PTEuNSkKYXJyb3dzKHgwPTE3LjUseDE9ZnZhbCx5MD0uOSx5MT0uOSxjb2w9ImRhcmtvcmFuZ2UiKQpgYGAKCgojIyMgRi1kaXN0cmlidXRpb25zIHdpdGggZGlmZmVyZW50IG51bWJlciBvZiBkZWdyZWVzIG9mIGZyZWVkb20gaW4gdGhlIG5vbWluYXRvciBhbmQgZGVub21pbmF0b3IgCmBgYHtyIGZ0aGVvLCBvdXQud2lkdGg9JzEwMCUnLCBmaWcuYXNwPS44LCBmaWcuYWxpZ249J2NlbnRlcicsZWNobz1GQUxTRX0KcGxvdChncmlkLGRmKGdyaWQsMSw1KSx0eXBlPSJsIix5bGFiPSJEZW5zaXR5Iix4bGFiPSJGLXN0YXRpc3RpYyIseGxpbT1jKDAsNSkseWxpbT1jKDAsMS41KSxsd2Q9MixjZXguYXhpcz0xLjUsY2V4LmxhYj0xLjUpCmxpbmVzKGdyaWQsZGYoZ3JpZCw1LDUpLHR5cGU9ImwiLGNvbD0yLGx3ZD0yKQpsaW5lcyhncmlkLGRmKGdyaWQsMTAsMzApLHR5cGU9ImwiLGNvbD0zLGx3ZD0yKQpsaW5lcyhncmlkLGRmKGdyaWQsMjAsMzApLHR5cGU9ImwiLGNvbD00LGx3ZD0yKQpsaW5lcyhncmlkLGRmKGdyaWQsNTAsNTApLHR5cGU9ImwiLGNvbD01LGx3ZD0yKQpsZWdlbmQoInRvcHJpZ2h0IixsdHk9MSxjb2w9YygxLDIsMyw0LDUpLGxlZ2VuZD1jKCJGKDEsNSkiLCJGKDUsNSkiLCJGKDEwLDMwKSIsIkYoMjAsMzApIiwiRig1MCw1MCkiKSxsd2Q9MixjZXg9MS41KQpgYGAKCiMjI1Byb3N0YWN5Y2xpbiBleGFtcGxlOiB3aGljaCBncm91cHMgYXJlIGRpZmZlcmVudD8KCmBgYHtyfQpzdW1tYXJ5KG1vZGVsMSkKYGBgCgpXaXRoIG1vZGVsIG91dHB1dCB3ZSBjYW4gYXNzZXNzIGlmIHRoZSBtZWFuIHByb3N0YWN5Y2xpbiBjb25jZW50cmF0aW9uIGRpZmZlcnMgYmV0d2VlbiBtaWRkbGUgYW5kIGxvdyBkb3NlIGdyb3VwICgkXGJldGFfMSQ6IGRvc2UyNSksIGFuZCwgYmV0d2VlbiBoaWdoIGFuZCBsb3cgZG9zZSBncm91cCAoJFxiZXRhXzIkOiBkb3NlNTApLgoKVGhlIHAtdmFsdWVzIGRvIG5vdCBhY2NvdW50IGZvciBtdWx0aXBsZSB0ZXN0aW5nLiAgCgojIFBvc3QgaG9jIGFuYWx5c2lzOiBNdWx0aXBsZSBjb21wYXJpc29ucyBvZiBtZWFucwoKIyMgTmFpdmUgbWV0aG9kCgpJbiB0aGUgZmlyc3QgcGFydCB3ZSBkZXZlbG9wZWQgdGhlICRGJC10ZXN0IHRvIGFzc2VzcwoKJCQgIEhfMDogXG11XzE9XGNkb3RzID0gXG11X2cgXHRleHR7IHZlcnN1cyB9IEhfMTogSF8xOiBcZXhpc3RzXCBqLGsgXGluIFx7MSxcbGRvdHMsZ1x9IDogXG11X2pcbmVxXG11X2skJAoKCi0gSWYgd2UgcmVqZWN0ICRIXzAkIHdlIGNvbmNsdWRlIHRoYXQgYXQgbGVhc3QgdHdvIG1lYW5zIGFyZSBkaWZmZXJlbnQKLSBUaGUgbWV0aG9kIGRvZXMgbm90IGFsbG93IHRvIGlkZW50aWZ5IHdoaWNoIG1lYW5zIGFyZSBkaWZmZXJlbnQuCgpBIGZpcnN0IG5haXZlIG1ldGhvZCBpcyB0byBzcGxpdCAkSF8wJCAgaW4gcGFydGlhbCBoeXBvdGhlc2VzCiQkSF97MGprfTogXG11X2o9XG11X2sgXHRleHR7IHZlcnN1cyB9IEhfezFqa306IFxtdV9qIFxuZXEgXG11X2skJAoKLSBGYWxzaWZ5IHBhcnRpYWwgbnVsbCBoeXBvdGhlc2VzIHdpdGggdHdvLXNhbXBsZSAkdCQtdGVzdGVuCgotIENvbXBhcmlzb24gb2YgZ3JvdXAgJGokIHdpdGggZ3JvdXAgJGskIHdpdGggdHdvLXNhbXBsZSAkdCQtdGVzdCB1bmRlciB0aGUgZXF1YWxpdHkgb2YgbWVhbnM6CiQkVF97amt9ID0gXGZyYWN7XGJhcntZfV9qLVxiYXJ7WX1fa317U19wXHNxcnR7XGZyYWN7MX17bl9qfStcZnJhY3sxfXtuX2t9fX0gXHNpbSB0X3tuLTJ9JCQKCldpdGgKCi0gJFNfcF4yJCB0aGUgcG9vbGVkIHZhcmlhbmNlIGVzdGltYXRvciwKJCRTX3BeMiA9IFxmcmFjeyhuX2otMSlTX2peMiArIChuX2stMSlTX2teMn17bl9qK25fay0yfSQkCgotIHdpdGggJFNfal4yJCBhbmQgJFNfa14yJCB0aGUgc2FtcGxlIHZhcmlhbmNlcyBvZiBncm91cCAkaiQgZW4gJGskLCByZXNwZWN0aXZlbHkuIAoKSW4gQU5PVkEgY29udGV4dCB3ZSBhc3N1bWUgdGhhdCB0aGUgdmFyaWFuY2Ugb2YgKiphbGwqKiAkZyQgZ3JvdXBzIGlzIGVxdWFsLCBpLmUuIHRoZSByZXNpZHVhbCB2YXJpYW5jZSAkXHNpZ21hXjIkLgoKLSBVc2Ugb2YgJFNfcF4yJCBpcyBub3QgZWZmaWNpZW50IGJlY2F1c2UgaXQgZG9lcyBub3QgbWFrZSB1c2Ugb2YgYWxsIGRhdGEKCi0gV2UgY2FuIGdhaW4gZWZmaWNpZW5jeSBieSB1c2luZyBNU0UKJCRcdGV4dHtNU0V9PSBcc3VtX3tqPTF9XmcgXGZyYWN7KG5fai0xKVNfal4yfXtuLWd9JCQKCi0gVGhlICR0JC10ZXN0cyBhcmUgdGh1cyBiZXN0IGJhc2VkIG9uCiQkVF97amt9ID0gXGZyYWN7XGJhcntZfV9qLVxiYXJ7WX1fa317XHRleHR7TVNFfVxzcXJ0e1xmcmFjezF9e25fan0rXGZyYWN7MX17bl9rfX19IFxzaW0gdF97bi1nfS4kJAoKLS0tCgpgYGB7cn0Kd2l0aChwcm9zdGFjeWNsaW4scGFpcndpc2UudC50ZXN0KHByb3N0YWMsZG9zZSwibm9uZSIpKQpgYGAKCldoZW4gd2UgcGVyZm9ybSAkbSQtdGVzdHMgb24gdGhlICRcYWxwaGEkIHNpZ25pZmljYW5jZSBsZXZlbCB3ZSBjYW5ub3QgY29ycmVjdGx5IGNvbnRyb2wgdGhlIHR5cGUgSSBlcnJvci4KCiMjIFdlIHNob3cgd2l0aCBzaW11bGF0aW9uIHRoYXQgbmFpdmUgbWV0aG9kIGRvZXMgbm90IHdvcmsKCjEuIFdlIHNpbXVsYXRlIGZyb20gYW4gQU5PVkEgbW9kZWwgd2l0aCAkZz0zJCBncm91cHMuCjIuIFRoZSBtZWFucyBpbiB0aGUgQU5PVkEgbW9kZWwgYXJlIGVxdWFsIHRvIGVhY2ggb3RoZXIsIHNvIHRoYXQgJCRIXzA6IFxtdV8xPVxtdV8yPVxtdV8zJCQuCjMuIEZvciBlYWNoIHNpbXVsYXRlZCBkYXRhc2V0IHdlIGNvbmR1Y3QgJG09MyQgcGFpcndpc2UgdHdvLXNhbXBsZSAkdCQtdGVzdAo0LiBBcyBzb29uIGFzIG9uZSBvZiB0aGUgJHAkLXZhbHVlcyBpcyBiZWxvdyBzaWduaWZpY2FuY2UgbGV2ZWwgJFxhbHBoYT01XCUkLCB3ZSByZWplY3QgJEhfMDogXG11XzE9XG11XzI9XG11XzMkIGJlY2F1c2UgdHdvIG1lYW5zIGFyZSBkaWZmZXJlbnQgYWNjb3JkaW5nIHRvIHRoZSAgJHQkLXRlc3RzLgo1LiBXZSByYXBwb3J0IHRoZSByZWxhdGl2ZSBmcmVxdWVuY3kgb2YgcmVqZWN0aW9uIG9mIHRoZSBnbG9iYWwgbnVsbCBoeXBvdGhlc2lzLCBpLmUuIHRoZSBwcm9iYWJpbGl0eSBvbiBhIHR5cGUgSSBlcnJvciAgJEhfMDogXG11XzE9XG11XzI9XG11XzMkLgoKCmBgYHtyfQpnPC0zICMgbnVtYmVyIG9mIHRyZWF0bWVudHMgKGc9MykKbmk8LTEyICMgbnVtYmVyIG9mIG9ic2VydmF0aW9ucyBpbiBlYWNoIGdyb3VwCm48LWcqbmkgIyB0b3RhbCBudW1iZXIgb2Ygb2JzZXJ2YXRpb24KYWxwaGE8LTAuMDUgIyBzaWduaWZpY2FuY2UgbGV2ZWwgb2YgaW5kaXZpZHVhbCB0ZXN0IApOPTEwMDAwICMgbnVtYmVyIG9mIHNpbXVsYXRpb25zCnNldC5zZWVkKDMwMikgI3NlZWQgdG8gcmVwcm9kdWNlIHJlc3VsdHMgZXhhY3RseSAKdHJ0PWZhY3RvcihyZXAoMTpnLG5pKSkgI2ZhY3RvcgpjbnQ8LTAgI2NvdW50ZXIgZm9yIGVycm9uZW91cyByZWplY3Rpb25zCmZvcihpIGluIDE6TikgewojaWYgKGklJTEwMDA9PTApIGNhdChpLCIvIixOLCJcbiIpCnkgPC0gcm5vcm0obikKdGVzdHM8LXBhaXJ3aXNlLnQudGVzdCh5LHRydCwibm9uZSIpCnJlamVjdDwtbWluKHRlc3RzJHAudmFsdWUsbmEucm09VCk8YWxwaGEKaWYocmVqZWN0KSBjbnQ8LWNudCsxCn0KY250L04KYGBgCgotLS0KCi0gUHJvYmFiaWxpdHkgb24gdGhlIHR5cGUgSSBlcnJvciBlcXVhbHMgYHIgcm91bmQoY250L04sMykqMTAwYCUKLSBJdCBpcyBtb3JlIHRoZW4gdHdpY2UgJFxhbHBoYT01JCUuCi0gSWYgd2UgcmVwZWF0IHRoZSBzaW11bGF0aW9uIHdpdGggZyA9IDUgZ3JvdXBzIChpLmUuIDEwIHBhaXJ3aXNlIHQtdGVzdHMpIHdlIGZpbmQgYSB0eXBlIEkgZXJyb3Igb2YgMjguMCUgaW5zdGVhZCBvZiB0aGUgZGVzaXJlZCA1JS4KCi0gVGhlIHNpbXVsYXRpb24gc3R1ZHkgaWxsdXN0cmF0ZXMgdGhlICAqKm11bHRpcGxpY2l0eSoqIHByb2JsZW0KCiAgLSBDbGFzc2ljYWwgcC12YWx1ZXMgY2FuIG9ubHkgYmUgY29tcGFyZWQgd2l0aCB0aGUgc2lnbmlmaWNhbmNlIGxldmVsICRcYWxwaGEkLCBpZiB0aGUgY29uY2x1c2lvbiBpcyBiYXNlZCBvbiBhIHNpbmdsZSBwLXZhbHVlLgogIC0gSGVyZSB0aGUgZmluYWwgZGVjaXNpb24gaXMgYmFzZWQgb24gJG09Z1x0aW1lcyhnLTEpLzIkICRwJC12YWx1ZXMuCgotIFdlIGZpcnN0IGRpc2N1c3Mgb24gdGhlIGV4dGVuc2lvbiBvZiB0aGUgY29uY2VwdCBvZiB0eXBlIEkgZXJyb3JzIGFuZCB0aGVuIGludHJvZHVjZSBzb21lIHNvbHV0aW9ucwoKIyMgRmFtaWx5LXdpc2UgZXJyb3IgcmF0ZQoKLSBXaGVuICRtPjEkIHRlc3RzIGFyZSB1c2VkIHRvIG1ha2Ugb25lIGRlY2lzaW9uIGl0IGlzIG5lY2Vzc2FyeSB0byBjb3JyZWN0IGZvciB0aGUgcmlzayBvbiBmYWxzZSBwb3NpdGl2ZSByZXN1bHRzICh0eXBlIEkgZXJyb3JzKS4KLSBNb3N0IHByb2NlZHVyZXMgZm9yIG11bHRpcGxlIHRlc3RpbmcgYXNzdW1lIHRoYXQgKmFsbCAkbSQgbnVsbCBoeXBvdGhlc2VzIGFyZSB0cnVlKi4KCi0gU28gb25lIHRyaWVzIHRvIGNvbnRyb2wgdGhlICpyaXNrIG9uIGF0IGxlYXN0IDEgZmFsc2UgcG9zaXRpdmUqIG9uIHRoZSAqKmZhbWlseSB3aXNlIGVycm9yIHJhdGUgKEZXRVIpICRcYWxwaGFfRiQqKiwgdHlwaWNhbCAkXGFscGhhX0Y9MC4wNSQuCgojIyBCb25mZXJyb25pIGNvcnJlY3Rpb24KCldoZW4gd2UgY29uZHVjdCAkbSQgaW5kZXBlbmRlbnQgdGVzdCBlYWNoIG9uIHRoZSBzaWduaWZpY2FuY2UgbGV2ZWwgJFxhbHBoYSQsIHRoZW4KXGJlZ2lue2VxbmFycmF5Kn0KXGFscGhhX0YmPSZcdGV4dHtQfVtcdGV4dHthdCBsZWFzdCAxIFR5cGUgSSBmb3V0fV1cXAomPSYxLSgxLVxhbHBoYSlebSBcbGVxIG1cYWxwaGEKXGVuZHtlcW5hcnJheSp9CgotIElmIHdlIGFzc2VzcyA1IHRlc3RzIG9uIHRoZSA1JSBzaWduaWZpY2FuY2UgbGV2ZWwgdGhlbiAgdGhlIEZXRVIgJFxhcHByb3ggMjVcJSQuIHsxMHB0fQotIEJ5IGNvbmR1Y3RpbmcgdGhlbSBhdCB0aGUgMSUgc2lnbmlmaWNhbmNlIGxldmVsIHRoZSBGV0VSICRcYXBwcm94IDVcJSQuCgotIFRoZSBCb25mZXJyb25pIGNvcnJlY3Rpb24gY29udHJvbHMgdGhlIEZXRVIgb24gJFxhbHBoYV9GJCBieSBzZXR0aW5nICQkXGFscGhhPVxhbHBoYV9GL20kJCBmb3IgZWFjaCBvZiB0aGUgJG0kIHBhaXJ3aXNlIGNvbXBhcmlzb25zCgpBbiBhbHRlcm5hdGl2ZSBhcHByb2FjaCBpcyB0byByZXBvcnQKCiAgMS4gKmFkanVzdGVkIHAtdmFsdWVzKiB0aGF0IGNhbiBiZSBjb21wYXJlZCB0byB0aGUgRldFUiAkXGFscGhhX0YkIGxldmVsOiAkJFx0aWxkZXtwfT1taW4obVx0aW1lcyBwLDEpJCQKICAyLiBhbmQgJCgxLVxhbHBoYV9GL20pMTAwXCUkIGNvbmZpZGVuY2UgaW50ZXJ2YWxzLgoKIyMjIHByb3N0YWN5Y2xpbiBleGFtcGxlIAoKYGBge3J9CndpdGgocHJvc3RhY3ljbGluLHBhaXJ3aXNlLnQudGVzdChwcm9zdGFjLGRvc2UsIGRhdGEgPSBwcm9zdGFjeWNsaW4sIHAuYWRqdXN0Lm1ldGhvZD0iYm9uZmVycm9uaSIpKQpgYGAKCi0gVGhlIGNvbmNsdXNpb25zIHJlbWFpbiBzaW1pbGFyLCBleGNlcHQgdGhhdCB0aGUgRldFUiBpcyBub3cgY29udHJvbGxlZCBhdCAkXGFscGhhX0Y9NVwlJCBhbmQgdGhhdCB0aGUgJFx0aWxkZXtwfSQtdmFsdWVzIGFyZSBsYXJnZXIgd2l0aCBhIGZhY3RvciAzLiAKClRoZSBzYW1lIGFuYWx5c2lzIGNhbiBiZSBjb25kdWN0ZWQgaW4gdGhlIGBtdWx0Y29tcGAgUiBwYWNrYWdlIHRoYXQgaXMgZGV2ZWxvcGVkIGZvciBtdWx0aXBsZSB0ZXN0aW5nIGluIGxpbmVhciBtb2RlbHMuCmBgYHtyfQpsaWJyYXJ5KG11bHRjb21wKQpgYGAKCmBgYHtyfQptb2RlbDEubWNwPC1nbGh0KG1vZGVsMSxsaW5mY3Q9bWNwKGRvc2U9IlR1a2V5IikpCnN1bW1hcnkobW9kZWwxLm1jcCx0ZXN0PWFkanVzdGVkKCJib25mZXJyb25pIikpCmBgYAoKTm90ZSwgdGhhdCB0aGUgdXNlciBoYXMgdG8gZGVmaW5lIGN1c3R1bSBmdW5jdGlvbnMgdG8gb2J0YWluIEJvbmZlcm9ubmkgYWRqdXN0ZWQgY29uZmlkZW5jZSBpbnRlcnZhbHMuIAoKLSBCb25mZXJvbm5pIGNvbmZpZGVuY2UgaW50ZXJ2YWxzIGFyZSBub3QgaW1wbGVtZW50ZWQgYmVjYXVzZSBiZXR0ZXIgbWV0aG9kcyBleGlzdCBmb3IgbXVsdGlwbGUgdGVzdGluZy4gCgotIFRoZSBmdW5jdGlvbiBiZWxvdyBpcyBhZGRlZCBoZXJlIG1lcmVseSBmb3IgY29tcGxldGVuZXNzLCBidXQgd2Ugd2lsbCBnZW5lcmFsbHkgdXNlIHRoZSBkZWZhdWx0IG1ldGhvZCBmb3IgbXVsdGlwbGUgdGVzdGluZyBpbiBtdWx0Y29tcC4KCmBgYHtyfQpjYWxwaGFfYm9uX3Q8LWZ1bmN0aW9uKG9iamVjdCxsZXZlbCkKIGFicygKICAgcXQoCiAgICAgKDEtbGV2ZWwpLzIvbnJvdyhvYmplY3QkbGluZmN0KSwKICAgICBvYmplY3QkZGYKICAgICApCiAgICApCmBgYAoKYGBge3J9CmNvbmZpbnQobW9kZWwxLm1jcCxjYWxwaGE9Y2FscGhhX2Jvbl90KQpgYGAKCiMjIyBFdmFsdWF0ZSBCb25mZXJyb25pIG1ldGhvZCB2aWEgc2ltdWxhdGlvbgoKYGBge3J9Cmc8LTMgIyBudW1iZXIgb2YgdHJlYXRtZW50cyAoZz0zKQpuaTwtMTIgIyBudW1iZXIgb2Ygb2JzZXJ2YXRpb25zIGluIGVhY2ggZ3JvdXAKbjwtZypuaSAjIHRvdGFhbCBudW1iZXIgb2JzZXJ2YXRpb24KYWxwaGE8LTAuMDUgIyBzaWduaWZpY2FuY2UgbGV2ZWwgb2YgaW5kaXZpZHVhbCB0ZXN0IApOPTEwMDAwICMgbnVtYmVyIG9mIHNpbXVsYXRpZXMKc2V0LnNlZWQoMzAyKSAjc2VlZCB0byByZXByb2R1Y2UgcmVzdWx0cyBleGFjdGx5IAp0cnQ9ZmFjdG9yKHJlcCgxOmcsbmkpKSAjZmFjdG9yCmNudDwtMCAjY291bnRlciBmb3IgZXJyb25lb3VzIHJlamVjdGlvbnMKZm9yKGkgaW4gMTpOKSB7CiNpZiAoaSUlMTAwMD09MCkgY2F0KGksIi8iLE4sIlxuIikKeSA8LSBybm9ybShuKQp0ZXN0czwtcGFpcndpc2UudC50ZXN0KHksdHJ0LCJib25mZXJyb25pIikKcmVqZWN0PC1taW4odGVzdHMkcC52YWx1ZSxuYS5ybT1UKTxhbHBoYQppZihyZWplY3QpIGNudDwtY250KzEKfQpjbnQvTgpgYGAKCgotIFdlIGZpbmQgYW4gRldFUiBvZiBgciByb3VuZChjbnQvTioxMDAsMSlgJSwgd2hpY2ggaXMgc2xpZ2h0bHkgY29uc2VydmF0aXZlLiAKLSBGb3Igc2ltdWxhdGlvbnMgb2YgJGc9NSQgZ3JvdXAgdGhlIEZXRVIgaXMgJDQuMVwlJCAobW9yZSBjb25zZXJ2YXRpdmUpLgoKLSBCeSB1c2luZyBCb25mZXJyb25pIHRoZSBwcm9iYWJpbGl0eSBvbiBhdCBsZWFzdCBvbmUgZmFsc2UgcG9zaXRpdmUgcmVzdWx0IGlzIGxvd2VyIHRoYW4gJDwgXGFscGhhX0YkLgotIFBvd2VyIGxvc3MgYmVjYXVzZSB0aGUgcmVhbCBGV0VSIGlzIHNtYWxsZXIgdGhhbiA1JQoKIyMgVHVrZXkgTWV0aG9kCgotIExlc3MgY29uc2VydmF0aWV2ZQotIEltcGxlbWVudGF0aW9uIGFwcHJveGltYXRlcyB0aGUgbnVsbCBkaXN0cmlidXRpb24gb2YgcG9zdGhvYyB0ZXN0cyB2aWEgc2ltdWxhdGlvbnMKLSBSZXN1bHRzIGNhbiBjaGFuZ2Ugc2xpZ2h0bHkgaWYgdGhlIHBvc3Rob2MgYW5hbHlzaXMgaXMgcmVwZWF0ZWQgCi0gRGV0YWlscyBvbiB0aGUgbWV0aG9kIGZhbGxzIG91dHNpZGUgdGhlIHNjb3BlIG9mIHRoZSBzaG9ydCBjb3Vyc2UgIAotIElzIHRoZSBkZWZhdWx0IG1ldGhvZCBpbiB0aGUgbXVsdGNvbXAgcGFja2FnZToKCiAgICAtIGFkanVzdGVkIHAtdmFsdWVzCiAgICAtIGFkanVzdGVkIGNvbmZpZGVuY2UgaW50ZXJ2YWxzIAogICAgCiMjIyBDYXB0b3ByaWwgZXhhbXBsZQoKYGBge3J9Cm1vZGVsMS5tY3A8LWdsaHQobW9kZWwxLGxpbmZjdD1tY3AoZG9zZT0iVHVrZXkiKSkKc3VtbWFyeShtb2RlbDEubWNwKQpgYGAKCgpgYGB7cn0KY29uZmludChtb2RlbDEubWNwKQpgYGAKCgpgYGB7ciBvdXQud2lkdGg9JzEwMCUnLCBmaWcuYXNwPS44LCBmaWcuYWxpZ249J2NlbnRlcid9CnBsb3QoY29uZmludChtb2RlbDEubWNwKSkKYGBgCgojIyNFdmFsdWF0ZSBUdWtleSBtZXRob2QKCmBgYHtyfQpnPC0zICMgbnVtYmVyIG9mIHRyZWF0bWVudHMgKGc9MykKbmk8LTEyICMgbnVtYmVyIG9mIG9ic2VydmF0aW9ucyBpbiBlYWNoIGdyb3VwCm48LWcqbmkgIyB0b3RhYWwgbnVtYmVyIG9ic2VydmF0aW9uCmFscGhhPC0wLjA1ICMgc2lnbmlmaWNhbmNlIGxldmVsIG9mIGluZGl2aWR1YWwgdGVzdCAKTiA8LSAxMDAwMCAjIG51bWJlciBvZiBzaW11bGF0aW9ucwpzZXQuc2VlZCgzMDIpICNzZWVkIHRvIHJlcHJvZHVjZSByZXN1bHRzIGV4YWN0bHkgCnRydCA8LSBmYWN0b3IocmVwKDE6ZyxuaSkpICNmYWN0b3IKY250PC0wICNjb3VudGVyIGZvciBlcnJvbmVvdXMgcmVqZWN0aW9ucwpmb3IoaSBpbiAxOk4pIHsKI2lmIChpJSUxMDAwPT0wKSBjYXQoaSwiLyIsTiwiXG4iKQp5IDwtIHJub3JtKG4pCm08LWxtKHl+dHJ0KQptLm1jcDwtZ2xodChtLGxpbmZjdD1tY3AodHJ0PSJUdWtleSIpKQp0ZXN0czwtc3VtbWFyeShtLm1jcCkkdGVzdApyZWplY3Q8LW1pbihhcy5udW1lcmljKHRlc3RzJHB2YWx1ZXMpLG5hLnJtPVQpPGFscGhhCmlmKHJlamVjdCkgY250PC1jbnQrMQp9CmNudC9OCmBgYAoKCiMgQ29uY2x1c2lvbnM6IFByb3N0YWN5Y2xpbiBleGFtcGxlIAoKRW50aXJlIGFuYWx5c2lzIGZvciBwcm9zdGFjeWNsaW4gZXhhbXBsZSAKCjEuIEFub3ZhIGJlZm9yZSBwb3N0aG9jIHRlc3RzOiBGLXRlc3QgaGFzIGEgaGlnaGVyIHBvd2VyIHRoYW4gIHBhaXJ3aXNlIHQtdGVzdAoKICAgIC0gRi10ZXN0IHVzZXMgYWxsIGRhdGEKICAgIC0gRm9yIEYtdGVzdCB3ZSBkbyBub3QgbmVlZCB0byBjb3JyZWN0IGZvciBtdWx0aXBsZSB0ZXN0aW5nOiBvbmUgdGVzdCBpcyBjb25kdWN0ZWQgZm9yIHRoZSBnZW5lcmFsIG9tbmlidXMgaHlwb3RoZXNpcwoKYGBge3J9Cm1vZGVsMSA8LSBsbShwcm9zdGFjfmRvc2UsZGF0YT1wcm9zdGFjeWNsaW4pCmFub3ZhKG1vZGVsMSkKYGBgCgpgYGB7cn0KbW9kZWwxLm1jcDwtZ2xodChtb2RlbDEsbGluZmN0PW1jcChkb3NlPSJUdWtleSIpKQpzdW1tYXJ5KG1vZGVsMS5tY3ApCmBgYAoKYGBge3J9CmNvbmZpbnQobW9kZWwxLm1jcCkKYGBgCgoKLSBUaGVyZSBpcyBhbiBleHRyZW1lIHNpZ25pZmljYW50IGVmZmVjdCBvZiBhcmFjaGlkb25pYyBhY2lkIG9uIHRoZSBhdmVyYWdlIHByb3N0YWN5Y2xpbiBibG9vZCBjb25jZW50cmF0aW9uIGluIHJhdHMgKCRwPDAuMDAxJCkuClRoZSBhdmVyYWdlIHByb3N0YWN5Y2xpbiBjb25jZW50cmF0aW9uIGlzIGhpZ2hlciBpbiB0aGUgaGlnaCBkb3NlIGdyb3VwIHRoYW4gaW4gdGhlIGxvdyBhbmQgbW9kZXJhdGUgZG9zZSBncm91cCAoYm90aCBwLXZhbHVlcyBhcmUgc21hbGxlciB0aGFuICRwPDAuMDAxJCkuCi0gVGhlIGF2ZXJhZ2UgY29uY2VudHJhdGlvbiBpbiB0aGUgaGlnaCBkb3NlIGdyb3VwIGlzIGByIHJvdW5kKGNvbmZpbnQobW9kZWwxLm1jcCkkY29uZmludFsyLDFdLDEpYG5nL21sICg5NSUgQ0kgW2ByIHBhc3RlKHJvdW5kKGNvbmZpbnQobW9kZWwxLm1jcCkkY29uZmludFsyLDI6M10sMSksY29sbGFwc2U9IiwiKWBdbmcvbWwpIGFuZCBgciByb3VuZChjb25maW50KG1vZGVsMS5tY3ApJGNvbmZpbnRbMywxXSwxKWBuZy9tbCAoOTUlIEJJIFtgciBwYXN0ZShyb3VuZChjb25maW50KG1vZGVsMS5tY3ApJGNvbmZpbnRbMywyOjNdLDEpLGNvbGxhcHNlPSIsIilgXW5nL21sKSBoaWdoZXIgdGhhbiBpbiB0aGUgbG93IGFuZCBtaWRkbGUgZG9zZSBncm91cCwgcmVzcGVjdGl2ZWx5LgotIFRoZSBkaWZmZXJlbmNlIGluIGF2ZXJhZ2UgcHJvc3RhY3ljbGluIGNvbmNlbnRyYXRpb24gYmV0d2VlbiB0aGUgbW9kZXJhdGUgYW5kIGxvdyBkb3NlIGdyb3VwIGlzIG5vdCBzaWduaWZpY2FudCAgKHA9YHIgcm91bmQoc3VtbWFyeShtb2RlbDEubWNwKSR0ZXN0JHB2YWx1ZXNbMV0sMilgKS4KKEFsbCBwLXZhbHVlcyBhbmQgY29uZmlkZW5jZSBpbnRlcnZhbHMgZm9yIHBvc3QtaG9jIHRlc3RzIGFyZSBjb3JyZWN0ZWQgZm9yIG11bHRpcGxlIHRlc3RpbmcgdXNpbmcgdGhlIFR1a2V5IG1ldGhvZCkuCgoKLS0tCgojIFtIb21lXShodHRwczovL2d0cGIuZ2l0aHViLmlvL1BTTFMyMC8pIHstfQo=