1 Inleiding

  • Vorige hoofdstukken:

    • continue uitkomst
    • categorische of continue predictor.
  • Nu besluitvorming voor categorische uitkomst.

  • Focus op associatie tussen categorische uitkomst en een categorische predictor.

  • Gebruik van kruistabellen om associatie voor te stellen.


2 Toetsen voor een proportie

2.1 Saksen-studie

  • Vrij gesloten populatie (weinig immigratie en emigratie)
  • Wat is de kans dat een ongeboren kind mannelijk is?
boys <- 3175
n <- 6155
  • Op 6155 ongeboren kinderen werden 3175 jongens geobserveerd.
  • Verschil in kans dat ongeboren kind jongen of meisje is?

  • Gegevens voorstellen als uitkomsten van een numerieke toevalsveranderlijke \(X\)

    • \(X=1\) voor jongens en
    • \(X=0\) voor meisjes.
  • Merk op: telprobleem omdat de uitkomst een telling (nl. het aantal jongens)

  • Formeel: populatie van ongeboren kinderen waarin elk individu gekenmerkt wordt door een 0 of een 1.

  • Uitkomst variabele is binair.


2.2 Bernoulli verdeling

  • Binaire data \(\longrightarrow\) Bernoulli verdeling: \[\begin{eqnarray*} X_i &\sim& B(\pi) \text{ met}\\ B(\pi)&=&\pi^{X_i}(1-\pi)^{(1-X_i)}, \end{eqnarray*}\]

  • Distributie met 1 model parameter \(\pi\)

    • Verwachte waarde van \(X_i\): \(\text{E}[X_i]=\pi,\)
    • Proportie van ongeboren jongens (d.i. kinderen met een 1) in de populatie.
    • Bijgevolg is \(\pi\) kans dat lukraak getrokken individu een jongen is (een observatie die 1 oplevert).
  • Variantie van Bernoulli data bepaald door kans \(\pi\). \[\text{Var}[X_i]=\pi (1-\pi).\]


Grafische weergave van enkele Bernoulli kansverdelingen


  • In Saksenstudie worden lukraak 6155 observaties getrokken uit populatie.
  • We schatten \(\pi\) als het steekproefgemiddelde : \[\hat \pi = \bar X = \frac{\sum\limits_{i=1}^n X_i}{n},\]
pi <- boys/n
pi
## [1] 0.5158408

In ons voorbeeld is \(\bar x =\) 3175 / 6155 = 51.6%.


2.3 Asymptotisch Betrouwbaarheidsinterval

  • Saksenstudie heel grote steekproef: 6155 onafhankelijke observaties.

  • CLT kan worden toegepast op gemiddelde: data volgt Bernoulli verdeling, maar gemiddelde o.b.v. onafhankelijke en identiek verdeelde observaties in heel grote steekproef volgt approximatief een normaal verdeling.

  • \(\text{E}[\bar X] = \pi\)

  • \(\text{Var}[\bar X] = \frac{\text{Var}[X]}{n} = \frac{\pi(1-\pi)}{n}\)

  • \(\bar x\) = 0.516

se <- sqrt((pi*(1-pi))/n)
  • SE = 0.0064\[ \text{SE} = \hat\sigma_{\bar x} = \sqrt{\frac{\bar x(1-\bar x)}{n}} \]

  • BI: [0.503, 0.528] \[ [\bar x - z_{\alpha/2} \text{SE}_{\bar x}, \bar x + z_{\alpha/2} \text{SE}_{\bar x}]\]

  • 0.5 valt niet binnen het 95% BI.

  • De kans op een jongen is significant hoger dan 50% op het 5% significantie-niveau.

2.4 Asymptotische Test

  • H\(_0\): \(\pi = 0.5\) vs H\(_1\): \(\pi \neq 0.5\)

  • Merk op dat voor een Bernoulli verdeling de variantie onder H\(_0\) ook gekend is: \(\pi_0 (1-\pi_0)\).

  • Dus onder \(H_0\) is standaard error op x:

\[ \text{SE}_{0, \bar x}=\sqrt{\frac{\pi_0 (1-\pi_0)}{n}} \]

  • Statistiek \[ z = \frac{\bar x - \pi_0}{\text{SE}_{0, \bar x}}\]

  • Volgt onder de nulhypothese dat er evenveel kans is op een jongen of een meisje (\(\pi_0=0.5\)) asymptotisch een normaal verdeling: CLT

  • p-waarde? Merk op dat het een tweezijdige test is!

pi0 <- 0.5
se0 <- sqrt(pi0*(1-pi0)/n)
z <- (pi-pi0)/se0
z
## [1] 2.485539
pval <- pnorm(abs(z),lower=FALSE) *2
pval
## [1] 0.01293554

Er is significant meer kans dat een ongeboren kind mannelijk dan vrouwelijk is (p=0.013). De kans dat een ongeboren kind mannelijk is bedraagt 0.516 (95% BI [0.503, 0.528]).

2.5 Exacte test: Binomiale test

  • Statistische toets voor \[H_0: \pi=1/2 \text{ versus } H_1: \pi\neq 1/2,\]

  • Daarvoor moeten we verdeling van de

    • \(X\) en \(\bar X\)
    • of van de som \(S=n\bar X\) kennen.
  • Als alle observaties onafhankelijk zijn en eenzelfde verdeling \(B(\pi)\) volgen dan volgt \(S\) een binomiaal verdeling.


  • Stel \(H_0:\pi=1/2\) is waar (voorkomen van jongens en meisjes in populatie even waarschijnlijk)
  • Lukrake trekking van één individu uit de populatie, kans op een jongen \[P(X=1)=\pi=1/2.\]
  • Twee kinderen onafhankelijk van elkaar (en de populatie \(\approx \infty\)):
    • Kans \(\pi=1/2\) op jongen voor zowel eerste als tweede kind (onafhankelijk van elkaar)
    • Uitkomsten \((x_1, x_2)\) voor beide kinderen hebben dan 4 mogelijke waarden: \((0,0),(0,1),(1,0)\text{ en }(1,1).\)
    • Deze komen elk voor met kans \(1/4 = 1/2 \times 1/2\).
  • Toevalsveranderlijke \(S\) die som van uitkomsten weergeeft kan volgende waarden aannemen:
\((x_1,x_2)\) \(s\) \(P(S = s)\)
(0,0) 0 1/4
(0,1), (1,0) 1 1/2
(1,1) 2 1/4

2.5.1 Algemeen: \(n\) onafhankelijke observaties

  • Kans \(\pi\) op “succes” (uitkomst 1) voor elke observatie

  • Totaal aantal successen \(S\) (som van alle 1-en) kan \(n+1\) mogelijke waarden hebben \[S=k\text{, met }k=0,\ldots,n\]

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

  • \(1-\pi\): kans op mislukking in 1 enkele trekking (uitkomst met 0 genoteerd) en

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

  • In R kan je de kansen van binomiale verdeling voor elke \(S=k\) opvragen met dbinom(k,n,p)


2.5.2 Binomiale Verdeling

De toevalsveranderlijke \(S\) volgt:

  • Binomiaal verdeelde toevalsveranderlijke met bijhorende Binomiale kansverdeling

  • parameters

    • \(n\) (d.i. het aantal trekkingen of, equivalent, de maximale uitkomstwaarde)
    • \(\pi\) (de kans op een `succes’ bij elke trekking).
  • Kans berekenen dat \(k\) gebeurtenissen zich voordoen op \(n\) onafhankelijke experimenten waarbij kans op 1 zo’n gebeurtenis per experiment, \(\pi\) bedraagt.

  • Voor analyse van gegevens die slechts 2 mogelijke waarden kunnen aannemen.

  • Bijvoorbeeld: al dan niet besmet met HIV, wild type van een gen vs een mutant,…

  • Gebruik: Proporties of risico’s op een gebeurtenis van een bepaald type vergelijken tussen verschillende groepen.


2.5.3 Een grafische weergave van enkele Binomiale kansverdelingen.

Binomiale verdelingen.

Binomiale verdelingen.


Toetsstatistieken voor \[H_0:\pi=1/2\text{ versus }H_1:\pi\neq 1/2\]

  • \(\bar X-1/2\) of, equivalent,
  • \(\Delta=n(\bar X-\pi_0)=S-s_0\).
  • Verdeling van deze laatste toetsstatistiek volgt rechtstreeks uit de Binomiale verdeling:
    • We observeren \(s=\) 3175 en dus \(\delta=s-s_0=\) 3175 \(-\) 6155 \(\times 0.5=\) 97.5.
    • In veronderstelling dat jongens en meisjes even waarschijnlijk zijn (d.i. onder de nulhypothese \(H_0:\pi=1/2\)), bekomen we de bijhorende tweezijdige p-waarde: \[p=\text{P}_0\left[S-s_0\geq \vert \delta\vert \right] + \text{P}_0\left[S-s_0\leq - \vert \delta\vert \right].\]
  • Merk op dat we dit kunnen herschrijven in termen van S. \[p=\text{P}_0\left[S\geq s_0+ \vert \delta\vert \right] + \text{P}_0\left[S \leq s_0 - \vert \delta\vert \right].\]

  • Voor ons voorbeeld kunnen we deze kansen als volgt berekenen:

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

  • Binomiale distributie is symmetrisch als \(\pi=1/2\): \[\text{P}_0\left[S\geq s_0+ \vert \delta\vert \right] = \text{P}_0\left[S \leq s_0 - \vert \delta\vert \right]\]
  • Dat is niet langer het geval wanneer \(\pi\) afwijkt van 0.5.

pi0 <- 0.5; s0 <- pi0 *n
delta <- abs(boys- s0)
delta
## [1] 97.5
sUp <- s0 + delta
sDown <- s0 -delta
c(sDown,sUp)
## [1] 2980 3175
pUp <- 1-pbinom(sUp-1,n,pi0)
pDown <- pbinom(sDown,n,pi0)
p <- pUp+pDown
c(pUp,pDown, p)
## [1] 0.006699883 0.006699883 0.013399766
  • Als \(\pi= 1/2\), kans om door toeval minstens \(\delta=\) 97.5 jongens meer of minder te observeren dan het gemiddelde onder \(H_0: s_0=\) 3077.5 , slechts 1.34% is: de \(p\)-waarde van de binomiale test.
  • Kleine kans om een dergelijk groot aantal jongens te observeren als in realiteit jongens en meisjes even veel voorkomen in de populatie.
  • Drukt uit dat de onderstelling dat jongens en meisjes even veel voorkomen, weinig gesteund wordt door de data.


De test kan worden uitgevoerd a.d.h.v. de binom.test functie in R.

binom.test(x=boys,n=n,p=pi0)
## 
##  Exact binomial test
## 
## data:  boys and n
## number of successes = 3175, number of trials = 6155, p-value = 0.0134
## alternative hypothesis: true probability of success is not equal to 0.5
## 95 percent confidence interval:
##  0.5032696 0.5283969
## sample estimates:
## probability of success 
##              0.5158408

Op het 5% significantie-niveau besluiten we dat er gemiddeld meer kans is dat een ongeboren kind mannelijk dan vrouwelijk is.

  • De Binomiale test heeft ook een exact BI weer op een proportie.

  • Het exacte BI is te verkiezen boven het BI dat gebaseerd is op de CLT.

  • Voor Saksen-studie ligt BI o.b.v. CLT heel dicht bij exacte BI: grote steekproef (\(n=\) 6155).

  • Merk op dat het testen voor een proportie kan gezien worden als het equivalent van een one-sample t-test voor binaire data.


2.6 Conclusie

  • Voor de Saksen populatie besluiten we op het 5% significantieniveau dat er meer kans is dat een ongeboren kind mannelijk dan vrouwelijk is (\(p=\) 0.013). De kans dat een ongeboren kind mannelijk is, bedraagt 51.6% (95% BI [50.3, 52.8]%).

3 Toets voor associatie tussen 2 kwalitatieve variabelen

3.1 Gepaarde gegevens

  • 2 keer zelfde individu meten
  • bijvoorbeeld, vóór en na blootstelling aan de experimentele stof
  • telkens de categorische uitkomst te observeren.
  • Hier enkel: gepaarde binaire uitkomsten
  • Statistische analyse moet rekening houden met de paring.

3.1.1 Voorbeeld: partnerkeuze van seksueel mature vrouwelijke Campbelli dwerghamster (Rogovin et al. 2017)


  • Na 3 minuten, scheidingswand weg

  • aggressief vs niet-agressief mannentje

  • Elk vrouwtje onderging tweemaal de test: na verblijf in

    • vijandige omgeving (hoge populatie, weinig voedsel, veel concurrentie)
    • vriendelijkere omgeving
Kruistabel van partnerkeuze bij dwerghamster.
vriendelijk-agressief vriendelijk-niet-agressief totaal
vijandig-agressief 3 (e) 17 (f) 20
vijandig-niet-agressief 1 (g) 13 (h) 14
totaal 4 30 34

  • \(\pi_2=P[\text{agressief mannetje } \vert \text{ verblijf vijandige omgeving}]\)

  • \(\hat \pi_2=(e+f)/n\), waarbij \(n=e+f+g+h\).

  • \(\pi_1=P[\text{agressief mannetje } \vert \text{ verblijf vriendelijke omgeving}]\)

  • \(\hat \pi_1=(e+g)/n\)

  • Absoluut riscoverschil (ARV) \[\begin{equation*} \widehat{\text{ARV}}=\hat\pi_2-\hat\pi_1=\frac{e+f}{n}-\frac{e+g}{n}=\frac{f-g}{n} \end{equation*}\]

  • Enkel beïnvloed door aantallen discordante paren \(f\) en \(g\)


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

  • Als er voldoende gegevens zijn, kan men een \((1-\alpha)100\%\) BI op ARV \[\left[\widehat{\text{ARV}}-z_{\alpha/2}\text{SE}_{\widehat{\text{ARV}}},\widehat{\text{ARV}}-z_{\alpha/2}\text{SE}_{\widehat{\text{ARV}}}\right]\] of \[\left[\frac{f-g}{n}-\frac{z_{\alpha/2}}{n}\sqrt{f+g-\frac{(f-g)^2}{n}},\frac{f-g}{n}+\frac{z_{\alpha/2}}{n}\sqrt{f+g-\frac{(f-g)^2}{n}}\right] \]


hamster <- matrix(c(3,17,1,13),ncol=2,byrow=TRUE)
rownames(hamster) <- c("vijandig-agressief", "vijandig-niet-agressief")
colnames(hamster) <- c("vriendelijk-agressief","vriendelijk-niet-agressief")

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

\[\begin{equation*} \widehat{\text{ARV}}=\frac{17-1}{34}=0.471 \end{equation*}\] of 47.1%.

  • De standaard error \[\begin{equation*} \text{SE}_{\widehat{\text{ARV}}}=\frac{1}{34}\sqrt{17+1-\frac{(17-1)^2}{34}}=0.0952 \end{equation*}\]

  • Een 95% betrouwbaarheidsinterval voor het absolute risicoverschil op de keuze van een agressief mannetje tussen een verblijf in een vijandige en vriendelijke omgeving is bijgevolg \[\begin{equation*} \left[0.471-1.96\times 0.0952,0.471+1.96\times 0.0952\right]=[0.284,0.658] \end{equation*}\]

  • We hebben besluiten dus dat absolute risico verschil in het interval [28.4,65.8]% ligt en weten dat dergelijke intervallen voor grote steekproeven het werkelijke absolute risco verschil met een kans van 95% bevatten.

  • Op basis van het BI besluiten we op het 5% niveau dat het meer waarschijnlijk is dat vrouwelijke hamsters een aggressieve partner kiezen nadat ze in een vijandige omgeving hebben verbleven dan wanneer ze in een vriendelijke omgeving verbleven. De kans op de keuze van een agressief mannetje is 47% hoger nadat ze in een vijandige omgeving heeft verbleven (95% BI 28.4,65.8]%)


3.1.2 McNemar test

vriendelijk-agressief vriendelijk-niet-agressief totaal
vijandig-agressief 3 (e) 17 (f) 20
vijandig-niet-agressief 1 (g) 13 (h) 14
totaal 4 30 34
  • Toetsen of de risico’s verschillen tussen de vijandige en vriendelijke omgeving.
  • Enkel de discordante paren leveren hier informatie over.
  • \(f>g\) indicatie tegen \(H_0\): partnerkeuze niet geassocieerd met omgeving
  • Kans evalueren dat in een lukraak discordant paar, vrouwtje na verblijf in een vijandige omgeving kiest voor het agressieve mannetje.
  • Deze kans wordt geschat als \[\frac{f}{f+g}\]

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


  • Asymptotisch one-sample z-test (o.b.v. normale verdeling)

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

  • De Normale benadering is goed als \[f \times g/(f+g) \geq 5\]

  • In kleine steekproeven is het meer aangewezen om een continuïteitscorrectie te gebruiken d.m.v. de toetsingsgrootheid \[\begin{equation*} \frac{|f-g|-1}{\sqrt{f+g}} \end{equation*}\]

De Mc Nemar test analogon van de gepaarde t-test voor binaire, kwalitatieve i.p.v. continue variabelen.


In R mcnemar.test functie

mcnemar.test(hamster)
## 
##  McNemar's Chi-squared test with continuity correction
## 
## data:  hamster
## McNemar's chi-squared = 12.5, df = 1, p-value = 0.000407
  • We verwerpen bijgevolg de nulhypothese op het 5% significantieniveau en

  • Besluiten dat de parternkeuze extreem significant geassocieerd is met de omgeving.

  • We zien dat hier eveneens de continuïteitscorrectie werd uitgevoerd en dat we exact dezelfde p-waarde bekomen.


  • Normale benadering van deze toetstatistiek niet ideaal is omdat \(f \times g/(f+g) < 5\).

  • Steeds beter: binomiale test

binom.test(x = f,
  n = f + g,
  p = 0.5)
## 
##  Exact binomial test
## 
## data:  f and f + g
## number of successes = 17, number of trials = 18, p-value = 0.000145
## alternative hypothesis: true probability of success is not equal to 0.5
## 95 percent confidence interval:
##  0.7270564 0.9985944
## sample estimates:
## probability of success 
##              0.9444444

3.1.3 Conclusie

  • Op basis van de exacte test besluiten we eveneens dat de parternkeuze extreem significant geassocieerd is met de omgeving (\(p<0.001\)).
  • De kans op de keuze van een agressief mannetje ligt 47.1% hoger als een dwerghamster vrouwtje zich in een vijandige omgeving bevindt dan wanneer ze zich in een vriendelijke omgeving bevindt (95% BI [28.4, 65.7]%).

3.2 Ongepaarde gegevens

3.2.1 Genetische associatie studie

  • Genetische associatiestudie polymorfismen in het BRCA1 gen geassocieerd is met borstkanker?
  • Retrospectieve case-controle studie met 800 borstkankercases en 572 controles
library(tidyverse)
## ── Attaching packages ─────────────────────────────────────────────── tidyverse 1.3.0 ──
## ✔ ggplot2 3.3.2     ✔ purrr   0.3.4
## ✔ tibble  3.0.4     ✔ dplyr   1.0.2
## ✔ tidyr   1.1.2     ✔ stringr 1.4.0
## ✔ readr   1.4.0     ✔ forcats 0.5.0
## ── Conflicts ────────────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
brca <- read_csv("https://raw.githubusercontent.com/statOmics/sbc20/master/data/brca.csv")
## 
## ── Column specification ────────────────────────────────────────────────────────────────
## cols(
##   cancer = col_character(),
##   variant = col_character(),
##   variant2 = col_character()
## )
head(brca)
## # A tibble: 6 x 3
##   cancer  variant variant2
##   <chr>   <chr>   <chr>   
## 1 control pro/pro other   
## 2 control pro/pro other   
## 3 control pro/pro other   
## 4 control pro/pro other   
## 5 control pro/pro other   
## 6 control pro/pro other
summary(brca)
##     cancer            variant            variant2        
##  Length:1372        Length:1372        Length:1372       
##  Class :character   Class :character   Class :character  
##  Mode  :character   Mode  :character   Mode  :character

Genotype Controles Cases Totaal
Pro/Pro 266 (a) 342 (d) 608 (a+d)
Pro/Leu 250 (b) 369 (e) 619 (b+e)
Leu/Leu 56 (c) 89 (f) 145 (c+f)
Totaal 572 (a+b+c) 800 (d+e+f) 1372 (n)
  • In case-controle studies kiest men een vast aantal cases en controles en spoort men voor hen op welke blootstellingen ze in het verleden ondervonden hebben.
  • Dergelijke studies noemt men ook retrospectief
  • Onmogelijk om het risico’s and riscoverschillen op borstkanker te schatten: proportie van cases en controles weerspiegelt populatie niet!

Genotype Controles Cases Totaal
Pro/Pro 266 (a) 342 (d) 608 (a+d)
Pro/Leu 250 (b) 369 (e) 619 (b+e)
Leu/Leu 56 (c) 89 (f) 145 (c+f)
Totaal 572 (a+b+c) 800 (d+e+f) 1372 (n)
  • Wel mogelijk om kans te schatten om allel Leu/Leu
    • cases: \(\pi_1=f/(d+e+f)=89/800=11.1\%\)
    • controles:\(\pi_0=c/(a+b+c)=56/572=9.8\%\)
  • Relatief risico op blootstelling voor cases versus controles is bijgevolg \(11.1/9.8=1.14\).
  • Vrouwen met borstkanker hebben dus 14% meer kans om de allelcombinatie Leu/Leu te hebben op het BRCA1 gen dan vrouwen zonder borstkanker.
  • Dit suggereert een associatie, maar drukt iet uit hoeveel hoger het risico op borstkanker is voor vrouwen met de allelcombinatie Leu/Leu dan voor andere vrouwen
  • Andere risicomaat?

\[\begin{equation*} Odds=\frac{p}{1-p} \end{equation*}\] waarbij \(p\) de kans is op die gebeurtenis.

Transformatie van het risico, met volgende eigenschappen:

  • de odds neemt waarden aan tussen nul en oneindig.

  • de odds is gelijk aan 1 als en slechts als de kans zelf gelijk is aan 1/2.

  • de odds neemt toe als de kans toeneemt.

  • populair bij gokkers: hoeveel waarschijnlijker het is om te winnen dan om te verliezen


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

Odds op allel Leu/Leu

  • Cases: \(\mbox{odds}_1=\frac{ f/(d+e+f)}{(d+e)/(d+e+f)}=f/(d+e)=89/711=0.125\). Vrouwen met borstkanker hebben ongeveer 8 keer meer kans om de allelcombinatie Leu/Leu niet te hebben op het BRCA1 gen dan om het wel te hebben.

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

  • Associatie tussen blootstelling en uitkomst: \[ OR_{Leu/Leu}=\frac{\mbox{odds}_T}{\mbox{odds}_C}= \frac{f/(d+e)}{c/(a+b)}=\frac{f/(d+e)}{c/(a+b)}=1.15 \]


Genotype Controles Cases Totaal
Pro/Pro 266 (a) 342 (d) 608 (a+d)
Pro/Leu 250 (b) 369 (e) 619 (b+e)
Leu/Leu 56 (c) 89 (f) 145 (c+f)
Totaal 572 (a+b+c) 800 (d+e+f) 1372 (n)
  • Was de bovenstaande studie echter een volledig lukrake steekproef geweest (waarbij het aantal cases en controles niet per design werden vastgelegd),
  • dan konden we daar ook de odds ratio op borstkanker berekenen voor mensen met versus zonder het allel Leu/leu. \[\begin{equation*} OR_{case}=\frac{ \frac{ f}{c}}{ \frac{(d+e)}{(a+b)}} = \frac{f(a+b)}{c(d+e)}=OR_{Leu/Leu}=1.15, \end{equation*}\]
  • OR is een symmetrische maat! OR op borstkanker kan wel worden geschat!
  • De odds op borstkanker is bijgevolg 15% hoger bij vrouwen met die specifieke allelcombinatie.

  • Is verschil groot genoeg zodat we het effect die we in de steekproef zien kunnen veralgemenen naar de populatie toe.

  • Hiertoe zullen we de kruistabel eerst herschrijven tot een 2x2 tabel

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

3.3 De Pearson Chi-kwadraat test voor ongepaarde gegevens

  • Testen voor associatie tussen de categorische blootstelling (bvb. variant, X) en de categorische uitkomst (bvb. ziekte, Y). \[H_0: \text{Er is geen associatie tussen } X \text{ en } Y \text{ vs } H_1: X \text{ en } Y \text{ zijn geassocieerd}\]

  • Beschouw de rijtotalen \(n_\text{andere}=a+c\), \(n_\text{leu,leu}=b+d\) enerzijds en

  • de kolomtotalen \(n_\text{contr}=a+b\) en \(n_\text{case}=c+d\) anderzijds.

  • Zij verstrekken informatie over de marginale verdeling van de blootstelling (bvb. variant, X) en de uitkomst (bvb. ziekte, Y), maar niet over de associatie tussen die veranderlijken.

  • Onder \(H_0\) zijn \(X\) en \(Y\) onafhankelijk zijn en verwacht men een proportie \((b+d)/n\) van \(a+b\) controles met een Leu/Leu variant, of dat \((a+b)(b+d)/n\) een Leu/Leu variant hebben

  • Analoog kan men verwachte aantal \(E_{ij}\) berekenen dat onder de nulhypothese in elke cel van de \(2\times 2\) tabel zou liggen.


  • \(E_{11}\) = het verwachte aantal onder \(H_0\) in de (1,1)-cel = 145 \(\times\) 800/1372 = 84.55 ;

  • \(E_{12}\) = het verwachte aantal onder \(H_0\) in de (1,2)-cel = 145 \(\times\) 572/1372 = 60.45 ;

  • \(E_{21}\) = het verwachte aantal onder \(H_0\) in de (2,1)-cel = 1227 \(\times\) 800/1372 = 715.5 ;

  • \(E_{22}\) = het verwachte aantal onder \(H_0\) in de (2,2)-cel = 1227 \(\times\) 572/1372 = 511.5 ;

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



  • Toetsingsgrootheid groot \(\longrightarrow\) indicatie voor afwijking van \(H_0\).
  • De p-waarde voor een 2-zijdige toets is kans om grotere waarde voor toetsingsgrootheid te observeren dan geobserveerde waarde \(x^2\) als nulhypothese waar is \(\longrightarrow\) kans dat \(\chi^2_1\)-verdeelde toevalsveranderlijke waarden groter dan \(x^2\) aanneemt.

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

  • Omdat observaties \(O_{ij}\) discrete getallen zijn, kan toetsingsgrootheid \(X^2\) slechts discrete waarden aannemen en kan continue verdeling zoals \(\chi^2_1\)-verdeling slechts een benadering zijn.
  • continuïteitscorrectie: 0.5 aftrekken van verwachte aantallen in elke cel \(\longrightarrow\) om beter aan te laten sluiten bij \(\chi^2_1\)-verdeling
  • Pearson Chi-kwadraat toets met Yates correctie.
  • Wanneer de correctie niet gebruikt wordt (d.w.z. wanneer de getallen `0.5’ in de uitdrukking voor \(X^2\) door 0 vervangen worden), dan spreekt men van de Pearson Chi-kwadraat toets.

In R kan je deze toetsen uitvoeren door de optie op TRUE of FALSE te zetten:

chisq.test(brcaTab2)
## 
##  Pearson's Chi-squared test with Yates' continuity correction
## 
## data:  brcaTab2
## X-squared = 0.49542, df = 1, p-value = 0.4815
chisq.test(brcaTab2, correct=FALSE)
## 
##  Pearson's Chi-squared test
## 
## data:  brcaTab2
## X-squared = 0.62871, df = 1, p-value = 0.4278

  • Zelfs met continuïteitscorrectie is \(\chi^2_1\) benadering slechts verantwoord als in geen enkele van de cellen het verwachte aantal onder \(H_0\) kleiner is dan 5.
  • Wanneer de \(\chi^2\)-benadering niet verantwoord is, kan men een Fisher’s exact test uitvoeren.
  • De nulhypothese van deze test is eveneens dat \(X\) en \(Y\) onafhankelijk zijn, en de alternatieve hypothese dat \(X\) en \(Y\) afhankelijk zijn.
fisher.test(brcaTab2)
## 
##  Fisher's Exact Test for Count Data
## 
## data:  brcaTab2
## p-value = 0.4764
## alternative hypothesis: true odds ratio is not equal to 1
## 95 percent confidence interval:
##  0.7998798 1.6738449
## sample estimates:
## odds ratio 
##   1.153279

3.3.1 Uitbreiding naar categorische variabelen met meerdere niveaus

  • \(\chi^2\)-toets kan ook als minstens 1 van de discrete variabelen \(X\) en \(Y\) meer dan 2 mogelijke waarden aanneemt

  • Opnieuw: nulhypothese \(H_0: X\) en \(Y\) zijn onafhankelijk (niet-geassocieerd), ten opzichte van het tweezijdig alternatief \(H_A: X\) en \(Y\) zijn niet onafhankelijk (geassocieerd).

  • Als de variabele voorgesteld op de rijen \(r\) mogelijke uitkomsten heeft en die op de kolommen \(c\) mogelijke uitkomsten, dan noemt men de kruistabel die \(X\) tegenover \(Y\) uitzet, een \(r \times c\) tabel.

  • Zoals voorheen vergelijkt men het aantal geobserveerde waarden in cel \((i,j)\), \(O_{ij}\) genoteerd, met het aantal verwachte waarden onder de nulhypothese, \(E_{ij}\) -Opnieuw is \(E_{ij}\) product van het \(i\)-de rijtotaal met het \(j\)-de kolomtotaal gedeeld door het algemene totaal.

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


  • Men kan aantonen dat ze een Chi-kwadraat verdeling volgt met \((r-1) \times (c-1)\) vrijheidsgraden als de nulhypothese waar is.
  • De continuïteitscorrectie wordt meestal niet gebruikt bij meer dan 2 rijen of kolommen.
  • Pearson \(\chi^2\) test is analogon van de one-way variantie-analyse voor kwalitatieve i.p.v. continue variabelen.

brcaTab <- table(brca$variant,brca$cancer)
chisq.test(brcaTab)
## 
##  Pearson's Chi-squared test
## 
## data:  brcaTab
## X-squared = 2.0551, df = 2, p-value = 0.3579
  • Om te onderzoeken of het BRCA1 gen geassocieerd is met borstkanker, berekenen we de Pearson chi-kwadraat toets voor de case-controle studie.
  • De toetsingsgrootheid bedraagt nu 2.055 en volgt een Chi-kwadraat verdeling met 2 vrijheidsgraden. De kans dat zo’n \(\chi^2\)- verdeelde toevalsveranderlijke extremer is dan 2.055, bedraagt 36%.
  • Op het 5% significantieniveau kunnen we dus niet besluiten dat het BRCA1 gen geassocieerd is met borstkanker.

4 Logistische regressie

  • Raamwerk voor het modelleren van binaire data (vb. kanker vs geen kanker): logistische regressie-modellen.

  • Binaire gegevens modelleren a.d.h.v. continue en/of dummy variabelen.

  • De modellen veronderstellen dat observaties voor subject \(i=1,\ldots,n\) onafhankelijk zijn en een Bernoulli verdeling volgen.

  • Het logaritme van de odds wordt dan gemodelleerd d.m.v. een lineair model, ook wel lineaire predictor genoemd: \[\begin{equation} \left\{ \begin{array}{ccl} Y_i&\sim&B(\pi_i)\\\\ E[Y_i] &=& \pi_i\\\\ \log \frac{\pi_i}{1-\pi_i}&=&\beta_0 + \beta_1X_{i1} + \ldots + \beta_p X_{ip} \end{array}\right. \end{equation}\]


4.1 Categorische predictor

  • Borstkanker voorbeeld: is BRCA 1 variant geassocieerd is met het krijgen van borstkanker.

  • Net zoals in de anova context, factor in het regressieraamwerk d.m.v. dummy variabelen.

  • 1 dummy variable minder nodig hebben dan er groepen zijn.

  • Voor het BRCA 1 voorbeeld zijn dus twee dummy variabelen nodig en kunnen we de data dus modelleren met onderstaande lineaire predictor:

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


  • Waarbij de predictoren dummy-variabelen zijn: \[x_{i1} = \left\{ \begin{array}{ll} 1 & \text{ als subject $i$ heterozygoot is, Pro/Leu variant} \\ 0 & \text{ als subject $i$ homozygoot is, (Pro/Pro of Leu/Leu variant)} \end{array}\right. .\] \[x_{i2} = \left\{ \begin{array}{ll} 1 & \text{ als subject $i$ homozygoot is in de Leucine mutatie: Leu/Leu } \\ 0 & \text{ als subject $i$ niet homozygoot is in de Leu/Leu variant} \end{array}\right. .\]

  • Homozygositeit in het wild type allel Pro/Pro wordt voor dit model de referentiegroep.


We fitten het model in R.

  • Merk op dat we functie as.factor gebruiken om de cancer variabele om te zetten naar een factor.
  • en dat we de functie relevel gebruiken om de controles als referentie groep de definiëren: eerste niveau van de factor.
brca <- brca %>%
  mutate(
    cancer = cancer %>%
      as.factor %>%
      relevel("control"),
    variant = variant %>%
      as.factor %>%
      relevel("pro/pro")
  )

brcaLogit <- glm(
  cancer ~ variant,
  data = brca,
  family = binomial)

summary(brcaLogit)
## 
## Call:
## glm(formula = cancer ~ variant, family = binomial, data = brca)
## 
## Deviance Residuals: 
##    Min      1Q  Median      3Q     Max  
## -1.379  -1.286   1.017   1.017   1.073  
## 
## Coefficients:
##                Estimate Std. Error z value Pr(>|z|)   
## (Intercept)     0.25131    0.08175   3.074  0.00211 **
## variantleu/leu  0.21197    0.18915   1.121  0.26243   
## variantpro/leu  0.13802    0.11573   1.193  0.23302   
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 1863.9  on 1371  degrees of freedom
## Residual deviance: 1861.9  on 1369  degrees of freedom
## AIC: 1867.9
## 
## Number of Fisher Scoring iterations: 4

Het intercept is de log-odds op kanker in de referentieklasse (Pro/Pro) en de hellingstermen zijn log odds ratio’s tussen de behandeling en de referentieklasse: \[\begin{eqnarray*} \log \text{ODDS}_\text{Pro/Pro}&=&\beta_0\\\\ \log \text{ODDS}_\text{Pro/Leu}&=&\beta_0+\beta_1\\\\ \log \text{ODDS}_\text{Leu/Leu}&=&\beta_0+\beta_2\\\\ \log \frac{\text{ODDS}_\text{Pro/Leu}}{\text{ODDS}_\text{Pro/Pro}}&=&\log \text{ODDS}_\text{Pro/Leu}-\log ODDS_{Pro/Pro}\\ &=&\beta_0+\beta_1-\beta_0=\beta_1\\\\ \log \frac{\text{ODDS}_\text{Leu/Leu}}{\text{ODDS}_\text{Pro/Pro}}&=&\beta_2 \end{eqnarray*}\]

  • De analyse laat dus toe om de resultaten onmiddellijk te interpreteren in termen van Odds’es en Odds-ratio’s!

anova(brcaLogit, test = "Chisq")
## Analysis of Deviance Table
## 
## Model: binomial, link: logit
## 
## Response: cancer
## 
## Terms added sequentially (first to last)
## 
## 
##         Df Deviance Resid. Df Resid. Dev Pr(>Chi)
## NULL                     1371     1863.9         
## variant  2   2.0562      1369     1861.9   0.3577

De \(\chi^2\)-test op het logistische regressiemodel geeft eveneens aan dat er geen significante associatie is tussen de uitkomst (voorkomen van kanker) en de factor ( de genetische variant van het BRCA gen) (\(p=\) 0.358). De p-waarde is bijna equivalent aan de p-waarde van de \(\chi^2\)-test uit de vorige sectie.


  • Significante associatie? Post-hoc tests om te evalueren welke odds ratio’s verschillend zijn.
  • Voor het BRCA1 voorbeeld zouden we uiteraard geen post-hoc testen
  • Toch illustratie zodat jullie over de code beschikken

suppressPackageStartupMessages({library(multcomp)})
posthoc <- glht(brcaLogit, linfct = mcp(variant = "Tukey"))
posthocTests <- summary(posthoc)
posthocTests
## 
##   Simultaneous Tests for General Linear Hypotheses
## 
## Multiple Comparisons of Means: Tukey Contrasts
## 
## 
## Fit: glm(formula = cancer ~ variant, family = binomial, data = brca)
## 
## Linear Hypotheses:
##                        Estimate Std. Error z value Pr(>|z|)
## leu/leu - pro/pro == 0  0.21197    0.18915   1.121    0.493
## pro/leu - pro/pro == 0  0.13802    0.11573   1.193    0.449
## pro/leu - leu/leu == 0 -0.07395    0.18922  -0.391    0.917
## (Adjusted p values reported -- single-step method)

posthocBI <- confint(posthoc)
posthocBI
## 
##   Simultaneous Confidence Intervals
## 
## Multiple Comparisons of Means: Tukey Contrasts
## 
## 
## Fit: glm(formula = cancer ~ variant, family = binomial, data = brca)
## 
## Quantile = 2.3232
## 95% family-wise confidence level
##  
## 
## Linear Hypotheses:
##                        Estimate lwr      upr     
## leu/leu - pro/pro == 0  0.21197 -0.22745  0.65139
## pro/leu - pro/pro == 0  0.13802 -0.13084  0.40688
## pro/leu - leu/leu == 0 -0.07395 -0.51353  0.36564
  • Door middel van de confint functie worden BI’s verkregen op de log-odds ratios die gecorrigeerd zijn voor multiple testing.

  • BI’s kunnen als volgt worden teruggetransformeerd naar odds ratios:
OR <- exp(posthocBI$confint)
OR
##                    Estimate       lwr      upr
## leu/leu - pro/pro 1.2361111 0.7965606 1.918210
## pro/leu - pro/pro 1.1480000 0.8773578 1.502128
## pro/leu - leu/leu 0.9287191 0.5983766 1.441432
## attr(,"conf.level")
## [1] 0.95
## attr(,"calpha")
## [1] 2.323183
  • De odds ratios die worden bekomen met het logistisch regressiemodel zijn exact gelijk aan de odds ratios die we zouden bekomen op basis van Tabel:

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

  • Merk op dat de statistische besluitvorming bij logistische modellen beroep doet op asymptotische theorie.


4.2 Continue predictor

  • Toxicologisch effect van koolstofdisulfide (CS\(_2\)) op kevers.

  • De centrale onderzoeksvraag is of de concentratie van CS\(_2\) een effect heeft op de mortaliteit (i.e. kans op sterven) van de kevers?

Design

  • 32 onafhankelijk experimenten
  • Telkens 1 kever blootgesteld aan één van 8 concentraties (mg/l) van CS\(_2\) voor een gegeven periode.
  • De uitkomst van het experiment is: de kever sterft (\(y=1\)) of de kever overleeft (\(y=0\)).
beetles <- read_csv("https://raw.githubusercontent.com/statomics/sbc20/master/data/beetles.csv")
## 
## ── Column specification ────────────────────────────────────────────────────────────────
## cols(
##   dose = col_double(),
##   status = col_double()
## )
head(beetles)
## # A tibble: 6 x 2
##    dose status
##   <dbl>  <dbl>
## 1  169.      1
## 2  169.      0
## 3  169.      0
## 4  169.      0
## 5  172.      1
## 6  172.      0
table(beetles$dose, beetles$status)
##         
##          0 1
##   169.07 3 1
##   172.42 3 1
##   175.52 3 1
##   178.42 2 2
##   181.13 1 3
##   183.69 0 4
##   186.1  0 4
##   188.39 0 4

Logistisch regressiemodel dat log odds modelleert in functie van dosis \(x_i\): \[\log \frac{\pi_i}{1-\pi_i}=\beta_0+\beta_1 \times x_i.\]

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

summary(beetleModel)
## 
## Call:
## glm(formula = status ~ dose, family = binomial, data = beetles)
## 
## Deviance Residuals: 
##     Min       1Q   Median       3Q      Max  
## -1.7943  -0.7136   0.2825   0.5177   2.1670  
## 
## Coefficients:
##             Estimate Std. Error z value Pr(>|z|)   
## (Intercept) -53.1928    18.0046  -2.954  0.00313 **
## dose          0.3013     0.1014   2.972  0.00296 **
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 42.340  on 31  degrees of freedom
## Residual deviance: 26.796  on 30  degrees of freedom
## AIC: 30.796
## 
## Number of Fisher Scoring iterations: 5

  • Intercept: log odds op mortaliteit wanneer er geen \(\text{CS}_2\) gas wordt toegediend.

  • Erg lage odds op sterfte (\(\pi/(1-\pi)=\exp(-53.2)\)) en dus op een kans die nagenoeg nul is.

  • Merk op: heel sterke extrapolatie: minimum dosis in de dataset 169.07 mg/l.

  • Geschatte odds ratio voor dosis effect op de mortaliteitskans is \(\exp(0.3013)=1.35\).

  • Dus bij een toename van de dosis CS\(_2\) met 1 mg/l, is de odds ratio voor de mortaliteit \(1.35\).


  • We besluiten dat dit effect heel significant is (\(p=\) 0.003).
  • Een toename in de CS\(_2\) dosis doet de kans op sterven toenemen.
beetlesTab<-table(beetles) %>% data.frame

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


LS0tCnRpdGxlOiA5LiBDYXRlZ29yaXNjaGUgRGF0YSBBbmFseXNlCmF1dGhvcjogIkxpZXZlbiBDbGVtZW50IgpkYXRlOiAic3RhdE9taWNzLCBHaGVudCBVbml2ZXJzaXR5IChodHRwczovL3N0YXRvbWljcy5naXRodWIuaW8pIgpvdXRwdXQ6CiAgICBodG1sX2RvY3VtZW50OgogICAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICAgIHRoZW1lOiBjb3NtbwogICAgICB0b2M6IHRydWUKICAgICAgdG9jX2Zsb2F0OiB0cnVlCiAgICAgIGhpZ2hsaWdodDogdGFuZ28KICAgICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCi0tLQoKCiMgSW5sZWlkaW5nCgotIFZvcmlnZSBob29mZHN0dWtrZW46CgogIC0gY29udGludWUgdWl0a29tc3QgIAogIC0gY2F0ZWdvcmlzY2hlIG9mIGNvbnRpbnVlIHByZWRpY3Rvci4KCi0gTnUgYmVzbHVpdHZvcm1pbmcgdm9vciBjYXRlZ29yaXNjaGUgdWl0a29tc3QuCi0gRm9jdXMgb3AgYXNzb2NpYXRpZSB0dXNzZW4gY2F0ZWdvcmlzY2hlIHVpdGtvbXN0IGVuIGVlbiBjYXRlZ29yaXNjaGUgcHJlZGljdG9yLgotIEdlYnJ1aWsgdmFuICprcnVpc3RhYmVsbGVuKiBvbSBhc3NvY2lhdGllIHZvb3IgdGUgc3RlbGxlbi4KCi0tLQoKIyBUb2V0c2VuIHZvb3IgZWVuIHByb3BvcnRpZQoKIyMgU2Frc2VuLXN0dWRpZQoKLSBWcmlqIGdlc2xvdGVuIHBvcHVsYXRpZSAod2VpbmlnIGltbWlncmF0aWUgZW4gZW1pZ3JhdGllKQotIFdhdCBpcyBkZSBrYW5zIGRhdCBlZW4gb25nZWJvcmVuIGtpbmQgbWFubmVsaWprIGlzPwoKYGBge3J9CmJveXMgPC0gMzE3NQpuIDwtIDYxNTUKYGBgCgotIE9wIGByIG5gIG9uZ2Vib3JlbiBraW5kZXJlbiB3ZXJkZW4gYHIgYm95c2Agam9uZ2VucyBnZW9ic2VydmVlcmQuCi0gVmVyc2NoaWwgaW4ga2FucyBkYXQgb25nZWJvcmVuIGtpbmQgam9uZ2VuIG9mIG1laXNqZSBpcz8KCi0tLQoKLSBHZWdldmVucyB2b29yc3RlbGxlbiBhbHMgdWl0a29tc3RlbiB2YW4gZWVuIG51bWVyaWVrZSB0b2V2YWxzdmVyYW5kZXJsaWprZSAkWCQKCiAgLSAkWD0xJCB2b29yIGpvbmdlbnMgZW4KICAtICRYPTAkIHZvb3IgbWVpc2plcy4KCi0gTWVyayBvcDogdGVscHJvYmxlZW0gb21kYXQgZGUgdWl0a29tc3QgZWVuIHRlbGxpbmcgKG5sLiBoZXQgYWFudGFsIGpvbmdlbnMpCgotIEZvcm1lZWw6IHBvcHVsYXRpZSB2YW4gb25nZWJvcmVuIGtpbmRlcmVuCndhYXJpbiBlbGsgaW5kaXZpZHUgZ2VrZW5tZXJrdCB3b3JkdCBkb29yIGVlbiAwIG9mIGVlbiAxLgoKLSBVaXRrb21zdCB2YXJpYWJlbGUgaXMgYmluYWlyLgoKLS0tCgojIyBCZXJub3VsbGkgdmVyZGVsaW5nCgotIEJpbmFpcmUgZGF0YSAkXGxvbmdyaWdodGFycm93JCBCZXJub3VsbGkgdmVyZGVsaW5nOgogIFxiZWdpbntlcW5hcnJheSp9ClhfaSAmXHNpbSYgQihccGkpIFx0ZXh0eyBtZXR9XFwKQihccGkpJj0mXHBpXntYX2l9KDEtXHBpKV57KDEtWF9pKX0sClxlbmR7ZXFuYXJyYXkqfQoKLSBEaXN0cmlidXRpZSBtZXQgMSBtb2RlbCBwYXJhbWV0ZXIgJFxwaSQKCiAgICAtIFZlcndhY2h0ZSB3YWFyZGUgdmFuICRYX2kkOiAkXHRleHR7RX1bWF9pXT1ccGksJAogICAgLSBQcm9wb3J0aWUgdmFuIG9uZ2Vib3JlbiBqb25nZW5zIChkLmkuIGtpbmRlcmVuIG1ldCBlZW4gMSkgaW4gZGUgcG9wdWxhdGllLgogICAgLSBCaWpnZXZvbGcgaXMgJFxwaSQga2FucyBkYXQgbHVrcmFhayBnZXRyb2trZW4gaW5kaXZpZHUgZWVuIGpvbmdlbiBpcyAoZWVuIG9ic2VydmF0aWUgZGllIDEgb3BsZXZlcnQpLgoKLSBWYXJpYW50aWUgdmFuIEJlcm5vdWxsaSBkYXRhIGJlcGFhbGQgZG9vciBrYW5zICRccGkkLgokJFx0ZXh0e1Zhcn1bWF9pXT1ccGkgKDEtXHBpKS4kJAoKLS0tCgpHcmFmaXNjaGUgd2VlcmdhdmUgdmFuIGVua2VsZSBCZXJub3VsbGkga2Fuc3ZlcmRlbGluZ2VuCgpgYGB7ciwgb3V0LndpZHRoPScxMDAlJywgZmlnLmFzcD0xLCBmaWcuYWxpZ249J2NlbnRlcicsZWNobz1GQUxTRX0KcGFyKG1mcm93PWMoMSwzKSxwdHk9InMiKQpwcm9icz1jKDAuMjUsLjUsLjc1KQpmb3IgKGkgaW4gMTpsZW5ndGgocHJvYnMpKQp7CnBsb3QoYygwLDEpLGMoMS1wcm9ic1tpXSxwcm9ic1tpXSkseWxpbT1jKDAsMSksdHlwZT0iaCIseGF4dD0ibiIseGxhYj0iWCIseWxhYj0iS2FucyAoRGljaHRoZWlkKSIsbWFpbj0gYXMuZXhwcmVzc2lvbihzdWJzdGl0dXRlKHBpID09IHZhbCxsaXN0KHZhbD1wcm9ic1tpXSkpKSxsd2Q9MykKYXhpcygxLGF0PWMoMCwxKSkKfQpgYGAKCi0tLQoKLSBJbiBTYWtzZW5zdHVkaWUgd29yZGVuIGx1a3JhYWsgNjE1NSBvYnNlcnZhdGllcyBnZXRyb2trZW4gdWl0IHBvcHVsYXRpZS4KLSBXZSBzY2hhdHRlbiAkXHBpJCBhbHMgaGV0IHN0ZWVrcHJvZWZnZW1pZGRlbGRlIDoKJCRcaGF0IFxwaSA9IFxiYXIgWCA9IFxmcmFje1xzdW1cbGltaXRzX3tpPTF9Xm4gWF9pfXtufSwkJAoKYGBge3J9CnBpIDwtIGJveXMvbgpwaQpgYGAKCkluIG9ucyB2b29yYmVlbGQgaXMgJFxiYXIgeCA9JCBgciBib3lzYCAvIGByIG5gID0gYHIgZm9ybWF0KHBpKjEwMCxkaWdpdHM9MylgJS4KCi0tLQoKIyMgQXN5bXB0b3Rpc2NoIEJldHJvdXdiYWFyaGVpZHNpbnRlcnZhbAoKLSBTYWtzZW5zdHVkaWUgaGVlbCBncm90ZSBzdGVla3Byb2VmOiBgciBuYCBvbmFmaGFua2VsaWprZSBvYnNlcnZhdGllcy4KLSBDTFQga2FuIHdvcmRlbiB0b2VnZXBhc3Qgb3AgZ2VtaWRkZWxkZTogZGF0YSB2b2xndCBCZXJub3VsbGkgdmVyZGVsaW5nLCBtYWFyIGdlbWlkZGVsZGUgby5iLnYuIG9uYWZoYW5rZWxpamtlIGVuIGlkZW50aWVrIHZlcmRlZWxkZSBvYnNlcnZhdGllcyBpbiBoZWVsIGdyb3RlIHN0ZWVrcHJvZWYgdm9sZ3QgYXBwcm94aW1hdGllZiBlZW4gbm9ybWFhbCB2ZXJkZWxpbmcuICAKLSAkXHRleHR7RX1bXGJhciBYXSA9IFxwaSQKLSAkXHRleHR7VmFyfVtcYmFyIFhdID0gXGZyYWN7XHRleHR7VmFyfVtYXX17bn0gPSBcZnJhY3tccGkoMS1ccGkpfXtufSQKCi0gJFxiYXIgeCQgPSBgciByb3VuZChwaSwzKWAKCmBgYHtyfQpzZSA8LSBzcXJ0KChwaSooMS1waSkpL24pCmBgYAoKLSBTRSA9IGByIHJvdW5kKHNlLDQpYFxbClx0ZXh0e1NFfSA9IFxoYXRcc2lnbWFfe1xiYXIgeH0gPSBcc3FydHtcZnJhY3tcYmFyIHgoMS1cYmFyIHgpfXtufX0gXF0KLSBCSTogW2ByICBwYXN0ZShmb3JtYXQocGkgKyBjKC0xLDEpKnFub3JtKC45NzUpKnNlLCBkaWdpdHM9MyksIGNvbGxhcHNlPSIsICIpYF0KXFsgW1xiYXIgeCAtIHpfe1xhbHBoYS8yfSBcdGV4dHtTRX1fe1xiYXIgeH0sIFxiYXIgeCArIHpfe1xhbHBoYS8yfSBcdGV4dHtTRX1fe1xiYXIgeH1dXF0KCi0gMC41IHZhbHQgbmlldCBiaW5uZW4gaGV0IDk1JSBCSS4KCi0gRGUga2FucyBvcCBlZW4gam9uZ2VuIGlzIHNpZ25pZmljYW50IGhvZ2VyIGRhbiA1MCUgb3AgaGV0IDUlIHNpZ25pZmljYW50aWUtbml2ZWF1LgoKIyMgQXN5bXB0b3Rpc2NoZSBUZXN0CgotIEgkXzAkOiAkXHBpID0gMC41JCB2cyBIJF8xJDogJFxwaSBcbmVxIDAuNSQKCi0gTWVyayBvcCBkYXQgdm9vciBlZW4gQmVybm91bGxpIHZlcmRlbGluZyBkZSB2YXJpYW50aWUgb25kZXIgSCRfMCQgb29rIGdla2VuZCBpczogJFxwaV8wICgxLVxwaV8wKSQuCgotIER1cyBvbmRlciAkSF8wJCBpcyBzdGFuZGFhcmQgZXJyb3Igb3AgXGJhciB4OgoKXFsKXHRleHR7U0V9X3swLCBcYmFyIHh9PVxzcXJ0e1xmcmFje1xwaV8wICgxLVxwaV8wKX17bn19ClxdCgotIFN0YXRpc3RpZWsKXFsgeiA9IFxmcmFje1xiYXIgeCAtIFxwaV8wfXtcdGV4dHtTRX1fezAsIFxiYXIgeH19XF0KCi0gVm9sZ3Qgb25kZXIgZGUgbnVsaHlwb3RoZXNlIGRhdCBlciBldmVudmVlbCBrYW5zIGlzIG9wIGVlbiBqb25nZW4gb2YgZWVuIG1laXNqZSAoJFxwaV8wPTAuNSQpIGFzeW1wdG90aXNjaCBlZW4gbm9ybWFhbCB2ZXJkZWxpbmc6IENMVAoKCi0gcC13YWFyZGU/IE1lcmsgb3AgZGF0IGhldCBlZW4gdHdlZXppamRpZ2UgdGVzdCBpcyEKCmBgYHtyfQpwaTAgPC0gMC41CnNlMCA8LSBzcXJ0KHBpMCooMS1waTApL24pCnogPC0gKHBpLXBpMCkvc2UwCnoKcHZhbCA8LSBwbm9ybShhYnMoeiksbG93ZXI9RkFMU0UpICoyCnB2YWwKYGBgCgpFciBpcyBzaWduaWZpY2FudCBtZWVyIGthbnMgZGF0IGVlbiBvbmdlYm9yZW4ga2luZCBtYW5uZWxpamsgZGFuIHZyb3V3ZWxpamsgaXMgKHA9YHIgcm91bmQocHZhbCwzKWApLiBEZSBrYW5zIGRhdCBlZW4gb25nZWJvcmVuIGtpbmQgbWFubmVsaWprIGlzIGJlZHJhYWd0IGByIHJvdW5kKHBpLCAzKWAgKDk1JSBCSSBbYHIgIHBhc3RlKGZvcm1hdChwaSArIGMoLTEsMSkqcW5vcm0oLjk3NSkqc2UsIGRpZ2l0cz0zKSwgY29sbGFwc2U9IiwgIilgXSkuCgojIyBFeGFjdGUgdGVzdDogQmlub21pYWxlIHRlc3QKCi0gU3RhdGlzdGlzY2hlIHRvZXRzIHZvb3IKICAkJEhfMDogXHBpPTEvMiBcdGV4dHsgdmVyc3VzIH0gSF8xOiBccGlcbmVxIDEvMiwkJAoKLSBEYWFydm9vciBtb2V0ZW4gd2UgdmVyZGVsaW5nIHZhbiBkZQogICAtICRYJCBlbiAkXGJhciBYJAogICAtIG9mIHZhbiBkZSBzb20gJFM9blxiYXIgWCQga2VubmVuLgotIEFscyBhbGxlIG9ic2VydmF0aWVzIG9uYWZoYW5rZWxpamsgemlqbiBlbiBlZW56ZWxmZGUgdmVyZGVsaW5nICRCKFxwaSkkIHZvbGdlbiBkYW4gdm9sZ3QgJFMkIGVlbiBiaW5vbWlhYWwgdmVyZGVsaW5nLgoKLS0tCgotIFN0ZWwgICRIXzA6XHBpPTEvMiQgaXMgd2FhciAodm9vcmtvbWVuIHZhbiBqb25nZW5zIGVuIG1laXNqZXMgaW4gcG9wdWxhdGllIGV2ZW4gd2FhcnNjaGlqbmxpamspCi0gTHVrcmFrZSB0cmVra2luZyB2YW4gw6nDqW4gaW5kaXZpZHUgdWl0IGRlIHBvcHVsYXRpZSwga2FucyBvcCBlZW4gam9uZ2VuICQkUChYPTEpPVxwaT0xLzIuJCQKLSBUd2VlIGtpbmRlcmVuIG9uYWZoYW5rZWxpamsgdmFuIGVsa2FhciAoZW4gZGUgcG9wdWxhdGllICRcYXBwcm94IFxpbmZ0eSQpOgogIC0gS2FucyAkXHBpPTEvMiQgb3Agam9uZ2VuIHZvb3Igem93ZWwgZWVyc3RlIGFscyB0d2VlZGUga2luZCAob25hZmhhbmtlbGlqayB2YW4gZWxrYWFyKQogIC0gVWl0a29tc3RlbiAkKHhfMSwgeF8yKSQgdm9vciBiZWlkZSBraW5kZXJlbiBoZWJiZW4gZGFuIDQgbW9nZWxpamtlIHdhYXJkZW46CiAgICAkKDAsMCksKDAsMSksKDEsMClcdGV4dHsgZW4gfSgxLDEpLiQKICAtIERlemUga29tZW4gZWxrIHZvb3IgbWV0IGthbnMgJDEvNCA9IDEvMiBcdGltZXMgMS8yJC4KCi0gVG9ldmFsc3ZlcmFuZGVybGlqa2UgJFMkIGRpZSBzb20gdmFuIHVpdGtvbXN0ZW4gd2VlcmdlZWZ0IGthbiB2b2xnZW5kZSB3YWFyZGVuIGFhbm5lbWVuOgoKJCh4XzEseF8yKSR8JHMkfCRQKFMgPSBzKSR8Cnw6LS0tOnw6LS0tOnw6LS0tOnwKKDAsMCl8MHwxLzR8CigwLDEpLCAoMSwwKXwxfDEvMnwKKDEsMSl8MnwxLzR8CgotLS0KCiMjIyBBbGdlbWVlbjogJG4kIG9uYWZoYW5rZWxpamtlIG9ic2VydmF0aWVzCgotIEthbnMgJFxwaSQgb3AgInN1Y2NlcyIgKHVpdGtvbXN0IDEpIHZvb3IgZWxrZSBvYnNlcnZhdGllCi0gVG90YWFsIGFhbnRhbCBzdWNjZXNzZW4gJFMkIChzb20gdmFuIGFsbGUgMS1lbikga2FuICRuKzEkIG1vZ2VsaWprZSB3YWFyZGVuIGhlYmJlbgogICQkUz1rXHRleHR7LCBtZXQgfWs9MCxcbGRvdHMsbiQkCi0gVmVyZGVsaW5nIHZhbiAkUyQ/ClxiZWdpbntlcXVhdGlvbn0KUChTPWspID0gXGxlZnQgKApcYmVnaW57YXJyYXl9e2N9Cm4gXFwKayBcXApcZW5ke2FycmF5fQpccmlnaHQgKSBccGleayAoMS1ccGkpXntuLWt9ICAKXGVuZHtlcXVhdGlvbn0KLSAkMS1ccGkkOiBrYW5zIG9wIG1pc2x1a2tpbmcgaW4gMSBlbmtlbGUgdHJla2tpbmcgKHVpdGtvbXN0IG1ldCAwIGdlbm90ZWVyZCkgZW4KLSAgYmlub21pYWFsY2/Dq2ZmaWNpZW50ClxiZWdpbntlcXVhdGlvbip9ClxsZWZ0ICgKXGJlZ2lue2FycmF5fXtjfQpuIFxcCmsgXFwKXGVuZHthcnJheX0KXHJpZ2h0ICkgPSBcZnJhY3tuIFx0aW1lcyAobi0xKSBcdGltZXMgLi4uXHRpbWVzIChuLWsrMSkgfXsgayF9ID0gXGZyYWN7IG4hfXsgayEobi1rKSEgfQpcZW5ke2VxdWF0aW9uKn0KCi0gSW4gUiBrYW4gamUgZGUga2Fuc2VuIHZhbiBiaW5vbWlhbGUgdmVyZGVsaW5nIHZvb3IgZWxrZSAkUz1rJCBvcHZyYWdlbiBtZXQgYGRiaW5vbShrLG4scClgCgoKLS0tCgojIyMgQmlub21pYWxlIFZlcmRlbGluZwoKRGUgdG9ldmFsc3ZlcmFuZGVybGlqa2UgJFMkIHZvbGd0OgoKLSAgKkJpbm9taWFhbCB2ZXJkZWVsZGUgdG9ldmFsc3ZlcmFuZGVybGlqa2UqIG1ldCBiaWpob3JlbmRlICpCaW5vbWlhbGUga2Fuc3ZlcmRlbGluZyoKLSBwYXJhbWV0ZXJzCgogICAgLSAkbiQgKGQuaS4gaGV0IGFhbnRhbCB0cmVra2luZ2VuIG9mLCBlcXVpdmFsZW50LCBkZSBtYXhpbWFsZQp1aXRrb21zdHdhYXJkZSkgIAogICAgLSAkXHBpJCAoZGUga2FucyBvcCBlZW4gYHN1Y2NlcycgYmlqIGVsa2UgdHJla2tpbmcpLgoKLSBLYW5zIGJlcmVrZW5lbiBkYXQgJGskIGdlYmV1cnRlbmlzc2VuIHppY2ggdm9vcmRvZW4gb3AgJG4kIG9uYWZoYW5rZWxpamtlIGV4cGVyaW1lbnRlbiB3YWFyYmlqIGthbnMgb3AgMSB6byduIGdlYmV1cnRlbmlzIHBlciBleHBlcmltZW50LCAkXHBpJCBiZWRyYWFndC4KLSBWb29yIGFuYWx5c2UgdmFuIGdlZ2V2ZW5zIGRpZSBzbGVjaHRzIDIgbW9nZWxpamtlIHdhYXJkZW4ga3VubmVuIGFhbm5lbWVuLgotIEJpanZvb3JiZWVsZDogYWwgZGFuIG5pZXQgYmVzbWV0IG1ldCBISVYsIHdpbGQgdHlwZSB2YW4gZWVuIGdlbiB2cyBlZW4gbXV0YW50LC4uLgotIEdlYnJ1aWs6IFByb3BvcnRpZXMgb2YgcmlzaWNvJ3Mgb3AgZWVuIGdlYmV1cnRlbmlzIHZhbiBlZW4gYmVwYWFsZCB0eXBlIHZlcmdlbGlqa2VuIHR1c3NlbiB2ZXJzY2hpbGxlbmRlIGdyb2VwZW4uCgotLS0KCiMjIyBFZW4gZ3JhZmlzY2hlIHdlZXJnYXZlIHZhbiBlbmtlbGUgQmlub21pYWxlIGthbnN2ZXJkZWxpbmdlbi4KCmBgYHtyIGJpbm9tcyxmaWcuY2FwPSdCaW5vbWlhbGUgdmVyZGVsaW5nZW4uJywgb3V0LndpZHRoPSc4MCUnLCBmaWcuYXNwPS44LCBmaWcuYWxpZ249J2NlbnRlcicsZWNobz1GQUxTRX0KcGFyKG1mcm93PWMoMiwyKSkKcHJvYnMgPC0gYygwLjI1LC41LC43NSkKZm9yIChpIGluIDE6bGVuZ3RoKHByb2JzKSkKewpwbG90KDA6MTAsZGJpbm9tKDA6MTAscHJvYj1wcm9ic1tpXSxzaXplPTEwKSx5bGltPWMoMCwxKSx0eXBlPSJoIix4bGFiPSJYIix5bGFiPSJLYW5zIChEaWNodGhlaWQpIixtYWluPSBhcy5leHByZXNzaW9uKHN1YnN0aXR1dGUocGkgPT0gdmFsLGxpc3QodmFsPXBhc3RlKHByb2JzW2ldLCIsIG5vYnM9MTAiKSkpKSxsd2Q9MykKfQpwbG90KDI5MjU6MzIyNSxkYmlub20oMjkyNTozMjI1LHByb2I9LjUsc2l6ZT1uKSx0eXBlPSJoIix4bGFiPSJYIix5bGFiPSJLYW5zIChEaWNodGhlaWQpIixtYWluPSBhcy5leHByZXNzaW9uKHN1YnN0aXR1dGUocGkgPT0gdmFsLGxpc3QodmFsPXBhc3RlMCgiMC41LCBub2JzPSIsbikpKSkpCmBgYAoKLS0tCgpUb2V0c3N0YXRpc3RpZWtlbiB2b29yICQkSF8wOlxwaT0xLzJcdGV4dHsgdmVyc3VzIH1IXzE6XHBpXG5lcSAxLzIkJAoKCi0gJFxiYXIgWC0xLzIkIG9mLCBlcXVpdmFsZW50LAotICRcRGVsdGE9bihcYmFyIFgtXHBpXzApPVMtc18wJC4KLSBWZXJkZWxpbmcgdmFuIGRlemUgbGFhdHN0ZSB0b2V0c3N0YXRpc3RpZWsgdm9sZ3QgcmVjaHRzdHJlZWtzIHVpdCBkZSBCaW5vbWlhbGUgdmVyZGVsaW5nOgogIC0gV2Ugb2JzZXJ2ZXJlbiAkcz0kIGByIGJveXNgIGVuIGR1cyAkXGRlbHRhPXMtc18wPSQgYHIgYm95c2AgJC0kIGByIG5gICRcdGltZXMgMC41PSQgYHIgYm95cy1uLzJgLgogIC0gSW4gdmVyb25kZXJzdGVsbGluZyBkYXQgam9uZ2VucyBlbiBtZWlzamVzIGV2ZW4gd2FhcnNjaGlqbmxpamsgemlqbiAoZC5pLiBvbmRlciBkZSBudWxoeXBvdGhlc2UgJEhfMDpccGk9MS8yJCksIGJla29tZW4gd2UgZGUgYmlqaG9yZW5kZSB0d2VlemlqZGlnZSBwLXdhYXJkZToKICAgICQkcD1cdGV4dHtQfV8wXGxlZnRbUy1zXzBcZ2VxIFx2ZXJ0IFxkZWx0YVx2ZXJ0IFxyaWdodF0gKyBcdGV4dHtQfV8wXGxlZnRbUy1zXzBcbGVxIC0gXHZlcnQgXGRlbHRhXHZlcnQgXHJpZ2h0XS4kJAoKLSBNZXJrIG9wIGRhdCB3ZSBkaXQga3VubmVuIGhlcnNjaHJpanZlbiBpbiB0ZXJtZW4gdmFuIFMuCiQkcD1cdGV4dHtQfV8wXGxlZnRbU1xnZXEgc18wKyBcdmVydCBcZGVsdGFcdmVydCBccmlnaHRdICsgXHRleHR7UH1fMFxsZWZ0W1MgXGxlcSBzXzAgLSBcdmVydCBcZGVsdGFcdmVydCBccmlnaHRdLiQkCgotLS0KCi0gVm9vciBvbnMgdm9vcmJlZWxkIGt1bm5lbiB3ZSBkZXplIGthbnNlbiBhbHMgdm9sZ3QgYmVyZWtlbmVuOgoKXGJlZ2lue2VxbmFycmF5Kn0KXHRleHR7UH1fMFxsZWZ0W1NcZ2VxIHNfMCsgXHZlcnQgXGRlbHRhXHZlcnQgXHJpZ2h0XSAmPSYgUChTIFxnZXEgNjE1NSBcdGltZXMgMC41ICsgXHZlcnQgMzE3NSAtIDYxNTUgXHRpbWVzIDAuNVx2ZXJ0ICkgXFwmPSYgUChTIFxnZXEgMzE3NSlcXAomPSAmUChTPSAzMTc1KSArIFAoUz0zMTc2KSArIC4uLiArIFAoUz02MTU1KVxcCiYgPSYgMC4wMDY3XFxcXApcdGV4dHtQfV8wXGxlZnRbUyBcbGVxIHNfMCAtIFx2ZXJ0IFxkZWx0YVx2ZXJ0IFxyaWdodF0gJj0mIFAoUyBcbGVxICA2MTU1IFx0aW1lcyAwLjUgLSBcdmVydCAzMTc1LSA2MTU1IFx0aW1lcyAwLjVcdmVydCkgXFwmPSYgUChTIFxsZXEgMjk4MClcXCAmPSAmUChTPTApICsgLi4uICsgUChTPTI5ODApIFxcCiY9JjAuMDA2NwpcZW5ke2VxbmFycmF5Kn0KCi0gQmlub21pYWxlIGRpc3RyaWJ1dGllIGlzIHN5bW1ldHJpc2NoIGFscyAkXHBpPTEvMiQ6CiQkXHRleHR7UH1fMFxsZWZ0W1NcZ2VxIHNfMCsgXHZlcnQgXGRlbHRhXHZlcnQgXHJpZ2h0XSA9IFx0ZXh0e1B9XzBcbGVmdFtTIFxsZXEgc18wIC0gXHZlcnQgXGRlbHRhXHZlcnQgXHJpZ2h0XSQkCi0gRGF0IGlzIG5pZXQgbGFuZ2VyIGhldCBnZXZhbCB3YW5uZWVyICRccGkkIGFmd2lqa3QgdmFuIDAuNS4gIAoKLS0tCgpgYGB7cn0KcGkwIDwtIDAuNTsgczAgPC0gcGkwICpuCmRlbHRhIDwtIGFicyhib3lzLSBzMCkKZGVsdGEKCnNVcCA8LSBzMCArIGRlbHRhCnNEb3duIDwtIHMwIC1kZWx0YQpjKHNEb3duLHNVcCkKCnBVcCA8LSAxLXBiaW5vbShzVXAtMSxuLHBpMCkKcERvd24gPC0gcGJpbm9tKHNEb3duLG4scGkwKQpwIDwtIHBVcCtwRG93bgpjKHBVcCxwRG93biwgcCkKYGBgCgotIEFscyAkXHBpPSAxLzIkLCBrYW5zIG9tIGRvb3IgdG9ldmFsIG1pbnN0ZW5zICRcZGVsdGE9JCBgciBkZWx0YWAgam9uZ2VucyBtZWVyIG9mIG1pbmRlciB0ZSBvYnNlcnZlcmVuIGRhbiBoZXQgZ2VtaWRkZWxkZSBvbmRlciAkSF8wOiBzXzA9JCBgciBzMGAgLCBzbGVjaHRzIGByIGZvcm1hdChwKjEwMCxkaWdpdHM9MylgJSBpczogKipkZSAkcCQtd2FhcmRlIHZhbiBkZSBiaW5vbWlhbGUgdGVzdC4qKiAgCi0gS2xlaW5lIGthbnMgb20gZWVuIGRlcmdlbGlqayBncm9vdCBhYW50YWwgam9uZ2VucyB0ZSBvYnNlcnZlcmVuIGFscyBpbiByZWFsaXRlaXQgam9uZ2VucyBlbiBtZWlzamVzIGV2ZW4gdmVlbCB2b29ya29tZW4gaW4gZGUgcG9wdWxhdGllLgotIERydWt0IHVpdCBkYXQgZGUgb25kZXJzdGVsbGluZyBkYXQgam9uZ2VucyBlbiBtZWlzamVzIGV2ZW4gdmVlbCB2b29ya29tZW4sIHdlaW5pZyBnZXN0ZXVuZCB3b3JkdCBkb29yIGRlIGRhdGEuCgotLS0KCmBgYHtyLCBvdXQud2lkdGg9JzEwMCUnLCBmaWcuYXNwPS44LCBmaWcuYWxpZ249J2NlbnRlcicsZWNobz1GQUxTRX0KcGxvdChzMCtzZXEoLTE1MC41LDE1MC41LDEpLGRiaW5vbShzMCtzZXEoLTE1MC41LDE1MC41LDEpLHByb2I9LjUsc2l6ZT1uKSx0eXBlPSJoIix4bGFiPSJYIix5bGFiPSJLYW5zIChEaWNodGhlaWQpIixtYWluPSBhcy5leHByZXNzaW9uKHN1YnN0aXR1dGUocGkgPT0gdmFsLGxpc3QodmFsPXBhc3RlMCgiMC41LCBub2JzPSIsbikpKSkseWxpbT1jKC0uMDAwOSwwLjAxMSkpCmFibGluZSh2PXMwLGx3ZD0yLGNvbD00KQphYmxpbmUodj1ib3lzLGx3ZD0yLGNvbD0yKQphYmxpbmUodj1zRG93bixsd2Q9MSxjb2w9MixsdHk9MikKdGV4dChjKHNEb3duLHMwLGJveXMsYm95cyksYyhyZXAoMC4wMTEsMyksMC4wMSksbGFiZWxzPWMoZXhwcmVzc2lvbihwYXN0ZShzWzBdLWRlbHRhKSksZXhwcmVzc2lvbihzWzBdKSxleHByZXNzaW9uKHM9PXNbMF0rZGVsdGEpLGFzLmV4cHJlc3Npb24oc3Vic3RpdHV0ZShzPT12YWwsbGlzdCh2YWw9Ym95cykpKSkscG9zPTQsY29sPWMoMiw0LDIpKQp0ZXh0KHNEb3duLTUwLC0uMDAwNSxsYWJlbD0icC13YWFyZGUiLGNvbD0yLHBvcz00KQp0ZXh0KHNVcCwtLjAwMDUsbGFiZWw9InAtd2FhcmRlIixjb2w9Mixwb3M9NCkKYXJyb3dzKHMwKzE1MDAuNSwtLjAwMDksc1VwLC0uMDAwOSxjb2w9Mixsd2Q9MixhbmdsZT0yMCxsZW5ndGg9LjEpCmFycm93cyhzMC0xNTAwLjUsLS4wMDA5LHNEb3duLC0uMDAwOSxjb2w9Mixsd2Q9MixhbmdsZT0yMCxsZW5ndGg9LjEpCmBgYAoKLS0tCgpEZSB0ZXN0IGthbiB3b3JkZW4gdWl0Z2V2b2VyZCBhLmQuaC52LiBkZSBgYmlub20udGVzdGAgZnVuY3RpZSBpbiBSLgoKYGBge3J9CmJpbm9tLnRlc3QoeD1ib3lzLG49bixwPXBpMCkKYGBgCgpPcCBoZXQgNSUgc2lnbmlmaWNhbnRpZS1uaXZlYXUgYmVzbHVpdGVuIHdlIGRhdCBlciBnZW1pZGRlbGQgbWVlciBrYW5zIGlzIGRhdCBlZW4gb25nZWJvcmVuIGtpbmQgbWFubmVsaWprIGRhbiB2cm91d2VsaWprIGlzLgoKLSBEZSBCaW5vbWlhbGUgdGVzdCBoZWVmdCBvb2sgZWVuIGV4YWN0IEJJIHdlZXIgb3AgZWVuIHByb3BvcnRpZS4KCi0gSGV0IGV4YWN0ZSBCSSBpcyB0ZSB2ZXJraWV6ZW4gYm92ZW4gaGV0IEJJIGRhdCBnZWJhc2VlcmQgaXMgb3AgZGUgQ0xULgoKLSBWb29yIFNha3Nlbi1zdHVkaWUgbGlndCBCSSBvLmIudi4gQ0xUIGhlZWwgZGljaHQgYmlqIGV4YWN0ZSBCSTogZ3JvdGUgc3RlZWtwcm9lZiAoJG49JCBgciBuYCkuCgotIE1lcmsgb3AgZGF0IGhldCB0ZXN0ZW4gdm9vciBlZW4gcHJvcG9ydGllIGthbiBnZXppZW4gd29yZGVuIGFscyBoZXQgZXF1aXZhbGVudCB2YW4gZWVuIG9uZS1zYW1wbGUgdC10ZXN0IHZvb3IgYmluYWlyZSBkYXRhLgoKLS0tCgojIyBDb25jbHVzaWUKCi0gVm9vciBkZSBTYWtzZW4gcG9wdWxhdGllIGJlc2x1aXRlbiB3ZSBvcCBoZXQgNSUgc2lnbmlmaWNhbnRpZW5pdmVhdSBkYXQgZXIgbWVlciBrYW5zIGlzIGRhdCBlZW4gb25nZWJvcmVuIGtpbmQgbWFubmVsaWprIGRhbiB2cm91d2VsaWprIGlzICgkcD0kIGByIHJvdW5kKGJpbm9tLnRlc3QoeD1ib3lzLG49bixwPXBpMCkkcC52YWx1ZSwzKWApLgpEZSBrYW5zIGRhdCBlZW4gb25nZWJvcmVuIGtpbmQgbWFubmVsaWprIGlzLCBiZWRyYWFndCBgciBmb3JtYXQocGkqMTAwLGRpZ2l0cz0zKWAlICg5NSUgQkkgW2ByIHBhc3RlKGZvcm1hdChiaW5vbS50ZXN0KHg9Ym95cyxuPW4scD1waTApJGNvbmYuaW50KjEwMCxkaWdpdHM9MyksY29sbGFwc2U9IiwgIilgXSUpLgoKLS0tCgojIFRvZXRzIHZvb3IgYXNzb2NpYXRpZSB0dXNzZW4gMiBrd2FsaXRhdGlldmUgdmFyaWFiZWxlbgojIyBHZXBhYXJkZSBnZWdldmVucwoKLSAyIGtlZXIgemVsZmRlIGluZGl2aWR1IG1ldGVuCi0gYmlqdm9vcmJlZWxkLCB2w7PDs3IgZW4gbmEgYmxvb3RzdGVsbGluZyBhYW4gZGUgZXhwZXJpbWVudGVsZSBzdG9mCi0gdGVsa2VucyBkZSBjYXRlZ29yaXNjaGUgdWl0a29tc3QgdGUgb2JzZXJ2ZXJlbi4KLSBIaWVyIGVua2VsOiAqZ2VwYWFyZGUgYmluYWlyZSB1aXRrb21zdGVuKgotIFN0YXRpc3Rpc2NoZSBhbmFseXNlIG1vZXQgcmVrZW5pbmcgaG91ZGVuIG1ldCBkZSBwYXJpbmcuCgotLS0KCiMjIyBWb29yYmVlbGQ6ICBwYXJ0bmVya2V1emUgdmFuIHNla3N1ZWVsIG1hdHVyZSB2cm91d2VsaWprZSAqQ2FtcGJlbGxpKiBkd2VyZ2hhbXN0ZXIgKFJvZ292aW4gZXQgYWwuIDIwMTcpCgpgYGB7ciwgb3V0LndpZHRoPSc3MCUnLCBmaWcuYXNwPTEsIGZpZy5hbGlnbj0nY2VudGVyJyxlY2hvPUZBTFNFfQpsaWJyYXJ5KHBsb3RyaXgpCnBhcihtYXI9YygwLDAsMCwwKSxtYWk9YygwLDAsMCwwKSkKcGxvdCgwLDAsYXhlcz1GQUxTRSx4bGFiPSIiLHlsYWI9IiIsY29sPTAseGxpbT1jKDAsMykseWxpbT1jKDAsMykpCnJlY3QoMCwwLDMsMykKbGluZXMoYygxLDEpLGMoMCwzKSkKbGluZXMoYygyLDIpLGMoMCwzKSkKbGluZXMoYygxLDEpLGMoMSwyKSxsd2Q9MikKbGluZXMoYygxLDEpLGMoMSwyKSxsd2Q9NCkKbGluZXMoYygyLDIpLGMoMSwyKSxsd2Q9NCkKcmVjdCgxLjQ1LDEsMS41NSwxLjMpCmRyYXcuY2lyY2xlKDEuNSwxLjM2LDAuMDUpCmxpbmVzKGMoMS41LDEuNSksYygxLC44NSkpCnRleHQoMS41LDEuMTUsIlxcVkUiLHZmb250PWMoInNhbnMgc2VyaWYiLCJib2xkIiksY2V4PTEuMykKcmVjdCgwLjUsMS4wNSwwLjgsMS4xNSkKZHJhdy5jaXJjbGUoMC44NiwxLjEsMC4wNSkKbGluZXMoYygwLjUsMC4zNSksYygxLjEsMS4xKSkKbGluZXMoYygwLjgsMCksYygxLjEsMS41KSxsdHk9MikKdGV4dCgwLjY1LDEuMSwiXFxNQSIsdmZvbnQ9Yygic2FucyBzZXJpZiIsImJvbGQiKSxjZXg9MS4zKQpyZWN0KDIuNSwxLjk1LDIuMiwxLjg1KQpkcmF3LmNpcmNsZSgyLjE0LDEuOSwwLjA1KQpsaW5lcyhjKDIuNSwyLjY1KSxjKDEuOSwxLjkpKQpsaW5lcyhjKDIuMiwzKSxjKDEuOSwxLjUpLGx0eT0yKQp0ZXh0KDIuMzUsMS45LCJcXE1BIix2Zm9udD1jKCJzYW5zIHNlcmlmIiwiYm9sZCIpLGNleD0xLjMpCmBgYAoKLS0tCgotIE5hIDMgbWludXRlbiwgc2NoZWlkaW5nc3dhbmQgd2VnCi0gYWdncmVzc2llZiB2cyBuaWV0LWFncmVzc2llZiBtYW5uZW50amUKLSBFbGsgdnJvdXd0amUgb25kZXJnaW5nIHR3ZWVtYWFsIGRlIHRlc3Q6IG5hIHZlcmJsaWpmIGluCgogICAgLSB2aWphbmRpZ2Ugb21nZXZpbmcgKGhvZ2UgcG9wdWxhdGllLCB3ZWluaWcgdm9lZHNlbCwgdmVlbCBjb25jdXJyZW50aWUpCiAgICAtIHZyaWVuZGVsaWprZXJlIG9tZ2V2aW5nCgoKYGBge3IgY2F0SGFtc3RlciwgZWNobz1GQUxTRX0KaGFtc3RlciA8LSBtYXRyaXgoYygzLDE3LDEsMTMpLG5jb2w9MixieXJvdz1UUlVFKQpyb3duYW1lcyhoYW1zdGVyKSA8LSBjKCJ2aWphbmRpZy1hZ3Jlc3NpZWYiLCAidmlqYW5kaWctbmlldC1hZ3Jlc3NpZWYiKQpjb2xuYW1lcyhoYW1zdGVyKSA8LSBjKCJ2cmllbmRlbGlqay1hZ3Jlc3NpZWYiLCJ2cmllbmRlbGlqay1uaWV0LWFncmVzc2llZiIpCmhhbXN0ZXJUb3Q9bWF0cml4KDAsbnJvdz0zLG5jb2w9MykKaGFtc3RlclRvdFsxOjIsMToyXT1oYW1zdGVyCmhhbXN0ZXJUb3RbMywxOjJdPWNvbFN1bXMoaGFtc3RlcikKaGFtc3RlclRvdFssM109cm93U3VtcyhoYW1zdGVyVG90WywxOjJdKQpoYW1zdGVyTGV0dGVycz1tYXRyaXgoYygiIChlKSIsIiAoZikiLCIiLCIgKGcpIiwiIChoKSIsIiIsIiIsIiIsIiIpLG5jb2w9MyxieXJvdz1UUlVFKQpoYW1zdGVyVG90PW1hdHJpeChwYXN0ZTAoaGFtc3RlclRvdCxoYW1zdGVyTGV0dGVycyksYnlyb3c9RkFMU0UsbmNvbD0zKQpjb2xuYW1lcyhoYW1zdGVyVG90KTwtYyhjb2xuYW1lcyhoYW1zdGVyKSwidG90YWFsIikKcm93bmFtZXMoaGFtc3RlclRvdCk8LWMocm93bmFtZXMoaGFtc3RlciksInRvdGFhbCIpCmtuaXRyOjprYWJsZShoYW1zdGVyVG90LGNhcHRpb249IktydWlzdGFiZWwgdmFuIHBhcnRuZXJrZXV6ZSBiaWogZHdlcmdoYW1zdGVyLiIsYm9va3RhYnMgPSBUUlVFLCBmb3JtYXQ9Im1hcmtkb3duIikKYGBgCgotLS0KCi0gJFxwaV8yPVBbXHRleHR7YWdyZXNzaWVmIG1hbm5ldGplIH0gXHZlcnQgXHRleHR7IHZlcmJsaWpmIHZpamFuZGlnZSBvbWdldmluZ31dJAotICRcaGF0IFxwaV8yPShlK2YpL24kLCB3YWFyYmlqICRuPWUrZitnK2gkLgoKLSAkXHBpXzE9UFtcdGV4dHthZ3Jlc3NpZWYgbWFubmV0amUgfSBcdmVydCBcdGV4dHsgdmVyYmxpamYgdnJpZW5kZWxpamtlIG9tZ2V2aW5nfV0kCi0gJFxoYXQgXHBpXzE9KGUrZykvbiQKLSBBYnNvbHV1dCByaXNjb3ZlcnNjaGlsIChBUlYpClxiZWdpbntlcXVhdGlvbip9Clx3aWRlaGF0e1x0ZXh0e0FSVn19PVxoYXRccGlfMi1caGF0XHBpXzE9XGZyYWN7ZStmfXtufS1cZnJhY3tlK2d9e259PVxmcmFje2YtZ317bn0KXGVuZHtlcXVhdGlvbip9Ci0gRW5rZWwgYmXDr252bG9lZCBkb29yIGFhbnRhbGxlbiBkaXNjb3JkYW50ZSBwYXJlbiAkZiQgZW4gJGckCgotLS0KCi0gU3RhbmRhYXJkIGVycm9yIG9wIEFSVgpcYmVnaW57ZXF1YXRpb24qfQpcdGV4dHtTRX1fe1x3aWRlaGF0e1x0ZXh0e0FSVn19fT1cZnJhY3sxfXtufVxzcXJ0e2YrZy1cZnJhY3soZi1nKV4yfXtufX0KXGVuZHtlcXVhdGlvbip9CgotIEFscyBlciB2b2xkb2VuZGUgZ2VnZXZlbnMgemlqbiwga2FuIG1lbiBlZW4gJCgxLVxhbHBoYSkxMDBcJSQgQkkgb3AgQVJWCiQkXGxlZnRbXHdpZGVoYXR7XHRleHR7QVJWfX0tel97XGFscGhhLzJ9XHRleHR7U0V9X3tcd2lkZWhhdHtcdGV4dHtBUlZ9fX0sXHdpZGVoYXR7XHRleHR7QVJWfX0tel97XGFscGhhLzJ9XHRleHR7U0V9X3tcd2lkZWhhdHtcdGV4dHtBUlZ9fX1ccmlnaHRdJCQKb2YKJCRcbGVmdFtcZnJhY3tmLWd9e259LVxmcmFje3pfe1xhbHBoYS8yfX17bn1cc3FydHtmK2ctXGZyYWN7KGYtZyleMn17bn19LFxmcmFje2YtZ317bn0rXGZyYWN7el97XGFscGhhLzJ9fXtufVxzcXJ0e2YrZy1cZnJhY3soZi1nKV4yfXtufX1ccmlnaHRdICQkCgotLS0KCmBgYHtyfQpoYW1zdGVyIDwtIG1hdHJpeChjKDMsMTcsMSwxMyksbmNvbD0yLGJ5cm93PVRSVUUpCnJvd25hbWVzKGhhbXN0ZXIpIDwtIGMoInZpamFuZGlnLWFncmVzc2llZiIsICJ2aWphbmRpZy1uaWV0LWFncmVzc2llZiIpCmNvbG5hbWVzKGhhbXN0ZXIpIDwtIGMoInZyaWVuZGVsaWprLWFncmVzc2llZiIsInZyaWVuZGVsaWprLW5pZXQtYWdyZXNzaWVmIikKCmYgPC0gaGFtc3RlclsxLDJdCmcgPC0gaGFtc3RlclsyLDFdCm4gPC0gc3VtKGhhbXN0ZXIpCnJpc2tkaWZmIDwtIChmLWcpL24Kcmlza2RpZmYKc2UgPC0gc3FydChmK2ctKGYtZyleMi9uKS9uCnNlCmJpIDwtIHJpc2tkaWZmICsgYygtMSwxKSpxbm9ybSgwLjk3NSkqc2UKYmkKYGBgCgotLS0KClxiZWdpbntlcXVhdGlvbip9Clx3aWRlaGF0e1x0ZXh0e0FSVn19PVxmcmFjezE3LTF9ezM0fT0wLjQ3MQpcZW5ke2VxdWF0aW9uKn0Kb2YgNDcuMSUuCgotIERlIHN0YW5kYWFyZCBlcnJvcgpcYmVnaW57ZXF1YXRpb24qfQpcdGV4dHtTRX1fe1x3aWRlaGF0e1x0ZXh0e0FSVn19fT1cZnJhY3sxfXszNH1cc3FydHsxNysxLVxmcmFjeygxNy0xKV4yfXszNH19PTAuMDk1MgpcZW5ke2VxdWF0aW9uKn0KCi0gRWVuIDk1XCUgYmV0cm91d2JhYXJoZWlkc2ludGVydmFsIHZvb3IgaGV0IGFic29sdXRlIHJpc2ljb3ZlcnNjaGlsIG9wIGRlIGtldXplIHZhbiBlZW4gYWdyZXNzaWVmIG1hbm5ldGplIHR1c3NlbiBlZW4gdmVyYmxpamYgaW4gZWVuIHZpamFuZGlnZSBlbiB2cmllbmRlbGlqa2Ugb21nZXZpbmcgaXMgYmlqZ2V2b2xnClxiZWdpbntlcXVhdGlvbip9ClxsZWZ0WzAuNDcxLTEuOTZcdGltZXMgMC4wOTUyLDAuNDcxKzEuOTZcdGltZXMgMC4wOTUyXHJpZ2h0XT1bMC4yODQsMC42NThdClxlbmR7ZXF1YXRpb24qfQoKLSBXZSBoZWJiZW4gYmVzbHVpdGVuIGR1cyBkYXQgYWJzb2x1dGUgcmlzaWNvIHZlcnNjaGlsIGluIGhldCBpbnRlcnZhbCBbMjguNCw2NS44XSUgbGlndCBlbiB3ZXRlbiBkYXQgZGVyZ2VsaWprZSBpbnRlcnZhbGxlbiB2b29yIGdyb3RlIHN0ZWVrcHJvZXZlbiBoZXQgd2Vya2VsaWprZSBhYnNvbHV0ZSByaXNjbyB2ZXJzY2hpbCBtZXQgZWVuIGthbnMgdmFuIDk1JSBiZXZhdHRlbi4KCi0gT3AgYmFzaXMgdmFuIGhldCBCSSBiZXNsdWl0ZW4gd2Ugb3AgaGV0IDUlIG5pdmVhdSBkYXQgaGV0IG1lZXIgd2FhcnNjaGlqbmxpamsgaXMgZGF0IHZyb3V3ZWxpamtlIGhhbXN0ZXJzIGVlbiBhZ2dyZXNzaWV2ZSBwYXJ0bmVyIGtpZXplbiBuYWRhdCB6ZSBpbiBlZW4gdmlqYW5kaWdlIG9tZ2V2aW5nIGhlYmJlbiB2ZXJibGV2ZW4gZGFuIHdhbm5lZXIgemUgaW4gZWVuIHZyaWVuZGVsaWprZSBvbWdldmluZyB2ZXJibGV2ZW4uIERlIGthbnMgb3AgZGUga2V1emUgdmFuIGVlbiBhZ3Jlc3NpZWYgbWFubmV0amUgaXMgNDclIGhvZ2VyIG5hZGF0IHplIGluIGVlbiB2aWphbmRpZ2Ugb21nZXZpbmcgaGVlZnQgdmVyYmxldmVuICg5NSUgQkkgMjguNCw2NS44XSUpCgotLS0KCiMjIyBNY05lbWFyIHRlc3QKCmBgYHtyLGVjaG89RkFMU0V9CmtuaXRyOjprYWJsZShoYW1zdGVyVG90LAogIGJvb2t0YWJzID0gVFJVRSwKICBmb3JtYXQ9Im1hcmtkb3duIikKYGBgCgotIFRvZXRzZW4gb2YgZGUgcmlzaWNvJ3MgdmVyc2NoaWxsZW4gdHVzc2VuIGRlIHZpamFuZGlnZSBlbiB2cmllbmRlbGlqa2Ugb21nZXZpbmcuCi0gRW5rZWwgZGUgZGlzY29yZGFudGUgcGFyZW4gbGV2ZXJlbiBoaWVyIGluZm9ybWF0aWUgb3Zlci4KLSAkZj5nJCBpbmRpY2F0aWUgdGVnZW4gJEhfMCQ6IHBhcnRuZXJrZXV6ZSBuaWV0IGdlYXNzb2NpZWVyZCBtZXQgb21nZXZpbmcKLSBLYW5zIGV2YWx1ZXJlbiBkYXQgaW4gZWVuIGx1a3JhYWsgZGlzY29yZGFudCBwYWFyLCB2cm91d3RqZSBuYSB2ZXJibGlqZiBpbiBlZW4gdmlqYW5kaWdlIG9tZ2V2aW5nIGtpZXN0IHZvb3IgaGV0IGFncmVzc2lldmUgbWFubmV0amUuCi0gRGV6ZSBrYW5zIHdvcmR0IGdlc2NoYXQgYWxzCiAgJCRcZnJhY3tmfXtmK2d9JCQKCi0tLQoKICBcYmVnaW57ZXFuYXJyYXkqfQogIFx0ZXh0e0V9XGxlZnRbZi8oZitnKVxyaWdodF0mXHN0YWNrcmVse0hfMH17PX0mIDAuNVxcCiAgZiAmIFxzdGFja3JlbHtIXzB9e1xzaW19JiBcdGV4dHtCaW5vbX0obj1mK2csXHBpPTAuNSlcXAogIFx0ZXh0e1NFfV97XGZyYWN7Zn17ZitnfX0gJiBcc3RhY2tyZWx7SF8wfXs9fSYgXHNxcnR7KGYrZylcdGltZXMgMC41XHRpbWVzIDAuNX09XGZyYWN7XHNxcnR7ZitnfX17Mn0KXGVuZHtlcW5hcnJheSp9CgotLS0KCi0gQXN5bXB0b3Rpc2NoIG9uZS1zYW1wbGUgei10ZXN0IChvLmIudi4gbm9ybWFsZSB2ZXJkZWxpbmcpCgpcYmVnaW57ZXF1YXRpb24qfQp6IDwtIFxmcmFje2YtKGYrZykvMn17XHNxcnR7ZitnfS8yfT1cZnJhY3tmLWd9e1xzcXJ0e2YrZ319ClxlbmR7ZXF1YXRpb24qfQoKLSBEZSBOb3JtYWxlIGJlbmFkZXJpbmcgaXMgZ29lZCBhbHMgJCRmIFx0aW1lcyBnLyhmK2cpIFxnZXEgNSQkCgotIEluIGtsZWluZSBzdGVla3Byb2V2ZW4gaXMgaGV0IG1lZXIgYWFuZ2V3ZXplbiBvbSBlZW4gY29udGludcOvdGVpdHNjb3JyZWN0aWUgdGUgZ2VicnVpa2VuIGQubS52LiBkZSB0b2V0c2luZ3Nncm9vdGhlaWQKXGJlZ2lue2VxdWF0aW9uKn0KXGZyYWN7fGYtZ3wtMX17XHNxcnR7ZitnfX0KXGVuZHtlcXVhdGlvbip9CgpEZSAqKk1jIE5lbWFyIHRlc3QqKiBhbmFsb2dvbiB2YW4gZGUgZ2VwYWFyZGUgdC10ZXN0IHZvb3IgYmluYWlyZSwga3dhbGl0YXRpZXZlIGkucC52LiBjb250aW51ZSB2YXJpYWJlbGVuLgoKLS0tCgpJbiBSICBgbWNuZW1hci50ZXN0YCBmdW5jdGllCmBgYHtyfQptY25lbWFyLnRlc3QoaGFtc3RlcikKYGBgCgoKLSBXZSB2ZXJ3ZXJwZW4gYmlqZ2V2b2xnIGRlIG51bGh5cG90aGVzZSBvcCBoZXQgNSUgc2lnbmlmaWNhbnRpZW5pdmVhdSBlbgotIEJlc2x1aXRlbiBkYXQgZGUgcGFydGVybmtldXplIGV4dHJlZW0gc2lnbmlmaWNhbnQgZ2Vhc3NvY2llZXJkIGlzIG1ldCBkZSBvbWdldmluZy4KCi0gV2UgemllbiBkYXQgaGllciBldmVuZWVucyBkZSBjb250aW51w690ZWl0c2NvcnJlY3RpZSB3ZXJkIHVpdGdldm9lcmQgZW4gZGF0IHdlIGV4YWN0IGRlemVsZmRlIHAtd2FhcmRlIGJla29tZW4uCgotLS0KCi0gTm9ybWFsZSBiZW5hZGVyaW5nIHZhbiBkZXplIHRvZXRzdGF0aXN0aWVrIG5pZXQgaWRlYWFsCmlzIG9tZGF0ICRmIFx0aW1lcyBnLyhmK2cpIDwgNSQuCgotIFN0ZWVkcyBiZXRlcjogYmlub21pYWxlIHRlc3QKCmBgYHtyfQpiaW5vbS50ZXN0KHggPSBmLAogIG4gPSBmICsgZywKICBwID0gMC41KQpgYGAKCi0tLQoKIyMjIENvbmNsdXNpZQoKLSBPcCBiYXNpcyB2YW4gZGUgZXhhY3RlIHRlc3QgYmVzbHVpdGVuIHdlIGV2ZW5lZW5zIGRhdCBkZSBwYXJ0ZXJua2V1emUgZXh0cmVlbSBzaWduaWZpY2FudCBnZWFzc29jaWVlcmQgaXMgbWV0IGRlIG9tZ2V2aW5nICgkcDwwLjAwMSQpLgotIERlIGthbnMgb3AgZGUga2V1emUgdmFuIGVlbiBhZ3Jlc3NpZWYgbWFubmV0amUgbGlndCBgciBmb3JtYXQocmlza2RpZmYqMTAwLGRpZ2l0cz0zKWAlIGhvZ2VyIGFscyBlZW4gZHdlcmdoYW1zdGVyIHZyb3V3dGplIHppY2ggaW4gZWVuIHZpamFuZGlnZSBvbWdldmluZyBiZXZpbmR0IGRhbiB3YW5uZWVyIHplIHppY2ggaW4gZWVuIHZyaWVuZGVsaWprZSBvbWdldmluZyBiZXZpbmR0ICg5NSUgQkkgW2ByIHBhc3RlKGZvcm1hdChiaSoxMDAsZGlnaXRzPTMpLGNvbGxhcHNlPSIsICIpYF0lKS4KCi0tLQoKIyMgT25nZXBhYXJkZSBnZWdldmVucwojIyMgR2VuZXRpc2NoZSBhc3NvY2lhdGllIHN0dWRpZQotIEdlbmV0aXNjaGUgYXNzb2NpYXRpZXN0dWRpZSBwb2x5bW9yZmlzbWVuIGluIGhldCBCUkNBMSBnZW4gZ2Vhc3NvY2llZXJkIGlzIG1ldCBib3JzdGthbmtlcj8KLSBSZXRyb3NwZWN0aWV2ZSBjYXNlLWNvbnRyb2xlIHN0dWRpZSBtZXQgODAwIGJvcnN0a2Fua2VyY2FzZXMgZW4gNTcyIGNvbnRyb2xlcwoKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpicmNhIDwtIHJlYWRfY3N2KCJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vc3RhdE9taWNzL3NiYzIwL21hc3Rlci9kYXRhL2JyY2EuY3N2IikKaGVhZChicmNhKQpzdW1tYXJ5KGJyY2EpCmBgYAoKLS0tCgpgYGB7ciwgdGlkeT1GQUxTRSxlY2hvPUZBTFNFfQpicmNhSGxwPWRhdGEuZnJhbWUoR2Vub3R5cGU9YygiUHJvL1BybyIsIlByby9MZXUiLCJMZXUvTGV1IiwiVG90YWFsIiksQ29udHJvbGVzPWMoIjI2NiAoYSkiLCIyNTAgKGIpIiwiNTYgKGMpIiwiNTcyIChhK2IrYykiKSxDYXNlcz1jKCIzNDIgKGQpIiwiMzY5IChlKSIsIjg5IChmKSIsIjgwMCAoZCtlK2YpIiksVG90YWFsPWMoIjYwOCAoYStkKSIsIjYxOSAoYitlKSIsIjE0NSAoYytmKSIsIjEzNzIgKG4pIikpCmtuaXRyOjprYWJsZShicmNhSGxwLAogIGJvb2t0YWJzID0gVFJVRSwgIAogIGZvcm1hdD0ibWFya2Rvd24iCikKYGBgCgotIEluIGNhc2UtY29udHJvbGUgc3R1ZGllcyBraWVzdCBtZW4gZWVuIHZhc3QgYWFudGFsIGNhc2VzIGVuIGNvbnRyb2xlcyBlbiBzcG9vcnQgbWVuIHZvb3IgaGVuIG9wIHdlbGtlIGJsb290c3RlbGxpbmdlbiB6ZSBpbiBoZXQgdmVybGVkZW4gb25kZXJ2b25kZW4gaGViYmVuLgotIERlcmdlbGlqa2Ugc3R1ZGllcyBub2VtdCBtZW4gb29rIHJldHJvc3BlY3RpZWYKLSBPbm1vZ2VsaWprIG9tIGhldCByaXNpY28ncyBhbmQgcmlzY292ZXJzY2hpbGxlbiBvcCBib3JzdGthbmtlciB0ZSBzY2hhdHRlbjogcHJvcG9ydGllIHZhbiBjYXNlcyBlbiBjb250cm9sZXMgd2VlcnNwaWVnZWx0IHBvcHVsYXRpZSBuaWV0IQoKLS0tCgpgYGB7ciwgdGlkeT1GQUxTRSxlY2hvPUZBTFNFfQpicmNhSGxwIDwtIGRhdGEuZnJhbWUoR2Vub3R5cGU9YygiUHJvL1BybyIsIlByby9MZXUiLCJMZXUvTGV1IiwiVG90YWFsIiksQ29udHJvbGVzPWMoIjI2NiAoYSkiLCIyNTAgKGIpIiwiNTYgKGMpIiwiNTcyIChhK2IrYykiKSxDYXNlcz1jKCIzNDIgKGQpIiwiMzY5IChlKSIsIjg5IChmKSIsIjgwMCAoZCtlK2YpIiksVG90YWFsPWMoIjYwOCAoYStkKSIsIjYxOSAoYitlKSIsIjE0NSAoYytmKSIsIjEzNzIgKG4pIikpCmtuaXRyOjprYWJsZShicmNhSGxwLAogIGJvb2t0YWJzID0gVFJVRSwKICBmb3JtYXQ9Im1hcmtkb3duIgopCmBgYAoKLSBXZWwgbW9nZWxpamsgb20ga2FucyB0ZSBzY2hhdHRlbiBvbSBhbGxlbCBMZXUvTGV1CiAgICAtIGNhc2VzOiAkXHBpXzE9Zi8oZCtlK2YpPTg5LzgwMD0xMS4xXCUkCiAgICAtIGNvbnRyb2xlczokXHBpXzA9Yy8oYStiK2MpPTU2LzU3Mj05LjhcJSQKLSBSZWxhdGllZiByaXNpY28gb3AgYmxvb3RzdGVsbGluZyB2b29yIGNhc2VzIHZlcnN1cwpjb250cm9sZXMgaXMgYmlqZ2V2b2xnICQxMS4xLzkuOD0xLjE0JC4KLSBWcm91d2VuIG1ldCBib3JzdGthbmtlciBoZWJiZW4gZHVzIDE0JSBtZWVyIGthbnMgb20gZGUgYWxsZWxjb21iaW5hdGllIExldS9MZXUgdGUgaGViYmVuIG9wIGhldCBCUkNBMSBnZW4gZGFuIHZyb3V3ZW4gem9uZGVyIGJvcnN0a2Fua2VyLgotIERpdCBzdWdnZXJlZXJ0IGVlbiBhc3NvY2lhdGllLCBtYWFyIGRydWt0IGlldCB1aXQgaG9ldmVlbCBob2dlciBoZXQgcmlzaWNvIG9wIGJvcnN0a2Fua2VyIGlzIHZvb3IgdnJvdXdlbiBtZXQgZGUgYWxsZWxjb21iaW5hdGllIExldS9MZXUgZGFuIHZvb3IgYW5kZXJlIHZyb3V3ZW4KLSBBbmRlcmUgcmlzaWNvbWFhdD8KCi0tLQoKXGJlZ2lue2VxdWF0aW9uKn0KT2Rkcz1cZnJhY3twfXsxLXB9ClxlbmR7ZXF1YXRpb24qfQp3YWFyYmlqICRwJCBkZSBrYW5zIGlzIG9wIGRpZSBnZWJldXJ0ZW5pcy4KClRyYW5zZm9ybWF0aWUgdmFuIGhldCByaXNpY28sIG1ldCB2b2xnZW5kZSBlaWdlbnNjaGFwcGVuOgoKICAtIGRlIG9kZHMgbmVlbXQgd2FhcmRlbiBhYW4gdHVzc2VuIG51bCBlbiBvbmVpbmRpZy4KCiAgLSBkZSBvZGRzIGlzIGdlbGlqayBhYW4gMSBhbHMgZW4gc2xlY2h0cyBhbHMgZGUga2FucyB6ZWxmIGdlbGlqayBpcyBhYW4KMS8yLgoKICAtIGRlIG9kZHMgbmVlbXQgdG9lIGFscyBkZSBrYW5zIHRvZW5lZW10LgoKLSBwb3B1bGFpciBiaWogZ29ra2VyczogaG9ldmVlbCB3YWFyc2NoaWpubGlqa2VyIGhldCBpcyBvbSB0ZSB3aW5uZW4gZGFuIG9tIHRlIHZlcmxpZXplbgoKLS0tCgpgYGB7ciwgdGlkeT1GQUxTRSxlY2hvPUZBTFNFfQpicmNhSGxwPWRhdGEuZnJhbWUoR2Vub3R5cGU9YygiUHJvL1BybyIsIlByby9MZXUiLCJMZXUvTGV1IiwiVG90YWFsIiksQ29udHJvbGVzPWMoIjI2NiAoYSkiLCIyNTAgKGIpIiwiNTYgKGMpIiwiNTcyIChhK2IrYykiKSxDYXNlcz1jKCIzNDIgKGQpIiwiMzY5IChlKSIsIjg5IChmKSIsIjgwMCAoZCtlK2YpIiksVG90YWFsPWMoIjYwOCAoYStkKSIsIjYxOSAoYitlKSIsIjE0NSAoYytmKSIsIjEzNzIgKG4pIikpCmtuaXRyOjprYWJsZShicmNhSGxwLAogIGJvb2t0YWJzID0gVFJVRSwKICBmb3JtYXQ9Im1hcmtkb3duIgopCmBgYAoKT2RkcyBvcCBhbGxlbCBMZXUvTGV1CgotIENhc2VzOiAkXG1ib3h7b2Rkc31fMT1cZnJhY3sgZi8oZCtlK2YpfXsoZCtlKS8oZCtlK2YpfT1mLyhkK2UpPTg5LzcxMT0wLjEyNSQuIFZyb3V3ZW4gbWV0IGJvcnN0a2Fua2VyIGhlYmJlbiBvbmdldmVlciA4IGtlZXIgbWVlciBrYW5zIG9tIGRlIGFsbGVsY29tYmluYXRpZSBMZXUvTGV1IG5pZXQgdGUgaGViYmVuIG9wIGhldCBCUkNBMSBnZW4gZGFuIG9tIGhldCB3ZWwgdGUgaGViYmVuLgotIENvbnRyb2xlczogJFxtYm94e29kZHN9XzI9Yy8oYStiKT01Ni81MTY9MC4xMDkkLgoKLSBBc3NvY2lhdGllIHR1c3NlbiBibG9vdHN0ZWxsaW5nIGVuIHVpdGtvbXN0OgokJApPUl97TGV1L0xldX09XGZyYWN7XG1ib3h7b2Rkc31fVH17XG1ib3h7b2Rkc31fQ309IFxmcmFje2YvKGQrZSl9e2MvKGErYil9PVxmcmFje2YvKGQrZSl9e2MvKGErYil9PTEuMTUKJCQKCi0tLQoKCmBgYHtyLCB0aWR5PUZBTFNFLGVjaG89RkFMU0V9CmJyY2FIbHA9ZGF0YS5mcmFtZShHZW5vdHlwZT1jKCJQcm8vUHJvIiwiUHJvL0xldSIsIkxldS9MZXUiLCJUb3RhYWwiKSxDb250cm9sZXM9YygiMjY2IChhKSIsIjI1MCAoYikiLCI1NiAoYykiLCI1NzIgKGErYitjKSIpLENhc2VzPWMoIjM0MiAoZCkiLCIzNjkgKGUpIiwiODkgKGYpIiwiODAwIChkK2UrZikiKSxUb3RhYWw9YygiNjA4IChhK2QpIiwiNjE5IChiK2UpIiwiMTQ1IChjK2YpIiwiMTM3MiAobikiKSkKa25pdHI6OmthYmxlKGJyY2FIbHAsCiAgYm9va3RhYnMgPSBUUlVFLAogICBmb3JtYXQ9Im1hcmtkb3duIgopCmBgYAoKLSBXYXMgZGUgYm92ZW5zdGFhbmRlIHN0dWRpZSBlY2h0ZXIgZWVuIHZvbGxlZGlnIGx1a3Jha2Ugc3RlZWtwcm9lZiBnZXdlZXN0Cih3YWFyYmlqIGhldCBhYW50YWwgY2FzZXMgZW4gY29udHJvbGVzIG5pZXQgcGVyIGRlc2lnbiB3ZXJkZW4gdmFzdGdlbGVnZCksCi0gZGFuIGtvbmRlbiB3ZSBkYWFyIG9vayBkZSBvZGRzIHJhdGlvIG9wIGJvcnN0a2Fua2VyIGJlcmVrZW5lbiB2b29yIG1lbnNlbgptZXQgdmVyc3VzIHpvbmRlciBoZXQgYWxsZWwgTGV1L2xldS4KXGJlZ2lue2VxdWF0aW9uKn0KT1Jfe2Nhc2V9PVxmcmFjeyBcZnJhY3sgZn17Y319eyBcZnJhY3soZCtlKX17KGErYil9fSA9IFxmcmFje2YoYStiKX17YyhkK2UpfT1PUl97TGV1L0xldX09MS4xNSwKXGVuZHtlcXVhdGlvbip9Ci0gT1IgaXMgZWVuIHN5bW1ldHJpc2NoZSBtYWF0ISBPUiBvcCBib3JzdGthbmtlciBrYW4gd2VsIHdvcmRlbiBnZXNjaGF0IQotIERlIG9kZHMgb3AgYm9yc3RrYW5rZXIgaXMgYmlqZ2V2b2xnIDE1JSBob2dlciBiaWogdnJvdXdlbiBtZXQgZGllIHNwZWNpZmlla2UgYWxsZWxjb21iaW5hdGllLgoKLS0tCgotIElzIHZlcnNjaGlsIGdyb290IGdlbm9lZyB6b2RhdCB3ZSBoZXQgZWZmZWN0IGRpZSB3ZSBpbiBkZSBzdGVla3Byb2VmIHppZW4ga3VubmVuIHZlcmFsZ2VtZW5lbiBuYWFyIGRlIHBvcHVsYXRpZSB0b2UuCgotIEhpZXJ0b2UgenVsbGVuIHdlIGRlIGtydWlzdGFiZWwgZWVyc3QgaGVyc2NocmlqdmVuIHRvdCBlZW4gMngyIHRhYmVsCgpgYGB7ciBsZXU0LCB0aWR5PUZBTFNFLGVjaG89RkFMU0V9CmJyY2FUYWIyIDwtIHRhYmxlKGJyY2EkdmFyaWFudDIsYnJjYSRjYW5jZXIpCmJyY2FIbHAyPWRhdGEuZnJhbWUoR2Vub3R5cGU9YygiYW5kZXJlIiwiTGV1L0xldSIsIlRvdGFhbCIpLENvbnRyb2xlcz1jKCI1MTYgKGEpIiwiNTYgKGIpIiwiNTcyIChhK2IpIiksQ2FzZXM9YygiNzExIChjKSIsIjg5IChkKSIsIjgwMCAoYytkKSIpLFRvdGFhbD1jKCIxMjI3IChhK2MpIiwiMTQ1IChiK2QpIiwiMTM3MiAobikiKSkKa25pdHI6OmthYmxlKGJyY2FIbHAyLAogIGJvb2t0YWJzID0gVFJVRSwgIAogIGZvcm1hdD0ibWFya2Rvd24iCikKYGBgCgotLS0KCiMjIERlIFBlYXJzb24gQ2hpLWt3YWRyYWF0IHRlc3Qgdm9vciBvbmdlcGFhcmRlIGdlZ2V2ZW5zCgotIFRlc3RlbiB2b29yIGFzc29jaWF0aWUgdHVzc2VuIGRlIGNhdGVnb3Jpc2NoZSBibG9vdHN0ZWxsaW5nIChidmIuIHZhcmlhbnQsIFgpIGVuIGRlIGNhdGVnb3Jpc2NoZSB1aXRrb21zdCAoYnZiLiB6aWVrdGUsIFkpLgokJEhfMDogXHRleHR7RXIgaXMgZ2VlbiBhc3NvY2lhdGllIHR1c3NlbiB9IFggXHRleHR7IGVuIH0gWSBcdGV4dHsgdnMgfSBIXzE6IFggXHRleHR7IGVuIH0gWSBcdGV4dHsgemlqbiBnZWFzc29jaWVlcmR9JCQKCi0gQmVzY2hvdXcgZGUgcmlqdG90YWxlbiAkbl9cdGV4dHthbmRlcmV9PWErYyQsICRuX1x0ZXh0e2xldSxsZXV9PWIrZCQgZW5lcnppamRzIGVuCi0gZGUga29sb210b3RhbGVuICRuX1x0ZXh0e2NvbnRyfT1hK2IkIGVuICRuX1x0ZXh0e2Nhc2V9PWMrZCQgYW5kZXJ6aWpkcy4KLSBaaWogdmVyc3RyZWtrZW4gaW5mb3JtYXRpZSBvdmVyIGRlICptYXJnaW5hbGUgdmVyZGVsaW5nKiB2YW4gZGUgYmxvb3RzdGVsbGluZyAoYnZiLiB2YXJpYW50LCBYKSBlbiBkZSB1aXRrb21zdCAoYnZiLiB6aWVrdGUsIFkpLAptYWFyIG5pZXQgb3ZlciBkZSBhc3NvY2lhdGllIHR1c3NlbiBkaWUgdmVyYW5kZXJsaWprZW4uCi0gT25kZXIgJEhfMCQgemlqbiAkWCQgZW4gJFkkIG9uYWZoYW5rZWxpamsgemlqbiBlbiB2ZXJ3YWNodCBtZW4gZWVuIHByb3BvcnRpZSAkKGIrZCkvbiQKdmFuICRhK2IkIGNvbnRyb2xlcyBtZXQgZWVuIExldS9MZXUgdmFyaWFudCwgb2YgZGF0ICQoYStiKShiK2QpL24kIGVlbiBMZXUvTGV1IHZhcmlhbnQgaGViYmVuCi0gQW5hbG9vZyBrYW4gbWVuIHZlcndhY2h0ZSBhYW50YWwgJEVfe2lqfSQgYmVyZWtlbmVuIGRhdCBvbmRlciBkZSBudWxoeXBvdGhlc2UgaW4gKmVsa2UgY2VsKiB2YW4gZGUgJDJcdGltZXMgMiQgdGFiZWwgem91IGxpZ2dlbi4KCi0tLQoKLSAkRV97MTF9JCA9IGhldCB2ZXJ3YWNodGUgYWFudGFsIG9uZGVyICRIXzAkIGluIGRlICgxLDEpLWNlbCA9IGByIHN1bShicmNhVGFiMlsxLF0pYCAkXHRpbWVzJCBgciBzdW0oYnJjYVRhYjJbLDFdKWAvYHIgc3VtKGJyY2FUYWIyKWAgPSBgciBmb3JtYXQoc3VtKGJyY2FUYWIyWzEsXSkqc3VtKGJyY2FUYWIyWywxXSkvc3VtKGJyY2FUYWIyKSxkaWdpdHM9NClgIDsKCi0gJEVfezEyfSQgPSBoZXQgdmVyd2FjaHRlIGFhbnRhbCBvbmRlciAkSF8wJCBpbiBkZSAoMSwyKS1jZWwgPSBgciBzdW0oYnJjYVRhYjJbMSxdKWAgJFx0aW1lcyQgYHIgc3VtKGJyY2FUYWIyWywyXSlgL2ByIHN1bShicmNhVGFiMilgID0gYHIgZm9ybWF0KHN1bShicmNhVGFiMlsxLF0pKnN1bShicmNhVGFiMlssMl0pL3N1bShicmNhVGFiMiksZGlnaXRzPTQpYCA7CgotICRFX3syMX0kID0gaGV0IHZlcndhY2h0ZSBhYW50YWwgb25kZXIgJEhfMCQgaW4gZGUgKDIsMSktY2VsID0gYHIgc3VtKGJyY2FUYWIyWzIsXSlgICRcdGltZXMkIGByIHN1bShicmNhVGFiMlssMV0pYC9gciBzdW0oYnJjYVRhYjIpYCA9IGByIGZvcm1hdChzdW0oYnJjYVRhYjJbMixdKSpzdW0oYnJjYVRhYjJbLDFdKS9zdW0oYnJjYVRhYjIpLGRpZ2l0cz00KWAgOwoKLSAkRV97MjJ9JCA9IGhldCB2ZXJ3YWNodGUgYWFudGFsIG9uZGVyICRIXzAkIGluIGRlICgyLDIpLWNlbCA9IGByIHN1bShicmNhVGFiMlsyLF0pYCAkXHRpbWVzJCBgciBzdW0oYnJjYVRhYjJbLDJdKWAvYHIgc3VtKGJyY2FUYWIyKWAgPSBgciBmb3JtYXQoc3VtKGJyY2FUYWIyWzIsXSkqc3VtKGJyY2FUYWIyWywyXSkvc3VtKGJyY2FUYWIyKSxkaWdpdHM9NClgIDsKClRvZXRzc3RhdGlzdGllazoKXGJlZ2lue2VxbmFycmF5Kn0KWF4yICY9JiBcZnJhY3tcbGVmdCAofE9fezExfSAtIEVfezExfXwgLSAuNSBccmlnaHQpXjIgfXsgRV97MTF9fSArIFxmcmFjewpcbGVmdCAoIHxPX3sxMn0gLSBFX3sxMn18IC0gLjUgXHJpZ2h0KV4yIH17RV97MTJ9IH0rIFxcCiYmXHF1YWRccXVhZApcZnJhY3sgXGxlZnQgKCB8T197MjF9Ci0gRV97MjF9fCAtIC41IFxyaWdodCleMiB9e0VfezIxfX0rIFxmcmFjeyBcbGVmdCAoIHxPX3syMn0gLSBFX3syMn18IC0gLjUKXHJpZ2h0KV4yIH17RV97MjJ9IH1cXAogWF4yICZcc3RhY2tyZWx7SF8wfXtcbG9uZ3JpZ2h0YXJyb3d9JiBcY2hpXjIoZGY9MSkKXGVuZHtlcW5hcnJheSp9CgotLS0KCmBgYHtyLCBvdXQud2lkdGg9JzEwMCUnLCBmaWcuYXNwPS44LCBmaWcuYWxpZ249J2NlbnRlcicsZWNobz1GQUxTRX0KZ3JpZD1zZXEoMCwxMCwuMSkKcGxvdChncmlkLGRjaGlzcShncmlkLDEpLHR5cGU9ImwiLGx3ZD0yKQpkZnM9YygxLDIsNSkKZm9yIChpIGluIDI6MykKCWxpbmVzKGdyaWQsZGNoaXNxKGdyaWQsZGZzW2ldKSxjb2w9aSxsd2Q9MikKbGVnZW5kKCJ0b3ByaWdodCIsbHR5PTEsbHdkPTIsY29sPTE6MyxsZWdlbmQ9c2FwcGx5KGRmcywgZnVuY3Rpb24oZCkgYXMuZXhwcmVzc2lvbihzdWJzdGl0dXRlKGNoaVtkZj09dmFsXV4yLGxpc3QodmFsPWQpKSkpKQpgYGAKCi0tLQoKLSBUb2V0c2luZ3Nncm9vdGhlaWQgIGdyb290ICRcbG9uZ3JpZ2h0YXJyb3ckIGluZGljYXRpZSB2b29yCmFmd2lqa2luZyB2YW4gJEhfMCQuCi0gRGUgcC13YWFyZGUgdm9vciBlZW4gMi16aWpkaWdlIHRvZXRzIGlzCmthbnMgb20gZ3JvdGVyZSB3YWFyZGUgdm9vciB0b2V0c2luZ3Nncm9vdGhlaWQgdGUgb2JzZXJ2ZXJlbiBkYW4KZ2VvYnNlcnZlZXJkZSB3YWFyZGUgJHheMiQgYWxzIG51bGh5cG90aGVzZSB3YWFyIGlzICRcbG9uZ3JpZ2h0YXJyb3ckIGthbnMgZGF0ICRcY2hpXjJfMSQtdmVyZGVlbGRlIHRvZXZhbHN2ZXJhbmRlcmxpamtlIHdhYXJkZW4gZ3JvdGVyIGRhbiAkeF4yJAphYW5uZWVtdC4KCi0tLQoKYGBge3J9CmV4cGVjdGVkIDwtIG1hdHJpeCgwLG5yb3c9MixuY29sPTIpCmZvciAoaSBpbiAxOjIpCglmb3IgKGogaW4gMToyKQoJCWV4cGVjdGVkW2ksal0gPC0KCQkJc3VtKGJyY2FUYWIyW2ksXSkqc3VtKGJyY2FUYWIyWyxqXSkvc3VtKGJyY2FUYWIyKQpleHBlY3RlZAp4MiA8LSBzdW0oKGFicyhicmNhVGFiMi1leHBlY3RlZCkgLSAuNSleMi9leHBlY3RlZCkKMS1wY2hpc3EoeDIsMSkKYGBgCgotLS0KCi0gT21kYXQgb2JzZXJ2YXRpZXMgJE9fe2lqfSQgZGlzY3JldGUgZ2V0YWxsZW4gemlqbiwga2FuCnRvZXRzaW5nc2dyb290aGVpZCAkWF4yJCBzbGVjaHRzIGRpc2NyZXRlIHdhYXJkZW4gYWFubmVtZW4gZW4ga2FuCmNvbnRpbnVlIHZlcmRlbGluZyB6b2FscyAkXGNoaV4yXzEkLXZlcmRlbGluZyBzbGVjaHRzIGVlbiBiZW5hZGVyaW5nIHppam4uCi0gKmNvbnRpbnXDr3RlaXRzY29ycmVjdGllKjogMC41IGFmdHJla2tlbiB2YW4gdmVyd2FjaHRlIGFhbnRhbGxlbiBpbiBlbGtlIGNlbCAkXGxvbmdyaWdodGFycm93JCBvbSBiZXRlciBhYW4gdGUgbGF0ZW4gc2x1aXRlbiBiaWogJFxjaGleMl8xJC12ZXJkZWxpbmcKLSAqUGVhcnNvbgpDaGkta3dhZHJhYXQgdG9ldHMgbWV0IFlhdGVzIGNvcnJlY3RpZSouCi0gV2FubmVlciBkZSBjb3JyZWN0aWUgbmlldCBnZWJydWlrdAp3b3JkdCAoZC53LnouIHdhbm5lZXIgZGUgZ2V0YWxsZW4gYDAuNScgaW4gZGUgdWl0ZHJ1a2tpbmcgdm9vciAkWF4yJCBkb29yIDAKdmVydmFuZ2VuIHdvcmRlbiksIGRhbiBzcHJlZWt0IG1lbiB2YW4gZGUgKlBlYXJzb24gQ2hpLWt3YWRyYWF0IHRvZXRzKi4KCi0tLQoKSW4gUiBrYW4gamUgZGV6ZSB0b2V0c2VuIHVpdHZvZXJlbiBkb29yIGRlIG9wdGllIFx0ZXh0dHR7Y29ycmVjdH0gb3AgVFJVRSBvZiBGQUxTRSB0ZSB6ZXR0ZW46CgpgYGB7cn0KY2hpc3EudGVzdChicmNhVGFiMikKY2hpc3EudGVzdChicmNhVGFiMiwgY29ycmVjdD1GQUxTRSkKYGBgCgotLS0KCi0gWmVsZnMgbWV0IGNvbnRpbnXDr3RlaXRzY29ycmVjdGllIGlzICRcY2hpXjJfMSQgYmVuYWRlcmluZyBzbGVjaHRzCnZlcmFudHdvb3JkIGFscyBpbiBnZWVuIGVua2VsZSB2YW4gZGUgY2VsbGVuIGhldCB2ZXJ3YWNodGUgYWFudGFsIG9uZGVyCiRIXzAkIGtsZWluZXIgaXMgZGFuIDUuCi0gV2FubmVlciBkZSAkXGNoaV4yJC1iZW5hZGVyaW5nIG5pZXQgdmVyYW50d29vcmQgaXMsIGthbiBtZW4gZWVuICAqRmlzaGVyJ3MgZXhhY3QgdGVzdCogdWl0dm9lcmVuLgotICBEZSBudWxoeXBvdGhlc2UgdmFuIGRlemUgdGVzdCBpcyBldmVuZWVucyBkYXQgJFgkIGVuICRZJCBvbmFmaGFua2VsaWprIHppam4sIGVuIGRlIGFsdGVybmF0aWV2ZSBoeXBvdGhlc2UgZGF0ICRYJCBlbiAkWSQKYWZoYW5rZWxpamsgemlqbi4KCmBgYHtyfQpmaXNoZXIudGVzdChicmNhVGFiMikKYGBgCgotLS0KCgojIyMgVWl0YnJlaWRpbmcgbmFhciBjYXRlZ29yaXNjaGUgdmFyaWFiZWxlbiBtZXQgbWVlcmRlcmUgbml2ZWF1cwoKLSAkXGNoaV4yJC10b2V0cyBrYW4gb29rIGFscyBtaW5zdGVucyAxIHZhbiBkZSBkaXNjcmV0ZSB2YXJpYWJlbGVuICRYJCBlbiAkWSQgbWVlciBkYW4gMiBtb2dlbGlqa2Ugd2FhcmRlbiBhYW5uZWVtdAoKLSBPcG5pZXV3OiBudWxoeXBvdGhlc2UgJEhfMDogWCQgZW4gJFkkIHppam4gb25hZmhhbmtlbGlqayAobmlldC1nZWFzc29jaWVlcmQpLCB0ZW4gb3B6aWNodGUgdmFuIGhldCB0d2VlemlqZGlnIGFsdGVybmF0aWVmICRIX0E6IFgkIGVuICRZJAp6aWpuIG5pZXQgb25hZmhhbmtlbGlqayAoZ2Vhc3NvY2llZXJkKS4KCi0gQWxzIGRlIHZhcmlhYmVsZSB2b29yZ2VzdGVsZCBvcCBkZSByaWplbiAkciQgbW9nZWxpamtlIHVpdGtvbXN0ZW4gaGVlZnQgZW4gZGllIG9wIGRlIGtvbG9tbWVuICRjJCBtb2dlbGlqa2UgdWl0a29tc3RlbiwKZGFuIG5vZW10IG1lbiBkZSBrcnVpc3RhYmVsIGRpZSAkWCQgdGVnZW5vdmVyICRZJCB1aXR6ZXQsIGVlbiAkciBcdGltZXMgYyQgdGFiZWwuCgotIFpvYWxzIHZvb3JoZWVuIHZlcmdlbGlqa3QgbWVuIGhldCBhYW50YWwgZ2VvYnNlcnZlZXJkZSB3YWFyZGVuIGluIGNlbCAkKGksaikkLCAkT197aWp9JCBnZW5vdGVlcmQsIG1ldCBoZXQgYWFudGFsIHZlcndhY2h0ZSB3YWFyZGVuIG9uZGVyIGRlIG51bGh5cG90aGVzZSwgJEVfe2lqfSQKIC1PcG5pZXV3IGlzICRFX3tpan0kIHByb2R1Y3QgdmFuIGhldCAkaSQtZGUgcmlqdG90YWFsIG1ldCBoZXQgJGokLWRlCmtvbG9tdG90YWFsIGdlZGVlbGQgZG9vciBoZXQgYWxnZW1lbmUgdG90YWFsLgoKXGJlZ2lue2VxdWF0aW9uKn0KWF4yID0gXHN1bV97aWp9IFxmcmFje1xsZWZ0IChPX3tpan0gLSBFX3tpan1ccmlnaHQpXjIgfXsgRV97aWp9fQpcZW5ke2VxdWF0aW9uKn0KCi0tLQoKLSBNZW4ga2FuIGFhbnRvbmVuIGRhdCB6ZSBlZW4gQ2hpLWt3YWRyYWF0IHZlcmRlbGluZyB2b2xndCBtZXQgJChyLTEpIFx0aW1lcwooYy0xKSQgdnJpamhlaWRzZ3JhZGVuIGFscyBkZSBudWxoeXBvdGhlc2Ugd2FhciBpcy4KLSBEZSBjb250aW51w690ZWl0c2NvcnJlY3RpZSB3b3JkdCBtZWVzdGFsIG5pZXQgZ2VicnVpa3QgYmlqIG1lZXIgZGFuIDIgcmlqZW4gb2YKa29sb21tZW4uCi0gKipQZWFyc29uICRcY2hpXjIkIHRlc3QqKiBpcyBhbmFsb2dvbiB2YW4gZGUgb25lLXdheSB2YXJpYW50aWUtYW5hbHlzZSB2b29yIGt3YWxpdGF0aWV2ZSBpLnAudi4gY29udGludWUgdmFyaWFiZWxlbi4KCi0tLQoKCmBgYHtyfQpicmNhVGFiIDwtIHRhYmxlKGJyY2EkdmFyaWFudCxicmNhJGNhbmNlcikKY2hpc3EudGVzdChicmNhVGFiKQpgYGAKCi0gT20gdGUgb25kZXJ6b2VrZW4gb2YgaGV0IEJSQ0ExIGdlbiBnZWFzc29jaWVlcmQgaXMgbWV0IGJvcnN0a2Fua2VyLCBiZXJla2VuZW4gd2UgZGUgUGVhcnNvbiBjaGkta3dhZHJhYXQgdG9ldHMgdm9vciBkZSBjYXNlLWNvbnRyb2xlIHN0dWRpZS4KLSBEZSB0b2V0c2luZ3Nncm9vdGhlaWQgYmVkcmFhZ3QgbnUgYHIgZm9ybWF0KGNoaXNxLnRlc3QoYnJjYVRhYikkc3RhdGlzdGljLGRpZ2l0cz00KWAgZW4gdm9sZ3QgZWVuIENoaS1rd2FkcmFhdCB2ZXJkZWxpbmcgbWV0IGByIGNoaXNxLnRlc3QoYnJjYVRhYikkcGFyYW1ldGVyYCB2cmlqaGVpZHNncmFkZW4uIERlIGthbnMgZGF0IHpv4oCZbiAkXGNoaV4yJC0gdmVyZGVlbGRlIHRvZXZhbHN2ZXJhbmRlcmxpamtlIGV4dHJlbWVyIGlzIGRhbiBgciBmb3JtYXQoY2hpc3EudGVzdChicmNhVGFiKSRzdGF0aXN0aWMsZGlnaXRzPTQpYCwgYmVkcmFhZ3QgYHIgZm9ybWF0KGNoaXNxLnRlc3QoYnJjYVRhYikkcC52YWx1ZSoxMDAsZGlnaXRzPTIpYCUuCi0gT3AgaGV0IDUlIHNpZ25pZmljYW50aWVuaXZlYXUga3VubmVuIHdlIGR1cyBuaWV0IGJlc2x1aXRlbiBkYXQgaGV0IEJSQ0ExIGdlbiBnZWFzc29jaWVlcmQgaXMgbWV0IGJvcnN0a2Fua2VyLgoKLS0tCgojIExvZ2lzdGlzY2hlIHJlZ3Jlc3NpZQoKLSBSYWFtd2VyayB2b29yIGhldCBtb2RlbGxlcmVuIHZhbiBiaW5haXJlIGRhdGEgKHZiLiBrYW5rZXIgdnMgZ2VlbiBrYW5rZXIpOiAqbG9naXN0aXNjaGUgcmVncmVzc2llLW1vZGVsbGVuKi4KLSBCaW5haXJlIGdlZ2V2ZW5zIG1vZGVsbGVyZW4gYS5kLmgudi4gY29udGludWUgZW4vb2YgZHVtbXkgdmFyaWFiZWxlbi4KCi0gRGUgbW9kZWxsZW4gdmVyb25kZXJzdGVsbGVuIGRhdCBvYnNlcnZhdGllcyB2b29yIHN1YmplY3QgJGk9MSxcbGRvdHMsbiQgb25hZmhhbmtlbGlqayB6aWpuIGVuIGVlbiBCZXJub3VsbGkgdmVyZGVsaW5nIHZvbGdlbi4KLSBIZXQgbG9nYXJpdG1lIHZhbiBkZSBvZGRzIHdvcmR0IGRhbiBnZW1vZGVsbGVlcmQgZC5tLnYuIGVlbiBsaW5lYWlyIG1vZGVsLCBvb2sgd2VsIGxpbmVhaXJlIHByZWRpY3RvciBnZW5vZW1kOgpcYmVnaW57ZXF1YXRpb259ClxsZWZ0XHsKXGJlZ2lue2FycmF5fXtjY2x9CllfaSZcc2ltJkIoXHBpX2kpXFxcXApFW1lfaV0gJj0mIFxwaV9pXFxcXApcbG9nIFxmcmFje1xwaV9pfXsxLVxwaV9pfSY9JlxiZXRhXzAgKyBcYmV0YV8xWF97aTF9ICsgXGxkb3RzICsgXGJldGFfcCBYX3tpcH0KXGVuZHthcnJheX1ccmlnaHQuClxlbmR7ZXF1YXRpb259CgotLS0KCiMjIENhdGVnb3Jpc2NoZSBwcmVkaWN0b3IKCi0gQm9yc3RrYW5rZXIgdm9vcmJlZWxkOiBpcyBCUkNBIDEgdmFyaWFudCBnZWFzc29jaWVlcmQgaXMgbWV0IGhldCBrcmlqZ2VuIHZhbiBib3JzdGthbmtlci4KCi0gTmV0IHpvYWxzIGluIGRlIGFub3ZhIGNvbnRleHQsIGZhY3RvciBpbiBoZXQgcmVncmVzc2llcmFhbXdlcmsgZC5tLnYuIGR1bW15IHZhcmlhYmVsZW4uCi0gMSBkdW1teSB2YXJpYWJsZSBtaW5kZXIgbm9kaWcgaGViYmVuIGRhbiBlciBncm9lcGVuIHppam4uCgotIFZvb3IgaGV0IEJSQ0EgMSB2b29yYmVlbGQgemlqbiBkdXMgdHdlZSBkdW1teSB2YXJpYWJlbGVuIG5vZGlnIGVuIGt1bm5lbiB3ZSBkZSBkYXRhIGR1cyBtb2RlbGxlcmVuIG1ldCBvbmRlcnN0YWFuZGUgbGluZWFpcmUgcHJlZGljdG9yOgoKXGJlZ2lue2VxbmFycmF5Kn0KICBcbG9nIFxmcmFje1xwaV9pfXsxLVxwaV9pfSAmPSYgXGJldGFfMCtcYmV0YV8xIHhfe2kxfSArXGJldGFfMiB4X3tpMn0KXGVuZHtlcW5hcnJheSp9CgotLS0KCi0gV2FhcmJpaiBkZSBwcmVkaWN0b3JlbiBkdW1teS12YXJpYWJlbGVuIHppam46CiQkeF97aTF9ID0gXGxlZnRceyBcYmVnaW57YXJyYXl9e2xsfQoxICYgXHRleHR7IGFscyBzdWJqZWN0ICRpJCBoZXRlcm96eWdvb3QgaXMsIFByby9MZXUgdmFyaWFudH0gXFwKMCAmIFx0ZXh0eyBhbHMgc3ViamVjdCAkaSQgaG9tb3p5Z29vdCBpcywgKFByby9Qcm8gb2YgTGV1L0xldSB2YXJpYW50KX0gXGVuZHthcnJheX1ccmlnaHQuIC4kJAokJHhfe2kyfSA9IFxsZWZ0XHsgXGJlZ2lue2FycmF5fXtsbH0KMSAmIFx0ZXh0eyBhbHMgc3ViamVjdCAkaSQgaG9tb3p5Z29vdCBpcyBpbiBkZSBMZXVjaW5lIG11dGF0aWU6IExldS9MZXUgfSBcXAowICYgXHRleHR7IGFscyBzdWJqZWN0ICRpJCBuaWV0IGhvbW96eWdvb3QgaXMgaW4gZGUgTGV1L0xldSB2YXJpYW50fSBcZW5ke2FycmF5fVxyaWdodC4gLiQkCgotIEhvbW96eWdvc2l0ZWl0IGluIGhldCB3aWxkIHR5cGUgYWxsZWwgUHJvL1BybyB3b3JkdCB2b29yICBkaXQgbW9kZWwgZGUgKipyZWZlcmVudGllZ3JvZXAqKi4KCi0tLQoKCldlIGZpdHRlbiBoZXQgbW9kZWwgaW4gUi4KCi0gTWVyayBvcCBkYXQgd2UgZnVuY3RpZSBgYXMuZmFjdG9yYCBnZWJydWlrZW4gb20gZGUgY2FuY2VyIHZhcmlhYmVsZSBvbSB0ZSB6ZXR0ZW4gbmFhciBlZW4gZmFjdG9yLgotIGVuIGRhdCB3ZSBkZSBmdW5jdGllIGByZWxldmVsYCBnZWJydWlrZW4gb20gZGUgY29udHJvbGVzIGFscyByZWZlcmVudGllIGdyb2VwIGRlIGRlZmluacOrcmVuOiBlZXJzdGUgbml2ZWF1IHZhbiBkZSBmYWN0b3IuCgpgYGB7cn0KYnJjYSA8LSBicmNhICU+JQogIG11dGF0ZSgKICAgIGNhbmNlciA9IGNhbmNlciAlPiUKICAgICAgYXMuZmFjdG9yICU+JQogICAgICByZWxldmVsKCJjb250cm9sIiksCiAgICB2YXJpYW50ID0gdmFyaWFudCAlPiUKICAgICAgYXMuZmFjdG9yICU+JQogICAgICByZWxldmVsKCJwcm8vcHJvIikKICApCgpicmNhTG9naXQgPC0gZ2xtKAogIGNhbmNlciB+IHZhcmlhbnQsCiAgZGF0YSA9IGJyY2EsCiAgZmFtaWx5ID0gYmlub21pYWwpCgpzdW1tYXJ5KGJyY2FMb2dpdCkKYGBgCgoKSGV0IGludGVyY2VwdCBpcyBkZSBsb2ctb2RkcyBvcCBrYW5rZXIgaW4gZGUgcmVmZXJlbnRpZWtsYXNzZSAoUHJvL1BybykgZW4gZGUgaGVsbGluZ3N0ZXJtZW4gemlqbiBsb2cgb2RkcyByYXRpbydzIHR1c3NlbiBkZSBiZWhhbmRlbGluZyBlbiBkZSByZWZlcmVudGlla2xhc3NlOgpcYmVnaW57ZXFuYXJyYXkqfQpcbG9nIFx0ZXh0e09ERFN9X1x0ZXh0e1Byby9Qcm99Jj0mXGJldGFfMFxcXFwKXGxvZyBcdGV4dHtPRERTfV9cdGV4dHtQcm8vTGV1fSY9JlxiZXRhXzArXGJldGFfMVxcXFwKXGxvZyBcdGV4dHtPRERTfV9cdGV4dHtMZXUvTGV1fSY9JlxiZXRhXzArXGJldGFfMlxcXFwKXGxvZyAgXGZyYWN7XHRleHR7T0REU31fXHRleHR7UHJvL0xldX19e1x0ZXh0e09ERFN9X1x0ZXh0e1Byby9Qcm99fSY9Jlxsb2cgXHRleHR7T0REU31fXHRleHR7UHJvL0xldX0tXGxvZyBPRERTX3tQcm8vUHJvfVxcCiY9JlxiZXRhXzArXGJldGFfMS1cYmV0YV8wPVxiZXRhXzFcXFxcClxsb2cgIFxmcmFje1x0ZXh0e09ERFN9X1x0ZXh0e0xldS9MZXV9fXtcdGV4dHtPRERTfV9cdGV4dHtQcm8vUHJvfX0mPSZcYmV0YV8yClxlbmR7ZXFuYXJyYXkqfQoKLSBEZSBhbmFseXNlIGxhYXQgZHVzIHRvZSBvbSBkZSByZXN1bHRhdGVuIG9ubWlkZGVsbGlqayB0ZSBpbnRlcnByZXRlcmVuIGluIHRlcm1lbiB2YW4gT2RkcydlcyBlbiBPZGRzLXJhdGlvJ3MhCgotLS0KCmBgYHtyfQphbm92YShicmNhTG9naXQsIHRlc3QgPSAiQ2hpc3EiKQpgYGAKCkRlICRcY2hpXjIkLXRlc3Qgb3AgaGV0IGxvZ2lzdGlzY2hlIHJlZ3Jlc3NpZW1vZGVsIGdlZWZ0IGV2ZW5lZW5zIGFhbiBkYXQgZXIgZ2VlbiBzaWduaWZpY2FudGUgYXNzb2NpYXRpZSBpcyB0dXNzZW4gZGUgdWl0a29tc3QgKHZvb3Jrb21lbiB2YW4ga2Fua2VyKSBlbiBkZSBmYWN0b3IgKCBkZSBnZW5ldGlzY2hlIHZhcmlhbnQgdmFuIGhldCBCUkNBIGdlbikgKCRwPSQgYHIgZm9ybWF0KGFub3ZhKGJyY2FMb2dpdCx0ZXN0PSJDaGlzcSIpWzIsIlByKD5DaGkpIl0sZGlnaXRzPTMpYCkuCkRlIHAtd2FhcmRlIGlzIGJpam5hIGVxdWl2YWxlbnQgYWFuIGRlIHAtd2FhcmRlIHZhbiBkZSAkXGNoaV4yJC10ZXN0IHVpdCBkZSB2b3JpZ2Ugc2VjdGllLgoKLS0tCgotIFNpZ25pZmljYW50ZSBhc3NvY2lhdGllPyBQb3N0LWhvYyB0ZXN0cyBvbSB0ZSBldmFsdWVyZW4gd2Vsa2Ugb2RkcyByYXRpbydzIHZlcnNjaGlsbGVuZCB6aWpuLgotIFZvb3IgaGV0IEJSQ0ExIHZvb3JiZWVsZCB6b3VkZW4gd2UgdWl0ZXJhYXJkIGdlZW4gcG9zdC1ob2MgdGVzdGVuCi0gVG9jaCBpbGx1c3RyYXRpZSB6b2RhdCBqdWxsaWUgb3ZlciBkZSBjb2RlIGJlc2NoaWtrZW4KCgotLS0KCmBgYHtyfQpzdXBwcmVzc1BhY2thZ2VTdGFydHVwTWVzc2FnZXMoe2xpYnJhcnkobXVsdGNvbXApfSkKcG9zdGhvYyA8LSBnbGh0KGJyY2FMb2dpdCwgbGluZmN0ID0gbWNwKHZhcmlhbnQgPSAiVHVrZXkiKSkKcG9zdGhvY1Rlc3RzIDwtIHN1bW1hcnkocG9zdGhvYykKcG9zdGhvY1Rlc3RzCmBgYAoKLS0tCgpgYGB7cn0KcG9zdGhvY0JJIDwtIGNvbmZpbnQocG9zdGhvYykKcG9zdGhvY0JJCmBgYAotIERvb3IgbWlkZGVsIHZhbiBkZSBgY29uZmludGAgZnVuY3RpZSB3b3JkZW4gQkkncyB2ZXJrcmVnZW4gb3AgZGUgbG9nLW9kZHMgcmF0aW9zIGRpZSBnZWNvcnJpZ2VlcmQgemlqbiB2b29yIG11bHRpcGxlIHRlc3RpbmcuCgotLS0KCi0gQkkncyBrdW5uZW4gYWxzIHZvbGd0IHdvcmRlbiB0ZXJ1Z2dldHJhbnNmb3JtZWVyZCBuYWFyIG9kZHMgcmF0aW9zOgoKYGBge3J9Ck9SIDwtIGV4cChwb3N0aG9jQkkkY29uZmludCkKT1IKYGBgCgotIERlIG9kZHMgcmF0aW9zIGRpZSB3b3JkZW4gYmVrb21lbiBtZXQgaGV0IGxvZ2lzdGlzY2ggcmVncmVzc2llbW9kZWwgemlqbiBleGFjdCBnZWxpamsgYWFuIGRlIG9kZHMgcmF0aW9zIGRpZSB3ZSB6b3VkZW4gYmVrb21lbiBvcCBiYXNpcyB2YW4gVGFiZWw6Ci0gdmIuICAkXHRleHR7T1J9X1x0ZXh0e0xldS9MZXUtUHJvL1Byb309ODlcdGltZXMgMjY2Lyg1Nlx0aW1lcyAzNDIpPSQgYHIgZm9ybWF0KCg4OS81NikvKDM0Mi8yNjYpLGRpZ2l0cz00KWAuCgotIE1lcmsgb3AgZGF0IGRlIHN0YXRpc3Rpc2NoZSBiZXNsdWl0dm9ybWluZyBiaWogbG9naXN0aXNjaGUgbW9kZWxsZW4gYmVyb2VwIGRvZXQgb3AgYXN5bXB0b3Rpc2NoZSB0aGVvcmllLgoKLS0tCgojIyBDb250aW51ZSBwcmVkaWN0b3IKCi0gVG94aWNvbG9naXNjaCBlZmZlY3QgdmFuIGtvb2xzdG9mZGlzdWxmaWRlIChDUyRfMiQpIG9wIGtldmVycy4KCi0gRGUgY2VudHJhbGUgb25kZXJ6b2Vrc3ZyYWFnIGlzIG9mIGRlIGNvbmNlbnRyYXRpZSB2YW4gQ1MkXzIkIGVlbiBlZmZlY3QgaGVlZnQgb3AgZGUgbW9ydGFsaXRlaXQgKGkuZS4ga2FucyBvcCBzdGVydmVuKSB2YW4gZGUga2V2ZXJzPwoKKipEZXNpZ24qKgoKLSAzMiBvbmFmaGFua2VsaWprIGV4cGVyaW1lbnRlbgotIFRlbGtlbnMgMSBrZXZlciBibG9vdGdlc3RlbGQgYWFuIMOpw6luIHZhbiA4IGNvbmNlbnRyYXRpZXMgKG1nL2wpIHZhbiBDUyRfMiQgdm9vciBlZW4gZ2VnZXZlbiBwZXJpb2RlLgotIERlIHVpdGtvbXN0IHZhbiBoZXQgZXhwZXJpbWVudCBpczogZGUga2V2ZXIgc3RlcmZ0ICgkeT0xJCkgb2YgZGUga2V2ZXIgb3ZlcmxlZWZ0ICgkeT0wJCkuCgpgYGB7cn0KYmVldGxlcyA8LSByZWFkX2NzdigiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL3N0YXRvbWljcy9zYmMyMC9tYXN0ZXIvZGF0YS9iZWV0bGVzLmNzdiIpCmhlYWQoYmVldGxlcykKdGFibGUoYmVldGxlcyRkb3NlLCBiZWV0bGVzJHN0YXR1cykKYGBgCgotLS0KCkxvZ2lzdGlzY2ggcmVncmVzc2llbW9kZWwgZGF0IGxvZyBvZGRzIG1vZGVsbGVlcnQgaW4gZnVuY3RpZSB2YW4gZG9zaXMgJHhfaSQ6CiQkXGxvZyBcZnJhY3tccGlfaX17MS1ccGlfaX09XGJldGFfMCtcYmV0YV8xIFx0aW1lcyB4X2kuJCQKCmBgYHtyfQpiZWV0bGVNb2RlbDwtZ2xtKAogIHN0YXR1c35kb3NlLAogIGRhdGEgPSBiZWV0bGVzLAogIGZhbWlseSA9IGJpbm9taWFsKQoKc3VtbWFyeShiZWV0bGVNb2RlbCkKYGBgCgotLS0tCgotIEludGVyY2VwdDogbG9nIG9kZHMgb3AgbW9ydGFsaXRlaXQgd2FubmVlciBlciBnZWVuICRcdGV4dHtDU31fMiQgZ2FzIHdvcmR0IHRvZWdlZGllbmQuCi0gRXJnIGxhZ2Ugb2RkcyBvcCBzdGVyZnRlICgkXHBpLygxLVxwaSk9XGV4cCgtNTMuMikkKSBlbiBkdXMgb3AgZWVuIGthbnMgZGllIG5hZ2Vub2VnIG51bCBpcy4KLSBNZXJrIG9wOiBoZWVsIHN0ZXJrZSBleHRyYXBvbGF0aWU6IG1pbmltdW0gZG9zaXMgaW4gZGUgZGF0YXNldCBgciBtaW4oYmVldGxlcyRkb3NlKWAgbWcvbC4KCgotIEdlc2NoYXR0ZSBvZGRzIHJhdGlvIHZvb3IgZG9zaXMgZWZmZWN0IG9wIGRlIG1vcnRhbGl0ZWl0c2thbnMgaXMgJFxleHAoMC4zMDEzKT0xLjM1JC4KLSBEdXMgYmlqIGVlbiB0b2VuYW1lIHZhbiBkZSBkb3NpcyBDUyRfMiQgbWV0IDEgbWcvbCwgaXMgZGUgb2RkcyByYXRpbyB2b29yIGRlIG1vcnRhbGl0ZWl0ICQxLjM1JC4KCi0tLQoKLSBXZSBiZXNsdWl0ZW4gZGF0IGRpdCBlZmZlY3QgaGVlbCBzaWduaWZpY2FudCBpcyAoJHA9JCBgciByb3VuZChzdW1tYXJ5KGJlZXRsZU1vZGVsKSRjb2VmWzIsNF0sMylgKS4KLSBFZW4gdG9lbmFtZSBpbiBkZSBDUyRfMiQgIGRvc2lzIGRvZXQgZGUga2FucyBvcCBzdGVydmVuIHRvZW5lbWVuLgoKCmBgYHtyfQoKYmVldGxlc1RhYjwtdGFibGUoYmVldGxlcykgJT4lIGRhdGEuZnJhbWUKCmRhdGEuZnJhbWUoCiAgICBncmlkID0gc2VxKAogICAgICBtaW4oYmVldGxlcyRkb3NlKSwKICAgICAgbWF4KGJlZXRsZXMkZG9zZSksLjEpCiAgKSAlPiUKICBtdXRhdGUocGlIYXQgPSBwcmVkaWN0KGJlZXRsZU1vZGVsLAoJICAgICAgbmV3ZGF0YSA9IGRhdGEuZnJhbWUoZG9zZT1ncmlkKSwKCSAgICAgIHR5cGUgPSAicmVzcG9uc2UiKQogICkgJT4lCiAgZ2dwbG90KGFlcyhncmlkLCBwaUhhdCkpKwogIGdlb21fbGluZSgpICsKICB4bGFiKCJkb3NlIikgKwogIHlsYWIoInByb2JhYmlsaXR5IChkZWFkKSIpICsKICBnZW9tX3RleHQoCiAgICBhZXMoeCA9IGRvc2UgJT4lCiAgICAgICAgICBhcy5jaGFyYWN0ZXIgJT4lCiAgICAgICAgICBhcy5kb3VibGUsCiAgICAgICAgeSA9IHN0YXR1cyAlPiUKICAgICAgICAgIGFzLmNoYXJhY3RlciAlPiUKICAgICAgICAgIGFzLmRvdWJsZSwKICAgICAgICBsYWJlbCA9IEZyZXEpLAogICAgYmVldGxlc1RhYiAlPiUKICAgICAgZmlsdGVyKHN0YXR1cz09MCkKICApICsKICBnZW9tX3RleHQoCiAgICBhZXMoeCA9IGRvc2UgJT4lCiAgICAgICAgICBhcy5jaGFyYWN0ZXIgJT4lCiAgICAgICAgICBhcy5kb3VibGUsCiAgICAgICAgeSA9IHN0YXR1cyAlPiUKICAgICAgICAgIGFzLmNoYXJhY3RlciAlPiUKICAgICAgICAgIGFzLmRvdWJsZSwKICAgICAgIGxhYmVsPUZyZXEpLAogICBiZWV0bGVzVGFiICU+JQogICAgZmlsdGVyKHN0YXR1cz09MSkKICApCmBgYAoKCi0tLQoKIyBbSG9tZV0oaHR0cHM6Ly9zdGF0b21pY3MuZ2l0aHViLmlvL3NiYzIwLykgey19Cg==