Úvod

Klastrová (zhluková) analýza patrí medzi najpoužívanejšie metódy exploratívnej štatistiky. V praxi sa využíva všade tam, kde je potrebné rozdeliť pozorovania do homogénnych celkov - napríklad pri segmentácii zákazníkov v marketingu, identifikácii podobných krajín v makroekonomických ukazovateľoch, hodnotenízdravotných rizík, klasifikácii biologických vzoriek či v geoinformatike pri zoskupovaní priestorových sobjektov. Jej výhodou je, že pracuje s viacerými premennými naraz a dokáže odhaliť vzory, ktoré by pri samotnom hodnotení jednotlivých ukazovateľov zostali skryté. Správne zvolená metrika vzdialenosti a metóda zhlukovania umožňujú odhaliť skryté vzťahy v dátach, čím poskytujú cenný podklad pre rozhodovanie v rôznych oblastiach aplikovaného výskumu.

Predstavím zhlukovú analýzu pri analýze krajín sveta z hľadiska demografických ukazovateľov, ako sú predpokladaná populácia v roku 2025, miera plodnosti, medián veku a čistá migrácia. Cieľom je identifikovať skupiny krajín, ktoré majú podobné demografické profily a môžu byť preto analyzované spoločne. Takto vytvorené zhluky poskytujú prehľad o krajinách s podobným populačným vývojom či dynamikou rastu populácie. Pri analýze využívame najnovšie dostupné údaje z databázy, s ktorou sme pracovali aj v predchádzajúcich častiach.

library(knitr)
library(kableExtra)
# Načítanie dát
udaje <- read.csv("population_data.csv", stringsAsFactors = FALSE)

# 10 európskych krajín, s ktorými chcem pracovať
krajiny10 <- c("Germany",
               "United Kingdom",
               "France",
               "Italy",
               "Spain",
               "Ukraine",
               "Poland",
               "Romania",
               "Netherlands",
               "Belgium")

# Výber len týchto krajín a požadovaných premenných
udaje10 <- subset(
  udaje,
  Country..or.dependency. %in% krajiny10,
  select = c(
    Country..or.dependency.,
    Population.2025,
    Fert..Rate,
    Median.Age,
    Migrants..net.
  )
)

# Pre pomenovanie stĺpcov v tabuľke
colnames(udaje10) <- c(
  "Krajina",
  "Populácia 2025",
  "Miera plodnosti",
  "Medián veku",
  "Čistá migrácia"
)

Table 1.

udaje10

Hierarchická zhluková analýza pracuje s mierami vzdialenosti medzi pozorovaniami. Aby boli tieto vzdialenosti porovnateľné, je potrebné, aby všetky premenné boli definované na rovnakejškále. Používame pritom tzv. z-škálovanie, pričom transformované \(z\) hodnoty (skóre) vypočítame nasledovne

\[z = \frac{x-\mu}{\sigma}\]

kde \(\mu\) je stredná hodnota a \(\sigma\) je štandardná odchýlka pozorovaní \(x\). Predpokladáme pritom, že súbor údajov už neobsahuje NA hodnoty, ktoré boli ošetrené v predchádzajúcich krokoch.

Touto operáciou získame škálované pozorovania, pričom ich rozloženie je znázornené nasledovne:

# 1) Načítanie dát -------------------------------------------------------
udaje <- read.csv("population_data.csv",
                  sep = ",",
                  header = TRUE,
                  stringsAsFactors = FALSE)

# 2) Vyberieme 10 európskych krajín, s ktorými chceme pracovať ----------
krajiny10 <- c("Germany",
               "United Kingdom",
               "France",
               "Italy",
               "Spain",
               "Ukraine",
               "Poland",
               "Romania",
               "Netherlands",
               "Belgium")

# filter na týchto 10 krajín
udaje10 <- subset(udaje, Country..or.dependency. %in% krajiny10)

# pre istotu zoradíme riadky v rovnakom poradí ako vo vektore krajiny10
udaje10 <- udaje10[match(krajiny10, udaje10$Country..or.dependency.), ]

# 3) Pripravíme dátový rámec len s číselnými premennými -----------------
#    (populácia 2025, miera plodnosti, medián veku, čistá migrácia)
udaje_complete <- udaje10[, c("Population.2025",
                              "Fert..Rate",
                              "Median.Age",
                              "Migrants..net.")]

# istota: pretypujeme stĺpce na numeric (keby ich R načítal ako text)
udaje_complete[] <- lapply(udaje_complete, function(x) as.numeric(x))

# pomenujeme riadky podľa krajín
rownames(udaje_complete) <- udaje10$Country..or..dependency.

# 4) Škálovanie premenných (z-skóre) ------------------------------------
udaje_scaled <- scale(udaje_complete)

# Výstupy do tabuľky (najprv pôvodné dáta, potom škálované)
udaje_complete      # neškálované hodnoty
udaje_scaled        # z-skóre
      Population.2025  Fert..Rate  Median.Age Migrants..net.
 [1,]       1.5833411  0.31344708  0.89440379             NA
 [2,]       0.9895915  0.68771224 -1.29101724     0.05585233
 [3,]       0.8710141  1.15554370 -0.40066052    -0.43681319
 [4,]       0.5642185 -0.85613157  1.98711431    -0.46372711
 [5,]       0.1040462 -0.76256528  1.05628683    -0.42872861
 [6,]      -0.2601892 -1.83857763 -0.60301432     2.22437606
 [7,]      -0.2945077 -0.38830011 -0.31971900             NA
 [8,]      -1.0807476  1.48302572 -0.03642368             NA
 [9,]      -1.1037160  0.21988079 -0.72442660    -0.41542614
[10,]      -1.3730509 -0.01403494 -0.56254356    -0.53553334
attr(,"scaled:center")
Population.2025      Fert..Rate      Median.Age  Migrants..net. 
   45344878.700           1.393          43.290      356107.714 
attr(,"scaled:scale")
Population.2025      Fert..Rate      Median.Age  Migrants..net. 
   2.446106e+07    2.137522e-01    2.470920e+00    6.052260e+05 

Obr. 1.

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 = "lightblue",
          horizontal = TRUE)
}

mtext("Boxploty numerických premenných (vybraných 10 krajín)", outer = TRUE, cex = 1.3, font = 2)

Tentokrát odľahlé hodnoty nevylúčime, nakoľko definujú konkrétnu krajinu.

Pri zhlukovej analýze je dôležitá korelačná matica premenných. Vysoká korelácia zvýhodňuje pri zhlukovej analýze korelované premenné. Preto pri korelácii nad 0,8 alebo 0.9 vylúčime jednu z korelovaných premenných. V Tab. 2. sa však takáto vysoká korelácia nenachádza, preto sa nemusíme ďalej s problémom zaoberať. > V prípade, ak máme väčší počet významne korelovaných premenných, sa odporúča i transformácia pomocou Analýzy hlavných komponentov (Principal Component Analysis) Pri zhlukovej analýze je dôležitá korelačná matica premenných. Vysoká korelácia medzi premennými môže spôsobovať, že niektoré z nich budú mať pri tvorbe zhlukov neprimerane veľký vplyv. Preto sa pri koreláciách vyšších ako 0.8 – 0.9 často odporúča vylúčiť jednu z dvojice silne korelovaných premenných. V našom prípade (pozri Tab. 2) však žiadna z korelácií nedosahuje hodnotu, ktorá by bola problematická:

najvyššia korelácia je medzi premennými Fert..Rate a Migrants..net. na úrovni –0.64, ostatné korelácie sa pohybujú len v intervale približne –0.30 až 0.32, premenné teda nie sú výrazne multikolineárne. To znamená, že sa nemusíme zaoberať odstraňovaním premenných ani uvažovať o ďalšej transformácii z dôvodu vysokej korelácie. V prípade, že by sme mali väčší počet veľmi korelovaných ukazovateľov, bolo by vhodné zvážiť transformáciu pomocou Analýzy hlavných komponentov (Principal Component Analysis). V našom prípade to však nie je potrebné.

Tab. 2

cor_mat <- cor(udaje_scaled, use="pairwise.complete.obs")
cor_mat <- round(cor_mat,2)
print(cor_mat)
                Population.2025 Fert..Rate Median.Age Migrants..net.
Population.2025            1.00       0.04       0.32           0.00
Fert..Rate                 0.04       1.00      -0.28          -0.64
Median.Age                 0.32      -0.28       1.00          -0.29
Migrants..net.             0.00      -0.64      -0.29           1.00

Každej krajine zodpovedá jeden riadok pozorovaní. Vzdialenosť medzi krajinami \(i\) a \(j\) je:

\[ d^{ij} = \sqrt{\sum_k (x^i_k - x^j_k)^2} \] kde \(x^i_k\) je \(k\)ta premenná vstupujúca do výpočtu (Population.2025, Fert..Rate, Median.Age a Migrants..net.) krajiny \(i\). Tento typ vzdialenosti nazývame aj Euklidovská vzdialenosť. Vzdialenosti medzi jednotlivými krajinami sa súhrnne vyjadrujú aj v matici vzdialenosti, čo v našom prípade je uvedené v Tab.3.. Na základe výsledkov z Tab. 3 môžeme uviesť nasledovné:

Najväčšia vzdialenosť (t. j. najmenšia podobnosť) bola zistená medzi Ukrajinou a Nemeckom (3.70), ako aj medzi Ukrajinou a Francúzskom (3.62). Tieto krajiny sa výrazne líšia najmä v migračnej bilancii, vekovej štruktúre aj plodnosti. Silné rozdiely pozorujeme aj medzi Rumunskom a Dánskom (3.19) a Rumunskom a Holandskom (3.36), čo môže súvisieť s vyššou plodnosťou a odlišnou migračnou dynamikou Rumunska. Najmenšiu vzdialenosť, teda najväčšiu podobnosť, nachádzame medzi: Holandskom a Belgickom (0.41), Francúzskom a Belgickom (1.13), Nemeckom a Veľkou Britániou (2.65) Tieto krajiny vykazujú podobné hodnoty medianu veku a relatívne vyrovnanú migračnú bilanciu. Stredná úroveň podobnosti je napríklad medzi Poľskom a Španielskom (1.71) alebo Francúzskom a Španielskom (2.94). Celkovo teda vidíme, že európske krajiny vytvárajú podľa svojich ukazovateľov prirodzené skupiny – napr. Belgicko–Holandsko, Nemecko–UK, zatiaľ čo krajiny ako Ukrajina či Rumunsko sa od väčšiny ostatných výraznejšie odlišujú.

Tab. 3

## ============================
## 3) Distance matrix
## ============================

# Pomenovanie riadkov podľa 10 zvolených krajín
rownames(udaje_scaled) <- c("Germany",
                            "United Kingdom",
                            "France",
                            "Italy",
                            "Spain",
                            "Ukraine",
                            "Poland",
                            "Romania",
                            "Netherlands",
                            "Belgium")

# Výpočet euklidovskej vzdialenosti a zaokrúhlenie na 2 desatinné miesta
dist_mat <- round(dist(udaje_scaled, method = "euclidean"), 2)

dist_mat
               Germany United Kingdom France Italy Spain Ukraine Poland
United Kingdom    2.65                                                 
France            1.96           1.13                                  
Italy             2.19           3.69   3.14                           
Spain             2.12           2.94   2.53  1.04                     
Ukraine           3.70           3.62   4.17  3.95  3.33               
Poland            2.71           2.24   2.24  2.89  1.71    1.71       
Romania           3.53           2.94   2.32  4.05  3.19    4.00   2.37
Netherlands       3.62           2.27   2.21  3.36  2.37    3.45   1.26
Belgium           3.82           2.64   2.54  3.31  2.32    3.49   1.35
               Romania Netherlands
United Kingdom                    
France                            
Italy                             
Spain                             
Ukraine                           
Poland                            
Romania                           
Netherlands       1.66            
Belgium           1.86        0.41

Princíp hierarchického zhlukovania (Wardova metóda)

Zhlukovanie v prípade Wardovej metódy prebieha zdola smerom nahor, t.j. začíname s jednočlennými klastrami, ktoré postupne zlučujeme. Táto metóda patrí teda medzi aglomeratívne hierarchické metódy. Minimalizuje nárast vnútornej variability pri spojení dvoch klastrov, pričom využíva nasledovné výpočty:

Wardová metóda minimalizuje sumu štvorcov chýb (Error sum of Squares - ESS)

\[ESS(C) = \sum_{i \in C} \lVert x_i - \bar{x}_C \rVert^2\] kde \(C\) je zvažovaný klaster (zhluk). V každom kroku zlučovania dvoch klasterov, Wardova metóda hľadá minimálny prírastok sumy štvorcov chýb (\(\Delta ESS\)), pričom

\[\Delta ESS = ESS(A \cup B) - ESS(A) - ESS(B)\] Dvojica zhlukov, ktoré tejto podmienke o minimalizácii vyhovuje, je následne zlúčená a prechádza sa k ďalšiemu kkroku. To spravidla vedie k vytváraniu homogénnych zhlukov, pričom nedochádza k odtrhávaniu odľahlých hodnôt tak, ako pri iných zhlukovacích metódach.

Obr. 2. Hierarchické zhlukovanie - dendogram. Červená čiara určuje rez definujúci tri klastre.

## ============================
## 4) Hierarchical klastering
## ============================

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 = "red", lwd = 2, lty = 2)


klaster_membership <- cutree(hc, k = k)

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

Tab.4. Príslušnosť krajín do klastrov.

## Tab. 4 – Príslušnosť krajín do klastrov

# Vytvoríme dátový rámec s krajinami a ich klastrom
data_prac <- data.frame(
  Country = rownames(udaje_scaled),
  klaster = udaje_klasters
)

# Zobrazíme výslednú tabuľku
data_prac
NA
# Výsledná tabuľka krajín a ich klastrov
data_prac <- data.frame(
  Country = udaje_klasters$Country,
  Klastor = udaje_klasters$klaster
)

data_prac
NA

Na základe hierarchickej zhlukovej analýzy (Wardova metóda) sme analyzovali podobnosť desiatich európskych krajín podľa vybraných ukazovateľov (Population 2025, Fertility Rate, Median Age, Net Migration). Výsledkom procesu bolo rozdelenie krajín do troch klastrov, pričom krajiny v rámci jedného klastru majú podobnejšie demografické ukazovatele ako krajiny v iných klastroch.

Z tabuľky vidíme nasledovné zaradenie:

Klastre typu 1: tvorí ho Nemecko, Taliansko a Španielsko. Tieto krajiny majú podobnú populačnú veľkosť a spoločné demografické črty, napríklad nízku mieru plodnosti a vyšší mediánový vek, čo sú typické znaky západoeurópskych krajín s dlhodobým starnutím populácie.

Klastre typu 2: sem spadajú Spojené kráľovstvo, Francúzsko, Poľsko, Holandsko, Belgicko a Ukrajina. Ide o najrozmanitejší klaster, ktorý zahŕňa veľké aj stredne veľké krajiny s mierne vyššou plodnosťou, odlišným migračným profilom a rôznorodým vekovým zložením populácie.

Klastre typu 3: predstavuje ho len Rumunsko. Zaradenie Rumunska do samostatného klastru naznačuje, že sa jeho demografické charakteristiky významne odlišujú od ostatných analyzovaných krajín — napríklad nižšou populačnou veľkosťou, špecifickou migráciou či výraznejšími rozdielmi v plodnosti alebo vekovej štruktúre.

Celkovo môžeme konštatovať, že klastrová analýza odhalila prirodzené skupiny krajín so spoločnými demografickými znakmi. Najviac homogénny je klaster č. 1, zatiaľ čo klaster č. 2 zahŕňa krajiny s väčšou vnútornou variabilitou. Samostatné postavenie Rumunska v klasteri č. 3 poukazuje na jeho výraznú odlišnosť od ostatných európskych krajín v sledovaných premenných.

Deskriptívne štatistiky výsledkov

Pri analýze rozkladu variancie sledujeme, aká časť variability jednotlivých premenných je vysvetlená samotným klastrovým riešením. Kľúčovým ukazovateľom je stĺpec Prop_Between, ktorý udáva podiel variability vysvetlenej rozdielmi medzi klastrami (BSS / TSS). Čím je táto hodnota vyššia, tým lepšie klastrovanie zachytáva rozdiely medzi krajinami podľa danej premennej.

Z Tab. 5. vyplýva nasledovné:

Population.2025 – Prop_Between ≈ 0.268 Podiel variability vysvetlenej klastrami je približne 27 %, čo znamená, že populácia iba mierne prispieva k odlišovaniu klastrov. Krajiny sa teda z hľadiska veľkosti populácie v roku 2025 neodlišujú natoľko, aby tvorili jasne oddelené skupiny.

Fert..Rate – Prop_Between ≈ 0.621 Miera plodnosti vysvetľuje až 62 % variability medzi klastrami, čo je pomerne vysoká hodnota. To znamená, že fertilita je významným faktorom, podľa ktorého sa krajiny skutočne odlišujú. Klastry teda zachytávajú rozdiely v demografickej dynamike veľmi dobre.

Median.Age – Prop_Between ≈ 0.821 Až 82 % variability v mediánovom veku je vysvetlených klastrami. Ide o najvyššiu hodnotu zo všetkých sledovaných premenných. Znamená to, že mediánový vek populácie je dominantným ukazovateľom, ktorý najlepšie odlišuje vytvorené skupiny krajín. Krajiny sa teda výrazne líšia v tom, či majú mladšiu alebo staršiu populáciu.

Migrants..net – nebolo možné vyhodnotiť (NA) Pre túto premennú nebol výpočet možný, pravdepodobne kvôli chýbajúcim hodnotám (NA). Preto nevystupuje v rozklade variancie ani v posudzovaní vhodnosti klastrovania.

Tab. 5. Vysvetlenie vnútroklastrovej variability z hľadiska jednotlivých premenných

## ============================
## 5) Variability measures
## ============================

ssq <- function(x, m) sum((x - m)^2)

var_names <- colnames(udaje_scaled)

TSS <- sapply(var_names, function(v) ssq(udaje_scaled[, v], mean(udaje_scaled[, v])))

WSS <- sapply(var_names, function(v) {
  x <- udaje_scaled[, v]
  tapply(x, klaster_membership, function(z) ssq(z, mean(z))) |> sum()
})

BSS <- TSS - WSS

ss_table <- data.frame(
  Variable = var_names,
  TSS = TSS,
  WSS = WSS,
  BSS = BSS,
  Prop_Between = BSS / TSS
)

ss_table
# Pridáme ku datasetu priradené klastry
udaje10 <- data.frame(
  Country          = udaje10$Country..or.dependency.,
  Population.2025  = udaje10$Population.2025,
  Fert..Rate       = udaje10$Fert..Rate,
  Median.Age       = udaje10$Median.Age,
  Migrants..net.   = udaje10$Migrants..net.,
  klaster          = udaje_klasters$klaster
)

# Zobrazenie výsledného datasetu
udaje10
NA

Tab. 6. Centroidy - priemerné hodnoty sledovaných premenných

library(dplyr)

descriptives <- udaje10 %>%
  group_by(klaster) %>%
  summarise(
    across(
      .cols = where(is.numeric),
      .fns = list(
        mean = ~mean(.x, na.rm = TRUE)
      ),
      .names = "{.col}_{.fn}"
    )
  )
descriptives
NA

Na záver sme porovnali priemerné charakteristiky troch klastrov vybraných európskych krajín.

Klaster 1 (Nemecko, Taliansko, Španielsko) má najväčšiu priemernú populáciu – približne 63,7 milióna obyvateľov, strednú mieru plodnosti okolo 1,30 dieťaťa na ženu a zároveň najvyšší mediánový vek (≈ 46,5 roka). Tento klaster teda reprezentuje veľké a demograficky „starnúce“ krajiny so skôr nižšou, ale nie úplne kriticky nízkou plodnosťou.

Klaster 2 (Spojené kráľovstvo, Francúzsko, Poľsko, Rumunsko, Holandsko, Belgicko) má nižšiu priemernú populáciu – asi 37,2 milióna obyvateľov, no zároveň najvyššiu priemernú mieru plodnosti (≈ 1,51) a mladšiu vekovú štruktúru s mediánovým vekom približne 41,9 roka. Tento klaster združuje stredne veľké krajiny, kde je plodnosť relatívne najvyššia a populácia je v priemere mladšia než v klustri 1.

Klaster 3 je tvorený jedinou krajinou – Ukrajinou. Jej priemerná (a zároveň skutočná) populácia je približne 38,98 milióna obyvateľov, pričom má najnižšiu mieru plodnosti (≈ 1,00) a mediánový vek okolo 41,8 roka. Tento klaster predstavuje krajinu s veľmi nízkou plodnosťou, pri vekovej štruktúre podobnej klastru 2.

Z porovnania klastrov vidno, že najvyšší priemerný počet obyvateľov sa spája so staršou populáciou (klaster 1), zatiaľ čo najvyššia plodnosť sa vyskytuje v krajinách so skôr mladšou populáciou (klaster 2). Ukrajina tvorí samostatný klaster kvôli kombinácii priemernej veľkosti populácie a extrémne nízkej miery plodnosti.

Záver

Predložená analýza sa zameriava na demografické charakteristiky vybraných európskych krajín na základe ich predpokladanej populácie v roku 2025, miery plodnosti a mediánu veku obyvateľstva. Na základe týchto premenných boli krajiny rozdelené do troch klastrov, pričom jednotlivé klastry odrážajú spoločné demografické črty týchto štátov.

Výsledné klastry predstavujú tri odlišné skupiny krajín. Prvý klaster tvoria štáty s najvyššou predpokladanou populáciou a zároveň vyšším mediánovým vekom obyvateľstva, čo naznačuje starnúcu populáciu veľkých krajín. Druhý klaster združuje krajiny s relatívne vyššou mierou plodnosti a strednými hodnotami populácie, čo poukazuje na dynamickejší populačný vývoj. Tretí klaster obsahuje krajiny s najnižšou mierou plodnosti a zároveň strednou až nižšou veľkosťou populácie.

Takáto klasifikácia umožňuje pochopiť vzťahy medzi demografickými ukazovateľmi a poukazuje na podobnosti v populačnom vývoji naprieč Európou. Analýza môže slúžiť ako podklad pre tvorbu populačných či sociálnych politík, prípadne pre ďalšie porovnávacie štúdie medzi európskymi krajinami.

LS0tCnRpdGxlOiAiWmhsdWtvdsOhIGFuYWzDvXphIChrbGFzdGVyIEFuYWx5c2lzKSIKYXV0aG9yOiAiUmFkb3ZhbiBTdGFuxI3DrWsiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCi0tLS0tLS0tLQoKYGBge3Igc2V0dXAxLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoCiAgZWNobyAgICA9IFRSVUUsICAgIyBkbyBub3Qgc2hvdyBjb2RlCiAgbWVzc2FnZSA9IFRSVUUsICAgIyBzdXBwcmVzcyBwYWNrYWdlL3N5c3RlbSBtZXNzYWdlcwogIHdhcm5pbmcgPSBGQUxTRSwgICAjIHN1cHByZXNzIHdhcm5pbmdzCiAgZXJyb3IgICA9IEZBTFNFICAgICMgc3VwcHJlc3MgZXJyb3Igb3V0cHV0CikKYGBgCgojIyDDmnZvZAoKS2xhc3Ryb3bDoSAoemhsdWtvdsOhKSBhbmFsw716YSBwYXRyw60gbWVkemkgbmFqcG91xb7DrXZhbmVqxaFpZSBtZXTDs2R5IGV4cGxvcmF0w612bmVqIMWhdGF0aXN0aWt5LiBWIHByYXhpIHNhIHZ5dcW+w612YSB2xaFhZGUgdGFtLCBrZGUgamUgcG90cmVibsOpIHJvemRlbGnFpSBwb3pvcm92YW5pYSBkbyBob21vZ8Opbm55Y2ggY2Vsa292IC0gbmFwcsOta2xhZCBwcmkgc2VnbWVudMOhY2lpIHrDoWthem7DrWtvdiB2IG1hcmtldGluZ3UsIGlkZW50aWZpa8OhY2lpIHBvZG9ibsO9Y2gga3JhasOtbiB2IG1ha3JvZWtvbm9taWNrw71jaCB1a2F6b3ZhdGXEvm9jaCwgaG9kbm90ZW7DrXpkcmF2b3Ruw71jaCByaXrDrWssIGtsYXNpZmlrw6FjaWkgYmlvbG9naWNrw71jaCB2em9yaWVrIMSNaSB2IGdlb2luZm9ybWF0aWtlIHByaSB6b3NrdXBvdmFuw60gcHJpZXN0b3JvdsO9Y2ggc29iamVrdG92LiBKZWogdsO9aG9kb3UgamUsIMW+ZSBwcmFjdWplIHMgdmlhY2Vyw71taSBwcmVtZW5uw71taSBuYXJheiBhIGRva8Ohxb5lIG9kaGFsacWlIHZ6b3J5LCBrdG9yw6kgYnkgcHJpIHNhbW90bm9tIGhvZG5vdGVuw60gamVkbm90bGl2w71jaCB1a2F6b3ZhdGXEvm92IHpvc3RhbGkgc2tyeXTDqS4gU3Byw6F2bmUgenZvbGVuw6EgbWV0cmlrYSB2emRpYWxlbm9zdGkgYSBtZXTDs2RhIHpobHVrb3ZhbmlhIHVtb8W+xYh1asO6IG9kaGFsacWlIHNrcnl0w6kgdnrFpWFoeSB2IGTDoXRhY2gsIMSNw61tIHBvc2t5dHVqw7ogY2VubsO9IHBvZGtsYWQgcHJlIHJvemhvZG92YW5pZSB2IHLDtHpueWNoIG9ibGFzdGlhY2ggYXBsaWtvdmFuw6lobyB2w71za3VtdS4KClByZWRzdGF2w61tIHpobHVrb3bDuiBhbmFsw716dSBwcmkgYW5hbMO9emUga3JhasOtbiBzdmV0YSB6IGjEvmFkaXNrYSBkZW1vZ3JhZmlja8O9Y2ggdWthem92YXRlxL5vdiwgYWtvIHPDuiBwcmVkcG9rbGFkYW7DoSBwb3B1bMOhY2lhIHYgcm9rdSAyMDI1LCBtaWVyYSBwbG9kbm9zdGksIG1lZGnDoW4gdmVrdSBhIMSNaXN0w6EgbWlncsOhY2lhLiBDaWXEvm9tIGplIGlkZW50aWZpa292YcWlIHNrdXBpbnkga3JhasOtbiwga3RvcsOpIG1hasO6IHBvZG9ibsOpIGRlbW9ncmFmaWNrw6kgcHJvZmlseSBhIG3DtMW+dSBiecWlIHByZXRvIGFuYWx5em92YW7DqSBzcG9sb8SNbmUuIFRha3RvIHZ5dHZvcmVuw6kgemhsdWt5IHBvc2t5dHVqw7ogcHJlaMS+YWQgbyBrcmFqaW7DoWNoIHMgcG9kb2Juw71tIHBvcHVsYcSNbsO9bSB2w712b2pvbSDEjWkgZHluYW1pa291IHJhc3R1IHBvcHVsw6FjaWUuIFByaSBhbmFsw716ZSB2eXXFvsOtdmFtZSBuYWpub3bFoWllIGRvc3R1cG7DqSDDumRhamUgeiBkYXRhYsOhenksIHMga3Rvcm91IHNtZSBwcmFjb3ZhbGkgYWogdiBwcmVkY2jDoWR6YWrDumNpY2ggxI1hc3RpYWNoLgoKYGBge3Igc2V0dXAyLCBtZXNzYWdlPUZBTFNFfQpsaWJyYXJ5KGtuaXRyKQpsaWJyYXJ5KGthYmxlRXh0cmEpCmBgYAoKYGBge3IgdGFibGUxLCBtZXNzYWdlPUZBTFNFfQojIE5hxI3DrXRhbmllIGTDoXQKdWRhamUgPC0gcmVhZC5jc3YoInBvcHVsYXRpb25fZGF0YS5jc3YiLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpCgojIDEwIGV1csOzcHNreWNoIGtyYWrDrW4sIHMga3RvcsO9bWkgY2hjZW0gcHJhY292YcWlCmtyYWppbnkxMCA8LSBjKCJHZXJtYW55IiwKICAgICAgICAgICAgICAgIlVuaXRlZCBLaW5nZG9tIiwKICAgICAgICAgICAgICAgIkZyYW5jZSIsCiAgICAgICAgICAgICAgICJJdGFseSIsCiAgICAgICAgICAgICAgICJTcGFpbiIsCiAgICAgICAgICAgICAgICJVa3JhaW5lIiwKICAgICAgICAgICAgICAgIlBvbGFuZCIsCiAgICAgICAgICAgICAgICJSb21hbmlhIiwKICAgICAgICAgICAgICAgIk5ldGhlcmxhbmRzIiwKICAgICAgICAgICAgICAgIkJlbGdpdW0iKQoKIyBWw71iZXIgbGVuIHTDvWNodG8ga3JhasOtbiBhIHBvxb5hZG92YW7DvWNoIHByZW1lbm7DvWNoCnVkYWplMTAgPC0gc3Vic2V0KAogIHVkYWplLAogIENvdW50cnkuLm9yLmRlcGVuZGVuY3kuICVpbiUga3JhamlueTEwLAogIHNlbGVjdCA9IGMoCiAgICBDb3VudHJ5Li5vci5kZXBlbmRlbmN5LiwKICAgIFBvcHVsYXRpb24uMjAyNSwKICAgIEZlcnQuLlJhdGUsCiAgICBNZWRpYW4uQWdlLAogICAgTWlncmFudHMuLm5ldC4KICApCikKCiMgUHJlIHBvbWVub3ZhbmllIHN0xLpwY292IHYgdGFidcS+a2UKY29sbmFtZXModWRhamUxMCkgPC0gYygKICAiS3JhamluYSIsCiAgIlBvcHVsw6FjaWEgMjAyNSIsCiAgIk1pZXJhIHBsb2Rub3N0aSIsCiAgIk1lZGnDoW4gdmVrdSIsCiAgIsSMaXN0w6EgbWlncsOhY2lhIgopCgpgYGAKCioqVGFibGUgMS4qKgpgYGB7cn0KdWRhamUxMApgYGAKCkhpZXJhcmNoaWNrw6EgemhsdWtvdsOhIGFuYWzDvXphIHByYWN1amUgcyBtaWVyYW1pIHZ6ZGlhbGVub3N0aSBtZWR6aSBwb3pvcm92YW5pYW1pLiBBYnkgYm9saSB0aWV0byB2emRpYWxlbm9zdGkgcG9yb3ZuYXRlxL5uw6ksIGplIHBvdHJlYm7DqSwgYWJ5IHbFoWV0a3kgcHJlbWVubsOpIGJvbGkgZGVmaW5vdmFuw6kgbmEgcm92bmFrZWrFoWvDoWxlLiBQb3XFvsOtdmFtZSBwcml0b20gdHp2LiB6LcWha8OhbG92YW5pZSwgcHJpxI1vbSB0cmFuc2Zvcm1vdmFuw6kgJHokIGhvZG5vdHkgKHNrw7NyZSkgdnlwb8SNw610YW1lIG5hc2xlZG92bmUKCiQkeiA9IFxmcmFje3gtXG11fXtcc2lnbWF9JCQKCmtkZSAkXG11JCBqZSBzdHJlZG7DoSBob2Rub3RhIGEgJFxzaWdtYSQgamUgxaF0YW5kYXJkbsOhIG9kY2jDvWxrYSBwb3pvcm92YW7DrSAkeCQuIFByZWRwb2tsYWTDoW1lIHByaXRvbSwgxb5lIHPDumJvciDDumRham92IHXFviBuZW9ic2FodWplIE5BIGhvZG5vdHksIGt0b3LDqSBib2xpIG/FoWV0cmVuw6kgdiBwcmVkY2jDoWR6YWrDumNpY2gga3Jva29jaC4KClRvdXRvIG9wZXLDoWNpb3UgesOtc2thbWUgxaFrw6Fsb3ZhbsOpIHBvem9yb3ZhbmlhLCBwcmnEjW9tIGljaCByb3psb8W+ZW5pZSBqZSB6bsOhem9ybmVuw6kgbmFzbGVkb3ZuZToKCmBgYHtyfQojIDEpIE5hxI3DrXRhbmllIGTDoXQgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQp1ZGFqZSA8LSByZWFkLmNzdigicG9wdWxhdGlvbl9kYXRhLmNzdiIsCiAgICAgICAgICAgICAgICAgIHNlcCA9ICIsIiwKICAgICAgICAgICAgICAgICAgaGVhZGVyID0gVFJVRSwKICAgICAgICAgICAgICAgICAgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQoKIyAyKSBWeWJlcmllbWUgMTAgZXVyw7Nwc2t5Y2gga3JhasOtbiwgcyBrdG9yw71taSBjaGNlbWUgcHJhY292YcWlIC0tLS0tLS0tLS0Ka3JhamlueTEwIDwtIGMoIkdlcm1hbnkiLAogICAgICAgICAgICAgICAiVW5pdGVkIEtpbmdkb20iLAogICAgICAgICAgICAgICAiRnJhbmNlIiwKICAgICAgICAgICAgICAgIkl0YWx5IiwKICAgICAgICAgICAgICAgIlNwYWluIiwKICAgICAgICAgICAgICAgIlVrcmFpbmUiLAogICAgICAgICAgICAgICAiUG9sYW5kIiwKICAgICAgICAgICAgICAgIlJvbWFuaWEiLAogICAgICAgICAgICAgICAiTmV0aGVybGFuZHMiLAogICAgICAgICAgICAgICAiQmVsZ2l1bSIpCgojIGZpbHRlciBuYSB0w71jaHRvIDEwIGtyYWrDrW4KdWRhamUxMCA8LSBzdWJzZXQodWRhamUsIENvdW50cnkuLm9yLmRlcGVuZGVuY3kuICVpbiUga3JhamlueTEwKQoKIyBwcmUgaXN0b3R1IHpvcmFkw61tZSByaWFka3kgdiByb3ZuYWtvbSBwb3JhZMOtIGFrbyB2byB2ZWt0b3JlIGtyYWppbnkxMAp1ZGFqZTEwIDwtIHVkYWplMTBbbWF0Y2goa3JhamlueTEwLCB1ZGFqZTEwJENvdW50cnkuLm9yLmRlcGVuZGVuY3kuKSwgXQoKIyAzKSBQcmlwcmF2w61tZSBkw6F0b3bDvSByw6FtZWMgbGVuIHMgxI3DrXNlbG7DvW1pIHByZW1lbm7DvW1pIC0tLS0tLS0tLS0tLS0tLS0tCiMgICAgKHBvcHVsw6FjaWEgMjAyNSwgbWllcmEgcGxvZG5vc3RpLCBtZWRpw6FuIHZla3UsIMSNaXN0w6EgbWlncsOhY2lhKQp1ZGFqZV9jb21wbGV0ZSA8LSB1ZGFqZTEwWywgYygiUG9wdWxhdGlvbi4yMDI1IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkZlcnQuLlJhdGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTWVkaWFuLkFnZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJNaWdyYW50cy4ubmV0LiIpXQoKIyBpc3RvdGE6IHByZXR5cHVqZW1lIHN0xLpwY2UgbmEgbnVtZXJpYyAoa2VieSBpY2ggUiBuYcSNw610YWwgYWtvIHRleHQpCnVkYWplX2NvbXBsZXRlW10gPC0gbGFwcGx5KHVkYWplX2NvbXBsZXRlLCBmdW5jdGlvbih4KSBhcy5udW1lcmljKHgpKQoKIyBwb21lbnVqZW1lIHJpYWRreSBwb2TEvmEga3JhasOtbgpyb3duYW1lcyh1ZGFqZV9jb21wbGV0ZSkgPC0gdWRhamUxMCRDb3VudHJ5Li5vci4uZGVwZW5kZW5jeS4KCiMgNCkgxaBrw6Fsb3ZhbmllIHByZW1lbm7DvWNoICh6LXNrw7NyZSkgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCnVkYWplX3NjYWxlZCA8LSBzY2FsZSh1ZGFqZV9jb21wbGV0ZSkKCiMgVsO9c3R1cHkgZG8gdGFidcS+a3kgKG5hanBydiBww7R2b2Ruw6kgZMOhdGEsIHBvdG9tIMWha8OhbG92YW7DqSkKdWRhamVfY29tcGxldGUgICAgICAjIG5lxaFrw6Fsb3ZhbsOpIGhvZG5vdHkKdWRhamVfc2NhbGVkICAgICAgICAjIHotc2vDs3JlCgpgYGAKCgoqKk9ici4gMS4qKgpgYGB7ciBib3hwbG90cywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZmlnLnNob3c9J2hvbGQnfQpudW1fdmFycyA8LSBhcy5kYXRhLmZyYW1lKHVkYWplX3NjYWxlZCkKbnVtX3Bsb3RzIDwtIG5jb2wobnVtX3ZhcnMpCgpwYXIobWZyb3cgPSBjKGNlaWxpbmcoc3FydChudW1fcGxvdHMpKSwgY2VpbGluZyhudW1fcGxvdHMgLyBjZWlsaW5nKHNxcnQobnVtX3Bsb3RzKSkpKSkKcGFyKG1hciA9IGMoNCwgNCwgMiwgMSkpCgpmb3IgKGNvbCBpbiBuYW1lcyhudW1fdmFycykpIHsKICBib3hwbG90KG51bV92YXJzW1tjb2xdXSwKICAgICAgICAgIG1haW4gPSBjb2wsCiAgICAgICAgICBjb2wgPSAibGlnaHRibHVlIiwKICAgICAgICAgIGhvcml6b250YWwgPSBUUlVFKQp9CgptdGV4dCgiQm94cGxvdHkgbnVtZXJpY2vDvWNoIHByZW1lbm7DvWNoICh2eWJyYW7DvWNoIDEwIGtyYWrDrW4pIiwgb3V0ZXIgPSBUUlVFLCBjZXggPSAxLjMsIGZvbnQgPSAyKQpgYGAKCgpUZW50b2tyw6F0IG9kxL5haGzDqSBob2Rub3R5IG5ldnlsw7rEjWltZSwgbmFrb8S+a28gZGVmaW51asO6IGtvbmtyw6l0bnUga3JhamludS4gCgoKClByaSB6aGx1a292ZWogYW5hbMO9emUgamUgZMO0bGXFvml0w6Ega29yZWxhxI1uw6EgbWF0aWNhIHByZW1lbm7DvWNoLiBWeXNva8OhIGtvcmVsw6FjaWEgenbDvWhvZMWIdWplIHByaSB6aGx1a292ZWogYW5hbMO9emUga29yZWxvdmFuw6kgcHJlbWVubsOpLiBQcmV0byBwcmkga29yZWzDoWNpaSBuYWQgMCw4IGFsZWJvIDAuOSB2eWzDusSNaW1lIGplZG51IHoga29yZWxvdmFuw71jaCBwcmVtZW5uw71jaC4gViAqKlRhYi4gMi4qKiBzYSB2xaFhayB0YWvDoXRvIHZ5c29rw6Ega29yZWzDoWNpYSBuZW5hY2jDoWR6YSwgcHJldG8gc2EgbmVtdXPDrW1lIMSPYWxlaiBzIHByb2Jsw6ltb20gemFvYmVyYcWlLiAKPiBWIHByw61wYWRlLCBhayBtw6FtZSB2w6TEjcWhw60gcG/EjWV0IHbDvXpuYW1uZSBrb3JlbG92YW7DvWNoIHByZW1lbm7DvWNoLCBzYSBvZHBvcsO6xI1hIGkgdHJhbnNmb3Jtw6FjaWEgcG9tb2NvdSBBbmFsw716eSBobGF2bsO9Y2gga29tcG9uZW50b3YgKFByaW5jaXBhbCBDb21wb25lbnQgQW5hbHlzaXMpIApQcmkgemhsdWtvdmVqIGFuYWzDvXplIGplIGTDtGxlxb5pdMOhIGtvcmVsYcSNbsOhIG1hdGljYSBwcmVtZW5uw71jaC4gVnlzb2vDoSBrb3JlbMOhY2lhIG1lZHppIHByZW1lbm7DvW1pIG3DtMW+ZSBzcMO0c29ib3ZhxaUsIMW+ZSBuaWVrdG9yw6kgeiBuaWNoIGJ1ZMO6IG1hxaUgcHJpIHR2b3JiZSB6aGx1a292IG5lcHJpbWVyYW5lIHZlxL5rw70gdnBseXYuIFByZXRvIHNhIHByaSBrb3JlbMOhY2nDoWNoIHZ5xaHFocOtY2ggYWtvIDAuOCDigJMgMC45IMSNYXN0byBvZHBvcsO6xI1hIHZ5bMO6xI1pxaUgamVkbnUgeiBkdm9qaWNlIHNpbG5lIGtvcmVsb3ZhbsO9Y2ggcHJlbWVubsO9Y2guIFYgbmHFoW9tIHByw61wYWRlIChwb3pyaSAqKlRhYi4gMioqKSB2xaFhayDFvmlhZG5hIHoga29yZWzDoWNpw60gbmVkb3NhaHVqZSBob2Rub3R1LCBrdG9yw6EgYnkgYm9sYSBwcm9ibGVtYXRpY2vDoToKCm5hanZ5xaHFoWlhIGtvcmVsw6FjaWEgamUgbWVkemkgcHJlbWVubsO9bWkgRmVydC4uUmF0ZSBhIE1pZ3JhbnRzLi5uZXQuIG5hIMO6cm92bmkg4oCTMC42NCwgb3N0YXRuw6kga29yZWzDoWNpZSBzYSBwb2h5YnVqw7ogbGVuIHYgaW50ZXJ2YWxlIHByaWJsacW+bmUg4oCTMC4zMCBhxb4gMC4zMiwgcHJlbWVubsOpIHRlZGEgbmllIHPDuiB2w71yYXpuZSBtdWx0aWtvbGluZcOhcm5lLiBUbyB6bmFtZW7DoSwgxb5lIHNhIG5lbXVzw61tZSB6YW9iZXJhxaUgb2RzdHJhxYhvdmFuw61tIHByZW1lbm7DvWNoIGFuaSB1dmHFvm92YcWlIG8gxI9hbMWhZWogdHJhbnNmb3Jtw6FjaWkgeiBkw7R2b2R1IHZ5c29rZWoga29yZWzDoWNpZS4gViBwcsOtcGFkZSwgxb5lIGJ5IHNtZSBtYWxpIHbDpMSNxaHDrSBwb8SNZXQgdmXEvm1pIGtvcmVsb3ZhbsO9Y2ggdWthem92YXRlxL5vdiwgYm9sbyBieSB2aG9kbsOpIHp2w6HFvmnFpSB0cmFuc2Zvcm3DoWNpdSBwb21vY291IEFuYWzDvXp5IGhsYXZuw71jaCBrb21wb25lbnRvdiAoUHJpbmNpcGFsIENvbXBvbmVudCBBbmFseXNpcykuIFYgbmHFoW9tIHByw61wYWRlIHRvIHbFoWFrIG5pZSBqZSBwb3RyZWJuw6kuCgoKKipUYWIuIDIqKgpgYGB7cn0KY29yX21hdCA8LSBjb3IodWRhamVfc2NhbGVkLCB1c2U9InBhaXJ3aXNlLmNvbXBsZXRlLm9icyIpCmNvcl9tYXQgPC0gcm91bmQoY29yX21hdCwyKQpwcmludChjb3JfbWF0KQpgYGAKS2HFvmRlaiBrcmFqaW5lIHpvZHBvdmVkw6EgamVkZW4gcmlhZG9rIHBvem9yb3ZhbsOtLiBWemRpYWxlbm9zxaUgbWVkemkga3JhamluYW1pICRpJCBhICRqJCBqZToKCiQkCmRee2lqfSA9IFxzcXJ0e1xzdW1fayAoeF5pX2sgLSB4XmpfayleMn0KJCQKa2RlICR4XmlfayQgamUgJGskdGEgcHJlbWVubsOhIHZzdHVwdWrDumNhIGRvIHbDvXBvxI10dSAoUG9wdWxhdGlvbi4yMDI1LCBGZXJ0Li5SYXRlLCBNZWRpYW4uQWdlIGEgTWlncmFudHMuLm5ldC4pIGtyYWppbnkgJGkkLiAgVGVudG8gdHlwIHZ6ZGlhbGVub3N0aSBuYXrDvXZhbWUgYWogRXVrbGlkb3Zza8OhIHZ6ZGlhbGVub3PFpS4gVnpkaWFsZW5vc3RpIG1lZHppIGplZG5vdGxpdsO9bWkga3JhamluYW1pIHNhIHPDumhybm5lIHZ5amFkcnVqw7ogYWogdiBtYXRpY2kgdnpkaWFsZW5vc3RpLCDEjW8gdiBuYcWhb20gcHLDrXBhZGUgamUgdXZlZGVuw6kgdiAqKlRhYi4zLioqLiBOYSB6w6FrbGFkZSB2w71zbGVka292IHogKipUYWIuIDMqKiBtw7TFvmVtZSB1dmllc8WlIG5hc2xlZG92bsOpOgoKTmFqdsOkxI3FoWlhIHZ6ZGlhbGVub3PFpSAodC4gai4gbmFqbWVuxaFpYSBwb2RvYm5vc8WlKSBib2xhIHppc3RlbsOhIG1lZHppIFVrcmFqaW5vdSBhIE5lbWVja29tICgzLjcwKSwgYWtvIGFqIG1lZHppIFVrcmFqaW5vdSBhIEZyYW5jw7p6c2tvbSAoMy42MikuIFRpZXRvIGtyYWppbnkgc2EgdsO9cmF6bmUgbMOtxaFpYSBuYWptw6QgdiBtaWdyYcSNbmVqIGJpbGFuY2lpLCB2ZWtvdmVqIMWhdHJ1a3TDunJlIGFqIHBsb2Rub3N0aS4gU2lsbsOpIHJvemRpZWx5IHBvem9ydWplbWUgYWogbWVkemkgUnVtdW5za29tIGEgRMOhbnNrb20gKDMuMTkpIGEgUnVtdW5za29tIGEgSG9sYW5kc2tvbSAoMy4zNiksIMSNbyBtw7TFvmUgc8O6dmlzaWXFpSBzIHZ5xaHFoW91IHBsb2Rub3PFpW91IGEgb2RsacWhbm91IG1pZ3JhxI1ub3UgZHluYW1pa291IFJ1bXVuc2thLiBOYWptZW7FoWl1IHZ6ZGlhbGVub3PFpSwgdGVkYSBuYWp2w6TEjcWhaXUgcG9kb2Jub3PFpSwgbmFjaMOhZHphbWUgbWVkemk6CkhvbGFuZHNrb20gYSBCZWxnaWNrb20gKDAuNDEpLCBGcmFuY8O6enNrb20gYSBCZWxnaWNrb20gKDEuMTMpLCBOZW1lY2tvbSBhIFZlxL5rb3UgQnJpdMOhbmlvdSAoMi42NSkKVGlldG8ga3JhamlueSB2eWthenVqw7ogcG9kb2Juw6kgaG9kbm90eSBtZWRpYW51IHZla3UgYSByZWxhdMOtdm5lIHZ5cm92bmFuw7ogbWlncmHEjW7DuiBiaWxhbmNpdS4KU3RyZWRuw6Egw7pyb3ZlxYggcG9kb2Jub3N0aSBqZSBuYXByw61rbGFkIG1lZHppIFBvxL5za29tIGEgxaBwYW5pZWxza29tICgxLjcxKSBhbGVibyBGcmFuY8O6enNrb20gYSDFoHBhbmllbHNrb20gKDIuOTQpLgpDZWxrb3ZvIHRlZGEgdmlkw61tZSwgxb5lIGV1csOzcHNrZSBrcmFqaW55IHZ5dHbDoXJhasO6IHBvZMS+YSBzdm9qaWNoIHVrYXpvdmF0ZcS+b3YgcHJpcm9kemVuw6kgc2t1cGlueSDigJMgbmFwci4gQmVsZ2lja2/igJNIb2xhbmRza28sIE5lbWVja2/igJNVSywgemF0aWHEviDEjW8ga3JhamlueSBha28gVWtyYWppbmEgxI1pIFJ1bXVuc2tvIHNhIG9kIHbDpMSNxaFpbnkgb3N0YXRuw71jaCB2w71yYXpuZWrFoWllIG9kbGnFoXVqw7ouCgoqKlRhYi4gMyoqCmBgYHtyfQojIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09CiMjIDMpIERpc3RhbmNlIG1hdHJpeAojIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09CgojIFBvbWVub3ZhbmllIHJpYWRrb3YgcG9kxL5hIDEwIHp2b2xlbsO9Y2gga3JhasOtbgpyb3duYW1lcyh1ZGFqZV9zY2FsZWQpIDwtIGMoIkdlcm1hbnkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIlVuaXRlZCBLaW5nZG9tIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJGcmFuY2UiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIkl0YWx5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTcGFpbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVWtyYWluZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUG9sYW5kIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJSb21hbmlhIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOZXRoZXJsYW5kcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiQmVsZ2l1bSIpCgojIFbDvXBvxI1ldCBldWtsaWRvdnNrZWogdnpkaWFsZW5vc3RpIGEgemFva3LDumhsZW5pZSBuYSAyIGRlc2F0aW5uw6kgbWllc3RhCmRpc3RfbWF0IDwtIHJvdW5kKGRpc3QodWRhamVfc2NhbGVkLCBtZXRob2QgPSAiZXVjbGlkZWFuIiksIDIpCgpkaXN0X21hdAoKYGBgCgoKIyMgUHJpbmPDrXAgaGllcmFyY2hpY2vDqWhvIHpobHVrb3ZhbmlhIChXYXJkb3ZhIG1ldMOzZGEpCgpaaGx1a292YW5pZSB2IHByw61wYWRlIFdhcmRvdmVqIG1ldMOzZHkgcHJlYmllaGEgemRvbGEgc21lcm9tIG5haG9yLCB0LmouIHphxI3DrW5hbWUgcyBqZWRub8SNbGVubsO9bWkga2xhc3RyYW1pLCBrdG9yw6kgcG9zdHVwbmUgemx1xI11amVtZS4gVMOhdG8gbWV0w7NkYSBwYXRyw60gdGVkYSBtZWR6aSBhZ2xvbWVyYXTDrXZuZSBoaWVyYXJjaGlja8OpIG1ldMOzZHkuIE1pbmltYWxpenVqZSBuw6FyYXN0IHZuw7p0b3JuZWogdmFyaWFiaWxpdHkgcHJpIHNwb2plbsOtIGR2b2NoIGtsYXN0cm92LCBwcmnEjW9tIHZ5dcW+w612YSBuYXNsZWRvdm7DqSB2w71wb8SNdHk6CgpXYXJkb3bDoSBtZXTDs2RhIG1pbmltYWxpenVqZSBzdW11IMWhdHZvcmNvdiBjaMO9YiAoRXJyb3Igc3VtIG9mIFNxdWFyZXMgLSBFU1MpCgokJEVTUyhDKSA9IFxzdW1fe2kgXGluIEN9IFxsVmVydCB4X2kgLSBcYmFye3h9X0MgXHJWZXJ0XjIkJAprZGUgJEMkIGplIHp2YcW+b3ZhbsO9IGtsYXN0ZXIgKHpobHVrKS4gViBrYcW+ZG9tIGtyb2t1IHpsdcSNb3ZhbmlhIGR2b2NoIGtsYXN0ZXJvdiwgV2FyZG92YSBtZXTDs2RhIGjEvmFkw6EgbWluaW3DoWxueSBwcsOtcmFzdG9rIHN1bXkgxaF0dm9yY292IGNow71iICgkXERlbHRhIEVTUyQpLCBwcmnEjW9tCgokJFxEZWx0YSBFU1MgPSBFU1MoQSBcY3VwIEIpIC0gRVNTKEEpIC0gRVNTKEIpJCQKRHZvamljYSB6aGx1a292LCBrdG9yw6kgdGVqdG8gcG9kbWllbmtlIG8gbWluaW1hbGl6w6FjaWkgdnlob3Z1amUsIGplIG7DoXNsZWRuZSB6bMO6xI1lbsOhIGEgcHJlY2jDoWR6YSBzYSBrIMSPYWzFoWllbXUga2tyb2t1LiBUbyBzcHJhdmlkbGEgdmVkaWUgayB2eXR2w6FyYW5pdSBob21vZ8Opbm55Y2ggemhsdWtvdiwgcHJpxI1vbSBuZWRvY2jDoWR6YSBrIG9kdHJow6F2YW5pdSBvZMS+YWhsw71jaCBob2Ruw7R0IHRhaywgYWtvIHByaSBpbsO9Y2ggemhsdWtvdmFjw61jaCBtZXTDs2RhY2guCgoKKipPYnIuIDIuKiogSGllcmFyY2hpY2vDqSB6aGx1a292YW5pZSAtIGRlbmRvZ3JhbS4gxIxlcnZlbsOhIMSNaWFyYSB1csSNdWplIHJleiBkZWZpbnVqw7pjaSB0cmkga2xhc3RyZS4KYGBge3J9CiMjID09PT09PT09PT09PT09PT09PT09PT09PT09PT0KIyMgNCkgSGllcmFyY2hpY2FsIGtsYXN0ZXJpbmcKIyMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PQoKaGMgPC0gaGNsdXN0KGRpc3RfbWF0LCBtZXRob2QgPSAid2FyZC5EMiIpCgpwbG90KGhjLCBsYWJlbHMgPSByb3duYW1lcyh1ZGFqZV9zY2FsZWQpLAogICAgIG1haW4gPSAiSGllcmFyY2hpY2FsIGtsYXN0ZXJpbmcgb2YgY291bnRyaWVzIChXYXJkLkQyKSIsCiAgICAgeGxhYiA9ICIiLCBzdWIgPSAiIikKCmsgPC0gMwpoX2N1dCA8LSBoYyRoZWlnaHRbbGVuZ3RoKGhjJGhlaWdodCkgLSAoayAtIDEpXQphYmxpbmUoaCA9IGhfY3V0LCBjb2wgPSAicmVkIiwgbHdkID0gMiwgbHR5ID0gMikKCmtsYXN0ZXJfbWVtYmVyc2hpcCA8LSBjdXRyZWUoaGMsIGsgPSBrKQoKdWRhamVfa2xhc3RlcnMgPC0gZGF0YS5mcmFtZSgKICBDb3VudHJ5ID0gcm93bmFtZXModWRhamVfY29tcGxldGUpLAogIHVkYWplX2NvbXBsZXRlLAogIGtsYXN0ZXIgPSBmYWN0b3Ioa2xhc3Rlcl9tZW1iZXJzaGlwKQopCmBgYAoKKipUYWIuNC4qKiAgUHLDrXNsdcWhbm9zxaUga3JhasOtbiBkbyBrbGFzdHJvdi4KYGBge3J9CiMjIFRhYi4gNCDigJMgUHLDrXNsdcWhbm9zxaUga3JhasOtbiBkbyBrbGFzdHJvdgoKIyBWeXR2b3LDrW1lIGTDoXRvdsO9IHLDoW1lYyBzIGtyYWppbmFtaSBhIGljaCBrbGFzdHJvbQpkYXRhX3ByYWMgPC0gZGF0YS5mcmFtZSgKICBDb3VudHJ5ID0gcm93bmFtZXModWRhamVfc2NhbGVkKSwKICBrbGFzdGVyID0gdWRhamVfa2xhc3RlcnMKKQoKIyBab2JyYXrDrW1lIHbDvXNsZWRuw7ogdGFidcS+a3UKZGF0YV9wcmFjCgpgYGAKCmBgYHtyfQojIFbDvXNsZWRuw6EgdGFidcS+a2Ega3JhasOtbiBhIGljaCBrbGFzdHJvdgpkYXRhX3ByYWMgPC0gZGF0YS5mcmFtZSgKICBDb3VudHJ5ID0gdWRhamVfa2xhc3RlcnMkQ291bnRyeSwKICBLbGFzdG9yID0gdWRhamVfa2xhc3RlcnMka2xhc3RlcgopCgpkYXRhX3ByYWMKCmBgYApOYSB6w6FrbGFkZSBoaWVyYXJjaGlja2VqIHpobHVrb3ZlaiBhbmFsw716eSAoV2FyZG92YSBtZXTDs2RhKSBzbWUgYW5hbHl6b3ZhbGkgcG9kb2Jub3PFpSBkZXNpYXRpY2ggZXVyw7Nwc2t5Y2gga3JhasOtbiBwb2TEvmEgdnlicmFuw71jaCB1a2F6b3ZhdGXEvm92IChQb3B1bGF0aW9uIDIwMjUsIEZlcnRpbGl0eSBSYXRlLCBNZWRpYW4gQWdlLCBOZXQgTWlncmF0aW9uKS4gVsO9c2xlZGtvbSBwcm9jZXN1IGJvbG8gcm96ZGVsZW5pZSBrcmFqw61uIGRvIHRyb2NoIGtsYXN0cm92LCBwcmnEjW9tIGtyYWppbnkgdiByw6FtY2kgamVkbsOpaG8ga2xhc3RydSBtYWrDuiBwb2RvYm5lasWhaWUgZGVtb2dyYWZpY2vDqSB1a2F6b3ZhdGVsZSBha28ga3JhamlueSB2IGluw71jaCBrbGFzdHJvY2guCgpaIHRhYnXEvmt5IHZpZMOtbWUgbmFzbGVkb3Zuw6kgemFyYWRlbmllOgoKS2xhc3RyZSB0eXB1IDE6IHR2b3LDrSBobyBOZW1lY2tvLCBUYWxpYW5za28gYSDFoHBhbmllbHNrby4gVGlldG8ga3JhamlueSBtYWrDuiBwb2RvYm7DuiBwb3B1bGHEjW7DuiB2ZcS+a29zxaUgYSBzcG9sb8SNbsOpIGRlbW9ncmFmaWNrw6kgxI1ydHksIG5hcHLDrWtsYWQgbsOtemt1IG1pZXJ1IHBsb2Rub3N0aSBhIHZ5xaHFocOtIG1lZGnDoW5vdsO9IHZlaywgxI1vIHPDuiB0eXBpY2vDqSB6bmFreSB6w6FwYWRvZXVyw7Nwc2t5Y2gga3JhasOtbiBzIGRsaG9kb2LDvW0gc3Rhcm51dMOtbSBwb3B1bMOhY2llLgoKS2xhc3RyZSB0eXB1IDI6IHNlbSBzcGFkYWrDuiBTcG9qZW7DqSBrcsOhxL5vdnN0dm8sIEZyYW5jw7p6c2tvLCBQb8S+c2tvLCBIb2xhbmRza28sIEJlbGdpY2tvIGEgVWtyYWppbmEuIElkZSBvIG5hanJvem1hbml0ZWrFocOtIGtsYXN0ZXIsIGt0b3LDvSB6YWjFlcWIYSB2ZcS+a8OpIGFqIHN0cmVkbmUgdmXEvmvDqSBrcmFqaW55IHMgbWllcm5lIHZ5xaHFoW91IHBsb2Rub3PFpW91LCBvZGxpxaFuw71tIG1pZ3JhxI1uw71tIHByb2ZpbG9tIGEgcsO0em5vcm9kw71tIHZla292w71tIHpsb8W+ZW7DrW0gcG9wdWzDoWNpZS4KCktsYXN0cmUgdHlwdSAzOiBwcmVkc3RhdnVqZSBobyBsZW4gUnVtdW5za28uIFphcmFkZW5pZSBSdW11bnNrYSBkbyBzYW1vc3RhdG7DqWhvIGtsYXN0cnUgbmF6bmHEjXVqZSwgxb5lIHNhIGplaG8gZGVtb2dyYWZpY2vDqSBjaGFyYWt0ZXJpc3Rpa3kgdsO9em5hbW5lIG9kbGnFoXVqw7ogb2Qgb3N0YXRuw71jaCBhbmFseXpvdmFuw71jaCBrcmFqw61uIOKAlCBuYXByw61rbGFkIG5pxb7FoW91IHBvcHVsYcSNbm91IHZlxL5rb3PFpW91LCDFoXBlY2lmaWNrb3UgbWlncsOhY2lvdSDEjWkgdsO9cmF6bmVqxaHDrW1pIHJvemRpZWxtaSB2IHBsb2Rub3N0aSBhbGVibyB2ZWtvdmVqIMWhdHJ1a3TDunJlLgoKQ2Vsa292byBtw7TFvmVtZSBrb27FoXRhdG92YcWlLCDFvmUga2xhc3Ryb3bDoSBhbmFsw716YSBvZGhhbGlsYSBwcmlyb2R6ZW7DqSBza3VwaW55IGtyYWrDrW4gc28gc3BvbG/EjW7DvW1pIGRlbW9ncmFmaWNrw71taSB6bmFrbWkuIE5hanZpYWMgaG9tb2fDqW5ueSBqZSBrbGFzdGVyIMSNLiAxLCB6YXRpYcS+IMSNbyBrbGFzdGVyIMSNLiAyIHphaMWVxYhhIGtyYWppbnkgcyB2w6TEjcWhb3Ugdm7DunRvcm5vdSB2YXJpYWJpbGl0b3UuIFNhbW9zdGF0bsOpIHBvc3RhdmVuaWUgUnVtdW5za2EgdiBrbGFzdGVyaSDEjS4gMyBwb3VrYXp1amUgbmEgamVobyB2w71yYXpuw7ogb2RsacWhbm9zxaUgb2Qgb3N0YXRuw71jaCBldXLDs3Bza3ljaCBrcmFqw61uIHYgc2xlZG92YW7DvWNoIHByZW1lbm7DvWNoLgoKIyMgRGVza3JpcHTDrXZuZSDFoXRhdGlzdGlreSB2w71zbGVka292CgpQcmkgYW5hbMO9emUgcm96a2xhZHUgdmFyaWFuY2llIHNsZWR1amVtZSwgYWvDoSDEjWFzxaUgdmFyaWFiaWxpdHkgamVkbm90bGl2w71jaCBwcmVtZW5uw71jaCBqZSB2eXN2ZXRsZW7DoSBzYW1vdG7DvW0ga2xhc3Ryb3bDvW0gcmllxaFlbsOtbS4gS8S+w7rEjW92w71tIHVrYXpvdmF0ZcS+b20gamUgc3TEunBlYyBQcm9wX0JldHdlZW4sIGt0b3LDvSB1ZMOhdmEgcG9kaWVsIHZhcmlhYmlsaXR5IHZ5c3ZldGxlbmVqIHJvemRpZWxtaSBtZWR6aSBrbGFzdHJhbWkgKEJTUyAvIFRTUykuIMSMw61tIGplIHTDoXRvIGhvZG5vdGEgdnnFocWhaWEsIHTDvW0gbGVwxaFpZSBrbGFzdHJvdmFuaWUgemFjaHl0w6F2YSByb3pkaWVseSBtZWR6aSBrcmFqaW5hbWkgcG9kxL5hIGRhbmVqIHByZW1lbm5lai4KClogKipUYWIuIDUuKiogdnlwbMO9dmEgbmFzbGVkb3Zuw6k6CgpQb3B1bGF0aW9uLjIwMjUg4oCTIFByb3BfQmV0d2VlbiDiiYggMC4yNjgKUG9kaWVsIHZhcmlhYmlsaXR5IHZ5c3ZldGxlbmVqIGtsYXN0cmFtaSBqZSBwcmlibGnFvm5lIDI3ICUsIMSNbyB6bmFtZW7DoSwgxb5lIHBvcHVsw6FjaWEgaWJhIG1pZXJuZSBwcmlzcGlldmEgayBvZGxpxaFvdmFuaXUga2xhc3Ryb3YuIEtyYWppbnkgc2EgdGVkYSB6IGjEvmFkaXNrYSB2ZcS+a29zdGkgcG9wdWzDoWNpZSB2IHJva3UgMjAyNSBuZW9kbGnFoXVqw7ogbmF0b8S+a28sIGFieSB0dm9yaWxpIGphc25lIG9kZGVsZW7DqSBza3VwaW55LgoKRmVydC4uUmF0ZSDigJMgUHJvcF9CZXR3ZWVuIOKJiCAwLjYyMQpNaWVyYSBwbG9kbm9zdGkgdnlzdmV0xL51amUgYcW+IDYyICUgdmFyaWFiaWxpdHkgbWVkemkga2xhc3RyYW1pLCDEjW8gamUgcG9tZXJuZSB2eXNva8OhIGhvZG5vdGEuIFRvIHpuYW1lbsOhLCDFvmUgZmVydGlsaXRhIGplIHbDvXpuYW1uw71tIGZha3Rvcm9tLCBwb2TEvmEga3RvcsOpaG8gc2Ega3JhamlueSBza3V0b8SNbmUgb2RsacWhdWrDui4gS2xhc3RyeSB0ZWRhIHphY2h5dMOhdmFqw7ogcm96ZGllbHkgdiBkZW1vZ3JhZmlja2VqIGR5bmFtaWtlIHZlxL5taSBkb2JyZS4KCk1lZGlhbi5BZ2Ug4oCTIFByb3BfQmV0d2VlbiDiiYggMC44MjEKQcW+IDgyICUgdmFyaWFiaWxpdHkgdiBtZWRpw6Fub3ZvbSB2ZWt1IGplIHZ5c3ZldGxlbsO9Y2gga2xhc3RyYW1pLiBJZGUgbyBuYWp2ecWhxaFpdSBob2Rub3R1IHpvIHbFoWV0a8O9Y2ggc2xlZG92YW7DvWNoIHByZW1lbm7DvWNoLiBabmFtZW7DoSB0bywgxb5lIG1lZGnDoW5vdsO9IHZlayBwb3B1bMOhY2llIGplIGRvbWluYW50bsO9bSB1a2F6b3ZhdGXEvm9tLCBrdG9yw70gbmFqbGVwxaFpZSBvZGxpxaF1amUgdnl0dm9yZW7DqSBza3VwaW55IGtyYWrDrW4uIEtyYWppbnkgc2EgdGVkYSB2w71yYXpuZSBsw63FoWlhIHYgdG9tLCDEjWkgbWFqw7ogbWxhZMWhaXUgYWxlYm8gc3RhcsWhaXUgcG9wdWzDoWNpdS4KCk1pZ3JhbnRzLi5uZXQg4oCTIG5lYm9sbyBtb8W+bsOpIHZ5aG9kbm90acWlIChOQSkKUHJlIHTDunRvIHByZW1lbm7DuiBuZWJvbCB2w71wb8SNZXQgbW/Fvm7DvSwgcHJhdmRlcG9kb2JuZSBrdsO0bGkgY2jDvWJhasO6Y2ltIGhvZG5vdMOhbSAoTkEpLiBQcmV0byBuZXZ5c3R1cHVqZSB2IHJvemtsYWRlIHZhcmlhbmNpZSBhbmkgdiBwb3N1ZHpvdmFuw60gdmhvZG5vc3RpIGtsYXN0cm92YW5pYS4KCgoqKlRhYi4gNS4qKiBWeXN2ZXRsZW5pZSB2bsO6dHJva2xhc3Ryb3ZlaiB2YXJpYWJpbGl0eSB6IGjEvmFkaXNrYSBqZWRub3RsaXbDvWNoIHByZW1lbm7DvWNoCgpgYGB7cn0KIyMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PQojIyA1KSBWYXJpYWJpbGl0eSBtZWFzdXJlcwojIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09Cgpzc3EgPC0gZnVuY3Rpb24oeCwgbSkgc3VtKCh4IC0gbSleMikKCnZhcl9uYW1lcyA8LSBjb2xuYW1lcyh1ZGFqZV9zY2FsZWQpCgpUU1MgPC0gc2FwcGx5KHZhcl9uYW1lcywgZnVuY3Rpb24odikgc3NxKHVkYWplX3NjYWxlZFssIHZdLCBtZWFuKHVkYWplX3NjYWxlZFssIHZdKSkpCgpXU1MgPC0gc2FwcGx5KHZhcl9uYW1lcywgZnVuY3Rpb24odikgewogIHggPC0gdWRhamVfc2NhbGVkWywgdl0KICB0YXBwbHkoeCwga2xhc3Rlcl9tZW1iZXJzaGlwLCBmdW5jdGlvbih6KSBzc3EoeiwgbWVhbih6KSkpIHw+IHN1bSgpCn0pCgpCU1MgPC0gVFNTIC0gV1NTCgpzc190YWJsZSA8LSBkYXRhLmZyYW1lKAogIFZhcmlhYmxlID0gdmFyX25hbWVzLAogIFRTUyA9IFRTUywKICBXU1MgPSBXU1MsCiAgQlNTID0gQlNTLAogIFByb3BfQmV0d2VlbiA9IEJTUyAvIFRTUwopCgpzc190YWJsZQpgYGAKCmBgYHtyfQojIFByaWTDoW1lIGt1IGRhdGFzZXR1IHByaXJhZGVuw6kga2xhc3RyeQp1ZGFqZTEwIDwtIGRhdGEuZnJhbWUoCiAgQ291bnRyeSAgICAgICAgICA9IHVkYWplMTAkQ291bnRyeS4ub3IuZGVwZW5kZW5jeS4sCiAgUG9wdWxhdGlvbi4yMDI1ICA9IHVkYWplMTAkUG9wdWxhdGlvbi4yMDI1LAogIEZlcnQuLlJhdGUgICAgICAgPSB1ZGFqZTEwJEZlcnQuLlJhdGUsCiAgTWVkaWFuLkFnZSAgICAgICA9IHVkYWplMTAkTWVkaWFuLkFnZSwKICBNaWdyYW50cy4ubmV0LiAgID0gdWRhamUxMCRNaWdyYW50cy4ubmV0LiwKICBrbGFzdGVyICAgICAgICAgID0gdWRhamVfa2xhc3RlcnMka2xhc3RlcgopCgojIFpvYnJhemVuaWUgdsO9c2xlZG7DqWhvIGRhdGFzZXR1CnVkYWplMTAKCmBgYAoKKipUYWIuIDYuKiogQ2VudHJvaWR5IC0gcHJpZW1lcm7DqSBob2Rub3R5IHNsZWRvdmFuw71jaCBwcmVtZW5uw71jaApgYGB7cn0KbGlicmFyeShkcGx5cikKCmRlc2NyaXB0aXZlcyA8LSB1ZGFqZTEwICU+JQogIGdyb3VwX2J5KGtsYXN0ZXIpICU+JQogIHN1bW1hcmlzZSgKICAgIGFjcm9zcygKICAgICAgLmNvbHMgPSB3aGVyZShpcy5udW1lcmljKSwKICAgICAgLmZucyA9IGxpc3QoCiAgICAgICAgbWVhbiA9IH5tZWFuKC54LCBuYS5ybSA9IFRSVUUpCiAgICAgICksCiAgICAgIC5uYW1lcyA9ICJ7LmNvbH1fey5mbn0iCiAgICApCiAgKQpkZXNjcmlwdGl2ZXMKCmBgYAoKTmEgesOhdmVyIHNtZSBwb3Jvdm5hbGkgcHJpZW1lcm7DqSBjaGFyYWt0ZXJpc3Rpa3kgdHJvY2gga2xhc3Ryb3YgdnlicmFuw71jaCBldXLDs3Bza3ljaCBrcmFqw61uLiAgCgoqKktsYXN0ZXIgMSoqIChOZW1lY2tvLCBUYWxpYW5za28sIMWgcGFuaWVsc2tvKSBtw6EgKipuYWp2w6TEjcWhaXUgcHJpZW1lcm7DuiBwb3B1bMOhY2l1Kiog4oCTIHByaWJsacW+bmUgKio2Myw3IG1pbGnDs25hIG9ieXZhdGXEvm92KiosICoqc3RyZWRuw7ogbWllcnUgcGxvZG5vc3RpKiogb2tvbG8gKioxLDMwIGRpZcWlYcWlYSBuYSDFvmVudSoqIGEgesOhcm92ZcWIICoqbmFqdnnFocWhw60gbWVkacOhbm92w70gdmVrKiogKCoq4omIIDQ2LDUgcm9rYSoqKS4gVGVudG8ga2xhc3RlciB0ZWRhIHJlcHJlemVudHVqZSB2ZcS+a8OpIGEgZGVtb2dyYWZpY2t5IOKAnnN0YXJuw7pjZeKAnCBrcmFqaW55IHNvIHNrw7RyIG5pxb7FoW91LCBhbGUgbmllIMO6cGxuZSBrcml0aWNreSBuw616a291IHBsb2Rub3PFpW91LiAgCgoqKktsYXN0ZXIgMioqIChTcG9qZW7DqSBrcsOhxL5vdnN0dm8sIEZyYW5jw7p6c2tvLCBQb8S+c2tvLCBSdW11bnNrbywgSG9sYW5kc2tvLCBCZWxnaWNrbykgbcOhICoqbmnFvsWhaXUgcHJpZW1lcm7DuiBwb3B1bMOhY2l1Kiog4oCTIGFzaSAqKjM3LDIgbWlsacOzbmEgb2J5dmF0ZcS+b3YqKiwgbm8gesOhcm92ZcWIICoqbmFqdnnFocWhaXUgcHJpZW1lcm7DuiBtaWVydSBwbG9kbm9zdGkqKiAoKiriiYggMSw1MSoqKSBhICoqbWxhZMWhaXUgdmVrb3bDuiDFoXRydWt0w7pydSoqIHMgbWVkacOhbm92w71tIHZla29tIHByaWJsacW+bmUgKio0MSw5IHJva2EqKi4gVGVudG8ga2xhc3RlciB6ZHJ1xb51amUgc3RyZWRuZSB2ZcS+a8OpIGtyYWppbnksIGtkZSBqZSBwbG9kbm9zxaUgcmVsYXTDrXZuZSBuYWp2ecWhxaFpYSBhIHBvcHVsw6FjaWEgamUgdiBwcmllbWVyZSBtbGFkxaFpYSBuZcW+IHYga2x1c3RyaSAxLiAgCgoqKktsYXN0ZXIgMyoqIGplIHR2b3JlbsO9IGplZGlub3Uga3Jhamlub3Ug4oCTICoqVWtyYWppbm91KiouIEplaiBwcmllbWVybsOhIChhIHrDoXJvdmXFiCBza3V0b8SNbsOhKSBwb3B1bMOhY2lhIGplIHByaWJsacW+bmUgKiozOCw5OCBtaWxpw7NuYSBvYnl2YXRlxL5vdioqLCBwcmnEjW9tIG3DoSAqKm5ham5pxb7FoWl1IG1pZXJ1IHBsb2Rub3N0aSoqICgqKuKJiCAxLDAwKiopIGEgbWVkacOhbm92w70gdmVrIG9rb2xvICoqNDEsOCByb2thKiouIFRlbnRvIGtsYXN0ZXIgcHJlZHN0YXZ1amUga3JhamludSBzIHZlxL5taSBuw616a291IHBsb2Rub3PFpW91LCBwcmkgdmVrb3ZlaiDFoXRydWt0w7pyZSBwb2RvYm5laiBrbGFzdHJ1IDIuICAKClogcG9yb3ZuYW5pYSBrbGFzdHJvdiB2aWRubywgxb5lIG5hanZ5xaHFocOtIHByaWVtZXJuw70gcG/EjWV0IG9ieXZhdGXEvm92IHNhIHNww6FqYSBzbyBzdGFyxaFvdSBwb3B1bMOhY2lvdSAoa2xhc3RlciAxKSwgemF0aWHEviDEjW8gbmFqdnnFocWhaWEgcGxvZG5vc8WlIHNhIHZ5c2t5dHVqZSB2IGtyYWppbsOhY2ggc28gc2vDtHIgbWxhZMWhb3UgcG9wdWzDoWNpb3UgKGtsYXN0ZXIgMikuIFVrcmFqaW5hIHR2b3LDrSBzYW1vc3RhdG7DvSBrbGFzdGVyIGt2w7RsaSBrb21iaW7DoWNpaSBwcmllbWVybmVqIHZlxL5rb3N0aSBwb3B1bMOhY2llIGEgZXh0csOpbW5lIG7DrXprZWogbWllcnkgcGxvZG5vc3RpLgogCgojIyBaw6F2ZXIKUHJlZGxvxb5lbsOhIGFuYWzDvXphIHNhIHphbWVyaWF2YSBuYSBkZW1vZ3JhZmlja8OpIGNoYXJha3RlcmlzdGlreSB2eWJyYW7DvWNoIGV1csOzcHNreWNoIGtyYWrDrW4gbmEgesOha2xhZGUgaWNoIHByZWRwb2tsYWRhbmVqIHBvcHVsw6FjaWUgdiByb2t1IDIwMjUsIG1pZXJ5IHBsb2Rub3N0aSBhIG1lZGnDoW51IHZla3Ugb2J5dmF0ZcS+c3R2YS4gTmEgesOha2xhZGUgdMO9Y2h0byBwcmVtZW5uw71jaCBib2xpIGtyYWppbnkgcm96ZGVsZW7DqSBkbyB0cm9jaCBrbGFzdHJvdiwgcHJpxI1vbSBqZWRub3RsaXbDqSBrbGFzdHJ5IG9kcsOhxb5hasO6IHNwb2xvxI1uw6kgZGVtb2dyYWZpY2vDqSDEjXJ0eSB0w71jaHRvIMWhdMOhdG92LgoKVsO9c2xlZG7DqSBrbGFzdHJ5IHByZWRzdGF2dWrDuiB0cmkgb2RsacWhbsOpIHNrdXBpbnkga3JhasOtbi4gUHJ2w70ga2xhc3RlciB0dm9yaWEgxaF0w6F0eSBzIG5hanZ5xaHFoW91IHByZWRwb2tsYWRhbm91IHBvcHVsw6FjaW91IGEgesOhcm92ZcWIIHZ5xaHFocOtbSBtZWRpw6Fub3bDvW0gdmVrb20gb2J5dmF0ZcS+c3R2YSwgxI1vIG5hem5hxI11amUgc3Rhcm7DumN1IHBvcHVsw6FjaXUgdmXEvmvDvWNoIGtyYWrDrW4uIERydWjDvSBrbGFzdGVyIHpkcnXFvnVqZSBrcmFqaW55IHMgcmVsYXTDrXZuZSB2ecWhxaFvdSBtaWVyb3UgcGxvZG5vc3RpIGEgc3RyZWRuw71taSBob2Rub3RhbWkgcG9wdWzDoWNpZSwgxI1vIHBvdWthenVqZSBuYSBkeW5hbWlja2VqxaHDrSBwb3B1bGHEjW7DvSB2w712b2ouIFRyZXTDrSBrbGFzdGVyIG9ic2FodWplIGtyYWppbnkgcyBuYWpuacW+xaFvdSBtaWVyb3UgcGxvZG5vc3RpIGEgesOhcm92ZcWIIHN0cmVkbm91IGHFviBuacW+xaFvdSB2ZcS+a29zxaVvdSBwb3B1bMOhY2llLgoKVGFrw6F0byBrbGFzaWZpa8OhY2lhIHVtb8W+xYh1amUgcG9jaG9wacWlIHZ6xaVhaHkgbWVkemkgZGVtb2dyYWZpY2vDvW1pIHVrYXpvdmF0ZcS+bWkgYSBwb3VrYXp1amUgbmEgcG9kb2Jub3N0aSB2IHBvcHVsYcSNbm9tIHbDvXZvamkgbmFwcmllxI0gRXVyw7Nwb3UuIEFuYWzDvXphIG3DtMW+ZSBzbMO6xb5pxaUgYWtvIHBvZGtsYWQgcHJlIHR2b3JidSBwb3B1bGHEjW7DvWNoIMSNaSBzb2Npw6FsbnljaCBwb2xpdMOtaywgcHLDrXBhZG5lIHByZSDEj2FsxaFpZSBwb3Jvdm7DoXZhY2llIMWhdMO6ZGllIG1lZHppIGV1csOzcHNreW1pIGtyYWppbmFtaS4=