Úvod do regresie

Práca s údajmi z Japonska za roky 2000-2015

V tejto práci sa budeme zaoberať prvými krokmi v odhade regresnej funkcie. Budeme využívať databázu [Life Expectancy (WHO) Fixed dataset] (https://www.kaggle.com/datasets/lashagoch/life-expectancy-who-updated), ktorá obsahuje ukazovatele na úrovni krajín, ako je priemerná dĺžka života, HDP, školské vzdelávanie a výdavky na zdravotníctvo. Vyberáme krajinu Japonsko.

Využívanie niektorých knižníc

rm(list=ls())
library(lmtest)   #  podpora regresie
library(outliers) # analyza odlahlych hodnot (outliers)
library(gptstudio)
library(kableExtra)
library(knitr)
library(dplyr)
library(broom)
library(corrplot)

Príprava údajov - import z csv súboru

Súbor Life_Expectancy_Data obsahuje databázu determinantov očakávanej dĺžky života. Import údajov urobíme nasledovne:

# import the dataset and create a data.frame udaje
udaje_svet <- read.csv("udaje/Life-Expectancy-Data-Updated.csv",header=TRUE,sep=",",dec=".",check.names = TRUE)
head(udaje_svet)

Databáza obsahuje údaje o 2938 pozorovaniach a 22 premenných. V tejto práci sa budeme zaoberať len časťou z nich, konkrétne tými, ktoré súvisia s dĺžkou dožitia. Na začiatku si vyberieme krajinu, ktorej zdravotný stav chceme analyzovať. V tomto prípade ide o už spomínané Japonsko:

# z databázy udaje_svet si vyberieme len tie pozorovania, ktoré sa týkajú Japonska 
udaje <- subset(udaje_svet, Country == "Japan")

Tabuľka uvedená nižšie nám poskytuje základné popisné štatistiky vybraných kvantitatívnych premenných. Vylúčená je Hepatitída B nakoľko údaj bol konštantný.

# niektoré štatistiky a ich prehľad v tabuľke KableExtra
library(kableExtra)
udaje %>%
  select(Adult_mortality,Alcohol_consumption,Measles,BMI,Polio,Diphtheria,GDP_per_capita,Population_mln,Life_expectancy,Schooling) %>%
  summary() %>%
  kable() %>%
  kable_styling(bootstrap_options = "striped", full_width = FALSE)
Adult_mortality Alcohol_consumption Measles BMI Polio Diphtheria GDP_per_capita Population_mln Life_expectancy Schooling
Min. :53.59 Min. :6.980 Min. :78.00 Min. :22.50 Min. :81.00 Min. :85.00 Min. :31416 Min. :126.8 Min. :81.10 Min. :10.70
1st Qu.:61.20 1st Qu.:7.638 1st Qu.:86.00 1st Qu.:22.57 1st Qu.:95.75 1st Qu.:96.00 1st Qu.:31785 1st Qu.:127.4 1st Qu.:81.88 1st Qu.:11.07
Median :64.70 Median :7.970 Median :88.00 Median :22.60 Median :97.50 Median :97.00 Median :33055 Median :127.7 Median :82.55 Median :11.35
Mean :64.52 Mean :7.932 Mean :88.81 Mean :22.62 Mean :96.00 Mean :96.25 Mean :32972 Mean :127.6 Mean :82.46 Mean :11.47
3rd Qu.:69.23 3rd Qu.:8.402 3rd Qu.:92.25 3rd Qu.:22.70 3rd Qu.:99.00 3rd Qu.:98.00 3rd Qu.:33666 3rd Qu.:127.9 3rd Qu.:82.95 3rd Qu.:11.85
Max. :72.95 Max. :8.650 Max. :97.00 Max. :22.70 Max. :99.00 Max. :99.00 Max. :34961 Max. :128.1 Max. :83.80 Max. :12.50

Vyššie uvedená tabuľka nám poskytuje prehľad o základných štatistických charakteristikách vybraných premenných, ako sú priemerné hodnoty, rozptyl, minimum a maximum. Tieto informácie nám pomáhajú lepšie pochopiť rozdelenie a rozsah hodnôt v našich dátach. Na druhej strane je zaujímavá aj informácia o vzájomných vzťahoch medzi týmito premennými, čo môžeme merať pomocou korelačnej matice.

# grafický prehľad o korelačných vzťahoch vyjadruje nasledovný obrázok

cor_matrix <- cor(udaje %>% select(Adult_mortality,Alcohol_consumption,Measles,BMI,Polio,Diphtheria,GDP_per_capita,Population_mln,Life_expectancy,Schooling), use = "complete.obs")
corrplot(cor_matrix, method = "color", type = "upper", tl.col =
"darkblue", tl.srt = 45, title = "Korelačná matica vybraných premenných", mar = c(0,0,1,0))

Uvedený graf nám poskytuje vizuálny prehľad o korelačných vzťahoch medzi vybranými premennými. Farby a intenzita farieb nám umožňujú rýchlo identifikovať silné pozitívne alebo negatívne korelácie. Upozorňujeme, že korelácia neznamená kauzalitu.

V nasledovnom zobrazení je uvedený graf vývoja očakávanej dĺžky dožitia v Japonsku v rokoch 2000-2015. Vidíme, že očakávaná dĺžka života sa zvyšovala od roku 2000 z 81 na 83 rokov v roku 2015, čo je pozitívny trend.

#  graf vývoja očakávanej dĺžky dožitia v Japonsku v rokoch 2000-2015.
library(ggplot2)
ggplot(udaje, aes(x = Year, y = Life_expectancy)) +
  geom_line() +
  geom_point() +
  labs(title = "Vývoj očakávanej dĺžky dožitia v Japonsku (2000-2015)",
       x = "Rok",
       y = "Očakávaná dĺžka dožitia") +
  theme_minimal()

Na začiatku sa pokúsme o vyrovnanie priebehu tejto premennej v čase pomocou lineárnej regresie, kde nezávislou premennou bude rok a závislou premennou bude očakávaná dĺžka dožitia. Odhadneme koeficienty tejto regresie a posúdime kvalitu vyrovnania pomocou ukazovateľov, ako je R-squared a p-value.

# vyrovnanie priebehu očakávanej dĺžky dožitia v čase
model <- lm(Life_expectancy ~ Year, data = udaje)

library(broom)
library(knitr)
library(kableExtra)

# koeficienty regresie
tidy(model) %>%
  kable(digits = 3, caption = "Odhadnuté koeficienty regresie") %>%
  kable_styling(bootstrap_options = "striped", full_width = FALSE)
Odhadnuté koeficienty regresie
term estimate std.error statistic p.value
(Intercept) -242.582 17.119 -14.170 0
Year 0.162 0.009 18.987 0

# kvalita vyrovnania
glance(model) %>%
  kable(digits = 3, caption = "Ukazovatele kvality vyrovnania") %>%
  kable_styling(bootstrap_options = "striped", full_width = FALSE)
Ukazovatele kvality vyrovnania
r.squared adj.r.squared sigma statistic p.value df logLik AIC BIC deviance df.residual nobs
0.963 0.96 0.157 360.514 0 1 7.965 -9.93 -7.613 0.346 14 16
NA

Výsledky regresie nám ukazujú, že koeficient pre rok je pozitívny a štatisticky významný, čo naznačuje, že očakávaná dĺžka dožitia v Japonsku sa zvyšovala v priebehu rokov 2000-2015. Jej priemerný ročný nárast dosahoval 0,162. Hodnota R-squared hodnota nám hovorí, že model vysvetľuje 96 % variability modelu. Podľa hodnoty p-value môžeme povedať, že model ako celok je štatisticky významný.

# teraz vyššie uvedený obrázok doplníme o regresnú priamku
ggplot(udaje, aes(x = Year, y = Life_expectancy)) +
  geom_line() +
  geom_point() +
  geom_smooth(method = "lm", se = FALSE, color = "green") +
  labs(title = "Vývoj očakávanej dĺžky dožitia v Japonsku (2000-2015) s regresnou priamkou",
       x = "Rok",
       y = "Očakávaná dĺžka dožitia") +
  theme_minimal()

###Vývoj spotreby alkoholu Teraz sa pozrieme, ako sa vyvýja konzumácia alkoholu v čase od roku 2000 do roku 2015 v Japonsku. Nakoľko alkohol je faktorom negatívne vplývajúcim na dĺžku dožitia.

model_alkohol <- lm(Alcohol_consumption ~ Year, data = udaje)
# kvalita regresie
tidy(model_alkohol) %>%
  kable(digits = 3, caption = "Odhadnuté koeficienty regresie pre spotrebu alkoholu") %>%
  kable_styling(bootstrap_options = "striped", full_width = FALSE)
Odhadnuté koeficienty regresie pre spotrebu alkoholu
term estimate std.error statistic p.value
(Intercept) -91.115 53.198 -1.713 0.109
Year 0.049 0.026 1.862 0.084

# a teraz model quality statistics R squared
r2<- summary(model_alkohol)$r.square
adj_r2 <-summary(model_alkohol)$adj.r.square
#printujeme koeficient determinancie a upravený koeficient determinancie
cat ("R-squared:",round (r2,3), "\n")
R-squared: 0.198 
cat ("Adjusted R-squared:",round (adj_r2,3), "\n")
Adjusted R-squared: 0.141 

Výsledky regresie ukazujú, že koeficient pre premennú rok je pozitívny, čo naznačuje mierny rast spotreby alkoholu v Japonsku v období rokov 2000 – 2015. Odhadovaný koeficient 0,049 znamená, že spotreba alkoholu sa v priemere zvyšovala približne o 0,049 jednotky ročne. Hodnota p-value (0,084) však naznačuje, že tento koeficient nie je štatisticky významný na hladine významnosti 5 %, preto nie je možné s dostatočnou istotou potvrdiť existenciu štatisticky významného trendu rastu spotreby alkoholu v sledovanom období.

#Obrázok o skutočných vyrovnaných hodnotách spotreby alkoholu

fitted_vals <- fitted(model_alkohol)
# vykreslenie skutočných a vyrovnaných hodnôt - Alcohol_consumption a fitted_values
ggplot(udaje, aes(x = Year)) +
  geom_line(aes(y = Alcohol_consumption), color = "darkblue", size = 1) +
  geom_line(aes(y = fitted_vals), color = "orange", size = 1, linetype = "dashed") +
  labs(title = "Skutočné vs. Vyrovnané hodnoty spotreby alkoholu v Japonsku (2000-2015)",
       x = "Rok",
       y = "Spotreba alkoholu") +
  theme_minimal() +
  scale_y_continuous(limits = c(0, max(udaje$Alcohol_consumption, fitted_vals) * 1.1)) +
  theme(legend.position = "none")

Diagnostické grafy

Residuals vs Fitted

Graf Residuals vs Fitted slúži na posúdenie linearity modelu a približnej konštantnosti rozptylu rezíduí. Reziduály by mali byť rozložené náhodne okolo nulovej hodnoty bez výrazného systematického vzoru. Ak sa objaví vizuálne významné zakrivenie červenej vyhladzovacej čiary,1 ktorá slúži na vizuálnu identifikáciu systematických odchýlok od náhodného rozloženia rezíduí, signalizuje to určité systematické problémy. Ak je LOESS približne horizontálna, model je špecifikovaný vhodne; ak sa zakrivuje, môže to naznačovať nelinearitu, chybnú špecifikáciu (teda výber vysvetľujúcich premenných) alebo iný problém v modeli. Ak sa body rozširujú alebo zužujú v tvare lievika, môže ísť o heteroskedasticitu.

plot(model, which = 1)

Reziduá sú rozložené približne okolo nulovej hodnoty, avšak pri najmenších aj najväčších odhadnutých hodnotách model systematicky nadhodnocuje, resp. podhodnocuje skutočné hodnoty. Do určitej miery to môže byť ovplyvnené odľahlými pozorovaniami, najmä pozorovaním č. 1411 a 530. Počet pozorovaní je však relatívne malý, preto túto skutočnosť zatiaľ nepovažujeme za zásadný problém a podrobnejšie sa k nej môžeme vrátiť pri analýze ďalších diagnostických grafov.

Q-Q plot

Q-Q graf porovnáva rozdelenie štandardizovaných rezíduí s teoretickým normálnym rozdelením. Ak body ležia približne na priamke, predpoklad normality rezíduí je približne splnený. Výraznejšie odchýlky na krajoch naznačujú možné problémy s extrémnymi hodnotami alebo s ťažšími koncami rozdelenia. Určitou pomôckou tu môže byť nasledovná tabuľka:

Interpretácia Q–Q grafu
Prípad Tvar.Q.Q.grafu Ľavý.chvost Pravý.chvost Interpretácia
Normálne rozdelenie Priamka Na priamke Na priamke Dáta majú normálne rozdelenie
Ľavostranná šikmosť (negatívna) Prehnutý nadol (∩ tvar) Nad priamkou Pod priamkou Dlhý ľavý chvost (extrémne nízke hodnoty)
Pravostranná šikmosť (pozitívna) Prehnutý nahor (∪ tvar) Pod priamkou Nad priamkou Dlhý pravý chvost (extrémne vysoké hodnoty)
Symetrické, vysoká špicatosť (> 3) S-tvar Pod priamkou Nad priamkou Ťažké chvosty (viac extrémnych hodnôt)
Symetrické, nízka špicatosť (< 3) Obrátený S-tvar Nad priamkou Pod priamkou Ľahké chvosty (menej extrémnych hodnôt)

Niekedy hovoríme o pomôcke:

  • Priamka → normálne rozdelenie
  • ∪ → pravostranná šikmosť
  • ∩ → ľavostranná šikmosť
  • S → vysoká špicatosť (ťažké chvosty)
  • obrátené S → nízka špicatosť
plot(model, which = 2)

Upravený popis podľa grafu:


Q-Q graf porovnáva empirické rozdelenie štandardizovaných rezíduí s teoretickým normálnym rozdelením. V prípade splnenia predpokladu normality by mali body ležať približne na diagonálnej priamke.

V našom prípade väčšina bodov v strednej časti grafu leží pomerne blízko priamky, čo naznačuje, že pre väčšinu pozorovaní je predpoklad normality približne splnený. Centrálna časť rozdelenia rezíduí sa teda správa podobne ako normálne rozdelenie.

Na ľavom konci grafu dochádza k výraznejšiemu odchýleniu bodov pod referenčnú priamku. Najmä pozorovanie č. 530 predstavuje extrémne záporné reziduum, čo naznačuje ťažší ľavý chvost rozdelenia oproti normálnemu rozdeleniu. Menšia odchýlka je viditeľná aj pri pozorovaní č. 566.

Na pravom konci grafu sú body relatívne blízko referenčnej priamky. Pozorovanie č. 1411 sa nachádza mierne pod priamkou, čo poukazuje len na malú odchýlku od normality a nepredstavuje výrazný problém.

Celkovo možno konštatovať, že normalita rezíduí je približne splnená, avšak s miernymi odchýlkami v chvostoch rozdelenia, najmä v ľavom chvoste spôsobenými odľahlými pozorovaniami. Z praktického hľadiska ide o mierne porušenie predpokladu normality, ktoré však vzhľadom na dobré správanie väčšiny rezíduí nemusí predstavovať zásadný problém pre ďalšiu analýzu.

Scale-Location plot

Scale-Location graf sa používa na posúdenie homoskedasticity, teda konštantnosti rozptylu rezíduí. Ak sú body rozložené približne rovnomerne a červená čiara je relatívne vodorovná, ide o priaznivý výsledok. Systematický rast alebo pokles naznačuje, že rozptyl rezíduí sa mení s úrovňou predikovaných hodnôt.

plot(model, which = 3)

Tu je upravený popis presnejšie podľa grafu:

Body sú rozptýlené pomerne rovnomerne v celom rozsahu vyrovnaných hodnôt, bez výrazného systematického vzoru. Červená vyhladzovacia krivka mierne rastie pri nižších hodnotách, následne sa stabilizuje a ku koncu len veľmi mierne kolíše, bez výrazného rastúceho trendu pri vyšších hodnotách.

Niektoré body (napr. pozorovania označené 530, 566 a 1411) sa od ostatných mierne odchyľujú, môžu teda predstavovať potenciálne odľahlé alebo vplyvné pozorovania, avšak ich vplyv nie je extrémny.

Nevzniká typický „lievikovitý“ tvar, ktorý by naznačoval výrazné porušenie predpokladu konštantného rozptylu. Variabilita rezíduí sa javí ako relatívne stabilná naprieč hodnotami, čo naznačuje, že predpoklad homoskedasticity je splnený, prípadne len veľmi mierne narušený.

Residuals vs Leverage

Graf Residuals vs Leverage pomáha identifikovať vplyvné pozorovania. Leverage to predstavuje vzialenosť daného pozorovania všetkých vysvetľujúcich premenných (teda vektora) od ostatných, resp. od stredného vektora všetkych pozorovaní. Títo vzdialenosť je normovaná na interval (0,1) a väčšina pozorovaní má veľmi malý leverage. Ak sa vyskytujú pozorovania s vysokým leverage, identifikujeme ich na vodorovnej osi a môžu znamenať potenciálne nebezpečenstvo v skreslení parametrov vyrovnávajúcej nadroviny (teda odhadovaných \(\beta\) koeficientov). Pozorovania s vysokou hodnotou leverage a súčasne veľkými rezíduami môžu môžu spôsobovať tento problém. Ak sa niektoré body nachádzajú blízko alebo za krivkami Cookovej vzdialenosti, je vhodné ich podrobnejšie preskúmať.

plot(model, which = 5)

Tu je upravený popis podľa zobrazeného grafu:

V našom prípade má väčšina pozorovaní nízke až stredné hodnoty leverage a je rozptýlená najmä v intervale približne od 0.05 do 0.20, čo naznačuje, že žiadne pozorovanie nemá extrémne vysokú pákovú hodnotu. Dáta teda nepôsobia výrazne nevyvážene z hľadiska vysvetľujúcich premenných.

Z hľadiska rezíduí väčšina bodov nevykazuje extrémne hodnoty, avšak niektoré pozorovania (najmä 530) majú výraznejšie záporné rezíduum. Okrem toho body ako 1197 a 566 majú vyššie leverage, čo znamená, že môžu mať väčší vplyv na odhad modelu.

Kontúry Cookovej vzdialenosti ukazujú mieru vplyvu jednotlivých pozorovaní. Žiadny bod zjavne neprekračuje hranicu hodnoty 1, avšak pozorovanie 530 sa nachádza v oblasti vyšších hodnôt Cookovej vzdialenosti (medzi 0.5 a 1), čo naznačuje, že môže byť potenciálne vplyvné a zaslúži si bližšie preskúmanie.

Celkovo možno konštatovať, že model neobsahuje extrémne vplyvné pozorovania, ktoré by zásadne narúšali jeho stabilitu, avšak existujú jednotlivé body (najmä 530, prípadne 1197 a 566), ktoré môžu mať zvýšený vplyv na výsledky a je vhodné im venovať pozornosť.


  1. LOESS (LOcal regrESSion) krivka predstavuje lokálne vyhladený trend medzi premennými bez predpokladu konkrétneho funkčného tvaru.↩︎

LS0tCnRpdGxlOiAiUHLDoWNhIHMgcmVncmVzaW91IgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKYXV0aG9yOiBOYXTDoWxpYSBLdW5vdsOhCi0tLQojIyMgw5p2b2QgZG8gcmVncmVzaWUKUHLDoWNhIHMgw7pkYWptaSAgeiBKYXBvbnNrYSB6YSByb2t5IDIwMDAtMjAxNSAKCgpWIHRlanRvIHByw6FjaSBzYSBidWRlbWUgemFvYmVyYcWlIHBydsO9bWkga3Jva21pIHYgb2RoYWRlIHJlZ3Jlc25laiBmdW5rY2llLiBCdWRlbWUgdnl1xb7DrXZhxaUgZGF0YWLDoXp1IFtMaWZlIEV4cGVjdGFuY3kgKFdITykgRml4ZWQgZGF0YXNldF0KKGh0dHBzOi8vd3d3LmthZ2dsZS5jb20vZGF0YXNldHMvbGFzaGFnb2NoL2xpZmUtZXhwZWN0YW5jeS13aG8tdXBkYXRlZCksIGt0b3LDoSBvYnNhaHVqZSB1a2F6b3ZhdGVsZSBuYSDDunJvdm5pIGtyYWrDrW4sIGFrbyBqZSBwcmllbWVybsOhIGTEusW+a2Egxb5pdm90YSwgSERQLCDFoWtvbHNrw6kgdnpkZWzDoXZhbmllIGEgdsO9ZGF2a3kgbmEgemRyYXZvdG7DrWN0dm8uIFZ5YmVyw6FtZSBrcmFqaW51IEphcG9uc2tvLgoKCiMjIFZ5dcW+w612YW5pZSBuaWVrdG9yw71jaCBrbmnFvm7DrWMKCmBgYHtyfQpybShsaXN0PWxzKCkpCmxpYnJhcnkobG10ZXN0KSAgICMgIHBvZHBvcmEgcmVncmVzaWUKbGlicmFyeShvdXRsaWVycykgIyBhbmFseXphIG9kbGFobHljaCBob2Rub3QgKG91dGxpZXJzKQpsaWJyYXJ5KGdwdHN0dWRpbykKbGlicmFyeShrYWJsZUV4dHJhKQpsaWJyYXJ5KGtuaXRyKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KGJyb29tKQpsaWJyYXJ5KGNvcnJwbG90KQpgYGAKCgoKIyMgUHLDrXByYXZhIMO6ZGFqb3YgLSBpbXBvcnQgeiBjc3Ygc8O6Ym9ydQoKU8O6Ym9yIExpZmVfRXhwZWN0YW5jeV9EYXRhIG9ic2FodWplIGRhdGFiw6F6dSBkZXRlcm1pbmFudG92IG/EjWFrw6F2YW5laiBkxLrFvmt5IMW+aXZvdGEuIEltcG9ydCDDumRham92IHVyb2LDrW1lIG5hc2xlZG92bmU6CgpgYGB7cn0KIyBpbXBvcnQgdGhlIGRhdGFzZXQgYW5kIGNyZWF0ZSBhIGRhdGEuZnJhbWUgdWRhamUKdWRhamVfc3ZldCA8LSByZWFkLmNzdigidWRhamUvTGlmZS1FeHBlY3RhbmN5LURhdGEtVXBkYXRlZC5jc3YiLGhlYWRlcj1UUlVFLHNlcD0iLCIsZGVjPSIuIixjaGVjay5uYW1lcyA9IFRSVUUpCmhlYWQodWRhamVfc3ZldCkKYGBgCkRhdGFiw6F6YSBvYnNhaHVqZSDDumRhamUgbyAyOTM4IHBvem9yb3ZhbmlhY2ggYSAyMiBwcmVtZW5uw71jaC4gViB0ZWp0byBwcsOhY2kgc2EgYnVkZW1lIHphb2JlcmHFpSBsZW4gxI1hc8Wlb3UgeiBuaWNoLCBrb25rcsOpdG5lIHTDvW1pLCBrdG9yw6kgc8O6dmlzaWEgcyBkxLrFvmtvdSBkb8W+aXRpYS4gTmEgemHEjWlhdGt1IHNpIHZ5YmVyaWVtZSBrcmFqaW51LCBrdG9yZWogemRyYXZvdG7DvSBzdGF2IGNoY2VtZSBhbmFseXpvdmHFpS4gViB0b210byBwcsOtcGFkZSBpZGUgbyB1xb4gc3BvbcOtbmFuw6kgSmFwb25za286CgpgYGB7cn0KIyB6IGRhdGFiw6F6eSB1ZGFqZV9zdmV0IHNpIHZ5YmVyaWVtZSBsZW4gdGllIHBvem9yb3ZhbmlhLCBrdG9yw6kgc2EgdMO9a2Fqw7ogSmFwb25za2EgCnVkYWplIDwtIHN1YnNldCh1ZGFqZV9zdmV0LCBDb3VudHJ5ID09ICJKYXBhbiIpCmBgYAoKVGFidcS+a2EgdXZlZGVuw6EgbmnFvsWhaWUgbsOhbSBwb3NreXR1amUgesOha2xhZG7DqSBwb3Bpc27DqSDFoXRhdGlzdGlreSB2eWJyYW7DvWNoIGt2YW50aXRhdMOtdm55Y2ggcHJlbWVubsO9Y2guIFZ5bMO6xI1lbsOhIGplIEhlcGF0aXTDrWRhIEIgbmFrb8S+a28gw7pkYWogYm9sIGtvbsWhdGFudG7DvS4KCmBgYHtyfQojIG5pZWt0b3LDqSDFoXRhdGlzdGlreSBhIGljaCBwcmVoxL5hZCB2IHRhYnXEvmtlIEthYmxlRXh0cmEKbGlicmFyeShrYWJsZUV4dHJhKQp1ZGFqZSAlPiUKICBzZWxlY3QoQWR1bHRfbW9ydGFsaXR5LEFsY29ob2xfY29uc3VtcHRpb24sTWVhc2xlcyxCTUksUG9saW8sRGlwaHRoZXJpYSxHRFBfcGVyX2NhcGl0YSxQb3B1bGF0aW9uX21sbixMaWZlX2V4cGVjdGFuY3ksU2Nob29saW5nKSAlPiUKICBzdW1tYXJ5KCkgJT4lCiAga2FibGUoKSAlPiUKICBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gInN0cmlwZWQiLCBmdWxsX3dpZHRoID0gRkFMU0UpCmBgYAoKVnnFocWhaWUgdXZlZGVuw6EgdGFidcS+a2EgbsOhbSBwb3NreXR1amUgcHJlaMS+YWQgbyB6w6FrbGFkbsO9Y2ggxaF0YXRpc3RpY2vDvWNoIGNoYXJha3RlcmlzdGlrw6FjaCB2eWJyYW7DvWNoIHByZW1lbm7DvWNoLCBha28gc8O6IHByaWVtZXJuw6kgaG9kbm90eSwgcm96cHR5bCwgbWluaW11bSBhIG1heGltdW0uIFRpZXRvIGluZm9ybcOhY2llIG7DoW0gcG9tw6FoYWrDuiBsZXDFoWllIHBvY2hvcGnFpSByb3pkZWxlbmllIGEgcm96c2FoIGhvZG7DtHQgdiBuYcWhaWNoIGTDoXRhY2guIE5hIGRydWhlaiBzdHJhbmUgamUgemF1asOtbWF2w6EgYWogaW5mb3Jtw6FjaWEgbyB2esOham9tbsO9Y2ggdnrFpWFob2NoIG1lZHppIHTDvW1pdG8gcHJlbWVubsO9bWksIMSNbyBtw7TFvmVtZSBtZXJhxaUgcG9tb2NvdSBrb3JlbGHEjW5laiBtYXRpY2UuCgpgYGB7cn0KIyBncmFmaWNrw70gcHJlaMS+YWQgbyBrb3JlbGHEjW7DvWNoIHZ6xaVhaG9jaCB2eWphZHJ1amUgbmFzbGVkb3Zuw70gb2Jyw6F6b2sKCmNvcl9tYXRyaXggPC0gY29yKHVkYWplICU+JSBzZWxlY3QoQWR1bHRfbW9ydGFsaXR5LEFsY29ob2xfY29uc3VtcHRpb24sTWVhc2xlcyxCTUksUG9saW8sRGlwaHRoZXJpYSxHRFBfcGVyX2NhcGl0YSxQb3B1bGF0aW9uX21sbixMaWZlX2V4cGVjdGFuY3ksU2Nob29saW5nKSwgdXNlID0gImNvbXBsZXRlLm9icyIpCmNvcnJwbG90KGNvcl9tYXRyaXgsIG1ldGhvZCA9ICJjb2xvciIsIHR5cGUgPSAidXBwZXIiLCB0bC5jb2wgPQoiZGFya2JsdWUiLCB0bC5zcnQgPSA0NSwgdGl0bGUgPSAiS29yZWxhxI1uw6EgbWF0aWNhIHZ5YnJhbsO9Y2ggcHJlbWVubsO9Y2giLCBtYXIgPSBjKDAsMCwxLDApKQoKYGBgClV2ZWRlbsO9IGdyYWYgbsOhbSBwb3NreXR1amUgdml6dcOhbG55IHByZWjEvmFkIG8ga29yZWxhxI1uw71jaCB2esWlYWhvY2ggbWVkemkgdnlicmFuw71taSBwcmVtZW5uw71taS4gRmFyYnkgYSBpbnRlbnppdGEgZmFyaWViIG7DoW0gdW1vxb7FiHVqw7ogcsO9Y2hsbyBpZGVudGlmaWtvdmHFpSBzaWxuw6kgcG96aXTDrXZuZSBhbGVibyBuZWdhdMOtdm5lIGtvcmVsw6FjaWUuIFVwb3pvcsWIdWplbWUsIMW+ZSBrb3JlbMOhY2lhIG5lem5hbWVuw6Ega2F1emFsaXR1LgoKCgogClYgbmFzbGVkb3Zub20gem9icmF6ZW7DrSBqZSB1dmVkZW7DvSBncmFmIHbDvXZvamEgb8SNYWvDoXZhbmVqIGTEusW+a3kgZG/Fvml0aWEgdiBKYXBvbnNrdSB2IHJva29jaCAyMDAwLTIwMTUuIFZpZMOtbWUsIMW+ZSBvxI1ha8OhdmFuw6EgZMS6xb5rYSDFvml2b3RhIHNhIHp2ecWhb3ZhbGEgIG9kIHJva3UgMjAwMCB6IDgxIG5hIDgzIHJva292IHYgcm9rdSAyMDE1LCDEjW8gamUgcG96aXTDrXZueSB0cmVuZC4KCmBgYHtyfQojICBncmFmIHbDvXZvamEgb8SNYWvDoXZhbmVqIGTEusW+a3kgZG/Fvml0aWEgdiBKYXBvbnNrdSB2IHJva29jaCAyMDAwLTIwMTUuCmxpYnJhcnkoZ2dwbG90MikKZ2dwbG90KHVkYWplLCBhZXMoeCA9IFllYXIsIHkgPSBMaWZlX2V4cGVjdGFuY3kpKSArCiAgZ2VvbV9saW5lKCkgKwogIGdlb21fcG9pbnQoKSArCiAgbGFicyh0aXRsZSA9ICJWw712b2ogb8SNYWvDoXZhbmVqIGTEusW+a3kgZG/Fvml0aWEgdiBKYXBvbnNrdSAoMjAwMC0yMDE1KSIsCiAgICAgICB4ID0gIlJvayIsCiAgICAgICB5ID0gIk/EjWFrw6F2YW7DoSBkxLrFvmthIGRvxb5pdGlhIikgKwogIHRoZW1lX21pbmltYWwoKQpgYGAKCgpOYSB6YcSNaWF0a3Ugc2EgcG9rw7pzbWUgbyB2eXJvdm5hbmllIHByaWViZWh1IHRlanRvIHByZW1lbm5laiB2IMSNYXNlIHBvbW9jb3UgbGluZcOhcm5laiByZWdyZXNpZSwga2RlIG5lesOhdmlzbG91IHByZW1lbm5vdSBidWRlIHJvayBhIHrDoXZpc2xvdSBwcmVtZW5ub3UgYnVkZSBvxI1ha8OhdmFuw6EgZMS6xb5rYSBkb8W+aXRpYS4gT2RoYWRuZW1lIGtvZWZpY2llbnR5IHRlanRvIHJlZ3Jlc2llIGEgcG9zw7pkaW1lIGt2YWxpdHUgdnlyb3ZuYW5pYSBwb21vY291IHVrYXpvdmF0ZcS+b3YsIGFrbyBqZSBSLXNxdWFyZWQgYSBwLXZhbHVlLgoKYGBge3J9CiMgdnlyb3ZuYW5pZSBwcmllYmVodSBvxI1ha8OhdmFuZWogZMS6xb5reSBkb8W+aXRpYSB2IMSNYXNlCm1vZGVsIDwtIGxtKExpZmVfZXhwZWN0YW5jeSB+IFllYXIsIGRhdGEgPSB1ZGFqZSkKCmxpYnJhcnkoYnJvb20pCmxpYnJhcnkoa25pdHIpCmxpYnJhcnkoa2FibGVFeHRyYSkKCiMga29lZmljaWVudHkgcmVncmVzaWUKdGlkeShtb2RlbCkgJT4lCiAga2FibGUoZGlnaXRzID0gMywgY2FwdGlvbiA9ICJPZGhhZG51dMOpIGtvZWZpY2llbnR5IHJlZ3Jlc2llIikgJT4lCiAga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9ICJzdHJpcGVkIiwgZnVsbF93aWR0aCA9IEZBTFNFKQoKIyBrdmFsaXRhIHZ5cm92bmFuaWEKZ2xhbmNlKG1vZGVsKSAlPiUKICBrYWJsZShkaWdpdHMgPSAzLCBjYXB0aW9uID0gIlVrYXpvdmF0ZWxlIGt2YWxpdHkgdnlyb3ZuYW5pYSIpICU+JQogIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSAic3RyaXBlZCIsIGZ1bGxfd2lkdGggPSBGQUxTRSkKCmBgYAoKVsO9c2xlZGt5IHJlZ3Jlc2llIG7DoW0gdWthenVqw7osIMW+ZSBrb2VmaWNpZW50IHByZSByb2sgamUgcG96aXTDrXZueSBhIMWhdGF0aXN0aWNreSB2w716bmFtbsO9LCDEjW8gbmF6bmHEjXVqZSwgxb5lIG/EjWFrw6F2YW7DoSBkxLrFvmthIGRvxb5pdGlhIHYgSmFwb25za3Ugc2EgenZ5xaFvdmFsYSB2IHByaWViZWh1IHJva292IDIwMDAtMjAxNS4gSmVqIHByaWVtZXJuw70gcm/EjW7DvSBuw6FyYXN0IGRvc2Fob3ZhbCAwLDE2Mi4gSG9kbm90YSBSLXNxdWFyZWQgaG9kbm90YSBuw6FtIGhvdm9yw60sIMW+ZSBtb2RlbCB2eXN2ZXTEvnVqZSA5NiAlIHZhcmlhYmlsaXR5IG1vZGVsdS4gUG9kxL5hIGhvZG5vdHkgcC12YWx1ZSBtw7TFvmVtZSBwb3ZlZGHFpSwgxb5lIG1vZGVsIGFrbyBjZWxvayBqZSDFoXRhdGlzdGlja3kgdsO9em5hbW7DvS4KCmBgYHtyfQojIHRlcmF6IHZ5xaHFoWllIHV2ZWRlbsO9IG9icsOhem9rIGRvcGxuw61tZSBvIHJlZ3Jlc27DuiBwcmlhbWt1CmdncGxvdCh1ZGFqZSwgYWVzKHggPSBZZWFyLCB5ID0gTGlmZV9leHBlY3RhbmN5KSkgKwogIGdlb21fbGluZSgpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UsIGNvbG9yID0gImdyZWVuIikgKwogIGxhYnModGl0bGUgPSAiVsO9dm9qIG/EjWFrw6F2YW5laiBkxLrFvmt5IGRvxb5pdGlhIHYgSmFwb25za3UgKDIwMDAtMjAxNSkgcyByZWdyZXNub3UgcHJpYW1rb3UiLAogICAgICAgeCA9ICJSb2siLAogICAgICAgeSA9ICJPxI1ha8OhdmFuw6EgZMS6xb5rYSBkb8W+aXRpYSIpICsKICB0aGVtZV9taW5pbWFsKCkKYGBgCgoKIyMjVsO9dm9qIHNwb3RyZWJ5IGFsa29ob2x1ClRlcmF6IHNhIHBvenJpZW1lLCBha28gc2Egdnl2w71qYSBrb256dW3DoWNpYSBhbGtvaG9sdSB2IMSNYXNlIG9kIHJva3UgMjAwMCBkbyByb2t1IDIwMTUgdiBKYXBvbnNrdS4gTmFrb8S+a28gYWxrb2hvbCBqZSBmYWt0b3JvbSBuZWdhdMOtdm5lIHZwbMO9dmFqw7pjaW0gbmEgZMS6xb5rdSBkb8W+aXRpYS4KCgpgYGB7cn0KbW9kZWxfYWxrb2hvbCA8LSBsbShBbGNvaG9sX2NvbnN1bXB0aW9uIH4gWWVhciwgZGF0YSA9IHVkYWplKQojIGt2YWxpdGEgcmVncmVzaWUKdGlkeShtb2RlbF9hbGtvaG9sKSAlPiUKICBrYWJsZShkaWdpdHMgPSAzLCBjYXB0aW9uID0gIk9kaGFkbnV0w6kga29lZmljaWVudHkgcmVncmVzaWUgcHJlIHNwb3RyZWJ1IGFsa29ob2x1IikgJT4lCiAga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9ICJzdHJpcGVkIiwgZnVsbF93aWR0aCA9IEZBTFNFKQoKIyBhIHRlcmF6IG1vZGVsIHF1YWxpdHkgc3RhdGlzdGljcyBSIHNxdWFyZWQKcjI8LSBzdW1tYXJ5KG1vZGVsX2Fsa29ob2wpJHIuc3F1YXJlCmFkal9yMiA8LXN1bW1hcnkobW9kZWxfYWxrb2hvbCkkYWRqLnIuc3F1YXJlCiNwcmludHVqZW1lIGtvZWZpY2llbnQgZGV0ZXJtaW5hbmNpZSBhIHVwcmF2ZW7DvSBrb2VmaWNpZW50IGRldGVybWluYW5jaWUKY2F0ICgiUi1zcXVhcmVkOiIscm91bmQgKHIyLDMpLCAiXG4iKQpjYXQgKCJBZGp1c3RlZCBSLXNxdWFyZWQ6Iixyb3VuZCAoYWRqX3IyLDMpLCAiXG4iKQpgYGAKVsO9c2xlZGt5IHJlZ3Jlc2llIHVrYXp1asO6LCDFvmUga29lZmljaWVudCBwcmUgcHJlbWVubsO6IHJvayBqZSBwb3ppdMOtdm55LCDEjW8gbmF6bmHEjXVqZSBtaWVybnkgcmFzdCBzcG90cmVieSBhbGtvaG9sdSB2IEphcG9uc2t1IHYgb2Jkb2LDrSByb2tvdiAyMDAwIOKAkyAyMDE1LiBPZGhhZG92YW7DvSBrb2VmaWNpZW50IDAsMDQ5IHpuYW1lbsOhLCDFvmUgc3BvdHJlYmEgYWxrb2hvbHUgc2EgdiBwcmllbWVyZSB6dnnFoW92YWxhIHByaWJsacW+bmUgbyAwLDA0OSBqZWRub3RreSByb8SNbmUuIEhvZG5vdGEgcC12YWx1ZSAoMCwwODQpIHbFoWFrIG5hem5hxI11amUsIMW+ZSB0ZW50byBrb2VmaWNpZW50IG5pZSBqZSDFoXRhdGlzdGlja3kgdsO9em5hbW7DvSBuYSBobGFkaW5lIHbDvXpuYW1ub3N0aSA1ICUsIHByZXRvIG5pZSBqZSBtb8W+bsOpIHMgZG9zdGF0b8SNbm91IGlzdG90b3UgcG90dnJkacWlIGV4aXN0ZW5jaXUgxaF0YXRpc3RpY2t5IHbDvXpuYW1uw6lobyB0cmVuZHUgcmFzdHUgc3BvdHJlYnkgYWxrb2hvbHUgdiBzbGVkb3Zhbm9tIG9iZG9iw60uCgoKI09icsOhem9rIG8gc2t1dG/EjW7DvWNoIHZ5cm92bmFuw71jaCBob2Rub3TDoWNoIHNwb3RyZWJ5IGFsa29ob2x1CiAgICAKYGBge3J9CmZpdHRlZF92YWxzIDwtIGZpdHRlZChtb2RlbF9hbGtvaG9sKQojIHZ5a3Jlc2xlbmllIHNrdXRvxI1uw71jaCBhIHZ5cm92bmFuw71jaCBob2Ruw7R0IC0gQWxjb2hvbF9jb25zdW1wdGlvbiBhIGZpdHRlZF92YWx1ZXMKZ2dwbG90KHVkYWplLCBhZXMoeCA9IFllYXIpKSArCiAgZ2VvbV9saW5lKGFlcyh5ID0gQWxjb2hvbF9jb25zdW1wdGlvbiksIGNvbG9yID0gImRhcmtibHVlIiwgc2l6ZSA9IDEpICsKICBnZW9tX2xpbmUoYWVzKHkgPSBmaXR0ZWRfdmFscyksIGNvbG9yID0gIm9yYW5nZSIsIHNpemUgPSAxLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArCiAgbGFicyh0aXRsZSA9ICJTa3V0b8SNbsOpIHZzLiBWeXJvdm5hbsOpIGhvZG5vdHkgc3BvdHJlYnkgYWxrb2hvbHUgdiBKYXBvbnNrdSAoMjAwMC0yMDE1KSIsCiAgICAgICB4ID0gIlJvayIsCiAgICAgICB5ID0gIlNwb3RyZWJhIGFsa29ob2x1IikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwgbWF4KHVkYWplJEFsY29ob2xfY29uc3VtcHRpb24sIGZpdHRlZF92YWxzKSAqIDEuMSkpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCmBgYAoKCiMjIERpYWdub3N0aWNrw6kgZ3JhZnkKCiMjIyBSZXNpZHVhbHMgdnMgRml0dGVkCgpHcmFmICpSZXNpZHVhbHMgdnMgRml0dGVkKiBzbMO6xb5pIG5hIHBvc8O6ZGVuaWUgbGluZWFyaXR5IG1vZGVsdSBhIHByaWJsacW+bmVqIGtvbsWhdGFudG5vc3RpIHJvenB0eWx1IHJlesOtZHXDrS4gUmV6aWR1w6FseSBieSBtYWxpIGJ5xaUgcm96bG/FvmVuw6kgbsOhaG9kbmUgb2tvbG8gbnVsb3ZlaiBob2Rub3R5IGJleiB2w71yYXpuw6lobyBzeXN0ZW1hdGlja8OpaG8gdnpvcnUuIEFrIHNhIG9iamF2w60gdml6dcOhbG5lIHbDvXpuYW1uw6kgemFrcml2ZW5pZSDEjWVydmVuZWogdnlobGFkem92YWNlaiDEjWlhcnksXltMT0VTUyAoTE9jYWwgcmVnckVTU2lvbikga3JpdmthIHByZWRzdGF2dWplIGxva8OhbG5lIHZ5aGxhZGVuw70gdHJlbmQgbWVkemkgcHJlbWVubsO9bWkgYmV6IHByZWRwb2tsYWR1IGtvbmtyw6l0bmVobyBmdW5rxI1uw6lobyB0dmFydS5dIGt0b3LDoSBzbMO6xb5pIG5hIHZpenXDoWxudSBpZGVudGlmaWvDoWNpdSBzeXN0ZW1hdGlja8O9Y2ggb2RjaMO9bG9rIG9kIG7DoWhvZG7DqWhvIHJvemxvxb5lbmlhIHJlesOtZHXDrSwgc2lnbmFsaXp1amUgdG8gdXLEjWl0w6kgc3lzdGVtYXRpY2vDqSBwcm9ibMOpbXkuIEFrIGplIExPRVNTIHByaWJsacW+bmUgaG9yaXpvbnTDoWxuYSwgbW9kZWwgamUgxaFwZWNpZmlrb3ZhbsO9IHZob2RuZTsgYWsgc2EgemFrcml2dWplLCBtw7TFvmUgdG8gbmF6bmHEjW92YcWlIG5lbGluZWFyaXR1LCBjaHlibsO6IMWhcGVjaWZpa8OhY2l1ICh0ZWRhIHbDvWJlciB2eXN2ZXTEvnVqw7pjaWNoIHByZW1lbm7DvWNoKSBhbGVibyBpbsO9IHByb2Jsw6ltIHYgbW9kZWxpLiBBayBzYSBib2R5IHJvesWhaXJ1asO6IGFsZWJvIHp1xb51asO6IHYgdHZhcmUgbGlldmlrYSwgbcO0xb5lIMOtc8WlIG8gaGV0ZXJvc2tlZGFzdGljaXR1LgoKYGBge3IgcmVzaWQtZml0dGVkLCBmaWcuY2FwPSJSZXNpZHVhbHMgdnMgRml0dGVkIiwgZmlnLndpZHRoPTYsIGZpZy5oZWlnaHQ9NX0KcGxvdChtb2RlbCwgd2hpY2ggPSAxKQpgYGAKClJlemlkdcOhIHPDuiByb3psb8W+ZW7DqSBwcmlibGnFvm5lIG9rb2xvIG51bG92ZWogaG9kbm90eSwgYXbFoWFrIHByaSBuYWptZW7FocOtY2ggYWogbmFqdsOkxI3FocOtY2ggb2RoYWRudXTDvWNoIGhvZG5vdMOhY2ggbW9kZWwgc3lzdGVtYXRpY2t5IG5hZGhvZG5vY3VqZSwgcmVzcC4gcG9kaG9kbm9jdWplIHNrdXRvxI1uw6kgaG9kbm90eS4gRG8gdXLEjWl0ZWogbWllcnkgdG8gbcO0xb5lIGJ5xaUgb3ZwbHl2bmVuw6kgb2TEvmFobMO9bWkgcG96b3JvdmFuaWFtaSwgbmFqbcOkIHBvem9yb3ZhbsOtbSDEjS4gMTQxMSBhIDUzMC4gUG/EjWV0IHBvem9yb3ZhbsOtIGplIHbFoWFrIHJlbGF0w612bmUgbWFsw70sIHByZXRvIHTDunRvIHNrdXRvxI1ub3PFpSB6YXRpYcS+IG5lcG92YcW+dWplbWUgemEgesOhc2FkbsO9IHByb2Jsw6ltIGEgcG9kcm9ibmVqxaFpZSBzYSBrIG5laiBtw7TFvmVtZSB2csOhdGnFpSBwcmkgYW5hbMO9emUgxI9hbMWhw61jaCBkaWFnbm9zdGlja8O9Y2ggZ3JhZm92LgoKCiMjIyBRLVEgcGxvdAoKKlEtUSBncmFmKiBwb3Jvdm7DoXZhIHJvemRlbGVuaWUgxaF0YW5kYXJkaXpvdmFuw71jaCByZXrDrWR1w60gcyB0ZW9yZXRpY2vDvW0gbm9ybcOhbG55bSByb3pkZWxlbsOtbS4gQWsgYm9keSBsZcW+aWEgcHJpYmxpxb5uZSBuYSBwcmlhbWtlLCBwcmVkcG9rbGFkIG5vcm1hbGl0eSByZXrDrWR1w60gamUgcHJpYmxpxb5uZSBzcGxuZW7DvS4gVsO9cmF6bmVqxaFpZSBvZGNow71sa3kgbmEga3Jham9jaCBuYXpuYcSNdWrDuiBtb8W+bsOpIHByb2Jsw6lteSBzIGV4dHLDqW1ueW1pIGhvZG5vdGFtaSBhbGVibyBzIMWlYcW+xaHDrW1pIGtvbmNhbWkgcm96ZGVsZW5pYS4gVXLEjWl0b3UgcG9tw7Rja291IHR1IG3DtMW+ZSBiecWlIG5hc2xlZG92bsOhIHRhYnXEvmthOgoKYGBge3IgcXFfdGFibGVfc2ssIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmxpYnJhcnkoa25pdHIpCmxpYnJhcnkoa2FibGVFeHRyYSkKCnFxX3RhYmxlIDwtIGRhdGEuZnJhbWUoCiAgUHLDrXBhZCA9IGMoCiAgICAiTm9ybcOhbG5lIHJvemRlbGVuaWUiLAogICAgIsS9YXZvc3RyYW5uw6EgxaFpa21vc8WlIChuZWdhdMOtdm5hKSIsCiAgICAiUHJhdm9zdHJhbm7DoSDFoWlrbW9zxaUgKHBveml0w612bmEpIiwKICAgICJTeW1ldHJpY2vDqSwgdnlzb2vDoSDFoXBpY2F0b3PFpSAoPiAzKSIsCiAgICAiU3ltZXRyaWNrw6ksIG7DrXprYSDFoXBpY2F0b3PFpSAoPCAzKSIKICApLAogIGBUdmFyIFEtUSBncmFmdWAgPSBjKAogICAgIlByaWFta2EiLAogICAgIlByZWhudXTDvSBuYWRvbCAo4oipIHR2YXIpIiwKICAgICJQcmVobnV0w70gbmFob3IgKOKIqiB0dmFyKSIsCiAgICAiUy10dmFyIiwKICAgICJPYnLDoXRlbsO9IFMtdHZhciIKICApLAogIGDEvWF2w70gY2h2b3N0YCA9IGMoCiAgICAiTmEgcHJpYW1rZSIsCiAgICAiTmFkIHByaWFta291IiwKICAgICJQb2QgcHJpYW1rb3UiLAogICAgIlBvZCBwcmlhbWtvdSIsCiAgICAiTmFkIHByaWFta291IgogICksCiAgYFByYXbDvSBjaHZvc3RgID0gYygKICAgICJOYSBwcmlhbWtlIiwKICAgICJQb2QgcHJpYW1rb3UiLAogICAgIk5hZCBwcmlhbWtvdSIsCiAgICAiTmFkIHByaWFta291IiwKICAgICJQb2QgcHJpYW1rb3UiCiAgKSwKICBJbnRlcnByZXTDoWNpYSA9IGMoCiAgICAiRMOhdGEgbWFqw7ogbm9ybcOhbG5lIHJvemRlbGVuaWUiLAogICAgIkRsaMO9IMS+YXbDvSBjaHZvc3QgKGV4dHLDqW1uZSBuw616a2UgaG9kbm90eSkiLAogICAgIkRsaMO9IHByYXbDvSBjaHZvc3QgKGV4dHLDqW1uZSB2eXNva8OpIGhvZG5vdHkpIiwKICAgICLFpGHFvmvDqSBjaHZvc3R5ICh2aWFjIGV4dHLDqW1ueWNoIGhvZG7DtHQpIiwKICAgICLEvWFoa8OpIGNodm9zdHkgKG1lbmVqIGV4dHLDqW1ueWNoIGhvZG7DtHQpIgogICkKKQoKa2FibGUocXFfdGFibGUsIGNhcHRpb24gPSAiSW50ZXJwcmV0w6FjaWEgUeKAk1EgZ3JhZnUiKSAlPiUKICBrYWJsZV9zdHlsaW5nKAogICAgYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImhvdmVyIiwgImNvbmRlbnNlZCIpLAogICAgZnVsbF93aWR0aCA9IEZBTFNFLAogICAgcG9zaXRpb24gPSAiY2VudGVyIgogICkgJT4lCiAgcm93X3NwZWMoMCwgYm9sZCA9IFRSVUUpCmBgYAoKTmlla2VkeSBob3ZvcsOtbWUgbyBwb23DtGNrZToKCi0gUHJpYW1rYSDihpIgbm9ybcOhbG5lIHJvemRlbGVuaWUKLSDiiKog4oaSIHByYXZvc3RyYW5uw6EgxaFpa21vc8WlCi0g4oipIOKGkiDEvmF2b3N0cmFubsOhIMWhaWttb3PFpQotIFMg4oaSIHZ5c29rw6EgxaFwaWNhdG9zxaUgKMWlYcW+a8OpIGNodm9zdHkpCi0gb2Jyw6F0ZW7DqSBTIOKGkiBuw616a2EgxaFwaWNhdG9zxaUKCgpgYGB7ciBxcS1wbG90LCBmaWcuY2FwPSJOb3JtYWwgUS1RIHBsb3QiLCBmaWcud2lkdGg9NiwgZmlnLmhlaWdodD01fQpwbG90KG1vZGVsLCB3aGljaCA9IDIpCmBgYAoKVXByYXZlbsO9IHBvcGlzIHBvZMS+YSBncmFmdToKCi0tLQoKUS1RIGdyYWYgcG9yb3Zuw6F2YSBlbXBpcmlja8OpIHJvemRlbGVuaWUgxaF0YW5kYXJkaXpvdmFuw71jaCByZXrDrWR1w60gcyB0ZW9yZXRpY2vDvW0gbm9ybcOhbG55bSByb3pkZWxlbsOtbS4gViBwcsOtcGFkZSBzcGxuZW5pYSBwcmVkcG9rbGFkdSBub3JtYWxpdHkgYnkgbWFsaSBib2R5IGxlxb5hxaUgcHJpYmxpxb5uZSBuYSBkaWFnb27DoWxuZWogcHJpYW1rZS4KClYgbmHFoW9tIHByw61wYWRlIHbDpMSNxaFpbmEgYm9kb3YgdiBzdHJlZG5laiDEjWFzdGkgZ3JhZnUgbGXFvsOtIHBvbWVybmUgYmzDrXprbyBwcmlhbWt5LCDEjW8gbmF6bmHEjXVqZSwgxb5lIHByZSB2w6TEjcWhaW51IHBvem9yb3ZhbsOtIGplIHByZWRwb2tsYWQgbm9ybWFsaXR5IHByaWJsacW+bmUgc3BsbmVuw70uIENlbnRyw6FsbmEgxI1hc8WlIHJvemRlbGVuaWEgcmV6w61kdcOtIHNhIHRlZGEgc3Byw6F2YSBwb2RvYm5lIGFrbyBub3Jtw6FsbmUgcm96ZGVsZW5pZS4KCk5hIMS+YXZvbSBrb25jaSBncmFmdSBkb2Now6FkemEgayB2w71yYXpuZWrFoWllbXUgb2RjaMO9bGVuaXUgYm9kb3YgcG9kIHJlZmVyZW7EjW7DuiBwcmlhbWt1LiBOYWptw6QgcG96b3JvdmFuaWUgxI0uIDUzMCBwcmVkc3RhdnVqZSBleHRyw6ltbmUgesOhcG9ybsOpIHJlemlkdXVtLCDEjW8gbmF6bmHEjXVqZSDFpWHFvsWhw60gxL5hdsO9IGNodm9zdCByb3pkZWxlbmlhIG9wcm90aSBub3Jtw6FsbmVtdSByb3pkZWxlbml1LiBNZW7FoWlhIG9kY2jDvWxrYSBqZSB2aWRpdGXEvm7DoSBhaiBwcmkgcG96b3JvdmFuw60gxI0uIDU2Ni4KCk5hIHByYXZvbSBrb25jaSBncmFmdSBzw7ogYm9keSByZWxhdMOtdm5lIGJsw616a28gcmVmZXJlbsSNbmVqIHByaWFta3kuIFBvem9yb3ZhbmllIMSNLiAxNDExIHNhIG5hY2jDoWR6YSBtaWVybmUgcG9kIHByaWFta291LCDEjW8gcG91a2F6dWplIGxlbiBuYSBtYWzDuiBvZGNow71sa3Ugb2Qgbm9ybWFsaXR5IGEgbmVwcmVkc3RhdnVqZSB2w71yYXpuw70gcHJvYmzDqW0uCgpDZWxrb3ZvIG1vxb5ubyBrb27FoXRhdG92YcWlLCDFvmUgbm9ybWFsaXRhIHJlesOtZHXDrSBqZSBwcmlibGnFvm5lIHNwbG5lbsOhLCBhdsWhYWsgcyBtaWVybnltaSBvZGNow71sa2FtaSB2IGNodm9zdG9jaCByb3pkZWxlbmlhLCBuYWptw6QgdiDEvmF2b20gY2h2b3N0ZSBzcMO0c29iZW7DvW1pIG9kxL5haGzDvW1pIHBvem9yb3ZhbmlhbWkuIFogcHJha3RpY2vDqWhvIGjEvmFkaXNrYSBpZGUgbyBtaWVybmUgcG9ydcWhZW5pZSBwcmVkcG9rbGFkdSBub3JtYWxpdHksIGt0b3LDqSB2xaFhayB2emjEvmFkb20gbmEgZG9icsOpIHNwcsOhdmFuaWUgdsOkxI3FoWlueSByZXrDrWR1w60gbmVtdXPDrSBwcmVkc3Rhdm92YcWlIHrDoXNhZG7DvSBwcm9ibMOpbSBwcmUgxI9hbMWhaXUgYW5hbMO9enUuCgojIyMgU2NhbGUtTG9jYXRpb24gcGxvdAoKKlNjYWxlLUxvY2F0aW9uIGdyYWYqIHNhIHBvdcW+w612YSBuYSBwb3PDumRlbmllIGhvbW9za2VkYXN0aWNpdHksIHRlZGEga29uxaF0YW50bm9zdGkgcm96cHR5bHUgcmV6w61kdcOtLiBBayBzw7ogYm9keSByb3psb8W+ZW7DqSBwcmlibGnFvm5lIHJvdm5vbWVybmUgYSDEjWVydmVuw6EgxI1pYXJhIGplIHJlbGF0w612bmUgdm9kb3Jvdm7DoSwgaWRlIG8gcHJpYXpuaXbDvSB2w71zbGVkb2suIFN5c3RlbWF0aWNrw70gcmFzdCBhbGVibyBwb2tsZXMgbmF6bmHEjXVqZSwgxb5lIHJvenB0eWwgcmV6w61kdcOtIHNhIG1lbsOtIHMgw7pyb3bFiG91IHByZWRpa292YW7DvWNoIGhvZG7DtHQuCgpgYGB7ciBzY2FsZS1sb2NhdGlvbiwgZmlnLmNhcD0iU2NhbGUtTG9jYXRpb24gcGxvdCIsIGZpZy53aWR0aD02LCBmaWcuaGVpZ2h0PTV9CnBsb3QobW9kZWwsIHdoaWNoID0gMykKYGBgCgoKVHUgamUgdXByYXZlbsO9IHBvcGlzIHByZXNuZWrFoWllIHBvZMS+YSBncmFmdToKCkJvZHkgc8O6IHJvenB0w71sZW7DqSBwb21lcm5lIHJvdm5vbWVybmUgdiBjZWxvbSByb3pzYWh1IHZ5cm92bmFuw71jaCBob2Ruw7R0LCBiZXogdsO9cmF6bsOpaG8gc3lzdGVtYXRpY2vDqWhvIHZ6b3J1LiDEjGVydmVuw6EgdnlobGFkem92YWNpYSBrcml2a2EgbWllcm5lIHJhc3RpZSBwcmkgbmnFvsWhw61jaCBob2Rub3TDoWNoLCBuw6FzbGVkbmUgc2Egc3RhYmlsaXp1amUgYSBrdSBrb25jdSBsZW4gdmXEvm1pIG1pZXJuZSBrb2zDrcWhZSwgYmV6IHbDvXJhem7DqWhvIHJhc3TDumNlaG8gdHJlbmR1IHByaSB2ecWhxaHDrWNoIGhvZG5vdMOhY2guCgpOaWVrdG9yw6kgYm9keSAobmFwci4gcG96b3JvdmFuaWEgb3puYcSNZW7DqSA1MzAsIDU2NiBhIDE0MTEpIHNhIG9kIG9zdGF0bsO9Y2ggbWllcm5lIG9kY2h5xL51asO6LCBtw7TFvnUgdGVkYSBwcmVkc3Rhdm92YcWlIHBvdGVuY2nDoWxuZSBvZMS+YWhsw6kgYWxlYm8gdnBseXZuw6kgcG96b3JvdmFuaWEsIGF2xaFhayBpY2ggdnBseXYgbmllIGplIGV4dHLDqW1ueS4KCk5ldnpuaWvDoSB0eXBpY2vDvSDigJ5saWV2aWtvdml0w73igJwgdHZhciwga3RvcsO9IGJ5IG5hem5hxI1vdmFsIHbDvXJhem7DqSBwb3J1xaFlbmllIHByZWRwb2tsYWR1IGtvbsWhdGFudG7DqWhvIHJvenB0eWx1LiBWYXJpYWJpbGl0YSByZXrDrWR1w60gc2EgamF2w60gYWtvIHJlbGF0w612bmUgc3RhYmlsbsOhIG5hcHJpZcSNIGhvZG5vdGFtaSwgxI1vIG5hem5hxI11amUsIMW+ZSBwcmVkcG9rbGFkIGhvbW9za2VkYXN0aWNpdHkgamUgc3BsbmVuw70sIHByw61wYWRuZSBsZW4gdmXEvm1pIG1pZXJuZSBuYXJ1xaFlbsO9LgoKIyMjIFJlc2lkdWFscyB2cyBMZXZlcmFnZQoKR3JhZiAqUmVzaWR1YWxzIHZzIExldmVyYWdlKiBwb23DoWhhIGlkZW50aWZpa292YcWlIHZwbHl2bsOpIHBvem9yb3ZhbmlhLiBMZXZlcmFnZSB0byBwcmVkc3RhdnVqZSB2emlhbGVub3PFpSBkYW7DqWhvIHBvem9yb3ZhbmlhIHbFoWV0a8O9Y2ggdnlzdmV0xL51asO6Y2ljaCBwcmVtZW5uw71jaCAodGVkYSB2ZWt0b3JhKSBvZCBvc3RhdG7DvWNoLCByZXNwLiBvZCBzdHJlZG7DqWhvIHZla3RvcmEgdsWhZXRreWNoIHBvem9yb3ZhbsOtLiBUw610byB2emRpYWxlbm9zxaUgamUgbm9ybW92YW7DoSBuYSBpbnRlcnZhbCAoMCwxKSBhIHbDpMSNxaFpbmEgcG96b3JvdmFuw60gbcOhIHZlxL5taSBtYWzDvSBsZXZlcmFnZS4gQWsgc2Egdnlza3l0dWrDuiBwb3pvcm92YW5pYSBzIHZ5c29rw71tIGxldmVyYWdlLCBpZGVudGlmaWt1amVtZSBpY2ggbmEgdm9kb3Jvdm5laiBvc2kgYSBtw7TFvnUgem5hbWVuYcWlIHBvdGVuY2nDoWxuZSBuZWJlenBlxI1lbnN0dm8gdiBza3Jlc2xlbsOtIHBhcmFtZXRyb3Ygdnlyb3Zuw6F2YWrDumNlaiBuYWRyb3ZpbnkgKHRlZGEgb2RoYWRvdmFuw71jaCAkXGJldGEkIGtvZWZpY2llbnRvdikuIFBvem9yb3ZhbmlhIHMgdnlzb2tvdSBob2Rub3RvdSBsZXZlcmFnZSBhIHPDusSNYXNuZSB2ZcS+a8O9bWkgcmV6w61kdWFtaSBtw7TFvnUgbcO0xb51IHNww7Rzb2JvdmHFpSB0ZW50byBwcm9ibMOpbS4gQWsgc2Egbmlla3RvcsOpIGJvZHkgbmFjaMOhZHphasO6IGJsw616a28gYWxlYm8gemEga3JpdmthbWkgQ29va292ZWogdnpkaWFsZW5vc3RpLCBqZSB2aG9kbsOpIGljaCBwb2Ryb2JuZWrFoWllIHByZXNrw7ptYcWlLgoKCmBgYHtyIHJlc2lkLWxldmVyYWdlLCBmaWcuY2FwPSJSZXNpZHVhbHMgdnMgTGV2ZXJhZ2UiLCBmaWcud2lkdGg9NiwgZmlnLmhlaWdodD01fQpwbG90KG1vZGVsLCB3aGljaCA9IDUpCmBgYAoKClR1IGplIHVwcmF2ZW7DvSBwb3BpcyBwb2TEvmEgem9icmF6ZW7DqWhvIGdyYWZ1OgoKViBuYcWhb20gcHLDrXBhZGUgbcOhIHbDpMSNxaFpbmEgcG96b3JvdmFuw60gbsOtemtlIGHFviBzdHJlZG7DqSBob2Rub3R5IGxldmVyYWdlIGEgamUgcm96cHTDvWxlbsOhIG5ham3DpCB2IGludGVydmFsZSBwcmlibGnFvm5lIG9kIDAuMDUgZG8gMC4yMCwgxI1vIG5hem5hxI11amUsIMW+ZSDFvmlhZG5lIHBvem9yb3ZhbmllIG5lbcOhIGV4dHLDqW1uZSB2eXNva8O6IHDDoWtvdsO6IGhvZG5vdHUuIETDoXRhIHRlZGEgbmVww7Rzb2JpYSB2w71yYXpuZSBuZXZ5dsOhxb5lbmUgeiBoxL5hZGlza2EgdnlzdmV0xL51asO6Y2ljaCBwcmVtZW5uw71jaC4KClogaMS+YWRpc2thIHJlesOtZHXDrSB2w6TEjcWhaW5hIGJvZG92IG5ldnlrYXp1amUgZXh0csOpbW5lIGhvZG5vdHksIGF2xaFhayBuaWVrdG9yw6kgcG96b3JvdmFuaWEgKG5ham3DpCA1MzApIG1hasO6IHbDvXJhem5lasWhaWUgesOhcG9ybsOpIHJlesOtZHV1bS4gT2tyZW0gdG9obyBib2R5IGFrbyAxMTk3IGEgNTY2IG1hasO6IHZ5xaHFoWllIGxldmVyYWdlLCDEjW8gem5hbWVuw6EsIMW+ZSBtw7TFvnUgbWHFpSB2w6TEjcWhw60gdnBseXYgbmEgb2RoYWQgbW9kZWx1LgoKS29udMO6cnkgQ29va292ZWogdnpkaWFsZW5vc3RpIHVrYXp1asO6IG1pZXJ1IHZwbHl2dSBqZWRub3RsaXbDvWNoIHBvem9yb3ZhbsOtLiDFvWlhZG55IGJvZCB6amF2bmUgbmVwcmVrcmHEjXVqZSBocmFuaWN1IGhvZG5vdHkgMSwgYXbFoWFrIHBvem9yb3ZhbmllIDUzMCBzYSBuYWNow6FkemEgdiBvYmxhc3RpIHZ5xaHFocOtY2ggaG9kbsO0dCBDb29rb3ZlaiB2emRpYWxlbm9zdGkgKG1lZHppIDAuNSBhIDEpLCDEjW8gbmF6bmHEjXVqZSwgxb5lIG3DtMW+ZSBiecWlIHBvdGVuY2nDoWxuZSB2cGx5dm7DqSBhIHphc2zDusW+aSBzaSBibGnFvsWhaWUgcHJlc2vDum1hbmllLgoKQ2Vsa292byBtb8W+bm8ga29uxaF0YXRvdmHFpSwgxb5lIG1vZGVsIG5lb2JzYWh1amUgZXh0csOpbW5lIHZwbHl2bsOpIHBvem9yb3ZhbmlhLCBrdG9yw6kgYnkgesOhc2FkbmUgbmFyw7rFoWFsaSBqZWhvIHN0YWJpbGl0dSwgYXbFoWFrIGV4aXN0dWrDuiBqZWRub3RsaXbDqSBib2R5IChuYWptw6QgNTMwLCBwcsOtcGFkbmUgMTE5NyBhIDU2NiksIGt0b3LDqSBtw7TFvnUgbWHFpSB6dsO9xaFlbsO9IHZwbHl2IG5hIHbDvXNsZWRreSBhIGplIHZob2Ruw6kgaW0gdmVub3ZhxaUgcG96b3Jub3PFpS4K