Creative Commons License

library(Rmisc)
library(tidyverse)
library(NHANES)

1 Introduction

Until now we used models for a continuous response in function of categorical or continuous predictor. Here we will focus on a categorical response.

  • we study the association of a categorical outcome and a categorical predictor and
  • touch upon methods to model a categorical outcome with a continuous response.

2 Test for a proportion

2.1 Saksen-study

  • Fairly closed population (few migration)
  • Probability that an unborn child is male?
boys <- 3175
n <- 6155
  • On 6155 unborn children 3175 boys are observed.
  • Is there a difference in the probability on the gender of an unborn child?

  • The data are derived from a binary random variable \(X\)

    • \(X=1\) for a boy and
    • \(X=0\) for a girl.
  • Note: count problem: the outcome is a count (number of boys)

  • Formally we have considered a population of unborn children where each individual is characterized by a 0 or 1.


2.2 Bernoulli Probability Mass Distribution

  • Binary data can be modelled using a Bernoulli distribution: \[\begin{eqnarray*} X_i &\sim& B(\pi) \text{ with}\\ B(\pi)&=&\pi^{X_i}(1-\pi)^{(1-X_i)}, \end{eqnarray*}\]

  • It has one model parameter \(\pi\)

    • Expected value of \(X_i\): \(\text{E}[X_i]=\pi,\)
    • Proportion of unborn boys (children with \(X=1\)) in the population.
    • Hence \(\pi\) is the probability that a random individual from the population is a boy (an observation with \(X=1\)).
  • The variance of Bernoulli data is also related to \(\pi\). \[\text{Var}[X_i]=\pi (1-\pi).\]


Some Bernoulli probability mass functions


  • In the Saksen study 6155 observaties were sampled at random from the population.
  • We can estimate \(\pi\) using the sample mean: \[\hat \pi = \bar X = \frac{\sum\limits_{i=1}^n X_i}{n},\]
pi <- boys / n
pi
[1] 0.5158408

In our example \(\bar x =\) 3175 / 6155 = 51.6%.


2.3 Binomial test

  • Is the observed probability 51.6% that an unborn child is male, sufficient evidence to conclude that there is a higher chance on a boy than on a girl?

  • Statistical test for \[H_0: \pi=1/2 \text{ versus } H_1: \pi\neq 1/2,\]

  • We need known the distribution of

    • \(X\) and \(\bar X\)
    • or of the sum \(S=n\bar X\).

  • Suppose that \(H_0:\pi=1/2\) is true (boys and girls have an equal frequency in the population)

  • A random individual from the population has a probability of \[P(X=1)=\pi=1/2.\] to be a boy

  • Two children that are drawn independently :

    • Probability of \(\pi=1/2\) on a boy for the first and second child (independent from each other)
    • Outcomes \((x_1, x_2)\) for both children have 4 possible combinations: \((0,0),(0,1),(1,0)\text{ en }(1,1).\)
    • Each of them has a probability of \(1/4 = 1/2 \times 1/2\).
  • Random variable \(S\) is the sum of the outcomes :

\((x_1,x_2)\) \(s\) \(P(S = s)\)
(0,0) 0 1/4
(0,1), (1,0) 1 1/2
(1,1) 2 1/4

2.3.1 General: \(n\) independent samples

  • Probability for \(\pi\) on success (\(X=1\))

  • Total number of successes \(S\) (sum of all values of 1) can take \(n+1\) possible values \[S=k\text{, met }k=0,\ldots,n\]

  • Distribution of \(S\)? \[\begin{equation} P(S=k) = \left ( \begin{array}{c} n \\ k \\ \end{array} \right ) \pi^k (1-\pi)^{n-k} \end{equation}\]

  • \(1-\pi\): probability on 0 for individual observation and

  • binomial coefficient \[\begin{equation*} \left ( \begin{array}{c} n \\ k \\ \end{array} \right ) = \frac{n \times (n-1) \times ...\times (n-k+1) }{ k!} = \frac{ n!}{ k!(n-k)! } \end{equation*}\]

  • In R you can calculate the probabilities on each \(S=k\) with the function dbinom(k,n,p)


2.3.2 Binomial Distribution

S is a:

  • Binomial distributed random variable with Binomial probability mass function

  • Parameters

    • \(n\) (total number of draws from the population, is equivalent to maximal value of the outcome)
    • \(\pi\) (probability on success for each draw).
  • Calculate probability on \(k\) successes on \(n\) independent draws each with a succes probability of \(\pi\).

  • For binary data X.

  • e.g.: wild type vs mutant of a gene, infected or not infected with HIV, …

  • Use: Compare proportions or risks on a particular event between groups.


2.3.3 Some Binomial probability mass functions.

Binomial distributions.

Binomial distributions.


Test statistic \[H_0:\pi=1/2\text{ vs }H_1:\pi\neq 1/2\]

  • \(\bar X-1/2\) or, equivalent,
  • \(\Delta=n(\bar X-\pi_0)=S-s_0\).
  • Distribution of the latter test statistic can be derived immediately from the Binomial distribution:
    • We observe \(s=\) 3175 and thus \(\delta=s-s_0=\) 3175 \(-\) 6155 \(\times 0.5=\) 97.5.
    • When boys and girls are equally likely, i.e. under \(H_0:\pi=1/2\), we will get following two-sided p-value: \[p=\text{P}_0\left[S-s_0\geq \vert \delta\vert \right] + \text{P}_0\left[S-s_0\leq - \vert \delta\vert \right].\]
  • Note, that we can rewrite it in terms of S. \[p=\text{P}_0\left[S\geq s_0+ \vert \delta\vert \right] + \text{P}_0\left[S \leq s_0 - \vert \delta\vert \right].\]

  • For the Saksen study we calculate:

\[\begin{eqnarray*} \text{P}_0\left[S\geq s_0+ \vert \delta\vert \right] &=& P(S \geq 6155 \times 0.5 + \vert 3175 - 6155 \times 0.5\vert ) \\&=& P(S \geq 3175)\\ &= &P(S= 3175) + P(S=3176) + ... + P(S=6155)\\ & =& 0.0067\\\\ \text{P}_0\left[S \leq s_0 - \vert \delta\vert \right] &=& P(S \leq 6155 \times 0.5 - \vert 3175- 6155 \times 0.5\vert) \\&=& P(S \leq 2980)\\ &= &P(S=0) + ... + P(S=2980) \\ &=&0.0067 \end{eqnarray*}\]

  • The Binomial distribution is symmetric for\(\pi=1/2\): \[\text{P}_0\left[S\geq s_0+ \vert \delta\vert \right] = \text{P}_0\left[S \leq s_0 - \vert \delta\vert \right]\]
  • This is no longer the case when \(\pi\) deviate from 0.5.

pi0 <- 0.5
s0 <- pi0 * n
delta <- abs(boys - s0)
delta
[1] 97.5
sUp <- s0 + delta
sDown <- s0 - delta
c(sDown, sUp)
[1] 2980 3175
pUp <- 1 - pbinom(sUp - 1, n, pi0)
pDown <- pbinom(sDown, n, pi0)
p <- pUp + pDown
c(pUp, pDown, p)
[1] 0.006699883 0.006699883 0.013399766

  • If \(\pi= 1/2\), the probability to observe at least \(\delta=\) 97.5 boys more or less than the mean under \(H_0: s_0=\) 3077.5 in a random sample under H_0 is only 1.34% is: \(p\)-value of binomial test.
  • Very unlikely to observe such a large number of boys in a random sample when boys and girls have the same frequency in the population (under \(H_0\)).
  • Hence the hypothesis that the frequency of boys and girls is the same is not supported by the data.


The test can immediately be conducted using the binomial.test function in R.

binom.test(x = boys, n = n, p = pi0)

    Exact binomial test

data:  boys and n
number of successes = 3175, number of trials = 6155, p-value =
0.0134
alternative hypothesis: true probability of success is not equal to 0.5
95 percent confidence interval:
 0.5032696 0.5283969
sample estimates:
probability of success 
             0.5158408 

On the 5% significance-level we conclude that there is on average a higher probability on a unborn male child than an unborn female child.


2.3.4 Confidence interval on a proportion

  • Estimator of the proportion of boys in the population is the sample mean \(\hat \pi=\bar x=\) 0.516
  • The standard error is \[SE_{\bar x}=\sqrt{\frac{\text{Var}[X]}{n}}=\sqrt{\frac{\pi(1-\pi)}{n}}\]
  • We can estimate this based on the sample: \(SE_{\bar x}=\sqrt{\frac{\hat\pi(1-\hat\pi)}{n}}=\) 0.0064.
  • 95% CI via CLT: \(\hat\pi \pm 1.96 SE_{\hat\pi}.\)
se <- sqrt(pi * (1 - pi) / n)
pi + c(-1, 1) * qnorm(0.975) * se
[1] 0.5033559 0.5283257

2.3.5 CI on proportion in small sample?

CI <- binom.test(x = boys, n = n, p = pi0)$conf.int
CI
[1] 0.5032696 0.5283969
attr(,"conf.level")
[1] 0.95

2.3.6 Conclusion

  • Note that the test for a proportion is equivalent to a one-sample t-test for binary data.

  • For the Saksen population we conclude at the 5% significance level that the gender of unborn children is more likely to be male than female (\(p=\) 0.013). The probability that an unborn child is male equals 51.6% (95% CI [50.3,52.8]%).


3 Test for association between two qualitative variables

3.1 Paired observations

  • 2 measurements on same individual
  • e.g. before and after exposure to a chemical substance
  • observe a categorical outcome before and after.
  • paired binary responses
  • Statistical analysis has to account for paired design.

3.1.1 Example: Females choose gentle, but not healthy or macho males in Campbell dwarf hamsters (Rogovin et al. 2017)


  • The gate is opened upon 3 minutes

  • aggressive vs non-agressive male

  • Each female undergoes the test twice:

    • once upon stay in hostile environment (high population density, shortage of feed, a lot of competition)
    • and once upon stay in gentle evironment.
friendly_agressive friendly_non-agressive total
hostile_agressive 3 (e) 17 (f) 20
hostile_non-agressive 1 (g) 13 (h) 14
total 4 30 34

3.1.2 Absolute risk difference (ARD)

  • \(\pi_1=P[\text{agressive male } \vert \text{hostile}]\)

  • \(\hat \pi_1=(e+f)/n\), with \(n=e+f+g+h\).

  • \(\pi_0=P[\text{agressive male } \vert \text{ friendly}]\)

  • \(\hat \pi_0=(e+g)/n\) \[\begin{equation*} \widehat{\text{ARD}}=\hat\pi_1-\hat\pi_0=\frac{e+f}{n}-\frac{e+g}{n}=\frac{f-g}{n} \end{equation*}\]

  • Only affected by discordant pairs \(f\) en \(g\)


  • Standard error on ARD \[\begin{equation*} \text{SE}_{\widehat{\text{ARD}}}=\frac{1}{n}\sqrt{f+g-\frac{(f-g)^2}{n}} \end{equation*}\]

  • If we have large number of observations we can use the CLT to establish an \((1-\alpha)100\%\) CI on the ARD \[\left[\widehat{\text{ARD}}-z_{\alpha/2}\text{SE}_{\widehat{\text{ARD}}},\widehat{\text{ARD}}-z_{\alpha/2}\text{SE}_{\widehat{\text{ARD}}}\right]\] or \[\left[\frac{f-g}{n}-\frac{z_{\alpha/2}}{n}\sqrt{f+g-\frac{(f-g)^2}{n}},\frac{f-g}{n}+\frac{z_{\alpha/2}}{n}\sqrt{f+g-\frac{(f-g)^2}{n}}\right] \]


hamster <- matrix(c(3, 17, 1, 13), ncol = 2, byrow = TRUE)
rownames(hamster) <- c("hostile-agressive", "hostile-non-agressive")
colnames(hamster) <- c("friendly-agressive", "friendly-non-agressive")

f <- hamster[1, 2]
g <- hamster[2, 1]
n <- sum(hamster)
riskdiff <- (f - g) / n
riskdiff
[1] 0.4705882
se <- sqrt(f + g - (f - g)^2 / n) / n
se
[1] 0.09517144
ci <- riskdiff + c(-1, 1) * qnorm(0.975) * se
ci
[1] 0.2840556 0.6571208

\[\begin{equation*} \widehat{\text{ARD}}=\frac{17-1}{34}=0.471 \end{equation*}\] The absolute risk difference on choosing for an agressive male is 47.1% larger upon staying in a hostile environment that when residing in a gentle environment. - The standard error \[\begin{equation*} \text{SE}_{\widehat{\text{ARD}}}=\frac{1}{34}\sqrt{17+1-\frac{(17-1)^2}{34}}=0.0952 \end{equation*}\] - A 95% confidence interval on this absolute risk difference is \[\begin{equation*} \left[0.471-1.96\times 0.0952,0.471+1.96\times 0.0952\right]=[0.284,0.658] \end{equation*}\]


3.2 McNemar test

friendly_agressive friendly_non-agressive total
hostile_agressive 3 (e) 17 (f) 20
hostile_non-agressive 1 (g) 13 (h) 14
total 4 30 34
  • Assess if risk on choice for agressive male differs between residing in hostile and friendly environment.
  • Only discordant pairs give information.
  • \(f>g\) indication against \(H_0\): choice of partner not associated with environment.
  • Evaluate probability that in a random discordant pair, a female chooses an agressive male upon a stay in a hostile environment.
  • We estimate the probability as \[\frac{f}{f+g}\]

\[\begin{eqnarray*} \text{E}\left[f/(f+g)\right]&\stackrel{H_0}{=}& 0.5\\ f & \stackrel{H_0}{\sim}& \text{Binom}(n=f+g,\pi=0.5)\\ \text{SE}_{\frac{f}{f+g}} & \stackrel{H_0}{=}& \sqrt{(f+g)\times 0.5\times 0.5}=\frac{\sqrt{f+g}}{2} \end{eqnarray*}\]


  • Asymptotically a one-sample z-test (based on the Normal distribution)

\[\begin{equation*} z=\frac{f-(f+g)/2}{\sqrt{f+g}/2}=\frac{f-g}{\sqrt{f+g}} \end{equation*}\]

  • Normal approximation is good if \[f \times g/(f+g) \geq 5\]

The Mc Nemar test is the analogon of the paired t-test for binary qualitative variables.


In R we can conduct the analysis using the mcnemar.test function

mcnemar.test(hamster)

    McNemar's Chi-squared test with continuity correction

data:  hamster
McNemar's chi-squared = 12.5, df = 1, p-value = 0.000407
  • We reject the null hypothesis at the 5% significance level
  • We conclude that the choice of partner is extremely significantly associated with the environment.

  • Normale approximation is not optimal and we can perform an exact test using the binomial test
binom.test(x = f, n = f + g, p = 0.5)

    Exact binomial test

data:  f and f + g
number of successes = 17, number of trials = 18, p-value =
0.000145
alternative hypothesis: true probability of success is not equal to 0.5
95 percent confidence interval:
 0.7270564 0.9985944
sample estimates:
probability of success 
             0.9444444 

3.2.1 Conclusion

  • We conclude that the partner choice is extremely signficantly associated with the environment (\(p<0.001\)).
  • The probability on choosing an agressive male is on average 47.1% higher when a female hamster resides in a hostile environment than when she resides in a friendly environment (95% CI [28.4,65.7]%).

4 Unpaired observations

4.1 Genetic association study

  • Are genetic polymorphisms in the BRCA1 gene associated with breast cancer?
  • Retrospective case-control study with 800 breast cancer cases en 572 controls
brca <- read_csv("https://raw.githubusercontent.com/GTPB/PSLS20/master/data/brca.csv")
head(brca)
summary(brca)
    cancer            variant            variant2        
 Length:1372        Length:1372        Length:1372       
 Class :character   Class :character   Class :character  
 Mode  :character   Mode  :character   Mode  :character  

Genotype Control Cases Total
Pro/Pro 266 (a) 342 (d) 608 (a+d)
Pro/Leu 250 (b) 369 (e) 619 (b+e)
Leu/Leu 56 (c) 89 (f) 145 (c+f)
Totaal 572 (a+b+c) 800 (d+e+f) 1372 (n)
  • In case-control study one chooses a fixed number of cases and controls and registers which exposures they had in the past.
  • Retrospective study
  • Impossible to assess risks and risk-differences on breast cancer because the proportion of cases and controls does not reflect that in the population!

Genotype Controls Cases Total
Pro/Pro 266 (a) 342 (d) 608 (a+d)
Pro/Leu 250 (b) 369 (e) 619 (b+e)
Leu/Leu 56 (c) 89 (f) 145 (c+f)
Totaal 572 (a+b+c) 800 (d+e+f) 1372 (n)
  • Is possible to assess probability on allel Leu/Leu
    • cases: \(\pi_1=f/(d+e+f)=89/800=11.1\%\)
    • controls:\(\pi_0=c/(a+b+c)=56/572=9.8\%\)
  • Relative risk on exposure for cases versus controls is \(11.1/9.8=1.14\).
  • The probability on the Leu/Leu genotype is 14% higher for women with breast cancer than for women without borstkanker.
  • It suggests an association, but it does not let us conclude how much higher the risk is on breast cancer for women with the Leu/Leu genotype as compared to the other women.
  • Other statistic?

\[\begin{equation*} Odds=\frac{p}{1-p} \end{equation*}\] with \(p\) the probability on the event.

Transformation of risk with following properties:

  • odds has value between 1 and \(\infty\).

  • odds only equals 1 for probability \(p=1/2\).

  • de odds increases if probability increases.

  • popular in gambling: how much more likely is it to win than to loose


Genotype Controls Cases Total
Pro/Pro 266 (a) 342 (d) 608 (a+d)
Pro/Leu 250 (b) 369 (e) 619 (b+e)
Leu/Leu 56 (c) 89 (f) 145 (c+f)
Totaal 572 (a+b+c) 800 (d+e+f) 1372 (n)

Odds on allel Leu/Leu

  • Cases: \(\mbox{odds}_1=\frac{ f/(d+e+f)}{(d+e)/(d+e+f)}=f/(d+e)=89/711=0.125\). The double Leu/Leu variant is 8 times less likely than other allele combinations in the breast cancer cases

  • Controls: \(\mbox{odds}_2=c/(a+b)=56/516=0.109\).

  • Association between exposure and outcome: \[ OR_{Leu/Leu}=\frac{\mbox{odds}_T}{\mbox{odds}_C}= \frac{f/(d+e)}{c/(a+b)}=\frac{f/(d+e)}{c/(a+b)}=1.15 \]


Genotype Controls Cases Total
Pro/Pro 266 (a) 342 (d) 608 (a+d)
Pro/Leu 250 (b) 369 (e) 619 (b+e)
Leu/Leu 56 (c) 89 (f) 145 (c+f)
Totaal 572 (a+b+c) 800 (d+e+f) 1372 (n)
  • If the study would have been a random sample of the population (number of cases and controls not fixed by design) then we would be able to calculate the odds ratio on breast cancer for people with and without the double Leu/leu variant. \[\begin{equation*} OR_{case}=\frac{ \frac{ f}{c}}{ \frac{(d+e)}{(a+b)}} = \frac{f(a+b)}{c(d+e)}=OR_{Leu/Leu}=1.15, \end{equation*}\]
  • OR is a symmetric statistic!
  • OR on borstcancer can be estimated!
  • The odds on borstcancer is 15% higher for women with this specific allele combination.

  • Is the difference large enough to generalize the effect in the sample towards the population?

  • We will first rewrite the data in a 2x2 table

Genotype Controls Cases Totaal
other 516 (a) 711 (c) 1227 (a+c)
Leu/Leu 56 (b) 89 (d) 145 (b+d)
Total 572 (a+b) 800 (c+d) 1372 (n)

4.2 Pearson Chi-square test for independent samples

  • Test association between categorical exposure(e.g. variant, X) en categorical response (e.g. disease, Y). \[H_0: \text{There is no association between } X \text{ and } Y \text{ vs } H_1: X \text{ and } Y \text{ are associated}\]

  • Consider row totals \(n_\text{other}=a+c\), \(n_\text{leu,leu}=b+d\) and

  • column totals \(n_\text{contr}=a+b\) en \(n_\text{case}=c+d\).

  • They give information on marginal distribution of the exposure (variant, X) and outcome (disease, Y), but not on the association between these variables.

  • Under \(H_0\) \(X\) and \(Y\) are independent and one expects that \((b+d)/n\) of the \(a+b\) controls have a Leu/Leu variant, or that \((a+b)(b+d)/n\) of them has a Leu/Leu variant

  • We can calculate this expected number \(E_{ij}\) under the null hypothesis for each cell of the \(2 \times 2\) table.


  • \(E_{11}\) = Expected number under \(H_0\) in (1,1)-cell = 1227 \(\times\) 800/1372 = 715.5 ;

  • \(E_{12}\) = Expected number under \(H_0\) in (1,2)-cell = 1227 \(\times\) 572/1372 = 511.5 ;

  • \(E_{21}\) = Expected number under \(H_0\) in (2,1)-cell = 145 \(\times\) 800/1372 = 84.55 ;

  • \(E_{22}\) = Expected number under \(H_0\) in (2,2)-cell = 145 \(\times\) 572/1372 = 60.45 ;

Test-statistic: \[\begin{eqnarray*} X^2 &=& \frac{\left (|O_{11} - E_{11}| - .5 \right)^2 }{ E_{11}} + \frac{ \left ( |O_{12} - E_{12}| - .5 \right)^2 }{E_{12} }+ \\ &&\quad\quad \frac{ \left ( |O_{21} - E_{21}| - .5 \right)^2 }{E_{21}}+ \frac{ \left ( |O_{22} - E_{22}| - .5 \right)^2 }{E_{22} }\\ X^2 &\stackrel{H_0}{\longrightarrow}& \chi^2(df=1) \end{eqnarray*}\]



  • A large value of the test statistic gives an indication that the null hypothesis is false.
  • The test will reject \(H_0\) at the \(\alpha 100\%\) significance level as soon as the observed test-statistic is larger than the \(100\%(1-\alpha)\)-quantile, \(\chi^2_{1, \alpha}\), of the \(\chi^2_1\)-distribution.
  • Otherwise we do not reject \(H_0\).
  • The p-value of a 2-sided test is the probability to observe a larger test-statistic in a random sample under the null than what we observed in our sample. \[p=P_0[\chi^2_1 \geq x^2]\].

expected <- matrix(0, nrow = 2, ncol = 2)
for (i in 1:2) {
  for (j in 1:2) {
    expected[i, j] <-
      sum(brcaTab2[i, ]) * sum(brcaTab2[, j]) / sum(brcaTab2)
  }
}
expected
         [,1]     [,2]
[1,] 715.4519 511.5481
[2,]  84.5481  60.4519
x2 <- sum((abs(brcaTab2 - expected) - .5)^2 / expected)
1 - pchisq(x2, 1)
[1] 0.481519

  • Because \(O_{ij}\) are discrete values, the \(X^2\) can only take discrete values and the continuouss \(\chi^2_1\)-distribution is only an approximation of the real distribution.
  • To improve the approximation one substracts 0.5 from the value in each cell: continuity-correction
  • We refer to this test as Pearson Chi-squared test with Yates correction.
  • When the correction is not used (i.e. when the values of `0.5’ in the estimator \(X^2\) are replaced) we use the Pearson Chi-squared test.

In R you can switch the correction on or off by setting the argument correct on TRUE or FALSE, respectively:

chisq.test(brcaTab2)

    Pearson's Chi-squared test with Yates' continuity correction

data:  brcaTab2
X-squared = 0.49542, df = 1, p-value = 0.4815
chisq.test(brcaTab2, correct = FALSE)

    Pearson's Chi-squared test

data:  brcaTab2
X-squared = 0.62871, df = 1, p-value = 0.4278

  • Even with the \(\chi^2_1\) correction the approximation is only valid if non of the cells has an expected count below 5 under \(H_0\).
  • When the \(\chi^2\)-approximation is invalid we will use Fisher’s exact test.
  • Null hypothesis is also that \(X\) and \(Y\) are independent, and, the alternative hypothesis that \(X\) and \(Y\) are dependent.
fisher.test(brcaTab2)

    Fisher's Exact Test for Count Data

data:  brcaTab2
p-value = 0.4764
alternative hypothesis: true odds ratio is not equal to 1
95 percent confidence interval:
 0.5974269 1.2501878
sample estimates:
odds ratio 
 0.8670925 

4.3 Extension to categorical variables with multiple levels

  • The \(\chi^2\)-test can also be used if one of the categorical variables \(X\) and \(Y\) has more than 2 levels

  • Again: the null hypothesis \(H_0\): \(X\) and \(Y\) are independent (not associated), against the alternative \(H_A: X\) and \(Y\) are associated.

  • Let the variable in the rows have \(r\) different possible outcomes and the one in the columns \(c\) possible outcomes, then we obtain an \(r \times c\) table.

  • Again we will compare the observed values in cell \((i,j)\), referred to as \(O_{ij}\), with the expected number under \(H_0\), \(E_{ij}\)

  • Again \(E_{ij}\) is the product of the \(i^\text{th}\) row-total and the \(j^\text{th}\) column total devided by the overall total.

\[\begin{equation*} X^2 = \sum_{ij} \frac{\left (O_{ij} - E_{ij}\right)^2 }{ E_{ij}} \end{equation*}\]


  • We can show that the statistic follows a \(\chi^2\) distribution with \((r-1) \times (c-1)\) degrees of freedom under \(H_0\).
  • No continuity correction
  • Pearson \(\chi^2\) test is analogon of one-way ANOVA for qualitative variables.

brcaTab <- table(brca$variant, brca$cancer)
chisq.test(brcaTab)

    Pearson's Chi-squared test

data:  brcaTab
X-squared = 2.0551, df = 2, p-value = 0.3579
  • To assess if the variant of the BRCA1 gene is associated with breast cancer we conducted a Pearson \(\chi^2\)test for the \(3 \times 2\) table.
  • The statistic is now 2.055 and follows a \(\chi^2\) distribution with 2 degrees of freedom under \(H_0\). The probability to obtain a \(\chi^2\)-test statistic in a random sample under \(H_0\) that is more extreme than 2.055, is 36%.
  • On the 5% level of significance we conclude that the variant of the BRCA-gene is not associated with breast cancer.

5 Logistic regression

  • Framework to model binary data (e.g cancer vs no cancer): logistic regression model.

  • Model binary data with continuous and/or dummy variables.

  • The model assumes that observations for subject \(i=1,\ldots,n\) are independent and follow a Bernoulli distribution.

  • The logarithm of the odds is modelled using a linear model, also referred to as linear predictor: \[\begin{equation} \left\{ \begin{array}{ccl} Y_i&\sim&B(\pi_i)\\\\ \log \frac{\pi_i}{1-\pi_i}&=&\beta_0 + \beta_1X_{i1} + \ldots + \beta_p X_{ip} \end{array}\right. \end{equation}\]


5.1 Categorical predictor

  • breast cancer example: is BRCA 1 variant associated with breast cancer.

  • As in the Anova context, a factor in logistic regression is coded using dummy variables.

  • 1 dummy variable less than the number of groups.

  • For BRCA 1 we need two dummy variables and obtain the following linear predictor:

\[\begin{eqnarray*} \log \frac{\pi_i}{1-\pi_i} &=& \beta_0+\beta_1 x_{i1} +\beta_2 x_{i2} \end{eqnarray*}\]

  • with : \[x_{i1} = \left\{ \begin{array}{ll} 1 & \text{ if subject $i$ is heterozygous, Pro/Leu variant} \\ 0 & \text{if subject $i$ is homozygous, (Pro/Pro or Leu/Leu variant)} \end{array}\right. .\] \[x_{i2} = \left\{ \begin{array}{ll} 1 & \text{ if subject $i$ is homozygous is the Leucine mutation: Leu/Leu } \\ 0 & \text{ of subject $i$ is not homozygous in the Leu/Leu variant} \end{array}\right. .\]

  • Homozygosity in the wild type allele Pro/Pro is the reference group.


We fit the model in R.

  • Note that we use the function as.factor to convert the cancer variable to a factor variable. - We further use the function relevel to specify the control treatment as the reference group.
brca$cancer <- brca$cancer %>%
  as.factor() %>%
  relevel("control")
brca$variant <- brca$variant %>%
  as.factor() %>%
  relevel("pro/pro")
brcaLogit <- glm(cancer ~ variant, data = brca, family = binomial)
summary(brcaLogit)

Call:
glm(formula = cancer ~ variant, family = binomial, data = brca)

Deviance Residuals: 
   Min      1Q  Median      3Q     Max  
-1.379  -1.286   1.017   1.017   1.073  

Coefficients:
               Estimate Std. Error z value Pr(>|z|)   
(Intercept)     0.25131    0.08175   3.074  0.00211 **
variantleu/leu  0.21197    0.18915   1.121  0.26243   
variantpro/leu  0.13802    0.11573   1.193  0.23302   
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

(Dispersion parameter for binomial family taken to be 1)

    Null deviance: 1863.9  on 1371  degrees of freedom
Residual deviance: 1861.9  on 1369  degrees of freedom
AIC: 1867.9

Number of Fisher Scoring iterations: 4

The intercept is the log-odds on cancer in the reference class (Pro/Pro) and the slope terms are log odds ratios between treatment and reference class: \[\begin{eqnarray*} \log \text{ODDS}_\text{Pro/Pro}&=&\beta_0\\\\ \log \text{ODDS}_\text{Pro/Leu}&=&\beta_0+\beta_1\\\\ \log \text{ODDS}_\text{Leu/Leu}&=&\beta_0+\beta_2\\\\ \log \frac{\text{ODDS}_\text{Pro/Leu}}{\text{ODDS}_\text{Pro/Pro}}&=&\log \text{ODDS}_\text{Pro/Leu}-\log ODDS_{Pro/Pro}\\ &=&\beta_0+\beta_1-\beta_0=\beta_1\\\\ \log \frac{\text{ODDS}_\text{Leu/Leu}}{\text{ODDS}_\text{Pro/Pro}}&=&\beta_2 \end{eqnarray*}\]

  • The analysis allows us to interpret the result immediately in oddses and odds ratios!

anova(brcaLogit, test = "Chisq")

The \(\chi^2\)-test on the logsitic regression model also indicates that there is no significant association between cancer status and the genetic variant of the BRCA gene (\(p=\) 0.358). De p-value is almost equivalent to the one of the \(\chi^2\)-test (see previous section).


  • Significant association?

    • Post-hoc tests to evaluate which of the odds ratios are different from 1.
    • For BRCA1 example we did not reject the omnibus hypothesis so no post-hoc analysis
    • For your reference we include the post hoc analysis so that you would have the code.

suppressPackageStartupMessages({
  library(multcomp)
})
posthoc <- glht(brcaLogit, linfct = mcp(variant = "Tukey"))
posthocTests <- summary(posthoc)
posthocTests

     Simultaneous Tests for General Linear Hypotheses

Multiple Comparisons of Means: Tukey Contrasts


Fit: glm(formula = cancer ~ variant, family = binomial, data = brca)

Linear Hypotheses:
                       Estimate Std. Error z value Pr(>|z|)
leu/leu - pro/pro == 0  0.21197    0.18915   1.121    0.493
pro/leu - pro/pro == 0  0.13802    0.11573   1.193    0.449
pro/leu - leu/leu == 0 -0.07395    0.18922  -0.391    0.917
(Adjusted p values reported -- single-step method)

posthocCI <- confint(posthoc)
posthocCI

     Simultaneous Confidence Intervals

Multiple Comparisons of Means: Tukey Contrasts


Fit: glm(formula = cancer ~ variant, family = binomial, data = brca)

Quantile = 2.3247
95% family-wise confidence level
 

Linear Hypotheses:
                       Estimate lwr      upr     
leu/leu - pro/pro == 0  0.21197 -0.22774  0.65168
pro/leu - pro/pro == 0  0.13802 -0.13102  0.40706
pro/leu - leu/leu == 0 -0.07395 -0.51382  0.36592
  • With the confint function CI are obtained on the log-odds ratios corrected for multiple testing.

  • CI’s can be backtransformed to odds ratios:
OR <- exp(posthocCI$confint)
OR
                   Estimate       lwr      upr
leu/leu - pro/pro 1.2361111 0.7963315 1.918762
pro/leu - pro/pro 1.1480000 0.8772035 1.502393
pro/leu - leu/leu 0.9287191 0.5982045 1.441847
attr(,"conf.level")
[1] 0.95
attr(,"calpha")
[1] 2.324703
  • De odds ratios that we obtain is exactly equal to the one we calculated based on the contingency table:

  • e.g \(\text{OR}_\text{Leu/Leu-Pro/Pro}=89\times 266/(56\times 342)=\) 1.236.

  • Note, that statistical inference for logistic regression relies on asymptotic theory.


5.2 Continuous Predictor

  • Toxicolocal effect of carbon disulfite (CS\(_2\)) on beetles.
  • Research hypothesis is there an effect of the CS\(_2\) concentration on the mortality of beetles?

Design:

  • 32 independent experiments
  • Each time 1 beatle is exposed to one of 8 CS\(_2\) concentrations (mg/l).
  • The outcome: mortality (\(y=1\)) or survival (\(y=0\)).
beetles <- read_csv("https://raw.githubusercontent.com/GTPB/PSLS20/master/data/beetles.csv")
head(beetles)
table(beetles$dose, beetles$status)
        
         0 1
  169.07 3 1
  172.42 3 1
  175.52 3 1
  178.42 2 2
  181.13 1 3
  183.69 0 4
  186.1  0 4
  188.39 0 4

We build a model for the log odds in function of the dose \(x_i\): \[\log \frac{\pi_i}{1-\pi_i}=\beta_0+\beta_1 \times x_i.\]

beatleModel <- glm(status ~ dose, data = beetles, family = binomial)
summary(beatleModel)

Call:
glm(formula = status ~ dose, family = binomial, data = beetles)

Deviance Residuals: 
    Min       1Q   Median       3Q      Max  
-1.7943  -0.7136   0.2825   0.5177   2.1670  

Coefficients:
            Estimate Std. Error z value Pr(>|z|)   
(Intercept) -53.1928    18.0046  -2.954  0.00313 **
dose          0.3013     0.1014   2.972  0.00296 **
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

(Dispersion parameter for binomial family taken to be 1)

    Null deviance: 42.340  on 31  degrees of freedom
Residual deviance: 26.796  on 30  degrees of freedom
AIC: 30.796

Number of Fisher Scoring iterations: 5

  • Intercept has an interpretation of a log odds on mortality when no \(\text{CS}_2\) gas is applied.

  • Very small odds on mortality (\(\pi/(1-\pi)=\exp(-53.2)\)) so the probability is almost 0.

  • Note that this is a very large extrapolation: minimum dose in dataset is 169.07 mg/l.

  • Estimated odds ratio for the effect of dose on the mortality probability is \(\exp(0.3013)=1.35\).

  • So a beatle exposed to a CS\(_2\) concentration that is 1 mg/l larger than another beatle, will on average have an odds ratio on mortality of \(1.35\).


  • We conclude that this effect is very significant (\(p=\) 0.003).
  • Increasing the CS\(_2\) dose increases the mortality.
beetlesTab <- table(beetles) %>% data.frame()

data.frame(grid = seq(min(beetles$dose), max(beetles$dose), .1)) %>%
  mutate(piHat = predict(beatleModel,
    newdata = data.frame(dose = grid),
    type = "response"
  )) %>%
  ggplot(aes(grid, piHat)) +
  geom_line() +
  xlab("dose") +
  ylab("probability (dead)") +
  geom_text(aes(x = dose %>% as.character() %>% as.double(), y = status %>% as.character() %>% as.double(), label = Freq), beetlesTab %>% filter(status == 0)) +
  geom_text(aes(x = dose %>% as.character() %>% as.double(), y = status %>% as.character() %>% as.double(), label = Freq), beetlesTab %>% filter(status == 1))

LS0tCnRpdGxlOiAiMTAuIENhdGVnb3JpY2FsIERhdGEgQW5hbHlzaXMiCmF1dGhvcjogIkxpZXZlbiBDbGVtZW50IgpkYXRlOiAic3RhdE9taWNzLCBHaGVudCBVbml2ZXJzaXR5IChodHRwczovL3N0YXRvbWljcy5naXRodWIuaW8pIgotLS0KCjxhIHJlbD0ibGljZW5zZSIgaHJlZj0iaHR0cHM6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL2xpY2Vuc2VzL2J5LW5jLXNhLzQuMCI+PGltZyBhbHQ9IkNyZWF0aXZlIENvbW1vbnMgTGljZW5zZSIgc3R5bGU9ImJvcmRlci13aWR0aDowIiBzcmM9Imh0dHBzOi8vaS5jcmVhdGl2ZWNvbW1vbnMub3JnL2wvYnktbmMtc2EvNC4wLzg4eDMxLnBuZyIgLz48L2E+CgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRSwgY2FjaGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldCgKICBpbmNsdWRlID0gVFJVRSwgY29tbWVudCA9IE5BLCBlY2hvID0gVFJVRSwKICBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSwgY2FjaGUgPSBUUlVFCikKYGBgCgpgYGB7ciBsaWJyYXJpZXMsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGNhY2hlPUZBTFNFfQpsaWJyYXJ5KFJtaXNjKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShOSEFORVMpCmBgYAoKCgojIEludHJvZHVjdGlvbgoKVW50aWwgbm93IHdlIHVzZWQgbW9kZWxzIGZvciBhIGNvbnRpbnVvdXMgcmVzcG9uc2UgaW4gZnVuY3Rpb24gb2YgY2F0ZWdvcmljYWwgb3IgY29udGludW91cyBwcmVkaWN0b3IuIEhlcmUgd2Ugd2lsbCBmb2N1cyBvbiBhIGNhdGVnb3JpY2FsIHJlc3BvbnNlLgoKLSB3ZSBzdHVkeSB0aGUgYXNzb2NpYXRpb24gb2YgYSBjYXRlZ29yaWNhbCBvdXRjb21lIGFuZCBhIGNhdGVnb3JpY2FsIHByZWRpY3RvciBhbmQKLSB0b3VjaCB1cG9uIG1ldGhvZHMgdG8gbW9kZWwgYSBjYXRlZ29yaWNhbCBvdXRjb21lIHdpdGggYSBjb250aW51b3VzIHJlc3BvbnNlLgoKCi0tLQoKIyBUZXN0IGZvciBhIHByb3BvcnRpb24KCiMjIFNha3Nlbi1zdHVkeQoKLSBGYWlybHkgY2xvc2VkIHBvcHVsYXRpb24gKGZldyBtaWdyYXRpb24pCi0gUHJvYmFiaWxpdHkgdGhhdCBhbiB1bmJvcm4gY2hpbGQgaXMgbWFsZT8KCmBgYHtyfQpib3lzIDwtIDMxNzUKbiA8LSA2MTU1CmBgYAoKLSBPbiBgciBuYCB1bmJvcm4gY2hpbGRyZW4gYHIgYm95c2AgYm95cyBhcmUgb2JzZXJ2ZWQuCi0gSXMgdGhlcmUgYSBkaWZmZXJlbmNlIGluIHRoZSBwcm9iYWJpbGl0eSBvbiB0aGUgZ2VuZGVyIG9mIGFuIHVuYm9ybiBjaGlsZD8KCi0tLQoKLSBUaGUgZGF0YSBhcmUgZGVyaXZlZCBmcm9tIGEgYmluYXJ5IHJhbmRvbSB2YXJpYWJsZSAkWCQKCiAgLSAkWD0xJCBmb3IgYSBib3kgYW5kCiAgLSAkWD0wJCBmb3IgYSBnaXJsLgoKLSBOb3RlOiBjb3VudCBwcm9ibGVtOiB0aGUgb3V0Y29tZSBpcyBhIGNvdW50IChudW1iZXIgb2YgYm95cykKCi0gRm9ybWFsbHkgd2UgaGF2ZSBjb25zaWRlcmVkIGEgcG9wdWxhdGlvbiBvZiB1bmJvcm4gY2hpbGRyZW4gd2hlcmUgZWFjaCBpbmRpdmlkdWFsIGlzIGNoYXJhY3Rlcml6ZWQgYnkgYSAwIG9yIDEuCgotLS0KCiMjIEJlcm5vdWxsaSBQcm9iYWJpbGl0eSBNYXNzIERpc3RyaWJ1dGlvbgoKLSBCaW5hcnkgZGF0YSBjYW4gYmUgbW9kZWxsZWQgdXNpbmcgYSBCZXJub3VsbGkgZGlzdHJpYnV0aW9uOgogIFxiZWdpbntlcW5hcnJheSp9ClhfaSAmXHNpbSYgQihccGkpIFx0ZXh0eyB3aXRofVxcCkIoXHBpKSY9JlxwaV57WF9pfSgxLVxwaSleeygxLVhfaSl9LApcZW5ke2VxbmFycmF5Kn0KCi0gSXQgaGFzIG9uZSBtb2RlbCBwYXJhbWV0ZXIgJFxwaSQKCiAgICAtIEV4cGVjdGVkIHZhbHVlIG9mICRYX2kkOiAkXHRleHR7RX1bWF9pXT1ccGksJAogICAgLSBQcm9wb3J0aW9uIG9mIHVuYm9ybiBib3lzIChjaGlsZHJlbiB3aXRoICRYPTEkKSBpbiB0aGUgcG9wdWxhdGlvbi4KICAgIC0gSGVuY2UgJFxwaSQgaXMgdGhlIHByb2JhYmlsaXR5IHRoYXQgYSByYW5kb20gaW5kaXZpZHVhbCBmcm9tIHRoZSBwb3B1bGF0aW9uIGlzIGEgYm95IChhbiBvYnNlcnZhdGlvbiB3aXRoICRYPTEkKS4KCi0gVGhlIHZhcmlhbmNlIG9mIEJlcm5vdWxsaSBkYXRhIGlzIGFsc28gcmVsYXRlZCB0byAkXHBpJC4KJCRcdGV4dHtWYXJ9W1hfaV09XHBpICgxLVxwaSkuJCQKCi0tLQoKU29tZSBCZXJub3VsbGkgcHJvYmFiaWxpdHkgbWFzcyBmdW5jdGlvbnMKCmBgYHtyLCBvdXQud2lkdGg9JzEwMCUnLCBmaWcuYXNwPTEsIGZpZy5hbGlnbj0nY2VudGVyJyxlY2hvPUZBTFNFfQpwYXIobWZyb3cgPSBjKDEsIDMpLCBwdHkgPSAicyIpCnByb2JzIDwtIGMoMC4yNSwgLjUsIC43NSkKZm9yIChpIGluIDE6bGVuZ3RoKHByb2JzKSkKewogIHBsb3QoYygwLCAxKSwgYygxIC0gcHJvYnNbaV0sIHByb2JzW2ldKSwgeWxpbSA9IGMoMCwgMSksIHR5cGUgPSAiaCIsIHhheHQgPSAibiIsIHhsYWIgPSAiWCIsIHlsYWIgPSAiUHJvYmFiaWxpdHkiLCBtYWluID0gYXMuZXhwcmVzc2lvbihzdWJzdGl0dXRlKHBpID09IHZhbCwgbGlzdCh2YWwgPSBwcm9ic1tpXSkpKSwgbHdkID0gMykKICBheGlzKDEsIGF0ID0gYygwLCAxKSkKfQpgYGAKCi0tLQoKLSBJbiB0aGUgU2Frc2VuIHN0dWR5ICA2MTU1IG9ic2VydmF0aWVzIHdlcmUgc2FtcGxlZCBhdCByYW5kb20gZnJvbSB0aGUgcG9wdWxhdGlvbi4KLSBXZSBjYW4gZXN0aW1hdGUgJFxwaSQgIHVzaW5nIHRoZSBzYW1wbGUgbWVhbjoKJCRcaGF0IFxwaSA9IFxiYXIgWCA9IFxmcmFje1xzdW1cbGltaXRzX3tpPTF9Xm4gWF9pfXtufSwkJAoKYGBge3J9CnBpIDwtIGJveXMgLyBuCnBpCmBgYAoKSW4gb3VyIGV4YW1wbGUgJFxiYXIgeCA9JCBgciBib3lzYCAvIGByIG5gID0gYHIgZm9ybWF0KHBpKjEwMCxkaWdpdHM9MylgJS4KCi0tLQoKIyMgQmlub21pYWwgdGVzdAoKLSBJcyB0aGUgb2JzZXJ2ZWQgcHJvYmFiaWxpdHkgYHIgZm9ybWF0KHBpKjEwMCxkaWdpdD0zKWAlIHRoYXQgYW4gdW5ib3JuIGNoaWxkIGlzIG1hbGUsIHN1ZmZpY2llbnQgZXZpZGVuY2UgdG8gY29uY2x1ZGUgdGhhdCB0aGVyZSBpcyBhIGhpZ2hlciBjaGFuY2Ugb24gYSBib3kgdGhhbiBvbiBhIGdpcmw/CgotIFN0YXRpc3RpY2FsIHRlc3QgZm9yCiAgJCRIXzA6IFxwaT0xLzIgXHRleHR7IHZlcnN1cyB9IEhfMTogXHBpXG5lcSAxLzIsJCQKCi0gV2UgbmVlZCBrbm93biB0aGUgZGlzdHJpYnV0aW9uIG9mCgogICAgLSAkWCQgYW5kICRcYmFyIFgkCiAgICAtIG9yIG9mIHRoZSBzdW0gJFM9blxiYXIgWCQuCgotLS0KCgotIFN1cHBvc2UgdGhhdCAkSF8wOlxwaT0xLzIkIGlzIHRydWUgKGJveXMgYW5kIGdpcmxzIGhhdmUgYW4gZXF1YWwgZnJlcXVlbmN5IGluIHRoZSBwb3B1bGF0aW9uKQotIEEgcmFuZG9tIGluZGl2aWR1YWwgZnJvbSB0aGUgcG9wdWxhdGlvbiBoYXMgYSBwcm9iYWJpbGl0eSBvZiAkJFAoWD0xKT1ccGk9MS8yLiQkIHRvIGJlIGEgYm95CgotIFR3byBjaGlsZHJlbiB0aGF0IGFyZSBkcmF3biBpbmRlcGVuZGVudGx5IDoKCiAgICAtIFByb2JhYmlsaXR5IG9mICRccGk9MS8yJCBvbiBhIGJveSBmb3IgdGhlIGZpcnN0IGFuZCBzZWNvbmQgY2hpbGQgKGluZGVwZW5kZW50IGZyb20gZWFjaCBvdGhlcikKICAgIC0gT3V0Y29tZXMgJCh4XzEsIHhfMikkIGZvciBib3RoIGNoaWxkcmVuIGhhdmUgNCBwb3NzaWJsZSBjb21iaW5hdGlvbnM6CiAgICAkKDAsMCksKDAsMSksKDEsMClcdGV4dHsgZW4gfSgxLDEpLiQKICAgIC0gRWFjaCBvZiB0aGVtIGhhcyBhIHByb2JhYmlsaXR5IG9mICQxLzQgPSAxLzIgXHRpbWVzIDEvMiQuCgotIFJhbmRvbSB2YXJpYWJsZSAkUyQgaXMgdGhlIHN1bSBvZiB0aGUgb3V0Y29tZXMgOgoKJCh4XzEseF8yKSR8JHMkfCRQKFMgPSBzKSR8Cnw6LS0tOnw6LS0tOnw6LS0tOnwKKDAsMCl8MHwxLzR8CigwLDEpLCAoMSwwKXwxfDEvMnwKKDEsMSl8MnwxLzR8CgotLS0KCiMjIyBHZW5lcmFsOiAkbiQgaW5kZXBlbmRlbnQgc2FtcGxlcwoKLSBQcm9iYWJpbGl0eSBmb3IgJFxwaSQgb24gc3VjY2VzcyAoJFg9MSQpCi0gVG90YWwgbnVtYmVyIG9mIHN1Y2Nlc3NlcyAkUyQgKHN1bSBvZiBhbGwgdmFsdWVzIG9mIDEpIGNhbiB0YWtlICRuKzEkIHBvc3NpYmxlIHZhbHVlcwogICQkUz1rXHRleHR7LCBtZXQgfWs9MCxcbGRvdHMsbiQkCi0gRGlzdHJpYnV0aW9uIG9mICRTJD8KXGJlZ2lue2VxdWF0aW9ufQpQKFM9aykgPSBcbGVmdCAoClxiZWdpbnthcnJheX17Y30KbiBcXAprIFxcClxlbmR7YXJyYXl9ClxyaWdodCApIFxwaV5rICgxLVxwaSlee24ta30KXGVuZHtlcXVhdGlvbn0KLSAkMS1ccGkkOiBwcm9iYWJpbGl0eSBvbiAwIGZvciBpbmRpdmlkdWFsIG9ic2VydmF0aW9uIGFuZAotICBiaW5vbWlhbCBjb2VmZmljaWVudApcYmVnaW57ZXF1YXRpb24qfQpcbGVmdCAoClxiZWdpbnthcnJheX17Y30KbiBcXAprIFxcClxlbmR7YXJyYXl9ClxyaWdodCApID0gXGZyYWN7biBcdGltZXMgKG4tMSkgXHRpbWVzIC4uLlx0aW1lcyAobi1rKzEpIH17IGshfSA9IFxmcmFjeyBuIX17IGshKG4taykhIH0KXGVuZHtlcXVhdGlvbip9CgotIEluIFIgeW91IGNhbiBjYWxjdWxhdGUgdGhlIHByb2JhYmlsaXRpZXMgb24gZWFjaCAkUz1rJCB3aXRoIHRoZSBmdW5jdGlvbiBgZGJpbm9tKGssbixwKWAKCgotLS0KCiMjIyBCaW5vbWlhbCBEaXN0cmlidXRpb24KClMgaXMgYToKCi0gICpCaW5vbWlhbCBkaXN0cmlidXRlZCByYW5kb20gIHZhcmlhYmxlKiB3aXRoICpCaW5vbWlhbCBwcm9iYWJpbGl0eSBtYXNzIGZ1bmN0aW9uKgoKLSBQYXJhbWV0ZXJzCgogICAgLSAkbiQgKHRvdGFsIG51bWJlciBvZiBkcmF3cyBmcm9tIHRoZSBwb3B1bGF0aW9uLCBpcyBlcXVpdmFsZW50IHRvIG1heGltYWwgdmFsdWUgb2YgdGhlIG91dGNvbWUpCiAgICAtICRccGkkIChwcm9iYWJpbGl0eSBvbiBgc3VjY2Vzc2AgZm9yIGVhY2ggZHJhdykuCgotIENhbGN1bGF0ZSBwcm9iYWJpbGl0eSBvbiAkayQgc3VjY2Vzc2VzIG9uICRuJCBpbmRlcGVuZGVudCBkcmF3cyBlYWNoIHdpdGggYSBzdWNjZXMgcHJvYmFiaWxpdHkgb2YgJFxwaSQuCi0gRm9yIGJpbmFyeSBkYXRhIFguCi0gZS5nLjogd2lsZCB0eXBlIHZzIG11dGFudCBvZiBhIGdlbmUsIGluZmVjdGVkIG9yIG5vdCBpbmZlY3RlZCB3aXRoIEhJViwgLi4uCi0gVXNlOiBDb21wYXJlIHByb3BvcnRpb25zIG9yIHJpc2tzIG9uIGEgcGFydGljdWxhciBldmVudCBiZXR3ZWVuIGdyb3Vwcy4KCi0tLQoKIyMjIFNvbWUgQmlub21pYWwgcHJvYmFiaWxpdHkgbWFzcyBmdW5jdGlvbnMuCgpgYGB7ciBiaW5vbXMsZmlnLmNhcD0nQmlub21pYWwgZGlzdHJpYnV0aW9ucy4nLCBvdXQud2lkdGg9JzgwJScsIGZpZy5hc3A9LjgsIGZpZy5hbGlnbj0nY2VudGVyJyxlY2hvPUZBTFNFfQpwYXIobWZyb3cgPSBjKDIsIDIpKQpwcm9icyA8LSBjKDAuMjUsIC41LCAuNzUpCmZvciAoaSBpbiAxOmxlbmd0aChwcm9icykpCnsKICBwbG90KDA6MTAsIGRiaW5vbSgwOjEwLCBwcm9iID0gcHJvYnNbaV0sIHNpemUgPSAxMCksIHlsaW0gPSBjKDAsIDEpLCB0eXBlID0gImgiLCB4bGFiID0gIlgiLCB5bGFiID0gIkthbnMgKERpY2h0aGVpZCkiLCBtYWluID0gYXMuZXhwcmVzc2lvbihzdWJzdGl0dXRlKHBpID09IHZhbCwgbGlzdCh2YWwgPSBwYXN0ZShwcm9ic1tpXSwgIiwgbm9icz0xMCIpKSkpLCBsd2QgPSAzKQp9CnBsb3QoMjkyNTozMjI1LCBkYmlub20oMjkyNTozMjI1LCBwcm9iID0gLjUsIHNpemUgPSBuKSwgdHlwZSA9ICJoIiwgeGxhYiA9ICJYIiwgeWxhYiA9ICJLYW5zIChEaWNodGhlaWQpIiwgbWFpbiA9IGFzLmV4cHJlc3Npb24oc3Vic3RpdHV0ZShwaSA9PSB2YWwsIGxpc3QodmFsID0gcGFzdGUwKCIwLjUsIG5vYnM9IiwgbikpKSkpCmBgYAoKLS0tCgpUZXN0IHN0YXRpc3RpYyAkJEhfMDpccGk9MS8yXHRleHR7IHZzIH1IXzE6XHBpXG5lcSAxLzIkJAoKCi0gJFxiYXIgWC0xLzIkIG9yLCBlcXVpdmFsZW50LAotICRcRGVsdGE9bihcYmFyIFgtXHBpXzApPVMtc18wJC4KLSBEaXN0cmlidXRpb24gb2YgdGhlIGxhdHRlciB0ZXN0IHN0YXRpc3RpYyBjYW4gYmUgZGVyaXZlZCBpbW1lZGlhdGVseSBmcm9tIHRoZSBCaW5vbWlhbCBkaXN0cmlidXRpb246CiAgLSBXZSBvYnNlcnZlICRzPSQgYHIgYm95c2AgYW5kIHRodXMgJFxkZWx0YT1zLXNfMD0kIGByIGJveXNgICQtJCBgciBuYCAkXHRpbWVzIDAuNT0kIGByIGJveXMtbi8yYC4KICAtIFdoZW4gYm95cyBhbmQgZ2lybHMgYXJlIGVxdWFsbHkgbGlrZWx5LCBpLmUuIHVuZGVyICRIXzA6XHBpPTEvMiQsIHdlIHdpbGwgZ2V0IGZvbGxvd2luZyB0d28tc2lkZWQgcC12YWx1ZToKICAgICQkcD1cdGV4dHtQfV8wXGxlZnRbUy1zXzBcZ2VxIFx2ZXJ0IFxkZWx0YVx2ZXJ0IFxyaWdodF0gKyBcdGV4dHtQfV8wXGxlZnRbUy1zXzBcbGVxIC0gXHZlcnQgXGRlbHRhXHZlcnQgXHJpZ2h0XS4kJAoKLSBOb3RlLCB0aGF0IHdlIGNhbiByZXdyaXRlIGl0IGluIHRlcm1zIG9mIFMuCiQkcD1cdGV4dHtQfV8wXGxlZnRbU1xnZXEgc18wKyBcdmVydCBcZGVsdGFcdmVydCBccmlnaHRdICsgXHRleHR7UH1fMFxsZWZ0W1MgXGxlcSBzXzAgLSBcdmVydCBcZGVsdGFcdmVydCBccmlnaHRdLiQkCgotLS0KCi0gRm9yIHRoZSBTYWtzZW4gc3R1ZHkgd2UgY2FsY3VsYXRlOgoKXGJlZ2lue2VxbmFycmF5Kn0KXHRleHR7UH1fMFxsZWZ0W1NcZ2VxIHNfMCsgXHZlcnQgXGRlbHRhXHZlcnQgXHJpZ2h0XSAmPSYgUChTIFxnZXEgNjE1NSBcdGltZXMgMC41ICsgXHZlcnQgMzE3NSAtIDYxNTUgXHRpbWVzIDAuNVx2ZXJ0ICkgXFwmPSYgUChTIFxnZXEgMzE3NSlcXAomPSAmUChTPSAzMTc1KSArIFAoUz0zMTc2KSArIC4uLiArIFAoUz02MTU1KVxcCiYgPSYgMC4wMDY3XFxcXApcdGV4dHtQfV8wXGxlZnRbUyBcbGVxIHNfMCAtIFx2ZXJ0IFxkZWx0YVx2ZXJ0IFxyaWdodF0gJj0mIFAoUyBcbGVxICA2MTU1IFx0aW1lcyAwLjUgLSBcdmVydCAzMTc1LSA2MTU1IFx0aW1lcyAwLjVcdmVydCkgXFwmPSYgUChTIFxsZXEgMjk4MClcXCAmPSAmUChTPTApICsgLi4uICsgUChTPTI5ODApIFxcCiY9JjAuMDA2NwpcZW5ke2VxbmFycmF5Kn0KCi0gVGhlIEJpbm9taWFsIGRpc3RyaWJ1dGlvbiBpcyBzeW1tZXRyaWMgZm9yJFxwaT0xLzIkOgokJFx0ZXh0e1B9XzBcbGVmdFtTXGdlcSBzXzArIFx2ZXJ0IFxkZWx0YVx2ZXJ0IFxyaWdodF0gPSBcdGV4dHtQfV8wXGxlZnRbUyBcbGVxIHNfMCAtIFx2ZXJ0IFxkZWx0YVx2ZXJ0IFxyaWdodF0kJAotIFRoaXMgaXMgbm8gbG9uZ2VyIHRoZSBjYXNlIHdoZW4gJFxwaSQgZGV2aWF0ZSBmcm9tIDAuNS4KCi0tLQoKCmBgYHtyfQpwaTAgPC0gMC41CnMwIDwtIHBpMCAqIG4KZGVsdGEgPC0gYWJzKGJveXMgLSBzMCkKZGVsdGEKCnNVcCA8LSBzMCArIGRlbHRhCnNEb3duIDwtIHMwIC0gZGVsdGEKYyhzRG93biwgc1VwKQoKcFVwIDwtIDEgLSBwYmlub20oc1VwIC0gMSwgbiwgcGkwKQpwRG93biA8LSBwYmlub20oc0Rvd24sIG4sIHBpMCkKcCA8LSBwVXAgKyBwRG93bgpjKHBVcCwgcERvd24sIHApCmBgYAoKLS0tCgoKLSBJZiAkXHBpPSAxLzIkLCB0aGUgcHJvYmFiaWxpdHkgdG8gb2JzZXJ2ZSBhdCBsZWFzdCAgJFxkZWx0YT0kIGByIGRlbHRhYCBib3lzIG1vcmUgb3IgbGVzcyB0aGFuIHRoZSBtZWFuIHVuZGVyICRIXzA6IHNfMD0kIGByIHMwYCBpbiBhIHJhbmRvbSBzYW1wbGUgdW5kZXIgSF8wIGlzIG9ubHkgYHIgZm9ybWF0KHAqMTAwLGRpZ2l0cz0zKWAlIGlzOiAqKiRwJC12YWx1ZSBvZiBiaW5vbWlhbCB0ZXN0LioqCi0gVmVyeSB1bmxpa2VseSB0byBvYnNlcnZlIHN1Y2ggYSBsYXJnZSBudW1iZXIgb2YgYm95cyBpbiBhIHJhbmRvbSBzYW1wbGUgd2hlbiBib3lzIGFuZCBnaXJscyBoYXZlIHRoZSBzYW1lICBmcmVxdWVuY3kgaW4gdGhlIHBvcHVsYXRpb24gKHVuZGVyICRIXzAkKS4KLSBIZW5jZSB0aGUgaHlwb3RoZXNpcyB0aGF0IHRoZSBmcmVxdWVuY3kgb2YgYm95cyBhbmQgZ2lybHMgaXMgdGhlIHNhbWUgaXMgbm90IHN1cHBvcnRlZCBieSB0aGUgZGF0YS4KCi0tLQoKYGBge3IsIG91dC53aWR0aD0nMTAwJScsIGZpZy5hc3A9LjgsIGZpZy5hbGlnbj0nY2VudGVyJyxlY2hvPUZBTFNFfQpwbG90KHMwICsgc2VxKC0xNTAuNSwgMTUwLjUsIDEpLCBkYmlub20oczAgKyBzZXEoLTE1MC41LCAxNTAuNSwgMSksIHByb2IgPSAuNSwgc2l6ZSA9IG4pLCB0eXBlID0gImgiLCB4bGFiID0gIlgiLCB5bGFiID0gIlByb2JhYmlsaXR5IiwgbWFpbiA9IGFzLmV4cHJlc3Npb24oc3Vic3RpdHV0ZShwaSA9PSB2YWwsIGxpc3QodmFsID0gcGFzdGUwKCIwLjUsIG5vYnM9IiwgbikpKSksIHlsaW0gPSBjKC0uMDAwOSwgMC4wMTEpKQphYmxpbmUodiA9IHMwLCBsd2QgPSAyLCBjb2wgPSA0KQphYmxpbmUodiA9IGJveXMsIGx3ZCA9IDIsIGNvbCA9IDIpCmFibGluZSh2ID0gc0Rvd24sIGx3ZCA9IDEsIGNvbCA9IDIsIGx0eSA9IDIpCnRleHQoYyhzRG93biwgczAsIGJveXMsIGJveXMpLCBjKHJlcCgwLjAxMSwgMyksIDAuMDEpLCBsYWJlbHMgPSBjKGV4cHJlc3Npb24ocGFzdGUoc1swXSAtIGRlbHRhKSksIGV4cHJlc3Npb24oc1swXSksIGV4cHJlc3Npb24ocyA9PSBzWzBdICsgZGVsdGEpLCBhcy5leHByZXNzaW9uKHN1YnN0aXR1dGUocyA9PSB2YWwsIGxpc3QodmFsID0gYm95cykpKSksIHBvcyA9IDQsIGNvbCA9IGMoMiwgNCwgMikpCnRleHQoc0Rvd24gLSA1MCwgLS4wMDA1LCBsYWJlbCA9ICJwLXZhbHVlIiwgY29sID0gMiwgcG9zID0gNCkKdGV4dChzVXAsIC0uMDAwNSwgbGFiZWwgPSAicC12YWx1ZSIsIGNvbCA9IDIsIHBvcyA9IDQpCmFycm93cyhzMCArIDE1MDAuNSwgLS4wMDA5LCBzVXAsIC0uMDAwOSwgY29sID0gMiwgbHdkID0gMiwgYW5nbGUgPSAyMCwgbGVuZ3RoID0gLjEpCmFycm93cyhzMCAtIDE1MDAuNSwgLS4wMDA5LCBzRG93biwgLS4wMDA5LCBjb2wgPSAyLCBsd2QgPSAyLCBhbmdsZSA9IDIwLCBsZW5ndGggPSAuMSkKYGBgCgotLS0KClRoZSB0ZXN0IGNhbiBpbW1lZGlhdGVseSBiZSBjb25kdWN0ZWQgdXNpbmcgdGhlIGBiaW5vbWlhbC50ZXN0YCBmdW5jdGlvbiBpbiBSLgoKYGBge3J9CmJpbm9tLnRlc3QoeCA9IGJveXMsIG4gPSBuLCBwID0gcGkwKQpgYGAKCk9uIHRoZSA1JSBzaWduaWZpY2FuY2UtbGV2ZWwgd2UgY29uY2x1ZGUgdGhhdCB0aGVyZSBpcyBvbiBhdmVyYWdlIGEgaGlnaGVyIHByb2JhYmlsaXR5IG9uIGEgdW5ib3JuIG1hbGUgY2hpbGQgdGhhbiBhbiB1bmJvcm4gZmVtYWxlIGNoaWxkLgoKLS0tCgojIyMgQ29uZmlkZW5jZSBpbnRlcnZhbCBvbiBhIHByb3BvcnRpb24KCi0gRXN0aW1hdG9yIG9mIHRoZSBwcm9wb3J0aW9uIG9mIGJveXMgaW4gdGhlIHBvcHVsYXRpb24gIGlzIHRoZSBzYW1wbGUgbWVhbiAkXGhhdCBccGk9XGJhciB4PSQgYHIgZm9ybWF0KHBpLGRpZ2l0cz0zKWAKLSBUaGUgc3RhbmRhcmQgZXJyb3IgaXMKJCRTRV97XGJhciB4fT1cc3FydHtcZnJhY3tcdGV4dHtWYXJ9W1hdfXtufX09XHNxcnR7XGZyYWN7XHBpKDEtXHBpKX17bn19JCQKLSBXZSBjYW4gZXN0aW1hdGUgdGhpcyBiYXNlZCBvbiB0aGUgc2FtcGxlOiAkU0Vfe1xiYXIgeH09XHNxcnR7XGZyYWN7XGhhdFxwaSgxLVxoYXRccGkpfXtufX09JCBgciBmb3JtYXQoc3FydChwaSooMS1waSkvbiksZGlnaXRzPTIpYC4KLSA5NSUgQ0kgdmlhIENMVDogJFxoYXRccGkgXHBtIDEuOTYgU0Vfe1xoYXRccGl9LiQKCmBgYHtyfQpzZSA8LSBzcXJ0KHBpICogKDEgLSBwaSkgLyBuKQpwaSArIGMoLTEsIDEpICogcW5vcm0oMC45NzUpICogc2UKYGBgCgotLS0KCiMjIyBDSSBvbiBwcm9wb3J0aW9uIGluIHNtYWxsIHNhbXBsZT8KCmBgYHtyfQpDSSA8LSBiaW5vbS50ZXN0KHggPSBib3lzLCBuID0gbiwgcCA9IHBpMCkkY29uZi5pbnQKQ0kKYGBgCgotLS0KCgojIyMgQ29uY2x1c2lvbgoKLSBOb3RlIHRoYXQgdGhlIHRlc3QgZm9yIGEgcHJvcG9ydGlvbiBpcyBlcXVpdmFsZW50IHRvIGEgb25lLXNhbXBsZSB0LXRlc3QgZm9yIGJpbmFyeSBkYXRhLgoKLSBGb3IgdGhlIFNha3NlbiBwb3B1bGF0aW9uIHdlIGNvbmNsdWRlIGF0IHRoZSA1JSBzaWduaWZpY2FuY2UgbGV2ZWwgdGhhdCB0aGUgZ2VuZGVyIG9mIHVuYm9ybiBjaGlsZHJlbiBpcyBtb3JlIGxpa2VseSB0byBiZSBtYWxlIHRoYW4gZmVtYWxlICgkcD0kIGByIHJvdW5kKGJpbm9tLnRlc3QoeD1ib3lzLG49bixwPXBpMCkkcC52YWx1ZSwzKWApLgpUaGUgcHJvYmFiaWxpdHkgdGhhdCBhbiB1bmJvcm4gY2hpbGQgaXMgbWFsZSBlcXVhbHMgYHIgZm9ybWF0KHBpKjEwMCxkaWdpdHM9MylgJSAoOTUlIENJIFtgciBwYXN0ZShmb3JtYXQoQ0kqMTAwLGRpZ2l0cz0zKSxjb2xsYXBzZT0iLCIpYF0lKS4KCi0tLQoKIyBUZXN0IGZvciBhc3NvY2lhdGlvbiBiZXR3ZWVuIHR3byBxdWFsaXRhdGl2ZSB2YXJpYWJsZXMKIyMgUGFpcmVkIG9ic2VydmF0aW9ucwoKLSAyIG1lYXN1cmVtZW50cyBvbiBzYW1lIGluZGl2aWR1YWwKLSBlLmcuIGJlZm9yZSBhbmQgYWZ0ZXIgZXhwb3N1cmUgdG8gYSBjaGVtaWNhbCBzdWJzdGFuY2UKLSBvYnNlcnZlIGEgY2F0ZWdvcmljYWwgb3V0Y29tZSBiZWZvcmUgYW5kIGFmdGVyLgotICpwYWlyZWQgYmluYXJ5IHJlc3BvbnNlcyoKLSBTdGF0aXN0aWNhbCBhbmFseXNpcyBoYXMgdG8gYWNjb3VudCBmb3IgcGFpcmVkIGRlc2lnbi4KCi0tLQoKIyMjIEV4YW1wbGU6ICBGZW1hbGVzIGNob29zZSBnZW50bGUsIGJ1dCBub3QgaGVhbHRoeSBvciBtYWNobyBtYWxlcyBpbiBDYW1wYmVsbCBkd2FyZiBoYW1zdGVycyAoUm9nb3ZpbiBldCBhbC4gMjAxNykKCmBgYHtyLCBvdXQud2lkdGg9JzcwJScsIGZpZy5hc3A9MSwgZmlnLmFsaWduPSdjZW50ZXInLGVjaG89RkFMU0V9CmxpYnJhcnkocGxvdHJpeCkKcGFyKG1hciA9IGMoMCwgMCwgMCwgMCksIG1haSA9IGMoMCwgMCwgMCwgMCkpCnBsb3QoMCwgMCwgYXhlcyA9IEZBTFNFLCB4bGFiID0gIiIsIHlsYWIgPSAiIiwgY29sID0gMCwgeGxpbSA9IGMoMCwgMyksIHlsaW0gPSBjKDAsIDMpKQpyZWN0KDAsIDAsIDMsIDMpCmxpbmVzKGMoMSwgMSksIGMoMCwgMykpCmxpbmVzKGMoMiwgMiksIGMoMCwgMykpCmxpbmVzKGMoMSwgMSksIGMoMSwgMiksIGx3ZCA9IDIpCmxpbmVzKGMoMSwgMSksIGMoMSwgMiksIGx3ZCA9IDQpCmxpbmVzKGMoMiwgMiksIGMoMSwgMiksIGx3ZCA9IDQpCnJlY3QoMS40NSwgMSwgMS41NSwgMS4zKQpkcmF3LmNpcmNsZSgxLjUsIDEuMzYsIDAuMDUpCmxpbmVzKGMoMS41LCAxLjUpLCBjKDEsIC44NSkpCnRleHQoMS41LCAxLjE1LCAiXFxWRSIsIHZmb250ID0gYygic2FucyBzZXJpZiIsICJib2xkIiksIGNleCA9IDEuMykKcmVjdCgwLjUsIDEuMDUsIDAuOCwgMS4xNSkKZHJhdy5jaXJjbGUoMC44NiwgMS4xLCAwLjA1KQpsaW5lcyhjKDAuNSwgMC4zNSksIGMoMS4xLCAxLjEpKQpsaW5lcyhjKDAuOCwgMCksIGMoMS4xLCAxLjUpLCBsdHkgPSAyKQp0ZXh0KDAuNjUsIDEuMSwgIlxcTUEiLCB2Zm9udCA9IGMoInNhbnMgc2VyaWYiLCAiYm9sZCIpLCBjZXggPSAxLjMpCnJlY3QoMi41LCAxLjk1LCAyLjIsIDEuODUpCmRyYXcuY2lyY2xlKDIuMTQsIDEuOSwgMC4wNSkKbGluZXMoYygyLjUsIDIuNjUpLCBjKDEuOSwgMS45KSkKbGluZXMoYygyLjIsIDMpLCBjKDEuOSwgMS41KSwgbHR5ID0gMikKdGV4dCgyLjM1LCAxLjksICJcXE1BIiwgdmZvbnQgPSBjKCJzYW5zIHNlcmlmIiwgImJvbGQiKSwgY2V4ID0gMS4zKQpgYGAKCi0tLQoKLSBUaGUgZ2F0ZSBpcyBvcGVuZWQgdXBvbiAzIG1pbnV0ZXMKLSBhZ2dyZXNzaXZlIHZzIG5vbi1hZ3Jlc3NpdmUgbWFsZQotIEVhY2ggZmVtYWxlIHVuZGVyZ29lcyB0aGUgdGVzdCB0d2ljZToKCiAgICAtIG9uY2UgdXBvbiBzdGF5IGluIGhvc3RpbGUgZW52aXJvbm1lbnQgKGhpZ2ggcG9wdWxhdGlvbiBkZW5zaXR5LCBzaG9ydGFnZSBvZiBmZWVkLCBhIGxvdCBvZiBjb21wZXRpdGlvbikKICAgIC0gYW5kIG9uY2UgdXBvbiBzdGF5IGluIGdlbnRsZSBldmlyb25tZW50LgoKCmBgYHtyIGNhdEhhbXN0ZXIsIGVjaG89RkFMU0V9CmhhbXN0ZXIgPC0gbWF0cml4KGMoMywgMTcsIDEsIDEzKSwgbmNvbCA9IDIsIGJ5cm93ID0gVFJVRSkKcm93bmFtZXMoaGFtc3RlcikgPC0gYygiaG9zdGlsZV9hZ3Jlc3NpdmUiLCAiaG9zdGlsZV9ub24tYWdyZXNzaXZlIikKY29sbmFtZXMoaGFtc3RlcikgPC0gYygiZnJpZW5kbHlfYWdyZXNzaXZlIiwgImZyaWVuZGx5X25vbi1hZ3Jlc3NpdmUiKQpoYW1zdGVyVG90IDwtIG1hdHJpeCgwLCBucm93ID0gMywgbmNvbCA9IDMpCmhhbXN0ZXJUb3RbMToyLCAxOjJdIDwtIGhhbXN0ZXIKaGFtc3RlclRvdFszLCAxOjJdIDwtIGNvbFN1bXMoaGFtc3RlcikKaGFtc3RlclRvdFssIDNdIDwtIHJvd1N1bXMoaGFtc3RlclRvdFssIDE6Ml0pCmhhbXN0ZXJMZXR0ZXJzIDwtIG1hdHJpeChjKCIgKGUpIiwgIiAoZikiLCAiIiwgIiAoZykiLCAiIChoKSIsICIiLCAiIiwgIiIsICIiKSwgbmNvbCA9IDMsIGJ5cm93ID0gVFJVRSkKaGFtc3RlclRvdCA8LSBtYXRyaXgocGFzdGUwKGhhbXN0ZXJUb3QsIGhhbXN0ZXJMZXR0ZXJzKSwgYnlyb3cgPSBGQUxTRSwgbmNvbCA9IDMpCmNvbG5hbWVzKGhhbXN0ZXJUb3QpIDwtIGMoY29sbmFtZXMoaGFtc3RlciksICJ0b3RhbCIpCnJvd25hbWVzKGhhbXN0ZXJUb3QpIDwtIGMocm93bmFtZXMoaGFtc3RlciksICJ0b3RhbCIpCmtuaXRyOjprYWJsZShoYW1zdGVyVG90LCBib29rdGFicyA9IFRSVUUpCmBgYAoKLS0tCgojIyMgQWJzb2x1dGUgcmlzayBkaWZmZXJlbmNlIChBUkQpCgotICRccGlfMT1QW1x0ZXh0e2FncmVzc2l2ZSBtYWxlIH0gXHZlcnQgXHRleHR7aG9zdGlsZX1dJAotICRcaGF0IFxwaV8xPShlK2YpL24kLCB3aXRoICRuPWUrZitnK2gkLgoKLSAkXHBpXzA9UFtcdGV4dHthZ3Jlc3NpdmUgbWFsZSB9IFx2ZXJ0IFx0ZXh0eyBmcmllbmRseX1dJAotICRcaGF0IFxwaV8wPShlK2cpL24kClxiZWdpbntlcXVhdGlvbip9Clx3aWRlaGF0e1x0ZXh0e0FSRH19PVxoYXRccGlfMS1caGF0XHBpXzA9XGZyYWN7ZStmfXtufS1cZnJhY3tlK2d9e259PVxmcmFje2YtZ317bn0KXGVuZHtlcXVhdGlvbip9Ci0gT25seSBhZmZlY3RlZCBieSBkaXNjb3JkYW50IHBhaXJzICRmJCBlbiAkZyQKCi0tLQoKLSBTdGFuZGFyZCBlcnJvciBvbiBBUkQKXGJlZ2lue2VxdWF0aW9uKn0KXHRleHR7U0V9X3tcd2lkZWhhdHtcdGV4dHtBUkR9fX09XGZyYWN7MX17bn1cc3FydHtmK2ctXGZyYWN7KGYtZyleMn17bn19ClxlbmR7ZXF1YXRpb24qfQoKLSBJZiB3ZSBoYXZlIGxhcmdlIG51bWJlciBvZiBvYnNlcnZhdGlvbnMgd2UgY2FuIHVzZSB0aGUgQ0xUIHRvIGVzdGFibGlzaCBhbiAkKDEtXGFscGhhKTEwMFwlJCBDSSBvbiB0aGUgQVJECiQkXGxlZnRbXHdpZGVoYXR7XHRleHR7QVJEfX0tel97XGFscGhhLzJ9XHRleHR7U0V9X3tcd2lkZWhhdHtcdGV4dHtBUkR9fX0sXHdpZGVoYXR7XHRleHR7QVJEfX0tel97XGFscGhhLzJ9XHRleHR7U0V9X3tcd2lkZWhhdHtcdGV4dHtBUkR9fX1ccmlnaHRdJCQKb3IKJCRcbGVmdFtcZnJhY3tmLWd9e259LVxmcmFje3pfe1xhbHBoYS8yfX17bn1cc3FydHtmK2ctXGZyYWN7KGYtZyleMn17bn19LFxmcmFje2YtZ317bn0rXGZyYWN7el97XGFscGhhLzJ9fXtufVxzcXJ0e2YrZy1cZnJhY3soZi1nKV4yfXtufX1ccmlnaHRdICQkCgotLS0KCmBgYHtyfQpoYW1zdGVyIDwtIG1hdHJpeChjKDMsIDE3LCAxLCAxMyksIG5jb2wgPSAyLCBieXJvdyA9IFRSVUUpCnJvd25hbWVzKGhhbXN0ZXIpIDwtIGMoImhvc3RpbGUtYWdyZXNzaXZlIiwgImhvc3RpbGUtbm9uLWFncmVzc2l2ZSIpCmNvbG5hbWVzKGhhbXN0ZXIpIDwtIGMoImZyaWVuZGx5LWFncmVzc2l2ZSIsICJmcmllbmRseS1ub24tYWdyZXNzaXZlIikKCmYgPC0gaGFtc3RlclsxLCAyXQpnIDwtIGhhbXN0ZXJbMiwgMV0KbiA8LSBzdW0oaGFtc3RlcikKcmlza2RpZmYgPC0gKGYgLSBnKSAvIG4Kcmlza2RpZmYKc2UgPC0gc3FydChmICsgZyAtIChmIC0gZyleMiAvIG4pIC8gbgpzZQpjaSA8LSByaXNrZGlmZiArIGMoLTEsIDEpICogcW5vcm0oMC45NzUpICogc2UKY2kKYGBgCgotLS0KClxiZWdpbntlcXVhdGlvbip9Clx3aWRlaGF0e1x0ZXh0e0FSRH19PVxmcmFjezE3LTF9ezM0fT0wLjQ3MQpcZW5ke2VxdWF0aW9uKn0KVGhlIGFic29sdXRlIHJpc2sgZGlmZmVyZW5jZSBvbiBjaG9vc2luZyBmb3IgYW4gYWdyZXNzaXZlIG1hbGUgaXMgNDcuMSUgbGFyZ2VyIHVwb24gc3RheWluZyBpbiBhIGhvc3RpbGUgZW52aXJvbm1lbnQgdGhhdCB3aGVuIHJlc2lkaW5nIGluIGEgZ2VudGxlIGVudmlyb25tZW50LgotIFRoZSBzdGFuZGFyZCBlcnJvcgpcYmVnaW57ZXF1YXRpb24qfQpcdGV4dHtTRX1fe1x3aWRlaGF0e1x0ZXh0e0FSRH19fT1cZnJhY3sxfXszNH1cc3FydHsxNysxLVxmcmFjeygxNy0xKV4yfXszNH19PTAuMDk1MgpcZW5ke2VxdWF0aW9uKn0KLSBBIDk1XCUgY29uZmlkZW5jZSBpbnRlcnZhbCBvbiB0aGlzIGFic29sdXRlIHJpc2sgZGlmZmVyZW5jZSBpcwpcYmVnaW57ZXF1YXRpb24qfQpcbGVmdFswLjQ3MS0xLjk2XHRpbWVzIDAuMDk1MiwwLjQ3MSsxLjk2XHRpbWVzIDAuMDk1MlxyaWdodF09WzAuMjg0LDAuNjU4XQpcZW5ke2VxdWF0aW9uKn0KCi0tLQoKIyMgTWNOZW1hciB0ZXN0CmBgYHtyLGVjaG89RkFMU0V9CmtuaXRyOjprYWJsZShoYW1zdGVyVG90LCBib29rdGFicyA9IFRSVUUpCmBgYAoKLSBBc3Nlc3MgaWYgcmlzayBvbiBjaG9pY2UgZm9yIGFncmVzc2l2ZSBtYWxlIGRpZmZlcnMgYmV0d2VlbiByZXNpZGluZyBpbiBob3N0aWxlIGFuZCBmcmllbmRseSBlbnZpcm9ubWVudC4KLSBPbmx5IGRpc2NvcmRhbnQgcGFpcnMgZ2l2ZSBpbmZvcm1hdGlvbi4KLSAkZj5nJCBpbmRpY2F0aW9uIGFnYWluc3QgJEhfMCQ6IGNob2ljZSBvZiBwYXJ0bmVyIG5vdCBhc3NvY2lhdGVkIHdpdGggZW52aXJvbm1lbnQuCi0gRXZhbHVhdGUgcHJvYmFiaWxpdHkgdGhhdCBpbiBhIHJhbmRvbSBkaXNjb3JkYW50IHBhaXIsIGEgZmVtYWxlIGNob29zZXMgYW4gYWdyZXNzaXZlIG1hbGUgdXBvbiBhIHN0YXkgaW4gYSBob3N0aWxlIGVudmlyb25tZW50LgotIFdlIGVzdGltYXRlIHRoZSBwcm9iYWJpbGl0eSBhcwogICQkXGZyYWN7Zn17ZitnfSQkCgotLS0KCiAgXGJlZ2lue2VxbmFycmF5Kn0KICBcdGV4dHtFfVxsZWZ0W2YvKGYrZylccmlnaHRdJlxzdGFja3JlbHtIXzB9ez19JiAwLjVcXAogIGYgJiBcc3RhY2tyZWx7SF8wfXtcc2ltfSYgXHRleHR7Qmlub219KG49ZitnLFxwaT0wLjUpXFwKICBcdGV4dHtTRX1fe1xmcmFje2Z9e2YrZ319ICYgXHN0YWNrcmVse0hfMH17PX0mIFxzcXJ0eyhmK2cpXHRpbWVzIDAuNVx0aW1lcyAwLjV9PVxmcmFje1xzcXJ0e2YrZ319ezJ9ClxlbmR7ZXFuYXJyYXkqfQoKLS0tCgotIEFzeW1wdG90aWNhbGx5IGEgb25lLXNhbXBsZSB6LXRlc3QgKGJhc2VkIG9uIHRoZSBOb3JtYWwgZGlzdHJpYnV0aW9uKQoKXGJlZ2lue2VxdWF0aW9uKn0Kej1cZnJhY3tmLShmK2cpLzJ9e1xzcXJ0e2YrZ30vMn09XGZyYWN7Zi1nfXtcc3FydHtmK2d9fQpcZW5ke2VxdWF0aW9uKn0KCi0gTm9ybWFsIGFwcHJveGltYXRpb24gaXMgZ29vZCBpZiAkJGYgXHRpbWVzIGcvKGYrZykgXGdlcSA1JCQKClRoZSAqKk1jIE5lbWFyIHRlc3QqKiBpcyB0aGUgYW5hbG9nb24gb2YgdGhlIHBhaXJlZCB0LXRlc3QgZm9yIGJpbmFyeSBxdWFsaXRhdGl2ZSB2YXJpYWJsZXMuCgotLS0KCkluIFIgd2UgY2FuIGNvbmR1Y3QgdGhlIGFuYWx5c2lzIHVzaW5nIHRoZSAgYG1jbmVtYXIudGVzdGAgZnVuY3Rpb24KYGBge3J9Cm1jbmVtYXIudGVzdChoYW1zdGVyKQpgYGAKCgotIFdlIHJlamVjdCB0aGUgbnVsbCBoeXBvdGhlc2lzIGF0IHRoZSA1JSBzaWduaWZpY2FuY2UgbGV2ZWwKLSBXZSBjb25jbHVkZSB0aGF0IHRoZSBjaG9pY2Ugb2YgcGFydG5lciBpcyBleHRyZW1lbHkgc2lnbmlmaWNhbnRseSBhc3NvY2lhdGVkIHdpdGggdGhlIGVudmlyb25tZW50LgoKLS0tCgotIE5vcm1hbGUgYXBwcm94aW1hdGlvbiBpcyBub3Qgb3B0aW1hbCBhbmQgd2UgY2FuIHBlcmZvcm0gYW4gZXhhY3QgdGVzdCB1c2luZyB0aGUgYmlub21pYWwgdGVzdAoKYGBge3J9CmJpbm9tLnRlc3QoeCA9IGYsIG4gPSBmICsgZywgcCA9IDAuNSkKYGBgCgotLS0KCiMjIyBDb25jbHVzaW9uCgotIFdlIGNvbmNsdWRlIHRoYXQgdGhlIHBhcnRuZXIgY2hvaWNlIGlzIGV4dHJlbWVseSBzaWduZmljYW50bHkgYXNzb2NpYXRlZCB3aXRoIHRoZSBlbnZpcm9ubWVudCAoJHA8MC4wMDEkKS4KLSBUaGUgcHJvYmFiaWxpdHkgb24gY2hvb3NpbmcgYW4gYWdyZXNzaXZlIG1hbGUgaXMgb24gYXZlcmFnZSBgciBmb3JtYXQocmlza2RpZmYqMTAwLGRpZ2l0cz0zKWAlIGhpZ2hlciB3aGVuIGEgZmVtYWxlIGhhbXN0ZXIgcmVzaWRlcyBpbiBhIGhvc3RpbGUgZW52aXJvbm1lbnQgdGhhbiB3aGVuIHNoZSByZXNpZGVzIGluIGEgZnJpZW5kbHkgZW52aXJvbm1lbnQgKDk1JSBDSSBbYHIgcGFzdGUoZm9ybWF0KGNpKjEwMCxkaWdpdHM9MyksY29sbGFwc2U9IiwiKWBdJSkuCgotLS0KCiMgVW5wYWlyZWQgb2JzZXJ2YXRpb25zCiMjIEdlbmV0aWMgYXNzb2NpYXRpb24gc3R1ZHkKCi0gQXJlIGdlbmV0aWMgcG9seW1vcnBoaXNtcyBpbiB0aGUgQlJDQTEgZ2VuZSBhc3NvY2lhdGVkIHdpdGggYnJlYXN0IGNhbmNlcj8KLSBSZXRyb3NwZWN0aXZlIGNhc2UtY29udHJvbCBzdHVkeSB3aXRoIDgwMCBicmVhc3QgY2FuY2VyIGNhc2VzIGVuIDU3MiBjb250cm9scwoKYGBge3J9CmJyY2EgPC0gcmVhZF9jc3YoImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9HVFBCL1BTTFMyMC9tYXN0ZXIvZGF0YS9icmNhLmNzdiIpCmhlYWQoYnJjYSkKc3VtbWFyeShicmNhKQpgYGAKCi0tLQoKYGBge3IgZWNobz1GQUxTRX0KYnJjYUhscCA8LSBkYXRhLmZyYW1lKEdlbm90eXBlID0gYygiUHJvL1BybyIsICJQcm8vTGV1IiwgIkxldS9MZXUiLCAiVG90YWFsIiksIENvbnRyb2wgPSBjKCIyNjYgKGEpIiwgIjI1MCAoYikiLCAiNTYgKGMpIiwgIjU3MiAoYStiK2MpIiksIENhc2VzID0gYygiMzQyIChkKSIsICIzNjkgKGUpIiwgIjg5IChmKSIsICI4MDAgKGQrZStmKSIpLCBUb3RhbCA9IGMoIjYwOCAoYStkKSIsICI2MTkgKGIrZSkiLCAiMTQ1IChjK2YpIiwgIjEzNzIgKG4pIikpCmtuaXRyOjprYWJsZShicmNhSGxwLAogIGJvb2t0YWJzID0gVFJVRQopCmBgYAoKLSBJbiBjYXNlLWNvbnRyb2wgc3R1ZHkgb25lIGNob29zZXMgYSBmaXhlZCBudW1iZXIgb2YgY2FzZXMgYW5kIGNvbnRyb2xzIGFuZCByZWdpc3RlcnMgd2hpY2ggZXhwb3N1cmVzIHRoZXkgaGFkIGluIHRoZSBwYXN0LgotIFJldHJvc3BlY3RpdmUgc3R1ZHkKLSBJbXBvc3NpYmxlIHRvIGFzc2VzcyByaXNrcyBhbmQgcmlzay1kaWZmZXJlbmNlcyBvbiBicmVhc3QgY2FuY2VyIGJlY2F1c2UgdGhlIHByb3BvcnRpb24gb2YgY2FzZXMgYW5kIGNvbnRyb2xzIGRvZXMgbm90IHJlZmxlY3QgdGhhdCBpbiB0aGUgcG9wdWxhdGlvbiEKCi0tLQoKYGBge3IsIHRpZHk9RkFMU0UsZWNobz1GQUxTRX0KYnJjYUhscD1kYXRhLmZyYW1lKEdlbm90eXBlPWMoIlByby9Qcm8iLCJQcm8vTGV1IiwiTGV1L0xldSIsIlRvdGFhbCIpLENvbnRyb2xzPWMoIjI2NiAoYSkiLCIyNTAgKGIpIiwiNTYgKGMpIiwiNTcyIChhK2IrYykiKSxDYXNlcz1jKCIzNDIgKGQpIiwiMzY5IChlKSIsIjg5IChmKSIsIjgwMCAoZCtlK2YpIiksVG90YWw9YygiNjA4IChhK2QpIiwiNjE5IChiK2UpIiwiMTQ1IChjK2YpIiwiMTM3MiAobikiKSkKa25pdHI6OmthYmxlKGJyY2FIbHAsCiAgYm9va3RhYnMgPSBUUlVFCikKYGBgCgotIElzIHBvc3NpYmxlIHRvIGFzc2VzcyBwcm9iYWJpbGl0eSBvbiBhbGxlbCBMZXUvTGV1CiAgICAtIGNhc2VzOiAkXHBpXzE9Zi8oZCtlK2YpPTg5LzgwMD0xMS4xXCUkCiAgICAtIGNvbnRyb2xzOiRccGlfMD1jLyhhK2IrYyk9NTYvNTcyPTkuOFwlJAotIFJlbGF0aXZlIHJpc2sgb24gZXhwb3N1cmUgZm9yIGNhc2VzIHZlcnN1cyBjb250cm9scyBpcyAkMTEuMS85Ljg9MS4xNCQuCi0gVGhlIHByb2JhYmlsaXR5IG9uIHRoZSBMZXUvTGV1IGdlbm90eXBlIGlzIDE0JSBoaWdoZXIgZm9yIHdvbWVuIHdpdGggYnJlYXN0IGNhbmNlciB0aGFuIGZvciB3b21lbiB3aXRob3V0IGJvcnN0a2Fua2VyLgotIEl0IHN1Z2dlc3RzIGFuIGFzc29jaWF0aW9uLCBidXQgaXQgZG9lcyBub3QgbGV0IHVzIGNvbmNsdWRlIGhvdyBtdWNoIGhpZ2hlciB0aGUgcmlzayBpcyBvbiBicmVhc3QgY2FuY2VyIGZvciB3b21lbiB3aXRoIHRoZSBMZXUvTGV1IGdlbm90eXBlIGFzIGNvbXBhcmVkIHRvIHRoZSBvdGhlciB3b21lbi4KLSBPdGhlciBzdGF0aXN0aWM/CgotLS0KClxiZWdpbntlcXVhdGlvbip9Ck9kZHM9XGZyYWN7cH17MS1wfQpcZW5ke2VxdWF0aW9uKn0Kd2l0aCAkcCQgdGhlIHByb2JhYmlsaXR5IG9uIHRoZSBldmVudC4KClRyYW5zZm9ybWF0aW9uIG9mIHJpc2sgd2l0aCBmb2xsb3dpbmcgcHJvcGVydGllczoKCiAgLSBvZGRzIGhhcyB2YWx1ZSBiZXR3ZWVuIDEgYW5kICRcaW5mdHkkLgoKICAtIG9kZHMgb25seSBlcXVhbHMgMSBmb3IgcHJvYmFiaWxpdHkgJHA9MS8yJC4KCiAgLSBkZSBvZGRzIGluY3JlYXNlcyBpZiBwcm9iYWJpbGl0eSBpbmNyZWFzZXMuCgotIHBvcHVsYXIgaW4gZ2FtYmxpbmc6IGhvdyBtdWNoIG1vcmUgbGlrZWx5IGlzIGl0IHRvIHdpbiB0aGFuIHRvIGxvb3NlCgotLS0KCmBgYHtyLCB0aWR5PUZBTFNFLGVjaG89RkFMU0V9CmJyY2FIbHA9ZGF0YS5mcmFtZShHZW5vdHlwZT1jKCJQcm8vUHJvIiwiUHJvL0xldSIsIkxldS9MZXUiLCJUb3RhYWwiKSxDb250cm9scz1jKCIyNjYgKGEpIiwiMjUwIChiKSIsIjU2IChjKSIsIjU3MiAoYStiK2MpIiksQ2FzZXM9YygiMzQyIChkKSIsIjM2OSAoZSkiLCI4OSAoZikiLCI4MDAgKGQrZStmKSIpLFRvdGFsPWMoIjYwOCAoYStkKSIsIjYxOSAoYitlKSIsIjE0NSAoYytmKSIsIjEzNzIgKG4pIikpCmtuaXRyOjprYWJsZShicmNhSGxwLAogIGJvb2t0YWJzID0gVFJVRQopCmBgYAoKT2RkcyBvbiBhbGxlbCBMZXUvTGV1CgotIENhc2VzOiAkXG1ib3h7b2Rkc31fMT1cZnJhY3sgZi8oZCtlK2YpfXsoZCtlKS8oZCtlK2YpfT1mLyhkK2UpPTg5LzcxMT0wLjEyNSQuIFRoZSBkb3VibGUgTGV1L0xldSB2YXJpYW50IGlzIDggdGltZXMgbGVzcyBsaWtlbHkgdGhhbiBvdGhlciBhbGxlbGUgY29tYmluYXRpb25zIGluIHRoZSBicmVhc3QgY2FuY2VyIGNhc2VzCi0gQ29udHJvbHM6ICRcbWJveHtvZGRzfV8yPWMvKGErYik9NTYvNTE2PTAuMTA5JC4KCi0gQXNzb2NpYXRpb24gYmV0d2VlbiBleHBvc3VyZSBhbmQgb3V0Y29tZToKJCQKT1Jfe0xldS9MZXV9PVxmcmFje1xtYm94e29kZHN9X1R9e1xtYm94e29kZHN9X0N9PSBcZnJhY3tmLyhkK2UpfXtjLyhhK2IpfT1cZnJhY3tmLyhkK2UpfXtjLyhhK2IpfT0xLjE1CiQkCgotLS0KCgpgYGB7ciwgdGlkeT1GQUxTRSxlY2hvPUZBTFNFfQpicmNhSGxwPWRhdGEuZnJhbWUoR2Vub3R5cGU9YygiUHJvL1BybyIsIlByby9MZXUiLCJMZXUvTGV1IiwiVG90YWFsIiksQ29udHJvbHM9YygiMjY2IChhKSIsIjI1MCAoYikiLCI1NiAoYykiLCI1NzIgKGErYitjKSIpLENhc2VzPWMoIjM0MiAoZCkiLCIzNjkgKGUpIiwiODkgKGYpIiwiODAwIChkK2UrZikiKSxUb3RhbD1jKCI2MDggKGErZCkiLCI2MTkgKGIrZSkiLCIxNDUgKGMrZikiLCIxMzcyIChuKSIpKQprbml0cjo6a2FibGUoYnJjYUhscCwKICBib29rdGFicyA9IFRSVUUKKQpgYGAKCi0gSWYgdGhlIHN0dWR5IHdvdWxkIGhhdmUgYmVlbiBhIHJhbmRvbSBzYW1wbGUgb2YgdGhlIHBvcHVsYXRpb24gKG51bWJlciBvZiBjYXNlcyBhbmQgY29udHJvbHMgbm90IGZpeGVkIGJ5IGRlc2lnbikgdGhlbiB3ZSB3b3VsZCBiZSBhYmxlIHRvIGNhbGN1bGF0ZSB0aGUgb2RkcyByYXRpbyBvbiBicmVhc3QgY2FuY2VyIGZvciBwZW9wbGUgd2l0aCBhbmQgd2l0aG91dCB0aGUgZG91YmxlIExldS9sZXUgdmFyaWFudC4KXGJlZ2lue2VxdWF0aW9uKn0KT1Jfe2Nhc2V9PVxmcmFjeyBcZnJhY3sgZn17Y319eyBcZnJhY3soZCtlKX17KGErYil9fSA9IFxmcmFje2YoYStiKX17YyhkK2UpfT1PUl97TGV1L0xldX09MS4xNSwKXGVuZHtlcXVhdGlvbip9Ci0gT1IgaXMgYSBzeW1tZXRyaWMgc3RhdGlzdGljIQotIE9SIG9uIGJvcnN0Y2FuY2VyIGNhbiBiZSBlc3RpbWF0ZWQhCi0gVGhlIG9kZHMgb24gYm9yc3RjYW5jZXIgaXMgMTUlIGhpZ2hlciBmb3Igd29tZW4gd2l0aCB0aGlzIHNwZWNpZmljIGFsbGVsZSBjb21iaW5hdGlvbi4KCi0tLQoKLSBJcyB0aGUgZGlmZmVyZW5jZSBsYXJnZSBlbm91Z2ggdG8gZ2VuZXJhbGl6ZSB0aGUgZWZmZWN0IGluIHRoZSBzYW1wbGUgdG93YXJkcyB0aGUgcG9wdWxhdGlvbj8KCi0gV2Ugd2lsbCBmaXJzdCByZXdyaXRlIHRoZSBkYXRhIGluIGEgMngyIHRhYmxlCgpgYGB7ciBsZXU0LCB0aWR5PUZBTFNFLGVjaG89RkFMU0V9CmJyY2FUYWIyIDwtIHRhYmxlKGJyY2EkdmFyaWFudDIsYnJjYSRjYW5jZXIpCmJyY2FUYWIyIDwtIGJyY2FUYWIyWzI6MSxdCmJyY2FIbHAyIDwtIGRhdGEuZnJhbWUoR2Vub3R5cGU9Yygib3RoZXIiLCJMZXUvTGV1IiwiVG90YWwiKSxDb250cm9scz1jKCI1MTYgKGEpIiwiNTYgKGIpIiwiNTcyIChhK2IpIiksQ2FzZXM9YygiNzExIChjKSIsIjg5IChkKSIsIjgwMCAoYytkKSIpLFRvdGFhbD1jKCIxMjI3IChhK2MpIiwiMTQ1IChiK2QpIiwiMTM3MiAobikiKSkKa25pdHI6OmthYmxlKGJyY2FIbHAyLAogIGJvb2t0YWJzID0gVFJVRQopCmBgYAoKLS0tCgojIyBQZWFyc29uIENoaS1zcXVhcmUgdGVzdCBmb3IgaW5kZXBlbmRlbnQgc2FtcGxlcwoKLSBUZXN0IGFzc29jaWF0aW9uIGJldHdlZW4gY2F0ZWdvcmljYWwgZXhwb3N1cmUoZS5nLiB2YXJpYW50LCBYKSBlbiBjYXRlZ29yaWNhbCByZXNwb25zZSAoZS5nLiBkaXNlYXNlLCBZKS4KJCRIXzA6IFx0ZXh0e1RoZXJlIGlzIG5vIGFzc29jaWF0aW9uIGJldHdlZW4gfSBYIFx0ZXh0eyBhbmQgfSBZIFx0ZXh0eyB2cyB9IEhfMTogWCBcdGV4dHsgYW5kIH0gWSBcdGV4dHsgYXJlIGFzc29jaWF0ZWR9JCQKCi0gQ29uc2lkZXIgcm93IHRvdGFscyAkbl9cdGV4dHtvdGhlcn09YStjJCwgJG5fXHRleHR7bGV1LGxldX09YitkJCBhbmQKLSBjb2x1bW4gdG90YWxzICRuX1x0ZXh0e2NvbnRyfT1hK2IkIGVuICRuX1x0ZXh0e2Nhc2V9PWMrZCQuCi0gVGhleSBnaXZlIGluZm9ybWF0aW9uIG9uICptYXJnaW5hbCBkaXN0cmlidXRpb24qIG9mIHRoZSBleHBvc3VyZSAodmFyaWFudCwgWCkgYW5kIG91dGNvbWUgKGRpc2Vhc2UsIFkpLApidXQgbm90IG9uIHRoZSBhc3NvY2lhdGlvbiBiZXR3ZWVuIHRoZXNlIHZhcmlhYmxlcy4KLSBVbmRlciAkSF8wJCAkWCQgYW5kICRZJCBhcmUgaW5kZXBlbmRlbnQgYW5kIG9uZSBleHBlY3RzICB0aGF0ICQoYitkKS9uJApvZiB0aGUgJGErYiQgY29udHJvbHMgaGF2ZSBhIExldS9MZXUgdmFyaWFudCwgb3IgdGhhdCAkKGErYikoYitkKS9uJCBvZiB0aGVtIGhhcyBhIExldS9MZXUgdmFyaWFudAotIFdlIGNhbiBjYWxjdWxhdGUgdGhpcyBleHBlY3RlZCBudW1iZXIgJEVfe2lqfSQgdW5kZXIgdGhlIG51bGwgaHlwb3RoZXNpcyBmb3IgKmVhY2ggY2VsbCogb2YgdGhlICQyClx0aW1lcyAyJCB0YWJsZS4KCi0tLQoKLSAkRV97MTF9JCA9IEV4cGVjdGVkIG51bWJlciB1bmRlciAkSF8wJCBpbiAgKDEsMSktY2VsbCA9IGByIHN1bShicmNhVGFiMlsxLF0pYCAkXHRpbWVzJCBgciBzdW0oYnJjYVRhYjJbLDFdKWAvYHIgc3VtKGJyY2FUYWIyKWAgPSBgciBmb3JtYXQoc3VtKGJyY2FUYWIyWzEsXSkqc3VtKGJyY2FUYWIyWywxXSkvc3VtKGJyY2FUYWIyKSxkaWdpdHM9NClgIDsKCi0gJEVfezEyfSQgPSBFeHBlY3RlZCBudW1iZXIgdW5kZXIgJEhfMCQgaW4gICgxLDIpLWNlbGwgPSBgciBzdW0oYnJjYVRhYjJbMSxdKWAgJFx0aW1lcyQgYHIgc3VtKGJyY2FUYWIyWywyXSlgL2ByIHN1bShicmNhVGFiMilgID0gYHIgZm9ybWF0KHN1bShicmNhVGFiMlsxLF0pKnN1bShicmNhVGFiMlssMl0pL3N1bShicmNhVGFiMiksZGlnaXRzPTQpYCA7CgotICRFX3syMX0kID0gRXhwZWN0ZWQgbnVtYmVyIHVuZGVyICRIXzAkIGluICAoMiwxKS1jZWxsID0gYHIgc3VtKGJyY2FUYWIyWzIsXSlgICRcdGltZXMkIGByIHN1bShicmNhVGFiMlssMV0pYC9gciBzdW0oYnJjYVRhYjIpYCA9IGByIGZvcm1hdChzdW0oYnJjYVRhYjJbMixdKSpzdW0oYnJjYVRhYjJbLDFdKS9zdW0oYnJjYVRhYjIpLGRpZ2l0cz00KWAgOwoKLSAkRV97MjJ9JCA9IEV4cGVjdGVkIG51bWJlciB1bmRlciAkSF8wJCBpbiAgKDIsMiktY2VsbCA9IGByIHN1bShicmNhVGFiMlsyLF0pYCAkXHRpbWVzJCBgciBzdW0oYnJjYVRhYjJbLDJdKWAvYHIgc3VtKGJyY2FUYWIyKWAgPSBgciBmb3JtYXQoc3VtKGJyY2FUYWIyWzIsXSkqc3VtKGJyY2FUYWIyWywyXSkvc3VtKGJyY2FUYWIyKSxkaWdpdHM9NClgIDsKClRlc3Qtc3RhdGlzdGljOgpcYmVnaW57ZXFuYXJyYXkqfQpYXjIgJj0mIFxmcmFje1xsZWZ0ICh8T197MTF9IC0gRV97MTF9fCAtIC41IFxyaWdodCleMiB9eyBFX3sxMX19ICsgXGZyYWN7ClxsZWZ0ICggfE9fezEyfSAtIEVfezEyfXwgLSAuNSBccmlnaHQpXjIgfXtFX3sxMn0gfSsgXFwKJiZccXVhZFxxdWFkClxmcmFjeyBcbGVmdCAoIHxPX3syMX0KLSBFX3syMX18IC0gLjUgXHJpZ2h0KV4yIH17RV97MjF9fSsgXGZyYWN7IFxsZWZ0ICggfE9fezIyfSAtIEVfezIyfXwgLSAuNQpccmlnaHQpXjIgfXtFX3syMn0gfVxcCiBYXjIgJlxzdGFja3JlbHtIXzB9e1xsb25ncmlnaHRhcnJvd30mIFxjaGleMihkZj0xKQpcZW5ke2VxbmFycmF5Kn0KCi0tLQoKYGBge3IgZWNobz1GQUxTRX0KZ3JpZCA8LSBzZXEoMCwgMTAsIC4xKQpwbG90KGdyaWQsIGRjaGlzcShncmlkLCAxKSwgdHlwZSA9ICJsIiwgbHdkID0gMikKZGZzIDwtIGMoMSwgMiwgNSkKZm9yIChpIGluIDI6MykgewogIGxpbmVzKGdyaWQsIGRjaGlzcShncmlkLCBkZnNbaV0pLCBjb2wgPSBpLCBsd2QgPSAyKQp9CmxlZ2VuZCgidG9wcmlnaHQiLCBsdHkgPSAxLCBsd2QgPSAyLCBjb2wgPSAxOjMsIGxlZ2VuZCA9IHNhcHBseShkZnMsIGZ1bmN0aW9uKGQpIGFzLmV4cHJlc3Npb24oc3Vic3RpdHV0ZShjaGlbZGYgPT0gdmFsXV4yLCBsaXN0KHZhbCA9IGQpKSkpKQpgYGAKCi0tLQoKLSBBIGxhcmdlIHZhbHVlIG9mIHRoZSB0ZXN0IHN0YXRpc3RpYyBnaXZlcyBhbiBpbmRpY2F0aW9uIHRoYXQgdGhlIG51bGwgaHlwb3RoZXNpcyBpcyBmYWxzZS4KLSBUaGUgdGVzdCB3aWxsIHJlamVjdCAkSF8wJCBhdCB0aGUgJFxhbHBoYSAxMDBcJSQKc2lnbmlmaWNhbmNlIGxldmVsIGFzIHNvb24gYXMgdGhlIG9ic2VydmVkIHRlc3Qtc3RhdGlzdGljIGlzIGxhcmdlciB0aGFuIHRoZSAkMTAwXCUoMS1cYWxwaGEpJC1xdWFudGlsZSwgJFxjaGleMl97MSwKXGFscGhhfSQsIG9mIHRoZSAkXGNoaV4yXzEkLWRpc3RyaWJ1dGlvbi4KLSBPdGhlcndpc2Ugd2UgZG8gbm90IHJlamVjdCAkSF8wJC4KLSBUaGUgcC12YWx1ZSBvZiBhIDItc2lkZWQgdGVzdCBpcyB0aGUgcHJvYmFiaWxpdHkgdG8gb2JzZXJ2ZSBhIGxhcmdlciB0ZXN0LXN0YXRpc3RpYyBpbiBhIHJhbmRvbSBzYW1wbGUgdW5kZXIgdGhlIG51bGwgdGhhbiB3aGF0IHdlIG9ic2VydmVkIGluIG91ciBzYW1wbGUuCiQkcD1QXzBbXGNoaV4yXzEgXGdlcSB4XjJdJCQuCgotLS0KCmBgYHtyfQpleHBlY3RlZCA8LSBtYXRyaXgoMCwgbnJvdyA9IDIsIG5jb2wgPSAyKQpmb3IgKGkgaW4gMToyKSB7CiAgZm9yIChqIGluIDE6MikgewogICAgZXhwZWN0ZWRbaSwgal0gPC0KICAgICAgc3VtKGJyY2FUYWIyW2ksIF0pICogc3VtKGJyY2FUYWIyWywgal0pIC8gc3VtKGJyY2FUYWIyKQogIH0KfQpleHBlY3RlZAp4MiA8LSBzdW0oKGFicyhicmNhVGFiMiAtIGV4cGVjdGVkKSAtIC41KV4yIC8gZXhwZWN0ZWQpCjEgLSBwY2hpc3EoeDIsIDEpCmBgYAoKLS0tCgotIEJlY2F1c2UgJE9fe2lqfSQgYXJlIGRpc2NyZXRlIHZhbHVlcywgdGhlICRYXjIkIGNhbiBvbmx5IHRha2UgZGlzY3JldGUgdmFsdWVzIGFuZCB0aGUgY29udGludW91c3MgJFxjaGleMl8xJC1kaXN0cmlidXRpb24gaXMgb25seSBhbiBhcHByb3hpbWF0aW9uIG9mIHRoZSByZWFsIGRpc3RyaWJ1dGlvbi4KLSBUbyBpbXByb3ZlIHRoZSBhcHByb3hpbWF0aW9uIG9uZSBzdWJzdHJhY3RzIDAuNSBmcm9tIHRoZSB2YWx1ZSBpbiBlYWNoIGNlbGw6Cipjb250aW51aXR5LWNvcnJlY3Rpb24qCi0gV2UgcmVmZXIgdG8gdGhpcyB0ZXN0IGFzICpQZWFyc29uIENoaS1zcXVhcmVkIHRlc3Qgd2l0aCBZYXRlcyBjb3JyZWN0aW9uKi4KLSBXaGVuIHRoZSBjb3JyZWN0aW9uIGlzIG5vdCB1c2VkIChpLmUuIHdoZW4gdGhlIHZhbHVlcyBvZiBgMC41JyBpbiB0aGUgZXN0aW1hdG9yICRYXjIkIGFyZSByZXBsYWNlZCkgd2UgdXNlIHRoZSAqUGVhcnNvbiBDaGktc3F1YXJlZCB0ZXN0Ki4KCi0tLQoKSW4gUiB5b3UgY2FuIHN3aXRjaCB0aGUgY29ycmVjdGlvbiBvbiBvciBvZmYgYnkgc2V0dGluZyB0aGUgYXJndW1lbnQgYGNvcnJlY3RgIG9uIFRSVUUgb3IgRkFMU0UsIHJlc3BlY3RpdmVseToKCmBgYHtyfQpjaGlzcS50ZXN0KGJyY2FUYWIyKQpjaGlzcS50ZXN0KGJyY2FUYWIyLCBjb3JyZWN0ID0gRkFMU0UpCmBgYAoKLS0tCgotIEV2ZW4gd2l0aCB0aGUgJFxjaGleMl8xJCBjb3JyZWN0aW9uIHRoZSBhcHByb3hpbWF0aW9uIGlzIG9ubHkgdmFsaWQgaWYgbm9uIG9mIHRoZSBjZWxscyBoYXMgYW4gZXhwZWN0ZWQgY291bnQgYmVsb3cgNSB1bmRlciAkSF8wJC4KLSBXaGVuIHRoZSAkXGNoaV4yJC1hcHByb3hpbWF0aW9uIGlzIGludmFsaWQgd2Ugd2lsbCB1c2UgKkZpc2hlcidzIGV4YWN0IHRlc3QqLgotICBOdWxsIGh5cG90aGVzaXMgaXMgYWxzbyB0aGF0ICRYJCBhbmQgJFkkIGFyZSBpbmRlcGVuZGVudCwgYW5kLCB0aGUgYWx0ZXJuYXRpdmUgaHlwb3RoZXNpcyB0aGF0ICRYJCBhbmQgJFkkIGFyZSBkZXBlbmRlbnQuCgpgYGB7cn0KZmlzaGVyLnRlc3QoYnJjYVRhYjIpCmBgYAoKLS0tCgoKIyMgRXh0ZW5zaW9uIHRvIGNhdGVnb3JpY2FsIHZhcmlhYmxlcyB3aXRoIG11bHRpcGxlIGxldmVscwoKLSBUaGUgJFxjaGleMiQtdGVzdCBjYW4gYWxzbyBiZSB1c2VkIGlmIG9uZSBvZiB0aGUgY2F0ZWdvcmljYWwgdmFyaWFibGVzICRYJCBhbmQgJFkkIGhhcyBtb3JlIHRoYW4gMiBsZXZlbHMKCi0gQWdhaW46IHRoZSBudWxsIGh5cG90aGVzaXMgJEhfMCQ6ICRYJCBhbmQgJFkkIGFyZSBpbmRlcGVuZGVudCAobm90IGFzc29jaWF0ZWQpLCBhZ2FpbnN0IHRoZSBhbHRlcm5hdGl2ZSAkSF9BOiBYJCBhbmQgJFkkCmFyZSBhc3NvY2lhdGVkLgoKLSBMZXQgdGhlIHZhcmlhYmxlIGluIHRoZSByb3dzIGhhdmUgJHIkIGRpZmZlcmVudCBwb3NzaWJsZSBvdXRjb21lcyBhbmQgdGhlIG9uZSBpbiB0aGUgY29sdW1ucyAkYyQgcG9zc2libGUgb3V0Y29tZXMsIHRoZW4gd2Ugb2J0YWluIGFuICRyIFx0aW1lcyBjJCB0YWJsZS4KCi0gQWdhaW4gd2Ugd2lsbCBjb21wYXJlIHRoZSBvYnNlcnZlZCB2YWx1ZXMgaW4gIGNlbGwgJChpLGopJCwgcmVmZXJyZWQgdG8gYXMgJE9fe2lqfSQsIHdpdGggdGhlIGV4cGVjdGVkIG51bWJlciB1bmRlciAkSF8wJCwgJEVfe2lqfSQKIC0gQWdhaW4gJEVfe2lqfSQgaXMgdGhlIHByb2R1Y3Qgb2YgdGhlICRpXlx0ZXh0e3RofSQgcm93LXRvdGFsIGFuZCB0aGUgJGpeXHRleHR7dGh9JCBjb2x1bW4gdG90YWwgZGV2aWRlZCBieSB0aGUgb3ZlcmFsbCB0b3RhbC4KClxiZWdpbntlcXVhdGlvbip9ClheMiA9IFxzdW1fe2lqfSBcZnJhY3tcbGVmdCAoT197aWp9IC0gRV97aWp9XHJpZ2h0KV4yIH17IEVfe2lqfX0KXGVuZHtlcXVhdGlvbip9CgotLS0KCi0gV2UgY2FuIHNob3cgdGhhdCB0aGUgc3RhdGlzdGljIGZvbGxvd3MgYSAkXGNoaV4yJCBkaXN0cmlidXRpb24gd2l0aCAkKHItMSkgXHRpbWVzCihjLTEpJCBkZWdyZWVzIG9mIGZyZWVkb20gdW5kZXIgJEhfMCQuCi0gTm8gY29udGludWl0eSBjb3JyZWN0aW9uCi0gKipQZWFyc29uICRcY2hpXjIkIHRlc3QqKiBpcyBhbmFsb2dvbiBvZiBvbmUtd2F5IEFOT1ZBIGZvciBxdWFsaXRhdGl2ZSB2YXJpYWJsZXMuCgotLS0KCgpgYGB7cn0KYnJjYVRhYiA8LSB0YWJsZShicmNhJHZhcmlhbnQsIGJyY2EkY2FuY2VyKQpjaGlzcS50ZXN0KGJyY2FUYWIpCmBgYAoKLSBUbyBhc3Nlc3MgaWYgdGhlIHZhcmlhbnQgb2YgdGhlIEJSQ0ExIGdlbmUgaXMgYXNzb2NpYXRlZCB3aXRoIGJyZWFzdCBjYW5jZXIgd2UgY29uZHVjdGVkIGEgIFBlYXJzb24gJFxjaGleMiR0ZXN0IGZvciB0aGUgJDMgXHRpbWVzIDIkIHRhYmxlLgotIFRoZSBzdGF0aXN0aWMgaXMgbm93IGByIGZvcm1hdChjaGlzcS50ZXN0KGJyY2FUYWIpJHN0YXRpc3RpYyxkaWdpdHM9NClgIGFuZCBmb2xsb3dzIGEgJFxjaGleMiQgZGlzdHJpYnV0aW9uIHdpdGggYHIgY2hpc3EudGVzdChicmNhVGFiKSRwYXJhbWV0ZXJgIGRlZ3JlZXMgb2YgZnJlZWRvbSB1bmRlciAkSF8wJC4gVGhlIHByb2JhYmlsaXR5IHRvIG9idGFpbiBhICRcY2hpXjIkLXRlc3Qgc3RhdGlzdGljIGluIGEgcmFuZG9tIHNhbXBsZSB1bmRlciAkSF8wJCB0aGF0IGlzIG1vcmUgZXh0cmVtZSB0aGFuIGByIGZvcm1hdChjaGlzcS50ZXN0KGJyY2FUYWIpJHN0YXRpc3RpYyxkaWdpdHM9NClgLCBpcyBgciBmb3JtYXQoY2hpc3EudGVzdChicmNhVGFiKSRwLnZhbHVlKjEwMCxkaWdpdHM9MilgJS4KLSBPbiB0aGUgNSUgbGV2ZWwgb2Ygc2lnbmlmaWNhbmNlIHdlIGNvbmNsdWRlIHRoYXQgdGhlIHZhcmlhbnQgb2YgdGhlIEJSQ0EtZ2VuZSBpcyBub3QgYXNzb2NpYXRlZCB3aXRoIGJyZWFzdCBjYW5jZXIuCgotLS0KCiMgTG9naXN0aWMgcmVncmVzc2lvbgoKLSBGcmFtZXdvcmsgdG8gbW9kZWwgYmluYXJ5IGRhdGEgKGUuZyBjYW5jZXIgdnMgbm8gY2FuY2VyKTogKmxvZ2lzdGljIHJlZ3Jlc3Npb24gbW9kZWwqLgotIE1vZGVsIGJpbmFyeSBkYXRhIHdpdGggY29udGludW91cyBhbmQvb3IgZHVtbXkgdmFyaWFibGVzLgoKLSBUaGUgbW9kZWwgYXNzdW1lcyB0aGF0IG9ic2VydmF0aW9ucyBmb3Igc3ViamVjdCAkaT0xLFxsZG90cyxuJCBhcmUgaW5kZXBlbmRlbnQgYW5kIGZvbGxvdyBhIEJlcm5vdWxsaSBkaXN0cmlidXRpb24uCi0gVGhlIGxvZ2FyaXRobSBvZiB0aGUgb2RkcyBpcyBtb2RlbGxlZCB1c2luZyBhIGxpbmVhciBtb2RlbCwgYWxzbyByZWZlcnJlZCB0byBhcyBsaW5lYXIgcHJlZGljdG9yOgpcYmVnaW57ZXF1YXRpb259ClxsZWZ0XHsKXGJlZ2lue2FycmF5fXtjY2x9CllfaSZcc2ltJkIoXHBpX2kpXFxcXApcbG9nIFxmcmFje1xwaV9pfXsxLVxwaV9pfSY9JlxiZXRhXzAgKyBcYmV0YV8xWF97aTF9ICsgXGxkb3RzICsgXGJldGFfcCBYX3tpcH0KXGVuZHthcnJheX1ccmlnaHQuClxlbmR7ZXF1YXRpb259CgotLS0KCiMjIENhdGVnb3JpY2FsIHByZWRpY3RvcgoKLSBicmVhc3QgY2FuY2VyIGV4YW1wbGU6IGlzIEJSQ0EgMSAgdmFyaWFudCBhc3NvY2lhdGVkIHdpdGggYnJlYXN0IGNhbmNlci4KCi0gQXMgaW4gdGhlIEFub3ZhIGNvbnRleHQsIGEgZmFjdG9yIGluIGxvZ2lzdGljIHJlZ3Jlc3Npb24gaXMgY29kZWQgdXNpbmcgZHVtbXkgdmFyaWFibGVzLgotIDEgZHVtbXkgdmFyaWFibGUgbGVzcyB0aGFuIHRoZSBudW1iZXIgb2YgZ3JvdXBzLgoKLSBGb3IgQlJDQSAxIHdlIG5lZWQgdHdvIGR1bW15IHZhcmlhYmxlcyBhbmQgb2J0YWluIHRoZSBmb2xsb3dpbmcgbGluZWFyIHByZWRpY3RvcjoKClxiZWdpbntlcW5hcnJheSp9CiAgXGxvZyBcZnJhY3tccGlfaX17MS1ccGlfaX0gJj0mIFxiZXRhXzArXGJldGFfMSB4X3tpMX0gK1xiZXRhXzIgeF97aTJ9ClxlbmR7ZXFuYXJyYXkqfQoKLSB3aXRoIDoKJCR4X3tpMX0gPSBcbGVmdFx7IFxiZWdpbnthcnJheX17bGx9CjEgJiBcdGV4dHsgaWYgc3ViamVjdCAkaSQgaXMgaGV0ZXJvenlnb3VzLCBQcm8vTGV1IHZhcmlhbnR9IFxcCjAgJiBcdGV4dHtpZiBzdWJqZWN0ICRpJCBpcyBob21venlnb3VzLCAoUHJvL1BybyBvciBMZXUvTGV1IHZhcmlhbnQpfSBcZW5ke2FycmF5fVxyaWdodC4gLiQkCiQkeF97aTJ9ID0gXGxlZnRceyBcYmVnaW57YXJyYXl9e2xsfQoxICYgXHRleHR7IGlmIHN1YmplY3QgJGkkIGlzIGhvbW96eWdvdXMgaXMgdGhlIExldWNpbmUgbXV0YXRpb246IExldS9MZXUgfSBcXAowICYgXHRleHR7IG9mIHN1YmplY3QgJGkkIGlzIG5vdCBob21venlnb3VzIGluIHRoZSBMZXUvTGV1IHZhcmlhbnR9IFxlbmR7YXJyYXl9XHJpZ2h0LiAuJCQKCi0gSG9tb3p5Z29zaXR5IGluIHRoZSAgd2lsZCB0eXBlIGFsbGVsZSBQcm8vUHJvIGlzIHRoZSAgKipyZWZlcmVuY2UgZ3JvdXAqKi4KCi0tLQoKV2UgZml0IHRoZSBtb2RlbCBpbiBSLgoKLSBOb3RlIHRoYXQgd2UgdXNlIHRoZSBmdW5jdGlvbiBgYXMuZmFjdG9yYCB0byBjb252ZXJ0IHRoZSBjYW5jZXIgdmFyaWFibGUgdG8gYSBmYWN0b3IgdmFyaWFibGUuIC0gV2UgZnVydGhlciB1c2UgdGhlIGZ1bmN0aW9uIGByZWxldmVsYCB0byBzcGVjaWZ5IHRoZSBjb250cm9sIHRyZWF0bWVudCBhcyB0aGUgcmVmZXJlbmNlIGdyb3VwLgpgYGB7cn0KYnJjYSRjYW5jZXIgPC0gYnJjYSRjYW5jZXIgJT4lCiAgYXMuZmFjdG9yKCkgJT4lCiAgcmVsZXZlbCgiY29udHJvbCIpCmJyY2EkdmFyaWFudCA8LSBicmNhJHZhcmlhbnQgJT4lCiAgYXMuZmFjdG9yKCkgJT4lCiAgcmVsZXZlbCgicHJvL3BybyIpCmJyY2FMb2dpdCA8LSBnbG0oY2FuY2VyIH4gdmFyaWFudCwgZGF0YSA9IGJyY2EsIGZhbWlseSA9IGJpbm9taWFsKQpzdW1tYXJ5KGJyY2FMb2dpdCkKYGBgCgpUaGUgaW50ZXJjZXB0IGlzIHRoZSBsb2ctb2RkcyBvbiBjYW5jZXIgaW4gdGhlIHJlZmVyZW5jZSBjbGFzcyAoUHJvL1BybykgYW5kIHRoZSBzbG9wZSB0ZXJtcyBhcmUgIGxvZyBvZGRzIHJhdGlvcyBiZXR3ZWVuIHRyZWF0bWVudCBhbmQgcmVmZXJlbmNlIGNsYXNzOgpcYmVnaW57ZXFuYXJyYXkqfQpcbG9nIFx0ZXh0e09ERFN9X1x0ZXh0e1Byby9Qcm99Jj0mXGJldGFfMFxcXFwKXGxvZyBcdGV4dHtPRERTfV9cdGV4dHtQcm8vTGV1fSY9JlxiZXRhXzArXGJldGFfMVxcXFwKXGxvZyBcdGV4dHtPRERTfV9cdGV4dHtMZXUvTGV1fSY9JlxiZXRhXzArXGJldGFfMlxcXFwKXGxvZyAgXGZyYWN7XHRleHR7T0REU31fXHRleHR7UHJvL0xldX19e1x0ZXh0e09ERFN9X1x0ZXh0e1Byby9Qcm99fSY9Jlxsb2cgXHRleHR7T0REU31fXHRleHR7UHJvL0xldX0tXGxvZyBPRERTX3tQcm8vUHJvfVxcCiY9JlxiZXRhXzArXGJldGFfMS1cYmV0YV8wPVxiZXRhXzFcXFxcClxsb2cgIFxmcmFje1x0ZXh0e09ERFN9X1x0ZXh0e0xldS9MZXV9fXtcdGV4dHtPRERTfV9cdGV4dHtQcm8vUHJvfX0mPSZcYmV0YV8yClxlbmR7ZXFuYXJyYXkqfQoKLSBUaGUgYW5hbHlzaXMgYWxsb3dzIHVzIHRvIGludGVycHJldCB0aGUgcmVzdWx0IGltbWVkaWF0ZWx5IGluIG9kZHNlcyBhbmQgb2RkcyByYXRpb3MhCgotLS0KCmBgYHtyfQphbm92YShicmNhTG9naXQsIHRlc3QgPSAiQ2hpc3EiKQpgYGAKClRoZSAkXGNoaV4yJC10ZXN0IG9uIHRoZSBsb2dzaXRpYyByZWdyZXNzaW9uIG1vZGVsIGFsc28gaW5kaWNhdGVzIHRoYXQgdGhlcmUgaXMgbm8gc2lnbmlmaWNhbnQgYXNzb2NpYXRpb24gYmV0d2VlbiBjYW5jZXIgc3RhdHVzIGFuZCB0aGUgZ2VuZXRpYyB2YXJpYW50IG9mIHRoZSBCUkNBIGdlbmUgKCRwPSQgYHIgZm9ybWF0KGFub3ZhKGJyY2FMb2dpdCx0ZXN0PSJDaGlzcSIpWzIsIlByKD5DaGkpIl0sZGlnaXRzPTMpYCkuCkRlIHAtdmFsdWUgaXMgYWxtb3N0IGVxdWl2YWxlbnQgdG8gdGhlIG9uZSBvZiB0aGUgICRcY2hpXjIkLXRlc3QgKHNlZSBwcmV2aW91cyBzZWN0aW9uKS4KCi0tLQoKLSBTaWduaWZpY2FudCBhc3NvY2lhdGlvbj8KCiAgICAtIFBvc3QtaG9jIHRlc3RzIHRvIGV2YWx1YXRlIHdoaWNoIG9mIHRoZSBvZGRzIHJhdGlvcyBhcmUgZGlmZmVyZW50IGZyb20gMS4KICAgIC0gRm9yIEJSQ0ExIGV4YW1wbGUgd2UgZGlkIG5vdCByZWplY3QgdGhlIG9tbmlidXMgaHlwb3RoZXNpcyBzbyBubyBwb3N0LWhvYyBhbmFseXNpcwogICAgLSBGb3IgeW91ciByZWZlcmVuY2Ugd2UgaW5jbHVkZSB0aGUgcG9zdCBob2MgYW5hbHlzaXMgc28gdGhhdCB5b3Ugd291bGQgaGF2ZSB0aGUgY29kZS4KCi0tLQoKYGBge3J9CnN1cHByZXNzUGFja2FnZVN0YXJ0dXBNZXNzYWdlcyh7CiAgbGlicmFyeShtdWx0Y29tcCkKfSkKcG9zdGhvYyA8LSBnbGh0KGJyY2FMb2dpdCwgbGluZmN0ID0gbWNwKHZhcmlhbnQgPSAiVHVrZXkiKSkKcG9zdGhvY1Rlc3RzIDwtIHN1bW1hcnkocG9zdGhvYykKcG9zdGhvY1Rlc3RzCmBgYAoKLS0tCgpgYGB7cn0KcG9zdGhvY0NJIDwtIGNvbmZpbnQocG9zdGhvYykKcG9zdGhvY0NJCmBgYAotIFdpdGggdGhlIGBjb25maW50YCBmdW5jdGlvbiBDSSBhcmUgb2J0YWluZWQgb24gdGhlIGxvZy1vZGRzIHJhdGlvcyBjb3JyZWN0ZWQgZm9yIG11bHRpcGxlIHRlc3RpbmcuCgotLS0KCi0gQ0kncyBjYW4gYmUgYmFja3RyYW5zZm9ybWVkIHRvIG9kZHMgcmF0aW9zOgoKYGBge3J9Ck9SIDwtIGV4cChwb3N0aG9jQ0kkY29uZmludCkKT1IKYGBgCgotIERlIG9kZHMgcmF0aW9zIHRoYXQgd2Ugb2J0YWluIGlzIGV4YWN0bHkgZXF1YWwgdG8gdGhlIG9uZSB3ZSBjYWxjdWxhdGVkIGJhc2VkIG9uIHRoZSBjb250aW5nZW5jeSB0YWJsZToKLSBlLmcgICRcdGV4dHtPUn1fXHRleHR7TGV1L0xldS1Qcm8vUHJvfT04OVx0aW1lcyAyNjYvKDU2XHRpbWVzIDM0Mik9JCBgciBmb3JtYXQoKDg5LzU2KS8oMzQyLzI2NiksZGlnaXRzPTQpYC4KCi0gTm90ZSwgdGhhdCBzdGF0aXN0aWNhbCBpbmZlcmVuY2UgZm9yIGxvZ2lzdGljIHJlZ3Jlc3Npb24gcmVsaWVzIG9uIGFzeW1wdG90aWMgdGhlb3J5LgoKLS0tCgojIyBDb250aW51b3VzIFByZWRpY3RvcgoKLSBUb3hpY29sb2NhbCBlZmZlY3Qgb2YgY2FyYm9uIGRpc3VsZml0ZSAoQ1MkXzIkKSBvbiBiZWV0bGVzLgotIFJlc2VhcmNoIGh5cG90aGVzaXMgaXMgdGhlcmUgYW4gZWZmZWN0IG9mIHRoZSAgQ1MkXzIkIGNvbmNlbnRyYXRpb24gb24gdGhlIG1vcnRhbGl0eSBvZiBiZWV0bGVzPwoKRGVzaWduOgoKLSAzMiBpbmRlcGVuZGVudCBleHBlcmltZW50cwotIEVhY2ggdGltZSAxIGJlYXRsZSBpcyBleHBvc2VkIHRvIG9uZSBvZiA4IENTJF8yJCBjb25jZW50cmF0aW9ucyAobWcvbCkuCi0gVGhlIG91dGNvbWU6IG1vcnRhbGl0eSAoJHk9MSQpIG9yIHN1cnZpdmFsICgkeT0wJCkuCgpgYGB7cn0KYmVldGxlcyA8LSByZWFkX2NzdigiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL0dUUEIvUFNMUzIwL21hc3Rlci9kYXRhL2JlZXRsZXMuY3N2IikKaGVhZChiZWV0bGVzKQp0YWJsZShiZWV0bGVzJGRvc2UsIGJlZXRsZXMkc3RhdHVzKQpgYGAKCi0tLQoKV2UgYnVpbGQgYSBtb2RlbCBmb3IgdGhlIGxvZyBvZGRzIGluIGZ1bmN0aW9uIG9mIHRoZSBkb3NlICR4X2kkOgokJFxsb2cgXGZyYWN7XHBpX2l9ezEtXHBpX2l9PVxiZXRhXzArXGJldGFfMSBcdGltZXMgeF9pLiQkCgpgYGB7cn0KYmVhdGxlTW9kZWwgPC0gZ2xtKHN0YXR1cyB+IGRvc2UsIGRhdGEgPSBiZWV0bGVzLCBmYW1pbHkgPSBiaW5vbWlhbCkKc3VtbWFyeShiZWF0bGVNb2RlbCkKYGBgCgotLS0KCi0gSW50ZXJjZXB0IGhhcyBhbiBpbnRlcnByZXRhdGlvbiBvZiBhIGxvZyBvZGRzIG9uIG1vcnRhbGl0eSB3aGVuIG5vICRcdGV4dHtDU31fMiQgZ2FzIGlzIGFwcGxpZWQuCi0gVmVyeSBzbWFsbCBvZGRzIG9uIG1vcnRhbGl0eSAoJFxwaS8oMS1ccGkpPVxleHAoLTUzLjIpJCkgc28gdGhlIHByb2JhYmlsaXR5IGlzIGFsbW9zdCAwLgotIE5vdGUgdGhhdCB0aGlzIGlzIGEgdmVyeSBsYXJnZSBleHRyYXBvbGF0aW9uOiBtaW5pbXVtIGRvc2UgaW4gZGF0YXNldCBpcyBgciBtaW4oYmVldGxlcyRkb3NlKWAgbWcvbC4KCgotIEVzdGltYXRlZCBvZGRzIHJhdGlvIGZvciB0aGUgZWZmZWN0IG9mIGRvc2Ugb24gdGhlIG1vcnRhbGl0eSBwcm9iYWJpbGl0eSBpcyAkXGV4cCgwLjMwMTMpPTEuMzUkLgotIFNvIGEgYmVhdGxlIGV4cG9zZWQgdG8gYSBDUyRfMiQgY29uY2VudHJhdGlvbiB0aGF0IGlzIDEgbWcvbCBsYXJnZXIgdGhhbiBhbm90aGVyIGJlYXRsZSwgd2lsbCBvbiBhdmVyYWdlIGhhdmUgYW4gb2RkcyByYXRpbyBvbiBtb3J0YWxpdHkgb2YgJDEuMzUkLgoKLS0tCgotIFdlIGNvbmNsdWRlIHRoYXQgdGhpcyBlZmZlY3QgaXMgdmVyeSBzaWduaWZpY2FudCAoJHA9JCBgciByb3VuZChzdW1tYXJ5KGJlYXRsZU1vZGVsKSRjb2VmWzIsNF0sMylgKS4KLSBJbmNyZWFzaW5nIHRoZSBDUyRfMiQgZG9zZSBpbmNyZWFzZXMgdGhlIG1vcnRhbGl0eS4KCgpgYGB7cn0KCmJlZXRsZXNUYWIgPC0gdGFibGUoYmVldGxlcykgJT4lIGRhdGEuZnJhbWUoKQoKZGF0YS5mcmFtZShncmlkID0gc2VxKG1pbihiZWV0bGVzJGRvc2UpLCBtYXgoYmVldGxlcyRkb3NlKSwgLjEpKSAlPiUKICBtdXRhdGUocGlIYXQgPSBwcmVkaWN0KGJlYXRsZU1vZGVsLAogICAgbmV3ZGF0YSA9IGRhdGEuZnJhbWUoZG9zZSA9IGdyaWQpLAogICAgdHlwZSA9ICJyZXNwb25zZSIKICApKSAlPiUKICBnZ3Bsb3QoYWVzKGdyaWQsIHBpSGF0KSkgKwogIGdlb21fbGluZSgpICsKICB4bGFiKCJkb3NlIikgKwogIHlsYWIoInByb2JhYmlsaXR5IChkZWFkKSIpICsKICBnZW9tX3RleHQoYWVzKHggPSBkb3NlICU+JSBhcy5jaGFyYWN0ZXIoKSAlPiUgYXMuZG91YmxlKCksIHkgPSBzdGF0dXMgJT4lIGFzLmNoYXJhY3RlcigpICU+JSBhcy5kb3VibGUoKSwgbGFiZWwgPSBGcmVxKSwgYmVldGxlc1RhYiAlPiUgZmlsdGVyKHN0YXR1cyA9PSAwKSkgKwogIGdlb21fdGV4dChhZXMoeCA9IGRvc2UgJT4lIGFzLmNoYXJhY3RlcigpICU+JSBhcy5kb3VibGUoKSwgeSA9IHN0YXR1cyAlPiUgYXMuY2hhcmFjdGVyKCkgJT4lIGFzLmRvdWJsZSgpLCBsYWJlbCA9IEZyZXEpLCBiZWV0bGVzVGFiICU+JSBmaWx0ZXIoc3RhdHVzID09IDEpKQpgYGAK