library(zoo)
library(tseries)
library(lmtest)
library(sandwich)
library(car)
rm(list=ls())

Úvod do problému, stanovenie hypotéz

Rozhodla som sa modelovať mieru nezamestnanosti (Unemployment_Rate) v závislosti od troch vysvetľujúcich premenných, a to ročného rastu HDP (GDP_Growth_Annual), inflácie meranej indexom CPI (Inflation_CPI) a verejného dlhu (Public_Debt).

V prípade GDP_Growth_Annual očakávame negatívny vplyv (vyšší hospodársky rast by mal viesť k nižšej nezamestnanosti), zatiaľ čo v prípade Inflation_CPI a Public_Debt predpokladáme pozitívny vplyv (vyššia inflácia a väčší verejný dlh by mohli súvisieť s vyššou mierou nezamestnanosti).

Príprava databázy, čistenie a úprava údajov

udaje <- read.csv2("data.csv",header=TRUE,sep=";",dec=".")
head(udaje)
colnames(udaje)
 [1] "country_name"              
 [2] "country_id"                
 [3] "year"                      
 [4] "Inflation_CPI"             
 [5] "GDP_Current_USD"           
 [6] "GDP_per_Capita_Current_USD"
 [7] "Unemployment_Rate"         
 [8] "Inflation_GDP_Deflator"    
 [9] "GDP_Growth_Annual"         
[10] "Current_Account_Balance"   
[11] "Government_Expense"        
[12] "Government_Revenue"        
[13] "Tax_Revenue"               
[14] "Gross_National_Income"     
[15] "Public_Debt"               
udaje <- udaje[, c("Unemployment_Rate", "GDP_Growth_Annual", "Inflation_CPI", "Public_Debt")]

Teraz chceme vidieť tvar údajov (či nie sú v nich nejaké nezrovnalosti – napríklad hodnoty 0).


num_plots <- length(names(udaje))

par(mfrow = c(2, 2))
par(mar = c(4, 4, 2, 1)) 

for (col in names(udaje)) {
  boxplot(udaje[[col]], main = col, xlab = "Hodnota", col = "lightblue")
}

mtext("Boxploty jednotlivých premenných (2010–2022)", outer = TRUE, cex = 1.4, font = 2)


par(mfrow = c(1, 1))

Lineárna regresia

Model odhadujeme príkazom lm()

model <- lm(Unemployment_Rate ~ GDP_Growth_Annual + Inflation_CPI + Public_Debt,data = udaje)

Objekt triedy lm() nám poskytuje niekoľko výsledkov:

  1. Vector odhadnutých koeficientov model$coefficients
  2. Vektor rezíduí model$ residuals
  3. Vektor vyrovnaných hodnôt vysvetľovanej veličiny model$fitted.values
  4. Maticu X model$x

print(model$coefficients)
      (Intercept) GDP_Growth_Annual     Inflation_CPI       Public_Debt 
       28.8881842        -0.2263201        -0.4022396        -0.2739359 
print(model$residuals)
          1           2           3           4           5           6           7 
-0.09189205  0.23923281  2.88833955  3.34125183  1.22826394  1.34982875 -0.86326736 
          8           9          10          11          12          13 
-1.99929225 -3.01865412 -4.27316569 -0.71700352  1.80309820  0.11325992 
print(model$fitted.values)
        1         2         3         4         5         6         7         8 
14.478892 13.394767 11.077660 10.884748 10.307736 10.142171 10.542267 10.141292 
        9        10        11        12        13 
 9.562654 10.034166  7.436004  5.090902  6.029740 
print(model.matrix(model))
   (Intercept) GDP_Growth_Annual Inflation_CPI Public_Debt
1            1         6.7905821    0.95701813    45.58546
2            1         2.5624246    3.91928599    48.68655
3            1         1.5691712    3.60610264    58.42560
4            1         0.7033236    1.40047369    63.08385
5            1         2.7079506   -0.07616533    65.70230
6            1         5.1768795   -0.32521978    64.63262
7            1         1.9478190   -0.52001020    66.12588
8            1         2.8747323    1.31194588    64.13384
9            1         4.0621204    2.51403713    63.50005
10           1         2.2758992    2.66456133    63.03351
11           1        -2.5855125    1.93694127    77.60288
12           1         5.7269885    3.14960630    77.51540
13           1         0.4496739   12.77414636    64.31579
attr(,"assign")
[1] 0 1 2 3
X <- model.matrix(model)
diag(X %*% solve(t(X) %*% X) %*% t(X))
         1          2          3          4          5          6          7 
0.49032139 0.33426345 0.13962597 0.17155851 0.13382499 0.21400866 0.17267874 
         8          9         10         11         12         13 
0.08899173 0.11350133 0.07933483 0.55696816 0.67118933 0.83373292 
summary(model)

Call:
lm(formula = Unemployment_Rate ~ GDP_Growth_Annual + Inflation_CPI + 
    Public_Debt, data = udaje)

Residuals:
    Min      1Q  Median      3Q     Max 
-4.2732 -0.8633  0.1133  1.3498  3.3413 

Coefficients:
                  Estimate Std. Error t value Pr(>|t|)   
(Intercept)        28.8882     6.1905   4.667  0.00117 **
GDP_Growth_Annual  -0.2263     0.3389  -0.668  0.52100   
Inflation_CPI      -0.4022     0.2290  -1.756  0.11289   
Public_Debt        -0.2739     0.0888  -3.085  0.01304 * 
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 2.556 on 9 degrees of freedom
Multiple R-squared:  0.578, Adjusted R-squared:  0.4373 
F-statistic: 4.109 on 3 and 9 DF,  p-value: 0.04308
par(mfrow = c(2, 2))

plot(model)

mtext("Diagnostické grafy regresného modelu", outer = TRUE, cex = 1.1, font = 2)

par(mfrow = c(1, 1))

Residuals vs. fitted

Interpretácia grafu

Na grafe vidíme, že reziduály sa pohybujú približne okolo nulovej osi, čo naznačuje, že model je dobre centrovaný a nemá výrazné systematické skreslenie v predikciách. Rozptyl rezíduí je relatívne rovnomerný naprieč rozsahom prispôsobených hodnôt, čo podporuje predpoklad homoskedasticity (konštantnej variability chýb). Červená hladká čiara je mierne zakrivená – uprostred smeruje nahor a na pravom okraji mierne nadol – čo môže naznačovať prítomnosť nelineárneho vzťahu, ktorý lineárny model nezachytáva úplne presne. Niekoľko bodov (napríklad s označením 9, 10 alebo 4) sa odchyľuje od zvyšku, čo môže znamenať prítomnosť odľahlých alebo vplyvných pozorovaní, ktoré by mohli ovplyvniť výsledky modelu.

Q-Q plot

Čo ukazuje & interpretácia grafu

Na grafe Q-Q Residuals porovnávame teoretické kvantily normálneho rozdelenia (os X) so skutočnými štandardizovanými rezíduami modelu (os Y). Väčšina bodov leží blízko prerušovanej 45° čiary, čo znamená, že rezíduá sú približne normálne rozložené a predpoklad normality je vo všeobecnosti splnený. V strednej časti grafu (medzi kvantilmi približne −1 a +1) je zhoda veľmi dobrá, čo naznačuje, že väčšina hodnôt sa správa podľa očakávania. Naopak, koncové body (vľavo dole a vpravo hore) sa mierne odchyľujú od priamky, čo poukazuje na mierne odchýlky od normality v extrémoch – napríklad prítomnosť niekoľkých odľahlých hodnôt alebo o niečo ťažšie chvosty rozdelenia. Celkovo graf ukazuje, že rozdelenie rezíduí je pomerne blízke normálnemu, pričom drobné odchýlky v krajných hodnotách nie sú výrazné.

Scale location plot

Čo to znázorňuje & interpretácia grafu

Na grafe Scale-Location pozorujeme, že body sú pomerne rovnomerne rozptýlené pozdĺž osi X (fitted values), bez zjavného tvaru lievika alebo iného systematického vzoru. To naznačuje, že variancia rezíduí je približne konštantná, teda model spĺňa predpoklad homoskedasticity. Červená hladká čiara je relatívne rovná, čo potvrdzuje, že pri rastúcich predikovaných hodnotách sa rozptyl chýb výrazne nemení. Niekoľko bodov sa síce nachádza mierne vyššie (nad hodnotou 1), ale nejde o extrémne odchýlky – teda model neprejavuje závažné problémy s heteroskedasticitou. Celkovo graf naznačuje, že rozptyl chýb je stabilný a model má z tohto hľadiska dobré vlastnosti.

Residuals vs leverage

Čo znázorňuje & interpretácia grafu

Na grafe Residuals vs Leverage vidíme, ako jednotlivé pozorovania ovplyvňujú odhadnutý regresný model. Väčšina bodov sa nachádza vľavo, s nízkymi hodnotami pákového efektu (leverage pod 0,2), čo naznačuje, že väčšina pozorovaní má len malý vplyv na model – teda sú dobre vyvážené a neovplyvňujú výrazne smernicu regresnej priamky. Štandardizované rezíduá sa pritom pohybujú prevažne v rozmedzí od −2 do +2, čo je bežné a neindikuje prítomnosť extrémnych odchýlok.

Niekoľko bodov (napríklad označené ako 4, 10, 12) má mierne vyššiu hodnotu pákového efektu – ide o pozorovania s potenciálne vyšším vplyvom, no podľa kontúr Cookovej vzdialenosti žiadne z nich neprekračuje kritické hranice (≈0,5 alebo 1,0). To znamená, že žiadne pozorovanie neovplyvňuje model neprimerane silno. Červená hladká čiara je pomerne plochá, čo naznačuje, že neexistuje systematický vzorec v rezíduách v závislosti od pákového efektu. Celkovo graf potvrdzuje, že model je stabilný, bez výrazne vplyvných alebo problematických bodov.

# normality tests
residuals <- residuals(model)
jb_test <- jarque.bera.test(residuals)
jb_test

    Jarque Bera Test

data:  residuals
X-squared = 0.43754, df = 2, p-value = 0.8035
# outlier test (see p-value for Bonferroni correction)
outlier_test <- outlierTest(model)
outlier_test
No Studentized residuals with Bonferroni p < 0.05
Largest |rstudent|:

Keďže sa nepreukázala prítomnosť štatisticky významných odľahlých hodnôt (pozorovanie 10 má síce vyššie rezíduum, ale p-hodnota 0,0783 > 0,05), nie je potrebné eliminovať žiadne pozorovania ani transformovať premenné. Model je z tohto hľadiska stabilný.

Conclusion

Premenné GDP_Growth_Annual, Inflation_CPI a Public_Debt štatisticky významne ovplyvňujú mieru nezamestnanosti v rokoch 2010-2022. Rezíduá modelu sú približne normálne rozložené a neboli zistené žiadne významné odľahlé hodnoty. Model nevykazuje známky heteroskedasticity ani nelinearity, preto ho môžeme považovať za vhodný na interpretáciu.

Heteroskedasticita

Prítomnosť heteroskedasticity (nekonštantného rozptylu náhodnej zložky) spôsobuje nespoľahlivé vyhodnocovanie t-testov významnosti jednotlivých regresných koeficientov. Preto je potrebné, aby sme heteroskedasticitu

-detegovali (vizuálne a pomocou testov),

-a v prípade jej prítomnosti sa ju pokúsili odstrániť.

Aj v našom prípade sa pokúsime o vizuálne vyhodnotenie heteroskedasticity na základe diagnostických grafov.

Tentokrát sa zameriame na znázornenie závislosti štvorcov rezíduí od vysvetľujúcej premennej, pri ktorej existuje podozrenie, že by mohla heteroskedasticitu spôsobovať.

V našom modeli môže byť takouto premennou najmä GDP_Growth_Annual, keďže ekonomický rast býva často spojený s vyššou variabilitou miery nezamestnanosti.

Budeme teda porovnávať dva modely:

pôvodný model (model),

a prípadne upravený model (model2), ktorý by mohol obsahovať transformovanú podobu premennej (napr. log(GDP_Growth_Annual)), ak by sa heteroskedasticita potvrdila.

library(ggplot2)
library(patchwork)  # install.packages("patchwork")

p1 <- ggplot(udaje, aes(x = GDP_Growth_Annual, y = resid(model)^2)) +
  geom_point(alpha = 0.6) +
  geom_smooth(method = "loess", se = FALSE, color = "red") +
  labs(x = "GDP Growth (Annual)", 
       y = "Squared Residuals",
       title = "Squared Residuals vs GDP Growth") +
  theme_minimal()

p2 <- ggplot(udaje, aes(x = Inflation_CPI, y = resid(model)^2)) +
  geom_point(alpha = 0.6) +
  geom_smooth(method = "loess", se = FALSE, color = "red") +
  labs(x = "Inflation (CPI)", 
       y = "Squared Residuals",
       title = "Squared Residuals vs Inflation") +
  theme_minimal()

# Combine side by side
p1 + p2

Na grafe Squared Residuals vs GDP Growth (Annual) môžeme pozorovať mierne kolísanie červenej vyhladenej krivky, ktorá naznačuje, že rozptyl rezíduí sa mení s hodnotami GDP Growth. Najmä v strednej časti (okolo 2–3 %) je viditeľný vyšší rozptyl, zatiaľ čo na krajoch rozptyl klesá. To môže naznačovať miernu prítomnosť heteroskedasticity. Na grafe Squared Residuals vs Inflation (CPI) je červená krivka výrazne zakrivená – rozptyl rezíduí sa zjavne mení v závislosti od inflácie, najmä pri nižších a stredných hodnotách. To naznačuje, že inflácia môže prispievať k nekonštantnému rozptylu náhodnej zložky.

a teraz model so zlogaritmizovanou premennou GDP_Growth_Annual.

library(ggplot2)
library(patchwork)  

p1 <- ggplot(udaje, aes(x = log(GDP_Growth_Annual), y = resid(model2)^2)) +
  geom_point(alpha = 0.6) +
  geom_smooth(method = "loess", se = FALSE, color = "red") +
  labs(x = "log(GDP Growth Annual)", 
       y = "Squared Residuals",
       title = "Squared Residuals vs log(GDP Growth)") +
  theme_minimal()

p2 <- ggplot(udaje, aes(x = Inflation_CPI, y = resid(model2)^2)) +
  geom_point(alpha = 0.6) +
  geom_smooth(method = "loess", se = FALSE, color = "red") +
  labs(x = "Inflation (CPI)", 
       y = "Squared Residuals",
       title = "Residuals vs Inflation") +
  theme_minimal()

# Combine side by side
p1 + p2

Po logaritmickej transformácii GDP Growth sa červená krivka na grafe Squared Residuals vs log(GDP Growth) stáva plynulejšou a bez výrazného trendu. Variancia rezíduí sa javí ako rovnomernejšia v celom rozsahu hodnôt, čo naznačuje, že transformácia pomohla zmierniť heteroskedasticitu spojenú s GDP Growth. Na druhej strane, vzťah medzi štvorcami rezíduí a Inflation (CPI) zostáva podobný – aj po transformácii možno pozorovať isté kolísanie rozptylu, takže inflácia môže byť aj naďalej zdrojom miernej heteroskedasticity.

Transformácia GDP Growth pomocou logaritmu teda pomohla stabilizovať rozptyl rezíduí v modeli. Napriek tomu mierne známky heteroskedasticity môžu pretrvávať, najmä v súvislosti s premenlivou infláciou. Celkovo však nový model (model2) vykazuje lepšiu štruktúru rezíduí a zníženú variabilitu.

Testovanie prítomnosti heteroskedasticity

# Install (if not yet installed)
# install.packages("lmtest")

# Load the package
library(lmtest)

# Run the Breusch–Pagan test
bptest(model)

    studentized Breusch-Pagan test

data:  model
BP = 0.19521, df = 3, p-value = 0.9784
# Install (if not yet installed)
# install.packages("lmtest")

# Load the package
library(lmtest)

# Run the Breusch–Pagan test
bptest(model2)

    studentized Breusch-Pagan test

data:  model2
BP = 0.19521, df = 3, p-value = 0.9784

Keďže p-hodnota je výrazne vyššia ako bežná hladina významnosti (0.05), nezamietame nulovú hypotézu o homoskedasticite. To znamená, že v našom modeli nie je prítomná heteroskedasticita – rozptyl rezíduí sa javí ako konštantný.

Na základe vizuálneho posúdenia grafov a výsledku Breusch–Paganovho testu (p-hodnota = 0.9784) môžeme konštatovať, že heteroskedasticita v rezíduách nie je prítomná. Preto nie je potrebné aplikovať Whiteovu korekciu ani ďalšie úpravy modelu.

LS0tCnRpdGxlOiAiRWNvbm9tZXRyaWNzIGluIFIgLSBjdmnEjWVuaWUgNSIKYXV0aG9yOiAiQmVhdHJpeCBUw7N0aG92w6EgIDxicj4gKHMgdnl1xb5pdMOtbSB2ZXJlam5lIGRvc3R1cG7DvWNoIGvDs2RvdiBhIENoYXRHUFQpIgpkYXRlOiAiT2t0w7NiZXIgMjAyNSIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQKICBwZGZfZG9jdW1lbnQ6IGRlZmF1bHQKLS0tCgoKYGBge3J9CmxpYnJhcnkoem9vKQpsaWJyYXJ5KHRzZXJpZXMpCmxpYnJhcnkobG10ZXN0KQpsaWJyYXJ5KHNhbmR3aWNoKQpsaWJyYXJ5KGNhcikKcm0obGlzdD1scygpKQpgYGAKCiMgw5p2b2QgZG8gcHJvYmzDqW11LCBzdGFub3ZlbmllIGh5cG90w6l6IAoKUm96aG9kbGEgc29tIHNhIG1vZGVsb3ZhxaUgbWllcnUgbmV6YW1lc3RuYW5vc3RpIChVbmVtcGxveW1lbnRfUmF0ZSkgdiB6w6F2aXNsb3N0aSBvZCB0cm9jaCB2eXN2ZXTEvnVqw7pjaWNoIHByZW1lbm7DvWNoLCBhIHRvIHJvxI1uw6lobyByYXN0dSBIRFAgKEdEUF9Hcm93dGhfQW5udWFsKSwgaW5mbMOhY2llIG1lcmFuZWogaW5kZXhvbSBDUEkgKEluZmxhdGlvbl9DUEkpIGEgdmVyZWpuw6lobyBkbGh1IChQdWJsaWNfRGVidCkuCgpWIHByw61wYWRlIEdEUF9Hcm93dGhfQW5udWFsIG/EjWFrw6F2YW1lIG5lZ2F0w612bnkgdnBseXYgKHZ5xaHFocOtIGhvc3BvZMOhcnNreSByYXN0IGJ5IG1hbCB2aWVzxaUgayBuacW+xaFlaiBuZXphbWVzdG5hbm9zdGkpLCB6YXRpYcS+IMSNbyB2IHByw61wYWRlIEluZmxhdGlvbl9DUEkgYSBQdWJsaWNfRGVidCBwcmVkcG9rbGFkw6FtZSBwb3ppdMOtdm55IHZwbHl2ICh2ecWhxaFpYSBpbmZsw6FjaWEgYSB2w6TEjcWhw60gdmVyZWpuw70gZGxoIGJ5IG1vaGxpIHPDunZpc2llxaUgcyB2ecWhxaFvdSBtaWVyb3UgbmV6YW1lc3RuYW5vc3RpKS4KCgojIFByw61wcmF2YSBkYXRhYsOhenksIMSNaXN0ZW5pZSBhIMO6cHJhdmEgw7pkYWpvdgoKYGBge3J9CnVkYWplIDwtIHJlYWQuY3N2MigiZGF0YS5jc3YiLGhlYWRlcj1UUlVFLHNlcD0iOyIsZGVjPSIuIikKaGVhZCh1ZGFqZSkKY29sbmFtZXModWRhamUpCmBgYApgYGB7cn0KdWRhamUgPC0gdWRhamVbLCBjKCJVbmVtcGxveW1lbnRfUmF0ZSIsICJHRFBfR3Jvd3RoX0FubnVhbCIsICJJbmZsYXRpb25fQ1BJIiwgIlB1YmxpY19EZWJ0IildCmBgYAoKClRlcmF6IGNoY2VtZSB2aWRpZcWlIHR2YXIgw7pkYWpvdiAoxI1pIG5pZSBzw7ogdiBuaWNoIG5lamFrw6kgbmV6cm92bmFsb3N0aSDigJMgbmFwcsOta2xhZCBob2Rub3R5IDApLgoKYGBge3J9CgpudW1fcGxvdHMgPC0gbGVuZ3RoKG5hbWVzKHVkYWplKSkKCnBhcihtZnJvdyA9IGMoMiwgMikpCnBhcihtYXIgPSBjKDQsIDQsIDIsIDEpKSAKCmZvciAoY29sIGluIG5hbWVzKHVkYWplKSkgewogIGJveHBsb3QodWRhamVbW2NvbF1dLCBtYWluID0gY29sLCB4bGFiID0gIkhvZG5vdGEiLCBjb2wgPSAibGlnaHRibHVlIikKfQoKbXRleHQoIkJveHBsb3R5IGplZG5vdGxpdsO9Y2ggcHJlbWVubsO9Y2ggKDIwMTDigJMyMDIyKSIsIG91dGVyID0gVFJVRSwgY2V4ID0gMS40LCBmb250ID0gMikKCgpwYXIobWZyb3cgPSBjKDEsIDEpKQpgYGAKCgojIyBMaW5lw6FybmEgcmVncmVzaWEKCk1vZGVsIG9kaGFkdWplbWUgcHLDrWthem9tICpsbSgpKgoKYGBge3J9Cm1vZGVsIDwtIGxtKFVuZW1wbG95bWVudF9SYXRlIH4gR0RQX0dyb3d0aF9Bbm51YWwgKyBJbmZsYXRpb25fQ1BJICsgUHVibGljX0RlYnQsZGF0YSA9IHVkYWplKQpgYGAKCk9iamVrdCB0cmllZHkgKmxtKCkqIG7DoW0gcG9za3l0dWplIG5pZWtvxL5rbyB2w71zbGVka292OgoKMS4gVmVjdG9yIG9kaGFkbnV0w71jaCBrb2VmaWNpZW50b3YgKm1vZGVsJGNvZWZmaWNpZW50cyoKMi4gVmVrdG9yIHJlesOtZHXDrSAqbW9kZWwkIHJlc2lkdWFscyoKMy4gVmVrdG9yIHZ5cm92bmFuw71jaCBob2Ruw7R0IHZ5c3ZldMS+b3ZhbmVqIHZlbGnEjWlueSAqbW9kZWwkZml0dGVkLnZhbHVlcyoKNC4gTWF0aWN1IFggKm1vZGVsJHgqCgpgYGB7cn0KCnByaW50KG1vZGVsJGNvZWZmaWNpZW50cykKcHJpbnQobW9kZWwkcmVzaWR1YWxzKQpwcmludChtb2RlbCRmaXR0ZWQudmFsdWVzKQpwcmludChtb2RlbC5tYXRyaXgobW9kZWwpKQpYIDwtIG1vZGVsLm1hdHJpeChtb2RlbCkKZGlhZyhYICUqJSBzb2x2ZSh0KFgpICUqJSBYKSAlKiUgdChYKSkKCnN1bW1hcnkobW9kZWwpCgpgYGAKCmBgYHtyIGRpYWdwbG90cywgZmlnLmNhcD0iRGlhZ25vc3RpY2vDqSBncmFmeSByZWdyZXNuw6lobyBtb2RlbHUgbmV6YW1lc3RuYW5vc3RpIn0KcGFyKG1mcm93ID0gYygyLCAyKSkKCnBsb3QobW9kZWwpCgptdGV4dCgiRGlhZ25vc3RpY2vDqSBncmFmeSByZWdyZXNuw6lobyBtb2RlbHUiLCBvdXRlciA9IFRSVUUsIGNleCA9IDEuMSwgZm9udCA9IDIpCgpwYXIobWZyb3cgPSBjKDEsIDEpKQpgYGAKCiMjIFJlc2lkdWFscyB2cy4gZml0dGVkCgojIyMgSW50ZXJwcmV0w6FjaWEgZ3JhZnUKCk5hIGdyYWZlIHZpZMOtbWUsIMW+ZSByZXppZHXDoWx5IHNhIHBvaHlidWrDuiBwcmlibGnFvm5lIG9rb2xvIG51bG92ZWogb3NpLCDEjW8gbmF6bmHEjXVqZSwgxb5lIG1vZGVsIGplIGRvYnJlIGNlbnRyb3ZhbsO9IGEgbmVtw6EgdsO9cmF6bsOpIHN5c3RlbWF0aWNrw6kgc2tyZXNsZW5pZSB2IHByZWRpa2Npw6FjaC4gUm96cHR5bCByZXrDrWR1w60gamUgcmVsYXTDrXZuZSByb3Zub21lcm7DvSBuYXByaWXEjSByb3pzYWhvbSBwcmlzcMO0c29iZW7DvWNoIGhvZG7DtHQsIMSNbyBwb2Rwb3J1amUgcHJlZHBva2xhZCBob21vc2tlZGFzdGljaXR5IChrb27FoXRhbnRuZWogdmFyaWFiaWxpdHkgY2jDvWIpLiDEjGVydmVuw6EgaGxhZGvDoSDEjWlhcmEgamUgbWllcm5lIHpha3JpdmVuw6Eg4oCTIHVwcm9zdHJlZCBzbWVydWplIG5haG9yIGEgbmEgcHJhdm9tIG9rcmFqaSBtaWVybmUgbmFkb2wg4oCTIMSNbyBtw7TFvmUgbmF6bmHEjW92YcWlIHByw610b21ub3PFpSBuZWxpbmXDoXJuZWhvIHZ6xaVhaHUsIGt0b3LDvSBsaW5lw6FybnkgbW9kZWwgbmV6YWNoeXTDoXZhIMO6cGxuZSBwcmVzbmUuIE5pZWtvxL5rbyBib2RvdiAobmFwcsOta2xhZCBzIG96bmHEjWVuw61tIDksIDEwIGFsZWJvIDQpIHNhIG9kY2h5xL51amUgb2QgenZ5xaFrdSwgxI1vIG3DtMW+ZSB6bmFtZW5hxaUgcHLDrXRvbW5vc8WlIG9kxL5haGzDvWNoIGFsZWJvIHZwbHl2bsO9Y2ggcG96b3JvdmFuw60sIGt0b3LDqSBieSBtb2hsaSBvdnBseXZuacWlIHbDvXNsZWRreSBtb2RlbHUuCgoKIyMgUS1RIHBsb3QKCiMjIyDEjG8gdWthenVqZSAmIGludGVycHJldMOhY2lhIGdyYWZ1CgpOYSBncmFmZSBRLVEgUmVzaWR1YWxzIHBvcm92bsOhdmFtZSB0ZW9yZXRpY2vDqSBrdmFudGlseSBub3Jtw6FsbmVobyByb3pkZWxlbmlhIChvcyBYKSBzbyBza3V0b8SNbsO9bWkgxaF0YW5kYXJkaXpvdmFuw71taSByZXrDrWR1YW1pIG1vZGVsdSAob3MgWSkuIFbDpMSNxaFpbmEgYm9kb3YgbGXFvsOtIGJsw616a28gcHJlcnXFoW92YW5laiA0NcKwIMSNaWFyeSwgxI1vIHpuYW1lbsOhLCDFvmUgcmV6w61kdcOhIHPDuiBwcmlibGnFvm5lIG5vcm3DoWxuZSByb3psb8W+ZW7DqSBhIHByZWRwb2tsYWQgbm9ybWFsaXR5IGplIHZvIHbFoWVvYmVjbm9zdGkgc3BsbmVuw70uIFYgc3RyZWRuZWogxI1hc3RpIGdyYWZ1IChtZWR6aSBrdmFudGlsbWkgcHJpYmxpxb5uZSDiiJIxIGEgKzEpIGplIHpob2RhIHZlxL5taSBkb2Jyw6EsIMSNbyBuYXpuYcSNdWplLCDFvmUgdsOkxI3FoWluYSBob2Ruw7R0IHNhIHNwcsOhdmEgcG9kxL5hIG/EjWFrw6F2YW5pYS4gTmFvcGFrLCBrb25jb3bDqSBib2R5ICh2xL5hdm8gZG9sZSBhIHZwcmF2byBob3JlKSBzYSBtaWVybmUgb2RjaHnEvnVqw7ogb2QgcHJpYW1reSwgxI1vIHBvdWthenVqZSBuYSBtaWVybmUgb2RjaMO9bGt5IG9kIG5vcm1hbGl0eSB2IGV4dHLDqW1vY2gg4oCTIG5hcHLDrWtsYWQgcHLDrXRvbW5vc8WlIG5pZWtvxL5rw71jaCBvZMS+YWhsw71jaCBob2Ruw7R0IGFsZWJvIG8gbmllxI1vIMWlYcW+xaFpZSBjaHZvc3R5IHJvemRlbGVuaWEuIENlbGtvdm8gZ3JhZiB1a2F6dWplLCDFvmUgcm96ZGVsZW5pZSByZXrDrWR1w60gamUgcG9tZXJuZSBibMOtemtlIG5vcm3DoWxuZW11LCBwcmnEjW9tIGRyb2Juw6kgb2RjaMO9bGt5IHYga3Jham7DvWNoIGhvZG5vdMOhY2ggbmllIHPDuiB2w71yYXpuw6kuCgojIyBTY2FsZSBsb2NhdGlvbiBwbG90CgojIyMgxIxvIHRvIHpuw6F6b3LFiHVqZSAmIGludGVycHJldMOhY2lhIGdyYWZ1CgpOYSBncmFmZSBTY2FsZS1Mb2NhdGlvbiBwb3pvcnVqZW1lLCDFvmUgYm9keSBzw7ogcG9tZXJuZSByb3Zub21lcm5lIHJvenB0w71sZW7DqSBwb3pkxLrFviBvc2kgWCAoZml0dGVkIHZhbHVlcyksIGJleiB6amF2bsOpaG8gdHZhcnUgbGlldmlrYSBhbGVibyBpbsOpaG8gc3lzdGVtYXRpY2vDqWhvIHZ6b3J1LiBUbyBuYXpuYcSNdWplLCDFvmUgdmFyaWFuY2lhIHJlesOtZHXDrSBqZSBwcmlibGnFvm5lIGtvbsWhdGFudG7DoSwgdGVkYSBtb2RlbCBzcMS6xYhhIHByZWRwb2tsYWQgaG9tb3NrZWRhc3RpY2l0eS4gxIxlcnZlbsOhIGhsYWRrw6EgxI1pYXJhIGplIHJlbGF0w612bmUgcm92bsOhLCDEjW8gcG90dnJkenVqZSwgxb5lIHByaSByYXN0w7pjaWNoIHByZWRpa292YW7DvWNoIGhvZG5vdMOhY2ggc2Egcm96cHR5bCBjaMO9YiB2w71yYXpuZSBuZW1lbsOtLiBOaWVrb8S+a28gYm9kb3Ygc2Egc8OtY2UgbmFjaMOhZHphIG1pZXJuZSB2ecWhxaFpZSAobmFkIGhvZG5vdG91IDEpLCBhbGUgbmVqZGUgbyBleHRyw6ltbmUgb2RjaMO9bGt5IOKAkyB0ZWRhIG1vZGVsIG5lcHJlamF2dWplIHrDoXZhxb5uw6kgcHJvYmzDqW15IHMgaGV0ZXJvc2tlZGFzdGljaXRvdS4gQ2Vsa292byBncmFmIG5hem5hxI11amUsIMW+ZSByb3pwdHlsIGNow71iIGplIHN0YWJpbG7DvSBhIG1vZGVsIG3DoSB6IHRvaHRvIGjEvmFkaXNrYSBkb2Jyw6kgdmxhc3Rub3N0aS4KCiMjIFJlc2lkdWFscyB2cyBsZXZlcmFnZQoKIyMjIMSMbyB6bsOhem9yxYh1amUgJiBpbnRlcnByZXTDoWNpYSBncmFmdQoKTmEgZ3JhZmUgUmVzaWR1YWxzIHZzIExldmVyYWdlIHZpZMOtbWUsIGFrbyBqZWRub3RsaXbDqSBwb3pvcm92YW5pYSBvdnBseXbFiHVqw7ogb2RoYWRudXTDvSByZWdyZXNuw70gbW9kZWwuIFbDpMSNxaFpbmEgYm9kb3Ygc2EgbmFjaMOhZHphIHbEvmF2bywgcyBuw616a3ltaSBob2Rub3RhbWkgcMOha292w6lobyBlZmVrdHUgKGxldmVyYWdlIHBvZCAwLDIpLCDEjW8gbmF6bmHEjXVqZSwgxb5lIHbDpMSNxaFpbmEgcG96b3JvdmFuw60gbcOhIGxlbiBtYWzDvSB2cGx5diBuYSBtb2RlbCDigJMgdGVkYSBzw7ogZG9icmUgdnl2w6HFvmVuw6kgYSBuZW92cGx5dsWIdWrDuiB2w71yYXpuZSBzbWVybmljdSByZWdyZXNuZWogcHJpYW1reS4gxaB0YW5kYXJkaXpvdmFuw6kgcmV6w61kdcOhIHNhIHByaXRvbSBwb2h5YnVqw7ogcHJldmHFvm5lIHYgcm96bWVkesOtIG9kIOKIkjIgZG8gKzIsIMSNbyBqZSBiZcW+bsOpIGEgbmVpbmRpa3VqZSBwcsOtdG9tbm9zxaUgZXh0csOpbW55Y2ggb2RjaMO9bG9rLgoKTmlla2/EvmtvIGJvZG92IChuYXByw61rbGFkIG96bmHEjWVuw6kgYWtvIDQsIDEwLCAxMikgbcOhIG1pZXJuZSB2ecWhxaFpdSBob2Rub3R1IHDDoWtvdsOpaG8gZWZla3R1IOKAkyBpZGUgbyBwb3pvcm92YW5pYSBzIHBvdGVuY2nDoWxuZSB2ecWhxaHDrW0gdnBseXZvbSwgbm8gcG9kxL5hIGtvbnTDunIgQ29va292ZWogdnpkaWFsZW5vc3RpIMW+aWFkbmUgeiBuaWNoIG5lcHJla3JhxI11amUga3JpdGlja8OpIGhyYW5pY2UgKOKJiDAsNSBhbGVibyAxLDApLiBUbyB6bmFtZW7DoSwgxb5lIMW+aWFkbmUgcG96b3JvdmFuaWUgbmVvdnBseXbFiHVqZSBtb2RlbCBuZXByaW1lcmFuZSBzaWxuby4gxIxlcnZlbsOhIGhsYWRrw6EgxI1pYXJhIGplIHBvbWVybmUgcGxvY2jDoSwgxI1vIG5hem5hxI11amUsIMW+ZSBuZWV4aXN0dWplIHN5c3RlbWF0aWNrw70gdnpvcmVjIHYgcmV6w61kdcOhY2ggdiB6w6F2aXNsb3N0aSBvZCBww6Frb3bDqWhvIGVmZWt0dS4gQ2Vsa292byBncmFmIHBvdHZyZHp1amUsIMW+ZSBtb2RlbCBqZSBzdGFiaWxuw70sIGJleiB2w71yYXpuZSB2cGx5dm7DvWNoIGFsZWJvIHByb2JsZW1hdGlja8O9Y2ggYm9kb3YuCgoKYGBge3J9CiMgbm9ybWFsaXR5IHRlc3RzCnJlc2lkdWFscyA8LSByZXNpZHVhbHMobW9kZWwpCmpiX3Rlc3QgPC0gamFycXVlLmJlcmEudGVzdChyZXNpZHVhbHMpCmpiX3Rlc3QKIyBvdXRsaWVyIHRlc3QgKHNlZSBwLXZhbHVlIGZvciBCb25mZXJyb25pIGNvcnJlY3Rpb24pCm91dGxpZXJfdGVzdCA8LSBvdXRsaWVyVGVzdChtb2RlbCkKb3V0bGllcl90ZXN0CmBgYAoKS2XEj8W+ZSBzYSBuZXByZXVrw6F6YWxhIHByw610b21ub3PFpSDFoXRhdGlzdGlja3kgdsO9em5hbW7DvWNoIG9kxL5haGzDvWNoIGhvZG7DtHQgKHBvem9yb3ZhbmllIDEwIG3DoSBzw61jZSB2ecWhxaFpZSByZXrDrWR1dW0sIGFsZSBwLWhvZG5vdGEgMCwwNzgzID4gMCwwNSksIG5pZSBqZSBwb3RyZWJuw6kgZWxpbWlub3ZhxaUgxb5pYWRuZSBwb3pvcm92YW5pYSBhbmkgdHJhbnNmb3Jtb3ZhxaUgcHJlbWVubsOpLiBNb2RlbCBqZSB6IHRvaHRvIGjEvmFkaXNrYSBzdGFiaWxuw70uCgoKIyMgQ29uY2x1c2lvbgoKUHJlbWVubsOpIEdEUF9Hcm93dGhfQW5udWFsLCBJbmZsYXRpb25fQ1BJIGEgUHVibGljX0RlYnQgxaF0YXRpc3RpY2t5IHbDvXpuYW1uZSBvdnBseXbFiHVqw7ogbWllcnUgbmV6YW1lc3RuYW5vc3RpIHYgcm9rb2NoIDIwMTAtMjAyMi4gUmV6w61kdcOhIG1vZGVsdSBzw7ogcHJpYmxpxb5uZSBub3Jtw6FsbmUgcm96bG/FvmVuw6kgYSBuZWJvbGkgemlzdGVuw6kgxb5pYWRuZSB2w716bmFtbsOpIG9kxL5haGzDqSBob2Rub3R5LiBNb2RlbCBuZXZ5a2F6dWplIHpuw6Fta3kgaGV0ZXJvc2tlZGFzdGljaXR5IGFuaSBuZWxpbmVhcml0eSwgcHJldG8gaG8gbcO0xb5lbWUgcG92YcW+b3ZhxaUgemEgdmhvZG7DvSBuYSBpbnRlcnByZXTDoWNpdS4KCgoKIyMgSGV0ZXJvc2tlZGFzdGljaXRhCgpQcsOtdG9tbm9zxaUgaGV0ZXJvc2tlZGFzdGljaXR5IChuZWtvbsWhdGFudG7DqWhvIHJvenB0eWx1IG7DoWhvZG5laiB6bG/Fvmt5KSBzcMO0c29idWplIG5lc3BvxL5haGxpdsOpIHZ5aG9kbm9jb3ZhbmllIHQtdGVzdG92IHbDvXpuYW1ub3N0aSBqZWRub3RsaXbDvWNoIHJlZ3Jlc27DvWNoIGtvZWZpY2llbnRvdi4gUHJldG8gamUgcG90cmVibsOpLCBhYnkgc21lIGhldGVyb3NrZWRhc3RpY2l0dQoKLWRldGVnb3ZhbGkgKHZpenXDoWxuZSBhIHBvbW9jb3UgdGVzdG92KSwKCi1hIHYgcHLDrXBhZGUgamVqIHByw610b21ub3N0aSBzYSBqdSBwb2vDunNpbGkgb2RzdHLDoW5pxaUuCgpBaiB2IG5hxaFvbSBwcsOtcGFkZSBzYSBwb2vDunNpbWUgbyB2aXp1w6FsbmUgdnlob2Rub3RlbmllIGhldGVyb3NrZWRhc3RpY2l0eSBuYSB6w6FrbGFkZSBkaWFnbm9zdGlja8O9Y2ggZ3JhZm92LgoKVGVudG9rcsOhdCBzYSB6YW1lcmlhbWUgbmEgem7DoXpvcm5lbmllIHrDoXZpc2xvc3RpIMWhdHZvcmNvdiByZXrDrWR1w60gb2QgdnlzdmV0xL51asO6Y2VqIHByZW1lbm5laiwgcHJpIGt0b3JlaiBleGlzdHVqZSBwb2RvenJlbmllLCDFvmUgYnkgbW9obGEgaGV0ZXJvc2tlZGFzdGljaXR1IHNww7Rzb2JvdmHFpS4KClYgbmHFoW9tIG1vZGVsaSBtw7TFvmUgYnnFpSB0YWtvdXRvIHByZW1lbm5vdSBuYWptw6QgKkdEUF9Hcm93dGhfQW5udWFsKiwga2XEj8W+ZSBla29ub21pY2vDvSByYXN0IGLDvXZhIMSNYXN0byBzcG9qZW7DvSBzIHZ5xaHFoW91IHZhcmlhYmlsaXRvdSBtaWVyeSBuZXphbWVzdG5hbm9zdGkuCgpCdWRlbWUgdGVkYSBwb3Jvdm7DoXZhxaUgZHZhIG1vZGVseToKCnDDtHZvZG7DvSBtb2RlbCAobW9kZWwpLAoKYSBwcsOtcGFkbmUgdXByYXZlbsO9IG1vZGVsIChtb2RlbDIpLCBrdG9yw70gYnkgbW9ob2wgb2JzYWhvdmHFpSB0cmFuc2Zvcm1vdmFuw7ogcG9kb2J1IHByZW1lbm5laiAobmFwci4gbG9nKEdEUF9Hcm93dGhfQW5udWFsKSksIGFrIGJ5IHNhIGhldGVyb3NrZWRhc3RpY2l0YSBwb3R2cmRpbGEuCgpgYGB7ciBoZXRlcm9wbG90czEsIGZpZy5jYXA9IlNrw7ptYW5pZSBoZXRlcm9za2VkYXN0aWNpdHkiLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9NH0KbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHBhdGNod29yaykgICMgaW5zdGFsbC5wYWNrYWdlcygicGF0Y2h3b3JrIikKCnAxIDwtIGdncGxvdCh1ZGFqZSwgYWVzKHggPSBHRFBfR3Jvd3RoX0FubnVhbCwgeSA9IHJlc2lkKG1vZGVsKV4yKSkgKwogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjYpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG9lc3MiLCBzZSA9IEZBTFNFLCBjb2xvciA9ICJyZWQiKSArCiAgbGFicyh4ID0gIkdEUCBHcm93dGggKEFubnVhbCkiLCAKICAgICAgIHkgPSAiU3F1YXJlZCBSZXNpZHVhbHMiLAogICAgICAgdGl0bGUgPSAiU3F1YXJlZCBSZXNpZHVhbHMgdnMgR0RQIEdyb3d0aCIpICsKICB0aGVtZV9taW5pbWFsKCkKCnAyIDwtIGdncGxvdCh1ZGFqZSwgYWVzKHggPSBJbmZsYXRpb25fQ1BJLCB5ID0gcmVzaWQobW9kZWwpXjIpKSArCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuNikgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsb2VzcyIsIHNlID0gRkFMU0UsIGNvbG9yID0gInJlZCIpICsKICBsYWJzKHggPSAiSW5mbGF0aW9uIChDUEkpIiwgCiAgICAgICB5ID0gIlNxdWFyZWQgUmVzaWR1YWxzIiwKICAgICAgIHRpdGxlID0gIlNxdWFyZWQgUmVzaWR1YWxzIHZzIEluZmxhdGlvbiIpICsKICB0aGVtZV9taW5pbWFsKCkKCiMgQ29tYmluZSBzaWRlIGJ5IHNpZGUKcDEgKyBwMgpgYGAKTmEgZ3JhZmUgU3F1YXJlZCBSZXNpZHVhbHMgdnMgR0RQIEdyb3d0aCAoQW5udWFsKSBtw7TFvmVtZSBwb3pvcm92YcWlIG1pZXJuZSBrb2zDrXNhbmllIMSNZXJ2ZW5laiB2eWhsYWRlbmVqIGtyaXZreSwga3RvcsOhIG5hem5hxI11amUsIMW+ZSByb3pwdHlsIHJlesOtZHXDrSBzYSBtZW7DrSBzIGhvZG5vdGFtaSBHRFAgR3Jvd3RoLiBOYWptw6QgdiBzdHJlZG5laiDEjWFzdGkgKG9rb2xvIDLigJMzICUpIGplIHZpZGl0ZcS+bsO9IHZ5xaHFocOtIHJvenB0eWwsIHphdGlhxL4gxI1vIG5hIGtyYWpvY2ggcm96cHR5bCBrbGVzw6EuIFRvIG3DtMW+ZSBuYXpuYcSNb3ZhxaUgbWllcm51IHByw610b21ub3PFpSBoZXRlcm9za2VkYXN0aWNpdHkuCk5hIGdyYWZlIFNxdWFyZWQgUmVzaWR1YWxzIHZzIEluZmxhdGlvbiAoQ1BJKSBqZSDEjWVydmVuw6Ega3JpdmthIHbDvXJhem5lIHpha3JpdmVuw6Eg4oCTIHJvenB0eWwgcmV6w61kdcOtIHNhIHpqYXZuZSBtZW7DrSB2IHrDoXZpc2xvc3RpIG9kIGluZmzDoWNpZSwgbmFqbcOkIHByaSBuacW+xaHDrWNoIGEgc3RyZWRuw71jaCBob2Rub3TDoWNoLiBUbyBuYXpuYcSNdWplLCDFvmUgaW5mbMOhY2lhIG3DtMW+ZSBwcmlzcGlldmHFpSBrIG5la29uxaF0YW50bsOpbXUgcm96cHR5bHUgbsOhaG9kbmVqIHpsb8W+a3kuCgphIHRlcmF6IG1vZGVsIHNvIHpsb2dhcml0bWl6b3Zhbm91IHByZW1lbm5vdSAqR0RQX0dyb3d0aF9Bbm51YWwqLgoKYGBge3IgaGV0ZXJvcGxvdHMyLCBmaWcuY2FwPSJTa8O6bWFuaWUgaGV0ZXJvc2tlZGFzdGljaXR5IiwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTR9CmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShwYXRjaHdvcmspICAKCnAxIDwtIGdncGxvdCh1ZGFqZSwgYWVzKHggPSBsb2coR0RQX0dyb3d0aF9Bbm51YWwpLCB5ID0gcmVzaWQobW9kZWwyKV4yKSkgKwogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjYpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG9lc3MiLCBzZSA9IEZBTFNFLCBjb2xvciA9ICJyZWQiKSArCiAgbGFicyh4ID0gImxvZyhHRFAgR3Jvd3RoIEFubnVhbCkiLCAKICAgICAgIHkgPSAiU3F1YXJlZCBSZXNpZHVhbHMiLAogICAgICAgdGl0bGUgPSAiU3F1YXJlZCBSZXNpZHVhbHMgdnMgbG9nKEdEUCBHcm93dGgpIikgKwogIHRoZW1lX21pbmltYWwoKQoKcDIgPC0gZ2dwbG90KHVkYWplLCBhZXMoeCA9IEluZmxhdGlvbl9DUEksIHkgPSByZXNpZChtb2RlbDIpXjIpKSArCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuNikgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsb2VzcyIsIHNlID0gRkFMU0UsIGNvbG9yID0gInJlZCIpICsKICBsYWJzKHggPSAiSW5mbGF0aW9uIChDUEkpIiwgCiAgICAgICB5ID0gIlNxdWFyZWQgUmVzaWR1YWxzIiwKICAgICAgIHRpdGxlID0gIlJlc2lkdWFscyB2cyBJbmZsYXRpb24iKSArCiAgdGhlbWVfbWluaW1hbCgpCgojIENvbWJpbmUgc2lkZSBieSBzaWRlCnAxICsgcDIKYGBgCgpQbyBsb2dhcml0bWlja2VqIHRyYW5zZm9ybcOhY2lpIEdEUCBHcm93dGggc2EgxI1lcnZlbsOhIGtyaXZrYSBuYSBncmFmZSBTcXVhcmVkIFJlc2lkdWFscyB2cyBsb2coR0RQIEdyb3d0aCkgc3TDoXZhIHBseW51bGVqxaFvdSBhIGJleiB2w71yYXpuw6lobyB0cmVuZHUuIFZhcmlhbmNpYSByZXrDrWR1w60gc2EgamF2w60gYWtvIHJvdm5vbWVybmVqxaFpYSB2IGNlbG9tIHJvenNhaHUgaG9kbsO0dCwgxI1vIG5hem5hxI11amUsIMW+ZSB0cmFuc2Zvcm3DoWNpYSBwb21vaGxhIHptaWVybmnFpSBoZXRlcm9za2VkYXN0aWNpdHUgc3BvamVuw7ogcyBHRFAgR3Jvd3RoLgpOYSBkcnVoZWogc3RyYW5lLCB2esWlYWggbWVkemkgxaF0dm9yY2FtaSByZXrDrWR1w60gYSBJbmZsYXRpb24gKENQSSkgem9zdMOhdmEgcG9kb2Juw70g4oCTIGFqIHBvIHRyYW5zZm9ybcOhY2lpIG1vxb5ubyBwb3pvcm92YcWlIGlzdMOpIGtvbMOtc2FuaWUgcm96cHR5bHUsIHRha8W+ZSBpbmZsw6FjaWEgbcO0xb5lIGJ5xaUgYWogbmHEj2FsZWogemRyb2pvbSBtaWVybmVqIGhldGVyb3NrZWRhc3RpY2l0eS4KClRyYW5zZm9ybcOhY2lhIEdEUCBHcm93dGggcG9tb2NvdSBsb2dhcml0bXUgdGVkYSBwb21vaGxhIHN0YWJpbGl6b3ZhxaUgcm96cHR5bCByZXrDrWR1w60gdiBtb2RlbGkuIE5hcHJpZWsgdG9tdSBtaWVybmUgem7DoW1reSBoZXRlcm9za2VkYXN0aWNpdHkgbcO0xb51IHByZXRydsOhdmHFpSwgbmFqbcOkIHYgc8O6dmlzbG9zdGkgcyBwcmVtZW5saXZvdSBpbmZsw6FjaW91LiBDZWxrb3ZvIHbFoWFrIG5vdsO9IG1vZGVsIChtb2RlbDIpIHZ5a2F6dWplIGxlcMWhaXUgxaF0cnVrdMO6cnUgcmV6w61kdcOtIGEgem7DrcW+ZW7DuiB2YXJpYWJpbGl0dS4KCiMjIFRlc3RvdmFuaWUgcHLDrXRvbW5vc3RpIGhldGVyb3NrZWRhc3RpY2l0eQpgYGB7cn0KIyBJbnN0YWxsIChpZiBub3QgeWV0IGluc3RhbGxlZCkKIyBpbnN0YWxsLnBhY2thZ2VzKCJsbXRlc3QiKQoKIyBMb2FkIHRoZSBwYWNrYWdlCmxpYnJhcnkobG10ZXN0KQoKIyBSdW4gdGhlIEJyZXVzY2jigJNQYWdhbiB0ZXN0CmJwdGVzdChtb2RlbCkKCmBgYAoKYGBge3J9CiMgSW5zdGFsbCAoaWYgbm90IHlldCBpbnN0YWxsZWQpCiMgaW5zdGFsbC5wYWNrYWdlcygibG10ZXN0IikKCiMgTG9hZCB0aGUgcGFja2FnZQpsaWJyYXJ5KGxtdGVzdCkKCiMgUnVuIHRoZSBCcmV1c2No4oCTUGFnYW4gdGVzdApicHRlc3QobW9kZWwyKQoKYGBgCktlxI/FvmUgcC1ob2Rub3RhIGplIHbDvXJhem5lIHZ5xaHFoWlhIGFrbyBiZcW+bsOhIGhsYWRpbmEgdsO9em5hbW5vc3RpICgwLjA1KSwgbmV6YW1pZXRhbWUgbnVsb3bDuiBoeXBvdMOpenUgbyBob21vc2tlZGFzdGljaXRlLiBUbyB6bmFtZW7DoSwgxb5lIHYgbmHFoW9tIG1vZGVsaSBuaWUgamUgcHLDrXRvbW7DoSBoZXRlcm9za2VkYXN0aWNpdGEg4oCTIHJvenB0eWwgcmV6w61kdcOtIHNhIGphdsOtIGFrbyBrb27FoXRhbnRuw70uCgpOYSB6w6FrbGFkZSB2aXp1w6FsbmVobyBwb3PDumRlbmlhIGdyYWZvdiBhIHbDvXNsZWRrdSBCcmV1c2No4oCTUGFnYW5vdmhvIHRlc3R1IChwLWhvZG5vdGEgPSAwLjk3ODQpIG3DtMW+ZW1lIGtvbsWhdGF0b3ZhxaUsIMW+ZSBoZXRlcm9za2VkYXN0aWNpdGEgdiByZXrDrWR1w6FjaCBuaWUgamUgcHLDrXRvbW7DoS4gUHJldG8gbmllIGplIHBvdHJlYm7DqSBhcGxpa292YcWlIFdoaXRlb3Z1IGtvcmVrY2l1IGFuaSDEj2FsxaFpZSDDunByYXZ5IG1vZGVsdS4=