Situering

In de landbouw is het belangrijk om een goede productie van gewassen te bekomen. Voor het kweken van bladgroenten zoals sla en spinazie houdt dit in om zo groot mogelijke kroppen of bladeren te bekomen. De consument zal namelijk eerder kiezen voor grote, volle kroppen met veel blad.

Om dit te bekomen, gebruiken de boeren vaak verschillende types van mest. Er is meer en meer een tendens om over te schakelen van kunstmeststoffen naar meer duurzame organische meststoffen. De meest gekende organische meststof is compost. In het ILVO worden er echter ook nieuwe types van organische meststoffen getest. Één van deze nieuwe stoffen is biochar. Biochar wordt gevormd tijdens een pyrolyse proces van biomassa (zoals bv. houtafval) waarbij energie wordt opgewekt. Het restmateriaal van de pyrolyse wordt de biochar genoemd, een stof die sterk gelijkt op houtskool maar nuttige eigenschappen heeft zoals vasthouden van het water in de bodem en het beïnvloeden van de nuttige bacteriën in de bodem.

Data

De onderzoekers willen nagaan of biochar, compost en compost gemengd met biochar invloed heeft op de groei van bladgroenten. Daarvoor groeiden ze sla op in potten met veldgrond in een groeikamer. Het versgewicht van de plant werd na acht weken gemeten. Versgewicht wordt gebruikt als een maat voor de plantengroei. De planten zijn in vier verschillende types grond opgegroeid:

  1. Veldgrond (controle)
  2. Veldgrond waaraan biochar werd toegevoegd (refoak)
  3. Veldgrond waaraan compost werd toegevoegd (compost)
  4. Veldgrond waaraan compost gemengd met biochar werd toegevoegd (cobc)

Het bestandje ‘versgewicht_sla.txt’ bevat het versgewicht in gram voor 28 slaplanten en welke behandeling ze ondergingen.

Onderzoeksvraag

Ga na of er een effect is de verschillende behandelingen op de plantengroei van bladgroenten. Indien dit zo is, welke behandelingen zijn effectief?

Waarom een niet-parametrische test?

Voor het project lossen jullie deze onderzoeksvraag op met behulp van parametrische ANOVA (de F-test). Dit is een geldige test als aan een aantal assumpties voldaan worden die geverifieerd moeten worden in de dataset. Echter, hoe kleiner de dataset hoe moeilijker het is om deze assumptie te controleren. Laten we als voorbeeld kijken naar de asumptie van normaliteit.

#Lees de data in
dataset=read.csv("~/Dropbox/PhD/Onderwijs/Statistiek Biochemie/201819/dropboxStats1819/class6_nonPar/half/versgewicht_sla.txt",header=TRUE)
m <- lm(versgewicht ~ behandeling, data=dataset)
par(mfrow=c(2,2))
plot(m)
par(mfrow=c(1,1))

De QQ-plot is nogal twijfelachtig, en men zou beide kanten kunnen beargumenteren. Inderdaad, enerzijds kan men argumenteren dat de QQ-plot niet bijzonder sterk afwijkt van wat men zou verwachten op basis van een Normale distributie. Anderzijds, kan men argumenteren dat (i) de QQ-plot licht afwijkt, en (ii) we bovendien een Normale distributie moeten veronderstellen binnen elke groep, en de bovenstaande QQ-plot geen sluitend bewijs geeft. Zoals je ziet, is dit een dataset waarbij zowel de argumentatie voor een parametrische ANOVA test als de argumentatie voor een niet-parametrische Kruskal-Wallis test steek kan houden. De veilige optie is duidelijk de Kruskal-Wallis test, aangezien die geen parametrsiche assumpties veronderstelt. De enige veronderstelling is dat de data onafhankelijk zijn. Bovendien kan het, om een algemeen inzicht te verkrijgen, ook nuttig zijn om de resultaten te interpreteren in functie van de probabilistische index.

Stel dat de versgewichten van de planten geen Normale maar bvb een gamma distributie volgen. Een gamma distributie heeft een aantal eigenschappen die een betere keuze zou maken on gewichten te modelleren. Bijvoorbeeld, gewichten kunnen niet negatief zijn, een normalie distributie kan tot min oneindig lopen waar een gamma distributie een ondergrens heeft bij nul.

x = seq(-1,10,.01)
ynorm = dnorm(x,2)
ygam = dgamma(x,5,2)
plot(x,ynorm,type = 'l')
lines(x,ygam,col = 'red')
abline(v = 0)
legend('topright',c('Normale', 'Gamma'),text.col = c('black','red'))

We zullen 9 samples van elk 7 datapunten genereren uit een normale distributie.

par(mfrow = c(3,3))
set.seed(11) ## zorgt ervoor dat bij herlopen van de code exact dezelfde 'random' waarden genereerd worden.
for(i in 1:9){
  x = rnorm(7)
  qqnorm(x, main = i)
  qqline(x)
}

We zien in de QQ-plots dat de meeste samples normaal verdeeld lijken, terwijl sommigen toch niet-lineaire patronen vertonen (zoals QQ-plot 5) en dus misschien (incorrect) als niet normaal beoordeeld zouden worden.

We zullen nu 9 samples van elk 7 datapunten genereren uit een gamma distributie.

par(mfrow = c(3,3))
set.seed(11)
for(i in 1:9){
  x = rgamma(7,5,2)
  qqnorm(x, main = i)
  qqline(x)
}

We zien in de QQ-plots (bijvoorbeeld QQ-plot 4) dat sommige stalen samples afwijken van een rechte wat correct tot de conlusie van niet-normaal verdeelde data zou leiden. Aan de andere kant hebben de datapunten in bvb QQ-plot 7 wel een linear verband en zou deze data incorrect wel als normaal verdeeld beschouwd kunnen worden.

Nu is de assumptie van normaliteit belangrijk bij ANOVA (en ook t-test) omdat men hier ervan uitgaat dat je steekproefgemiddelde normaal verdeeld is rond het populatiegemidelde. Als je data normaal verdeeld is, zal dit altijd het geval zijn. Als je data niet normaal verdeeld is, dan gaat dit alleen maar op als je dataset groot genoeg is (zie de Centrale Limietstelling in de cursus).

We illustreren dit met een simulatie. Een groot aantal datasets van elk 4 datapunten worden gegenereerd uit een normale verdeling. We bereken per dataset het gemiddelde en we construeren een QQ-plot van deze gemiddelden om te controleren of ze normaal verdeeld zijn. We herhalen dit, maar nu worden de 4 datapunten gegenereerd uit een Gamma distributie. Om het effect van dataset grootte te bestuderen zullen we ook datasets uit een Gamma distributie genereren van grootte 7 en 10.

set.seed(11)
samples_normaal = replicate(30000, mean(rnorm(4)))
samples_gamma_4 = replicate(30000, mean(rgamma(3,5,2)))
samples_gamma_7 = replicate(30000, mean(rgamma(7,5,2)))
samples_gamma_10 = replicate(30000, mean(rgamma(30,5,2)))
par(mfrow = c(2,2))
qqnorm(samples_normaal,pch = 20, main = 'normaal; n = 4')
qqline(samples_normaal, col = 'red')
qqnorm(samples_gamma_4, pch = 20, main = 'gamma; n = 4')
qqline(samples_gamma_4, col = 'red')
qqnorm(samples_gamma_7,pch = 20, main = 'gamma; n = 7')
qqline(samples_gamma_7, col = 'red')
qqnorm(samples_gamma_10,pch = 20, main = 'gamma; n = 30')
qqline(samples_gamma_10, col = 'red')

We zien in de QQ-plot linksboven dat de gemiddelden van de normaal verdeelde datasets inderdaad op een rechte liggen en dus normaal verdeeld lijken. Bij de gemiddelden van de gamma datasets met grootte 4 zien we duidelijke afwijken van de normaliteit (de distributie is scheef verdeeld naar links). Teststatistieken en p-waarden berekend met ANOVA en t-testen zijn in dat geval ongeldig.

In de onderste rij QQ-plots kan men zien dat hoe groter de steekproeven worden, hoe meer de gemiddelden een normale distributie benaderen. Bij grotere datasets zal dus men kunnen argumenteren dat het steekproefgemiddelde een normale verdeling volgt. Dit effect, waarbij de gemiddelden van een steekproef uit om het even welke distributie een normale distributie gaan benaderen als de steekproef maar groot genoeg is, noemt men de centrale limietstelling. Als je steekproef groot genoeg is, kan je dus de centrale limietstelling inroepen om de normaliteitsassumptie te aanvaarden.

Als er geen sterke argumenten om de normaliteitsassumptie te aanvaarden (bijvoorbeeld gelijkaardige grotere datasets in het verleden lijken normaal verdeeld), is het doorgaans veiliger om dit niet te doen en een niet-parametrische test te gebruiken.

Merk op: ook als de assumptie van homoscedasticiteit geschonden is of moeilijk kan worden nagegaan door een te kleine steekproef, zullen de teststatistieken en p-waarden vertekend zijn. Voor een t-test kan je nog gebruik maken van de Welch t-test, voor een ANOVA zal je bij zeer sterke afwijkingen van homoscedasticiteit ook een niet-parametrische test moeten gebruiken en je resulaten in termen van de probabilistische index moeten interpreteren.

Data analyse

We zullen nu de slaplanten dataset herevalueren en niet-parametrische testen overwegen.

#Lees de data in
dataset=read.csv("~/Dropbox/PhD/Onderwijs/Statistiek Biochemie/201819/dropboxStats1819/class6_nonPar/half/versgewicht_sla.txt",header=TRUE)

Dataverkenning

## Tel het aantal metingen per behandeling
table(dataset$behandeling)

    cobc  compost controle   refoak 
       7        7        7        7 

Tabel 1: frequentietabel van het aantal observaties per behandelingsgroep.

boxplot(versgewicht~behandeling,dataset)
set.seed(10)
stripchart(versgewicht~behandeling, data = dataset,
            vertical = TRUE, method = "jitter", 
            pch = 19, col =c("coral","steelblue","gold","aquamarine3"), 
            add = TRUE)

Figuur 1: Boxplot van het versgewicht in gram per behandelingsgroep. De punten zijn de individuele metingen.

In de frequentietabel (Tabel 1) zien we dat er slechts 7 observaties per groep zijn. De gemeten versgewichten binnen de refoak behandelingsgroep zijn zeer vergelijkbaar met die van de controlegroep. De gemeten versgewichten binnen de cobc en de compost behandelingsgroepen zijn merkelijk hoger dan die binnen de controlegroep. De gemeten versgewichten binnen de compost behandelingsgroep liggen gemiddeld gezien iets hoger dan die binnen in de cobc groep, maar er is een grote overlap tussen gemeten waardes. Geen enkele behandelingsgroep bevat uitschieters. De metingen binnen iedere behandelijksgroep lijkt symmetrisch verdeeld. De variantie van de metingen lijkt niet sterk af te wijken tussen de behandelingsgroepen. Het bereik en de spreiding van de waarden tussen de verschillende groepen is zeer vergelijkbaar.

Kruskal-Wallis Rank Test

Door de weinig datapunten is het moeilijk om de distributionele assumpties voor de parametrische ANOVA te controleren (normaliteit en gelijke variantie tussen de groepen). De Kruskal-Wallis Rank Test (KW-test) is een niet-parametrische variant van de ANOVA. Deze test laat ons toe om de distributionele assumpties te relaxeren. Let erop dat de assumptie van onafhankelijkheid tussen de observaties nog steeds moet opgaan!

Als we willen testen voor een verschil tussen de mediaan van de verschillende behandelingsgroepen, dan moeten we uitgaan van de locatie shift assumptie. Onder de locatie shift assumptie veronderstellen we dat de verschillende groepen onderling nog steeds dezelfde distributie volgen (dit hoeft uiteraard niet noodzakelijk een normale verdeling te zijn, elke verdeling is goed, zolang het maar in beide groepen dezelfde verdeling is).

Wanneer je kijkt naar de boxplots in Figuur 1, denk je dan dat de locatie shift assumptie aannemelijk is?

De range en spreiding van de waarden tussen de verschillende groepen is op het eerste zicht zeer vergelijkbaar, maar je ziet in de boxplots wel grote verschillen in interquantiel afstanden (bvb tussen COBC en refoak boxplot). Eigenlijk hebben we te weinig data om deze assumptie te verifieren.

Wanneer we niet bereid zijn om de locatie shift assumptie te aanvaarden, dan kunnen we de distributionele assumpties nog verder relaxeren, en testen we in termen van probabilistische indexen. Hier testen we in het geval van twee groepen de kans dat een willekeurige meetwaarde uit de eerste groep komt groter of gelijk (“\(\geq\)”) is dan een willekeurige meetwaarde uit de tweede groep.

Hypothese

Probeer nu eens de nulhypothese op te stellen in termen van de onderzoeksvraag?

De nulhypothese stelt dat de verdelingen van de versgewichten van slaplanten gelijk zijn in de vier types grond.

De alternatieve hypothese stelt dat de kans dat het versgewicht van een willekeurige slaplant uit minstens één van de vier soorten grond groter is dan of gelijk is aan (“\(\geq\)”) het versgewicht van een willekeurige slaplant uit minstens één van de andere soorten grond verschilt van 50%.

Statistische test

Sinds we te maken hebben met een klein aantal observaties per groep is het niet aan te raden om de asymptotische KW-test te gebruiken om een p-waarde te berekenen. Deze stelt namelijk dat je teststatistiek onder de nulhypothese een \(\chi^2\) distributie volgt (de nuldistributie) wanneer het aantal oberservaties per groep naar oneindig neigt (dus voor een groot aantal observaties).

Wanneer je een beperkt aantal observaties hebt, is het beter de nuldistributie exact te berekenen via permutaties. Dit is uiteraard computationeel onmogelijk, want met 4 groepen van elk 7 observaties bestaan er 4.725183510^{14} mogelijke permutaties. Gelukkig is het meestal voldoende om de exacte nuldistributie te benaderen met een kleiner aantal permutaties.

Voer een KW test uit op de data met behulp van een groot aantal permutaties (bv. 10000). (Tip: zie cursus http://users.ugent.be/~lclement/statistiek/ voor code voorbeelden) Wat kan je besluiten uit dit resultaat?

library(coin)
kwPerm <- kruskal_test(versgewicht~behandeling,dataset, distribution=approximate(B=100000))
kwPerm

    Approximative Kruskal-Wallis Test

data:  versgewicht by behandeling (cobc, compost, controle, refoak)
chi-squared = 20.715, p-value < 2.2e-16

We zien een extreem significant effect (p << .001) van het type bemesting op het versgewicht van slaplanten. Op het 5% significantieniveau stellen we datde kans dat een willekeurige slaplant uit minstens één van de vier types grond een groter dan of gelijk (“\(\geq\)”) versgewicht heeft vergeleken met een willekeurige slaplant uit minstens één van de andere types grond verschilt van 50%.

Merk op: doordat we de p-waarde benaderd hebben aan de hand van simulaties, kan de p-waarde indien we de code opnieuw uitvoeren (en dus ook met je collega naast jou). Merk op dat deze variatie in p-waarde zou moeten verminderen als we het aantal permutaties zouden opdrijven, omdat we dan dichter in de buurt komen bij de exacte nuldistributie.

Als we willen weten in welke soorten grond er nu juist een significant verschil in versgewicht optreedt, zal men een post-hoc analyse moeten doen.

Post-hoc analyse

Zoals bij de parametrische ANOVA zal je ook bij de niet-parametrische KW test paarsgewijze testen moeten uitvoeren om onderlinge verschillen in versgewicht tussen de slaplanten te detecteren. Dit zullen uiteraard ook niet-parametrische testen zijn zoals de Wilcoxon-Mann-Whitney Test (WMW test). Als je de keuze gemaakt hebt om bij de KW test de locatie shift assumptie te verwerpen dan zal je dit hier terug doen en de resultaten in termen van de probabilistische index interpreteren.

Wat zal nu de nul en alternatieve hypothese zijn voor iedere paarsgewijze test?

De nulhypothese stelt dat de verdeling van het versgewicht van slaplanten gelijk is voor beide types grond.

De alternatieve nulhypothese stelt dat de kans dat het versgewicht van een willekeurige slaplant uit opgegroeid in de ene soort grond hoger is dan of gelijk is aan (“\(\geq\)”) het versgewicht van een willekeurige slaplant uit de andere soort grond verschillend is van 50%.

Voer een WMW post-hoc analyse uit op de data.

We doen een paarsgewijze WMW test zoals beschreven in de curus.

pairwise.wilcox.test(dataset$versgewicht,dataset$behandeling)
cannot compute exact p-value with tiescannot compute exact p-value with tiescannot compute exact p-value with tiescannot compute exact p-value with tiescannot compute exact p-value with tiescannot compute exact p-value with ties

    Pairwise comparisons using Wilcoxon rank sum test 

data:  dataset$versgewicht and dataset$behandeling 

         cobc  compost controle
compost  0.400 -       -       
controle 0.013 0.013   -       
refoak   0.013 0.013   0.400   

P value adjustment method: holm 

We zien in de output een foutmelding: cannot compute exact p-value with ties. Dit is omdat de pairwise.wilcox.test() functie de standaard wilcox.test() functie gebruikt in R. In de help van deze functie zien we dat deze functie standaard een exacte test doet maar in de aanwezigheid van ties dit niet kan doen en terugrijpt naar een asymptotische test. We kunnen echter wel exacte p-waarden bekomen met de wilcox_test() uit de coin package voor iedere combinatie van behandeling en vervolgens te corrigeren voor multiple testing met de p.adjust() functie.

library(coin)
## tel het aantal observaties per groep
nGroep <- table(dataset$behandeling)
## bereken met de wilcoxon test een p-waarde voor iedere combinatie van grondsoorten
behandelingen = (levels(dataset$behandeling))
pvalues <- combn(behandelingen,2,function(x){
  ## Doe een paarsgewijze WMW test.
  test = wilcox_test(versgewicht~behandeling,subset(dataset,behandeling%in%x), distribution = 'exact')
  ## Neem de pwaarde uit output van de test
  pvalue(test)
})
## Doe een correctie voor multiple testing met Holm (je kan eventueel ook kiezen voor Bonferroni etc ...)
pvalues_holm = p.adjust(pvalues,method = 'holm') 
 ## link de pwaarde met de juiste paarsgewijze test
names(pvalues_holm) <- combn(levels(dataset$behandeling),2,paste,collapse="_VS_")
pvalues_holm
    cobc_VS_compost    cobc_VS_controle      cobc_VS_refoak compost_VS_controle   compost_VS_refoak  controle_VS_refoak 
        0.393939394         0.005244755         0.003496503         0.003496503         0.003496503         0.405594406 

We zien inderdaad dat de exacte p-waarden afwijken van de p-waarden berekend door de pairwise.wilcox.test() functie. We zullen verder werken met deze laatste p-waarden. We zien dat er alleen significante verschillen zijn tussen de slaplanten die gegroeid zijn in compost ten opzichte van de planten die zonder compost opgegroeid zijn.

Kan je nu ook aan de hand van de Mann-Whitney teststatistiek een puntschatting geven voor de probabilistische index?

## tel het aantal observaties per groep
nGroep <- table(dataset$behandeling)
## bereken een probabilistische index voor iedere mogelijke combinatie van grondsoorten
behandelingen = (levels(dataset$behandeling))
probInd <- combn(behandelingen,2,function(x){
  ## Berkeken de U1 statistiek
  U1 = wilcox.test(versgewicht~behandeling,subset(dataset,behandeling%in%x))$statistic
  ## Bereken probabilistische index
  U1/prod(nGroep[x])
})
cannot compute exact p-value with tiescannot compute exact p-value with tiescannot compute exact p-value with tiescannot compute exact p-value with tiescannot compute exact p-value with tiescannot compute exact p-value with ties
names(probInd) <- combn(levels(dataset$behandeling),2,paste,collapse="_VS_")
probInd
    cobc_VS_compost    cobc_VS_controle      cobc_VS_refoak compost_VS_controle   compost_VS_refoak  controle_VS_refoak 
          0.2857143           0.9795918           1.0000000           1.0000000           1.0000000           0.6428571 

We zien in de output opnieuw dezelfde foutmelding: cannot compute exact p-value with ties omdat we terug de wilcox.test() functie gebruiken. Maar dit is hier geen probleem omdat we niet de p-waarde nodig hebben maar de U1 statistiek. U1 is het aantal keer dat een observatie uit de eerste groep groter of gelijk is aan een observatie uit de tweede groep en is dus gedefinieerd bij ties (zie ook cursus).

Hoe interpreteer je de resultaten van de WMW testen?

We vinden significante verschillen in de verdelingen van versgewicht in vergelijking met de controle behandeling. De kans dat het versgewicht voor slaplanten opgegroeid in grond met compost hoger of gelijk is dan (“\(\geq\)”) het versgewicht voor slaplanten opgegroeid in de controle behandeling is gelijk aan 100% (WMW test, aangepaste p-waarde < 0.01). Gelijkaardig, de kans dat het versgewicht voor slaplanten opgegroeid in grond met compost en biochar hoger of gelijk (“\(\geq\)”) is dan het versgewicht voor slaplanten opgegroeid in de controle behandeling is gelijk aan 98.0% (WMW test, aangepaste p-waarde < 0.01).

Bovendien vinden we ook significante verschillen in de verdelingen van versgewicht in vergelijking met de biochar behandeling. De kans dat het versgewicht voor slaplanten opgegroeid in grond met biochar hoger of gelijk (“\(\geq\)”) is dan het versgewicht voor slaplanten opgegroeid in grond met compost is gelijk aan 100% (WMW test, aangepaste p-waarde < 0.01). Ook, de kans dat het versgewicht voor slaplanten opgegroeid in grond met biochar hoger of gelijk (“\(\geq\)”) is dan het versgewicht voor slaplanten opgegroeid in grond met compost en biochar is gelijk aan 100% (WMW test, aangepaste p-waarde < 0.01).

We vinden geen significant verschillende verdelingen in versgewicht van slaplanten tussen grond met biochar en de controle grond en tussen de grond met compost en de grond met compost en biochar.

Conclusie

We zien dat er een extreem significant effect (p << .001) is van het type grond op het versgewicht van slaplanten. Op het 5% significantieniveau stellen we dat de kans dat het versgewicht van een willekeurige slaplant opgegroeid in de ene soort grond hoger is dan of gelijk is (“\(\geq\)”) aan het versgewicht van een willekeurige slaplant uit de andere soorten grond extreem significant verschilt van 50%.

We vinden significante verschillen in de verdelingen van versgewicht in vergelijking met de controle behandeling. De kans dat het versgewicht voor slaplanten opgegroeid in grond met compost hoger of gelijk (“\(\geq\)”) is dan het versgewicht voor slaplanten opgegroeid in de controle behandeling is gelijk aan 100% (WMW test, aangepaste p-waarde < 0.01). Gelijkaardig, de kans dat het versgewicht voor slaplanten opgegroeid in grond met compost en biochar hoger of gelijk (“\(\geq\)”) is dan het versgewicht voor slaplanten opgegroeid in de controle behandeling is gelijk aan 98.0% (WMW test, aangepaste p-waarde < 0.01).

Bovendien vinden we ook significante verschillen in de verdelingen van versgewicht in vergelijking met de biochar behandeling. De kans dat het versgewicht voor slaplanten opgegroeid in grond met biochar hoger of gelijk (“\(\geq\)”) is dan het versgewicht voor slaplanten opgegroeid in grond met compost is gelijk aan 100% (WMW test, aangepaste p-waarde < 0.01). Ook, de kans dat het versgewicht voor slaplanten opgegroeid in grond met biochar hoger of gelijk (“\(\geq\)”) is dan het versgewicht voor slaplanten opgegroeid in grond met compost en biochar is gelijk aan 100% (WMW test, aangepaste p-waarde < 0.01).

We vinden geen significant verschillende kans op een verschillend versgewicht van slaplanten tussen grond met biochar en de controle grond en tussen de grond met compost en de grond met compost en biochar.

We kunnen besluiten dat grond met compost en grond met compost en biochar een positieve invloed heeft op de groei van slaplanten. Aangezien in deze studie alleen gekeken werd naar slaplanten, kunnen we dit uiteraard niet besluiten voor bladgroenten in het algemeen.

LS0tCnRpdGxlOiAiTmlldC1wYXJhbWV0cmlzY2hlIHRlc3RlbjogUGxhbnRlbmdyb2VpIGluIGJsYWRncm9lbnRlbiIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyBTaXR1ZXJpbmcKSW4gZGUgbGFuZGJvdXcgaXMgaGV0IGJlbGFuZ3Jpamsgb20gZWVuIGdvZWRlIHByb2R1Y3RpZSB2YW4gZ2V3YXNzZW4gdGUgYmVrb21lbi4gVm9vciBoZXQga3dla2VuIHZhbiBibGFkZ3JvZW50ZW4gem9hbHMgc2xhIGVuIHNwaW5hemllIGhvdWR0IGRpdCBpbiBvbSB6byBncm9vdCBtb2dlbGlqa2Uga3JvcHBlbiBvZiBibGFkZXJlbiB0ZSBiZWtvbWVuLiBEZSBjb25zdW1lbnQgemFsIG5hbWVsaWprIGVlcmRlciBraWV6ZW4gdm9vciBncm90ZSwgdm9sbGUga3JvcHBlbiBtZXQgdmVlbCBibGFkLgoKT20gZGl0IHRlIGJla29tZW4sIGdlYnJ1aWtlbiBkZSBib2VyZW4gdmFhayB2ZXJzY2hpbGxlbmRlIHR5cGVzIHZhbiBtZXN0LiBFciBpcyBtZWVyIGVuIG1lZXIgZWVuIHRlbmRlbnMgb20gb3ZlciB0ZSBzY2hha2VsZW4gdmFuIGt1bnN0bWVzdHN0b2ZmZW4gbmFhciBtZWVyIGR1dXJ6YW1lIG9yZ2FuaXNjaGUgbWVzdHN0b2ZmZW4uIERlIG1lZXN0IGdla2VuZGUgb3JnYW5pc2NoZSBtZXN0c3RvZiBpcyBjb21wb3N0LiBJbiBoZXQgSUxWTyB3b3JkZW4gZXIgZWNodGVyIG9vayBuaWV1d2UgdHlwZXMgdmFuIG9yZ2FuaXNjaGUgbWVzdHN0b2ZmZW4gZ2V0ZXN0LiDDicOpbiB2YW4gZGV6ZSBuaWV1d2Ugc3RvZmZlbiBpcyBiaW9jaGFyLiBCaW9jaGFyIHdvcmR0IGdldm9ybWQgdGlqZGVucyBlZW4gcHlyb2x5c2UgcHJvY2VzIHZhbiBiaW9tYXNzYSAoem9hbHMgYnYuIGhvdXRhZnZhbCkgd2FhcmJpaiBlbmVyZ2llIHdvcmR0IG9wZ2V3ZWt0LiBIZXQgcmVzdG1hdGVyaWFhbCB2YW4gZGUgcHlyb2x5c2Ugd29yZHQgZGUgYmlvY2hhciBnZW5vZW1kLCBlZW4gc3RvZiBkaWUgc3RlcmsgZ2VsaWprdCBvcCBob3V0c2tvb2wgbWFhciBudXR0aWdlIGVpZ2Vuc2NoYXBwZW4gaGVlZnQgem9hbHMgdmFzdGhvdWRlbiB2YW4gaGV0IHdhdGVyIGluIGRlIGJvZGVtIGVuIGhldCBiZcOvbnZsb2VkZW4gdmFuIGRlIG51dHRpZ2UgYmFjdGVyacOrbiBpbiBkZSBib2RlbS4KCiMgRGF0YQpEZSBvbmRlcnpvZWtlcnMgd2lsbGVuIG5hZ2FhbiBvZiAgYmlvY2hhciwgY29tcG9zdCBlbiBjb21wb3N0IGdlbWVuZ2QgbWV0IGJpb2NoYXIgaW52bG9lZCBoZWVmdCBvcCBkZSBncm9laSB2YW4gYmxhZGdyb2VudGVuLiBEYWFydm9vciBncm9laWRlbiB6ZSBzbGEgb3AgaW4gcG90dGVuIG1ldCB2ZWxkZ3JvbmQgaW4gZWVuIGdyb2Vpa2FtZXIuIEhldCB2ZXJzZ2V3aWNodCB2YW4gZGUgcGxhbnQgd2VyZCBuYSBhY2h0IHdla2VuIGdlbWV0ZW4uIFZlcnNnZXdpY2h0IHdvcmR0IGdlYnJ1aWt0IGFscyBlZW4gbWFhdCB2b29yIGRlIHBsYW50ZW5ncm9laS4gIERlIHBsYW50ZW4gemlqbiBpbiB2aWVyIHZlcnNjaGlsbGVuZGUgdHlwZXMgZ3JvbmQgb3BnZWdyb2VpZDoKIAoxLiBWZWxkZ3JvbmQgKGNvbnRyb2xlKSAKMi4gVmVsZGdyb25kIHdhYXJhYW4gYmlvY2hhciB3ZXJkIHRvZWdldm9lZ2QgKHJlZm9haykKMy4gVmVsZGdyb25kIHdhYXJhYW4gY29tcG9zdCB3ZXJkIHRvZWdldm9lZ2QgKGNvbXBvc3QpCjQuIFZlbGRncm9uZCB3YWFyYWFuIGNvbXBvc3QgZ2VtZW5nZCBtZXQgYmlvY2hhciB3ZXJkIHRvZWdldm9lZ2QgKGNvYmMpCgpIZXQgYmVzdGFuZGplICd2ZXJzZ2V3aWNodF9zbGEudHh0JyBiZXZhdCBoZXQgdmVyc2dld2ljaHQgaW4gZ3JhbSB2b29yIDI4IHNsYXBsYW50ZW4gZW4gd2Vsa2UgYmVoYW5kZWxpbmcgemUgb25kZXJnaW5nZW4uCgojIE9uZGVyem9la3N2cmFhZwpHYSBuYSBvZiBlciBlZW4gZWZmZWN0IGlzIGRlIHZlcnNjaGlsbGVuZGUgYmVoYW5kZWxpbmdlbiBvcCBkZSBwbGFudGVuZ3JvZWkgdmFuIGJsYWRncm9lbnRlbi4KSW5kaWVuIGRpdCB6byBpcywgd2Vsa2UgYmVoYW5kZWxpbmdlbiB6aWpuIGVmZmVjdGllZj8KCiMgV2Fhcm9tIGVlbiBuaWV0LXBhcmFtZXRyaXNjaGUgdGVzdD8KVm9vciBoZXQgcHJvamVjdCBsb3NzZW4ganVsbGllIGRlemUgb25kZXJ6b2Vrc3ZyYWFnIG9wIG1ldCBiZWh1bHAgdmFuIHBhcmFtZXRyaXNjaGUgQU5PVkEgKGRlIEYtdGVzdCkuCkRpdCBpcyBlZW4gZ2VsZGlnZSB0ZXN0IGFscyBhYW4gZWVuIGFhbnRhbCBhc3N1bXB0aWVzIHZvbGRhYW4gd29yZGVuIGRpZSBnZXZlcmlmaWVlcmQgbW9ldGVuIHdvcmRlbiBpbiBkZSBkYXRhc2V0LgpFY2h0ZXIsIGhvZSBrbGVpbmVyIGRlIGRhdGFzZXQgaG9lIG1vZWlsaWprZXIgaGV0IGlzIG9tIGRlemUgYXNzdW1wdGllIHRlIGNvbnRyb2xlcmVuLgpMYXRlbiB3ZSBhbHMgdm9vcmJlZWxkIGtpamtlbiBuYWFyIGRlIGFzdW1wdGllIHZhbiBub3JtYWxpdGVpdC4KCmBgYHtyfQojTGVlcyBkZSBkYXRhIGluCmRhdGFzZXQ9cmVhZC5jc3YoIn4vRHJvcGJveC9QaEQvT25kZXJ3aWpzL1N0YXRpc3RpZWsgQmlvY2hlbWllLzIwMTgxOS9kcm9wYm94U3RhdHMxODE5L2NsYXNzNl9ub25QYXIvaGFsZi92ZXJzZ2V3aWNodF9zbGEudHh0IixoZWFkZXI9VFJVRSkKbSA8LSBsbSh2ZXJzZ2V3aWNodCB+IGJlaGFuZGVsaW5nLCBkYXRhPWRhdGFzZXQpCnBhcihtZnJvdz1jKDIsMikpCnBsb3QobSkKcGFyKG1mcm93PWMoMSwxKSkKYGBgCgpEZSBRUS1wbG90IGlzIG5vZ2FsIHR3aWpmZWxhY2h0aWcsIGVuIG1lbiB6b3UgYmVpZGUga2FudGVuIGt1bm5lbiBiZWFyZ3VtZW50ZXJlbi4KSW5kZXJkYWFkLCBlbmVyemlqZHMga2FuIG1lbiBhcmd1bWVudGVyZW4gZGF0IGRlIFFRLXBsb3QgbmlldCBiaWp6b25kZXIgc3RlcmsgYWZ3aWprdCB2YW4gd2F0IG1lbiB6b3UgdmVyd2FjaHRlbiBvcCBiYXNpcyB2YW4gZWVuIE5vcm1hbGUgZGlzdHJpYnV0aWUuCkFuZGVyemlqZHMsIGthbiBtZW4gYXJndW1lbnRlcmVuIGRhdCAoaSkgZGUgUVEtcGxvdCBsaWNodCBhZndpamt0LCBlbiAoaWkpIHdlIGJvdmVuZGllbiBlZW4gTm9ybWFsZSBkaXN0cmlidXRpZSBtb2V0ZW4gdmVyb25kZXJzdGVsbGVuICoqYmlubmVuIGVsa2UgZ3JvZXAqKiwgZW4gZGUgYm92ZW5zdGFhbmRlIFFRLXBsb3QgZ2VlbiBzbHVpdGVuZCBiZXdpanMgZ2VlZnQuClpvYWxzIGplIHppZXQsIGlzIGRpdCBlZW4gZGF0YXNldCB3YWFyYmlqIHpvd2VsIGRlIGFyZ3VtZW50YXRpZSB2b29yIGVlbiBwYXJhbWV0cmlzY2hlIEFOT1ZBIHRlc3QgYWxzIGRlIGFyZ3VtZW50YXRpZSB2b29yIGVlbiBuaWV0LXBhcmFtZXRyaXNjaGUgS3J1c2thbC1XYWxsaXMgdGVzdCBzdGVlayBrYW4gaG91ZGVuLiBEZSB2ZWlsaWdlIG9wdGllIGlzIGR1aWRlbGlqayBkZSBLcnVza2FsLVdhbGxpcyB0ZXN0LCBhYW5nZXppZW4gZGllIGdlZW4gcGFyYW1ldHJzaWNoZSBhc3N1bXB0aWVzIHZlcm9uZGVyc3RlbHQuIERlIGVuaWdlIHZlcm9uZGVyc3RlbGxpbmcgaXMgZGF0IGRlIGRhdGEgb25hZmhhbmtlbGlqayB6aWpuLgpCb3ZlbmRpZW4ga2FuIGhldCwgb20gZWVuIGFsZ2VtZWVuIGluemljaHQgdGUgdmVya3Jpamdlbiwgb29rIG51dHRpZyB6aWpuIG9tIGRlIHJlc3VsdGF0ZW4gdGUgaW50ZXJwcmV0ZXJlbiBpbiBmdW5jdGllIHZhbiBkZSBwcm9iYWJpbGlzdGlzY2hlIGluZGV4LgoKU3RlbCBkYXQgZGUgdmVyc2dld2ljaHRlbiB2YW4gZGUgcGxhbnRlbiBnZWVuIE5vcm1hbGUgbWFhciBidmIgZWVuIGdhbW1hIGRpc3RyaWJ1dGllIHZvbGdlbi4KRWVuIGdhbW1hIGRpc3RyaWJ1dGllIGhlZWZ0IGVlbiBhYW50YWwgZWlnZW5zY2hhcHBlbiBkaWUgZWVuIGJldGVyZSBrZXV6ZSB6b3UgbWFrZW4gb24gZ2V3aWNodGVuIHRlIG1vZGVsbGVyZW4uCkJpanZvb3JiZWVsZCwgZ2V3aWNodGVuIGt1bm5lbiBuaWV0IG5lZ2F0aWVmIHppam4sIGVlbiBub3JtYWxpZSBkaXN0cmlidXRpZSBrYW4gdG90IG1pbiBvbmVpbmRpZyBsb3BlbiB3YWFyIGVlbiBnYW1tYSBkaXN0cmlidXRpZSBlZW4gb25kZXJncmVucyBoZWVmdCBiaWogbnVsLgoKYGBge3J9CnggPSBzZXEoLTEsMTAsLjAxKQp5bm9ybSA9IGRub3JtKHgsMikKeWdhbSA9IGRnYW1tYSh4LDUsMikKcGxvdCh4LHlub3JtLHR5cGUgPSAnbCcpCmxpbmVzKHgseWdhbSxjb2wgPSAncmVkJykKYWJsaW5lKHYgPSAwKQpsZWdlbmQoJ3RvcHJpZ2h0JyxjKCdOb3JtYWxlJywgJ0dhbW1hJyksdGV4dC5jb2wgPSBjKCdibGFjaycsJ3JlZCcpKQpgYGAKCgoKV2UgenVsbGVuIDkgc2FtcGxlcyB2YW4gZWxrIDcgZGF0YXB1bnRlbiBnZW5lcmVyZW4gdWl0IGVlbiAqKm5vcm1hbGUqKiBkaXN0cmlidXRpZS4KCmBgYHtyfQpwYXIobWZyb3cgPSBjKDMsMykpCnNldC5zZWVkKDExKSAjIyB6b3JndCBlcnZvb3IgZGF0IGJpaiBoZXJsb3BlbiB2YW4gZGUgY29kZSBleGFjdCBkZXplbGZkZSAncmFuZG9tJyB3YWFyZGVuIGdlbmVyZWVyZCB3b3JkZW4uCmZvcihpIGluIDE6OSl7CiAgeCA9IHJub3JtKDcpCiAgcXFub3JtKHgsIG1haW4gPSBpKQogIHFxbGluZSh4KQp9CmBgYAoKV2UgemllbiBpbiBkZSBRUS1wbG90cyBkYXQgZGUgbWVlc3RlIHNhbXBsZXMgbm9ybWFhbCB2ZXJkZWVsZCBsaWprZW4sIHRlcndpamwgc29tbWlnZW4gdG9jaCBuaWV0LWxpbmVhaXJlIHBhdHJvbmVuIHZlcnRvbmVuICh6b2FscyBRUS1wbG90IDUpIGVuIGR1cyBtaXNzY2hpZW4gKGluY29ycmVjdCkgYWxzIG5pZXQgbm9ybWFhbCBiZW9vcmRlZWxkIHpvdWRlbiB3b3JkZW4uCgpXZSB6dWxsZW4gbnUgOSBzYW1wbGVzIHZhbiBlbGsgNyBkYXRhcHVudGVuIGdlbmVyZXJlbiB1aXQgZWVuICoqZ2FtbWEqKiBkaXN0cmlidXRpZS4KCmBgYHtyfQpwYXIobWZyb3cgPSBjKDMsMykpCnNldC5zZWVkKDExKQoKZm9yKGkgaW4gMTo5KXsKICB4ID0gcmdhbW1hKDcsNSwyKQogIHFxbm9ybSh4LCBtYWluID0gaSkKICBxcWxpbmUoeCkKfQpgYGAKCgpXZSB6aWVuIGluIGRlIFFRLXBsb3RzIChiaWp2b29yYmVlbGQgUVEtcGxvdCA0KSBkYXQgc29tbWlnZSBzdGFsZW4gc2FtcGxlcyBhZndpamtlbiB2YW4gZWVuIHJlY2h0ZSB3YXQgY29ycmVjdCB0b3QgZGUgY29ubHVzaWUgdmFuIG5pZXQtbm9ybWFhbCB2ZXJkZWVsZGUgZGF0YSB6b3UgbGVpZGVuLgpBYW4gZGUgYW5kZXJlIGthbnQgaGViYmVuIGRlIGRhdGFwdW50ZW4gaW4gYnZiIFFRLXBsb3QgNyB3ZWwgZWVuIGxpbmVhciB2ZXJiYW5kIGVuIHpvdSBkZXplIGRhdGEgaW5jb3JyZWN0IHdlbCBhbHMgbm9ybWFhbCB2ZXJkZWVsZCBiZXNjaG91d2Qga3VubmVuIHdvcmRlbi4KCk51IGlzIGRlIGFzc3VtcHRpZSB2YW4gbm9ybWFsaXRlaXQgYmVsYW5ncmlqayBiaWogQU5PVkEgKGVuIG9vayB0LXRlc3QpIG9tZGF0IG1lbiBoaWVyIGVydmFuIHVpdGdhYXQgZGF0IGplIHN0ZWVrcHJvZWZnZW1pZGRlbGRlIG5vcm1hYWwgdmVyZGVlbGQgaXMgcm9uZCBoZXQgcG9wdWxhdGllZ2VtaWRlbGRlLiAKQWxzIGplIGRhdGEgbm9ybWFhbCB2ZXJkZWVsZCBpcywgemFsIGRpdCBhbHRpamQgaGV0IGdldmFsIHppam4uCkFscyBqZSBkYXRhIG5pZXQgbm9ybWFhbCB2ZXJkZWVsZCBpcywgZGFuIGdhYXQgZGl0IGFsbGVlbiBtYWFyIG9wIGFscyBqZSBkYXRhc2V0IGdyb290IGdlbm9lZyBpcyAoemllIGRlIENlbnRyYWxlIExpbWlldHN0ZWxsaW5nIGluIGRlIGN1cnN1cykuCgpXZSBpbGx1c3RyZXJlbiBkaXQgbWV0IGVlbiBzaW11bGF0aWUuCkVlbiBncm9vdCBhYW50YWwgZGF0YXNldHMgdmFuIGVsayA0IGRhdGFwdW50ZW4gd29yZGVuIGdlZ2VuZXJlZXJkIHVpdCBlZW4gbm9ybWFsZSB2ZXJkZWxpbmcuCldlIGJlcmVrZW4gcGVyIGRhdGFzZXQgaGV0IGdlbWlkZGVsZGUgZW4gd2UgY29uc3RydWVyZW4gZWVuIFFRLXBsb3QgdmFuIGRlemUgZ2VtaWRkZWxkZW4gb20gdGUgY29udHJvbGVyZW4gb2YgemUgbm9ybWFhbCB2ZXJkZWVsZCB6aWpuLiAKV2UgaGVyaGFsZW4gZGl0LCBtYWFyIG51IHdvcmRlbiBkZSA0IGRhdGFwdW50ZW4gZ2VnZW5lcmVlcmQgdWl0IGVlbiBHYW1tYSBkaXN0cmlidXRpZS4KT20gaGV0IGVmZmVjdCB2YW4gZGF0YXNldCBncm9vdHRlIHRlIGJlc3R1ZGVyZW4genVsbGVuIHdlIG9vayBkYXRhc2V0cyB1aXQgZWVuIEdhbW1hIGRpc3RyaWJ1dGllIGdlbmVyZXJlbiB2YW4gZ3Jvb3R0ZSA3IGVuIDEwLgoKYGBge3J9CnNldC5zZWVkKDExKQpzYW1wbGVzX25vcm1hYWwgPSByZXBsaWNhdGUoMzAwMDAsIG1lYW4ocm5vcm0oNCkpKQpzYW1wbGVzX2dhbW1hXzQgPSByZXBsaWNhdGUoMzAwMDAsIG1lYW4ocmdhbW1hKDMsNSwyKSkpCnNhbXBsZXNfZ2FtbWFfNyA9IHJlcGxpY2F0ZSgzMDAwMCwgbWVhbihyZ2FtbWEoNyw1LDIpKSkKc2FtcGxlc19nYW1tYV8xMCA9IHJlcGxpY2F0ZSgzMDAwMCwgbWVhbihyZ2FtbWEoMzAsNSwyKSkpCnBhcihtZnJvdyA9IGMoMiwyKSkKcXFub3JtKHNhbXBsZXNfbm9ybWFhbCxwY2ggPSAyMCwgbWFpbiA9ICdub3JtYWFsOyBuID0gNCcpCnFxbGluZShzYW1wbGVzX25vcm1hYWwsIGNvbCA9ICdyZWQnKQpxcW5vcm0oc2FtcGxlc19nYW1tYV80LCBwY2ggPSAyMCwgbWFpbiA9ICdnYW1tYTsgbiA9IDQnKQpxcWxpbmUoc2FtcGxlc19nYW1tYV80LCBjb2wgPSAncmVkJykKcXFub3JtKHNhbXBsZXNfZ2FtbWFfNyxwY2ggPSAyMCwgbWFpbiA9ICdnYW1tYTsgbiA9IDcnKQpxcWxpbmUoc2FtcGxlc19nYW1tYV83LCBjb2wgPSAncmVkJykKcXFub3JtKHNhbXBsZXNfZ2FtbWFfMTAscGNoID0gMjAsIG1haW4gPSAnZ2FtbWE7IG4gPSAzMCcpCnFxbGluZShzYW1wbGVzX2dhbW1hXzEwLCBjb2wgPSAncmVkJykKYGBgCgoKV2UgemllbiBpbiBkZSBRUS1wbG90IGxpbmtzYm92ZW4gZGF0IGRlIGdlbWlkZGVsZGVuIHZhbiBkZSBub3JtYWFsIHZlcmRlZWxkZSBkYXRhc2V0cyBpbmRlcmRhYWQgb3AgZWVuIHJlY2h0ZSBsaWdnZW4gZW4gZHVzIG5vcm1hYWwgdmVyZGVlbGQgbGlqa2VuLgpCaWogZGUgZ2VtaWRkZWxkZW4gdmFuIGRlIGdhbW1hIGRhdGFzZXRzIG1ldCBncm9vdHRlIDQgemllbiB3ZSBkdWlkZWxpamtlIGFmd2lqa2VuIHZhbiBkZSBub3JtYWxpdGVpdCAoZGUgZGlzdHJpYnV0aWUgaXMgc2NoZWVmIHZlcmRlZWxkIG5hYXIgbGlua3MpLiBUZXN0c3RhdGlzdGlla2VuIGVuIHAtd2FhcmRlbiBiZXJla2VuZCBtZXQgQU5PVkEgZW4gdC10ZXN0ZW4gemlqbiBpbiBkYXQgZ2V2YWwgb25nZWxkaWcuIAoKSW4gZGUgb25kZXJzdGUgcmlqIFFRLXBsb3RzIGthbiBtZW4gemllbiBkYXQgaG9lIGdyb3RlciBkZSBzdGVla3Byb2V2ZW4gd29yZGVuLCBob2UgbWVlciBkZSBnZW1pZGRlbGRlbiBlZW4gbm9ybWFsZSBkaXN0cmlidXRpZSBiZW5hZGVyZW4uCkJpaiBncm90ZXJlIGRhdGFzZXRzIHphbCBkdXMgbWVuIGt1bm5lbiBhcmd1bWVudGVyZW4gZGF0ICoqaGV0IHN0ZWVrcHJvZWZnZW1pZGRlbGRlKiogZWVuIG5vcm1hbGUgdmVyZGVsaW5nIHZvbGd0LiBEaXQgZWZmZWN0LCB3YWFyYmlqIGRlIGdlbWlkZGVsZGVuIHZhbiBlZW4gc3RlZWtwcm9lZiB1aXQgb20gaGV0IGV2ZW4gd2Vsa2UgZGlzdHJpYnV0aWUgZWVuIG5vcm1hbGUgZGlzdHJpYnV0aWUgZ2FhbiBiZW5hZGVyZW4gYWxzIGRlIHN0ZWVrcHJvZWYgbWFhciBncm9vdCBnZW5vZWcgaXMsIG5vZW10IG1lbiBkZSBjZW50cmFsZSBsaW1pZXRzdGVsbGluZy4gQWxzIGplIHN0ZWVrcHJvZWYgZ3Jvb3QgZ2Vub2VnIGlzLCBrYW4gamUgZHVzIGRlIGNlbnRyYWxlIGxpbWlldHN0ZWxsaW5nIGlucm9lcGVuIG9tIGRlIG5vcm1hbGl0ZWl0c2Fzc3VtcHRpZSB0ZSBhYW52YWFyZGVuLgoKQWxzIGVyIGdlZW4gc3RlcmtlIGFyZ3VtZW50ZW4gb20gZGUgbm9ybWFsaXRlaXRzYXNzdW1wdGllIHRlIGFhbnZhYXJkZW4gKGJpanZvb3JiZWVsZCBnZWxpamthYXJkaWdlIGdyb3RlcmUgZGF0YXNldHMgaW4gaGV0IHZlcmxlZGVuIGxpamtlbiBub3JtYWFsIHZlcmRlZWxkKSwgaXMgaGV0IGRvb3JnYWFucyB2ZWlsaWdlciBvbSBkaXQgbmlldCB0ZSBkb2VuIGVuIGVlbiBuaWV0LXBhcmFtZXRyaXNjaGUgdGVzdCB0ZSBnZWJydWlrZW4uCgoqKk1lcmsgb3A6Kiogb29rIGFscyBkZSBhc3N1bXB0aWUgdmFuIGhvbW9zY2VkYXN0aWNpdGVpdCBnZXNjaG9uZGVuIGlzIG9mIG1vZWlsaWprIGthbiB3b3JkZW4gbmFnZWdhYW4gZG9vciBlZW4gdGUga2xlaW5lIHN0ZWVrcHJvZWYsIHp1bGxlbiBkZSB0ZXN0c3RhdGlzdGlla2VuIGVuIHAtd2FhcmRlbiB2ZXJ0ZWtlbmQgemlqbi4gVm9vciBlZW4gdC10ZXN0IGthbiBqZSBub2cgZ2VicnVpayBtYWtlbiB2YW4gZGUgV2VsY2ggdC10ZXN0LCB2b29yIGVlbiBBTk9WQSB6YWwgamUgYmlqIHplZXIgc3RlcmtlIGFmd2lqa2luZ2VuIHZhbiBob21vc2NlZGFzdGljaXRlaXQgb29rIGVlbiBuaWV0LXBhcmFtZXRyaXNjaGUgdGVzdCBtb2V0ZW4gZ2VicnVpa2VuIGVuIGplIHJlc3VsYXRlbiBpbiB0ZXJtZW4gdmFuIGRlIHByb2JhYmlsaXN0aXNjaGUgaW5kZXggbW9ldGVuIGludGVycHJldGVyZW4uCgojIERhdGEgYW5hbHlzZQpXZSB6dWxsZW4gbnUgZGUgc2xhcGxhbnRlbiBkYXRhc2V0IGhlcmV2YWx1ZXJlbiBlbiBuaWV0LXBhcmFtZXRyaXNjaGUgdGVzdGVuIG92ZXJ3ZWdlbi4KCmBgYHtyfQojTGVlcyBkZSBkYXRhIGluCmRhdGFzZXQ9cmVhZC5jc3YoIn4vRHJvcGJveC9QaEQvT25kZXJ3aWpzL1N0YXRpc3RpZWsgQmlvY2hlbWllLzIwMTgxOS9kcm9wYm94U3RhdHMxODE5L2NsYXNzNl9ub25QYXIvaGFsZi92ZXJzZ2V3aWNodF9zbGEudHh0IixoZWFkZXI9VFJVRSkKYGBgCgojIyBEYXRhdmVya2VubmluZwoKYGBge3J9CiMjIFRlbCBoZXQgYWFudGFsIG1ldGluZ2VuIHBlciBiZWhhbmRlbGluZwp0YWJsZShkYXRhc2V0JGJlaGFuZGVsaW5nKQpgYGAKCioqVGFiZWwgMToqKiBmcmVxdWVudGlldGFiZWwgdmFuIGhldCBhYW50YWwgb2JzZXJ2YXRpZXMgcGVyIGJlaGFuZGVsaW5nc2dyb2VwLgoKYGBge3J9CmJveHBsb3QodmVyc2dld2ljaHR+YmVoYW5kZWxpbmcsZGF0YXNldCkKc2V0LnNlZWQoMTApCnN0cmlwY2hhcnQodmVyc2dld2ljaHR+YmVoYW5kZWxpbmcsIGRhdGEgPSBkYXRhc2V0LAogICAgICAgICAgICB2ZXJ0aWNhbCA9IFRSVUUsIG1ldGhvZCA9ICJqaXR0ZXIiLCAKICAgICAgICAgICAgcGNoID0gMTksIGNvbCA9YygiY29yYWwiLCJzdGVlbGJsdWUiLCJnb2xkIiwiYXF1YW1hcmluZTMiKSwgCiAgICAgICAgICAgIGFkZCA9IFRSVUUpCmBgYAoKKipGaWd1dXIgMToqKiBCb3hwbG90IHZhbiBoZXQgdmVyc2dld2ljaHQgaW4gZ3JhbSBwZXIgYmVoYW5kZWxpbmdzZ3JvZXAuIERlIHB1bnRlbiB6aWpuIGRlIGluZGl2aWR1ZWxlIG1ldGluZ2VuLgoKSW4gZGUgZnJlcXVlbnRpZXRhYmVsIChUYWJlbCAxKSB6aWVuIHdlIGRhdCBlciBzbGVjaHRzIDcgb2JzZXJ2YXRpZXMgcGVyIGdyb2VwIHppam4uCkRlIGdlbWV0ZW4gdmVyc2dld2ljaHRlbiBiaW5uZW4gZGUgcmVmb2FrIGJlaGFuZGVsaW5nc2dyb2VwIHppam4gemVlciB2ZXJnZWxpamtiYWFyIG1ldCBkaWUgdmFuIGRlIGNvbnRyb2xlZ3JvZXAuCkRlIGdlbWV0ZW4gdmVyc2dld2ljaHRlbiBiaW5uZW4gZGUgY29iYyBlbiBkZSBjb21wb3N0IGJlaGFuZGVsaW5nc2dyb2VwZW4gemlqbiBtZXJrZWxpamsgaG9nZXIgZGFuIGRpZSBiaW5uZW4gZGUgY29udHJvbGVncm9lcC4KRGUgZ2VtZXRlbiB2ZXJzZ2V3aWNodGVuIGJpbm5lbiBkZSBjb21wb3N0IGJlaGFuZGVsaW5nc2dyb2VwIGxpZ2dlbiBnZW1pZGRlbGQgZ2V6aWVuIGlldHMgaG9nZXIgZGFuIGRpZSBiaW5uZW4gaW4gZGUgY29iYyBncm9lcCwgbWFhciBlciBpcyBlZW4gZ3JvdGUgb3ZlcmxhcCB0dXNzZW4gZ2VtZXRlbiB3YWFyZGVzLgpHZWVuIGVua2VsZSBiZWhhbmRlbGluZ3Nncm9lcCBiZXZhdCB1aXRzY2hpZXRlcnMuCkRlIG1ldGluZ2VuIGJpbm5lbiBpZWRlcmUgYmVoYW5kZWxpamtzZ3JvZXAgbGlqa3Qgc3ltbWV0cmlzY2ggdmVyZGVlbGQuCkRlIHZhcmlhbnRpZSB2YW4gZGUgbWV0aW5nZW4gbGlqa3QgbmlldCBzdGVyayBhZiB0ZSB3aWprZW4gdHVzc2VuIGRlIGJlaGFuZGVsaW5nc2dyb2VwZW4uCkhldCBiZXJlaWsgZW4gZGUgc3ByZWlkaW5nIHZhbiBkZSB3YWFyZGVuIHR1c3NlbiBkZSB2ZXJzY2hpbGxlbmRlIGdyb2VwZW4gaXMgemVlciB2ZXJnZWxpamtiYWFyLgoKIyAgS3J1c2thbC1XYWxsaXMgUmFuayBUZXN0CkRvb3IgZGUgd2VpbmlnIGRhdGFwdW50ZW4gaXMgaGV0IG1vZWlsaWprIG9tIGRlIGRpc3RyaWJ1dGlvbmVsZSBhc3N1bXB0aWVzIHZvb3IgZGUgcGFyYW1ldHJpc2NoZSBBTk9WQSB0ZSBjb250cm9sZXJlbiAobm9ybWFsaXRlaXQgZW4gZ2VsaWprZSB2YXJpYW50aWUgdHVzc2VuIGRlIGdyb2VwZW4pLgpEZSBLcnVza2FsLVdhbGxpcyBSYW5rIFRlc3QgKEtXLXRlc3QpIGlzIGVlbiBuaWV0LXBhcmFtZXRyaXNjaGUgdmFyaWFudCB2YW4gZGUgQU5PVkEuCkRlemUgdGVzdCBsYWF0IG9ucyB0b2Ugb20gZGUgZGlzdHJpYnV0aW9uZWxlIGFzc3VtcHRpZXMgdGUgcmVsYXhlcmVuLgoqKkxldCBlcm9wIGRhdCBkZSBhc3N1bXB0aWUgdmFuIG9uYWZoYW5rZWxpamtoZWlkIHR1c3NlbiBkZSBvYnNlcnZhdGllcyBub2cgc3RlZWRzIG1vZXQgb3BnYWFuISoqCgpBbHMgd2Ugd2lsbGVuIHRlc3RlbiB2b29yIGVlbiB2ZXJzY2hpbCB0dXNzZW4gZGUgbWVkaWFhbiB2YW4gZGUgdmVyc2NoaWxsZW5kZSBiZWhhbmRlbGluZ3Nncm9lcGVuLCBkYW4gbW9ldGVuIHdlIHVpdGdhYW4gdmFuIGRlIGxvY2F0aWUgc2hpZnQgYXNzdW1wdGllLgpPbmRlciBkZSBsb2NhdGllIHNoaWZ0IGFzc3VtcHRpZSB2ZXJvbmRlcnN0ZWxsZW4gd2UgZGF0IGRlIHZlcnNjaGlsbGVuZGUgZ3JvZXBlbiBvbmRlcmxpbmcgbm9nIHN0ZWVkcyBkZXplbGZkZSBkaXN0cmlidXRpZSB2b2xnZW4gKGRpdCBob2VmdCB1aXRlcmFhcmQgbmlldCBub29kemFrZWxpamsgZWVuIG5vcm1hbGUgdmVyZGVsaW5nIHRlIHppam4sIGVsa2UgdmVyZGVsaW5nIGlzIGdvZWQsIHpvbGFuZyBoZXQgbWFhciBpbiBiZWlkZSBncm9lcGVuIGRlemVsZmRlIHZlcmRlbGluZyBpcykuIAoKKipXYW5uZWVyIGplIGtpamt0IG5hYXIgZGUgYm94cGxvdHMgaW4gRmlndXVyIDEsIGRlbmsgamUgZGFuIGRhdCBkZSBsb2NhdGllIHNoaWZ0IGFzc3VtcHRpZSBhYW5uZW1lbGlqayBpcz8qKgoKIERlIHJhbmdlIGVuIHNwcmVpZGluZyB2YW4gZGUgd2FhcmRlbiB0dXNzZW4gZGUgdmVyc2NoaWxsZW5kZSBncm9lcGVuIGlzIG9wIGhldCBlZXJzdGUgemljaHQgemVlciB2ZXJnZWxpamtiYWFyLAogbWFhciBqZSB6aWV0IGluIGRlIGJveHBsb3RzIHdlbCBncm90ZSB2ZXJzY2hpbGxlbiBpbiBpbnRlcnF1YW50aWVsIGFmc3RhbmRlbiAoYnZiIHR1c3NlbiBDT0JDIGVuIHJlZm9hayBib3hwbG90KS4KIEVpZ2VubGlqayBoZWJiZW4gd2UgdGUgd2VpbmlnIGRhdGEgb20gZGV6ZSBhc3N1bXB0aWUgdGUgdmVyaWZpZXJlbi4KCldhbm5lZXIgd2UgbmlldCBiZXJlaWQgemlqbiBvbSBkZSBsb2NhdGllIHNoaWZ0IGFzc3VtcHRpZSB0ZSBhYW52YWFyZGVuLCBkYW4ga3VubmVuIHdlIGRlIGRpc3RyaWJ1dGlvbmVsZSBhc3N1bXB0aWVzIG5vZyB2ZXJkZXIgcmVsYXhlcmVuLCBlbiB0ZXN0ZW4gd2UgaW4gdGVybWVuIHZhbiBwcm9iYWJpbGlzdGlzY2hlIGluZGV4ZW4uCkhpZXIgdGVzdGVuIHdlIGluIGhldCBnZXZhbCB2YW4gdHdlZSBncm9lcGVuIGRlIGthbnMgZGF0IGVlbiB3aWxsZWtldXJpZ2UgbWVldHdhYXJkZSB1aXQgZGUgZWVyc3RlIGdyb2VwIGtvbXQgZ3JvdGVyIG9mIGdlbGlqayAoIiRcZ2VxJCIpIGlzIGRhbiBlZW4gd2lsbGVrZXVyaWdlIG1lZXR3YWFyZGUgdWl0IGRlIHR3ZWVkZSBncm9lcC4KCiMjIEh5cG90aGVzZQoqKlByb2JlZXIgbnUgZWVucyBkZSBudWxoeXBvdGhlc2Ugb3AgdGUgc3RlbGxlbiBpbiB0ZXJtZW4gdmFuIGRlIG9uZGVyem9la3N2cmFhZz8qKgoKICoqRGUgbnVsaHlwb3RoZXNlKiogc3RlbHQgZGF0IGRlIHZlcmRlbGluZ2VuIHZhbiBkZSB2ZXJzZ2V3aWNodGVuIHZhbiBzbGFwbGFudGVuIGdlbGlqayB6aWpuIGluIGRlIHZpZXIgdHlwZXMgZ3JvbmQuCiAKICoqRGUgYWx0ZXJuYXRpZXZlIGh5cG90aGVzZSoqIHN0ZWx0IGRhdCBkZSBrYW5zIGRhdCBoZXQgdmVyc2dld2ljaHQgdmFuIGVlbiB3aWxsZWtldXJpZ2Ugc2xhcGxhbnQgdWl0IG1pbnN0ZW5zIMOpw6luIHZhbiBkZSB2aWVyIHNvb3J0ZW4gZ3JvbmQgZ3JvdGVyIGlzIGRhbiBvZiBnZWxpamsgaXMgYWFuICAoIiRcZ2VxJCIpIGhldCB2ZXJzZ2V3aWNodCB2YW4gZWVuIHdpbGxla2V1cmlnZSBzbGFwbGFudCB1aXQgbWluc3RlbnMgw6nDqW4gdmFuIGRlIGFuZGVyZSBzb29ydGVuIGdyb25kIHZlcnNjaGlsdCB2YW4gNTAlLgoKCiMjIFN0YXRpc3Rpc2NoZSB0ZXN0CgpTaW5kcyB3ZSB0ZSBtYWtlbiBoZWJiZW4gbWV0IGVlbiBrbGVpbiBhYW50YWwgb2JzZXJ2YXRpZXMgcGVyIGdyb2VwIGlzIGhldCBuaWV0IGFhbiB0ZSByYWRlbiBvbSBkZSBhc3ltcHRvdGlzY2hlIEtXLXRlc3QgdGUgZ2VicnVpa2VuIG9tIGVlbiBwLXdhYXJkZSB0ZSBiZXJla2VuZW4uCkRlemUgc3RlbHQgbmFtZWxpamsgZGF0IGplIHRlc3RzdGF0aXN0aWVrIG9uZGVyIGRlIG51bGh5cG90aGVzZSBlZW4gJFxjaGleMiQgZGlzdHJpYnV0aWUgdm9sZ3QgKGRlIG51bGRpc3RyaWJ1dGllKSB3YW5uZWVyIGhldCBhYW50YWwgb2JlcnNlcnZhdGllcyBwZXIgZ3JvZXAgbmFhciBvbmVpbmRpZyBuZWlndCAoZHVzIHZvb3IgZWVuIGdyb290IGFhbnRhbCBvYnNlcnZhdGllcykuCgpXYW5uZWVyIGplIGVlbiBiZXBlcmt0IGFhbnRhbCBvYnNlcnZhdGllcyBoZWJ0LCBpcyBoZXQgYmV0ZXIgZGUgbnVsZGlzdHJpYnV0aWUgZXhhY3QgdGUgYmVyZWtlbmVuIHZpYSBwZXJtdXRhdGllcy4KRGl0IGlzIHVpdGVyYWFyZCBjb21wdXRhdGlvbmVlbCBvbm1vZ2VsaWprLCB3YW50IG1ldCA0IGdyb2VwZW4gdmFuIGVsayA3IG9ic2VydmF0aWVzIGJlc3RhYW4gZXIgYHIgZmFjdG9yaWFsKDI4KS9mYWN0b3JpYWwoNyleNGAgbW9nZWxpamtlIHBlcm11dGF0aWVzLgpHZWx1a2tpZyBpcyBoZXQgbWVlc3RhbCB2b2xkb2VuZGUgb20gZGUgZXhhY3RlIG51bGRpc3RyaWJ1dGllIHRlIGJlbmFkZXJlbiBtZXQgZWVuIGtsZWluZXIgYWFudGFsIHBlcm11dGF0aWVzLgoKKipWb2VyIGVlbiBLVyB0ZXN0IHVpdCBvcCBkZSBkYXRhIG1ldCBiZWh1bHAgdmFuIGVlbiBncm9vdCBhYW50YWwgcGVybXV0YXRpZXMgKGJ2LiAxMDAwMCkuKioKKiooVGlwOiB6aWUgY3Vyc3VzIGh0dHA6Ly91c2Vycy51Z2VudC5iZS9+bGNsZW1lbnQvc3RhdGlzdGllay8gdm9vciBjb2RlIHZvb3JiZWVsZGVuKSoqCioqV2F0IGthbiBqZSBiZXNsdWl0ZW4gdWl0IGRpdCByZXN1bHRhYXQ/KioKCmBgYHtyfQpsaWJyYXJ5KGNvaW4pCmt3UGVybSA8LSBrcnVza2FsX3Rlc3QodmVyc2dld2ljaHR+YmVoYW5kZWxpbmcsZGF0YXNldCwgZGlzdHJpYnV0aW9uPWFwcHJveGltYXRlKEI9MTAwMDAwKSkKa3dQZXJtCmBgYApXZSB6aWVuIGVlbiBleHRyZWVtIHNpZ25pZmljYW50IGVmZmVjdCAocCA8PCAuMDAxKSB2YW4gaGV0IHR5cGUgYmVtZXN0aW5nIG9wIGhldCB2ZXJzZ2V3aWNodCB2YW4gc2xhcGxhbnRlbi4KT3AgaGV0IDUlIHNpZ25pZmljYW50aWVuaXZlYXUgc3RlbGxlbiB3ZSBkYXRkZSBrYW5zIGRhdCBlZW4gd2lsbGVrZXVyaWdlIHNsYXBsYW50IHVpdCBtaW5zdGVucyDDqcOpbiB2YW4gZGUgdmllciB0eXBlcyBncm9uZCBlZW4gZ3JvdGVyIGRhbiBvZiBnZWxpamsgKCIkXGdlcSQiKSB2ZXJzZ2V3aWNodCBoZWVmdCB2ZXJnZWxla2VuIG1ldCBlZW4gd2lsbGVrZXVyaWdlIHNsYXBsYW50IHVpdCBtaW5zdGVucyDDqcOpbiB2YW4gZGUgYW5kZXJlIHR5cGVzIGdyb25kIHZlcnNjaGlsdCB2YW4gNTAlLgogCiAqKk1lcmsgb3A6KiogZG9vcmRhdCB3ZSBkZSBwLXdhYXJkZSBiZW5hZGVyZCBoZWJiZW4gYWFuIGRlIGhhbmQgdmFuIHNpbXVsYXRpZXMsIGthbiBkZSBwLXdhYXJkZSBpbmRpZW4gd2UgZGUgY29kZSBvcG5pZXV3IHVpdHZvZXJlbiAoZW4gZHVzIG9vayBtZXQgamUgY29sbGVnYSBuYWFzdCBqb3UpLiBNZXJrIG9wIGRhdCBkZXplIHZhcmlhdGllIGluIHAtd2FhcmRlIHpvdSBtb2V0ZW4gdmVybWluZGVyZW4gYWxzIHdlIGhldCBhYW50YWwgcGVybXV0YXRpZXMgem91ZGVuIG9wZHJpanZlbiwgb21kYXQgd2UgZGFuIGRpY2h0ZXIgaW4gZGUgYnV1cnQga29tZW4gYmlqIGRlIGV4YWN0ZSBudWxkaXN0cmlidXRpZS4gCgpBbHMgd2Ugd2lsbGVuIHdldGVuIGluIHdlbGtlIHNvb3J0ZW4gZ3JvbmQgZXIgbnUganVpc3QgZWVuIHNpZ25pZmljYW50IHZlcnNjaGlsIGluIHZlcnNnZXdpY2h0IG9wdHJlZWR0LCB6YWwgbWVuIGVlbiBwb3N0LWhvYyBhbmFseXNlIG1vZXRlbiBkb2VuLgoKIyMgUG9zdC1ob2MgYW5hbHlzZQpab2FscyBiaWogZGUgcGFyYW1ldHJpc2NoZSBBTk9WQSB6YWwgamUgb29rIGJpaiBkZSBuaWV0LXBhcmFtZXRyaXNjaGUgS1cgdGVzdCBwYWFyc2dld2lqemUgdGVzdGVuIG1vZXRlbiB1aXR2b2VyZW4gb20gb25kZXJsaW5nZSB2ZXJzY2hpbGxlbiBpbiB2ZXJzZ2V3aWNodCB0dXNzZW4gZGUgc2xhcGxhbnRlbiB0ZSBkZXRlY3RlcmVuLgpEaXQgenVsbGVuIHVpdGVyYWFyZCBvb2sgbmlldC1wYXJhbWV0cmlzY2hlIHRlc3RlbiB6aWpuIHpvYWxzIGRlIFdpbGNveG9uLU1hbm4tV2hpdG5leSBUZXN0IChXTVcgdGVzdCkuCkFscyBqZSBkZSBrZXV6ZSBnZW1hYWt0IGhlYnQgb20gYmlqIGRlIEtXIHRlc3QgZGUgbG9jYXRpZSBzaGlmdCBhc3N1bXB0aWUgdGUgdmVyd2VycGVuIGRhbiB6YWwgamUgZGl0IGhpZXIgdGVydWcgZG9lbiBlbiBkZSByZXN1bHRhdGVuIGluIHRlcm1lbiB2YW4gZGUgcHJvYmFiaWxpc3Rpc2NoZSBpbmRleCBpbnRlcnByZXRlcmVuLgoKKipXYXQgemFsIG51IGRlIG51bCBlbiBhbHRlcm5hdGlldmUgaHlwb3RoZXNlIHppam4gdm9vciBpZWRlcmUgcGFhcnNnZXdpanplIHRlc3Q/KioKCiAqKkRlIG51bGh5cG90aGVzZSoqIHN0ZWx0IGRhdCBkZSB2ZXJkZWxpbmcgdmFuIGhldCB2ZXJzZ2V3aWNodCB2YW4gc2xhcGxhbnRlbiBnZWxpamsgaXMgdm9vciBiZWlkZSB0eXBlcyBncm9uZC4KIAogRGUgKiphbHRlcm5hdGlldmUgbnVsaHlwb3RoZXNlKiogc3RlbHQgZGF0IGRlIGthbnMgZGF0IGhldCB2ZXJzZ2V3aWNodCB2YW4gZWVuIHdpbGxla2V1cmlnZSBzbGFwbGFudCB1aXQgb3BnZWdyb2VpZCBpbiBkZSBlbmUgc29vcnQgZ3JvbmQgaG9nZXIgaXMgZGFuIG9mIGdlbGlqayBpcyBhYW4gKCIkXGdlcSQiKSBoZXQgdmVyc2dld2ljaHQgdmFuIGVlbiB3aWxsZWtldXJpZ2Ugc2xhcGxhbnQgdWl0IGRlIGFuZGVyZSBzb29ydCBncm9uZCB2ZXJzY2hpbGxlbmQgaXMgdmFuIDUwJS4KCgoqKlZvZXIgZWVuIFdNVyBwb3N0LWhvYyBhbmFseXNlIHVpdCBvcCBkZSBkYXRhLioqCgogV2UgZG9lbiBlZW4gcGFhcnNnZXdpanplIFdNVyB0ZXN0IHpvYWxzIGJlc2NocmV2ZW4gaW4gZGUgY3VydXMuCmBgYHtyfQpwYWlyd2lzZS53aWxjb3gudGVzdChkYXRhc2V0JHZlcnNnZXdpY2h0LGRhdGFzZXQkYmVoYW5kZWxpbmcpCmBgYAogV2UgemllbiBpbiBkZSBvdXRwdXQgZWVuIGZvdXRtZWxkaW5nOiBgY2Fubm90IGNvbXB1dGUgZXhhY3QgcC12YWx1ZSB3aXRoIHRpZXNgLgogRGl0IGlzIG9tZGF0IGRlIGBwYWlyd2lzZS53aWxjb3gudGVzdCgpYCBmdW5jdGllIGRlIHN0YW5kYWFyZCBgd2lsY294LnRlc3QoKWAgZnVuY3RpZSBnZWJydWlrdCBpbiBSLgogSW4gZGUgaGVscCB2YW4gZGV6ZSBmdW5jdGllIHppZW4gd2UgZGF0IGRlemUgZnVuY3RpZSBzdGFuZGFhcmQgZWVuIGV4YWN0ZSB0ZXN0IGRvZXQgbWFhciBpbiBkZSBhYW53ZXppZ2hlaWQgdmFuIHRpZXMgZGl0IG5pZXQga2FuIGRvZW4gZW4gdGVydWdyaWpwdCBuYWFyIGVlbiBhc3ltcHRvdGlzY2hlIHRlc3QuCldlIGt1bm5lbiBlY2h0ZXIgd2VsIGV4YWN0ZSBwLXdhYXJkZW4gYmVrb21lbiBtZXQgZGUgYHdpbGNveF90ZXN0KClgIHVpdCBkZSBgY29pbmAgcGFja2FnZSB2b29yIGllZGVyZSBjb21iaW5hdGllIHZhbiBiZWhhbmRlbGluZyBlbiB2ZXJ2b2xnZW5zIHRlIGNvcnJpZ2VyZW4gdm9vciBtdWx0aXBsZSB0ZXN0aW5nIG1ldCBkZSBgcC5hZGp1c3QoKWAgZnVuY3RpZS4KYGBge3J9CmxpYnJhcnkoY29pbikKIyMgdGVsIGhldCBhYW50YWwgb2JzZXJ2YXRpZXMgcGVyIGdyb2VwCm5Hcm9lcCA8LSB0YWJsZShkYXRhc2V0JGJlaGFuZGVsaW5nKQojIyBiZXJla2VuIG1ldCBkZSB3aWxjb3hvbiB0ZXN0IGVlbiBwLXdhYXJkZSB2b29yIGllZGVyZSBjb21iaW5hdGllIHZhbiBncm9uZHNvb3J0ZW4KYmVoYW5kZWxpbmdlbiA9IChsZXZlbHMoZGF0YXNldCRiZWhhbmRlbGluZykpCnB2YWx1ZXMgPC0gY29tYm4oYmVoYW5kZWxpbmdlbiwyLGZ1bmN0aW9uKHgpewogICMjIERvZSBlZW4gcGFhcnNnZXdpanplIFdNVyB0ZXN0LgogIHRlc3QgPSB3aWxjb3hfdGVzdCh2ZXJzZ2V3aWNodH5iZWhhbmRlbGluZyxzdWJzZXQoZGF0YXNldCxiZWhhbmRlbGluZyVpbiV4KSwgZGlzdHJpYnV0aW9uID0gJ2V4YWN0JykKICAjIyBOZWVtIGRlIHB3YWFyZGUgdWl0IG91dHB1dCB2YW4gZGUgdGVzdAogIHB2YWx1ZSh0ZXN0KQp9KQojIyBEb2UgZWVuIGNvcnJlY3RpZSB2b29yIG11bHRpcGxlIHRlc3RpbmcgbWV0IEhvbG0gKGplIGthbiBldmVudHVlZWwgb29rIGtpZXplbiB2b29yIEJvbmZlcnJvbmkgZXRjIC4uLikKcHZhbHVlc19ob2xtID0gcC5hZGp1c3QocHZhbHVlcyxtZXRob2QgPSAnaG9sbScpIAoKICMjIGxpbmsgZGUgcHdhYXJkZSBtZXQgZGUganVpc3RlIHBhYXJzZ2V3aWp6ZSB0ZXN0Cm5hbWVzKHB2YWx1ZXNfaG9sbSkgPC0gY29tYm4obGV2ZWxzKGRhdGFzZXQkYmVoYW5kZWxpbmcpLDIscGFzdGUsY29sbGFwc2U9Il9WU18iKQpwdmFsdWVzX2hvbG0KYGBgCldlIHppZW4gaW5kZXJkYWFkIGRhdCBkZSBleGFjdGUgcC13YWFyZGVuIGFmd2lqa2VuIHZhbiBkZSBwLXdhYXJkZW4gYmVyZWtlbmQgZG9vciBkZSBgcGFpcndpc2Uud2lsY294LnRlc3QoKWAgZnVuY3RpZS4KV2UgenVsbGVuIHZlcmRlciB3ZXJrZW4gbWV0IGRlemUgbGFhdHN0ZSBwLXdhYXJkZW4uCldlIHppZW4gZGF0IGVyIGFsbGVlbiBzaWduaWZpY2FudGUgdmVyc2NoaWxsZW4gemlqbiB0dXNzZW4gZGUgc2xhcGxhbnRlbiBkaWUgZ2Vncm9laWQgemlqbiBpbiBjb21wb3N0IHRlbiBvcHppY2h0ZSB2YW4gZGUgcGxhbnRlbiBkaWUgem9uZGVyIGNvbXBvc3Qgb3BnZWdyb2VpZCB6aWpuLgoKKipLYW4gamUgbnUgb29rIGFhbiBkZSBoYW5kIHZhbiBkZSBNYW5uLVdoaXRuZXkgdGVzdHN0YXRpc3RpZWsgZWVuIHB1bnRzY2hhdHRpbmcgZ2V2ZW4gdm9vciBkZSBwcm9iYWJpbGlzdGlzY2hlIGluZGV4PyoqCgpgYGB7cn0KIyMgdGVsIGhldCBhYW50YWwgb2JzZXJ2YXRpZXMgcGVyIGdyb2VwCm5Hcm9lcCA8LSB0YWJsZShkYXRhc2V0JGJlaGFuZGVsaW5nKQojIyBiZXJla2VuIGVlbiBwcm9iYWJpbGlzdGlzY2hlIGluZGV4IHZvb3IgaWVkZXJlIG1vZ2VsaWprZSBjb21iaW5hdGllIHZhbiBncm9uZHNvb3J0ZW4KYmVoYW5kZWxpbmdlbiA9IChsZXZlbHMoZGF0YXNldCRiZWhhbmRlbGluZykpCnByb2JJbmQgPC0gY29tYm4oYmVoYW5kZWxpbmdlbiwyLGZ1bmN0aW9uKHgpewogICMjIEJlcmtla2VuIGRlIFUxIHN0YXRpc3RpZWsKICBVMSA9IHdpbGNveC50ZXN0KHZlcnNnZXdpY2h0fmJlaGFuZGVsaW5nLHN1YnNldChkYXRhc2V0LGJlaGFuZGVsaW5nJWluJXgpKSRzdGF0aXN0aWMKICAjIyBCZXJla2VuIHByb2JhYmlsaXN0aXNjaGUgaW5kZXgKICBVMS9wcm9kKG5Hcm9lcFt4XSkKfSkKbmFtZXMocHJvYkluZCkgPC0gY29tYm4obGV2ZWxzKGRhdGFzZXQkYmVoYW5kZWxpbmcpLDIscGFzdGUsY29sbGFwc2U9Il9WU18iKQpwcm9iSW5kCmBgYApXZSB6aWVuIGluIGRlIG91dHB1dCBvcG5pZXV3IGRlemVsZmRlIGZvdXRtZWxkaW5nOiBgY2Fubm90IGNvbXB1dGUgZXhhY3QgcC12YWx1ZSB3aXRoIHRpZXNgIG9tZGF0IHdlIHRlcnVnIGRlIGB3aWxjb3gudGVzdCgpYCBmdW5jdGllIGdlYnJ1aWtlbi4gTWFhciBkaXQgaXMgaGllciBnZWVuIHByb2JsZWVtIG9tZGF0IHdlIG5pZXQgZGUgcC13YWFyZGUgbm9kaWcgaGViYmVuIG1hYXIgZGUgVTEgc3RhdGlzdGllay4gVTEgaXMgaGV0IGFhbnRhbCBrZWVyIGRhdCBlZW4gb2JzZXJ2YXRpZSB1aXQgZGUgZWVyc3RlIGdyb2VwIGdyb3RlciBvZiBnZWxpamsgaXMgYWFuIGVlbiBvYnNlcnZhdGllIHVpdCBkZSB0d2VlZGUgZ3JvZXAgZW4gaXMgZHVzIGdlZGVmaW5pZWVyZCBiaWogdGllcyAoemllIG9vayBjdXJzdXMpLgoKKipIb2UgaW50ZXJwcmV0ZWVyIGplIGRlIHJlc3VsdGF0ZW4gdmFuIGRlIFdNVyB0ZXN0ZW4/KioKCldlIHZpbmRlbiBzaWduaWZpY2FudGUgdmVyc2NoaWxsZW4gaW4gZGUgdmVyZGVsaW5nZW4gdmFuIHZlcnNnZXdpY2h0IGluIHZlcmdlbGlqa2luZyBtZXQgZGUgY29udHJvbGUgYmVoYW5kZWxpbmcuCkRlIGthbnMgZGF0IGhldCB2ZXJzZ2V3aWNodCB2b29yIHNsYXBsYW50ZW4gb3BnZWdyb2VpZCBpbiBncm9uZCBtZXQgY29tcG9zdCBob2dlciBvZiBnZWxpamsgaXMgZGFuICgiJFxnZXEkIikgaGV0IHZlcnNnZXdpY2h0IHZvb3Igc2xhcGxhbnRlbiBvcGdlZ3JvZWlkIGluIGRlIGNvbnRyb2xlIGJlaGFuZGVsaW5nIGlzIGdlbGlqayBhYW4gMTAwJSAgKFdNVyB0ZXN0LCBhYW5nZXBhc3RlIHAtd2FhcmRlIDwgMC4wMSkuCkdlbGlqa2FhcmRpZywgZGUga2FucyBkYXQgaGV0IHZlcnNnZXdpY2h0IHZvb3Igc2xhcGxhbnRlbiBvcGdlZ3JvZWlkIGluIGdyb25kIG1ldCBjb21wb3N0IGVuIGJpb2NoYXIgaG9nZXIgb2YgZ2VsaWprICgiJFxnZXEkIikgaXMgZGFuIGhldCB2ZXJzZ2V3aWNodCB2b29yIHNsYXBsYW50ZW4gb3BnZWdyb2VpZCBpbiBkZSBjb250cm9sZSBiZWhhbmRlbGluZyBpcyBnZWxpamsgYWFuIDk4LjAlICAoV01XIHRlc3QsIGFhbmdlcGFzdGUgcC13YWFyZGUgPCAwLjAxKS4KCkJvdmVuZGllbiB2aW5kZW4gd2Ugb29rIHNpZ25pZmljYW50ZSB2ZXJzY2hpbGxlbiBpbiBkZSB2ZXJkZWxpbmdlbiB2YW4gdmVyc2dld2ljaHQgaW4gdmVyZ2VsaWpraW5nIG1ldCBkZSBiaW9jaGFyIGJlaGFuZGVsaW5nLgpEZSBrYW5zIGRhdCBoZXQgdmVyc2dld2ljaHQgdm9vciBzbGFwbGFudGVuIG9wZ2Vncm9laWQgaW4gZ3JvbmQgbWV0IGJpb2NoYXIgaG9nZXIgb2YgZ2VsaWprICgiJFxnZXEkIikgaXMgZGFuIGhldCB2ZXJzZ2V3aWNodCB2b29yIHNsYXBsYW50ZW4gb3BnZWdyb2VpZCBpbiBncm9uZCBtZXQgY29tcG9zdCBpcyBnZWxpamsgYWFuIDEwMCUgIChXTVcgdGVzdCwgYWFuZ2VwYXN0ZSBwLXdhYXJkZSA8IDAuMDEpLgpPb2ssIGRlIGthbnMgZGF0IGhldCB2ZXJzZ2V3aWNodCB2b29yIHNsYXBsYW50ZW4gb3BnZWdyb2VpZCBpbiBncm9uZCBtZXQgYmlvY2hhciBob2dlciBvZiBnZWxpamsgKCIkXGdlcSQiKSBpcyBkYW4gaGV0IHZlcnNnZXdpY2h0IHZvb3Igc2xhcGxhbnRlbiBvcGdlZ3JvZWlkIGluIGdyb25kIG1ldCBjb21wb3N0IGVuIGJpb2NoYXIgaXMgZ2VsaWprIGFhbiAxMDAlICAoV01XIHRlc3QsIGFhbmdlcGFzdGUgcC13YWFyZGUgPCAwLjAxKS4KCgpXZSB2aW5kZW4gZ2VlbiBzaWduaWZpY2FudCB2ZXJzY2hpbGxlbmRlIHZlcmRlbGluZ2VuIGluIHZlcnNnZXdpY2h0IHZhbiBzbGFwbGFudGVuIHR1c3NlbiBncm9uZCBtZXQgYmlvY2hhciBlbiBkZSBjb250cm9sZSBncm9uZCBlbiB0dXNzZW4gZGUgZ3JvbmQgbWV0IGNvbXBvc3QgZW4gZGUgZ3JvbmQgbWV0IGNvbXBvc3QgZW4gYmlvY2hhci4KCiMgQ29uY2x1c2llCgpXZSB6aWVuIGRhdCBlciBlZW4gZXh0cmVlbSBzaWduaWZpY2FudCBlZmZlY3QgKHAgPDwgLjAwMSkgaXMgdmFuIGhldCB0eXBlIGdyb25kIG9wIGhldCB2ZXJzZ2V3aWNodCB2YW4gc2xhcGxhbnRlbi4KT3AgaGV0IDUlIHNpZ25pZmljYW50aWVuaXZlYXUgc3RlbGxlbiB3ZSBkYXQgZGUga2FucyBkYXQgaGV0IHZlcnNnZXdpY2h0IHZhbiBlZW4gd2lsbGVrZXVyaWdlIHNsYXBsYW50IG9wZ2Vncm9laWQgaW4gZGUgZW5lIHNvb3J0IGdyb25kIGhvZ2VyIGlzIGRhbiBvZiBnZWxpamsgaXMgKCIkXGdlcSQiKSBhYW4gaGV0IHZlcnNnZXdpY2h0IHZhbiBlZW4gd2lsbGVrZXVyaWdlIHNsYXBsYW50IHVpdCBkZSBhbmRlcmUgc29vcnRlbiBncm9uZCBleHRyZWVtIHNpZ25pZmljYW50IHZlcnNjaGlsdCB2YW4gNTAlLgoKV2UgdmluZGVuIHNpZ25pZmljYW50ZSB2ZXJzY2hpbGxlbiBpbiBkZSB2ZXJkZWxpbmdlbiB2YW4gdmVyc2dld2ljaHQgaW4gdmVyZ2VsaWpraW5nIG1ldCBkZSBjb250cm9sZSBiZWhhbmRlbGluZy4KRGUga2FucyBkYXQgaGV0IHZlcnNnZXdpY2h0IHZvb3Igc2xhcGxhbnRlbiBvcGdlZ3JvZWlkIGluIGdyb25kIG1ldCBjb21wb3N0IGhvZ2VyIG9mIGdlbGlqayAoIiRcZ2VxJCIpIGlzIGRhbiBoZXQgdmVyc2dld2ljaHQgdm9vciBzbGFwbGFudGVuIG9wZ2Vncm9laWQgaW4gZGUgY29udHJvbGUgYmVoYW5kZWxpbmcgaXMgZ2VsaWprIGFhbiAxMDAlICAoV01XIHRlc3QsIGFhbmdlcGFzdGUgcC13YWFyZGUgPCAwLjAxKS4KR2VsaWprYWFyZGlnLCBkZSBrYW5zIGRhdCBoZXQgdmVyc2dld2ljaHQgdm9vciBzbGFwbGFudGVuIG9wZ2Vncm9laWQgaW4gZ3JvbmQgbWV0IGNvbXBvc3QgZW4gYmlvY2hhciBob2dlciBvZiBnZWxpamsgKCIkXGdlcSQiKSBpcyBkYW4gaGV0IHZlcnNnZXdpY2h0IHZvb3Igc2xhcGxhbnRlbiBvcGdlZ3JvZWlkIGluIGRlIGNvbnRyb2xlIGJlaGFuZGVsaW5nIGlzIGdlbGlqayBhYW4gOTguMCUgIChXTVcgdGVzdCwgYWFuZ2VwYXN0ZSBwLXdhYXJkZSA8IDAuMDEpLgoKQm92ZW5kaWVuIHZpbmRlbiB3ZSBvb2sgc2lnbmlmaWNhbnRlIHZlcnNjaGlsbGVuIGluIGRlIHZlcmRlbGluZ2VuIHZhbiB2ZXJzZ2V3aWNodCBpbiB2ZXJnZWxpamtpbmcgbWV0IGRlIGJpb2NoYXIgYmVoYW5kZWxpbmcuCkRlIGthbnMgZGF0IGhldCB2ZXJzZ2V3aWNodCB2b29yIHNsYXBsYW50ZW4gb3BnZWdyb2VpZCBpbiBncm9uZCBtZXQgYmlvY2hhciBob2dlciBvZiBnZWxpamsgKCIkXGdlcSQiKSBpcyBkYW4gaGV0IHZlcnNnZXdpY2h0IHZvb3Igc2xhcGxhbnRlbiBvcGdlZ3JvZWlkIGluIGdyb25kIG1ldCBjb21wb3N0IGlzIGdlbGlqayBhYW4gMTAwJSAgKFdNVyB0ZXN0LCBhYW5nZXBhc3RlIHAtd2FhcmRlIDwgMC4wMSkuCk9vaywgZGUga2FucyBkYXQgaGV0IHZlcnNnZXdpY2h0IHZvb3Igc2xhcGxhbnRlbiBvcGdlZ3JvZWlkIGluIGdyb25kIG1ldCBiaW9jaGFyIGhvZ2VyIG9mIGdlbGlqayAoIiRcZ2VxJCIpIGlzIGRhbiBoZXQgdmVyc2dld2ljaHQgdm9vciBzbGFwbGFudGVuIG9wZ2Vncm9laWQgaW4gZ3JvbmQgbWV0IGNvbXBvc3QgZW4gYmlvY2hhciBpcyBnZWxpamsgYWFuIDEwMCUgIChXTVcgdGVzdCwgYWFuZ2VwYXN0ZSBwLXdhYXJkZSA8IDAuMDEpLgoKCldlIHZpbmRlbiBnZWVuIHNpZ25pZmljYW50IHZlcnNjaGlsbGVuZGUga2FucyBvcCBlZW4gdmVyc2NoaWxsZW5kIHZlcnNnZXdpY2h0IHZhbiBzbGFwbGFudGVuIHR1c3NlbiBncm9uZCBtZXQgYmlvY2hhciBlbiBkZSBjb250cm9sZSBncm9uZCBlbiB0dXNzZW4gZGUgZ3JvbmQgbWV0IGNvbXBvc3QgZW4gZGUgZ3JvbmQgbWV0IGNvbXBvc3QgZW4gYmlvY2hhci4KCldlIGt1bm5lbiBiZXNsdWl0ZW4gZGF0IGdyb25kIG1ldCBjb21wb3N0IGVuIGdyb25kIG1ldCBjb21wb3N0IGVuIGJpb2NoYXIgZWVuIHBvc2l0aWV2ZSBpbnZsb2VkIGhlZWZ0IG9wIGRlIGdyb2VpIHZhbiBzbGFwbGFudGVuLiBBYW5nZXppZW4gaW4gZGV6ZSBzdHVkaWUgYWxsZWVuIGdla2VrZW4gd2VyZCBuYWFyIHNsYXBsYW50ZW4sIGt1bm5lbiB3ZSBkaXQgdWl0ZXJhYXJkIG5pZXQgYmVzbHVpdGVuIHZvb3IgYmxhZGdyb2VudGVuIGluIGhldCBhbGdlbWVlbi4KCg==