Introdução e Contexto

O Problema de Negócio

A rotatividade dos funcionários (também conhecida por Employee Attrition) é um dos maiores desafios das organizações, e um dos que traz mais custos. Estudos indicam que o custo de substituir um funcionário pode variar entre 50% a 200% do seu salário anual, sendo considerados os custos de recrutamento, de formação e de perda de produtividade.

Para além do impacto financeiro, uma taxa de turnover elevada afeta a moral das equipas, a cultura da empresa e a continuidade dos projetos. Por isso, a capacidade de prever quem está em risco de sair e, mais importante, porquê, é uma vantagem competitiva crucial para o Departamento de Recursos Humanos (RH).

Sobre o Dataset

Neste projeto, foi utilizado o datasetIBM HR Analytics Employee Attrition & Performance”, disponibilizado publicamente no Kaggle. Este conjunto de dados foi criado por cientistas de dados da IBM e, embora seja fictício, reflete desafios reais do mundo corporativo.

O dataset contém 1470 observações (funcionários) e 35 variáveis (características)

Dicionário de Variáveis

A nossa variável-alvo (Target) é a Attrition, que indica se o funcionário saiu (“Yes”) ou permaneceu (“No”) na empresa.

As restantes variáveis podem ser agrupadas em três categorias principais que iremos explorar:

  1. Demográficas: Age, Gender, MaritialStatus, DistanceFromHome;

  2. Dados do Trabalho: Department, JobRole, JobLevel, OverTime, BusinessTravel;

  3. Compensação e Satisfação: MonthlyIncome, PercentSalaryHike, StockOptionLevel, JobSatisfaction, EnvironmentSatisfaction.

Para facilitar a leitura, foram destacadas acima apenas as variáveis mais relevantes para a análise. A lista completa das 35 variáveis e os seus tipos de dados serão apresentados na secção técnica de inspeção de dados.

Objetivos do Projeto

O objetivo central deste projeto é desenvolver uma solução de People Analytics capaz de antecipar a rotatividade de talentos e fornecer à gestão estratégias baseadas em dados. Para tal, a análise foca-se em três pilares verticais:

  • Diagnóstico de Causa Raiz: Quantificar o impacto real de fatores de risco, verificando a hipótese de que a sobrecarga de trabalho (OverTime) e a logística (DistanceFromHome) são catalisadores de burnout.

  • Hierarquia de Retenção: Determinar, através de algoritmos de Machine Learning, o que pesa mais na decisão de saída: incentivos financeiros (MonthlyIncome) ou fatores intangíveis como a Satisfação no Trabalho.

  • Modelação Preditiva: Treinar algoritmos de classificação (Regressão Logística e Random Forest) para identificar colaboradores em risco com elevada precisão, permitindo uma atuação preventiva do RH.

Importação dos Dados e Inspeção Inicial

# Importação dos Dados
# Lemos o ficheiro original
ibm_hr <- read.csv("data/WA_Fn-UseC_-HR-Employee-Attrition.csv", sep = ";")


library(janitor)
library(dplyr)

# Limpeza e Padronização
# Aqui criamos o objeto 'ibm_clean'

ibm_clean <- ibm_hr %>% 
  clean_names() %>% 
  # Removemos colunas que não variam
  select(-any_of(c("employee_count", "over18", "standard_hours", "employee_number")))

# Visualização (kable)
library(kableExtra)
ibm_clean %>% 
  select(age, attrition, monthly_income, job_role, over_time, total_working_years) %>% 
  head(10) %>% 
  kable(caption = "Tabela 1: Amostra das Variáveis Críticas para Análise de Rotatividade") %>% 
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"), 
                full_width = T, 
                position = "center") %>% 
  row_spec(0, bold = T, color = "white", background = "#2c3e50") 
Tabela 1: Amostra das Variáveis Críticas para Análise de Rotatividade
age attrition monthly_income job_role over_time total_working_years
41 Yes 5993 Sales Executive Yes 8
49 No 5130 Research Scientist No 10
37 Yes 2090 Laboratory Technician Yes 7
33 No 2909 Research Scientist Yes 8
27 No 3468 Laboratory Technician No 6
32 No 3068 Laboratory Technician No 8
59 No 2670 Laboratory Technician Yes 12
30 No 2693 Laboratory Technician No 1
38 No 9526 Manufacturing Director No 10
36 No 5237 Healthcare Representative No 17

A base de dados é composta por 35 variáveis que abrangem três dimensões centrais: características demográficas, fatores financeiros e indicadores de desempenho profissional.

Nesta fase inicial, a análise incide sobre variáveis com maior potencial explicativo da rotatividade de colaboradores, nomeadamente a remuneração mensal, os anos totais de antiguidade na empresa e a realização de horas extra.

Evidências empíricas e análises preliminares apontam para uma relação significativa entre estes fatores e a probabilidade de saída dos colaboradores, constituindo, por isso, pontos de partida fundamentais para o aprofundamento da análise.

Tratamento de Dados

Limpeza de Dados

A análise descritiva inicial, evidenciou dois aspetos relevantes relativamente à qualidade e estrutura do conjunto de dados:

  1. Qualidade dos dados – Verificou-se a inexistência de valores em falta (missing values) em todas as variáveis, o que simplifica substancialmente as etapas de pré-processamento.

  2. Variáveis redundantes e não informativas – Foram identificadas três variáveis com valor constante em todas as observações (desvio padrão = 0), bem como uma variável de identificação individual. Por não apresentarem variabilidade ou não contribuírem para a explicação do fenómeno estudado, estas variáveis foram removidas do dataset.

As variáveis eliminadas foram:

  • EmployeeCount: valor constante igual a “1”;

  • Over18: todos os colaboradores registados como maiores de idade (“Y”);

  • StandardHours: valor fixo de “80” em todos os registos;

  • EmployeeNumber: identificador único dos colaboradores, sem relevância preditiva.

A exclusão destas variáveis permite reduzir a dimensionalidade dos dados sem perda de informação relevante, contribuindo para um modelo analítico mais eficiente e interpretável.

# Padronização de Nomes
ibm_clean <- ibm_hr %>% 
  clean_names()

# Remover Variáveis Invariantes
colunas_remover <- c("employee_count", "over18", "standard_hours", "employee_number")

ibm_clean <- ibm_clean %>% 
  select(-any_of(colunas_remover))

# Resumo da Limpeza
cat("Base de dados limpa com sucesso.\n",
    "Total de Colunas Originais: ", ncol(ibm_hr), "\n",
    "Total de Colunas Após Limpeza: ", ncol(ibm_clean))
Base de dados limpa com sucesso.
 Total de Colunas Originais:  35 
 Total de Colunas Após Limpeza:  31

Análise Exploratória dos Dados (AED)

Esta fase tem como principal objetivo compreender a distribuição das variáveis e identificar padrões ou relações que possam explicar o fenómeno da rotatividade de colaboradores (employee attrition).

Inicia-se a exploração pela variável alvo, Attrition, que indica se o colaborador permaneceu na empresa (No) ou optou pela saída (Yes).

A análise desta variável fornece uma primeira perceção acerca do equilíbrio entre colaboradores ativos e aqueles que deixaram a organização, permitindo avaliar a dimensão real do fenómeno de saída.

Análise da Variável Target (Attrition)

Quantos funcionários efetivamente saíram da empresa?

# Criar a Tabela de Frequência Profissional
tabela_target <- ibm_clean %>%
  count(attrition) %>%
  mutate(
    percentagem = (n / sum(n)) * 100,
    attrition = ifelse(attrition == "Yes", "Saiu (Yes)", "Permaneceu (No)")
  )

# Exibir Tabela com o kableExtra
tabela_target %>%
  kable(
    caption = "Distribuição da Variável-Target (Attrition)",
    col.names = c("Status", "Total (n)", "Percentagem (%)"),
    digits = 1
  ) %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = F) %>%
  row_spec(0, bold = T, color = "white", background = "#2c3e50") %>%
  column_spec(3, bold = T, color = ifelse(tabela_target$percentagem < 20, "#e74c3c", "#2c3e50"))
Distribuição da Variável-Target (Attrition)
Status Total (n) Percentagem (%)
Permaneceu (No) 1233 83.9
Saiu (Yes) 237 16.1
# Visualização
ggplot(ibm_clean, aes(x = attrition, fill = attrition)) +
  geom_bar(width = 0.6, alpha = 0.9) +
 
  scale_fill_manual(values = c("No" = "#2C3E50", "Yes" = "#E74C3C")) +
  scale_y_continuous(expand = expansion(mult = c(0, 0.1))) +
  labs(
    title = "Visão Geral da Rotatividade na Empresa",
    subtitle = "Apenas 16% dos colaboradores deixaram a organização no período analisado",
    x = "Decisão de Saída",
    y = "Número de Funcionários"
  ) +
  theme_minimal() +
  theme(
    legend.position = "none", 
    plot.title = element_text(face = "bold", size = 16, color = "#2c3e50"),
    panel.grid.major.x = element_blank() 
  )

Insight Inicial: Verifica-se que a taxa de rotatividade (Attrition Rate) é de aproximadamente 16%, o que indica que a maioria dos colaboradores (cerca de 84%) permaneceu na empresa durante o período analisado.

Observa-se, assim, um desequilíbrio entre as classes da variável alvo, com predominância de colaboradores que não saíram da organização.

Este ponto é particularmente relevante para etapas posteriores de modelação preditiva, uma vez que a desproporção entre classes pode levar o modelo a sobrevalorizar a classe maioritária (colaboradores que ficam) e negligenciar os casos de saída, que são precisamente os que mais interessam compreender e prever.

Análise Demográfica: A Idade Influencia?

Vamos analisar a distribuição de idade entre os funcionários que saíram e os que ficaram. Utilizamos um Boxplot para visualizar a mediana e a dispersão dos dados.

# Gráfico: Distribuição de Idade por Rotatividade
ggplot(ibm_clean, aes(x = attrition, y = age, fill = attrition)) +
  geom_jitter(alpha = 0.2, color = "grey40", width = 0.2) +
  geom_boxplot(alpha = 0.8, outlier.colour = "red", width = 0.5) +
  
  # Cores consistentes com o resto do relatório
  scale_fill_manual(values = c("No" = "#2C3E50", "Yes" = "#E74C3C")) +
  
  labs(
    title = "O Fator Idade na Retenção de Talento",
    subtitle = "Colaboradores que saem (Yes) apresentam uma mediana de idade visivelmente inferior",
    x = "Decisão de Saída",
    y = "Idade (Anos)"
  ) +
  theme_minimal() +
  theme(
    legend.position = "none",
    plot.title = element_text(face = "bold", size = 16, color = "#2c3e50"),
    panel.grid.major.x = element_blank(),
    axis.title = element_text(face = "bold")
  )

Insights sobre a Idade:

A análise do boxplot evidencia uma tendência clara na relação entre idade e rotatividade de colaboradores:

  1. Fator Juventude – Verifica-se uma tendência segundo a qual os colaboradores mais jovens apresentam uma maior propensão para sair da empresa. A mediana de idade dos funcionários que saem é visivelmente inferior à dos que permanecem.

  2. Zona de Risco – A maior concentração de saídas situa-se entre os 25 e os 35 anos, faixa etária frequentemente associada a mobilidade profissional e procura de progressão na carreira. Este comportamento pode refletir desafios da organização em reter talento jovem ou em oferecer planos de desenvolvimento estruturados.

  3. Estabilidade Sénior – Colaboradores com mais de 40 anos apresentam maior estabilidade e menor probabilidade de saída. As poucas ocorrências nesta faixa etária surgem como outliers no gráfico, sugerindo casos pontuais de saída da empresa (por exemplo, reforma, mudança pessoal ou reestruturação interna).

Conclusão: Os resultados sugerem a necessidade de uma estratégia de retenção segmentada:

  • Colaboradores júniores e intermédios (25-35 anos) devem ser alvo de ações focadas em engagement, progressão interna e gestão de expectativas de carreira;

  • Já para os colaboradores séniores, o foco poderá ser reconhecimento, mentoria e transmissão de know-how, reforçando o sentimento de pertença e continuidade organizacional.

# Gráfico de Barras: Proporção de Saída por Estado Civil
ggplot(ibm_clean, aes(x = marital_status, fill = attrition)) +
  geom_bar(position = "fill", width = 0.7, alpha = 0.9) +
  
  scale_fill_manual(values = c("No" = "#2C3E50", "Yes" = "#E74C3C")) +
  
  # Formatação do eixo Y para percentagem
  scale_y_continuous(labels = scales::percent_format(), expand = c(0,0)) +
  
  labs(
    title = "Impacto do Estado Civil na Retenção",
    subtitle = "Colaboradores solteiros apresentam uma taxa de saída significativamente superior",
    x = "Estado Civil",
    y = "Proporção de Funcionários",
    fill = "Saída?"
  ) +
  theme_minimal() +
  theme(
    plot.title = element_text(face = "bold", size = 16, color = "#2c3e50"),
    legend.position = "top", 
    panel.grid.major.x = element_blank(),
    axis.text.x = element_text(face = "bold") 
  )

Insights sobre o Estado Civil:

A análise sugere que o estado civil constitui um fator relevante na rotatividade de colaboradores:

  1. Maior risco entre colaboradores solteiros – Os trabalhadores solteiros registam uma taxa de saída superior a 25%, mais do dobro da observada entre colaboradores casados ou divorciados (aproximadamente 11%). Este resultado indica que a probabilidade de saída está significativamente associada ao estado civil.

  2. Possível explicação comportamental – Este padrão é consistente com evidência empírica na literatura de recursos humanos, que aponta que profissionais sem dependentes ou laços familiares diretos tendem a apresentar maior mobilidade laboral. Essa flexibilidade geográfica e financeira pode facilitar a procura de novas oportunidades ou a aceitação de propostas em diferentes locais.

Conclusão: A gestão de talento poderá beneficiar de estratégias diferenciadas de retenção entre grupos, promovendo, por exemplo, iniciativas de progressão de carreira e programas de envolvimento organizacional que aumentem o compromisso dos colaboradores mais jovens e solteiros com a empresa.

Análise Profissional: Carga de Trabalho e Viagens

Será que o excesso de trabalho (OverTime) e as viagens frequentes (BusinessTravel) levam à exaustão e consequente saída?

# Gráfico de Horas Extra (p1)
p1 <- ggplot(ibm_clean, aes(x = over_time, fill = attrition)) +
  geom_bar(position = "fill", width = 0.7, alpha = 0.9) +
  scale_y_continuous(labels = scales::percent_format(), expand = c(0,0)) +
  scale_fill_manual(values = c("No" = "#2C3E50", "Yes" = "#E74C3C")) +
  labs(
    title = "Impacto das Horas Extra", 
    x = "Faz Horas Extra?", 
    y = "Proporção"
  ) +
  theme_minimal() +
  theme(
    legend.position = "none", 
    plot.title = element_text(face = "bold", size = 13, color = "#2c3e50"),
    panel.grid.major.x = element_blank()
  )

# Gráfico de Viagens de Trabalho (p2)
p2 <- ggplot(ibm_clean, aes(x = business_travel, fill = attrition)) +
  geom_bar(position = "fill", width = 0.7, alpha = 0.9) +
  scale_y_continuous(labels = scales::percent_format(), expand = c(0,0)) +
  scale_fill_manual(values = c("No" = "#2C3E50", "Yes" = "#E74C3C")) +
  labs(
    title = "Impacto das Viagens", 
    x = "Frequência de Viagens", 
    y = NULL,
    fill = "Saída?"
  ) +
  theme_minimal() +
  theme(
    plot.title = element_text(face = "bold", size = 13, color = "#2c3e50"),
    axis.text.x = element_text(angle = 45, hjust = 1),
    panel.grid.major.x = element_blank()
  )

# Juntar as duas visualizações
library(gridExtra)
grid.arrange(p1, p2, ncol = 2, top = grid::textGrob("Análise de Carga de Trabalho e Mobilidade", 
                                                   gp = grid::gpar(fontsize = 16, font = 2, col = "#2c3e50")))

Insights sobre Carga de Trabalho e Estilo de Vida:

A análise da carga de trabalho e da mobilidade profissional revela uma associação evidente entre exaustão e rotatividade de colaboradores:

  1. Impacto das Horas Extra – O efeito das horas extra é particularmente expressivo. Colaboradores que não realizam horas extra apresentam uma taxa de saída próxima de 10%, enquanto entre os que trabalham além do horário regular, essa proporção triplica para cerca de 30%. Este resultado constitui um indicador claro de risco de burnout e sugere que o excesso de carga horária pode estar associado à insatisfação e desgaste emocional.

  2. O Peso da Mobilidade (BusinessTravel) – Observa-se uma tendência crescente entre frequência de viagens e probabilidade de saída:

  • Colaboradores que não viajam (Non‑Travel) apresentam a menor taxa de rotatividade (<10%);

  • Entre os que viajam com frequência (Travel_Frequently), o risco aproxima‑se dos 25%, indicando que o equilíbrio entre vida pessoal e profissional se encontra consideravelmente comprometido.

Conclusão: Tanto a sobrecarga de trabalho como a mobilidade excessiva surgem como fatores de risco relevantes para a retenção de talento. Políticas organizacionais que promovam limites saudáveis de jornada, flexibilidade laboral e equilíbrio vida‑trabalho poderão mitigar significativamente este tipo de rotatividade.

Análise Financeira: O Salário Importa?

Foi analisada a distribuição salarial (MonthlyIncome) para entender se salários mais baixos impulsionam a saída.

# Gráfico de Densidade: Salário Mensal por Rotatividade
ggplot(ibm_clean, aes(x = monthly_income, fill = attrition)) +
  geom_density(alpha = 0.7, color = "white") +
  
  scale_fill_manual(values = c("No" = "#2C3E50", "Yes" = "#E74C3C")) +
  
  # Formatação do eixo X para Moeda (Dólar)
  scale_x_continuous(labels = scales::dollar_format(), breaks = seq(0, 20000, 2500)) +
  
  labs(
    title = "Distribuição Salarial e o Risco de Rotatividade",
    subtitle = "A probabilidade de saída é drasticamente superior em faixas salariais abaixo dos $5.000",
    x = "Salário Mensal (USD)",
    y = "Densidade de Colaboradores",
    fill = "Status de Saída"
  ) +
  theme_minimal() +
  theme(
    plot.title = element_text(face = "bold", size = 16, color = "#2c3e50"),
    legend.position = "top",
    panel.grid.minor = element_blank(),
    panel.grid.major.x = element_blank()
  )

Insights Financeiros:

A análise da distribuição salarial evidencia que a remuneração é um fator determinante na probabilidade de saída, apresentando um padrão bastante distinto entre as faixas de rendimento:

  1. **A barreira dos 5000\(** – Observa‑se uma concentração significativa de saídas entre colaboradores com salários mensais inferiores a 5000\) Nesta faixa, a densidade de casos de attrition é substancialmente superior, sugerindo que níveis salariais mais baixos estão associados a uma maior volatilidade da força de trabalho.

  2. Retenção em faixas salariais elevadas – À medida que o salário aumenta (particularmente acima dos 10000$), a probabilidade de saída reduz drasticamente. Entre os colaboradores com rendimentos mais altos, a curva de densidade associada à permanência é claramente predominante, indicando maior estabilidade e satisfação profissional.

Conclusão: O padrão observado sugere que a empresa enfrenta maiores desafios de retenção entre colaboradores de nível operacional e funções júniores, onde a compensação pode não estar alinhada com as expectativas do mercado. Estratégias salariais mais competitivas, complementadas por planos de progressão e valorização interna, poderão ser decisivas para reduzir a rotatividade nestas faixas salariais.

Análise de Função e Satisfação

Antes de avançarmos para as correlações numéricas, falta analisar duas variáveis categóricas cruciais: o Cargo (JobRole) e a Satisfação no Trabalho (JobSatisfaction).

O objetivo é identificar se existem cargos específicos com maior rotatividade.

# Rotatividade por Cargo
p_role <- ggplot(ibm_clean, aes(y = reorder(job_role, (attrition == "Yes")), fill = attrition)) +
  geom_bar(position = "fill", width = 0.7, alpha = 0.9) +
  scale_x_continuous(labels = scales::percent_format(), expand = c(0,0)) +
  scale_fill_manual(values = c("No" = "#2C3E50", "Yes" = "#E74C3C")) +
  labs(
    title = "Rotatividade por Cargo",
    subtitle = "Vendas, RH e Técnicos de Laboratório apresentam maior risco",
    y = NULL,
    x = "Proporção de Saída"
  ) +
  theme_minimal() +
  theme(
    legend.position = "none",
    plot.title = element_text(face = "bold", size = 13, color = "#2c3e50"),
    panel.grid.major.y = element_blank(),
    axis.text.y = element_text(size = 9, face = "bold")
  )

# Impacto da Satisfação
p_sat <- ggplot(ibm_clean, aes(x = factor(job_satisfaction), fill = attrition)) +
  geom_bar(position = "fill", width = 0.6, alpha = 0.9) +
  scale_y_continuous(labels = scales::percent_format(), expand = c(0,0)) +
  scale_fill_manual(values = c("No" = "#2C3E50", "Yes" = "#E74C3C")) +
  labs(
    title = "Impacto da Satisfação no Trabalho",
    subtitle = "Níveis baixos de satisfação (1 e 2) correlacionam-se com maior churn",
    x = "Nível de Satisfação (1: Baixa → 4: Alta)",
    y = "Proporção",
    fill = "Saída?"
  ) +
  theme_minimal() +
  theme(
    plot.title = element_text(face = "bold", size = 13, color = "#2c3e50"),
    legend.position = "right",
    panel.grid.major.x = element_blank()
  )

library(gridExtra)
grid.arrange(p_role, p_sat, nrow = 2, 
             top = grid::textGrob("Análise de Função e Sentimento", 
                                  gp = grid::gpar(fontsize = 16, font = 2, col = "#2c3e50")))

Insights sobre Função e Satisfação:

A análise evidencia padrões distintos de rotatividade por função, revelando áreas críticas dentro da organização:

  1. Funções de Vendas (Sales Representatives) – Este grupo apresenta a maior taxa de saída, próxima dos 40%, o que é indicativo de pressão comercial elevada, objetivos exigentes ou sistemas de incentivos pouco atrativos. Trata‑se de um foco prioritário de atuação, dada a importância estratégica destas funções para o desempenho global da empresa.

  2. Técnicos de Laboratório e Recursos Humanos – Ambas as funções registam taxas de saída em torno dos 25%, claramente acima da média organizacional.

  3. Retenção nas funções de liderança – Os cargos de gestão e direção (Managers e Directors) apresentam níveis de estabilidade muito elevados, o que sugere que a rotatividade é predominantemente um fenómeno dos níveis hierárquicos intermédios e operacionais. Este padrão revela a importância de direcionar as estratégias de retenção e desenvolvimento para as funções mais vulneráveis.

Conclusão: A rotatividade parece concentrar‑se em posições de base e funções de suporte operacional, exigindo políticas focadas em melhoria do clima organizacional, revisão de incentivos e oportunidades de progressão, por forma a fortalecer o compromisso e a retenção nestes grupos.

Análise da Antiguidade e Tempo de Deslocação

Foi investigada a antiguidade na empresa (YearsAtCompany) e a distância de casa (DistanceFromHome). O objetivo é entender se perdemos talento recém-contratado e se o trajeto diário influencia a decisão.

# Gráfico de Antiguidade (Anos na Empresa)
p_years <- ggplot(ibm_clean, aes(x = years_at_company, fill = attrition)) +
  geom_density(alpha = 0.7, color = "white") +
  scale_fill_manual(values = c("No" = "#2C3E50", "Yes" = "#E74C3C")) +
  labs(
    title = "Ciclo de Vida: Antiguidade na Empresa",
    subtitle = "O risco de 'churn' é crítico nos primeiros 2 anos (período de onboarding)",
    x = "Anos na Empresa",
    y = "Densidade"
  ) +
  theme_minimal() +
  theme(
    legend.position = "none",
    plot.title = element_text(face = "bold", size = 13, color = "#2c3e50"),
    panel.grid.minor = element_blank()
  )

# Gráfico de Distância (Boxplot)
p_dist <- ggplot(ibm_clean, aes(x = attrition, y = distance_from_home, fill = attrition)) +
  geom_boxplot(alpha = 0.8, width = 0.6, outlier.colour = "#E74C3C") +
  scale_fill_manual(values = c("No" = "#2C3E50", "Yes" = "#E74C3C")) +
  labs(
    title = "Logística: Distância Casa-Trabalho",
    subtitle = "Colaboradores que saem tendem a percorrer distâncias maiores",
    x = "Decisão de Saída",
    y = "Distância (km/milhas)"
  ) +
  theme_minimal() +
  theme(
    plot.title = element_text(face = "bold", size = 13, color = "#2c3e50"),
    panel.grid.major.x = element_blank()
  )

# Organizar os gráficos
library(gridExtra)
grid.arrange(p_years, p_dist, nrow = 2, 
             top = grid::textGrob("Análise de Retenção e Logística", 
                                  gp = grid::gpar(fontsize = 16, font = 2, col = "#2c3e50")))

Insights de Tempo e Logística:

A análise evidencia pontos críticos no ciclo de vida do colaborador, com implicações diretas para a retenção e o desempenho organizacional:

  1. Fase de Onboarding - Risco de saída precoce: O gráfico de antiguidade mostra um pico acentuado de rotatividade nos primeiros dois anos de vínculo, precisamente durante o período de integração e adaptação. Este resultado sugere fragilidades nos processos de acolhimento, acompanhamento inicial ou alinhamento de expectativas entre o colaborador e a organização. Investir em programas estruturados de onboarding e mentoria poderá reduzir substancialmente este tipo de perda prematura de talento.

  2. Custo da Deslocação – Fator logístico de desgaste: O boxplot de distâncias casa‑trabalho indica que os colaboradores que saem tendem a percorrer trajetos mais longos, o que aponta para um potencial impacto negativo do tempo e esforço de deslocação na satisfação geral. O desgaste associado ao commuting diário, quando combinado com elevadas cargas de trabalho, aumenta a probabilidade de saída voluntária. Medidas como teletrabalho híbrido, adaptação de horários ou incentivos de transporte podem mitigar esse efeito.

Conclusão: A retenção eficaz exige uma abordagem holística que abranja tanto a experiência inicial do colaborador (onboarding) como a sustentabilidade logística da sua rotina laboral. Estas duas dimensões revelam‑se determinantes para consolidar o compromisso organizacional nos primeiros anos de vínculo.

Análise do Género e Work-Life Balance

# Rotatividade por Género (p_gen)
p_gen <- ggplot(ibm_clean, aes(x = gender, fill = attrition)) +
  geom_bar(position = "fill", width = 0.6, alpha = 0.9) +
  scale_y_continuous(labels = scales::percent_format(), expand = c(0,0)) +
  scale_fill_manual(values = c("No" = "#2C3E50", "Yes" = "#E74C3C")) +
  labs(
    title = "Rotatividade por Género", 
    subtitle = "Existe disparidade entre homens e mulheres?",
    x = NULL, 
    y = "Proporção"
  ) +
  theme_minimal() +
  theme(
    legend.position = "none", # Escondemos a legenda aqui para não repetir
    plot.title = element_text(face = "bold", size = 13, color = "#2c3e50"),
    panel.grid.major.x = element_blank(),
    axis.text.x = element_text(face = "bold")
  )

# Análise do Work-Life Balance (p_wlb)
p_wlb <- ggplot(ibm_clean, aes(x = factor(work_life_balance), fill = attrition)) +
  geom_bar(position = "fill", width = 0.6, alpha = 0.9) +
  scale_y_continuous(labels = scales::percent_format(), expand = c(0,0)) +
  scale_fill_manual(values = c("No" = "#2C3E50", "Yes" = "#E74C3C")) +
  labs(
    title = "Equilíbrio Vida-Trabalho", 
    subtitle = "O impacto do equilíbrio na decisão de saída",
    x = "Nível (1: Mau → 4: Excelente)", 
    y = NULL,
    fill = "Saída?"
  ) +
  theme_minimal() +
  theme(
    plot.title = element_text(face = "bold", size = 13, color = "#2c3e50"),
    legend.position = "right",
    panel.grid.major.x = element_blank(),
    axis.text.x = element_text(face = "bold")
  )

# Juntar os dois lado a lado
library(gridExtra)
grid.arrange(p_gen, p_wlb, ncol = 2, 
             top = grid::textGrob("Bem-Estar e Diversidade", 
                                  gp = grid::gpar(fontsize = 16, font = 2, col = "#2c3e50")))

Insights de Género e Bem-Estar:

Para concluir a análise bivariada, destacam‑se dois fatores de natureza social e comportamental com impacto na rotatividade:

  1. Neutralidade de Género – A taxa de saída revela‑se relativamente uniforme entre homens e mulheres, situando‑se entre 15% e 17%. Este resultado sugere ausência de enviesamentos ou práticas discriminatórias associadas ao género, bem como equidade na experiência organizacional entre grupos.

  2. Equilíbrio Vida‑Trabalho – A variável Work‑Life Balance evidencia um “ponto crítico” no nível mais baixo de satisfação. Colaboradores que classificam o seu equilíbrio como “Mau” (Nível 1) apresentam uma taxa de rotatividade próxima de 30%, o dobro da verificada nos restantes níveis. A melhoria do equilíbrio vida‑trabalho, mesmo que apenas de Nível 1 para Nível 2, já produz uma redução substancial na taxa de saída. Isto indica que intervenções pontuais e realistas, como ajustes de horário, políticas de flexibilidade ou reforço do apoio à equipa, podem gerar efeitos imediatos na retenção, sem ser necessário atingir níveis “ideais” de satisfação (Nível 4).

Conclusão: Os resultados apontam para uma cultura organizacional relativamente equilibrada em termos de género, mas vulnerável a fatores ligados ao bem‑estar e equilíbrio pessoal‑profissional. Investir em políticas de saúde ocupacional e flexibilidade laboral poderá ter um retorno direto na satisfação e fidelização dos colaboradores.

Análise Multivariada (Correlações)

Nesta etapa, foi analisada a relação entre as variáveis numéricas para identificar multicolinearidade (redundância). Foi utilizada uma matriz de correlação visual.

ibm_numeric <- ibm_clean %>% select(where(is.numeric))
matriz_cor  <- cor(ibm_numeric, use = "complete.obs")

# Gráfico de correlações
col_paleta <- colorRampPalette(c("#E74C3C", "#FFFFFF", "#2C3E50"))(200)

corrplot(matriz_cor, 
         method = "color", 
         type = "upper", 
         order = "hclust",         
         tl.col = "black", 
         tl.cex = 0.7, 
         col = col_paleta,         
         title = "\n Mapa de Correlações Intervariáveis", 
         mar = c(0,0,2,0),
         diag = FALSE)

# Tabela de correlações
tabela_cor <- as.data.frame(as.table(matriz_cor))

tabela_melhorada <- tabela_cor %>%
  filter(Var1 != Var2) %>%
  filter(!duplicated(paste0(pmax(as.character(Var1), as.character(Var2)), 
                            pmin(as.character(Var1), as.character(Var2))))) %>%
  arrange(desc(abs(Freq))) %>%
  rename(Variavel_1 = Var1, Variavel_2 = Var2, Correlacao = Freq)

# Melhorar design da tabela
kable(head(tabela_melhorada, 10), 
      caption = "Top 10 Correlações Mais Fortes Identificadas", 
      digits = 2,
      col.names = c("Variável 1", "Variável 2", "Força da Correlação")) %>%
  kable_styling(
    bootstrap_options = c("striped", "hover", "condensed"), 
    full_width = T,           
    position = "center",      
    font_size = 14            
  ) %>%
  row_spec(0, bold = T, color = "white", background = "#2c3e50") %>%
  # Destaca em vermelho as correlações que podem causar multicolinearidade (>0.7)
  column_spec(3, bold = T, 
              color = ifelse(abs(head(tabela_melhorada$Correlacao, 10)) > 0.7, "#E74C3C", "black"))
Top 10 Correlações Mais Fortes Identificadas
Variável 1 Variável 2 Força da Correlação
monthly_income job_level 0.95
total_working_years job_level 0.78
performance_rating percent_salary_hike 0.77
total_working_years monthly_income 0.77
years_with_curr_manager years_at_company 0.77
years_in_current_role years_at_company 0.76
years_with_curr_manager years_in_current_role 0.71
total_working_years age 0.68
years_at_company total_working_years 0.63
years_since_last_promotion years_at_company 0.62

Insights da Análise de Correlação:

A matriz e a tabela de correlações evidenciam padrões de multicolinearidade significativos, revelando variáveis fortemente redundantes que exigirão tratamento específico na fase de pré‑processamento dos dados:

  1. Redundância entre remuneração e nível hierárquico: A correlação mais elevada de todo o conjunto é observada entre MonthlyIncome e JobLevel (r = 0.95).

Interpretação: Estas variáveis são, na prática, estatisticamente sobrepostas, pelo que o nível do cargo determina quase totalmente o salário. Manter ambas no modelo poderá introduzir instabilidade nos coeficientes e enviesar a importância preditiva. Assim, será recomendável reter apenas uma variável representativa (por exemplo, JobLevel).

  1. Antiguidade: Identifica‑se um cluster de variáveis temporais altamente correlacionadas, YearsAtCompany, YearsInCurrentRole e YearsWithCurrManager, com correlações entre 0.71 e 0.77.

Interpretação: Funcionários com maior antiguidade tendem a permanecer na mesma função e sob a mesma liderança. Convém, portanto, evitar incluir todas simultaneamente, podendo optar‑se por YearsAtCompany ou pela criação de uma variável agregada de “estagnação”, que capture esta dinâmica.

  1. Experiência profissional e remuneração: A variável TotalWorkingYears apresenta correlação forte com JobLevel (0.78) e MonthlyIncome (0.77).

Interpretação: O sistema de progressão e compensação da empresa aparenta estar altamente alinhado com a senioridade, valorizando sobretudo a experiência acumulada.

  1. Desempenho e recompensas: A correlação de 0.77 entre PerformanceRating e PercentSalaryHike confirma que os aumentos salariais estão diretamente associados à avaliação de desempenho anual — uma política típica de meritocracia organizacional.

Conclusão da Análise Exploratória (EDA): A exploração bivariada e correlacional permite concluir que a rotatividade está associada a fatores demográficos e laborais (idade jovem, cargos operacionais, viagens frequentes, salários mais baixos), enquanto no plano técnico destacam‑se relações redundantes entre variáveis de hierarquia, antiguidade e remuneração.

Estas constatações constituem o ponto de partida para o pré‑processamento de dados, onde serão tratadas as correlações excessivas e selecionadas as variáveis mais relevantes para os modelos preditivos.

Pré-processamento de dados

Seleção de variáveis (Feature Selection)

# Executar a Seleção
ibm_prep <- ibm_clean %>%
  select(-job_level) %>%  
  select(-any_of(c("employee_number", "employee_count", "over18", "standard_hours"))) %>%
  mutate(attrition = ifelse(attrition == "Yes", 1, 0))

# Criar Tabela de Impacto
resumo_prep <- data.frame(
  Etapa = c("Colunas Originais", "Colunas Removidas", "Total Final", "Target (Attrition)"),
  Valor = c(ncol(ibm_clean), 
            ncol(ibm_clean) - ncol(ibm_prep), 
            ncol(ibm_prep), 
            "Convertido para Binário (0/1)")
)

resumo_prep %>%
  kable(caption = "Resumo do Pré-processamento e Feature Selection") %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"), full_width = F) %>%
  row_spec(0, bold = T, color = "white", background = "#2c3e50")
Resumo do Pré-processamento e Feature Selection
Etapa Valor
Colunas Originais 31
Colunas Removidas 1
Total Final 30
Target (Attrition) Convertido para Binário (0/1)

Após a fase de análise exploratória, procedeu‑se à preparação dos dados para a modelação preditiva.

Esta etapa é fundamental para garantir que o modelo resultante não seja influenciado por ruído estatístico nem por informação redundante, assegurando a robustez e interpretabilidade dos resultados.

Principais decisões nesta fase:

  1. Eliminação de redundância (multicolinearidade) – Conforme identificado na matriz de correlações, as variáveis monthly_income e job_level apresentavam uma correlação de 0,95. Para evitar sobreajuste (overfitting) e simplificar o modelo, decidiu‑se manter apenas a variável mais representativa, privilegiando o impacto financeiro direto.

  2. Conversão da variável‑alvo – A variável attrition foi transformada para formato binário (0/1), de modo a permitir a aplicação de modelos de classificação supervisionada e facilitar a análise de desempenho preditivo.

Estas operações asseguram que o conjunto de dados final esteja estatisticamente equilibrado, computacionalmente eficiente e adequado à fase seguinte de modelação.

Criação de Dummies

library(fastDummies)

ibm_final <- dummy_cols(ibm_prep, 
                        remove_first_dummy = TRUE,      
                        remove_selected_columns = TRUE) %>%
             clean_names() # Garante que os nomes das novas colunas ficam padronizados

# Criar uma comparação visual
comparativo_dim <- data.frame(
  Metrica = c("Colunas Pré-Dummies", "Colunas Pós-Dummies (Expandidas)", "Novas Variáveis Criadas"),
  Quantidade = c(ncol(ibm_prep), ncol(ibm_final), ncol(ibm_final) - ncol(ibm_prep))
)

# Exibir Tabela de Impacto
comparativo_dim %>%
  kable(caption = "Impacto da Transformação de Variáveis Categóricas (One-Hot Encoding)") %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"), full_width = F) %>%
  row_spec(0, bold = T, color = "white", background = "#2c3e50")
Impacto da Transformação de Variáveis Categóricas (One-Hot Encoding)
Metrica Quantidade
Colunas Pré-Dummies 30
Colunas Pós-Dummies (Expandidas) 44
Novas Variáveis Criadas 14
# Mostrar as novas colunas 
data.frame(Exemplos_Novas_Colunas = colnames(ibm_final)[(ncol(ibm_prep)+1):(ncol(ibm_prep)+6)]) %>%
  kable() %>%
  kable_styling(bootstrap_options = "bordered", full_width = F, position = "float_right")
Exemplos_Novas_Colunas
education_field_other
education_field_technical_degree
gender_male
job_role_human_resources
job_role_laboratory_technician
job_role_manager

A maioria dos algoritmos de Machine Learning não é capaz de processar diretamente variáveis de texto.

Para ultrapassar esta limitação, aplicou‑se a técnica de One‑Hot Encoding, também conhecida por criação de variáveis dummy.

Procedimentos realizados:

  1. Transformação de variáveis categóricas – Variáveis qualitativas, como BusinessTravel ou Department, foram convertidas em múltiplas colunas binárias (0/1), representando a presença ou ausência de cada categoria distinta.

  2. Prevenção de multicolinearidade – Para evitar a chamada dummy variable trap, foi ativado o parâmetro remove_first_dummy = TRUE, o que remove uma categoria de cada grupo. Assim, por exemplo, no caso de uma variável com as modalidades Masculino e Feminino, apenas uma delas é mantida, dado que a ausência de uma implica a presença da outra.

  3. Expansão controlada do dataset – Após o processo, o número total de variáveis aumentou de 30 para 44, resultando na criação de 14 novas variáveis derivadas.

Esta expansão permite representar de forma mais rica a informação qualitativa, sem introduzir redundância ou comprometer a estabilidade dos modelos preditivos.

Divisão dos Dados (Treino e Teste)

library(caTools)
library(dplyr)
library(kableExtra)

# Divisão Estratificada 
set.seed(123)
split <- sample.split(ibm_final$attrition, SplitRatio = 0.70)

dados_treino <- subset(ibm_final, split == TRUE)
dados_teste  <- subset(ibm_final, split == FALSE)

# Criar Tabela de Resumo 
resumo_split <- data.frame(
  Conjunto = c("Treino (70%)", "Teste (30%)", "Total"),
  Observações = c(nrow(dados_treino), nrow(dados_teste), nrow(ibm_final)),
  Taxa_Churn = c(
    paste0(round(mean(dados_treino$attrition) * 100, 1), "%"),
    paste0(round(mean(dados_teste$attrition) * 100, 1), "%"),
    paste0(round(mean(ibm_final$attrition) * 100, 1), "%")
  )
)

# Exibir Tabela 
resumo_split %>%
  kable(caption = "Divisão de Dados: Verificação de Consistência e Estratificação") %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"), 
                full_width = F, 
                position = "center") %>%
  row_spec(0, bold = T, color = "white", background = "#2c3e50") %>%
  column_spec(3, bold = T, color = "#E74C3C") 
Divisão de Dados: Verificação de Consistência e Estratificação
Conjunto Observações Taxa_Churn
Treino (70%) 1029 16.1%
Teste (30%) 441 16.1%
Total 1470 16.1%

A divisão do conjunto de dados foi efetuada através de uma amostragem estratificada, assegurando que a proporção da variável‑alvo (Attrition) fosse mantida em ambos os subconjuntos (Treino (70%) e Teste (30%)).

Conforme ilustrado na tabela, a taxa de churn permanece rigorosamente constante em 16,1% em ambos os conjuntos. Esta consistência estatística é essencial para evitar distorções na amostragem, garantindo que a amostra de teste funcione como uma réplica representativa do dataset original.

Deste modo, as métricas de desempenho obtidas durante a fase de validação refletem de forma realista e fiável o comportamento do fenómeno de rotatividade na organização, aumentando a credibilidade e generalização dos resultados do modelo.

Equilíbrio de Classes

library(ROSE)
library(ggplot2)
library(gridExtra)

# Aplicar o ROSE para equilibrar apenas o conjunto de TREINO
set.seed(123)
dados_treino_bal <- ROSE(attrition ~ ., data = dados_treino, seed = 123)$data

# Criar dados para o gráfico comparativo
antes <- as.data.frame(table(dados_treino$attrition))
antes$Estado <- "1. Antes (Desequilibrado)"

depois <- as.data.frame(table(dados_treino_bal$attrition))
depois$Estado <- "2. Depois (Equilibrado com ROSE)"

comparativo <- rbind(antes, depois)

# Gráfico 
ggplot(comparativo, aes(x = Var1, y = Freq, fill = Var1)) +
  geom_bar(stat = "identity", width = 0.6, alpha = 0.9) +
  facet_wrap(~Estado) +
  scale_fill_manual(values = c("0" = "#2C3E50", "1" = "#E74C3C")) +
  scale_y_continuous(expand = c(0,0), limits = c(0, max(comparativo$Freq)*1.1)) +
  labs(
    title = "Estratégia de Rebalanceamento de Dados (ROSE)",
    subtitle = "Ajuste da classe minoritária para otimizar a aprendizagem do modelo",
    x = "Status de Saída (0 = Não, 1 = Sim)",
    y = "Número de Registos"
  ) +
  theme_minimal() +
  theme(
    legend.position = "none",
    plot.title = element_text(face = "bold", size = 14, color = "#2c3e50"),
    strip.text = element_text(face = "bold", size = 11),
    panel.grid.major.x = element_blank()
  )

A eficácia de um modelo preditivo depende da qualidade e do equilíbrio estatístico dos dados de treino.

Conforme identificado anteriormente, a variável‑alvo (Attrition) apresenta um desequilíbrio acentuado, com apenas 16,1% de casos positivos (colaboradores que saíram da empresa). Em contextos reais, este tipo de assimetria tende a levar o modelo a privilegiar a previsão de permanência e a subestimar os padrões de saída.

Para mitigar este problema, aplicou‑se o algoritmo ROSE (Random Over‑Sampling Examples) exclusivamente ao conjunto de treino. Esta técnica gera observações sintéticas baseadas na distribuição da classe minoritária, mantendo a coerência estatística do dataset original.

Principais benefícios do reequilíbrio:

  • Nivelamento da aprendizagem – O modelo passa a ser exposto a uma proporção equilibrada (aproximadamente 50/50) entre colaboradores que saem e que permanecem, o que melhora a sua capacidade de generalização.

  • Melhoria da sensibilidade (recall) – Aumenta‑se a capacidade do modelo de detetar corretamente os casos de saída, permitindo uma identificação precoce de potenciais perdas de talento.

  • Preservação da integridade do teste – O reequilíbrio foi aplicado apenas aos dados de treino, mantendo o conjunto de teste inalterado.

Machine Learning

Modelo 1: Regressão Logística

# Treinar o Modelo
modelo_logistico <- glm(attrition ~ ., data = dados_treino_bal, family = "binomial")

# Fazer Previsões
previsoes_prob <- predict(modelo_logistico, newdata = dados_teste, type = "response")
previsoes_classe <- ifelse(previsoes_prob > 0.50, 1, 0)

# Criar Matriz de Confusão 
tabela_confusao <- table(Realidade = dados_teste$attrition, Previsao = previsoes_classe)
df_confusao <- as.data.frame(tabela_confusao)

# Gráfico de Matriz de Confusão (Heatmap)
library(ggplot2)
ggplot(df_confusao, aes(x = Previsao, y = Realidade, fill = Freq)) +
  geom_tile(color = "white") +
  geom_text(aes(label = Freq), color = "white", size = 8, fontface = "bold") +
  scale_fill_gradient(low = "#34495E", high = "#E74C3C") +
  labs(title = "Matriz de Confusão: Regressão Logística",
       subtitle = "Visualização de Acertos e Erros de Previsão",
       x = "Previsão do Modelo (0=Fica, 1=Sai)",
       y = "Realidade (0=Fica, 1=Sai)") +
  theme_minimal() +
  theme(legend.position = "none",
        plot.title = element_text(face = "bold", size = 16),
        axis.title = element_text(face = "bold"))

# Tabela de Métricas 
acuracia <- sum(diag(tabela_confusao)) / sum(tabela_confusao)
sensibilidade <- tabela_confusao[2,2] / sum(tabela_confusao[2,])

metricas <- data.frame(
  Métrica = c("Acurácia Total", "Sensibilidade (Recall)"),
  Resultado = c(paste0(round(acuracia * 100, 2), "%"), 
                paste0(round(sensibilidade * 100, 2), "%"))
)

library(kableExtra)
metricas %>%
  kable(caption = "Performance do Modelo 1") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = F) %>%
  row_spec(0, bold = T, color = "white", background = "#2c3e50")
Performance do Modelo 1
Métrica Resultado
Acurácia Total 72.79%
Sensibilidade (Recall) 73.24%

Análise de Desempenho do Modelo 1 (Regressão Logística):

O primeiro modelo foi treinado com o conjunto de dados equilibrado obtido através da técnica ROSE, apresentando uma acurácia total de 72,79%.Embora esta métrica seja satisfatória, a acurácia isolada não é suficiente para avaliar o desempenho num problema de retenção de talentos, em que o custo de prever incorretamente uma saída é particularmente elevado.

A seguir apresentam‑se os principais resultados obtidos sobre o conjunto de teste (441 colaboradores):

  1. Capacidade de deteção (Recall): 73,2%

No conjunto de teste, existiam 71 colaboradores que efetivamente saíram da empresa. O modelo identificou corretamente 52 desses 71 casos. O algoritmo revela uma boa capacidade de deteção, conseguindo sinalizar aproximadamente 3 em cada 4 funcionários em risco de saída. Este é o principal ponto forte do modelo, pois assegura que a maioria dos casos críticos é antecipada e pode ser alvo de ações preventivas por parte dos Recursos Humanos.

  1. Custo dos falsos alarmes (Precisão: ~34%)

Para maximizar a deteção das saídas, o modelo tornou‑se mais sensível, o que resultou num aumento dos falsos positivos. Foram 153 colaboradores sinalizados como potenciais saídas, mas apenas 52 realmente deixaram a empresa. O modelo gera um volume considerável de alertas indevidos, em que cerca de 2 em cada 3 funcionários sinalizados permaneceram na empresa. Apesar de eficaz a antecipar saídas reais, o seu funcionamento é “hiper‑vigilante”, podendo levar a intervenções desnecessárias e a uma sobrecarga das equipas de RH.

  1. Matriz de confusão:
  • Verdadeiros Negativos (269): colaboradores que permaneceram e foram corretamente classificados.

  • Falsos Positivos (101): colaboradores que permaneceram, mas foram classificados como risco de saída (potencial desperdício de recursos de gestão).

  • Falsos Negativos (19): colaboradores que saíram, mas não foram antecipados (perdas imprevistas).

  • Verdadeiros Positivos (52): colaboradores que saíram e foram corretamente identificados (oportunidades de retenção antecipada).

Próximo passo: Testar um modelo mais robusto, como o Random Forest, com o objetivo de reduzir os falsos positivos sem comprometer a boa sensibilidade alcançada pela regressão logística.

Modelo 2: Random Forest

library(randomForest)
library(caret)
library(ggplot2)
library(dplyr)
library(kableExtra)

# Preparação e Treino
dados_treino_bal$attrition <- as.factor(dados_treino_bal$attrition)
dados_teste$attrition <- as.factor(dados_teste$attrition)

set.seed(123)
modelo_rf <- randomForest(attrition ~ ., 
                          data = dados_treino_bal, 
                          ntree = 500, 
                          importance = TRUE)

# Previsões e Métricas
previsoes_rf <- predict(modelo_rf, newdata = dados_teste)
conf_matrix_rf <- confusionMatrix(data = previsoes_rf, 
                                  reference = dados_teste$attrition, 
                                  positive = "1")

# Gráfico de Importância das Variáveis
imp_df <- as.data.frame(importance(modelo_rf))
imp_df$Variavel <- rownames(imp_df)

ggplot(imp_df %>% arrange(desc(MeanDecreaseAccuracy)) %>% head(15), 
       aes(x = reorder(Variavel, MeanDecreaseAccuracy), y = MeanDecreaseAccuracy)) +
  geom_bar(stat = "identity", fill = "#2C3E50", alpha = 0.9, width = 0.7) +
  coord_flip() +
  labs(title = "Top 15 Preditoras de Rotatividade",
       subtitle = "Quais os fatores que mais influenciam a decisão de saída?",
       x = NULL, y = "Importância (Mean Decrease Accuracy)") +
  theme_minimal() +
  theme(plot.title = element_text(face = "bold", size = 16),
        panel.grid.major.y = element_blank())

# Tabela de Performance Comparativa
metricas_rf <- data.frame(
  Métrica = c("Acurácia", "Sensibilidade (Recall)", "Especificidade"),
  Resultado = c(paste0(round(conf_matrix_rf$overall['Accuracy'] * 100, 2), "%"),
                paste0(round(conf_matrix_rf$byClass['Sensitivity'] * 100, 2), "%"),
                paste0(round(conf_matrix_rf$byClass['Specificity'] * 100, 2), "%"))
)

metricas_rf %>%
  kable(caption = "Performance do Modelo Random Forest") %>%
  kable_styling(bootstrap_options = c("striped", "hover"), full_width = F) %>%
  row_spec(0, bold = T, color = "white", background = "#2c3e50")
Performance do Modelo Random Forest
Métrica Resultado
Acurácia 74.15%
Sensibilidade (Recall) 70.42%
Especificidade 74.86%

O modelo Random Forest apresentou um desempenho superior e mais equilibrado em comparação com a Regressão Logística. Com uma acurácia global de 74,15%, este algoritmo demonstrou ser uma ferramenta robusta e fiável para apoiar decisões estratégicas de retenção de talento.

  1. Equilíbrio entre deteção e precisão Diferentemente do modelo anterior, a Random Forest revelou‑se mais precisa na distinção entre perfis de risco e de estabilidade.
  • Sensibilidade (Recall) de 70,4%: Identificou corretamente 50 dos 71 colaboradores que efetivamente saíram da empresa.

  • Redução dos falsos positivos: Embora ainda existam alertas indevidos, o modelo foi mais criterioso na sinalização de risco, diminuindo o ruído operacional para as equipas de Recursos Humanos.

Este equilíbrio traduz‑se numa ferramenta mais “cirúrgica”, capaz de alcançar elevada capacidade de deteção sem sacrificar de forma significativa a precisão das previsões.

  1. Principais preditores de rotatividade A análise de importância das variáveis revela os fatores que mais influenciam a decisão de saída, oferecendo insights de gestão extremamente relevantes:
  • OverTime (Horas Extra): surge como o preditor mais forte, indicando que colaboradores expostos a longas jornadas apresentam propensão significativamente superior à saída.

  • MonthlyIncome (Salário): confirma que as faixas salariais mais baixas constituem a zona de maior vulnerabilidade em termos de rotatividade.

  • StockOptionLevel: a ausência de incentivos de longo prazo (como planos de ações) está associada a menor compromisso organizacional.

  • Age e TotalWorkingYears: trabalhadores mais jovens e com menos anos de experiência mostram‑se mais propensos à mobilidade externa.

Estes resultados corroboram a literatura de Recursos Humanos, destacando o papel conjunto de fatores financeiros, de carga laboral e de experiência como determinantes da rotatividade.

  1. Conclusão técnica e interpretativa A Random Forest mostrou‑se capaz de captar padrões não lineares e interações complexas que modelos lineares não conseguem representar. O algoritmo identificou, por exemplo, que um salário médio pode ser aceitável isoladamente, mas torna‑se fator de risco quando combinado com excesso de horas extra ou baixa satisfação na relação com o gestor. Em suma, este modelo não apenas melhora o desempenho preditivo, mas também fornece informação acionável para políticas de retenção personalizadas e gestão preventiva do talento.

Análise de Drivers de Saída (Feature Importance)

# Extrair a importância das variáveis do modelo Random Forest
importancia <- as.data.frame(importance(modelo_rf))
importancia$Variavel <- rownames(importancia)

# Criar o gráfico
library(ggplot2)
library(dplyr)

ggplot(importancia %>% arrange(desc(MeanDecreaseAccuracy)) %>% head(15), 
       aes(x = reorder(Variavel, MeanDecreaseAccuracy), y = MeanDecreaseAccuracy)) +
  geom_bar(stat = "identity", fill = "#2C3E50", alpha = 0.9, width = 0.7) +
  geom_text(aes(label = round(MeanDecreaseAccuracy, 1)), 
            hjust = -0.2, size = 3, fontface = "bold", color = "#2C3E50") +
  coord_flip() +
  scale_y_continuous(expand = expansion(mult = c(0, 0.1))) +
  labs(
    title = "Drivers Críticos de Attrition",
    subtitle = "Variáveis que mais impactam a precisão do modelo Random Forest",
    x = NULL,
    y = "Importância (Mean Decrease Accuracy)"
  ) +
  theme_minimal() +
  theme(
    plot.title = element_text(face = "bold", size = 16, color = "#2c3e50"),
    plot.subtitle = element_text(size = 11, color = "grey40"),
    panel.grid.major.y = element_blank(),
    axis.text.y = element_text(face = "bold", size = 10)
  )

O gráfico acima apresenta as variáveis mais determinantes identificadas pelo modelo Random Forest, ordenadas pela métrica “Mean Decrease Accuracy”. Em termos práticos, quanto maior a importância desta métrica, maior é o contributo da variável para a capacidade preditiva global do modelo, ou seja, a sua remoção resultaria numa diminuição significativa da precisão.

  1. O cargo como principal determinante (JobRole) Quatro das cinco variáveis mais relevantes estão relacionadas com funções específicas dentro da organização. Destacam‑se dois extremos: Research Director (função com elevada estabilidade) e SalesRepresentative (função mais volátil).

Esta diferença confirma as conclusões obtidas na análise exploratória: o nível hierárquico e o tipo de função são os fatores que mais diferenciam o comportamento de rotatividade na empresa.

Implicação: Políticas genéricas de gestão de pessoas (“one‑size‑fits‑all”) são ineficazes.

A estratégia de retenção deve ser personalizada por área funcional, reconhecendo que vendas e investigação/rede de liderança exigem abordagens de motivação e reconhecimento distintas.

  1. O peso das horas extra (OverTime) A variável over_time_yes surge como o terceiro preditor mais crítico de todo o conjunto. Este resultado reforça a evidência de que a sobrecarga de trabalho e a falta de equilíbrio vida‑profissional constituem gatilhos diretos de saída. Tratar‑se‑á menos de uma questão de remuneração e mais de bem‑estar organizacional e prevenção de burnout.

  2. Estagnação e incentivos de longo prazo

  • Estagnação: A variável years_in_current_role (anos na função atual) destaca‑se na 6.ª posição. A permanência prolongada na mesma função, sem progressão visível, aumenta substancialmente o risco de saída voluntária.

  • Incentivos: O stock_option_level surge logo de seguida, evidenciando que os incentivos de longo prazo têm um efeito de retenção mais forte do que o salário mensal (monthly_income), que aparece apenas na 15.ª posição.

Estes resultados sugerem que a progressão de carreira e a valorização de capital simbólico (ações, reconhecimento, visibilidade) são mecanismos de retenção mais eficazes do que aumentos salariais isolados.

  1. Perfil demográfico de risco A presença das variáveis marital_status_single e age entre as 15 mais relevantes confirma o padrão identificado nas análises anteriores: colaboradores mais jovens e solteiros tendem a apresentar maior mobilidade e predisposição para mudança, sobretudo em contextos de poucas perspetivas de crescimento.

Para mitigar os riscos de attrition, recomenda‑se que as ações prioritárias da empresa incidam sobre três eixos principais:

  1. Rever as condições e incentivos das equipas de Vendas, onde a taxa de saída é mais elevada;

  2. Monitorizar e regular o volume de horas extra, promovendo práticas de equilíbrio e bem‑estar;

  3. Implementar planos de rotação e desenvolvimento de carreira, especialmente para colaboradores estagnados na mesma função há vários anos.

Estas ações estratégicas alinham‑se diretamente com os resultados do modelo e podem reduzir substancialmente o risco de rotatividade não desejada, fortalecendo a retenção de talento crítico.

Conclusão e Recomendações de Negócio

Este projeto teve como objetivo identificar as causas da rotatividade de funcionários (Attrition) e criar um modelo preditivo para mitigar o risco.

Comparação de Modelos

Foram testadas duas abordagens distintas: Regressão Logística e Random Forest.

O Random Forest demonstrou desempenho superior e maior estabilidade, alcançando uma acurácia global de 74,15%.

O modelo é capaz de identificar corretamente 70,4% dos colaboradores que efetivamente saem da empresa (sensibilidade), mantendo, em simultâneo, uma taxa de falsos alarmes controlada (especificidade de 74,9%).

Estas métricas evidenciam um equilíbrio adequado entre deteção e precisão, tornando o algoritmo uma ferramenta eficaz para uso prático em contextos de Recursos Humanos.

Fatores Críticos de Saída (Insights do Modelo)

A análise de importância das variáveis (Feature Importance) evidenciou três pilares centrais de ação:

  1. O Risco Associado à Função de Vendas

A função Sales Representative surge como o maior preditor de saída. A taxa de rotatividade neste cargo é substancialmente superior à observada em funções estáveis como Research Director ou Manager.

Diagnóstico provável: Desajuste no esquema de comissões, pressão elevada por resultados ou falta de perspetivas de progressão.

  1. Cultura de Horas Extra e Exaustão Ocupacional

A variável OverTime mantém‑se entre os três fatores mais críticos, confirmando que a sobrecarga de trabalho é um dos gatilhos diretos de saída. Colaboradores que realizam horas extra apresentam probabilidade significativamente superior de sair da empresa, independentemente do nível salarial.

Interpretação: este comportamento sugere sinais de burnout e desequilíbrio vida‑trabalho, áreas que requerem monitorização ativa.

  1. Retenção através de Incentivos de Capital

O StockOptionLevel mostra‑se determinante para a retenção de colaboradores. Funcionários com participação acionista ou incentivos de longo prazo tendem a reter‑se por mais tempo, reforçando o sentimento de pertença e compromisso organizacional. Inversamente, a ausência deste fator está fortemente associada a maior propensão à saída.

Plano de Ação Recomendado (Próximos Passos)

Com base nas evidências analíticas, recomenda‑se a implementação das seguintes medidas:

  1. Intervenção direcionada nas equipas de Vendas: Realizar entrevistas de saída específicas para Representantes de Vendas, com foco na revisão de políticas de comissão, objetivos e plano de carreira.

  2. Auditoria de Carga Horária e Bem‑Estar: Estabelecer mecanismos de controlo das horas extra, garantindo a sua compensação adequada (via folgas ou benefícios). Simultaneamente, promover programas de prevenção de burnout e de equilíbrio vida‑trabalho.

  3. Ferramenta de Previsão Contínua de Rotatividade: Integrar o modelo Random Forest como um sistema mensal de monitorização preditiva, uma “lista de risco” dinâmica, destacando colaboradores com probabilidade de saída superior a 50%. Esta informação deve ser utilizada de forma proativa, permitindo à equipa de RH agir antes da decisão de sair da empresa.

LS0tCnRpdGxlOiAiQW7DoWxpc2UgZGUgUm90YXRpdmlkYWRlIChIUiBBbmFseXRpY3MpIgpzdWJ0aXRsZTogIklkZW50aWZpY2HDp8OjbyBkZSBGYXRvcmVzIENyw610aWNvcyBwYXJhIGEgUmV0ZW7Dp8OjbyBkZSBUYWxlbnRvIgphdXRob3I6ICJKb2FuYSBJbsOhY2lvIHwgRGF0YSBBbmFseXN0IgpkYXRlOiAiYHIgZm9ybWF0KFN5cy5EYXRlKCksICclZC0lbS0lWScpYCIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgIHRoZW1lOiBjb3NtbyAgICAgICAgICAgCiAgICBoaWdobGlnaHQ6IHB5Z21lbnRzICAgCiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgY29kZV9kb3dubG9hZDogdHJ1ZSAgICAKICAgIG51bWJlcl9zZWN0aW9uczogZmFsc2UgCi0tLQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0KIyBNYW5pcHVsYcOnw6NvIGUgbGltcGV6YSBkZSBkYWRvcwpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KGphbml0b3IpCmxpYnJhcnkoZmFzdER1bW1pZXMpCmxpYnJhcnkoc2tpbXIpCgojIFZpc3VhbGl6YcOnw6NvCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShjb3JycGxvdCkKbGlicmFyeShncmlkRXh0cmEpCmxpYnJhcnkoa2FibGVFeHRyYSkKCiMgTW9kZWxhw6fDo28gZSBhdmFsaWHDp8OjbwpsaWJyYXJ5KGNhVG9vbHMpCmxpYnJhcnkoUk9TRSkKbGlicmFyeShyYW5kb21Gb3Jlc3QpCmxpYnJhcnkoY2FyZXQpCgprbml0cjo6b3B0c19jaHVuayRzZXQoCiAgZWNobyA9IFRSVUUsICMgTW9zdHJhIG8gY8OzZGlnbyBubyByZWxhdMOzcmlvIChUUlVFKSBvdSBlc2NvbmRlIChGQUxTRSkKICB3YXJuaW5nID0gRkFMU0UsICMgRXNjb25kZSBtZW5zYWdlbnMgZGUgYXZpc28gCiAgbWVzc2FnZSA9IEZBTFNFLCAjIEVzY29uZGUgbWVuc2FnZW5zIG5vcm1haXMKICBmaWcuYWxpZ24gPSAiY2VudGVyIiwgIyBDZW50cmEgdG9kb3Mgb3MgZ3LDoWZpY29zCiAgZmlnLndpZHRoID0gMTAsICMgw4kgYSBsYXJndXJhIHBhZHLDo28gcGFyYSBvcyBvdXRwdXRzCiAgZmlnLmhlaWdodCA9IDYsICMgw4kgYSBhbHR1cmEgcGFkcsOjbyBwYXJhIG9zIG91dHB1dHMKICBjb21tZW50ID0gTkEsICMgUmVtb3ZlIG9zICIjIyIgZGFzIGxpbmhhcyBkZSBvdXRwdXQgZGUgY8OzZGlnbwogIG91dC53aWR0aCA9ICI4MCUiICMgQSBsYXJndXJhIGRhcyBmaWd1cmFzIHRlcsOhIDgwJSBkYSBsYXJndXJhIGRhIHDDoWdpbmEKKQpgYGAKIyBJbnRyb2R1w6fDo28gZSBDb250ZXh0bwojIyBPIFByb2JsZW1hIGRlIE5lZ8OzY2lvCkEgcm90YXRpdmlkYWRlIGRvcyBmdW5jaW9uw6FyaW9zICh0YW1iw6ltIGNvbmhlY2lkYSBwb3IgX0VtcGxveWVlIEF0dHJpdGlvbl8pIMOpIHVtIGRvcyBtYWlvcmVzIGRlc2FmaW9zIGRhcyBvcmdhbml6YcOnw7VlcywgZSB1bSBkb3MgcXVlIHRyYXogbWFpcyBjdXN0b3MuIEVzdHVkb3MgaW5kaWNhbSBxdWUgbyBjdXN0byBkZSBzdWJzdGl0dWlyIHVtIGZ1bmNpb27DoXJpbyBwb2RlIHZhcmlhciBlbnRyZSA1MCUgYSAyMDAlIGRvIHNldSBzYWzDoXJpbyBhbnVhbCwgc2VuZG8gY29uc2lkZXJhZG9zIG9zIGN1c3RvcyBkZSByZWNydXRhbWVudG8sIGRlIGZvcm1hw6fDo28gZSBkZSBwZXJkYSBkZSBwcm9kdXRpdmlkYWRlLgoKUGFyYSBhbMOpbSBkbyBpbXBhY3RvIGZpbmFuY2Vpcm8sIHVtYSB0YXhhIGRlIF90dXJub3Zlcl8gZWxldmFkYSBhZmV0YSBhIG1vcmFsIGRhcyBlcXVpcGFzLCBhIGN1bHR1cmEgZGEgZW1wcmVzYSBlIGEgY29udGludWlkYWRlIGRvcyBwcm9qZXRvcy4gUG9yIGlzc28sIGEgY2FwYWNpZGFkZSBkZSBwcmV2ZXIgKipxdWVtKiogZXN0w6EgZW0gcmlzY28gZGUgc2FpciBlLCBtYWlzIGltcG9ydGFudGUsICoqcG9ycXXDqioqLCDDqSB1bWEgdmFudGFnZW0gY29tcGV0aXRpdmEgY3J1Y2lhbCBwYXJhIG8gRGVwYXJ0YW1lbnRvIGRlIFJlY3Vyc29zIEh1bWFub3MgKFJIKS4gCgojIyBTb2JyZSBvIF9EYXRhc2V0XwpOZXN0ZSBwcm9qZXRvLCBmb2kgdXRpbGl6YWRvIG8gX2RhdGFzZXRfICIqKklCTSBIUiBBbmFseXRpY3MgRW1wbG95ZWUgQXR0cml0aW9uICYgUGVyZm9ybWFuY2UqKiIsIGRpc3BvbmliaWxpemFkbyBwdWJsaWNhbWVudGUgbm8gS2FnZ2xlLiBFc3RlIGNvbmp1bnRvIGRlIGRhZG9zIGZvaSBjcmlhZG8gcG9yIGNpZW50aXN0YXMgZGUgZGFkb3MgZGEgSUJNIGUsIGVtYm9yYSBzZWphIGZpY3TDrWNpbywgcmVmbGV0ZSBkZXNhZmlvcyByZWFpcyBkbyBtdW5kbyBjb3Jwb3JhdGl2by4KCk8gX2RhdGFzZXRfIGNvbnTDqW0gKioxNDcwIG9ic2VydmHDp8O1ZXMqKiAoZnVuY2lvbsOhcmlvcykgZSAqKjM1IHZhcmnDoXZlaXMqKiAoY2FyYWN0ZXLDrXN0aWNhcykgCgojIyBEaWNpb27DoXJpbyBkZSBWYXJpw6F2ZWlzCkEgbm9zc2EgdmFyacOhdmVsLWFsdm8gKF9UYXJnZXRfKSDDqSBhICoqX0F0dHJpdGlvbl8qKiwgcXVlIGluZGljYSBzZSBvIGZ1bmNpb27DoXJpbyBzYWl1ICgiWWVzIikgb3UgcGVybWFuZWNldSAoIk5vIikgbmEgZW1wcmVzYS4gCgpBcyByZXN0YW50ZXMgdmFyacOhdmVpcyBwb2RlbSBzZXIgYWdydXBhZGFzIGVtIHRyw6pzIGNhdGVnb3JpYXMgcHJpbmNpcGFpcyBxdWUgaXJlbW9zIGV4cGxvcmFyOgoKMS4gKipEZW1vZ3LDoWZpY2FzKio6IGBBZ2VgLCBgR2VuZGVyYCwgYE1hcml0aWFsU3RhdHVzYCwgYERpc3RhbmNlRnJvbUhvbWVgOwoKMi4gKipEYWRvcyBkbyBUcmFiYWxobyoqOiBgRGVwYXJ0bWVudGAsIGBKb2JSb2xlYCwgYEpvYkxldmVsYCwgYE92ZXJUaW1lYCwgYEJ1c2luZXNzVHJhdmVsYDsKCjMuICoqQ29tcGVuc2HDp8OjbyBlIFNhdGlzZmHDp8OjbyoqOiBgTW9udGhseUluY29tZWAsIGBQZXJjZW50U2FsYXJ5SGlrZWAsIGBTdG9ja09wdGlvbkxldmVsYCwgYEpvYlNhdGlzZmFjdGlvbmAsIGBFbnZpcm9ubWVudFNhdGlzZmFjdGlvbmAuIAoKUGFyYSBmYWNpbGl0YXIgYSBsZWl0dXJhLCBmb3JhbSBkZXN0YWNhZGFzIGFjaW1hIGFwZW5hcyBhcyB2YXJpw6F2ZWlzIG1haXMgcmVsZXZhbnRlcyBwYXJhIGEgYW7DoWxpc2UuIEEgbGlzdGEgY29tcGxldGEgZGFzIDM1IHZhcmnDoXZlaXMgZSBvcyBzZXVzIHRpcG9zIGRlIGRhZG9zIHNlcsOjbyBhcHJlc2VudGFkb3MgbmEgc2Vjw6fDo28gdMOpY25pY2EgZGUgaW5zcGXDp8OjbyBkZSBkYWRvcy4KCiMjIE9iamV0aXZvcyBkbyBQcm9qZXRvCgpPIG9iamV0aXZvIGNlbnRyYWwgZGVzdGUgcHJvamV0byDDqSBkZXNlbnZvbHZlciB1bWEgc29sdcOnw6NvIGRlICoqUGVvcGxlIEFuYWx5dGljcyoqIGNhcGF6IGRlIGFudGVjaXBhciBhIHJvdGF0aXZpZGFkZSBkZSB0YWxlbnRvcyBlIGZvcm5lY2VyIMOgIGdlc3TDo28gZXN0cmF0w6lnaWFzIGJhc2VhZGFzIGVtIGRhZG9zLiBQYXJhIHRhbCwgYSBhbsOhbGlzZSBmb2NhLXNlIGVtIHRyw6pzIHBpbGFyZXMgdmVydGljYWlzOgoKKiAqKkRpYWduw7NzdGljbyBkZSBDYXVzYSBSYWl6Kio6IFF1YW50aWZpY2FyIG8gaW1wYWN0byByZWFsIGRlIGZhdG9yZXMgZGUgcmlzY28sIHZlcmlmaWNhbmRvIGEgaGlww7N0ZXNlIGRlIHF1ZSBhIHNvYnJlY2FyZ2EgZGUgdHJhYmFsaG8gKGBPdmVyVGltZWApIGUgYSBsb2fDrXN0aWNhIChgRGlzdGFuY2VGcm9tSG9tZWApIHPDo28gY2F0YWxpc2Fkb3JlcyBkZSBfYnVybm91dF8uCgoqICoqSGllcmFycXVpYSBkZSBSZXRlbsOnw6NvKio6IERldGVybWluYXIsIGF0cmF2w6lzIGRlIGFsZ29yaXRtb3MgZGUgTWFjaGluZSBMZWFybmluZywgbyBxdWUgcGVzYSBtYWlzIG5hIGRlY2lzw6NvIGRlIHNhw61kYTogaW5jZW50aXZvcyBmaW5hbmNlaXJvcyAoYE1vbnRobHlJbmNvbWVgKSBvdSBmYXRvcmVzIGludGFuZ8OtdmVpcyBjb21vIGEgU2F0aXNmYcOnw6NvIG5vIFRyYWJhbGhvLgoKKiAqKk1vZGVsYcOnw6NvIFByZWRpdGl2YSoqOiBUcmVpbmFyIGFsZ29yaXRtb3MgZGUgY2xhc3NpZmljYcOnw6NvIChSZWdyZXNzw6NvIExvZ8Otc3RpY2EgZSBSYW5kb20gRm9yZXN0KSBwYXJhIGlkZW50aWZpY2FyIGNvbGFib3JhZG9yZXMgZW0gcmlzY28gY29tIGVsZXZhZGEgcHJlY2lzw6NvLCBwZXJtaXRpbmRvIHVtYSBhdHVhw6fDo28gcHJldmVudGl2YSBkbyBSSC4KCiMgSW1wb3J0YcOnw6NvIGRvcyBEYWRvcyBlIEluc3Blw6fDo28gSW5pY2lhbAoKYGBge3IgaW1wb3J0YWNhbywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyBJbXBvcnRhw6fDo28gZG9zIERhZG9zCiMgTGVtb3MgbyBmaWNoZWlybyBvcmlnaW5hbAppYm1faHIgPC0gcmVhZC5jc3YoImRhdGEvV0FfRm4tVXNlQ18tSFItRW1wbG95ZWUtQXR0cml0aW9uLmNzdiIsIHNlcCA9ICI7IikKCgpsaWJyYXJ5KGphbml0b3IpCmxpYnJhcnkoZHBseXIpCgojIExpbXBlemEgZSBQYWRyb25pemHDp8OjbwojIEFxdWkgY3JpYW1vcyBvIG9iamV0byAnaWJtX2NsZWFuJwoKaWJtX2NsZWFuIDwtIGlibV9ociAlPiUgCiAgY2xlYW5fbmFtZXMoKSAlPiUgCiAgIyBSZW1vdmVtb3MgY29sdW5hcyBxdWUgbsOjbyB2YXJpYW0KICBzZWxlY3QoLWFueV9vZihjKCJlbXBsb3llZV9jb3VudCIsICJvdmVyMTgiLCAic3RhbmRhcmRfaG91cnMiLCAiZW1wbG95ZWVfbnVtYmVyIikpKQoKIyBWaXN1YWxpemHDp8OjbyAoa2FibGUpCmxpYnJhcnkoa2FibGVFeHRyYSkKaWJtX2NsZWFuICU+JSAKICBzZWxlY3QoYWdlLCBhdHRyaXRpb24sIG1vbnRobHlfaW5jb21lLCBqb2Jfcm9sZSwgb3Zlcl90aW1lLCB0b3RhbF93b3JraW5nX3llYXJzKSAlPiUgCiAgaGVhZCgxMCkgJT4lIAogIGthYmxlKGNhcHRpb24gPSAiVGFiZWxhIDE6IEFtb3N0cmEgZGFzIFZhcmnDoXZlaXMgQ3LDrXRpY2FzIHBhcmEgQW7DoWxpc2UgZGUgUm90YXRpdmlkYWRlIikgJT4lIAogIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImhvdmVyIiwgImNvbmRlbnNlZCIpLCAKICAgICAgICAgICAgICAgIGZ1bGxfd2lkdGggPSBULCAKICAgICAgICAgICAgICAgIHBvc2l0aW9uID0gImNlbnRlciIpICU+JSAKICByb3dfc3BlYygwLCBib2xkID0gVCwgY29sb3IgPSAid2hpdGUiLCBiYWNrZ3JvdW5kID0gIiMyYzNlNTAiKSAKYGBgCgpBIGJhc2UgZGUgZGFkb3Mgw6kgY29tcG9zdGEgcG9yICoqMzUgdmFyacOhdmVpcyoqIHF1ZSBhYnJhbmdlbSB0csOqcyBkaW1lbnPDtWVzIGNlbnRyYWlzOiAqKmNhcmFjdGVyw61zdGljYXMgZGVtb2dyw6FmaWNhcyoqLCAqKmZhdG9yZXMgZmluYW5jZWlyb3MqKiBlICoqaW5kaWNhZG9yZXMgZGUgZGVzZW1wZW5obyBwcm9maXNzaW9uYWwqKi4KCk5lc3RhIGZhc2UgaW5pY2lhbCwgYSBhbsOhbGlzZSBpbmNpZGUgc29icmUgdmFyacOhdmVpcyBjb20gbWFpb3IgcG90ZW5jaWFsIGV4cGxpY2F0aXZvIGRhICoqcm90YXRpdmlkYWRlIGRlIGNvbGFib3JhZG9yZXMqKiwgbm9tZWFkYW1lbnRlIGEgKipyZW11bmVyYcOnw6NvIG1lbnNhbCoqLCBvcyBhbm9zIHRvdGFpcyBkZSAqKmFudGlndWlkYWRlIG5hIGVtcHJlc2EqKiBlIGEgcmVhbGl6YcOnw6NvIGRlICoqaG9yYXMgZXh0cmEqKi4KCkV2aWTDqm5jaWFzIGVtcMOtcmljYXMgZSBhbsOhbGlzZXMgcHJlbGltaW5hcmVzIGFwb250YW0gcGFyYSB1bWEgcmVsYcOnw6NvIHNpZ25pZmljYXRpdmEgZW50cmUgZXN0ZXMgZmF0b3JlcyBlIGEgKipwcm9iYWJpbGlkYWRlIGRlIHNhw61kYSBkb3MgY29sYWJvcmFkb3JlcyoqLCBjb25zdGl0dWluZG8sIHBvciBpc3NvLCBwb250b3MgZGUgcGFydGlkYSBmdW5kYW1lbnRhaXMgcGFyYSBvIGFwcm9mdW5kYW1lbnRvIGRhIGFuw6FsaXNlLgoKIyBUcmF0YW1lbnRvIGRlIERhZG9zCiMjIExpbXBlemEgZGUgRGFkb3MKQSBhbsOhbGlzZSBkZXNjcml0aXZhIGluaWNpYWwsIGV2aWRlbmNpb3UgZG9pcyBhc3BldG9zIHJlbGV2YW50ZXMgcmVsYXRpdmFtZW50ZSDDoCBxdWFsaWRhZGUgZSBlc3RydXR1cmEgZG8gY29uanVudG8gZGUgZGFkb3M6CgoxLiAqKlF1YWxpZGFkZSBkb3MgZGFkb3MqKiDigJMgVmVyaWZpY291LXNlIGEgaW5leGlzdMOqbmNpYSBkZSB2YWxvcmVzIGVtIGZhbHRhIChfbWlzc2luZyB2YWx1ZXNfKSBlbSB0b2RhcyBhcyB2YXJpw6F2ZWlzLCBvIHF1ZSBzaW1wbGlmaWNhIHN1YnN0YW5jaWFsbWVudGUgYXMgZXRhcGFzIGRlIHByw6ktcHJvY2Vzc2FtZW50by4KCjIuICoqVmFyacOhdmVpcyByZWR1bmRhbnRlcyBlIG7Do28gaW5mb3JtYXRpdmFzKiog4oCTIEZvcmFtIGlkZW50aWZpY2FkYXMgdHLDqnMgdmFyacOhdmVpcyBjb20gdmFsb3IgY29uc3RhbnRlIGVtIHRvZGFzIGFzIG9ic2VydmHDp8O1ZXMgKGRlc3ZpbyBwYWRyw6NvID0gMCksIGJlbSBjb21vIHVtYSB2YXJpw6F2ZWwgZGUgaWRlbnRpZmljYcOnw6NvIGluZGl2aWR1YWwuIFBvciBuw6NvIGFwcmVzZW50YXJlbSB2YXJpYWJpbGlkYWRlIG91IG7Do28gY29udHJpYnXDrXJlbSBwYXJhIGEgZXhwbGljYcOnw6NvIGRvIGZlbsOzbWVubyBlc3R1ZGFkbywgZXN0YXMgdmFyacOhdmVpcyBmb3JhbSByZW1vdmlkYXMgZG8gX2RhdGFzZXRfLgoKQXMgKip2YXJpw6F2ZWlzIGVsaW1pbmFkYXMqKiBmb3JhbToKCiogYEVtcGxveWVlQ291bnRgOiB2YWxvciBjb25zdGFudGUgaWd1YWwgYSDigJwx4oCdOwoKKiBgT3ZlcjE4YDogdG9kb3Mgb3MgY29sYWJvcmFkb3JlcyByZWdpc3RhZG9zIGNvbW8gbWFpb3JlcyBkZSBpZGFkZSAo4oCcWeKAnSk7CgoqIGBTdGFuZGFyZEhvdXJzYDogdmFsb3IgZml4byBkZSDigJw4MOKAnSBlbSB0b2RvcyBvcyByZWdpc3RvczsKCiogYEVtcGxveWVlTnVtYmVyYDogaWRlbnRpZmljYWRvciDDum5pY28gZG9zIGNvbGFib3JhZG9yZXMsIHNlbSByZWxldsOibmNpYSBwcmVkaXRpdmEuCgpBIGV4Y2x1c8OjbyBkZXN0YXMgdmFyacOhdmVpcyBwZXJtaXRlIHJlZHV6aXIgYSBkaW1lbnNpb25hbGlkYWRlIGRvcyBkYWRvcyBzZW0gcGVyZGEgZGUgaW5mb3JtYcOnw6NvIHJlbGV2YW50ZSwgY29udHJpYnVpbmRvIHBhcmEgdW0gbW9kZWxvIGFuYWzDrXRpY28gbWFpcyBlZmljaWVudGUgZSBpbnRlcnByZXTDoXZlbC4KCmBgYHtyIGxpbXBlemFfZXNwZWNpZmljYSwgbWVzc2FnZT1GQUxTRX0KIyBQYWRyb25pemHDp8OjbyBkZSBOb21lcwppYm1fY2xlYW4gPC0gaWJtX2hyICU+JSAKICBjbGVhbl9uYW1lcygpCgojIFJlbW92ZXIgVmFyacOhdmVpcyBJbnZhcmlhbnRlcwpjb2x1bmFzX3JlbW92ZXIgPC0gYygiZW1wbG95ZWVfY291bnQiLCAib3ZlcjE4IiwgInN0YW5kYXJkX2hvdXJzIiwgImVtcGxveWVlX251bWJlciIpCgppYm1fY2xlYW4gPC0gaWJtX2NsZWFuICU+JSAKICBzZWxlY3QoLWFueV9vZihjb2x1bmFzX3JlbW92ZXIpKQoKIyBSZXN1bW8gZGEgTGltcGV6YQpjYXQoIkJhc2UgZGUgZGFkb3MgbGltcGEgY29tIHN1Y2Vzc28uXG4iLAogICAgIlRvdGFsIGRlIENvbHVuYXMgT3JpZ2luYWlzOiAiLCBuY29sKGlibV9ociksICJcbiIsCiAgICAiVG90YWwgZGUgQ29sdW5hcyBBcMOzcyBMaW1wZXphOiAiLCBuY29sKGlibV9jbGVhbikpCmBgYAoKIyBBbsOhbGlzZSBFeHBsb3JhdMOzcmlhIGRvcyBEYWRvcyAoQUVEKQpFc3RhIGZhc2UgdGVtIGNvbW8gcHJpbmNpcGFsIG9iamV0aXZvIGNvbXByZWVuZGVyIGEgZGlzdHJpYnVpw6fDo28gZGFzIHZhcmnDoXZlaXMgZSBpZGVudGlmaWNhciBwYWRyw7VlcyBvdSByZWxhw6fDtWVzIHF1ZSBwb3NzYW0gZXhwbGljYXIgbyBmZW7Ds21lbm8gZGEgKipyb3RhdGl2aWRhZGUgZGUgY29sYWJvcmFkb3JlcyoqIChfZW1wbG95ZWUgYXR0cml0aW9uXykuCgpJbmljaWEtc2UgYSBleHBsb3Jhw6fDo28gcGVsYSB2YXJpw6F2ZWwgYWx2bywgYEF0dHJpdGlvbmAsIHF1ZSBpbmRpY2Egc2UgbyBjb2xhYm9yYWRvciAqKnBlcm1hbmVjZXUgbmEgZW1wcmVzYSoqIChgTm9gKSBvdSAqKm9wdG91IHBlbGEgc2HDrWRhKiogKGBZZXNgKS4KCkEgYW7DoWxpc2UgZGVzdGEgdmFyacOhdmVsIGZvcm5lY2UgdW1hIHByaW1laXJhIHBlcmNlw6fDo28gYWNlcmNhIGRvIGVxdWlsw61icmlvIGVudHJlIGNvbGFib3JhZG9yZXMgYXRpdm9zIGUgYXF1ZWxlcyBxdWUgZGVpeGFyYW0gYSBvcmdhbml6YcOnw6NvLCBwZXJtaXRpbmRvIGF2YWxpYXIgYSBkaW1lbnPDo28gcmVhbCBkbyBmZW7Ds21lbm8gZGUgc2HDrWRhLgoKIyMgQW7DoWxpc2UgZGEgVmFyacOhdmVsIF9UYXJnZXRfIChfQXR0cml0aW9uXykKUXVhbnRvcyBmdW5jaW9uw6FyaW9zIGVmZXRpdmFtZW50ZSBzYcOtcmFtIGRhIGVtcHJlc2E/CgpgYGB7ciBhbmFsaXNlX3RhcmdlfQojIENyaWFyIGEgVGFiZWxhIGRlIEZyZXF1w6puY2lhIFByb2Zpc3Npb25hbAp0YWJlbGFfdGFyZ2V0IDwtIGlibV9jbGVhbiAlPiUKICBjb3VudChhdHRyaXRpb24pICU+JQogIG11dGF0ZSgKICAgIHBlcmNlbnRhZ2VtID0gKG4gLyBzdW0obikpICogMTAwLAogICAgYXR0cml0aW9uID0gaWZlbHNlKGF0dHJpdGlvbiA9PSAiWWVzIiwgIlNhaXUgKFllcykiLCAiUGVybWFuZWNldSAoTm8pIikKICApCgojIEV4aWJpciBUYWJlbGEgY29tIG8ga2FibGVFeHRyYQp0YWJlbGFfdGFyZ2V0ICU+JQogIGthYmxlKAogICAgY2FwdGlvbiA9ICJEaXN0cmlidWnDp8OjbyBkYSBWYXJpw6F2ZWwtVGFyZ2V0IChBdHRyaXRpb24pIiwKICAgIGNvbC5uYW1lcyA9IGMoIlN0YXR1cyIsICJUb3RhbCAobikiLCAiUGVyY2VudGFnZW0gKCUpIiksCiAgICBkaWdpdHMgPSAxCiAgKSAlPiUKICBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJob3ZlciIpLCBmdWxsX3dpZHRoID0gRikgJT4lCiAgcm93X3NwZWMoMCwgYm9sZCA9IFQsIGNvbG9yID0gIndoaXRlIiwgYmFja2dyb3VuZCA9ICIjMmMzZTUwIikgJT4lCiAgY29sdW1uX3NwZWMoMywgYm9sZCA9IFQsIGNvbG9yID0gaWZlbHNlKHRhYmVsYV90YXJnZXQkcGVyY2VudGFnZW0gPCAyMCwgIiNlNzRjM2MiLCAiIzJjM2U1MCIpKQoKIyBWaXN1YWxpemHDp8OjbwpnZ3Bsb3QoaWJtX2NsZWFuLCBhZXMoeCA9IGF0dHJpdGlvbiwgZmlsbCA9IGF0dHJpdGlvbikpICsKICBnZW9tX2Jhcih3aWR0aCA9IDAuNiwgYWxwaGEgPSAwLjkpICsKIAogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIk5vIiA9ICIjMkMzRTUwIiwgIlllcyIgPSAiI0U3NEMzQyIpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGV4cGFuc2lvbihtdWx0ID0gYygwLCAwLjEpKSkgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJWaXPDo28gR2VyYWwgZGEgUm90YXRpdmlkYWRlIG5hIEVtcHJlc2EiLAogICAgc3VidGl0bGUgPSAiQXBlbmFzIDE2JSBkb3MgY29sYWJvcmFkb3JlcyBkZWl4YXJhbSBhIG9yZ2FuaXphw6fDo28gbm8gcGVyw61vZG8gYW5hbGlzYWRvIiwKICAgIHggPSAiRGVjaXPDo28gZGUgU2HDrWRhIiwKICAgIHkgPSAiTsO6bWVybyBkZSBGdW5jaW9uw6FyaW9zIgogICkgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoCiAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsIAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBzaXplID0gMTYsIGNvbG9yID0gIiMyYzNlNTAiKSwKICAgIHBhbmVsLmdyaWQubWFqb3IueCA9IGVsZW1lbnRfYmxhbmsoKSAKICApCmBgYAoqKl9JbnNpZ2h0XyBJbmljaWFsKio6IApWZXJpZmljYS1zZSBxdWUgYSAqKnRheGEgZGUgcm90YXRpdmlkYWRlKiogKF9BdHRyaXRpb24gUmF0ZV8pIMOpIGRlIGFwcm94aW1hZGFtZW50ZSAqKjE2JSoqLCBvIHF1ZSBpbmRpY2EgcXVlIGEgbWFpb3JpYSBkb3MgY29sYWJvcmFkb3JlcyAoY2VyY2EgZGUgODQlKSBwZXJtYW5lY2V1IG5hIGVtcHJlc2EgZHVyYW50ZSBvIHBlcsOtb2RvIGFuYWxpc2Fkby4KCk9ic2VydmEtc2UsIGFzc2ltLCB1bSAqKmRlc2VxdWlsw61icmlvIGVudHJlIGFzIGNsYXNzZXMqKiBkYSB2YXJpw6F2ZWwgYWx2bywgY29tIHByZWRvbWluw6JuY2lhIGRlIGNvbGFib3JhZG9yZXMgcXVlIG7Do28gc2HDrXJhbSBkYSBvcmdhbml6YcOnw6NvLgoKRXN0ZSBwb250byDDqSBwYXJ0aWN1bGFybWVudGUgcmVsZXZhbnRlIHBhcmEgZXRhcGFzIHBvc3RlcmlvcmVzIGRlICoqbW9kZWxhw6fDo28gcHJlZGl0aXZhKiosIHVtYSB2ZXogcXVlIGEgZGVzcHJvcG9yw6fDo28gZW50cmUgY2xhc3NlcyBwb2RlIGxldmFyIG8gbW9kZWxvIGEgKipzb2JyZXZhbG9yaXphciBhIGNsYXNzZSBtYWlvcml0w6FyaWEqKiAoY29sYWJvcmFkb3JlcyBxdWUgZmljYW0pIGUgbmVnbGlnZW5jaWFyIG9zIGNhc29zIGRlIHNhw61kYSwgcXVlIHPDo28gcHJlY2lzYW1lbnRlIG9zIHF1ZSBtYWlzIGludGVyZXNzYW0gY29tcHJlZW5kZXIgZSBwcmV2ZXIuCgojIyBBbsOhbGlzZSBEZW1vZ3LDoWZpY2E6IEEgSWRhZGUgSW5mbHVlbmNpYT8KVmFtb3MgYW5hbGlzYXIgYSBkaXN0cmlidWnDp8OjbyBkZSBpZGFkZSBlbnRyZSBvcyBmdW5jaW9uw6FyaW9zIHF1ZSBzYcOtcmFtIGUgb3MgcXVlIGZpY2FyYW0uIFV0aWxpemFtb3MgdW0gQm94cGxvdCBwYXJhIHZpc3VhbGl6YXIgYSBtZWRpYW5hIGUgYSBkaXNwZXJzw6NvIGRvcyBkYWRvcy4KCmBgYHtyIGFuYWxpc2VfaWRhZGV9CiMgR3LDoWZpY286IERpc3RyaWJ1acOnw6NvIGRlIElkYWRlIHBvciBSb3RhdGl2aWRhZGUKZ2dwbG90KGlibV9jbGVhbiwgYWVzKHggPSBhdHRyaXRpb24sIHkgPSBhZ2UsIGZpbGwgPSBhdHRyaXRpb24pKSArCiAgZ2VvbV9qaXR0ZXIoYWxwaGEgPSAwLjIsIGNvbG9yID0gImdyZXk0MCIsIHdpZHRoID0gMC4yKSArCiAgZ2VvbV9ib3hwbG90KGFscGhhID0gMC44LCBvdXRsaWVyLmNvbG91ciA9ICJyZWQiLCB3aWR0aCA9IDAuNSkgKwogIAogICMgQ29yZXMgY29uc2lzdGVudGVzIGNvbSBvIHJlc3RvIGRvIHJlbGF0w7NyaW8KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJObyIgPSAiIzJDM0U1MCIsICJZZXMiID0gIiNFNzRDM0MiKSkgKwogIAogIGxhYnMoCiAgICB0aXRsZSA9ICJPIEZhdG9yIElkYWRlIG5hIFJldGVuw6fDo28gZGUgVGFsZW50byIsCiAgICBzdWJ0aXRsZSA9ICJDb2xhYm9yYWRvcmVzIHF1ZSBzYWVtIChZZXMpIGFwcmVzZW50YW0gdW1hIG1lZGlhbmEgZGUgaWRhZGUgdmlzaXZlbG1lbnRlIGluZmVyaW9yIiwKICAgIHggPSAiRGVjaXPDo28gZGUgU2HDrWRhIiwKICAgIHkgPSAiSWRhZGUgKEFub3MpIgogICkgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoCiAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxNiwgY29sb3IgPSAiIzJjM2U1MCIpLAogICAgcGFuZWwuZ3JpZC5tYWpvci54ID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiKQogICkKYGBgCgoqKl9JbnNpZ2h0c18gc29icmUgYSBJZGFkZToqKgoKQSBhbsOhbGlzZSBkbyBib3hwbG90IGV2aWRlbmNpYSB1bWEgdGVuZMOqbmNpYSBjbGFyYSBuYSByZWxhw6fDo28gZW50cmUgKippZGFkZSoqIGUgKipyb3RhdGl2aWRhZGUgZGUgY29sYWJvcmFkb3JlcyoqOgoKMS4gKipGYXRvciBKdXZlbnR1ZGUqKiDigJMgVmVyaWZpY2Etc2UgdW1hIHRlbmTDqm5jaWEgc2VndW5kbyBhIHF1YWwgb3MgY29sYWJvcmFkb3JlcyBtYWlzIGpvdmVucyBhcHJlc2VudGFtIHVtYSAqKm1haW9yIHByb3BlbnPDo28gcGFyYSBzYWlyIGRhIGVtcHJlc2EqKi4gQSBtZWRpYW5hIGRlIGlkYWRlIGRvcyBmdW5jaW9uw6FyaW9zIHF1ZSBzYWVtIMOpIHZpc2l2ZWxtZW50ZSBpbmZlcmlvciDDoCBkb3MgcXVlIHBlcm1hbmVjZW0uCgoyLiAqKlpvbmEgZGUgUmlzY28qKiDigJMgQSBtYWlvciBjb25jZW50cmHDp8OjbyBkZSBzYcOtZGFzIHNpdHVhLXNlIGVudHJlIG9zICoqMjUgZSBvcyAzNSBhbm9zKiosIGZhaXhhIGV0w6FyaWEgZnJlcXVlbnRlbWVudGUgYXNzb2NpYWRhIGEgKiptb2JpbGlkYWRlIHByb2Zpc3Npb25hbCoqIGUgKipwcm9jdXJhIGRlIHByb2dyZXNzw6NvIG5hIGNhcnJlaXJhKiouIEVzdGUgY29tcG9ydGFtZW50byBwb2RlIHJlZmxldGlyIGRlc2FmaW9zIGRhIG9yZ2FuaXphw6fDo28gZW0gKipyZXRlciB0YWxlbnRvIGpvdmVtKiogb3UgZW0gb2ZlcmVjZXIgKipwbGFub3MgZGUgZGVzZW52b2x2aW1lbnRvIGVzdHJ1dHVyYWRvcyoqLgoKMy4gKipFc3RhYmlsaWRhZGUgU8OpbmlvcioqIOKAkyBDb2xhYm9yYWRvcmVzIGNvbSAqKm1haXMgZGUgNDAgYW5vcyoqIGFwcmVzZW50YW0gKiptYWlvciBlc3RhYmlsaWRhZGUqKiBlICoqbWVub3IgcHJvYmFiaWxpZGFkZSBkZSBzYcOtZGEqKi4gQXMgcG91Y2FzIG9jb3Jyw6puY2lhcyBuZXN0YSBmYWl4YSBldMOhcmlhIHN1cmdlbSBjb21vIF9vdXRsaWVyc18gbm8gZ3LDoWZpY28sIHN1Z2VyaW5kbyBjYXNvcyBwb250dWFpcyBkZSBzYcOtZGEgZGEgZW1wcmVzYSAocG9yIGV4ZW1wbG8sIHJlZm9ybWEsIG11ZGFuw6dhIHBlc3NvYWwgb3UgcmVlc3RydXR1cmHDp8OjbyBpbnRlcm5hKS4KCioqQ29uY2x1c8OjbyoqOiBPcyByZXN1bHRhZG9zIHN1Z2VyZW0gYSBuZWNlc3NpZGFkZSBkZSB1bWEgKiplc3RyYXTDqWdpYSBkZSByZXRlbsOnw6NvIHNlZ21lbnRhZGEqKjoKCiogKipDb2xhYm9yYWRvcmVzIGrDum5pb3JlcyBlIGludGVybcOpZGlvcyoqICgyNS0zNSBhbm9zKSBkZXZlbSBzZXIgYWx2byBkZSBhw6fDtWVzIGZvY2FkYXMgZW0gX2VuZ2FnZW1lbnRfLCBwcm9ncmVzc8OjbyBpbnRlcm5hIGUgZ2VzdMOjbyBkZSBleHBlY3RhdGl2YXMgZGUgY2FycmVpcmE7CgoqIErDoSBwYXJhIG9zICoqY29sYWJvcmFkb3JlcyBzw6luaW9yZXMqKiwgbyBmb2NvIHBvZGVyw6Egc2VyIHJlY29uaGVjaW1lbnRvLCBtZW50b3JpYSBlIHRyYW5zbWlzc8OjbyBkZSBfa25vdy1ob3dfLCByZWZvcsOnYW5kbyBvIHNlbnRpbWVudG8gZGUgcGVydGVuw6dhIGUgY29udGludWlkYWRlIG9yZ2FuaXphY2lvbmFsLgoKYGBge3IgYW5hbGlzZV9lc3RhZG9fY2l2aWx9CiMgR3LDoWZpY28gZGUgQmFycmFzOiBQcm9wb3LDp8OjbyBkZSBTYcOtZGEgcG9yIEVzdGFkbyBDaXZpbApnZ3Bsb3QoaWJtX2NsZWFuLCBhZXMoeCA9IG1hcml0YWxfc3RhdHVzLCBmaWxsID0gYXR0cml0aW9uKSkgKwogIGdlb21fYmFyKHBvc2l0aW9uID0gImZpbGwiLCB3aWR0aCA9IDAuNywgYWxwaGEgPSAwLjkpICsKICAKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJObyIgPSAiIzJDM0U1MCIsICJZZXMiID0gIiNFNzRDM0MiKSkgKwogIAogICMgRm9ybWF0YcOnw6NvIGRvIGVpeG8gWSBwYXJhIHBlcmNlbnRhZ2VtCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudF9mb3JtYXQoKSwgZXhwYW5kID0gYygwLDApKSArCiAgCiAgbGFicygKICAgIHRpdGxlID0gIkltcGFjdG8gZG8gRXN0YWRvIENpdmlsIG5hIFJldGVuw6fDo28iLAogICAgc3VidGl0bGUgPSAiQ29sYWJvcmFkb3JlcyBzb2x0ZWlyb3MgYXByZXNlbnRhbSB1bWEgdGF4YSBkZSBzYcOtZGEgc2lnbmlmaWNhdGl2YW1lbnRlIHN1cGVyaW9yIiwKICAgIHggPSAiRXN0YWRvIENpdmlsIiwKICAgIHkgPSAiUHJvcG9yw6fDo28gZGUgRnVuY2lvbsOhcmlvcyIsCiAgICBmaWxsID0gIlNhw61kYT8iCiAgKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZSgKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDE2LCBjb2xvciA9ICIjMmMzZTUwIiksCiAgICBsZWdlbmQucG9zaXRpb24gPSAidG9wIiwgCiAgICBwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiKSAKICApCmBgYAoqKl9JbnNpZ2h0c18gc29icmUgbyBFc3RhZG8gQ2l2aWw6KioKCkEgYW7DoWxpc2Ugc3VnZXJlIHF1ZSBvICoqZXN0YWRvIGNpdmlsKiogY29uc3RpdHVpIHVtICoqZmF0b3IgcmVsZXZhbnRlIG5hIHJvdGF0aXZpZGFkZSBkZSBjb2xhYm9yYWRvcmVzKio6CgoxLiAqKk1haW9yIHJpc2NvIGVudHJlIGNvbGFib3JhZG9yZXMgc29sdGVpcm9zKiog4oCTIE9zIHRyYWJhbGhhZG9yZXMgc29sdGVpcm9zIHJlZ2lzdGFtIHVtYSAqKnRheGEgZGUgc2HDrWRhIHN1cGVyaW9yIGEgMjUlKiosIG1haXMgZG8gZG9icm8gZGEgb2JzZXJ2YWRhIGVudHJlIGNvbGFib3JhZG9yZXMgY2FzYWRvcyBvdSBkaXZvcmNpYWRvcyAoYXByb3hpbWFkYW1lbnRlIDExJSkuIEVzdGUgcmVzdWx0YWRvIGluZGljYSBxdWUgYSBwcm9iYWJpbGlkYWRlIGRlIHNhw61kYSBlc3TDoSBzaWduaWZpY2F0aXZhbWVudGUgYXNzb2NpYWRhIGFvIGVzdGFkbyBjaXZpbC4KCjIuICoqUG9zc8OtdmVsIGV4cGxpY2HDp8OjbyBjb21wb3J0YW1lbnRhbCoqIOKAkyBFc3RlIHBhZHLDo28gw6kgY29uc2lzdGVudGUgY29tIGV2aWTDqm5jaWEgZW1ww61yaWNhIG5hIGxpdGVyYXR1cmEgZGUgcmVjdXJzb3MgaHVtYW5vcywgcXVlIGFwb250YSBxdWUgcHJvZmlzc2lvbmFpcyBzZW0gZGVwZW5kZW50ZXMgb3UgbGHDp29zIGZhbWlsaWFyZXMgZGlyZXRvcyB0ZW5kZW0gYSBhcHJlc2VudGFyIG1haW9yIG1vYmlsaWRhZGUgbGFib3JhbC4gRXNzYSBmbGV4aWJpbGlkYWRlIGdlb2dyw6FmaWNhIGUgZmluYW5jZWlyYSBwb2RlIGZhY2lsaXRhciBhIHByb2N1cmEgZGUgbm92YXMgb3BvcnR1bmlkYWRlcyBvdSBhIGFjZWl0YcOnw6NvIGRlIHByb3Bvc3RhcyBlbSBkaWZlcmVudGVzIGxvY2Fpcy4KCioqQ29uY2x1c8OjbyoqOiBBIGdlc3TDo28gZGUgdGFsZW50byBwb2RlcsOhIGJlbmVmaWNpYXIgZGUgKiplc3RyYXTDqWdpYXMgZGlmZXJlbmNpYWRhcyBkZSByZXRlbsOnw6NvKiogZW50cmUgZ3J1cG9zLCBwcm9tb3ZlbmRvLCBwb3IgZXhlbXBsbywgaW5pY2lhdGl2YXMgZGUgcHJvZ3Jlc3PDo28gZGUgY2FycmVpcmEgZSBwcm9ncmFtYXMgZGUgZW52b2x2aW1lbnRvIG9yZ2FuaXphY2lvbmFsIHF1ZSBhdW1lbnRlbSBvIGNvbXByb21pc3NvIGRvcyBjb2xhYm9yYWRvcmVzIG1haXMgam92ZW5zIGUgc29sdGVpcm9zIGNvbSBhIGVtcHJlc2EuCgojIyBBbsOhbGlzZSBQcm9maXNzaW9uYWw6IENhcmdhIGRlIFRyYWJhbGhvIGUgVmlhZ2VucwoKU2Vyw6EgcXVlIG8gZXhjZXNzbyBkZSB0cmFiYWxobyAoYE92ZXJUaW1lYCkgZSBhcyB2aWFnZW5zIGZyZXF1ZW50ZXMgKGBCdXNpbmVzc1RyYXZlbGApIGxldmFtIMOgIGV4YXVzdMOjbyBlIGNvbnNlcXVlbnRlIHNhw61kYT8KCmBgYHtyIGFuYWxpc2VfY2FyZ2FfdHJhYmFsaG99CiMgR3LDoWZpY28gZGUgSG9yYXMgRXh0cmEgKHAxKQpwMSA8LSBnZ3Bsb3QoaWJtX2NsZWFuLCBhZXMoeCA9IG92ZXJfdGltZSwgZmlsbCA9IGF0dHJpdGlvbikpICsKICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJmaWxsIiwgd2lkdGggPSAwLjcsIGFscGhhID0gMC45KSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudF9mb3JtYXQoKSwgZXhwYW5kID0gYygwLDApKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiTm8iID0gIiMyQzNFNTAiLCAiWWVzIiA9ICIjRTc0QzNDIikpICsKICBsYWJzKAogICAgdGl0bGUgPSAiSW1wYWN0byBkYXMgSG9yYXMgRXh0cmEiLCAKICAgIHggPSAiRmF6IEhvcmFzIEV4dHJhPyIsIAogICAgeSA9ICJQcm9wb3LDp8OjbyIKICApICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKAogICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLCAKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDEzLCBjb2xvciA9ICIjMmMzZTUwIiksCiAgICBwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2JsYW5rKCkKICApCgojIEdyw6FmaWNvIGRlIFZpYWdlbnMgZGUgVHJhYmFsaG8gKHAyKQpwMiA8LSBnZ3Bsb3QoaWJtX2NsZWFuLCBhZXMoeCA9IGJ1c2luZXNzX3RyYXZlbCwgZmlsbCA9IGF0dHJpdGlvbikpICsKICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJmaWxsIiwgd2lkdGggPSAwLjcsIGFscGhhID0gMC45KSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudF9mb3JtYXQoKSwgZXhwYW5kID0gYygwLDApKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiTm8iID0gIiMyQzNFNTAiLCAiWWVzIiA9ICIjRTc0QzNDIikpICsKICBsYWJzKAogICAgdGl0bGUgPSAiSW1wYWN0byBkYXMgVmlhZ2VucyIsIAogICAgeCA9ICJGcmVxdcOqbmNpYSBkZSBWaWFnZW5zIiwgCiAgICB5ID0gTlVMTCwKICAgIGZpbGwgPSAiU2HDrWRhPyIKICApICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBzaXplID0gMTMsIGNvbG9yID0gIiMyYzNlNTAiKSwKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSksCiAgICBwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2JsYW5rKCkKICApCgojIEp1bnRhciBhcyBkdWFzIHZpc3VhbGl6YcOnw7VlcwpsaWJyYXJ5KGdyaWRFeHRyYSkKZ3JpZC5hcnJhbmdlKHAxLCBwMiwgbmNvbCA9IDIsIHRvcCA9IGdyaWQ6OnRleHRHcm9iKCJBbsOhbGlzZSBkZSBDYXJnYSBkZSBUcmFiYWxobyBlIE1vYmlsaWRhZGUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3AgPSBncmlkOjpncGFyKGZvbnRzaXplID0gMTYsIGZvbnQgPSAyLCBjb2wgPSAiIzJjM2U1MCIpKSkKYGBgCioqX0luc2lnaHRzXyBzb2JyZSBDYXJnYSBkZSBUcmFiYWxobyBlIEVzdGlsbyBkZSBWaWRhOioqCgpBIGFuw6FsaXNlIGRhIGNhcmdhIGRlIHRyYWJhbGhvIGUgZGEgbW9iaWxpZGFkZSBwcm9maXNzaW9uYWwgcmV2ZWxhIHVtYSBhc3NvY2lhw6fDo28gZXZpZGVudGUgZW50cmUgZXhhdXN0w6NvIGUgcm90YXRpdmlkYWRlIGRlIGNvbGFib3JhZG9yZXM6CgoxLiAqKkltcGFjdG8gZGFzIEhvcmFzIEV4dHJhKiog4oCTIE8gZWZlaXRvIGRhcyBob3JhcyBleHRyYSDDqSBwYXJ0aWN1bGFybWVudGUgZXhwcmVzc2l2by4gQ29sYWJvcmFkb3JlcyBxdWUgbsOjbyByZWFsaXphbSBob3JhcyBleHRyYSBhcHJlc2VudGFtIHVtYSB0YXhhIGRlIHNhw61kYSBwcsOzeGltYSBkZSAxMCUsIGVucXVhbnRvIGVudHJlIG9zIHF1ZSB0cmFiYWxoYW0gYWzDqW0gZG8gaG9yw6FyaW8gcmVndWxhciwgZXNzYSBwcm9wb3LDp8OjbyB0cmlwbGljYSBwYXJhIGNlcmNhIGRlIDMwJS4KRXN0ZSByZXN1bHRhZG8gY29uc3RpdHVpIHVtIGluZGljYWRvciBjbGFybyBkZSByaXNjbyBkZSBfYnVybm91dF8gZSBzdWdlcmUgcXVlIG8gZXhjZXNzbyBkZSBjYXJnYSBob3LDoXJpYSBwb2RlIGVzdGFyIGFzc29jaWFkbyDDoCBpbnNhdGlzZmHDp8OjbyBlIGRlc2dhc3RlIGVtb2Npb25hbC4KCjIuICoqTyBQZXNvIGRhIE1vYmlsaWRhZGUqKiAoYEJ1c2luZXNzVHJhdmVgbCkg4oCTIE9ic2VydmEtc2UgdW1hIHRlbmTDqm5jaWEgY3Jlc2NlbnRlIGVudHJlIGZyZXF1w6puY2lhIGRlIHZpYWdlbnMgZSBwcm9iYWJpbGlkYWRlIGRlIHNhw61kYToKCiogQ29sYWJvcmFkb3JlcyBxdWUgKipuw6NvIHZpYWphbSoqIChgTm9u4oCRVHJhdmVsYCkgYXByZXNlbnRhbSBhIG1lbm9yIHRheGEgZGUgcm90YXRpdmlkYWRlICg8MTAlKTsKCiogRW50cmUgb3MgcXVlICoqdmlhamFtIGNvbSBmcmVxdcOqbmNpYSoqIChgVHJhdmVsX0ZyZXF1ZW50bHlgKSwgbyByaXNjbyBhcHJveGltYeKAkXNlIGRvcyAyNSUsIGluZGljYW5kbyBxdWUgbyBlcXVpbMOtYnJpbyBlbnRyZSB2aWRhIHBlc3NvYWwgZSBwcm9maXNzaW9uYWwgc2UgZW5jb250cmEgY29uc2lkZXJhdmVsbWVudGUgY29tcHJvbWV0aWRvLgoKKipDb25jbHVzw6NvKio6IFRhbnRvIGEgc29icmVjYXJnYSBkZSB0cmFiYWxobyBjb21vIGEgbW9iaWxpZGFkZSBleGNlc3NpdmEgc3VyZ2VtIGNvbW8gZmF0b3JlcyBkZSByaXNjbyByZWxldmFudGVzIHBhcmEgYSByZXRlbsOnw6NvIGRlIHRhbGVudG8uIFBvbMOtdGljYXMgb3JnYW5pemFjaW9uYWlzIHF1ZSBwcm9tb3ZhbSBsaW1pdGVzIHNhdWTDoXZlaXMgZGUgam9ybmFkYSwgZmxleGliaWxpZGFkZSBsYWJvcmFsIGUgZXF1aWzDrWJyaW8gdmlkYeKAkXRyYWJhbGhvIHBvZGVyw6NvIG1pdGlnYXIgc2lnbmlmaWNhdGl2YW1lbnRlIGVzdGUgdGlwbyBkZSByb3RhdGl2aWRhZGUuCgojIyBBbsOhbGlzZSBGaW5hbmNlaXJhOiBPIFNhbMOhcmlvIEltcG9ydGE/CkZvaSBhbmFsaXNhZGEgYSBkaXN0cmlidWnDp8OjbyBzYWxhcmlhbCAoYE1vbnRobHlJbmNvbWVgKSBwYXJhIGVudGVuZGVyIHNlIHNhbMOhcmlvcyBtYWlzIGJhaXhvcyBpbXB1bHNpb25hbSBhIHNhw61kYS4KCmBgYHtyIGFuYWxpc2Vfc2FsYXJpb30KIyBHcsOhZmljbyBkZSBEZW5zaWRhZGU6IFNhbMOhcmlvIE1lbnNhbCBwb3IgUm90YXRpdmlkYWRlCmdncGxvdChpYm1fY2xlYW4sIGFlcyh4ID0gbW9udGhseV9pbmNvbWUsIGZpbGwgPSBhdHRyaXRpb24pKSArCiAgZ2VvbV9kZW5zaXR5KGFscGhhID0gMC43LCBjb2xvciA9ICJ3aGl0ZSIpICsKICAKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJObyIgPSAiIzJDM0U1MCIsICJZZXMiID0gIiNFNzRDM0MiKSkgKwogIAogICMgRm9ybWF0YcOnw6NvIGRvIGVpeG8gWCBwYXJhIE1vZWRhIChEw7NsYXIpCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6ZG9sbGFyX2Zvcm1hdCgpLCBicmVha3MgPSBzZXEoMCwgMjAwMDAsIDI1MDApKSArCiAgCiAgbGFicygKICAgIHRpdGxlID0gIkRpc3RyaWJ1acOnw6NvIFNhbGFyaWFsIGUgbyBSaXNjbyBkZSBSb3RhdGl2aWRhZGUiLAogICAgc3VidGl0bGUgPSAiQSBwcm9iYWJpbGlkYWRlIGRlIHNhw61kYSDDqSBkcmFzdGljYW1lbnRlIHN1cGVyaW9yIGVtIGZhaXhhcyBzYWxhcmlhaXMgYWJhaXhvIGRvcyAkNS4wMDAiLAogICAgeCA9ICJTYWzDoXJpbyBNZW5zYWwgKFVTRCkiLAogICAgeSA9ICJEZW5zaWRhZGUgZGUgQ29sYWJvcmFkb3JlcyIsCiAgICBmaWxsID0gIlN0YXR1cyBkZSBTYcOtZGEiCiAgKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZSgKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDE2LCBjb2xvciA9ICIjMmMzZTUwIiksCiAgICBsZWdlbmQucG9zaXRpb24gPSAidG9wIiwKICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICBwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2JsYW5rKCkKICApCmBgYAoKKipfSW5zaWdodHNfIEZpbmFuY2Vpcm9zOioqCgpBIGFuw6FsaXNlIGRhIGRpc3RyaWJ1acOnw6NvIHNhbGFyaWFsIGV2aWRlbmNpYSBxdWUgYSAqKnJlbXVuZXJhw6fDo28gw6kgdW0gZmF0b3IgZGV0ZXJtaW5hbnRlKiogbmEgcHJvYmFiaWxpZGFkZSBkZSBzYcOtZGEsIGFwcmVzZW50YW5kbyB1bSBwYWRyw6NvIGJhc3RhbnRlIGRpc3RpbnRvIGVudHJlIGFzIGZhaXhhcyBkZSByZW5kaW1lbnRvOgoKMS4gKipBIGJhcnJlaXJhIGRvcyA1MDAwJCoqIOKAkyBPYnNlcnZh4oCRc2UgdW1hIGNvbmNlbnRyYcOnw6NvIHNpZ25pZmljYXRpdmEgZGUgc2HDrWRhcyBlbnRyZSBjb2xhYm9yYWRvcmVzIGNvbSBzYWzDoXJpb3MgbWVuc2FpcyBpbmZlcmlvcmVzIGEgNTAwMCQgTmVzdGEgZmFpeGEsIGEgZGVuc2lkYWRlIGRlIGNhc29zIGRlIF9hdHRyaXRpb25fIMOpIHN1YnN0YW5jaWFsbWVudGUgc3VwZXJpb3IsIHN1Z2VyaW5kbyBxdWUgbsOtdmVpcyBzYWxhcmlhaXMgbWFpcyBiYWl4b3MgZXN0w6NvIGFzc29jaWFkb3MgYSB1bWEgbWFpb3Igdm9sYXRpbGlkYWRlIGRhIGZvcsOnYSBkZSB0cmFiYWxoby4KCjIuICoqUmV0ZW7Dp8OjbyBlbSBmYWl4YXMgc2FsYXJpYWlzIGVsZXZhZGFzKiog4oCTIMOAIG1lZGlkYSBxdWUgbyBzYWzDoXJpbyBhdW1lbnRhIChwYXJ0aWN1bGFybWVudGUgYWNpbWEgZG9zIDEwMDAwJCksIGEgcHJvYmFiaWxpZGFkZSBkZSBzYcOtZGEgcmVkdXogZHJhc3RpY2FtZW50ZS4gRW50cmUgb3MgY29sYWJvcmFkb3JlcyBjb20gcmVuZGltZW50b3MgbWFpcyBhbHRvcywgYSBjdXJ2YSBkZSBkZW5zaWRhZGUgYXNzb2NpYWRhIMOgIHBlcm1hbsOqbmNpYSDDqSBjbGFyYW1lbnRlIHByZWRvbWluYW50ZSwgaW5kaWNhbmRvIG1haW9yIGVzdGFiaWxpZGFkZSBlIHNhdGlzZmHDp8OjbyBwcm9maXNzaW9uYWwuCgoqKkNvbmNsdXPDo28qKjogTyBwYWRyw6NvIG9ic2VydmFkbyBzdWdlcmUgcXVlIGEgZW1wcmVzYSBlbmZyZW50YSBtYWlvcmVzIGRlc2FmaW9zIGRlIHJldGVuw6fDo28gZW50cmUgY29sYWJvcmFkb3JlcyBkZSBuw612ZWwgb3BlcmFjaW9uYWwgZSBmdW7Dp8O1ZXMgasO6bmlvcmVzLCBvbmRlIGEgY29tcGVuc2HDp8OjbyBwb2RlIG7Do28gZXN0YXIgYWxpbmhhZGEgY29tIGFzIGV4cGVjdGF0aXZhcyBkbyBtZXJjYWRvLiBFc3RyYXTDqWdpYXMgc2FsYXJpYWlzIG1haXMgY29tcGV0aXRpdmFzLCBjb21wbGVtZW50YWRhcyBwb3IgcGxhbm9zIGRlIHByb2dyZXNzw6NvIGUgdmFsb3JpemHDp8OjbyBpbnRlcm5hLCBwb2RlcsOjbyBzZXIgZGVjaXNpdmFzIHBhcmEgcmVkdXppciBhIHJvdGF0aXZpZGFkZSBuZXN0YXMgZmFpeGFzIHNhbGFyaWFpcy4KCiMjIEFuw6FsaXNlIGRlIEZ1bsOnw6NvIGUgU2F0aXNmYcOnw6NvCkFudGVzIGRlIGF2YW7Dp2FybW9zIHBhcmEgYXMgY29ycmVsYcOnw7VlcyBudW3DqXJpY2FzLCBmYWx0YSBhbmFsaXNhciBkdWFzIHZhcmnDoXZlaXMgY2F0ZWfDs3JpY2FzIGNydWNpYWlzOiBvIENhcmdvIChgSm9iUm9sZWApIGUgYSBTYXRpc2Zhw6fDo28gbm8gVHJhYmFsaG8gKGBKb2JTYXRpc2ZhY3Rpb25gKS4KCk8gb2JqZXRpdm8gw6kgaWRlbnRpZmljYXIgc2UgZXhpc3RlbSBjYXJnb3MgZXNwZWPDrWZpY29zIGNvbSBtYWlvciByb3RhdGl2aWRhZGUuCgpgYGB7ciBhbmFsaXNlX2NhcmdvX3NhdGlzZmFjYW99CiMgUm90YXRpdmlkYWRlIHBvciBDYXJnbwpwX3JvbGUgPC0gZ2dwbG90KGlibV9jbGVhbiwgYWVzKHkgPSByZW9yZGVyKGpvYl9yb2xlLCAoYXR0cml0aW9uID09ICJZZXMiKSksIGZpbGwgPSBhdHRyaXRpb24pKSArCiAgZ2VvbV9iYXIocG9zaXRpb24gPSAiZmlsbCIsIHdpZHRoID0gMC43LCBhbHBoYSA9IDAuOSkgKwogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnRfZm9ybWF0KCksIGV4cGFuZCA9IGMoMCwwKSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIk5vIiA9ICIjMkMzRTUwIiwgIlllcyIgPSAiI0U3NEMzQyIpKSArCiAgbGFicygKICAgIHRpdGxlID0gIlJvdGF0aXZpZGFkZSBwb3IgQ2FyZ28iLAogICAgc3VidGl0bGUgPSAiVmVuZGFzLCBSSCBlIFTDqWNuaWNvcyBkZSBMYWJvcmF0w7NyaW8gYXByZXNlbnRhbSBtYWlvciByaXNjbyIsCiAgICB5ID0gTlVMTCwKICAgIHggPSAiUHJvcG9yw6fDo28gZGUgU2HDrWRhIgogICkgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoCiAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxMywgY29sb3IgPSAiIzJjM2U1MCIpLAogICAgcGFuZWwuZ3JpZC5tYWpvci55ID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDksIGZhY2UgPSAiYm9sZCIpCiAgKQoKIyBJbXBhY3RvIGRhIFNhdGlzZmHDp8OjbwpwX3NhdCA8LSBnZ3Bsb3QoaWJtX2NsZWFuLCBhZXMoeCA9IGZhY3Rvcihqb2Jfc2F0aXNmYWN0aW9uKSwgZmlsbCA9IGF0dHJpdGlvbikpICsKICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJmaWxsIiwgd2lkdGggPSAwLjYsIGFscGhhID0gMC45KSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudF9mb3JtYXQoKSwgZXhwYW5kID0gYygwLDApKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiTm8iID0gIiMyQzNFNTAiLCAiWWVzIiA9ICIjRTc0QzNDIikpICsKICBsYWJzKAogICAgdGl0bGUgPSAiSW1wYWN0byBkYSBTYXRpc2Zhw6fDo28gbm8gVHJhYmFsaG8iLAogICAgc3VidGl0bGUgPSAiTsOtdmVpcyBiYWl4b3MgZGUgc2F0aXNmYcOnw6NvICgxIGUgMikgY29ycmVsYWNpb25hbS1zZSBjb20gbWFpb3IgY2h1cm4iLAogICAgeCA9ICJOw612ZWwgZGUgU2F0aXNmYcOnw6NvICgxOiBCYWl4YSDihpIgNDogQWx0YSkiLAogICAgeSA9ICJQcm9wb3LDp8OjbyIsCiAgICBmaWxsID0gIlNhw61kYT8iCiAgKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZSgKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDEzLCBjb2xvciA9ICIjMmMzZTUwIiksCiAgICBsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiLAogICAgcGFuZWwuZ3JpZC5tYWpvci54ID0gZWxlbWVudF9ibGFuaygpCiAgKQoKbGlicmFyeShncmlkRXh0cmEpCmdyaWQuYXJyYW5nZShwX3JvbGUsIHBfc2F0LCBucm93ID0gMiwgCiAgICAgICAgICAgICB0b3AgPSBncmlkOjp0ZXh0R3JvYigiQW7DoWxpc2UgZGUgRnVuw6fDo28gZSBTZW50aW1lbnRvIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncCA9IGdyaWQ6OmdwYXIoZm9udHNpemUgPSAxNiwgZm9udCA9IDIsIGNvbCA9ICIjMmMzZTUwIikpKQpgYGAKKipfSW5zaWdodHNfIHNvYnJlIEZ1bsOnw6NvIGUgU2F0aXNmYcOnw6NvOioqCgpBIGFuw6FsaXNlIGV2aWRlbmNpYSAqKnBhZHLDtWVzIGRpc3RpbnRvcyBkZSByb3RhdGl2aWRhZGUgcG9yIGZ1bsOnw6NvKiosIHJldmVsYW5kbyDDoXJlYXMgY3LDrXRpY2FzIGRlbnRybyBkYSBvcmdhbml6YcOnw6NvOgoKMS4gKipGdW7Dp8O1ZXMgZGUgVmVuZGFzIChfU2FsZXMgUmVwcmVzZW50YXRpdmVzXykqKiDigJMgRXN0ZSBncnVwbyBhcHJlc2VudGEgYSBtYWlvciB0YXhhIGRlIHNhw61kYSwgcHLDs3hpbWEgZG9zIDQwJSwgbyBxdWUgw6kgaW5kaWNhdGl2byBkZSBwcmVzc8OjbyBjb21lcmNpYWwgZWxldmFkYSwgb2JqZXRpdm9zIGV4aWdlbnRlcyBvdSBzaXN0ZW1hcyBkZSBpbmNlbnRpdm9zIHBvdWNvIGF0cmF0aXZvcy4gVHJhdGHigJFzZSBkZSB1bSBmb2NvIHByaW9yaXTDoXJpbyBkZSBhdHVhw6fDo28sIGRhZGEgYSBpbXBvcnTDom5jaWEgZXN0cmF0w6lnaWNhIGRlc3RhcyBmdW7Dp8O1ZXMgcGFyYSBvIGRlc2VtcGVuaG8gZ2xvYmFsIGRhIGVtcHJlc2EuCgoyLiAqKlTDqWNuaWNvcyBkZSBMYWJvcmF0w7NyaW8gZSBSZWN1cnNvcyBIdW1hbm9zKiog4oCTIEFtYmFzIGFzIGZ1bsOnw7VlcyByZWdpc3RhbSB0YXhhcyBkZSBzYcOtZGEgZW0gdG9ybm8gZG9zIDI1JSwgY2xhcmFtZW50ZSBhY2ltYSBkYSBtw6lkaWEgb3JnYW5pemFjaW9uYWwuIAoKMy4gKipSZXRlbsOnw6NvIG5hcyBmdW7Dp8O1ZXMgZGUgbGlkZXJhbsOnYSoqIOKAkyBPcyBjYXJnb3MgZGUgZ2VzdMOjbyBlIGRpcmXDp8OjbyAoX01hbmFnZXJzXyBlIF9EaXJlY3RvcnNfKSBhcHJlc2VudGFtIG7DrXZlaXMgZGUgZXN0YWJpbGlkYWRlIG11aXRvIGVsZXZhZG9zLCBvIHF1ZSBzdWdlcmUgcXVlIGEgcm90YXRpdmlkYWRlIMOpIHByZWRvbWluYW50ZW1lbnRlIHVtIGZlbsOzbWVubyBkb3MgbsOtdmVpcyBoaWVyw6FycXVpY29zIGludGVybcOpZGlvcyBlIG9wZXJhY2lvbmFpcy4gRXN0ZSBwYWRyw6NvIHJldmVsYSBhIGltcG9ydMOibmNpYSBkZSBkaXJlY2lvbmFyIGFzIGVzdHJhdMOpZ2lhcyBkZSByZXRlbsOnw6NvIGUgZGVzZW52b2x2aW1lbnRvIHBhcmEgYXMgZnVuw6fDtWVzIG1haXMgdnVsbmVyw6F2ZWlzLgoKKipDb25jbHVzw6NvKio6IEEgcm90YXRpdmlkYWRlIHBhcmVjZSBjb25jZW50cmFy4oCRc2UgZW0gcG9zacOnw7VlcyBkZSBiYXNlIGUgZnVuw6fDtWVzIGRlIHN1cG9ydGUgb3BlcmFjaW9uYWwsIGV4aWdpbmRvIHBvbMOtdGljYXMgZm9jYWRhcyBlbSBtZWxob3JpYSBkbyBjbGltYSBvcmdhbml6YWNpb25hbCwgcmV2aXPDo28gZGUgaW5jZW50aXZvcyBlIG9wb3J0dW5pZGFkZXMgZGUgcHJvZ3Jlc3PDo28sIHBvciBmb3JtYSBhIGZvcnRhbGVjZXIgbyBjb21wcm9taXNzbyBlIGEgcmV0ZW7Dp8OjbyBuZXN0ZXMgZ3J1cG9zLgoKIyMgQW7DoWxpc2UgZGEgQW50aWd1aWRhZGUgZSBUZW1wbyBkZSBEZXNsb2Nhw6fDo28gCkZvaSBpbnZlc3RpZ2FkYSBhIGFudGlndWlkYWRlIG5hIGVtcHJlc2EgKGBZZWFyc0F0Q29tcGFueWApIGUgYSBkaXN0w6JuY2lhIGRlIGNhc2EgKGBEaXN0YW5jZUZyb21Ib21lYCkuCk8gb2JqZXRpdm8gw6kgZW50ZW5kZXIgc2UgcGVyZGVtb3MgdGFsZW50byByZWPDqW0tY29udHJhdGFkbyBlIHNlIG8gdHJhamV0byBkacOhcmlvIGluZmx1ZW5jaWEgYSBkZWNpc8Ojby4KCmBgYHtyIGFuYWxpc2VfYW50aWd1aWRhZGVfZGlzdGFuY2lhfQojIEdyw6FmaWNvIGRlIEFudGlndWlkYWRlIChBbm9zIG5hIEVtcHJlc2EpCnBfeWVhcnMgPC0gZ2dwbG90KGlibV9jbGVhbiwgYWVzKHggPSB5ZWFyc19hdF9jb21wYW55LCBmaWxsID0gYXR0cml0aW9uKSkgKwogIGdlb21fZGVuc2l0eShhbHBoYSA9IDAuNywgY29sb3IgPSAid2hpdGUiKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiTm8iID0gIiMyQzNFNTAiLCAiWWVzIiA9ICIjRTc0QzNDIikpICsKICBsYWJzKAogICAgdGl0bGUgPSAiQ2ljbG8gZGUgVmlkYTogQW50aWd1aWRhZGUgbmEgRW1wcmVzYSIsCiAgICBzdWJ0aXRsZSA9ICJPIHJpc2NvIGRlICdjaHVybicgw6kgY3LDrXRpY28gbm9zIHByaW1laXJvcyAyIGFub3MgKHBlcsOtb2RvIGRlIG9uYm9hcmRpbmcpIiwKICAgIHggPSAiQW5vcyBuYSBFbXByZXNhIiwKICAgIHkgPSAiRGVuc2lkYWRlIgogICkgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoCiAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxMywgY29sb3IgPSAiIzJjM2U1MCIpLAogICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKQogICkKCiMgR3LDoWZpY28gZGUgRGlzdMOibmNpYSAoQm94cGxvdCkKcF9kaXN0IDwtIGdncGxvdChpYm1fY2xlYW4sIGFlcyh4ID0gYXR0cml0aW9uLCB5ID0gZGlzdGFuY2VfZnJvbV9ob21lLCBmaWxsID0gYXR0cml0aW9uKSkgKwogIGdlb21fYm94cGxvdChhbHBoYSA9IDAuOCwgd2lkdGggPSAwLjYsIG91dGxpZXIuY29sb3VyID0gIiNFNzRDM0MiKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiTm8iID0gIiMyQzNFNTAiLCAiWWVzIiA9ICIjRTc0QzNDIikpICsKICBsYWJzKAogICAgdGl0bGUgPSAiTG9nw61zdGljYTogRGlzdMOibmNpYSBDYXNhLVRyYWJhbGhvIiwKICAgIHN1YnRpdGxlID0gIkNvbGFib3JhZG9yZXMgcXVlIHNhZW0gdGVuZGVtIGEgcGVyY29ycmVyIGRpc3TDom5jaWFzIG1haW9yZXMiLAogICAgeCA9ICJEZWNpc8OjbyBkZSBTYcOtZGEiLAogICAgeSA9ICJEaXN0w6JuY2lhIChrbS9taWxoYXMpIgogICkgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxMywgY29sb3IgPSAiIzJjM2U1MCIpLAogICAgcGFuZWwuZ3JpZC5tYWpvci54ID0gZWxlbWVudF9ibGFuaygpCiAgKQoKIyBPcmdhbml6YXIgb3MgZ3LDoWZpY29zCmxpYnJhcnkoZ3JpZEV4dHJhKQpncmlkLmFycmFuZ2UocF95ZWFycywgcF9kaXN0LCBucm93ID0gMiwgCiAgICAgICAgICAgICB0b3AgPSBncmlkOjp0ZXh0R3JvYigiQW7DoWxpc2UgZGUgUmV0ZW7Dp8OjbyBlIExvZ8Otc3RpY2EiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdwID0gZ3JpZDo6Z3Bhcihmb250c2l6ZSA9IDE2LCBmb250ID0gMiwgY29sID0gIiMyYzNlNTAiKSkpCmBgYAoqKl9JbnNpZ2h0c18gZGUgVGVtcG8gZSBMb2fDrXN0aWNhOioqCgpBIGFuw6FsaXNlIGV2aWRlbmNpYSBwb250b3MgY3LDrXRpY29zIG5vIGNpY2xvIGRlIHZpZGEgZG8gY29sYWJvcmFkb3IsIGNvbSBpbXBsaWNhw6fDtWVzIGRpcmV0YXMgcGFyYSBhIHJldGVuw6fDo28gZSBvIGRlc2VtcGVuaG8gb3JnYW5pemFjaW9uYWw6CgoxLiAqKkZhc2UgZGUgX09uYm9hcmRpbmdfIC0gUmlzY28gZGUgc2HDrWRhIHByZWNvY2UqKjogTyBncsOhZmljbyBkZSBhbnRpZ3VpZGFkZSBtb3N0cmEgdW0gcGljbyBhY2VudHVhZG8gZGUgcm90YXRpdmlkYWRlIG5vcyBwcmltZWlyb3MgZG9pcyBhbm9zIGRlIHbDrW5jdWxvLCBwcmVjaXNhbWVudGUgZHVyYW50ZSBvIHBlcsOtb2RvIGRlIGludGVncmHDp8OjbyBlIGFkYXB0YcOnw6NvLiBFc3RlIHJlc3VsdGFkbyBzdWdlcmUgZnJhZ2lsaWRhZGVzIG5vcyBwcm9jZXNzb3MgZGUgYWNvbGhpbWVudG8sIGFjb21wYW5oYW1lbnRvIGluaWNpYWwgb3UgYWxpbmhhbWVudG8gZGUgZXhwZWN0YXRpdmFzIGVudHJlIG8gY29sYWJvcmFkb3IgZSBhIG9yZ2FuaXphw6fDo28uIEludmVzdGlyIGVtIHByb2dyYW1hcyBlc3RydXR1cmFkb3MgZGUgX29uYm9hcmRpbmdfIGUgbWVudG9yaWEgcG9kZXLDoSByZWR1emlyIHN1YnN0YW5jaWFsbWVudGUgZXN0ZSB0aXBvIGRlIHBlcmRhIHByZW1hdHVyYSBkZSB0YWxlbnRvLgoKMi4gKipDdXN0byBkYSBEZXNsb2Nhw6fDo28g4oCTIEZhdG9yIGxvZ8Otc3RpY28gZGUgZGVzZ2FzdGUqKjogTyBib3hwbG90IGRlIGRpc3TDom5jaWFzIGNhc2HigJF0cmFiYWxobyBpbmRpY2EgcXVlIG9zIGNvbGFib3JhZG9yZXMgcXVlIHNhZW0gdGVuZGVtIGEgcGVyY29ycmVyIHRyYWpldG9zIG1haXMgbG9uZ29zLCBvIHF1ZSBhcG9udGEgcGFyYSB1bSBwb3RlbmNpYWwgaW1wYWN0byBuZWdhdGl2byBkbyB0ZW1wbyBlIGVzZm9yw6dvIGRlIGRlc2xvY2HDp8OjbyBuYSBzYXRpc2Zhw6fDo28gZ2VyYWwuIE8gZGVzZ2FzdGUgYXNzb2NpYWRvIGFvIF9jb21tdXRpbmdfIGRpw6FyaW8sIHF1YW5kbyBjb21iaW5hZG8gY29tIGVsZXZhZGFzIGNhcmdhcyBkZSB0cmFiYWxobywgYXVtZW50YSBhIHByb2JhYmlsaWRhZGUgZGUgc2HDrWRhIHZvbHVudMOhcmlhLiBNZWRpZGFzIGNvbW8gdGVsZXRyYWJhbGhvIGjDrWJyaWRvLCBhZGFwdGHDp8OjbyBkZSBob3LDoXJpb3Mgb3UgaW5jZW50aXZvcyBkZSB0cmFuc3BvcnRlIHBvZGVtIG1pdGlnYXIgZXNzZSBlZmVpdG8uCgoqKkNvbmNsdXPDo28qKjogQSByZXRlbsOnw6NvIGVmaWNheiBleGlnZSB1bWEgYWJvcmRhZ2VtIGhvbMOtc3RpY2EgcXVlIGFicmFuamEgdGFudG8gYSBleHBlcmnDqm5jaWEgaW5pY2lhbCBkbyBjb2xhYm9yYWRvciAoX29uYm9hcmRpbmdfKSBjb21vIGEgc3VzdGVudGFiaWxpZGFkZSBsb2fDrXN0aWNhIGRhIHN1YSByb3RpbmEgbGFib3JhbC4gRXN0YXMgZHVhcyBkaW1lbnPDtWVzIHJldmVsYW3igJFzZSBkZXRlcm1pbmFudGVzIHBhcmEgY29uc29saWRhciBvIGNvbXByb21pc3NvIG9yZ2FuaXphY2lvbmFsIG5vcyBwcmltZWlyb3MgYW5vcyBkZSB2w61uY3Vsby4KCiMjIEFuw6FsaXNlIGRvIEfDqW5lcm8gZSBXb3JrLUxpZmUgQmFsYW5jZQpgYGB7ciBhbmFsaXNlX2dlbmVyb193fQojIFJvdGF0aXZpZGFkZSBwb3IgR8OpbmVybyAocF9nZW4pCnBfZ2VuIDwtIGdncGxvdChpYm1fY2xlYW4sIGFlcyh4ID0gZ2VuZGVyLCBmaWxsID0gYXR0cml0aW9uKSkgKwogIGdlb21fYmFyKHBvc2l0aW9uID0gImZpbGwiLCB3aWR0aCA9IDAuNiwgYWxwaGEgPSAwLjkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50X2Zvcm1hdCgpLCBleHBhbmQgPSBjKDAsMCkpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJObyIgPSAiIzJDM0U1MCIsICJZZXMiID0gIiNFNzRDM0MiKSkgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJSb3RhdGl2aWRhZGUgcG9yIEfDqW5lcm8iLCAKICAgIHN1YnRpdGxlID0gIkV4aXN0ZSBkaXNwYXJpZGFkZSBlbnRyZSBob21lbnMgZSBtdWxoZXJlcz8iLAogICAgeCA9IE5VTEwsIAogICAgeSA9ICJQcm9wb3LDp8OjbyIKICApICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKAogICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLCAjIEVzY29uZGVtb3MgYSBsZWdlbmRhIGFxdWkgcGFyYSBuw6NvIHJlcGV0aXIKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDEzLCBjb2xvciA9ICIjMmMzZTUwIiksCiAgICBwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiKQogICkKCiMgQW7DoWxpc2UgZG8gV29yay1MaWZlIEJhbGFuY2UgKHBfd2xiKQpwX3dsYiA8LSBnZ3Bsb3QoaWJtX2NsZWFuLCBhZXMoeCA9IGZhY3Rvcih3b3JrX2xpZmVfYmFsYW5jZSksIGZpbGwgPSBhdHRyaXRpb24pKSArCiAgZ2VvbV9iYXIocG9zaXRpb24gPSAiZmlsbCIsIHdpZHRoID0gMC42LCBhbHBoYSA9IDAuOSkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnRfZm9ybWF0KCksIGV4cGFuZCA9IGMoMCwwKSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIk5vIiA9ICIjMkMzRTUwIiwgIlllcyIgPSAiI0U3NEMzQyIpKSArCiAgbGFicygKICAgIHRpdGxlID0gIkVxdWlsw61icmlvIFZpZGEtVHJhYmFsaG8iLCAKICAgIHN1YnRpdGxlID0gIk8gaW1wYWN0byBkbyBlcXVpbMOtYnJpbyBuYSBkZWNpc8OjbyBkZSBzYcOtZGEiLAogICAgeCA9ICJOw612ZWwgKDE6IE1hdSDihpIgNDogRXhjZWxlbnRlKSIsIAogICAgeSA9IE5VTEwsCiAgICBmaWxsID0gIlNhw61kYT8iCiAgKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZSgKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDEzLCBjb2xvciA9ICIjMmMzZTUwIiksCiAgICBsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiLAogICAgcGFuZWwuZ3JpZC5tYWpvci54ID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIikKICApCgojIEp1bnRhciBvcyBkb2lzIGxhZG8gYSBsYWRvCmxpYnJhcnkoZ3JpZEV4dHJhKQpncmlkLmFycmFuZ2UocF9nZW4sIHBfd2xiLCBuY29sID0gMiwgCiAgICAgICAgICAgICB0b3AgPSBncmlkOjp0ZXh0R3JvYigiQmVtLUVzdGFyIGUgRGl2ZXJzaWRhZGUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdwID0gZ3JpZDo6Z3Bhcihmb250c2l6ZSA9IDE2LCBmb250ID0gMiwgY29sID0gIiMyYzNlNTAiKSkpCmBgYAoqKl9JbnNpZ2h0c18gZGUgR8OpbmVybyBlIEJlbS1Fc3RhcjoqKgoKUGFyYSBjb25jbHVpciBhIGFuw6FsaXNlIGJpdmFyaWFkYSwgZGVzdGFjYW3igJFzZSBkb2lzIGZhdG9yZXMgZGUgbmF0dXJlemEgc29jaWFsIGUgY29tcG9ydGFtZW50YWwgY29tIGltcGFjdG8gbmEgcm90YXRpdmlkYWRlOgoKMS4gKipOZXV0cmFsaWRhZGUgZGUgR8OpbmVybyoqIOKAkyBBIHRheGEgZGUgc2HDrWRhIHJldmVsYeKAkXNlIHJlbGF0aXZhbWVudGUgdW5pZm9ybWUgZW50cmUgaG9tZW5zIGUgbXVsaGVyZXMsIHNpdHVhbmRv4oCRc2UgZW50cmUgMTUlIGUgMTclLiBFc3RlIHJlc3VsdGFkbyBzdWdlcmUgYXVzw6puY2lhIGRlIGVudmllc2FtZW50b3Mgb3UgcHLDoXRpY2FzIGRpc2NyaW1pbmF0w7NyaWFzIGFzc29jaWFkYXMgYW8gZ8OpbmVybywgYmVtIGNvbW8gZXF1aWRhZGUgbmEgZXhwZXJpw6puY2lhIG9yZ2FuaXphY2lvbmFsIGVudHJlIGdydXBvcy4KCjIuICoqRXF1aWzDrWJyaW8gVmlkYeKAkVRyYWJhbGhvKiog4oCTIEEgdmFyacOhdmVsIF9Xb3Jr4oCRTGlmZSBCYWxhbmNlXyBldmlkZW5jaWEgdW0g4oCccG9udG8gY3LDrXRpY2/igJ0gbm8gbsOtdmVsIG1haXMgYmFpeG8gZGUgc2F0aXNmYcOnw6NvLiBDb2xhYm9yYWRvcmVzIHF1ZSBjbGFzc2lmaWNhbSBvIHNldSBlcXVpbMOtYnJpbyBjb21vIOKAnE1hdeKAnSAoTsOtdmVsIDEpIGFwcmVzZW50YW0gdW1hIHRheGEgZGUgcm90YXRpdmlkYWRlIHByw7N4aW1hIGRlIDMwJSwgbyBkb2JybyBkYSB2ZXJpZmljYWRhIG5vcyByZXN0YW50ZXMgbsOtdmVpcy4KQSBtZWxob3JpYSBkbyBlcXVpbMOtYnJpbyB2aWRh4oCRdHJhYmFsaG8sIG1lc21vIHF1ZSBhcGVuYXMgZGUgTsOtdmVsIDEgcGFyYSBOw612ZWwgMiwgasOhIHByb2R1eiB1bWEgcmVkdcOnw6NvIHN1YnN0YW5jaWFsIG5hIHRheGEgZGUgc2HDrWRhLiBJc3RvIGluZGljYSBxdWUgaW50ZXJ2ZW7Dp8O1ZXMgcG9udHVhaXMgZSByZWFsaXN0YXMsIGNvbW8gYWp1c3RlcyBkZSBob3LDoXJpbywgcG9sw610aWNhcyBkZSBmbGV4aWJpbGlkYWRlIG91IHJlZm9yw6dvIGRvIGFwb2lvIMOgIGVxdWlwYSwgcG9kZW0gZ2VyYXIgZWZlaXRvcyBpbWVkaWF0b3MgbmEgcmV0ZW7Dp8Ojbywgc2VtIHNlciBuZWNlc3PDoXJpbyBhdGluZ2lyIG7DrXZlaXMg4oCcaWRlYWlz4oCdIGRlIHNhdGlzZmHDp8OjbyAoTsOtdmVsIDQpLgoKKipDb25jbHVzw6NvKio6IE9zIHJlc3VsdGFkb3MgYXBvbnRhbSBwYXJhIHVtYSBjdWx0dXJhIG9yZ2FuaXphY2lvbmFsIHJlbGF0aXZhbWVudGUgZXF1aWxpYnJhZGEgZW0gdGVybW9zIGRlIGfDqW5lcm8sIG1hcyB2dWxuZXLDoXZlbCBhIGZhdG9yZXMgbGlnYWRvcyBhbyBiZW3igJFlc3RhciBlIGVxdWlsw61icmlvIHBlc3NvYWzigJFwcm9maXNzaW9uYWwuIEludmVzdGlyIGVtIHBvbMOtdGljYXMgZGUgc2HDumRlIG9jdXBhY2lvbmFsIGUgZmxleGliaWxpZGFkZSBsYWJvcmFsIHBvZGVyw6EgdGVyIHVtIHJldG9ybm8gZGlyZXRvIG5hIHNhdGlzZmHDp8OjbyBlIGZpZGVsaXphw6fDo28gZG9zIGNvbGFib3JhZG9yZXMuCiAgICAKIyBBbsOhbGlzZSBNdWx0aXZhcmlhZGEgKENvcnJlbGHDp8O1ZXMpCk5lc3RhIGV0YXBhLCBmb2kgYW5hbGlzYWRhIGEgcmVsYcOnw6NvIGVudHJlIGFzIHZhcmnDoXZlaXMgbnVtw6lyaWNhcyBwYXJhIGlkZW50aWZpY2FyIG11bHRpY29saW5lYXJpZGFkZSAocmVkdW5kw6JuY2lhKS4gRm9pIHV0aWxpemFkYSB1bWEgbWF0cml6IGRlIGNvcnJlbGHDp8OjbyB2aXN1YWwuCmBgYHtyfQoKaWJtX251bWVyaWMgPC0gaWJtX2NsZWFuICU+JSBzZWxlY3Qod2hlcmUoaXMubnVtZXJpYykpCm1hdHJpel9jb3IgIDwtIGNvcihpYm1fbnVtZXJpYywgdXNlID0gImNvbXBsZXRlLm9icyIpCgojIEdyw6FmaWNvIGRlIGNvcnJlbGHDp8O1ZXMKY29sX3BhbGV0YSA8LSBjb2xvclJhbXBQYWxldHRlKGMoIiNFNzRDM0MiLCAiI0ZGRkZGRiIsICIjMkMzRTUwIikpKDIwMCkKCmNvcnJwbG90KG1hdHJpel9jb3IsIAogICAgICAgICBtZXRob2QgPSAiY29sb3IiLCAKICAgICAgICAgdHlwZSA9ICJ1cHBlciIsIAogICAgICAgICBvcmRlciA9ICJoY2x1c3QiLCAgICAgICAgIAogICAgICAgICB0bC5jb2wgPSAiYmxhY2siLCAKICAgICAgICAgdGwuY2V4ID0gMC43LCAKICAgICAgICAgY29sID0gY29sX3BhbGV0YSwgICAgICAgICAKICAgICAgICAgdGl0bGUgPSAiXG4gTWFwYSBkZSBDb3JyZWxhw6fDtWVzIEludGVydmFyacOhdmVpcyIsIAogICAgICAgICBtYXIgPSBjKDAsMCwyLDApLAogICAgICAgICBkaWFnID0gRkFMU0UpCgojIFRhYmVsYSBkZSBjb3JyZWxhw6fDtWVzCnRhYmVsYV9jb3IgPC0gYXMuZGF0YS5mcmFtZShhcy50YWJsZShtYXRyaXpfY29yKSkKCnRhYmVsYV9tZWxob3JhZGEgPC0gdGFiZWxhX2NvciAlPiUKICBmaWx0ZXIoVmFyMSAhPSBWYXIyKSAlPiUKICBmaWx0ZXIoIWR1cGxpY2F0ZWQocGFzdGUwKHBtYXgoYXMuY2hhcmFjdGVyKFZhcjEpLCBhcy5jaGFyYWN0ZXIoVmFyMikpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBtaW4oYXMuY2hhcmFjdGVyKFZhcjEpLCBhcy5jaGFyYWN0ZXIoVmFyMikpKSkpICU+JQogIGFycmFuZ2UoZGVzYyhhYnMoRnJlcSkpKSAlPiUKICByZW5hbWUoVmFyaWF2ZWxfMSA9IFZhcjEsIFZhcmlhdmVsXzIgPSBWYXIyLCBDb3JyZWxhY2FvID0gRnJlcSkKCiMgTWVsaG9yYXIgZGVzaWduIGRhIHRhYmVsYQprYWJsZShoZWFkKHRhYmVsYV9tZWxob3JhZGEsIDEwKSwgCiAgICAgIGNhcHRpb24gPSAiVG9wIDEwIENvcnJlbGHDp8O1ZXMgTWFpcyBGb3J0ZXMgSWRlbnRpZmljYWRhcyIsIAogICAgICBkaWdpdHMgPSAyLAogICAgICBjb2wubmFtZXMgPSBjKCJWYXJpw6F2ZWwgMSIsICJWYXJpw6F2ZWwgMiIsICJGb3LDp2EgZGEgQ29ycmVsYcOnw6NvIikpICU+JQogIGthYmxlX3N0eWxpbmcoCiAgICBib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG92ZXIiLCAiY29uZGVuc2VkIiksIAogICAgZnVsbF93aWR0aCA9IFQsICAgICAgICAgICAKICAgIHBvc2l0aW9uID0gImNlbnRlciIsICAgICAgCiAgICBmb250X3NpemUgPSAxNCAgICAgICAgICAgIAogICkgJT4lCiAgcm93X3NwZWMoMCwgYm9sZCA9IFQsIGNvbG9yID0gIndoaXRlIiwgYmFja2dyb3VuZCA9ICIjMmMzZTUwIikgJT4lCiAgIyBEZXN0YWNhIGVtIHZlcm1lbGhvIGFzIGNvcnJlbGHDp8O1ZXMgcXVlIHBvZGVtIGNhdXNhciBtdWx0aWNvbGluZWFyaWRhZGUgKD4wLjcpCiAgY29sdW1uX3NwZWMoMywgYm9sZCA9IFQsIAogICAgICAgICAgICAgIGNvbG9yID0gaWZlbHNlKGFicyhoZWFkKHRhYmVsYV9tZWxob3JhZGEkQ29ycmVsYWNhbywgMTApKSA+IDAuNywgIiNFNzRDM0MiLCAiYmxhY2siKSkKYGBgCioqX0luc2lnaHRzXyBkYSBBbsOhbGlzZSBkZSBDb3JyZWxhw6fDo286KioKCkEgbWF0cml6IGUgYSB0YWJlbGEgZGUgY29ycmVsYcOnw7VlcyBldmlkZW5jaWFtIHBhZHLDtWVzIGRlIG11bHRpY29saW5lYXJpZGFkZSBzaWduaWZpY2F0aXZvcywgcmV2ZWxhbmRvIHZhcmnDoXZlaXMgZm9ydGVtZW50ZSByZWR1bmRhbnRlcyBxdWUgZXhpZ2lyw6NvIHRyYXRhbWVudG8gZXNwZWPDrWZpY28gbmEgZmFzZSBkZSBwcsOp4oCRcHJvY2Vzc2FtZW50byBkb3MgZGFkb3M6CgoKMS4gKipSZWR1bmTDom5jaWEgZW50cmUgcmVtdW5lcmHDp8OjbyBlIG7DrXZlbCBoaWVyw6FycXVpY28qKjogQSBjb3JyZWxhw6fDo28gbWFpcyBlbGV2YWRhIGRlIHRvZG8gbyBjb25qdW50byDDqSBvYnNlcnZhZGEgZW50cmUgYE1vbnRobHlJbmNvbWVgIGUgYEpvYkxldmVsYCAociA9IDAuOTUpLgoKKipJbnRlcnByZXRhw6fDo28qKjogRXN0YXMgdmFyacOhdmVpcyBzw6NvLCBuYSBwcsOhdGljYSwgZXN0YXRpc3RpY2FtZW50ZSBzb2JyZXBvc3RhcywgcGVsbyBxdWUgbyBuw612ZWwgZG8gY2FyZ28gZGV0ZXJtaW5hIHF1YXNlIHRvdGFsbWVudGUgbyBzYWzDoXJpby4KTWFudGVyIGFtYmFzIG5vIG1vZGVsbyBwb2RlcsOhIGludHJvZHV6aXIgaW5zdGFiaWxpZGFkZSBub3MgY29lZmljaWVudGVzIGUgZW52aWVzYXIgYSBpbXBvcnTDom5jaWEgcHJlZGl0aXZhLiBBc3NpbSwgc2Vyw6EgcmVjb21lbmTDoXZlbCByZXRlciBhcGVuYXMgdW1hIHZhcmnDoXZlbCByZXByZXNlbnRhdGl2YSAocG9yIGV4ZW1wbG8sIGBKb2JMZXZlbGApLgoKCjIuICoqQW50aWd1aWRhZGUqKjogSWRlbnRpZmljYeKAkXNlIHVtIF9jbHVzdGVyXyBkZSB2YXJpw6F2ZWlzIHRlbXBvcmFpcyBhbHRhbWVudGUgY29ycmVsYWNpb25hZGFzLCBgWWVhcnNBdENvbXBhbnlgLCBgWWVhcnNJbkN1cnJlbnRSb2xlYCBlIGBZZWFyc1dpdGhDdXJyTWFuYWdlcmAsIGNvbSBjb3JyZWxhw6fDtWVzIGVudHJlIDAuNzEgZSAwLjc3LgoKKipJbnRlcnByZXRhw6fDo28qKjogRnVuY2lvbsOhcmlvcyBjb20gbWFpb3IgYW50aWd1aWRhZGUgdGVuZGVtIGEgcGVybWFuZWNlciBuYSBtZXNtYSBmdW7Dp8OjbyBlIHNvYiBhIG1lc21hIGxpZGVyYW7Dp2EuIENvbnbDqW0sIHBvcnRhbnRvLCBldml0YXIgaW5jbHVpciB0b2RhcyBzaW11bHRhbmVhbWVudGUsIHBvZGVuZG8gb3B0YXLigJFzZSBwb3IgYFllYXJzQXRDb21wYW55YCBvdSBwZWxhIGNyaWHDp8OjbyBkZSB1bWEgdmFyacOhdmVsIGFncmVnYWRhIGRlIOKAnGVzdGFnbmHDp8Ojb+KAnSwgcXVlIGNhcHR1cmUgZXN0YSBkaW7Dom1pY2EuCgoKMy4gKipFeHBlcmnDqm5jaWEgcHJvZmlzc2lvbmFsIGUgcmVtdW5lcmHDp8OjbyoqOiBBIHZhcmnDoXZlbCBgVG90YWxXb3JraW5nWWVhcnNgIGFwcmVzZW50YSBjb3JyZWxhw6fDo28gZm9ydGUgY29tIGBKb2JMZXZlbGAgKDAuNzgpIGUgYE1vbnRobHlJbmNvbWVgICgwLjc3KS4KCioqSW50ZXJwcmV0YcOnw6NvKio6IE8gc2lzdGVtYSBkZSBwcm9ncmVzc8OjbyBlIGNvbXBlbnNhw6fDo28gZGEgZW1wcmVzYSBhcGFyZW50YSBlc3RhciBhbHRhbWVudGUgYWxpbmhhZG8gY29tIGEgc2VuaW9yaWRhZGUsIHZhbG9yaXphbmRvIHNvYnJldHVkbyBhIGV4cGVyacOqbmNpYSBhY3VtdWxhZGEuCgoKNC4gKipEZXNlbXBlbmhvIGUgcmVjb21wZW5zYXMqKjogQSBjb3JyZWxhw6fDo28gZGUgMC43NyBlbnRyZSBgUGVyZm9ybWFuY2VSYXRpbmdgIGUgYFBlcmNlbnRTYWxhcnlIaWtlYCBjb25maXJtYSBxdWUgb3MgYXVtZW50b3Mgc2FsYXJpYWlzIGVzdMOjbyBkaXJldGFtZW50ZSBhc3NvY2lhZG9zIMOgIGF2YWxpYcOnw6NvIGRlIGRlc2VtcGVuaG8gYW51YWwg4oCUIHVtYSBwb2zDrXRpY2EgdMOtcGljYSBkZSBtZXJpdG9jcmFjaWEgb3JnYW5pemFjaW9uYWwuCgoqKkNvbmNsdXPDo28gZGEgQW7DoWxpc2UgRXhwbG9yYXTDs3JpYSAoRURBKSoqOiBBIGV4cGxvcmHDp8OjbyBiaXZhcmlhZGEgZSBjb3JyZWxhY2lvbmFsIHBlcm1pdGUgY29uY2x1aXIgcXVlIGEgcm90YXRpdmlkYWRlIGVzdMOhIGFzc29jaWFkYSBhIGZhdG9yZXMgZGVtb2dyw6FmaWNvcyBlIGxhYm9yYWlzIChpZGFkZSBqb3ZlbSwgY2FyZ29zIG9wZXJhY2lvbmFpcywgdmlhZ2VucyBmcmVxdWVudGVzLCBzYWzDoXJpb3MgbWFpcyBiYWl4b3MpLCBlbnF1YW50byBubyBwbGFubyB0w6ljbmljbyBkZXN0YWNhbeKAkXNlIHJlbGHDp8O1ZXMgcmVkdW5kYW50ZXMgZW50cmUgdmFyacOhdmVpcyBkZSBoaWVyYXJxdWlhLCBhbnRpZ3VpZGFkZSBlIHJlbXVuZXJhw6fDo28uCgpFc3RhcyBjb25zdGF0YcOnw7VlcyBjb25zdGl0dWVtIG8gcG9udG8gZGUgcGFydGlkYSBwYXJhIG8gcHLDqeKAkXByb2Nlc3NhbWVudG8gZGUgZGFkb3MsIG9uZGUgc2Vyw6NvIHRyYXRhZGFzIGFzIGNvcnJlbGHDp8O1ZXMgZXhjZXNzaXZhcyBlIHNlbGVjaW9uYWRhcyBhcyB2YXJpw6F2ZWlzIG1haXMgcmVsZXZhbnRlcyBwYXJhIG9zIG1vZGVsb3MgcHJlZGl0aXZvcy4KCiMgUHLDqS1wcm9jZXNzYW1lbnRvIGRlIGRhZG9zCiMjIFNlbGXDp8OjbyBkZSB2YXJpw6F2ZWlzIChGZWF0dXJlIFNlbGVjdGlvbikKYGBge3J9CiMgRXhlY3V0YXIgYSBTZWxlw6fDo28KaWJtX3ByZXAgPC0gaWJtX2NsZWFuICU+JQogIHNlbGVjdCgtam9iX2xldmVsKSAlPiUgIAogIHNlbGVjdCgtYW55X29mKGMoImVtcGxveWVlX251bWJlciIsICJlbXBsb3llZV9jb3VudCIsICJvdmVyMTgiLCAic3RhbmRhcmRfaG91cnMiKSkpICU+JQogIG11dGF0ZShhdHRyaXRpb24gPSBpZmVsc2UoYXR0cml0aW9uID09ICJZZXMiLCAxLCAwKSkKCiMgQ3JpYXIgVGFiZWxhIGRlIEltcGFjdG8KcmVzdW1vX3ByZXAgPC0gZGF0YS5mcmFtZSgKICBFdGFwYSA9IGMoIkNvbHVuYXMgT3JpZ2luYWlzIiwgIkNvbHVuYXMgUmVtb3ZpZGFzIiwgIlRvdGFsIEZpbmFsIiwgIlRhcmdldCAoQXR0cml0aW9uKSIpLAogIFZhbG9yID0gYyhuY29sKGlibV9jbGVhbiksIAogICAgICAgICAgICBuY29sKGlibV9jbGVhbikgLSBuY29sKGlibV9wcmVwKSwgCiAgICAgICAgICAgIG5jb2woaWJtX3ByZXApLCAKICAgICAgICAgICAgIkNvbnZlcnRpZG8gcGFyYSBCaW7DoXJpbyAoMC8xKSIpCikKCnJlc3Vtb19wcmVwICU+JQogIGthYmxlKGNhcHRpb24gPSAiUmVzdW1vIGRvIFByw6ktcHJvY2Vzc2FtZW50byBlIEZlYXR1cmUgU2VsZWN0aW9uIikgJT4lCiAga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG92ZXIiLCAiY29uZGVuc2VkIiksIGZ1bGxfd2lkdGggPSBGKSAlPiUKICByb3dfc3BlYygwLCBib2xkID0gVCwgY29sb3IgPSAid2hpdGUiLCBiYWNrZ3JvdW5kID0gIiMyYzNlNTAiKQpgYGAKQXDDs3MgYSBmYXNlIGRlIGFuw6FsaXNlIGV4cGxvcmF0w7NyaWEsIHByb2NlZGV14oCRc2Ugw6AgcHJlcGFyYcOnw6NvIGRvcyBkYWRvcyBwYXJhIGEgbW9kZWxhw6fDo28gcHJlZGl0aXZhLgoKRXN0YSBldGFwYSDDqSBmdW5kYW1lbnRhbCBwYXJhIGdhcmFudGlyIHF1ZSBvIG1vZGVsbyByZXN1bHRhbnRlIG7Do28gc2VqYSBpbmZsdWVuY2lhZG8gcG9yIHJ1w61kbyBlc3RhdMOtc3RpY28gbmVtIHBvciBpbmZvcm1hw6fDo28gcmVkdW5kYW50ZSwgYXNzZWd1cmFuZG8gYSByb2J1c3RleiBlIGludGVycHJldGFiaWxpZGFkZSBkb3MgcmVzdWx0YWRvcy4KClByaW5jaXBhaXMgZGVjaXPDtWVzIG5lc3RhIGZhc2U6CgoxLiAqKkVsaW1pbmHDp8OjbyBkZSByZWR1bmTDom5jaWEgKG11bHRpY29saW5lYXJpZGFkZSkqKiDigJMgQ29uZm9ybWUgaWRlbnRpZmljYWRvIG5hIG1hdHJpeiBkZSBjb3JyZWxhw6fDtWVzLCBhcyB2YXJpw6F2ZWlzIGBtb250aGx5X2luY29tZWAgZSBgam9iX2xldmVsYCBhcHJlc2VudGF2YW0gdW1hIGNvcnJlbGHDp8OjbyBkZSAwLDk1LiBQYXJhIGV2aXRhciBzb2JyZWFqdXN0ZSAoX292ZXJmaXR0aW5nXykgZSBzaW1wbGlmaWNhciBvIG1vZGVsbywgZGVjaWRpdeKAkXNlIG1hbnRlciBhcGVuYXMgYSB2YXJpw6F2ZWwgbWFpcyByZXByZXNlbnRhdGl2YSwgcHJpdmlsZWdpYW5kbyBvIGltcGFjdG8gZmluYW5jZWlybyBkaXJldG8uCgoyLiAqKkNvbnZlcnPDo28gZGEgdmFyacOhdmVs4oCRYWx2byoqIOKAkyBBIHZhcmnDoXZlbCBgYXR0cml0aW9uYCBmb2kgdHJhbnNmb3JtYWRhIHBhcmEgZm9ybWF0byBiaW7DoXJpbyAoMC8xKSwgZGUgbW9kbyBhIHBlcm1pdGlyIGEgYXBsaWNhw6fDo28gZGUgbW9kZWxvcyBkZSBjbGFzc2lmaWNhw6fDo28gc3VwZXJ2aXNpb25hZGEgZSBmYWNpbGl0YXIgYSBhbsOhbGlzZSBkZSBkZXNlbXBlbmhvIHByZWRpdGl2by4KCkVzdGFzIG9wZXJhw6fDtWVzIGFzc2VndXJhbSBxdWUgbyBjb25qdW50byBkZSBkYWRvcyBmaW5hbCBlc3RlamEgZXN0YXRpc3RpY2FtZW50ZSBlcXVpbGlicmFkbywgY29tcHV0YWNpb25hbG1lbnRlIGVmaWNpZW50ZSBlIGFkZXF1YWRvIMOgIGZhc2Ugc2VndWludGUgZGUgbW9kZWxhw6fDo28uCgojIyBDcmlhw6fDo28gZGUgRHVtbWllcwpgYGB7cn0KbGlicmFyeShmYXN0RHVtbWllcykKCmlibV9maW5hbCA8LSBkdW1teV9jb2xzKGlibV9wcmVwLCAKICAgICAgICAgICAgICAgICAgICAgICAgcmVtb3ZlX2ZpcnN0X2R1bW15ID0gVFJVRSwgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgcmVtb3ZlX3NlbGVjdGVkX2NvbHVtbnMgPSBUUlVFKSAlPiUKICAgICAgICAgICAgIGNsZWFuX25hbWVzKCkgIyBHYXJhbnRlIHF1ZSBvcyBub21lcyBkYXMgbm92YXMgY29sdW5hcyBmaWNhbSBwYWRyb25pemFkb3MKCiMgQ3JpYXIgdW1hIGNvbXBhcmHDp8OjbyB2aXN1YWwKY29tcGFyYXRpdm9fZGltIDwtIGRhdGEuZnJhbWUoCiAgTWV0cmljYSA9IGMoIkNvbHVuYXMgUHLDqS1EdW1taWVzIiwgIkNvbHVuYXMgUMOzcy1EdW1taWVzIChFeHBhbmRpZGFzKSIsICJOb3ZhcyBWYXJpw6F2ZWlzIENyaWFkYXMiKSwKICBRdWFudGlkYWRlID0gYyhuY29sKGlibV9wcmVwKSwgbmNvbChpYm1fZmluYWwpLCBuY29sKGlibV9maW5hbCkgLSBuY29sKGlibV9wcmVwKSkKKQoKIyBFeGliaXIgVGFiZWxhIGRlIEltcGFjdG8KY29tcGFyYXRpdm9fZGltICU+JQogIGthYmxlKGNhcHRpb24gPSAiSW1wYWN0byBkYSBUcmFuc2Zvcm1hw6fDo28gZGUgVmFyacOhdmVpcyBDYXRlZ8OzcmljYXMgKE9uZS1Ib3QgRW5jb2RpbmcpIikgJT4lCiAga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG92ZXIiLCAiY29uZGVuc2VkIiksIGZ1bGxfd2lkdGggPSBGKSAlPiUKICByb3dfc3BlYygwLCBib2xkID0gVCwgY29sb3IgPSAid2hpdGUiLCBiYWNrZ3JvdW5kID0gIiMyYzNlNTAiKQoKIyBNb3N0cmFyIGFzIG5vdmFzIGNvbHVuYXMgCmRhdGEuZnJhbWUoRXhlbXBsb3NfTm92YXNfQ29sdW5hcyA9IGNvbG5hbWVzKGlibV9maW5hbClbKG5jb2woaWJtX3ByZXApKzEpOihuY29sKGlibV9wcmVwKSs2KV0pICU+JQogIGthYmxlKCkgJT4lCiAga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9ICJib3JkZXJlZCIsIGZ1bGxfd2lkdGggPSBGLCBwb3NpdGlvbiA9ICJmbG9hdF9yaWdodCIpCmBgYApBIG1haW9yaWEgZG9zIGFsZ29yaXRtb3MgZGUgTWFjaGluZSBMZWFybmluZyBuw6NvIMOpIGNhcGF6IGRlIHByb2Nlc3NhciBkaXJldGFtZW50ZSB2YXJpw6F2ZWlzIGRlIHRleHRvLgoKUGFyYSB1bHRyYXBhc3NhciBlc3RhIGxpbWl0YcOnw6NvLCBhcGxpY2914oCRc2UgYSB0w6ljbmljYSBkZSBPbmXigJFIb3QgRW5jb2RpbmcsIHRhbWLDqW0gY29uaGVjaWRhIHBvciBjcmlhw6fDo28gZGUgdmFyacOhdmVpcyBkdW1teS4KClByb2NlZGltZW50b3MgcmVhbGl6YWRvczoKCjEuICoqVHJhbnNmb3JtYcOnw6NvIGRlIHZhcmnDoXZlaXMgY2F0ZWfDs3JpY2FzKiog4oCTIFZhcmnDoXZlaXMgcXVhbGl0YXRpdmFzLCBjb21vIGBCdXNpbmVzc1RyYXZlbGAgb3UgYERlcGFydG1lbnRgLCBmb3JhbSBjb252ZXJ0aWRhcyBlbSBtw7psdGlwbGFzIGNvbHVuYXMgYmluw6FyaWFzICgwLzEpLCByZXByZXNlbnRhbmRvIGEgcHJlc2Vuw6dhIG91IGF1c8OqbmNpYSBkZSBjYWRhIGNhdGVnb3JpYSBkaXN0aW50YS4KCjIuICoqUHJldmVuw6fDo28gZGUgbXVsdGljb2xpbmVhcmlkYWRlKiog4oCTIFBhcmEgZXZpdGFyIGEgY2hhbWFkYSBfZHVtbXkgdmFyaWFibGUgdHJhcF8sIGZvaSBhdGl2YWRvIG8gcGFyw6JtZXRybyBgcmVtb3ZlX2ZpcnN0X2R1bW15ID0gVFJVRWAsIG8gcXVlIHJlbW92ZSB1bWEgY2F0ZWdvcmlhIGRlIGNhZGEgZ3J1cG8uIEFzc2ltLCBwb3IgZXhlbXBsbywgbm8gY2FzbyBkZSB1bWEgdmFyacOhdmVsIGNvbSBhcyBtb2RhbGlkYWRlcyBNYXNjdWxpbm8gZSBGZW1pbmlubywgYXBlbmFzIHVtYSBkZWxhcyDDqSBtYW50aWRhLCBkYWRvIHF1ZSBhIGF1c8OqbmNpYSBkZSB1bWEgaW1wbGljYSBhIHByZXNlbsOnYSBkYSBvdXRyYS4KCjMuICoqRXhwYW5zw6NvIGNvbnRyb2xhZGEgZG8gX2RhdGFzZXRfKiog4oCTIEFww7NzIG8gcHJvY2Vzc28sIG8gbsO6bWVybyB0b3RhbCBkZSB2YXJpw6F2ZWlzIGF1bWVudG91IGRlIDMwIHBhcmEgNDQsIHJlc3VsdGFuZG8gbmEgY3JpYcOnw6NvIGRlIDE0IG5vdmFzIHZhcmnDoXZlaXMgZGVyaXZhZGFzLgoKRXN0YSBleHBhbnPDo28gcGVybWl0ZSByZXByZXNlbnRhciBkZSBmb3JtYSBtYWlzIHJpY2EgYSBpbmZvcm1hw6fDo28gcXVhbGl0YXRpdmEsIHNlbSBpbnRyb2R1emlyIHJlZHVuZMOibmNpYSBvdSBjb21wcm9tZXRlciBhIGVzdGFiaWxpZGFkZSBkb3MgbW9kZWxvcyBwcmVkaXRpdm9zLgoKIyMgRGl2aXPDo28gZG9zIERhZG9zIChUcmVpbm8gZSBUZXN0ZSkKYGBge3IgZGl2aXNhb19kYWRvcywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbGlicmFyeShjYVRvb2xzKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KGthYmxlRXh0cmEpCgojIERpdmlzw6NvIEVzdHJhdGlmaWNhZGEgCnNldC5zZWVkKDEyMykKc3BsaXQgPC0gc2FtcGxlLnNwbGl0KGlibV9maW5hbCRhdHRyaXRpb24sIFNwbGl0UmF0aW8gPSAwLjcwKQoKZGFkb3NfdHJlaW5vIDwtIHN1YnNldChpYm1fZmluYWwsIHNwbGl0ID09IFRSVUUpCmRhZG9zX3Rlc3RlICA8LSBzdWJzZXQoaWJtX2ZpbmFsLCBzcGxpdCA9PSBGQUxTRSkKCiMgQ3JpYXIgVGFiZWxhIGRlIFJlc3VtbyAKcmVzdW1vX3NwbGl0IDwtIGRhdGEuZnJhbWUoCiAgQ29uanVudG8gPSBjKCJUcmVpbm8gKDcwJSkiLCAiVGVzdGUgKDMwJSkiLCAiVG90YWwiKSwKICBPYnNlcnZhw6fDtWVzID0gYyhucm93KGRhZG9zX3RyZWlubyksIG5yb3coZGFkb3NfdGVzdGUpLCBucm93KGlibV9maW5hbCkpLAogIFRheGFfQ2h1cm4gPSBjKAogICAgcGFzdGUwKHJvdW5kKG1lYW4oZGFkb3NfdHJlaW5vJGF0dHJpdGlvbikgKiAxMDAsIDEpLCAiJSIpLAogICAgcGFzdGUwKHJvdW5kKG1lYW4oZGFkb3NfdGVzdGUkYXR0cml0aW9uKSAqIDEwMCwgMSksICIlIiksCiAgICBwYXN0ZTAocm91bmQobWVhbihpYm1fZmluYWwkYXR0cml0aW9uKSAqIDEwMCwgMSksICIlIikKICApCikKCiMgRXhpYmlyIFRhYmVsYSAKcmVzdW1vX3NwbGl0ICU+JQogIGthYmxlKGNhcHRpb24gPSAiRGl2aXPDo28gZGUgRGFkb3M6IFZlcmlmaWNhw6fDo28gZGUgQ29uc2lzdMOqbmNpYSBlIEVzdHJhdGlmaWNhw6fDo28iKSAlPiUKICBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJob3ZlciIsICJjb25kZW5zZWQiKSwgCiAgICAgICAgICAgICAgICBmdWxsX3dpZHRoID0gRiwgCiAgICAgICAgICAgICAgICBwb3NpdGlvbiA9ICJjZW50ZXIiKSAlPiUKICByb3dfc3BlYygwLCBib2xkID0gVCwgY29sb3IgPSAid2hpdGUiLCBiYWNrZ3JvdW5kID0gIiMyYzNlNTAiKSAlPiUKICBjb2x1bW5fc3BlYygzLCBib2xkID0gVCwgY29sb3IgPSAiI0U3NEMzQyIpIApgYGAKQSBkaXZpc8OjbyBkbyBjb25qdW50byBkZSBkYWRvcyBmb2kgZWZldHVhZGEgYXRyYXbDqXMgZGUgdW1hICoqYW1vc3RyYWdlbSBlc3RyYXRpZmljYWRhKiosIGFzc2VndXJhbmRvIHF1ZSBhIHByb3BvcsOnw6NvIGRhIHZhcmnDoXZlbOKAkWFsdm8gKGBBdHRyaXRpb25gKSBmb3NzZSBtYW50aWRhIGVtIGFtYm9zIG9zIHN1YmNvbmp1bnRvcyAoVHJlaW5vICg3MCUpIGUgVGVzdGUgKDMwJSkpLgoKQ29uZm9ybWUgaWx1c3RyYWRvIG5hIHRhYmVsYSwgYSAqKnRheGEgZGUgY2h1cm4qKiBwZXJtYW5lY2Ugcmlnb3Jvc2FtZW50ZSBjb25zdGFudGUgZW0gKioxNiwxJSoqIGVtIGFtYm9zIG9zIGNvbmp1bnRvcy4gRXN0YSBjb25zaXN0w6puY2lhIGVzdGF0w61zdGljYSDDqSBlc3NlbmNpYWwgcGFyYSBldml0YXIgZGlzdG9yw6fDtWVzIG5hIGFtb3N0cmFnZW0sIGdhcmFudGluZG8gcXVlIGEgYW1vc3RyYSBkZSB0ZXN0ZSBmdW5jaW9uZSBjb21vIHVtYSByw6lwbGljYSByZXByZXNlbnRhdGl2YSBkbyBfZGF0YXNldF8gb3JpZ2luYWwuCgpEZXN0ZSBtb2RvLCBhcyBtw6l0cmljYXMgZGUgZGVzZW1wZW5obyBvYnRpZGFzIGR1cmFudGUgYSBmYXNlIGRlIHZhbGlkYcOnw6NvIHJlZmxldGVtIGRlIGZvcm1hIHJlYWxpc3RhIGUgZmnDoXZlbCBvIGNvbXBvcnRhbWVudG8gZG8gZmVuw7NtZW5vIGRlIHJvdGF0aXZpZGFkZSBuYSBvcmdhbml6YcOnw6NvLCBhdW1lbnRhbmRvIGEgY3JlZGliaWxpZGFkZSBlIGdlbmVyYWxpemHDp8OjbyBkb3MgcmVzdWx0YWRvcyBkbyBtb2RlbG8uCgojIyBFcXVpbMOtYnJpbyBkZSBDbGFzc2VzCmBgYHtyfQpsaWJyYXJ5KFJPU0UpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShncmlkRXh0cmEpCgojIEFwbGljYXIgbyBST1NFIHBhcmEgZXF1aWxpYnJhciBhcGVuYXMgbyBjb25qdW50byBkZSBUUkVJTk8Kc2V0LnNlZWQoMTIzKQpkYWRvc190cmVpbm9fYmFsIDwtIFJPU0UoYXR0cml0aW9uIH4gLiwgZGF0YSA9IGRhZG9zX3RyZWlubywgc2VlZCA9IDEyMykkZGF0YQoKIyBDcmlhciBkYWRvcyBwYXJhIG8gZ3LDoWZpY28gY29tcGFyYXRpdm8KYW50ZXMgPC0gYXMuZGF0YS5mcmFtZSh0YWJsZShkYWRvc190cmVpbm8kYXR0cml0aW9uKSkKYW50ZXMkRXN0YWRvIDwtICIxLiBBbnRlcyAoRGVzZXF1aWxpYnJhZG8pIgoKZGVwb2lzIDwtIGFzLmRhdGEuZnJhbWUodGFibGUoZGFkb3NfdHJlaW5vX2JhbCRhdHRyaXRpb24pKQpkZXBvaXMkRXN0YWRvIDwtICIyLiBEZXBvaXMgKEVxdWlsaWJyYWRvIGNvbSBST1NFKSIKCmNvbXBhcmF0aXZvIDwtIHJiaW5kKGFudGVzLCBkZXBvaXMpCgojIEdyw6FmaWNvIApnZ3Bsb3QoY29tcGFyYXRpdm8sIGFlcyh4ID0gVmFyMSwgeSA9IEZyZXEsIGZpbGwgPSBWYXIxKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCB3aWR0aCA9IDAuNiwgYWxwaGEgPSAwLjkpICsKICBmYWNldF93cmFwKH5Fc3RhZG8pICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIwIiA9ICIjMkMzRTUwIiwgIjEiID0gIiNFNzRDM0MiKSkgKwogIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKDAsMCksIGxpbWl0cyA9IGMoMCwgbWF4KGNvbXBhcmF0aXZvJEZyZXEpKjEuMSkpICsKICBsYWJzKAogICAgdGl0bGUgPSAiRXN0cmF0w6lnaWEgZGUgUmViYWxhbmNlYW1lbnRvIGRlIERhZG9zIChST1NFKSIsCiAgICBzdWJ0aXRsZSA9ICJBanVzdGUgZGEgY2xhc3NlIG1pbm9yaXTDoXJpYSBwYXJhIG90aW1pemFyIGEgYXByZW5kaXphZ2VtIGRvIG1vZGVsbyIsCiAgICB4ID0gIlN0YXR1cyBkZSBTYcOtZGEgKDAgPSBOw6NvLCAxID0gU2ltKSIsCiAgICB5ID0gIk7Dum1lcm8gZGUgUmVnaXN0b3MiCiAgKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICB0aGVtZSgKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDE0LCBjb2xvciA9ICIjMmMzZTUwIiksCiAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxMSksCiAgICBwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2JsYW5rKCkKICApCmBgYApBIGVmaWPDoWNpYSBkZSB1bSBtb2RlbG8gcHJlZGl0aXZvIGRlcGVuZGUgZGEgcXVhbGlkYWRlIGUgZG8gZXF1aWzDrWJyaW8gZXN0YXTDrXN0aWNvIGRvcyBkYWRvcyBkZSB0cmVpbm8uCgpDb25mb3JtZSBpZGVudGlmaWNhZG8gYW50ZXJpb3JtZW50ZSwgYSB2YXJpw6F2ZWzigJFhbHZvIChgQXR0cml0aW9uYCkgYXByZXNlbnRhIHVtICoqZGVzZXF1aWzDrWJyaW8gYWNlbnR1YWRvKiosIGNvbSBhcGVuYXMgKioxNiwxJSBkZSBjYXNvcyBwb3NpdGl2b3MqKiAoY29sYWJvcmFkb3JlcyBxdWUgc2HDrXJhbSBkYSBlbXByZXNhKS4KRW0gY29udGV4dG9zIHJlYWlzLCBlc3RlIHRpcG8gZGUgYXNzaW1ldHJpYSB0ZW5kZSBhIGxldmFyIG8gbW9kZWxvIGEgcHJpdmlsZWdpYXIgYSBwcmV2aXPDo28gZGUgcGVybWFuw6puY2lhIGUgYSBzdWJlc3RpbWFyIG9zIHBhZHLDtWVzIGRlIHNhw61kYS4KClBhcmEgbWl0aWdhciBlc3RlIHByb2JsZW1hLCBhcGxpY2914oCRc2UgbyAqKmFsZ29yaXRtbyBST1NFKiogKFJhbmRvbSBPdmVy4oCRU2FtcGxpbmcgRXhhbXBsZXMpIGV4Y2x1c2l2YW1lbnRlIGFvIGNvbmp1bnRvIGRlIHRyZWluby4KRXN0YSB0w6ljbmljYSBnZXJhICoqb2JzZXJ2YcOnw7VlcyBzaW50w6l0aWNhcyBiYXNlYWRhcyBuYSBkaXN0cmlidWnDp8OjbyBkYSBjbGFzc2UgbWlub3JpdMOhcmlhKiosIG1hbnRlbmRvIGEgY29lcsOqbmNpYSBlc3RhdMOtc3RpY2EgZG8gX2RhdGFzZXRfIG9yaWdpbmFsLgoKKipQcmluY2lwYWlzIGJlbmVmw61jaW9zIGRvIHJlZXF1aWzDrWJyaW8qKjoKCiogKipOaXZlbGFtZW50byBkYSBhcHJlbmRpemFnZW0qKiDigJMgTyBtb2RlbG8gcGFzc2EgYSBzZXIgZXhwb3N0byBhIHVtYSBwcm9wb3LDp8OjbyBlcXVpbGlicmFkYSAoYXByb3hpbWFkYW1lbnRlIDUwLzUwKSBlbnRyZSBjb2xhYm9yYWRvcmVzIHF1ZSBzYWVtIGUgcXVlIHBlcm1hbmVjZW0sIG8gcXVlIG1lbGhvcmEgYSBzdWEgY2FwYWNpZGFkZSBkZSBnZW5lcmFsaXphw6fDo28uCgoqICoqTWVsaG9yaWEgZGEgc2Vuc2liaWxpZGFkZSoqIChfcmVjYWxsXykg4oCTIEF1bWVudGHigJFzZSBhIGNhcGFjaWRhZGUgZG8gbW9kZWxvIGRlIGRldGV0YXIgY29ycmV0YW1lbnRlIG9zIGNhc29zIGRlIHNhw61kYSwgcGVybWl0aW5kbyB1bWEgaWRlbnRpZmljYcOnw6NvIHByZWNvY2UgZGUgcG90ZW5jaWFpcyBwZXJkYXMgZGUgdGFsZW50by4KCiogKipQcmVzZXJ2YcOnw6NvIGRhIGludGVncmlkYWRlIGRvIHRlc3RlKiog4oCTIE8gcmVlcXVpbMOtYnJpbyBmb2kgYXBsaWNhZG8gYXBlbmFzIGFvcyBkYWRvcyBkZSB0cmVpbm8sIG1hbnRlbmRvIG8gY29uanVudG8gZGUgdGVzdGUgaW5hbHRlcmFkby4KCiMgTWFjaGluZSBMZWFybmluZwojIyBNb2RlbG8gMTogUmVncmVzc8OjbyBMb2fDrXN0aWNhCmBgYHtyfQojIFRyZWluYXIgbyBNb2RlbG8KbW9kZWxvX2xvZ2lzdGljbyA8LSBnbG0oYXR0cml0aW9uIH4gLiwgZGF0YSA9IGRhZG9zX3RyZWlub19iYWwsIGZhbWlseSA9ICJiaW5vbWlhbCIpCgojIEZhemVyIFByZXZpc8O1ZXMKcHJldmlzb2VzX3Byb2IgPC0gcHJlZGljdChtb2RlbG9fbG9naXN0aWNvLCBuZXdkYXRhID0gZGFkb3NfdGVzdGUsIHR5cGUgPSAicmVzcG9uc2UiKQpwcmV2aXNvZXNfY2xhc3NlIDwtIGlmZWxzZShwcmV2aXNvZXNfcHJvYiA+IDAuNTAsIDEsIDApCgojIENyaWFyIE1hdHJpeiBkZSBDb25mdXPDo28gCnRhYmVsYV9jb25mdXNhbyA8LSB0YWJsZShSZWFsaWRhZGUgPSBkYWRvc190ZXN0ZSRhdHRyaXRpb24sIFByZXZpc2FvID0gcHJldmlzb2VzX2NsYXNzZSkKZGZfY29uZnVzYW8gPC0gYXMuZGF0YS5mcmFtZSh0YWJlbGFfY29uZnVzYW8pCgojIEdyw6FmaWNvIGRlIE1hdHJpeiBkZSBDb25mdXPDo28gKEhlYXRtYXApCmxpYnJhcnkoZ2dwbG90MikKZ2dwbG90KGRmX2NvbmZ1c2FvLCBhZXMoeCA9IFByZXZpc2FvLCB5ID0gUmVhbGlkYWRlLCBmaWxsID0gRnJlcSkpICsKICBnZW9tX3RpbGUoY29sb3IgPSAid2hpdGUiKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IEZyZXEpLCBjb2xvciA9ICJ3aGl0ZSIsIHNpemUgPSA4LCBmb250ZmFjZSA9ICJib2xkIikgKwogIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93ID0gIiMzNDQ5NUUiLCBoaWdoID0gIiNFNzRDM0MiKSArCiAgbGFicyh0aXRsZSA9ICJNYXRyaXogZGUgQ29uZnVzw6NvOiBSZWdyZXNzw6NvIExvZ8Otc3RpY2EiLAogICAgICAgc3VidGl0bGUgPSAiVmlzdWFsaXphw6fDo28gZGUgQWNlcnRvcyBlIEVycm9zIGRlIFByZXZpc8OjbyIsCiAgICAgICB4ID0gIlByZXZpc8OjbyBkbyBNb2RlbG8gKDA9RmljYSwgMT1TYWkpIiwKICAgICAgIHkgPSAiUmVhbGlkYWRlICgwPUZpY2EsIDE9U2FpKSIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxNiksCiAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiKSkKCiMgVGFiZWxhIGRlIE3DqXRyaWNhcyAKYWN1cmFjaWEgPC0gc3VtKGRpYWcodGFiZWxhX2NvbmZ1c2FvKSkgLyBzdW0odGFiZWxhX2NvbmZ1c2FvKQpzZW5zaWJpbGlkYWRlIDwtIHRhYmVsYV9jb25mdXNhb1syLDJdIC8gc3VtKHRhYmVsYV9jb25mdXNhb1syLF0pCgptZXRyaWNhcyA8LSBkYXRhLmZyYW1lKAogIE3DqXRyaWNhID0gYygiQWN1csOhY2lhIFRvdGFsIiwgIlNlbnNpYmlsaWRhZGUgKFJlY2FsbCkiKSwKICBSZXN1bHRhZG8gPSBjKHBhc3RlMChyb3VuZChhY3VyYWNpYSAqIDEwMCwgMiksICIlIiksIAogICAgICAgICAgICAgICAgcGFzdGUwKHJvdW5kKHNlbnNpYmlsaWRhZGUgKiAxMDAsIDIpLCAiJSIpKQopCgpsaWJyYXJ5KGthYmxlRXh0cmEpCm1ldHJpY2FzICU+JQogIGthYmxlKGNhcHRpb24gPSAiUGVyZm9ybWFuY2UgZG8gTW9kZWxvIDEiKSAlPiUKICBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJob3ZlciIpLCBmdWxsX3dpZHRoID0gRikgJT4lCiAgcm93X3NwZWMoMCwgYm9sZCA9IFQsIGNvbG9yID0gIndoaXRlIiwgYmFja2dyb3VuZCA9ICIjMmMzZTUwIikKYGBgCioqQW7DoWxpc2UgZGUgRGVzZW1wZW5obyBkbyBNb2RlbG8gMSAoUmVncmVzc8OjbyBMb2fDrXN0aWNhKToqKgoKTyBwcmltZWlybyBtb2RlbG8gZm9pIHRyZWluYWRvIGNvbSBvICoqY29uanVudG8gZGUgZGFkb3MgZXF1aWxpYnJhZG8qKiBvYnRpZG8gYXRyYXbDqXMgZGEgdMOpY25pY2EgUk9TRSwgYXByZXNlbnRhbmRvIHVtYSAqKmFjdXLDoWNpYSB0b3RhbCBkZSA3Miw3OSUqKi5FbWJvcmEgZXN0YSBtw6l0cmljYSBzZWphIHNhdGlzZmF0w7NyaWEsIGEgYWN1csOhY2lhIGlzb2xhZGEgbsOjbyDDqSBzdWZpY2llbnRlIHBhcmEgYXZhbGlhciBvIGRlc2VtcGVuaG8gbnVtIHByb2JsZW1hIGRlIHJldGVuw6fDo28gZGUgdGFsZW50b3MsIGVtIHF1ZSBvIGN1c3RvIGRlIHByZXZlciBpbmNvcnJldGFtZW50ZSB1bWEgc2HDrWRhIMOpIHBhcnRpY3VsYXJtZW50ZSBlbGV2YWRvLgoKQSBzZWd1aXIgYXByZXNlbnRhbeKAkXNlIG9zIHByaW5jaXBhaXMgcmVzdWx0YWRvcyBvYnRpZG9zIHNvYnJlIG8gKipjb25qdW50byBkZSB0ZXN0ZSAoNDQxIGNvbGFib3JhZG9yZXMpKio6CgoxLiAqKkNhcGFjaWRhZGUgZGUgZGV0ZcOnw6NvIChSZWNhbGwpOiA3MywyJSoqCgpObyBjb25qdW50byBkZSB0ZXN0ZSwgZXhpc3RpYW0gNzEgY29sYWJvcmFkb3JlcyBxdWUgZWZldGl2YW1lbnRlIHNhw61yYW0gZGEgZW1wcmVzYS4gTyBtb2RlbG8gaWRlbnRpZmljb3UgY29ycmV0YW1lbnRlIDUyIGRlc3NlcyA3MSBjYXNvcy4gTyBhbGdvcml0bW8gcmV2ZWxhIHVtYSBib2EgY2FwYWNpZGFkZSBkZSBkZXRlw6fDo28sIGNvbnNlZ3VpbmRvIHNpbmFsaXphciBhcHJveGltYWRhbWVudGUgMyBlbSBjYWRhIDQgZnVuY2lvbsOhcmlvcyBlbSByaXNjbyBkZSBzYcOtZGEuCkVzdGUgw6kgbyBwcmluY2lwYWwgcG9udG8gZm9ydGUgZG8gbW9kZWxvLCBwb2lzIGFzc2VndXJhIHF1ZSBhIG1haW9yaWEgZG9zIGNhc29zIGNyw610aWNvcyDDqSBhbnRlY2lwYWRhIGUgcG9kZSBzZXIgYWx2byBkZSBhw6fDtWVzIHByZXZlbnRpdmFzIHBvciBwYXJ0ZSBkb3MgUmVjdXJzb3MgSHVtYW5vcy4KCjIuICoqQ3VzdG8gZG9zIGZhbHNvcyBhbGFybWVzIChQcmVjaXPDo286IH4zNCUpKioKClBhcmEgbWF4aW1pemFyIGEgZGV0ZcOnw6NvIGRhcyBzYcOtZGFzLCBvIG1vZGVsbyB0b3Jub3XigJFzZSBtYWlzIHNlbnPDrXZlbCwgbyBxdWUgcmVzdWx0b3UgbnVtIGF1bWVudG8gZG9zIGZhbHNvcyBwb3NpdGl2b3MuIApGb3JhbSAxNTMgY29sYWJvcmFkb3JlcyBzaW5hbGl6YWRvcyBjb21vIHBvdGVuY2lhaXMgc2HDrWRhcywgbWFzIGFwZW5hcyA1MiByZWFsbWVudGUgZGVpeGFyYW0gYSBlbXByZXNhLgpPIG1vZGVsbyBnZXJhIHVtIHZvbHVtZSBjb25zaWRlcsOhdmVsIGRlIGFsZXJ0YXMgaW5kZXZpZG9zLCBlbSBxdWUgY2VyY2EgZGUgMiBlbSBjYWRhIDMgZnVuY2lvbsOhcmlvcyBzaW5hbGl6YWRvcyBwZXJtYW5lY2VyYW0gbmEgZW1wcmVzYS4KQXBlc2FyIGRlIGVmaWNheiBhIGFudGVjaXBhciBzYcOtZGFzIHJlYWlzLCBvIHNldSBmdW5jaW9uYW1lbnRvIMOpIOKAnGhpcGVy4oCRdmlnaWxhbnRl4oCdLCBwb2RlbmRvIGxldmFyIGEgaW50ZXJ2ZW7Dp8O1ZXMgZGVzbmVjZXNzw6FyaWFzIGUgYSB1bWEgc29icmVjYXJnYSBkYXMgZXF1aXBhcyBkZSBSSC4KCjMuICoqTWF0cml6IGRlIGNvbmZ1c8OjbyoqOgoKKiAqKlZlcmRhZGVpcm9zIE5lZ2F0aXZvcyAoMjY5KSoqOiBjb2xhYm9yYWRvcmVzIHF1ZSBwZXJtYW5lY2VyYW0gZSBmb3JhbSBjb3JyZXRhbWVudGUgY2xhc3NpZmljYWRvcy4KCiogKipGYWxzb3MgUG9zaXRpdm9zICgxMDEpKio6IGNvbGFib3JhZG9yZXMgcXVlIHBlcm1hbmVjZXJhbSwgbWFzIGZvcmFtIGNsYXNzaWZpY2Fkb3MgY29tbyByaXNjbyBkZSBzYcOtZGEgKHBvdGVuY2lhbCBkZXNwZXJkw61jaW8gZGUgcmVjdXJzb3MgZGUgZ2VzdMOjbykuCgoqICoqRmFsc29zIE5lZ2F0aXZvcyAoMTkpKio6IGNvbGFib3JhZG9yZXMgcXVlIHNhw61yYW0sIG1hcyBuw6NvIGZvcmFtIGFudGVjaXBhZG9zIChwZXJkYXMgaW1wcmV2aXN0YXMpLgoKKiAqKlZlcmRhZGVpcm9zIFBvc2l0aXZvcyAoNTIpKio6IGNvbGFib3JhZG9yZXMgcXVlIHNhw61yYW0gZSBmb3JhbSBjb3JyZXRhbWVudGUgaWRlbnRpZmljYWRvcyAob3BvcnR1bmlkYWRlcyBkZSByZXRlbsOnw6NvIGFudGVjaXBhZGEpLgoKKipQcsOzeGltbyBwYXNzbyoqOiBUZXN0YXIgdW0gbW9kZWxvIG1haXMgcm9idXN0bywgY29tbyBvIFJhbmRvbSBGb3Jlc3QsIGNvbSBvIG9iamV0aXZvIGRlIHJlZHV6aXIgb3MgZmFsc29zIHBvc2l0aXZvcyBzZW0gY29tcHJvbWV0ZXIgYSBib2Egc2Vuc2liaWxpZGFkZSBhbGNhbsOnYWRhIHBlbGEgcmVncmVzc8OjbyBsb2fDrXN0aWNhLgoKIyMgTW9kZWxvIDI6IFJhbmRvbSBGb3Jlc3QKYGBge3J9CmxpYnJhcnkocmFuZG9tRm9yZXN0KQpsaWJyYXJ5KGNhcmV0KQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoa2FibGVFeHRyYSkKCiMgUHJlcGFyYcOnw6NvIGUgVHJlaW5vCmRhZG9zX3RyZWlub19iYWwkYXR0cml0aW9uIDwtIGFzLmZhY3RvcihkYWRvc190cmVpbm9fYmFsJGF0dHJpdGlvbikKZGFkb3NfdGVzdGUkYXR0cml0aW9uIDwtIGFzLmZhY3RvcihkYWRvc190ZXN0ZSRhdHRyaXRpb24pCgpzZXQuc2VlZCgxMjMpCm1vZGVsb19yZiA8LSByYW5kb21Gb3Jlc3QoYXR0cml0aW9uIH4gLiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IGRhZG9zX3RyZWlub19iYWwsIAogICAgICAgICAgICAgICAgICAgICAgICAgIG50cmVlID0gNTAwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBpbXBvcnRhbmNlID0gVFJVRSkKCiMgUHJldmlzw7VlcyBlIE3DqXRyaWNhcwpwcmV2aXNvZXNfcmYgPC0gcHJlZGljdChtb2RlbG9fcmYsIG5ld2RhdGEgPSBkYWRvc190ZXN0ZSkKY29uZl9tYXRyaXhfcmYgPC0gY29uZnVzaW9uTWF0cml4KGRhdGEgPSBwcmV2aXNvZXNfcmYsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVmZXJlbmNlID0gZGFkb3NfdGVzdGUkYXR0cml0aW9uLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBvc2l0aXZlID0gIjEiKQoKIyBHcsOhZmljbyBkZSBJbXBvcnTDom5jaWEgZGFzIFZhcmnDoXZlaXMKaW1wX2RmIDwtIGFzLmRhdGEuZnJhbWUoaW1wb3J0YW5jZShtb2RlbG9fcmYpKQppbXBfZGYkVmFyaWF2ZWwgPC0gcm93bmFtZXMoaW1wX2RmKQoKZ2dwbG90KGltcF9kZiAlPiUgYXJyYW5nZShkZXNjKE1lYW5EZWNyZWFzZUFjY3VyYWN5KSkgJT4lIGhlYWQoMTUpLCAKICAgICAgIGFlcyh4ID0gcmVvcmRlcihWYXJpYXZlbCwgTWVhbkRlY3JlYXNlQWNjdXJhY3kpLCB5ID0gTWVhbkRlY3JlYXNlQWNjdXJhY3kpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIGZpbGwgPSAiIzJDM0U1MCIsIGFscGhhID0gMC45LCB3aWR0aCA9IDAuNykgKwogIGNvb3JkX2ZsaXAoKSArCiAgbGFicyh0aXRsZSA9ICJUb3AgMTUgUHJlZGl0b3JhcyBkZSBSb3RhdGl2aWRhZGUiLAogICAgICAgc3VidGl0bGUgPSAiUXVhaXMgb3MgZmF0b3JlcyBxdWUgbWFpcyBpbmZsdWVuY2lhbSBhIGRlY2lzw6NvIGRlIHNhw61kYT8iLAogICAgICAgeCA9IE5VTEwsIHkgPSAiSW1wb3J0w6JuY2lhIChNZWFuIERlY3JlYXNlIEFjY3VyYWN5KSIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDE2KSwKICAgICAgICBwYW5lbC5ncmlkLm1ham9yLnkgPSBlbGVtZW50X2JsYW5rKCkpCgojIFRhYmVsYSBkZSBQZXJmb3JtYW5jZSBDb21wYXJhdGl2YQptZXRyaWNhc19yZiA8LSBkYXRhLmZyYW1lKAogIE3DqXRyaWNhID0gYygiQWN1csOhY2lhIiwgIlNlbnNpYmlsaWRhZGUgKFJlY2FsbCkiLCAiRXNwZWNpZmljaWRhZGUiKSwKICBSZXN1bHRhZG8gPSBjKHBhc3RlMChyb3VuZChjb25mX21hdHJpeF9yZiRvdmVyYWxsWydBY2N1cmFjeSddICogMTAwLCAyKSwgIiUiKSwKICAgICAgICAgICAgICAgIHBhc3RlMChyb3VuZChjb25mX21hdHJpeF9yZiRieUNsYXNzWydTZW5zaXRpdml0eSddICogMTAwLCAyKSwgIiUiKSwKICAgICAgICAgICAgICAgIHBhc3RlMChyb3VuZChjb25mX21hdHJpeF9yZiRieUNsYXNzWydTcGVjaWZpY2l0eSddICogMTAwLCAyKSwgIiUiKSkKKQoKbWV0cmljYXNfcmYgJT4lCiAga2FibGUoY2FwdGlvbiA9ICJQZXJmb3JtYW5jZSBkbyBNb2RlbG8gUmFuZG9tIEZvcmVzdCIpICU+JQogIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImhvdmVyIiksIGZ1bGxfd2lkdGggPSBGKSAlPiUKICByb3dfc3BlYygwLCBib2xkID0gVCwgY29sb3IgPSAid2hpdGUiLCBiYWNrZ3JvdW5kID0gIiMyYzNlNTAiKQpgYGAKTyBtb2RlbG8gKipSYW5kb20gRm9yZXN0KiogYXByZXNlbnRvdSB1bSAqKmRlc2VtcGVuaG8gc3VwZXJpb3IgZSBtYWlzIGVxdWlsaWJyYWRvKiogZW0gY29tcGFyYcOnw6NvIGNvbSBhIFJlZ3Jlc3PDo28gTG9nw61zdGljYS4KQ29tIHVtYSAqKmFjdXLDoWNpYSBnbG9iYWwgZGUgNzQsMTUlKiosIGVzdGUgYWxnb3JpdG1vIGRlbW9uc3Ryb3Ugc2VyIHVtYSBmZXJyYW1lbnRhIHJvYnVzdGEgZSBmacOhdmVsIHBhcmEgYXBvaWFyIGRlY2lzw7VlcyBlc3RyYXTDqWdpY2FzIGRlIHJldGVuw6fDo28gZGUgdGFsZW50by4KCjEuICoqRXF1aWzDrWJyaW8gZW50cmUgZGV0ZcOnw6NvIGUgcHJlY2lzw6NvKioKRGlmZXJlbnRlbWVudGUgZG8gbW9kZWxvIGFudGVyaW9yLCBhIFJhbmRvbSBGb3Jlc3QgcmV2ZWxvdeKAkXNlIG1haXMgcHJlY2lzYSBuYSBkaXN0aW7Dp8OjbyBlbnRyZSBwZXJmaXMgZGUgcmlzY28gZSBkZSBlc3RhYmlsaWRhZGUuCgoqICoqU2Vuc2liaWxpZGFkZSAoX1JlY2FsbF8pIGRlIDcwLDQlKio6IElkZW50aWZpY291IGNvcnJldGFtZW50ZSA1MCBkb3MgNzEgY29sYWJvcmFkb3JlcyBxdWUgZWZldGl2YW1lbnRlIHNhw61yYW0gZGEgZW1wcmVzYS4KCiogKipSZWR1w6fDo28gZG9zIGZhbHNvcyBwb3NpdGl2b3MqKjogRW1ib3JhIGFpbmRhIGV4aXN0YW0gYWxlcnRhcyBpbmRldmlkb3MsIG8gbW9kZWxvIGZvaSBtYWlzIGNyaXRlcmlvc28gbmEgc2luYWxpemHDp8OjbyBkZSByaXNjbywgZGltaW51aW5kbyBvIHJ1w61kbyBvcGVyYWNpb25hbCBwYXJhIGFzIGVxdWlwYXMgZGUgUmVjdXJzb3MgSHVtYW5vcy4KCkVzdGUgZXF1aWzDrWJyaW8gdHJhZHV64oCRc2UgbnVtYSBmZXJyYW1lbnRhIG1haXMg4oCcY2lyw7pyZ2ljYeKAnSwgY2FwYXogZGUgYWxjYW7Dp2FyIGVsZXZhZGEgY2FwYWNpZGFkZSBkZSBkZXRlw6fDo28gc2VtIHNhY3JpZmljYXIgZGUgZm9ybWEgc2lnbmlmaWNhdGl2YSBhIHByZWNpc8OjbyBkYXMgcHJldmlzw7Vlcy4KCgoyLiAqKlByaW5jaXBhaXMgcHJlZGl0b3JlcyBkZSByb3RhdGl2aWRhZGUqKgpBIGFuw6FsaXNlIGRlIGltcG9ydMOibmNpYSBkYXMgdmFyacOhdmVpcyByZXZlbGEgb3MgZmF0b3JlcyBxdWUgbWFpcyBpbmZsdWVuY2lhbSBhIGRlY2lzw6NvIGRlIHNhw61kYSwgb2ZlcmVjZW5kbyBfaW5zaWdodHNfIGRlIGdlc3TDo28gZXh0cmVtYW1lbnRlIHJlbGV2YW50ZXM6CgoqICoqYE92ZXJUaW1lYCAoSG9yYXMgRXh0cmEpKio6IHN1cmdlIGNvbW8gbyBwcmVkaXRvciBtYWlzIGZvcnRlLCBpbmRpY2FuZG8gcXVlIGNvbGFib3JhZG9yZXMgZXhwb3N0b3MgYSBsb25nYXMgam9ybmFkYXMgYXByZXNlbnRhbSBwcm9wZW5zw6NvIHNpZ25pZmljYXRpdmFtZW50ZSBzdXBlcmlvciDDoCBzYcOtZGEuCgoqICoqYE1vbnRobHlJbmNvbWVgIChTYWzDoXJpbykqKjogY29uZmlybWEgcXVlIGFzIGZhaXhhcyBzYWxhcmlhaXMgbWFpcyBiYWl4YXMgY29uc3RpdHVlbSBhIHpvbmEgZGUgbWFpb3IgdnVsbmVyYWJpbGlkYWRlIGVtIHRlcm1vcyBkZSByb3RhdGl2aWRhZGUuCgoqICoqYFN0b2NrT3B0aW9uTGV2ZWxgKio6IGEgYXVzw6puY2lhIGRlIGluY2VudGl2b3MgZGUgbG9uZ28gcHJhem8gKGNvbW8gcGxhbm9zIGRlIGHDp8O1ZXMpIGVzdMOhIGFzc29jaWFkYSBhIG1lbm9yIGNvbXByb21pc3NvIG9yZ2FuaXphY2lvbmFsLgoKKiAqKmBBZ2VgIGUgYFRvdGFsV29ya2luZ1llYXJzYCoqOiB0cmFiYWxoYWRvcmVzIG1haXMgam92ZW5zIGUgY29tIG1lbm9zIGFub3MgZGUgZXhwZXJpw6puY2lhIG1vc3RyYW3igJFzZSBtYWlzIHByb3BlbnNvcyDDoCBtb2JpbGlkYWRlIGV4dGVybmEuCgpFc3RlcyByZXN1bHRhZG9zIGNvcnJvYm9yYW0gYSBsaXRlcmF0dXJhIGRlIFJlY3Vyc29zIEh1bWFub3MsIGRlc3RhY2FuZG8gbyBwYXBlbCBjb25qdW50byBkZSBmYXRvcmVzIGZpbmFuY2Vpcm9zLCBkZSBjYXJnYSBsYWJvcmFsIGUgZGUgZXhwZXJpw6puY2lhIGNvbW8gZGV0ZXJtaW5hbnRlcyBkYSByb3RhdGl2aWRhZGUuCgozLiAqKkNvbmNsdXPDo28gdMOpY25pY2EgZSBpbnRlcnByZXRhdGl2YSoqCkEgUmFuZG9tIEZvcmVzdCBtb3N0cm914oCRc2UgY2FwYXogZGUgY2FwdGFyIHBhZHLDtWVzIG7Do28gbGluZWFyZXMgZSBpbnRlcmHDp8O1ZXMgY29tcGxleGFzIHF1ZSBtb2RlbG9zIGxpbmVhcmVzIG7Do28gY29uc2VndWVtIHJlcHJlc2VudGFyLgpPIGFsZ29yaXRtbyBpZGVudGlmaWNvdSwgcG9yIGV4ZW1wbG8sIHF1ZSB1bSBzYWzDoXJpbyBtw6lkaW8gcG9kZSBzZXIgYWNlaXTDoXZlbCBpc29sYWRhbWVudGUsIG1hcyB0b3JuYeKAkXNlIGZhdG9yIGRlIHJpc2NvIHF1YW5kbyBjb21iaW5hZG8gY29tIGV4Y2Vzc28gZGUgaG9yYXMgZXh0cmEgb3UgYmFpeGEgc2F0aXNmYcOnw6NvIG5hIHJlbGHDp8OjbyBjb20gbyBnZXN0b3IuCkVtIHN1bWEsIGVzdGUgbW9kZWxvIG7Do28gYXBlbmFzIG1lbGhvcmEgbyBkZXNlbXBlbmhvIHByZWRpdGl2bywgbWFzIHRhbWLDqW0gZm9ybmVjZSBpbmZvcm1hw6fDo28gYWNpb27DoXZlbCBwYXJhIHBvbMOtdGljYXMgZGUgcmV0ZW7Dp8OjbyBwZXJzb25hbGl6YWRhcyBlIGdlc3TDo28gcHJldmVudGl2YSBkbyB0YWxlbnRvLgoKCiMjIEFuw6FsaXNlIGRlIERyaXZlcnMgZGUgU2HDrWRhIChGZWF0dXJlIEltcG9ydGFuY2UpCmBgYHtyfQojIEV4dHJhaXIgYSBpbXBvcnTDom5jaWEgZGFzIHZhcmnDoXZlaXMgZG8gbW9kZWxvIFJhbmRvbSBGb3Jlc3QKaW1wb3J0YW5jaWEgPC0gYXMuZGF0YS5mcmFtZShpbXBvcnRhbmNlKG1vZGVsb19yZikpCmltcG9ydGFuY2lhJFZhcmlhdmVsIDwtIHJvd25hbWVzKGltcG9ydGFuY2lhKQoKIyBDcmlhciBvIGdyw6FmaWNvCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShkcGx5cikKCmdncGxvdChpbXBvcnRhbmNpYSAlPiUgYXJyYW5nZShkZXNjKE1lYW5EZWNyZWFzZUFjY3VyYWN5KSkgJT4lIGhlYWQoMTUpLCAKICAgICAgIGFlcyh4ID0gcmVvcmRlcihWYXJpYXZlbCwgTWVhbkRlY3JlYXNlQWNjdXJhY3kpLCB5ID0gTWVhbkRlY3JlYXNlQWNjdXJhY3kpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIGZpbGwgPSAiIzJDM0U1MCIsIGFscGhhID0gMC45LCB3aWR0aCA9IDAuNykgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSByb3VuZChNZWFuRGVjcmVhc2VBY2N1cmFjeSwgMSkpLCAKICAgICAgICAgICAgaGp1c3QgPSAtMC4yLCBzaXplID0gMywgZm9udGZhY2UgPSAiYm9sZCIsIGNvbG9yID0gIiMyQzNFNTAiKSArCiAgY29vcmRfZmxpcCgpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gZXhwYW5zaW9uKG11bHQgPSBjKDAsIDAuMSkpKSArCiAgbGFicygKICAgIHRpdGxlID0gIkRyaXZlcnMgQ3LDrXRpY29zIGRlIEF0dHJpdGlvbiIsCiAgICBzdWJ0aXRsZSA9ICJWYXJpw6F2ZWlzIHF1ZSBtYWlzIGltcGFjdGFtIGEgcHJlY2lzw6NvIGRvIG1vZGVsbyBSYW5kb20gRm9yZXN0IiwKICAgIHggPSBOVUxMLAogICAgeSA9ICJJbXBvcnTDom5jaWEgKE1lYW4gRGVjcmVhc2UgQWNjdXJhY3kpIgogICkgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUoCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxNiwgY29sb3IgPSAiIzJjM2U1MCIpLAogICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTEsIGNvbG9yID0gImdyZXk0MCIpLAogICAgcGFuZWwuZ3JpZC5tYWpvci55ID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDEwKQogICkKYGBgCk8gZ3LDoWZpY28gYWNpbWEgYXByZXNlbnRhIGFzIHZhcmnDoXZlaXMgbWFpcyBkZXRlcm1pbmFudGVzIGlkZW50aWZpY2FkYXMgcGVsbyBtb2RlbG8gUmFuZG9tIEZvcmVzdCwgb3JkZW5hZGFzIHBlbGEgbcOpdHJpY2Eg4oCcTWVhbiBEZWNyZWFzZSBBY2N1cmFjeeKAnS4KRW0gdGVybW9zIHByw6F0aWNvcywgcXVhbnRvIG1haW9yIGEgaW1wb3J0w6JuY2lhIGRlc3RhIG3DqXRyaWNhLCBtYWlvciDDqSBvIGNvbnRyaWJ1dG8gZGEgdmFyacOhdmVsIHBhcmEgYSBjYXBhY2lkYWRlIHByZWRpdGl2YSBnbG9iYWwgZG8gbW9kZWxvLCBvdSBzZWphLCBhIHN1YSByZW1vw6fDo28gcmVzdWx0YXJpYSBudW1hIGRpbWludWnDp8OjbyBzaWduaWZpY2F0aXZhIGRhIHByZWNpc8Ojby4KCjEuICoqTyBjYXJnbyBjb21vIHByaW5jaXBhbCBkZXRlcm1pbmFudGUgKGBKb2JSb2xlYCkqKgpRdWF0cm8gZGFzIGNpbmNvIHZhcmnDoXZlaXMgbWFpcyByZWxldmFudGVzIGVzdMOjbyByZWxhY2lvbmFkYXMgY29tIGZ1bsOnw7VlcyBlc3BlY8OtZmljYXMgZGVudHJvIGRhIG9yZ2FuaXphw6fDo28uCkRlc3RhY2Ft4oCRc2UgZG9pcyBleHRyZW1vczogYFJlc2VhcmNoIERpcmVjdG9yYCAoZnVuw6fDo28gY29tIGVsZXZhZGEgZXN0YWJpbGlkYWRlKSBlIFNhbGVzYCBSZXByZXNlbnRhdGl2ZWAgKGZ1bsOnw6NvIG1haXMgdm9sw6F0aWwpLgoKRXN0YSBkaWZlcmVuw6dhIGNvbmZpcm1hIGFzIGNvbmNsdXPDtWVzIG9idGlkYXMgbmEgYW7DoWxpc2UgZXhwbG9yYXTDs3JpYTogbyBuw612ZWwgaGllcsOhcnF1aWNvIGUgbyB0aXBvIGRlIGZ1bsOnw6NvIHPDo28gb3MgZmF0b3JlcyBxdWUgbWFpcyBkaWZlcmVuY2lhbSBvIGNvbXBvcnRhbWVudG8gZGUgcm90YXRpdmlkYWRlIG5hIGVtcHJlc2EuCgoqKkltcGxpY2HDp8OjbyoqOiBQb2zDrXRpY2FzIGdlbsOpcmljYXMgZGUgZ2VzdMOjbyBkZSBwZXNzb2FzICjigJxvbmXigJFzaXpl4oCRZml0c+KAkWFsbOKAnSkgc8OjbyBpbmVmaWNhemVzLgoKQSBlc3RyYXTDqWdpYSBkZSByZXRlbsOnw6NvIGRldmUgc2VyIHBlcnNvbmFsaXphZGEgcG9yIMOhcmVhIGZ1bmNpb25hbCwgcmVjb25oZWNlbmRvIHF1ZSB2ZW5kYXMgZSBpbnZlc3RpZ2HDp8Ojby9yZWRlIGRlIGxpZGVyYW7Dp2EgZXhpZ2VtIGFib3JkYWdlbnMgZGUgbW90aXZhw6fDo28gZSByZWNvbmhlY2ltZW50byBkaXN0aW50YXMuCgoyLiAqKk8gcGVzbyBkYXMgaG9yYXMgZXh0cmEgKGBPdmVyVGltZWApKioKQSB2YXJpw6F2ZWwgYG92ZXJfdGltZV95ZXNgIHN1cmdlIGNvbW8gbyB0ZXJjZWlybyBwcmVkaXRvciBtYWlzIGNyw610aWNvIGRlIHRvZG8gbyBjb25qdW50by4KRXN0ZSByZXN1bHRhZG8gcmVmb3LDp2EgYSBldmlkw6puY2lhIGRlIHF1ZSBhIHNvYnJlY2FyZ2EgZGUgdHJhYmFsaG8gZSBhIGZhbHRhIGRlIGVxdWlsw61icmlvIHZpZGHigJFwcm9maXNzaW9uYWwgY29uc3RpdHVlbSBnYXRpbGhvcyBkaXJldG9zIGRlIHNhw61kYS4KVHJhdGFy4oCRc2XigJHDoSBtZW5vcyBkZSB1bWEgcXVlc3TDo28gZGUgcmVtdW5lcmHDp8OjbyBlIG1haXMgZGUgYmVt4oCRZXN0YXIgb3JnYW5pemFjaW9uYWwgZSBwcmV2ZW7Dp8OjbyBkZSBfYnVybm91dC5fCgozLiAqKkVzdGFnbmHDp8OjbyBlIGluY2VudGl2b3MgZGUgbG9uZ28gcHJhem8qKgoKKiAqKkVzdGFnbmHDp8OjbyoqOiBBIHZhcmnDoXZlbCBgeWVhcnNfaW5fY3VycmVudF9yb2xlYCAoYW5vcyBuYSBmdW7Dp8OjbyBhdHVhbCkgZGVzdGFjYeKAkXNlIG5hIDYuwqogcG9zacOnw6NvLiBBIHBlcm1hbsOqbmNpYSBwcm9sb25nYWRhIG5hIG1lc21hIGZ1bsOnw6NvLCBzZW0gcHJvZ3Jlc3PDo28gdmlzw612ZWwsIGF1bWVudGEgc3Vic3RhbmNpYWxtZW50ZSBvIHJpc2NvIGRlIHNhw61kYSB2b2x1bnTDoXJpYS4KCiogKipJbmNlbnRpdm9zKio6IE8gYHN0b2NrX29wdGlvbl9sZXZlbGAgc3VyZ2UgbG9nbyBkZSBzZWd1aWRhLCBldmlkZW5jaWFuZG8gcXVlIG9zIGluY2VudGl2b3MgZGUgbG9uZ28gcHJhem8gdMOqbSB1bSBlZmVpdG8gZGUgcmV0ZW7Dp8OjbyBtYWlzIGZvcnRlIGRvIHF1ZSBvIHNhbMOhcmlvIG1lbnNhbCAoYG1vbnRobHlfaW5jb21lYCksIHF1ZSBhcGFyZWNlIGFwZW5hcyBuYSAxNS7CqiBwb3Npw6fDo28uCgpFc3RlcyByZXN1bHRhZG9zIHN1Z2VyZW0gcXVlIGEgcHJvZ3Jlc3PDo28gZGUgY2FycmVpcmEgZSBhIHZhbG9yaXphw6fDo28gZGUgY2FwaXRhbCBzaW1iw7NsaWNvIChhw6fDtWVzLCByZWNvbmhlY2ltZW50bywgdmlzaWJpbGlkYWRlKSBzw6NvIG1lY2FuaXNtb3MgZGUgcmV0ZW7Dp8OjbyBtYWlzIGVmaWNhemVzIGRvIHF1ZSBhdW1lbnRvcyBzYWxhcmlhaXMgaXNvbGFkb3MuCgo0LiAqKlBlcmZpbCBkZW1vZ3LDoWZpY28gZGUgcmlzY28qKgpBIHByZXNlbsOnYSBkYXMgdmFyacOhdmVpcyBgbWFyaXRhbF9zdGF0dXNfc2luZ2xlYCBlIGFnZSBlbnRyZSBhcyAxNSBtYWlzIHJlbGV2YW50ZXMgY29uZmlybWEgbyBwYWRyw6NvIGlkZW50aWZpY2FkbyBuYXMgYW7DoWxpc2VzIGFudGVyaW9yZXM6IGNvbGFib3JhZG9yZXMgbWFpcyBqb3ZlbnMgZSBzb2x0ZWlyb3MgdGVuZGVtIGEgYXByZXNlbnRhciBtYWlvciBtb2JpbGlkYWRlIGUgcHJlZGlzcG9zacOnw6NvIHBhcmEgbXVkYW7Dp2EsIHNvYnJldHVkbyBlbSBjb250ZXh0b3MgZGUgcG91Y2FzIHBlcnNwZXRpdmFzIGRlIGNyZXNjaW1lbnRvLgoKUGFyYSBtaXRpZ2FyIG9zICoqcmlzY29zIGRlIF9hdHRyaXRpb25fKiosIHJlY29tZW5kYeKAkXNlIHF1ZSBhcyBhw6fDtWVzIHByaW9yaXTDoXJpYXMgZGEgZW1wcmVzYSBpbmNpZGFtIHNvYnJlIHRyw6pzIGVpeG9zIHByaW5jaXBhaXM6CgoxLiBSZXZlciBhcyBjb25kacOnw7VlcyBlIGluY2VudGl2b3MgZGFzIGVxdWlwYXMgZGUgVmVuZGFzLCBvbmRlIGEgdGF4YSBkZSBzYcOtZGEgw6kgbWFpcyBlbGV2YWRhOwoKMi4gTW9uaXRvcml6YXIgZSByZWd1bGFyIG8gdm9sdW1lIGRlIGhvcmFzIGV4dHJhLCBwcm9tb3ZlbmRvIHByw6F0aWNhcyBkZSBlcXVpbMOtYnJpbyBlIGJlbeKAkWVzdGFyOwoKMy4gSW1wbGVtZW50YXIgcGxhbm9zIGRlIHJvdGHDp8OjbyBlIGRlc2Vudm9sdmltZW50byBkZSBjYXJyZWlyYSwgZXNwZWNpYWxtZW50ZSBwYXJhIGNvbGFib3JhZG9yZXMgZXN0YWduYWRvcyBuYSBtZXNtYSBmdW7Dp8OjbyBow6EgdsOhcmlvcyBhbm9zLgoKRXN0YXMgYcOnw7VlcyBlc3RyYXTDqWdpY2FzIGFsaW5oYW3igJFzZSBkaXJldGFtZW50ZSBjb20gb3MgcmVzdWx0YWRvcyBkbyBtb2RlbG8gZSBwb2RlbSByZWR1emlyIHN1YnN0YW5jaWFsbWVudGUgbyByaXNjbyBkZSByb3RhdGl2aWRhZGUgbsOjbyBkZXNlamFkYSwgZm9ydGFsZWNlbmRvIGEgcmV0ZW7Dp8OjbyBkZSB0YWxlbnRvIGNyw610aWNvLgoKIyBDb25jbHVzw6NvIGUgUmVjb21lbmRhw6fDtWVzIGRlIE5lZ8OzY2lvCgpFc3RlIHByb2pldG8gdGV2ZSBjb21vIG9iamV0aXZvIGlkZW50aWZpY2FyIGFzIGNhdXNhcyBkYSByb3RhdGl2aWRhZGUgZGUgZnVuY2lvbsOhcmlvcyAoQXR0cml0aW9uKSBlIGNyaWFyIHVtIG1vZGVsbyBwcmVkaXRpdm8gcGFyYSBtaXRpZ2FyIG8gcmlzY28uCgojIyBDb21wYXJhw6fDo28gZGUgTW9kZWxvcwpGb3JhbSB0ZXN0YWRhcyBkdWFzIGFib3JkYWdlbnMgZGlzdGludGFzOiBSZWdyZXNzw6NvIExvZ8Otc3RpY2EgZSBSYW5kb20gRm9yZXN0LgoKTyAqKlJhbmRvbSBGb3Jlc3QqKiBkZW1vbnN0cm91ICoqZGVzZW1wZW5obyBzdXBlcmlvciBlIG1haW9yIGVzdGFiaWxpZGFkZSoqLCBhbGNhbsOnYW5kbyB1bWEgKiphY3Vyw6FjaWEgZ2xvYmFsIGRlIDc0LDE1JSoqLgoKTyBtb2RlbG8gw6kgY2FwYXogZGUgKippZGVudGlmaWNhciBjb3JyZXRhbWVudGUgNzAsNCUgZG9zIGNvbGFib3JhZG9yZXMgcXVlIGVmZXRpdmFtZW50ZSBzYWVtIGRhIGVtcHJlc2EqKiAoc2Vuc2liaWxpZGFkZSksIG1hbnRlbmRvLCBlbSBzaW11bHTDom5lbywgdW1hICoqdGF4YSBkZSBmYWxzb3MgYWxhcm1lcyBjb250cm9sYWRhKiogKGVzcGVjaWZpY2lkYWRlIGRlIDc0LDklKS4KCkVzdGFzIG3DqXRyaWNhcyBldmlkZW5jaWFtIHVtICoqZXF1aWzDrWJyaW8gYWRlcXVhZG8gZW50cmUgZGV0ZcOnw6NvIGUgcHJlY2lzw6NvKiosIHRvcm5hbmRvIG8gYWxnb3JpdG1vIHVtYSBmZXJyYW1lbnRhIGVmaWNheiBwYXJhIHVzbyBwcsOhdGljbyBlbSBjb250ZXh0b3MgZGUgUmVjdXJzb3MgSHVtYW5vcy4KCiMjIEZhdG9yZXMgQ3LDrXRpY29zIGRlIFNhw61kYSAoX0luc2lnaHRzXyBkbyBNb2RlbG8pCkEgYW7DoWxpc2UgZGUgaW1wb3J0w6JuY2lhIGRhcyB2YXJpw6F2ZWlzIChGZWF0dXJlIEltcG9ydGFuY2UpIGV2aWRlbmNpb3UgdHLDqnMgcGlsYXJlcyBjZW50cmFpcyBkZSBhw6fDo286CgoxLiAqKk8gUmlzY28gQXNzb2NpYWRvIMOgIEZ1bsOnw6NvIGRlIFZlbmRhcyoqCgpBIGZ1bsOnw6NvIGBTYWxlcyBSZXByZXNlbnRhdGl2ZWAgc3VyZ2UgY29tbyBvICoqbWFpb3IgcHJlZGl0b3IgZGUgc2HDrWRhKiouIEEgdGF4YSBkZSByb3RhdGl2aWRhZGUgbmVzdGUgY2FyZ28gw6kgc3Vic3RhbmNpYWxtZW50ZSBzdXBlcmlvciDDoCBvYnNlcnZhZGEgZW0gZnVuw6fDtWVzIGVzdMOhdmVpcyBjb21vIGBSZXNlYXJjaCBEaXJlY3RvcmAgb3UgYE1hbmFnZXIuYAoKKipEaWFnbsOzc3RpY28gcHJvdsOhdmVsKio6IERlc2FqdXN0ZSBubyBlc3F1ZW1hIGRlIGNvbWlzc8O1ZXMsIHByZXNzw6NvIGVsZXZhZGEgcG9yIHJlc3VsdGFkb3Mgb3UgZmFsdGEgZGUgcGVyc3BldGl2YXMgZGUgcHJvZ3Jlc3PDo28uCgoyLiAqKkN1bHR1cmEgZGUgSG9yYXMgRXh0cmEgZSBFeGF1c3TDo28gT2N1cGFjaW9uYWwqKgoKQSB2YXJpw6F2ZWwgYE92ZXJUaW1lYCBtYW50w6lt4oCRc2UgZW50cmUgb3MgKip0csOqcyBmYXRvcmVzIG1haXMgY3LDrXRpY29zKiosIGNvbmZpcm1hbmRvIHF1ZSBhICoqc29icmVjYXJnYSBkZSB0cmFiYWxobyDDqSB1bSBkb3MgZ2F0aWxob3MgZGlyZXRvcyBkZSBzYcOtZGEqKi4gQ29sYWJvcmFkb3JlcyBxdWUgcmVhbGl6YW0gaG9yYXMgZXh0cmEgYXByZXNlbnRhbSBwcm9iYWJpbGlkYWRlIHNpZ25pZmljYXRpdmFtZW50ZSBzdXBlcmlvciBkZSBzYWlyIGRhIGVtcHJlc2EsIGluZGVwZW5kZW50ZW1lbnRlIGRvIG7DrXZlbCBzYWxhcmlhbC4KCioqSW50ZXJwcmV0YcOnw6NvKio6IGVzdGUgY29tcG9ydGFtZW50byBzdWdlcmUgc2luYWlzIGRlIF9idXJub3V0XyBlIGRlc2VxdWlsw61icmlvIHZpZGHigJF0cmFiYWxobywgw6FyZWFzIHF1ZSByZXF1ZXJlbSBtb25pdG9yaXphw6fDo28gYXRpdmEuCgozLiAqKlJldGVuw6fDo28gYXRyYXbDqXMgZGUgSW5jZW50aXZvcyBkZSBDYXBpdGFsKioKCk8gYFN0b2NrT3B0aW9uTGV2ZWxgIG1vc3RyYeKAkXNlICoqZGV0ZXJtaW5hbnRlIHBhcmEgYSByZXRlbsOnw6NvIGRlIGNvbGFib3JhZG9yZXMqKi4gRnVuY2lvbsOhcmlvcyBjb20gcGFydGljaXBhw6fDo28gYWNpb25pc3RhIG91IGluY2VudGl2b3MgZGUgbG9uZ28gcHJhem8gdGVuZGVtIGEgcmV0ZXLigJFzZSBwb3IgbWFpcyB0ZW1wbywgcmVmb3LDp2FuZG8gbyBzZW50aW1lbnRvIGRlIHBlcnRlbsOnYSBlIGNvbXByb21pc3NvIG9yZ2FuaXphY2lvbmFsLiBJbnZlcnNhbWVudGUsIGEgYXVzw6puY2lhIGRlc3RlIGZhdG9yIGVzdMOhIGZvcnRlbWVudGUgYXNzb2NpYWRhIGEgbWFpb3IgcHJvcGVuc8OjbyDDoCBzYcOtZGEuCgojIyBQbGFubyBkZSBBw6fDo28gUmVjb21lbmRhZG8gKFByw7N4aW1vcyBQYXNzb3MpCgpDb20gYmFzZSBuYXMgZXZpZMOqbmNpYXMgYW5hbMOtdGljYXMsIHJlY29tZW5kYeKAkXNlIGEgaW1wbGVtZW50YcOnw6NvIGRhcyBzZWd1aW50ZXMgbWVkaWRhczoKCjEuICoqSW50ZXJ2ZW7Dp8OjbyBkaXJlY2lvbmFkYSBuYXMgZXF1aXBhcyBkZSBWZW5kYXMqKjogUmVhbGl6YXIgZW50cmV2aXN0YXMgZGUgc2HDrWRhIGVzcGVjw61maWNhcyBwYXJhIFJlcHJlc2VudGFudGVzIGRlIFZlbmRhcywgY29tIGZvY28gbmEgcmV2aXPDo28gZGUgcG9sw610aWNhcyBkZSBjb21pc3PDo28sIG9iamV0aXZvcyBlIHBsYW5vIGRlIGNhcnJlaXJhLgoKMi4gKipBdWRpdG9yaWEgZGUgQ2FyZ2EgSG9yw6FyaWEgZSBCZW3igJFFc3RhcioqOiBFc3RhYmVsZWNlciBtZWNhbmlzbW9zIGRlIGNvbnRyb2xvIGRhcyBob3JhcyBleHRyYSwgZ2FyYW50aW5kbyBhIHN1YSBjb21wZW5zYcOnw6NvIGFkZXF1YWRhICh2aWEgZm9sZ2FzIG91IGJlbmVmw61jaW9zKS4gU2ltdWx0YW5lYW1lbnRlLCBwcm9tb3ZlciBwcm9ncmFtYXMgZGUgcHJldmVuw6fDo28gZGUgX2J1cm5vdXRfIGUgZGUgZXF1aWzDrWJyaW8gdmlkYeKAkXRyYWJhbGhvLgoKMy4gKipGZXJyYW1lbnRhIGRlIFByZXZpc8OjbyBDb250w61udWEgZGUgUm90YXRpdmlkYWRlKio6IEludGVncmFyIG8gbW9kZWxvIFJhbmRvbSBGb3Jlc3QgY29tbyB1bSBzaXN0ZW1hIG1lbnNhbCBkZSBtb25pdG9yaXphw6fDo28gcHJlZGl0aXZhLCB1bWEg4oCcbGlzdGEgZGUgcmlzY2/igJ0gZGluw6JtaWNhLCBkZXN0YWNhbmRvIGNvbGFib3JhZG9yZXMgY29tIHByb2JhYmlsaWRhZGUgZGUgc2HDrWRhIHN1cGVyaW9yIGEgNTAlLiBFc3RhIGluZm9ybWHDp8OjbyBkZXZlIHNlciB1dGlsaXphZGEgZGUgZm9ybWEgcHJvYXRpdmEsIHBlcm1pdGluZG8gw6AgZXF1aXBhIGRlIFJIIGFnaXIgYW50ZXMgZGEgZGVjaXPDo28gZGUgc2FpciBkYSBlbXByZXNhLg==