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.
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==