library(knitr)
library(kableExtra)

Úvod

Zhluková (klastrová) analýza je kľúčovou metódou 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 alebo v sociálnej vede. 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é.

V tejto práci predstavíme zhlukovú analýzu na účely analýzy a profilovania vybraných krajín strednej, východnej a severnej Európy. Naším cieľom je identifikovať skupiny krajín, ktoré sú si podobné z hľadiska faktorov ovplyvňujúcich kvalitu života a vnímané šťastie. Využijeme dáta z databázy World Happiness Report za rok 2015 .

Pre zhlukovú analýzu sme vybrali päť kľúčových premenných, ktoré reprezentujú rôzne dimenzie životnej úrovne:

Na zistenie podobnosti krajín sme použili Euklidovskú vzdialenosť a na samotné zhlukovanie Hierarchické zhlukovanie s Wardovou metódou.

V Tab. 1. uvádzame celú nami použitú databázu obsahujúcu vybrané krajiny pre rok 2015.

udaje <- read.csv("World Happiness Report 2005-2021.csv", stringsAsFactors = FALSE)

# Výber prierezových dát pre rok 2015
udaje2015_prierez <- subset(udaje, Year == 2015)

# Výber vybraných európskych krajín
udaje2015_prierez <- subset(udaje2015_prierez,
  Country.name == "Poland" | Country.name == "Hungary" | Country.name == "Latvia" |
  Country.name == "Lithuania" | Country.name == "Croatia" | Country.name == "Slovenia" |
  Country.name == "Austria" | Country.name == "Serbia" | Country.name == "Montenegro" |
  Country.name == "Ukraine" | Country.name == "Bulgaria" | Country.name == "Romania" |
  Country.name == "Moldova" | Country.name == "Finland" | Country.name == "Sweden" |
  Country.name == "Denmark" | Country.name == "Estonia"
)

udaje2015_clusters <- udaje2015_prierez[, c(
  "Country.name", 
  "Log.GDP.per.capita",
  "Healthy.life.expectancy.at.birth", 
  "Social.support", 
  "Freedom.to.make.life.choices", 
  "Perceptions.of.corruption"
)]

rownames(udaje2015_clusters) <- udaje2015_clusters$Country.name
udaje2015_clusters$Country.name <- NULL

udaje2015_clusters <- na.omit(udaje2015_clusters)

summary(udaje2015_clusters)
 Log.GDP.per.capita Healthy.life.expectancy.at.birth Social.support  
 Min.   : 9.246     Min.   :62.90                    Min.   :0.7396  
 1st Qu.: 9.903     1st Qu.:65.90                    1st Qu.:0.8399  
 Median :10.223     Median :66.60                    Median :0.9012  
 Mean   :10.188     Mean   :67.46                    Mean   :0.8772  
 3rd Qu.:10.428     3rd Qu.:70.00                    3rd Qu.:0.9281  
 Max.   :10.876     Max.   :71.40                    Max.   :0.9597  
 Freedom.to.make.life.choices Perceptions.of.corruption
 Min.   :0.4306               Min.   :0.1910           
 1st Qu.:0.5952               1st Qu.:0.5687           
 Median :0.6935               Median :0.8485           
 Mean   :0.7263               Mean   :0.7296           
 3rd Qu.:0.8960               3rd Qu.:0.9242           
 Max.   :0.9414               Max.   :0.9617           

Základné štatistické miery pre vybrané premenné za rok 2015 odhaľujú značnú heterogenitu medzi sledovanými krajinami. Premenná Log.GDP.per.capita ukazuje najväčšiu ekonomickú rôznorodosť, čo je kľúčový predpoklad pre efektívne rozlíšenie zhlukov.

Taktiež v premenných Healthy.life.expectancy.at.birth a Perceptions.of.corruption pozorujeme významný rozptyl medzi minimálnymi a maximálnymi hodnotami, čo naznačuje existenciu dvoch výrazne odlišných skupín krajín (napr. Sever vs. Východ).

Naopak, faktor Social.support vykazuje v celom súbore pomerne vysoké hodnoty a nízky rozptyl, čo naznačuje, že táto premenná bude menej dôležitá pre primárnu segmentáciu krajín do zhlukov.

Na základe týchto zistení očakávame, že hlavné rozdiely medzi vytvorenými zhlukmi budú determinované predovšetkým ekonomickou úrovňou, zdravotným stavom a vnímaním inštitucionálnej kvality.

Table 1.

udaje2015_clusters

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:

udaje_complete <- na.omit(udaje2015_clusters)

udaje_scaled <- scale(udaje_complete)

head(udaje_scaled)
         Log.GDP.per.capita Healthy.life.expectancy.at.birth Social.support
Austria           1.3910801                        1.1791793      0.7781490
Bulgaria         -0.5775550                       -0.6249646      0.4635465
Croatia          -0.1341340                        0.1768771     -1.6622955
Denmark           1.3917981                        1.2192708      1.2607629
Estonia           0.3130872                        0.3372461      0.6226197
Finland           1.0680177                        1.2994538      1.0789562
         Freedom.to.make.life.choices Perceptions.of.corruption
Austria                     1.0805700                -0.6321481
Bulgaria                   -0.5559896                 0.7777174
Croatia                    -0.2037848                 0.4370637
Denmark                     1.3360424                -1.9783269
Estonia                     0.5488162                -0.5908042
Finland                     1.2641514                -1.8594793

Zobrazená tabuľka prezentuje dáta po štandardizácii, čím je zabezpečená porovnateľnosť všetkých premenných na spoločnej škále. Z-skóre nám okamžite ukazuje, ako veľmi sa daná krajina odchyľuje od priemeru celého súboru.

Napríklad:

Obr. 1.

num_vars <- as.data.frame(udaje_scaled)

num_plots <- ncol(num_vars)

side_length <- ceiling(sqrt(num_plots))
par(mfrow = c(side_length, ceiling(num_plots / side_length)))
par(mar = c(4, 4, 2, 1)) 

for (col in names(num_vars)) {
  boxplot(num_vars[[col]],
          main = col,
          col = "lightblue",
          horizontal = TRUE, 
          xlab = "Škálovaná hodnota (Z-skóre)")
}

Boxplot pre Log.GDP.per.capita signalizuje mierne zošikmenú distribúciu, pravdepodobne s niektorými odľahlými hodnotami na hornom konci stupnice. Tieto body reprezentujú ekonomicky najsilnejšie krajiny (napr. severské), ktorých HDP je výrazne nad priemerom sledovanej stredoeurópskej a východoeurópskej skupiny.

Distribúcia Healthy.life.expectancy.at.birth je vo všeobecnosti symetrická s mierne menším rozptylom než HDP. To znamená, že zatiaľ čo priemerná dĺžka zdravého života sa líši, krajiny majú tendenciu sa zoskupovať okolo priemeru, hoci horná hranica rozptylu (“najzdravšie” krajiny) môže byť výraznejšia.

Boxplot pre Social.support je viditeľne najužší, s najkratšími fúzmi, čo vizuálne potvrdzuje, že táto premenná má v porovnaní s ostatnými najnižšiu variabilitu. Väčšina sledovaných krajín má podobne vysoké skóre sociálnej podpory, čím sa táto premenná stáva najmenej dôležitou pre segmentáciu.

Distribúcia Freedom.to.make.life.choices je pomerne široká a mala by byť symetrická, hoci môže vykazovať odľahlé hodnoty na dolnom konci. Tieto body reprezentujú krajiny, kde obyvatelia vnímajú svoju slobodu rozhodovania o živote výrazne pod priemerom sledovanej skupiny.

Boxplot pre Perceptions.of.corruption má veľký rozsah a pravdepodobne vykazuje odľahlé hodnoty na oboch stranách. Tieto extrémy jasne oddeľujú krajiny s veľmi nízkym vnímaním korupcie (Sever) od krajín s veľmi vysokým vnímaním korupcie (Juh a Východ), čo z nej robí kľúčový rozlišovací faktor v dátovom súbore.

Tab. 2

cor_mat <- cor(udaje_scaled, use="pairwise.complete.obs")

cor_mat <- round(cor_mat, 2)

print(cor_mat)
                                 Log.GDP.per.capita
Log.GDP.per.capita                             1.00
Healthy.life.expectancy.at.birth               0.90
Social.support                                 0.55
Freedom.to.make.life.choices                   0.86
Perceptions.of.corruption                     -0.74
                                 Healthy.life.expectancy.at.birth
Log.GDP.per.capita                                           0.90
Healthy.life.expectancy.at.birth                             1.00
Social.support                                               0.42
Freedom.to.make.life.choices                                 0.88
Perceptions.of.corruption                                   -0.80
                                 Social.support
Log.GDP.per.capita                         0.55
Healthy.life.expectancy.at.birth           0.42
Social.support                             1.00
Freedom.to.make.life.choices               0.47
Perceptions.of.corruption                 -0.54
                                 Freedom.to.make.life.choices
Log.GDP.per.capita                                       0.86
Healthy.life.expectancy.at.birth                         0.88
Social.support                                           0.47
Freedom.to.make.life.choices                             1.00
Perceptions.of.corruption                               -0.74
                                 Perceptions.of.corruption
Log.GDP.per.capita                                   -0.74
Healthy.life.expectancy.at.birth                     -0.80
Social.support                                       -0.54
Freedom.to.make.life.choices                         -0.74
Perceptions.of.corruption                             1.00

Silná Pozitívna Korelácia (Redundancia):

Silná Negatívna Korelácia (Kľúčová Diverzita):

Slabšia Korelácia (Nezávislý Príspevok):

Tab. 3

rownames(udaje_scaled) <- c("Pol", "Hun", "Lat", "Lit", "Cro", "Slo", "Aus", "Ser", "Mon", "Ukr", "Bul", "Rom", "Mol", "Fin", "Swe", "Den.", "Est")

dist_mat <- round(dist(udaje_scaled, method = "euclidean"), 2)

dist_mat
      Pol  Hun  Lat  Lit  Cro  Slo  Aus  Ser  Mon  Ukr  Bul  Rom  Mol  Fin
Hun  3.45                                                                 
Lat  3.48 2.37                                                            
Lit  1.45 4.37 4.49                                                       
Cro  1.48 2.20 2.66 2.21                                                  
Slo  1.32 4.13 4.20 0.40 1.96                                             
Aus  3.37 1.14 1.73 4.38 2.33 4.15                                        
Ser  3.00 0.88 1.92 3.91 1.79 3.69 0.85                                   
Mon  3.13 0.96 2.73 4.06 2.08 3.90 1.32 0.94                              
Ukr  5.23 2.09 2.98 5.98 3.85 5.71 2.50 2.40 2.77                         
Bul  4.45 2.67 1.18 5.29 3.42 5.00 2.06 2.34 3.18 2.49                    
Rom  2.05 1.54 2.02 3.12 1.01 2.86 1.69 1.25 1.60 3.25 2.87               
Mol  3.54 2.13 1.04 4.61 2.65 4.34 1.88 1.77 2.46 2.63 1.74 1.87          
Fin  4.21 1.63 1.62 5.07 2.98 4.77 1.34 1.63 2.33 1.72 1.27 2.36 1.87     
Swe  1.59 2.54 2.61 2.89 1.49 2.65 2.62 2.34 2.51 4.27 3.67 1.15 2.49 3.31
Den. 1.28 4.33 4.18 0.61 2.16 0.47 4.25 3.85 4.10 5.93 5.03 2.99 4.38 4.89
Est  5.25 1.93 3.57 5.96 3.90 5.72 2.41 2.48 2.51 1.53 3.20 3.41 3.46 2.04
      Swe Den.
Hun           
Lat           
Lit           
Cro           
Slo           
Aus           
Ser           
Mon           
Ukr           
Bul           
Rom           
Mol           
Fin           
Swe           
Den. 2.67     
Est  4.42 5.96

Táto tabuľka predstavuje Maticu Euklidovských Vzdialeností (dist_mat) medzi krajinami. Každá hodnota (napr. 3.45 medzi Pol a Hun) kvantifikuje, aké sú si krajiny nepodobné vo všetkých piatich škálovaných premenných naraz. Nižšia hodnota znamená väčšiu podobnosť.

  1. Najvyššia Podobnosť (Najmenšie Vzdialenosti):
  1. Najnižšia Podobnosť (Najväčšie Vzdialenosti):

Hodnoty matice potvrdzujú silnú heterogenitu súboru a existencia veľmi blízkych párov (Slo a Lit) a extrémne vzdialených párov (Ukr a Lit/Den.) je kľúčovým predpokladom pre úspešnú hierarchickú zhlukovú analýzu.

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.

hc_ward <- hclust(dist_mat, method = "ward.D2")

plot(hc_ward, 
     labels = rownames(udaje_scaled),
     main = "Dendrogram: Hierarchické zhlukovanie krajín (Wardova metóda, 2015)",
     xlab = "Krajiny", 
     sub = "",
     ylab = "Euklidovská vzdialenosť")

k <- 3
h_cut <- hc_ward$height[length(hc_ward$height) - (k - 1)] 
abline(h = h_cut, col = "red", lwd = 2, lty = 2) 

klaster_membership <- cutree(hc_ward, k = k)

udaje_klasters <- udaje_complete

udaje_klasters$klaster <- factor(klaster_membership)

udaje_klasters$Country <- rownames(udaje_complete)

udaje_klasters <- udaje_klasters[, c("Country", names(udaje_klasters)[!names(udaje_klasters) %in% "Country"])]

head(udaje_klasters)

Červená prerušovaná čiara predstavuje prerezanie dendrogramu na základe rozhodnutia o optimálnom počte zhlukov \(k=3\). Akákoľvek vetva, ktorú táto čiara pretína, sa stáva samostatným zhlukom. Vodorovná čiara jasne delí súbor krajín na tri hlavné, navzájom odlišné, skupiny.

Na základe tohto prerezania vznikajú tri hlavné homogénne zhluky (clusters):

Hierarchická analýza jasne potvrdzuje existenciu silnej polarizácie v skúmaných sociálno-ekonomických ukazovateľoch, pričom hlavnými deliacimi faktormi je geograficko-ekonomická úroveň (Nordic vs. Východ).

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

data_prac <- udaje_klasters[, c("Country", "klaster")]

colnames(data_prac) <- c("Krajina", "Zhluk")

data_prac

Zhluk 1 je tvorený výlučne vysoko vyspelými severskými krajinami (Dánsko, Fínsko, Švédsko) a Rakúskom. Ide o skupinu, ktorá v profilovaní zhlukov dosiahne najvyššie hodnoty HDP, zdravého života a slobody a zároveň najnižšiu vnímanú korupciu. Tento zhluk predstavuje referenčný bod vysokého blahobytu.

Zhluk 2 je najväčším zhlukom združujúcim väčšinu krajín, ktoré prešli ekonomickou transformáciou a vstúpili do EÚ (Poľsko, Maďarsko, Estónsko, Lotyšsko, Litva, Slovinsko, Bulharsko, Rumunsko). Hoci sú medzi nimi rozdiely (Slovinsko je najvyspelejšie), ich sociálno-ekonomické ukazovatele sú na strednej úrovni, jasne odlíšené od severského modelu a najchudobnejších krajín.

Zhluk 3 je charakteristický tým, že v ňom sú sústredené krajiny z juhovýchodnej a východnej Európy, ktoré sa nachádzajú na dolnom konci ekonomickej výkonnosti v súbore (Chorvátsko, Srbsko, Čierna Hora, Moldavsko a Ukrajina). Tieto krajiny budú v profilovaní zhlukov vykazovať najnižšie HDP, zdravý život a najvyššiu vnímanú korupciu.

Deskriptívne štatistiky výsledkov

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

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(
  Premenna = var_names,
  TSS = TSS,
  WSS = WSS,
  BSS = BSS,
  Prop_Between = BSS / TSS
)

ss_table[order(-ss_table$Prop_Between), ]

Analýza mier variability ukázala, že vytvorené tri zhluky sú veľmi dobre oddelené a homogénne, pretože všetky premenné majú vysokú hodnotu BSS/TSS. Primárnymi faktormi odlíšenia krajín sú vnímanie korupcie (Prop_Between 0.819) a ekonomická úroveň (Prop_Between 0.777), ktoré vysvetľujú najväčšiu časť celkového rozptylu. Prekvapivo silným rozlišovacím faktorom je aj Sociálna podpora (Prop_Between 0.678), ktorá v rámci troch zhlukov vykazuje významné rozdiely, čím potvrdzuje existenciu jasne definovaných skupín krajín.

udaje_for_profiling <- subset(udaje_klasters, select = -Country)

cluster_profile <- aggregate(. ~ klaster, 
                             data = udaje_for_profiling, 
                             FUN = mean)

cluster_profile[, -1] <- round(cluster_profile[, -1], 3)

cluster_profile

Klaster 1 sa jasne profiluje ako skupina s najvyššou kvalitou života. Vykazuje najvyššie priemerné hodnoty vo všetkých pozitívnych ukazovateľoch, s HDP na úrovni 10.826, najdlhšou zdravou dĺžkou života 70.75 roka a najväčšou mierou slobody (0.927). Kľúčovo má aj najnižšiu vnímanú korupciu (0.301), čo podčiarkuje jeho charakter inštitucionálne silných a bohatých krajín.

Klaster 2 predstavuje priemernú úroveň v celom súbore. Má stredné hodnoty HDP na obyvateľa (10.236) a mieru korupcie (0.836). Táto skupina je najkoncentrovanejšia okolo priemeru, čím slúži ako stredný článok medzi dvoma extrémami.

Klaster 3 je definovaný najnižšími priemernými hodnotami vo všetkých pozitívnych ukazovateľoch (HDP 9.707, zdravá dĺžka života 65.65 roka, sloboda 0.607). Táto skupina zároveň vykazuje najvyššiu vnímanú mieru korupcie (0.891). Tento profil potvrdzuje, že Klaster 3 predstavuje krajiny s najnižšou úrovňou blahobytu v sledovanom súbore.

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

library(dplyr)

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

descriptives <- descriptives %>% 
  mutate(across(where(is.numeric), ~round(., 3)))

descriptives

Tab. 6. (Centroidy) slúži na profilovanie a pomenovanie troch vytvorených zhlukov. Klaster 1 sa jasne profiluje ako skupina s najvyššou kvalitou života a inštitucionálnou silou, čo je demonštrované najvyšším HDP (10.826), najdlhšou zdravou dĺžkou života (70.75 roka) a najnižšou vnímanou korupciou (0.301). Klaster 3 predstavuje najnižšiu úroveň blahobytu, pretože vo všetkých ukazovateľoch má najnižšie priemery (HDP 9.707) a zároveň najvyššiu korupciu (0.891). Klaster 2 tvorí strednú, prechodnú skupinu, ktorá je koncentrovaná okolo priemeru celého súboru.

Záver

Predložená analýza sa zaoberala klasifikáciou vybraných krajín strednej, východnej a severnej Európy na základe piatich kľúčových sociálno-ekonomických a inštitucionálnych ukazovateľov z databázy World Happiness Report za rok 2015. Cieľom bolo identifikovať homogénne skupiny (zhluky) s podobným profilom blahobytu.

Hierarchická zhluková analýza s Wardovou metódou úspešne rozdelila krajiny do troch jasne definovaných zhlukov. Profilovanie zhlukov potvrdilo, že táto klasifikácia do značnej miery korešponduje s ich stupňom ekonomického rozvoja, histórie a geografickej blízkosti:

Analýza mier variability (BSS/TSS) zároveň preukázala, že vnímanie korupcie a Log.GDP.per.capita sú primárnymi faktormi odlišujúcimi tieto skupiny.

Uvedené výsledky poskytujú cenný podklad pre medzinárodné inštitúcie, ako je Európska komisia, umožňujúc cielenejšiu alokáciu zdrojov a vypisovanie problémovo zameraných projektových výziev (napr. na zlepšenie inštitucionálnej kvality alebo sociálnej podpory) podľa príslušnosti štátov ku klasterom.

LS0tCnRpdGxlOiAiWmhsdWtvdsOhIGFuYWzDvXphIChLbGFzdGVyIEFuYWx5c2lzKSIKb3V0cHV0OiBodG1sX25vdGVib29rCmF1dGhvcjogTGluZGEgS2FrYXNvdmEKLS0tCgoKYGBge3Igc2V0dXAxLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoCiAgZWNobyAgICA9IFRSVUUsICAKICBtZXNzYWdlID0gVFJVRSwgICAKICB3YXJuaW5nID0gRkFMU0UsICAgCiAgZXJyb3IgICA9IEZBTFNFICAgIAopCmBgYAoKYGBge3Igc2V0dXAyLCBtZXNzYWdlPUZBTFNFfQpsaWJyYXJ5KGtuaXRyKQpsaWJyYXJ5KGthYmxlRXh0cmEpCmBgYAoKIyMgw5p2b2QKKipaaGx1a292w6EgKGtsYXN0cm92w6EpIGFuYWzDvXphKiogamUga8S+w7rEjW92b3UgbWV0w7Nkb3UgZXhwbG9yYXTDrXZuZWogxaF0YXRpc3Rpa3kuIFYgcHJheGkgc2Egdnl1xb7DrXZhIHbFoWFkZSB0YW0sIGtkZSBqZSBwb3RyZWJuw6kgcm96ZGVsacWlIHBvem9yb3ZhbmlhIGRvIGhvbW9nw6lubnljaCBjZWxrb3Yg4oCTIG5hcHLDrWtsYWQgcHJpIHNlZ21lbnTDoWNpaSB6w6FrYXpuw61rb3YgdiBtYXJrZXRpbmd1LCBpZGVudGlmaWvDoWNpaSBwb2RvYm7DvWNoIGtyYWrDrW4gdiBtYWtyb2Vrb25vbWlja8O9Y2ggdWthem92YXRlxL5vY2ggYWxlYm8gdiBzb2Npw6FsbmVqIHZlZGUuIEplaiB2w71ob2RvdSBqZSwgxb5lIHByYWN1amUgcyB2aWFjZXLDvW1pIHByZW1lbm7DvW1pIG5hcmF6IGEgZG9rw6HFvmUgb2RoYWxpxaUgdnpvcnksIGt0b3LDqSBieSBwcmkgc2Ftb3Rub20gaG9kbm90ZW7DrSBqZWRub3RsaXbDvWNoIHVrYXpvdmF0ZcS+b3Ygem9zdGFsaSBza3J5dMOpLgoKViB0ZWp0byBwcsOhY2kgcHJlZHN0YXbDrW1lIHpobHVrb3bDuiBhbmFsw716dSBuYSDDusSNZWx5IGFuYWzDvXp5IGEgcHJvZmlsb3ZhbmlhIHZ5YnJhbsO9Y2gga3JhasOtbiBzdHJlZG5laiwgdsO9Y2hvZG5laiBhIHNldmVybmVqIEV1csOzcHkuIE5hxaHDrW0gY2llxL5vbSBqZSBpZGVudGlmaWtvdmHFpSBza3VwaW55IGtyYWrDrW4sIGt0b3LDqSBzw7ogc2kgcG9kb2Juw6kgeiBoxL5hZGlza2EgZmFrdG9yb3Ygb3ZwbHl2xYh1asO6Y2ljaCBrdmFsaXR1IMW+aXZvdGEgYSB2bsOtbWFuw6kgxaHFpWFzdGllLiBWeXXFvmlqZW1lIGTDoXRhIHogZGF0YWLDoXp5IDx1PiBXb3JsZCBIYXBwaW5lc3MgUmVwb3J0IHphIHJvayAyMDE1PC91PiAuCgpQcmUgemhsdWtvdsO6IGFuYWzDvXp1IHNtZSB2eWJyYWxpIHDDpMWlIGvEvsO6xI1vdsO9Y2ggcHJlbWVubsO9Y2gsIGt0b3LDqSByZXByZXplbnR1asO6IHLDtHpuZSBkaW1lbnppZSDFvml2b3RuZWogw7pyb3ZuZToKCiogKipMb2cuR0RQLnBlci5jYXBpdGEqKiAoZWtvbm9taWNrw6Egw7pyb3ZlxYgpCgoqICoqSGVhbHRoeS5saWZlLmV4cGVjdGFuY3kuYXQuYmlydGgqKiAoemRyYXZvdG7DvSBzdGF2KQoKKiAqKlNvY2lhbC5zdXBwb3J0KiogKHNvY2nDoWxuYSBkaW1lbnppYSkKCiogKipGcmVlZG9tLnRvLm1ha2UubGlmZS5jaG9pY2VzKiogKG9zb2Juw6Egc2xvYm9kYSkKCiogKipQZXJjZXB0aW9ucy5vZi5jb3JydXB0aW9uKiogKGt2YWxpdGEgaW7FoXRpdMO6Y2nDrSkKCk5hIHppc3RlbmllIHBvZG9ibm9zdGkga3JhasOtbiBzbWUgcG91xb5pbGkgRXVrbGlkb3Zza8O6IHZ6ZGlhbGVub3PFpSBhIG5hIHNhbW90bsOpIHpobHVrb3ZhbmllIEhpZXJhcmNoaWNrw6kgemhsdWtvdmFuaWUgcyBXYXJkb3ZvdSBtZXTDs2RvdS4KClYgKipUYWIuIDEuKiogdXbDoWR6YW1lIGNlbMO6IG5hbWkgcG91xb5pdMO6IGRhdGFiw6F6dSBvYnNhaHVqw7pjdSB2eWJyYW7DqSBrcmFqaW55IHByZSByb2sgMjAxNS4KYGBge3J9CnVkYWplIDwtIHJlYWQuY3N2KCJXb3JsZCBIYXBwaW5lc3MgUmVwb3J0IDIwMDUtMjAyMS5jc3YiLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpCgojIFbDvWJlciBwcmllcmV6b3bDvWNoIGTDoXQgcHJlIHJvayAyMDE1CnVkYWplMjAxNV9wcmllcmV6IDwtIHN1YnNldCh1ZGFqZSwgWWVhciA9PSAyMDE1KQoKIyBWw71iZXIgdnlicmFuw71jaCBldXLDs3Bza3ljaCBrcmFqw61uCnVkYWplMjAxNV9wcmllcmV6IDwtIHN1YnNldCh1ZGFqZTIwMTVfcHJpZXJleiwKICBDb3VudHJ5Lm5hbWUgPT0gIlBvbGFuZCIgfCBDb3VudHJ5Lm5hbWUgPT0gIkh1bmdhcnkiIHwgQ291bnRyeS5uYW1lID09ICJMYXR2aWEiIHwKICBDb3VudHJ5Lm5hbWUgPT0gIkxpdGh1YW5pYSIgfCBDb3VudHJ5Lm5hbWUgPT0gIkNyb2F0aWEiIHwgQ291bnRyeS5uYW1lID09ICJTbG92ZW5pYSIgfAogIENvdW50cnkubmFtZSA9PSAiQXVzdHJpYSIgfCBDb3VudHJ5Lm5hbWUgPT0gIlNlcmJpYSIgfCBDb3VudHJ5Lm5hbWUgPT0gIk1vbnRlbmVncm8iIHwKICBDb3VudHJ5Lm5hbWUgPT0gIlVrcmFpbmUiIHwgQ291bnRyeS5uYW1lID09ICJCdWxnYXJpYSIgfCBDb3VudHJ5Lm5hbWUgPT0gIlJvbWFuaWEiIHwKICBDb3VudHJ5Lm5hbWUgPT0gIk1vbGRvdmEiIHwgQ291bnRyeS5uYW1lID09ICJGaW5sYW5kIiB8IENvdW50cnkubmFtZSA9PSAiU3dlZGVuIiB8CiAgQ291bnRyeS5uYW1lID09ICJEZW5tYXJrIiB8IENvdW50cnkubmFtZSA9PSAiRXN0b25pYSIKKQoKdWRhamUyMDE1X2NsdXN0ZXJzIDwtIHVkYWplMjAxNV9wcmllcmV6WywgYygKICAiQ291bnRyeS5uYW1lIiwgCiAgIkxvZy5HRFAucGVyLmNhcGl0YSIsCiAgIkhlYWx0aHkubGlmZS5leHBlY3RhbmN5LmF0LmJpcnRoIiwgCiAgIlNvY2lhbC5zdXBwb3J0IiwgCiAgIkZyZWVkb20udG8ubWFrZS5saWZlLmNob2ljZXMiLCAKICAiUGVyY2VwdGlvbnMub2YuY29ycnVwdGlvbiIKKV0KCnJvd25hbWVzKHVkYWplMjAxNV9jbHVzdGVycykgPC0gdWRhamUyMDE1X2NsdXN0ZXJzJENvdW50cnkubmFtZQp1ZGFqZTIwMTVfY2x1c3RlcnMkQ291bnRyeS5uYW1lIDwtIE5VTEwKCnVkYWplMjAxNV9jbHVzdGVycyA8LSBuYS5vbWl0KHVkYWplMjAxNV9jbHVzdGVycykKCnN1bW1hcnkodWRhamUyMDE1X2NsdXN0ZXJzKQpgYGAKWsOha2xhZG7DqSDFoXRhdGlzdGlja8OpIG1pZXJ5IHByZSB2eWJyYW7DqSBwcmVtZW5uw6kgemEgcm9rIDIwMTUgb2RoYcS+dWrDuiB6bmHEjW7DuiA8dT5oZXRlcm9nZW5pdHUgbWVkemkgc2xlZG92YW7DvW1pIGtyYWppbmFtaTwvdT4uIFByZW1lbm7DoSAqKkxvZy5HRFAucGVyLmNhcGl0YSoqIHVrYXp1amUgbmFqdsOkxI3FoWl1IGVrb25vbWlja8O6IHLDtHpub3JvZG9zxaUsIMSNbyBqZSBrxL7DusSNb3bDvSBwcmVkcG9rbGFkIHByZSBlZmVrdMOtdm5lIHJvemzDrcWhZW5pZSB6aGx1a292LgoKVGFrdGllxb4gdiBwcmVtZW5uw71jaCAqKkhlYWx0aHkubGlmZS5leHBlY3RhbmN5LmF0LmJpcnRoKiogYSAqKlBlcmNlcHRpb25zLm9mLmNvcnJ1cHRpb24qKiBwb3pvcnVqZW1lIHbDvXpuYW1uw70gcm96cHR5bCBtZWR6aSBtaW5pbcOhbG55bWkgYSBtYXhpbcOhbG55bWkgaG9kbm90YW1pLCDEjW8gbmF6bmHEjXVqZSBleGlzdGVuY2l1IGR2b2NoIHbDvXJhem5lIG9kbGnFoW7DvWNoIHNrdXDDrW4ga3JhasOtbiAobmFwci4gU2V2ZXIgdnMuIFbDvWNob2QpLgoKTmFvcGFrLCBmYWt0b3IgKipTb2NpYWwuc3VwcG9ydCoqIHZ5a2F6dWplIHYgY2Vsb20gc8O6Ym9yZSBwb21lcm5lIHZ5c29rw6kgaG9kbm90eSBhIG7DrXpreSByb3pwdHlsLCDEjW8gbmF6bmHEjXVqZSwgxb5lIHTDoXRvIHByZW1lbm7DoSBidWRlIG1lbmVqIGTDtGxlxb5pdMOhIHByZSBwcmltw6FybnUgc2VnbWVudMOhY2l1IGtyYWrDrW4gZG8gemhsdWtvdi4gCgpOYSB6w6FrbGFkZSB0w71jaHRvIHppc3RlbsOtIG/EjWFrw6F2YW1lLCDFvmUgaGxhdm7DqSByb3pkaWVseSBtZWR6aSB2eXR2b3JlbsO9bWkgemhsdWttaSBidWTDuiBkZXRlcm1pbm92YW7DqSBwcmVkb3bFoWV0a8O9bSBla29ub21pY2tvdSDDunJvdsWIb3UsIHpkcmF2b3Ruw71tIHN0YXZvbSBhIHZuw61tYW7DrW0gaW7FoXRpdHVjaW9uw6FsbmVqIGt2YWxpdHkuCgoqKlRhYmxlIDEuKioKYGBge3J9CnVkYWplMjAxNV9jbHVzdGVycwpgYGAKCkhpZXJhcmNoaWNrw6EgemhsdWtvdsOhIGFuYWzDvXphIHByYWN1amUgcyBtaWVyYW1pIHZ6ZGlhbGVub3N0aSBtZWR6aSBwb3pvcm92YW5pYW1pLiBBYnkgYm9saSB0aWV0byB2emRpYWxlbm9zdGkgcG9yb3ZuYXRlxL5uw6ksIGplIHBvdHJlYm7DqSwgYWJ5IHbFoWV0a3kgcHJlbWVubsOpIGJvbGkgZGVmaW5vdmFuw6kgbmEgcm92bmFrZWrFoWvDoWxlLiBQb3XFvsOtdmFtZSBwcml0b20gdHp2LiB6LcWha8OhbG92YW5pZSwgcHJpxI1vbSB0cmFuc2Zvcm1vdmFuw6kgJHokIGhvZG5vdHkgKHNrw7NyZSkgdnlwb8SNw610YW1lIG5hc2xlZG92bmUKCiQkeiA9IFxmcmFje3gtXG11fXtcc2lnbWF9JCQKa2RlICRcbXUkIGplIHN0cmVkbsOhIGhvZG5vdGEgYSAkXHNpZ21hJCBqZSDFoXRhbmRhcmRuw6Egb2RjaMO9bGthIHBvem9yb3ZhbsOtICR4JC4gUHJlZHBva2xhZMOhbWUgcHJpdG9tLCDFvmUgc8O6Ym9yIMO6ZGFqb3YgdcW+IG5lb2JzYWh1amUgTkEgaG9kbm90eSwga3RvcsOpIGJvbGkgb8WhZXRyZW7DqSB2IHByZWRjaMOhZHphasO6Y2ljaCBrcm9rb2NoLgoKVG91dG8gb3BlcsOhY2lvdSB6w61za2FtZSDFoWvDoWxvdmFuw6kgcG96b3JvdmFuaWEsIHByacSNb20gaWNoIHJvemxvxb5lbmllIGplIHpuw6F6b3JuZW7DqSBuYXNsZWRvdm5lOgoKYGBge3J9CnVkYWplX2NvbXBsZXRlIDwtIG5hLm9taXQodWRhamUyMDE1X2NsdXN0ZXJzKQoKdWRhamVfc2NhbGVkIDwtIHNjYWxlKHVkYWplX2NvbXBsZXRlKQoKaGVhZCh1ZGFqZV9zY2FsZWQpCmBgYApab2JyYXplbsOhIHRhYnXEvmthIHByZXplbnR1amUgZMOhdGEgcG8gxaF0YW5kYXJkaXrDoWNpaSwgxI3DrW0gamUgemFiZXpwZcSNZW7DoSBwb3Jvdm5hdGXEvm5vc8WlIHbFoWV0a8O9Y2ggcHJlbWVubsO9Y2ggbmEgc3BvbG/EjW5laiDFoWvDoWxlLiBaLXNrw7NyZSBuw6FtIG9rYW3Fvml0ZSB1a2F6dWplLCBha28gdmXEvm1pIHNhIGRhbsOhIGtyYWppbmEgb2RjaHnEvnVqZSBvZCBwcmllbWVydSBjZWzDqWhvIHPDumJvcnUuCgpOYXByw61rbGFkOgoKKiAqKkF1c3RyaWEqKiBhICoqRGVubWFyayoqIHZ5a2F6dWrDuiA8dT52w71yYXpuZSBuYWRwcmllbWVybsOpIGhvZG5vdHkgKG5hZCAxLjApIHZvIHbFoWV0a8O9Y2ggcG96aXTDrXZueWNoIHVrYXpvdmF0ZcS+b2NoPC91PiwgYWtvIHPDuiBMb2cuR0RQLnBlci5jYXBpdGEsIEhlYWx0aHkubGlmZS5leHBlY3RhbmN5LmF0LmJpcnRoIGEgRnJlZWRvbS50by5tYWtlLmxpZmUuY2hvaWNlcy4gU8O6xI1hc25lIG1hasO6IDx1PnBvZHByaWVtZXJuw6kgc2vDs3JlIHZvIFBlcmNlcHRpb25zLm9mLmNvcnJ1cHRpb24gKHrDoXBvcm7DqSBob2Rub3R5KSwgxI1vIHN2ZWTEjcOtIG8gdmXEvm1pIG7DrXprb20gdm7DrW1hbsOtIGtvcnVwY2llPC91PiwgxI3DrW0gc2EgamFzbmUgb2RsacWhdWrDuiBvZCBwcmllbWVydS4KCiogTmFvcGFrLCAqKkJ1bGdhcmlhKiogbcOhIDx1Pm1pZXJuZSBwb2RwcmllbWVybsOpIGhvZG5vdHkgdm8gdsWhZXRrw71jaCBrxL7DusSNb3bDvWNoIHByZW1lbm7DvWNoICh6w6Fwb3Juw6kgJHokLXNrw7NyZSkgYSB2w71yYXpuZSBuYWRwcmllbWVybsOpIHZuw61tYW5pZSBrb3J1cGNpZSAoMC43OCk8L3U+LCDEjcOtbSB0dm9yw60gb3BhxI1uw70gcMOzbCBkaXN0cmliw7pjaWUuCgoqICoqQ3JvYXRpYSoqIHNhIHYgcsOhbWNpIHByZW1lbm5laiBTb2NpYWwuc3VwcG9ydCBvZGNoecS+dWplIG9kIHByaWVtZXJ1IG5hanZpYWMgKGhvZG5vdGEgLTEuNjYpIHYgbmVnYXTDrXZub20gc21lcmUsIMSNbyBuYXpuYcSNdWplLCDFvmUgdiB0ZWp0byBkaW1lbnppaSBqZSBqZWhvIDx1PsO6cm92ZcWIIHNvY2nDoWxuZWogcG9kcG9yeSB2w71yYXpuZSBwb2QgcHJpZW1lcm9tPC91PiBzbGVkb3ZhbmVqIHNrdXBpbnkga3JhasOtbi4KCioqT2JyLiAxLioqCmBgYHtyfQpudW1fdmFycyA8LSBhcy5kYXRhLmZyYW1lKHVkYWplX3NjYWxlZCkKCm51bV9wbG90cyA8LSBuY29sKG51bV92YXJzKQoKc2lkZV9sZW5ndGggPC0gY2VpbGluZyhzcXJ0KG51bV9wbG90cykpCnBhcihtZnJvdyA9IGMoc2lkZV9sZW5ndGgsIGNlaWxpbmcobnVtX3Bsb3RzIC8gc2lkZV9sZW5ndGgpKSkKcGFyKG1hciA9IGMoNCwgNCwgMiwgMSkpIAoKZm9yIChjb2wgaW4gbmFtZXMobnVtX3ZhcnMpKSB7CiAgYm94cGxvdChudW1fdmFyc1tbY29sXV0sCiAgICAgICAgICBtYWluID0gY29sLAogICAgICAgICAgY29sID0gImxpZ2h0Ymx1ZSIsCiAgICAgICAgICBob3Jpem9udGFsID0gVFJVRSwgCiAgICAgICAgICB4bGFiID0gIsWga8OhbG92YW7DoSBob2Rub3RhIChaLXNrw7NyZSkiKQp9CgpgYGAKCkJveHBsb3QgcHJlICoqTG9nLkdEUC5wZXIuY2FwaXRhKiogc2lnbmFsaXp1amUgPHU+bWllcm5lIHpvxaFpa21lbsO6IGRpc3RyaWLDumNpdTwvdT4sIHByYXZkZXBvZG9ibmUgcyBuaWVrdG9yw71taSBvZMS+YWhsw71taSBob2Rub3RhbWkgbmEgaG9ybm9tIGtvbmNpIHN0dXBuaWNlLiBUaWV0byBib2R5IHJlcHJlemVudHVqw7ogZWtvbm9taWNreSBuYWpzaWxuZWrFoWllIGtyYWppbnkgKG5hcHIuIHNldmVyc2vDqSksIGt0b3LDvWNoIEhEUCBqZSB2w71yYXpuZSBuYWQgcHJpZW1lcm9tIHNsZWRvdmFuZWogc3RyZWRvZXVyw7Nwc2tlaiBhIHbDvWNob2RvZXVyw7Nwc2tlaiBza3VwaW55LgoKRGlzdHJpYsO6Y2lhICoqSGVhbHRoeS5saWZlLmV4cGVjdGFuY3kuYXQuYmlydGgqKiBqZSB2byB2xaFlb2JlY25vc3RpIDx1PnN5bWV0cmlja8OhPC91PiBzIG1pZXJuZSBtZW7FocOtbSByb3pwdHlsb20gbmXFviBIRFAuIFRvIHpuYW1lbsOhLCDFvmUgemF0aWHEviDEjW8gcHJpZW1lcm7DoSBkxLrFvmthIHpkcmF2w6lobyDFvml2b3RhIHNhIGzDrcWhaSwga3JhamlueSBtYWrDuiB0ZW5kZW5jaXUgc2Egem9za3Vwb3ZhxaUgb2tvbG8gcHJpZW1lcnUsIGhvY2kgaG9ybsOhIGhyYW5pY2Egcm96cHR5bHUgKCJuYWp6ZHJhdsWhaWUiIGtyYWppbnkpIG3DtMW+ZSBiecWlIHbDvXJhem5lasWhaWEuCgpCb3hwbG90IHByZSAqKlNvY2lhbC5zdXBwb3J0KiogamUgdmlkaXRlxL5uZSBuYWp1xb7FocOtLCBzIG5hamtyYXTFocOtbWkgZsO6em1pLCDEjW8gdml6dcOhbG5lIHBvdHZyZHp1amUsIMW+ZSB0w6F0byBwcmVtZW5uw6EgbcOhIHYgcG9yb3ZuYW7DrSBzIG9zdGF0bsO9bWkgPHU+bmFqbmnFvsWhaXUgdmFyaWFiaWxpdHU8L3U+LiBWw6TEjcWhaW5hIHNsZWRvdmFuw71jaCBrcmFqw61uIG3DoSBwb2RvYm5lIHZ5c29rw6kgc2vDs3JlIHNvY2nDoWxuZWogcG9kcG9yeSwgxI3DrW0gc2EgdMOhdG8gcHJlbWVubsOhIHN0w6F2YSBuYWptZW5laiBkw7RsZcW+aXRvdSBwcmUgc2VnbWVudMOhY2l1LgoKRGlzdHJpYsO6Y2lhICoqRnJlZWRvbS50by5tYWtlLmxpZmUuY2hvaWNlcyoqIGplIHBvbWVybmUgxaFpcm9rw6EgYSBtYWxhIGJ5IGJ5xaUgc3ltZXRyaWNrw6EsIGhvY2kgbcO0xb5lIHZ5a2F6b3ZhxaUgb2TEvmFobMOpIGhvZG5vdHkgbmEgZG9sbm9tIGtvbmNpLiBUaWV0byBib2R5IHJlcHJlemVudHVqw7oga3JhamlueSwga2RlIG9ieXZhdGVsaWEgdm7DrW1hasO6IHN2b2p1IHNsb2JvZHUgcm96aG9kb3ZhbmlhIG8gxb5pdm90ZSB2w71yYXpuZSBwb2QgcHJpZW1lcm9tIHNsZWRvdmFuZWogc2t1cGlueS4KCkJveHBsb3QgcHJlICoqUGVyY2VwdGlvbnMub2YuY29ycnVwdGlvbioqIG3DoSB2ZcS+a8O9IHJvenNhaCBhIHByYXZkZXBvZG9ibmUgdnlrYXp1amUgb2TEvmFobMOpIGhvZG5vdHkgbmEgb2JvY2ggc3RyYW7DoWNoLiBUaWV0byBleHRyw6lteSBqYXNuZSBvZGRlxL51asO6IGtyYWppbnkgcyB2ZcS+bWkgbsOtemt5bSB2bsOtbWFuw61tIGtvcnVwY2llIChTZXZlcikgb2Qga3JhasOtbiBzIHZlxL5taSB2eXNva8O9bSB2bsOtbWFuw61tIGtvcnVwY2llIChKdWggYSBWw71jaG9kKSwgxI1vIHogbmVqIHJvYsOtIGvEvsO6xI1vdsO9IHJvemxpxaFvdmFjw60gZmFrdG9yIHYgZMOhdG92b20gc8O6Ym9yZS4KCiAKCioqVGFiLiAyKioKYGBge3IgY29ycmVsYXRpb24tbWF0cml4fQpjb3JfbWF0IDwtIGNvcih1ZGFqZV9zY2FsZWQsIHVzZT0icGFpcndpc2UuY29tcGxldGUub2JzIikKCmNvcl9tYXQgPC0gcm91bmQoY29yX21hdCwgMikKCnByaW50KGNvcl9tYXQpCmBgYAoqKlNpbG7DoSBQb3ppdMOtdm5hIEtvcmVsw6FjaWEgKFJlZHVuZGFuY2lhKSoqOgoKKiAqKkxvZy5HRFAucGVyLmNhcGl0YSoqLCAqKkhlYWx0aHkubGlmZS5leHBlY3RhbmN5LmF0LmJpcnRoKiogYSAqKkZyZWVkb20udG8ubWFrZS5saWZlLmNob2ljZXMqKiBzw7ogdmXEvm1pIHNpbG5lIGtvcmVsb3ZhbsOpIChob2Rub3R5IG5hZCAwLjg2KS4gVG8gem5hbWVuw6EsIMW+ZSBrcmFqaW55IHMgdnnFocWhw61tIEhEUCBtYWrDuiB0eXBpY2t5IGFqIGRsaMWhaXUgemRyYXbDuiBkxLrFvmt1IMW+aXZvdGEgYSB2ecWhxaFpdSBtaWVydSB2bsOtbWFuZWogc2xvYm9keS4gVGlldG8gdHJpIHByZW1lbm7DqSBtZXJhasO6IGRvIHZlxL5rZWogbWllcnkgcG9kb2Juw7ogZGltZW56aXUga3ZhbGl0eSDFvml2b3RhLCBhIHByZXRvIG3DtMW+dSBiecWlIHYgemhsdWtvdmVqIGFuYWzDvXplIHBvdmHFvm92YW7DqSB6YSBtaWVybmUgcmVkdW5kYW50bsOpLgoKKipTaWxuw6EgTmVnYXTDrXZuYSBLb3JlbMOhY2lhIChLxL7DusSNb3bDoSBEaXZlcnppdGEpKio6CgoqICoqUGVyY2VwdGlvbnMub2YuY29ycnVwdGlvbioqIHZ5a2F6dWplIHNpbG7DuiBuZWdhdMOtdm51IGtvcmVsw6FjaXUgc28gdsWhZXRrw71taSB0cm9taSB2ecWhxaFpZSBzcG9tZW51dMO9bWkgcHJlbWVubsO9bWkgKGhvZG5vdHkgbWVkemkgLTAuNzQgYSAtMC44MCkuIFRvIHBvdHZyZHp1amUsIMW+ZSBrcmFqaW55IHMgdnlzb2vDvW0gSERQLCB6ZHJhdsOtbSBhIHNsb2JvZG91IG1hasO6IG7DrXprZSB2bsOtbWFuaWUga29ydXBjaWUgKHNpbG7DoSBrb3JlbMOhY2lhIG1lZHppIGJsYWhvYnl0b20gYSBpbsWhdGl0dWNpb27DoWxub3Uga3ZhbGl0b3UpLgoKKipTbGFixaFpYSBLb3JlbMOhY2lhIChOZXrDoXZpc2zDvSBQcsOtc3Bldm9rKSoqOgoKKiAqKlNvY2lhbC5zdXBwb3J0KiogdnlrYXp1amUgbmFqc2xhYsWhaXUga29yZWzDoWNpdSBzIG9zdGF0bsO9bWkgcHJlbWVubsO9bWkgKGhvZG5vdHkgbWVkemkgMC40MiBhIDAuNTUpLiBUbyBuYXpuYcSNdWplLCDFvmUgaG9jaSBzb2Npw6FsbmEgcG9kcG9yYSBzIGJsYWhvYnl0b20gc8O6dmlzw60sIGplaiBwcsOtc3Bldm9rIGsgY2Vsa292w71tIHJvemRpZWxvbSBtZWR6aSBrcmFqaW5hbWkgamUgcmVsYXTDrXZuZSBuZXrDoXZpc2zDvQoKCgoqKlRhYi4gMyoqCmBgYHtyfQpyb3duYW1lcyh1ZGFqZV9zY2FsZWQpIDwtIGMoIlBvbCIsICJIdW4iLCAiTGF0IiwgIkxpdCIsICJDcm8iLCAiU2xvIiwgIkF1cyIsICJTZXIiLCAiTW9uIiwgIlVrciIsICJCdWwiLCAiUm9tIiwgIk1vbCIsICJGaW4iLCAiU3dlIiwgIkRlbi4iLCAiRXN0IikKCmRpc3RfbWF0IDwtIHJvdW5kKGRpc3QodWRhamVfc2NhbGVkLCBtZXRob2QgPSAiZXVjbGlkZWFuIiksIDIpCgpkaXN0X21hdApgYGAKVMOhdG8gdGFidcS+a2EgcHJlZHN0YXZ1amUgKipNYXRpY3UgRXVrbGlkb3Zza8O9Y2ggVnpkaWFsZW5vc3TDrSoqIChkaXN0X21hdCkgbWVkemkga3JhamluYW1pLiBLYcW+ZMOhIGhvZG5vdGEgKG5hcHIuIDMuNDUgbWVkemkgUG9sIGEgSHVuKSBrdmFudGlmaWt1amUsIGFrw6kgc8O6IHNpIGtyYWppbnkgbmVwb2RvYm7DqSB2byB2xaFldGvDvWNoIHBpYXRpY2ggxaFrw6Fsb3ZhbsO9Y2ggcHJlbWVubsO9Y2ggbmFyYXouICoqTmnFvsWhaWEgaG9kbm90YSB6bmFtZW7DoSB2w6TEjcWhaXUgcG9kb2Jub3PFpS4qKgoKMS4gKipOYWp2ecWhxaFpYSBQb2RvYm5vc8WlIChOYWptZW7FoWllIFZ6ZGlhbGVub3N0aSkqKjoKKiBOYWptZW7FoWllIHZ6ZGlhbGVub3N0aSBzw7ogbWVkemkgTGl0dm91IChMaXQpIGEgU2xvdmluc2tvbSAoU2xvKSAoMC40MCkgYSBtZWR6aSBEw6Fuc2tvbSAoRGVuLikgYSBTbG92aW5za29tIChTbG8pICgwLjQ3KS4gVGlldG8ga3JhamlueSBzaSBzw7ogdiBkZWZpbm92YW7DvWNoIHVrYXpvdmF0ZcS+b2NoIG5hanZpYWMgcG9kb2Juw6kuCgoqIMSOYWzFoWlhIHNpbG7DoSBwb2RvYm5vc8WlIGplIG1lZHppIETDoW5za29tIChEZW4uKSBhIExpdHZvdSAoTGl0KSAoMC42MSkuCgoqIFNpbG5lIHBvZG9ibsOpIHPDuiB0aWXFviBTcmJza28gKFNlcikgYSBNYcSPYXJza28gKEh1bikgKDAuODgpLCBhIFJha8O6c2tvIChBdXMpIHNvIFNyYnNrb20gKFNlcikgKDAuODUpLCDEjW8gbmF6bmHEjXVqZSBleGlzdGVuY2l1IGJsw616a3ljaCB6b3NrdXBlbsOtIHYgcsOhbWNpIHN0cmVkbmVqIGEgdsO9Y2hvZG5laiBFdXLDs3B5LgoKMi4gKipOYWpuacW+xaFpYSBQb2RvYm5vc8WlIChOYWp2w6TEjcWhaWUgVnpkaWFsZW5vc3RpKSoqOgoKKiBOYWp2w6TEjcWhaWUgdnpkaWFsZW5vc3RpIChuYWQgNS4wKSBzYSBvYmphdnVqw7ogdiBwcsOtcGFkb2NoLCBha28gc8O6IFVrcmFqaW5hIChVa3IpIGEgTGl0dmEgKExpdCkgKDUuOTgpIGFsZWJvIFVrcmFqaW5hIChVa3IpIGEgRMOhbnNrbyAoRGVuLikgKDUuOTMpLiBUaWV0byB2eXNva8OpIHZ6ZGlhbGVub3N0aSBwb3R2cmR6dWrDuiwgxb5lIGtyYWppbnkgc2EgdiBza8O6bWFuw71jaCBkaW1lbnppw6FjaCBuYXZ6w6Fqb20gbmFqdmlhYyBsw63FoWlhLgoKKiBWxaFlb2JlY25lIHBsYXTDrSwgxb5lIHZ6ZGlhbGVub3N0aSBtZWR6aSBzZXZlcnNrw71taSBrcmFqaW5hbWkgKFN3ZSwgRGVuLiwgRmluKSBhIGtyYWppbmFtaSB2w71jaG9kbsOpaG8gYmxva3UgKFVrciwgTW9sKSBzw7ogbmFqdnnFocWhaWUsIMSNbyBwb3R2cmR6dWplIGV4aXN0ZW5jaXUgZHZvY2ggaGxhdm7DvWNoLCBuYXZ6w6Fqb20gdmXEvm1pIG9kbGnFoW7DvWNoIHNrdXDDrW4uCgpIb2Rub3R5IG1hdGljZSBwb3R2cmR6dWrDuiBzaWxuw7ogaGV0ZXJvZ2VuaXR1IHPDumJvcnUgYSBleGlzdGVuY2lhIHZlxL5taSBibMOtemt5Y2ggcMOhcm92IChTbG8gYSBMaXQpIGEgZXh0csOpbW5lIHZ6ZGlhbGVuw71jaCBww6Fyb3YgKFVrciBhIExpdC9EZW4uKSBqZSBrxL7DusSNb3bDvW0gcHJlZHBva2xhZG9tIHByZSDDunNwZcWhbsO6IGhpZXJhcmNoaWNrw7ogemhsdWtvdsO6IGFuYWzDvXp1LgoKIyMgUHJpbmPDrXAgaGllcmFyY2hpY2vDqWhvIHpobHVrb3ZhbmlhIChXYXJkb3ZhIG1ldMOzZGEpCgpaaGx1a292YW5pZSB2IHByw61wYWRlIFdhcmRvdmVqIG1ldMOzZHkgcHJlYmllaGEgemRvbGEgc21lcm9tIG5haG9yLCB0LmouIHphxI3DrW5hbWUgcyBqZWRub8SNbGVubsO9bWkga2xhc3RyYW1pLCBrdG9yw6kgcG9zdHVwbmUgemx1xI11amVtZS4gVMOhdG8gbWV0w7NkYSBwYXRyw60gdGVkYSBtZWR6aSBhZ2xvbWVyYXTDrXZuZSBoaWVyYXJjaGlja8OpIG1ldMOzZHkuIE1pbmltYWxpenVqZSBuw6FyYXN0IHZuw7p0b3JuZWogdmFyaWFiaWxpdHkgcHJpIHNwb2plbsOtIGR2b2NoIGtsYXN0cm92LCBwcmnEjW9tIHZ5dcW+w612YSBuYXNsZWRvdm7DqSB2w71wb8SNdHk6CgpXYXJkb3bDoSBtZXTDs2RhIG1pbmltYWxpenVqZSBzdW11IMWhdHZvcmNvdiBjaMO9YiAoRXJyb3Igc3VtIG9mIFNxdWFyZXMgLSBFU1MpCgokJEVTUyhDKSA9IFxzdW1fe2kgXGluIEN9IFxsVmVydCB4X2kgLSBcYmFye3h9X0MgXHJWZXJ0XjIkJAprZGUgJEMkIGplIHp2YcW+b3ZhbsO9IGtsYXN0ZXIgKHpobHVrKS4gViBrYcW+ZG9tIGtyb2t1IHpsdcSNb3ZhbmlhIGR2b2NoIGtsYXN0ZXJvdiwgV2FyZG92YSBtZXTDs2RhIGjEvmFkw6EgbWluaW3DoWxueSBwcsOtcmFzdG9rIHN1bXkgxaF0dm9yY292IGNow71iICgkXERlbHRhIEVTUyQpLCBwcmnEjW9tCgokJFxEZWx0YSBFU1MgPSBFU1MoQSBcY3VwIEIpIC0gRVNTKEEpIC0gRVNTKEIpJCQKRHZvamljYSB6aGx1a292LCBrdG9yw6kgdGVqdG8gcG9kbWllbmtlIG8gbWluaW1hbGl6w6FjaWkgdnlob3Z1amUsIGplIG7DoXNsZWRuZSB6bMO6xI1lbsOhIGEgcHJlY2jDoWR6YSBzYSBrIMSPYWzFoWllbXUga2tyb2t1LiBUbyBzcHJhdmlkbGEgdmVkaWUgayB2eXR2w6FyYW5pdSBob21vZ8Opbm55Y2ggemhsdWtvdiwgcHJpxI1vbSBuZWRvY2jDoWR6YSBrIG9kdHJow6F2YW5pdSBvZMS+YWhsw71jaCBob2Ruw7R0IHRhaywgYWtvIHByaSBpbsO9Y2ggemhsdWtvdmFjw61jaCBtZXTDs2RhY2guCgoKKipPYnIuIDIuKiogSGllcmFyY2hpY2vDqSB6aGx1a292YW5pZSAtIGRlbmRvZ3JhbS4gCmBgYHtyfQpoY193YXJkIDwtIGhjbHVzdChkaXN0X21hdCwgbWV0aG9kID0gIndhcmQuRDIiKQoKcGxvdChoY193YXJkLCAKICAgICBsYWJlbHMgPSByb3duYW1lcyh1ZGFqZV9zY2FsZWQpLAogICAgIG1haW4gPSAiRGVuZHJvZ3JhbTogSGllcmFyY2hpY2vDqSB6aGx1a292YW5pZSBrcmFqw61uIChXYXJkb3ZhIG1ldMOzZGEsIDIwMTUpIiwKICAgICB4bGFiID0gIktyYWppbnkiLCAKICAgICBzdWIgPSAiIiwKICAgICB5bGFiID0gIkV1a2xpZG92c2vDoSB2emRpYWxlbm9zxaUiKQoKayA8LSAzCmhfY3V0IDwtIGhjX3dhcmQkaGVpZ2h0W2xlbmd0aChoY193YXJkJGhlaWdodCkgLSAoayAtIDEpXSAKYWJsaW5lKGggPSBoX2N1dCwgY29sID0gInJlZCIsIGx3ZCA9IDIsIGx0eSA9IDIpIAprbGFzdGVyX21lbWJlcnNoaXAgPC0gY3V0cmVlKGhjX3dhcmQsIGsgPSBrKQoKdWRhamVfa2xhc3RlcnMgPC0gdWRhamVfY29tcGxldGUKCnVkYWplX2tsYXN0ZXJzJGtsYXN0ZXIgPC0gZmFjdG9yKGtsYXN0ZXJfbWVtYmVyc2hpcCkKCnVkYWplX2tsYXN0ZXJzJENvdW50cnkgPC0gcm93bmFtZXModWRhamVfY29tcGxldGUpCgp1ZGFqZV9rbGFzdGVycyA8LSB1ZGFqZV9rbGFzdGVyc1ssIGMoIkNvdW50cnkiLCBuYW1lcyh1ZGFqZV9rbGFzdGVycylbIW5hbWVzKHVkYWplX2tsYXN0ZXJzKSAlaW4lICJDb3VudHJ5Il0pXQoKaGVhZCh1ZGFqZV9rbGFzdGVycykKYGBgCirEjGVydmVuw6EgcHJlcnXFoW92YW7DoSDEjWlhcmEgcHJlZHN0YXZ1amUgcHJlcmV6YW5pZSBkZW5kcm9ncmFtdSBuYSB6w6FrbGFkZSByb3pob2RudXRpYSBvIG9wdGltw6Fsbm9tIHBvxI10ZSB6aGx1a292ICRrPTMkKi4gQWvDoWtvxL52ZWsgdmV0dmEsIGt0b3LDuiB0w6F0byDEjWlhcmEgcHJldMOtbmEsIHNhIHN0w6F2YSBzYW1vc3RhdG7DvW0gemhsdWtvbS4gVm9kb3Jvdm7DoSDEjWlhcmEgamFzbmUgZGVsw60gc8O6Ym9yIGtyYWrDrW4gbmEgdHJpIGhsYXZuw6ksIG5hdnrDoWpvbSBvZGxpxaFuw6ksIHNrdXBpbnkuCgpOYSB6w6FrbGFkZSB0b2h0byBwcmVyZXphbmlhIHZ6bmlrYWrDuiB0cmkgaGxhdm7DqSBob21vZ8Opbm5lIHpobHVreSAoY2x1c3RlcnMpOgoKKiAqKlpobHVrIDEgKE5vcmRpYy9WeXNva8O9IEJsYWhvYnl0KSoqOiBUZW50byB6aGx1ayBqZSB0eXBpY2t5IHR2b3JlbsO9IHNrdXBpbm91IGtyYWrDrW4sIGt0b3LDqSBzw7ogc3BvamVuw6kgcHJpIDx1PnZlxL5taSBuw616a2VqIHZ6ZGlhbGVub3N0aSBhIHPDuiBleHRyw6ltbmUgb2RkZWxlbsOpIG9kIHp2ecWha3U8L3U+IChuYXByLiBGaW4sIFN3ZSwgRGVuLikuIFRpZXRvIGtyYWppbnkgcHJlZHN0YXZ1asO6IHNrdXBpbnUgcyBuYWp2ecWhxaHDrW0gSERQLCB6ZHJhdsOtbSBhIG5ham5pxb7FoW91IGtvcnVwY2lvdS4KCiogKipaaGx1ayAyIChTdHJlZG7DoSBhIFbDvWNob2Ruw6EgRXVyw7NwYSkqKjogSWRlIG8gbmFqdsOkxI3FocOtLCBoZXRlcm9nw6lubmVqxaHDrSB6aGx1aywga3RvcsO9IHphaMWVxYhhIHbDpMSNxaFpbnUgdHJhbnNmb3JtYcSNbsO9Y2gga3JhasOtbiBhIGtyYWrDrW4gc3RyZWRuZWogYSBqdWhvdsO9Y2hvZG5laiBFdXLDs3B5IChQb2wsIEh1biwgTGF0LCBMaXQsIENybywgU2xvLCBCdWwsIFJvbSwgRXN0IGF0xI8uKS4gVGlldG8ga3JhamlueSB0dm9yaWEgPHU+cHJlY2hvZG7DuiBza3VwaW51IHMgcHJpZW1lcm7DvW1pIGhvZG5vdGFtaTwvdT4uCgoqICoqWmhsdWsgMyAoQmFsa8Ohbi9PdXRsaWVyL07DrXpreSBCbGFob2J5dCkqKjogVGVudG8gemhsdWsgamUgdHZvcmVuw70ga3JhamluYW1pLCBrdG9yw6kgc2Egb2QgdsWhZXRrw71jaCBvc3RhdG7DvWNoIG9kZGVsaWxpIGJ1xI8gbmEgdmXEvm1pIG5lc2tvcmVqIMO6cm92bmksIGFsZWJvIGJvbGkgcHJpcG9qZW7DqSBrIGhsYXZuw6ltdSB6aGx1a3UgYWtvIHBvc2xlZG7DqSAobmFwci4gVWtyIGEgbmlla3RvcsOpIGJhbGvDoW5za2UgxaF0w6F0eSksIMSNbyBzaWduYWxpenVqZSBpY2ggPHU+dsO9cmF6bsO6IG9kbGnFoW5vc8WlIG9kIHByaWVtZXJ1IHPDumJvcnU8L3U+LgoKSGllcmFyY2hpY2vDoSBhbmFsw716YSBqYXNuZSBwb3R2cmR6dWplIGV4aXN0ZW5jaXUgc2lsbmVqIHBvbGFyaXrDoWNpZSB2IHNrw7ptYW7DvWNoIHNvY2nDoWxuby1la29ub21pY2vDvWNoIHVrYXpvdmF0ZcS+b2NoLCBwcmnEjW9tIGhsYXZuw71taSBkZWxpYWNpbWkgZmFrdG9ybWkgamUgZ2VvZ3JhZmlja28tZWtvbm9taWNrw6Egw7pyb3ZlxYggKE5vcmRpYyB2cy4gVsO9Y2hvZCkuCgoqKlRhYi40LioqICBQcsOtc2x1xaFub3PFpSBrcmFqw61uIGRvIGtsYXN0cm92LgpgYGB7cn0KZGF0YV9wcmFjIDwtIHVkYWplX2tsYXN0ZXJzWywgYygiQ291bnRyeSIsICJrbGFzdGVyIildCgpjb2xuYW1lcyhkYXRhX3ByYWMpIDwtIGMoIktyYWppbmEiLCAiWmhsdWsiKQoKZGF0YV9wcmFjCmBgYAoqKlpobHVrIDEqKiBqZSB0dm9yZW7DvSB2w71sdcSNbmUgPHU+dnlzb2tvIHZ5c3BlbMO9bWkgc2V2ZXJza8O9bWkga3JhamluYW1pPC91PiAoRMOhbnNrbywgRsOtbnNrbywgxaB2w6lkc2tvKSBhIFJha8O6c2tvbS4gSWRlIG8gc2t1cGludSwga3RvcsOhIHYgcHJvZmlsb3ZhbsOtIHpobHVrb3YgZG9zaWFobmUgbmFqdnnFocWhaWUgaG9kbm90eSBIRFAsIHpkcmF2w6lobyDFvml2b3RhIGEgc2xvYm9keSBhIHrDoXJvdmXFiCBuYWpuacW+xaFpdSB2bsOtbWFuw7oga29ydXBjaXUuIFRlbnRvIHpobHVrIHByZWRzdGF2dWplIHJlZmVyZW7EjW7DvSBib2Qgdnlzb2vDqWhvIGJsYWhvYnl0dS4KCioqWmhsdWsgMioqIGplIG5hanbDpMSNxaHDrW0gemhsdWtvbSB6ZHJ1xb51asO6Y2ltIHbDpMSNxaFpbnUga3JhasOtbiwga3RvcsOpIDx1PnByZcWhbGkgZWtvbm9taWNrb3UgdHJhbnNmb3Jtw6FjaW91IGEgdnN0w7pwaWxpIGRvIEXDmjwvdT4gKFBvxL5za28sIE1hxI9hcnNrbywgRXN0w7Nuc2tvLCBMb3R5xaFza28sIExpdHZhLCBTbG92aW5za28sIEJ1bGhhcnNrbywgUnVtdW5za28pLiBIb2NpIHPDuiBtZWR6aSBuaW1pIHJvemRpZWx5IChTbG92aW5za28gamUgbmFqdnlzcGVsZWrFoWllKSwgaWNoIHNvY2nDoWxuby1la29ub21pY2vDqSB1a2F6b3ZhdGVsZSBzw7ogbmEgc3RyZWRuZWogw7pyb3ZuaSwgamFzbmUgb2Rsw63FoWVuw6kgb2Qgc2V2ZXJza8OpaG8gbW9kZWx1IGEgbmFqY2h1ZG9ibmVqxaHDrWNoIGtyYWrDrW4uCgoqKlpobHVrIDMqKiBqZSBjaGFyYWt0ZXJpc3RpY2vDvSB0w71tLCDFvmUgdiDFiG9tIHPDuiBzw7pzdHJlZGVuw6kga3JhamlueSB6IGp1aG92w71jaG9kbmVqIGEgdsO9Y2hvZG5laiBFdXLDs3B5LCBrdG9yw6kgc2EgbmFjaMOhZHphasO6IG5hIDx1PmRvbG5vbSBrb25jaSBla29ub21pY2tlaiB2w71rb25ub3N0aTwvdT4gdiBzw7pib3JlIChDaG9ydsOhdHNrbywgU3Jic2tvLCDEjGllcm5hIEhvcmEsIE1vbGRhdnNrbyBhIFVrcmFqaW5hKS4gVGlldG8ga3JhamlueSBidWTDuiB2IHByb2ZpbG92YW7DrSB6aGx1a292IHZ5a2F6b3ZhxaUgbmFqbmnFvsWhaWUgSERQLCB6ZHJhdsO9IMW+aXZvdCBhIG5hanZ5xaHFoWl1IHZuw61tYW7DuiBrb3J1cGNpdS4KCgojIyBEZXNrcmlwdMOtdm5lIMWhdGF0aXN0aWt5IHbDvXNsZWRrb3YKCioqVGFiLiA1LioqIFZ5c3ZldGxlbmllIHZuw7p0cm9rbGFzdHJvdmVqIHZhcmlhYmlsaXR5IHogaMS+YWRpc2thIGplZG5vdGxpdsO9Y2ggcHJlbWVubsO9Y2gKYGBge3J9CnNzcSA8LSBmdW5jdGlvbih4LCBtKSBzdW0oKHggLSBtKV4yKQoKdmFyX25hbWVzIDwtIGNvbG5hbWVzKHVkYWplX3NjYWxlZCkKClRTUyA8LSBzYXBwbHkodmFyX25hbWVzLCBmdW5jdGlvbih2KSBzc3EodWRhamVfc2NhbGVkWywgdl0sIG1lYW4odWRhamVfc2NhbGVkWywgdl0pKSkKCldTUyA8LSBzYXBwbHkodmFyX25hbWVzLCBmdW5jdGlvbih2KSB7CiAgeCA8LSB1ZGFqZV9zY2FsZWRbLCB2XQogIHRhcHBseSh4LCBrbGFzdGVyX21lbWJlcnNoaXAsIGZ1bmN0aW9uKHopIHNzcSh6LCBtZWFuKHopKSkgfD4gc3VtKCkKfSkKCkJTUyA8LSBUU1MgLSBXU1MKCnNzX3RhYmxlIDwtIGRhdGEuZnJhbWUoCiAgUHJlbWVubmEgPSB2YXJfbmFtZXMsCiAgVFNTID0gVFNTLAogIFdTUyA9IFdTUywKICBCU1MgPSBCU1MsCiAgUHJvcF9CZXR3ZWVuID0gQlNTIC8gVFNTCikKCnNzX3RhYmxlW29yZGVyKC1zc190YWJsZSRQcm9wX0JldHdlZW4pLCBdCmBgYApBbmFsw716YSBtaWVyIHZhcmlhYmlsaXR5IHVrw6F6YWxhLCDFvmUgdnl0dm9yZW7DqSB0cmkgemhsdWt5IHPDuiA8dT52ZcS+bWkgZG9icmUgb2RkZWxlbsOpIGEgaG9tb2fDqW5uZTwvdT4sIHByZXRvxb5lIHbFoWV0a3kgcHJlbWVubsOpIG1hasO6IHZ5c29rw7ogaG9kbm90dSBCU1MvVFNTLiAqKlByaW3DoXJueW1pIGZha3Rvcm1pIG9kbMOtxaFlbmlhKioga3JhasOtbiBzw7ogKip2bsOtbWFuaWUga29ydXBjaWUqKiAoUHJvcF9CZXR3ZWVuIDAuODE5KSBhICoqZWtvbm9taWNrw6Egw7pyb3ZlxYgqKiAoUHJvcF9CZXR3ZWVuIDAuNzc3KSwga3RvcsOpIHZ5c3ZldMS+dWrDuiBuYWp2w6TEjcWhaXUgxI1hc8WlIGNlbGtvdsOpaG8gcm96cHR5bHUuIFByZWt2YXBpdm8gc2lsbsO9bSByb3psacWhb3ZhY8OtbSBmYWt0b3JvbSBqZSBhaiAqKlNvY2nDoWxuYSBwb2Rwb3JhKiogKFByb3BfQmV0d2VlbiAwLjY3OCksIGt0b3LDoSB2IHLDoW1jaSB0cm9jaCB6aGx1a292IHZ5a2F6dWplIHbDvXpuYW1uw6kgcm96ZGllbHksIMSNw61tIHBvdHZyZHp1amUgZXhpc3RlbmNpdSBqYXNuZSBkZWZpbm92YW7DvWNoIHNrdXDDrW4ga3JhasOtbi4KCgpgYGB7cn0KdWRhamVfZm9yX3Byb2ZpbGluZyA8LSBzdWJzZXQodWRhamVfa2xhc3RlcnMsIHNlbGVjdCA9IC1Db3VudHJ5KQoKY2x1c3Rlcl9wcm9maWxlIDwtIGFnZ3JlZ2F0ZSguIH4ga2xhc3RlciwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IHVkYWplX2Zvcl9wcm9maWxpbmcsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZVTiA9IG1lYW4pCgpjbHVzdGVyX3Byb2ZpbGVbLCAtMV0gPC0gcm91bmQoY2x1c3Rlcl9wcm9maWxlWywgLTFdLCAzKQoKY2x1c3Rlcl9wcm9maWxlCmBgYAoqKktsYXN0ZXIgMSoqIHNhIGphc25lIHByb2ZpbHVqZSBha28gc2t1cGluYSBzIG5hanZ5xaHFoW91IGt2YWxpdG91IMW+aXZvdGEuIFZ5a2F6dWplIDx1Pm5hanZ5xaHFoWllIHByaWVtZXJuw6kgaG9kbm90eSB2byB2xaFldGvDvWNoIHBveml0w612bnljaCB1a2F6b3ZhdGXEvm9jaDwvdT4sIHMgSERQIG5hIMO6cm92bmkgMTAuODI2LCBuYWpkbGjFoW91IHpkcmF2b3UgZMS6xb5rb3Ugxb5pdm90YSA3MC43NSByb2thIGEgbmFqdsOkxI3FoW91IG1pZXJvdSBzbG9ib2R5ICgwLjkyNykuIEvEvsO6xI1vdm8gbcOhIGFqIG5ham5pxb7FoWl1IHZuw61tYW7DuiBrb3J1cGNpdSAoMC4zMDEpLCDEjW8gcG9kxI1pYXJrdWplIGplaG8gY2hhcmFrdGVyIGluxaF0aXR1Y2lvbsOhbG5lIHNpbG7DvWNoIGEgYm9oYXTDvWNoIGtyYWrDrW4uCgoqKktsYXN0ZXIgMioqIHByZWRzdGF2dWplIDx1PnByaWVtZXJuw7ogw7pyb3ZlxYg8L3U+IHYgY2Vsb20gc8O6Ym9yZS4gTcOhIHN0cmVkbsOpIGhvZG5vdHkgSERQIG5hIG9ieXZhdGXEvmEgKDEwLjIzNikgYSBtaWVydSBrb3J1cGNpZSAoMC44MzYpLiBUw6F0byBza3VwaW5hIGplIG5hamtvbmNlbnRyb3ZhbmVqxaFpYSBva29sbyBwcmllbWVydSwgxI3DrW0gc2zDusW+aSBha28gc3RyZWRuw70gxI1sw6Fub2sgbWVkemkgZHZvbWEgZXh0csOpbWFtaS4KCioqS2xhc3RlciAzKiogamUgZGVmaW5vdmFuw70gPHU+bmFqbmnFvsWhw61taSBwcmllbWVybsO9bWkgaG9kbm90YW1pIHZvIHbFoWV0a8O9Y2ggcG96aXTDrXZueWNoIHVrYXpvdmF0ZcS+b2NoPC91PiAoSERQIDkuNzA3LCB6ZHJhdsOhIGTEusW+a2Egxb5pdm90YSA2NS42NSByb2thLCBzbG9ib2RhIDAuNjA3KS4gVMOhdG8gc2t1cGluYSB6w6Fyb3ZlxYggdnlrYXp1amUgbmFqdnnFocWhaXUgdm7DrW1hbsO6IG1pZXJ1IGtvcnVwY2llICgwLjg5MSkuIFRlbnRvIHByb2ZpbCBwb3R2cmR6dWplLCDFvmUgS2xhc3RlciAzIHByZWRzdGF2dWplIGtyYWppbnkgcyBuYWpuacW+xaFvdSDDunJvdsWIb3UgYmxhaG9ieXR1IHYgc2xlZG92YW5vbSBzw7pib3JlLgoKKipUYWIuIDYuKiogQ2VudHJvaWR5IC0gcHJpZW1lcm7DqSBob2Rub3R5IHNsZWRvdmFuw71jaCBwcmVtZW5uw71jaApgYGB7cn0KbGlicmFyeShkcGx5cikKCmRlc2NyaXB0aXZlcyA8LSB1ZGFqZV9rbGFzdGVycyAlPiUKICBncm91cF9ieShrbGFzdGVyKSAlPiUKICBzdW1tYXJpc2UoCiAgICBhY3Jvc3MoCiAgICAgIC5jb2xzID0gd2hlcmUoaXMubnVtZXJpYyksCiAgICAgIC5mbnMgPSBsaXN0KAogICAgICAgIG1lYW4gPSB+bWVhbigueCwgbmEucm0gPSBUUlVFKQogICAgICApLAogICAgICAubmFtZXMgPSAiey5jb2x9X21lYW4iCiAgICApCiAgKQoKZGVzY3JpcHRpdmVzIDwtIGRlc2NyaXB0aXZlcyAlPiUgCiAgbXV0YXRlKGFjcm9zcyh3aGVyZShpcy5udW1lcmljKSwgfnJvdW5kKC4sIDMpKSkKCmRlc2NyaXB0aXZlcwpgYGAKKipUYWIuIDYuIChDZW50cm9pZHkpKiogc2zDusW+aSBuYSA8dT5wcm9maWxvdmFuaWUgYSBwb21lbm92YW5pZSB0cm9jaCB2eXR2b3JlbsO9Y2ggemhsdWtvdjwvdT4uICpLbGFzdGVyIDEqIHNhIGphc25lIHByb2ZpbHVqZSBha28gc2t1cGluYSBzIG5hanZ5xaHFoW91IGt2YWxpdG91IMW+aXZvdGEgYSBpbsWhdGl0dWNpb27DoWxub3Ugc2lsb3UsIMSNbyBqZSBkZW1vbsWhdHJvdmFuw6kgbmFqdnnFocWhw61tIEhEUCAoMTAuODI2KSwgbmFqZGxoxaFvdSB6ZHJhdm91IGTEusW+a291IMW+aXZvdGEgKDcwLjc1IHJva2EpIGEgbmFqbmnFvsWhb3Ugdm7DrW1hbm91IGtvcnVwY2lvdSAoMC4zMDEpLiAqS2xhc3RlciAzKiBwcmVkc3RhdnVqZSBuYWpuacW+xaFpdSDDunJvdmXFiCBibGFob2J5dHUsIHByZXRvxb5lIHZvIHbFoWV0a8O9Y2ggdWthem92YXRlxL5vY2ggbcOhIG5ham5pxb7FoWllIHByaWVtZXJ5IChIRFAgOS43MDcpIGEgesOhcm92ZcWIIG5hanZ5xaHFoWl1IGtvcnVwY2l1ICgwLjg5MSkuICpLbGFzdGVyIDIqIHR2b3LDrSBzdHJlZG7DuiwgcHJlY2hvZG7DuiBza3VwaW51LCBrdG9yw6EgamUga29uY2VudHJvdmFuw6Egb2tvbG8gcHJpZW1lcnUgY2Vsw6lobyBzw7pib3J1LgoKCiMjIFrDoXZlcgpQcmVkbG/FvmVuw6EgYW5hbMO9emEgc2EgemFvYmVyYWxhIGtsYXNpZmlrw6FjaW91IHZ5YnJhbsO9Y2gga3JhasOtbiBzdHJlZG5laiwgdsO9Y2hvZG5laiBhIHNldmVybmVqIEV1csOzcHkgbmEgesOha2xhZGUgKnBpYXRpY2gga8S+w7rEjW92w71jaCBzb2Npw6Fsbm8tZWtvbm9taWNrw71jaCBhIGluxaF0aXR1Y2lvbsOhbG55Y2ggdWthem92YXRlxL5vdiogeiBkYXRhYsOhenkgV29ybGQgSGFwcGluZXNzIFJlcG9ydCB6YSByb2sgMjAxNS4gQ2llxL5vbSBib2xvIDx1PmlkZW50aWZpa292YcWlIGhvbW9nw6lubmUgc2t1cGlueSAoemhsdWt5KSBzIHBvZG9ibsO9bSBwcm9maWxvbSBibGFob2J5dHU8L3U+LgoKSGllcmFyY2hpY2vDoSB6aGx1a292w6EgYW5hbMO9emEgcyBXYXJkb3ZvdSBtZXTDs2RvdSDDunNwZcWhbmUgcm96ZGVsaWxhIGtyYWppbnkgZG8gPHU+dHJvY2ggamFzbmUgZGVmaW5vdmFuw71jaCB6aGx1a292PC91Pi4gUHJvZmlsb3ZhbmllIHpobHVrb3YgcG90dnJkaWxvLCDFvmUgdMOhdG8ga2xhc2lmaWvDoWNpYSA8dT5kbyB6bmHEjW5laiBtaWVyeSBrb3JlxaFwb25kdWplIHMgaWNoIHN0dXDFiG9tIGVrb25vbWlja8OpaG8gcm96dm9qYSwgaGlzdMOzcmllIGEgZ2VvZ3JhZmlja2VqIGJsw616a29zdGk8L3U+OgoKKiAqKlpobHVrIDEgKE5vcmRpYy9WeXNva8O9IEJsYWhvYnl0KSoqOiBLcmFqaW55IHMgbmFqdnnFocWhw61tIEhEUCwgemRyYXbDvW0gxb5pdm90b20gYSBuYWpuacW+xaFvdSBtaWVyb3Ugdm7DrW1hbmVqIGtvcnVwY2llLgoKKiAqKlpobHVrIDIgKFN0cmVkbsOhIMOacm92ZcWIKSoqOiBLcmFqaW55IHN0cmVkbmVqIGEgc2V2ZXJuZWogRXVyw7NweSwga3RvcsOpIHR2b3JpYSBzdHJlZG7DvSDEjWzDoW5vay4KCiogKipaaGx1ayAzIChOw616a3kgQmxhaG9ieXQpKio6IEtyYWppbnksIGt0b3LDqSB2eWthenVqw7ogbmFqbmnFvsWhaWUgSERQIGEgbmFqdnnFocWhaXUgbWllcnUgdm7DrW1hbmVqIGtvcnVwY2llLgoKQW5hbMO9emEgbWllciB2YXJpYWJpbGl0eSAoQlNTL1RTUykgesOhcm92ZcWIIHByZXVrw6F6YWxhLCDFvmUgPHU+dm7DrW1hbmllIGtvcnVwY2llIGEgTG9nLkdEUC5wZXIuY2FwaXRhIHPDuiBwcmltw6FybnltaSBmYWt0b3JtaSBvZGxpxaF1asO6Y2ltaSB0aWV0byBza3VwaW55PC91Pi4KClV2ZWRlbsOpIHbDvXNsZWRreSBwb3NreXR1asO6IGNlbm7DvSBwb2RrbGFkIHByZSBtZWR6aW7DoXJvZG7DqSBpbsWhdGl0w7pjaWUsIGFrbyBqZSBFdXLDs3Bza2Ega29taXNpYSwgdW1vxb7FiHVqw7pjIGNpZWxlbmVqxaFpdSBhbG9rw6FjaXUgemRyb2pvdiBhIHZ5cGlzb3ZhbmllIHByb2Jsw6ltb3ZvIHphbWVyYW7DvWNoIHByb2pla3RvdsO9Y2ggdsO9emlldiAobmFwci4gbmEgemxlcMWhZW5pZSBpbsWhdGl0dWNpb27DoWxuZWoga3ZhbGl0eSBhbGVibyBzb2Npw6FsbmVqIHBvZHBvcnkpIHBvZMS+YSBwcsOtc2x1xaFub3N0aSDFoXTDoXRvdiBrdSBrbGFzdGVyb20u