if(!require(fitdistrplus)) install.packages("fitdistrplus")
if(!require(EnvStats)) install.packages("EnvStats")
if(!require(betareg)) install.packages("betareg")
if(!require(ggplot2)) install.packages("ggplot2")
if(!require(car)) install.packages("car")
Para realizar este estudo, utilizamos um dataset com 16.000 valores de Entropia de permutação de Shannon e Complexidade estatística referentes a ruídos brancos gerados artificialmente com amostras de tamanhos \(N \in \{10.000, 20.000, 30.000, 40.000, 50.000, 60.000, 70.000, 80.000, 90.000, 100.000\}\), aplicando todas as possíveis configurações de \(D \in \{3, 4, 5, 6\}\) e \(\tau \in \{1, 2, 3, 4\}\) aos descritores.
A disposição dos dados no plano pode ser observada abaixo.
HC.BP = data.frame("H" = numeric(16000),
"C" = numeric(16000),
"Dist" = numeric(16000),
"D" = numeric(16000),
"t" = numeric(16000),
"N" = numeric(16000),
stringsAsFactors=FALSE)
HC.BP$N = as.factor(rep(c(rep(1e+04, 100), rep(2e+04, 100), rep(3e+04, 100), rep(4e+04, 100), rep(5e+04, 100), rep(6e+04, 100), rep(7e+04, 100), rep(8e+04, 100), rep(9e+04, 100), rep(1e+05, 100)), 16))
HC.BP$t = as.factor(rep(c(rep(1,1000), rep(2,1000), rep(3,1000), rep(4,1000)), 4))
file.csv = data.frame(read.csv("../Data/HC_series_fk0_16000.csv"))
HC.BP$H = file.csv[,1]
HC.BP$C = file.csv[,2]
HC.BP$Dist = HC.BP$C / HC.BP$H
HC.BP$D= as.factor(file.csv[,3])
O primeiro passo que deve ser realizado ao modelar um problema por meio de uma regressão linear é analisar o comportamento das variáveis resposta e explicativa, verificando quais distribuições tais dados assumem. Logo, para isso analisaremos separadamente o histograma das variáveis consideradas no problema (entropia de Shannon e complexidade estatística).
Na geração dos modelos de regressão, vamos considerar duas hipóteses de análise: na primeira, apenas \(D\) e \(\tau\) influenciam na construção de uma região de intervalo de confiança, e na segunda além de tais parâmetros, o tamanho \(N\) das séries consideradas também possui um importante fator de impacto nesta construção.
Hypothesis 1: D and N matter
dimension = c(3,4,5,6)
N = c(1e+04, 2e+04, 3e+04, 4e+04, 5e+04, 6e+04, 7e+04, 8e+04, 9e+04, 1e+05)
HC.data.1 = list(data.frame("H" = numeric(400), "C" = numeric(400), stringsAsFactors=FALSE), 40)
b = cc = 0
for(i in 1:length(dimension)){
for(j in 1:length(N)){
cc = cc + 1
a = c((((j - 1) * 100) + 1):(j * 100))
elements = c(a + b, a + b + 1000, a + b + 2000, a + b + 3000)
HC.data.1$H[[cc]] = HC.BP$H[elements]
HC.data.1$C[[cc]] = HC.BP$C[elements]
}
b = b + 4000
}
Facilitando a visualização, mostraremos neste relatório apenas o comportamento dos dados de 1 dos 16 subconjuntos utilizados.
hist(HC.data.1$H[[1]], breaks = 10)
hist(HC.data.1$C[[1]], breaks = 10)

Observando o comportamento das distribuições, podemos inferir que \(H_1 \sim \mathbb{\beta}(\mu_{11}, \phi_{11})\) e \(C_1 \sim \mathbb{\beta}(\mu_{12}, \phi_{12})\). Para testar tais suposições, aplicamos o fit sobre os dados e obtemos os resuldados abaixo.
fit.H.1 = fitdist(HC.data.1$H[[1]], "beta")
NaNs producedNaNs producedNaNs producedNaNs producedNaNs producedNaNs produced
plot(fit.H.1, las = 1)

fit.C.1 = fitdist(HC.data.1$C[[1]], "beta")
NaNs producedNaNs producedNaNs producedNaNs producedNaNs producedNaNs produced
plot(fit.C.1, las = 1)

Hypothesis 2: D, t and N matter
Seguindo os mesmos passos com a hipótese 2:
HC.data.2 = array(data.frame("H" = numeric(100), "C" = numeric(100), stringsAsFactors=FALSE), 160)
for(i in 1:160){
elements = c((((i-1)*100)+1):(i*100))
HC.data.2$H[[i]] = HC.BP$H[elements]
HC.data.2$C[[i]] = HC.BP$C[elements]
}
hist(HC.data.2$H[[1]], breaks = 10)

hist(HC.data.2$C[[1]], breaks = 10)

fit.H.2 = fitdist(HC.data.2$C[[1]], "beta")
NaNs producedNaNs producedNaNs producedNaNs producedNaNs producedNaNs produced
plot(fit.H.2, las = 1)

fit.C.2 = fitdist(HC.data.2$C[[1]], "beta")
NaNs producedNaNs producedNaNs producedNaNs producedNaNs producedNaNs produced
plot(fit.C.2, las = 1)

Regressão beta
Os parâmetros desconhecidos de uma regressão linear são geralmente determinados pelo método da máxima verossimilhança, assumindo que dada as variáveis explicativas, a variável resposta correspondente segue uma distribuição gaussiana. No entando, verificamos acima que as variáveis do problema em questão assumem valores no intervalo unitário padrão \((0, 1)\) e seguem a distribuição beta. Tornando assim, as aproximações baseadas em distribuições gaussianas para estimativa de intervalos e teste de hipóteses bastante imprecisas.
Levando em consideração os fatores acima, analisamos a eficiência do modelo de regressão beta. Tal modelo inclui uma estrutura de variação mais flexível determinada por variáveis independentes distribuídas beta que estão relacionadas a um conjunto de variáveis independentes por meio de uma estrutura de regressão. É naturalmente heterocedástico, acomoda facilmente assimetrias e os seus parâmetros de regressão são interpretáveis em termos da média da variável de interesse.
As densidades beta podem ser expressas em uma parametrização em termos da média \(\mu\) e do parâmetro de precisão \(\phi\) do seguinte modo:
\[
f(y|\mu,\phi) = \frac{\Gamma(\phi)}{\Gamma(\mu\phi)\Gamma((1-\mu)\phi)} y^{\mu\phi-1} (1-y)^{(1-\mu)\phi-1},
\] sendo \(0 < y < 1\), \(0 < \mu < 1\) e \(\phi > 0\). Logo, temos que:
\[
\mathbb{E}(y) = \mu,
\]
\[
\mathbb{Var}(y) = \frac{\mu(1-\mu)}{(1 + \phi)} ,
\]
O parâmetro \(\phi\) é conhecido como parâmetro de precisão, pois, para \(\mu\) fixo, quanto maior \(\phi\), menor a variação de y. \(\phi^{-1}\) é um parâmetro de dispersão.
Seja \(y_1, y_2, \dots, y_n\) um conjunto de variáveis aleatórias, tais que \(y_i \sim \mathbb{\beta}(\mu_i, \phi)\), \(i = 1, 2, \dots, n\). O modelo de regressão beta é definido como:
\[
g(\mu_i) = x_i^T \alpha = \eta_i,
\]
onde \(\alpha = (\alpha_1, \dots, \alpha_n)^T\) é o vetor dos parâmetros desconhecidos da regressão e possui dimensão \(k \times 1\) \((k < n)\), \(x_i = (x_{i1}, \dots, x_{ik})^T\) é o vetor de \(k\) variáveis independentes e \(\eta_i\) é a variável linear preditora (isto é, \(\eta_i = \alpha_1 x_{i1} + \dots + \alpha_n x_{in}\), usualmente \(x_{i1} = 1\) para todo \(i\)).
A função \(g(.) : (0,1) \mapsto \mathbb{R}\) é uma função link, que é estritamente crescente e duplamente diferenciável. Existem duas principais motivações para o uso de uma função link na estrutura de regressão. Primeiramente, ambos os lados da equação de regressão assumem valores na linha real quando uma função de link é aplicada a \(\mu_i\). Em segundo lugar, há uma flexibilidade adicional, pois podemos escolher a função que produz o melhor ajuste.
As principais funções de link utilizadas são:
Logit: \(g(\mu) = log(\frac{\mu}{(1-\mu)})\);
Probit: \(g(\mu) = \phi^{-1}(\mu)\), onde \(\phi\) é a função de distribuição normal padrão;
Complementary log-log: \(g(\mu) = log(-log(1-\mu))\);
Log-log: \(g(\mu) = log(-log(\mu))\);
Cauchy: \(g(\mu) = tan(\pi(\mu - 0.5))\).
Seleção entre diferentes funções de link
A seleção de uma função de link apropriada pode melhorar muito o ajuste do modelo, especialmente se proporções extremas (próximas a 0 ou 1) foram observadas nos dados, como ocorre o caso em questão. Desse modo, modelamos nossas hipóteses com as principais variações da função link e calculamos seus respectivos valores de R-square. R-square consiste de uma medida estatística de quão próximos os dados estão da linha de regressão ajustada.
Hypothesis 1: D and t matter
dimension = c(3,4,5,6)
N = c(1e+04, 2e+04, 3e+04, 4e+04, 5e+04, 6e+04, 7e+04, 8e+04, 9e+04, 1e+05)
HC.data.1 = list(data.frame("H" = numeric(400), "C" = numeric(400), stringsAsFactors=FALSE), 40)
b = cc = 0
for(i in 1:length(dimension)){
for(j in 1:length(N)){
cc = cc + 1
a = c((((j - 1) * 100) + 1):(j * 100))
elements = c(a + b, a + b + 1000, a + b + 2000, a + b + 3000)
HC.data.1$H[[cc]] = HC.BP$H[elements]
HC.data.1$C[[cc]] = HC.BP$C[elements]
}
b = b + 4000
}
HC = data.frame("H" = numeric(400), "C" = numeric(400), stringsAsFactors=FALSE)
lm.fit.logit.1 = lm.fit.probit.1 = lm.fit.cloglog.1 = lm.fit.loglog.1 = array(list(), 40)
r.squared.1 = data.frame("logit" = numeric(40), "probit" = numeric(40), "cloglog" = numeric(40),"loglog" = numeric(40), stringsAsFactors=FALSE)
for(i in 1:40){
HC$H = HC.data.1$H[[i]]
HC$C = HC.data.1$C[[i]]
lm.fit.logit.1[[i]] = betareg(data = HC, formula = C ~ H, link = "logit")
r.squared.1$logit[i] = lm.fit.logit.1[[i]]$pseudo.r.squared
lm.fit.probit.1[[i]] = betareg(data = HC, formula = C ~ H, link = "probit")
r.squared.1$probit[i] = lm.fit.probit.1[[i]]$pseudo.r.squared
lm.fit.cloglog.1[[i]] = betareg(data = HC, formula = C ~ H, link = "cloglog")
r.squared.1$cloglog[i] = lm.fit.cloglog.1[[i]]$pseudo.r.squared
lm.fit.loglog.1[[i]] = betareg(data = HC, formula = C ~ H, link = "loglog")
r.squared.1$loglog[i] = lm.fit.loglog.1[[i]]$pseudo.r.squared
}
Hypothesis 2: D, t and N matter
HC = data.frame("H" = numeric(100), "C" = numeric(100), stringsAsFactors=FALSE)
lm.fit.logit.2 = lm.fit.probit.2 = lm.fit.cloglog.2 = lm.fit.loglog.2 = array(list(), 160)
r.squared.2 = data.frame("logit" = numeric(160), "probit" = numeric(160), "cloglog" = numeric(160),"loglog" = numeric(160), stringsAsFactors=FALSE)
for(i in 1:160){
HC$H = HC.data.2$H[[i]]
HC$C = HC.data.2$C[[i]]
lm.fit.logit.2[[i]] = betareg(data = HC, formula = C ~ H, link = "logit")
r.squared.2$logit[i] = lm.fit.logit.2[[i]]$pseudo.r.squared
lm.fit.probit.2[[i]] = betareg(data = HC, formula = C ~ H, link = "probit")
r.squared.2$probit[i] = lm.fit.probit.2[[i]]$pseudo.r.squared
lm.fit.cloglog.2[[i]] = betareg(data = HC, formula = C ~ H, link = "cloglog")
r.squared.2$cloglog[i] = lm.fit.cloglog.2[[i]]$pseudo.r.squared
lm.fit.loglog.2[[i]] = betareg(data = HC, formula = C ~ H, link = "loglog")
r.squared.2$loglog[i] = lm.fit.loglog.2[[i]]$pseudo.r.squared
}
summary(r.squared.2)
logit probit cloglog loglog
Min. :0.6430 Min. :0.7119 Min. :0.6399 Min. :0.7644
1st Qu.:0.7304 1st Qu.:0.7858 1st Qu.:0.7281 1st Qu.:0.8270
Median :0.7619 Median :0.8124 Median :0.7598 Median :0.8501
Mean :0.7600 Mean :0.8107 Mean :0.7581 Mean :0.8469
3rd Qu.:0.7926 3rd Qu.:0.8359 3rd Qu.:0.7909 3rd Qu.:0.8673
Max. :0.8527 Max. :0.8859 Max. :0.8511 Max. :0.9091
Como visto acima, os melhores ajustes são obtidos ao aplicar a função de link loglog sobre o modelo de regressão. No entanto, em geral um modelo ajusta bem os dados se as diferenças entre os valores observados e os valores previstos do modelo são pequenas e imparciais. Ao observar os gráficos de diagnótico para as regressões vemos que tal modelo ainda não é o adequado para os nossos dados.
Hypothesis 1: D and N matter
plot(lm.fit.loglog.1[[1]])




Hypothesis 2: D, t and N matter
plot(lm.fit.loglog.2[[1]])




Concluímos que o modelo ainda não obtem um bom ajuste após verificarmos os plots de suas respectivas regressões.
Hypothesis 1: D and N matter
HC = data.frame("H" = HC.data.1$H[[1]], "C" = HC.data.1$C[[1]], stringsAsFactors=FALSE)
ggplot(HC, aes(x = H, y = C)) +
geom_point() +
scale_fill_grey() +
geom_line(aes(y = predict(lm.fit.loglog.1[[1]], HC)))

Hypothesis 2: D, t and N matter
HC = data.frame("H" = HC.data.2$H[[1]], "C" = HC.data.2$C[[1]], stringsAsFactors=FALSE)
ggplot(HC, aes(x = H, y = C)) +
geom_point() +
scale_fill_grey() +
geom_line(aes(y = predict(lm.fit.loglog.2[[1]], HC)))

LS0tCnRpdGxlOiAiUmVwb3J0IDIgLSBCZXRhIHJlZ3Jlc3Npb24gYW5hbHlzaXMiCmF1dGhvcjogIkVkdWFyZGEgQ2hhZ2FzIgpkYXRlOiAiQXByIDI0LCAyMDIwIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazogZGVmYXVsdAogIHBkZl9kb2N1bWVudDogZGVmYXVsdAotLS0KCmBgYHtyfQppZighcmVxdWlyZShmaXRkaXN0cnBsdXMpKSBpbnN0YWxsLnBhY2thZ2VzKCJmaXRkaXN0cnBsdXMiKQppZighcmVxdWlyZShFbnZTdGF0cykpIGluc3RhbGwucGFja2FnZXMoIkVudlN0YXRzIikKaWYoIXJlcXVpcmUoYmV0YXJlZykpIGluc3RhbGwucGFja2FnZXMoImJldGFyZWciKQppZighcmVxdWlyZShnZ3Bsb3QyKSkgaW5zdGFsbC5wYWNrYWdlcygiZ2dwbG90MiIpCmlmKCFyZXF1aXJlKGNhcikpIGluc3RhbGwucGFja2FnZXMoImNhciIpCmBgYAoKUGFyYSByZWFsaXphciBlc3RlIGVzdHVkbywgdXRpbGl6YW1vcyB1bSBkYXRhc2V0IGNvbSAxNi4wMDAgdmFsb3JlcyBkZSBFbnRyb3BpYSBkZSBwZXJtdXRhw6fDo28gZGUgU2hhbm5vbiBlIENvbXBsZXhpZGFkZSBlc3RhdMOtc3RpY2EgcmVmZXJlbnRlcyBhIHJ1w61kb3MgYnJhbmNvcyBnZXJhZG9zIGFydGlmaWNpYWxtZW50ZSBjb20gYW1vc3RyYXMgZGUgdGFtYW5ob3MgJE4gXGluIFx7MTAuMDAwLCAyMC4wMDAsIDMwLjAwMCwgNDAuMDAwLCA1MC4wMDAsIDYwLjAwMCwgNzAuMDAwLCA4MC4wMDAsIDkwLjAwMCwgMTAwLjAwMFx9JCwgYXBsaWNhbmRvIHRvZGFzIGFzIHBvc3PDrXZlaXMgY29uZmlndXJhw6fDtWVzIGRlICREIFxpbiBcezMsIDQsIDUsIDZcfSQgZSAgJFx0YXUgXGluIFx7MSwgMiwgMywgNFx9JCBhb3MgZGVzY3JpdG9yZXMuCgpBIGRpc3Bvc2nDp8OjbyBkb3MgZGFkb3Mgbm8gcGxhbm8gcG9kZSBzZXIgb2JzZXJ2YWRhIGFiYWl4by4KCmBgYHtyfQpIQy5CUCA9IGRhdGEuZnJhbWUoIkgiID0gbnVtZXJpYygxNjAwMCksIAogICAgICAgICAgICAgICAgICAgIkMiID0gbnVtZXJpYygxNjAwMCksCiAgICAgICAgICAgICAgICAgICAiRGlzdCIgPSBudW1lcmljKDE2MDAwKSwKICAgICAgICAgICAgICAgICAgICJEIiA9IG51bWVyaWMoMTYwMDApLAogICAgICAgICAgICAgICAgICAgInQiID0gbnVtZXJpYygxNjAwMCksIAogICAgICAgICAgICAgICAgICAgIk4iID0gbnVtZXJpYygxNjAwMCksIAogICAgICAgICAgICAgICAgICAgc3RyaW5nc0FzRmFjdG9ycz1GQUxTRSkKCkhDLkJQJE4gPSBhcy5mYWN0b3IocmVwKGMocmVwKDFlKzA0LCAxMDApLCByZXAoMmUrMDQsIDEwMCksIHJlcCgzZSswNCwgMTAwKSwgcmVwKDRlKzA0LCAxMDApLCByZXAoNWUrMDQsIDEwMCksIHJlcCg2ZSswNCwgMTAwKSwgcmVwKDdlKzA0LCAxMDApLCByZXAoOGUrMDQsIDEwMCksIHJlcCg5ZSswNCwgMTAwKSwgcmVwKDFlKzA1LCAxMDApKSwgMTYpKQoKSEMuQlAkdCA9IGFzLmZhY3RvcihyZXAoYyhyZXAoMSwxMDAwKSwgcmVwKDIsMTAwMCksIHJlcCgzLDEwMDApLCByZXAoNCwxMDAwKSksIDQpKQoKZmlsZS5jc3YgPSBkYXRhLmZyYW1lKHJlYWQuY3N2KCIuLi9EYXRhL0hDX3Nlcmllc19mazBfMTYwMDAuY3N2IikpCgpIQy5CUCRIID0gZmlsZS5jc3ZbLDFdCkhDLkJQJEMgPSBmaWxlLmNzdlssMl0KSEMuQlAkRGlzdCA9IEhDLkJQJEMgLyBIQy5CUCRICkhDLkJQJEQ9IGFzLmZhY3RvcihmaWxlLmNzdlssM10pCmBgYAoKTyBwcmltZWlybyBwYXNzbyBxdWUgZGV2ZSBzZXIgcmVhbGl6YWRvIGFvIG1vZGVsYXIgdW0gcHJvYmxlbWEgcG9yIG1laW8gZGUgdW1hIHJlZ3Jlc3PDo28gbGluZWFyIMOpIGFuYWxpc2FyIG8gY29tcG9ydGFtZW50byBkYXMgdmFyacOhdmVpcyByZXNwb3N0YSBlIGV4cGxpY2F0aXZhLCB2ZXJpZmljYW5kbyBxdWFpcyBkaXN0cmlidWnDp8O1ZXMgdGFpcyBkYWRvcyBhc3N1bWVtLgpMb2dvLCBwYXJhIGlzc28gYW5hbGlzYXJlbW9zIHNlcGFyYWRhbWVudGUgbyBoaXN0b2dyYW1hIGRhcyB2YXJpw6F2ZWlzIGNvbnNpZGVyYWRhcyBubyBwcm9ibGVtYSAoZW50cm9waWEgZGUgU2hhbm5vbiBlIGNvbXBsZXhpZGFkZSBlc3RhdMOtc3RpY2EpLgoKTmEgZ2VyYcOnw6NvIGRvcyBtb2RlbG9zIGRlIHJlZ3Jlc3PDo28sIHZhbW9zIGNvbnNpZGVyYXIgZHVhcyBoaXDDs3Rlc2VzIGRlIGFuw6FsaXNlOiBuYSBwcmltZWlyYSwgYXBlbmFzICREJCBlICRcdGF1JCBpbmZsdWVuY2lhbSBuYSBjb25zdHJ1w6fDo28gZGUgdW1hIHJlZ2nDo28gZGUgaW50ZXJ2YWxvIGRlIGNvbmZpYW7Dp2EsIGUgbmEgc2VndW5kYSBhbMOpbSBkZSB0YWlzIHBhcsOibWV0cm9zLCBvIHRhbWFuaG8gJE4kIGRhcyBzw6lyaWVzIGNvbnNpZGVyYWRhcyB0YW1iw6ltIHBvc3N1aSB1bSBpbXBvcnRhbnRlIGZhdG9yIGRlIGltcGFjdG8gbmVzdGEgY29uc3RydcOnw6NvLiAgCgojIyMjIyoqSHlwb3RoZXNpcyAxOiBEIGFuZCBOIG1hdHRlcioqCgpgYGB7cn0KZGltZW5zaW9uID0gYygzLDQsNSw2KQpOID0gYygxZSswNCwgMmUrMDQsIDNlKzA0LCA0ZSswNCwgNWUrMDQsIDZlKzA0LCA3ZSswNCwgOGUrMDQsIDllKzA0LCAxZSswNSkKSEMuZGF0YS4xID0gbGlzdChkYXRhLmZyYW1lKCJIIiA9IG51bWVyaWMoNDAwKSwgIkMiID0gbnVtZXJpYyg0MDApLCBzdHJpbmdzQXNGYWN0b3JzPUZBTFNFKSwgNDApCgpiID0gY2MgPSAwCmZvcihpIGluIDE6bGVuZ3RoKGRpbWVuc2lvbikpewogIGZvcihqIGluIDE6bGVuZ3RoKE4pKXsKICAgIGNjID0gY2MgKyAxCiAgICBhID0gYygoKChqIC0gMSkgKiAxMDApICsgMSk6KGogKiAxMDApKQogICAgZWxlbWVudHMgPSBjKGEgKyBiLCBhICsgYiArIDEwMDAsIGEgKyBiICsgMjAwMCwgYSArIGIgKyAzMDAwKQogICAgSEMuZGF0YS4xJEhbW2NjXV0gPSBIQy5CUCRIW2VsZW1lbnRzXQogICAgSEMuZGF0YS4xJENbW2NjXV0gPSBIQy5CUCRDW2VsZW1lbnRzXQogIH0KICBiID0gYiArIDQwMDAKfQpgYGAKCkZhY2lsaXRhbmRvIGEgdmlzdWFsaXphw6fDo28sIG1vc3RyYXJlbW9zIG5lc3RlIHJlbGF0w7NyaW8gYXBlbmFzIG8gY29tcG9ydGFtZW50byBkb3MgZGFkb3MgZGUgMSBkb3MgMTYgc3ViY29uanVudG9zIHV0aWxpemFkb3MuCgpgYGB7cn0KaGlzdChIQy5kYXRhLjEkSFtbMV1dLCBicmVha3MgPSAxMCkKYGBgCgpgYGB7cn0KaGlzdChIQy5kYXRhLjEkQ1tbMV1dLCBicmVha3MgPSAxMCkKYGBgCgpPYnNlcnZhbmRvIG8gY29tcG9ydGFtZW50byBkYXMgZGlzdHJpYnVpw6fDtWVzLCBwb2RlbW9zIGluZmVyaXIgcXVlICRIXzEgXHNpbSBcbWF0aGJie1xiZXRhfShcbXVfezExfSwgXHBoaV97MTF9KSQgZSAkQ18xIFxzaW0gXG1hdGhiYntcYmV0YX0oXG11X3sxMn0sIFxwaGlfezEyfSkkLgpQYXJhIHRlc3RhciB0YWlzIHN1cG9zacOnw7VlcywgYXBsaWNhbW9zIG8gZml0IHNvYnJlIG9zIGRhZG9zIGUgb2J0ZW1vcyBvcyByZXN1bGRhZG9zIGFiYWl4by4KCmBgYHtyfQpmaXQuSC4xID0gZml0ZGlzdChIQy5kYXRhLjEkSFtbMV1dLCAiYmV0YSIpCnBsb3QoZml0LkguMSwgbGFzID0gMSkgCmBgYAoKYGBge3J9CmZpdC5DLjEgPSBmaXRkaXN0KEhDLmRhdGEuMSRDW1sxXV0sICJiZXRhIikKcGxvdChmaXQuQy4xLCBsYXMgPSAxKSAKYGBgCgojIyMjIyoqSHlwb3RoZXNpcyAyOiBELCB0IGFuZCBOIG1hdHRlcioqCgpTZWd1aW5kbyBvcyBtZXNtb3MgcGFzc29zIGNvbSBhIGhpcMOzdGVzZSAyOiAKCmBgYHtyfQpIQy5kYXRhLjIgPSBhcnJheShkYXRhLmZyYW1lKCJIIiA9IG51bWVyaWMoMTAwKSwgIkMiID0gbnVtZXJpYygxMDApLCBzdHJpbmdzQXNGYWN0b3JzPUZBTFNFKSwgMTYwKQoKZm9yKGkgaW4gMToxNjApewogIGVsZW1lbnRzID0gYygoKChpLTEpKjEwMCkrMSk6KGkqMTAwKSkKICBIQy5kYXRhLjIkSFtbaV1dID0gSEMuQlAkSFtlbGVtZW50c10KICBIQy5kYXRhLjIkQ1tbaV1dID0gSEMuQlAkQ1tlbGVtZW50c10KfQoKaGlzdChIQy5kYXRhLjIkSFtbMV1dLCBicmVha3MgPSAxMCkKYGBgCgoKYGBge3J9Cmhpc3QoSEMuZGF0YS4yJENbWzFdXSwgYnJlYWtzID0gMTApCmBgYAoKYGBge3J9CmZpdC5ILjIgPSBmaXRkaXN0KEhDLmRhdGEuMiRDW1sxXV0sICJiZXRhIikKcGxvdChmaXQuSC4yLCBsYXMgPSAxKSAKYGBgCgpgYGB7cn0KZml0LkMuMiA9IGZpdGRpc3QoSEMuZGF0YS4yJENbWzFdXSwgImJldGEiKQpwbG90KGZpdC5DLjIsIGxhcyA9IDEpIApgYGAKCiMjI1JlZ3Jlc3PDo28gYmV0YQoKT3MgcGFyw6JtZXRyb3MgZGVzY29uaGVjaWRvcyBkZSB1bWEgcmVncmVzc8OjbyBsaW5lYXIgc8OjbyBnZXJhbG1lbnRlIGRldGVybWluYWRvcyBwZWxvIG3DqXRvZG8gZGEgbcOheGltYSB2ZXJvc3NpbWlsaGFuw6dhLCBhc3N1bWluZG8gcXVlIGRhZGEgYXMgdmFyacOhdmVpcyBleHBsaWNhdGl2YXMsIGEgdmFyacOhdmVsIHJlc3Bvc3RhIGNvcnJlc3BvbmRlbnRlIHNlZ3VlIHVtYSBkaXN0cmlidWnDp8OjbyBnYXVzc2lhbmEuCk5vIGVudGFuZG8sIHZlcmlmaWNhbW9zIGFjaW1hIHF1ZSBhcyB2YXJpw6F2ZWlzIGRvIHByb2JsZW1hIGVtIHF1ZXN0w6NvIGFzc3VtZW0gdmFsb3JlcyBubyBpbnRlcnZhbG8gdW5pdMOhcmlvIHBhZHLDo28gJCgwLCAxKSQgZSBzZWd1ZW0gYSBkaXN0cmlidWnDp8OjbyBiZXRhLiAKVG9ybmFuZG8gYXNzaW0sIGFzIGFwcm94aW1hw6fDtWVzIGJhc2VhZGFzIGVtIGRpc3RyaWJ1acOnw7VlcyBnYXVzc2lhbmFzIHBhcmEgZXN0aW1hdGl2YSBkZSBpbnRlcnZhbG9zIGUgdGVzdGUgZGUgaGlww7N0ZXNlcyBiYXN0YW50ZSBpbXByZWNpc2FzLgoKTGV2YW5kbyBlbSBjb25zaWRlcmHDp8OjbyBvcyBmYXRvcmVzIGFjaW1hLCBhbmFsaXNhbW9zIGEgZWZpY2nDqm5jaWEgZG8gbW9kZWxvIGRlIHJlZ3Jlc3PDo28gYmV0YS4gClRhbCBtb2RlbG8gaW5jbHVpIHVtYSBlc3RydXR1cmEgZGUgdmFyaWHDp8OjbyBtYWlzIGZsZXjDrXZlbCBkZXRlcm1pbmFkYSBwb3IgdmFyacOhdmVpcyBpbmRlcGVuZGVudGVzIGRpc3RyaWJ1w61kYXMgYmV0YSBxdWUgZXN0w6NvIHJlbGFjaW9uYWRhcyBhIHVtIGNvbmp1bnRvIGRlIHZhcmnDoXZlaXMgaW5kZXBlbmRlbnRlcyBwb3IgbWVpbyBkZSB1bWEgZXN0cnV0dXJhIGRlIHJlZ3Jlc3PDo28uCsOJIG5hdHVyYWxtZW50ZSBoZXRlcm9jZWTDoXN0aWNvLCBhY29tb2RhIGZhY2lsbWVudGUgYXNzaW1ldHJpYXMgZSBvcyBzZXVzIHBhcsOibWV0cm9zIGRlIHJlZ3Jlc3PDo28gc8OjbyBpbnRlcnByZXTDoXZlaXMgZW0gdGVybW9zIGRhIG3DqWRpYSBkYSB2YXJpw6F2ZWwgZGUgaW50ZXJlc3NlLiAKCkFzIGRlbnNpZGFkZXMgYmV0YSBwb2RlbSBzZXIgZXhwcmVzc2FzIGVtIHVtYSBwYXJhbWV0cml6YcOnw6NvIGVtIHRlcm1vcyBkYSBtw6lkaWEgJFxtdSQgZSBkbyBwYXLDom1ldHJvIGRlIHByZWNpc8OjbyAkXHBoaSQgZG8gc2VndWludGUgbW9kbzoKCiQkCmYoeXxcbXUsXHBoaSkgPSBcZnJhY3tcR2FtbWEoXHBoaSl9e1xHYW1tYShcbXVccGhpKVxHYW1tYSgoMS1cbXUpXHBoaSl9IHlee1xtdVxwaGktMX0gKDEteSleeygxLVxtdSlccGhpLTF9LCAKJCQKIHNlbmRvICQwIDwgeSA8IDEkLCAkMCA8IFxtdSA8IDEkIGUgJFxwaGkgPiAwJC4KIExvZ28sIHRlbW9zIHF1ZToKIAogJCQKIFxtYXRoYmJ7RX0oeSkgPSBcbXUsCiAkJAogCiAkJAogXG1hdGhiYntWYXJ9KHkpID0gIFxmcmFje1xtdSgxLVxtdSl9eygxICsgXHBoaSl9ICwKICQkCiAKIE8gcGFyw6JtZXRybyAkXHBoaSQgw6kgY29uaGVjaWRvIGNvbW8gcGFyw6JtZXRybyBkZSBwcmVjaXPDo28sIHBvaXMsIHBhcmEgJFxtdSQgZml4bywgcXVhbnRvIG1haW9yICRccGhpJCwgbWVub3IgYSB2YXJpYcOnw6NvIGRlIHkuCiAkXHBoaV57LTF9JCDDqSB1bSBwYXLDom1ldHJvIGRlIGRpc3BlcnPDo28uCiAKIFNlamEgJHlfMSwgeV8yLCBcZG90cywgeV9uJCB1bSBjb25qdW50byBkZSB2YXJpw6F2ZWlzIGFsZWF0w7NyaWFzLCB0YWlzIHF1ZSAkeV9pIFxzaW0gXG1hdGhiYntcYmV0YX0oXG11X2ksIFxwaGkpJCwgJGkgPSAxLCAyLCBcZG90cywgbiQuIAogTyBtb2RlbG8gZGUgcmVncmVzc8OjbyBiZXRhIMOpIGRlZmluaWRvIGNvbW86IAogCiAkJAogZyhcbXVfaSkgPSB4X2leVCBcYWxwaGEgPSBcZXRhX2ksCiAkJAogCm9uZGUgJFxhbHBoYSA9IChcYWxwaGFfMSwgXGRvdHMsIFxhbHBoYV9uKV5UJCDDqSBvIHZldG9yIGRvcyBwYXLDom1ldHJvcyBkZXNjb25oZWNpZG9zIGRhIHJlZ3Jlc3PDo28gZSBwb3NzdWkgZGltZW5zw6NvICRrIFx0aW1lcyAxJCAkKGsgPCBuKSQsICR4X2kgPSAoeF97aTF9LCBcZG90cywgeF97aWt9KV5UJCDDqSBvIHZldG9yIGRlICRrJCB2YXJpw6F2ZWlzIGluZGVwZW5kZW50ZXMgZSAkXGV0YV9pJCDDqSBhIHZhcmnDoXZlbCBsaW5lYXIgcHJlZGl0b3JhIChpc3RvIMOpLCAkXGV0YV9pID0gXGFscGhhXzEgeF97aTF9ICsgXGRvdHMgKyBcYWxwaGFfbiB4X3tpbn0kLCB1c3VhbG1lbnRlICR4X3tpMX0gPSAxJCBwYXJhIHRvZG8gJGkkKS4KIApBIGZ1bsOnw6NvICRnKC4pIDogKDAsMSkgXG1hcHN0byBcbWF0aGJie1J9JCDDqSB1bWEgZnVuw6fDo28gbGluaywgcXVlIMOpIGVzdHJpdGFtZW50ZSBjcmVzY2VudGUgZSBkdXBsYW1lbnRlIGRpZmVyZW5jacOhdmVsLgpFeGlzdGVtIGR1YXMgcHJpbmNpcGFpcyBtb3RpdmHDp8O1ZXMgcGFyYSBvIHVzbyBkZSB1bWEgZnVuw6fDo28gbGluayBuYSBlc3RydXR1cmEgZGUgcmVncmVzc8Ojby4KUHJpbWVpcmFtZW50ZSwgYW1ib3Mgb3MgbGFkb3MgZGEgZXF1YcOnw6NvIGRlIHJlZ3Jlc3PDo28gYXNzdW1lbSB2YWxvcmVzIG5hIGxpbmhhIHJlYWwgcXVhbmRvIHVtYSBmdW7Dp8OjbyBkZSBsaW5rIMOpIGFwbGljYWRhIGEgJFxtdV9pJC4KRW0gc2VndW5kbyBsdWdhciwgaMOhIHVtYSBmbGV4aWJpbGlkYWRlIGFkaWNpb25hbCwgcG9pcyBwb2RlbW9zIGVzY29saGVyIGEgZnVuw6fDo28gcXVlIHByb2R1eiBvIG1lbGhvciBhanVzdGUuCgpBcyBwcmluY2lwYWlzIGZ1bsOnw7VlcyBkZSBsaW5rIHV0aWxpemFkYXMgc8OjbzoKCjEuIExvZ2l0OiAkZyhcbXUpID0gbG9nKFxmcmFje1xtdX17KDEtXG11KX0pJDsKCjIuIFByb2JpdDogJGcoXG11KSA9IFxwaGleey0xfShcbXUpJCwgb25kZSAkXHBoaSQgw6kgYSBmdW7Dp8OjbyBkZSBkaXN0cmlidWnDp8OjbyBub3JtYWwgcGFkcsOjbzsKCjMuIENvbXBsZW1lbnRhcnkgbG9nLWxvZzogJGcoXG11KSA9IGxvZygtbG9nKDEtXG11KSkkOwoKNC4gTG9nLWxvZzogJGcoXG11KSA9IGxvZygtbG9nKFxtdSkpJDsKCjUuIENhdWNoeTogJGcoXG11KSA9IHRhbihccGkoXG11IC0gMC41KSkkLgoKIyMjU2VsZcOnw6NvIGVudHJlIGRpZmVyZW50ZXMgZnVuw6fDtWVzIGRlIGxpbmsKCkEgc2VsZcOnw6NvIGRlIHVtYSBmdW7Dp8OjbyBkZSBsaW5rIGFwcm9wcmlhZGEgcG9kZSBtZWxob3JhciBtdWl0byBvIGFqdXN0ZSBkbyBtb2RlbG8sIGVzcGVjaWFsbWVudGUgc2UgcHJvcG9yw6fDtWVzIGV4dHJlbWFzIChwcsOzeGltYXMgYSAwIG91IDEpIGZvcmFtIG9ic2VydmFkYXMgbm9zIGRhZG9zLCBjb21vIG9jb3JyZSBvIGNhc28gZW0gcXVlc3TDo28uCkRlc3NlIG1vZG8sIG1vZGVsYW1vcyBub3NzYXMgaGlww7N0ZXNlcyBjb20gYXMgcHJpbmNpcGFpcyB2YXJpYcOnw7VlcyBkYSBmdW7Dp8OjbyBsaW5rIGUgY2FsY3VsYW1vcyBzZXVzIHJlc3BlY3Rpdm9zIHZhbG9yZXMgZGUgUi1zcXVhcmUuClItc3F1YXJlIGNvbnNpc3RlIGRlIHVtYSBtZWRpZGEgZXN0YXTDrXN0aWNhIGRlIHF1w6NvIHByw7N4aW1vcyBvcyBkYWRvcyBlc3TDo28gZGEgbGluaGEgZGUgcmVncmVzc8OjbyBhanVzdGFkYS4KCiMjIyMjKipIeXBvdGhlc2lzIDE6IEQgYW5kIHQgbWF0dGVyKioKCgpgYGB7cn0KZGltZW5zaW9uID0gYygzLDQsNSw2KQpOID0gYygxZSswNCwgMmUrMDQsIDNlKzA0LCA0ZSswNCwgNWUrMDQsIDZlKzA0LCA3ZSswNCwgOGUrMDQsIDllKzA0LCAxZSswNSkKSEMuZGF0YS4xID0gbGlzdChkYXRhLmZyYW1lKCJIIiA9IG51bWVyaWMoNDAwKSwgIkMiID0gbnVtZXJpYyg0MDApLCBzdHJpbmdzQXNGYWN0b3JzPUZBTFNFKSwgNDApCgpiID0gY2MgPSAwCmZvcihpIGluIDE6bGVuZ3RoKGRpbWVuc2lvbikpewogIGZvcihqIGluIDE6bGVuZ3RoKE4pKXsKICAgIGNjID0gY2MgKyAxCiAgICBhID0gYygoKChqIC0gMSkgKiAxMDApICsgMSk6KGogKiAxMDApKQogICAgZWxlbWVudHMgPSBjKGEgKyBiLCBhICsgYiArIDEwMDAsIGEgKyBiICsgMjAwMCwgYSArIGIgKyAzMDAwKQogICAgSEMuZGF0YS4xJEhbW2NjXV0gPSBIQy5CUCRIW2VsZW1lbnRzXQogICAgSEMuZGF0YS4xJENbW2NjXV0gPSBIQy5CUCRDW2VsZW1lbnRzXQogIH0KICBiID0gYiArIDQwMDAKfQpgYGAKCgpgYGB7cn0KSEMgPSBkYXRhLmZyYW1lKCJIIiA9IG51bWVyaWMoNDAwKSwgIkMiID0gbnVtZXJpYyg0MDApLCBzdHJpbmdzQXNGYWN0b3JzPUZBTFNFKQpsbS5maXQubG9naXQuMSA9IGxtLmZpdC5wcm9iaXQuMSA9IGxtLmZpdC5jbG9nbG9nLjEgPSBsbS5maXQubG9nbG9nLjEgPSBhcnJheShsaXN0KCksIDQwKQpyLnNxdWFyZWQuMSA9IGRhdGEuZnJhbWUoImxvZ2l0IiA9IG51bWVyaWMoNDApLCAicHJvYml0IiA9IG51bWVyaWMoNDApLCAiY2xvZ2xvZyIgPSBudW1lcmljKDQwKSwibG9nbG9nIiA9IG51bWVyaWMoNDApLCBzdHJpbmdzQXNGYWN0b3JzPUZBTFNFKQoKZm9yKGkgaW4gMTo0MCl7CiAgSEMkSCA9IEhDLmRhdGEuMSRIW1tpXV0KICBIQyRDID0gSEMuZGF0YS4xJENbW2ldXQogIAogIGxtLmZpdC5sb2dpdC4xW1tpXV0gPSBiZXRhcmVnKGRhdGEgPSBIQywgZm9ybXVsYSA9IEMgfiBILCBsaW5rID0gImxvZ2l0IikKICByLnNxdWFyZWQuMSRsb2dpdFtpXSA9IGxtLmZpdC5sb2dpdC4xW1tpXV0kcHNldWRvLnIuc3F1YXJlZAogIAogIGxtLmZpdC5wcm9iaXQuMVtbaV1dID0gYmV0YXJlZyhkYXRhID0gSEMsIGZvcm11bGEgPSBDIH4gSCwgbGluayA9ICJwcm9iaXQiKQogIHIuc3F1YXJlZC4xJHByb2JpdFtpXSA9IGxtLmZpdC5wcm9iaXQuMVtbaV1dJHBzZXVkby5yLnNxdWFyZWQKICAKICBsbS5maXQuY2xvZ2xvZy4xW1tpXV0gPSBiZXRhcmVnKGRhdGEgPSBIQywgZm9ybXVsYSA9IEMgfiBILCBsaW5rID0gImNsb2dsb2ciKQogIHIuc3F1YXJlZC4xJGNsb2dsb2dbaV0gPSBsbS5maXQuY2xvZ2xvZy4xW1tpXV0kcHNldWRvLnIuc3F1YXJlZAogIAogIGxtLmZpdC5sb2dsb2cuMVtbaV1dID0gYmV0YXJlZyhkYXRhID0gSEMsIGZvcm11bGEgPSBDIH4gSCwgbGluayA9ICJsb2dsb2ciKQogIHIuc3F1YXJlZC4xJGxvZ2xvZ1tpXSA9IGxtLmZpdC5sb2dsb2cuMVtbaV1dJHBzZXVkby5yLnNxdWFyZWQKfSAKCnN1bW1hcnkoci5zcXVhcmVkLjEpCmBgYAoKIyMjIyMqKkh5cG90aGVzaXMgMjogRCwgdCBhbmQgTiBtYXR0ZXIqKgoKYGBge3J9CkhDID0gZGF0YS5mcmFtZSgiSCIgPSBudW1lcmljKDEwMCksICJDIiA9IG51bWVyaWMoMTAwKSwgc3RyaW5nc0FzRmFjdG9ycz1GQUxTRSkKbG0uZml0LmxvZ2l0LjIgPSBsbS5maXQucHJvYml0LjIgPSBsbS5maXQuY2xvZ2xvZy4yID0gbG0uZml0LmxvZ2xvZy4yID0gYXJyYXkobGlzdCgpLCAxNjApCnIuc3F1YXJlZC4yID0gZGF0YS5mcmFtZSgibG9naXQiID0gbnVtZXJpYygxNjApLCAicHJvYml0IiA9IG51bWVyaWMoMTYwKSwgImNsb2dsb2ciID0gbnVtZXJpYygxNjApLCJsb2dsb2ciID0gbnVtZXJpYygxNjApLCBzdHJpbmdzQXNGYWN0b3JzPUZBTFNFKQoKZm9yKGkgaW4gMToxNjApewogIEhDJEggPSBIQy5kYXRhLjIkSFtbaV1dCiAgSEMkQyA9IEhDLmRhdGEuMiRDW1tpXV0KICAKICBsbS5maXQubG9naXQuMltbaV1dID0gYmV0YXJlZyhkYXRhID0gSEMsIGZvcm11bGEgPSBDIH4gSCwgbGluayA9ICJsb2dpdCIpCiAgci5zcXVhcmVkLjIkbG9naXRbaV0gPSBsbS5maXQubG9naXQuMltbaV1dJHBzZXVkby5yLnNxdWFyZWQKICAKICBsbS5maXQucHJvYml0LjJbW2ldXSA9IGJldGFyZWcoZGF0YSA9IEhDLCBmb3JtdWxhID0gQyB+IEgsIGxpbmsgPSAicHJvYml0IikKICByLnNxdWFyZWQuMiRwcm9iaXRbaV0gPSBsbS5maXQucHJvYml0LjJbW2ldXSRwc2V1ZG8uci5zcXVhcmVkCiAgCiAgbG0uZml0LmNsb2dsb2cuMltbaV1dID0gYmV0YXJlZyhkYXRhID0gSEMsIGZvcm11bGEgPSBDIH4gSCwgbGluayA9ICJjbG9nbG9nIikKICByLnNxdWFyZWQuMiRjbG9nbG9nW2ldID0gbG0uZml0LmNsb2dsb2cuMltbaV1dJHBzZXVkby5yLnNxdWFyZWQKICAKICBsbS5maXQubG9nbG9nLjJbW2ldXSA9IGJldGFyZWcoZGF0YSA9IEhDLCBmb3JtdWxhID0gQyB+IEgsIGxpbmsgPSAibG9nbG9nIikKICByLnNxdWFyZWQuMiRsb2dsb2dbaV0gPSBsbS5maXQubG9nbG9nLjJbW2ldXSRwc2V1ZG8uci5zcXVhcmVkCn0gCgpzdW1tYXJ5KHIuc3F1YXJlZC4yKQpgYGAKCkNvbW8gdmlzdG8gYWNpbWEsIG9zIG1lbGhvcmVzIGFqdXN0ZXMgc8OjbyBvYnRpZG9zIGFvIGFwbGljYXIgYSBmdW7Dp8OjbyBkZSBsaW5rIGxvZ2xvZyBzb2JyZSBvIG1vZGVsbyBkZSByZWdyZXNzw6NvLiAKTm8gZW50YW50bywgZW0gZ2VyYWwgdW0gbW9kZWxvIGFqdXN0YSBiZW0gb3MgZGFkb3Mgc2UgYXMgZGlmZXJlbsOnYXMgZW50cmUgb3MgdmFsb3JlcyBvYnNlcnZhZG9zIGUgb3MgdmFsb3JlcyBwcmV2aXN0b3MgZG8gbW9kZWxvIHPDo28gcGVxdWVuYXMgZSBpbXBhcmNpYWlzLgpBbyBvYnNlcnZhciBvcyBncsOhZmljb3MgZGUgZGlhZ27Ds3RpY28gcGFyYSBhcyByZWdyZXNzw7VlcyB2ZW1vcyBxdWUgdGFsIG1vZGVsbyBhaW5kYSBuw6NvIMOpIG8gYWRlcXVhZG8gcGFyYSBvcyBub3Nzb3MgZGFkb3MuCgojIyMjIyoqSHlwb3RoZXNpcyAxOiBEIGFuZCBOIG1hdHRlcioqCgpgYGB7cn0KcGxvdChsbS5maXQubG9nbG9nLjFbWzFdXSkgCmBgYAoKIyMjIyMqKkh5cG90aGVzaXMgMjogRCwgdCBhbmQgTiBtYXR0ZXIqKgoKYGBge3J9CnBsb3QobG0uZml0LmxvZ2xvZy4yW1sxXV0pIApgYGAKCkNvbmNsdcOtbW9zIHF1ZSBvIG1vZGVsbyBhaW5kYSBuw6NvIG9idGVtIHVtIGJvbSBhanVzdGUgYXDDs3MgdmVyaWZpY2FybW9zIG9zIHBsb3RzIGRlIHN1YXMgcmVzcGVjdGl2YXMgcmVncmVzc8O1ZXMuCgojIyMjIyoqSHlwb3RoZXNpcyAxOiBEIGFuZCBOIG1hdHRlcioqCgpgYGB7cn0KSEMgPSBkYXRhLmZyYW1lKCJIIiA9IEhDLmRhdGEuMSRIW1sxXV0sICJDIiA9IEhDLmRhdGEuMSRDW1sxXV0sIHN0cmluZ3NBc0ZhY3RvcnM9RkFMU0UpCgpnZ3Bsb3QoSEMsIGFlcyh4ID0gSCwgeSA9IEMpKSArCiAgZ2VvbV9wb2ludCgpICsKICBzY2FsZV9maWxsX2dyZXkoKSArCiAgZ2VvbV9saW5lKGFlcyh5ID0gcHJlZGljdChsbS5maXQubG9nbG9nLjFbWzFdXSwgSEMpKSkgCmBgYAoKIyMjIyMqKkh5cG90aGVzaXMgMjogRCwgdCBhbmQgTiBtYXR0ZXIqKgoKYGBge3J9CkhDID0gZGF0YS5mcmFtZSgiSCIgPSBIQy5kYXRhLjIkSFtbMV1dLCAiQyIgPSBIQy5kYXRhLjIkQ1tbMV1dLCBzdHJpbmdzQXNGYWN0b3JzPUZBTFNFKQoKZ2dwbG90KEhDLCBhZXMoeCA9IEgsIHkgPSBDKSkgKwogIGdlb21fcG9pbnQoKSArCiAgc2NhbGVfZmlsbF9ncmV5KCkgKwogIGdlb21fbGluZShhZXMoeSA9IHByZWRpY3QobG0uZml0LmxvZ2xvZy4yW1sxXV0sIEhDKSkpIApgYGAK