Libraries laden
library(ggplot2)
library(dplyr)
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
#install.packages("tidyr")
library(tidyr)
#install.packages("multcomp")
library(multcomp)
## Loading required package: mvtnorm
## Loading required package: survival
## Loading required package: TH.data
## Loading required package: MASS
##
## Attaching package: 'MASS'
## The following object is masked from 'package:dplyr':
##
## select
##
## Attaching package: 'TH.data'
## The following object is masked from 'package:MASS':
##
## geyser
Statististische
toets
Welke test kan men uitvoeren om de gemiddelde lengte simultaan te
vergelijken tussen alle soorten?
In vorige lessen 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 \]
Bijvoorbeeld, indien \(Y_i\) de
lengte van persoon \(i\) voorstelt en
\(X_i\) het geslacht van die persoon
waarbij \(X_i=0\) indien persoon \(i\) een vrouw is, en \(X_i=1\) indien niet. In dat geval, stelt
\(\beta_0\) de gemiddelde lengte voor
vrouwen voor, en \(\beta_1\) staat voor
het verschil in gemiddelde lengte tussen vrouwen en mannen. De
gemiddelde lengte voor een man kan men dan bekomen door \(E(Y_{male}) = \beta_0 + \beta_1\). Men kan
dit ook schrijven als \[ E(Y | female) =
E(Y|X=0) = \beta_0\] \[ E(Y | male) =
E(Y|X=1) = \beta_0 + \beta_1\]
Dit lineair model kan echter ook makkelijk veralgemeend worden naar
factoren met meerdere levels. Men kan inderdaad meerdere dummy
variabelen invoeren (1 minder dan het aantal toetsen). Voor ons
voorbeeld zullen we 5 dummyvariabelen nodig hebben: \(X_1\), \(X_2\), \(X_3\), \(X_4\) en \(X46\).
\[ E(Y_i) = \beta_0 + \beta_1 X_{1i}
+ \beta_2 X_{2i} + \beta_3 X_{3i} + \beta_4 X_{4i} + \beta_5
X_{5i}\]
De eerste soort is dan de referentiegroep (alle dummies \(X_1 = X_2 = X_3 = X_4 = X_5 =0\)).
\[ E(Y | soort_1) = \beta_0 + \beta_1 *0
+ \beta_2 *0 + \beta_3 *0 + \beta_4 *0 + \beta_5 *0 =
\beta_0\]
\[ E(Y | soort_2) = \beta_0 + \beta_1 *1
+ \beta_2 *0 + \beta_3 *0 + \beta_4 *0 + \beta_5 *0 = \beta_0 +
\beta_1\]
\[ E(Y | soort_3) = \beta_0 + \beta_1 *0
+ \beta_2 *1 + \beta_3 *0 + \beta_4 *0 + \beta_5 *0 = \beta_0 +
\beta_2\]
Er bestaat een manier waarbij we alle levels simultaan kunnen
testen, men zal namelijk testen of de gehele factor variabele
een invloed heeft op de respons. In de context van ons voorbeeld, zal
men kunnen testen of de pleegouder-soort uberhaupt een effect heeft op
de gemiddelde lengte van koekoekseieren. Zo’n een test heet een one-way
ANOVA. Men noemt de test ‘one-way’ omdat het de associatie bestudeert
tussen de response en 1 factor, met andere woorden het model bevat geen
meerdere factoren.
Nul- en alternatieve
hypothese voor de toets
Stel dat \(\mu_1\) de gemiddelde
lengte van koekoekseieren voor graspiepers (soort=1
)
voorstelt, en idem voor \(\mu_2 , \ldots ,
\mu_6\). De nul- en alternatieve hypothese voor een ANOVA kan men
dan voorstellen als
\(H_0\): \(\mu_1=\mu_2=\mu_3=\mu_4=\mu_5=\mu_6\)
\(H_A\): Voor minstens één \(i \ne j\) is \(\mu_i \neq \mu_j\)
De nulhypothese stelt dus dat de gemiddelde lengte van koekoekseiren
niet afhangt van de pleegouder-soort: er is geen systematisch verschil
in gemiddelde lengte van eieren tussen verschillende pleegouder-soorten.
De alternatieve hypothese stelt dat de gemiddelde lengte van
koekoekseieren verschilt tussen minstens twee
pleegouder-soorten. Merk op dat men bij het verwerpen van de
nulhypothese niet weet tussen welke soorten er een
verschil is!
Fit het model voor
de analyse
We fitten een lineair model met als respons variabele de lengte van
de eieren en als predictor de soort. Merk op dat het belangrijk is om
soort te definiëren als een factor, wat al in orde werd gebracht bij het
genereren van de boxplots. R zal dan automatisch het vereiste aantal
dummy-variabelen aanmaken.
m <- lm(lengte~soort, data = koekoek)
summary(m)
##
## Call:
## lm(formula = lengte ~ soort, data = koekoek)
##
## Residuals:
## Min 1Q Median 3Q Max
## -2.7376 -0.7406 0.0975 0.6869 2.7124
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 22.2876 0.1571 141.862 < 2e-16 ***
## soort2 0.8024 0.3142 2.554 0.011975 *
## soort3 0.8339 0.3225 2.585 0.010985 *
## soort4 0.2874 0.3068 0.937 0.350725
## soort5 0.6158 0.3142 1.960 0.052467 .
## soort6 -1.1576 0.3142 -3.684 0.000353 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 1.054 on 114 degrees of freedom
## Multiple R-squared: 0.254, Adjusted R-squared: 0.2213
## F-statistic: 7.762 on 5 and 114 DF, p-value: 2.576e-06
De output van het model suggereert dat er inderdaad verschillen
lijken te zijn in gemiddelde lengte tussen de pleegoudersoorten. Merk op
dat in de standaard output op basis van dit model de p-waarden echter
niet aangepast worden voor meervoudig toetsen. Ook laat het model enkel
toe om een toets uit te voeren voor de vergelijking tussen soorten 2-6
en de referentie soort = 1 (dus niet onderling tussen soorten 2-6).
Enkel de p-waarde van de globale F-toets kan voor een one-way ANOVA
analyse worden gebruikt. Het is de p-waarde die men bekomt wanneer men
ons model vergelijkt met een model met enkel het intercept. Het is dus
een toets voor de omnibus hypothese dat alle hellingparameters (\(\beta_1 - \beta_5\)) gelijk zijn aan
nul.
Ga de assumpties voor
een ANOVA na.
Zoals beschreven in de cursus, veronderstelt ANOVA een locatie-shift
model.
Dit wil zeggen dat de vorm van de distributie in elke groep gelijk is
en dat we veronderstellen dat er enkel shifts in gemiddelde kunnen
optreden tussen de groepen.
In het bijzonder nemen we de aanname dat de data van elke groep een
normale verdeling volgen. Dit impliceert dat de data in
- elke groep normaal verdeeld moeten zijn en
- dat de varianties van de data van alle groepen gelijk is.
Bovendien neemt de test nog aan dat alle observaties onafhankelijk
zijn van elkaar.
Deze laatste assumptie lijkt te zijn voldaan; de nesten werden
willekeurig gekozen.
De eerste twee assumpties kunnen we nagaan indien er niet te veel
groepen zijn. Hier hebben we zes groepen en is het checken van
assumpties binnen elke groep haalbaar.
Voor het nagaan van homoscedasticiteit werken we met boxplots:
We doen dit door de interquartiel ranges (boxbreedtes van de
boxplots) met elkaar te vergelijken.
De data lijken gelijke varianties te hebben, en deze assumptie lijkt
alvast niet geschonden.
Het is echter niet altijd eenvoudig om te beoordelen of de varianties
sterk van mekaar verschillen of niet. Om een beter idee te krijgen,
kunnen we eens een aantal boxplots simuleren met dezelfde
steekproefgrootte als in de dataset en in de veronderstelling dat de
varianties gelijk zijn.
set.seed(52)
par(mfrow=c(3,3), mar=c(3,2,1,1))
sd1<- m %>% sigma
means<- koekoek %>% group_by(soort) %>% summarise(m=mean(lengte))
nobs <-koekoek %>% count(soort)
plotList <- lapply(1:9, function(x,means,sd,nobs)
{
data.frame(y = rnorm(
sum(nobs$n),
mean=rep(means$m,times=nobs$n),
sd=sd),
soort = rep(nobs$soort,times=nobs$n)
) %>%
ggplot(aes(soort,y)) +
geom_boxplot(outlier.shape = NA) +
geom_jitter(alpha=.2)
}, means=means,nobs=nobs,sd=sd1)
library(gridExtra)
##
## Attaching package: 'gridExtra'
## The following object is masked from 'package:dplyr':
##
## combine
do.call("grid.arrange",c(plotList,nrow=3,ncol=3))
We zien dat de data die gesimuleerd wordt onder de model
veronderstellingen ook gelijkaardige variabiliteit in de boxbreedtes
vertonen door toeval.
We gaan vervolgens de assumptie na dat dat data binnen elke groep
normaal verdeeld zijn:
# Maak QQ-plot voor de lengte van de koekoekseieren per soort
plot_qq <- koekoek %>% ggplot(aes(sample = lengte)) +
geom_qq() + # qq-punten
geom_qq_line() + # qq-lijn
theme_bw() +
facet_wrap(~soort)
plot_qq
Bij de derde soort suggereert de QQ plot wat afwijkingen van
normaliteit. We stelden eerder al vast dat soort drie slechts 14
observaties bevat. We kunnen opnieuw data simuleren waarvoor alle
aannames voldaan zijn. De afwijkingen die we in onze qqplot zien lijken
niet zeer uitzonderlijk te zijn. Ook in de gesimuleerde data zijn we
vergelijkbare afwijkingen in sommige steekproeven.
plotList <- lapply(1:9, function(x,means,sd,nobs)
{
data.frame(y = rnorm(
sum(nobs$n),
mean=rep(means$m,times=nobs$n),
sd=sd),
soort = rep(nobs$soort,times=nobs$n)
) %>%
ggplot(aes(sample=y)) +
geom_qq() + # qq-punten
geom_qq_line() + # qq-lijn
theme_bw() +
facet_wrap(~soort)
}, means=means,nobs=nobs,sd=sd1)
plotList
## [[1]]
##
## [[2]]
##
## [[3]]
##
## [[4]]
##
## [[5]]
##
## [[6]]
##
## [[7]]
##
## [[8]]
##
## [[9]]
De data van elke groep lijken dus een normale verdeling te
volgen.
Indien men veel groepen moet vergelijken, kan het efficiënter 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 de respons variabele
rond hun groepsgemiddelde, en dus niet voor een normale distributie
binnen elke groep.
par(mfrow=c(2,2))
plot(m) # Enkel figuur rechts boven is relevant
De QQ-plot vertoont geen systematische afwijkingen van een normale
distributie.
Merk op dat je in principe de assumptie van homoscedasticiteit ook op
basis van de residuplot linksboven en linksonder 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. Hierbij is het voor dit voorbeeld wel van
belang om rekening te houden met het grote verschillen in
steekproefgrootte tussen de soorten.
Interpreteer de
resultaten van de ANOVA analyse
We voeren de ANOVA test uit aan de hand van het lineair
regressiemodel. In principe testen we dan volgende nulhypothese
\[ H_0: \beta_1 = \beta_2 = \beta_3 =
\beta_4 = \beta_5 = 0 \]
met de alternatieve hypothese dat minstens één regressieparameters
verschillend is van nul.
Merk op dat deze nulhypothese evenwaardig is aan de nulhypothese die
we eerder formuleerden. Als alle regressieparameters \(\beta_1, \dots, \beta_5 = 0\), betekent dit
dat er geen verschil is tussen de 6 groepsgemiddelde lengtes. Dat ziet
men ook eenvoudig in de output van de verschillende groepsgemiddeldes
die worden gemodelleerd met het model.
ExploreModelMatrix::VisualizeDesign(koekoek,~soort)$plotlist
## [[1]]
De p-waarde van deze ANOVA test is bijzonder klein. We besluiten dat
we de nulhypothese kunnen verwerpen (\(p<<0.001\)) en dat de gemiddelde
lengte van koekoekseieren verschilt tussen minstens twee van de
bestudeerde pleegoudersoorten op het 5% significantieniveau.
Aan de hand van dit resultaat weten we echter niet tussen welke
soorten er een verschil optreedt, en hiervoor zal men 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.
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\). In dit voorbeeld is \(k=6\) waardoor we \(15\) paarsgewijze vergelijkingen zullen
uitvoeren. We kunnen echter niet elke test op het 5% significantieniveau
uitvoeren vanwege het meervoudig toetsen probleem. Inderdaad, indien men
15 vergelijkingen zou doen, elk op het 5% significantieniveau, dan is de
kans dat we minstens één nulhypothese ten onrechte zouden verwerpen veel
hoger dan het significantieniveau (5%) die we voor elke individuele test
hebben gebruikt. Als alle pairsgewijze vergelijkingen onafhankelijk
zouden zijn van elkaar (wat ze niet zijn omdat een heel aantal
vergelijkingen dezelfde groepen delen) zouden we die kans kunnen
schatten als
alpha <- 0.05
nComparisons <- 15
1-(1-alpha)^nComparisons
## [1] 0.5367088
Een conservatieve bovengrens op die kans wordt gegeven door
Bonferroni:
## [1] 0.75
Dus indien we elke test op het 5% significantieniveau zouden
uitvoeren en als alle nulhypotheses waar zouden zijn, is het heel
waarschijnlijk dat we minstens één nulhypothese ten onrechte zouden
verwerpen! Om deze kans globaal gezien (dit is, over alle paarsgewijze
vergelijkingen) op 5% te houden, moeten we corrigeren voor meervoudig
testen.
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 soort
variabele willen testen aan de
hand van de "Tukey"
methode. Het resultaat van deze test
slaan we vervolgens op in het object mcp
, waarop we een
summary
opvragen van dat object. Het multcomp
package zorgt ervoor dat deze p-waarden automatisch gecorrigeerd worden
voor meervoudig toetsen.
library(multcomp)
mcp <- glht(m,linfct=mcp(soort="Tukey"))
summary(mcp)
##
## Simultaneous Tests for General Linear Hypotheses
##
## Multiple Comparisons of Means: Tukey Contrasts
##
##
## Fit: lm(formula = lengte ~ soort, data = koekoek)
##
## Linear Hypotheses:
## Estimate Std. Error t value Pr(>|t|)
## 2 - 1 == 0 0.80244 0.31421 2.554 0.11453
## 3 - 1 == 0 0.83387 0.32252 2.585 0.10648
## 4 - 1 == 0 0.28744 0.30676 0.937 0.93405
## 5 - 1 == 0 0.61578 0.31421 1.960 0.36564
## 6 - 1 == 0 -1.15756 0.31421 -3.684 0.00456 **
## 3 - 2 == 0 0.03143 0.39164 0.080 1.00000
## 4 - 2 == 0 -0.51500 0.37877 -1.360 0.74532
## 5 - 2 == 0 -0.18667 0.38483 -0.485 0.99648
## 6 - 2 == 0 -1.96000 0.38483 -5.093 < 0.001 ***
## 4 - 3 == 0 -0.54643 0.38569 -1.417 0.71100
## 5 - 3 == 0 -0.21810 0.39164 -0.557 0.99327
## 6 - 3 == 0 -1.99143 0.39164 -5.085 < 0.001 ***
## 5 - 4 == 0 0.32833 0.37877 0.867 0.95209
## 6 - 4 == 0 -1.44500 0.37877 -3.815 0.00286 **
## 6 - 5 == 0 -1.77333 0.38483 -4.608 < 0.001 ***
## ---
## 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. Elke vergelijking noemen we ook een
contrast. Contrast 2 - 1 == 0
duidt erop dat voor dit
contrast wordt getest of het verschil in gemiddelde lengte voor soort
2
en dat voor soort 1
gelijk is aan nul tegen
het alternatief dat beide gemiddeldes verschillend zijn. 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 de gemiddelde lengte van soort 6 (winterkoning) verschilt van
alle andere soorten. De effectgrootte is voor alle soorten negatief,
hetgeen impliceert dat de gemiddelde lengte van koekoekseieren lager is
in nesten van winterkoning in vergelijking met andere soorten.
Voor de rapportering zullen we ook betrouwbaarheidsintervallen voor
elke paarsgewijze vergelijking opvragen. We kunnen deze ook makkelijk
grafisch voorstellen aan de hand van de plot
functie die op
een glht
object kan toegepast worden. De
betrouwbaarheidsintervallen worden opnieuw gecorrigeerd voor meervoudig
testen.
##
## Simultaneous Confidence Intervals
##
## Multiple Comparisons of Means: Tukey Contrasts
##
##
## Fit: lm(formula = lengte ~ soort, data = koekoek)
##
## Quantile = 2.8894
## 95% family-wise confidence level
##
##
## Linear Hypotheses:
## Estimate lwr upr
## 2 - 1 == 0 0.80244 -0.10543 1.71032
## 3 - 1 == 0 0.83387 -0.09800 1.76575
## 4 - 1 == 0 0.28744 -0.59890 1.17379
## 5 - 1 == 0 0.61578 -0.29210 1.52365
## 6 - 1 == 0 -1.15756 -2.06543 -0.24968
## 3 - 2 == 0 0.03143 -1.10017 1.16303
## 4 - 2 == 0 -0.51500 -1.60941 0.57941
## 5 - 2 == 0 -0.18667 -1.29858 0.92525
## 6 - 2 == 0 -1.96000 -3.07192 -0.84808
## 4 - 3 == 0 -0.54643 -1.66082 0.56797
## 5 - 3 == 0 -0.21810 -1.34969 0.91350
## 6 - 3 == 0 -1.99143 -3.12303 -0.85983
## 5 - 4 == 0 0.32833 -0.76607 1.42274
## 6 - 4 == 0 -1.44500 -2.53941 -0.35059
## 6 - 5 == 0 -1.77333 -2.88525 -0.66142
Men kan de bekomen resultaten van de test ook interpreteren a.d.h.v.
ruwe data:
Waar we eveneens evidentie zien dat de eieren gemiddeld kleiner zijn
voor nesten van winterkoninkjes i.v.m. andere soorten.
Conclusie
winterId <- grep(rownames(confint(mcp)$confint),pattern="6")
Er is een extreem significant effect van de pleegoudersoort op de
gemiddelde lengte van koekoekseieren (one-way ANOVA test, \(p<<0.001\)). Op een globaal 5%
significantieniveau is de gemiddelde lengte van koekoekseieren in nesten
van winterkoning kleiner dan deze in nesten van alle andere bestudeerde
soorten: graspieper (Tukey test, verschil=-1.16, aangepaste p-waarde =
0.005, 95% BI: [-2.07, -0.25]), boompieper (Tukey test, verschil=-1.96,
aangepaste p-waarde < 0.001, 95% BI: [-3.07, -0.85]), heggenmus
(Tukey test, verschil=-1.99, aangepaste p-waarde < 0.001, 95% BI:
[-3.12, -0.86]), roodborstje (Tukey test, verschil=-1.45, aangepaste
p-waarde = 0.003, 95% BI: [-2.54, -0.35]) en witte kwikstaart (Tukey
test, verschil=-1.77, aangepaste p-waarde < 0.001, 95% BI: [-2.88,
-0.66]).
De verschillen in gemiddelde lengte van de koekoekseieren tussen de
overige soorten zijn niet significant.
LS0tCnRpdGxlOiAiUHJhY3RpY3VtIDU6IEFub3ZhIgphdXRob3I6ICJLb2VuIFZhbiBkZW4gQmVyZ2UgZW4gTGlldmVuIENsZW1lbnQiCmRhdGU6ICJzdGF0T21pY3MsIEdoZW50IFVuaXZlcnNpdHkgKGh0dHBzOi8vc3RhdG9taWNzLmdpdGh1Yi5pbykiCgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIGNvZGVfZG93bmxvYWQ6IHllcwogICAgaGlnaGxpZ2h0OiB0YW5nbwogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMKICAgIHRoZW1lOiBjb3NtbwogICAgdG9jOiB5ZXMKICAgIHRvY19mbG9hdDogeWVzCiAgcGRmX2RvY3VtZW50OgogICAgdG9jOiB5ZXMKICB3b3JkX2RvY3VtZW50OgogICAgdG9jOiB5ZXMKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQpgYGAKCjxhIHJlbD0ibGljZW5zZSIgaHJlZj0iaHR0cHM6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL2xpY2Vuc2VzL2J5LW5jLXNhLzQuMCI+PGltZyBhbHQ9IkNyZWF0aXZlIENvbW1vbnMgTGljZW5zZSIgc3R5bGU9ImJvcmRlci13aWR0aDowIiBzcmM9Imh0dHBzOi8vaS5jcmVhdGl2ZWNvbW1vbnMub3JnL2wvYnktbmMtc2EvNC4wLzg4eDMxLnBuZyIgLz48L2E+CgoKIyBEZSBrb2Vrb2VrIGRhdGFzZXQKCkhldCBpcyBiZWtlbmQgZGF0IGRlIGtvZWtvZWsgbmlldCB6ZWxmIGVlbiBuZXN0IGJvdXd0IG1hYXIgemlqbiBlaWVyZW4gbGVndCBpbiBkZSBuZXN0ZW4gdmFuIGFuZGVyZSB2b2dlbHMuIFNpbmRzIDE4OTIgd2VldCBtZW4gcmVlZHMgZGF0IGhldCBzb29ydCBrb2Vrb2Vrc2VpZXJlbiBlaWdlbiBpcyBhYW4gZGUgbG9jYXRpZSB3YWFyIHplIGdldm9uZGVuIHdvcmRlbi4gRWVuIHN0dWRpZSBpbiAxOTQwIHRvb25kZSBhYW4gZGF0IGRlIGtvZWtvZWtlbiBlbGsgamFhciB0ZXJ1Z2tlcmVuIG5hYXIgaGV0emVsZmRlIGdyb25kZ2ViaWVkIGVuIGVpZXJlbiBsZWdnZW4gaW4gZGUgbmVzdGVuIHZhbiB3ZWxiZXBhYWxkZSAicGxlZWdvdWRlciItdm9nZWxzLiBCb3ZlbmRpZW4gcGFyZW4ga29la29la2VuIGVua2VsIGJpbm5lbiBodW4gZ3JvbmRnZWJpZWQuIE9wIGRpZSBtYW5pZXIgemlqbiBnZW9ncmFmaXNjaGUgc3Vic29vcnRlbiBvbnR3aWtrZWxkLCBlbGsgbWV0IGVlbiBkb21pbmFudGUgcGxlZWdvdWRlci1zb29ydC4KSGllcmRvb3Iga29uIGVlbiBzcGVjaWFsaXNhdGllIG9wdHJlZGVuIHZhbiBkZSBrb2Vrb2VrIGFhbiBkZSBwbGVlZ291ZGVyLXNvb3J0IHZpYSBuYXR1dXJsaWprZSBzZWxlY3RpZSwgem9kYXQgZGUga29la29la3NlaWVyZW4gZWVuIGhvZ2VyZSBrYW5zIGtyZWdlbiBvbSBnZWFkb3B0ZWVyZCB0ZSB3b3JkZW4gZG9vciBkZSBwbGVlZ291ZGVyLXNvb3J0LgoKRGUgZGF0YXNldCBrb2Vrb2VrLnR4dCBiZXZhdCBkZSBsZW5ndGUgKHZhcmlhYmVsZSBgbGVuZ3RlYCkgdmFuIGRlIGtvZWtvZWtzZWllcmVuIChpbiBtbSkgdmFuIHdpbGxla2V1cmlnIGdla296ZW4gZ2VwYXJhc2l0ZWVyZGUgbmVzdGVuLiBJbiB0b3RhYWwgYmV2YXQgZGUgZGF0YXNldCAxMjAgb2JzZXJ2YXRpZXMgZW4gdm9vciBlbGsgZWkgaXMgYWFuZ2VnZXZlbiB2YW4gd2Vsa2Ugdm9nZWxzb29ydCAodmFyaWFiZWxlIGBzb29ydGApIGhldCBuZXN0IGlzLiBEZSBjb2RlcmluZyB2b29yIHNvb3J0IGlzIGFscyB2b2xndDoKCiAtIGBzb29ydD0xYDogZ3Jhc3BpZXBlcgogLSBgc29vcnQ9MmA6IGJvb21waWVwZXIKIC0gYHNvb3J0PTNgOiBoZWdnZW11cwogLSBgc29vcnQ9NGA6IHJvb2Rib3JzdGplCiAtIGBzb29ydD01YDogd2l0dGUga3dpa3N0YWFydAogLSBgc29vcnQ9NmA6IHdpbnRlcmtvbmluZwoKSW4gZGV6ZSBhbmFseXNlIHp1bGxlbiB3ZSBuYWdhYW4gb2YgZGUgcGxlZWdvdWRlci1zb29ydCBlZW4gaW52bG9lZCBoZWVmdCBvcCBkZSBnZW1pZGRlbGRlIGxlbmd0ZSB2YW4gZGUga29la29la3NlaWVyZW4uCgojIExpYnJhcmllcyBsYWRlbiAKYGBge3J9CmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShkcGx5cikKI2luc3RhbGwucGFja2FnZXMoInRpZHlyIikKbGlicmFyeSh0aWR5cikKI2luc3RhbGwucGFja2FnZXMoIm11bHRjb21wIikKbGlicmFyeShtdWx0Y29tcCkKYGBgCgojIERhdGFzZXQga29la29lay50eHQgaW5sZXplbgoKYGBge3J9CmtvZWtvZWs8LXJlYWQudGFibGUoImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9zdGF0T21pY3Mvc3RhdGlzdGlla0Jhc2lzQ3Vyc3VzRGF0YS9tYXN0ZXIvcHJhY3RpY3VtNS9rb2Vrb2VrLnR4dCIsaGVhZGVyPVRSVUUpCmhlYWQoa29la29laykKYGBgCgoKIyBEYXRhIGV4cGxvcmF0aWUKCiMjIEhvZXZlZWwgb2JzZXJ2YXRpZXMgemlqbiBlciB2b29yIGVsa2Ugc29vcnQ/IAoKVGVsIGhldCBhYW50YWwgb2JzZXJ2YXRpZXMgcGVyIHNvb3J0IGVuIHNsYSBoZXQgcmVzdWx0YWF0IG9wIGluIGBjb3VudGAuIE1hYWsgZWVuIGJhcnBsb3Qgdm9vciBkZSB2YXJpYWJlbGUgYHNvb3J0YC4KCmBgYHtyfQpjb3VudCA8LSBrb2Vrb2VrICU+JSBjb3VudChzb29ydCkKY291bnQKa29la29layAlPiUgZ2dwbG90KGFlcyh4ID0gc29vcnQpKSArIGdlb21fYmFyKGZpbGwgPSAic3RlZWxibHVlIikKYGBgCgojIyBEYXRhIHZpc3VhbGlzYXRpZQoKR2VuZXJlZXIgZWVuIGJveHBsb3QgdmFuIGRlIGxlbmd0ZSB2YW4gZGUga29la29la3NlaWVyZW4gdm9vciBlbGsgdmFuIGRlIDYgdm9nZWxzb29ydGVuLiBQbG90IG9vayBkZSBpbmRpdmlkdWVsZSBvYnNlcnZhdGllcy4KYGBge3J9CmtvZWtvZWskc29vcnQgPC0gYXMuZmFjdG9yKGtvZWtvZWskc29vcnQpCmJveHBsb3QgPC0gZ2dwbG90KGRhdGE9a29la29layxhZXMoeD1zb29ydCwgeT1sZW5ndGUsIGNvbD1zb29ydCkpICsgCiAgZ2VvbV9ib3hwbG90KG91dGxpZXIuc2hhcGUgPSBOQSkgKyAKICBnZW9tX2ppdHRlcigpICsKICB0aGVtZV9idygpICsgCiAgZ2d0aXRsZSgiTGVuZ3RlIHZhbiBkZSBrb2Vrb2Vrc2VpZXJlbiBwZXIgc29vcnQiKQpib3hwbG90CmBgYAoKCgojIFN0YXRpc3Rpc3Rpc2NoZSB0b2V0cwoKV2Vsa2UgdGVzdCBrYW4gbWVuIHVpdHZvZXJlbiBvbSBkZSBnZW1pZGRlbGRlIGxlbmd0ZSBzaW11bHRhYW4gdGUgdmVyZ2VsaWprZW4gdHVzc2VuIGFsbGUgc29vcnRlbj8KCkluIHZvcmlnZSBsZXNzZW4gemFnZW4gd2UgZW5rZWwgZGUgdHdvLXNhbXBsZSB0LXRlc3Qgb20gdHdlZSBnZW1pZGRlbGRlbiBtZXQgZWxrYWFyIHZlcmdlbGlqa2VuLgpXZSBoZWJiZW4gZWNodGVyIG9vayByZWVkcyBnZXppZW4gZGF0IGRlIHR3by1zYW1wbGUgdC10ZXN0IGVlbiBzcGVjaWZpZWtlIHZlcnNpZSBpcyB2YW4gZWVuIGxpbmVhaXIgbW9kZWwsIG5hbWVsaWprIHZhbiBlZW4gbGluZWFpciBtb2RlbCB3YWFyYmlqIGRlIGNvdmFyaWFhdCBlZW4gY2F0ZWdvcmlzY2hlIHZhcmlhYmVsZSAkWCQgaXMgbWV0ICQyJCBsZXZlbHMsIGkuZS4KXFsgRShZX2kpID0gXGJldGFfMCArIFxiZXRhXzEgWF9pIFxdCgpCaWp2b29yYmVlbGQsIGluZGllbiAkWV9pJCBkZSBsZW5ndGUgdmFuIHBlcnNvb24gJGkkIHZvb3JzdGVsdCBlbiAkWF9pJCBoZXQgZ2VzbGFjaHQgdmFuIGRpZSBwZXJzb29uIHdhYXJiaWogJFhfaT0wJCBpbmRpZW4gcGVyc29vbiAkaSQgZWVuIHZyb3V3IGlzLCBlbiAkWF9pPTEkIGluZGllbiBuaWV0LiBJbiBkYXQgZ2V2YWwsIHN0ZWx0ICRcYmV0YV8wJCBkZSBnZW1pZGRlbGRlIGxlbmd0ZSB2b29yIHZyb3V3ZW4gdm9vciwgZW4gJFxiZXRhXzEkIHN0YWF0IHZvb3IgaGV0IHZlcnNjaGlsIGluIGdlbWlkZGVsZGUgbGVuZ3RlIHR1c3NlbiB2cm91d2VuIGVuIG1hbm5lbi4gRGUgZ2VtaWRkZWxkZSBsZW5ndGUgdm9vciBlZW4gbWFuIGthbiBtZW4gZGFuIGJla29tZW4gZG9vciAkRShZX3ttYWxlfSkgPSBcYmV0YV8wICsgXGJldGFfMSQuIE1lbiBrYW4gZGl0IG9vayBzY2hyaWp2ZW4gYWxzClxbIEUoWSB8IGZlbWFsZSkgPSBFKFl8WD0wKSA9IFxiZXRhXzBcXQpcWyBFKFkgfCBtYWxlKSA9IEUoWXxYPTEpID0gXGJldGFfMCArIFxiZXRhXzFcXQoKRGl0IGxpbmVhaXIgbW9kZWwga2FuIGVjaHRlciBvb2sgbWFra2VsaWprIHZlcmFsZ2VtZWVuZCB3b3JkZW4gbmFhciBmYWN0b3JlbiBtZXQgbWVlcmRlcmUgbGV2ZWxzLiAKTWVuIGthbiBpbmRlcmRhYWQgbWVlcmRlcmUgZHVtbXkgdmFyaWFiZWxlbiBpbnZvZXJlbiAoMSBtaW5kZXIgZGFuIGhldCBhYW50YWwgdG9ldHNlbikuIApWb29yIG9ucyB2b29yYmVlbGQgenVsbGVuIHdlIDUgZHVtbXl2YXJpYWJlbGVuIG5vZGlnIGhlYmJlbjogJFhfMSQsICRYXzIkLCAkWF8zJCwgJFhfNCQgZW4gJFg0NiQuIAoKXFsgRShZX2kpID0gXGJldGFfMCArIFxiZXRhXzEgWF97MWl9ICsgIFxiZXRhXzIgWF97Mml9ICsgXGJldGFfMyBYX3szaX0gKyBcYmV0YV80IFhfezRpfSArIFxiZXRhXzUgWF97NWl9XF0KCkRlIGVlcnN0ZSBzb29ydCBpcyBkYW4gZGUgcmVmZXJlbnRpZWdyb2VwIChhbGxlIGR1bW1pZXMgJFhfMSA9IFhfMiA9IFhfMyA9IFhfNCA9IFhfNSA9MCQpLiAKClxbIEUoWSB8IHNvb3J0XzEpICA9IFxiZXRhXzAgKyBcYmV0YV8xICowICsgXGJldGFfMiAqMCArIFxiZXRhXzMgKjAgKyBcYmV0YV80ICowICsgXGJldGFfNSAqMCAgPSBcYmV0YV8wXF0KClxbIEUoWSB8IHNvb3J0XzIpICA9IFxiZXRhXzAgKyBcYmV0YV8xICoxICsgXGJldGFfMiAqMCArIFxiZXRhXzMgKjAgKyBcYmV0YV80ICowICsgXGJldGFfNSAqMCAgPSBcYmV0YV8wICsgXGJldGFfMVxdCgpcWyBFKFkgfCBzb29ydF8zKSAgPSBcYmV0YV8wICsgXGJldGFfMSAqMCArIFxiZXRhXzIgKjEgKyBcYmV0YV8zICowICsgXGJldGFfNCAqMCArIFxiZXRhXzUgKjAgID0gXGJldGFfMCArIFxiZXRhXzJcXQoKCgpFciBiZXN0YWF0IGVlbiBtYW5pZXIgd2FhcmJpaiB3ZSAqKmFsbGUgbGV2ZWxzIHNpbXVsdGFhbiBrdW5uZW4gdGVzdGVuKiosIG1lbiB6YWwgbmFtZWxpamsgdGVzdGVuIG9mIGRlIGdlaGVsZSBmYWN0b3IgdmFyaWFiZWxlIGVlbiBpbnZsb2VkIGhlZWZ0IG9wIGRlIHJlc3BvbnMuCkluIGRlIGNvbnRleHQgdmFuIG9ucyB2b29yYmVlbGQsIHphbCBtZW4ga3VubmVuIHRlc3RlbiBvZiBkZSBwbGVlZ291ZGVyLXNvb3J0IHViZXJoYXVwdCBlZW4gZWZmZWN0IGhlZWZ0IG9wIGRlIGdlbWlkZGVsZGUgbGVuZ3RlIHZhbiBrb2Vrb2Vrc2VpZXJlbi4KWm8nbiBlZW4gdGVzdCBoZWV0IGVlbiBvbmUtd2F5IEFOT1ZBLgpNZW4gbm9lbXQgZGUgdGVzdCAnb25lLXdheScgb21kYXQgaGV0IGRlIGFzc29jaWF0aWUgYmVzdHVkZWVydCB0dXNzZW4gZGUgcmVzcG9uc2UgZW4gMSBmYWN0b3IsIG1ldCBhbmRlcmUgd29vcmRlbiBoZXQgbW9kZWwgYmV2YXQgZ2VlbiBtZWVyZGVyZSBmYWN0b3Jlbi4KCgojIyBOdWwtIGVuIGFsdGVybmF0aWV2ZSBoeXBvdGhlc2Ugdm9vciBkZSB0b2V0cwoKU3RlbCBkYXQgJFxtdV8xJCBkZSBnZW1pZGRlbGRlIGxlbmd0ZSB2YW4ga29la29la3NlaWVyZW4gdm9vciBncmFzcGllcGVycyAoYHNvb3J0PTFgKSB2b29yc3RlbHQsIGVuIGlkZW0gdm9vciAkXG11XzIgLCBcbGRvdHMgLCBcbXVfNiQuCkRlIG51bC0gZW4gYWx0ZXJuYXRpZXZlIGh5cG90aGVzZSB2b29yIGVlbiBBTk9WQSBrYW4gbWVuIGRhbiB2b29yc3RlbGxlbiBhbHMKCiRIXzAkOiAkXG11XzE9XG11XzI9XG11XzM9XG11XzQ9XG11XzU9XG11XzYkCgokSF9BJDogVm9vciBtaW5zdGVucyDDqcOpbiAkaSBcbmUgaiQgaXMgJFxtdV9pIFxuZXEgXG11X2okCgpEZSBudWxoeXBvdGhlc2Ugc3RlbHQgZHVzIGRhdCBkZSBnZW1pZGRlbGRlIGxlbmd0ZSB2YW4ga29la29la3NlaXJlbiBuaWV0IGFmaGFuZ3QgdmFuIGRlIHBsZWVnb3VkZXItc29vcnQ6IGVyIGlzIGdlZW4gc3lzdGVtYXRpc2NoIHZlcnNjaGlsIGluIGdlbWlkZGVsZGUgbGVuZ3RlIHZhbiBlaWVyZW4gdHVzc2VuIHZlcnNjaGlsbGVuZGUgcGxlZWdvdWRlci1zb29ydGVuLgpEZSBhbHRlcm5hdGlldmUgaHlwb3RoZXNlIHN0ZWx0IGRhdCBkZSBnZW1pZGRlbGRlIGxlbmd0ZSB2YW4ga29la29la3NlaWVyZW4gdmVyc2NoaWx0IHR1c3NlbiAqKm1pbnN0ZW5zIHR3ZWUgcGxlZWdvdWRlci1zb29ydGVuKiouIE1lcmsgb3AgZGF0IG1lbiBiaWogaGV0IHZlcndlcnBlbiB2YW4gZGUgbnVsaHlwb3RoZXNlICoqbmlldCB3ZWV0IHR1c3NlbiB3ZWxrZSBzb29ydGVuKiogZXIgZWVuIHZlcnNjaGlsIGlzIQoKIyMjIEZpdCBoZXQgbW9kZWwgdm9vciBkZSBhbmFseXNlCldlIGZpdHRlbiBlZW4gbGluZWFpciBtb2RlbCBtZXQgYWxzIHJlc3BvbnMgdmFyaWFiZWxlIGRlIGxlbmd0ZSB2YW4gZGUgZWllcmVuIGVuIGFscyBwcmVkaWN0b3IgZGUgc29vcnQuIE1lcmsgb3AgZGF0IGhldCBiZWxhbmdyaWprIGlzIG9tIHNvb3J0IHRlIGRlZmluacOrcmVuIGFscyBlZW4gZmFjdG9yLCB3YXQgYWwgaW4gb3JkZSB3ZXJkIGdlYnJhY2h0IGJpaiBoZXQgZ2VuZXJlcmVuIHZhbiBkZSBib3hwbG90cy4gUiB6YWwgZGFuIGF1dG9tYXRpc2NoIGhldCB2ZXJlaXN0ZSBhYW50YWwgZHVtbXktdmFyaWFiZWxlbiBhYW5tYWtlbi4gCgoKYGBge3J9Cm0gPC0gbG0obGVuZ3RlfnNvb3J0LCBkYXRhID0ga29la29laykKc3VtbWFyeShtKQpgYGAKCkRlIG91dHB1dCB2YW4gaGV0IG1vZGVsIHN1Z2dlcmVlcnQgZGF0IGVyIGluZGVyZGFhZCB2ZXJzY2hpbGxlbiBsaWprZW4gdGUgemlqbiBpbiBnZW1pZGRlbGRlIGxlbmd0ZSB0dXNzZW4gZGUgcGxlZWdvdWRlcnNvb3J0ZW4uIE1lcmsgb3AgZGF0IGluIGRlIHN0YW5kYWFyZCBvdXRwdXQgb3AgYmFzaXMgdmFuIGRpdCBtb2RlbCBkZSBwLXdhYXJkZW4gZWNodGVyIG5pZXQgYWFuZ2VwYXN0IHdvcmRlbiB2b29yIG1lZXJ2b3VkaWcgdG9ldHNlbi4gT29rIGxhYXQgaGV0IG1vZGVsIGVua2VsIHRvZSBvbSBlZW4gdG9ldHMgdWl0IHRlIHZvZXJlbiB2b29yIGRlIHZlcmdlbGlqa2luZyB0dXNzZW4gc29vcnRlbiAyLTYgZW4gZGUgcmVmZXJlbnRpZSBzb29ydCA9IDEgKGR1cyBuaWV0IG9uZGVybGluZyB0dXNzZW4gc29vcnRlbiAyLTYpLiAKCkVua2VsIGRlIHAtd2FhcmRlIHZhbiBkZSBnbG9iYWxlIEYtdG9ldHMga2FuIHZvb3IgZWVuIG9uZS13YXkgQU5PVkEgYW5hbHlzZSB3b3JkZW4gZ2VicnVpa3QuIEhldCBpcyBkZSBwLXdhYXJkZSBkaWUgbWVuIGJla29tdCB3YW5uZWVyIG1lbiBvbnMgbW9kZWwgdmVyZ2VsaWprdCBtZXQgZWVuIG1vZGVsIG1ldCBlbmtlbCBoZXQgaW50ZXJjZXB0LiBIZXQgaXMgZHVzIGVlbiB0b2V0cyB2b29yIGRlIG9tbmlidXMgaHlwb3RoZXNlIGRhdCBhbGxlIGhlbGxpbmdwYXJhbWV0ZXJzICgkXGJldGFfMSAtIFxiZXRhXzUkKSBnZWxpamsgemlqbiBhYW4gbnVsLiAKCiMjIEdhIGRlIGFzc3VtcHRpZXMgdm9vciBlZW4gQU5PVkEgbmEuCgpab2FscyBiZXNjaHJldmVuIGluIGRlIGN1cnN1cywgdmVyb25kZXJzdGVsdCBBTk9WQSBlZW4gbG9jYXRpZS1zaGlmdCBtb2RlbC4KCkRpdCB3aWwgemVnZ2VuIGRhdCBkZSB2b3JtIHZhbiBkZSBkaXN0cmlidXRpZSBpbiBlbGtlIGdyb2VwIGdlbGlqayBpcyBlbiBkYXQgd2UgdmVyb25kZXJzdGVsbGVuIGRhdCBlciBlbmtlbCBzaGlmdHMgaW4gZ2VtaWRkZWxkZSBrdW5uZW4gb3B0cmVkZW4gdHVzc2VuIGRlIGdyb2VwZW4uCgpJbiBoZXQgYmlqem9uZGVyIG5lbWVuIHdlIGRlIGFhbm5hbWUgZGF0IGRlIGRhdGEgdmFuIGVsa2UgZ3JvZXAgZWVuIG5vcm1hbGUgdmVyZGVsaW5nIHZvbGdlbi4KRGl0IGltcGxpY2VlcnQgZGF0IGRlIGRhdGEgaW4KCiAtIGVsa2UgZ3JvZXAgbm9ybWFhbCB2ZXJkZWVsZCBtb2V0ZW4gemlqbiBlbgogLSBkYXQgZGUgdmFyaWFudGllcyB2YW4gZGUgZGF0YSB2YW4gYWxsZSBncm9lcGVuIGdlbGlqayBpcy4KIAogQm92ZW5kaWVuIG5lZW10IGRlIHRlc3Qgbm9nIGFhbiBkYXQgYWxsZSBvYnNlcnZhdGllcyBvbmFmaGFua2VsaWprIHppam4gdmFuIGVsa2Fhci4gCgpEZXplIGxhYXRzdGUgYXNzdW1wdGllIGxpamt0IHRlIHppam4gdm9sZGFhbjsgZGUgbmVzdGVuIHdlcmRlbiB3aWxsZWtldXJpZyBnZWtvemVuLgoKRGUgZWVyc3RlIHR3ZWUgYXNzdW1wdGllcyBrdW5uZW4gd2UgbmFnYWFuIGluZGllbiBlciBuaWV0IHRlIHZlZWwgZ3JvZXBlbiB6aWpuLiBIaWVyIGhlYmJlbiB3ZSB6ZXMgZ3JvZXBlbiBlbiBpcyBoZXQgY2hlY2tlbiB2YW4gYXNzdW1wdGllcyBiaW5uZW4gZWxrZSBncm9lcCBoYWFsYmFhci4KClZvb3IgaGV0IG5hZ2FhbiB2YW4gaG9tb3NjZWRhc3RpY2l0ZWl0IHdlcmtlbiB3ZSBtZXQgYm94cGxvdHM6CgpgYGB7cn0KYm94cGxvdApgYGAKCldlIGRvZW4gZGl0IGRvb3IgZGUgaW50ZXJxdWFydGllbCByYW5nZXMgKGJveGJyZWVkdGVzIHZhbiBkZSBib3hwbG90cykgbWV0IGVsa2FhciB0ZSB2ZXJnZWxpamtlbi4gCgpEZSBkYXRhIGxpamtlbiBnZWxpamtlIHZhcmlhbnRpZXMgdGUgaGViYmVuLCBlbiBkZXplIGFzc3VtcHRpZSBsaWprdCBhbHZhc3QgbmlldCBnZXNjaG9uZGVuLgoKSGV0IGlzIGVjaHRlciBuaWV0IGFsdGlqZCBlZW52b3VkaWcgb20gdGUgYmVvb3JkZWxlbiBvZiBkZSB2YXJpYW50aWVzIHN0ZXJrIHZhbiBtZWthYXIgdmVyc2NoaWxsZW4gb2YgbmlldC4gT20gZWVuIGJldGVyIGlkZWUgdGUga3Jpamdlbiwga3VubmVuIHdlIGVlbnMgZWVuIGFhbnRhbCBib3hwbG90cyBzaW11bGVyZW4gbWV0IGRlemVsZmRlIHN0ZWVrcHJvZWZncm9vdHRlIGFscyBpbiBkZSBkYXRhc2V0IGVuIGluIGRlIHZlcm9uZGVyc3RlbGxpbmcgZGF0IGRlIHZhcmlhbnRpZXMgZ2VsaWprIHppam4uCgpgYGB7cn0Kc2V0LnNlZWQoNTIpCnBhcihtZnJvdz1jKDMsMyksIG1hcj1jKDMsMiwxLDEpKQpzZDE8LSBtICU+JSBzaWdtYQptZWFuczwtIGtvZWtvZWsgJT4lIGdyb3VwX2J5KHNvb3J0KSAlPiUgc3VtbWFyaXNlKG09bWVhbihsZW5ndGUpKQpub2JzIDwta29la29layAlPiUgY291bnQoc29vcnQpIAoKcGxvdExpc3QgPC0gbGFwcGx5KDE6OSwgZnVuY3Rpb24oeCxtZWFucyxzZCxub2JzKQp7CiAgZGF0YS5mcmFtZSh5ID0gcm5vcm0oCiAgICAgIHN1bShub2JzJG4pLAogICAgICBtZWFuPXJlcChtZWFucyRtLHRpbWVzPW5vYnMkbiksCiAgICAgIHNkPXNkKSwKICAgICAgc29vcnQgPSAgcmVwKG5vYnMkc29vcnQsdGltZXM9bm9icyRuKQogICkgJT4lIAogICAgZ2dwbG90KGFlcyhzb29ydCx5KSkgKwogICAgZ2VvbV9ib3hwbG90KG91dGxpZXIuc2hhcGUgPSBOQSkgKwogICAgZ2VvbV9qaXR0ZXIoYWxwaGE9LjIpCn0sIG1lYW5zPW1lYW5zLG5vYnM9bm9icyxzZD1zZDEpCmxpYnJhcnkoZ3JpZEV4dHJhKQpkby5jYWxsKCJncmlkLmFycmFuZ2UiLGMocGxvdExpc3QsbnJvdz0zLG5jb2w9MykpCmBgYAoKV2UgemllbiBkYXQgZGUgZGF0YSBkaWUgZ2VzaW11bGVlcmQgd29yZHQgb25kZXIgZGUgbW9kZWwgdmVyb25kZXJzdGVsbGluZ2VuIG9vayBnZWxpamthYXJkaWdlIHZhcmlhYmlsaXRlaXQgaW4gZGUgYm94YnJlZWR0ZXMgdmVydG9uZW4gZG9vciB0b2V2YWwuIAoKV2UgZ2FhbiB2ZXJ2b2xnZW5zIGRlIGFzc3VtcHRpZSBuYSBkYXQgZGF0IGRhdGEgYmlubmVuIGVsa2UgZ3JvZXAgbm9ybWFhbCB2ZXJkZWVsZCB6aWpuOgoKYGBge3J9CiMgTWFhayBRUS1wbG90IHZvb3IgZGUgbGVuZ3RlIHZhbiBkZSBrb2Vrb2Vrc2VpZXJlbiBwZXIgc29vcnQgCnBsb3RfcXEgPC0ga29la29layAlPiUgZ2dwbG90KGFlcyhzYW1wbGUgPSBsZW5ndGUpKSArIAogICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3FxKCkgKyAjIHFxLXB1bnRlbgogICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3FxX2xpbmUoKSArICMgcXEtbGlqbgogICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9idygpICsgCiAgICAgICAgICAgICAgICAgICAgICAgIGZhY2V0X3dyYXAofnNvb3J0KQpwbG90X3FxCmBgYAoKQmlqIGRlIGRlcmRlIHNvb3J0IHN1Z2dlcmVlcnQgZGUgUVEgcGxvdCB3YXQgYWZ3aWpraW5nZW4gdmFuIG5vcm1hbGl0ZWl0LiAKV2Ugc3RlbGRlbiBlZXJkZXIgYWwgdmFzdCBkYXQgc29vcnQgZHJpZSBzbGVjaHRzIDE0IG9ic2VydmF0aWVzIGJldmF0LiAKV2Uga3VubmVuIG9wbmlldXcgZGF0YSBzaW11bGVyZW4gd2FhcnZvb3IgYWxsZSBhYW5uYW1lcyB2b2xkYWFuIHppam4uIApEZSBhZndpamtpbmdlbiBkaWUgd2UgaW4gb256ZSBxcXBsb3QgemllbiBsaWprZW4gbmlldCB6ZWVyIHVpdHpvbmRlcmxpamsgdGUgemlqbi4gCk9vayBpbiBkZSBnZXNpbXVsZWVyZGUgZGF0YSB6aWpuIHdlIHZlcmdlbGlqa2JhcmUgYWZ3aWpraW5nZW4gaW4gc29tbWlnZSBzdGVla3Byb2V2ZW4uCgpgYGB7cn0KcGxvdExpc3QgPC0gbGFwcGx5KDE6OSwgZnVuY3Rpb24oeCxtZWFucyxzZCxub2JzKQp7CiAgZGF0YS5mcmFtZSh5ID0gcm5vcm0oCiAgICAgIHN1bShub2JzJG4pLAogICAgICBtZWFuPXJlcChtZWFucyRtLHRpbWVzPW5vYnMkbiksCiAgICAgIHNkPXNkKSwKICAgICAgc29vcnQgPSAgcmVwKG5vYnMkc29vcnQsdGltZXM9bm9icyRuKQogICkgJT4lIAogICAgZ2dwbG90KGFlcyhzYW1wbGU9eSkpICsKICAgIGdlb21fcXEoKSArICMgcXEtcHVudGVuCiAgICBnZW9tX3FxX2xpbmUoKSArICMgcXEtbGlqbgogICAgdGhlbWVfYncoKSArIAogICAgZmFjZXRfd3JhcCh+c29vcnQpCn0sIG1lYW5zPW1lYW5zLG5vYnM9bm9icyxzZD1zZDEpCnBsb3RMaXN0CmBgYAoKCgpEZSBkYXRhIHZhbiBlbGtlIGdyb2VwIGxpamtlbiBkdXMgZWVuIG5vcm1hbGUgdmVyZGVsaW5nIHRlIHZvbGdlbi4KCkluZGllbiBtZW4gdmVlbCBncm9lcGVuIG1vZXQgdmVyZ2VsaWprZW4sIGthbiBoZXQgZWZmaWNpw6tudGVyIHppam4gb20gc2xlY2h0cyDDqcOpbiBwbG90IHRlIG1vZXRlbiBiZW9vcmRlbGVuLiBJbiBkYXQgZ2V2YWwga2FuIG1lbiBlcnZvb3Iga2llemVuIG9tIG5pZXQgdm9vciBlbGtlIGdyb2VwIGFwYXJ0IGVlbiBRUS1wbG90IHRlIG1ha2VuLCBtYWFyIGthbiBtZW4gZGUgcmVzaWR1ZW4gdmFuIGhldCBsaW5lYWlyIG1vZGVsIGNoZWNrZW4uIApNZXJrIG9wIGRhdCBtZW4gZGFuIGNoZWNrdCB2b29yIGVlbiBub3JtYWxlIGRpc3RyaWJ1dGllIHZhbiBhbGxlIHJlc2lkdWVuIHZhbiBkZSByZXNwb25zIHZhcmlhYmVsZSByb25kIGh1biBncm9lcHNnZW1pZGRlbGRlLCBlbiBkdXMgbmlldCB2b29yIGVlbiBub3JtYWxlIGRpc3RyaWJ1dGllIGJpbm5lbiBlbGtlIGdyb2VwLgoKYGBge3J9CnBhcihtZnJvdz1jKDIsMikpCnBsb3QobSkgIyBFbmtlbCBmaWd1dXIgcmVjaHRzIGJvdmVuIGlzIHJlbGV2YW50CnBhcihtZnJvdz1jKDEsMSkpCmBgYAoKRGUgUVEtcGxvdCB2ZXJ0b29udCBnZWVuIHN5c3RlbWF0aXNjaGUgYWZ3aWpraW5nZW4gdmFuIGVlbiBub3JtYWxlIGRpc3RyaWJ1dGllLiAKCk1lcmsgb3AgZGF0IGplIGluIHByaW5jaXBlIGRlIGFzc3VtcHRpZSB2YW4gaG9tb3NjZWRhc3RpY2l0ZWl0IG9vayBvcCBiYXNpcyB2YW4gZGUgcmVzaWR1cGxvdCBsaW5rc2JvdmVuIGVuIGxpbmtzb25kZXIgem91IGt1bm5lbiBjaGVja2VuOiBlbGtlICdrb2xvbScgdmFuIHB1bnRlbiBzdGVsdCBlZW4gc29vcnQgdm9vciAoMSBzb29ydCBoZWVmdCAxIGdlc2NoYXQgZ2VtaWRkZWxkZSkgZW4gZGUgcHVudGVuIHN0ZWxsZW4gZGUgcmVzaWR1ZW4gdm9vciB0ZW4gb3B6aWNodGUgdmFuIGh1biBncm9lcHNnZW1pZGRlbGRlLiBNZW4ga2FuIGRlemUgcGxvdCBkdXMgb29rIGdlYnJ1aWtlbiBvbSB0ZSBraWprZW4gb2YgZXIgZ3JvZXBlbiAoc29vcnRlbikgemlqbiBkaWUgZWVuIHZlcnNjaGlsbGVuZGUgdmFyaWFudGllIGhlYmJlbiB0ZW4gb3B6aWNodGUgdmFuIGFuZGVyZSBncm9lcGVuLiBIaWVyYmlqIGlzIGhldCB2b29yIGRpdCB2b29yYmVlbGQgd2VsIHZhbiBiZWxhbmcgb20gcmVrZW5pbmcgdGUgaG91ZGVuIG1ldCBoZXQgZ3JvdGUgdmVyc2NoaWxsZW4gaW4gc3RlZWtwcm9lZmdyb290dGUgdHVzc2VuIGRlIHNvb3J0ZW4uIAoKIyMgSW50ZXJwcmV0ZWVyIGRlIHJlc3VsdGF0ZW4gdmFuIGRlIEFOT1ZBIGFuYWx5c2UKCldlIHZvZXJlbiBkZSBBTk9WQSB0ZXN0IHVpdCBhYW4gZGUgaGFuZCB2YW4gaGV0IGxpbmVhaXIgcmVncmVzc2llbW9kZWwuIEluIHByaW5jaXBlIHRlc3RlbiB3ZSBkYW4gdm9sZ2VuZGUgbnVsaHlwb3RoZXNlCgpcWyBIXzA6IFxiZXRhXzEgPSBcYmV0YV8yID0gXGJldGFfMyA9IFxiZXRhXzQgPSBcYmV0YV81ID0gMCAgXF0KCm1ldCBkZSBhbHRlcm5hdGlldmUgaHlwb3RoZXNlIGRhdCBtaW5zdGVucyDDqcOpbiByZWdyZXNzaWVwYXJhbWV0ZXJzIHZlcnNjaGlsbGVuZCBpcyB2YW4gbnVsLiAKCk1lcmsgb3AgZGF0IGRlemUgbnVsaHlwb3RoZXNlIGV2ZW53YWFyZGlnIGlzIGFhbiBkZSBudWxoeXBvdGhlc2UgZGllIHdlIGVlcmRlciBmb3JtdWxlZXJkZW4uIEFscyBhbGxlIHJlZ3Jlc3NpZXBhcmFtZXRlcnMgJFxiZXRhXzEsIFxkb3RzLCBcYmV0YV81ID0gMCQsIGJldGVrZW50IGRpdCBkYXQgZXIgZ2VlbiB2ZXJzY2hpbCBpcyB0dXNzZW4gZGUgNiBncm9lcHNnZW1pZGRlbGRlIGxlbmd0ZXMuIERhdCB6aWV0IG1lbiBvb2sgZWVudm91ZGlnIGluIGRlIG91dHB1dCB2YW4gZGUgdmVyc2NoaWxsZW5kZSBncm9lcHNnZW1pZGRlbGRlcyBkaWUgd29yZGVuIGdlbW9kZWxsZWVyZCBtZXQgaGV0IG1vZGVsLiAKCmBgYHtyfQpFeHBsb3JlTW9kZWxNYXRyaXg6OlZpc3VhbGl6ZURlc2lnbihrb2Vrb2VrLH5zb29ydCkkcGxvdGxpc3QKYGBgCgoKYGBge3J9CmFub3ZhKG0pCmBgYAoKRGUgcC13YWFyZGUgdmFuIGRlemUgQU5PVkEgdGVzdCBpcyBiaWp6b25kZXIga2xlaW4uIFdlIGJlc2x1aXRlbiBkYXQgd2UgZGUgbnVsaHlwb3RoZXNlIGt1bm5lbiB2ZXJ3ZXJwZW4gKCRwPDwwLjAwMSQpIGVuIGRhdCBkZSBnZW1pZGRlbGRlIGxlbmd0ZSB2YW4ga29la29la3NlaWVyZW4gdmVyc2NoaWx0IHR1c3NlbiBtaW5zdGVucyB0d2VlIHZhbiBkZSBiZXN0dWRlZXJkZSBwbGVlZ291ZGVyc29vcnRlbiBvcCBoZXQgNSUgc2lnbmlmaWNhbnRpZW5pdmVhdS4KCkFhbiBkZSBoYW5kIHZhbiBkaXQgcmVzdWx0YWF0IHdldGVuIHdlIGVjaHRlciBuaWV0IHR1c3NlbiB3ZWxrZSBzb29ydGVuIGVyIGVlbiB2ZXJzY2hpbCBvcHRyZWVkdCwgZW4gaGllcnZvb3IgemFsIG1lbiBlZW4gKipwb3N0LWhvYyBhbmFseXNlKiogbW9ldGVuIHVpdHZvZXJlbi4gRWVuIHBvc3QtaG9jIGFuYWx5c2Ugdm9lcnQgbWVuIGVua2VsIHVpdCBpbmRpZW4gZGUgQU5PVkEgdGVzdCBzaWduaWZpY2FudCB3YXMsIGVuIGJlc3RhYXQgZXJpbiBvbSBwYWFyc2dld2lqemUgdmVyZ2VsaWpraW5nZW4gdWl0IHRlIHZvZXJlbiB0dXNzZW4gZGUgZ3JvZXBlbi4KCiMjIyBQb3N0LWhvYyBhbmFseXNlCgpEZSBwb3N0LWhvYyBhbmFseXNlIGJlc3RhYXQgZXJ1aXQgb20gcGFhcnNnZXdpanplIHRlc3RlbiB1aXQgdGUgdm9lcmVuLiBJbmRpZW4gbWVuIG92ZXIgJGskIGdyb2VwZW4gYmVzY2hpa3QgaXMgaGV0IHRvdGFhbCBhYW50YWwgcGFhcnNnZXdpanplIHZlcmdlbGlqa2luZ2VuIGdlbGlqayBhYW4gJGsoay0xKS8yJC4gSW4gZGl0IHZvb3JiZWVsZCBpcyAkaz02JCB3YWFyZG9vciB3ZSAkMTUkIHBhYXJzZ2V3aWp6ZSB2ZXJnZWxpamtpbmdlbiB6dWxsZW4gdWl0dm9lcmVuLgpXZSBrdW5uZW4gZWNodGVyIG5pZXQgZWxrZSB0ZXN0IG9wIGhldCA1JSBzaWduaWZpY2FudGllbml2ZWF1IHVpdHZvZXJlbiB2YW53ZWdlIGhldCBtZWVydm91ZGlnIHRvZXRzZW4gcHJvYmxlZW0uIApJbmRlcmRhYWQsIGluZGllbiBtZW4gMTUgdmVyZ2VsaWpraW5nZW4gem91IGRvZW4sIGVsayBvcCBoZXQgNSUgc2lnbmlmaWNhbnRpZW5pdmVhdSwgZGFuIGlzIGRlIGthbnMgZGF0IHdlIG1pbnN0ZW5zIMOpw6luIG51bGh5cG90aGVzZSB0ZW4gb25yZWNodGUgem91ZGVuIHZlcndlcnBlbiB2ZWVsIGhvZ2VyIGRhbiBoZXQgc2lnbmlmaWNhbnRpZW5pdmVhdSAoNSUpIGRpZSB3ZSB2b29yIGVsa2UgaW5kaXZpZHVlbGUgdGVzdCBoZWJiZW4gZ2VicnVpa3QuCkFscyBhbGxlIHBhaXJzZ2V3aWp6ZSB2ZXJnZWxpamtpbmdlbiBvbmFmaGFua2VsaWprIHpvdWRlbiB6aWpuIHZhbiBlbGthYXIgKHdhdCB6ZSBuaWV0IHppam4gb21kYXQgZWVuIGhlZWwgYWFudGFsIHZlcmdlbGlqa2luZ2VuIGRlemVsZmRlIGdyb2VwZW4gZGVsZW4pIHpvdWRlbiB3ZSBkaWUga2FucyBrdW5uZW4gc2NoYXR0ZW4gYWxzIAoKYGBge3J9CmFscGhhIDwtIDAuMDUKbkNvbXBhcmlzb25zIDwtIDE1CjEtKDEtYWxwaGEpXm5Db21wYXJpc29ucwpgYGAKCkVlbiBjb25zZXJ2YXRpZXZlIGJvdmVuZ3JlbnMgb3AgZGllIGthbnMgd29yZHQgZ2VnZXZlbiBkb29yIEJvbmZlcnJvbmk6IAoKYGBge3J9CmFscGhhICogbkNvbXBhcmlzb25zCmBgYAoKRHVzIGluZGllbiB3ZSBlbGtlIHRlc3Qgb3AgaGV0IDUlIHNpZ25pZmljYW50aWVuaXZlYXUgem91ZGVuIHVpdHZvZXJlbiBlbiBhbHMgYWxsZSBudWxoeXBvdGhlc2VzIHdhYXIgem91ZGVuIHppam4sIGlzIGhldCBoZWVsIHdhYXJzY2hpam5saWprIGRhdCB3ZSBtaW5zdGVucyDDqcOpbiBudWxoeXBvdGhlc2UgdGVuIG9ucmVjaHRlIHpvdWRlbiB2ZXJ3ZXJwZW4hCk9tIGRlemUga2FucyBnbG9iYWFsIGdlemllbiAoZGl0IGlzLCBvdmVyIGFsbGUgcGFhcnNnZXdpanplIHZlcmdlbGlqa2luZ2VuKSBvcCA1JSB0ZSBob3VkZW4sIG1vZXRlbiB3ZSBjb3JyaWdlcmVuIHZvb3IgbWVlcnZvdWRpZyB0ZXN0ZW4uIAoKSW4gYFJgIGt1bm5lbiB3ZSBkZSBwb3N0LWhvYyBhbmFseXNlIHVpdHZvZXJlbiBtZXQgYmVodWxwIHZhbiBoZXQgYG11bHRjb21wYCBwYWNrYWdlIGFhbiBkZSBoYW5kIHZhbiBkZSBgZ2xodGAgZnVuY3RpZS4gV2Ugc3BlY2lmacOrcmVuIGhpZXIgaW4gaGV0IGBsaW5mY3RgIGFyZ3VtZW50IGRhdCB3ZSAqbXVsdGlwbGUgY29tcGFyaXNvbnMqIChgbWNwYCkgd2lsbGVuIHVpdHZvZXJlbiB3YWFyYmlqIHdlIGFsbGUgcGFhcnNnZXdpanplIHZlcmdlbGlqa2luZ2VuIHZvb3IgZGUgYHNvb3J0YCB2YXJpYWJlbGUgd2lsbGVuIHRlc3RlbiBhYW4gZGUgaGFuZCB2YW4gZGUgYCJUdWtleSJgIG1ldGhvZGUuIEhldCByZXN1bHRhYXQgdmFuIGRlemUgdGVzdCBzbGFhbiB3ZSB2ZXJ2b2xnZW5zIG9wIGluIGhldCBvYmplY3QgYG1jcGAsIHdhYXJvcCB3ZSBlZW4gYHN1bW1hcnlgIG9wdnJhZ2VuIHZhbiBkYXQgb2JqZWN0LiBIZXQgYG11bHRjb21wYCBwYWNrYWdlIHpvcmd0IGVydm9vciBkYXQgZGV6ZSBwLXdhYXJkZW4gYXV0b21hdGlzY2ggZ2Vjb3JyaWdlZXJkIHdvcmRlbiB2b29yIG1lZXJ2b3VkaWcgdG9ldHNlbi4KCmBgYHtyfQpsaWJyYXJ5KG11bHRjb21wKQptY3AgPC0gZ2xodChtLGxpbmZjdD1tY3Aoc29vcnQ9IlR1a2V5IikpCnN1bW1hcnkobWNwKQpgYGAKCkluIGRlIG91dHB1dCBoaWVydmFuIHppZW4gd2UgZGUgdmVyc2NoaWxsZW5kZSBwYWFyc2dld2lqemUgdmVyZ2VsaWpraW5nZW4gZGllIHdlcmRlbiB1aXR2b2VyZC4gCkVsa2UgdmVyZ2VsaWpraW5nIG5vZW1lbiB3ZSBvb2sgZWVuIGNvbnRyYXN0LiAKQ29udHJhc3QgYDIgLSAxID09IDBgIGR1aWR0IGVyb3AgZGF0IHZvb3IgZGl0IGNvbnRyYXN0IHdvcmR0IGdldGVzdCBvZiBoZXQgdmVyc2NoaWwgaW4gZ2VtaWRkZWxkZSBsZW5ndGUgdm9vciBzb29ydCBgMmAgZW4gZGF0IHZvb3Igc29vcnQgYDFgIGdlbGlqayBpcyBhYW4gbnVsIHRlZ2VuIGhldCBhbHRlcm5hdGllZiBkYXQgYmVpZGUgZ2VtaWRkZWxkZXMgdmVyc2NoaWxsZW5kIHppam4uCkluIGRlIHR3ZWVkZSBrb2xvbSB3b3JkdCBoZXQgdmVyc2NoaWwgaW4gZ2VtaWRkZWxkZW4gd2VlcmdlZ2V2ZW4sIG1ldCBodW4gc3RhbmRhYXJkIGVycm9yIGVuIHRlc3RzdGF0aXN0aWVrIGluIGRlIHJlc3BlY3RpZXZlbGlqayBkZXJkZSBlbiB2aWVyZGUga29sb20uCkRlIGxhYXRzdGUga29sb20gZ2VlZnQgYWFuZ2VwYXN0ZSBwLXdhYXJkZW4gd2VlciBvcCBlZW4gZ2xvYmFhbCBzaWduaWZpY2FudGllbml2ZWF1IHZhbiA1JS4KQWFuIGRlIGhhbmQgdmFuIGRlIGFhbmdlcGFzdGUgcC13YWFyZGVuIHppZW4gd2UgZGF0IGRlIGdlbWlkZGVsZGUgbGVuZ3RlIHZhbiBzb29ydCA2ICh3aW50ZXJrb25pbmcpIHZlcnNjaGlsdCB2YW4gYWxsZSBhbmRlcmUgc29vcnRlbi4gCkRlIGVmZmVjdGdyb290dGUgaXMgdm9vciBhbGxlIHNvb3J0ZW4gbmVnYXRpZWYsIGhldGdlZW4gaW1wbGljZWVydCBkYXQgZGUgZ2VtaWRkZWxkZSBsZW5ndGUgdmFuIGtvZWtvZWtzZWllcmVuIGxhZ2VyIGlzIGluIG5lc3RlbiB2YW4gd2ludGVya29uaW5nIGluIHZlcmdlbGlqa2luZyBtZXQgYW5kZXJlIHNvb3J0ZW4uCgpWb29yIGRlIHJhcHBvcnRlcmluZyB6dWxsZW4gd2Ugb29rIGJldHJvdXdiYWFyaGVpZHNpbnRlcnZhbGxlbiB2b29yIGVsa2UgcGFhcnNnZXdpanplIHZlcmdlbGlqa2luZyBvcHZyYWdlbi4gV2Uga3VubmVuIGRlemUgb29rIG1ha2tlbGlqayBncmFmaXNjaCB2b29yc3RlbGxlbiBhYW4gZGUgaGFuZCB2YW4gZGUgYHBsb3RgIGZ1bmN0aWUgZGllIG9wIGVlbiBgZ2xodGAgb2JqZWN0IGthbiB0b2VnZXBhc3Qgd29yZGVuLgpEZSBiZXRyb3V3YmFhcmhlaWRzaW50ZXJ2YWxsZW4gd29yZGVuIG9wbmlldXcgZ2Vjb3JyaWdlZXJkIHZvb3IgbWVlcnZvdWRpZyB0ZXN0ZW4uIAoKYGBge3J9CmNvbmZpbnQobWNwKQpwbG90KG1jcCkKYGBgCgpNZW4ga2FuIGRlIGJla29tZW4gcmVzdWx0YXRlbiB2YW4gZGUgdGVzdCBvb2sgaW50ZXJwcmV0ZXJlbiBhLmQuaC52LiBydXdlIGRhdGE6IAoKYGBge3J9CmJveHBsb3QKYGBgCgpXYWFyIHdlIGV2ZW5lZW5zIGV2aWRlbnRpZSB6aWVuIGRhdCBkZSBlaWVyZW4gZ2VtaWRkZWxkIGtsZWluZXIgemlqbiB2b29yIG5lc3RlbiB2YW4gd2ludGVya29uaW5ramVzIGkudi5tLiBhbmRlcmUgc29vcnRlbi4gCgojIENvbmNsdXNpZQoKYGBge3J9CndpbnRlcklkIDwtIGdyZXAocm93bmFtZXMoY29uZmludChtY3ApJGNvbmZpbnQpLHBhdHRlcm49IjYiKQpgYGAKCkVyIGlzIGVlbiBleHRyZWVtIHNpZ25pZmljYW50IGVmZmVjdCB2YW4gZGUgcGxlZWdvdWRlcnNvb3J0IG9wIGRlIGdlbWlkZGVsZGUgbGVuZ3RlIHZhbiBrb2Vrb2Vrc2VpZXJlbiAob25lLXdheSBBTk9WQSB0ZXN0LCAkcDw8MC4wMDEkKS4KT3AgZWVuIGdsb2JhYWwgNSUgc2lnbmlmaWNhbnRpZW5pdmVhdSBpcyBkZSBnZW1pZGRlbGRlIGxlbmd0ZSB2YW4ga29la29la3NlaWVyZW4gaW4gbmVzdGVuIHZhbiB3aW50ZXJrb25pbmcga2xlaW5lciBkYW4gZGV6ZSBpbiBuZXN0ZW4gdmFuIGFsbGUgYW5kZXJlIGJlc3R1ZGVlcmRlIHNvb3J0ZW46IGdyYXNwaWVwZXIgKFR1a2V5IHRlc3QsIHZlcnNjaGlsPWByIGNvbmZpbnQobWNwKSRjb25maW50W3dpbnRlcklkWzFdLDFdICU+JSByb3VuZCgyKWAsIGFhbmdlcGFzdGUgcC13YWFyZGUgPSBgciBzdW1tYXJ5KG1jcCkkdGVzdCRwdmFsdWVzW3dpbnRlcklkWzFdXSAlPiUgcm91bmQoMylgLCA5NSUgQkk6IFtgciBjb25maW50KG1jcCkkY29uZmludFt3aW50ZXJJZFsxXSwtMV0gJT4lIHJvdW5kKDIpYF0pLCBib29tcGllcGVyIChUdWtleSB0ZXN0LCB2ZXJzY2hpbD1gciBjb25maW50KG1jcCkkY29uZmludFt3aW50ZXJJZFsyXSwxXSAlPiUgcm91bmQoMilgLCBhYW5nZXBhc3RlIHAtd2FhcmRlIDwgMC4wMDEsIDk1JSBCSTogW2ByIGNvbmZpbnQobWNwKSRjb25maW50W3dpbnRlcklkWzJdLC0xXSAlPiUgcm91bmQoMilgXSksIGhlZ2dlbm11cyAoVHVrZXkgdGVzdCwgdmVyc2NoaWw9YHIgY29uZmludChtY3ApJGNvbmZpbnRbd2ludGVySWRbM10sMV0gJT4lIHJvdW5kKDIpYCwgYWFuZ2VwYXN0ZSBwLXdhYXJkZSA8IDAuMDAxLCA5NSUgQkk6IFtgciBjb25maW50KG1jcCkkY29uZmludFt3aW50ZXJJZFszXSwtMV0gJT4lIHJvdW5kKDIpYF0pLCByb29kYm9yc3RqZSAoVHVrZXkgdGVzdCwgIHZlcnNjaGlsPWByIGNvbmZpbnQobWNwKSRjb25maW50W3dpbnRlcklkWzRdLDFdICU+JSByb3VuZCgyKWAsIGFhbmdlcGFzdGUgcC13YWFyZGUgPSBgciBzdW1tYXJ5KG1jcCkkdGVzdCRwdmFsdWVzW3dpbnRlcklkWzRdXSAlPiUgcm91bmQoMylgLCA5NSUgQkk6IFtgciBjb25maW50KG1jcCkkY29uZmludFt3aW50ZXJJZFs0XSwtMV0gJT4lIHJvdW5kKDIpYF0pIGVuIHdpdHRlIGt3aWtzdGFhcnQgKFR1a2V5IHRlc3QsICB2ZXJzY2hpbD1gciBjb25maW50KG1jcCkkY29uZmludFt3aW50ZXJJZFs1XSwxXSAlPiUgcm91bmQoMilgLCBhYW5nZXBhc3RlIHAtd2FhcmRlIDwgMC4wMDEsIDk1JSBCSTogW2ByIGNvbmZpbnQobWNwKSRjb25maW50W3dpbnRlcklkWzVdLC0xXSAlPiUgcm91bmQoMilgXSkuCgpEZSB2ZXJzY2hpbGxlbiBpbiBnZW1pZGRlbGRlIGxlbmd0ZSB2YW4gZGUga29la29la3NlaWVyZW4gdHVzc2VuIGRlIG92ZXJpZ2Ugc29vcnRlbiB6aWpuIG5pZXQgc2lnbmlmaWNhbnQuCg==