#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)
[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
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=