Задача 1
\[
Var(\alpha X+(1-\alpha)Y) =\\
\alpha^2Var(X)+(1-\alpha)^2Var(Y)+2\alpha(1-\alpha)Cov(X, Y)=\\
\alpha^2Var(X)+Var(Y)-2\alpha Var(Y)+\alpha^2Var(Y)+2\alpha Cov(X, Y) - 2\alpha^2Cov(X,Y) \\
\frac{\partial Var(\alpha X+(1-\alpha)Y)}{\partial \alpha} = \\
2\alpha Var(X)-2Var(Y)+2\alpha Var(Y) + 2Cov(X, Y)-4\alpha Cov(X,Y)\\
\frac{\partial Var(\alpha X+(1-\alpha)Y)}{\partial \alpha} = 0 \implies\\
\alpha(Var(X)+Var(Y)-2Cov(X,Y))=Var(Y)-Cov(X,Y) \implies \\
\alpha=\frac{Var(Y)-Cov(X,Y)}{Var(X)+Var(Y)-2Cov(X,Y)}=\frac{\sigma_Y^2-\sigma_{XY}}{\sigma_X^2+\sigma_Y^2-2\sigma_{XY}}
\]
Задача 2
(a)
Веројатноста дека првиот примерок во бутстрапот е ј-тиот примерок во оригиналот е \(\frac{1}{n}\). Веројатноста дека првиот примерок во бутстрапот не е ј-тиот примерок во оригиналот е \(1-\frac{1}{n}=\frac{n-1}{n}\).
(b)
Бидејќи влечеме со замена, второто влечење не зависи од првото, па веројатноста останува иста: \(1-\frac{1}{n}=\frac{n-1}{n}\).
(c)
Слично како и под б, за i-тиот примерок од бутстрапот важи дека веројатноста тој да не е ј-от примерок од оригиналот е \(1-\frac{1}{n}=\frac{n-1}{n}\). Сите влечења се независини, па затоа веројатноста да го нема ј-от примерок од оригиналот во целиот бутстрап е веројатноста сите примероци од бутстрапот да не се ј-от примерок од оригиналот што е \((1-\frac{1}{n})^n=(\frac{n-1}{n})^n\).
(d)
Веројатноста е обратна од тоа да го нема (под c), односно \(1-(1-\frac{1}{5})^5=1-\frac{4}{5}^5=0.67232\)
(e)
\(1-(1-\frac{1}{100})^{100}=1-\frac{99}{100}^{100}=0.6339677\)
(f)
\(1-(1-\frac{1}{10000})^{10000}=1-\frac{9999}{10000}^{10000}=0.632139\)
(g)
Конвергира кон 0.6321.
n=1:100000
p=1-((n-1)/n)^n
plot(n, p, type="l", ylim=c(0.5, 1))

(h)
Очекувано, резултатот е близок до 0.6321.
store = rep(NA, 10000)
for(i in 1:10000) {
store[i] = sum(sample(1:100, rep=TRUE) == 4) > 0
}
mean(store)
[1] 0.6353
Задача 3
(a)
Тренирачкото множество се дели на к еднакви подмножества. Модел се тренира к пати. Во i-тото трениранје, i-тото подмножество се трга настрана и не се тренира на него, туку се пресметува точноста/error rate/. Error rate на тестирачкото множество се оценува како просек од error rates на секое од к-те крос-валидациски подмножества.
(b)
- cross validation има понизок bias од еден валидациски сет, но знае да биде поваријабилно
- LOOCV (cross validation со к=1) пак има најнизок bias, но затоа варијабилноста може да биде превисока, па може да сакаме да користиме cross validation; секако, LOOCV и доста поспоро се извршува
Задача 4
Користејќи го бутстрап методот, тренираме B модели. За секој модел, со бутстрап техниката, избираме n парови (X, Y) од постоечкото множество од n парови (X, Y) со замена. За секое вакво бутстрап подмножество, го тренираме моделот и правиме предикција за точното X за кое што сме заинтересирани. Добиваме оценувачи на Y \((Y_1^*, Y_2^*, ..., Y_B^*)\). Користејќи ја формулата (5.8) ја пресметуваме стандардната девијација.
Задача 5
Податоците од задачата се:
library(ISLR)
Default
Ќе ја користиме оваа функција за да тренираме модел на тренирачко податочно множество и го валидираме на валидациско податочно множество, притоа враќајќи го error rate-от на валидациското податочно множество.
get_logistic_model_err <- function(formula, train_data, val_data, trues) {
model = glm(as.formula(formula), data=train_data, family=binomial)
probas = predict(model, val_data, type="response")
preds = rep("No", length(probas))
preds[probas > 0.5] = "Yes"
return(1 - mean(preds == trues))
}
Ќе ја користиме оваа функција за да добиеме тренирачки и валидациски множества:
get_train_val_sets <- function(data, split_pct, num_val_sets) {
set.seed(1337)
idxs = 1:nrow(data)
idxs_permutation = sample(idxs)
val_size = round(nrow(data) * split_pct)
train_sets = list()
val_sets = list()
for (val_idx in 1:num_val_sets) {
val_seq = (1 + val_size * (val_idx - 1)):(1 + val_size * val_idx)
train_sets[[val_idx]] = Default[idxs_permutation[-val_seq], ]
val_sets[[val_idx]] = Default[idxs_permutation[val_seq], ]
}
return(list(train_sets, val_sets))
}
(a) (b)
sets = get_train_val_sets(Default, 0.2, 1)
train_set = sets[[1]][[1]]
val_set = sets[[2]][[1]]
get_logistic_model_err(
"default ~ income + balance",
train_set,
val_set,
val_set$default
)
[1] 0.02398801
(c)
Резултатите од трите поделби се доста слични.
sets = get_train_val_sets(Default, 0.2, 3)
for (val_idx in 1:3) {
train_set = sets[[1]][[val_idx]]
val_set = sets[[2]][[val_idx]]
print(
get_logistic_model_err(
"default ~ income + balance",
train_set,
val_set,
val_set$default
)
)
}
[1] 0.02398801
[1] 0.02398801
[1] 0.02448776
(d)
Нема некое подобрување.
sets = get_train_val_sets(Default, 0.2, 3)
for (val_idx in 1:3) {
train_set = sets[[1]][[val_idx]]
val_set = sets[[2]][[val_idx]]
print(
get_logistic_model_err(
"default ~ income + balance + student",
train_set,
val_set,
val_set$default
)
)
}
[1] 0.02498751
[1] 0.02448776
[1] 0.02398801
Задача 6
(a)
model = glm(default ~ income + balance, family=binomial, data=Default)
coef(model)
(Intercept) income balance
-1.154047e+01 2.080898e-05 5.647103e-03
(b)
set.seed(1337)
boot.fn <- function (data, idxs){
return(
coef(
glm(default ~ income + balance, family=binomial, data=data[idxs, ])
)
)
}
boot.fn(Default, sample(nrow(Default), replace=TRUE))
(Intercept) income balance
-1.179284e+01 1.814249e-05 5.751864e-03
(c)
library(boot)
set.seed(1337)
boot_stds = boot(Default, boot.fn, 100)
boot_stds
ORDINARY NONPARAMETRIC BOOTSTRAP
Call:
boot(data = Default, statistic = boot.fn, R = 100)
Bootstrap Statistics :
original bias std. error
t1* -1.154047e+01 -4.699342e-02 4.513118e-01
t2* 2.080898e-05 3.373744e-07 5.121736e-06
t3* 5.647103e-03 1.530472e-05 2.237195e-04
(d)
Ги плотираме коефициентите добиени со glm (зелена боја) и отстапувањата (портокалова боја) заедно со просекот од бутстрапот (сина боја, испрекината линија) и отстапувањата од бутстрапот (црвена боја, испрекината). Се забележува дека вредностите се доста слични.
for (coef_idx in 1:3) {
min_est = min(boot_stds$t[, coef_idx])
max_est = max(boot_stds$t[, coef_idx])
range = max_est - min_est
padding = range * 0.1
ylim = c(min_est - padding, max_est + padding + range / 3)
plot(
boot_stds$t[, coef_idx],
type="l",
col="black",
ylab=paste("beta", coef_idx, sep=""),
xlab="Bootstrap iteration",
ylim=ylim
)
abline(a=mean(boot_stds$t[, coef_idx]), b=0, col="blue", lty=2)
abline(
a=mean(boot_stds$t[, coef_idx]) + sd(boot_stds$t[, coef_idx]),
b=0,
col="red",
lty=2
)
abline(
a=mean(boot_stds$t[, coef_idx]) - sd(boot_stds$t[, coef_idx]),
b=0,
col="red",
lty=2
)
abline(a=coef(model)[coef_idx], b=0, col="green")
model_std = summary(model)$coefficients[coef_idx, "Std. Error"]
abline(a=coef(model)[coef_idx] + model_std, b=0, col="orange")
abline(a=coef(model)[coef_idx] - model_std, b=0, col="orange")
legend(
0,
ylim[2],
legend=c("Model Beta", "Model Std"),
col=c("green", "orange"),
lty=c(1, 1)
)
legend(
40,
ylim[2],
legend=c("Mean Beta", "Std Beta"),
col=c("blue", "red"),
lty=c(2, 2)
)
}



Задача 7
(a)
full_model = glm(Direction ~ Lag1 + Lag2, family=binomial, data=Weekly)
summary(full_model)
Call:
glm(formula = Direction ~ Lag1 + Lag2, family = binomial, data = Weekly)
Deviance Residuals:
Min 1Q Median 3Q Max
-1.623 -1.261 1.001 1.083 1.506
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) 0.22122 0.06147 3.599 0.000319 ***
Lag1 -0.03872 0.02622 -1.477 0.139672
Lag2 0.06025 0.02655 2.270 0.023232 *
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
(Dispersion parameter for binomial family taken to be 1)
Null deviance: 1496.2 on 1088 degrees of freedom
Residual deviance: 1488.2 on 1086 degrees of freedom
AIC: 1494.2
Number of Fisher Scoring iterations: 4
(b)
all_but_first = glm(
Direction ~ Lag1 + Lag2,
family=binomial,
data=Weekly[2:nrow(Weekly), ]
)
summary(all_but_first)
Call:
glm(formula = Direction ~ Lag1 + Lag2, family = binomial, data = Weekly[2:nrow(Weekly),
])
Deviance Residuals:
Min 1Q Median 3Q Max
-1.6258 -1.2617 0.9999 1.0819 1.5071
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) 0.22324 0.06150 3.630 0.000283 ***
Lag1 -0.03843 0.02622 -1.466 0.142683
Lag2 0.06085 0.02656 2.291 0.021971 *
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
(Dispersion parameter for binomial family taken to be 1)
Null deviance: 1494.6 on 1087 degrees of freedom
Residual deviance: 1486.5 on 1085 degrees of freedom
AIC: 1492.5
Number of Fisher Scoring iterations: 4
(c)
Не е точно класифицирана.
proba_first = predict(all_but_first, Weekly[1:1, ], type="response")
pred = "Down"
if (proba_first > .5) {
pred = "Up"
}
proba_first
1
0.5713923
Weekly[1, "Direction"] == pred
[1] FALSE
(d) (e)
Оценкето е дека 44% од предвидувањата се погрешни. Сепак, овој пристап дава оценка со висока варијабилност, па не можеме да сме комплетно сигурни дека моделот е толку лош.
loocv_err = 0
for (idx in 1:nrow(Weekly)) {
model = glm(Direction ~ Lag1 + Lag2, family="binomial", data=Weekly[-idx, ])
proba = predict(model, Weekly[idx, ], type="response")
pred = "Down"
if (proba > 0.5) {
pred = "Up"
}
if (pred != Weekly[idx, "Direction"]) {
loocv_err = loocv_err + 1 / nrow(Weekly)
}
}
print(loocv_err)
[1] 0.4499541
Задача 8
(a)
n (бројот на примероци) e 100, a p (бројот на предиктори) е 1. Формулата е: \(y =-2x^2+x+err\).
set.seed(1)
y = rnorm(100)
x = rnorm(100)
y = x - 2 * x ^ 2 + rnorm(100)
(b)
Делува како да има квадратна врска помеѓу x и y (реално, знаеме дека има, од моделот).
plot(x, y)

(c) (d)
Резултатите се очекувано исти. Бидејќи користиме LOOCV, секој можен датасет од 99 елементи го пробуваме еднаш. Нема простор за случајност тука, па резултатите не зависат од seed-от.
data = data.frame(x, x ^ 2, x ^ 3, x ^ 4, y)
loocv_sint <- function(seed) {
set.seed(seed)
model = glm(y ∼ x, data=data)
loocv_err = cv.glm(data, model)
print(loocv_err$delta)
model = glm(y ∼ x + x.2, data=data)
loocv_err = cv.glm(data, model)
print(loocv_err$delta)
model = glm(y ∼ x + x.2 + x.3, data=data)
loocv_err = cv.glm(data, model)
print(loocv_err$delta)
model = glm(y ∼ x + x.2 + x.3 + x.4, data=data)
loocv_err = cv.glm(data, model)
print(loocv_err$delta)
}
for (seed in 1:2) {
loocv_sint(seed)
print("----------")
}
[1] 5.890979 5.888812
[1] 1.086596 1.086326
[1] 1.102585 1.102227
[1] 1.114772 1.114334
[1] "----------"
[1] 5.890979 5.888812
[1] 1.086596 1.086326
[1] 1.102585 1.102227
[1] 1.114772 1.114334
[1] "----------"
(e)
Квадратниот има најниско LOOCV. Тоа е очекувано, бидејќи оригиналниот модел со кој е добиено податочното множество е квадратен.
(f)
Во секој модел, освен линеарниот, најважни се \(x\) и \(x^2\). Тоа е очекувано, бидејќи податоците се добиени со квадратен модел. Линеарниот модел, нормално, доста лошо ги учи овие квадратни податоци, па кај него само интерцептот е важен.
summary(glm(y ∼ x, data=data))
summary(glm(y ∼ x + x.2, data=data))
summary(glm(y ∼ x + x.2 + x.3, data=data))
summary(glm(y ∼ x + x.2 + x.3 + x.4, data=data))
Задача 9
Оваа задача има се од претходните во неа, па затоа е скокната.
LS0tDQp0aXRsZTogIlJlc2FtcGxpbmcgTWV0aG9kcyINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCiMg0JfQsNC00LDRh9CwIDENCg0KJCQNClZhcihcYWxwaGEgWCsoMS1cYWxwaGEpWSkgPVxcDQpcYWxwaGFeMlZhcihYKSsoMS1cYWxwaGEpXjJWYXIoWSkrMlxhbHBoYSgxLVxhbHBoYSlDb3YoWCwgWSk9XFwNClxhbHBoYV4yVmFyKFgpK1ZhcihZKS0yXGFscGhhIFZhcihZKStcYWxwaGFeMlZhcihZKSsyXGFscGhhIENvdihYLCBZKSAtIDJcYWxwaGFeMkNvdihYLFkpIFxcDQpcZnJhY3tccGFydGlhbCBWYXIoXGFscGhhIFgrKDEtXGFscGhhKVkpfXtccGFydGlhbCBcYWxwaGF9ID0gXFwNCjJcYWxwaGEgVmFyKFgpLTJWYXIoWSkrMlxhbHBoYSBWYXIoWSkgKyAyQ292KFgsIFkpLTRcYWxwaGEgQ292KFgsWSlcXA0KXGZyYWN7XHBhcnRpYWwgVmFyKFxhbHBoYSBYKygxLVxhbHBoYSlZKX17XHBhcnRpYWwgXGFscGhhfSA9IDAgXGltcGxpZXNcXCANClxhbHBoYShWYXIoWCkrVmFyKFkpLTJDb3YoWCxZKSk9VmFyKFkpLUNvdihYLFkpIFxpbXBsaWVzIFxcDQpcYWxwaGE9XGZyYWN7VmFyKFkpLUNvdihYLFkpfXtWYXIoWCkrVmFyKFkpLTJDb3YoWCxZKX09XGZyYWN7XHNpZ21hX1leMi1cc2lnbWFfe1hZfX17XHNpZ21hX1heMitcc2lnbWFfWV4yLTJcc2lnbWFfe1hZfX0NCiQkDQoNCiMg0JfQsNC00LDRh9CwIDINCg0KIyMjIChhKQ0KDQrQktC10YDQvtGY0LDRgtC90L7RgdGC0LAg0LTQtdC60LAg0L/RgNCy0LjQvtGCINC/0YDQuNC80LXRgNC+0Log0LLQviDQsdGD0YLRgdGC0YDQsNC/0L7RgiDQtSDRmC3RgtC40L7RgiDQv9GA0LjQvNC10YDQvtC6INCy0L4g0L7RgNC40LPQuNC90LDQu9C+0YIg0LUgJFxmcmFjezF9e259JC4g0JLQtdGA0L7RmNCw0YLQvdC+0YHRgtCwINC00LXQutCwINC/0YDQstC40L7RgiDQv9GA0LjQvNC10YDQvtC6INCy0L4g0LHRg9GC0YHRgtGA0LDQv9C+0YIg0L3QtSDQtSDRmC3RgtC40L7RgiDQv9GA0LjQvNC10YDQvtC6INCy0L4g0L7RgNC40LPQuNC90LDQu9C+0YIg0LUgJDEtXGZyYWN7MX17bn09XGZyYWN7bi0xfXtufSQuDQoNCiMjIyAoYikNCg0K0JHQuNC00LXRmNGc0Lgg0LLQu9C10YfQtdC80LUg0YHQviDQt9Cw0LzQtdC90LAsINCy0YLQvtGA0L7RgtC+INCy0LvQtdGH0LXRmtC1INC90LUg0LfQsNCy0LjRgdC4INC+0LQg0L/RgNCy0L7RgtC+LCDQv9CwINCy0LXRgNC+0ZjQsNGC0L3QvtGB0YLQsCDQvtGB0YLQsNC90YPQstCwINC40YHRgtCwOiAkMS1cZnJhY3sxfXtufT1cZnJhY3tuLTF9e259JC4NCg0KIyMjIChjKQ0KDQrQodC70LjRh9C90L4g0LrQsNC60L4g0Lgg0L/QvtC0INCxLCDQt9CwIGkt0YLQuNC+0YIg0L/RgNC40LzQtdGA0L7QuiDQvtC0INCx0YPRgtGB0YLRgNCw0L/QvtGCINCy0LDQttC4INC00LXQutCwINCy0LXRgNC+0ZjQsNGC0L3QvtGB0YLQsCDRgtC+0Zgg0LTQsCDQvdC1INC1INGYLdC+0YIg0L/RgNC40LzQtdGA0L7QuiDQvtC0INC+0YDQuNCz0LjQvdCw0LvQvtGCINC1ICQxLVxmcmFjezF9e259PVxmcmFje24tMX17bn0kLiDQodC40YLQtSDQstC70LXRh9C10ZrQsCDRgdC1INC90LXQt9Cw0LLQuNGB0LjQvdC4LCDQv9CwINC30LDRgtC+0LAg0LLQtdGA0L7RmNCw0YLQvdC+0YHRgtCwINC00LAg0LPQviDQvdC10LzQsCDRmC3QvtGCINC/0YDQuNC80LXRgNC+0Log0L7QtCDQvtGA0LjQs9C40L3QsNC70L7RgiDQstC+INGG0LXQu9C40L7RgiDQsdGD0YLRgdGC0YDQsNC/INC1INCy0LXRgNC+0ZjQsNGC0L3QvtGB0YLQsCDRgdC40YLQtSDQv9GA0LjQvNC10YDQvtGG0Lgg0L7QtCDQsdGD0YLRgdGC0YDQsNC/0L7RgiDQtNCwINC90LUg0YHQtSDRmC3QvtGCINC/0YDQuNC80LXRgNC+0Log0L7QtCDQvtGA0LjQs9C40L3QsNC70L7RgiDRiNGC0L4g0LUgJCgxLVxmcmFjezF9e259KV5uPShcZnJhY3tuLTF9e259KV5uJC4NCg0KIyMjIChkKQ0KDQrQktC10YDQvtGY0LDRgtC90L7RgdGC0LAg0LUg0L7QsdGA0LDRgtC90LAg0L7QtCDRgtC+0LAg0LTQsCDQs9C+INC90LXQvNCwICjQv9C+0LQgYyksINC+0LTQvdC+0YHQvdC+ICQxLSgxLVxmcmFjezF9ezV9KV41PTEtXGZyYWN7NH17NX1eNT0wLjY3MjMyJA0KDQojIyMgKGUpDQoNCiQxLSgxLVxmcmFjezF9ezEwMH0pXnsxMDB9PTEtXGZyYWN7OTl9ezEwMH1eezEwMH09MC42MzM5Njc3JA0KDQojIyMgKGYpDQoNCiQxLSgxLVxmcmFjezF9ezEwMDAwfSleezEwMDAwfT0xLVxmcmFjezk5OTl9ezEwMDAwfV57MTAwMDB9PTAuNjMyMTM5JA0KDQojIyMgKGcpDQoNCtCa0L7QvdCy0LXRgNCz0LjRgNCwINC60L7QvSAwLjYzMjEuDQoNCmBgYHtyfQ0Kbj0xOjEwMDAwMA0KcD0xLSgobi0xKS9uKV5uDQpwbG90KG4sIHAsIHR5cGU9ImwiLCB5bGltPWMoMC41LCAxKSkNCmBgYA0KDQojIyMgKGgpDQoNCtCe0YfQtdC60YPQstCw0L3Qviwg0YDQtdC30YPQu9GC0LDRgtC+0YIg0LUg0LHQu9C40LfQvtC6INC00L4gMC42MzIxLg0KDQpgYGB7cn0NCnN0b3JlID0gcmVwKE5BLCAxMDAwMCkNCmZvcihpIGluIDE6MTAwMDApIHsNCiAgc3RvcmVbaV0gPSBzdW0oc2FtcGxlKDE6MTAwLCByZXA9VFJVRSkgPT0gNCkgPiAwDQp9DQptZWFuKHN0b3JlKQ0KYGBgDQoNCiMg0JfQsNC00LDRh9CwIDMNCg0KIyMjIChhKQ0KDQrQotGA0LXQvdC40YDQsNGH0LrQvtGC0L4g0LzQvdC+0LbQtdGB0YLQstC+INGB0LUg0LTQtdC70Lgg0L3QsCDQuiDQtdC00L3QsNC60LLQuCDQv9C+0LTQvNC90L7QttC10YHRgtCy0LAuINCc0L7QtNC10Lsg0YHQtSDRgtGA0LXQvdC40YDQsCDQuiDQv9Cw0YLQuC4g0JLQviBpLdGC0L7RgtC+INGC0YDQtdC90LjRgNCw0L3RmNC1LCBpLdGC0L7RgtC+INC/0L7QtNC80L3QvtC20LXRgdGC0LLQviDRgdC1INGC0YDQs9CwINC90LDRgdGC0YDQsNC90LAg0Lgg0L3QtSDRgdC1INGC0YDQtdC90LjRgNCwINC90LAg0L3QtdCz0L4sINGC0YPQutGDINGB0LUg0L/RgNC10YHQvNC10YLRg9Cy0LAg0YLQvtGH0L3QvtGB0YLQsC9lcnJvciByYXRlLy4gRXJyb3IgcmF0ZSDQvdCwINGC0LXRgdGC0LjRgNCw0YfQutC+0YLQviDQvNC90L7QttC10YHRgtCy0L4g0YHQtSDQvtGG0LXQvdGD0LLQsCDQutCw0LrQviDQv9GA0L7RgdC10Log0L7QtCBlcnJvciByYXRlcyDQvdCwINGB0LXQutC+0LUg0L7QtCDQui3RgtC1INC60YDQvtGBLdCy0LDQu9C40LTQsNGG0LjRgdC60Lgg0L/QvtC00LzQvdC+0LbQtdGB0YLQstCwLg0KDQojIyMgKGIpDQoNCi0gY3Jvc3MgdmFsaWRhdGlvbiDQuNC80LAg0L/QvtC90LjQt9C+0LogYmlhcyDQvtC0INC10LTQtdC9INCy0LDQu9C40LTQsNGG0LjRgdC60Lgg0YHQtdGCLCDQvdC+INC30L3QsNC1INC00LAg0LHQuNC00LUg0L/QvtCy0LDRgNC40ZjQsNCx0LjQu9C90L4NCi0gTE9PQ1YgKGNyb3NzIHZhbGlkYXRpb24g0YHQviDQuj0xKSDQv9Cw0Log0LjQvNCwINC90LDRmNC90LjQt9C+0LogYmlhcywg0L3QviDQt9Cw0YLQvtCwINCy0LDRgNC40ZjQsNCx0LjQu9C90L7RgdGC0LAg0LzQvtC20LUg0LTQsCDQsdC40LTQtSDQv9GA0LXQstC40YHQvtC60LAsINC/0LAg0LzQvtC20LUg0LTQsCDRgdCw0LrQsNC80LUg0LTQsCDQutC+0YDQuNGB0YLQuNC80LUgY3Jvc3MgdmFsaWRhdGlvbjsg0YHQtdC60LDQutC+LCBMT09DViDQuCDQtNC+0YHRgtCwINC/0L7RgdC/0L7RgNC+INGB0LUg0LjQt9Cy0YDRiNGD0LLQsA0KDQojINCX0LDQtNCw0YfQsCA0DQoNCtCa0L7RgNC40YHRgtC10ZjRnNC4INCz0L4g0LHRg9GC0YHRgtGA0LDQvyDQvNC10YLQvtC00L7Rgiwg0YLRgNC10L3QuNGA0LDQvNC1IEIg0LzQvtC00LXQu9C4LiDQl9CwINGB0LXQutC+0Zgg0LzQvtC00LXQuywg0YHQviDQsdGD0YLRgdGC0YDQsNC/INGC0LXRhdC90LjQutCw0YLQsCwg0LjQt9Cx0LjRgNCw0LzQtSBuINC/0LDRgNC+0LLQuCAoWCwgWSkg0L7QtCDQv9C+0YHRgtC+0LXRh9C60L7RgtC+INC80L3QvtC20LXRgdGC0LLQviDQvtC0IG4g0L/QsNGA0L7QstC4IChYLCBZKSDRgdC+INC30LDQvNC10L3QsC4g0JfQsCDRgdC10LrQvtC1INCy0LDQutCy0L4g0LHRg9GC0YHRgtGA0LDQvyDQv9C+0LTQvNC90L7QttC10YHRgtCy0L4sINCz0L4g0YLRgNC10L3QuNGA0LDQvNC1INC80L7QtNC10LvQvtGCINC4INC/0YDQsNCy0LjQvNC1INC/0YDQtdC00LjQutGG0LjRmNCwINC30LAg0YLQvtGH0L3QvtGC0L4gWCDQt9CwINC60L7QtSDRiNGC0L4g0YHQvNC1INC30LDQuNC90YLQtdGA0LXRgdC40YDQsNC90LguINCU0L7QsdC40LLQsNC80LUg0L7RhtC10L3Rg9Cy0LDRh9C4INC90LAgWSAkKFlfMV4qLCBZXzJeKiwgLi4uLCBZX0JeKikkLiDQmtC+0YDQuNGB0YLQtdGY0ZzQuCDRmNCwINGE0L7RgNC80YPQu9Cw0YLQsCAoNS44KSDRmNCwINC/0YDQtdGB0LzQtdGC0YPQstCw0LzQtSDRgdGC0LDQvdC00LDRgNC00L3QsNGC0LAg0LTQtdCy0LjRmNCw0YbQuNGY0LAuDQoNCiMg0JfQsNC00LDRh9CwIDUNCg0K0J/QvtC00LDRgtC+0YbQuNGC0LUg0L7QtCDQt9Cw0LTQsNGH0LDRgtCwINGB0LU6DQoNCmBgYHtyfQ0KbGlicmFyeShJU0xSKQ0KRGVmYXVsdA0KYGBgDQoNCtCM0LUg0ZjQsCDQutC+0YDQuNGB0YLQuNC80LUg0L7QstCw0LAg0YTRg9C90LrRhtC40ZjQsCDQt9CwINC00LAg0YLRgNC10L3QuNGA0LDQvNC1INC80L7QtNC10Lsg0L3QsCDRgtGA0LXQvdC40YDQsNGH0LrQviDQv9C+0LTQsNGC0L7Rh9C90L4g0LzQvdC+0LbQtdGB0YLQstC+INC4INCz0L4g0LLQsNC70LjQtNC40YDQsNC80LUg0L3QsCDQstCw0LvQuNC00LDRhtC40YHQutC+INC/0L7QtNCw0YLQvtGH0L3QviDQvNC90L7QttC10YHRgtCy0L4sINC/0YDQuNGC0L7QsCDQstGA0LDRnNCw0ZjRnNC4INCz0L4gZXJyb3IgcmF0ZS3QvtGCINC90LAg0LLQsNC70LjQtNCw0YbQuNGB0LrQvtGC0L4g0L/QvtC00LDRgtC+0YfQvdC+INC80L3QvtC20LXRgdGC0LLQvi4NCg0KYGBge3J9DQpnZXRfbG9naXN0aWNfbW9kZWxfZXJyIDwtIGZ1bmN0aW9uKGZvcm11bGEsIHRyYWluX2RhdGEsIHZhbF9kYXRhLCB0cnVlcykgew0KICBtb2RlbCA9IGdsbShhcy5mb3JtdWxhKGZvcm11bGEpLCBkYXRhPXRyYWluX2RhdGEsIGZhbWlseT1iaW5vbWlhbCkNCiAgcHJvYmFzID0gcHJlZGljdChtb2RlbCwgdmFsX2RhdGEsIHR5cGU9InJlc3BvbnNlIikNCiAgcHJlZHMgPSByZXAoIk5vIiwgbGVuZ3RoKHByb2JhcykpDQogIHByZWRzW3Byb2JhcyA+IDAuNV0gPSAiWWVzIg0KICByZXR1cm4oMSAtIG1lYW4ocHJlZHMgPT0gdHJ1ZXMpKQ0KfQ0KYGBgDQoNCtCM0LUg0ZjQsCDQutC+0YDQuNGB0YLQuNC80LUg0L7QstCw0LAg0YTRg9C90LrRhtC40ZjQsCDQt9CwINC00LAg0LTQvtCx0LjQtdC80LUg0YLRgNC10L3QuNGA0LDRh9C60Lgg0Lgg0LLQsNC70LjQtNCw0YbQuNGB0LrQuCDQvNC90L7QttC10YHRgtCy0LA6DQoNCmBgYHtyfQ0KZ2V0X3RyYWluX3ZhbF9zZXRzIDwtIGZ1bmN0aW9uKGRhdGEsIHNwbGl0X3BjdCwgbnVtX3ZhbF9zZXRzKSB7DQogIHNldC5zZWVkKDEzMzcpDQogIGlkeHMgPSAxOm5yb3coZGF0YSkNCiAgaWR4c19wZXJtdXRhdGlvbiA9IHNhbXBsZShpZHhzKQ0KICB2YWxfc2l6ZSA9IHJvdW5kKG5yb3coZGF0YSkgKiBzcGxpdF9wY3QpDQogIHRyYWluX3NldHMgPSBsaXN0KCkNCiAgdmFsX3NldHMgPSBsaXN0KCkNCiAgZm9yICh2YWxfaWR4IGluIDE6bnVtX3ZhbF9zZXRzKSB7DQogICAgdmFsX3NlcSA9ICgxICsgdmFsX3NpemUgKiAodmFsX2lkeCAtIDEpKTooMSArIHZhbF9zaXplICogdmFsX2lkeCkNCiAgICB0cmFpbl9zZXRzW1t2YWxfaWR4XV0gPSBEZWZhdWx0W2lkeHNfcGVybXV0YXRpb25bLXZhbF9zZXFdLCBdDQogICAgdmFsX3NldHNbW3ZhbF9pZHhdXSA9IERlZmF1bHRbaWR4c19wZXJtdXRhdGlvblt2YWxfc2VxXSwgXQ0KICB9DQogIHJldHVybihsaXN0KHRyYWluX3NldHMsIHZhbF9zZXRzKSkNCn0NCmBgYA0KDQoNCiMjIyAoYSkgKGIpDQoNCmBgYHtyfQ0Kc2V0cyA9IGdldF90cmFpbl92YWxfc2V0cyhEZWZhdWx0LCAwLjIsIDEpDQp0cmFpbl9zZXQgPSBzZXRzW1sxXV1bWzFdXQ0KdmFsX3NldCA9IHNldHNbWzJdXVtbMV1dDQpnZXRfbG9naXN0aWNfbW9kZWxfZXJyKA0KICAiZGVmYXVsdCB+IGluY29tZSArIGJhbGFuY2UiLCANCiAgdHJhaW5fc2V0LCANCiAgdmFsX3NldCwgDQogIHZhbF9zZXQkZGVmYXVsdA0KKQ0KYGBgDQoNCiMjIyAoYykNCg0K0KDQtdC30YPQu9GC0LDRgtC40YLQtSDQvtC0INGC0YDQuNGC0LUg0L/QvtC00LXQu9Cx0Lgg0YHQtSDQtNC+0YHRgtCwINGB0LvQuNGH0L3QuC4NCg0KYGBge3J9DQpzZXRzID0gZ2V0X3RyYWluX3ZhbF9zZXRzKERlZmF1bHQsIDAuMiwgMykNCmZvciAodmFsX2lkeCBpbiAxOjMpIHsNCiAgdHJhaW5fc2V0ID0gc2V0c1tbMV1dW1t2YWxfaWR4XV0NCiAgdmFsX3NldCA9IHNldHNbWzJdXVtbdmFsX2lkeF1dDQogIHByaW50KA0KICAgIGdldF9sb2dpc3RpY19tb2RlbF9lcnIoDQogICAgICAiZGVmYXVsdCB+IGluY29tZSArIGJhbGFuY2UiLCANCiAgICAgIHRyYWluX3NldCwgDQogICAgICB2YWxfc2V0LCANCiAgICAgIHZhbF9zZXQkZGVmYXVsdA0KICAgICkNCiAgKQ0KfQ0KYGBgDQoNCiMjIyAoZCkNCg0K0J3QtdC80LAg0L3QtdC60L7QtSDQv9C+0LTQvtCx0YDRg9Cy0LDRmtC1Lg0KDQpgYGB7cn0NCnNldHMgPSBnZXRfdHJhaW5fdmFsX3NldHMoRGVmYXVsdCwgMC4yLCAzKQ0KZm9yICh2YWxfaWR4IGluIDE6Mykgew0KICB0cmFpbl9zZXQgPSBzZXRzW1sxXV1bW3ZhbF9pZHhdXQ0KICB2YWxfc2V0ID0gc2V0c1tbMl1dW1t2YWxfaWR4XV0NCiAgcHJpbnQoDQogICAgZ2V0X2xvZ2lzdGljX21vZGVsX2VycigNCiAgICAgICJkZWZhdWx0IH4gaW5jb21lICsgYmFsYW5jZSArIHN0dWRlbnQiLCANCiAgICAgIHRyYWluX3NldCwgDQogICAgICB2YWxfc2V0LCANCiAgICAgIHZhbF9zZXQkZGVmYXVsdA0KICAgICkNCiAgKQ0KfQ0KYGBgDQoNCiMg0JfQsNC00LDRh9CwIDYNCg0KIyMjIChhKQ0KDQpgYGB7cn0NCm1vZGVsID0gZ2xtKGRlZmF1bHQgfiBpbmNvbWUgKyBiYWxhbmNlLCBmYW1pbHk9Ymlub21pYWwsIGRhdGE9RGVmYXVsdCkNCmNvZWYobW9kZWwpDQpgYGANCg0KIyMjIChiKQ0KDQpgYGB7cn0NCnNldC5zZWVkKDEzMzcpDQpib290LmZuIDwtIGZ1bmN0aW9uIChkYXRhLCBpZHhzKXsNCiAgcmV0dXJuKA0KICAgIGNvZWYoDQogICAgICBnbG0oZGVmYXVsdCB+IGluY29tZSArIGJhbGFuY2UsIGZhbWlseT1iaW5vbWlhbCwgZGF0YT1kYXRhW2lkeHMsIF0pDQogICAgKQ0KICApDQp9DQpib290LmZuKERlZmF1bHQsIHNhbXBsZShucm93KERlZmF1bHQpLCByZXBsYWNlPVRSVUUpKQ0KYGBgDQoNCiMjIyAoYykNCg0KYGBge3J9DQpsaWJyYXJ5KGJvb3QpDQpzZXQuc2VlZCgxMzM3KQ0KYm9vdF9zdGRzID0gYm9vdChEZWZhdWx0LCBib290LmZuLCAxMDApDQpib290X3N0ZHMNCmBgYA0KDQojIyMgKGQpDQoNCtCT0Lgg0L/Qu9C+0YLQuNGA0LDQvNC1INC60L7QtdGE0LjRhtC40LXQvdGC0LjRgtC1INC00L7QsdC40LXQvdC4INGB0L4gZ2xtICjQt9C10LvQtdC90LAg0LHQvtGY0LApINC4INC+0YLRgdGC0LDQv9GD0LLQsNGa0LDRgtCwICjQv9C+0YDRgtC+0LrQsNC70L7QstCwINCx0L7RmNCwKSDQt9Cw0LXQtNC90L4g0YHQviDQv9GA0L7RgdC10LrQvtGCINC+0LQg0LHRg9GC0YHRgtGA0LDQv9C+0YIgKNGB0LjQvdCwINCx0L7RmNCwLCDQuNGB0L/RgNC10LrQuNC90LDRgtCwINC70LjQvdC40ZjQsCkg0Lgg0L7RgtGB0YLQsNC/0YPQstCw0ZrQsNGC0LAg0L7QtCDQsdGD0YLRgdGC0YDQsNC/0L7RgiAo0YbRgNCy0LXQvdCwINCx0L7RmNCwLCDQuNGB0L/RgNC10LrQuNC90LDRgtCwKS4g0KHQtSDQt9Cw0LHQtdC70LXQttGD0LLQsCDQtNC10LrQsCDQstGA0LXQtNC90L7RgdGC0LjRgtC1INGB0LUg0LTQvtGB0YLQsCDRgdC70LjRh9C90LguDQoNCmBgYHtyfQ0KZm9yIChjb2VmX2lkeCBpbiAxOjMpIHsNCiAgbWluX2VzdCA9IG1pbihib290X3N0ZHMkdFssIGNvZWZfaWR4XSkNCiAgbWF4X2VzdCA9IG1heChib290X3N0ZHMkdFssIGNvZWZfaWR4XSkNCiAgcmFuZ2UgPSBtYXhfZXN0IC0gbWluX2VzdA0KICBwYWRkaW5nID0gcmFuZ2UgKiAwLjENCiAgeWxpbSA9IGMobWluX2VzdCAtIHBhZGRpbmcsIG1heF9lc3QgKyBwYWRkaW5nICsgcmFuZ2UgLyAzKQ0KICBwbG90KA0KICAgIGJvb3Rfc3RkcyR0WywgY29lZl9pZHhdLCANCiAgICB0eXBlPSJsIiwgDQogICAgY29sPSJibGFjayIsIA0KICAgIHlsYWI9cGFzdGUoImJldGEiLCBjb2VmX2lkeCwgc2VwPSIiKSwNCiAgICB4bGFiPSJCb290c3RyYXAgaXRlcmF0aW9uIiwNCiAgICB5bGltPXlsaW0NCiAgKQ0KICBhYmxpbmUoYT1tZWFuKGJvb3Rfc3RkcyR0WywgY29lZl9pZHhdKSwgYj0wLCBjb2w9ImJsdWUiLCBsdHk9MikNCiAgYWJsaW5lKA0KICAgIGE9bWVhbihib290X3N0ZHMkdFssIGNvZWZfaWR4XSkgKyBzZChib290X3N0ZHMkdFssIGNvZWZfaWR4XSksIA0KICAgIGI9MCwgDQogICAgY29sPSJyZWQiLCANCiAgICBsdHk9Mg0KICApDQogIGFibGluZSgNCiAgICBhPW1lYW4oYm9vdF9zdGRzJHRbLCBjb2VmX2lkeF0pIC0gc2QoYm9vdF9zdGRzJHRbLCBjb2VmX2lkeF0pLCANCiAgICBiPTAsIA0KICAgIGNvbD0icmVkIiwgDQogICAgbHR5PTINCiAgKQ0KICBhYmxpbmUoYT1jb2VmKG1vZGVsKVtjb2VmX2lkeF0sIGI9MCwgY29sPSJncmVlbiIpDQogIG1vZGVsX3N0ZCA9IHN1bW1hcnkobW9kZWwpJGNvZWZmaWNpZW50c1tjb2VmX2lkeCwgIlN0ZC4gRXJyb3IiXQ0KICBhYmxpbmUoYT1jb2VmKG1vZGVsKVtjb2VmX2lkeF0gKyBtb2RlbF9zdGQsIGI9MCwgY29sPSJvcmFuZ2UiKQ0KICBhYmxpbmUoYT1jb2VmKG1vZGVsKVtjb2VmX2lkeF0gLSBtb2RlbF9zdGQsIGI9MCwgY29sPSJvcmFuZ2UiKQ0KICBsZWdlbmQoDQogICAgMCwgDQogICAgeWxpbVsyXSwgDQogICAgbGVnZW5kPWMoIk1vZGVsIEJldGEiLCAiTW9kZWwgU3RkIiksIA0KICAgIGNvbD1jKCJncmVlbiIsICJvcmFuZ2UiKSwgDQogICAgbHR5PWMoMSwgMSkNCiAgKQ0KICBsZWdlbmQoDQogICAgNDAsIA0KICAgIHlsaW1bMl0sIA0KICAgIGxlZ2VuZD1jKCJNZWFuIEJldGEiLCAiU3RkIEJldGEiKSwgDQogICAgY29sPWMoImJsdWUiLCAicmVkIiksIA0KICAgIGx0eT1jKDIsIDIpDQogICkNCn0NCmBgYA0KDQojINCX0LDQtNCw0YfQsCA3DQoNCiMjIyAoYSkNCg0KYGBge3J9DQpmdWxsX21vZGVsID0gZ2xtKERpcmVjdGlvbiB+IExhZzEgKyBMYWcyLCBmYW1pbHk9Ymlub21pYWwsIGRhdGE9V2Vla2x5KQ0Kc3VtbWFyeShmdWxsX21vZGVsKQ0KYGBgDQoNCiMjIyAoYikNCg0KYGBge3J9DQphbGxfYnV0X2ZpcnN0ID0gZ2xtKA0KICBEaXJlY3Rpb24gfiBMYWcxICsgTGFnMiwgDQogIGZhbWlseT1iaW5vbWlhbCwgDQogIGRhdGE9V2Vla2x5WzI6bnJvdyhXZWVrbHkpLCBdDQopDQpzdW1tYXJ5KGFsbF9idXRfZmlyc3QpDQpgYGANCg0KIyMjIChjKQ0KDQrQndC1INC1INGC0L7Rh9C90L4g0LrQu9Cw0YHQuNGE0LjRhtC40YDQsNC90LAuDQoNCmBgYHtyfQ0KcHJvYmFfZmlyc3QgPSBwcmVkaWN0KGFsbF9idXRfZmlyc3QsIFdlZWtseVsxOjEsIF0sIHR5cGU9InJlc3BvbnNlIikNCnByZWQgPSAiRG93biINCmlmIChwcm9iYV9maXJzdCA+IC41KSB7DQogIHByZWQgPSAiVXAiDQp9DQpwcm9iYV9maXJzdA0KV2Vla2x5WzEsICJEaXJlY3Rpb24iXSA9PSBwcmVkDQpgYGANCg0KIyMjIChkKSAoZSkNCg0K0J7RhtC10L3QutC10YLQviDQtSDQtNC10LrQsCA0NCUg0L7QtCDQv9GA0LXQtNCy0LjQtNGD0LLQsNGa0LDRgtCwINGB0LUg0L/QvtCz0YDQtdGI0L3QuC4g0KHQtdC/0LDQuiwg0L7QstC+0Zgg0L/RgNC40YHRgtCw0L8g0LTQsNCy0LAg0L7RhtC10L3QutCwINGB0L4g0LLQuNGB0L7QutCwINCy0LDRgNC40ZjQsNCx0LjQu9C90L7RgdGCLCDQv9CwINC90LUg0LzQvtC20LXQvNC1INC00LAg0YHQvNC1INC60L7QvNC/0LvQtdGC0L3QviDRgdC40LPRg9GA0L3QuCDQtNC10LrQsCDQvNC+0LTQtdC70L7RgiDQtSDRgtC+0LvQutGDINC70L7RiC4NCg0KYGBge3J9DQpsb29jdl9lcnIgPSAwDQoNCmZvciAoaWR4IGluIDE6bnJvdyhXZWVrbHkpKSB7DQogIG1vZGVsID0gZ2xtKERpcmVjdGlvbiB+IExhZzEgKyBMYWcyLCBmYW1pbHk9ImJpbm9taWFsIiwgZGF0YT1XZWVrbHlbLWlkeCwgXSkNCiAgcHJvYmEgPSBwcmVkaWN0KG1vZGVsLCBXZWVrbHlbaWR4LCBdLCB0eXBlPSJyZXNwb25zZSIpDQogIHByZWQgPSAiRG93biINCiAgaWYgKHByb2JhID4gMC41KSB7DQogICAgcHJlZCA9ICJVcCINCiAgfQ0KICBpZiAocHJlZCAhPSBXZWVrbHlbaWR4LCAiRGlyZWN0aW9uIl0pIHsNCiAgICBsb29jdl9lcnIgPSBsb29jdl9lcnIgKyAxIC8gbnJvdyhXZWVrbHkpDQogIH0NCn0NCg0KcHJpbnQobG9vY3ZfZXJyKQ0KYGBgDQoNCiMg0JfQsNC00LDRh9CwIDgNCg0KIyMjIChhKQ0KDQpuICjQsdGA0L7RmNC+0YIg0L3QsCDQv9GA0LjQvNC10YDQvtGG0LgpIGUgMTAwLCBhIHAgKNCx0YDQvtGY0L7RgiDQvdCwINC/0YDQtdC00LjQutGC0L7RgNC4KSDQtSAxLiDQpNC+0YDQvNGD0LvQsNGC0LAg0LU6ICR5ID0tMnheMit4K2VyciQuDQoNCmBgYHtyfQ0Kc2V0LnNlZWQoMSkNCnkgPSBybm9ybSgxMDApDQp4ID0gcm5vcm0oMTAwKQ0KeSA9IHggLSAyICogeCBeIDIgKyBybm9ybSgxMDApDQpgYGANCg0KIyMjIChiKQ0KDQrQlNC10LvRg9Cy0LAg0LrQsNC60L4g0LTQsCDQuNC80LAg0LrQstCw0LTRgNCw0YLQvdCwINCy0YDRgdC60LAg0L/QvtC80LXRk9GDIHgg0LggeSAo0YDQtdCw0LvQvdC+LCDQt9C90LDQtdC80LUg0LTQtdC60LAg0LjQvNCwLCDQvtC0INC80L7QtNC10LvQvtGCKS4NCg0KYGBge3J9DQpwbG90KHgsIHkpDQpgYGANCg0KIyMjIChjKSAoZCkNCg0K0KDQtdC30YPQu9GC0LDRgtC40YLQtSDRgdC1INC+0YfQtdC60YPQstCw0L3QviDQuNGB0YLQuC4g0JHQuNC00LXRmNGc0Lgg0LrQvtGA0LjRgdGC0LjQvNC1IExPT0NWLCDRgdC10LrQvtGYINC80L7QttC10L0g0LTQsNGC0LDRgdC10YIg0L7QtCA5OSDQtdC70LXQvNC10L3RgtC4INCz0L4g0L/RgNC+0LHRg9Cy0LDQvNC1INC10LTQvdCw0YguINCd0LXQvNCwINC/0YDQvtGB0YLQvtGAINC30LAg0YHQu9GD0YfQsNGY0L3QvtGB0YIg0YLRg9C60LAsINC/0LAg0YDQtdC30YPQu9GC0LDRgtC40YLQtSDQvdC1INC30LDQstC40YHQsNGCINC+0LQgc2VlZC3QvtGCLg0KDQpgYGB7cn0NCmRhdGEgPSBkYXRhLmZyYW1lKHgsIHggXiAyLCB4IF4gMywgeCBeIDQsIHkpDQoNCmxvb2N2X3NpbnQgPC0gZnVuY3Rpb24oc2VlZCkgew0KICBzZXQuc2VlZChzZWVkKQ0KICANCiAgbW9kZWwgPSBnbG0oeSDiiLwgeCwgZGF0YT1kYXRhKQ0KICBsb29jdl9lcnIgPSBjdi5nbG0oZGF0YSwgbW9kZWwpDQogIHByaW50KGxvb2N2X2VyciRkZWx0YSkNCiAgDQogIG1vZGVsID0gZ2xtKHkg4oi8IHggKyB4LjIsIGRhdGE9ZGF0YSkNCiAgbG9vY3ZfZXJyID0gY3YuZ2xtKGRhdGEsIG1vZGVsKQ0KICBwcmludChsb29jdl9lcnIkZGVsdGEpDQogIA0KICBtb2RlbCA9IGdsbSh5IOKIvCB4ICsgeC4yICsgeC4zLCBkYXRhPWRhdGEpDQogIGxvb2N2X2VyciA9IGN2LmdsbShkYXRhLCBtb2RlbCkNCiAgcHJpbnQobG9vY3ZfZXJyJGRlbHRhKQ0KDQogIG1vZGVsID0gZ2xtKHkg4oi8IHggKyB4LjIgKyB4LjMgKyB4LjQsIGRhdGE9ZGF0YSkNCiAgbG9vY3ZfZXJyID0gY3YuZ2xtKGRhdGEsIG1vZGVsKQ0KICBwcmludChsb29jdl9lcnIkZGVsdGEpDQp9DQoNCmZvciAoc2VlZCBpbiAxOjIpIHsNCiAgbG9vY3Zfc2ludChzZWVkKQ0KICBwcmludCgiLS0tLS0tLS0tLSIpDQp9DQpgYGANCg0KIyMjIChlKQ0KDQrQmtCy0LDQtNGA0LDRgtC90LjQvtGCINC40LzQsCDQvdCw0ZjQvdC40YHQutC+IExPT0NWLiDQotC+0LAg0LUg0L7Rh9C10LrRg9Cy0LDQvdC+LCDQsdC40LTQtdGY0ZzQuCDQvtGA0LjQs9C40L3QsNC70L3QuNC+0YIg0LzQvtC00LXQuyDRgdC+INC60L7RmCDQtSDQtNC+0LHQuNC10L3QviDQv9C+0LTQsNGC0L7Rh9C90L7RgtC+INC80L3QvtC20LXRgdGC0LLQviDQtSDQutCy0LDQtNGA0LDRgtC10L0uDQoNCiMjIyAoZikNCg0K0JLQviDRgdC10LrQvtGYINC80L7QtNC10LssINC+0YHQstC10L0g0LvQuNC90LXQsNGA0L3QuNC+0YIsINC90LDRmNCy0LDQttC90Lgg0YHQtSAkeCQg0LggJHheMiQuINCi0L7QsCDQtSDQvtGH0LXQutGD0LLQsNC90L4sINCx0LjQtNC10ZjRnNC4INC/0L7QtNCw0YLQvtGG0LjRgtC1INGB0LUg0LTQvtCx0LjQtdC90Lgg0YHQviDQutCy0LDQtNGA0LDRgtC10L0g0LzQvtC00LXQuy4g0JvQuNC90LXQsNGA0L3QuNC+0YIg0LzQvtC00LXQuywg0L3QvtGA0LzQsNC70L3Qviwg0LTQvtGB0YLQsCDQu9C+0YjQviDQs9C4INGD0YfQuCDQvtCy0LjQtSDQutCy0LDQtNGA0LDRgtC90Lgg0L/QvtC00LDRgtC+0YbQuCwg0L/QsCDQutCw0Zgg0L3QtdCz0L4g0YHQsNC80L4g0LjQvdGC0LXRgNGG0LXQv9GC0L7RgiDQtSDQstCw0LbQtdC9Lg0KDQpgYGB7cn0NCnN1bW1hcnkoZ2xtKHkg4oi8IHgsIGRhdGE9ZGF0YSkpDQpzdW1tYXJ5KGdsbSh5IOKIvCB4ICsgeC4yLCBkYXRhPWRhdGEpKQ0Kc3VtbWFyeShnbG0oeSDiiLwgeCArIHguMiArIHguMywgZGF0YT1kYXRhKSkNCnN1bW1hcnkoZ2xtKHkg4oi8IHggKyB4LjIgKyB4LjMgKyB4LjQsIGRhdGE9ZGF0YSkpDQpgYGANCg0KIyDQl9Cw0LTQsNGH0LAgOQ0KDQrQntCy0LDQsCDQt9Cw0LTQsNGH0LAg0LjQvNCwINGB0LUg0L7QtCDQv9GA0LXRgtGF0L7QtNC90LjRgtC1INCy0L4g0L3QtdCwLCDQv9CwINC30LDRgtC+0LAg0LUg0YHQutC+0LrQvdCw0YLQsC4=