# Najprv inštalácia balíkov (iba raz)
install.packages("zoo")
trying URL 'http://rspm/default/__linux__/focal/latest/src/contrib/zoo_1.8-14.tar.gz'
Content type 'application/x-gzip' length 1018553 bytes (994 KB)
==================================================
downloaded 994 KB


The downloaded source packages are in
    ‘/tmp/RtmpeRarTf/downloaded_packages’
install.packages("tseries")
trying URL 'http://rspm/default/__linux__/focal/latest/src/contrib/tseries_0.10-58.tar.gz'
Content type 'application/x-gzip' length 373247 bytes (364 KB)
==================================================
downloaded 364 KB


The downloaded source packages are in
    ‘/tmp/RtmpeRarTf/downloaded_packages’
install.packages("lmtest")
trying URL 'http://rspm/default/__linux__/focal/latest/src/contrib/lmtest_0.9-40.tar.gz'
Content type 'application/x-gzip' length 399624 bytes (390 KB)
==================================================
downloaded 390 KB


The downloaded source packages are in
    ‘/tmp/RtmpeRarTf/downloaded_packages’
install.packages("sandwich")
trying URL 'http://rspm/default/__linux__/focal/latest/src/contrib/sandwich_3.1-1.tar.gz'
Content type 'application/x-gzip' length 1505348 bytes (1.4 MB)
==================================================
downloaded 1.4 MB


The downloaded source packages are in
    ‘/tmp/RtmpeRarTf/downloaded_packages’
install.packages("car")
trying URL 'http://rspm/default/__linux__/focal/latest/src/contrib/car_3.1-3.tar.gz'
Content type 'application/x-gzip' length 1510899 bytes (1.4 MB)
==================================================
downloaded 1.4 MB


The downloaded source packages are in
    ‘/tmp/RtmpeRarTf/downloaded_packages’
# Načítanie balíkov
library(zoo)
library(tseries)
library(lmtest)
library(sandwich)
library(car)

PRÍPRAVA ÚDAJOV

V tejto časti sme z datasetu vybrali tri dôležité ukazovatele: populáciu v roku 2020, rozlohu krajiny a hustotu obyvateľstva. Pretože údaje obsahovali chýbajúce hodnoty, doplnili sme ich pomocou mediánu, aby analýza nebola skreslená ani prerušená NA hodnotami. Následne sme všetky premenné prekonvertovali na číselný formát, aby sa dali ďalej štatisticky spracovať. Výsledkom je čistý a kompletný dataset vhodný na následné regresné modelovanie.

# Načítanie dát
udaje <- read.csv("world_population.csv", dec=".", sep=",", header = TRUE)

# Výber údajov z roku 2020 (nie 2015 — podľa tvojho datasetu)
# a výber premenných, ktoré si používala v predošlom cvičení:
# - 2020 Population
# - Area (km2)
# - Density (per km2)

udaje.2020 <- udaje[, c("X2020.Population", "Area..km..", "Density..per.km..")]

# Konverzia na numerické hodnoty (niektoré môžu byť ako text)
udaje.2020 <- as.data.frame(lapply(udaje.2020, as.numeric))

IMPUTÁCIA DÁT – DOPLNENIE NA MEDIÁN

# Výpočet mediánov pre každý stĺpec
column_medians <- sapply(udaje.2020, median, na.rm = TRUE)

# Imputácia
udaje_imputed <- udaje.2020
for (col in names(udaje.2020)) {
  udaje_imputed[[col]][is.na(udaje_imputed[[col]])] <- column_medians[col]
}

# Aktuálne upravený dataset
udaje.2020 <- udaje_imputed
udaje <- udaje.2020

KONTROLA

summary(udaje)
sum(is.na(udaje))

ZÁKLADNÁ REGRESIA – UPRAVENÁ NA WORLD POPULATION DÁTA

V regresnom modeli sme skúmali, ako populácia a rozloha krajiny ovplyvňujú hustotu obyvateľstva. Výsledky ukazujú, či existuje matematický vzťah medzi veľkosťou populácie, územím krajiny a tým, koľko ľudí žije na km². Koeficienty modelu ukazujú smer a silu týchto vzťahov, a štatistická významnosť (p-hodnoty) naznačuje, či sú premenné skutočne dôležitými prediktormi. Celkovo model pomáha pochopiť, ktoré faktory najviac prispievajú k hustote obyvateľstva.

attach(udaje)

# Lineárny model: hustota ako funkcia populácie a rozlohy
model <- lm(Density..per.km.. ~ 1 + X2020.Population + Area..km.., data = udaje)

summary(model)

1. Test RESET (test chyby špecifikácie Ramseyho regresnej rovnice - Ramsey Reset Test)

Myšlienka: Nech pôvodný model má tvar \[y_t = \beta_0 + \beta_1 x_{t10} + \dots +\beta_k x_{tk} + u_t\] \[y_t = \beta_0 + \beta_1 x_{t10} + \dots +\beta_k x_{tk} + \gamma_2\hat y_t^2 + \gamma_3\hat{y}_t^3 + u_t\] Budeme testovať hypotézu

\(H_0:\) model je správne špecifikovaný (\(\gamma_2 = \gamma_3 = 0\))

oproti

\(H_1:\) model je nesprávne špecifikovaný (\(\gamma_2 \ne 0 \quad \text{alebo} \quad \gamma_3 \ne 0\))

# Suppose your model is:
model <- lm(Density..per.km.. ~ 1 + X2020.Population + Area..km.., data = udaje)


# RESET test from 'lmtest' package:
library(lmtest)
resettest(model)

Interpretácia

Null hypotéza (H0): Model je správne špecifikovaný (nechýbajú nelineárne vzťahy ani dôležité premenné).

Alternatívna hypotéza (H1): Model je nesprávne špecifikovaný (chýbajú premenné alebo nelineárne vzťahy).

p-value = 0.2507 → vyššie ako bežnú hladinu významnosti (napr. 0.05).

RESET test overuje, či je model správne špecifikovaný, teda či mu nechýbajú dôležité premenné alebo nelineárne vzťahy. V našom prípade je p-hodnota 0.25, čo znamená, že nemáme dôkaz o nesprávnej špecifikácii. Model Density ~ Population + Area je teda vhodný a nie je potrebné pridávať ďalšie členy.

2. Grafická analýza

Graf Residuals vs. Fitted

plot(model, which = 1)

Grafy C+R **

\[y_t = \beta_0 + \beta_1 x_{t1} + \dots +\beta_k x_{tk} + u_t\] Túto rovnicu najprv odhadneme a potom vykresľujeme grafy, kde výraz component+residual (C+R) plot vykresľuje na zvislej osi \(\hat{\beta}_ix_{ti}+e_t\) a na vodorovnej osi vykresľuje hodnoty \(x_{ti}\)

car::crPlots(model)

Graf – 2020 Population

Väčšina bodov je veľmi blízko osi 0 → populácia väčšiny krajín/území je relatívne nízka (v porovnaní s extrémami).

Niekoľko vzdialených bodov (outlierov) predstavuje veľmi veľké populácie.

Fialová čiara (lineárny model) mierne stúpa → model predpokladá pozitívnu, ale slabú lineárnu závislosť.

Modrá LOESS krivka je takmer plochá → skutočný nelineárny trend je prakticky nulový.

Interpretácia:

Populácia nemá výrazný lineárny ani nelineárny efekt na hustotu obyvateľstva v tomto modeli. Outliery môžu skresľovať fit.

Graf – Area (km²)

Situácia je podobná – väčšina území má malú rozlohu, pár extrémne veľkých štátov vytvára outliery.

Lineárny model (fialová čiara) mierne klesá → väčšia rozloha môže súvisieť s nižšou hustotou.

LOESS (modrá krivka) je tiež mierne klesajúca, ale takmer plochá.

Interpretácia:

Rozloha má slabý negatívny vzťah s hustotou, čo je logicky očakávané, ale závislosť je veľmi slabá. Nelineárny efekt sa prakticky neprejavuje.

3. Nelineárna špecifikácia

\[y_t = \beta_0 + \beta_1 x_{t10} + \dots +\beta_k x_{tk} + \dots + \gamma_i\hat x_{ik}^2 + \dots + \gamma_j\hat x_{jk}^2 + \dots + u_t\]


model <- lm(Density..per.km.. ~ X2020.Population + Area..km.., data = udaje)

model_kvadr <- lm(Density..per.km.. ~ 
                    X2020.Population + Area..km.. +
                    I(X2020.Population^2) + I(Area..km..^2),
                  data = udaje)

summary(model_kvadr)

anova(model, model_kvadr)

library(lmtest)
resettest(model_kvadr)

Kvadratický regresný model ukázal, že žiadna z premenných (populácia, rozloha ani ich kvadratické členy) nie je štatisticky významným prediktorom hustoty obyvateľstva. Hodnota R² takmer nulová a záporné upravené R² potvrdzujú, že model nedokáže vysvetliť variabilitu hustoty. ANOVA test ukázal, že pridanie kvadratických členov model nezlepšuje. RESET test síce nenaznačil chybnú špecifikáciu modelu, no samotný model je pre predikciu hustoty nevhodný.

model_kvadr <- lm(Density..per.km.. ~ X2020.Population + Area..km.. + I(X2020.Population^2), 
                  data = udaje)

summary(model_kvadr)

Reziduá majú veľmi široký rozsah, pričom maximum výrazne prevyšuje ostatné hodnoty, čo naznačuje prítomnosť extrémnych odľahlých pozorovaní v dátach. Žiadny z koeficientov vysvetľujúcich premenných nie je štatisticky významný (p-hodnoty sú vysoko nad 0.05), takže populácia, rozloha ani kvadratický člen populácie nevysvetľujú hustotu obyvateľstva. Veľmi nízke R² a záporné upravené R² ukazujú, že model prakticky nedokáže zachytiť variabilitu závislej premennej a je menej vhodný než triviálny model bez prediktorov. Nízka hodnota F-štatistiky a vysoká p-hodnota potvrdzujú, že model ako celok nie je štatisticky významný.

5. Použitie rozšíreného RESET testu

model_rozsireny <- lm(Density..per.km.. ~ 
                        X2020.Population + 
                        Area..km.. + 
                        I(X2020.Population^2) + 
                        I(Area..km..^2),
                      data = udaje)

summary(model_rozsireny)
anova(model,model_rozsireny)
resettest(model_rozsireny)

6. Transformácia pomocou dummy premennej a lineárnej lomenej funkcie

  1. zlom v autonómnom člene \(\beta_0\) a to nasledovnou špecifikáciou \[y_t = \beta_0 + \beta_D D+ \beta_1 x_{t1} + \dots +\beta_k x_{tk} + u_t\] čo interpretujeme ako posun regresnej priamky (regresnej nadroviny) o \(\beta_D\) jednotiek pozdĺž zvislej osi a to len v pozorovaniach, ak je splnená podmienka \(D_t = 1\)
  2. zlom v sklone regresnej priamky (nadroviny) a to len v pozorovaniach, ak je splnená podmienka \(D_t = 1\), čo dosiahneme nasledovnou špecifikáciou \[y_t = \beta_0 + \beta_1 x_{t1} + \dots + \beta_{i}x_{ti} + \beta_{Di}D_tx_{ti}+ \dots + \beta_k x_{tk} + u_t\] kde teda sklon priamky pozdĺž premenne \(x_{ti}\) je \(\beta_i\) ale len v prípade \(D_t=0\), inak je ten sklon rovný \(\beta_i+\beta_{D_i}\).
# Dummy premenná podľa populácie – nízka vs. vysoká populácia 
udaje$DUM <- ifelse(udaje$X2020.Population < median(udaje$X2020.Population, na.rm = TRUE), 
                    0, 1)

# Lineárny model s dummy premennou
modelD_auto <- lm(Density..per.km.. ~ DUM + X2020.Population + Area..km.., data = udaje)

summary(modelD_auto)

Model ukazuje, že žiadna z premenných – ani dummy premenná, populácia či rozloha – nie je štatisticky významným prediktorom hustoty obyvateľstva. Hodnoty R² aj upraveného R² sú takmer nulové, čo znamená, že model nedokáže vysvetliť variabilitu dát. Intercept je jediný významný parameter, čo naznačuje, že vysvetľujúce premenné neprispievajú k predikcii nad rámec priemernej hodnoty. Celkovo model ako celok opäť nie je štatisticky významný, čo potvrdzuje aj vysoká p-hodnota F-štatistiky.

# Príklad: predikcia Density na základe Population a Area
modelD_sklon <- lm(Density..per.km.. ~ X2020.Population + Area..km.., data=udaje)
summary(modelD_sklon)

Model sa snažil predikovať hustotu obyvateľstva (Density..per.km..) na základe populácie (X2020.Population) a rozlohy (Area..km..). Hodnoty koeficientov ukazujú, že ani populácia, ani rozloha nemajú štatisticky významný vplyv na hustotu (p-hodnoty 0.981 a 0.387, teda veľmi vysoko). Nízke R-squared (0.004) znamená, že model vysvetľuje len veľmi malú časť variability hustoty, prakticky zanedbateľnú. Celkovo teda tento lineárny model nie je vhodný na predikciu hustoty obyvateľstva z týchto premenných.

anova(model, modelD_sklon)
resettest(modelD_sklon)

V kombinácii s predchádzajúcim summary(), kde model vysvetľoval len zanedbateľnú časť variability (R² ≈ 0.004), to znamená: model je lineárne správne špecifikovaný, ale je prakticky nepoužiteľný, pretože prediktory populácia a rozloha veľmi nevysvetľujú hustotu.

7. Box-Coxov transformačný test

library(MASS)
boxcox(model)

Z tohto grafu vyplýva, že najpravdepodobnejšia hodnota parametra λ bola úspešne odhadnutá pomocou metódy maximálnej vierohodnosti (MLE). Interval spoľahlivosti okolo tejto hodnoty nám ukazuje, v akom rozsahu sa s vysokou istotou (napr. 95 %) nachádza skutočný parameter. To znamená, že model je dobre prispôsobený dátam a máme kvantifikovanú mieru neistoty ohľadne odhadu λ.

# Transformácia závislej premennej (napr. mocnina 1.8)
model_lambda <- lm(I((`Density..per.km..`^1.8 - 1)/1.8) ~ `X2020.Population` + `Area..km..`, data = udaje)

# Výpis výsledkov modelu
summary(model_lambda)

# RESET test pre kontrolu špecifikácie modelu
library(lmtest)
resettest(model_lambda)

fRESET test s p-hodnotou 0.5505 naznačuje, že lineárny tvar modelu je štatisticky správne špecifikovaný a nie je dôkaz potreby nelineárnych transformácií prediktorov.

LS0tCnRpdGxlOiAiUHLDoWNhIHMgZGF0YWLDoXpvdSAtIFdvcmxkIHBvcHVsYXRpb24iCmF1dGhvcjogIkJhcmJvcmEgS3VjaMOhcmlrb3bDoSAgPGJyPiIKZGF0ZTogIk5vdmVtYmVyIDIwMjUiCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIHRoZW1lOiB1bml0ZWQKICAgIGhpZ2hsaWdodDogdGFuZ28KICAgIGNzczogY3VzdG9tLmNzcwogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IHRydWUKICAgIGRmX3ByaW50OiBwYWdlZAogIHBkZl9kb2N1bWVudDoKICAgIHRvYzogdHJ1ZQplZGl0b3Jfb3B0aW9uczoKICBtYXJrZG93bjoKICAgIHdyYXA6IDcyCi0tLQoKCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQpgYGAKCmBgYHtyfQojIE5hanBydiBpbsWhdGFsw6FjaWEgYmFsw61rb3YgKGliYSByYXopCmluc3RhbGwucGFja2FnZXMoInpvbyIpCmluc3RhbGwucGFja2FnZXMoInRzZXJpZXMiKQppbnN0YWxsLnBhY2thZ2VzKCJsbXRlc3QiKQppbnN0YWxsLnBhY2thZ2VzKCJzYW5kd2ljaCIpCmluc3RhbGwucGFja2FnZXMoImNhciIpCgojIE5hxI3DrXRhbmllIGJhbMOta292CmxpYnJhcnkoem9vKQpsaWJyYXJ5KHRzZXJpZXMpCmxpYnJhcnkobG10ZXN0KQpsaWJyYXJ5KHNhbmR3aWNoKQpsaWJyYXJ5KGNhcikKYGBgCiMgUFLDjVBSQVZBIMOaREFKT1YKCipWIHRlanRvIMSNYXN0aSBzbWUgeiBkYXRhc2V0dSB2eWJyYWxpIHRyaSBkw7RsZcW+aXTDqSB1a2F6b3ZhdGVsZTogcG9wdWzDoWNpdSB2IHJva3UgMjAyMCwgcm96bG9odSBrcmFqaW55IGEgaHVzdG90dSBvYnl2YXRlxL5zdHZhLiBQcmV0b8W+ZSDDumRhamUgb2JzYWhvdmFsaSBjaMO9YmFqw7pjZSBob2Rub3R5LCBkb3BsbmlsaSBzbWUgaWNoIHBvbW9jb3UgbWVkacOhbnUsIGFieSBhbmFsw716YSBuZWJvbGEgc2tyZXNsZW7DoSBhbmkgcHJlcnXFoWVuw6EgTkEgaG9kbm90YW1pLiBOw6FzbGVkbmUgc21lIHbFoWV0a3kgcHJlbWVubsOpIHByZWtvbnZlcnRvdmFsaSBuYSDEjcOtc2VsbsO9IGZvcm3DoXQsIGFieSBzYSBkYWxpIMSPYWxlaiDFoXRhdGlzdGlja3kgc3ByYWNvdmHFpS4gVsO9c2xlZGtvbSBqZSDEjWlzdMO9IGEga29tcGxldG7DvSBkYXRhc2V0IHZob2Ruw70gbmEgbsOhc2xlZG7DqSByZWdyZXNuw6kgbW9kZWxvdmFuaWUuKgoKYGBge3J9CiMgTmHEjcOtdGFuaWUgZMOhdAp1ZGFqZSA8LSByZWFkLmNzdigid29ybGRfcG9wdWxhdGlvbi5jc3YiLCBkZWM9Ii4iLCBzZXA9IiwiLCBoZWFkZXIgPSBUUlVFKQoKIyBWw71iZXIgw7pkYWpvdiB6IHJva3UgMjAyMCAobmllIDIwMTUg4oCUIHBvZMS+YSB0dm9qaG8gZGF0YXNldHUpCiMgYSB2w71iZXIgcHJlbWVubsO9Y2gsIGt0b3LDqSBzaSBwb3XFvsOtdmFsYSB2IHByZWRvxaFsb20gY3ZpxI1lbsOtOgojIC0gMjAyMCBQb3B1bGF0aW9uCiMgLSBBcmVhIChrbTIpCiMgLSBEZW5zaXR5IChwZXIga20yKQoKdWRhamUuMjAyMCA8LSB1ZGFqZVssIGMoIlgyMDIwLlBvcHVsYXRpb24iLCAiQXJlYS4ua20uLiIsICJEZW5zaXR5Li5wZXIua20uLiIpXQoKIyBLb252ZXJ6aWEgbmEgbnVtZXJpY2vDqSBob2Rub3R5IChuaWVrdG9yw6kgbcO0xb51IGJ5xaUgYWtvIHRleHQpCnVkYWplLjIwMjAgPC0gYXMuZGF0YS5mcmFtZShsYXBwbHkodWRhamUuMjAyMCwgYXMubnVtZXJpYykpCmBgYAoKIyBJTVBVVMOBQ0lBIETDgVQg4oCTIERPUExORU5JRSBOQSBNRURJw4FOCgpgYGB7cn0KIyBWw71wb8SNZXQgbWVkacOhbm92IHByZSBrYcW+ZMO9IHN0xLpwZWMKY29sdW1uX21lZGlhbnMgPC0gc2FwcGx5KHVkYWplLjIwMjAsIG1lZGlhbiwgbmEucm0gPSBUUlVFKQoKIyBJbXB1dMOhY2lhCnVkYWplX2ltcHV0ZWQgPC0gdWRhamUuMjAyMApmb3IgKGNvbCBpbiBuYW1lcyh1ZGFqZS4yMDIwKSkgewogIHVkYWplX2ltcHV0ZWRbW2NvbF1dW2lzLm5hKHVkYWplX2ltcHV0ZWRbW2NvbF1dKV0gPC0gY29sdW1uX21lZGlhbnNbY29sXQp9CgojIEFrdHXDoWxuZSB1cHJhdmVuw70gZGF0YXNldAp1ZGFqZS4yMDIwIDwtIHVkYWplX2ltcHV0ZWQKdWRhamUgPC0gdWRhamUuMjAyMApgYGAKCiMgS09OVFJPTEEKCmBgYHtyfQpzdW1tYXJ5KHVkYWplKQpzdW0oaXMubmEodWRhamUpKQpgYGAKCiMgWsOBS0xBRE7DgSBSRUdSRVNJQSDigJMgVVBSQVZFTsOBIE5BIFdPUkxEIFBPUFVMQVRJT04gRMOBVEEKCipWIHJlZ3Jlc25vbSBtb2RlbGkgc21lIHNrw7ptYWxpLCBha28gcG9wdWzDoWNpYSBhIHJvemxvaGEga3JhamlueSBvdnBseXbFiHVqw7ogaHVzdG90dSBvYnl2YXRlxL5zdHZhLiBWw71zbGVka3kgdWthenVqw7osIMSNaSBleGlzdHVqZSBtYXRlbWF0aWNrw70gdnrFpWFoIG1lZHppIHZlxL5rb3PFpW91IHBvcHVsw6FjaWUsIMO6emVtw61tIGtyYWppbnkgYSB0w71tLCBrb8S+a28gxL51ZMOtIMW+aWplIG5hIGttwrIuIEtvZWZpY2llbnR5IG1vZGVsdSB1a2F6dWrDuiBzbWVyIGEgc2lsdSB0w71jaHRvIHZ6xaVhaG92LCBhIMWhdGF0aXN0aWNrw6EgdsO9em5hbW5vc8WlIChwLWhvZG5vdHkpIG5hem5hxI11amUsIMSNaSBzw7ogcHJlbWVubsOpIHNrdXRvxI1uZSBkw7RsZcW+aXTDvW1pIHByZWRpa3Rvcm1pLiBDZWxrb3ZvIG1vZGVsIHBvbcOhaGEgcG9jaG9wacWlLCBrdG9yw6kgZmFrdG9yeSBuYWp2aWFjIHByaXNwaWV2YWrDuiBrIGh1c3RvdGUgb2J5dmF0ZcS+c3R2YS4qCgpgYGB7cn0KYXR0YWNoKHVkYWplKQoKIyBMaW5lw6FybnkgbW9kZWw6IGh1c3RvdGEgYWtvIGZ1bmtjaWEgcG9wdWzDoWNpZSBhIHJvemxvaHkKbW9kZWwgPC0gbG0oRGVuc2l0eS4ucGVyLmttLi4gfiAxICsgWDIwMjAuUG9wdWxhdGlvbiArIEFyZWEuLmttLi4sIGRhdGEgPSB1ZGFqZSkKCnN1bW1hcnkobW9kZWwpCmBgYAoKCiMjIyAxLiBUZXN0IFJFU0VUICh0ZXN0IGNoeWJ5IMWhcGVjaWZpa8OhY2llIFJhbXNleWhvIHJlZ3Jlc25laiByb3ZuaWNlIC0gUmFtc2V5IFJlc2V0IFRlc3QpCgpNecWhbGllbmthOiBOZWNoIHDDtHZvZG7DvSBtb2RlbCBtw6EgdHZhcgokJHlfdCA9IFxiZXRhXzAgKyBcYmV0YV8xIHhfe3QxMH0gKyBcZG90cyArXGJldGFfayB4X3t0a30gKyB1X3QkJAokJHlfdCA9IFxiZXRhXzAgKyBcYmV0YV8xIHhfe3QxMH0gKyBcZG90cyArXGJldGFfayB4X3t0a30gKyBcZ2FtbWFfMlxoYXQgeV90XjIgKyBcZ2FtbWFfM1xoYXR7eX1fdF4zICsgdV90JCQKQnVkZW1lIHRlc3RvdmHFpSBoeXBvdMOpenUgCgokSF8wOiQgbW9kZWwgamUgc3Byw6F2bmUgxaFwZWNpZmlrb3ZhbsO9ICgkXGdhbW1hXzIgPSBcZ2FtbWFfMyA9IDAkKQoKb3Byb3RpCgokSF8xOiQgbW9kZWwgamUgbmVzcHLDoXZuZSDFoXBlY2lmaWtvdmFuw70gKCRcZ2FtbWFfMiBcbmUgMCAgXHF1YWQgXHRleHR7YWxlYm99ICBccXVhZCBcZ2FtbWFfMyBcbmUgMCQpCgpgYGB7cn0KIyBTdXBwb3NlIHlvdXIgbW9kZWwgaXM6Cm1vZGVsIDwtIGxtKERlbnNpdHkuLnBlci5rbS4uIH4gMSArIFgyMDIwLlBvcHVsYXRpb24gKyBBcmVhLi5rbS4uLCBkYXRhID0gdWRhamUpCgoKIyBSRVNFVCB0ZXN0IGZyb20gJ2xtdGVzdCcgcGFja2FnZToKbGlicmFyeShsbXRlc3QpCnJlc2V0dGVzdChtb2RlbCkKYGBgCgojIyMgSW50ZXJwcmV0w6FjaWEKKipOdWxsIGh5cG90w6l6YSAoSDApOioqIE1vZGVsIGplIHNwcsOhdm5lIMWhcGVjaWZpa292YW7DvSAobmVjaMO9YmFqw7ogbmVsaW5lw6FybmUgdnrFpWFoeSBhbmkgZMO0bGXFvml0w6kgcHJlbWVubsOpKS4KCioqQWx0ZXJuYXTDrXZuYSBoeXBvdMOpemEgKEgxKToqKiBNb2RlbCBqZSBuZXNwcsOhdm5lIMWhcGVjaWZpa292YW7DvSAoY2jDvWJhasO6IHByZW1lbm7DqSBhbGVibyBuZWxpbmXDoXJuZSB2esWlYWh5KS4KCioqcC12YWx1ZSA9IDAuMjUwNyDihpIqKiB2ecWhxaFpZSBha28gYmXFvm7DuiBobGFkaW51IHbDvXpuYW1ub3N0aSAobmFwci4gMC4wNSkuCgoqUkVTRVQgdGVzdCBvdmVydWplLCDEjWkgamUgbW9kZWwgc3Byw6F2bmUgxaFwZWNpZmlrb3ZhbsO9LCB0ZWRhIMSNaSBtdSBuZWNow71iYWrDuiBkw7RsZcW+aXTDqSBwcmVtZW5uw6kgYWxlYm8gbmVsaW5lw6FybmUgdnrFpWFoeS4gViBuYcWhb20gcHLDrXBhZGUgamUgcC1ob2Rub3RhIDAuMjUsIMSNbyB6bmFtZW7DoSwgxb5lIG5lbcOhbWUgZMO0a2F6IG8gbmVzcHLDoXZuZWogxaFwZWNpZmlrw6FjaWkuIE1vZGVsIERlbnNpdHkgfiBQb3B1bGF0aW9uICsgQXJlYSBqZSB0ZWRhIHZob2Ruw70gYSBuaWUgamUgcG90cmVibsOpIHByaWTDoXZhxaUgxI9hbMWhaWUgxI1sZW55LioKCgoKIyMjIDIuIEdyYWZpY2vDoSBhbmFsw716YQoKIyMjIyBHcmFmICpSZXNpZHVhbHMgdnMuIEZpdHRlZCoKYGBge3J9CnBsb3QobW9kZWwsIHdoaWNoID0gMSkKYGBgCgojIyMjIEdyYWZ5IEMrUiAqKgokJHlfdCA9IFxiZXRhXzAgKyBcYmV0YV8xIHhfe3QxfSArIFxkb3RzICtcYmV0YV9rIHhfe3RrfSArIHVfdCQkClTDunRvIHJvdm5pY3UgbmFqcHJ2IG9kaGFkbmVtZSBhIHBvdG9tIHZ5a3Jlc8S+dWplbWUgZ3JhZnksIGtkZSB2w71yYXogY29tcG9uZW50K3Jlc2lkdWFsIChDK1IpIHBsb3QgdnlrcmVzxL51amUgbmEgenZpc2xlaiBvc2kgJFxoYXR7XGJldGF9X2l4X3t0aX0rZV90JCBhIG5hIHZvZG9yb3ZuZWogb3NpIHZ5a3Jlc8S+dWplIGhvZG5vdHkgJHhfe3RpfSQKYGBge3J9CmNhcjo6Y3JQbG90cyhtb2RlbCkKYGBgCgojIyMgR3JhZiDigJMgMjAyMCBQb3B1bGF0aW9uCgoqVsOkxI3FoWluYSBib2RvdiBqZSB2ZcS+bWkgYmzDrXprbyBvc2kgMCog4oaSIHBvcHVsw6FjaWEgdsOkxI3FoWlueSBrcmFqw61uL8O6emVtw60gamUgcmVsYXTDrXZuZSBuw616a2EgKHYgcG9yb3ZuYW7DrSBzIGV4dHLDqW1hbWkpLgoKTmlla2/EvmtvIHZ6ZGlhbGVuw71jaCBib2RvdiAob3V0bGllcm92KSBwcmVkc3RhdnVqZSB2ZcS+bWkgdmXEvmvDqSBwb3B1bMOhY2llLgoKKkZpYWxvdsOhIMSNaWFyYSAobGluZcOhcm55IG1vZGVsKSBtaWVybmUgc3TDunBhKiDihpIgbW9kZWwgcHJlZHBva2xhZMOhIHBveml0w612bnUsIGFsZSBzbGFiw7ogbGluZcOhcm51IHrDoXZpc2xvc8WlLgoKKk1vZHLDoSBMT0VTUyBrcml2a2EgamUgdGFrbWVyIHBsb2Now6EqIOKGkiBza3V0b8SNbsO9IG5lbGluZcOhcm55IHRyZW5kIGplIHByYWt0aWNreSBudWxvdsO9LgoKIyMjIyBJbnRlcnByZXTDoWNpYToKUG9wdWzDoWNpYSBuZW3DoSB2w71yYXpuw70gbGluZcOhcm55IGFuaSBuZWxpbmXDoXJueSBlZmVrdCBuYSBodXN0b3R1IG9ieXZhdGXEvnN0dmEgdiB0b210byBtb2RlbGkuCk91dGxpZXJ5IG3DtMW+dSBza3Jlc8S+b3ZhxaUgZml0LgoKCiMjIyBHcmFmIOKAkyBBcmVhIChrbcKyKQoKU2l0dcOhY2lhIGplIHBvZG9ibsOhIOKAkyB2w6TEjcWhaW5hIMO6emVtw60gbcOhIG1hbMO6IHJvemxvaHUsIHDDoXIgZXh0csOpbW5lIHZlxL5rw71jaCDFoXTDoXRvdiB2eXR2w6FyYSBvdXRsaWVyeS4KCipMaW5lw6FybnkgbW9kZWwgKGZpYWxvdsOhIMSNaWFyYSkgbWllcm5lIGtsZXPDoSog4oaSIHbDpMSNxaFpYSByb3psb2hhIG3DtMW+ZSBzw7p2aXNpZcWlIHMgbmnFvsWhb3UgaHVzdG90b3UuCgoqTE9FU1MgKG1vZHLDoSBrcml2a2EpKiBqZSB0aWXFviBtaWVybmUga2xlc2Fqw7pjYSwgYWxlIHRha21lciBwbG9jaMOhLgoKIyMjIyBJbnRlcnByZXTDoWNpYToKUm96bG9oYSBtw6Egc2xhYsO9IG5lZ2F0w612bnkgdnrFpWFoIHMgaHVzdG90b3UsIMSNbyBqZSBsb2dpY2t5IG/EjWFrw6F2YW7DqSwgYWxlIHrDoXZpc2xvc8WlIGplIHZlxL5taSBzbGFiw6EuCk5lbGluZcOhcm55IGVmZWt0IHNhIHByYWt0aWNreSBuZXByZWphdnVqZS4KCgojIyAzLiBOZWxpbmXDoXJuYSDFoXBlY2lmaWvDoWNpYQokJHlfdCA9IFxiZXRhXzAgKyBcYmV0YV8xIHhfe3QxMH0gKyBcZG90cyArXGJldGFfayB4X3t0a30gKyBcZG90cyArIFxnYW1tYV9pXGhhdCB4X3tpa31eMiArIFxkb3RzICsgXGdhbW1hX2pcaGF0IHhfe2prfV4yICsgXGRvdHMgKyB1X3QkJApgYGB7cn0KCm1vZGVsIDwtIGxtKERlbnNpdHkuLnBlci5rbS4uIH4gWDIwMjAuUG9wdWxhdGlvbiArIEFyZWEuLmttLi4sIGRhdGEgPSB1ZGFqZSkKCm1vZGVsX2t2YWRyIDwtIGxtKERlbnNpdHkuLnBlci5rbS4uIH4gCiAgICAgICAgICAgICAgICAgICAgWDIwMjAuUG9wdWxhdGlvbiArIEFyZWEuLmttLi4gKwogICAgICAgICAgICAgICAgICAgIEkoWDIwMjAuUG9wdWxhdGlvbl4yKSArIEkoQXJlYS4ua20uLl4yKSwKICAgICAgICAgICAgICAgICAgZGF0YSA9IHVkYWplKQoKc3VtbWFyeShtb2RlbF9rdmFkcikKCmFub3ZhKG1vZGVsLCBtb2RlbF9rdmFkcikKCmxpYnJhcnkobG10ZXN0KQpyZXNldHRlc3QobW9kZWxfa3ZhZHIpCmBgYAoqS3ZhZHJhdGlja8O9IHJlZ3Jlc27DvSBtb2RlbCB1a8OhemFsLCDFvmUgxb5pYWRuYSB6IHByZW1lbm7DvWNoIChwb3B1bMOhY2lhLCByb3psb2hhIGFuaSBpY2gga3ZhZHJhdGlja8OpIMSNbGVueSkgbmllIGplIMWhdGF0aXN0aWNreSB2w716bmFtbsO9bSBwcmVkaWt0b3JvbSBodXN0b3R5IG9ieXZhdGXEvnN0dmEuIEhvZG5vdGEgUsKyIHRha21lciBudWxvdsOhIGEgesOhcG9ybsOpIHVwcmF2ZW7DqSBSwrIgcG90dnJkenVqw7osIMW+ZSBtb2RlbCBuZWRva8Ohxb5lIHZ5c3ZldGxpxaUgdmFyaWFiaWxpdHUgaHVzdG90eS4gQU5PVkEgdGVzdCB1a8OhemFsLCDFvmUgcHJpZGFuaWUga3ZhZHJhdGlja8O9Y2ggxI1sZW5vdiBtb2RlbCBuZXpsZXDFoXVqZS4gUkVTRVQgdGVzdCBzw61jZSBuZW5hem5hxI1pbCBjaHlibsO6IMWhcGVjaWZpa8OhY2l1IG1vZGVsdSwgbm8gc2Ftb3Ruw70gbW9kZWwgamUgcHJlIHByZWRpa2NpdSBodXN0b3R5IG5ldmhvZG7DvS4qCgpgYGB7cn0KbW9kZWxfa3ZhZHIgPC0gbG0oRGVuc2l0eS4ucGVyLmttLi4gfiBYMjAyMC5Qb3B1bGF0aW9uICsgQXJlYS4ua20uLiArIEkoWDIwMjAuUG9wdWxhdGlvbl4yKSwgCiAgICAgICAgICAgICAgICAgIGRhdGEgPSB1ZGFqZSkKCnN1bW1hcnkobW9kZWxfa3ZhZHIpCmBgYAoqUmV6aWR1w6EgbWFqw7ogdmXEvm1pIMWhaXJva8O9IHJvenNhaCwgcHJpxI1vbSBtYXhpbXVtIHbDvXJhem5lIHByZXZ5xaF1amUgb3N0YXRuw6kgaG9kbm90eSwgxI1vIG5hem5hxI11amUgcHLDrXRvbW5vc8WlIGV4dHLDqW1ueWNoIG9kxL5haGzDvWNoIHBvem9yb3ZhbsOtIHYgZMOhdGFjaC4gxb1pYWRueSB6IGtvZWZpY2llbnRvdiB2eXN2ZXTEvnVqw7pjaWNoIHByZW1lbm7DvWNoIG5pZSBqZSDFoXRhdGlzdGlja3kgdsO9em5hbW7DvSAocC1ob2Rub3R5IHPDuiB2eXNva28gbmFkIDAuMDUpLCB0YWvFvmUgcG9wdWzDoWNpYSwgcm96bG9oYSBhbmkga3ZhZHJhdGlja8O9IMSNbGVuIHBvcHVsw6FjaWUgbmV2eXN2ZXTEvnVqw7ogaHVzdG90dSBvYnl2YXRlxL5zdHZhLiBWZcS+bWkgbsOtemtlIFLCsiBhIHrDoXBvcm7DqSB1cHJhdmVuw6kgUsKyIHVrYXp1asO6LCDFvmUgbW9kZWwgcHJha3RpY2t5IG5lZG9rw6HFvmUgemFjaHl0acWlIHZhcmlhYmlsaXR1IHrDoXZpc2xlaiBwcmVtZW5uZWogYSBqZSBtZW5laiB2aG9kbsO9IG5lxb4gdHJpdmnDoWxueSBtb2RlbCBiZXogcHJlZGlrdG9yb3YuICoqTsOtemthIGhvZG5vdGEgRi3FoXRhdGlzdGlreSBhIHZ5c29rw6EgcC1ob2Rub3RhIHBvdHZyZHp1asO6LCDFvmUgbW9kZWwgYWtvIGNlbG9rIG5pZSBqZSDFoXRhdGlzdGlja3kgdsO9em5hbW7DvSoqLioKCiMjIyA1LiBQb3XFvml0aWUgcm96xaHDrXJlbsOpaG8gUkVTRVQgdGVzdHUKYGBge3J9Cm1vZGVsX3JvenNpcmVueSA8LSBsbShEZW5zaXR5Li5wZXIua20uLiB+IAogICAgICAgICAgICAgICAgICAgICAgICBYMjAyMC5Qb3B1bGF0aW9uICsgCiAgICAgICAgICAgICAgICAgICAgICAgIEFyZWEuLmttLi4gKyAKICAgICAgICAgICAgICAgICAgICAgICAgSShYMjAyMC5Qb3B1bGF0aW9uXjIpICsgCiAgICAgICAgICAgICAgICAgICAgICAgIEkoQXJlYS4ua20uLl4yKSwKICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSB1ZGFqZSkKCnN1bW1hcnkobW9kZWxfcm96c2lyZW55KQpgYGAKYGBge3J9CmFub3ZhKG1vZGVsLG1vZGVsX3JvenNpcmVueSkKcmVzZXR0ZXN0KG1vZGVsX3JvenNpcmVueSkKYGBgCiMjIyA2LiBUcmFuc2Zvcm3DoWNpYSBwb21vY291IGR1bW15IHByZW1lbm5laiBhIGxpbmXDoXJuZWogbG9tZW5laiBmdW5rY2llCjEuIHpsb20gdiBhdXRvbsOzbW5vbSDEjWxlbmUgJFxiZXRhXzAkIGEgdG8gbmFzbGVkb3Zub3UgxaFwZWNpZmlrw6FjaW91CiQkeV90ID0gXGJldGFfMCArIFxiZXRhX0QgRCsgXGJldGFfMSB4X3t0MX0gKyBcZG90cyArXGJldGFfayB4X3t0a30gKyB1X3QkJArEjW8gaW50ZXJwcmV0dWplbWUgYWtvIHBvc3VuIHJlZ3Jlc25laiBwcmlhbWt5IChyZWdyZXNuZWogbmFkcm92aW55KSBvICRcYmV0YV9EJCBqZWRub3RpZWsgcG96ZMS6xb4genZpc2xlaiBvc2kgYSB0byBsZW4gdiBwb3pvcm92YW5pYWNoLCBhayBqZSBzcGxuZW7DoSBwb2RtaWVua2EgJERfdCA9IDEkCjIuIHpsb20gdiBza2xvbmUgcmVncmVzbmVqIHByaWFta3kgKG5hZHJvdmlueSkgYSB0byBsZW4gdiBwb3pvcm92YW5pYWNoLCBhayBqZSBzcGxuZW7DoSBwb2RtaWVua2EgJERfdCA9IDEkLCDEjW8gZG9zaWFobmVtZSBuYXNsZWRvdm5vdSDFoXBlY2lmaWvDoWNpb3UKJCR5X3QgPSBcYmV0YV8wICsgIFxiZXRhXzEgeF97dDF9ICsgXGRvdHMgKyBcYmV0YV97aX14X3t0aX0gKyBcYmV0YV97RGl9RF90eF97dGl9KyBcZG90cyArIFxiZXRhX2sgeF97dGt9ICsgdV90JCQKa2RlIHRlZGEgc2tsb24gcHJpYW1reSBwb3pkxLrFviBwcmVtZW5uZSAkeF97dGl9JCBqZSAkXGJldGFfaSQgYWxlIGxlbiB2IHByw61wYWRlICREX3Q9MCQsIGluYWsgamUgdGVuIHNrbG9uIHJvdm7DvSAkXGJldGFfaStcYmV0YV97RF9pfSQuCgpgYGB7cn0KIyBEdW1teSBwcmVtZW5uw6EgcG9kxL5hIHBvcHVsw6FjaWUg4oCTIG7DrXprYSB2cy4gdnlzb2vDoSBwb3B1bMOhY2lhIAp1ZGFqZSREVU0gPC0gaWZlbHNlKHVkYWplJFgyMDIwLlBvcHVsYXRpb24gPCBtZWRpYW4odWRhamUkWDIwMjAuUG9wdWxhdGlvbiwgbmEucm0gPSBUUlVFKSwgCiAgICAgICAgICAgICAgICAgICAgMCwgMSkKCiMgTGluZcOhcm55IG1vZGVsIHMgZHVtbXkgcHJlbWVubm91Cm1vZGVsRF9hdXRvIDwtIGxtKERlbnNpdHkuLnBlci5rbS4uIH4gRFVNICsgWDIwMjAuUG9wdWxhdGlvbiArIEFyZWEuLmttLi4sIGRhdGEgPSB1ZGFqZSkKCnN1bW1hcnkobW9kZWxEX2F1dG8pCmBgYAoqTW9kZWwgdWthenVqZSwgxb5lIMW+aWFkbmEgeiBwcmVtZW5uw71jaCDigJMgYW5pIGR1bW15IHByZW1lbm7DoSwgcG9wdWzDoWNpYSDEjWkgcm96bG9oYSDigJMgbmllIGplIMWhdGF0aXN0aWNreSB2w716bmFtbsO9bSBwcmVkaWt0b3JvbSBodXN0b3R5IG9ieXZhdGXEvnN0dmEuIEhvZG5vdHkgUsKyIGFqIHVwcmF2ZW7DqWhvIFLCsiBzw7ogdGFrbWVyIG51bG92w6ksIMSNbyB6bmFtZW7DoSwgxb5lIG1vZGVsIG5lZG9rw6HFvmUgdnlzdmV0bGnFpSB2YXJpYWJpbGl0dSBkw6F0LiBJbnRlcmNlcHQgamUgamVkaW7DvSB2w716bmFtbsO9IHBhcmFtZXRlciwgxI1vIG5hem5hxI11amUsIMW+ZSB2eXN2ZXTEvnVqw7pjZSBwcmVtZW5uw6kgbmVwcmlzcGlldmFqw7ogayBwcmVkaWtjaWkgbmFkIHLDoW1lYyBwcmllbWVybmVqIGhvZG5vdHkuIENlbGtvdm8gbW9kZWwgYWtvIGNlbG9rIG9ww6TFpSBuaWUgamUgxaF0YXRpc3RpY2t5IHbDvXpuYW1uw70sIMSNbyBwb3R2cmR6dWplIGFqIHZ5c29rw6EgcC1ob2Rub3RhIEYtxaF0YXRpc3Rpa3kuKgoKYGBge3J9CiMgUHLDrWtsYWQ6IHByZWRpa2NpYSBEZW5zaXR5IG5hIHrDoWtsYWRlIFBvcHVsYXRpb24gYSBBcmVhCm1vZGVsRF9za2xvbiA8LSBsbShEZW5zaXR5Li5wZXIua20uLiB+IFgyMDIwLlBvcHVsYXRpb24gKyBBcmVhLi5rbS4uLCBkYXRhPXVkYWplKQpzdW1tYXJ5KG1vZGVsRF9za2xvbikKYGBgCipNb2RlbCBzYSBzbmHFvmlsIHByZWRpa292YcWlIGh1c3RvdHUgb2J5dmF0ZcS+c3R2YSAoRGVuc2l0eS4ucGVyLmttLi4pIG5hIHrDoWtsYWRlIHBvcHVsw6FjaWUgKFgyMDIwLlBvcHVsYXRpb24pIGEgcm96bG9oeSAoQXJlYS4ua20uLikuIEhvZG5vdHkga29lZmljaWVudG92IHVrYXp1asO6LCDFvmUgYW5pIHBvcHVsw6FjaWEsIGFuaSByb3psb2hhIG5lbWFqw7ogxaF0YXRpc3RpY2t5IHbDvXpuYW1uw70gdnBseXYgbmEgaHVzdG90dSAocC1ob2Rub3R5IDAuOTgxIGEgMC4zODcsIHRlZGEgdmXEvm1pIHZ5c29rbykuIE7DrXprZSBSLXNxdWFyZWQgKDAuMDA0KSB6bmFtZW7DoSwgxb5lIG1vZGVsIHZ5c3ZldMS+dWplIGxlbiB2ZcS+bWkgbWFsw7ogxI1hc8WlIHZhcmlhYmlsaXR5IGh1c3RvdHksIHByYWt0aWNreSB6YW5lZGJhdGXEvm7Dui4gQ2Vsa292byB0ZWRhIHRlbnRvIGxpbmXDoXJueSBtb2RlbCBuaWUgamUgdmhvZG7DvSBuYSBwcmVkaWtjaXUgaHVzdG90eSBvYnl2YXRlxL5zdHZhIHogdMO9Y2h0byBwcmVtZW5uw71jaC4qCgpgYGB7cn0KYW5vdmEobW9kZWwsIG1vZGVsRF9za2xvbikKcmVzZXR0ZXN0KG1vZGVsRF9za2xvbikKYGBgCipWIGtvbWJpbsOhY2lpIHMgcHJlZGNow6FkemFqw7pjaW0gc3VtbWFyeSgpLCBrZGUgbW9kZWwgdnlzdmV0xL5vdmFsIGxlbiB6YW5lZGJhdGXEvm7DuiDEjWFzxaUgdmFyaWFiaWxpdHkgKFLCsiDiiYggMC4wMDQpLCB0byB6bmFtZW7DoTogbW9kZWwgamUgbGluZcOhcm5lICoqc3Byw6F2bmUgxaFwZWNpZmlrb3ZhbsO9KiosIGFsZSBqZSAqKnByYWt0aWNreSBuZXBvdcW+aXRlxL5uw70qKiwgcHJldG/FvmUgcHJlZGlrdG9yeSBwb3B1bMOhY2lhIGEgcm96bG9oYSB2ZcS+bWkgbmV2eXN2ZXTEvnVqw7ogaHVzdG90dS4qCgojIyMgNy4gQm94LUNveG92IHRyYW5zZm9ybWHEjW7DvSB0ZXN0CmBgYHtyfQpsaWJyYXJ5KE1BU1MpCmJveGNveChtb2RlbCkKYGBgCipaIHRvaHRvIGdyYWZ1IHZ5cGzDvXZhLCDFvmUgbmFqcHJhdmRlcG9kb2JuZWrFoWlhIGhvZG5vdGEgcGFyYW1ldHJhIM67IGJvbGEgw7pzcGXFoW5lIG9kaGFkbnV0w6EgcG9tb2NvdSBtZXTDs2R5IG1heGltw6FsbmVqIHZpZXJvaG9kbm9zdGkgKE1MRSkuIEludGVydmFsIHNwb8S+YWhsaXZvc3RpIG9rb2xvIHRlanRvIGhvZG5vdHkgbsOhbSB1a2F6dWplLCB2IGFrb20gcm96c2FodSBzYSBzIHZ5c29rb3UgaXN0b3RvdSAobmFwci4gOTUgJSkgbmFjaMOhZHphIHNrdXRvxI1uw70gcGFyYW1ldGVyLiBUbyB6bmFtZW7DoSwgxb5lIG1vZGVsIGplIGRvYnJlIHByaXNww7Rzb2JlbsO9IGTDoXRhbSBhIG3DoW1lIGt2YW50aWZpa292YW7DuiBtaWVydSBuZWlzdG90eSBvaMS+YWRuZSBvZGhhZHUgzrsuKgoKYGBge3J9CiMgVHJhbnNmb3Jtw6FjaWEgesOhdmlzbGVqIHByZW1lbm5laiAobmFwci4gbW9jbmluYSAxLjgpCm1vZGVsX2xhbWJkYSA8LSBsbShJKChgRGVuc2l0eS4ucGVyLmttLi5gXjEuOCAtIDEpLzEuOCkgfiBgWDIwMjAuUG9wdWxhdGlvbmAgKyBgQXJlYS4ua20uLmAsIGRhdGEgPSB1ZGFqZSkKCiMgVsO9cGlzIHbDvXNsZWRrb3YgbW9kZWx1CnN1bW1hcnkobW9kZWxfbGFtYmRhKQoKIyBSRVNFVCB0ZXN0IHByZSBrb250cm9sdSDFoXBlY2lmaWvDoWNpZSBtb2RlbHUKbGlicmFyeShsbXRlc3QpCnJlc2V0dGVzdChtb2RlbF9sYW1iZGEpCmBgYAoqZlJFU0VUIHRlc3QgcyBwLWhvZG5vdG91IDAuNTUwNSBuYXpuYcSNdWplLCDFvmUgbGluZcOhcm55IHR2YXIgbW9kZWx1IGplIMWhdGF0aXN0aWNreSBzcHLDoXZuZSDFoXBlY2lmaWtvdmFuw70gYSBuaWUgamUgZMO0a2F6IHBvdHJlYnkgbmVsaW5lw6FybnljaCB0cmFuc2Zvcm3DoWNpw60gcHJlZGlrdG9yb3YuKgoKCgoKCgoKCgoKCgoKCgoK