S využitím databázy WHO
Life Expactancy Data database.
Pri ďalšej práci budeme používať knižnice
library(zoo)
library(tseries)
library(lmtest)
library(sandwich)
library(car)
rm(list=ls())
V hlavnom menu som Session nastavil na Source
File Location. Môžeme to urobiť aj interaktívnym spôsobom - napísať
dole do Console (alebo to zahrnúť priamo do skriptu) ako
setwd(“/Cloud/project/tyzdne/tyzden5”)
Organizácia priečinkov a podpriečinkov sa však môže líšiť v
závislosti od projektu, preto som ich nezaradil do Chunk-u.
Údaje o očakávanej dĺžke života sú usporiadané v súbore csv,
stĺpce sú oddelené znakom “,” a používajú desatinnú čiarku. V pracovnom
priečinku som vytvoril podpriečinok s názvom udaje, aby som
oddelil údaje od zvyšku projektu. Môj priečinok sa tiež nazýva
udaje.
Nie všetky údaje budú použité, preto som vybral len niektoré stĺpce
pre neskoršie použitie.
Úvod do problému, stanovenie hypotéz
Rozhodol som sa modelovať strednú dĺžku života
Life.expectancy v závislosti od troch vysvetľujúcich premenných
a to BMI, HDP na obyvateľa GDP a stredný počet rokov
štúdia Schooling.
Naša pracovná hypotéza hovorí o štatisticky významnom vplyve všetkých
troch vysvetľujúcich premenných, pričom u premenných GDP a
Schooling by malo ísť o pozitívny vplyv (očakávame kladné
znamienko odhadovaného regresného koeficienta) a v prípade BMI by malo
ísť of negatívny vplyv (so záporným znamienkom)
Príprava databázy, čistenie a úprava údajov
Keďže niektoré údaje chýbajú, doplnil som ich mediánovými hodnotami
premennej, ktorú zvažujem. lm
udaje <- read.csv("udaje/Life_Expectancy_Data.csv",dec=".",sep=",",header = TRUE)
# select just the record from 2015
udaje.2015 <- udaje[udaje$Year==2015,c("Life.expectancy","BMI","GDP","Schooling")]
# data imputation
# Compute column medians
#column_medians <- sapply(udaje.2015, median, na.rm = TRUE)
# Impute missing values with column medians
# Compute column medians
column_medians <- sapply(udaje.2015, median, na.rm = TRUE)
# Impute missing values with column medians
udaje_imputed <- udaje.2015
for (col in names(udaje.2015)) {
udaje_imputed[[col]][is.na(udaje_imputed[[col]])] <- column_medians[col]
}
udaje.2015 <- udaje_imputed
Teraz chceme vidieť tvar údajov (či nie sú v nich nejaké
nezrovnalosti – napríklad hodnoty 0).
# Suppose udaje.2015 is your data frame
# Determine number of plots
num_plots <- length(names(udaje.2015))
# Set the layout: 2 rows × 2 columns
par(mfrow = c(2, 2))
par(mar = c(4, 4, 2, 1)) # Adjust margins (optional)
# Loop through columns and plot each boxplot
for (col in names(udaje.2015)) {
boxplot(udaje.2015[[col]], main = "lmcol", xlab = "Value", col = "lightblue")
}
# Add a global caption / title
mtext("Boxploty jednotlivých premenných", outer = TRUE, cex = 1.4, font = 2)
# Reset layout to default (1 plot per figure)
par(mfrow = c(1, 1))

Lineárna regresia
Model odhadujeme príkazom lm()
model <- lm(Life.expectancy ~ +1 + BMI + GDP + Schooling,data=udaje.2015)
Objekt triedy lm() nám poskytuje niekoľko výsledkov:
- Vector odhadnutých koeficientov model$coefficients
- Vektor rezíduí model$ residuals
- Vektor vyrovnaných hodnôt vysvetľovanej veličiny
model$fitted.values
- Maticu X model$x
#print("Odhadnuté koeficienty sú: ")
# print(model$coefficients)
#print("Odhadnuté rezíduá: ")
#print(model$residuals)
#print("Vyrovnané hodnoty vysvetľovanej premennej sú: ")
#print(model$fitted.values)
#print("matica model$xlevels: ")
#print(model.matrix(model))
#X <- model.matrix(model)
#diag(X %*% solve(t(X) %*% X) %*% t(X))
summary(model)
Call:
lm(formula = Life.expectancy ~ +1 + BMI + GDP + Schooling, data = udaje.2015)
Residuals:
Min 1Q Median 3Q Max
-17.6471 -2.4024 0.4563 3.2355 12.8591
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 4.419e+01 1.839e+00 24.033 <2e-16 ***
BMI 4.948e-02 2.144e-02 2.308 0.0222 *
GDP 6.972e-05 3.845e-05 1.813 0.0715 .
Schooling 1.921e+00 1.645e-01 11.676 <2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 5.033 on 179 degrees of freedom
Multiple R-squared: 0.6224, Adjusted R-squared: 0.6161
F-statistic: 98.36 on 3 and 179 DF, p-value: < 2.2e-16
Súhrn odhadovaného modelu nám poskytuje súbor odhadovaných regresných
koeficientov, ktorých znamienka budú rozoberané neskôr. Ak hovoríme o
vlastnostiach modelu ako celku, pozrime sa najskôr na nasledujúce
obrázky. Na základe Q-Q grafu získavame dojem o možných problémoch
porušenia normality rezíduí.
# Nastaviť rozloženie 2 x 2
par(mfrow = c(2, 2))
# Vykresliť všetky 4 diagnostické grafy modelu
plot(model)
# (Voliteľné) pridať spoločný nadpis
#mtext("Diagnostické grafy regresného modelu", outer = TRUE, cex = 1.2, font = 2)
# Resetovať layout
par(mfrow = c(1, 1))

Residuals vs. fitted
Interpretácia vášho konkrétneho grafu
Centrovanie okolo nuly
Reziduály kolíšu približne okolo 0 – to je dobré.
Naznačuje to, že model nemá výrazné skreslenie v
predikciách.
Červená hladká čiara je mierne zakrivená (vpravo sa ohýba nadol a
uprostred nahor), to naznačuje možnú miernu nelinearitu – modelu môže
chýbať nelineárny tvar nejakej premennej.
Rozptyl rezíduí - Vertikálny rozptyl (variancia rezíduí) sa javí
ako približne konštantný v rámci prispôsobených hodnôt čo je dobrý dôkaz
homoscedasticity.
Ak by sa rezíduá rozprestierali (tvorili kónus), naznačovalo by
to heteroskedasticitu.
Odľahlé hodnoty - Niekoľko bodov (napr. v blízkosti −20) leží
ďaleko od ostatných – ide o potenciálne odľahlé hodnoty alebo vplyvné
pozorovania.
Môžeme ich preskúmať pomocou outlierTest(model) (z balíka car).
Q-Q plot
Čo ukazuje
- Os X: Teoretické kvantily – čo by sme očakávali, ak by rezíduá boli
dokonale normálne rozložené.
- Os Y: Štandardizované rezíduá – skutočné kvantily z vašej
vzorky.
- 45° prerušovaná čiara: Ideálny prípad – ak sú rezíduá normálne
rozložené, body by mali ležať tesne pozdĺž tejto čiary.
Interpretácia vášho konkrétneho grafu
Celkový tvar
Väčšina bodov leží blízko priamky — to naznačuje, že rezíduá sú
približne normálne.
To je dobré: predpoklad normality sa zdá byť vo veľkej miere
splnený.
Krajné hodnoty (extrémy)
Body na oboch koncoch (vľavo dole a vpravo hore) sa mierne odchyľujú
od priamky.
To naznačuje miernu nenormálnosť v koncoch – možno niekoľko odľahlých
hodnôt alebo ťažšie konce, ako je normálne (trochu špicatosť).
Stredná oblasť
Stredná časť grafu (−1 až +1 kvantily) sa veľmi dobre zhoduje – čo
znamená, že väčšina rezíduí pekne zapadá do normálneho rozdelenia.
Zároveň vykonávame následné testy, v ktorých zamietame hypotézu o
normálnom rozložení modelových chýb, ako aj prítomnosť extrémnych
hodnôt.
Scale location plot
Čo to znázorňuje
Os X: Vyrovnan0 hodnoty Os Y: Druhá odmocnina absolútnych
štandardizovaných rezíduí Červená čiara: LOESS (vyhladený) trend cez
body
Interpretácia nášho konkrétneho grafu
Horizontálne rozptýlenie
- Body sú rovnomerne rozptýlené po osi x bez vytvorenia lievika alebo
krivky. To naznačuje približne konštantnú varianciu – rezíduá sú
homoscedastické.
- Červená hladká čiara je takmer rovná – ďalší znak, že pri zvyšovaní
vyrovnaných hodnôt nedochádza k žiadnej systematickej zmene
variancie.
- Odľahlé hodnoty - niekoľko bodov je mierne nad 1,5, ale žiadny z
nich nie je extrémny – takže nedochádza k žiadnym závažným anomáliám
variancie.
residuals vs leverage
Čo znázorňuje graf
Os X: Pákový efekt — meria, ako ďaleko je prediktorový vektor bodu od
stredu všetkých 𝑥 x.
Os Y: Štandardizované rezíduá — ako ďaleko je pozorovaná hodnota od
vyrovnanej hodnoty v jednotkách štandardnej odchýlky.
Bodkované krivky: Kontúry Cookovej vzdialenosti, ktoré udávajú, do
akej miery pozorovanie ovplyvňuje regresnú priamku.
Červená čiara: Hladká LOESS čiara prechádzajúca rezíduami.lm
Interpretácia vášho konkrétneho grafu
Rozloženie vplyvu
Väčšina pozorovaní má nízky vplyv (pod 0,05) — typické pre veľké
vzorky alebo dobre vyvážené údaje.
Jeden alebo dva body (napr. okolo 0,2) vynikajú – ide o pozorovania s
vysokou pákou, čo znamená, že ich hodnoty sú ďaleko od väčšiny
údajov.
Veľkosť rezíduí
Štandardizované rezíduá väčšinou medzi −2 a +2 – to je dobré (žiadne
závažné výnimky v 𝑦 y).
Pozorovanie označené číslom 113 má zdanlivo stredný vplyv a relatívne
veľkú rezíduálnu hodnotu – potenciálne vplyvný prípad.
Kontúry Cookovej vzdialenosti
Žiaden z bodov jasne neprekračuje vonkajšie línie Cookovej
vzdialenosti (≈0,5 alebo 1,0).
Preto sa nezdá, že by niektoré pozorovanie neprimerane ovplyvňovalo
regresné koeficienty.
{r}lm # normality tests residuals <- residuals(model) jb_test <- jarque.bera.test(residuals) jb_test # outlier test (see p-value for Bonferroni correction) outlier_test <- outlierTest(model) outlier_test
Keďže sa nepreukázala normalita rezíduí, pokúsme sa eliminovať
odľahlé hodnoty v prípade GDP - dokážeme to logaritmickou transformáciou
tejto premennej a vylúčením BMI, ktoré sa ukázalo ako
neinterpretovateľné. Nová regresia bude mať tvar
model2 <- lm(Life.expectancy ~ +1 + I(log(GDP)) + Schooling,data=udaje.2015)
summary(model2)
Call:
lm(formula = Life.expectancy ~ +1 + I(log(GDP)) + Schooling,
data = udaje.2015)
Residuals:
Min 1Q Median 3Q Max
-18.7351 -2.4761 0.5209 3.4551 10.6277
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 40.0434 2.1992 18.208 <2e-16 ***
I(log(GDP)) 0.6338 0.3002 2.112 0.0361 *
Schooling 2.0561 0.1557 13.203 <2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 5.09 on 180 degrees of freedom
Multiple R-squared: 0.6118, Adjusted R-squared: 0.6075
F-statistic: 141.8 on 2 and 180 DF, p-value: < 2.2e-16
# Nastaviť rozloženie 2 x 2
par(mfrow = c(2, 2))
# Vykresliť všetky 4 diagnostické grafy modelu
plot(model2)
# (Voliteľné) pridať spoločný nadpis
#mtext("Diagnostické grafy regresného modelu", outer = TRUE, cex = 1.2, font = 2)
# Resetovať layout
par(mfrow = c(1, 1))

# normality tests
residuals <- residuals(model)
jb_test <- jarque.bera.test(residuals)
jb_test
Jarque Bera Test
data: residuals
X-squared = 21.391, df = 2, p-value = 2.265e-05
# outlier test (see p-value for Bonferroni correction)
outlier_test <- outlierTest(model)
outlier_test
No Studentized residuals with Bonferroni p < 0.05
Largest |rstudent|:
##Conclusion##
Premenné GDP, a Schooling predlžujú štatisicky
významne strednú dĺžku života. Na druhej strane BMI nám dávalo
neinterpretovateľné výsledky. Rezíduá nevykazujú normálne rozdelenie,
keďže však máme veľké množstvo pozorovaní, aj naďalej budeme pracovať s
týmito údajmi. V modeli sa nepreukazujú žiadne významné nelinearity.
LS0tCnRpdGxlOiAiRWNvbm9tZXRyaWNzIGluIFIgLSBjdmnEjWVuaWUgNSIKb3V0cHV0OiBodG1sX25vdGVib29rCmF1dGhvcjogVi4gR2F6ZGEKLS0tCgpTIHZ5dcW+aXTDrW0gZGF0YWLDoXp5IFtXSE8gTGlmZSBFeHBhY3RhbmN5IERhdGFdKGh0dHBzOi8vd3d3LmthZ2dsZS5jb20vZGF0YXNldHMva3VtYXJhamFyc2hpL2xpZmUtZXhwZWN0YW5jeS13aG8pIGRhdGFiYXNlLgoKUHJpIMSPYWzFoWVqIHByw6FjaSBidWRlbWUgcG91xb7DrXZhxaUga25pxb5uaWNlCgpgYGB7cn0KbGlicmFyeSh6b28pCmxpYnJhcnkodHNlcmllcykKbGlicmFyeShsbXRlc3QpCmxpYnJhcnkoc2FuZHdpY2gpCmxpYnJhcnkoY2FyKQpybShsaXN0PWxzKCkpCmBgYAoKClYgKmhsYXZub20gbWVudSogc29tICpTZXNzaW9uKiBuYXN0YXZpbCBuYSAqU291cmNlIEZpbGUgTG9jYXRpb24qLiBNw7TFvmVtZSB0byB1cm9iacWlIGFqIGludGVyYWt0w612bnltIHNww7Rzb2JvbSAtIG5hcMOtc2HFpSBkb2xlIGRvIENvbnNvbGUgKGFsZWJvIHRvIHphaHJuw7rFpSBwcmlhbW8gZG8gc2tyaXB0dSkgYWtvIAoKICoqc2V0d2QoIi9DbG91ZC9wcm9qZWN0L3R5emRuZS90eXpkZW41IikqKgoKT3JnYW5pesOhY2lhIHByaWXEjWlua292IGEgcG9kcHJpZcSNaW5rb3Ygc2EgdsWhYWsgbcO0xb5lIGzDrcWhacWlIHYgesOhdmlzbG9zdGkgb2QgcHJvamVrdHUsIHByZXRvIHNvbSBpY2ggbmV6YXJhZGlsIGRvIENodW5rLXUuCgrDmmRhamUgbyBvxI1ha8OhdmFuZWogZMS6xb5rZSDFvml2b3RhIHPDuiB1c3BvcmlhZGFuw6kgdiBzw7pib3JlICpjc3YqLCBzdMS6cGNlIHPDuiBvZGRlbGVuw6kgem5ha29tICIsIiBhIHBvdcW+w612YWrDuiBkZXNhdGlubsO6IMSNaWFya3UuIFYgcHJhY292bm9tIHByaWXEjWlua3Ugc29tIHZ5dHZvcmlsIHBvZHByaWXEjWlub2sgcyBuw6F6dm9tICp1ZGFqZSosIGFieSBzb20gb2RkZWxpbCDDumRhamUgb2QgenZ5xaFrdSBwcm9qZWt0dS4gTcO0aiBwcmllxI1pbm9rIHNhIHRpZcW+IG5hesO9dmEgKnVkYWplKi4gCgpOaWUgdsWhZXRreSDDumRhamUgYnVkw7ogcG91xb5pdMOpLCBwcmV0byBzb20gdnlicmFsIGxlbiBuaWVrdG9yw6kgc3TEunBjZSBwcmUgbmVza29yxaFpZSBwb3XFvml0aWUuCgojIMOadm9kIGRvIHByb2Jsw6ltdSwgc3Rhbm92ZW5pZSBoeXBvdMOpeiAKClJvemhvZG9sIHNvbSBzYSBtb2RlbG92YcWlIHN0cmVkbsO6IGTEusW+a3Ugxb5pdm90YSAqTGlmZS5leHBlY3RhbmN5KiB2IHrDoXZpc2xvc3RpIG9kIHRyb2NoIHZ5c3ZldMS+dWrDumNpY2ggcHJlbWVubsO9Y2ggYSB0byAqQk1JKiwgSERQIG5hIG9ieXZhdGXEvmEgKkdEUCogYSBzdHJlZG7DvSBwb8SNZXQgcm9rb3YgxaF0w7pkaWEgICpTY2hvb2xpbmcqLgoKTmHFoWEgcHJhY292bsOhIGh5cG90w6l6YSBob3ZvcsOtIG8gxaF0YXRpc3RpY2t5IHbDvXpuYW1ub20gdnBseXZlIHbFoWV0a8O9Y2ggdHJvY2ggdnlzdmV0xL51asO6Y2ljaCBwcmVtZW5uw71jaCwgcHJpxI1vbSB1IHByZW1lbm7DvWNoICpHRFAqIGEgKlNjaG9vbGluZyogYnkgbWFsbyDDrXPFpSBvIHBveml0w612bnkgdnBseXYgKG/EjWFrw6F2YW1lIGtsYWRuw6kgem5hbWllbmtvIG9kaGFkb3ZhbsOpaG8gcmVncmVzbsOpaG8ga29lZmljaWVudGEpIGEgdiBwcsOtcGFkZSBCTUkgYnkgbWFsbyDDrXPFpSBvZiBuZWdhdMOtdm55IHZwbHl2IChzbyB6w6Fwb3Juw71tIHpuYW1pZW5rb20pCgoKCgojIFByw61wcmF2YSBkYXRhYsOhenksIMSNaXN0ZW5pZSBhIMO6cHJhdmEgw7pkYWpvdgoKS2XEj8W+ZSBuaWVrdG9yw6kgw7pkYWplIGNow71iYWrDuiwgZG9wbG5pbCBzb20gaWNoIG1lZGnDoW5vdsO9bWkgaG9kbm90YW1pIHByZW1lbm5laiwga3RvcsO6IHp2YcW+dWplbS4gbG0KCgpgYGB7cn0KdWRhamUgPC0gcmVhZC5jc3YoInVkYWplL0xpZmVfRXhwZWN0YW5jeV9EYXRhLmNzdiIsZGVjPSIuIixzZXA9IiwiLGhlYWRlciA9IFRSVUUpCiMgc2VsZWN0IGp1c3QgdGhlIHJlY29yZCBmcm9tIDIwMTUKdWRhamUuMjAxNSA8LSB1ZGFqZVt1ZGFqZSRZZWFyPT0yMDE1LGMoIkxpZmUuZXhwZWN0YW5jeSIsIkJNSSIsIkdEUCIsIlNjaG9vbGluZyIpXQoKIyBkYXRhIGltcHV0YXRpb24KCiMgQ29tcHV0ZSBjb2x1bW4gbWVkaWFucwojY29sdW1uX21lZGlhbnMgPC0gc2FwcGx5KHVkYWplLjIwMTUsIG1lZGlhbiwgbmEucm0gPSBUUlVFKQoKIyBJbXB1dGUgbWlzc2luZyB2YWx1ZXMgd2l0aCBjb2x1bW4gbWVkaWFucwojIENvbXB1dGUgY29sdW1uIG1lZGlhbnMKY29sdW1uX21lZGlhbnMgPC0gc2FwcGx5KHVkYWplLjIwMTUsIG1lZGlhbiwgbmEucm0gPSBUUlVFKQoKIyBJbXB1dGUgbWlzc2luZyB2YWx1ZXMgd2l0aCBjb2x1bW4gbWVkaWFucwp1ZGFqZV9pbXB1dGVkIDwtIHVkYWplLjIwMTUKZm9yIChjb2wgaW4gbmFtZXModWRhamUuMjAxNSkpIHsKICB1ZGFqZV9pbXB1dGVkW1tjb2xdXVtpcy5uYSh1ZGFqZV9pbXB1dGVkW1tjb2xdXSldIDwtIGNvbHVtbl9tZWRpYW5zW2NvbF0KfQoKdWRhamUuMjAxNSA8LSB1ZGFqZV9pbXB1dGVkCgpgYGAKCgoKVGVyYXogY2hjZW1lIHZpZGllxaUgdHZhciDDumRham92ICjEjWkgbmllIHPDuiB2IG5pY2ggbmVqYWvDqSBuZXpyb3ZuYWxvc3RpIOKAkyBuYXByw61rbGFkIGhvZG5vdHkgMCkuCgpgYGB7cn0KIyBTdXBwb3NlIHVkYWplLjIwMTUgaXMgeW91ciBkYXRhIGZyYW1lCgojIERldGVybWluZSBudW1iZXIgb2YgcGxvdHMKbnVtX3Bsb3RzIDwtIGxlbmd0aChuYW1lcyh1ZGFqZS4yMDE1KSkKCiMgU2V0IHRoZSBsYXlvdXQ6IDIgcm93cyDDlyAyIGNvbHVtbnMKcGFyKG1mcm93ID0gYygyLCAyKSkKcGFyKG1hciA9IGMoNCwgNCwgMiwgMSkpICAjIEFkanVzdCBtYXJnaW5zIChvcHRpb25hbCkKCiMgTG9vcCB0aHJvdWdoIGNvbHVtbnMgYW5kIHBsb3QgZWFjaCBib3hwbG90CmZvciAoY29sIGluIG5hbWVzKHVkYWplLjIwMTUpKSB7CiAgYm94cGxvdCh1ZGFqZS4yMDE1W1tjb2xdXSwgbWFpbiA9ICJsbWNvbCIsIHhsYWIgPSAiVmFsdWUiLCBjb2wgPSAibGlnaHRibHVlIikKfQoKIyBBZGQgYSBnbG9iYWwgY2FwdGlvbiAvIHRpdGxlCm10ZXh0KCJCb3hwbG90eSBqZWRub3RsaXbDvWNoIHByZW1lbm7DvWNoIiwgb3V0ZXIgPSBUUlVFLCBjZXggPSAxLjQsIGZvbnQgPSAyKQoKIyBSZXNldCBsYXlvdXQgdG8gZGVmYXVsdCAoMSBwbG90IHBlciBmaWd1cmUpCnBhcihtZnJvdyA9IGMoMSwgMSkpCmBgYAoKCgoKIyMgTGluZcOhcm5hIHJlZ3Jlc2lhCgpNb2RlbCBvZGhhZHVqZW1lIHByw61rYXpvbSAqbG0oKSoKCmBgYHtyfQptb2RlbCA8LSBsbShMaWZlLmV4cGVjdGFuY3kgfiArMSArIEJNSSArIEdEUCArIFNjaG9vbGluZyxkYXRhPXVkYWplLjIwMTUpCmBgYAoKT2JqZWt0IHRyaWVkeSAqbG0oKSogbsOhbSBwb3NreXR1amUgbmlla2/EvmtvIHbDvXNsZWRrb3Y6CgoxLiBWZWN0b3Igb2RoYWRudXTDvWNoIGtvZWZpY2llbnRvdiAqbW9kZWwkY29lZmZpY2llbnRzKgoyLiBWZWt0b3IgcmV6w61kdcOtICptb2RlbCQgcmVzaWR1YWxzKgozLiBWZWt0b3Igdnlyb3ZuYW7DvWNoIGhvZG7DtHQgdnlzdmV0xL5vdmFuZWogdmVsacSNaW55ICptb2RlbCRmaXR0ZWQudmFsdWVzKgo0LiBNYXRpY3UgWCAqbW9kZWwkeCoKCmBgYHtyfQojcHJpbnQoIk9kaGFkbnV0w6kga29lZmljaWVudHkgc8O6OiAiKQojICAgICAgcHJpbnQobW9kZWwkY29lZmZpY2llbnRzKQojcHJpbnQoIk9kaGFkbnV0w6kgcmV6w61kdcOhOiAiKQojcHJpbnQobW9kZWwkcmVzaWR1YWxzKQojcHJpbnQoIlZ5cm92bmFuw6kgaG9kbm90eSB2eXN2ZXTEvm92YW5laiBwcmVtZW5uZWogc8O6OiAiKQojcHJpbnQobW9kZWwkZml0dGVkLnZhbHVlcykKI3ByaW50KCJtYXRpY2EgbW9kZWwkeGxldmVsczogIikKI3ByaW50KG1vZGVsLm1hdHJpeChtb2RlbCkpCiNYIDwtIG1vZGVsLm1hdHJpeChtb2RlbCkKI2RpYWcoWCAlKiUgc29sdmUodChYKSAlKiUgWCkgJSolIHQoWCkpCgpzdW1tYXJ5KG1vZGVsKQoKYGBgCgoKClPDumhybiBvZGhhZG92YW7DqWhvIG1vZGVsdSBuw6FtIHBvc2t5dHVqZSBzw7pib3Igb2RoYWRvdmFuw71jaCByZWdyZXNuw71jaCBrb2VmaWNpZW50b3YsIGt0b3LDvWNoIHpuYW1pZW5rYSBidWTDuiByb3pvYmVyYW7DqSBuZXNrw7RyLiBBayBob3ZvcsOtbWUgbyB2bGFzdG5vc3RpYWNoIG1vZGVsdSBha28gY2Vsa3UsIHBvenJpbWUgc2EgbmFqc2vDtHIgbmEgbmFzbGVkdWrDumNlIG9icsOhemt5LiBOYSB6w6FrbGFkZSBRLVEgZ3JhZnUgesOtc2thdmFtZSBkb2plbSBvIG1vxb5uw71jaCBwcm9ibMOpbW9jaCBwb3J1xaFlbmlhIG5vcm1hbGl0eSByZXrDrWR1w60uIAoKYGBge3IgZGlhZ3Bsb3RzLCBmaWcuY2FwPSJEaWFnbm9zdGlja8OpIGdyYWZ5IHJlZ3Jlc27DqWhvIG1vZGVsdSJ9CiMgTmFzdGF2acWlIHJvemxvxb5lbmllIDIgeCAyCnBhcihtZnJvdyA9IGMoMiwgMikpCgojIFZ5a3Jlc2xpxaUgdsWhZXRreSA0IGRpYWdub3N0aWNrw6kgZ3JhZnkgbW9kZWx1CnBsb3QobW9kZWwpCgojIChWb2xpdGXEvm7DqSkgcHJpZGHFpSBzcG9sb8SNbsO9IG5hZHBpcwojbXRleHQoIkRpYWdub3N0aWNrw6kgZ3JhZnkgcmVncmVzbsOpaG8gbW9kZWx1Iiwgb3V0ZXIgPSBUUlVFLCBjZXggPSAxLjIsIGZvbnQgPSAyKQoKIyBSZXNldG92YcWlIGxheW91dApwYXIobWZyb3cgPSBjKDEsIDEpKQpgYGAKCgojIyBSZXNpZHVhbHMgdnMuIGZpdHRlZAoKIyMjIEludGVycHJldMOhY2lhIHbDocWhaG8ga29ua3LDqXRuZWhvIGdyYWZ1CgotIENlbnRyb3ZhbmllIG9rb2xvIG51bHkKLSBSZXppZHXDoWx5IGtvbMOtxaF1IHByaWJsacW+bmUgb2tvbG8gMCDigJMgdG8gamUgZG9icsOpLgotIE5hem5hxI11amUgdG8sIMW+ZSBtb2RlbCBuZW3DoSB2w71yYXpuw6kgc2tyZXNsZW5pZSB2IHByZWRpa2Npw6FjaC4KLSDEjGVydmVuw6EgaGxhZGvDoSDEjWlhcmEgamUgbWllcm5lIHpha3JpdmVuw6EgKHZwcmF2byBzYSBvaMO9YmEgbmFkb2wgYSB1cHJvc3RyZWQgbmFob3IpLCB0byBuYXpuYcSNdWplIG1vxb5uw7ogbWllcm51IG5lbGluZWFyaXR1IOKAkyBtb2RlbHUgbcO0xb5lIGNow71iYcWlIG5lbGluZcOhcm55IHR2YXIgbmVqYWtlaiBwcmVtZW5uZWouCgotIFJvenB0eWwgcmV6w61kdcOtIC0gVmVydGlrw6Fsbnkgcm96cHR5bCAodmFyaWFuY2lhIHJlesOtZHXDrSkgc2EgamF2w60gYWtvIHByaWJsacW+bmUga29uxaF0YW50bsO9IHYgcsOhbWNpIHByaXNww7Rzb2JlbsO9Y2ggaG9kbsO0dCAgxI1vIGplIGRvYnLDvSBkw7RrYXogaG9tb3NjZWRhc3RpY2l0eS4KCi0gQWsgYnkgc2EgcmV6w61kdcOhIHJvenByZXN0aWVyYWxpICh0dm9yaWxpIGvDs251cyksIG5hem5hxI1vdmFsbyBieSB0byBoZXRlcm9za2VkYXN0aWNpdHUuCgotIE9kxL5haGzDqSBob2Rub3R5IC0gTmlla2/EvmtvIGJvZG92IChuYXByLiB2IGJsw616a29zdGkg4oiSMjApIGxlxb7DrSDEj2FsZWtvIG9kIG9zdGF0bsO9Y2gg4oCTIGlkZSBvIHBvdGVuY2nDoWxuZSBvZMS+YWhsw6kgaG9kbm90eSBhbGVibyB2cGx5dm7DqSBwb3pvcm92YW5pYS4KCk3DtMW+ZW1lIGljaCBwcmVza8O6bWHFpSBwb21vY291IG91dGxpZXJUZXN0KG1vZGVsKSAoeiBiYWzDrWthIGNhcikuCgojIyBRLVEgcGxvdAoKIyMjIMSMbyB1a2F6dWplCgoKLSBPcyBYOiBUZW9yZXRpY2vDqSBrdmFudGlseSDigJMgxI1vIGJ5IHNtZSBvxI1ha8OhdmFsaSwgYWsgYnkgcmV6w61kdcOhIGJvbGkgZG9rb25hbGUgbm9ybcOhbG5lIHJvemxvxb5lbsOpLgotIE9zIFk6IMWgdGFuZGFyZGl6b3ZhbsOpIHJlesOtZHXDoSDigJMgc2t1dG/EjW7DqSBrdmFudGlseSB6IHZhxaFlaiB2em9ya3kuCi0gNDXCsCBwcmVydcWhb3ZhbsOhIMSNaWFyYTogSWRlw6FsbnkgcHLDrXBhZCDigJMgYWsgc8O6IHJlesOtZHXDoSBub3Jtw6FsbmUgcm96bG/FvmVuw6ksIGJvZHkgYnkgbWFsaSBsZcW+YcWlIHRlc25lIHBvemTEusW+IHRlanRvIMSNaWFyeS4KCiMjIyBJbnRlcnByZXTDoWNpYSB2w6HFoWhvIGtvbmtyw6l0bmVobyBncmFmdQoKQ2Vsa292w70gdHZhcgoKVsOkxI3FoWluYSBib2RvdiBsZcW+w60gYmzDrXprbyBwcmlhbWt5IOKAlCB0byBuYXpuYcSNdWplLCDFvmUgcmV6w61kdcOhIHPDuiBwcmlibGnFvm5lIG5vcm3DoWxuZS4KClRvIGplIGRvYnLDqTogcHJlZHBva2xhZCBub3JtYWxpdHkgc2EgemTDoSBiecWlIHZvIHZlxL5rZWogbWllcmUgc3BsbmVuw70uCgpLcmFqbsOpIGhvZG5vdHkgKGV4dHLDqW15KQoKQm9keSBuYSBvYm9jaCBrb25jb2NoICh2xL5hdm8gZG9sZSBhIHZwcmF2byBob3JlKSBzYSBtaWVybmUgb2RjaHnEvnVqw7ogb2QgcHJpYW1reS4KClRvIG5hem5hxI11amUgbWllcm51IG5lbm9ybcOhbG5vc8WlIHYga29uY29jaCDigJMgbW/Fvm5vIG5pZWtvxL5rbyBvZMS+YWhsw71jaCBob2Ruw7R0IGFsZWJvIMWlYcW+xaFpZSBrb25jZSwgYWtvIGplIG5vcm3DoWxuZSAodHJvY2h1IMWhcGljYXRvc8WlKS4KClN0cmVkbsOhIG9ibGFzxaUKClN0cmVkbsOhIMSNYXPFpSBncmFmdSAo4oiSMSBhxb4gKzEga3ZhbnRpbHkpIHNhIHZlxL5taSBkb2JyZSB6aG9kdWplIOKAkyDEjW8gem5hbWVuw6EsIMW+ZSB2w6TEjcWhaW5hIHJlesOtZHXDrSBwZWtuZSB6YXBhZMOhIGRvIG5vcm3DoWxuZWhvIHJvemRlbGVuaWEuCgpaw6Fyb3ZlxYggdnlrb27DoXZhbWUgbsOhc2xlZG7DqSB0ZXN0eSwgdiBrdG9yw71jaCB6YW1pZXRhbWUgaHlwb3TDqXp1IG8gbm9ybcOhbG5vbSByb3psb8W+ZW7DrSBtb2RlbG92w71jaCBjaMO9YiwgYWtvIGFqIHByw610b21ub3PFpSBleHRyw6ltbnljaCBob2Ruw7R0LiAKCiMjIFNjYWxlIGxvY2F0aW9uIHBsb3QKCiMjIyDEjG8gdG8gem7DoXpvcsWIdWplCgpPcyBYOiBWeXJvdm5hbjAgaG9kbm90eSAKT3MgWTogRHJ1aMOhIG9kbW9jbmluYSBhYnNvbMO6dG55Y2ggxaF0YW5kYXJkaXpvdmFuw71jaCByZXrDrWR1w60gCsSMZXJ2ZW7DoSDEjWlhcmE6IExPRVNTICh2eWhsYWRlbsO9KSB0cmVuZCBjZXogYm9keQoKIyMjIEludGVycHJldMOhY2lhIG7DocWhaG8ga29ua3LDqXRuZWhvIGdyYWZ1CgpIb3Jpem9udMOhbG5lIHJvenB0w71sZW5pZQoKLSBCb2R5IHPDuiByb3Zub21lcm5lIHJvenB0w71sZW7DqSBwbyBvc2kgeCBiZXogdnl0dm9yZW5pYSBsaWV2aWthIGFsZWJvIGtyaXZreS4gVG8gbmF6bmHEjXVqZSBwcmlibGnFvm5lIGtvbsWhdGFudG7DuiB2YXJpYW5jaXUg4oCTIHJlesOtZHXDoSBzw7ogaG9tb3NjZWRhc3RpY2vDqS4KLSDEjGVydmVuw6EgaGxhZGvDoSDEjWlhcmEgamUgdGFrbWVyIHJvdm7DoSDigJMgxI9hbMWhw60gem5haywgxb5lIHByaSB6dnnFoW92YW7DrSB2eXJvdm5hbsO9Y2ggaG9kbsO0dCBuZWRvY2jDoWR6YSBrIMW+aWFkbmVqIHN5c3RlbWF0aWNrZWogem1lbmUgdmFyaWFuY2llLgotIE9kxL5haGzDqSBob2Rub3R5IC0gbmlla2/EvmtvIGJvZG92IGplIG1pZXJuZSBuYWQgMSw1LCBhbGUgxb5pYWRueSB6IG5pY2ggbmllIGplIGV4dHLDqW1ueSDigJMgdGFrxb5lIG5lZG9jaMOhZHphIGsgxb5pYWRueW0gesOhdmHFvm7DvW0gYW5vbcOhbGnDoW0gdmFyaWFuY2llLgoKIyMgcmVzaWR1YWxzIHZzIGxldmVyYWdlCgojIyMgxIxvIHpuw6F6b3LFiHVqZSBncmFmCgpPcyBYOiBQw6Frb3bDvSBlZmVrdCAg4oCUIG1lcmlhLCBha28gxI9hbGVrbyBqZSBwcmVkaWt0b3JvdsO9IHZla3RvciBib2R1ICBvZCBzdHJlZHUgdsWhZXRrw71jaCAK8J2RpQp4LgoKT3MgWTogxaB0YW5kYXJkaXpvdmFuw6kgcmV6w61kdcOhIOKAlCBha28gxI9hbGVrbyBqZSBwb3pvcm92YW7DoSBob2Rub3RhIAogb2Qgdnlyb3ZuYW5laiBob2Rub3R5IHYgamVkbm90a8OhY2ggxaF0YW5kYXJkbmVqIG9kY2jDvWxreS4KCkJvZGtvdmFuw6kga3Jpdmt5OiBLb250w7pyeSBDb29rb3ZlaiB2emRpYWxlbm9zdGksIGt0b3LDqSB1ZMOhdmFqw7osIGRvIGFrZWogbWllcnkgcG96b3JvdmFuaWUgb3ZwbHl2xYh1amUgcmVncmVzbsO6IHByaWFta3UuCgrEjGVydmVuw6EgxI1pYXJhOiBIbGFka8OhIExPRVNTIMSNaWFyYSBwcmVjaMOhZHphasO6Y2EgcmV6w61kdWFtaS5sbQoKIyMjIEludGVycHJldMOhY2lhIHbDocWhaG8ga29ua3LDqXRuZWhvIGdyYWZ1CgpSb3psb8W+ZW5pZSB2cGx5dnUKClbDpMSNxaFpbmEgcG96b3JvdmFuw60gbcOhIG7DrXpreSB2cGx5diAocG9kIDAsMDUpIOKAlCB0eXBpY2vDqSBwcmUgdmXEvmvDqSB2em9ya3kgYWxlYm8gZG9icmUgdnl2w6HFvmVuw6kgw7pkYWplLgoKSmVkZW4gYWxlYm8gZHZhIGJvZHkgKG5hcHIuIG9rb2xvIDAsMikgdnluaWthasO6IOKAkyBpZGUgbyBwb3pvcm92YW5pYSBzIHZ5c29rb3UgcMOha291LCDEjW8gem5hbWVuw6EsIMW+ZSBpY2ggaG9kbm90eSBzw7ogxI9hbGVrbyBvZCB2w6TEjcWhaW55IMO6ZGFqb3YuCgpWZcS+a29zxaUgcmV6w61kdcOtCgrFoHRhbmRhcmRpem92YW7DqSByZXrDrWR1w6EgdsOkxI3FoWlub3UgbWVkemkg4oiSMiBhICsyIOKAkyB0byBqZSBkb2Jyw6kgKMW+aWFkbmUgesOhdmHFvm7DqSB2w71uaW1reSB2IArwnZGmCnkpLgoKUG96b3JvdmFuaWUgb3puYcSNZW7DqSDEjcOtc2xvbSAxMTMgbcOhIHpkYW5saXZvIHN0cmVkbsO9IHZwbHl2IGEgcmVsYXTDrXZuZSB2ZcS+a8O6IHJlesOtZHXDoWxudSBob2Rub3R1IOKAkyBwb3RlbmNpw6FsbmUgdnBseXZuw70gcHLDrXBhZC4KCktvbnTDunJ5IENvb2tvdmVqIHZ6ZGlhbGVub3N0aQoKxb1pYWRlbiB6IGJvZG92IGphc25lIG5lcHJla3JhxI11amUgdm9ua2FqxaFpZSBsw61uaWUgQ29va292ZWogdnpkaWFsZW5vc3RpICjiiYgwLDUgYWxlYm8gMSwwKS4KClByZXRvIHNhIG5lemTDoSwgxb5lIGJ5IG5pZWt0b3LDqSBwb3pvcm92YW5pZSBuZXByaW1lcmFuZSBvdnBseXbFiG92YWxvIHJlZ3Jlc27DqSBrb2VmaWNpZW50eS4KCmBgYHtyfWxtCiMgbm9ybWFsaXR5IHRlc3RzCnJlc2lkdWFscyA8LSByZXNpZHVhbHMobW9kZWwpCmpiX3Rlc3QgPC0gamFycXVlLmJlcmEudGVzdChyZXNpZHVhbHMpCmpiX3Rlc3QKIyBvdXRsaWVyIHRlc3QgKHNlZSBwLXZhbHVlIGZvciBCb25mZXJyb25pIGNvcnJlY3Rpb24pCm91dGxpZXJfdGVzdCA8LSBvdXRsaWVyVGVzdChtb2RlbCkKb3V0bGllcl90ZXN0CmBgYAoKS2XEj8W+ZSBzYSBuZXByZXVrw6F6YWxhIG5vcm1hbGl0YSByZXrDrWR1w60sIHBva8O6c21lIHNhIGVsaW1pbm92YcWlIG9kxL5haGzDqSBob2Rub3R5IHYgcHLDrXBhZGUgR0RQIC0gZG9rw6HFvmVtZSB0byBsb2dhcml0bWlja291IHRyYW5zZm9ybcOhY2lvdSB0ZWp0byBwcmVtZW5uZWogYSB2eWzDusSNZW7DrW0gQk1JLCBrdG9yw6kgc2EgdWvDoXphbG8gYWtvIG5laW50ZXJwcmV0b3ZhdGXEvm7DqS4gTm92w6EgcmVncmVzaWEgYnVkZSBtYcWlIHR2YXIKCgpgYGB7cn0KbW9kZWwyIDwtIGxtKExpZmUuZXhwZWN0YW5jeSB+ICsxICsgSShsb2coR0RQKSkgKyBTY2hvb2xpbmcsZGF0YT11ZGFqZS4yMDE1KQpzdW1tYXJ5KG1vZGVsMikKYGBgCmBgYHtyIGRpYWdwbG90czIsIGZpZy5jYXA9IkRpYWdub3N0aWNrw6kgZ3JhZnkgcmVncmVzbsOpaG8gbW9kZWx1In0KIyBOYXN0YXZpxaUgcm96bG/FvmVuaWUgMiB4IDIKcGFyKG1mcm93ID0gYygyLCAyKSkKCiMgVnlrcmVzbGnFpSB2xaFldGt5IDQgZGlhZ25vc3RpY2vDqSBncmFmeSBtb2RlbHUKcGxvdChtb2RlbDIpCgojIChWb2xpdGXEvm7DqSkgcHJpZGHFpSBzcG9sb8SNbsO9IG5hZHBpcwojbXRleHQoIkRpYWdub3N0aWNrw6kgZ3JhZnkgcmVncmVzbsOpaG8gbW9kZWx1Iiwgb3V0ZXIgPSBUUlVFLCBjZXggPSAxLjIsIGZvbnQgPSAyKQoKIyBSZXNldG92YcWlIGxheW91dApwYXIobWZyb3cgPSBjKDEsIDEpKQpgYGAKCgoKCmBgYHtyfQojIG5vcm1hbGl0eSB0ZXN0cwpyZXNpZHVhbHMgPC0gcmVzaWR1YWxzKG1vZGVsKQpqYl90ZXN0IDwtIGphcnF1ZS5iZXJhLnRlc3QocmVzaWR1YWxzKQpqYl90ZXN0CiMgb3V0bGllciB0ZXN0IChzZWUgcC12YWx1ZSBmb3IgQm9uZmVycm9uaSBjb3JyZWN0aW9uKQpvdXRsaWVyX3Rlc3QgPC0gb3V0bGllclRlc3QobW9kZWwpCm91dGxpZXJfdGVzdApgYGAKCiMjQ29uY2x1c2lvbiMjCgpQcmVtZW5uw6kgKkdEUCosIGEgKlNjaG9vbGluZyogcHJlZGzFvnVqw7ogxaF0YXRpc2lja3kgdsO9em5hbW5lIHN0cmVkbsO6IGTEusW+a3Ugxb5pdm90YS4gTmEgZHJ1aGVqIHN0cmFuZSAqQk1JKiBuw6FtIGTDoXZhbG8gbmVpbnRlcnByZXRvdmF0ZcS+bsOpIHbDvXNsZWRreS4gUmV6w61kdcOhIG5ldnlrYXp1asO6IG5vcm3DoWxuZSByb3pkZWxlbmllLCBrZcSPxb5lIHbFoWFrIG3DoW1lIHZlxL5rw6kgbW5vxb5zdHZvIHBvem9yb3ZhbsOtLCBhaiBuYcSPYWxlaiBidWRlbWUgcHJhY292YcWlIHMgdMO9bWl0byDDumRham1pLiBWIG1vZGVsaSBzYSBuZXByZXVrYXp1asO6IMW+aWFkbmUgdsO9em5hbW7DqSBuZWxpbmVhcml0eS4KCg==