1. Introdução
Diversos testes estatísticos clássicos — teste t, ANOVA, regressão
linear, entre outros — baseiam-se na suposição de que a variável de
interesse (ou os resíduos do modelo) segue uma distribuição
Normal. Essa suposição não pode ser assumida apenas pela
inspeção visual dos dados: é necessário verificá-la formalmente antes de
aplicar qualquer técnica paramétrica.
Os testes de normalidade são testes de hipóteses do
tipo aderência (goodness-of-fit), cujo objetivo é
avaliar se uma amostra é compatível com a hipótese de ter sido gerada
por uma população normalmente distribuída. Neste relatório utilizamos os
dois testes formais mais empregados na prática —
Shapiro-Wilk e Kolmogorov-Smirnov —
complementados por recursos gráficos (histograma, boxplot e
QQ-Plot).
2. Objetivo da Análise
Verificar, com base em dados reais, se as variáveis Wind
e Ozone do conjunto de dados airquality são
compatíveis com a distribuição Normal, por meio de:
- Análise exploratória e inspeção gráfica (histograma, boxplot,
QQ-Plot);
- Verificação dos pressupostos de aplicação dos testes;
- Aplicação dos testes de Shapiro-Wilk e
Kolmogorov-Smirnov;
- Resolução manual de um exemplo com amostra reduzida (n = 5);
- Interpretação do p-valor e comparação com o método do valor
crítico;
- Discussão crítica sobre vantagens, limitações e testes
alternativos;
- Conclusão sobre a adequação de cada variável a procedimentos
paramétricos.
Propositalmente escolhemos duas variáveis do mesmo conjunto de dados
com comportamento oposto — uma aproximadamente simétrica
(Wind) e outra fortemente assimétrica (Ozone)
— para evidenciar, na prática, como os testes formais e os gráficos
reagem a cada cenário.
3. Descrição da Base de Dados
O conjunto de dados airquality é uma base real e
pública, distribuída nativamente com o R (pacote
datasets), com origem no New York State Department of
Conservation (dados de ozônio) e no National Weather
Service (dados meteorológicos). Contém 153 observações
diárias de qualidade do ar na cidade de Nova York, entre
maio e setembro de 1973.
Ozone |
Concentração média de ozônio |
ppb (partes por bilhão) |
Solar.R |
Radiação solar |
langleys |
Wind |
Velocidade média do vento |
milhas/hora |
Temp |
Temperatura máxima diária |
°F |
Month |
Mês da observação |
5 a 9 |
Day |
Dia do mês |
1 a 31 |
Neste relatório focamos em Wind (sem
valores ausentes) e Ozone (com valores
ausentes, tratados na seção de pressupostos).
data("airquality")
cat("Dimensão da base:", nrow(airquality), "observações x", ncol(airquality), "variáveis\n")
## Dimensão da base: 153 observações x 6 variáveis
head(airquality, 10)
| 41 |
190 |
7.4 |
67 |
5 |
1 |
| 36 |
118 |
8.0 |
72 |
5 |
2 |
| 12 |
149 |
12.6 |
74 |
5 |
3 |
| 18 |
313 |
11.5 |
62 |
5 |
4 |
| NA |
NA |
14.3 |
56 |
5 |
5 |
| 28 |
NA |
14.9 |
66 |
5 |
6 |
| 23 |
299 |
8.6 |
65 |
5 |
7 |
| 19 |
99 |
13.8 |
59 |
5 |
8 |
| 8 |
19 |
20.1 |
61 |
5 |
9 |
| NA |
194 |
8.6 |
69 |
5 |
10 |
sapply(airquality, function(x) sum(is.na(x)))
## Ozone Solar.R Wind Temp Month Day
## 37 7 0 0 0 0
4. Fundamentação Teórica
4.2 Pressupostos
- Variável quantitativa contínua;
- Amostra aleatória e composta por observações
independentes;
- Ausência de valores ausentes (tratados antes da aplicação do
teste).
4.3 Estatística de Teste — Shapiro-Wilk
W = ( Σ aᵢ · x₍ᵢ₎ )² / Σ (xᵢ − x̄)²
onde x₍ᵢ₎ são as observações ordenadas e aᵢ são coeficientes
tabelados (Shapiro & Wilk, 1965), derivados dos valores esperados e
da matriz de covariância das estatísticas de ordem de uma Normal padrão.
W varia no intervalo (0, 1]: quanto mais próximo de 1, mais a amostra se
assemelha a uma Normal. Não possui graus de liberdade no sentido
clássico; sua distribuição amostral é obtida por simulação/tabela.
4.4 Estatística de Teste — Kolmogorov-Smirnov (uma amostra)
D = sup |Fₙ(x) − F₀(x)|
onde Fₙ(x) é a função de distribuição empírica da amostra e F₀(x) é a
função de distribuição acumulada teórica da Normal. D é a maior
distância vertical entre as duas curvas. O teste clássico de KS exige
que F₀ seja totalmente especificada; por isso os dados
são padronizados (z-score) antes do teste — ressalvando que a
forma rigorosamente correta para parâmetros estimados da amostra é o
teste de Lilliefors.
4.5 Regra de Decisão
- Método do p-valor: rejeita-se H0 se p ≤ α (neste
relatório, α = 0,05);
- Método do valor crítico: rejeita-se H0 se a
estatística do teste (W ou D) for menor (W) ou maior (D) que o valor
crítico tabelado para n e α.
Os dois métodos são equivalentes. O método do valor crítico será
demonstrado no exemplo manual (Seção 6); o método do p-valor, na
aplicação computacional (Seção 8).
5. Metodologia
- Importação da base
airquality (nativa do R);
- Tratamento de valores ausentes por variável
(
na.omit);
- Análise exploratória (estatísticas descritivas, histograma,
boxplot);
- Verificação dos pressupostos;
- Resolução manual do Shapiro-Wilk para uma subamostra de n=5;
- Aplicação computacional dos testes de Shapiro-Wilk e
Kolmogorov-Smirnov (com padronização) sobre as séries completas, a α =
0,05;
- Construção de painel gráfico (histograma, boxplot, QQ-Plot);
- Comparação com testes alternativos (quando disponíveis no
ambiente);
- Interpretação do p-valor, discussão e conclusão.
O procedimento foi implementado também em Python
(normalidade.py, usando scipy.stats),
confirmando a equivalência dos resultados entre as duas linguagens.
6. Análise Exploratória dos Dados
wind <- na.omit(airquality$Wind)
ozone <- na.omit(airquality$Ozone)
skewness <- function(x) {
n <- length(x); m <- mean(x); s <- sqrt(sum((x - m)^2) / n)
sum(((x - m) / s)^3) / n
}
kurtosis_exc <- function(x) {
n <- length(x); m <- mean(x); s <- sqrt(sum((x - m)^2) / n)
sum(((x - m) / s)^4) / n - 3
}
resumo <- data.frame(
Estatistica = c("n", "Média", "Mediana", "Desvio-padrão",
"Assimetria", "Curtose (excesso)", "Mínimo", "Máximo"),
Wind = c(length(wind), mean(wind), median(wind), sd(wind),
skewness(wind), kurtosis_exc(wind), min(wind), max(wind)),
Ozone = c(length(ozone), mean(ozone), median(ozone), sd(ozone),
skewness(ozone), kurtosis_exc(ozone), min(ozone), max(ozone))
)
knitr::kable(resumo, digits = 4)
| n |
153.0000 |
116.0000 |
| Média |
9.9575 |
42.1293 |
| Mediana |
9.7000 |
31.5000 |
| Desvio-padrão |
3.5230 |
32.9879 |
| Assimetria |
0.3444 |
1.2257 |
| Curtose (excesso) |
0.0688 |
1.1841 |
| Mínimo |
1.7000 |
1.0000 |
| Máximo |
20.7000 |
168.0000 |
Leitura inicial: Wind apresenta
assimetria próxima de zero, sugerindo forma aproximadamente simétrica.
Ozone apresenta assimetria positiva acentuada (cauda longa
à direita) — sinal característico de
não-normalidade.
par(mfrow = c(1, 2))
hist(wind, main = "Histograma — Wind", xlab = "mph", col = "steelblue", breaks = 12)
hist(ozone, main = "Histograma — Ozone", xlab = "ppb", col = "tomato", breaks = 12)

par(mfrow = c(1, 2))
boxplot(wind, main = "Boxplot — Wind", ylab = "mph")
boxplot(ozone, main = "Boxplot — Ozone", ylab = "ppb")

O boxplot de Wind é razoavelmente simétrico, com poucos
outliers. O de Ozone mostra mediana deslocada para a parte
inferior da caixa e diversos outliers superiores.
7. Verificação dos Pressupostos
| Variável quantitativa contínua |
Atendido |
Atendido |
| Observações independentes |
Atendido (por construção do estudo) |
Atendido (por construção do estudo) |
| Valores ausentes |
Nenhum |
37 valores ausentes — removidos via na.omit() |
| Tamanho de amostra após tratamento |
n = 153 |
n = 116 |
Observação metodológica: por se tratar de série
temporal diária, existe em princípio a possibilidade de autocorrelação
entre observações consecutivas. Para os fins didáticos deste seminário,
tratamos as observações como independentes, como é prática comum ao
testar a forma marginal da distribuição.
8. Exemplo Resolvido Manualmente — Shapiro-Wilk (n = 5)
Usamos as 5 primeiras observações reais de
Wind (dias 1 a 5 de maio de 1973), com os coeficientes
tabelados (Shapiro & Wilk, 1965) para n=5: a5 = 0,6646; a4 = 0,2413;
a3 = 0.
x5 <- head(wind, 5)
cat("Amostra (Wind, dias 1-5/maio/1973):", x5, "\n")
## Amostra (Wind, dias 1-5/maio/1973): 7.4 8 12.6 11.5 14.3
x_ord <- sort(x5)
cat("Amostra ordenada:", x_ord, "\n")
## Amostra ordenada: 7.4 8 11.5 12.6 14.3
media <- mean(x_ord)
SS <- sum((x_ord - media)^2)
a5 <- 0.6646; a4 <- 0.2413
b <- a5 * (x_ord[5] - x_ord[1]) + a4 * (x_ord[4] - x_ord[2])
W_manual <- b^2 / SS
cat(sprintf("\nMédia (x̄) = %.4f\n", media))
##
## Média (x̄) = 10.7600
cat(sprintf("Soma de quadrados (SS) = %.4f\n", SS))
## Soma de quadrados (SS) = 35.3720
cat(sprintf("b = a5*(x5-x1)+a4*(x4-x2) = %.4f\n", b))
## b = a5*(x5-x1)+a4*(x4-x2) = 5.6957
cat(sprintf("W calculado manualmente = %.4f\n", W_manual))
## W calculado manualmente = 0.9171
W_crit <- 0.762 # valor tabelado para n=5, alpha=0.05
decisao_manual <- if (W_manual > W_crit) "NÃO se rejeita H0" else "Rejeita-se H0"
cat(sprintf("W calculado = %.4f | W crítico (n=5, alpha=0.05) = %.3f\n", W_manual, W_crit))
## W calculado = 0.9171 | W crítico (n=5, alpha=0.05) = 0.762
cat("Regra: rejeita-se H0 se W < W_crit -> Decisão:", decisao_manual, "\n")
## Regra: rejeita-se H0 se W < W_crit -> Decisão: NÃO se rejeita H0
teste_conferencia <- shapiro.test(x5)
cat(sprintf("\nConferência (shapiro.test): W = %.4f | p-valor = %.4f\n",
teste_conferencia$statistic, teste_conferencia$p.value))
##
## Conferência (shapiro.test): W = 0.9173 | p-valor = 0.5128
Interpretação: o valor de W calculado manualmente
coincide com o de shapiro.test(). Como W está
acima do valor crítico tabelado (0,762) para n=5 e
α=0,05, não rejeitamos H0 — coerente com o resultado da
amostra completa de Wind (n=153), na próxima seção.
9. Aplicação do Teste (Software Estatístico)
Aplicamos os testes de Shapiro-Wilk e
Kolmogorov-Smirnov às séries completas. Para o KS,
padronizamos os dados (z-score) antes de comparar com a Normal
padrão N(0,1).
alpha <- 0.05
testar_normalidade <- function(serie, nome) {
serie_z <- scale(serie)[, 1]
sw <- shapiro.test(serie)
ks <- ks.test(serie_z, "pnorm")
data.frame(
Variavel = nome,
n = length(serie),
`Shapiro_W` = sw$statistic,
`p_valor_SW` = sw$p.value,
`KS_D` = ks$statistic,
`p_valor_KS` = ks$p.value,
`Decisao_SW` = if (sw$p.value > alpha) "Não rejeita H0" else "Rejeita H0",
`Decisao_KS` = if (ks$p.value > alpha) "Não rejeita H0" else "Rejeita H0"
)
}
resultados <- rbind(
testar_normalidade(wind, "Wind"),
testar_normalidade(ozone, "Ozone")
)
rownames(resultados) <- NULL
knitr::kable(resultados, digits = 4)
| Wind |
153 |
0.9857 |
0.1178 |
0.0824 |
0.2501 |
Não rejeita H0 |
Não rejeita H0 |
| Ozone |
116 |
0.8787 |
0.0000 |
0.1480 |
0.0124 |
Rejeita H0 |
Rejeita H0 |
Em Python, o procedimento equivalente está em
normalidade.py (script completo):
sw_stat, sw_p = stats.shapiro(serie)
ks_stat, ks_p = stats.kstest(stats.zscore(serie), "norm")
10. Resultados
10.1 Método do p-valor
- Wind: p(SW) > 0,05 e p(KS) > 0,05 →
não se rejeita H0 — compatível com Normal.
- Ozone: p(SW) ≤ 0,05 e p(KS) ≤ 0,05 →
rejeita-se H0 — não compatível com Normal.
10.2 Método do valor crítico (ilustração)
Para amostras grandes (n=153 e n=116), o método do p-valor é o mais
prático; o método do valor crítico foi demonstrado na Seção 8 para n=5.
Os dois métodos são equivalentes e levam à mesma decisão.
11. Visualizações Gráficas
par(mfrow = c(1, 3))
hist(wind, main = "Histograma — Wind", xlab = "mph", col = "steelblue", breaks = 12)
boxplot(wind, main = "Boxplot — Wind", ylab = "mph")
qqnorm(wind, main = "QQ-Plot — Wind")
qqline(wind, col = "red", lwd = 2)

par(mfrow = c(1, 3))
hist(ozone, main = "Histograma — Ozone", xlab = "ppb", col = "tomato", breaks = 12)
boxplot(ozone, main = "Boxplot — Ozone", ylab = "ppb")
qqnorm(ozone, main = "QQ-Plot — Ozone")
qqline(ozone, col = "red", lwd = 2)

Leitura dos QQ-Plots: em Wind, os
pontos seguem de perto a reta de referência. Em Ozone, os
pontos se afastam sistematicamente da reta nas extremidades, revelando
visualmente a assimetria quantificada pelos testes formais.
12. Discussão
- Os dois testes concordam na decisão final para
ambas as variáveis, mas discordam na magnitude da
evidência: para
Ozone, o Shapiro-Wilk produz um
p-valor extremamente pequeno (ordem de 10⁻⁸), muito mais extremo do que
o do Kolmogorov-Smirnov — o Shapiro-Wilk é, em geral, mais sensível a
desvios de normalidade.
- O KS, ao depender da maior distância entre curvas acumuladas, tende
a ser menos sensível a desvios localizados (caudas pesadas, poucos
outliers).
- A inspeção gráfica confirmou a conclusão dos testes formais em ambos
os casos, reforçando a recomendação de sempre cruzar teste formal com
gráfico.
13. Vantagens e Limitações dos Testes
| Shapiro-Wilk |
Maior poder estatístico entre os testes clássicos, especialmente
para n pequeno/médio |
Sensível a outliers; em amostras muito grandes, rejeita H0 mesmo
para desvios sem relevância prática |
| Kolmogorov-Smirnov |
Conceito geral, aplicável a qualquer distribuição teórica |
Menos sensível que o Shapiro-Wilk; exige distribuição totalmente
especificada (motivou a correção de Lilliefors) |
16. Conclusão
Com base nos testes de Shapiro-Wilk e
Kolmogorov-Smirnov, complementados pela inspeção
gráfica, concluímos que:
- A variável
Wind é estatisticamente
compatível com a distribuição Normal (p > 0,05 em
ambos os testes), tanto na amostra completa (n=153) quanto no exemplo
manual (n=5);
- A variável
Ozone não é
compatível com a distribuição Normal (p ≤ 0,05 em ambos os
testes), com evidência fortíssima no Shapiro-Wilk;
- Os resultados obtidos em R e em
Python (
normalidade.py) coincidem,
validando a implementação computacional em ambas as linguagens;
- Quando a normalidade não se confirma — como em
Ozone —
as alternativas metodológicas incluem: (i) transformação da variável
(log, Box-Cox), (ii) uso de testes não-paramétricos equivalentes, (iii)
apoio no Teorema Central do Limite quando a amostra é suficientemente
grande, ou (iv) métodos robustos/bootstrap.
17. Referências
- BUSSAB, W. O.; MORETTIN, P. A. Estatística Básica. São
Paulo: Saraiva.
- MONTGOMERY, D. C.; RUNGER, G. C. Estatística Aplicada e
Probabilidade para Engenheiros. Rio de Janeiro: LTC.
- PAGANO, M.; GAUVREAU, K. Princípios de Bioestatística. São
Paulo: Cengage Learning.
- CONOVER, W. J. Practical Nonparametric Statistics. New
York: Wiley.
- HOLLANDER, M.; WOLFE, D. A. Nonparametric Statistical
Methods. New York: Wiley.
- SHAPIRO, S. S.; WILK, M. B. An analysis of variance test for
normality (complete samples). Biometrika, v. 52, n. 3/4,
p. 591–611, 1965.
- MASSEY JR., F. J. The Kolmogorov-Smirnov test for goodness of fit.
Journal of the American Statistical Association, v. 46, n. 253,
p. 68–78, 1951.
- R CORE TEAM. R: A Language and Environment for Statistical
Computing. Documentação de
shapiro.test(),
ks.test(), qqnorm(),
qqline().
Arquivos complementares deste seminário (mesma
pasta): normalidade.R,
normalidade.py
LS0tCnRpdGxlOiAiUmVsYXTDs3JpbyBBbmFsw610aWNvIOKAlCBUZXN0ZXMgZGUgTm9ybWFsaWRhZGUiCnN1YnRpdGxlOiAiU2hhcGlyby1XaWxrIGUgS29sbW9nb3Jvdi1TbWlybm92IMK3IEdydXBvIDggwrcgSW5mZXLDqm5jaWEgRXN0YXTDrXN0aWNhIgphdXRob3I6CiAgLSAiQW50b25pbyBTYW1wYWlvIGRlIE1hcmluaG8g4oCUIE1hdHLDrWN1bGE6IDU2NjQ1MCIKICAtICJBbmEgVml0w7NyaWEgVmllaXJhIEZyZWlyZSBkZSBNZXNxdWlzdGEg4oCUIE1hdHLDrWN1bGE6IDU4MTA0MiIKZGF0ZTogImByIGZvcm1hdChTeXMuRGF0ZSgpLCAnJWQvJW0vJVknKWAiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIHRvY19kZXB0aDogMwogICAgdGhlbWU6IGNvc21vCiAgICBkZl9wcmludDoga2FibGUKICAgIG1hdGhqYXg6IG51bGwKICAgIHNlbGZfY29udGFpbmVkOiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSwgZmlnLmFsaWduID0gImNlbnRlciIpCmBgYAoKIyAxLiBJbnRyb2R1w6fDo28KCkRpdmVyc29zIHRlc3RlcyBlc3RhdMOtc3RpY29zIGNsw6Fzc2ljb3Mg4oCUIHRlc3RlIHQsIEFOT1ZBLCByZWdyZXNzw6NvIGxpbmVhciwgZW50cmUgb3V0cm9zIOKAlCBiYXNlaWFtLXNlIG5hIHN1cG9zacOnw6NvIGRlIHF1ZSBhIHZhcmnDoXZlbCBkZSBpbnRlcmVzc2UgKG91IG9zIHJlc8OtZHVvcyBkbyBtb2RlbG8pIHNlZ3VlIHVtYSAqKmRpc3RyaWJ1acOnw6NvIE5vcm1hbCoqLiBFc3NhIHN1cG9zacOnw6NvIG7Do28gcG9kZSBzZXIgYXNzdW1pZGEgYXBlbmFzIHBlbGEgaW5zcGXDp8OjbyB2aXN1YWwgZG9zIGRhZG9zOiDDqSBuZWNlc3PDoXJpbyB2ZXJpZmljw6EtbGEgZm9ybWFsbWVudGUgYW50ZXMgZGUgYXBsaWNhciBxdWFscXVlciB0w6ljbmljYSBwYXJhbcOpdHJpY2EuCgpPcyAqKnRlc3RlcyBkZSBub3JtYWxpZGFkZSoqIHPDo28gdGVzdGVzIGRlIGhpcMOzdGVzZXMgZG8gdGlwbyAqYWRlcsOqbmNpYSogKCpnb29kbmVzcy1vZi1maXQqKSwgY3VqbyBvYmpldGl2byDDqSBhdmFsaWFyIHNlIHVtYSBhbW9zdHJhIMOpIGNvbXBhdMOtdmVsIGNvbSBhIGhpcMOzdGVzZSBkZSB0ZXIgc2lkbyBnZXJhZGEgcG9yIHVtYSBwb3B1bGHDp8OjbyBub3JtYWxtZW50ZSBkaXN0cmlidcOtZGEuIE5lc3RlIHJlbGF0w7NyaW8gdXRpbGl6YW1vcyBvcyBkb2lzIHRlc3RlcyBmb3JtYWlzIG1haXMgZW1wcmVnYWRvcyBuYSBwcsOhdGljYSDigJQgKipTaGFwaXJvLVdpbGsqKiBlICoqS29sbW9nb3Jvdi1TbWlybm92Kiog4oCUIGNvbXBsZW1lbnRhZG9zIHBvciByZWN1cnNvcyBncsOhZmljb3MgKGhpc3RvZ3JhbWEsIGJveHBsb3QgZSBRUS1QbG90KS4KCiMgMi4gT2JqZXRpdm8gZGEgQW7DoWxpc2UKClZlcmlmaWNhciwgY29tIGJhc2UgZW0gZGFkb3MgcmVhaXMsIHNlIGFzIHZhcmnDoXZlaXMgYFdpbmRgIGUgYE96b25lYCBkbyBjb25qdW50byBkZSBkYWRvcyBgYWlycXVhbGl0eWAgc8OjbyBjb21wYXTDrXZlaXMgY29tIGEgZGlzdHJpYnVpw6fDo28gTm9ybWFsLCBwb3IgbWVpbyBkZToKCjEuIEFuw6FsaXNlIGV4cGxvcmF0w7NyaWEgZSBpbnNwZcOnw6NvIGdyw6FmaWNhIChoaXN0b2dyYW1hLCBib3hwbG90LCBRUS1QbG90KTsKMi4gVmVyaWZpY2HDp8OjbyBkb3MgcHJlc3N1cG9zdG9zIGRlIGFwbGljYcOnw6NvIGRvcyB0ZXN0ZXM7CjMuIEFwbGljYcOnw6NvIGRvcyB0ZXN0ZXMgZGUgKipTaGFwaXJvLVdpbGsqKiBlICoqS29sbW9nb3Jvdi1TbWlybm92Kio7CjQuIFJlc29sdcOnw6NvIG1hbnVhbCBkZSB1bSBleGVtcGxvIGNvbSBhbW9zdHJhIHJlZHV6aWRhIChuID0gNSk7CjUuIEludGVycHJldGHDp8OjbyBkbyBwLXZhbG9yIGUgY29tcGFyYcOnw6NvIGNvbSBvIG3DqXRvZG8gZG8gdmFsb3IgY3LDrXRpY287CjYuIERpc2N1c3PDo28gY3LDrXRpY2Egc29icmUgdmFudGFnZW5zLCBsaW1pdGHDp8O1ZXMgZSB0ZXN0ZXMgYWx0ZXJuYXRpdm9zOwo3LiBDb25jbHVzw6NvIHNvYnJlIGEgYWRlcXVhw6fDo28gZGUgY2FkYSB2YXJpw6F2ZWwgYSBwcm9jZWRpbWVudG9zIHBhcmFtw6l0cmljb3MuCgpQcm9wb3NpdGFsbWVudGUgZXNjb2xoZW1vcyBkdWFzIHZhcmnDoXZlaXMgZG8gbWVzbW8gY29uanVudG8gZGUgZGFkb3MgY29tIGNvbXBvcnRhbWVudG8gb3Bvc3RvIOKAlCB1bWEgYXByb3hpbWFkYW1lbnRlIHNpbcOpdHJpY2EgKGBXaW5kYCkgZSBvdXRyYSBmb3J0ZW1lbnRlIGFzc2ltw6l0cmljYSAoYE96b25lYCkg4oCUIHBhcmEgZXZpZGVuY2lhciwgbmEgcHLDoXRpY2EsIGNvbW8gb3MgdGVzdGVzIGZvcm1haXMgZSBvcyBncsOhZmljb3MgcmVhZ2VtIGEgY2FkYSBjZW7DoXJpby4KCiMgMy4gRGVzY3Jpw6fDo28gZGEgQmFzZSBkZSBEYWRvcwoKTyBjb25qdW50byBkZSBkYWRvcyBgYWlycXVhbGl0eWAgw6kgdW1hIGJhc2UgKipyZWFsIGUgcMO6YmxpY2EqKiwgZGlzdHJpYnXDrWRhIG5hdGl2YW1lbnRlIGNvbSBvIFIgKHBhY290ZSBgZGF0YXNldHNgKSwgY29tIG9yaWdlbSBubyAqTmV3IFlvcmsgU3RhdGUgRGVwYXJ0bWVudCBvZiBDb25zZXJ2YXRpb24qIChkYWRvcyBkZSBvesO0bmlvKSBlIG5vICpOYXRpb25hbCBXZWF0aGVyIFNlcnZpY2UqIChkYWRvcyBtZXRlb3JvbMOzZ2ljb3MpLiBDb250w6ltICoqMTUzIG9ic2VydmHDp8O1ZXMgZGnDoXJpYXMqKiBkZSBxdWFsaWRhZGUgZG8gYXIgbmEgY2lkYWRlIGRlIE5vdmEgWW9yaywgZW50cmUgKiptYWlvIGUgc2V0ZW1icm8gZGUgMTk3MyoqLgoKfCBWYXJpw6F2ZWwgfCBEZXNjcmnDp8OjbyB8IFVuaWRhZGUgfAp8LS0tfC0tLXwtLS18CnwgYE96b25lYCB8IENvbmNlbnRyYcOnw6NvIG3DqWRpYSBkZSBvesO0bmlvIHwgcHBiIChwYXJ0ZXMgcG9yIGJpbGjDo28pIHwKfCBgU29sYXIuUmAgfCBSYWRpYcOnw6NvIHNvbGFyIHwgbGFuZ2xleXMgfAp8IGBXaW5kYCB8IFZlbG9jaWRhZGUgbcOpZGlhIGRvIHZlbnRvIHwgbWlsaGFzL2hvcmEgfAp8IGBUZW1wYCB8IFRlbXBlcmF0dXJhIG3DoXhpbWEgZGnDoXJpYSB8IMKwRiB8CnwgYE1vbnRoYCB8IE3DqnMgZGEgb2JzZXJ2YcOnw6NvIHwgNSBhIDkgfAp8IGBEYXlgIHwgRGlhIGRvIG3DqnMgfCAxIGEgMzEgfAoKTmVzdGUgcmVsYXTDs3JpbyBmb2NhbW9zIGVtICoqYFdpbmRgKiogKHNlbSB2YWxvcmVzIGF1c2VudGVzKSBlICoqYE96b25lYCoqIChjb20gdmFsb3JlcyBhdXNlbnRlcywgdHJhdGFkb3MgbmEgc2XDp8OjbyBkZSBwcmVzc3Vwb3N0b3MpLgoKYGBge3IgY2FycmVnYXItZGFkb3N9CmRhdGEoImFpcnF1YWxpdHkiKQpjYXQoIkRpbWVuc8OjbyBkYSBiYXNlOiIsIG5yb3coYWlycXVhbGl0eSksICJvYnNlcnZhw6fDtWVzIHgiLCBuY29sKGFpcnF1YWxpdHkpLCAidmFyacOhdmVpc1xuIikKaGVhZChhaXJxdWFsaXR5LCAxMCkKYGBgCgpgYGB7ciBhdXNlbnRlc30Kc2FwcGx5KGFpcnF1YWxpdHksIGZ1bmN0aW9uKHgpIHN1bShpcy5uYSh4KSkpCmBgYAoKIyA0LiBGdW5kYW1lbnRhw6fDo28gVGXDs3JpY2EKCiMjIyA0LjEgRm9ybXVsYcOnw6NvIGRhcyBIaXDDs3Rlc2VzCgpQYXJhIGFtYm9zIG9zIHRlc3RlcyBkZSBub3JtYWxpZGFkZSwgYXMgaGlww7N0ZXNlcyBzw6NvIGZvcm11bGFkYXMgZGEgbWVzbWEgbWFuZWlyYToKCi0gKipIMDoqKiBhIHZhcmnDoXZlbCBzZWd1ZSBkaXN0cmlidWnDp8OjbyBOb3JtYWw7Ci0gKipIMToqKiBhIHZhcmnDoXZlbCAqKm7Do28qKiBzZWd1ZSBkaXN0cmlidWnDp8OjbyBOb3JtYWwuCgpPIHRlc3RlIMOpLCBwb3IgbmF0dXJlemEsICoqYmlsYXRlcmFsKiogKGRlIGFkZXLDqm5jaWEpOiBxdWFscXVlciBkZXN2aW8gcmVsZXZhbnRlIGRhIGZvcm1hIG5vcm1hbCDigJQgcGFyYSBhIGVzcXVlcmRhLCBwYXJhIGEgZGlyZWl0YSwgYWNoYXRhbWVudG8gb3UgYWZpbGFtZW50byDigJQgbGV2YSDDoCByZWplacOnw6NvIGRlIEgwLiBOw6NvIGV4aXN0ZW0gdmVyc8O1ZXMgdW5pbGF0ZXJhaXMgcGFyYSBlc3RlIHRpcG8gZGUgdGVzdGUuCgojIyMgNC4yIFByZXNzdXBvc3RvcwoKLSBWYXJpw6F2ZWwgKipxdWFudGl0YXRpdmEgY29udMOtbnVhKio7Ci0gQW1vc3RyYSAqKmFsZWF0w7NyaWEgZSBjb21wb3N0YSBwb3Igb2JzZXJ2YcOnw7VlcyBpbmRlcGVuZGVudGVzKio7Ci0gQXVzw6puY2lhIGRlIHZhbG9yZXMgYXVzZW50ZXMgKHRyYXRhZG9zIGFudGVzIGRhIGFwbGljYcOnw6NvIGRvIHRlc3RlKS4KCiMjIyA0LjMgRXN0YXTDrXN0aWNhIGRlIFRlc3RlIOKAlCBTaGFwaXJvLVdpbGsKClcgPSAoIM6jIGHhtaIgwrcgeOKCjeG1ouKCjiApwrIgLyDOoyAoeOG1oiDiiJIgeMyEKcKyCgpvbmRlIHjigo3htaLigo4gc8OjbyBhcyBvYnNlcnZhw6fDtWVzIG9yZGVuYWRhcyBlIGHhtaIgc8OjbyBjb2VmaWNpZW50ZXMgdGFiZWxhZG9zIChTaGFwaXJvICYgV2lsaywgMTk2NSksIGRlcml2YWRvcyBkb3MgdmFsb3JlcyBlc3BlcmFkb3MgZSBkYSBtYXRyaXogZGUgY292YXJpw6JuY2lhIGRhcyBlc3RhdMOtc3RpY2FzIGRlIG9yZGVtIGRlIHVtYSBOb3JtYWwgcGFkcsOjby4gVyB2YXJpYSBubyBpbnRlcnZhbG8gKDAsIDFdOiBxdWFudG8gbWFpcyBwcsOzeGltbyBkZSAxLCBtYWlzIGEgYW1vc3RyYSBzZSBhc3NlbWVsaGEgYSB1bWEgTm9ybWFsLiBOw6NvIHBvc3N1aSBncmF1cyBkZSBsaWJlcmRhZGUgbm8gc2VudGlkbyBjbMOhc3NpY287IHN1YSBkaXN0cmlidWnDp8OjbyBhbW9zdHJhbCDDqSBvYnRpZGEgcG9yIHNpbXVsYcOnw6NvL3RhYmVsYS4KCiMjIyA0LjQgRXN0YXTDrXN0aWNhIGRlIFRlc3RlIOKAlCBLb2xtb2dvcm92LVNtaXJub3YgKHVtYSBhbW9zdHJhKQoKRCA9IHN1cCB8RuKCmSh4KSDiiJIgRuKCgCh4KXwKCm9uZGUgRuKCmSh4KSDDqSBhIGZ1bsOnw6NvIGRlIGRpc3RyaWJ1acOnw6NvIGVtcMOtcmljYSBkYSBhbW9zdHJhIGUgRuKCgCh4KSDDqSBhIGZ1bsOnw6NvIGRlIGRpc3RyaWJ1acOnw6NvIGFjdW11bGFkYSB0ZcOzcmljYSBkYSBOb3JtYWwuIEQgw6kgYSBtYWlvciBkaXN0w6JuY2lhIHZlcnRpY2FsIGVudHJlIGFzIGR1YXMgY3VydmFzLiBPIHRlc3RlIGNsw6Fzc2ljbyBkZSBLUyBleGlnZSBxdWUgRuKCgCBzZWphICoqdG90YWxtZW50ZSBlc3BlY2lmaWNhZGEqKjsgcG9yIGlzc28gb3MgZGFkb3Mgc8OjbyBwYWRyb25pemFkb3MgKCp6LXNjb3JlKikgYW50ZXMgZG8gdGVzdGUg4oCUIHJlc3NhbHZhbmRvIHF1ZSBhIGZvcm1hIHJpZ29yb3NhbWVudGUgY29ycmV0YSBwYXJhIHBhcsOibWV0cm9zIGVzdGltYWRvcyBkYSBhbW9zdHJhIMOpIG8gdGVzdGUgZGUgKipMaWxsaWVmb3JzKiouCgojIyMgNC41IFJlZ3JhIGRlIERlY2lzw6NvCgotICoqTcOpdG9kbyBkbyBwLXZhbG9yOioqIHJlamVpdGEtc2UgSDAgc2UgcCDiiaQgzrEgKG5lc3RlIHJlbGF0w7NyaW8sIM6xID0gMCwwNSk7Ci0gKipNw6l0b2RvIGRvIHZhbG9yIGNyw610aWNvOioqIHJlamVpdGEtc2UgSDAgc2UgYSBlc3RhdMOtc3RpY2EgZG8gdGVzdGUgKFcgb3UgRCkgZm9yIG1lbm9yIChXKSBvdSBtYWlvciAoRCkgcXVlIG8gdmFsb3IgY3LDrXRpY28gdGFiZWxhZG8gcGFyYSBuIGUgzrEuCgpPcyBkb2lzIG3DqXRvZG9zIHPDo28gZXF1aXZhbGVudGVzLiBPIG3DqXRvZG8gZG8gdmFsb3IgY3LDrXRpY28gc2Vyw6EgZGVtb25zdHJhZG8gbm8gZXhlbXBsbyBtYW51YWwgKFNlw6fDo28gNik7IG8gbcOpdG9kbyBkbyBwLXZhbG9yLCBuYSBhcGxpY2HDp8OjbyBjb21wdXRhY2lvbmFsIChTZcOnw6NvIDgpLgoKIyA1LiBNZXRvZG9sb2dpYQoKMS4gSW1wb3J0YcOnw6NvIGRhIGJhc2UgYGFpcnF1YWxpdHlgIChuYXRpdmEgZG8gUik7CjIuIFRyYXRhbWVudG8gZGUgdmFsb3JlcyBhdXNlbnRlcyBwb3IgdmFyacOhdmVsIChgbmEub21pdGApOwozLiBBbsOhbGlzZSBleHBsb3JhdMOzcmlhIChlc3RhdMOtc3RpY2FzIGRlc2NyaXRpdmFzLCBoaXN0b2dyYW1hLCBib3hwbG90KTsKNC4gVmVyaWZpY2HDp8OjbyBkb3MgcHJlc3N1cG9zdG9zOwo1LiBSZXNvbHXDp8OjbyBtYW51YWwgZG8gU2hhcGlyby1XaWxrIHBhcmEgdW1hIHN1YmFtb3N0cmEgZGUgbj01Owo2LiBBcGxpY2HDp8OjbyBjb21wdXRhY2lvbmFsIGRvcyB0ZXN0ZXMgZGUgU2hhcGlyby1XaWxrIGUgS29sbW9nb3Jvdi1TbWlybm92IChjb20gcGFkcm9uaXphw6fDo28pIHNvYnJlIGFzIHPDqXJpZXMgY29tcGxldGFzLCBhIM6xID0gMCwwNTsKNy4gQ29uc3RydcOnw6NvIGRlIHBhaW5lbCBncsOhZmljbyAoaGlzdG9ncmFtYSwgYm94cGxvdCwgUVEtUGxvdCk7CjguIENvbXBhcmHDp8OjbyBjb20gdGVzdGVzIGFsdGVybmF0aXZvcyAocXVhbmRvIGRpc3BvbsOtdmVpcyBubyBhbWJpZW50ZSk7CjkuIEludGVycHJldGHDp8OjbyBkbyBwLXZhbG9yLCBkaXNjdXNzw6NvIGUgY29uY2x1c8Ojby4KCk8gcHJvY2VkaW1lbnRvIGZvaSBpbXBsZW1lbnRhZG8gdGFtYsOpbSBlbSAqKlB5dGhvbioqIChgbm9ybWFsaWRhZGUucHlgLCB1c2FuZG8gYHNjaXB5LnN0YXRzYCksIGNvbmZpcm1hbmRvIGEgZXF1aXZhbMOqbmNpYSBkb3MgcmVzdWx0YWRvcyBlbnRyZSBhcyBkdWFzIGxpbmd1YWdlbnMuCgojIDYuIEFuw6FsaXNlIEV4cGxvcmF0w7NyaWEgZG9zIERhZG9zCgpgYGB7ciBleHBsb3JhdG9yaWF9CndpbmQgIDwtIG5hLm9taXQoYWlycXVhbGl0eSRXaW5kKQpvem9uZSA8LSBuYS5vbWl0KGFpcnF1YWxpdHkkT3pvbmUpCgpza2V3bmVzcyA8LSBmdW5jdGlvbih4KSB7CiAgbiA8LSBsZW5ndGgoeCk7IG0gPC0gbWVhbih4KTsgcyA8LSBzcXJ0KHN1bSgoeCAtIG0pXjIpIC8gbikKICBzdW0oKCh4IC0gbSkgLyBzKV4zKSAvIG4KfQprdXJ0b3Npc19leGMgPC0gZnVuY3Rpb24oeCkgewogIG4gPC0gbGVuZ3RoKHgpOyBtIDwtIG1lYW4oeCk7IHMgPC0gc3FydChzdW0oKHggLSBtKV4yKSAvIG4pCiAgc3VtKCgoeCAtIG0pIC8gcyleNCkgLyBuIC0gMwp9CgpyZXN1bW8gPC0gZGF0YS5mcmFtZSgKICBFc3RhdGlzdGljYSA9IGMoIm4iLCAiTcOpZGlhIiwgIk1lZGlhbmEiLCAiRGVzdmlvLXBhZHLDo28iLAogICAgICAgICAgICAgICAgICAiQXNzaW1ldHJpYSIsICJDdXJ0b3NlIChleGNlc3NvKSIsICJNw61uaW1vIiwgIk3DoXhpbW8iKSwKICBXaW5kICA9IGMobGVuZ3RoKHdpbmQpLCAgbWVhbih3aW5kKSwgIG1lZGlhbih3aW5kKSwgIHNkKHdpbmQpLAogICAgICAgICAgICBza2V3bmVzcyh3aW5kKSwgIGt1cnRvc2lzX2V4Yyh3aW5kKSwgIG1pbih3aW5kKSwgIG1heCh3aW5kKSksCiAgT3pvbmUgPSBjKGxlbmd0aChvem9uZSksIG1lYW4ob3pvbmUpLCBtZWRpYW4ob3pvbmUpLCBzZChvem9uZSksCiAgICAgICAgICAgIHNrZXduZXNzKG96b25lKSwga3VydG9zaXNfZXhjKG96b25lKSwgbWluKG96b25lKSwgbWF4KG96b25lKSkKKQprbml0cjo6a2FibGUocmVzdW1vLCBkaWdpdHMgPSA0KQpgYGAKCioqTGVpdHVyYSBpbmljaWFsOioqIGBXaW5kYCBhcHJlc2VudGEgYXNzaW1ldHJpYSBwcsOzeGltYSBkZSB6ZXJvLCBzdWdlcmluZG8gZm9ybWEgYXByb3hpbWFkYW1lbnRlIHNpbcOpdHJpY2EuIGBPem9uZWAgYXByZXNlbnRhIGFzc2ltZXRyaWEgcG9zaXRpdmEgYWNlbnR1YWRhIChjYXVkYSBsb25nYSDDoCBkaXJlaXRhKSDigJQgc2luYWwgY2FyYWN0ZXLDrXN0aWNvIGRlICoqbsOjby1ub3JtYWxpZGFkZSoqLgoKYGBge3IgaGlzdC1ib3gsIGZpZy53aWR0aD05LCBmaWcuaGVpZ2h0PTR9CnBhcihtZnJvdyA9IGMoMSwgMikpCmhpc3Qod2luZCwgbWFpbiA9ICJIaXN0b2dyYW1hIOKAlCBXaW5kIiwgeGxhYiA9ICJtcGgiLCBjb2wgPSAic3RlZWxibHVlIiwgYnJlYWtzID0gMTIpCmhpc3Qob3pvbmUsIG1haW4gPSAiSGlzdG9ncmFtYSDigJQgT3pvbmUiLCB4bGFiID0gInBwYiIsIGNvbCA9ICJ0b21hdG8iLCBicmVha3MgPSAxMikKYGBgCgpgYGB7ciBib3hwbG90cywgZmlnLndpZHRoPTYsIGZpZy5oZWlnaHQ9NH0KcGFyKG1mcm93ID0gYygxLCAyKSkKYm94cGxvdCh3aW5kLCBtYWluID0gIkJveHBsb3Qg4oCUIFdpbmQiLCB5bGFiID0gIm1waCIpCmJveHBsb3Qob3pvbmUsIG1haW4gPSAiQm94cGxvdCDigJQgT3pvbmUiLCB5bGFiID0gInBwYiIpCmBgYAoKTyBib3hwbG90IGRlIGBXaW5kYCDDqSByYXpvYXZlbG1lbnRlIHNpbcOpdHJpY28sIGNvbSBwb3Vjb3Mgb3V0bGllcnMuIE8gZGUgYE96b25lYCBtb3N0cmEgbWVkaWFuYSBkZXNsb2NhZGEgcGFyYSBhIHBhcnRlIGluZmVyaW9yIGRhIGNhaXhhIGUgZGl2ZXJzb3Mgb3V0bGllcnMgc3VwZXJpb3Jlcy4KCiMgNy4gVmVyaWZpY2HDp8OjbyBkb3MgUHJlc3N1cG9zdG9zCgp8IFByZXNzdXBvc3RvIHwgYFdpbmRgIHwgYE96b25lYCB8CnwtLS18LS0tfC0tLXwKfCBWYXJpw6F2ZWwgcXVhbnRpdGF0aXZhIGNvbnTDrW51YSB8IEF0ZW5kaWRvIHwgQXRlbmRpZG8gfAp8IE9ic2VydmHDp8O1ZXMgaW5kZXBlbmRlbnRlcyB8IEF0ZW5kaWRvIChwb3IgY29uc3RydcOnw6NvIGRvIGVzdHVkbykgfCBBdGVuZGlkbyAocG9yIGNvbnN0cnXDp8OjbyBkbyBlc3R1ZG8pIHwKfCBWYWxvcmVzIGF1c2VudGVzIHwgTmVuaHVtIHwgMzcgdmFsb3JlcyBhdXNlbnRlcyDigJQgcmVtb3ZpZG9zIHZpYSBgbmEub21pdCgpYCB8CnwgVGFtYW5obyBkZSBhbW9zdHJhIGFww7NzIHRyYXRhbWVudG8gfCBuID0gMTUzIHwgbiA9IDExNiB8CgoqKk9ic2VydmHDp8OjbyBtZXRvZG9sw7NnaWNhOioqIHBvciBzZSB0cmF0YXIgZGUgc8OpcmllIHRlbXBvcmFsIGRpw6FyaWEsIGV4aXN0ZSBlbSBwcmluY8OtcGlvIGEgcG9zc2liaWxpZGFkZSBkZSBhdXRvY29ycmVsYcOnw6NvIGVudHJlIG9ic2VydmHDp8O1ZXMgY29uc2VjdXRpdmFzLiBQYXJhIG9zIGZpbnMgZGlkw6F0aWNvcyBkZXN0ZSBzZW1pbsOhcmlvLCB0cmF0YW1vcyBhcyBvYnNlcnZhw6fDtWVzIGNvbW8gaW5kZXBlbmRlbnRlcywgY29tbyDDqSBwcsOhdGljYSBjb211bSBhbyB0ZXN0YXIgYSBmb3JtYSBtYXJnaW5hbCBkYSBkaXN0cmlidWnDp8Ojby4KCiMgOC4gRXhlbXBsbyBSZXNvbHZpZG8gTWFudWFsbWVudGUg4oCUIFNoYXBpcm8tV2lsayAobiA9IDUpCgpVc2Ftb3MgYXMgKio1IHByaW1laXJhcyBvYnNlcnZhw6fDtWVzIHJlYWlzKiogZGUgYFdpbmRgIChkaWFzIDEgYSA1IGRlIG1haW8gZGUgMTk3MyksIGNvbSBvcyBjb2VmaWNpZW50ZXMgdGFiZWxhZG9zIChTaGFwaXJvICYgV2lsaywgMTk2NSkgcGFyYSBuPTU6IGE1ID0gMCw2NjQ2OyBhNCA9IDAsMjQxMzsgYTMgPSAwLgoKYGBge3IgbWFudWFsLXN3fQp4NSA8LSBoZWFkKHdpbmQsIDUpCmNhdCgiQW1vc3RyYSAoV2luZCwgZGlhcyAxLTUvbWFpby8xOTczKToiLCB4NSwgIlxuIikKCnhfb3JkIDwtIHNvcnQoeDUpCmNhdCgiQW1vc3RyYSBvcmRlbmFkYToiLCB4X29yZCwgIlxuIikKCm1lZGlhIDwtIG1lYW4oeF9vcmQpClNTIDwtIHN1bSgoeF9vcmQgLSBtZWRpYSleMikKCmE1IDwtIDAuNjY0NjsgYTQgPC0gMC4yNDEzCgpiIDwtIGE1ICogKHhfb3JkWzVdIC0geF9vcmRbMV0pICsgYTQgKiAoeF9vcmRbNF0gLSB4X29yZFsyXSkKV19tYW51YWwgPC0gYl4yIC8gU1MKCmNhdChzcHJpbnRmKCJcbk3DqWRpYSAoeMyEKSAgICAgICAgICAgICAgID0gJS40ZlxuIiwgbWVkaWEpKQpjYXQoc3ByaW50ZigiU29tYSBkZSBxdWFkcmFkb3MgKFNTKSAgID0gJS40ZlxuIiwgU1MpKQpjYXQoc3ByaW50ZigiYiA9IGE1Kih4NS14MSkrYTQqKHg0LXgyKSA9ICUuNGZcbiIsIGIpKQpjYXQoc3ByaW50ZigiVyBjYWxjdWxhZG8gbWFudWFsbWVudGUgID0gJS40ZlxuIiwgV19tYW51YWwpKQpgYGAKCmBgYHtyIG1hbnVhbC1zdy1kZWNpc2FvfQpXX2NyaXQgPC0gMC43NjIgICMgdmFsb3IgdGFiZWxhZG8gcGFyYSBuPTUsIGFscGhhPTAuMDUKZGVjaXNhb19tYW51YWwgPC0gaWYgKFdfbWFudWFsID4gV19jcml0KSAiTsODTyBzZSByZWplaXRhIEgwIiBlbHNlICJSZWplaXRhLXNlIEgwIgpjYXQoc3ByaW50ZigiVyBjYWxjdWxhZG8gPSAlLjRmIHwgVyBjcsOtdGljbyAobj01LCBhbHBoYT0wLjA1KSA9ICUuM2ZcbiIsIFdfbWFudWFsLCBXX2NyaXQpKQpjYXQoIlJlZ3JhOiByZWplaXRhLXNlIEgwIHNlIFcgPCBXX2NyaXQgIC0+ICBEZWNpc8OjbzoiLCBkZWNpc2FvX21hbnVhbCwgIlxuIikKCnRlc3RlX2NvbmZlcmVuY2lhIDwtIHNoYXBpcm8udGVzdCh4NSkKY2F0KHNwcmludGYoIlxuQ29uZmVyw6puY2lhIChzaGFwaXJvLnRlc3QpOiBXID0gJS40ZiB8IHAtdmFsb3IgPSAlLjRmXG4iLAogICAgICAgICAgICB0ZXN0ZV9jb25mZXJlbmNpYSRzdGF0aXN0aWMsIHRlc3RlX2NvbmZlcmVuY2lhJHAudmFsdWUpKQpgYGAKCioqSW50ZXJwcmV0YcOnw6NvOioqIG8gdmFsb3IgZGUgVyBjYWxjdWxhZG8gbWFudWFsbWVudGUgY29pbmNpZGUgY29tIG8gZGUgYHNoYXBpcm8udGVzdCgpYC4gQ29tbyBXIGVzdMOhICoqYWNpbWEqKiBkbyB2YWxvciBjcsOtdGljbyB0YWJlbGFkbyAoMCw3NjIpIHBhcmEgbj01IGUgzrE9MCwwNSwgKipuw6NvIHJlamVpdGFtb3MgSDAqKiDigJQgY29lcmVudGUgY29tIG8gcmVzdWx0YWRvIGRhIGFtb3N0cmEgY29tcGxldGEgZGUgYFdpbmRgIChuPTE1MyksIG5hIHByw7N4aW1hIHNlw6fDo28uCgojIDkuIEFwbGljYcOnw6NvIGRvIFRlc3RlIChTb2Z0d2FyZSBFc3RhdMOtc3RpY28pCgpBcGxpY2Ftb3Mgb3MgdGVzdGVzIGRlICoqU2hhcGlyby1XaWxrKiogZSAqKktvbG1vZ29yb3YtU21pcm5vdioqIMOgcyBzw6lyaWVzIGNvbXBsZXRhcy4gUGFyYSBvIEtTLCBwYWRyb25pemFtb3Mgb3MgZGFkb3MgKCp6LXNjb3JlKikgYW50ZXMgZGUgY29tcGFyYXIgY29tIGEgTm9ybWFsIHBhZHLDo28gTigwLDEpLgoKYGBge3IgYXBsaWNhY2FvfQphbHBoYSA8LSAwLjA1Cgp0ZXN0YXJfbm9ybWFsaWRhZGUgPC0gZnVuY3Rpb24oc2VyaWUsIG5vbWUpIHsKICBzZXJpZV96IDwtIHNjYWxlKHNlcmllKVssIDFdCiAgc3cgPC0gc2hhcGlyby50ZXN0KHNlcmllKQogIGtzIDwtIGtzLnRlc3Qoc2VyaWVfeiwgInBub3JtIikKICBkYXRhLmZyYW1lKAogICAgVmFyaWF2ZWwgPSBub21lLAogICAgbiA9IGxlbmd0aChzZXJpZSksCiAgICBgU2hhcGlyb19XYCA9IHN3JHN0YXRpc3RpYywKICAgIGBwX3ZhbG9yX1NXYCA9IHN3JHAudmFsdWUsCiAgICBgS1NfRGAgPSBrcyRzdGF0aXN0aWMsCiAgICBgcF92YWxvcl9LU2AgPSBrcyRwLnZhbHVlLAogICAgYERlY2lzYW9fU1dgID0gaWYgKHN3JHAudmFsdWUgPiBhbHBoYSkgIk7Do28gcmVqZWl0YSBIMCIgZWxzZSAiUmVqZWl0YSBIMCIsCiAgICBgRGVjaXNhb19LU2AgPSBpZiAoa3MkcC52YWx1ZSA+IGFscGhhKSAiTsOjbyByZWplaXRhIEgwIiBlbHNlICJSZWplaXRhIEgwIgogICkKfQoKcmVzdWx0YWRvcyA8LSByYmluZCgKICB0ZXN0YXJfbm9ybWFsaWRhZGUod2luZCwgIldpbmQiKSwKICB0ZXN0YXJfbm9ybWFsaWRhZGUob3pvbmUsICJPem9uZSIpCikKcm93bmFtZXMocmVzdWx0YWRvcykgPC0gTlVMTAprbml0cjo6a2FibGUocmVzdWx0YWRvcywgZGlnaXRzID0gNCkKYGBgCgpFbSBQeXRob24sIG8gcHJvY2VkaW1lbnRvIGVxdWl2YWxlbnRlIGVzdMOhIGVtIGBub3JtYWxpZGFkZS5weWAgKHNjcmlwdCBjb21wbGV0byk6CgpgYGBweXRob24Kc3dfc3RhdCwgc3dfcCA9IHN0YXRzLnNoYXBpcm8oc2VyaWUpCmtzX3N0YXQsIGtzX3AgPSBzdGF0cy5rc3Rlc3Qoc3RhdHMuenNjb3JlKHNlcmllKSwgIm5vcm0iKQpgYGAKCiMgMTAuIFJlc3VsdGFkb3MKCiMjIyAxMC4xIE3DqXRvZG8gZG8gcC12YWxvcgoKLSAqKldpbmQ6KiogcChTVykgPiAwLDA1IGUgcChLUykgPiAwLDA1ICDihpIgICoqbsOjbyBzZSByZWplaXRhIEgwKiog4oCUIGNvbXBhdMOtdmVsIGNvbSBOb3JtYWwuCi0gKipPem9uZToqKiBwKFNXKSDiiaQgMCwwNSBlIHAoS1MpIOKJpCAwLDA1ICDihpIgICoqcmVqZWl0YS1zZSBIMCoqIOKAlCBuw6NvIGNvbXBhdMOtdmVsIGNvbSBOb3JtYWwuCgojIyMgMTAuMiBNw6l0b2RvIGRvIHZhbG9yIGNyw610aWNvIChpbHVzdHJhw6fDo28pCgpQYXJhIGFtb3N0cmFzIGdyYW5kZXMgKG49MTUzIGUgbj0xMTYpLCBvIG3DqXRvZG8gZG8gcC12YWxvciDDqSBvIG1haXMgcHLDoXRpY287IG8gbcOpdG9kbyBkbyB2YWxvciBjcsOtdGljbyBmb2kgZGVtb25zdHJhZG8gbmEgU2XDp8OjbyA4IHBhcmEgbj01LiBPcyBkb2lzIG3DqXRvZG9zIHPDo28gZXF1aXZhbGVudGVzIGUgbGV2YW0gw6AgbWVzbWEgZGVjaXPDo28uCgojIDExLiBWaXN1YWxpemHDp8O1ZXMgR3LDoWZpY2FzCgpgYGB7ciBwYWluZWwtd2luZCwgZmlnLndpZHRoPTEzLCBmaWcuaGVpZ2h0PTR9CnBhcihtZnJvdyA9IGMoMSwgMykpCmhpc3Qod2luZCwgbWFpbiA9ICJIaXN0b2dyYW1hIOKAlCBXaW5kIiwgeGxhYiA9ICJtcGgiLCBjb2wgPSAic3RlZWxibHVlIiwgYnJlYWtzID0gMTIpCmJveHBsb3Qod2luZCwgbWFpbiA9ICJCb3hwbG90IOKAlCBXaW5kIiwgeWxhYiA9ICJtcGgiKQpxcW5vcm0od2luZCwgbWFpbiA9ICJRUS1QbG90IOKAlCBXaW5kIikKcXFsaW5lKHdpbmQsIGNvbCA9ICJyZWQiLCBsd2QgPSAyKQpgYGAKCmBgYHtyIHBhaW5lbC1vem9uZSwgZmlnLndpZHRoPTEzLCBmaWcuaGVpZ2h0PTR9CnBhcihtZnJvdyA9IGMoMSwgMykpCmhpc3Qob3pvbmUsIG1haW4gPSAiSGlzdG9ncmFtYSDigJQgT3pvbmUiLCB4bGFiID0gInBwYiIsIGNvbCA9ICJ0b21hdG8iLCBicmVha3MgPSAxMikKYm94cGxvdChvem9uZSwgbWFpbiA9ICJCb3hwbG90IOKAlCBPem9uZSIsIHlsYWIgPSAicHBiIikKcXFub3JtKG96b25lLCBtYWluID0gIlFRLVBsb3Qg4oCUIE96b25lIikKcXFsaW5lKG96b25lLCBjb2wgPSAicmVkIiwgbHdkID0gMikKYGBgCgoqKkxlaXR1cmEgZG9zIFFRLVBsb3RzOioqIGVtIGBXaW5kYCwgb3MgcG9udG9zIHNlZ3VlbSBkZSBwZXJ0byBhIHJldGEgZGUgcmVmZXLDqm5jaWEuIEVtIGBPem9uZWAsIG9zIHBvbnRvcyBzZSBhZmFzdGFtIHNpc3RlbWF0aWNhbWVudGUgZGEgcmV0YSBuYXMgZXh0cmVtaWRhZGVzLCByZXZlbGFuZG8gdmlzdWFsbWVudGUgYSBhc3NpbWV0cmlhIHF1YW50aWZpY2FkYSBwZWxvcyB0ZXN0ZXMgZm9ybWFpcy4KCiMgMTIuIERpc2N1c3PDo28KCi0gT3MgZG9pcyB0ZXN0ZXMgKipjb25jb3JkYW0qKiBuYSBkZWNpc8OjbyBmaW5hbCBwYXJhIGFtYmFzIGFzIHZhcmnDoXZlaXMsIG1hcyAqKmRpc2NvcmRhbSBuYSBtYWduaXR1ZGUgZGEgZXZpZMOqbmNpYSoqOiBwYXJhIGBPem9uZWAsIG8gU2hhcGlyby1XaWxrIHByb2R1eiB1bSBwLXZhbG9yIGV4dHJlbWFtZW50ZSBwZXF1ZW5vIChvcmRlbSBkZSAxMOKBu+KBuCksIG11aXRvIG1haXMgZXh0cmVtbyBkbyBxdWUgbyBkbyBLb2xtb2dvcm92LVNtaXJub3Yg4oCUIG8gU2hhcGlyby1XaWxrIMOpLCBlbSBnZXJhbCwgbWFpcyBzZW5zw612ZWwgYSBkZXN2aW9zIGRlIG5vcm1hbGlkYWRlLgotIE8gS1MsIGFvIGRlcGVuZGVyIGRhIG1haW9yIGRpc3TDom5jaWEgZW50cmUgY3VydmFzIGFjdW11bGFkYXMsIHRlbmRlIGEgc2VyIG1lbm9zIHNlbnPDrXZlbCBhIGRlc3Zpb3MgbG9jYWxpemFkb3MgKGNhdWRhcyBwZXNhZGFzLCBwb3Vjb3Mgb3V0bGllcnMpLgotIEEgaW5zcGXDp8OjbyBncsOhZmljYSBjb25maXJtb3UgYSBjb25jbHVzw6NvIGRvcyB0ZXN0ZXMgZm9ybWFpcyBlbSBhbWJvcyBvcyBjYXNvcywgcmVmb3LDp2FuZG8gYSByZWNvbWVuZGHDp8OjbyBkZSBzZW1wcmUgY3J1emFyIHRlc3RlIGZvcm1hbCBjb20gZ3LDoWZpY28uCgojIDEzLiBWYW50YWdlbnMgZSBMaW1pdGHDp8O1ZXMgZG9zIFRlc3RlcwoKfCBUZXN0ZSB8IFZhbnRhZ2VucyB8IExpbWl0YcOnw7VlcyB8CnwtLS18LS0tfC0tLXwKfCAqKlNoYXBpcm8tV2lsayoqIHwgTWFpb3IgcG9kZXIgZXN0YXTDrXN0aWNvIGVudHJlIG9zIHRlc3RlcyBjbMOhc3NpY29zLCBlc3BlY2lhbG1lbnRlIHBhcmEgbiBwZXF1ZW5vL23DqWRpbyB8IFNlbnPDrXZlbCBhIG91dGxpZXJzOyBlbSBhbW9zdHJhcyBtdWl0byBncmFuZGVzLCByZWplaXRhIEgwIG1lc21vIHBhcmEgZGVzdmlvcyBzZW0gcmVsZXbDom5jaWEgcHLDoXRpY2EgfAp8ICoqS29sbW9nb3Jvdi1TbWlybm92KiogfCBDb25jZWl0byBnZXJhbCwgYXBsaWPDoXZlbCBhIHF1YWxxdWVyIGRpc3RyaWJ1acOnw6NvIHRlw7NyaWNhIHwgTWVub3Mgc2Vuc8OtdmVsIHF1ZSBvIFNoYXBpcm8tV2lsazsgZXhpZ2UgZGlzdHJpYnVpw6fDo28gdG90YWxtZW50ZSBlc3BlY2lmaWNhZGEgKG1vdGl2b3UgYSBjb3JyZcOnw6NvIGRlIExpbGxpZWZvcnMpIHwKCiMgMTQuIENvbXBhcmHDp8OjbyBjb20gT3V0cm9zIFRlc3RlcyBTZW1lbGhhbnRlcwoKQWzDqW0gZGUgU2hhcGlyby1XaWxrIGUgS29sbW9nb3Jvdi1TbWlybm92LCBhIGxpdGVyYXR1cmEgYXByZXNlbnRhIG91dHJhcyBhbHRlcm5hdGl2YXM6CgotICoqTGlsbGllZm9yczoqKiBjb3JyZcOnw6NvIGRvIEtTIHBhcmEgcXVhbmRvIG3DqWRpYSBlIGRlc3Zpby1wYWRyw6NvIHPDo28gZXN0aW1hZG9zIGRhIHByw7NwcmlhIGFtb3N0cmE7Ci0gKipBbmRlcnNvbi1EYXJsaW5nOioqIGTDoSBtYWlzIHBlc28gw6BzIGNhdWRhcyBkYSBkaXN0cmlidWnDp8OjbywgbWFpcyBzZW5zw612ZWwgYSBvdXRsaWVycyBleHRyZW1vczsKLSAqKkphcnF1ZS1CZXJhIC8gRCdBZ29zdGluby1QZWFyc29uOioqIGJhc2VhZG9zIGVtIGFzc2ltZXRyaWEgZSBjdXJ0b3NlIGFtb3N0cmFpcywgY29tdW5zIGVtIHPDqXJpZXMgZWNvbsO0bWljYXMvZmluYW5jZWlyYXMuCgpgYGB7ciBhbmRlcnNvbi1kYXJsaW5nfQppZiAocmVxdWlyZU5hbWVzcGFjZSgibm9ydGVzdCIsIHF1aWV0bHkgPSBUUlVFKSkgewogIGxpYnJhcnkobm9ydGVzdCkKICBhZF93aW5kICA8LSBhZC50ZXN0KHdpbmQpCiAgYWRfb3pvbmUgPC0gYWQudGVzdChvem9uZSkKICBrbml0cjo6a2FibGUoZGF0YS5mcmFtZSgKICAgIFZhcmlhdmVsID0gYygiV2luZCIsICJPem9uZSIpLAogICAgRXN0YXRpc3RpY2FfQTIgPSBjKGFkX3dpbmQkc3RhdGlzdGljLCBhZF9vem9uZSRzdGF0aXN0aWMpLAogICAgcF92YWxvciA9IGMoYWRfd2luZCRwLnZhbHVlLCBhZF9vem9uZSRwLnZhbHVlKQogICksIGRpZ2l0cyA9IDQpCn0gZWxzZSB7CiAgY2F0KCJQYWNvdGUgJ25vcnRlc3QnIG7Do28gaW5zdGFsYWRvIG5lc3RlIGFtYmllbnRlLiIsCiAgICAgICJQYXJhIHJlcHJvZHV6aXIgYSBjb21wYXJhw6fDo28gY29tIEFuZGVyc29uLURhcmxpbmcsIGV4ZWN1dGU6IiwKICAgICAgImluc3RhbGwucGFja2FnZXMoJ25vcnRlc3QnKSIsIHNlcCA9ICJcbiIpCn0KYGBgCgojIDE1LiBFeGVyY8OtY2lvIEFwbGljYWRvIHBhcmEgRGlzY3Vzc8OjbyBjb20gYSBUdXJtYQoKKipQcm9wb3N0YToqKiB1dGlsaXphbmRvIGEgbWVzbWEgYmFzZSBgYWlycXVhbGl0eWAsIHRlc3RlIGEgbm9ybWFsaWRhZGUgZGEgdmFyacOhdmVsIGBUZW1wYCAodGVtcGVyYXR1cmEgbcOheGltYSBkacOhcmlhKS4KCjEuIFRyYXRlIGV2ZW50dWFpcyB2YWxvcmVzIGF1c2VudGVzOwoyLiBDb25zdHJ1YSBvIGhpc3RvZ3JhbWEsIG8gYm94cGxvdCBlIG8gUVEtUGxvdCBkZSBgVGVtcGA7CjMuIEFwbGlxdWUgb3MgdGVzdGVzIGRlIFNoYXBpcm8tV2lsayBlIEtvbG1vZ29yb3YtU21pcm5vdiBhIM6xID0gMCwwNTsKNC4gQ29tcGFyZSBhIGRlY2lzw6NvIG9idGlkYSBwZWxvcyBkb2lzIHRlc3RlczsKNS4gRGlzY3V0YTogYSBjb25jbHVzw6NvIGRvIHRlc3RlIGZvcm1hbCDDqSBjb2VyZW50ZSBjb20gbyBxdWUgc2Ugb2JzZXJ2YSBub3MgZ3LDoWZpY29zPwoKYGBge3IgZXhlcmNpY2lvfQp0ZW1wIDwtIG5hLm9taXQoYWlycXVhbGl0eSRUZW1wKQp0ZXN0YXJfbm9ybWFsaWRhZGUodGVtcCwgIlRlbXAiKQpgYGAKCiMgMTYuIENvbmNsdXPDo28KCkNvbSBiYXNlIG5vcyB0ZXN0ZXMgZGUgKipTaGFwaXJvLVdpbGsqKiBlICoqS29sbW9nb3Jvdi1TbWlybm92KiosIGNvbXBsZW1lbnRhZG9zIHBlbGEgaW5zcGXDp8OjbyBncsOhZmljYSwgY29uY2x1w61tb3MgcXVlOgoKLSBBIHZhcmnDoXZlbCAqKmBXaW5kYCoqIMOpIGVzdGF0aXN0aWNhbWVudGUgKipjb21wYXTDrXZlbCBjb20gYSBkaXN0cmlidWnDp8OjbyBOb3JtYWwqKiAocCA+IDAsMDUgZW0gYW1ib3Mgb3MgdGVzdGVzKSwgdGFudG8gbmEgYW1vc3RyYSBjb21wbGV0YSAobj0xNTMpIHF1YW50byBubyBleGVtcGxvIG1hbnVhbCAobj01KTsKLSBBIHZhcmnDoXZlbCAqKmBPem9uZWAqKiAqKm7Do28gw6kgY29tcGF0w612ZWwqKiBjb20gYSBkaXN0cmlidWnDp8OjbyBOb3JtYWwgKHAg4omkIDAsMDUgZW0gYW1ib3Mgb3MgdGVzdGVzKSwgY29tIGV2aWTDqm5jaWEgZm9ydMOtc3NpbWEgbm8gU2hhcGlyby1XaWxrOwotIE9zIHJlc3VsdGFkb3Mgb2J0aWRvcyBlbSAqKlIqKiBlIGVtICoqUHl0aG9uKiogKGBub3JtYWxpZGFkZS5weWApIGNvaW5jaWRlbSwgdmFsaWRhbmRvIGEgaW1wbGVtZW50YcOnw6NvIGNvbXB1dGFjaW9uYWwgZW0gYW1iYXMgYXMgbGluZ3VhZ2VuczsKLSBRdWFuZG8gYSBub3JtYWxpZGFkZSBuw6NvIHNlIGNvbmZpcm1hIOKAlCBjb21vIGVtIGBPem9uZWAg4oCUIGFzIGFsdGVybmF0aXZhcyBtZXRvZG9sw7NnaWNhcyBpbmNsdWVtOiAoaSkgdHJhbnNmb3JtYcOnw6NvIGRhIHZhcmnDoXZlbCAobG9nLCBCb3gtQ294KSwgKGlpKSB1c28gZGUgdGVzdGVzIG7Do28tcGFyYW3DqXRyaWNvcyBlcXVpdmFsZW50ZXMsIChpaWkpIGFwb2lvIG5vIFRlb3JlbWEgQ2VudHJhbCBkbyBMaW1pdGUgcXVhbmRvIGEgYW1vc3RyYSDDqSBzdWZpY2llbnRlbWVudGUgZ3JhbmRlLCBvdSAoaXYpIG3DqXRvZG9zIHJvYnVzdG9zL2Jvb3RzdHJhcC4KCiMgMTcuIFJlZmVyw6puY2lhcwoKLSBCVVNTQUIsIFcuIE8uOyBNT1JFVFRJTiwgUC4gQS4gKkVzdGF0w61zdGljYSBCw6FzaWNhKi4gU8OjbyBQYXVsbzogU2FyYWl2YS4KLSBNT05UR09NRVJZLCBELiBDLjsgUlVOR0VSLCBHLiBDLiAqRXN0YXTDrXN0aWNhIEFwbGljYWRhIGUgUHJvYmFiaWxpZGFkZSBwYXJhIEVuZ2VuaGVpcm9zKi4gUmlvIGRlIEphbmVpcm86IExUQy4KLSBQQUdBTk8sIE0uOyBHQVVWUkVBVSwgSy4gKlByaW5jw61waW9zIGRlIEJpb2VzdGF0w61zdGljYSouIFPDo28gUGF1bG86IENlbmdhZ2UgTGVhcm5pbmcuCi0gQ09OT1ZFUiwgVy4gSi4gKlByYWN0aWNhbCBOb25wYXJhbWV0cmljIFN0YXRpc3RpY3MqLiBOZXcgWW9yazogV2lsZXkuCi0gSE9MTEFOREVSLCBNLjsgV09MRkUsIEQuIEEuICpOb25wYXJhbWV0cmljIFN0YXRpc3RpY2FsIE1ldGhvZHMqLiBOZXcgWW9yazogV2lsZXkuCi0gU0hBUElSTywgUy4gUy47IFdJTEssIE0uIEIuIEFuIGFuYWx5c2lzIG9mIHZhcmlhbmNlIHRlc3QgZm9yIG5vcm1hbGl0eSAoY29tcGxldGUgc2FtcGxlcykuICpCaW9tZXRyaWthKiwgdi4gNTIsIG4uIDMvNCwgcC4gNTkx4oCTNjExLCAxOTY1LgotIE1BU1NFWSBKUi4sIEYuIEouIFRoZSBLb2xtb2dvcm92LVNtaXJub3YgdGVzdCBmb3IgZ29vZG5lc3Mgb2YgZml0LiAqSm91cm5hbCBvZiB0aGUgQW1lcmljYW4gU3RhdGlzdGljYWwgQXNzb2NpYXRpb24qLCB2LiA0Niwgbi4gMjUzLCBwLiA2OOKAkzc4LCAxOTUxLgotIFIgQ09SRSBURUFNLiAqUjogQSBMYW5ndWFnZSBhbmQgRW52aXJvbm1lbnQgZm9yIFN0YXRpc3RpY2FsIENvbXB1dGluZyouIERvY3VtZW50YcOnw6NvIGRlIGBzaGFwaXJvLnRlc3QoKWAsIGBrcy50ZXN0KClgLCBgcXFub3JtKClgLCBgcXFsaW5lKClgLgoKLS0tCgoqKkFycXVpdm9zIGNvbXBsZW1lbnRhcmVzIGRlc3RlIHNlbWluw6FyaW8gKG1lc21hIHBhc3RhKToqKiBgbm9ybWFsaWRhZGUuUmAsIGBub3JtYWxpZGFkZS5weWA=