knitr::opts_chunk$set(
echo = TRUE,
message = FALSE,
warning = FALSE
)
library(zoo)
library(tseries)
library(lmtest)
library(sandwich)
library(car)
library(ggplot2)
library(patchwork)
library(quantmod)
Na začiatok si stiahneme naše dáta a z nich vypočítame logaritmické
výnosnosti, s ktorými následne budeme pracovať.
tickers <- c("AAPL", "GLD", "XLE", "SPY") # Apple, Gold ETF, Energy ETF, S&P500 ETF
getSymbols(tickers, from = "2024-01-01", to = "2025-01-01")
[1] "AAPL" "GLD" "XLE" "SPY"
data <- merge(Cl(AAPL), Cl(GLD), Cl(XLE), Cl(SPY))
colnames(data) <- tickers
ret <- na.omit(diff(log(data)))
colnames(ret) <- paste0(colnames(ret), "_ret")
ret_df <- na.omit(as.data.frame(ret))
head(ret_df)
op <- par(mfrow = c(2, 2), mar = c(4,4,2,1))
for (col in names(ret_df)) {
boxplot(ret_df[[col]], main = col, xlab = "Value", col = "purple")
}
par(op)

Boxploty znázorňujú rozdelenie denných logaritmických výnosov aktív
AAPL, GLD, XLE a SPY. Všetky výnosy sa sústreďujú okolo nuly, pričom
najväčšiu volatilitu vykazuje AAPL a najstabilnejšie hodnoty má GLD.
Mierne odľahlé body predstavujú extrémne pohyby na trhu, no celkové
rozdelenie je vyvážené a vhodné na ďalšiu analýzu.
model <- lm(AAPL_ret ~ GLD_ret + XLE_ret + SPY_ret, data = ret_df)
summary(model)
Call:
lm(formula = AAPL_ret ~ GLD_ret + XLE_ret + SPY_ret, data = ret_df)
Residuals:
Min 1Q Median 3Q Max
-0.044288 -0.006673 -0.000362 0.005717 0.066928
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.0003073 0.0007477 0.411 0.6814
GLD_ret 0.0028525 0.0818840 0.035 0.9722
XLE_ret -0.1950403 0.0705065 -2.766 0.0061 **
SPY_ret 1.0396059 0.1007431 10.319 <2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.01173 on 247 degrees of freedom
Multiple R-squared: 0.3122, Adjusted R-squared: 0.3038
F-statistic: 37.37 on 3 and 247 DF, p-value: < 2.2e-16
Model vysvetľuje závislosť výnosu akcie AAPL od výnosov GLD, XLE a
SPY. Z výsledkov vyplýva, že štatisticky významné premenné sú XLE (p =
0,0061) a SPY (p < 0,001). Premenná GLD významný vplyv nemá. Kladný
koeficient pri SPY (1,04) potvrdzuje silnú väzbu akcie Apple na celkový
trh, zatiaľ čo záporný koeficient pri XLE (-0,20) naznačuje mierny
opačný vzťah s energetickým sektorom. Hodnota R^2=0,31 znamená, že model
vysvetľuje približne 31 % variability výnosov akcie Apple.
op <- par(mfrow = c(2,2))
plot(model)
par(op)

library(ggfortify)
autoplot(model,
which = 1:4,
colour = "#c8a2c8", # svetlofialové body
smooth.colour = "#9d4edd", # jemnejšia fialová LOESS čiara
smooth.linetype = "solid",
size = 2,
label.size = 3) +
theme_minimal(base_size = 13) +
theme(
plot.title = element_text(color = "#5a189a", face = "bold", hjust = 0.5),
strip.text = element_text(color = "#5a189a", face = "bold"),
panel.grid.minor = element_blank(),
panel.background = element_rect(fill = "white", color = NA),
plot.background = element_rect(fill = "white", color = NA)
)

Diagnostické grafy ukazujú, že model je dobre špecifikovaný. Reziduá
sú rozložené rovnomerne okolo nuly, čo potvrdzuje absenciu výraznej
systematickej chyby. Q-Q graf naznačuje len mierne odchýlky od normality
na okrajoch rozdelenia. Graf Scale-Location potvrdzuje približne
konštantnú varianciu rezíduí (homoskedasticitu) a graf Residuals vs
Leverage neodhalil žiadne významné vplyvné pozorovania. Celkovo možno
model považovať za stabilný a spoľahlivý.Graf Cook’s distance naznačuje,
že žiadne pozorovanie výrazne neovplyvňuje stabilitu modelu, keďže
všetky hodnoty zostávajú bezpečne pod hranicou významného vplyvu.
# Jarque–Bera
jb_test <- tseries::jarque.bera.test(residuals(model)); jb_test
Jarque Bera Test
data: residuals(model)
X-squared = 279.24, df = 2, p-value < 2.2e-16
# Outlier test (Bonferroni)
outlier_car <- car::outlierTest(model); outlier_car
Jarque-Bera test ukázal, že reziduá modelu nie sú normálne rozdelené
(p-hodnota < 0,001), čo naznačuje prítomnosť extrémnych hodnôt. Test
odľahlých pozorovaní (Bonferroni) identifikoval tri dni – 21. 3. 2024,
3. 5. 2024 a 11. 6. 2024 – ako štatisticky významné odľahlé pozorovania,
ktoré mohli ovplyvniť výsledky regresie.
model2 <- lm(AAPL_ret ~ I(log(1 + SPY_ret)) + XLE_ret, data = ret_df)
summary(model2)
Call:
lm(formula = AAPL_ret ~ I(log(1 + SPY_ret)) + XLE_ret, data = ret_df)
Residuals:
Min 1Q Median 3Q Max
-0.044321 -0.006706 -0.000423 0.005711 0.066901
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.0003426 0.0007431 0.461 0.64516
I(log(1 + SPY_ret)) 1.0402443 0.0980078 10.614 < 2e-16 ***
XLE_ret -0.1953592 0.0696616 -2.804 0.00544 **
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 0.0117 on 248 degrees of freedom
Multiple R-squared: 0.313, Adjusted R-squared: 0.3074
F-statistic: 56.48 on 2 and 248 DF, p-value: < 2.2e-16
op <- par(mfrow = c(2,2))
plot(model2)
par(op)

# Normalita + outliers pre model2
tseries::jarque.bera.test(residuals(model2))
Jarque Bera Test
data: residuals(model2)
X-squared = 280.67, df = 2, p-value < 2.2e-16
autoplot(model2,
which = 1:4,
colour = "#c8a2c8", # svetlofialové body
smooth.colour = "#9d4edd", # jemnejšia fialová LOESS čiara
smooth.linetype = "solid",
size = 2,
label.size = 3) +
theme_minimal(base_size = 13) +
theme(
plot.title = element_text(color = "#5a189a", face = "bold", hjust = 0.5),
strip.text = element_text(color = "#5a189a", face = "bold"),
panel.grid.minor = element_blank(),
panel.background = element_rect(fill = "white", color = NA),
plot.background = element_rect(fill = "white", color = NA)
)

Po úprave modelu (logaritmická transformácia SPY_ret) sa štruktúra
rezíduí zlepšila, hoci Jarque-Bera test stále naznačuje mierne odchýlky
od normality. Outlier test opäť identifikoval rovnaké tri dni – 21. 3.
2024, 3. 5. 2024 a 11. 6. 2024 – ako odľahlé pozorovania, avšak ich
vplyv na model je už menší. Celkovo možno povedať, že transformácia
prispela k stabilnejšiemu a robustnejšiemu modelu.
# Pôvodný model
p1 <- ggplot(ret_df, aes(x = SPY_ret, y = resid(model)^2)) +
geom_point(alpha = 0.6) +
geom_smooth(method = "loess", se = FALSE, color = "purple") +
labs(x = "SPY_ret", y = "Squared residuals", title = "Squared residuals vs SPY_ret") +
theme_minimal()
p2 <- ggplot(ret_df, aes(x = XLE_ret, y = resid(model)^2)) +
geom_point(alpha = 0.6) +
geom_smooth(method = "loess", se = FALSE, color = "purple") +
labs(x = "XLE_ret", y = "Squared residuals", title = "Squared residuals vs XLE_ret") +
theme_minimal()
p1 + p2

Grafy zobrazujú závislosť štvorcov rezíduí od výnosov SPY_ret a
XLE_ret s cieľom overiť prítomnosť heteroskedasticity. Červená
vyhladzovacia krivka je takmer vodorovná, čo naznačuje, že rozptyl
rezíduí zostáva približne konštantný pri rôznych hodnotách oboch
premenných. Nevidíme žiadny rozširujúci sa alebo zužujúci tvar, preto
možno konštatovať, že v modeli sa heteroskedasticita nevyskytuje.
# Upravený model (model2) s log(1+SPY_ret)
p3 <- ggplot(ret_df, aes(x = log(1 + SPY_ret), y = resid(model2)^2)) +
geom_point(alpha = 0.6) +
geom_smooth(method = "loess", se = FALSE, color = "purple") +
labs(x = "log(1 + SPY_ret)", y = "Squared residuals", title = "Residuals vs log(1+SPY_ret)") +
theme_minimal()
p4 <- ggplot(ret_df, aes(x = XLE_ret, y = resid(model2)^2)) +
geom_point(alpha = 0.6) +
geom_smooth(method = "loess", se = FALSE, color = "purple") +
labs(x = "XLE_ret", y = "Squared residuals", title = "Residuals vs XLE_ret (model2)") +
theme_minimal()
p3 + p4

Grafy zobrazujú závislosť štvorcov rezíduí od premenných log(1 +
SPY_ret) a XLE_ret po logaritmickej transformácii v modeli 2. Červená
vyhladzovacia krivka zostáva takmer vodorovná, čo naznačuje, že rozptyl
rezíduí sa s hodnotami vysvetľujúcich premenných výrazne nemení. Z toho
vyplýva, že transformácia úspešne odstránila heteroskedasticitu a model
má konštantný rozptyl chýb.
studentized Breusch-Pagan test
data: model
BP = 0.48024, df = 3, p-value = 0.9232
studentized Breusch-Pagan test
data: model2
BP = 0.48542, df = 2, p-value = 0.7845
Výsledky Breusch–Pagan testu pre oba modely ukazujú, že p-hodnoty
(0,9232 a 0,7845) sú výrazne vyššie než 0,05. To znamená, že nezamietame
nulovú hypotézu o homoskedasticite rezíduí. Inými slovami, rozptyl chýb
je konštantný a v modeloch nie je prítomná heteroskedasticita, čo
potvrdzuje ich spoľahlivosť.
# Robustné SE pre model2 (doporučené reportovať)
lmtest::coeftest(model2, vcov = sandwich::vcovHC(model2, type = "HC1"))
t test of coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 0.00034261 0.00073427 0.4666 0.641193
I(log(1 + SPY_ret)) 1.04024435 0.09913013 10.4937 < 2.2e-16 ***
XLE_ret -0.19535922 0.06000130 -3.2559 0.001288 **
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Tabuľka zobrazuje výsledky robustnej regresie s upravenými
smerodajnými chybami (HC1), ktoré zohľadňujú možnú
heteroskedasticitu.
Premenná log(1 + SPY_ret) má silne pozitívny a štatisticky významný
vplyv (p < 0.001) na výnos akcie AAPL, čo znamená, že Apple sa správa
veľmi podobne ako trhový index SPY. Premenná XLE_ret má negatívny a
štatisticky významný vplyv (p < 0.01), teda rast energetického
sektora súvisí s miernym poklesom výnosov Apple. Konštanta (intercept)
nie je štatisticky významná, čo naznačuje, že pri nulových výnosoch SPY
a XLE je priemerný výnos AAPL blízky nule.
# Durbin–Watson (autokorelácia rezíduí)
lmtest::dwtest(model2)
Durbin-Watson test
data: model2
DW = 2.0406, p-value = 0.6239
alternative hypothesis: true autocorrelation is greater than 0
# RESET (nelinearity/špecifikácia)
lmtest::resettest(model2, power = 2:3, type = "fitted")
RESET test
data: model2
RESET = 1.3159, df1 = 2, df2 = 246, p-value = 0.2701
# VIF (multikolinearita)
car::vif(model2)
I(log(1 + SPY_ret)) XLE_ret
1.109609 1.109609
Výsledky doplnkových testov potvrdzujú, že vytvorený model je
štatisticky spoľahlivý a správne špecifikovaný. Hodnota
Durbin–Watsonovho testu (DW = 2.04, p = 0.62) naznačuje, že v rezíduách
sa nenachádza autokorelácia, čo znamená, že chyby nie sú navzájom
závislé a model spĺňa predpoklad nezávislosti rezíduí. RESET test s
p-hodnotou 0.27 nepreukázal žiadne problémy so špecifikáciou modelu,
teda model má správne zvolenú funkčnú formu a nie je potrebné pridávať
nelineárne členy. Výsledky VIF (Variance Inflation Factor) s hodnotou
1.1 pre obe vysvetľujúce premenné potvrdzujú, že medzi nimi neexistuje
multikolinearita. Celkovo možno konštatovať, že model je dobre
špecifikovaný, rezíduá sú nezávislé a vysvetľujúce premenné nie sú
navzájom závislé.
library(knitr)
library(dplyr)
results <- data.frame(
Test = c("Durbin–Watson", "RESET", "VIF (I(log(1+SPY_ret)))", "VIF (XLE_ret)"),
Statistic = c(2.0406, 1.3159, 1.1096, 1.1096),
`p-hodnota` = c(0.6239, 0.2701, NA, NA),
Interpretácia = c(
"Bez autokorelácie rezíduí",
"Bez problémov so špecifikáciou modelu",
"Žiadna multikolinearita",
"Žiadna multikolinearita"
)
)
kable(results, caption = "Súhrn doplnkových diagnostických testov pre model2")
Súhrn doplnkových diagnostických testov pre model2
| Test |
Statistic |
p.hodnota |
Interpretácia |
| Durbin–Watson |
2.0406 |
0.6239 |
Bez autokorelácie rezíduí |
| RESET |
1.3159 |
0.2701 |
Bez problémov so špecifikáciou modelu |
| VIF (I(log(1+SPY_ret))) |
1.1096 |
NA |
Žiadna multikolinearita |
| VIF (XLE_ret) |
1.1096 |
NA |
Žiadna multikolinearita |
Tabuľka zobrazuje výsledky doplnkových diagnostických testov pre
model 2. Durbin–Watson test potvrdzuje, že rezíduá nie sú
autokorelované. RESET test ukazuje, že model je správne špecifikovaný a
neobsahuje nelineárne chyby. Hodnoty VIF sú veľmi nízke, čo znamená, že
medzi vysvetľujúcimi premennými neexistuje multikolinearita. Celkovo
možno model považovať za stabilný a štatisticky spoľahlivý.
LS0tCnRpdGxlOiAixaBpZXN0YSDDumxvaGEiCmF1dGhvcjogJyBNaXJvc2xhdmEgTWVkdmVja8OhICA8YnI+JwpkYXRlOiAiU2VwdGVtYmVyIDIwMjUiCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIHRoZW1lOiB1bml0ZWQKICAgIGhpZ2hsaWdodDogdGFuZ28KICBodG1sX2RvY3VtZW50OgogICAgdG9jOiB0cnVlCiAgICBkZl9wcmludDogcGFnZWQKZWRpdG9yX29wdGlvbnM6CiAgbWFya2Rvd246CiAgICB3cmFwOiA3MgotLS0KYGBge3J9CmtuaXRyOjpvcHRzX2NodW5rJHNldCgKICAgIGVjaG8gPSBUUlVFLAogICAgbWVzc2FnZSA9IEZBTFNFLAogICAgd2FybmluZyA9IEZBTFNFCikKYGBgCgo8c3R5bGU+Ci8qIENlbGtvdsOpIHBvemFkaWUgKi8KYm9keSB7CiAgYmFja2dyb3VuZDogbGluZWFyLWdyYWRpZW50KDEzNWRlZywgI2YzZThmZiwgI2U5ZDVmZiwgI2VkZTlmZSk7CiAgZm9udC1mYW1pbHk6ICdIZWx2ZXRpY2EgTmV1ZScsIEhlbHZldGljYSwgQXJpYWwsIHNhbnMtc2VyaWY7CiAgY29sb3I6ICMyZTA4NTQ7CiAgbGluZS1oZWlnaHQ6IDEuNzsKICBwYWRkaW5nOiAyNXB4Owp9CgovKiBIbGF2bsOpIG5hZHBpc3kgKi8KaDEsIGgyLCBoMyB7CiAgZm9udC1mYW1pbHk6ICdIZWx2ZXRpY2EgTmV1ZScsIEhlbHZldGljYSwgQXJpYWwsIHNhbnMtc2VyaWY7CiAgbGV0dGVyLXNwYWNpbmc6IDAuNXB4OwogIGNvbG9yOiAjNGIwMDgyOyAvKiB0bWF2b2ZpYWxvdsOhICovCiAgdGV4dC1zaGFkb3c6IDBweCAxcHggMnB4ICNlOWQ1ZmY7Cn0KPC9zdHlsZT4KCmBgYHtyfQpsaWJyYXJ5KHpvbykKbGlicmFyeSh0c2VyaWVzKQpsaWJyYXJ5KGxtdGVzdCkKbGlicmFyeShzYW5kd2ljaCkKbGlicmFyeShjYXIpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShwYXRjaHdvcmspCmxpYnJhcnkocXVhbnRtb2QpCmBgYAogICAgIApOYSB6YcSNaWF0b2sgc2kgc3RpYWhuZW1lIG5hxaFlIGTDoXRhIGEgeiBuaWNoIHZ5cG/EjcOtdGFtZSBsb2dhcml0bWlja8OpIHbDvW5vc25vc3RpLCBzIGt0b3LDvW1pIG7DoXNsZWRuZSBidWRlbWUgcHJhY292YcWlLiAgICAgIApgYGB7cn0KdGlja2VycyA8LSBjKCJBQVBMIiwgIkdMRCIsICJYTEUiLCAiU1BZIikgICAjIEFwcGxlLCBHb2xkIEVURiwgRW5lcmd5IEVURiwgUyZQNTAwIEVURgpnZXRTeW1ib2xzKHRpY2tlcnMsIGZyb20gPSAiMjAyNC0wMS0wMSIsIHRvID0gIjIwMjUtMDEtMDEiKQoKZGF0YSA8LSBtZXJnZShDbChBQVBMKSwgQ2woR0xEKSwgQ2woWExFKSwgQ2woU1BZKSkKY29sbmFtZXMoZGF0YSkgPC0gdGlja2VycwoKcmV0IDwtIG5hLm9taXQoZGlmZihsb2coZGF0YSkpKQpjb2xuYW1lcyhyZXQpIDwtIHBhc3RlMChjb2xuYW1lcyhyZXQpLCAiX3JldCIpCgpyZXRfZGYgPC0gbmEub21pdChhcy5kYXRhLmZyYW1lKHJldCkpCmhlYWQocmV0X2RmKQpgYGAKICAgICAKYGBge3J9Cm9wIDwtIHBhcihtZnJvdyA9IGMoMiwgMiksIG1hciA9IGMoNCw0LDIsMSkpCmZvciAoY29sIGluIG5hbWVzKHJldF9kZikpIHsKICBib3hwbG90KHJldF9kZltbY29sXV0sIG1haW4gPSBjb2wsIHhsYWIgPSAiVmFsdWUiLCBjb2wgPSAicHVycGxlIikKfQpwYXIob3ApCmBgYAogICAgIApCb3hwbG90eSB6bsOhem9yxYh1asO6IHJvemRlbGVuaWUgZGVubsO9Y2ggbG9nYXJpdG1pY2vDvWNoIHbDvW5vc292IGFrdMOtdiBBQVBMLCBHTEQsIFhMRSBhIFNQWS4gVsWhZXRreSB2w71ub3N5IHNhIHPDunN0cmXEj3Vqw7ogb2tvbG8gbnVseSwgcHJpxI1vbSBuYWp2w6TEjcWhaXUgdm9sYXRpbGl0dSB2eWthenVqZSBBQVBMIGEgbmFqc3RhYmlsbmVqxaFpZSBob2Rub3R5IG3DoSBHTEQuIE1pZXJuZSBvZMS+YWhsw6kgYm9keSBwcmVkc3RhdnVqw7ogZXh0csOpbW5lIHBvaHlieSBuYSB0cmh1LCBubyBjZWxrb3bDqSByb3pkZWxlbmllIGplIHZ5dsOhxb5lbsOpIGEgdmhvZG7DqSBuYSDEj2FsxaFpdSBhbmFsw716dS4gICAgIApgYGB7cn0KbW9kZWwgPC0gbG0oQUFQTF9yZXQgfiBHTERfcmV0ICsgWExFX3JldCArIFNQWV9yZXQsIGRhdGEgPSByZXRfZGYpCnN1bW1hcnkobW9kZWwpCmBgYAogICAgIApNb2RlbCB2eXN2ZXTEvnVqZSB6w6F2aXNsb3PFpSB2w71ub3N1IGFrY2llIEFBUEwgb2QgdsO9bm9zb3YgR0xELCBYTEUgYSBTUFkuIFogdsO9c2xlZGtvdiB2eXBsw712YSwgxb5lIMWhdGF0aXN0aWNreSB2w716bmFtbsOpIHByZW1lbm7DqSBzw7ogWExFIChwID0gMCwwMDYxKSBhIFNQWSAocCA8IDAsMDAxKS4gUHJlbWVubsOhIEdMRCB2w716bmFtbsO9IHZwbHl2IG5lbcOhLiBLbGFkbsO9IGtvZWZpY2llbnQgcHJpIFNQWSAoMSwwNCkgcG90dnJkenVqZSBzaWxuw7ogdsOkemJ1IGFrY2llIEFwcGxlIG5hIGNlbGtvdsO9IHRyaCwgemF0aWHEviDEjW8gesOhcG9ybsO9IGtvZWZpY2llbnQgcHJpIFhMRSAoLTAsMjApIG5hem5hxI11amUgbWllcm55IG9wYcSNbsO9IHZ6xaVhaCBzIGVuZXJnZXRpY2vDvW0gc2VrdG9yb20uIEhvZG5vdGEgUl4yPTAsMzEgem5hbWVuw6EsIMW+ZSBtb2RlbCB2eXN2ZXTEvnVqZSBwcmlibGnFvm5lIDMxICUgdmFyaWFiaWxpdHkgdsO9bm9zb3YgYWtjaWUgQXBwbGUuCiAgICAgCmBgYHtyfQpvcCA8LSBwYXIobWZyb3cgPSBjKDIsMikpCnBsb3QobW9kZWwpCnBhcihvcCkKYGBgCmBgYHtyfQpsaWJyYXJ5KGdnZm9ydGlmeSkKCmF1dG9wbG90KG1vZGVsLCAKICAgICAgICAgd2hpY2ggPSAxOjQsIAogICAgICAgICBjb2xvdXIgPSAiI2M4YTJjOCIsICAgICAgICAgICMgc3ZldGxvZmlhbG92w6kgYm9keQogICAgICAgICBzbW9vdGguY29sb3VyID0gIiM5ZDRlZGQiLCAgICMgamVtbmVqxaFpYSBmaWFsb3bDoSBMT0VTUyDEjWlhcmEKICAgICAgICAgc21vb3RoLmxpbmV0eXBlID0gInNvbGlkIiwKICAgICAgICAgc2l6ZSA9IDIsCiAgICAgICAgIGxhYmVsLnNpemUgPSAzKSArCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxMykgKwogIHRoZW1lKAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChjb2xvciA9ICIjNWExODlhIiwgZmFjZSA9ICJib2xkIiwgaGp1c3QgPSAwLjUpLAogICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChjb2xvciA9ICIjNWExODlhIiwgZmFjZSA9ICJib2xkIiksCiAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLAogICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIndoaXRlIiwgY29sb3IgPSBOQSksCiAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ3aGl0ZSIsIGNvbG9yID0gTkEpCiAgKQpgYGAKCkRpYWdub3N0aWNrw6kgZ3JhZnkgdWthenVqw7osIMW+ZSBtb2RlbCBqZSBkb2JyZSDFoXBlY2lmaWtvdmFuw70uIFJlemlkdcOhIHPDuiByb3psb8W+ZW7DqSByb3Zub21lcm5lIG9rb2xvIG51bHksIMSNbyBwb3R2cmR6dWplIGFic2VuY2l1IHbDvXJhem5laiBzeXN0ZW1hdGlja2VqIGNoeWJ5LiBRLVEgZ3JhZiBuYXpuYcSNdWplIGxlbiBtaWVybmUgb2RjaMO9bGt5IG9kIG5vcm1hbGl0eSBuYSBva3Jham9jaCByb3pkZWxlbmlhLiBHcmFmIFNjYWxlLUxvY2F0aW9uIHBvdHZyZHp1amUgcHJpYmxpxb5uZSBrb27FoXRhbnRuw7ogdmFyaWFuY2l1IHJlesOtZHXDrSAoaG9tb3NrZWRhc3RpY2l0dSkgYSBncmFmIFJlc2lkdWFscyB2cyBMZXZlcmFnZSBuZW9kaGFsaWwgxb5pYWRuZSB2w716bmFtbsOpIHZwbHl2bsOpIHBvem9yb3ZhbmlhLiBDZWxrb3ZvIG1vxb5ubyBtb2RlbCBwb3Zhxb5vdmHFpSB6YSBzdGFiaWxuw70gYSBzcG/EvmFobGl2w70uR3JhZiBDb29r4oCZcyBkaXN0YW5jZSBuYXpuYcSNdWplLCDFvmUgxb5pYWRuZSBwb3pvcm92YW5pZSB2w71yYXpuZSBuZW92cGx5dsWIdWplIHN0YWJpbGl0dSBtb2RlbHUsIGtlxI/FvmUgdsWhZXRreSBob2Rub3R5IHpvc3TDoXZhasO6IGJlenBlxI1uZSBwb2QgaHJhbmljb3UgdsO9em5hbW7DqWhvIHZwbHl2dS4KICAgIApgYGB7cn0KIyBKYXJxdWXigJNCZXJhCmpiX3Rlc3QgPC0gdHNlcmllczo6amFycXVlLmJlcmEudGVzdChyZXNpZHVhbHMobW9kZWwpKTsgamJfdGVzdAoKIyBPdXRsaWVyIHRlc3QgKEJvbmZlcnJvbmkpCm91dGxpZXJfY2FyIDwtIGNhcjo6b3V0bGllclRlc3QobW9kZWwpOyBvdXRsaWVyX2NhcgpgYGAKCkphcnF1ZS1CZXJhIHRlc3QgdWvDoXphbCwgxb5lIHJlemlkdcOhIG1vZGVsdSBuaWUgc8O6IG5vcm3DoWxuZSByb3pkZWxlbsOpIChwLWhvZG5vdGEgPCAwLDAwMSksIMSNbyBuYXpuYcSNdWplIHByw610b21ub3PFpSBleHRyw6ltbnljaCBob2Ruw7R0LiBUZXN0IG9kxL5haGzDvWNoIHBvem9yb3ZhbsOtIChCb25mZXJyb25pKSBpZGVudGlmaWtvdmFsIHRyaSBkbmkg4oCTIDIxLiAzLiAyMDI0LCAzLiA1LiAyMDI0IGEgMTEuIDYuIDIwMjQg4oCTIGFrbyDFoXRhdGlzdGlja3kgdsO9em5hbW7DqSBvZMS+YWhsw6kgcG96b3JvdmFuaWEsIGt0b3LDqSBtb2hsaSBvdnBseXZuacWlIHbDvXNsZWRreSByZWdyZXNpZS4gICAgCgpgYGB7cn0KbW9kZWwyIDwtIGxtKEFBUExfcmV0IH4gSShsb2coMSArIFNQWV9yZXQpKSArIFhMRV9yZXQsIGRhdGEgPSByZXRfZGYpCnN1bW1hcnkobW9kZWwyKQoKb3AgPC0gcGFyKG1mcm93ID0gYygyLDIpKQpwbG90KG1vZGVsMikKcGFyKG9wKQoKIyBOb3JtYWxpdGEgKyBvdXRsaWVycyBwcmUgbW9kZWwyCnRzZXJpZXM6OmphcnF1ZS5iZXJhLnRlc3QocmVzaWR1YWxzKG1vZGVsMikpCmNhcjo6b3V0bGllclRlc3QobW9kZWwyKQpgYGAKCmBgYHtyfQphdXRvcGxvdChtb2RlbDIsIAogICAgICAgICB3aGljaCA9IDE6NCwgCiAgICAgICAgIGNvbG91ciA9ICIjYzhhMmM4IiwgICAgICAgICAgIyBzdmV0bG9maWFsb3bDqSBib2R5CiAgICAgICAgIHNtb290aC5jb2xvdXIgPSAiIzlkNGVkZCIsICAgIyBqZW1uZWrFoWlhIGZpYWxvdsOhIExPRVNTIMSNaWFyYQogICAgICAgICBzbW9vdGgubGluZXR5cGUgPSAic29saWQiLAogICAgICAgICBzaXplID0gMiwKICAgICAgICAgbGFiZWwuc2l6ZSA9IDMpICsKICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDEzKSArCiAgdGhlbWUoCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGNvbG9yID0gIiM1YTE4OWEiLCBmYWNlID0gImJvbGQiLCBoanVzdCA9IDAuNSksCiAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KGNvbG9yID0gIiM1YTE4OWEiLCBmYWNlID0gImJvbGQiKSwKICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAid2hpdGUiLCBjb2xvciA9IE5BKSwKICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIndoaXRlIiwgY29sb3IgPSBOQSkKICApCmBgYApQbyDDunByYXZlIG1vZGVsdSAobG9nYXJpdG1pY2vDoSB0cmFuc2Zvcm3DoWNpYSBTUFlfcmV0KSBzYSDFoXRydWt0w7pyYSByZXrDrWR1w60gemxlcMWhaWxhLCBob2NpIEphcnF1ZS1CZXJhIHRlc3Qgc3TDoWxlIG5hem5hxI11amUgbWllcm5lIG9kY2jDvWxreSBvZCBub3JtYWxpdHkuIE91dGxpZXIgdGVzdCBvcMOkxaUgaWRlbnRpZmlrb3ZhbCByb3ZuYWvDqSB0cmkgZG5pIOKAkyAyMS4gMy4gMjAyNCwgMy4gNS4gMjAyNCBhIDExLiA2LiAyMDI0IOKAkyBha28gb2TEvmFobMOpIHBvem9yb3ZhbmlhLCBhdsWhYWsgaWNoIHZwbHl2IG5hIG1vZGVsIGplIHXFviBtZW7FocOtLiBDZWxrb3ZvIG1vxb5ubyBwb3ZlZGHFpSwgxb5lIHRyYW5zZm9ybcOhY2lhIHByaXNwZWxhIGsgc3RhYmlsbmVqxaFpZW11IGEgcm9idXN0bmVqxaFpZW11IG1vZGVsdS4gIAoKYGBge3J9CiMgUMO0dm9kbsO9IG1vZGVsCnAxIDwtIGdncGxvdChyZXRfZGYsIGFlcyh4ID0gU1BZX3JldCwgeSA9IHJlc2lkKG1vZGVsKV4yKSkgKwogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjYpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG9lc3MiLCBzZSA9IEZBTFNFLCBjb2xvciA9ICJwdXJwbGUiKSArCiAgbGFicyh4ID0gIlNQWV9yZXQiLCB5ID0gIlNxdWFyZWQgcmVzaWR1YWxzIiwgdGl0bGUgPSAiU3F1YXJlZCByZXNpZHVhbHMgdnMgU1BZX3JldCIpICsKICB0aGVtZV9taW5pbWFsKCkKCnAyIDwtIGdncGxvdChyZXRfZGYsIGFlcyh4ID0gWExFX3JldCwgeSA9IHJlc2lkKG1vZGVsKV4yKSkgKwogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjYpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG9lc3MiLCBzZSA9IEZBTFNFLCBjb2xvciA9ICJwdXJwbGUiKSArCiAgbGFicyh4ID0gIlhMRV9yZXQiLCB5ID0gIlNxdWFyZWQgcmVzaWR1YWxzIiwgdGl0bGUgPSAiU3F1YXJlZCByZXNpZHVhbHMgdnMgWExFX3JldCIpICsKICB0aGVtZV9taW5pbWFsKCkKCnAxICsgcDIKYGBgCkdyYWZ5IHpvYnJhenVqw7ogesOhdmlzbG9zxaUgxaF0dm9yY292IHJlesOtZHXDrSBvZCB2w71ub3NvdiBTUFlfcmV0IGEgWExFX3JldCBzIGNpZcS+b20gb3ZlcmnFpSBwcsOtdG9tbm9zxaUgaGV0ZXJvc2tlZGFzdGljaXR5LiDEjGVydmVuw6EgdnlobGFkem92YWNpYSBrcml2a2EgamUgdGFrbWVyIHZvZG9yb3Zuw6EsIMSNbyBuYXpuYcSNdWplLCDFvmUgcm96cHR5bCByZXrDrWR1w60gem9zdMOhdmEgcHJpYmxpxb5uZSBrb27FoXRhbnRuw70gcHJpIHLDtHpueWNoIGhvZG5vdMOhY2ggb2JvY2ggcHJlbWVubsO9Y2guIE5ldmlkw61tZSDFvmlhZG55IHJvesWhaXJ1asO6Y2kgc2EgYWxlYm8genXFvnVqw7pjaSB0dmFyLCBwcmV0byBtb8W+bm8ga29uxaF0YXRvdmHFpSwgxb5lIHYgbW9kZWxpIHNhIGhldGVyb3NrZWRhc3RpY2l0YSBuZXZ5c2t5dHVqZS4KYGBge3J9CiMgVXByYXZlbsO9IG1vZGVsIChtb2RlbDIpIHMgbG9nKDErU1BZX3JldCkKcDMgPC0gZ2dwbG90KHJldF9kZiwgYWVzKHggPSBsb2coMSArIFNQWV9yZXQpLCB5ID0gcmVzaWQobW9kZWwyKV4yKSkgKwogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjYpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG9lc3MiLCBzZSA9IEZBTFNFLCBjb2xvciA9ICJwdXJwbGUiKSArCiAgbGFicyh4ID0gImxvZygxICsgU1BZX3JldCkiLCB5ID0gIlNxdWFyZWQgcmVzaWR1YWxzIiwgdGl0bGUgPSAiUmVzaWR1YWxzIHZzIGxvZygxK1NQWV9yZXQpIikgKwogIHRoZW1lX21pbmltYWwoKQoKcDQgPC0gZ2dwbG90KHJldF9kZiwgYWVzKHggPSBYTEVfcmV0LCB5ID0gcmVzaWQobW9kZWwyKV4yKSkgKwogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjYpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG9lc3MiLCBzZSA9IEZBTFNFLCBjb2xvciA9ICJwdXJwbGUiKSArCiAgbGFicyh4ID0gIlhMRV9yZXQiLCB5ID0gIlNxdWFyZWQgcmVzaWR1YWxzIiwgdGl0bGUgPSAiUmVzaWR1YWxzIHZzIFhMRV9yZXQgKG1vZGVsMikiKSArCiAgdGhlbWVfbWluaW1hbCgpCgpwMyArIHA0CmBgYApHcmFmeSB6b2JyYXp1asO6IHrDoXZpc2xvc8WlIMWhdHZvcmNvdiByZXrDrWR1w60gb2QgcHJlbWVubsO9Y2ggbG9nKDEgKyBTUFlfcmV0KSBhIFhMRV9yZXQgcG8gbG9nYXJpdG1pY2tlaiB0cmFuc2Zvcm3DoWNpaSB2IG1vZGVsaSAyLiDEjGVydmVuw6EgdnlobGFkem92YWNpYSBrcml2a2Egem9zdMOhdmEgdGFrbWVyIHZvZG9yb3Zuw6EsIMSNbyBuYXpuYcSNdWplLCDFvmUgcm96cHR5bCByZXrDrWR1w60gc2EgcyBob2Rub3RhbWkgdnlzdmV0xL51asO6Y2ljaCBwcmVtZW5uw71jaCB2w71yYXpuZSBuZW1lbsOtLiBaIHRvaG8gdnlwbMO9dmEsIMW+ZSB0cmFuc2Zvcm3DoWNpYSDDunNwZcWhbmUgb2RzdHLDoW5pbGEgaGV0ZXJvc2tlZGFzdGljaXR1IGEgbW9kZWwgbcOhIGtvbsWhdGFudG7DvSByb3pwdHlsIGNow71iLgpgYGB7cn0KbG10ZXN0OjpicHRlc3QobW9kZWwpCmxtdGVzdDo6YnB0ZXN0KG1vZGVsMikKYGBgCgpWw71zbGVka3kgQnJldXNjaOKAk1BhZ2FuIHRlc3R1IHByZSBvYmEgbW9kZWx5IHVrYXp1asO6LCDFvmUgcC1ob2Rub3R5ICgwLDkyMzIgYSAwLDc4NDUpIHPDuiB2w71yYXpuZSB2ecWhxaFpZSBuZcW+IDAsMDUuIFRvIHpuYW1lbsOhLCDFvmUgbmV6YW1pZXRhbWUgbnVsb3bDuiBoeXBvdMOpenUgbyBob21vc2tlZGFzdGljaXRlIHJlesOtZHXDrS4gSW7DvW1pIHNsb3ZhbWksIHJvenB0eWwgY2jDvWIgamUga29uxaF0YW50bsO9IGEgdiBtb2RlbG9jaCBuaWUgamUgcHLDrXRvbW7DoSBoZXRlcm9za2VkYXN0aWNpdGEsIMSNbyBwb3R2cmR6dWplIGljaCBzcG/EvmFobGl2b3PFpS4KYGBge3J9CiMgUm9idXN0bsOpIFNFIHByZSBtb2RlbDIgKGRvcG9ydcSNZW7DqSByZXBvcnRvdmHFpSkKbG10ZXN0Ojpjb2VmdGVzdChtb2RlbDIsIHZjb3YgPSBzYW5kd2ljaDo6dmNvdkhDKG1vZGVsMiwgdHlwZSA9ICJIQzEiKSkKYGBgClRhYnXEvmthIHpvYnJhenVqZSB2w71zbGVka3kgcm9idXN0bmVqIHJlZ3Jlc2llIHMgdXByYXZlbsO9bWkgc21lcm9kYWpuw71taSBjaHliYW1pIChIQzEpLCBrdG9yw6kgem9oxL5hZMWIdWrDuiBtb8W+bsO6IGhldGVyb3NrZWRhc3RpY2l0dS4KClByZW1lbm7DoSBsb2coMSArIFNQWV9yZXQpIG3DoSBzaWxuZSBwb3ppdMOtdm55IGEgxaF0YXRpc3RpY2t5IHbDvXpuYW1uw70gdnBseXYgKHAgPCAwLjAwMSkgbmEgdsO9bm9zIGFrY2llIEFBUEwsIMSNbyB6bmFtZW7DoSwgxb5lIEFwcGxlIHNhIHNwcsOhdmEgdmXEvm1pIHBvZG9ibmUgYWtvIHRyaG92w70gaW5kZXggU1BZLgpQcmVtZW5uw6EgWExFX3JldCBtw6EgbmVnYXTDrXZueSBhIMWhdGF0aXN0aWNreSB2w716bmFtbsO9IHZwbHl2IChwIDwgMC4wMSksIHRlZGEgcmFzdCBlbmVyZ2V0aWNrw6lobyBzZWt0b3JhIHPDunZpc8OtIHMgbWllcm55bSBwb2tsZXNvbSB2w71ub3NvdiBBcHBsZS4KS29uxaF0YW50YSAoaW50ZXJjZXB0KSBuaWUgamUgxaF0YXRpc3RpY2t5IHbDvXpuYW1uw6EsIMSNbyBuYXpuYcSNdWplLCDFvmUgcHJpIG51bG92w71jaCB2w71ub3NvY2ggU1BZIGEgWExFIGplIHByaWVtZXJuw70gdsO9bm9zIEFBUEwgYmzDrXpreSBudWxlLgpgYGB7cn0KIyBEdXJiaW7igJNXYXRzb24gKGF1dG9rb3JlbMOhY2lhIHJlesOtZHXDrSkKbG10ZXN0Ojpkd3Rlc3QobW9kZWwyKQoKIyBSRVNFVCAobmVsaW5lYXJpdHkvxaFwZWNpZmlrw6FjaWEpCmxtdGVzdDo6cmVzZXR0ZXN0KG1vZGVsMiwgcG93ZXIgPSAyOjMsIHR5cGUgPSAiZml0dGVkIikKCiMgVklGIChtdWx0aWtvbGluZWFyaXRhKQpjYXI6OnZpZihtb2RlbDIpCmBgYApWw71zbGVka3kgZG9wbG5rb3bDvWNoIHRlc3RvdiBwb3R2cmR6dWrDuiwgxb5lIHZ5dHZvcmVuw70gbW9kZWwgamUgxaF0YXRpc3RpY2t5IHNwb8S+YWhsaXbDvSBhIHNwcsOhdm5lIMWhcGVjaWZpa292YW7DvS4gSG9kbm90YSBEdXJiaW7igJNXYXRzb25vdmhvIHRlc3R1IChEVyA9IDIuMDQsIHAgPSAwLjYyKSBuYXpuYcSNdWplLCDFvmUgdiByZXrDrWR1w6FjaCBzYSBuZW5hY2jDoWR6YSBhdXRva29yZWzDoWNpYSwgxI1vIHpuYW1lbsOhLCDFvmUgY2h5YnkgbmllIHPDuiBuYXZ6w6Fqb20gesOhdmlzbMOpIGEgbW9kZWwgc3DEusWIYSBwcmVkcG9rbGFkIG5lesOhdmlzbG9zdGkgcmV6w61kdcOtLiBSRVNFVCB0ZXN0IHMgcC1ob2Rub3RvdSAwLjI3IG5lcHJldWvDoXphbCDFvmlhZG5lIHByb2Jsw6lteSBzbyDFoXBlY2lmaWvDoWNpb3UgbW9kZWx1LCB0ZWRhIG1vZGVsIG3DoSBzcHLDoXZuZSB6dm9sZW7DuiBmdW5rxI1uw7ogZm9ybXUgYSBuaWUgamUgcG90cmVibsOpIHByaWTDoXZhxaUgbmVsaW5lw6FybmUgxI1sZW55LiBWw71zbGVka3kgVklGIChWYXJpYW5jZSBJbmZsYXRpb24gRmFjdG9yKSBzIGhvZG5vdG91IDEuMSBwcmUgb2JlIHZ5c3ZldMS+dWrDumNlIHByZW1lbm7DqSBwb3R2cmR6dWrDuiwgxb5lIG1lZHppIG5pbWkgbmVleGlzdHVqZSBtdWx0aWtvbGluZWFyaXRhLiBDZWxrb3ZvIG1vxb5ubyBrb27FoXRhdG92YcWlLCDFvmUgbW9kZWwgamUgZG9icmUgxaFwZWNpZmlrb3ZhbsO9LCByZXrDrWR1w6Egc8O6IG5lesOhdmlzbMOpIGEgdnlzdmV0xL51asO6Y2UgcHJlbWVubsOpIG5pZSBzw7ogbmF2esOham9tIHrDoXZpc2zDqS4KYGBge3J9CmxpYnJhcnkoa25pdHIpCmxpYnJhcnkoZHBseXIpCgpyZXN1bHRzIDwtIGRhdGEuZnJhbWUoCiAgVGVzdCA9IGMoIkR1cmJpbuKAk1dhdHNvbiIsICJSRVNFVCIsICJWSUYgKEkobG9nKDErU1BZX3JldCkpKSIsICJWSUYgKFhMRV9yZXQpIiksCiAgU3RhdGlzdGljID0gYygyLjA0MDYsIDEuMzE1OSwgMS4xMDk2LCAxLjEwOTYpLAogIGBwLWhvZG5vdGFgID0gYygwLjYyMzksIDAuMjcwMSwgTkEsIE5BKSwKICBJbnRlcnByZXTDoWNpYSA9IGMoCiAgICAiQmV6IGF1dG9rb3JlbMOhY2llIHJlesOtZHXDrSIsCiAgICAiQmV6IHByb2Jsw6ltb3Ygc28gxaFwZWNpZmlrw6FjaW91IG1vZGVsdSIsCiAgICAixb1pYWRuYSBtdWx0aWtvbGluZWFyaXRhIiwKICAgICLFvWlhZG5hIG11bHRpa29saW5lYXJpdGEiCiAgKQopCgprYWJsZShyZXN1bHRzLCBjYXB0aW9uID0gIlPDumhybiBkb3BsbmtvdsO9Y2ggZGlhZ25vc3RpY2vDvWNoIHRlc3RvdiBwcmUgbW9kZWwyIikKYGBgClRhYnXEvmthIHpvYnJhenVqZSB2w71zbGVka3kgZG9wbG5rb3bDvWNoIGRpYWdub3N0aWNrw71jaCB0ZXN0b3YgcHJlIG1vZGVsIDIuIER1cmJpbuKAk1dhdHNvbiB0ZXN0IHBvdHZyZHp1amUsIMW+ZSByZXrDrWR1w6EgbmllIHPDuiBhdXRva29yZWxvdmFuw6kuIFJFU0VUIHRlc3QgdWthenVqZSwgxb5lIG1vZGVsIGplIHNwcsOhdm5lIMWhcGVjaWZpa292YW7DvSBhIG5lb2JzYWh1amUgbmVsaW5lw6FybmUgY2h5YnkuIEhvZG5vdHkgVklGIHPDuiB2ZcS+bWkgbsOtemtlLCDEjW8gem5hbWVuw6EsIMW+ZSBtZWR6aSB2eXN2ZXTEvnVqw7pjaW1pIHByZW1lbm7DvW1pIG5lZXhpc3R1amUgbXVsdGlrb2xpbmVhcml0YS4gQ2Vsa292byBtb8W+bm8gbW9kZWwgcG92YcW+b3ZhxaUgemEgc3RhYmlsbsO9IGEgxaF0YXRpc3RpY2t5IHNwb8S+YWhsaXbDvS4K