Úvod a predstavenie databázy

Cieľom práce je analyzovať vývoj populácie Slovenskej republiky v porovnaní s vybranými štátmi Európskej únie, predovšetkým s Českou republikou. Analýza využíva databázu World_Population, ktorá obsahuje súhrnné demografické údaje o krajinách sveta.

1.Základná charakteristika databázy:

Databáza zhromažďuje napríklad údaje o:

  • počte obyvateľov jednotlivých krajín/kontinentov,
  • rozlohe územia,
  • hustote obyvateľstva,
  • ročnom prírastku alebo úbytku populácie,
  • roku záznamu

Tieto údaje umožňujú porovnanie demografického vývoja medzi krajinami a identifikáciu základných trendov.

head(world_population)                            # niekolko prvych riadkov
colnames(world_population)
 [1] "Rank"                        "CCA3"                        "Country.Territory"          
 [4] "Capital"                     "Continent"                   "X2022.Population"           
 [7] "X2020.Population"            "X2015.Population"            "X2010.Population"           
[10] "X2000.Population"            "X1990.Population"            "X1980.Population"           
[13] "X1970.Population"            "Area..km.."                  "Density..per.km.."          
[16] "Growth.Rate"                 "World.Population.Percentage"

2.Porovnanie Slovenska a Českej republiky (1980–2020)

Pre naše skúmanie si z databázy world population na začiatok vyberáme krajiny Slovensko a Českú republiku. Následne pozorujeme roky 1980-2020 ako sa vyvíjala populácia a teda počet obyvateľov v priebehu týchto rokov.

library(ggplot2)
SVK_CZE_data <- world_population %>%
  filter(CCA3 %in% c("SVK", "CZE")) %>%  # Filtrovanie na Slovensko a Česko
  select(CCA3, "X2020.Population", "X2010.Population", "X2000.Population", "X1990.Population", "X1980.Population") # Vyberáme len relevantné stĺpce
head(SVK_CZE_data)

Scatter plot

library(dplyr)
library(tidyr)
library(ggplot2)

# Predpokladám, že dataset je uložený v premennej `SVK_CZE_data`

# 1. Vyberieme potrebné stĺpce a dáta len pre Slovensko a Česko
SVK_CZE_sel <- SVK_CZE_data %>%
  filter(CCA3 %in% c("SVK", "CZE")) %>%  # Filtrovanie na Slovensko a Česko
  select(CCA3, "X2020.Population", "X2010.Population", "X2000.Population", "X1990.Population", "X1980.Population")  # Vyberáme len relevantné stĺpce

# 2. Premeníme dáta do dlhého formátu (pre graf)
SVK_CZE_long <- SVK_CZE_sel %>%
  pivot_longer(cols = c("X2020.Population", "X2010.Population", "X2000.Population", "X1990.Population", "X1980.Population"),
               names_to = "year",     # Stĺpec s rokmi
               values_to = "population")  # Stĺpec s populáciou

# 3. Vytvoríme stĺpcový graf - Zobrazíme populáciu Slovenska a Česka v rokoch 1980, 1990, 2000, 2010 a 2020
ggplot(SVK_CZE_long, aes(x = year,y = population, fill = CCA3, group = CCA3)) + geom_bar(stat = "identity", position = "dodge", width = 0.8) + # Stĺpcový graf s oddelenými stĺpcami pre každú krajinu 
  geom_text(aes(label = population), position = position_dodge(width = 0.3), vjust = -0.1) + # Pridanie označení hodnôt 
  theme_minimal() + # Minimalistický dizajn grafu 
  labs(title = "Vývoj populácie Slovenska a Česka", # Upravený nadpis 
       x = "Rok", 
       y = "Populácia", 
       fill = "Krajina") + # Popis farieb podľa krajiny 
  theme(axis.text.x = element_text(angle = 30, hjust = 1)) # Rotácia textu na osi X

(Tento graf má deskriptívny charakter a slúži na ilustráciu základných rozdielov medzi krajinami.)

Obe krajiny vykazujú v sledovanom období mierny rast populácie.

Česká republika má počas celého obdobia vyšší počet obyvateľov než Slovensko. -> v Česku možno pozorovať mierny pokles populácie v období 1990–2000, ktorý môže súvisieť s demografickými a spoločenskými zmenami po roku 1989.

library(dplyr)
library(knitr)

# 1. Vyberieme potrebné stĺpce a dáta len pre Slovensko a Česko
SVK_CZE_sel <- SVK_CZE_data %>%
  filter(CCA3 %in% c("SVK", "CZE")) %>%  # Filtrovanie na Slovensko a Česko
  select(CCA3, "X2020.Population", "X2010.Population", "X2000.Population", "X1990.Population", "X1980.Population")  # Relevantné stĺpce

# 2. Premeníme dáta do dlhého formátu
SVK_CZE_long <- SVK_CZE_sel %>%
  pivot_longer(cols = c("X2020.Population", "X2010.Population", "X2000.Population", "X1990.Population", "X1980.Population"),
               names_to = "year",
               values_to = "population")
# 3. Vypočítame základné štatistiky populácie podľa krajiny a roku
SVK_CZE_stats <- SVK_CZE_long %>%
  group_by(CCA3, year) %>%
  summarise(
    n      = n(),
    mean   = mean(population, na.rm = TRUE),
    sd     = sd(population, na.rm = TRUE),
    min    = min(population, na.rm = TRUE),
    q25    = quantile(population, 0.25, na.rm = TRUE),
    median = median(population, na.rm = TRUE),
    q75    = quantile(population, 0.75, na.rm = TRUE),
    max    = max(population, na.rm = TRUE),
    .groups = "drop"
  )

# 4. Vytvoríme tabuľku pomocou knitr
kable(SVK_CZE_stats, digits = 0, caption = "Základné štatistiky populácie Slovenska a Česka (1980–2020)")
Základné štatistiky populácie Slovenska a Česka (1980–2020)
CCA3 year n mean sd min q25 median q75 max
CZE X1980.Population 1 10270060 NA 10270060 10270060 10270060 10270060 10270060
CZE X1990.Population 1 10301192 NA 10301192 10301192 10301192 10301192 10301192
CZE X2000.Population 1 10234710 NA 10234710 10234710 10234710 10234710 10234710
CZE X2010.Population 1 10464749 NA 10464749 10464749 10464749 10464749 10464749
CZE X2020.Population 1 10530953 NA 10530953 10530953 10530953 10530953 10530953
SVK X1980.Population 1 4973883 NA 4973883 4973883 4973883 4973883 4973883
SVK X1990.Population 1 5261305 NA 5261305 5261305 5261305 5261305 5261305
SVK X2000.Population 1 5376690 NA 5376690 5376690 5376690 5376690 5376690
SVK X2010.Population 1 5396424 NA 5396424 5396424 5396424 5396424 5396424
SVK X2020.Population 1 5456681 NA 5456681 5456681 5456681 5456681 5456681

Hlavné zistenia:

Rast populácie: Obidve krajiny vykazujú pozitívny trend rastu populácie od roku 1980 do roku 2020, čo môže naznačovať stabilný demografický vývoj, alebo len veľmi pomalý rast.

Medzery v dynamike: Mierny pokles v populácii Česka medzi 1990 a 2000 môže byť spôsobený rôznymi faktormi (napr. emigrácia, pokles natality a pod.) a môže si vyžadovať hlbšiu analýzu, či už v kontexte ekonomických alebo politických zmien v tej dobe.

Porovnanie krajín: Počet obyvateľov Česka bol v priebehu rokov vždy vyšší než počet obyvateľov Slovenska, čo je očakávané vzhľadom na veľkosť oboch krajín (Česká republika má väčšiu populáciu než Slovensko).

3.Porovnanie populácie Slovenska a Česka v rokoch 2020

Štatistické testovanie – metodické obmedzenia

Na porovnanie populácií Slovenska a Českej republiky bol vykonaný t-test a jednoduchá analýza rozptylu (ANOVA). Tieto testy sú však použité len ilustratívne, pretože pozorovania v jednotlivých rokoch nie sú nezávislé a tvoria časový rad. Z tohto dôvodu výsledky t-testu a ANOVA neinterpretujeme ako inferenčný dôkaz, ale len ako potvrdenie výrazného rozdielu v úrovni populácie medzi krajinami.

# 1. Vyberieme populáciu Slovenska a Česka v roku 2020
SVK_CZE_2020 <- SVK_CZE_data %>%
  filter(CCA3 %in% c("SVK", "CZE")) %>%
  select(CCA3, "X2020.Population")

# 2. Vykonáme t-test na porovnanie populácie medzi SVK a CZE v roku 2020
SVK_pop <- SVK_CZE_long %>% filter(CCA3 == "SVK") %>% pull(population)
CZE_pop <- SVK_CZE_long %>% filter(CCA3 == "CZE") %>% pull(population)

# 3. Výpis výsledku testu
t_test_result <- t.test(SVK_pop, CZE_pop)
print(t_test_result)

    Welch Two Sample t-test

data:  SVK_pop and CZE_pop
t = -48.899, df = 7.0276, p-value = 3.655e-10
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 -5312182 -4822491
sample estimates:
mean of x mean of y 
  5292997  10360333 

Rozdiel v populáciách medzi Slovenskom a Českom je štatisticky významný. P-hodnota je extrémne nízka (3.655 × 10⁻¹⁰), čo znamená, že rozdiel medzi priemernými populáciami týchto dvoch krajín nie je náhodný.

Priemerná populácia Česka je oveľa vyššia než populácia Slovenska, čo je očakávané vzhľadom na veľkosť oboch krajín.

95% interval spoľahlivosti naznačuje, že skutočný rozdiel medzi priemernými populáciami sa pohybuje medzi približne 4,8 miliónmi a 5,3 miliónmi obyvateľov v prospech Česka.

Na základe tohto testu môžeme jednoznačne povedať, že medzi populáciami Slovenska a Česka je štatisticky významný rozdiel. Tento rozdiel je veľmi vysoký a neexistuje žiadna pravdepodobnosť, že by tento rozdiel bol spôsobený náhodou.

ANOVA

anova_result <- aov(population ~ year, data = SVK_CZE_long)
summary(anova_result)

Výsledky analýzy rozptylu (ANOVA) naznačujú, že medzi priemernými populáciami Slovenska a Česka v rokoch 1980, 1990, 2000, 2010 a 2020 neexistuje štatisticky významný rozdiel.

F-hodnota: 0.003 P-hodnota: 1

Na základe týchto výsledkov nemôžeme odmietnuť nulovú hypotézu, čo znamená, že z hľadiska týchto dát neexistuje dôkaz o rozdieloch medzi populáciami v jednotlivých rokoch.

Tieto výsledky naznačujú stabilitu populácie v sledovanom období (1980–2020), pričom populácie oboch krajín sa vyvíjali relatívne konzistentne bez štatisticky významných zmien.

Regresná analýza vývoja populácie

# install.packages(c("broom", "kableExtra", "dplyr", "stringr"))
library(broom)
library(dplyr)
library(kableExtra)
library(stringr)

# Your model (already fitted)
# model <- lm(ESG.INDEX ~ RETURN.ON.ASSETS + FIRM.SIZE + DEBT.TO.ASSET, data = udaje.2013)

coef.tbl <- tidy(model, conf.int = TRUE) %>%
  mutate(
    term = recode(term,
      "(Intercept)" = "Intercept",
      "year1990 Population" = "Rok 1990",
      "year2000 Population" = "Rok 2000",
      "year2010 Population" = "Rok 2010",
      "year2020 Population" = "Rok 2020",
      "CCA3SVK" = "Slovensko"
    ),
    stars = case_when(
      p.value < 0.001 ~ "***",
      p.value < 0.01  ~ "**",
      p.value < 0.05  ~ "*",
      p.value < 0.1   ~ "·",
      TRUE            ~ ""
    )
  ) %>%
  transmute(
    Term = term,
    Estimate = estimate,
    `Std. Error` = std.error,
    `t value` = statistic,
    `p value` = p.value,
    `95% CI` = str_c("[", round(conf.low, 0), ", ", round(conf.high, 0), "]"),
    Sig = stars
  )

coef.tbl %>%
  kable(
    digits = 0,
    caption = "OLS regresné koeficienty (population ~ year + CCA3)"
  ) %>%
  kable_styling(full_width = FALSE, bootstrap_options = c("striped", "hover", "condensed")) %>%
  column_spec(1, bold = TRUE) %>%
  row_spec(0, bold = TRUE, background = "#f2f2f2") %>%
  footnote(
    general = "Signif. codes: *** p<0.001, ** p<0.01, * p<0.05, · p<0.1.",
    threeparttable = TRUE)
OLS regresné koeficienty (population ~ year + CCA3)
Term Estimate Std. Error t value p value 95% CI Sig
Intercept 10155640 85287 119 0 [9918846, 10392433] ***
Rok 1990 159277 110104 1 0 [-146422, 464976]
Rok 2000 183728 110104 2 0 [-121970, 489427]
Rok 2010 308615 110104 3 0 [2916, 614314] *
Rok 2020 371845 110104 3 0 [66147, 677544] *
Slovensko -5067336 69636 -73 0 [-5260677, -4873995] ***
Note:
Signif. codes: *** p<0.001, ** p<0.01, * p<0.05, · p<0.1.
NA

Na základe výsledkov lineárnej regresie (OLS) môžeme konštatovať, že v rokoch 1990, 2000, 2010 a 2020 došlo k určitému nárastu populácie v porovnaní s rokom 1980. Všetky rozdiely, okrem rokov 1990 a 2000, sú štatisticky významné. V rokoch 2010 a 2020 bola populácia o 308,615 a 371,845 obyvateľov vyššia než v roku 1980, čo naznačuje rast v týchto obdobiach.

Naproti tomu roky 1990 a 2000 nevykazujú štatisticky významný rozdiel v porovnaní s rokom 1980, čo naznačuje stabilitu v tomto období. Výrazný rozdiel bol pozorovaný aj medzi Českou republikou a Slovenskom, kde populácia Slovenska bola v priemere nižšia o viac než 5 miliónov obyvateľov, čo je štatisticky veľmi významné. Model ukazuje, že rok 1980 predstavuje základný referenčný bod pre ďalšie analýzy a vplyv rôznych faktorov na zmeny v populácii.

Vysoká hodnota R-squared (0.9992) ukazuje, že model veľmi dobre vysvetľuje variabilitu v populáciách oboch krajín. P-hodnoty pre roky 2010 a 2020, ako aj pre Slovensko, sú významné, čo naznačuje, že tieto faktory majú silný vplyv na populáciu.

Celkovo môžeme povedať, že medzi rokom 1980 a 2020 došlo k významným zmenám v populácii, pričom Slovensko vykazuje výrazne nižšiu populáciu v porovnaní s Českou republikou. Výsledky tejto analýzy tak poskytujú cenné informácie o demografických trendoch v oboch krajinách v posledných desaťročiach. Ale keďže model má veľmi vysoké R², čo je spôsobené malým počtom pozorovaní a veľkými rozdielmi v úrovni populácie, výsledky preto interpretujeme opisne, nie predikčne.

4.Hustota obyvateľstva a jej determinanty

Ďalšia časť práce sa zameriava na vzťah medzi hustotou obyvateľstva, populáciou a rozlohou krajín v roku 2020.

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

# Kontrola názvov stĺpcov
names(udaje)
 [1] "Rank"                        "CCA3"                        "Country.Territory"          
 [4] "Capital"                     "Continent"                   "X2022.Population"           
 [7] "X2020.Population"            "X2015.Population"            "X2010.Population"           
[10] "X2000.Population"            "X1990.Population"            "X1980.Population"           
[13] "X1970.Population"            "Area..km.."                  "Density..per.km.."          
[16] "Growth.Rate"                 "World.Population.Percentage"
# Výber len číselných údajov (uprav podľa presných názvov stĺpcov)
udaje.2020 <- udaje[, c("X2020.Population", "Area..km..", "Density..per.km..")]

# Konverzia na numeric
udaje.2020 <- as.data.frame(lapply(udaje.2020, as.numeric))

# Nahradenie NA mediánmi
column_medians <- sapply(udaje.2020, median, na.rm = TRUE)
for (col in names(udaje.2020)) {
  udaje.2020[[col]][is.na(udaje.2020[[col]])] <- column_medians[col]
}

# Vykreslenie boxplotov
par(mfrow = c(2, 2))
par(mar = c(4, 4, 2, 1))
for (col in names(udaje.2020)) {
  boxplot(udaje.2020[[col]], main = col, xlab = "Hodnoty", col = "lightblue", border = "pink")
}

1. X2020.Population

Väčšina hodnôt sa koncentruje pri veľmi nízkych hodnotách populácie. Viditeľných je niekoľko výrazných odľahlých hodnôt (outliers) – niektoré krajiny/územia majú populáciu výrazne vyššiu než ostatné. Rozdelenie je silne pravostranné (pozitívne zošikmené) – väčšina pozorovaní má malé hodnoty, zatiaľ čo niekoľko extrémnych pozorovaní ťahá medián smerom nadol.

2. Area..km..

Väčšina krajín má pomerne malú rozlohu, pričom zopár veľmi veľkých území spôsobuje silnú pravostrannú šikmosť. Viaceré body ďaleko od hlavného poľa dát naznačujú odľahlé pozorovania (veľké krajiny). Podobne ako pri populácii, dáta sú veľmi nesymetrické – odporúča sa zvážiť transformáciu (napr. log(area)).

3. Density..per.km..

Hustota obyvateľstva má väčšinu hodnôt sústredených pri nízkych číslach, no niekoľko oblastí má extrémne vysokú hustotu. To sa prejavuje odľahlými bodmi nad horným fúzom boxplotu. Rozdelenie je pravostranné, teda existujú niektoré extrémne husto obývané regióny. Transformácia (napr. log) by mohla pomôcť zlepšiť symetriu rozdelenia.

# Nastaviť rozloženie 2 x 2
par(mfrow = c(2, 2))

# Vykresliť všetky 4 diagnostické grafy modelu
plot(model)

# (Voliteľné) pridať spoločný nadpis
mtext("Diagnostické grafy regresného modelu", outer = TRUE, cex = 1.2, font = 2)

# Resetovať layout
par(mfrow = c(1, 1))

Čo nám hovoria tieto grafy?

Residuals vs Fitted

Reziduály sú rozložené okolo nuly bez výrazného trendu, čo naznačuje dobré prispôsobenie modelu. Mierne zakrivenie čiary poukazuje na možnú nelinearitu alebo vplyv niekoľkých odľahlých pozorovaní.

Normal Q–Q plot

Väčšina bodov leží blízko diagonály, takže rozdelenie rezíduí je približne normálne. Menšie odchýlky na okrajoch naznačujú len mierne porušenie normality.

Scale–Location

Rozptyl rezíduí sa javí ako približne konštantný, čo podporuje predpoklad homoskedasticity. Mierne výkyvy na začiatku môžu byť spôsobené niekoľkými extrémnymi bodmi.

Residuals vs Factor Levels

Reziduály sa v jednotlivých faktorových úrovniach pohybujú okolo nuly, bez systematického trendu. Body 5 a 10 pôsobia ako možné vplyvné pozorovania, ktoré môžu ovplyvňovať model.

install.packages("tseries")  # len raz
library(tseries)   
model2 <- lm(Density..per.km.. ~ X2020.Population + Area..km.., data = udaje.2020)
summary(model2)

Call:
lm(formula = Density..per.km.. ~ X2020.Population + Area..km.., 
    data = udaje.2020)

Residuals:
    Min      1Q  Median      3Q     Max 
 -493.6  -417.8  -361.8  -217.8 22677.4 

Coefficients:
                   Estimate Std. Error t value Pr(>|t|)    
(Intercept)       4.948e+02  1.434e+02   3.452 0.000662 ***
X2020.Population  2.622e-08  1.124e-06   0.023 0.981404    
Area..km..       -7.495e-05  8.647e-05  -0.867 0.386995    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 2071 on 231 degrees of freedom
Multiple R-squared:  0.003987,  Adjusted R-squared:  -0.004636 
F-statistic: 0.4624 on 2 and 231 DF,  p-value: 0.6304
# Diagnostické grafy
par(mfrow = c(2, 2))
par(mar = c(4, 4, 2, 1))
plot(model2)
par(mfrow = c(1, 1))

Residuals vs Fitted

Reziduály sa väčšinou pohybujú okolo nuly, čo naznačuje, že model nemá výrazné systematické chyby v predikciách. Niekoľko bodov s veľkými reziduálmi (napr. 120, 135, 188) predstavuje možné odľahlé pozorovania.

Normal Q–Q plot

Väčšina bodov sleduje diagonálu, no koniec grafu sa výrazne odchyľuje smerom nahor. To znamená, že reziduály nie sú dokonale normálne rozdelené a existujú extrémne hodnoty v pravej časti rozdelenia.

Scale–Location

Rozptyl rezíduí sa javí ako relatívne konštantný, bez výrazného rozširovania alebo zužovania. Len niekoľko bodov s vysokými štandardizovanými reziduálmi môže naznačovať miernu heteroskedasticitu.

Residuals vs Leverage

Väčšina bodov má nízke hodnoty leverage, čo je dobré, no niekoľko pozorovaní (napr. 120, 135, 172) má väčší vplyv podľa Cookovej vzdialenosti. Tieto pozorovania môžu výraznejšie ovplyvňovať odhad parametrov a je vhodné ich skontrolovať.

5.Analýza heteroskedasticity

Pri modelovaní tempa rastu populácie bola identifikovaná heteroskedasticita rezíduí, čo potvrdil aj Breusch–Paganov test. Rozptyl chýb sa zvyšuje pri extrémnych hodnotách rastu populácie. Na riešenie tohto problému boli použité robustné štandardné chyby, ktoré potvrdili štatistickú významnosť trendu poklesu tempa rastu populácie v čase.

library(dplyr)
library(tidyr)
library(ggplot2)
library(patchwork)

# 1️⃣ Preformátovanie dát do dlhého formátu
world_population_long <- world_population %>%
  select(Continent, Country.Territory, 
         X2022.Population, X2020.Population, X2015.Population, 
         X2010.Population, X2000.Population, X1990.Population, X1980.Population, X1970.Population) %>%
  pivot_longer(cols = starts_with("X"), 
               names_to = "Year", 
               values_to = "Population") %>%
  mutate(Year = as.numeric(gsub("X|\\.Population", "", Year))) %>%  # odstráni "X" a ".Population", zostáva rok
  group_by(Country.Territory) %>%
  arrange(Year) %>%
  mutate(GrowthRate = (Population / lag(Population) - 1) * 100) %>%
  ungroup() %>%
  filter(!is.na(GrowthRate))

# 2️⃣ Lineárny model
model <- lm(GrowthRate ~ Year, data = world_population_long)

# 3️⃣ Predikcie a reziduá
world_population_long$pred_model <- predict(model)
world_population_long$resid_model <- resid(model)

# 4️⃣ Grafy heteroskedasticity
p1 <- ggplot(world_population_long, aes(x = Year, y = resid_model^2)) +
  geom_point(alpha = 1, color = "steelblue") +
  geom_smooth(method = "loess", se = FALSE, color = "pink") +
  labs(x = "Rok", y = "Štvorce rezíduí", title = "Residuals² vs Rok") +
  theme_minimal()

p2 <- ggplot(world_population_long, aes(x = GrowthRate, y = resid_model^2)) +
  geom_point(alpha = 0.6, color = "lightblue") +
  geom_smooth(method = "loess", se = FALSE, color = "pink") +
  labs(x = "Tempo rastu populácie (%)", y = "Štvorce rezíduí", title = "Residuals² vs Growth Rate") +
  theme_minimal()

# 5️⃣ Zobrazenie oboch grafov vedľa seba
p1 + p2

Graf Residuals² vs Rok

ukazuje, že model predpovedá populáciu presne v rokoch medzi 1990 a 2020, ale má veľké odchýlky v roku 1980 a niektorých ďalších rokoch, čo naznačuje, že model nezachytáva všetky faktory ovplyvňujúce populáciu v týchto obdobiach.

Graf Residuals² vs Growth Rate

ukazuje, že model má väčšie chyby pri vyšších tempách rastu populácie. To naznačuje, že model nie je schopný presne predpovedať populáciu pri rýchlom raste, čo môže vyžadovať komplexnejší model pre obdobia s extrémnym rastom.

library(ggplot2)
library(patchwork)
model <- lm(GrowthRate ~ Continent, data = world_population_long)
world_population_long$resid_model <- resid(model)
p1 <- ggplot(world_population_long, aes(x = Year, y = resid_model^2)) +
  geom_point(alpha = 0.6, color = "grey") +
  geom_smooth(method = "loess", se = FALSE, color = "purple") +
  labs(x = "Rok", y = "Štvorce rezíduí", title = "Residuals² vs Rok") +
  theme_minimal() +
  theme(
  plot.background = element_rect(fill = "#f5f5dc", color = NA),  # béžová
  panel.background = element_rect(fill = "#f5f5dc", color = NA)
) 
p2 <- ggplot(world_population_long, aes(x = GrowthRate, y = resid_model^2)) +
  geom_point(alpha = 0.6, color = "lightblue") +
  geom_smooth(method = "loess", se = FALSE, color = "pink") +
  labs(x = "Tempo rastu populácie (%)", y = "Štvorce rezíduí", title = "Residuals² vs Growth Rate") +
  theme_minimal() +
  theme(
  plot.background = element_rect(fill = "#f5f5dc", color = NA),  # béžová
  panel.background = element_rect(fill = "#f5f5dc", color = NA)
) 
p1 + p2

Graf: Štvorce rezíduí vs Rok

V tomto grafe sledujeme, či sa veľkosť chýb modelu mení v čase. Fialová vyhladená krivka je takmer rovná, čo naznačuje, že rozptyl rezíduí je stabilný naprieč rokmi. To znamená, že premenná „rok“ pravdepodobne nespôsobuje heteroskedasticitu. Model teda v tomto smere neukazuje žiadny systematický problém.

Graf: Štvorce rezíduí vs Tempo rastu populácie

Tu skúmame, či veľkosť chýb závisí od tempa rastu populácie. Červená krivka má výrazný oblúkovitý tvar, čo naznačuje, že model robí väčšie chyby pri extrémnych hodnotách rastu. To je vizuálny náznak heteroskedasticity teda toho, že rozptyl rezíduí nie je konštantný. Tento problém potvrdzuje aj výsledok Breusch–Paganovho testu.

# 📦 Načítanie knižníc
library(dplyr)
library(tidyr)
library(ggplot2)
library(lmtest)
library(patchwork)

# 1️⃣ Preformátovanie dát do dlhého formátu
world_population_long <- world_population %>%
  select(Continent, Country.Territory, 
         X2022.Population, X2020.Population, X2015.Population, 
         X2010.Population, X2000.Population, X1990.Population, X1980.Population, X1970.Population) %>%
  pivot_longer(cols = starts_with("X"), 
               names_to = "Year", 
               values_to = "Population") %>%
  mutate(Year = as.numeric(gsub("X|\\.Population", "", Year))) %>%  # z názvu stĺpca vyber rok
  group_by(Country.Territory) %>%
  arrange(Year) %>%
  mutate(GrowthRate = (Population / lag(Population) - 1) * 100) %>%
  ungroup() %>%
  filter(!is.na(GrowthRate))

# 2️⃣ Vytvorenie lineárneho modelu
model <- lm(GrowthRate ~ Year, data = world_population_long)
summary(model)

Call:
lm(formula = GrowthRate ~ Year, data = world_population_long)

Residuals:
    Min      1Q  Median      3Q     Max 
-69.121  -7.491  -2.093   5.668 239.690 

Coefficients:
              Estimate Std. Error t value Pr(>|t|)    
(Intercept) 1087.20768   59.39472   18.30   <2e-16 ***
Year          -0.53527    0.02962  -18.07   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 17.63 on 1636 degrees of freedom
Multiple R-squared:  0.1664,    Adjusted R-squared:  0.1659 
F-statistic: 326.6 on 1 and 1636 DF,  p-value: < 2.2e-16
# 3️⃣ Breusch-Pagan test na heteroskedasticitu
bptest(model)

    studentized Breusch-Pagan test

data:  model
BP = 19.018, df = 1, p-value = 1.295e-05

Breusch–Paganov test overuje, či sa veľkosť chýb modelu mení v závislosti od vysvetľujúcich premenných – teda či je prítomná heteroskedasticita. Výsledok testu (BP = 19.018, p-hodnota < 0.001) naznačuje, že rozptyl rezíduí nie je konštantný. To znamená, že model robí systematicky väčšie chyby pri určitých hodnotách vstupných premenných. Takýto problém môže ovplyvniť spoľahlivosť odhadov a vyžaduje úpravu modelu.

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

# Load the package
library(lmtest)

model2 <- lm(GrowthRate ~ +1 + I(log(Year)),data=world_population_long)
summary(model2)

Call:
lm(formula = GrowthRate ~ +1 + I(log(Year)), data = world_population_long)

Residuals:
    Min      1Q  Median      3Q     Max 
-69.089  -7.493  -2.125   5.670 239.708 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept)   8153.92     450.83   18.09   <2e-16 ***
I(log(Year)) -1070.57      59.29  -18.06   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 17.63 on 1636 degrees of freedom
Multiple R-squared:  0.1662,    Adjusted R-squared:  0.1657 
F-statistic:   326 on 1 and 1636 DF,  p-value: < 2.2e-16
# Run the Breusch–Pagan test
bptest(model2)

    studentized Breusch-Pagan test

data:  model2
BP = 18.994, df = 1, p-value = 1.311e-05

Tento model skúma vzťah medzi rastom populácie a logaritmicky transformovaným rokom. Výsledky ukazujú, že log(Year) má silne negatívny a štatisticky významný vplyv na rast populácie. Napriek transformácii však Breusch–Paganov test (BP = 18.994, p < 0.001) stále naznačuje prítomnosť heteroskedasticity. To znamená, že rozptyl chýb sa mení a model by mohol byť ďalej upravený, napríklad použitím robustných metód.

#install.packages("sandwich")
#install.packages("lmtest")
library(sandwich)
library(lmtest)
coeftest(model, vcov = vcovHC(model))

t test of coefficients:

               Estimate  Std. Error t value  Pr(>|t|)    
(Intercept) 1087.207679   66.659480  16.310 < 2.2e-16 ***
Year          -0.535267    0.033097 -16.173 < 2.2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
library(zoo)
library(tseries)
library(lmtest)
library(sandwich)
library(car)
rm(list=ls())

Následne 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.

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)

Call:
lm(formula = Density..per.km.. ~ 1 + X2020.Population + Area..km.., 
    data = udaje)

Residuals:
    Min      1Q  Median      3Q     Max 
 -493.6  -417.8  -361.8  -217.8 22677.4 

Coefficients:
                   Estimate Std. Error t value Pr(>|t|)    
(Intercept)       4.948e+02  1.434e+02   3.452 0.000662 ***
X2020.Population  2.622e-08  1.124e-06   0.023 0.981404    
Area..km..       -7.495e-05  8.647e-05  -0.867 0.386995    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 2071 on 231 degrees of freedom
Multiple R-squared:  0.003987,  Adjusted R-squared:  -0.004636 
F-statistic: 0.4624 on 2 and 231 DF,  p-value: 0.6304

Zostavila som lineárny model, v ktorom som hustotu obyvateľstva vysvetľovala pomocou populácie v roku 2020 a rozlohy územia. Cieľom bolo overiť, či tieto dve premenné dokážu štatisticky významne vysvetliť rozdiely v hustote obyvateľstva medzi krajinami.

Z výsledkov vidím, že ani populácia, ani rozloha územia nemajú v tomto modeli štatisticky významný vplyv na hustotu obyvateľstva. Hodnoty p-value sú pri oboch premenných veľmi vysoké, čo znamená, že ich vplyv na vysvetľovanú premennú sa v tomto modeli nepotvrdil.

Teda na základe našej doterajšej analýzy vieme povedať, že počet obyvateľov v roku 2020 a rozloha územia nemajú štatisticky významný vplyv na hustotu obyvateľstva v tomto modeli, čo naznačuje, že tieto faktory nie sú dôležité pre vysvetlenie hustoty obyvateľstva v tomto prípade.

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.

6.Klastrová analýza európskych krajín

Pre ďalšiu analýzu sme si tentokrát z našej databázy vytiahli všetky európske štáty.

Pomocou hierarchického zhlukovania (Ward.D2) boli európske krajiny rozdelené do troch klastrov:

Klaster 1: menšie a stredne veľké krajiny s vyššou hustotou obyvateľstva, Klaster 2: veľké krajiny s vysokou populáciou a strednou hustotou, Klaster 3: veľmi veľké krajiny s nízkou hustotou obyvateľstva.

Táto analýza nám umožnila identifikovať štrukturálne podobnosti medzi krajinami a lepšie pochopiť regionálne rozdiely v demografii.

rm(list = ls())
udaje <- read.csv("world_population.csv", stringsAsFactors = FALSE)

# výber kontinentov podľa tvojich údajov
kontinenty <- c("Europe")

udaje2020 <- subset(udaje, Continent %in% kontinenty)

# výber stĺpcov, ktoré v databáze existujú
udaje2020 <- udaje2020[, c("Country.Territory",
                           "X2020.Population",
                           "Area..km..",
                           "Density..per.km..",
                           "Growth.Rate")]

# zmena názvu riadkov
rownames(udaje2020) <- udaje2020$Country.Territory
udaje2020$Country.Territory <- NULL

udaje2020
NA
udaje_complete <- na.omit(udaje2020)
udaje_scaled <- scale(udaje_complete)
num_vars <- as.data.frame(udaje_scaled)
num_plots <- ncol(num_vars)
par(mfrow = c(ceiling(sqrt(num_plots)), ceiling(num_plots / ceiling(sqrt(num_plots)))))
par(mar = c(4, 4, 2, 1))
for (col in names(num_vars)) {
  boxplot(num_vars[[col]],
          main = col,
          col = "lightpink",
          horizontal = TRUE)}
mtext("Boxploty numerických premenných (rok 2020)", outer = TRUE, cex = 1.3, font = 2)

Tento graf nám ukazuje rozdelenie štyroch premenných európskych štátov po logaritmickej transformácii: populácie, rozlohy, hustoty obyvateľstva a miery rastu. Vidíme, že populácia, rozloha aj hustota majú väčšinou nízke až stredné hodnoty, no zároveň obsahujú výrazné odľahlé hodnoty, čo znamená prítomnosť veľkých alebo veľmi hustých krajín. Miera rastu populácie je zväčša blízko nule, avšak niektoré štáty vykazujú výraznejší pokles alebo nárast.

dist_mat <- dist(udaje2020, method = "euclidean")
hc <- hclust(dist_mat, method = "ward.D2")
plot(hc, labels = rownames(udaje_scaled),
     main = "Hierarchical klastering of countries (Ward.D2)",
     xlab = "", sub = "")
k <- 3
h_cut <- hc$height[length(hc$height) - (k - 1)]
abline(h = h_cut, col = "pink", lwd = 6, lty = 6)

klaster_membership <- cutree(hc, k = k)
udaje_klasters <- data.frame(
  Country = rownames(udaje_complete),
  udaje_complete,
  klaster = factor(klaster_membership))

Tento dendrogram nám zobrazuje výsledky hierarchického zhlukovania európskych krajín na základe vybraných charakteristík pomocou metódy Ward.D2.Vidíme, že krajiny sa delia do niekoľkých výrazných skupín podľa podobnosti v analyzovaných dátach. Niektoré krajiny sú veľmi blízko seba, čo znamená, že majú podobné hodnoty premenných, zatiaľ čo iné tvoria samostatné, odlišné klastre.Prerušovaná červená čiara predstavuje prah, podľa ktorého môžeme určiť počet zhlukov. Pod týmto prahom sa krajiny rozdeľujú do viacerých skupín, ktoré môžeme ďalej skúmať, napríklad na základe podobnej hustoty obyvateľstva, veľkosti alebo populácie.Tento výsledok nám umožňuje lepšie porozumieť štruktúre dát a identifikovať prirodzené zoskupenia krajín v Európe, čo je užitočné pre ďalšie analýzy a porovnania.

data_prac <- data.frame(cbind(udaje_klasters$Country, udaje_klasters$klaster))
colnames(data_prac) <- c("Country","klaster")
data_prac
udaje2020 <- data.frame(
  udaje2020,
  klaster = udaje_klasters$klaster)
library(dplyr)
descriptives <- udaje2020 %>%
  group_by(klaster) %>%
  summarise(
    across(
      .cols = where(is.numeric),
      .fns = list(
        mean = ~mean(.x, na.rm = TRUE)),
      .names = "{.col}_{.fn}"))
descriptives

7.Predikcia budúcej populácie

V poslednej časti práce bola vykonaná jednoduchá predikcia populácie na roky 2025 a 2030 na základe historickej populácie a miery rastu.

# Load data
udaje <- read.csv("world_population.csv", dec=".", sep=",", header = TRUE)
udaje_pred <- udaje[, c("Country.Territory","X2020.Population", "X2015.Population",
                        "Growth.Rate", "Continent")]
numeric_cols <- c("X2020.Population", "X2015.Population", "Growth.Rate")
column_medians <- sapply(udaje_pred[, numeric_cols], median, na.rm = TRUE)
for (col in numeric_cols) {
  udaje_pred[[col]][is.na(udaje_pred[[col]])] <- column_medians[col]}
udaje_pred$log_pop <- log(udaje_pred$X2020.Population)
udaje_pred$log_pop15 <- log(udaje_pred$X2015.Population)
udaje <- udaje_pred

Čo skúmame: - Pripravujeme dáta na predikciu budúcej populácie. - Chýbajúce hodnoty dopĺňame mediánom, aby model fungoval správne. - Log-transformácia populácie stabilizuje extrémne rozdiely medzi malými a veľkými krajinami.

Pre budúcu populáciu nás najviac zaujíma historická populácia a rast

# Pre budúcu populáciu nás najviac zaujíma historická populácia a rast
xvars <- udaje[, c("X2015.Population", "Growth.Rate")]
round(cor(xvars), 3)
                 X2015.Population Growth.Rate
X2015.Population            1.000      -0.032
Growth.Rate                -0.032       1.000

Scatterplotová matica – historická populácia a Growth Rate

Vizualizujeme vzťah medzi historickou populáciou a rastom a pozrieme sa, či existujú extrémne hodnoty alebo netypické krajiny.

Ako môžme vidieť, väčšina krajín sa nachádza v stabilnom pásme rastu, niektoré majú extrémne hodnoty, ktoré môžu ovplyvniť predikciu.

pairs(xvars, main = "Scatterplotová matica – historická populácia a Growth Rate")

model_pred <- lm(log_pop ~ log_pop15 + Growth.Rate + Continent, data = udaje)
# Spätná transformácia na počet obyvateľov
udaje$pred_pop2020 <- exp(predict(model_pred, newdata = udaje))
# Predikcia podľa Growth.Rate
udaje$pred_pop2025 <- udaje$X2020.Population * (1 + udaje$Growth.Rate)^5
udaje$pred_pop2030 <- udaje$X2020.Population * (1 + udaje$Growth.Rate)^10
# --- Výber konkrétnych krajín ---
vybrane_krajiny <- c("Slovakia", 
                     "Czech Republic", 
                     "Hungary", 
                     "Austria", 
                     "Ukraine", 
                     "Poland")
# Filtrovanie podľa názvu krajiny
udaje_vybrane <- udaje[udaje$Country.Territory %in% vybrane_krajiny, ]
# --- Zobrazenie výsledku ---
udaje_vybrane[, c("Country.Territory", 
                  "X2020.Population", 
                  "pred_pop2020", 
                  "pred_pop2025", 
                  "pred_pop2030")]

Predikujeme populáciu do budúcnosti (2025 a 2030) pomocou Growth.Rate. Umožňuje nám odhadnúť rast a porovnať ho medzi krajinami.

Keď sa pozrieme na naše výsledky, vidíme, že východiskové hodnoty populácie v roku 2020 zodpovedajú reálnym počtom obyvateľov v jednotlivých krajinách. Model však pri dlhodobej predikcii (najmä smerom k roku 2030) generuje extrémne vysoké čísla. Toto sa deje preto, že sme použili jednoduchý výpočet založený na exponenciálnom raste, ktorý pri dlhšom období veľmi preháňa výsledky.

V krátkodobom horizonte (do roku 2025) sú predpovede ešte relatívne podobné realite – populácia sa mení len mierne. V dlhodobom horizonte (rok 2030) už model predpovedá nereálne vysoký nárast, takže tieto čísla nevnímame ako skutočnú predpoveď, ale skôr ako ukážku toho, ako rýchlo vie populácia narásť, keď necháme v modeli pôsobiť rastovú mieru bez obmedzenia.

Krajinám môžeme pripísať tieto trendy:

Slovensko, Česko, Rakúsko, Maďarsko a Poľsko – krátkodobo stabilné, bez veľkých zmien.

Ukrajina – krátkodobo skôr pokles, čo zodpovedá realite.

Zistenia

-> krátkodobé predikcie (do roku 2025) sú relatívne stabilné, ->dlhodobé predikcie generujú extrémne vysoké hodnoty v dôsledku exponenciálneho charakteru modelu.

Tieto výsledky preto neinterpretujeme ako realistickú prognózu, ale ako ilustráciu citlivosti modelu na rastovú mieru.

8.Záver

Analýza vývoja populácie Slovenskej republiky a Českej republiky ukázala, že v sledovanom období dochádza v oboch krajinách k relatívne stabilnému demografickému vývoju, bez výrazných výkyvov v celkovom počte obyvateľov. Napriek podobnému trendu je rozdiel v absolútnej veľkosti populácie medzi týmito krajinami výrazný a dlhodobo pretrvávajúci, čo odráža ich odlišnú historickú a demografickú trajektóriu.

Analýza hustoty obyvateľstva potvrdila, že tento ukazovateľ nie je možné jednoducho vysvetliť len pomocou veľkosti populácie alebo rozlohy krajiny. Výsledky naznačujú, že hustota obyvateľstva je ovplyvnená širším spektrom faktorov, ako sú geografické podmienky, úroveň urbanizácie, ekonomická štruktúra či historický vývoj osídlenia. Jednoduché lineárne modely preto nedokážu plne zachytiť komplexnosť tohto javu.

Použité štatistické a regresné modely sa ukázali ako vhodné nástroje na deskriptívnu analýzu a krátkodobé porovnanie demografických trendov medzi krajinami. Pri pokusoch o dlhodobejšiu predikciu populácie sa však prejavili ich výrazné obmedzenia, najmä citlivosť na zvolenú mieru rastu a predpoklad konštantného trendu v čase. Pre realistickejšie prognózy by bolo potrebné uplatniť sofistikovanejšie demografické prístupy, ktoré zohľadňujú vekovú štruktúru obyvateľstva, migračné toky a fertilitu.

Napriek uvedeným obmedzeniam práca poskytuje ucelený pohľad na základné demografické rozdiely a podobnosti medzi vybranými krajinami Európy. Zároveň poukazuje na limity jednoduchých štatistických modelov pri analýze populačných procesov a zdôrazňuje potrebu opatrnej interpretácie výsledkov, najmä pri ich využití na predikčné účely.

LS0tCnRpdGxlOiAiVsO9dm9qIHBvcHVsw6FjaWUgU2xvdmVuc2tlaiByZXB1Ymxpa3kgdiBwb3Jvdm5hbsOtIHMgaW7DvW1pIMWhdMOhdG1pIEXDmiIKYXV0aG9yOiAiQmFyYm9yYSBLdWNow6FyaWtvdsOhICA8YnI+IgpkYXRlOiAiT2t0w7NiZXIgMjAyNSIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgdGhlbWU6IHVuaXRlZAogICAgaGlnaGxpZ2h0OiB0YW5nbwogICAgY3NzOiBjdXN0b20uY3NzCiAgaHRtbF9kb2N1bWVudDoKICAgIHRvYzogdHJ1ZQogICAgZGZfcHJpbnQ6IHBhZ2VkCiAgcGRmX2RvY3VtZW50OgogICAgdG9jOiB0cnVlCmVkaXRvcl9vcHRpb25zOgogIG1hcmtkb3duOgogICAgd3JhcDogNzIKLS0tCgoKIyDDmnZvZCBhIHByZWRzdGF2ZW5pZSBkYXRhYsOhenkKCkNpZcS+b20gcHLDoWNlIGplIGFuYWx5em92YcWlICoqdsO9dm9qIHBvcHVsw6FjaWUgU2xvdmVuc2tlaiByZXB1Ymxpa3kqKiB2IHBvcm92bmFuw60gcyB2eWJyYW7DvW1pIMWhdMOhdG1pIEV1csOzcHNrZWogw7puaWUsIHByZWRvdsWhZXRrw71tIHMgxIxlc2tvdSByZXB1Ymxpa291LiBBbmFsw716YSB2eXXFvsOtdmEgZGF0YWLDoXp1ICoqV29ybGRfUG9wdWxhdGlvbioqLCBrdG9yw6Egb2JzYWh1amUgc8O6aHJubsOpIGRlbW9ncmFmaWNrw6kgw7pkYWplIG8ga3Jhamluw6FjaCBzdmV0YS4KCiMgMS5aw6FrbGFkbsOhIGNoYXJha3RlcmlzdGlrYSBkYXRhYsOhenk6ICMjCgoqKkRhdGFiw6F6YSB6aHJvbWHFvsSPdWplIG5hcHLDrWtsYWQgw7pkYWplIG86KioKCi0gcG/EjXRlIG9ieXZhdGXEvm92IGplZG5vdGxpdsO9Y2gga3JhasOtbi9rb250aW5lbnRvdiwKLSByb3psb2hlIMO6emVtaWEsCi0gaHVzdG90ZSBvYnl2YXRlxL5zdHZhLAotIHJvxI1ub20gcHLDrXJhc3RrdSBhbGVibyDDumJ5dGt1IHBvcHVsw6FjaWUsCi0gcm9rdSB6w6F6bmFtdQoKVGlldG8gw7pkYWplIHVtb8W+xYh1asO6IHBvcm92bmFuaWUgZGVtb2dyYWZpY2vDqWhvIHbDvXZvamEgbWVkemkga3JhamluYW1pIGEgaWRlbnRpZmlrw6FjaXUgesOha2xhZG7DvWNoIHRyZW5kb3YuCmBgYHtyfQpoZWFkKHdvcmxkX3BvcHVsYXRpb24pICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgbmlla29sa28gcHJ2eWNoIHJpYWRrb3YKY29sbmFtZXMod29ybGRfcG9wdWxhdGlvbikKCmBgYAojIDIuUG9yb3ZuYW5pZSBTbG92ZW5za2EgYSDEjGVza2VqIHJlcHVibGlreSAoMTk4MOKAkzIwMjApCgpQcmUgbmHFoWUgc2vDum1hbmllIHNpIHogZGF0YWLDoXp5IHdvcmxkIHBvcHVsYXRpb24gbmEgemHEjWlhdG9rIHZ5YmVyw6FtZSBrcmFqaW55IFNsb3ZlbnNrbyBhIMSMZXNrw7ogcmVwdWJsaWt1LiBOw6FzbGVkbmUgcG96b3J1amVtZSByb2t5IDE5ODAtMjAyMCBha28gc2Egdnl2w61qYWxhIHBvcHVsw6FjaWEgYSB0ZWRhIHBvxI1ldCBvYnl2YXRlxL5vdiB2IHByaWViZWh1IHTDvWNodG8gcm9rb3YuCgpgYGB7cn0KbGlicmFyeShnZ3Bsb3QyKQpTVktfQ1pFX2RhdGEgPC0gd29ybGRfcG9wdWxhdGlvbiAlPiUKICBmaWx0ZXIoQ0NBMyAlaW4lIGMoIlNWSyIsICJDWkUiKSkgJT4lICAjIEZpbHRyb3ZhbmllIG5hIFNsb3ZlbnNrbyBhIMSMZXNrbwogIHNlbGVjdChDQ0EzLCAiWDIwMjAuUG9wdWxhdGlvbiIsICJYMjAxMC5Qb3B1bGF0aW9uIiwgIlgyMDAwLlBvcHVsYXRpb24iLCAiWDE5OTAuUG9wdWxhdGlvbiIsICJYMTk4MC5Qb3B1bGF0aW9uIikgIyBWeWJlcsOhbWUgbGVuIHJlbGV2YW50bsOpIHN0xLpwY2UKaGVhZChTVktfQ1pFX2RhdGEpCmBgYAoKIyMjIyAqKlNjYXR0ZXIgcGxvdCoqCmBgYHtyfQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHRpZHlyKQpsaWJyYXJ5KGdncGxvdDIpCgojIFByZWRwb2tsYWTDoW0sIMW+ZSBkYXRhc2V0IGplIHVsb8W+ZW7DvSB2IHByZW1lbm5laiBgU1ZLX0NaRV9kYXRhYAoKIyAxLiBWeWJlcmllbWUgcG90cmVibsOpIHN0xLpwY2UgYSBkw6F0YSBsZW4gcHJlIFNsb3ZlbnNrbyBhIMSMZXNrbwpTVktfQ1pFX3NlbCA8LSBTVktfQ1pFX2RhdGEgJT4lCiAgZmlsdGVyKENDQTMgJWluJSBjKCJTVksiLCAiQ1pFIikpICU+JSAgIyBGaWx0cm92YW5pZSBuYSBTbG92ZW5za28gYSDEjGVza28KICBzZWxlY3QoQ0NBMywgIlgyMDIwLlBvcHVsYXRpb24iLCAiWDIwMTAuUG9wdWxhdGlvbiIsICJYMjAwMC5Qb3B1bGF0aW9uIiwgIlgxOTkwLlBvcHVsYXRpb24iLCAiWDE5ODAuUG9wdWxhdGlvbiIpICAjIFZ5YmVyw6FtZSBsZW4gcmVsZXZhbnRuw6kgc3TEunBjZQoKIyAyLiBQcmVtZW7DrW1lIGTDoXRhIGRvIGRsaMOpaG8gZm9ybcOhdHUgKHByZSBncmFmKQpTVktfQ1pFX2xvbmcgPC0gU1ZLX0NaRV9zZWwgJT4lCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBjKCJYMjAyMC5Qb3B1bGF0aW9uIiwgIlgyMDEwLlBvcHVsYXRpb24iLCAiWDIwMDAuUG9wdWxhdGlvbiIsICJYMTk5MC5Qb3B1bGF0aW9uIiwgIlgxOTgwLlBvcHVsYXRpb24iKSwKICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAieWVhciIsICAgICAjIFN0xLpwZWMgcyByb2ttaQogICAgICAgICAgICAgICB2YWx1ZXNfdG8gPSAicG9wdWxhdGlvbiIpICAjIFN0xLpwZWMgcyBwb3B1bMOhY2lvdQoKIyAzLiBWeXR2b3LDrW1lIHN0xLpwY292w70gZ3JhZiAtIFpvYnJhesOtbWUgcG9wdWzDoWNpdSBTbG92ZW5za2EgYSDEjGVza2EgdiByb2tvY2ggMTk4MCwgMTk5MCwgMjAwMCwgMjAxMCBhIDIwMjAKZ2dwbG90KFNWS19DWkVfbG9uZywgYWVzKHggPSB5ZWFyLHkgPSBwb3B1bGF0aW9uLCBmaWxsID0gQ0NBMywgZ3JvdXAgPSBDQ0EzKSkgKyBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSAiZG9kZ2UiLCB3aWR0aCA9IDAuOCkgKyAjIFN0xLpwY292w70gZ3JhZiBzIG9kZGVsZW7DvW1pIHN0xLpwY2FtaSBwcmUga2HFvmTDuiBrcmFqaW51IAogIGdlb21fdGV4dChhZXMobGFiZWwgPSBwb3B1bGF0aW9uKSwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuMyksIHZqdXN0ID0gLTAuMSkgKyAjIFByaWRhbmllIG96bmHEjWVuw60gaG9kbsO0dCAKICB0aGVtZV9taW5pbWFsKCkgKyAjIE1pbmltYWxpc3RpY2vDvSBkaXpham4gZ3JhZnUgCiAgbGFicyh0aXRsZSA9ICJWw712b2ogcG9wdWzDoWNpZSBTbG92ZW5za2EgYSDEjGVza2EiLCAjIFVwcmF2ZW7DvSBuYWRwaXMgCiAgICAgICB4ID0gIlJvayIsIAogICAgICAgeSA9ICJQb3B1bMOhY2lhIiwgCiAgICAgICBmaWxsID0gIktyYWppbmEiKSArICMgUG9waXMgZmFyaWViIHBvZMS+YSBrcmFqaW55IAogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMzAsIGhqdXN0ID0gMSkpICMgUm90w6FjaWEgdGV4dHUgbmEgb3NpIFgKYGBgCiooVGVudG8gZ3JhZiBtw6EgZGVza3JpcHTDrXZueSBjaGFyYWt0ZXIgYSBzbMO6xb5pIG5hIGlsdXN0csOhY2l1IHrDoWtsYWRuw71jaCByb3pkaWVsb3YgbWVkemkga3JhamluYW1pLikqCgpPYmUga3JhamlueSB2eWthenVqw7ogdiBzbGVkb3Zhbm9tIG9iZG9iw60gbWllcm55IHJhc3QgcG9wdWzDoWNpZS4KCsSMZXNrw6EgcmVwdWJsaWthIG3DoSBwb8SNYXMgY2Vsw6lobyBvYmRvYmlhIHZ5xaHFocOtIHBvxI1ldCBvYnl2YXRlxL5vdiBuZcW+IFNsb3ZlbnNrby4KLT4gdiDEjGVza3UgbW/Fvm5vIHBvem9yb3ZhxaUgbWllcm55IHBva2xlcyBwb3B1bMOhY2llIHYgb2Jkb2LDrSAxOTkw4oCTMjAwMCwga3RvcsO9IG3DtMW+ZSBzw7p2aXNpZcWlIHMgZGVtb2dyYWZpY2vDvW1pIGEgc3BvbG/EjWVuc2vDvW1pIHptZW5hbWkgcG8gcm9rdSAxOTg5LgoKCmBgYHtyfQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KGtuaXRyKQoKIyAxLiBWeWJlcmllbWUgcG90cmVibsOpIHN0xLpwY2UgYSBkw6F0YSBsZW4gcHJlIFNsb3ZlbnNrbyBhIMSMZXNrbwpTVktfQ1pFX3NlbCA8LSBTVktfQ1pFX2RhdGEgJT4lCiAgZmlsdGVyKENDQTMgJWluJSBjKCJTVksiLCAiQ1pFIikpICU+JSAgIyBGaWx0cm92YW5pZSBuYSBTbG92ZW5za28gYSDEjGVza28KICBzZWxlY3QoQ0NBMywgIlgyMDIwLlBvcHVsYXRpb24iLCAiWDIwMTAuUG9wdWxhdGlvbiIsICJYMjAwMC5Qb3B1bGF0aW9uIiwgIlgxOTkwLlBvcHVsYXRpb24iLCAiWDE5ODAuUG9wdWxhdGlvbiIpICAjIFJlbGV2YW50bsOpIHN0xLpwY2UKCiMgMi4gUHJlbWVuw61tZSBkw6F0YSBkbyBkbGjDqWhvIGZvcm3DoXR1ClNWS19DWkVfbG9uZyA8LSBTVktfQ1pFX3NlbCAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IGMoIlgyMDIwLlBvcHVsYXRpb24iLCAiWDIwMTAuUG9wdWxhdGlvbiIsICJYMjAwMC5Qb3B1bGF0aW9uIiwgIlgxOTkwLlBvcHVsYXRpb24iLCAiWDE5ODAuUG9wdWxhdGlvbiIpLAogICAgICAgICAgICAgICBuYW1lc190byA9ICJ5ZWFyIiwKICAgICAgICAgICAgICAgdmFsdWVzX3RvID0gInBvcHVsYXRpb24iKQojIDMuIFZ5cG/EjcOtdGFtZSB6w6FrbGFkbsOpIMWhdGF0aXN0aWt5IHBvcHVsw6FjaWUgcG9kxL5hIGtyYWppbnkgYSByb2t1ClNWS19DWkVfc3RhdHMgPC0gU1ZLX0NaRV9sb25nICU+JQogIGdyb3VwX2J5KENDQTMsIHllYXIpICU+JQogIHN1bW1hcmlzZSgKICAgIG4gICAgICA9IG4oKSwKICAgIG1lYW4gICA9IG1lYW4ocG9wdWxhdGlvbiwgbmEucm0gPSBUUlVFKSwKICAgIHNkICAgICA9IHNkKHBvcHVsYXRpb24sIG5hLnJtID0gVFJVRSksCiAgICBtaW4gICAgPSBtaW4ocG9wdWxhdGlvbiwgbmEucm0gPSBUUlVFKSwKICAgIHEyNSAgICA9IHF1YW50aWxlKHBvcHVsYXRpb24sIDAuMjUsIG5hLnJtID0gVFJVRSksCiAgICBtZWRpYW4gPSBtZWRpYW4ocG9wdWxhdGlvbiwgbmEucm0gPSBUUlVFKSwKICAgIHE3NSAgICA9IHF1YW50aWxlKHBvcHVsYXRpb24sIDAuNzUsIG5hLnJtID0gVFJVRSksCiAgICBtYXggICAgPSBtYXgocG9wdWxhdGlvbiwgbmEucm0gPSBUUlVFKSwKICAgIC5ncm91cHMgPSAiZHJvcCIKICApCiMgNC4gVnl0dm9yw61tZSB0YWJ1xL5rdSBwb21vY291IGtuaXRyCmthYmxlKFNWS19DWkVfc3RhdHMsIGRpZ2l0cyA9IDAsIGNhcHRpb24gPSAiWsOha2xhZG7DqSDFoXRhdGlzdGlreSBwb3B1bMOhY2llIFNsb3ZlbnNrYSBhIMSMZXNrYSAoMTk4MOKAkzIwMjApIikKYGBgCgojIyMgKipIbGF2bsOpIHppc3RlbmlhOioqCgoqKlJhc3QgcG9wdWzDoWNpZToqKiBPYmlkdmUga3JhamlueSB2eWthenVqw7ogcG96aXTDrXZueSB0cmVuZCByYXN0dSBwb3B1bMOhY2llIG9kIHJva3UgMTk4MCBkbyByb2t1IDIwMjAsIMSNbyBtw7TFvmUgbmF6bmHEjW92YcWlIHN0YWJpbG7DvSBkZW1vZ3JhZmlja8O9IHbDvXZvaiwgYWxlYm8gbGVuIHZlxL5taSBwb21hbMO9IHJhc3QuCgoqKk1lZHplcnkgdiBkeW5hbWlrZToqKiBNaWVybnkgcG9rbGVzIHYgcG9wdWzDoWNpaSDEjGVza2EgbWVkemkgMTk5MCBhIDIwMDAgbcO0xb5lIGJ5xaUgc3DDtHNvYmVuw70gcsO0em55bWkgZmFrdG9ybWkgKG5hcHIuIGVtaWdyw6FjaWEsIHBva2xlcyBuYXRhbGl0eSBhIHBvZC4pIGEgbcO0xb5lIHNpIHZ5xb5hZG92YcWlIGhsYsWhaXUgYW5hbMO9enUsIMSNaSB1xb4gdiBrb250ZXh0ZSBla29ub21pY2vDvWNoIGFsZWJvIHBvbGl0aWNrw71jaCB6bWllbiB2IHRlaiBkb2JlLgoKKipQb3Jvdm5hbmllIGtyYWrDrW46KiogUG/EjWV0IG9ieXZhdGXEvm92IMSMZXNrYSBib2wgdiBwcmllYmVodSByb2tvdiB2xb5keSB2ecWhxaHDrSBuZcW+IHBvxI1ldCBvYnl2YXRlxL5vdiBTbG92ZW5za2EsIMSNbyBqZSBvxI1ha8OhdmFuw6kgdnpoxL5hZG9tIG5hIHZlxL5rb3PFpSBvYm9jaCBrcmFqw61uICjEjGVza8OhIHJlcHVibGlrYSBtw6EgdsOkxI3FoWl1IHBvcHVsw6FjaXUgbmXFviBTbG92ZW5za28pLgoKCiMgMy5Qb3Jvdm5hbmllIHBvcHVsw6FjaWUgU2xvdmVuc2thIGEgxIxlc2thIHYgcm9rb2NoIDIwMjAKCiMjIyDFoHRhdGlzdGlja8OpIHRlc3RvdmFuaWUg4oCTIG1ldG9kaWNrw6kgb2JtZWR6ZW5pYQoqTmEgcG9yb3ZuYW5pZSBwb3B1bMOhY2nDrSBTbG92ZW5za2EgYSDEjGVza2VqIHJlcHVibGlreSBib2wgdnlrb25hbsO9IHQtdGVzdCBhIGplZG5vZHVjaMOhIGFuYWzDvXphIHJvenB0eWx1IChBTk9WQSkuIFRpZXRvIHRlc3R5IHPDuiB2xaFhayBwb3XFvml0w6kgbGVuIGlsdXN0cmF0w612bmUsIHByZXRvxb5lIHBvem9yb3ZhbmlhIHYgamVkbm90bGl2w71jaCByb2tvY2ggbmllIHPDuiBuZXrDoXZpc2zDqSBhIHR2b3JpYSDEjWFzb3bDvSByYWQuIFogdG9odG8gZMO0dm9kdSB2w71zbGVka3kgdC10ZXN0dSBhIEFOT1ZBIG5laW50ZXJwcmV0dWplbWUgYWtvIGluZmVyZW7EjW7DvSBkw7RrYXosIGFsZSBsZW4gYWtvIHBvdHZyZGVuaWUgdsO9cmF6bsOpaG8gcm96ZGllbHUgdiDDunJvdm5pIHBvcHVsw6FjaWUgbWVkemkga3JhamluYW1pLioKYGBge3J9CiMgMS4gVnliZXJpZW1lIHBvcHVsw6FjaXUgU2xvdmVuc2thIGEgxIxlc2thIHYgcm9rdSAyMDIwClNWS19DWkVfMjAyMCA8LSBTVktfQ1pFX2RhdGEgJT4lCiAgZmlsdGVyKENDQTMgJWluJSBjKCJTVksiLCAiQ1pFIikpICU+JQogIHNlbGVjdChDQ0EzLCAiWDIwMjAuUG9wdWxhdGlvbiIpCiMgMi4gVnlrb27DoW1lIHQtdGVzdCBuYSBwb3Jvdm5hbmllIHBvcHVsw6FjaWUgbWVkemkgU1ZLIGEgQ1pFIHYgcm9rdSAyMDIwClNWS19wb3AgPC0gU1ZLX0NaRV9sb25nICU+JSBmaWx0ZXIoQ0NBMyA9PSAiU1ZLIikgJT4lIHB1bGwocG9wdWxhdGlvbikKQ1pFX3BvcCA8LSBTVktfQ1pFX2xvbmcgJT4lIGZpbHRlcihDQ0EzID09ICJDWkUiKSAlPiUgcHVsbChwb3B1bGF0aW9uKQojIDMuIFbDvXBpcyB2w71zbGVka3UgdGVzdHUKdF90ZXN0X3Jlc3VsdCA8LSB0LnRlc3QoU1ZLX3BvcCwgQ1pFX3BvcCkKcHJpbnQodF90ZXN0X3Jlc3VsdCkKYGBgClJvemRpZWwgdiBwb3B1bMOhY2nDoWNoIG1lZHppIFNsb3ZlbnNrb20gYSDEjGVza29tICpqZSDFoXRhdGlzdGlja3kgdsO9em5hbW7DvSouIFAtaG9kbm90YSBqZSBleHRyw6ltbmUgbsOtemthICgzLjY1NSDDlyAxMOKBu8K54oGwKSwgxI1vIHpuYW1lbsOhLCDFvmUgcm96ZGllbCBtZWR6aSBwcmllbWVybsO9bWkgcG9wdWzDoWNpYW1pIHTDvWNodG8gZHZvY2gga3JhasOtbiBuaWUgamUgbsOhaG9kbsO9LgoKKlByaWVtZXJuw6EgcG9wdWzDoWNpYSogxIxlc2thIGplIG92ZcS+YSB2ecWhxaFpYSBuZcW+IHBvcHVsw6FjaWEgU2xvdmVuc2thLCDEjW8gamUgb8SNYWvDoXZhbsOpIHZ6aMS+YWRvbSBuYSB2ZcS+a29zxaUgb2JvY2gga3JhasOtbi4KCio5NSUgaW50ZXJ2YWwqIHNwb8S+YWhsaXZvc3RpIG5hem5hxI11amUsIMW+ZSBza3V0b8SNbsO9IHJvemRpZWwgbWVkemkgcHJpZW1lcm7DvW1pIHBvcHVsw6FjaWFtaSBzYSBwb2h5YnVqZSBtZWR6aSBwcmlibGnFvm5lIDQsOCBtaWxpw7NubWkgYSA1LDMgbWlsacOzbm1pIG9ieXZhdGXEvm92IHYgcHJvc3BlY2ggxIxlc2thLgoKCk5hIHrDoWtsYWRlIHRvaHRvIHRlc3R1IG3DtMW+ZW1lIGplZG5vem5hxI1uZSBwb3ZlZGHFpSwgxb5lIG1lZHppIHBvcHVsw6FjaWFtaSBTbG92ZW5za2EgYSDEjGVza2EgamUgKirFoXRhdGlzdGlja3kgdsO9em5hbW7DvSByb3pkaWVsLioqIFRlbnRvIHJvemRpZWwgamUgdmXEvm1pIHZ5c29rw70gYSBuZWV4aXN0dWplIMW+aWFkbmEgcHJhdmRlcG9kb2Jub3PFpSwgxb5lIGJ5IHRlbnRvIHJvemRpZWwgYm9sIHNww7Rzb2JlbsO9IG7DoWhvZG91LgoKIyMjICoqKkFOT1ZBKioqCgpgYGB7cn0KYW5vdmFfcmVzdWx0IDwtIGFvdihwb3B1bGF0aW9uIH4geWVhciwgZGF0YSA9IFNWS19DWkVfbG9uZykKc3VtbWFyeShhbm92YV9yZXN1bHQpCmBgYApWw71zbGVka3kgYW5hbMO9enkgcm96cHR5bHUgKEFOT1ZBKSBuYXpuYcSNdWrDuiwgxb5lIG1lZHppIHByaWVtZXJuw71taSBwb3B1bMOhY2lhbWkgU2xvdmVuc2thIGEgxIxlc2thIHYgcm9rb2NoIDE5ODAsIDE5OTAsIDIwMDAsIDIwMTAgYSAyMDIwIG5lZXhpc3R1amUgxaF0YXRpc3RpY2t5IHbDvXpuYW1uw70gcm96ZGllbC4KCioqRi1ob2Rub3RhOiAwLjAwMyoqCioqUC1ob2Rub3RhOiAxKioKCk5hIHrDoWtsYWRlIHTDvWNodG8gdsO9c2xlZGtvdiAqbmVtw7TFvmVtZSBvZG1pZXRudcWlIG51bG92w7ogaHlwb3TDqXp1KiwgxI1vIHpuYW1lbsOhLCDFvmUgeiBoxL5hZGlza2EgdMO9Y2h0byBkw6F0IG5lZXhpc3R1amUgZMO0a2F6IG8gcm96ZGllbG9jaCBtZWR6aSBwb3B1bMOhY2lhbWkgdiBqZWRub3RsaXbDvWNoIHJva29jaC4KClRpZXRvIHbDvXNsZWRreSBuYXpuYcSNdWrDuiBzdGFiaWxpdHUgcG9wdWzDoWNpZSB2IHNsZWRvdmFub20gb2Jkb2LDrSAoMTk4MOKAkzIwMjApLCBwcmnEjW9tIHBvcHVsw6FjaWUgb2JvY2gga3JhasOtbiBzYSB2eXbDrWphbGkgcmVsYXTDrXZuZSBrb256aXN0ZW50bmUgYmV6IMWhdGF0aXN0aWNreSB2w716bmFtbsO9Y2ggem1pZW4uCgojIyMgKioqUmVncmVzbsOhIGFuYWzDvXphIHbDvXZvamEgcG9wdWzDoWNpZSoqKgoKYGBge3J9CmxpYnJhcnkoYnJvb20pCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoa2FibGVFeHRyYSkKbGlicmFyeShzdHJpbmdyKQpjb2VmLnRibCA8LSB0aWR5KG1vZGVsLCBjb25mLmludCA9IFRSVUUpICU+JQogIG11dGF0ZSgKICAgIHRlcm0gPSByZWNvZGUodGVybSwKICAgICAgIihJbnRlcmNlcHQpIiA9ICJJbnRlcmNlcHQiLCJ5ZWFyMTk5MCBQb3B1bGF0aW9uIiA9ICJSb2sgMTk5MCIsICJ5ZWFyMjAwMCBQb3B1bGF0aW9uIiA9ICJSb2sgMjAwMCIsICJ5ZWFyMjAxMCBQb3B1bGF0aW9uIiA9ICJSb2sgMjAxMCIsInllYXIyMDIwIFBvcHVsYXRpb24iID0gIlJvayAyMDIwIiwiQ0NBM1NWSyIgPSAiU2xvdmVuc2tvIiApLAogICAgc3RhcnMgPSBjYXNlX3doZW4oCiAgICAgIHAudmFsdWUgPCAwLjAwMSB+ICIqKioiLAogICAgICBwLnZhbHVlIDwgMC4wMSAgfiAiKioiLAogICAgICBwLnZhbHVlIDwgMC4wNSAgfiAiKiIsCiAgICAgIHAudmFsdWUgPCAwLjEgICB+ICLCtyIsCiAgICAgIFRSVUUgICAgICAgICAgICB+ICIiICkgKSAlPiUKICB0cmFuc211dGUoCiAgICBUZXJtID0gdGVybSwKICAgIEVzdGltYXRlID0gZXN0aW1hdGUsCiAgICBgU3RkLiBFcnJvcmAgPSBzdGQuZXJyb3IsCiAgICBgdCB2YWx1ZWAgPSBzdGF0aXN0aWMsCiAgICBgcCB2YWx1ZWAgPSBwLnZhbHVlLAogICAgYDk1JSBDSWAgPSBzdHJfYygiWyIsIHJvdW5kKGNvbmYubG93LCAwKSwgIiwgIiwgcm91bmQoY29uZi5oaWdoLCAwKSwgIl0iKSwKICAgIFNpZyA9IHN0YXJzICkKY29lZi50YmwgJT4lCiAga2FibGUoCiAgICBkaWdpdHMgPSAwLAogICAgY2FwdGlvbiA9ICJPTFMgcmVncmVzbsOpIGtvZWZpY2llbnR5IChwb3B1bGF0aW9uIH4geWVhciArIENDQTMpIiApICU+JQogIGthYmxlX3N0eWxpbmcoZnVsbF93aWR0aCA9IEZBTFNFLCBib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG92ZXIiLCAiY29uZGVuc2VkIikpICU+JQogIGNvbHVtbl9zcGVjKDEsIGJvbGQgPSBUUlVFKSAlPiUKICByb3dfc3BlYygwLCBib2xkID0gVFJVRSwgYmFja2dyb3VuZCA9ICIjZjJmMmYyIikgJT4lCiAgZm9vdG5vdGUoCiAgICBnZW5lcmFsID0gIlNpZ25pZi4gY29kZXM6ICoqKiBwPDAuMDAxLCAqKiBwPDAuMDEsICogcDwwLjA1LCDCtyBwPDAuMS4iLAogICAgdGhyZWVwYXJ0dGFibGUgPSBUUlVFKQpgYGAKTmEgesOha2xhZGUgdsO9c2xlZGtvdiBsaW5lw6FybmVqIHJlZ3Jlc2llIChPTFMpIG3DtMW+ZW1lIGtvbsWhdGF0b3ZhxaUsIMW+ZSB2IHJva29jaCAxOTkwLCAyMDAwLCAyMDEwIGEgMjAyMCBkb8WhbG8gayB1csSNaXTDqW11ICoqbsOhcmFzdHUgcG9wdWzDoWNpZSoqIHYgcG9yb3ZuYW7DrSBzIHJva29tIDE5ODAuIFbFoWV0a3kgcm96ZGllbHksIG9rcmVtIHJva292IDE5OTAgYSAyMDAwLCBzw7ogxaF0YXRpc3RpY2t5IHbDvXpuYW1uw6kuIFYgcm9rb2NoIDIwMTAgYSAyMDIwIGJvbGEgcG9wdWzDoWNpYSBvIDMwOCw2MTUgYSAzNzEsODQ1IG9ieXZhdGXEvm92ICoqdnnFocWhaWEqKiBuZcW+IHYgcm9rdSAxOTgwLCDEjW8gbmF6bmHEjXVqZSByYXN0IHYgdMO9Y2h0byBvYmRvYmlhY2guIAoKTmFwcm90aSB0b211IHJva3kgMTk5MCBhIDIwMDAgbmV2eWthenVqw7ogxaF0YXRpc3RpY2t5IHbDvXpuYW1uw70gcm96ZGllbCB2IHBvcm92bmFuw60gcyByb2tvbSAxOTgwLCDEjW8gbmF6bmHEjXVqZSBzdGFiaWxpdHUgdiB0b210byBvYmRvYsOtLiBWw71yYXpuw70gcm96ZGllbCBib2wgcG96b3JvdmFuw70gYWogbWVkemkgxIxlc2tvdSByZXB1Ymxpa291IGEgU2xvdmVuc2tvbSwga2RlIHBvcHVsw6FjaWEgU2xvdmVuc2thIGJvbGEgdiBwcmllbWVyZSAqKm5pxb7FoWlhKiogbyB2aWFjIG5lxb4gNSBtaWxpw7Nub3Ygb2J5dmF0ZcS+b3YsIMSNbyBqZSDFoXRhdGlzdGlja3kgdmXEvm1pIHbDvXpuYW1uw6kuIE1vZGVsIHVrYXp1amUsIMW+ZSByb2sgMTk4MCBwcmVkc3RhdnVqZSB6w6FrbGFkbsO9IHJlZmVyZW7EjW7DvSBib2QgcHJlIMSPYWzFoWllIGFuYWzDvXp5IGEgdnBseXYgcsO0em55Y2ggZmFrdG9yb3YgbmEgem1lbnkgdiBwb3B1bMOhY2lpLiAKCioqVnlzb2vDoSBob2Rub3RhIFItc3F1YXJlZCoqICgwLjk5OTIpIHVrYXp1amUsIMW+ZSBtb2RlbCB2ZcS+bWkgZG9icmUgdnlzdmV0xL51amUgdmFyaWFiaWxpdHUgdiBwb3B1bMOhY2nDoWNoIG9ib2NoIGtyYWrDrW4uIFAtaG9kbm90eSBwcmUgcm9reSAyMDEwIGEgMjAyMCwgYWtvIGFqIHByZSBTbG92ZW5za28sICoqc8O6IHbDvXpuYW1uw6kqKiwgxI1vIG5hem5hxI11amUsIMW+ZSB0aWV0byBmYWt0b3J5IG1hasO6ICoqc2lsbsO9IHZwbHl2KiogbmEgcG9wdWzDoWNpdS4gCgpDZWxrb3ZvIG3DtMW+ZW1lIHBvdmVkYcWlLCDFvmUgbWVkemkgcm9rb20gMTk4MCBhIDIwMjAgZG/FoWxvIGsgdsO9em5hbW7DvW0gem1lbsOhbSB2IHBvcHVsw6FjaWksIHByacSNb20gU2xvdmVuc2tvIHZ5a2F6dWplICoqdsO9cmF6bmUgbmnFvsWhaXUqKiBwb3B1bMOhY2l1IHYgcG9yb3ZuYW7DrSBzIMSMZXNrb3UgcmVwdWJsaWtvdS4gVsO9c2xlZGt5IHRlanRvIGFuYWzDvXp5IHRhayBwb3NreXR1asO6IGNlbm7DqSBpbmZvcm3DoWNpZSBvIGRlbW9ncmFmaWNrw71jaCB0cmVuZG9jaCB2IG9ib2NoIGtyYWppbsOhY2ggdiBwb3NsZWRuw71jaCBkZXNhxaVyb8SNaWFjaC4gQWxlIGtlxI/FvmUgbW9kZWwgbcOhIHZlxL5taSB2eXNva8OpIFLCsiwgxI1vIGplIHNww7Rzb2JlbsOpIG1hbMO9bSBwb8SNdG9tIHBvem9yb3ZhbsOtIGEgdmXEvmvDvW1pIHJvemRpZWxtaSB2IMO6cm92bmkgcG9wdWzDoWNpZSwgdsO9c2xlZGt5IHByZXRvIGludGVycHJldHVqZW1lIG9waXNuZSwgbmllIHByZWRpa8SNbmUuCgojIDQuSHVzdG90YSBvYnl2YXRlxL5zdHZhIGEgamVqIGRldGVybWluYW50eQoKxI5hbMWhaWEgxI1hc8WlIHByw6FjZSBzYSB6YW1lcmlhdmEgbmEgdnrFpWFoIG1lZHppIGh1c3RvdG91IG9ieXZhdGXEvnN0dmEsIHBvcHVsw6FjaW91IGEgcm96bG9ob3Uga3JhasOtbiB2IHJva3UgMjAyMC4KCmBgYHtyfQp1ZGFqZSA8LSByZWFkLmNzdigid29ybGRfcG9wdWxhdGlvbi5jc3YiLCBkZWM9Ii4iLCBzZXA9IiwiLCBoZWFkZXIgPSBUUlVFKQp1ZGFqZS4yMDIwIDwtIGFzLmRhdGEuZnJhbWUobGFwcGx5KHVkYWplLjIwMjAsIGFzLm51bWVyaWMpKQpjb2x1bW5fbWVkaWFucyA8LSBzYXBwbHkodWRhamUuMjAyMCwgbWVkaWFuLCBuYS5ybSA9IFRSVUUpCmZvciAoY29sIGluIG5hbWVzKHVkYWplLjIwMjApKSB7CiAgdWRhamUuMjAyMFtbY29sXV1baXMubmEodWRhamUuMjAyMFtbY29sXV0pXSA8LSBjb2x1bW5fbWVkaWFuc1tjb2xdfQpwYXIobWZyb3cgPSBjKDIsIDIpKQpwYXIobWFyID0gYyg0LCA0LCAyLCAxKSkKZm9yIChjb2wgaW4gbmFtZXModWRhamUuMjAyMCkpIHsKICBib3hwbG90KHVkYWplLjIwMjBbW2NvbF1dLCBtYWluID0gY29sLCB4bGFiID0gIkhvZG5vdHkiLCBjb2wgPSAibGlnaHRibHVlIiwgYm9yZGVyID0gInBpbmsiKX0KYGBgCgojIyMgKjEuIFgyMDIwLlBvcHVsYXRpb24qClbDpMSNxaFpbmEgaG9kbsO0dCBzYSBrb25jZW50cnVqZSBwcmkgdmXEvm1pIG7DrXpreWNoIGhvZG5vdMOhY2ggcG9wdWzDoWNpZS4KVmlkaXRlxL5uw71jaCBqZSBuaWVrb8S+a28gdsO9cmF6bsO9Y2ggb2TEvmFobMO9Y2ggaG9kbsO0dCAob3V0bGllcnMpIOKAkyBuaWVrdG9yw6kga3JhamlueS/DunplbWlhIG1hasO6IHBvcHVsw6FjaXUgdsO9cmF6bmUgdnnFocWhaXUgbmXFviBvc3RhdG7DqS4KUm96ZGVsZW5pZSBqZSBzaWxuZSBwcmF2b3N0cmFubsOpIChwb3ppdMOtdm5lIHpvxaFpa21lbsOpKSDigJMgdsOkxI3FoWluYSBwb3pvcm92YW7DrSBtw6EgbWFsw6kgaG9kbm90eSwgemF0aWHEviDEjW8gbmlla2/EvmtvIGV4dHLDqW1ueWNoIHBvem9yb3ZhbsOtIMWlYWjDoSBtZWRpw6FuIHNtZXJvbSBuYWRvbC4KCgojIyMgKjIuIEFyZWEuLmttLi4qClbDpMSNxaFpbmEga3JhasOtbiBtw6EgcG9tZXJuZSBtYWzDuiByb3psb2h1LCBwcmnEjW9tIHpvcMOhciB2ZcS+bWkgdmXEvmvDvWNoIMO6emVtw60gc3DDtHNvYnVqZSBzaWxuw7ogcHJhdm9zdHJhbm7DuiDFoWlrbW9zxaUuClZpYWNlcsOpIGJvZHkgxI9hbGVrbyBvZCBobGF2bsOpaG8gcG/EvmEgZMOhdCBuYXpuYcSNdWrDuiBvZMS+YWhsw6kgcG96b3JvdmFuaWEgKHZlxL5rw6kga3JhamlueSkuClBvZG9ibmUgYWtvIHByaSBwb3B1bMOhY2lpLCBkw6F0YSBzw7ogdmXEvm1pIG5lc3ltZXRyaWNrw6kg4oCTIG9kcG9yw7rEjWEgc2EgenbDocW+acWlIHRyYW5zZm9ybcOhY2l1IChuYXByLiBsb2coYXJlYSkpLgoKIyMjICozLiBEZW5zaXR5Li5wZXIua20uLioKSHVzdG90YSBvYnl2YXRlxL5zdHZhIG3DoSB2w6TEjcWhaW51IGhvZG7DtHQgc8O6c3RyZWRlbsO9Y2ggcHJpIG7DrXpreWNoIMSNw61zbGFjaCwgbm8gbmlla2/EvmtvIG9ibGFzdMOtIG3DoSBleHRyw6ltbmUgdnlzb2vDuiBodXN0b3R1LgpUbyBzYSBwcmVqYXZ1amUgb2TEvmFobMO9bWkgYm9kbWkgbmFkIGhvcm7DvW0gZsO6em9tIGJveHBsb3R1LgpSb3pkZWxlbmllIGplIHByYXZvc3RyYW5uw6ksIHRlZGEgZXhpc3R1asO6IG5pZWt0b3LDqSBleHRyw6ltbmUgaHVzdG8gb2LDvXZhbsOpIHJlZ2nDs255LgpUcmFuc2Zvcm3DoWNpYSAobmFwci4gbG9nKSBieSBtb2hsYSBwb23DtGPFpSB6bGVwxaFpxaUgc3ltZXRyaXUgcm96ZGVsZW5pYS4KCgpgYGB7ciBkaWFncGxvdHMsIGZpZy5jYXA9IkRpYWdub3N0aWNrw6kgZ3JhZnkgcmVncmVzbsOpaG8gbW9kZWx1In0KIyBOYXN0YXZpxaUgcm96bG/FvmVuaWUgMiB4IDIKcGFyKG1mcm93ID0gYygyLCAyKSkKCiMgVnlrcmVzbGnFpSB2xaFldGt5IDQgZGlhZ25vc3RpY2vDqSBncmFmeSBtb2RlbHUKcGxvdChtb2RlbCkKCiMgKFZvbGl0ZcS+bsOpKSBwcmlkYcWlIHNwb2xvxI1uw70gbmFkcGlzCm10ZXh0KCJEaWFnbm9zdGlja8OpIGdyYWZ5IHJlZ3Jlc27DqWhvIG1vZGVsdSIsIG91dGVyID0gVFJVRSwgY2V4ID0gMS4yLCBmb250ID0gMikKCiMgUmVzZXRvdmHFpSBsYXlvdXQKcGFyKG1mcm93ID0gYygxLCAxKSkKYGBgCiMjIMSMbyBuw6FtIGhvdm9yaWEgdGlldG8gZ3JhZnk/CgojIyMgKlJlc2lkdWFscyB2cyBGaXR0ZWQqClJlemlkdcOhbHkgc8O6IHJvemxvxb5lbsOpIG9rb2xvIG51bHkgYmV6IHbDvXJhem7DqWhvIHRyZW5kdSwgxI1vIG5hem5hxI11amUgZG9icsOpIHByaXNww7Rzb2JlbmllIG1vZGVsdS4KTWllcm5lIHpha3JpdmVuaWUgxI1pYXJ5IHBvdWthenVqZSBuYSBtb8W+bsO6IG5lbGluZWFyaXR1IGFsZWJvIHZwbHl2IG5pZWtvxL5rw71jaCBvZMS+YWhsw71jaCBwb3pvcm92YW7DrS4KCiMjIyAqTm9ybWFsIFHigJNRIHBsb3QqClbDpMSNxaFpbmEgYm9kb3YgbGXFvsOtIGJsw616a28gZGlhZ29uw6FseSwgdGFrxb5lIHJvemRlbGVuaWUgcmV6w61kdcOtIGplIHByaWJsacW+bmUgbm9ybcOhbG5lLgpNZW7FoWllIG9kY2jDvWxreSBuYSBva3Jham9jaCBuYXpuYcSNdWrDuiBsZW4gbWllcm5lIHBvcnXFoWVuaWUgbm9ybWFsaXR5LgoKIyMjICpTY2FsZeKAk0xvY2F0aW9uKgpSb3pwdHlsIHJlesOtZHXDrSBzYSBqYXbDrSBha28gcHJpYmxpxb5uZSBrb27FoXRhbnRuw70sIMSNbyBwb2Rwb3J1amUgcHJlZHBva2xhZCBob21vc2tlZGFzdGljaXR5LgpNaWVybmUgdsO9a3l2eSBuYSB6YcSNaWF0a3UgbcO0xb51IGJ5xaUgc3DDtHNvYmVuw6kgbmlla2/EvmvDvW1pIGV4dHLDqW1ueW1pIGJvZG1pLgoKIyMjICpSZXNpZHVhbHMgdnMgRmFjdG9yIExldmVscyoKUmV6aWR1w6FseSBzYSB2IGplZG5vdGxpdsO9Y2ggZmFrdG9yb3bDvWNoIMO6cm92bmlhY2ggcG9oeWJ1asO6IG9rb2xvIG51bHksIGJleiBzeXN0ZW1hdGlja8OpaG8gdHJlbmR1LgpCb2R5IDUgYSAxMCBww7Rzb2JpYSBha28gbW/Fvm7DqSB2cGx5dm7DqSBwb3pvcm92YW5pYSwga3RvcsOpIG3DtMW+dSBvdnBseXbFiG92YcWlIG1vZGVsLgoKYGBge3J9Cmluc3RhbGwucGFja2FnZXMoInRzZXJpZXMiKSAgIyBsZW4gcmF6CmxpYnJhcnkodHNlcmllcykgICAKYGBgCmBgYHtyfQptb2RlbDIgPC0gbG0oRGVuc2l0eS4ucGVyLmttLi4gfiBYMjAyMC5Qb3B1bGF0aW9uICsgQXJlYS4ua20uLiwgZGF0YSA9IHVkYWplLjIwMjApCnN1bW1hcnkobW9kZWwyKQojIERpYWdub3N0aWNrw6kgZ3JhZnkKcGFyKG1mcm93ID0gYygyLCAyKSkKcGFyKG1hciA9IGMoNCwgNCwgMiwgMSkpCnBsb3QobW9kZWwyKQpwYXIobWZyb3cgPSBjKDEsIDEpKQoKYGBgCgojIyMgKlJlc2lkdWFscyB2cyBGaXR0ZWQqClJlemlkdcOhbHkgc2EgdsOkxI3FoWlub3UgcG9oeWJ1asO6IG9rb2xvIG51bHksIMSNbyBuYXpuYcSNdWplLCDFvmUgbW9kZWwgbmVtw6EgdsO9cmF6bsOpIHN5c3RlbWF0aWNrw6kgY2h5YnkgdiBwcmVkaWtjacOhY2guCk5pZWtvxL5rbyBib2RvdiBzIHZlxL5rw71taSByZXppZHXDoWxtaSAobmFwci4gMTIwLCAxMzUsIDE4OCkgcHJlZHN0YXZ1amUgbW/Fvm7DqSBvZMS+YWhsw6kgcG96b3JvdmFuaWEuCgojIyMgKk5vcm1hbCBR4oCTUSBwbG90KgpWw6TEjcWhaW5hIGJvZG92IHNsZWR1amUgZGlhZ29uw6FsdSwgbm8ga29uaWVjIGdyYWZ1IHNhIHbDvXJhem5lIG9kY2h5xL51amUgc21lcm9tIG5haG9yLgpUbyB6bmFtZW7DoSwgxb5lIHJlemlkdcOhbHkgbmllIHPDuiBkb2tvbmFsZSBub3Jtw6FsbmUgcm96ZGVsZW7DqSBhIGV4aXN0dWrDuiBleHRyw6ltbmUgaG9kbm90eSB2IHByYXZlaiDEjWFzdGkgcm96ZGVsZW5pYS4KCiMjIyAqU2NhbGXigJNMb2NhdGlvbioKUm96cHR5bCByZXrDrWR1w60gc2EgamF2w60gYWtvIHJlbGF0w612bmUga29uxaF0YW50bsO9LCBiZXogdsO9cmF6bsOpaG8gcm96xaFpcm92YW5pYSBhbGVibyB6dcW+b3ZhbmlhLgpMZW4gbmlla2/EvmtvIGJvZG92IHMgdnlzb2vDvW1pIMWhdGFuZGFyZGl6b3ZhbsO9bWkgcmV6aWR1w6FsbWkgbcO0xb5lIG5hem5hxI1vdmHFpSBtaWVybnUgaGV0ZXJvc2tlZGFzdGljaXR1LgoKIyMjICpSZXNpZHVhbHMgdnMgTGV2ZXJhZ2UqClbDpMSNxaFpbmEgYm9kb3YgbcOhIG7DrXprZSBob2Rub3R5IGxldmVyYWdlLCDEjW8gamUgZG9icsOpLCBubyBuaWVrb8S+a28gcG96b3JvdmFuw60gKG5hcHIuIDEyMCwgMTM1LCAxNzIpIG3DoSB2w6TEjcWhw60gdnBseXYgcG9kxL5hIENvb2tvdmVqIHZ6ZGlhbGVub3N0aS4KVGlldG8gcG96b3JvdmFuaWEgbcO0xb51IHbDvXJhem5lasWhaWUgb3ZwbHl2xYhvdmHFpSBvZGhhZCBwYXJhbWV0cm92IGEgamUgdmhvZG7DqSBpY2ggc2tvbnRyb2xvdmHFpS4KCgojIDUuQW5hbMO9emEgaGV0ZXJvc2tlZGFzdGljaXR5CgpQcmkgbW9kZWxvdmFuw60gdGVtcGEgcmFzdHUgcG9wdWzDoWNpZSBib2xhIGlkZW50aWZpa292YW7DoSBoZXRlcm9za2VkYXN0aWNpdGEgcmV6w61kdcOtLCDEjW8gcG90dnJkaWwgYWogKkJyZXVzY2jigJNQYWdhbm92IHRlc3QqLiBSb3pwdHlsIGNow71iIHNhIHp2ecWhdWplIHByaSBleHRyw6ltbnljaCBob2Rub3TDoWNoIHJhc3R1IHBvcHVsw6FjaWUuIE5hIHJpZcWhZW5pZSB0b2h0byBwcm9ibMOpbXUgYm9saSBwb3XFvml0w6kgcm9idXN0bsOpIMWhdGFuZGFyZG7DqSBjaHlieSwga3RvcsOpIHBvdHZyZGlsaSDFoXRhdGlzdGlja8O6IHbDvXpuYW1ub3PFpSB0cmVuZHUgcG9rbGVzdSB0ZW1wYSByYXN0dSBwb3B1bMOhY2llIHYgxI1hc2UuCmBgYHtyfQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHRpZHlyKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkocGF0Y2h3b3JrKQojIDHvuI/ig6MgUHJlZm9ybcOhdG92YW5pZSBkw6F0IGRvIGRsaMOpaG8gZm9ybcOhdHUKd29ybGRfcG9wdWxhdGlvbl9sb25nIDwtIHdvcmxkX3BvcHVsYXRpb24gJT4lCiAgc2VsZWN0KENvbnRpbmVudCwgQ291bnRyeS5UZXJyaXRvcnksIAogICAgICAgICBYMjAyMi5Qb3B1bGF0aW9uLCBYMjAyMC5Qb3B1bGF0aW9uLCBYMjAxNS5Qb3B1bGF0aW9uLCAKICAgICAgICAgWDIwMTAuUG9wdWxhdGlvbiwgWDIwMDAuUG9wdWxhdGlvbiwgWDE5OTAuUG9wdWxhdGlvbiwgWDE5ODAuUG9wdWxhdGlvbiwgWDE5NzAuUG9wdWxhdGlvbikgJT4lCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBzdGFydHNfd2l0aCgiWCIpLCAKICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAiWWVhciIsIAogICAgICAgICAgICAgICB2YWx1ZXNfdG8gPSAiUG9wdWxhdGlvbiIpICU+JQogIG11dGF0ZShZZWFyID0gYXMubnVtZXJpYyhnc3ViKCJYfFxcLlBvcHVsYXRpb24iLCAiIiwgWWVhcikpKSAlPiUgICMgb2RzdHLDoW5pICJYIiBhICIuUG9wdWxhdGlvbiIsIHpvc3TDoXZhIHJvawogIGdyb3VwX2J5KENvdW50cnkuVGVycml0b3J5KSAlPiUKICBhcnJhbmdlKFllYXIpICU+JQogIG11dGF0ZShHcm93dGhSYXRlID0gKFBvcHVsYXRpb24gLyBsYWcoUG9wdWxhdGlvbikgLSAxKSAqIDEwMCkgJT4lCiAgdW5ncm91cCgpICU+JQogIGZpbHRlcighaXMubmEoR3Jvd3RoUmF0ZSkpCiMgMu+4j+KDoyBMaW5lw6FybnkgbW9kZWwKbW9kZWwgPC0gbG0oR3Jvd3RoUmF0ZSB+IFllYXIsIGRhdGEgPSB3b3JsZF9wb3B1bGF0aW9uX2xvbmcpCiMgM++4j+KDoyBQcmVkaWtjaWUgYSByZXppZHXDoQp3b3JsZF9wb3B1bGF0aW9uX2xvbmckcHJlZF9tb2RlbCA8LSBwcmVkaWN0KG1vZGVsKQp3b3JsZF9wb3B1bGF0aW9uX2xvbmckcmVzaWRfbW9kZWwgPC0gcmVzaWQobW9kZWwpCiMgNO+4j+KDoyBHcmFmeSBoZXRlcm9za2VkYXN0aWNpdHkKcDEgPC0gZ2dwbG90KHdvcmxkX3BvcHVsYXRpb25fbG9uZywgYWVzKHggPSBZZWFyLCB5ID0gcmVzaWRfbW9kZWxeMikpICsKICBnZW9tX3BvaW50KGFscGhhID0gMSwgY29sb3IgPSAic3RlZWxibHVlIikgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsb2VzcyIsIHNlID0gRkFMU0UsIGNvbG9yID0gInBpbmsiKSArCiAgbGFicyh4ID0gIlJvayIsIHkgPSAixaB0dm9yY2UgcmV6w61kdcOtIiwgdGl0bGUgPSAiUmVzaWR1YWxzwrIgdnMgUm9rIikgKwogIHRoZW1lX21pbmltYWwoKQpwMiA8LSBnZ3Bsb3Qod29ybGRfcG9wdWxhdGlvbl9sb25nLCBhZXMoeCA9IEdyb3d0aFJhdGUsIHkgPSByZXNpZF9tb2RlbF4yKSkgKwogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjYsIGNvbG9yID0gImxpZ2h0Ymx1ZSIpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG9lc3MiLCBzZSA9IEZBTFNFLCBjb2xvciA9ICJwaW5rIikgKwogIGxhYnMoeCA9ICJUZW1wbyByYXN0dSBwb3B1bMOhY2llICglKSIsIHkgPSAixaB0dm9yY2UgcmV6w61kdcOtIiwgdGl0bGUgPSAiUmVzaWR1YWxzwrIgdnMgR3Jvd3RoIFJhdGUiKSArCiAgdGhlbWVfbWluaW1hbCgpCiMgNe+4j+KDoyBab2JyYXplbmllIG9ib2NoIGdyYWZvdiB2ZWTEvmEgc2ViYQpwMSArIHAyCmBgYAojIyMgKipHcmFmIFJlc2lkdWFsc8KyIHZzIFJvayoqIAoqdWthenVqZSwgxb5lIG1vZGVsIHByZWRwb3ZlZMOhIHBvcHVsw6FjaXUgcHJlc25lIHYgcm9rb2NoIG1lZHppIDE5OTAgYSAyMDIwLCBhbGUgbcOhIHZlxL5rw6kgb2RjaMO9bGt5IHYgcm9rdSAxOTgwIGEgbmlla3RvcsO9Y2ggxI9hbMWhw61jaCByb2tvY2gsIMSNbyBuYXpuYcSNdWplLCDFvmUgbW9kZWwgbmV6YWNoeXTDoXZhIHbFoWV0a3kgZmFrdG9yeSBvdnBseXbFiHVqw7pjZSBwb3B1bMOhY2l1IHYgdMO9Y2h0byBvYmRvYmlhY2guKgoKIyMjICoqR3JhZiBSZXNpZHVhbHPCsiB2cyBHcm93dGggUmF0ZSoqIAoqdWthenVqZSwgxb5lIG1vZGVsIG3DoSB2w6TEjcWhaWUgY2h5YnkgcHJpIHZ5xaHFocOtY2ggdGVtcMOhY2ggcmFzdHUgcG9wdWzDoWNpZS4gVG8gbmF6bmHEjXVqZSwgxb5lIG1vZGVsIG5pZSBqZSBzY2hvcG7DvSBwcmVzbmUgcHJlZHBvdmVkYcWlIHBvcHVsw6FjaXUgcHJpIHLDvWNobG9tIHJhc3RlLCDEjW8gbcO0xb5lIHZ5xb5hZG92YcWlIGtvbXBsZXhuZWrFocOtIG1vZGVsIHByZSBvYmRvYmlhIHMgZXh0csOpbW55bSByYXN0b20uKgpgYGB7cn0KbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHBhdGNod29yaykKbW9kZWwgPC0gbG0oR3Jvd3RoUmF0ZSB+IENvbnRpbmVudCwgZGF0YSA9IHdvcmxkX3BvcHVsYXRpb25fbG9uZykKd29ybGRfcG9wdWxhdGlvbl9sb25nJHJlc2lkX21vZGVsIDwtIHJlc2lkKG1vZGVsKQpwMSA8LSBnZ3Bsb3Qod29ybGRfcG9wdWxhdGlvbl9sb25nLCBhZXMoeCA9IFllYXIsIHkgPSByZXNpZF9tb2RlbF4yKSkgKwogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjYsIGNvbG9yID0gImdyZXkiKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxvZXNzIiwgc2UgPSBGQUxTRSwgY29sb3IgPSAicHVycGxlIikgKwogIGxhYnMoeCA9ICJSb2siLCB5ID0gIsWgdHZvcmNlIHJlesOtZHXDrSIsIHRpdGxlID0gIlJlc2lkdWFsc8KyIHZzIFJvayIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKAogIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIiNmNWY1ZGMiLCBjb2xvciA9IE5BKSwgICMgYsOpxb5vdsOhCiAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIiNmNWY1ZGMiLCBjb2xvciA9IE5BKQopIApwMiA8LSBnZ3Bsb3Qod29ybGRfcG9wdWxhdGlvbl9sb25nLCBhZXMoeCA9IEdyb3d0aFJhdGUsIHkgPSByZXNpZF9tb2RlbF4yKSkgKwogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjYsIGNvbG9yID0gImxpZ2h0Ymx1ZSIpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG9lc3MiLCBzZSA9IEZBTFNFLCBjb2xvciA9ICJwaW5rIikgKwogIGxhYnMoeCA9ICJUZW1wbyByYXN0dSBwb3B1bMOhY2llICglKSIsIHkgPSAixaB0dm9yY2UgcmV6w61kdcOtIiwgdGl0bGUgPSAiUmVzaWR1YWxzwrIgdnMgR3Jvd3RoIFJhdGUiKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZSgKICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICIjZjVmNWRjIiwgY29sb3IgPSBOQSksICAjIGLDqcW+b3bDoQogIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICIjZjVmNWRjIiwgY29sb3IgPSBOQSkKKSAKcDEgKyBwMgpgYGAKIyMjICoqR3JhZjogxaB0dm9yY2UgcmV6w61kdcOtIHZzIFJvayoqCipWIHRvbXRvIGdyYWZlIHNsZWR1amVtZSwgxI1pIHNhIHZlxL5rb3PFpSBjaMO9YiBtb2RlbHUgbWVuw60gdiDEjWFzZS4gRmlhbG92w6EgdnlobGFkZW7DoSBrcml2a2EgamUgdGFrbWVyIHJvdm7DoSwgxI1vIG5hem5hxI11amUsIMW+ZSByb3pwdHlsIHJlesOtZHXDrSBqZSBzdGFiaWxuw70gbmFwcmllxI0gcm9rbWkuIFRvIHpuYW1lbsOhLCDFvmUgcHJlbWVubsOhIOKAnnJva+KAnCBwcmF2ZGVwb2RvYm5lICoqbmVzcMO0c29idWplIGhldGVyb3NrZWRhc3RpY2l0dSoqLiBNb2RlbCB0ZWRhIHYgdG9tdG8gc21lcmUgbmV1a2F6dWplIMW+aWFkbnkgc3lzdGVtYXRpY2vDvSBwcm9ibMOpbS4qCgojIyMgKipHcmFmOiDFoHR2b3JjZSByZXrDrWR1w60gdnMgVGVtcG8gcmFzdHUgcG9wdWzDoWNpZSoqCipUdSBza8O6bWFtZSwgxI1pIHZlxL5rb3PFpSBjaMO9YiB6w6F2aXPDrSBvZCB0ZW1wYSByYXN0dSBwb3B1bMOhY2llLiDEjGVydmVuw6Ega3JpdmthIG3DoSB2w71yYXpuw70gb2Jsw7prb3ZpdMO9IHR2YXIsIMSNbyBuYXpuYcSNdWplLCDFvmUgbW9kZWwgcm9iw60gdsOkxI3FoWllIGNoeWJ5IHByaSBleHRyw6ltbnljaCBob2Rub3TDoWNoIHJhc3R1LiBUbyBqZSB2aXp1w6FsbnkqICoqbsOhem5hayBoZXRlcm9za2VkYXN0aWNpdHkgKiog4oCTICp0ZWRhIHRvaG8sIMW+ZSByb3pwdHlsIHJlesOtZHXDrSBuaWUgamUga29uxaF0YW50bsO9LiBUZW50byBwcm9ibMOpbSBwb3R2cmR6dWplIGFqIHbDvXNsZWRvayBCcmV1c2No4oCTUGFnYW5vdmhvIHRlc3R1LioKCmBgYHtyfQojIPCfk6YgTmHEjcOtdGFuaWUga25pxb5uw61jCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkodGlkeXIpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShsbXRlc3QpCmxpYnJhcnkocGF0Y2h3b3JrKQojIDHvuI/ig6MgUHJlZm9ybcOhdG92YW5pZSBkw6F0IGRvIGRsaMOpaG8gZm9ybcOhdHUKd29ybGRfcG9wdWxhdGlvbl9sb25nIDwtIHdvcmxkX3BvcHVsYXRpb24gJT4lCiAgc2VsZWN0KENvbnRpbmVudCwgQ291bnRyeS5UZXJyaXRvcnksIAogICAgICAgICBYMjAyMi5Qb3B1bGF0aW9uLCBYMjAyMC5Qb3B1bGF0aW9uLCBYMjAxNS5Qb3B1bGF0aW9uLCAKICAgICAgICAgWDIwMTAuUG9wdWxhdGlvbiwgWDIwMDAuUG9wdWxhdGlvbiwgWDE5OTAuUG9wdWxhdGlvbiwgWDE5ODAuUG9wdWxhdGlvbiwgWDE5NzAuUG9wdWxhdGlvbikgJT4lCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBzdGFydHNfd2l0aCgiWCIpLCAKICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAiWWVhciIsIAogICAgICAgICAgICAgICB2YWx1ZXNfdG8gPSAiUG9wdWxhdGlvbiIpICU+JQogIG11dGF0ZShZZWFyID0gYXMubnVtZXJpYyhnc3ViKCJYfFxcLlBvcHVsYXRpb24iLCAiIiwgWWVhcikpKSAlPiUgICMgeiBuw6F6dnUgc3TEunBjYSB2eWJlciByb2sKICBncm91cF9ieShDb3VudHJ5LlRlcnJpdG9yeSkgJT4lCiAgYXJyYW5nZShZZWFyKSAlPiUKICBtdXRhdGUoR3Jvd3RoUmF0ZSA9IChQb3B1bGF0aW9uIC8gbGFnKFBvcHVsYXRpb24pIC0gMSkgKiAxMDApICU+JQogIHVuZ3JvdXAoKSAlPiUKICBmaWx0ZXIoIWlzLm5hKEdyb3d0aFJhdGUpKQojIDLvuI/ig6MgVnl0dm9yZW5pZSBsaW5lw6FybmVobyBtb2RlbHUKbW9kZWwgPC0gbG0oR3Jvd3RoUmF0ZSB+IFllYXIsIGRhdGEgPSB3b3JsZF9wb3B1bGF0aW9uX2xvbmcpCnN1bW1hcnkobW9kZWwpCiMgM++4j+KDoyBCcmV1c2NoLVBhZ2FuIHRlc3QgbmEgaGV0ZXJvc2tlZGFzdGljaXR1CmJwdGVzdChtb2RlbCkKYGBgCipCcmV1c2No4oCTUGFnYW5vdiB0ZXN0IG92ZXJ1amUsIMSNaSBzYSB2ZcS+a29zxaUgY2jDvWIgbW9kZWx1IG1lbsOtIHYgesOhdmlzbG9zdGkgb2QgdnlzdmV0xL51asO6Y2ljaCBwcmVtZW5uw71jaCDigJMgdGVkYSDEjWkgamUgcHLDrXRvbW7DoSBoZXRlcm9za2VkYXN0aWNpdGEuIFbDvXNsZWRvayB0ZXN0dSAoQlAgPSAxOS4wMTgsIHAtaG9kbm90YSA8IDAuMDAxKSBuYXpuYcSNdWplLCDFvmUgcm96cHR5bCByZXrDrWR1w60gbmllIGplIGtvbsWhdGFudG7DvS4gVG8gem5hbWVuw6EsIMW+ZSBtb2RlbCByb2LDrSBzeXN0ZW1hdGlja3kgdsOkxI3FoWllIGNoeWJ5IHByaSB1csSNaXTDvWNoIGhvZG5vdMOhY2ggdnN0dXBuw71jaCBwcmVtZW5uw71jaC4gVGFrw710byBwcm9ibMOpbSBtw7TFvmUgb3ZwbHl2bmnFpSBzcG/EvmFobGl2b3PFpSBvZGhhZG92IGEgdnnFvmFkdWplIMO6cHJhdnUgbW9kZWx1LioKCmBgYHtyfQpsaWJyYXJ5KGxtdGVzdCkKbW9kZWwyIDwtIGxtKEdyb3d0aFJhdGUgfiArMSArIEkobG9nKFllYXIpKSxkYXRhPXdvcmxkX3BvcHVsYXRpb25fbG9uZykKc3VtbWFyeShtb2RlbDIpCmJwdGVzdChtb2RlbDIpCmBgYAoqVGVudG8gbW9kZWwgc2vDum1hIHZ6xaVhaCBtZWR6aSByYXN0b20gcG9wdWzDoWNpZSBhIGxvZ2FyaXRtaWNreSB0cmFuc2Zvcm1vdmFuw71tIHJva29tLiBWw71zbGVka3kgdWthenVqw7osIMW+ZSBsb2coWWVhcikgbcOhIHNpbG5lIG5lZ2F0w612bnkgYSDFoXRhdGlzdGlja3kgdsO9em5hbW7DvSB2cGx5diBuYSByYXN0IHBvcHVsw6FjaWUuIE5hcHJpZWsgdHJhbnNmb3Jtw6FjaWkgdsWhYWsgQnJldXNjaOKAk1BhZ2Fub3YgdGVzdCAoQlAgPSAxOC45OTQsIHAgPCAwLjAwMSkgc3TDoWxlIG5hem5hxI11amUgcHLDrXRvbW5vc8WlIGhldGVyb3NrZWRhc3RpY2l0eS4gVG8gem5hbWVuw6EsIMW+ZSByb3pwdHlsIGNow71iIHNhIG1lbsOtIGEgbW9kZWwgYnkgbW9ob2wgYnnFpSDEj2FsZWogdXByYXZlbsO9LCBuYXByw61rbGFkIHBvdcW+aXTDrW0gcm9idXN0bsO9Y2ggbWV0w7NkLioKCmBgYHtyfQpsaWJyYXJ5KHNhbmR3aWNoKQpsaWJyYXJ5KGxtdGVzdCkKY29lZnRlc3QobW9kZWwsIHZjb3YgPSB2Y292SEMobW9kZWwpKQpgYGAKCmBgYHtyfQpsaWJyYXJ5KHpvbykKbGlicmFyeSh0c2VyaWVzKQpsaWJyYXJ5KGxtdGVzdCkKbGlicmFyeShzYW5kd2ljaCkKbGlicmFyeShjYXIpCnJtKGxpc3Q9bHMoKSkKYGBgCgoqTsOhc2xlZG5lIHNtZSB6IGRhdGFzZXR1IHZ5YnJhbGkgdHJpIGTDtGxlxb5pdMOpIHVrYXpvdmF0ZWxlOiBwb3B1bMOhY2l1IHYgcm9rdSAyMDIwLCByb3psb2h1IGtyYWppbnkgYSBodXN0b3R1IG9ieXZhdGXEvnN0dmEuIFByZXRvxb5lIMO6ZGFqZSBvYnNhaG92YWxpIGNow71iYWrDumNlIGhvZG5vdHksIGRvcGxuaWxpIHNtZSBpY2ggcG9tb2NvdSBtZWRpw6FudSwgYWJ5IGFuYWzDvXphIG5lYm9sYSBza3Jlc2xlbsOhIGFuaSBwcmVydcWhZW7DoSBOQSBob2Rub3RhbWkuIE7DoXNsZWRuZSBzbWUgdsWhZXRreSBwcmVtZW5uw6kgcHJla29udmVydG92YWxpIG5hIMSNw61zZWxuw70gZm9ybcOhdCwgYWJ5IHNhIGRhbGkgxI9hbGVqIMWhdGF0aXN0aWNreSBzcHJhY292YcWlLiBWw71zbGVka29tIGplIMSNaXN0w70gYSBrb21wbGV0bsO9IGRhdGFzZXQgdmhvZG7DvSBuYSBuw6FzbGVkbsOpIHJlZ3Jlc27DqSBtb2RlbG92YW5pZS4qCgoKYGBge3J9CmF0dGFjaCh1ZGFqZSkKIyBMaW5lw6FybnkgbW9kZWw6IGh1c3RvdGEgYWtvIGZ1bmtjaWEgcG9wdWzDoWNpZSBhIHJvemxvaHkKbW9kZWwgPC0gbG0oRGVuc2l0eS4ucGVyLmttLi4gfiAxICsgWDIwMjAuUG9wdWxhdGlvbiArIEFyZWEuLmttLi4sIGRhdGEgPSB1ZGFqZSkKc3VtbWFyeShtb2RlbCkKYGBgClpvc3RhdmlsYSBzb20gbGluZcOhcm55IG1vZGVsLCB2IGt0b3JvbSBzb20gaHVzdG90dSBvYnl2YXRlxL5zdHZhIHZ5c3ZldMS+b3ZhbGEgcG9tb2NvdSBwb3B1bMOhY2llIHYgcm9rdSAyMDIwIGEgcm96bG9oeSDDunplbWlhLiBDaWXEvm9tIGJvbG8gb3ZlcmnFpSwgxI1pIHRpZXRvIGR2ZSBwcmVtZW5uw6kgZG9rw6HFvnUgxaF0YXRpc3RpY2t5IHbDvXpuYW1uZSB2eXN2ZXRsacWlIHJvemRpZWx5IHYgaHVzdG90ZSBvYnl2YXRlxL5zdHZhIG1lZHppIGtyYWppbmFtaS4KClogdsO9c2xlZGtvdiB2aWTDrW0sIMW+ZSBhbmkgcG9wdWzDoWNpYSwgYW5pIHJvemxvaGEgw7p6ZW1pYSBuZW1hasO6IHYgdG9tdG8gbW9kZWxpIMWhdGF0aXN0aWNreSB2w716bmFtbsO9IHZwbHl2IG5hIGh1c3RvdHUgb2J5dmF0ZcS+c3R2YS4gSG9kbm90eSBwLXZhbHVlIHPDuiBwcmkgb2JvY2ggcHJlbWVubsO9Y2ggdmXEvm1pIHZ5c29rw6ksIMSNbyB6bmFtZW7DoSwgxb5lIGljaCB2cGx5diBuYSB2eXN2ZXTEvm92YW7DuiBwcmVtZW5uw7ogc2EgdiB0b210byBtb2RlbGkgbmVwb3R2cmRpbC4KClRlZGEgbmEgesOha2xhZGUgbmHFoWVqIGRvdGVyYWrFoWVqIGFuYWzDvXp5IHZpZW1lIHBvdmVkYcWlLCDFvmUgKnBvxI1ldCBvYnl2YXRlxL5vdiB2IHJva3UgMjAyMCBhIHJvemxvaGEgw7p6ZW1pYSBuZW1hasO6IMWhdGF0aXN0aWNreSB2w716bmFtbsO9IHZwbHl2IG5hIGh1c3RvdHUgb2J5dmF0ZcS+c3R2YSB2IHRvbXRvIG1vZGVsaSosIMSNbyBuYXpuYcSNdWplLCDFvmUgdGlldG8gZmFrdG9yeSBuaWUgc8O6IGTDtGxlxb5pdMOpIHByZSB2eXN2ZXRsZW5pZSBodXN0b3R5IG9ieXZhdGXEvnN0dmEgdiB0b210byBwcsOtcGFkZS4KCgpgYGB7cn0KY2FyOjpjclBsb3RzKG1vZGVsKQpgYGAKIyMjIEdyYWYg4oCTIDIwMjAgUG9wdWxhdGlvbgoqVsOkxI3FoWluYSBib2RvdiBqZSB2ZcS+bWkgYmzDrXprbyBvc2kgMCog4oaSIHBvcHVsw6FjaWEgdsOkxI3FoWlueSBrcmFqw61uL8O6emVtw60gamUgcmVsYXTDrXZuZSBuw616a2EgKHYgcG9yb3ZuYW7DrSBzIGV4dHLDqW1hbWkpLgpOaWVrb8S+a28gdnpkaWFsZW7DvWNoIGJvZG92IChvdXRsaWVyb3YpIHByZWRzdGF2dWplIHZlxL5taSB2ZcS+a8OpIHBvcHVsw6FjaWUuCipGaWFsb3bDoSDEjWlhcmEgKGxpbmXDoXJueSBtb2RlbCkgbWllcm5lIHN0w7pwYSog4oaSIG1vZGVsIHByZWRwb2tsYWTDoSBwb3ppdMOtdm51LCBhbGUgc2xhYsO6IGxpbmXDoXJudSB6w6F2aXNsb3PFpS4KKk1vZHLDoSBMT0VTUyBrcml2a2EgamUgdGFrbWVyIHBsb2Now6EqIOKGkiBza3V0b8SNbsO9IG5lbGluZcOhcm55IHRyZW5kIGplIHByYWt0aWNreSBudWxvdsO9LgojIyMjIEludGVycHJldMOhY2lhOgpQb3B1bMOhY2lhIG5lbcOhIHbDvXJhem7DvSBsaW5lw6FybnkgYW5pIG5lbGluZcOhcm55IGVmZWt0IG5hIGh1c3RvdHUgb2J5dmF0ZcS+c3R2YSB2IHRvbXRvIG1vZGVsaS4KT3V0bGllcnkgbcO0xb51IHNrcmVzxL5vdmHFpSBmaXQuCgojIyMgR3JhZiDigJMgQXJlYSAoa23CsikKU2l0dcOhY2lhIGplIHBvZG9ibsOhIOKAkyB2w6TEjcWhaW5hIMO6emVtw60gbcOhIG1hbMO6IHJvemxvaHUsIHDDoXIgZXh0csOpbW5lIHZlxL5rw71jaCDFoXTDoXRvdiB2eXR2w6FyYSBvdXRsaWVyeS4KKkxpbmXDoXJueSBtb2RlbCAoZmlhbG92w6EgxI1pYXJhKSBtaWVybmUga2xlc8OhKiDihpIgdsOkxI3FoWlhIHJvemxvaGEgbcO0xb5lIHPDunZpc2llxaUgcyBuacW+xaFvdSBodXN0b3RvdS4KKkxPRVNTIChtb2Ryw6Ega3JpdmthKSogamUgdGllxb4gbWllcm5lIGtsZXNhasO6Y2EsIGFsZSB0YWttZXIgcGxvY2jDoS4KIyMjIyBJbnRlcnByZXTDoWNpYToKUm96bG9oYSBtw6Egc2xhYsO9IG5lZ2F0w612bnkgdnrFpWFoIHMgaHVzdG90b3UsIMSNbyBqZSBsb2dpY2t5IG/EjWFrw6F2YW7DqSwgYWxlIHrDoXZpc2xvc8WlIGplIHZlxL5taSBzbGFiw6EuCk5lbGluZcOhcm55IGVmZWt0IHNhIHByYWt0aWNreSBuZXByZWphdnVqZS4KCgojIDYuS2xhc3Ryb3bDoSBhbmFsw716YSBldXLDs3Bza3ljaCBrcmFqw61uClByZSDEj2FsxaFpdSBhbmFsw716dSBzbWUgc2kgdGVudG9rcsOhdCB6IG5hxaFlaiBkYXRhYsOhenkgdnl0aWFobGkgdsWhZXRreSBldXLDs3Bza2UgxaF0w6F0eS4KClBvbW9jb3UgaGllcmFyY2hpY2vDqWhvIHpobHVrb3ZhbmlhIChXYXJkLkQyKSBib2xpIGV1csOzcHNrZSBrcmFqaW55IHJvemRlbGVuw6kgZG8gdHJvY2gga2xhc3Ryb3Y6CgoqS2xhc3RlciAxOiogbWVuxaFpZSBhIHN0cmVkbmUgdmXEvmvDqSBrcmFqaW55IHMgdnnFocWhb3UgaHVzdG90b3Ugb2J5dmF0ZcS+c3R2YSwKKktsYXN0ZXIgMjoqIHZlxL5rw6kga3JhamlueSBzIHZ5c29rb3UgcG9wdWzDoWNpb3UgYSBzdHJlZG5vdSBodXN0b3RvdSwKKktsYXN0ZXIgMzoqIHZlxL5taSB2ZcS+a8OpIGtyYWppbnkgcyBuw616a291IGh1c3RvdG91IG9ieXZhdGXEvnN0dmEuCgpUw6F0byBhbmFsw716YSBuw6FtIHVtb8W+bmlsYSBpZGVudGlmaWtvdmHFpSDFoXRydWt0dXLDoWxuZSBwb2RvYm5vc3RpIG1lZHppIGtyYWppbmFtaSBhIGxlcMWhaWUgcG9jaG9wacWlIHJlZ2lvbsOhbG5lIHJvemRpZWx5IHYgZGVtb2dyYWZpaS4KYGBge3J9CnJtKGxpc3QgPSBscygpKQp1ZGFqZSA8LSByZWFkLmNzdigid29ybGRfcG9wdWxhdGlvbi5jc3YiLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpCmtvbnRpbmVudHkgPC0gYygiRXVyb3BlIikKdWRhamUyMDIwIDwtIHN1YnNldCh1ZGFqZSwgQ29udGluZW50ICVpbiUga29udGluZW50eSkKIyB2w71iZXIgc3TEunBjb3YsIGt0b3LDqSB2IGRhdGFiw6F6ZSBleGlzdHVqw7oKdWRhamUyMDIwIDwtIHVkYWplMjAyMFssIGMoIkNvdW50cnkuVGVycml0b3J5IiwgIlgyMDIwLlBvcHVsYXRpb24iLCJBcmVhLi5rbS4uIiwiRGVuc2l0eS4ucGVyLmttLi4iLCJHcm93dGguUmF0ZSIpXQpyb3duYW1lcyh1ZGFqZTIwMjApIDwtIHVkYWplMjAyMCRDb3VudHJ5LlRlcnJpdG9yeQp1ZGFqZTIwMjAkQ291bnRyeS5UZXJyaXRvcnkgPC0gTlVMTAp1ZGFqZTIwMjAKYGBgCmBgYHtyfQp1ZGFqZV9jb21wbGV0ZSA8LSBuYS5vbWl0KHVkYWplMjAyMCkKdWRhamVfc2NhbGVkIDwtIHNjYWxlKHVkYWplX2NvbXBsZXRlKQpgYGAKYGBge3IgYm94cGxvdHMsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGZpZy5zaG93PSdob2xkJ30KbnVtX3ZhcnMgPC0gYXMuZGF0YS5mcmFtZSh1ZGFqZV9zY2FsZWQpCm51bV9wbG90cyA8LSBuY29sKG51bV92YXJzKQpwYXIobWZyb3cgPSBjKGNlaWxpbmcoc3FydChudW1fcGxvdHMpKSwgY2VpbGluZyhudW1fcGxvdHMgLyBjZWlsaW5nKHNxcnQobnVtX3Bsb3RzKSkpKSkKcGFyKG1hciA9IGMoNCwgNCwgMiwgMSkpCmZvciAoY29sIGluIG5hbWVzKG51bV92YXJzKSkgewogIGJveHBsb3QobnVtX3ZhcnNbW2NvbF1dLAogICAgICAgICAgbWFpbiA9IGNvbCwKICAgICAgICAgIGNvbCA9ICJsaWdodHBpbmsiLAogICAgICAgICAgaG9yaXpvbnRhbCA9IFRSVUUpfQptdGV4dCgiQm94cGxvdHkgbnVtZXJpY2vDvWNoIHByZW1lbm7DvWNoIChyb2sgMjAyMCkiLCBvdXRlciA9IFRSVUUsIGNleCA9IDEuMywgZm9udCA9IDIpCmBgYApUZW50byBncmFmIG7DoW0gdWthenVqZSByb3pkZWxlbmllIMWhdHlyb2NoIHByZW1lbm7DvWNoIGV1csOzcHNreWNoIMWhdMOhdG92IHBvIGxvZ2FyaXRtaWNrZWogdHJhbnNmb3Jtw6FjaWk6IHBvcHVsw6FjaWUsIHJvemxvaHksIGh1c3RvdHkgb2J5dmF0ZcS+c3R2YSBhIG1pZXJ5IHJhc3R1LiBWaWTDrW1lLCDFvmUgcG9wdWzDoWNpYSwgcm96bG9oYSBhaiBodXN0b3RhIG1hasO6IHbDpMSNxaFpbm91IG7DrXprZSBhxb4gc3RyZWRuw6kgaG9kbm90eSwgbm8gesOhcm92ZcWIIG9ic2FodWrDuiB2w71yYXpuw6kgb2TEvmFobMOpIGhvZG5vdHksIMSNbyB6bmFtZW7DoSBwcsOtdG9tbm9zxaUgdmXEvmvDvWNoIGFsZWJvIHZlxL5taSBodXN0w71jaCBrcmFqw61uLiBNaWVyYSByYXN0dSBwb3B1bMOhY2llIGplIHp2w6TEjcWhYSBibMOtemtvIG51bGUsIGF2xaFhayBuaWVrdG9yw6kgxaF0w6F0eSB2eWthenVqw7ogdsO9cmF6bmVqxaHDrSBwb2tsZXMgYWxlYm8gbsOhcmFzdC4KCmBgYHtyfQpkaXN0X21hdCA8LSBkaXN0KHVkYWplMjAyMCwgbWV0aG9kID0gImV1Y2xpZGVhbiIpCmhjIDwtIGhjbHVzdChkaXN0X21hdCwgbWV0aG9kID0gIndhcmQuRDIiKQpwbG90KGhjLCBsYWJlbHMgPSByb3duYW1lcyh1ZGFqZV9zY2FsZWQpLAogICAgIG1haW4gPSAiSGllcmFyY2hpY2FsIGtsYXN0ZXJpbmcgb2YgY291bnRyaWVzIChXYXJkLkQyKSIsCiAgICAgeGxhYiA9ICIiLCBzdWIgPSAiIikKayA8LSAzCmhfY3V0IDwtIGhjJGhlaWdodFtsZW5ndGgoaGMkaGVpZ2h0KSAtIChrIC0gMSldCmFibGluZShoID0gaF9jdXQsIGNvbCA9ICJwaW5rIiwgbHdkID0gNiwgbHR5ID0gNikKa2xhc3Rlcl9tZW1iZXJzaGlwIDwtIGN1dHJlZShoYywgayA9IGspCnVkYWplX2tsYXN0ZXJzIDwtIGRhdGEuZnJhbWUoCiAgQ291bnRyeSA9IHJvd25hbWVzKHVkYWplX2NvbXBsZXRlKSwKICB1ZGFqZV9jb21wbGV0ZSwKICBrbGFzdGVyID0gZmFjdG9yKGtsYXN0ZXJfbWVtYmVyc2hpcCkpCmBgYApUZW50byBkZW5kcm9ncmFtIG7DoW0gem9icmF6dWplIHbDvXNsZWRreSBoaWVyYXJjaGlja8OpaG8gemhsdWtvdmFuaWEgZXVyw7Nwc2t5Y2gga3JhasOtbiBuYSB6w6FrbGFkZSB2eWJyYW7DvWNoIGNoYXJha3RlcmlzdMOtayBwb21vY291IG1ldMOzZHkgV2FyZC5EMi5WaWTDrW1lLCDFvmUga3JhamlueSBzYSBkZWxpYSBkbyBuaWVrb8S+a8O9Y2ggdsO9cmF6bsO9Y2ggc2t1cMOtbiBwb2TEvmEgcG9kb2Jub3N0aSB2IGFuYWx5em92YW7DvWNoIGTDoXRhY2guIE5pZWt0b3LDqSBrcmFqaW55IHPDuiB2ZcS+bWkgYmzDrXprbyBzZWJhLCDEjW8gem5hbWVuw6EsIMW+ZSBtYWrDuiBwb2RvYm7DqSBob2Rub3R5IHByZW1lbm7DvWNoLCB6YXRpYcS+IMSNbyBpbsOpIHR2b3JpYSBzYW1vc3RhdG7DqSwgb2RsacWhbsOpIGtsYXN0cmUuUHJlcnXFoW92YW7DoSDEjWVydmVuw6EgxI1pYXJhIHByZWRzdGF2dWplIHByYWgsIHBvZMS+YSBrdG9yw6lobyBtw7TFvmVtZSB1csSNacWlIHBvxI1ldCB6aGx1a292LiBQb2QgdMO9bXRvIHByYWhvbSBzYSBrcmFqaW55IHJvemRlxL51asO6IGRvIHZpYWNlcsO9Y2ggc2t1cMOtbiwga3RvcsOpIG3DtMW+ZW1lIMSPYWxlaiBza8O6bWHFpSwgbmFwcsOta2xhZCBuYSB6w6FrbGFkZSBwb2RvYm5laiBodXN0b3R5IG9ieXZhdGXEvnN0dmEsIHZlxL5rb3N0aSBhbGVibyBwb3B1bMOhY2llLlRlbnRvIHbDvXNsZWRvayBuw6FtIHVtb8W+xYh1amUgbGVwxaFpZSBwb3JvenVtaWXFpSDFoXRydWt0w7pyZSBkw6F0IGEgaWRlbnRpZmlrb3ZhxaUgcHJpcm9kemVuw6kgem9za3VwZW5pYSBrcmFqw61uIHYgRXVyw7NwZSwgxI1vIGplIHXFvml0b8SNbsOpIHByZSDEj2FsxaFpZSBhbmFsw716eSBhIHBvcm92bmFuaWEuCgpgYGB7cn0KZGF0YV9wcmFjIDwtIGRhdGEuZnJhbWUoY2JpbmQodWRhamVfa2xhc3RlcnMkQ291bnRyeSwgdWRhamVfa2xhc3RlcnMka2xhc3RlcikpCmNvbG5hbWVzKGRhdGFfcHJhYykgPC0gYygiQ291bnRyeSIsImtsYXN0ZXIiKQpkYXRhX3ByYWMKYGBgCmBgYHtyfQp1ZGFqZTIwMjAgPC0gZGF0YS5mcmFtZSgKICB1ZGFqZTIwMjAsCiAga2xhc3RlciA9IHVkYWplX2tsYXN0ZXJzJGtsYXN0ZXIpCmxpYnJhcnkoZHBseXIpCmRlc2NyaXB0aXZlcyA8LSB1ZGFqZTIwMjAgJT4lCiAgZ3JvdXBfYnkoa2xhc3RlcikgJT4lCiAgc3VtbWFyaXNlKAogICAgYWNyb3NzKAogICAgICAuY29scyA9IHdoZXJlKGlzLm51bWVyaWMpLAogICAgICAuZm5zID0gbGlzdCgKICAgICAgICBtZWFuID0gfm1lYW4oLngsIG5hLnJtID0gVFJVRSkpLAogICAgICAubmFtZXMgPSAiey5jb2x9X3suZm59IikpCmRlc2NyaXB0aXZlcwpgYGAKCiMgNy5QcmVkaWtjaWEgYnVkw7pjZWogcG9wdWzDoWNpZQpWIHBvc2xlZG5laiDEjWFzdGkgcHLDoWNlIGJvbGEgdnlrb25hbsOhIGplZG5vZHVjaMOhIHByZWRpa2NpYSBwb3B1bMOhY2llIG5hIHJva3kgMjAyNSBhIDIwMzAgbmEgesOha2xhZGUgaGlzdG9yaWNrZWogcG9wdWzDoWNpZSBhIG1pZXJ5IHJhc3R1LgpgYGB7cn0KIyBMb2FkIGRhdGEKdWRhamUgPC0gcmVhZC5jc3YoIndvcmxkX3BvcHVsYXRpb24uY3N2IiwgZGVjPSIuIiwgc2VwPSIsIiwgaGVhZGVyID0gVFJVRSkKdWRhamVfcHJlZCA8LSB1ZGFqZVssIGMoIkNvdW50cnkuVGVycml0b3J5IiwiWDIwMjAuUG9wdWxhdGlvbiIsICJYMjAxNS5Qb3B1bGF0aW9uIiwiR3Jvd3RoLlJhdGUiLCAiQ29udGluZW50IildCm51bWVyaWNfY29scyA8LSBjKCJYMjAyMC5Qb3B1bGF0aW9uIiwgIlgyMDE1LlBvcHVsYXRpb24iLCAiR3Jvd3RoLlJhdGUiKQpjb2x1bW5fbWVkaWFucyA8LSBzYXBwbHkodWRhamVfcHJlZFssIG51bWVyaWNfY29sc10sIG1lZGlhbiwgbmEucm0gPSBUUlVFKQpmb3IgKGNvbCBpbiBudW1lcmljX2NvbHMpIHsKICB1ZGFqZV9wcmVkW1tjb2xdXVtpcy5uYSh1ZGFqZV9wcmVkW1tjb2xdXSldIDwtIGNvbHVtbl9tZWRpYW5zW2NvbF19CnVkYWplX3ByZWQkbG9nX3BvcCA8LSBsb2codWRhamVfcHJlZCRYMjAyMC5Qb3B1bGF0aW9uKQp1ZGFqZV9wcmVkJGxvZ19wb3AxNSA8LSBsb2codWRhamVfcHJlZCRYMjAxNS5Qb3B1bGF0aW9uKQp1ZGFqZSA8LSB1ZGFqZV9wcmVkCmBgYAoqKsSMbyBza8O6bWFtZToqKgotIFByaXByYXZ1amVtZSBkw6F0YSBuYSBwcmVkaWtjaXUgYnVkw7pjZWogcG9wdWzDoWNpZS4KLSBDaMO9YmFqw7pjZSBob2Rub3R5IGRvcMS6xYhhbWUgbWVkacOhbm9tLCBhYnkgbW9kZWwgZnVuZ292YWwgc3Byw6F2bmUuCi0gTG9nLXRyYW5zZm9ybcOhY2lhIHBvcHVsw6FjaWUgc3RhYmlsaXp1amUgZXh0csOpbW5lIHJvemRpZWx5IG1lZHppIG1hbMO9bWkgYSB2ZcS+a8O9bWkga3JhamluYW1pLgoKKipQcmUgYnVkw7pjdSBwb3B1bMOhY2l1IG7DoXMgbmFqdmlhYyB6YXVqw61tYSBoaXN0b3JpY2vDoSBwb3B1bMOhY2lhIGEgcmFzdCoqCmBgYHtyfQp4dmFycyA8LSB1ZGFqZVssIGMoIlgyMDE1LlBvcHVsYXRpb24iLCAiR3Jvd3RoLlJhdGUiKV0Kcm91bmQoY29yKHh2YXJzKSwgMykKYGBgClNjYXR0ZXJwbG90b3bDoSBtYXRpY2Eg4oCTIGhpc3Rvcmlja8OhIHBvcHVsw6FjaWEgYSBHcm93dGggUmF0ZQoKKipWaXp1YWxpenVqZW1lIHZ6xaVhaCBtZWR6aSBoaXN0b3JpY2tvdSBwb3B1bMOhY2lvdSBhIHJhc3RvbSBhIHBvenJpZW1lIHNhLCDEjWkgZXhpc3R1asO6IGV4dHLDqW1uZSBob2Rub3R5IGFsZWJvIG5ldHlwaWNrw6kga3JhamlueS4qKgoKQWtvIG3DtMW+bWUgdmlkaWXFpSwgdsOkxI3FoWluYSBrcmFqw61uIHNhIG5hY2jDoWR6YSB2IHN0YWJpbG5vbSBww6FzbWUgcmFzdHUsIG5pZWt0b3LDqSBtYWrDuiBleHRyw6ltbmUgaG9kbm90eSwga3RvcsOpIG3DtMW+dSBvdnBseXZuacWlIHByZWRpa2NpdS4KYGBge3J9CnBhaXJzKHh2YXJzLCBtYWluID0gIlNjYXR0ZXJwbG90b3bDoSBtYXRpY2Eg4oCTIGhpc3Rvcmlja8OhIHBvcHVsw6FjaWEgYSBHcm93dGggUmF0ZSIpCmBgYApgYGB7cn0KbW9kZWxfcHJlZCA8LSBsbShsb2dfcG9wIH4gbG9nX3BvcDE1ICsgR3Jvd3RoLlJhdGUgKyBDb250aW5lbnQsIGRhdGEgPSB1ZGFqZSkKIyBTcMOkdG7DoSB0cmFuc2Zvcm3DoWNpYSBuYSBwb8SNZXQgb2J5dmF0ZcS+b3YKdWRhamUkcHJlZF9wb3AyMDIwIDwtIGV4cChwcmVkaWN0KG1vZGVsX3ByZWQsIG5ld2RhdGEgPSB1ZGFqZSkpCiMgUHJlZGlrY2lhIHBvZMS+YSBHcm93dGguUmF0ZQp1ZGFqZSRwcmVkX3BvcDIwMjUgPC0gdWRhamUkWDIwMjAuUG9wdWxhdGlvbiAqICgxICsgdWRhamUkR3Jvd3RoLlJhdGUpXjUKdWRhamUkcHJlZF9wb3AyMDMwIDwtIHVkYWplJFgyMDIwLlBvcHVsYXRpb24gKiAoMSArIHVkYWplJEdyb3d0aC5SYXRlKV4xMAojIC0tLSBWw71iZXIga29ua3LDqXRueWNoIGtyYWrDrW4gLS0tCnZ5YnJhbmVfa3JhamlueSA8LSBjKCJTbG92YWtpYSIsICJDemVjaCBSZXB1YmxpYyIsICJIdW5nYXJ5IiwgIkF1c3RyaWEiLCAiVWtyYWluZSIsICJQb2xhbmQiKQojIEZpbHRyb3ZhbmllIHBvZMS+YSBuw6F6dnUga3JhamlueQp1ZGFqZV92eWJyYW5lIDwtIHVkYWplW3VkYWplJENvdW50cnkuVGVycml0b3J5ICVpbiUgdnlicmFuZV9rcmFqaW55LCBdCiMgLS0tIFpvYnJhemVuaWUgdsO9c2xlZGt1IC0tLQp1ZGFqZV92eWJyYW5lWywgYygiQ291bnRyeS5UZXJyaXRvcnkiLCAiWDIwMjAuUG9wdWxhdGlvbiIsICJwcmVkX3BvcDIwMjAiLCAicHJlZF9wb3AyMDI1IiwgInByZWRfcG9wMjAzMCIpXQpgYGAKKlByZWRpa3VqZW1lIHBvcHVsw6FjaXUgZG8gYnVkw7pjbm9zdGkgKDIwMjUgYSAyMDMwKSBwb21vY291IEdyb3d0aC5SYXRlLiBVbW/FvsWIdWplIG7DoW0gb2RoYWRuw7rFpSByYXN0IGEgcG9yb3ZuYcWlIGhvIG1lZHppIGtyYWppbmFtaS4qCgpLZcSPIHNhIHBvenJpZW1lIG5hIG5hxaFlIHbDvXNsZWRreSwgdmlkw61tZSwgxb5lIHbDvWNob2Rpc2tvdsOpIGhvZG5vdHkgcG9wdWzDoWNpZSB2IHJva3UgMjAyMCB6b2Rwb3ZlZGFqw7ogcmXDoWxueW0gcG/EjXRvbSBvYnl2YXRlxL5vdiB2IGplZG5vdGxpdsO9Y2gga3Jhamluw6FjaC4gTW9kZWwgdsWhYWsgcHJpIGRsaG9kb2JlaiBwcmVkaWtjaWkgKG5ham3DpCBzbWVyb20gayByb2t1IDIwMzApIGdlbmVydWplIGV4dHLDqW1uZSB2eXNva8OpIMSNw61zbGEuIFRvdG8gc2EgZGVqZSBwcmV0bywgxb5lIHNtZSBwb3XFvmlsaSBqZWRub2R1Y2jDvSB2w71wb8SNZXQgemFsb8W+ZW7DvSBuYSBleHBvbmVuY2nDoWxub20gcmFzdGUsIGt0b3LDvSBwcmkgZGxoxaFvbSBvYmRvYsOtIHZlxL5taSBwcmVow6HFiGEgdsO9c2xlZGt5LgoKViBrcsOhdGtvZG9ib20gaG9yaXpvbnRlIChkbyByb2t1IDIwMjUpIHPDuiBwcmVkcG92ZWRlIGXFoXRlIHJlbGF0w612bmUgcG9kb2Juw6kgcmVhbGl0ZSDigJMgcG9wdWzDoWNpYSBzYSBtZW7DrSBsZW4gbWllcm5lLgpWIGRsaG9kb2JvbSBob3Jpem9udGUgKHJvayAyMDMwKSB1xb4gbW9kZWwgcHJlZHBvdmVkw6EgbmVyZcOhbG5lIHZ5c29rw70gbsOhcmFzdCwgdGFrxb5lIHRpZXRvIMSNw61zbGEgbmV2bsOtbWFtZSBha28gc2t1dG/EjW7DuiBwcmVkcG92ZcSPLCBhbGUgc2vDtHIgYWtvIHVrw6HFvmt1IHRvaG8sIGFrbyByw71jaGxvIHZpZSBwb3B1bMOhY2lhIG5hcsOhc8WlLCBrZcSPIG5lY2jDoW1lIHYgbW9kZWxpIHDDtHNvYmnFpSByYXN0b3bDuiBtaWVydSBiZXogb2JtZWR6ZW5pYS4KCioqS3Jhamluw6FtIG3DtMW+ZW1lIHByaXDDrXNhxaUgdGlldG8gdHJlbmR5OioqCgoqU2xvdmVuc2tvLCDEjGVza28sIFJha8O6c2tvLCBNYcSPYXJza28gYSBQb8S+c2tvKiDigJMga3LDoXRrb2RvYm8gc3RhYmlsbsOpLCBiZXogdmXEvmvDvWNoIHptaWVuLgoKKlVrcmFqaW5hKiDigJMga3LDoXRrb2RvYm8gc2vDtHIgcG9rbGVzLCDEjW8gem9kcG92ZWTDoSByZWFsaXRlLgoKIyMgKlppc3RlbmlhKgoKLT4ga3LDoXRrb2RvYsOpIHByZWRpa2NpZSAoZG8gcm9rdSAyMDI1KSBzw7ogcmVsYXTDrXZuZSBzdGFiaWxuw6ksCi0+ZGxob2RvYsOpIHByZWRpa2NpZSBnZW5lcnVqw7ogZXh0csOpbW5lIHZ5c29rw6kgaG9kbm90eSB2IGTDtHNsZWRrdSBleHBvbmVuY2nDoWxuZWhvIGNoYXJha3RlcnUgbW9kZWx1LgoKVGlldG8gdsO9c2xlZGt5IHByZXRvIG5laW50ZXJwcmV0dWplbWUgYWtvIHJlYWxpc3RpY2vDuiBwcm9nbsOzenUsIGFsZSBha28gaWx1c3Ryw6FjaXUgY2l0bGl2b3N0aSBtb2RlbHUgbmEgcmFzdG92w7ogbWllcnUuCgojIDguWsOhdmVyCgpBbmFsw716YSB2w712b2phIHBvcHVsw6FjaWUgU2xvdmVuc2tlaiByZXB1Ymxpa3kgYSDEjGVza2VqIHJlcHVibGlreSB1a8OhemFsYSwgxb5lIHYgc2xlZG92YW5vbSBvYmRvYsOtIGRvY2jDoWR6YSB2IG9ib2NoIGtyYWppbsOhY2ggayAqKnJlbGF0w612bmUgc3RhYmlsbsOpbXUgZGVtb2dyYWZpY2vDqW11IHbDvXZvanUqKiwgYmV6IHbDvXJhem7DvWNoIHbDvWt5dm92IHYgY2Vsa292b20gcG/EjXRlIG9ieXZhdGXEvm92LiBOYXByaWVrIHBvZG9ibsOpbXUgdHJlbmR1IGplIHJvemRpZWwgdiBhYnNvbMO6dG5laiB2ZcS+a29zdGkgcG9wdWzDoWNpZSBtZWR6aSB0w71taXRvIGtyYWppbmFtaSB2w71yYXpuw70gYSBkbGhvZG9ibyBwcmV0cnbDoXZhasO6Y2ksIMSNbyBvZHLDocW+YSBpY2ggb2RsacWhbsO6IGhpc3Rvcmlja8O6IGEgZGVtb2dyYWZpY2vDuiB0cmFqZWt0w7NyaXUuCgpBbmFsw716YSBodXN0b3R5IG9ieXZhdGXEvnN0dmEgcG90dnJkaWxhLCDFvmUgdGVudG8gdWthem92YXRlxL4gKipuaWUgamUgbW/Fvm7DqSBqZWRub2R1Y2hvIHZ5c3ZldGxpxaUgbGVuIHBvbW9jb3UgdmXEvmtvc3RpIHBvcHVsw6FjaWUgYWxlYm8gcm96bG9oeSBrcmFqaW55KiouIFbDvXNsZWRreSBuYXpuYcSNdWrDuiwgxb5lIGh1c3RvdGEgb2J5dmF0ZcS+c3R2YSBqZSBvdnBseXZuZW7DoSDFoWlyxaHDrW0gc3Bla3Ryb20gZmFrdG9yb3YsIGFrbyBzw7ogZ2VvZ3JhZmlja8OpIHBvZG1pZW5reSwgw7pyb3ZlxYggdXJiYW5pesOhY2llLCBla29ub21pY2vDoSDFoXRydWt0w7pyYSDEjWkgaGlzdG9yaWNrw70gdsO9dm9qIG9zw61kbGVuaWEuIEplZG5vZHVjaMOpIGxpbmXDoXJuZSBtb2RlbHkgcHJldG8gbmVkb2vDocW+dSBwbG5lIHphY2h5dGnFpSBrb21wbGV4bm9zxaUgdG9odG8gamF2dS4KClBvdcW+aXTDqSDFoXRhdGlzdGlja8OpIGEgcmVncmVzbsOpIG1vZGVseSBzYSB1a8OhemFsaSBha28gdmhvZG7DqSBuw6FzdHJvamUgbmEgZGVza3JpcHTDrXZudSBhbmFsw716dSBhIGtyw6F0a29kb2LDqSBwb3Jvdm5hbmllIGRlbW9ncmFmaWNrw71jaCB0cmVuZG92IG1lZHppIGtyYWppbmFtaS4gUHJpIHBva3Vzb2NoIG8gZGxob2RvYmVqxaFpdSBwcmVkaWtjaXUgcG9wdWzDoWNpZSBzYSB2xaFhayBwcmVqYXZpbGkgaWNoICoqdsO9cmF6bsOpIG9ibWVkemVuaWEqKiwgbmFqbcOkIGNpdGxpdm9zxaUgbmEgenZvbGVuw7ogbWllcnUgcmFzdHUgYSBwcmVkcG9rbGFkIGtvbsWhdGFudG7DqWhvIHRyZW5kdSB2IMSNYXNlLiBQcmUgcmVhbGlzdGlja2VqxaFpZSBwcm9nbsOzenkgYnkgYm9sbyBwb3RyZWJuw6kgdXBsYXRuacWlIHNvZmlzdGlrb3ZhbmVqxaFpZSBkZW1vZ3JhZmlja8OpIHByw61zdHVweSwga3RvcsOpIHpvaMS+YWTFiHVqw7ogdmVrb3bDuiDFoXRydWt0w7pydSBvYnl2YXRlxL5zdHZhLCBtaWdyYcSNbsOpIHRva3kgYSBmZXJ0aWxpdHUuCgpOYXByaWVrIHV2ZWRlbsO9bSBvYm1lZHplbmlhbSBwcsOhY2EgcG9za3l0dWplIHVjZWxlbsO9IHBvaMS+YWQgbmEgesOha2xhZG7DqSBkZW1vZ3JhZmlja8OpIHJvemRpZWx5IGEgcG9kb2Jub3N0aSBtZWR6aSB2eWJyYW7DvW1pIGtyYWppbmFtaSBFdXLDs3B5LiBaw6Fyb3ZlxYggcG91a2F6dWplIG5hICoqbGltaXR5IGplZG5vZHVjaMO9Y2ggxaF0YXRpc3RpY2vDvWNoIG1vZGVsb3YqKiBwcmkgYW5hbMO9emUgcG9wdWxhxI1uw71jaCBwcm9jZXNvdiBhIHpkw7RyYXrFiHVqZSBwb3RyZWJ1IG9wYXRybmVqIGludGVycHJldMOhY2llIHbDvXNsZWRrb3YsIG5ham3DpCBwcmkgaWNoIHZ5dcW+aXTDrSBuYSAqKnByZWRpa8SNbsOpIMO6xI1lbHkqKi4KCgoKCgoKCgoKCgoKCgoKCgo=