1 Prostacycline dataset

  • Effect van arachidonzuur op het prostacycline niveau in het bloedplasma.

  • 3 verschillende concentraties van arachidonzuur:

    • laag (L, 10 eenheden)
    • gemiddeld (M, 25 eenheden)
    • hoge dosis (H, 50 eenheden)
  • Prostacycline concentratie in bloed plasma via gecalibreerde elisa fluorescentie meting

  • 12 ratten worden at random toegekend aan elke behandelingsgroep.

  • Factoriële proef, volledige gerandomiseerde proefopzet, “completely randomized design” CRD.

prostacyclin <- read_tsv("https://raw.githubusercontent.com/GTPB/PSLS20/master/data/prostacyclin.txt")

prostacyclin <- prostacyclin %>%
  mutate(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   

1.1 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)

Data in de drie groepen lijkt normaal verdeeld en de variantie is ongeveer gelijk: \[Y_i \vert \text{groep j} \sim N(\mu_j,\sigma^2),\] met \(j= \text{1, 2, 3}\)

1.2 Onderzoeksvraag

Vraagstelling kan vertaald worden in volgende hypotheses

  • \(H_0\): De arachidonzuurconcentratie heeft geen effect op het gemiddelde prostacycline niveau bij ratten \[ H_0:\mu_1=\mu_2 = \mu_3 \]

  • \(H_1\): De arachidonzuurconcentratie heeft een effect op het gemiddelde prostacycline niveau bij ratten. Wat betekent dat minstens twee gemiddelden verschillend zijn: \[H_1: \exists\ j,k \in \{1,\ldots,g\} : \mu_j\neq\mu_k\]

naïeve benadering: nulhypothese op splitsen in partiële hypotheses \[ H_{0jk}: \mu_j=\mu_k \text{ versus } H_{1jk}: \mu_j \neq \mu_k \]

Elk van deze partiële hypotheses testen met two-sample \(t\)-testen

\(\rightarrow\) Probleem van meervoudig toetsen + verlies van power.

\(\rightarrow\) \(H_0:\mu_1=\mu_2=\mu_3\) testen met 1 enkele test.

2 Analyse van variantie

  • Correcte oplossing voor het testprobleem: variantie-analyse, afgekort door ANOVA (ANalysis Of VAriance)

  • We leiden de methode af voor de meest eenvoudige uitbreiding met 3 groepen (prostacycline voorbeeld)

  • Data modelleren a.d.h.v een lineair model door gebruik te maken van dummy variabelen.

  • 1 dummy variable minder nodig hebben dan het aantal groepen. Hier dus 2 dummy variabelen.

  • De veralgemening naar g groepen \(g>3\) is triviaal (extra dummy variabelen)

2.1 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 uitkomst voor observatie \(i\) (\(i=1,\ldots, n\))
  • \(\epsilon_i\text{i.i.d.} N(0,\sigma^2)\)
  • en dummyvariabelen \[x_{i1} = \left\{ \begin{array}{ll} 1 & \text{ als observatie $i$ tot de middelste dosisgroep behoort (M)} \\ 0 & \text{ als observatie $i$ behoort tot een andere dosisgroep} \end{array}\right.\] \[x_{i2} = \left\{ \begin{array}{ll} 1 & \text{ als observatie $i$ behoort tot de groep met hoge doses (H)} \\ 0 & \text{als observatie $i$ behoort tot een andere dosisgroep} \end{array}\right. .\]
  • Lage dosis groep (L) with \(x_{i1}=x_{i2}=0\) is referentie groep

Regressiemodel kan worden herschreven als een model voor elke groep: \[\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*}\] met \(\epsilon_i \sim N(0,\sigma^2)\)

Interpretatie van model parameters: \[\begin{eqnarray*} \beta_0 &=& \text{E}\left[Y_i \mid \text{Behandeling met lage dosis groep L}\right] \\ \beta_1 &=& (\beta_0+\beta_1)-\beta_0 = \text{E}\left[Y_i \mid \text{behandeling M}\right] - \text{E}\left[Y_i \mid \text{behandeling L}\right] \\ \beta_2 &=& (\beta_0+\beta_2)-\beta_0 = \text{E}\left[Y_i \mid \text{behandeling H}\right]-\text{E}\left[Y_i \mid \text{behandeling L}\right]. \end{eqnarray*}\]

  1. \(\beta_0\) is gemiddelde uitkomst in groep L

  2. \(\beta_1\) is effect (verschil in gemiddelde concentratie) van groep M t.o.v. groep L

  3. \(\beta_2\) is effect van groep H t.o.v. groep L

We herformuleren het model door \(\mu\)-notaties te gebruiken: \[\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*}\] met \(\epsilon_i \sim N(0,\sigma^2)\) en \[ \mu_j = \text{E}\left[Y_i \mid \text{treatment group } j\right].\]

De oorspronkelijk nulhypothese \(H_0:\mu_1=\mu_2=\mu_3\) kan equivalent geformuleerd worden als

\[H_0: \beta_1=\beta_2=0\]

Model laat toe om methoden van lineaire regressie te gebruiken voor meervoudig vergelijken van gemiddelden.

  • Parameterschatting van parameters, varianties en standard errors uit theorie van lineaire regressie

  • Inferentie: Betrouwbaarheidsintervallen, hypothesetests

  • Test \(H_0: \beta_1=\beta_2=0\) met \(F\)-test.

2.2 Prostacyclin voorbeeld

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

3 Kwadratensommen en Anova

Zoals bij enkelvoudige regressie kwadratensom van regressie gebruiken bij het opstellen van de 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*}\] met \(n_1\), \(n_2\) en \(n_3\) het aantal waarnemingen in elke groep (hier \(n-1=n_2=n_3=12\)).

\[\begin{eqnarray*} \text{SSR}&=&\sum\limits_{i=1}^n (\hat Y_i -\bar Y)^2 \end{eqnarray*}\]

  • Kwadratensom opnieuw equivalent aan vergelijken van model (1) en een gereduceerd model met enkel een intercept.

  • Voor gereduceerd model zal intercept worden geschat door steekproefgemiddelde.

  • Deze kwadratensom heeft dus g-1=2 vrijheidsgraden:

    • g=3 model parameters - 1 parameter voor steekproefgemiddelde of
    • g=3 par. van complexe model - 1 par. van gereduceerde model.

3.1 Ontbinding van de Totale Kwadratensom

  • De conventie in een Anova setting is om de kwadratensom te noteren als SST, de kwadratensom van de behandeling (treatment) of als SSBetween.

  • De kwadratensom van de regressie geeft voor model (1) inderdaad de variabiliteit weer tussen de groepen.

  • De overeenkomstige gemiddelde kwadratensom wordt dan \(\text{MST}=\text{SST}/2\).

De decompositie van SSTot wordt dan geschreven als \[ \text{SSTot} = \text{SST} + \text{SSE} \]

##SSTot

##SST

3.2 SSE

3.3 Anova test

Test \(H_0: \beta_1=\beta_2=0\) met \(F\)-test. \[ F = \frac{\text{MST}}{\text{MSE}} \]

met

  • \(\text{MST}=\text{SST}/(g-1)\)
  • \(\text{MSE}=\text{SSE}/(n-p)\)
  • Teststatistiek vergelijkt de variabiliteit verklaard door model (MST) met de residuele variabiliteit (MSE)

of

  • Variabiliteit tussen groepen (MST) tot variabiliteit binnen groepen (MSE)
  • onder \(H_0\): \(F \sim F_{g-1,n-g}\), met g=3.

3.4 Anova Tabel

Df Sum Sq Mean Sq F value Pr(>F)
Treatment d.f. SST SST MST F-statistiek p-waarde
Error d.f. SSE SSE MSE
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

3.4.1 F-verdeling met kritieke waarde (\(\alpha\)=5%) en geobserveerde F-statistiek voor prostacycline voorbeeld

3.4.2 F-verdeling met verschillend aantal vrijheidsgraden in de noemer en teller

3.4.3 Prostacyclin voorbeeld: welke groepen zijn verschillend?

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

Met output van model kunnen we ook testen of de gemiddelde prostacycline concentratie verschillend is tussen de matige en lage dosis groep (\(\beta_1\): dose25) en tussen de hoge en lage dosis groep (\(\beta_2\): dose50).

De p-waarden houden geen rekening met het feit dat we meervoudig toetsen.

4 Post hoc analysis: Meerdere vergelijkingen van gemiddelden

4.1 Naïeve methode

In eerste deel van dit hoofdstuk hebben we \(F\)-test besproken voor het testen van

\[ 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\]

  • Als we \(H_0\) verwerpen besluiten we dat er minstens twee gemiddelden verschillen van elkaar.

  • De methode niet in staat om te identificeren welke gemiddelden van elkaar verschillen.

Een eerste, maar naïeve benadering: \(H_0\) opsplitsen in partiële hypotheses \[H_{0jk}: \mu_j=\mu_k \text{ versus } H_{1jk}: \mu_j \neq \mu_k\]

  • partiële hypotheses testen met two-sample \(t\)-testen

  • Voor vergelijken van groep \(j\) met groep \(k\) wordt klassieke two-sample \(t\)-test onder gelijkheid van variantie gegeven door: \[T_{jk} = \frac{\bar{Y}_j-\bar{Y}_k}{S_p\sqrt{\frac{1}{n_j}+\frac{1}{n_k}}} \sim t_{n-2}\]

Met

  • \(S_p^2\) de gepoolde variantieschatter is, \[S_p^2 = \frac{(n_j-1)S_j^2 + (n_k-1)S_k^2}{n_j+n_k-2}\]

  • met \(S_j^2\) en \(S_k^2\) de steekproefvarianties van respectievelijk de uitkomsten uit groep \(j\) en \(k\).


In ANOVA context veronderstellen we dat variantie in alle \(g\) groepen dezelfde is: de residuele variantie \(\sigma^2\).

  • Gebruik van \(S_p^2\) is niet efficiënt omdat die niet van alle data gebruik maakt

  • Aan efficiëntie winnen door door MSE te gebruiken \[\text{MSE}= \sum_{j=1}^g \frac{(n_j-1)S_j^2}{n-g}\]

  • De \(t\)-testen worden dus best gebaseerd op \[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 

Het werken met \(m\)-testen op het \(\alpha\) significantieniveau is echter een foute aanpak die de kans op een type I fout niet onder controle kan houden.

4.2 We tonen aan dat naïve methode niet werkt via simulatie

  1. We simuleren uit een ANOVA model met \(g=3\) groepen.
  2. De gemiddelden in het ANOVA model zijn gelijk aan elkaar, zodat de nulhypothese \[H_0: \mu_1=\mu_2=\mu_3\] opgaat.
  3. Voor iedere gesimuleerde dataset zijn er \(m=3\) paarsgewijze two-sample \(t\)-testen
  4. Zodra minstens één van de \(p\)-waarden kleiner is dan het significantieniveau \(\alpha=5\%\), wordt de nulhypothese \(H_0: \mu_1=\mu_2=\mu_3\) verworpen omdat er minstens twee gemiddelden verschillend zijn volgens de \(t\)-testen.
  5. We rapporteren de relatieve frequentie van het verwerpen van de globale nulhypothese, meer bepaald de kans op een type I fout van de test voor \(H_0: \mu_1=\mu_2=\mu_3\).
g <- 3 # aantal behandelingen (g=3)
ni <- 12 # aantal herhalingen in iedere groep
n <- g*ni # totaal aantal observaties
alpha <- 0.05 # significantieniveau van een individuele test
N <- 10000 #aantal simulaties
set.seed(302) #seed zodat resultaten exact geproduceerd kunnen worden
trt <- factor(rep(1:g, ni)) #factor
cnt <- 0 #teller voor aantal foutieve verwerpingen

for(i in 1:N) {
if (i %% 1000 == 0) cat(i, "/", N, "\n")
y <- rnorm(n)
tests <- pairwise.t.test(y, trt, "none")
verwerp <- min(tests$p.value, na.rm = T) < alpha
if(verwerp) cnt <- cnt+1
}
1000 / 10000 
2000 / 10000 
3000 / 10000 
4000 / 10000 
5000 / 10000 
6000 / 10000 
7000 / 10000 
8000 / 10000 
9000 / 10000 
10000 / 10000 
cnt/N
[1] 0.1209

  • Kans op een type I fout gelijk is aan 12.1%

  • Is meer dan dubbel zo groot is dan vooropgestelde \(\alpha=5\)%.

  • Als we simulatiestudie herhalen met g = 5 groepen (i.e. 10 paarsgewijze t-testen) dan vinden we 28.0% in plaats van de gewenste 5%.

  • Deze simulaties illustreren het probleem van multipliciteit (Engels: multiplicity)

    • klassieke \(p\)-waarden mogen enkel met het significantieniveau \(\alpha\) vergeleken worden, indien het besluit op exact één \(p\)-waarde gebaseerd is.
    • Finale besluit (al dan niet verwerpen van \(H_0: \mu_1=\cdots =\mu_g\)) gebaseerd op \(m=g\times(g-1)/2\) \(p\)-waarden.
  • We bespreken eerst een uitbreiding van het begrip van type I fout en vervolgens introduceren we enkele oplossingen.

4.3 Family-wise error rate

  • Wanneer \(m>1\) toetsen worden aangewend om 1 beslissing te vormen, is het noodzakelijk te corrigeren voor het risico op vals positieve resultaten (type I fout).
  • Meeste procedures voor meervoudig toetsen gaan ervan uit dat alle \(m\) nulhypotheses waar zijn.
  • Er wordt dan geprobeerd om het risico op minstens 1 vals positief resultaat te controleren op experimentgewijs significantieniveau \(\alpha_E\), typisch \(\alpha_E=0.05\).
  • In de Engelstalige literatuur wordt het experimentgewijs significantieniveau family-wise error rate (FWER) genoemd.

4.4 Bonferroni correction

Bij het uitvoeren van \(m\) onafhankelijke toetsen met elk significantieniveau \(\alpha\), is \[\begin{eqnarray*} \alpha_E&=&\text{P}[\text{minstens 1 Type I fout}]\\ &=&1-(1-\alpha)^m \leq m\alpha \end{eqnarray*}\]

  • Als we 3 toetsen uitvoeren op het 5% significantieniveau is FWER \(\approx 15\%\).
  • Door ze op het 1% significantieniveau uit te voeren, bekomen we FWER \(\approx 5\%\).
  • De Bonferroni correctie houdt de FWER begrensd op \(\alpha_E\) door \[\alpha=\alpha_E/m\] te kiezen voor het uitvoeren van de \(m\) paarsgewijze vergelijkingen.

Als alternatieve methode kunnen we ook

  1. aangepaste p-waarden rapporteren zodat we deze met het experimentgewijze \(\alpha_E\) niveau kunnen vergelijken: \[\tilde{p}=min(m\times p,1)\]

  2. \((1-\alpha_E/m)100\%\) betrouwbaarheidsintervallen rapporteren.

4.4.1 Prostacyclin voorbeeld

with(
  prostacyclin,
  pairwise.t.test(
    prostac,
    dose,
    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 
  • Conclusies blijven gelijk behalve dat FWER nu gecontroleerd is \(\alpha_E=5\%\) en \(\tilde{p}\)-waarden zijn factor 3 groter

Zelfde analyse kan via multcomp R package ontwikkeld voor multipliciteit in lineaire modellen.

library(multcomp)
library(multcomp)
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)

Om Bonferroni aangepaste betrouwbaarheidsintervallen te verkrijgen moeten we eerst zelf functie definiëren in R om bonferroni kritische waarde te bepalen.

  • Bonferonni-betrouwbaarheidsintervallen worden niet geïmplementeerd omdat er betere methoden bestaan voor meervoudige tests.

  • De onderstaande functie is hier alleen voor de volledigheid toegevoegd, maar we zullen over het algemeen de standaardmethode gebruiken voor meervoudige tests 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

4.4.2 Simulatie om Bonferroni methode te evalueren

g <- 3 # aantal behandelingen (g=3)
ni <- 12 # aantal herhalingen in iedere groep
n <- g*ni # totaal aantal observaties
alpha <- 0.05 # significantieniveau van een individuele test
N <- 10000 #aantal simulaties
set.seed(302) #seed zodat resultaten exact geproduceerd kunnen worden
trt <- factor(rep(1:g, ni)) #factor
cnt <- 0 #teller voor aantal foutieve verwerpingen

for(i in 1:N) {
if (i %% 1000 == 0) cat(i, "/", N, "\n")
y <- rnorm(n)
tests <- pairwise.t.test(y, trt, "bonferroni")
verwerp <- min(tests$p.value, na.rm = T) < alpha
if(verwerp) cnt <- cnt+1
}
1000 / 10000 
2000 / 10000 
3000 / 10000 
4000 / 10000 
5000 / 10000 
6000 / 10000 
7000 / 10000 
8000 / 10000 
9000 / 10000 
10000 / 10000 
cnt/N
[1] 0.0457
  • We vinden een FWER van 4.6% (een beetje conservatief)

  • Bij simulaties voor \(g=5\) groepen, vinden we een FWER van \(4.1\%\) (conservatiever).

  • Door Bonferroni correctie is kans op minstens één vals positief resultaat \(< \alpha_E\).

  • Power verlies aangezien werkelijke niveau lager is dan het vooropgestelde 5% experimentsgewijs significantieniveau.

4.5 Tukey Methode

  • Minder conservatieve methode

  • Implementatie benadert de nuldistributie van de posthoc test d.m.v. simulaties.

  • Resultaten kunnen lichtjes verschillen wanneer je posthoc analyse opnieuw uitvoert.

  • Details van de methode vallen buiten het bestek van deze cursus.

  • Implementatie in multcomp package:

    • aangepaste p-waarden

    • aangepaste betrouwbaarheidsintervallen

    • Niet nodig om functies te definiëren voor Tukey gecorrigeerde BIs

4.5.1 Captopril voorbeeld

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)
confint(model1.mcp)

     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
model1.mcp %>%
  confint %>%
  plot

4.5.2 Evalueer Tukey methode in een simulatiestudie

g <- 3 # aantal behandelingen (g=3)
ni <- 12 # aantal herhalingen in iedere groep
n <- g*ni # totaal aantal observaties
alpha <- 0.05 # significantieniveau van een individuele test
N <- 10000 #aantal simulaties
set.seed(302) #seed zodat resultaten exact geproduceerd kunnen worden
trt <- factor(rep(1:g, ni)) #factor
cnt <- 0 #teller voor aantal foutieve verwerpingen

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
verwerp <- min(
  as.numeric(tests$pvalues),
  na.rm=T) < alpha
if(verwerp) cnt <- cnt+1
}
1000 / 10000 
2000 / 10000 
3000 / 10000 
4000 / 10000 
5000 / 10000 
6000 / 10000 
7000 / 10000 
8000 / 10000 
9000 / 10000 
10000 / 10000 
cnt/N
[1] 0.0503

De methode wordt mooi op het 5% experimentsgewijs significantieniveau gecontroleerd.

5 Conclusies: Prostacycline voorbeeld

Volledige analyse voor voorbeeld prostacycline

  1. Anova vóór posthoc-tests: F-test heeft een hogere power dan paarsgewijze t-test

    • F-test gebruikt alle gegevens
    • Voor F-test hoeven we niet te corrigeren voor meervoudige testen: er wordt één test uitgevoerd voor de algemene omnibushypothese
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)
confint(model1.mcp)

     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
  • Er is een extreem significant effect van arachidonzuur op de gemiddelde bloedconcentratie van prostacycline bij ratten (\(p<0.001\)). De gemiddelde prostacyclineconcentratie is hoger in de hoge dosisgroep dan in de lage en matige dosisgroep (beide p-waardes zijn kleiner dan \(p<0.001\)).
  • De gemiddelde concentratie in de hoge dosisgroep is 43.3ng/ml (95% CI [21.9,64.6]ng/ml) en 35ng/ml (95% BI [13.6,56.4]ng/ml) hoger dan in de lage en matige dosisgroep, respectievelijk.
  • Het verschil in gemiddelde prostacyclineconcentratie tussen de matige en lage dosisgroep is niet significant (p=0.61). (Alle p-waardes en betrouwbaarheidsintervallen voor post-hoc-tests worden gecorrigeerd voor meervoudige tests met behulp van de Tukey-methode).

Merk op dat het belangrijk is om ook de niet significante resultaten te vermelden!


LS0tCnRpdGxlOiAiNy4gQW5hbHlzaXMgb2YgVmFyaWFuY2UiCmF1dGhvcjogIkxpZXZlbiBDbGVtZW50IgpkYXRlOiAic3RhdE9taWNzLCBHaGVudCBVbml2ZXJzaXR5IChodHRwczovL3N0YXRvbWljcy5naXRodWIuaW8pIgpvdXRwdXQ6CiAgICBodG1sX2RvY3VtZW50OgogICAgICBjb2RlX2Rvd25sb2FkOiB0cnVlICAgIAogICAgICB0aGVtZTogY29zbW8KICAgICAgdG9jOiB0cnVlCiAgICAgIHRvY19mbG9hdDogdHJ1ZQogICAgICBoaWdobGlnaHQ6IHRhbmdvCiAgICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQotLS0KCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoaW5jbHVkZSA9IFRSVUUsIGNvbW1lbnQgPSBOQSwgZWNobyA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSkKbGlicmFyeShSbWlzYykKbGlicmFyeSh0aWR5dmVyc2UpCmBgYAoKCiMgUHJvc3RhY3ljbGluZSBkYXRhc2V0CgotIEVmZmVjdCB2YW4gYXJhY2hpZG9uenV1ciBvcCBoZXQgcHJvc3RhY3ljbGluZSBuaXZlYXUgaW4gaGV0IGJsb2VkcGxhc21hLgotIDMgdmVyc2NoaWxsZW5kZSBjb25jZW50cmF0aWVzIHZhbiBhcmFjaGlkb256dXVyOgoKICAtIGxhYWcgKEwsIDEwIGVlbmhlZGVuKQogIC0gZ2VtaWRkZWxkIChNLCAyNSBlZW5oZWRlbikKICAtIGhvZ2UgZG9zaXMgKEgsIDUwIGVlbmhlZGVuKQoKLSBQcm9zdGFjeWNsaW5lIGNvbmNlbnRyYXRpZSBpbiBibG9lZCBwbGFzbWEgdmlhICBnZWNhbGlicmVlcmRlIGVsaXNhIGZsdW9yZXNjZW50aWUgbWV0aW5nCi0gMTIgcmF0dGVuIHdvcmRlbiBhdCByYW5kb20gdG9lZ2VrZW5kIGFhbiBlbGtlIGJlaGFuZGVsaW5nc2dyb2VwLgotIEZhY3RvcmnDq2xlIHByb2VmLCAqdm9sbGVkaWdlIGdlcmFuZG9taXNlZXJkZSBwcm9lZm9wemV0KiwgKiJjb21wbGV0ZWx5IHJhbmRvbWl6ZWQgZGVzaWduIiBDUkQqLgoKCgoKYGBge3J9CnByb3N0YWN5Y2xpbiA8LSByZWFkX3RzdigiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL0dUUEIvUFNMUzIwL21hc3Rlci9kYXRhL3Byb3N0YWN5Y2xpbi50eHQiKQoKcHJvc3RhY3ljbGluIDwtIHByb3N0YWN5Y2xpbiAlPiUKICBtdXRhdGUoZG9zZSA9IGFzLmZhY3Rvcihwcm9zdGFjeWNsaW4kZG9zZSkpCgpoZWFkKHByb3N0YWN5Y2xpbikKYGBgCgotLS0KCiMjIERhdGEgZXhwbG9yYXRpb24KCmBgYHtyfQpwcm9zdGFjeWNsaW4gJT4lCiAgZ2dwbG90KGFlcyh4ID0gZG9zZSwgeSA9IHByb3N0YWMsIGZpbGwgPSBkb3NlKSkgKwogIGdlb21fYm94cGxvdCgpICsKICBnZW9tX3BvaW50KHBvc2l0aW9uID0gImppdHRlciIpICsKICB5bGFiKCJwcm9zdGFjeWNsaW4gKG5nL21sKSIpCgpwcm9zdGFjeWNsaW4gJT4lCiAgZ2dwbG90KGFlcyhzYW1wbGUgPSBwcm9zdGFjKSkgKwogIGdlb21fcXEoKSArCiAgZ2VvbV9xcV9saW5lKCkgKwogIGZhY2V0X2dyaWQofiBkb3NlKQpgYGAKCgoKRGF0YSBpbiBkZSBkcmllIGdyb2VwZW4gbGlqa3Qgbm9ybWFhbCB2ZXJkZWVsZCBlbiBkZSB2YXJpYW50aWUgaXMgb25nZXZlZXIgZ2VsaWprOgpcW1lfaSBcdmVydCBcdGV4dHtncm9lcCBqfSBcc2ltIE4oXG11X2osXHNpZ21hXjIpLFxdCm1ldCAkaj0gXHRleHR7MSwgMiwgM30kCgoKIyMgT25kZXJ6b2Vrc3ZyYWFnCgpWcmFhZ3N0ZWxsaW5nIGthbiB2ZXJ0YWFsZCB3b3JkZW4gaW4gdm9sZ2VuZGUgaHlwb3RoZXNlcwoKLSAkSF8wJDogRGUgYXJhY2hpZG9uenV1cmNvbmNlbnRyYXRpZSBoZWVmdCBnZWVuIGVmZmVjdCBvcCBoZXQgZ2VtaWRkZWxkZSBwcm9zdGFjeWNsaW5lIG5pdmVhdSBiaWogcmF0dGVuClxbCiAgSF8wOlxtdV8xPVxtdV8yID0gXG11XzMKXF0KCi0gJEhfMSQ6IERlIGFyYWNoaWRvbnp1dXJjb25jZW50cmF0aWUgaGVlZnQgZWVuIGVmZmVjdCBvcCBoZXQgZ2VtaWRkZWxkZSBwcm9zdGFjeWNsaW5lIG5pdmVhdSBiaWogcmF0dGVuLiBXYXQgYmV0ZWtlbnQgZGF0IG1pbnN0ZW5zIHR3ZWUgZ2VtaWRkZWxkZW4gdmVyc2NoaWxsZW5kIHppam46ClxbSF8xOiBcZXhpc3RzXCBqLGsgXGluIFx7MSxcbGRvdHMsZ1x9IDogXG11X2pcbmVxXG11X2tcXQoKCgoqKm5hw69ldmUgYmVuYWRlcmluZyoqOiBudWxoeXBvdGhlc2Ugb3Agc3BsaXRzZW4gaW4gKipwYXJ0acOrbGUgaHlwb3RoZXNlcyoqClxbCiAgSF97MGprfTogXG11X2o9XG11X2sgXHRleHR7IHZlcnN1cyB9IEhfezFqa306IFxtdV9qIFxuZXEgXG11X2sKXF0KCkVsayB2YW4gZGV6ZSBwYXJ0acOrbGUgaHlwb3RoZXNlcyB0ZXN0ZW4gbWV0IHR3by1zYW1wbGUgJHQkLXRlc3RlbgoKJFxyaWdodGFycm93JCBQcm9ibGVlbSB2YW4gbWVlcnZvdWRpZyB0b2V0c2VuICsgdmVybGllcyB2YW4gcG93ZXIuCgokXHJpZ2h0YXJyb3ckICAkSF8wOlxtdV8xPVxtdV8yPVxtdV8zJCB0ZXN0ZW4gbWV0ICoqMSBlbmtlbGUgdGVzdCoqLgoKCgoKIyBBbmFseXNlIHZhbiB2YXJpYW50aWUKCi0gQ29ycmVjdGUgb3Bsb3NzaW5nIHZvb3IgaGV0IHRlc3Rwcm9ibGVlbTogKip2YXJpYW50aWUtYW5hbHlzZSoqLCBhZmdla29ydCBkb29yIEFOT1ZBIChBTmFseXNpcyBPZiBWQXJpYW5jZSkKCi0gV2UgbGVpZGVuIGRlIG1ldGhvZGUgYWYgdm9vciBkZSBtZWVzdCBlZW52b3VkaWdlIHVpdGJyZWlkaW5nIG1ldCAzIGdyb2VwZW4gKHByb3N0YWN5Y2xpbmUgdm9vcmJlZWxkKQoKLSBEYXRhIG1vZGVsbGVyZW4gYS5kLmgudiBlZW4gbGluZWFpciBtb2RlbCBkb29yIGdlYnJ1aWsgdGUgbWFrZW4gdmFuIGR1bW15IHZhcmlhYmVsZW4uCgotIDEgZHVtbXkgdmFyaWFibGUgbWluZGVyIG5vZGlnIGhlYmJlbiBkYW4gaGV0IGFhbnRhbCBncm9lcGVuLiBIaWVyIGR1cyAyIGR1bW15IHZhcmlhYmVsZW4uCi0gRGUgdmVyYWxnZW1lbmluZyBuYWFyIGcgZ3JvZXBlbiAkZz4zJCBpcyB0cml2aWFhbCAoZXh0cmEgZHVtbXkgdmFyaWFiZWxlbikKCiMjIE1vZGVsCgpcYmVnaW57ZXFuYXJyYXl9CiAgWV9pICY9JiBnKHhfe2kxfSx4X3tpMn0pICsgXGVwc2lsb25faVxcCiAgWV9pICY9JiBcYmV0YV8wK1xiZXRhXzEgeF97aTF9ICtcYmV0YV8yIHhfe2kyfSArXGVwc2lsb25faQpcZW5ke2VxbmFycmF5fQoKLSAkWV9pJCBkZSB1aXRrb21zdCB2b29yIG9ic2VydmF0aWUgJGkkICgkaT0xLFxsZG90cywgbiQpClx2c3BhY2V7N3B0fQotICRcZXBzaWxvbl9pXHRleHR7aS5pLmQufSBOKDAsXHNpZ21hXjIpJApcdnNwYWNlezdwdH0KLSBlbiBkdW1teXZhcmlhYmVsZW4KJCR4X3tpMX0gPSBcbGVmdFx7IFxiZWdpbnthcnJheX17bGx9CjEgJiBcdGV4dHsgYWxzIG9ic2VydmF0aWUgJGkkIHRvdCBkZSBtaWRkZWxzdGUgZG9zaXNncm9lcCBiZWhvb3J0IChNKX0gXFwKMCAmIFx0ZXh0eyBhbHMgb2JzZXJ2YXRpZSAkaSQgYmVob29ydCB0b3QgZWVuIGFuZGVyZSBkb3Npc2dyb2VwfSBcZW5ke2FycmF5fVxyaWdodC4kJAokJHhfe2kyfSA9IFxsZWZ0XHsgXGJlZ2lue2FycmF5fXtsbH0KMSAmIFx0ZXh0eyBhbHMgb2JzZXJ2YXRpZSAkaSQgYmVob29ydCB0b3QgZGUgZ3JvZXAgbWV0IGhvZ2UgZG9zZXMgKEgpfSBcXAowICYgXHRleHR7YWxzIG9ic2VydmF0aWUgJGkkIGJlaG9vcnQgdG90IGVlbiBhbmRlcmUgZG9zaXNncm9lcH0gXGVuZHthcnJheX1ccmlnaHQuIC4kJApcdnNwYWNlezdwdH0KIC0gTGFnZSBkb3NpcyBncm9lcCAoTCkgd2l0aCAkeF97aTF9PXhfe2kyfT0wJCBpcyAgKnJlZmVyZW50aWUgZ3JvZXAqCgpSZWdyZXNzaWVtb2RlbCBrYW4gd29yZGVuIGhlcnNjaHJldmVuIGFscyBlZW4gbW9kZWwgdm9vciBlbGtlIGdyb2VwOgpcdnNwYWNley0yMHB0fQpcYmVnaW57ZXFuYXJyYXkqfQogWV97aVx2ZXJ0IFx0ZXh0e2Rvc2U9TH19ICY9JiBcYmV0YV8wK1xlcHNpbG9uX2kgXFwKIFlfe2lcdmVydCBcdGV4dHtkb3NlPU19fSAmPSYgXGJldGFfMCtcYmV0YV8xKyBcZXBzaWxvbl9pICBcXAogWV97aVx2ZXJ0IFx0ZXh0e2Rvc2U9SH19ICY9JiBcYmV0YV8wK1xiZXRhXzIgKyBcZXBzaWxvbl9pClxlbmR7ZXFuYXJyYXkqfQptZXQgJFxlcHNpbG9uX2kgXHNpbSBOKDAsXHNpZ21hXjIpJApcdnNwYWNlezEwcHR9CgpJbnRlcnByZXRhdGllIHZhbiBtb2RlbCBwYXJhbWV0ZXJzOgpcdnNwYWNley0yMHB0fQogXGJlZ2lue2VxbmFycmF5Kn0KICAgXGJldGFfMCAmPSYgIFx0ZXh0e0V9XGxlZnRbWV9pIFxtaWQgXHRleHR7QmVoYW5kZWxpbmcgbWV0IGxhZ2UgZG9zaXMgZ3JvZXAgTH1ccmlnaHRdIFxcCiAgIFxiZXRhXzEgJj0mICAoXGJldGFfMCtcYmV0YV8xKS1cYmV0YV8wID0gXHRleHR7RX1cbGVmdFtZX2kgXG1pZCBcdGV4dHtiZWhhbmRlbGluZyBNfVxyaWdodF0gLSBcdGV4dHtFfVxsZWZ0W1lfaSBcbWlkIFx0ZXh0e2JlaGFuZGVsaW5nIEx9XHJpZ2h0XSBcXAogICBcYmV0YV8yICY9JiAgKFxiZXRhXzArXGJldGFfMiktXGJldGFfMCA9IFx0ZXh0e0V9XGxlZnRbWV9pIFxtaWQgXHRleHR7YmVoYW5kZWxpbmcgSH1ccmlnaHRdLVx0ZXh0e0V9XGxlZnRbWV9pIFxtaWQgXHRleHR7YmVoYW5kZWxpbmcgTH1ccmlnaHRdLgogXGVuZHtlcW5hcnJheSp9CgogIDEuICAkXGJldGFfMCQgaXMgZ2VtaWRkZWxkZSB1aXRrb21zdCBpbiBncm9lcCBMCgogIDIuICAkXGJldGFfMSQgaXMgZWZmZWN0ICh2ZXJzY2hpbCBpbiBnZW1pZGRlbGRlIGNvbmNlbnRyYXRpZSkgdmFuIGdyb2VwIE0gdC5vLnYuIGdyb2VwIEwKCiAgMy4gICRcYmV0YV8yJCBpcyBlZmZlY3QgdmFuIGdyb2VwIEggdC5vLnYuIGdyb2VwIEwKCgpXZSBoZXJmb3JtdWxlcmVuIGhldCBtb2RlbCBkb29yICRcbXUkLW5vdGF0aWVzIHRlIGdlYnJ1aWtlbjoKIFx2c3BhY2V7LTdwdH0KIFxiZWdpbntlcW5hcnJheSp9CiAgWV97aVx2ZXJ0IFx0ZXh0e2Rvc2U9TH19ICY9JiBcYmV0YV8wK1xlcHNpbG9uX2kgPSBcbXVfMStcZXBzaWxvbl9pIFxcCiAgWV97aVx2ZXJ0IFx0ZXh0e2Rvc2U9TX19ICY9JiBcYmV0YV8wK1xiZXRhXzErIFxlcHNpbG9uX2kgPSBcbXVfMitcZXBzaWxvbl9pIFxcCiAgWV97aVx2ZXJ0IFx0ZXh0e2Rvc2U9SH19ICY9JiBcYmV0YV8wK1xiZXRhXzIgKyBcZXBzaWxvbl9pID0gXG11XzMrXGVwc2lsb25faSAuCiBcZW5ke2VxbmFycmF5Kn0KIG1ldCAkXGVwc2lsb25faSBcc2ltIE4oMCxcc2lnbWFeMikkIGVuCiAkJCAgXG11X2ogPSBcdGV4dHtFfVxsZWZ0W1lfaSBcbWlkIFx0ZXh0e3RyZWF0bWVudCBncm91cCB9IGpccmlnaHRdLiQkCgogRGUgb29yc3Byb25rZWxpamsgbnVsaHlwb3RoZXNlICRIXzA6XG11XzE9XG11XzI9XG11XzMkIGthbiBlcXVpdmFsZW50IGdlZm9ybXVsZWVyZCB3b3JkZW4gYWxzCgpcW0hfMDogXGJldGFfMT1cYmV0YV8yPTBcXQoKIE1vZGVsIGxhYXQgdG9lIG9tIG1ldGhvZGVuIHZhbiBsaW5lYWlyZSByZWdyZXNzaWUgdGUgZ2VicnVpa2VuIHZvb3IgbWVlcnZvdWRpZyB2ZXJnZWxpamtlbiB2YW4gZ2VtaWRkZWxkZW4uCgogLSBQYXJhbWV0ZXJzY2hhdHRpbmcgdmFuIHBhcmFtZXRlcnMsIHZhcmlhbnRpZXMgZW4gc3RhbmRhcmQgZXJyb3JzIHVpdCB0aGVvcmllIHZhbiBsaW5lYWlyZSByZWdyZXNzaWUKCi0gSW5mZXJlbnRpZTogQmV0cm91d2JhYXJoZWlkc2ludGVydmFsbGVuLCBoeXBvdGhlc2V0ZXN0cwoKLSBUZXN0ICRIXzA6IFxiZXRhXzE9XGJldGFfMj0wJCBtZXQgJEYkLXRlc3QuCgojIyBQcm9zdGFjeWNsaW4gdm9vcmJlZWxkCgpgYGB7cn0KbW9kZWwxIDwtIGxtKHByb3N0YWMgfiBkb3NlLCBkYXRhID0gcHJvc3RhY3ljbGluKQpzdW1tYXJ5KG1vZGVsMSkKYGBgCgoKIyBLd2FkcmF0ZW5zb21tZW4gZW4gQW5vdmEKClpvYWxzIGJpaiBlbmtlbHZvdWRpZ2UgcmVncmVzc2llIGt3YWRyYXRlbnNvbSB2YW4gcmVncmVzc2llIGdlYnJ1aWtlbiBiaWogaGV0IG9wc3RlbGxlbiB2YW4gZGUgRi10ZXN0LgpcdnNwYWNley0xMHB0fQpcYmVnaW57ZXFuYXJyYXkqfQpcdGV4dHtTU1J9Jj0mXHN1bVxsaW1pdHNfe2k9MX1ebiAoXGhhdCBZX2kgLVxiYXIgWSleMlxcCiY9JiBcc3VtXGxpbWl0c197aT0xfV5uIChcaGF0e2d9ICh4X3tpMX0seF97aTJ9KSAtIFxiYXIgWSleMlxcCiY9JiBcc3VtXGxpbWl0c197aT0xfV5uIChcaGF0XGJldGFfMCtcaGF0XGJldGFfMXhfe2kxfStcaGF0XGJldGFfMnhfe2kyfSkgLSBcYmFyIFkpXjJcXAomPSYgXHN1bVxsaW1pdHNfe2k9MX1ee25fMX0gKFxoYXRcYmV0YV8wIC0gXGJhciBZKV4yICtcc3VtXGxpbWl0c197aT0xfV57bl8yfSAoXGhhdFxiZXRhXzAgKyBcaGF0XGJldGFfMSAtIFxiYXIgWSleMitcc3VtXGxpbWl0c197aT0xfV57bl8zfSAoXGhhdFxiZXRhXzAgKyBcaGF0XGJldGFfMiAtIFxiYXIgWSleMlxcCiY9JiBcc3VtXGxpbWl0c197aT0xfV57bl8xfSAoXGJhciBZXzEtIFxiYXIgWSleMiArXHN1bVxsaW1pdHNfe2k9MX1ee25fMn0gKFxiYXIgWV8yLSBcYmFyIFkpXjIrXHN1bVxsaW1pdHNfe2k9MX1ee25fM30gKFxiYXIgWV8zIC0gXGJhciBZKV4yXFwKXGVuZHtlcW5hcnJheSp9Cm1ldCAkbl8xJCwgJG5fMiQgZW4gJG5fMyQgaGV0IGFhbnRhbCB3YWFybmVtaW5nZW4gaW4gZWxrZSBncm9lcCAoaGllciAkbi0xPW5fMj1uXzM9MTIkKS4KCgpcYmVnaW57ZXFuYXJyYXkqfQpcdGV4dHtTU1J9Jj0mXHN1bVxsaW1pdHNfe2k9MX1ebiAoXGhhdCBZX2kgLVxiYXIgWSleMgpcZW5ke2VxbmFycmF5Kn0KCi0gS3dhZHJhdGVuc29tIG9wbmlldXcgZXF1aXZhbGVudCBhYW4gdmVyZ2VsaWprZW4gdmFuIG1vZGVsICgxKSBlbiBlZW4gZ2VyZWR1Y2VlcmQgbW9kZWwgbWV0IGVua2VsIGVlbiBpbnRlcmNlcHQuCi0gVm9vciBnZXJlZHVjZWVyZCBtb2RlbCB6YWwgaW50ZXJjZXB0IHdvcmRlbiBnZXNjaGF0IGRvb3Igc3RlZWtwcm9lZmdlbWlkZGVsZGUuCi0gRGV6ZSBrd2FkcmF0ZW5zb20gaGVlZnQgZHVzIGctMT0yIHZyaWpoZWlkc2dyYWRlbjogIAoKICAtIGc9MyBtb2RlbCBwYXJhbWV0ZXJzIC0gMSBwYXJhbWV0ZXIgdm9vciBzdGVla3Byb2VmZ2VtaWRkZWxkZSBvZgogIC0gZz0zIHBhci4gdmFuIGNvbXBsZXhlIG1vZGVsIC0gMSBwYXIuIHZhbiBnZXJlZHVjZWVyZGUgbW9kZWwuCgoKIyMgT250YmluZGluZyB2YW4gZGUgVG90YWxlIEt3YWRyYXRlbnNvbQoKLSBEZSBjb252ZW50aWUgaW4gZWVuIEFub3ZhIHNldHRpbmcgaXMgb20gZGUga3dhZHJhdGVuc29tIHRlIG5vdGVyZW4gYWxzIFNTVCwgZGUgKiprd2FkcmF0ZW5zb20gdmFuIGRlIGJlaGFuZGVsaW5nICh0cmVhdG1lbnQpKiogb2YgYWxzIFNTQmV0d2Vlbi4KCgotIERlIGt3YWRyYXRlbnNvbSB2YW4gZGUgcmVncmVzc2llIGdlZWZ0IHZvb3IgbW9kZWwgKDEpIGluZGVyZGFhZCBkZSB2YXJpYWJpbGl0ZWl0IHdlZXIgdHVzc2VuIGRlIGdyb2VwZW4uCgotIERlIG92ZXJlZW5rb21zdGlnZSBnZW1pZGRlbGRlIGt3YWRyYXRlbnNvbSB3b3JkdCBkYW4gJFx0ZXh0e01TVH09XHRleHR7U1NUfS8yJC4KCkRlIGRlY29tcG9zaXRpZSB2YW4gU1NUb3Qgd29yZHQgZGFuIGdlc2NocmV2ZW4gYWxzCiAgXFsKICAgIFx0ZXh0e1NTVG90fSA9IFx0ZXh0e1NTVH0gKyBcdGV4dHtTU0V9CiAgXF0KCiMjU1NUb3QKCmBgYHtyIGVjaG89RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnBhcihtZnJvdz1jKDEsMikpCmppdElrPXJ1bmlmKDM2LC0uMiwuMikrcmVwKDE6MyxlYWNoPTEyKQpwbG90KHByb3N0YWN+ZG9zZSxkYXRhPXByb3N0YWN5Y2xpbix4bGFiPSJBcmFjaGlkb25pYyBhY2lkIGRvc2UgIix5bGFiPSJQcm9zdGFjeWNsaW4gKG5nL21sKSIsY2V4LmF4aXM9MS41LGNleC5sYWI9MS41LGNleC5tYWluPTEuNSkKcG9pbnRzKGppdElrLHByb3N0YWN5Y2xpbiRwcm9zdGFjLGNvbD1jb2wscGNoPTE5KQpwb2ludHMoaml0SWsscHJvc3RhY3ljbGluJHByb3N0YWMsY29sPTQpCnBvaW50cygxOjMscHJlZGljdChtb2RlbDEsZGF0YS5mcmFtZShkb3NlPWZhY3RvcihjKDEwLDI1LDUwKSkpKSxwY2g9MTcsY29sPWMoImJpc3F1ZSIsImNvcmFsIiwiZGFya2N5YW4iKSxjZXg9MS41KQpwb2ludHMoMTozLHByZWRpY3QobW9kZWwxLGRhdGEuZnJhbWUoZG9zZT1mYWN0b3IoYygxMCwyNSw1MCkpKSkscGNoPTIsY29sPTEsY2V4PTEuNSkKYWJsaW5lKGg9bWVhbihwcm9zdGFjeWNsaW4kcHJvc3RhYyksbHR5PTEpCmZvciAoaSBpbiAxOjM2KSBsaW5lcyhyZXAoaml0SWtbaV0sMiksYyhtZWFuKHByb3N0YWN5Y2xpbiRwcm9zdGFjKSxwcm9zdGFjeWNsaW4kcHJvc3RhY1tpXSksY29sPTQsbHR5PTIpCmppdElrPXJ1bmlmKDM2LC0uMiwuMikrcmVwKDE6MyxlYWNoPTEyKQoKcGxvdChyZXAoMSwzNikscHJvc3RhY3ljbGluJHByb3N0YWMtbWVhbihwcm9zdGFjeWNsaW4kcHJvc3RhYykseGF4dD0ibm9uZSIseWxhYj0iRGV2aWF0aW9ucyIsY2V4LmxhYj0xLjUsY2V4Lm1haW49MS41LGNleC5heGlzPTEuNSxjb2w9YXMuY2hhcmFjdGVyKHByb3N0YWN5Y2xpbiRjb2wpLHhsaW09YygxLDMpLHBjaD0xOSx4bGFiPSIiKQpwb2ludHMocmVwKDEsMzYpLHByb3N0YWN5Y2xpbiRwcm9zdGFjLW1lYW4ocHJvc3RhY3ljbGluJHByb3N0YWMpLHBjaD0xLGNvbD00KQpheGlzKGF0PTE6MyxsYWJlbHM9YyhleHByZXNzaW9uKHBhc3RlKHlbaV0sIiAtICIsYmFyKHkpKSksZXhwcmVzc2lvbihwYXN0ZShiYXIoeSlbal0sIiAtICIsYmFyKHkpKSksZXhwcmVzc2lvbihwYXN0ZSh5W2ldLCIgLSAiLGJhcih5KVtqXSkpKSxzaWRlPTEsY2V4LmF4aXM9MS41KQpgYGAKCgojI1NTVAoKYGBge3IgZWNobz1GQUxTRSwgd2FybmluZz1GQUxTRX0KcGFyKG1mcm93PWMoMSwyKSkKcGxvdChwcm9zdGFjfmRvc2UsZGF0YT1wcm9zdGFjeWNsaW4seGxhYj0iQXJhY2hpZG9uaWMgYWNpZCBkb3NlICIseWxhYj0iUHJvc3RhY3ljbGluIChuZy9tbCkiLGNleC5heGlzPTEuNSxjZXgubGFiPTEuNSxjZXgubWFpbj0xLjUpCnBvaW50cyhqaXRJayxwcm9zdGFjeWNsaW4kcHJvc3RhYyxjb2w9Y29sLHBjaD0xOSkKcG9pbnRzKGppdElrLHByb3N0YWN5Y2xpbiRwcm9zdGFjLGNvbD00KQpwb2ludHMoMTozLHByZWRpY3QobW9kZWwxLGRhdGEuZnJhbWUoZG9zZT1mYWN0b3IoYygxMCwyNSw1MCkpKSkscGNoPTE3LGNvbD1jKCJiaXNxdWUiLCJjb3JhbCIsImRhcmtjeWFuIiksY2V4PTEuNSkKcG9pbnRzKDE6MyxwcmVkaWN0KG1vZGVsMSxkYXRhLmZyYW1lKGRvc2U9ZmFjdG9yKGMoMTAsMjUsNTApKSkpLHBjaD0yLGNvbD0yLGNleD0xLjUpCmFibGluZShoPW1lYW4ocHJvc3RhY3ljbGluJHByb3N0YWMpLGx0eT0xKQpmb3IgKGkgaW4gMTozKSBsaW5lcyhyZXAoaSwyKSxjKG1lYW4ocHJvc3RhY3ljbGluJHByb3N0YWMpLHByZWRpY3QobW9kZWwxLGRhdGEuZnJhbWUoZG9zZT1sZXZlbHMocHJvc3RhY3ljbGluJGRvc2UpW2ldKSkpLGNvbD0yLGx0eT0yKQoKcGxvdChyZXAoMSwzNikscHJvc3RhY3ljbGluJHByb3N0YWMtbWVhbihwcm9zdGFjeWNsaW4kcHJvc3RhYykseGF4dD0ibm9uZSIseWxhYj0iRGV2aWF0aW9ucyIsY2V4LmxhYj0xLjUsY2V4Lm1haW49MS41LGNleC5heGlzPTEuNSxjb2w9YXMuY2hhcmFjdGVyKHByb3N0YWN5Y2xpbiRjb2wpLHhsaW09YygxLDMpLHBjaD0xOSx4bGFiPSIiKQpwb2ludHMocmVwKDEsMzYpLHByb3N0YWN5Y2xpbiRwcm9zdGFjLW1lYW4ocHJvc3RhY3ljbGluJHByb3N0YWMpLHBjaD0xLGNvbD00KQpwb2ludHMocmVwKDIsMykscHJlZGljdChtb2RlbDEsZGF0YS5mcmFtZShkb3NlPWZhY3RvcihjKDEwLDI1LDUwKSkpKS1tZWFuKHByb3N0YWN5Y2xpbiRwcm9zdGFjKSxwY2g9MTcsY29sPXVuaXF1ZShwcm9zdGFjeWNsaW4kY29sKSxjZXg9MS41KQpwb2ludHMocmVwKDIsMykscHJlZGljdChtb2RlbDEsZGF0YS5mcmFtZShkb3NlPWZhY3RvcihjKDEwLDI1LDUwKSkpKS1tZWFuKHByb3N0YWN5Y2xpbiRwcm9zdGFjKSxwY2g9MixjZXg9MS41LGNvbD0yKQpheGlzKGF0PTE6MyxsYWJlbHM9YyhleHByZXNzaW9uKHBhc3RlKHlbaV0sIiAtICIsYmFyKHkpKSksZXhwcmVzc2lvbihwYXN0ZShiYXIoeSlbal0sIiAtICIsYmFyKHkpKSksZXhwcmVzc2lvbihwYXN0ZSh5W2ldLCIgLSAiLGJhcih5KVtqXSkpKSxzaWRlPTEsY2V4LmF4aXM9MS41KQpgYGAKCiMjIFNTRQoKYGBge3IgZWNobz1GQUxTRSwgd2FybmluZz1GQUxTRX0KcGFyKG1mcm93PWMoMSwyKSkKcGxvdChwcm9zdGFjfmRvc2UsZGF0YT1wcm9zdGFjeWNsaW4seGxhYj0iQXJhY2hpZG9uaWMgYWNpZCBkb3NlICIseWxhYj0iUHJvc3RhY3ljbGluIChuZy9tbCkiLGNleC5heGlzPTEuNSxjZXgubGFiPTEuNSxjZXgubWFpbj0xLjUpCnBvaW50cyhqaXRJayxwcm9zdGFjeWNsaW4kcHJvc3RhYyxjb2w9Y29sLHBjaD0xOSkKcG9pbnRzKGppdElrLHByb3N0YWN5Y2xpbiRwcm9zdGFjLGNvbD0xKQpwb2ludHMoMTozLHByZWRpY3QobW9kZWwxLGRhdGEuZnJhbWUoZG9zZT1mYWN0b3IoYygxMCwyNSw1MCkpKSkscGNoPTE3LGNvbD1jKCJiaXNxdWUiLCJjb3JhbCIsImRhcmtjeWFuIiksY2V4PTEuNSkKcG9pbnRzKDE6MyxwcmVkaWN0KG1vZGVsMSxkYXRhLmZyYW1lKGRvc2U9ZmFjdG9yKGMoMTAsMjUsNTApKSkpLHBjaD0yLGNvbD0yLGNleD0xLjUpCmZvciAoaSBpbiAxOjMpIGxpbmVzKGMoaS0uMixpKy4yKSxyZXAocHJlZGljdChtb2RlbDEsZGF0YS5mcmFtZShkb3NlPWxldmVscyhwcm9zdGFjeWNsaW4kZG9zZSlbaV0pKSwyKSxjb2w9YygiYmlzcXVlIiwiY29yYWwiLCJkYXJrY3lhbiIpW2ldKQphYmxpbmUoaD1tZWFuKHByb3N0YWN5Y2xpbiRwcm9zdGFjKSxsdHk9MSkKZm9yIChpIGluIDE6MzYpIGxpbmVzKHJlcChqaXRJa1tpXSwyKSxjKHByb3N0YWN5Y2xpbiRwcm9zdGFjW2ldLG1vZGVsMSRmaXR0ZWRbaV0pLGNvbD0xLGx0eT0yKQoKcGxvdChyZXAoMSwzNikscHJvc3RhY3ljbGluJHByb3N0YWMtbWVhbihwcm9zdGFjeWNsaW4kcHJvc3RhYykseGF4dD0ibm9uZSIseWxhYj0iRGV2aWF0aW9ucyIsY2V4LmxhYj0xLjUsY2V4Lm1haW49MS41LGNleC5heGlzPTEuNSxjb2w9YXMuY2hhcmFjdGVyKHByb3N0YWN5Y2xpbiRjb2wpLHhsaW09YygxLDMpLHBjaD0xOSx4bGFiPSIiKQpwb2ludHMocmVwKDEsMzYpLHByb3N0YWN5Y2xpbiRwcm9zdGFjLW1lYW4ocHJvc3RhY3ljbGluJHByb3N0YWMpLHBjaD0xLGNvbD00KQpwb2ludHMocmVwKDIsMykscHJlZGljdChtb2RlbDEsZGF0YS5mcmFtZShkb3NlPWZhY3RvcihjKDEwLDI1LDUwKSkpKS1tZWFuKHByb3N0YWN5Y2xpbiRwcm9zdGFjKSxwY2g9MTcsY29sPXVuaXF1ZShwcm9zdGFjeWNsaW4kY29sKSxjZXg9MS41KQpwb2ludHMocmVwKDIsMykscHJlZGljdChtb2RlbDEsZGF0YS5mcmFtZShkb3NlPWZhY3RvcihjKDEwLDI1LDUwKSkpKS1tZWFuKHByb3N0YWN5Y2xpbiRwcm9zdGFjKSxwY2g9Mixjb2w9MixjZXg9MS41KQpwb2ludHMocmVwKDMsMzYpLG1vZGVsMSRyZXMscGNoPTE5LGNvbD1hcy5jaGFyYWN0ZXIocHJvc3RhY3ljbGluJGNvbCkpCnBvaW50cyhyZXAoMywzNiksbW9kZWwxJHJlcyxwY2g9MSkKYXhpcyhhdD0xOjMsbGFiZWxzPWMoZXhwcmVzc2lvbihwYXN0ZSh5W2ldLCIgLSAiLGJhcih5KSkpLGV4cHJlc3Npb24ocGFzdGUoYmFyKHkpW2pdLCIgLSAiLGJhcih5KSkpLGV4cHJlc3Npb24ocGFzdGUoeVtpXSwiIC0gIixiYXIoeSlbal0pKSksc2lkZT0xLGNleC5heGlzPTEuNSkKYGBgCgoKIyMgQW5vdmEgdGVzdAoKVGVzdCAkSF8wOiBcYmV0YV8xPVxiZXRhXzI9MCQgbWV0ICRGJC10ZXN0LgpcWwogIEYgPSBcZnJhY3tcdGV4dHtNU1R9fXtcdGV4dHtNU0V9fQpcXQoKbWV0CgotICRcdGV4dHtNU1R9PVx0ZXh0e1NTVH0vKGctMSkkICAKXHZzcGFjZXsxMHB0fQotICRcdGV4dHtNU0V9PVx0ZXh0e1NTRX0vKG4tcCkkClx2c3BhY2V7MTBwdH0KLSBUZXN0c3RhdGlzdGllayB2ZXJnZWxpamt0IGRlIHZhcmlhYmlsaXRlaXQgdmVya2xhYXJkIGRvb3IgbW9kZWwgKE1TVCkgbWV0IGRlIHJlc2lkdWVsZSB2YXJpYWJpbGl0ZWl0IChNU0UpCgpvZgoKLSBWYXJpYWJpbGl0ZWl0IHR1c3NlbiBncm9lcGVuIChNU1QpIHRvdCB2YXJpYWJpbGl0ZWl0IGJpbm5lbiBncm9lcGVuIChNU0UpClx2c3BhY2V7MTBwdH0KLSBvbmRlciAkSF8wJDogJEYgXHNpbSBGX3tnLTEsbi1nfSQsIG1ldCBnPTMuCgoKIyMgQW5vdmEgVGFiZWwKCnwgfERmfFN1bSBTcXxNZWFuIFNxfEYgdmFsdWV8UHIoPkYpfAp8LS0tfC0tLXwtLS18LS0tfC0tLXwtLS18CnxUcmVhdG1lbnR8ZC5mLiBTU1R8U1NUfE1TVHxGLXN0YXRpc3RpZWt8cC13YWFyZGV8CnxFcnJvcnxkLmYuIFNTRXxTU0V8TVNFfCB8IHwKCmBgYHtyfQphbm92YShtb2RlbDEpCmBgYAoKCiMjIyBGLXZlcmRlbGluZyBtZXQga3JpdGlla2Ugd2FhcmRlICAoJFxhbHBoYSQ9NSUpIGVuIGdlb2JzZXJ2ZWVyZGUgRi1zdGF0aXN0aWVrIHZvb3IgcHJvc3RhY3ljbGluZSB2b29yYmVlbGQKYGBge3IgcHJvc3RhY0YsIG91dC53aWR0aD0nMTAwJScsIGZpZy5hc3A9LjgsIGZpZy5hbGlnbj0nY2VudGVyJyxlY2hvPUZBTFNFfQpncmlkIDwtIHNlcSgwLDE3LC4wMSkKZGYxPWFub3ZhKG1vZGVsMSlbMSwxXQpkZjI9YW5vdmEobW9kZWwxKVsyLDFdCmZ2YWw9YW5vdmEobW9kZWwxKVsxLDRdCmNyaXQ9cWYoMC45NSxkZjEsZGYyKQpyZWplY3Q9Yyhjcml0LGdyaWRbd2hpY2goZ3JpZD5jcml0KV0pCmFjY2VwdD1jKGdyaWRbd2hpY2goZ3JpZDxjcml0KV0sY3JpdCkKcGxvdChncmlkLGRmKGdyaWQsZGYxLGRmMiksdHlwZT0ibCIseWxhYj0iRGVuc2l0eSIseGxhYj0iRi1zdGF0aXN0aWMiLGNleC5heGlzPTEuNSxjZXgubGFiPTEuNSkKcG9seWdvbihjKDAsYWNjZXB0LGNyaXQsMCksYygwLGRmKGFjY2VwdCxkZjEsZGYyKSwwLDApLGNvbD0iYmx1ZSIsYm9yZGVyPSJibHVlIikKdGV4dChjcml0LzIsLjk3LGxhYmVscz0iYWNjZXB0XG45NSUiLGNvbD0iYmx1ZSIsY2V4PTEuNSkKcG9seWdvbihjKGNyaXQscmVqZWN0LDE1LGNyaXQpLGMoMCxkZihyZWplY3QsZGYxLGRmMiksMCwwKSxjb2w9InJlZCIsYm9yZGVyPSJyZWQiKQphYmxpbmUodj1jcml0LGNvbD0icmVkIixsd2Q9MikKdGV4dChjcml0KyhmdmFsLWNyaXQpLzIsLjk3LGxhYmVscz0icmVqZWN0XG41JSIsY29sPSJyZWQiLGNleD0xLjUpCnRleHQocG9zPTQsY3JpdCxkZihjcml0LDIsMzMpLGxhYmVscz1wYXN0ZTAoIkYoMC4wNSwiLGRmMSwiLCIsZGYyLCIpIiksY29sPSJyZWQiLGNleD0xLjUpCnRleHQocG9zPTQsZnZhbCxkZihjcml0LGRmMSxkZjIpLGxhYmVscz1wYXN0ZTAoImY9Iixyb3VuZChmdmFsLDEpKSxjb2w9ImRhcmtvcmFuZ2UiLGNleD0xLjUpCmFibGluZSh2PWZ2YWwsY29sPSJkYXJrb3JhbmdlIixsd2Q9MixsdHk9MikKdGV4dCgxNS41LC45NyxsYWJlbHM9cGFzdGUwKCJwLXZhbHVlXG4iLGZvcm1hdChhbm92YShtb2RlbDEpWzEsNV0sZGlnaXRzPTIpKSxjb2w9ImRhcmtvcmFuZ2UiLGNleD0xLjUpCmFycm93cyh4MD0xNy41LHgxPWZ2YWwseTA9LjkseTE9LjksY29sPSJkYXJrb3JhbmdlIikKYGBgCgoKIyMjIEYtdmVyZGVsaW5nIG1ldCB2ZXJzY2hpbGxlbmQgYWFudGFsIHZyaWpoZWlkc2dyYWRlbiBpbiBkZSBub2VtZXIgZW4gdGVsbGVyCmBgYHtyIGZ0aGVvLCBvdXQud2lkdGg9JzEwMCUnLCBmaWcuYXNwPS44LCBmaWcuYWxpZ249J2NlbnRlcicsZWNobz1GQUxTRX0KcGxvdChncmlkLGRmKGdyaWQsMSw1KSx0eXBlPSJsIix5bGFiPSJEZW5zaXR5Iix4bGFiPSJGLXN0YXRpc3RpYyIseGxpbT1jKDAsNSkseWxpbT1jKDAsMS41KSxsd2Q9MixjZXguYXhpcz0xLjUsY2V4LmxhYj0xLjUpCmxpbmVzKGdyaWQsZGYoZ3JpZCw1LDUpLHR5cGU9ImwiLGNvbD0yLGx3ZD0yKQpsaW5lcyhncmlkLGRmKGdyaWQsMTAsMzApLHR5cGU9ImwiLGNvbD0zLGx3ZD0yKQpsaW5lcyhncmlkLGRmKGdyaWQsMjAsMzApLHR5cGU9ImwiLGNvbD00LGx3ZD0yKQpsaW5lcyhncmlkLGRmKGdyaWQsNTAsNTApLHR5cGU9ImwiLGNvbD01LGx3ZD0yKQpsZWdlbmQoInRvcHJpZ2h0IixsdHk9MSxjb2w9YygxLDIsMyw0LDUpLGxlZ2VuZD1jKCJGKDEsNSkiLCJGKDUsNSkiLCJGKDEwLDMwKSIsIkYoMjAsMzApIiwiRig1MCw1MCkiKSxsd2Q9MixjZXg9MS41KQpgYGAKCiMjIyBQcm9zdGFjeWNsaW4gdm9vcmJlZWxkOiB3ZWxrZSBncm9lcGVuIHppam4gdmVyc2NoaWxsZW5kPwoKYGBge3J9CnN1bW1hcnkobW9kZWwxKQpgYGAKCgpNZXQgb3V0cHV0IHZhbiBtb2RlbCBrdW5uZW4gd2Ugb29rIHRlc3RlbiBvZiBkZSBnZW1pZGRlbGRlIHByb3N0YWN5Y2xpbmUgY29uY2VudHJhdGllIHZlcnNjaGlsbGVuZCBpcyB0dXNzZW4gZGUgbWF0aWdlIGVuIGxhZ2UgZG9zaXMgZ3JvZXAgKCRcYmV0YV8xJDogZG9zZTI1KSBlbiB0dXNzZW4gZGUgaG9nZSBlbiBsYWdlIGRvc2lzIGdyb2VwICgkXGJldGFfMiQ6IGRvc2U1MCkuCgpEZSBwLXdhYXJkZW4gaG91ZGVuIGdlZW4gcmVrZW5pbmcgbWV0IGhldCBmZWl0IGRhdCB3ZSBtZWVydm91ZGlnIHRvZXRzZW4uCgojIFBvc3QgaG9jIGFuYWx5c2lzOiBNZWVyZGVyZSB2ZXJnZWxpamtpbmdlbiB2YW4gZ2VtaWRkZWxkZW4KCiMjIE5hw69ldmUgbWV0aG9kZQoKCgpJbiBlZXJzdGUgZGVlbCB2YW4gZGl0IGhvb2Zkc3R1ayBoZWJiZW4gd2UgJEYkLXRlc3QgYmVzcHJva2VuIHZvb3IgaGV0IHRlc3RlbiB2YW4KCiQkICBIXzA6IFxtdV8xPVxjZG90cyA9IFxtdV9nIFx0ZXh0eyB2ZXJzdXMgfSBIXzE6IEhfMTogXGV4aXN0c1wgaixrIFxpbiBcezEsXGxkb3RzLGdcfSA6IFxtdV9qXG5lcVxtdV9rJCQKCi0gQWxzIHdlICRIXzAkIHZlcndlcnBlbiBiZXNsdWl0ZW4gd2UgZGF0IGVyIG1pbnN0ZW5zIHR3ZWUgZ2VtaWRkZWxkZW4gdmVyc2NoaWxsZW4gdmFuIGVsa2Fhci4KCi0gRGUgbWV0aG9kZSBuaWV0IGluIHN0YWF0IG9tIHRlIGlkZW50aWZpY2VyZW4gd2Vsa2UgZ2VtaWRkZWxkZW4gdmFuIGVsa2FhciB2ZXJzY2hpbGxlbi4KCgpFZW4gZWVyc3RlLCBtYWFyIG5hw69ldmUgYmVuYWRlcmluZzogICRIXzAkIG9wc3BsaXRzZW4gaW4gcGFydGnDq2xlIGh5cG90aGVzZXMKJCRIX3swamt9OiBcbXVfaj1cbXVfayBcdGV4dHsgdmVyc3VzIH0gSF97MWprfTogXG11X2ogXG5lcSBcbXVfayQkCgotIHBhcnRpw6tsZSBoeXBvdGhlc2VzIHRlc3RlbiBtZXQgdHdvLXNhbXBsZSAkdCQtdGVzdGVuCgotIFZvb3IgdmVyZ2VsaWprZW4gdmFuIGdyb2VwICRqJCBtZXQgZ3JvZXAgJGskIHdvcmR0ICBrbGFzc2lla2UgdHdvLXNhbXBsZSAkdCQtdGVzdCBvbmRlciBnZWxpamtoZWlkIHZhbiB2YXJpYW50aWUgZ2VnZXZlbiBkb29yOgokJFRfe2prfSA9IFxmcmFje1xiYXJ7WX1fai1cYmFye1l9X2t9e1NfcFxzcXJ0e1xmcmFjezF9e25fan0rXGZyYWN7MX17bl9rfX19IFxzaW0gdF97bi0yfSQkCgpNZXQKCi0gJFNfcF4yJCBkZSBnZXBvb2xkZSB2YXJpYW50aWVzY2hhdHRlciBpcywKJCRTX3BeMiA9IFxmcmFjeyhuX2otMSlTX2peMiArIChuX2stMSlTX2teMn17bl9qK25fay0yfSQkCgotIG1ldCAkU19qXjIkIGVuICRTX2teMiQgZGUgc3RlZWtwcm9lZnZhcmlhbnRpZXMgdmFuIHJlc3BlY3RpZXZlbGlqayBkZSB1aXRrb21zdGVuIHVpdCBncm9lcCAkaiQgZW4gJGskLgoKLS0tCgoKSW4gQU5PVkEgY29udGV4dCB2ZXJvbmRlcnN0ZWxsZW4gd2UgZGF0IHZhcmlhbnRpZSBpbiAgKiphbGxlKiogJGckIGdyb2VwZW4gZGV6ZWxmZGUgaXM6IGRlIHJlc2lkdWVsZSB2YXJpYW50aWUgJFxzaWdtYV4yJC4KCi0gR2VicnVpayB2YW4gJFNfcF4yJCBpcyBuaWV0IGVmZmljacOrbnQgb21kYXQgZGllIG5pZXQgdmFuIGFsbGUgZGF0YSBnZWJydWlrIG1hYWt0CgotIEFhbiBlZmZpY2nDq250aWUgd2lubmVuIGRvb3IgZG9vciBNU0UgdGUgZ2VicnVpa2VuCiQkXHRleHR7TVNFfT0gXHN1bV97aj0xfV5nIFxmcmFjeyhuX2otMSlTX2peMn17bi1nfSQkCgotIERlICR0JC10ZXN0ZW4gd29yZGVuIGR1cyBiZXN0IGdlYmFzZWVyZCBvcAokJFRfe2prfSA9IFxmcmFje1xiYXJ7WX1fai1cYmFye1l9X2t9e1x0ZXh0e01TRX1cc3FydHtcZnJhY3sxfXtuX2p9K1xmcmFjezF9e25fa319fSBcc2ltIHRfe24tZ30uJCQKCi0tLQoKYGBge3J9CndpdGgoCiAgcHJvc3RhY3ljbGluLAogIHBhaXJ3aXNlLnQudGVzdChwcm9zdGFjLCBkb3NlLCAibm9uZSIpCiAgKQpgYGAKCkhldCB3ZXJrZW4gbWV0ICRtJC10ZXN0ZW4gb3AgaGV0ICRcYWxwaGEkIHNpZ25pZmljYW50aWVuaXZlYXUgaXMgZWNodGVyIGVlbiBmb3V0ZSBhYW5wYWsgZGllIGRlIGthbnMgb3AgZWVuIHR5cGUgSSBmb3V0IG5pZXQgb25kZXIgY29udHJvbGUga2FuIGhvdWRlbi4KCiMjIFdlIHRvbmVuIGFhbiBkYXQgbmHDr3ZlIG1ldGhvZGUgbmlldCB3ZXJrdCB2aWEgc2ltdWxhdGllCgoxLiBXZSBzaW11bGVyZW4gdWl0IGVlbiBBTk9WQSBtb2RlbCBtZXQgJGc9MyQgZ3JvZXBlbi4KMi4gRGUgZ2VtaWRkZWxkZW4gaW4gaGV0IEFOT1ZBIG1vZGVsIHppam4gZ2VsaWprIGFhbiBlbGthYXIsIHpvZGF0IGRlIG51bGh5cG90aGVzZSAkJEhfMDogXG11XzE9XG11XzI9XG11XzMkJCBvcGdhYXQuCjMuIFZvb3IgaWVkZXJlIGdlc2ltdWxlZXJkZSBkYXRhc2V0IHppam4gZXIgJG09MyQgcGFhcnNnZXdpanplIHR3by1zYW1wbGUgJHQkLXRlc3Rlbgo0LiBab2RyYSBtaW5zdGVucyDDqcOpbiB2YW4gZGUgJHAkLXdhYXJkZW4ga2xlaW5lciBpcyBkYW4gaGV0IHNpZ25pZmljYW50aWVuaXZlYXUgJFxhbHBoYT01XCUkLCB3b3JkdCBkZSBudWxoeXBvdGhlc2UgJEhfMDogXG11XzE9XG11XzI9XG11XzMkIHZlcndvcnBlbiBvbWRhdCBlciBtaW5zdGVucyB0d2VlIGdlbWlkZGVsZGVuIHZlcnNjaGlsbGVuZCB6aWpuIHZvbGdlbnMgZGUgJHQkLXRlc3Rlbi4KNS4gV2UgcmFwcG9ydGVyZW4gZGUgcmVsYXRpZXZlIGZyZXF1ZW50aWUgdmFuIGhldCB2ZXJ3ZXJwZW4gdmFuIGRlIGdsb2JhbGUgbnVsaHlwb3RoZXNlLCBtZWVyIGJlcGFhbGQgZGUga2FucyBvcCBlZW4gdHlwZSBJIGZvdXQgdmFuIGRlIHRlc3Qgdm9vciAgJEhfMDogXG11XzE9XG11XzI9XG11XzMkLgoKCmBgYHtyfQpnIDwtIDMgIyBhYW50YWwgYmVoYW5kZWxpbmdlbiAoZz0zKQpuaSA8LSAxMiAjIGFhbnRhbCBoZXJoYWxpbmdlbiBpbiBpZWRlcmUgZ3JvZXAKbiA8LSBnKm5pICMgdG90YWFsIGFhbnRhbCBvYnNlcnZhdGllcwphbHBoYSA8LSAwLjA1ICMgc2lnbmlmaWNhbnRpZW5pdmVhdSB2YW4gZWVuIGluZGl2aWR1ZWxlIHRlc3QKTiA8LSAxMDAwMCAjYWFudGFsIHNpbXVsYXRpZXMKc2V0LnNlZWQoMzAyKSAjc2VlZCB6b2RhdCByZXN1bHRhdGVuIGV4YWN0IGdlcHJvZHVjZWVyZCBrdW5uZW4gd29yZGVuCnRydCA8LSBmYWN0b3IocmVwKDE6ZywgbmkpKSAjZmFjdG9yCmNudCA8LSAwICN0ZWxsZXIgdm9vciBhYW50YWwgZm91dGlldmUgdmVyd2VycGluZ2VuCgpmb3IoaSBpbiAxOk4pIHsKaWYgKGkgJSUgMTAwMCA9PSAwKSBjYXQoaSwgIi8iLCBOLCAiXG4iKQp5IDwtIHJub3JtKG4pCnRlc3RzIDwtIHBhaXJ3aXNlLnQudGVzdCh5LCB0cnQsICJub25lIikKdmVyd2VycCA8LSBtaW4odGVzdHMkcC52YWx1ZSwgbmEucm0gPSBUKSA8IGFscGhhCmlmKHZlcndlcnApIGNudCA8LSBjbnQrMQp9CmNudC9OCmBgYAoKLS0tCgotIEthbnMgb3AgZWVuIHR5cGUgSSBmb3V0IGdlbGlqayBpcyBhYW4gYHIgcm91bmQoY250L04sMykqMTAwYCUKCi0gSXMgbWVlciBkYW4gZHViYmVsIHpvIGdyb290IGlzIGRhbiB2b29yb3BnZXN0ZWxkZSAkXGFscGhhPTUkJS4KCi0gQWxzIHdlIHNpbXVsYXRpZXN0dWRpZSBoZXJoYWxlbiBtZXQgZyA9IDUgZ3JvZXBlbiAoaS5lLiAxMCBwYWFyc2dld2lqemUgdC10ZXN0ZW4pIGRhbiB2aW5kZW4gd2UgMjguMCUgaW4gcGxhYXRzIHZhbiBkZSBnZXdlbnN0ZSA1JS4KCi0gRGV6ZSBzaW11bGF0aWVzIGlsbHVzdHJlcmVuIGhldCBwcm9ibGVlbSB2YW4gKiptdWx0aXBsaWNpdGVpdCoqIChFbmdlbHM6ICptdWx0aXBsaWNpdHkqKQoKICAtIGtsYXNzaWVrZSAkcCQtd2FhcmRlbiAgbW9nZW4gZW5rZWwgbWV0IGhldCBzaWduaWZpY2FudGllbml2ZWF1ICRcYWxwaGEkIHZlcmdlbGVrZW4gd29yZGVuLCBpbmRpZW4gaGV0IGJlc2x1aXQgb3AgZXhhY3Qgw6nDqW4gJHAkLXdhYXJkZSBnZWJhc2VlcmQgaXMuCiAgLSBGaW5hbGUgYmVzbHVpdCAoYWwgZGFuIG5pZXQgdmVyd2VycGVuIHZhbiAkSF8wOiBcbXVfMT1cY2RvdHMgPVxtdV9nJCkgZ2ViYXNlZXJkIG9wICRtPWdcdGltZXMoZy0xKS8yJCAkcCQtd2FhcmRlbi4KCi0gV2UgYmVzcHJla2VuIGVlcnN0IGVlbiB1aXRicmVpZGluZyB2YW4gaGV0IGJlZ3JpcCB2YW4gdHlwZSBJIGZvdXQgZW4gdmVydm9sZ2VucyBpbnRyb2R1Y2VyZW4gd2UgZW5rZWxlIG9wbG9zc2luZ2VuLgoKIyMgRmFtaWx5LXdpc2UgZXJyb3IgcmF0ZQoKLSBXYW5uZWVyICRtPjEkIHRvZXRzZW4gd29yZGVuIGFhbmdld2VuZCBvbSAxIGJlc2xpc3NpbmcgdGUgdm9ybWVuLCBpcyBoZXQgbm9vZHpha2VsaWprIHRlIGNvcnJpZ2VyZW4gdm9vciBoZXQgcmlzaWNvIG9wIHZhbHMgcG9zaXRpZXZlIHJlc3VsdGF0ZW4gKHR5cGUgSSBmb3V0KS4KXHZzcGFjZXsxMHB0fQotIE1lZXN0ZSBwcm9jZWR1cmVzIHZvb3IgbWVlcnZvdWRpZyB0b2V0c2VuIGdhYW4gZXJ2YW4gdWl0IGRhdCAqYWxsZSAkbSQgbnVsaHlwb3RoZXNlcyB3YWFyKiB6aWpuLgpcdnNwYWNlezEwcHR9Ci0gRXIgd29yZHQgZGFuIGdlcHJvYmVlcmQgb20gaGV0ICpyaXNpY28gb3AgbWluc3RlbnMgMSB2YWxzIHBvc2l0aWVmIHJlc3VsdGFhdCogdGUgY29udHJvbGVyZW4gb3AgKipleHBlcmltZW50Z2V3aWpzIHNpZ25pZmljYW50aWVuaXZlYXUgJFxhbHBoYV9FJCoqLCB0eXBpc2NoICRcYWxwaGFfRT0wLjA1JC4KXHZzcGFjZXsxMHB0fQotIEluIGRlIEVuZ2Vsc3RhbGlnZSBsaXRlcmF0dXVyIHdvcmR0IGhldCBleHBlcmltZW50Z2V3aWpzIHNpZ25pZmljYW50aWVuaXZlYXUgKmZhbWlseS13aXNlIGVycm9yIHJhdGUgKEZXRVIpKiBnZW5vZW1kLgoKCiMjIEJvbmZlcnJvbmkgY29ycmVjdGlvbgoKQmlqIGhldCB1aXR2b2VyZW4gdmFuICRtJCBvbmFmaGFua2VsaWprZSB0b2V0c2VuIG1ldCBlbGsgc2lnbmlmaWNhbnRpZW5pdmVhdSAkXGFscGhhJCwgaXMKXGJlZ2lue2VxbmFycmF5Kn0KXGFscGhhX0UmPSZcdGV4dHtQfVtcdGV4dHttaW5zdGVucyAxIFR5cGUgSSBmb3V0fV1cXAomPSYxLSgxLVxhbHBoYSlebSBcbGVxIG1cYWxwaGEKXGVuZHtlcW5hcnJheSp9CgotIEFscyB3ZSAzIHRvZXRzZW4gdWl0dm9lcmVuIG9wIGhldCA1XCUgc2lnbmlmaWNhbnRpZW5pdmVhdSBpcyBGV0VSICRcYXBwcm94IDE1XCUkLgpcdnNwYWNlezEwcHR9Ci0gRG9vciB6ZSBvcCBoZXQgMVwlIHNpZ25pZmljYW50aWVuaXZlYXUgdWl0IHRlIHZvZXJlbiwgYmVrb21lbiB3ZSBGV0VSICRcYXBwcm94IDVcJSQuClx2c3BhY2V7MTBwdH0KLSBEZSBCb25mZXJyb25pIGNvcnJlY3RpZSBob3VkdCBkZSBGV0VSIGJlZ3JlbnNkIG9wICRcYWxwaGFfRSQgZG9vciAkJFxhbHBoYT1cYWxwaGFfRS9tJCQgdGUga2llemVuIHZvb3IgaGV0IHVpdHZvZXJlbiB2YW4gZGUgJG0kIHBhYXJzZ2V3aWp6ZSB2ZXJnZWxpamtpbmdlbi4KCi0tLQoKQWxzIGFsdGVybmF0aWV2ZSBtZXRob2RlIGt1bm5lbiB3ZSBvb2sKCiAgMS4gKmFhbmdlcGFzdGUgcC13YWFyZGVuKiByYXBwb3J0ZXJlbiB6b2RhdCB3ZSBkZXplIG1ldCBoZXQgZXhwZXJpbWVudGdld2lqemUgJFxhbHBoYV9FJCBuaXZlYXUga3VubmVuIHZlcmdlbGlqa2VuOiAkJFx0aWxkZXtwfT1taW4obVx0aW1lcyBwLDEpJCQKCiAgMi4gJCgxLVxhbHBoYV9FL20pMTAwXCUkIGJldHJvdXdiYWFyaGVpZHNpbnRlcnZhbGxlbiByYXBwb3J0ZXJlbi4KCiMjIyBQcm9zdGFjeWNsaW4gdm9vcmJlZWxkCgpgYGB7cn0Kd2l0aCgKICBwcm9zdGFjeWNsaW4sCiAgcGFpcndpc2UudC50ZXN0KAogICAgcHJvc3RhYywKICAgIGRvc2UsCiAgICBwLmFkanVzdC5tZXRob2Q9ImJvbmZlcnJvbmkiKQogICkKYGBgCgotIENvbmNsdXNpZXMgYmxpanZlbiBnZWxpamsgYmVoYWx2ZSBkYXQgRldFUiBudSBnZWNvbnRyb2xlZXJkIGlzICRcYWxwaGFfRT01XCUkIGVuICRcdGlsZGV7cH0kLXdhYXJkZW4gemlqbiBmYWN0b3IgMyBncm90ZXIKCi0tLQoKWmVsZmRlIGFuYWx5c2Uga2FuIHZpYSBgbXVsdGNvbXBgIFIgcGFja2FnZSBvbnR3aWtrZWxkIHZvb3IgbXVsdGlwbGljaXRlaXQgaW4gbGluZWFpcmUgbW9kZWxsZW4uCgpgYGB7cn0KbGlicmFyeShtdWx0Y29tcCkKYGBgCgpgYGB7cn0KbGlicmFyeShtdWx0Y29tcCkKbW9kZWwxLm1jcCA8LSBnbGh0KG1vZGVsMSwgbGluZmN0ID0gbWNwKGRvc2UgPSAiVHVrZXkiKSkKc3VtbWFyeShtb2RlbDEubWNwLCB0ZXN0ID0gYWRqdXN0ZWQoImJvbmZlcnJvbmkiKSkKYGBgCgotLS0KCk9tIEJvbmZlcnJvbmkgYWFuZ2VwYXN0ZSBiZXRyb3V3YmFhcmhlaWRzaW50ZXJ2YWxsZW4gdGUgdmVya3JpamdlbiBtb2V0ZW4gd2UgZWVyc3QgemVsZiBmdW5jdGllIGRlZmluacOrcmVuIGluIFIgb20gYm9uZmVycm9uaSBrcml0aXNjaGUgd2FhcmRlIHRlIGJlcGFsZW4uCgotIEJvbmZlcm9ubmktYmV0cm91d2JhYXJoZWlkc2ludGVydmFsbGVuIHdvcmRlbiBuaWV0IGdlw69tcGxlbWVudGVlcmQgb21kYXQgZXIgYmV0ZXJlIG1ldGhvZGVuIGJlc3RhYW4gdm9vciBtZWVydm91ZGlnZSB0ZXN0cy4KCi0gRGUgb25kZXJzdGFhbmRlIGZ1bmN0aWUgaXMgaGllciBhbGxlZW4gdm9vciBkZSB2b2xsZWRpZ2hlaWQgdG9lZ2V2b2VnZCwgbWFhciB3ZSB6dWxsZW4gb3ZlciBoZXQgYWxnZW1lZW4gZGUgc3RhbmRhYXJkbWV0aG9kZSBnZWJydWlrZW4gdm9vciBtZWVydm91ZGlnZSB0ZXN0cyBpbiBtdWx0Y29tcC4KCmBgYHtyfQpjYWxwaGFfYm9uX3QgPC0gZnVuY3Rpb24ob2JqZWN0LCBsZXZlbCkKewogIGFicygKICAgIHF0KAogICAgICAoMS1sZXZlbCkvMi9ucm93KG9iamVjdCRsaW5mY3QpLAogICAgICBvYmplY3QkZGYpCiAgICApCn0KYGBgCgpgYGB7cn0KY29uZmludChtb2RlbDEubWNwLCBjYWxwaGEgPSBjYWxwaGFfYm9uX3QpCmBgYAoKIyMjIFNpbXVsYXRpZSBvbSBCb25mZXJyb25pIG1ldGhvZGUgdGUgZXZhbHVlcmVuCgpgYGB7cn0KZyA8LSAzICMgYWFudGFsIGJlaGFuZGVsaW5nZW4gKGc9MykKbmkgPC0gMTIgIyBhYW50YWwgaGVyaGFsaW5nZW4gaW4gaWVkZXJlIGdyb2VwCm4gPC0gZypuaSAjIHRvdGFhbCBhYW50YWwgb2JzZXJ2YXRpZXMKYWxwaGEgPC0gMC4wNSAjIHNpZ25pZmljYW50aWVuaXZlYXUgdmFuIGVlbiBpbmRpdmlkdWVsZSB0ZXN0Ck4gPC0gMTAwMDAgI2FhbnRhbCBzaW11bGF0aWVzCnNldC5zZWVkKDMwMikgI3NlZWQgem9kYXQgcmVzdWx0YXRlbiBleGFjdCBnZXByb2R1Y2VlcmQga3VubmVuIHdvcmRlbgp0cnQgPC0gZmFjdG9yKHJlcCgxOmcsIG5pKSkgI2ZhY3RvcgpjbnQgPC0gMCAjdGVsbGVyIHZvb3IgYWFudGFsIGZvdXRpZXZlIHZlcndlcnBpbmdlbgoKZm9yKGkgaW4gMTpOKSB7CmlmIChpICUlIDEwMDAgPT0gMCkgY2F0KGksICIvIiwgTiwgIlxuIikKeSA8LSBybm9ybShuKQp0ZXN0cyA8LSBwYWlyd2lzZS50LnRlc3QoeSwgdHJ0LCAiYm9uZmVycm9uaSIpCnZlcndlcnAgPC0gbWluKHRlc3RzJHAudmFsdWUsIG5hLnJtID0gVCkgPCBhbHBoYQppZih2ZXJ3ZXJwKSBjbnQgPC0gY250KzEKfQpjbnQvTgpgYGAKCgoKLSBXZSB2aW5kZW4gZWVuIEZXRVIgdmFuIGByIHJvdW5kKGNudC9OKjEwMCwxKWAlIChlZW4gYmVldGplIGNvbnNlcnZhdGllZikKCi0gQmlqIHNpbXVsYXRpZXMgdm9vciAkZz01JCBncm9lcGVuLCB2aW5kZW4gd2UgZWVuIEZXRVIgdmFuICQ0LjFcJSQgKGNvbnNlcnZhdGlldmVyKS4KCi0gRG9vciBCb25mZXJyb25pIGNvcnJlY3RpZSBpcyBrYW5zIG9wIG1pbnN0ZW5zIMOpw6luIHZhbHMgcG9zaXRpZWYgcmVzdWx0YWF0ICQ8IFxhbHBoYV9FJC4KCi0gUG93ZXIgdmVybGllcyBhYW5nZXppZW4gd2Vya2VsaWprZSBuaXZlYXUgbGFnZXIgaXMgZGFuIGhldCB2b29yb3BnZXN0ZWxkZSA1JSBleHBlcmltZW50c2dld2lqcyBzaWduaWZpY2FudGllbml2ZWF1LgoKIyMgVHVrZXkgTWV0aG9kZQoKCi0gTWluZGVyIGNvbnNlcnZhdGlldmUgbWV0aG9kZQoKLSBJbXBsZW1lbnRhdGllIGJlbmFkZXJ0IGRlIG51bGRpc3RyaWJ1dGllIHZhbiBkZSBwb3N0aG9jIHRlc3QgZC5tLnYuIHNpbXVsYXRpZXMuCgotIFJlc3VsdGF0ZW4ga3VubmVuIGxpY2h0amVzIHZlcnNjaGlsbGVuIHdhbm5lZXIgamUgcG9zdGhvYyBhbmFseXNlIG9wbmlldXcgdWl0dm9lcnQuCgotIERldGFpbHMgdmFuIGRlIG1ldGhvZGUgdmFsbGVuIGJ1aXRlbiBoZXQgYmVzdGVrIHZhbiBkZXplIGN1cnN1cy4KCi0gSW1wbGVtZW50YXRpZSBpbiBtdWx0Y29tcCBwYWNrYWdlOgoKICAgIC0gYWFuZ2VwYXN0ZSBwLXdhYXJkZW4KCiAgICAtIGFhbmdlcGFzdGUgYmV0cm91d2JhYXJoZWlkc2ludGVydmFsbGVuCgogICAgLSBOaWV0IG5vZGlnIG9tIGZ1bmN0aWVzIHRlIGRlZmluacOrcmVuIHZvb3IgVHVrZXkgZ2Vjb3JyaWdlZXJkZSBCSXMKCgojIyMgQ2FwdG9wcmlsIHZvb3JiZWVsZAoKYGBge3J9Cm1vZGVsMS5tY3AgPC0gZ2xodChtb2RlbDEsIGxpbmZjdCA9IG1jcChkb3NlID0gIlR1a2V5IikpCnN1bW1hcnkobW9kZWwxLm1jcCkKYGBgCgoKYGBge3J9CmNvbmZpbnQobW9kZWwxLm1jcCkKYGBgCgoKYGBge3Igb3V0LndpZHRoPScxMDAlJywgZmlnLmFzcD0uOCwgZmlnLmFsaWduPSdjZW50ZXInfQptb2RlbDEubWNwICU+JQogIGNvbmZpbnQgJT4lCiAgcGxvdApgYGAKCiMjIyBFdmFsdWVlciBUdWtleSBtZXRob2RlIGluIGVlbiBzaW11bGF0aWVzdHVkaWUKCmBgYHtyfQpnIDwtIDMgIyBhYW50YWwgYmVoYW5kZWxpbmdlbiAoZz0zKQpuaSA8LSAxMiAjIGFhbnRhbCBoZXJoYWxpbmdlbiBpbiBpZWRlcmUgZ3JvZXAKbiA8LSBnKm5pICMgdG90YWFsIGFhbnRhbCBvYnNlcnZhdGllcwphbHBoYSA8LSAwLjA1ICMgc2lnbmlmaWNhbnRpZW5pdmVhdSB2YW4gZWVuIGluZGl2aWR1ZWxlIHRlc3QKTiA8LSAxMDAwMCAjYWFudGFsIHNpbXVsYXRpZXMKc2V0LnNlZWQoMzAyKSAjc2VlZCB6b2RhdCByZXN1bHRhdGVuIGV4YWN0IGdlcHJvZHVjZWVyZCBrdW5uZW4gd29yZGVuCnRydCA8LSBmYWN0b3IocmVwKDE6ZywgbmkpKSAjZmFjdG9yCmNudCA8LSAwICN0ZWxsZXIgdm9vciBhYW50YWwgZm91dGlldmUgdmVyd2VycGluZ2VuCgpmb3IoaSBpbiAxOk4pIHsKaWYgKGkgJSUgMTAwMCA9PSAwKSBjYXQoaSwgIi8iLCBOLCAiXG4iKQp5IDwtIHJub3JtKG4pCm0gPC0gbG0oeSB+IHRydCkKbS5tY3AgPC0gZ2xodChtLCBsaW5mY3QgPSBtY3AodHJ0ID0gIlR1a2V5IikpCnRlc3RzIDwtIHN1bW1hcnkobS5tY3ApJHRlc3QKdmVyd2VycCA8LSBtaW4oCiAgYXMubnVtZXJpYyh0ZXN0cyRwdmFsdWVzKSwKICBuYS5ybT1UKSA8IGFscGhhCmlmKHZlcndlcnApIGNudCA8LSBjbnQrMQp9CmNudC9OCmBgYAoKRGUgbWV0aG9kZSB3b3JkdCBtb29pIG9wIGhldCA1JSBleHBlcmltZW50c2dld2lqcyBzaWduaWZpY2FudGllbml2ZWF1IGdlY29udHJvbGVlcmQuCgojIENvbmNsdXNpZXM6IFByb3N0YWN5Y2xpbmUgdm9vcmJlZWxkCgpWb2xsZWRpZ2UgYW5hbHlzZSB2b29yIHZvb3JiZWVsZCBwcm9zdGFjeWNsaW5lCgoxLiBBbm92YSB2w7PDs3IgcG9zdGhvYy10ZXN0czogRi10ZXN0IGhlZWZ0IGVlbiBob2dlcmUgcG93ZXIgZGFuIHBhYXJzZ2V3aWp6ZSB0LXRlc3QKCiAgICAtIEYtdGVzdCBnZWJydWlrdCBhbGxlIGdlZ2V2ZW5zCiAgICAtIFZvb3IgRi10ZXN0IGhvZXZlbiB3ZSBuaWV0IHRlIGNvcnJpZ2VyZW4gdm9vciBtZWVydm91ZGlnZSB0ZXN0ZW46IGVyIHdvcmR0IMOpw6luIHRlc3QgdWl0Z2V2b2VyZCB2b29yIGRlIGFsZ2VtZW5lIG9tbmlidXNoeXBvdGhlc2UKCmBgYHtyfQptb2RlbDEgPC0gbG0ocHJvc3RhYyB+IGRvc2UsIGRhdGEgPSBwcm9zdGFjeWNsaW4pCmFub3ZhKG1vZGVsMSkKYGBgCgpgYGB7cn0KbW9kZWwxLm1jcCA8LSBnbGh0KG1vZGVsMSwgbGluZmN0ID0gbWNwKGRvc2UgPSAiVHVrZXkiKSkKc3VtbWFyeShtb2RlbDEubWNwKQpgYGAKCmBgYHtyfQpjb25maW50KG1vZGVsMS5tY3ApCmBgYAoKCi0gRXIgaXMgZWVuIGV4dHJlZW0gc2lnbmlmaWNhbnQgZWZmZWN0IHZhbiBhcmFjaGlkb256dXVyIG9wIGRlIGdlbWlkZGVsZGUgYmxvZWRjb25jZW50cmF0aWUgdmFuIHByb3N0YWN5Y2xpbmUgYmlqIHJhdHRlbiAoJHA8MC4wMDEkKS4KRGUgZ2VtaWRkZWxkZSBwcm9zdGFjeWNsaW5lY29uY2VudHJhdGllIGlzIGhvZ2VyIGluIGRlIGhvZ2UgZG9zaXNncm9lcCBkYW4gaW4gZGUgbGFnZSBlbiBtYXRpZ2UgZG9zaXNncm9lcCAoYmVpZGUgcC13YWFyZGVzIHppam4ga2xlaW5lciBkYW4gJHA8MC4wMDEkKS4KLSBEZSBnZW1pZGRlbGRlIGNvbmNlbnRyYXRpZSBpbiBkZSBob2dlIGRvc2lzZ3JvZXAgaXMgYHIgcm91bmQoY29uZmludChtb2RlbDEubWNwKSRjb25maW50WzIsMV0sMSlgbmcvbWwgKDk1JSBDSSBbYHIgcGFzdGUocm91bmQoY29uZmludChtb2RlbDEubWNwKSRjb25maW50WzIsMjozXSwxKSxjb2xsYXBzZT0iLCIpYF1uZy9tbCkgZW4gYHIgcm91bmQoY29uZmludChtb2RlbDEubWNwKSRjb25maW50WzMsMV0sMSlgbmcvbWwgKDk1JSBCSSBbYHIgcGFzdGUocm91bmQoY29uZmludChtb2RlbDEubWNwKSRjb25maW50WzMsMjozXSwxKSxjb2xsYXBzZT0iLCIpYF1uZy9tbCkgaG9nZXIgZGFuIGluIGRlIGxhZ2UgZW4gbWF0aWdlIGRvc2lzZ3JvZXAsIHJlc3BlY3RpZXZlbGlqay4KLSBIZXQgdmVyc2NoaWwgaW4gZ2VtaWRkZWxkZSBwcm9zdGFjeWNsaW5lY29uY2VudHJhdGllIHR1c3NlbiBkZSBtYXRpZ2UgZW4gbGFnZSBkb3Npc2dyb2VwIGlzIG5pZXQgc2lnbmlmaWNhbnQgIChwPWByIHJvdW5kKHN1bW1hcnkobW9kZWwxLm1jcCkkdGVzdCRwdmFsdWVzWzFdLDIpYCkuCihBbGxlIHAtd2FhcmRlcyBlbiBiZXRyb3V3YmFhcmhlaWRzaW50ZXJ2YWxsZW4gdm9vciBwb3N0LWhvYy10ZXN0cyB3b3JkZW4gZ2Vjb3JyaWdlZXJkIHZvb3IgbWVlcnZvdWRpZ2UgdGVzdHMgbWV0IGJlaHVscCB2YW4gZGUgVHVrZXktbWV0aG9kZSkuCgpNZXJrIG9wIGRhdCBoZXQgYmVsYW5ncmlqayBpcyBvbSBvb2sgZGUgbmlldCBzaWduaWZpY2FudGUgcmVzdWx0YXRlbiB0ZSB2ZXJtZWxkZW4hCgotLS0KCiMgW0hvbWVdKGh0dHBzOi8vc3RhdG9taWNzLmdpdGh1Yi5pby9zYmMyMC8pIHstfQo=