1 Introductie

  • We leven in het big data era
  • Gegevens over locatie, surfgedrag, aankoopgedrag, sociale media
  • Wetenschap: expressie meten van duizenden genen, eiwitten,… voor elk subject
  • Chemische proces controle: groot aantal sensoren die continu een proces meten zodat het proces kan worden bijgestuurd
  • Data driven journalism

Statistiek is de wetenschap om te leren uit empirische gegevens

Statistische geletterdheid is cruciaal om resultaten en publicaties kritisch te kunnen interpreteren.


2 Case study: oksel microbiome


  • Okselgeur wordt niet veroorzaakt door het zweet zelf. De geur is afkomstig van specificiek micro-organismen van de groep Corynebacterium spp. die het zweet metaboliseren. Staphylococcus spp. zijn een andere groep bacteriën die ook abundant zijn in het microbiome van de oksel die zweet metaboliseren naar metabolieten die niet stinken.

  • De CMET-groep aan UGENT doet onderzoek naar het transplanteren van de microbiële gemeenschap, het microbiome, om mensen van geurende oksels af te helpen.

  • Voorgestelde therapie

    1. Verwijder het oksel microbiome met antibiotica
    2. Beïnvloed het oksel microbiome door microbiome te transplanteren van een individue die geen geurende oksels heeft (https://youtu.be/9RIFyqLXdVw)

2.1 Proefopzet (experimental design)



  • Experiment:

    • 20 personen worden at random uit de populatie getrokken van personen met een okselgeur: steekproef representatief voor populatie!

    • de personen worden at random verdeeld over twee behandelingsgroepen:

      • placebo (enkel antibiotica)
      • transplantie (antibiotica en microbiële transplantatie).
      • Randomisatie is belangrijk om ervoor te zorgen dat de groepen vergelijkbaar zijn.
    • Het microbiome wordt bemonsterd 6 weken na de behandeling.

    • The relative abundantie van Staphylococcus spp. op Corynebacterium spp. + Staphylococcus spp. in het microbiome wordt gemeten via DGGE (Denaturing Gradient Gel Electrophoresis).


DGGE

https://doi.org/10.1371/journal.pone.0070538


Vertaal onderzoeksvraag naar iets wat we kunnen quantificeren: Is er een verschil in relatieve abundantie van Staphylococcus spp. in het microbiome van de placebo groep en de transplantatie



2.2 Data Exploratie en beschrijvende statistiek

  • Data exploratie is heel belangrijk om inzicht te krijgen in de data en is een essentiële eerste stap om te leren uit data.
  • Het wordt vaak ondergewaardeerd of over het hoofd gezien.

2.2.1 Importeer de data

  • Data in deze cursus wordt verwerkt via het statistisch software pakket R.

  • Dit pakket laat toe om te leren uit data.

  • In deze cursus gaan we data eerst exploreren om inzicht te verwerven in de gegevens om die vervolgens statistisch te verwerken.

  • Vooraleer we hiermee van start kunnen gaan moeten we de data eerst importeren in R.

  • Via het volgende commando kunnen we enkele regels van een data bestand inlezen om de structuur van het data bestand te weten te komen.

read_lines("https://raw.githubusercontent.com/statOmics/sbc20/master/data/armpit.csv")
 [1] "trt,rel"                       "placebo,54.99207606973059"    
 [3] "placebo,31.84466019417476"     "placebo,41.09947643979057"    
 [5] "placebo,59.52063914780293"     "placebo,63.573407202216075"   
 [7] "placebo,41.48648648648649"     "placebo,30.44041450777202"    
 [9] "placebo,42.95676429567643"     "placebo,41.7391304347826"     
[11] "placebo,33.896515311510036"    "transplant,57.218124341412015"
[13] "transplant,72.50900360144058"  "transplant,61.89258312020461" 
[15] "transplant,56.690140845070424" "transplant,76"                
[17] "transplant,71.7357910906298"   "transplant,57.757296466973884"
[19] "transplant,65.1219512195122"   "transplant,67.53424657534246" 
[21] "transplant,77.55359394703657" 
  • Gegevens in het bestand zijn door comma’s gescheiden.
  • Elke rij bevat de gegevens voor 1 proefpersoon
  • Verschillende variabelen worden gemeten per persoon en zijn van elkaar gescheiden door een comma. Het bestand is csv formaat: “comma separated values”.
  • We kunnen bestanden met dit formaat inlezen R via het commando read_csv.
  • We slaan de data op in R in het object met naam ap. Hiervoor gebruiken we de <- operator.
  • We geven de data tabel terug door het object aan te roepen door zijn naam te typen.
ap <- read_csv("https://raw.githubusercontent.com/statOmics/sbc20/master/data/armpit.csv")
ap
# A tibble: 20 × 2
   trt          rel
   <chr>      <dbl>
 1 placebo     55.0
 2 placebo     31.8
 3 placebo     41.1
 4 placebo     59.5
 5 placebo     63.6
 6 placebo     41.5
 7 placebo     30.4
 8 placebo     43.0
 9 placebo     41.7
10 placebo     33.9
11 transplant  57.2
12 transplant  72.5
13 transplant  61.9
14 transplant  56.7
15 transplant  76  
16 transplant  71.7
17 transplant  57.8
18 transplant  65.1
19 transplant  67.5
20 transplant  77.6

2.2.2 Beschrijvende statistiek

  • In artikels en de media worden resultaten uit een steekproef vaak gerapporteerd a.d.h.v. gemiddelde en de standaardafwijking

  • We vatten de data eerst samen. We berekenen het gemiddelde en de standaard deviatie (een maat voor de spreiding, zie volgende hoofdstukken). We slaan het resultaat hiervan op in het object apRelSum via apRelSum <-.

  1. We pipen (via %>%) het ap dataframe naar de group_by functie om de data te groeperen per treatment trt: group_by(trt).

  2. We pipen het resultaat naar de summarize_at function om de “rel” variable samen te vatten en berekenen hierbij het gemiddelde en standaardafwijking. Omdat we de data eerst hebben gegroepeerd zullen we het gemiddelde en de standaard deviatie berekenen per groep.

apRelSum <- ap %>%
  group_by(trt) %>%
  summarize_at("rel",
               list(mean=mean,
                    sd=sd
                    )
                )

We tonen vervolgens het resultaat door het object apRelSum aan te roepen

apRelSum
# A tibble: 2 × 3
  trt         mean    sd
  <chr>      <dbl> <dbl>
1 placebo     44.2 11.5 
2 transplant  66.4  7.88

We kunnen ook een tabel in de webpagina of het pdf bestand integreren via het commando kable van het knitr pakket:

knitr::kable(apRelSum)
trt mean sd
placebo 44.15496 11.543251
transplant 66.40127 7.880175

2.2.3 Grafieken

We maken in deze cursus gebruik van het pakket ggplot2 om grafieken te maken.
Met de ggplot2 bibliotheek kunnen we gemakkelijk grafieken opbouwen in lagen (layers). Hierdoor leest de code veel makkelijker.

2.2.3.1 barplot

Bar plots worden heel veel gebruikt in artikels om resultaten weer te geven.

  1. We pipen de samengevatte data naar de functie ggplot. Dat is de basis van elke ggplot. We selecteren de variabele met de behandeling trt als x variabele en de variabele met naam mean als y-variabele voor de plot. We doen dit steeds via de aestetics aes functie. aes(x=trt,y=mean)

  2. We maken een barplot door een laag toe te voegen via de geom_bar function. De statistiek is stat="identity" omdat de hoogte van de bar gelijk is aan de waarde voor y (hier het gemiddelde voor de relatieve abundantie).

  3. We voegen foutenvlaggen toe om de onzekerheid op het gemiddelde weer te geven. We doen dit via de geom_errorbar functie en specifiëren het minimum en maximum van de error bar. Het width argument wordt gebruikt om de breedte van de error bar smaller te maken dat deze van de bar.

apRelSum %>%
  ggplot(aes(x=trt,y=mean)) +
  geom_bar(stat="identity") +
  geom_errorbar(aes(ymin=mean-sd,ymax=mean+sd),width=.2)

  • Is deze plot informatief??

2.2.3.2 boxplots

Barplots zijn geen goede grafieken:

  • Ze zijn niet informatief

  • Ze visulariseren een samenvatting van de data door twee punten: two point summary: gemiddelde en de standaard deviatie hierop en kunnen beter in een tabel worden opgenomen.

  • Ze laten niet toe om anomalieën in de data zoals meetfouten op te sporen.

  • Ze verbruiken veel ruimte, b.v. van nul tot de kleinste waarde voor de relatieve abundantie) waar geen data in ligt.

Het is beter om de data zo ruw mogelijk voor te stellen zodat we inzicht krijgen in de verdeling van de gegevens. Hiervoor zullen we ondermeer boxplots gebruiken.


We maken nu een boxplot voor de ap data

  1. We pipen het ap dataframe naar ggplot
  2. We selecteren de data voor de plot via ggplot(aes(x=trt,y=rel))
  3. We voegen laag toe voor de boxplot dmv de functie geom_boxplot()
ap %>%  
  ggplot(aes(x=trt,y=rel)) +
  geom_boxplot()


Merk op dat we de plot ook op kunnen slaan als een object.

apBoxplot <- ap %>%  
  ggplot(aes(x=trt,y=rel)) +
  geom_boxplot()

De plot wordt dan niet gemaakt.

Om de plot weer te geven kunnen we het object aanroepen

apBoxplot


  • Merk op dat we niet zoveel gegevens hebben. Enkel 10 per groep.

  • Het is altijd beter om de data zo ruw mogelijk te tonen!

Omdat er niet zoveel gegevens zijn kunnen we de data toevoegen aan de plot zonder dat die te druk wordt.

  • Merk op dat we het argument outlier.shape op NA (not available) zetten outlier.shape=NA in the geom_boxplot functie omdat we anders outliers twee keer weer zullen geven. Eerst via de boxplot laag en daarna omdat we een laag met alle ruwe data toevoegen aan de plot.
  • We geven de ruwe data weer via de geom_point(position="jitter") functie. We gebruiken hierbij het argument position=‘jitter’ zodat we wat random ruis toevoegen aan de x-cordinaat zodat de gegevens elkaar niet overlappen.
ap %>%  
  ggplot(aes(x=trt,y=rel)) +
  geom_boxplot(outlier.shape=NA) +
  geom_point(position="jitter")

Dit is een informatieve plot!


Aangezien we de plot ook hebben opgeslagen konden we dit ook doen door de plot op te roepen en nog een laag toe te voegen.

apBoxplot +
  geom_point(position="jitter")

We hadden het resultaat ook opnieuw op kunnen slaan voor later hergebruik.

apBoxplot <- apBoxplot +
  geom_point(position="jitter")

  • We zagen duidelijk een effect van de transplantatie op de relatieve abundantie van Staphylococcus.

  • Is dat effect nu groot genoeg om te kunnen concluderen dat de behandeling werkt?



  • Inductie: Door middel van statistische besluitvorming (inference) kunnen we uitspraken doen over de populatie op basis van een steekproef.

  • De prijs die we hiervoor betalen is onzekerheid!

  • We kunnen op basis van een steekproef nooit absoluut zeker zijn van onze conclusies.


  • Met data kunnen we niet bewijzen dat een behandeling werkt.

  • Falsificatie principe van Popper: Data kunnen enkel een hypothese of een theorie ontkrachten.

  • Met statistiek kunnen we dus niet aantonen dat de behandeling werkt.

  • Statistiek zal ons wel toelaten om het omgekeerde te falsifiëren: als we veronderstellen dat er geen effect van de behandeling, spreekt de data in de steekproef dit tegen?

  • Met statistiek kunnen we berekenen hoe waarschijnlijk het is om in een random steekproef (wanneer we het experiment dus opnieuw uit zouden voeren) een gemiddeld verschil in relatieve abundantie te zien tussen placebo en transplantatiegroep dat minstens zo groot is als in onze steekproef als de behandeling geen effect zou hebben.

  • Die kans wordt een p-waarde genoemd.

  • Als p heel klein is, dan is het heel onwaarschijnlijk om een dergelijk effect te observeren in een steekproef door toeval.

  • p wordt meestal vergeleken met 5%. Als er geen effect is van de behandeling dan tolereren 5% vals positieve conclusies.

  • Om de kans p te berekenen is het nodig om de data te modelleren met statistische modellen.


In latere hoofdstukken zullen we zien dat we t-test kunnen gebruiken om hetgeen we observeren in de microbiome dataset te veralgemenen naar de populatie.

t.test(rel~trt,data=ap)

    Welch Two Sample t-test

data:  rel by trt
t = -5.0334, df = 15.892, p-value = 0.0001249
alternative hypothesis: true difference in means between group placebo and group transplant is not equal to 0
95 percent confidence interval:
 -31.62100 -12.87163
sample estimates:
   mean in group placebo mean in group transplant 
                44.15496                 66.40127 

Conclusie: Gemiddeld is de relatieve abundantie van Staphylococcus in het microbiome van personen met een zweetgeur 22.2% hoger na de transplantie dan na de placebo behandeling.


2.3 Randomisatie

  • Wat wordt zijn de consequenties van het gebruik van een steekproef en van randomisatie?

  • Randomisatie is sterk gerelateerd met het concept van de populatie en scope van de studie.

  • De scope van de studie moet goed worden omschreven voor de start van het experiment.

  • Omdat de statistische analyse valide zou zijn is het noodzakelijk dat de subjecten volledig random worden getrokken uit de populatie naar waar we onze conclusies wensen te veralgemenen.

  • Volledig random trekken van de populatie impliceert dat:

    • alle subjecten van de populatie evenveel kans hebben om in de steekproef te worden opgenomen
    • de selectie van een subject onafhankelijk is van de andere subjecten in de steekproef.
  • De steekproef is dan representatief voor de populatie, maar is nog steeds random.

  • Wat betekent dit?


3 Case study: Lengte van mannen en vrouwen - Variabiliteit van steekproef tot steekproef

  • Om te begrijpen dat een steekproef random is zouden we hetzelfde experiment veel keer moeten kunnen herhalen (repeated sampling).

  • Dan zouden we inzicht kunnen krijgen hoe de gegevens veranderen van steekproef tot steekproef.

  • Om dit te illustreren zullen we gebruik maken van een hele grote studie.

  • Uit die studie zullen we dan herhaaldelijk kleine steekproeven trekken om te begrijpen hoe de gegevens en statistieken veranderen van steekproef tot steekproef. Of om met andere woorden na te gaan wat de variabiliteit is tussen steekproeven.


National Health And Nutrition Examination Study (NHANES)

  • Sinds 1960 worden elk jaar mensen van alle leeftijden geïnterviewd bij hen thuis.
  • Er maakt ook een gezondheidsonderzoek deel uit van de study die in een mobiel onderzoekscentrum wordt afgenomen.
  • We zullen deze grote studie gebruiken om at random personen te selecteren van de Amerikaanse populatie.
  • Dat zal inzicht geven in hoe de gegevens en resultaten van een analyse zullen variëren van steekproef tot steekproef.
  • De data van deze studie is terug te vinden in het R pakket NHANES

library(NHANES)
head(NHANES)
# A tibble: 6 × 76
     ID SurveyYr Gender   Age AgeDecade AgeMonths Race1 Race3 Education   
  <int> <fct>    <fct>  <int> <fct>         <int> <fct> <fct> <fct>       
1 51624 2009_10  male      34 " 30-39"        409 White <NA>  High School 
2 51624 2009_10  male      34 " 30-39"        409 White <NA>  High School 
3 51624 2009_10  male      34 " 30-39"        409 White <NA>  High School 
4 51625 2009_10  male       4 " 0-9"           49 Other <NA>  <NA>        
5 51630 2009_10  female    49 " 40-49"        596 White <NA>  Some College
6 51638 2009_10  male       9 " 0-9"          115 White <NA>  <NA>        
# … with 67 more variables: MaritalStatus <fct>, HHIncome <fct>,
#   HHIncomeMid <int>, Poverty <dbl>, HomeRooms <int>, HomeOwn <fct>,
#   Work <fct>, Weight <dbl>, Length <dbl>, HeadCirc <dbl>, Height <dbl>,
#   BMI <dbl>, BMICatUnder20yrs <fct>, BMI_WHO <fct>, Pulse <int>,
#   BPSysAve <int>, BPDiaAve <int>, BPSys1 <int>, BPDia1 <int>, BPSys2 <int>,
#   BPDia2 <int>, BPSys3 <int>, BPDia3 <int>, Testosterone <dbl>,
#   DirectChol <dbl>, TotChol <dbl>, UrineVol1 <int>, UrineFlow1 <dbl>, …
glimpse(NHANES)
Rows: 10,000
Columns: 76
$ ID               <int> 51624, 51624, 51624, 51625, 51630, 51638, 51646, 5164…
$ SurveyYr         <fct> 2009_10, 2009_10, 2009_10, 2009_10, 2009_10, 2009_10,…
$ Gender           <fct> male, male, male, male, female, male, male, female, f…
$ Age              <int> 34, 34, 34, 4, 49, 9, 8, 45, 45, 45, 66, 58, 54, 10, …
$ AgeDecade        <fct>  30-39,  30-39,  30-39,  0-9,  40-49,  0-9,  0-9,  40…
$ AgeMonths        <int> 409, 409, 409, 49, 596, 115, 101, 541, 541, 541, 795,…
$ Race1            <fct> White, White, White, Other, White, White, White, Whit…
$ Race3            <fct> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
$ Education        <fct> High School, High School, High School, NA, Some Colle…
$ MaritalStatus    <fct> Married, Married, Married, NA, LivePartner, NA, NA, M…
$ HHIncome         <fct> 25000-34999, 25000-34999, 25000-34999, 20000-24999, 3…
$ HHIncomeMid      <int> 30000, 30000, 30000, 22500, 40000, 87500, 60000, 8750…
$ Poverty          <dbl> 1.36, 1.36, 1.36, 1.07, 1.91, 1.84, 2.33, 5.00, 5.00,…
$ HomeRooms        <int> 6, 6, 6, 9, 5, 6, 7, 6, 6, 6, 5, 10, 6, 10, 10, 4, 3,…
$ HomeOwn          <fct> Own, Own, Own, Own, Rent, Rent, Own, Own, Own, Own, O…
$ Work             <fct> NotWorking, NotWorking, NotWorking, NA, NotWorking, N…
$ Weight           <dbl> 87.4, 87.4, 87.4, 17.0, 86.7, 29.8, 35.2, 75.7, 75.7,…
$ Length           <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
$ HeadCirc         <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
$ Height           <dbl> 164.7, 164.7, 164.7, 105.4, 168.4, 133.1, 130.6, 166.…
$ BMI              <dbl> 32.22, 32.22, 32.22, 15.30, 30.57, 16.82, 20.64, 27.2…
$ BMICatUnder20yrs <fct> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
$ BMI_WHO          <fct> 30.0_plus, 30.0_plus, 30.0_plus, 12.0_18.5, 30.0_plus…
$ Pulse            <int> 70, 70, 70, NA, 86, 82, 72, 62, 62, 62, 60, 62, 76, 8…
$ BPSysAve         <int> 113, 113, 113, NA, 112, 86, 107, 118, 118, 118, 111, …
$ BPDiaAve         <int> 85, 85, 85, NA, 75, 47, 37, 64, 64, 64, 63, 74, 85, 6…
$ BPSys1           <int> 114, 114, 114, NA, 118, 84, 114, 106, 106, 106, 124, …
$ BPDia1           <int> 88, 88, 88, NA, 82, 50, 46, 62, 62, 62, 64, 76, 86, 6…
$ BPSys2           <int> 114, 114, 114, NA, 108, 84, 108, 118, 118, 118, 108, …
$ BPDia2           <int> 88, 88, 88, NA, 74, 50, 36, 68, 68, 68, 62, 72, 88, 6…
$ BPSys3           <int> 112, 112, 112, NA, 116, 88, 106, 118, 118, 118, 114, …
$ BPDia3           <int> 82, 82, 82, NA, 76, 44, 38, 60, 60, 60, 64, 76, 82, 7…
$ Testosterone     <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
$ DirectChol       <dbl> 1.29, 1.29, 1.29, NA, 1.16, 1.34, 1.55, 2.12, 2.12, 2…
$ TotChol          <dbl> 3.49, 3.49, 3.49, NA, 6.70, 4.86, 4.09, 5.82, 5.82, 5…
$ UrineVol1        <int> 352, 352, 352, NA, 77, 123, 238, 106, 106, 106, 113, …
$ UrineFlow1       <dbl> NA, NA, NA, NA, 0.094, 1.538, 1.322, 1.116, 1.116, 1.…
$ UrineVol2        <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
$ UrineFlow2       <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
$ Diabetes         <fct> No, No, No, No, No, No, No, No, No, No, No, No, No, N…
$ DiabetesAge      <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
$ HealthGen        <fct> Good, Good, Good, NA, Good, NA, NA, Vgood, Vgood, Vgo…
$ DaysPhysHlthBad  <int> 0, 0, 0, NA, 0, NA, NA, 0, 0, 0, 10, 0, 4, NA, NA, 0,…
$ DaysMentHlthBad  <int> 15, 15, 15, NA, 10, NA, NA, 3, 3, 3, 0, 0, 0, NA, NA,…
$ LittleInterest   <fct> Most, Most, Most, NA, Several, NA, NA, None, None, No…
$ Depressed        <fct> Several, Several, Several, NA, Several, NA, NA, None,…
$ nPregnancies     <int> NA, NA, NA, NA, 2, NA, NA, 1, 1, 1, NA, NA, NA, NA, N…
$ nBabies          <int> NA, NA, NA, NA, 2, NA, NA, NA, NA, NA, NA, NA, NA, NA…
$ Age1stBaby       <int> NA, NA, NA, NA, 27, NA, NA, NA, NA, NA, NA, NA, NA, N…
$ SleepHrsNight    <int> 4, 4, 4, NA, 8, NA, NA, 8, 8, 8, 7, 5, 4, NA, 5, 7, N…
$ SleepTrouble     <fct> Yes, Yes, Yes, NA, Yes, NA, NA, No, No, No, No, No, Y…
$ PhysActive       <fct> No, No, No, NA, No, NA, NA, Yes, Yes, Yes, Yes, Yes, …
$ PhysActiveDays   <int> NA, NA, NA, NA, NA, NA, NA, 5, 5, 5, 7, 5, 1, NA, 2, …
$ TVHrsDay         <fct> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
$ CompHrsDay       <fct> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…
$ TVHrsDayChild    <int> NA, NA, NA, 4, NA, 5, 1, NA, NA, NA, NA, NA, NA, 4, N…
$ CompHrsDayChild  <int> NA, NA, NA, 1, NA, 0, 6, NA, NA, NA, NA, NA, NA, 3, N…
$ Alcohol12PlusYr  <fct> Yes, Yes, Yes, NA, Yes, NA, NA, Yes, Yes, Yes, Yes, Y…
$ AlcoholDay       <int> NA, NA, NA, NA, 2, NA, NA, 3, 3, 3, 1, 2, 6, NA, NA, …
$ AlcoholYear      <int> 0, 0, 0, NA, 20, NA, NA, 52, 52, 52, 100, 104, 364, N…
$ SmokeNow         <fct> No, No, No, NA, Yes, NA, NA, NA, NA, NA, No, NA, NA, …
$ Smoke100         <fct> Yes, Yes, Yes, NA, Yes, NA, NA, No, No, No, Yes, No, …
$ Smoke100n        <fct> Smoker, Smoker, Smoker, NA, Smoker, NA, NA, Non-Smoke…
$ SmokeAge         <int> 18, 18, 18, NA, 38, NA, NA, NA, NA, NA, 13, NA, NA, N…
$ Marijuana        <fct> Yes, Yes, Yes, NA, Yes, NA, NA, Yes, Yes, Yes, NA, Ye…
$ AgeFirstMarij    <int> 17, 17, 17, NA, 18, NA, NA, 13, 13, 13, NA, 19, 15, N…
$ RegularMarij     <fct> No, No, No, NA, No, NA, NA, No, No, No, NA, Yes, Yes,…
$ AgeRegMarij      <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, 20, 15, N…
$ HardDrugs        <fct> Yes, Yes, Yes, NA, Yes, NA, NA, No, No, No, No, Yes, …
$ SexEver          <fct> Yes, Yes, Yes, NA, Yes, NA, NA, Yes, Yes, Yes, Yes, Y…
$ SexAge           <int> 16, 16, 16, NA, 12, NA, NA, 13, 13, 13, 17, 22, 12, N…
$ SexNumPartnLife  <int> 8, 8, 8, NA, 10, NA, NA, 20, 20, 20, 15, 7, 100, NA, …
$ SexNumPartYear   <int> 1, 1, 1, NA, 1, NA, NA, 0, 0, 0, NA, 1, 1, NA, NA, 1,…
$ SameSex          <fct> No, No, No, NA, Yes, NA, NA, Yes, Yes, Yes, No, No, N…
$ SexOrientation   <fct> Heterosexual, Heterosexual, Heterosexual, NA, Heteros…
$ PregnantNow      <fct> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N…

3.1 Data exploratie

Onderzoeksvraag: hoe verschilt de lengte van volwassen mannen en vrouwen.

  1. We pipen de dataset naar de function filter om de data te filteren volgens leeftijd.
  2. We plotten de lengte metingen.
    • We selecteren de data data met het commando ggplot(aes(x=lengte))
    • We voegen een histogram toe met het commando geom_histogram()
    • We maken twee vertikale panels met het commando facet_grid(Gender~.)
    • We veranderen het label van de x-as met de xlab functie.
NHANES%>%  
  filter(Age >= 18 & !is.na(Height)) %>%
  ggplot(aes(x = Height))+
  geom_histogram() +
  facet_grid(Gender ~ .) +
  xlab("Lengte (cm)")


We zien dat de data nu min of meer symmetrisch verdeeld zijn en een klokvorm hebben.
Dat zal ons toe laten om de data verder samen te vatten door gebruik te maken van twee statistieken: het gemiddelde en de standaard deviatie wat een maat is voor de spreiding van de gegevens rond het gemiddelde.


We maken nu een subset van de data die we zullen gebruiken om aan te tonen hoe de variabiliteit in kleine steekproeven kan variëren van steekproef tot steekproef.

  1. We filteren op leeftijd en verwijderen ontbrekenden gegevens (NA, Not Available).
  2. We selecteren enkel het geslacht en Lengte zodat de dataset geen onnodige variabelen bevat.
nhanesSub <- NHANES %>%
  filter(Age >= 18 & !is.na(Height)) %>%
  select(c("Gender","Height"))

We berekenen het gemiddelde en de standaard deviatie voor de lengte voor mannen en vrouwen in de grote dataset. We groeperen de data hiervoor op basis van het geslacht (variable Gender).

HeightSum <- nhanesSub %>%
  group_by(Gender) %>%
  summarize_at("Height",
               list(mean = mean,
               sd = sd)
              )

knitr::kable(
  HeightSum %>%
  mutate_if(is.numeric, round, digits=1)
  )
Gender mean sd
female 162.1 7.3
male 175.9 7.5

3.2 Experiment

  • Stel dat we geen toegang hebben tot de metingen van de NHANES studie.

  • We zouden dan een experiment op moeten zetten om metingen bij mannen en vrouwen te doen.

  • Veronderstel dat we budget hebben om metingen bij 5 mannen en 5 vrouwen te doen.

  • We zouden dan 5 mannen en 5 vrouwen boven de 18 jaar at random selecteren uit de Amerikaanse populatie.

  • We kunnen dit experiment simuleren door 5 vrouwen en 5 mannen at random te selecteren uit de NHANES studie.


set.seed(1023)
nSamp <- 5
fem <- nhanesSub %>%
  filter(Gender=="female") %>%
  sample_n(size=5)

mal <- nhanesSub %>%
  filter(Gender=="male") %>%
  sample_n(size=5)

samp1 <- rbind(fem,mal)

samp1
# A tibble: 10 × 2
   Gender Height
   <fct>   <dbl>
 1 female   164 
 2 female   160.
 3 female   159 
 4 female   154.
 5 female   156.
 6 male     170.
 7 male     183.
 8 male     183.
 9 male     185.
10 male     170.

Data Exploratie

samp1 %>%
  ggplot(aes(x=Height)) +
  geom_histogram() +
  facet_grid(Gender~.) +
  xlab("Lengte (cm)")

HeightSumExp1 <- samp1 %>%
  group_by(Gender) %>%
  summarize_at("Height",
               list(mean = mean,
                      sd = sd)
                  )
HeightSumExp1
# A tibble: 2 × 3
  Gender  mean    sd
  <fct>  <dbl> <dbl>
1 female  159.  3.76
2 male    178.  7.55

Histogram is niet zinvol als we maar zo weinig datapunten hebben.


Boxplot is beter:


We voeren hier ook een t-test uit.

t.test(Height~Gender,data=samp1)

    Welch Two Sample t-test

data:  Height by Gender
t = -5.0783, df = 5.8695, p-value = 0.00242
alternative hypothesis: true difference in means between group female and group male is not equal to 0
95 percent confidence interval:
 -28.441927  -9.878073
sample estimates:
mean in group female   mean in group male 
              158.72               177.88 

In het experiment zijn vrouwen gemiddeld 19.16 cm kleiner dan mannen. En als we een statistische test uitvoeren (zie hoofdstuk 5: Statistische besluitvorming) kunnen we besluiten dat dit verschil statistisch significant is.


3.3 Herhaal het experiment

Als we het experiment herhalen selecteren we andere mensen en verkrijgen we andere resultaten.

set.seed(1024)
fem <- nhanesSub %>%
  filter(Gender=="female") %>%
  sample_n(size=5)

mal <- nhanesSub %>%
  filter(Gender=="male") %>%
  sample_n(size=5)

samp2 <- rbind(fem,mal)

HeightSumExp2 <- samp2 %>%
  group_by(Gender) %>%
  summarize_at("Height",
               list(mean=mean,
                    sd=sd)
              )
HeightSumExp2
# A tibble: 2 × 3
  Gender  mean    sd
  <fct>  <dbl> <dbl>
1 female  166.  9.89
2 male    170.  8.24
samp2 %>%
  ggplot(aes(x = Gender,y = Height)) +
  geom_boxplot(outlier.shape = NA) +
  geom_point(position = "jitter") +
  geom_point(
    aes(x = 1, y = HeightSumExp2$mean[1]),
    size = 3,
    pch = 17,
    color="darkred") +
  geom_point(
    aes(x = 2, y = HeightSumExp2$mean[2]),
    size = 3,
    pch = 17,
    color = "darkred") +
  ylab("Height (cm)")

t.test(Height ~ Gender, data=samp2)

    Welch Two Sample t-test

data:  Height by Gender
t = -0.7295, df = 7.747, p-value = 0.4872
alternative hypothesis: true difference in means between group female and group male is not equal to 0
95 percent confidence interval:
 -17.552343   9.152343
sample estimates:
mean in group female   mean in group male 
              166.26               170.46 

In de nieuwe steekproef zijn vrouwen gemiddeld 4.2 cm kleiner dan mannen. En dit verschil is statistisch niet significant


3.4 Herhaal het experiment opnieuw

seed <- 88605
set.seed(seed)
fem <- nhanesSub %>%
  filter(Gender=="female") %>%
  sample_n(size=5)

mal <- nhanesSub %>%
  filter(Gender=="male") %>%
  sample_n(size=5)

samp3 <- rbind(fem,mal)

HeightSumExp3 <- samp3 %>%
  group_by(Gender) %>%
  summarize_at("Height",
               list(mean=mean,
                    sd=sd)
              )
HeightSumExp3
# A tibble: 2 × 3
  Gender  mean    sd
  <fct>  <dbl> <dbl>
1 female  173.  1.97
2 male    168.  2.84
samp3 %>%
  ggplot(aes(x = Gender,y = Height)) +
  geom_boxplot(outlier.shape = NA) +
  geom_point(position = "jitter") +
  geom_point(
    aes(x = 1, y = HeightSumExp3$mean[1]),
    size = 3,
    pch = 17,
    color="darkred") +
  geom_point(
    aes(x = 2, y = HeightSumExp3$mean[2]),
    size = 3,
    pch = 17,
    color = "darkred") +
  ylab("Height (cm)")

t.test(Height ~ Gender, data=samp3)

    Welch Two Sample t-test

data:  Height by Gender
t = 3.1182, df = 7.136, p-value = 0.01648
alternative hypothesis: true difference in means between group female and group male is not equal to 0
95 percent confidence interval:
 1.178916 8.461084
sample estimates:
mean in group female   mean in group male 
              172.60               167.78 

In de nieuwe steekproef zijn vrouwen gemiddeld 4.82 cm groter dan mannen. En dit verschil is statistisch significant


3.5 Samenvatting

  • We trokken at random andere proefpersonen in elke steekproef

  • Hierdoor verschillen lengtemetingen van steekproef tot steekproef.

  • Dus ook de geschatte gemiddeldes en standaard deviaties.

  • Bijgevolg zijn onze conclusies ook onzeker en kunnen deze wijzigen van steekproef tot steekproef.

  • Voor het lengte voorbeeld zijn steekproeven waarbij het effect tegengesteld is aan dat in de populatie en waarbij we besluiten dat het verschil significant echter zeldzaam.

\(\rightarrow\) Met statistiek controleren we de kans op het trekken foute conclusies.

3.6 Controle van fouten

Hoe controleert statistiek de kans op het trekken van foute conclusies?

  • In onderstaande code trekken we 10000 herhaalde steekproeven van 5 vrouwen en 5 mannen uit de NHANES studie.
set.seed(15152)
# Aantal simulaties en steekproefgrootte per groep
nSim <- 10000
nSamp <- 5

# We filteren de data vooraf zodat we dit niet telkens opnieuw hoeven te doen
fem <- nhanesSub %>%
  filter(Gender == "female")

mal <- nhanesSub %>%
  filter(Gender == "male")

# Simulatie studie
# Om snelle functies te kunnen gebruiken nemen we eerst nSim steekproeven en berekenen we daarna alles.

femSamps <- malSamps <-matrix(NA, nrow=nSamp, ncol=nSim)
for (i in 1:nSim)
{
  femSamps[,i] <- sample(fem$Height, nSamp)
  malSamps[,i] <- sample(mal$Height, nSamp)
}

res <- data.frame(
  verschil=colMeans(femSamps) - colMeans(malSamps),
  Rfast::ttests(femSamps, malSamps)
  )

sum(res$pvalue < 0.05 & res$verschil < 0)
[1] 7234
sum(res$pvalue >= 0.05)
[1] 2766
sum(res$pvalue < 0.05 & res$verschil>0)
[1] 0
res %>%
  ggplot(aes(x=verschil,y=-log10(pvalue),color=pvalue < 0.05)) +
  geom_point() +
  xlab("Gemiddeld Verschil (cm)") +
  ylab("Statistische Significantie (-log10 p)")

res %>%
  ggplot(aes(y = verschil)) +
  geom_boxplot() +
  ylab("Gemiddeld Verschil (cm)")

  xlab("")
$x
[1] ""

attr(,"class")
[1] "labels"

Op basis van 10000 steekproeven van 5 mannen en 5 vrouwen zagen we dat in 7234 steekproeven vrouwen gemiddeld significant kleiner zijn dan mannen. In 2766 steekproeven besluiten we dat vrouwen en mannen gemiddeld niet significant verschillen in lengte. En in 0 besluiten we dat vrouwen gemiddeld significant groter zijn dan mannen.

  • De steekproef die we toonden waaruit we zouden besluiten dat vrouwen significant groter zijn dan mannen is heel onwaarschijnlijk. Er moesten 88605 steekproeven worden getrokken om deze extreme steekproef te vinden.

Het feit dat we in veel steekproeven resultaten vinden die statistisch niet significant zijn komt omdat de statistische toets een te lage kracht heeft om het verschil te detecteren wanneer er maar 5 observaties zijn per groep.


3.6.1 Grotere steekproef?

Wat gebeurt er als we de steekproef verhogen naar 50 observaties per groep?

set.seed(11145)
# Aantal simulaties en steekproefgrootte per groep
nSim <- 10000
nSamp <- 50

# We filteren de data vooraf zodat we dit niet telkens opnieuw hoeven te doen
fem <- nhanesSub %>%
  filter(Gender == "female")

mal <- nhanesSub %>%
  filter(Gender == "male")

# Simulatie studie
# Om snelle functies te kunnen gebruiken nemen we eerst nSim steekproeven en berekenen we daarna alles.

femSamps <- malSamps <- matrix(NA, nrow = nSamp, ncol = nSim)
for (i in 1:nSim)
{
  femSamps[,i] <- sample(fem$Height, nSamp)
  malSamps[,i] <- sample(mal$Height, nSamp)
}

res <- data.frame(
  verschil = colMeans(femSamps) - colMeans(malSamps),
  Rfast::ttests(femSamps, malSamps)
  )

sum(res$pvalue < 0.05 & res$verschil < 0)
[1] 10000
sum(res$pvalue >= 0.05)
[1] 0
sum(res$pvalue < 0.05 & res$verschil > 0)
[1] 0
res %>%
  ggplot(aes(x=verschil,y=-log10(pvalue),color=pvalue<0.05)) +
  geom_point() +
  xlab("Gemiddeld Verschil (cm)") +
  ylab("Statistische Significantie (-log10 p)")

res %>%
  ggplot(aes(y=verschil)) +
  geom_boxplot() +
  ylab("Gemiddeld Verschil (cm)")

  xlab("")
$x
[1] ""

attr(,"class")
[1] "labels"
  • We zien dus dat we de kans om een verschil te vinden als er in werkelijkheid een verschil is in de populatie kunnen beïnvloeden in de design fase: aan de hand van de steekproefgrootte.

  • Hoe meer gegevens hoe makkelijker we het werkelijk verschil oppikken in de steekproef.

3.6.2 Controle van vals positieven

Wat gebeurt er als er geen verschil is tussen beide groepen?

  • We moeten hiervoor experimenten simuleren waarbij de groepen gelijk zijn.

  • Hiervoor zullen we twee groepen vergelijken waarvoor de lengte gemiddeld niet verschillend is.

  • Dat kunnen we doen door een steekproef te trekken waarbij we voor beide groepen at random subjecten trekken uit de subset van vrouwen in de NHANES studie.

  • We doen dit opnieuw voor een steekproef met 5 subjecten per groep

set.seed(13245)
# Aantal simulaties en steekproefgrootte per groep
nSim <- 10000
nSamp <- 5

# We filteren de data vooraf zodat we dit niet telkens opnieuw hoeven te doen
fem <- nhanesSub %>%
  filter(Gender == "female")

# Simulatie studie
# Om snelle functies te kunnen gebruiken nemen we eerst nSim steekproeven en berekenen we daarna alles.

femSamps <- femSamps2 <-matrix(NA, nrow=nSamp, ncol=nSim)
for (i in 1:nSim)
{
  femSamps[,i] <- sample(fem$Height, nSamp)
  femSamps2[,i] <- sample(fem$Height, nSamp)
}

res <- data.frame(
  verschil=colMeans(femSamps) - colMeans(femSamps2),
  Rfast::ttests(femSamps, femSamps2)
  )

sum(res$pvalue < 0.05 & res$verschil < 0)
[1] 213
sum(res$pvalue >= 0.05)
[1] 9558
sum(res$pvalue < 0.05 & res$verschil>0)
[1] 229
res %>%
  ggplot(aes(x=verschil,y=-log10(pvalue),color=pvalue < 0.05)) +
  geom_point() +
  xlab("Gemiddeld Verschil (cm)") +
  ylab("Statistische Significantie (-log10 p)")

res %>%
  ggplot(aes(y = verschil)) +
  geom_boxplot() +
  ylab("Gemiddeld Verschil (cm)")

  xlab("")
$x
[1] ""

attr(,"class")
[1] "labels"

Op basis van 10000 steekproeven zien we dat we in 442 steekproeven ten onrechte besluiten dat er een verschil is in gemiddelde lengte tussen twee groepen vrouwen.

Met de statistische analyse controleren we dus het aantal vals positieve resultaten correct op 5%.

Wat gebeurt er als we het aantal observaties verhogen?

We simuleren opnieuw experimenten met 50 subjecten per groep maar we trekken de subjecten opnieuw telkens uit de populatie van vrouwen.

set.seed(1345)
# Aantal simulaties en steekproefgrootte per groep
nSim <- 10000
nSamp <- 50

# We filteren de data vooraf zodat we dit niet telkens opnieuw hoeven te doen
fem <- nhanesSub %>%
  filter(Gender == "female")

# Simulatie studie
# Om snelle functies te kunnen gebruiken nemen we eerst nSim steekproeven en berekenen we daarna alles.

femSamps <- femSamps2 <-matrix(NA, nrow=nSamp, ncol=nSim)
for (i in 1:nSim)
{
  femSamps[,i] <- sample(fem$Height, nSamp)
  femSamps2[,i] <- sample(fem$Height, nSamp)
}

res <- data.frame(
  verschil=colMeans(femSamps) - colMeans(femSamps2),
  Rfast::ttests(femSamps, femSamps2)
  )

sum(res$pvalue < 0.05 & res$verschil < 0)
[1] 271
sum(res$pvalue >= 0.05)
[1] 9501
sum(res$pvalue < 0.05 & res$verschil>0)
[1] 228
res %>%
  ggplot(aes(x=verschil,y=-log10(pvalue),color=pvalue < 0.05)) +
  geom_point() +
  xlab("Gemiddeld Verschil (cm)") +
  ylab("Statistische Significantie (-log10 p)")

res %>%
  ggplot(aes(y = verschil)) +
  geom_boxplot() +
  ylab("Gemiddeld Verschil (cm)")

  xlab("")
$x
[1] ""

attr(,"class")
[1] "labels"

Op basis van 10000 steekproeven zien we dat we in 499 steekproeven ten onrechte besluiten dat er een verschil is in gemiddelde lengte tussen twee groepen vrouwen.

Met de statistische analyse controleren we dus ook bij het nemen van een grote steekproef het aantal vals positieve resultaten correct op 5% (Vals positief: Op basis van de steekproef besluiten dat er gemiddeld een verschil is in lengte tussen beide groepen terwijl er in werkelijkheid geen verschil is in de populatie.)

3.6.3 Conclusies

  • De statistische analyse controleert steeds de kans op het nemen van een vals positieve conclusie.

  • De statistische analysis controleert de kans op het nemen van een vals negatieve conclusies niet, maar in de design fase kunnen we deze kans beïnvloeden ondermeer d.m.v. de steekproefgrootte.


#Case study: Salk vaccin

  • In 1916, brak de eerste grote polio epidemie uit in de USA.
  • Begin de jaren 50 ontwikkelde John Salk een vaccin met belovende resultaten in het lab.
  • In 1954, heeft de National Foundation for Infantile Paralysis (NFIP) een grote studie opgezet om de effectiviteit van het Salk vaccin na te gaan.
  • Veronderstel dat de NFIP in 1954 een groot aantal kinderen zou hebben gevaccineerd, wat zouden ze dan kunnen besluiten als de polio incidentie in 1954 lager was dan in 1953?

3.7 NFIP Study

3.7.1 Design

  • Grote simultane studie met gevaccineerde kinderen (cases) en ongevaccineerde kinderen (controles).
  • In scholen van districten met hoge polio incidentie.
  • Cases: kinderen van de tweede graad van het lager onderwijs waarvan de ouders toestemden met vaccinatie.
  • Controles: kinderen van de eerste en derde graad.

3.7.2 Data

nfip <- tibble(
  group=c("cases","controls","noConcent"),
  grade=c("g2","g1g3","g2"),
  vaccin=c("yes","no","no"),
  total=c(221998,725173,123605),
  polio=c(54,391,56)
  ) %>%
  mutate(noPolio = total - polio)
knitr::kable(nfip)
group grade vaccin total polio noPolio
cases g2 yes 221998 54 221944
controls g1g3 no 725173 391 724782
noConcent g2 no 123605 56 123549

Vergelijk de polio incidentie?


nfip <- nfip %>%
  mutate(incidencePM = round(nfip$polio/nfip$total*1e6,0))
knitr::kable(nfip)
group grade vaccin total polio noPolio incidencePM
cases g2 yes 221998 54 221944 243
controls g1g3 no 725173 391 724782 539
noConcent g2 no 123605 56 123549 453

Wat kunnen we concluderen?


3.8 Confounding

  • We observeren een lagere polio (P) incidentie voor kinderen bij wie de ouders geen toestemming gaven dan in de controle groep.

  • Toestemming voor vaccinatie (V) is geassocieerd met de socio-economische status (S).

  • Kinderen van lagere socio-economische status zijn meer resistent tegen de ziekte.

  • De groepen van cases en controles zijn niet vergelijkbaar

    • verschil in leeftijd
    • verschil in socio-economische status en
    • verschil in vatbaarheid voor de ziekte.

3.9 Salk Study

3.9.1 Design

Een nieuwe studie werd uitgevoerd: dubbel blinde gerandomiseerde studie.

  • Kinderen worden at random toegewezen aan controle of case arm van het experiment nadat de ouders toestemden met vaccinatie.
  • Controle: vaccinatie met placebo
  • Treatment: vaccinatie met vaccin
  • Double blinding:
    • ouders en kinderen weten niet of ze werden gevaccineerd of niet
    • medische staf en onderzoekers weten niet of het kind het vaccin of de placebo kreeg

3.9.2 Data

salk <- data.frame(
  group=c("cases","control","noConcent"),
  treatment=c("vaccine","placebo","none"),
  total=c(200745,201229, 338778),polio=c(57,142,157)
  ) %>%
  mutate(
    noPolio = total-polio,
    incidencePM = round(polio/total*1e6,0)
    )
knitr::kable(salk)
group treatment total polio noPolio incidencePM
cases vaccine 200745 57 200688 284
control placebo 201229 142 201087 706
noConcent none 338778 157 338621 463
  • We observeren een veel groter effect nu dat cases en controles vergelijkbaar zijn, incidentie van respectievelijk 284 and 706 per miljoen.

  • De polio incidentie voor kinderen die geen toestemming geven blijft vergelijkbaar 453 and 463 per miljoen respectievelijk in the NFIP and Salk study.


4 Rol van Statistiek

  • We hebben gezien dat
    • het belangrijk is om de scope van de studie goed te specifiëren voor de start van het experiment
    • randomisatie nodig is om een representatieve steekproef te nemen
    • steekproef grootte is heel belangrijk
    • we moeten ons bewust zijn van Confounding
    • een goede controle is belangrijk

\(\rightarrow\) Goede proefopzet is cruciaal!


  • We hebben ook geobserveerd dat er variabiliteit is in de populatie
  • We kunnen maar een beperkte steekproef nemen uit de populatie

\(\rightarrow\) onzekerheid in de resultaten \(\rightarrow\) onzekerheid in de conclusies


  • Statistiek is de wetenschap voor het
    1. verzamelen (experimenteel design),
    2. exploren (data exploration) en
    3. leren van data zodat we hetgeen we observeren in de steekproef zouden kunnen veralgemenen naar de populatie terwijl we de onzekerheid quantificeren, controleren en rapporteren (statistisch modelleren en statistische besluitvorming).
  • Statistiek speelt daarom een heel belangrijke rol in zowat alle wetenschappen
LS0tCnRpdGxlOiAiMS4gSW5sZWlkaW5nOiBXYWFyb20gU3RhdGlzdGllaz8iCmF1dGhvcjogIkxpZXZlbiBDbGVtZW50IgpkYXRlOiAic3RhdE9taWNzLCBHaGVudCBVbml2ZXJzaXR5IChodHRwczovL3N0YXRvbWljcy5naXRodWIuaW8pIgpvdXRwdXQ6CiAgICBodG1sX2RvY3VtZW50OgogICAgICBjb2RlX2Rvd25sb2FkOiB0cnVlICAgIAogICAgICB0aGVtZTogY29zbW8KICAgICAgdG9jOiB0cnVlCiAgICAgIHRvY19mbG9hdDogdHJ1ZQogICAgICBoaWdobGlnaHQ6IHRhbmdvCiAgICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQotLS0KCiMgSW50cm9kdWN0aWUKCmBgYHtyIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChpbmNsdWRlID0gVFJVRSwgY29tbWVudCA9IE5BLCBlY2hvID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKYGBgCgotIFdlIGxldmVuIGluIGhldCBiaWcgZGF0YSBlcmEKLSBHZWdldmVucyBvdmVyIGxvY2F0aWUsIHN1cmZnZWRyYWcsIGFhbmtvb3BnZWRyYWcsIHNvY2lhbGUgbWVkaWEKLSBXZXRlbnNjaGFwOiBleHByZXNzaWUgbWV0ZW4gdmFuIGR1aXplbmRlbiBnZW5lbiwgZWl3aXR0ZW4sLi4uIHZvb3IgZWxrIHN1YmplY3QKLSBDaGVtaXNjaGUgcHJvY2VzIGNvbnRyb2xlOiBncm9vdCBhYW50YWwgc2Vuc29yZW4gZGllIGNvbnRpbnUgZWVuIHByb2NlcyBtZXRlbiB6b2RhdCBoZXQgcHJvY2VzIGthbiB3b3JkZW4gYmlqZ2VzdHV1cmQKLSBEYXRhIGRyaXZlbiBqb3VybmFsaXNtCi0gLi4uCgpTdGF0aXN0aWVrIGlzIGRlIHdldGVuc2NoYXAgb20gdGUgbGVyZW4gdWl0IGVtcGlyaXNjaGUgZ2VnZXZlbnMKClN0YXRpc3Rpc2NoZSBnZWxldHRlcmRoZWlkIGlzIGNydWNpYWFsIG9tIHJlc3VsdGF0ZW4gZW4gcHVibGljYXRpZXMga3JpdGlzY2ggdGUga3VubmVuIGludGVycHJldGVyZW4uCgotLS0KCiMgQ2FzZSBzdHVkeTogb2tzZWwgbWljcm9iaW9tZQoKCiFbXShodHRwczovL2ltYWdlcy52cnQuYmUvd2lkdGgxMjgwLzIwMTgvMDYvMjcvNGU3MjA5OGQtN2EwZC0xMWU4LWFiY2MtMDJiN2I3NmJmNDdmLmpwZyl7d2lkdGg9NzAlfQoKLSBodHRwczovL3d3dy52cnQuYmUvdnJ0bndzL25sLzIwMTgvMTAvMjIvZ2V6b2NodC1tZW5zZW4tbWV0LXBlbmV0cmFudGUtbGlqZmdldXItb20tcHJvYmlvdGlzY2hlLWRlb2Rvci8KLSBodHRwczovL3lvdXR1LmJlLzlSSUZ5cUxYZFZ3CgotLS0KCi0gT2tzZWxnZXVyIHdvcmR0IG5pZXQgdmVyb29yemFha3QgZG9vciBoZXQgendlZXQgemVsZi4gRGUgZ2V1ciBpcyBhZmtvbXN0aWcgdmFuIHNwZWNpZmljaWVrIG1pY3JvLW9yZ2FuaXNtZW4gdmFuIGRlIGdyb2VwICpDb3J5bmViYWN0ZXJpdW0gc3BwLiogZGllIGhldCB6d2VldCBtZXRhYm9saXNlcmVuLiAqU3RhcGh5bG9jb2NjdXMgc3BwLiogemlqbiBlZW4gYW5kZXJlIGdyb2VwIGJhY3RlcmnDq24gZGllIG9vayBhYnVuZGFudCB6aWpuIGluIGhldCBtaWNyb2Jpb21lIHZhbiBkZSBva3NlbCBkaWUgendlZXQgbWV0YWJvbGlzZXJlbiBuYWFyIG1ldGFib2xpZXRlbiBkaWUgbmlldCBzdGlua2VuLgoKLSBEZSBDTUVULWdyb2VwIGFhbiBVR0VOVCBkb2V0IG9uZGVyem9layBuYWFyIGhldCB0cmFuc3BsYW50ZXJlbiB2YW4gZGUgbWljcm9iacOrbGUgZ2VtZWVuc2NoYXAsIGhldCBtaWNyb2Jpb21lLCBvbSBtZW5zZW4gdmFuIGdldXJlbmRlIG9rc2VscyBhZiB0ZSBoZWxwZW4uICAKCi0gVm9vcmdlc3RlbGRlIHRoZXJhcGllCiAgCTEuIFZlcndpamRlciBoZXQgb2tzZWwgbWljcm9iaW9tZSBtZXQgYW50aWJpb3RpY2EKICAgIDIuIEJlw69udmxvZWQgaGV0IG9rc2VsIG1pY3JvYmlvbWUgZG9vciBtaWNyb2Jpb21lIHRlIHRyYW5zcGxhbnRlcmVuIHZhbiBlZW4gaW5kaXZpZHVlIGRpZSBnZWVuIGdldXJlbmRlIG9rc2VscyBoZWVmdCAoaHR0cHM6Ly95b3V0dS5iZS85UklGeXFMWGRWdykKCgotLS0KCiMjIFByb2Vmb3B6ZXQgKGV4cGVyaW1lbnRhbCBkZXNpZ24pCgpgYGB7ciBvdXQud2lkdGg9JzgwJScsZmlnLmFzcD0uOCwgZmlnLmFsaWduPSdjZW50ZXInLGVjaG89RkFMU0V9CmlmICgicGkiJWluJWxzKCkpIHJtKCJwaSIpCmtvcHZvZXRlcjwtZnVuY3Rpb24oeCx5LGFuZ2xlPTAsbD0uMixjZXguZG90PS41LHBjaD0xOSxjb2w9ImJsYWNrIikKewphbmdsZT1hbmdsZS8xODAqcGkKcG9pbnRzKHgseSxjZXg9Y2V4LmRvdCxwY2g9cGNoLGNvbD1jb2wpCmxpbmVzKGMoeCx4K2wqY29zKC1waS8yK2FuZ2xlKSksYyh5LHkrbCpzaW4oLXBpLzIrYW5nbGUpKSxjb2w9Y29sKQpsaW5lcyhjKHgrbC8yKmNvcygtcGkvMithbmdsZSkseCtsLzIqY29zKC1waS8yK2FuZ2xlKStsLzQqY29zKGFuZ2xlKSksYyh5K2wvMipzaW4oLXBpLzIrYW5nbGUpLHkrbC8yKnNpbigtcGkvMithbmdsZSkrbC80KnNpbihhbmdsZSkpLGNvbD1jb2wpCmxpbmVzKGMoeCtsLzIqY29zKC1waS8yK2FuZ2xlKSx4K2wvMipjb3MoLXBpLzIrYW5nbGUpK2wvNCpjb3MocGkrYW5nbGUpKSxjKHkrbC8yKnNpbigtcGkvMithbmdsZSkseStsLzIqc2luKC1waS8yK2FuZ2xlKStsLzQqc2luKHBpK2FuZ2xlKSksY29sPWNvbCkKbGluZXMoYyh4K2wqY29zKC1waS8yK2FuZ2xlKSx4K2wqY29zKC1waS8yK2FuZ2xlKStsLzIqY29zKC1waS8yK3BpLzQrYW5nbGUpKSxjKHkrbCpzaW4oLXBpLzIrYW5nbGUpLHkrbCpzaW4oLXBpLzIrYW5nbGUpK2wvMipzaW4oLXBpLzIrcGkvNCthbmdsZSkpLGNvbD1jb2wpCmxpbmVzKGMoeCtsKmNvcygtcGkvMithbmdsZSkseCtsKmNvcygtcGkvMithbmdsZSkrbC8yKmNvcygtcGkvMi1waS80K2FuZ2xlKSksYyh5K2wqc2luKC1waS8yK2FuZ2xlKSx5K2wqc2luKC1waS8yK2FuZ2xlKStsLzIqc2luKC1waS8yLXBpLzQrYW5nbGUpKSxjb2w9Y29sKQp9CgpwYXIobWFyPWMoMCwwLDAsMCksbWFpPWMoMCwwLDAsMCkpCnBsb3QoMCwwLHhsYWI9IiIseWxhYj0iIix4bGltPWMoMCwxMCkseWxpbT1jKDAsMTApLGNvbD0wLHhheHQ9Im5vbmUiLHlheHQ9Im5vbmUiLGF4ZXM9RkFMU0UpCnJlY3QoMCw2LDEwLDEwLGJvcmRlcj0icmVkIixsd2Q9MikKdGV4dCguNSw4LCJwb3B1bGF0aW9uIixzcnQ9OTAsY29sPSJyZWQiLGNleD0yKQpzeW1ib2xzICgzLCA4LCBjaXJjbGVzPTEuNSwgY29sPSJyZWQiLGFkZD1UUlVFLGZnPSJyZWQiLGluY2hlcz1GQUxTRSxsd2Q9MikKc2V0LnNlZWQoMzMwKQpncmlkPXNlcSgwLDEuMywuMDEpCgpmb3IgKGkgaW4gMTo1MCkKewoJYW5nbGUxPXJ1bmlmKG49MSxtaW49MCxtYXg9MzYwKQoJYW5nbGUyPXJ1bmlmKG49MSxtaW49MCxtYXg9MzYwKQoJcmFkaXVzPXNhbXBsZShncmlkLHByb2I9Z3JpZF4yKnBpL3N1bShncmlkXjIqcGkpLHNpemU9MSkKCWtvcHZvZXRlcigzK3JhZGl1cypjb3MoYW5nbGUxLzE4MCpwaSksOCtyYWRpdXMqc2luKGFuZ2xlMS8xODAqcGkpLGFuZ2xlPWFuZ2xlMikKfQp0ZXh0KDcuNSw4LCJNaWNyb2Jpb21lIGluIHBvcHVsYXRpb24iLGNvbD0icmVkIixjZXg9MS4yKQpgYGAKCi0tLQoKCmBgYHtyIG91dC53aWR0aD0nODAlJyxmaWcuYXNwPS44LCBmaWcuYWxpZ249J2NlbnRlcicsZWNobz1GQUxTRX0KaWYgKCJwaSIlaW4lbHMoKSkgcm0oInBpIikKa29wdm9ldGVyPC1mdW5jdGlvbih4LHksYW5nbGU9MCxsPS4yLGNleC5kb3Q9LjUscGNoPTE5LGNvbD0iYmxhY2siKQp7CmFuZ2xlPWFuZ2xlLzE4MCpwaQpwb2ludHMoeCx5LGNleD1jZXguZG90LHBjaD1wY2gsY29sPWNvbCkKbGluZXMoYyh4LHgrbCpjb3MoLXBpLzIrYW5nbGUpKSxjKHkseStsKnNpbigtcGkvMithbmdsZSkpLGNvbD1jb2wpCmxpbmVzKGMoeCtsLzIqY29zKC1waS8yK2FuZ2xlKSx4K2wvMipjb3MoLXBpLzIrYW5nbGUpK2wvNCpjb3MoYW5nbGUpKSxjKHkrbC8yKnNpbigtcGkvMithbmdsZSkseStsLzIqc2luKC1waS8yK2FuZ2xlKStsLzQqc2luKGFuZ2xlKSksY29sPWNvbCkKbGluZXMoYyh4K2wvMipjb3MoLXBpLzIrYW5nbGUpLHgrbC8yKmNvcygtcGkvMithbmdsZSkrbC80KmNvcyhwaSthbmdsZSkpLGMoeStsLzIqc2luKC1waS8yK2FuZ2xlKSx5K2wvMipzaW4oLXBpLzIrYW5nbGUpK2wvNCpzaW4ocGkrYW5nbGUpKSxjb2w9Y29sKQpsaW5lcyhjKHgrbCpjb3MoLXBpLzIrYW5nbGUpLHgrbCpjb3MoLXBpLzIrYW5nbGUpK2wvMipjb3MoLXBpLzIrcGkvNCthbmdsZSkpLGMoeStsKnNpbigtcGkvMithbmdsZSkseStsKnNpbigtcGkvMithbmdsZSkrbC8yKnNpbigtcGkvMitwaS80K2FuZ2xlKSksY29sPWNvbCkKbGluZXMoYyh4K2wqY29zKC1waS8yK2FuZ2xlKSx4K2wqY29zKC1waS8yK2FuZ2xlKStsLzIqY29zKC1waS8yLXBpLzQrYW5nbGUpKSxjKHkrbCpzaW4oLXBpLzIrYW5nbGUpLHkrbCpzaW4oLXBpLzIrYW5nbGUpK2wvMipzaW4oLXBpLzItcGkvNCthbmdsZSkpLGNvbD1jb2wpCn0KCnBhcihtYXI9YygwLDAsMCwwKSxtYWk9YygwLDAsMCwwKSkKcGxvdCgwLDAseGxhYj0iIix5bGFiPSIiLHhsaW09YygwLDEwKSx5bGltPWMoMCwxMCksY29sPTAseGF4dD0ibm9uZSIseWF4dD0ibm9uZSIsYXhlcz1GQUxTRSkKcmVjdCgwLDYsMTAsMTAsYm9yZGVyPSJyZWQiLGx3ZD0yKQp0ZXh0KC41LDgsInBvcHVsYXRpb24iLHNydD05MCxjb2w9InJlZCIsY2V4PTIpCnN5bWJvbHMgKDMsIDgsIGNpcmNsZXM9MS41LCBjb2w9InJlZCIsYWRkPVRSVUUsZmc9InJlZCIsaW5jaGVzPUZBTFNFLGx3ZD0yKQpzZXQuc2VlZCgzMzApCmdyaWQ9c2VxKDAsMS4zLC4wMSkKCmZvciAoaSBpbiAxOjUwKQp7CglhbmdsZTE9cnVuaWYobj0xLG1pbj0wLG1heD0zNjApCglhbmdsZTI9cnVuaWYobj0xLG1pbj0wLG1heD0zNjApCglyYWRpdXM9c2FtcGxlKGdyaWQscHJvYj1ncmlkXjIqcGkvc3VtKGdyaWReMipwaSksc2l6ZT0xKQoJa29wdm9ldGVyKDMrcmFkaXVzKmNvcyhhbmdsZTEvMTgwKnBpKSw4K3JhZGl1cypzaW4oYW5nbGUxLzE4MCpwaSksYW5nbGU9YW5nbGUyKQp9CnRleHQoNy41LDgsIk1pY3JvYmlvbWUgaW4gcG9wdWxhdGlvbiIsY29sPSJyZWQiLGNleD0xLjIpCgpyZWN0KDAsMCwxMCw0LGJvcmRlcj0iYmx1ZSIsbHdkPTIpCnRleHQoLjUsMiwic2FtcGxlIixzcnQ9OTAsY29sPSJibHVlIixjZXg9MikKc3ltYm9scyAoMywgMiwgY2lyY2xlcz0xLjUsIGNvbD0icmVkIixhZGQ9VFJVRSxmZz0iYmx1ZSIsaW5jaGVzPUZBTFNFLGx3ZD0yKQpmb3IgKGkgaW4gMDoxKQoJZm9yIChqIGluIDA6NCkKewoKCWtvcHZvZXRlcigyLjEraiooMy45LTIuMSkvNCwxLjEraS8yLGNvbD0iYmxhY2siKQp9CmZvciAoaSBpbiAyOjMpCglmb3IgKGogaW4gMDo0KQp7CgoJa29wdm9ldGVyKDIuMStqKigzLjktMi4xKS80LDEuNitpLzIsY29sPSJibGFjayIpCn0KdGV4dCg3LjUsMiwiTWljcm9iaW9tZSBpbiBzYW1wbGUiLGNvbD0iYmx1ZSIsY2V4PTEuMikKCmFycm93cygzLDUuOSwzLDQuMSxjb2w9ImJsYWNrIixsd2Q9MykKdGV4dCgxLjUsNSwiRVhQLiBERVNJR04gKDEpIixjb2w9ImJsYWNrIixjZXg9MS4yKQpgYGAKCi0tLQoKLSBFeHBlcmltZW50OgoKICAgIC0gMjAgcGVyc29uZW4gd29yZGVuIGF0IHJhbmRvbSB1aXQgZGUgcG9wdWxhdGllIGdldHJva2tlbiB2YW4gcGVyc29uZW4gbWV0IGVlbiBva3NlbGdldXI6IHN0ZWVrcHJvZWYgcmVwcmVzZW50YXRpZWYgdm9vciBwb3B1bGF0aWUhCgogICAgLSBkZSBwZXJzb25lbiB3b3JkZW4gYXQgcmFuZG9tIHZlcmRlZWxkIG92ZXIgdHdlZSBiZWhhbmRlbGluZ3Nncm9lcGVuOgoKICAgICAgICAtIHBsYWNlYm8gKGVua2VsIGFudGliaW90aWNhKQogICAgICAgIC0gdHJhbnNwbGFudGllIChhbnRpYmlvdGljYSBlbiBtaWNyb2Jpw6tsZSB0cmFuc3BsYW50YXRpZSkuCiAgICAgICAgLSBSYW5kb21pc2F0aWUgaXMgYmVsYW5ncmlqayBvbSBlcnZvb3IgdGUgem9yZ2VuIGRhdCBkZSBncm9lcGVuIHZlcmdlbGlqa2JhYXIgemlqbi4KCiAgICAtIEhldCBtaWNyb2Jpb21lIHdvcmR0IGJlbW9uc3RlcmQgNiB3ZWtlbiBuYSBkZSBiZWhhbmRlbGluZy4KICAgIC0gVGhlIHJlbGF0aXZlIGFidW5kYW50aWUgdmFuICpTdGFwaHlsb2NvY2N1cyBzcHAuKiBvcCAqQ29yeW5lYmFjdGVyaXVtIHNwcC4qICsgKlN0YXBoeWxvY29jY3VzIHNwcC4qIGluIGhldCBtaWNyb2Jpb21lIHdvcmR0IGdlbWV0ZW4gdmlhIERHR0UgKCpEZW5hdHVyaW5nIEdyYWRpZW50IEdlbCBFbGVjdHJvcGhvcmVzaXMqKS4KCi0tLQoKREdHRQoKIVtdKGh0dHBzOi8vam91cm5hbHMucGxvcy5vcmcvcGxvc29uZS9hcnRpY2xlL2ZpZ3VyZS9pbWFnZT9zaXplPWxhcmdlJmRvd25sb2FkPSZpZD0xMC4xMzcxL2pvdXJuYWwucG9uZS4wMDcwNTM4LmcwMDEpe3dpZHRoPTcwJX0KCmh0dHBzOi8vZG9pLm9yZy8xMC4xMzcxL2pvdXJuYWwucG9uZS4wMDcwNTM4CgotLS0KClZlcnRhYWwgb25kZXJ6b2Vrc3ZyYWFnIG5hYXIgaWV0cyB3YXQgd2Uga3VubmVuIHF1YW50aWZpY2VyZW46IElzIGVyIGVlbiB2ZXJzY2hpbCBpbiByZWxhdGlldmUgYWJ1bmRhbnRpZSB2YW4gKlN0YXBoeWxvY29jY3VzIHNwcC4qIGluIGhldCBtaWNyb2Jpb21lIHZhbiBkZSBwbGFjZWJvIGdyb2VwIGVuIGRlIHRyYW5zcGxhbnRhdGllCgotLS0KCmBgYHtyIG91dC53aWR0aD0nODAlJyxmaWcuYXNwPS44LCBmaWcuYWxpZ249J2NlbnRlcicsZWNobz1GQUxTRX0KaWYgKCJwaSIlaW4lbHMoKSkgcm0oInBpIikKa29wdm9ldGVyPC1mdW5jdGlvbih4LHksYW5nbGU9MCxsPS4yLGNleC5kb3Q9LjUscGNoPTE5LGNvbD0iYmxhY2siKQp7CmFuZ2xlPWFuZ2xlLzE4MCpwaQpwb2ludHMoeCx5LGNleD1jZXguZG90LHBjaD1wY2gsY29sPWNvbCkKbGluZXMoYyh4LHgrbCpjb3MoLXBpLzIrYW5nbGUpKSxjKHkseStsKnNpbigtcGkvMithbmdsZSkpLGNvbD1jb2wpCmxpbmVzKGMoeCtsLzIqY29zKC1waS8yK2FuZ2xlKSx4K2wvMipjb3MoLXBpLzIrYW5nbGUpK2wvNCpjb3MoYW5nbGUpKSxjKHkrbC8yKnNpbigtcGkvMithbmdsZSkseStsLzIqc2luKC1waS8yK2FuZ2xlKStsLzQqc2luKGFuZ2xlKSksY29sPWNvbCkKbGluZXMoYyh4K2wvMipjb3MoLXBpLzIrYW5nbGUpLHgrbC8yKmNvcygtcGkvMithbmdsZSkrbC80KmNvcyhwaSthbmdsZSkpLGMoeStsLzIqc2luKC1waS8yK2FuZ2xlKSx5K2wvMipzaW4oLXBpLzIrYW5nbGUpK2wvNCpzaW4ocGkrYW5nbGUpKSxjb2w9Y29sKQpsaW5lcyhjKHgrbCpjb3MoLXBpLzIrYW5nbGUpLHgrbCpjb3MoLXBpLzIrYW5nbGUpK2wvMipjb3MoLXBpLzIrcGkvNCthbmdsZSkpLGMoeStsKnNpbigtcGkvMithbmdsZSkseStsKnNpbigtcGkvMithbmdsZSkrbC8yKnNpbigtcGkvMitwaS80K2FuZ2xlKSksY29sPWNvbCkKbGluZXMoYyh4K2wqY29zKC1waS8yK2FuZ2xlKSx4K2wqY29zKC1waS8yK2FuZ2xlKStsLzIqY29zKC1waS8yLXBpLzQrYW5nbGUpKSxjKHkrbCpzaW4oLXBpLzIrYW5nbGUpLHkrbCpzaW4oLXBpLzIrYW5nbGUpK2wvMipzaW4oLXBpLzItcGkvNCthbmdsZSkpLGNvbD1jb2wpCn0KCnBhcihtYXI9YygwLDAsMCwwKSxtYWk9YygwLDAsMCwwKSkKcGxvdCgwLDAseGxhYj0iIix5bGFiPSIiLHhsaW09YygwLDEwKSx5bGltPWMoMCwxMCksY29sPTAseGF4dD0ibm9uZSIseWF4dD0ibm9uZSIsYXhlcz1GQUxTRSkKcmVjdCgwLDYsMTAsMTAsYm9yZGVyPSJyZWQiLGx3ZD0yKQp0ZXh0KC41LDgsInBvcHVsYXRpb24iLHNydD05MCxjb2w9InJlZCIsY2V4PTIpCnN5bWJvbHMgKDMsIDgsIGNpcmNsZXM9MS41LCBjb2w9InJlZCIsYWRkPVRSVUUsZmc9InJlZCIsaW5jaGVzPUZBTFNFLGx3ZD0yKQpzZXQuc2VlZCgzMzApCmdyaWQ9c2VxKDAsMS4zLC4wMSkKCmZvciAoaSBpbiAxOjUwKQp7CglhbmdsZTE9cnVuaWYobj0xLG1pbj0wLG1heD0zNjApCglhbmdsZTI9cnVuaWYobj0xLG1pbj0wLG1heD0zNjApCglyYWRpdXM9c2FtcGxlKGdyaWQscHJvYj1ncmlkXjIqcGkvc3VtKGdyaWReMipwaSksc2l6ZT0xKQoJa29wdm9ldGVyKDMrcmFkaXVzKmNvcyhhbmdsZTEvMTgwKnBpKSw4K3JhZGl1cypzaW4oYW5nbGUxLzE4MCpwaSksYW5nbGU9YW5nbGUyKQp9CnRleHQoNy41LDgsIk1pY3JvYmlvbWUgaW4gcG9wdWxhdGlvbiIsY29sPSJyZWQiLGNleD0xLjIpCgpyZWN0KDAsMCwxMCw0LGJvcmRlcj0iYmx1ZSIsbHdkPTIpCnRleHQoLjUsMiwic2FtcGxlIixzcnQ9OTAsY29sPSJibHVlIixjZXg9MikKc3ltYm9scyAoMywgMiwgY2lyY2xlcz0xLjUsIGNvbD0icmVkIixhZGQ9VFJVRSxmZz0iYmx1ZSIsaW5jaGVzPUZBTFNFLGx3ZD0yKQpmb3IgKGkgaW4gMDoxKQoJZm9yIChqIGluIDA6NCkKewoKCWtvcHZvZXRlcigyLjEraiooMy45LTIuMSkvNCwxLjEraS8yLGNvbD0icHVycGxlIikKfQpmb3IgKGkgaW4gMjozKQoJZm9yIChqIGluIDA6NCkKewoKCWtvcHZvZXRlcigyLjEraiooMy45LTIuMSkvNCwxLjYraS8yLGNvbD0ib3JhbmdlIikKfQp0ZXh0KDcuNSwyLCJNaWNyb2Jpb21lIGluIHNhbXBsZSIsY29sPSJibHVlIixjZXg9MS4yKQoKYXJyb3dzKDMsNS45LDMsNC4xLGNvbD0iYmxhY2siLGx3ZD0zKQp0ZXh0KDEuNSw1LCJFWFAuIERFU0lHTiAoMSkiLGNvbD0iYmxhY2siLGNleD0xLjIpCnRleHQoNy41LC41LCJEQVRBIEVYUExPUkFUSU9OICZcbkRFU0NSSVBUSVZFIFNUQVRJU1RJQ1MgKDIpIixjb2w9ImJsYWNrIixjZXg9MS4yKQpgYGAKCi0tLQoKIyMgRGF0YSBFeHBsb3JhdGllIGVuIGJlc2NocmlqdmVuZGUgc3RhdGlzdGllawoKCi0gRGF0YSBleHBsb3JhdGllIGlzIGhlZWwgYmVsYW5ncmlqayBvbSBpbnppY2h0IHRlIGtyaWpnZW4gaW4gZGUgZGF0YSBlbiBpcyBlZW4gZXNzZW50acOrbGUgZWVyc3RlIHN0YXAgb20gdGUgbGVyZW4gdWl0IGRhdGEuCi0gSGV0IHdvcmR0IHZhYWsgb25kZXJnZXdhYXJkZWVyZCBvZiBvdmVyIGhldCBob29mZCBnZXppZW4uCgotLS0KCiMjIyBJbXBvcnRlZXIgZGUgZGF0YQoKLSBEYXRhIGluIGRlemUgY3Vyc3VzIHdvcmR0IHZlcndlcmt0IHZpYSBoZXQgc3RhdGlzdGlzY2ggc29mdHdhcmUgcGFra2V0IFIuCi0gRGl0IHBha2tldCBsYWF0IHRvZSBvbSB0ZSBsZXJlbiB1aXQgZGF0YS4KLSBJbiBkZXplIGN1cnN1cyBnYWFuIHdlIGRhdGEgZWVyc3QgZXhwbG9yZXJlbiBvbSBpbnppY2h0IHRlIHZlcndlcnZlbiBpbiBkZSBnZWdldmVucyBvbSBkaWUgdmVydm9sZ2VucyBzdGF0aXN0aXNjaCB0ZSB2ZXJ3ZXJrZW4uCi0gVm9vcmFsZWVyIHdlIGhpZXJtZWUgdmFuIHN0YXJ0IGt1bm5lbiBnYWFuIG1vZXRlbiB3ZSBkZSBkYXRhIGVlcnN0IGltcG9ydGVyZW4gaW4gUi4KCi0gVmlhIGhldCB2b2xnZW5kZSBjb21tYW5kbyBrdW5uZW4gd2UgZW5rZWxlIHJlZ2VscyB2YW4gZWVuIGRhdGEgYmVzdGFuZCBpbmxlemVuIG9tIGRlIHN0cnVjdHV1ciB2YW4gaGV0IGRhdGEgYmVzdGFuZCB0ZSB3ZXRlbiB0ZSBrb21lbi4KCmBgYHtyfQpyZWFkX2xpbmVzKCJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vc3RhdE9taWNzL3NiYzIwL21hc3Rlci9kYXRhL2FybXBpdC5jc3YiKQpgYGAKCi0gR2VnZXZlbnMgaW4gaGV0IGJlc3RhbmQgemlqbiBkb29yIGNvbW1hJ3MgZ2VzY2hlaWRlbi4KLSBFbGtlIHJpaiBiZXZhdCBkZSBnZWdldmVucyB2b29yIDEgcHJvZWZwZXJzb29uCi0gVmVyc2NoaWxsZW5kZSB2YXJpYWJlbGVuIHdvcmRlbiBnZW1ldGVuIHBlciBwZXJzb29uIGVuIHppam4gdmFuIGVsa2FhciBnZXNjaGVpZGVuIGRvb3IgZWVuIGNvbW1hLiBIZXQgYmVzdGFuZCBpcyBjc3YgZm9ybWFhdDogImNvbW1hIHNlcGFyYXRlZCB2YWx1ZXMiLgotIFdlIGt1bm5lbiBiZXN0YW5kZW4gbWV0IGRpdCBmb3JtYWF0IGlubGV6ZW4gUiB2aWEgaGV0IGNvbW1hbmRvIHJlYWRfY3N2LgotIFdlIHNsYWFuIGRlIGRhdGEgb3AgaW4gUiBpbiBoZXQgb2JqZWN0IG1ldCBuYWFtIGFwLiBIaWVydm9vciBnZWJydWlrZW4gd2UgZGUgYDwtYCBvcGVyYXRvci4KLSBXZSBnZXZlbiBkZSBkYXRhIHRhYmVsIHRlcnVnIGRvb3IgaGV0IG9iamVjdCBhYW4gdGUgcm9lcGVuIGRvb3IgemlqbiBuYWFtIHRlIHR5cGVuLgoKYGBge3J9CmFwIDwtIHJlYWRfY3N2KCJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vc3RhdE9taWNzL3NiYzIwL21hc3Rlci9kYXRhL2FybXBpdC5jc3YiKQphcApgYGAKCi0tLQoKIyMjIEJlc2NocmlqdmVuZGUgc3RhdGlzdGllawoKLSBJbiBhcnRpa2VscyBlbiBkZSBtZWRpYSB3b3JkZW4gcmVzdWx0YXRlbiB1aXQgZWVuIHN0ZWVrcHJvZWYgdmFhayBnZXJhcHBvcnRlZXJkIGEuZC5oLnYuIGdlbWlkZGVsZGUgZW4gZGUgc3RhbmRhYXJkYWZ3aWpraW5nCgotIFdlIHZhdHRlbiBkZSBkYXRhIGVlcnN0IHNhbWVuLiBXZSBiZXJla2VuZW4gaGV0IGdlbWlkZGVsZGUgZW4gZGUgc3RhbmRhYXJkIGRldmlhdGllIChlZW4gbWFhdCB2b29yIGRlIHNwcmVpZGluZywgemllIHZvbGdlbmRlIGhvb2Zkc3R1a2tlbikuCldlIHNsYWFuIGhldCByZXN1bHRhYXQgaGllcnZhbiBvcCBpbiBoZXQgb2JqZWN0IGFwUmVsU3VtIHZpYSBgYXBSZWxTdW0gPC1gLgoKMS4gV2UgcGlwZW4gKHZpYSBgJT4lYCkgaGV0IGBhcGAgZGF0YWZyYW1lIG5hYXIgZGUgYGdyb3VwX2J5YCBmdW5jdGllIG9tIGRlIGRhdGEgdGUgZ3JvZXBlcmVuIHBlciB0cmVhdG1lbnQgdHJ0OiBgZ3JvdXBfYnkodHJ0KWAuCgoyLiBXZSBwaXBlbiBoZXQgcmVzdWx0YWF0IG5hYXIgZGUgYHN1bW1hcml6ZV9hdGAgZnVuY3Rpb24gb20gZGUgInJlbCIgdmFyaWFibGUgc2FtZW4gdGUgdmF0dGVuIGVuIGJlcmVrZW5lbiBoaWVyYmlqIGhldCBnZW1pZGRlbGRlIGVuIHN0YW5kYWFyZGFmd2lqa2luZy4gT21kYXQgd2UgZGUgZGF0YSBlZXJzdCBoZWJiZW4gZ2Vncm9lcGVlcmQgenVsbGVuIHdlIGhldCBnZW1pZGRlbGRlIGVuIGRlIHN0YW5kYWFyZCBkZXZpYXRpZSBiZXJla2VuZW4gcGVyIGdyb2VwLgoKCgpgYGB7cn0KYXBSZWxTdW0gPC0gYXAgJT4lCiAgZ3JvdXBfYnkodHJ0KSAlPiUKICBzdW1tYXJpemVfYXQoInJlbCIsCiAgICAgICAgICAgICAgIGxpc3QobWVhbj1tZWFuLAogICAgICAgICAgICAgICAgICAgIHNkPXNkCiAgICAgICAgICAgICAgICAgICAgKQogICAgICAgICAgICAgICAgKQpgYGAKCldlIHRvbmVuIHZlcnZvbGdlbnMgaGV0IHJlc3VsdGFhdCBkb29yIGhldCBvYmplY3QgYXBSZWxTdW0gYWFuIHRlIHJvZXBlbgoKYGBge3J9CmFwUmVsU3VtCmBgYAoKV2Uga3VubmVuIG9vayBlZW4gdGFiZWwgaW4gZGUgd2VicGFnaW5hIG9mIGhldCBwZGYgYmVzdGFuZCBpbnRlZ3JlcmVuIHZpYSBoZXQgY29tbWFuZG8ga2FibGUgdmFuIGhldCBrbml0ciBwYWtrZXQ6CgpgYGB7cn0Ka25pdHI6OmthYmxlKGFwUmVsU3VtKQpgYGAKCi0tLQoKIyMjIEdyYWZpZWtlbgoKV2UgbWFrZW4gaW4gZGV6ZSBjdXJzdXMgZ2VicnVpayB2YW4gaGV0IHBha2tldCBgZ2dwbG90MmAgb20gZ3JhZmlla2VuIHRlIG1ha2VuLiAgCk1ldCBkZSBnZ3Bsb3QyIGJpYmxpb3RoZWVrIGt1bm5lbiB3ZSBnZW1ha2tlbGlqayBncmFmaWVrZW4gb3Bib3V3ZW4gaW4gbGFnZW4gKGxheWVycykuCkhpZXJkb29yIGxlZXN0IGRlIGNvZGUgdmVlbCBtYWtrZWxpamtlci4KCiMjIyMgYmFycGxvdAoKQmFyIHBsb3RzIHdvcmRlbiBoZWVsIHZlZWwgZ2VicnVpa3QgaW4gYXJ0aWtlbHMgb20gcmVzdWx0YXRlbiB3ZWVyIHRlIGdldmVuLgoKMS4gV2UgcGlwZW4gZGUgc2FtZW5nZXZhdHRlIGRhdGEgbmFhciBkZSBmdW5jdGllIGBnZ3Bsb3RgLiBEYXQgaXMgZGUgYmFzaXMgdmFuIGVsa2UgZ2dwbG90LiAgV2Ugc2VsZWN0ZXJlbiBkZSB2YXJpYWJlbGUgbWV0IGRlIGJlaGFuZGVsaW5nIHRydCBhbHMgeCB2YXJpYWJlbGUgZW4gZGUgdmFyaWFiZWxlIG1ldCBuYWFtIG1lYW4gYWxzIHktdmFyaWFiZWxlIHZvb3IgZGUgcGxvdC4KV2UgZG9lbiBkaXQgc3RlZWRzIHZpYSBkZSBhZXN0ZXRpY3MgYGFlc2AgZnVuY3RpZS4gICBgYWVzKHg9dHJ0LHk9bWVhbilgCgoyLiBXZSBtYWtlbiBlZW4gYmFycGxvdCBkb29yIGVlbiBsYWFnIHRvZSB0ZSB2b2VnZW4gdmlhIGRlICBgZ2VvbV9iYXJgIGZ1bmN0aW9uLiBEZSBzdGF0aXN0aWVrIGlzIGBzdGF0PSJpZGVudGl0eSJgIG9tZGF0IGRlIGhvb2d0ZSB2YW4gZGUgYmFyIGdlbGlqayBpcyBhYW4gZGUgd2FhcmRlIHZvb3IgeSAoaGllciBoZXQgZ2VtaWRkZWxkZSB2b29yIGRlIHJlbGF0aWV2ZSBhYnVuZGFudGllKS4KCjMuIFdlIHZvZWdlbiBmb3V0ZW52bGFnZ2VuIHRvZSBvbSBkZSBvbnpla2VyaGVpZCBvcCBoZXQgZ2VtaWRkZWxkZSB3ZWVyIHRlIGdldmVuLiAgV2UgZG9lbiBkaXQgdmlhIGRlIGBnZW9tX2Vycm9yYmFyYCBmdW5jdGllIGVuIHNwZWNpZmnDq3JlbiBoZXQgbWluaW11bSBlbiBtYXhpbXVtIHZhbiBkZSBlcnJvciBiYXIuIEhldCBgd2lkdGhgIGFyZ3VtZW50IHdvcmR0IGdlYnJ1aWt0IG9tIGRlIGJyZWVkdGUgdmFuIGRlIGVycm9yIGJhciBzbWFsbGVyIHRlIG1ha2VuIGRhdCBkZXplIHZhbiBkZSBiYXIuCgpgYGB7cn0KYXBSZWxTdW0gJT4lCiAgZ2dwbG90KGFlcyh4PXRydCx5PW1lYW4pKSArCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiKSArCiAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbj1tZWFuLXNkLHltYXg9bWVhbitzZCksd2lkdGg9LjIpCmBgYAoKLSBJcyBkZXplIHBsb3QgaW5mb3JtYXRpZWY/PwoKLS0tCgojIyMjIGJveHBsb3RzCgpCYXJwbG90cyB6aWpuIGdlZW4gZ29lZGUgZ3JhZmlla2VuOgoKLSBaZSB6aWpuIG5pZXQgaW5mb3JtYXRpZWYKCi0gWmUgdmlzdWxhcmlzZXJlbiBlZW4gc2FtZW52YXR0aW5nIHZhbiBkZSBkYXRhIGRvb3IgdHdlZSBwdW50ZW46IGB0d28gcG9pbnQgc3VtbWFyeWA6IGdlbWlkZGVsZGUgZW4gZGUgc3RhbmRhYXJkIGRldmlhdGllIGhpZXJvcCBlbiBrdW5uZW4gYmV0ZXIgaW4gZWVuIHRhYmVsIHdvcmRlbiBvcGdlbm9tZW4uCgotIFplIGxhdGVuIG5pZXQgdG9lIG9tIGFub21hbGllw6tuIGluIGRlIGRhdGEgem9hbHMgbWVldGZvdXRlbiBvcCB0ZSBzcG9yZW4uCgotIFplIHZlcmJydWlrZW4gdmVlbCBydWltdGUsIGIudi4gdmFuIG51bCB0b3QgZGUga2xlaW5zdGUgd2FhcmRlIHZvb3IgZGUgcmVsYXRpZXZlIGFidW5kYW50aWUpIHdhYXIgZ2VlbiBkYXRhIGluIGxpZ3QuCgpIZXQgaXMgYmV0ZXIgb20gZGUgZGF0YSB6byBydXcgbW9nZWxpamsgdm9vciB0ZSBzdGVsbGVuIHpvZGF0IHdlIGluemljaHQga3JpamdlbiBpbiBkZSB2ZXJkZWxpbmcgdmFuIGRlIGdlZ2V2ZW5zLgpIaWVydm9vciB6dWxsZW4gd2Ugb25kZXJtZWVyIGJveHBsb3RzIGdlYnJ1aWtlbi4KCi0tLQoKV2UgbWFrZW4gbnUgZWVuIGJveHBsb3Qgdm9vciBkZSBhcCBkYXRhCgoxLiBXZSBwaXBlbiBoZXQgYGFwYCBkYXRhZnJhbWUgbmFhciBgZ2dwbG90YAoyLiBXZSBzZWxlY3RlcmVuIGRlIGRhdGEgdm9vciBkZSBwbG90IHZpYSBgZ2dwbG90KGFlcyh4PXRydCx5PXJlbCkpYAozLiBXZSB2b2VnZW4gbGFhZyB0b2Ugdm9vciBkZSBib3hwbG90IGRtdiBkZSBmdW5jdGllIGBnZW9tX2JveHBsb3QoKWAKCmBgYHtyfQphcCAlPiUgIAogIGdncGxvdChhZXMoeD10cnQseT1yZWwpKSArCiAgZ2VvbV9ib3hwbG90KCkKYGBgCgotLS0KCk1lcmsgb3AgZGF0IHdlIGRlIHBsb3Qgb29rIG9wIGt1bm5lbiBzbGFhbiBhbHMgZWVuIG9iamVjdC4KCmBgYHtyfQphcEJveHBsb3QgPC0gYXAgJT4lICAKICBnZ3Bsb3QoYWVzKHg9dHJ0LHk9cmVsKSkgKwogIGdlb21fYm94cGxvdCgpCmBgYAoKRGUgcGxvdCB3b3JkdCBkYW4gbmlldCBnZW1hYWt0LgoKT20gZGUgcGxvdCB3ZWVyIHRlIGdldmVuIGt1bm5lbiB3ZSBoZXQgb2JqZWN0IGFhbnJvZXBlbgoKYGBge3J9CmFwQm94cGxvdApgYGAKCi0tLQoKLSBNZXJrIG9wIGRhdCB3ZSBuaWV0IHpvdmVlbCBnZWdldmVucyBoZWJiZW4uIEVua2VsIDEwIHBlciBncm9lcC4KCi0gSGV0IGlzIGFsdGlqZCBiZXRlciBvbSBkZSBkYXRhIHpvIHJ1dyBtb2dlbGlqayB0ZSB0b25lbiEKCk9tZGF0IGVyIG5pZXQgem92ZWVsIGdlZ2V2ZW5zIHppam4ga3VubmVuIHdlIGRlIGRhdGEgdG9ldm9lZ2VuIGFhbiBkZSBwbG90IHpvbmRlciBkYXQgZGllIHRlIGRydWsgd29yZHQuCgotIE1lcmsgb3AgZGF0IHdlIGhldCBhcmd1bWVudCBgb3V0bGllci5zaGFwZWAgb3AgTkEgKG5vdCBhdmFpbGFibGUpIHpldHRlbiBgb3V0bGllci5zaGFwZT1OQWAgaW4gdGhlIGBnZW9tX2JveHBsb3RgIGZ1bmN0aWUgb21kYXQgd2UgYW5kZXJzIG91dGxpZXJzIHR3ZWUga2VlciB3ZWVyIHp1bGxlbiBnZXZlbi4gRWVyc3QgdmlhIGRlIGJveHBsb3QgbGFhZyBlbiBkYWFybmEgb21kYXQgd2UgZWVuIGxhYWcgbWV0IGFsbGUgcnV3ZSBkYXRhIHRvZXZvZWdlbiBhYW4gZGUgcGxvdC4KLSBXZSBnZXZlbiBkZSBydXdlIGRhdGEgd2VlciB2aWEgZGUgIGBnZW9tX3BvaW50KHBvc2l0aW9uPSJqaXR0ZXIiKWAgZnVuY3RpZS4gV2UgZ2VicnVpa2VuIGhpZXJiaWogaGV0IGFyZ3VtZW50IHBvc2l0aW9uPSdqaXR0ZXInIHpvZGF0IHdlIHdhdCByYW5kb20gcnVpcyB0b2V2b2VnZW4gYWFuIGRlIHgtY29yZGluYWF0IHpvZGF0IGRlIGdlZ2V2ZW5zIGVsa2FhciBuaWV0IG92ZXJsYXBwZW4uCgpgYGB7cn0KYXAgJT4lICAKICBnZ3Bsb3QoYWVzKHg9dHJ0LHk9cmVsKSkgKwogIGdlb21fYm94cGxvdChvdXRsaWVyLnNoYXBlPU5BKSArCiAgZ2VvbV9wb2ludChwb3NpdGlvbj0iaml0dGVyIikKYGBgCgpEaXQgaXMgZWVuIGluZm9ybWF0aWV2ZSBwbG90IQoKLS0tCgpBYW5nZXppZW4gd2UgZGUgcGxvdCBvb2sgaGViYmVuIG9wZ2VzbGFnZW4ga29uZGVuIHdlIGRpdCBvb2sgZG9lbiBkb29yIGRlIHBsb3Qgb3AgdGUgcm9lcGVuIGVuIG5vZyBlZW4gbGFhZyB0b2UgdGUgdm9lZ2VuLgoKYGBge3J9CmFwQm94cGxvdCArCiAgZ2VvbV9wb2ludChwb3NpdGlvbj0iaml0dGVyIikKYGBgCgpXZSBoYWRkZW4gaGV0IHJlc3VsdGFhdCBvb2sgb3BuaWV1dyBvcCBrdW5uZW4gc2xhYW4gdm9vciBsYXRlciBoZXJnZWJydWlrLgoKYGBge3J9CmFwQm94cGxvdCA8LSBhcEJveHBsb3QgKwogIGdlb21fcG9pbnQocG9zaXRpb249ImppdHRlciIpCmBgYAoKLS0tCgotIFdlIHphZ2VuIGR1aWRlbGlqayBlZW4gZWZmZWN0IHZhbiBkZSB0cmFuc3BsYW50YXRpZSBvcCBkZSByZWxhdGlldmUgYWJ1bmRhbnRpZSB2YW4gU3RhcGh5bG9jb2NjdXMuCgotIElzIGRhdCBlZmZlY3QgbnUgZ3Jvb3QgZ2Vub2VnIG9tIHRlIGt1bm5lbiBjb25jbHVkZXJlbiBkYXQgZGUgYmVoYW5kZWxpbmcgd2Vya3Q/CgotLS0KCmBgYHtyIG91dC53aWR0aD0nODAlJyxmaWcuYXNwPS44LCBmaWcuYWxpZ249J2NlbnRlcicsZWNobz1GQUxTRX0KaWYgKCJwaSIlaW4lbHMoKSkgcm0oInBpIikKa29wdm9ldGVyPC1mdW5jdGlvbih4LHksYW5nbGU9MCxsPS4yLGNleC5kb3Q9LjUscGNoPTE5LGNvbD0iYmxhY2siKQp7CmFuZ2xlPWFuZ2xlLzE4MCpwaQpwb2ludHMoeCx5LGNleD1jZXguZG90LHBjaD1wY2gsY29sPWNvbCkKbGluZXMoYyh4LHgrbCpjb3MoLXBpLzIrYW5nbGUpKSxjKHkseStsKnNpbigtcGkvMithbmdsZSkpLGNvbD1jb2wpCmxpbmVzKGMoeCtsLzIqY29zKC1waS8yK2FuZ2xlKSx4K2wvMipjb3MoLXBpLzIrYW5nbGUpK2wvNCpjb3MoYW5nbGUpKSxjKHkrbC8yKnNpbigtcGkvMithbmdsZSkseStsLzIqc2luKC1waS8yK2FuZ2xlKStsLzQqc2luKGFuZ2xlKSksY29sPWNvbCkKbGluZXMoYyh4K2wvMipjb3MoLXBpLzIrYW5nbGUpLHgrbC8yKmNvcygtcGkvMithbmdsZSkrbC80KmNvcyhwaSthbmdsZSkpLGMoeStsLzIqc2luKC1waS8yK2FuZ2xlKSx5K2wvMipzaW4oLXBpLzIrYW5nbGUpK2wvNCpzaW4ocGkrYW5nbGUpKSxjb2w9Y29sKQpsaW5lcyhjKHgrbCpjb3MoLXBpLzIrYW5nbGUpLHgrbCpjb3MoLXBpLzIrYW5nbGUpK2wvMipjb3MoLXBpLzIrcGkvNCthbmdsZSkpLGMoeStsKnNpbigtcGkvMithbmdsZSkseStsKnNpbigtcGkvMithbmdsZSkrbC8yKnNpbigtcGkvMitwaS80K2FuZ2xlKSksY29sPWNvbCkKbGluZXMoYyh4K2wqY29zKC1waS8yK2FuZ2xlKSx4K2wqY29zKC1waS8yK2FuZ2xlKStsLzIqY29zKC1waS8yLXBpLzQrYW5nbGUpKSxjKHkrbCpzaW4oLXBpLzIrYW5nbGUpLHkrbCpzaW4oLXBpLzIrYW5nbGUpK2wvMipzaW4oLXBpLzItcGkvNCthbmdsZSkpLGNvbD1jb2wpCn0KCnBhcihtYXI9YygwLDAsMCwwKSxtYWk9YygwLDAsMCwwKSkKcGxvdCgwLDAseGxhYj0iIix5bGFiPSIiLHhsaW09YygwLDEwKSx5bGltPWMoMCwxMCksY29sPTAseGF4dD0ibm9uZSIseWF4dD0ibm9uZSIsYXhlcz1GQUxTRSkKcmVjdCgwLDYsMTAsMTAsYm9yZGVyPSJyZWQiLGx3ZD0yKQp0ZXh0KC41LDgsInBvcHVsYXRpb24iLHNydD05MCxjb2w9InJlZCIsY2V4PTIpCnN5bWJvbHMgKDMsIDgsIGNpcmNsZXM9MS41LCBjb2w9InJlZCIsYWRkPVRSVUUsZmc9InJlZCIsaW5jaGVzPUZBTFNFLGx3ZD0yKQpzZXQuc2VlZCgzMzApCmdyaWQ9c2VxKDAsMS4zLC4wMSkKCmZvciAoaSBpbiAxOjUwKQp7CglhbmdsZTE9cnVuaWYobj0xLG1pbj0wLG1heD0zNjApCglhbmdsZTI9cnVuaWYobj0xLG1pbj0wLG1heD0zNjApCglyYWRpdXM9c2FtcGxlKGdyaWQscHJvYj1ncmlkXjIqcGkvc3VtKGdyaWReMipwaSksc2l6ZT0xKQoJa29wdm9ldGVyKDMrcmFkaXVzKmNvcyhhbmdsZTEvMTgwKnBpKSw4K3JhZGl1cypzaW4oYW5nbGUxLzE4MCpwaSksYW5nbGU9YW5nbGUyKQp9CnRleHQoNy41LDgsIk1pY3JvYmlvbWUgaW4gcG9wdWxhdGlvbiIsY29sPSJyZWQiLGNleD0xLjIpCgpyZWN0KDAsMCwxMCw0LGJvcmRlcj0iYmx1ZSIsbHdkPTIpCnRleHQoLjUsMiwic2FtcGxlIixzcnQ9OTAsY29sPSJibHVlIixjZXg9MikKc3ltYm9scyAoMywgMiwgY2lyY2xlcz0xLjUsIGNvbD0icmVkIixhZGQ9VFJVRSxmZz0iYmx1ZSIsaW5jaGVzPUZBTFNFLGx3ZD0yKQpmb3IgKGkgaW4gMDoxKQoJZm9yIChqIGluIDA6NCkKewoKCWtvcHZvZXRlcigyLjEraiooMy45LTIuMSkvNCwxLjEraS8yLGNvbD0icHVycGxlIikKfQpmb3IgKGkgaW4gMjozKQoJZm9yIChqIGluIDA6NCkKewoKCWtvcHZvZXRlcigyLjEraiooMy45LTIuMSkvNCwxLjYraS8yLGNvbD0ib3JhbmdlIikKfQp0ZXh0KDcuNSwyLCJNaWNyb2Jpb21lIGluIHNhbXBsZSIsY29sPSJibHVlIixjZXg9MS4yKQoKYXJyb3dzKDMsNS45LDMsNC4xLGNvbD0iYmxhY2siLGx3ZD0zKQp0ZXh0KDEuNSw1LCJFWFAuIERFU0lHTiAoMSkiLGNvbD0iYmxhY2siLGNleD0xLjIpCnRleHQoNy41LC41LCJEQVRBIEVYUExPUkFUSU9OICZcbkRFU0NSSVBUSVZFIFNUQVRJU1RJQ1MgKDIpIixjb2w9ImJsYWNrIixjZXg9MS4yKQphcnJvd3MoNyw0LjEsNyw1LjksY29sPSJibGFjayIsbHdkPTMpCnRleHQoOC41LDUsIkVTVElNQVRJT04gJlxuSU5GRVJFTkNFICgzKSIsY29sPSJibGFjayIsY2V4PTEuMikKYGBgCgotLS0KCi0gSW5kdWN0aWU6IERvb3IgbWlkZGVsIHZhbiBzdGF0aXN0aXNjaGUgYmVzbHVpdHZvcm1pbmcgKGluZmVyZW5jZSkga3VubmVuIHdlIHVpdHNwcmFrZW4gZG9lbiBvdmVyIGRlIHBvcHVsYXRpZSBvcCBiYXNpcyB2YW4gZWVuIHN0ZWVrcHJvZWYuCgotIERlIHByaWpzIGRpZSB3ZSBoaWVydm9vciBiZXRhbGVuIGlzIG9uemVrZXJoZWlkIQoKLSBXZSBrdW5uZW4gb3AgYmFzaXMgdmFuIGVlbiBzdGVla3Byb2VmIG5vb2l0IGFic29sdXV0IHpla2VyIHppam4gdmFuIG9uemUgY29uY2x1c2llcy4KCi0tLQoKLSBNZXQgZGF0YSBrdW5uZW4gd2UgbmlldCBiZXdpanplbiBkYXQgZWVuIGJlaGFuZGVsaW5nIHdlcmt0LgoKLSBGYWxzaWZpY2F0aWUgcHJpbmNpcGUgdmFuIFBvcHBlcjogRGF0YSBrdW5uZW4gZW5rZWwgZWVuIGh5cG90aGVzZSBvZiBlZW4gdGhlb3JpZSBvbnRrcmFjaHRlbi4KCi0gTWV0IHN0YXRpc3RpZWsga3VubmVuIHdlIGR1cyBuaWV0IGFhbnRvbmVuIGRhdCBkZSBiZWhhbmRlbGluZyB3ZXJrdC4KCi0gU3RhdGlzdGllayB6YWwgb25zIHdlbCB0b2VsYXRlbiBvbSBoZXQgb21nZWtlZXJkZSB0ZSBmYWxzaWZpw6tyZW46IGFscyB3ZSB2ZXJvbmRlcnN0ZWxsZW4gZGF0IGVyIGdlZW4gZWZmZWN0IHZhbiBkZSBiZWhhbmRlbGluZywgc3ByZWVrdCBkZSBkYXRhIGluIGRlIHN0ZWVrcHJvZWYgZGl0IHRlZ2VuPwoKLSBNZXQgc3RhdGlzdGllayBrdW5uZW4gd2UgYmVyZWtlbmVuIGhvZSB3YWFyc2NoaWpubGlqayBoZXQgaXMgb20gaW4gZWVuIHJhbmRvbSBzdGVla3Byb2VmICh3YW5uZWVyIHdlIGhldCBleHBlcmltZW50IGR1cyBvcG5pZXV3IHVpdCB6b3VkZW4gdm9lcmVuKSBlZW4gZ2VtaWRkZWxkIHZlcnNjaGlsIGluIHJlbGF0aWV2ZSBhYnVuZGFudGllIHRlIHppZW4gdHVzc2VuIHBsYWNlYm8gZW4gdHJhbnNwbGFudGF0aWVncm9lcCBkYXQgbWluc3RlbnMgem8gZ3Jvb3QgaXMgYWxzIGluIG9uemUgc3RlZWtwcm9lZiBhbHMgZGUgYmVoYW5kZWxpbmcgZ2VlbiBlZmZlY3Qgem91IGhlYmJlbi4KCi0gRGllIGthbnMgd29yZHQgZWVuIHAtd2FhcmRlIGdlbm9lbWQuCgotIEFscyBwIGhlZWwga2xlaW4gaXMsIGRhbiBpcyBoZXQgaGVlbCBvbndhYXJzY2hpam5saWprIG9tIGVlbiBkZXJnZWxpamsgZWZmZWN0IHRlIG9ic2VydmVyZW4gaW4gZWVuIHN0ZWVrcHJvZWYgZG9vciB0b2V2YWwuCgotIHAgd29yZHQgbWVlc3RhbCB2ZXJnZWxla2VuIG1ldCA1JS4gQWxzIGVyIGdlZW4gZWZmZWN0IGlzIHZhbiBkZSBiZWhhbmRlbGluZyBkYW4gdG9sZXJlcmVuIDUlIHZhbHMgcG9zaXRpZXZlIGNvbmNsdXNpZXMuCgotIE9tIGRlIGthbnMgcCB0ZSBiZXJla2VuZW4gaXMgaGV0IG5vZGlnIG9tIGRlIGRhdGEgdGUgbW9kZWxsZXJlbiBtZXQgc3RhdGlzdGlzY2hlIG1vZGVsbGVuLgoKLS0tCgpJbiBsYXRlcmUgaG9vZmRzdHVra2VuIHp1bGxlbiB3ZSB6aWVuIGRhdCB3ZSB0LXRlc3Qga3VubmVuIGdlYnJ1aWtlbiBvbSBoZXRnZWVuIHdlIG9ic2VydmVyZW4gaW4gZGUgbWljcm9iaW9tZSBkYXRhc2V0IHRlIHZlcmFsZ2VtZW5lbiBuYWFyIGRlIHBvcHVsYXRpZS4KCmBgYHtyfQp0LnRlc3QocmVsfnRydCxkYXRhPWFwKQpgYGAKCkNvbmNsdXNpZToKR2VtaWRkZWxkIGlzIGRlIHJlbGF0aWV2ZSBhYnVuZGFudGllIHZhbiBTdGFwaHlsb2NvY2N1cyBpbiBoZXQgbWljcm9iaW9tZSB2YW4gcGVyc29uZW4gbWV0IGVlbiB6d2VldGdldXIgYHIgZm9ybWF0KGFwUmVsU3VtJG1lYW5bMl0tYXBSZWxTdW0kbWVhblsxXSxkaWdpdHM9MylgJSBob2dlciBuYSBkZSB0cmFuc3BsYW50aWUgZGFuIG5hIGRlIHBsYWNlYm8gYmVoYW5kZWxpbmcuCgotLS0KCiMjIFJhbmRvbWlzYXRpZQoKLSBXYXQgd29yZHQgemlqbiBkZSBjb25zZXF1ZW50aWVzIHZhbiBoZXQgZ2VicnVpayB2YW4gZWVuIHN0ZWVrcHJvZWYgZW4gdmFuIHJhbmRvbWlzYXRpZT8KCi0gUmFuZG9taXNhdGllIGlzIHN0ZXJrIGdlcmVsYXRlZXJkIG1ldCBoZXQgY29uY2VwdCB2YW4gZGUgcG9wdWxhdGllIGVuIHNjb3BlIHZhbiBkZSBzdHVkaWUuICAKCi0gRGUgc2NvcGUgdmFuIGRlIHN0dWRpZSBtb2V0IGdvZWQgd29yZGVuIG9tc2NocmV2ZW4gdm9vciBkZSBzdGFydCB2YW4gaGV0IGV4cGVyaW1lbnQuCgotIE9tZGF0IGRlIHN0YXRpc3Rpc2NoZSBhbmFseXNlIHZhbGlkZSB6b3UgemlqbiBpcyBoZXQgbm9vZHpha2VsaWprIGRhdCBkZSBzdWJqZWN0ZW4gdm9sbGVkaWcgcmFuZG9tIHdvcmRlbiBnZXRyb2trZW4gdWl0IGRlIHBvcHVsYXRpZSBuYWFyIHdhYXIgd2Ugb256ZSBjb25jbHVzaWVzIHdlbnNlbiB0ZSB2ZXJhbGdlbWVuZW4uCgotIFZvbGxlZGlnIHJhbmRvbSB0cmVra2VuIHZhbiBkZSBwb3B1bGF0aWUgaW1wbGljZWVydCBkYXQ6CgogICAgLSBhbGxlIHN1YmplY3RlbiB2YW4gZGUgcG9wdWxhdGllIGV2ZW52ZWVsIGthbnMgaGViYmVuIG9tIGluIGRlIHN0ZWVrcHJvZWYgdGUgd29yZGVuIG9wZ2Vub21lbgogICAgLSBkZSBzZWxlY3RpZSB2YW4gZWVuIHN1YmplY3Qgb25hZmhhbmtlbGlqayBpcyB2YW4gZGUgYW5kZXJlIHN1YmplY3RlbiBpbiBkZSBzdGVla3Byb2VmLgoKCi0gRGUgc3RlZWtwcm9lZiBpcyBkYW4gcmVwcmVzZW50YXRpZWYgdm9vciBkZSBwb3B1bGF0aWUsIG1hYXIgaXMgbm9nIHN0ZWVkcyByYW5kb20uCgotIFdhdCBiZXRla2VudCBkaXQ/CgotLS0KCiMgQ2FzZSBzdHVkeTogTGVuZ3RlIHZhbiBtYW5uZW4gZW4gdnJvdXdlbiBcLSBWYXJpYWJpbGl0ZWl0IHZhbiBzdGVla3Byb2VmIHRvdCBzdGVla3Byb2VmCgotIE9tIHRlIGJlZ3JpanBlbiBkYXQgZWVuIHN0ZWVrcHJvZWYgcmFuZG9tIGlzIHpvdWRlbiB3ZSBoZXR6ZWxmZGUgZXhwZXJpbWVudCB2ZWVsIGtlZXIgbW9ldGVuIGt1bm5lbiBoZXJoYWxlbiAoYHJlcGVhdGVkIHNhbXBsaW5nYCkuCgotIERhbiB6b3VkZW4gd2UgaW56aWNodCBrdW5uZW4ga3JpamdlbiBob2UgZGUgZ2VnZXZlbnMgdmVyYW5kZXJlbiB2YW4gc3RlZWtwcm9lZiB0b3Qgc3RlZWtwcm9lZi4KCi0gT20gZGl0IHRlIGlsbHVzdHJlcmVuIHp1bGxlbiB3ZSBnZWJydWlrIG1ha2VuIHZhbiBlZW4gaGVsZSBncm90ZSBzdHVkaWUuCgotIFVpdCBkaWUgc3R1ZGllIHp1bGxlbiB3ZSBkYW4gaGVyaGFhbGRlbGlqayBrbGVpbmUgc3RlZWtwcm9ldmVuIHRyZWtrZW4gb20gdGUgYmVncmlqcGVuIGhvZSBkZSBnZWdldmVucyBlbiBzdGF0aXN0aWVrZW4gdmVyYW5kZXJlbiB2YW4gc3RlZWtwcm9lZiB0b3Qgc3RlZWtwcm9lZi4gT2Ygb20gbWV0IGFuZGVyZSB3b29yZGVuIG5hIHRlIGdhYW4gd2F0IGRlIHZhcmlhYmlsaXRlaXQgaXMgdHVzc2VuIHN0ZWVrcHJvZXZlbi4KCi0tLQoKTmF0aW9uYWwgSGVhbHRoIEFuZCBOdXRyaXRpb24gRXhhbWluYXRpb24gU3R1ZHkgKE5IQU5FUykKCiAgLSBTaW5kcyAxOTYwIHdvcmRlbiBlbGsgamFhciBtZW5zZW4gdmFuIGFsbGUgbGVlZnRpamRlbiBnZcOvbnRlcnZpZXdkIGJpaiBoZW4gdGh1aXMuCiAgLSBFciBtYWFrdCBvb2sgZWVuIGdlem9uZGhlaWRzb25kZXJ6b2VrIGRlZWwgdWl0IHZhbiBkZSBzdHVkeSBkaWUgaW4gZWVuIG1vYmllbCBvbmRlcnpvZWtzY2VudHJ1bSB3b3JkdCBhZmdlbm9tZW4uCiAgLSBXZSB6dWxsZW4gZGV6ZSBncm90ZSBzdHVkaWUgZ2VicnVpa2VuIG9tIGF0IHJhbmRvbSBwZXJzb25lbiB0ZSBzZWxlY3RlcmVuIHZhbiBkZSBBbWVyaWthYW5zZSBwb3B1bGF0aWUuCiAgLSBEYXQgemFsIGluemljaHQgZ2V2ZW4gaW4gaG9lIGRlIGdlZ2V2ZW5zIGVuIHJlc3VsdGF0ZW4gdmFuIGVlbiBhbmFseXNlIHp1bGxlbiB2YXJpw6tyZW4gdmFuIHN0ZWVrcHJvZWYgdG90IHN0ZWVrcHJvZWYuCiAgLSBEZSBkYXRhIHZhbiBkZXplIHN0dWRpZSBpcyB0ZXJ1ZyB0ZSB2aW5kZW4gaW4gaGV0IFIgcGFra2V0IGBOSEFORVNgCgotLS0KCmBgYHtyfQpsaWJyYXJ5KE5IQU5FUykKaGVhZChOSEFORVMpCmdsaW1wc2UoTkhBTkVTKQpgYGAKCi0tLQoKIyMgRGF0YSBleHBsb3JhdGllCgoKCk9uZGVyem9la3N2cmFhZzogaG9lIHZlcnNjaGlsdCBkZSBsZW5ndGUgdmFuIHZvbHdhc3NlbiBtYW5uZW4gZW4gdnJvdXdlbi4KCjEuIFdlIHBpcGVuIGRlIGRhdGFzZXQgbmFhciBkZSBmdW5jdGlvbiBgZmlsdGVyYCBvbSBkZSBkYXRhIHRlIGZpbHRlcmVuIHZvbGdlbnMgbGVlZnRpamQuICAKMi4gV2UgcGxvdHRlbiBkZSBsZW5ndGUgbWV0aW5nZW4uCiAgICAtIFdlIHNlbGVjdGVyZW4gZGUgZGF0YSBkYXRhIG1ldCBoZXQgY29tbWFuZG8gYGdncGxvdChhZXMoeD1sZW5ndGUpKWAKICAgIC0gV2Ugdm9lZ2VuIGVlbiBoaXN0b2dyYW0gdG9lIG1ldCBoZXQgY29tbWFuZG8gYGdlb21faGlzdG9ncmFtKClgCiAgICAtIFdlIG1ha2VuIHR3ZWUgdmVydGlrYWxlIHBhbmVscyBtZXQgaGV0IGNvbW1hbmRvIGBmYWNldF9ncmlkKEdlbmRlcn4uKWAKICAgIC0gV2UgdmVyYW5kZXJlbiBoZXQgbGFiZWwgdmFuIGRlIHgtYXMgbWV0IGRlIGB4bGFiYCBmdW5jdGllLgoKYGBge3J9Ck5IQU5FUyU+JSAgCiAgZmlsdGVyKEFnZSA+PSAxOCAmICFpcy5uYShIZWlnaHQpKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBIZWlnaHQpKSsKICBnZW9tX2hpc3RvZ3JhbSgpICsKICBmYWNldF9ncmlkKEdlbmRlciB+IC4pICsKICB4bGFiKCJMZW5ndGUgKGNtKSIpCmBgYAoKLS0tCgpXZSB6aWVuIGRhdCBkZSBkYXRhIG51IG1pbiBvZiBtZWVyIHN5bW1ldHJpc2NoIHZlcmRlZWxkIHppam4gZW4gZWVuIGtsb2t2b3JtIGhlYmJlbi4gIApEYXQgemFsIG9ucyB0b2UgbGF0ZW4gb20gZGUgZGF0YSB2ZXJkZXIgc2FtZW4gdGUgdmF0dGVuIGRvb3IgZ2VicnVpayB0ZSBtYWtlbiB2YW4gdHdlZSBzdGF0aXN0aWVrZW46IGhldCBnZW1pZGRlbGRlIGVuIGRlIHN0YW5kYWFyZCBkZXZpYXRpZSB3YXQgZWVuIG1hYXQgaXMgdm9vciBkZSBzcHJlaWRpbmcgdmFuIGRlIGdlZ2V2ZW5zIHJvbmQgaGV0IGdlbWlkZGVsZGUuCgotLS0KCldlIG1ha2VuIG51IGVlbiBzdWJzZXQgdmFuIGRlIGRhdGEgZGllIHdlIHp1bGxlbiBnZWJydWlrZW4gb20gYWFuIHRlIHRvbmVuIGhvZSBkZSB2YXJpYWJpbGl0ZWl0IGluIGtsZWluZSBzdGVla3Byb2V2ZW4ga2FuIHZhcmnDq3JlbiB2YW4gc3RlZWtwcm9lZiB0b3Qgc3RlZWtwcm9lZi4KCiAgMS4gV2UgZmlsdGVyZW4gb3AgbGVlZnRpamQgZW4gdmVyd2lqZGVyZW4gb250YnJla2VuZGVuIGdlZ2V2ZW5zIChOQSwgTm90IEF2YWlsYWJsZSkuCiAgMi4gV2Ugc2VsZWN0ZXJlbiBlbmtlbCBoZXQgZ2VzbGFjaHQgZW4gTGVuZ3RlIHpvZGF0IGRlIGRhdGFzZXQgZ2VlbiBvbm5vZGlnZSB2YXJpYWJlbGVuIGJldmF0LgoKYGBge3J9Cm5oYW5lc1N1YiA8LSBOSEFORVMgJT4lCiAgZmlsdGVyKEFnZSA+PSAxOCAmICFpcy5uYShIZWlnaHQpKSAlPiUKICBzZWxlY3QoYygiR2VuZGVyIiwiSGVpZ2h0IikpCmBgYAoKLS0tCgpXZSBiZXJla2VuZW4gaGV0IGdlbWlkZGVsZGUgZW4gZGUgc3RhbmRhYXJkIGRldmlhdGllIHZvb3IgZGUgbGVuZ3RlIHZvb3IgbWFubmVuIGVuIHZyb3V3ZW4gaW4gZGUgZ3JvdGUgZGF0YXNldC4KV2UgZ3JvZXBlcmVuIGRlIGRhdGEgaGllcnZvb3Igb3AgYmFzaXMgdmFuIGhldCBnZXNsYWNodCAodmFyaWFibGUgR2VuZGVyKS4KCgpgYGB7cn0KCkhlaWdodFN1bSA8LSBuaGFuZXNTdWIgJT4lCiAgZ3JvdXBfYnkoR2VuZGVyKSAlPiUKICBzdW1tYXJpemVfYXQoIkhlaWdodCIsCiAgICAgICAgICAgICAgIGxpc3QobWVhbiA9IG1lYW4sCiAgICAgICAgICAgICAgIHNkID0gc2QpCiAgICAgICAgICAgICAgKQoKa25pdHI6OmthYmxlKAogIEhlaWdodFN1bSAlPiUKICBtdXRhdGVfaWYoaXMubnVtZXJpYywgcm91bmQsIGRpZ2l0cz0xKQogICkKYGBgCgotLS0KCiMjIEV4cGVyaW1lbnQKCi0gU3RlbCBkYXQgd2UgZ2VlbiB0b2VnYW5nIGhlYmJlbiB0b3QgZGUgbWV0aW5nZW4gdmFuIGRlIE5IQU5FUyBzdHVkaWUuCgotIFdlIHpvdWRlbiBkYW4gZWVuIGV4cGVyaW1lbnQgb3AgbW9ldGVuIHpldHRlbiBvbSBtZXRpbmdlbiBiaWogbWFubmVuIGVuIHZyb3V3ZW4gdGUgZG9lbi4KCi0gVmVyb25kZXJzdGVsIGRhdCB3ZSBidWRnZXQgaGViYmVuIG9tIG1ldGluZ2VuIGJpaiA1IG1hbm5lbiBlbiA1IHZyb3V3ZW4gdGUgZG9lbi4KCi0gV2Ugem91ZGVuIGRhbiA1IG1hbm5lbiBlbiA1IHZyb3V3ZW4gYm92ZW4gZGUgMTggamFhciBhdCByYW5kb20gc2VsZWN0ZXJlbiB1aXQgZGUgQW1lcmlrYWFuc2UgcG9wdWxhdGllLgoKLSBXZSBrdW5uZW4gZGl0IGV4cGVyaW1lbnQgc2ltdWxlcmVuIGRvb3IgNSB2cm91d2VuIGVuIDUgbWFubmVuIGF0IHJhbmRvbSB0ZSBzZWxlY3RlcmVuIHVpdCBkZSBOSEFORVMgc3R1ZGllLgoKLS0tCgpgYGB7cn0Kc2V0LnNlZWQoMTAyMykKblNhbXAgPC0gNQpmZW0gPC0gbmhhbmVzU3ViICU+JQogIGZpbHRlcihHZW5kZXI9PSJmZW1hbGUiKSAlPiUKICBzYW1wbGVfbihzaXplPTUpCgptYWwgPC0gbmhhbmVzU3ViICU+JQogIGZpbHRlcihHZW5kZXI9PSJtYWxlIikgJT4lCiAgc2FtcGxlX24oc2l6ZT01KQoKc2FtcDEgPC0gcmJpbmQoZmVtLG1hbCkKCnNhbXAxCmBgYAoKLS0tCgpEYXRhIEV4cGxvcmF0aWUKCmBgYHtyfQpzYW1wMSAlPiUKICBnZ3Bsb3QoYWVzKHg9SGVpZ2h0KSkgKwogIGdlb21faGlzdG9ncmFtKCkgKwogIGZhY2V0X2dyaWQoR2VuZGVyfi4pICsKICB4bGFiKCJMZW5ndGUgKGNtKSIpCgpIZWlnaHRTdW1FeHAxIDwtIHNhbXAxICU+JQogIGdyb3VwX2J5KEdlbmRlcikgJT4lCiAgc3VtbWFyaXplX2F0KCJIZWlnaHQiLAogICAgICAgICAgICAgICBsaXN0KG1lYW4gPSBtZWFuLAogICAgICAgICAgICAgICAgICAgICAgc2QgPSBzZCkKICAgICAgICAgICAgICAgICAgKQpIZWlnaHRTdW1FeHAxCmBgYAoKSGlzdG9ncmFtIGlzIG5pZXQgemludm9sIGFscyB3ZSBtYWFyIHpvIHdlaW5pZyBkYXRhcHVudGVuIGhlYmJlbi4KCi0tLQoKCkJveHBsb3QgaXMgYmV0ZXI6CgpgYGB7ciBlY2hvPUZBTFNFfQpzYW1wMSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBHZW5kZXIseSA9IEhlaWdodCkpICsKICBnZW9tX2JveHBsb3Qob3V0bGllci5zaGFwZSA9IE5BKSArCiAgZ2VvbV9wb2ludChwb3NpdGlvbiA9ICJqaXR0ZXIiKSArCiAgZ2VvbV9wb2ludCgKICAgIGFlcyh4ID0gMSwgeSA9IEhlaWdodFN1bUV4cDEkbWVhblsxXSksCiAgICBzaXplID0gMywKICAgIHBjaCA9IDE3LAogICAgY29sb3I9ImRhcmtyZWQiKSArCiAgZ2VvbV9wb2ludCgKICAgIGFlcyh4ID0gMiwgeSA9IEhlaWdodFN1bUV4cDEkbWVhblsyXSksCiAgICBzaXplID0gMywKICAgIHBjaCA9IDE3LAogICAgY29sb3IgPSAiZGFya3JlZCIpICsKICB5bGFiKCJIZWlnaHQgKGNtKSIpCmBgYAoKLS0tCgpXZSB2b2VyZW4gaGllciBvb2sgZWVuIHQtdGVzdCB1aXQuCgpgYGB7cn0KdC50ZXN0KEhlaWdodH5HZW5kZXIsZGF0YT1zYW1wMSkKYGBgCgpJbiBoZXQgZXhwZXJpbWVudCB6aWpuIHZyb3V3ZW4gZ2VtaWRkZWxkIGByIHJvdW5kKGFicyhIZWlnaHRTdW1FeHAxJG1lYW5bMV0tSGVpZ2h0U3VtRXhwMSRtZWFuWzJdKSwyKWAgY20gYHIgaWZlbHNlKEhlaWdodFN1bUV4cDEkbWVhblsxXT5IZWlnaHRTdW1FeHAxJG1lYW5bMl0sImdyb3RlciIsImtsZWluZXIiKWAgZGFuIG1hbm5lbi4gRW4gYWxzIHdlIGVlbiBzdGF0aXN0aXNjaGUgdGVzdCB1aXR2b2VyZW4gKHppZSBob29mZHN0dWsgNTogU3RhdGlzdGlzY2hlIGJlc2x1aXR2b3JtaW5nKSBrdW5uZW4gd2UgYmVzbHVpdGVuIGRhdCBkaXQgdmVyc2NoaWwgc3RhdGlzdGlzY2ggYHIgaWZlbHNlKHQudGVzdChIZWlnaHR+R2VuZGVyLHNhbXAxKSRwLnZhbHVlIDwgMC4wNSwic2lnbmlmaWNhbnQiLCJuaWV0IHNpZ25pZmljYW50IilgIGlzLgoKLS0tCgojIyBIZXJoYWFsIGhldCBleHBlcmltZW50CgpBbHMgd2UgaGV0IGV4cGVyaW1lbnQgaGVyaGFsZW4gc2VsZWN0ZXJlbiB3ZSBhbmRlcmUgbWVuc2VuIGVuIHZlcmtyaWpnZW4gd2UgYW5kZXJlIHJlc3VsdGF0ZW4uCgoKYGBge3J9CnNldC5zZWVkKDEwMjQpCmZlbSA8LSBuaGFuZXNTdWIgJT4lCiAgZmlsdGVyKEdlbmRlcj09ImZlbWFsZSIpICU+JQogIHNhbXBsZV9uKHNpemU9NSkKCm1hbCA8LSBuaGFuZXNTdWIgJT4lCiAgZmlsdGVyKEdlbmRlcj09Im1hbGUiKSAlPiUKICBzYW1wbGVfbihzaXplPTUpCgpzYW1wMiA8LSByYmluZChmZW0sbWFsKQoKSGVpZ2h0U3VtRXhwMiA8LSBzYW1wMiAlPiUKICBncm91cF9ieShHZW5kZXIpICU+JQogIHN1bW1hcml6ZV9hdCgiSGVpZ2h0IiwKICAgICAgICAgICAgICAgbGlzdChtZWFuPW1lYW4sCiAgICAgICAgICAgICAgICAgICAgc2Q9c2QpCiAgICAgICAgICAgICAgKQpIZWlnaHRTdW1FeHAyCgpzYW1wMiAlPiUKICBnZ3Bsb3QoYWVzKHggPSBHZW5kZXIseSA9IEhlaWdodCkpICsKICBnZW9tX2JveHBsb3Qob3V0bGllci5zaGFwZSA9IE5BKSArCiAgZ2VvbV9wb2ludChwb3NpdGlvbiA9ICJqaXR0ZXIiKSArCiAgZ2VvbV9wb2ludCgKICAgIGFlcyh4ID0gMSwgeSA9IEhlaWdodFN1bUV4cDIkbWVhblsxXSksCiAgICBzaXplID0gMywKICAgIHBjaCA9IDE3LAogICAgY29sb3I9ImRhcmtyZWQiKSArCiAgZ2VvbV9wb2ludCgKICAgIGFlcyh4ID0gMiwgeSA9IEhlaWdodFN1bUV4cDIkbWVhblsyXSksCiAgICBzaXplID0gMywKICAgIHBjaCA9IDE3LAogICAgY29sb3IgPSAiZGFya3JlZCIpICsKICB5bGFiKCJIZWlnaHQgKGNtKSIpCgp0LnRlc3QoSGVpZ2h0IH4gR2VuZGVyLCBkYXRhPXNhbXAyKQpgYGAKCgpJbiBkZSBuaWV1d2Ugc3RlZWtwcm9lZiB6aWpuIHZyb3V3ZW4gZ2VtaWRkZWxkIGByIHJvdW5kKGFicyhIZWlnaHRTdW1FeHAyJG1lYW5bMV0tSGVpZ2h0U3VtRXhwMiRtZWFuWzJdKSwyKWAgY20gYHIgaWZlbHNlKEhlaWdodFN1bUV4cDIkbWVhblsxXT5IZWlnaHRTdW1FeHAyJG1lYW5bMl0sImdyb3RlciIsImtsZWluZXIiKWAgZGFuIG1hbm5lbi4gRW4gZGl0IHZlcnNjaGlsIGlzIHN0YXRpc3Rpc2NoIGByIGlmZWxzZSh0LnRlc3QoSGVpZ2h0fkdlbmRlcixzYW1wMix2YXIuZXF1YWw9VFJVRSkkcC52YWx1ZSA8IDAuMDUsInNpZ25pZmljYW50IiwibmlldCBzaWduaWZpY2FudCIpYAoKCi0tLQoKIyMgSGVyaGFhbCBoZXQgZXhwZXJpbWVudCBvcG5pZXV3CgpgYGB7cn0Kc2VlZCA8LSA4ODYwNQpzZXQuc2VlZChzZWVkKQpmZW0gPC0gbmhhbmVzU3ViICU+JQogIGZpbHRlcihHZW5kZXI9PSJmZW1hbGUiKSAlPiUKICBzYW1wbGVfbihzaXplPTUpCgptYWwgPC0gbmhhbmVzU3ViICU+JQogIGZpbHRlcihHZW5kZXI9PSJtYWxlIikgJT4lCiAgc2FtcGxlX24oc2l6ZT01KQoKc2FtcDMgPC0gcmJpbmQoZmVtLG1hbCkKCkhlaWdodFN1bUV4cDMgPC0gc2FtcDMgJT4lCiAgZ3JvdXBfYnkoR2VuZGVyKSAlPiUKICBzdW1tYXJpemVfYXQoIkhlaWdodCIsCiAgICAgICAgICAgICAgIGxpc3QobWVhbj1tZWFuLAogICAgICAgICAgICAgICAgICAgIHNkPXNkKQogICAgICAgICAgICAgICkKSGVpZ2h0U3VtRXhwMwoKc2FtcDMgJT4lCiAgZ2dwbG90KGFlcyh4ID0gR2VuZGVyLHkgPSBIZWlnaHQpKSArCiAgZ2VvbV9ib3hwbG90KG91dGxpZXIuc2hhcGUgPSBOQSkgKwogIGdlb21fcG9pbnQocG9zaXRpb24gPSAiaml0dGVyIikgKwogIGdlb21fcG9pbnQoCiAgICBhZXMoeCA9IDEsIHkgPSBIZWlnaHRTdW1FeHAzJG1lYW5bMV0pLAogICAgc2l6ZSA9IDMsCiAgICBwY2ggPSAxNywKICAgIGNvbG9yPSJkYXJrcmVkIikgKwogIGdlb21fcG9pbnQoCiAgICBhZXMoeCA9IDIsIHkgPSBIZWlnaHRTdW1FeHAzJG1lYW5bMl0pLAogICAgc2l6ZSA9IDMsCiAgICBwY2ggPSAxNywKICAgIGNvbG9yID0gImRhcmtyZWQiKSArCiAgeWxhYigiSGVpZ2h0IChjbSkiKQoKdC50ZXN0KEhlaWdodCB+IEdlbmRlciwgZGF0YT1zYW1wMykKYGBgCgpJbiBkZSBuaWV1d2Ugc3RlZWtwcm9lZiB6aWpuIHZyb3V3ZW4gZ2VtaWRkZWxkIGByIHJvdW5kKGFicyhIZWlnaHRTdW1FeHAzJG1lYW5bMV0tSGVpZ2h0U3VtRXhwMyRtZWFuWzJdKSwyKWAgY20gYHIgaWZlbHNlKEhlaWdodFN1bUV4cDMkbWVhblsxXT5IZWlnaHRTdW1FeHAzJG1lYW5bMl0sImdyb3RlciIsImtsZWluZXIiKWAgZGFuIG1hbm5lbi4gRW4gZGl0IHZlcnNjaGlsIGlzIHN0YXRpc3Rpc2NoIGByIGlmZWxzZSh0LnRlc3QoSGVpZ2h0fkdlbmRlcixzYW1wMyx2YXIuZXF1YWw9VFJVRSkkcC52YWx1ZSA8IDAuMDUsInNpZ25pZmljYW50IiwibmlldCBzaWduaWZpY2FudCIpYAoKLS0tCgojIyBTYW1lbnZhdHRpbmcKCi0gV2UgdHJva2tlbiBhdCByYW5kb20gYW5kZXJlIHByb2VmcGVyc29uZW4gaW4gZWxrZSBzdGVla3Byb2VmCgotIEhpZXJkb29yIHZlcnNjaGlsbGVuIGxlbmd0ZW1ldGluZ2VuIHZhbiBzdGVla3Byb2VmIHRvdCBzdGVla3Byb2VmLgoKLSBEdXMgb29rIGRlIGdlc2NoYXR0ZSBnZW1pZGRlbGRlcyBlbiBzdGFuZGFhcmQgZGV2aWF0aWVzLgoKLSBCaWpnZXZvbGcgemlqbiBvbnplIGNvbmNsdXNpZXMgb29rIG9uemVrZXIgZW4ga3VubmVuIGRlemUgd2lqemlnZW4gdmFuIHN0ZWVrcHJvZWYgdG90IHN0ZWVrcHJvZWYuCgotIFZvb3IgaGV0IGxlbmd0ZSB2b29yYmVlbGQgemlqbiBzdGVla3Byb2V2ZW4gd2FhcmJpaiBoZXQgZWZmZWN0IHRlZ2VuZ2VzdGVsZCBpcyBhYW4gZGF0IGluIGRlIHBvcHVsYXRpZSBlbiB3YWFyYmlqIHdlIGJlc2x1aXRlbiBkYXQgaGV0IHZlcnNjaGlsIHNpZ25pZmljYW50IGVjaHRlciB6ZWxkemFhbS4KCiRccmlnaHRhcnJvdyQgTWV0IHN0YXRpc3RpZWsgY29udHJvbGVyZW4gd2UgZGUga2FucyBvcCBoZXQgdHJla2tlbiBmb3V0ZSBjb25jbHVzaWVzLgoKIyMgQ29udHJvbGUgdmFuIGZvdXRlbgoKSG9lIGNvbnRyb2xlZXJ0IHN0YXRpc3RpZWsgZGUga2FucyBvcCBoZXQgdHJla2tlbiB2YW4gZm91dGUgY29uY2x1c2llcz8KCi0gSW4gb25kZXJzdGFhbmRlIGNvZGUgdHJla2tlbiB3ZSAxMDAwMCBoZXJoYWFsZGUgc3RlZWtwcm9ldmVuIHZhbiA1IHZyb3V3ZW4gZW4gNSBtYW5uZW4gdWl0IGRlIE5IQU5FUyBzdHVkaWUuCgpgYGB7cn0Kc2V0LnNlZWQoMTUxNTIpCiMgQWFudGFsIHNpbXVsYXRpZXMgZW4gc3RlZWtwcm9lZmdyb290dGUgcGVyIGdyb2VwCm5TaW0gPC0gMTAwMDAKblNhbXAgPC0gNQoKIyBXZSBmaWx0ZXJlbiBkZSBkYXRhIHZvb3JhZiB6b2RhdCB3ZSBkaXQgbmlldCB0ZWxrZW5zIG9wbmlldXcgaG9ldmVuIHRlIGRvZW4KZmVtIDwtIG5oYW5lc1N1YiAlPiUKICBmaWx0ZXIoR2VuZGVyID09ICJmZW1hbGUiKQoKbWFsIDwtIG5oYW5lc1N1YiAlPiUKICBmaWx0ZXIoR2VuZGVyID09ICJtYWxlIikKCiMgU2ltdWxhdGllIHN0dWRpZQojIE9tIHNuZWxsZSBmdW5jdGllcyB0ZSBrdW5uZW4gZ2VicnVpa2VuIG5lbWVuIHdlIGVlcnN0IG5TaW0gc3RlZWtwcm9ldmVuIGVuIGJlcmVrZW5lbiB3ZSBkYWFybmEgYWxsZXMuCgpmZW1TYW1wcyA8LSBtYWxTYW1wcyA8LW1hdHJpeChOQSwgbnJvdz1uU2FtcCwgbmNvbD1uU2ltKQpmb3IgKGkgaW4gMTpuU2ltKQp7CiAgZmVtU2FtcHNbLGldIDwtIHNhbXBsZShmZW0kSGVpZ2h0LCBuU2FtcCkKICBtYWxTYW1wc1ssaV0gPC0gc2FtcGxlKG1hbCRIZWlnaHQsIG5TYW1wKQp9CgpyZXMgPC0gZGF0YS5mcmFtZSgKICB2ZXJzY2hpbD1jb2xNZWFucyhmZW1TYW1wcykgLSBjb2xNZWFucyhtYWxTYW1wcyksCiAgUmZhc3Q6OnR0ZXN0cyhmZW1TYW1wcywgbWFsU2FtcHMpCiAgKQoKc3VtKHJlcyRwdmFsdWUgPCAwLjA1ICYgcmVzJHZlcnNjaGlsIDwgMCkKc3VtKHJlcyRwdmFsdWUgPj0gMC4wNSkKc3VtKHJlcyRwdmFsdWUgPCAwLjA1ICYgcmVzJHZlcnNjaGlsPjApCgpyZXMgJT4lCiAgZ2dwbG90KGFlcyh4PXZlcnNjaGlsLHk9LWxvZzEwKHB2YWx1ZSksY29sb3I9cHZhbHVlIDwgMC4wNSkpICsKICBnZW9tX3BvaW50KCkgKwogIHhsYWIoIkdlbWlkZGVsZCBWZXJzY2hpbCAoY20pIikgKwogIHlsYWIoIlN0YXRpc3Rpc2NoZSBTaWduaWZpY2FudGllICgtbG9nMTAgcCkiKQoKcmVzICU+JQogIGdncGxvdChhZXMoeSA9IHZlcnNjaGlsKSkgKwogIGdlb21fYm94cGxvdCgpICsKICB5bGFiKCJHZW1pZGRlbGQgVmVyc2NoaWwgKGNtKSIpCiAgeGxhYigiIikKYGBgCgpPcCBiYXNpcyB2YW4gMTAwMDAgc3RlZWtwcm9ldmVuIHZhbiA1IG1hbm5lbiBlbiA1IHZyb3V3ZW4gemFnZW4gd2UgZGF0IGluIGByIHN1bShyZXMkcHZhbHVlPDAuMDUmcmVzJHZlcnNjaGlsPDApYCBzdGVla3Byb2V2ZW4gdnJvdXdlbiBnZW1pZGRlbGQgc2lnbmlmaWNhbnQga2xlaW5lciB6aWpuIGRhbiBtYW5uZW4uIEluIGByIHN1bShyZXMkcHZhbHVlPj0wLjA1KWAgc3RlZWtwcm9ldmVuIGJlc2x1aXRlbiB3ZSBkYXQgdnJvdXdlbiBlbiBtYW5uZW4gZ2VtaWRkZWxkIG5pZXQgc2lnbmlmaWNhbnQgdmVyc2NoaWxsZW4gaW4gbGVuZ3RlLiBFbiBpbiBgciBzdW0ocmVzJHB2YWx1ZTwwLjA1JnJlcyR2ZXJzY2hpbD4wKWAgYmVzbHVpdGVuIHdlIGRhdCB2cm91d2VuIGdlbWlkZGVsZCBzaWduaWZpY2FudCBncm90ZXIgemlqbiBkYW4gbWFubmVuLgoKLSBEZSBzdGVla3Byb2VmIGRpZSB3ZSB0b29uZGVuIHdhYXJ1aXQgd2Ugem91ZGVuIGJlc2x1aXRlbiBkYXQgdnJvdXdlbiBzaWduaWZpY2FudCBncm90ZXIgemlqbiBkYW4gbWFubmVuIGlzIGhlZWwgb253YWFyc2NoaWpubGlqay4gRXIgbW9lc3RlbiBgciBwYXN0ZShzZWVkKWAgc3RlZWtwcm9ldmVuIHdvcmRlbiBnZXRyb2trZW4gb20gZGV6ZSBleHRyZW1lIHN0ZWVrcHJvZWYgdGUgdmluZGVuLgoKSGV0IGZlaXQgZGF0IHdlIGluIHZlZWwgc3RlZWtwcm9ldmVuIHJlc3VsdGF0ZW4gdmluZGVuIGRpZSBzdGF0aXN0aXNjaCBuaWV0IHNpZ25pZmljYW50IHppam4ga29tdCBvbWRhdCBkZSBzdGF0aXN0aXNjaGUgdG9ldHMgZWVuIHRlIGxhZ2Uga3JhY2h0IGhlZWZ0IG9tIGhldCB2ZXJzY2hpbCB0ZSBkZXRlY3RlcmVuIHdhbm5lZXIgZXIgbWFhciA1IG9ic2VydmF0aWVzIHppam4gcGVyIGdyb2VwLgoKLS0tCgojIyMgR3JvdGVyZSBzdGVla3Byb2VmPwoKV2F0IGdlYmV1cnQgZXIgYWxzIHdlIGRlIHN0ZWVrcHJvZWYgdmVyaG9nZW4gbmFhciA1MCBvYnNlcnZhdGllcyBwZXIgZ3JvZXA/CgoKYGBge3J9CnNldC5zZWVkKDExMTQ1KQojIEFhbnRhbCBzaW11bGF0aWVzIGVuIHN0ZWVrcHJvZWZncm9vdHRlIHBlciBncm9lcApuU2ltIDwtIDEwMDAwCm5TYW1wIDwtIDUwCgojIFdlIGZpbHRlcmVuIGRlIGRhdGEgdm9vcmFmIHpvZGF0IHdlIGRpdCBuaWV0IHRlbGtlbnMgb3BuaWV1dyBob2V2ZW4gdGUgZG9lbgpmZW0gPC0gbmhhbmVzU3ViICU+JQogIGZpbHRlcihHZW5kZXIgPT0gImZlbWFsZSIpCgptYWwgPC0gbmhhbmVzU3ViICU+JQogIGZpbHRlcihHZW5kZXIgPT0gIm1hbGUiKQoKIyBTaW11bGF0aWUgc3R1ZGllCiMgT20gc25lbGxlIGZ1bmN0aWVzIHRlIGt1bm5lbiBnZWJydWlrZW4gbmVtZW4gd2UgZWVyc3QgblNpbSBzdGVla3Byb2V2ZW4gZW4gYmVyZWtlbmVuIHdlIGRhYXJuYSBhbGxlcy4KCmZlbVNhbXBzIDwtIG1hbFNhbXBzIDwtIG1hdHJpeChOQSwgbnJvdyA9IG5TYW1wLCBuY29sID0gblNpbSkKZm9yIChpIGluIDE6blNpbSkKewogIGZlbVNhbXBzWyxpXSA8LSBzYW1wbGUoZmVtJEhlaWdodCwgblNhbXApCiAgbWFsU2FtcHNbLGldIDwtIHNhbXBsZShtYWwkSGVpZ2h0LCBuU2FtcCkKfQoKcmVzIDwtIGRhdGEuZnJhbWUoCiAgdmVyc2NoaWwgPSBjb2xNZWFucyhmZW1TYW1wcykgLSBjb2xNZWFucyhtYWxTYW1wcyksCiAgUmZhc3Q6OnR0ZXN0cyhmZW1TYW1wcywgbWFsU2FtcHMpCiAgKQoKc3VtKHJlcyRwdmFsdWUgPCAwLjA1ICYgcmVzJHZlcnNjaGlsIDwgMCkKc3VtKHJlcyRwdmFsdWUgPj0gMC4wNSkKc3VtKHJlcyRwdmFsdWUgPCAwLjA1ICYgcmVzJHZlcnNjaGlsID4gMCkKCnJlcyAlPiUKICBnZ3Bsb3QoYWVzKHg9dmVyc2NoaWwseT0tbG9nMTAocHZhbHVlKSxjb2xvcj1wdmFsdWU8MC4wNSkpICsKICBnZW9tX3BvaW50KCkgKwogIHhsYWIoIkdlbWlkZGVsZCBWZXJzY2hpbCAoY20pIikgKwogIHlsYWIoIlN0YXRpc3Rpc2NoZSBTaWduaWZpY2FudGllICgtbG9nMTAgcCkiKQoKcmVzICU+JQogIGdncGxvdChhZXMoeT12ZXJzY2hpbCkpICsKICBnZW9tX2JveHBsb3QoKSArCiAgeWxhYigiR2VtaWRkZWxkIFZlcnNjaGlsIChjbSkiKQogIHhsYWIoIiIpCmBgYAoKLSBXZSB6aWVuIGR1cyBkYXQgd2UgZGUga2FucyBvbSBlZW4gdmVyc2NoaWwgdGUgdmluZGVuIGFscyBlciBpbiB3ZXJrZWxpamtoZWlkIGVlbiB2ZXJzY2hpbCBpcyBpbiBkZSBwb3B1bGF0aWUga3VubmVuIGJlw69udmxvZWRlbiBpbiBkZSBkZXNpZ24gZmFzZTogYWFuIGRlIGhhbmQgdmFuIGRlIHN0ZWVrcHJvZWZncm9vdHRlLgoKLSBIb2UgbWVlciBnZWdldmVucyBob2UgbWFra2VsaWprZXIgd2UgaGV0IHdlcmtlbGlqayB2ZXJzY2hpbCBvcHBpa2tlbiBpbiBkZSBzdGVla3Byb2VmLgoKCiMjIyBDb250cm9sZSB2YW4gdmFscyBwb3NpdGlldmVuCgpXYXQgZ2ViZXVydCBlciBhbHMgZXIgZ2VlbiB2ZXJzY2hpbCBpcyB0dXNzZW4gYmVpZGUgZ3JvZXBlbj8KCi0gV2UgbW9ldGVuIGhpZXJ2b29yIGV4cGVyaW1lbnRlbiBzaW11bGVyZW4gd2FhcmJpaiBkZSBncm9lcGVuIGdlbGlqayB6aWpuLiAgCgotIEhpZXJ2b29yIHp1bGxlbiB3ZSB0d2VlIGdyb2VwZW4gdmVyZ2VsaWprZW4gd2FhcnZvb3IgZGUgbGVuZ3RlIGdlbWlkZGVsZCBuaWV0IHZlcnNjaGlsbGVuZCBpcy4KCi0gRGF0IGt1bm5lbiB3ZSBkb2VuIGRvb3IgZWVuIHN0ZWVrcHJvZWYgdGUgdHJla2tlbiB3YWFyYmlqIHdlIHZvb3IgYmVpZGUgZ3JvZXBlbiBhdCByYW5kb20gc3ViamVjdGVuIHRyZWtrZW4gdWl0IGRlIHN1YnNldCB2YW4gdnJvdXdlbiBpbiBkZSBOSEFORVMgc3R1ZGllLgoKLSBXZSBkb2VuIGRpdCBvcG5pZXV3IHZvb3IgZWVuIHN0ZWVrcHJvZWYgbWV0IDUgc3ViamVjdGVuIHBlciBncm9lcAoKCmBgYHtyfQpzZXQuc2VlZCgxMzI0NSkKIyBBYW50YWwgc2ltdWxhdGllcyBlbiBzdGVla3Byb2VmZ3Jvb3R0ZSBwZXIgZ3JvZXAKblNpbSA8LSAxMDAwMApuU2FtcCA8LSA1CgojIFdlIGZpbHRlcmVuIGRlIGRhdGEgdm9vcmFmIHpvZGF0IHdlIGRpdCBuaWV0IHRlbGtlbnMgb3BuaWV1dyBob2V2ZW4gdGUgZG9lbgpmZW0gPC0gbmhhbmVzU3ViICU+JQogIGZpbHRlcihHZW5kZXIgPT0gImZlbWFsZSIpCgojIFNpbXVsYXRpZSBzdHVkaWUKIyBPbSBzbmVsbGUgZnVuY3RpZXMgdGUga3VubmVuIGdlYnJ1aWtlbiBuZW1lbiB3ZSBlZXJzdCBuU2ltIHN0ZWVrcHJvZXZlbiBlbiBiZXJla2VuZW4gd2UgZGFhcm5hIGFsbGVzLgoKZmVtU2FtcHMgPC0gZmVtU2FtcHMyIDwtbWF0cml4KE5BLCBucm93PW5TYW1wLCBuY29sPW5TaW0pCmZvciAoaSBpbiAxOm5TaW0pCnsKICBmZW1TYW1wc1ssaV0gPC0gc2FtcGxlKGZlbSRIZWlnaHQsIG5TYW1wKQogIGZlbVNhbXBzMlssaV0gPC0gc2FtcGxlKGZlbSRIZWlnaHQsIG5TYW1wKQp9CgpyZXMgPC0gZGF0YS5mcmFtZSgKICB2ZXJzY2hpbD1jb2xNZWFucyhmZW1TYW1wcykgLSBjb2xNZWFucyhmZW1TYW1wczIpLAogIFJmYXN0Ojp0dGVzdHMoZmVtU2FtcHMsIGZlbVNhbXBzMikKICApCgpzdW0ocmVzJHB2YWx1ZSA8IDAuMDUgJiByZXMkdmVyc2NoaWwgPCAwKQpzdW0ocmVzJHB2YWx1ZSA+PSAwLjA1KQpzdW0ocmVzJHB2YWx1ZSA8IDAuMDUgJiByZXMkdmVyc2NoaWw+MCkKCnJlcyAlPiUKICBnZ3Bsb3QoYWVzKHg9dmVyc2NoaWwseT0tbG9nMTAocHZhbHVlKSxjb2xvcj1wdmFsdWUgPCAwLjA1KSkgKwogIGdlb21fcG9pbnQoKSArCiAgeGxhYigiR2VtaWRkZWxkIFZlcnNjaGlsIChjbSkiKSArCiAgeWxhYigiU3RhdGlzdGlzY2hlIFNpZ25pZmljYW50aWUgKC1sb2cxMCBwKSIpCgpyZXMgJT4lCiAgZ2dwbG90KGFlcyh5ID0gdmVyc2NoaWwpKSArCiAgZ2VvbV9ib3hwbG90KCkgKwogIHlsYWIoIkdlbWlkZGVsZCBWZXJzY2hpbCAoY20pIikKICB4bGFiKCIiKQpgYGAKCk9wIGJhc2lzIHZhbiAxMDAwMCBzdGVla3Byb2V2ZW4gemllbiB3ZSBkYXQgd2UgaW4gYHIgc3VtKHJlcyRwdmFsdWU8MC4wNSlgIHN0ZWVrcHJvZXZlbiB0ZW4gb25yZWNodGUgYmVzbHVpdGVuIGRhdCBlciBlZW4gdmVyc2NoaWwgaXMgaW4gZ2VtaWRkZWxkZSBsZW5ndGUgdHVzc2VuIHR3ZWUgZ3JvZXBlbiB2cm91d2VuLgoKTWV0IGRlIHN0YXRpc3Rpc2NoZSBhbmFseXNlIGNvbnRyb2xlcmVuIHdlIGR1cyBoZXQgYWFudGFsIHZhbHMgcG9zaXRpZXZlIHJlc3VsdGF0ZW4gY29ycmVjdCBvcCA1JS4KCipXYXQgZ2ViZXVydCBlciBhbHMgd2UgaGV0IGFhbnRhbCBvYnNlcnZhdGllcyB2ZXJob2dlbj8qCgpXZSBzaW11bGVyZW4gb3BuaWV1dyBleHBlcmltZW50ZW4gbWV0IDUwIHN1YmplY3RlbiBwZXIgZ3JvZXAgbWFhciB3ZSB0cmVra2VuIGRlIHN1YmplY3RlbiBvcG5pZXV3IHRlbGtlbnMgdWl0IGRlIHBvcHVsYXRpZSB2YW4gdnJvdXdlbi4KCmBgYHtyfQpzZXQuc2VlZCgxMzQ1KQojIEFhbnRhbCBzaW11bGF0aWVzIGVuIHN0ZWVrcHJvZWZncm9vdHRlIHBlciBncm9lcApuU2ltIDwtIDEwMDAwCm5TYW1wIDwtIDUwCgojIFdlIGZpbHRlcmVuIGRlIGRhdGEgdm9vcmFmIHpvZGF0IHdlIGRpdCBuaWV0IHRlbGtlbnMgb3BuaWV1dyBob2V2ZW4gdGUgZG9lbgpmZW0gPC0gbmhhbmVzU3ViICU+JQogIGZpbHRlcihHZW5kZXIgPT0gImZlbWFsZSIpCgojIFNpbXVsYXRpZSBzdHVkaWUKIyBPbSBzbmVsbGUgZnVuY3RpZXMgdGUga3VubmVuIGdlYnJ1aWtlbiBuZW1lbiB3ZSBlZXJzdCBuU2ltIHN0ZWVrcHJvZXZlbiBlbiBiZXJla2VuZW4gd2UgZGFhcm5hIGFsbGVzLgoKZmVtU2FtcHMgPC0gZmVtU2FtcHMyIDwtbWF0cml4KE5BLCBucm93PW5TYW1wLCBuY29sPW5TaW0pCmZvciAoaSBpbiAxOm5TaW0pCnsKICBmZW1TYW1wc1ssaV0gPC0gc2FtcGxlKGZlbSRIZWlnaHQsIG5TYW1wKQogIGZlbVNhbXBzMlssaV0gPC0gc2FtcGxlKGZlbSRIZWlnaHQsIG5TYW1wKQp9CgpyZXMgPC0gZGF0YS5mcmFtZSgKICB2ZXJzY2hpbD1jb2xNZWFucyhmZW1TYW1wcykgLSBjb2xNZWFucyhmZW1TYW1wczIpLAogIFJmYXN0Ojp0dGVzdHMoZmVtU2FtcHMsIGZlbVNhbXBzMikKICApCgpzdW0ocmVzJHB2YWx1ZSA8IDAuMDUgJiByZXMkdmVyc2NoaWwgPCAwKQpzdW0ocmVzJHB2YWx1ZSA+PSAwLjA1KQpzdW0ocmVzJHB2YWx1ZSA8IDAuMDUgJiByZXMkdmVyc2NoaWw+MCkKCnJlcyAlPiUKICBnZ3Bsb3QoYWVzKHg9dmVyc2NoaWwseT0tbG9nMTAocHZhbHVlKSxjb2xvcj1wdmFsdWUgPCAwLjA1KSkgKwogIGdlb21fcG9pbnQoKSArCiAgeGxhYigiR2VtaWRkZWxkIFZlcnNjaGlsIChjbSkiKSArCiAgeWxhYigiU3RhdGlzdGlzY2hlIFNpZ25pZmljYW50aWUgKC1sb2cxMCBwKSIpCgpyZXMgJT4lCiAgZ2dwbG90KGFlcyh5ID0gdmVyc2NoaWwpKSArCiAgZ2VvbV9ib3hwbG90KCkgKwogIHlsYWIoIkdlbWlkZGVsZCBWZXJzY2hpbCAoY20pIikKICB4bGFiKCIiKQpgYGAKCgpPcCBiYXNpcyB2YW4gMTAwMDAgc3RlZWtwcm9ldmVuIHppZW4gd2UgZGF0IHdlIGluIGByIHN1bShyZXMkcHZhbHVlPDAuMDUpYCBzdGVla3Byb2V2ZW4gdGVuIG9ucmVjaHRlIGJlc2x1aXRlbiBkYXQgZXIgZWVuIHZlcnNjaGlsIGlzIGluIGdlbWlkZGVsZGUgbGVuZ3RlIHR1c3NlbiB0d2VlIGdyb2VwZW4gdnJvdXdlbi4KCk1ldCBkZSBzdGF0aXN0aXNjaGUgYW5hbHlzZSBjb250cm9sZXJlbiB3ZSBkdXMgb29rIGJpaiBoZXQgbmVtZW4gdmFuIGVlbiBncm90ZSBzdGVla3Byb2VmIGhldCBhYW50YWwgdmFscyBwb3NpdGlldmUgcmVzdWx0YXRlbiBjb3JyZWN0IG9wIDUlIChWYWxzIHBvc2l0aWVmOiBPcCBiYXNpcyB2YW4gZGUgc3RlZWtwcm9lZiBiZXNsdWl0ZW4gZGF0IGVyIGdlbWlkZGVsZCBlZW4gdmVyc2NoaWwgaXMgaW4gbGVuZ3RlIHR1c3NlbiBiZWlkZSBncm9lcGVuIHRlcndpamwgZXIgaW4gd2Vya2VsaWpraGVpZCBnZWVuIHZlcnNjaGlsIGlzIGluIGRlIHBvcHVsYXRpZS4pCgojIyMgQ29uY2x1c2llcwoKIC0gRGUgc3RhdGlzdGlzY2hlIGFuYWx5c2UgY29udHJvbGVlcnQgc3RlZWRzIGRlIGthbnMgb3AgaGV0IG5lbWVuIHZhbiBlZW4gdmFscyBwb3NpdGlldmUgY29uY2x1c2llLgoKIC0gRGUgc3RhdGlzdGlzY2hlIGFuYWx5c2lzIGNvbnRyb2xlZXJ0IGRlIGthbnMgb3AgaGV0IG5lbWVuIHZhbiBlZW4gdmFscyBuZWdhdGlldmUgY29uY2x1c2llcyBuaWV0LCBtYWFyIGluIGRlIGRlc2lnbiBmYXNlIGt1bm5lbiB3ZSBkZXplIGthbnMgYmXDr252bG9lZGVuIG9uZGVybWVlciBkLm0udi4gZGUgc3RlZWtwcm9lZmdyb290dGUuCgotLS0KCiNDYXNlIHN0dWR5OiBTYWxrIHZhY2NpbgoKLSBJbiAxOTE2LCBicmFrIGRlIGVlcnN0ZSBncm90ZSBwb2xpbyBlcGlkZW1pZSB1aXQgaW4gZGUgVVNBLgotIEJlZ2luIGRlIGphcmVuIDUwIG9udHdpa2tlbGRlIEpvaG4gU2FsayBlZW4gdmFjY2luIG1ldCBiZWxvdmVuZGUgcmVzdWx0YXRlbiBpbiBoZXQgbGFiLgotIEluIDE5NTQsIGhlZWZ0IGRlIE5hdGlvbmFsIEZvdW5kYXRpb24KZm9yIEluZmFudGlsZSBQYXJhbHlzaXMgKE5GSVApIGVlbiBncm90ZSBzdHVkaWUgb3BnZXpldCBvbSBkZSBlZmZlY3Rpdml0ZWl0IHZhbiBoZXQgU2FsayB2YWNjaW4gbmEgdGUgZ2Fhbi4KLSBWZXJvbmRlcnN0ZWwgZGF0IGRlIE5GSVAgaW4gMTk1NCBlZW4gZ3Jvb3QgYWFudGFsIGtpbmRlcmVuIHpvdSBoZWJiZW4gZ2V2YWNjaW5lZXJkLCB3YXQgem91ZGVuIHplIGRhbiBrdW5uZW4gYmVzbHVpdGVuIGFscyBkZSBwb2xpbyBpbmNpZGVudGllIGluIDE5NTQgbGFnZXIgd2FzIGRhbiBpbiAxOTUzPwoKLS0tCgojIyBORklQIFN0dWR5CiMjIyBEZXNpZ24KCi0gR3JvdGUgc2ltdWx0YW5lIHN0dWRpZSBtZXQgZ2V2YWNjaW5lZXJkZSBraW5kZXJlbiAoY2FzZXMpIGVuIG9uZ2V2YWNjaW5lZXJkZSBraW5kZXJlbiAoY29udHJvbGVzKS4KLSBJbiBzY2hvbGVuIHZhbiBkaXN0cmljdGVuIG1ldCBob2dlIHBvbGlvIGluY2lkZW50aWUuCi0gQ2FzZXM6IGtpbmRlcmVuIHZhbiBkZSB0d2VlZGUgZ3JhYWQgdmFuIGhldCBsYWdlciBvbmRlcndpanMgd2FhcnZhbiBkZSBvdWRlcnMgdG9lc3RlbWRlbiBtZXQgdmFjY2luYXRpZS4KLSBDb250cm9sZXM6IGtpbmRlcmVuIHZhbiBkZSBlZXJzdGUgZW4gZGVyZGUgZ3JhYWQuCgojIyMgRGF0YQpgYGB7cn0KbmZpcCA8LSB0aWJibGUoCiAgZ3JvdXA9YygiY2FzZXMiLCJjb250cm9scyIsIm5vQ29uY2VudCIpLAogIGdyYWRlPWMoImcyIiwiZzFnMyIsImcyIiksCiAgdmFjY2luPWMoInllcyIsIm5vIiwibm8iKSwKICB0b3RhbD1jKDIyMTk5OCw3MjUxNzMsMTIzNjA1KSwKICBwb2xpbz1jKDU0LDM5MSw1NikKICApICU+JQogIG11dGF0ZShub1BvbGlvID0gdG90YWwgLSBwb2xpbykKa25pdHI6OmthYmxlKG5maXApCmBgYAoKVmVyZ2VsaWprIGRlIHBvbGlvIGluY2lkZW50aWU/CgotLS0KCmBgYHtyfQpuZmlwIDwtIG5maXAgJT4lCiAgbXV0YXRlKGluY2lkZW5jZVBNID0gcm91bmQobmZpcCRwb2xpby9uZmlwJHRvdGFsKjFlNiwwKSkKa25pdHI6OmthYmxlKG5maXApCmBgYAoKV2F0IGt1bm5lbiB3ZSBjb25jbHVkZXJlbj8KCi0tLQoKIyMgQ29uZm91bmRpbmcKCgpgYGB7cixlY2hvPUZBTFNFLCBmaWcuYWxpZ24gPSAiY2VudGVyIixvdXQud2lkdGggPSAnNTAlJ30KcGxvdChjKDAsMCwxKSxjKC0yLDIsMCkscGNoPWMoIlMiLCJWIiwiUCIpLHhheHQ9Im5vbmUiLHlheHQ9Im5vbmUiLGF4ZXM9RkFMU0UseGxhYj0iIix5bGFiPSIiLGNleD00LHlsaW09YygtMi4yLDIuMikpCmFycm93cyh4MD0wLjEseDE9LjkseTA9MS44LHkxPTAuMSxsd2Q9NCkKYXJyb3dzKHgwPTAuMSx4MT0uOSx5MD0tMS44LHkxPS0wLjIsbHdkPTQpCmFycm93cyh4MD0wLHgxPTAseTA9LTEuNCx5MT0xLjQsbHdkPTQpCmBgYAoKCi0gV2Ugb2JzZXJ2ZXJlbiBlZW4gbGFnZXJlIHBvbGlvIChQKSBpbmNpZGVudGllIHZvb3Iga2luZGVyZW4gYmlqIHdpZSBkZSBvdWRlcnMgZ2VlbiB0b2VzdGVtbWluZyBnYXZlbiBkYW4gaW4gZGUgY29udHJvbGUgZ3JvZXAuICAKCi0gVG9lc3RlbW1pbmcgdm9vciB2YWNjaW5hdGllIChWKSBpcyBnZWFzc29jaWVlcmQgbWV0IGRlIHNvY2lvLWVjb25vbWlzY2hlIHN0YXR1cyAoUykuCgotIEtpbmRlcmVuIHZhbiBsYWdlcmUgc29jaW8tZWNvbm9taXNjaGUgc3RhdHVzIHppam4gbWVlciByZXNpc3RlbnQgdGVnZW4gZGUgemlla3RlLgoKLSBEZSBncm9lcGVuIHZhbiBjYXNlcyBlbiBjb250cm9sZXMgemlqbiBuaWV0IHZlcmdlbGlqa2JhYXIKICAgIC0gdmVyc2NoaWwgaW4gbGVlZnRpamQKICAgIC0gdmVyc2NoaWwgaW4gc29jaW8tZWNvbm9taXNjaGUgc3RhdHVzIGVuCiAgICAtIHZlcnNjaGlsIGluIHZhdGJhYXJoZWlkIHZvb3IgZGUgemlla3RlLgoKLS0tCgojIyBTYWxrIFN0dWR5CgojIyMgRGVzaWduCkVlbiBuaWV1d2Ugc3R1ZGllIHdlcmQgdWl0Z2V2b2VyZDogZHViYmVsIGJsaW5kZSBnZXJhbmRvbWlzZWVyZGUgc3R1ZGllLgoKICAtIEtpbmRlcmVuIHdvcmRlbiBhdCByYW5kb20gdG9lZ2V3ZXplbiBhYW4gY29udHJvbGUgb2YgY2FzZSBhcm0gdmFuIGhldCBleHBlcmltZW50IG5hZGF0IGRlIG91ZGVycyB0b2VzdGVtZGVuIG1ldCB2YWNjaW5hdGllLgogIC0gQ29udHJvbGU6IHZhY2NpbmF0aWUgbWV0IHBsYWNlYm8KICAtIFRyZWF0bWVudDogdmFjY2luYXRpZSBtZXQgdmFjY2luCiAgLSBEb3VibGUgYmxpbmRpbmc6CiAgICAtIG91ZGVycyBlbiBraW5kZXJlbiB3ZXRlbiBuaWV0IG9mIHplIHdlcmRlbiBnZXZhY2NpbmVlcmQgb2YgbmlldAogICAgLSBtZWRpc2NoZSBzdGFmIGVuIG9uZGVyem9la2VycyB3ZXRlbiBuaWV0IG9mIGhldCBraW5kIGhldCB2YWNjaW4gb2YgZGUgcGxhY2VibyBrcmVlZwoKLS0tCgojIyMgRGF0YQoKYGBge3J9CnNhbGsgPC0gZGF0YS5mcmFtZSgKICBncm91cD1jKCJjYXNlcyIsImNvbnRyb2wiLCJub0NvbmNlbnQiKSwKICB0cmVhdG1lbnQ9YygidmFjY2luZSIsInBsYWNlYm8iLCJub25lIiksCiAgdG90YWw9YygyMDA3NDUsMjAxMjI5LCAzMzg3NzgpLHBvbGlvPWMoNTcsMTQyLDE1NykKICApICU+JQogIG11dGF0ZSgKICAgIG5vUG9saW8gPSB0b3RhbC1wb2xpbywKICAgIGluY2lkZW5jZVBNID0gcm91bmQocG9saW8vdG90YWwqMWU2LDApCiAgICApCmtuaXRyOjprYWJsZShzYWxrKQpgYGAKCi0gV2Ugb2JzZXJ2ZXJlbiBlZW4gdmVlbCBncm90ZXIgZWZmZWN0IG51IGRhdCBjYXNlcyBlbiBjb250cm9sZXMgdmVyZ2VsaWprYmFhciB6aWpuLCBpbmNpZGVudGllIHZhbiByZXNwZWN0aWV2ZWxpamsgYHIgc2FsayRpbmNpZGVuY2VQTVsxXWAgIGFuZCBgciBzYWxrJGluY2lkZW5jZVBNWzJdYCBwZXIgbWlsam9lbi4KCi0gRGUgcG9saW8gaW5jaWRlbnRpZSB2b29yIGtpbmRlcmVuIGRpZSBnZWVuIHRvZXN0ZW1taW5nIGdldmVuIGJsaWpmdCB2ZXJnZWxpamtiYWFyICBgciBuZmlwJGluY2lkZW5jZVBNWzNdYCBhbmQgYHIgc2FsayRpbmNpZGVuY2VQTVszXWAgcGVyIG1pbGpvZW4gcmVzcGVjdGlldmVsaWprIGluIHRoZSBORklQIGFuZCBTYWxrIHN0dWR5LgoKLS0tCgojIFJvbCB2YW4gU3RhdGlzdGllawoKLSBXZSBoZWJiZW4gZ2V6aWVuIGRhdAogICAgLSBoZXQgYmVsYW5ncmlqayBpcyBvbSBkZSBzY29wZSB2YW4gZGUgc3R1ZGllIGdvZWQgdGUgc3BlY2lmacOrcmVuIHZvb3IgZGUgc3RhcnQgdmFuIGhldCBleHBlcmltZW50CiAgICAtIHJhbmRvbWlzYXRpZSBub2RpZyBpcyBvbSBlZW4gcmVwcmVzZW50YXRpZXZlIHN0ZWVrcHJvZWYgdGUgbmVtZW4KICAgIC0gc3RlZWtwcm9lZiBncm9vdHRlIGlzIGhlZWwgYmVsYW5ncmlqawogICAgLSB3ZSBtb2V0ZW4gb25zIGJld3VzdCB6aWpuIHZhbiBDb25mb3VuZGluZwogICAgLSBlZW4gZ29lZGUgY29udHJvbGUgaXMgYmVsYW5ncmlqawoKCiRccmlnaHRhcnJvdyQgR29lZGUgcHJvZWZvcHpldCBpcyBjcnVjaWFhbCEKCi0tLQoKLSBXZSBoZWJiZW4gb29rIGdlb2JzZXJ2ZWVyZCBkYXQgZXIgdmFyaWFiaWxpdGVpdCBpcyBpbiBkZSBwb3B1bGF0aWUKLSBXZSBrdW5uZW4gbWFhciBlZW4gYmVwZXJrdGUgc3RlZWtwcm9lZiBuZW1lbiB1aXQgZGUgcG9wdWxhdGllCgokXHJpZ2h0YXJyb3ckIG9uemVrZXJoZWlkIGluIGRlIHJlc3VsdGF0ZW4KJFxyaWdodGFycm93JCBvbnpla2VyaGVpZCBpbiBkZSBjb25jbHVzaWVzCgoKLS0tCgotIFN0YXRpc3RpZWsgaXMgZGUgd2V0ZW5zY2hhcCB2b29yIGhldAogICAgMS4gdmVyemFtZWxlbiAoZXhwZXJpbWVudGVlbCBkZXNpZ24pLAogICAgMi4gZXhwbG9yZW4gKGRhdGEgZXhwbG9yYXRpb24pIGVuCiAgICAzLiBsZXJlbiB2YW4gZGF0YSB6b2RhdCB3ZSBoZXRnZWVuIHdlIG9ic2VydmVyZW4gaW4gZGUgc3RlZWtwcm9lZiB6b3VkZW4ga3VubmVuIHZlcmFsZ2VtZW5lbiBuYWFyIGRlIHBvcHVsYXRpZSB0ZXJ3aWpsIHdlIGRlIG9uemVrZXJoZWlkIHF1YW50aWZpY2VyZW4sIGNvbnRyb2xlcmVuIGVuIHJhcHBvcnRlcmVuIChzdGF0aXN0aXNjaCBtb2RlbGxlcmVuIGVuIHN0YXRpc3Rpc2NoZSBiZXNsdWl0dm9ybWluZykuCgotIFN0YXRpc3RpZWsgc3BlZWx0IGRhYXJvbSBlZW4gaGVlbCBiZWxhbmdyaWprZSByb2wgaW4gem93YXQgYWxsZSB3ZXRlbnNjaGFwcGVuCgoKIyBbSG9tZV0oaHR0cHM6Ly9zdGF0b21pY3MuZ2l0aHViLmlvL3NiYzIwKSB7LX0K