Ideia central. Regressão múltipla não é uma sequência de botões. É um argumento científico: definimos uma pergunta, explicitamos um modelo, confrontamos suas suposições com os dados, avaliamos incerteza e só então comunicamos o que o modelo permite — e o que ele não permite — concluir.

1 Visão geral da análise

1.1 Preparação do ambiente

Instale os pacotes uma única vez. Depois, abra o arquivo .Rmd no RStudio e use Knit, ou execute rmarkdown::render(). No HTML, os códigos ficam recolhidos: clique em Code para visualizá-los. Para reproduzir ou alterar a análise, execute/renderize o documento inteiro na ordem apresentada, pois cada etapa usa objetos criados nas etapas anteriores.

install.packages(c(
  "rmarkdown", "knitr", "ggplot2", "dplyr", "tidyr", "purrr",
  "broom", "performance", "patchwork", "GGally",
  "kableExtra", "DT"
))

rmarkdown::render("tutorial_regressao_multipla_iris.Rmd")

1.2 Objetivos da análise

Esta análise foi estruturada para:

  1. transformar uma pergunta substantiva em uma equação de regressão;
  2. distinguir variável resposta, preditores numéricos e preditores categóricos;
  3. realizar uma análise exploratória orientada ao modelo;
  4. ajustar e interpretar uma regressão linear múltipla em R;
  5. verificar linearidade, independência, homocedasticidade, normalidade aproximada, multicolinearidade e influência;
  6. comparar cinco modelos usando teste F, \(R^2\) ajustado, AIC, BIC e parcimônia;
  7. interpretar corretamente variáveis categóricas e categorias de referência;
  8. diferenciar intervalo de confiança da média e intervalo de previsão individual;
  9. reconhecer multicolinearidade, extrapolação e linguagem causal indevida;
  10. selecionar um modelo com base no conjunto das evidências e produzir uma conclusão defensável.

1.3 O mapa do processo

Etapa Pergunta que guia a etapa Produto
1. Problema O que queremos explicar ou prever? pergunta, população e unidade de análise
2. Dados As variáveis medem o que precisamos? dicionário, qualidade e exploração
3. Especificação Que relação estamos supondo? fórmula, termos e interações justificadas
4. Ajuste Quais coeficientes melhor reproduzem os dados? modelo estimado e incerteza
5. Comparação preliminar Qual modelo tem melhor ajuste e quais termos acrescentam informação? tabela comparativa, teste F e candidato ao diagnóstico
6. Diagnóstico O candidato respeita os pressupostos de forma razoável? resíduos, influência, VIF e gráficos auxiliares
7. Decisão Qual especificação é mais defensável para cada objetivo? melhor ajuste, alternativa interpretável e justificativa
8. Comunicação O que aprendemos e com quais limites? conclusão, intervalos e próximos passos

2 A pergunta vem antes do modelo

Usaremos Sepal.Length — o comprimento da sépala, em centímetros — como resposta. Queremos investigar e prever essa medida a partir da largura da sépala, das medidas da pétala e da espécie.

Uma pergunta bem formulada seria:

Entre flores semelhantes nas demais características consideradas, como o comprimento esperado da sépala varia com cada preditor, e quão bem o modelo prevê novas flores?

Essa frase já contém duas metas diferentes:

“Melhor modelo” não é uma propriedade absoluta. Um modelo pode ser excelente para previsão e ruim para interpretação; outro pode ser transparente e estável, mas perder um pouco de acurácia. Antes de comparar modelos, declare o objetivo.

2.1 O modelo matemático

Para a observação \(i\), um modelo com três preditores numéricos é

\[ Y_i = \beta_0 + \beta_1 X_{1i} + \beta_2 X_{2i} + \beta_3 X_{3i} + \varepsilon_i, \]

em que:

  • \(Y_i\) é o comprimento observado da sépala;
  • \(\beta_0\) é o valor esperado de \(Y\) quando os preditores valem zero;
  • \(\beta_j\) é a mudança média esperada em \(Y\) para uma unidade adicional de \(X_j\), mantendo os demais preditores constantes;
  • \(\varepsilon_i\) representa tudo o que o modelo não explica.

Quando incluímos Species, o R cria contrastes (as chamadas variáveis indicadoras ou dummies) comparando cada nível com uma categoria de referência.

2.2 Suposições: o que realmente precisamos verificar

Suposição Significado operacional Como verificar O que fazer se falhar
Linearidade a média condicional de \(Y\) é linear nos parâmetros resíduos vs. ajustados; resíduos parciais transformação, polinômio, spline ou interação justificada
Independência erros de unidades distintas não são correlacionados desenho da coleta; ordem/tempo/grupos modelos mistos, séries temporais, erros agrupados
Variância aproximadamente constante dispersão dos erros é semelhante ao longo da média resíduos vs. ajustados; escala-localização transformação, erros robustos, WLS
Normalidade aproximada dos erros necessária principalmente para inferência exata em amostras pequenas QQ-plot; forma dos resíduos bootstrap, erros robustos, investigar modelo/outliers
Ausência de colinearidade prejudicial preditores não carregam quase a mesma informação VIF/GVIF; estabilidade dos coeficientes reformular, combinar, centrar, regularizar, coletar mais dados
Ausência de influência excessiva nenhuma observação domina o ajuste alavancagem e distância de Cook verificar dado, relatar sensibilidade; nunca excluir automaticamente
Especificação adequada termos importantes não foram omitidos teoria, resíduos, interações, validação reespecificar com justificativa substantiva

Cheque conceitual. Normalidade dos preditores não é pressuposto da regressão linear. O foco é a distribuição dos erros condicionais, e nem toda pequena violação invalida o modelo.

3 Conhecendo a base Iris

3.1 Estrutura, unidade e qualidade

dados <- datasets::iris |>
  mutate(
    Species = factor(Species),
    id = row_number()
  )

glimpse(dados)
## Rows: 150
## Columns: 6
## $ Sepal.Length <dbl> 5.1, 4.9, 4.7, 4.6, 5.0, 5.4, 4.6, 5.0, 4.4, 4.9, 5.4, 4.…
## $ Sepal.Width  <dbl> 3.5, 3.0, 3.2, 3.1, 3.6, 3.9, 3.4, 3.4, 2.9, 3.1, 3.7, 3.…
## $ Petal.Length <dbl> 1.4, 1.4, 1.3, 1.5, 1.4, 1.7, 1.4, 1.5, 1.4, 1.5, 1.5, 1.…
## $ Petal.Width  <dbl> 0.2, 0.2, 0.2, 0.2, 0.2, 0.4, 0.3, 0.2, 0.2, 0.1, 0.2, 0.…
## $ Species      <fct> setosa, setosa, setosa, setosa, setosa, setosa, setosa, s…
## $ id           <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17…

Cada linha representa uma flor; cada medida está em centímetros. Há 150 observações, 50 de cada espécie.

dicionario <- tibble::tribble(
  ~variavel, ~tipo, ~papel, ~definicao,
  "Sepal.Length", "numérica", "resposta", "comprimento da sépala (cm)",
  "Sepal.Width", "numérica", "preditor", "largura da sépala (cm)",
  "Petal.Length", "numérica", "preditor", "comprimento da pétala (cm)",
  "Petal.Width", "numérica", "preditor", "largura da pétala (cm)",
  "Species", "categórica", "preditor/estrato", "espécie da flor",
  "id", "inteira", "identificador", "linha original para rastreabilidade"
)

knitr::kable(dicionario, align = c("l", "l", "l", "l")) |>
  kable_styling(full_width = FALSE, bootstrap_options = c("striped", "hover"))
variavel tipo papel definicao
Sepal.Length numérica resposta comprimento da sépala (cm)
Sepal.Width numérica preditor largura da sépala (cm)
Petal.Length numérica preditor comprimento da pétala (cm)
Petal.Width numérica preditor largura da pétala (cm)
Species categórica preditor/estrato espécie da flor
id inteira identificador linha original para rastreabilidade
qualidade <- dados |>
  summarise(
    observacoes = n(),
    duplicatas_exatas = sum(duplicated(across(-id))),
    valores_ausentes = sum(is.na(across(everything()))),
    especies = n_distinct(Species)
  )

qualidade

Há uma duplicata exata nas medidas e espécie. Isso não prova erro: duas flores podem ter medidas idênticas. Sem um identificador original da coleta, não devemos apagar a linha automaticamente. O correto é registrar a ambiguidade e fazer análise de sensibilidade se ela puder afetar o resultado.

3.2 Estatísticas descritivas

descritivas <- dados |>
  select(-id) |>
  pivot_longer(where(is.numeric), names_to = "variavel", values_to = "valor") |>
  group_by(variavel) |>
  summarise(
    n = n(),
    media = mean(valor),
    dp = sd(valor),
    minimo = min(valor),
    q1 = quantile(valor, 0.25),
    mediana = median(valor),
    q3 = quantile(valor, 0.75),
    maximo = max(valor),
    .groups = "drop"
  )

knitr::kable(descritivas, digits = 2) |>
  kable_styling(full_width = FALSE, bootstrap_options = c("striped", "hover"))
variavel n media dp minimo q1 mediana q3 maximo
Petal.Length 150 3.76 1.77 1.0 1.6 4.35 5.1 6.9
Petal.Width 150 1.20 0.76 0.1 0.3 1.30 1.8 2.5
Sepal.Length 150 5.84 0.83 4.3 5.1 5.80 6.4 7.9
Sepal.Width 150 3.06 0.44 2.0 2.8 3.00 3.3 4.4

3.3 Distribuições e grupos

dados_longos <- dados |>
  pivot_longer(
    cols = c(Sepal.Length, Sepal.Width, Petal.Length, Petal.Width),
    names_to = "medida",
    values_to = "valor"
  )

ggplot(dados_longos, aes(Species, valor, color = Species)) +
  geom_boxplot(aes(fill = Species), alpha = 0.12, width = 0.58,
               outlier.shape = NA, linewidth = 0.55) +
  geom_jitter(width = 0.14, alpha = 0.55, size = 1.35) +
  facet_wrap(~ medida, scales = "free_y", ncol = 2) +
  scale_color_manual(values = paleta_especies) +
  scale_fill_manual(values = paleta_especies) +
  labs(
    title = "Medidas morfológicas por espécie",
    subtitle = "150 flores; 50 observações por espécie; valores em centímetros",
    x = NULL, y = "Valor (cm)", color = "Espécie", fill = "Espécie"
  ) +
  guides(fill = "none")
Distribuições das quatro medidas por espécie. Pontos e boxplots tornam a amostra e a dispersão visíveis sem depender apenas das médias.

Distribuições das quatro medidas por espécie. Pontos e boxplots tornam a amostra e a dispersão visíveis sem depender apenas das médias.

Leitura. A espécie separa fortemente as medidas da pétala e também parte do comprimento da sépala. Portanto, uma relação agregada entre pétala e sépala pode misturar dois fenômenos: diferenças entre espécies e variação dentro de cada espécie.

3.4 Relações bivariadas não contam a história completa

GGally::ggpairs(
  dados,
  columns = 1:4,
  mapping = aes(color = Species, alpha = 0.7),
  upper = list(continuous = GGally::wrap("cor", size = 3.4)),
  diag = list(continuous = GGally::wrap("densityDiag", alpha = 0.35))
) +
  scale_color_manual(values = paleta_especies) +
  scale_fill_manual(values = paleta_especies) +
  theme_bw(base_size = 10)
Matriz de pares: distribuições na diagonal, correlações no triângulo superior e dispersões no triângulo inferior.

Matriz de pares: distribuições na diagonal, correlações no triângulo superior e dispersões no triângulo inferior.

matriz_cor <- cor(select(dados, Sepal.Length:Petal.Width))
round(matriz_cor, 3)
##              Sepal.Length Sepal.Width Petal.Length Petal.Width
## Sepal.Length        1.000      -0.118        0.872       0.818
## Sepal.Width        -0.118       1.000       -0.428      -0.366
## Petal.Length        0.872      -0.428        1.000       0.963
## Petal.Width         0.818      -0.366        0.963       1.000

Petal.Length e Petal.Width têm correlação muito alta. Isso sinaliza possível multicolinearidade, mas a decisão não deve ser tomada por um limiar mecânico de correlação. O VIF, a estabilidade dos coeficientes e o objetivo do modelo completam o diagnóstico.

Correção de uma armadilha comum. Dois preditores positivamente correlacionados não precisam ter coeficientes múltiplos com o mesmo sinal. Cada coeficiente é um efeito parcial, condicionado aos demais termos. Uma inversão de sinal pode revelar colinearidade, confundimento ou uma pergunta condicional diferente — não uma contradição lógica automática.

p_agregado <- ggplot(dados, aes(Petal.Length, Sepal.Length)) +
  geom_point(color = azul, alpha = 0.65) +
  geom_smooth(method = "lm", se = TRUE, color = azul_escuro, fill = "#DCE8F7") +
  labs(
    title = "Relação agregada",
    subtitle = "Uma única reta para todas as flores",
    x = "Comprimento da pétala (cm)", y = "Comprimento da sépala (cm)"
  )

p_grupos <- ggplot(dados, aes(Petal.Length, Sepal.Length, color = Species)) +
  geom_point(alpha = 0.72) +
  geom_smooth(method = "lm", se = FALSE, linewidth = 0.9) +
  scale_color_manual(values = paleta_especies) +
  labs(
    title = "Relações por espécie",
    subtitle = "A inclinação pode variar entre grupos",
    x = "Comprimento da pétala (cm)", y = "Comprimento da sépala (cm)",
    color = "Espécie"
  )

p_agregado + p_grupos
A linha agregada mistura diferenças entre espécies e relações dentro de cada espécie.

A linha agregada mistura diferenças entre espécies e relações dentro de cada espécie.

4 Construção progressiva dos cinco modelos

Os cinco modelos serão ajustados com as 150 observações. A ordem foi escolhida para que cada novo ajuste responda a uma dúvida surgida no modelo anterior. A decisão será tomada somente depois que todos tiverem sido estimados, interpretados e comparados.

4.1 Como ler a saída de lm()

  • Estimate: estimativa de cada coeficiente \(\beta_j\);
  • Std. Error: erro-padrão, que mede a incerteza da estimativa;
  • t value e p-valor: teste de \(H_0: \beta_j=0\), condicionado aos demais termos do modelo;
  • Residual standard error: escala típica dos resíduos, em centímetros;
  • Multiple \(R^2\): proporção da variabilidade observada explicada pelo ajuste;
  • Adjusted \(R^2\): versão do \(R^2\) que considera o número de parâmetros;
  • F-statistic: teste global do modelo contra um ajuste somente com intercepto.

O coeficiente estimado e seu erro-padrão cumprem papéis diferentes. A estimativa indica o tamanho e o sentido da associação; o erro-padrão indica a precisão dessa estimativa. Em termos simples, ele resume quanto a estimativa tenderia a variar se repetíssemos a coleta e o ajuste muitas vezes sob condições semelhantes. O valor de \(t\) é calculado por \(t=\widehat\beta/EP(\widehat\beta)\): para um mesmo coeficiente, maior erro-padrão implica menor precisão e menor evidência contra \(H_0:\beta=0\).

4.2 Modelo 1 — todas as medidas numéricas

O primeiro ajuste utiliza as três medidas disponíveis como preditoras e ainda não inclui a espécie:

\[ Y_i=\beta_0+\beta_1\,Sepal.Width_i+\beta_2\,Petal.Length_i+ \beta_3\,Petal.Width_i+\varepsilon_i. \]

modelo1 <- lm(
  Sepal.Length ~ Sepal.Width + Petal.Length + Petal.Width,
  data = dados
)

summary(modelo1)
## 
## Call:
## lm(formula = Sepal.Length ~ Sepal.Width + Petal.Length + Petal.Width, 
##     data = dados)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -0.8282 -0.2199  0.0187  0.1971  0.8457 
## 
## Coefficients:
##              Estimate Std. Error t value             Pr(>|t|)    
## (Intercept)    1.8560     0.2508    7.40      0.0000000000099 ***
## Sepal.Width    0.6508     0.0666    9.77 < 0.0000000000000002 ***
## Petal.Length   0.7091     0.0567   12.50 < 0.0000000000000002 ***
## Petal.Width   -0.5565     0.1275   -4.36      0.0000241287569 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.315 on 146 degrees of freedom
## Multiple R-squared:  0.859,  Adjusted R-squared:  0.856 
## F-statistic:  296 on 3 and 146 DF,  p-value: <0.0000000000000002
tabela_coeficientes(modelo1) |>
  knitr::kable(digits = 3) |>
  kable_styling(full_width = FALSE, bootstrap_options = c("striped", "hover"))
termo estimativa erro-padrão estatistica_t p-valor IC 95% inferior IC 95% superior
(Intercept) 1.856 0.251 7.401 0 1.360 2.352
Sepal.Width 0.651 0.067 9.765 0 0.519 0.783
Petal.Length 0.709 0.057 12.502 0 0.597 0.821
Petal.Width -0.556 0.128 -4.363 0 -0.809 -0.304

A equação ajustada é:

\[ \widehat{Sepal.Length}= 1,856 + 0,651\,Sepal.Width + 0,709\,Petal.Length - 0,556\,Petal.Width. \]

4.2.1 Comentários e observações sobre o Modelo 1

O modelo é globalmente significativo e apresenta \(R^2\) ajustado igual a 0,856, ou aproximadamente 85,6% da variabilidade explicada após a correção pelo número de parâmetros. Todas as variáveis têm p-valor inferior a 0,05.

Vamos isolar os erros-padrão dos três preditores para tornar a comparação explícita:

comparacao_ep_modelo1 <- tidy(modelo1) |>
  filter(term != "(Intercept)") |>
  transmute(
    variavel = term,
    estimativa = estimate,
    `erro-padrão` = std.error,
    `EP / |estimativa| (%)` = 100 * std.error / abs(estimate),
    `EP em relação ao menor EP` = std.error / min(std.error)
  )

comparacao_ep_modelo1 |>
  knitr::kable(digits = 3) |>
  kable_styling(full_width = FALSE, bootstrap_options = c("striped", "hover"))
variavel estimativa erro-padrão EP / &#124;estimativa&#124; (%) EP em relação ao menor EP
Sepal.Width 0.651 0.067 10.240 1.175
Petal.Length 0.709 0.057 7.998 1.000
Petal.Width -0.556 0.128 22.920 2.249

Dois resultados da própria saída do Modelo 1 merecem atenção:

  1. o erro-padrão de Petal.Width é 0,128, contra 0,067 para Sepal.Width e 0,057 para Petal.Length. Portanto, ele é aproximadamente 1,91 vez o erro-padrão de Sepal.Width e 2,25 vezes o de Petal.Length;
  2. Petal.Length apresenta coeficiente positivo (0,709), enquanto Petal.Width apresenta coeficiente negativo (-0,556), apesar da forte correlação positiva entre ambas.

Como todos os três preditores estão medidos em centímetros, a comparação direta dos erros-padrão é informativa neste exemplo. Mesmo assim, um erro-padrão maior não deve ser interpretado isoladamente: ele também depende da dispersão da variável, do tamanho da amostra e da relação desse preditor com os demais. A coluna percentual da tabela fornece uma segunda referência, comparando o erro-padrão com o tamanho absoluto da respectiva estimativa.

Essa inversão de sinal não é uma contradição matemática: na regressão múltipla, cada coeficiente representa uma associação parcial, mantendo os demais preditores constantes. Contudo, combinada com a correlação de aproximadamente 0,963, ela sugere que as duas medidas da pétala competem para explicar a mesma parcela da resposta. Para quantificar esse problema, calculamos o VIF.

4.2.2 O que é VIF?

VIF significa Variance Inflation Factor, ou fator de inflação da variância. Para o preditor \(X_j\),

\[ VIF_j=\frac{1}{1-R_j^2}, \]

em que \(R_j^2\) vem de uma regressão auxiliar de \(X_j\) contra todos os outros preditores. Se os demais preditores quase conseguem reconstruir \(X_j\), esse \(R_j^2\) fica próximo de 1 e o VIF cresce.

O VIF informa por quanto a variância estimada de \(\widehat\beta_j\) foi inflada pela relação linear entre os preditores. A raiz quadrada do VIF informa aproximadamente por quanto o erro-padrão foi inflado em comparação com uma situação ideal de preditores não correlacionados. A tolerância é \(1/VIF\); valores pequenos significam que resta pouca informação exclusiva naquele preditor.

vif_modelo1 <- performance::check_collinearity(modelo1) |>
  as.data.frame() |>
  transmute(
    variavel = Term,
    VIF = VIF,
    `raiz do VIF` = sqrt(VIF),
    tolerancia = Tolerance,
    R2_regressao_auxiliar = 1 - 1 / VIF
  )

vif_modelo1 |>
  rename(`R² da regressão auxiliar` = R2_regressao_auxiliar) |>
  knitr::kable(digits = 3) |>
  kable_styling(full_width = FALSE, bootstrap_options = c("striped", "hover"))
variavel VIF raiz do VIF tolerancia R² da regressão auxiliar
Sepal.Width 1.271 1.127 0.787 0.213
Petal.Length 15.098 3.886 0.066 0.934
Petal.Width 14.234 3.773 0.070 0.930

Para Sepal.Width, o VIF é baixo (1,27). Para Petal.Length e Petal.Width, os VIF são 15,10 e 14,23. Isso significa que aproximadamente 93,4% da variação de Petal.Length e 93,0% da variação de Petal.Width podem ser explicadas pelos outros preditores do modelo. As raízes dos VIF, próximas de 3,89 e 3,77, evidenciam uma inflação importante da incerteza dos coeficientes.

Regras como “VIF maior que 5 exige atenção” e “VIF maior que 10 indica colinearidade forte” são referências práticas, não leis universais. Aqui, valores acima de 14, correlação de 0,963 e mudança de sinal contam uma história coerente: os efeitos individuais das duas medidas da pétala são difíceis de separar com estabilidade.

Leitura correta da multicolinearidade. O modelo ainda pode ajustar bem os dados. O principal prejuízo está na separação e interpretação dos efeitos individuais, nos erros-padrão e na estabilidade dos coeficientes.

4.3 Modelo 2 — retirada de Petal.Width

Como Petal.Length apresenta associação mais forte com a resposta e as duas medidas da pétala são muito correlacionadas, o segundo modelo retira Petal.Width:

\[ Y_i=\beta_0+\beta_1\,Sepal.Width_i+\beta_2\,Petal.Length_i+\varepsilon_i. \]

modelo2 <- lm(
  Sepal.Length ~ Sepal.Width + Petal.Length,
  data = dados
)

summary(modelo2)
## 
## Call:
## lm(formula = Sepal.Length ~ Sepal.Width + Petal.Length, data = dados)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -0.9616 -0.2349  0.0008  0.2145  0.7856 
## 
## Coefficients:
##              Estimate Std. Error t value             Pr(>|t|)    
## (Intercept)    2.2491     0.2480    9.07   0.0000000000000007 ***
## Sepal.Width    0.5955     0.0693    8.59   0.0000000000000116 ***
## Petal.Length   0.4719     0.0171   27.57 < 0.0000000000000002 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.333 on 147 degrees of freedom
## Multiple R-squared:  0.84,   Adjusted R-squared:  0.838 
## F-statistic:  386 on 2 and 147 DF,  p-value: <0.0000000000000002
tabela_coeficientes(modelo2) |>
  knitr::kable(digits = 3) |>
  kable_styling(full_width = FALSE, bootstrap_options = c("striped", "hover"))
termo estimativa erro-padrão estatistica_t p-valor IC 95% inferior IC 95% superior
(Intercept) 2.249 0.248 9.07 0 1.759 2.739
Sepal.Width 0.596 0.069 8.59 0 0.459 0.733
Petal.Length 0.472 0.017 27.57 0 0.438 0.506

A equação ajustada é:

\[ \widehat{Sepal.Length}= 2,249 + 0,596\,Sepal.Width + 0,472\,Petal.Length. \]

4.3.1 Comentários e interpretação do Modelo 2

O modelo permanece globalmente significativo e explica aproximadamente 83,8% da variabilidade do comprimento da sépala, segundo o \(R^2\) ajustado.

  • Mantendo o comprimento da pétala constante, o aumento de 1 cm em Sepal.Width está associado a um aumento médio estimado de 0,596 cm em Sepal.Length.
  • Mantendo a largura da sépala constante, o aumento de 1 cm em Petal.Length está associado a um aumento médio estimado de 0,472 cm em Sepal.Length.

As duas associações são positivas, estatisticamente significativas e simples de comunicar. A retirada de Petal.Width reduz a colinearidade e custa cerca de 1,8 ponto percentual de \(R^2\) ajustado em relação ao Modelo 1.

4.4 Modelo 3 — retirada de Petal.Length

Para avaliar a alternativa oposta, retiramos Petal.Length e mantemos Petal.Width:

\[ Y_i=\beta_0+\beta_1\,Sepal.Width_i+\beta_2\,Petal.Width_i+\varepsilon_i. \]

modelo3 <- lm(
  Sepal.Length ~ Sepal.Width + Petal.Width,
  data = dados
)

summary(modelo3)
## 
## Call:
## lm(formula = Sepal.Length ~ Sepal.Width + Petal.Width, data = dados)
## 
## Residuals:
##    Min     1Q Median     3Q    Max 
## -1.208 -0.229 -0.045  0.227  1.181 
## 
## Coefficients:
##             Estimate Std. Error t value             Pr(>|t|)    
## (Intercept)   3.4573     0.3092   11.18 < 0.0000000000000002 ***
## Sepal.Width   0.3991     0.0911    4.38             0.000022 ***
## Petal.Width   0.9721     0.0521   18.66 < 0.0000000000000002 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.451 on 147 degrees of freedom
## Multiple R-squared:  0.707,  Adjusted R-squared:  0.703 
## F-statistic:  178 on 2 and 147 DF,  p-value: <0.0000000000000002
tabela_coeficientes(modelo3) |>
  knitr::kable(digits = 3) |>
  kable_styling(full_width = FALSE, bootstrap_options = c("striped", "hover"))
termo estimativa erro-padrão estatistica_t p-valor IC 95% inferior IC 95% superior
(Intercept) 3.457 0.309 11.18 0 2.846 4.068
Sepal.Width 0.399 0.091 4.38 0 0.219 0.579
Petal.Width 0.972 0.052 18.66 0 0.869 1.075

A equação ajustada é:

\[ \widehat{Sepal.Length}= 3,457 + 0,399\,Sepal.Width + 0,972\,Petal.Width. \]

4.4.1 Comentários e interpretação do Modelo 3

As duas variáveis também são significativas, mas o \(R^2\) ajustado cai para 0,703. Mantendo Petal.Width constante, o aumento de 1 cm em Sepal.Width está associado a 0,399 cm adicionais no comprimento médio da sépala. Mantendo Sepal.Width constante, 1 cm adicional em Petal.Width está associado a 0,972 cm adicionais na resposta.

O ajuste inferior ao do Modelo 2 é coerente com a exploração: Petal.Width tem correlação total um pouco menor com Sepal.Length que Petal.Length. Entre os dois modelos que eliminam uma das medidas colineares, o Modelo 2 preserva mais informação.

4.5 Preparação para os Modelos 4 e 5 — variável Species

A espécie possui três categorias. O R usa setosa como referência e cria duas variáveis indicadoras:

Espécie \(Z_1\): versicolor \(Z_2\): virginica
setosa 0 0
versicolor 1 0
virginica 0 1
levels(dados$Species)
## [1] "setosa"     "versicolor" "virginica"
contrasts(dados$Species)
##            versicolor virginica
## setosa              0         0
## versicolor          1         0
## virginica           0         1
amostra_dummies <- dados[c(1, 51, 101), ] |>
  bind_cols(
    as.data.frame(model.matrix(~ Species, data = dados[c(1, 51, 101), ])[, -1])
  )

amostra_dummies |>
  select(id, Species, Speciesversicolor, Speciesvirginica) |>
  knitr::kable() |>
  kable_styling(full_width = FALSE, bootstrap_options = c("striped", "hover"))
id Species Speciesversicolor Speciesvirginica
1 1 setosa 0 0
51 51 versicolor 1 0
101 101 virginica 0 1

Assim, dois coeficientes bastam para representar três categorias sem criar dependência linear perfeita com o intercepto.

4.6 Modelo 4 — medidas selecionadas e espécie

O quarto modelo acrescenta Species ao Modelo 2:

\[ Y_i=\beta_0+\beta_1\,Sepal.Width_i+\beta_2\,Petal.Length_i+ \beta_3 Z_{1i}+\beta_4 Z_{2i}+\varepsilon_i. \]

modelo4 <- lm(
  Sepal.Length ~ Sepal.Width + Petal.Length + Species,
  data = dados
)

summary(modelo4)
## 
## Call:
## lm(formula = Sepal.Length ~ Sepal.Width + Petal.Length + Species, 
##     data = dados)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -0.8216 -0.2053  0.0064  0.2265  0.7500 
## 
## Coefficients:
##                   Estimate Std. Error t value             Pr(>|t|)    
## (Intercept)         2.3904     0.2623    9.11  0.00000000000000059 ***
## Sepal.Width         0.4322     0.0814    5.31  0.00000040259819018 ***
## Petal.Length        0.7756     0.0642   12.07 < 0.0000000000000002 ***
## Speciesversicolor  -0.9558     0.2152   -4.44  0.00001759998870080 ***
## Speciesvirginica   -1.3941     0.2857   -4.88  0.00000275961767052 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.31 on 145 degrees of freedom
## Multiple R-squared:  0.863,  Adjusted R-squared:  0.86 
## F-statistic:  229 on 4 and 145 DF,  p-value: <0.0000000000000002
tabela_coeficientes(modelo4) |>
  knitr::kable(digits = 3) |>
  kable_styling(full_width = FALSE, bootstrap_options = c("striped", "hover"))
termo estimativa erro-padrão estatistica_t p-valor IC 95% inferior IC 95% superior
(Intercept) 2.390 0.262 9.114 0 1.872 2.909
Sepal.Width 0.432 0.081 5.310 0 0.271 0.593
Petal.Length 0.776 0.064 12.073 0 0.649 0.903
Speciesversicolor -0.956 0.215 -4.442 0 -1.381 -0.530
Speciesvirginica -1.394 0.286 -4.880 0 -1.959 -0.830

Com setosa como referência, a equação ajustada é:

\[ \widehat{Sepal.Length}= 2,390 + 0,432\,Sepal.Width + 0,776\,Petal.Length - 0,956\,Z_1 - 1,394\,Z_2. \]

4.6.1 Comentários e observações sobre o Modelo 4

O Modelo 4 apresenta o maior \(R^2\) ajustado entre os cinco ajustes (0,860) e todos os termos são significativos. Entretanto, os coeficientes de versicolor e virginica ficam negativos em relação a setosa, o que parece estranho diante dos gráficos, nos quais essas espécies têm sépalas maiores.

Para compreender esse resultado, observe que Species e Petal.Length estão fortemente associados. Os coeficientes de espécie no Modelo 4 não comparam as médias brutas das espécies; eles comparam flores de espécies diferentes que possuam os mesmos valores de Sepal.Width e Petal.Length. Como há pouca sobreposição de Petal.Length entre setosa e as outras espécies, essa interpretação condicional é frágil e próxima de uma extrapolação.

vif_modelo4 <- performance::check_collinearity(modelo4) |>
  as.data.frame() |>
  transmute(
    variavel = Term,
    `VIF/GVIF bruto` = VIF,
    `graus de liberdade` = ifelse(Term == "Species", nlevels(dados$Species) - 1, 1),
    `fator comparável de inflação do EP` = VIF^(1 / (2 * `graus de liberdade`)),
    tolerancia = Tolerance
  )

vif_modelo4 |>
  knitr::kable(digits = 3) |>
  kable_styling(full_width = FALSE, bootstrap_options = c("striped", "hover"))
variavel VIF/GVIF bruto graus de liberdade fator comparável de inflação do EP tolerancia
Sepal.Width 1.947 1 1.395 0.514
Petal.Length 19.899 1 4.461 0.050
Species 27.112 2 2.282 0.037

Para Petal.Length, o VIF é 19,90 e o fator de inflação do erro-padrão é 4,46. Para Species, que possui dois graus de liberdade, o valor bruto é um GVIF de 27,11; para compará-lo com variáveis de um grau de liberdade, usamos o fator ajustado GVIF^(1/(2×gl)), igual a 2,28. Portanto, o Modelo 4 oferece melhor ajuste interno, mas seus coeficientes condicionais — sobretudo os contrastes de espécie, apoiados por pouca sobreposição de Petal.Length — exigem cautela e não devem ser tratados como efeitos estáveis ou causais.

4.7 Modelo 5 — largura da sépala e espécie

Para obter contrastes de espécie mais diretamente compatíveis com a exploração gráfica, retiramos Petal.Length:

\[ Y_i=\beta_0+\beta_1\,Sepal.Width_i+\beta_2 Z_{1i}+\beta_3 Z_{2i}+\varepsilon_i. \]

modelo5 <- lm(
  Sepal.Length ~ Sepal.Width + Species,
  data = dados
)

summary(modelo5)
## 
## Call:
## lm(formula = Sepal.Length ~ Sepal.Width + Species, data = dados)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -1.3071 -0.2571 -0.0533  0.1954  1.4125 
## 
## Coefficients:
##                   Estimate Std. Error t value             Pr(>|t|)    
## (Intercept)          2.251      0.370    6.09      0.0000000095681 ***
## Sepal.Width          0.804      0.106    7.56      0.0000000000042 ***
## Speciesversicolor    1.459      0.112   13.01 < 0.0000000000000002 ***
## Speciesvirginica     1.947      0.100   19.47 < 0.0000000000000002 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.438 on 146 degrees of freedom
## Multiple R-squared:  0.726,  Adjusted R-squared:  0.72 
## F-statistic:  129 on 3 and 146 DF,  p-value: <0.0000000000000002
tabela_coeficientes(modelo5) |>
  knitr::kable(digits = 3) |>
  kable_styling(full_width = FALSE, bootstrap_options = c("striped", "hover"))
termo estimativa erro-padrão estatistica_t p-valor IC 95% inferior IC 95% superior
(Intercept) 2.251 0.370 6.089 0 1.521 2.982
Sepal.Width 0.804 0.106 7.557 0 0.593 1.014
Speciesversicolor 1.459 0.112 13.012 0 1.237 1.680
Speciesvirginica 1.947 0.100 19.465 0 1.749 2.144

Com setosa como referência, a equação ajustada é:

\[ \widehat{Sepal.Length}= 2,251 + 0,804\,Sepal.Width + 1,459\,Z_1 + 1,947\,Z_2. \]

4.7.1 Comentários e interpretação do Modelo 5

Agora os coeficientes de espécie acompanham as diferenças observadas nos gráficos:

  • controlando Sepal.Width, flores versicolor apresentam comprimento médio de sépala 1,459 cm maior que flores setosa;
  • controlando Sepal.Width, flores virginica apresentam comprimento médio de sépala 1,947 cm maior que flores setosa.

As interpretações são mais intuitivas, mas o \(R^2\) ajustado cai para 0,720, bem abaixo do Modelo 2. Portanto, retirar Petal.Length melhora a leitura dos contrastes de espécie, porém elimina uma variável quantitativa muito informativa.

4.8 Alterando a categoria de referência

Mudar a referência altera a forma dos coeficientes, mas não altera resíduos, valores ajustados, \(R^2\), AIC ou BIC.

dados_ref_virginica <- dados |>
  mutate(Species = relevel(Species, ref = "virginica"))

modelo5_ref_virginica <- lm(
  Sepal.Length ~ Sepal.Width + Species,
  data = dados_ref_virginica
)

tabela_coeficientes(modelo5_ref_virginica) |>
  knitr::kable(digits = 3) |>
  kable_styling(full_width = FALSE, bootstrap_options = c("striped", "hover"))
termo estimativa erro-padrão estatistica_t p-valor IC 95% inferior IC 95% superior
(Intercept) 4.198 0.322 13.027 0 3.561 4.835
Sepal.Width 0.804 0.106 7.557 0 0.593 1.014
Speciessetosa -1.947 0.100 -19.465 0 -2.144 -1.749
Speciesversicolor -0.488 0.090 -5.409 0 -0.666 -0.310

Com virginica como referência, os coeficientes negativos de setosa e versicolor expressam quanto essas espécies têm sépalas menores, em média condicional, do que virginica. O exemplo mostra que mudar a referência muda as comparações expressas pelos coeficientes, mas não muda o ajuste do modelo.

4.9 Seleção do modelo

Antes de examinar resíduos ou fazer previsões, comparamos os modelos e identificamos um candidato de melhor ajuste. A tabela abaixo reúne os cinco ajustes. Valores maiores de \(R^2\) ajustado e menores de RQME residual, AIC e BIC são preferíveis.

  • \(R^2\) ajustado: parcela da variação explicada, com penalização pelo número de parâmetros;
  • RQME residual: tamanho típico do erro de ajuste, em centímetros;
  • AIC e BIC: critérios que equilibram ajuste e complexidade; valores menores são preferíveis, e o BIC penaliza mais modelos complexos.
comparacao_ajuste <- imap_dfr(modelos, function(ajuste, nome) {
  g <- glance(ajuste)
  tibble(
    modelo = nome,
    parametros = length(coef(ajuste)),
    R2 = g$r.squared,
    R2_ajustado = g$adj.r.squared,
    RQME_residual = sqrt(mean(residuals(ajuste)^2)),
    AIC = AIC(ajuste),
    BIC = BIC(ajuste)
  )
})

knitr::kable(comparacao_ajuste, digits = 3) |>
  kable_styling(full_width = FALSE, bootstrap_options = c("striped", "hover"))
modelo parametros R2 R2_ajustado RQME_residual AIC BIC
Modelo 1 — todas as medidas 4 0.859 0.856 0.310 84.64 99.70
Modelo 2 — sem Petal.Width 3 0.840 0.838 0.330 101.03 113.07
Modelo 3 — sem Petal.Length 3 0.707 0.703 0.447 191.82 203.86
Modelo 4 — medidas + espécie 5 0.863 0.860 0.305 81.58 99.64
Modelo 5 — largura + espécie 4 0.726 0.720 0.432 183.94 198.99

O Modelo 4 lidera os critérios de ajuste interno entre os cinco modelos. O Modelo 1 fica próximo em ajuste, mas mantém a multicolinearidade entre as duas medidas da pétala. O Modelo 2 é mais simples, mas perde ajuste; os Modelos 3 e 5 perdem informação importante ao excluir Petal.Length.

Como complemento, os testes F abaixo verificam se um termo específico acrescenta informação quando comparamos modelos aninhados. Cada comparação é apresentada separadamente para que fique claro qual variável está sendo avaliada.

4.9.1 Comparação 1 — Modelo 2 versus Modelo 1: contribuição de Petal.Width

O Modelo 1 contém Sepal.Width, Petal.Length e Petal.Width; o Modelo 2 retira apenas Petal.Width. Este teste verifica se essa variável acrescenta ajuste depois de considerar as outras duas medidas.

anova(modelo2, modelo1)

4.9.2 Comparação 2 — Modelo 3 versus Modelo 1: contribuição de Petal.Length

O Modelo 3 retira Petal.Length do Modelo 1. Assim, o teste avalia a contribuição dessa medida quando Sepal.Width e Petal.Width já estão no modelo.

anova(modelo3, modelo1)

4.9.3 Comparação 3 — Modelo 2 versus Modelo 4: contribuição conjunta de Species

O Modelo 4 acrescenta Species ao Modelo 2. Este é o teste que verifica diretamente se representar as diferenças entre espécies melhora o ajuste.

teste_m2_m4 <- anova(modelo2, modelo4)
teste_m2_m4

4.9.4 Comparação 4 — Modelo 5 versus Modelo 4: contribuição de Petal.Length na presença de Species

O Modelo 5 retira Petal.Length do Modelo 4. O teste mostra se essa medida continua trazendo informação mesmo depois de controlar a espécie.

anova(modelo5, modelo4)

A tabela identifica o candidato de melhor ajuste interno; os testes F verificam se ganhos específicos são compatíveis com os dados. Em especial, o teste anova(modelo2, modelo4) avalia diretamente a passagem do Modelo 2 para o Modelo 4: a inclusão conjunta de Species melhora significativamente o ajuste (p-valor 0,000012). O teste F responde a uma pergunta pontual — “este termo melhora este modelo reduzido?” — e só pode ser usado para modelos aninhados. AIC, BIC e \(R^2\) ajustado comparam o equilíbrio geral entre ajuste e complexidade.

Candidato de melhor ajuste interno: Modelo 4 — Sepal.Length ~ Sepal.Width + Petal.Length + Species. Ele apresenta o maior \(R^2\) ajustado (0,860), o menor RQME residual (0,305), o menor AIC (81,57) e o menor BIC (99,64) entre os cinco ajustes. Como a colinearidade é forte, a decisão final depende também do diagnóstico e do objetivo: ajuste interno ou interpretação mais estável. Esta comparação não demonstra desempenho em novas flores; isso exigiria uma base de teste.

5 Diagnóstico completo dos resíduos

O Modelo 4, candidato de melhor ajuste na tabela anterior, será usado para a análise detalhada dos pressupostos. O diagnóstico verificará se sua forma linear é compatível com os dados antes da decisão final.

modelo_diagnostico <- modelo4

diag <- augment(modelo_diagnostico, data = dados) |>
  mutate(
    indice = row_number(),
    cook_limite = 4 / nrow(dados),
    leverage_limite = 2 * length(coef(modelo_diagnostico)) / nrow(dados)
  )

5.1 O que verificaremos antes dos gráficos

O diagnóstico não procura um “gráfico perfeito”; ele verifica se há indícios fortes de que o modelo linear escolhido é inadequado. Antes de olhar a figura, estabeleça as perguntas de cada painel:

  • Linearidade: os resíduos oscilam sem curvatura em torno de zero?
  • Homocedasticidade: a dispersão dos resíduos se mantém semelhante ao longo dos valores ajustados?
  • Normalidade aproximada: a distribuição dos resíduos é compatível com uma normal, especialmente nas caudas?
  • Alavancagem e influência: existe alguma flor com combinação incomum de preditores e capacidade de alterar substancialmente o ajuste?

Essas verificações se complementam. Um único ponto fora de um limite não invalida o modelo; o interesse está em padrões persistentes e em sua relevância para a pergunta da análise.

5.2 Quatro gráficos fundamentais

p1 <- ggplot(diag, aes(.fitted, .resid)) +
  geom_hline(yintercept = 0, color = cinza, linetype = 2) +
  geom_point(color = azul, alpha = 0.7) +
  geom_smooth(se = FALSE, method = "loess", color = rosa, linewidth = 0.85) +
  labs(title = "Resíduos × ajustados", subtitle = "Procure curvatura e formato de funil",
       x = "Valor ajustado", y = "Resíduo")

set.seed(20260715)
n_diag <- nrow(diag)
quantis_teoricos <- qnorm(ppoints(n_diag))
simulacoes_normais <- replicate(2000, sort(rnorm(n_diag)))
envelope_qq <- tibble(
  quantil_teorico = quantis_teoricos,
  residuo_observado = sort(diag$.std.resid),
  limite_inferior = apply(simulacoes_normais, 1, quantile, probs = 0.025),
  limite_superior = apply(simulacoes_normais, 1, quantile, probs = 0.975)
)

p2 <- ggplot(envelope_qq, aes(quantil_teorico, residuo_observado)) +
  geom_ribbon(
    aes(ymin = limite_inferior, ymax = limite_superior),
    fill = dourado, alpha = 0.22
  ) +
  geom_abline(intercept = 0, slope = 1, color = rosa, linewidth = 0.85) +
  geom_point(color = azul, alpha = 0.72) +
  labs(title = "QQ-plot com envelope de 95%", subtitle = "Pontos fora da faixa sugerem desvio de normalidade",
       x = "Quantis teóricos", y = "Resíduo padronizado")

p3 <- ggplot(diag, aes(.fitted, sqrt(abs(.std.resid)))) +
  geom_point(color = azul, alpha = 0.7) +
  geom_smooth(se = FALSE, method = "loess", color = rosa, linewidth = 0.85) +
  labs(title = "Escala–localização", subtitle = "Uma faixa aproximadamente horizontal é desejável",
       x = "Valor ajustado", y = expression(sqrt("|resíduo padronizado|")))

p4 <- ggplot(diag, aes(.hat, .std.resid, size = .cooksd)) +
  geom_hline(yintercept = c(-2, 2), color = cinza, linetype = 2) +
  geom_vline(xintercept = unique(diag$leverage_limite), color = dourado, linetype = 2) +
  geom_point(color = azul, alpha = 0.62) +
  scale_size_continuous(range = c(1.2, 6), guide = "none") +
  labs(title = "Alavancagem e influência", subtitle = "Linha laranja: alavancagem alta; tamanho: distância de Cook",
       x = "Alavancagem", y = "Resíduo padronizado")

(p1 + p2) / (p3 + p4)
Diagnóstico do Modelo 4 com as 150 observações. Linhas de referência servem como guias, não como decisões mecânicas.

Diagnóstico do Modelo 4 com as 150 observações. Linhas de referência servem como guias, não como decisões mecânicas.

5.2.1 Linearidade

O primeiro gráfico coloca no eixo horizontal os valores previstos pelo modelo e, no eixo vertical, os resíduos \(e_i=y_i-\widehat y_i\). Um resíduo positivo indica que o modelo subestimou o comprimento da sépala; um resíduo negativo indica que o modelo superestimou.

O gráfico responde principalmente à pergunta: a forma linear escolhida consegue representar a média da resposta? O comportamento desejável é uma nuvem distribuída aleatoriamente ao redor de zero, com a linha suavizada aproximadamente horizontal. Uma forma em U ou U invertido sugeriria curvatura não representada; ondas poderiam indicar termos omitidos; grupos separados poderiam revelar que alguma estrutura categórica ainda não foi modelada.

No Modelo 4, a linha suavizada permanece próxima de zero e não aparece uma curvatura persistente. Há resíduos positivos e negativos ao longo de toda a faixa de valores ajustados. Portanto, o gráfico não mostra evidência visual forte de que a média precise de um termo não linear. Isso é compatível com linearidade, mas não constitui uma prova definitiva.

5.2.2 Homocedasticidade

O terceiro gráfico, escala–localização, retira o sinal dos resíduos padronizados e destaca seu tamanho. Ele responde à pergunta: a dispersão dos erros permanece aproximadamente constante para valores previstos pequenos e grandes? Uma faixa de largura semelhante e uma linha suavizada horizontal são desejáveis. Um funil que se abre indicaria variância crescente; um funil que se fecha indicaria variância decrescente.

No Modelo 4, não se observa um funil forte, e a linha suavizada varia pouco ao longo do eixo horizontal. O gráfico de resíduos × ajustados conduz à mesma conclusão visual: a amplitude vertical não aumenta sistematicamente com o valor previsto. Assim, a inspeção gráfica não sugere heterocedasticidade importante.

5.2.3 Normalidade aproximada

O QQ-plot compara os quantis dos resíduos padronizados com os quantis esperados de uma distribuição normal. A faixa dourada é um envelope simulado heurístico de 95%: ela mostra a variação esperada de uma amostra normal independente do mesmo tamanho. Resíduos padronizados de uma regressão não são observações independentes perfeitas; por isso, o envelope é apenas uma referência visual. Pontos sistematicamente fora da faixa, sobretudo nas caudas, sugerem desvio de normalidade; poucos pontos isolados podem ocorrer ao acaso.

No Modelo 4, os pontos acompanham bem a reta, inclusive nas caudas, sem uma forma sistemática de S. O QQ-plot avalia a distribuição dos resíduos, e não exige que Sepal.Length ou os preditores sejam normalmente distribuídos. Essa normalidade é especialmente relevante para a qualidade dos testes, p-valores e intervalos de confiança em amostras pequenas. O envelope não avalia alavancagem ou influência: uma observação pode estar dentro do envelope de normalidade e, ainda assim, ter alavancagem alta.

teste_shapiro <- shapiro.test(residuals(modelo_diagnostico))
tibble(
  teste = "Shapiro–Wilk",
  W = unname(teste_shapiro$statistic),
  `p-valor` = teste_shapiro$p.value
) |>
  mutate(across(where(is.numeric), ~ round(.x, 4)))

O teste de Shapiro–Wilk apresentou p-valor 0,9048. Como esse valor é maior que 0,05, não rejeitamos a hipótese de normalidade. O teste e o QQ-plot apontam na mesma direção. Ainda assim, com amostras grandes, testes podem detectar desvios irrelevantes; com amostras pequenas, podem ter baixa potência. Por isso, o gráfico e o teste devem ser lidos em conjunto.

5.2.4 Alavancagem e influência

O quarto gráfico combina três informações. A alavancagem, no eixo horizontal, mede quão incomum é a combinação de preditores de uma flor. A linha laranja é apenas um limite de triagem para alavancagem alta; ultrapassá-la significa que a flor está em uma região pouco comum dos preditores, e não que ela seja uma observação errada ou que deva ser removida. O resíduo padronizado, no eixo vertical, mede quão distante sua resposta ficou do valor previsto. O tamanho do ponto representa a distância de Cook, que resume quanto o ajuste completo pode mudar quando aquela observação é retirada.

Uma observação com alavancagem alta não é automaticamente problemática: ela pode seguir perfeitamente a tendência. Uma observação com resíduo grande também pode ter pouca influência se estiver em uma região muito povoada dos preditores. A maior preocupação ocorre quando alavancagem alta e resíduo grande aparecem juntos, produzindo distância de Cook elevada.

Usando apenas referências de triagem, 7 observações ultrapassam $2p/n=0,067 e 7 ultrapassam $4/n=0,027 para a distância de Cook. A maior distância de Cook é 0,067, muito abaixo da referência ampla de 1. Isso sugere pontos que merecem inspeção, mas não uma observação isolada dominando completamente o Modelo 4.

5.2.5 Independência

A independência não pode ser confirmada por um gráfico se o desenho da coleta for desconhecido. Se várias flores vieram da mesma planta, canteiro, região ou lote, talvez seja necessário um modelo hierárquico. Se as linhas estiverem ordenadas no tempo, avalie autocorrelação.

ggplot(diag, aes(indice, .resid)) +
  geom_hline(yintercept = 0, color = cinza, linetype = 2) +
  geom_line(color = "#9FB4D1", linewidth = 0.55) +
  geom_point(color = azul, size = 1.5) +
  labs(
    title = "Resíduos na ordem das observações",
    subtitle = "Só é informativo sobre dependência se a ordem tiver significado no desenho",
    x = "Ordem", y = "Resíduo"
  )

5.2.6 Investigando as observações sinalizadas

influentes <- augment(modelo_diagnostico, data = dados) |>
  mutate(
    id = dados$id,
    limiar_cook = 4 / nrow(dados),
    sinalizada = .cooksd > limiar_cook | abs(.std.resid) > 2
  ) |>
  arrange(desc(.cooksd)) |>
  transmute(
    id,
    especie = Species,
    comprimento_sepala = Sepal.Length,
    largura_sepala = Sepal.Width,
    comprimento_petala = Petal.Length,
    valor_ajustado = .fitted,
    residuo = .resid,
    residuo_padronizado = .std.resid,
    alavancagem = .hat,
    distancia_cook = .cooksd,
    sinalizada
  )

DT::datatable(
  head(influentes, 12),
  rownames = FALSE,
  options = list(pageLength = 6, scrollX = TRUE),
  caption = "Observações com maior distância de Cook",
  colnames = c(
    "ID", "Espécie", "Comprimento da sépala", "Largura da sépala",
    "Comprimento da pétala", "Valor ajustado", "Resíduo",
    "Resíduo padronizado", "Alavancagem", "Distância de Cook", "Sinalizada"
  )
) |>
  formatRound(columns = c("comprimento_sepala", "largura_sepala", "comprimento_petala",
                          "valor_ajustado", "residuo", "residuo_padronizado",
                          "alavancagem", "distancia_cook"), digits = 3)

Distância de Cook acima de \(4/n\) é um sinal para investigar, não uma ordem para excluir. Primeiro verifique erro de digitação, compatibilidade com a população e sensibilidade das conclusões com e sem o ponto.

Análise de sensibilidade, não seleção de modelo. Os pontos abaixo são retirados apenas para verificar a estabilidade das conclusões. A comparação não deve ser usada para escolher um modelo com \(R^2\) maior nem para justificar exclusões automáticas.

ids_sensiveis <- influentes |>
  filter(sinalizada) |>
  pull(id)

modelo_sem_sensiveis <- lm(
  formula(modelo_diagnostico),
  data = dados |> filter(!id %in% ids_sensiveis)
)

metricas_sensibilidade <- tibble(
  metrica = c("R²", "R² ajustado", "Erro-padrão residual"),
  `Todos os dados` = c(
    summary(modelo_diagnostico)$r.squared,
    summary(modelo_diagnostico)$adj.r.squared,
    summary(modelo_diagnostico)$sigma
  ),
  `Sem pontos sinalizados` = c(
    summary(modelo_sem_sensiveis)$r.squared,
    summary(modelo_sem_sensiveis)$adj.r.squared,
    summary(modelo_sem_sensiveis)$sigma
  )
)

metricas_sensibilidade |>
  knitr::kable(digits = 3, caption = "Métricas de ajuste na análise de sensibilidade") |>
  kable_styling(full_width = FALSE, bootstrap_options = c("striped", "hover"))
Métricas de ajuste na análise de sensibilidade
metrica Todos os dados Sem pontos sinalizados
0.863 0.898
R² ajustado 0.860 0.895
Erro-padrão residual 0.310 0.269
comparacao_sensibilidade <- bind_rows(
  tidy(modelo_diagnostico) |> mutate(ajuste = "Todos os dados"),
  tidy(modelo_sem_sensiveis) |> mutate(ajuste = "Sem pontos sinalizados")
) |>
  select(ajuste, term, estimate, std.error) |>
  pivot_wider(names_from = ajuste, values_from = c(estimate, std.error))

knitr::kable(comparacao_sensibilidade, digits = 3) |>
  kable_styling(full_width = FALSE, bootstrap_options = c("striped", "hover"))
term estimate_Todos os dados estimate_Sem pontos sinalizados std.error_Todos os dados std.error_Sem pontos sinalizados
(Intercept) 2.390 2.358 0.262 0.233
Sepal.Width 0.432 0.423 0.081 0.072
Petal.Length 0.776 0.809 0.064 0.059
Speciesversicolor -0.956 -0.981 0.215 0.193
Speciesvirginica -1.394 -1.502 0.286 0.259

Foram sinalizadas 8 observações. Ao retirá-las apenas para esta análise de sensibilidade, o \(R^2\) ajustado passa de 0,860 para 0,895 e o erro residual passa de 0,310 para 0,269. Essa aparente “melhora” é esperada quando removemos pontos com resíduos maiores; ela não prova que o modelo sem essas flores é melhor ou que elas devam ser excluídas.

Os coeficientes permanecem próximos, como mostra a tabela. Portanto, o Modelo 4 com as 150 flores continua sendo o resultado principal. Uma observação só deveria ser removida se houver evidência independente de erro de registro, de que ela não pertence à população estudada ou uma regra definida antes da análise — nunca apenas por cruzar a linha laranja, ter resíduo grande ou ficar dentro/fora do envelope.

6 Previsão e incerteza

Com o Modelo 4 selecionado, podemos estimar o comprimento da sépala para novos valores de Sepal.Width, Petal.Length e Species. Os nomes e tipos das colunas no novo data.frame precisam coincidir com os usados no ajuste.

modelo_final <- modelo4

novas_flores <- tibble(
  cenario = c("Flor A", "Flor B", "Flor C"),
  Sepal.Width = c(2.5, 3.0, 3.5),
  Petal.Length = c(1.5, 4.0, 5.5),
  Species = factor(
    c("setosa", "versicolor", "virginica"),
    levels = levels(dados$Species)
  )
)

ic_media <- predict(modelo_final, newdata = novas_flores,
                    interval = "confidence", level = 0.95)
ip_individual <- predict(modelo_final, newdata = novas_flores,
                         interval = "prediction", level = 0.95)

bind_rows(
  bind_cols(novas_flores, as_tibble(ic_media)) |>
    mutate(intervalo = "IC 95% da média"),
  bind_cols(novas_flores, as_tibble(ip_individual)) |>
    mutate(intervalo = "IP 95% individual")
) |>
  select(cenario, Species, Sepal.Width, Petal.Length, intervalo,
         estimativa = fit, inferior = lwr, superior = upr) |>
  knitr::kable(digits = 3) |>
  kable_styling(full_width = FALSE, bootstrap_options = c("striped", "hover"))
cenario Species Sepal.Width Petal.Length intervalo estimativa inferior superior
Flor A setosa 2.5 1.5 IC 95% da média 4.634 4.460 4.809
Flor B versicolor 3.0 4.0 IC 95% da média 5.834 5.729 5.938
Flor C virginica 3.5 5.5 IC 95% da média 6.775 6.652 6.898
Flor A setosa 2.5 1.5 IP 95% individual 4.634 3.997 5.272
Flor B versicolor 3.0 4.0 IP 95% individual 5.834 5.212 6.456
Flor C virginica 3.5 5.5 IP 95% individual 6.775 6.149 7.401

Para uma previsão individual, use o intervalo de previsão. Usar o intervalo de confiança da média nesse caso produz uma faixa estreita demais e aumenta a chance de não conter o valor individual observado.

Dica para uma análise voltada à previsão. Em um projeto preditivo, separe os dados logo no início em duas bases: treinamento e teste. Use somente a base de treinamento para explorar os dados, ajustar os modelos, comparar especificações e diagnosticar resíduos — ou seja, para realizar todo o percurso apresentado até aqui. Guarde a base de teste sem usá-la nesse processo. Ao final, aplique predict() ao conjunto de teste e compare as previsões com os valores verdadeiros de Sepal.Length, por exemplo com RQME, MAE e gráficos de observado versus previsto. Essa avaliação mostra como o modelo se comporta em flores que não participaram do ajuste. Nesta aula, a base completa foi usada para privilegiar a explicação e a inferência; a divisão é uma extensão recomendada quando a finalidade principal for previsão.

7 Conclusões finais

7.1 Síntese da exploração

A base contém 150 flores, igualmente distribuídas entre setosa, versicolor e virginica, sem valores ausentes. As medidas das pétalas são fortemente correlacionadas entre si (\(r\approx0{,}963\)), o que explica a multicolinearidade observada quando ambas entram simultaneamente. A exploração também mostra separação marcante entre espécies, principalmente nas medidas da pétala; por isso, Species não pode ser ignorada sem uma justificativa substantiva.

7.2 Decisão e interpretação

Após os diagnósticos, o Modelo 4 permanece o melhor ajuste interno entre os cinco modelos: os gráficos não revelam um motivo claro para descartá-lo, e ele lidera os critérios de ajuste. Porém, ele não é automaticamente o melhor modelo para toda finalidade. Para descrição global interna, ele é a escolha principal; para ensinar e interpretar efeitos contínuos com menor colinearidade, o Modelo 2 é uma alternativa mais estável e mais simples. Não há base de teste nesta análise, portanto não é possível afirmar qual dos cinco é melhor para prever novas flores.

No Modelo 4:

  • mantendo Petal.Length e Species constantes, 1 cm adicional em Sepal.Width está associado a um aumento médio de 0,432 cm em Sepal.Length;
  • mantendo Sepal.Width e Species constantes, 1 cm adicional em Petal.Length está associado a um aumento médio de 0,776 cm em Sepal.Length;
  • os coeficientes de versicolor e virginica são negativos em relação a setosa depois de fixar as duas medidas numéricas. Eles não contradizem os gráficos de médias brutas: respondem a uma comparação condicional diferente e apoiada por pouca sobreposição de comprimento de pétala entre as espécies.
tabela_coeficientes(modelo4) |>
  knitr::kable(digits = 3) |>
  kable_styling(full_width = FALSE, bootstrap_options = c("striped", "hover"))
termo estimativa erro-padrão estatistica_t p-valor IC 95% inferior IC 95% superior
(Intercept) 2.390 0.262 9.114 0 1.872 2.909
Sepal.Width 0.432 0.081 5.310 0 0.271 0.593
Petal.Length 0.776 0.064 12.073 0 0.649 0.903
Speciesversicolor -0.956 0.215 -4.442 0 -1.381 -0.530
Speciesvirginica -1.394 0.286 -4.880 0 -1.959 -0.830

7.3 Verificação final dos pressupostos

Os gráficos de resíduos e escala–localização não sugerem mudança forte de variância. O teste de Shapiro–Wilk apresentou p-valor 0,9048, compatível com a normalidade aproximada indicada pelo QQ-plot com envelope. Os gráficos de alavancagem e distância de Cook foram examinados em conjunto e não revelaram um motivo isolado para descartar o ajuste.

A independência não pode ser estabelecida apenas com a base. Se houver várias flores provenientes da mesma planta, canteiro ou local, seria necessário representar essa estrutura no modelo. As observações sinalizadas por influência também devem ser investigadas, não eliminadas automaticamente.

7.4 Conclusão substantiva

O comprimento da sépala está positivamente associado à largura da sépala e ao comprimento da pétala, depois de controlar a espécie. A espécie organiza grande parte da estrutura morfológica da base e altera a interpretação das relações entre as medidas. Entre os cinco modelos estudados, o Modelo 4 oferece o melhor ajuste interno; o Modelo 2 oferece a leitura mais simples dos efeitos contínuos. Os contrastes de espécie do Modelo 4 precisam ser comunicados como associações condicionais, sob forte colinearidade.

As conclusões são associativas, não causais. A base Iris é observacional e não contém detalhes suficientes do desenho da coleta para sustentar afirmações de causa e efeito.

LS0tCnRpdGxlOiAiUmVncmVzc8OjbyBMaW5lYXIgTcO6bHRpcGxhIOKAlCBBbsOhbGlzZSBDb21wbGV0YSBkYSBCYXNlIElyaXMiCnN1YnRpdGxlOiAiRXN0YXTDrXN0aWNhIEFwbGljYWRhIOKAlCBVbml2ZXJzaWRhZGUgRmVkZXJhbCBkZSBDYW1waW5hIEdyYW5kZSAoVUZDRykiCmF1dGhvcjogIlByb2ZhLiBEcmEuIEFtYW5kYSBHb21lczxicj5Qcm9mLiBEci4gSmVyZnNvbiBCcnVubzxicj5Qcm9mLiBEci4gR2lsYmVydG8gTWF0b3MiCmRhdGU6ICJgciBmb3JtYXQoU3lzLkRhdGUoKSwgJyVkLyVtLyVZJylgIgpsYW5nOiBwdC1CUgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIHRoZW1lOiBmbGF0bHkKICAgIHRvYzogZmFsc2UKICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogICAgY29kZV9mb2xkaW5nOiBoaWRlCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICBoaWdobGlnaHQ6IHRhbmdvCiAgICBzZWxmX2NvbnRhaW5lZDogdHJ1ZQogICAgZGZfcHJpbnQ6IHBhZ2VkCiAgICBjc3M6IHR1dG9yaWFsX3JlZ3Jlc3Nhb19tdWx0aXBsYS5jc3MKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KAogIGVjaG8gPSBUUlVFLAogIG1lc3NhZ2UgPSBGQUxTRSwKICB3YXJuaW5nID0gRkFMU0UsCiAgZmlnLmFsaWduID0gImNlbnRlciIsCiAgZmlnLndpZHRoID0gOSwKICBmaWcuaGVpZ2h0ID0gNS42LAogIGRwaSA9IDE0MCwKICBvdXQud2lkdGggPSAiMTAwJSIsCiAgY2FjaGUgPSBGQUxTRQopCgpvcHRpb25zKHNjaXBlbiA9IDk5OSwgZGlnaXRzID0gNCkKCnBhY290ZXNfbmVjZXNzYXJpb3MgPC0gYygKICAiZ2dwbG90MiIsICJkcGx5ciIsICJ0aWR5ciIsICJwdXJyciIsICJicm9vbSIsCiAgInBlcmZvcm1hbmNlIiwgInBhdGNod29yayIsICJHR2FsbHkiLCAia2FibGVFeHRyYSIsICJEVCIKKQoKcGFjb3Rlc19hdXNlbnRlcyA8LSBzZXRkaWZmKHBhY290ZXNfbmVjZXNzYXJpb3MsIHJvd25hbWVzKGluc3RhbGxlZC5wYWNrYWdlcygpKSkKaWYgKGxlbmd0aChwYWNvdGVzX2F1c2VudGVzKSA+IDApIHsKICBzdG9wKAogICAgIlBhY290ZXMgYXVzZW50ZXM6ICIsIHBhc3RlKHBhY290ZXNfYXVzZW50ZXMsIGNvbGxhcHNlID0gIiwgIiksCiAgICAiLiBJbnN0YWxlLW9zIGFudGVzIGRlIHJlbmRlcml6YXIgY29tIGluc3RhbGwucGFja2FnZXMocGFjb3Rlc19hdXNlbnRlcykuIgogICkKfQoKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHRpZHlyKQpsaWJyYXJ5KHB1cnJyKQpsaWJyYXJ5KGJyb29tKQpsaWJyYXJ5KHBlcmZvcm1hbmNlKQpsaWJyYXJ5KHBhdGNod29yaykKbGlicmFyeShHR2FsbHkpCmxpYnJhcnkoa2FibGVFeHRyYSkKbGlicmFyeShEVCkKCmF6dWwgPC0gIiMxRjVBQTYiCmF6dWxfZXNjdXJvIDwtICIjMTczRjczIgpkb3VyYWRvIDwtICIjRDc5QjJFIgpvbGl2YSA8LSAiIzY2N0EzQyIKcm9zYSA8LSAiI0E2NEQ3OSIKY2luemEgPC0gIiM2Qjc3ODgiCgpwYWxldGFfZXNwZWNpZXMgPC0gYygKICBzZXRvc2EgPSAiIzFGNUFBNiIsCiAgdmVyc2ljb2xvciA9ICIjRDc5QjJFIiwKICB2aXJnaW5pY2EgPSAiI0E2NEQ3OSIKKQoKdGVtYV9hdWxhIDwtIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTMpICsKICB0aGVtZSgKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgY29sb3IgPSBhenVsX2VzY3Vybywgc2l6ZSA9IDE1KSwKICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoY29sb3IgPSBjaW56YSwgc2l6ZSA9IDEwLjUpLAogICAgcGxvdC5jYXB0aW9uID0gZWxlbWVudF90ZXh0KGNvbG9yID0gY2luemEsIGhqdXN0ID0gMCksCiAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KGNvbG9yID0gIiMzMTQ0NUUiKSwKICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9saW5lKGNvbG9yID0gIiNFNEVBRjIiLCBsaW5ld2lkdGggPSAwLjM1KSwKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLAogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIpLAogICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBjb2xvciA9IGF6dWxfZXNjdXJvKSwKICAgIHBsb3QubWFyZ2luID0gbWFyZ2luKDEwLCAxNCwgMTAsIDEwKQogICkKCnRoZW1lX3NldCh0ZW1hX2F1bGEpCgpmbXRfcCA8LSBmdW5jdGlvbihwKSB7CiAgaWZlbHNlKHAgPCAwLjAwMSwgIjwgMCwwMDEiLCBmb3JtYXQocm91bmQocCwgMyksIGRlY2ltYWwubWFyayA9ICIsIikpCn0KCmZtdF9udW0gPC0gZnVuY3Rpb24oeCwgbiA9IDMpIHsKICBmb3JtYXQocm91bmQoeCwgbiksIG5zbWFsbCA9IG4sIGRlY2ltYWwubWFyayA9ICIsIiwgYmlnLm1hcmsgPSAiLiIpCn0KCmZtdF9wYXJjZWxhIDwtIGZ1bmN0aW9uKHgsIG4gPSAzKSB7CiAgcGFzdGUoaWZlbHNlKHggPj0gMCwgIisiLCAiLSIpLCBmbXRfbnVtKGFicyh4KSwgbikpCn0KCnRhYmVsYV9jb2VmaWNpZW50ZXMgPC0gZnVuY3Rpb24obW9kZWxvKSB7CiAgdGlkeShtb2RlbG8sIGNvbmYuaW50ID0gVFJVRSkgfD4KICAgIHRyYW5zbXV0ZSgKICAgICAgdGVybW8gPSB0ZXJtLAogICAgICBlc3RpbWF0aXZhID0gZXN0aW1hdGUsCiAgICAgIGBlcnJvLXBhZHLDo29gID0gc3RkLmVycm9yLAogICAgICBlc3RhdGlzdGljYV90ID0gc3RhdGlzdGljLAogICAgICBgcC12YWxvcmAgPSBwLnZhbHVlLAogICAgICBgSUMgOTUlIGluZmVyaW9yYCA9IGNvbmYubG93LAogICAgICBgSUMgOTUlIHN1cGVyaW9yYCA9IGNvbmYuaGlnaAogICAgKQp9CmBgYAoKPGRpdiBjbGFzcz0iY2FsbG91dCI+CjxzdHJvbmc+SWRlaWEgY2VudHJhbC48L3N0cm9uZz4gUmVncmVzc8OjbyBtw7psdGlwbGEgbsOjbyDDqSB1bWEgc2VxdcOqbmNpYSBkZSBib3TDtWVzLiDDiSB1bSBhcmd1bWVudG8gY2llbnTDrWZpY286IGRlZmluaW1vcyB1bWEgcGVyZ3VudGEsIGV4cGxpY2l0YW1vcyB1bSBtb2RlbG8sIGNvbmZyb250YW1vcyBzdWFzIHN1cG9zacOnw7VlcyBjb20gb3MgZGFkb3MsIGF2YWxpYW1vcyBpbmNlcnRlemEgZSBzw7MgZW50w6NvIGNvbXVuaWNhbW9zIG8gcXVlIG8gbW9kZWxvIHBlcm1pdGUg4oCUIGUgbyBxdWUgZWxlIG7Do28gcGVybWl0ZSDigJQgY29uY2x1aXIuCjwvZGl2PgoKIyBWaXPDo28gZ2VyYWwgZGEgYW7DoWxpc2UKCiMjIFByZXBhcmHDp8OjbyBkbyBhbWJpZW50ZQoKSW5zdGFsZSBvcyBwYWNvdGVzIHVtYSDDum5pY2EgdmV6LiBEZXBvaXMsIGFicmEgbyBhcnF1aXZvIGAuUm1kYCBubyBSU3R1ZGlvIGUgdXNlICoqS25pdCoqLCBvdSBleGVjdXRlIGBybWFya2Rvd246OnJlbmRlcigpYC4gTm8gSFRNTCwgb3MgY8OzZGlnb3MgZmljYW0gcmVjb2xoaWRvczogY2xpcXVlIGVtICoqQ29kZSoqIHBhcmEgdmlzdWFsaXrDoS1sb3MuIFBhcmEgcmVwcm9kdXppciBvdSBhbHRlcmFyIGEgYW7DoWxpc2UsIGV4ZWN1dGUvcmVuZGVyaXplIG8gZG9jdW1lbnRvIGludGVpcm8gbmEgb3JkZW0gYXByZXNlbnRhZGEsIHBvaXMgY2FkYSBldGFwYSB1c2Egb2JqZXRvcyBjcmlhZG9zIG5hcyBldGFwYXMgYW50ZXJpb3Jlcy4KCmBgYHtyIGluc3RhbGFyLXBhY290ZXMsIGV2YWw9RkFMU0V9Cmluc3RhbGwucGFja2FnZXMoYygKICAicm1hcmtkb3duIiwgImtuaXRyIiwgImdncGxvdDIiLCAiZHBseXIiLCAidGlkeXIiLCAicHVycnIiLAogICJicm9vbSIsICJwZXJmb3JtYW5jZSIsICJwYXRjaHdvcmsiLCAiR0dhbGx5IiwKICAia2FibGVFeHRyYSIsICJEVCIKKSkKCnJtYXJrZG93bjo6cmVuZGVyKCJ0dXRvcmlhbF9yZWdyZXNzYW9fbXVsdGlwbGFfaXJpcy5SbWQiKQpgYGAKCiMjIE9iamV0aXZvcyBkYSBhbsOhbGlzZQoKRXN0YSBhbsOhbGlzZSBmb2kgZXN0cnV0dXJhZGEgcGFyYToKCjEuIHRyYW5zZm9ybWFyIHVtYSBwZXJndW50YSBzdWJzdGFudGl2YSBlbSB1bWEgZXF1YcOnw6NvIGRlIHJlZ3Jlc3PDo287CjIuIGRpc3Rpbmd1aXIgdmFyacOhdmVsIHJlc3Bvc3RhLCBwcmVkaXRvcmVzIG51bcOpcmljb3MgZSBwcmVkaXRvcmVzIGNhdGVnw7NyaWNvczsKMy4gcmVhbGl6YXIgdW1hIGFuw6FsaXNlIGV4cGxvcmF0w7NyaWEgb3JpZW50YWRhIGFvIG1vZGVsbzsKNC4gYWp1c3RhciBlIGludGVycHJldGFyIHVtYSByZWdyZXNzw6NvIGxpbmVhciBtw7psdGlwbGEgZW0gUjsKNS4gdmVyaWZpY2FyIGxpbmVhcmlkYWRlLCBpbmRlcGVuZMOqbmNpYSwgaG9tb2NlZGFzdGljaWRhZGUsIG5vcm1hbGlkYWRlIGFwcm94aW1hZGEsIG11bHRpY29saW5lYXJpZGFkZSBlIGluZmx1w6puY2lhOwo2LiBjb21wYXJhciBjaW5jbyBtb2RlbG9zIHVzYW5kbyB0ZXN0ZSBGLCAkUl4yJCBhanVzdGFkbywgQUlDLCBCSUMgZSBwYXJjaW3DtG5pYTsKNy4gaW50ZXJwcmV0YXIgY29ycmV0YW1lbnRlIHZhcmnDoXZlaXMgY2F0ZWfDs3JpY2FzIGUgY2F0ZWdvcmlhcyBkZSByZWZlcsOqbmNpYTsKOC4gZGlmZXJlbmNpYXIgaW50ZXJ2YWxvIGRlIGNvbmZpYW7Dp2EgZGEgbcOpZGlhIGUgaW50ZXJ2YWxvIGRlIHByZXZpc8OjbyBpbmRpdmlkdWFsOwo5LiByZWNvbmhlY2VyIG11bHRpY29saW5lYXJpZGFkZSwgZXh0cmFwb2xhw6fDo28gZSBsaW5ndWFnZW0gY2F1c2FsIGluZGV2aWRhOwoxMC4gc2VsZWNpb25hciB1bSBtb2RlbG8gY29tIGJhc2Ugbm8gY29uanVudG8gZGFzIGV2aWTDqm5jaWFzIGUgcHJvZHV6aXIgdW1hIGNvbmNsdXPDo28gZGVmZW5zw6F2ZWwuCgojIyBPIG1hcGEgZG8gcHJvY2Vzc28KCnwgRXRhcGEgfCBQZXJndW50YSBxdWUgZ3VpYSBhIGV0YXBhIHwgUHJvZHV0byB8CnwtLS18LS0tfC0tLXwKfCAxLiBQcm9ibGVtYSB8IE8gcXVlIHF1ZXJlbW9zIGV4cGxpY2FyIG91IHByZXZlcj8gfCBwZXJndW50YSwgcG9wdWxhw6fDo28gZSB1bmlkYWRlIGRlIGFuw6FsaXNlIHwKfCAyLiBEYWRvcyB8IEFzIHZhcmnDoXZlaXMgbWVkZW0gbyBxdWUgcHJlY2lzYW1vcz8gfCBkaWNpb27DoXJpbywgcXVhbGlkYWRlIGUgZXhwbG9yYcOnw6NvIHwKfCAzLiBFc3BlY2lmaWNhw6fDo28gfCBRdWUgcmVsYcOnw6NvIGVzdGFtb3Mgc3Vwb25kbz8gfCBmw7NybXVsYSwgdGVybW9zIGUgaW50ZXJhw6fDtWVzIGp1c3RpZmljYWRhcyB8CnwgNC4gQWp1c3RlIHwgUXVhaXMgY29lZmljaWVudGVzIG1lbGhvciByZXByb2R1emVtIG9zIGRhZG9zPyB8IG1vZGVsbyBlc3RpbWFkbyBlIGluY2VydGV6YSB8CnwgNS4gQ29tcGFyYcOnw6NvIHByZWxpbWluYXIgfCBRdWFsIG1vZGVsbyB0ZW0gbWVsaG9yIGFqdXN0ZSBlIHF1YWlzIHRlcm1vcyBhY3Jlc2NlbnRhbSBpbmZvcm1hw6fDo28/IHwgdGFiZWxhIGNvbXBhcmF0aXZhLCB0ZXN0ZSBGIGUgY2FuZGlkYXRvIGFvIGRpYWduw7NzdGljbyB8CnwgNi4gRGlhZ27Ds3N0aWNvIHwgTyBjYW5kaWRhdG8gcmVzcGVpdGEgb3MgcHJlc3N1cG9zdG9zIGRlIGZvcm1hIHJhem/DoXZlbD8gfCByZXPDrWR1b3MsIGluZmx1w6puY2lhLCBWSUYgZSBncsOhZmljb3MgYXV4aWxpYXJlcyB8CnwgNy4gRGVjaXPDo28gfCBRdWFsIGVzcGVjaWZpY2HDp8OjbyDDqSBtYWlzIGRlZmVuc8OhdmVsIHBhcmEgY2FkYSBvYmpldGl2bz8gfCBtZWxob3IgYWp1c3RlLCBhbHRlcm5hdGl2YSBpbnRlcnByZXTDoXZlbCBlIGp1c3RpZmljYXRpdmEgfAp8IDguIENvbXVuaWNhw6fDo28gfCBPIHF1ZSBhcHJlbmRlbW9zIGUgY29tIHF1YWlzIGxpbWl0ZXM/IHwgY29uY2x1c8OjbywgaW50ZXJ2YWxvcyBlIHByw7N4aW1vcyBwYXNzb3MgfAoKIyBBIHBlcmd1bnRhIHZlbSBhbnRlcyBkbyBtb2RlbG8KClVzYXJlbW9zIGBTZXBhbC5MZW5ndGhgIOKAlCBvIGNvbXByaW1lbnRvIGRhIHPDqXBhbGEsIGVtIGNlbnTDrW1ldHJvcyDigJQgY29tbyByZXNwb3N0YS4gUXVlcmVtb3MgaW52ZXN0aWdhciBlIHByZXZlciBlc3NhIG1lZGlkYSBhIHBhcnRpciBkYSBsYXJndXJhIGRhIHPDqXBhbGEsIGRhcyBtZWRpZGFzIGRhIHDDqXRhbGEgZSBkYSBlc3DDqWNpZS4KClVtYSBwZXJndW50YSBiZW0gZm9ybXVsYWRhIHNlcmlhOgoKPiBFbnRyZSBmbG9yZXMgc2VtZWxoYW50ZXMgbmFzIGRlbWFpcyBjYXJhY3RlcsOtc3RpY2FzIGNvbnNpZGVyYWRhcywgY29tbyBvIGNvbXByaW1lbnRvIGVzcGVyYWRvIGRhIHPDqXBhbGEgdmFyaWEgY29tIGNhZGEgcHJlZGl0b3IsIGUgcXXDo28gYmVtIG8gbW9kZWxvIHByZXbDqiBub3ZhcyBmbG9yZXM/CgpFc3NhIGZyYXNlIGrDoSBjb250w6ltIGR1YXMgbWV0YXMgZGlmZXJlbnRlczoKCi0gKippbmZlcsOqbmNpYS9leHBsaWNhw6fDo286KiogaW50ZXJwcmV0YXIgcmVsYcOnw7VlcyBjb25kaWNpb25haXMgZSBzdWEgaW5jZXJ0ZXphOwotICoqcHJldmlzw6NvOioqIGVzdGltYXIgdmFsb3JlcyBwYXJhIG5vdmFzIG9ic2VydmHDp8O1ZXMgY29tIGJhaXhvIGVycm8uCgo8ZGl2IGNsYXNzPSJ3YXJuaW5nIj4KPHN0cm9uZz7igJxNZWxob3IgbW9kZWxv4oCdIG7Do28gw6kgdW1hIHByb3ByaWVkYWRlIGFic29sdXRhLjwvc3Ryb25nPiBVbSBtb2RlbG8gcG9kZSBzZXIgZXhjZWxlbnRlIHBhcmEgcHJldmlzw6NvIGUgcnVpbSBwYXJhIGludGVycHJldGHDp8Ojbzsgb3V0cm8gcG9kZSBzZXIgdHJhbnNwYXJlbnRlIGUgZXN0w6F2ZWwsIG1hcyBwZXJkZXIgdW0gcG91Y28gZGUgYWN1csOhY2lhLiBBbnRlcyBkZSBjb21wYXJhciBtb2RlbG9zLCBkZWNsYXJlIG8gb2JqZXRpdm8uCjwvZGl2PgoKIyMgTyBtb2RlbG8gbWF0ZW3DoXRpY28KClBhcmEgYSBvYnNlcnZhw6fDo28gJGkkLCB1bSBtb2RlbG8gY29tIHRyw6pzIHByZWRpdG9yZXMgbnVtw6lyaWNvcyDDqQoKJCQKWV9pID0gXGJldGFfMCArIFxiZXRhXzEgWF97MWl9ICsgXGJldGFfMiBYX3syaX0gKyBcYmV0YV8zIFhfezNpfSArIFx2YXJlcHNpbG9uX2ksCiQkCgplbSBxdWU6CgotICRZX2kkIMOpIG8gY29tcHJpbWVudG8gb2JzZXJ2YWRvIGRhIHPDqXBhbGE7Ci0gJFxiZXRhXzAkIMOpIG8gdmFsb3IgZXNwZXJhZG8gZGUgJFkkIHF1YW5kbyBvcyBwcmVkaXRvcmVzIHZhbGVtIHplcm87Ci0gJFxiZXRhX2okIMOpIGEgbXVkYW7Dp2EgbcOpZGlhIGVzcGVyYWRhIGVtICRZJCBwYXJhIHVtYSB1bmlkYWRlIGFkaWNpb25hbCBkZSAkWF9qJCwgKiptYW50ZW5kbyBvcyBkZW1haXMgcHJlZGl0b3JlcyBjb25zdGFudGVzKio7Ci0gJFx2YXJlcHNpbG9uX2kkIHJlcHJlc2VudGEgdHVkbyBvIHF1ZSBvIG1vZGVsbyBuw6NvIGV4cGxpY2EuCgpRdWFuZG8gaW5jbHXDrW1vcyBgU3BlY2llc2AsIG8gUiBjcmlhIGNvbnRyYXN0ZXMgKGFzIGNoYW1hZGFzIHZhcmnDoXZlaXMgaW5kaWNhZG9yYXMgb3UgKmR1bW1pZXMqKSBjb21wYXJhbmRvIGNhZGEgbsOtdmVsIGNvbSB1bWEgY2F0ZWdvcmlhIGRlIHJlZmVyw6puY2lhLgoKIyMgU3Vwb3Npw6fDtWVzOiBvIHF1ZSByZWFsbWVudGUgcHJlY2lzYW1vcyB2ZXJpZmljYXIKCnwgU3Vwb3Npw6fDo28gfCBTaWduaWZpY2FkbyBvcGVyYWNpb25hbCB8IENvbW8gdmVyaWZpY2FyIHwgTyBxdWUgZmF6ZXIgc2UgZmFsaGFyIHwKfC0tLXwtLS18LS0tfC0tLXwKfCBMaW5lYXJpZGFkZSB8IGEgbcOpZGlhIGNvbmRpY2lvbmFsIGRlICRZJCDDqSBsaW5lYXIgbm9zIHBhcsOibWV0cm9zIHwgcmVzw61kdW9zIHZzLiBhanVzdGFkb3M7IHJlc8OtZHVvcyBwYXJjaWFpcyB8IHRyYW5zZm9ybWHDp8OjbywgcG9saW7DtG1pbywgc3BsaW5lIG91IGludGVyYcOnw6NvIGp1c3RpZmljYWRhIHwKfCBJbmRlcGVuZMOqbmNpYSB8IGVycm9zIGRlIHVuaWRhZGVzIGRpc3RpbnRhcyBuw6NvIHPDo28gY29ycmVsYWNpb25hZG9zIHwgZGVzZW5obyBkYSBjb2xldGE7IG9yZGVtL3RlbXBvL2dydXBvcyB8IG1vZGVsb3MgbWlzdG9zLCBzw6lyaWVzIHRlbXBvcmFpcywgZXJyb3MgYWdydXBhZG9zIHwKfCBWYXJpw6JuY2lhIGFwcm94aW1hZGFtZW50ZSBjb25zdGFudGUgfCBkaXNwZXJzw6NvIGRvcyBlcnJvcyDDqSBzZW1lbGhhbnRlIGFvIGxvbmdvIGRhIG3DqWRpYSB8IHJlc8OtZHVvcyB2cy4gYWp1c3RhZG9zOyBlc2NhbGEtbG9jYWxpemHDp8OjbyB8IHRyYW5zZm9ybWHDp8OjbywgZXJyb3Mgcm9idXN0b3MsIFdMUyB8CnwgTm9ybWFsaWRhZGUgYXByb3hpbWFkYSBkb3MgZXJyb3MgfCBuZWNlc3PDoXJpYSBwcmluY2lwYWxtZW50ZSBwYXJhIGluZmVyw6puY2lhIGV4YXRhIGVtIGFtb3N0cmFzIHBlcXVlbmFzIHwgUVEtcGxvdDsgZm9ybWEgZG9zIHJlc8OtZHVvcyB8IGJvb3RzdHJhcCwgZXJyb3Mgcm9idXN0b3MsIGludmVzdGlnYXIgbW9kZWxvL291dGxpZXJzIHwKfCBBdXPDqm5jaWEgZGUgY29saW5lYXJpZGFkZSBwcmVqdWRpY2lhbCB8IHByZWRpdG9yZXMgbsOjbyBjYXJyZWdhbSBxdWFzZSBhIG1lc21hIGluZm9ybWHDp8OjbyB8IFZJRi9HVklGOyBlc3RhYmlsaWRhZGUgZG9zIGNvZWZpY2llbnRlcyB8IHJlZm9ybXVsYXIsIGNvbWJpbmFyLCBjZW50cmFyLCByZWd1bGFyaXphciwgY29sZXRhciBtYWlzIGRhZG9zIHwKfCBBdXPDqm5jaWEgZGUgaW5mbHXDqm5jaWEgZXhjZXNzaXZhIHwgbmVuaHVtYSBvYnNlcnZhw6fDo28gZG9taW5hIG8gYWp1c3RlIHwgYWxhdmFuY2FnZW0gZSBkaXN0w6JuY2lhIGRlIENvb2sgfCB2ZXJpZmljYXIgZGFkbywgcmVsYXRhciBzZW5zaWJpbGlkYWRlOyBudW5jYSBleGNsdWlyIGF1dG9tYXRpY2FtZW50ZSB8CnwgRXNwZWNpZmljYcOnw6NvIGFkZXF1YWRhIHwgdGVybW9zIGltcG9ydGFudGVzIG7Do28gZm9yYW0gb21pdGlkb3MgfCB0ZW9yaWEsIHJlc8OtZHVvcywgaW50ZXJhw6fDtWVzLCB2YWxpZGHDp8OjbyB8IHJlZXNwZWNpZmljYXIgY29tIGp1c3RpZmljYXRpdmEgc3Vic3RhbnRpdmEgfAoKPGRpdiBjbGFzcz0iY2hlY2twb2ludCI+CjxzdHJvbmc+Q2hlcXVlIGNvbmNlaXR1YWwuPC9zdHJvbmc+IE5vcm1hbGlkYWRlIGRvcyBwcmVkaXRvcmVzIG7Do28gw6kgcHJlc3N1cG9zdG8gZGEgcmVncmVzc8OjbyBsaW5lYXIuIE8gZm9jbyDDqSBhIGRpc3RyaWJ1acOnw6NvIGRvcyBlcnJvcyBjb25kaWNpb25haXMsIGUgbmVtIHRvZGEgcGVxdWVuYSB2aW9sYcOnw6NvIGludmFsaWRhIG8gbW9kZWxvLgo8L2Rpdj4KCiMgQ29uaGVjZW5kbyBhIGJhc2UgSXJpcwoKIyMgRXN0cnV0dXJhLCB1bmlkYWRlIGUgcXVhbGlkYWRlCgpgYGB7ciBkYWRvcy1pbmljaWFpc30KZGFkb3MgPC0gZGF0YXNldHM6OmlyaXMgfD4KICBtdXRhdGUoCiAgICBTcGVjaWVzID0gZmFjdG9yKFNwZWNpZXMpLAogICAgaWQgPSByb3dfbnVtYmVyKCkKICApCgpnbGltcHNlKGRhZG9zKQpgYGAKCkNhZGEgbGluaGEgcmVwcmVzZW50YSB1bWEgZmxvcjsgY2FkYSBtZWRpZGEgZXN0w6EgZW0gY2VudMOtbWV0cm9zLiBIw6EgMTUwIG9ic2VydmHDp8O1ZXMsIDUwIGRlIGNhZGEgZXNww6ljaWUuCgpgYGB7ciBkaWNpb25hcmlvfQpkaWNpb25hcmlvIDwtIHRpYmJsZTo6dHJpYmJsZSgKICB+dmFyaWF2ZWwsIH50aXBvLCB+cGFwZWwsIH5kZWZpbmljYW8sCiAgIlNlcGFsLkxlbmd0aCIsICJudW3DqXJpY2EiLCAicmVzcG9zdGEiLCAiY29tcHJpbWVudG8gZGEgc8OpcGFsYSAoY20pIiwKICAiU2VwYWwuV2lkdGgiLCAibnVtw6lyaWNhIiwgInByZWRpdG9yIiwgImxhcmd1cmEgZGEgc8OpcGFsYSAoY20pIiwKICAiUGV0YWwuTGVuZ3RoIiwgIm51bcOpcmljYSIsICJwcmVkaXRvciIsICJjb21wcmltZW50byBkYSBww6l0YWxhIChjbSkiLAogICJQZXRhbC5XaWR0aCIsICJudW3DqXJpY2EiLCAicHJlZGl0b3IiLCAibGFyZ3VyYSBkYSBww6l0YWxhIChjbSkiLAogICJTcGVjaWVzIiwgImNhdGVnw7NyaWNhIiwgInByZWRpdG9yL2VzdHJhdG8iLCAiZXNww6ljaWUgZGEgZmxvciIsCiAgImlkIiwgImludGVpcmEiLCAiaWRlbnRpZmljYWRvciIsICJsaW5oYSBvcmlnaW5hbCBwYXJhIHJhc3RyZWFiaWxpZGFkZSIKKQoKa25pdHI6OmthYmxlKGRpY2lvbmFyaW8sIGFsaWduID0gYygibCIsICJsIiwgImwiLCAibCIpKSB8PgogIGthYmxlX3N0eWxpbmcoZnVsbF93aWR0aCA9IEZBTFNFLCBib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG92ZXIiKSkKYGBgCgpgYGB7ciBxdWFsaWRhZGUtZGFkb3N9CnF1YWxpZGFkZSA8LSBkYWRvcyB8PgogIHN1bW1hcmlzZSgKICAgIG9ic2VydmFjb2VzID0gbigpLAogICAgZHVwbGljYXRhc19leGF0YXMgPSBzdW0oZHVwbGljYXRlZChhY3Jvc3MoLWlkKSkpLAogICAgdmFsb3Jlc19hdXNlbnRlcyA9IHN1bShpcy5uYShhY3Jvc3MoZXZlcnl0aGluZygpKSkpLAogICAgZXNwZWNpZXMgPSBuX2Rpc3RpbmN0KFNwZWNpZXMpCiAgKQoKcXVhbGlkYWRlCmBgYAoKPGRpdiBjbGFzcz0id2FybmluZyI+CkjDoSB1bWEgZHVwbGljYXRhIGV4YXRhIG5hcyBtZWRpZGFzIGUgZXNww6ljaWUuIElzc28gbsOjbyBwcm92YSBlcnJvOiBkdWFzIGZsb3JlcyBwb2RlbSB0ZXIgbWVkaWRhcyBpZMOqbnRpY2FzLiBTZW0gdW0gaWRlbnRpZmljYWRvciBvcmlnaW5hbCBkYSBjb2xldGEsIG7Do28gZGV2ZW1vcyBhcGFnYXIgYSBsaW5oYSBhdXRvbWF0aWNhbWVudGUuIE8gY29ycmV0byDDqSByZWdpc3RyYXIgYSBhbWJpZ3VpZGFkZSBlIGZhemVyIGFuw6FsaXNlIGRlIHNlbnNpYmlsaWRhZGUgc2UgZWxhIHB1ZGVyIGFmZXRhciBvIHJlc3VsdGFkby4KPC9kaXY+CgojIyBFc3RhdMOtc3RpY2FzIGRlc2NyaXRpdmFzCgpgYGB7ciBkZXNjcml0aXZhc30KZGVzY3JpdGl2YXMgPC0gZGFkb3MgfD4KICBzZWxlY3QoLWlkKSB8PgogIHBpdm90X2xvbmdlcih3aGVyZShpcy5udW1lcmljKSwgbmFtZXNfdG8gPSAidmFyaWF2ZWwiLCB2YWx1ZXNfdG8gPSAidmFsb3IiKSB8PgogIGdyb3VwX2J5KHZhcmlhdmVsKSB8PgogIHN1bW1hcmlzZSgKICAgIG4gPSBuKCksCiAgICBtZWRpYSA9IG1lYW4odmFsb3IpLAogICAgZHAgPSBzZCh2YWxvciksCiAgICBtaW5pbW8gPSBtaW4odmFsb3IpLAogICAgcTEgPSBxdWFudGlsZSh2YWxvciwgMC4yNSksCiAgICBtZWRpYW5hID0gbWVkaWFuKHZhbG9yKSwKICAgIHEzID0gcXVhbnRpbGUodmFsb3IsIDAuNzUpLAogICAgbWF4aW1vID0gbWF4KHZhbG9yKSwKICAgIC5ncm91cHMgPSAiZHJvcCIKICApCgprbml0cjo6a2FibGUoZGVzY3JpdGl2YXMsIGRpZ2l0cyA9IDIpIHw+CiAga2FibGVfc3R5bGluZyhmdWxsX3dpZHRoID0gRkFMU0UsIGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJob3ZlciIpKQpgYGAKCiMjIERpc3RyaWJ1acOnw7VlcyBlIGdydXBvcwoKYGBge3IgZGlzdHJpYnVpY29lcywgZmlnLmhlaWdodD02LjIsIGZpZy5jYXA9IkRpc3RyaWJ1acOnw7VlcyBkYXMgcXVhdHJvIG1lZGlkYXMgcG9yIGVzcMOpY2llLiBQb250b3MgZSBib3hwbG90cyB0b3JuYW0gYSBhbW9zdHJhIGUgYSBkaXNwZXJzw6NvIHZpc8OtdmVpcyBzZW0gZGVwZW5kZXIgYXBlbmFzIGRhcyBtw6lkaWFzLiJ9CmRhZG9zX2xvbmdvcyA8LSBkYWRvcyB8PgogIHBpdm90X2xvbmdlcigKICAgIGNvbHMgPSBjKFNlcGFsLkxlbmd0aCwgU2VwYWwuV2lkdGgsIFBldGFsLkxlbmd0aCwgUGV0YWwuV2lkdGgpLAogICAgbmFtZXNfdG8gPSAibWVkaWRhIiwKICAgIHZhbHVlc190byA9ICJ2YWxvciIKICApCgpnZ3Bsb3QoZGFkb3NfbG9uZ29zLCBhZXMoU3BlY2llcywgdmFsb3IsIGNvbG9yID0gU3BlY2llcykpICsKICBnZW9tX2JveHBsb3QoYWVzKGZpbGwgPSBTcGVjaWVzKSwgYWxwaGEgPSAwLjEyLCB3aWR0aCA9IDAuNTgsCiAgICAgICAgICAgICAgIG91dGxpZXIuc2hhcGUgPSBOQSwgbGluZXdpZHRoID0gMC41NSkgKwogIGdlb21faml0dGVyKHdpZHRoID0gMC4xNCwgYWxwaGEgPSAwLjU1LCBzaXplID0gMS4zNSkgKwogIGZhY2V0X3dyYXAofiBtZWRpZGEsIHNjYWxlcyA9ICJmcmVlX3kiLCBuY29sID0gMikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBwYWxldGFfZXNwZWNpZXMpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBwYWxldGFfZXNwZWNpZXMpICsKICBsYWJzKAogICAgdGl0bGUgPSAiTWVkaWRhcyBtb3Jmb2zDs2dpY2FzIHBvciBlc3DDqWNpZSIsCiAgICBzdWJ0aXRsZSA9ICIxNTAgZmxvcmVzOyA1MCBvYnNlcnZhw6fDtWVzIHBvciBlc3DDqWNpZTsgdmFsb3JlcyBlbSBjZW50w61tZXRyb3MiLAogICAgeCA9IE5VTEwsIHkgPSAiVmFsb3IgKGNtKSIsIGNvbG9yID0gIkVzcMOpY2llIiwgZmlsbCA9ICJFc3DDqWNpZSIKICApICsKICBndWlkZXMoZmlsbCA9ICJub25lIikKYGBgCgoqKkxlaXR1cmEuKiogQSBlc3DDqWNpZSBzZXBhcmEgZm9ydGVtZW50ZSBhcyBtZWRpZGFzIGRhIHDDqXRhbGEgZSB0YW1iw6ltIHBhcnRlIGRvIGNvbXByaW1lbnRvIGRhIHPDqXBhbGEuIFBvcnRhbnRvLCB1bWEgcmVsYcOnw6NvIGFncmVnYWRhIGVudHJlIHDDqXRhbGEgZSBzw6lwYWxhIHBvZGUgbWlzdHVyYXIgZG9pcyBmZW7DtG1lbm9zOiBkaWZlcmVuw6dhcyAqKmVudHJlIGVzcMOpY2llcyoqIGUgdmFyaWHDp8OjbyAqKmRlbnRybyBkZSBjYWRhIGVzcMOpY2llKiouCgojIyBSZWxhw6fDtWVzIGJpdmFyaWFkYXMgbsOjbyBjb250YW0gYSBoaXN0w7NyaWEgY29tcGxldGEKCmBgYHtyIG1hdHJpei1wYXJlcywgZmlnLmhlaWdodD04LjIsIGZpZy5jYXA9Ik1hdHJpeiBkZSBwYXJlczogZGlzdHJpYnVpw6fDtWVzIG5hIGRpYWdvbmFsLCBjb3JyZWxhw6fDtWVzIG5vIHRyacOibmd1bG8gc3VwZXJpb3IgZSBkaXNwZXJzw7VlcyBubyB0cmnDom5ndWxvIGluZmVyaW9yLiJ9CkdHYWxseTo6Z2dwYWlycygKICBkYWRvcywKICBjb2x1bW5zID0gMTo0LAogIG1hcHBpbmcgPSBhZXMoY29sb3IgPSBTcGVjaWVzLCBhbHBoYSA9IDAuNyksCiAgdXBwZXIgPSBsaXN0KGNvbnRpbnVvdXMgPSBHR2FsbHk6OndyYXAoImNvciIsIHNpemUgPSAzLjQpKSwKICBkaWFnID0gbGlzdChjb250aW51b3VzID0gR0dhbGx5Ojp3cmFwKCJkZW5zaXR5RGlhZyIsIGFscGhhID0gMC4zNSkpCikgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBwYWxldGFfZXNwZWNpZXMpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBwYWxldGFfZXNwZWNpZXMpICsKICB0aGVtZV9idyhiYXNlX3NpemUgPSAxMCkKYGBgCgpgYGB7ciBjb3JyZWxhY29lc30KbWF0cml6X2NvciA8LSBjb3Ioc2VsZWN0KGRhZG9zLCBTZXBhbC5MZW5ndGg6UGV0YWwuV2lkdGgpKQpyb3VuZChtYXRyaXpfY29yLCAzKQpgYGAKCmBQZXRhbC5MZW5ndGhgIGUgYFBldGFsLldpZHRoYCB0w6ptIGNvcnJlbGHDp8OjbyBtdWl0byBhbHRhLiBJc3NvIHNpbmFsaXphIHBvc3PDrXZlbCBtdWx0aWNvbGluZWFyaWRhZGUsIG1hcyBhIGRlY2lzw6NvIG7Do28gZGV2ZSBzZXIgdG9tYWRhIHBvciB1bSBsaW1pYXIgbWVjw6JuaWNvIGRlIGNvcnJlbGHDp8Ojby4gTyBWSUYsIGEgZXN0YWJpbGlkYWRlIGRvcyBjb2VmaWNpZW50ZXMgZSBvIG9iamV0aXZvIGRvIG1vZGVsbyBjb21wbGV0YW0gbyBkaWFnbsOzc3RpY28uCgo8ZGl2IGNsYXNzPSJ3YXJuaW5nIj4KPHN0cm9uZz5Db3JyZcOnw6NvIGRlIHVtYSBhcm1hZGlsaGEgY29tdW0uPC9zdHJvbmc+IERvaXMgcHJlZGl0b3JlcyBwb3NpdGl2YW1lbnRlIGNvcnJlbGFjaW9uYWRvcyBuw6NvIHByZWNpc2FtIHRlciBjb2VmaWNpZW50ZXMgbcO6bHRpcGxvcyBjb20gbyBtZXNtbyBzaW5hbC4gQ2FkYSBjb2VmaWNpZW50ZSDDqSB1bSBlZmVpdG8gcGFyY2lhbCwgY29uZGljaW9uYWRvIGFvcyBkZW1haXMgdGVybW9zLiBVbWEgaW52ZXJzw6NvIGRlIHNpbmFsIHBvZGUgcmV2ZWxhciBjb2xpbmVhcmlkYWRlLCBjb25mdW5kaW1lbnRvIG91IHVtYSBwZXJndW50YSBjb25kaWNpb25hbCBkaWZlcmVudGUg4oCUIG7Do28gdW1hIGNvbnRyYWRpw6fDo28gbMOzZ2ljYSBhdXRvbcOhdGljYS4KPC9kaXY+CgpgYGB7ciByZWxhY2FvLWFncmVnYWRhLWdydXBvcywgZmlnLmhlaWdodD01LjgsIGZpZy5jYXA9IkEgbGluaGEgYWdyZWdhZGEgbWlzdHVyYSBkaWZlcmVuw6dhcyBlbnRyZSBlc3DDqWNpZXMgZSByZWxhw6fDtWVzIGRlbnRybyBkZSBjYWRhIGVzcMOpY2llLiJ9CnBfYWdyZWdhZG8gPC0gZ2dwbG90KGRhZG9zLCBhZXMoUGV0YWwuTGVuZ3RoLCBTZXBhbC5MZW5ndGgpKSArCiAgZ2VvbV9wb2ludChjb2xvciA9IGF6dWwsIGFscGhhID0gMC42NSkgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gVFJVRSwgY29sb3IgPSBhenVsX2VzY3VybywgZmlsbCA9ICIjRENFOEY3IikgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJSZWxhw6fDo28gYWdyZWdhZGEiLAogICAgc3VidGl0bGUgPSAiVW1hIMO6bmljYSByZXRhIHBhcmEgdG9kYXMgYXMgZmxvcmVzIiwKICAgIHggPSAiQ29tcHJpbWVudG8gZGEgcMOpdGFsYSAoY20pIiwgeSA9ICJDb21wcmltZW50byBkYSBzw6lwYWxhIChjbSkiCiAgKQoKcF9ncnVwb3MgPC0gZ2dwbG90KGRhZG9zLCBhZXMoUGV0YWwuTGVuZ3RoLCBTZXBhbC5MZW5ndGgsIGNvbG9yID0gU3BlY2llcykpICsKICBnZW9tX3BvaW50KGFscGhhID0gMC43MikgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UsIGxpbmV3aWR0aCA9IDAuOSkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBwYWxldGFfZXNwZWNpZXMpICsKICBsYWJzKAogICAgdGl0bGUgPSAiUmVsYcOnw7VlcyBwb3IgZXNww6ljaWUiLAogICAgc3VidGl0bGUgPSAiQSBpbmNsaW5hw6fDo28gcG9kZSB2YXJpYXIgZW50cmUgZ3J1cG9zIiwKICAgIHggPSAiQ29tcHJpbWVudG8gZGEgcMOpdGFsYSAoY20pIiwgeSA9ICJDb21wcmltZW50byBkYSBzw6lwYWxhIChjbSkiLAogICAgY29sb3IgPSAiRXNww6ljaWUiCiAgKQoKcF9hZ3JlZ2FkbyArIHBfZ3J1cG9zCmBgYAoKIyBDb25zdHJ1w6fDo28gcHJvZ3Jlc3NpdmEgZG9zIGNpbmNvIG1vZGVsb3MKCk9zIGNpbmNvIG1vZGVsb3Mgc2Vyw6NvIGFqdXN0YWRvcyBjb20gYXMgMTUwIG9ic2VydmHDp8O1ZXMuIEEgb3JkZW0gZm9pIGVzY29saGlkYSBwYXJhIHF1ZSBjYWRhIG5vdm8gYWp1c3RlIHJlc3BvbmRhIGEgdW1hIGTDunZpZGEgc3VyZ2lkYSBubyBtb2RlbG8gYW50ZXJpb3IuIEEgZGVjaXPDo28gc2Vyw6EgdG9tYWRhIHNvbWVudGUgZGVwb2lzIHF1ZSB0b2RvcyB0aXZlcmVtIHNpZG8gZXN0aW1hZG9zLCBpbnRlcnByZXRhZG9zIGUgY29tcGFyYWRvcy4KCiMjIENvbW8gbGVyIGEgc2HDrWRhIGRlIGBsbSgpYAoKLSAqKkVzdGltYXRlOioqIGVzdGltYXRpdmEgZGUgY2FkYSBjb2VmaWNpZW50ZSAkXGJldGFfaiQ7Ci0gKipTdGQuIEVycm9yOioqIGVycm8tcGFkcsOjbywgcXVlIG1lZGUgYSBpbmNlcnRlemEgZGEgZXN0aW1hdGl2YTsKLSAqKnQgdmFsdWUgZSBwLXZhbG9yOioqIHRlc3RlIGRlICRIXzA6IFxiZXRhX2o9MCQsIGNvbmRpY2lvbmFkbyBhb3MgZGVtYWlzIHRlcm1vcyBkbyBtb2RlbG87Ci0gKipSZXNpZHVhbCBzdGFuZGFyZCBlcnJvcjoqKiBlc2NhbGEgdMOtcGljYSBkb3MgcmVzw61kdW9zLCBlbSBjZW50w61tZXRyb3M7Ci0gKipNdWx0aXBsZSAkUl4yJDoqKiBwcm9wb3LDp8OjbyBkYSB2YXJpYWJpbGlkYWRlIG9ic2VydmFkYSBleHBsaWNhZGEgcGVsbyBhanVzdGU7Ci0gKipBZGp1c3RlZCAkUl4yJDoqKiB2ZXJzw6NvIGRvICRSXjIkIHF1ZSBjb25zaWRlcmEgbyBuw7ptZXJvIGRlIHBhcsOibWV0cm9zOwotICoqRi1zdGF0aXN0aWM6KiogdGVzdGUgZ2xvYmFsIGRvIG1vZGVsbyBjb250cmEgdW0gYWp1c3RlIHNvbWVudGUgY29tIGludGVyY2VwdG8uCgpPIGNvZWZpY2llbnRlIGVzdGltYWRvIGUgc2V1IGVycm8tcGFkcsOjbyBjdW1wcmVtIHBhcMOpaXMgZGlmZXJlbnRlcy4gQSBlc3RpbWF0aXZhIGluZGljYSBvIHRhbWFuaG8gZSBvIHNlbnRpZG8gZGEgYXNzb2NpYcOnw6NvOyBvIGVycm8tcGFkcsOjbyBpbmRpY2EgYSBwcmVjaXPDo28gZGVzc2EgZXN0aW1hdGl2YS4gRW0gdGVybW9zIHNpbXBsZXMsIGVsZSByZXN1bWUgcXVhbnRvIGEgZXN0aW1hdGl2YSB0ZW5kZXJpYSBhIHZhcmlhciBzZSByZXBldMOtc3NlbW9zIGEgY29sZXRhIGUgbyBhanVzdGUgbXVpdGFzIHZlemVzIHNvYiBjb25kacOnw7VlcyBzZW1lbGhhbnRlcy4gTyB2YWxvciBkZSAkdCQgw6kgY2FsY3VsYWRvIHBvciAkdD1cd2lkZWhhdFxiZXRhL0VQKFx3aWRlaGF0XGJldGEpJDogcGFyYSB1bSBtZXNtbyBjb2VmaWNpZW50ZSwgbWFpb3IgZXJyby1wYWRyw6NvIGltcGxpY2EgbWVub3IgcHJlY2lzw6NvIGUgbWVub3IgZXZpZMOqbmNpYSBjb250cmEgJEhfMDpcYmV0YT0wJC4KCiMjIE1vZGVsbyAxIOKAlCB0b2RhcyBhcyBtZWRpZGFzIG51bcOpcmljYXMKCk8gcHJpbWVpcm8gYWp1c3RlIHV0aWxpemEgYXMgdHLDqnMgbWVkaWRhcyBkaXNwb27DrXZlaXMgY29tbyBwcmVkaXRvcmFzIGUgYWluZGEgbsOjbyBpbmNsdWkgYSBlc3DDqWNpZToKCiQkCllfaT1cYmV0YV8wK1xiZXRhXzFcLFNlcGFsLldpZHRoX2krXGJldGFfMlwsUGV0YWwuTGVuZ3RoX2krClxiZXRhXzNcLFBldGFsLldpZHRoX2krXHZhcmVwc2lsb25faS4KJCQKCmBgYHtyIG1vZGVsbzF9Cm1vZGVsbzEgPC0gbG0oCiAgU2VwYWwuTGVuZ3RoIH4gU2VwYWwuV2lkdGggKyBQZXRhbC5MZW5ndGggKyBQZXRhbC5XaWR0aCwKICBkYXRhID0gZGFkb3MKKQoKc3VtbWFyeShtb2RlbG8xKQoKdGFiZWxhX2NvZWZpY2llbnRlcyhtb2RlbG8xKSB8PgogIGtuaXRyOjprYWJsZShkaWdpdHMgPSAzKSB8PgogIGthYmxlX3N0eWxpbmcoZnVsbF93aWR0aCA9IEZBTFNFLCBib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG92ZXIiKSkKYGBgCgpBIGVxdWHDp8OjbyBhanVzdGFkYSDDqToKCiQkClx3aWRlaGF0e1NlcGFsLkxlbmd0aH09CmByIGZtdF9udW0oY29lZihtb2RlbG8xKVsiKEludGVyY2VwdCkiXSlgCmByIGZtdF9wYXJjZWxhKGNvZWYobW9kZWxvMSlbIlNlcGFsLldpZHRoIl0pYFwsU2VwYWwuV2lkdGgKYHIgZm10X3BhcmNlbGEoY29lZihtb2RlbG8xKVsiUGV0YWwuTGVuZ3RoIl0pYFwsUGV0YWwuTGVuZ3RoCmByIGZtdF9wYXJjZWxhKGNvZWYobW9kZWxvMSlbIlBldGFsLldpZHRoIl0pYFwsUGV0YWwuV2lkdGguCiQkCgojIyMgQ29tZW50w6FyaW9zIGUgb2JzZXJ2YcOnw7VlcyBzb2JyZSBvIE1vZGVsbyAxCgpPIG1vZGVsbyDDqSBnbG9iYWxtZW50ZSBzaWduaWZpY2F0aXZvIGUgYXByZXNlbnRhICRSXjIkIGFqdXN0YWRvIGlndWFsIGEgYHIgZm10X251bShzdW1tYXJ5KG1vZGVsbzEpJGFkai5yLnNxdWFyZWQpYCwgb3UgYXByb3hpbWFkYW1lbnRlIGByIGZtdF9udW0oMTAwICogc3VtbWFyeShtb2RlbG8xKSRhZGouci5zcXVhcmVkLCAxKWAlIGRhIHZhcmlhYmlsaWRhZGUgZXhwbGljYWRhIGFww7NzIGEgY29ycmXDp8OjbyBwZWxvIG7Dum1lcm8gZGUgcGFyw6JtZXRyb3MuIFRvZGFzIGFzIHZhcmnDoXZlaXMgdMOqbSBwLXZhbG9yIGluZmVyaW9yIGEgMCwwNS4KClZhbW9zIGlzb2xhciBvcyBlcnJvcy1wYWRyw6NvIGRvcyB0csOqcyBwcmVkaXRvcmVzIHBhcmEgdG9ybmFyIGEgY29tcGFyYcOnw6NvIGV4cGzDrWNpdGE6CgpgYGB7ciBjb21wYXJhY2FvLWVycm9zLXBhZHJhby1tb2RlbG8xfQpjb21wYXJhY2FvX2VwX21vZGVsbzEgPC0gdGlkeShtb2RlbG8xKSB8PgogIGZpbHRlcih0ZXJtICE9ICIoSW50ZXJjZXB0KSIpIHw+CiAgdHJhbnNtdXRlKAogICAgdmFyaWF2ZWwgPSB0ZXJtLAogICAgZXN0aW1hdGl2YSA9IGVzdGltYXRlLAogICAgYGVycm8tcGFkcsOjb2AgPSBzdGQuZXJyb3IsCiAgICBgRVAgLyB8ZXN0aW1hdGl2YXwgKCUpYCA9IDEwMCAqIHN0ZC5lcnJvciAvIGFicyhlc3RpbWF0ZSksCiAgICBgRVAgZW0gcmVsYcOnw6NvIGFvIG1lbm9yIEVQYCA9IHN0ZC5lcnJvciAvIG1pbihzdGQuZXJyb3IpCiAgKQoKY29tcGFyYWNhb19lcF9tb2RlbG8xIHw+CiAga25pdHI6OmthYmxlKGRpZ2l0cyA9IDMpIHw+CiAga2FibGVfc3R5bGluZyhmdWxsX3dpZHRoID0gRkFMU0UsIGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJob3ZlciIpKQpgYGAKCkRvaXMgcmVzdWx0YWRvcyBkYSBwcsOzcHJpYSBzYcOtZGEgZG8gTW9kZWxvIDEgbWVyZWNlbSBhdGVuw6fDo286CgoxLiBvIGVycm8tcGFkcsOjbyBkZSBgUGV0YWwuV2lkdGhgIMOpIGByIGZtdF9udW0odGlkeShtb2RlbG8xKSRzdGQuZXJyb3JbdGlkeShtb2RlbG8xKSR0ZXJtID09ICJQZXRhbC5XaWR0aCJdKWAsIGNvbnRyYSBgciBmbXRfbnVtKHRpZHkobW9kZWxvMSkkc3RkLmVycm9yW3RpZHkobW9kZWxvMSkkdGVybSA9PSAiU2VwYWwuV2lkdGgiXSlgIHBhcmEgYFNlcGFsLldpZHRoYCBlIGByIGZtdF9udW0odGlkeShtb2RlbG8xKSRzdGQuZXJyb3JbdGlkeShtb2RlbG8xKSR0ZXJtID09ICJQZXRhbC5MZW5ndGgiXSlgIHBhcmEgYFBldGFsLkxlbmd0aGAuIFBvcnRhbnRvLCBlbGUgw6kgYXByb3hpbWFkYW1lbnRlIGByIGZtdF9udW0odGlkeShtb2RlbG8xKSRzdGQuZXJyb3JbdGlkeShtb2RlbG8xKSR0ZXJtID09ICJQZXRhbC5XaWR0aCJdIC8gdGlkeShtb2RlbG8xKSRzdGQuZXJyb3JbdGlkeShtb2RlbG8xKSR0ZXJtID09ICJTZXBhbC5XaWR0aCJdLCAyKWAgdmV6IG8gZXJyby1wYWRyw6NvIGRlIGBTZXBhbC5XaWR0aGAgZSBgciBmbXRfbnVtKHRpZHkobW9kZWxvMSkkc3RkLmVycm9yW3RpZHkobW9kZWxvMSkkdGVybSA9PSAiUGV0YWwuV2lkdGgiXSAvIHRpZHkobW9kZWxvMSkkc3RkLmVycm9yW3RpZHkobW9kZWxvMSkkdGVybSA9PSAiUGV0YWwuTGVuZ3RoIl0sIDIpYCB2ZXplcyBvIGRlIGBQZXRhbC5MZW5ndGhgOwoyLiBgUGV0YWwuTGVuZ3RoYCBhcHJlc2VudGEgY29lZmljaWVudGUgcG9zaXRpdm8gKGByIGZtdF9udW0oY29lZihtb2RlbG8xKVsiUGV0YWwuTGVuZ3RoIl0pYCksIGVucXVhbnRvIGBQZXRhbC5XaWR0aGAgYXByZXNlbnRhIGNvZWZpY2llbnRlIG5lZ2F0aXZvIChgciBmbXRfbnVtKGNvZWYobW9kZWxvMSlbIlBldGFsLldpZHRoIl0pYCksIGFwZXNhciBkYSBmb3J0ZSBjb3JyZWxhw6fDo28gcG9zaXRpdmEgZW50cmUgYW1iYXMuCgpDb21vIHRvZG9zIG9zIHRyw6pzIHByZWRpdG9yZXMgZXN0w6NvIG1lZGlkb3MgZW0gY2VudMOtbWV0cm9zLCBhIGNvbXBhcmHDp8OjbyBkaXJldGEgZG9zIGVycm9zLXBhZHLDo28gw6kgaW5mb3JtYXRpdmEgbmVzdGUgZXhlbXBsby4gTWVzbW8gYXNzaW0sIHVtIGVycm8tcGFkcsOjbyBtYWlvciBuw6NvIGRldmUgc2VyIGludGVycHJldGFkbyBpc29sYWRhbWVudGU6IGVsZSB0YW1iw6ltIGRlcGVuZGUgZGEgZGlzcGVyc8OjbyBkYSB2YXJpw6F2ZWwsIGRvIHRhbWFuaG8gZGEgYW1vc3RyYSBlIGRhIHJlbGHDp8OjbyBkZXNzZSBwcmVkaXRvciBjb20gb3MgZGVtYWlzLiBBIGNvbHVuYSBwZXJjZW50dWFsIGRhIHRhYmVsYSBmb3JuZWNlIHVtYSBzZWd1bmRhIHJlZmVyw6puY2lhLCBjb21wYXJhbmRvIG8gZXJyby1wYWRyw6NvIGNvbSBvIHRhbWFuaG8gYWJzb2x1dG8gZGEgcmVzcGVjdGl2YSBlc3RpbWF0aXZhLgoKRXNzYSBpbnZlcnPDo28gZGUgc2luYWwgbsOjbyDDqSB1bWEgY29udHJhZGnDp8OjbyBtYXRlbcOhdGljYTogbmEgcmVncmVzc8OjbyBtw7psdGlwbGEsIGNhZGEgY29lZmljaWVudGUgcmVwcmVzZW50YSB1bWEgYXNzb2NpYcOnw6NvICoqcGFyY2lhbCoqLCBtYW50ZW5kbyBvcyBkZW1haXMgcHJlZGl0b3JlcyBjb25zdGFudGVzLiBDb250dWRvLCBjb21iaW5hZGEgY29tIGEgY29ycmVsYcOnw6NvIGRlIGFwcm94aW1hZGFtZW50ZSAwLDk2MywgZWxhIHN1Z2VyZSBxdWUgYXMgZHVhcyBtZWRpZGFzIGRhIHDDqXRhbGEgY29tcGV0ZW0gcGFyYSBleHBsaWNhciBhIG1lc21hIHBhcmNlbGEgZGEgcmVzcG9zdGEuIFBhcmEgcXVhbnRpZmljYXIgZXNzZSBwcm9ibGVtYSwgY2FsY3VsYW1vcyBvIFZJRi4KCiMjIyBPIHF1ZSDDqSBWSUY/CgoqKlZJRioqIHNpZ25pZmljYSAqVmFyaWFuY2UgSW5mbGF0aW9uIEZhY3RvciosIG91ICoqZmF0b3IgZGUgaW5mbGHDp8OjbyBkYSB2YXJpw6JuY2lhKiouIFBhcmEgbyBwcmVkaXRvciAkWF9qJCwKCiQkClZJRl9qPVxmcmFjezF9ezEtUl9qXjJ9LAokJAoKZW0gcXVlICRSX2peMiQgdmVtIGRlIHVtYSByZWdyZXNzw6NvIGF1eGlsaWFyIGRlICRYX2okIGNvbnRyYSB0b2RvcyBvcyBvdXRyb3MgcHJlZGl0b3Jlcy4gU2Ugb3MgZGVtYWlzIHByZWRpdG9yZXMgcXVhc2UgY29uc2VndWVtIHJlY29uc3RydWlyICRYX2okLCBlc3NlICRSX2peMiQgZmljYSBwcsOzeGltbyBkZSAxIGUgbyBWSUYgY3Jlc2NlLgoKTyBWSUYgaW5mb3JtYSBwb3IgcXVhbnRvIGEgKip2YXJpw6JuY2lhKiogZXN0aW1hZGEgZGUgJFx3aWRlaGF0XGJldGFfaiQgZm9pIGluZmxhZGEgcGVsYSByZWxhw6fDo28gbGluZWFyIGVudHJlIG9zIHByZWRpdG9yZXMuIEEgcmFpeiBxdWFkcmFkYSBkbyBWSUYgaW5mb3JtYSBhcHJveGltYWRhbWVudGUgcG9yIHF1YW50byBvICoqZXJyby1wYWRyw6NvKiogZm9pIGluZmxhZG8gZW0gY29tcGFyYcOnw6NvIGNvbSB1bWEgc2l0dWHDp8OjbyBpZGVhbCBkZSBwcmVkaXRvcmVzIG7Do28gY29ycmVsYWNpb25hZG9zLiBBIHRvbGVyw6JuY2lhIMOpICQxL1ZJRiQ7IHZhbG9yZXMgcGVxdWVub3Mgc2lnbmlmaWNhbSBxdWUgcmVzdGEgcG91Y2EgaW5mb3JtYcOnw6NvIGV4Y2x1c2l2YSBuYXF1ZWxlIHByZWRpdG9yLgoKYGBge3IgdmlmLW1vZGVsbzF9CnZpZl9tb2RlbG8xIDwtIHBlcmZvcm1hbmNlOjpjaGVja19jb2xsaW5lYXJpdHkobW9kZWxvMSkgfD4KICBhcy5kYXRhLmZyYW1lKCkgfD4KICB0cmFuc211dGUoCiAgICB2YXJpYXZlbCA9IFRlcm0sCiAgICBWSUYgPSBWSUYsCiAgICBgcmFpeiBkbyBWSUZgID0gc3FydChWSUYpLAogICAgdG9sZXJhbmNpYSA9IFRvbGVyYW5jZSwKICAgIFIyX3JlZ3Jlc3Nhb19hdXhpbGlhciA9IDEgLSAxIC8gVklGCiAgKQoKdmlmX21vZGVsbzEgfD4KICByZW5hbWUoYFLCsiBkYSByZWdyZXNzw6NvIGF1eGlsaWFyYCA9IFIyX3JlZ3Jlc3Nhb19hdXhpbGlhcikgfD4KICBrbml0cjo6a2FibGUoZGlnaXRzID0gMykgfD4KICBrYWJsZV9zdHlsaW5nKGZ1bGxfd2lkdGggPSBGQUxTRSwgYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImhvdmVyIikpCmBgYAoKUGFyYSBgU2VwYWwuV2lkdGhgLCBvIFZJRiDDqSBiYWl4byAoYHIgZm10X251bSh2aWZfbW9kZWxvMSRWSUZbdmlmX21vZGVsbzEkdmFyaWF2ZWwgPT0gIlNlcGFsLldpZHRoIl0sIDIpYCkuIFBhcmEgYFBldGFsLkxlbmd0aGAgZSBgUGV0YWwuV2lkdGhgLCBvcyBWSUYgc8OjbyBgciBmbXRfbnVtKHZpZl9tb2RlbG8xJFZJRlt2aWZfbW9kZWxvMSR2YXJpYXZlbCA9PSAiUGV0YWwuTGVuZ3RoIl0sIDIpYCBlIGByIGZtdF9udW0odmlmX21vZGVsbzEkVklGW3ZpZl9tb2RlbG8xJHZhcmlhdmVsID09ICJQZXRhbC5XaWR0aCJdLCAyKWAuIElzc28gc2lnbmlmaWNhIHF1ZSBhcHJveGltYWRhbWVudGUgYHIgZm10X251bSgxMDAgKiB2aWZfbW9kZWxvMSRSMl9yZWdyZXNzYW9fYXV4aWxpYXJbdmlmX21vZGVsbzEkdmFyaWF2ZWwgPT0gIlBldGFsLkxlbmd0aCJdLCAxKWAlIGRhIHZhcmlhw6fDo28gZGUgYFBldGFsLkxlbmd0aGAgZSBgciBmbXRfbnVtKDEwMCAqIHZpZl9tb2RlbG8xJFIyX3JlZ3Jlc3Nhb19hdXhpbGlhclt2aWZfbW9kZWxvMSR2YXJpYXZlbCA9PSAiUGV0YWwuV2lkdGgiXSwgMSlgJSBkYSB2YXJpYcOnw6NvIGRlIGBQZXRhbC5XaWR0aGAgcG9kZW0gc2VyIGV4cGxpY2FkYXMgcGVsb3Mgb3V0cm9zIHByZWRpdG9yZXMgZG8gbW9kZWxvLiBBcyByYcOtemVzIGRvcyBWSUYsIHByw7N4aW1hcyBkZSBgciBmbXRfbnVtKHNxcnQodmlmX21vZGVsbzEkVklGW3ZpZl9tb2RlbG8xJHZhcmlhdmVsID09ICJQZXRhbC5MZW5ndGgiXSksIDIpYCBlIGByIGZtdF9udW0oc3FydCh2aWZfbW9kZWxvMSRWSUZbdmlmX21vZGVsbzEkdmFyaWF2ZWwgPT0gIlBldGFsLldpZHRoIl0pLCAyKWAsIGV2aWRlbmNpYW0gdW1hIGluZmxhw6fDo28gaW1wb3J0YW50ZSBkYSBpbmNlcnRlemEgZG9zIGNvZWZpY2llbnRlcy4KClJlZ3JhcyBjb21vIOKAnFZJRiBtYWlvciBxdWUgNSBleGlnZSBhdGVuw6fDo2/igJ0gZSDigJxWSUYgbWFpb3IgcXVlIDEwIGluZGljYSBjb2xpbmVhcmlkYWRlIGZvcnRl4oCdIHPDo28gcmVmZXLDqm5jaWFzIHByw6F0aWNhcywgbsOjbyBsZWlzIHVuaXZlcnNhaXMuIEFxdWksIHZhbG9yZXMgYWNpbWEgZGUgMTQsIGNvcnJlbGHDp8OjbyBkZSAwLDk2MyBlIG11ZGFuw6dhIGRlIHNpbmFsIGNvbnRhbSB1bWEgaGlzdMOzcmlhIGNvZXJlbnRlOiBvcyBlZmVpdG9zIGluZGl2aWR1YWlzIGRhcyBkdWFzIG1lZGlkYXMgZGEgcMOpdGFsYSBzw6NvIGRpZsOtY2VpcyBkZSBzZXBhcmFyIGNvbSBlc3RhYmlsaWRhZGUuCgo8ZGl2IGNsYXNzPSJ3YXJuaW5nIj4KPHN0cm9uZz5MZWl0dXJhIGNvcnJldGEgZGEgbXVsdGljb2xpbmVhcmlkYWRlLjwvc3Ryb25nPiBPIG1vZGVsbyBhaW5kYSBwb2RlIGFqdXN0YXIgYmVtIG9zIGRhZG9zLiBPIHByaW5jaXBhbCBwcmVqdcOtem8gZXN0w6EgbmEgc2VwYXJhw6fDo28gZSBpbnRlcnByZXRhw6fDo28gZG9zIGVmZWl0b3MgaW5kaXZpZHVhaXMsIG5vcyBlcnJvcy1wYWRyw6NvIGUgbmEgZXN0YWJpbGlkYWRlIGRvcyBjb2VmaWNpZW50ZXMuCjwvZGl2PgoKIyMgTW9kZWxvIDIg4oCUIHJldGlyYWRhIGRlIGBQZXRhbC5XaWR0aGAKCkNvbW8gYFBldGFsLkxlbmd0aGAgYXByZXNlbnRhIGFzc29jaWHDp8OjbyBtYWlzIGZvcnRlIGNvbSBhIHJlc3Bvc3RhIGUgYXMgZHVhcyBtZWRpZGFzIGRhIHDDqXRhbGEgc8OjbyBtdWl0byBjb3JyZWxhY2lvbmFkYXMsIG8gc2VndW5kbyBtb2RlbG8gcmV0aXJhIGBQZXRhbC5XaWR0aGA6CgokJApZX2k9XGJldGFfMCtcYmV0YV8xXCxTZXBhbC5XaWR0aF9pK1xiZXRhXzJcLFBldGFsLkxlbmd0aF9pK1x2YXJlcHNpbG9uX2kuCiQkCgpgYGB7ciBtb2RlbG8yfQptb2RlbG8yIDwtIGxtKAogIFNlcGFsLkxlbmd0aCB+IFNlcGFsLldpZHRoICsgUGV0YWwuTGVuZ3RoLAogIGRhdGEgPSBkYWRvcwopCgpzdW1tYXJ5KG1vZGVsbzIpCgp0YWJlbGFfY29lZmljaWVudGVzKG1vZGVsbzIpIHw+CiAga25pdHI6OmthYmxlKGRpZ2l0cyA9IDMpIHw+CiAga2FibGVfc3R5bGluZyhmdWxsX3dpZHRoID0gRkFMU0UsIGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJob3ZlciIpKQpgYGAKCkEgZXF1YcOnw6NvIGFqdXN0YWRhIMOpOgoKJCQKXHdpZGVoYXR7U2VwYWwuTGVuZ3RofT0KYHIgZm10X251bShjb2VmKG1vZGVsbzIpWyIoSW50ZXJjZXB0KSJdKWAKYHIgZm10X3BhcmNlbGEoY29lZihtb2RlbG8yKVsiU2VwYWwuV2lkdGgiXSlgXCxTZXBhbC5XaWR0aApgciBmbXRfcGFyY2VsYShjb2VmKG1vZGVsbzIpWyJQZXRhbC5MZW5ndGgiXSlgXCxQZXRhbC5MZW5ndGguCiQkCgojIyMgQ29tZW50w6FyaW9zIGUgaW50ZXJwcmV0YcOnw6NvIGRvIE1vZGVsbyAyCgpPIG1vZGVsbyBwZXJtYW5lY2UgZ2xvYmFsbWVudGUgc2lnbmlmaWNhdGl2byBlIGV4cGxpY2EgYXByb3hpbWFkYW1lbnRlIGByIGZtdF9udW0oMTAwICogc3VtbWFyeShtb2RlbG8yKSRhZGouci5zcXVhcmVkLCAxKWAlIGRhIHZhcmlhYmlsaWRhZGUgZG8gY29tcHJpbWVudG8gZGEgc8OpcGFsYSwgc2VndW5kbyBvICRSXjIkIGFqdXN0YWRvLgoKLSBNYW50ZW5kbyBvIGNvbXByaW1lbnRvIGRhIHDDqXRhbGEgY29uc3RhbnRlLCBvIGF1bWVudG8gZGUgMSBjbSBlbSBgU2VwYWwuV2lkdGhgIGVzdMOhIGFzc29jaWFkbyBhIHVtIGF1bWVudG8gbcOpZGlvIGVzdGltYWRvIGRlIGByIGZtdF9udW0oY29lZihtb2RlbG8yKVsiU2VwYWwuV2lkdGgiXSlgIGNtIGVtIGBTZXBhbC5MZW5ndGhgLgotIE1hbnRlbmRvIGEgbGFyZ3VyYSBkYSBzw6lwYWxhIGNvbnN0YW50ZSwgbyBhdW1lbnRvIGRlIDEgY20gZW0gYFBldGFsLkxlbmd0aGAgZXN0w6EgYXNzb2NpYWRvIGEgdW0gYXVtZW50byBtw6lkaW8gZXN0aW1hZG8gZGUgYHIgZm10X251bShjb2VmKG1vZGVsbzIpWyJQZXRhbC5MZW5ndGgiXSlgIGNtIGVtIGBTZXBhbC5MZW5ndGhgLgoKQXMgZHVhcyBhc3NvY2lhw6fDtWVzIHPDo28gcG9zaXRpdmFzLCBlc3RhdGlzdGljYW1lbnRlIHNpZ25pZmljYXRpdmFzIGUgc2ltcGxlcyBkZSBjb211bmljYXIuIEEgcmV0aXJhZGEgZGUgYFBldGFsLldpZHRoYCByZWR1eiBhIGNvbGluZWFyaWRhZGUgZSBjdXN0YSBjZXJjYSBkZSBgciBmbXRfbnVtKDEwMCAqIChzdW1tYXJ5KG1vZGVsbzEpJGFkai5yLnNxdWFyZWQgLSBzdW1tYXJ5KG1vZGVsbzIpJGFkai5yLnNxdWFyZWQpLCAxKWAgcG9udG8gcGVyY2VudHVhbCBkZSAkUl4yJCBhanVzdGFkbyBlbSByZWxhw6fDo28gYW8gTW9kZWxvIDEuCgojIyBNb2RlbG8gMyDigJQgcmV0aXJhZGEgZGUgYFBldGFsLkxlbmd0aGAKClBhcmEgYXZhbGlhciBhIGFsdGVybmF0aXZhIG9wb3N0YSwgcmV0aXJhbW9zIGBQZXRhbC5MZW5ndGhgIGUgbWFudGVtb3MgYFBldGFsLldpZHRoYDoKCiQkCllfaT1cYmV0YV8wK1xiZXRhXzFcLFNlcGFsLldpZHRoX2krXGJldGFfMlwsUGV0YWwuV2lkdGhfaStcdmFyZXBzaWxvbl9pLgokJAoKYGBge3IgbW9kZWxvM30KbW9kZWxvMyA8LSBsbSgKICBTZXBhbC5MZW5ndGggfiBTZXBhbC5XaWR0aCArIFBldGFsLldpZHRoLAogIGRhdGEgPSBkYWRvcwopCgpzdW1tYXJ5KG1vZGVsbzMpCgp0YWJlbGFfY29lZmljaWVudGVzKG1vZGVsbzMpIHw+CiAga25pdHI6OmthYmxlKGRpZ2l0cyA9IDMpIHw+CiAga2FibGVfc3R5bGluZyhmdWxsX3dpZHRoID0gRkFMU0UsIGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJob3ZlciIpKQpgYGAKCkEgZXF1YcOnw6NvIGFqdXN0YWRhIMOpOgoKJCQKXHdpZGVoYXR7U2VwYWwuTGVuZ3RofT0KYHIgZm10X251bShjb2VmKG1vZGVsbzMpWyIoSW50ZXJjZXB0KSJdKWAKYHIgZm10X3BhcmNlbGEoY29lZihtb2RlbG8zKVsiU2VwYWwuV2lkdGgiXSlgXCxTZXBhbC5XaWR0aApgciBmbXRfcGFyY2VsYShjb2VmKG1vZGVsbzMpWyJQZXRhbC5XaWR0aCJdKWBcLFBldGFsLldpZHRoLgokJAoKIyMjIENvbWVudMOhcmlvcyBlIGludGVycHJldGHDp8OjbyBkbyBNb2RlbG8gMwoKQXMgZHVhcyB2YXJpw6F2ZWlzIHRhbWLDqW0gc8OjbyBzaWduaWZpY2F0aXZhcywgbWFzIG8gJFJeMiQgYWp1c3RhZG8gY2FpIHBhcmEgYHIgZm10X251bShzdW1tYXJ5KG1vZGVsbzMpJGFkai5yLnNxdWFyZWQpYC4gTWFudGVuZG8gYFBldGFsLldpZHRoYCBjb25zdGFudGUsIG8gYXVtZW50byBkZSAxIGNtIGVtIGBTZXBhbC5XaWR0aGAgZXN0w6EgYXNzb2NpYWRvIGEgYHIgZm10X251bShjb2VmKG1vZGVsbzMpWyJTZXBhbC5XaWR0aCJdKWAgY20gYWRpY2lvbmFpcyBubyBjb21wcmltZW50byBtw6lkaW8gZGEgc8OpcGFsYS4gTWFudGVuZG8gYFNlcGFsLldpZHRoYCBjb25zdGFudGUsIDEgY20gYWRpY2lvbmFsIGVtIGBQZXRhbC5XaWR0aGAgZXN0w6EgYXNzb2NpYWRvIGEgYHIgZm10X251bShjb2VmKG1vZGVsbzMpWyJQZXRhbC5XaWR0aCJdKWAgY20gYWRpY2lvbmFpcyBuYSByZXNwb3N0YS4KCk8gYWp1c3RlIGluZmVyaW9yIGFvIGRvIE1vZGVsbyAyIMOpIGNvZXJlbnRlIGNvbSBhIGV4cGxvcmHDp8OjbzogYFBldGFsLldpZHRoYCB0ZW0gY29ycmVsYcOnw6NvIHRvdGFsIHVtIHBvdWNvIG1lbm9yIGNvbSBgU2VwYWwuTGVuZ3RoYCBxdWUgYFBldGFsLkxlbmd0aGAuIEVudHJlIG9zIGRvaXMgbW9kZWxvcyBxdWUgZWxpbWluYW0gdW1hIGRhcyBtZWRpZGFzIGNvbGluZWFyZXMsIG8gTW9kZWxvIDIgcHJlc2VydmEgbWFpcyBpbmZvcm1hw6fDo28uCgojIyBQcmVwYXJhw6fDo28gcGFyYSBvcyBNb2RlbG9zIDQgZSA1IOKAlCB2YXJpw6F2ZWwgYFNwZWNpZXNgCgpBIGVzcMOpY2llIHBvc3N1aSB0csOqcyBjYXRlZ29yaWFzLiBPIFIgdXNhIGBzZXRvc2FgIGNvbW8gcmVmZXLDqm5jaWEgZSBjcmlhIGR1YXMgdmFyacOhdmVpcyBpbmRpY2Fkb3JhczoKCnwgRXNww6ljaWUgfCAkWl8xJDogdmVyc2ljb2xvciB8ICRaXzIkOiB2aXJnaW5pY2EgfAp8LS0tfC0tLTp8LS0tOnwKfCBzZXRvc2EgfCAwIHwgMCB8CnwgdmVyc2ljb2xvciB8IDEgfCAwIHwKfCB2aXJnaW5pY2EgfCAwIHwgMSB8CgpgYGB7ciBkdW1taWVzLXNwZWNpZXN9CmxldmVscyhkYWRvcyRTcGVjaWVzKQpjb250cmFzdHMoZGFkb3MkU3BlY2llcykKCmFtb3N0cmFfZHVtbWllcyA8LSBkYWRvc1tjKDEsIDUxLCAxMDEpLCBdIHw+CiAgYmluZF9jb2xzKAogICAgYXMuZGF0YS5mcmFtZShtb2RlbC5tYXRyaXgofiBTcGVjaWVzLCBkYXRhID0gZGFkb3NbYygxLCA1MSwgMTAxKSwgXSlbLCAtMV0pCiAgKQoKYW1vc3RyYV9kdW1taWVzIHw+CiAgc2VsZWN0KGlkLCBTcGVjaWVzLCBTcGVjaWVzdmVyc2ljb2xvciwgU3BlY2llc3ZpcmdpbmljYSkgfD4KICBrbml0cjo6a2FibGUoKSB8PgogIGthYmxlX3N0eWxpbmcoZnVsbF93aWR0aCA9IEZBTFNFLCBib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG92ZXIiKSkKYGBgCgpBc3NpbSwgZG9pcyBjb2VmaWNpZW50ZXMgYmFzdGFtIHBhcmEgcmVwcmVzZW50YXIgdHLDqnMgY2F0ZWdvcmlhcyBzZW0gY3JpYXIgZGVwZW5kw6puY2lhIGxpbmVhciBwZXJmZWl0YSBjb20gbyBpbnRlcmNlcHRvLgoKIyMgTW9kZWxvIDQg4oCUIG1lZGlkYXMgc2VsZWNpb25hZGFzIGUgZXNww6ljaWUKCk8gcXVhcnRvIG1vZGVsbyBhY3Jlc2NlbnRhIGBTcGVjaWVzYCBhbyBNb2RlbG8gMjoKCiQkCllfaT1cYmV0YV8wK1xiZXRhXzFcLFNlcGFsLldpZHRoX2krXGJldGFfMlwsUGV0YWwuTGVuZ3RoX2krClxiZXRhXzMgWl97MWl9K1xiZXRhXzQgWl97Mml9K1x2YXJlcHNpbG9uX2kuCiQkCgpgYGB7ciBtb2RlbG80fQptb2RlbG80IDwtIGxtKAogIFNlcGFsLkxlbmd0aCB+IFNlcGFsLldpZHRoICsgUGV0YWwuTGVuZ3RoICsgU3BlY2llcywKICBkYXRhID0gZGFkb3MKKQoKc3VtbWFyeShtb2RlbG80KQoKdGFiZWxhX2NvZWZpY2llbnRlcyhtb2RlbG80KSB8PgogIGtuaXRyOjprYWJsZShkaWdpdHMgPSAzKSB8PgogIGthYmxlX3N0eWxpbmcoZnVsbF93aWR0aCA9IEZBTFNFLCBib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG92ZXIiKSkKYGBgCgpDb20gYHNldG9zYWAgY29tbyByZWZlcsOqbmNpYSwgYSBlcXVhw6fDo28gYWp1c3RhZGEgw6k6CgokJApcd2lkZWhhdHtTZXBhbC5MZW5ndGh9PQpgciBmbXRfbnVtKGNvZWYobW9kZWxvNClbIihJbnRlcmNlcHQpIl0pYApgciBmbXRfcGFyY2VsYShjb2VmKG1vZGVsbzQpWyJTZXBhbC5XaWR0aCJdKWBcLFNlcGFsLldpZHRoCmByIGZtdF9wYXJjZWxhKGNvZWYobW9kZWxvNClbIlBldGFsLkxlbmd0aCJdKWBcLFBldGFsLkxlbmd0aApgciBmbXRfcGFyY2VsYShjb2VmKG1vZGVsbzQpWyJTcGVjaWVzdmVyc2ljb2xvciJdKWBcLFpfMQpgciBmbXRfcGFyY2VsYShjb2VmKG1vZGVsbzQpWyJTcGVjaWVzdmlyZ2luaWNhIl0pYFwsWl8yLgokJAoKIyMjIENvbWVudMOhcmlvcyBlIG9ic2VydmHDp8O1ZXMgc29icmUgbyBNb2RlbG8gNAoKTyBNb2RlbG8gNCBhcHJlc2VudGEgbyBtYWlvciAkUl4yJCBhanVzdGFkbyBlbnRyZSBvcyBjaW5jbyBhanVzdGVzIChgciBmbXRfbnVtKHN1bW1hcnkobW9kZWxvNCkkYWRqLnIuc3F1YXJlZClgKSBlIHRvZG9zIG9zIHRlcm1vcyBzw6NvIHNpZ25pZmljYXRpdm9zLiBFbnRyZXRhbnRvLCBvcyBjb2VmaWNpZW50ZXMgZGUgYHZlcnNpY29sb3JgIGUgYHZpcmdpbmljYWAgZmljYW0gbmVnYXRpdm9zIGVtIHJlbGHDp8OjbyBhIGBzZXRvc2FgLCBvIHF1ZSBwYXJlY2UgZXN0cmFuaG8gZGlhbnRlIGRvcyBncsOhZmljb3MsIG5vcyBxdWFpcyBlc3NhcyBlc3DDqWNpZXMgdMOqbSBzw6lwYWxhcyBtYWlvcmVzLgoKUGFyYSBjb21wcmVlbmRlciBlc3NlIHJlc3VsdGFkbywgb2JzZXJ2ZSBxdWUgYFNwZWNpZXNgIGUgYFBldGFsLkxlbmd0aGAgZXN0w6NvIGZvcnRlbWVudGUgYXNzb2NpYWRvcy4gT3MgY29lZmljaWVudGVzIGRlIGVzcMOpY2llIG5vIE1vZGVsbyA0ICoqbsOjbyBjb21wYXJhbSBhcyBtw6lkaWFzIGJydXRhcyBkYXMgZXNww6ljaWVzKio7IGVsZXMgY29tcGFyYW0gZmxvcmVzIGRlIGVzcMOpY2llcyBkaWZlcmVudGVzIHF1ZSBwb3NzdWFtIG9zIG1lc21vcyB2YWxvcmVzIGRlIGBTZXBhbC5XaWR0aGAgZSBgUGV0YWwuTGVuZ3RoYC4gQ29tbyBow6EgcG91Y2Egc29icmVwb3Npw6fDo28gZGUgYFBldGFsLkxlbmd0aGAgZW50cmUgYHNldG9zYWAgZSBhcyBvdXRyYXMgZXNww6ljaWVzLCBlc3NhIGludGVycHJldGHDp8OjbyBjb25kaWNpb25hbCDDqSBmcsOhZ2lsIGUgcHLDs3hpbWEgZGUgdW1hIGV4dHJhcG9sYcOnw6NvLgoKYGBge3IgdmlmLW1vZGVsbzR9CnZpZl9tb2RlbG80IDwtIHBlcmZvcm1hbmNlOjpjaGVja19jb2xsaW5lYXJpdHkobW9kZWxvNCkgfD4KICBhcy5kYXRhLmZyYW1lKCkgfD4KICB0cmFuc211dGUoCiAgICB2YXJpYXZlbCA9IFRlcm0sCiAgICBgVklGL0dWSUYgYnJ1dG9gID0gVklGLAogICAgYGdyYXVzIGRlIGxpYmVyZGFkZWAgPSBpZmVsc2UoVGVybSA9PSAiU3BlY2llcyIsIG5sZXZlbHMoZGFkb3MkU3BlY2llcykgLSAxLCAxKSwKICAgIGBmYXRvciBjb21wYXLDoXZlbCBkZSBpbmZsYcOnw6NvIGRvIEVQYCA9IFZJRl4oMSAvICgyICogYGdyYXVzIGRlIGxpYmVyZGFkZWApKSwKICAgIHRvbGVyYW5jaWEgPSBUb2xlcmFuY2UKICApCgp2aWZfbW9kZWxvNCB8PgogIGtuaXRyOjprYWJsZShkaWdpdHMgPSAzKSB8PgogIGthYmxlX3N0eWxpbmcoZnVsbF93aWR0aCA9IEZBTFNFLCBib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG92ZXIiKSkKYGBgCgpQYXJhIGBQZXRhbC5MZW5ndGhgLCBvIFZJRiDDqSBgciBmbXRfbnVtKHZpZl9tb2RlbG80W1siVklGL0dWSUYgYnJ1dG8iXV1bdmlmX21vZGVsbzQkdmFyaWF2ZWwgPT0gIlBldGFsLkxlbmd0aCJdLCAyKWAgZSBvIGZhdG9yIGRlIGluZmxhw6fDo28gZG8gZXJyby1wYWRyw6NvIMOpIGByIGZtdF9udW0odmlmX21vZGVsbzRbWyJmYXRvciBjb21wYXLDoXZlbCBkZSBpbmZsYcOnw6NvIGRvIEVQIl1dW3ZpZl9tb2RlbG80JHZhcmlhdmVsID09ICJQZXRhbC5MZW5ndGgiXSwgMilgLiBQYXJhIGBTcGVjaWVzYCwgcXVlIHBvc3N1aSBkb2lzIGdyYXVzIGRlIGxpYmVyZGFkZSwgbyB2YWxvciBicnV0byDDqSB1bSAqKkdWSUYqKiBkZSBgciBmbXRfbnVtKHZpZl9tb2RlbG80W1siVklGL0dWSUYgYnJ1dG8iXV1bdmlmX21vZGVsbzQkdmFyaWF2ZWwgPT0gIlNwZWNpZXMiXSwgMilgOyBwYXJhIGNvbXBhcsOhLWxvIGNvbSB2YXJpw6F2ZWlzIGRlIHVtIGdyYXUgZGUgbGliZXJkYWRlLCB1c2Ftb3MgbyBmYXRvciBhanVzdGFkbyBgR1ZJRl4oMS8oMsOXZ2wpKWAsIGlndWFsIGEgYHIgZm10X251bSh2aWZfbW9kZWxvNFtbImZhdG9yIGNvbXBhcsOhdmVsIGRlIGluZmxhw6fDo28gZG8gRVAiXV1bdmlmX21vZGVsbzQkdmFyaWF2ZWwgPT0gIlNwZWNpZXMiXSwgMilgLiBQb3J0YW50bywgbyBNb2RlbG8gNCBvZmVyZWNlIG1lbGhvciBhanVzdGUgaW50ZXJubywgbWFzIHNldXMgY29lZmljaWVudGVzIGNvbmRpY2lvbmFpcyDigJQgc29icmV0dWRvIG9zIGNvbnRyYXN0ZXMgZGUgZXNww6ljaWUsIGFwb2lhZG9zIHBvciBwb3VjYSBzb2JyZXBvc2nDp8OjbyBkZSBgUGV0YWwuTGVuZ3RoYCDigJQgZXhpZ2VtIGNhdXRlbGEgZSBuw6NvIGRldmVtIHNlciB0cmF0YWRvcyBjb21vIGVmZWl0b3MgZXN0w6F2ZWlzIG91IGNhdXNhaXMuCgojIyBNb2RlbG8gNSDigJQgbGFyZ3VyYSBkYSBzw6lwYWxhIGUgZXNww6ljaWUKClBhcmEgb2J0ZXIgY29udHJhc3RlcyBkZSBlc3DDqWNpZSBtYWlzIGRpcmV0YW1lbnRlIGNvbXBhdMOtdmVpcyBjb20gYSBleHBsb3Jhw6fDo28gZ3LDoWZpY2EsIHJldGlyYW1vcyBgUGV0YWwuTGVuZ3RoYDoKCiQkCllfaT1cYmV0YV8wK1xiZXRhXzFcLFNlcGFsLldpZHRoX2krXGJldGFfMiBaX3sxaX0rXGJldGFfMyBaX3syaX0rXHZhcmVwc2lsb25faS4KJCQKCmBgYHtyIG1vZGVsbzV9Cm1vZGVsbzUgPC0gbG0oCiAgU2VwYWwuTGVuZ3RoIH4gU2VwYWwuV2lkdGggKyBTcGVjaWVzLAogIGRhdGEgPSBkYWRvcwopCgpzdW1tYXJ5KG1vZGVsbzUpCgp0YWJlbGFfY29lZmljaWVudGVzKG1vZGVsbzUpIHw+CiAga25pdHI6OmthYmxlKGRpZ2l0cyA9IDMpIHw+CiAga2FibGVfc3R5bGluZyhmdWxsX3dpZHRoID0gRkFMU0UsIGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJob3ZlciIpKQpgYGAKCkNvbSBgc2V0b3NhYCBjb21vIHJlZmVyw6puY2lhLCBhIGVxdWHDp8OjbyBhanVzdGFkYSDDqToKCiQkClx3aWRlaGF0e1NlcGFsLkxlbmd0aH09CmByIGZtdF9udW0oY29lZihtb2RlbG81KVsiKEludGVyY2VwdCkiXSlgCmByIGZtdF9wYXJjZWxhKGNvZWYobW9kZWxvNSlbIlNlcGFsLldpZHRoIl0pYFwsU2VwYWwuV2lkdGgKYHIgZm10X3BhcmNlbGEoY29lZihtb2RlbG81KVsiU3BlY2llc3ZlcnNpY29sb3IiXSlgXCxaXzEKYHIgZm10X3BhcmNlbGEoY29lZihtb2RlbG81KVsiU3BlY2llc3ZpcmdpbmljYSJdKWBcLFpfMi4KJCQKCiMjIyBDb21lbnTDoXJpb3MgZSBpbnRlcnByZXRhw6fDo28gZG8gTW9kZWxvIDUKCkFnb3JhIG9zIGNvZWZpY2llbnRlcyBkZSBlc3DDqWNpZSBhY29tcGFuaGFtIGFzIGRpZmVyZW7Dp2FzIG9ic2VydmFkYXMgbm9zIGdyw6FmaWNvczoKCi0gY29udHJvbGFuZG8gYFNlcGFsLldpZHRoYCwgZmxvcmVzIGB2ZXJzaWNvbG9yYCBhcHJlc2VudGFtIGNvbXByaW1lbnRvIG3DqWRpbyBkZSBzw6lwYWxhIGByIGZtdF9udW0oY29lZihtb2RlbG81KVsiU3BlY2llc3ZlcnNpY29sb3IiXSlgIGNtIG1haW9yIHF1ZSBmbG9yZXMgYHNldG9zYWA7Ci0gY29udHJvbGFuZG8gYFNlcGFsLldpZHRoYCwgZmxvcmVzIGB2aXJnaW5pY2FgIGFwcmVzZW50YW0gY29tcHJpbWVudG8gbcOpZGlvIGRlIHPDqXBhbGEgYHIgZm10X251bShjb2VmKG1vZGVsbzUpWyJTcGVjaWVzdmlyZ2luaWNhIl0pYCBjbSBtYWlvciBxdWUgZmxvcmVzIGBzZXRvc2FgLgoKQXMgaW50ZXJwcmV0YcOnw7VlcyBzw6NvIG1haXMgaW50dWl0aXZhcywgbWFzIG8gJFJeMiQgYWp1c3RhZG8gY2FpIHBhcmEgYHIgZm10X251bShzdW1tYXJ5KG1vZGVsbzUpJGFkai5yLnNxdWFyZWQpYCwgYmVtIGFiYWl4byBkbyBNb2RlbG8gMi4gUG9ydGFudG8sIHJldGlyYXIgYFBldGFsLkxlbmd0aGAgbWVsaG9yYSBhIGxlaXR1cmEgZG9zIGNvbnRyYXN0ZXMgZGUgZXNww6ljaWUsIHBvcsOpbSBlbGltaW5hIHVtYSB2YXJpw6F2ZWwgcXVhbnRpdGF0aXZhIG11aXRvIGluZm9ybWF0aXZhLgoKIyMgQWx0ZXJhbmRvIGEgY2F0ZWdvcmlhIGRlIHJlZmVyw6puY2lhCgpNdWRhciBhIHJlZmVyw6puY2lhIGFsdGVyYSBhIGZvcm1hIGRvcyBjb2VmaWNpZW50ZXMsIG1hcyBuw6NvIGFsdGVyYSByZXPDrWR1b3MsIHZhbG9yZXMgYWp1c3RhZG9zLCAkUl4yJCwgQUlDIG91IEJJQy4KCmBgYHtyIG11ZGFuY2EtcmVmZXJlbmNpYX0KZGFkb3NfcmVmX3ZpcmdpbmljYSA8LSBkYWRvcyB8PgogIG11dGF0ZShTcGVjaWVzID0gcmVsZXZlbChTcGVjaWVzLCByZWYgPSAidmlyZ2luaWNhIikpCgptb2RlbG81X3JlZl92aXJnaW5pY2EgPC0gbG0oCiAgU2VwYWwuTGVuZ3RoIH4gU2VwYWwuV2lkdGggKyBTcGVjaWVzLAogIGRhdGEgPSBkYWRvc19yZWZfdmlyZ2luaWNhCikKCnRhYmVsYV9jb2VmaWNpZW50ZXMobW9kZWxvNV9yZWZfdmlyZ2luaWNhKSB8PgogIGtuaXRyOjprYWJsZShkaWdpdHMgPSAzKSB8PgogIGthYmxlX3N0eWxpbmcoZnVsbF93aWR0aCA9IEZBTFNFLCBib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG92ZXIiKSkKYGBgCgpDb20gYHZpcmdpbmljYWAgY29tbyByZWZlcsOqbmNpYSwgb3MgY29lZmljaWVudGVzIG5lZ2F0aXZvcyBkZSBgc2V0b3NhYCBlIGB2ZXJzaWNvbG9yYCBleHByZXNzYW0gcXVhbnRvIGVzc2FzIGVzcMOpY2llcyB0w6ptIHPDqXBhbGFzIG1lbm9yZXMsIGVtIG3DqWRpYSBjb25kaWNpb25hbCwgZG8gcXVlIGB2aXJnaW5pY2FgLiBPIGV4ZW1wbG8gbW9zdHJhIHF1ZSBtdWRhciBhIHJlZmVyw6puY2lhIG11ZGEgYXMgY29tcGFyYcOnw7VlcyBleHByZXNzYXMgcGVsb3MgY29lZmljaWVudGVzLCBtYXMgbsOjbyBtdWRhIG8gYWp1c3RlIGRvIG1vZGVsby4KCmBgYHtyIGxpc3RhLW1vZGVsb3MsIGluY2x1ZGU9RkFMU0V9Cm1vZGVsb3MgPC0gbGlzdCgKICAiTW9kZWxvIDEg4oCUIHRvZGFzIGFzIG1lZGlkYXMiID0gbW9kZWxvMSwKICAiTW9kZWxvIDIg4oCUIHNlbSBQZXRhbC5XaWR0aCIgPSBtb2RlbG8yLAogICJNb2RlbG8gMyDigJQgc2VtIFBldGFsLkxlbmd0aCIgPSBtb2RlbG8zLAogICJNb2RlbG8gNCDigJQgbWVkaWRhcyArIGVzcMOpY2llIiA9IG1vZGVsbzQsCiAgIk1vZGVsbyA1IOKAlCBsYXJndXJhICsgZXNww6ljaWUiID0gbW9kZWxvNQopCmBgYAoKIyMgU2VsZcOnw6NvIGRvIG1vZGVsbwoKQW50ZXMgZGUgZXhhbWluYXIgcmVzw61kdW9zIG91IGZhemVyIHByZXZpc8O1ZXMsIGNvbXBhcmFtb3Mgb3MgbW9kZWxvcyBlIGlkZW50aWZpY2Ftb3MgdW0gY2FuZGlkYXRvIGRlIG1lbGhvciBhanVzdGUuIEEgdGFiZWxhIGFiYWl4byByZcO6bmUgb3MgY2luY28gYWp1c3Rlcy4gVmFsb3JlcyBtYWlvcmVzIGRlICRSXjIkIGFqdXN0YWRvIGUgbWVub3JlcyBkZSBSUU1FIHJlc2lkdWFsLCBBSUMgZSBCSUMgc8OjbyBwcmVmZXLDrXZlaXMuCgotICoqJFJeMiQgYWp1c3RhZG86KiogcGFyY2VsYSBkYSB2YXJpYcOnw6NvIGV4cGxpY2FkYSwgY29tIHBlbmFsaXphw6fDo28gcGVsbyBuw7ptZXJvIGRlIHBhcsOibWV0cm9zOwotICoqUlFNRSByZXNpZHVhbDoqKiB0YW1hbmhvIHTDrXBpY28gZG8gZXJybyBkZSBhanVzdGUsIGVtIGNlbnTDrW1ldHJvczsKLSAqKkFJQyBlIEJJQzoqKiBjcml0w6lyaW9zIHF1ZSBlcXVpbGlicmFtIGFqdXN0ZSBlIGNvbXBsZXhpZGFkZTsgdmFsb3JlcyBtZW5vcmVzIHPDo28gcHJlZmVyw612ZWlzLCBlIG8gQklDIHBlbmFsaXphIG1haXMgbW9kZWxvcyBjb21wbGV4b3MuCgpgYGB7ciBjb21wYXJhY2FvLWluaWNpYWwtbW9kZWxvc30KY29tcGFyYWNhb19hanVzdGUgPC0gaW1hcF9kZnIobW9kZWxvcywgZnVuY3Rpb24oYWp1c3RlLCBub21lKSB7CiAgZyA8LSBnbGFuY2UoYWp1c3RlKQogIHRpYmJsZSgKICAgIG1vZGVsbyA9IG5vbWUsCiAgICBwYXJhbWV0cm9zID0gbGVuZ3RoKGNvZWYoYWp1c3RlKSksCiAgICBSMiA9IGckci5zcXVhcmVkLAogICAgUjJfYWp1c3RhZG8gPSBnJGFkai5yLnNxdWFyZWQsCiAgICBSUU1FX3Jlc2lkdWFsID0gc3FydChtZWFuKHJlc2lkdWFscyhhanVzdGUpXjIpKSwKICAgIEFJQyA9IEFJQyhhanVzdGUpLAogICAgQklDID0gQklDKGFqdXN0ZSkKICApCn0pCgprbml0cjo6a2FibGUoY29tcGFyYWNhb19hanVzdGUsIGRpZ2l0cyA9IDMpIHw+CiAga2FibGVfc3R5bGluZyhmdWxsX3dpZHRoID0gRkFMU0UsIGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJob3ZlciIpKQpgYGAKCk8gTW9kZWxvIDQgbGlkZXJhIG9zIGNyaXTDqXJpb3MgZGUgKiphanVzdGUgaW50ZXJubyoqIGVudHJlIG9zIGNpbmNvIG1vZGVsb3MuIE8gTW9kZWxvIDEgZmljYSBwcsOzeGltbyBlbSBhanVzdGUsIG1hcyBtYW50w6ltIGEgbXVsdGljb2xpbmVhcmlkYWRlIGVudHJlIGFzIGR1YXMgbWVkaWRhcyBkYSBww6l0YWxhLiBPIE1vZGVsbyAyIMOpIG1haXMgc2ltcGxlcywgbWFzIHBlcmRlIGFqdXN0ZTsgb3MgTW9kZWxvcyAzIGUgNSBwZXJkZW0gaW5mb3JtYcOnw6NvIGltcG9ydGFudGUgYW8gZXhjbHVpciBgUGV0YWwuTGVuZ3RoYC4KCkNvbW8gY29tcGxlbWVudG8sIG9zIHRlc3RlcyBGIGFiYWl4byB2ZXJpZmljYW0gc2UgdW0gdGVybW8gZXNwZWPDrWZpY28gYWNyZXNjZW50YSBpbmZvcm1hw6fDo28gcXVhbmRvIGNvbXBhcmFtb3MgbW9kZWxvcyBhbmluaGFkb3MuIENhZGEgY29tcGFyYcOnw6NvIMOpIGFwcmVzZW50YWRhIHNlcGFyYWRhbWVudGUgcGFyYSBxdWUgZmlxdWUgY2xhcm8gcXVhbCB2YXJpw6F2ZWwgZXN0w6Egc2VuZG8gYXZhbGlhZGEuCgojIyMgQ29tcGFyYcOnw6NvIDEg4oCUIE1vZGVsbyAyIHZlcnN1cyBNb2RlbG8gMTogY29udHJpYnVpw6fDo28gZGUgYFBldGFsLldpZHRoYAoKTyBNb2RlbG8gMSBjb250w6ltIGBTZXBhbC5XaWR0aGAsIGBQZXRhbC5MZW5ndGhgIGUgYFBldGFsLldpZHRoYDsgbyBNb2RlbG8gMiByZXRpcmEgYXBlbmFzIGBQZXRhbC5XaWR0aGAuIEVzdGUgdGVzdGUgdmVyaWZpY2Egc2UgZXNzYSB2YXJpw6F2ZWwgYWNyZXNjZW50YSBhanVzdGUgZGVwb2lzIGRlIGNvbnNpZGVyYXIgYXMgb3V0cmFzIGR1YXMgbWVkaWRhcy4KCmBgYHtyIHRlc3RlLW1vZGVsbzItbW9kZWxvMX0KYW5vdmEobW9kZWxvMiwgbW9kZWxvMSkKYGBgCgojIyMgQ29tcGFyYcOnw6NvIDIg4oCUIE1vZGVsbyAzIHZlcnN1cyBNb2RlbG8gMTogY29udHJpYnVpw6fDo28gZGUgYFBldGFsLkxlbmd0aGAKCk8gTW9kZWxvIDMgcmV0aXJhIGBQZXRhbC5MZW5ndGhgIGRvIE1vZGVsbyAxLiBBc3NpbSwgbyB0ZXN0ZSBhdmFsaWEgYSBjb250cmlidWnDp8OjbyBkZXNzYSBtZWRpZGEgcXVhbmRvIGBTZXBhbC5XaWR0aGAgZSBgUGV0YWwuV2lkdGhgIGrDoSBlc3TDo28gbm8gbW9kZWxvLgoKYGBge3IgdGVzdGUtbW9kZWxvMy1tb2RlbG8xfQphbm92YShtb2RlbG8zLCBtb2RlbG8xKQpgYGAKCiMjIyBDb21wYXJhw6fDo28gMyDigJQgTW9kZWxvIDIgdmVyc3VzIE1vZGVsbyA0OiBjb250cmlidWnDp8OjbyBjb25qdW50YSBkZSBgU3BlY2llc2AKCk8gTW9kZWxvIDQgYWNyZXNjZW50YSBgU3BlY2llc2AgYW8gTW9kZWxvIDIuIEVzdGUgw6kgbyB0ZXN0ZSBxdWUgdmVyaWZpY2EgZGlyZXRhbWVudGUgc2UgcmVwcmVzZW50YXIgYXMgZGlmZXJlbsOnYXMgZW50cmUgZXNww6ljaWVzIG1lbGhvcmEgbyBhanVzdGUuCgpgYGB7ciB0ZXN0ZS1tb2RlbG8yLW1vZGVsbzR9CnRlc3RlX20yX200IDwtIGFub3ZhKG1vZGVsbzIsIG1vZGVsbzQpCnRlc3RlX20yX200CmBgYAoKIyMjIENvbXBhcmHDp8OjbyA0IOKAlCBNb2RlbG8gNSB2ZXJzdXMgTW9kZWxvIDQ6IGNvbnRyaWJ1acOnw6NvIGRlIGBQZXRhbC5MZW5ndGhgIG5hIHByZXNlbsOnYSBkZSBgU3BlY2llc2AKCk8gTW9kZWxvIDUgcmV0aXJhIGBQZXRhbC5MZW5ndGhgIGRvIE1vZGVsbyA0LiBPIHRlc3RlIG1vc3RyYSBzZSBlc3NhIG1lZGlkYSBjb250aW51YSB0cmF6ZW5kbyBpbmZvcm1hw6fDo28gbWVzbW8gZGVwb2lzIGRlIGNvbnRyb2xhciBhIGVzcMOpY2llLgoKYGBge3IgdGVzdGUtbW9kZWxvNS1tb2RlbG80fQphbm92YShtb2RlbG81LCBtb2RlbG80KQpgYGAKCkEgdGFiZWxhIGlkZW50aWZpY2EgbyBjYW5kaWRhdG8gZGUgbWVsaG9yIGFqdXN0ZSBpbnRlcm5vOyBvcyB0ZXN0ZXMgRiB2ZXJpZmljYW0gc2UgZ2FuaG9zIGVzcGVjw61maWNvcyBzw6NvIGNvbXBhdMOtdmVpcyBjb20gb3MgZGFkb3MuIEVtIGVzcGVjaWFsLCBvIHRlc3RlIGBhbm92YShtb2RlbG8yLCBtb2RlbG80KWAgYXZhbGlhIGRpcmV0YW1lbnRlIGEgcGFzc2FnZW0gZG8gTW9kZWxvIDIgcGFyYSBvIE1vZGVsbyA0OiBhIGluY2x1c8OjbyBjb25qdW50YSBkZSBgU3BlY2llc2AgbWVsaG9yYSBzaWduaWZpY2F0aXZhbWVudGUgbyBhanVzdGUgKHAtdmFsb3IgYHIgZm10X251bSh0ZXN0ZV9tMl9tNFtbIlByKD5GKSJdXVsyXSwgNilgKS4gTyB0ZXN0ZSBGIHJlc3BvbmRlIGEgdW1hIHBlcmd1bnRhIHBvbnR1YWwg4oCUIOKAnGVzdGUgdGVybW8gbWVsaG9yYSBlc3RlIG1vZGVsbyByZWR1emlkbz/igJ0g4oCUIGUgc8OzIHBvZGUgc2VyIHVzYWRvIHBhcmEgbW9kZWxvcyBhbmluaGFkb3MuIEFJQywgQklDIGUgJFJeMiQgYWp1c3RhZG8gY29tcGFyYW0gbyBlcXVpbMOtYnJpbyBnZXJhbCBlbnRyZSBhanVzdGUgZSBjb21wbGV4aWRhZGUuCgo8ZGl2IGNsYXNzPSJkZWNpc2lvbiI+CjxzdHJvbmc+Q2FuZGlkYXRvIGRlIG1lbGhvciBhanVzdGUgaW50ZXJubzogTW9kZWxvIDQg4oCUIDxjb2RlPlNlcGFsLkxlbmd0aCB+IFNlcGFsLldpZHRoICsgUGV0YWwuTGVuZ3RoICsgU3BlY2llczwvY29kZT4uPC9zdHJvbmc+IEVsZSBhcHJlc2VudGEgbyBtYWlvciAkUl4yJCBhanVzdGFkbyAoYHIgZm10X251bShzdW1tYXJ5KG1vZGVsbzQpJGFkai5yLnNxdWFyZWQpYCksIG8gbWVub3IgUlFNRSByZXNpZHVhbCAoYHIgZm10X251bShzcXJ0KG1lYW4ocmVzaWR1YWxzKG1vZGVsbzQpXjIpKSlgKSwgbyBtZW5vciBBSUMgKGByIGZtdF9udW0oQUlDKG1vZGVsbzQpLCAyKWApIGUgbyBtZW5vciBCSUMgKGByIGZtdF9udW0oQklDKG1vZGVsbzQpLCAyKWApIGVudHJlIG9zIGNpbmNvIGFqdXN0ZXMuIENvbW8gYSBjb2xpbmVhcmlkYWRlIMOpIGZvcnRlLCBhIGRlY2lzw6NvIGZpbmFsIGRlcGVuZGUgdGFtYsOpbSBkbyBkaWFnbsOzc3RpY28gZSBkbyBvYmpldGl2bzogYWp1c3RlIGludGVybm8gb3UgaW50ZXJwcmV0YcOnw6NvIG1haXMgZXN0w6F2ZWwuIEVzdGEgY29tcGFyYcOnw6NvIG7Do28gZGVtb25zdHJhIGRlc2VtcGVuaG8gZW0gbm92YXMgZmxvcmVzOyBpc3NvIGV4aWdpcmlhIHVtYSBiYXNlIGRlIHRlc3RlLgo8L2Rpdj4KCiMgRGlhZ27Ds3N0aWNvIGNvbXBsZXRvIGRvcyByZXPDrWR1b3MKCk8gTW9kZWxvIDQsIGNhbmRpZGF0byBkZSBtZWxob3IgYWp1c3RlIG5hIHRhYmVsYSBhbnRlcmlvciwgc2Vyw6EgdXNhZG8gcGFyYSBhIGFuw6FsaXNlIGRldGFsaGFkYSBkb3MgcHJlc3N1cG9zdG9zLiBPIGRpYWduw7NzdGljbyB2ZXJpZmljYXLDoSBzZSBzdWEgZm9ybWEgbGluZWFyIMOpIGNvbXBhdMOtdmVsIGNvbSBvcyBkYWRvcyBhbnRlcyBkYSBkZWNpc8OjbyBmaW5hbC4KCmBgYHtyIG1vZGVsby1kaWFnbm9zdGljb30KbW9kZWxvX2RpYWdub3N0aWNvIDwtIG1vZGVsbzQKCmRpYWcgPC0gYXVnbWVudChtb2RlbG9fZGlhZ25vc3RpY28sIGRhdGEgPSBkYWRvcykgfD4KICBtdXRhdGUoCiAgICBpbmRpY2UgPSByb3dfbnVtYmVyKCksCiAgICBjb29rX2xpbWl0ZSA9IDQgLyBucm93KGRhZG9zKSwKICAgIGxldmVyYWdlX2xpbWl0ZSA9IDIgKiBsZW5ndGgoY29lZihtb2RlbG9fZGlhZ25vc3RpY28pKSAvIG5yb3coZGFkb3MpCiAgKQpgYGAKCiMjIE8gcXVlIHZlcmlmaWNhcmVtb3MgYW50ZXMgZG9zIGdyw6FmaWNvcwoKTyBkaWFnbsOzc3RpY28gbsOjbyBwcm9jdXJhIHVtIOKAnGdyw6FmaWNvIHBlcmZlaXRv4oCdOyBlbGUgdmVyaWZpY2Egc2UgaMOhIGluZMOtY2lvcyBmb3J0ZXMgZGUgcXVlIG8gbW9kZWxvIGxpbmVhciBlc2NvbGhpZG8gw6kgaW5hZGVxdWFkby4gQW50ZXMgZGUgb2xoYXIgYSBmaWd1cmEsIGVzdGFiZWxlw6dhIGFzIHBlcmd1bnRhcyBkZSBjYWRhIHBhaW5lbDoKCi0gKipMaW5lYXJpZGFkZToqKiBvcyByZXPDrWR1b3Mgb3NjaWxhbSBzZW0gY3VydmF0dXJhIGVtIHRvcm5vIGRlIHplcm8/Ci0gKipIb21vY2VkYXN0aWNpZGFkZToqKiBhIGRpc3BlcnPDo28gZG9zIHJlc8OtZHVvcyBzZSBtYW50w6ltIHNlbWVsaGFudGUgYW8gbG9uZ28gZG9zIHZhbG9yZXMgYWp1c3RhZG9zPwotICoqTm9ybWFsaWRhZGUgYXByb3hpbWFkYToqKiBhIGRpc3RyaWJ1acOnw6NvIGRvcyByZXPDrWR1b3Mgw6kgY29tcGF0w612ZWwgY29tIHVtYSBub3JtYWwsIGVzcGVjaWFsbWVudGUgbmFzIGNhdWRhcz8KLSAqKkFsYXZhbmNhZ2VtIGUgaW5mbHXDqm5jaWE6KiogZXhpc3RlIGFsZ3VtYSBmbG9yIGNvbSBjb21iaW5hw6fDo28gaW5jb211bSBkZSBwcmVkaXRvcmVzIGUgY2FwYWNpZGFkZSBkZSBhbHRlcmFyIHN1YnN0YW5jaWFsbWVudGUgbyBhanVzdGU/CgpFc3NhcyB2ZXJpZmljYcOnw7VlcyBzZSBjb21wbGVtZW50YW0uIFVtIMO6bmljbyBwb250byBmb3JhIGRlIHVtIGxpbWl0ZSBuw6NvIGludmFsaWRhIG8gbW9kZWxvOyBvIGludGVyZXNzZSBlc3TDoSBlbSBwYWRyw7VlcyBwZXJzaXN0ZW50ZXMgZSBlbSBzdWEgcmVsZXbDom5jaWEgcGFyYSBhIHBlcmd1bnRhIGRhIGFuw6FsaXNlLgoKIyMgUXVhdHJvIGdyw6FmaWNvcyBmdW5kYW1lbnRhaXMKCmBgYHtyIGdyYWZpY29zLWRpYWdub3N0aWNvLCBmaWcuaGVpZ2h0PTguNCwgZmlnLmNhcD0iRGlhZ27Ds3N0aWNvIGRvIE1vZGVsbyA0IGNvbSBhcyAxNTAgb2JzZXJ2YcOnw7Vlcy4gTGluaGFzIGRlIHJlZmVyw6puY2lhIHNlcnZlbSBjb21vIGd1aWFzLCBuw6NvIGNvbW8gZGVjaXPDtWVzIG1lY8OibmljYXMuIn0KcDEgPC0gZ2dwbG90KGRpYWcsIGFlcyguZml0dGVkLCAucmVzaWQpKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgY29sb3IgPSBjaW56YSwgbGluZXR5cGUgPSAyKSArCiAgZ2VvbV9wb2ludChjb2xvciA9IGF6dWwsIGFscGhhID0gMC43KSArCiAgZ2VvbV9zbW9vdGgoc2UgPSBGQUxTRSwgbWV0aG9kID0gImxvZXNzIiwgY29sb3IgPSByb3NhLCBsaW5ld2lkdGggPSAwLjg1KSArCiAgbGFicyh0aXRsZSA9ICJSZXPDrWR1b3Mgw5cgYWp1c3RhZG9zIiwgc3VidGl0bGUgPSAiUHJvY3VyZSBjdXJ2YXR1cmEgZSBmb3JtYXRvIGRlIGZ1bmlsIiwKICAgICAgIHggPSAiVmFsb3IgYWp1c3RhZG8iLCB5ID0gIlJlc8OtZHVvIikKCnNldC5zZWVkKDIwMjYwNzE1KQpuX2RpYWcgPC0gbnJvdyhkaWFnKQpxdWFudGlzX3Rlb3JpY29zIDwtIHFub3JtKHBwb2ludHMobl9kaWFnKSkKc2ltdWxhY29lc19ub3JtYWlzIDwtIHJlcGxpY2F0ZSgyMDAwLCBzb3J0KHJub3JtKG5fZGlhZykpKQplbnZlbG9wZV9xcSA8LSB0aWJibGUoCiAgcXVhbnRpbF90ZW9yaWNvID0gcXVhbnRpc190ZW9yaWNvcywKICByZXNpZHVvX29ic2VydmFkbyA9IHNvcnQoZGlhZyQuc3RkLnJlc2lkKSwKICBsaW1pdGVfaW5mZXJpb3IgPSBhcHBseShzaW11bGFjb2VzX25vcm1haXMsIDEsIHF1YW50aWxlLCBwcm9icyA9IDAuMDI1KSwKICBsaW1pdGVfc3VwZXJpb3IgPSBhcHBseShzaW11bGFjb2VzX25vcm1haXMsIDEsIHF1YW50aWxlLCBwcm9icyA9IDAuOTc1KQopCgpwMiA8LSBnZ3Bsb3QoZW52ZWxvcGVfcXEsIGFlcyhxdWFudGlsX3Rlb3JpY28sIHJlc2lkdW9fb2JzZXJ2YWRvKSkgKwogIGdlb21fcmliYm9uKAogICAgYWVzKHltaW4gPSBsaW1pdGVfaW5mZXJpb3IsIHltYXggPSBsaW1pdGVfc3VwZXJpb3IpLAogICAgZmlsbCA9IGRvdXJhZG8sIGFscGhhID0gMC4yMgogICkgKwogIGdlb21fYWJsaW5lKGludGVyY2VwdCA9IDAsIHNsb3BlID0gMSwgY29sb3IgPSByb3NhLCBsaW5ld2lkdGggPSAwLjg1KSArCiAgZ2VvbV9wb2ludChjb2xvciA9IGF6dWwsIGFscGhhID0gMC43MikgKwogIGxhYnModGl0bGUgPSAiUVEtcGxvdCBjb20gZW52ZWxvcGUgZGUgOTUlIiwgc3VidGl0bGUgPSAiUG9udG9zIGZvcmEgZGEgZmFpeGEgc3VnZXJlbSBkZXN2aW8gZGUgbm9ybWFsaWRhZGUiLAogICAgICAgeCA9ICJRdWFudGlzIHRlw7NyaWNvcyIsIHkgPSAiUmVzw61kdW8gcGFkcm9uaXphZG8iKQoKcDMgPC0gZ2dwbG90KGRpYWcsIGFlcyguZml0dGVkLCBzcXJ0KGFicyguc3RkLnJlc2lkKSkpKSArCiAgZ2VvbV9wb2ludChjb2xvciA9IGF6dWwsIGFscGhhID0gMC43KSArCiAgZ2VvbV9zbW9vdGgoc2UgPSBGQUxTRSwgbWV0aG9kID0gImxvZXNzIiwgY29sb3IgPSByb3NhLCBsaW5ld2lkdGggPSAwLjg1KSArCiAgbGFicyh0aXRsZSA9ICJFc2NhbGHigJNsb2NhbGl6YcOnw6NvIiwgc3VidGl0bGUgPSAiVW1hIGZhaXhhIGFwcm94aW1hZGFtZW50ZSBob3Jpem9udGFsIMOpIGRlc2Vqw6F2ZWwiLAogICAgICAgeCA9ICJWYWxvciBhanVzdGFkbyIsIHkgPSBleHByZXNzaW9uKHNxcnQoInxyZXPDrWR1byBwYWRyb25pemFkb3wiKSkpCgpwNCA8LSBnZ3Bsb3QoZGlhZywgYWVzKC5oYXQsIC5zdGQucmVzaWQsIHNpemUgPSAuY29va3NkKSkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IGMoLTIsIDIpLCBjb2xvciA9IGNpbnphLCBsaW5ldHlwZSA9IDIpICsKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSB1bmlxdWUoZGlhZyRsZXZlcmFnZV9saW1pdGUpLCBjb2xvciA9IGRvdXJhZG8sIGxpbmV0eXBlID0gMikgKwogIGdlb21fcG9pbnQoY29sb3IgPSBhenVsLCBhbHBoYSA9IDAuNjIpICsKICBzY2FsZV9zaXplX2NvbnRpbnVvdXMocmFuZ2UgPSBjKDEuMiwgNiksIGd1aWRlID0gIm5vbmUiKSArCiAgbGFicyh0aXRsZSA9ICJBbGF2YW5jYWdlbSBlIGluZmx1w6puY2lhIiwgc3VidGl0bGUgPSAiTGluaGEgbGFyYW5qYTogYWxhdmFuY2FnZW0gYWx0YTsgdGFtYW5obzogZGlzdMOibmNpYSBkZSBDb29rIiwKICAgICAgIHggPSAiQWxhdmFuY2FnZW0iLCB5ID0gIlJlc8OtZHVvIHBhZHJvbml6YWRvIikKCihwMSArIHAyKSAvIChwMyArIHA0KQpgYGAKCiMjIyBMaW5lYXJpZGFkZQoKTyBwcmltZWlybyBncsOhZmljbyBjb2xvY2Egbm8gZWl4byBob3Jpem9udGFsIG9zIHZhbG9yZXMgcHJldmlzdG9zIHBlbG8gbW9kZWxvIGUsIG5vIGVpeG8gdmVydGljYWwsIG9zIHJlc8OtZHVvcyAkZV9pPXlfaS1cd2lkZWhhdCB5X2kkLiBVbSByZXPDrWR1byBwb3NpdGl2byBpbmRpY2EgcXVlIG8gbW9kZWxvIHN1YmVzdGltb3UgbyBjb21wcmltZW50byBkYSBzw6lwYWxhOyB1bSByZXPDrWR1byBuZWdhdGl2byBpbmRpY2EgcXVlIG8gbW9kZWxvIHN1cGVyZXN0aW1vdS4KCk8gZ3LDoWZpY28gcmVzcG9uZGUgcHJpbmNpcGFsbWVudGUgw6AgcGVyZ3VudGE6ICoqYSBmb3JtYSBsaW5lYXIgZXNjb2xoaWRhIGNvbnNlZ3VlIHJlcHJlc2VudGFyIGEgbcOpZGlhIGRhIHJlc3Bvc3RhPyoqIE8gY29tcG9ydGFtZW50byBkZXNlasOhdmVsIMOpIHVtYSBudXZlbSBkaXN0cmlidcOtZGEgYWxlYXRvcmlhbWVudGUgYW8gcmVkb3IgZGUgemVybywgY29tIGEgbGluaGEgc3Vhdml6YWRhIGFwcm94aW1hZGFtZW50ZSBob3Jpem9udGFsLiBVbWEgZm9ybWEgZW0gVSBvdSBVIGludmVydGlkbyBzdWdlcmlyaWEgY3VydmF0dXJhIG7Do28gcmVwcmVzZW50YWRhOyBvbmRhcyBwb2RlcmlhbSBpbmRpY2FyIHRlcm1vcyBvbWl0aWRvczsgZ3J1cG9zIHNlcGFyYWRvcyBwb2RlcmlhbSByZXZlbGFyIHF1ZSBhbGd1bWEgZXN0cnV0dXJhIGNhdGVnw7NyaWNhIGFpbmRhIG7Do28gZm9pIG1vZGVsYWRhLgoKTm8gTW9kZWxvIDQsIGEgbGluaGEgc3Vhdml6YWRhIHBlcm1hbmVjZSBwcsOzeGltYSBkZSB6ZXJvIGUgbsOjbyBhcGFyZWNlIHVtYSBjdXJ2YXR1cmEgcGVyc2lzdGVudGUuIEjDoSByZXPDrWR1b3MgcG9zaXRpdm9zIGUgbmVnYXRpdm9zIGFvIGxvbmdvIGRlIHRvZGEgYSBmYWl4YSBkZSB2YWxvcmVzIGFqdXN0YWRvcy4gUG9ydGFudG8sIG8gZ3LDoWZpY28gbsOjbyBtb3N0cmEgZXZpZMOqbmNpYSB2aXN1YWwgZm9ydGUgZGUgcXVlIGEgbcOpZGlhIHByZWNpc2UgZGUgdW0gdGVybW8gbsOjbyBsaW5lYXIuIElzc28gw6kgY29tcGF0w612ZWwgY29tIGxpbmVhcmlkYWRlLCBtYXMgbsOjbyBjb25zdGl0dWkgdW1hIHByb3ZhIGRlZmluaXRpdmEuCgojIyMgSG9tb2NlZGFzdGljaWRhZGUKCk8gdGVyY2Vpcm8gZ3LDoWZpY28sIGVzY2FsYeKAk2xvY2FsaXphw6fDo28sIHJldGlyYSBvIHNpbmFsIGRvcyByZXPDrWR1b3MgcGFkcm9uaXphZG9zIGUgZGVzdGFjYSBzZXUgdGFtYW5oby4gRWxlIHJlc3BvbmRlIMOgIHBlcmd1bnRhOiAqKmEgZGlzcGVyc8OjbyBkb3MgZXJyb3MgcGVybWFuZWNlIGFwcm94aW1hZGFtZW50ZSBjb25zdGFudGUgcGFyYSB2YWxvcmVzIHByZXZpc3RvcyBwZXF1ZW5vcyBlIGdyYW5kZXM/KiogVW1hIGZhaXhhIGRlIGxhcmd1cmEgc2VtZWxoYW50ZSBlIHVtYSBsaW5oYSBzdWF2aXphZGEgaG9yaXpvbnRhbCBzw6NvIGRlc2Vqw6F2ZWlzLiBVbSBmdW5pbCBxdWUgc2UgYWJyZSBpbmRpY2FyaWEgdmFyacOibmNpYSBjcmVzY2VudGU7IHVtIGZ1bmlsIHF1ZSBzZSBmZWNoYSBpbmRpY2FyaWEgdmFyacOibmNpYSBkZWNyZXNjZW50ZS4KCk5vIE1vZGVsbyA0LCBuw6NvIHNlIG9ic2VydmEgdW0gZnVuaWwgZm9ydGUsIGUgYSBsaW5oYSBzdWF2aXphZGEgdmFyaWEgcG91Y28gYW8gbG9uZ28gZG8gZWl4byBob3Jpem9udGFsLiBPIGdyw6FmaWNvIGRlIHJlc8OtZHVvcyDDlyBhanVzdGFkb3MgY29uZHV6IMOgIG1lc21hIGNvbmNsdXPDo28gdmlzdWFsOiBhIGFtcGxpdHVkZSB2ZXJ0aWNhbCBuw6NvIGF1bWVudGEgc2lzdGVtYXRpY2FtZW50ZSBjb20gbyB2YWxvciBwcmV2aXN0by4gQXNzaW0sIGEgaW5zcGXDp8OjbyBncsOhZmljYSBuw6NvIHN1Z2VyZSBoZXRlcm9jZWRhc3RpY2lkYWRlIGltcG9ydGFudGUuCgojIyMgTm9ybWFsaWRhZGUgYXByb3hpbWFkYQoKTyBRUS1wbG90IGNvbXBhcmEgb3MgcXVhbnRpcyBkb3MgcmVzw61kdW9zIHBhZHJvbml6YWRvcyBjb20gb3MgcXVhbnRpcyBlc3BlcmFkb3MgZGUgdW1hIGRpc3RyaWJ1acOnw6NvIG5vcm1hbC4gQSBmYWl4YSBkb3VyYWRhIMOpIHVtIGVudmVsb3BlIHNpbXVsYWRvICoqaGV1csOtc3RpY28qKiBkZSA5NSU6IGVsYSBtb3N0cmEgYSB2YXJpYcOnw6NvIGVzcGVyYWRhIGRlIHVtYSBhbW9zdHJhIG5vcm1hbCBpbmRlcGVuZGVudGUgZG8gbWVzbW8gdGFtYW5oby4gUmVzw61kdW9zIHBhZHJvbml6YWRvcyBkZSB1bWEgcmVncmVzc8OjbyBuw6NvIHPDo28gb2JzZXJ2YcOnw7VlcyBpbmRlcGVuZGVudGVzIHBlcmZlaXRhczsgcG9yIGlzc28sIG8gZW52ZWxvcGUgw6kgYXBlbmFzIHVtYSByZWZlcsOqbmNpYSB2aXN1YWwuIFBvbnRvcyBzaXN0ZW1hdGljYW1lbnRlIGZvcmEgZGEgZmFpeGEsIHNvYnJldHVkbyBuYXMgY2F1ZGFzLCBzdWdlcmVtIGRlc3ZpbyBkZSBub3JtYWxpZGFkZTsgcG91Y29zIHBvbnRvcyBpc29sYWRvcyBwb2RlbSBvY29ycmVyIGFvIGFjYXNvLgoKTm8gTW9kZWxvIDQsIG9zIHBvbnRvcyBhY29tcGFuaGFtIGJlbSBhIHJldGEsIGluY2x1c2l2ZSBuYXMgY2F1ZGFzLCBzZW0gdW1hIGZvcm1hIHNpc3RlbcOhdGljYSBkZSBTLiBPIFFRLXBsb3QgYXZhbGlhIGEgZGlzdHJpYnVpw6fDo28gZG9zICoqcmVzw61kdW9zKiosIGUgbsOjbyBleGlnZSBxdWUgYFNlcGFsLkxlbmd0aGAgb3Ugb3MgcHJlZGl0b3JlcyBzZWphbSBub3JtYWxtZW50ZSBkaXN0cmlidcOtZG9zLiBFc3NhIG5vcm1hbGlkYWRlIMOpIGVzcGVjaWFsbWVudGUgcmVsZXZhbnRlIHBhcmEgYSBxdWFsaWRhZGUgZG9zIHRlc3RlcywgcC12YWxvcmVzIGUgaW50ZXJ2YWxvcyBkZSBjb25maWFuw6dhIGVtIGFtb3N0cmFzIHBlcXVlbmFzLiBPIGVudmVsb3BlIG7Do28gYXZhbGlhIGFsYXZhbmNhZ2VtIG91IGluZmx1w6puY2lhOiB1bWEgb2JzZXJ2YcOnw6NvIHBvZGUgZXN0YXIgZGVudHJvIGRvIGVudmVsb3BlIGRlIG5vcm1hbGlkYWRlIGUsIGFpbmRhIGFzc2ltLCB0ZXIgYWxhdmFuY2FnZW0gYWx0YS4KCmBgYHtyIHNoYXBpcm99CnRlc3RlX3NoYXBpcm8gPC0gc2hhcGlyby50ZXN0KHJlc2lkdWFscyhtb2RlbG9fZGlhZ25vc3RpY28pKQp0aWJibGUoCiAgdGVzdGUgPSAiU2hhcGlyb+KAk1dpbGsiLAogIFcgPSB1bm5hbWUodGVzdGVfc2hhcGlybyRzdGF0aXN0aWMpLAogIGBwLXZhbG9yYCA9IHRlc3RlX3NoYXBpcm8kcC52YWx1ZQopIHw+CiAgbXV0YXRlKGFjcm9zcyh3aGVyZShpcy5udW1lcmljKSwgfiByb3VuZCgueCwgNCkpKQpgYGAKCk8gdGVzdGUgZGUgU2hhcGlyb+KAk1dpbGsgYXByZXNlbnRvdSBwLXZhbG9yIGByIGZtdF9udW0odGVzdGVfc2hhcGlybyRwLnZhbHVlLCA0KWAuIENvbW8gZXNzZSB2YWxvciDDqSBtYWlvciBxdWUgMCwwNSwgbsOjbyByZWplaXRhbW9zIGEgaGlww7N0ZXNlIGRlIG5vcm1hbGlkYWRlLiBPIHRlc3RlIGUgbyBRUS1wbG90IGFwb250YW0gbmEgbWVzbWEgZGlyZcOnw6NvLiBBaW5kYSBhc3NpbSwgY29tIGFtb3N0cmFzIGdyYW5kZXMsIHRlc3RlcyBwb2RlbSBkZXRlY3RhciBkZXN2aW9zIGlycmVsZXZhbnRlczsgY29tIGFtb3N0cmFzIHBlcXVlbmFzLCBwb2RlbSB0ZXIgYmFpeGEgcG90w6puY2lhLiBQb3IgaXNzbywgbyBncsOhZmljbyBlIG8gdGVzdGUgZGV2ZW0gc2VyIGxpZG9zIGVtIGNvbmp1bnRvLgoKIyMjIEFsYXZhbmNhZ2VtIGUgaW5mbHXDqm5jaWEKCk8gcXVhcnRvIGdyw6FmaWNvIGNvbWJpbmEgdHLDqnMgaW5mb3JtYcOnw7Vlcy4gQSAqKmFsYXZhbmNhZ2VtKiosIG5vIGVpeG8gaG9yaXpvbnRhbCwgbWVkZSBxdcOjbyBpbmNvbXVtIMOpIGEgY29tYmluYcOnw6NvIGRlIHByZWRpdG9yZXMgZGUgdW1hIGZsb3IuIEEgbGluaGEgbGFyYW5qYSDDqSBhcGVuYXMgdW0gbGltaXRlIGRlIHRyaWFnZW0gcGFyYSBhbGF2YW5jYWdlbSBhbHRhOyB1bHRyYXBhc3PDoS1sYSBzaWduaWZpY2EgcXVlIGEgZmxvciBlc3TDoSBlbSB1bWEgcmVnacOjbyBwb3VjbyBjb211bSBkb3MgcHJlZGl0b3JlcywgZSAqKm7Do28qKiBxdWUgZWxhIHNlamEgdW1hIG9ic2VydmHDp8OjbyBlcnJhZGEgb3UgcXVlIGRldmEgc2VyIHJlbW92aWRhLiBPIHJlc8OtZHVvIHBhZHJvbml6YWRvLCBubyBlaXhvIHZlcnRpY2FsLCBtZWRlIHF1w6NvIGRpc3RhbnRlIHN1YSByZXNwb3N0YSBmaWNvdSBkbyB2YWxvciBwcmV2aXN0by4gTyB0YW1hbmhvIGRvIHBvbnRvIHJlcHJlc2VudGEgYSAqKmRpc3TDom5jaWEgZGUgQ29vayoqLCBxdWUgcmVzdW1lIHF1YW50byBvIGFqdXN0ZSBjb21wbGV0byBwb2RlIG11ZGFyIHF1YW5kbyBhcXVlbGEgb2JzZXJ2YcOnw6NvIMOpIHJldGlyYWRhLgoKVW1hIG9ic2VydmHDp8OjbyBjb20gYWxhdmFuY2FnZW0gYWx0YSBuw6NvIMOpIGF1dG9tYXRpY2FtZW50ZSBwcm9ibGVtw6F0aWNhOiBlbGEgcG9kZSBzZWd1aXIgcGVyZmVpdGFtZW50ZSBhIHRlbmTDqm5jaWEuIFVtYSBvYnNlcnZhw6fDo28gY29tIHJlc8OtZHVvIGdyYW5kZSB0YW1iw6ltIHBvZGUgdGVyIHBvdWNhIGluZmx1w6puY2lhIHNlIGVzdGl2ZXIgZW0gdW1hIHJlZ2nDo28gbXVpdG8gcG92b2FkYSBkb3MgcHJlZGl0b3Jlcy4gQSBtYWlvciBwcmVvY3VwYcOnw6NvIG9jb3JyZSBxdWFuZG8gYWxhdmFuY2FnZW0gYWx0YSBlIHJlc8OtZHVvIGdyYW5kZSBhcGFyZWNlbSBqdW50b3MsIHByb2R1emluZG8gZGlzdMOibmNpYSBkZSBDb29rIGVsZXZhZGEuCgpVc2FuZG8gYXBlbmFzIHJlZmVyw6puY2lhcyBkZSB0cmlhZ2VtLCBgciBzdW0oZGlhZyQuaGF0ID4gdW5pcXVlKGRpYWckbGV2ZXJhZ2VfbGltaXRlKSlgIG9ic2VydmHDp8O1ZXMgdWx0cmFwYXNzYW0gJDJwL249YHIgZm10X251bSh1bmlxdWUoZGlhZyRsZXZlcmFnZV9saW1pdGUpLCAzKWAgZSBgciBzdW0oZGlhZyQuY29va3NkID4gNCAvIG5yb3coZGFkb3MpKWAgdWx0cmFwYXNzYW0gJDQvbj1gciBmbXRfbnVtKDQgLyBucm93KGRhZG9zKSwgMylgIHBhcmEgYSBkaXN0w6JuY2lhIGRlIENvb2suIEEgbWFpb3IgZGlzdMOibmNpYSBkZSBDb29rIMOpIGByIGZtdF9udW0obWF4KGRpYWckLmNvb2tzZCksIDMpYCwgbXVpdG8gYWJhaXhvIGRhIHJlZmVyw6puY2lhIGFtcGxhIGRlIDEuIElzc28gc3VnZXJlIHBvbnRvcyBxdWUgbWVyZWNlbSBpbnNwZcOnw6NvLCBtYXMgbsOjbyB1bWEgb2JzZXJ2YcOnw6NvIGlzb2xhZGEgZG9taW5hbmRvIGNvbXBsZXRhbWVudGUgbyBNb2RlbG8gNC4KCiMjIyBJbmRlcGVuZMOqbmNpYQoKQSBpbmRlcGVuZMOqbmNpYSBuw6NvIHBvZGUgc2VyIGNvbmZpcm1hZGEgcG9yIHVtIGdyw6FmaWNvIHNlIG8gZGVzZW5obyBkYSBjb2xldGEgZm9yIGRlc2NvbmhlY2lkby4gU2UgdsOhcmlhcyBmbG9yZXMgdmllcmFtIGRhIG1lc21hIHBsYW50YSwgY2FudGVpcm8sIHJlZ2nDo28gb3UgbG90ZSwgdGFsdmV6IHNlamEgbmVjZXNzw6FyaW8gdW0gbW9kZWxvIGhpZXLDoXJxdWljby4gU2UgYXMgbGluaGFzIGVzdGl2ZXJlbSBvcmRlbmFkYXMgbm8gdGVtcG8sIGF2YWxpZSBhdXRvY29ycmVsYcOnw6NvLgoKYGBge3IgcmVzaWR1b3Mtb3JkZW0sIGZpZy5oZWlnaHQ9NC40fQpnZ3Bsb3QoZGlhZywgYWVzKGluZGljZSwgLnJlc2lkKSkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGNvbG9yID0gY2luemEsIGxpbmV0eXBlID0gMikgKwogIGdlb21fbGluZShjb2xvciA9ICIjOUZCNEQxIiwgbGluZXdpZHRoID0gMC41NSkgKwogIGdlb21fcG9pbnQoY29sb3IgPSBhenVsLCBzaXplID0gMS41KSArCiAgbGFicygKICAgIHRpdGxlID0gIlJlc8OtZHVvcyBuYSBvcmRlbSBkYXMgb2JzZXJ2YcOnw7VlcyIsCiAgICBzdWJ0aXRsZSA9ICJTw7Mgw6kgaW5mb3JtYXRpdm8gc29icmUgZGVwZW5kw6puY2lhIHNlIGEgb3JkZW0gdGl2ZXIgc2lnbmlmaWNhZG8gbm8gZGVzZW5obyIsCiAgICB4ID0gIk9yZGVtIiwgeSA9ICJSZXPDrWR1byIKICApCmBgYAoKIyMjIEludmVzdGlnYW5kbyBhcyBvYnNlcnZhw6fDtWVzIHNpbmFsaXphZGFzCgpgYGB7ciBpbmZsdWVudGVzfQppbmZsdWVudGVzIDwtIGF1Z21lbnQobW9kZWxvX2RpYWdub3N0aWNvLCBkYXRhID0gZGFkb3MpIHw+CiAgbXV0YXRlKAogICAgaWQgPSBkYWRvcyRpZCwKICAgIGxpbWlhcl9jb29rID0gNCAvIG5yb3coZGFkb3MpLAogICAgc2luYWxpemFkYSA9IC5jb29rc2QgPiBsaW1pYXJfY29vayB8IGFicyguc3RkLnJlc2lkKSA+IDIKICApIHw+CiAgYXJyYW5nZShkZXNjKC5jb29rc2QpKSB8PgogIHRyYW5zbXV0ZSgKICAgIGlkLAogICAgZXNwZWNpZSA9IFNwZWNpZXMsCiAgICBjb21wcmltZW50b19zZXBhbGEgPSBTZXBhbC5MZW5ndGgsCiAgICBsYXJndXJhX3NlcGFsYSA9IFNlcGFsLldpZHRoLAogICAgY29tcHJpbWVudG9fcGV0YWxhID0gUGV0YWwuTGVuZ3RoLAogICAgdmFsb3JfYWp1c3RhZG8gPSAuZml0dGVkLAogICAgcmVzaWR1byA9IC5yZXNpZCwKICAgIHJlc2lkdW9fcGFkcm9uaXphZG8gPSAuc3RkLnJlc2lkLAogICAgYWxhdmFuY2FnZW0gPSAuaGF0LAogICAgZGlzdGFuY2lhX2Nvb2sgPSAuY29va3NkLAogICAgc2luYWxpemFkYQogICkKCkRUOjpkYXRhdGFibGUoCiAgaGVhZChpbmZsdWVudGVzLCAxMiksCiAgcm93bmFtZXMgPSBGQUxTRSwKICBvcHRpb25zID0gbGlzdChwYWdlTGVuZ3RoID0gNiwgc2Nyb2xsWCA9IFRSVUUpLAogIGNhcHRpb24gPSAiT2JzZXJ2YcOnw7VlcyBjb20gbWFpb3IgZGlzdMOibmNpYSBkZSBDb29rIiwKICBjb2xuYW1lcyA9IGMoCiAgICAiSUQiLCAiRXNww6ljaWUiLCAiQ29tcHJpbWVudG8gZGEgc8OpcGFsYSIsICJMYXJndXJhIGRhIHPDqXBhbGEiLAogICAgIkNvbXByaW1lbnRvIGRhIHDDqXRhbGEiLCAiVmFsb3IgYWp1c3RhZG8iLCAiUmVzw61kdW8iLAogICAgIlJlc8OtZHVvIHBhZHJvbml6YWRvIiwgIkFsYXZhbmNhZ2VtIiwgIkRpc3TDom5jaWEgZGUgQ29vayIsICJTaW5hbGl6YWRhIgogICkKKSB8PgogIGZvcm1hdFJvdW5kKGNvbHVtbnMgPSBjKCJjb21wcmltZW50b19zZXBhbGEiLCAibGFyZ3VyYV9zZXBhbGEiLCAiY29tcHJpbWVudG9fcGV0YWxhIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAidmFsb3JfYWp1c3RhZG8iLCAicmVzaWR1byIsICJyZXNpZHVvX3BhZHJvbml6YWRvIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAiYWxhdmFuY2FnZW0iLCAiZGlzdGFuY2lhX2Nvb2siKSwgZGlnaXRzID0gMykKYGBgCgo8ZGl2IGNsYXNzPSJ3YXJuaW5nIj4KRGlzdMOibmNpYSBkZSBDb29rIGFjaW1hIGRlICQ0L24kIMOpIHVtIHNpbmFsIHBhcmEgaW52ZXN0aWdhciwgbsOjbyB1bWEgb3JkZW0gcGFyYSBleGNsdWlyLiBQcmltZWlybyB2ZXJpZmlxdWUgZXJybyBkZSBkaWdpdGHDp8OjbywgY29tcGF0aWJpbGlkYWRlIGNvbSBhIHBvcHVsYcOnw6NvIGUgc2Vuc2liaWxpZGFkZSBkYXMgY29uY2x1c8O1ZXMgY29tIGUgc2VtIG8gcG9udG8uCjwvZGl2PgoKPGRpdiBjbGFzcz0iY2hlY2twb2ludCI+CjxzdHJvbmc+QW7DoWxpc2UgZGUgc2Vuc2liaWxpZGFkZSwgbsOjbyBzZWxlw6fDo28gZGUgbW9kZWxvLjwvc3Ryb25nPiBPcyBwb250b3MgYWJhaXhvIHPDo28gcmV0aXJhZG9zIGFwZW5hcyBwYXJhIHZlcmlmaWNhciBhIGVzdGFiaWxpZGFkZSBkYXMgY29uY2x1c8O1ZXMuIEEgY29tcGFyYcOnw6NvIG7Do28gZGV2ZSBzZXIgdXNhZGEgcGFyYSBlc2NvbGhlciB1bSBtb2RlbG8gY29tICRSXjIkIG1haW9yIG5lbSBwYXJhIGp1c3RpZmljYXIgZXhjbHVzw7VlcyBhdXRvbcOhdGljYXMuCjwvZGl2PgoKYGBge3Igc2Vuc2liaWxpZGFkZS1pbmZsdWVuY2lhfQppZHNfc2Vuc2l2ZWlzIDwtIGluZmx1ZW50ZXMgfD4KICBmaWx0ZXIoc2luYWxpemFkYSkgfD4KICBwdWxsKGlkKQoKbW9kZWxvX3NlbV9zZW5zaXZlaXMgPC0gbG0oCiAgZm9ybXVsYShtb2RlbG9fZGlhZ25vc3RpY28pLAogIGRhdGEgPSBkYWRvcyB8PiBmaWx0ZXIoIWlkICVpbiUgaWRzX3NlbnNpdmVpcykKKQoKbWV0cmljYXNfc2Vuc2liaWxpZGFkZSA8LSB0aWJibGUoCiAgbWV0cmljYSA9IGMoIlLCsiIsICJSwrIgYWp1c3RhZG8iLCAiRXJyby1wYWRyw6NvIHJlc2lkdWFsIiksCiAgYFRvZG9zIG9zIGRhZG9zYCA9IGMoCiAgICBzdW1tYXJ5KG1vZGVsb19kaWFnbm9zdGljbykkci5zcXVhcmVkLAogICAgc3VtbWFyeShtb2RlbG9fZGlhZ25vc3RpY28pJGFkai5yLnNxdWFyZWQsCiAgICBzdW1tYXJ5KG1vZGVsb19kaWFnbm9zdGljbykkc2lnbWEKICApLAogIGBTZW0gcG9udG9zIHNpbmFsaXphZG9zYCA9IGMoCiAgICBzdW1tYXJ5KG1vZGVsb19zZW1fc2Vuc2l2ZWlzKSRyLnNxdWFyZWQsCiAgICBzdW1tYXJ5KG1vZGVsb19zZW1fc2Vuc2l2ZWlzKSRhZGouci5zcXVhcmVkLAogICAgc3VtbWFyeShtb2RlbG9fc2VtX3NlbnNpdmVpcykkc2lnbWEKICApCikKCm1ldHJpY2FzX3NlbnNpYmlsaWRhZGUgfD4KICBrbml0cjo6a2FibGUoZGlnaXRzID0gMywgY2FwdGlvbiA9ICJNw6l0cmljYXMgZGUgYWp1c3RlIG5hIGFuw6FsaXNlIGRlIHNlbnNpYmlsaWRhZGUiKSB8PgogIGthYmxlX3N0eWxpbmcoZnVsbF93aWR0aCA9IEZBTFNFLCBib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG92ZXIiKSkKCmNvbXBhcmFjYW9fc2Vuc2liaWxpZGFkZSA8LSBiaW5kX3Jvd3MoCiAgdGlkeShtb2RlbG9fZGlhZ25vc3RpY28pIHw+IG11dGF0ZShhanVzdGUgPSAiVG9kb3Mgb3MgZGFkb3MiKSwKICB0aWR5KG1vZGVsb19zZW1fc2Vuc2l2ZWlzKSB8PiBtdXRhdGUoYWp1c3RlID0gIlNlbSBwb250b3Mgc2luYWxpemFkb3MiKQopIHw+CiAgc2VsZWN0KGFqdXN0ZSwgdGVybSwgZXN0aW1hdGUsIHN0ZC5lcnJvcikgfD4KICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gYWp1c3RlLCB2YWx1ZXNfZnJvbSA9IGMoZXN0aW1hdGUsIHN0ZC5lcnJvcikpCgprbml0cjo6a2FibGUoY29tcGFyYWNhb19zZW5zaWJpbGlkYWRlLCBkaWdpdHMgPSAzKSB8PgogIGthYmxlX3N0eWxpbmcoZnVsbF93aWR0aCA9IEZBTFNFLCBib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG92ZXIiKSkKYGBgCgpGb3JhbSBzaW5hbGl6YWRhcyBgciBsZW5ndGgoaWRzX3NlbnNpdmVpcylgIG9ic2VydmHDp8O1ZXMuIEFvIHJldGlyw6EtbGFzIGFwZW5hcyBwYXJhIGVzdGEgYW7DoWxpc2UgZGUgc2Vuc2liaWxpZGFkZSwgbyAkUl4yJCBhanVzdGFkbyBwYXNzYSBkZSBgciBmbXRfbnVtKHN1bW1hcnkobW9kZWxvX2RpYWdub3N0aWNvKSRhZGouci5zcXVhcmVkKWAgcGFyYSBgciBmbXRfbnVtKHN1bW1hcnkobW9kZWxvX3NlbV9zZW5zaXZlaXMpJGFkai5yLnNxdWFyZWQpYCBlIG8gZXJybyByZXNpZHVhbCBwYXNzYSBkZSBgciBmbXRfbnVtKHN1bW1hcnkobW9kZWxvX2RpYWdub3N0aWNvKSRzaWdtYSlgIHBhcmEgYHIgZm10X251bShzdW1tYXJ5KG1vZGVsb19zZW1fc2Vuc2l2ZWlzKSRzaWdtYSlgLiBFc3NhIGFwYXJlbnRlIOKAnG1lbGhvcmHigJ0gw6kgZXNwZXJhZGEgcXVhbmRvIHJlbW92ZW1vcyBwb250b3MgY29tIHJlc8OtZHVvcyBtYWlvcmVzOyBlbGEgKipuw6NvKiogcHJvdmEgcXVlIG8gbW9kZWxvIHNlbSBlc3NhcyBmbG9yZXMgw6kgbWVsaG9yIG91IHF1ZSBlbGFzIGRldmFtIHNlciBleGNsdcOtZGFzLgoKT3MgY29lZmljaWVudGVzIHBlcm1hbmVjZW0gcHLDs3hpbW9zLCBjb21vIG1vc3RyYSBhIHRhYmVsYS4gUG9ydGFudG8sIG8gTW9kZWxvIDQgY29tIGFzIDE1MCBmbG9yZXMgY29udGludWEgc2VuZG8gbyByZXN1bHRhZG8gcHJpbmNpcGFsLiBVbWEgb2JzZXJ2YcOnw6NvIHPDsyBkZXZlcmlhIHNlciByZW1vdmlkYSBzZSBob3V2ZXIgZXZpZMOqbmNpYSBpbmRlcGVuZGVudGUgZGUgZXJybyBkZSByZWdpc3RybywgZGUgcXVlIGVsYSBuw6NvIHBlcnRlbmNlIMOgIHBvcHVsYcOnw6NvIGVzdHVkYWRhIG91IHVtYSByZWdyYSBkZWZpbmlkYSBhbnRlcyBkYSBhbsOhbGlzZSDigJQgbnVuY2EgYXBlbmFzIHBvciBjcnV6YXIgYSBsaW5oYSBsYXJhbmphLCB0ZXIgcmVzw61kdW8gZ3JhbmRlIG91IGZpY2FyIGRlbnRyby9mb3JhIGRvIGVudmVsb3BlLgoKIyBQcmV2aXPDo28gZSBpbmNlcnRlemEKCkNvbSBvIE1vZGVsbyA0IHNlbGVjaW9uYWRvLCBwb2RlbW9zIGVzdGltYXIgbyBjb21wcmltZW50byBkYSBzw6lwYWxhIHBhcmEgbm92b3MgdmFsb3JlcyBkZSBgU2VwYWwuV2lkdGhgLCBgUGV0YWwuTGVuZ3RoYCBlIGBTcGVjaWVzYC4gT3Mgbm9tZXMgZSB0aXBvcyBkYXMgY29sdW5hcyBubyBub3ZvIGBkYXRhLmZyYW1lYCBwcmVjaXNhbSBjb2luY2lkaXIgY29tIG9zIHVzYWRvcyBubyBhanVzdGUuCgpgYGB7ciBtb2RlbG8tZmluYWx9Cm1vZGVsb19maW5hbCA8LSBtb2RlbG80Cgpub3Zhc19mbG9yZXMgPC0gdGliYmxlKAogIGNlbmFyaW8gPSBjKCJGbG9yIEEiLCAiRmxvciBCIiwgIkZsb3IgQyIpLAogIFNlcGFsLldpZHRoID0gYygyLjUsIDMuMCwgMy41KSwKICBQZXRhbC5MZW5ndGggPSBjKDEuNSwgNC4wLCA1LjUpLAogIFNwZWNpZXMgPSBmYWN0b3IoCiAgICBjKCJzZXRvc2EiLCAidmVyc2ljb2xvciIsICJ2aXJnaW5pY2EiKSwKICAgIGxldmVscyA9IGxldmVscyhkYWRvcyRTcGVjaWVzKQogICkKKQoKaWNfbWVkaWEgPC0gcHJlZGljdChtb2RlbG9fZmluYWwsIG5ld2RhdGEgPSBub3Zhc19mbG9yZXMsCiAgICAgICAgICAgICAgICAgICAgaW50ZXJ2YWwgPSAiY29uZmlkZW5jZSIsIGxldmVsID0gMC45NSkKaXBfaW5kaXZpZHVhbCA8LSBwcmVkaWN0KG1vZGVsb19maW5hbCwgbmV3ZGF0YSA9IG5vdmFzX2Zsb3JlcywKICAgICAgICAgICAgICAgICAgICAgICAgIGludGVydmFsID0gInByZWRpY3Rpb24iLCBsZXZlbCA9IDAuOTUpCgpiaW5kX3Jvd3MoCiAgYmluZF9jb2xzKG5vdmFzX2Zsb3JlcywgYXNfdGliYmxlKGljX21lZGlhKSkgfD4KICAgIG11dGF0ZShpbnRlcnZhbG8gPSAiSUMgOTUlIGRhIG3DqWRpYSIpLAogIGJpbmRfY29scyhub3Zhc19mbG9yZXMsIGFzX3RpYmJsZShpcF9pbmRpdmlkdWFsKSkgfD4KICAgIG11dGF0ZShpbnRlcnZhbG8gPSAiSVAgOTUlIGluZGl2aWR1YWwiKQopIHw+CiAgc2VsZWN0KGNlbmFyaW8sIFNwZWNpZXMsIFNlcGFsLldpZHRoLCBQZXRhbC5MZW5ndGgsIGludGVydmFsbywKICAgICAgICAgZXN0aW1hdGl2YSA9IGZpdCwgaW5mZXJpb3IgPSBsd3IsIHN1cGVyaW9yID0gdXByKSB8PgogIGtuaXRyOjprYWJsZShkaWdpdHMgPSAzKSB8PgogIGthYmxlX3N0eWxpbmcoZnVsbF93aWR0aCA9IEZBTFNFLCBib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG92ZXIiKSkKYGBgCgotICoqSW50ZXJ2YWxvIGRlIGNvbmZpYW7Dp2EgZGEgbcOpZGlhOioqIGNhcHR1cmEgYSBpbmNlcnRlemEgc29icmUgbyBjb21wcmltZW50byBtw6lkaW8gZXNwZXJhZG8gZGUgdG9kYXMgYXMgZmxvcmVzIGNvbSBhcXVlbGUgY29uanVudG8gZGUgcHJlZGl0b3Jlcy4KLSAqKkludGVydmFsbyBkZSBwcmV2aXPDo286KiogY2FwdHVyYSBhIGluY2VydGV6YSBwYXJhIHVtYSBub3ZhIGZsb3IgaW5kaXZpZHVhbDsgaW5jb3Jwb3JhIGEgdmFyaWHDp8OjbyByZXNpZHVhbCBlLCBwb3IgaXNzbywgw6kgc2VtcHJlIG1haXMgYW1wbG8gcGFyYSBvcyBtZXNtb3MgdmFsb3JlcyBkb3MgcHJlZGl0b3Jlcy4KCjxkaXYgY2xhc3M9ImNoZWNrcG9pbnQiPgpQYXJhIHVtYSBwcmV2aXPDo28gaW5kaXZpZHVhbCwgdXNlIG8gaW50ZXJ2YWxvIGRlIHByZXZpc8Ojby4gVXNhciBvIGludGVydmFsbyBkZSBjb25maWFuw6dhIGRhIG3DqWRpYSBuZXNzZSBjYXNvIHByb2R1eiB1bWEgZmFpeGEgZXN0cmVpdGEgZGVtYWlzIGUgYXVtZW50YSBhIGNoYW5jZSBkZSBuw6NvIGNvbnRlciBvIHZhbG9yIGluZGl2aWR1YWwgb2JzZXJ2YWRvLgo8L2Rpdj4KCjxkaXYgY2xhc3M9InRlYWNoZXItbm90ZSI+CjxzdHJvbmc+RGljYSBwYXJhIHVtYSBhbsOhbGlzZSB2b2x0YWRhIMOgIHByZXZpc8Ojby48L3N0cm9uZz4gRW0gdW0gcHJvamV0byBwcmVkaXRpdm8sIHNlcGFyZSBvcyBkYWRvcyBsb2dvIG5vIGluw61jaW8gZW0gZHVhcyBiYXNlczogPHN0cm9uZz50cmVpbmFtZW50bzwvc3Ryb25nPiBlIDxzdHJvbmc+dGVzdGU8L3N0cm9uZz4uIFVzZSBzb21lbnRlIGEgYmFzZSBkZSB0cmVpbmFtZW50byBwYXJhIGV4cGxvcmFyIG9zIGRhZG9zLCBhanVzdGFyIG9zIG1vZGVsb3MsIGNvbXBhcmFyIGVzcGVjaWZpY2HDp8O1ZXMgZSBkaWFnbm9zdGljYXIgcmVzw61kdW9zIOKAlCBvdSBzZWphLCBwYXJhIHJlYWxpemFyIHRvZG8gbyBwZXJjdXJzbyBhcHJlc2VudGFkbyBhdMOpIGFxdWkuIEd1YXJkZSBhIGJhc2UgZGUgdGVzdGUgc2VtIHVzw6EtbGEgbmVzc2UgcHJvY2Vzc28uIEFvIGZpbmFsLCBhcGxpcXVlIDxjb2RlPnByZWRpY3QoKTwvY29kZT4gYW8gY29uanVudG8gZGUgdGVzdGUgZSBjb21wYXJlIGFzIHByZXZpc8O1ZXMgY29tIG9zIHZhbG9yZXMgdmVyZGFkZWlyb3MgZGUgPGNvZGU+U2VwYWwuTGVuZ3RoPC9jb2RlPiwgcG9yIGV4ZW1wbG8gY29tIFJRTUUsIE1BRSBlIGdyw6FmaWNvcyBkZSBvYnNlcnZhZG8gdmVyc3VzIHByZXZpc3RvLiBFc3NhIGF2YWxpYcOnw6NvIG1vc3RyYSBjb21vIG8gbW9kZWxvIHNlIGNvbXBvcnRhIGVtIGZsb3JlcyBxdWUgbsOjbyBwYXJ0aWNpcGFyYW0gZG8gYWp1c3RlLiBOZXN0YSBhdWxhLCBhIGJhc2UgY29tcGxldGEgZm9pIHVzYWRhIHBhcmEgcHJpdmlsZWdpYXIgYSBleHBsaWNhw6fDo28gZSBhIGluZmVyw6puY2lhOyBhIGRpdmlzw6NvIMOpIHVtYSBleHRlbnPDo28gcmVjb21lbmRhZGEgcXVhbmRvIGEgZmluYWxpZGFkZSBwcmluY2lwYWwgZm9yIHByZXZpc8Ojby4KPC9kaXY+CgojIENvbmNsdXPDtWVzIGZpbmFpcwoKIyMgU8OtbnRlc2UgZGEgZXhwbG9yYcOnw6NvCgpBIGJhc2UgY29udMOpbSAxNTAgZmxvcmVzLCBpZ3VhbG1lbnRlIGRpc3RyaWJ1w61kYXMgZW50cmUgYHNldG9zYWAsIGB2ZXJzaWNvbG9yYCBlIGB2aXJnaW5pY2FgLCBzZW0gdmFsb3JlcyBhdXNlbnRlcy4gQXMgbWVkaWRhcyBkYXMgcMOpdGFsYXMgc8OjbyBmb3J0ZW1lbnRlIGNvcnJlbGFjaW9uYWRhcyBlbnRyZSBzaSAoJHJcYXBwcm94MHssfTk2MyQpLCBvIHF1ZSBleHBsaWNhIGEgbXVsdGljb2xpbmVhcmlkYWRlIG9ic2VydmFkYSBxdWFuZG8gYW1iYXMgZW50cmFtIHNpbXVsdGFuZWFtZW50ZS4gQSBleHBsb3Jhw6fDo28gdGFtYsOpbSBtb3N0cmEgc2VwYXJhw6fDo28gbWFyY2FudGUgZW50cmUgZXNww6ljaWVzLCBwcmluY2lwYWxtZW50ZSBuYXMgbWVkaWRhcyBkYSBww6l0YWxhOyBwb3IgaXNzbywgYFNwZWNpZXNgIG7Do28gcG9kZSBzZXIgaWdub3JhZGEgc2VtIHVtYSBqdXN0aWZpY2F0aXZhIHN1YnN0YW50aXZhLgoKIyMgRGVjaXPDo28gZSBpbnRlcnByZXRhw6fDo28KCkFww7NzIG9zIGRpYWduw7NzdGljb3MsIG8gTW9kZWxvIDQgcGVybWFuZWNlIG8gKiptZWxob3IgYWp1c3RlIGludGVybm8qKiBlbnRyZSBvcyBjaW5jbyBtb2RlbG9zOiBvcyBncsOhZmljb3MgbsOjbyByZXZlbGFtIHVtIG1vdGl2byBjbGFybyBwYXJhIGRlc2NhcnTDoS1sbywgZSBlbGUgbGlkZXJhIG9zIGNyaXTDqXJpb3MgZGUgYWp1c3RlLiBQb3LDqW0sIGVsZSBuw6NvIMOpIGF1dG9tYXRpY2FtZW50ZSBvIG1lbGhvciBtb2RlbG8gcGFyYSB0b2RhIGZpbmFsaWRhZGUuIFBhcmEgZGVzY3Jpw6fDo28gZ2xvYmFsIGludGVybmEsIGVsZSDDqSBhIGVzY29saGEgcHJpbmNpcGFsOyBwYXJhIGVuc2luYXIgZSBpbnRlcnByZXRhciBlZmVpdG9zIGNvbnTDrW51b3MgY29tIG1lbm9yIGNvbGluZWFyaWRhZGUsIG8gTW9kZWxvIDIgw6kgdW1hIGFsdGVybmF0aXZhIG1haXMgZXN0w6F2ZWwgZSBtYWlzIHNpbXBsZXMuIE7Do28gaMOhIGJhc2UgZGUgdGVzdGUgbmVzdGEgYW7DoWxpc2UsIHBvcnRhbnRvIG7Do28gw6kgcG9zc8OtdmVsIGFmaXJtYXIgcXVhbCBkb3MgY2luY28gw6kgbWVsaG9yIHBhcmEgcHJldmVyIG5vdmFzIGZsb3Jlcy4KCk5vIE1vZGVsbyA0OgoKLSBtYW50ZW5kbyBgUGV0YWwuTGVuZ3RoYCBlIGBTcGVjaWVzYCBjb25zdGFudGVzLCAxIGNtIGFkaWNpb25hbCBlbSBgU2VwYWwuV2lkdGhgIGVzdMOhIGFzc29jaWFkbyBhIHVtIGF1bWVudG8gbcOpZGlvIGRlIGByIGZtdF9udW0oY29lZihtb2RlbG80KVsiU2VwYWwuV2lkdGgiXSlgIGNtIGVtIGBTZXBhbC5MZW5ndGhgOwotIG1hbnRlbmRvIGBTZXBhbC5XaWR0aGAgZSBgU3BlY2llc2AgY29uc3RhbnRlcywgMSBjbSBhZGljaW9uYWwgZW0gYFBldGFsLkxlbmd0aGAgZXN0w6EgYXNzb2NpYWRvIGEgdW0gYXVtZW50byBtw6lkaW8gZGUgYHIgZm10X251bShjb2VmKG1vZGVsbzQpWyJQZXRhbC5MZW5ndGgiXSlgIGNtIGVtIGBTZXBhbC5MZW5ndGhgOwotIG9zIGNvZWZpY2llbnRlcyBkZSBgdmVyc2ljb2xvcmAgZSBgdmlyZ2luaWNhYCBzw6NvIG5lZ2F0aXZvcyBlbSByZWxhw6fDo28gYSBgc2V0b3NhYCAqKmRlcG9pcyBkZSBmaXhhciBhcyBkdWFzIG1lZGlkYXMgbnVtw6lyaWNhcyoqLiBFbGVzIG7Do28gY29udHJhZGl6ZW0gb3MgZ3LDoWZpY29zIGRlIG3DqWRpYXMgYnJ1dGFzOiByZXNwb25kZW0gYSB1bWEgY29tcGFyYcOnw6NvIGNvbmRpY2lvbmFsIGRpZmVyZW50ZSBlIGFwb2lhZGEgcG9yIHBvdWNhIHNvYnJlcG9zacOnw6NvIGRlIGNvbXByaW1lbnRvIGRlIHDDqXRhbGEgZW50cmUgYXMgZXNww6ljaWVzLgoKYGBge3IgY29uY2x1c2FvLWNvZWZpY2llbnRlc30KdGFiZWxhX2NvZWZpY2llbnRlcyhtb2RlbG80KSB8PgogIGtuaXRyOjprYWJsZShkaWdpdHMgPSAzKSB8PgogIGthYmxlX3N0eWxpbmcoZnVsbF93aWR0aCA9IEZBTFNFLCBib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG92ZXIiKSkKYGBgCgojIyBWZXJpZmljYcOnw6NvIGZpbmFsIGRvcyBwcmVzc3Vwb3N0b3MKCk9zIGdyw6FmaWNvcyBkZSByZXPDrWR1b3MgZSBlc2NhbGHigJNsb2NhbGl6YcOnw6NvIG7Do28gc3VnZXJlbSBtdWRhbsOnYSBmb3J0ZSBkZSB2YXJpw6JuY2lhLiBPIHRlc3RlIGRlIFNoYXBpcm/igJNXaWxrIGFwcmVzZW50b3UgcC12YWxvciBgciBmbXRfbnVtKHRlc3RlX3NoYXBpcm8kcC52YWx1ZSwgNClgLCBjb21wYXTDrXZlbCBjb20gYSBub3JtYWxpZGFkZSBhcHJveGltYWRhIGluZGljYWRhIHBlbG8gUVEtcGxvdCBjb20gZW52ZWxvcGUuIE9zIGdyw6FmaWNvcyBkZSBhbGF2YW5jYWdlbSBlIGRpc3TDom5jaWEgZGUgQ29vayBmb3JhbSBleGFtaW5hZG9zIGVtIGNvbmp1bnRvIGUgbsOjbyByZXZlbGFyYW0gdW0gbW90aXZvIGlzb2xhZG8gcGFyYSBkZXNjYXJ0YXIgbyBhanVzdGUuCgpBIGluZGVwZW5kw6puY2lhIG7Do28gcG9kZSBzZXIgZXN0YWJlbGVjaWRhIGFwZW5hcyBjb20gYSBiYXNlLiBTZSBob3V2ZXIgdsOhcmlhcyBmbG9yZXMgcHJvdmVuaWVudGVzIGRhIG1lc21hIHBsYW50YSwgY2FudGVpcm8gb3UgbG9jYWwsIHNlcmlhIG5lY2Vzc8OhcmlvIHJlcHJlc2VudGFyIGVzc2EgZXN0cnV0dXJhIG5vIG1vZGVsby4gQXMgb2JzZXJ2YcOnw7VlcyBzaW5hbGl6YWRhcyBwb3IgaW5mbHXDqm5jaWEgdGFtYsOpbSBkZXZlbSBzZXIgaW52ZXN0aWdhZGFzLCBuw6NvIGVsaW1pbmFkYXMgYXV0b21hdGljYW1lbnRlLgoKIyMgQ29uY2x1c8OjbyBzdWJzdGFudGl2YQoKTyBjb21wcmltZW50byBkYSBzw6lwYWxhIGVzdMOhIHBvc2l0aXZhbWVudGUgYXNzb2NpYWRvIMOgIGxhcmd1cmEgZGEgc8OpcGFsYSBlIGFvIGNvbXByaW1lbnRvIGRhIHDDqXRhbGEsIGRlcG9pcyBkZSBjb250cm9sYXIgYSBlc3DDqWNpZS4gQSBlc3DDqWNpZSBvcmdhbml6YSBncmFuZGUgcGFydGUgZGEgZXN0cnV0dXJhIG1vcmZvbMOzZ2ljYSBkYSBiYXNlIGUgYWx0ZXJhIGEgaW50ZXJwcmV0YcOnw6NvIGRhcyByZWxhw6fDtWVzIGVudHJlIGFzIG1lZGlkYXMuIEVudHJlIG9zIGNpbmNvIG1vZGVsb3MgZXN0dWRhZG9zLCBvIE1vZGVsbyA0IG9mZXJlY2UgbyBtZWxob3IgYWp1c3RlIGludGVybm87IG8gTW9kZWxvIDIgb2ZlcmVjZSBhIGxlaXR1cmEgbWFpcyBzaW1wbGVzIGRvcyBlZmVpdG9zIGNvbnTDrW51b3MuIE9zIGNvbnRyYXN0ZXMgZGUgZXNww6ljaWUgZG8gTW9kZWxvIDQgcHJlY2lzYW0gc2VyIGNvbXVuaWNhZG9zIGNvbW8gYXNzb2NpYcOnw7VlcyBjb25kaWNpb25haXMsIHNvYiBmb3J0ZSBjb2xpbmVhcmlkYWRlLgoKQXMgY29uY2x1c8O1ZXMgc8OjbyAqKmFzc29jaWF0aXZhcywgbsOjbyBjYXVzYWlzKiouIEEgYmFzZSBJcmlzIMOpIG9ic2VydmFjaW9uYWwgZSBuw6NvIGNvbnTDqW0gZGV0YWxoZXMgc3VmaWNpZW50ZXMgZG8gZGVzZW5obyBkYSBjb2xldGEgcGFyYSBzdXN0ZW50YXIgYWZpcm1hw6fDtWVzIGRlIGNhdXNhIGUgZWZlaXRvLgo=