Case study: Lengte van mannen en vrouwen - Variabiliteit van steekproef tot steekproef
Om te begrijpen dat een steekproef random is zouden we hetzelfde experiment veel keer moeten kunnen herhalen (repeated sampling
).
Dan zouden we inzicht kunnen krijgen hoe de gegevens veranderen van steekproef tot steekproef.
Om dit te illustreren zullen we gebruik maken van een hele grote studie.
Uit die studie zullen we dan herhaaldelijk kleine steekproeven trekken om te begrijpen hoe de gegevens en statistieken veranderen van steekproef tot steekproef. Of om met andere woorden na te gaan wat de variabiliteit is tussen steekproeven.
National Health And Nutrition Examination Study (NHANES)
- Sinds 1960 worden elk jaar mensen van alle leeftijden geïnterviewd bij hen thuis.
- Er maakt ook een gezondheidsonderzoek deel uit van de study die in een mobiel onderzoekscentrum wordt afgenomen.
- We zullen deze grote studie gebruiken om at random personen te selecteren van de Amerikaanse populatie.
- Dat zal inzicht geven in hoe de gegevens en resultaten van een analyse zullen variëren van steekproef tot steekproef.
- De data van deze studie is terug te vinden in het R pakket
NHANES
library(NHANES)
head(NHANES)
# A tibble: 6 x 76
ID SurveyYr Gender Age AgeDecade AgeMonths Race1 Race3 Education
<int> <fct> <fct> <int> <fct> <int> <fct> <fct> <fct>
1 51624 2009_10 male 34 " 30-39" 409 White <NA> High Sch…
2 51624 2009_10 male 34 " 30-39" 409 White <NA> High Sch…
3 51624 2009_10 male 34 " 30-39" 409 White <NA> High Sch…
4 51625 2009_10 male 4 " 0-9" 49 Other <NA> <NA>
5 51630 2009_10 female 49 " 40-49" 596 White <NA> Some Col…
6 51638 2009_10 male 9 " 0-9" 115 White <NA> <NA>
# … with 67 more variables: MaritalStatus <fct>, HHIncome <fct>,
# HHIncomeMid <int>, Poverty <dbl>, HomeRooms <int>, HomeOwn <fct>,
# Work <fct>, Weight <dbl>, Length <dbl>, HeadCirc <dbl>, Height <dbl>,
# BMI <dbl>, BMICatUnder20yrs <fct>, BMI_WHO <fct>, Pulse <int>,
# BPSysAve <int>, BPDiaAve <int>, BPSys1 <int>, BPDia1 <int>,
# BPSys2 <int>, BPDia2 <int>, BPSys3 <int>, BPDia3 <int>,
# Testosterone <dbl>, DirectChol <dbl>, TotChol <dbl>, UrineVol1 <int>,
# UrineFlow1 <dbl>, UrineVol2 <int>, UrineFlow2 <dbl>, Diabetes <fct>,
# DiabetesAge <int>, HealthGen <fct>, DaysPhysHlthBad <int>,
# DaysMentHlthBad <int>, LittleInterest <fct>, Depressed <fct>,
# nPregnancies <int>, nBabies <int>, Age1stBaby <int>,
# SleepHrsNight <int>, SleepTrouble <fct>, PhysActive <fct>,
# PhysActiveDays <int>, TVHrsDay <fct>, CompHrsDay <fct>,
# TVHrsDayChild <int>, CompHrsDayChild <int>, Alcohol12PlusYr <fct>,
# AlcoholDay <int>, AlcoholYear <int>, SmokeNow <fct>, Smoke100 <fct>,
# Smoke100n <fct>, SmokeAge <int>, Marijuana <fct>, AgeFirstMarij <int>,
# RegularMarij <fct>, AgeRegMarij <int>, HardDrugs <fct>, SexEver <fct>,
# SexAge <int>, SexNumPartnLife <int>, SexNumPartYear <int>,
# SameSex <fct>, SexOrientation <fct>, PregnantNow <fct>
Observations: 10,000
Variables: 76
$ ID <int> 51624, 51624, 51624, 51625, 51630, 51638, 51646…
$ SurveyYr <fct> 2009_10, 2009_10, 2009_10, 2009_10, 2009_10, 20…
$ Gender <fct> male, male, male, male, female, male, male, fem…
$ Age <int> 34, 34, 34, 4, 49, 9, 8, 45, 45, 45, 66, 58, 54…
$ AgeDecade <fct> 30-39, 30-39, 30-39, 0-9, 40-49, 0-9, 0-…
$ AgeMonths <int> 409, 409, 409, 49, 596, 115, 101, 541, 541, 541…
$ Race1 <fct> White, White, White, Other, White, White, White…
$ Race3 <fct> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
$ Education <fct> High School, High School, High School, NA, Some…
$ MaritalStatus <fct> Married, Married, Married, NA, LivePartner, NA,…
$ HHIncome <fct> 25000-34999, 25000-34999, 25000-34999, 20000-24…
$ HHIncomeMid <int> 30000, 30000, 30000, 22500, 40000, 87500, 60000…
$ Poverty <dbl> 1.36, 1.36, 1.36, 1.07, 1.91, 1.84, 2.33, 5.00,…
$ HomeRooms <int> 6, 6, 6, 9, 5, 6, 7, 6, 6, 6, 5, 10, 6, 10, 10,…
$ HomeOwn <fct> Own, Own, Own, Own, Rent, Rent, Own, Own, Own, …
$ Work <fct> NotWorking, NotWorking, NotWorking, NA, NotWork…
$ Weight <dbl> 87.4, 87.4, 87.4, 17.0, 86.7, 29.8, 35.2, 75.7,…
$ Length <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
$ HeadCirc <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
$ Height <dbl> 164.7, 164.7, 164.7, 105.4, 168.4, 133.1, 130.6…
$ BMI <dbl> 32.22, 32.22, 32.22, 15.30, 30.57, 16.82, 20.64…
$ BMICatUnder20yrs <fct> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
$ BMI_WHO <fct> 30.0_plus, 30.0_plus, 30.0_plus, 12.0_18.5, 30.…
$ Pulse <int> 70, 70, 70, NA, 86, 82, 72, 62, 62, 62, 60, 62,…
$ BPSysAve <int> 113, 113, 113, NA, 112, 86, 107, 118, 118, 118,…
$ BPDiaAve <int> 85, 85, 85, NA, 75, 47, 37, 64, 64, 64, 63, 74,…
$ BPSys1 <int> 114, 114, 114, NA, 118, 84, 114, 106, 106, 106,…
$ BPDia1 <int> 88, 88, 88, NA, 82, 50, 46, 62, 62, 62, 64, 76,…
$ BPSys2 <int> 114, 114, 114, NA, 108, 84, 108, 118, 118, 118,…
$ BPDia2 <int> 88, 88, 88, NA, 74, 50, 36, 68, 68, 68, 62, 72,…
$ BPSys3 <int> 112, 112, 112, NA, 116, 88, 106, 118, 118, 118,…
$ BPDia3 <int> 82, 82, 82, NA, 76, 44, 38, 60, 60, 60, 64, 76,…
$ Testosterone <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
$ DirectChol <dbl> 1.29, 1.29, 1.29, NA, 1.16, 1.34, 1.55, 2.12, 2…
$ TotChol <dbl> 3.49, 3.49, 3.49, NA, 6.70, 4.86, 4.09, 5.82, 5…
$ UrineVol1 <int> 352, 352, 352, NA, 77, 123, 238, 106, 106, 106,…
$ UrineFlow1 <dbl> NA, NA, NA, NA, 0.094, 1.538, 1.322, 1.116, 1.1…
$ UrineVol2 <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
$ UrineFlow2 <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
$ Diabetes <fct> No, No, No, No, No, No, No, No, No, No, No, No,…
$ DiabetesAge <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
$ HealthGen <fct> Good, Good, Good, NA, Good, NA, NA, Vgood, Vgoo…
$ DaysPhysHlthBad <int> 0, 0, 0, NA, 0, NA, NA, 0, 0, 0, 10, 0, 4, NA, …
$ DaysMentHlthBad <int> 15, 15, 15, NA, 10, NA, NA, 3, 3, 3, 0, 0, 0, N…
$ LittleInterest <fct> Most, Most, Most, NA, Several, NA, NA, None, No…
$ Depressed <fct> Several, Several, Several, NA, Several, NA, NA,…
$ nPregnancies <int> NA, NA, NA, NA, 2, NA, NA, 1, 1, 1, NA, NA, NA,…
$ nBabies <int> NA, NA, NA, NA, 2, NA, NA, NA, NA, NA, NA, NA, …
$ Age1stBaby <int> NA, NA, NA, NA, 27, NA, NA, NA, NA, NA, NA, NA,…
$ SleepHrsNight <int> 4, 4, 4, NA, 8, NA, NA, 8, 8, 8, 7, 5, 4, NA, 5…
$ SleepTrouble <fct> Yes, Yes, Yes, NA, Yes, NA, NA, No, No, No, No,…
$ PhysActive <fct> No, No, No, NA, No, NA, NA, Yes, Yes, Yes, Yes,…
$ PhysActiveDays <int> NA, NA, NA, NA, NA, NA, NA, 5, 5, 5, 7, 5, 1, N…
$ TVHrsDay <fct> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
$ CompHrsDay <fct> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
$ TVHrsDayChild <int> NA, NA, NA, 4, NA, 5, 1, NA, NA, NA, NA, NA, NA…
$ CompHrsDayChild <int> NA, NA, NA, 1, NA, 0, 6, NA, NA, NA, NA, NA, NA…
$ Alcohol12PlusYr <fct> Yes, Yes, Yes, NA, Yes, NA, NA, Yes, Yes, Yes, …
$ AlcoholDay <int> NA, NA, NA, NA, 2, NA, NA, 3, 3, 3, 1, 2, 6, NA…
$ AlcoholYear <int> 0, 0, 0, NA, 20, NA, NA, 52, 52, 52, 100, 104, …
$ SmokeNow <fct> No, No, No, NA, Yes, NA, NA, NA, NA, NA, No, NA…
$ Smoke100 <fct> Yes, Yes, Yes, NA, Yes, NA, NA, No, No, No, Yes…
$ Smoke100n <fct> Smoker, Smoker, Smoker, NA, Smoker, NA, NA, Non…
$ SmokeAge <int> 18, 18, 18, NA, 38, NA, NA, NA, NA, NA, 13, NA,…
$ Marijuana <fct> Yes, Yes, Yes, NA, Yes, NA, NA, Yes, Yes, Yes, …
$ AgeFirstMarij <int> 17, 17, 17, NA, 18, NA, NA, 13, 13, 13, NA, 19,…
$ RegularMarij <fct> No, No, No, NA, No, NA, NA, No, No, No, NA, Yes…
$ AgeRegMarij <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 20,…
$ HardDrugs <fct> Yes, Yes, Yes, NA, Yes, NA, NA, No, No, No, No,…
$ SexEver <fct> Yes, Yes, Yes, NA, Yes, NA, NA, Yes, Yes, Yes, …
$ SexAge <int> 16, 16, 16, NA, 12, NA, NA, 13, 13, 13, 17, 22,…
$ SexNumPartnLife <int> 8, 8, 8, NA, 10, NA, NA, 20, 20, 20, 15, 7, 100…
$ SexNumPartYear <int> 1, 1, 1, NA, 1, NA, NA, 0, 0, 0, NA, 1, 1, NA, …
$ SameSex <fct> No, No, No, NA, Yes, NA, NA, Yes, Yes, Yes, No,…
$ SexOrientation <fct> Heterosexual, Heterosexual, Heterosexual, NA, H…
$ PregnantNow <fct> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,…
Data exploratie
Onderzoeksvraag: hoe verschilt de lengte van volwassen mannen en vrouwen.
- We pipen de dataset naar de function
filter
om de data te filteren volgens leeftijd.
- We plotten de lengte metingen.
- We selecteren de data data met het commando
ggplot(aes(x=lengte))
- We voegen een histogram toe met het commando
geom_histogram()
- We maken twee vertikale panels met het commando
facet_grid(Gender~.)
- We veranderen het label van de x-as met de
xlab
functie.
NHANES%>%
filter(Age >= 18 & !is.na(Height)) %>%
ggplot(aes(x = Height))+
geom_histogram() +
facet_grid(Gender ~ .) +
xlab("Lengte (cm)")
We zien dat de data nu min of meer symmetrisch verdeeld zijn en een klokvorm hebben.
Dat zal ons toe laten om de data verder samen te vatten door gebruik te maken van twee statistieken: het gemiddelde en de standaard deviatie wat een maat is voor de spreiding van de gegevens rond het gemiddelde.
We maken nu een subset van de data die we zullen gebruiken om aan te tonen hoe de variabiliteit in kleine steekproeven kan variëren van steekproef tot steekproef.
- We filteren op leeftijd en verwijderen ontbrekenden gegevens (NA, Not Available).
- We selecteren enkel het geslacht en Lengte zodat de dataset geen onnodige variabelen bevat.
nhanesSub <- NHANES %>%
filter(Age >= 18 & !is.na(Height)) %>%
select(c("Gender","Height"))
We berekenen het gemiddelde en de standaard deviatie voor de lengte voor mannen en vrouwen in de grote dataset. We groeperen de data hiervoor op basis van het geslacht (variable Gender).
HeightSum <- nhanesSub %>%
group_by(Gender) %>%
summarize_at("Height",
list(mean = mean,
sd = sd)
)
knitr::kable(
HeightSum %>%
mutate_if(is.numeric, round, digits=1)
)
female |
162.1 |
7.3 |
male |
175.9 |
7.5 |
Experiment
Stel dat we geen toegang hebben tot de metingen van de NHANES studie.
We zouden dan een experiment op moeten zetten om metingen bij mannen en vrouwen te doen.
Veronderstel dat we budget hebben om metingen bij 5 mannen en 5 vrouwen te doen.
We zouden dan 5 mannen en 5 vrouwen boven de 18 jaar at random selecteren uit de Amerikaanse populatie.
We kunnen dit experiment simuleren door 5 vrouwen en 5 mannen at random te selecteren uit de NHANES studie.
set.seed(1023)
nSamp <- 5
fem <- nhanesSub %>%
filter(Gender=="female") %>%
sample_n(size=5)
mal <- nhanesSub %>%
filter(Gender=="male") %>%
sample_n(size=5)
samp1 <- rbind(fem,mal)
samp1
# A tibble: 10 x 2
Gender Height
<fct> <dbl>
1 female 164
2 female 160.
3 female 159
4 female 154.
5 female 156.
6 male 170.
7 male 183.
8 male 183.
9 male 185.
10 male 170.
Data Exploratie
samp1 %>%
ggplot(aes(x=Height)) +
geom_histogram() +
facet_grid(Gender~.) +
xlab("Lengte (cm)")
HeightSumExp1 <- samp1 %>%
group_by(Gender) %>%
summarize_at("Height",
list(mean = mean,
sd = sd)
)
HeightSumExp1
# A tibble: 2 x 3
Gender mean sd
<fct> <dbl> <dbl>
1 female 159. 3.76
2 male 178. 7.55
Histogram is niet zinvol als we maar zo weinig datapunten hebben.
Boxplot is beter:
We voeren hier ook een t-test uit.
t.test(Height~Gender,data=samp1)
Welch Two Sample t-test
data: Height by Gender
t = -5.0783, df = 5.8695, p-value = 0.00242
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
-28.441927 -9.878073
sample estimates:
mean in group female mean in group male
158.72 177.88
In het experiment zijn vrouwen gemiddeld 19.16 cm kleiner dan mannen. En als we een statistische test uitvoeren (zie hoofdstuk 5: Statistische besluitvorming) kunnen we besluiten dat dit verschil statistisch significant is.
Herhaal het experiment
Als we het experiment herhalen selecteren we andere mensen en verkrijgen we andere resultaten.
set.seed(1024)
fem <- nhanesSub %>%
filter(Gender=="female") %>%
sample_n(size=5)
mal <- nhanesSub %>%
filter(Gender=="male") %>%
sample_n(size=5)
samp2 <- rbind(fem,mal)
HeightSumExp2 <- samp2 %>%
group_by(Gender) %>%
summarize_at("Height",
list(mean=mean,
sd=sd)
)
HeightSumExp2
# A tibble: 2 x 3
Gender mean sd
<fct> <dbl> <dbl>
1 female 166. 9.89
2 male 170. 8.24
samp2 %>%
ggplot(aes(x = Gender,y = Height)) +
geom_boxplot(outlier.shape = NA) +
geom_point(position = "jitter") +
geom_point(
aes(x = 1, y = HeightSumExp2$mean[1]),
size = 3,
pch = 17,
color="darkred") +
geom_point(
aes(x = 2, y = HeightSumExp2$mean[2]),
size = 3,
pch = 17,
color = "darkred") +
ylab("Height (cm)")
t.test(Height ~ Gender, data=samp2)
Welch Two Sample t-test
data: Height by Gender
t = -0.7295, df = 7.747, p-value = 0.4872
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
-17.552343 9.152343
sample estimates:
mean in group female mean in group male
166.26 170.46
In de nieuwe steekproef zijn vrouwen gemiddeld 4.2 cm kleiner dan mannen. En dit verschil is statistisch niet significant
Herhaal het experiment opnieuw
seed <- 88605
set.seed(seed)
fem <- nhanesSub %>%
filter(Gender=="female") %>%
sample_n(size=5)
mal <- nhanesSub %>%
filter(Gender=="male") %>%
sample_n(size=5)
samp3 <- rbind(fem,mal)
HeightSumExp3 <- samp3 %>%
group_by(Gender) %>%
summarize_at("Height",
list(mean=mean,
sd=sd)
)
HeightSumExp3
# A tibble: 2 x 3
Gender mean sd
<fct> <dbl> <dbl>
1 female 173. 1.97
2 male 168. 2.84
samp3 %>%
ggplot(aes(x = Gender,y = Height)) +
geom_boxplot(outlier.shape = NA) +
geom_point(position = "jitter") +
geom_point(
aes(x = 1, y = HeightSumExp3$mean[1]),
size = 3,
pch = 17,
color="darkred") +
geom_point(
aes(x = 2, y = HeightSumExp3$mean[2]),
size = 3,
pch = 17,
color = "darkred") +
ylab("Height (cm)")
t.test(Height ~ Gender, data=samp3)
Welch Two Sample t-test
data: Height by Gender
t = 3.1182, df = 7.136, p-value = 0.01648
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
1.178916 8.461084
sample estimates:
mean in group female mean in group male
172.60 167.78
In de nieuwe steekproef zijn vrouwen gemiddeld 4.82 cm groter dan mannen. En dit verschil is statistisch significant
Samenvatting
We trokken at random andere proefpersonen in elke steekproef
Hierdoor verschillen lengtemetingen van steekproef tot steekproef.
Dus ook de geschatte gemiddeldes en standaard deviaties.
Bijgevolg zijn onze conclusies ook onzeker en kunnen deze wijzigen van steekproef tot steekproef.
Voor het lengte voorbeeld zijn steekproeven waarbij het effect tegengesteld is aan dat in de populatie en waarbij we besluiten dat het verschil significant echter zeldzaam.
\(\rightarrow\) Met statistiek controleren we de kans op het trekken foute conclusies.
Controle van fouten
Hoe controleert statistiek de kans op het trekken van foute conclusies?
- In onderstaande code trekken we 10000 herhaalde steekproeven van 5 vrouwen en 5 mannen uit de NHANES studie.
set.seed(15152)
# Aantal simulaties en steekproefgrootte per groep
nSim <- 10000
nSamp <- 5
# We filteren de data vooraf zodat we dit niet telkens opnieuw hoeven te doen
fem <- nhanesSub %>%
filter(Gender == "female")
mal <- nhanesSub %>%
filter(Gender == "male")
# Simulatie studie
# Om snelle functies te kunnen gebruiken nemen we eerst nSim steekproeven en berekenen we daarna alles.
femSamps <- malSamps <-matrix(NA, nrow=nSamp, ncol=nSim)
for (i in 1:nSim)
{
femSamps[,i] <- sample(fem$Height, nSamp)
malSamps[,i] <- sample(mal$Height, nSamp)
}
res <- data.frame(
verschil=colMeans(femSamps) - colMeans(malSamps),
Rfast::ttests(femSamps, malSamps)
)
sum(res$pvalue < 0.05 & res$verschil < 0)
[1] 7234
[1] 2766
sum(res$pvalue < 0.05 & res$verschil>0)
[1] 0
res %>%
ggplot(aes(x=verschil,y=-log10(pvalue),color=pvalue < 0.05)) +
geom_point() +
xlab("Gemiddeld Verschil (cm)") +
ylab("Statistische Significantie (-log10 p)")
res %>%
ggplot(aes(y = verschil)) +
geom_boxplot() +
ylab("Gemiddeld Verschil (cm)")
$x
[1] ""
attr(,"class")
[1] "labels"
Op basis van 10000 steekproeven van 5 mannen en 5 vrouwen zagen we dat in 7234 steekproeven vrouwen gemiddeld significant kleiner zijn dan mannen. In 2766 steekproeven besluiten we dat vrouwen en mannen gemiddeld niet significant verschillen in lengte. En in 0 besluiten we dat vrouwen gemiddeld significant groter zijn dan mannen.
- De steekproef die we toonden waaruit we zouden besluiten dat vrouwen significant groter zijn dan mannen is heel onwaarschijnlijk. Er moesten 88605 steekproeven worden getrokken om deze extreme steekproef te vinden.
Het feit dat we in veel steekproeven resultaten vinden die statistisch niet significant zijn komt omdat de statistische toets een te lage kracht heeft om het verschil te detecteren wanneer er maar 5 observaties zijn per groep.
Grotere steekproef?
Wat gebeurt er als we de steekproef verhogen naar 50 observaties per groep?
set.seed(11145)
# Aantal simulaties en steekproefgrootte per groep
nSim <- 10000
nSamp <- 50
# We filteren de data vooraf zodat we dit niet telkens opnieuw hoeven te doen
fem <- nhanesSub %>%
filter(Gender == "female")
mal <- nhanesSub %>%
filter(Gender == "male")
# Simulatie studie
# Om snelle functies te kunnen gebruiken nemen we eerst nSim steekproeven en berekenen we daarna alles.
femSamps <- malSamps <- matrix(NA, nrow = nSamp, ncol = nSim)
for (i in 1:nSim)
{
femSamps[,i] <- sample(fem$Height, nSamp)
malSamps[,i] <- sample(mal$Height, nSamp)
}
res <- data.frame(
verschil = colMeans(femSamps) - colMeans(malSamps),
Rfast::ttests(femSamps, malSamps)
)
sum(res$pvalue < 0.05 & res$verschil < 0)
[1] 10000
[1] 0
sum(res$pvalue < 0.05 & res$verschil > 0)
[1] 0
res %>%
ggplot(aes(x=verschil,y=-log10(pvalue),color=pvalue<0.05)) +
geom_point() +
xlab("Gemiddeld Verschil (cm)") +
ylab("Statistische Significantie (-log10 p)")
res %>%
ggplot(aes(y=verschil)) +
geom_boxplot() +
ylab("Gemiddeld Verschil (cm)")
$x
[1] ""
attr(,"class")
[1] "labels"
We zien dus dat we de kans om een verschil te vinden als er in werkelijkheid een verschil is in de populatie kunnen beïnvloeden in de design fase: aan de hand van de steekproefgrootte.
Hoe meer gegevens hoe makkelijker we het werkelijk verschil oppikken in de steekproef.
Controle van vals positieven
Wat gebeurt er als er geen verschil is tussen beide groepen?
We moeten hiervoor experimenten simuleren waarbij de groepen gelijk zijn.
Hiervoor zullen we twee groepen vergelijken waarvoor de lengte gemiddeld niet verschillend is.
Dat kunnen we doen door een steekproef te trekken waarbij we voor beide groepen at random subjecten trekken uit de subset van vrouwen in de NHANES studie.
We doen dit opnieuw voor een steekproef met 5 subjecten per groep
set.seed(13245)
# Aantal simulaties en steekproefgrootte per groep
nSim <- 10000
nSamp <- 5
# We filteren de data vooraf zodat we dit niet telkens opnieuw hoeven te doen
fem <- nhanesSub %>%
filter(Gender == "female")
# Simulatie studie
# Om snelle functies te kunnen gebruiken nemen we eerst nSim steekproeven en berekenen we daarna alles.
femSamps <- femSamps2 <-matrix(NA, nrow=nSamp, ncol=nSim)
for (i in 1:nSim)
{
femSamps[,i] <- sample(fem$Height, nSamp)
femSamps2[,i] <- sample(fem$Height, nSamp)
}
res <- data.frame(
verschil=colMeans(femSamps) - colMeans(femSamps2),
Rfast::ttests(femSamps, femSamps2)
)
sum(res$pvalue < 0.05 & res$verschil < 0)
[1] 213
[1] 9558
sum(res$pvalue < 0.05 & res$verschil>0)
[1] 229
res %>%
ggplot(aes(x=verschil,y=-log10(pvalue),color=pvalue < 0.05)) +
geom_point() +
xlab("Gemiddeld Verschil (cm)") +
ylab("Statistische Significantie (-log10 p)")
res %>%
ggplot(aes(y = verschil)) +
geom_boxplot() +
ylab("Gemiddeld Verschil (cm)")
$x
[1] ""
attr(,"class")
[1] "labels"
Op basis van 10000 steekproeven zien we dat we in 442 steekproeven ten onrechte besluiten dat er een verschil is in gemiddelde lengte tussen twee groepen vrouwen.
Met de statistische analyse controleren we dus het aantal vals positieve resultaten correct op 5%.
Wat gebeurt er als we het aantal observaties verhogen?
We simuleren opnieuw experimenten met 50 subjecten per groep maar we trekken de subjecten opnieuw telkens uit de populatie van vrouwen.
set.seed(1345)
# Aantal simulaties en steekproefgrootte per groep
nSim <- 10000
nSamp <- 50
# We filteren de data vooraf zodat we dit niet telkens opnieuw hoeven te doen
fem <- nhanesSub %>%
filter(Gender == "female")
# Simulatie studie
# Om snelle functies te kunnen gebruiken nemen we eerst nSim steekproeven en berekenen we daarna alles.
femSamps <- femSamps2 <-matrix(NA, nrow=nSamp, ncol=nSim)
for (i in 1:nSim)
{
femSamps[,i] <- sample(fem$Height, nSamp)
femSamps2[,i] <- sample(fem$Height, nSamp)
}
res <- data.frame(
verschil=colMeans(femSamps) - colMeans(femSamps2),
Rfast::ttests(femSamps, femSamps2)
)
sum(res$pvalue < 0.05 & res$verschil < 0)
[1] 271
[1] 9501
sum(res$pvalue < 0.05 & res$verschil>0)
[1] 228
res %>%
ggplot(aes(x=verschil,y=-log10(pvalue),color=pvalue < 0.05)) +
geom_point() +
xlab("Gemiddeld Verschil (cm)") +
ylab("Statistische Significantie (-log10 p)")
res %>%
ggplot(aes(y = verschil)) +
geom_boxplot() +
ylab("Gemiddeld Verschil (cm)")
$x
[1] ""
attr(,"class")
[1] "labels"
Op basis van 10000 steekproeven zien we dat we in 499 steekproeven ten onrechte besluiten dat er een verschil is in gemiddelde lengte tussen twee groepen vrouwen.
Met de statistische analyse controleren we dus ook bij het nemen van een grote steekproef het aantal vals positieve resultaten correct op 5% (Vals positief: Op basis van de steekproef besluiten dat er gemiddeld een verschil is in lengte tussen beide groepen terwijl er in werkelijkheid geen verschil is in de populatie.)
Conclusies
De statistische analyse controleert steeds de kans op het nemen van een vals positieve conclusie.
De statistische analysis controleert de kans op het nemen van een vals negatieve conclusies niet, maar in de design fase kunnen we deze kans beïnvloeden ondermeer d.m.v. de steekproefgrootte.
#Case study: Salk vaccin
- In 1916, brak de eerste grote polio epidemie uit in de USA.
- Begin de jaren 50 ontwikkelde John Salk een vaccin met belovende resultaten in het lab.
- In 1954, heeft de National Foundation for Infantile Paralysis (NFIP) een grote studie opgezet om de effectiviteit van het Salk vaccin na te gaan.
- Veronderstel dat de NFIP in 1954 een groot aantal kinderen zou hebben gevaccineerd, wat zouden ze dan kunnen besluiten als de polio incidentie in 1954 lager was dan in 1953?
NFIP Study
Design
- Grote simultane studie met gevaccineerde kinderen (cases) en ongevaccineerde kinderen (controles).
- In scholen van districten met hoge polio incidentie.
- Cases: kinderen van de tweede graad van het lager onderwijs waarvan de ouders toestemden met vaccinatie.
- Controles: kinderen van de eerste en derde graad.
Data
nfip <- tibble(
group=c("cases","controls","noConcent"),
grade=c("g2","g1g3","g2"),
vaccin=c("yes","no","no"),
total=c(221998,725173,123605),
polio=c(54,391,56)
) %>%
mutate(noPolio = total - polio)
knitr::kable(nfip)
cases |
g2 |
yes |
221998 |
54 |
221944 |
controls |
g1g3 |
no |
725173 |
391 |
724782 |
noConcent |
g2 |
no |
123605 |
56 |
123549 |
Vergelijk de polio incidentie?
nfip <- nfip %>%
mutate(incidencePM = round(nfip$polio/nfip$total*1e6,0))
knitr::kable(nfip)
cases |
g2 |
yes |
221998 |
54 |
221944 |
243 |
controls |
g1g3 |
no |
725173 |
391 |
724782 |
539 |
noConcent |
g2 |
no |
123605 |
56 |
123549 |
453 |
Wat kunnen we concluderen?
Confounding
We observeren een lagere polio (P) incidentie voor kinderen bij wie de ouders geen toestemming gaven dan in de controle groep.
Toestemming voor vaccinatie (V) is geassocieerd met de socio-economische status (S).
Kinderen van lagere socio-economische status zijn meer resistent tegen de ziekte.
De groepen van cases en controles zijn niet vergelijkbaar
- verschil in leeftijd
- verschil in socio-economische status en
- verschil in vatbaarheid voor de ziekte.
Salk Study
Design
Een nieuwe studie werd uitgevoerd: dubbel blinde gerandomiseerde studie.
- Kinderen worden at random toegewezen aan controle of case arm van het experiment nadat de ouders toestemden met vaccinatie.
- Controle: vaccinatie met placebo
- Treatment: vaccinatie met vaccin
- Double blinding:
- ouders en kinderen weten niet of ze werden gevaccineerd of niet
- medische staf en onderzoekers weten niet of het kind het vaccin of de placebo kreeg
Data
salk <- data.frame(
group=c("cases","control","noConcent"),
treatment=c("vaccine","placebo","none"),
total=c(200745,201229, 338778),polio=c(57,142,157)
) %>%
mutate(
noPolio = total-polio,
incidencePM = round(polio/total*1e6,0)
)
knitr::kable(salk)
cases |
vaccine |
200745 |
57 |
200688 |
284 |
control |
placebo |
201229 |
142 |
201087 |
706 |
noConcent |
none |
338778 |
157 |
338621 |
463 |
We observeren een veel groter effect nu dat cases en controles vergelijkbaar zijn, incidentie van respectievelijk 284 and 706 per miljoen.
De polio incidentie voor kinderen die geen toestemming geven blijft vergelijkbaar 453 and 463 per miljoen respectievelijk in the NFIP and Salk study.
LS0tCnRpdGxlOiAiMS4gSW5sZWlkaW5nOiBXYWFyb20gU3RhdGlzdGllaz8iCmF1dGhvcjogIkxpZXZlbiBDbGVtZW50IgpkYXRlOiAic3RhdE9taWNzLCBHaGVudCBVbml2ZXJzaXR5IChodHRwczovL3N0YXRvbWljcy5naXRodWIuaW8pIgpvdXRwdXQ6CiAgICBodG1sX2RvY3VtZW50OgogICAgICBjb2RlX2Rvd25sb2FkOiB0cnVlICAgIAogICAgICB0aGVtZTogY29zbW8KICAgICAgdG9jOiB0cnVlCiAgICAgIHRvY19mbG9hdDogdHJ1ZQogICAgICBoaWdobGlnaHQ6IHRhbmdvCiAgICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQotLS0KCiMgSW50cm9kdWN0aWUKCmBgYHtyIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChpbmNsdWRlID0gVFJVRSwgY29tbWVudCA9IE5BLCBlY2hvID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKYGBgCgotIFdlIGxldmVuIGluIGhldCBiaWcgZGF0YSBlcmEKLSBHZWdldmVucyBvdmVyIGxvY2F0aWUsIHN1cmZnZWRyYWcsIGFhbmtvb3BnZWRyYWcsIHNvY2lhbGUgbWVkaWEKLSBXZXRlbnNjaGFwOiBleHByZXNzaWUgbWV0ZW4gdmFuIGR1aXplbmRlbiBnZW5lbiwgZWl3aXR0ZW4sLi4uIHZvb3IgZWxrIHN1YmplY3QKLSBDaGVtaXNjaGUgcHJvY2VzIGNvbnRyb2xlOiBncm9vdCBhYW50YWwgc2Vuc29yZW4gZGllIGNvbnRpbnUgZWVuIHByb2NlcyBtZXRlbiB6b2RhdCBoZXQgcHJvY2VzIGthbiB3b3JkZW4gYmlqZ2VzdHV1cmQKLSBEYXRhIGRyaXZlbiBqb3VybmFsaXNtCi0gLi4uCgpTdGF0aXN0aWVrIGlzIGRlIHdldGVuc2NoYXAgb20gdGUgbGVyZW4gdWl0IGVtcGlyaXNjaGUgZ2VnZXZlbnMKClN0YXRpc3Rpc2NoZSBnZWxldHRlcmRoZWlkIGlzIGNydWNpYWFsIG9tIHJlc3VsdGF0ZW4gZW4gcHVibGljYXRpZXMga3JpdGlzY2ggdGUga3VubmVuIGludGVycHJldGVyZW4uCgojIyBCb3V0YWRlOiBNZXQgc3RhdGlzdGllayBrYW4gamUgYWxsZXMgYmV3aWp6ZW4KCi0tLQoKIyMgTWV0IGZvdXRlIHN0YXRpc3RpZWsga2FuIGplIGFsbGVzIGJld2lqemVuCgotLS0KCmh0dHBzOi8vd3d3Lm1lZHJ4aXYub3JnL2NvbnRlbnQvMTAuMTEwMS8yMDIwLjA3LjE3LjIwMTU1ODQ2djEKCiFbXShodHRwczovL2dpdGh1Yi5jb20vc3RhdE9taWNzL3NiYzIwL3Jhdy9tYXN0ZXIvZmlndXJlcy9Gb25zZWNhMjAyMENvdmlkVmVnZXRhYmxlcy5wbmcpCgotLS0KCiFbXShodHRwczovL2dpdGh1Yi5jb20vc3RhdE9taWNzL3NiYzIwL3Jhdy9tYXN0ZXIvZmlndXJlcy9jb3ZpZFZlZ2V0YWJsZXM2LnBuZyl7d2lkdGg9NzAlfQoKTm9nIG5pZXQgZ2VwdWJsaWNlZXJkIG1hYXIgaW50dXNzZW4gb29rIGdlY2l0ZWVyZCBpbiA0IGdlcHVibGljZWVyZGUgd2V0ZW5zY2hhcHBlbGlqa2UgYXJ0aWtlbHMKCi0tLQoKIVtdKGh0dHBzOi8vZ2l0aHViLmNvbS9zdGF0T21pY3Mvc2JjMjAvcmF3L21hc3Rlci9maWd1cmVzL2NvdmlkVmVnZXRhYmxlcy5wbmcpe3dpZHRoPTcwJX0KCiJUaGUgYXV0aG9ycyBzdGF0ZTogVGhlIG5lZ2F0aXZlIGVjb2xvZ2ljYWwgYXNzb2NpYXRpb24gYmV0d2VlbiBDT1ZJRC0xOSBtb3J0YWxpdHkgYW5kIHRoZSBjb25zdW1wdGlvbiBvZiBjYWJiYWdlIGFuZCBjdWN1bWJlciBzdXBwb3J0cyB0aGUgYSBwcmlvcmkgaHlwb3RoZXNpcyBwcmV2aW91c2x5IHJlcG9ydGVkLgpJbiB0aGlzIGh5cG90aGVzaXMsIHdlIHByb3Bvc2VkIHRoYXQgdmVnZXRhYmxlcyBzdWNoIGFzIEJyYXNzaWNhIC0gd2l0aCBhbiBhbnRpb3hpZGFudCBhY3Rpdml0eSByZWR1Y2luZyBpbnN1bGluIHJlc2lzdGFuY2UgLSBtYXkgYWxzbyBiZSBhc3NvY2lhdGVkIHdpdGggbG93IENPVklELTE5IG1vcnRhbGl0eSBpbiBjb3VudHJpZXMuCiIKCiIKVGhvdWdoIG91ciByZXN1bHRzIGRvIG5vdCBhbGxvdyB0byBpbmZlciBjYXVzYWxpdHksIHRoZXkgZG8gcmVpbmZvcmNlIG91ciBhIHByaW9yeSBoeXBvdGhlc2lzIHRoYXQgdGhlIGluZ2VzdGlvbiBvZiBhbnRpLW94aWRhbnQgZm9vZHMgYWN0aW5nIG9uIGluc3VsaW4gaW50b2xlcmFuY2UgbWF5IGhhdmUgcmVkdWNlZCB0aGUgc2V2ZXJpdHkgb2YgQ09WSUQtMTkuCiIKCi0tLQoKIVtdKGh0dHBzOi8vZ2l0aHViLmNvbS9zdGF0T21pY3Mvc2JjMjAvcmF3L21hc3Rlci9maWd1cmVzL2NvdmlkVmVnZXRhYmxlczQucG5nKQoKLS0tCgohW10oaHR0cHM6Ly9naXRodWIuY29tL3N0YXRPbWljcy9zYmMyMC9yYXcvbWFzdGVyL2ZpZ3VyZXMvY292aWRWZWdldGFibGVzMy5wbmcpCgotIFZlbGUgaHlwb3RoZXNlcyB3b3JkZW4gZ2V0ZXN0ID8hCi0gQ2F1c2FsaXRlaXQgPyEKLSBCZWxhbmcgdmFuIGV4cGVyaW1lbnRlZWwgZGVzaWduOiBPYnNlcnZhdGlvbmVsZSBzdHVkaWUKLSBPcCBiYXNpcyB2YW4gZGUgZGF0YSB6aWpuIGdlZW4gdWl0c3ByYWtlbiBtb2dlbGlqayBvcCBoZXQgbml2ZWF1IHZhbiBpbmRpdmlkdWVuCgotLS0KCiFbXShodHRwczovL2dpdGh1Yi5jb20vc3RhdE9taWNzL3NiYzIwL3Jhdy9tYXN0ZXIvZmlndXJlcy9jb3ZpZFZlZ2V0YWJsZXMyLnBuZyl7d2lkdGg9NzAlfQoKLSBCZWxhbmcgRGF0YSBFeHBsb3JhdGllIQotIERhdGEgdG9vbnQgbmlldCBlY2h0IGVlbiB0cmVuZAotIERhdGEgdG9vbnQgZWVyZGVyIHR3ZWUgY2x1c3RlcnM6IGJlbmVkZW4gZW4gYm92ZW4gMjAwIGRvZGVuL21pbGpvZW4KLSBNb2RlbCBvcCBiYXNpcyB2YW4ga29ta29tbWVyIGNvbnN1bXB0aWUgbW9kZWxsZWVydCBkZSBkYXRhIG5pZXQgY29ycmVjdDogb3ZlcnNjaGF0dGluZyB2b29yIGVlbiBoZWVsIGFhbnRhbCBsYW5kZW4gbWV0IGxhZ2UgY29uc3VtcHRpZSB6b2FscyBQb3J0dWdhbCwgSG9uZ2FyaWplLCBTbG92ZW5pw6ssIC4uLgoKLS0tCgotIFBhcGVycyB6aWpuIG5vZyBuaWV0IGFhbnZhYXJkIGluIGVlbiBqb3VybmFsIG1hYXIgd29yZGVuIHRvY2ggYWwgNCBrZWVyIGdlY2l0ZWVyZCBpbiBwYXBlcnMgZGllIHJlZWRzIHppam4gZ2VwdWJsaWNlZXJkIGluIHdldGVuc2NoYXBwZWxpamtlIHRpamRzY2hyaWZ0ZW4hISEKCi0tLQoKRHJpZSBncm90ZSB0YWtrZW4gaW4gc3RhdGlzdGllawoKMS4gU3RhdGlzdGlzY2hlIGluZmVyZW50aWUKCiAgLSBJcyBlciBlZW4gdmVyYmFuZCB0dXNzZW4gQ09WSUQtMTkgZW4gdm9lZHNlbGNvbnN1bXB0aWU/CiAgLSBHZXZhYXIgZGllIHdlIG9wbWVya3RlbiBpbiBzdHVkaWU6CiAgICAgIC0gZGF0YSBkcmVkZ2luZywgcC1oYWNraW5nLCAuLi46IGluIGdyb3RlIGRhdGFzZXRzIHdhYXIgamUgaGVlbCB2ZWVsIGh5cG90aGVzZXMgdGVzdCB2aW5kIGplIHZyaWp3ZWwgYWx0aWpkIHZyaWogc3RlcmtlIHBhdHJvbmVuIHZpbmRlbiBkb29yIHRvZXZhbCAkXHJpZ2h0YXJyb3ckIEplIG1vZXQgamUgYW5hbHlzZSBjb3JyaWdlcmVuIGFscyBqZSBtZWVyZGVyZSBoeXBvdGhlc2VzIHRlc3QuCiAgICAgIC0gTW9kZWwgYWFubmFtZXMgbmlldCB2b2xkYWFuCiAgICAgIC0gQ29uZm91bmRpbmcKCjIuIFN0dWRpZWRlc2lnbgoKICAgIC0gQ29uZm91bmRpbmc6IExhbmRlbiB2ZXJzY2hpbGxlbiBuaWV0IGVua2VsIGluIGNvbnN1bXB0aWUgdmFuIMOpw6luIGJlcGFhbGRlIGdyb2VudGUgbWFhciBvb2sgaW4gYW5kZXJlIHZlcmFuZGVybGlqa2VuIChkZW1vZ3JhZmllLCByZWdpc3RyYXRpZSB2YW4gY292aWQgZG9kZW4sIG1hYXRyZWdlbHMsIGdlem9uZGhlaWRzem9yay4uLikgZGllIGdlcmVsYXRlZXJkIHppam4gYWFuIENPVklELTE5IG1vcnRhbGl0ZWl0CgogICAgLSBEYWFyb20gbW9laWxpamsgb20gdWl0IG9ic2VydmF0aW9uZWxlIHN0dWRpZXMgY2F1c2FsZSAob29yemFhay1nZXZvbGcpIHZlcmJhbmRlbiB0ZSB0cmVra2VuCgogICAgLSBJbiBleHBlcmltZW50ZWxlIHN0dWRpZTogIHJhbmRvbWlzYXRpZSBvbSB0ZSB6b3JnZW4gZGF0IGdyb2VwZW4gZW5rZWwgdmVyc2NoaWxsZW4gaW4gZGUgYmVoYW5kZWxpbmcuCgogICAgLSBFeHBlcmltZW50ZWxlIHN0dWRpZXMgemlqbiBkYWFyb20gZGUgZ291ZGVuIHN0YW5kYWFyZCBvbSB0ZSB0ZXN0ZW4gdm9vciBjYXVzYWxlIHZlcmJhbmRlbi4KCjMuIERhdGEgZXhwbG9yYXRpZSBlbiB2aXN1YWxpc2F0aWUKCiAgICAtIENydWNpYWFsIG9tIGluemljaHQgdGUgdmVyd2VydmVuIGluIGRlIGRhdGEKICAgIC0gTW9kZWwgdmVyb25kZXJzdGVsbGluZ2VuIG5hZ2FhbiEKCi0tLQoKR2FyY2lhLUJlcnRob3UgJiBBbGNhcmF6IChNZWQuIFJlcy4gTWV0aC4gMjAwNCk6CgotIEphYXJnYW5nIDIwMDEgdmFuIE5hdHVyZSBlbiBCcml0aXNoIE1lZGljYWwgSm91cm5hbAotIDM4JSBlbiAyNSUgdmFuIGFydGlrZWxlbiBiZXZhdCBlZW4gc3RhdGlzdGlzY2hlIGZvdXQKLSAxMSU6IGZvdXRlbiB0ZWdlbiBpbnRlcnByZXRhdGllCi0gNCU6IGJlc2x1aXQgc3ByZWVrdCBldmlkZW50aWUgdGVnZW4KCiRccmlnaHRhcnJvdyQgU3RhdGlzdGlzY2hlIGdlbGV0dGVyZGhlaWQgaXMgY3J1Y2lhYWwgb20gcmVzdWx0YXRlbiBlbiBwdWJsaWNhdGllcyBrcml0aXNjaCBlbiBjb3JyZWN0IHRlIGt1bm5lbiBpbnRlcnByZXRlcmVuLgoKLS0tCgojIENhc2Ugc3R1ZHk6IG9rc2VsIG1pY3JvYmlvbWUKCgohW10oaHR0cHM6Ly9pbWFnZXMudnJ0LmJlL3dpZHRoMTI4MC8yMDE4LzA2LzI3LzRlNzIwOThkLTdhMGQtMTFlOC1hYmNjLTAyYjdiNzZiZjQ3Zi5qcGcpe3dpZHRoPTcwJX0KCi0gaHR0cHM6Ly93d3cudnJ0LmJlL3ZydG53cy9ubC8yMDE4LzEwLzIyL2dlem9jaHQtbWVuc2VuLW1ldC1wZW5ldHJhbnRlLWxpamZnZXVyLW9tLXByb2Jpb3Rpc2NoZS1kZW9kb3IvCi0gaHR0cHM6Ly95b3V0dS5iZS85UklGeXFMWGRWdwoKLS0tCgotIE9rc2VsZ2V1ciB3b3JkdCBuaWV0IHZlcm9vcnphYWt0IGRvb3IgaGV0IHp3ZWV0IHplbGYuIERlIGdldXIgaXMgYWZrb21zdGlnIHZhbiBzcGVjaWZpY2llayBtaWNyby1vcmdhbmlzbWVuIHZhbiBkZSBncm9lcCAqQ29yeW5lYmFjdGVyaXVtIHNwcC4qIGRpZSBoZXQgendlZXQgbWV0YWJvbGlzZXJlbi4gKlN0YXBoeWxvY29jY3VzIHNwcC4qIHppam4gZWVuIGFuZGVyZSBncm9lcCBiYWN0ZXJpw6tuIGRpZSBvb2sgYWJ1bmRhbnQgemlqbiBpbiBoZXQgbWljcm9iaW9tZSB2YW4gZGUgb2tzZWwgZGllIHp3ZWV0IG1ldGFib2xpc2VyZW4gbmFhciBtZXRhYm9saWV0ZW4gZGllIG5pZXQgc3Rpbmtlbi4KCi0gRGUgQ01FVC1ncm9lcCBhYW4gVUdFTlQgZG9ldCBvbmRlcnpvZWsgbmFhciBoZXQgdHJhbnNwbGFudGVyZW4gdmFuIGRlIG1pY3JvYmnDq2xlIGdlbWVlbnNjaGFwLCBoZXQgbWljcm9iaW9tZSwgb20gbWVuc2VuIHZhbiBnZXVyZW5kZSBva3NlbHMgYWYgdGUgaGVscGVuLiAgCgotIFZvb3JnZXN0ZWxkZSB0aGVyYXBpZQogIAkxLiBWZXJ3aWpkZXIgaGV0IG9rc2VsIG1pY3JvYmlvbWUgbWV0IGFudGliaW90aWNhCiAgICAyLiBCZcOvbnZsb2VkIGhldCBva3NlbCBtaWNyb2Jpb21lIGRvb3IgbWljcm9iaW9tZSB0ZSB0cmFuc3BsYW50ZXJlbiB2YW4gZWVuIGluZGl2aWR1ZSBkaWUgZ2VlbiBnZXVyZW5kZSBva3NlbHMgaGVlZnQgKGh0dHBzOi8veW91dHUuYmUvOVJJRnlxTFhkVncpCgoKLS0tCgojIyBQcm9lZm9wemV0IChleHBlcmltZW50YWwgZGVzaWduKQoKYGBge3Igb3V0LndpZHRoPSc4MCUnLGZpZy5hc3A9LjgsIGZpZy5hbGlnbj0nY2VudGVyJyxlY2hvPUZBTFNFfQppZiAoInBpIiVpbiVscygpKSBybSgicGkiKQprb3B2b2V0ZXI8LWZ1bmN0aW9uKHgseSxhbmdsZT0wLGw9LjIsY2V4LmRvdD0uNSxwY2g9MTksY29sPSJibGFjayIpCnsKYW5nbGU9YW5nbGUvMTgwKnBpCnBvaW50cyh4LHksY2V4PWNleC5kb3QscGNoPXBjaCxjb2w9Y29sKQpsaW5lcyhjKHgseCtsKmNvcygtcGkvMithbmdsZSkpLGMoeSx5K2wqc2luKC1waS8yK2FuZ2xlKSksY29sPWNvbCkKbGluZXMoYyh4K2wvMipjb3MoLXBpLzIrYW5nbGUpLHgrbC8yKmNvcygtcGkvMithbmdsZSkrbC80KmNvcyhhbmdsZSkpLGMoeStsLzIqc2luKC1waS8yK2FuZ2xlKSx5K2wvMipzaW4oLXBpLzIrYW5nbGUpK2wvNCpzaW4oYW5nbGUpKSxjb2w9Y29sKQpsaW5lcyhjKHgrbC8yKmNvcygtcGkvMithbmdsZSkseCtsLzIqY29zKC1waS8yK2FuZ2xlKStsLzQqY29zKHBpK2FuZ2xlKSksYyh5K2wvMipzaW4oLXBpLzIrYW5nbGUpLHkrbC8yKnNpbigtcGkvMithbmdsZSkrbC80KnNpbihwaSthbmdsZSkpLGNvbD1jb2wpCmxpbmVzKGMoeCtsKmNvcygtcGkvMithbmdsZSkseCtsKmNvcygtcGkvMithbmdsZSkrbC8yKmNvcygtcGkvMitwaS80K2FuZ2xlKSksYyh5K2wqc2luKC1waS8yK2FuZ2xlKSx5K2wqc2luKC1waS8yK2FuZ2xlKStsLzIqc2luKC1waS8yK3BpLzQrYW5nbGUpKSxjb2w9Y29sKQpsaW5lcyhjKHgrbCpjb3MoLXBpLzIrYW5nbGUpLHgrbCpjb3MoLXBpLzIrYW5nbGUpK2wvMipjb3MoLXBpLzItcGkvNCthbmdsZSkpLGMoeStsKnNpbigtcGkvMithbmdsZSkseStsKnNpbigtcGkvMithbmdsZSkrbC8yKnNpbigtcGkvMi1waS80K2FuZ2xlKSksY29sPWNvbCkKfQoKcGFyKG1hcj1jKDAsMCwwLDApLG1haT1jKDAsMCwwLDApKQpwbG90KDAsMCx4bGFiPSIiLHlsYWI9IiIseGxpbT1jKDAsMTApLHlsaW09YygwLDEwKSxjb2w9MCx4YXh0PSJub25lIix5YXh0PSJub25lIixheGVzPUZBTFNFKQpyZWN0KDAsNiwxMCwxMCxib3JkZXI9InJlZCIsbHdkPTIpCnRleHQoLjUsOCwicG9wdWxhdGlvbiIsc3J0PTkwLGNvbD0icmVkIixjZXg9MikKc3ltYm9scyAoMywgOCwgY2lyY2xlcz0xLjUsIGNvbD0icmVkIixhZGQ9VFJVRSxmZz0icmVkIixpbmNoZXM9RkFMU0UsbHdkPTIpCnNldC5zZWVkKDMzMCkKZ3JpZD1zZXEoMCwxLjMsLjAxKQoKZm9yIChpIGluIDE6NTApCnsKCWFuZ2xlMT1ydW5pZihuPTEsbWluPTAsbWF4PTM2MCkKCWFuZ2xlMj1ydW5pZihuPTEsbWluPTAsbWF4PTM2MCkKCXJhZGl1cz1zYW1wbGUoZ3JpZCxwcm9iPWdyaWReMipwaS9zdW0oZ3JpZF4yKnBpKSxzaXplPTEpCglrb3B2b2V0ZXIoMytyYWRpdXMqY29zKGFuZ2xlMS8xODAqcGkpLDgrcmFkaXVzKnNpbihhbmdsZTEvMTgwKnBpKSxhbmdsZT1hbmdsZTIpCn0KdGV4dCg3LjUsOCwiTWljcm9iaW9tZSBpbiBwb3B1bGF0aW9uIixjb2w9InJlZCIsY2V4PTEuMikKYGBgCgotLS0KCgpgYGB7ciBvdXQud2lkdGg9JzgwJScsZmlnLmFzcD0uOCwgZmlnLmFsaWduPSdjZW50ZXInLGVjaG89RkFMU0V9CmlmICgicGkiJWluJWxzKCkpIHJtKCJwaSIpCmtvcHZvZXRlcjwtZnVuY3Rpb24oeCx5LGFuZ2xlPTAsbD0uMixjZXguZG90PS41LHBjaD0xOSxjb2w9ImJsYWNrIikKewphbmdsZT1hbmdsZS8xODAqcGkKcG9pbnRzKHgseSxjZXg9Y2V4LmRvdCxwY2g9cGNoLGNvbD1jb2wpCmxpbmVzKGMoeCx4K2wqY29zKC1waS8yK2FuZ2xlKSksYyh5LHkrbCpzaW4oLXBpLzIrYW5nbGUpKSxjb2w9Y29sKQpsaW5lcyhjKHgrbC8yKmNvcygtcGkvMithbmdsZSkseCtsLzIqY29zKC1waS8yK2FuZ2xlKStsLzQqY29zKGFuZ2xlKSksYyh5K2wvMipzaW4oLXBpLzIrYW5nbGUpLHkrbC8yKnNpbigtcGkvMithbmdsZSkrbC80KnNpbihhbmdsZSkpLGNvbD1jb2wpCmxpbmVzKGMoeCtsLzIqY29zKC1waS8yK2FuZ2xlKSx4K2wvMipjb3MoLXBpLzIrYW5nbGUpK2wvNCpjb3MocGkrYW5nbGUpKSxjKHkrbC8yKnNpbigtcGkvMithbmdsZSkseStsLzIqc2luKC1waS8yK2FuZ2xlKStsLzQqc2luKHBpK2FuZ2xlKSksY29sPWNvbCkKbGluZXMoYyh4K2wqY29zKC1waS8yK2FuZ2xlKSx4K2wqY29zKC1waS8yK2FuZ2xlKStsLzIqY29zKC1waS8yK3BpLzQrYW5nbGUpKSxjKHkrbCpzaW4oLXBpLzIrYW5nbGUpLHkrbCpzaW4oLXBpLzIrYW5nbGUpK2wvMipzaW4oLXBpLzIrcGkvNCthbmdsZSkpLGNvbD1jb2wpCmxpbmVzKGMoeCtsKmNvcygtcGkvMithbmdsZSkseCtsKmNvcygtcGkvMithbmdsZSkrbC8yKmNvcygtcGkvMi1waS80K2FuZ2xlKSksYyh5K2wqc2luKC1waS8yK2FuZ2xlKSx5K2wqc2luKC1waS8yK2FuZ2xlKStsLzIqc2luKC1waS8yLXBpLzQrYW5nbGUpKSxjb2w9Y29sKQp9CgpwYXIobWFyPWMoMCwwLDAsMCksbWFpPWMoMCwwLDAsMCkpCnBsb3QoMCwwLHhsYWI9IiIseWxhYj0iIix4bGltPWMoMCwxMCkseWxpbT1jKDAsMTApLGNvbD0wLHhheHQ9Im5vbmUiLHlheHQ9Im5vbmUiLGF4ZXM9RkFMU0UpCnJlY3QoMCw2LDEwLDEwLGJvcmRlcj0icmVkIixsd2Q9MikKdGV4dCguNSw4LCJwb3B1bGF0aW9uIixzcnQ9OTAsY29sPSJyZWQiLGNleD0yKQpzeW1ib2xzICgzLCA4LCBjaXJjbGVzPTEuNSwgY29sPSJyZWQiLGFkZD1UUlVFLGZnPSJyZWQiLGluY2hlcz1GQUxTRSxsd2Q9MikKc2V0LnNlZWQoMzMwKQpncmlkPXNlcSgwLDEuMywuMDEpCgpmb3IgKGkgaW4gMTo1MCkKewoJYW5nbGUxPXJ1bmlmKG49MSxtaW49MCxtYXg9MzYwKQoJYW5nbGUyPXJ1bmlmKG49MSxtaW49MCxtYXg9MzYwKQoJcmFkaXVzPXNhbXBsZShncmlkLHByb2I9Z3JpZF4yKnBpL3N1bShncmlkXjIqcGkpLHNpemU9MSkKCWtvcHZvZXRlcigzK3JhZGl1cypjb3MoYW5nbGUxLzE4MCpwaSksOCtyYWRpdXMqc2luKGFuZ2xlMS8xODAqcGkpLGFuZ2xlPWFuZ2xlMikKfQp0ZXh0KDcuNSw4LCJNaWNyb2Jpb21lIGluIHBvcHVsYXRpb24iLGNvbD0icmVkIixjZXg9MS4yKQoKcmVjdCgwLDAsMTAsNCxib3JkZXI9ImJsdWUiLGx3ZD0yKQp0ZXh0KC41LDIsInNhbXBsZSIsc3J0PTkwLGNvbD0iYmx1ZSIsY2V4PTIpCnN5bWJvbHMgKDMsIDIsIGNpcmNsZXM9MS41LCBjb2w9InJlZCIsYWRkPVRSVUUsZmc9ImJsdWUiLGluY2hlcz1GQUxTRSxsd2Q9MikKZm9yIChpIGluIDA6MSkKCWZvciAoaiBpbiAwOjQpCnsKCglrb3B2b2V0ZXIoMi4xK2oqKDMuOS0yLjEpLzQsMS4xK2kvMixjb2w9ImJsYWNrIikKfQpmb3IgKGkgaW4gMjozKQoJZm9yIChqIGluIDA6NCkKewoKCWtvcHZvZXRlcigyLjEraiooMy45LTIuMSkvNCwxLjYraS8yLGNvbD0iYmxhY2siKQp9CnRleHQoNy41LDIsIk1pY3JvYmlvbWUgaW4gc2FtcGxlIixjb2w9ImJsdWUiLGNleD0xLjIpCgphcnJvd3MoMyw1LjksMyw0LjEsY29sPSJibGFjayIsbHdkPTMpCnRleHQoMS41LDUsIkVYUC4gREVTSUdOICgxKSIsY29sPSJibGFjayIsY2V4PTEuMikKYGBgCgotLS0KCi0gRXhwZXJpbWVudDoKCiAgICAtIDIwIHBlcnNvbmVuIHdvcmRlbiBhdCByYW5kb20gdWl0IGRlIHBvcHVsYXRpZSBnZXRyb2trZW4gdmFuIHBlcnNvbmVuIG1ldCBlZW4gb2tzZWxnZXVyOiBzdGVla3Byb2VmIHJlcHJlc2VudGF0aWVmIHZvb3IgcG9wdWxhdGllIQoKICAgIC0gZGUgcGVyc29uZW4gd29yZGVuIGF0IHJhbmRvbSB2ZXJkZWVsZCBvdmVyIHR3ZWUgYmVoYW5kZWxpbmdzZ3JvZXBlbjoKCiAgICAgICAgLSBwbGFjZWJvIChlbmtlbCBhbnRpYmlvdGljYSkKICAgICAgICAtIHRyYW5zcGxhbnRpZSAoYW50aWJpb3RpY2EgZW4gbWljcm9iacOrbGUgdHJhbnNwbGFudGF0aWUpLgogICAgICAgIC0gUmFuZG9taXNhdGllIGlzIGJlbGFuZ3Jpamsgb20gZXJ2b29yIHRlIHpvcmdlbiBkYXQgZGUgZ3JvZXBlbiB2ZXJnZWxpamtiYWFyIHppam4uCgogICAgLSBIZXQgbWljcm9iaW9tZSB3b3JkdCBiZW1vbnN0ZXJkIDYgd2VrZW4gbmEgZGUgYmVoYW5kZWxpbmcuCiAgICAtIFRoZSByZWxhdGl2ZSBhYnVuZGFudGllIHZhbiAqU3RhcGh5bG9jb2NjdXMgc3BwLiogb3AgKkNvcnluZWJhY3Rlcml1bSBzcHAuKiArICpTdGFwaHlsb2NvY2N1cyBzcHAuKiBpbiBoZXQgbWljcm9iaW9tZSB3b3JkdCBnZW1ldGVuIHZpYSBER0dFICgqRGVuYXR1cmluZyBHcmFkaWVudCBHZWwgRWxlY3Ryb3Bob3Jlc2lzKikuCgotLS0KCkRHR0UKCiFbXShodHRwczovL2pvdXJuYWxzLnBsb3Mub3JnL3Bsb3NvbmUvYXJ0aWNsZS9maWd1cmUvaW1hZ2U/c2l6ZT1sYXJnZSZkb3dubG9hZD0maWQ9MTAuMTM3MS9qb3VybmFsLnBvbmUuMDA3MDUzOC5nMDAxKXt3aWR0aD03MCV9CgpodHRwczovL2RvaS5vcmcvMTAuMTM3MS9qb3VybmFsLnBvbmUuMDA3MDUzOAoKLS0tCgpWZXJ0YWFsIG9uZGVyem9la3N2cmFhZyBuYWFyIGlldHMgd2F0IHdlIGt1bm5lbiBxdWFudGlmaWNlcmVuOiBJcyBlciBlZW4gdmVyc2NoaWwgaW4gcmVsYXRpZXZlIGFidW5kYW50aWUgdmFuICpTdGFwaHlsb2NvY2N1cyBzcHAuKiBpbiBoZXQgbWljcm9iaW9tZSB2YW4gZGUgcGxhY2VibyBncm9lcCBlbiBkZSB0cmFuc3BsYW50YXRpZQoKLS0tCgpgYGB7ciBvdXQud2lkdGg9JzgwJScsZmlnLmFzcD0uOCwgZmlnLmFsaWduPSdjZW50ZXInLGVjaG89RkFMU0V9CmlmICgicGkiJWluJWxzKCkpIHJtKCJwaSIpCmtvcHZvZXRlcjwtZnVuY3Rpb24oeCx5LGFuZ2xlPTAsbD0uMixjZXguZG90PS41LHBjaD0xOSxjb2w9ImJsYWNrIikKewphbmdsZT1hbmdsZS8xODAqcGkKcG9pbnRzKHgseSxjZXg9Y2V4LmRvdCxwY2g9cGNoLGNvbD1jb2wpCmxpbmVzKGMoeCx4K2wqY29zKC1waS8yK2FuZ2xlKSksYyh5LHkrbCpzaW4oLXBpLzIrYW5nbGUpKSxjb2w9Y29sKQpsaW5lcyhjKHgrbC8yKmNvcygtcGkvMithbmdsZSkseCtsLzIqY29zKC1waS8yK2FuZ2xlKStsLzQqY29zKGFuZ2xlKSksYyh5K2wvMipzaW4oLXBpLzIrYW5nbGUpLHkrbC8yKnNpbigtcGkvMithbmdsZSkrbC80KnNpbihhbmdsZSkpLGNvbD1jb2wpCmxpbmVzKGMoeCtsLzIqY29zKC1waS8yK2FuZ2xlKSx4K2wvMipjb3MoLXBpLzIrYW5nbGUpK2wvNCpjb3MocGkrYW5nbGUpKSxjKHkrbC8yKnNpbigtcGkvMithbmdsZSkseStsLzIqc2luKC1waS8yK2FuZ2xlKStsLzQqc2luKHBpK2FuZ2xlKSksY29sPWNvbCkKbGluZXMoYyh4K2wqY29zKC1waS8yK2FuZ2xlKSx4K2wqY29zKC1waS8yK2FuZ2xlKStsLzIqY29zKC1waS8yK3BpLzQrYW5nbGUpKSxjKHkrbCpzaW4oLXBpLzIrYW5nbGUpLHkrbCpzaW4oLXBpLzIrYW5nbGUpK2wvMipzaW4oLXBpLzIrcGkvNCthbmdsZSkpLGNvbD1jb2wpCmxpbmVzKGMoeCtsKmNvcygtcGkvMithbmdsZSkseCtsKmNvcygtcGkvMithbmdsZSkrbC8yKmNvcygtcGkvMi1waS80K2FuZ2xlKSksYyh5K2wqc2luKC1waS8yK2FuZ2xlKSx5K2wqc2luKC1waS8yK2FuZ2xlKStsLzIqc2luKC1waS8yLXBpLzQrYW5nbGUpKSxjb2w9Y29sKQp9CgpwYXIobWFyPWMoMCwwLDAsMCksbWFpPWMoMCwwLDAsMCkpCnBsb3QoMCwwLHhsYWI9IiIseWxhYj0iIix4bGltPWMoMCwxMCkseWxpbT1jKDAsMTApLGNvbD0wLHhheHQ9Im5vbmUiLHlheHQ9Im5vbmUiLGF4ZXM9RkFMU0UpCnJlY3QoMCw2LDEwLDEwLGJvcmRlcj0icmVkIixsd2Q9MikKdGV4dCguNSw4LCJwb3B1bGF0aW9uIixzcnQ9OTAsY29sPSJyZWQiLGNleD0yKQpzeW1ib2xzICgzLCA4LCBjaXJjbGVzPTEuNSwgY29sPSJyZWQiLGFkZD1UUlVFLGZnPSJyZWQiLGluY2hlcz1GQUxTRSxsd2Q9MikKc2V0LnNlZWQoMzMwKQpncmlkPXNlcSgwLDEuMywuMDEpCgpmb3IgKGkgaW4gMTo1MCkKewoJYW5nbGUxPXJ1bmlmKG49MSxtaW49MCxtYXg9MzYwKQoJYW5nbGUyPXJ1bmlmKG49MSxtaW49MCxtYXg9MzYwKQoJcmFkaXVzPXNhbXBsZShncmlkLHByb2I9Z3JpZF4yKnBpL3N1bShncmlkXjIqcGkpLHNpemU9MSkKCWtvcHZvZXRlcigzK3JhZGl1cypjb3MoYW5nbGUxLzE4MCpwaSksOCtyYWRpdXMqc2luKGFuZ2xlMS8xODAqcGkpLGFuZ2xlPWFuZ2xlMikKfQp0ZXh0KDcuNSw4LCJNaWNyb2Jpb21lIGluIHBvcHVsYXRpb24iLGNvbD0icmVkIixjZXg9MS4yKQoKcmVjdCgwLDAsMTAsNCxib3JkZXI9ImJsdWUiLGx3ZD0yKQp0ZXh0KC41LDIsInNhbXBsZSIsc3J0PTkwLGNvbD0iYmx1ZSIsY2V4PTIpCnN5bWJvbHMgKDMsIDIsIGNpcmNsZXM9MS41LCBjb2w9InJlZCIsYWRkPVRSVUUsZmc9ImJsdWUiLGluY2hlcz1GQUxTRSxsd2Q9MikKZm9yIChpIGluIDA6MSkKCWZvciAoaiBpbiAwOjQpCnsKCglrb3B2b2V0ZXIoMi4xK2oqKDMuOS0yLjEpLzQsMS4xK2kvMixjb2w9InB1cnBsZSIpCn0KZm9yIChpIGluIDI6MykKCWZvciAoaiBpbiAwOjQpCnsKCglrb3B2b2V0ZXIoMi4xK2oqKDMuOS0yLjEpLzQsMS42K2kvMixjb2w9Im9yYW5nZSIpCn0KdGV4dCg3LjUsMiwiTWljcm9iaW9tZSBpbiBzYW1wbGUiLGNvbD0iYmx1ZSIsY2V4PTEuMikKCmFycm93cygzLDUuOSwzLDQuMSxjb2w9ImJsYWNrIixsd2Q9MykKdGV4dCgxLjUsNSwiRVhQLiBERVNJR04gKDEpIixjb2w9ImJsYWNrIixjZXg9MS4yKQp0ZXh0KDcuNSwuNSwiREFUQSBFWFBMT1JBVElPTiAmXG5ERVNDUklQVElWRSBTVEFUSVNUSUNTICgyKSIsY29sPSJibGFjayIsY2V4PTEuMikKYGBgCgotLS0KCiMjIERhdGEgRXhwbG9yYXRpZSBlbiBiZXNjaHJpanZlbmRlIHN0YXRpc3RpZWsKCgotIERhdGEgZXhwbG9yYXRpZSBpcyBoZWVsIGJlbGFuZ3Jpamsgb20gaW56aWNodCB0ZSBrcmlqZ2VuIGluIGRlIGRhdGEgZW4gaXMgZWVuIGVzc2VudGnDq2xlIGVlcnN0ZSBzdGFwIG9tIHRlIGxlcmVuIHVpdCBkYXRhLgotIEhldCB3b3JkdCB2YWFrIG9uZGVyZ2V3YWFyZGVlcmQgb2Ygb3ZlciBoZXQgaG9vZmQgZ2V6aWVuLgoKLS0tCgojIyMgSW1wb3J0ZWVyIGRlIGRhdGEKCi0gRGF0YSBpbiBkZXplIGN1cnN1cyB3b3JkdCB2ZXJ3ZXJrdCB2aWEgaGV0IHN0YXRpc3Rpc2NoIHNvZnR3YXJlIHBha2tldCBSLgotIERpdCBwYWtrZXQgbGFhdCB0b2Ugb20gdGUgbGVyZW4gdWl0IGRhdGEuCi0gSW4gZGV6ZSBjdXJzdXMgZ2FhbiB3ZSBkYXRhIGVlcnN0IGV4cGxvcmVyZW4gb20gaW56aWNodCB0ZSB2ZXJ3ZXJ2ZW4gaW4gZGUgZ2VnZXZlbnMgb20gZGllIHZlcnZvbGdlbnMgc3RhdGlzdGlzY2ggdGUgdmVyd2Vya2VuLgotIFZvb3JhbGVlciB3ZSBoaWVybWVlIHZhbiBzdGFydCBrdW5uZW4gZ2FhbiBtb2V0ZW4gd2UgZGUgZGF0YSBlZXJzdCBpbXBvcnRlcmVuIGluIFIuCgotIFZpYSBoZXQgdm9sZ2VuZGUgY29tbWFuZG8ga3VubmVuIHdlIGVua2VsZSByZWdlbHMgdmFuIGVlbiBkYXRhIGJlc3RhbmQgaW5sZXplbiBvbSBkZSBzdHJ1Y3R1dXIgdmFuIGhldCBkYXRhIGJlc3RhbmQgdGUgd2V0ZW4gdGUga29tZW4uCgpgYGB7cn0KcmVhZF9saW5lcygiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL3N0YXRPbWljcy9zYmMyMC9tYXN0ZXIvZGF0YS9hcm1waXQuY3N2IikKYGBgCgotIEdlZ2V2ZW5zIGluIGhldCBiZXN0YW5kIHppam4gZG9vciBjb21tYSdzIGdlc2NoZWlkZW4uCi0gRWxrZSByaWogYmV2YXQgZGUgZ2VnZXZlbnMgdm9vciAxIHByb2VmcGVyc29vbgotIFZlcnNjaGlsbGVuZGUgdmFyaWFiZWxlbiB3b3JkZW4gZ2VtZXRlbiBwZXIgcGVyc29vbiBlbiB6aWpuIHZhbiBlbGthYXIgZ2VzY2hlaWRlbiBkb29yIGVlbiBjb21tYS4gSGV0IGJlc3RhbmQgaXMgY3N2IGZvcm1hYXQ6ICJjb21tYSBzZXBhcmF0ZWQgdmFsdWVzIi4KLSBXZSBrdW5uZW4gYmVzdGFuZGVuIG1ldCBkaXQgZm9ybWFhdCBpbmxlemVuIFIgdmlhIGhldCBjb21tYW5kbyByZWFkX2Nzdi4KLSBXZSBzbGFhbiBkZSBkYXRhIG9wIGluIFIgaW4gaGV0IG9iamVjdCBtZXQgbmFhbSBhcC4gSGllcnZvb3IgZ2VicnVpa2VuIHdlIGRlIGA8LWAgb3BlcmF0b3IuCi0gV2UgZ2V2ZW4gZGUgZGF0YSB0YWJlbCB0ZXJ1ZyBkb29yIGhldCBvYmplY3QgYWFuIHRlIHJvZXBlbiBkb29yIHppam4gbmFhbSB0ZSB0eXBlbi4KCmBgYHtyfQphcCA8LSByZWFkX2NzdigiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL3N0YXRPbWljcy9zYmMyMC9tYXN0ZXIvZGF0YS9hcm1waXQuY3N2IikKYXAKYGBgCgotLS0KCiMjIyBCZXNjaHJpanZlbmRlIHN0YXRpc3RpZWsKCi0gSW4gYXJ0aWtlbHMgZW4gZGUgbWVkaWEgd29yZGVuIHJlc3VsdGF0ZW4gdWl0IGVlbiBzdGVla3Byb2VmIHZhYWsgZ2VyYXBwb3J0ZWVyZCBhLmQuaC52LiBnZW1pZGRlbGRlIGVuIGRlIHN0YW5kYWFyZGFmd2lqa2luZwoKLSBXZSB2YXR0ZW4gZGUgZGF0YSBlZXJzdCBzYW1lbi4gV2UgYmVyZWtlbmVuIGhldCBnZW1pZGRlbGRlIGVuIGRlIHN0YW5kYWFyZCBkZXZpYXRpZSAoZWVuIG1hYXQgdm9vciBkZSBzcHJlaWRpbmcsIHppZSB2b2xnZW5kZSBob29mZHN0dWtrZW4pLgpXZSBzbGFhbiBoZXQgcmVzdWx0YWF0IGhpZXJ2YW4gb3AgaW4gaGV0IG9iamVjdCBhcFJlbFN1bSB2aWEgYGFwUmVsU3VtIDwtYC4KCjEuIFdlIHBpcGVuICh2aWEgYCU+JWApIGhldCBgYXBgIGRhdGFmcmFtZSBuYWFyIGRlIGBncm91cF9ieWAgZnVuY3RpZSBvbSBkZSBkYXRhIHRlIGdyb2VwZXJlbiBwZXIgdHJlYXRtZW50IHRydDogYGdyb3VwX2J5KHRydClgLgoKMi4gV2UgcGlwZW4gaGV0IHJlc3VsdGFhdCBuYWFyIGRlIGBzdW1tYXJpemVfYXRgIGZ1bmN0aW9uIG9tIGRlICJyZWwiIHZhcmlhYmxlIHNhbWVuIHRlIHZhdHRlbiBlbiBiZXJla2VuZW4gaGllcmJpaiBoZXQgZ2VtaWRkZWxkZSBlbiBzdGFuZGFhcmRhZndpamtpbmcuIE9tZGF0IHdlIGRlIGRhdGEgZWVyc3QgaGViYmVuIGdlZ3JvZXBlZXJkIHp1bGxlbiB3ZSBoZXQgZ2VtaWRkZWxkZSBlbiBkZSBzdGFuZGFhcmQgZGV2aWF0aWUgYmVyZWtlbmVuIHBlciBncm9lcC4KCgoKYGBge3J9CmFwUmVsU3VtIDwtIGFwICU+JQogIGdyb3VwX2J5KHRydCkgJT4lCiAgc3VtbWFyaXplX2F0KCJyZWwiLAogICAgICAgICAgICAgICBsaXN0KG1lYW49bWVhbiwKICAgICAgICAgICAgICAgICAgICBzZD1zZAogICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICkKYGBgCgpXZSB0b25lbiB2ZXJ2b2xnZW5zIGhldCByZXN1bHRhYXQgZG9vciBoZXQgb2JqZWN0IGFwUmVsU3VtIGFhbiB0ZSByb2VwZW4KCmBgYHtyfQphcFJlbFN1bQpgYGAKCldlIGt1bm5lbiBvb2sgZWVuIHRhYmVsIGluIGRlIHdlYnBhZ2luYSBvZiBoZXQgcGRmIGJlc3RhbmQgaW50ZWdyZXJlbiB2aWEgaGV0IGNvbW1hbmRvIGthYmxlIHZhbiBoZXQga25pdHIgcGFra2V0OgoKYGBge3J9CmtuaXRyOjprYWJsZShhcFJlbFN1bSkKYGBgCgotLS0KCiMjIyBHcmFmaWVrZW4KCldlIG1ha2VuIGluIGRlemUgY3Vyc3VzIGdlYnJ1aWsgdmFuIGhldCBwYWtrZXQgYGdncGxvdDJgIG9tIGdyYWZpZWtlbiB0ZSBtYWtlbi4gIApNZXQgZGUgZ2dwbG90MiBiaWJsaW90aGVlayBrdW5uZW4gd2UgZ2VtYWtrZWxpamsgZ3JhZmlla2VuIG9wYm91d2VuIGluIGxhZ2VuIChsYXllcnMpLgpIaWVyZG9vciBsZWVzdCBkZSBjb2RlIHZlZWwgbWFra2VsaWprZXIuCgojIyMjIGJhcnBsb3QKCkJhciBwbG90cyB3b3JkZW4gaGVlbCB2ZWVsIGdlYnJ1aWt0IGluIGFydGlrZWxzIG9tIHJlc3VsdGF0ZW4gd2VlciB0ZSBnZXZlbi4KCjEuIFdlIHBpcGVuIGRlIHNhbWVuZ2V2YXR0ZSBkYXRhIG5hYXIgZGUgZnVuY3RpZSBgZ2dwbG90YC4gRGF0IGlzIGRlIGJhc2lzIHZhbiBlbGtlIGdncGxvdC4gIFdlIHNlbGVjdGVyZW4gZGUgdmFyaWFiZWxlIG1ldCBkZSBiZWhhbmRlbGluZyB0cnQgYWxzIHggdmFyaWFiZWxlIGVuIGRlIHZhcmlhYmVsZSBtZXQgbmFhbSBtZWFuIGFscyB5LXZhcmlhYmVsZSB2b29yIGRlIHBsb3QuCldlIGRvZW4gZGl0IHN0ZWVkcyB2aWEgZGUgYWVzdGV0aWNzIGBhZXNgIGZ1bmN0aWUuICAgYGFlcyh4PXRydCx5PW1lYW4pYAoKMi4gV2UgbWFrZW4gZWVuIGJhcnBsb3QgZG9vciBlZW4gbGFhZyB0b2UgdGUgdm9lZ2VuIHZpYSBkZSAgYGdlb21fYmFyYCBmdW5jdGlvbi4gRGUgc3RhdGlzdGllayBpcyBgc3RhdD0iaWRlbnRpdHkiYCBvbWRhdCBkZSBob29ndGUgdmFuIGRlIGJhciBnZWxpamsgaXMgYWFuIGRlIHdhYXJkZSB2b29yIHkgKGhpZXIgaGV0IGdlbWlkZGVsZGUgdm9vciBkZSByZWxhdGlldmUgYWJ1bmRhbnRpZSkuCgozLiBXZSB2b2VnZW4gZm91dGVudmxhZ2dlbiB0b2Ugb20gZGUgb256ZWtlcmhlaWQgb3AgaGV0IGdlbWlkZGVsZGUgd2VlciB0ZSBnZXZlbi4gIFdlIGRvZW4gZGl0IHZpYSBkZSBgZ2VvbV9lcnJvcmJhcmAgZnVuY3RpZSBlbiBzcGVjaWZpw6tyZW4gaGV0IG1pbmltdW0gZW4gbWF4aW11bSB2YW4gZGUgZXJyb3IgYmFyLiBIZXQgYHdpZHRoYCBhcmd1bWVudCB3b3JkdCBnZWJydWlrdCBvbSBkZSBicmVlZHRlIHZhbiBkZSBlcnJvciBiYXIgc21hbGxlciB0ZSBtYWtlbiBkYXQgZGV6ZSB2YW4gZGUgYmFyLgoKYGBge3J9CmFwUmVsU3VtICU+JQogIGdncGxvdChhZXMoeD10cnQseT1tZWFuKSkgKwogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IikgKwogIGdlb21fZXJyb3JiYXIoYWVzKHltaW49bWVhbi1zZCx5bWF4PW1lYW4rc2QpLHdpZHRoPS4yKQpgYGAKCi0gSXMgZGV6ZSBwbG90IGluZm9ybWF0aWVmPz8KCi0tLQoKIyMjIyBib3hwbG90cwoKQmFycGxvdHMgemlqbiBnZWVuIGdvZWRlIGdyYWZpZWtlbjoKCi0gWmUgemlqbiBuaWV0IGluZm9ybWF0aWVmCgotIFplIHZpc3VsYXJpc2VyZW4gZWVuIHNhbWVudmF0dGluZyB2YW4gZGUgZGF0YSBkb29yIHR3ZWUgcHVudGVuOiBgdHdvIHBvaW50IHN1bW1hcnlgOiBnZW1pZGRlbGRlIGVuIGRlIHN0YW5kYWFyZCBkZXZpYXRpZSBoaWVyb3AgZW4ga3VubmVuIGJldGVyIGluIGVlbiB0YWJlbCB3b3JkZW4gb3BnZW5vbWVuLgoKLSBaZSBsYXRlbiBuaWV0IHRvZSBvbSBhbm9tYWxpZcOrbiBpbiBkZSBkYXRhIHpvYWxzIG1lZXRmb3V0ZW4gb3AgdGUgc3BvcmVuLgoKLSBaZSB2ZXJicnVpa2VuIHZlZWwgcnVpbXRlLCBiLnYuIHZhbiBudWwgdG90IGRlIGtsZWluc3RlIHdhYXJkZSB2b29yIGRlIHJlbGF0aWV2ZSBhYnVuZGFudGllKSB3YWFyIGdlZW4gZGF0YSBpbiBsaWd0LgoKSGV0IGlzIGJldGVyIG9tIGRlIGRhdGEgem8gcnV3IG1vZ2VsaWprIHZvb3IgdGUgc3RlbGxlbiB6b2RhdCB3ZSBpbnppY2h0IGtyaWpnZW4gaW4gZGUgdmVyZGVsaW5nIHZhbiBkZSBnZWdldmVucy4KSGllcnZvb3IgenVsbGVuIHdlIG9uZGVybWVlciBib3hwbG90cyBnZWJydWlrZW4uCgotLS0KCldlIG1ha2VuIG51IGVlbiBib3hwbG90IHZvb3IgZGUgYXAgZGF0YQoKMS4gV2UgcGlwZW4gaGV0IGBhcGAgZGF0YWZyYW1lIG5hYXIgYGdncGxvdGAKMi4gV2Ugc2VsZWN0ZXJlbiBkZSBkYXRhIHZvb3IgZGUgcGxvdCB2aWEgYGdncGxvdChhZXMoeD10cnQseT1yZWwpKWAKMy4gV2Ugdm9lZ2VuIGxhYWcgdG9lIHZvb3IgZGUgYm94cGxvdCBkbXYgZGUgZnVuY3RpZSBgZ2VvbV9ib3hwbG90KClgCgpgYGB7cn0KYXAgJT4lICAKICBnZ3Bsb3QoYWVzKHg9dHJ0LHk9cmVsKSkgKwogIGdlb21fYm94cGxvdCgpCmBgYAoKLS0tCgpNZXJrIG9wIGRhdCB3ZSBkZSBwbG90IG9vayBvcCBrdW5uZW4gc2xhYW4gYWxzIGVlbiBvYmplY3QuCgpgYGB7cn0KYXBCb3hwbG90IDwtIGFwICU+JSAgCiAgZ2dwbG90KGFlcyh4PXRydCx5PXJlbCkpICsKICBnZW9tX2JveHBsb3QoKQpgYGAKCkRlIHBsb3Qgd29yZHQgZGFuIG5pZXQgZ2VtYWFrdC4KCk9tIGRlIHBsb3Qgd2VlciB0ZSBnZXZlbiBrdW5uZW4gd2UgaGV0IG9iamVjdCBhYW5yb2VwZW4KCmBgYHtyfQphcEJveHBsb3QKYGBgCgotLS0KCi0gTWVyayBvcCBkYXQgd2UgbmlldCB6b3ZlZWwgZ2VnZXZlbnMgaGViYmVuLiBFbmtlbCAxMCBwZXIgZ3JvZXAuCgotIEhldCBpcyBhbHRpamQgYmV0ZXIgb20gZGUgZGF0YSB6byBydXcgbW9nZWxpamsgdGUgdG9uZW4hCgpPbWRhdCBlciBuaWV0IHpvdmVlbCBnZWdldmVucyB6aWpuIGt1bm5lbiB3ZSBkZSBkYXRhIHRvZXZvZWdlbiBhYW4gZGUgcGxvdCB6b25kZXIgZGF0IGRpZSB0ZSBkcnVrIHdvcmR0LgoKLSBNZXJrIG9wIGRhdCB3ZSBoZXQgYXJndW1lbnQgYG91dGxpZXIuc2hhcGVgIG9wIE5BIChub3QgYXZhaWxhYmxlKSB6ZXR0ZW4gYG91dGxpZXIuc2hhcGU9TkFgIGluIHRoZSBgZ2VvbV9ib3hwbG90YCBmdW5jdGllIG9tZGF0IHdlIGFuZGVycyBvdXRsaWVycyB0d2VlIGtlZXIgd2VlciB6dWxsZW4gZ2V2ZW4uIEVlcnN0IHZpYSBkZSBib3hwbG90IGxhYWcgZW4gZGFhcm5hIG9tZGF0IHdlIGVlbiBsYWFnIG1ldCBhbGxlIHJ1d2UgZGF0YSB0b2V2b2VnZW4gYWFuIGRlIHBsb3QuCi0gV2UgZ2V2ZW4gZGUgcnV3ZSBkYXRhIHdlZXIgdmlhIGRlICBgZ2VvbV9wb2ludChwb3NpdGlvbj0iaml0dGVyIilgIGZ1bmN0aWUuIFdlIGdlYnJ1aWtlbiBoaWVyYmlqIGhldCBhcmd1bWVudCBwb3NpdGlvbj0naml0dGVyJyB6b2RhdCB3ZSB3YXQgcmFuZG9tIHJ1aXMgdG9ldm9lZ2VuIGFhbiBkZSB4LWNvcmRpbmFhdCB6b2RhdCBkZSBnZWdldmVucyBlbGthYXIgbmlldCBvdmVybGFwcGVuLgoKYGBge3J9CmFwICU+JSAgCiAgZ2dwbG90KGFlcyh4PXRydCx5PXJlbCkpICsKICBnZW9tX2JveHBsb3Qob3V0bGllci5zaGFwZT1OQSkgKwogIGdlb21fcG9pbnQocG9zaXRpb249ImppdHRlciIpCmBgYAoKRGl0IGlzIGVlbiBpbmZvcm1hdGlldmUgcGxvdCEKCi0tLQoKQWFuZ2V6aWVuIHdlIGRlIHBsb3Qgb29rIGhlYmJlbiBvcGdlc2xhZ2VuIGtvbmRlbiB3ZSBkaXQgb29rIGRvZW4gZG9vciBkZSBwbG90IG9wIHRlIHJvZXBlbiBlbiBub2cgZWVuIGxhYWcgdG9lIHRlIHZvZWdlbi4KCmBgYHtyfQphcEJveHBsb3QgKwogIGdlb21fcG9pbnQocG9zaXRpb249ImppdHRlciIpCmBgYAoKV2UgaGFkZGVuIGhldCByZXN1bHRhYXQgb29rIG9wbmlldXcgb3Aga3VubmVuIHNsYWFuIHZvb3IgbGF0ZXIgaGVyZ2VicnVpay4KCmBgYHtyfQphcEJveHBsb3QgPC0gYXBCb3hwbG90ICsKICBnZW9tX3BvaW50KHBvc2l0aW9uPSJqaXR0ZXIiKQpgYGAKCi0tLQoKLSBXZSB6YWdlbiBkdWlkZWxpamsgZWVuIGVmZmVjdCB2YW4gZGUgdHJhbnNwbGFudGF0aWUgb3AgZGUgcmVsYXRpZXZlIGFidW5kYW50aWUgdmFuIFN0YXBoeWxvY29jY3VzLgoKLSBJcyBkYXQgZWZmZWN0IG51IGdyb290IGdlbm9lZyBvbSB0ZSBrdW5uZW4gY29uY2x1ZGVyZW4gZGF0IGRlIGJlaGFuZGVsaW5nIHdlcmt0PwoKLS0tCgpgYGB7ciBvdXQud2lkdGg9JzgwJScsZmlnLmFzcD0uOCwgZmlnLmFsaWduPSdjZW50ZXInLGVjaG89RkFMU0V9CmlmICgicGkiJWluJWxzKCkpIHJtKCJwaSIpCmtvcHZvZXRlcjwtZnVuY3Rpb24oeCx5LGFuZ2xlPTAsbD0uMixjZXguZG90PS41LHBjaD0xOSxjb2w9ImJsYWNrIikKewphbmdsZT1hbmdsZS8xODAqcGkKcG9pbnRzKHgseSxjZXg9Y2V4LmRvdCxwY2g9cGNoLGNvbD1jb2wpCmxpbmVzKGMoeCx4K2wqY29zKC1waS8yK2FuZ2xlKSksYyh5LHkrbCpzaW4oLXBpLzIrYW5nbGUpKSxjb2w9Y29sKQpsaW5lcyhjKHgrbC8yKmNvcygtcGkvMithbmdsZSkseCtsLzIqY29zKC1waS8yK2FuZ2xlKStsLzQqY29zKGFuZ2xlKSksYyh5K2wvMipzaW4oLXBpLzIrYW5nbGUpLHkrbC8yKnNpbigtcGkvMithbmdsZSkrbC80KnNpbihhbmdsZSkpLGNvbD1jb2wpCmxpbmVzKGMoeCtsLzIqY29zKC1waS8yK2FuZ2xlKSx4K2wvMipjb3MoLXBpLzIrYW5nbGUpK2wvNCpjb3MocGkrYW5nbGUpKSxjKHkrbC8yKnNpbigtcGkvMithbmdsZSkseStsLzIqc2luKC1waS8yK2FuZ2xlKStsLzQqc2luKHBpK2FuZ2xlKSksY29sPWNvbCkKbGluZXMoYyh4K2wqY29zKC1waS8yK2FuZ2xlKSx4K2wqY29zKC1waS8yK2FuZ2xlKStsLzIqY29zKC1waS8yK3BpLzQrYW5nbGUpKSxjKHkrbCpzaW4oLXBpLzIrYW5nbGUpLHkrbCpzaW4oLXBpLzIrYW5nbGUpK2wvMipzaW4oLXBpLzIrcGkvNCthbmdsZSkpLGNvbD1jb2wpCmxpbmVzKGMoeCtsKmNvcygtcGkvMithbmdsZSkseCtsKmNvcygtcGkvMithbmdsZSkrbC8yKmNvcygtcGkvMi1waS80K2FuZ2xlKSksYyh5K2wqc2luKC1waS8yK2FuZ2xlKSx5K2wqc2luKC1waS8yK2FuZ2xlKStsLzIqc2luKC1waS8yLXBpLzQrYW5nbGUpKSxjb2w9Y29sKQp9CgpwYXIobWFyPWMoMCwwLDAsMCksbWFpPWMoMCwwLDAsMCkpCnBsb3QoMCwwLHhsYWI9IiIseWxhYj0iIix4bGltPWMoMCwxMCkseWxpbT1jKDAsMTApLGNvbD0wLHhheHQ9Im5vbmUiLHlheHQ9Im5vbmUiLGF4ZXM9RkFMU0UpCnJlY3QoMCw2LDEwLDEwLGJvcmRlcj0icmVkIixsd2Q9MikKdGV4dCguNSw4LCJwb3B1bGF0aW9uIixzcnQ9OTAsY29sPSJyZWQiLGNleD0yKQpzeW1ib2xzICgzLCA4LCBjaXJjbGVzPTEuNSwgY29sPSJyZWQiLGFkZD1UUlVFLGZnPSJyZWQiLGluY2hlcz1GQUxTRSxsd2Q9MikKc2V0LnNlZWQoMzMwKQpncmlkPXNlcSgwLDEuMywuMDEpCgpmb3IgKGkgaW4gMTo1MCkKewoJYW5nbGUxPXJ1bmlmKG49MSxtaW49MCxtYXg9MzYwKQoJYW5nbGUyPXJ1bmlmKG49MSxtaW49MCxtYXg9MzYwKQoJcmFkaXVzPXNhbXBsZShncmlkLHByb2I9Z3JpZF4yKnBpL3N1bShncmlkXjIqcGkpLHNpemU9MSkKCWtvcHZvZXRlcigzK3JhZGl1cypjb3MoYW5nbGUxLzE4MCpwaSksOCtyYWRpdXMqc2luKGFuZ2xlMS8xODAqcGkpLGFuZ2xlPWFuZ2xlMikKfQp0ZXh0KDcuNSw4LCJNaWNyb2Jpb21lIGluIHBvcHVsYXRpb24iLGNvbD0icmVkIixjZXg9MS4yKQoKcmVjdCgwLDAsMTAsNCxib3JkZXI9ImJsdWUiLGx3ZD0yKQp0ZXh0KC41LDIsInNhbXBsZSIsc3J0PTkwLGNvbD0iYmx1ZSIsY2V4PTIpCnN5bWJvbHMgKDMsIDIsIGNpcmNsZXM9MS41LCBjb2w9InJlZCIsYWRkPVRSVUUsZmc9ImJsdWUiLGluY2hlcz1GQUxTRSxsd2Q9MikKZm9yIChpIGluIDA6MSkKCWZvciAoaiBpbiAwOjQpCnsKCglrb3B2b2V0ZXIoMi4xK2oqKDMuOS0yLjEpLzQsMS4xK2kvMixjb2w9InB1cnBsZSIpCn0KZm9yIChpIGluIDI6MykKCWZvciAoaiBpbiAwOjQpCnsKCglrb3B2b2V0ZXIoMi4xK2oqKDMuOS0yLjEpLzQsMS42K2kvMixjb2w9Im9yYW5nZSIpCn0KdGV4dCg3LjUsMiwiTWljcm9iaW9tZSBpbiBzYW1wbGUiLGNvbD0iYmx1ZSIsY2V4PTEuMikKCmFycm93cygzLDUuOSwzLDQuMSxjb2w9ImJsYWNrIixsd2Q9MykKdGV4dCgxLjUsNSwiRVhQLiBERVNJR04gKDEpIixjb2w9ImJsYWNrIixjZXg9MS4yKQp0ZXh0KDcuNSwuNSwiREFUQSBFWFBMT1JBVElPTiAmXG5ERVNDUklQVElWRSBTVEFUSVNUSUNTICgyKSIsY29sPSJibGFjayIsY2V4PTEuMikKYXJyb3dzKDcsNC4xLDcsNS45LGNvbD0iYmxhY2siLGx3ZD0zKQp0ZXh0KDguNSw1LCJFU1RJTUFUSU9OICZcbklORkVSRU5DRSAoMykiLGNvbD0iYmxhY2siLGNleD0xLjIpCmBgYAoKLS0tCgotIEluZHVjdGllOiBEb29yIG1pZGRlbCB2YW4gc3RhdGlzdGlzY2hlIGJlc2x1aXR2b3JtaW5nIChpbmZlcmVuY2UpIGt1bm5lbiB3ZSB1aXRzcHJha2VuIGRvZW4gb3ZlciBkZSBwb3B1bGF0aWUgb3AgYmFzaXMgdmFuIGVlbiBzdGVla3Byb2VmLgoKLSBEZSBwcmlqcyBkaWUgd2UgaGllcnZvb3IgYmV0YWxlbiBpcyBvbnpla2VyaGVpZCEKCi0gV2Uga3VubmVuIG9wIGJhc2lzIHZhbiBlZW4gc3RlZWtwcm9lZiBub29pdCBhYnNvbHV1dCB6ZWtlciB6aWpuIHZhbiBvbnplIGNvbmNsdXNpZXMuCgotLS0KCi0gTWV0IGRhdGEga3VubmVuIHdlIG5pZXQgYmV3aWp6ZW4gZGF0IGVlbiBiZWhhbmRlbGluZyB3ZXJrdC4KCi0gRmFsc2lmaWNhdGllIHByaW5jaXBlIHZhbiBQb3BwZXI6IERhdGEga3VubmVuIGVua2VsIGVlbiBoeXBvdGhlc2Ugb2YgZWVuIHRoZW9yaWUgb250a3JhY2h0ZW4uCgotIE1ldCBzdGF0aXN0aWVrIGt1bm5lbiB3ZSBkdXMgbmlldCBhYW50b25lbiBkYXQgZGUgYmVoYW5kZWxpbmcgd2Vya3QuCgotIFN0YXRpc3RpZWsgemFsIG9ucyB3ZWwgdG9lbGF0ZW4gb20gaGV0IG9tZ2VrZWVyZGUgdGUgZmFsc2lmacOrcmVuOiBhbHMgd2UgdmVyb25kZXJzdGVsbGVuIGRhdCBlciBnZWVuIGVmZmVjdCB2YW4gZGUgYmVoYW5kZWxpbmcsIHNwcmVla3QgZGUgZGF0YSBpbiBkZSBzdGVla3Byb2VmIGRpdCB0ZWdlbj8KCi0gTWV0IHN0YXRpc3RpZWsga3VubmVuIHdlIGJlcmVrZW5lbiBob2Ugd2FhcnNjaGlqbmxpamsgaGV0IGlzIG9tIGluIGVlbiByYW5kb20gc3RlZWtwcm9lZiAod2FubmVlciB3ZSBoZXQgZXhwZXJpbWVudCBkdXMgb3BuaWV1dyB1aXQgem91ZGVuIHZvZXJlbikgZWVuIGdlbWlkZGVsZCB2ZXJzY2hpbCBpbiByZWxhdGlldmUgYWJ1bmRhbnRpZSB0ZSB6aWVuIHR1c3NlbiBwbGFjZWJvIGVuIHRyYW5zcGxhbnRhdGllZ3JvZXAgZGF0IG1pbnN0ZW5zIHpvIGdyb290IGlzIGFscyBpbiBvbnplIHN0ZWVrcHJvZWYgYWxzIGRlIGJlaGFuZGVsaW5nIGdlZW4gZWZmZWN0IHpvdSBoZWJiZW4uCgotIERpZSBrYW5zIHdvcmR0IGVlbiBwLXdhYXJkZSBnZW5vZW1kLgoKLSBBbHMgcCBoZWVsIGtsZWluIGlzLCBkYW4gaXMgaGV0IGhlZWwgb253YWFyc2NoaWpubGlqayBvbSBlZW4gZGVyZ2VsaWprIGVmZmVjdCB0ZSBvYnNlcnZlcmVuIGluIGVlbiBzdGVla3Byb2VmIGRvb3IgdG9ldmFsLgoKLSBwIHdvcmR0IG1lZXN0YWwgdmVyZ2VsZWtlbiBtZXQgNSUuIEFscyBlciBnZWVuIGVmZmVjdCBpcyB2YW4gZGUgYmVoYW5kZWxpbmcgZGFuIHRvbGVyZXJlbiA1JSB2YWxzIHBvc2l0aWV2ZSBjb25jbHVzaWVzLgoKLSBPbSBkZSBrYW5zIHAgdGUgYmVyZWtlbmVuIGlzIGhldCBub2RpZyBvbSBkZSBkYXRhIHRlIG1vZGVsbGVyZW4gbWV0IHN0YXRpc3Rpc2NoZSBtb2RlbGxlbi4KCi0tLQoKSW4gbGF0ZXJlIGhvb2Zkc3R1a2tlbiB6dWxsZW4gd2UgemllbiBkYXQgd2UgdC10ZXN0IGt1bm5lbiBnZWJydWlrZW4gb20gaGV0Z2VlbiB3ZSBvYnNlcnZlcmVuIGluIGRlIG1pY3JvYmlvbWUgZGF0YXNldCB0ZSB2ZXJhbGdlbWVuZW4gbmFhciBkZSBwb3B1bGF0aWUuCgpgYGB7cn0KdC50ZXN0KHJlbH50cnQsZGF0YT1hcCkKYGBgCgpDb25jbHVzaWU6CkdlbWlkZGVsZCBpcyBkZSByZWxhdGlldmUgYWJ1bmRhbnRpZSB2YW4gU3RhcGh5bG9jb2NjdXMgaW4gaGV0IG1pY3JvYmlvbWUgdmFuIHBlcnNvbmVuIG1ldCBlZW4gendlZXRnZXVyIGByIGZvcm1hdChhcFJlbFN1bSRtZWFuWzJdLWFwUmVsU3VtJG1lYW5bMV0sZGlnaXRzPTMpYCUgaG9nZXIgbmEgZGUgdHJhbnNwbGFudGllIGRhbiBuYSBkZSBwbGFjZWJvIGJlaGFuZGVsaW5nLgoKLS0tCgojIyBSYW5kb21pc2F0aWUKCi0gV2F0IHdvcmR0IHppam4gZGUgY29uc2VxdWVudGllcyB2YW4gaGV0IGdlYnJ1aWsgdmFuIGVlbiBzdGVla3Byb2VmIGVuIHZhbiByYW5kb21pc2F0aWU/CgotIFJhbmRvbWlzYXRpZSBpcyBzdGVyayBnZXJlbGF0ZWVyZCBtZXQgaGV0IGNvbmNlcHQgdmFuIGRlIHBvcHVsYXRpZSBlbiBzY29wZSB2YW4gZGUgc3R1ZGllLiAgCgotIERlIHNjb3BlIHZhbiBkZSBzdHVkaWUgbW9ldCBnb2VkIHdvcmRlbiBvbXNjaHJldmVuIHZvb3IgZGUgc3RhcnQgdmFuIGhldCBleHBlcmltZW50LgoKLSBPbWRhdCBkZSBzdGF0aXN0aXNjaGUgYW5hbHlzZSB2YWxpZGUgem91IHppam4gaXMgaGV0IG5vb2R6YWtlbGlqayBkYXQgZGUgc3ViamVjdGVuIHZvbGxlZGlnIHJhbmRvbSB3b3JkZW4gZ2V0cm9ra2VuIHVpdCBkZSBwb3B1bGF0aWUgbmFhciB3YWFyIHdlIG9uemUgY29uY2x1c2llcyB3ZW5zZW4gdGUgdmVyYWxnZW1lbmVuLgoKLSBWb2xsZWRpZyByYW5kb20gdHJla2tlbiB2YW4gZGUgcG9wdWxhdGllIGltcGxpY2VlcnQgZGF0OgoKICAgIC0gYWxsZSBzdWJqZWN0ZW4gdmFuIGRlIHBvcHVsYXRpZSBldmVudmVlbCBrYW5zIGhlYmJlbiBvbSBpbiBkZSBzdGVla3Byb2VmIHRlIHdvcmRlbiBvcGdlbm9tZW4KICAgIC0gZGUgc2VsZWN0aWUgdmFuIGVlbiBzdWJqZWN0IG9uYWZoYW5rZWxpamsgaXMgdmFuIGRlIGFuZGVyZSBzdWJqZWN0ZW4gaW4gZGUgc3RlZWtwcm9lZi4KCgotIERlIHN0ZWVrcHJvZWYgaXMgZGFuIHJlcHJlc2VudGF0aWVmIHZvb3IgZGUgcG9wdWxhdGllLCBtYWFyIGlzIG5vZyBzdGVlZHMgcmFuZG9tLgoKLSBXYXQgYmV0ZWtlbnQgZGl0PwoKLS0tCgojIENhc2Ugc3R1ZHk6IExlbmd0ZSB2YW4gbWFubmVuIGVuIHZyb3V3ZW4gXC0gVmFyaWFiaWxpdGVpdCB2YW4gc3RlZWtwcm9lZiB0b3Qgc3RlZWtwcm9lZgoKLSBPbSB0ZSBiZWdyaWpwZW4gZGF0IGVlbiBzdGVla3Byb2VmIHJhbmRvbSBpcyB6b3VkZW4gd2UgaGV0emVsZmRlIGV4cGVyaW1lbnQgdmVlbCBrZWVyIG1vZXRlbiBrdW5uZW4gaGVyaGFsZW4gKGByZXBlYXRlZCBzYW1wbGluZ2ApLgoKLSBEYW4gem91ZGVuIHdlIGluemljaHQga3VubmVuIGtyaWpnZW4gaG9lIGRlIGdlZ2V2ZW5zIHZlcmFuZGVyZW4gdmFuIHN0ZWVrcHJvZWYgdG90IHN0ZWVrcHJvZWYuCgotIE9tIGRpdCB0ZSBpbGx1c3RyZXJlbiB6dWxsZW4gd2UgZ2VicnVpayBtYWtlbiB2YW4gZWVuIGhlbGUgZ3JvdGUgc3R1ZGllLgoKLSBVaXQgZGllIHN0dWRpZSB6dWxsZW4gd2UgZGFuIGhlcmhhYWxkZWxpamsga2xlaW5lIHN0ZWVrcHJvZXZlbiB0cmVra2VuIG9tIHRlIGJlZ3JpanBlbiBob2UgZGUgZ2VnZXZlbnMgZW4gc3RhdGlzdGlla2VuIHZlcmFuZGVyZW4gdmFuIHN0ZWVrcHJvZWYgdG90IHN0ZWVrcHJvZWYuIE9mIG9tIG1ldCBhbmRlcmUgd29vcmRlbiBuYSB0ZSBnYWFuIHdhdCBkZSB2YXJpYWJpbGl0ZWl0IGlzIHR1c3NlbiBzdGVla3Byb2V2ZW4uCgotLS0KCk5hdGlvbmFsIEhlYWx0aCBBbmQgTnV0cml0aW9uIEV4YW1pbmF0aW9uIFN0dWR5IChOSEFORVMpCgogIC0gU2luZHMgMTk2MCB3b3JkZW4gZWxrIGphYXIgbWVuc2VuIHZhbiBhbGxlIGxlZWZ0aWpkZW4gZ2XDr250ZXJ2aWV3ZCBiaWogaGVuIHRodWlzLgogIC0gRXIgbWFha3Qgb29rIGVlbiBnZXpvbmRoZWlkc29uZGVyem9layBkZWVsIHVpdCB2YW4gZGUgc3R1ZHkgZGllIGluIGVlbiBtb2JpZWwgb25kZXJ6b2Vrc2NlbnRydW0gd29yZHQgYWZnZW5vbWVuLgogIC0gV2UgenVsbGVuIGRlemUgZ3JvdGUgc3R1ZGllIGdlYnJ1aWtlbiBvbSBhdCByYW5kb20gcGVyc29uZW4gdGUgc2VsZWN0ZXJlbiB2YW4gZGUgQW1lcmlrYWFuc2UgcG9wdWxhdGllLgogIC0gRGF0IHphbCBpbnppY2h0IGdldmVuIGluIGhvZSBkZSBnZWdldmVucyBlbiByZXN1bHRhdGVuIHZhbiBlZW4gYW5hbHlzZSB6dWxsZW4gdmFyacOrcmVuIHZhbiBzdGVla3Byb2VmIHRvdCBzdGVla3Byb2VmLgogIC0gRGUgZGF0YSB2YW4gZGV6ZSBzdHVkaWUgaXMgdGVydWcgdGUgdmluZGVuIGluIGhldCBSIHBha2tldCBgTkhBTkVTYAoKLS0tCgpgYGB7cn0KbGlicmFyeShOSEFORVMpCmhlYWQoTkhBTkVTKQpnbGltcHNlKE5IQU5FUykKYGBgCgotLS0KCiMjIERhdGEgZXhwbG9yYXRpZQoKCgpPbmRlcnpvZWtzdnJhYWc6IGhvZSB2ZXJzY2hpbHQgZGUgbGVuZ3RlIHZhbiB2b2x3YXNzZW4gbWFubmVuIGVuIHZyb3V3ZW4uCgoxLiBXZSBwaXBlbiBkZSBkYXRhc2V0IG5hYXIgZGUgZnVuY3Rpb24gYGZpbHRlcmAgb20gZGUgZGF0YSB0ZSBmaWx0ZXJlbiB2b2xnZW5zIGxlZWZ0aWpkLiAgCjIuIFdlIHBsb3R0ZW4gZGUgbGVuZ3RlIG1ldGluZ2VuLgogICAgLSBXZSBzZWxlY3RlcmVuIGRlIGRhdGEgZGF0YSBtZXQgaGV0IGNvbW1hbmRvIGBnZ3Bsb3QoYWVzKHg9bGVuZ3RlKSlgCiAgICAtIFdlIHZvZWdlbiBlZW4gaGlzdG9ncmFtIHRvZSBtZXQgaGV0IGNvbW1hbmRvIGBnZW9tX2hpc3RvZ3JhbSgpYAogICAgLSBXZSBtYWtlbiB0d2VlIHZlcnRpa2FsZSBwYW5lbHMgbWV0IGhldCBjb21tYW5kbyBgZmFjZXRfZ3JpZChHZW5kZXJ+LilgCiAgICAtIFdlIHZlcmFuZGVyZW4gaGV0IGxhYmVsIHZhbiBkZSB4LWFzIG1ldCBkZSBgeGxhYmAgZnVuY3RpZS4KCmBgYHtyfQpOSEFORVMlPiUgIAogIGZpbHRlcihBZ2UgPj0gMTggJiAhaXMubmEoSGVpZ2h0KSkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gSGVpZ2h0KSkrCiAgZ2VvbV9oaXN0b2dyYW0oKSArCiAgZmFjZXRfZ3JpZChHZW5kZXIgfiAuKSArCiAgeGxhYigiTGVuZ3RlIChjbSkiKQpgYGAKCi0tLQoKV2UgemllbiBkYXQgZGUgZGF0YSBudSBtaW4gb2YgbWVlciBzeW1tZXRyaXNjaCB2ZXJkZWVsZCB6aWpuIGVuIGVlbiBrbG9rdm9ybSBoZWJiZW4uICAKRGF0IHphbCBvbnMgdG9lIGxhdGVuIG9tIGRlIGRhdGEgdmVyZGVyIHNhbWVuIHRlIHZhdHRlbiBkb29yIGdlYnJ1aWsgdGUgbWFrZW4gdmFuIHR3ZWUgc3RhdGlzdGlla2VuOiBoZXQgZ2VtaWRkZWxkZSBlbiBkZSBzdGFuZGFhcmQgZGV2aWF0aWUgd2F0IGVlbiBtYWF0IGlzIHZvb3IgZGUgc3ByZWlkaW5nIHZhbiBkZSBnZWdldmVucyByb25kIGhldCBnZW1pZGRlbGRlLgoKLS0tCgpXZSBtYWtlbiBudSBlZW4gc3Vic2V0IHZhbiBkZSBkYXRhIGRpZSB3ZSB6dWxsZW4gZ2VicnVpa2VuIG9tIGFhbiB0ZSB0b25lbiBob2UgZGUgdmFyaWFiaWxpdGVpdCBpbiBrbGVpbmUgc3RlZWtwcm9ldmVuIGthbiB2YXJpw6tyZW4gdmFuIHN0ZWVrcHJvZWYgdG90IHN0ZWVrcHJvZWYuCgogIDEuIFdlIGZpbHRlcmVuIG9wIGxlZWZ0aWpkIGVuIHZlcndpamRlcmVuIG9udGJyZWtlbmRlbiBnZWdldmVucyAoTkEsIE5vdCBBdmFpbGFibGUpLgogIDIuIFdlIHNlbGVjdGVyZW4gZW5rZWwgaGV0IGdlc2xhY2h0IGVuIExlbmd0ZSB6b2RhdCBkZSBkYXRhc2V0IGdlZW4gb25ub2RpZ2UgdmFyaWFiZWxlbiBiZXZhdC4KCmBgYHtyfQpuaGFuZXNTdWIgPC0gTkhBTkVTICU+JQogIGZpbHRlcihBZ2UgPj0gMTggJiAhaXMubmEoSGVpZ2h0KSkgJT4lCiAgc2VsZWN0KGMoIkdlbmRlciIsIkhlaWdodCIpKQpgYGAKCi0tLQoKV2UgYmVyZWtlbmVuIGhldCBnZW1pZGRlbGRlIGVuIGRlIHN0YW5kYWFyZCBkZXZpYXRpZSB2b29yIGRlIGxlbmd0ZSB2b29yIG1hbm5lbiBlbiB2cm91d2VuIGluIGRlIGdyb3RlIGRhdGFzZXQuCldlIGdyb2VwZXJlbiBkZSBkYXRhIGhpZXJ2b29yIG9wIGJhc2lzIHZhbiBoZXQgZ2VzbGFjaHQgKHZhcmlhYmxlIEdlbmRlcikuCgoKYGBge3J9CgpIZWlnaHRTdW0gPC0gbmhhbmVzU3ViICU+JQogIGdyb3VwX2J5KEdlbmRlcikgJT4lCiAgc3VtbWFyaXplX2F0KCJIZWlnaHQiLAogICAgICAgICAgICAgICBsaXN0KG1lYW4gPSBtZWFuLAogICAgICAgICAgICAgICBzZCA9IHNkKQogICAgICAgICAgICAgICkKCmtuaXRyOjprYWJsZSgKICBIZWlnaHRTdW0gJT4lCiAgbXV0YXRlX2lmKGlzLm51bWVyaWMsIHJvdW5kLCBkaWdpdHM9MSkKICApCmBgYAoKLS0tCgojIyBFeHBlcmltZW50CgotIFN0ZWwgZGF0IHdlIGdlZW4gdG9lZ2FuZyBoZWJiZW4gdG90IGRlIG1ldGluZ2VuIHZhbiBkZSBOSEFORVMgc3R1ZGllLgoKLSBXZSB6b3VkZW4gZGFuIGVlbiBleHBlcmltZW50IG9wIG1vZXRlbiB6ZXR0ZW4gb20gbWV0aW5nZW4gYmlqIG1hbm5lbiBlbiB2cm91d2VuIHRlIGRvZW4uCgotIFZlcm9uZGVyc3RlbCBkYXQgd2UgYnVkZ2V0IGhlYmJlbiBvbSBtZXRpbmdlbiBiaWogNSBtYW5uZW4gZW4gNSB2cm91d2VuIHRlIGRvZW4uCgotIFdlIHpvdWRlbiBkYW4gNSBtYW5uZW4gZW4gNSB2cm91d2VuIGJvdmVuIGRlIDE4IGphYXIgYXQgcmFuZG9tIHNlbGVjdGVyZW4gdWl0IGRlIEFtZXJpa2FhbnNlIHBvcHVsYXRpZS4KCi0gV2Uga3VubmVuIGRpdCBleHBlcmltZW50IHNpbXVsZXJlbiBkb29yIDUgdnJvdXdlbiBlbiA1IG1hbm5lbiBhdCByYW5kb20gdGUgc2VsZWN0ZXJlbiB1aXQgZGUgTkhBTkVTIHN0dWRpZS4KCi0tLQoKYGBge3J9CnNldC5zZWVkKDEwMjMpCm5TYW1wIDwtIDUKZmVtIDwtIG5oYW5lc1N1YiAlPiUKICBmaWx0ZXIoR2VuZGVyPT0iZmVtYWxlIikgJT4lCiAgc2FtcGxlX24oc2l6ZT01KQoKbWFsIDwtIG5oYW5lc1N1YiAlPiUKICBmaWx0ZXIoR2VuZGVyPT0ibWFsZSIpICU+JQogIHNhbXBsZV9uKHNpemU9NSkKCnNhbXAxIDwtIHJiaW5kKGZlbSxtYWwpCgpzYW1wMQpgYGAKCi0tLQoKRGF0YSBFeHBsb3JhdGllCgpgYGB7cn0Kc2FtcDEgJT4lCiAgZ2dwbG90KGFlcyh4PUhlaWdodCkpICsKICBnZW9tX2hpc3RvZ3JhbSgpICsKICBmYWNldF9ncmlkKEdlbmRlcn4uKSArCiAgeGxhYigiTGVuZ3RlIChjbSkiKQoKSGVpZ2h0U3VtRXhwMSA8LSBzYW1wMSAlPiUKICBncm91cF9ieShHZW5kZXIpICU+JQogIHN1bW1hcml6ZV9hdCgiSGVpZ2h0IiwKICAgICAgICAgICAgICAgbGlzdChtZWFuID0gbWVhbiwKICAgICAgICAgICAgICAgICAgICAgIHNkID0gc2QpCiAgICAgICAgICAgICAgICAgICkKSGVpZ2h0U3VtRXhwMQpgYGAKCkhpc3RvZ3JhbSBpcyBuaWV0IHppbnZvbCBhbHMgd2UgbWFhciB6byB3ZWluaWcgZGF0YXB1bnRlbiBoZWJiZW4uCgotLS0KCgpCb3hwbG90IGlzIGJldGVyOgoKYGBge3IgZWNobz1GQUxTRX0Kc2FtcDEgJT4lCiAgZ2dwbG90KGFlcyh4ID0gR2VuZGVyLHkgPSBIZWlnaHQpKSArCiAgZ2VvbV9ib3hwbG90KG91dGxpZXIuc2hhcGUgPSBOQSkgKwogIGdlb21fcG9pbnQocG9zaXRpb24gPSAiaml0dGVyIikgKwogIGdlb21fcG9pbnQoCiAgICBhZXMoeCA9IDEsIHkgPSBIZWlnaHRTdW1FeHAxJG1lYW5bMV0pLAogICAgc2l6ZSA9IDMsCiAgICBwY2ggPSAxNywKICAgIGNvbG9yPSJkYXJrcmVkIikgKwogIGdlb21fcG9pbnQoCiAgICBhZXMoeCA9IDIsIHkgPSBIZWlnaHRTdW1FeHAxJG1lYW5bMl0pLAogICAgc2l6ZSA9IDMsCiAgICBwY2ggPSAxNywKICAgIGNvbG9yID0gImRhcmtyZWQiKSArCiAgeWxhYigiSGVpZ2h0IChjbSkiKQpgYGAKCi0tLQoKV2Ugdm9lcmVuIGhpZXIgb29rIGVlbiB0LXRlc3QgdWl0LgoKYGBge3J9CnQudGVzdChIZWlnaHR+R2VuZGVyLGRhdGE9c2FtcDEpCmBgYAoKSW4gaGV0IGV4cGVyaW1lbnQgemlqbiB2cm91d2VuIGdlbWlkZGVsZCBgciByb3VuZChhYnMoSGVpZ2h0U3VtRXhwMSRtZWFuWzFdLUhlaWdodFN1bUV4cDEkbWVhblsyXSksMilgIGNtIGByIGlmZWxzZShIZWlnaHRTdW1FeHAxJG1lYW5bMV0+SGVpZ2h0U3VtRXhwMSRtZWFuWzJdLCJncm90ZXIiLCJrbGVpbmVyIilgIGRhbiBtYW5uZW4uIEVuIGFscyB3ZSBlZW4gc3RhdGlzdGlzY2hlIHRlc3QgdWl0dm9lcmVuICh6aWUgaG9vZmRzdHVrIDU6IFN0YXRpc3Rpc2NoZSBiZXNsdWl0dm9ybWluZykga3VubmVuIHdlIGJlc2x1aXRlbiBkYXQgZGl0IHZlcnNjaGlsIHN0YXRpc3Rpc2NoIGByIGlmZWxzZSh0LnRlc3QoSGVpZ2h0fkdlbmRlcixzYW1wMSkkcC52YWx1ZSA8IDAuMDUsInNpZ25pZmljYW50IiwibmlldCBzaWduaWZpY2FudCIpYCBpcy4KCi0tLQoKIyMgSGVyaGFhbCBoZXQgZXhwZXJpbWVudAoKQWxzIHdlIGhldCBleHBlcmltZW50IGhlcmhhbGVuIHNlbGVjdGVyZW4gd2UgYW5kZXJlIG1lbnNlbiBlbiB2ZXJrcmlqZ2VuIHdlIGFuZGVyZSByZXN1bHRhdGVuLgoKCmBgYHtyfQpzZXQuc2VlZCgxMDI0KQpmZW0gPC0gbmhhbmVzU3ViICU+JQogIGZpbHRlcihHZW5kZXI9PSJmZW1hbGUiKSAlPiUKICBzYW1wbGVfbihzaXplPTUpCgptYWwgPC0gbmhhbmVzU3ViICU+JQogIGZpbHRlcihHZW5kZXI9PSJtYWxlIikgJT4lCiAgc2FtcGxlX24oc2l6ZT01KQoKc2FtcDIgPC0gcmJpbmQoZmVtLG1hbCkKCkhlaWdodFN1bUV4cDIgPC0gc2FtcDIgJT4lCiAgZ3JvdXBfYnkoR2VuZGVyKSAlPiUKICBzdW1tYXJpemVfYXQoIkhlaWdodCIsCiAgICAgICAgICAgICAgIGxpc3QobWVhbj1tZWFuLAogICAgICAgICAgICAgICAgICAgIHNkPXNkKQogICAgICAgICAgICAgICkKSGVpZ2h0U3VtRXhwMgoKc2FtcDIgJT4lCiAgZ2dwbG90KGFlcyh4ID0gR2VuZGVyLHkgPSBIZWlnaHQpKSArCiAgZ2VvbV9ib3hwbG90KG91dGxpZXIuc2hhcGUgPSBOQSkgKwogIGdlb21fcG9pbnQocG9zaXRpb24gPSAiaml0dGVyIikgKwogIGdlb21fcG9pbnQoCiAgICBhZXMoeCA9IDEsIHkgPSBIZWlnaHRTdW1FeHAyJG1lYW5bMV0pLAogICAgc2l6ZSA9IDMsCiAgICBwY2ggPSAxNywKICAgIGNvbG9yPSJkYXJrcmVkIikgKwogIGdlb21fcG9pbnQoCiAgICBhZXMoeCA9IDIsIHkgPSBIZWlnaHRTdW1FeHAyJG1lYW5bMl0pLAogICAgc2l6ZSA9IDMsCiAgICBwY2ggPSAxNywKICAgIGNvbG9yID0gImRhcmtyZWQiKSArCiAgeWxhYigiSGVpZ2h0IChjbSkiKQoKdC50ZXN0KEhlaWdodCB+IEdlbmRlciwgZGF0YT1zYW1wMikKYGBgCgoKSW4gZGUgbmlldXdlIHN0ZWVrcHJvZWYgemlqbiB2cm91d2VuIGdlbWlkZGVsZCBgciByb3VuZChhYnMoSGVpZ2h0U3VtRXhwMiRtZWFuWzFdLUhlaWdodFN1bUV4cDIkbWVhblsyXSksMilgIGNtIGByIGlmZWxzZShIZWlnaHRTdW1FeHAyJG1lYW5bMV0+SGVpZ2h0U3VtRXhwMiRtZWFuWzJdLCJncm90ZXIiLCJrbGVpbmVyIilgIGRhbiBtYW5uZW4uIEVuIGRpdCB2ZXJzY2hpbCBpcyBzdGF0aXN0aXNjaCBgciBpZmVsc2UodC50ZXN0KEhlaWdodH5HZW5kZXIsc2FtcDIsdmFyLmVxdWFsPVRSVUUpJHAudmFsdWUgPCAwLjA1LCJzaWduaWZpY2FudCIsIm5pZXQgc2lnbmlmaWNhbnQiKWAKCgotLS0KCiMjIEhlcmhhYWwgaGV0IGV4cGVyaW1lbnQgb3BuaWV1dwoKYGBge3J9CnNlZWQgPC0gODg2MDUKc2V0LnNlZWQoc2VlZCkKZmVtIDwtIG5oYW5lc1N1YiAlPiUKICBmaWx0ZXIoR2VuZGVyPT0iZmVtYWxlIikgJT4lCiAgc2FtcGxlX24oc2l6ZT01KQoKbWFsIDwtIG5oYW5lc1N1YiAlPiUKICBmaWx0ZXIoR2VuZGVyPT0ibWFsZSIpICU+JQogIHNhbXBsZV9uKHNpemU9NSkKCnNhbXAzIDwtIHJiaW5kKGZlbSxtYWwpCgpIZWlnaHRTdW1FeHAzIDwtIHNhbXAzICU+JQogIGdyb3VwX2J5KEdlbmRlcikgJT4lCiAgc3VtbWFyaXplX2F0KCJIZWlnaHQiLAogICAgICAgICAgICAgICBsaXN0KG1lYW49bWVhbiwKICAgICAgICAgICAgICAgICAgICBzZD1zZCkKICAgICAgICAgICAgICApCkhlaWdodFN1bUV4cDMKCnNhbXAzICU+JQogIGdncGxvdChhZXMoeCA9IEdlbmRlcix5ID0gSGVpZ2h0KSkgKwogIGdlb21fYm94cGxvdChvdXRsaWVyLnNoYXBlID0gTkEpICsKICBnZW9tX3BvaW50KHBvc2l0aW9uID0gImppdHRlciIpICsKICBnZW9tX3BvaW50KAogICAgYWVzKHggPSAxLCB5ID0gSGVpZ2h0U3VtRXhwMyRtZWFuWzFdKSwKICAgIHNpemUgPSAzLAogICAgcGNoID0gMTcsCiAgICBjb2xvcj0iZGFya3JlZCIpICsKICBnZW9tX3BvaW50KAogICAgYWVzKHggPSAyLCB5ID0gSGVpZ2h0U3VtRXhwMyRtZWFuWzJdKSwKICAgIHNpemUgPSAzLAogICAgcGNoID0gMTcsCiAgICBjb2xvciA9ICJkYXJrcmVkIikgKwogIHlsYWIoIkhlaWdodCAoY20pIikKCnQudGVzdChIZWlnaHQgfiBHZW5kZXIsIGRhdGE9c2FtcDMpCmBgYAoKSW4gZGUgbmlldXdlIHN0ZWVrcHJvZWYgemlqbiB2cm91d2VuIGdlbWlkZGVsZCBgciByb3VuZChhYnMoSGVpZ2h0U3VtRXhwMyRtZWFuWzFdLUhlaWdodFN1bUV4cDMkbWVhblsyXSksMilgIGNtIGByIGlmZWxzZShIZWlnaHRTdW1FeHAzJG1lYW5bMV0+SGVpZ2h0U3VtRXhwMyRtZWFuWzJdLCJncm90ZXIiLCJrbGVpbmVyIilgIGRhbiBtYW5uZW4uIEVuIGRpdCB2ZXJzY2hpbCBpcyBzdGF0aXN0aXNjaCBgciBpZmVsc2UodC50ZXN0KEhlaWdodH5HZW5kZXIsc2FtcDMsdmFyLmVxdWFsPVRSVUUpJHAudmFsdWUgPCAwLjA1LCJzaWduaWZpY2FudCIsIm5pZXQgc2lnbmlmaWNhbnQiKWAKCi0tLQoKIyMgU2FtZW52YXR0aW5nCgotIFdlIHRyb2trZW4gYXQgcmFuZG9tIGFuZGVyZSBwcm9lZnBlcnNvbmVuIGluIGVsa2Ugc3RlZWtwcm9lZgoKLSBIaWVyZG9vciB2ZXJzY2hpbGxlbiBsZW5ndGVtZXRpbmdlbiB2YW4gc3RlZWtwcm9lZiB0b3Qgc3RlZWtwcm9lZi4KCi0gRHVzIG9vayBkZSBnZXNjaGF0dGUgZ2VtaWRkZWxkZXMgZW4gc3RhbmRhYXJkIGRldmlhdGllcy4KCi0gQmlqZ2V2b2xnIHppam4gb256ZSBjb25jbHVzaWVzIG9vayBvbnpla2VyIGVuIGt1bm5lbiBkZXplIHdpanppZ2VuIHZhbiBzdGVla3Byb2VmIHRvdCBzdGVla3Byb2VmLgoKLSBWb29yIGhldCBsZW5ndGUgdm9vcmJlZWxkIHppam4gc3RlZWtwcm9ldmVuIHdhYXJiaWogaGV0IGVmZmVjdCB0ZWdlbmdlc3RlbGQgaXMgYWFuIGRhdCBpbiBkZSBwb3B1bGF0aWUgZW4gd2FhcmJpaiB3ZSBiZXNsdWl0ZW4gZGF0IGhldCB2ZXJzY2hpbCBzaWduaWZpY2FudCBlY2h0ZXIgemVsZHphYW0uCgokXHJpZ2h0YXJyb3ckIE1ldCBzdGF0aXN0aWVrIGNvbnRyb2xlcmVuIHdlIGRlIGthbnMgb3AgaGV0IHRyZWtrZW4gZm91dGUgY29uY2x1c2llcy4KCiMjIENvbnRyb2xlIHZhbiBmb3V0ZW4KCkhvZSBjb250cm9sZWVydCBzdGF0aXN0aWVrIGRlIGthbnMgb3AgaGV0IHRyZWtrZW4gdmFuIGZvdXRlIGNvbmNsdXNpZXM/CgotIEluIG9uZGVyc3RhYW5kZSBjb2RlIHRyZWtrZW4gd2UgMTAwMDAgaGVyaGFhbGRlIHN0ZWVrcHJvZXZlbiB2YW4gNSB2cm91d2VuIGVuIDUgbWFubmVuIHVpdCBkZSBOSEFORVMgc3R1ZGllLgoKYGBge3J9CnNldC5zZWVkKDE1MTUyKQojIEFhbnRhbCBzaW11bGF0aWVzIGVuIHN0ZWVrcHJvZWZncm9vdHRlIHBlciBncm9lcApuU2ltIDwtIDEwMDAwCm5TYW1wIDwtIDUKCiMgV2UgZmlsdGVyZW4gZGUgZGF0YSB2b29yYWYgem9kYXQgd2UgZGl0IG5pZXQgdGVsa2VucyBvcG5pZXV3IGhvZXZlbiB0ZSBkb2VuCmZlbSA8LSBuaGFuZXNTdWIgJT4lCiAgZmlsdGVyKEdlbmRlciA9PSAiZmVtYWxlIikKCm1hbCA8LSBuaGFuZXNTdWIgJT4lCiAgZmlsdGVyKEdlbmRlciA9PSAibWFsZSIpCgojIFNpbXVsYXRpZSBzdHVkaWUKIyBPbSBzbmVsbGUgZnVuY3RpZXMgdGUga3VubmVuIGdlYnJ1aWtlbiBuZW1lbiB3ZSBlZXJzdCBuU2ltIHN0ZWVrcHJvZXZlbiBlbiBiZXJla2VuZW4gd2UgZGFhcm5hIGFsbGVzLgoKZmVtU2FtcHMgPC0gbWFsU2FtcHMgPC1tYXRyaXgoTkEsIG5yb3c9blNhbXAsIG5jb2w9blNpbSkKZm9yIChpIGluIDE6blNpbSkKewogIGZlbVNhbXBzWyxpXSA8LSBzYW1wbGUoZmVtJEhlaWdodCwgblNhbXApCiAgbWFsU2FtcHNbLGldIDwtIHNhbXBsZShtYWwkSGVpZ2h0LCBuU2FtcCkKfQoKcmVzIDwtIGRhdGEuZnJhbWUoCiAgdmVyc2NoaWw9Y29sTWVhbnMoZmVtU2FtcHMpIC0gY29sTWVhbnMobWFsU2FtcHMpLAogIFJmYXN0Ojp0dGVzdHMoZmVtU2FtcHMsIG1hbFNhbXBzKQogICkKCnN1bShyZXMkcHZhbHVlIDwgMC4wNSAmIHJlcyR2ZXJzY2hpbCA8IDApCnN1bShyZXMkcHZhbHVlID49IDAuMDUpCnN1bShyZXMkcHZhbHVlIDwgMC4wNSAmIHJlcyR2ZXJzY2hpbD4wKQoKcmVzICU+JQogIGdncGxvdChhZXMoeD12ZXJzY2hpbCx5PS1sb2cxMChwdmFsdWUpLGNvbG9yPXB2YWx1ZSA8IDAuMDUpKSArCiAgZ2VvbV9wb2ludCgpICsKICB4bGFiKCJHZW1pZGRlbGQgVmVyc2NoaWwgKGNtKSIpICsKICB5bGFiKCJTdGF0aXN0aXNjaGUgU2lnbmlmaWNhbnRpZSAoLWxvZzEwIHApIikKCnJlcyAlPiUKICBnZ3Bsb3QoYWVzKHkgPSB2ZXJzY2hpbCkpICsKICBnZW9tX2JveHBsb3QoKSArCiAgeWxhYigiR2VtaWRkZWxkIFZlcnNjaGlsIChjbSkiKQogIHhsYWIoIiIpCmBgYAoKT3AgYmFzaXMgdmFuIDEwMDAwIHN0ZWVrcHJvZXZlbiB2YW4gNSBtYW5uZW4gZW4gNSB2cm91d2VuIHphZ2VuIHdlIGRhdCBpbiBgciBzdW0ocmVzJHB2YWx1ZTwwLjA1JnJlcyR2ZXJzY2hpbDwwKWAgc3RlZWtwcm9ldmVuIHZyb3V3ZW4gZ2VtaWRkZWxkIHNpZ25pZmljYW50IGtsZWluZXIgemlqbiBkYW4gbWFubmVuLiBJbiBgciBzdW0ocmVzJHB2YWx1ZT49MC4wNSlgIHN0ZWVrcHJvZXZlbiBiZXNsdWl0ZW4gd2UgZGF0IHZyb3V3ZW4gZW4gbWFubmVuIGdlbWlkZGVsZCBuaWV0IHNpZ25pZmljYW50IHZlcnNjaGlsbGVuIGluIGxlbmd0ZS4gRW4gaW4gYHIgc3VtKHJlcyRwdmFsdWU8MC4wNSZyZXMkdmVyc2NoaWw+MClgIGJlc2x1aXRlbiB3ZSBkYXQgdnJvdXdlbiBnZW1pZGRlbGQgc2lnbmlmaWNhbnQgZ3JvdGVyIHppam4gZGFuIG1hbm5lbi4KCi0gRGUgc3RlZWtwcm9lZiBkaWUgd2UgdG9vbmRlbiB3YWFydWl0IHdlIHpvdWRlbiBiZXNsdWl0ZW4gZGF0IHZyb3V3ZW4gc2lnbmlmaWNhbnQgZ3JvdGVyIHppam4gZGFuIG1hbm5lbiBpcyBoZWVsIG9ud2FhcnNjaGlqbmxpamsuIEVyIG1vZXN0ZW4gYHIgcGFzdGUoc2VlZClgIHN0ZWVrcHJvZXZlbiB3b3JkZW4gZ2V0cm9ra2VuIG9tIGRlemUgZXh0cmVtZSBzdGVla3Byb2VmIHRlIHZpbmRlbi4KCkhldCBmZWl0IGRhdCB3ZSBpbiB2ZWVsIHN0ZWVrcHJvZXZlbiByZXN1bHRhdGVuIHZpbmRlbiBkaWUgc3RhdGlzdGlzY2ggbmlldCBzaWduaWZpY2FudCB6aWpuIGtvbXQgb21kYXQgZGUgc3RhdGlzdGlzY2hlIHRvZXRzIGVlbiB0ZSBsYWdlIGtyYWNodCBoZWVmdCBvbSBoZXQgdmVyc2NoaWwgdGUgZGV0ZWN0ZXJlbiB3YW5uZWVyIGVyIG1hYXIgNSBvYnNlcnZhdGllcyB6aWpuIHBlciBncm9lcC4KCi0tLQoKIyMjIEdyb3RlcmUgc3RlZWtwcm9lZj8KCldhdCBnZWJldXJ0IGVyIGFscyB3ZSBkZSBzdGVla3Byb2VmIHZlcmhvZ2VuIG5hYXIgNTAgb2JzZXJ2YXRpZXMgcGVyIGdyb2VwPwoKCmBgYHtyfQpzZXQuc2VlZCgxMTE0NSkKIyBBYW50YWwgc2ltdWxhdGllcyBlbiBzdGVla3Byb2VmZ3Jvb3R0ZSBwZXIgZ3JvZXAKblNpbSA8LSAxMDAwMApuU2FtcCA8LSA1MAoKIyBXZSBmaWx0ZXJlbiBkZSBkYXRhIHZvb3JhZiB6b2RhdCB3ZSBkaXQgbmlldCB0ZWxrZW5zIG9wbmlldXcgaG9ldmVuIHRlIGRvZW4KZmVtIDwtIG5oYW5lc1N1YiAlPiUKICBmaWx0ZXIoR2VuZGVyID09ICJmZW1hbGUiKQoKbWFsIDwtIG5oYW5lc1N1YiAlPiUKICBmaWx0ZXIoR2VuZGVyID09ICJtYWxlIikKCiMgU2ltdWxhdGllIHN0dWRpZQojIE9tIHNuZWxsZSBmdW5jdGllcyB0ZSBrdW5uZW4gZ2VicnVpa2VuIG5lbWVuIHdlIGVlcnN0IG5TaW0gc3RlZWtwcm9ldmVuIGVuIGJlcmVrZW5lbiB3ZSBkYWFybmEgYWxsZXMuCgpmZW1TYW1wcyA8LSBtYWxTYW1wcyA8LSBtYXRyaXgoTkEsIG5yb3cgPSBuU2FtcCwgbmNvbCA9IG5TaW0pCmZvciAoaSBpbiAxOm5TaW0pCnsKICBmZW1TYW1wc1ssaV0gPC0gc2FtcGxlKGZlbSRIZWlnaHQsIG5TYW1wKQogIG1hbFNhbXBzWyxpXSA8LSBzYW1wbGUobWFsJEhlaWdodCwgblNhbXApCn0KCnJlcyA8LSBkYXRhLmZyYW1lKAogIHZlcnNjaGlsID0gY29sTWVhbnMoZmVtU2FtcHMpIC0gY29sTWVhbnMobWFsU2FtcHMpLAogIFJmYXN0Ojp0dGVzdHMoZmVtU2FtcHMsIG1hbFNhbXBzKQogICkKCnN1bShyZXMkcHZhbHVlIDwgMC4wNSAmIHJlcyR2ZXJzY2hpbCA8IDApCnN1bShyZXMkcHZhbHVlID49IDAuMDUpCnN1bShyZXMkcHZhbHVlIDwgMC4wNSAmIHJlcyR2ZXJzY2hpbCA+IDApCgpyZXMgJT4lCiAgZ2dwbG90KGFlcyh4PXZlcnNjaGlsLHk9LWxvZzEwKHB2YWx1ZSksY29sb3I9cHZhbHVlPDAuMDUpKSArCiAgZ2VvbV9wb2ludCgpICsKICB4bGFiKCJHZW1pZGRlbGQgVmVyc2NoaWwgKGNtKSIpICsKICB5bGFiKCJTdGF0aXN0aXNjaGUgU2lnbmlmaWNhbnRpZSAoLWxvZzEwIHApIikKCnJlcyAlPiUKICBnZ3Bsb3QoYWVzKHk9dmVyc2NoaWwpKSArCiAgZ2VvbV9ib3hwbG90KCkgKwogIHlsYWIoIkdlbWlkZGVsZCBWZXJzY2hpbCAoY20pIikKICB4bGFiKCIiKQpgYGAKCi0gV2UgemllbiBkdXMgZGF0IHdlIGRlIGthbnMgb20gZWVuIHZlcnNjaGlsIHRlIHZpbmRlbiBhbHMgZXIgaW4gd2Vya2VsaWpraGVpZCBlZW4gdmVyc2NoaWwgaXMgaW4gZGUgcG9wdWxhdGllIGt1bm5lbiBiZcOvbnZsb2VkZW4gaW4gZGUgZGVzaWduIGZhc2U6IGFhbiBkZSBoYW5kIHZhbiBkZSBzdGVla3Byb2VmZ3Jvb3R0ZS4KCi0gSG9lIG1lZXIgZ2VnZXZlbnMgaG9lIG1ha2tlbGlqa2VyIHdlIGhldCB3ZXJrZWxpamsgdmVyc2NoaWwgb3BwaWtrZW4gaW4gZGUgc3RlZWtwcm9lZi4KCgojIyMgQ29udHJvbGUgdmFuIHZhbHMgcG9zaXRpZXZlbgoKV2F0IGdlYmV1cnQgZXIgYWxzIGVyIGdlZW4gdmVyc2NoaWwgaXMgdHVzc2VuIGJlaWRlIGdyb2VwZW4/CgotIFdlIG1vZXRlbiBoaWVydm9vciBleHBlcmltZW50ZW4gc2ltdWxlcmVuIHdhYXJiaWogZGUgZ3JvZXBlbiBnZWxpamsgemlqbi4gIAoKLSBIaWVydm9vciB6dWxsZW4gd2UgdHdlZSBncm9lcGVuIHZlcmdlbGlqa2VuIHdhYXJ2b29yIGRlIGxlbmd0ZSBnZW1pZGRlbGQgbmlldCB2ZXJzY2hpbGxlbmQgaXMuCgotIERhdCBrdW5uZW4gd2UgZG9lbiBkb29yIGVlbiBzdGVla3Byb2VmIHRlIHRyZWtrZW4gd2FhcmJpaiB3ZSB2b29yIGJlaWRlIGdyb2VwZW4gYXQgcmFuZG9tIHN1YmplY3RlbiB0cmVra2VuIHVpdCBkZSBzdWJzZXQgdmFuIHZyb3V3ZW4gaW4gZGUgTkhBTkVTIHN0dWRpZS4KCi0gV2UgZG9lbiBkaXQgb3BuaWV1dyB2b29yIGVlbiBzdGVla3Byb2VmIG1ldCA1IHN1YmplY3RlbiBwZXIgZ3JvZXAKCgpgYGB7cn0Kc2V0LnNlZWQoMTMyNDUpCiMgQWFudGFsIHNpbXVsYXRpZXMgZW4gc3RlZWtwcm9lZmdyb290dGUgcGVyIGdyb2VwCm5TaW0gPC0gMTAwMDAKblNhbXAgPC0gNQoKIyBXZSBmaWx0ZXJlbiBkZSBkYXRhIHZvb3JhZiB6b2RhdCB3ZSBkaXQgbmlldCB0ZWxrZW5zIG9wbmlldXcgaG9ldmVuIHRlIGRvZW4KZmVtIDwtIG5oYW5lc1N1YiAlPiUKICBmaWx0ZXIoR2VuZGVyID09ICJmZW1hbGUiKQoKIyBTaW11bGF0aWUgc3R1ZGllCiMgT20gc25lbGxlIGZ1bmN0aWVzIHRlIGt1bm5lbiBnZWJydWlrZW4gbmVtZW4gd2UgZWVyc3QgblNpbSBzdGVla3Byb2V2ZW4gZW4gYmVyZWtlbmVuIHdlIGRhYXJuYSBhbGxlcy4KCmZlbVNhbXBzIDwtIGZlbVNhbXBzMiA8LW1hdHJpeChOQSwgbnJvdz1uU2FtcCwgbmNvbD1uU2ltKQpmb3IgKGkgaW4gMTpuU2ltKQp7CiAgZmVtU2FtcHNbLGldIDwtIHNhbXBsZShmZW0kSGVpZ2h0LCBuU2FtcCkKICBmZW1TYW1wczJbLGldIDwtIHNhbXBsZShmZW0kSGVpZ2h0LCBuU2FtcCkKfQoKcmVzIDwtIGRhdGEuZnJhbWUoCiAgdmVyc2NoaWw9Y29sTWVhbnMoZmVtU2FtcHMpIC0gY29sTWVhbnMoZmVtU2FtcHMyKSwKICBSZmFzdDo6dHRlc3RzKGZlbVNhbXBzLCBmZW1TYW1wczIpCiAgKQoKc3VtKHJlcyRwdmFsdWUgPCAwLjA1ICYgcmVzJHZlcnNjaGlsIDwgMCkKc3VtKHJlcyRwdmFsdWUgPj0gMC4wNSkKc3VtKHJlcyRwdmFsdWUgPCAwLjA1ICYgcmVzJHZlcnNjaGlsPjApCgpyZXMgJT4lCiAgZ2dwbG90KGFlcyh4PXZlcnNjaGlsLHk9LWxvZzEwKHB2YWx1ZSksY29sb3I9cHZhbHVlIDwgMC4wNSkpICsKICBnZW9tX3BvaW50KCkgKwogIHhsYWIoIkdlbWlkZGVsZCBWZXJzY2hpbCAoY20pIikgKwogIHlsYWIoIlN0YXRpc3Rpc2NoZSBTaWduaWZpY2FudGllICgtbG9nMTAgcCkiKQoKcmVzICU+JQogIGdncGxvdChhZXMoeSA9IHZlcnNjaGlsKSkgKwogIGdlb21fYm94cGxvdCgpICsKICB5bGFiKCJHZW1pZGRlbGQgVmVyc2NoaWwgKGNtKSIpCiAgeGxhYigiIikKYGBgCgpPcCBiYXNpcyB2YW4gMTAwMDAgc3RlZWtwcm9ldmVuIHppZW4gd2UgZGF0IHdlIGluIGByIHN1bShyZXMkcHZhbHVlPDAuMDUpYCBzdGVla3Byb2V2ZW4gdGVuIG9ucmVjaHRlIGJlc2x1aXRlbiBkYXQgZXIgZWVuIHZlcnNjaGlsIGlzIGluIGdlbWlkZGVsZGUgbGVuZ3RlIHR1c3NlbiB0d2VlIGdyb2VwZW4gdnJvdXdlbi4KCk1ldCBkZSBzdGF0aXN0aXNjaGUgYW5hbHlzZSBjb250cm9sZXJlbiB3ZSBkdXMgaGV0IGFhbnRhbCB2YWxzIHBvc2l0aWV2ZSByZXN1bHRhdGVuIGNvcnJlY3Qgb3AgNSUuCgoqV2F0IGdlYmV1cnQgZXIgYWxzIHdlIGhldCBhYW50YWwgb2JzZXJ2YXRpZXMgdmVyaG9nZW4/KgoKV2Ugc2ltdWxlcmVuIG9wbmlldXcgZXhwZXJpbWVudGVuIG1ldCA1MCBzdWJqZWN0ZW4gcGVyIGdyb2VwIG1hYXIgd2UgdHJla2tlbiBkZSBzdWJqZWN0ZW4gb3BuaWV1dyB0ZWxrZW5zIHVpdCBkZSBwb3B1bGF0aWUgdmFuIHZyb3V3ZW4uCgpgYGB7cn0Kc2V0LnNlZWQoMTM0NSkKIyBBYW50YWwgc2ltdWxhdGllcyBlbiBzdGVla3Byb2VmZ3Jvb3R0ZSBwZXIgZ3JvZXAKblNpbSA8LSAxMDAwMApuU2FtcCA8LSA1MAoKIyBXZSBmaWx0ZXJlbiBkZSBkYXRhIHZvb3JhZiB6b2RhdCB3ZSBkaXQgbmlldCB0ZWxrZW5zIG9wbmlldXcgaG9ldmVuIHRlIGRvZW4KZmVtIDwtIG5oYW5lc1N1YiAlPiUKICBmaWx0ZXIoR2VuZGVyID09ICJmZW1hbGUiKQoKIyBTaW11bGF0aWUgc3R1ZGllCiMgT20gc25lbGxlIGZ1bmN0aWVzIHRlIGt1bm5lbiBnZWJydWlrZW4gbmVtZW4gd2UgZWVyc3QgblNpbSBzdGVla3Byb2V2ZW4gZW4gYmVyZWtlbmVuIHdlIGRhYXJuYSBhbGxlcy4KCmZlbVNhbXBzIDwtIGZlbVNhbXBzMiA8LW1hdHJpeChOQSwgbnJvdz1uU2FtcCwgbmNvbD1uU2ltKQpmb3IgKGkgaW4gMTpuU2ltKQp7CiAgZmVtU2FtcHNbLGldIDwtIHNhbXBsZShmZW0kSGVpZ2h0LCBuU2FtcCkKICBmZW1TYW1wczJbLGldIDwtIHNhbXBsZShmZW0kSGVpZ2h0LCBuU2FtcCkKfQoKcmVzIDwtIGRhdGEuZnJhbWUoCiAgdmVyc2NoaWw9Y29sTWVhbnMoZmVtU2FtcHMpIC0gY29sTWVhbnMoZmVtU2FtcHMyKSwKICBSZmFzdDo6dHRlc3RzKGZlbVNhbXBzLCBmZW1TYW1wczIpCiAgKQoKc3VtKHJlcyRwdmFsdWUgPCAwLjA1ICYgcmVzJHZlcnNjaGlsIDwgMCkKc3VtKHJlcyRwdmFsdWUgPj0gMC4wNSkKc3VtKHJlcyRwdmFsdWUgPCAwLjA1ICYgcmVzJHZlcnNjaGlsPjApCgpyZXMgJT4lCiAgZ2dwbG90KGFlcyh4PXZlcnNjaGlsLHk9LWxvZzEwKHB2YWx1ZSksY29sb3I9cHZhbHVlIDwgMC4wNSkpICsKICBnZW9tX3BvaW50KCkgKwogIHhsYWIoIkdlbWlkZGVsZCBWZXJzY2hpbCAoY20pIikgKwogIHlsYWIoIlN0YXRpc3Rpc2NoZSBTaWduaWZpY2FudGllICgtbG9nMTAgcCkiKQoKcmVzICU+JQogIGdncGxvdChhZXMoeSA9IHZlcnNjaGlsKSkgKwogIGdlb21fYm94cGxvdCgpICsKICB5bGFiKCJHZW1pZGRlbGQgVmVyc2NoaWwgKGNtKSIpCiAgeGxhYigiIikKYGBgCgoKT3AgYmFzaXMgdmFuIDEwMDAwIHN0ZWVrcHJvZXZlbiB6aWVuIHdlIGRhdCB3ZSBpbiBgciBzdW0ocmVzJHB2YWx1ZTwwLjA1KWAgc3RlZWtwcm9ldmVuIHRlbiBvbnJlY2h0ZSBiZXNsdWl0ZW4gZGF0IGVyIGVlbiB2ZXJzY2hpbCBpcyBpbiBnZW1pZGRlbGRlIGxlbmd0ZSB0dXNzZW4gdHdlZSBncm9lcGVuIHZyb3V3ZW4uCgpNZXQgZGUgc3RhdGlzdGlzY2hlIGFuYWx5c2UgY29udHJvbGVyZW4gd2UgZHVzIG9vayBiaWogaGV0IG5lbWVuIHZhbiBlZW4gZ3JvdGUgc3RlZWtwcm9lZiBoZXQgYWFudGFsIHZhbHMgcG9zaXRpZXZlIHJlc3VsdGF0ZW4gY29ycmVjdCBvcCA1JSAoVmFscyBwb3NpdGllZjogT3AgYmFzaXMgdmFuIGRlIHN0ZWVrcHJvZWYgYmVzbHVpdGVuIGRhdCBlciBnZW1pZGRlbGQgZWVuIHZlcnNjaGlsIGlzIGluIGxlbmd0ZSB0dXNzZW4gYmVpZGUgZ3JvZXBlbiB0ZXJ3aWpsIGVyIGluIHdlcmtlbGlqa2hlaWQgZ2VlbiB2ZXJzY2hpbCBpcyBpbiBkZSBwb3B1bGF0aWUuKQoKIyMjIENvbmNsdXNpZXMKCiAtIERlIHN0YXRpc3Rpc2NoZSBhbmFseXNlIGNvbnRyb2xlZXJ0IHN0ZWVkcyBkZSBrYW5zIG9wIGhldCBuZW1lbiB2YW4gZWVuIHZhbHMgcG9zaXRpZXZlIGNvbmNsdXNpZS4KCiAtIERlIHN0YXRpc3Rpc2NoZSBhbmFseXNpcyBjb250cm9sZWVydCBkZSBrYW5zIG9wIGhldCBuZW1lbiB2YW4gZWVuIHZhbHMgbmVnYXRpZXZlIGNvbmNsdXNpZXMgbmlldCwgbWFhciBpbiBkZSBkZXNpZ24gZmFzZSBrdW5uZW4gd2UgZGV6ZSBrYW5zIGJlw69udmxvZWRlbiBvbmRlcm1lZXIgZC5tLnYuIGRlIHN0ZWVrcHJvZWZncm9vdHRlLgoKLS0tCgojQ2FzZSBzdHVkeTogU2FsayB2YWNjaW4KCi0gSW4gMTkxNiwgYnJhayBkZSBlZXJzdGUgZ3JvdGUgcG9saW8gZXBpZGVtaWUgdWl0IGluIGRlIFVTQS4KLSBCZWdpbiBkZSBqYXJlbiA1MCBvbnR3aWtrZWxkZSBKb2huIFNhbGsgZWVuIHZhY2NpbiBtZXQgYmVsb3ZlbmRlIHJlc3VsdGF0ZW4gaW4gaGV0IGxhYi4KLSBJbiAxOTU0LCBoZWVmdCBkZSBOYXRpb25hbCBGb3VuZGF0aW9uCmZvciBJbmZhbnRpbGUgUGFyYWx5c2lzIChORklQKSBlZW4gZ3JvdGUgc3R1ZGllIG9wZ2V6ZXQgb20gZGUgZWZmZWN0aXZpdGVpdCB2YW4gaGV0IFNhbGsgdmFjY2luIG5hIHRlIGdhYW4uCi0gVmVyb25kZXJzdGVsIGRhdCBkZSBORklQIGluIDE5NTQgZWVuIGdyb290IGFhbnRhbCBraW5kZXJlbiB6b3UgaGViYmVuIGdldmFjY2luZWVyZCwgd2F0IHpvdWRlbiB6ZSBkYW4ga3VubmVuIGJlc2x1aXRlbiBhbHMgZGUgcG9saW8gaW5jaWRlbnRpZSBpbiAxOTU0IGxhZ2VyIHdhcyBkYW4gaW4gMTk1Mz8KCi0tLQoKIyMgTkZJUCBTdHVkeQojIyMgRGVzaWduCgotIEdyb3RlIHNpbXVsdGFuZSBzdHVkaWUgbWV0IGdldmFjY2luZWVyZGUga2luZGVyZW4gKGNhc2VzKSBlbiBvbmdldmFjY2luZWVyZGUga2luZGVyZW4gKGNvbnRyb2xlcykuCi0gSW4gc2Nob2xlbiB2YW4gZGlzdHJpY3RlbiBtZXQgaG9nZSBwb2xpbyBpbmNpZGVudGllLgotIENhc2VzOiBraW5kZXJlbiB2YW4gZGUgdHdlZWRlIGdyYWFkIHZhbiBoZXQgbGFnZXIgb25kZXJ3aWpzIHdhYXJ2YW4gZGUgb3VkZXJzIHRvZXN0ZW1kZW4gbWV0IHZhY2NpbmF0aWUuCi0gQ29udHJvbGVzOiBraW5kZXJlbiB2YW4gZGUgZWVyc3RlIGVuIGRlcmRlIGdyYWFkLgoKIyMjIERhdGEKYGBge3J9Cm5maXAgPC0gdGliYmxlKAogIGdyb3VwPWMoImNhc2VzIiwiY29udHJvbHMiLCJub0NvbmNlbnQiKSwKICBncmFkZT1jKCJnMiIsImcxZzMiLCJnMiIpLAogIHZhY2Npbj1jKCJ5ZXMiLCJubyIsIm5vIiksCiAgdG90YWw9YygyMjE5OTgsNzI1MTczLDEyMzYwNSksCiAgcG9saW89Yyg1NCwzOTEsNTYpCiAgKSAlPiUKICBtdXRhdGUobm9Qb2xpbyA9IHRvdGFsIC0gcG9saW8pCmtuaXRyOjprYWJsZShuZmlwKQpgYGAKClZlcmdlbGlqayBkZSBwb2xpbyBpbmNpZGVudGllPwoKLS0tCgpgYGB7cn0KbmZpcCA8LSBuZmlwICU+JQogIG11dGF0ZShpbmNpZGVuY2VQTSA9IHJvdW5kKG5maXAkcG9saW8vbmZpcCR0b3RhbCoxZTYsMCkpCmtuaXRyOjprYWJsZShuZmlwKQpgYGAKCldhdCBrdW5uZW4gd2UgY29uY2x1ZGVyZW4/CgotLS0KCiMjIENvbmZvdW5kaW5nCgoKYGBge3IsZWNobz1GQUxTRSwgZmlnLmFsaWduID0gImNlbnRlciIsb3V0LndpZHRoID0gJzUwJSd9CnBsb3QoYygwLDAsMSksYygtMiwyLDApLHBjaD1jKCJTIiwiViIsIlAiKSx4YXh0PSJub25lIix5YXh0PSJub25lIixheGVzPUZBTFNFLHhsYWI9IiIseWxhYj0iIixjZXg9NCx5bGltPWMoLTIuMiwyLjIpKQphcnJvd3MoeDA9MC4xLHgxPS45LHkwPTEuOCx5MT0wLjEsbHdkPTQpCmFycm93cyh4MD0wLjEseDE9LjkseTA9LTEuOCx5MT0tMC4yLGx3ZD00KQphcnJvd3MoeDA9MCx4MT0wLHkwPS0xLjQseTE9MS40LGx3ZD00KQpgYGAKCgotIFdlIG9ic2VydmVyZW4gZWVuIGxhZ2VyZSBwb2xpbyAoUCkgaW5jaWRlbnRpZSB2b29yIGtpbmRlcmVuIGJpaiB3aWUgZGUgb3VkZXJzIGdlZW4gdG9lc3RlbW1pbmcgZ2F2ZW4gZGFuIGluIGRlIGNvbnRyb2xlIGdyb2VwLiAgCgotIFRvZXN0ZW1taW5nIHZvb3IgdmFjY2luYXRpZSAoVikgaXMgZ2Vhc3NvY2llZXJkIG1ldCBkZSBzb2Npby1lY29ub21pc2NoZSBzdGF0dXMgKFMpLgoKLSBLaW5kZXJlbiB2YW4gbGFnZXJlIHNvY2lvLWVjb25vbWlzY2hlIHN0YXR1cyB6aWpuIG1lZXIgcmVzaXN0ZW50IHRlZ2VuIGRlIHppZWt0ZS4KCi0gRGUgZ3JvZXBlbiB2YW4gY2FzZXMgZW4gY29udHJvbGVzIHppam4gbmlldCB2ZXJnZWxpamtiYWFyCiAgICAtIHZlcnNjaGlsIGluIGxlZWZ0aWpkCiAgICAtIHZlcnNjaGlsIGluIHNvY2lvLWVjb25vbWlzY2hlIHN0YXR1cyBlbgogICAgLSB2ZXJzY2hpbCBpbiB2YXRiYWFyaGVpZCB2b29yIGRlIHppZWt0ZS4KCi0tLQoKIyMgU2FsayBTdHVkeQoKIyMjIERlc2lnbgpFZW4gbmlldXdlIHN0dWRpZSB3ZXJkIHVpdGdldm9lcmQ6IGR1YmJlbCBibGluZGUgZ2VyYW5kb21pc2VlcmRlIHN0dWRpZS4KCiAgLSBLaW5kZXJlbiB3b3JkZW4gYXQgcmFuZG9tIHRvZWdld2V6ZW4gYWFuIGNvbnRyb2xlIG9mIGNhc2UgYXJtIHZhbiBoZXQgZXhwZXJpbWVudCBuYWRhdCBkZSBvdWRlcnMgdG9lc3RlbWRlbiBtZXQgdmFjY2luYXRpZS4KICAtIENvbnRyb2xlOiB2YWNjaW5hdGllIG1ldCBwbGFjZWJvCiAgLSBUcmVhdG1lbnQ6IHZhY2NpbmF0aWUgbWV0IHZhY2NpbgogIC0gRG91YmxlIGJsaW5kaW5nOgogICAgLSBvdWRlcnMgZW4ga2luZGVyZW4gd2V0ZW4gbmlldCBvZiB6ZSB3ZXJkZW4gZ2V2YWNjaW5lZXJkIG9mIG5pZXQKICAgIC0gbWVkaXNjaGUgc3RhZiBlbiBvbmRlcnpvZWtlcnMgd2V0ZW4gbmlldCBvZiBoZXQga2luZCBoZXQgdmFjY2luIG9mIGRlIHBsYWNlYm8ga3JlZWcKCi0tLQoKIyMjIERhdGEKCmBgYHtyfQpzYWxrIDwtIGRhdGEuZnJhbWUoCiAgZ3JvdXA9YygiY2FzZXMiLCJjb250cm9sIiwibm9Db25jZW50IiksCiAgdHJlYXRtZW50PWMoInZhY2NpbmUiLCJwbGFjZWJvIiwibm9uZSIpLAogIHRvdGFsPWMoMjAwNzQ1LDIwMTIyOSwgMzM4Nzc4KSxwb2xpbz1jKDU3LDE0MiwxNTcpCiAgKSAlPiUKICBtdXRhdGUoCiAgICBub1BvbGlvID0gdG90YWwtcG9saW8sCiAgICBpbmNpZGVuY2VQTSA9IHJvdW5kKHBvbGlvL3RvdGFsKjFlNiwwKQogICAgKQprbml0cjo6a2FibGUoc2FsaykKYGBgCgotIFdlIG9ic2VydmVyZW4gZWVuIHZlZWwgZ3JvdGVyIGVmZmVjdCBudSBkYXQgY2FzZXMgZW4gY29udHJvbGVzIHZlcmdlbGlqa2JhYXIgemlqbiwgaW5jaWRlbnRpZSB2YW4gcmVzcGVjdGlldmVsaWprIGByIHNhbGskaW5jaWRlbmNlUE1bMV1gICBhbmQgYHIgc2FsayRpbmNpZGVuY2VQTVsyXWAgcGVyIG1pbGpvZW4uCgotIERlIHBvbGlvIGluY2lkZW50aWUgdm9vciBraW5kZXJlbiBkaWUgZ2VlbiB0b2VzdGVtbWluZyBnZXZlbiBibGlqZnQgdmVyZ2VsaWprYmFhciAgYHIgbmZpcCRpbmNpZGVuY2VQTVszXWAgYW5kIGByIHNhbGskaW5jaWRlbmNlUE1bM11gIHBlciBtaWxqb2VuIHJlc3BlY3RpZXZlbGlqayBpbiB0aGUgTkZJUCBhbmQgU2FsayBzdHVkeS4KCi0tLQoKIyBSb2wgdmFuIFN0YXRpc3RpZWsKCi0gV2UgaGViYmVuIGdlemllbiBkYXQKICAgIC0gaGV0IGJlbGFuZ3JpamsgaXMgb20gZGUgc2NvcGUgdmFuIGRlIHN0dWRpZSBnb2VkIHRlIHNwZWNpZmnDq3JlbiB2b29yIGRlIHN0YXJ0IHZhbiBoZXQgZXhwZXJpbWVudAogICAgLSByYW5kb21pc2F0aWUgbm9kaWcgaXMgb20gZWVuIHJlcHJlc2VudGF0aWV2ZSBzdGVla3Byb2VmIHRlIG5lbWVuCiAgICAtIHN0ZWVrcHJvZWYgZ3Jvb3R0ZSBpcyBoZWVsIGJlbGFuZ3JpamsKICAgIC0gd2UgbW9ldGVuIG9ucyBiZXd1c3QgemlqbiB2YW4gQ29uZm91bmRpbmcKICAgIC0gZWVuIGdvZWRlIGNvbnRyb2xlIGlzIGJlbGFuZ3JpamsKCgokXHJpZ2h0YXJyb3ckIEdvZWRlIHByb2Vmb3B6ZXQgaXMgY3J1Y2lhYWwhCgotLS0KCi0gV2UgaGViYmVuIG9vayBnZW9ic2VydmVlcmQgZGF0IGVyIHZhcmlhYmlsaXRlaXQgaXMgaW4gZGUgcG9wdWxhdGllCi0gV2Uga3VubmVuIG1hYXIgZWVuIGJlcGVya3RlIHN0ZWVrcHJvZWYgbmVtZW4gdWl0IGRlIHBvcHVsYXRpZQoKJFxyaWdodGFycm93JCBvbnpla2VyaGVpZCBpbiBkZSByZXN1bHRhdGVuCiRccmlnaHRhcnJvdyQgb256ZWtlcmhlaWQgaW4gZGUgY29uY2x1c2llcwoKCi0tLQoKLSBTdGF0aXN0aWVrIGlzIGRlIHdldGVuc2NoYXAgdm9vciBoZXQKICAgIDEuIHZlcnphbWVsZW4gKGV4cGVyaW1lbnRlZWwgZGVzaWduKSwKICAgIDIuIGV4cGxvcmVuIChkYXRhIGV4cGxvcmF0aW9uKSBlbgogICAgMy4gbGVyZW4gdmFuIGRhdGEgem9kYXQgd2UgaGV0Z2VlbiB3ZSBvYnNlcnZlcmVuIGluIGRlIHN0ZWVrcHJvZWYgem91ZGVuIGt1bm5lbiB2ZXJhbGdlbWVuZW4gbmFhciBkZSBwb3B1bGF0aWUgdGVyd2lqbCB3ZSBkZSBvbnpla2VyaGVpZCBxdWFudGlmaWNlcmVuLCBjb250cm9sZXJlbiBlbiByYXBwb3J0ZXJlbiAoc3RhdGlzdGlzY2ggbW9kZWxsZXJlbiBlbiBzdGF0aXN0aXNjaGUgYmVzbHVpdHZvcm1pbmcpLgoKLSBTdGF0aXN0aWVrIHNwZWVsdCBkYWFyb20gZWVuIGhlZWwgYmVsYW5ncmlqa2Ugcm9sIGluIHpvd2F0IGFsbGUgd2V0ZW5zY2hhcHBlbgoKCiMgW0hvbWVdKGh0dHBzOi8vc3RhdG9taWNzLmdpdGh1Yi5pby9zYmMyMCkgey19Cg==