##Load##
library (devtools)
library (dplyr)
library (ggplot2)
library (shiny)
library(statsr)
library(huxtable)
data("nlschools")
library(GGally)
| esse é um tutorialzinho - básico- começa com regressão e depois segue com outros - se tiver ideias ou dúvidas me mande gregoriosilva1986@gmail.com |
| FONTE e Codebook |
| FONTE Snijders, T. A. B. and Bosker, R. J. (1999) Multilevel Analysis. An Introduction to Basic and Advanced Multilevel Modelling. London: Sage. |
| References Venables, W. N. and Ripley, B. D. (2002) Modern Applied Statistics with S. Fourth edition. Springer. |
| CODEBOOOK: lang language test score. |
| IQ verbal IQ. |
| class class ID. |
| GS class size: number of eighth-grade pupils recorded in the class (there may be others: see COMB, and some may have been omitted with missing values). |
| SES social-economic status of pupil’s family. |
| COMB were the pupils taught in a multi-grade class (0/1)? Classes which contained pupils from grades 7 and 8 are coded 1, but only eighth-graders were tested. |
|
|
|
r str(nlschools) |
|
|
'data.frame': 2287 obs. of 6 variables: $ lang : int 46 45 33 46 20 30 30 57 36 36 ... $ IQ : num 15 14.5 9.5 11 8 9.5 9.5 13 9.5 11 ... $ class: Factor w/ 133 levels "180","280","1082",..: 1 1 1 1 1 1 1 1 1 1 ... $ GS : int 29 29 29 29 29 29 29 29 29 29 ... $ SES : int 23 10 15 23 10 10 23 10 13 15 ... $ COMB : Factor w/ 2 levels "0","1": 1 1 1 1 1 1 1 1 1 1 ... |
|
|
|
O que será feito (ou o indíce)
A variável a ser explicada é a nota no teste de linguaguem(lang). Para cumprir tal propósito essa atividade terá as seguintes atribuições:
1- Selecionar em uma novo “quadro de dados” chamado(q1) contendo as variáveis: lang,IQ, e SES.
2- Primeiro serão testes de dispersão e frequência das 3 variáveis
3- Depois associar-se-à a variável depedente com as outras.
4- Será rodada regressão linear simples **lang ~ IQ" e testes de diagnóstico
5- Será rodada regressão linear simples **lang ~ SES" e testes de diagnóstico
6- Será rodada regressão linear múltipla completa
7- Decidirá qual das hipóteses é a correta
#H1 - Há associação entre lang e IQ
There were 22 warnings (use warnings() to see them)
#H2 - Há associação entre lang e SES
#H3 - Há associção entre lang e ambas
#h0 - não há associação.
glance(q1)
Data frame tidiers are deprecated and will be removed in an upcoming release of broom.`data_frame()` is deprecated as of tibble 1.1.0.
Please use `tibble()` instead.
[90mThis warning is displayed once every 8 hours.[39m
[90mCall `lifecycle::last_warnings()` to see where this warning was generated.[39m
daí em diante outros tutoriais para mais info ver depois do sete consta novo indíce
8, 9, 10, ….. veja lá. outros testes. ‘sampling’ ‘intervalo de confiança’ ‘níveis de confiança’ ‘inferência de variável numérica sem ser regressão’ daí em diante outros tutoriais para mais info ver depois do sete consta novo indíce
na sessão 11 - encontra testes de associação entre numérica e caractere bem legal.
1- Criando o quadro de dados
q1 <- subset(nlschools, select = c(lang, IQ, SES)) %>% na.omit()
dim(nlschools)
[1] 2287 6
dim(q1)
[1] 2287 3
Ok não houve perda de casos - Q1 criado.
2- testes de dispersão e frequência das 3 variáveis
summary(q1)
lang IQ SES
Min. : 9.00 Min. : 4.00 Min. :10.00
1st Qu.:35.00 1st Qu.:10.50 1st Qu.:20.00
Median :42.00 Median :12.00 Median :27.00
Mean :40.93 Mean :11.83 Mean :27.81
3rd Qu.:48.00 3rd Qu.:13.00 3rd Qu.:35.00
Max. :58.00 Max. :18.00 Max. :50.00
hist(q1$lang)

hist(q1$IQ)

hist(q1$SES)

3- Depois associar-se-à a variável depedente com as outras.
3.1 lang e IQ
plot(q1$lang ~ q1$IQ)

q1 %>%
summarise(cor(lang, IQ))
obs - tanto visual, quanto no valor de cor, parece haver associação.
3.2 lang e SES
plot(q1$lang ~ q1$SES)

q1 %>%
summarise(cor(lang, SES))
Não parece haver associação (ou bem fraca)
4- Será rodada regressão linear simples com lang ~ IQ" e testes de diagnóstico
m1 <- lm(lang ~ IQ, data = q1)
summary(m1)
Call:
lm(formula = lang ~ IQ, data = q1)
Residuals:
Min 1Q Median 3Q Max
-28.7022 -4.3944 0.6056 5.2595 26.2212
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 9.52848 0.86682 10.99 <2e-16 ***
IQ 2.65390 0.07215 36.78 <2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 7.137 on 2285 degrees of freedom
Multiple R-squared: 0.3719, Adjusted R-squared: 0.3716
F-statistic: 1353 on 1 and 2285 DF, p-value: < 2.2e-16
Bom resultado, - cada indicar de Qi parece fazer subir 2.6 em lang.
vejamos a análise
ggplot(data = q1, aes(x = IQ, y = lang)) +
geom_point() +
stat_smooth(method = "lm", se = FALSE)

Diagnóstico
#Linearidade: você já verificou se a relação entre as corridas e as batidas é linear usando um gráfico de dispersão. Devemos também verificar esta condição com um gráfico dos valores residuais vs. ajustados (previstos).
ggplot(data = m1, aes(x = .fitted, y = .resid)) +
geom_point() +
geom_hline(yintercept = 0, linetype = "dashed") +
xlab("Fitted values") +
ylab("Residuals")

#Resíduos quase normais: para verificar esta condição, podemos olhar um histograma
ggplot(data = m1, aes(x = .resid)) +
geom_histogram(binwidth = 25) +
xlab("Residuals")

ggplot(data = m1, aes(sample = .resid)) +
stat_qq()

Em suma, parece bom. O R_adju_m1 é 0.3716
r_adju_m1 <- 0.3716
5- Será rodada regressão linear simples com lang ~ SES" e testes de diagnóstico
m2 <- lm(lang ~ SES, data = q1)
summary(m2)
Call:
lm(formula = lang ~ SES, data = q1)
Residuals:
Min 1Q Median 3Q Max
-32.577 -5.483 0.557 6.363 21.410
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 32.77758 0.48219 67.98 <2e-16 ***
SES 0.29330 0.01614 18.17 <2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 8.418 on 2285 degrees of freedom
Multiple R-squared: 0.1263, Adjusted R-squared: 0.1259
F-statistic: 330.2 on 1 and 2285 DF, p-value: < 2.2e-16
A variável SES parece ter menos poder explicativo, embora apresente algum. o valor de r adjusted é menor que na sessão anterior, mas não é desprezível.
veja a linha:
ggplot(data = q1, aes(x = SES, y = lang)) +
geom_point() +
stat_smooth(method = "lm", se = FALSE)

testes de diagnóstico dá medo
#Linearidade: você já verificou se a relação entre as corridas e as batidas é linear usando um gráfico de dispersão. Devemos também verificar esta condição com um gráfico dos valores residuais vs. ajustados (previstos).
ggplot(data = m2, aes(x = .fitted, y = .resid)) +
geom_point() +
geom_hline(yintercept = 0, linetype = "dashed") +
xlab("Fitted values") +
ylab("Residuals")

#Resíduos quase normais: para verificar esta condição, podemos olhar um histograma
ggplot(data = m2, aes(x = .resid)) +
geom_histogram(binwidth = 25) +
xlab("Residuals")

ggplot(data = m1, aes(sample = .resid)) +
stat_qq()

Em suma:
testes meia boca
e
valor de r adjusted para m2 é 0.125
r_adju_m2 <- 0.125
6- Será rodada regressão linear múltipla completa*
A primeira coisa é avaliar a função gg_pairs para ver se há colinearidade
ggpairs(q1)

Não há correlação entre as variáveis indepedentes a ponto do risco de colinearidade
AGORA A REGRESSÃO CHAMADA DE m3
m3 <- lm(lang ~ IQ + SES, data = q1)
summary(m3)
Call:
lm(formula = lang ~ IQ + SES, data = q1)
Residuals:
Min 1Q Median 3Q Max
-27.8208 -4.5375 0.4499 4.9173 25.6117
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 8.33128 0.85416 9.754 <2e-16 ***
IQ 2.40542 0.07430 32.376 <2e-16 ***
SES 0.14877 0.01409 10.557 <2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 6.971 on 2284 degrees of freedom
Multiple R-squared: 0.4011, Adjusted R-squared: 0.4006
F-statistic: 764.8 on 2 and 2284 DF, p-value: < 2.2e-16
Adjusted de 0,40 melhor que o de m1- portanto o melhor modelo: Logo: parece ser h3, mas antes vamos aos testes de diagnóstico
dignóstico de m3(Reg.Linear Múltipla)
#passo 1 - LINEAR RELATIONSHIPS BETWEEN X AND Y - obs tem que ser random para dar boa
cog_final = lm(lang ~ IQ + SES, data = q1)
plot(cog_final$residuals ~ q1$IQ)

plot(cog_final$residuals ~ q1$SES)

#passo 2 - nearly normal residuals
hist(cog_final$residuals)

qqnorm(cog_final$residuals)
qqline(cog_final$residuals)

#passo 3 - constant variability of residualsa
plot(cog_final$residuals ~ cog_final$fitted)

plot(abs(cog_final$residuals) ~ cog_final$fitted)

#PASSO 4 - iNDEPENDENCE OF RESIDUALS
plot(cog_final$residuals)

Vou olhar em C:R _DUKE33 (procurar no meu Dropbox se estiver em outro PC) imagem a28 em diante para ver se está correto
7- qual das hipóteses é a correta?
H3 - Há associção entre lang e ambas
| FIm?????? |
| se quer ver como faz regressão só com variáveis numéricas okm |
o Novo indíce
8 - brincando de sampling lang
9- intervalo de confiança sampling com lang
10- Confidence levels em lang
11- ‘inferência de variável numérica sem ser regressão’
8- brincando de sampling lang
#os dados "reais"
q1 %>%
summarise(mu = mean(lang), pop_med = median(lang),
sigma = sd(lang), pop_iqr = IQR(lang),
pop_min = min(lang), pop_max = max(lang),
pop_q1 = quantile(lang, 0.25), # first quartile, 25th percentile
pop_q3 = quantile(lang, 0.75)) # third quartile, 75th percentile
##criando amostrinha de 50
samp1 <- q1 %>%
sample_n(size = 50)
samp1 %>%
summarise(mean_samp_1 = mean(lang), samp_1_med = median(lang),
s_samp_1 = sd(lang), samp_1_iqr = IQR(lang),
samp_1_min = min(lang), samp1_max = max(lang),
samp_1_q1 = quantile(lang, 0.25), # first quartile, 25th percentile
samp_1_q3 = quantile(lang, 0.75)) # third quartile, 75th percentile
esse amostrinha(nome real = samp1) aleatória de 50 deu parecida com o dado real, a maior diferença é o minimo de 9 na “população” e 21 na amostrinha
#Se estivermos interessados em estimar a lang média em Ames usando a amostrinha, nossa melhor estimativa é a média da amostra.acima 41,4. vou chamála de x_bar - vide abaixo
There were 21 warnings (use warnings() to see them)
samp1 %>%
summarise(x_bar = mean(lang))
NA
#Aqui iremos gerar 15.000 amostras e calcular a média da amostra de cada um. Observe que estamos amostrando com substituição, `substituir = TRUE`, uma vez que as distribuições de amostragem são construídas com amostragem com substituição.
sample_means50 <- q1 %>%
rep_sample_n(size = 50, reps = 15000, replace = TRUE) %>%
summarise(x_bar = mean(lang))
`summarise()` ungrouping output (override with `.groups` argument)
ggplot(data = sample_means50, aes(x = x_bar)) +
geom_histogram(binwidth = 1)

acima fiz módulo 2 week 1———daí módulo módulo 2 weeek 2 Foundations for inference - Confidence intervals…
9 - intervalos de confiança com lang repito que
acima fiz módulo 2 week 1
daí módulo módulo 2 weeek 2 Foundations for inference - Confidence intervals
então vemmmmmmmmmmmm
#começa criando uma de 60
n <- 60
samp <- sample_n(q1, n)
#aí se mostra as medidas de dispersão dessa amostrinha aleatória de 60(como fiz com o de 50 na sessão anterior)
#obs - para comparar com os dados "populacionais" e a amostrinha de 50 (chamada de samp1) basta ir a sessão anterior(8).
samp %>%
summarise (mean_samp60 = mean(lang), med_s60 = median(lang),
se_s60 = sd(lang))
confidence intervals de 95%
primeiro aplico a fórmulo
xbar +ou- z* s/raiz quadrada de n
a famosa fórmula para esse cáclulo
para saber o valor de z* ´é só olhar a famosa tabela
#Podemos encontrar o valor crítico para um intervalo de confiança de 95% usando
z_star_95 <- 1.959964
z_star_95
[1] 1.959964
aplica-se a fórmula:
samp %>%
summarise(lower = mean(lang) - z_star_95 * (sd(lang) / sqrt(n)),
upper = mean(lang) + z_star_95 * (sd(lang) / sqrt(n)))
10- níveis de confiança em lang
Confidence levels…………
#params é o nome dado para fixar o valor real da média populacional
params <- q1 %>%
summarise(mu = mean(lang))
params
vamo continua trabaiando com a nossa amostrinha de 60 (samp)
antes só uma observação - o intervalo gerado acima não capta a média “real”(mu)
por isso ñ é 100%
né
vamos então criar vários intervalos de confiança…………………
ci <- q1 %>%
rep_sample_n(size = n, reps = 50, replace = TRUE) %>%
summarise(lower = mean(lang) - z_star_95 * (sd(lang) / sqrt(n)),
upper = mean(lang) + z_star_95 * (sd(lang) / sqrt(n)))
`summarise()` ungrouping output (override with `.groups` argument)
#eu fiz cinquenta, vamos ver os cinco primeiros
ci %>%
slice(1:5)
todos os cinco acima captam o valor real mu - conforme se vê abaixo
ci <- ci %>%
mutate(capture_mu = ifelse(lower < params$mu & upper > params$mu, "yes", "no"))
ci %>%
slice(1:5)
vamos ver da linha 21 a 32
ci %>%
slice(21:32)
como se vê acima a linha 25 (vigésima quinta simulação não contemplou o valor real de mu, as outras sim)
A seguir gerarei um ótimo gráfico com todas as 50
ci_data <- data.frame(ci_id = c(1:50, 1:50),
ci_bounds = c(ci$lower, ci$upper),
capture_mu = c(ci$capture_mu, ci$capture_mu))
ggplot(data = ci_data, aes(x = ci_bounds, y = ci_id,
group = ci_id, color = capture_mu)) +
geom_point(size = 2) + # add points at the ends, size = 2
geom_line() + # connect with lines
geom_vline(xintercept = params$mu, color = "darkgray") # draw vertical line

somente duas não capturaram o valor real. nossa amostra de 60 seria um bom número para 95% de confiança
11- ‘inferência de variável numérica sem ser regressão’
cserá necessária outra base - uma que tenha - uma variável numérica sendo explicada por uma categorial
conforme exemplo da módulo 2 week 3 - (peso do bebê explicado pelo hábito de fumar da gestante[sim ou não dicotômica])
para esse exercício procurarei outra relaçaõ simular (com tipos de variáveis parecidas) criarei q11 com as duas variáveis da brincadeira
a idade da mãe gestante (mage) pelo fato de ela ser casada ou não (marital - sim ou não dicotômica) no dia do nascimento da criança
acredito que a idade da mãe seja explicada por esse estado marital
omiti os missings
veja tudo abaixo
data(nc)
q11 <- subset(nc, select = c(mage,marital)) %>% na.omit()
dim(nc)
[1] 1000 13
dim(q11)
[1] 999 2
perdi um caso que era missing, de boas , ainda tem 999 na amostra.
summary(q11$mage)
Min. 1st Qu. Median Mean 3rd Qu. Max.
13.00 22.00 27.00 26.99 32.00 50.00
summary(q11$marital)
married not married
386 613
hist(q11$mage)

plot(q11$marital)

primeiro teste de associação é o boxplot (visual)
boxplot(q11$mage ~ q11$marital, col = "orange", main="idade da mãe e casamento", ylab="idade da mãe", xlab="estado civil")

as não casadas parecem mães mais velhas que as casadas. nossa!
Os boxplots mostram como as medianas das duas distribuições se comparam, mas também podemos comparar as médias das distribuições usando o seguinte para primeiro agrupar os dados pela variável de marital e, em seguida, calcular a idade média nesses grupos usando a função média.
q11 %>%
group_by(marital) %>%
summarise(mean_mage = mean(mage))
`summarise()` ungrouping output (override with `.groups` argument)
as casadas tem o filho com 23 anos em média, ao passado que as não casados são mães com cerca de 29 anos.
Inference
inference(y = mage, x = marital, data = q11, statistic = "mean", type = "ht", null = 0,
alternative = "twosided", method = "theoretical")
Response variable: numerical
Explanatory variable: categorical (2 levels)
n_married = 386, y_bar_married = 23.5622, s_married = 5.658
n_not married = 613, y_bar_not married = 29.1419, s_not married = 5.524
H0: mu_married = mu_not married
HA: mu_married != mu_not married
t = -15.3164, df = 385
p_value = < 0.0001

Let’s pause for a moment to go through the arguments of this custom function. The first argument is y, which is the response variable that we are interested in: weight. The second argument is the explanatory variable, x, which is the variable that splits the data into two groups, smokers and non-smokers: habit. The third argument, data, is the data frame these variables are stored in. Next is statistic, which is the sample statistic we’re using, or similarly, the population parameter we’re estimating. In future labs we can also work with “median” and “proportion”. Next we decide on the type of inference we want: a hypothesis test (“ht”) or a confidence interval (“ci”). When performing a hypothesis test, we also need to supply the null value, which in this case is 0, since the null hypothesis sets the two population means equal to each other. The alternative hypothesis can be “less”, “greater”, or “twosided”. Lastly, the method of inference can be “theoretical” or “simulation” based.
For more information on the inference function see the help file with ?inference.
Exercise: What is the conclusion of the hypothesis test?
REJECT the NULL HIPOTHESIS p value bom
constituindo um intervalo de confiança (seguindo com dados e interação de cima)
inference(y = mage, x = marital, data = q11, statistic = "mean", type = "ci", method = "theoretical", order = c("not married","married"))
Response variable: numerical, Explanatory variable: categorical (2 levels)
n_not married = 613, y_bar_not married = 29.1419, s_not married = 5.524
n_married = 386, y_bar_married = 23.5622, s_married = 5.658
95% CI (not married - married): (4.8635 , 6.296)

CONCLUSÃO : Estamos 95% confiantes de que mulheres não casadas que tem seus filhos são em média 4,8 a 6,2 anos mais velhas que as casadas.
xxx
LS0tDQp0aXRsZTogInR1dG9yaWFsemluaG8gYsOhc2ljbyINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCiMjTG9hZCMjDQoNCmBgYHtyfQ0KbGlicmFyeSAoZGV2dG9vbHMpDQoNCmxpYnJhcnkgKGRwbHlyKQ0KDQpsaWJyYXJ5IChnZ3Bsb3QyKQ0KDQpsaWJyYXJ5IChzaGlueSkNCg0KbGlicmFyeShzdGF0c3IpDQoNCmxpYnJhcnkoaHV4dGFibGUpDQoNCmRhdGEoIm5sc2Nob29scyIpDQpgYGANCg0KLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQpgYGB7cn0NCmxpYnJhcnkoR0dhbGx5KQ0KYGBgDQotLS0tLS0tLS0tLS0tLS0tLS0tLS0NCmVzc2Ugw6kgdW0gdHV0b3JpYWx6aW5obyAtIGLDoXNpY28tIGNvbWXDp2EgY29tIHJlZ3Jlc3PDo28gZSBkZXBvaXMgc2VndWUgY29tIG91dHJvcyAtIHNlIHRpdmVyIGlkZWlhcyBvdSBkw7p2aWRhcyBtZSBtYW5kZSAqZ3JlZ29yaW9zaWx2YTE5ODZAZ21haWwuY29tKg0KDQoqKipGT05URSBlIENvZGVib29rKioqDQoNCioqRk9OVEUqKiANClNuaWpkZXJzLCBULiBBLiBCLiBhbmQgQm9za2VyLCBSLiBKLiAoMTk5OSkgTXVsdGlsZXZlbCBBbmFseXNpcy4gQW4gSW50cm9kdWN0aW9uIHRvIEJhc2ljIGFuZCBBZHZhbmNlZCBNdWx0aWxldmVsIE1vZGVsbGluZy4gTG9uZG9uOiBTYWdlLg0KDQpSZWZlcmVuY2VzDQpWZW5hYmxlcywgVy4gTi4gYW5kIFJpcGxleSwgQi4gRC4gKDIwMDIpIE1vZGVybiBBcHBsaWVkIFN0YXRpc3RpY3Mgd2l0aCBTLiBGb3VydGggZWRpdGlvbi4gU3ByaW5nZXIuDQoNCg0KKipDT0RFQk9PT0s6KioNCmxhbmcNCmxhbmd1YWdlIHRlc3Qgc2NvcmUuDQoNCklRDQp2ZXJiYWwgSVEuDQoNCmNsYXNzDQpjbGFzcyBJRC4NCg0KR1MNCmNsYXNzIHNpemU6IG51bWJlciBvZiBlaWdodGgtZ3JhZGUgcHVwaWxzIHJlY29yZGVkIGluIHRoZSBjbGFzcyAodGhlcmUgbWF5IGJlIG90aGVyczogc2VlIENPTUIsIGFuZCBzb21lIG1heSBoYXZlIGJlZW4gb21pdHRlZCB3aXRoIG1pc3NpbmcgdmFsdWVzKS4NCg0KU0VTDQpzb2NpYWwtZWNvbm9taWMgc3RhdHVzIG9mIHB1cGlsJ3MgZmFtaWx5Lg0KDQpDT01CDQp3ZXJlIHRoZSBwdXBpbHMgdGF1Z2h0IGluIGEgbXVsdGktZ3JhZGUgY2xhc3MgKDAvMSk/IENsYXNzZXMgd2hpY2ggY29udGFpbmVkIHB1cGlscyBmcm9tIGdyYWRlcyA3IGFuZCA4IGFyZSBjb2RlZCAxLCBidXQgb25seSBlaWdodGgtZ3JhZGVycyB3ZXJlIHRlc3RlZC4NCg0KYGBge3J9DQpzdHIobmxzY2hvb2xzKQ0KYGBgDQoNCg0KLS0tLS0tLS0tLS0tLS0tLS0tLQ0KKioqTyBxdWUgc2Vyw6EgZmVpdG8gKG91IG8gaW5kw61jZSkqKioNCg0KQSB2YXJpw6F2ZWwgYSBzZXIgZXhwbGljYWRhIMOpIGEgbm90YSBubyB0ZXN0ZSBkZSBsaW5ndWFndWVtKCoqbGFuZyoqKS4gUGFyYSBjdW1wcmlyIHRhbCBwcm9ww7NzaXRvIGVzc2EgYXRpdmlkYWRlIHRlcsOhIGFzIHNlZ3VpbnRlcyBhdHJpYnVpw6fDtWVzOg0KDQoxLSBTZWxlY2lvbmFyIGVtIHVtYSBub3ZvICJxdWFkcm8gZGUgZGFkb3MiIGNoYW1hZG8oKipxMSoqKSBjb250ZW5kbyBhcyB2YXJpw6F2ZWlzOiAqbGFuZyosKklRKiwgZSAqU0VTKi4NCg0KMi0gUHJpbWVpcm8gc2Vyw6NvIHRlc3RlcyBkZSBkaXNwZXJzw6NvIGUgZnJlcXXDqm5jaWEgZGFzIDMgdmFyacOhdmVpcw0KDQozLSBEZXBvaXMgYXNzb2NpYXItc2Utw6AgYSB2YXJpw6F2ZWwgZGVwZWRlbnRlIGNvbSBhcyBvdXRyYXMuDQoNCjQtIFNlcsOhIHJvZGFkYSByZWdyZXNzw6NvIGxpbmVhciBzaW1wbGVzICoqbGFuZyB+IElRIiBlIHRlc3RlcyBkZSBkaWFnbsOzc3RpY28NCg0KNS0gU2Vyw6Egcm9kYWRhIHJlZ3Jlc3PDo28gbGluZWFyIHNpbXBsZXMgKipsYW5nIH4gU0VTIiBlIHRlc3RlcyBkZSBkaWFnbsOzc3RpY28NCg0KNi0gU2Vyw6Egcm9kYWRhIHJlZ3Jlc3PDo28gbGluZWFyIG3Dumx0aXBsYSBjb21wbGV0YQ0KDQo3LSBEZWNpZGlyw6EgcXVhbCBkYXMgaGlww7N0ZXNlcyDDqSBhIGNvcnJldGENCg0KYGBge3J9DQojSDEgLSBIw6EgYXNzb2NpYcOnw6NvIGVudHJlIGxhbmcgZSBJUQ0KDQojSDIgLSBIw6EgYXNzb2NpYcOnw6NvIGVudHJlIGxhbmcgZSBTRVMNCg0KI0gzIC0gSMOhIGFzc29jacOnw6NvIGVudHJlIGxhbmcgZSBhbWJhcw0KDQojaDAgLSBuw6NvIGjDoSBhc3NvY2lhw6fDo28uDQpnbGFuY2UocTEpDQoNCmBgYA0KDQpkYcOtIGVtIGRpYW50ZSBvdXRyb3MgdHV0b3JpYWlzIHBhcmEgbWFpcyBpbmZvIHZlciBkZXBvaXMgZG8gc2V0ZSBjb25zdGEgbm92byBpbmTDrWNlDQoNCjgsIDksIDEwLCAuLi4uLiB2ZWphIGzDoS4gb3V0cm9zIHRlc3Rlcy4NCidzYW1wbGluZycNCidpbnRlcnZhbG8gZGUgY29uZmlhbsOnYScgDQonbsOtdmVpcyBkZSBjb25maWFuw6dhJw0KJ2luZmVyw6puY2lhIGRlIHZhcmnDoXZlbCBudW3DqXJpY2Egc2VtIHNlciByZWdyZXNzw6NvJw0KZGHDrSBlbSBkaWFudGUgb3V0cm9zIHR1dG9yaWFpcyBwYXJhIG1haXMgaW5mbyB2ZXIgZGVwb2lzIGRvIHNldGUgY29uc3RhIG5vdm8gaW5kw61jZQ0KDQpuYSBzZXNzw6NvIDExIC0gZW5jb250cmEgdGVzdGVzIGRlIGFzc29jaWHDp8OjbyBlbnRyZSBudW3DqXJpY2EgZSBjYXJhY3RlcmUgYmVtIGxlZ2FsLg0KDQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KKioqMS0gQ3JpYW5kbyBvIHF1YWRybyBkZSBkYWRvcyoqKg0KDQpgYGB7cn0NCnExIDwtIHN1YnNldChubHNjaG9vbHMsIHNlbGVjdCA9IGMobGFuZywgSVEsIFNFUykpICU+JSBuYS5vbWl0KCkNCmRpbShubHNjaG9vbHMpDQpkaW0ocTEpDQpgYGANCg0KT2sgbsOjbyBob3V2ZSBwZXJkYSBkZSBjYXNvcyAtIFExIGNyaWFkby4NCg0KDQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQoqKioyLSB0ZXN0ZXMgZGUgZGlzcGVyc8OjbyBlIGZyZXF1w6puY2lhIGRhcyAzIHZhcmnDoXZlaXMqKioNCg0KYGBge3J9DQpzdW1tYXJ5KHExKQ0KYGBgDQoNCmBgYHtyfQ0KaGlzdChxMSRsYW5nKQ0KaGlzdChxMSRJUSkNCmhpc3QocTEkU0VTKQ0KYGBgDQoNCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQoqKiozLSBEZXBvaXMgYXNzb2NpYXItc2Utw6AgYSB2YXJpw6F2ZWwgZGVwZWRlbnRlIGNvbSBhcyBvdXRyYXMuKioqDQoNCjMuMQ0KbGFuZyBlIElRDQoNCg0KYGBge3J9DQpwbG90KHExJGxhbmcgfiBxMSRJUSkNCmBgYA0KDQpgYGB7cn0NCnExICU+JQ0KICBzdW1tYXJpc2UoY29yKGxhbmcsIElRKSkNCmBgYA0KDQpvYnMgLSB0YW50byB2aXN1YWwsIHF1YW50byBubyB2YWxvciBkZSBjb3IsIHBhcmVjZSBoYXZlciBhc3NvY2lhw6fDo28uDQoNCg0KDQozLjIgbGFuZyBlIFNFUw0KYGBge3J9DQpwbG90KHExJGxhbmcgfiBxMSRTRVMpDQpgYGANCg0KYGBge3J9DQpxMSAlPiUNCiAgc3VtbWFyaXNlKGNvcihsYW5nLCBTRVMpKQ0KYGBgDQoNCk7Do28gcGFyZWNlIGhhdmVyIGFzc29jaWHDp8OjbyAob3UgYmVtIGZyYWNhKQ0KDQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQoNCioqKjQtIFNlcsOhIHJvZGFkYSByZWdyZXNzw6NvIGxpbmVhciBzaW1wbGVzIGNvbSBsYW5nIH4gSVEiIGUgdGVzdGVzIGRlIGRpYWduw7NzdGljbyoqKg0KDQoNCmBgYHtyfQ0KbTEgPC0gbG0obGFuZyB+IElRLCBkYXRhID0gcTEpDQpzdW1tYXJ5KG0xKQ0KYGBgDQoNCkJvbSByZXN1bHRhZG8sIC0gY2FkYSBpbmRpY2FyIGRlIFFpIHBhcmVjZSBmYXplciBzdWJpciAyLjYgZW0gbGFuZy4NCg0KdmVqYW1vcyBhIGFuw6FsaXNlDQpgYGB7cn0NCmdncGxvdChkYXRhID0gcTEsIGFlcyh4ID0gSVEsIHkgPSBsYW5nKSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBzdGF0X3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFKQ0KYGBgDQoNCkRpYWduw7NzdGljbw0KYGBge3J9DQojTGluZWFyaWRhZGU6IHZvY8OqIGrDoSB2ZXJpZmljb3Ugc2UgYSByZWxhw6fDo28gZW50cmUgYXMgY29ycmlkYXMgZSBhcyBiYXRpZGFzIMOpIGxpbmVhciB1c2FuZG8gdW0gZ3LDoWZpY28gZGUgZGlzcGVyc8Ojby4gRGV2ZW1vcyB0YW1iw6ltIHZlcmlmaWNhciBlc3RhIGNvbmRpw6fDo28gY29tIHVtIGdyw6FmaWNvIGRvcyB2YWxvcmVzIHJlc2lkdWFpcyB2cy4gYWp1c3RhZG9zIChwcmV2aXN0b3MpLg0KZ2dwbG90KGRhdGEgPSBtMSwgYWVzKHggPSAuZml0dGVkLCB5ID0gLnJlc2lkKSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArDQogIHhsYWIoIkZpdHRlZCB2YWx1ZXMiKSArDQogIHlsYWIoIlJlc2lkdWFscyIpDQpgYGANCg0KYGBge3J9DQojUmVzw61kdW9zIHF1YXNlIG5vcm1haXM6IHBhcmEgdmVyaWZpY2FyIGVzdGEgY29uZGnDp8OjbywgcG9kZW1vcyBvbGhhciB1bSBoaXN0b2dyYW1hDQpnZ3Bsb3QoZGF0YSA9IG0xLCBhZXMoeCA9IC5yZXNpZCkpICsNCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAyNSkgKw0KICB4bGFiKCJSZXNpZHVhbHMiKQ0KZ2dwbG90KGRhdGEgPSBtMSwgYWVzKHNhbXBsZSA9IC5yZXNpZCkpICsNCiAgc3RhdF9xcSgpDQpgYGANCg0KDQoNCkVtIHN1bWEsIHBhcmVjZSBib20uIE8gUl9hZGp1X20xIMOpIDAuMzcxNg0KYGBge3J9DQpyX2FkanVfbTEgPC0gMC4zNzE2DQpgYGANCg0KLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KKioqNS0gU2Vyw6Egcm9kYWRhIHJlZ3Jlc3PDo28gbGluZWFyIHNpbXBsZXMgY29tIGxhbmcgfiBTRVMiIGUgdGVzdGVzIGRlIGRpYWduw7NzdGljbyoqKg0KDQpgYGB7cn0NCm0yIDwtIGxtKGxhbmcgfiBTRVMsIGRhdGEgPSBxMSkNCnN1bW1hcnkobTIpDQpgYGANCg0KQSB2YXJpw6F2ZWwgU0VTIHBhcmVjZSB0ZXIgbWVub3MgcG9kZXIgZXhwbGljYXRpdm8sIGVtYm9yYSBhcHJlc2VudGUgYWxndW0uIG8gdmFsb3IgZGUgciBhZGp1c3RlZCDDqSBtZW5vciBxdWUgbmEgc2Vzc8OjbyBhbnRlcmlvciwgbWFzIG7Do28gw6kgZGVzcHJlesOtdmVsLg0KDQp2ZWphIGEgbGluaGE6DQoNCmBgYHtyfQ0KZ2dwbG90KGRhdGEgPSBxMSwgYWVzKHggPSBTRVMsIHkgPSBsYW5nKSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBzdGF0X3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFKQ0KYGBgDQoNCip0ZXN0ZXMgZGUgZGlhZ27Ds3N0aWNvKiBkw6EgbWVkbw0KDQpgYGB7cn0NCg0KDQojTGluZWFyaWRhZGU6IHZvY8OqIGrDoSB2ZXJpZmljb3Ugc2UgYSByZWxhw6fDo28gZW50cmUgYXMgY29ycmlkYXMgZSBhcyBiYXRpZGFzIMOpIGxpbmVhciB1c2FuZG8gdW0gZ3LDoWZpY28gZGUgZGlzcGVyc8Ojby4gRGV2ZW1vcyB0YW1iw6ltIHZlcmlmaWNhciBlc3RhIGNvbmRpw6fDo28gY29tIHVtIGdyw6FmaWNvIGRvcyB2YWxvcmVzIHJlc2lkdWFpcyB2cy4gYWp1c3RhZG9zIChwcmV2aXN0b3MpLg0KZ2dwbG90KGRhdGEgPSBtMiwgYWVzKHggPSAuZml0dGVkLCB5ID0gLnJlc2lkKSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArDQogIHhsYWIoIkZpdHRlZCB2YWx1ZXMiKSArDQogIHlsYWIoIlJlc2lkdWFscyIpDQoNCiNSZXPDrWR1b3MgcXVhc2Ugbm9ybWFpczogcGFyYSB2ZXJpZmljYXIgZXN0YSBjb25kacOnw6NvLCBwb2RlbW9zIG9saGFyIHVtIGhpc3RvZ3JhbWENCmdncGxvdChkYXRhID0gbTIsIGFlcyh4ID0gLnJlc2lkKSkgKw0KICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDI1KSArDQogIHhsYWIoIlJlc2lkdWFscyIpDQpnZ3Bsb3QoZGF0YSA9IG0xLCBhZXMoc2FtcGxlID0gLnJlc2lkKSkgKw0KICBzdGF0X3FxKCkNCmBgYA0KDQpFbSBzdW1hOg0KDQp0ZXN0ZXMgbWVpYSBib2NhDQoNCmUNCg0KdmFsb3IgZGUgciBhZGp1c3RlZCBwYXJhIG0yIMOpIDAuMTI1DQpgYGB7cn0NCnJfYWRqdV9tMiA8LSAwLjEyNQ0KYGBgDQoNCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQoqKio2LSBTZXLDoSByb2RhZGEgcmVncmVzc8OjbyBsaW5lYXIgbcO6bHRpcGxhIGNvbXBsZXRhKioqKg0KDQoNCg0KQSBwcmltZWlyYSBjb2lzYSDDqSBhdmFsaWFyIGEgZnVuw6fDo28gZ2dfcGFpcnMgcGFyYSB2ZXIgc2UgaMOhIGNvbGluZWFyaWRhZGUNCg0KYGBge3J9DQpnZ3BhaXJzKHExKQ0KYGBgDQoNCk7Do28gaMOhIGNvcnJlbGHDp8OjbyBlbnRyZSBhcyB2YXJpw6F2ZWlzIGluZGVwZWRlbnRlcyBhIHBvbnRvIGRvIHJpc2NvIGRlIGNvbGluZWFyaWRhZGUNCg0KQUdPUkEgQSBSRUdSRVNTw4NPIENIQU1BREEgREUgKiptMyoqDQoNCmBgYHtyfQ0KbTMgPC0gbG0obGFuZyB+IElRICsgU0VTLCBkYXRhID0gcTEpDQpzdW1tYXJ5KG0zKQ0KYGBgDQoNCkFkanVzdGVkIGRlIDAsNDAgbWVsaG9yIHF1ZSBvIGRlIG0xLSBwb3J0YW50byBvIG1lbGhvciBtb2RlbG86IExvZ286IHBhcmVjZSBzZXIgaDMsIG1hcyBhbnRlcyB2YW1vcyBhb3MgdGVzdGVzIGRlIGRpYWduw7NzdGljbw0KDQoNCioqZGlnbsOzc3RpY28gZGUgbTMoUmVnLkxpbmVhciBNw7psdGlwbGEpKioNCmBgYHtyfQ0KDQojcGFzc28gMSAtIExJTkVBUiBSRUxBVElPTlNISVBTIEJFVFdFRU4gWCBBTkQgWSAtIG9icyB0ZW0gcXVlIHNlciByYW5kb20gcGFyYSBkYXIgYm9hDQpjb2dfZmluYWwgPSBsbShsYW5nIH4gSVEgKyBTRVMsIGRhdGEgPSBxMSkNCnBsb3QoY29nX2ZpbmFsJHJlc2lkdWFscyB+IHExJElRKQ0KcGxvdChjb2dfZmluYWwkcmVzaWR1YWxzIH4gcTEkU0VTKQ0KDQojcGFzc28gMiAtIG5lYXJseSBub3JtYWwgcmVzaWR1YWxzDQpoaXN0KGNvZ19maW5hbCRyZXNpZHVhbHMpDQoNCnFxbm9ybShjb2dfZmluYWwkcmVzaWR1YWxzKQ0KcXFsaW5lKGNvZ19maW5hbCRyZXNpZHVhbHMpDQoNCiNwYXNzbyAzIC0gY29uc3RhbnQgdmFyaWFiaWxpdHkgb2YgcmVzaWR1YWxzYQ0KcGxvdChjb2dfZmluYWwkcmVzaWR1YWxzIH4gY29nX2ZpbmFsJGZpdHRlZCkNCg0KcGxvdChhYnMoY29nX2ZpbmFsJHJlc2lkdWFscykgfiBjb2dfZmluYWwkZml0dGVkKQ0KDQojUEFTU08gNCAtIGlOREVQRU5ERU5DRSBPRiBSRVNJRFVBTFMNCnBsb3QoY29nX2ZpbmFsJHJlc2lkdWFscykNCmBgYA0KDQpWb3Ugb2xoYXIgZW0gQzpcVXNlcnNcZ3JlZ29cRHJvcGJveFxkb3V0b3JhZG9cY3Vyc28gUiBfRFVLRVxtb2R1bG8gM1x3ZWVrIDMgKHByb2N1cmFyIG5vIG1ldSBEcm9wYm94IHNlIGVzdGl2ZXIgZW0gb3V0cm8gUEMpDQppbWFnZW0gYTI4IGVtIGRpYW50ZSBwYXJhIHZlciBzZSBlc3TDoSBjb3JyZXRvDQoNCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KKioqNy0gcXVhbCBkYXMgaGlww7N0ZXNlcyDDqSBhIGNvcnJldGE/KioqDQoNCkgzIC0gSMOhIGFzc29jacOnw6NvIGVudHJlIGxhbmcgZSBhbWJhcw0KDQotLS0tLS0tLS0tLS0tLS0tLS0NCkZJbT8/Pz8/Pw0KDQpzZSBxdWVyIHZlciBjb21vIGZheiByZWdyZXNzw6NvIHPDsyBjb20gdmFyacOhdmVpcyBudW3DqXJpY2FzIG9rbSANCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCioqKm8gTm92byBpbmTDrWNlKioqDQoNCjggLSBicmluY2FuZG8gZGUgc2FtcGxpbmcgbGFuZw0KDQo5LSBpbnRlcnZhbG8gZGUgY29uZmlhbsOnYSBzYW1wbGluZyBjb20gbGFuZw0KDQoxMC0gQ29uZmlkZW5jZSBsZXZlbHMgZW0gbGFuZw0KDQoxMS0gJ2luZmVyw6puY2lhIGRlIHZhcmnDoXZlbCBudW3DqXJpY2Egc2VtIHNlciByZWdyZXNzw6NvJw0KDQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCioqKjgtIGJyaW5jYW5kbyBkZSBzYW1wbGluZyBsYW5nKioqDQoNCmBgYHtyfQ0KI29zIGRhZG9zICJyZWFpcyINCnExICU+JQ0KICBzdW1tYXJpc2UobXUgPSBtZWFuKGxhbmcpLCBwb3BfbWVkID0gbWVkaWFuKGxhbmcpLCANCiAgICAgICAgICAgIHNpZ21hID0gc2QobGFuZyksIHBvcF9pcXIgPSBJUVIobGFuZyksDQogICAgICAgICAgICBwb3BfbWluID0gbWluKGxhbmcpLCBwb3BfbWF4ID0gbWF4KGxhbmcpLA0KICAgICAgICAgICAgcG9wX3ExID0gcXVhbnRpbGUobGFuZywgMC4yNSksICAjIGZpcnN0IHF1YXJ0aWxlLCAyNXRoIHBlcmNlbnRpbGUNCiAgICAgICAgICAgIHBvcF9xMyA9IHF1YW50aWxlKGxhbmcsIDAuNzUpKSAgIyB0aGlyZCBxdWFydGlsZSwgNzV0aCBwZXJjZW50aWxlDQpgYGANCg0KDQpgYGB7cn0NCiMjY3JpYW5kbyBhbW9zdHJpbmhhIGRlIDUwDQpzYW1wMSA8LSBxMSAlPiUNCiAgc2FtcGxlX24oc2l6ZSA9IDUwKQ0Kc2FtcDEgJT4lDQogIHN1bW1hcmlzZShtZWFuX3NhbXBfMSA9IG1lYW4obGFuZyksIHNhbXBfMV9tZWQgPSBtZWRpYW4obGFuZyksIA0KICAgICAgICAgICAgc19zYW1wXzEgPSBzZChsYW5nKSwgc2FtcF8xX2lxciA9IElRUihsYW5nKSwNCiAgICAgICAgICAgIHNhbXBfMV9taW4gPSBtaW4obGFuZyksIHNhbXAxX21heCA9IG1heChsYW5nKSwNCiAgICAgICAgICAgIHNhbXBfMV9xMSA9IHF1YW50aWxlKGxhbmcsIDAuMjUpLCAgIyBmaXJzdCBxdWFydGlsZSwgMjV0aCBwZXJjZW50aWxlDQogICAgICAgICAgICBzYW1wXzFfcTMgPSBxdWFudGlsZShsYW5nLCAwLjc1KSkgICMgdGhpcmQgcXVhcnRpbGUsIDc1dGggcGVyY2VudGlsZQ0KYGBgDQoNCmVzc2UgYW1vc3RyaW5oYShub21lIHJlYWwgPSAqKnNhbXAxKiopIGFsZWF0w7NyaWEgZGUgNTAgZGV1IHBhcmVjaWRhIGNvbSBvIGRhZG8gcmVhbCwgYSBtYWlvciBkaWZlcmVuw6dhIMOpIG8gbWluaW1vIGRlIDkgbmEgInBvcHVsYcOnw6NvIiBlIDIxIG5hIGFtb3N0cmluaGENCg0KYGBge3J9DQojU2UgZXN0aXZlcm1vcyBpbnRlcmVzc2Fkb3MgZW0gZXN0aW1hciBhIGxhbmcgbcOpZGlhIGVtIEFtZXMgdXNhbmRvIGEgYW1vc3RyaW5oYSwgbm9zc2EgbWVsaG9yIGVzdGltYXRpdmEgw6kgYSBtw6lkaWEgZGEgYW1vc3RyYS5hY2ltYSA0MSw0LiB2b3UgY2hhbcOhbGEgZGUgeF9iYXIgLSB2aWRlIGFiYWl4bw0Kc2FtcDEgJT4lDQogIHN1bW1hcmlzZSh4X2JhciA9IG1lYW4obGFuZykpDQoNCmBgYA0KYGBge3J9DQojQXF1aSBpcmVtb3MgZ2VyYXIgMTUuMDAwIGFtb3N0cmFzIGUgY2FsY3VsYXIgYSBtw6lkaWEgZGEgYW1vc3RyYSBkZSBjYWRhIHVtLiBPYnNlcnZlIHF1ZSBlc3RhbW9zIGFtb3N0cmFuZG8gY29tIHN1YnN0aXR1acOnw6NvLCBgc3Vic3RpdHVpciA9IFRSVUVgLCB1bWEgdmV6IHF1ZSBhcyBkaXN0cmlidWnDp8O1ZXMgZGUgYW1vc3RyYWdlbSBzw6NvIGNvbnN0cnXDrWRhcyBjb20gYW1vc3RyYWdlbSBjb20gc3Vic3RpdHVpw6fDo28uDQpzYW1wbGVfbWVhbnM1MCA8LSBxMSAlPiUNCiAgICAgICAgICAgICAgICAgICAgcmVwX3NhbXBsZV9uKHNpemUgPSA1MCwgcmVwcyA9IDE1MDAwLCByZXBsYWNlID0gVFJVRSkgJT4lDQogICAgICAgICAgICAgICAgICAgIHN1bW1hcmlzZSh4X2JhciA9IG1lYW4obGFuZykpDQoNCmdncGxvdChkYXRhID0gc2FtcGxlX21lYW5zNTAsIGFlcyh4ID0geF9iYXIpKSArDQogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gMSkNCmBgYA0KDQphY2ltYSBmaXogbcOzZHVsbyAyIHdlZWsgMS0tLS0tLS0tLWRhw60gbcOzZHVsbyBtw7NkdWxvIDIgd2VlZWsgMiBGb3VuZGF0aW9ucyBmb3IgaW5mZXJlbmNlIC0gQ29uZmlkZW5jZSBpbnRlcnZhbHMuLi4NCg0KLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCioqKjkgLSBpbnRlcnZhbG9zIGRlIGNvbmZpYW7Dp2EgY29tIGxhbmcqKioNCnJlcGl0byBxdWUNCg0KYWNpbWEgZml6IG3Ds2R1bG8gMiB3ZWVrIDENCg0KZGHDrSBtw7NkdWxvIG3Ds2R1bG8gMiB3ZWVlayAyIEZvdW5kYXRpb25zIGZvciBpbmZlcmVuY2UgLSBDb25maWRlbmNlIGludGVydmFscw0KDQplbnTDo28gdmVtbW1tbW1tbW1tbW0NCmBgYHtyfQ0KI2NvbWXDp2EgY3JpYW5kbyB1bWEgZGUgNjANCm4gPC0gNjANCnNhbXAgPC0gc2FtcGxlX24ocTEsIG4pDQojYcOtIHNlIG1vc3RyYSBhcyBtZWRpZGFzIGRlIGRpc3BlcnPDo28gZGVzc2EgYW1vc3RyaW5oYSBhbGVhdMOzcmlhIGRlIDYwKGNvbW8gZml6IGNvbSBvIGRlIDUwIG5hIHNlc3PDo28gYW50ZXJpb3IpDQojb2JzIC0gcGFyYSBjb21wYXJhciBjb20gb3MgZGFkb3MgInBvcHVsYWNpb25haXMiIGUgYSBhbW9zdHJpbmhhIGRlIDUwIChjaGFtYWRhIGRlIHNhbXAxKSBiYXN0YSBpciBhIHNlc3PDo28gYW50ZXJpb3IoOCkuDQpzYW1wICU+JQ0Kc3VtbWFyaXNlIChtZWFuX3NhbXA2MCA9IG1lYW4obGFuZyksIG1lZF9zNjAgPSBtZWRpYW4obGFuZyksDQpzZV9zNjAgPSBzZChsYW5nKSkNCmBgYA0KDQoqKmNvbmZpZGVuY2UgaW50ZXJ2YWxzIGRlIDk1JSoqDQoNCnByaW1laXJvIGFwbGljbyBhIGbDs3JtdWxvIA0KDQp4YmFyICtvdS0geiogcy9yYWl6IHF1YWRyYWRhIGRlIG4NCg0KYSBmYW1vc2EgZsOzcm11bGEgcGFyYSBlc3NlIGPDoWNsdWxvDQoNCnBhcmEgc2FiZXIgbyB2YWxvciBkZSB6KiDCtMOpIHPDsyBvbGhhciBhIGZhbW9zYSB0YWJlbGENCg0KYGBge3J9DQojUG9kZW1vcyBlbmNvbnRyYXIgbyB2YWxvciBjcsOtdGljbyBwYXJhIHVtIGludGVydmFsbyBkZSBjb25maWFuw6dhIGRlIDk1JSB1c2FuZG8NCnpfc3Rhcl85NSA8LSAxLjk1OTk2NA0Kel9zdGFyXzk1DQpgYGANCg0KYXBsaWNhLXNlIGEgZsOzcm11bGE6DQpgYGB7cn0NCnNhbXAgJT4lDQogIHN1bW1hcmlzZShsb3dlciA9IG1lYW4obGFuZykgLSB6X3N0YXJfOTUgKiAoc2QobGFuZykgLyBzcXJ0KG4pKSwNCiAgICAgICAgICAgIHVwcGVyID0gbWVhbihsYW5nKSArIHpfc3Rhcl85NSAqIChzZChsYW5nKSAvIHNxcnQobikpKQ0KYGBgDQoNCi0tLS0tLS0tLS0tLS0tLS0tLQ0KKioqMTAtIG7DrXZlaXMgZGUgY29uZmlhbsOnYSBlbSBsYW5nKioqDQoNCkNvbmZpZGVuY2UgbGV2ZWxzLi4uLi4uLi4uLi4uDQpgYGB7cn0NCiNwYXJhbXMgw6kgbyBub21lIGRhZG8gcGFyYSBmaXhhciBvIHZhbG9yIHJlYWwgZGEgbcOpZGlhIHBvcHVsYWNpb25hbA0KcGFyYW1zIDwtIHExICU+JQ0KICBzdW1tYXJpc2UobXUgPSBtZWFuKGxhbmcpKQ0KcGFyYW1zDQpgYGANCg0KdmFtbyBjb250aW51YSB0cmFiYWlhbmRvIGNvbSBhIG5vc3NhIGFtb3N0cmluaGEgZGUgNjAgKCoqc2FtcCoqKQ0KDQphbnRlcyBzw7MgdW1hIG9ic2VydmHDp8OjbyAtICoqKm8gaW50ZXJ2YWxvIGdlcmFkbyBhY2ltYSBuw6NvIGNhcHRhIGEgbcOpZGlhICJyZWFsIihtdSkqKioNCg0KcG9yIGlzc28gw7Egw6kgMTAwJQ0KDQpuw6kNCg0KDQp2YW1vcyBlbnTDo28gY3JpYXIgdsOhcmlvcyBpbnRlcnZhbG9zIGRlIGNvbmZpYW7Dp2EuLi4uLi4uLi4uLi4uLi4uLi4uLi4NCg0KYGBge3J9DQpjaSA8LSBxMSAlPiUNCiAgICAgICAgcmVwX3NhbXBsZV9uKHNpemUgPSBuLCByZXBzID0gNTAsIHJlcGxhY2UgPSBUUlVFKSAlPiUNCiAgICAgICAgc3VtbWFyaXNlKGxvd2VyID0gbWVhbihsYW5nKSAtIHpfc3Rhcl85NSAqIChzZChsYW5nKSAvIHNxcnQobikpLA0KICAgICAgICAgICAgICAgICAgdXBwZXIgPSBtZWFuKGxhbmcpICsgel9zdGFyXzk1ICogKHNkKGxhbmcpIC8gc3FydChuKSkpDQojZXUgZml6IGNpbnF1ZW50YSwgdmFtb3MgdmVyIG9zIGNpbmNvIHByaW1laXJvcw0KY2kgJT4lDQogIHNsaWNlKDE6NSkNCmBgYA0KDQp0b2RvcyBvcyBjaW5jbyBhY2ltYSBjYXB0YW0gbyB2YWxvciByZWFsIG11IC0gY29uZm9ybWUgc2UgdsOqIGFiYWl4bw0KYGBge3J9DQpjaSA8LSBjaSAlPiUNCiAgbXV0YXRlKGNhcHR1cmVfbXUgPSBpZmVsc2UobG93ZXIgPCBwYXJhbXMkbXUgJiB1cHBlciA+IHBhcmFtcyRtdSwgInllcyIsICJubyIpKQ0KY2kgJT4lDQogIHNsaWNlKDE6NSkNCmBgYA0KDQp2YW1vcyB2ZXIgZGEgbGluaGEgMjEgYSAzMg0KYGBge3J9DQpjaSAlPiUNCiAgc2xpY2UoMjE6MzIpDQpgYGANCg0KY29tbyBzZSB2w6ogYWNpbWEgYSBsaW5oYSAyNSAodmlnw6lzaW1hIHF1aW50YSBzaW11bGHDp8OjbyBuw6NvIGNvbnRlbXBsb3UgbyB2YWxvciByZWFsIGRlIG11LCBhcyBvdXRyYXMgc2ltKQ0KDQpBIHNlZ3VpciBnZXJhcmVpIHVtIMOzdGltbyBncsOhZmljbyBjb20gdG9kYXMgYXMgNTANCg0KYGBge3J9DQpjaV9kYXRhIDwtIGRhdGEuZnJhbWUoY2lfaWQgPSBjKDE6NTAsIDE6NTApLA0KICAgICAgICAgICAgICAgICAgICAgIGNpX2JvdW5kcyA9IGMoY2kkbG93ZXIsIGNpJHVwcGVyKSwNCiAgICAgICAgICAgICAgICAgICAgICBjYXB0dXJlX211ID0gYyhjaSRjYXB0dXJlX211LCBjaSRjYXB0dXJlX211KSkNCmdncGxvdChkYXRhID0gY2lfZGF0YSwgYWVzKHggPSBjaV9ib3VuZHMsIHkgPSBjaV9pZCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cCA9IGNpX2lkLCBjb2xvciA9IGNhcHR1cmVfbXUpKSArDQogIGdlb21fcG9pbnQoc2l6ZSA9IDIpICsgICMgYWRkIHBvaW50cyBhdCB0aGUgZW5kcywgc2l6ZSA9IDINCiAgZ2VvbV9saW5lKCkgKyAgICAgICAgICAgIyBjb25uZWN0IHdpdGggbGluZXMNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gcGFyYW1zJG11LCBjb2xvciA9ICJkYXJrZ3JheSIpICMgZHJhdyB2ZXJ0aWNhbCBsaW5lDQpgYGANCnNvbWVudGUgZHVhcyBuw6NvIGNhcHR1cmFyYW0gbyB2YWxvciByZWFsLiBub3NzYSBhbW9zdHJhIGRlIDYwIHNlcmlhIHVtIGJvbSBuw7ptZXJvIHBhcmEgOTUlIGRlIGNvbmZpYW7Dp2ENCg0KDQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KKioqMTEtICdpbmZlcsOqbmNpYSBkZSB2YXJpw6F2ZWwgbnVtw6lyaWNhIHNlbSBzZXIgcmVncmVzc8OjbycqKioNCg0KY3NlcsOhIG5lY2Vzc8OhcmlhIG91dHJhIGJhc2UgLSB1bWEgcXVlIHRlbmhhIC0gdW1hIHZhcmnDoXZlbCBudW3DqXJpY2Egc2VuZG8gZXhwbGljYWRhIHBvciB1bWEgY2F0ZWdvcmlhbA0KDQpjb25mb3JtZSBleGVtcGxvIGRhIG3Ds2R1bG8gMiB3ZWVrIDMgLSAocGVzbyBkbyBiZWLDqiBleHBsaWNhZG8gcGVsbyBow6FiaXRvIGRlIGZ1bWFyIGRhIGdlc3RhbnRlW3NpbSBvdSBuw6NvIGRpY290w7RtaWNhXSkNCg0KcGFyYSBlc3NlIGV4ZXJjw61jaW8gcHJvY3VyYXJlaSBvdXRyYSByZWxhw6dhw7Ugc2ltdWxhciAoY29tIHRpcG9zIGRlIHZhcmnDoXZlaXMgcGFyZWNpZGFzKQ0KY3JpYXJlaSBxMTEgY29tIGFzIGR1YXMgdmFyacOhdmVpcyBkYSBicmluY2FkZWlyYQ0KDQphIGlkYWRlIGRhIG3Do2UgZ2VzdGFudGUgKG1hZ2UpIHBlbG8gZmF0byBkZSBlbGEgc2VyIGNhc2FkYSBvdSBuw6NvIChtYXJpdGFsIC0gc2ltIG91IG7Do28gZGljb3TDtG1pY2EpIG5vIGRpYSBkbyBuYXNjaW1lbnRvIGRhIGNyaWFuw6dhDQoNCmFjcmVkaXRvIHF1ZSBhIGlkYWRlIGRhIG3Do2Ugc2VqYSBleHBsaWNhZGEgcG9yIGVzc2UgZXN0YWRvIG1hcml0YWwNCg0Kb21pdGkgb3MgbWlzc2luZ3MgDQoNCnZlamEgdHVkbyBhYmFpeG8NCg0KDQpgYGB7cn0NCmRhdGEobmMpDQpxMTEgPC0gc3Vic2V0KG5jLCBzZWxlY3QgPSBjKG1hZ2UsbWFyaXRhbCkpICU+JSBuYS5vbWl0KCkNCmRpbShuYykNCmRpbShxMTEpDQpgYGANCg0KcGVyZGkgdW0gY2FzbyBxdWUgZXJhIG1pc3NpbmcsIGRlIGJvYXMgLCBhaW5kYSB0ZW0gOTk5IG5hIGFtb3N0cmEuDQoNCmBgYHtyfQ0Kc3VtbWFyeShxMTEkbWFnZSkNCnN1bW1hcnkocTExJG1hcml0YWwpDQpoaXN0KHExMSRtYWdlKQ0KcGxvdChxMTEkbWFyaXRhbCkNCmBgYA0KDQoNCnByaW1laXJvIHRlc3RlIGRlIGFzc29jaWHDp8OjbyDDqSBvIGJveHBsb3QgKHZpc3VhbCkNCg0KYGBge3J9DQpib3hwbG90KHExMSRtYWdlIH4gcTExJG1hcml0YWwsIGNvbCA9ICJvcmFuZ2UiLCBtYWluPSJpZGFkZSBkYSBtw6NlIGUgY2FzYW1lbnRvIiwgeWxhYj0iaWRhZGUgZGEgbcOjZSIsIHhsYWI9ImVzdGFkbyBjaXZpbCIpDQpgYGANCg0KYXMgbsOjbyBjYXNhZGFzIHBhcmVjZW0gbcOjZXMgbWFpcyB2ZWxoYXMgcXVlIGFzIGNhc2FkYXMuIG5vc3NhIQ0KDQpPcyBib3hwbG90cyBtb3N0cmFtIGNvbW8gYXMgbWVkaWFuYXMgZGFzIGR1YXMgZGlzdHJpYnVpw6fDtWVzIHNlIGNvbXBhcmFtLCBtYXMgdGFtYsOpbSBwb2RlbW9zIGNvbXBhcmFyIGFzIG3DqWRpYXMgZGFzIGRpc3RyaWJ1acOnw7VlcyB1c2FuZG8gbyBzZWd1aW50ZSBwYXJhIHByaW1laXJvIGFncnVwYXIgb3MgZGFkb3MgcGVsYSB2YXJpw6F2ZWwgZGUgbWFyaXRhbCBlLCBlbSBzZWd1aWRhLCBjYWxjdWxhciBhIGlkYWRlIG3DqWRpYSBuZXNzZXMgZ3J1cG9zIHVzYW5kbyBhIGZ1bsOnw6NvIG3DqWRpYS4NCg0KYGBge3J9DQpxMTEgJT4lDQogIGdyb3VwX2J5KG1hcml0YWwpICU+JQ0KICBzdW1tYXJpc2UobWVhbl9tYWdlID0gbWVhbihtYWdlKSkNCmBgYA0KDQphcyBjYXNhZGFzIHRlbSBvIGZpbGhvIGNvbSAyMyBhbm9zIGVtIG3DqWRpYSwgYW8gcGFzc2FkbyBxdWUgYXMgbsOjbyBjYXNhZG9zIHPDo28gbcOjZXMgY29tIGNlcmNhIGRlIDI5IGFub3MuDQoNCg0KSW5mZXJlbmNlDQoNCmBgYHtyfQ0KaW5mZXJlbmNlKHkgPSBtYWdlLCB4ID0gbWFyaXRhbCwgZGF0YSA9IHExMSwgc3RhdGlzdGljID0gIm1lYW4iLCB0eXBlID0gImh0IiwgbnVsbCA9IDAsIA0KICAgICAgICAgIGFsdGVybmF0aXZlID0gInR3b3NpZGVkIiwgbWV0aG9kID0gInRoZW9yZXRpY2FsIikNCmBgYA0KTGV04oCZcyBwYXVzZSBmb3IgYSBtb21lbnQgdG8gZ28gdGhyb3VnaCB0aGUgYXJndW1lbnRzIG9mIHRoaXMgY3VzdG9tIGZ1bmN0aW9uLiBUaGUgZmlyc3QgYXJndW1lbnQgaXMgeSwgd2hpY2ggaXMgdGhlIHJlc3BvbnNlIHZhcmlhYmxlIHRoYXQgd2UgYXJlIGludGVyZXN0ZWQgaW46IHdlaWdodC4gVGhlIHNlY29uZCBhcmd1bWVudCBpcyB0aGUgZXhwbGFuYXRvcnkgdmFyaWFibGUsIHgsIHdoaWNoIGlzIHRoZSB2YXJpYWJsZSB0aGF0IHNwbGl0cyB0aGUgZGF0YSBpbnRvIHR3byBncm91cHMsIHNtb2tlcnMgYW5kIG5vbi1zbW9rZXJzOiBoYWJpdC4gVGhlIHRoaXJkIGFyZ3VtZW50LCBkYXRhLCBpcyB0aGUgZGF0YSBmcmFtZSB0aGVzZSB2YXJpYWJsZXMgYXJlIHN0b3JlZCBpbi4gTmV4dCBpcyBzdGF0aXN0aWMsIHdoaWNoIGlzIHRoZSBzYW1wbGUgc3RhdGlzdGljIHdl4oCZcmUgdXNpbmcsIG9yIHNpbWlsYXJseSwgdGhlIHBvcHVsYXRpb24gcGFyYW1ldGVyIHdl4oCZcmUgZXN0aW1hdGluZy4gSW4gZnV0dXJlIGxhYnMgd2UgY2FuIGFsc28gd29yayB3aXRoIOKAnG1lZGlhbuKAnSBhbmQg4oCccHJvcG9ydGlvbuKAnS4gTmV4dCB3ZSBkZWNpZGUgb24gdGhlIHR5cGUgb2YgaW5mZXJlbmNlIHdlIHdhbnQ6IGEgaHlwb3RoZXNpcyB0ZXN0ICgiaHQiKSBvciBhIGNvbmZpZGVuY2UgaW50ZXJ2YWwgKCJjaSIpLiBXaGVuIHBlcmZvcm1pbmcgYSBoeXBvdGhlc2lzIHRlc3QsIHdlIGFsc28gbmVlZCB0byBzdXBwbHkgdGhlIG51bGwgdmFsdWUsIHdoaWNoIGluIHRoaXMgY2FzZSBpcyAwLCBzaW5jZSB0aGUgbnVsbCBoeXBvdGhlc2lzIHNldHMgdGhlIHR3byBwb3B1bGF0aW9uIG1lYW5zIGVxdWFsIHRvIGVhY2ggb3RoZXIuIFRoZSBhbHRlcm5hdGl2ZSBoeXBvdGhlc2lzIGNhbiBiZSAibGVzcyIsICJncmVhdGVyIiwgb3IgInR3b3NpZGVkIi4gTGFzdGx5LCB0aGUgbWV0aG9kIG9mIGluZmVyZW5jZSBjYW4gYmUgInRoZW9yZXRpY2FsIiBvciAic2ltdWxhdGlvbiIgYmFzZWQuDQoNCkZvciBtb3JlIGluZm9ybWF0aW9uIG9uIHRoZSBpbmZlcmVuY2UgZnVuY3Rpb24gc2VlIHRoZSBoZWxwIGZpbGUgd2l0aCA/aW5mZXJlbmNlLg0KDQpFeGVyY2lzZTogV2hhdCBpcyB0aGUgY29uY2x1c2lvbiBvZiB0aGUgaHlwb3RoZXNpcyB0ZXN0Pw0KDQpSRUpFQ1QgdGhlIE5VTEwgSElQT1RIRVNJUw0KKipwIHZhbHVlIGJvbSoqDQoNCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCg0KY29uc3RpdHVpbmRvIHVtIGludGVydmFsbyBkZSBjb25maWFuw6dhIChzZWd1aW5kbyBjb20gZGFkb3MgZSBpbnRlcmHDp8OjbyBkZSBjaW1hKQ0KDQpgYGB7cn0NCmluZmVyZW5jZSh5ID0gbWFnZSwgeCA9IG1hcml0YWwsIGRhdGEgPSBxMTEsIHN0YXRpc3RpYyA9ICJtZWFuIiwgdHlwZSA9ICJjaSIsIG1ldGhvZCA9ICJ0aGVvcmV0aWNhbCIsIG9yZGVyID0gYygibm90IG1hcnJpZWQiLCJtYXJyaWVkIikpDQpgYGANCg0KDQoNCkNPTkNMVVPDg08gOiBFc3RhbW9zIDk1JSBjb25maWFudGVzIGRlIHF1ZSBtdWxoZXJlcyBuw6NvIGNhc2FkYXMgcXVlIHRlbSBzZXVzIGZpbGhvcyBzw6NvIGVtIG3DqWRpYSA0LDggYSA2LDIgYW5vcyBtYWlzIHZlbGhhcyBxdWUgYXMgY2FzYWRhcy4NCg0KeHh4DQo=