1 Inleiding

Vorige hoofdstukken: parametrische methoden

  • Inferentie enkel correct als voldaan aan param. veronderstellingen:

    • distributionele veronderstellingen: v.b. Normaal verdeelde gegevens.
    • gelijkheid van varianties (two-sample \(t\)-test en ANOVA)
  • De \(p\)-waarde: \(\text{P}_0\left[ \vert T\vert \geq \vert t \vert \right]\).

    • Berekend o.b.v. nuldistributie van \(T\) die afgeleid is van verdeling van observaties
    • Fout als niet voldaan is aan veronderstellingen
  • \(95\%\) BI steunt eveneens op veronderstellingen. Niet voldaan: geen garantie dat intervallen populatie parameterwaarde omvatten met \(95\%\) kans.


  • Asymptotische theorie moeilijker te plaatsen: je kan stellen dat \(t\)-test asymptotisch niet-parametrisch is omdat bij erg grote steekproefgroottes de distributionele veronderstelling van normaliteit niet meer belangrijk is.

  • Parametrische aanpak:

    • efficiënter: grotere power bij zelfde steekproefgrootte + smallere BI
    • meer flexibel: makkelijker inzetbaar voor experimenten met meer complexe designs

2 Vergelijken van twee groepen

2.1 Cholestorol voorbeeld

  • Cholestorolconcentratie in bloed
    • 5 patiënten (groep=1) die twee dagen geleden een hartaanval deden
    • bij 5 gezonde personen (groep=2).
  • Cholestorolconcentratie verschillend bij hartpatiënten en gezonde personen?
chol <- read_tsv("https://raw.githubusercontent.com/statOmics/sbc20/master/data/chol.txt")

chol <- chol %>%
  mutate(group = as.factor(group))

nGroups <- chol %>%
  pull(group) %>%
  table

n <- nGroups %>%
  sum
chol
# A tibble: 10 x 2
   group cholest
   <fct>   <dbl>
 1 1         244
 2 1         206
 3 1         242
 4 1         278
 5 1         236
 6 2         188
 7 2         212
 8 2         186
 9 2         198
10 2         160

  • Mogelijks outliers
  • Moeilijk om inzicht te krijgen in verdeling: maar 5 observaties per groep

2.2 Permutatie-testen

Vraagstelling Cholestorol voorbeeld vertaling naar nulhypothese. Klassiek: \[H_0: \mu_1=\mu_2 \text{ versus } H_1: \mu_1\neq \mu_2.\]

  • Groep 1: Hartpatiënten
  • Groep 2: Gezonde individuen
  • Testen van deze hypotheses d.m.v. two-sample \(t\)-test.

We gaan de voorwaarden na:

  • Normaliteit?
  • Gelijkheid van variantie?
  • Te weinig observaties per groep.
  • We kunnen veronderstellingen niet nagaan!
  • Gevaarlijk!
  • Oplossing: permutatietesten

2.2.1 Hypothesen

  • \(Y_{1j}\) en \(Y_{2j}\) uitkomsten uit respectievelijk groep 1 en 2: \[Y_{1j} \text{ iid } N(\mu_1,\sigma^2) \;\;\;\text{ en }\;\;\; Y_{2j} \text{ iid } N(\mu_2,\sigma^2).\]

  • Onder \(H_0:\mu_1=\mu_2\), wordt dit (stel \(\mu=\mu_1=\mu_2\) onder \(H_0\)) \[ Y_{ij} \text{ iid } N(\mu,\sigma^2),\]

  • Drukt uit dat alle \(n=n_1+n_2\) uitkomsten uit zelfde normale distributie komen en onafhankelijk zijn

  • Laat toe om oorspronkelijke nulhypothese anders te schrijven: \[H_0: f_1(y) = f_2(y) \text{ voor alle } y \] met

    • \(f_1\) en \(f_2\) de verdeling van uitkomsten
    • Bijkomende veronderstelling dat \(f_1\) en \(f_2\) normale verdelingen zijn.

Onder de alternatieve hypothese wordt een locatie-shift verondersteld: \[H_1: f_1(y)=f_2(y-\Delta) \;\;\;\text{ voor alle } y\] met

  • \(\Delta=\mu_1-\mu_2\)
  • en \(f_1\) en \(f_2\) normale verdelingen met dezelfde variantie.

We illustreren dit in R voor \(f_1\sim N(0,1)\) en \(f_2\sim N(1,1)\) en \(\Delta=-1\).

mu1 <- 0; mu2 <- 1; sigma1 <- sigma2 <- 1
y <- -2:2
delta <- mu1-mu2; delta
[1] -1
rbind(dnorm(y,mu1,sigma1), dnorm(y-delta,mu2,sigma2))
           [,1]      [,2]      [,3]      [,4]       [,5]
[1,] 0.05399097 0.2419707 0.3989423 0.2419707 0.05399097
[2,] 0.05399097 0.2419707 0.3989423 0.2419707 0.05399097

De permutatietesten die we ontwikkelen kunnen gebruikt worden voor het testen van \[ H_0: F_1=F_2 \;\;\;\text{ of }\;\;\; H_0:f_1=f_2. \] maar zonder de Normaliteitsveronderstellingen.

We weten dat onder \(H_0\) geldt dat :

  • Verdeling van de cholestorolconcentraties gelijk voor hartpatiënten en gezonde personen
  • Groep-labels van de 10 personen niet informatief
  • Groepering gebruikt om originele teststatistiek te bepalen is onder de nulhypothese een van de vele groeperingen die allemaal even zinvol/even weinig zinvol zijn.
  • Elke groepering zou immers dezelfde uitkomsten hebben gegenereerd aangezien er geen effect is van de behandeling.
  • Bereken nulldistributie door permuteren van de groepslabels!

2.2.2 Verdeling van de statistiek onder \(H_0\)

  • \(m=\binom{n_1+n_2}{n_1}=\binom{n}{n_1}=\binom{n}{n_2}\) mogelijke unique permutaties \(\cal{G}\) van de groepslabels.
  • In ons voorbeeld \(m=\) 252.
  • Als \(m\) niet te groot is kunnen alle unieke permutaties van de groepslabels berekend worden.
  • Vervolgens wordt voor iedere unique permutatie \(g \in \cal{G}\) de teststatistiek \(t^*_g\) berekend
  • Hier de t-test statistiek door de originele uitkomsten te gebruiken die nu gekoppeld worden aan de gepermuteerde groepslabels \(G_g^*\).

We kunnen alle m=252 permutaties in R genereren a.d.h.v. de functie combn(n,n_1). Dit wordt geïllustreerd in de onderstaande R code:

  • G bevat volgnummers van de observaties uit groep 1 voor elke permutatie d
  • We tonen enkel de eerste 10 permutaties.
G <- combn(n,nGroups[1])
dim(G)
[1]   5 252
G[,1:10]
     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
[1,]    1    1    1    1    1    1    1    1    1     1
[2,]    2    2    2    2    2    2    2    2    2     2
[3,]    3    3    3    3    3    3    3    3    3     3
[4,]    4    4    4    4    4    4    5    5    5     5
[5,]    5    6    7    8    9   10    6    7    8     9

We berekenen nu de teststatistiek voor elke permutatie

tOrig <- t.test(cholest ~ group, chol)$statistic
tOrig
       t 
3.664425 
tStar <- combn(
  n,
  nGroups[1],
    function(g,y) {
    t.test(y[g],y[-g])$statistic
    },
  y = chol %>% pull(cholest)
  )
head(tStar)
[1] 3.6644253 1.6397911 2.3973923 1.5876250 1.9217173 0.9967105
length(tStar)
[1] 252

  • We kunnen nu de verdeling van de teststatistiek onder \(H_0\) bestuderen.
  • Originele statistiek (rode verticale lijn) is extreem


2.2.3 p-waarde

  • Permutatienuldistributie \(\longrightarrow\) hypothesetesten uitvoeren.

  • tweezijdige permutatie \(p\)-waarde \[p=\text{P}_0\left[\vert T\vert \geq \vert t\vert \mid \mathbf{y}\right].\]

  • p-waarde geconditioneerd op geobserveerde cholestorolwaarden \(\mathbf{y}=(y_{11},\ldots,y_{51},y_{12},\ldots,y_{52})^T\).

  • Gezien permutatienuldistrubutie van \(T\) bepaald wordt door \(t^*_g\), \(g \in{\cal{G}}\), berekenen we \[p = \frac{\#\{g\in {\cal{G}}: \vert t^*_g\vert \geq \vert t \vert \}}{m}\]

pval <- mean(abs(tStar)>=abs(tOrig))
pval
[1] 0.01587302

  • Op het \(5\%\) significantieniveau besluiten we dat de distributies van de cholestorol concentraties niet gelijk zijn bij hartpatiënten en bij gezonde personen. (\(p=\) 0.0159).

  • De \(p\)-waarde op basis van alle permutaties wordt een exacte \(p\)-waarde genoemd.

  • De permutatienuldistributie wordt een exacte nuldistributie genoemd.

  • De term exact betekent dat de resultaten correct zijn voor iedere steekproefgrootte \(n\).

  • De kans op een type I fout wordt dus gecontroleerd door een permutatietest, maar wel conditioneel op de geobserveerde uitkomsten data \(\mathbf{y}\).

  • We kunnen ons nu afvragen of we de conclusies kunnen veralgemenen naar de populatie toe? Het antwoord is ja, als de subjecten at random getrokken zijn uit de populatie.

  • Het bewijs hiervan valt buiten het bestek van de cursus.


  • Soms probleem omdat het aantal permutaties \(m=\#{\cal{G}}\) erg groot is

    • \(\binom{20}{10}=\) 184756
    • \(\binom{30}{15}=\) 1.55e+08
    • \(\binom{40}{20}=\) 1.38e+11.
  • Daarom niet alle \(g \in {\cal{G}}\) te beschouwen, maar groot aantal random permutaties uitvoeren (b.v. 10000)

  • Ter illustratie staat de code hiervan ook in de cursus.


2.2.4 Hoe kunnen we conclusie interpreteren

  • We permuteren immers t statistiek, effectgrootte locatie-shift

  • Als locatie-shift model niet opgaat is een significant resultaat moeilijk te interpreteren, tegenover welk alternatief testen we dan???

  • Locatie-shift kan niet worden nagegaan in kleine steekproeven…


2.3 Rank Testen

  • Belangrijkste groep van niet-parametrische testen
  • Populariteit:
    • Niet-parametrisch,
    • Exacte \(p\)-waarden d.m.v.permutatienuldistributie.
    • Geen nood aan aparte permutatienuldistributie voor iedere nieuwe dataset.
    • Permutatienuldistributie van rank testen hangt alleen af van steekproefgroottes.
    • Erg robust zijn tegen uitschieters (Engels: outliers)
    • Nuttig als locatie-shift model niet opgaat.

2.3.1 Ranks

Rank testen starten vanuit rank-getransformeerde uitkomsten.

  • Beschouw \(Y_1, \ldots, Y_n\).
  • Afwezigheid van twee gelijke observaties (i.e. geen ties). \[R_i=R(Y_i) = \#\{Y_j: Y_j\leq Y_i; j=1,\ldots, n\}\]
  • Kleinste observatie krijgt dus rank 1, de tweede kleinste rank 2, enzovoort, en de grootste observatie, tenslotte, krijgt rank \(n\).
chol %>%
  pull(cholest)
 [1] 244 206 242 278 236 188 212 186 198 160
chol %>%
  pull(cholest) %>%
  rank
 [1]  9  5  8 10  7  3  6  2  4  1

Soms komen ties voor in de data, i.e. minstens twee observaties hebben dezelfde numerieke waarde. Een klein voorbeeld:

metTies <- c(403, 507, 507, 610, 651, 651, 651, 830, 900)
metTies %>% rank
[1] 1.0 2.5 2.5 4.0 6.0 6.0 6.0 8.0 9.0
  • Ties: 507 komt tweemaal voor, 651 komt driemaal voor. Dit zijn voorbeelden van ties.

  • Wanneer ties voorkomen, worden midranks gebruikt.

  • midrank van observatie \(Y_i\) wordt \[\begin{eqnarray*} R_i &=& \frac{ \#\{Y_j: Y_j\leq Y_i\} + ( \#\{Y_j: Y_j < Y_i\} +1)}{2}. \end{eqnarray*}\]


  • Dikwijls ranks nodig in de gepoolde steekproef
  • Bijvoorbeeld: \(Y_{ij}\), \(i=1,\ldots, n_j\) en \(j=1,2\).
  • Uitkomsten kunnen worden voorgesteld door \(Z_1,\ldots, Z_n\) (\(n=n_1+n_2\)), de uitkomsten uit de gepoolde steekproef.
t(chol)
        [,1]  [,2]  [,3]  [,4]  [,5]  [,6]  [,7]  [,8]  [,9]  [,10]
group   "1"   "1"   "1"   "1"   "1"   "2"   "2"   "2"   "2"   "2"  
cholest "244" "206" "242" "278" "236" "188" "212" "186" "198" "160"
z <- chol %>%
  pull(cholest)
z
 [1] 244 206 242 278 236 188 212 186 198 160
rank(z)
 [1]  9  5  8 10  7  3  6  2  4  1

2.3.2 Wilcoxon-Mann-Whitney Test

  • Gelijktijdig ontwikkeld door Wilcoxon en door Mann en Whitney
  • Wilcoxon-Mann-Whitney, Wilcoxon rank sum test of Mann-Whitney U test
  • \(H_0: f_1=f_2\) vs \(H_1: \mu_1\neq \mu_2\) (of de eenzijdige versies).
  • Eerst locatie-shift model veronderstellen later relaxeren we aanname.

  • Klassieke t-test: verschil in steekproefgemiddelden \(\bar{Y}_1-\bar{Y}_2\).
  • Hier: verschil in steekgroepgemiddelde op basis van rank-getransformeerde uitkomsten.
  • Ranks op basis van gepoolde sample (na samenvoegen van uitkomsten uit groep 1 en groep 2)

  • \(R_{ij}=R(Y_{ij})\) is de rank van uitkomst \(Y_{ij}\) in de gepoolde steekproef. \[ T = \frac{1}{n_1}\sum_{i=1}^{n_1} R(Y_{i1}) - \frac{1}{n_2}\sum_{i=1}^{n_2} R(Y_{i2}) . \]

  • Onder \(H_0\) verwachten we dat gemiddelde rank in de eerste groep ongeveer gelijk is aan de gemiddelde rank in de tweede groep en \(T\) dicht bij nul.

  • Als \(H_1\) waar is dan verwachten we dat gemiddelde ranks verschillen en dus dat \(T\) niet dicht bij nul zal liggen.

  • Eigenlijk voldoende om enkel \[S_1=\sum_{i=1}^{n_1} R(Y_{i1})\].

  • \(S_1\) is som van de ranks van observaties uit groep 1 vandaar de naam rank sum test.

  • Want \[ S_1+S_2 = \text{som van alle ranks} = 1+2+\cdots + n=\frac{1}{2}n(n+1). \]


  • \(S_1\) (of \(S_2\)) een goede teststatistiek
  • Permutatietestmethode toegepassen om exacte permutatienuldistributie te bekomen
  • Voor een gegeven steekproefgrootte \(n\), en veronderstellend dat er geen ties zijn, zijn rank-getransformeerde uitkomsten altijd \[1, 2, \ldots, n\]
  • Voor gegeven groepsgroottes \(n_1\) en \(n_2\), zal de permutatienuldistributie dan ook steeds dezelfde zijn!
  • Tot 1980 werd dit als een groot voordeel beschouwd omdat de nuldistributies voor gegeven \(n_1\) en \(n_2\) getabuleerd konden worden
  • Door rekencapaciteit speelt dit argument niet meer, wel andere belangrijke redenen.

  • Vaak wordt gestandaardiseerde teststatistiek gebruikt \[ T = \frac{S_1-\text{E}_{0}\left[S_1\right]}{\sqrt{\text{Var}_{0}\left[S_1\right]}}, \]

  • met \(\text{E}_{0}\left[S_1\right]\) en \(\text{Var}_{0}\left[S_1\right]\) de verwachtingswaarde en variantie van \(S_1\) onder \(H_0\).

  • Dit zijn dus het gemiddelde en variantie van de permutatienuldistributie van \(S_1\).

  • Onder \(H_0\) geldt \[ \text{E}_{0}\left[S_1\right]= \frac{1}{2}n_1(n+1) \;\;\;\;\text{ en }\;\;\;\; \text{Var}_{0}\left[S_1\right]=\frac{1}{12}n_1n_2(n+1). \]

  • Verder kan men onder \(H_0\) en als \(\min(n_1,n_2)\rightarrow \infty\) opgaat aantonen dat, \[ T = \frac{S_1-\text{E}_{0}\left[S_1\right]}{\sqrt{\text{Var}_{0}\left[S_1\right]}} \rightarrow N(0,1). \]

  • Asymptotisch volgt gestandaardiseerde teststatistiek een standaardnormaal verdeling!


We illustreren de WMW test aan de hand van de R functie wilcox.test.

wilcox.test(cholest ~ group, data = chol)

    Wilcoxon rank sum exact test

data:  cholest by group
W = 24, p-value = 0.01587
alternative hypothesis: true location shift is not equal to 0
  • We verwerpen \(H_0\) (\(p=\) 0.016 \(<0.05\))

  • De output geeft de teststatistiek \(W=\) 24?

  • In volgende lijnen berekenen we \(S_1\) en \(S_2\) manueel voor de dataset.

S1 <- chol %>%
  mutate(cholRank=rank(cholest)) %>%
  filter(group==1) %>%
  pull(cholRank) %>%
  sum

S2 <- chol %>%
  mutate(cholRank = rank(cholest)) %>%
  filter(group == 2) %>%
  pull(cholRank) %>%
  sum

S1
[1] 39
S2
[1] 16

Waar komt \(W=\) 24 vandaan?

2.3.3 Mann and Whitney test

  • Mann en Whitney test in afwezigheid van ties: \[ U_1 = \sum_{i=1}^{n_1}\sum_{k=1}^{n_2} \text{I}\left\{Y_{i1}\geq Y_{k2}\right\}. \]

  • \(\text{I}\left\{.\right\}\): indicator is 1 is als uitdrukking waar is en 0 als dit niet het geval is.

  • U telt hoeveel keer observatie uit groep 1 \(\geq\) observatie uit groep 2.

y1 <- chol %>%
  filter(group==1) %>%
  pull("cholest")

y2 <- chol %>%
  filter(group==2) %>%
  pull("cholest")

u1Hlp <- sapply(
  y1,
  function(y1i,y2) {y1i>=y2},
  y2=y2)

colnames(u1Hlp) <- y1
rownames(u1Hlp) <- y2

u1Hlp
     244   206  242  278  236
188 TRUE  TRUE TRUE TRUE TRUE
212 TRUE FALSE TRUE TRUE TRUE
186 TRUE  TRUE TRUE TRUE TRUE
198 TRUE  TRUE TRUE TRUE TRUE
160 TRUE  TRUE TRUE TRUE TRUE
U1 <- sum(u1Hlp)
U1
[1] 24

Er kan worden aangetoond dat

\[U_1 = S_1 - \frac{1}{2}n_1(n_1+1).\]

S1-nGroups[1]*(nGroups[1]+1)/2
 1 
24 

  1. \(U_1\) en \(S_1\) zelfde informatie
  2. \(U_1\) ook rankstatistiek
  3. Exacte testen gebaseerd op \(U_1\) en \(S_1\) zijn equivalent.

  • \(U_1\) heeft interpretatievoordeel

  • Stel \(Y_j\) een willekeurige uitkomst uit behandelingsgroep \(j\) (\(j=1,2\)). Dan geldt \[\begin{eqnarray*} \frac{1}{n_1n_2}\text{E}\left[U_1\right] &=& \text{P}\left[Y_1 \geq Y_2\right]. \end{eqnarray*}\]

  • Intuïtief voelen we dit aan:

    • Op basis van steekproef kunnen we kans: gemiddelde van alle indicator waarden \(\text{I}\left\{Y_{i1}\geq Y_{k2}\right\}\).

    • \(n_1 \times n_2\) vergelijkingen


mean(u1Hlp)
[1] 0.96
U1/(nGroups[1]*nGroups[2])
   1 
0.96 

\[\text{P}\left[Y_1 \geq Y_2\right]\] wordt een probabilistische index (Engels: probabilistic index) genoemd.

  • Kans dat een uitkomst uit groep1 \(\geq\) dan uitkomst uit groep 2

  • Onder \(H_0\): \[\text{P}\left[Y_1 \geq Y_2\right]=\frac{1}{2}\]


  • R functie wilcox.test geeft niet de Wilcoxon rank sum statistiek, maar wel de Mann-Whitney statistiek \(U_1\).
  • We bekijken nogmaals de output
wTest <- wilcox.test(cholest~group, data = chol)
wTest

    Wilcoxon rank sum exact test

data:  cholest by group
W = 24, p-value = 0.01587
alternative hypothesis: true location shift is not equal to 0
U1
[1] 24
probInd <- wTest$statistic/prod(nGroups)
probInd
   W 
0.96 

  • Aangezien \(p=\) 0.0159 \(<0.05\) besluiten we op het \(5\%\) significantieniveau dat de gemiddelde cholestorolconcentratie groter is bij hartpatiënten kort na een hartaanval dan bij gezonde personen. (We nemen aan dat locatie-shift opgaat)

  • We weten ook dat een cholestorolwaarde van hartpatiënten met een kans van \(U1/(n_1\times n_2)=\) 96% groter is die van gezonde personen.

  • We zouden de veronderstelling van de locatie-shift moeten nagaan, maar met slechts 5 observaties in elke behandelingsgroep is dit zinloos.


  • Zonder locatie-shift veronderstelling blijft de conclusie in termen van de probabilistische index correct!

  • Dus wanneer we geen locatie-shift veronderstellen en een tweezijdige test uitvoeren testen we eigenlijk

\[H_0: F_1=F_2 \text{ vs P}(Y_1 \geq Y_2) \neq 0.5.\]

Conclusie: Er is een significant verschil in de distributie van de cholestorolconcentraties bij hartpatiënten 2 dagen na hun hartaanval en gezonde individuen (\(p=\) 0.0159). Het is meer waarschijnlijk om een hogere cholestorolconcentraties te observeren hartpatiënten dan bij gezonde individuen. De puntschatting voor deze kans bedraagt 96%.


3 Vergelijken van \(g\) Behandelingen

  • Veralgemenen naar niet-parametrische tegenhangers van de \(F\)-test uit een one-way ANOVA.

3.1 DMH Voorbeeld

1,2-dimethylhydrazine dihydrochloride (DMH) testen op genotoxiciteit (EU directive)

  • 24 ratten

  • Vier groepen volgens dagelijkse DMH dosis

    • controle
    • laag
    • medium
    • hoog
  • Genotoxiciteit in de lever a.d.h.v. een comet assay op 150 levercellen per rat.

  • De onderzoekers wensen na te gaan of verschillen zijn in de DNA schade tengevolge van de DMH dosis.


Comet Assay:

  • DNA strengbreuken visualiseren
  • Lengte comet staart is proxy voor strengbreuken.

Comet assay


dna <- read_delim("https://raw.githubusercontent.com/statOmics/sbc20/master/data/dna.txt",delim=" ")
dna <- dna %>%
  mutate(dose = as.factor(dna$dose))
dna
# A tibble: 24 x 3
   id    length dose 
   <chr>  <dbl> <fct>
 1 Rat1    19.3 0    
 2 Rat2    18.9 0    
 3 Rat3    18.6 0    
 4 Rat4    19.0 0    
 5 Rat5    17.1 0    
 6 Rat6    18.8 0    
 7 Rat7    55.4 1.25 
 8 Rat8    59.2 1.25 
 9 Rat9    59.1 1.25 
10 Rat10   52.1 1.25 
# … with 14 more rows

  • Indicatie dat controle groep andere variabiliteit heeft.
  • 6 observaties per groep te weinig om aannames na te gaan.


3.2 Kruskal-Wallis Rank Test

  • De Kruskal-Wallis Rank Test (KW-test) is een niet-parameterisch alternatief voor de ANOVA F-test.

  • klassieke \(F\)-teststatistiek kan geschreven worden als \[ F = \frac{\text{SST}/(g-1)}{\text{SSE}/(n-g)} = \frac{\text{SST}/(g-1)}{(\text{SSTot}-\text{SST})/(n-g)} , \]

  • met \(g\) het aantal groepen.

  • SSTot hangt enkel af van uitkomsten \(\mathbf{y}\) en zal niet variëren bij permutaties.

  • Voldoende om SST als teststatistiek te gebruiken. \[\text{SST}=\sum_{j=1}^t n_j(\bar{Y}_j-\bar{Y})^2\]


  • De KW teststatistiek maakt gebruik van SST maar dan gebaseerd op de rank-getransformeerde uitkomsten1, \[ \text{SST} = \sum_{j=1}^g n_j \left(\bar{R}_j - \bar{R}\right)^2 = \sum_{j=1}^t n_j \left(\bar{R}_j - \frac{n+1}{2}\right)^2 , \]
  • met \(\bar{R}_j\) het gemiddelde van de ranks in behandelingsgroep \(j\), en \(\bar{R}\) het gemiddelde van alle ranks, \[ \bar{R} = \frac{1}{n}(1+2+\cdots + n) = \frac{1}{n}\frac{1}{2}n(n+1) = \frac{n+1}{2}. \]
  • De KW teststatistiek wordt gegeven door \[ KW = \frac{12}{n(n+1)} \sum_{j=1}^g n_j \left(\bar{R}_j - \frac{n+1}{2}\right)^2. \]
  • De factor \(\frac{12}{n(n+1)}\) zorgt ervoor dat \(KW\) een eenvoudige asymptotische nuldistributie heeft. In het bijzonder, onder \(H_0\), als \(\min(n_1,\ldots, n_g)\rightarrow \infty\), \[ KW \rightarrow \chi^2_{t-1}. \]

  • Exacte KW-test via permutatienuldistributie (die enkel afhangt van \(n_1, \ldots, n_g\)) \[H_0: f_1=\ldots=f_g \text{ vs } H_1: \text{ minstens twee gemiddelden verschillend}.\]

  • Locatie-shift

  • Indien locatie-shift niet opgaat, moet \(H_1\) geformuleerd worden in termen van probabilistische indexen: \[H_0: f_1=\ldots=f_g \text{ vs } H_1: \exists\ j,k \in \{1,\ldots,g\} : \text{P}\left[Y_j\geq Y_k\right]\neq 0.5\]


3.3 DNA Schade Voorbeeld

kruskal.test(length ~ dose, data = dna)

    Kruskal-Wallis rank sum test

data:  length by dose
Kruskal-Wallis chi-squared = 14, df = 3, p-value = 0.002905
  • Op \(5\%\) significantieniveau kan nulhypothese worden verworpen.

  • R-functie kruskal.test enkel asymptotische benadering voor berekening van \(p\)-waarden.

  • Met slechts 6 observaties per groep, is dit geen optimale benadering van de exacte \(p\)-waarde!


  • Met de coin R package kan de exacte \(p\)-waarde wel berekenen
library(coin)
kwPerm <- kruskal_test(length ~ dose, data = dna,
            distribution = approximate(nresample = 100000))
kwPerm

    Approximative Kruskal-Wallis Test

data:  length by dose (0, 1.25, 2.5, 5)
chi-squared = 14, p-value = 0.00025
  • We besluiten dat er een extreem significant verschil is in distributie van de DNA schade ten gevolge van de dosis.

3.4 Posthoc analyse

  • Welke groepen zijn verschillend???

  • Posthoc analyse a.d.h.v WMW testen

  • Eigenlijk niet optimaal na KW-test want de data worden opnieuw gerangschikt!

    • KW gebaseerd over ranks bepaalde over alle groepen
    • WMW gebaseerd op ranks van twee groepen in vergelijking
  • Betere alternatieven bestaan maar vallen buiten bestek van de cursus

pairwise.wilcox.test(dna$length,dna$dose)

    Pairwise comparisons using Wilcoxon rank sum exact test 

data:  dna$length and dna$dose 

     0     1.25  2.5  
1.25 0.013 -     -    
2.5  0.013 0.818 -    
5    0.013 0.721 0.788

P value adjustment method: holm 
  • Alle DMH behandelingen verschillen significant van de controle.
  • U1 niet in pairwise.wilcox.test output. Puntschatter op de kans op hogere DNA-schade?

nGroep <- table(dna$dose)
probInd <- combn(
  levels(dna$dose),
  2,
  function(x) {
         test <- wilcox.test(
       length~dose,
       dna %>% filter(dose%in%x)
       )
         return(test$statistic/prod(nGroep[x]))
    })
names(probInd) <- combn(
  dna %>% pull(dose) %>% levels,
  2,
  paste,
  collapse="vs")
probInd
  0vs1.25    0vs2.5      0vs5 1.25vs2.5   1.25vs5    2.5vs5 
0.0000000 0.0000000 0.0000000 0.4444444 0.2777778 0.3333333 

Omdat er twijfels zijn of het locatie-shift model geldig is, doen we enkel uitspraken in termen van de probabilistische index.


3.5 Conclusie

  • Er extreem significant verschil is in de distributie van de DNA-schade metingen tengevolge van de DMH behandeling (\(p<0.001\) KW-test).
  • DNA-schade is meer waarschijnlijk na behandeling met DMH dan in de controle behandeling (alle p=0.013, WMW-testen).
  • De kansen op hogere DNA-schade na blootstelling aan DMH bedraagt 100% (Berekenen van BI op kans buiten bestek van cursus).
  • Er zijn geen significante verschillen in de distributies van de comit-lengtes tussen de DMH behandelingen onderling (\(p=\) 0.72-0.82).
  • DMH vertoont dus al bij de lage dosis genotoxische effecten.
  • (Alle paarsgewijze testen werden gecorrigeerd voor multiple testing d.m.v. Holm’s methode).

  1. we veronderstellen afwezigheid van ties↩︎

LS0tCnRpdGxlOiAiOC4gTmlldC1wYXJhbWV0cmlzY2hlIHN0YXRpc3RpZWtlbiIgIAphdXRob3I6ICJMaWV2ZW4gQ2xlbWVudCIKZGF0ZTogInN0YXRPbWljcywgR2hlbnQgVW5pdmVyc2l0eSAoaHR0cHM6Ly9zdGF0b21pY3MuZ2l0aHViLmlvKSIKb3V0cHV0OgogICAgaHRtbF9kb2N1bWVudDoKICAgICAgY29kZV9kb3dubG9hZDogdHJ1ZSAgICAKICAgICAgdGhlbWU6IGNvc21vCiAgICAgIHRvYzogdHJ1ZQogICAgICB0b2NfZmxvYXQ6IHRydWUKICAgICAgaGlnaGxpZ2h0OiB0YW5nbwogICAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGluY2x1ZGUgPSBUUlVFLCBjb21tZW50ID0gTkEsIGVjaG8gPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0UpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KFJtaXNjKQpzZXQuc2VlZCgxNDApCmBgYAoKIyBJbmxlaWRpbmcKClZvcmlnZSBob29mZHN0dWtrZW46IHBhcmFtZXRyaXNjaGUgbWV0aG9kZW4KCi0gIEluZmVyZW50aWUgZW5rZWwgY29ycmVjdCBhbHMgdm9sZGFhbiBhYW4gcGFyYW0uIHZlcm9uZGVyc3RlbGxpbmdlbjoKCgktIGRpc3RyaWJ1dGlvbmVsZSB2ZXJvbmRlcnN0ZWxsaW5nZW46IHYuYi4gTm9ybWFhbCB2ZXJkZWVsZGUgZ2VnZXZlbnMuCgktIGdlbGlqa2hlaWQgdmFuIHZhcmlhbnRpZXMgKHR3by1zYW1wbGUgJHQkLXRlc3QgZW4gQU5PVkEpCgotICBEZSAkcCQtd2FhcmRlOiAkXHRleHR7UH1fMFxsZWZ0WyBcdmVydCBUXHZlcnQgXGdlcSBcdmVydCB0IFx2ZXJ0IFxyaWdodF0kLgoKICAgIC0gQmVyZWtlbmQgby5iLnYuIG51bGRpc3RyaWJ1dGllIHZhbiAkVCQgZGllIGFmZ2VsZWlkIGlzIHZhbiB2ZXJkZWxpbmcgdmFuIG9ic2VydmF0aWVzCiAgICAtIEZvdXQgYWxzIG5pZXQgdm9sZGFhbiBpcyBhYW4gdmVyb25kZXJzdGVsbGluZ2VuCgotICAkOTVcJSQgQkkgc3RldW50IGV2ZW5lZW5zIG9wIHZlcm9uZGVyc3RlbGxpbmdlbi4gTmlldCB2b2xkYWFuOiBnZWVuIGdhcmFudGllIGRhdCBpbnRlcnZhbGxlbiBwb3B1bGF0aWUgcGFyYW1ldGVyd2FhcmRlIG9tdmF0dGVuIG1ldCAkOTVcJSQga2Fucy4KCi0tLQoKLSBBc3ltcHRvdGlzY2hlIHRoZW9yaWUgbW9laWxpamtlciB0ZSBwbGFhdHNlbjogamUga2FuIHN0ZWxsZW4gZGF0ICR0JC10ZXN0IGFzeW1wdG90aXNjaCBuaWV0LXBhcmFtZXRyaXNjaCBpcyBvbWRhdCBiaWogZXJnIGdyb3RlIHN0ZWVrcHJvZWZncm9vdHRlcyBkZSBkaXN0cmlidXRpb25lbGUgdmVyb25kZXJzdGVsbGluZyB2YW4gbm9ybWFsaXRlaXQgbmlldCBtZWVyIGJlbGFuZ3JpamsgaXMuCgotIFBhcmFtZXRyaXNjaGUgYWFucGFrOgoKCS0gZWZmaWNpw6tudGVyOiBncm90ZXJlIHBvd2VyIGJpaiB6ZWxmZGUgc3RlZWtwcm9lZmdyb290dGUgKyBzbWFsbGVyZSBCSQoJLSBtZWVyIGZsZXhpYmVsOiBtYWtrZWxpamtlciBpbnpldGJhYXIgdm9vciBleHBlcmltZW50ZW4gbWV0IG1lZXIgY29tcGxleGUgZGVzaWducwoKLS0tCgojIFZlcmdlbGlqa2VuIHZhbiB0d2VlIGdyb2VwZW4KCiMjIENob2xlc3Rvcm9sIHZvb3JiZWVsZAoKLSBDaG9sZXN0b3JvbGNvbmNlbnRyYXRpZSBpbiBibG9lZAogIC0gNSBwYXRpw6tudGVuIChncm9lcD0xKSBkaWUgdHdlZSBkYWdlbiBnZWxlZGVuIGVlbiBoYXJ0YWFudmFsIGRlZGVuCiAgLSBiaWogNSBnZXpvbmRlIHBlcnNvbmVuIChncm9lcD0yKS4KCi0gQ2hvbGVzdG9yb2xjb25jZW50cmF0aWUgdmVyc2NoaWxsZW5kIGJpaiBoYXJ0cGF0acOrbnRlbiBlbiBnZXpvbmRlIHBlcnNvbmVuPwoKYGBge3J9CmNob2wgPC0gcmVhZF90c3YoImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9zdGF0T21pY3Mvc2JjMjAvbWFzdGVyL2RhdGEvY2hvbC50eHQiKQoKY2hvbCA8LSBjaG9sICU+JQogIG11dGF0ZShncm91cCA9IGFzLmZhY3Rvcihncm91cCkpCgpuR3JvdXBzIDwtIGNob2wgJT4lCiAgcHVsbChncm91cCkgJT4lCiAgdGFibGUKCm4gPC0gbkdyb3VwcyAlPiUKICBzdW0KY2hvbApgYGAKCi0tLQoKCmBgYHtyLCBlY2hvPUZBTFNFLG91dC53aWR0aD0nNTAlJywgZmlnLmFzcD0uOCwgZmlnLmFsaWduPSdjZW50ZXInfQpjaG9sICU+JSAgCiAgZ2dwbG90KGFlcyh4PWdyb3VwLHk9Y2hvbGVzdCkpICsKICBnZW9tX2JveHBsb3Qob3V0bGllci5zaGFwZT1OQSkgKwogIGdlb21fcG9pbnQocG9zaXRpb249ImppdHRlciIpCgpjaG9sICU+JSBnZ3Bsb3QoYWVzKHNhbXBsZT1jaG9sZXN0KSkgKwogIGdlb21fcXEoKSArCiAgZ2VvbV9xcV9saW5lKCkgKwogIGZhY2V0X3dyYXAofmdyb3VwKQpgYGAKCi0gTW9nZWxpamtzIG91dGxpZXJzCi0gTW9laWxpamsgb20gaW56aWNodCB0ZSBrcmlqZ2VuIGluIHZlcmRlbGluZzogbWFhciA1IG9ic2VydmF0aWVzIHBlciBncm9lcAoKLS0tCgoKIyMgUGVybXV0YXRpZS10ZXN0ZW4KClZyYWFnc3RlbGxpbmcgQ2hvbGVzdG9yb2wgdm9vcmJlZWxkIHZlcnRhbGluZyBuYWFyIG51bGh5cG90aGVzZS4KS2xhc3NpZWs6CiQkSF8wOiBcbXVfMT1cbXVfMiBcdGV4dHsgdmVyc3VzIH0gSF8xOiBcbXVfMVxuZXEgXG11XzIuJCQKCi0gR3JvZXAgMTogSGFydHBhdGnDq250ZW4KLSBHcm9lcCAyOiBHZXpvbmRlIGluZGl2aWR1ZW4KLSBUZXN0ZW4gdmFuIGRlemUgaHlwb3RoZXNlcyBkLm0udi4gdHdvLXNhbXBsZSAkdCQtdGVzdC4KCldlIGdhYW4gZGUgdm9vcndhYXJkZW4gbmE6CgotIE5vcm1hbGl0ZWl0PwotIEdlbGlqa2hlaWQgdmFuIHZhcmlhbnRpZT8KLSBUZSB3ZWluaWcgb2JzZXJ2YXRpZXMgcGVyIGdyb2VwLgotIFdlIGt1bm5lbiB2ZXJvbmRlcnN0ZWxsaW5nZW4gbmlldCBuYWdhYW4hCi0gR2V2YWFybGlqayEKLSBPcGxvc3Npbmc6IHBlcm11dGF0aWV0ZXN0ZW4KCi0tLQoKIyMjIEh5cG90aGVzZW4KCi0gJFlfezFqfSQgZW4gJFlfezJqfSQgdWl0a29tc3RlbiB1aXQgcmVzcGVjdGlldmVsaWprIGdyb2VwIDEgZW4gMjoKJCRZX3sxan0gXHRleHR7IGlpZCB9IE4oXG11XzEsXHNpZ21hXjIpIFw7XDtcO1x0ZXh0eyBlbiB9XDtcO1w7IFlfezJqfSBcdGV4dHsgaWlkIH0gTihcbXVfMixcc2lnbWFeMikuJCQKLSBPbmRlciAkSF8wOlxtdV8xPVxtdV8yJCwgd29yZHQgZGl0IChzdGVsICRcbXU9XG11XzE9XG11XzIkIG9uZGVyICRIXzAkKQokJCBZX3tpan0gXHRleHR7IGlpZCB9IE4oXG11LFxzaWdtYV4yKSwkJAoKLSBEcnVrdCB1aXQgZGF0IGFsbGUgJG49bl8xK25fMiQgdWl0a29tc3RlbiB1aXQgemVsZmRlIG5vcm1hbGUgZGlzdHJpYnV0aWUga29tZW4gZW4gb25hZmhhbmtlbGlqayB6aWpuCi0gTGFhdCB0b2Ugb20gb29yc3Byb25rZWxpamtlIG51bGh5cG90aGVzZSBhbmRlcnMgdGUgc2NocmlqdmVuOgpcW0hfMDogZl8xKHkpID0gZl8yKHkpIFx0ZXh0eyB2b29yIGFsbGUgfSB5IFxdCm1ldAoKICAtICRmXzEkIGVuICRmXzIkIGRlIHZlcmRlbGluZyB2YW4gdWl0a29tc3RlbgogIC0gQmlqa29tZW5kZSB2ZXJvbmRlcnN0ZWxsaW5nIGRhdCAkZl8xJCBlbiAkZl8yJCBub3JtYWxlIHZlcmRlbGluZ2VuIHppam4uCgotLS0KCk9uZGVyIGRlIGFsdGVybmF0aWV2ZSBoeXBvdGhlc2Ugd29yZHQgZWVuIGxvY2F0aWUtc2hpZnQgdmVyb25kZXJzdGVsZDoKJCRIXzE6IGZfMSh5KT1mXzIoeS1cRGVsdGEpIFw7XDtcO1x0ZXh0eyB2b29yIGFsbGUgfSB5JCQKbWV0CgotICRcRGVsdGE9XG11XzEtXG11XzIkCi0gZW4gJGZfMSQgZW4gJGZfMiQgbm9ybWFsZSB2ZXJkZWxpbmdlbiBtZXQgZGV6ZWxmZGUgdmFyaWFudGllLgoKV2UgaWxsdXN0cmVyZW4gZGl0IGluIFIgdm9vciAkZl8xXHNpbSBOKDAsMSkkIGVuICRmXzJcc2ltIE4oMSwxKSQgZW4gJFxEZWx0YT0tMSQuCmBgYHtyLCBzaXplPSJ0aW55In0KbXUxIDwtIDA7IG11MiA8LSAxOyBzaWdtYTEgPC0gc2lnbWEyIDwtIDEKeSA8LSAtMjoyCmRlbHRhIDwtIG11MS1tdTI7IGRlbHRhCnJiaW5kKGRub3JtKHksbXUxLHNpZ21hMSksIGRub3JtKHktZGVsdGEsbXUyLHNpZ21hMikpCmBgYAoKLS0tCgpEZSBwZXJtdXRhdGlldGVzdGVuIGRpZSB3ZSBvbnR3aWtrZWxlbiBrdW5uZW4gZ2VicnVpa3Qgd29yZGVuIHZvb3IgaGV0IHRlc3RlbiB2YW4KXFsKICBIXzA6IEZfMT1GXzIgXDtcO1w7XHRleHR7IG9mIH1cO1w7XDsgSF8wOmZfMT1mXzIuClxdCm1hYXIgem9uZGVyIGRlIE5vcm1hbGl0ZWl0c3Zlcm9uZGVyc3RlbGxpbmdlbi4KCldlIHdldGVuIGRhdCBvbmRlciAkSF8wJCBnZWxkdCBkYXQgOgoKLSBWZXJkZWxpbmcgdmFuIGRlIGNob2xlc3Rvcm9sY29uY2VudHJhdGllcyBnZWxpamsgdm9vciBoYXJ0cGF0acOrbnRlbiBlbiBnZXpvbmRlIHBlcnNvbmVuCi0gR3JvZXAtbGFiZWxzIHZhbiBkZSBgciBuYCBwZXJzb25lbiBuaWV0IGluZm9ybWF0aWVmCi0gR3JvZXBlcmluZyBnZWJydWlrdCBvbSBvcmlnaW5lbGUgdGVzdHN0YXRpc3RpZWsgdGUgYmVwYWxlbiBpcyBvbmRlciBkZSBudWxoeXBvdGhlc2UgZWVuIHZhbiBkZSB2ZWxlIGdyb2VwZXJpbmdlbiBkaWUgYWxsZW1hYWwgZXZlbiB6aW52b2wvZXZlbiB3ZWluaWcgemludm9sIHppam4uCi0gRWxrZSBncm9lcGVyaW5nIHpvdSBpbW1lcnMgZGV6ZWxmZGUgdWl0a29tc3RlbiBoZWJiZW4gZ2VnZW5lcmVlcmQgYWFuZ2V6aWVuIGVyIGdlZW4gZWZmZWN0IGlzIHZhbiBkZSBiZWhhbmRlbGluZy4KLSBCZXJla2VuIG51bGxkaXN0cmlidXRpZSBkb29yIHBlcm11dGVyZW4gdmFuIGRlIGdyb2Vwc2xhYmVscyEKCi0tLQoKIyMjIFZlcmRlbGluZyB2YW4gZGUgc3RhdGlzdGllayBvbmRlciAkSF8wJAoKLSAkbT1cYmlub217bl8xK25fMn17bl8xfT1cYmlub217bn17bl8xfT1cYmlub217bn17bl8yfSQgbW9nZWxpamtlIHVuaXF1ZSBwZXJtdXRhdGllcyAkXGNhbHtHfSQgdmFuIGRlIGdyb2Vwc2xhYmVscy4KLSBJbiBvbnMgdm9vcmJlZWxkICRtPSQgYHIgY2hvb3NlKG4sbkdyb3Vwc1sxXSlgLgotIEFscyAkbSQgbmlldCB0ZSBncm9vdCBpcyBrdW5uZW4gYWxsZSB1bmlla2UgcGVybXV0YXRpZXMgdmFuIGRlIGdyb2Vwc2xhYmVscyBiZXJla2VuZCB3b3JkZW4uCi0gVmVydm9sZ2VucyB3b3JkdCB2b29yIGllZGVyZSB1bmlxdWUgcGVybXV0YXRpZSAkZyBcaW4gXGNhbHtHfSQgZGUgdGVzdHN0YXRpc3RpZWsgJHReKl9nJCBiZXJla2VuZAotIEhpZXIgZGUgdC10ZXN0IHN0YXRpc3RpZWsgZG9vciBkZSBvcmlnaW5lbGUgdWl0a29tc3RlbiB0ZSBnZWJydWlrZW4gZGllIG51IGdla29wcGVsZCB3b3JkZW4gYWFuIGRlIGdlcGVybXV0ZWVyZGUgZ3JvZXBzbGFiZWxzICRHX2deKiQuCgotLS0KCldlIGt1bm5lbiBhbGxlIG09YHIgY2hvb3NlKG4sbkdyb3Vwc1sxXSlgIHBlcm11dGF0aWVzIGluIFIgZ2VuZXJlcmVuIGEuZC5oLnYuIGRlIGZ1bmN0aWUgYGNvbWJuKG4sbl8xKWAuCkRpdCB3b3JkdCBnZcOvbGx1c3RyZWVyZCBpbiBkZSBvbmRlcnN0YWFuZGUgUiBjb2RlOgoKLSBHIGJldmF0IHZvbGdudW1tZXJzIHZhbiBkZSBvYnNlcnZhdGllcyB1aXQgZ3JvZXAgMSB2b29yIGVsa2UgcGVybXV0YXRpZSBkCi0gV2UgdG9uZW4gZW5rZWwgZGUgZWVyc3RlIDEwIHBlcm11dGF0aWVzLgoKYGBge3Isc2l6ZT0idGlueSJ9CkcgPC0gY29tYm4obixuR3JvdXBzWzFdKQpkaW0oRykKR1ssMToxMF0KYGBgCgotLS0KCldlIGJlcmVrZW5lbiBudSBkZSB0ZXN0c3RhdGlzdGllayB2b29yIGVsa2UgcGVybXV0YXRpZQoKYGBge3Isc2l6ZT0idGlueSJ9CnRPcmlnIDwtIHQudGVzdChjaG9sZXN0IH4gZ3JvdXAsIGNob2wpJHN0YXRpc3RpYwp0T3JpZwp0U3RhciA8LSBjb21ibigKICBuLAogIG5Hcm91cHNbMV0sCglmdW5jdGlvbihnLHkpIHsKICAgIHQudGVzdCh5W2ddLHlbLWddKSRzdGF0aXN0aWMKICAgIH0sCiAgeSA9IGNob2wgJT4lIHB1bGwoY2hvbGVzdCkKICApCmhlYWQodFN0YXIpCmxlbmd0aCh0U3RhcikKYGBgCgotLS0KCi0gV2Uga3VubmVuIG51IGRlIHZlcmRlbGluZyB2YW4gZGUgdGVzdHN0YXRpc3RpZWsgb25kZXIgJEhfMCQgYmVzdHVkZXJlbi4KLSBPcmlnaW5lbGUgc3RhdGlzdGllayAocm9kZSB2ZXJ0aWNhbGUgbGlqbikgaXMgZXh0cmVlbQoKYGBge3Isb3V0LndpZHRoPSc4MCUnLCBmaWcuYXNwPS44LCBmaWcuYWxpZ249J2NlbnRlcicsZWNobz1GQUxTRX0KcXBsb3QodFN0YXIsYmlucz01MCkgKwogIHhsYWIoZXhwcmVzc2lvbigicGVybXV0YXRpZXN0YXRpc3RpZWsgdCJeIioiKSkgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdD10T3JpZyxjb2w9MikKYGBgCgotLS0KCiMjIyBwLXdhYXJkZQoKLSBQZXJtdXRhdGllbnVsZGlzdHJpYnV0aWUgJFxsb25ncmlnaHRhcnJvdyQgaHlwb3RoZXNldGVzdGVuIHVpdHZvZXJlbi4KCi0gdHdlZXppamRpZ2UgcGVybXV0YXRpZSAkcCQtd2FhcmRlCiAgJCRwPVx0ZXh0e1B9XzBcbGVmdFtcdmVydCBUXHZlcnQgXGdlcSBcdmVydCB0XHZlcnQgXG1pZCBcbWF0aGJme3l9XHJpZ2h0XS4kJAoKLSBwLXdhYXJkZSBnZWNvbmRpdGlvbmVlcmQgb3AgZ2VvYnNlcnZlZXJkZSBjaG9sZXN0b3JvbHdhYXJkZW4gJFxtYXRoYmZ7eX09KHlfezExfSxcbGRvdHMseV97NTF9LHlfezEyfSxcbGRvdHMseV97NTJ9KV5UJC4KCi0gR2V6aWVuIHBlcm11dGF0aWVudWxkaXN0cnVidXRpZSB2YW4gJFQkIGJlcGFhbGQgd29yZHQgZG9vciAkdF4qX2ckLCAkZyBcaW57XGNhbHtHfX0kLCBiZXJla2VuZW4gd2UKJCRwICA9IFxmcmFje1wjXHtnXGluIHtcY2Fse0d9fTogXHZlcnQgdF4qX2dcdmVydCBcZ2VxIFx2ZXJ0IHQgXHZlcnQgXH19e219JCQKCmBgYHtyfQpwdmFsIDwtIG1lYW4oYWJzKHRTdGFyKT49YWJzKHRPcmlnKSkKcHZhbApgYGAKCi0tLQoKCi0gT3AgaGV0ICQ1XCUkIHNpZ25pZmljYW50aWVuaXZlYXUgYmVzbHVpdGVuIHdlIGRhdCBkZSBkaXN0cmlidXRpZXMgdmFuIGRlIGNob2xlc3Rvcm9sIGNvbmNlbnRyYXRpZXMgbmlldCBnZWxpamsgemlqbiBiaWogaGFydHBhdGnDq250ZW4gZW4gYmlqIGdlem9uZGUgcGVyc29uZW4uICgkcD0kIGByIHBhc3RlKGZvcm1hdChwdmFsLGRpZ2l0cz0zKSlgKS4KCgotIERlICRwJC13YWFyZGUgb3AgYmFzaXMgdmFuIGFsbGUgcGVybXV0YXRpZXMgd29yZHQgZWVuICoqZXhhY3RlKiogJHAkLXdhYXJkZSBnZW5vZW1kLgotIERlIHBlcm11dGF0aWVudWxkaXN0cmlidXRpZSB3b3JkdCBlZW4gKipleGFjdGUqKiBudWxkaXN0cmlidXRpZSBnZW5vZW1kLgotIERlIHRlcm0gKipleGFjdCoqIGJldGVrZW50IGRhdCBkZSByZXN1bHRhdGVuIGNvcnJlY3QgemlqbiB2b29yIGllZGVyZSBzdGVla3Byb2VmZ3Jvb3R0ZSAkbiQuCgoKLSBEZSBrYW5zIG9wIGVlbiB0eXBlIEkgZm91dCB3b3JkdCBkdXMgZ2Vjb250cm9sZWVyZCBkb29yIGVlbiBwZXJtdXRhdGlldGVzdCwgbWFhciB3ZWwgY29uZGl0aW9uZWVsIG9wIGRlIGdlb2JzZXJ2ZWVyZGUgdWl0a29tc3RlbiBkYXRhICRcbWF0aGJme3l9JC4KCi0gICoqV2Uga3VubmVuIG9ucyBudSBhZnZyYWdlbiBvZiB3ZSBkZSBjb25jbHVzaWVzIGt1bm5lbiB2ZXJhbGdlbWVuZW4gbmFhciBkZSBwb3B1bGF0aWUgdG9lPyBIZXQgYW50d29vcmQgaXMgamEsIGFscyBkZSBzdWJqZWN0ZW4gYXQgcmFuZG9tIGdldHJva2tlbiB6aWpuIHVpdCBkZSBwb3B1bGF0aWUuKioKCi0gSGV0IGJld2lqcyBoaWVydmFuIHZhbHQgYnVpdGVuIGhldCBiZXN0ZWsgdmFuIGRlIGN1cnN1cy4KCi0tLQoKLSBTb21zIHByb2JsZWVtIG9tZGF0IGhldCBhYW50YWwgcGVybXV0YXRpZXMgJG09XCN7XGNhbHtHfX0kIGVyZyBncm9vdCBpcwoKICAtICRcYmlub217MjB9ezEwfT0kIGByIGZvcm1hdCggY2hvb3NlKDIwLDEwKSxkaWdpdD0zKWAKICAtICRcYmlub217MzB9ezE1fT0kIGByIGZvcm1hdCggY2hvb3NlKDMwLDE1KSxkaWdpdD0zKWAKICAtICRcYmlub217NDB9ezIwfT0kIGByIGZvcm1hdCggY2hvb3NlKDQwLDIwKSxkaWdpdD0zKWAuCgotIERhYXJvbSBuaWV0IGFsbGUgJGcgXGluIHtcY2Fse0d9fSQgdGUgYmVzY2hvdXdlbiwgbWFhciBncm9vdCBhYW50YWwgcmFuZG9tIHBlcm11dGF0aWVzIHVpdHZvZXJlbiAoYi52LiAxMDAwMCkKCi0gVGVyIGlsbHVzdHJhdGllIHN0YWF0IGRlIGNvZGUgaGllcnZhbiBvb2sgaW4gZGUgY3Vyc3VzLgoKLS0tCgojIyMgSG9lIGt1bm5lbiB3ZSBjb25jbHVzaWUgaW50ZXJwcmV0ZXJlbiAgCgotIFdlIHBlcm11dGVyZW4gaW1tZXJzIHQgc3RhdGlzdGllaywgZWZmZWN0Z3Jvb3R0ZSBsb2NhdGllLXNoaWZ0CgotIEFscyBsb2NhdGllLXNoaWZ0IG1vZGVsIG5pZXQgb3BnYWF0IGlzIGVlbiBzaWduaWZpY2FudCByZXN1bHRhYXQgbW9laWxpamsgdGUgaW50ZXJwcmV0ZXJlbiwgdGVnZW5vdmVyIHdlbGsgYWx0ZXJuYXRpZWYgdGVzdGVuIHdlIGRhbj8/PwoKLSBMb2NhdGllLXNoaWZ0IGthbiBuaWV0IHdvcmRlbiBuYWdlZ2FhbiBpbiBrbGVpbmUgc3RlZWtwcm9ldmVuLi4uCgotLS0KCiMjIFJhbmsgVGVzdGVuCgotIEJlbGFuZ3JpamtzdGUgZ3JvZXAgdmFuIG5pZXQtcGFyYW1ldHJpc2NoZSB0ZXN0ZW4KLSBQb3B1bGFyaXRlaXQ6CiAgLSBOaWV0LXBhcmFtZXRyaXNjaCwKICAtIEV4YWN0ZSAkcCQtd2FhcmRlbiBkLm0udi5wZXJtdXRhdGllbnVsZGlzdHJpYnV0aWUuCiAgLSBHZWVuIG5vb2QgYWFuIGFwYXJ0ZSBwZXJtdXRhdGllbnVsZGlzdHJpYnV0aWUgdm9vciBpZWRlcmUgbmlldXdlIGRhdGFzZXQuCiAgLSBQZXJtdXRhdGllbnVsZGlzdHJpYnV0aWUgdmFuIHJhbmsgdGVzdGVuIGhhbmd0IGFsbGVlbiBhZiB2YW4gc3RlZWtwcm9lZmdyb290dGVzLgogIC0gRXJnIHJvYnVzdCB6aWpuIHRlZ2VuIHVpdHNjaGlldGVycyAoRW5nZWxzOiAqb3V0bGllcnMqKQogIC0gTnV0dGlnIGFscyBsb2NhdGllLXNoaWZ0IG1vZGVsIG5pZXQgb3BnYWF0LgoKLS0tCgojIyMgUmFua3MKClJhbmsgdGVzdGVuIHN0YXJ0ZW4gdmFudWl0IHJhbmstZ2V0cmFuc2Zvcm1lZXJkZSB1aXRrb21zdGVuLgoKLSBCZXNjaG91dyAkWV8xLCBcbGRvdHMsIFlfbiQuCi0gQWZ3ZXppZ2hlaWQgdmFuIHR3ZWUgZ2VsaWprZSBvYnNlcnZhdGllcyAoaS5lLiBnZWVuICp0aWVzKikuCiAgJCRSX2k9UihZX2kpID0gXCNce1lfajogWV9qXGxlcSBZX2k7IGo9MSxcbGRvdHMsIG5cfSQkCi0gS2xlaW5zdGUgb2JzZXJ2YXRpZSBrcmlqZ3QgZHVzIHJhbmsgMSwgZGUgdHdlZWRlIGtsZWluc3RlIHJhbmsgMiwgZW56b3Zvb3J0LCBlbiBkZSBncm9vdHN0ZSBvYnNlcnZhdGllLAogIHRlbnNsb3R0ZSwga3Jpamd0IHJhbmsgJG4kLgoKYGBge3J9CmNob2wgJT4lCiAgcHVsbChjaG9sZXN0KQoKY2hvbCAlPiUKICBwdWxsKGNob2xlc3QpICU+JQogIHJhbmsKYGBgCgotLS0KClNvbXMga29tZW4gKnRpZXMqIHZvb3IgaW4gZGUgZGF0YSwgaS5lLiBtaW5zdGVucyB0d2VlIG9ic2VydmF0aWVzIGhlYmJlbiBkZXplbGZkZSBudW1lcmlla2Ugd2FhcmRlLiBFZW4ga2xlaW4gdm9vcmJlZWxkOgoKYGBge3J9Cm1ldFRpZXMgPC0gYyg0MDMsIDUwNywgNTA3LCA2MTAsIDY1MSwgNjUxLCA2NTEsIDgzMCwgOTAwKQptZXRUaWVzICU+JSByYW5rCmBgYAoKLSBUaWVzOiA1MDcga29tdCB0d2VlbWFhbCB2b29yLCA2NTEga29tdCBkcmllbWFhbCB2b29yLiBEaXQgemlqbiB2b29yYmVlbGRlbiB2YW4gKnRpZXMqLgotIFdhbm5lZXIgKnRpZXMqIHZvb3Jrb21lbiwgd29yZGVuICptaWRyYW5rcyogZ2VicnVpa3QuCgotICoqbWlkcmFuayoqIHZhbiBvYnNlcnZhdGllICRZX2kkIHdvcmR0CiAgXGJlZ2lue2VxbmFycmF5Kn0KICAgUl9pICY9JiBcZnJhY3sgXCNce1lfajogWV9qXGxlcSBZX2lcfSArICggXCNce1lfajogWV9qIDwgWV9pXH0gKzEpfXsyfS4KICAgXGVuZHtlcW5hcnJheSp9CgotLS0KCi0gRGlrd2lqbHMgcmFua3Mgbm9kaWcgaW4gZGUgZ2Vwb29sZGUgc3RlZWtwcm9lZgotIEJpanZvb3JiZWVsZDogJFlfe2lqfSQsICRpPTEsXGxkb3RzLCBuX2okIGVuICRqPTEsMiQuCi0gVWl0a29tc3RlbiBrdW5uZW4gd29yZGVuIHZvb3JnZXN0ZWxkIGRvb3IgJFpfMSxcbGRvdHMsIFpfbiQgKCRuPW5fMStuXzIkKSwgZGUgdWl0a29tc3RlbiB1aXQgZGUgZ2Vwb29sZGUgc3RlZWtwcm9lZi4KCmBgYHtyfQp0KGNob2wpCnogPC0gY2hvbCAlPiUKICBwdWxsKGNob2xlc3QpCnoKcmFuayh6KQpgYGAKCi0tLQoKIyMjIFdpbGNveG9uLU1hbm4tV2hpdG5leSBUZXN0CgotIEdlbGlqa3RpamRpZyBvbnR3aWtrZWxkIGRvb3IgIFdpbGNveG9uIGVuIGRvb3IgTWFubiBlbiBXaGl0bmV5Ci0gICoqV2lsY294b24tTWFubi1XaGl0bmV5KiosICoqV2lsY294b24gcmFuayBzdW0gdGVzdCoqICBvZiAqKk1hbm4tV2hpdG5leSBVIHRlc3QqKgotICRIXzA6IGZfMT1mXzIkIHZzICRIXzE6IFxtdV8xXG5lcSBcbXVfMiQgKG9mIGRlIGVlbnppamRpZ2UgdmVyc2llcykuCi0gRWVyc3QgKipsb2NhdGllLXNoaWZ0KiogbW9kZWwgdmVyb25kZXJzdGVsbGVuIGxhdGVyIHJlbGF4ZXJlbiB3ZSBhYW5uYW1lLgoKLS0tCgotIEtsYXNzaWVrZSB0LXRlc3Q6IHZlcnNjaGlsIGluIHN0ZWVrcHJvZWZnZW1pZGRlbGRlbiAkXGJhcntZfV8xLVxiYXJ7WX1fMiQuCi0gSGllcjogdmVyc2NoaWwgaW4gc3RlZWtncm9lcGdlbWlkZGVsZGUgb3AgYmFzaXMgdmFuIHJhbmstZ2V0cmFuc2Zvcm1lZXJkZSB1aXRrb21zdGVuLgotIFJhbmtzIG9wIGJhc2lzIHZhbiBnZXBvb2xkZSBzYW1wbGUgKG5hIHNhbWVudm9lZ2VuIHZhbiB1aXRrb21zdGVuIHVpdCBncm9lcCAxIGVuIGdyb2VwIDIpCgotLS0KCi0gJFJfe2lqfT1SKFlfe2lqfSkkIGlzIGRlIHJhbmsgdmFuIHVpdGtvbXN0ICRZX3tpan0kIGluIGRlIGdlcG9vbGRlIHN0ZWVrcHJvZWYuClxbCiAgVCA9IFxmcmFjezF9e25fMX1cc3VtX3tpPTF9XntuXzF9IFIoWV97aTF9KSAtIFxmcmFjezF9e25fMn1cc3VtX3tpPTF9XntuXzJ9IFIoWV97aTJ9KSAuClxdCgotIE9uZGVyICRIXzAkIHZlcndhY2h0ZW4gd2UgZGF0IGdlbWlkZGVsZGUgcmFuayBpbiBkZSBlZXJzdGUgZ3JvZXAgb25nZXZlZXIgZ2VsaWprIGlzIGFhbiBkZSBnZW1pZGRlbGRlIHJhbmsgaW4gZGUgdHdlZWRlIGdyb2VwIGVuICRUJCBkaWNodCBiaWogbnVsLgotIEFscyAkSF8xJCB3YWFyIGlzIGRhbiB2ZXJ3YWNodGVuIHdlIGRhdCBnZW1pZGRlbGRlIHJhbmtzIHZlcnNjaGlsbGVuIGVuIGR1cyBkYXQgJFQkIG5pZXQgZGljaHQgYmlqIG51bCB6YWwgbGlnZ2VuLgoKLSBFaWdlbmxpamsgdm9sZG9lbmRlIG9tIGVua2VsCiAgJCRTXzE9XHN1bV97aT0xfV57bl8xfSBSKFlfe2kxfSkkJC4KCi0gJFNfMSQgaXMgc29tIHZhbiBkZSByYW5rcyB2YW4gb2JzZXJ2YXRpZXMgdWl0IGdyb2VwIDEgdmFuZGFhciBkZSBuYWFtICpyYW5rIHN1bSB0ZXN0Ki4KCi0gV2FudApcWwogIFNfMStTXzIgPSBcdGV4dHtzb20gdmFuIGFsbGUgcmFua3N9ID0gMSsyK1xjZG90cyArIG49XGZyYWN7MX17Mn1uKG4rMSkuClxdCgotLS0KCi0gJFNfMSQgKG9mICRTXzIkKSBlZW4gZ29lZGUgdGVzdHN0YXRpc3RpZWsKLSBQZXJtdXRhdGlldGVzdG1ldGhvZGUgdG9lZ2VwYXNzZW4gb20gZXhhY3RlIHBlcm11dGF0aWVudWxkaXN0cmlidXRpZSB0ZSBiZWtvbWVuCi0gVm9vciBlZW4gZ2VnZXZlbiBzdGVla3Byb2VmZ3Jvb3R0ZSAkbiQsIGVuIHZlcm9uZGVyc3RlbGxlbmQgZGF0IGVyIGdlZW4gKnRpZXMqIHppam4sIHppam4gcmFuay1nZXRyYW5zZm9ybWVlcmRlIHVpdGtvbXN0ZW4gYWx0aWpkCiAgJCQxLCAyLCBcbGRvdHMsIG4kJAotIFZvb3IgZ2VnZXZlbiBncm9lcHNncm9vdHRlcyAkbl8xJCBlbiAkbl8yJCwgemFsIGRlIHBlcm11dGF0aWVudWxkaXN0cmlidXRpZSBkYW4gb29rIHN0ZWVkcyBkZXplbGZkZSB6aWpuIQotIFRvdCAxOTgwIHdlcmQgZGl0IGFscyBlZW4gZ3Jvb3Qgdm9vcmRlZWwgYmVzY2hvdXdkIG9tZGF0IGRlIG51bGRpc3RyaWJ1dGllcyB2b29yIGdlZ2V2ZW4gJG5fMSQgZW4gJG5fMiQgZ2V0YWJ1bGVlcmQga29uZGVuIHdvcmRlbgotIERvb3IgcmVrZW5jYXBhY2l0ZWl0IHNwZWVsdCBkaXQgYXJndW1lbnQgbmlldCBtZWVyLCB3ZWwgYW5kZXJlIGJlbGFuZ3JpamtlIHJlZGVuZW4uCgotLS0KCgotIFZhYWsgd29yZHQgZ2VzdGFuZGFhcmRpc2VlcmRlIHRlc3RzdGF0aXN0aWVrIGdlYnJ1aWt0ClxbCiAgVCA9IFxmcmFje1NfMS1cdGV4dHtFfV97MH1cbGVmdFtTXzFccmlnaHRdfXtcc3FydHtcdGV4dHtWYXJ9X3swfVxsZWZ0W1NfMVxyaWdodF19fSwKXF0KLSBtZXQgJFx0ZXh0e0V9X3swfVxsZWZ0W1NfMVxyaWdodF0kIGVuICRcdGV4dHtWYXJ9X3swfVxsZWZ0W1NfMVxyaWdodF0kIGRlIHZlcndhY2h0aW5nc3dhYXJkZSBlbiB2YXJpYW50aWUgdmFuICRTXzEkIG9uZGVyICRIXzAkLgotIERpdCB6aWpuIGR1cyBoZXQgZ2VtaWRkZWxkZSBlbiB2YXJpYW50aWUgdmFuIGRlIHBlcm11dGF0aWVudWxkaXN0cmlidXRpZSB2YW4gJFNfMSQuCgotIE9uZGVyICRIXzAkIGdlbGR0CiBcWwogICBcdGV4dHtFfV97MH1cbGVmdFtTXzFccmlnaHRdPSBcZnJhY3sxfXsyfW5fMShuKzEpIFw7XDtcO1w7XHRleHR7IGVuIH1cO1w7XDtcOyBcdGV4dHtWYXJ9X3swfVxsZWZ0W1NfMVxyaWdodF09XGZyYWN7MX17MTJ9bl8xbl8yKG4rMSkuCiBcXQoKLSBWZXJkZXIga2FuIG1lbiBvbmRlciAkSF8wJCAgZW4gYWxzICRcbWluKG5fMSxuXzIpXHJpZ2h0YXJyb3cgXGluZnR5JCBvcGdhYXQgYWFudG9uZW4gZGF0LAogXFsKICAgIFQgPSBcZnJhY3tTXzEtXHRleHR7RX1fezB9XGxlZnRbU18xXHJpZ2h0XX17XHNxcnR7XHRleHR7VmFyfV97MH1cbGVmdFtTXzFccmlnaHRdfX0gXHJpZ2h0YXJyb3cgTigwLDEpLiAgCiBcXQoKLSBBc3ltcHRvdGlzY2ggdm9sZ3QgZ2VzdGFuZGFhcmRpc2VlcmRlIHRlc3RzdGF0aXN0aWVrIGVlbiBzdGFuZGFhcmRub3JtYWFsIHZlcmRlbGluZyEKCi0tLQoKCldlIGlsbHVzdHJlcmVuIGRlIFdNVyB0ZXN0IGFhbiBkZSBoYW5kIHZhbiBkZSBSIGZ1bmN0aWUgYHdpbGNveC50ZXN0YC4KYGBge3J9CndpbGNveC50ZXN0KGNob2xlc3QgfiBncm91cCwgZGF0YSA9IGNob2wpCmBgYAoKLSBXZSB2ZXJ3ZXJwZW4gJEhfMCQgKCRwPSQgYHIgZm9ybWF0KHdpbGNveC50ZXN0KGNob2xlc3QgfiBncm91cCxkYXRhPWNob2wpJHAudmFsdWUsZGlnaXRzPTIpYCAkPDAuMDUkKQoKLSBEZSBvdXRwdXQgZ2VlZnQgZGUgdGVzdHN0YXRpc3RpZWsgJFc9JCBgciB3aWxjb3gudGVzdChjaG9sZXN0fmdyb3VwLGRhdGE9Y2hvbCkkc3RhdGlzdGljYD8KCi0gSW4gdm9sZ2VuZGUgbGlqbmVuIGJlcmVrZW5lbiB3ZSAgJFNfMSQgZW4gJFNfMiQgbWFudWVlbCB2b29yIGRlIGRhdGFzZXQuCmBgYHtyfQpTMSA8LSBjaG9sICU+JQogIG11dGF0ZShjaG9sUmFuaz1yYW5rKGNob2xlc3QpKSAlPiUKICBmaWx0ZXIoZ3JvdXA9PTEpICU+JQogIHB1bGwoY2hvbFJhbmspICU+JQogIHN1bQoKUzIgPC0gY2hvbCAlPiUKICBtdXRhdGUoY2hvbFJhbmsgPSByYW5rKGNob2xlc3QpKSAlPiUKICBmaWx0ZXIoZ3JvdXAgPT0gMikgJT4lCiAgcHVsbChjaG9sUmFuaykgJT4lCiAgc3VtCgpTMQpTMgpgYGAKCi0tLQoKV2FhciBrb210ICAkVz0kIGByIHdpbGNveC50ZXN0KGNob2xlc3R+Z3JvdXAsZGF0YT1jaG9sKSRzdGF0aXN0aWNgIHZhbmRhYW4/CgojIyMgTWFubiBhbmQgV2hpdG5leSB0ZXN0CgotIE1hbm4gZW4gV2hpdG5leSB0ZXN0IGluIGFmd2V6aWdoZWlkIHZhbiB0aWVzOgpcWwogVV8xID0gXHN1bV97aT0xfV57bl8xfVxzdW1fe2s9MX1ee25fMn0gXHRleHR7SX1cbGVmdFx7WV97aTF9XGdlcSBZX3trMn1ccmlnaHRcfS4KXF0KCi0gJFx0ZXh0e0l9XGxlZnRcey5ccmlnaHRcfSQ6IGluZGljYXRvciBpcyAxIGlzIGFscyAgdWl0ZHJ1a2tpbmcgd2FhciBpcyBlbiAwIGFscyBkaXQgbmlldCBoZXQgZ2V2YWwgaXMuCgotIFUgdGVsdCBob2V2ZWVsIGtlZXIgb2JzZXJ2YXRpZSB1aXQgZ3JvZXAgMSAkXGdlcSQgb2JzZXJ2YXRpZSB1aXQgZ3JvZXAgMi4KCmBgYHtyfQp5MSA8LSBjaG9sICU+JQogIGZpbHRlcihncm91cD09MSkgJT4lCiAgcHVsbCgiY2hvbGVzdCIpCgp5MiA8LSBjaG9sICU+JQogIGZpbHRlcihncm91cD09MikgJT4lCiAgcHVsbCgiY2hvbGVzdCIpCgp1MUhscCA8LSBzYXBwbHkoCiAgeTEsCiAgZnVuY3Rpb24oeTFpLHkyKSB7eTFpPj15Mn0sCiAgeTI9eTIpCgpjb2xuYW1lcyh1MUhscCkgPC0geTEKcm93bmFtZXModTFIbHApIDwtIHkyCmBgYAoKLS0tCgpgYGB7cn0KdTFIbHAKVTEgPC0gc3VtKHUxSGxwKQpVMQpgYGAKCkVyIGthbiB3b3JkZW4gYWFuZ2V0b29uZCBkYXQKCiQkVV8xID0gU18xIC0gXGZyYWN7MX17Mn1uXzEobl8xKzEpLiQkCgpgYGB7cn0KUzEtbkdyb3Vwc1sxXSoobkdyb3Vwc1sxXSsxKS8yCmBgYAoKLS0tCgoxLiAkVV8xJCBlbiAkU18xJCB6ZWxmZGUgaW5mb3JtYXRpZQoyLiAkVV8xJCBvb2sgcmFua3N0YXRpc3RpZWsKMy4gRXhhY3RlIHRlc3RlbiBnZWJhc2VlcmQgb3AgJFVfMSQgZW4gJFNfMSQgemlqbiBlcXVpdmFsZW50LgoKLS0tCgotICRVXzEkIGhlZWZ0IGludGVycHJldGF0aWV2b29yZGVlbAotIFN0ZWwgJFlfaiQgZWVuIHdpbGxla2V1cmlnZSB1aXRrb21zdCB1aXQgYmVoYW5kZWxpbmdzZ3JvZXAgJGokICgkaj0xLDIkKS4gRGFuIGdlbGR0ClxiZWdpbntlcW5hcnJheSp9CiAgXGZyYWN7MX17bl8xbl8yfVx0ZXh0e0V9XGxlZnRbVV8xXHJpZ2h0XQogICAgICY9JiBcdGV4dHtQfVxsZWZ0W1lfMSBcZ2VxIFlfMlxyaWdodF0uClxlbmR7ZXFuYXJyYXkqfQoKLSBJbnR1w690aWVmIHZvZWxlbiB3ZSBkaXQgYWFuOgoKICAtIE9wIGJhc2lzIHZhbiBzdGVla3Byb2VmIGt1bm5lbiB3ZSBrYW5zOiBnZW1pZGRlbGRlIHZhbiBhbGxlIGluZGljYXRvciB3YWFyZGVuICRcdGV4dHtJfVxsZWZ0XHtZX3tpMX1cZ2VxIFlfe2syfVxyaWdodFx9JC4KCiAgLSAkbl8xIFx0aW1lcyBuXzIkIHZlcmdlbGlqa2luZ2VuCgotLS0KCmBgYHtyfQptZWFuKHUxSGxwKQpVMS8obkdyb3Vwc1sxXSpuR3JvdXBzWzJdKQpgYGAKCgpcW1x0ZXh0e1B9XGxlZnRbWV8xIFxnZXEgWV8yXHJpZ2h0XVxdCndvcmR0IGVlbiAqKnByb2JhYmlsaXN0aXNjaGUgaW5kZXgqKiAoRW5nZWxzOiAqcHJvYmFiaWxpc3RpYyBpbmRleCopIGdlbm9lbWQuCgotIEthbnMgZGF0IGVlbiB1aXRrb21zdCB1aXQgZ3JvZXAxICRcZ2VxJCBkYW4gdWl0a29tc3QgdWl0IGdyb2VwIDIKCi0gT25kZXIgJEhfMCQ6ClxbXHRleHR7UH1cbGVmdFtZXzEgXGdlcSBZXzJccmlnaHRdPVxmcmFjezF9ezJ9XF0KCi0tLQoKLSBSIGZ1bmN0aWUgYHdpbGNveC50ZXN0YCBnZWVmdCBuaWV0IGRlIFdpbGNveG9uIHJhbmsgc3VtIHN0YXRpc3RpZWssIG1hYXIgd2VsIGRlIE1hbm4tV2hpdG5leSBzdGF0aXN0aWVrICRVXzEkLgotIFdlIGJla2lqa2VuIG5vZ21hYWxzIGRlIG91dHB1dApgYGB7cn0Kd1Rlc3QgPC0gd2lsY294LnRlc3QoY2hvbGVzdH5ncm91cCwgZGF0YSA9IGNob2wpCndUZXN0ClUxCnByb2JJbmQgPC0gd1Rlc3Qkc3RhdGlzdGljL3Byb2Qobkdyb3VwcykKcHJvYkluZApgYGAKCi0tLQoKLSBBYW5nZXppZW4gJHA9JCBgciBmb3JtYXQod1Rlc3QkcC52YWx1ZSxkaWdpdHM9MylgICQ8MC4wNSQgYmVzbHVpdGVuIHdlIG9wIGhldCAkNVwlJCBzaWduaWZpY2FudGllbml2ZWF1IGRhdCBkZSBnZW1pZGRlbGRlIGNob2xlc3Rvcm9sY29uY2VudHJhdGllIGdyb3RlciBpcyBiaWogaGFydHBhdGnDq250ZW4ga29ydCBuYSBlZW4gaGFydGFhbnZhbCBkYW4gYmlqIGdlem9uZGUgcGVyc29uZW4uICAoV2UgbmVtZW4gYWFuIGRhdCBsb2NhdGllLXNoaWZ0IG9wZ2FhdCkKCi0gV2Ugd2V0ZW4gb29rIGRhdCBlZW4gY2hvbGVzdG9yb2x3YWFyZGUgdmFuIGhhcnRwYXRpw6tudGVuIG1ldCBlZW4ga2FucyB2YW4KJFUxLyhuXzFcdGltZXMgbl8yKT0kIGByIHByb2JJbmQqMTAwYCUgZ3JvdGVyIGlzIGRpZSB2YW4gZ2V6b25kZSBwZXJzb25lbi4KCi0gV2Ugem91ZGVuIGRlIHZlcm9uZGVyc3RlbGxpbmcgdmFuIGRlIGxvY2F0aWUtc2hpZnQgbW9ldGVuIG5hZ2FhbiwgbWFhciBtZXQgc2xlY2h0cyA1IG9ic2VydmF0aWVzIGluIGVsa2UgYmVoYW5kZWxpbmdzZ3JvZXAgaXMgZGl0IHppbmxvb3MuCgotLS0KCi0gWm9uZGVyIGxvY2F0aWUtc2hpZnQgdmVyb25kZXJzdGVsbGluZyBibGlqZnQgZGUgY29uY2x1c2llIGluIHRlcm1lbiB2YW4gZGUgcHJvYmFiaWxpc3Rpc2NoZSBpbmRleCBjb3JyZWN0IQoKLSBEdXMgd2FubmVlciB3ZSBnZWVuIGxvY2F0aWUtc2hpZnQgdmVyb25kZXJzdGVsbGVuIGVuIGVlbiB0d2VlemlqZGlnZSB0ZXN0IHVpdHZvZXJlbiB0ZXN0ZW4gd2UgZWlnZW5saWprCgpcW0hfMDogRl8xPUZfMiBcdGV4dHsgdnMgUH0oWV8xIFxnZXEgWV8yKSBcbmVxIDAuNS5cXQoKCioqQ29uY2x1c2llOioqIEVyIGlzIGVlbiBzaWduaWZpY2FudCB2ZXJzY2hpbCBpbiBkZSBkaXN0cmlidXRpZSB2YW4gZGUgY2hvbGVzdG9yb2xjb25jZW50cmF0aWVzIGJpaiBoYXJ0cGF0acOrbnRlbiAyIGRhZ2VuIG5hIGh1biBoYXJ0YWFudmFsIGVuIGdlem9uZGUgaW5kaXZpZHVlbiAoJHA9JCBgciBmb3JtYXQod1Rlc3QkcC52YWx1ZSxkaWdpdHM9MylgKS4gSGV0IGlzIG1lZXIgd2FhcnNjaGlqbmxpamsgb20gZWVuIGhvZ2VyZSBjaG9sZXN0b3JvbGNvbmNlbnRyYXRpZXMgdGUgb2JzZXJ2ZXJlbiBoYXJ0cGF0acOrbnRlbiAgZGFuIGJpaiBnZXpvbmRlIGluZGl2aWR1ZW4uIERlIHB1bnRzY2hhdHRpbmcgdm9vciBkZXplIGthbnMgYmVkcmFhZ3QgYHIgcHJvYkluZCoxMDBgJS4KCi0tLQoKCiMgVmVyZ2VsaWprZW4gdmFuICRnJCBCZWhhbmRlbGluZ2VuCgotIFZlcmFsZ2VtZW5lbiBuYWFyIG5pZXQtcGFyYW1ldHJpc2NoZSB0ZWdlbmhhbmdlcnMgdmFuIGRlICRGJC10ZXN0IHVpdCBlZW4gb25lLXdheSBBTk9WQS4KCi0tLQoKIyMgRE1IIFZvb3JiZWVsZAoKMSwyLWRpbWV0aHlsaHlkcmF6aW5lIGRpaHlkcm9jaGxvcmlkZSAoRE1IKSB0ZXN0ZW4gb3AgZ2Vub3RveGljaXRlaXQgKEVVIGRpcmVjdGl2ZSkKCi0gMjQgcmF0dGVuCi0gVmllciBncm9lcGVuIHZvbGdlbnMgZGFnZWxpamtzZSBETUggZG9zaXMKCiAgLSBjb250cm9sZQogIC0gbGFhZwogIC0gbWVkaXVtCiAgLSBob29nCgotIEdlbm90b3hpY2l0ZWl0IGluIGRlIGxldmVyIGEuZC5oLnYuIGVlbiBjb21ldCBhc3NheSBvcCAxNTAgbGV2ZXJjZWxsZW4gcGVyIHJhdC4KLSBEZSBvbmRlcnpvZWtlcnMgd2Vuc2VuIG5hIHRlIGdhYW4gb2YgdmVyc2NoaWxsZW4gemlqbiBpbiBkZSBETkEgc2NoYWRlIHRlbmdldm9sZ2UgdmFuIGRlIERNSCBkb3Npcy4KCi0tLQoKQ29tZXQgQXNzYXk6CgotIEROQSBzdHJlbmdicmV1a2VuIHZpc3VhbGlzZXJlbgotIExlbmd0ZSBjb21ldCBzdGFhcnQgaXMgcHJveHkgdm9vciBzdHJlbmdicmV1a2VuLgoKIVtDb21ldCBhc3NheV0oaHR0cHM6Ly9naXRodWIuY29tL3N0YXRPbWljcy9zYmMyMC9yYXcvbWFzdGVyL2ZpZ3VyZXMvY29tZXQuanBnKXsgd2lkdGg9NTAlIH0KCgotLS0KCmBgYHtyfQpkbmEgPC0gcmVhZF9kZWxpbSgiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL3N0YXRPbWljcy9zYmMyMC9tYXN0ZXIvZGF0YS9kbmEudHh0IixkZWxpbT0iICIpCmRuYSA8LSBkbmEgJT4lCiAgbXV0YXRlKGRvc2UgPSBhcy5mYWN0b3IoZG5hJGRvc2UpKQpkbmEKYGBgCgotLS0KCmBgYHtyLCBlY2hvPUZBTFNFLG91dC53aWR0aD0nMTAwJScsIGZpZy5hc3A9LjgsIGZpZy5hbGlnbj0nY2VudGVyJ30KZG5hICU+JQogIGdncGxvdChhZXMoeD1kb3NlLHk9bGVuZ3RoLGZpbGw9ZG9zZSkpKwogIGdlb21fYm94cGxvdCgpICsKICBnZW9tX3BvaW50KHBvc2l0aW9uPSJqaXR0ZXIiKQoKZG5hICU+JQogIGdncGxvdChhZXMoc2FtcGxlPWxlbmd0aCkpICsKICBnZW9tX3FxKCkgKwogIGdlb21fcXFfbGluZSgpICsKICBmYWNldF93cmFwKH5kb3NlKQpgYGAKCi0gSW5kaWNhdGllIGRhdCBjb250cm9sZSBncm9lcCBhbmRlcmUgdmFyaWFiaWxpdGVpdCBoZWVmdC4KLSA2IG9ic2VydmF0aWVzIHBlciBncm9lcCB0ZSB3ZWluaWcgb20gYWFubmFtZXMgbmEgdGUgZ2Fhbi4KCgotLS0KCmBgYHtyLCBlY2hvPUZBTFNFLG91dC53aWR0aD0nMTAwJScsIGZpZy5hc3A9LjgsIGZpZy5hbGlnbj0nY2VudGVyJ30KbG0obGVuZ3RoIH4gZG9zZSwgZGF0YSA9IGRuYSkgJT4lCiAgcGxvdApgYGAKCi0tLQoKIyMgS3J1c2thbC1XYWxsaXMgUmFuayBUZXN0CgotIERlIEtydXNrYWwtV2FsbGlzIFJhbmsgVGVzdCAoS1ctdGVzdCkgaXMgZWVuIG5pZXQtcGFyYW1ldGVyaXNjaCBhbHRlcm5hdGllZiB2b29yIGRlIEFOT1ZBIEYtdGVzdC4gIAoKLSAga2xhc3NpZWtlICRGJC10ZXN0c3RhdGlzdGllayBrYW4gZ2VzY2hyZXZlbiB3b3JkZW4gYWxzCiAgXFsKICAgIEYgPSBcZnJhY3tcdGV4dHtTU1R9LyhnLTEpfXtcdGV4dHtTU0V9LyhuLWcpfSA9IFxmcmFje1x0ZXh0e1NTVH0vKGctMSl9eyhcdGV4dHtTU1RvdH0tXHRleHR7U1NUfSkvKG4tZyl9ICwKICBcXQotICBtZXQgJGckIGhldCBhYW50YWwgZ3JvZXBlbi4KCi0gU1NUb3QgaGFuZ3QgZW5rZWwgYWYgdmFuIHVpdGtvbXN0ZW4gJFxtYXRoYmZ7eX0kIGVuIHphbCBuaWV0IHZhcmnDq3JlbiBiaWogcGVybXV0YXRpZXMuCi0gVm9sZG9lbmRlIG9tIFNTVCBhbHMgdGVzdHN0YXRpc3RpZWsgdGUgZ2VicnVpa2VuLgogJCRcdGV4dHtTU1R9PVxzdW1fe2o9MX1edCBuX2ooXGJhcntZfV9qLVxiYXJ7WX0pXjIkJAoKLS0tCgotICBEZSBLVyB0ZXN0c3RhdGlzdGllayBtYWFrdCBnZWJydWlrIHZhbiBTU1QgbWFhciBkYW4gZ2ViYXNlZXJkIG9wIGRlIHJhbmstZ2V0cmFuc2Zvcm1lZXJkZSB1aXRrb21zdGVuXlt3ZSB2ZXJvbmRlcnN0ZWxsZW4gYWZ3ZXppZ2hlaWQgdmFuICp0aWVzKl0sCiAgXFsKICAgICBcdGV4dHtTU1R9ID0gXHN1bV97aj0xfV5nIG5faiBcbGVmdChcYmFye1J9X2ogLSBcYmFye1J9XHJpZ2h0KV4yID0gXHN1bV97aj0xfV50IG5faiBcbGVmdChcYmFye1J9X2ogLSBcZnJhY3tuKzF9ezJ9XHJpZ2h0KV4yICwKICBcXQotICBtZXQgJFxiYXJ7Un1faiQgaGV0IGdlbWlkZGVsZGUgdmFuIGRlIHJhbmtzIGluIGJlaGFuZGVsaW5nc2dyb2VwICRqJCwgZW4gJFxiYXJ7Un0kIGhldCBnZW1pZGRlbGRlIHZhbiBhbGxlIHJhbmtzLAogIFxbCiAgICBcYmFye1J9ID0gXGZyYWN7MX17bn0oMSsyK1xjZG90cyArIG4pID0gXGZyYWN7MX17bn1cZnJhY3sxfXsyfW4obisxKSA9IFxmcmFje24rMX17Mn0uCiAgXF0KLSAgRGUgS1cgdGVzdHN0YXRpc3RpZWsgd29yZHQgZ2VnZXZlbiBkb29yCiAgXFsKICAgIEtXID0gXGZyYWN7MTJ9e24obisxKX0gIFxzdW1fe2o9MX1eZyBuX2ogXGxlZnQoXGJhcntSfV9qIC0gXGZyYWN7bisxfXsyfVxyaWdodCleMi4KICBcXQotICBEZSBmYWN0b3IgJFxmcmFjezEyfXtuKG4rMSl9JCB6b3JndCBlcnZvb3IgZGF0ICRLVyQgZWVuIGVlbnZvdWRpZ2UgYXN5bXB0b3Rpc2NoZSBudWxkaXN0cmlidXRpZSBoZWVmdC4gSW4gaGV0IGJpanpvbmRlciwgb25kZXIgJEhfMCQsIGFscyAkXG1pbihuXzEsXGxkb3RzLCBuX2cpXHJpZ2h0YXJyb3cgXGluZnR5JCwKICBcWwogICAgS1cgIFxyaWdodGFycm93IFxjaGleMl97dC0xfS4KICBcXQoKLS0tCgotICBFeGFjdGUgS1ctdGVzdCB2aWEgcGVybXV0YXRpZW51bGRpc3RyaWJ1dGllIChkaWUgZW5rZWwgYWZoYW5ndCB2YW4gJG5fMSwgXGxkb3RzLCBuX2ckKQogICQkSF8wOiBmXzE9XGxkb3RzPWZfZyBcdGV4dHsgdnMgfSBIXzE6IFx0ZXh0eyBtaW5zdGVucyB0d2VlIGdlbWlkZGVsZGVuIHZlcnNjaGlsbGVuZH0uJCQKCi0gTG9jYXRpZS1zaGlmdAoKLSBJbmRpZW4gbG9jYXRpZS1zaGlmdCBuaWV0IG9wZ2FhdCwgbW9ldCAkSF8xJCBnZWZvcm11bGVlcmQgd29yZGVuIGluIHRlcm1lbiB2YW4gcHJvYmFiaWxpc3Rpc2NoZSBpbmRleGVuOgogICQkSF8wOiBmXzE9XGxkb3RzPWZfZyBcdGV4dHsgdnMgfSBIXzE6IFxleGlzdHNcIGosayBcaW4gXHsxLFxsZG90cyxnXH0gOiBcdGV4dHtQfVxsZWZ0W1lfalxnZXEgWV9rXHJpZ2h0XVxuZXEgMC41JCQKCi0tLQoKIyMgRE5BIFNjaGFkZSBWb29yYmVlbGQKCmBgYHtyfQprcnVza2FsLnRlc3QobGVuZ3RoIH4gZG9zZSwgZGF0YSA9IGRuYSkKYGBgCgotIE9wICQ1XCUkIHNpZ25pZmljYW50aWVuaXZlYXUga2FuIG51bGh5cG90aGVzZSB3b3JkZW4gdmVyd29ycGVuLgoKLSBSLWZ1bmN0aWUgYGtydXNrYWwudGVzdGAgZW5rZWwgYXN5bXB0b3Rpc2NoZSBiZW5hZGVyaW5nIHZvb3IgYmVyZWtlbmluZyB2YW4gJHAkLXdhYXJkZW4uCgotIE1ldCBzbGVjaHRzIDYgb2JzZXJ2YXRpZXMgcGVyIGdyb2VwLCBpcyBkaXQgZ2VlbiBvcHRpbWFsZSBiZW5hZGVyaW5nIHZhbiBkZSBleGFjdGUgJHAkLXdhYXJkZSEKCi0tLQoKLSAgTWV0IGRlIGBjb2luYCBSIHBhY2thZ2Uga2FuIGRlIGV4YWN0ZSAkcCQtd2FhcmRlIHdlbCBiZXJla2VuZW4KCmBgYHtyLHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRX0KbGlicmFyeShjb2luKQprd1Blcm0gPC0ga3J1c2thbF90ZXN0KGxlbmd0aCB+IGRvc2UsIGRhdGEgPSBkbmEsCgkJICAgIGRpc3RyaWJ1dGlvbiA9IGFwcHJveGltYXRlKG5yZXNhbXBsZSA9IDEwMDAwMCkpCmt3UGVybQpgYGAKCi0gV2UgYmVzbHVpdGVuIGRhdCBlciBlZW4gZXh0cmVlbSBzaWduaWZpY2FudCB2ZXJzY2hpbCBpcyBpbiBkaXN0cmlidXRpZSB2YW4gZGUgRE5BIHNjaGFkZSB0ZW4gZ2V2b2xnZSB2YW4gZGUgZG9zaXMuCgotLS0KCiMjIFBvc3Rob2MgYW5hbHlzZQoKLSBXZWxrZSBncm9lcGVuIHppam4gdmVyc2NoaWxsZW5kPz8/CgotIFBvc3Rob2MgYW5hbHlzZSBhLmQuaC52IFdNVyB0ZXN0ZW4KCi0gRWlnZW5saWprIG5pZXQgb3B0aW1hYWwgbmEgS1ctdGVzdCB3YW50IGRlIGRhdGEgd29yZGVuIG9wbmlldXcgZ2VyYW5nc2NoaWt0IQogICAgLSBLVyBnZWJhc2VlcmQgb3ZlciByYW5rcyBiZXBhYWxkZSBvdmVyIGFsbGUgZ3JvZXBlbgogICAgLSBXTVcgZ2ViYXNlZXJkIG9wIHJhbmtzIHZhbiB0d2VlIGdyb2VwZW4gaW4gdmVyZ2VsaWpraW5nCgotIEJldGVyZSBhbHRlcm5hdGlldmVuIGJlc3RhYW4gbWFhciB2YWxsZW4gYnVpdGVuIGJlc3RlayB2YW4gZGUgY3Vyc3VzCgpgYGB7cn0KcGFpcndpc2Uud2lsY294LnRlc3QoZG5hJGxlbmd0aCxkbmEkZG9zZSkKYGBgCgotIEFsbGUgRE1IIGJlaGFuZGVsaW5nZW4gdmVyc2NoaWxsZW4gc2lnbmlmaWNhbnQgdmFuIGRlIGNvbnRyb2xlLgotIFUxIG5pZXQgaW4gYHBhaXJ3aXNlLndpbGNveC50ZXN0YCBvdXRwdXQuICBQdW50c2NoYXR0ZXIgb3AgZGUga2FucyBvcCBob2dlcmUgRE5BLXNjaGFkZT8KCi0tLQoKYGBge3IsIGVjaG89RkFMU0V9CnBhaXJXaWxjb3ggPC0gcGFpcndpc2Uud2lsY294LnRlc3QoZG5hJGxlbmd0aCxkbmEkZG9zZSkKYGBgCgpgYGB7cn0Kbkdyb2VwIDwtIHRhYmxlKGRuYSRkb3NlKQpwcm9iSW5kIDwtIGNvbWJuKAogIGxldmVscyhkbmEkZG9zZSksCiAgMiwKICBmdW5jdGlvbih4KSB7CgkJIHRlc3QgPC0gd2lsY294LnRlc3QoCiAgICAgICBsZW5ndGh+ZG9zZSwKICAgICAgIGRuYSAlPiUgZmlsdGVyKGRvc2UlaW4leCkKICAgICAgICkKCQkgcmV0dXJuKHRlc3Qkc3RhdGlzdGljL3Byb2Qobkdyb2VwW3hdKSkKCX0pCm5hbWVzKHByb2JJbmQpIDwtIGNvbWJuKAogIGRuYSAlPiUgcHVsbChkb3NlKSAlPiUgbGV2ZWxzLAogIDIsCiAgcGFzdGUsCiAgY29sbGFwc2U9InZzIikKcHJvYkluZApgYGAKCk9tZGF0IGVyIHR3aWpmZWxzIHppam4gb2YgaGV0IGxvY2F0aWUtc2hpZnQgbW9kZWwgZ2VsZGlnIGlzLCBkb2VuIHdlIGVua2VsIHVpdHNwcmFrZW4gaW4gdGVybWVuIHZhbiBkZSBwcm9iYWJpbGlzdGlzY2hlIGluZGV4LgoKLS0tCgojIyBDb25jbHVzaWUKCi0gRXIgZXh0cmVlbSBzaWduaWZpY2FudCB2ZXJzY2hpbCBpcyBpbiBkZSBkaXN0cmlidXRpZSB2YW4gZGUgRE5BLXNjaGFkZSBtZXRpbmdlbiB0ZW5nZXZvbGdlIHZhbiBkZSBETUggYmVoYW5kZWxpbmcgKCRwPDAuMDAxJCBLVy10ZXN0KS4KLSBETkEtc2NoYWRlIGlzIG1lZXIgd2FhcnNjaGlqbmxpamsgbmEgYmVoYW5kZWxpbmcgbWV0IERNSCBkYW4gaW4gZGUgY29udHJvbGUgYmVoYW5kZWxpbmcgKGFsbGUgcD0wLjAxMywgV01XLXRlc3RlbikuCi0gRGUga2Fuc2VuIG9wIGhvZ2VyZSBETkEtc2NoYWRlIG5hIGJsb290c3RlbGxpbmcgYWFuIERNSCBiZWRyYWFndCAxMDAlIChCZXJla2VuZW4gdmFuIEJJIG9wIGthbnMgYnVpdGVuIGJlc3RlayB2YW4gY3Vyc3VzKS4KLSBFciB6aWpuIGdlZW4gc2lnbmlmaWNhbnRlIHZlcnNjaGlsbGVuIGluIGRlIGRpc3RyaWJ1dGllcyB2YW4gZGUgY29taXQtbGVuZ3RlcyB0dXNzZW4gZGUgRE1IIGJlaGFuZGVsaW5nZW4gb25kZXJsaW5nICgkcD0kIGByIHBhc3RlKGZvcm1hdChyYW5nZShwYWlyV2lsY294JHAudmFsdWVbLC0xXSxuYS5ybT1UUlVFKSxkaWdpdD0yKSxjb2xsYXBzZT0iLSIpYCkuCi0gRE1IIHZlcnRvb250IGR1cyBhbCBiaWogZGUgbGFnZSBkb3NpcyBnZW5vdG94aXNjaGUgZWZmZWN0ZW4uCi0gKEFsbGUgcGFhcnNnZXdpanplIHRlc3RlbiB3ZXJkZW4gZ2Vjb3JyaWdlZXJkIHZvb3IgbXVsdGlwbGUgdGVzdGluZyBkLm0udi4gSG9sbSdzIG1ldGhvZGUpLgo=