#1.IPriprava dát a regresia

priprava dát z cvičenia 7.

# Import vlastného CSV súboru

udaje <- read.csv("Employment_Unemployment_GDP_data.csv",
header = TRUE,
sep = ",",
dec = ".",
stringsAsFactors = FALSE)

# Zobrazenie prvých riadkov a názvov stĺpcov

head(udaje)
colnames(udaje)
[1] "Country.Name"                   "Year"                          
[3] "Employment.Sector..Agriculture" "Employment.Sector..Industry"   
[5] "Employment.Sector..Services"    "Unemployment.Rate"             
[7] "GDP..in.USD."                  
#######################################################################
# PRIPRAVA UDAJOV
#######################################################################
udaje <- read.csv("Employment_Unemployment_GDP_data.csv",dec=".",sep=",",header = TRUE)
# select just the record from 2003
udaje.2003 <- udaje[udaje$Year==2003,c("Unemployment.Rate","Employment.Sector..Agriculture","GDP..in.USD.", "Employment.Sector..Industry","Employment.Sector..Services" )]

# data imputation

# Compute column medians
#column_medians <- sapply(udaje.2003, median, na.rm = TRUE)

# Impute missing values with column medians
# Compute column medians
column_medians <- sapply(udaje.2003, median, na.rm = TRUE)

# Impute missing values with column medians
udaje_imputed <- udaje.2003
for (col in names(udaje.2003)) {
  udaje_imputed[[col]][is.na(udaje_imputed[[col]])] <- column_medians[col]
}

udaje.2003 <- udaje_imputed
udaje <- udaje.2003

################################################################################
# ZAKLADNA REGRESIA
################################################################################
attach(udaje)
model <- lm(Unemployment.Rate ~ 
              Employment.Sector..Agriculture +
              Employment.Sector..Industry +
              Employment.Sector..Services +
              GDP..in.USD.,
            data = udaje)
summary(model)

Call:
lm(formula = Unemployment.Rate ~ Employment.Sector..Agriculture + 
    Employment.Sector..Industry + Employment.Sector..Services + 
    GDP..in.USD., data = udaje)

Residuals:
    Min      1Q  Median      3Q     Max 
-11.426  -4.399  -1.240   2.583  25.949 

Coefficients:
                                 Estimate Std. Error t value Pr(>|t|)  
(Intercept)                     8.812e+04  1.580e+05   0.558   0.5777  
Employment.Sector..Agriculture -8.812e+02  1.580e+03  -0.558   0.5777  
Employment.Sector..Industry    -8.811e+02  1.580e+03  -0.558   0.5778  
Employment.Sector..Services    -8.812e+02  1.580e+03  -0.558   0.5777  
GDP..in.USD.                   -8.262e-13  4.844e-13  -1.706   0.0898 .
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 6.16 on 177 degrees of freedom
Multiple R-squared:  0.09631,   Adjusted R-squared:  0.07589 
F-statistic: 4.716 on 4 and 177 DF,  p-value: 0.00122

Interpretácia

Tento model skúma, či sa dá miera nezamestnanosti vysvetliť pomocou štruktúry zamestnanosti (poľnohospodárstvo, priemysel, služby) a HDP na obyvateľa.

Z výsledkov vidím toto:

  • všetky tri sektorové premenné (Agriculture, Industry, Services) majú takmer rovnaké koeficienty a všetky sú nevýznamné (p-hodnoty okolo 0.58),
  • premenná GDP je len tesne na hranici významnosti (p ≈ 0.09),
  • celková vysvetľovacia schopnosť modelu je nízka (Adjusted R² ≈ 0.076),

2. Korelačná matica

V tejto časti skúmame, či medzi našimi vysvetľujúcimi premennými existuje silná korelácia.
Ak by niektoré premenné mali veľmi vysokú koreláciu (napr. nad 0.8–0.9), znamenalo by to riziko multikolinearity — teda že do modelu dávam premenné, ktoré sú si príliš podobné.

#######################################################################
# 5. KORELAČNÁ MATICA
#######################################################################

xvars <- udaje[, c("Employment.Sector..Agriculture",
                   "Employment.Sector..Industry",
                   "Employment.Sector..Services",
                   "GDP..in.USD.")]

round(cor(xvars), 3)
                               Employment.Sector..Agriculture
Employment.Sector..Agriculture                          1.000
Employment.Sector..Industry                            -0.766
Employment.Sector..Services                            -0.957
GDP..in.USD.                                           -0.194
                               Employment.Sector..Industry
Employment.Sector..Agriculture                      -0.766
Employment.Sector..Industry                          1.000
Employment.Sector..Services                          0.547
GDP..in.USD.                                         0.140
                               Employment.Sector..Services GDP..in.USD.
Employment.Sector..Agriculture                      -0.957       -0.194
Employment.Sector..Industry                          0.547        0.140
Employment.Sector..Services                          1.000        0.189
GDP..in.USD.                                         0.189        1.000

Interpretácia korelačnej matice

Z korelačnej matice vidím viacero silných vzťahov medzi premennými. Najvýraznejšia je korelácia medzi:

  • Agriculture a Services, kde korelácia je –0.957 → to je extrémne vysoká negatívna korelácia.
  • Agriculture a Industry majú koreláciu –0.766, čo je tiež pomerne silný vzťah.

To znamená, že tieto sektorové premenné sú medzi sebou veľmi podobné (ak stúpne jedna, druhé výrazne klesnú).

HDP (GDP..in.USD.) má s ostatnými premennými len slabé korelácie (okolo ±0.19). Takže podľa korelačnej matice sa multikolinearita prejavuje hlavne medzi tromi sektorovými premennými, ktoré sú navzájom veľmi silno previazané.

##Scatterplotova matica

pairs(xvars,
      main = "Scatterplotová matica – sektorové premenné a GDP")

Scatterplotová matica pekne potvrdzuje to, čo sme videli už v korelačnej matici:

  • medzi Agriculture a Services je veľmi silný negatívny vzťah – čím viac ľudí pracuje v poľnohospodárstve, tým menej ich pracuje v službách. Body tvoria takmer dokonalú klesajúcu priamku.
  • podobne, Agriculture a Industry tiež silne klesajú – tieto dve premenné sú tiež navzájom prepojené.
  • vzťahy medzi sektormi sú spôsobené tým, že všetky sektory spolu tvoria 100 % zamestnanosti, takže keď jeden sektor rastie, iné musia klesať.
  • GDP je na grafoch prakticky „bez vzoru“, body sú rozhádzané → GDP nie je so sektormi silno prepojené a nespôsobuje multikolinearitu.

Z toho vyplýva, že Scatterplotová matica potvrdila, že multikolinearita vzniká najmä medzi tromi sektorovými premennými, nie medzi GDP a sektormi.

3. VIF – Variance Inflation Factor

VIF používame na to, aby sme zistili, ktorá premenná spôsobuje multikolinearitu.
Platí jednoduché pravidlo:

  • VIF okolo 1–2 → žiadny problém
  • VIF > 5 → začínajúci problém
  • VIF > 10 → vážna multikolinearita
#######################################################################
# 6. VIF
#######################################################################

library(car)
vif(model)
Employment.Sector..Agriculture    Employment.Sector..Industry 
                  7.256425e+09                   8.674182e+08 
   Employment.Sector..Services                   GDP..in.USD. 
                  4.280920e+09                   1.039469e+00 

Interpretácia VIF

Hodnoty VIF v mojom modeli sú obrovské pri sektorových premenných (Agriculture, Industry, Services). Keď jeden sektor stúpa, ostatné musia klesať, takže sú prakticky naviazané jedna na druhú, čo je jasný znak veľmi silnej multikolinearity.

Takže to znamená, že tieto tri premenné sú pre model „takmer to isté“, len v inom poradía spôsobujú chaos v koeficientoch, model ich nevie spoľahlivo odlíšiť.

Premenná GDP takýto problém nemá (VIF ≈ 1), takže multikolinearitu spôsobujú výhradne sektorové premenné.

4. Condition Number

Condition Number je ďalší ukazovateľ, ktorý sa používa na zistenie multikolinearity.

Intuitívne pravidlo:

  • < 10 → žiadny problém
  • 10–30 → mierna multikolinearita
  • 30–100 → silná
  • 100 → veľmi vážna multikolinearita


# 4. CONDITION NUMBER

X <- model.matrix(model)[, -1]
XtX <- t(X) %*% X
eig <- eigen(XtX)

condition_number <- sqrt(max(eig$values) / min(eig$values))
condition_number
[1] NaN

Interpretácia Condition Number

Pri výpočte Condition Number sa mi zobrazila hodnota NaN.
To sa stáva v situácii, keď je matica vysvetľujúcich premenných takmer singulárna, teda jedna premenná sa dá skoro úplne presne vyjadriť pomocou iných premenných. V mojom prípade je to dôsledok toho, že sektorové premenné (Agriculture, Industry, Services) spolu tvoria 100 % zamestnanosti.

To znamená, že medzi nimi existuje extrémne silná lineárna závislosť a Condition Number sa nedá normálne vypočítať. Tento výsledok je ešte silnejším dôkazom multikolinearity než vysoké hodnoty VIF.

5. Riešenia multikolinearity

Vynechanie premennej Agroculture

model_noAgri <- lm(Unemployment.Rate ~ 
                     Employment.Sector..Industry +
                     Employment.Sector..Services +
                     GDP..in.USD.,
                   data = udaje)

summary(model_noAgri)

Call:
lm(formula = Unemployment.Rate ~ Employment.Sector..Industry + 
    Employment.Sector..Services + GDP..in.USD., data = udaje)

Residuals:
    Min      1Q  Median      3Q     Max 
-11.448  -4.385  -1.239   2.587  25.914 

Coefficients:
                              Estimate Std. Error t value Pr(>|t|)  
(Intercept)                  3.551e+00  1.375e+00   2.583   0.0106 *
Employment.Sector..Industry  1.472e-01  6.402e-02   2.299   0.0226 *
Employment.Sector..Services  5.079e-02  2.906e-02   1.748   0.0822 .
GDP..in.USD.                -8.216e-13  4.834e-13  -1.700   0.0909 .
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 6.148 on 178 degrees of freedom
Multiple R-squared:  0.09472,   Adjusted R-squared:  0.07946 
F-statistic: 6.208 on 3 and 178 DF,  p-value: 0.0004924

Model bez premennej Agriculture – interpretácia

Keď sme z modelu vynechali premennú Agriculture, výsledky sa zlepšili:

  • premenná Industry je teraz štatisticky významná (p ≈ 0.02),
  • premenná Services je tesne pod hranicou významnosti (p ≈ 0.08),
  • premenná GDP je stále na hranici významnosti (p ≈ 0.09).

Upravený R² je síce stále nízky (≈ 0.079), ale model je už stabilnejší než pôvodný.

Z toho vyplýva, že vynechanie Agriculture pomohlo, pretože táto premenná spôsobovala najviac multikolinearity so zvyšnými dvoma sektorovými premennými (bola extrémne silne korelovaná so Services a Industry).

Tento model je preto o niečo lepší než pôvodný model so všetkými premennými.

Vynechanie premennej Indusry

model_noIndustry <- lm(Unemployment.Rate ~ 
                         Employment.Sector..Agriculture +
                         Employment.Sector..Services +
                         GDP..in.USD.,
                       data = udaje)

summary(model_noIndustry)

Call:
lm(formula = Unemployment.Rate ~ Employment.Sector..Agriculture + 
    Employment.Sector..Services + GDP..in.USD., data = udaje)

Residuals:
    Min      1Q  Median      3Q     Max 
-11.448  -4.385  -1.239   2.587  25.914 

Coefficients:
                                 Estimate Std. Error t value Pr(>|t|)   
(Intercept)                     1.827e+01  6.082e+00   3.004  0.00305 **
Employment.Sector..Agriculture -1.472e-01  6.402e-02  -2.299  0.02264 * 
Employment.Sector..Services    -9.641e-02  8.327e-02  -1.158  0.24848   
GDP..in.USD.                   -8.216e-13  4.834e-13  -1.700  0.09095 . 
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 6.148 on 178 degrees of freedom
Multiple R-squared:  0.09472,   Adjusted R-squared:  0.07946 
F-statistic: 6.208 on 3 and 178 DF,  p-value: 0.0004923

Model bez premennej Industry – interpretácia

Keď sme z modelu vynechali premennú Industry, významnosť sa obrátila:

  • premenná Agriculture je teraz štatisticky významná (p ≈ 0.022),
  • premenná Services nie je významná (p ≈ 0.25),
  • premenná GDP je opäť na hranici (p ≈ 0.09).

Hodnota R² sa nezmenila (je rovnaká ako v modeli bez Agriculture), čo znamená, že vysvetľovacia schopnosť modelu je rovnaká.

Tento model je však horší než model bez Agriculture, pretože v ňom ostáva len jedna významná premenná (Agriculture), zatiaľ čo model bez Agriculture mal významný Industry a skoro významný Services.

Takže vynechanie Industry neprinieslo také zlepšenie ako vynechanie Agriculture.

Vynechanie premennej Services

model_noServices <- lm(Unemployment.Rate ~ 
                         Employment.Sector..Agriculture +
                         Employment.Sector..Industry +
                         GDP..in.USD.,
                       data = udaje)

summary(model_noServices)

Call:
lm(formula = Unemployment.Rate ~ Employment.Sector..Agriculture + 
    Employment.Sector..Industry + GDP..in.USD., data = udaje)

Residuals:
    Min      1Q  Median      3Q     Max 
-11.448  -4.385  -1.239   2.587  25.914 

Coefficients:
                                 Estimate Std. Error t value Pr(>|t|)    
(Intercept)                     8.630e+00  2.415e+00   3.574 0.000452 ***
Employment.Sector..Agriculture -5.079e-02  2.906e-02  -1.748 0.082183 .  
Employment.Sector..Industry     9.641e-02  8.327e-02   1.158 0.248489    
GDP..in.USD.                   -8.216e-13  4.834e-13  -1.700 0.090946 .  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 6.148 on 178 degrees of freedom
Multiple R-squared:  0.09472,   Adjusted R-squared:  0.07946 
F-statistic: 6.208 on 3 and 178 DF,  p-value: 0.0004924

Model bez premennej Services – interpretácia

Keď sme z modelu vynechali premennú Services, výsledok je podobný ako v predošlom modeli:

  • premenná Agriculture je len na hranici významnosti (p ≈ 0.082),
  • premenná Industry nie je významná (p ≈ 0.25),
  • premenná GDP je stále len tesne nevýznamná (p ≈ 0.09).

R² je opäť rovnaké ako v predchádzajúcich dvoch prípadoch.

Tento model je najslabší zo všetkých troch, pretože nemá žiadnu jasne významnú premennú a koeficienty sú ešte menej stabilné.

Ktorú premennú je najlepšie vynechať?

Porovnali sme všetky tri modely, kde sme vždy jednu premennú vynechala.
Najlepší výsledok vyšiel teda pri modeli bez Agriculture, pretože:

  • Industry sa stal významným,
  • Services bol aspoň na hranici významnosti,
  • model vyzeral najstabilnejšie,
  • a číselne dával najrozumnejšie koeficienty.

Model bez Industry a model bez Services boli horšie – vždy zostala iba jedna významná premenná alebo žiadna.

5.2 Škálovanie premenných (centrovanie)

# 8.2 ŠKÁLOVANIE PREMENNÝCH

udaje$Agri_c     <- scale(udaje$Employment.Sector..Agriculture, center=TRUE, scale=TRUE)
udaje$Industry_c <- scale(udaje$Employment.Sector..Industry, center=TRUE, scale=TRUE)
udaje$Services_c <- scale(udaje$Employment.Sector..Services, center=TRUE, scale=TRUE)
udaje$GDP_c      <- scale(udaje$GDP..in.USD., center=TRUE, scale=TRUE)

model_centered <- lm(Unemployment.Rate ~ Agri_c + Industry_c + Services_c + GDP_c,
                     data = udaje)

summary(model_centered)

Call:
lm(formula = Unemployment.Rate ~ Agri_c + Industry_c + Services_c + 
    GDP_c, data = udaje)

Residuals:
    Min      1Q  Median      3Q     Max 
-11.426  -4.399  -1.240   2.583  25.949 

Coefficients:
              Estimate Std. Error t value Pr(>|t|)    
(Intercept)  8.774e+00  4.566e-01  19.215   <2e-16 ***
Agri_c      -2.176e+04  3.901e+04  -0.558   0.5777    
Industry_c  -7.521e+03  1.349e+04  -0.558   0.5778    
Services_c  -1.671e+04  2.996e+04  -0.558   0.5777    
GDP_c       -7.962e-01  4.668e-01  -1.706   0.0898 .  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 6.16 on 177 degrees of freedom
Multiple R-squared:  0.09631,   Adjusted R-squared:  0.07589 
F-statistic: 4.716 on 4 and 177 DF,  p-value: 0.00122

Interpretácia škálovaného modelu

Po preškálovaní premenných sa model síce vypočítal stabilnejšie, ale správanie koeficientov sa prakticky nezmenilo.
Výsledky sú takmer totožné ako v pôvodnom modeli:

  • žiadna sektorová premenná (Agri_c, Industry_c, Services_c) nie je štatisticky významná,
  • GDP_c je opäť len tesne na hranici významnosti (p ≈ 0.09),
  • upravený R² je rovnaký ako pred škálovaním (≈ 0.076).

Škálovanie teda neodstránilo multikolinearitu medzi sektorovými premennými, iba stabilizovalo výpočty.
Problém zostáva, pretože tri sektory sú stále naviazané (tvoria spolu takmer 100 % zamestnanosti), takže model ich nedokáže od seba oddeliť ani po škálovaní.

5.3 Úprava jednotiek (GDP/1000)


# ÚPRAVA JEDNOTIEK – GDP / 1000


udaje$GDP1000 <- udaje$GDP..in.USD. / 1000

model_GDP1000 <- lm(Unemployment.Rate ~
                      Employment.Sector..Agriculture +
                      Employment.Sector..Industry +
                      Employment.Sector..Services +
                      GDP1000,
                    data = udaje)

summary(model_GDP1000)

Call:
lm(formula = Unemployment.Rate ~ Employment.Sector..Agriculture + 
    Employment.Sector..Industry + Employment.Sector..Services + 
    GDP1000, data = udaje)

Residuals:
    Min      1Q  Median      3Q     Max 
-11.426  -4.399  -1.240   2.583  25.949 

Coefficients:
                                 Estimate Std. Error t value Pr(>|t|)  
(Intercept)                     8.812e+04  1.580e+05   0.558   0.5777  
Employment.Sector..Agriculture -8.812e+02  1.580e+03  -0.558   0.5777  
Employment.Sector..Industry    -8.811e+02  1.580e+03  -0.558   0.5778  
Employment.Sector..Services    -8.812e+02  1.580e+03  -0.558   0.5777  
GDP1000                        -8.262e-10  4.844e-10  -1.706   0.0898 .
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 6.16 on 177 degrees of freedom
Multiple R-squared:  0.09631,   Adjusted R-squared:  0.07589 
F-statistic: 4.716 on 4 and 177 DF,  p-value: 0.00122
vif(model_GDP1000)
Employment.Sector..Agriculture    Employment.Sector..Industry 
                  7.256425e+09                   8.674182e+08 
   Employment.Sector..Services                        GDP1000 
                  4.280920e+09                   1.039469e+00 

Model s premenou GDP na tisíce dolárov – interpretácia

Po prepočítaní GDP na tisíce dolárov sa samotný model takmer vôbec nezmenil.
Koeficienty pri sektorových premenných aj pri GDP1000 majú rovnaké p-hodnoty ako predtým, čo znamená, že úprava jednotiek:

  • nezmenila významnosť premenných,
  • nezlepšila schopnosť modelu vysvetľovať nezamestnanosť,
  • a multikolinearita zostala rovnako silná.

R² aj chyby zostali identické ako v pôvodnom modeli.

VIF hodnoty hovoria úplne jasne: - sektorové premenné majú opäť extrémne vysoké VIF (rády miliárd), - GDP1000 má normálny VIF ≈ 1. :
Úprava GDP na „tisíce dolárov“ síce zlepšila čitateľnosť koeficientu GDP, ale neodstránila multikolinearitu, pretože tú spôsobujú sektorové premenné, nie GDP.

#Zhrnutie V tejto úlohe som skúmala multikolinearitu v regresnom modeli, kde vysvetľujem mieru nezamestnanosti pomocou podielu zamestnanosti v jednotlivých sektoroch a HDP na obyvateľa. Už základný model naznačoval problém: koeficienty sektorových premenných boli nevýznamné a mali takmer rovnaké hodnoty.

Korelácie medzi premennými ukázali veľmi silnú väzbu hlavne medzi tromi sektorovými premennými (Agriculture, Industry, Services). Najsilnejšia bola korelácia Agriculture–Services (–0.957). Je to logické, pretože tieto tri premenné spolu tvoria takmer 100 % zamestnanosti, ta

LS0tCnRpdGxlOiAiUHLDoWNhIHMgZGF0YWLDoXpvdSAtIGltcG9ydCDDumRham92LCBncmFmeSwgxaF0YXRpc3Rpa3kiCmF1dGhvcjogIkzDrXZpYSBNZWxpY2hvdsOhIgpkYXRlOiAiRGVjZW1iZXIgMjAyNSIKb3V0cHV0OiAKICBodG1sX25vdGVib29rOgogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIHRoZW1lOiB1bml0ZWQKICAgIGhpZ2hsaWdodDogdGFuZ28KZWRpdG9yX29wdGlvbnM6IAogIG1hcmtkb3duOiAKICAgIHdyYXA6IDcyCi0tLQoKIzEuSVByaXByYXZhIGTDoXQgYSByZWdyZXNpYSAKCnByaXByYXZhIGTDoXQgeiBjdmnEjWVuaWEgNy4gCgpgYGB7cn0KIyBJbXBvcnQgdmxhc3Ruw6lobyBDU1Ygc8O6Ym9ydQoKdWRhamUgPC0gcmVhZC5jc3YoIkVtcGxveW1lbnRfVW5lbXBsb3ltZW50X0dEUF9kYXRhLmNzdiIsCmhlYWRlciA9IFRSVUUsCnNlcCA9ICIsIiwKZGVjID0gIi4iLApzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpCgojIFpvYnJhemVuaWUgcHJ2w71jaCByaWFka292IGEgbsOhenZvdiBzdMS6cGNvdgoKaGVhZCh1ZGFqZSkKY29sbmFtZXModWRhamUpCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMgUFJJUFJBVkEgVURBSk9WCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCnVkYWplIDwtIHJlYWQuY3N2KCJFbXBsb3ltZW50X1VuZW1wbG95bWVudF9HRFBfZGF0YS5jc3YiLGRlYz0iLiIsc2VwPSIsIixoZWFkZXIgPSBUUlVFKQojIHNlbGVjdCBqdXN0IHRoZSByZWNvcmQgZnJvbSAyMDAzCnVkYWplLjIwMDMgPC0gdWRhamVbdWRhamUkWWVhcj09MjAwMyxjKCJVbmVtcGxveW1lbnQuUmF0ZSIsIkVtcGxveW1lbnQuU2VjdG9yLi5BZ3JpY3VsdHVyZSIsIkdEUC4uaW4uVVNELiIsICJFbXBsb3ltZW50LlNlY3Rvci4uSW5kdXN0cnkiLCJFbXBsb3ltZW50LlNlY3Rvci4uU2VydmljZXMiICldCgojIGRhdGEgaW1wdXRhdGlvbgoKIyBDb21wdXRlIGNvbHVtbiBtZWRpYW5zCiNjb2x1bW5fbWVkaWFucyA8LSBzYXBwbHkodWRhamUuMjAwMywgbWVkaWFuLCBuYS5ybSA9IFRSVUUpCgojIEltcHV0ZSBtaXNzaW5nIHZhbHVlcyB3aXRoIGNvbHVtbiBtZWRpYW5zCiMgQ29tcHV0ZSBjb2x1bW4gbWVkaWFucwpjb2x1bW5fbWVkaWFucyA8LSBzYXBwbHkodWRhamUuMjAwMywgbWVkaWFuLCBuYS5ybSA9IFRSVUUpCgojIEltcHV0ZSBtaXNzaW5nIHZhbHVlcyB3aXRoIGNvbHVtbiBtZWRpYW5zCnVkYWplX2ltcHV0ZWQgPC0gdWRhamUuMjAwMwpmb3IgKGNvbCBpbiBuYW1lcyh1ZGFqZS4yMDAzKSkgewogIHVkYWplX2ltcHV0ZWRbW2NvbF1dW2lzLm5hKHVkYWplX2ltcHV0ZWRbW2NvbF1dKV0gPC0gY29sdW1uX21lZGlhbnNbY29sXQp9Cgp1ZGFqZS4yMDAzIDwtIHVkYWplX2ltcHV0ZWQKdWRhamUgPC0gdWRhamUuMjAwMwoKIyBaQUtMQUROQSBSRUdSRVNJQQoKYXR0YWNoKHVkYWplKQptb2RlbCA8LSBsbShVbmVtcGxveW1lbnQuUmF0ZSB+IAogICAgICAgICAgICAgIEVtcGxveW1lbnQuU2VjdG9yLi5BZ3JpY3VsdHVyZSArCiAgICAgICAgICAgICAgRW1wbG95bWVudC5TZWN0b3IuLkluZHVzdHJ5ICsKICAgICAgICAgICAgICBFbXBsb3ltZW50LlNlY3Rvci4uU2VydmljZXMgKwogICAgICAgICAgICAgIEdEUC4uaW4uVVNELiwKICAgICAgICAgICAgZGF0YSA9IHVkYWplKQpzdW1tYXJ5KG1vZGVsKQoKYGBgCiMjIyBJbnRlcnByZXTDoWNpYQoKVGVudG8gbW9kZWwgc2vDum1hLCDEjWkgc2EgZMOhIG1pZXJhIG5lemFtZXN0bmFub3N0aSB2eXN2ZXRsacWlIHBvbW9jb3UgxaF0cnVrdMO6cnkgemFtZXN0bmFub3N0aSAocG/Evm5vaG9zcG9kw6Fyc3R2bywgcHJpZW15c2VsLCBzbHXFvmJ5KSBhIEhEUCBuYSBvYnl2YXRlxL5hLgoKWiB2w71zbGVka292IHZpZMOtbSB0b3RvOgoKLSB2xaFldGt5IHRyaSBzZWt0b3JvdsOpIHByZW1lbm7DqSAoQWdyaWN1bHR1cmUsIEluZHVzdHJ5LCBTZXJ2aWNlcykgbWFqw7ogKip0YWttZXIgcm92bmFrw6kga29lZmljaWVudHkqKiBhIHbFoWV0a3kgc8O6ICoqbmV2w716bmFtbsOpKiogKHAtaG9kbm90eSBva29sbyAwLjU4KSwKLSBwcmVtZW5uw6EgKipHRFAqKiBqZSBsZW4gdGVzbmUgbmEgaHJhbmljaSB2w716bmFtbm9zdGkgKHAg4omIIDAuMDkpLAotIGNlbGtvdsOhIHZ5c3ZldMS+b3ZhY2lhIHNjaG9wbm9zxaUgbW9kZWx1IGplICoqbsOtemthKiogKEFkanVzdGVkIFLCsiDiiYggMC4wNzYpLAoKIyAyLiBLb3JlbGHEjW7DoSBtYXRpY2EKClYgdGVqdG8gxI1hc3RpIHNrw7ptYW1lLCDEjWkgbWVkemkgbmHFoWltaSB2eXN2ZXTEvnVqw7pjaW1pIHByZW1lbm7DvW1pIGV4aXN0dWplIHNpbG7DoSBrb3JlbMOhY2lhLiAgCkFrIGJ5IG5pZWt0b3LDqSBwcmVtZW5uw6kgbWFsaSB2ZcS+bWkgdnlzb2vDuiBrb3JlbMOhY2l1IChuYXByLiBuYWQgMC444oCTMC45KSwgem5hbWVuYWxvIGJ5IHRvIHJpemlrbyBtdWx0aWtvbGluZWFyaXR5IOKAlCB0ZWRhIMW+ZSBkbyBtb2RlbHUgZMOhdmFtIHByZW1lbm7DqSwga3RvcsOpIHPDuiBzaSBwcsOtbGnFoSBwb2RvYm7DqS4KCmBgYHtyfQoKIyAyLiBLT1JFTEHEjE7DgSBNQVRJQ0EKCgp4dmFycyA8LSB1ZGFqZVssIGMoIkVtcGxveW1lbnQuU2VjdG9yLi5BZ3JpY3VsdHVyZSIsCiAgICAgICAgICAgICAgICAgICAiRW1wbG95bWVudC5TZWN0b3IuLkluZHVzdHJ5IiwKICAgICAgICAgICAgICAgICAgICJFbXBsb3ltZW50LlNlY3Rvci4uU2VydmljZXMiLAogICAgICAgICAgICAgICAgICAgIkdEUC4uaW4uVVNELiIpXQoKcm91bmQoY29yKHh2YXJzKSwgMykKCmBgYAojIyMgSW50ZXJwcmV0w6FjaWEga29yZWxhxI1uZWogbWF0aWNlCgpaIGtvcmVsYcSNbmVqIG1hdGljZSB2aWTDrW0gdmlhY2VybyBzaWxuw71jaCB2esWlYWhvdiBtZWR6aSBwcmVtZW5uw71taS4gTmFqdsO9cmF6bmVqxaFpYSBqZSBrb3JlbMOhY2lhIG1lZHppOgoKLSAqKkFncmljdWx0dXJlIGEgU2VydmljZXMqKiwga2RlIGtvcmVsw6FjaWEgamUgKirigJMwLjk1NyoqIOKGkiB0byBqZSBleHRyw6ltbmUgdnlzb2vDoSBuZWdhdMOtdm5hIGtvcmVsw6FjaWEuCi0gKipBZ3JpY3VsdHVyZSBhIEluZHVzdHJ5KiogbWFqw7oga29yZWzDoWNpdSAqKuKAkzAuNzY2KiosIMSNbyBqZSB0aWXFviBwb21lcm5lIHNpbG7DvSB2esWlYWguCgpUbyB6bmFtZW7DoSwgxb5lIHRpZXRvIHNla3Rvcm92w6kgcHJlbWVubsOpIHPDuiBtZWR6aSBzZWJvdSB2ZcS+bWkgcG9kb2Juw6kgKGFrIHN0w7pwbmUgamVkbmEsIGRydWjDqSB2w71yYXpuZSBrbGVzbsO6KS4gIAoKCkhEUCAoR0RQLi5pbi5VU0QuKSBtw6EgcyBvc3RhdG7DvW1pIHByZW1lbm7DvW1pIGxlbiBzbGFiw6kga29yZWzDoWNpZSAob2tvbG8gwrEwLjE5KS4KVGFrxb5lIHBvZMS+YSBrb3JlbGHEjW5laiBtYXRpY2Ugc2EgbXVsdGlrb2xpbmVhcml0YSBwcmVqYXZ1amUgaGxhdm5lIG1lZHppIHRyb21pIHNla3Rvcm92w71taSBwcmVtZW5uw71taSwga3RvcsOpIHPDuiBuYXZ6w6Fqb20gdmXEvm1pIHNpbG5vIHByZXZpYXphbsOpLgoKIyNTY2F0dGVycGxvdG92YSBtYXRpY2EKCmBgYHtyfQpwYWlycyh4dmFycywKICAgICAgbWFpbiA9ICJTY2F0dGVycGxvdG92w6EgbWF0aWNhIOKAkyBzZWt0b3JvdsOpIHByZW1lbm7DqSBhIEdEUCIpCgpgYGAKClNjYXR0ZXJwbG90b3bDoSBtYXRpY2EgcGVrbmUgcG90dnJkenVqZSB0bywgxI1vIHNtZSB2aWRlbGkgdcW+IHYga29yZWxhxI1uZWogbWF0aWNpOgoKLSBtZWR6aSAqKkFncmljdWx0dXJlIGEgU2VydmljZXMqKiBqZSB2ZcS+bWkgc2lsbsO9IG5lZ2F0w612bnkgdnrFpWFoIOKAkyDEjcOtbSB2aWFjIMS+dWTDrSBwcmFjdWplIHYgcG/Evm5vaG9zcG9kw6Fyc3R2ZSwgdMO9bSBtZW5laiBpY2ggcHJhY3VqZSB2IHNsdcW+YsOhY2guIEJvZHkgdHZvcmlhIHRha21lciBkb2tvbmFsw7oga2xlc2Fqw7pjdSBwcmlhbWt1LgotIHBvZG9ibmUsICoqQWdyaWN1bHR1cmUgYSBJbmR1c3RyeSoqIHRpZcW+IHNpbG5lIGtsZXNhasO6IOKAkyB0aWV0byBkdmUgcHJlbWVubsOpIHPDuiB0aWXFviBuYXZ6w6Fqb20gcHJlcG9qZW7DqS4KLSB2esWlYWh5IG1lZHppIHNla3Rvcm1pIHPDuiBzcMO0c29iZW7DqSB0w71tLCDFvmUgdsWhZXRreSBzZWt0b3J5IHNwb2x1IHR2b3JpYSAxMDAgJSB6YW1lc3RuYW5vc3RpLCB0YWvFvmUga2XEjyBqZWRlbiBzZWt0b3IgcmFzdGllLCBpbsOpIG11c2lhIGtsZXNhxaUuCi0gKipHRFAqKiBqZSBuYSBncmFmb2NoIHByYWt0aWNreSDigJ5iZXogdnpvcnXigJwsIGJvZHkgc8O6IHJvemjDoWR6YW7DqSDihpIgR0RQIG5pZSBqZSBzbyBzZWt0b3JtaSBzaWxubyBwcmVwb2plbsOpIGEgbmVzcMO0c29idWplIG11bHRpa29saW5lYXJpdHUuCgpaIHRvaG8gdnlwbMO9dmEsIMW+ZSBTY2F0dGVycGxvdG92w6EgbWF0aWNhIHBvdHZyZGlsYSwgxb5lIG11bHRpa29saW5lYXJpdGEgdnpuaWvDoSBuYWptw6QgbWVkemkgdHJvbWkgc2VrdG9yb3bDvW1pIHByZW1lbm7DvW1pLCBuaWUgbWVkemkgR0RQIGEgc2VrdG9ybWkuCgojIDMuIFZJRiDigJMgVmFyaWFuY2UgSW5mbGF0aW9uIEZhY3RvcgoKVklGIHBvdcW+w612YW1lIG5hIHRvLCBhYnkgc21lIHppc3RpbGksIGt0b3LDoSBwcmVtZW5uw6Egc3DDtHNvYnVqZSBtdWx0aWtvbGluZWFyaXR1LiAgClBsYXTDrSBqZWRub2R1Y2jDqSBwcmF2aWRsbzoKCi0gVklGIG9rb2xvICoqMeKAkzIqKiDihpIgxb5pYWRueSBwcm9ibMOpbSAgCi0gVklGICoqPiA1Kiog4oaSIHphxI3DrW5hasO6Y2kgcHJvYmzDqW0gIAotIFZJRiAqKj4gMTAqKiDihpIgdsOhxb5uYSBtdWx0aWtvbGluZWFyaXRhICAKCmBgYHtyfQoKIyAzLiBWSUYKCmxpYnJhcnkoY2FyKQp2aWYobW9kZWwpCgpgYGAKIyMjIEludGVycHJldMOhY2lhIFZJRiAKCkhvZG5vdHkgVklGIHYgbW9qb20gbW9kZWxpIHPDuiBvYnJvdnNrw6kgcHJpIHNla3Rvcm92w71jaCBwcmVtZW5uw71jaCAoQWdyaWN1bHR1cmUsIEluZHVzdHJ5LCBTZXJ2aWNlcykuIAogS2XEjyBqZWRlbiBzZWt0b3Igc3TDunBhLCBvc3RhdG7DqSBtdXNpYSBrbGVzYcWlLCB0YWvFvmUgc8O6IHByYWt0aWNreSBuYXZpYXphbsOpIGplZG5hIG5hIGRydWjDuiwgxI1vIGplIGphc27DvSB6bmFrIHZlxL5taSBzaWxuZWogbXVsdGlrb2xpbmVhcml0eS4KClRha8W+ZSB0byB6bmFtZW7DoSwgxb5lICB0aWV0byB0cmkgcHJlbWVubsOpIHPDuiBwcmUgbW9kZWwg4oCedGFrbWVyIHRvIGlzdMOp4oCcLCBsZW4gdiBpbm9tIHBvcmFkw61hIHNww7Rzb2J1asO6IGNoYW9zIHYga29lZmljaWVudG9jaCwgbW9kZWwgaWNoIG5ldmllIHNwb8S+YWhsaXZvIG9kbMOtxaFpxaUuCgpQcmVtZW5uw6EgR0RQIHRha8O9dG8gcHJvYmzDqW0gbmVtw6EgKFZJRiDiiYggMSksIHRha8W+ZSBtdWx0aWtvbGluZWFyaXR1IHNww7Rzb2J1asO6IHbDvWhyYWRuZSBzZWt0b3JvdsOpIHByZW1lbm7DqS4KCiMgNC4gQ29uZGl0aW9uIE51bWJlcgoKQ29uZGl0aW9uIE51bWJlciBqZSDEj2FsxaHDrSB1a2F6b3ZhdGXEviwga3RvcsO9IHNhIHBvdcW+w612YSBuYSB6aXN0ZW5pZSBtdWx0aWtvbGluZWFyaXR5LiAgCgpJbnR1aXTDrXZuZSBwcmF2aWRsbzoKCi0gPCAxMCDihpIgxb5pYWRueSBwcm9ibMOpbSAgCi0gMTDigJMzMCDihpIgbWllcm5hIG11bHRpa29saW5lYXJpdGEgIAotIDMw4oCTMTAwIOKGkiBzaWxuw6EgIAotID4gMTAwIOKGkiB2ZcS+bWkgdsOhxb5uYSBtdWx0aWtvbGluZWFyaXRhICAKCmBgYHtyfQoKIyA0LiBDT05ESVRJT04gTlVNQkVSCgpYIDwtIG1vZGVsLm1hdHJpeChtb2RlbClbLCAtMV0KWHRYIDwtIHQoWCkgJSolIFgKZWlnIDwtIGVpZ2VuKFh0WCkKCmNvbmRpdGlvbl9udW1iZXIgPC0gc3FydChtYXgoZWlnJHZhbHVlcykgLyBtaW4oZWlnJHZhbHVlcykpCmNvbmRpdGlvbl9udW1iZXIKCmBgYAojIyBJbnRlcnByZXTDoWNpYSBDb25kaXRpb24gTnVtYmVyCgpQcmkgdsO9cG/EjXRlIENvbmRpdGlvbiBOdW1iZXIgc2EgbWkgem9icmF6aWxhIGhvZG5vdGEgTmFOLiAgClRvIHNhIHN0w6F2YSB2IHNpdHXDoWNpaSwga2XEjyBqZSBtYXRpY2EgdnlzdmV0xL51asO6Y2ljaCBwcmVtZW5uw71jaCB0YWttZXIgc2luZ3Vsw6FybmEsIHRlZGEgamVkbmEgcHJlbWVubsOhIHNhIGTDoSBza29ybyDDunBsbmUgcHJlc25lIHZ5amFkcmnFpSBwb21vY291IGluw71jaCBwcmVtZW5uw71jaC4gViBtb2pvbSBwcsOtcGFkZSBqZSB0byBkw7RzbGVkb2sgdG9obywgxb5lIHNla3Rvcm92w6kgcHJlbWVubsOpIChBZ3JpY3VsdHVyZSwgSW5kdXN0cnksIFNlcnZpY2VzKSBzcG9sdSB0dm9yaWEgMTAwICUgemFtZXN0bmFub3N0aS4KClRvIHpuYW1lbsOhLCDFvmUgbWVkemkgbmltaSBleGlzdHVqZSBleHRyw6ltbmUgc2lsbsOhIGxpbmXDoXJuYSB6w6F2aXNsb3PFpSBhIENvbmRpdGlvbiBOdW1iZXIgc2EgbmVkw6Egbm9ybcOhbG5lIHZ5cG/EjcOtdGHFpS4gVGVudG8gdsO9c2xlZG9rIGplIGXFoXRlIHNpbG5lasWhw61tIGTDtGthem9tIG11bHRpa29saW5lYXJpdHkgbmXFviB2eXNva8OpIGhvZG5vdHkgVklGLgoKIyA1LiBSaWXFoWVuaWEgbXVsdGlrb2xpbmVhcml0eQoKIyMgVnluZWNoYW5pZSBwcmVtZW5uZWogQWdyb2N1bHR1cmUgCmBgYHtyfQptb2RlbF9ub0FncmkgPC0gbG0oVW5lbXBsb3ltZW50LlJhdGUgfiAKICAgICAgICAgICAgICAgICAgICAgRW1wbG95bWVudC5TZWN0b3IuLkluZHVzdHJ5ICsKICAgICAgICAgICAgICAgICAgICAgRW1wbG95bWVudC5TZWN0b3IuLlNlcnZpY2VzICsKICAgICAgICAgICAgICAgICAgICAgR0RQLi5pbi5VU0QuLAogICAgICAgICAgICAgICAgICAgZGF0YSA9IHVkYWplKQoKc3VtbWFyeShtb2RlbF9ub0FncmkpCgpgYGAKIyMjIE1vZGVsIGJleiBwcmVtZW5uZWogQWdyaWN1bHR1cmUg4oCTIGludGVycHJldMOhY2lhCgpLZcSPIHNtZSB6IG1vZGVsdSB2eW5lY2hhbGkgcHJlbWVubsO6IEFncmljdWx0dXJlLCB2w71zbGVka3kgc2EgemxlcMWhaWxpOgoKLSBwcmVtZW5uw6EgKipJbmR1c3RyeSoqIGplIHRlcmF6IMWhdGF0aXN0aWNreSB2w716bmFtbsOhIChwIOKJiCAwLjAyKSwKLSBwcmVtZW5uw6EgKipTZXJ2aWNlcyoqIGplIHRlc25lIHBvZCBocmFuaWNvdSB2w716bmFtbm9zdGkgKHAg4omIIDAuMDgpLAotIHByZW1lbm7DoSAqKkdEUCoqIGplIHN0w6FsZSBuYSBocmFuaWNpIHbDvXpuYW1ub3N0aSAocCDiiYggMC4wOSkuCgpVcHJhdmVuw70gUsKyIGplIHPDrWNlIHN0w6FsZSBuw616a3kgKOKJiCAwLjA3OSksIGFsZSBtb2RlbCBqZSB1xb4gc3RhYmlsbmVqxaHDrSBuZcW+IHDDtHZvZG7DvS4KClogdG9obyB2eXBsw712YSwgxb5lIHZ5bmVjaGFuaWUgQWdyaWN1bHR1cmUgcG9tb2hsbywgcHJldG/FvmUgdMOhdG8gcHJlbWVubsOhIHNww7Rzb2JvdmFsYSBuYWp2aWFjIG11bHRpa29saW5lYXJpdHkgc28genZ5xaFuw71taSBkdm9tYSBzZWt0b3JvdsO9bWkgcHJlbWVubsO9bWkgKGJvbGEgZXh0csOpbW5lIHNpbG5lIGtvcmVsb3ZhbsOhIHNvIFNlcnZpY2VzIGEgSW5kdXN0cnkpLgoKVGVudG8gbW9kZWwgamUgcHJldG8gbyBuaWXEjW8gbGVwxaHDrSBuZcW+IHDDtHZvZG7DvSBtb2RlbCBzbyB2xaFldGvDvW1pIHByZW1lbm7DvW1pLgoKIyMgVnluZWNoYW5pZSBwcmVtZW5uZWogSW5kdXNyeQpgYGB7cn0KbW9kZWxfbm9JbmR1c3RyeSA8LSBsbShVbmVtcGxveW1lbnQuUmF0ZSB+IAogICAgICAgICAgICAgICAgICAgICAgICAgRW1wbG95bWVudC5TZWN0b3IuLkFncmljdWx0dXJlICsKICAgICAgICAgICAgICAgICAgICAgICAgIEVtcGxveW1lbnQuU2VjdG9yLi5TZXJ2aWNlcyArCiAgICAgICAgICAgICAgICAgICAgICAgICBHRFAuLmluLlVTRC4sCiAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IHVkYWplKQoKc3VtbWFyeShtb2RlbF9ub0luZHVzdHJ5KQoKYGBgCiMjIyBNb2RlbCBiZXogcHJlbWVubmVqIEluZHVzdHJ5IOKAkyBpbnRlcnByZXTDoWNpYQoKS2XEjyBzbWUgeiBtb2RlbHUgdnluZWNoYWxpIHByZW1lbm7DuiBJbmR1c3RyeSwgdsO9em5hbW5vc8WlIHNhIG9icsOhdGlsYToKCi0gcHJlbWVubsOhICoqQWdyaWN1bHR1cmUqKiBqZSB0ZXJheiDFoXRhdGlzdGlja3kgdsO9em5hbW7DoSAocCDiiYggMC4wMjIpLAotIHByZW1lbm7DoSAqKlNlcnZpY2VzKiogbmllIGplIHbDvXpuYW1uw6EgKHAg4omIIDAuMjUpLAotIHByZW1lbm7DoSAqKkdEUCoqIGplIG9ww6TFpSBuYSBocmFuaWNpIChwIOKJiCAwLjA5KS4KCkhvZG5vdGEgUsKyIHNhIG5lem1lbmlsYSAoamUgcm92bmFrw6EgYWtvIHYgbW9kZWxpIGJleiBBZ3JpY3VsdHVyZSksIMSNbyB6bmFtZW7DoSwgxb5lIHZ5c3ZldMS+b3ZhY2lhIHNjaG9wbm9zxaUgbW9kZWx1IGplIHJvdm5ha8OhLgoKVGVudG8gbW9kZWwgamUgdsWhYWsgKipob3LFocOtIG5lxb4gbW9kZWwgYmV6IEFncmljdWx0dXJlKiosIHByZXRvxb5lIHYgxYhvbSBvc3TDoXZhIGxlbiBqZWRuYSB2w716bmFtbsOhIHByZW1lbm7DoSAoQWdyaWN1bHR1cmUpLCB6YXRpYcS+IMSNbyBtb2RlbCBiZXogQWdyaWN1bHR1cmUgbWFsIHbDvXpuYW1uw70gSW5kdXN0cnkgYSBza29ybyB2w716bmFtbsO9IFNlcnZpY2VzLgoKVGFrxb5lIHZ5bmVjaGFuaWUgSW5kdXN0cnkgbmVwcmluaWVzbG8gdGFrw6kgemxlcMWhZW5pZSBha28gdnluZWNoYW5pZSBBZ3JpY3VsdHVyZS4KCgojIyBWeW5lY2hhbmllIHByZW1lbm5laiBTZXJ2aWNlcwpgYGB7cn0KbW9kZWxfbm9TZXJ2aWNlcyA8LSBsbShVbmVtcGxveW1lbnQuUmF0ZSB+IAogICAgICAgICAgICAgICAgICAgICAgICAgRW1wbG95bWVudC5TZWN0b3IuLkFncmljdWx0dXJlICsKICAgICAgICAgICAgICAgICAgICAgICAgIEVtcGxveW1lbnQuU2VjdG9yLi5JbmR1c3RyeSArCiAgICAgICAgICAgICAgICAgICAgICAgICBHRFAuLmluLlVTRC4sCiAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IHVkYWplKQoKc3VtbWFyeShtb2RlbF9ub1NlcnZpY2VzKQoKYGBgCiMjIyBNb2RlbCBiZXogcHJlbWVubmVqIFNlcnZpY2VzIOKAkyBpbnRlcnByZXTDoWNpYQoKS2XEjyBzbWUgeiBtb2RlbHUgdnluZWNoYWxpIHByZW1lbm7DuiBTZXJ2aWNlcywgdsO9c2xlZG9rIGplIHBvZG9ibsO9IGFrbyB2IHByZWRvxaFsb20gbW9kZWxpOgoKLSBwcmVtZW5uw6EgKipBZ3JpY3VsdHVyZSoqIGplIGxlbiBuYSBocmFuaWNpIHbDvXpuYW1ub3N0aSAocCDiiYggMC4wODIpLAotIHByZW1lbm7DoSAqKkluZHVzdHJ5KiogbmllIGplIHbDvXpuYW1uw6EgKHAg4omIIDAuMjUpLAotIHByZW1lbm7DoSAqKkdEUCoqIGplIHN0w6FsZSBsZW4gdGVzbmUgbmV2w716bmFtbsOhIChwIOKJiCAwLjA5KS4KClLCsiBqZSBvcMOkxaUgcm92bmFrw6kgYWtvIHYgcHJlZGNow6FkemFqw7pjaWNoIGR2b2NoIHByw61wYWRvY2guCgpUZW50byBtb2RlbCBqZSBuYWpzbGFixaHDrSB6byB2xaFldGvDvWNoIHRyb2NoLCBwcmV0b8W+ZSBuZW3DoSDFvmlhZG51IGphc25lIHbDvXpuYW1uw7ogcHJlbWVubsO6IGEga29lZmljaWVudHkgc8O6IGXFoXRlIG1lbmVqIHN0YWJpbG7DqS4KCiMjIyBLdG9yw7ogcHJlbWVubsO6IGplIG5hamxlcMWhaWUgdnluZWNoYcWlPwoKUG9yb3ZuYWxpIHNtZSB2xaFldGt5IHRyaSBtb2RlbHksIGtkZSBzbWUgdsW+ZHkgamVkbnUgcHJlbWVubsO6IHZ5bmVjaGFsYS4gIApOYWpsZXDFocOtIHbDvXNsZWRvayB2ecWhaWVsIHRlZGEgcHJpIG1vZGVsaSAqKmJleiBBZ3JpY3VsdHVyZSoqLCBwcmV0b8W+ZToKCi0gSW5kdXN0cnkgc2Egc3RhbCB2w716bmFtbsO9bSwKLSBTZXJ2aWNlcyBib2wgYXNwb8WIIG5hIGhyYW5pY2kgdsO9em5hbW5vc3RpLAotIG1vZGVsIHZ5emVyYWwgbmFqc3RhYmlsbmVqxaFpZSwKLSBhIMSNw61zZWxuZSBkw6F2YWwgbmFqcm96dW1uZWrFoWllIGtvZWZpY2llbnR5LgoKTW9kZWwgYmV6IEluZHVzdHJ5IGEgbW9kZWwgYmV6IFNlcnZpY2VzIGJvbGkgaG9yxaFpZSDigJMgdsW+ZHkgem9zdGFsYSBpYmEgamVkbmEgdsO9em5hbW7DoSBwcmVtZW5uw6EgYWxlYm8gxb5pYWRuYS4KCiMjIDUuMiDFoGvDoWxvdmFuaWUgcHJlbWVubsO9Y2ggKGNlbnRyb3ZhbmllKQpgYGB7cn0KI8WgS8OBTE9WQU5JRSBQUkVNRU5Ow51DSAoKdWRhamUkQWdyaV9jICAgICA8LSBzY2FsZSh1ZGFqZSRFbXBsb3ltZW50LlNlY3Rvci4uQWdyaWN1bHR1cmUsIGNlbnRlcj1UUlVFLCBzY2FsZT1UUlVFKQp1ZGFqZSRJbmR1c3RyeV9jIDwtIHNjYWxlKHVkYWplJEVtcGxveW1lbnQuU2VjdG9yLi5JbmR1c3RyeSwgY2VudGVyPVRSVUUsIHNjYWxlPVRSVUUpCnVkYWplJFNlcnZpY2VzX2MgPC0gc2NhbGUodWRhamUkRW1wbG95bWVudC5TZWN0b3IuLlNlcnZpY2VzLCBjZW50ZXI9VFJVRSwgc2NhbGU9VFJVRSkKdWRhamUkR0RQX2MgICAgICA8LSBzY2FsZSh1ZGFqZSRHRFAuLmluLlVTRC4sIGNlbnRlcj1UUlVFLCBzY2FsZT1UUlVFKQoKbW9kZWxfY2VudGVyZWQgPC0gbG0oVW5lbXBsb3ltZW50LlJhdGUgfiBBZ3JpX2MgKyBJbmR1c3RyeV9jICsgU2VydmljZXNfYyArIEdEUF9jLAogICAgICAgICAgICAgICAgICAgICBkYXRhID0gdWRhamUpCgpzdW1tYXJ5KG1vZGVsX2NlbnRlcmVkKQoKYGBgCiMjIyBJbnRlcnByZXTDoWNpYSDFoWvDoWxvdmFuw6lobyBtb2RlbHUKClBvIHByZcWha8OhbG92YW7DrSBwcmVtZW5uw71jaCBzYSBtb2RlbCBzw61jZSB2eXBvxI3DrXRhbCBzdGFiaWxuZWrFoWllLCBhbGUgc3Byw6F2YW5pZSBrb2VmaWNpZW50b3Ygc2EgcHJha3RpY2t5IG5lem1lbmlsby4gIApWw71zbGVka3kgc8O6IHRha21lciB0b3Rvxb5uw6kgYWtvIHYgcMO0dm9kbm9tIG1vZGVsaToKCi0gxb5pYWRuYSBzZWt0b3JvdsOhIHByZW1lbm7DoSAoQWdyaV9jLCBJbmR1c3RyeV9jLCBTZXJ2aWNlc19jKSAqKm5pZSBqZSDFoXRhdGlzdGlja3kgdsO9em5hbW7DoSoqLCAgCi0gR0RQX2MgamUgb3DDpMWlIGxlbiB0ZXNuZSBuYSBocmFuaWNpIHbDvXpuYW1ub3N0aSAocCDiiYggMC4wOSksICAKLSB1cHJhdmVuw70gUsKyIGplIHJvdm5ha8O9IGFrbyBwcmVkIMWha8OhbG92YW7DrW0gKOKJiCAwLjA3NikuCgrFoGvDoWxvdmFuaWUgdGVkYSAqKm5lb2RzdHLDoW5pbG8gbXVsdGlrb2xpbmVhcml0dSBtZWR6aSBzZWt0b3JvdsO9bWkgcHJlbWVubsO9bWkqKiwgaWJhIHN0YWJpbGl6b3ZhbG8gdsO9cG/EjXR5LiAgClByb2Jsw6ltIHpvc3TDoXZhLCBwcmV0b8W+ZSB0cmkgc2VrdG9yeSBzw7ogc3TDoWxlIG5hdmlhemFuw6kgKHR2b3JpYSBzcG9sdSB0YWttZXIgMTAwICUgemFtZXN0bmFub3N0aSksIHRha8W+ZSBtb2RlbCBpY2ggbmVkb2vDocW+ZSBvZCBzZWJhIG9kZGVsacWlIGFuaSBwbyDFoWvDoWxvdmFuw60uCgoKIyMgNS4zIMOacHJhdmEgamVkbm90aWVrIChHRFAvMTAwMCkKCgpgYGB7cn0KCiMgw5pQUkFWQSBKRUROT1RJRUsg4oCTIEdEUCAvIDEwMDAKCgp1ZGFqZSRHRFAxMDAwIDwtIHVkYWplJEdEUC4uaW4uVVNELiAvIDEwMDAKCm1vZGVsX0dEUDEwMDAgPC0gbG0oVW5lbXBsb3ltZW50LlJhdGUgfgogICAgICAgICAgICAgICAgICAgICAgRW1wbG95bWVudC5TZWN0b3IuLkFncmljdWx0dXJlICsKICAgICAgICAgICAgICAgICAgICAgIEVtcGxveW1lbnQuU2VjdG9yLi5JbmR1c3RyeSArCiAgICAgICAgICAgICAgICAgICAgICBFbXBsb3ltZW50LlNlY3Rvci4uU2VydmljZXMgKwogICAgICAgICAgICAgICAgICAgICAgR0RQMTAwMCwKICAgICAgICAgICAgICAgICAgICBkYXRhID0gdWRhamUpCgpzdW1tYXJ5KG1vZGVsX0dEUDEwMDApCnZpZihtb2RlbF9HRFAxMDAwKQoKYGBgCiMjIyBNb2RlbCBzIHByZW1lbm91IEdEUCBuYSB0aXPDrWNlIGRvbMOhcm92IOKAkyBpbnRlcnByZXTDoWNpYQoKUG8gcHJlcG/EjcOtdGFuw60gR0RQIG5hIHRpc8OtY2UgZG9sw6Fyb3Ygc2Egc2Ftb3Ruw70gbW9kZWwgdGFrbWVyIHbDtGJlYyBuZXptZW5pbC4gIApLb2VmaWNpZW50eSBwcmkgc2VrdG9yb3bDvWNoIHByZW1lbm7DvWNoIGFqIHByaSBHRFAxMDAwIG1hasO6IHJvdm5ha8OpIHAtaG9kbm90eSBha28gcHJlZHTDvW0sIMSNbyB6bmFtZW7DoSwgxb5lIMO6cHJhdmEgamVkbm90aWVrOgoKLSBuZXptZW5pbGEgdsO9em5hbW5vc8WlIHByZW1lbm7DvWNoLAotIG5lemxlcMWhaWxhIHNjaG9wbm9zxaUgbW9kZWx1IHZ5c3ZldMS+b3ZhxaUgbmV6YW1lc3RuYW5vc8WlLAotIGEgbXVsdGlrb2xpbmVhcml0YSB6b3N0YWxhIHJvdm5ha28gc2lsbsOhLgoKUsKyIGFqIGNoeWJ5IHpvc3RhbGkgaWRlbnRpY2vDqSBha28gdiBww7R2b2Rub20gbW9kZWxpLgoKVklGIGhvZG5vdHkgaG92b3JpYSDDunBsbmUgamFzbmU6Ci0gc2VrdG9yb3bDqSBwcmVtZW5uw6kgbWFqw7ogb3DDpMWlIGV4dHLDqW1uZSB2eXNva8OpIFZJRiAocsOhZHkgbWlsacOhcmQpLAotIEdEUDEwMDAgbcOhIG5vcm3DoWxueSBWSUYg4omIIDEuCjogIArDmnByYXZhIEdEUCBuYSDigJ50aXPDrWNlIGRvbMOhcm924oCcIHPDrWNlIHpsZXDFoWlsYSDEjWl0YXRlxL5ub3PFpSBrb2VmaWNpZW50dSBHRFAsIGFsZSAqKm5lb2RzdHLDoW5pbGEgbXVsdGlrb2xpbmVhcml0dSoqLCBwcmV0b8W+ZSB0w7ogc3DDtHNvYnVqw7ogc2VrdG9yb3bDqSBwcmVtZW5uw6ksIG5pZSBHRFAuCgojWmhybnV0aWUKViB0ZWp0byDDumxvaGUgc29tIHNrw7ptYWxhIG11bHRpa29saW5lYXJpdHUgdiByZWdyZXNub20gbW9kZWxpLCBrZGUgdnlzdmV0xL51amVtIG1pZXJ1IG5lemFtZXN0bmFub3N0aSBwb21vY291IHBvZGllbHUgemFtZXN0bmFub3N0aSB2IGplZG5vdGxpdsO9Y2ggc2VrdG9yb2NoIGEgSERQIG5hIG9ieXZhdGXEvmEuIFXFviB6w6FrbGFkbsO9IG1vZGVsIG5hem5hxI1vdmFsIHByb2Jsw6ltOiBrb2VmaWNpZW50eSBzZWt0b3JvdsO9Y2ggcHJlbWVubsO9Y2ggYm9saSBuZXbDvXpuYW1uw6kgYSBtYWxpIHRha21lciByb3ZuYWvDqSBob2Rub3R5LgoKS29yZWzDoWNpZSBtZWR6aSBwcmVtZW5uw71taSB1a8OhemFsaSB2ZcS+bWkgc2lsbsO6IHbDpHpidSBobGF2bmUgbWVkemkgdHJvbWkgc2VrdG9yb3bDvW1pIHByZW1lbm7DvW1pIChBZ3JpY3VsdHVyZSwgSW5kdXN0cnksIFNlcnZpY2VzKS4gTmFqc2lsbmVqxaFpYSBib2xhIGtvcmVsw6FjaWEgQWdyaWN1bHR1cmXigJNTZXJ2aWNlcyAo4oCTMC45NTcpLiBKZSB0byBsb2dpY2vDqSwgcHJldG/FvmUgdGlldG8gdHJpIHByZW1lbm7DqSBzcG9sdSB0dm9yaWEgdGFrbWVyIDEwMCAlIHphbWVzdG5hbm9zdGksIHRhCgo=