Statische test:
Welke test kan men uitvoeren om het gemiddelde gewicht simultaan te vergelijken tussen alle soorten voeding? Wat is de link met het lineair model? Geef de nul- en alternatieve hypothese van deze test.
In vorige oefening zagen we enkel de two-sample t-test om twee gemiddelden met elkaar vergelijken. We hebben echter ook reeds gezien dat de two-sample t-test een specifieke versie is van een lineair model, namelijk van een lineair model waarbij de covariaat een categorische variabele \(X\) is met \(2\) levels, i.e. \[ E[Y_i] = \beta_0 + \beta_1 X_i \]
Dit lineair model kan echter ook makkelijk veralgemeend worden naar factoren met meerdere levels.
\[ E[Y_i] = \beta_0 + \beta_1 X_{1i} + \beta_2 X_{2i} \]
Waarbij \(X_{1i}\) gelijk is aan 1 wanneer de voeding linseed is en anders 0. Anderzijds is \(X_{2i}\) gelijk aan 1 bij soybeans en gelijk aan 0 bij de andere voedingen.
Er bestaat een manier waarbij we alle levels simultaan kunnen testen, men zal namelijk testen of de gehele categorische variabele een invloed heeft op de respons variabele. In de context van ons voorbeeld, zal men kunnen testen of de voeding-soort überhaupt een effect heeft op het gemiddelde gewicht van kuikentjes. Zo’n een test heet een one-way ANOVA.
Stel dat \(\mu_1\) het gemiddelde gewicht van kuikens voor caseïne voorstelt, en idem voor \(\mu_2\) en \(\mu_3\). De nul- en alternatieve hypothese voor een ANOVA kan men dan voorstellen als
\(H_0\): \(\mu_1=\mu_2=\mu_3\)
\(H_A\): Voor minstens één \(i \ne j\) is \(\mu_i \neq \mu_j\): met andere woorden \(\mu_1 \ne \mu_2\) of \(\mu_1 \ne \mu_3\) of \(\mu_2 \ne \mu_3\)
In woorden, zegt de nulhypothese dat het gemiddelde gewicht van kuikens onafhankelijk is van de voeding: er is geen systematisch verschil in gemiddeld gewicht van het kuiken. De alternatieve hypothese zegt dat het gemiddelde gewicht verschilt tussen minstens twee voeding-soorten. Merk op dat men bij het verwerpen van de nulhypothese niet weet tussen welke soorten er een verschil is!
Indien we de ANOVA testen op basis van het lineair model kunnen we ook de volgende nul- en alternatieve hypothese opstellen:
\(H_0\): \(\beta_1 = \beta_2 = 0\)
\(H_A\): \(\beta_1 \ne 0\) of \(\beta_2 \ne 0\)
Geef de assumpties voor dit model en ga deze na:
Zoals beschreven in de cursus, veronderstelt ANOVA een locatie-shift. Dit wil zeggen dat elke groep een gelijke variantie heeft en er enkel shifts in gemiddelde kunnen optreden. Een andere assumptie is dat de data van elke groep normaal verdeeld is, en dat de observaties onafhankelijk van elkaar zijn.
Er zijn dus drie assumpties die moeten voldaan zijn. Aangezien we in de data niet kunnen waarnemen of de observaties onafhankelijk zijn van elkaar, moeten we dit veronderstellen dat de onderzoeker dit correct heeft uitgevoerd. Daarnaast moeten we controleren dat:
We gaan gelijkheid van varianties na met boxplots. Dit lijkt alvast in orde te zijn.
We zullen nu de assumptie van normale verdeling binnen elke groep nagaan.
#Maak een QQplot voor het gewicht per voedingssoort.
chickwts %>%
ggplot(aes(sample = weight)) +
geom_qq() +
geom_qq_line() +
facet_grid(.~feed) +
ylab("Relatieve abundantie")

De afwijkingen die we in onze qqplot zien lijken niet zeer uitzonderlijk. Daarom kunnen we stellen dat elke groep een normale verdeling lijkt te volgen.
Indien men veel groepen moet vergelijken, kan het makkelijker zijn om slechts één plot te moeten beoordelen. In dat geval kan men ervoor kiezen om niet voor elke groep apart een QQ-plot te maken, maar kan men de residuen van het lineair model checken. Merk op dat men dan checkt voor een normale distributie van alle residuen van het gewicht ten opzichte van hun groepsgemiddelde, en dus niet voor een normale distributie binnen elke groep apart.
model_lm <- lm(weight ~ feed, data = chickwts)
par(mfrow=c(2,2))
plot(model_lm) # Enkel figuur rechts boven is relevant

De QQ-plot vertoont geen systematische afwijkingen van een normale distributie. Dit is geen garantie dat de data normaal verdeeld is binnen elke groep, maar het is een benadering die we kunnen gebruiken in het geval dat:
- er te veel groepen zijn om de assumpties te checken binnen elke groep;
- er te weinig observaties zijn per groep om binnen elke groep de assumpties na te gaan.
Merk op dat je in principe de assumptie van gelijke varianties ook op basis van de plot linksboven zou kunnen checken: elke ‘kolom’ van punten stelt een soort voor (1 soort heeft 1 geschat gemiddelde) en de punten stellen de residuen voor ten opzichte van hun groepsgemiddelde. Men kan deze plot dus ook gebruiken om te kijken of er groepen (soorten) zijn die een verschillende variantie hebben ten opzichte van andere groepen.
Modelleer de data met het lineair model:
##
## Call:
## lm(formula = weight ~ feed, data = chickwts)
##
## Residuals:
## Min 1Q Median 3Q Max
## -107.583 -45.717 2.571 40.500 90.250
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 323.58 16.46 19.660 < 2e-16 ***
## feedlinseed -104.83 23.28 -4.504 7.11e-05 ***
## feedsoybean -77.15 22.43 -3.440 0.00152 **
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 57.01 on 35 degrees of freedom
## Multiple R-squared: 0.3854, Adjusted R-squared: 0.3503
## F-statistic: 10.97 on 2 and 35 DF, p-value: 0.0001996
De p-waarden die we hier krijgen voor de parameters komen niet overeen met de ANOVA-test die we willen uitvoeren. De p-waarde bij de F-statistic is wel de juiste p-waarde. We kunnen dit ook verkrijgen door de volgende code:
#Voer de ANOVA uit op het lineare model.
anova(model_lm)
We voerden de ANOVA test uit aan de hand van het lineair regressiemodel. In principe testen we dan volgende nulhypothese:
\[ H_0: \beta_1 = \beta_2 = 0 \]
Merk op dat deze nulhypothese evenwaardig is aan de nulhypothese die we eerder formuleerden. Als alle gemiddelden \(\mu_1, \mu_2, \mu_3 = 0\), betekent dit dat beide regressieparameters \(\beta_1\) en \(\beta_1\) gelijk zijn aan 0.
De p-waarde van deze ANOVA test is bijzonder klein. We besluiten dat we de nulhypothese kunnen verwerpen (\(p<<0.001\)) en dat het gemiddelde gewicht van kuikens verschilt tussen minstens twee van de voedingspatronen op het 5% significantieniveau.
Aan de hand van dit resultaat weten we echter niet tussen welke voedingen er een verschil optreedt, en hiervoor zullen we een post-hoc analyse moeten uitvoeren. Een post-hoc analyse voert men enkel uit indien de ANOVA test significant was, en bestaat erin om paarsgewijze vergelijkingen uit te voeren tussen de groepen. In dit geval komt dit overeen met het vergelijken of er een verschil is tussen groep 1 en 2, tussen groep 1 en 3 en tussen groep 2 en 3.
Post-hoc analyse
De post-hoc analyse bestaat eruit om paarsgewijze testen uit te voeren. Indien men over \(k\) groepen beschikt is het totaal aantal paarsgewijze vergelijkingen gelijk aan \(k(k-1)/2\). Bij ons is \(k=3\) waardoor we \(3\) paarsgewijze vergelijkingen zullen uitvoeren. We kunnen echter niet elke test op het 5% significantieniveau uitvoeren vanwege het meervoudig toetsen probleem. Indien we 3 vergelijkingen zouden testen elk op het 5% significantieniveau, dan is de kans dat we minstens één nulhypothese onterecht zouden verwerpen niet langer gelijk aan ons significantieniveau (5%). In ons geval, zou deze kans gelijk zijn aan:
alpha <- 0.05
nComparisons <- 3
1-(1-alpha)^nComparisons
## [1] 0.142625
Dus indien we elke test op het 5% significantieniveau zouden uitvoeren hebben we, als alle nulhypotheses waar zouden zijn, een kans van 14.3% dat we minstens één nulhypothese verkeerd zouden verwerpen. Om deze kans globaal gezien (dit is, over alle paarsgewijze vergelijkingen) op 5% te houden, kunnen we bijvoorbeeld de Bonferroni correctie uitvoeren.
In R
kunnen we de post-hoc analyse uitvoeren met behulp van het multcomp
package aan de hand van de glht
functie. We specifiëren hier in het linfct
argument dat we multiple comparisons (mcp
) willen uitvoeren waarbij we alle paarsgewijze vergelijkingen voor de feed
variabele willen testen aan de hand van de "Tukey"
methode. De multcomp
package zorgt ervoor dat deze p-waarden automatisch gecorrigeerd worden voor meervoudig toetsen.
suppressPackageStartupMessages(library(multcomp))
mcp <- glht(model_lm,linfct=mcp(feed="Tukey"))
summary <- summary(mcp)
summary
##
## Simultaneous Tests for General Linear Hypotheses
##
## Multiple Comparisons of Means: Tukey Contrasts
##
##
## Fit: lm(formula = weight ~ feed, data = chickwts)
##
## Linear Hypotheses:
## Estimate Std. Error t value Pr(>|t|)
## linseed - casein == 0 -104.83 23.28 -4.504 < 0.001 ***
## soybean - casein == 0 -77.15 22.43 -3.440 0.00423 **
## soybean - linseed == 0 27.68 22.43 1.234 0.44144
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## (Adjusted p values reported -- single-step method)
In de output hiervan zien we de verschillende paarsgewijze vergelijkingen die werden uitvoerd. Bijvoorbeeld linseed - casein == 0
duidt erop dat voor dit contrast wordt getest of het gemiddelde gewicht voor voeding linseed
min het gemiddelde gewicht voor soort casein
verschillend is van nul. In de tweede kolom wordt het verschil in gemiddelden weergegeven, met hun standaard error en teststatistiek in de respectievelijk derde en vierde kolom. De laatste kolom geeft aangepaste p-waarden weer op een globaal significantieniveau van 5%. Aan de hand van de aangepaste p-waarden zien we dat het gemiddelde gewicht bij casein
verschilt van zowel linseed
en soybean
(p < 0.001 en p = 0.004) op het 5% significantieniveau. We zien ook dat er geen significant verschil is in gemiddeld gewicht bij voeding soybean
en linseed
op het 5% significantieniveau. De effectgrootte is voor bij zowel linseed
als soybean
negatief, wat erop duidt dat het gemiddelde gewicht van kuikens hoger is bij voedingspatroon casein
.
De betrouwbaarheidsintervallen van elke paarsgewijze test kunnen we ook makkelijk grafisch voorstellen aan de hand van de plot
functie die zo op een glht
object kan toegepast worden.
##
## Simultaneous Confidence Intervals
##
## Multiple Comparisons of Means: Tukey Contrasts
##
##
## Fit: lm(formula = weight ~ feed, data = chickwts)
##
## Quantile = 2.4474
## 95% family-wise confidence level
##
##
## Linear Hypotheses:
## Estimate lwr upr
## linseed - casein == 0 -104.8333 -161.7991 -47.8675
## soybean - casein == 0 -77.1548 -132.0484 -22.2611
## soybean - linseed == 0 27.6786 -27.2151 82.5722

LS0tCnRpdGxlOiAiUHJhY3RpY3VtIDE6IE9lZmVuaW5nIGFub3ZhIgphdXRob3I6ICJBbGV4YW5kcmUgU2VnZXJzICYgTGlldmVuIENsZW1lbnQiCmRhdGU6ICJzdGF0T21pY3MsIEdoZW50IFVuaXZlcnNpdHkgKGh0dHBzOi8vc3RhdG9taWNzLmdpdGh1Yi5pbykiCm91dHB1dDoKICAgIGh0bWxfZG9jdW1lbnQ6CiAgICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgICAgdGhlbWU6IGNvc21vCiAgICAgIHRvYzogdHJ1ZQogICAgICB0b2NfZmxvYXQ6IHRydWUKICAgICAgaGlnaGxpZ2h0OiB0YW5nbwogICAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgIHBkZl9kb2N1bWVudDoKICAgICAgdG9jOiB0cnVlCiAgICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogICAgICBsYXRleF9lbmdpbmU6IHhlbGF0ZXgKbGlua2NvbG9yOiBibHVlCnVybGNvbG9yOiBibHVlCmNpdGVjb2xvcjogYmx1ZQoKLS0tCgo8YSByZWw9ImxpY2Vuc2UiIGhyZWY9Imh0dHBzOi8vY3JlYXRpdmVjb21tb25zLm9yZy9saWNlbnNlcy9ieS1uYy1zYS80LjAiPjxpbWcgYWx0PSJDcmVhdGl2ZSBDb21tb25zIExpY2Vuc2UiIHN0eWxlPSJib3JkZXItd2lkdGg6MCIgc3JjPSJodHRwczovL2kuY3JlYXRpdmVjb21tb25zLm9yZy9sL2J5LW5jLXNhLzQuMC84OHgzMS5wbmciIC8+PC9hPgoKCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQpgYGAKCiMgQU5PVkE6IEt1aWtlbnRqZXMKCkluIGRlemUgc3R1ZGllICgxOTQ4KSB3ZXJkIGRlIGludmxvZWQgdmFuIHZlcnNjaGlsbGVuZGUgc29vcnRlbiB2b2VkaW5nIG9wIGhldCBnZXdpY2h0IHZhbiBrdWlrZW50amVzIG9uZGVyem9jaHQuIERlIGt1aWtlbnRqZXMgd2VyZGVuIG5hIGdlYm9vcnRlIHdpbGxla2V1cmlnIGluIMOpw6luIHZhbiB6ZXMgZ3JvZXBlbiB0b2VnZWtlbmQsIHdhYXJuYSBkZXplIGdyb2VwZW4gZWxrIGVlbiBhbmRlcmUgdm9lZGluZyBrcmVnZW4uIEhldCBnZXdpY2h0IHZhbiBkZXplIGt1aWtlbnRqZXMgd2VyZCBnZW1ldGVuIG5hIHplcyB3ZWtlbi4gV2lqIHp1bGxlbiBvbnMgYmVwZXJrZW4gdG90IGRyaWUgZ3JvZXBlbiB2YW4gdm9lZGluZzogY2FzZcOvbmUgKGNhc2VpbiksIGxpam56YWFkIChsaW5zZWVkKSBlbiBzb2phYm9uZW4gKHNveWJlYW4pLgoKCgpgYGB7cn0Kc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKHsKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoZ2dwbG90Mil9KQpgYGAKCiMgRGF0YSBleHBsb3JhdGllCmBgYHtyfQpkYXRhKCJjaGlja3d0cyIpCmBgYAoKIyMgRGF0YXN0cnVjdHV1ciBiZWtpamtlbgoKYGBge3J9CiNCZWtpamsgZGUgc3RydWN0dXVyIHZhbiBkYXRhc2V0IGNoaWNrd3RzCmhlYWQoY2hpY2t3dHMpCmBgYAoKIyMgRGF0YSBmaWx0ZXJlbgoKV2UgZ2FhbiBkZSBhbmFseXNlIGJlcGVya2VuIHRvdCBoZXQgdmVyZ2VsaWprZW4gdmFuIHZvZWRpbmcgY2FzZcOvbmUgKGNhc2VpbiksIGxpam56YWFkIChsaW5zZWVkKSBlbiBzb2phYm9uZW4gKHNveWJlYW4pLiAKCmBgYHtyfQojRmlsdGVyIGRlIGRhdGFzZXQgem9kYXQgZW5rZWwgZGF0YXB1bnRlbiB2YW4gZGUgcmVsZXZhbnRlIHZvZWRpbmcgKGZlZWQpIGFhbndlemlnIHppam4uCmNoaWNrd3RzIDwtIGNoaWNrd3RzICU+JSBmaWx0ZXIoZmVlZCAlaW4lIGMoImNhc2VpbiIsImxpbnNlZWQiLCJzb3liZWFuIikpCmBgYAoKIyMgRmlndXVyIHZhbiBkZSBkYXRhCgpXZSBnYWFuIGVlcnN0IGRlIGRhdGEgYmVraWprZW4gem9kYXQgd2UgZWVuIGlkZWUgaGViYmVuIHdhYXJtZWUgd2UgdGUgbWFrZW4gaGViYmVuLgoKYGBge3J9CiNNYWFrIGVlbiBib3hwbG90IHZhbiBoZXQgZ2V3aWNodCB2b29yIGVsa2UgZ3JvZXAgdmFuIHZvZWRpbmcuIFBsb3Qgb29rIGRlIGluZGl2aWR1ZWxlIG9ic2VydmF0aWVzLgpjaGlja3d0cyAlPiUgZ2dwbG90KGFlcyh4PWZlZWQseT13ZWlnaHQpKSArIAogIGdlb21fYm94cGxvdCgpICsKICBnZW9tX2ppdHRlcigpICsKICBnZ3RpdGxlKCJHZXdpY2h0IHZhbiBrdWlrZW50amVzIG5hIHplcyB3ZWtlbiBwZXIgc29vcnQgdm9lZGluZyIpCmBgYAoKCiMgU3RhdGlzY2hlIHRlc3Q6CgojIyBXZWxrZSB0ZXN0IGthbiBtZW4gdWl0dm9lcmVuIG9tIGhldCBnZW1pZGRlbGRlIGdld2ljaHQgc2ltdWx0YWFuIHRlIHZlcmdlbGlqa2VuIHR1c3NlbiBhbGxlIHNvb3J0ZW4gdm9lZGluZz8gV2F0IGlzIGRlIGxpbmsgbWV0IGhldCBsaW5lYWlyIG1vZGVsPyBHZWVmIGRlIG51bC0gZW4gYWx0ZXJuYXRpZXZlIGh5cG90aGVzZSB2YW4gZGV6ZSB0ZXN0LgoKSW4gdm9yaWdlIG9lZmVuaW5nIHphZ2VuIHdlIGVua2VsIGRlIHR3by1zYW1wbGUgdC10ZXN0IG9tIHR3ZWUgZ2VtaWRkZWxkZW4gbWV0IGVsa2FhciB2ZXJnZWxpamtlbi4KV2UgaGViYmVuIGVjaHRlciBvb2sgcmVlZHMgZ2V6aWVuIGRhdCBkZSB0d28tc2FtcGxlIHQtdGVzdCBlZW4gc3BlY2lmaWVrZSB2ZXJzaWUgaXMgdmFuIGVlbiBsaW5lYWlyIG1vZGVsLCBuYW1lbGlqayB2YW4gZWVuIGxpbmVhaXIgbW9kZWwgd2FhcmJpaiBkZSBjb3ZhcmlhYXQgZWVuIGNhdGVnb3Jpc2NoZSB2YXJpYWJlbGUgJFgkIGlzIG1ldCAkMiQgbGV2ZWxzLCBpLmUuClxbIEVbWV9pXSA9IFxiZXRhXzAgKyBcYmV0YV8xIFhfaSBcXQoKRGl0IGxpbmVhaXIgbW9kZWwga2FuIGVjaHRlciBvb2sgbWFra2VsaWprIHZlcmFsZ2VtZWVuZCB3b3JkZW4gbmFhciBmYWN0b3JlbiBtZXQgbWVlcmRlcmUgbGV2ZWxzLiAKClxbIEVbWV9pXSA9IFxiZXRhXzAgKyBcYmV0YV8xIFhfezFpfSArIFxiZXRhXzIgWF97Mml9IFxdCgpXYWFyYmlqICRYX3sxaX0kIGdlbGlqayBpcyBhYW4gMSB3YW5uZWVyIGRlIHZvZWRpbmcgbGluc2VlZCBpcyBlbiBhbmRlcnMgMC4gQW5kZXJ6aWpkcyBpcyAkWF97Mml9JCBnZWxpamsgYWFuIDEgYmlqIHNveWJlYW5zIGVuIGdlbGlqayBhYW4gMCBiaWogZGUgYW5kZXJlIHZvZWRpbmdlbi4gCgpFciBiZXN0YWF0IGVlbiBtYW5pZXIgd2FhcmJpaiB3ZSAqKmFsbGUgbGV2ZWxzIHNpbXVsdGFhbiBrdW5uZW4gdGVzdGVuKiosIG1lbiB6YWwgbmFtZWxpamsgdGVzdGVuIG9mIGRlIGdlaGVsZSBjYXRlZ29yaXNjaGUgdmFyaWFiZWxlIGVlbiBpbnZsb2VkIGhlZWZ0IG9wIGRlIHJlc3BvbnMgdmFyaWFiZWxlLgpJbiBkZSBjb250ZXh0IHZhbiBvbnMgdm9vcmJlZWxkLCB6YWwgbWVuIGt1bm5lbiB0ZXN0ZW4gb2YgZGUgdm9lZGluZy1zb29ydCDDvGJlcmhhdXB0IGVlbiBlZmZlY3QgaGVlZnQgb3AgaGV0IGdlbWlkZGVsZGUgZ2V3aWNodCB2YW4ga3Vpa2VudGplcy4KWm8nbiBlZW4gdGVzdCBoZWV0IGVlbiBvbmUtd2F5IEFOT1ZBLgoKU3RlbCBkYXQgJFxtdV8xJCBoZXQgZ2VtaWRkZWxkZSBnZXdpY2h0IHZhbiBrdWlrZW5zIHZvb3IgY2FzZcOvbmUgdm9vcnN0ZWx0LCBlbiBpZGVtIHZvb3IgJFxtdV8yJCBlbiAkXG11XzMkLgpEZSBudWwtIGVuIGFsdGVybmF0aWV2ZSBoeXBvdGhlc2Ugdm9vciBlZW4gQU5PVkEga2FuIG1lbiBkYW4gdm9vcnN0ZWxsZW4gYWxzCgokSF8wJDogJFxtdV8xPVxtdV8yPVxtdV8zJAoKJEhfQSQ6IFZvb3IgbWluc3RlbnMgw6nDqW4gJGkgXG5lIGokIGlzICRcbXVfaSBcbmVxIFxtdV9qJDogbWV0IGFuZGVyZSB3b29yZGVuICRcbXVfMSBcbmUgXG11XzIkIG9mICRcbXVfMSBcbmUgXG11XzMkIG9mICRcbXVfMiBcbmUgXG11XzMkCgpJbiB3b29yZGVuLCB6ZWd0IGRlIG51bGh5cG90aGVzZSBkYXQgaGV0IGdlbWlkZGVsZGUgZ2V3aWNodCB2YW4ga3Vpa2VucyBvbmFmaGFua2VsaWprIGlzIHZhbiBkZSB2b2VkaW5nOiBlciBpcyBnZWVuIHN5c3RlbWF0aXNjaCB2ZXJzY2hpbCBpbiBnZW1pZGRlbGQgZ2V3aWNodCB2YW4gaGV0IGt1aWtlbi4KRGUgYWx0ZXJuYXRpZXZlIGh5cG90aGVzZSB6ZWd0IGRhdCBoZXQgZ2VtaWRkZWxkZSBnZXdpY2h0IHZlcnNjaGlsdCB0dXNzZW4gKiptaW5zdGVucyB0d2VlIHZvZWRpbmctc29vcnRlbioqLiBNZXJrIG9wIGRhdCBtZW4gYmlqIGhldCB2ZXJ3ZXJwZW4gdmFuIGRlIG51bGh5cG90aGVzZSAqKm5pZXQgd2VldCB0dXNzZW4gd2Vsa2Ugc29vcnRlbioqIGVyIGVlbiB2ZXJzY2hpbCBpcyEKCkluZGllbiB3ZSBkZSBBTk9WQSB0ZXN0ZW4gb3AgYmFzaXMgdmFuIGhldCBsaW5lYWlyIG1vZGVsIGt1bm5lbiB3ZSBvb2sgZGUgdm9sZ2VuZGUgbnVsLSBlbiBhbHRlcm5hdGlldmUgaHlwb3RoZXNlIG9wc3RlbGxlbjoKCiRIXzAkOiAkXGJldGFfMSA9IFxiZXRhXzIgPSAwJAogCiRIX0EkOiAkXGJldGFfMSBcbmUgMCQgb2YgJFxiZXRhXzIgXG5lIDAkCgojIyBHZWVmIGRlIGFzc3VtcHRpZXMgdm9vciBkaXQgbW9kZWwgZW4gZ2EgZGV6ZSBuYToKClpvYWxzIGJlc2NocmV2ZW4gaW4gZGUgY3Vyc3VzLCB2ZXJvbmRlcnN0ZWx0IEFOT1ZBIGVlbiBsb2NhdGllLXNoaWZ0LgpEaXQgd2lsIHplZ2dlbiBkYXQgZWxrZSBncm9lcCBlZW4gZ2VsaWprZSB2YXJpYW50aWUgaGVlZnQgZW4gZXIgZW5rZWwgc2hpZnRzIGluIGdlbWlkZGVsZGUga3VubmVuIG9wdHJlZGVuLiBFZW4gYW5kZXJlIGFzc3VtcHRpZSBpcyBkYXQgZGUgZGF0YSB2YW4gZWxrZSBncm9lcCBub3JtYWFsIHZlcmRlZWxkIGlzLCBlbiBkYXQgZGUgb2JzZXJ2YXRpZXMgb25hZmhhbmtlbGlqayB2YW4gZWxrYWFyIHppam4uIAoKRXIgemlqbiBkdXMgZHJpZSBhc3N1bXB0aWVzIGRpZSBtb2V0ZW4gdm9sZGFhbiB6aWpuLiBBYW5nZXppZW4gd2UgaW4gZGUgZGF0YSBuaWV0IGt1bm5lbiB3YWFybmVtZW4gb2YgZGUgb2JzZXJ2YXRpZXMgb25hZmhhbmtlbGlqayB6aWpuIHZhbiBlbGthYXIsIG1vZXRlbiB3ZSBkaXQgdmVyb25kZXJzdGVsbGVuIGRhdCBkZSBvbmRlcnpvZWtlciBkaXQgY29ycmVjdCBoZWVmdCB1aXRnZXZvZXJkLiBEYWFybmFhc3QgbW9ldGVuIHdlIGNvbnRyb2xlcmVuIGRhdDoKCiAtIGVsa2UgZ3JvZXAgbm9ybWFhbCBpcy4KIAogLSBkZSBncm9lcGVuIGVlbiBnZWxpamtlIHZhcmlhbnRpZSBoZWJiZW4uIChob21vc2NlZGFzdGljaXRlaXQpCgpXZSBnYWFuIGdlbGlqa2hlaWQgdmFuIHZhcmlhbnRpZXMgbmEgbWV0IGJveHBsb3RzLiBEaXQgbGlqa3QgYWx2YXN0IGluIG9yZGUgdGUgemlqbi4KCldlIHp1bGxlbiBudSBkZSBhc3N1bXB0aWUgdmFuIG5vcm1hbGUgdmVyZGVsaW5nIGJpbm5lbiBlbGtlIGdyb2VwIG5hZ2Fhbi4gCgpgYGB7cn0KI01hYWsgZWVuIFFRcGxvdCB2b29yIGhldCBnZXdpY2h0IHBlciB2b2VkaW5nc3Nvb3J0LgpjaGlja3d0cyAlPiUKICBnZ3Bsb3QoYWVzKHNhbXBsZSA9IHdlaWdodCkpICsKICBnZW9tX3FxKCkgKwogIGdlb21fcXFfbGluZSgpICsKICBmYWNldF9ncmlkKC5+ZmVlZCkgKwogIHlsYWIoIlJlbGF0aWV2ZSBhYnVuZGFudGllIikKCmBgYAoKCkRlIGFmd2lqa2luZ2VuIGRpZSB3ZSBpbiBvbnplIHFxcGxvdCB6aWVuIGxpamtlbiBuaWV0IHplZXIgdWl0em9uZGVybGlqay4gRGFhcm9tIGt1bm5lbiB3ZSBzdGVsbGVuIGRhdCBlbGtlIGdyb2VwIGVlbiBub3JtYWxlIHZlcmRlbGluZyBsaWprdCB0ZSB2b2xnZW4uCgpJbmRpZW4gbWVuIHZlZWwgZ3JvZXBlbiBtb2V0IHZlcmdlbGlqa2VuLCBrYW4gaGV0IG1ha2tlbGlqa2VyIHppam4gb20gc2xlY2h0cyDDqcOpbiBwbG90IHRlIG1vZXRlbiBiZW9vcmRlbGVuLiBJbiBkYXQgZ2V2YWwga2FuIG1lbiBlcnZvb3Iga2llemVuIG9tIG5pZXQgdm9vciBlbGtlIGdyb2VwIGFwYXJ0IGVlbiBRUS1wbG90IHRlIG1ha2VuLCBtYWFyIGthbiBtZW4gZGUgcmVzaWR1ZW4gdmFuIGhldCBsaW5lYWlyIG1vZGVsIGNoZWNrZW4uIApNZXJrIG9wIGRhdCBtZW4gZGFuIGNoZWNrdCB2b29yIGVlbiBub3JtYWxlIGRpc3RyaWJ1dGllIHZhbiAqKiphbGxlKioqIHJlc2lkdWVuIHZhbiBoZXQgZ2V3aWNodCB0ZW4gb3B6aWNodGUgdmFuIGh1biBncm9lcHNnZW1pZGRlbGRlLCBlbiBkdXMgbmlldCB2b29yIGVlbiBub3JtYWxlIGRpc3RyaWJ1dGllIGJpbm5lbiBlbGtlIGdyb2VwIGFwYXJ0LgoKYGBge3J9Cm1vZGVsX2xtIDwtIGxtKHdlaWdodCB+IGZlZWQsIGRhdGEgPSBjaGlja3d0cykKcGFyKG1mcm93PWMoMiwyKSkKcGxvdChtb2RlbF9sbSkgIyBFbmtlbCBmaWd1dXIgcmVjaHRzIGJvdmVuIGlzIHJlbGV2YW50CnBhcihtZnJvdz1jKDEsMSkpCmBgYAoKRGUgUVEtcGxvdCB2ZXJ0b29udCBnZWVuIHN5c3RlbWF0aXNjaGUgYWZ3aWpraW5nZW4gdmFuIGVlbiBub3JtYWxlIGRpc3RyaWJ1dGllLiBEaXQgaXMgZ2VlbiBnYXJhbnRpZSBkYXQgZGUgZGF0YSBub3JtYWFsIHZlcmRlZWxkIGlzIGJpbm5lbiBlbGtlIGdyb2VwLCBtYWFyIGhldCBpcyBlZW4gYmVuYWRlcmluZyBkaWUgd2Uga3VubmVuIGdlYnJ1aWtlbiBpbiBoZXQgZ2V2YWwgZGF0OgoKIC0gZXIgdGUgdmVlbCBncm9lcGVuIHppam4gb20gZGUgYXNzdW1wdGllcyB0ZSBjaGVja2VuIGJpbm5lbiBlbGtlIGdyb2VwOwogLSBlciB0ZSB3ZWluaWcgb2JzZXJ2YXRpZXMgemlqbiBwZXIgZ3JvZXAgb20gYmlubmVuIGVsa2UgZ3JvZXAgZGUgYXNzdW1wdGllcyBuYSB0ZSBnYWFuLgoKTWVyayBvcCBkYXQgamUgaW4gcHJpbmNpcGUgZGUgYXNzdW1wdGllIHZhbiBnZWxpamtlIHZhcmlhbnRpZXMgb29rIG9wIGJhc2lzIHZhbiBkZSBwbG90IGxpbmtzYm92ZW4gem91IGt1bm5lbiBjaGVja2VuOiBlbGtlICdrb2xvbScgdmFuIHB1bnRlbiBzdGVsdCBlZW4gc29vcnQgdm9vciAoMSBzb29ydCBoZWVmdCAxIGdlc2NoYXQgZ2VtaWRkZWxkZSkgZW4gZGUgcHVudGVuIHN0ZWxsZW4gZGUgcmVzaWR1ZW4gdm9vciB0ZW4gb3B6aWNodGUgdmFuIGh1biBncm9lcHNnZW1pZGRlbGRlLiBNZW4ga2FuIGRlemUgcGxvdCBkdXMgb29rIGdlYnJ1aWtlbiBvbSB0ZSBraWprZW4gb2YgZXIgZ3JvZXBlbiAoc29vcnRlbikgemlqbiBkaWUgZWVuIHZlcnNjaGlsbGVuZGUgdmFyaWFudGllIGhlYmJlbiB0ZW4gb3B6aWNodGUgdmFuIGFuZGVyZSBncm9lcGVuLgoKCgojIyBNb2RlbGxlZXIgZGUgZGF0YSBtZXQgaGV0IGxpbmVhaXIgbW9kZWw6CgpgYGB7cn0Kc3VtbWFyeShtb2RlbF9sbSkKYGBgCgpEZSBwLXdhYXJkZW4gZGllIHdlIGhpZXIga3JpamdlbiB2b29yIGRlIHBhcmFtZXRlcnMga29tZW4gbmlldCBvdmVyZWVuIG1ldCBkZSBBTk9WQS10ZXN0IGRpZSB3ZSB3aWxsZW4gdWl0dm9lcmVuLiBEZSBwLXdhYXJkZSBiaWogZGUgRi1zdGF0aXN0aWMgaXMgd2VsIGRlIGp1aXN0ZSBwLXdhYXJkZS4gV2Uga3VubmVuIGRpdCBvb2sgdmVya3JpamdlbiBkb29yIGRlIHZvbGdlbmRlIGNvZGU6CgpgYGB7cn0KI1ZvZXIgZGUgQU5PVkEgdWl0IG9wIGhldCBsaW5lYXJlIG1vZGVsLgphbm92YShtb2RlbF9sbSkKYGBgCgpXZSB2b2VyZGVuIGRlIEFOT1ZBIHRlc3QgdWl0IGFhbiBkZSBoYW5kIHZhbiBoZXQgbGluZWFpciByZWdyZXNzaWVtb2RlbC4gSW4gcHJpbmNpcGUgdGVzdGVuIHdlIGRhbiB2b2xnZW5kZSBudWxoeXBvdGhlc2U6CgpcWyBIXzA6IFxiZXRhXzEgPSBcYmV0YV8yID0gMCAgXF0KCgpNZXJrIG9wIGRhdCBkZXplIG51bGh5cG90aGVzZSBldmVud2FhcmRpZyBpcyBhYW4gZGUgbnVsaHlwb3RoZXNlIGRpZSB3ZSBlZXJkZXIgZm9ybXVsZWVyZGVuLiBBbHMgYWxsZSBnZW1pZGRlbGRlbiAkXG11XzEsIFxtdV8yLCBcbXVfMyA9IDAkLCBiZXRla2VudCBkaXQgZGF0IGJlaWRlIHJlZ3Jlc3NpZXBhcmFtZXRlcnMgJFxiZXRhXzEkIGVuICRcYmV0YV8xJCBnZWxpamsgemlqbiBhYW4gMC4KCgpEZSBwLXdhYXJkZSB2YW4gZGV6ZSBBTk9WQSB0ZXN0IGlzIGJpanpvbmRlciBrbGVpbi4gV2UgYmVzbHVpdGVuIGRhdCB3ZSBkZSBudWxoeXBvdGhlc2Uga3VubmVuIHZlcndlcnBlbiAoJHA8PDAuMDAxJCkgZW4gZGF0IGhldCBnZW1pZGRlbGRlIGdld2ljaHQgdmFuIGt1aWtlbnMgdmVyc2NoaWx0IHR1c3NlbiBtaW5zdGVucyB0d2VlIHZhbiBkZSB2b2VkaW5nc3BhdHJvbmVuIG9wIGhldCA1JSBzaWduaWZpY2FudGllbml2ZWF1LgoKQWFuIGRlIGhhbmQgdmFuIGRpdCByZXN1bHRhYXQgd2V0ZW4gd2UgZWNodGVyIG5pZXQgdHVzc2VuIHdlbGtlIHZvZWRpbmdlbiBlciBlZW4gdmVyc2NoaWwgb3B0cmVlZHQsIGVuIGhpZXJ2b29yIHp1bGxlbiB3ZSBlZW4gKipwb3N0LWhvYyBhbmFseXNlKiogbW9ldGVuIHVpdHZvZXJlbi4gRWVuIHBvc3QtaG9jIGFuYWx5c2Ugdm9lcnQgbWVuIGVua2VsIHVpdCBpbmRpZW4gZGUgQU5PVkEgdGVzdCBzaWduaWZpY2FudCB3YXMsIGVuIGJlc3RhYXQgZXJpbiBvbSBwYWFyc2dld2lqemUgdmVyZ2VsaWpraW5nZW4gdWl0IHRlIHZvZXJlbiB0dXNzZW4gZGUgZ3JvZXBlbi4gSW4gZGl0IGdldmFsIGtvbXQgZGl0IG92ZXJlZW4gbWV0IGhldCB2ZXJnZWxpamtlbiBvZiBlciBlZW4gdmVyc2NoaWwgaXMgdHVzc2VuIGdyb2VwIDEgZW4gMiwgdHVzc2VuIGdyb2VwIDEgZW4gMyBlbiB0dXNzZW4gZ3JvZXAgMiBlbiAzLiAKCgojIyBQb3N0LWhvYyBhbmFseXNlCgpEZSBwb3N0LWhvYyBhbmFseXNlIGJlc3RhYXQgZXJ1aXQgb20gcGFhcnNnZXdpanplIHRlc3RlbiB1aXQgdGUgdm9lcmVuLiBJbmRpZW4gbWVuIG92ZXIgJGskIGdyb2VwZW4gYmVzY2hpa3QgaXMgaGV0IHRvdGFhbCBhYW50YWwgcGFhcnNnZXdpanplIHZlcmdlbGlqa2luZ2VuIGdlbGlqayBhYW4gJGsoay0xKS8yJC4gQmlqIG9ucyBpcyAkaz0zJCB3YWFyZG9vciB3ZSAkMyQgcGFhcnNnZXdpanplIHZlcmdlbGlqa2luZ2VuIHp1bGxlbiB1aXR2b2VyZW4uCldlIGt1bm5lbiBlY2h0ZXIgbmlldCBlbGtlIHRlc3Qgb3AgaGV0IDUlIHNpZ25pZmljYW50aWVuaXZlYXUgdWl0dm9lcmVuIHZhbndlZ2UgaGV0IG1lZXJ2b3VkaWcgdG9ldHNlbiBwcm9ibGVlbS4gCkluZGllbiB3ZSAzIHZlcmdlbGlqa2luZ2VuIHpvdWRlbiB0ZXN0ZW4gZWxrIG9wIGhldCA1JSBzaWduaWZpY2FudGllbml2ZWF1LCBkYW4gaXMgZGUga2FucyBkYXQgd2UgbWluc3RlbnMgw6nDqW4gbnVsaHlwb3RoZXNlIG9udGVyZWNodCB6b3VkZW4gdmVyd2VycGVuIG5pZXQgbGFuZ2VyIGdlbGlqayBhYW4gb25zIHNpZ25pZmljYW50aWVuaXZlYXUgKDUlKS4KSW4gb25zIGdldmFsLCB6b3UgZGV6ZSBrYW5zIGdlbGlqayB6aWpuIGFhbjoKCmBgYHtSfQphbHBoYSA8LSAwLjA1Cm5Db21wYXJpc29ucyA8LSAzCjEtKDEtYWxwaGEpXm5Db21wYXJpc29ucwpgYGAKCkR1cyBpbmRpZW4gd2UgZWxrZSB0ZXN0IG9wIGhldCA1JSBzaWduaWZpY2FudGllbml2ZWF1IHpvdWRlbiB1aXR2b2VyZW4gaGViYmVuIHdlLCBhbHMgYWxsZSBudWxoeXBvdGhlc2VzIHdhYXIgem91ZGVuIHppam4sIGVlbiBrYW5zIHZhbiBgciByb3VuZCgxLSgxLWFscGhhKV5uQ29tcGFyaXNvbnMsMykqMTAwYCUgZGF0IHdlIG1pbnN0ZW5zIMOpw6luIG51bGh5cG90aGVzZSB2ZXJrZWVyZCB6b3VkZW4gdmVyd2VycGVuLgpPbSBkZXplIGthbnMgZ2xvYmFhbCBnZXppZW4gKGRpdCBpcywgb3ZlciBhbGxlIHBhYXJzZ2V3aWp6ZSB2ZXJnZWxpamtpbmdlbikgb3AgNSUgdGUgaG91ZGVuLCBrdW5uZW4gd2UgYmlqdm9vcmJlZWxkIGRlIEJvbmZlcnJvbmkgY29ycmVjdGllIHVpdHZvZXJlbi4KCkluIGBSYCBrdW5uZW4gd2UgZGUgcG9zdC1ob2MgYW5hbHlzZSB1aXR2b2VyZW4gbWV0IGJlaHVscCB2YW4gaGV0IGBtdWx0Y29tcGAgcGFja2FnZSBhYW4gZGUgaGFuZCB2YW4gZGUgYGdsaHRgIGZ1bmN0aWUuIFdlIHNwZWNpZmnDq3JlbiBoaWVyIGluIGhldCBgbGluZmN0YCBhcmd1bWVudCBkYXQgd2UgKm11bHRpcGxlIGNvbXBhcmlzb25zKiAoYG1jcGApIHdpbGxlbiB1aXR2b2VyZW4gd2FhcmJpaiB3ZSBhbGxlIHBhYXJzZ2V3aWp6ZSB2ZXJnZWxpamtpbmdlbiB2b29yIGRlIGBmZWVkYCB2YXJpYWJlbGUgd2lsbGVuIHRlc3RlbiBhYW4gZGUgaGFuZCB2YW4gZGUgYCJUdWtleSJgIG1ldGhvZGUuIERlIGBtdWx0Y29tcGAgcGFja2FnZSB6b3JndCBlcnZvb3IgZGF0IGRlemUgcC13YWFyZGVuIGF1dG9tYXRpc2NoIGdlY29ycmlnZWVyZCB3b3JkZW4gdm9vciBtZWVydm91ZGlnIHRvZXRzZW4uCgpgYGB7cn0Kc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKGxpYnJhcnkobXVsdGNvbXApKQptY3AgPC0gZ2xodChtb2RlbF9sbSxsaW5mY3Q9bWNwKGZlZWQ9IlR1a2V5IikpCnN1bW1hcnkgPC0gc3VtbWFyeShtY3ApCnN1bW1hcnkKYGBgCgpJbiBkZSBvdXRwdXQgaGllcnZhbiB6aWVuIHdlIGRlIHZlcnNjaGlsbGVuZGUgcGFhcnNnZXdpanplIHZlcmdlbGlqa2luZ2VuIGRpZSB3ZXJkZW4gdWl0dm9lcmQuIEJpanZvb3JiZWVsZCBgbGluc2VlZCAtIGNhc2VpbiA9PSAwYCBkdWlkdCBlcm9wIGRhdCB2b29yIGRpdCBjb250cmFzdCB3b3JkdCBnZXRlc3Qgb2YgaGV0IGdlbWlkZGVsZGUgZ2V3aWNodCB2b29yIHZvZWRpbmcgYGxpbnNlZWRgIG1pbiBoZXQgZ2VtaWRkZWxkZSBnZXdpY2h0IHZvb3Igc29vcnQgYGNhc2VpbmAgdmVyc2NoaWxsZW5kIGlzIHZhbiBudWwuCkluIGRlIHR3ZWVkZSBrb2xvbSB3b3JkdCBoZXQgdmVyc2NoaWwgaW4gZ2VtaWRkZWxkZW4gd2VlcmdlZ2V2ZW4sIG1ldCBodW4gc3RhbmRhYXJkIGVycm9yIGVuIHRlc3RzdGF0aXN0aWVrIGluIGRlIHJlc3BlY3RpZXZlbGlqayBkZXJkZSBlbiB2aWVyZGUga29sb20uCkRlIGxhYXRzdGUga29sb20gZ2VlZnQgYWFuZ2VwYXN0ZSBwLXdhYXJkZW4gd2VlciBvcCBlZW4gZ2xvYmFhbCBzaWduaWZpY2FudGllbml2ZWF1IHZhbiA1JS4KQWFuIGRlIGhhbmQgdmFuIGRlIGFhbmdlcGFzdGUgcC13YWFyZGVuIHppZW4gd2UgZGF0IGhldCBnZW1pZGRlbGRlIGdld2ljaHQgYmlqIGBjYXNlaW5gIHZlcnNjaGlsdCB2YW4gem93ZWwgYGxpbnNlZWRgIGVuIGBzb3liZWFuYCAocCA8IDAuMDAxIGVuIHAgPSAwLjAwNCkgb3AgaGV0IDUlIHNpZ25pZmljYW50aWVuaXZlYXUuIFdlIHppZW4gb29rIGRhdCBlciBnZWVuIHNpZ25pZmljYW50IHZlcnNjaGlsIGlzIGluIGdlbWlkZGVsZCBnZXdpY2h0IGJpaiB2b2VkaW5nIGBzb3liZWFuYCBlbiBgbGluc2VlZGAgb3AgaGV0IDUlIHNpZ25pZmljYW50aWVuaXZlYXUuCkRlIGVmZmVjdGdyb290dGUgaXMgdm9vciBiaWogem93ZWwgYGxpbnNlZWRgIGFscyBgc295YmVhbmAgbmVnYXRpZWYsIHdhdCBlcm9wIGR1aWR0IGRhdCBoZXQgZ2VtaWRkZWxkZSBnZXdpY2h0IHZhbiBrdWlrZW5zIGhvZ2VyIGlzIGJpaiB2b2VkaW5nc3BhdHJvb24gYGNhc2VpbmAuCgpEZSBiZXRyb3V3YmFhcmhlaWRzaW50ZXJ2YWxsZW4gdmFuIGVsa2UgcGFhcnNnZXdpanplIHRlc3Qga3VubmVuIHdlIG9vayBtYWtrZWxpamsgZ3JhZmlzY2ggdm9vcnN0ZWxsZW4gYWFuIGRlIGhhbmQgdmFuIGRlIGBwbG90YCBmdW5jdGllIGRpZSB6byBvcCBlZW4gYGdsaHRgIG9iamVjdCBrYW4gdG9lZ2VwYXN0IHdvcmRlbi4KCmBgYHtyfQpjb25maW50KG1jcCkKYGBgCgpgYGB7cn0KcGxvdChtY3ApCmBgYAoKCiMgQ29uY2x1c2llCgpXZSBrdW5uZW4gY29uY2x1ZGVyZW4gZGF0IGVyIGVlbiBzaWduaWZpY2FudCB2ZXJzY2hpbCBpbiBnZXdpY2h0IGlzIHR1c3NlbiBoZXQgZ2V3aWNodCB2YW4ga3Vpa2VudGplcyBtZXQgdm9lZGluZyBjYXNlaW5lIHRlZ2Vub3ZlciBkZSBhbmRlcmUgdm9lZGluZ2VuIG9wIGhldCA1JSBzaWduaWZpY2FudGllbml2ZWF1LiBUdXNzZW4gbGluc2VlZCBlbiBzb3liZWFuIGlzIGVyIGdlZW4gc2lnbmlmaWNhbnQgdmVyc2NoaWwgaW4gZ2V3aWNodCB2YW4gZGUga3Vpa2VudGplcy4KCg==