1 Breast cancer dataset

  • subset van studie https://doi.org/10.1093/jnci/djj052

  • 32 borstkanker patiĆ«nten met een estrogen recepter positieve tumor die tamoxifen chemotherapy behandeling ondergaan. Variabelen:

    • grade: histologische graad van tumor (graad 1 vs 3),
    • node: status van de lymfe knopen (0: niet aangetast, 1: aantasting en verwijdering van de lymfe knopen),
    • size: grootte van tumor in cm,
    • ESR1 en S100A8 gen expressie in tumor biopsy (via microarray technologie)
brca <- read_csv("https://raw.githubusercontent.com/statOmics/sbc20/master/data/breastcancer.csv")
brca
# A tibble: 32 x 10
   sample_name filename     treatment    er grade  node  size   age  ESR1 S100A8
   <chr>       <chr>        <chr>     <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>  <dbl>
 1 OXFT_209    gsm65344.ceā€¦ tamoxifen     1     3     1   2.5    66 1939.  207. 
 2 OXFT_1769   gsm65345.ceā€¦ tamoxifen     1     1     1   3.5    86 2752.   37.0
 3 OXFT_2093   gsm65347.ceā€¦ tamoxifen     1     1     1   2.2    74  379. 2364. 
 4 OXFT_1770   gsm65348.ceā€¦ tamoxifen     1     1     1   1.7    69 2532.   23.6
 5 OXFT_1342   gsm65350.ceā€¦ tamoxifen     1     3     0   2.5    62  141. 3219. 
 6 OXFT_2338   gsm65352.ceā€¦ tamoxifen     1     3     1   1.4    63 1495.  108. 
 7 OXFT_2341   gsm65353.ceā€¦ tamoxifen     1     1     1   3.3    76 3406.   14.0
 8 OXFT_1902   gsm65354.ceā€¦ tamoxifen     1     3     0   2.4    61 2813.   68.4
 9 OXFT_1982   gsm65355.ceā€¦ tamoxifen     1     1     0   1.7    62  950.   74.2
10 OXFT_5210   gsm65356.ceā€¦ tamoxifen     1     3     0   3.5    65 1053.  182. 
# ā€¦ with 22 more rows
  • Om didactische redenen verwijderen we eerst 3 outliers in de S100A8 expressie data.
  • In deze studie kan dit echter niet worden verantwoord
  • Later in de lessen laten we zien hoe je goed met alle data omgaat.
brca %>%
  ggplot(aes(x="", y=S100A8)) +
  geom_boxplot() +
  xlab("") +
  ylab("S100A8 expressie")


library(GGally)
brcaSubset <- brca %>%
  filter(S100A8<2000)
brcaSubset[,-(1:4)] %>% ggpairs()

1.1 Associatie tussen ESR1 en S100A8 expressie

  • ESR1 in \(\pm\) 75% van borstkankertumoren.

    • Expressie van ER-gen positief voor behandeling: tumor reageert op hormoontherapie
    • Tamoxifen interageert met ER en moduleert genexpressie.
  • Eiwitten van de S100-familie zijn vaak gedisreguleerd bij kanker

  • S100A8 expressie onderdrukt immuunsysteem in tumor en creĆ«ert inflamatoir milieu die kankergroei promoot.

  • Interesse in associatie tussen ESR1 en S100A8 expressie.

  1. pipe dataset naar ggplot
  2. selecteer data ggplot(aes(x=ESR1,y=S100A8))
  3. voeg punten toe met geom_point()
  4. voeg een ā€œsmooth lineā€ toe geom_smooth()
brcaSubset %>%
  ggplot(aes(x=ESR1,y=S100A8)) +
  geom_point() +
  geom_smooth()

2 Lineaire Regressie

  • Statistische methode om relatie tussen 2 reeksen observaties \((X_i, Y_i)\), bekomen voor onafhankelijke subjecten \(i = 1, ..., n\), te beschrijven.

  • Gen expressie voorbeeld

    • Response Y : S100A8 expressie
    • Predictor X: ESR1 expressie
  1. pipe dataset naar ggplot
  2. selecteer data ggplot(aes(x=ESR1,y=S100A8))
  3. voeg punten toe met geom_point()
  4. voeg een ā€œsmooth lineā€ toe geom_smooth()
  5. voeg een rechte toe geom_smooth() met method = "lm" (linear model). (We zetten se = FALSE om geen puntgewijze betrouwbaarheidsintervallen weer te geven)
brcaSubset %>%
  ggplot(aes(x = ESR1,y = S100A8)) +
  geom_point() +
  geom_smooth(se = FALSE, col = "grey") +
  geom_smooth(method = "lm", se = FALSE)

2.1 Model

  • Voor vaste \(X\), heeft \(Y\) niet noodzakelijke dezelfde waarde

\[\text{observation = signal + noise}\]

\[Y_i=g(X_i)+\epsilon_i\]

  • We definiĆ«ren \(g(x)\) als het verwachte resultaat voor subjects met \(X_i=x\)

\[E[Y_i|X_i=x]=g(x)\]

Daarom is \(\epsilon_i\) gemiddeld 0 voor subjects met dezelfde \(X_i\): \[E[\epsilon_i|X_i]=0\]

2.2 Lineaire regressie

  • Om accurate en interpreteerbare resultaten te bekomen, kiest men \(g(x)\) vaak als een lineaire functie met ongekende parameters.

\[E(Y|X=x)=\beta_0 + \beta_1 x\]

onbekend intercept \(\beta_0\) en helling \(\beta_1\).

  • Lineair model legt een assumptie op de verdeling van \(X\) en \(Y\), die incorrect kan zijn.

  • EfficiĆ«nte data-analyse: benut alle observaties om iets te leren over verwachte uitkomst bij \(X=x\).

2.3 Gebruik

  • Predictie: wanneer \(Y\) ongekend is, maar \(X\) wel, kunnen we \(Y\) voorspellen op basis van \(X\) \[E(Y|X=x)=\beta_0 + \beta_1 x\]

  • Associatie: biologische relatie tussen variabele \(X\) en continue meting \(Y\) beschrijven.

  • Intercept: \(E(Y|X=0)=\beta_0\)

  • Slope: \[\begin{eqnarray*} E(Y|X=x+\delta)-E(Y|X=x)&=&\beta_0 + \beta_1 (x+\delta) -\beta_0-\beta_1 x\\ &=& \beta_1\delta \end{eqnarray*}\]

\(\beta_1:\) verschil in gemiddelde uitkomst voor subjecten die verschillen in Ć©Ć©n eenheid van de predictor \(X\).

3 Parameterschatting

    • Kleinste kwadraten techniek (Least squares)
brcaSubset %>%
  ggplot(aes(x = ESR1, y = S100A8)) +
  geom_point() +
  geom_smooth(se = FALSE, col = "grey") +
  geom_smooth(method = "lm", se = FALSE)

  • Parameters \(\beta_0\) en \(\beta_1\) zijn ongekend

  • Parameters schatten op basis van beperkte steekproef

  • Best passende lijn

    • Punt op regressielijn voor een gegeven \(x_i\): \((x_i, \beta_0 + \beta_1 x_i)\) zo dicht mogelijk bij \((x_i, y_i)\)
    • Kies \(\beta_0\) en \(\beta_1\) zodat de som tussen voorspelde en waargenomen punten zo klein mogelijk wordt.

\[SSE=\sum_{i=1}^n (y_i-\beta_0-\beta_1 x_i)^2=\sum_{i=1}^n e_i^2\]

  • Met \(e_i\) de residuen: de verticale afstanden van de observaties tot de gefitte regressierechte

3.1 Schatters die SSE minimaliseren

\[\hat{\beta_1}= \frac{\sum\limits_{i=1}^n (y_i-\bar y)(x_i-\bar x)}{\sum\limits_{i=1}^n (x_i-\bar x_i)^2}=\frac{\mbox{cor}(x,y)s_y}{s_x} \]

\[\hat{\beta_0}=\bar y - \hat{\beta}_1 \bar x \]

  • Merk op dat de helling van de kleinste kwadratenlijn evenredig is met de correlatie tussen de uitkomst en de verklarende variabele.

Geschatte lineaire regressiemodel laat toe om:

  • verwachte uitkomst te voorspellen voor subjecten met een gegeven waarde \(x\) voor de predictor: \[\text{E} [ Y | X = x]=\hat{\beta}_0+\hat{\beta}_1x\]

  • na te gaan hoeveel uitkomst gemiddeld verschilt tussen 2 groepen subjecten met een verschil van \(\delta\) eenheden in de verklarende variabele:

\[\text{E}\left[Y|X=x+\delta\right]-\text{E}\left[Y|X=x\right]= \hat{\beta}_1\delta\]

3.1.1 Borstkanker voorbeeld

lm1 <- lm(S100A8 ~ ESR1, brcaSubset)
summary(lm1)

Call:
lm(formula = S100A8 ~ ESR1, data = brcaSubset)

Residuals:
   Min     1Q Median     3Q    Max 
-95.43 -34.81  -6.79  34.23 145.21 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept) 208.47145   28.57207   7.296 7.56e-08 ***
ESR1         -0.05926    0.01212  -4.891 4.08e-05 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 59.91 on 27 degrees of freedom
Multiple R-squared:  0.4698,    Adjusted R-squared:  0.4502 
F-statistic: 23.93 on 1 and 27 DF,  p-value: 4.078e-05

\[E(Y|X=x)=208.47-0.059 x\]

  • De verwachte S100A8-expressie is gemiddeld 59 eenheden lager voor patiĆ«nten met een ESR1-expressieniveau die 1000 eenheden hoger ligt.

  • Verwachte S100A8 expressieniveau voor patiĆ«nten met een ESR1 expressieniveau van 2000:
    \[208.47-0.059\times 2000=89.94\]

  • Verwachte S100A8 expressieniveau voor patiĆ«nten met een ESR1 expressieniveau van 4000:
    \[208.47-0.059\times 4000=-28.58\]

  • Let op voor extrapolatie! (Veronderstelling van lineariteit kan men enkel nagaan binnen het bereik van de data).

4 Statistische besluitvorming (statistische inferentie)

Om besluiten te kunnen trekken over lineaire regressiemodel \[E(Y|X)=\beta_0+\beta_1 X\]

moeten we weten:

  • Hoe de least squares parameter schatters variĆ«ren van steekproef tot steekproef, en

  • En hoe is dit onder de nulhypothese dat er geen associatie is tussen predictor en response

  • Noodzaak aan statistisch model!

  • Modelleer de verdeling van \(Y\) gegeven \(X\) expliciet: \(f_{Y|X}(y)\)

4.1 Modelleer verdeling van Y?

  1. Naast lineariteit hebben we nog aannames nodig!
  2. Onafhankelijkheid: waarnemingen \((X_1,Y_1), ..., (X_n,Y_n)\) zijn gemaakt voor n onafhankelijke subjecten (Is vereist om de variantie te schatten)
  3. Homoscedasticiteit of gelijke varianties: waarnemingen variƫren met gelijk gemiddelde rond de regressielijn.
    • Residuen \(\epsilon_i\) hebben gelijke variantie voor elke \(X_i=x\)
    • \(\text{var}(Y\vert X=x) = \sigma^2\) voor elke \(X=x\)
    • \(\sigma\) wordt de residuele standaarddeviatie genoemd.
  4. Normaliteit: de residuen \(\epsilon_i\) zijn normaal verdeeld

  • Uit 2, 3 en 4 volgt dat \[\epsilon_i \text{ i.i.d.} N(0,\sigma^2).\]

  • Als we ook steunen op eerste veronderstelling van lineariteit: \[Y_i\vert X_i\sim N(\beta_0+\beta_1 X_i,\sigma^2),\]

  • Verder kan men aantonen dat onder deze aannames \[\sigma^2_{\hat{\beta}_0}=\frac{\sum\limits_{i=1}^n X^2_i}{\sum\limits_{i=1}^n (X_i-\bar X)^2} \times\frac{\sigma^2}{n} \text{ en } \sigma^2_{\hat{\beta}_1}=\frac{\sigma^2}{\sum\limits_{i=1}^n (X_i-\bar X)^2}\]

  • en dat de parameterschatters eveneens normaal verdeeld zijn \[\hat\beta_0 \sim N\left(\beta_0,\sigma^2_{\hat \beta_0}\right) \text{ en } \hat\beta_1 \sim N\left(\beta_1,\sigma^2_{\hat \beta_1}\right)\]

4.2 Hoge spreiding op \(X\) verbetert de precisie

\[\sigma^2_{\hat{\beta}_1}=\frac{\sigma^2}{\sum\limits_{i=1}^n (X_i-\bar X)^2}\]

  • Conditionele variantie (\(\sigma^2\)) is niet gekend
  • Schatten d.m.v. gemiddelde van die kwadratische afwijkingen rond de regressierechte
  • mean squared error (MSE)

\[\hat\sigma^2=MSE=\frac{\sum\limits_{i=1}^n \left(y_i-\hat\beta_0-\hat\beta_1\times x_i\right)^2}{n-2}=\frac{\sum\limits_{i=1}^n e^2_i}{n-2}.\] - Voor het bekomen van deze schatter steunen we op onafhankelijkheid (aanname 2) en homoscedasticiteit (aanname 3). - deel door \(n-2\)

Na schatting van \(\sigma^2\) bekomen we volgende standaard errors:

\[\text{SE}_{\hat{\beta}_0}=\hat\sigma_{\hat{\beta}_0}=\sqrt{\frac{\sum\limits_{i=1}^n X^2_i}{\sum\limits_{i=1}^n (X_i-\bar X)^2} \times\frac{\text{MSE}}{n}} \text{ en } \text{SE}_{\hat{\beta}_1}=\hat\sigma_{\hat{\beta}_1}=\sqrt{\frac{\text{MSE}}{\sum\limits_{i=1}^n (X_i-\bar X)^2}}\]

  • Opnieuw toetsen en betrouwbaarheidsintervallen o.b.v. \[T=\frac{\hat{\beta}_k-\beta_k}{SE(\hat{\beta}_k)} \text{ with } k=1,2.\]

  • Als aan alle aannames is voldaan volgt \(T\) een t-verdeling met n-2 vrijheidsgraden.

  • Als geen normaliteit maar wel onafhankelijk, lineariteit en homoscedasticiteit en grote dataset \[\rightarrow \text{Centrale Limietstelling}\]

4.2.1 Borstkanker voorbeeld

  • Negatieve associatie tussen S100A8 en ESR1 gen expressie.

  • Veralgemeen effect in steekproef naar populatie met behulp van het betrouwbaarheidsinterval op de helling: \[[\hat\beta_1 - t_{n-2,\alpha/2} \text{SE}_{\hat\beta_1},\hat\beta_1 + t_{n-2,\alpha/2} \text{SE}_{\hat\beta_1}]\].

confint(lm1)
                   2.5 %       97.5 %
(Intercept) 149.84639096 267.09649989
ESR1         -0.08412397  -0.03440378
  • Negatief verband is significant op het 5% significantieniveau.

4.3 Hypothese test

  • Vertaal de onderzoeksvraag ā€œIs er een associatie tussen de S100A8- en ESR1-genexpressie?ā€ naar de parameters in het model.

  • Onder nulhypothese geen associatie tussen expressie van beide genen: \[H_0: \beta_1=0\]

  • Onder alternatieve hypothese is er een associatie tussen beide genen: \[H_1: \beta_1\neq0\]

  • Test statistiek \[T=\frac{\hat{\beta}_1-0}{SE(\hat{\beta}_k)}\]

  • Onder \(H_0\) volgt de statistiek een t-verdeling met n-2 vrijheidsgraden.

4.3.1 Brca dataset

summary(lm1)

Call:
lm(formula = S100A8 ~ ESR1, data = brcaSubset)

Residuals:
   Min     1Q Median     3Q    Max 
-95.43 -34.81  -6.79  34.23 145.21 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept) 208.47145   28.57207   7.296 7.56e-08 ***
ESR1         -0.05926    0.01212  -4.891 4.08e-05 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 59.91 on 27 degrees of freedom
Multiple R-squared:  0.4698,    Adjusted R-squared:  0.4502 
F-statistic: 23.93 on 1 and 27 DF,  p-value: 4.078e-05
  • Associatie tussen de S100A8 en ESR1 genexpressie extreem significant is (p<<0.001).
  • Maar eerst moeten we alle assumpties controleren!
  • Anders kunnen de conclusies o.b.v. de statistische test en het BI onjuist zijn.

5 Nagaan van modelveronderstellingen

  • Onafhankelijkheid: design
  • Lineariteit: besluitvorming geen zin als model niet lineair is
  • Homoscedasticiteit: besluitvorming/p-waarde is niet betrouwbaar als de data niet homoscedastisch zijn
  • Normaliteit: besluitvorming/p-waarde is niet betrouwbaar als de data niet normaal verdeeld zijn in kleine steekproeven

5.1 Lineariteit

brcaSubset %>%
  ggplot(aes(x = ESR1, y = S100A8)) +
  geom_point() +
  geom_smooth(se = FALSE, col = "grey") +
  geom_smooth(method = "lm", se = FALSE)

5.2 Residuplots

  • Afwijkingen van lineariteit echter makkelijker opgespoord d.m.v. een residuplot. (Zeker als er later meer variabelen zijn in het lineaire model)

  • verklarende variabele of predicties \(\hat\beta_0+\hat\beta_1 x\) op de \(X\)-as

  • de residuen op de \(Y\)-as \[e_i=y_i-\hat{g}(x_i)=y_i-\hat\beta_0-\hat\beta_1\times x_i,\]

plot(lm1)

5.3 Homoscedasticiteit (gelijkheid van variantie)

  • Residuen en kwadratische residuā€™s dragen informatie over residuele variabiliteit.

  • Associatie met de verklarende variabelen \(\rightarrow\) indicatie van heteroscedasticiteit.

  • Scatterplot van of \(e_i\) versus \(x_i\) of predicties \(\hat \beta_0+ \hat \beta_1 x_i\).

  • Scatterplot van gestandardiseerd residu versus \(x_i\) of predicties.

5.4 Normaliteit

  • Indien voldoende gegevens, schatters normaal verdeeld zelfs wanneer observaties niet Normaal verdeeld zijn: centrale limiet stelling

  • Wat ā€˜voldoende observatiesā€™ zijn, hangt af van hoe goed de verdeling op de Normale lijkt.

  • Aanname is dat uitkomsten Normaal verdeeld zijn bij vaste waarden van de verklarende variabelen. \[Y_i\vert X_i\sim N(\beta_0+\beta_1X_i,\sigma^2)\]

  • QQ-plot van response Y is heel misleidend.

  • QQ-plot van de residuen \(e_i\)

plot(lm1, which=2)

6 Afwijkingen van Modelveronderstellingen

  • Transformatie van onafhankelijke veranderlijke wijzigt de verdeling van Y bij gegeven X niet:

    • helpt niet om normaliteit of homoscedasticiteit te bekomen
    • helpt wel om lineariteit te bekomen wanneer er normaliteit en homoscedasticiteit is
    • Vaak ook hogere orde termen: \(X^2\), \(X^3\), ā€¦ \[Y_i=\beta_0+\beta_1X_i+\beta_2X_i^2+ ... + \epsilon_i\]
  • Transformatie van response Y kan helpen om normaliteit en homoscedasticiteit te bekomen.

    • \(\sqrt(Y)\), \(\log(Y)\), 1/Y, ā€¦

6.1 Borstkanker voorbeeld

Problemen met

  • heteroscedasticiteit

  • mogelijkse afwijking van normaliteit (scheefheid naar rechts)

  • negatieve concentratievoorspellingen die theoretisch niet mogelijk zijn

  • niet-lineairiteit

  • treedt veelal op bij concentratie en intensiteitsmetingen

  • Deze zijn vaak log-normaal verdeeld (normale verdeling na log-transformatie)

  • In Figuur 6.3 eveneens een soort exponentiĆ«le trend

  • In de genexpressie literatuur wordt veelal gebruik gemaak van \(\log_2\) transformatie

  • gen-expressie op log-schaal proportionele verschillen op de originele schaal

brca %>%
  ggplot(aes(x = ESR1, y = S100A8)) +
  geom_point() +
  geom_smooth()

brca %>%
  ggplot(aes(
    x = ESR1 %>% log2,
    y = S100A8 %>% log2)
    ) +
  geom_point() +
  geom_smooth()

lm2<-lm(S100A8 %>% log2 ~ ESR1 %>% log2, brca)
plot(lm2)

summary(lm2)

Call:
lm(formula = S100A8 %>% log2 ~ ESR1 %>% log2, data = brca)

Residuals:
     Min       1Q   Median       3Q      Max 
-1.94279 -0.66537  0.08124  0.68468  1.92714 

Coefficients:
              Estimate Std. Error t value Pr(>|t|)    
(Intercept)     23.401      1.603   14.60 3.57e-15 ***
ESR1 %>% log2   -1.615      0.150  -10.76 8.07e-12 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 1.026 on 30 degrees of freedom
Multiple R-squared:  0.7942,    Adjusted R-squared:  0.7874 
F-statistic: 115.8 on 1 and 30 DF,  p-value: 8.07e-12
confint(lm2)
                  2.5 %    97.5 %
(Intercept)   20.128645 26.674023
ESR1 %>% log2 -1.921047 -1.308185

6.1.1 Interpretatie 1

Een patiƫnt met een ESR1 expressie die 1 eenheid op de \(\log_2\) schaal hoger ligt dan dat van een andere patiƫnt heeft gemiddeld gezien een expressie-niveau van het S100A8 gen dat 1.61 eenheden lager ligt (95% BI [-1.92,-1.31]).

Crossectionele studie: enkel uitspraken over verschillen tussen patiƫnten!

\[\log_2 \hat\mu_1=23.401 -1.615 \times \text{logESR}_1,\text{ } \log_2 \hat\mu_2=23.401 -1.615 \times \text{logESR}_2 \] \[\log_2 \hat\mu_2-\log_2 \hat\mu_1= -1.615 (\log_2 \text{ESR}_2-\log_2 \text{ESR}_1) = -1.615 \times 1 = -1.615\]

6.1.2 Interpretatie 2

Model op log-schaal: bij terugtransformatie verkrijgen we het geometrische gemiddelde

\[\begin{eqnarray*} \sum\limits_{i=1}^n \frac{\log x_i}{n}&=&\frac{\log x_1 + \ldots + \log x_n}{n}\\\\ &\stackrel{(1)}{=}&\frac{\log(x_1 \times \ldots \times x_n)}{n}=\frac{\log\left(\prod\limits_{i=1}^n x_i\right)}{n}\\\\ &\stackrel{(2)}{=}&\log \left(\sqrt[\leftroot{-1}\uproot{2}\scriptstyle n]{\prod\limits_{i=1}^n x_i}\right) \end{eqnarray*}\]

  • Populatiegemiddelden \(\mu\) dus geschat a.d.h.v. geometrisch gemiddelden.
  • Logaritmische transformatie is een monotoon: we kunnen betrouwbaarheidsintervallen berekend op log-schaal terugtransformeren!
2^lm2$coef[2]
ESR1 %>% log2 
    0.3265519 
2^-lm2$coef[2]
ESR1 %>% log2 
       3.0623 
2^-confint(lm2)[2,]
   2.5 %   97.5 % 
3.786977 2.476298 

Een patiƫnt met een ESR1 expressie die 2 keer zo hoog is als die van een andere patiƫnt, zal gemiddeld een S100A8-expressie hebben die 3.06 keer lager is (95% BI [2.48,3.79]).

\[\log_2 \hat\mu_1=23.401 -1.615 \times \text{logESR}_1,\text{ } \log_2 \hat\mu_2=23.401 -1.615 \times \text{logESR}_2 \] \[\log_2 \hat\mu_2-\log_2 \hat\mu_1= -1.615 (\log_2 \text{ESR}_2-\log_2 \text{ESR}_1) \] \[\log_2 \left[\frac{\hat\mu_2}{\hat\mu_1}\right]= -1.615 \log_2\left[\frac{ \text{ESR}_2}{\text{ESR}_1}\right] \] \[\frac{\hat\mu_2}{\hat\mu_1}=\left[\frac{ \text{ESR}_2}{\text{ESR}_1}\right]^{-1.615}=2^ {-1.615} =0.326\] or \[\frac{\hat\mu_1}{\hat\mu_2}=2^{1.615} =3.06\]

6.1.3 Interpratie 3

Een patiƫnt met een ESR1 expressie die 1% hoger is dan die van een andere patiƫnt zal gemiddeld een expressieniveau voor het S100A8 gen hebben dat ongeveer -1.61% lager is (95% BI [-1.92,-1.31])%.

\[\log_2 \hat\mu_1=23.401 -1.615 \times \text{logESR}_1,\text{ } \log_2 \hat\mu_2=23.401 -1.615 \times \text{logESR}_2 \] \[\log_2 \hat\mu_2-\hat\log_2 \mu_1= -1.615 (\log_2 \text{ESR}_2-\log_2 \text{ESR}_1) \] \[\log_2 \left[\frac{\hat\mu_2}{\hat\mu_1}\right]= -1.615 \log_2\left[\frac{ \text{ESR}_2}{\text{ESR}_1}\right] \] \[\frac{\hat\mu_2}{\hat\mu_1}=\left[\frac{ \text{ESR}_2}{\text{ESR}_1}\right]^{-1.615}=1.01^ {-1.615} =0.984 \approx -1.6\%\]

Dit geldt voor lage tot matige waarden van \(\beta_1\): \[-10<\beta_1<10 \rightarrow 1.01^{\beta_1} -1 \approx \frac{\beta_1}{100}.\]

7 Besluitvorming over gemiddelde uitkomst

  • Regressie model kan ook worden gebruikt voor predictie

  • Besluitvorming te doen over de gemiddelde uitkomst bij een gegeven waarde \(x\), m.a.w. \[\hat{g}(x)= \hat{\beta}_0 + \hat{\beta}_1 x\]

  • \(\hat{g}(x)\) een schatter van het conditionele gemiddelde \(E[Y\vert X=x]\)

  • Parameterschatters Normale verdeeld en onvertekend \(\rightarrow\) schatter \(\hat{g}(x)\) ook Normaal verdeeld en onvertekend.

\[\text{SE}_{\hat{g}(x)}=\sqrt{MSE\left\{\frac{1}{n}+\frac{(x-\bar X)^2}{\sum\limits_{i=1}^n (X_i-\bar X)^2}\right\}}.\]

\[T=\frac{\hat{g}(x)-g(x)}{SE_{\hat{g}(x)}}\sim t_{n-2}\]

  • Gemiddelde uitkomst en betrouwbaarheidsintervallen op de gemiddelde uitkomst in R via de predict(.) functie.
  • newdata argument: predictorwaarden (x-waarden) voor het berekenen van gemiddelde uitkomsten
  • interval="confidence" argument om betrouwbaarheidsintervallen te bekomen.
  • Zonder newdata argument wordt de gemiddelde uitkomsten berekend voor alle predictorwaarden van de dataset.
grid <- 140:4000
g <- predict(
  lm2,
  newdata = data.frame(ESR1 = grid),
  interval = "confidence")
head(g)
       fit      lwr      upr
1 11.89028 10.76082 13.01974
2 11.87370 10.74721 13.00019
3 11.85724 10.73370 12.98078
4 11.84089 10.72028 12.96151
5 11.82466 10.70696 12.94237
6 11.80854 10.69372 12.92336

Merk op dat we de nieuwe data die we gespecificeerd hebben voor de ESR1 expressie niet moeten transformeren omdat we het model fitten met de lmfunctie en de transformatie hebben gespecificeerd binnen die functie met behulp van het pipe commando!

brca %>% ggplot(
  aes(
    x = ESR1 %>% log2,
    y = S100A8 %>% log2)
  ) +
  geom_point() +
  geom_smooth(method = "lm")

7.1 Terugtransformatie

newdata<-data.frame(cbind(grid,2^g))
brca %>%
  ggplot(aes(x = ESR1, y = S100A8)) +
  geom_point() +
  geom_line(aes(x=grid,y=fit),newdata) +
  geom_line(aes(x=grid,y=lwr),newdata,color="grey") +
  geom_line(aes(x=grid,y=upr),newdata,color="grey")

8 Predictie-intervallen

-We kunnen ook een voorspelling doen voor de locatie van een nieuwe waarneming die zou worden verzameld in een nieuw experiment voor een patiƫnt met een bepaalde waarde voor hun ESR1-expressie

  • Het is belangrijk op te merken dat dit experiment nog moet worden uitgevoerd. We willen dus de niet-waargenomen individuele expressiewaarde voor een nieuwe patiĆ«nt voorspellen.

  • Voor een nieuwe onafhankelijke waarneming \(Y^*\) \[ Y^* = g(x) + \epsilon^* \] met \(\epsilon^*\sim N(0,\sigma^2)\) en \(\epsilon^*\) onafhankelijk van de waarnemingen in de steekproef \(Y_1,\ldots, Y_n\).

  • We voorspellen een nieuwe log-S100A8 voor een patiĆ«nt met een gekend log2-ESR1-expressieniveau x \[ \hat{y}(x)=\hat{\beta}_0+\hat{\beta}_1 \times x \]

  • De geschatte gemiddelde uitkomst en voorspelling voor een nieuwe waarneming zijn gelijk.

  • Maar hun steekproef verdelingen zijn anders!

    • Onzekerheid over de geschatte gemiddelde uitkomst \(\leftarrow\) onzekerheid over de geschatte modelparameters \(\hat\beta_0\) en \(\hat\beta_1\).
    • Onzekerheid over nieuwe waarneming \(\leftarrow\) onzekerheid over geschat gemiddelde en extra onzekerheid omdat de nieuwe waarneming zal afwijken rond het gemiddelde!

\[\text{SE}_{\hat{Y}(x)}=\sqrt{\hat\sigma^2+\hat\sigma^2_{\hat{g}(x)}}=\sqrt{MSE\left\{1+\frac{1}{n}+\frac{(x-\bar X)^2}{\sum\limits_{i=1}^n (X_i-\bar X)^2}\right\}}.\]

\[\frac{\hat{Y}(x)-Y}{\text{SE}_{\hat{Y}(x)}}\sim t_{n-2}\]

  • Merk op dat een predictie-interval (PI) een verbeterde versie is van een referentie-interval wanneer de modelparameters onbekend zijn: onzekerheid over modelparameters + t-verdeling.
p <- predict(
  lm2,
  newdata = data.frame(ESR1 = grid),
  interval="prediction")

head(p)
       fit      lwr      upr
1 11.89028 9.510524 14.27004
2 11.87370 9.495354 14.25205
3 11.85724 9.480288 14.23419
4 11.84089 9.465324 14.21646
5 11.82466 9.450461 14.19886
6 11.80854 9.435698 14.18138
preddata<-data.frame(
  grid = grid%>%log2,
  p)
brca %>% ggplot(aes(x=ESR1%>%log2,y=S100A8%>%log2)) +
  geom_point() +
  geom_smooth(method="lm") +
     geom_line(aes(x=grid,y=lwr),preddata,color="blue") +
  geom_line(aes(x=grid,y=upr),preddata,color="blue")

preddata<-data.frame(cbind(grid,2^p))
brca %>% ggplot(aes(x = ESR1, y = S100A8)) +
  geom_point() +
  geom_line(
    aes(x = grid,y = fit),
    newdata) +
  geom_line(
    aes(x = grid, y = lwr),
    newdata,
    color = "grey") +
  geom_line(
    aes(x = grid, y = upr),
    newdata,
    color = "grey") +
  geom_line(
    aes(x = grid, y = lwr),
    preddata,
    color = "blue") +
  geom_line(
    aes(x = grid,y = upr),
    preddata,
    color = "blue")

8.1 NHANES voorbeeld

  • Vergelijk referentie-interval voor cholesterolgehalte met predictie interval.

  • Referentie-interval

library(NHANES)
fem <- NHANES %>%
  filter(Gender=="female"&!is.na(DirectChol))

2^(
  fem %>%
  pull(DirectChol) %>%
  log2 %>%
  mean +
    c(-1,1) *
    qnorm(0.975) *
    (fem %>%
      pull(DirectChol) %>%
      log2 %>%
      sd)
  )
[1] 0.8361311 2.4397130
  • Predictie interval
lmChol <- lm(DirectChol %>% log2 ~ 1, data=fem)
predInt <- predict(
  lmChol,
  interval="prediction",
  newdata=data.frame(noPred=1)
  )
round(2^predInt,2)
   fit  lwr  upr
1 1.43 0.84 2.44

Merk op dat het voorspellingsinterval bijna gelijk is aan het referentie-interval voor de grote steekproef. We konden de parameters inderdaad heel precies schatten.

We zullen hetzelfde doen voor een kleine steekproef van 10 patiƫnten.

  • Referentie interval
set.seed(1)
fem10 <- NHANES %>%
  filter(Gender=="female"&!is.na(DirectChol)) %>%
  sample_n(size=10)

2^(
  fem10 %>%
    pull(DirectChol) %>%
    log2 %>%
    mean +
      c(-1,1) *
      qnorm(0.975) *
      (fem10 %>%
        pull(DirectChol) %>%
        log2 %>%
        sd)
  )
[1] 0.8976012 2.2571645

Het referentie-interval is veel smaller dan in de grote steekproef.

  • Predictie interval
lmChol10 <- lm(DirectChol %>% log2 ~ 1, data = fem10)
predInt10 <- predict(
  lmChol10,
  interval = "prediction",
  newdata = data.frame(noPred=1)
  )
round(2^predInt10, 2)
   fit  lwr  upr
1 1.42 0.81 2.49
  • Merk op dat het PI nu onzekerheid meeneemt in parameterschatters (gemiddelde en standaard error). En dat het interval veel breder wordt! Dit is hier vooral belangrijk voor de bovengrens omdat we de gegevens terug hebben getransformeerd!

  • Het interval is bijna net zo breed als dat gebaseerd op de grote steekproef.

  • Bij kleine steekproeven is het erg belangrijk om met deze extra onzekerheid rekening te houden.

9 Kwadratensommen en Anova-tabel

9.1 Totale kwadratensom

\[\text{SSTot} = \sum_{i=1}^n (Y_i-\bar{Y})^2.\]

  • SStot kan worden gebruikt om de variantie van de marginale verdeling van de respons te schatten.

  • In dit hoofdstuk hebben we ons gefocused op de conditionele verdeling \(f(Y\vert X=x)\).

  • We weten dat MSE een goede schatting is van de variantie van de conditionele verdeling van \(Y\vert X=x\).

9.2 Kwadratensom van de regressie SSR

\[\text{SSR} = \sum_{i=1}^n (\hat{Y}_i - \bar{Y})^2 = \sum_{i=1}^n (\hat{g}(x_i) - \bar{Y})^2.\]

  • Maat voor de afwijking tussen de predicties op de geschatte regressierechte en het steekproefgemiddelde van de uitkomsten.

  • Een andere interpretatie: verschil tussen twee modellen

    • Geschatte model \(\hat{g}(x)=\hat\beta_0+\hat\beta_1x\)
    • Geschatte model zonder predictor (enkel intercept): \(g(x)=\beta_0\) \(\rightarrow\) \(\beta_0\) zal gelijk zijn aan \(\bar{Y}\).
  • SSR meet de grootte van het effect van de predictor

9.3 Kwadratensom van de fouten

\[ \text{SSE} = \sum_{i=1}^n (Y_i-\hat{Y}_i )^2 = \sum_{i=1}^n \left\{Y_i-\hat{g}\left(x_i\right)\right\}^2.\]

  • Hoe kleiner de SSE, hoe beter het model fit.

  • Kleinste kwadraten techniek!


We kunnen aantonen dat SST kan worden ontbonden in \[\begin{eqnarray*} \text{SSTot} &=& \sum_{i=1}^n (Y_i-\bar{Y})^2 \\ &=& \sum_{i=1}^n (Y_i-\hat{Y}_i+\hat{Y}_i-\bar{Y})^2 \\ &=& \sum_{i=1}^n (Y_i-\hat{Y}_i)^2+\sum_{i=1}^n(\hat{Y}_i-\bar{Y})^2 \\ &=& \text{SSE }+\text{SSR} \end{eqnarray*}\]

  • De totale variabiliteit in de gegevens (SSTot) wordt gedeeltelijk verklaard door het regressieverband (SSR).
  • Variabiliteit die we niet kunnen verklaren met het regressiemodel is de residuele variabiliteit (SSE).

9.4 Determinatie-coƫfficiƫnt

\[ R^2 = 1-\frac{\text{SSE}}{\text{SSTot}}=\frac{\text{SSR}}{\text{SSTot}}.\]

  • Fractie van de totale variabiliteit in de steekproef-uitkomsten die verklaard wordt door het geschatte regressieverband.

  • Grote \(R^2\) indicatie dat model potentieel tot goede predicties kan leiden (kleine SSE)

  • Slechts in beperkte mate indicatief voor de p-waarde van de test \(H_0:\beta_1=0\) vs \(H_1:\beta_1\neq0\).

    • p-waarde sterk beĆÆnvloed door SSE en steekproefgrootte \(n\), maar niet door SSTot
    • De determinatiecoĆ«fficiĆ«nt \(R^2\) wordt door SSE en SSTot bepaald, maar niet door de steekproefgrootte n.
  • Model met lage \(R^2\) blijft wel nuttig om associatie te bestuderen, zolang het de associatie correct modelleert!

9.4.1 Borstkanker voorbeeld

summary(lm2)

Call:
lm(formula = S100A8 %>% log2 ~ ESR1 %>% log2, data = brca)

Residuals:
     Min       1Q   Median       3Q      Max 
-1.94279 -0.66537  0.08124  0.68468  1.92714 

Coefficients:
              Estimate Std. Error t value Pr(>|t|)    
(Intercept)     23.401      1.603   14.60 3.57e-15 ***
ESR1 %>% log2   -1.615      0.150  -10.76 8.07e-12 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 1.026 on 30 degrees of freedom
Multiple R-squared:  0.7942,    Adjusted R-squared:  0.7874 
F-statistic: 115.8 on 1 and 30 DF,  p-value: 8.07e-12

9.5 F-Testen in het enkelvoudig lineair regressiemodel

  • Kwadratensommen zijn basis voor \(F\)-tests \[ F = \frac{\text{MSR}}{\text{MSE}}\]

met \(\text{MSR} = \frac{\text{SSR}}{1} \text{ and } \text{MSE} = \frac{\text{SSE}}{n-2}.\)

  • MSR wordt de gemiddelde kwadratensom van de regressie genoemd.

  • noemers 1 en \(n-2\) zijn de vrijheidsgraden van SSR en SSE.

  • onder \(H_0: \beta_1=0\) volgt de teststatistiek \[H_0:F = \frac{\text{MSR}}{\text{MSE}} \sim F_{1,n-2},\]

  • F-test is altijd twee-zijdig! \(H_1:\beta_1\neq 0\) \[ p = P_0\left[F\geq f\right]=1-F_F(f;1,n-2)\]

summary(lm2)

Call:
lm(formula = S100A8 %>% log2 ~ ESR1 %>% log2, data = brca)

Residuals:
     Min       1Q   Median       3Q      Max 
-1.94279 -0.66537  0.08124  0.68468  1.92714 

Coefficients:
              Estimate Std. Error t value Pr(>|t|)    
(Intercept)     23.401      1.603   14.60 3.57e-15 ***
ESR1 %>% log2   -1.615      0.150  -10.76 8.07e-12 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 1.026 on 30 degrees of freedom
Multiple R-squared:  0.7942,    Adjusted R-squared:  0.7874 
F-statistic: 115.8 on 1 and 30 DF,  p-value: 8.07e-12

9.6 Anova Tabel

Df Sum Sq Mean Sq F value Pr(>F)
Regressie vrijheidsgraden SSR SSR MSR f-statistiek p-waarde
Error vrijheidsgraden SSE SSE MSE
anova(lm2)
Analysis of Variance Table

Response: S100A8 %>% log2
              Df  Sum Sq Mean Sq F value   Pr(>F)    
ESR1 %>% log2  1 121.814 121.814   115.8 8.07e-12 ***
Residuals     30  31.559   1.052                     
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

10 Dummy variabelen

  • Lineaire regressiemodel voor het vergelijken van twee gemiddelden.

  • Borstkanker: verschil is in gemiddelde leeftijd van de patiĆ«nten met onaangetaste lymfeknopen en patiĆ«nten waarvan lymfeknopen werden verwijderd.

  • Hiervoor definiĆ«ren we eerst een \(dummy\) variabele \[x_i = \left\{ \begin{array}{ll} 1 & \text{aangetaste lymfeknopen} \\ 0 & \text{onaangetaste lymfeknopen} \end{array}\right.\]

  • groep met \(x_i=0\) wordt de referentiegroep genoemd.

  • Het regressiemodel blijft ongewijzigd, \[Y_i = \beta_0 + \beta_1 x_i +\epsilon_i\] met \(\epsilon_i \text{ iid } N(0,\sigma^2)\)

Gezien \(x_i\) slechts twee waarden kan aannemen, is het eenvoudig om het regressiemodel voor beide waarden van \(x_i\) afzonderlijk te bekijken: \[ \begin{array}{lcll} Y_i &=& \beta_0 +\epsilon_i &\text{onaangetaste lymfeknopen} (x_i=0) \\ Y_i &=& \beta_0 + \beta_1 +\epsilon_i &\text{ aangetaste lymfeknopen} (x_i=1) . \end{array}\]

Dus \[\begin{eqnarray*} E\left[Y_i\mid x_i=0\right] &=& \beta_0 \\ E\left[Y_i\mid x_i=1\right] &=& \beta_0 + \beta_1, \end{eqnarray*}\]

waaruit direct de interpretatie van \(\beta_1\) volgt: \[ \beta_1 = E\left[Y_i\mid x_i=1\right]-E\left[Y_i\mid x_i=0\right]\]

\(\beta_1\) is dus het gemiddelde verschil in leeftijd tussen patiƫnten met aangetaste lymfeknopen en patiƫnten met onaangetaste lymfeknopen (referentiegroep).

Met de notatie \(\mu_0= E\left[Y_i\mid x_i=0\right]\) en \(\mu_1= E\left[Y_i\mid x_i=1\right]\) wordt dit \[\beta_1 = \mu_1-\mu_0.\]

Er kan aangetoond worden dat \[\begin{array}{ccll} \hat\beta_0 &=& \bar{Y}_1&\text{ (steekproefgemiddelde in referentiegroep)} \\ \hat\beta_1 &=& \bar{Y}_2-\bar{Y}_1&\text{(schatter van effectgrootte)} \\ \text{MSE} &=& S_p^2 . \end{array}\]

De testen voor \(H_0:\beta_1=0\) vs.Ā \(H_1:\beta_1\neq0\) kunnen gebruikt worden voor het testen van de nulhypothese van de two-sample \(t\)-test, \(H_0:\mu_1=\mu_2\) t.o.v. \(H_1:\mu_1\neq\mu_2\).

brca$node <- as.factor(brca$node)
t.test(age~node,brca,var.equal=TRUE)

    Two Sample t-test

data:  age by node
t = -2.7988, df = 30, p-value = 0.008879
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 -15.791307  -2.467802
sample estimates:
mean in group 0 mean in group 1 
       59.94737        69.07692 
lm3 <- lm(age~node, brca)
summary(lm3)

Call:
lm(formula = age ~ node, data = brca)

Residuals:
     Min       1Q   Median       3Q      Max 
-19.9474  -5.3269   0.0526   5.3026  18.0526 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)   59.947      2.079  28.834  < 2e-16 ***
node1          9.130      3.262   2.799  0.00888 ** 
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 9.063 on 30 degrees of freedom
Multiple R-squared:  0.207, Adjusted R-squared:  0.1806 
F-statistic: 7.833 on 1 and 30 DF,  p-value: 0.008879
plot(lm3)

brca %>%
  ggplot(
    aes(
      x = node %>%
        as.factor,
      y = age)
      ) +
  geom_boxplot()

  1. Simulate 9 datasets with the same number of observations as the brca dataset from a normal distribution with the same standard deviation as in the original data. Store the data of all simulations in a data frame
  2. Plot the simulated data using the ggplot function
  3. Add a boxplot layer
  4. Use facet_wrap to make a separate plot for simulated dataset
  5. Change label of y-axis
set.seed(354)
sim_df <- data.frame(
  node = rep(brca$node, 9),
  iid = rnorm(9 * nrow(brca), sd = sigma(lm3)),
  sim = rep(1:9, each = 32)
  )
sim_df %>%
  ggplot(aes(x = node, y=iid)) +
  geom_boxplot() +
  facet_wrap(.~sim) +
  ylab(paste0("iid N(0,",round(sigma(lm3)^2,2),")"))

10.1 Observationele study

  • We kunnen echter niet besluiten dat oudere personen een hoger risico hebben op aantasting van de lymfeknopen ten gevolge van hun leeftijd.

  • Mogelijks confounding: geen randomisatie \(\rightarrow\) groepen patiĆ«nten met aangetaste lymfeknopen en niet-aangetaste lymfeknopen kunnen nog in andere karateristieken van elkaar verschillen.

  • Enkel besluiten dat er een associatie is tussen de lymfeknoop status en de leeftijd.

  • Het is dus niet noodzakelijkerwijs een causaal verband!


  • Is ook zo voor lineair model voor de \(\log_2\)-S100A8-expressie.

  • Aangezien we de ESR1-expressie niet experimenteel vast hebben kunnen leggen, kunnen we niet besluiten dat een hogere ESR1-expressie de S100A8-expressie doet verlagen.

  • Enkel besluiten dat er een negatieve associatie is.

  • Om impact van gen te bestuderen op andere genen: knockout mutanten generenen in het labo


LS0tCnRpdGxlOiAiNi4gRW5rZWx2b3VkaWdlIGxpbmVhaXJlIHJlZ3Jlc3NpZSIgICAKYXV0aG9yOiAiTGlldmVuIENsZW1lbnQiCmRhdGU6ICJzdGF0T21pY3MsIEdoZW50IFVuaXZlcnNpdHkgKGh0dHBzOi8vc3RhdG9taWNzLmdpdGh1Yi5pbykiCm91dHB1dDoKICAgIGh0bWxfZG9jdW1lbnQ6CiAgICAgIGNvZGVfZG93bmxvYWQ6IHRydWUgICAgCiAgICAgIHRoZW1lOiBjb3NtbwogICAgICB0b2M6IHRydWUKICAgICAgdG9jX2Zsb2F0OiB0cnVlCiAgICAgIGhpZ2hsaWdodDogdGFuZ28KICAgICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChpbmNsdWRlID0gVFJVRSwgY29tbWVudCA9IE5BLCBlY2hvID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFKQpsaWJyYXJ5KFJtaXNjKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKYGBgCgoKIyBCcmVhc3QgY2FuY2VyIGRhdGFzZXQKCgotIHN1YnNldCB2YW4gc3R1ZGllIGh0dHBzOi8vZG9pLm9yZy8xMC4xMDkzL2puY2kvZGpqMDUyCi0gMzIgYm9yc3RrYW5rZXIgcGF0acOrbnRlbiBtZXQgZWVuIGVzdHJvZ2VuIHJlY2VwdGVyIHBvc2l0aWV2ZSB0dW1vciBkaWUgdGFtb3hpZmVuIGNoZW1vdGhlcmFweSBiZWhhbmRlbGluZyBvbmRlcmdhYW4uIFZhcmlhYmVsZW46CgogICAgLSBncmFkZTogaGlzdG9sb2dpc2NoZSBncmFhZCB2YW4gdHVtb3IgKGdyYWFkIDEgdnMgMyksCiAgICAtIG5vZGU6IHN0YXR1cyB2YW4gZGUgbHltZmUga25vcGVuICgwOiBuaWV0IGFhbmdldGFzdCwgMTogYWFudGFzdGluZyBlbiB2ZXJ3aWpkZXJpbmcgdmFuIGRlIGx5bWZlIGtub3BlbiksCiAgICAtIHNpemU6IGdyb290dGUgdmFuIHR1bW9yIGluIGNtLAogICAgLSBFU1IxIGVuIFMxMDBBOCBnZW4gZXhwcmVzc2llIGluIHR1bW9yIGJpb3BzeSAodmlhIG1pY3JvYXJyYXkgdGVjaG5vbG9naWUpCgoKYGBge3J9CmJyY2EgPC0gcmVhZF9jc3YoImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9zdGF0T21pY3Mvc2JjMjAvbWFzdGVyL2RhdGEvYnJlYXN0Y2FuY2VyLmNzdiIpCmJyY2EKYGBgCgotIE9tIGRpZGFjdGlzY2hlIHJlZGVuZW4gdmVyd2lqZGVyZW4gd2UgZWVyc3QgMyBvdXRsaWVycyBpbiBkZSBTMTAwQTggZXhwcmVzc2llIGRhdGEuCi0gSW4gZGV6ZSBzdHVkaWUga2FuIGRpdCBlY2h0ZXIgbmlldCB3b3JkZW4gdmVyYW50d29vcmQKLSBMYXRlciBpbiBkZSBsZXNzZW4gbGF0ZW4gd2UgemllbiBob2UgamUgZ29lZCBtZXQgYWxsZSBkYXRhIG9tZ2FhdC4KCgpgYGB7ciBvdXQud2lkdGg9JzcwJScsIGZpZy5hbGlnbj0nY2VudGVyJyx3YXJuaW5ncz1GQUxTRX0KYnJjYSAlPiUKICBnZ3Bsb3QoYWVzKHg9IiIsIHk9UzEwMEE4KSkgKwogIGdlb21fYm94cGxvdCgpICsKICB4bGFiKCIiKSArCiAgeWxhYigiUzEwMEE4IGV4cHJlc3NpZSIpCmBgYAoKLS0tCgpgYGB7cn0KbGlicmFyeShHR2FsbHkpCmJyY2FTdWJzZXQgPC0gYnJjYSAlPiUKICBmaWx0ZXIoUzEwMEE4PDIwMDApCmJyY2FTdWJzZXRbLC0oMTo0KV0gJT4lIGdncGFpcnMoKQpgYGAKCiMjIEFzc29jaWF0aWUgdHVzc2VuIEVTUjEgZW4gUzEwMEE4IGV4cHJlc3NpZQoKLSBFU1IxIGluICRccG0kIDc1JSB2YW4gYm9yc3RrYW5rZXJ0dW1vcmVuLgoKICAgIC0gRXhwcmVzc2llIHZhbiBFUi1nZW4gcG9zaXRpZWYgdm9vciBiZWhhbmRlbGluZzogdHVtb3IgcmVhZ2VlcnQgb3AgaG9ybW9vbnRoZXJhcGllCiAgICAtIFRhbW94aWZlbiBpbnRlcmFnZWVydCBtZXQgRVIgZW4gbW9kdWxlZXJ0IGdlbmV4cHJlc3NpZS4KCi0gRWl3aXR0ZW4gdmFuIGRlIFMxMDAtZmFtaWxpZSB6aWpuIHZhYWsgZ2VkaXNyZWd1bGVlcmQgYmlqIGthbmtlcgoKLSBTMTAwQTggZXhwcmVzc2llIG9uZGVyZHJ1a3QgaW1tdXVuc3lzdGVlbSBpbiB0dW1vciBlbiBjcmXDq2VydCBpbmZsYW1hdG9pciBtaWxpZXUgZGllIGthbmtlcmdyb2VpIHByb21vb3QuCgotIEludGVyZXNzZSBpbiBhc3NvY2lhdGllIHR1c3NlbiBFU1IxIGVuIFMxMDBBOCBleHByZXNzaWUuCgoxLiBwaXBlIGRhdGFzZXQgbmFhciBnZ3Bsb3QKMi4gc2VsZWN0ZWVyIGRhdGEgYGdncGxvdChhZXMoeD1FU1IxLHk9UzEwMEE4KSlgCjMuIHZvZWcgcHVudGVuIHRvZSBtZXQgYGdlb21fcG9pbnQoKWAKNC4gdm9lZyBlZW4gInNtb290aCBsaW5lIiB0b2UgYGdlb21fc21vb3RoKClgCgpgYGB7ciBmaWcuYWxpZ249J2NlbnRlcid9CmJyY2FTdWJzZXQgJT4lCiAgZ2dwbG90KGFlcyh4PUVTUjEseT1TMTAwQTgpKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX3Ntb290aCgpCmBgYAoKIyBMaW5lYWlyZSBSZWdyZXNzaWUKCi0gU3RhdGlzdGlzY2hlIG1ldGhvZGUgb20gcmVsYXRpZSB0dXNzZW4gMiByZWVrc2VuIG9ic2VydmF0aWVzICQoWF9pLCBZX2kpJCwgYmVrb21lbiB2b29yIG9uYWZoYW5rZWxpamtlIHN1YmplY3RlbiAkaSA9IDEsIC4uLiwgbiQsIHRlIGJlc2NocmlqdmVuLgoKLSBHZW4gZXhwcmVzc2llIHZvb3JiZWVsZAoKICAgIC0gUmVzcG9uc2UgWSA6IFMxMDBBOCBleHByZXNzaWUKICAgIC0gUHJlZGljdG9yIFg6IEVTUjEgZXhwcmVzc2llCgoxLiBwaXBlIGRhdGFzZXQgbmFhciBnZ3Bsb3QKMi4gc2VsZWN0ZWVyIGRhdGEgYGdncGxvdChhZXMoeD1FU1IxLHk9UzEwMEE4KSlgCjMuIHZvZWcgcHVudGVuIHRvZSBtZXQgYGdlb21fcG9pbnQoKWAKNC4gdm9lZyBlZW4gInNtb290aCBsaW5lIiB0b2UgYGdlb21fc21vb3RoKClgCjUuIHZvZWcgZWVuIHJlY2h0ZSB0b2UgYGdlb21fc21vb3RoKClgIG1ldCBgbWV0aG9kID0gImxtImAgKGxpbmVhciBtb2RlbCkuIChXZSB6ZXR0ZW4gYHNlID0gRkFMU0VgIG9tIGdlZW4gcHVudGdld2lqemUgYmV0cm91d2JhYXJoZWlkc2ludGVydmFsbGVuIHdlZXIgdGUgZ2V2ZW4pCgpgYGB7ciBmaWcuYWxpZ249J2NlbnRlcid9CmJyY2FTdWJzZXQgJT4lCiAgZ2dwbG90KGFlcyh4ID0gRVNSMSx5ID0gUzEwMEE4KSkgKwogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9zbW9vdGgoc2UgPSBGQUxTRSwgY29sID0gImdyZXkiKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSkKYGBgCgojIyBNb2RlbAoKLSBWb29yIHZhc3RlICRYJCwgaGVlZnQgJFkkIG5pZXQgbm9vZHpha2VsaWprZSBkZXplbGZkZSB3YWFyZGUKCiQkXHRleHR7b2JzZXJ2YXRpb24gPSBzaWduYWwgKyBub2lzZX0kJAoKJCRZX2k9ZyhYX2kpK1xlcHNpbG9uX2kkJAoKLSBXZSBkZWZpbmnDq3JlbiAkZyh4KSQgYWxzIGhldCB2ZXJ3YWNodGUgcmVzdWx0YWF0IHZvb3Igc3ViamVjdHMgbWV0ICRYX2k9eCQKCiQkRVtZX2l8WF9pPXhdPWcoeCkkJAoKRGFhcm9tIGlzICRcZXBzaWxvbl9pJCBnZW1pZGRlbGQgMCB2b29yIHN1YmplY3RzIG1ldCBkZXplbGZkZSAkWF9pJDoKJCRFW1xlcHNpbG9uX2l8WF9pXT0wJCQKCiMjIExpbmVhaXJlIHJlZ3Jlc3NpZQoKLSBPbSAqKmFjY3VyYXRlKiogZW4gKippbnRlcnByZXRlZXJiYXJlKiogcmVzdWx0YXRlbiB0ZSBiZWtvbWVuLCBraWVzdCBtZW4gJGcoeCkkIHZhYWsgYWxzIGVlbiBsaW5lYWlyZSBmdW5jdGllIG1ldCBvbmdla2VuZGUgcGFyYW1ldGVycy4KCiQkRShZfFg9eCk9XGJldGFfMCArIFxiZXRhXzEgeCQkCgpvbmJla2VuZCAgKippbnRlcmNlcHQqKiAkXGJldGFfMCQgZW4KKipoZWxsaW5nKiogJFxiZXRhXzEkLgoKLSBMaW5lYWlyIG1vZGVsIGxlZ3QgZWVuICphc3N1bXB0aWUqIG9wIGRlIHZlcmRlbGluZyB2YW4gJFgkIGVuICRZJCwgZGllIGluY29ycmVjdCBrYW4gemlqbi4KCi0gKkVmZmljacOrbnRlIGRhdGEtYW5hbHlzZSo6IGJlbnV0IGFsbGUgb2JzZXJ2YXRpZXMgb20gaWV0cyB0ZSBsZXJlbiBvdmVyIHZlcndhY2h0ZSB1aXRrb21zdCBiaWogJFg9eCQuCgoKIyMgR2VicnVpawoKLSAqUHJlZGljdGllKjogd2FubmVlciAkWSQgb25nZWtlbmQgaXMsIG1hYXIgJFgkIHdlbCwga3VubmVuIHdlICRZJCB2b29yc3BlbGxlbiBvcCBiYXNpcyB2YW4gJFgkClxbRShZfFg9eCk9XGJldGFfMCArIFxiZXRhXzEgeFxdCgotICpBc3NvY2lhdGllKjogYmlvbG9naXNjaGUgcmVsYXRpZSB0dXNzZW4gdmFyaWFiZWxlICRYJCBlbiBjb250aW51ZSBtZXRpbmcgJFkkIGJlc2NocmlqdmVuLgotICpJbnRlcmNlcHQ6KiAkRShZfFg9MCk9XGJldGFfMCQKCi0gKlNsb3BlKjoKXGJlZ2lue2VxbmFycmF5Kn0KRShZfFg9eCtcZGVsdGEpLUUoWXxYPXgpJj0mXGJldGFfMCArIFxiZXRhXzEgKHgrXGRlbHRhKSAtXGJldGFfMC1cYmV0YV8xIHhcXAomPSYgXGJldGFfMVxkZWx0YQpcZW5ke2VxbmFycmF5Kn0KCiRcYmV0YV8xOiQgdmVyc2NoaWwgaW4gZ2VtaWRkZWxkZSB1aXRrb21zdCB2b29yIHN1YmplY3RlbiBkaWUgdmVyc2NoaWxsZW4gaW4gw6nDqW4gZWVuaGVpZCB2YW4gZGUgcHJlZGljdG9yICRYJC4KCiMgUGFyYW1ldGVyc2NoYXR0aW5nCgotIC0gS2xlaW5zdGUga3dhZHJhdGVuIHRlY2huaWVrCihMZWFzdCBzcXVhcmVzKQoKYGBge3IgZmlnLmFsaWduPSdjZW50ZXInfQpicmNhU3Vic2V0ICU+JQogIGdncGxvdChhZXMoeCA9IEVTUjEsIHkgPSBTMTAwQTgpKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX3Ntb290aChzZSA9IEZBTFNFLCBjb2wgPSAiZ3JleSIpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFKQpgYGAKCi0gUGFyYW1ldGVycyAkXGJldGFfMCQgZW4gJFxiZXRhXzEkIHppam4gb25nZWtlbmQKCi0gUGFyYW1ldGVycyBzY2hhdHRlbiBvcCBiYXNpcyB2YW4gYmVwZXJrdGUgc3RlZWtwcm9lZgoKLSBCZXN0IHBhc3NlbmRlIGxpam4KCiAgICAtIFB1bnQgb3AgcmVncmVzc2llbGlqbiB2b29yIGVlbiBnZWdldmVuICR4X2kkOiAkKHhfaSwgXGJldGFfMCArIFxiZXRhXzEgeF9pKSQgIHpvIGRpY2h0IG1vZ2VsaWprIGJpaiAkKHhfaSwgeV9pKSQKICAgIC0gS2llcyAkXGJldGFfMCQgZW4gJFxiZXRhXzEkIHpvZGF0IGRlIHNvbSB0dXNzZW4gdm9vcnNwZWxkZSBlbiB3YWFyZ2Vub21lbiBwdW50ZW4gem8ga2xlaW4gbW9nZWxpamsgd29yZHQuCgokJFNTRT1cc3VtX3tpPTF9Xm4gKHlfaS1cYmV0YV8wLVxiZXRhXzEgeF9pKV4yPVxzdW1fe2k9MX1ebiBlX2leMiQkCgotIE1ldCAkZV9pJCBkZSByZXNpZHVlbjogZGUgdmVydGljYWxlIGFmc3RhbmRlbiB2YW4gZGUgb2JzZXJ2YXRpZXMgdG90IGRlIGdlZml0dGUgcmVncmVzc2llcmVjaHRlCgojIyBTY2hhdHRlcnMgZGllIFNTRSBtaW5pbWFsaXNlcmVuCgokJFxoYXR7XGJldGFfMX09IFxmcmFje1xzdW1cbGltaXRzX3tpPTF9Xm4gKHlfaS1cYmFyIHkpKHhfaS1cYmFyIHgpfXtcc3VtXGxpbWl0c197aT0xfV5uICh4X2ktXGJhciB4X2kpXjJ9PVxmcmFje1xtYm94e2Nvcn0oeCx5KXNfeX17c194fSAkJAoKJCRcaGF0e1xiZXRhXzB9PVxiYXIgeSAtIFxoYXR7XGJldGF9XzEgXGJhciB4ICQkCgotIE1lcmsgb3AgZGF0IGRlIGhlbGxpbmcgdmFuIGRlIGtsZWluc3RlIGt3YWRyYXRlbmxpam4gZXZlbnJlZGlnIGlzIG1ldCBkZSBjb3JyZWxhdGllIHR1c3NlbiBkZSB1aXRrb21zdCBlbiBkZSB2ZXJrbGFyZW5kZSB2YXJpYWJlbGUuCgpHZXNjaGF0dGUgbGluZWFpcmUgcmVncmVzc2llbW9kZWwgbGFhdCB0b2Ugb206CgotIHZlcndhY2h0ZSB1aXRrb21zdCB0ZSB2b29yc3BlbGxlbiB2b29yIHN1YmplY3RlbiBtZXQgZWVuIGdlZ2V2ZW4gd2FhcmRlICR4JCB2b29yIGRlIHByZWRpY3RvcjoKJCRcdGV4dHtFfSBbIFkgfCBYID0geF09XGhhdHtcYmV0YX1fMCtcaGF0e1xiZXRhfV8xeCQkCgotIG5hIHRlIGdhYW4gaG9ldmVlbCB1aXRrb21zdCBnZW1pZGRlbGQgdmVyc2NoaWx0IHR1c3NlbiAyIGdyb2VwZW4gc3ViamVjdGVuIG1ldCBlZW4gdmVyc2NoaWwgdmFuICRcZGVsdGEkIGVlbmhlZGVuIGluIGRlIHZlcmtsYXJlbmRlIHZhcmlhYmVsZToKCiQkXHRleHR7RX1cbGVmdFtZfFg9eCtcZGVsdGFccmlnaHRdLVx0ZXh0e0V9XGxlZnRbWXxYPXhccmlnaHRdPSBcaGF0e1xiZXRhfV8xXGRlbHRhJCQKCiMjIyBCb3JzdGthbmtlciB2b29yYmVlbGQKCmBgYHtyfQpsbTEgPC0gbG0oUzEwMEE4IH4gRVNSMSwgYnJjYVN1YnNldCkKc3VtbWFyeShsbTEpCmBgYAoKXFtFKFl8WD14KT1gciByb3VuZChsbTEkY29lZlsxXSwyKWAtYHIgYWJzKHJvdW5kKGxtMSRjb2VmWzJdLDMpKWAgeFxdCgotIERlIHZlcndhY2h0ZSBTMTAwQTgtZXhwcmVzc2llIGlzIGdlbWlkZGVsZCAgYHIgYWJzKHJvdW5kKGxtMSRjb2VmWzJdLDMpKjEwMDApYCBlZW5oZWRlbiBsYWdlciB2b29yIHBhdGnDq250ZW4gbWV0IGVlbiBFU1IxLWV4cHJlc3NpZW5pdmVhdSBkaWUgMTAwMCBlZW5oZWRlbiBob2dlciBsaWd0LgoKLSBWZXJ3YWNodGUgUzEwMEE4IGV4cHJlc3NpZW5pdmVhdSB2b29yIHBhdGnDq250ZW4gbWV0IGVlbiBFU1IxIGV4cHJlc3NpZW5pdmVhdSB2YW4gMjAwMDogIApcW2ByIHJvdW5kKGxtMSRjb2VmWzFdLDIpYC1gciBhYnMocm91bmQobG0xJGNvZWZbMl0sMykpYFx0aW1lcyAyMDAwPWByIHJvdW5kKGxtMSRjb2VmWzFdK2xtMSRjb2VmWzJdKjIwMDAsMilgXF0KCi0gVmVyd2FjaHRlIFMxMDBBOCBleHByZXNzaWVuaXZlYXUgdm9vciBwYXRpw6tudGVuIG1ldCBlZW4gRVNSMSBleHByZXNzaWVuaXZlYXUgdmFuIDQwMDA6ICAKXFtgciByb3VuZChsbTEkY29lZlsxXSwyKWAtYHIgYWJzKHJvdW5kKGxtMSRjb2VmWzJdLDMpKWBcdGltZXMgNDAwMD1gciByb3VuZChsbTEkY29lZlsxXStsbTEkY29lZlsyXSo0MDAwLDIpYFxdCi0gKipMZXQgb3Agdm9vciBleHRyYXBvbGF0aWUhKiogKFZlcm9uZGVyc3RlbGxpbmcgdmFuIGxpbmVhcml0ZWl0IGthbiBtZW4gZW5rZWwgbmFnYWFuIGJpbm5lbiBoZXQgYmVyZWlrIHZhbiBkZSBkYXRhKS4KCiMgU3RhdGlzdGlzY2hlIGJlc2x1aXR2b3JtaW5nIChzdGF0aXN0aXNjaGUgaW5mZXJlbnRpZSkKCk9tIGJlc2x1aXRlbiB0ZSBrdW5uZW4gdHJla2tlbiBvdmVyIGxpbmVhaXJlIHJlZ3Jlc3NpZW1vZGVsClxbRShZfFgpPVxiZXRhXzArXGJldGFfMSBYXF0KCm1vZXRlbiB3ZSB3ZXRlbjoKCi0gSG9lIGRlIGxlYXN0IHNxdWFyZXMgcGFyYW1ldGVyIHNjaGF0dGVycyB2YXJpw6tyZW4gdmFuIHN0ZWVrcHJvZWYgdG90IHN0ZWVrcHJvZWYsIGVuCi0gRW4gaG9lIGlzIGRpdCBvbmRlciBkZSBudWxoeXBvdGhlc2UgZGF0IGVyIGdlZW4gYXNzb2NpYXRpZSBpcyB0dXNzZW4gcHJlZGljdG9yIGVuIHJlc3BvbnNlCgotIE5vb2R6YWFrIGFhbiBzdGF0aXN0aXNjaCBtb2RlbCEKCi0gTW9kZWxsZWVyIGRlIHZlcmRlbGluZyB2YW4gJFkkIGdlZ2V2ZW4gJFgkIGV4cGxpY2lldDogJGZfe1l8WH0oeSkkCgojIyBNb2RlbGxlZXIgdmVyZGVsaW5nIHZhbiBZPwoKMS4gTmFhc3QgKmxpbmVhcml0ZWl0KiBoZWJiZW4gd2Ugbm9nIGFhbm5hbWVzIG5vZGlnIQoyLiAqT25hZmhhbmtlbGlqa2hlaWQqOiB3YWFybmVtaW5nZW4gJChYXzEsWV8xKSwgLi4uLCAgKFhfbixZX24pJCB6aWpuIGdlbWFha3Qgdm9vciBuIG9uYWZoYW5rZWxpamtlIHN1YmplY3RlbiAoSXMgdmVyZWlzdCBvbSBkZSB2YXJpYW50aWUgdGUgc2NoYXR0ZW4pCjMuICpIb21vc2NlZGFzdGljaXRlaXQgKiBvZiAqZ2VsaWprZSB2YXJpYW50aWVzKjogd2Fhcm5lbWluZ2VuIHZhcmnDq3JlbiBtZXQgZ2VsaWprIGdlbWlkZGVsZGUgcm9uZCBkZSByZWdyZXNzaWVsaWpuLgogICAgLSBSZXNpZHVlbiAkXGVwc2lsb25faSQgaGViYmVuIGdlbGlqa2UgdmFyaWFudGllIHZvb3IgZWxrZSAkWF9pPXgkCiAgICAtICRcdGV4dHt2YXJ9KFlcdmVydCBYPXgpID0gXHNpZ21hXjIkIHZvb3IgZWxrZSAkWD14JAogICAgLSAkXHNpZ21hJCB3b3JkdCBkZSAqcmVzaWR1ZWxlIHN0YW5kYWFyZGRldmlhdGllKiBnZW5vZW1kLgo0LiAqTm9ybWFsaXRlaXQqOiBkZSByZXNpZHVlbiAkXGVwc2lsb25faSQgemlqbiBub3JtYWFsIHZlcmRlZWxkCgohW10oaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL3N0YXRvbWljcy9zYmMyMC9tYXN0ZXIvZmlndXJlcy9SZWdNb2RlbDMucG5nKXt3aWR0aD0xMDAlfQoKCi0gVWl0IDIsIDMgZW4gNCB2b2xndCBkYXQKJCRcZXBzaWxvbl9pIFx0ZXh0eyBpLmkuZC59IE4oMCxcc2lnbWFeMikuJCQKLSBBbHMgd2Ugb29rIHN0ZXVuZW4gb3AgZWVyc3RlIHZlcm9uZGVyc3RlbGxpbmcgdmFuIGxpbmVhcml0ZWl0OgokJFlfaVx2ZXJ0IFhfaVxzaW0gTihcYmV0YV8wK1xiZXRhXzEgWF9pLFxzaWdtYV4yKSwkJAoKLSBWZXJkZXIga2FuIG1lbiBhYW50b25lbiBkYXQgb25kZXIgZGV6ZSBhYW5uYW1lcwokJFxzaWdtYV4yX3tcaGF0e1xiZXRhfV8wfT1cZnJhY3tcc3VtXGxpbWl0c197aT0xfV5uIFheMl9pfXtcc3VtXGxpbWl0c197aT0xfV5uIChYX2ktXGJhciBYKV4yfSBcdGltZXNcZnJhY3tcc2lnbWFeMn17bn0gXHRleHR7IGVuIH0gXHNpZ21hXjJfe1xoYXR7XGJldGF9XzF9PVxmcmFje1xzaWdtYV4yfXtcc3VtXGxpbWl0c197aT0xfV5uIChYX2ktXGJhciBYKV4yfSQkCi0gZW4gZGF0IGRlIHBhcmFtZXRlcnNjaGF0dGVycyBldmVuZWVucyBub3JtYWFsIHZlcmRlZWxkIHppam4KJCRcaGF0XGJldGFfMCBcc2ltIE5cbGVmdChcYmV0YV8wLFxzaWdtYV4yX3tcaGF0IFxiZXRhXzB9XHJpZ2h0KSBcdGV4dHsgZW4gfSBcaGF0XGJldGFfMSBcc2ltIE5cbGVmdChcYmV0YV8xLFxzaWdtYV4yX3tcaGF0IFxiZXRhXzF9XHJpZ2h0KSQkCgojIyBIb2dlIHNwcmVpZGluZyBvcCAkWCQgdmVyYmV0ZXJ0IGRlIHByZWNpc2llCgokJFxzaWdtYV4yX3tcaGF0e1xiZXRhfV8xfT1cZnJhY3tcc2lnbWFeMn17XHN1bVxsaW1pdHNfe2k9MX1ebiAoWF9pLVxiYXIgWCleMn0kJAoKIVtdKGh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9zdGF0b21pY3Mvc2JjMjAvbWFzdGVyL2ZpZ3VyZXMvc3ByZWFkLnBuZyl7IHdpZHRoPTEwMCUgfQoKLSBDb25kaXRpb25lbGUgdmFyaWFudGllICgkXHNpZ21hXjIkKSBpcyBuaWV0IGdla2VuZAotIFNjaGF0dGVuIGQubS52LiBnZW1pZGRlbGRlIHZhbiBkaWUga3dhZHJhdGlzY2hlIGFmd2lqa2luZ2VuIHJvbmQgZGUgcmVncmVzc2llcmVjaHRlCi0gKm1lYW4gc3F1YXJlZCBlcnJvciogKE1TRSkKCiQkXGhhdFxzaWdtYV4yPU1TRT1cZnJhY3tcc3VtXGxpbWl0c197aT0xfV5uIFxsZWZ0KHlfaS1caGF0XGJldGFfMC1caGF0XGJldGFfMVx0aW1lcyB4X2lccmlnaHQpXjJ9e24tMn09XGZyYWN7XHN1bVxsaW1pdHNfe2k9MX1ebiBlXjJfaX17bi0yfS4kJAotIFZvb3IgaGV0IGJla29tZW4gdmFuIGRlemUgc2NoYXR0ZXIgc3RldW5lbiB3ZSBvcCBvbmFmaGFua2VsaWpraGVpZCAoYWFubmFtZSAyKSBlbiBob21vc2NlZGFzdGljaXRlaXQgKGFhbm5hbWUgMykuCi0gZGVlbCBkb29yICRuLTIkCgpOYSBzY2hhdHRpbmcgdmFuICRcc2lnbWFeMiQgYmVrb21lbiB3ZSB2b2xnZW5kZSBzdGFuZGFhcmQgZXJyb3JzOgoKJCRcdGV4dHtTRX1fe1xoYXR7XGJldGF9XzB9PVxoYXRcc2lnbWFfe1xoYXR7XGJldGF9XzB9PVxzcXJ0e1xmcmFje1xzdW1cbGltaXRzX3tpPTF9Xm4gWF4yX2l9e1xzdW1cbGltaXRzX3tpPTF9Xm4gKFhfaS1cYmFyIFgpXjJ9IFx0aW1lc1xmcmFje1x0ZXh0e01TRX19e259fSBcdGV4dHsgZW4gfSBcdGV4dHtTRX1fe1xoYXR7XGJldGF9XzF9PVxoYXRcc2lnbWFfe1xoYXR7XGJldGF9XzF9PVxzcXJ0e1xmcmFje1x0ZXh0e01TRX19e1xzdW1cbGltaXRzX3tpPTF9Xm4gKFhfaS1cYmFyIFgpXjJ9fSQkCgotIE9wbmlldXcgdG9ldHNlbiBlbiBiZXRyb3V3YmFhcmhlaWRzaW50ZXJ2YWxsZW4gby5iLnYuCiQkVD1cZnJhY3tcaGF0e1xiZXRhfV9rLVxiZXRhX2t9e1NFKFxoYXR7XGJldGF9X2spfSBcdGV4dHsgd2l0aCB9IGs9MSwyLiQkCgotIEFscyBhYW4gYWxsZSBhYW5uYW1lcyBpcyB2b2xkYWFuIHZvbGd0ICRUJCBlZW4gdC12ZXJkZWxpbmcgbWV0IG4tMiB2cmlqaGVpZHNncmFkZW4uCgotIEFscyBnZWVuIG5vcm1hbGl0ZWl0IG1hYXIgd2VsIG9uYWZoYW5rZWxpamssIGxpbmVhcml0ZWl0IGVuIGhvbW9zY2VkYXN0aWNpdGVpdCBlbiBncm90ZSBkYXRhc2V0ClxbXHJpZ2h0YXJyb3cgXHRleHR7Q2VudHJhbGUgTGltaWV0c3RlbGxpbmd9XF0KCgojIyMgQm9yc3RrYW5rZXIgdm9vcmJlZWxkCgotIE5lZ2F0aWV2ZSBhc3NvY2lhdGllIHR1c3NlbiBTMTAwQTggZW4gRVNSMSBnZW4gZXhwcmVzc2llLgoKLSBWZXJhbGdlbWVlbiBlZmZlY3QgaW4gc3RlZWtwcm9lZiBuYWFyIHBvcHVsYXRpZSBtZXQgYmVodWxwIHZhbiBoZXQgYmV0cm91d2JhYXJoZWlkc2ludGVydmFsIG9wIGRlIGhlbGxpbmc6CiQkW1xoYXRcYmV0YV8xIC0gdF97bi0yLFxhbHBoYS8yfSBcdGV4dHtTRX1fe1xoYXRcYmV0YV8xfSxcaGF0XGJldGFfMSArIHRfe24tMixcYWxwaGEvMn0gXHRleHR7U0V9X3tcaGF0XGJldGFfMX1dJCQuCgpgYGB7cn0KY29uZmludChsbTEpCmBgYAoKLSBOZWdhdGllZiB2ZXJiYW5kIGlzIHNpZ25pZmljYW50IG9wIGhldCA1JSBzaWduaWZpY2FudGllbml2ZWF1LgoKCiMjIEh5cG90aGVzZSB0ZXN0CgotIFZlcnRhYWwgZGUgb25kZXJ6b2Vrc3ZyYWFnICJJcyBlciBlZW4gYXNzb2NpYXRpZSB0dXNzZW4gZGUgUzEwMEE4LSBlbiBFU1IxLWdlbmV4cHJlc3NpZT8iIG5hYXIgZGUgcGFyYW1ldGVycyBpbiBoZXQgbW9kZWwuCi0gT25kZXIgbnVsaHlwb3RoZXNlIGdlZW4gYXNzb2NpYXRpZSB0dXNzZW4gZXhwcmVzc2llIHZhbiBiZWlkZSBnZW5lbjoKJCRIXzA6IFxiZXRhXzE9MCQkCgotIE9uZGVyIGFsdGVybmF0aWV2ZSBoeXBvdGhlc2UgaXMgZXIgZWVuIGFzc29jaWF0aWUgdHVzc2VuIGJlaWRlIGdlbmVuOgokJEhfMTogXGJldGFfMVxuZXEwJCQKCi0gVGVzdCBzdGF0aXN0aWVrCiQkVD1cZnJhY3tcaGF0e1xiZXRhfV8xLTB9e1NFKFxoYXR7XGJldGF9X2spfSQkCgotIE9uZGVyICRIXzAkIHZvbGd0IGRlIHN0YXRpc3RpZWsgZWVuIHQtdmVyZGVsaW5nIG1ldCBuLTIgdnJpamhlaWRzZ3JhZGVuLgoKIyMjIEJyY2EgZGF0YXNldAoKYGBge3J9CnN1bW1hcnkobG0xKQpgYGAKCgotIEFzc29jaWF0aWUgdHVzc2VuIGRlIFMxMDBBOCBlbiBFU1IxIGdlbmV4cHJlc3NpZSBleHRyZWVtIHNpZ25pZmljYW50IGlzIChwPDwwLjAwMSkuCi0gTWFhciBlZXJzdCBtb2V0ZW4gd2UgYWxsZSBhc3N1bXB0aWVzIGNvbnRyb2xlcmVuIQotIEFuZGVycyBrdW5uZW4gZGUgY29uY2x1c2llcyBvLmIudi4gZGUgc3RhdGlzdGlzY2hlIHRlc3QgZW4gaGV0IEJJIG9uanVpc3Qgemlqbi4gIAoKIyBOYWdhYW4gdmFuIG1vZGVsdmVyb25kZXJzdGVsbGluZ2VuCgotIE9uYWZoYW5rZWxpamtoZWlkOiBkZXNpZ24KLSBMaW5lYXJpdGVpdDogYmVzbHVpdHZvcm1pbmcgZ2VlbiB6aW4gYWxzIG1vZGVsIG5pZXQgbGluZWFpciBpcwotIEhvbW9zY2VkYXN0aWNpdGVpdDogYmVzbHVpdHZvcm1pbmcvcC13YWFyZGUgaXMgbmlldCBiZXRyb3V3YmFhciBhbHMgZGUgZGF0YSBuaWV0IGhvbW9zY2VkYXN0aXNjaCB6aWpuCi0gTm9ybWFsaXRlaXQ6IGJlc2x1aXR2b3JtaW5nL3Atd2FhcmRlIGlzIG5pZXQgYmV0cm91d2JhYXIgYWxzIGRlIGRhdGEgbmlldCBub3JtYWFsIHZlcmRlZWxkIHppam4gaW4ga2xlaW5lIHN0ZWVrcHJvZXZlbgoKCiMjIExpbmVhcml0ZWl0CgpgYGB7ciBmaWcuYWxpZ249J2NlbnRlcid9CmJyY2FTdWJzZXQgJT4lCiAgZ2dwbG90KGFlcyh4ID0gRVNSMSwgeSA9IFMxMDBBOCkpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fc21vb3RoKHNlID0gRkFMU0UsIGNvbCA9ICJncmV5IikgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UpCmBgYAoKCiMjIFJlc2lkdXBsb3RzCgotIEFmd2lqa2luZ2VuIHZhbiBsaW5lYXJpdGVpdCBlY2h0ZXIgbWFra2VsaWprZXIgb3BnZXNwb29yZCBkLm0udi4gZWVuICpyZXNpZHVwbG90Ki4gKFpla2VyIGFscyBlciBsYXRlciBtZWVyIHZhcmlhYmVsZW4gemlqbiBpbiBoZXQgbGluZWFpcmUgbW9kZWwpCgotIHZlcmtsYXJlbmRlIHZhcmlhYmVsZSBvZiBwcmVkaWN0aWVzICRcaGF0XGJldGFfMCtcaGF0XGJldGFfMSB4JCBvcCBkZSAkWCQtYXMKCi0gZGUgKnJlc2lkdWVuKiBvcCBkZSAkWSQtYXMKJCRlX2k9eV9pLVxoYXR7Z30oeF9pKT15X2ktXGhhdFxiZXRhXzAtXGhhdFxiZXRhXzFcdGltZXMgeF9pLCQkCgpgYGB7cn0KcGxvdChsbTEpCmBgYAoKIyMgSG9tb3NjZWRhc3RpY2l0ZWl0IChnZWxpamtoZWlkIHZhbiB2YXJpYW50aWUpCgotIFJlc2lkdWVuIGVuIGt3YWRyYXRpc2NoZSByZXNpZHXigJlzIGRyYWdlbiBpbmZvcm1hdGllIG92ZXIgcmVzaWR1ZWxlIHZhcmlhYmlsaXRlaXQuCgotIEFzc29jaWF0aWUgbWV0IGRlIHZlcmtsYXJlbmRlIHZhcmlhYmVsZW4gJFxyaWdodGFycm93JCBpbmRpY2F0aWUgdmFuIGhldGVyb3NjZWRhc3RpY2l0ZWl0LgoKLSBTY2F0dGVycGxvdCB2YW4gb2YgJGVfaSQgdmVyc3VzICR4X2kkIG9mIHByZWRpY3RpZXMgJFxoYXQgXGJldGFfMCsgXGhhdCBcYmV0YV8xIHhfaSQuCgotIFNjYXR0ZXJwbG90IHZhbiBnZXN0YW5kYXJkaXNlZXJkIHJlc2lkdSB2ZXJzdXMgJHhfaSQgb2YgcHJlZGljdGllcy4KCgojIyBOb3JtYWxpdGVpdAoKLSBJbmRpZW4gdm9sZG9lbmRlIGdlZ2V2ZW5zLCBzY2hhdHRlcnMgbm9ybWFhbCB2ZXJkZWVsZCB6ZWxmcyB3YW5uZWVyIG9ic2VydmF0aWVzIG5pZXQgTm9ybWFhbCB2ZXJkZWVsZCB6aWpuOiBjZW50cmFsZSBsaW1pZXQgc3RlbGxpbmcKCi0gV2F0IOKAmHZvbGRvZW5kZSBvYnNlcnZhdGllc+KAmSB6aWpuLCBoYW5ndCBhZiB2YW4gaG9lIGdvZWQgZGUgdmVyZGVsaW5nIG9wIGRlIE5vcm1hbGUgbGlqa3QuCgotIEFhbm5hbWUgaXMgZGF0IHVpdGtvbXN0ZW4gTm9ybWFhbCB2ZXJkZWVsZCB6aWpuIGJpaiB2YXN0ZSB3YWFyZGVuIHZhbiBkZSB2ZXJrbGFyZW5kZSB2YXJpYWJlbGVuLgokJFlfaVx2ZXJ0IFhfaVxzaW0gTihcYmV0YV8wK1xiZXRhXzFYX2ksXHNpZ21hXjIpJCQKCi0gUVEtcGxvdCB2YW4gcmVzcG9uc2UgWSBpcyBoZWVsIG1pc2xlaWRlbmQuCgotIFFRLXBsb3QgdmFuIGRlIHJlc2lkdWVuICRlX2kkCgpgYGB7ciBlY2hvPUZBTFNFfQpzZXQuc2VlZCA8LSAyMDAKcGFyKG1mcm93PWMoMSwzKSkKeCA8LSByZXAoMToxMCxlYWNoPTIwKQp5IDwtIHgrcm5vcm0obGVuZ3RoKHgpKQpib3hwbG90KHl+eCkKcXFub3JtKHksIG1haW49Ik9yaWdpbmFsIG9ic2VydmF0aW9ucyIpCnFxbGluZSh5KQpsbUggPC0gbG0oeX54KQpwbG90KGxtSCwgd2hpY2g9MiwgbWFpbj0iUmVzaWR1YWxzIikKYGBgCgoKYGBge3J9CnBsb3QobG0xLCB3aGljaD0yKQpgYGAKCgojIEFmd2lqa2luZ2VuIHZhbiBNb2RlbHZlcm9uZGVyc3RlbGxpbmdlbgoKLSBUcmFuc2Zvcm1hdGllIHZhbiBvbmFmaGFua2VsaWprZSB2ZXJhbmRlcmxpamtlIHdpanppZ3QgZGUgdmVyZGVsaW5nIHZhbiBZIGJpaiBnZWdldmVuIFggbmlldDoKCiAgICAtIGhlbHB0IG5pZXQgb20gbm9ybWFsaXRlaXQgb2YgaG9tb3NjZWRhc3RpY2l0ZWl0IHRlIGJla29tZW4KICAgIC0gaGVscHQgd2VsIG9tIGxpbmVhcml0ZWl0IHRlIGJla29tZW4gd2FubmVlciBlciBub3JtYWxpdGVpdCBlbiBob21vc2NlZGFzdGljaXRlaXQgaXMKICAgIC0gVmFhayBvb2sgaG9nZXJlIG9yZGUgdGVybWVuOiAkWF4yJCwgJFheMyQsIC4uLgogICAgJCRZX2k9XGJldGFfMCtcYmV0YV8xWF9pK1xiZXRhXzJYX2leMisgLi4uICsgXGVwc2lsb25faSQkCgoKLSBUcmFuc2Zvcm1hdGllIHZhbiByZXNwb25zZSBZIGthbiBoZWxwZW4gb20gbm9ybWFsaXRlaXQgZW4gaG9tb3NjZWRhc3RpY2l0ZWl0IHRlIGJla29tZW4uCgogICAgLSAgJFxzcXJ0KFkpJCwgJFxsb2coWSkkLCAxL1ksIC4uLgoKCiMjIEJvcnN0a2Fua2VyIHZvb3JiZWVsZAoKUHJvYmxlbWVuIG1ldAoKLSAgaGV0ZXJvc2NlZGFzdGljaXRlaXQKLSBtb2dlbGlqa3NlIGFmd2lqa2luZyB2YW4gbm9ybWFsaXRlaXQgKHNjaGVlZmhlaWQgbmFhciByZWNodHMpCi0gbmVnYXRpZXZlIGNvbmNlbnRyYXRpZXZvb3JzcGVsbGluZ2VuIGRpZSB0aGVvcmV0aXNjaCBuaWV0IG1vZ2VsaWprIHppam4KLSBuaWV0LWxpbmVhaXJpdGVpdAoKLSB0cmVlZHQgdmVlbGFsIG9wIGJpaiBjb25jZW50cmF0aWUgZW4gaW50ZW5zaXRlaXRzbWV0aW5nZW4KLSBEZXplIHppam4gdmFhayBsb2ctbm9ybWFhbCB2ZXJkZWVsZCAobm9ybWFsZSB2ZXJkZWxpbmcgbmEgbG9nLXRyYW5zZm9ybWF0aWUpCi0gSW4gRmlndXVyIDYuMyBldmVuZWVucyBlZW4gc29vcnQgZXhwb25lbnRpw6tsZSB0cmVuZAotIEluIGRlIGdlbmV4cHJlc3NpZSBsaXRlcmF0dXVyIHdvcmR0IHZlZWxhbCBnZWJydWlrIGdlbWFhayB2YW4gJFxsb2dfMiQgdHJhbnNmb3JtYXRpZQotIGdlbi1leHByZXNzaWUgb3AgbG9nLXNjaGFhbCBwcm9wb3J0aW9uZWxlIHZlcnNjaGlsbGVuIG9wIGRlIG9yaWdpbmVsZSBzY2hhYWwKCgpgYGB7cn0KYnJjYSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBFU1IxLCB5ID0gUzEwMEE4KSkgKwogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9zbW9vdGgoKQpgYGAKCmBgYHtyfQpicmNhICU+JQogIGdncGxvdChhZXMoCiAgICB4ID0gRVNSMSAlPiUgbG9nMiwKICAgIHkgPSBTMTAwQTggJT4lIGxvZzIpCiAgICApICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fc21vb3RoKCkKYGBgCgpgYGB7cn0KbG0yPC1sbShTMTAwQTggJT4lIGxvZzIgfiBFU1IxICU+JSBsb2cyLCBicmNhKQpwbG90KGxtMikKc3VtbWFyeShsbTIpCmBgYAoKCmBgYHtyfQpjb25maW50KGxtMikKYGBgCgoKIyMjIEludGVycHJldGF0aWUgMQoKRWVuIHBhdGnDq250IG1ldCBlZW4gRVNSMSBleHByZXNzaWUgZGllIDEgZWVuaGVpZCBvcCBkZSAkXGxvZ18yJCBzY2hhYWwgaG9nZXIgbGlndCBkYW4gZGF0IHZhbiBlZW4gYW5kZXJlIHBhdGnDq250IGhlZWZ0IGdlbWlkZGVsZCBnZXppZW4gZWVuIGV4cHJlc3NpZS1uaXZlYXUgdmFuIGhldCBTMTAwQTggZ2VuICBkYXQgYHIgYWJzKHJvdW5kKGxtMiRjb2VmWzJdLDIpKWAgZWVuaGVkZW4gbGFnZXIgbGlndCAoOTVcJSBCSSBbYHIgcGFzdGUocm91bmQoY29uZmludChsbTIpWzIsXSwyKSxjb2xsYXBzZT0iLCIpYF0pLgoKKipDcm9zc2VjdGlvbmVsZSBzdHVkaWU6IGVua2VsIHVpdHNwcmFrZW4gb3ZlciB2ZXJzY2hpbGxlbiB0dXNzZW4gcGF0acOrbnRlbiEqKgoKJCRcbG9nXzIgXGhhdFxtdV8xPTIzLjQwMSAgLTEuNjE1IFx0aW1lcyBcdGV4dHtsb2dFU1J9XzEsXHRleHR7IH0gXGxvZ18yIFxoYXRcbXVfMj0yMy40MDEgIC0xLjYxNSBcdGltZXMgXHRleHR7bG9nRVNSfV8yICQkCiQkXGxvZ18yIFxoYXRcbXVfMi1cbG9nXzIgXGhhdFxtdV8xPSAgLTEuNjE1IChcbG9nXzIgXHRleHR7RVNSfV8yLVxsb2dfMiBcdGV4dHtFU1J9XzEpID0gLTEuNjE1IFx0aW1lcyAxID0gLTEuNjE1JCQKCiMjIyBJbnRlcnByZXRhdGllIDIKCk1vZGVsIG9wIGxvZy1zY2hhYWw6IGJpaiB0ZXJ1Z3RyYW5zZm9ybWF0aWUgdmVya3JpamdlbiB3ZSBoZXQgZ2VvbWV0cmlzY2hlIGdlbWlkZGVsZGUKClxiZWdpbntlcW5hcnJheSp9ClxzdW1cbGltaXRzX3tpPTF9Xm4gXGZyYWN7XGxvZyB4X2l9e259Jj0mXGZyYWN7XGxvZyB4XzEgKyBcbGRvdHMgKyBcbG9nIHhfbn17bn1cXFxcCiZcc3RhY2tyZWx7KDEpfXs9fSZcZnJhY3tcbG9nKHhfMSBcdGltZXMgXGxkb3RzIFx0aW1lcyB4X24pfXtufT1cZnJhY3tcbG9nXGxlZnQoXHByb2RcbGltaXRzX3tpPTF9Xm4geF9pXHJpZ2h0KX17bn1cXFxcCiZcc3RhY2tyZWx7KDIpfXs9fSZcbG9nIFxsZWZ0KFxzcXJ0W1xsZWZ0cm9vdHstMX1cdXByb290ezJ9XHNjcmlwdHN0eWxlIG5de1xwcm9kXGxpbWl0c197aT0xfV5uIHhfaX1ccmlnaHQpClxlbmR7ZXFuYXJyYXkqfQoKLSBQb3B1bGF0aWVnZW1pZGRlbGRlbiAkXG11JCBkdXMgZ2VzY2hhdCBhLmQuaC52LiBnZW9tZXRyaXNjaCBnZW1pZGRlbGRlbi4KLSBMb2dhcml0bWlzY2hlIHRyYW5zZm9ybWF0aWUgaXMgZWVuIG1vbm90b29uOiB3ZSBrdW5uZW4gYmV0cm91d2JhYXJoZWlkc2ludGVydmFsbGVuIGJlcmVrZW5kIG9wIGxvZy1zY2hhYWwgdGVydWd0cmFuc2Zvcm1lcmVuIQoKYGBge3J9CjJebG0yJGNvZWZbMl0KMl4tbG0yJGNvZWZbMl0KMl4tY29uZmludChsbTIpWzIsXQpgYGAKCkVlbiBwYXRpw6tudCBtZXQgZWVuIEVTUjEgZXhwcmVzc2llIGRpZSAyIGtlZXIgem8gaG9vZyBpcyBhbHMgZGllIHZhbiBlZW4gYW5kZXJlIHBhdGnDq250LCB6YWwgZ2VtaWRkZWxkIGVlbiBTMTAwQTgtZXhwcmVzc2llIGhlYmJlbiBkaWUgYHIgcm91bmQoMl4tbG0yJGNvZWZbMl0KLDIpYCBrZWVyIGxhZ2VyIGlzICg5NVwlIEJJIFtgciBwYXN0ZShzb3J0KHJvdW5kKDJeLWNvbmZpbnQobG0yKVsyLF0sMikpLGNvbGxhcHNlPSIsIilgXSkuCgoKJCRcbG9nXzIgXGhhdFxtdV8xPTIzLjQwMSAgLTEuNjE1IFx0aW1lcyBcdGV4dHtsb2dFU1J9XzEsXHRleHR7IH0gXGxvZ18yIFxoYXRcbXVfMj0yMy40MDEgIC0xLjYxNSBcdGltZXMgXHRleHR7bG9nRVNSfV8yICQkCiQkXGxvZ18yIFxoYXRcbXVfMi1cbG9nXzIgXGhhdFxtdV8xPSAgLTEuNjE1IChcbG9nXzIgXHRleHR7RVNSfV8yLVxsb2dfMiBcdGV4dHtFU1J9XzEpICQkCiQkXGxvZ18yIFxsZWZ0W1xmcmFje1xoYXRcbXVfMn17XGhhdFxtdV8xfVxyaWdodF09ICAtMS42MTUgXGxvZ18yXGxlZnRbXGZyYWN7IFx0ZXh0e0VTUn1fMn17XHRleHR7RVNSfV8xfVxyaWdodF0gJCQKJCRcZnJhY3tcaGF0XG11XzJ9e1xoYXRcbXVfMX09XGxlZnRbXGZyYWN7IFx0ZXh0e0VTUn1fMn17XHRleHR7RVNSfV8xfVxyaWdodF1eey0xLjYxNX09Ml4gey0xLjYxNX0gPTAuMzI2JCQKb3IKJCRcZnJhY3tcaGF0XG11XzF9e1xoYXRcbXVfMn09Ml57MS42MTV9ID0zLjA2JCQKCgojIyMgSW50ZXJwcmF0aWUgMwoKRWVuIHBhdGnDq250IG1ldCBlZW4gRVNSMSBleHByZXNzaWUgZGllIDFcJSBob2dlciBpcyBkYW4gZGllIHZhbiBlZW4gYW5kZXJlIHBhdGnDq250IHphbCBnZW1pZGRlbGQgZWVuIGV4cHJlc3NpZW5pdmVhdSB2b29yIGhldCBTMTAwQTggZ2VuICBoZWJiZW4gZGF0IG9uZ2V2ZWVyIGByIHJvdW5kKGxtMiRjb2VmWzJdLDIpYCUgbGFnZXIgaXMgKDk1XCUgQkkgW2ByIHBhc3RlKHJvdW5kKGNvbmZpbnQobG0yKVsyLF0sMiksY29sbGFwc2U9IiwiKWBdKSUuCgokJFxsb2dfMiBcaGF0XG11XzE9MjMuNDAxICAtMS42MTUgXHRpbWVzIFx0ZXh0e2xvZ0VTUn1fMSxcdGV4dHsgfSBcbG9nXzIgXGhhdFxtdV8yPTIzLjQwMSAgLTEuNjE1IFx0aW1lcyBcdGV4dHtsb2dFU1J9XzIgJCQKJCRcbG9nXzIgXGhhdFxtdV8yLVxoYXRcbG9nXzIgXG11XzE9ICAtMS42MTUgKFxsb2dfMiBcdGV4dHtFU1J9XzItXGxvZ18yIFx0ZXh0e0VTUn1fMSkgJCQKJCRcbG9nXzIgXGxlZnRbXGZyYWN7XGhhdFxtdV8yfXtcaGF0XG11XzF9XHJpZ2h0XT0gIC0xLjYxNSBcbG9nXzJcbGVmdFtcZnJhY3sgXHRleHR7RVNSfV8yfXtcdGV4dHtFU1J9XzF9XHJpZ2h0XSAkJAokJFxmcmFje1xoYXRcbXVfMn17XGhhdFxtdV8xfT1cbGVmdFtcZnJhY3sgXHRleHR7RVNSfV8yfXtcdGV4dHtFU1J9XzF9XHJpZ2h0XV57LTEuNjE1fT0xLjAxXiB7LTEuNjE1fSA9MC45ODQgXGFwcHJveCAtMS42XCUkJAoKRGl0IGdlbGR0IHZvb3IgbGFnZSB0b3QgbWF0aWdlIHdhYXJkZW4gdmFuICRcYmV0YV8xJDoKJCQtMTA8XGJldGFfMTwxMCBccmlnaHRhcnJvdyAxLjAxXntcYmV0YV8xfSAtMSBcYXBwcm94IFxmcmFje1xiZXRhXzF9ezEwMH0uJCQKCiMgQmVzbHVpdHZvcm1pbmcgb3ZlciBnZW1pZGRlbGRlIHVpdGtvbXN0CgotIFJlZ3Jlc3NpZSBtb2RlbCBrYW4gb29rIHdvcmRlbiBnZWJydWlrdCB2b29yIHByZWRpY3RpZQoKLSBCZXNsdWl0dm9ybWluZyB0ZSBkb2VuIG92ZXIgZGUgZ2VtaWRkZWxkZSB1aXRrb21zdCBiaWogZWVuIGdlZ2V2ZW4gd2FhcmRlICR4JCwgbS5hLncuCiQkXGhhdHtnfSh4KT0gXGhhdHtcYmV0YX1fMCArIFxoYXR7XGJldGF9XzEgeCQkCi0gJFxoYXR7Z30oeCkkIGVlbiBzY2hhdHRlciB2YW4gaGV0IGNvbmRpdGlvbmVsZSBnZW1pZGRlbGRlICRFW1lcdmVydCBYPXhdJAoKLSBQYXJhbWV0ZXJzY2hhdHRlcnMgTm9ybWFsZSB2ZXJkZWVsZCBlbiBvbnZlcnRla2VuZCAkXHJpZ2h0YXJyb3ckIHNjaGF0dGVyICRcaGF0e2d9KHgpJCBvb2sgTm9ybWFhbCB2ZXJkZWVsZCBlbiBvbnZlcnRla2VuZC4KCiQkXHRleHR7U0V9X3tcaGF0e2d9KHgpfT1cc3FydHtNU0VcbGVmdFx7XGZyYWN7MX17bn0rXGZyYWN7KHgtXGJhciBYKV4yfXtcc3VtXGxpbWl0c197aT0xfV5uIChYX2ktXGJhciBYKV4yfVxyaWdodFx9fS4kJAoKJCRUPVxmcmFje1xoYXR7Z30oeCktZyh4KX17U0Vfe1xoYXR7Z30oeCl9fVxzaW0gdF97bi0yfSQkCgotIEdlbWlkZGVsZGUgdWl0a29tc3QgZW4gYmV0cm91d2JhYXJoZWlkc2ludGVydmFsbGVuIG9wIGRlIGdlbWlkZGVsZGUgdWl0a29tc3QgaW4gUiB2aWEgZGUgYHByZWRpY3QoLilgIGZ1bmN0aWUuCi0gYG5ld2RhdGFgIGFyZ3VtZW50OiBwcmVkaWN0b3J3YWFyZGVuICh4LXdhYXJkZW4pIHZvb3IgaGV0IGJlcmVrZW5lbiB2YW4gZ2VtaWRkZWxkZSB1aXRrb21zdGVuCi0gYGludGVydmFsPSJjb25maWRlbmNlImAgYXJndW1lbnQgb20gYmV0cm91d2JhYXJoZWlkc2ludGVydmFsbGVuIHRlIGJla29tZW4uCi0gWm9uZGVyIGBuZXdkYXRhYCBhcmd1bWVudCB3b3JkdCBkZSBnZW1pZGRlbGRlIHVpdGtvbXN0ZW4gYmVyZWtlbmQgdm9vciBhbGxlIHByZWRpY3RvcndhYXJkZW4gdmFuIGRlIGRhdGFzZXQuCgoKYGBge3J9CmdyaWQgPC0gMTQwOjQwMDAKZyA8LSBwcmVkaWN0KAogIGxtMiwKICBuZXdkYXRhID0gZGF0YS5mcmFtZShFU1IxID0gZ3JpZCksCiAgaW50ZXJ2YWwgPSAiY29uZmlkZW5jZSIpCmhlYWQoZykKYGBgCgpNZXJrIG9wIGRhdCB3ZSBkZSBuaWV1d2UgZGF0YSBkaWUgd2UgZ2VzcGVjaWZpY2VlcmQgaGViYmVuIHZvb3IgZGUgRVNSMSBleHByZXNzaWUgbmlldCBtb2V0ZW4gdHJhbnNmb3JtZXJlbiBvbWRhdCB3ZSBoZXQgbW9kZWwgZml0dGVuIG1ldCBkZSBgbG1gZnVuY3RpZSBlbiBkZSB0cmFuc2Zvcm1hdGllIGhlYmJlbiBnZXNwZWNpZmljZWVyZCBiaW5uZW4gZGllIGZ1bmN0aWUgbWV0IGJlaHVscCB2YW4gaGV0IHBpcGUgY29tbWFuZG8hCgpgYGB7cn0KYnJjYSAlPiUgZ2dwbG90KAogIGFlcygKICAgIHggPSBFU1IxICU+JSBsb2cyLAogICAgeSA9IFMxMDBBOCAlPiUgbG9nMikKICApICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIpCmBgYAoKIyMgVGVydWd0cmFuc2Zvcm1hdGllCmBgYHtyfQpuZXdkYXRhPC1kYXRhLmZyYW1lKGNiaW5kKGdyaWQsMl5nKSkKYnJjYSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBFU1IxLCB5ID0gUzEwMEE4KSkgKwogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9saW5lKGFlcyh4PWdyaWQseT1maXQpLG5ld2RhdGEpICsKICBnZW9tX2xpbmUoYWVzKHg9Z3JpZCx5PWx3ciksbmV3ZGF0YSxjb2xvcj0iZ3JleSIpICsKICBnZW9tX2xpbmUoYWVzKHg9Z3JpZCx5PXVwciksbmV3ZGF0YSxjb2xvcj0iZ3JleSIpCmBgYAoKIyBQcmVkaWN0aWUtaW50ZXJ2YWxsZW4KCi1XZSBrdW5uZW4gb29rIGVlbiB2b29yc3BlbGxpbmcgZG9lbiB2b29yIGRlIGxvY2F0aWUgdmFuIGVlbiBuaWV1d2Ugd2Fhcm5lbWluZyBkaWUgem91IHdvcmRlbiB2ZXJ6YW1lbGQgaW4gZWVuIG5pZXV3IGV4cGVyaW1lbnQgdm9vciBlZW4gcGF0acOrbnQgbWV0IGVlbiBiZXBhYWxkZSB3YWFyZGUgdm9vciBodW4gRVNSMS1leHByZXNzaWUKCi0gSGV0IGlzIGJlbGFuZ3Jpamsgb3AgdGUgbWVya2VuIGRhdCBkaXQgZXhwZXJpbWVudCBub2cgbW9ldCB3b3JkZW4gdWl0Z2V2b2VyZC4gV2Ugd2lsbGVuIGR1cyBkZSBuaWV0LXdhYXJnZW5vbWVuIGluZGl2aWR1ZWxlIGV4cHJlc3NpZXdhYXJkZSB2b29yIGVlbiBuaWV1d2UgcGF0acOrbnQgdm9vcnNwZWxsZW4uCgotIFZvb3IgZWVuIG5pZXV3ZSBvbmFmaGFua2VsaWprZSB3YWFybmVtaW5nICRZXiokCiQkCiAgWV4qID0gZyh4KSArIFxlcHNpbG9uXioKJCQKbWV0ICRcZXBzaWxvbl4qXHNpbSBOKDAsXHNpZ21hXjIpJCBlbiAkXGVwc2lsb25eKiQgb25hZmhhbmtlbGlqayB2YW4gZGUgd2Fhcm5lbWluZ2VuIGluIGRlIHN0ZWVrcHJvZWYgJFlfMSxcbGRvdHMsIFlfbiQuCgotIFdlIHZvb3JzcGVsbGVuIGVlbiBuaWV1d2UgbG9nLVMxMDBBOCB2b29yIGVlbiBwYXRpw6tudCBtZXQgZWVuIGdla2VuZCBsb2cyLUVTUjEtZXhwcmVzc2llbml2ZWF1IHgKXFsKICBcaGF0e3l9KHgpPVxoYXR7XGJldGF9XzArXGhhdHtcYmV0YX1fMSBcdGltZXMgeApcXQoKLSAgRGUgZ2VzY2hhdHRlIGdlbWlkZGVsZGUgdWl0a29tc3QgZW4gdm9vcnNwZWxsaW5nIHZvb3IgZWVuIG5pZXV3ZSB3YWFybmVtaW5nIHppam4gZ2VsaWprLgoKLSAgTWFhciBodW4gc3RlZWtwcm9lZiB2ZXJkZWxpbmdlbiB6aWpuIGFuZGVycyEKCiAgICAtIE9uemVrZXJoZWlkIG92ZXIgZGUgZ2VzY2hhdHRlIGdlbWlkZGVsZGUgdWl0a29tc3QgICAkXGxlZnRhcnJvdyQgb256ZWtlcmhlaWQgb3ZlciBkZSBnZXNjaGF0dGUgbW9kZWxwYXJhbWV0ZXJzICRcaGF0XGJldGFfMCQgZW4gJFxoYXRcYmV0YV8xJC4KICAgIC0gT256ZWtlcmhlaWQgb3ZlciBuaWV1d2Ugd2Fhcm5lbWluZyAkXGxlZnRhcnJvdyQgKm9uemVrZXJoZWlkIG92ZXIgZ2VzY2hhdCBnZW1pZGRlbGRlKiBlbiAgKmV4dHJhIG9uemVrZXJoZWlkKiAgb21kYXQgZGUgbmlldXdlIHdhYXJuZW1pbmcgemFsIGFmd2lqa2VuIHJvbmQgaGV0IGdlbWlkZGVsZGUhCgoKJCRcdGV4dHtTRX1fe1xoYXR7WX0oeCl9PVxzcXJ0e1xoYXRcc2lnbWFeMitcaGF0XHNpZ21hXjJfe1xoYXR7Z30oeCl9fT1cc3FydHtNU0VcbGVmdFx7MStcZnJhY3sxfXtufStcZnJhY3soeC1cYmFyIFgpXjJ9e1xzdW1cbGltaXRzX3tpPTF9Xm4gKFhfaS1cYmFyIFgpXjJ9XHJpZ2h0XH19LiQkCgokJFxmcmFje1xoYXR7WX0oeCktWX17XHRleHR7U0V9X3tcaGF0e1l9KHgpfX1cc2ltIHRfe24tMn0kJAoKLSBNZXJrIG9wIGRhdCBlZW4gKipwcmVkaWN0aWUtaW50ZXJ2YWwqKiAoUEkpIGVlbiB2ZXJiZXRlcmRlIHZlcnNpZSBpcyB2YW4gZWVuIHJlZmVyZW50aWUtaW50ZXJ2YWwgd2FubmVlciBkZSBtb2RlbHBhcmFtZXRlcnMgb25iZWtlbmQgemlqbjogb256ZWtlcmhlaWQgb3ZlciBtb2RlbHBhcmFtZXRlcnMgKyB0LXZlcmRlbGluZy4KCgpgYGB7cn0KcCA8LSBwcmVkaWN0KAogIGxtMiwKICBuZXdkYXRhID0gZGF0YS5mcmFtZShFU1IxID0gZ3JpZCksCiAgaW50ZXJ2YWw9InByZWRpY3Rpb24iKQoKaGVhZChwKQpgYGAKCmBgYHtyfQpwcmVkZGF0YTwtZGF0YS5mcmFtZSgKICBncmlkID0gZ3JpZCU+JWxvZzIsCiAgcCkKYnJjYSAlPiUgZ2dwbG90KGFlcyh4PUVTUjElPiVsb2cyLHk9UzEwMEE4JT4lbG9nMikpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fc21vb3RoKG1ldGhvZD0ibG0iKSArCiAgICAgZ2VvbV9saW5lKGFlcyh4PWdyaWQseT1sd3IpLHByZWRkYXRhLGNvbG9yPSJibHVlIikgKwogIGdlb21fbGluZShhZXMoeD1ncmlkLHk9dXByKSxwcmVkZGF0YSxjb2xvcj0iYmx1ZSIpCmBgYAoKYGBge3J9CnByZWRkYXRhPC1kYXRhLmZyYW1lKGNiaW5kKGdyaWQsMl5wKSkKYnJjYSAlPiUgZ2dwbG90KGFlcyh4ID0gRVNSMSwgeSA9IFMxMDBBOCkpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fbGluZSgKICAgIGFlcyh4ID0gZ3JpZCx5ID0gZml0KSwKICAgIG5ld2RhdGEpICsKICBnZW9tX2xpbmUoCiAgICBhZXMoeCA9IGdyaWQsIHkgPSBsd3IpLAogICAgbmV3ZGF0YSwKICAgIGNvbG9yID0gImdyZXkiKSArCiAgZ2VvbV9saW5lKAogICAgYWVzKHggPSBncmlkLCB5ID0gdXByKSwKICAgIG5ld2RhdGEsCiAgICBjb2xvciA9ICJncmV5IikgKwogIGdlb21fbGluZSgKICAgIGFlcyh4ID0gZ3JpZCwgeSA9IGx3ciksCiAgICBwcmVkZGF0YSwKICAgIGNvbG9yID0gImJsdWUiKSArCiAgZ2VvbV9saW5lKAogICAgYWVzKHggPSBncmlkLHkgPSB1cHIpLAogICAgcHJlZGRhdGEsCiAgICBjb2xvciA9ICJibHVlIikKYGBgCgoKIyMgTkhBTkVTIHZvb3JiZWVsZAoKCi0gVmVyZ2VsaWprIHJlZmVyZW50aWUtaW50ZXJ2YWwgdm9vciBjaG9sZXN0ZXJvbGdlaGFsdGUgbWV0IHByZWRpY3RpZSBpbnRlcnZhbC4KCi0gUmVmZXJlbnRpZS1pbnRlcnZhbAoKYGBge3J9CmxpYnJhcnkoTkhBTkVTKQpmZW0gPC0gTkhBTkVTICU+JQogIGZpbHRlcihHZW5kZXI9PSJmZW1hbGUiJiFpcy5uYShEaXJlY3RDaG9sKSkKCjJeKAogIGZlbSAlPiUKICBwdWxsKERpcmVjdENob2wpICU+JQogIGxvZzIgJT4lCiAgbWVhbiArCiAgICBjKC0xLDEpICoKICAgIHFub3JtKDAuOTc1KSAqCiAgICAoZmVtICU+JQogICAgICBwdWxsKERpcmVjdENob2wpICU+JQogICAgICBsb2cyICU+JQogICAgICBzZCkKICApCmBgYAoKLSBQcmVkaWN0aWUgaW50ZXJ2YWwKCmBgYHtyfQpsbUNob2wgPC0gbG0oRGlyZWN0Q2hvbCAlPiUgbG9nMiB+IDEsIGRhdGE9ZmVtKQpwcmVkSW50IDwtIHByZWRpY3QoCiAgbG1DaG9sLAogIGludGVydmFsPSJwcmVkaWN0aW9uIiwKICBuZXdkYXRhPWRhdGEuZnJhbWUobm9QcmVkPTEpCiAgKQpyb3VuZCgyXnByZWRJbnQsMikKYGBgCgpNZXJrIG9wIGRhdCBoZXQgdm9vcnNwZWxsaW5nc2ludGVydmFsIGJpam5hIGdlbGlqayBpcyBhYW4gaGV0IHJlZmVyZW50aWUtaW50ZXJ2YWwgdm9vciBkZSBncm90ZSBzdGVla3Byb2VmLiBXZSBrb25kZW4gZGUgcGFyYW1ldGVycyBpbmRlcmRhYWQgaGVlbCBwcmVjaWVzIHNjaGF0dGVuLgoKV2UgenVsbGVuIGhldHplbGZkZSBkb2VuIHZvb3IgZWVuIGtsZWluZSBzdGVla3Byb2VmIHZhbiAxMCBwYXRpw6tudGVuLgoKLSBSZWZlcmVudGllIGludGVydmFsCgpgYGB7cn0Kc2V0LnNlZWQoMSkKZmVtMTAgPC0gTkhBTkVTICU+JQogIGZpbHRlcihHZW5kZXI9PSJmZW1hbGUiJiFpcy5uYShEaXJlY3RDaG9sKSkgJT4lCiAgc2FtcGxlX24oc2l6ZT0xMCkKCjJeKAogIGZlbTEwICU+JQogICAgcHVsbChEaXJlY3RDaG9sKSAlPiUKICAgIGxvZzIgJT4lCiAgICBtZWFuICsKICAgICAgYygtMSwxKSAqCiAgICAgIHFub3JtKDAuOTc1KSAqCiAgICAgIChmZW0xMCAlPiUKICAgICAgICBwdWxsKERpcmVjdENob2wpICU+JQogICAgICAgIGxvZzIgJT4lCiAgICAgICAgc2QpCiAgKQpgYGAKCkhldCByZWZlcmVudGllLWludGVydmFsIGlzIHZlZWwgc21hbGxlciBkYW4gaW4gZGUgZ3JvdGUgc3RlZWtwcm9lZi4KCi0gUHJlZGljdGllIGludGVydmFsCgpgYGB7cn0KbG1DaG9sMTAgPC0gbG0oRGlyZWN0Q2hvbCAlPiUgbG9nMiB+IDEsIGRhdGEgPSBmZW0xMCkKcHJlZEludDEwIDwtIHByZWRpY3QoCiAgbG1DaG9sMTAsCiAgaW50ZXJ2YWwgPSAicHJlZGljdGlvbiIsCiAgbmV3ZGF0YSA9IGRhdGEuZnJhbWUobm9QcmVkPTEpCiAgKQpyb3VuZCgyXnByZWRJbnQxMCwgMikKYGBgCgotIE1lcmsgb3AgZGF0IGhldCBQSSBudSBvbnpla2VyaGVpZCBtZWVuZWVtdCBpbiBwYXJhbWV0ZXJzY2hhdHRlcnMgKGdlbWlkZGVsZGUgZW4gc3RhbmRhYXJkIGVycm9yKS4KRW4gZGF0IGhldCBpbnRlcnZhbCB2ZWVsIGJyZWRlciB3b3JkdCEgRGl0IGlzIGhpZXIgdm9vcmFsIGJlbGFuZ3Jpamsgdm9vciBkZSBib3ZlbmdyZW5zIG9tZGF0IHdlIGRlIGdlZ2V2ZW5zIHRlcnVnIGhlYmJlbiBnZXRyYW5zZm9ybWVlcmQhCgotIEhldCBpbnRlcnZhbCBpcyBiaWpuYSBuZXQgem8gYnJlZWQgYWxzIGRhdCBnZWJhc2VlcmQgb3AgZGUgZ3JvdGUgc3RlZWtwcm9lZi4KCi0gQmlqIGtsZWluZSBzdGVla3Byb2V2ZW4gaXMgaGV0IGVyZyBiZWxhbmdyaWprIG9tIG1ldCBkZXplIGV4dHJhIG9uemVrZXJoZWlkIHJla2VuaW5nIHRlIGhvdWRlbi4KCgojIEt3YWRyYXRlbnNvbW1lbiBlbiBBbm92YS10YWJlbAoKIyMgVG90YWxlIGt3YWRyYXRlbnNvbQoKJCRcdGV4dHtTU1RvdH0gPSBcc3VtX3tpPTF9Xm4gKFlfaS1cYmFye1l9KV4yLiQkCgotIFNTdG90IGthbiB3b3JkZW4gZ2VicnVpa3Qgb20gZGUgdmFyaWFudGllIHZhbiBkZSAqKm1hcmdpbmFsZSB2ZXJkZWxpbmcqKiB2YW4gZGUgcmVzcG9ucyB0ZSBzY2hhdHRlbi4KCi0gSW4gZGl0IGhvb2Zkc3R1ayBoZWJiZW4gd2Ugb25zIGdlZm9jdXNlZCBvcCBkZSAqKmNvbmRpdGlvbmVsZSB2ZXJkZWxpbmcqKiAkZihZXHZlcnQgWD14KSQuCgotIFdlIHdldGVuIGRhdCBNU0UgZWVuIGdvZWRlIHNjaGF0dGluZyBpcyB2YW4gZGUgdmFyaWFudGllIHZhbiBkZSBjb25kaXRpb25lbGUgdmVyZGVsaW5nIHZhbiAgJFlcdmVydCBYPXgkLgoKCmBgYHtyIG91dC53aWR0aD0nMTAwJScsIGZpZy5hc3A9LjgsIGZpZy5hbGlnbj0nY2VudGVyJywgZWNobz1GQUxTRX0KYnJjYSRsb2cyRVNSMSA8LSBsb2cyKGJyY2EkRVNSMSkKYnJjYSRsb2cyUzEwMEE4IDwtIGxvZzIoYnJjYSRTMTAwQTgpCnBsb3QobG9nMlMxMDBBOCB+IGxvZzJFU1IxLAogIGRhdGEgPSBicmNhLAogIHhsYWIgPSAiRVNSMSBleHByZXNzaWUgKGxvZzIpIiwKICB5bGFiID0gIlMxMDBBOCBleHByZXNzaWUgKGxvZzIpIiwKICBjZXguYXhpcz0xLjUsCiAgY2V4Lm1haW49MS41LAogIGNleC5sYWI9MS41LGNvbD00KQphYmxpbmUoaCA9IG1lYW4oYnJjYSRsb2cyUzEwMEE4KSkKZm9yIChpIGluIDE6bGVuZ3RoKGJyY2EkbG9nMlMxMDBBOCkpIGxpbmVzKHJlcChicmNhJGxvZzJFU1IxW2ldLDIpLGMobWVhbihicmNhJGxvZzJTMTAwQTgpLGJyY2EkbG9nMlMxMDBBOFtpXSksbHR5PTIsY29sPTQpCmBgYAoKIyMgS3dhZHJhdGVuc29tIHZhbiBkZSByZWdyZXNzaWUgU1NSCgokJFx0ZXh0e1NTUn0gPSBcc3VtX3tpPTF9Xm4gKFxoYXR7WX1faSAtIFxiYXJ7WX0pXjIgPSBcc3VtX3tpPTF9Xm4gKFxoYXR7Z30oeF9pKSAtIFxiYXJ7WX0pXjIuJCQKCi0gTWFhdCB2b29yIGRlIGFmd2lqa2luZyB0dXNzZW4gZGUgcHJlZGljdGllcyBvcCBkZSBnZXNjaGF0dGUgcmVncmVzc2llcmVjaHRlIGVuIGhldCBzdGVla3Byb2VmZ2VtaWRkZWxkZSB2YW4gZGUgdWl0a29tc3Rlbi4KCi0gRWVuIGFuZGVyZSBpbnRlcnByZXRhdGllOiB2ZXJzY2hpbCB0dXNzZW4gdHdlZSBtb2RlbGxlbgoKICAgIC0gR2VzY2hhdHRlIG1vZGVsICRcaGF0e2d9KHgpPVxoYXRcYmV0YV8wK1xoYXRcYmV0YV8xeCQKICAgIC0gR2VzY2hhdHRlIG1vZGVsIHpvbmRlciBwcmVkaWN0b3IgKGVua2VsIGludGVyY2VwdCk6ICRnKHgpPVxiZXRhXzAkICRccmlnaHRhcnJvdyQgJFxiZXRhXzAkIHphbCBnZWxpamsgemlqbiBhYW4gJFxiYXJ7WX0kLgoKLSBTU1IgbWVldCBkZSBncm9vdHRlIHZhbiBoZXQgZWZmZWN0IHZhbiBkZSBwcmVkaWN0b3IKCmBgYHtyIG91dC53aWR0aD0nMTAwJScsIGZpZy5hc3A9LjgsIGZpZy5hbGlnbj0nY2VudGVyJyxlY2hvPUZBTFNFfQpwbG90KGxvZzJTMTAwQTh+bG9nMkVTUjEsYnJjYSx4bGFiPSJFU1IxIGV4cHJlc3NpZSAobG9nMikiLHlsYWI9IlMxMDBBOCBleHByZXNzaWUgKGxvZzIpIixjZXguYXhpcz0xLjUsY2V4Lm1haW49MS41LGNleC5sYWI9MS41KQphYmxpbmUoaD1tZWFuKGJyY2EkbG9nMlMxMDBBOCkpCmFibGluZShsbTIsY29sPTIpCnBvaW50cyhicmNhJGxvZzJFU1IxLGxtMiRmaXR0ZWQscGNoPTIsY29sPTIpCmZvciAoaSBpbiAxOmxlbmd0aChicmNhJGxvZzJTMTAwQTgpKSBsaW5lcyhyZXAoYnJjYSRsb2cyRVNSMVtpXSwyKSxjKG1lYW4oYnJjYSRsb2cyUzEwMEE4KSxsbTIkZml0dGVkW2ldKSxsdHk9Mixjb2w9MikKYGBgCgoKIyMgS3dhZHJhdGVuc29tIHZhbiBkZSBmb3V0ZW4KCiQkIFx0ZXh0e1NTRX0gPSBcc3VtX3tpPTF9Xm4gKFlfaS1caGF0e1l9X2kgKV4yID0gXHN1bV97aT0xfV5uIFxsZWZ0XHtZX2ktXGhhdHtnfVxsZWZ0KHhfaVxyaWdodClccmlnaHRcfV4yLiQkCgotIEhvZSBrbGVpbmVyIGRlIFNTRSwgaG9lIGJldGVyIGhldCBtb2RlbCBmaXQuCgoKLSBLbGVpbnN0ZSBrd2FkcmF0ZW4gdGVjaG5pZWshCgotLS0KCmBgYHtyIG91dC53aWR0aD0nMTAwJScsIGZpZy5hc3A9LjgsIGZpZy5hbGlnbj0nY2VudGVyJyxlY2hvPUZBTFNFfQpwbG90KGxvZzJTMTAwQTh+bG9nMkVTUjEsYnJjYSx4bGFiPSJFU1IxIGV4cHJlc3NpZSAobG9nMikiLHlsYWI9IlMxMDBBOCBleHByZXNzaWUgKGxvZzIpIixjZXguYXhpcz0xLjUsY2V4Lm1haW49MS41LGNleC5sYWI9MS41KQphYmxpbmUobG0yLGNvbD0yKQpwb2ludHMoYnJjYSRsb2cyRVNSMSxsbTIkZml0dGVkLHBjaD0yLGNvbD0yKQpmb3IgKGkgaW4gMTpsZW5ndGgoYnJjYSRsb2cyUzEwMEE4KSkgbGluZXMocmVwKGJyY2EkbG9nMkVTUjFbaV0sMiksYyhicmNhJGxvZzJTMTAwQThbaV0sbG0yJGZpdHRlZFtpXSksbHR5PTIpCmBgYAoKV2Uga3VubmVuIGFhbnRvbmVuIGRhdCBTU1Qga2FuIHdvcmRlbiBvbnRib25kZW4gaW4KXGJlZ2lue2VxbmFycmF5Kn0KICBcdGV4dHtTU1RvdH0KICAgICY9JiAgXHN1bV97aT0xfV5uIChZX2ktXGJhcntZfSleMiBcXAogICAgJj0mICBcc3VtX3tpPTF9Xm4gKFlfaS1caGF0e1l9X2krXGhhdHtZfV9pLVxiYXJ7WX0pXjIgXFwKICAgICY9JiAgXHN1bV97aT0xfV5uIChZX2ktXGhhdHtZfV9pKV4yK1xzdW1fe2k9MX1ebihcaGF0e1l9X2ktXGJhcntZfSleMiBcXAogICAgJj0mICBcdGV4dHtTU0UgfStcdGV4dHtTU1J9ICAKICBcZW5ke2VxbmFycmF5Kn0KCi0gIERlIHRvdGFsZSB2YXJpYWJpbGl0ZWl0IGluIGRlIGdlZ2V2ZW5zIChTU1RvdCkgd29yZHQgZ2VkZWVsdGVsaWprIHZlcmtsYWFyZCBkb29yIGhldCByZWdyZXNzaWV2ZXJiYW5kIChTU1IpLgotIFZhcmlhYmlsaXRlaXQgZGllIHdlIG5pZXQga3VubmVuIHZlcmtsYXJlbiBtZXQgaGV0IHJlZ3Jlc3NpZW1vZGVsIGlzIGRlIHJlc2lkdWVsZSB2YXJpYWJpbGl0ZWl0IChTU0UpLgoKCiMjICBEZXRlcm1pbmF0aWUtY2/Dq2ZmaWNpw6tudAoKJCQgUl4yID0gMS1cZnJhY3tcdGV4dHtTU0V9fXtcdGV4dHtTU1RvdH19PVxmcmFje1x0ZXh0e1NTUn19e1x0ZXh0e1NTVG90fX0uJCQKCi0gKkZyYWN0aWUgdmFuIGRlIHRvdGFsZSB2YXJpYWJpbGl0ZWl0IGluIGRlIHN0ZWVrcHJvZWYtdWl0a29tc3RlbiBkaWUgdmVya2xhYXJkIHdvcmR0IGRvb3IgaGV0IGdlc2NoYXR0ZSByZWdyZXNzaWV2ZXJiYW5kKi4KCi0gR3JvdGUgJFJeMiQgaW5kaWNhdGllIGRhdCBtb2RlbCBwb3RlbnRpZWVsIHRvdCBnb2VkZSBwcmVkaWN0aWVzIGthbiBsZWlkZW4gKGtsZWluZSBTU0UpCgotIFNsZWNodHMgaW4gYmVwZXJrdGUgbWF0ZSBpbmRpY2F0aWVmIHZvb3IgZGUgcC13YWFyZGUgdmFuIGRlIHRlc3QgJEhfMDpcYmV0YV8xPTAkIHZzICRIXzE6XGJldGFfMVxuZXEwJC4KCiAgICAtIHAtd2FhcmRlIHN0ZXJrIGJlw69udmxvZWQgZG9vciBTU0UgZW4gc3RlZWtwcm9lZmdyb290dGUgJG4kLCBtYWFyIG5pZXQgZG9vciBTU1RvdAogICAgLSBEZSBkZXRlcm1pbmF0aWVjb8OrZmZpY2nDq250ICRSXjIkIHdvcmR0IGRvb3IgU1NFIGVuIFNTVG90IGJlcGFhbGQsIG1hYXIgbmlldCBkb29yIGRlIHN0ZWVrcHJvZWZncm9vdHRlIG4uCgotIE1vZGVsIG1ldCBsYWdlICRSXjIkIGJsaWpmdCB3ZWwgbnV0dGlnIG9tIGFzc29jaWF0aWUgdGUgYmVzdHVkZXJlbiwgem9sYW5nIGhldCBkZSBhc3NvY2lhdGllIGNvcnJlY3QgbW9kZWxsZWVydCEKCiMjIyBCb3JzdGthbmtlciB2b29yYmVlbGQKCmBgYHtyfQpzdW1tYXJ5KGxtMikKYGBgCgojIyBGLVRlc3RlbiBpbiBoZXQgZW5rZWx2b3VkaWcgbGluZWFpciByZWdyZXNzaWVtb2RlbAoKLSBLd2FkcmF0ZW5zb21tZW4gIHppam4gYmFzaXMgdm9vciAkRiQtdGVzdHMKJCQgIEYgID0gXGZyYWN7XHRleHR7TVNSfX17XHRleHR7TVNFfX0kJAoKbWV0ICAkXHRleHR7TVNSfSA9IFxmcmFje1x0ZXh0e1NTUn19ezF9IFx0ZXh0eyBhbmQgfSBcdGV4dHtNU0V9ID0gXGZyYWN7XHRleHR7U1NFfX17bi0yfS4kCgotIE1TUiB3b3JkdCBkZSBnZW1pZGRlbGRlIGt3YWRyYXRlbnNvbSB2YW4gZGUgcmVncmVzc2llIGdlbm9lbWQuCgotIG5vZW1lcnMgMSBlbiAkbi0yJCB6aWpuIGRlIHZyaWpoZWlkc2dyYWRlbiB2YW4gU1NSIGVuIFNTRS4KCi0gb25kZXIgJEhfMDogXGJldGFfMT0wJCB2b2xndCBkZSB0ZXN0c3RhdGlzdGllawokJEhfMDpGID0gXGZyYWN7XHRleHR7TVNSfX17XHRleHR7TVNFfX0gXHNpbSBGX3sxLG4tMn0sJCQKLSBGLXRlc3QgaXMgYWx0aWpkIHR3ZWUtemlqZGlnISAkSF8xOlxiZXRhXzFcbmVxIDAkCiQkICBwID0gUF8wXGxlZnRbRlxnZXEgZlxyaWdodF09MS1GX0YoZjsxLG4tMikkJAoKCmBgYHtyfQpzdW1tYXJ5KGxtMikKYGBgCgoKYGBge3IsIGVjaG89RkFMU0V9CmdyaWQ8LXNlcSgwLDEwLC4xKQpwbG90KGdyaWQsZGYoZ3JpZCwxLDMwKSx0eXBlPSJsIix4bGFiPSJGIix5bGFiPSJEZW5zaXR5IixtYWluPSJGLWRpc3RyaWJ1dGllIDEgZGYgaW4gdGVsbGVuLCAzMCBpbiBub2VtZXIiLGNleC5tYWluPTEuNSxjZXguYXhpcz0xLjUsY2V4LmxhYj0xLjUpCmBgYAoKCiMjIEFub3ZhIFRhYmVsCgoKfCB8RGZ8U3VtIFNxfE1lYW4gU3F8RiB2YWx1ZXxQcig+Ril8CnwtLS18LS0tfC0tLXwtLS18LS0tfC0tLXwKfFJlZ3Jlc3NpZXx2cmlqaGVpZHNncmFkZW4gU1NSfFNTUnxNU1J8Zi1zdGF0aXN0aWVrfHAtd2FhcmRlfAp8RXJyb3J8dnJpamhlaWRzZ3JhZGVuIFNTRXxTU0V8TVNFfCB8IHwKCmBgYHtyfQphbm92YShsbTIpCmBgYAoKCiMgRHVtbXkgdmFyaWFiZWxlbgoKLSBMaW5lYWlyZSByZWdyZXNzaWVtb2RlbCB2b29yIGhldCB2ZXJnZWxpamtlbiB2YW4gdHdlZSBnZW1pZGRlbGRlbi4KLSBCb3JzdGthbmtlcjogdmVyc2NoaWwgaXMgaW4gZ2VtaWRkZWxkZSBsZWVmdGlqZCB2YW4gZGUgcGF0acOrbnRlbiBtZXQgb25hYW5nZXRhc3RlIGx5bWZla25vcGVuIGVuIHBhdGnDq250ZW4gd2FhcnZhbiBseW1mZWtub3BlbiB3ZXJkZW4gdmVyd2lqZGVyZC4KCi0gSGllcnZvb3IgZGVmaW5pw6tyZW4gd2UgZWVyc3QgZWVuICRkdW1teSQgdmFyaWFiZWxlCiQkeF9pID0gXGxlZnRceyBcYmVnaW57YXJyYXl9e2xsfQoxICYgXHRleHR7YWFuZ2V0YXN0ZSBseW1mZWtub3Blbn0gXFwKMCAmIFx0ZXh0e29uYWFuZ2V0YXN0ZSBseW1mZWtub3Blbn0gXGVuZHthcnJheX1ccmlnaHQuJCQKCi0gZ3JvZXAgbWV0ICR4X2k9MCQgd29yZHQgZGUgKipyZWZlcmVudGllZ3JvZXAqKiBnZW5vZW1kLgoKLSBIZXQgcmVncmVzc2llbW9kZWwgYmxpamZ0IG9uZ2V3aWp6aWdkLAokJFlfaSA9IFxiZXRhXzAgKyBcYmV0YV8xIHhfaSArXGVwc2lsb25faSQkCm1ldCAkXGVwc2lsb25faSBcdGV4dHsgaWlkIH0gTigwLFxzaWdtYV4yKSQKCgpHZXppZW4gJHhfaSQgc2xlY2h0cyB0d2VlIHdhYXJkZW4ga2FuIGFhbm5lbWVuLCBpcyBoZXQgZWVudm91ZGlnIG9tIGhldCByZWdyZXNzaWVtb2RlbCB2b29yIGJlaWRlIHdhYXJkZW4gdmFuICR4X2kkIGFmem9uZGVybGlqayB0ZSBiZWtpamtlbjoKJCQgXGJlZ2lue2FycmF5fXtsY2xsfQogICBZX2kgJj0mIFxiZXRhXzAgK1xlcHNpbG9uX2kgJlx0ZXh0e29uYWFuZ2V0YXN0ZSBseW1mZWtub3Blbn0gKHhfaT0wKSBcXAogICBZX2kgJj0mIFxiZXRhXzAgKyBcYmV0YV8xICtcZXBzaWxvbl9pICZcdGV4dHsgYWFuZ2V0YXN0ZSBseW1mZWtub3Blbn0gKHhfaT0xKSAuCiBcZW5ke2FycmF5fSQkCgpEdXMKIFxiZWdpbntlcW5hcnJheSp9CiAgIEVcbGVmdFtZX2lcbWlkIHhfaT0wXHJpZ2h0XSAmPSYgXGJldGFfMCBcXAogICBFXGxlZnRbWV9pXG1pZCB4X2k9MVxyaWdodF0gJj0mIFxiZXRhXzAgKyBcYmV0YV8xLApcZW5ke2VxbmFycmF5Kn0KCiB3YWFydWl0IGRpcmVjdCBkZSBpbnRlcnByZXRhdGllIHZhbiAkXGJldGFfMSQgdm9sZ3Q6CiQkICAgXGJldGFfMSA9IEVcbGVmdFtZX2lcbWlkIHhfaT0xXHJpZ2h0XS1FXGxlZnRbWV9pXG1pZCB4X2k9MFxyaWdodF0kJAoKJFxiZXRhXzEkIGlzIGR1cyBoZXQgZ2VtaWRkZWxkZSB2ZXJzY2hpbCBpbiBsZWVmdGlqZCB0dXNzZW4gcGF0acOrbnRlbiBtZXQgYWFuZ2V0YXN0ZSBseW1mZWtub3BlbiBlbiBwYXRpw6tudGVuIG1ldCBvbmFhbmdldGFzdGUgbHltZmVrbm9wZW4gKHJlZmVyZW50aWVncm9lcCkuCgpNZXQgZGUgbm90YXRpZSAkXG11XzA9IEVcbGVmdFtZX2lcbWlkIHhfaT0wXHJpZ2h0XSQgZW4gJFxtdV8xPSBFXGxlZnRbWV9pXG1pZCB4X2k9MVxyaWdodF0kIHdvcmR0IGRpdAokJFxiZXRhXzEgPSBcbXVfMS1cbXVfMC4kJAoKCkVyIGthbiBhYW5nZXRvb25kIHdvcmRlbiBkYXQKJCRcYmVnaW57YXJyYXl9e2NjbGx9CiBcaGF0XGJldGFfMAogICAmPSYgXGJhcntZfV8xJlx0ZXh0eyAoc3RlZWtwcm9lZmdlbWlkZGVsZGUgaW4gcmVmZXJlbnRpZWdyb2VwKX0gXFwKIFxoYXRcYmV0YV8xCiAgICY9JiBcYmFye1l9XzItXGJhcntZfV8xJlx0ZXh0eyhzY2hhdHRlciB2YW4gZWZmZWN0Z3Jvb3R0ZSl9IFxcCiBcdGV4dHtNU0V9CiAgICY9JiBTX3BeMiAuClxlbmR7YXJyYXl9JCQKCkRlIHRlc3RlbiB2b29yICRIXzA6XGJldGFfMT0wJCB2cy4gICRIXzE6XGJldGFfMVxuZXEwJCBrdW5uZW4gZ2VicnVpa3Qgd29yZGVuIHZvb3IgaGV0IHRlc3RlbiB2YW4gZGUgbnVsaHlwb3RoZXNlIHZhbiBkZSB0d28tc2FtcGxlICR0JC10ZXN0LCAkSF8wOlxtdV8xPVxtdV8yJCB0Lm8udi4gJEhfMTpcbXVfMVxuZXFcbXVfMiQuCgpgYGB7cn0KYnJjYSRub2RlIDwtIGFzLmZhY3RvcihicmNhJG5vZGUpCnQudGVzdChhZ2V+bm9kZSxicmNhLHZhci5lcXVhbD1UUlVFKQpgYGAKCmBgYHtyfQpsbTMgPC0gbG0oYWdlfm5vZGUsIGJyY2EpCnN1bW1hcnkobG0zKQpgYGAKCmBgYHtyfQpwbG90KGxtMykKYGBgCgoKCmBgYHtyfQpicmNhICU+JQogIGdncGxvdCgKICAgIGFlcygKICAgICAgeCA9IG5vZGUgJT4lCiAgICAgICAgYXMuZmFjdG9yLAogICAgICB5ID0gYWdlKQogICAgICApICsKICBnZW9tX2JveHBsb3QoKQpgYGAKCgoxLiBTaW11bGF0ZSA5IGRhdGFzZXRzIHdpdGggdGhlIHNhbWUgbnVtYmVyIG9mIG9ic2VydmF0aW9ucyBhcyB0aGUgYnJjYSBkYXRhc2V0IGZyb20gYSBub3JtYWwgZGlzdHJpYnV0aW9uIHdpdGggdGhlIHNhbWUgc3RhbmRhcmQgZGV2aWF0aW9uIGFzIGluIHRoZSBvcmlnaW5hbCBkYXRhLiBTdG9yZSB0aGUgZGF0YSBvZiBhbGwgc2ltdWxhdGlvbnMgaW4gYSBkYXRhIGZyYW1lCjIuIFBsb3QgdGhlIHNpbXVsYXRlZCBkYXRhIHVzaW5nIHRoZSBgZ2dwbG90YCBmdW5jdGlvbgozLiBBZGQgYSBib3hwbG90IGxheWVyCjQuIFVzZSBmYWNldF93cmFwIHRvIG1ha2UgYSBzZXBhcmF0ZSBwbG90IGZvciBzaW11bGF0ZWQgZGF0YXNldAo1LiBDaGFuZ2UgbGFiZWwgb2YgeS1heGlzCgpgYGB7ciBvdXQud2lkdGg9JzEwMCUnLCBmaWcuYXNwPS44LCBmaWcuYWxpZ249J2NlbnRlcid9CnNldC5zZWVkKDM1NCkKc2ltX2RmIDwtIGRhdGEuZnJhbWUoCiAgbm9kZSA9IHJlcChicmNhJG5vZGUsIDkpLAogIGlpZCA9IHJub3JtKDkgKiBucm93KGJyY2EpLCBzZCA9IHNpZ21hKGxtMykpLAogIHNpbSA9IHJlcCgxOjksIGVhY2ggPSAzMikKICApCnNpbV9kZiAlPiUKICBnZ3Bsb3QoYWVzKHggPSBub2RlLCB5PWlpZCkpICsKICBnZW9tX2JveHBsb3QoKSArCiAgZmFjZXRfd3JhcCgufnNpbSkgKwogIHlsYWIocGFzdGUwKCJpaWQgTigwLCIscm91bmQoc2lnbWEobG0zKV4yLDIpLCIpIikpCmBgYAoKCiMjIE9ic2VydmF0aW9uZWxlIHN0dWR5CgotIFdlIGt1bm5lbiBlY2h0ZXIgbmlldCBiZXNsdWl0ZW4gZGF0IG91ZGVyZSBwZXJzb25lbiBlZW4gaG9nZXIgcmlzaWNvIGhlYmJlbiBvcCBhYW50YXN0aW5nIHZhbiBkZSBseW1mZWtub3BlbiB0ZW4gZ2V2b2xnZSB2YW4gaHVuIGxlZWZ0aWpkLgoKLSBNb2dlbGlqa3MgKipjb25mb3VuZGluZyoqOiBnZWVuIHJhbmRvbWlzYXRpZSAkXHJpZ2h0YXJyb3ckIGdyb2VwZW4gcGF0acOrbnRlbiBtZXQgYWFuZ2V0YXN0ZSBseW1mZWtub3BlbiBlbiBuaWV0LWFhbmdldGFzdGUgbHltZmVrbm9wZW4ga3VubmVuIG5vZyBpbiBhbmRlcmUga2FyYXRlcmlzdGlla2VuIHZhbiBlbGthYXIgdmVyc2NoaWxsZW4uCgotIEVua2VsIGJlc2x1aXRlbiBkYXQgZXIgZWVuIGFzc29jaWF0aWUgaXMgdHVzc2VuIGRlIGx5bWZla25vb3Agc3RhdHVzIGVuIGRlIGxlZWZ0aWpkLgoKLSBIZXQgaXMgZHVzIG5pZXQgbm9vZHpha2VsaWprZXJ3aWpzIGVlbiBjYXVzYWFsIHZlcmJhbmQhCgotLS0KCi0gSXMgb29rIHpvIHZvb3IgbGluZWFpciBtb2RlbCB2b29yIGRlICRcbG9nXzIkLVMxMDBBOC1leHByZXNzaWUuCgotIEFhbmdlemllbiB3ZSBkZSBFU1IxLWV4cHJlc3NpZSBuaWV0IGV4cGVyaW1lbnRlZWwgdmFzdCBoZWJiZW4ga3VubmVuIGxlZ2dlbiwga3VubmVuIHdlIG5pZXQgYmVzbHVpdGVuIGRhdCBlZW4gaG9nZXJlIEVTUjEtZXhwcmVzc2llIGRlIFMxMDBBOC1leHByZXNzaWUgZG9ldCB2ZXJsYWdlbi4KCi0gRW5rZWwgYmVzbHVpdGVuIGRhdCBlciBlZW4gbmVnYXRpZXZlIGFzc29jaWF0aWUgaXMuCgotIE9tIGltcGFjdCB2YW4gZ2VuIHRlIGJlc3R1ZGVyZW4gb3AgYW5kZXJlIGdlbmVuOiBrbm9ja291dCBtdXRhbnRlbiBnZW5lcmVuZW4gaW4gaGV0IGxhYm8KCgotLS0KCiMgW0hvbWVdKGh0dHBzOi8vc3RhdG9taWNzLmdpdGh1Yi5pby9zYmMyMC8pIHstfQo=