##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
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.
This warning is displayed once every 8 hours.
Call `lifecycle::last_warnings()` to see where this warning was generated.

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%

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=