Het is geweten dat PCBs (Polychlorinated biphenyls, o.a. gebruikt in koelelementen en smeermiddel) makkelijk opstapelen in het vetweefsel van garnalen. In dit experiment werden twee groepen van elk 18 samples van garnalen gekweekt in verschillende condities. De garnalen werden gerandomiseerd over de twee groepen, en de PCB concentratie werd gemeten door het vetweefsel te extraheren van 100g garnalen in een sample. De onderzoeksvraag is om na te gaan of de PCB concentratie beïnvloed wordt door de groeicondities. De PCB concentraties werden gemeten in pg/g vet.
shrimps <- read.table("/Users/koenvandenberge/Dropbox/PhD/Onderwijs/Statistiek Biochemie/201819/dropboxStats1819/class6_nonPar/full/shrimps.txt")
shrimps$group <- factor(shrimps$group)
Data-exploratie
table(shrimps$group)
1 2
18 18
boxplot(PCB.conc ~ group, data=shrimps)

De ``outliers’’ in de data werden dubbel gecheckt door de onderzoekers en zijn correcte metingen.
par(mfrow = c(1,2))
qqnorm(shrimps$PCB.conc[shrimps$group == 1])
qqline(shrimps$PCB.conc[shrimps$group == 1])
qqnorm(shrimps$PCB.conc[shrimps$group == 2])
qqline(shrimps$PCB.conc[shrimps$group == 2])
par(mfrow = c(1,1))

Conclusie:
- De data lijken niet afkomstig te zijn uit een Normale verdeling;
- Er zijn onvoldoende observaties om te berusten op de centrale limiet stelling;
- De varianties in beide groepen zijn niet gelijk;
- Er zijn grote outliers.
Geen enkel van de parametrische toetsen die we reeds gezien hebben kunnen gebruikt worden voor deze data analyse. We zullen dus beroep doen op niet-parametrische methoden.
Permutatie-test
Bij een permutatietest testen we of er gelijkheid is in distributies tussen groepen. De nulhypothese kan men dus schrijven als:
\[ H_0: f_1(y) = f_2(y) \]
In de alternatieve hypothese wordt verondersteld dat beide groepen een gelijke distributie hebben, maar met een verschillend gemiddelde:
\[ H_1: f_1(y) = f_2(y + \Delta) \]
Hierbij is \(f_1(y)\) de distributie voor de PBC concentraties in groeiconditie 1, en \(f_2(y)\) voor groeiconditie 2. Onder de alternatieve hypothese, stelt \(\Delta\) het verschil in gemiddelde voor tussen groep 1 en groep 2. Merk op dat \(\Delta\) zowel positief als negatief kan zijn.
We zullen eerst de geobserveerde test-statistiek van de two-sample t-test berekenen.
t.test(PCB.conc~group, data=shrimps)
Welch Two Sample t-test
data: PCB.conc by group
t = 0.085098, df = 19.805, p-value = 0.933
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
-14.90106 16.16773
sample estimates:
mean in group 1 mean in group 2
46.63889 46.00556
t.obs <- t.test(PCB.conc~group, data=shrimps)$statistic
Aangezien niet aan de assumpties voor de two-sample t-test voldaan is, zal de theoretische nuldistributie niet opgaan voor de geobserveerde teststatistiek. Hierdoor zullen we zelf een nuldistributie berekenen op basis van de data.
N <- 10000 #1000 permutaties
t.star <- c() #initialiseer een vector met permutatie teststatistieken
group.labels <- shrimps$group #groep labels: om te permuteren
perm.data <- shrimps #kopieer originele dataset voor permutatie test
for(i in 1:N) { #doe 1 tot N keer
perm.labels <- sample(group.labels,replace=F) # willekeurige herschikking van de groep labels
perm.data$group <- perm.labels #voeg willekeurige groeplabels toe aan originele dataset
t.star <- c(t.star,t.test(PCB.conc~group,data=perm.data)$statistic) #voeg permutatie teststatistiek toe aan vector.
}
hist(t.star) #de nuldistributie
abline(v=t.obs, col="red") #geobserveerde teststatistiek = rode lijn

We zien dat de geobserveerde \(t\)-teststatistiek niet extreem is in vergelijking met de nuldistributie. We kunnen de nuldistributie gebruiken om de (tweezijdige) p-waarde te berekenen:
pvalue <- 2*mean(t.star >= t.obs)
pvalue
[1] 0.926
We bekomen een heel hoge p-waarde. We vinden aldus onvoldoende bewijs voor een verschil in gemiddelde PBC concentratie tussen de twee groeicondities op het 5% significantieniveau (p = 0.02). Merk op dat iedereen een andere p-waarde zal uitkomen vanwege het willekeurig herordenen van de groep-labels in de simulatie. Om een reproduceerbare uitkomst te bekomen kan je een seed gebruiken a.d.h.v. set.seed
(zie cursus)
Rank test
Bovenstaande permutatietest testte voor een verschil in gemiddelde. De test was echter computationeel intensief: we moesten duizenden keer opnieuw de teststatistiek berekenen. Voor deze studie was dat nog haalbaar, en verloopt het uitvoeren van de test over een tijdspanne van enkele seconden. Echter, in moderne hoog-dimensionale biologische datasets zijn permutatietesten vaak niet haalbaar. Denk maar aan genexpressie data, waar men een test zou kunnen uitvoeren voor meer dan \(50 000\) menselijke transcripten. Bovendien dient men in die context een erg accurate p-waarde te bekomen (dus gebaseerd op een groot aantal permutaties, zeker in de orde van miljoenen) aangezien de correctie voor meervoudig toetsen erg groot zal zijn. In deze sectie zullen we dus een alternatieve niet-parametrische toets uitvoeren, namelijk een rank test. Merk op dat permutatietesten ook enkel geldig zijn indien we het locatie-shift model veronderstellen, in andere woorden, indien we veronderstellen dat beide groepen een zelfde distributie hebben. Indien we deze assumptie ook nemen bij rank testen, kunnen we het resultaat van de rank test interpreteren in functie van een verschil in de mediaan. Het is logisch dat we hier geen interpretatie in functie van de gemiddelden zullen kunnen bekomen, aangezien we de gemiddelden niet gebruiken in het berekenen van de teststatistiek. Echter, rank-testen zijn ook geldig indien het locatie-shift model niet opgaat. In dat geval, kunnen we het resultaat interpreteren in functie van de probabilistische index \(P(Y_{1} \ge Y_2)\).
Bij rank tests wordt de data \(Y_i\) getransformeerd naar ranks \[ R_i=R(Y_i) = \#\{Y_j: Y_j\leq Y_i; j=1,\ldots, n\}. \] Ranks zijn erg robuust voor outliers: of de hoogste observatie nu een waarde van 100 of 10 heeft, het blijft dezelfde rank behouden. In het geval van ties, dit zijn gelijke waarden, worden midranks gebruikt: \[R(Y_i) = \frac{\sum\limits_{\forall j : Y_j=Y_i}R(Y_j)}{\#{\forall j:Y_j=Y_i}} \] dit is, de midrank is het gemiddelde van de ranks van de gelijke observaties.
Vervolgens kan men de gemiddelde rank vergelijken tussen de twee groepen aan de hand van de Wilcoxon-Mann-Whitney (WNW) test.
wilcox.test(PCB.conc~group, data = shrimps)
Wilcoxon rank sum test
data: PCB.conc by group
W = 88, p-value = 0.01871
alternative hypothesis: true location shift is not equal to 0
We vinden dat de test significant is (op het 5%-significantieniveau), maar wachten nog even met de interpretatie van het resultaat. De Wilcoxon test hierboven is standaard een exacte test (zie vierde paragraaf in sectie Details in ?wilcox.test
). Dit wil zeggen dat de theoretische distributies voor onze steekproefgroottes gebruikt worden als nuldistributie, in plaats van permutaties. Hieronder gaan we na of het volgend resultaat ook bekomen wordt indien we zelf permuteren.
N <- 10000 #1000 permutaties
W.star <- c() #initialiseer een vector met permutatie teststatistieken
group.labels <- shrimps$group #groep labels: om te permuteren
perm.data <- shrimps #kopieer originele dataset voor permutatie test
for(i in 1:N) { #doe 1 tot N keer
perm.labels<-sample(group.labels,replace=F) # willekeurige herschikking van de groep labels
perm.data$group<-perm.labels #voeg willekeurige groeplabels toe aan originele dataset
W.star[i] = wilcox.test(PCB.conc~group, data=perm.data)$statistic #voeg permutatie teststatistiek toe aan vector.
}
hist(W.star)
abline(v=88, col=2)

pvalue <- 2*mean(W.star<=88)
pvalue #via manuele permutaties vinden we inderdaad een gelijkaardige p-waarde
[1] 0.0172
De p-waarde is uiteraard niet exact gelijk omdat dit slechts een benadering is, maar komt wel dicht in de buurt! Merk op dat de teststatistiek kan bekomen worden door de som te nemen van de ranks van één van de groepen die men test. Aangezien we geen gemiddelden van de data gebruiken in de test, kunnen we de test uiteraard ook niet interpreteren in termen van deze gemiddelden. Via de ranks kunnen we het resultaat echter wel interpreteren aan de hand van de probabilistische index. De nulhypothese stelt dat de distributies van de probabiliteitsdensiteitsfuncties in beide groepen gelijk zijn.
\[ H_0: f_1 = f_2 \]
In woorden: de verdeling van PCB concentraties in garnalen zijn in beide condities gelijk. In termen van probabilistische index, kunnen we de nulhypothese ook formuleren als:
\[ H_0: P(Y_{i1} \geq Y_{i2}) = 1/2 \]
De alternatieve hypothese kan in termen van de probabilistische index kan men scrhijven als volgt:
\[ H_1: P(Y_{i1} \geq Y_{i2}) \ne 1/2 \]
In woorden: de kans dat een willekeurige observatie van de PCB concentratie van garnalen die opgegroeid werden in conditie 1 groter dan of gelijk is aan een willekeurige observatie van de PCB concentratie van garnalen die opgegroeid werden in conditie 2 is niet gelijk aan 50%.
Deze kans, die wordt aangenomen 50% te zijn onder de nulhypothese, kan men bekomen aan de hand van de geobserveerde teststatistiek:
n1 <- n2 <- 18 #18 observaties in elke groep
WObs <- wilcox.test(PCB.conc~group, data=shrimps)$statistic #geobserveerde teststatistiek
WObs/(n1*n2)
W
0.2716049
De puntschatting voor deze kans is dus 27.2%.
We interpreteren dit als volgt: De kans dat de PCB concentratie in een willekeurige garnaal die werd opgegroeid in conditie 1 groter of gelijk is aan de PCB concentratie in een willekeurige garnaal die werd opgegroeid in conditie 2 is gelijk aan 27.2%.
Of nog:
De kans dat de PCB concentratie in een willekeurige garnaal die werd opgegroeid in conditie 1 kleiner is dan de PCB concentratie in een willekeurige garnaal die werd opgegroeid in conditie 2 is gelijk aan 72.8%.
Deze kans verschilt significant van 50% op het 5% significantieniveau (p=0.019).
LS0tCnRpdGxlOiAiTmlldCBwYXJhbWV0cmlzY2hlIHN0YXRpc3RpZWsiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCkhldCBpcyBnZXdldGVuIGRhdCBQQ0JzIChQb2x5Y2hsb3JpbmF0ZWQgYmlwaGVueWxzLCBvLmEuIGdlYnJ1aWt0IGluIGtvZWxlbGVtZW50ZW4gZW4gc21lZXJtaWRkZWwpIG1ha2tlbGlqayBvcHN0YXBlbGVuIGluIGhldCB2ZXR3ZWVmc2VsIHZhbiBnYXJuYWxlbi4KSW4gZGl0IGV4cGVyaW1lbnQgd2VyZGVuIHR3ZWUgZ3JvZXBlbiB2YW4gZWxrIDE4IHNhbXBsZXMgdmFuIGdhcm5hbGVuIGdla3dlZWt0IGluIHZlcnNjaGlsbGVuZGUgY29uZGl0aWVzLgpEZSBnYXJuYWxlbiB3ZXJkZW4gZ2VyYW5kb21pc2VlcmQgb3ZlciBkZSB0d2VlIGdyb2VwZW4sIGVuIGRlIFBDQiBjb25jZW50cmF0aWUgd2VyZCBnZW1ldGVuIGRvb3IgaGV0IHZldHdlZWZzZWwgdGUgZXh0cmFoZXJlbiB2YW4gMTAwZyBnYXJuYWxlbiBpbiBlZW4gc2FtcGxlLgpEZSBvbmRlcnpvZWtzdnJhYWcgaXMgb20gbmEgdGUgZ2FhbiBvZiBkZSBQQ0IgY29uY2VudHJhdGllIGJlw69udmxvZWQgd29yZHQgZG9vciBkZSBncm9laWNvbmRpdGllcy4KRGUgUENCIGNvbmNlbnRyYXRpZXMgd2VyZGVuIGdlbWV0ZW4gaW4gcGcvZyB2ZXQuCgpgYGB7cn0Kc2hyaW1wcyA8LSByZWFkLnRhYmxlKCIvVXNlcnMva29lbnZhbmRlbmJlcmdlL0Ryb3Bib3gvUGhEL09uZGVyd2lqcy9TdGF0aXN0aWVrIEJpb2NoZW1pZS8yMDE4MTkvZHJvcGJveFN0YXRzMTgxOS9jbGFzczZfbm9uUGFyL2Z1bGwvc2hyaW1wcy50eHQiKQpzaHJpbXBzJGdyb3VwIDwtIGZhY3RvcihzaHJpbXBzJGdyb3VwKQpgYGAKCiMjIyBEYXRhLWV4cGxvcmF0aWUKCmBgYHtyfQp0YWJsZShzaHJpbXBzJGdyb3VwKQpib3hwbG90KFBDQi5jb25jIH4gZ3JvdXAsIGRhdGE9c2hyaW1wcykKYGBgCgpEZSBgYG91dGxpZXJzJycgaW4gZGUgZGF0YSB3ZXJkZW4gZHViYmVsIGdlY2hlY2t0IGRvb3IgZGUgb25kZXJ6b2VrZXJzIGVuIHppam4gY29ycmVjdGUgbWV0aW5nZW4uCgpgYGB7cn0KcGFyKG1mcm93ID0gYygxLDIpKQpxcW5vcm0oc2hyaW1wcyRQQ0IuY29uY1tzaHJpbXBzJGdyb3VwID09IDFdKQpxcWxpbmUoc2hyaW1wcyRQQ0IuY29uY1tzaHJpbXBzJGdyb3VwID09IDFdKQpxcW5vcm0oc2hyaW1wcyRQQ0IuY29uY1tzaHJpbXBzJGdyb3VwID09IDJdKQpxcWxpbmUoc2hyaW1wcyRQQ0IuY29uY1tzaHJpbXBzJGdyb3VwID09IDJdKQpwYXIobWZyb3cgPSBjKDEsMSkpCmBgYAoKQ29uY2x1c2llOgoKIC0gRGUgZGF0YSBsaWprZW4gbmlldCBhZmtvbXN0aWcgdGUgemlqbiB1aXQgZWVuIE5vcm1hbGUgdmVyZGVsaW5nOwogLSBFciB6aWpuIG9udm9sZG9lbmRlIG9ic2VydmF0aWVzIG9tIHRlIGJlcnVzdGVuIG9wIGRlIGNlbnRyYWxlIGxpbWlldCBzdGVsbGluZzsKIC0gRGUgdmFyaWFudGllcyBpbiBiZWlkZSBncm9lcGVuIHppam4gbmlldCBnZWxpams7CiAtIEVyIHppam4gZ3JvdGUgb3V0bGllcnMuCiAKIEdlZW4gZW5rZWwgdmFuIGRlIHBhcmFtZXRyaXNjaGUgdG9ldHNlbiBkaWUgd2UgcmVlZHMgZ2V6aWVuIGhlYmJlbiBrdW5uZW4gZ2VicnVpa3Qgd29yZGVuIHZvb3IgZGV6ZSBkYXRhIGFuYWx5c2UuCiBXZSB6dWxsZW4gZHVzIGJlcm9lcCBkb2VuIG9wIG5pZXQtcGFyYW1ldHJpc2NoZSBtZXRob2Rlbi4KIAojIyBQZXJtdXRhdGllLXRlc3QKCkJpaiBlZW4gcGVybXV0YXRpZXRlc3QgdGVzdGVuIHdlIG9mIGVyIGdlbGlqa2hlaWQgaXMgaW4gZGlzdHJpYnV0aWVzIHR1c3NlbiBncm9lcGVuLiBEZSBudWxoeXBvdGhlc2Uga2FuIG1lbiBkdXMgc2NocmlqdmVuIGFsczoKClxbIEhfMDogZl8xKHkpID0gZl8yKHkpIFxdCgpJbiBkZSBhbHRlcm5hdGlldmUgaHlwb3RoZXNlIHdvcmR0IHZlcm9uZGVyc3RlbGQgZGF0IGJlaWRlIGdyb2VwZW4gZWVuIGdlbGlqa2UgZGlzdHJpYnV0aWUgaGViYmVuLCBtYWFyIG1ldCBlZW4gdmVyc2NoaWxsZW5kIGdlbWlkZGVsZGU6CgpcWyBIXzE6IGZfMSh5KSA9IGZfMih5ICsgXERlbHRhKSBcXQoKSGllcmJpaiBpcyAkZl8xKHkpJCBkZSBkaXN0cmlidXRpZSB2b29yIGRlIFBCQyBjb25jZW50cmF0aWVzIGluIGdyb2VpY29uZGl0aWUgMSwgZW4gJGZfMih5KSQgdm9vciBncm9laWNvbmRpdGllIDIuCk9uZGVyIGRlIGFsdGVybmF0aWV2ZSBoeXBvdGhlc2UsIHN0ZWx0ICRcRGVsdGEkIGhldCB2ZXJzY2hpbCBpbiBnZW1pZGRlbGRlIHZvb3IgdHVzc2VuIGdyb2VwIDEgZW4gZ3JvZXAgMi4gTWVyayBvcCBkYXQgJFxEZWx0YSQgem93ZWwgcG9zaXRpZWYgYWxzIG5lZ2F0aWVmIGthbiB6aWpuLgoKV2UgenVsbGVuIGVlcnN0IGRlIGdlb2JzZXJ2ZWVyZGUgdGVzdC1zdGF0aXN0aWVrIHZhbiBkZSB0d28tc2FtcGxlIHQtdGVzdCBiZXJla2VuZW4uCiAKYGBge3J9CnQudGVzdChQQ0IuY29uY35ncm91cCwgZGF0YT1zaHJpbXBzKQp0Lm9icyA8LSB0LnRlc3QoUENCLmNvbmN+Z3JvdXAsIGRhdGE9c2hyaW1wcykkc3RhdGlzdGljCmBgYAoKQWFuZ2V6aWVuIG5pZXQgYWFuIGRlIGFzc3VtcHRpZXMgdm9vciBkZSB0d28tc2FtcGxlIHQtdGVzdCB2b2xkYWFuIGlzLCB6YWwgZGUgdGhlb3JldGlzY2hlIG51bGRpc3RyaWJ1dGllIG5pZXQgb3BnYWFuIHZvb3IgZGUgZ2VvYnNlcnZlZXJkZSB0ZXN0c3RhdGlzdGllay4KSGllcmRvb3IgenVsbGVuIHdlIHplbGYgZWVuIG51bGRpc3RyaWJ1dGllIGJlcmVrZW5lbiBvcCBiYXNpcyB2YW4gZGUgZGF0YS4KCmBgYHtyfQpOIDwtIDEwMDAwICMxMDAwIHBlcm11dGF0aWVzCnQuc3RhciA8LSBjKCkgI2luaXRpYWxpc2VlciBlZW4gdmVjdG9yIG1ldCBwZXJtdXRhdGllIHRlc3RzdGF0aXN0aWVrZW4KZ3JvdXAubGFiZWxzIDwtIHNocmltcHMkZ3JvdXAgI2dyb2VwIGxhYmVsczogb20gdGUgcGVybXV0ZXJlbgpwZXJtLmRhdGEgPC0gc2hyaW1wcyAja29waWVlciBvcmlnaW5lbGUgZGF0YXNldCB2b29yIHBlcm11dGF0aWUgdGVzdApmb3IoaSBpbiAxOk4pIHsgI2RvZSAxIHRvdCBOIGtlZXIKICBwZXJtLmxhYmVscyA8LSBzYW1wbGUoZ3JvdXAubGFiZWxzLHJlcGxhY2U9RikgIyB3aWxsZWtldXJpZ2UgaGVyc2NoaWtraW5nIHZhbiBkZSBncm9lcCBsYWJlbHMKICBwZXJtLmRhdGEkZ3JvdXAgPC0gcGVybS5sYWJlbHMgI3ZvZWcgd2lsbGVrZXVyaWdlIGdyb2VwbGFiZWxzIHRvZSBhYW4gb3JpZ2luZWxlIGRhdGFzZXQKICB0LnN0YXIgPC0gYyh0LnN0YXIsdC50ZXN0KFBDQi5jb25jfmdyb3VwLGRhdGE9cGVybS5kYXRhKSRzdGF0aXN0aWMpICN2b2VnIHBlcm11dGF0aWUgdGVzdHN0YXRpc3RpZWsgdG9lIGFhbiB2ZWN0b3IuCn0KaGlzdCh0LnN0YXIpICNkZSBudWxkaXN0cmlidXRpZQphYmxpbmUodj10Lm9icywgY29sPSJyZWQiKSAjZ2VvYnNlcnZlZXJkZSB0ZXN0c3RhdGlzdGllayA9IHJvZGUgbGlqbgoKYGBgCgoKV2UgemllbiBkYXQgZGUgZ2VvYnNlcnZlZXJkZSAkdCQtdGVzdHN0YXRpc3RpZWsgbmlldCBleHRyZWVtIGlzIGluIHZlcmdlbGlqa2luZyBtZXQgZGUgbnVsZGlzdHJpYnV0aWUuCldlIGt1bm5lbiBkZSBudWxkaXN0cmlidXRpZSBnZWJydWlrZW4gb20gZGUgKHR3ZWV6aWpkaWdlKSBwLXdhYXJkZSB0ZSBiZXJla2VuZW46CgpgYGB7cn0KcHZhbHVlIDwtIDIqbWVhbih0LnN0YXIgPj0gdC5vYnMpCnB2YWx1ZQpgYGAKCldlIGJla29tZW4gZWVuIGhlZWwgaG9nZSBwLXdhYXJkZS4KV2UgdmluZGVuIGFsZHVzIG9udm9sZG9lbmRlIGJld2lqcyB2b29yIGVlbiB2ZXJzY2hpbCBpbiBnZW1pZGRlbGRlIFBCQyBjb25jZW50cmF0aWUgdHVzc2VuIGRlIHR3ZWUgZ3JvZWljb25kaXRpZXMgb3AgaGV0IDUlIHNpZ25pZmljYW50aWVuaXZlYXUgKHAgPSBgciByb3VuZChwdmFsdWUsMilgKS4KKipNZXJrIG9wIGRhdCBpZWRlcmVlbiBlZW4gYW5kZXJlIHAtd2FhcmRlIHphbCB1aXRrb21lbiB2YW53ZWdlIGhldCB3aWxsZWtldXJpZyBoZXJvcmRlbmVuIHZhbiBkZSBncm9lcC1sYWJlbHMgaW4gZGUgc2ltdWxhdGllLiBPbSBlZW4gcmVwcm9kdWNlZXJiYXJlIHVpdGtvbXN0IHRlIGJla29tZW4ga2FuIGplIGVlbiBzZWVkIGdlYnJ1aWtlbiBhLmQuaC52LiBgc2V0LnNlZWRgICh6aWUgY3Vyc3VzKSoqCgojIyBSYW5rIHRlc3QKCkJvdmVuc3RhYW5kZSBwZXJtdXRhdGlldGVzdCB0ZXN0dGUgdm9vciBlZW4gdmVyc2NoaWwgaW4gZ2VtaWRkZWxkZS4KRGUgdGVzdCB3YXMgZWNodGVyIGNvbXB1dGF0aW9uZWVsIGludGVuc2llZjogd2UgbW9lc3RlbiBkdWl6ZW5kZW4ga2VlciBvcG5pZXV3IGRlIHRlc3RzdGF0aXN0aWVrIGJlcmVrZW5lbi4gVm9vciBkZXplIHN0dWRpZSB3YXMgZGF0IG5vZyBoYWFsYmFhciwgZW4gdmVybG9vcHQgaGV0IHVpdHZvZXJlbiB2YW4gZGUgdGVzdCBvdmVyIGVlbiB0aWpkc3Bhbm5lIHZhbiBlbmtlbGUgc2Vjb25kZW4uCkVjaHRlciwgaW4gbW9kZXJuZSBob29nLWRpbWVuc2lvbmFsZSBiaW9sb2dpc2NoZSBkYXRhc2V0cyB6aWpuIHBlcm11dGF0aWV0ZXN0ZW4gdmFhayBuaWV0IGhhYWxiYWFyLgpEZW5rIG1hYXIgYWFuIGdlbmV4cHJlc3NpZSBkYXRhLCB3YWFyIG1lbiBlZW4gdGVzdCB6b3Uga3VubmVuIHVpdHZvZXJlbiB2b29yIG1lZXIgZGFuICQ1MCAwMDAkIG1lbnNlbGlqa2UgdHJhbnNjcmlwdGVuLgpCb3ZlbmRpZW4gZGllbnQgbWVuIGluIGRpZSBjb250ZXh0IGVlbiBlcmcgYWNjdXJhdGUgcC13YWFyZGUgdGUgYmVrb21lbiAoZHVzIGdlYmFzZWVyZCBvcCBlZW4gZ3Jvb3QgYWFudGFsIHBlcm11dGF0aWVzLCB6ZWtlciBpbiBkZSBvcmRlIHZhbiBtaWxqb2VuZW4pIGFhbmdlemllbiBkZSBjb3JyZWN0aWUgdm9vciBtZWVydm91ZGlnIHRvZXRzZW4gZXJnIGdyb290IHphbCB6aWpuLgpJbiBkZXplIHNlY3RpZSB6dWxsZW4gd2UgZHVzIGVlbiBhbHRlcm5hdGlldmUgbmlldC1wYXJhbWV0cmlzY2hlIHRvZXRzIHVpdHZvZXJlbiwgbmFtZWxpamsgZWVuIHJhbmsgdGVzdC4KTWVyayBvcCBkYXQgcGVybXV0YXRpZXRlc3RlbiBvb2sgZW5rZWwgZ2VsZGlnIHppam4gaW5kaWVuIHdlIGhldCBsb2NhdGllLXNoaWZ0IG1vZGVsIHZlcm9uZGVyc3RlbGxlbiwgaW4gYW5kZXJlIHdvb3JkZW4sIGluZGllbiB3ZSB2ZXJvbmRlcnN0ZWxsZW4gZGF0IGJlaWRlIGdyb2VwZW4gZWVuIHplbGZkZSBkaXN0cmlidXRpZSBoZWJiZW4uCkluZGllbiB3ZSBkZXplIGFzc3VtcHRpZSBvb2sgbmVtZW4gYmlqIHJhbmsgdGVzdGVuLCBrdW5uZW4gd2UgaGV0IHJlc3VsdGFhdCB2YW4gZGUgcmFuayB0ZXN0IGludGVycHJldGVyZW4gaW4gZnVuY3RpZSB2YW4gZWVuIHZlcnNjaGlsIGluIGRlIG1lZGlhYW4uIEhldCBpcyBsb2dpc2NoIGRhdCB3ZSBoaWVyIGdlZW4gaW50ZXJwcmV0YXRpZSBpbiBmdW5jdGllIHZhbiBkZSBnZW1pZGRlbGRlbiB6dWxsZW4ga3VubmVuIGJla29tZW4sIGFhbmdlemllbiB3ZSBkZSBnZW1pZGRlbGRlbiBuaWV0IGdlYnJ1aWtlbiBpbiBoZXQgYmVyZWtlbmVuIHZhbiBkZSB0ZXN0c3RhdGlzdGllay4KRWNodGVyLCByYW5rLXRlc3RlbiB6aWpuIG9vayBnZWxkaWcgaW5kaWVuIGhldCBsb2NhdGllLXNoaWZ0IG1vZGVsIG5pZXQgb3BnYWF0LiBJbiBkYXQgZ2V2YWwsIGt1bm5lbiB3ZSBoZXQgcmVzdWx0YWF0IGludGVycHJldGVyZW4gaW4gZnVuY3RpZSB2YW4gZGUgcHJvYmFiaWxpc3Rpc2NoZSBpbmRleCAkUChZX3sxfSBcZ2UgWV8yKSQuCgpCaWogcmFuayB0ZXN0cyB3b3JkdCBkZSBkYXRhICRZX2kkIGdldHJhbnNmb3JtZWVyZCBuYWFyIHJhbmtzClxbIFJfaT1SKFlfaSkgPSBcI1x7WV9qOiBZX2pcbGVxIFlfaTsgaj0xLFxsZG90cywgblx9LiBcXQpSYW5rcyB6aWpuIGVyZyByb2J1dXN0IHZvb3Igb3V0bGllcnM6IG9mIGRlIGhvb2dzdGUgb2JzZXJ2YXRpZSBudSBlZW4gd2FhcmRlIHZhbiAxMDAgb2YgMTAgaGVlZnQsIGhldCBibGlqZnQgZGV6ZWxmZGUgcmFuayBiZWhvdWRlbi4KSW4gaGV0IGdldmFsIHZhbiAqdGllcyosIGRpdCB6aWpuIGdlbGlqa2Ugd2FhcmRlbiwgd29yZGVuIG1pZHJhbmtzIGdlYnJ1aWt0OgpcW1IoWV9pKSA9IFxmcmFje1xzdW1cbGltaXRzX3tcZm9yYWxsIGogOiBZX2o9WV9pfVIoWV9qKX17XCN7XGZvcmFsbCBqOllfaj1ZX2l9fSAgXF0KZGl0IGlzLCBkZSBtaWRyYW5rIGlzIGhldCBnZW1pZGRlbGRlIHZhbiBkZSByYW5rcyB2YW4gZGUgZ2VsaWprZSBvYnNlcnZhdGllcy4KClZlcnZvbGdlbnMga2FuIG1lbiBkZSBnZW1pZGRlbGRlIHJhbmsgdmVyZ2VsaWprZW4gdHVzc2VuIGRlIHR3ZWUgZ3JvZXBlbiBhYW4gZGUgaGFuZCB2YW4gZGUgV2lsY294b24tTWFubi1XaGl0bmV5IChXTlcpIHRlc3QuCgpgYGB7cn0Kd2lsY294LnRlc3QoUENCLmNvbmN+Z3JvdXAsIGRhdGEgPSBzaHJpbXBzKQpgYGAKCldlIHZpbmRlbiBkYXQgZGUgdGVzdCBzaWduaWZpY2FudCBpcyAob3AgaGV0IDUlLXNpZ25pZmljYW50aWVuaXZlYXUpLCBtYWFyIHdhY2h0ZW4gbm9nIGV2ZW4gbWV0IGRlIGludGVycHJldGF0aWUgdmFuIGhldCByZXN1bHRhYXQuCkRlIFdpbGNveG9uIHRlc3QgaGllcmJvdmVuIGlzIHN0YW5kYWFyZCBlZW4gZXhhY3RlIHRlc3QgKHppZSB2aWVyZGUgcGFyYWdyYWFmIGluIHNlY3RpZSBEZXRhaWxzIGluIGA/d2lsY294LnRlc3RgKS4KRGl0IHdpbCB6ZWdnZW4gZGF0IGRlIHRoZW9yZXRpc2NoZSBkaXN0cmlidXRpZXMgdm9vciBvbnplIHN0ZWVrcHJvZWZncm9vdHRlcyBnZWJydWlrdCB3b3JkZW4gYWxzIG51bGRpc3RyaWJ1dGllLCBpbiBwbGFhdHMgdmFuIHBlcm11dGF0aWVzLgpIaWVyb25kZXIgZ2FhbiB3ZSBuYSBvZiBoZXQgdm9sZ2VuZCByZXN1bHRhYXQgb29rIGJla29tZW4gd29yZHQgaW5kaWVuIHdlIHplbGYgcGVybXV0ZXJlbi4KCmBgYHtyfQpOIDwtIDEwMDAwICMxMDAwIHBlcm11dGF0aWVzClcuc3RhciA8LSBjKCkgI2luaXRpYWxpc2VlciBlZW4gdmVjdG9yIG1ldCBwZXJtdXRhdGllIHRlc3RzdGF0aXN0aWVrZW4KZ3JvdXAubGFiZWxzIDwtIHNocmltcHMkZ3JvdXAgI2dyb2VwIGxhYmVsczogb20gdGUgcGVybXV0ZXJlbgpwZXJtLmRhdGEgPC0gc2hyaW1wcyAja29waWVlciBvcmlnaW5lbGUgZGF0YXNldCB2b29yIHBlcm11dGF0aWUgdGVzdApmb3IoaSBpbiAxOk4pIHsgI2RvZSAxIHRvdCBOIGtlZXIKICBwZXJtLmxhYmVsczwtc2FtcGxlKGdyb3VwLmxhYmVscyxyZXBsYWNlPUYpICMgd2lsbGVrZXVyaWdlIGhlcnNjaGlra2luZyB2YW4gZGUgZ3JvZXAgbGFiZWxzCiAgcGVybS5kYXRhJGdyb3VwPC1wZXJtLmxhYmVscyAjdm9lZyB3aWxsZWtldXJpZ2UgZ3JvZXBsYWJlbHMgdG9lIGFhbiBvcmlnaW5lbGUgZGF0YXNldAogIFcuc3RhcltpXSA9IHdpbGNveC50ZXN0KFBDQi5jb25jfmdyb3VwLCBkYXRhPXBlcm0uZGF0YSkkc3RhdGlzdGljICN2b2VnIHBlcm11dGF0aWUgdGVzdHN0YXRpc3RpZWsgdG9lIGFhbiB2ZWN0b3IuCn0KCmhpc3QoVy5zdGFyKQphYmxpbmUodj04OCwgY29sPTIpCnB2YWx1ZSA8LSAyKm1lYW4oVy5zdGFyPD04OCkKcHZhbHVlICN2aWEgbWFudWVsZSBwZXJtdXRhdGllcyB2aW5kZW4gd2UgaW5kZXJkYWFkIGVlbiBnZWxpamthYXJkaWdlIHAtd2FhcmRlCmBgYAoKRGUgcC13YWFyZGUgaXMgdWl0ZXJhYXJkIG5pZXQgZXhhY3QgZ2VsaWprIG9tZGF0IGRpdCBzbGVjaHRzIGVlbiBiZW5hZGVyaW5nIGlzLCBtYWFyIGtvbXQgd2VsIGRpY2h0IGluIGRlIGJ1dXJ0IQpNZXJrIG9wIGRhdCBkZSB0ZXN0c3RhdGlzdGllayBrYW4gYmVrb21lbiB3b3JkZW4gZG9vciBkZSBzb20gdGUgbmVtZW4gdmFuIGRlIHJhbmtzIHZhbiDDqcOpbiB2YW4gZGUgZ3JvZXBlbiBkaWUgbWVuIHRlc3QuCkFhbmdlemllbiB3ZSBnZWVuIGdlbWlkZGVsZGVuIHZhbiBkZSBkYXRhIGdlYnJ1aWtlbiBpbiBkZSB0ZXN0LCBrdW5uZW4gd2UgZGUgdGVzdCB1aXRlcmFhcmQgb29rIG5pZXQgaW50ZXJwcmV0ZXJlbiBpbiB0ZXJtZW4gdmFuIGRlemUgZ2VtaWRkZWxkZW4uClZpYSBkZSByYW5rcyBrdW5uZW4gd2UgaGV0IHJlc3VsdGFhdCBlY2h0ZXIgd2VsIGludGVycHJldGVyZW4gYWFuIGRlIGhhbmQgdmFuIGRlICpwcm9iYWJpbGlzdGlzY2hlIGluZGV4Ki4KRGUgbnVsaHlwb3RoZXNlIHN0ZWx0IGRhdCBkZSBkaXN0cmlidXRpZXMgdmFuIGRlIHByb2JhYmlsaXRlaXRzZGVuc2l0ZWl0c2Z1bmN0aWVzIGluIGJlaWRlIGdyb2VwZW4gZ2VsaWprIHppam4uCgpcWyBIXzA6IGZfMSA9IGZfMiBcXQoKSW4gd29vcmRlbjogZGUgdmVyZGVsaW5nIHZhbiBQQ0IgY29uY2VudHJhdGllcyBpbiBnYXJuYWxlbiB6aWpuIGluIGJlaWRlIGNvbmRpdGllcyBnZWxpamsuIEluIHRlcm1lbiB2YW4gcHJvYmFiaWxpc3Rpc2NoZSBpbmRleCwga3VubmVuIHdlIGRlIG51bGh5cG90aGVzZSBvb2sgZm9ybXVsZXJlbiBhbHM6CgpcWyBIXzA6IFAoWV97aTF9IFxnZXEgWV97aTJ9KSA9IDEvMiBcXQoKRGUgYWx0ZXJuYXRpZXZlIGh5cG90aGVzZSBrYW4gaW4gdGVybWVuIHZhbiBkZSBwcm9iYWJpbGlzdGlzY2hlIGluZGV4IGthbiBtZW4gc2NyaGlqdmVuIGFscyB2b2xndDoKClxbIEhfMTogUChZX3tpMX0gXGdlcSBZX3tpMn0pIFxuZSAxLzIgXF0KCkluIHdvb3JkZW46IGRlIGthbnMgZGF0IGVlbiB3aWxsZWtldXJpZ2Ugb2JzZXJ2YXRpZSB2YW4gZGUgUENCIGNvbmNlbnRyYXRpZSB2YW4gZ2FybmFsZW4gZGllIG9wZ2Vncm9laWQgd2VyZGVuIGluIGNvbmRpdGllIDEgZ3JvdGVyIGRhbiBvZiBnZWxpamsgaXMgYWFuIGVlbiB3aWxsZWtldXJpZ2Ugb2JzZXJ2YXRpZSB2YW4gZGUgUENCIGNvbmNlbnRyYXRpZSB2YW4gZ2FybmFsZW4gZGllIG9wZ2Vncm9laWQgd2VyZGVuIGluIGNvbmRpdGllIDIgaXMgbmlldCBnZWxpamsgYWFuIDUwJS4KCkRlemUga2FucywgZGllIHdvcmR0IGFhbmdlbm9tZW4gNTAlIHRlIHppam4gb25kZXIgZGUgbnVsaHlwb3RoZXNlLCBrYW4gbWVuIGJla29tZW4gYWFuIGRlIGhhbmQgdmFuIGRlIGdlb2JzZXJ2ZWVyZGUgdGVzdHN0YXRpc3RpZWs6CgpgYGB7cn0KbjEgPC0gbjIgPC0gMTggIzE4IG9ic2VydmF0aWVzIGluIGVsa2UgZ3JvZXAKV09icyA8LSB3aWxjb3gudGVzdChQQ0IuY29uY35ncm91cCwgZGF0YT1zaHJpbXBzKSRzdGF0aXN0aWMgI2dlb2JzZXJ2ZWVyZGUgdGVzdHN0YXRpc3RpZWsKV09icy8objEqbjIpCmBgYAoKRGUgcHVudHNjaGF0dGluZyB2b29yIGRlemUga2FucyBpcyBkdXMgYHIgcm91bmQoV09icy8objEqbjIpLDMpKjEwMGAlLgoKV2UgaW50ZXJwcmV0ZXJlbiBkaXQgYWxzIHZvbGd0OgpEZSBrYW5zIGRhdCBkZSBQQ0IgY29uY2VudHJhdGllIGluIGVlbiB3aWxsZWtldXJpZ2UgZ2FybmFhbCBkaWUgd2VyZCBvcGdlZ3JvZWlkIGluIGNvbmRpdGllIDEgZ3JvdGVyIG9mIGdlbGlqayBpcyBhYW4gZGUgUENCIGNvbmNlbnRyYXRpZSBpbiBlZW4gd2lsbGVrZXVyaWdlIGdhcm5hYWwgZGllIHdlcmQgb3BnZWdyb2VpZCBpbiBjb25kaXRpZSAyIGlzIGdlbGlqayBhYW4gMjcuMiUuCgpPZiBub2c6CgpEZSBrYW5zIGRhdCBkZSBQQ0IgY29uY2VudHJhdGllIGluIGVlbiB3aWxsZWtldXJpZ2UgZ2FybmFhbCBkaWUgd2VyZCBvcGdlZ3JvZWlkIGluIGNvbmRpdGllIDEga2xlaW5lciBpcyBkYW4gZGUgUENCIGNvbmNlbnRyYXRpZSBpbiBlZW4gd2lsbGVrZXVyaWdlIGdhcm5hYWwgZGllIHdlcmQgb3BnZWdyb2VpZCBpbiBjb25kaXRpZSAyIGlzIGdlbGlqayBhYW4gNzIuOCUuCgpEZXplIGthbnMgdmVyc2NoaWx0IHNpZ25pZmljYW50IHZhbiA1MCUgb3AgaGV0IDUlIHNpZ25pZmljYW50aWVuaXZlYXUgKHA9MC4wMTkpLgo=