1 Objetivo Geral


  • Apresentar um cenário comparativo a partir do salário-hora entre trabalhadores formais e trabalhadores por conta-própria que possuem CNPJ, a partir da pesquisa PNADc


2 Escolhas Metodológicas


  • A base de dados utilizada foi a Pesquisa Nacional por Amostra de Domicílios Contínua - PNADc

  • O recorte temporal foi o 3º trimestre/2024. Essa escolha ocorre tendo em vista as volatilidades do mercado de trabalho no início e fim de ano.

  • A comparação de salário-hora não é direta. Para formalizados foram inseridos valores de 13º, férias, 1/3 de férias e FGTS. Para trabalhadores por conta-própria com PJ que recebem abaixo de R$ 81.000,00 foi retirada a contribuição de R$ 70,00 referente ao MEI. Para os demais PJs foram retirados 20% do valor do salário-mínimo. As fórmulas estão disponíveis na seção “Salário-Hora

  • Foram retirados outliers abaixo de 1% e acima de 99% a partir das variáveis de rendimento e de horas trabalhadas. Depois do cálculo de salário-hora foram retirados também outliers a partir dessa variável

  • Foram retirados trabalhadores caracterizados como subocupados por insuficiência de horas.

  • Tendo em vista que se trata de pesquisa amostral, quando foram analisados os valores totais (com peso pós-estratificado) qualquer valor total dos grupos (formal e conta-própria) que estivesse com coeficiente de variação acima de 25% foi retirado da tabela de resultados.

  • A PNADc utiliza a Classificação de Ocupações para as Pesquisas Domiciliares – COD (https://ftp.ibge.gov.br/Censos/Censo_Demografico_2010/metodologia/anexos/anexo_7_ocupacao_cod.pdf) que tem a seguinte estrutura:




3 Desenho da Base

3.1 Variáveis de Interesse

  • Ano
  • Trimestre
  • UF
  • V4010 - Código da ocupação (cargo ou função)
    • É utilizada a Classificação de Ocupações para as Pesquisas Domiciliares – COD
  • VD4002 - Ocupados/Desocupados
  • VD4009 - Posição na ocupação e categoria do emprego
    • 1 - Empregado no setor privado com carteira de trabalho assinada
    • 9 - Conta-própria #VD4010 - Grupamentos de atividade principal do empreendimento do trabalho
  • VD4016 - Rendimento mensal habitual do trabalho principal
  • VD4010 - Grupamentos de atividade principal do empreendimento do trabalho principal
    • Ex.: Agricultura, Indústria, Construção etc
  • V4039 - “Quantas horas … trabalhava normalmente, por semana, nesse trabalho principal?”
  • V4019 - “Esse negócio/empresa era registrado no Cadastro Nacional da Pessoa Jurídica - CNPJ?”
  • VD4004A - Subocupação por insuficiência de horas habitualmente trabalhadas em todos os trabalhos
  • VD3004 - Escolaridade
  • VD3005 - Anos de Estudo
  • V2007 - Sexo
  • V2010 - Cor/Raça
  • V2009 - Idade
  • VD4011 - Grupamento Ocupacional
  • VD4012 - Contribuição para instituto de previdência em qualquer trabalho da semana de referência para pessoas de 14 anos ou mais de idade


3.2 Pré-Processamento

#Temas para Rmarkdown - https://rpubs.com/ranydc/rmarkdown_themes

library(tidyverse)
library(readxl)
library(DT)
library(PNADcIBGE)
library(survey)
library(srvyr)
library(scales)
library(jtools) #função summ - parte inferencial

Sys.setlocale("LC_ALL", "pt_BR.UTF-8") #problemas com encoding

Será feita uma consulta somente à base de dados de 2024 - 3º Trimestre, tendo em vista a limitação de capacidade de processamento.

O código abaixo fará o download dos dados e salvará em um objeto do tipo .rds para uma pasta local.

##########RODAR SOMENTE A PRIMEIRA VEZ###############

# variaveis_selecionadas <- c("Ano", "Trimestre", "UF","V4010",
#                             "VD4002","VD4009","VD4010","VD4016",
#                             "V4039","V4019", "VD4004A", "VD3004", "VD3005",
#                             "V2007", "V2010", "V2009", "VD4012", "VD4011")
# 
# pnadc <- get_pnadc(year=2024, quarter=3,
#                    vars=variaveis_selecionadas, design = T, labels = F)
# class(pnadc)

# #TRANSFORMAR PARA TIBBLE PARA USAR A GRAMÁTICA TIDYVERSE
# pnad_srvyr <- as_survey(pnadc)
# class(pnad_srvyr)

# #PRIMEIRO FILTRO - SOMENTE OCUPADOS
# ocupados <- pnad_srvyr |>
#   filter(VD4002 == 1) |>
#   mutate(V1028 = as.numeric(V1028))
# class(ocupados)

# rm(pnad_srvyr)
# rm(pnadc)

# #SALVAR PARA USAR OFFLINE
# saveRDS(ocupados, file = "c:/Users/raphael.rsl/Desktop/R/pjclt/ocupados3.rds")

3.3 Preparação da Base de Dados

Aqui será realizada a junção entre a PNADc pura e a tabela COD das profissões.

ocupados <- readRDS("c:/Users/raphael.rsl/Desktop/R/pjclt/ocupados3.rds")
#class(ocupados)

#LER A TABELA DE OCUPAÇÕES
cod <- read_xls("c:/Users/raphael.rsl/Desktop/R/pjclt/Estrutura_Ocupacao_COD.xls") |>
  rename(grande_grupo = `Grande Grupo`,
         subgrupo_principal = `Subgrupo principal`,
         subgrupo = Subgrupo,
         grupo_base = `Grupo de base`,
         denominacao = Denominação) |>
  mutate( #NÃO TRAZER NAs, ou seja, se não for NA traz "denominacao"
    denom_subgrupo_principal = if_else(!is.na(subgrupo_principal), denominacao, NA_character_),
    denom_subgrupo = if_else(!is.na(subgrupo), denominacao, NA_character_),
    denom_grupo_base = if_else(!is.na(grupo_base), denominacao, NA_character_)) |>
  fill(grande_grupo, subgrupo_principal, denom_subgrupo_principal, 
       subgrupo, denom_subgrupo, grupo_base, denom_grupo_base, .direction = "down")
       #propaga os valores para baixo

#RETIRANDO NAs e possíveis duplicados
cod_map <- cod |>
  filter(!is.na(grupo_base)) |>
  select(grupo_base, denom_grupo_base, subgrupo, denom_subgrupo,
         subgrupo_principal, denom_subgrupo_principal, grande_grupo) |>
  distinct()

#aplicando a base COD na base geral
ocupados2 <- ocupados |> 
  mutate(V4010 = as.character(V4010),
         subgrupo_cod = substr(V4010, 1, 3),
         # busca grupo_base e subgrupo e faz o match
         grupo_base = cod_map$denom_grupo_base[match(V4010, cod_map$grupo_base)],
         subgrupo = cod_map$denom_subgrupo[match(subgrupo_cod, cod_map$subgrupo)])

# Retirados indivíduos classificados como subocupados
ocupados2 <- ocupados2 |> 
  filter(is.na(VD4004A) | VD4004A != 1)
#É necessário manter NA por conta da estrutura do tbl_svy

#outliers - retira 1% superior e 1% inferior
ocupados2 <- ocupados2 |> 
  filter(VD4016 >= quantile(VD4016, 0.01, na.rm = TRUE),
         VD4016 <= quantile(VD4016, 0.99, na.rm = TRUE),
         V4039 >= quantile(V4039, 0.01, na.rm = TRUE),
         V4039 <= quantile(V4039, 0.99, na.rm = TRUE)) 

Gráficos Exploratórios

#VERIFICAR SE É O CASO DE RETIRAR MAIS OUTLIERS A PARTIR DOS BOXPLOTS

# Boxplot para Rendimento
ggplot(ocupados2, aes(x = "", y = VD4016)) +
  geom_boxplot(outlier.color = "red") +
  labs(title = "Boxplot de Rendimento", y = "Rendimento") +
  theme_minimal()

# Boxplot para Jornada
ggplot(ocupados2, aes(x = "", y = V4039)) +
  geom_boxplot(outlier.color = "red") +
  labs(title = "Boxplot de Jornada", y = "Horas") +
  theme_minimal()  

3.4 Salário-Hora

Criou-se uma variável auxiliar: salario_hora com a seguinte composição

Para formais, consideramos: - 12 salários mensais habituais; - 13º salário (1 salário adicional); - 1/3 adicional de férias; - 8% de FGTS; - Apenas 11 meses de trabalho efetivo (pois 1 mês é de férias).

A fórmula do salário-hora é:

\[ \text{Salário-hora}_{formal} = \frac{(12 + 1 + \tfrac{1}{3}) \cdot \text{Salário Mensal Habitual} \cdot (1 + \text{FGTS})} {\text{Horas Semanais Habitual} \cdot \tfrac{52}{12} \cdot 11} \]

Para trabalhadores autônomos registrados como MEI, consideramos:
- Rendimento mensal habitual declarado;
- Desconto fixo da guia DAS (imposto mensal do MEI);
- Jornada habitual semanal multiplicada por \(52/12\) (para obter as horas mensais).

A fórmula do salário-hora é:

\[ \text{Salário-hora}_{MEI} = \frac{\text{Salário Mensal Habitual} - \text{DAS}} {\text{Horas Semanais Habitual} \cdot \tfrac{52}{12}} \]

Autônomos acima do limite MEI

Para trabalhadores por conta própria com rendimento acima do limite MEI, consideramos:

  • Contribuição proporcional: aplica-se 11% diretamente sobre o rendimento mensal, considerado o valor declarado como pro-labore.

\[ \text{Salário-hora}_{CP}^{prop} = \frac{\text{Salário Mensal Habitual} \cdot (1 - 11\%)} {\text{Horas Semanais Habitual} \cdot \tfrac{52}{12}} \]

Além disso, foi criada uma variável auxiliar chamada categoria_emprego para facilitar a filtragem de formal, cnpj e outros.

# Parâmetros
sal_min <- 1412          # salário-mínimo em 2024
mei_mensal <- 81000 / 12  # R$ 6750 por mês
mei_das <- 71.60          # DAS-MEI 2025
fgts <- 0.08         # 8% FGTS
semana_mes <- 52/12  # ~4.333
opcao_inss <- "NOT_fixed_min_wage_11pct" # regra usada para contribuição direta no salário minimo - não usada
#ou 20% segundo teste foi para 20%
inss_valor <- 0.11

# --- converter campos para numeric / proteger divisões ---
ocupados2 <- ocupados2  |> 
  mutate(VD4016 = as.numeric(as.character(VD4016)),  
         V4039  = as.numeric(as.character(V4039)),   
         VD4009 = as.character(VD4009))

# --- cálculo atualizado ---
ocupados3 <- ocupados2 |>
  mutate(
    # horas efetivamente trabalhadas no mês
    horas_mes = if_else(!is.na(V4039) & V4039 > 0, V4039 * semana_mes, NA_real_),

    # salário-hora
    salario_hora = case_when(
      # Formal com férias, 13º e FGTS (11 meses de trabalho no ano)
      VD4009 == "1" & !is.na(horas_mes) ~ {
        sal_anual <- VD4016 * (12 + 1 + 1/3)      # 12 salários + 13º + 1/3 férias
        horas_ano <- horas_mes * 11               # só 11 meses de trabalho, tendo em vista férias
        (sal_anual * (1 + fgts)) / horas_ano},

      # Autônomo / MEI até limite mensal = desconta DAS fixo
      VD4009 != "1" & !is.na(horas_mes) & VD4016 <= mei_mensal ~
        pmax((VD4016 - mei_das) / horas_mes, 0), #pmax garante que não vem valor negativo

      # Autônomo / CNPJ acima do limite MEI = aplica regra do INSS
      VD4009 != "1" & !is.na(horas_mes) & VD4016 > mei_mensal ~ {
        if (opcao_inss == "fixed_min_wage_11pct") {
          inss_val <- sal_min * inss_valor
          pmax((VD4016 - inss_val) / horas_mes, 0)} 
        else {
          pmax((VD4016 * (1 - inss_valor)) / horas_mes, 0)}},
      TRUE ~ NA_real_  ))

# --- categorias de emprego ---
ocupados3$variables <- ocupados3$variables |>
  mutate(categoria_emprego = case_when(
    VD4009 == "01" ~ "formal",
    VD4009 == "09" & V4019 == "1" ~ "cnpj",
    TRUE ~ "outros"))

rm(ocupados)

ggplot(ocupados3, aes(x = "", y = salario_hora)) +
  geom_boxplot(outlier.color = "red") +
  labs(title = "Boxplot de Salário-Hora", y = "Horas") +
  theme_minimal()  

#retirar outliers de salario_hora
ocupados3 <- ocupados3 |>
  filter(salario_hora >= quantile(salario_hora, 0.01, na.rm = TRUE),
         salario_hora <= quantile(salario_hora, 0.99, na.rm = TRUE))

4 Análise Descritiva

4.1 Iniciais - Por Categoria

4.1.1 Salário-Hora

resumo_sal <- ocupados3 |>
  group_by(categoria_emprego) |>
  summarise(n = survey_total(na.rm = TRUE),
            mediana = survey_median(salario_hora, na.rm = TRUE),
            .groups = "drop") |>
  mutate(n_label = paste0("n = ", scales::comma(n)),
         mediana_label = paste0("Mediana = R$ ", round(mediana, 2)))

ggplot(ocupados3, aes(x = categoria_emprego, y = salario_hora, fill = categoria_emprego)) +
  geom_boxplot(alpha = 0.7, outlier.colour = "red") +
  scale_y_continuous(labels = scales::dollar_format(prefix = "R$ ")) +
  coord_cartesian(ylim = c(0, 50)) +
  labs(title = "Distribuição do Salário-Hora por Categoria de Emprego \n (até R$ 50)",
       x = "Categoria de Emprego",
       y = "Salário-Hora") +
  theme_minimal(base_size = 14) +
  theme(legend.position = "none") +
  geom_text(data = resumo_sal,
            aes(x = categoria_emprego, y = 5, label = n_label), # coloca o texto no topo
            inherit.aes = FALSE,
            vjust = -0.5,
            size = 4) +
  geom_text(data = resumo_sal,
            aes(x = categoria_emprego, y = mediana, label = round(mediana, 1)),
            inherit.aes = FALSE,
            vjust = -0.5,
            fontface = "bold",
            size = 4,
            color = "blue")

4.1.2 Escolaridade

ocupados3 <- ocupados3 |> 
  mutate(escolaridade = factor(VD3004,
                               levels = 1:7,
                               labels = c("Sem instrução",
                                          "Fundamental incompleto",
                                          "Fundamental completo",
                                          "Médio incompleto",
                                          "Médio completo",
                                          "Superior incompleto","Superior completo")))


resumo_escolaridade <- ocupados3 |>
  filter(!is.na(escolaridade)) |>
  group_by(categoria_emprego, escolaridade) |>
  summarise(n = survey_total(na.rm = TRUE)) |>
  group_by(categoria_emprego) |>
  mutate(freq_relativa = n / sum(n) * 100)

ggplot(resumo_escolaridade, aes(x = categoria_emprego, y = freq_relativa, fill = escolaridade)) +
  geom_bar(stat = "identity", position = "stack") +
  scale_y_continuous(labels = scales::percent_format(scale = 1)) +
  labs(title = "Distribuição Percentual da Escolaridade \n por Categoria de Emprego",
       x = "Categoria de Emprego",
       y = "Frequência Relativa (%)",
       fill = "Faixa de Escolaridade") +
  theme_minimal()

4.1.3 E a questão regional?

ufs_labels <- c(
  "11" = "RO", "12" = "AC", "13" = "AM", "14" = "RR", "15" = "PA",
  "16" = "AP", "17" = "TO", "21" = "MA", "22" = "PI", "23" = "CE",
  "24" = "RN", "25" = "PB", "26" = "PE", "27" = "AL", "28" = "SE",
  "29" = "BA", "31" = "MG", "32" = "ES", "33" = "RJ", "35" = "SP",
  "41" = "PR", "42" = "SC", "43" = "RS", "50" = "MT", "51" = "MS",
  "52" = "GO", "53" = "DF")

ocupados3 <- ocupados3 |>
  mutate(uf_sigla = ufs_labels[as.character(UF)])

# Filtro apenas para duas categorias para não ficar poluído
dados_plot_uf <- ocupados3 |>
  filter(categoria_emprego %in% c("formal", "cnpj")) |>
  mutate(UF_label = factor(ufs_labels[as.character(UF)], levels = ufs_labels))

# Selecionar só UFs que tenham os dois grupos: formal e cnpj
ufs_completas <- dados_plot_uf |>
  group_by(UF_label, categoria_emprego) |>
  summarise(contagem = n(), .groups = 'drop') |>
  pivot_wider(names_from = categoria_emprego, values_from = contagem, values_fill = 0) |>
  filter(formal > 0 & cnpj > 0) |>
  pull(UF_label)

# Filtrar pelos UFs completos e criar fator para categoria de emprego
dados_plot_uf <- dados_plot_uf |>
  filter(UF_label %in% ufs_completas) |>
  mutate(categoria_emprego = factor(categoria_emprego, levels = c("formal", "cnpj")))

# Calcular medianas por UF e categoria de emprego para mostrar no gráfico
medianas_uf <- dados_plot_uf |>
  group_by(UF_label, categoria_emprego) |>
  summarise(mediana = survey_median(salario_hora, na.rm = TRUE), .groups = 'drop')

# Boxplot com facet_wrap por UF
ggplot(dados_plot_uf, aes(x = categoria_emprego, y = salario_hora, fill = categoria_emprego)) +
  geom_boxplot(alpha = 0.7, outlier.colour = "red") +
  geom_text(data = medianas_uf, 
            aes(x = categoria_emprego, 
                y = mediana, 
                label = paste0("R$ ", round(mediana, 2))),
            vjust = -0.5, color = "black", fontface = "bold", size = 4) +
  scale_y_continuous(labels = scales::dollar_format(prefix = "R$ ")) +
  coord_cartesian(ylim = c(0, 75)) +
  labs(title = "Distribuição do Salário-Hora por Categoria de Emprego e UF\n(visualização até R$ 75)",
       x = "Categoria de Emprego",
       y = "Salário-Hora") +
  facet_wrap(~ UF_label, scales = "free_x", ncol = 5) +
  theme_minimal(base_size = 14) +
  theme(legend.position = "none")

4.1.4 Contribuição Previdenciária

resumo_contribuinte <- ocupados3 |>
  filter(categoria_emprego %in% c("formal", "cnpj")) |>
  mutate(contribuinte_cat = case_when(VD4012 == 1 ~ "Contribuinte",
                                      VD4012 == 2 ~ "Não contribuinte",
                                      TRUE ~ "Não aplicável")) |>
  group_by(categoria_emprego, contribuinte_cat) |>
  summarise(n = survey_total(na.rm = TRUE)) |>
  group_by(categoria_emprego) |>
  mutate(prop = n / sum(n)) |>
  ungroup()

ggplot(resumo_contribuinte, aes(x = categoria_emprego, y = prop, fill = contribuinte_cat)) +
  geom_col(position = "fill") +
  scale_y_continuous(labels = scales::percent_format()) +
  labs(title = "Proporção de Contribuintes por Categoria de Emprego",
       x = "Categoria de Emprego",
       y = "Proporção (%)",
       fill = "Categoria de Contribuinte") +
  theme_minimal()

4.2 Grupo-Base - Profissões

Para a análise das profissões foram criados três objetos.

tab_total que sumariza o total por profissão (grupo_base).

tab_formal que sumariza por trabalhadores formais

tab_cnpj que sumariza por trabalhadores por conta-própria que possuem CNPJ

Foram criadas duas variáveis auxiliares para análise: a dif_perc_cnpj_formal que consiste em verificar a relação percentual da média entre o salário-hora do CNPJ e o salário-hora do formal e a *dif_perc_medianas_cnpj_formal** para verificar a mesma relação, mas a partir da mediana.

Uma análise adequada a partir das profissões deve considerar as duas variáveis em conjunto.

tab_total <- ocupados3 |> 
  group_by(grupo_base) |> 
  summarise(total = survey_total(na.rm = TRUE),
            salario_hora = survey_mean(salario_hora, na.rm = TRUE))

tab_total <- tab_total |> 
  mutate(total_cv = 100 * total_se / total)

tab_formal <- ocupados3 |> 
  filter(categoria_emprego == "formal") |>
  group_by(grupo_base) |> 
  summarise(total_formal = survey_total(),
            salario_hora_formal = survey_mean(salario_hora, na.rm = TRUE, vartype = "se"))

tab_formal <- tab_formal |> 
  mutate(total_formal_cv = 100 * total_formal_se / total_formal)

tab_cnpj <- ocupados3 |> 
  filter(categoria_emprego == "cnpj") |>
  group_by(grupo_base) |> 
  summarise(total_cnpj = survey_total(),
            salario_hora_cnpj = survey_mean(salario_hora, na.rm = TRUE, vartype = "se"))

tab_cnpj <- tab_cnpj |> 
  mutate(total_cnpj_cv = 100 * total_cnpj_se / total_cnpj)

tab_geral <- tab_total |> 
  full_join(tab_formal, by = "grupo_base") |> 
  full_join(tab_cnpj, by = "grupo_base")

#Variável Auxiliar - Diferença entre CNPJ e Formal
#Se CNPJ > Formal = positivo
tab_geral <- tab_geral |> 
  mutate(dif_perc_cnpj_formal = 100 * (salario_hora_cnpj - salario_hora_formal) / salario_hora_formal)

# Indicadores de precisão - Coeficiente de variação acima de 25%
tab_geral <- tab_geral |> 
  mutate(low_precision_formal = total_formal_cv > 25, #indicadores de baixa precisão - coeficiente de variação acima de 25%
    low_precision_cnpj = total_cnpj_cv > 25,
    total_formal_exib = if_else(low_precision_formal, "NS", format(round(total_formal, 0), big.mark = ",")),
    total_cnpj_exib = if_else(low_precision_cnpj, "NS", format(round(total_cnpj, 0), big.mark = ",")),
    salario_hora_formal_exib = if_else(low_precision_formal, "NS", format(round(salario_hora_formal, 2))),
    salario_hora_cnpj_exib = if_else(low_precision_cnpj, "NS", format(round(salario_hora_cnpj, 2))),
    dif_perc_cnpj_formal = if_else(
      low_precision_formal | low_precision_cnpj,
      NA_real_,
      100 * (salario_hora_cnpj - salario_hora_formal) / salario_hora_formal))

Medianas

medianas_formal <- ocupados3 |> 
  filter(categoria_emprego == "formal") |>
  group_by(grupo_base) |> 
  summarise(mediana_salario_hora_formal = survey_median(salario_hora, na.rm = TRUE, vartype = "se"),
            mediana_salario_hora_formal_se = attr(mediana_salario_hora_formal, "se"))

medianas_cnpj <- ocupados3 |> 
  filter(categoria_emprego == "cnpj") |>
  group_by(grupo_base) |> 
  summarise(mediana_salario_hora_cnpj = survey_median(salario_hora, na.rm = TRUE, vartype = "se"),
            mediana_salario_hora_cnpj_se = attr(mediana_salario_hora_cnpj, "se"))

# Indicadores de precisão para medianas
tab_geral <- tab_geral |> 
  left_join(medianas_formal, by = "grupo_base") |>
  left_join(medianas_cnpj, by = "grupo_base") |>
  mutate(
    # CV das medianas
    mediana_formal_cv = 100 * mediana_salario_hora_formal_se / mediana_salario_hora_formal,
    mediana_cnpj_cv = 100 * mediana_salario_hora_cnpj_se / mediana_salario_hora_cnpj,
    
    # Indicadores de baixa precisão
    low_precision_median_formal = mediana_formal_cv > 25,
    low_precision_median_cnpj = mediana_cnpj_cv > 25,
    
    # Exibição condicional para medianas
    mediana_salario_hora_formal_exib = if_else(low_precision_median_formal, "NS", format(round(mediana_salario_hora_formal, 2))),
    mediana_salario_hora_cnpj_exib = if_else(low_precision_median_cnpj, "NS", format(round(mediana_salario_hora_cnpj, 2))),
    
    # Diferença % medianas condicionada à precisão
    dif_perc_medianas_cnpj_formal = if_else(
      low_precision_median_formal | low_precision_median_cnpj,
      NA_real_,
      100 * (mediana_salario_hora_cnpj - mediana_salario_hora_formal) / mediana_salario_hora_formal))

4.3 Tabela de Resultados - Grupo-Base de Profissões

A tabela abaixo apresenta os resultados a partir do dado mais granular: as profissões.

É importante fazer uma leitura que considere os números ponderados, as médias e também as medianas.

tab_geral_sem_se <- tab_geral |> 
  select(
    grupo_base,
    total,
    total_formal,
    total_cnpj,
    salario_hora,
    salario_hora_formal,
    salario_hora_cnpj,
    dif_perc_cnpj_formal,
    mediana_salario_hora_formal_exib,
    mediana_salario_hora_cnpj_exib,
    dif_perc_medianas_cnpj_formal) |> 
  arrange(desc(total_cnpj))

colnames(tab_geral_sem_se) <- c(
  "Profissão",
  "Total da Profissão",
  "Total Formal",
  "Total CNPJ",
  "Salário-hora - Profissão (Média)",
  "Salário-hora Formal (Média)",
  "Salário-hora CNPJ (Média)",
  "Dif. % Média CNPJ vs. Formal",
  "Mediana Formal",
  "Mediana CNPJ",
  "Dif. % Mediana CNPJ vs. Formal")

# Atualizar o datatable para exibir e formatar as novas colunas
datatable(tab_geral_sem_se,
  options = list(
    pageLength = 20,
    columnDefs = list(
      list(targets = 0, createdCell = JS("function(td){$(td).css({'border-right': '4px double #333'});}")),
      list(targets = 3, createdCell = JS("function(td){$(td).css({'border-right': '4px double #333'});}")),
      list(targets = 7, createdCell = JS("function(td){$(td).css({'border-right': '4px double #333'});}")),
      list(targets = 10, createdCell = JS("function(td){$(td).css({'border-right': '4px double #333'});}"))
      #list(targets = 10, createdCell = JS("function(td){$(td).css({'border-right': '4px double #333'});}"))
    )
  ),
  rownames = FALSE,
  class = 'cell-border stripe',
  caption = htmltools::tags$caption(
    style = 'caption-side: top; text-align: left; font-size: 16px; font-weight: bold;',
    "Tabela Comparativa por Profissões com Médias e Medianas",
    htmltools::tags$div(
      style = 'font-size: 12px; font-weight: normal; color: gray; margin-top: 4px;',
      "Nota: Valores com coeficiente de variação acima de 25% foram retirados --- A ordenação-padrão está em ordem decrescente para o Total de CNPJ" 
    ))
) |> 
  formatCurrency(columns = c('Salário-hora - Profissão (Média)', 'Salário-hora Formal (Média)', 'Salário-hora CNPJ (Média)', 
                            'Dif. % Média CNPJ vs. Formal', 'Mediana Formal', 
                            'Mediana CNPJ', 'Dif. % Mediana CNPJ vs. Formal'), currency = "", digits = 2, interval = 3, mark = "."
  ) |> 
  formatRound(
    columns = c('Total da Profissão', 'Total Formal', 'Total CNPJ'),
    digits = 0, mark = "."
  ) |>
  formatStyle(
    columns = 1:ncol(tab_geral_sem_se),
    fontFamily = "Calibri, sans-serif")

4.3.1 Conclusões Parciais

Uma análise a partir das profissões nos permite avaliar distintas questões:

Em números absolutos, as 5 profissões com mais trabalhadores são:

  • Escriturário Geral (ou seja, trabalhadores de apoio administrativo geral)
  • Balconistas e vendedores de lojas
  • Trabalhadores dos serviços domésticos em geral
  • Comerciantes de lojas
  • Trabalhadores de limpeza de interior de edifícios, escritórios, hotéis e outros estabelecimentos

Em números absolutos, as 5 profissões com mais trabalhadores formalizados são:

  • Balconistas e vendedores de lojas
  • Escriturários gerais
  • Trabalhadores de limpeza de interior de edifícios, escritórios, hotéis e outros estabelecimentos
  • Condutores de caminhões pesados
  • Guardas de segurança

Em números absolutos, as 5 profissões com mais trabalhadores por cont-própria que possuem CNPJ são:

  • Comerciantes de lojas
  • Cabeleireiros
  • Especialistas em tratamento de beleza e afins
  • Condutores de automóveis, taxis e caminhonetes
  • Pedreiros

Uma análise da tabela com uma desagregação muito grande deve considerar os valores de salário-hora a partir do número ponderado de profissionais.

Assim, as cinco maiores médias de salário-hora de formalizados, que considere somente acima de 20 mil profissionais, são as seguintes profissões:

  • Médicos especialistas - R$ 54.14
  • Engenheiros mecânicos - R$ 45.17
  • Dirigentes de serviços de tecnologia da informação e comunicações - R$ 45.11
  • Engenheiros industriais e de produção - R$ 42.21
  • Engenheiros não classificados anteriormente - R$ 38.74

Por sua vez, as cinco maiores médias de salário-hora de conta-própria com CNPJ, que considere somente acima de 20 mil profissionais, são as seguintes profissões:

  • Médicos especialistas - R$ 50.89
  • Analistas de sistemas - R$ 43.11
  • Advogados e juristas - R$ 34.99
  • Engenheiros civis - R$ 34.46
  • Analista de Gestão e Administração - R$ 33.51

Dado o objetivo do estudo, entretanto, é relevante direcionar o olhar para a diferença entre profissionais de ocupação semelhante. Nesse sentido, é importante sempre olhar a diferença a partir de uma análise coordenada de média e mediana. A partir do qual pode-se concluir:

As maiores diferenças em que é o PJ recebe mais que o formalizado encontram-se nas seguintes profissões

  • Agentes imobiliários - onde um PJ (~89 mil) recebe uma média de R$ 30,50 e o CLT (~29 mil) recebe uma média de R$ 16,09. A análise da mediana também indica uma diferença relevante com formal a R$ 11.69 e PJ a R$ 24,72. É importante destacar, entretanto que a maioria dos profissionais (cerca de 63%) não estão em nenhuma dessas duas classificações.

Análise semelhante deve ser feita para Especialistas em tratamento de beleza e afins que apresenta diferença significativa entre as duas categorias (82% a mais para PJ na média e 56% a mais na mediana), mas tem-se cerca de 75% de todos os profissionais fora dessas duas categorias.

As demais diferenças que podem ser destacadas estão nas seguintes profissões:

  • Trabalhadores de agências de viagem
  • Condutores de automóveis, taxis e caminhonetes
  • Representantes comerciais
  • Lavadores de veículos
  • Condutores de caminhões pesados

4.4 Grupamentos de Atividade

vd4010_labels <- c(
  "01" = "Agricultura, pecuária, produção florestal, pesca e aquicultura",
  "02" = "Indústria geral",
  "03" = "Construção",
  "04" = "Comércio, reparação de veículos automotores e motocicletas",
  "05" = "Transporte, armazenagem e correio",
  "06" = "Alojamento e alimentação",
  "07" = "Informação, comunicação e atividades financeiras, imobiliárias, profissionais e administrativas",
  "08" = "Administração pública, defesa e seguridade social",
  "09" = "Educação, saúde humana e serviços sociais",
  "10" = "Outros Serviços",
  "11" = "Serviços domésticos",
  "12" = "Atividades mal definidas")

ocupados3 <- ocupados3 |>
  mutate(VD4010_label = vd4010_labels[as.character(VD4010)])

resumo_salario <- ocupados3 |>
  group_by(VD4010_label, categoria_emprego) |>
  summarise(salario_medio = mean(salario_hora, na.rm = TRUE),
            n = survey_total(na.rm = TRUE)) |>
  ungroup() |>
  mutate(n_label = paste0("n = ", scales::comma(round(as.numeric(n)))))

# Gráfico de barras com facet
ggplot(resumo_salario, aes(x = categoria_emprego, y = salario_medio, fill = categoria_emprego)) +
  geom_col(position = "dodge") +
  geom_text(aes(label = paste0("n=", scales::comma(round(n))), y = salario_medio + max(salario_medio, na.rm = TRUE) * 0.03),
            position = position_dodge(width = 0.9), size = 4, color = "black") +
  facet_wrap(~ VD4010_label, scales = "free_y", ncol = 3,
             labeller = labeller(VD4010_label = label_wrap_gen(width = 40))) +
  scale_y_continuous(labels = scales::dollar_format(prefix = "R$ ")) +
  labs(title = "Média do Salário-Hora por Categoria de Emprego e Atividade\n(n ponderado por barra)",
       x = "Categoria de Emprego",
       y = "Salário-Hora Médio") +
  theme_minimal(base_size = 13) +
  theme(axis.text.x = element_text(angle = 0, hjust = 0.5), legend.position = "none")

max_salario <- 50 # ponto próximo da borda direita do gráfico, tendo em vista outliers

#Boxplot
ggplot(ocupados3, aes(x = salario_hora, y = categoria_emprego, fill = categoria_emprego)) +
  geom_boxplot(alpha = 0.7, outlier.colour = "red") +
  facet_wrap(~ VD4010_label, scales = "free_y", ncol = 3,
             labeller = labeller(VD4010_label = label_wrap_gen(width = 40))) +
  scale_x_continuous(labels = dollar_format(prefix = "R$ ")) +
  coord_cartesian(xlim = c(0, 60)) +
  labs(
    title = "Distribuição do Salário-Hora por Categoria de Emprego e Atividade\n(Limite de visualização: R$ 60)",
    x = "Salário-Hora",
    y = "Categoria de Emprego") +
  theme_minimal(base_size = 13) +
  theme(legend.position = "none") +
  geom_text(
    data = resumo_salario,
    mapping = aes(x = max_salario, y = categoria_emprego, label = n_label),
    inherit.aes = FALSE,
    hjust = 0,
    size = 3)

4.5 Grupamentos Ocupacionais

# Dicionário dos rótulos das ocupações - VD4011
vd4011_labels <- c(
  "01" = "Diretores e gerentes",
  "02" = "Profissionais das ciências e intelectuais",
  "03" = "Técnicos e profissionais de nível médio",
  "04" = "Trabalhadores de apoio administrativo",
  "05" = "Trabalhadores dos serviços, vendedores dos comércios e mercados",
  "06" = "Trabalhadores qualificados da agropecuária, florestais, da caça e da pesca",
  "07" = "Trabalhadores qualificados, operários e artesões da construção, das artes mecânicas e outros ofícios",
  "08" = "Operadores de instalações e máquinas e montadores",
  "09" = "Ocupações elementares",
  "10" = "Membros das forças armadas, policiais e bombeiros militares",
  "11" = "Ocupações maldefinidas")

ocupados3 <- ocupados3 |>
  mutate(VD4011_label = vd4011_labels[as.character(VD4011)] |> factor(levels = vd4011_labels))

resumo_salario2 <- ocupados3 |>
  group_by(VD4011_label, categoria_emprego) |>
  summarise(salario_medio = mean(salario_hora, na.rm = TRUE),
            n = survey_total(na.rm = TRUE)) |>
  ungroup() |>
  mutate(n_label = paste0("n = ", scales::comma(round(as.numeric(n)))))

# Gráfico de barras com facet
ggplot(resumo_salario2, aes(x = categoria_emprego, y = salario_medio, fill = categoria_emprego)) +
  geom_col(position = "dodge") +
  geom_text(aes(label = paste0("n=", scales::comma(round(n))), y = salario_medio + max(salario_medio, na.rm = TRUE) * 0.03),
            position = position_dodge(width = 0.9), size = 4, color = "black") +
  facet_wrap(~ VD4011_label, scales = "free_y", ncol = 3,
             labeller = labeller(VD4011_label = label_wrap_gen(width = 40))) +
  scale_y_continuous(labels = scales::dollar_format(prefix = "R$ ")) +
  labs(title = "Média do Salário-Hora por Categoria de Emprego e Grupo Ocupacional\n(n ponderado por barra)",
       x = "Grupo Ocupacional",
       y = "Salário-Hora Médio") +
  theme_minimal(base_size = 13) +
  theme(axis.text.x = element_text(angle = 0, hjust = 0.5), legend.position = "none")

# Plot boxplot horizontal com n como texto
ggplot(ocupados3, aes(x = salario_hora, y = categoria_emprego, fill = categoria_emprego)) +
  geom_boxplot(alpha = 0.7, outlier.colour = "red") +
  facet_wrap(~ VD4011_label, scales = "free_y", ncol = 3,
             labeller = labeller(VD4011_label = label_wrap_gen(width = 40))) +
  scale_x_continuous(labels = dollar_format(prefix = "R$ ")) +
  coord_cartesian(xlim = c(0, 60)) +
  labs(title = "Distribuição do Salário-Hora por Categoria de Emprego e Grupamento Ocupacional\n(Limite de visualização: R$ 100)",
       x = "Salário-Hora",
       y = "Categoria de Emprego") +
  theme_minimal(base_size = 13) +
  theme(legend.position = "none") +
  geom_text(data = resumo_salario2,
            mapping = aes(x = max_salario, y = categoria_emprego, label = n_label),
            inherit.aes = FALSE,
            hjust = 0,
            size = 3)

5 Análise Inferencial

5.1 Mincer

Existe uma diferença salarial entre a condição “Conta-Própria com CNPJ” e “Formal - CLT”.

A pergunta que se coloca, entretanto, é: o quanto essa diferença salarial deve-se à condição PJ/Formal?

Para isso, vamos fazer um modelo de regressão a partir das equações de Mincer.

5.1.1 Recodificação de Variáveis

No código abaixo foi criado o log(salario_hora), colocados os rótulos para sexo e raça/cor.

Além disso, será criada a variável idade_centralizada que consiste em

\[ \text{Idade_Centralizada}_{i} = Idade_{i} - \overline{Idade} \] Essa variável permite diminuir a multicolinearidade entre idade e idade^2

Para uma aproximação da variavel experiência será feito o seguinte cálculo

\[ \text{Experiência} = Idade - Anos de Escolaridade - 5 \]

ocupados3 <- ocupados3 |>
  mutate(
    # log do salário-hora (apenas se válido)
    ln_salario_hora = if_else(salario_hora > 0, log(salario_hora), NA_real_),
    
    # Sexo
    sexo = factor(V2007,
      levels = c(1, 2),
      labels = c("Homem", "Mulher")),
    
    # Raça
    raca = factor(V2010,
      levels = c(1, 2, 3, 4, 5, 9),
      labels = c("Branca", "Preta", "Amarela", "Parda", "Indígena", "Ignorado")),
    
    # Idade
    idade = as.numeric(V2009),

    # Anos de escolaridade (converter de character p/ numeric)
    anos_escolaridade = as.numeric(VD3005)) |>
  mutate(
    # Idade centralizada pela média
    idade_centralizada = idade - mean(idade, na.rm = TRUE),

    # Experiência potencial
    experiencia = idade - anos_escolaridade - 5,
    
    # Experiência centralizada pela média
    experiencia_c = experiencia - mean(experiencia, na.rm = TRUE))

5.1.2 Regressões

A equação de Mincer pode ser expressa como:

\[ \ln(w_i) = \beta_0 + \beta_1 Escolaridade_i + \beta_2 Experiência_i + \beta_3 Experiência_i^2 + \varepsilon_i \] O modelo estimado é dado por:

\[ \begin{aligned} \ln(\text{SalárioHora}_i) =\ & \beta_0 + \beta_1 \text{Categoria de Emprego}_i + \beta_2 \overline{Experiência}_i \\ &+ \beta_3 \overline{Experiência}_i^2 + \beta_4 \text{Raça}_i \\ &+ \beta_5 \text{Sexo}_i + \beta_6 \text{SetorAtividade}_i + \varepsilon_i \end{aligned} \]

Foram realizados dois testes:

1 - O primeiro que utiliza idade_centralizada + idade_centralizada^2 2 - O segundo que utiliza o proxy experiencia_centralizada

Em ambos os modelos o poder explicativo ficou em 25%. Assim, para manter fidelidade com o modelo de Mincer optou-se por seguir

#Não substituir UF e VD4010 pelos labels porque o tempo de processamento aumenta demais
library(jtools)
modelo_mincer <- summ(
  svyglm(ln_salario_hora ~ categoria_emprego + anos_escolaridade + experiencia_c + I(experiencia_c^2) + raca + sexo + VD4010,
  design = ocupados3,
  family = gaussian()),
  digits = 2, confint = FALSE)

coefs <- modelo_mincer$coeftable |> 
  as.data.frame() |> 
  rownames_to_column("term")

# filtrar para p <= 0.05 e sem o intercepto
sig_coefs <- coefs |>
  filter(p <= 0.05, term != "(Intercept)") |>
  pull(term)

plot_summs(modelo_mincer, coefs = sig_coefs)

#Referências
#CNPJ
#Escolaridade - Sem Instrução
#Raça - Branca
#Sexo - Masculino
#VD4010 1 - Agricultura, pecuária, produção florestal, pesca e aquicultura 

#Percentual

library(broom)
resultados <- broom::tidy(modelo_mincer) |>
  mutate(efeito_pct = (exp(estimate) - 1) * 100,   # transformar log em %
         signif = ifelse(p.value < 0.05, "Significativo", "Não significativo"))

#apenas significativos
resultados_sig <- resultados |>
  filter(signif == "Significativo") |>
  select(term, estimate, efeito_pct, std.error, statistic, p.value)

# renomear colunas
resultados_sig <- resultados_sig |>
  rename(Variável = term,
         Coef_Log = estimate,
         `Efeito (%)` = efeito_pct,
         `Erro Padrão` = std.error,
         `t valor` = statistic,
         `p-valor` = p.value)

library(kableExtra)

resultados_sig |>
  kable(digits = 2, caption = "Efeitos percentuais significativos no salário-hora (modelo Mincer)") |>
  kable_styling(full_width = FALSE, position = "center")
Efeitos percentuais significativos no salário-hora (modelo Mincer)
Variável Coef_Log Efeito (%) Erro Padrão t valor p-valor
(Intercept) 1.84 532.77 0.02 109.93 0.00
categoria_empregoformal -0.19 -17.37 0.01 -18.79 0.00
categoria_empregooutros -0.26 -22.95 0.01 -24.87 0.00
anos_escolaridade 0.08 8.22 0.00 89.07 0.00
experiencia_c 0.01 1.16 0.00 68.89 0.00
I(experiencia_c^2) 0.00 -0.02 0.00 -23.57 0.00
racaPreta -0.18 -16.33 0.01 -28.67 0.00
racaParda -0.18 -16.66 0.00 -44.07 0.00
racaIndígena -0.20 -18.26 0.03 -6.80 0.00
sexoMulher -0.19 -16.95 0.00 -48.13 0.00
VD401002 0.21 22.77 0.01 19.07 0.00
VD401003 0.17 19.07 0.01 16.11 0.00
VD401004 0.08 8.09 0.01 7.02 0.00
VD401005 0.20 21.61 0.01 16.56 0.00
VD401006 0.04 3.84 0.01 3.11 0.00
VD401007 0.31 36.41 0.01 28.22 0.00
VD401008 0.54 72.18 0.01 44.64 0.00
VD401009 0.40 49.58 0.01 35.17 0.00
VD401010 0.13 14.20 0.01 10.46 0.00
VD401011 0.02 2.51 0.01 2.05 0.04

Colinearidade

Muita colinearidade para UF

# usa os dados que estão dentro do design survey
data_svy <- ocupados3$variables

# monta a matrix de regressors como o modelo que você citou
mm <- model.matrix(~ categoria_emprego + anos_escolaridade + experiencia_c + I(experiencia_c^2) + sexo + raca + VD4010,
                   data = data_svy)

# remove a coluna do intercepto
preds <- as.data.frame(mm[, -1, drop = FALSE])

# obtém os pesos de amostra do design (tipo "sampling")
wt <- weights(ocupados3, type = "sampling")

# função para R2 ponderado (usaremos em lm com weights)
weighted_R2 <- function(y, yhat, w) {
  # soma dos quadrados dos resíduos ponderados
  sse <- sum(w * (y - yhat)^2, na.rm = TRUE)
  # soma total ponderada
  ybar_w <- stats::weighted.mean(y, w, na.rm = TRUE)
  sst <- sum(w * (y - ybar_w)^2, na.rm = TRUE)
  1 - sse / sst
}

# calcula VIF para cada coluna da matrix de regressors
vif_table <- data.frame(variable = character(), R2 = numeric(), VIF = numeric(), stringsAsFactors = FALSE)

for (j in seq_len(ncol(preds))) {
  y <- preds[[j]]
  Xother <- preds[, -j, drop = FALSE]

  # monta data frame temporário
  df_tmp <- cbind(y = y, Xother)

  # regressão ponderada com lm (resposta y contra os demais)
  fit <- lm(y ~ ., data = df_tmp, weights = wt)

  # prediz e calcula R2 ponderado
  yhat <- predict(fit, newdata = df_tmp)
  R2w <- weighted_R2(y, yhat, wt)

  vif_j <- 1 / (1 - R2w)
  vif_table <- rbind(vif_table, data.frame(variable = colnames(preds)[j], R2 = R2w, VIF = vif_j))
}

# ordena e mostra
vif_table[order(-vif_table$VIF), ]

O modelo explica cerca de 32% da diferença salarial.

Formais ganham, em média, cerca de 19% menos que o conta-própria com CNPJ, mantendo escolaridade, idade, raça, sexo, e setor econômico fixos.

Mas qual variável conta mais?

5.2 Comparar modelos

Testando função para ver o incremento

# Função compacta para calcular pseudo-R² para svyglm (Gaussian)
pseudo_r2 <- function(model) {
  y <- model$y
  yhat <- model$fitted.values
  ss_res <- sum((y - yhat)^2)
  ss_tot <- sum((y - mean(y))^2)
  1 - ss_res / ss_tot}

# Ajuste incremental, reutilizando o objeto de design e limpando explicitamente
r2s <- numeric(0)

formulas <- list(
  ln_salario_hora ~ categoria_emprego,
  ln_salario_hora ~ categoria_emprego + sexo,
  ln_salario_hora ~ categoria_emprego + sexo + raca,
  ln_salario_hora ~ categoria_emprego + sexo + raca + VD4010,
  ln_salario_hora ~ categoria_emprego + sexo + raca + VD4010 + anos_escolaridade,
  ln_salario_hora ~ categoria_emprego + sexo + raca + VD4010 + anos_escolaridade + experiencia_c,
  ln_salario_hora ~ categoria_emprego + sexo + raca + VD4010 + anos_escolaridade + experiencia_c + I(experiencia_c^2)
)

for (f in formulas) {
  modelo <- svyglm(f, design = ocupados3, family = gaussian())
  r2s <- c(r2s, pseudo_r2(modelo))
  rm(modelo) # remove objeto grande
  gc() # força o garbage collector a liberar memória
}

names(r2s) <- c("categoria_emprego", "+sexo", "+raça", "+grupo_ativ", "+escolaridade", "+experiencia", "+experiencia2")
print(r2s)
## categoria_emprego             +sexo             +raça       +grupo_ativ 
##        0.01351587        0.01244125        0.05583003        0.20438819 
##     +escolaridade      +experiencia     +experiencia2 
##        0.28018363        0.31889390        0.32297245

5.2.1 Conclusões Parciais

Ainda que exista uma diferença entre as categorias de emprego percebe-se que o fator que mais influencia o salário-hora é a escolaridade e o grupo de atividade.

A categoria emprego sozinha explica cerca de 1% da variação salarial.

5.3 Propensity Score Matching

Propensity Score Matching cria um grupo de controle artificial para comparar com o grupo de tratamento, com o objetivo de eliminar vieses.

A escolha por esse teste permite responder à pergunta:

“Dados dois trabalhadores com perfis semelhantes (mesma escolaridade, experiência, sexo e raça), como fica a diferença salário-hora entre aquele formalizado e conta-própria com CNPJ?”

library(MatchIt)

# Variável de tratamento
ocupados_psm <- ocupados3$variables |>
  filter(categoria_emprego %in% c("formal", "cnpj")) |>
  mutate(formal = if_else(categoria_emprego == "formal", 1, 0),
         formal = factor(formal, levels = c(0, 1), labels = c("Conta própria", "Formal")))

ocupados_psm <- as.data.frame(ocupados_psm)

# Matching com logit 
# Foi retirado VD4010 pois demorava cerca de 40 minutos.
system.time({
psm_model <- matchit(formal ~ sexo + raca + anos_escolaridade + experiencia_c + I(experiencia_c^2),
                     data = ocupados_psm,
                     method = "nearest",
                     distance = "logit")
})
##   usuário   sistema decorrido 
##     47.97      2.63     51.64
matched_data <- match.data(psm_model)

library(cobalt)
love.plot(psm_model, binary = "std")  # gráfico de diferenças padronizadas

5.3.1 Teste t

t_test <- t.test(salario_hora ~ formal, data = matched_data, weights = weights)
t_test
## 
##  Welch Two Sample t-test
## 
## data:  salario_hora by formal
## t = 74.234, df = 12181, p-value < 2.2e-16
## alternative hypothesis: true difference in means between group Conta própria and group Formal is not equal to 0
## 95 percent confidence interval:
##  10.77835 11.36300
## sample estimates:
## mean in group Conta própria        mean in group Formal 
##                   20.512122                    9.441448
# Visualizar balanceamento (standardized mean differences)
#plot(psm_model, type = "jitter", interactive = FALSE)
#plot(psm_model, type = "qq")
#plot(psm_model, type = "hist")

matched_data$final_weights <- matched_data$weights * matched_data$V1028

options(survey.lonely.psu = "adjust")

design_psm <- svydesign(
  ids = ~1,  # ignora cluster
  weights = ~final_weights,
  data = matched_data
)

# Teste t ponderado
svy_test <- svyttest(salario_hora ~ formal, design = design_psm)
svy_test
## 
##  Design-based t-test
## 
## data:  salario_hora ~ formal
## t = -53.95, df = 21342, p-value < 2.2e-16
## alternative hypothesis: true difference in mean is not equal to 0
## 95 percent confidence interval:
##  -11.76878 -10.94361
## sample estimates:
## difference in mean 
##          -11.35619

O test t indica R$ 20,51 para conta própria e R$ 9,44 para o formalizado (cerca de R$ 11,07 a menos) O test t para objeto do tipo survey indica uma diferença de cerca de -R$ 11,35 para o formalizado

5.4 Quantílica com PSM

Como já foi possível visualizar, especialmente na parte de análise descritiva, as variáveis que envolvem salários tem boxplots com o terceiro quartil mais alongado e o quarto quartil com muitos outliers.

Assim, a pergunta seguinte é:

A diferença salário-hora entre formais e PJs se mantêm entre todos os níveis salariais?

Para responder essa pergunta será feita uma análise quantílica. Ou seja, o salário-hora será dividido em dez partes e será observado o comportamento diferencial entre cada decil.

library(quantreg)

taus <- seq(0.0, 1.0, by = 0.1)
rq_model_all <- rq(salario_hora ~ formal, 
                   data = matched_data, 
                   tau = taus, 
                   weights = weights)

system.time({
rq_summary <- summary(rq_model_all, se = "boot", R = 50)
})
##   usuário   sistema decorrido 
##    108.61      0.22    109.98

5.4.1 Resultados

#Sys.setlocale("LC_ALL", "pt_BR.UTF-8")

results <- do.call(rbind, lapply(rq_summary, function(s) {
  data.frame(
    tau = s$tau,
    coef = s$coefficients["formalFormal", 1],
    se   = s$coefficients["formalFormal", 2]
  )}))

#erros-padrão
results <- results |>
  mutate(lower = coef - 1.96 * se,
         upper = coef + 1.96 * se,
         type = "Quantílico")

#resultados dos dois tests t - adicionados
mean_effects <- data.frame(
  tau = c(0.5, 0.5),
  coef = c(t_test$estimate[2] - t_test$estimate[1], svy_test$estimate),     # Formal - Conta própria
  lower = c(-t_test$conf.int[2], svy_test$conf.int[1]),                     # Inverta upper (vai para lower)
  upper = c(-t_test$conf.int[1], svy_test$conf.int[2]),                     # Inverta lower (vai para upper)
  type = c("T-test", "Svy T-test"))

plot_data <- bind_rows(results, mean_effects)

g1 <- ggplot() +
  # efeitos quantílicos
  geom_line(data = results, aes(x = tau, y = coef, color = type), size = 1) +
  geom_point(data = results, aes(x = tau, y = coef, color = type), size = 2) +
  geom_ribbon(data = results, aes(x = tau, ymin = lower, ymax = upper, fill = type), alpha = 0.15) +

  # rótulos nos efeitos quantílicos
  geom_text(data = results, 
            aes(x = tau, y = coef, label = round(coef, 1), color = type), 
            vjust = -1, size = 3.5, show.legend = FALSE) +

  # médias destacadas
  geom_point(data = mean_effects, aes(x = tau, y = coef, shape = type, color = type), size = 4) +
  geom_errorbar(data = mean_effects, aes(x = tau, ymin = lower, ymax = upper, color = type), 
                width = 0.05, size = 1) +

  # rótulos nas médias
  geom_text(data = mean_effects, 
            aes(x = tau, y = coef, label = round(coef, 1), color = type), 
            vjust = -1.2, size = 4, fontface = "bold", show.legend = FALSE) +

  # linha de referência
  geom_hline(yintercept = 0, linetype = "dashed", color = "red") +

  # eixo de 0% a 100%
  scale_x_continuous(breaks = seq(0, 1, 0.1),  # decil a decil
                     labels = scales::percent) +

  labs(x = "Quantil da distribuição salarial",
       y = "Diferença (Formal - Conta própria)",
       title = "Diferença Salário-Hora (Formal vs PJ) por Decil - Usando PSM \n Efeitos médios (t-test / survey t-test) vs quantílicos") +
  theme_minimal(base_size = 14)

g1

5.4.2 Composição dos Quantis

library(Hmisc)

# Calcular os cortes de salário-hora ponderados
quantile_cuts <- Hmisc::wtd.quantile(matched_data$salario_hora,
                                     weights = matched_data$final_weights,
                                     probs = taus)

quantile_cuts
##        0%       10%       20%       30%       40%       50%       60%       70% 
##  1.284923  6.873846  7.491608  8.016084  9.065035 10.493846 12.592615 15.358741 
##       80%       90%      100% 
## 20.603497 30.218462 82.153846
# Classificar cada indivíduo no seu intervalo de quantil
matched_data <- matched_data |>
  mutate(quantil = cut(salario_hora,
                       breaks = quantile_cuts,
                       labels = c("0-10%", "10-20%", "20-30%", "30-40%", "40-50%", 
                                  "50-60%", "60-70%", "70-80%", "80-90%", "90-100%"),
                       right = TRUE,
                       include.lowest = TRUE))

dist_quantis <- matched_data |>
  group_by(quantil, formal) |>
  summarise(n_ponderado = sum(final_weights, na.rm = TRUE), .groups = "drop") |>
  filter(!is.na(quantil)) |>
  mutate(prop_total = n_ponderado / sum(n_ponderado))

g2 <- ggplot(dist_quantis, aes(x = quantil, y = prop_total, fill = formal)) +
  geom_col(position = position_dodge(width = 0.8), width = 0.7) +
  geom_text(aes(label = scales::percent(prop_total, accuracy = 0.1)),
            position = position_dodge(width = 0.8),
            vjust = -0.3, size = 3.5) +
  scale_y_continuous(labels = scales::percent_format(accuracy = 1)) +
  labs(title = "Proporção de Formal vs Conta Própria \n por Quantil (com PSM)",
       x = "Quantis do salário-hora", y = "Proporção do total geral",
       fill = "Categoria de emprego") +
  theme_minimal(base_size = 14)

g2

5.4.3 Média salarial

medias_decis <- matched_data |>
  group_by(quantil, formal) |>
  summarise(media_salario = weighted.mean(salario_hora, w = final_weights, na.rm = TRUE),
            .groups = "drop")

# se os quantis estão como fator, converter para numérico para alinhar no eixo
medias_decis <- medias_decis |>
  mutate(quantil_num = as.numeric(gsub("(%|\\-).*", "", quantil)) / 100) #ponto médio

medias_decis <- medias_decis |> filter(!is.na(quantil))

g3 <- ggplot(medias_decis, aes(x = quantil, y = media_salario, fill = formal)) +
  geom_col(position = "dodge", alpha = 0.8) +
  geom_text(aes(label = round(media_salario, 1)),
            position = position_dodge(width = 0.9),
            vjust = -0.1, size = 3.5) +
  labs(
    title = "Salário-Hora Médio por Decil da Distribuição",
    subtitle = "Comparação entre trabalhadores formais e conta própria \n com PSM",
    x = "Quantil da distribuição salarial",
    y = "Salário-hora médio (R$)",
    fill = "Categoria") +
  scale_y_continuous(labels = scales::dollar_format(prefix = "R$ ", big.mark = ".", decimal.mark = ",")) +
  theme_minimal(base_size = 14)

g3

5.5 Quantílica sem PSM

5.5.1 Resultados

t_test <- t.test(salario_hora ~ formal, data = ocupados_psm, weights = V1028)
t_test
## 
##  Welch Two Sample t-test
## 
## data:  salario_hora by formal
## t = 44.486, df = 12230, p-value < 2.2e-16
## alternative hypothesis: true difference in means between group Conta própria and group Formal is not equal to 0
## 95 percent confidence interval:
##  6.341628 6.926236
## sample estimates:
## mean in group Conta própria        mean in group Formal 
##                    20.51212                    13.87819
rq_model_all_SEMPSM <- rq(salario_hora ~ formal, 
                   data = ocupados_psm, 
                   tau = taus, 
                   weights = V1028)

#boot com R = 50 para diminuir o tempo de processamento. Diminuiu de 1h20 para 30m
system.time({
rq_summary_SEMPSM <- summary(rq_model_all_SEMPSM, se = "boot", R=50)
})
##   usuário   sistema decorrido 
##   1131.08      1.33   1135.28
results_SEMPSM <- do.call(rbind, lapply(rq_summary_SEMPSM, function(s) {
  data.frame(
    tau = s$tau,
    coef = s$coefficients["formalFormal", 1],
    se   = s$coefficients["formalFormal", 2])}))

results_SEMPSM <- results_SEMPSM |>
  mutate(lower = coef - 1.96 * se,
         upper = coef + 1.96 * se,
         type = "Quantílico")

g4 <- ggplot() +
  # efeitos quantílicos
  geom_line(data = results_SEMPSM, aes(x = tau, y = coef, color = type), size = 1) +
  geom_point(data = results_SEMPSM, aes(x = tau, y = coef, color = type), size = 2) +
  geom_ribbon(data = results_SEMPSM, aes(x = tau, ymin = lower, ymax = upper, fill = type), 
              alpha = 0.15) +

  # rótulos nos efeitos quantílicos
  geom_text(data = results_SEMPSM, 
            aes(x = tau, y = coef, label = round(coef, 1), color = type), 
            vjust = -0.3, size = 3.5, show.legend = FALSE) +

  # linha de referência
  geom_hline(yintercept = 0, linetype = "dashed", color = "red") +

  # eixo de 0% a 100%
  scale_x_continuous(breaks = seq(0, 1, 0.1),  # decil a decil
                     labels = scales::percent) +
  
  labs(x = "Quantil da distribuição salarial",
       y = "Diferença (Formal - Conta própria)",
       title = "Diferença Salário-Hora (Formal vs PJ) por Decil - Sem PSM") +
  theme_minimal(base_size = 14)

library(patchwork)
g1 / g4

5.5.2 Composição dos Quantis

quantile_cuts_puro <- Hmisc::wtd.quantile(ocupados_psm$salario_hora,
                                          weights = ocupados_psm$V1028,
                                          probs = taus)

ocupados_psm <- ocupados_psm |>
  mutate(quantil = cut(salario_hora,
                       breaks = quantile_cuts_puro,
                       labels = c("0-10%", "10-20%", "20-30%", "30-40%", "40-50%", 
                                  "50-60%", "60-70%", "70-80%", "80-90%", "90-100%"),
                       include.lowest = TRUE))

dist_quantis_puro <- ocupados_psm |>
  group_by(quantil, formal) |>
  summarise(n_ponderado = sum(V1028, na.rm = TRUE), .groups = "drop") |>
  filter(!is.na(quantil)) |>
  mutate(prop_total = n_ponderado / sum(n_ponderado))

g5 <- ggplot(dist_quantis_puro, aes(x = quantil, y = prop_total, fill = formal)) +
  geom_col(position = position_dodge(width = 0.8), width = 0.7) +
  geom_text(aes(label = scales::percent(prop_total, accuracy = 0.1)),
            position = position_dodge(width = 0.8),
            vjust = -0.3, size = 3.5) +
  scale_y_continuous(labels = scales::percent_format(accuracy = 1)) +
  labs(title = "Proporção de Formal vs Conta Própria \n por Quantil (sem PSM)",
       x = "Quantis do salário-hora", y = "Proporção do total geral",
       fill = "Categoria de emprego") +
  theme_minimal(base_size = 14)


## Comparação lado a lado
g2 / g5

table(matched_data$formal)
## 
## Conta própria        Formal 
##         10672         10672
table(ocupados_psm$formal)
## 
## Conta própria        Formal 
##         10672         67340
prop.table(table(matched_data$formal))
## 
## Conta própria        Formal 
##           0.5           0.5
prop.table(table(ocupados_psm$formal))
## 
## Conta própria        Formal 
##     0.1367995     0.8632005

5.5.3 Média Salarial

medias_sempsm <- ocupados_psm |>
  group_by(quantil, formal) |>
  summarise(media_salario = weighted.mean(salario_hora, w = V1028, na.rm = TRUE),
            .groups = "drop") |>
  filter(!is.na(quantil)) |>
  mutate(tipo = "Sem PSM")


g6 <- ggplot(medias_sempsm, aes(x = quantil, y = media_salario, fill = formal)) +
  geom_col(position = "dodge", alpha = 0.8) +
  geom_text(aes(label = round(media_salario, 1)),
            position = position_dodge(width = 0.9),
            vjust = -0.1, size = 3.5) +
  labs(
    title = "Salário-Hora Médio por Decil da Distribuição",
    subtitle = "Comparação entre trabalhadores formais e conta própria \n sem PSM",
    x = "Quantil da distribuição salarial",
    y = "Salário-hora médio (R$)",
    fill = "Categoria") +
  scale_y_continuous(labels = scales::dollar_format(prefix = "R$ ", big.mark = ".", decimal.mark = ",")) +
  theme_minimal(base_size = 14)


g3 / g6

5.5.4 Conclusões Parciais

A formalidade estabiliza (menos dispersão), mas no topo implica em salários-hora consistentemente mais baixos.

O efeito não é constante: é pequeno na base e grande no topo.

Isso indica que a formalidade atua como uma “âncora” salarial: protege contra rendas muito baixas, mas também limita a chance de rendas muito altas.

No percentil 10, a diferença é positiva para formais, a medida que o salário-hora sobe a diferença se inverte, mas é gradual.

Isso confirma que a formalidade cresce ao longo da distribuição: quanto mais alto o decil, maior a perda relativa dos formais.

Já os pontos de t-test e survey t-test ficam próximos de -13 R$/h, refletindo a diferença média encontrada antes, mas demonstrando como a análise quantílica é relevante.

O resultado médio mascara a heterogeneidade: ser formal implica, em média, salário-hora menor, mas a magnitude depende fortemente da posição na distribuição.

LS0tDQp0aXRsZTogIlVtYSBhbsOhbGlzZSBjb21wYXJhZGEgZW50cmUgVHJhYmFsaGFkb3JlcyBGb3JtYWlzIGUgVHJhYmFsaGFkb3JlcyBwb3IgQ29udGEtUHLDs3ByaWEgY29tIENOUEoiDQphdXRob3I6ICJSYXBoYWVsIFNhbnRvcyBMYXBhIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIHRoZW1lOiBqb3VybmFsDQogICAgdG9jOiB0cnVlDQogICAgdG9jX2RlcHRoOiA0DQogICAgdG9jX2Zsb2F0OiANCiAgICAgIGNvbGxhcHNlZDogZmFsc2UNCiAgICAgIHNtb290aF9zY3JvbGw6IHRydWUNCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcw0KICAgIGRmX3ByaW50OiBwYWdlZA0KICAgIHNlbGZfY29udGFpbmVkOiBubw0KICAgIGNvZGVfZm9sZGluZzogc2hvdw0KICAgIGNvZGVfZG93bmxvYWQ6IHllcw0KY3NzOiBlc3RpbG8uY3NzDQplZGl0b3Jfb3B0aW9uczoNCiAgbWFya2Rvd246DQogICAgd3JhcDogNzINCi0tLQ0KDQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KIyBPYmpldGl2byBHZXJhbA0KDQo8YnI+DQoNCi0gICBBcHJlc2VudGFyIHVtIGNlbsOhcmlvIGNvbXBhcmF0aXZvIGEgcGFydGlyIGRvICoqc2Fsw6FyaW8taG9yYSoqIGVudHJlDQogICAgKip0cmFiYWxoYWRvcmVzIGZvcm1haXMqKiBlICoqdHJhYmFsaGFkb3JlcyBwb3IgY29udGEtcHLDs3ByaWEgcXVlDQogICAgcG9zc3VlbSBDTlBKKiosIGEgcGFydGlyIGRhIHBlc3F1aXNhIFBOQURjDQoNCjxicj4NCg0KIyBFc2NvbGhhcyBNZXRvZG9sw7NnaWNhcw0KDQo8YnI+DQoNCi0gICBBIGJhc2UgZGUgZGFkb3MgdXRpbGl6YWRhIGZvaSBhIFBlc3F1aXNhIE5hY2lvbmFsIHBvciBBbW9zdHJhIGRlDQogICAgRG9taWPDrWxpb3MgQ29udMOtbnVhIC0gUE5BRGMNCg0KLSAgIE8gcmVjb3J0ZSB0ZW1wb3JhbCBmb2kgbyAzwrogdHJpbWVzdHJlLzIwMjQuIEVzc2EgZXNjb2xoYSBvY29ycmUNCiAgICB0ZW5kbyBlbSB2aXN0YSBhcyB2b2xhdGlsaWRhZGVzIGRvIG1lcmNhZG8gZGUgdHJhYmFsaG8gbm8gaW7DrWNpbyBlDQogICAgZmltIGRlIGFuby4NCg0KLSAgIEEgY29tcGFyYcOnw6NvIGRlIHNhbMOhcmlvLWhvcmEgbsOjbyDDqSBkaXJldGEuIFBhcmEgZm9ybWFsaXphZG9zIGZvcmFtDQogICAgaW5zZXJpZG9zIHZhbG9yZXMgZGUgMTPCuiwgZsOpcmlhcywgMS8zIGRlIGbDqXJpYXMgZSBGR1RTLiBQYXJhDQogICAgdHJhYmFsaGFkb3JlcyBwb3IgY29udGEtcHLDs3ByaWEgY29tIFBKIHF1ZSByZWNlYmVtIGFiYWl4byBkZSBSXCQNCiAgICA4MS4wMDAsMDAgZm9pIHJldGlyYWRhIGEgY29udHJpYnVpw6fDo28gZGUgUlwkIDcwLDAwIHJlZmVyZW50ZSBhbyBNRUkuDQogICAgUGFyYSBvcyBkZW1haXMgUEpzIGZvcmFtIHJldGlyYWRvcyAyMCUgZG8gdmFsb3IgZG8gc2Fsw6FyaW8tbcOtbmltby4NCiAgICBBcyBmw7NybXVsYXMgZXN0w6NvIGRpc3BvbsOtdmVpcyBuYSBzZcOnw6NvICIqKlNhbMOhcmlvLUhvcmEqKiINCg0KLSAgIEZvcmFtIHJldGlyYWRvcyAqKm91dGxpZXJzKiogYWJhaXhvIGRlIDElIGUgYWNpbWEgZGUgOTklIGEgcGFydGlyDQogICAgZGFzIHZhcmnDoXZlaXMgZGUgcmVuZGltZW50byBlIGRlIGhvcmFzIHRyYWJhbGhhZGFzLiBEZXBvaXMgZG8NCiAgICBjw6FsY3VsbyBkZSBzYWzDoXJpby1ob3JhIGZvcmFtIHJldGlyYWRvcyB0YW1iw6ltIG91dGxpZXJzIGEgcGFydGlyDQogICAgZGVzc2EgdmFyacOhdmVsDQoNCi0gICBGb3JhbSByZXRpcmFkb3MgdHJhYmFsaGFkb3JlcyBjYXJhY3Rlcml6YWRvcyBjb21vICoqc3Vib2N1cGFkb3MqKg0KICAgIHBvciBpbnN1ZmljacOqbmNpYSBkZSBob3Jhcy4NCg0KLSAgIFRlbmRvIGVtIHZpc3RhIHF1ZSBzZSB0cmF0YSBkZSBwZXNxdWlzYSBhbW9zdHJhbCwgcXVhbmRvIGZvcmFtDQogICAgYW5hbGlzYWRvcyBvcyB2YWxvcmVzIHRvdGFpcyAoY29tIHBlc28gcMOzcy1lc3RyYXRpZmljYWRvKSBxdWFscXVlcg0KICAgIHZhbG9yIHRvdGFsIGRvcyBncnVwb3MgKGZvcm1hbCBlIGNvbnRhLXByw7NwcmlhKSBxdWUgZXN0aXZlc3NlIGNvbQ0KICAgICoqY29lZmljaWVudGUgZGUgdmFyaWHDp8OjbyBhY2ltYSBkZSAyNSUgZm9pIHJldGlyYWRvIGRhIHRhYmVsYSBkZQ0KICAgIHJlc3VsdGFkb3MqKi4NCg0KLSAgIEEgUE5BRGMgdXRpbGl6YSBhIENsYXNzaWZpY2HDp8OjbyBkZSBPY3VwYcOnw7VlcyBwYXJhIGFzIFBlc3F1aXNhcw0KICAgIERvbWljaWxpYXJlcyDigJMgQ09EDQogICAgKDxodHRwczovL2Z0cC5pYmdlLmdvdi5ici9DZW5zb3MvQ2Vuc29fRGVtb2dyYWZpY29fMjAxMC9tZXRvZG9sb2dpYS9hbmV4b3MvYW5leG9fN19vY3VwYWNhb19jb2QucGRmPikNCiAgICBxdWUgdGVtIGEgc2VndWludGUgZXN0cnV0dXJhOg0KDQo8YnI+DQoNCmBgYHtyLCBlY2hvPSBGfQ0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoImM6L1VzZXJzL3JhcGhhZWwucnNsL0Rlc2t0b3AvUi9wamNsdC9jb2QuanBnIikNCmBgYA0KDQo8YnI+DQoNCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQojIERlc2VuaG8gZGEgQmFzZSANCg0KIyMgVmFyacOhdmVpcyBkZSBJbnRlcmVzc2UNCg0KLSAgIEFubw0KLSAgIFRyaW1lc3RyZQ0KLSAgIFVGDQotICAgVjQwMTAgLSBDw7NkaWdvIGRhIG9jdXBhw6fDo28gKGNhcmdvIG91IGZ1bsOnw6NvKQ0KICAgIC0gICDDiSB1dGlsaXphZGEgYSBDbGFzc2lmaWNhw6fDo28gZGUgT2N1cGHDp8O1ZXMgcGFyYSBhcyBQZXNxdWlzYXMNCiAgICAgICAgRG9taWNpbGlhcmVzIOKAkyBDT0QNCi0gICBWRDQwMDIgLSBPY3VwYWRvcy9EZXNvY3VwYWRvcw0KLSAgIFZENDAwOSAtIFBvc2nDp8OjbyBuYSBvY3VwYcOnw6NvIGUgY2F0ZWdvcmlhIGRvIGVtcHJlZ28NCiAgICAtICAgMSAtIEVtcHJlZ2FkbyBubyBzZXRvciBwcml2YWRvIGNvbSBjYXJ0ZWlyYSBkZSB0cmFiYWxobyBhc3NpbmFkYQ0KICAgIC0gICA5IC0gQ29udGEtcHLDs3ByaWEgI1ZENDAxMCAtIEdydXBhbWVudG9zIGRlIGF0aXZpZGFkZSBwcmluY2lwYWwNCiAgICAgICAgZG8gZW1wcmVlbmRpbWVudG8gZG8gdHJhYmFsaG8NCi0gICBWRDQwMTYgLSBSZW5kaW1lbnRvIG1lbnNhbCBoYWJpdHVhbCBkbyB0cmFiYWxobyBwcmluY2lwYWwNCi0gICBWRDQwMTAgLSBHcnVwYW1lbnRvcyBkZSBhdGl2aWRhZGUgcHJpbmNpcGFsIGRvIGVtcHJlZW5kaW1lbnRvIGRvDQogICAgdHJhYmFsaG8gcHJpbmNpcGFsDQogICAgLSAgIEV4LjogQWdyaWN1bHR1cmEsIEluZMO6c3RyaWEsIENvbnN0cnXDp8OjbyBldGMNCi0gICBWNDAzOSAtICJRdWFudGFzIGhvcmFzIC4uLiB0cmFiYWxoYXZhIG5vcm1hbG1lbnRlLCBwb3Igc2VtYW5hLCBuZXNzZQ0KICAgIHRyYWJhbGhvIHByaW5jaXBhbD8iDQotICAgVjQwMTkgLSAiRXNzZSBuZWfDs2Npby9lbXByZXNhIGVyYSByZWdpc3RyYWRvIG5vIENhZGFzdHJvIE5hY2lvbmFsIGRhDQogICAgUGVzc29hIEp1csOtZGljYSAtIENOUEo/Ig0KLSAgIFZENDAwNEEgLSBTdWJvY3VwYcOnw6NvIHBvciBpbnN1ZmljacOqbmNpYSBkZSBob3JhcyBoYWJpdHVhbG1lbnRlDQogICAgdHJhYmFsaGFkYXMgZW0gdG9kb3Mgb3MgdHJhYmFsaG9zDQotICAgVkQzMDA0IC0gRXNjb2xhcmlkYWRlDQotICAgVkQzMDA1IC0gQW5vcyBkZSBFc3R1ZG8NCi0gICBWMjAwNyAtIFNleG8NCi0gICBWMjAxMCAtIENvci9SYcOnYQ0KLSAgIFYyMDA5IC0gSWRhZGUNCi0gICBWRDQwMTEgLSBHcnVwYW1lbnRvIE9jdXBhY2lvbmFsDQotICAgVkQ0MDEyIC0gQ29udHJpYnVpw6fDo28gcGFyYSBpbnN0aXR1dG8gZGUgcHJldmlkw6puY2lhIGVtIHF1YWxxdWVyDQogICAgdHJhYmFsaG8gZGEgc2VtYW5hIGRlIHJlZmVyw6puY2lhIHBhcmEgcGVzc29hcyBkZSAxNCBhbm9zIG91IG1haXMgZGUNCiAgICBpZGFkZQ0KDQo8L2JyPg0KDQojIyBQcsOpLVByb2Nlc3NhbWVudG8gDQoNCmBgYHtyLCB3YXJuaW5nID0gRiwgcmVzdWx0cyA9ICdoaWRlJywgbWVzc2FnZSA9IEZ9DQojVGVtYXMgcGFyYSBSbWFya2Rvd24gLSBodHRwczovL3JwdWJzLmNvbS9yYW55ZGMvcm1hcmtkb3duX3RoZW1lcw0KDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkocmVhZHhsKQ0KbGlicmFyeShEVCkNCmxpYnJhcnkoUE5BRGNJQkdFKQ0KbGlicmFyeShzdXJ2ZXkpDQpsaWJyYXJ5KHNydnlyKQ0KbGlicmFyeShzY2FsZXMpDQpsaWJyYXJ5KGp0b29scykgI2Z1bsOnw6NvIHN1bW0gLSBwYXJ0ZSBpbmZlcmVuY2lhbA0KDQpTeXMuc2V0bG9jYWxlKCJMQ19BTEwiLCAicHRfQlIuVVRGLTgiKSAjcHJvYmxlbWFzIGNvbSBlbmNvZGluZw0KYGBgDQoNClNlcsOhIGZlaXRhIHVtYSBjb25zdWx0YSBzb21lbnRlIMOgIGJhc2UgZGUgZGFkb3MgZGUgMjAyNCAtIDPCuiBUcmltZXN0cmUsDQp0ZW5kbyBlbSB2aXN0YSBhIGxpbWl0YcOnw6NvIGRlIGNhcGFjaWRhZGUgZGUgcHJvY2Vzc2FtZW50by4NCg0KTyBjw7NkaWdvIGFiYWl4byBmYXLDoSBvIGRvd25sb2FkIGRvcyBkYWRvcyBlIHNhbHZhcsOhIGVtIHVtIG9iamV0byBkbyB0aXBvDQoucmRzIHBhcmEgdW1hIHBhc3RhIGxvY2FsLg0KDQpgYGB7cn0NCiMjIyMjIyMjIyNST0RBUiBTT01FTlRFIEEgUFJJTUVJUkEgVkVaIyMjIyMjIyMjIyMjIyMjDQoNCiMgdmFyaWF2ZWlzX3NlbGVjaW9uYWRhcyA8LSBjKCJBbm8iLCAiVHJpbWVzdHJlIiwgIlVGIiwiVjQwMTAiLA0KIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlZENDAwMiIsIlZENDAwOSIsIlZENDAxMCIsIlZENDAxNiIsDQojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVjQwMzkiLCJWNDAxOSIsICJWRDQwMDRBIiwgIlZEMzAwNCIsICJWRDMwMDUiLA0KIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlYyMDA3IiwgIlYyMDEwIiwgIlYyMDA5IiwgIlZENDAxMiIsICJWRDQwMTEiKQ0KIyANCiMgcG5hZGMgPC0gZ2V0X3BuYWRjKHllYXI9MjAyNCwgcXVhcnRlcj0zLA0KIyAgICAgICAgICAgICAgICAgICAgdmFycz12YXJpYXZlaXNfc2VsZWNpb25hZGFzLCBkZXNpZ24gPSBULCBsYWJlbHMgPSBGKQ0KIyBjbGFzcyhwbmFkYykNCg0KIyAjVFJBTlNGT1JNQVIgUEFSQSBUSUJCTEUgUEFSQSBVU0FSIEEgR1JBTcOBVElDQSBUSURZVkVSU0UNCiMgcG5hZF9zcnZ5ciA8LSBhc19zdXJ2ZXkocG5hZGMpDQojIGNsYXNzKHBuYWRfc3J2eXIpDQoNCiMgI1BSSU1FSVJPIEZJTFRSTyAtIFNPTUVOVEUgT0NVUEFET1MNCiMgb2N1cGFkb3MgPC0gcG5hZF9zcnZ5ciB8Pg0KIyAgIGZpbHRlcihWRDQwMDIgPT0gMSkgfD4NCiMgICBtdXRhdGUoVjEwMjggPSBhcy5udW1lcmljKFYxMDI4KSkNCiMgY2xhc3Mob2N1cGFkb3MpDQoNCiMgcm0ocG5hZF9zcnZ5cikNCiMgcm0ocG5hZGMpDQoNCiMgI1NBTFZBUiBQQVJBIFVTQVIgT0ZGTElORQ0KIyBzYXZlUkRTKG9jdXBhZG9zLCBmaWxlID0gImM6L1VzZXJzL3JhcGhhZWwucnNsL0Rlc2t0b3AvUi9wamNsdC9vY3VwYWRvczMucmRzIikNCmBgYA0KDQojIyBQcmVwYXJhw6fDo28gZGEgQmFzZSBkZSBEYWRvcw0KDQpBcXVpIHNlcsOhIHJlYWxpemFkYSBhIGp1bsOnw6NvIGVudHJlIGEgUE5BRGMgcHVyYSBlIGEgdGFiZWxhIENPRCBkYXMNCnByb2Zpc3PDtWVzLg0KDQpgYGB7cn0NCm9jdXBhZG9zIDwtIHJlYWRSRFMoImM6L1VzZXJzL3JhcGhhZWwucnNsL0Rlc2t0b3AvUi9wamNsdC9vY3VwYWRvczMucmRzIikNCiNjbGFzcyhvY3VwYWRvcykNCg0KI0xFUiBBIFRBQkVMQSBERSBPQ1VQQcOHw5VFUw0KY29kIDwtIHJlYWRfeGxzKCJjOi9Vc2Vycy9yYXBoYWVsLnJzbC9EZXNrdG9wL1IvcGpjbHQvRXN0cnV0dXJhX09jdXBhY2FvX0NPRC54bHMiKSB8Pg0KICByZW5hbWUoZ3JhbmRlX2dydXBvID0gYEdyYW5kZSBHcnVwb2AsDQogICAgICAgICBzdWJncnVwb19wcmluY2lwYWwgPSBgU3ViZ3J1cG8gcHJpbmNpcGFsYCwNCiAgICAgICAgIHN1YmdydXBvID0gU3ViZ3J1cG8sDQogICAgICAgICBncnVwb19iYXNlID0gYEdydXBvIGRlIGJhc2VgLA0KICAgICAgICAgZGVub21pbmFjYW8gPSBEZW5vbWluYcOnw6NvKSB8Pg0KICBtdXRhdGUoICNOw4NPIFRSQVpFUiBOQXMsIG91IHNlamEsIHNlIG7Do28gZm9yIE5BIHRyYXogImRlbm9taW5hY2FvIg0KICAgIGRlbm9tX3N1YmdydXBvX3ByaW5jaXBhbCA9IGlmX2Vsc2UoIWlzLm5hKHN1YmdydXBvX3ByaW5jaXBhbCksIGRlbm9taW5hY2FvLCBOQV9jaGFyYWN0ZXJfKSwNCiAgICBkZW5vbV9zdWJncnVwbyA9IGlmX2Vsc2UoIWlzLm5hKHN1YmdydXBvKSwgZGVub21pbmFjYW8sIE5BX2NoYXJhY3Rlcl8pLA0KICAgIGRlbm9tX2dydXBvX2Jhc2UgPSBpZl9lbHNlKCFpcy5uYShncnVwb19iYXNlKSwgZGVub21pbmFjYW8sIE5BX2NoYXJhY3Rlcl8pKSB8Pg0KICBmaWxsKGdyYW5kZV9ncnVwbywgc3ViZ3J1cG9fcHJpbmNpcGFsLCBkZW5vbV9zdWJncnVwb19wcmluY2lwYWwsIA0KICAgICAgIHN1YmdydXBvLCBkZW5vbV9zdWJncnVwbywgZ3J1cG9fYmFzZSwgZGVub21fZ3J1cG9fYmFzZSwgLmRpcmVjdGlvbiA9ICJkb3duIikNCiAgICAgICAjcHJvcGFnYSBvcyB2YWxvcmVzIHBhcmEgYmFpeG8NCg0KI1JFVElSQU5ETyBOQXMgZSBwb3Nzw612ZWlzIGR1cGxpY2Fkb3MNCmNvZF9tYXAgPC0gY29kIHw+DQogIGZpbHRlcighaXMubmEoZ3J1cG9fYmFzZSkpIHw+DQogIHNlbGVjdChncnVwb19iYXNlLCBkZW5vbV9ncnVwb19iYXNlLCBzdWJncnVwbywgZGVub21fc3ViZ3J1cG8sDQogICAgICAgICBzdWJncnVwb19wcmluY2lwYWwsIGRlbm9tX3N1YmdydXBvX3ByaW5jaXBhbCwgZ3JhbmRlX2dydXBvKSB8Pg0KICBkaXN0aW5jdCgpDQoNCiNhcGxpY2FuZG8gYSBiYXNlIENPRCBuYSBiYXNlIGdlcmFsDQpvY3VwYWRvczIgPC0gb2N1cGFkb3MgfD4gDQogIG11dGF0ZShWNDAxMCA9IGFzLmNoYXJhY3RlcihWNDAxMCksDQogICAgICAgICBzdWJncnVwb19jb2QgPSBzdWJzdHIoVjQwMTAsIDEsIDMpLA0KICAgICAgICAgIyBidXNjYSBncnVwb19iYXNlIGUgc3ViZ3J1cG8gZSBmYXogbyBtYXRjaA0KICAgICAgICAgZ3J1cG9fYmFzZSA9IGNvZF9tYXAkZGVub21fZ3J1cG9fYmFzZVttYXRjaChWNDAxMCwgY29kX21hcCRncnVwb19iYXNlKV0sDQogICAgICAgICBzdWJncnVwbyA9IGNvZF9tYXAkZGVub21fc3ViZ3J1cG9bbWF0Y2goc3ViZ3J1cG9fY29kLCBjb2RfbWFwJHN1YmdydXBvKV0pDQoNCiMgUmV0aXJhZG9zIGluZGl2w61kdW9zIGNsYXNzaWZpY2Fkb3MgY29tbyBzdWJvY3VwYWRvcw0Kb2N1cGFkb3MyIDwtIG9jdXBhZG9zMiB8PiANCiAgZmlsdGVyKGlzLm5hKFZENDAwNEEpIHwgVkQ0MDA0QSAhPSAxKQ0KI8OJIG5lY2Vzc8OhcmlvIG1hbnRlciBOQSBwb3IgY29udGEgZGEgZXN0cnV0dXJhIGRvIHRibF9zdnkNCg0KI291dGxpZXJzIC0gcmV0aXJhIDElIHN1cGVyaW9yIGUgMSUgaW5mZXJpb3INCm9jdXBhZG9zMiA8LSBvY3VwYWRvczIgfD4gDQogIGZpbHRlcihWRDQwMTYgPj0gcXVhbnRpbGUoVkQ0MDE2LCAwLjAxLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICAgVkQ0MDE2IDw9IHF1YW50aWxlKFZENDAxNiwgMC45OSwgbmEucm0gPSBUUlVFKSwNCiAgICAgICAgIFY0MDM5ID49IHF1YW50aWxlKFY0MDM5LCAwLjAxLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICAgVjQwMzkgPD0gcXVhbnRpbGUoVjQwMzksIDAuOTksIG5hLnJtID0gVFJVRSkpIA0KYGBgDQoNCkdyw6FmaWNvcyBFeHBsb3JhdMOzcmlvcw0KDQpgYGB7cn0NCiNWRVJJRklDQVIgU0Ugw4kgTyBDQVNPIERFIFJFVElSQVIgTUFJUyBPVVRMSUVSUyBBIFBBUlRJUiBET1MgQk9YUExPVFMNCg0KIyBCb3hwbG90IHBhcmEgUmVuZGltZW50bw0KZ2dwbG90KG9jdXBhZG9zMiwgYWVzKHggPSAiIiwgeSA9IFZENDAxNikpICsNCiAgZ2VvbV9ib3hwbG90KG91dGxpZXIuY29sb3IgPSAicmVkIikgKw0KICBsYWJzKHRpdGxlID0gIkJveHBsb3QgZGUgUmVuZGltZW50byIsIHkgPSAiUmVuZGltZW50byIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQoNCiMgQm94cGxvdCBwYXJhIEpvcm5hZGENCmdncGxvdChvY3VwYWRvczIsIGFlcyh4ID0gIiIsIHkgPSBWNDAzOSkpICsNCiAgZ2VvbV9ib3hwbG90KG91dGxpZXIuY29sb3IgPSAicmVkIikgKw0KICBsYWJzKHRpdGxlID0gIkJveHBsb3QgZGUgSm9ybmFkYSIsIHkgPSAiSG9yYXMiKSArDQogIHRoZW1lX21pbmltYWwoKSAgDQpgYGANCg0KIyMgU2Fsw6FyaW8tSG9yYSA8YSBpZD0ic2FsYXJpby1ob3JhIj48L2E+DQoNCkNyaW91LXNlIHVtYSB2YXJpw6F2ZWwgYXV4aWxpYXI6ICoqc2FsYXJpb19ob3JhKiogY29tIGEgc2VndWludGUNCmNvbXBvc2nDp8Ojbw0KDQpQYXJhIGZvcm1haXMsIGNvbnNpZGVyYW1vczogLSAxMiBzYWzDoXJpb3MgbWVuc2FpcyBoYWJpdHVhaXM7IC0gMTPCug0Kc2Fsw6FyaW8gKDEgc2Fsw6FyaW8gYWRpY2lvbmFsKTsgLSAxLzMgYWRpY2lvbmFsIGRlIGbDqXJpYXM7IC0gOCUgZGUNCkZHVFM7IC0gQXBlbmFzIDExIG1lc2VzIGRlIHRyYWJhbGhvIGVmZXRpdm8gKHBvaXMgMSBtw6pzIMOpIGRlIGbDqXJpYXMpLg0KDQpBIGbDs3JtdWxhIGRvIHNhbMOhcmlvLWhvcmEgw6k6DQoNCiQkDQpcdGV4dHtTYWzDoXJpby1ob3JhfV97Zm9ybWFsfSA9IA0KXGZyYWN7KDEyICsgMSArIFx0ZnJhY3sxfXszfSkgXGNkb3QgXHRleHR7U2Fsw6FyaW8gTWVuc2FsIEhhYml0dWFsfSBcY2RvdCAoMSArIFx0ZXh0e0ZHVFN9KX0NCntcdGV4dHtIb3JhcyBTZW1hbmFpcyBIYWJpdHVhbH0gXGNkb3QgXHRmcmFjezUyfXsxMn0gXGNkb3QgMTF9DQokJA0KDQpQYXJhIHRyYWJhbGhhZG9yZXMgYXV0w7Rub21vcyByZWdpc3RyYWRvcyBjb21vICoqTUVJKiosIGNvbnNpZGVyYW1vczpcDQotIFJlbmRpbWVudG8gbWVuc2FsIGhhYml0dWFsIGRlY2xhcmFkbztcDQotIERlc2NvbnRvIGZpeG8gZGEgZ3VpYSAqKkRBUyoqIChpbXBvc3RvIG1lbnNhbCBkbyBNRUkpO1wNCi0gSm9ybmFkYSBoYWJpdHVhbCBzZW1hbmFsIG11bHRpcGxpY2FkYSBwb3IgJDUyLzEyJCAocGFyYSBvYnRlciBhcyBob3Jhcw0KbWVuc2FpcykuDQoNCkEgZsOzcm11bGEgZG8gc2Fsw6FyaW8taG9yYSDDqToNCg0KJCQNClx0ZXh0e1NhbMOhcmlvLWhvcmF9X3tNRUl9ID0gDQpcZnJhY3tcdGV4dHtTYWzDoXJpbyBNZW5zYWwgSGFiaXR1YWx9IC0gXHRleHR7REFTfX0NCntcdGV4dHtIb3JhcyBTZW1hbmFpcyBIYWJpdHVhbH0gXGNkb3QgXHRmcmFjezUyfXsxMn19DQokJA0KDQpBdXTDtG5vbW9zIGFjaW1hIGRvIGxpbWl0ZSBNRUkNCg0KUGFyYSB0cmFiYWxoYWRvcmVzIHBvciBjb250YSBwcsOzcHJpYSBjb20gcmVuZGltZW50byAqKmFjaW1hIGRvIGxpbWl0ZQ0KTUVJKiosIGNvbnNpZGVyYW1vczoNCg0KLSAgICoqQ29udHJpYnVpw6fDo28gcHJvcG9yY2lvbmFsOioqIGFwbGljYS1zZSAxMSUgZGlyZXRhbWVudGUgc29icmUgbw0KICAgIHJlbmRpbWVudG8gbWVuc2FsLCBjb25zaWRlcmFkbyBvIHZhbG9yIGRlY2xhcmFkbyBjb21vIHByby1sYWJvcmUuDQoNCiQkDQpcdGV4dHtTYWzDoXJpby1ob3JhfV97Q1B9Xntwcm9wfSA9IA0KXGZyYWN7XHRleHR7U2Fsw6FyaW8gTWVuc2FsIEhhYml0dWFsfSBcY2RvdCAoMSAtIDExXCUpfQ0Ke1x0ZXh0e0hvcmFzIFNlbWFuYWlzIEhhYml0dWFsfSBcY2RvdCBcdGZyYWN7NTJ9ezEyfX0NCiQkDQoNCkFsw6ltIGRpc3NvLCBmb2kgY3JpYWRhIHVtYSB2YXJpw6F2ZWwgYXV4aWxpYXIgY2hhbWFkYQ0KKipjYXRlZ29yaWFfZW1wcmVnbyoqIHBhcmEgZmFjaWxpdGFyIGEgZmlsdHJhZ2VtIGRlIGZvcm1hbCwgY25waiBlDQpvdXRyb3MuDQoNCmBgYHtyLCBmaWcud2lkdGggPSA4LCBmaWcuaGVpZ2h0ID0gMTB9DQojIFBhcsOibWV0cm9zDQpzYWxfbWluIDwtIDE0MTIgICAgICAgICAgIyBzYWzDoXJpby1tw61uaW1vIGVtIDIwMjQNCm1laV9tZW5zYWwgPC0gODEwMDAgLyAxMiAgIyBSJCA2NzUwIHBvciBtw6pzDQptZWlfZGFzIDwtIDcxLjYwICAgICAgICAgICMgREFTLU1FSSAyMDI1DQpmZ3RzIDwtIDAuMDggICAgICAgICAjIDglIEZHVFMNCnNlbWFuYV9tZXMgPC0gNTIvMTIgICMgfjQuMzMzDQpvcGNhb19pbnNzIDwtICJOT1RfZml4ZWRfbWluX3dhZ2VfMTFwY3QiICMgcmVncmEgdXNhZGEgcGFyYSBjb250cmlidWnDp8OjbyBkaXJldGEgbm8gc2Fsw6FyaW8gbWluaW1vIC0gbsOjbyB1c2FkYQ0KI291IDIwJSBzZWd1bmRvIHRlc3RlIGZvaSBwYXJhIDIwJQ0KaW5zc192YWxvciA8LSAwLjExDQoNCiMgLS0tIGNvbnZlcnRlciBjYW1wb3MgcGFyYSBudW1lcmljIC8gcHJvdGVnZXIgZGl2aXPDtWVzIC0tLQ0Kb2N1cGFkb3MyIDwtIG9jdXBhZG9zMiAgfD4gDQogIG11dGF0ZShWRDQwMTYgPSBhcy5udW1lcmljKGFzLmNoYXJhY3RlcihWRDQwMTYpKSwgIA0KICAgICAgICAgVjQwMzkgID0gYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoVjQwMzkpKSwgICANCiAgICAgICAgIFZENDAwOSA9IGFzLmNoYXJhY3RlcihWRDQwMDkpKQ0KDQojIC0tLSBjw6FsY3VsbyBhdHVhbGl6YWRvIC0tLQ0Kb2N1cGFkb3MzIDwtIG9jdXBhZG9zMiB8Pg0KICBtdXRhdGUoDQogICAgIyBob3JhcyBlZmV0aXZhbWVudGUgdHJhYmFsaGFkYXMgbm8gbcOqcw0KICAgIGhvcmFzX21lcyA9IGlmX2Vsc2UoIWlzLm5hKFY0MDM5KSAmIFY0MDM5ID4gMCwgVjQwMzkgKiBzZW1hbmFfbWVzLCBOQV9yZWFsXyksDQoNCiAgICAjIHNhbMOhcmlvLWhvcmENCiAgICBzYWxhcmlvX2hvcmEgPSBjYXNlX3doZW4oDQogICAgICAjIEZvcm1hbCBjb20gZsOpcmlhcywgMTPCuiBlIEZHVFMgKDExIG1lc2VzIGRlIHRyYWJhbGhvIG5vIGFubykNCiAgICAgIFZENDAwOSA9PSAiMSIgJiAhaXMubmEoaG9yYXNfbWVzKSB+IHsNCiAgICAgICAgc2FsX2FudWFsIDwtIFZENDAxNiAqICgxMiArIDEgKyAxLzMpICAgICAgIyAxMiBzYWzDoXJpb3MgKyAxM8K6ICsgMS8zIGbDqXJpYXMNCiAgICAgICAgaG9yYXNfYW5vIDwtIGhvcmFzX21lcyAqIDExICAgICAgICAgICAgICAgIyBzw7MgMTEgbWVzZXMgZGUgdHJhYmFsaG8sIHRlbmRvIGVtIHZpc3RhIGbDqXJpYXMNCiAgICAgICAgKHNhbF9hbnVhbCAqICgxICsgZmd0cykpIC8gaG9yYXNfYW5vfSwNCg0KICAgICAgIyBBdXTDtG5vbW8gLyBNRUkgYXTDqSBsaW1pdGUgbWVuc2FsID0gZGVzY29udGEgREFTIGZpeG8NCiAgICAgIFZENDAwOSAhPSAiMSIgJiAhaXMubmEoaG9yYXNfbWVzKSAmIFZENDAxNiA8PSBtZWlfbWVuc2FsIH4NCiAgICAgICAgcG1heCgoVkQ0MDE2IC0gbWVpX2RhcykgLyBob3Jhc19tZXMsIDApLCAjcG1heCBnYXJhbnRlIHF1ZSBuw6NvIHZlbSB2YWxvciBuZWdhdGl2bw0KDQogICAgICAjIEF1dMO0bm9tbyAvIENOUEogYWNpbWEgZG8gbGltaXRlIE1FSSA9IGFwbGljYSByZWdyYSBkbyBJTlNTDQogICAgICBWRDQwMDkgIT0gIjEiICYgIWlzLm5hKGhvcmFzX21lcykgJiBWRDQwMTYgPiBtZWlfbWVuc2FsIH4gew0KICAgICAgICBpZiAob3BjYW9faW5zcyA9PSAiZml4ZWRfbWluX3dhZ2VfMTFwY3QiKSB7DQogICAgICAgICAgaW5zc192YWwgPC0gc2FsX21pbiAqIGluc3NfdmFsb3INCiAgICAgICAgICBwbWF4KChWRDQwMTYgLSBpbnNzX3ZhbCkgLyBob3Jhc19tZXMsIDApfSANCiAgICAgICAgZWxzZSB7DQogICAgICAgICAgcG1heCgoVkQ0MDE2ICogKDEgLSBpbnNzX3ZhbG9yKSkgLyBob3Jhc19tZXMsIDApfX0sDQogICAgICBUUlVFIH4gTkFfcmVhbF8gICkpDQoNCiMgLS0tIGNhdGVnb3JpYXMgZGUgZW1wcmVnbyAtLS0NCm9jdXBhZG9zMyR2YXJpYWJsZXMgPC0gb2N1cGFkb3MzJHZhcmlhYmxlcyB8Pg0KICBtdXRhdGUoY2F0ZWdvcmlhX2VtcHJlZ28gPSBjYXNlX3doZW4oDQogICAgVkQ0MDA5ID09ICIwMSIgfiAiZm9ybWFsIiwNCiAgICBWRDQwMDkgPT0gIjA5IiAmIFY0MDE5ID09ICIxIiB+ICJjbnBqIiwNCiAgICBUUlVFIH4gIm91dHJvcyIpKQ0KDQpybShvY3VwYWRvcykNCg0KZ2dwbG90KG9jdXBhZG9zMywgYWVzKHggPSAiIiwgeSA9IHNhbGFyaW9faG9yYSkpICsNCiAgZ2VvbV9ib3hwbG90KG91dGxpZXIuY29sb3IgPSAicmVkIikgKw0KICBsYWJzKHRpdGxlID0gIkJveHBsb3QgZGUgU2Fsw6FyaW8tSG9yYSIsIHkgPSAiSG9yYXMiKSArDQogIHRoZW1lX21pbmltYWwoKSAgDQoNCiNyZXRpcmFyIG91dGxpZXJzIGRlIHNhbGFyaW9faG9yYQ0Kb2N1cGFkb3MzIDwtIG9jdXBhZG9zMyB8Pg0KICBmaWx0ZXIoc2FsYXJpb19ob3JhID49IHF1YW50aWxlKHNhbGFyaW9faG9yYSwgMC4wMSwgbmEucm0gPSBUUlVFKSwNCiAgICAgICAgIHNhbGFyaW9faG9yYSA8PSBxdWFudGlsZShzYWxhcmlvX2hvcmEsIDAuOTksIG5hLnJtID0gVFJVRSkpDQpgYGANCg0KIyBBbsOhbGlzZSBEZXNjcml0aXZhDQoNCiMjIEluaWNpYWlzIC0gUG9yIENhdGVnb3JpYQ0KDQojIyMgU2Fsw6FyaW8tSG9yYQ0KDQpgYGB7ciwgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSJ9DQpyZXN1bW9fc2FsIDwtIG9jdXBhZG9zMyB8Pg0KICBncm91cF9ieShjYXRlZ29yaWFfZW1wcmVnbykgfD4NCiAgc3VtbWFyaXNlKG4gPSBzdXJ2ZXlfdG90YWwobmEucm0gPSBUUlVFKSwNCiAgICAgICAgICAgIG1lZGlhbmEgPSBzdXJ2ZXlfbWVkaWFuKHNhbGFyaW9faG9yYSwgbmEucm0gPSBUUlVFKSwNCiAgICAgICAgICAgIC5ncm91cHMgPSAiZHJvcCIpIHw+DQogIG11dGF0ZShuX2xhYmVsID0gcGFzdGUwKCJuID0gIiwgc2NhbGVzOjpjb21tYShuKSksDQogICAgICAgICBtZWRpYW5hX2xhYmVsID0gcGFzdGUwKCJNZWRpYW5hID0gUiQgIiwgcm91bmQobWVkaWFuYSwgMikpKQ0KDQpnZ3Bsb3Qob2N1cGFkb3MzLCBhZXMoeCA9IGNhdGVnb3JpYV9lbXByZWdvLCB5ID0gc2FsYXJpb19ob3JhLCBmaWxsID0gY2F0ZWdvcmlhX2VtcHJlZ28pKSArDQogIGdlb21fYm94cGxvdChhbHBoYSA9IDAuNywgb3V0bGllci5jb2xvdXIgPSAicmVkIikgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpkb2xsYXJfZm9ybWF0KHByZWZpeCA9ICJSJCAiKSkgKw0KICBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoMCwgNTApKSArDQogIGxhYnModGl0bGUgPSAiRGlzdHJpYnVpw6fDo28gZG8gU2Fsw6FyaW8tSG9yYSBwb3IgQ2F0ZWdvcmlhIGRlIEVtcHJlZ28gXG4gKGF0w6kgUiQgNTApIiwNCiAgICAgICB4ID0gIkNhdGVnb3JpYSBkZSBFbXByZWdvIiwNCiAgICAgICB5ID0gIlNhbMOhcmlvLUhvcmEiKSArDQogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTQpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArDQogIGdlb21fdGV4dChkYXRhID0gcmVzdW1vX3NhbCwNCiAgICAgICAgICAgIGFlcyh4ID0gY2F0ZWdvcmlhX2VtcHJlZ28sIHkgPSA1LCBsYWJlbCA9IG5fbGFiZWwpLCAjIGNvbG9jYSBvIHRleHRvIG5vIHRvcG8NCiAgICAgICAgICAgIGluaGVyaXQuYWVzID0gRkFMU0UsDQogICAgICAgICAgICB2anVzdCA9IC0wLjUsDQogICAgICAgICAgICBzaXplID0gNCkgKw0KICBnZW9tX3RleHQoZGF0YSA9IHJlc3Vtb19zYWwsDQogICAgICAgICAgICBhZXMoeCA9IGNhdGVnb3JpYV9lbXByZWdvLCB5ID0gbWVkaWFuYSwgbGFiZWwgPSByb3VuZChtZWRpYW5hLCAxKSksDQogICAgICAgICAgICBpbmhlcml0LmFlcyA9IEZBTFNFLA0KICAgICAgICAgICAgdmp1c3QgPSAtMC41LA0KICAgICAgICAgICAgZm9udGZhY2UgPSAiYm9sZCIsDQogICAgICAgICAgICBzaXplID0gNCwNCiAgICAgICAgICAgIGNvbG9yID0gImJsdWUiKQ0KYGBgDQoNCiMjIyBFc2NvbGFyaWRhZGUNCg0KYGBge3IsIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUifQ0Kb2N1cGFkb3MzIDwtIG9jdXBhZG9zMyB8PiANCiAgbXV0YXRlKGVzY29sYXJpZGFkZSA9IGZhY3RvcihWRDMwMDQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gMTo3LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIlNlbSBpbnN0cnXDp8OjbyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRnVuZGFtZW50YWwgaW5jb21wbGV0byIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRnVuZGFtZW50YWwgY29tcGxldG8iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk3DqWRpbyBpbmNvbXBsZXRvIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJNw6lkaW8gY29tcGxldG8iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlN1cGVyaW9yIGluY29tcGxldG8iLCJTdXBlcmlvciBjb21wbGV0byIpKSkNCg0KDQpyZXN1bW9fZXNjb2xhcmlkYWRlIDwtIG9jdXBhZG9zMyB8Pg0KICBmaWx0ZXIoIWlzLm5hKGVzY29sYXJpZGFkZSkpIHw+DQogIGdyb3VwX2J5KGNhdGVnb3JpYV9lbXByZWdvLCBlc2NvbGFyaWRhZGUpIHw+DQogIHN1bW1hcmlzZShuID0gc3VydmV5X3RvdGFsKG5hLnJtID0gVFJVRSkpIHw+DQogIGdyb3VwX2J5KGNhdGVnb3JpYV9lbXByZWdvKSB8Pg0KICBtdXRhdGUoZnJlcV9yZWxhdGl2YSA9IG4gLyBzdW0obikgKiAxMDApDQoNCmdncGxvdChyZXN1bW9fZXNjb2xhcmlkYWRlLCBhZXMoeCA9IGNhdGVnb3JpYV9lbXByZWdvLCB5ID0gZnJlcV9yZWxhdGl2YSwgZmlsbCA9IGVzY29sYXJpZGFkZSkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gInN0YWNrIikgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50X2Zvcm1hdChzY2FsZSA9IDEpKSArDQogIGxhYnModGl0bGUgPSAiRGlzdHJpYnVpw6fDo28gUGVyY2VudHVhbCBkYSBFc2NvbGFyaWRhZGUgXG4gcG9yIENhdGVnb3JpYSBkZSBFbXByZWdvIiwNCiAgICAgICB4ID0gIkNhdGVnb3JpYSBkZSBFbXByZWdvIiwNCiAgICAgICB5ID0gIkZyZXF1w6puY2lhIFJlbGF0aXZhICglKSIsDQogICAgICAgZmlsbCA9ICJGYWl4YSBkZSBFc2NvbGFyaWRhZGUiKSArDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQoNCiMjIyBFIGEgcXVlc3TDo28gcmVnaW9uYWw/DQoNCmBgYHtyLCBmaWcuaGVpZ2h0ID0gMTQsIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUifQ0KdWZzX2xhYmVscyA8LSBjKA0KICAiMTEiID0gIlJPIiwgIjEyIiA9ICJBQyIsICIxMyIgPSAiQU0iLCAiMTQiID0gIlJSIiwgIjE1IiA9ICJQQSIsDQogICIxNiIgPSAiQVAiLCAiMTciID0gIlRPIiwgIjIxIiA9ICJNQSIsICIyMiIgPSAiUEkiLCAiMjMiID0gIkNFIiwNCiAgIjI0IiA9ICJSTiIsICIyNSIgPSAiUEIiLCAiMjYiID0gIlBFIiwgIjI3IiA9ICJBTCIsICIyOCIgPSAiU0UiLA0KICAiMjkiID0gIkJBIiwgIjMxIiA9ICJNRyIsICIzMiIgPSAiRVMiLCAiMzMiID0gIlJKIiwgIjM1IiA9ICJTUCIsDQogICI0MSIgPSAiUFIiLCAiNDIiID0gIlNDIiwgIjQzIiA9ICJSUyIsICI1MCIgPSAiTVQiLCAiNTEiID0gIk1TIiwNCiAgIjUyIiA9ICJHTyIsICI1MyIgPSAiREYiKQ0KDQpvY3VwYWRvczMgPC0gb2N1cGFkb3MzIHw+DQogIG11dGF0ZSh1Zl9zaWdsYSA9IHVmc19sYWJlbHNbYXMuY2hhcmFjdGVyKFVGKV0pDQoNCiMgRmlsdHJvIGFwZW5hcyBwYXJhIGR1YXMgY2F0ZWdvcmlhcyBwYXJhIG7Do28gZmljYXIgcG9sdcOtZG8NCmRhZG9zX3Bsb3RfdWYgPC0gb2N1cGFkb3MzIHw+DQogIGZpbHRlcihjYXRlZ29yaWFfZW1wcmVnbyAlaW4lIGMoImZvcm1hbCIsICJjbnBqIikpIHw+DQogIG11dGF0ZShVRl9sYWJlbCA9IGZhY3Rvcih1ZnNfbGFiZWxzW2FzLmNoYXJhY3RlcihVRildLCBsZXZlbHMgPSB1ZnNfbGFiZWxzKSkNCg0KIyBTZWxlY2lvbmFyIHPDsyBVRnMgcXVlIHRlbmhhbSBvcyBkb2lzIGdydXBvczogZm9ybWFsIGUgY25wag0KdWZzX2NvbXBsZXRhcyA8LSBkYWRvc19wbG90X3VmIHw+DQogIGdyb3VwX2J5KFVGX2xhYmVsLCBjYXRlZ29yaWFfZW1wcmVnbykgfD4NCiAgc3VtbWFyaXNlKGNvbnRhZ2VtID0gbigpLCAuZ3JvdXBzID0gJ2Ryb3AnKSB8Pg0KICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gY2F0ZWdvcmlhX2VtcHJlZ28sIHZhbHVlc19mcm9tID0gY29udGFnZW0sIHZhbHVlc19maWxsID0gMCkgfD4NCiAgZmlsdGVyKGZvcm1hbCA+IDAgJiBjbnBqID4gMCkgfD4NCiAgcHVsbChVRl9sYWJlbCkNCg0KIyBGaWx0cmFyIHBlbG9zIFVGcyBjb21wbGV0b3MgZSBjcmlhciBmYXRvciBwYXJhIGNhdGVnb3JpYSBkZSBlbXByZWdvDQpkYWRvc19wbG90X3VmIDwtIGRhZG9zX3Bsb3RfdWYgfD4NCiAgZmlsdGVyKFVGX2xhYmVsICVpbiUgdWZzX2NvbXBsZXRhcykgfD4NCiAgbXV0YXRlKGNhdGVnb3JpYV9lbXByZWdvID0gZmFjdG9yKGNhdGVnb3JpYV9lbXByZWdvLCBsZXZlbHMgPSBjKCJmb3JtYWwiLCAiY25waiIpKSkNCg0KIyBDYWxjdWxhciBtZWRpYW5hcyBwb3IgVUYgZSBjYXRlZ29yaWEgZGUgZW1wcmVnbyBwYXJhIG1vc3RyYXIgbm8gZ3LDoWZpY28NCm1lZGlhbmFzX3VmIDwtIGRhZG9zX3Bsb3RfdWYgfD4NCiAgZ3JvdXBfYnkoVUZfbGFiZWwsIGNhdGVnb3JpYV9lbXByZWdvKSB8Pg0KICBzdW1tYXJpc2UobWVkaWFuYSA9IHN1cnZleV9tZWRpYW4oc2FsYXJpb19ob3JhLCBuYS5ybSA9IFRSVUUpLCAuZ3JvdXBzID0gJ2Ryb3AnKQ0KDQojIEJveHBsb3QgY29tIGZhY2V0X3dyYXAgcG9yIFVGDQpnZ3Bsb3QoZGFkb3NfcGxvdF91ZiwgYWVzKHggPSBjYXRlZ29yaWFfZW1wcmVnbywgeSA9IHNhbGFyaW9faG9yYSwgZmlsbCA9IGNhdGVnb3JpYV9lbXByZWdvKSkgKw0KICBnZW9tX2JveHBsb3QoYWxwaGEgPSAwLjcsIG91dGxpZXIuY29sb3VyID0gInJlZCIpICsNCiAgZ2VvbV90ZXh0KGRhdGEgPSBtZWRpYW5hc191ZiwgDQogICAgICAgICAgICBhZXMoeCA9IGNhdGVnb3JpYV9lbXByZWdvLCANCiAgICAgICAgICAgICAgICB5ID0gbWVkaWFuYSwgDQogICAgICAgICAgICAgICAgbGFiZWwgPSBwYXN0ZTAoIlIkICIsIHJvdW5kKG1lZGlhbmEsIDIpKSksDQogICAgICAgICAgICB2anVzdCA9IC0wLjUsIGNvbG9yID0gImJsYWNrIiwgZm9udGZhY2UgPSAiYm9sZCIsIHNpemUgPSA0KSArDQogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OmRvbGxhcl9mb3JtYXQocHJlZml4ID0gIlIkICIpKSArDQogIGNvb3JkX2NhcnRlc2lhbih5bGltID0gYygwLCA3NSkpICsNCiAgbGFicyh0aXRsZSA9ICJEaXN0cmlidWnDp8OjbyBkbyBTYWzDoXJpby1Ib3JhIHBvciBDYXRlZ29yaWEgZGUgRW1wcmVnbyBlIFVGXG4odmlzdWFsaXphw6fDo28gYXTDqSBSJCA3NSkiLA0KICAgICAgIHggPSAiQ2F0ZWdvcmlhIGRlIEVtcHJlZ28iLA0KICAgICAgIHkgPSAiU2Fsw6FyaW8tSG9yYSIpICsNCiAgZmFjZXRfd3JhcCh+IFVGX2xhYmVsLCBzY2FsZXMgPSAiZnJlZV94IiwgbmNvbCA9IDUpICsNCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxNCkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpDQpgYGANCg0KIyMjIENvbnRyaWJ1acOnw6NvIFByZXZpZGVuY2nDoXJpYQ0KDQpgYGB7ciwgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSJ9DQpyZXN1bW9fY29udHJpYnVpbnRlIDwtIG9jdXBhZG9zMyB8Pg0KICBmaWx0ZXIoY2F0ZWdvcmlhX2VtcHJlZ28gJWluJSBjKCJmb3JtYWwiLCAiY25waiIpKSB8Pg0KICBtdXRhdGUoY29udHJpYnVpbnRlX2NhdCA9IGNhc2Vfd2hlbihWRDQwMTIgPT0gMSB+ICJDb250cmlidWludGUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBWRDQwMTIgPT0gMiB+ICJOw6NvIGNvbnRyaWJ1aW50ZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiAiTsOjbyBhcGxpY8OhdmVsIikpIHw+DQogIGdyb3VwX2J5KGNhdGVnb3JpYV9lbXByZWdvLCBjb250cmlidWludGVfY2F0KSB8Pg0KICBzdW1tYXJpc2UobiA9IHN1cnZleV90b3RhbChuYS5ybSA9IFRSVUUpKSB8Pg0KICBncm91cF9ieShjYXRlZ29yaWFfZW1wcmVnbykgfD4NCiAgbXV0YXRlKHByb3AgPSBuIC8gc3VtKG4pKSB8Pg0KICB1bmdyb3VwKCkNCg0KZ2dwbG90KHJlc3Vtb19jb250cmlidWludGUsIGFlcyh4ID0gY2F0ZWdvcmlhX2VtcHJlZ28sIHkgPSBwcm9wLCBmaWxsID0gY29udHJpYnVpbnRlX2NhdCkpICsNCiAgZ2VvbV9jb2wocG9zaXRpb24gPSAiZmlsbCIpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudF9mb3JtYXQoKSkgKw0KICBsYWJzKHRpdGxlID0gIlByb3BvcsOnw6NvIGRlIENvbnRyaWJ1aW50ZXMgcG9yIENhdGVnb3JpYSBkZSBFbXByZWdvIiwNCiAgICAgICB4ID0gIkNhdGVnb3JpYSBkZSBFbXByZWdvIiwNCiAgICAgICB5ID0gIlByb3BvcsOnw6NvICglKSIsDQogICAgICAgZmlsbCA9ICJDYXRlZ29yaWEgZGUgQ29udHJpYnVpbnRlIikgKw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KDQojIyBHcnVwby1CYXNlIC0gUHJvZmlzc8O1ZXMNCg0KUGFyYSBhIGFuw6FsaXNlIGRhcyBwcm9maXNzw7VlcyBmb3JhbSBjcmlhZG9zIHRyw6pzIG9iamV0b3MuDQoNCioqdGFiX3RvdGFsKiogcXVlIHN1bWFyaXphIG8gdG90YWwgcG9yIHByb2Zpc3PDo28gKCoqZ3J1cG9fYmFzZSoqKS4NCg0KKip0YWJfZm9ybWFsKiogcXVlIHN1bWFyaXphIHBvciB0cmFiYWxoYWRvcmVzIGZvcm1haXMNCg0KKip0YWJfY25waioqIHF1ZSBzdW1hcml6YSBwb3IgdHJhYmFsaGFkb3JlcyBwb3IgY29udGEtcHLDs3ByaWEgcXVlDQpwb3NzdWVtIENOUEoNCg0KRm9yYW0gY3JpYWRhcyBkdWFzIHZhcmnDoXZlaXMgYXV4aWxpYXJlcyBwYXJhIGFuw6FsaXNlOiBhDQoqKmRpZl9wZXJjX2NucGpfZm9ybWFsKiogcXVlIGNvbnNpc3RlIGVtIHZlcmlmaWNhciBhIHJlbGHDp8OjbyBwZXJjZW50dWFsDQpkYSBtw6lkaWEgZW50cmUgbyBzYWzDoXJpby1ob3JhIGRvIENOUEogZSBvIHNhbMOhcmlvLWhvcmEgZG8gZm9ybWFsIGUgYQ0KXCpkaWZfcGVyY19tZWRpYW5hc19jbnBqX2Zvcm1hbFwqXCogcGFyYSB2ZXJpZmljYXIgYSBtZXNtYSByZWxhw6fDo28sIG1hcw0KYSBwYXJ0aXIgZGEgbWVkaWFuYS4NCg0KVW1hIGFuw6FsaXNlIGFkZXF1YWRhIGEgcGFydGlyIGRhcyBwcm9maXNzw7VlcyBkZXZlIGNvbnNpZGVyYXIgYXMgZHVhcw0KdmFyacOhdmVpcyBlbSBjb25qdW50by4NCg0KYGBge3IsIHdhcm5pbmcgPSBGfQ0KDQp0YWJfdG90YWwgPC0gb2N1cGFkb3MzIHw+IA0KICBncm91cF9ieShncnVwb19iYXNlKSB8PiANCiAgc3VtbWFyaXNlKHRvdGFsID0gc3VydmV5X3RvdGFsKG5hLnJtID0gVFJVRSksDQogICAgICAgICAgICBzYWxhcmlvX2hvcmEgPSBzdXJ2ZXlfbWVhbihzYWxhcmlvX2hvcmEsIG5hLnJtID0gVFJVRSkpDQoNCnRhYl90b3RhbCA8LSB0YWJfdG90YWwgfD4gDQogIG11dGF0ZSh0b3RhbF9jdiA9IDEwMCAqIHRvdGFsX3NlIC8gdG90YWwpDQoNCnRhYl9mb3JtYWwgPC0gb2N1cGFkb3MzIHw+IA0KICBmaWx0ZXIoY2F0ZWdvcmlhX2VtcHJlZ28gPT0gImZvcm1hbCIpIHw+DQogIGdyb3VwX2J5KGdydXBvX2Jhc2UpIHw+IA0KICBzdW1tYXJpc2UodG90YWxfZm9ybWFsID0gc3VydmV5X3RvdGFsKCksDQogICAgICAgICAgICBzYWxhcmlvX2hvcmFfZm9ybWFsID0gc3VydmV5X21lYW4oc2FsYXJpb19ob3JhLCBuYS5ybSA9IFRSVUUsIHZhcnR5cGUgPSAic2UiKSkNCg0KdGFiX2Zvcm1hbCA8LSB0YWJfZm9ybWFsIHw+IA0KICBtdXRhdGUodG90YWxfZm9ybWFsX2N2ID0gMTAwICogdG90YWxfZm9ybWFsX3NlIC8gdG90YWxfZm9ybWFsKQ0KDQp0YWJfY25waiA8LSBvY3VwYWRvczMgfD4gDQogIGZpbHRlcihjYXRlZ29yaWFfZW1wcmVnbyA9PSAiY25waiIpIHw+DQogIGdyb3VwX2J5KGdydXBvX2Jhc2UpIHw+IA0KICBzdW1tYXJpc2UodG90YWxfY25waiA9IHN1cnZleV90b3RhbCgpLA0KICAgICAgICAgICAgc2FsYXJpb19ob3JhX2NucGogPSBzdXJ2ZXlfbWVhbihzYWxhcmlvX2hvcmEsIG5hLnJtID0gVFJVRSwgdmFydHlwZSA9ICJzZSIpKQ0KDQp0YWJfY25waiA8LSB0YWJfY25waiB8PiANCiAgbXV0YXRlKHRvdGFsX2NucGpfY3YgPSAxMDAgKiB0b3RhbF9jbnBqX3NlIC8gdG90YWxfY25waikNCg0KdGFiX2dlcmFsIDwtIHRhYl90b3RhbCB8PiANCiAgZnVsbF9qb2luKHRhYl9mb3JtYWwsIGJ5ID0gImdydXBvX2Jhc2UiKSB8PiANCiAgZnVsbF9qb2luKHRhYl9jbnBqLCBieSA9ICJncnVwb19iYXNlIikNCg0KI1ZhcmnDoXZlbCBBdXhpbGlhciAtIERpZmVyZW7Dp2EgZW50cmUgQ05QSiBlIEZvcm1hbA0KI1NlIENOUEogPiBGb3JtYWwgPSBwb3NpdGl2bw0KdGFiX2dlcmFsIDwtIHRhYl9nZXJhbCB8PiANCiAgbXV0YXRlKGRpZl9wZXJjX2NucGpfZm9ybWFsID0gMTAwICogKHNhbGFyaW9faG9yYV9jbnBqIC0gc2FsYXJpb19ob3JhX2Zvcm1hbCkgLyBzYWxhcmlvX2hvcmFfZm9ybWFsKQ0KDQojIEluZGljYWRvcmVzIGRlIHByZWNpc8OjbyAtIENvZWZpY2llbnRlIGRlIHZhcmlhw6fDo28gYWNpbWEgZGUgMjUlDQp0YWJfZ2VyYWwgPC0gdGFiX2dlcmFsIHw+IA0KICBtdXRhdGUobG93X3ByZWNpc2lvbl9mb3JtYWwgPSB0b3RhbF9mb3JtYWxfY3YgPiAyNSwgI2luZGljYWRvcmVzIGRlIGJhaXhhIHByZWNpc8OjbyAtIGNvZWZpY2llbnRlIGRlIHZhcmlhw6fDo28gYWNpbWEgZGUgMjUlDQogICAgbG93X3ByZWNpc2lvbl9jbnBqID0gdG90YWxfY25wal9jdiA+IDI1LA0KICAgIHRvdGFsX2Zvcm1hbF9leGliID0gaWZfZWxzZShsb3dfcHJlY2lzaW9uX2Zvcm1hbCwgIk5TIiwgZm9ybWF0KHJvdW5kKHRvdGFsX2Zvcm1hbCwgMCksIGJpZy5tYXJrID0gIiwiKSksDQogICAgdG90YWxfY25wal9leGliID0gaWZfZWxzZShsb3dfcHJlY2lzaW9uX2NucGosICJOUyIsIGZvcm1hdChyb3VuZCh0b3RhbF9jbnBqLCAwKSwgYmlnLm1hcmsgPSAiLCIpKSwNCiAgICBzYWxhcmlvX2hvcmFfZm9ybWFsX2V4aWIgPSBpZl9lbHNlKGxvd19wcmVjaXNpb25fZm9ybWFsLCAiTlMiLCBmb3JtYXQocm91bmQoc2FsYXJpb19ob3JhX2Zvcm1hbCwgMikpKSwNCiAgICBzYWxhcmlvX2hvcmFfY25wal9leGliID0gaWZfZWxzZShsb3dfcHJlY2lzaW9uX2NucGosICJOUyIsIGZvcm1hdChyb3VuZChzYWxhcmlvX2hvcmFfY25waiwgMikpKSwNCiAgICBkaWZfcGVyY19jbnBqX2Zvcm1hbCA9IGlmX2Vsc2UoDQogICAgICBsb3dfcHJlY2lzaW9uX2Zvcm1hbCB8IGxvd19wcmVjaXNpb25fY25waiwNCiAgICAgIE5BX3JlYWxfLA0KICAgICAgMTAwICogKHNhbGFyaW9faG9yYV9jbnBqIC0gc2FsYXJpb19ob3JhX2Zvcm1hbCkgLyBzYWxhcmlvX2hvcmFfZm9ybWFsKSkNCmBgYA0KDQpNZWRpYW5hcw0KDQpgYGB7ciwgd2FybmluZz1GfQ0KbWVkaWFuYXNfZm9ybWFsIDwtIG9jdXBhZG9zMyB8PiANCiAgZmlsdGVyKGNhdGVnb3JpYV9lbXByZWdvID09ICJmb3JtYWwiKSB8Pg0KICBncm91cF9ieShncnVwb19iYXNlKSB8PiANCiAgc3VtbWFyaXNlKG1lZGlhbmFfc2FsYXJpb19ob3JhX2Zvcm1hbCA9IHN1cnZleV9tZWRpYW4oc2FsYXJpb19ob3JhLCBuYS5ybSA9IFRSVUUsIHZhcnR5cGUgPSAic2UiKSwNCiAgICAgICAgICAgIG1lZGlhbmFfc2FsYXJpb19ob3JhX2Zvcm1hbF9zZSA9IGF0dHIobWVkaWFuYV9zYWxhcmlvX2hvcmFfZm9ybWFsLCAic2UiKSkNCg0KbWVkaWFuYXNfY25waiA8LSBvY3VwYWRvczMgfD4gDQogIGZpbHRlcihjYXRlZ29yaWFfZW1wcmVnbyA9PSAiY25waiIpIHw+DQogIGdyb3VwX2J5KGdydXBvX2Jhc2UpIHw+IA0KICBzdW1tYXJpc2UobWVkaWFuYV9zYWxhcmlvX2hvcmFfY25waiA9IHN1cnZleV9tZWRpYW4oc2FsYXJpb19ob3JhLCBuYS5ybSA9IFRSVUUsIHZhcnR5cGUgPSAic2UiKSwNCiAgICAgICAgICAgIG1lZGlhbmFfc2FsYXJpb19ob3JhX2NucGpfc2UgPSBhdHRyKG1lZGlhbmFfc2FsYXJpb19ob3JhX2NucGosICJzZSIpKQ0KDQojIEluZGljYWRvcmVzIGRlIHByZWNpc8OjbyBwYXJhIG1lZGlhbmFzDQp0YWJfZ2VyYWwgPC0gdGFiX2dlcmFsIHw+IA0KICBsZWZ0X2pvaW4obWVkaWFuYXNfZm9ybWFsLCBieSA9ICJncnVwb19iYXNlIikgfD4NCiAgbGVmdF9qb2luKG1lZGlhbmFzX2NucGosIGJ5ID0gImdydXBvX2Jhc2UiKSB8Pg0KICBtdXRhdGUoDQogICAgIyBDViBkYXMgbWVkaWFuYXMNCiAgICBtZWRpYW5hX2Zvcm1hbF9jdiA9IDEwMCAqIG1lZGlhbmFfc2FsYXJpb19ob3JhX2Zvcm1hbF9zZSAvIG1lZGlhbmFfc2FsYXJpb19ob3JhX2Zvcm1hbCwNCiAgICBtZWRpYW5hX2NucGpfY3YgPSAxMDAgKiBtZWRpYW5hX3NhbGFyaW9faG9yYV9jbnBqX3NlIC8gbWVkaWFuYV9zYWxhcmlvX2hvcmFfY25waiwNCiAgICANCiAgICAjIEluZGljYWRvcmVzIGRlIGJhaXhhIHByZWNpc8Ojbw0KICAgIGxvd19wcmVjaXNpb25fbWVkaWFuX2Zvcm1hbCA9IG1lZGlhbmFfZm9ybWFsX2N2ID4gMjUsDQogICAgbG93X3ByZWNpc2lvbl9tZWRpYW5fY25waiA9IG1lZGlhbmFfY25wal9jdiA+IDI1LA0KICAgIA0KICAgICMgRXhpYmnDp8OjbyBjb25kaWNpb25hbCBwYXJhIG1lZGlhbmFzDQogICAgbWVkaWFuYV9zYWxhcmlvX2hvcmFfZm9ybWFsX2V4aWIgPSBpZl9lbHNlKGxvd19wcmVjaXNpb25fbWVkaWFuX2Zvcm1hbCwgIk5TIiwgZm9ybWF0KHJvdW5kKG1lZGlhbmFfc2FsYXJpb19ob3JhX2Zvcm1hbCwgMikpKSwNCiAgICBtZWRpYW5hX3NhbGFyaW9faG9yYV9jbnBqX2V4aWIgPSBpZl9lbHNlKGxvd19wcmVjaXNpb25fbWVkaWFuX2NucGosICJOUyIsIGZvcm1hdChyb3VuZChtZWRpYW5hX3NhbGFyaW9faG9yYV9jbnBqLCAyKSkpLA0KICAgIA0KICAgICMgRGlmZXJlbsOnYSAlIG1lZGlhbmFzIGNvbmRpY2lvbmFkYSDDoCBwcmVjaXPDo28NCiAgICBkaWZfcGVyY19tZWRpYW5hc19jbnBqX2Zvcm1hbCA9IGlmX2Vsc2UoDQogICAgICBsb3dfcHJlY2lzaW9uX21lZGlhbl9mb3JtYWwgfCBsb3dfcHJlY2lzaW9uX21lZGlhbl9jbnBqLA0KICAgICAgTkFfcmVhbF8sDQogICAgICAxMDAgKiAobWVkaWFuYV9zYWxhcmlvX2hvcmFfY25waiAtIG1lZGlhbmFfc2FsYXJpb19ob3JhX2Zvcm1hbCkgLyBtZWRpYW5hX3NhbGFyaW9faG9yYV9mb3JtYWwpKQ0KDQpgYGANCg0KIyMgVGFiZWxhIGRlIFJlc3VsdGFkb3MgLSBHcnVwby1CYXNlIGRlIFByb2Zpc3PDtWVzDQoNCkEgdGFiZWxhIGFiYWl4byBhcHJlc2VudGEgb3MgcmVzdWx0YWRvcyBhIHBhcnRpciBkbyBkYWRvIG1haXMgZ3JhbnVsYXI6DQphcyBwcm9maXNzw7Vlcy4NCg0Kw4kgaW1wb3J0YW50ZSBmYXplciB1bWEgbGVpdHVyYSBxdWUgY29uc2lkZXJlIG9zIG7Dum1lcm9zIHBvbmRlcmFkb3MsIGFzDQptw6lkaWFzIGUgdGFtYsOpbSBhcyBtZWRpYW5hcy4NCg0KYGBge3IsIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUifQ0KdGFiX2dlcmFsX3NlbV9zZSA8LSB0YWJfZ2VyYWwgfD4gDQogIHNlbGVjdCgNCiAgICBncnVwb19iYXNlLA0KICAgIHRvdGFsLA0KICAgIHRvdGFsX2Zvcm1hbCwNCiAgICB0b3RhbF9jbnBqLA0KICAgIHNhbGFyaW9faG9yYSwNCiAgICBzYWxhcmlvX2hvcmFfZm9ybWFsLA0KICAgIHNhbGFyaW9faG9yYV9jbnBqLA0KICAgIGRpZl9wZXJjX2NucGpfZm9ybWFsLA0KICAgIG1lZGlhbmFfc2FsYXJpb19ob3JhX2Zvcm1hbF9leGliLA0KICAgIG1lZGlhbmFfc2FsYXJpb19ob3JhX2NucGpfZXhpYiwNCiAgICBkaWZfcGVyY19tZWRpYW5hc19jbnBqX2Zvcm1hbCkgfD4gDQogIGFycmFuZ2UoZGVzYyh0b3RhbF9jbnBqKSkNCg0KY29sbmFtZXModGFiX2dlcmFsX3NlbV9zZSkgPC0gYygNCiAgIlByb2Zpc3PDo28iLA0KICAiVG90YWwgZGEgUHJvZmlzc8OjbyIsDQogICJUb3RhbCBGb3JtYWwiLA0KICAiVG90YWwgQ05QSiIsDQogICJTYWzDoXJpby1ob3JhIC0gUHJvZmlzc8OjbyAoTcOpZGlhKSIsDQogICJTYWzDoXJpby1ob3JhIEZvcm1hbCAoTcOpZGlhKSIsDQogICJTYWzDoXJpby1ob3JhIENOUEogKE3DqWRpYSkiLA0KICAiRGlmLiAlIE3DqWRpYSBDTlBKIHZzLiBGb3JtYWwiLA0KICAiTWVkaWFuYSBGb3JtYWwiLA0KICAiTWVkaWFuYSBDTlBKIiwNCiAgIkRpZi4gJSBNZWRpYW5hIENOUEogdnMuIEZvcm1hbCIpDQoNCiMgQXR1YWxpemFyIG8gZGF0YXRhYmxlIHBhcmEgZXhpYmlyIGUgZm9ybWF0YXIgYXMgbm92YXMgY29sdW5hcw0KZGF0YXRhYmxlKHRhYl9nZXJhbF9zZW1fc2UsDQogIG9wdGlvbnMgPSBsaXN0KA0KICAgIHBhZ2VMZW5ndGggPSAyMCwNCiAgICBjb2x1bW5EZWZzID0gbGlzdCgNCiAgICAgIGxpc3QodGFyZ2V0cyA9IDAsIGNyZWF0ZWRDZWxsID0gSlMoImZ1bmN0aW9uKHRkKXskKHRkKS5jc3Moeydib3JkZXItcmlnaHQnOiAnNHB4IGRvdWJsZSAjMzMzJ30pO30iKSksDQogICAgICBsaXN0KHRhcmdldHMgPSAzLCBjcmVhdGVkQ2VsbCA9IEpTKCJmdW5jdGlvbih0ZCl7JCh0ZCkuY3NzKHsnYm9yZGVyLXJpZ2h0JzogJzRweCBkb3VibGUgIzMzMyd9KTt9IikpLA0KICAgICAgbGlzdCh0YXJnZXRzID0gNywgY3JlYXRlZENlbGwgPSBKUygiZnVuY3Rpb24odGQpeyQodGQpLmNzcyh7J2JvcmRlci1yaWdodCc6ICc0cHggZG91YmxlICMzMzMnfSk7fSIpKSwNCiAgICAgIGxpc3QodGFyZ2V0cyA9IDEwLCBjcmVhdGVkQ2VsbCA9IEpTKCJmdW5jdGlvbih0ZCl7JCh0ZCkuY3NzKHsnYm9yZGVyLXJpZ2h0JzogJzRweCBkb3VibGUgIzMzMyd9KTt9IikpDQogICAgICAjbGlzdCh0YXJnZXRzID0gMTAsIGNyZWF0ZWRDZWxsID0gSlMoImZ1bmN0aW9uKHRkKXskKHRkKS5jc3Moeydib3JkZXItcmlnaHQnOiAnNHB4IGRvdWJsZSAjMzMzJ30pO30iKSkNCiAgICApDQogICksDQogIHJvd25hbWVzID0gRkFMU0UsDQogIGNsYXNzID0gJ2NlbGwtYm9yZGVyIHN0cmlwZScsDQogIGNhcHRpb24gPSBodG1sdG9vbHM6OnRhZ3MkY2FwdGlvbigNCiAgICBzdHlsZSA9ICdjYXB0aW9uLXNpZGU6IHRvcDsgdGV4dC1hbGlnbjogbGVmdDsgZm9udC1zaXplOiAxNnB4OyBmb250LXdlaWdodDogYm9sZDsnLA0KICAgICJUYWJlbGEgQ29tcGFyYXRpdmEgcG9yIFByb2Zpc3PDtWVzIGNvbSBNw6lkaWFzIGUgTWVkaWFuYXMiLA0KICAgIGh0bWx0b29sczo6dGFncyRkaXYoDQogICAgICBzdHlsZSA9ICdmb250LXNpemU6IDEycHg7IGZvbnQtd2VpZ2h0OiBub3JtYWw7IGNvbG9yOiBncmF5OyBtYXJnaW4tdG9wOiA0cHg7JywNCiAgICAgICJOb3RhOiBWYWxvcmVzIGNvbSBjb2VmaWNpZW50ZSBkZSB2YXJpYcOnw6NvIGFjaW1hIGRlIDI1JSBmb3JhbSByZXRpcmFkb3MgLS0tIEEgb3JkZW5hw6fDo28tcGFkcsOjbyBlc3TDoSBlbSBvcmRlbSBkZWNyZXNjZW50ZSBwYXJhIG8gVG90YWwgZGUgQ05QSiIgDQogICAgKSkNCikgfD4gDQogIGZvcm1hdEN1cnJlbmN5KGNvbHVtbnMgPSBjKCdTYWzDoXJpby1ob3JhIC0gUHJvZmlzc8OjbyAoTcOpZGlhKScsICdTYWzDoXJpby1ob3JhIEZvcm1hbCAoTcOpZGlhKScsICdTYWzDoXJpby1ob3JhIENOUEogKE3DqWRpYSknLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAnRGlmLiAlIE3DqWRpYSBDTlBKIHZzLiBGb3JtYWwnLCAnTWVkaWFuYSBGb3JtYWwnLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAnTWVkaWFuYSBDTlBKJywgJ0RpZi4gJSBNZWRpYW5hIENOUEogdnMuIEZvcm1hbCcpLCBjdXJyZW5jeSA9ICIiLCBkaWdpdHMgPSAyLCBpbnRlcnZhbCA9IDMsIG1hcmsgPSAiLiINCiAgKSB8PiANCiAgZm9ybWF0Um91bmQoDQogICAgY29sdW1ucyA9IGMoJ1RvdGFsIGRhIFByb2Zpc3PDo28nLCAnVG90YWwgRm9ybWFsJywgJ1RvdGFsIENOUEonKSwNCiAgICBkaWdpdHMgPSAwLCBtYXJrID0gIi4iDQogICkgfD4NCiAgZm9ybWF0U3R5bGUoDQogICAgY29sdW1ucyA9IDE6bmNvbCh0YWJfZ2VyYWxfc2VtX3NlKSwNCiAgICBmb250RmFtaWx5ID0gIkNhbGlicmksIHNhbnMtc2VyaWYiKQ0KYGBgDQoNCiMjIyBDb25jbHVzw7VlcyBQYXJjaWFpcw0KDQpVbWEgYW7DoWxpc2UgYSBwYXJ0aXIgZGFzIHByb2Zpc3PDtWVzIG5vcyBwZXJtaXRlIGF2YWxpYXIgZGlzdGludGFzDQpxdWVzdMO1ZXM6DQoNCioqRW0gbsO6bWVyb3MgYWJzb2x1dG9zLCBhcyA1IHByb2Zpc3PDtWVzIGNvbSBtYWlzIHRyYWJhbGhhZG9yZXMgc8OjbzoqKg0KDQotICAgRXNjcml0dXLDoXJpbyBHZXJhbCAob3Ugc2VqYSwgdHJhYmFsaGFkb3JlcyBkZSBhcG9pbyBhZG1pbmlzdHJhdGl2bw0KICAgIGdlcmFsKQ0KLSAgIEJhbGNvbmlzdGFzIGUgdmVuZGVkb3JlcyBkZSBsb2phcw0KLSAgIFRyYWJhbGhhZG9yZXMgZG9zIHNlcnZpw6dvcyBkb23DqXN0aWNvcyBlbSBnZXJhbFwNCi0gICBDb21lcmNpYW50ZXMgZGUgbG9qYXMNCi0gICBUcmFiYWxoYWRvcmVzIGRlIGxpbXBlemEgZGUgaW50ZXJpb3IgZGUgZWRpZsOtY2lvcywgZXNjcml0w7NyaW9zLA0KICAgIGhvdMOpaXMgZSBvdXRyb3MgZXN0YWJlbGVjaW1lbnRvcw0KDQoqKkVtIG7Dum1lcm9zIGFic29sdXRvcywgYXMgNSBwcm9maXNzw7VlcyBjb20gbWFpcyB0cmFiYWxoYWRvcmVzDQpmb3JtYWxpemFkb3Mgc8OjbzoqKg0KDQotICAgQmFsY29uaXN0YXMgZSB2ZW5kZWRvcmVzIGRlIGxvamFzDQotICAgRXNjcml0dXLDoXJpb3MgZ2VyYWlzXA0KLSAgIFRyYWJhbGhhZG9yZXMgZGUgbGltcGV6YSBkZSBpbnRlcmlvciBkZSBlZGlmw61jaW9zLCBlc2NyaXTDs3Jpb3MsDQogICAgaG90w6lpcyBlIG91dHJvcyBlc3RhYmVsZWNpbWVudG9zXA0KLSAgIENvbmR1dG9yZXMgZGUgY2FtaW5ow7VlcyBwZXNhZG9zXA0KLSAgIEd1YXJkYXMgZGUgc2VndXJhbsOnYQ0KDQoqKkVtIG7Dum1lcm9zIGFic29sdXRvcywgYXMgNSBwcm9maXNzw7VlcyBjb20gbWFpcyB0cmFiYWxoYWRvcmVzIHBvcg0KY29udC1wcsOzcHJpYSBxdWUgcG9zc3VlbSBDTlBKIHPDo286KioNCg0KLSAgIENvbWVyY2lhbnRlcyBkZSBsb2phcw0KLSAgIENhYmVsZWlyZWlyb3MNCi0gICBFc3BlY2lhbGlzdGFzIGVtIHRyYXRhbWVudG8gZGUgYmVsZXphIGUgYWZpbnMNCi0gICBDb25kdXRvcmVzIGRlIGF1dG9tw7N2ZWlzLCB0YXhpcyBlIGNhbWluaG9uZXRlc1wNCi0gICBQZWRyZWlyb3MNCg0KVW1hIGFuw6FsaXNlIGRhIHRhYmVsYSBjb20gdW1hIGRlc2FncmVnYcOnw6NvIG11aXRvIGdyYW5kZSBkZXZlIGNvbnNpZGVyYXINCm9zIHZhbG9yZXMgZGUgc2Fsw6FyaW8taG9yYSBhIHBhcnRpciBkbyBuw7ptZXJvIHBvbmRlcmFkbyBkZQ0KcHJvZmlzc2lvbmFpcy4NCg0KQXNzaW0sIGFzIGNpbmNvIG1haW9yZXMgbcOpZGlhcyBkZSBzYWzDoXJpby1ob3JhIGRlIGZvcm1hbGl6YWRvcywgcXVlDQpjb25zaWRlcmUgc29tZW50ZSBhY2ltYSBkZSAyMCBtaWwgcHJvZmlzc2lvbmFpcywgc8OjbyBhcyBzZWd1aW50ZXMNCnByb2Zpc3PDtWVzOg0KDQotICAgTcOpZGljb3MgZXNwZWNpYWxpc3RhcyAtIFJcJCA1NC4xNFwNCi0gICBFbmdlbmhlaXJvcyBtZWPDom5pY29zIC0gUlwkIDQ1LjE3XA0KLSAgIERpcmlnZW50ZXMgZGUgc2VydmnDp29zIGRlIHRlY25vbG9naWEgZGEgaW5mb3JtYcOnw6NvIGUgY29tdW5pY2HDp8O1ZXMgLQ0KICAgIFJcJCA0NS4xMVwNCi0gICBFbmdlbmhlaXJvcyBpbmR1c3RyaWFpcyBlIGRlIHByb2R1w6fDo28gLSBSXCQgNDIuMjENCi0gICBFbmdlbmhlaXJvcyBuw6NvIGNsYXNzaWZpY2Fkb3MgYW50ZXJpb3JtZW50ZSAtIFJcJCAzOC43NA0KDQpQb3Igc3VhIHZleiwgYXMgY2luY28gbWFpb3JlcyBtw6lkaWFzIGRlIHNhbMOhcmlvLWhvcmEgZGUgY29udGEtcHLDs3ByaWENCmNvbSBDTlBKLCBxdWUgY29uc2lkZXJlIHNvbWVudGUgYWNpbWEgZGUgMjAgbWlsIHByb2Zpc3Npb25haXMsIHPDo28gYXMNCnNlZ3VpbnRlcyBwcm9maXNzw7VlczoNCg0KLSAgIE3DqWRpY29zIGVzcGVjaWFsaXN0YXMgLSBSXCQgNTAuODkNCi0gICBBbmFsaXN0YXMgZGUgc2lzdGVtYXMgLSBSXCQgNDMuMTENCi0gICBBZHZvZ2Fkb3MgZSBqdXJpc3RhcyAtIFJcJCAzNC45OQ0KLSAgIEVuZ2VuaGVpcm9zIGNpdmlzIC0gUlwkIDM0LjQ2DQotICAgQW5hbGlzdGEgZGUgR2VzdMOjbyBlIEFkbWluaXN0cmHDp8OjbyAtIFJcJCAzMy41MQ0KDQpEYWRvIG8gb2JqZXRpdm8gZG8gZXN0dWRvLCBlbnRyZXRhbnRvLCDDqSByZWxldmFudGUgZGlyZWNpb25hciBvIG9saGFyDQpwYXJhIGEgKipkaWZlcmVuw6dhKiogZW50cmUgcHJvZmlzc2lvbmFpcyBkZSBvY3VwYcOnw6NvIHNlbWVsaGFudGUuIE5lc3NlDQpzZW50aWRvLCDDqSBpbXBvcnRhbnRlIHNlbXByZSBvbGhhciBhIGRpZmVyZW7Dp2EgYSBwYXJ0aXIgZGUgdW1hIGFuw6FsaXNlDQpjb29yZGVuYWRhIGRlIG3DqWRpYSBlIG1lZGlhbmEuIEEgcGFydGlyIGRvIHF1YWwgcG9kZS1zZSBjb25jbHVpcjoNCg0KQXMgbWFpb3JlcyBkaWZlcmVuw6dhcyBlbSBxdWUgw6kgbyBQSiByZWNlYmUgbWFpcyBxdWUgbyBmb3JtYWxpemFkbw0KZW5jb250cmFtLXNlIG5hcyBzZWd1aW50ZXMgcHJvZmlzc8O1ZXMNCg0KLSAgICoqQWdlbnRlcyBpbW9iaWxpw6FyaW9zKiogLSBvbmRlIHVtIFBKIChcfjg5IG1pbCkgcmVjZWJlIHVtYSBtw6lkaWEgZGUNCiAgICBSXCQgMzAsNTAgZSBvIENMVCAoXH4yOSBtaWwpIHJlY2ViZSB1bWEgbcOpZGlhIGRlIFJcJCAxNiwwOS4gQQ0KICAgIGFuw6FsaXNlIGRhIG1lZGlhbmEgdGFtYsOpbSBpbmRpY2EgdW1hIGRpZmVyZW7Dp2EgcmVsZXZhbnRlIGNvbSBmb3JtYWwNCiAgICBhIFJcJCAxMS42OSBlIFBKIGEgUlwkIDI0LDcyLiDDiSBpbXBvcnRhbnRlIGRlc3RhY2FyLCBlbnRyZXRhbnRvIHF1ZQ0KICAgIGEgbWFpb3JpYSBkb3MgcHJvZmlzc2lvbmFpcyAoY2VyY2EgZGUgNjMlKSBuw6NvIGVzdMOjbyBlbSBuZW5odW1hDQogICAgZGVzc2FzIGR1YXMgY2xhc3NpZmljYcOnw7Vlcy4NCg0KQW7DoWxpc2Ugc2VtZWxoYW50ZSBkZXZlIHNlciBmZWl0YSBwYXJhICoqRXNwZWNpYWxpc3RhcyBlbSB0cmF0YW1lbnRvIGRlDQpiZWxlemEgZSBhZmlucyoqIHF1ZSBhcHJlc2VudGEgZGlmZXJlbsOnYSBzaWduaWZpY2F0aXZhIGVudHJlIGFzIGR1YXMNCmNhdGVnb3JpYXMgKDgyJSBhIG1haXMgcGFyYSBQSiBuYSBtw6lkaWEgZSA1NiUgYSBtYWlzIG5hIG1lZGlhbmEpLCBtYXMNCnRlbS1zZSBjZXJjYSBkZSA3NSUgZGUgdG9kb3Mgb3MgcHJvZmlzc2lvbmFpcyBmb3JhIGRlc3NhcyBkdWFzDQpjYXRlZ29yaWFzLg0KDQpBcyBkZW1haXMgZGlmZXJlbsOnYXMgcXVlIHBvZGVtIHNlciBkZXN0YWNhZGFzIGVzdMOjbyBuYXMgc2VndWludGVzDQpwcm9maXNzw7VlczoNCg0KLSAgIFRyYWJhbGhhZG9yZXMgZGUgYWfDqm5jaWFzIGRlIHZpYWdlbVwNCi0gICBDb25kdXRvcmVzIGRlIGF1dG9tw7N2ZWlzLCB0YXhpcyBlIGNhbWluaG9uZXRlc1wNCi0gICBSZXByZXNlbnRhbnRlcyBjb21lcmNpYWlzDQotICAgTGF2YWRvcmVzIGRlIHZlw61jdWxvcw0KLSAgIENvbmR1dG9yZXMgZGUgY2FtaW5ow7VlcyBwZXNhZG9zDQoNCiMjIEdydXBhbWVudG9zIGRlIEF0aXZpZGFkZQ0KDQpgYGB7ciwgZmlnLndpZHRoID0gMTAsIGZpZy5oZWlnaHQgPSAxMiwgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSJ9DQoNCnZkNDAxMF9sYWJlbHMgPC0gYygNCiAgIjAxIiA9ICJBZ3JpY3VsdHVyYSwgcGVjdcOhcmlhLCBwcm9kdcOnw6NvIGZsb3Jlc3RhbCwgcGVzY2EgZSBhcXVpY3VsdHVyYSIsDQogICIwMiIgPSAiSW5kw7pzdHJpYSBnZXJhbCIsDQogICIwMyIgPSAiQ29uc3RydcOnw6NvIiwNCiAgIjA0IiA9ICJDb23DqXJjaW8sIHJlcGFyYcOnw6NvIGRlIHZlw61jdWxvcyBhdXRvbW90b3JlcyBlIG1vdG9jaWNsZXRhcyIsDQogICIwNSIgPSAiVHJhbnNwb3J0ZSwgYXJtYXplbmFnZW0gZSBjb3JyZWlvIiwNCiAgIjA2IiA9ICJBbG9qYW1lbnRvIGUgYWxpbWVudGHDp8OjbyIsDQogICIwNyIgPSAiSW5mb3JtYcOnw6NvLCBjb211bmljYcOnw6NvIGUgYXRpdmlkYWRlcyBmaW5hbmNlaXJhcywgaW1vYmlsacOhcmlhcywgcHJvZmlzc2lvbmFpcyBlIGFkbWluaXN0cmF0aXZhcyIsDQogICIwOCIgPSAiQWRtaW5pc3RyYcOnw6NvIHDDumJsaWNhLCBkZWZlc2EgZSBzZWd1cmlkYWRlIHNvY2lhbCIsDQogICIwOSIgPSAiRWR1Y2HDp8Ojbywgc2HDumRlIGh1bWFuYSBlIHNlcnZpw6dvcyBzb2NpYWlzIiwNCiAgIjEwIiA9ICJPdXRyb3MgU2VydmnDp29zIiwNCiAgIjExIiA9ICJTZXJ2acOnb3MgZG9tw6lzdGljb3MiLA0KICAiMTIiID0gIkF0aXZpZGFkZXMgbWFsIGRlZmluaWRhcyIpDQoNCm9jdXBhZG9zMyA8LSBvY3VwYWRvczMgfD4NCiAgbXV0YXRlKFZENDAxMF9sYWJlbCA9IHZkNDAxMF9sYWJlbHNbYXMuY2hhcmFjdGVyKFZENDAxMCldKQ0KDQpyZXN1bW9fc2FsYXJpbyA8LSBvY3VwYWRvczMgfD4NCiAgZ3JvdXBfYnkoVkQ0MDEwX2xhYmVsLCBjYXRlZ29yaWFfZW1wcmVnbykgfD4NCiAgc3VtbWFyaXNlKHNhbGFyaW9fbWVkaW8gPSBtZWFuKHNhbGFyaW9faG9yYSwgbmEucm0gPSBUUlVFKSwNCiAgICAgICAgICAgIG4gPSBzdXJ2ZXlfdG90YWwobmEucm0gPSBUUlVFKSkgfD4NCiAgdW5ncm91cCgpIHw+DQogIG11dGF0ZShuX2xhYmVsID0gcGFzdGUwKCJuID0gIiwgc2NhbGVzOjpjb21tYShyb3VuZChhcy5udW1lcmljKG4pKSkpKQ0KDQojIEdyw6FmaWNvIGRlIGJhcnJhcyBjb20gZmFjZXQNCmdncGxvdChyZXN1bW9fc2FsYXJpbywgYWVzKHggPSBjYXRlZ29yaWFfZW1wcmVnbywgeSA9IHNhbGFyaW9fbWVkaW8sIGZpbGwgPSBjYXRlZ29yaWFfZW1wcmVnbykpICsNCiAgZ2VvbV9jb2wocG9zaXRpb24gPSAiZG9kZ2UiKSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBwYXN0ZTAoIm49Iiwgc2NhbGVzOjpjb21tYShyb3VuZChuKSkpLCB5ID0gc2FsYXJpb19tZWRpbyArIG1heChzYWxhcmlvX21lZGlvLCBuYS5ybSA9IFRSVUUpICogMC4wMyksDQogICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC45KSwgc2l6ZSA9IDQsIGNvbG9yID0gImJsYWNrIikgKw0KICBmYWNldF93cmFwKH4gVkQ0MDEwX2xhYmVsLCBzY2FsZXMgPSAiZnJlZV95IiwgbmNvbCA9IDMsDQogICAgICAgICAgICAgbGFiZWxsZXIgPSBsYWJlbGxlcihWRDQwMTBfbGFiZWwgPSBsYWJlbF93cmFwX2dlbih3aWR0aCA9IDQwKSkpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6ZG9sbGFyX2Zvcm1hdChwcmVmaXggPSAiUiQgIikpICsNCiAgbGFicyh0aXRsZSA9ICJNw6lkaWEgZG8gU2Fsw6FyaW8tSG9yYSBwb3IgQ2F0ZWdvcmlhIGRlIEVtcHJlZ28gZSBBdGl2aWRhZGVcbihuIHBvbmRlcmFkbyBwb3IgYmFycmEpIiwNCiAgICAgICB4ID0gIkNhdGVnb3JpYSBkZSBFbXByZWdvIiwNCiAgICAgICB5ID0gIlNhbMOhcmlvLUhvcmEgTcOpZGlvIikgKw0KICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDEzKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMCwgaGp1c3QgPSAwLjUpLCBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpDQoNCm1heF9zYWxhcmlvIDwtIDUwICMgcG9udG8gcHLDs3hpbW8gZGEgYm9yZGEgZGlyZWl0YSBkbyBncsOhZmljbywgdGVuZG8gZW0gdmlzdGEgb3V0bGllcnMNCg0KI0JveHBsb3QNCmdncGxvdChvY3VwYWRvczMsIGFlcyh4ID0gc2FsYXJpb19ob3JhLCB5ID0gY2F0ZWdvcmlhX2VtcHJlZ28sIGZpbGwgPSBjYXRlZ29yaWFfZW1wcmVnbykpICsNCiAgZ2VvbV9ib3hwbG90KGFscGhhID0gMC43LCBvdXRsaWVyLmNvbG91ciA9ICJyZWQiKSArDQogIGZhY2V0X3dyYXAofiBWRDQwMTBfbGFiZWwsIHNjYWxlcyA9ICJmcmVlX3kiLCBuY29sID0gMywNCiAgICAgICAgICAgICBsYWJlbGxlciA9IGxhYmVsbGVyKFZENDAxMF9sYWJlbCA9IGxhYmVsX3dyYXBfZ2VuKHdpZHRoID0gNDApKSkgKw0KICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0gZG9sbGFyX2Zvcm1hdChwcmVmaXggPSAiUiQgIikpICsNCiAgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKDAsIDYwKSkgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIkRpc3RyaWJ1acOnw6NvIGRvIFNhbMOhcmlvLUhvcmEgcG9yIENhdGVnb3JpYSBkZSBFbXByZWdvIGUgQXRpdmlkYWRlXG4oTGltaXRlIGRlIHZpc3VhbGl6YcOnw6NvOiBSJCA2MCkiLA0KICAgIHggPSAiU2Fsw6FyaW8tSG9yYSIsDQogICAgeSA9ICJDYXRlZ29yaWEgZGUgRW1wcmVnbyIpICsNCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxMykgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsNCiAgZ2VvbV90ZXh0KA0KICAgIGRhdGEgPSByZXN1bW9fc2FsYXJpbywNCiAgICBtYXBwaW5nID0gYWVzKHggPSBtYXhfc2FsYXJpbywgeSA9IGNhdGVnb3JpYV9lbXByZWdvLCBsYWJlbCA9IG5fbGFiZWwpLA0KICAgIGluaGVyaXQuYWVzID0gRkFMU0UsDQogICAgaGp1c3QgPSAwLA0KICAgIHNpemUgPSAzKQ0KYGBgDQoNCiMjIEdydXBhbWVudG9zIE9jdXBhY2lvbmFpcw0KDQpgYGB7ciwgZmlnLndpZHRoID0gMTAsIGZpZy5oZWlnaHQgPSAxMiwgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSJ9DQojIERpY2lvbsOhcmlvIGRvcyByw7N0dWxvcyBkYXMgb2N1cGHDp8O1ZXMgLSBWRDQwMTENCnZkNDAxMV9sYWJlbHMgPC0gYygNCiAgIjAxIiA9ICJEaXJldG9yZXMgZSBnZXJlbnRlcyIsDQogICIwMiIgPSAiUHJvZmlzc2lvbmFpcyBkYXMgY2nDqm5jaWFzIGUgaW50ZWxlY3R1YWlzIiwNCiAgIjAzIiA9ICJUw6ljbmljb3MgZSBwcm9maXNzaW9uYWlzIGRlIG7DrXZlbCBtw6lkaW8iLA0KICAiMDQiID0gIlRyYWJhbGhhZG9yZXMgZGUgYXBvaW8gYWRtaW5pc3RyYXRpdm8iLA0KICAiMDUiID0gIlRyYWJhbGhhZG9yZXMgZG9zIHNlcnZpw6dvcywgdmVuZGVkb3JlcyBkb3MgY29tw6lyY2lvcyBlIG1lcmNhZG9zIiwNCiAgIjA2IiA9ICJUcmFiYWxoYWRvcmVzIHF1YWxpZmljYWRvcyBkYSBhZ3JvcGVjdcOhcmlhLCBmbG9yZXN0YWlzLCBkYSBjYcOnYSBlIGRhIHBlc2NhIiwNCiAgIjA3IiA9ICJUcmFiYWxoYWRvcmVzIHF1YWxpZmljYWRvcywgb3BlcsOhcmlvcyBlIGFydGVzw7VlcyBkYSBjb25zdHJ1w6fDo28sIGRhcyBhcnRlcyBtZWPDom5pY2FzIGUgb3V0cm9zIG9mw61jaW9zIiwNCiAgIjA4IiA9ICJPcGVyYWRvcmVzIGRlIGluc3RhbGHDp8O1ZXMgZSBtw6FxdWluYXMgZSBtb250YWRvcmVzIiwNCiAgIjA5IiA9ICJPY3VwYcOnw7VlcyBlbGVtZW50YXJlcyIsDQogICIxMCIgPSAiTWVtYnJvcyBkYXMgZm9yw6dhcyBhcm1hZGFzLCBwb2xpY2lhaXMgZSBib21iZWlyb3MgbWlsaXRhcmVzIiwNCiAgIjExIiA9ICJPY3VwYcOnw7VlcyBtYWxkZWZpbmlkYXMiKQ0KDQpvY3VwYWRvczMgPC0gb2N1cGFkb3MzIHw+DQogIG11dGF0ZShWRDQwMTFfbGFiZWwgPSB2ZDQwMTFfbGFiZWxzW2FzLmNoYXJhY3RlcihWRDQwMTEpXSB8PiBmYWN0b3IobGV2ZWxzID0gdmQ0MDExX2xhYmVscykpDQoNCnJlc3Vtb19zYWxhcmlvMiA8LSBvY3VwYWRvczMgfD4NCiAgZ3JvdXBfYnkoVkQ0MDExX2xhYmVsLCBjYXRlZ29yaWFfZW1wcmVnbykgfD4NCiAgc3VtbWFyaXNlKHNhbGFyaW9fbWVkaW8gPSBtZWFuKHNhbGFyaW9faG9yYSwgbmEucm0gPSBUUlVFKSwNCiAgICAgICAgICAgIG4gPSBzdXJ2ZXlfdG90YWwobmEucm0gPSBUUlVFKSkgfD4NCiAgdW5ncm91cCgpIHw+DQogIG11dGF0ZShuX2xhYmVsID0gcGFzdGUwKCJuID0gIiwgc2NhbGVzOjpjb21tYShyb3VuZChhcy5udW1lcmljKG4pKSkpKQ0KDQojIEdyw6FmaWNvIGRlIGJhcnJhcyBjb20gZmFjZXQNCmdncGxvdChyZXN1bW9fc2FsYXJpbzIsIGFlcyh4ID0gY2F0ZWdvcmlhX2VtcHJlZ28sIHkgPSBzYWxhcmlvX21lZGlvLCBmaWxsID0gY2F0ZWdvcmlhX2VtcHJlZ28pKSArDQogIGdlb21fY29sKHBvc2l0aW9uID0gImRvZGdlIikgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGFzdGUwKCJuPSIsIHNjYWxlczo6Y29tbWEocm91bmQobikpKSwgeSA9IHNhbGFyaW9fbWVkaW8gKyBtYXgoc2FsYXJpb19tZWRpbywgbmEucm0gPSBUUlVFKSAqIDAuMDMpLA0KICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOSksIHNpemUgPSA0LCBjb2xvciA9ICJibGFjayIpICsNCiAgZmFjZXRfd3JhcCh+IFZENDAxMV9sYWJlbCwgc2NhbGVzID0gImZyZWVfeSIsIG5jb2wgPSAzLA0KICAgICAgICAgICAgIGxhYmVsbGVyID0gbGFiZWxsZXIoVkQ0MDExX2xhYmVsID0gbGFiZWxfd3JhcF9nZW4od2lkdGggPSA0MCkpKSArDQogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OmRvbGxhcl9mb3JtYXQocHJlZml4ID0gIlIkICIpKSArDQogIGxhYnModGl0bGUgPSAiTcOpZGlhIGRvIFNhbMOhcmlvLUhvcmEgcG9yIENhdGVnb3JpYSBkZSBFbXByZWdvIGUgR3J1cG8gT2N1cGFjaW9uYWxcbihuIHBvbmRlcmFkbyBwb3IgYmFycmEpIiwNCiAgICAgICB4ID0gIkdydXBvIE9jdXBhY2lvbmFsIiwNCiAgICAgICB5ID0gIlNhbMOhcmlvLUhvcmEgTcOpZGlvIikgKw0KICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDEzKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMCwgaGp1c3QgPSAwLjUpLCBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpDQoNCiMgUGxvdCBib3hwbG90IGhvcml6b250YWwgY29tIG4gY29tbyB0ZXh0bw0KZ2dwbG90KG9jdXBhZG9zMywgYWVzKHggPSBzYWxhcmlvX2hvcmEsIHkgPSBjYXRlZ29yaWFfZW1wcmVnbywgZmlsbCA9IGNhdGVnb3JpYV9lbXByZWdvKSkgKw0KICBnZW9tX2JveHBsb3QoYWxwaGEgPSAwLjcsIG91dGxpZXIuY29sb3VyID0gInJlZCIpICsNCiAgZmFjZXRfd3JhcCh+IFZENDAxMV9sYWJlbCwgc2NhbGVzID0gImZyZWVfeSIsIG5jb2wgPSAzLA0KICAgICAgICAgICAgIGxhYmVsbGVyID0gbGFiZWxsZXIoVkQ0MDExX2xhYmVsID0gbGFiZWxfd3JhcF9nZW4od2lkdGggPSA0MCkpKSArDQogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBkb2xsYXJfZm9ybWF0KHByZWZpeCA9ICJSJCAiKSkgKw0KICBjb29yZF9jYXJ0ZXNpYW4oeGxpbSA9IGMoMCwgNjApKSArDQogIGxhYnModGl0bGUgPSAiRGlzdHJpYnVpw6fDo28gZG8gU2Fsw6FyaW8tSG9yYSBwb3IgQ2F0ZWdvcmlhIGRlIEVtcHJlZ28gZSBHcnVwYW1lbnRvIE9jdXBhY2lvbmFsXG4oTGltaXRlIGRlIHZpc3VhbGl6YcOnw6NvOiBSJCAxMDApIiwNCiAgICAgICB4ID0gIlNhbMOhcmlvLUhvcmEiLA0KICAgICAgIHkgPSAiQ2F0ZWdvcmlhIGRlIEVtcHJlZ28iKSArDQogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTMpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArDQogIGdlb21fdGV4dChkYXRhID0gcmVzdW1vX3NhbGFyaW8yLA0KICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0gbWF4X3NhbGFyaW8sIHkgPSBjYXRlZ29yaWFfZW1wcmVnbywgbGFiZWwgPSBuX2xhYmVsKSwNCiAgICAgICAgICAgIGluaGVyaXQuYWVzID0gRkFMU0UsDQogICAgICAgICAgICBoanVzdCA9IDAsDQogICAgICAgICAgICBzaXplID0gMykNCmBgYA0KDQojIEFuw6FsaXNlIEluZmVyZW5jaWFsDQoNCiMjIE1pbmNlcg0KDQpFeGlzdGUgdW1hIGRpZmVyZW7Dp2Egc2FsYXJpYWwgZW50cmUgYSBjb25kacOnw6NvICJDb250YS1QcsOzcHJpYSBjb20gQ05QSiINCmUgIkZvcm1hbCAtIENMVCIuDQoNCkEgcGVyZ3VudGEgcXVlIHNlIGNvbG9jYSwgZW50cmV0YW50bywgw6k6ICoqbyBxdWFudG8gZXNzYSBkaWZlcmVuw6dhDQpzYWxhcmlhbCBkZXZlLXNlIMOgIGNvbmRpw6fDo28gUEovRm9ybWFsPyoqDQoNClBhcmEgaXNzbywgdmFtb3MgZmF6ZXIgdW0gbW9kZWxvIGRlIHJlZ3Jlc3PDo28gYSBwYXJ0aXIgZGFzIGVxdWHDp8O1ZXMgZGUNCk1pbmNlci4NCg0KIyMjIFJlY29kaWZpY2HDp8OjbyBkZSBWYXJpw6F2ZWlzDQoNCk5vIGPDs2RpZ28gYWJhaXhvIGZvaSBjcmlhZG8gbyBsb2coc2FsYXJpb19ob3JhKSwgY29sb2NhZG9zIG9zIHLDs3R1bG9zDQpwYXJhIHNleG8gZSByYcOnYS9jb3IuDQoNCkFsw6ltIGRpc3NvLCBzZXLDoSBjcmlhZGEgYSB2YXJpw6F2ZWwgKippZGFkZV9jZW50cmFsaXphZGEqKiBxdWUgY29uc2lzdGUNCmVtDQoNCiQkDQpcdGV4dHtJZGFkZV9DZW50cmFsaXphZGF9X3tpfSA9IElkYWRlX3tpfSAtIFxvdmVybGluZXtJZGFkZX0NCiQkIEVzc2EgdmFyacOhdmVsIHBlcm1pdGUgZGltaW51aXIgYSBtdWx0aWNvbGluZWFyaWRhZGUgZW50cmUgaWRhZGUgZQ0KaWRhZGVcXjINCg0KUGFyYSB1bWEgYXByb3hpbWHDp8OjbyBkYSB2YXJpYXZlbCAqKmV4cGVyacOqbmNpYSoqIHNlcsOhIGZlaXRvIG8gc2VndWludGUNCmPDoWxjdWxvDQoNCiQkDQpcdGV4dHtFeHBlcmnDqm5jaWF9ID0gSWRhZGUgLSBBbm9zIGRlIEVzY29sYXJpZGFkZSAtIDUNCiQkDQoNCmBgYHtyLCBjbGFzcy5zb3VyY2UgPSAiZm9sZC1oaWRlIn0NCm9jdXBhZG9zMyA8LSBvY3VwYWRvczMgfD4NCiAgbXV0YXRlKA0KICAgICMgbG9nIGRvIHNhbMOhcmlvLWhvcmEgKGFwZW5hcyBzZSB2w6FsaWRvKQ0KICAgIGxuX3NhbGFyaW9faG9yYSA9IGlmX2Vsc2Uoc2FsYXJpb19ob3JhID4gMCwgbG9nKHNhbGFyaW9faG9yYSksIE5BX3JlYWxfKSwNCiAgICANCiAgICAjIFNleG8NCiAgICBzZXhvID0gZmFjdG9yKFYyMDA3LA0KICAgICAgbGV2ZWxzID0gYygxLCAyKSwNCiAgICAgIGxhYmVscyA9IGMoIkhvbWVtIiwgIk11bGhlciIpKSwNCiAgICANCiAgICAjIFJhw6dhDQogICAgcmFjYSA9IGZhY3RvcihWMjAxMCwNCiAgICAgIGxldmVscyA9IGMoMSwgMiwgMywgNCwgNSwgOSksDQogICAgICBsYWJlbHMgPSBjKCJCcmFuY2EiLCAiUHJldGEiLCAiQW1hcmVsYSIsICJQYXJkYSIsICJJbmTDrWdlbmEiLCAiSWdub3JhZG8iKSksDQogICAgDQogICAgIyBJZGFkZQ0KICAgIGlkYWRlID0gYXMubnVtZXJpYyhWMjAwOSksDQoNCiAgICAjIEFub3MgZGUgZXNjb2xhcmlkYWRlIChjb252ZXJ0ZXIgZGUgY2hhcmFjdGVyIHAvIG51bWVyaWMpDQogICAgYW5vc19lc2NvbGFyaWRhZGUgPSBhcy5udW1lcmljKFZEMzAwNSkpIHw+DQogIG11dGF0ZSgNCiAgICAjIElkYWRlIGNlbnRyYWxpemFkYSBwZWxhIG3DqWRpYQ0KICAgIGlkYWRlX2NlbnRyYWxpemFkYSA9IGlkYWRlIC0gbWVhbihpZGFkZSwgbmEucm0gPSBUUlVFKSwNCg0KICAgICMgRXhwZXJpw6puY2lhIHBvdGVuY2lhbA0KICAgIGV4cGVyaWVuY2lhID0gaWRhZGUgLSBhbm9zX2VzY29sYXJpZGFkZSAtIDUsDQogICAgDQogICAgIyBFeHBlcmnDqm5jaWEgY2VudHJhbGl6YWRhIHBlbGEgbcOpZGlhDQogICAgZXhwZXJpZW5jaWFfYyA9IGV4cGVyaWVuY2lhIC0gbWVhbihleHBlcmllbmNpYSwgbmEucm0gPSBUUlVFKSkNCmBgYA0KDQojIyMgUmVncmVzc8O1ZXMNCg0KQSBlcXVhw6fDo28gZGUgTWluY2VyIHBvZGUgc2VyIGV4cHJlc3NhIGNvbW86DQoNCiQkDQpcbG4od19pKSA9IFxiZXRhXzAgKyANClxiZXRhXzEgRXNjb2xhcmlkYWRlX2kgKyANClxiZXRhXzIgRXhwZXJpw6puY2lhX2kgKyANClxiZXRhXzMgRXhwZXJpw6puY2lhX2leMiArIA0KXHZhcmVwc2lsb25faQ0KJCQgTyBtb2RlbG8gZXN0aW1hZG8gw6kgZGFkbyBwb3I6DQoNCiQkDQpcYmVnaW57YWxpZ25lZH0NClxsbihcdGV4dHtTYWzDoXJpb0hvcmF9X2kpID1cICYgXGJldGFfMA0KKyBcYmV0YV8xIFx0ZXh0e0NhdGVnb3JpYSBkZSBFbXByZWdvfV9pDQorIFxiZXRhXzIgXG92ZXJsaW5le0V4cGVyacOqbmNpYX1faSBcXA0KJisgXGJldGFfMyBcb3ZlcmxpbmV7RXhwZXJpw6puY2lhfV9pXjINCisgXGJldGFfNCBcdGV4dHtSYcOnYX1faSBcXA0KJisgXGJldGFfNSBcdGV4dHtTZXhvfV9pDQorIFxiZXRhXzYgXHRleHR7U2V0b3JBdGl2aWRhZGV9X2kNCisgXHZhcmVwc2lsb25faQ0KXGVuZHthbGlnbmVkfQ0KJCQNCg0KRm9yYW0gcmVhbGl6YWRvcyBkb2lzIHRlc3RlczoNCg0KMSAtIE8gcHJpbWVpcm8gcXVlIHV0aWxpemEgaWRhZGVfY2VudHJhbGl6YWRhICsgaWRhZGVfY2VudHJhbGl6YWRhXF4yDQoyIC0gTyBzZWd1bmRvIHF1ZSB1dGlsaXphIG8gcHJveHkgKipleHBlcmllbmNpYV9jZW50cmFsaXphZGEqKg0KDQpFbSBhbWJvcyBvcyBtb2RlbG9zIG8gcG9kZXIgZXhwbGljYXRpdm8gZmljb3UgZW0gMjUlLiBBc3NpbSwgcGFyYSBtYW50ZXINCmZpZGVsaWRhZGUgY29tIG8gbW9kZWxvIGRlIE1pbmNlciBvcHRvdS1zZSBwb3Igc2VndWlyDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUiLCB3YXJuaW5nPUYsIG1lc3NhZ2U9Rn0NCiNOw6NvIHN1YnN0aXR1aXIgVUYgZSBWRDQwMTAgcGVsb3MgbGFiZWxzIHBvcnF1ZSBvIHRlbXBvIGRlIHByb2Nlc3NhbWVudG8gYXVtZW50YSBkZW1haXMNCmxpYnJhcnkoanRvb2xzKQ0KbW9kZWxvX21pbmNlciA8LSBzdW1tKA0KICBzdnlnbG0obG5fc2FsYXJpb19ob3JhIH4gY2F0ZWdvcmlhX2VtcHJlZ28gKyBhbm9zX2VzY29sYXJpZGFkZSArIGV4cGVyaWVuY2lhX2MgKyBJKGV4cGVyaWVuY2lhX2NeMikgKyByYWNhICsgc2V4byArIFZENDAxMCwNCiAgZGVzaWduID0gb2N1cGFkb3MzLA0KICBmYW1pbHkgPSBnYXVzc2lhbigpKSwNCiAgZGlnaXRzID0gMiwgY29uZmludCA9IEZBTFNFKQ0KDQpjb2VmcyA8LSBtb2RlbG9fbWluY2VyJGNvZWZ0YWJsZSB8PiANCiAgYXMuZGF0YS5mcmFtZSgpIHw+IA0KICByb3duYW1lc190b19jb2x1bW4oInRlcm0iKQ0KDQojIGZpbHRyYXIgcGFyYSBwIDw9IDAuMDUgZSBzZW0gbyBpbnRlcmNlcHRvDQpzaWdfY29lZnMgPC0gY29lZnMgfD4NCiAgZmlsdGVyKHAgPD0gMC4wNSwgdGVybSAhPSAiKEludGVyY2VwdCkiKSB8Pg0KICBwdWxsKHRlcm0pDQoNCnBsb3Rfc3VtbXMobW9kZWxvX21pbmNlciwgY29lZnMgPSBzaWdfY29lZnMpDQojUmVmZXLDqm5jaWFzDQojQ05QSg0KI0VzY29sYXJpZGFkZSAtIFNlbSBJbnN0cnXDp8Ojbw0KI1Jhw6dhIC0gQnJhbmNhDQojU2V4byAtIE1hc2N1bGlubw0KI1ZENDAxMCAxIC0gQWdyaWN1bHR1cmEsIHBlY3XDoXJpYSwgcHJvZHXDp8OjbyBmbG9yZXN0YWwsIHBlc2NhIGUgYXF1aWN1bHR1cmEgDQoNCiNQZXJjZW50dWFsDQoNCmxpYnJhcnkoYnJvb20pDQpyZXN1bHRhZG9zIDwtIGJyb29tOjp0aWR5KG1vZGVsb19taW5jZXIpIHw+DQogIG11dGF0ZShlZmVpdG9fcGN0ID0gKGV4cChlc3RpbWF0ZSkgLSAxKSAqIDEwMCwgICAjIHRyYW5zZm9ybWFyIGxvZyBlbSAlDQogICAgICAgICBzaWduaWYgPSBpZmVsc2UocC52YWx1ZSA8IDAuMDUsICJTaWduaWZpY2F0aXZvIiwgIk7Do28gc2lnbmlmaWNhdGl2byIpKQ0KDQojYXBlbmFzIHNpZ25pZmljYXRpdm9zDQpyZXN1bHRhZG9zX3NpZyA8LSByZXN1bHRhZG9zIHw+DQogIGZpbHRlcihzaWduaWYgPT0gIlNpZ25pZmljYXRpdm8iKSB8Pg0KICBzZWxlY3QodGVybSwgZXN0aW1hdGUsIGVmZWl0b19wY3QsIHN0ZC5lcnJvciwgc3RhdGlzdGljLCBwLnZhbHVlKQ0KDQojIHJlbm9tZWFyIGNvbHVuYXMNCnJlc3VsdGFkb3Nfc2lnIDwtIHJlc3VsdGFkb3Nfc2lnIHw+DQogIHJlbmFtZShWYXJpw6F2ZWwgPSB0ZXJtLA0KICAgICAgICAgQ29lZl9Mb2cgPSBlc3RpbWF0ZSwNCiAgICAgICAgIGBFZmVpdG8gKCUpYCA9IGVmZWl0b19wY3QsDQogICAgICAgICBgRXJybyBQYWRyw6NvYCA9IHN0ZC5lcnJvciwNCiAgICAgICAgIGB0IHZhbG9yYCA9IHN0YXRpc3RpYywNCiAgICAgICAgIGBwLXZhbG9yYCA9IHAudmFsdWUpDQoNCmxpYnJhcnkoa2FibGVFeHRyYSkNCg0KcmVzdWx0YWRvc19zaWcgfD4NCiAga2FibGUoZGlnaXRzID0gMiwgY2FwdGlvbiA9ICJFZmVpdG9zIHBlcmNlbnR1YWlzIHNpZ25pZmljYXRpdm9zIG5vIHNhbMOhcmlvLWhvcmEgKG1vZGVsbyBNaW5jZXIpIikgfD4NCiAga2FibGVfc3R5bGluZyhmdWxsX3dpZHRoID0gRkFMU0UsIHBvc2l0aW9uID0gImNlbnRlciIpDQoNCmBgYA0KDQpDb2xpbmVhcmlkYWRlDQoNCk11aXRhIGNvbGluZWFyaWRhZGUgcGFyYSBVRg0KDQpgYGB7cn0NCg0KIyB1c2Egb3MgZGFkb3MgcXVlIGVzdMOjbyBkZW50cm8gZG8gZGVzaWduIHN1cnZleQ0KZGF0YV9zdnkgPC0gb2N1cGFkb3MzJHZhcmlhYmxlcw0KDQojIG1vbnRhIGEgbWF0cml4IGRlIHJlZ3Jlc3NvcnMgY29tbyBvIG1vZGVsbyBxdWUgdm9jw6ogY2l0b3UNCm1tIDwtIG1vZGVsLm1hdHJpeCh+IGNhdGVnb3JpYV9lbXByZWdvICsgYW5vc19lc2NvbGFyaWRhZGUgKyBleHBlcmllbmNpYV9jICsgSShleHBlcmllbmNpYV9jXjIpICsgc2V4byArIHJhY2EgKyBWRDQwMTAsDQogICAgICAgICAgICAgICAgICAgZGF0YSA9IGRhdGFfc3Z5KQ0KDQojIHJlbW92ZSBhIGNvbHVuYSBkbyBpbnRlcmNlcHRvDQpwcmVkcyA8LSBhcy5kYXRhLmZyYW1lKG1tWywgLTEsIGRyb3AgPSBGQUxTRV0pDQoNCiMgb2J0w6ltIG9zIHBlc29zIGRlIGFtb3N0cmEgZG8gZGVzaWduICh0aXBvICJzYW1wbGluZyIpDQp3dCA8LSB3ZWlnaHRzKG9jdXBhZG9zMywgdHlwZSA9ICJzYW1wbGluZyIpDQoNCiMgZnVuw6fDo28gcGFyYSBSMiBwb25kZXJhZG8gKHVzYXJlbW9zIGVtIGxtIGNvbSB3ZWlnaHRzKQ0Kd2VpZ2h0ZWRfUjIgPC0gZnVuY3Rpb24oeSwgeWhhdCwgdykgew0KICAjIHNvbWEgZG9zIHF1YWRyYWRvcyBkb3MgcmVzw61kdW9zIHBvbmRlcmFkb3MNCiAgc3NlIDwtIHN1bSh3ICogKHkgLSB5aGF0KV4yLCBuYS5ybSA9IFRSVUUpDQogICMgc29tYSB0b3RhbCBwb25kZXJhZGENCiAgeWJhcl93IDwtIHN0YXRzOjp3ZWlnaHRlZC5tZWFuKHksIHcsIG5hLnJtID0gVFJVRSkNCiAgc3N0IDwtIHN1bSh3ICogKHkgLSB5YmFyX3cpXjIsIG5hLnJtID0gVFJVRSkNCiAgMSAtIHNzZSAvIHNzdA0KfQ0KDQojIGNhbGN1bGEgVklGIHBhcmEgY2FkYSBjb2x1bmEgZGEgbWF0cml4IGRlIHJlZ3Jlc3NvcnMNCnZpZl90YWJsZSA8LSBkYXRhLmZyYW1lKHZhcmlhYmxlID0gY2hhcmFjdGVyKCksIFIyID0gbnVtZXJpYygpLCBWSUYgPSBudW1lcmljKCksIHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkNCg0KZm9yIChqIGluIHNlcV9sZW4obmNvbChwcmVkcykpKSB7DQogIHkgPC0gcHJlZHNbW2pdXQ0KICBYb3RoZXIgPC0gcHJlZHNbLCAtaiwgZHJvcCA9IEZBTFNFXQ0KDQogICMgbW9udGEgZGF0YSBmcmFtZSB0ZW1wb3LDoXJpbw0KICBkZl90bXAgPC0gY2JpbmQoeSA9IHksIFhvdGhlcikNCg0KICAjIHJlZ3Jlc3PDo28gcG9uZGVyYWRhIGNvbSBsbSAocmVzcG9zdGEgeSBjb250cmEgb3MgZGVtYWlzKQ0KICBmaXQgPC0gbG0oeSB+IC4sIGRhdGEgPSBkZl90bXAsIHdlaWdodHMgPSB3dCkNCg0KICAjIHByZWRpeiBlIGNhbGN1bGEgUjIgcG9uZGVyYWRvDQogIHloYXQgPC0gcHJlZGljdChmaXQsIG5ld2RhdGEgPSBkZl90bXApDQogIFIydyA8LSB3ZWlnaHRlZF9SMih5LCB5aGF0LCB3dCkNCg0KICB2aWZfaiA8LSAxIC8gKDEgLSBSMncpDQogIHZpZl90YWJsZSA8LSByYmluZCh2aWZfdGFibGUsIGRhdGEuZnJhbWUodmFyaWFibGUgPSBjb2xuYW1lcyhwcmVkcylbal0sIFIyID0gUjJ3LCBWSUYgPSB2aWZfaikpDQp9DQoNCiMgb3JkZW5hIGUgbW9zdHJhDQp2aWZfdGFibGVbb3JkZXIoLXZpZl90YWJsZSRWSUYpLCBdDQoNCg0KYGBgDQoNCioqTyBtb2RlbG8gZXhwbGljYSBjZXJjYSBkZSAzMiUgZGEgZGlmZXJlbsOnYSBzYWxhcmlhbC4qKg0KDQpGb3JtYWlzIGdhbmhhbSwgZW0gbcOpZGlhLCBjZXJjYSBkZSAxOSUgbWVub3MgcXVlIG8gY29udGEtcHLDs3ByaWEgY29tDQpDTlBKLCBtYW50ZW5kbyBlc2NvbGFyaWRhZGUsIGlkYWRlLCByYcOnYSwgc2V4bywgZSBzZXRvciBlY29uw7RtaWNvIGZpeG9zLg0KDQpNYXMgcXVhbCB2YXJpw6F2ZWwgY29udGEgbWFpcz8NCg0KIyMgQ29tcGFyYXIgbW9kZWxvcw0KDQpUZXN0YW5kbyBmdW7Dp8OjbyBwYXJhIHZlciBvIGluY3JlbWVudG8NCg0KYGBge3J9DQoNCiMgRnVuw6fDo28gY29tcGFjdGEgcGFyYSBjYWxjdWxhciBwc2V1ZG8tUsKyIHBhcmEgc3Z5Z2xtIChHYXVzc2lhbikNCnBzZXVkb19yMiA8LSBmdW5jdGlvbihtb2RlbCkgew0KICB5IDwtIG1vZGVsJHkNCiAgeWhhdCA8LSBtb2RlbCRmaXR0ZWQudmFsdWVzDQogIHNzX3JlcyA8LSBzdW0oKHkgLSB5aGF0KV4yKQ0KICBzc190b3QgPC0gc3VtKCh5IC0gbWVhbih5KSleMikNCiAgMSAtIHNzX3JlcyAvIHNzX3RvdH0NCg0KIyBBanVzdGUgaW5jcmVtZW50YWwsIHJldXRpbGl6YW5kbyBvIG9iamV0byBkZSBkZXNpZ24gZSBsaW1wYW5kbyBleHBsaWNpdGFtZW50ZQ0KcjJzIDwtIG51bWVyaWMoMCkNCg0KZm9ybXVsYXMgPC0gbGlzdCgNCiAgbG5fc2FsYXJpb19ob3JhIH4gY2F0ZWdvcmlhX2VtcHJlZ28sDQogIGxuX3NhbGFyaW9faG9yYSB+IGNhdGVnb3JpYV9lbXByZWdvICsgc2V4bywNCiAgbG5fc2FsYXJpb19ob3JhIH4gY2F0ZWdvcmlhX2VtcHJlZ28gKyBzZXhvICsgcmFjYSwNCiAgbG5fc2FsYXJpb19ob3JhIH4gY2F0ZWdvcmlhX2VtcHJlZ28gKyBzZXhvICsgcmFjYSArIFZENDAxMCwNCiAgbG5fc2FsYXJpb19ob3JhIH4gY2F0ZWdvcmlhX2VtcHJlZ28gKyBzZXhvICsgcmFjYSArIFZENDAxMCArIGFub3NfZXNjb2xhcmlkYWRlLA0KICBsbl9zYWxhcmlvX2hvcmEgfiBjYXRlZ29yaWFfZW1wcmVnbyArIHNleG8gKyByYWNhICsgVkQ0MDEwICsgYW5vc19lc2NvbGFyaWRhZGUgKyBleHBlcmllbmNpYV9jLA0KICBsbl9zYWxhcmlvX2hvcmEgfiBjYXRlZ29yaWFfZW1wcmVnbyArIHNleG8gKyByYWNhICsgVkQ0MDEwICsgYW5vc19lc2NvbGFyaWRhZGUgKyBleHBlcmllbmNpYV9jICsgSShleHBlcmllbmNpYV9jXjIpDQopDQoNCmZvciAoZiBpbiBmb3JtdWxhcykgew0KICBtb2RlbG8gPC0gc3Z5Z2xtKGYsIGRlc2lnbiA9IG9jdXBhZG9zMywgZmFtaWx5ID0gZ2F1c3NpYW4oKSkNCiAgcjJzIDwtIGMocjJzLCBwc2V1ZG9fcjIobW9kZWxvKSkNCiAgcm0obW9kZWxvKSAjIHJlbW92ZSBvYmpldG8gZ3JhbmRlDQogIGdjKCkgIyBmb3LDp2EgbyBnYXJiYWdlIGNvbGxlY3RvciBhIGxpYmVyYXIgbWVtw7NyaWENCn0NCg0KbmFtZXMocjJzKSA8LSBjKCJjYXRlZ29yaWFfZW1wcmVnbyIsICIrc2V4byIsICIrcmHDp2EiLCAiK2dydXBvX2F0aXYiLCAiK2VzY29sYXJpZGFkZSIsICIrZXhwZXJpZW5jaWEiLCAiK2V4cGVyaWVuY2lhMiIpDQpwcmludChyMnMpDQpgYGANCg0KIyMjIENvbmNsdXPDtWVzIFBhcmNpYWlzDQoNCkFpbmRhIHF1ZSBleGlzdGEgdW1hIGRpZmVyZW7Dp2EgZW50cmUgYXMgY2F0ZWdvcmlhcyBkZSBlbXByZWdvIHBlcmNlYmUtc2UNCnF1ZSBvIGZhdG9yIHF1ZSBtYWlzIGluZmx1ZW5jaWEgbyBzYWzDoXJpby1ob3JhIMOpIGEgZXNjb2xhcmlkYWRlIGUgbw0KZ3J1cG8gZGUgYXRpdmlkYWRlLg0KDQpBIGNhdGVnb3JpYSBlbXByZWdvIHNvemluaGEgZXhwbGljYSBjZXJjYSBkZSAxJSBkYSB2YXJpYcOnw6NvIHNhbGFyaWFsLg0KDQojIyBQcm9wZW5zaXR5IFNjb3JlIE1hdGNoaW5nDQoNClByb3BlbnNpdHkgU2NvcmUgTWF0Y2hpbmcgY3JpYSB1bSBncnVwbyBkZSBjb250cm9sZSBhcnRpZmljaWFsIHBhcmENCmNvbXBhcmFyIGNvbSBvIGdydXBvIGRlIHRyYXRhbWVudG8sIGNvbSBvIG9iamV0aXZvIGRlIGVsaW1pbmFyIHZpZXNlcy4NCg0KQSBlc2NvbGhhIHBvciBlc3NlIHRlc3RlIHBlcm1pdGUgcmVzcG9uZGVyIMOgIHBlcmd1bnRhOg0KDQrigJxEYWRvcyBkb2lzIHRyYWJhbGhhZG9yZXMgY29tIHBlcmZpcyBzZW1lbGhhbnRlcyAobWVzbWEgZXNjb2xhcmlkYWRlLA0KZXhwZXJpw6puY2lhLCBzZXhvIGUgcmHDp2EpLCBjb21vIGZpY2EgYSBkaWZlcmVuw6dhIHNhbMOhcmlvLWhvcmEgZW50cmUNCmFxdWVsZSBmb3JtYWxpemFkbyBlIGNvbnRhLXByw7NwcmlhIGNvbSBDTlBKP+KAnQ0KDQpgYGB7ciwgd2FybmluZz1GLCBtZXNzYWdlID0gRn0NCmxpYnJhcnkoTWF0Y2hJdCkNCg0KIyBWYXJpw6F2ZWwgZGUgdHJhdGFtZW50bw0Kb2N1cGFkb3NfcHNtIDwtIG9jdXBhZG9zMyR2YXJpYWJsZXMgfD4NCiAgZmlsdGVyKGNhdGVnb3JpYV9lbXByZWdvICVpbiUgYygiZm9ybWFsIiwgImNucGoiKSkgfD4NCiAgbXV0YXRlKGZvcm1hbCA9IGlmX2Vsc2UoY2F0ZWdvcmlhX2VtcHJlZ28gPT0gImZvcm1hbCIsIDEsIDApLA0KICAgICAgICAgZm9ybWFsID0gZmFjdG9yKGZvcm1hbCwgbGV2ZWxzID0gYygwLCAxKSwgbGFiZWxzID0gYygiQ29udGEgcHLDs3ByaWEiLCAiRm9ybWFsIikpKQ0KDQpvY3VwYWRvc19wc20gPC0gYXMuZGF0YS5mcmFtZShvY3VwYWRvc19wc20pDQoNCiMgTWF0Y2hpbmcgY29tIGxvZ2l0IA0KIyBGb2kgcmV0aXJhZG8gVkQ0MDEwIHBvaXMgZGVtb3JhdmEgY2VyY2EgZGUgNDAgbWludXRvcy4NCnN5c3RlbS50aW1lKHsNCnBzbV9tb2RlbCA8LSBtYXRjaGl0KGZvcm1hbCB+IHNleG8gKyByYWNhICsgYW5vc19lc2NvbGFyaWRhZGUgKyBleHBlcmllbmNpYV9jICsgSShleHBlcmllbmNpYV9jXjIpLA0KICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IG9jdXBhZG9zX3BzbSwNCiAgICAgICAgICAgICAgICAgICAgIG1ldGhvZCA9ICJuZWFyZXN0IiwNCiAgICAgICAgICAgICAgICAgICAgIGRpc3RhbmNlID0gImxvZ2l0IikNCn0pDQoNCm1hdGNoZWRfZGF0YSA8LSBtYXRjaC5kYXRhKHBzbV9tb2RlbCkNCg0KbGlicmFyeShjb2JhbHQpDQpsb3ZlLnBsb3QocHNtX21vZGVsLCBiaW5hcnkgPSAic3RkIikgICMgZ3LDoWZpY28gZGUgZGlmZXJlbsOnYXMgcGFkcm9uaXphZGFzDQoNCmBgYA0KDQojIyMgVGVzdGUgdA0KDQpgYGB7cn0NCnRfdGVzdCA8LSB0LnRlc3Qoc2FsYXJpb19ob3JhIH4gZm9ybWFsLCBkYXRhID0gbWF0Y2hlZF9kYXRhLCB3ZWlnaHRzID0gd2VpZ2h0cykNCnRfdGVzdA0KDQojIFZpc3VhbGl6YXIgYmFsYW5jZWFtZW50byAoc3RhbmRhcmRpemVkIG1lYW4gZGlmZmVyZW5jZXMpDQojcGxvdChwc21fbW9kZWwsIHR5cGUgPSAiaml0dGVyIiwgaW50ZXJhY3RpdmUgPSBGQUxTRSkNCiNwbG90KHBzbV9tb2RlbCwgdHlwZSA9ICJxcSIpDQojcGxvdChwc21fbW9kZWwsIHR5cGUgPSAiaGlzdCIpDQoNCm1hdGNoZWRfZGF0YSRmaW5hbF93ZWlnaHRzIDwtIG1hdGNoZWRfZGF0YSR3ZWlnaHRzICogbWF0Y2hlZF9kYXRhJFYxMDI4DQoNCm9wdGlvbnMoc3VydmV5LmxvbmVseS5wc3UgPSAiYWRqdXN0IikNCg0KZGVzaWduX3BzbSA8LSBzdnlkZXNpZ24oDQogIGlkcyA9IH4xLCAgIyBpZ25vcmEgY2x1c3Rlcg0KICB3ZWlnaHRzID0gfmZpbmFsX3dlaWdodHMsDQogIGRhdGEgPSBtYXRjaGVkX2RhdGENCikNCg0KIyBUZXN0ZSB0IHBvbmRlcmFkbw0Kc3Z5X3Rlc3QgPC0gc3Z5dHRlc3Qoc2FsYXJpb19ob3JhIH4gZm9ybWFsLCBkZXNpZ24gPSBkZXNpZ25fcHNtKQ0Kc3Z5X3Rlc3QNCg0KYGBgDQoNCk8gdGVzdCB0IGluZGljYSBSXCQgMjAsNTEgcGFyYSBjb250YSBwcsOzcHJpYSBlIFJcJCA5LDQ0IHBhcmEgbw0KZm9ybWFsaXphZG8gKGNlcmNhIGRlIFJcJCAxMSwwNyBhIG1lbm9zKSBPIHRlc3QgdCBwYXJhIG9iamV0byBkbyB0aXBvDQpzdXJ2ZXkgaW5kaWNhIHVtYSBkaWZlcmVuw6dhIGRlIGNlcmNhIGRlIC1SXCQgMTEsMzUgcGFyYSBvIGZvcm1hbGl6YWRvDQoNCiMjIFF1YW50w61saWNhIGNvbSBQU00NCg0KQ29tbyBqw6EgZm9pIHBvc3PDrXZlbCB2aXN1YWxpemFyLCBlc3BlY2lhbG1lbnRlIG5hIHBhcnRlIGRlIGFuw6FsaXNlDQpkZXNjcml0aXZhLCBhcyB2YXJpw6F2ZWlzIHF1ZSBlbnZvbHZlbSBzYWzDoXJpb3MgdGVtIGJveHBsb3RzIGNvbSBvDQp0ZXJjZWlybyBxdWFydGlsIG1haXMgYWxvbmdhZG8gZSBvIHF1YXJ0byBxdWFydGlsIGNvbSBtdWl0b3Mgb3V0bGllcnMuDQoNCkFzc2ltLCBhIHBlcmd1bnRhIHNlZ3VpbnRlIMOpOg0KDQoqKkEgZGlmZXJlbsOnYSBzYWzDoXJpby1ob3JhIGVudHJlIGZvcm1haXMgZSBQSnMgc2UgbWFudMOqbSBlbnRyZSB0b2RvcyBvcw0KbsOtdmVpcyBzYWxhcmlhaXM/KioNCg0KUGFyYSByZXNwb25kZXIgZXNzYSBwZXJndW50YSBzZXLDoSBmZWl0YSB1bWEgYW7DoWxpc2UgcXVhbnTDrWxpY2EuIE91IHNlamEsDQpvIHNhbMOhcmlvLWhvcmEgc2Vyw6EgZGl2aWRpZG8gZW0gZGV6IHBhcnRlcyBlIHNlcsOhIG9ic2VydmFkbyBvDQpjb21wb3J0YW1lbnRvIGRpZmVyZW5jaWFsIGVudHJlIGNhZGEgZGVjaWwuDQoNCmBgYHtyLCB3YXJuaW5nPUYsIG1lc3NhZ2U9Rn0NCg0KbGlicmFyeShxdWFudHJlZykNCg0KdGF1cyA8LSBzZXEoMC4wLCAxLjAsIGJ5ID0gMC4xKQ0KcnFfbW9kZWxfYWxsIDwtIHJxKHNhbGFyaW9faG9yYSB+IGZvcm1hbCwgDQogICAgICAgICAgICAgICAgICAgZGF0YSA9IG1hdGNoZWRfZGF0YSwgDQogICAgICAgICAgICAgICAgICAgdGF1ID0gdGF1cywgDQogICAgICAgICAgICAgICAgICAgd2VpZ2h0cyA9IHdlaWdodHMpDQoNCnN5c3RlbS50aW1lKHsNCnJxX3N1bW1hcnkgPC0gc3VtbWFyeShycV9tb2RlbF9hbGwsIHNlID0gImJvb3QiLCBSID0gNTApDQp9KQ0KYGBgDQoNCiMjIyBSZXN1bHRhZG9zDQoNCmBgYHtyLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD02LCB3YXJuaW5nPUZ9DQojU3lzLnNldGxvY2FsZSgiTENfQUxMIiwgInB0X0JSLlVURi04IikNCg0KcmVzdWx0cyA8LSBkby5jYWxsKHJiaW5kLCBsYXBwbHkocnFfc3VtbWFyeSwgZnVuY3Rpb24ocykgew0KICBkYXRhLmZyYW1lKA0KICAgIHRhdSA9IHMkdGF1LA0KICAgIGNvZWYgPSBzJGNvZWZmaWNpZW50c1siZm9ybWFsRm9ybWFsIiwgMV0sDQogICAgc2UgICA9IHMkY29lZmZpY2llbnRzWyJmb3JtYWxGb3JtYWwiLCAyXQ0KICApfSkpDQoNCiNlcnJvcy1wYWRyw6NvDQpyZXN1bHRzIDwtIHJlc3VsdHMgfD4NCiAgbXV0YXRlKGxvd2VyID0gY29lZiAtIDEuOTYgKiBzZSwNCiAgICAgICAgIHVwcGVyID0gY29lZiArIDEuOTYgKiBzZSwNCiAgICAgICAgIHR5cGUgPSAiUXVhbnTDrWxpY28iKQ0KDQojcmVzdWx0YWRvcyBkb3MgZG9pcyB0ZXN0cyB0IC0gYWRpY2lvbmFkb3MNCm1lYW5fZWZmZWN0cyA8LSBkYXRhLmZyYW1lKA0KICB0YXUgPSBjKDAuNSwgMC41KSwNCiAgY29lZiA9IGModF90ZXN0JGVzdGltYXRlWzJdIC0gdF90ZXN0JGVzdGltYXRlWzFdLCBzdnlfdGVzdCRlc3RpbWF0ZSksICAgICAjIEZvcm1hbCAtIENvbnRhIHByw7NwcmlhDQogIGxvd2VyID0gYygtdF90ZXN0JGNvbmYuaW50WzJdLCBzdnlfdGVzdCRjb25mLmludFsxXSksICAgICAgICAgICAgICAgICAgICAgIyBJbnZlcnRhIHVwcGVyICh2YWkgcGFyYSBsb3dlcikNCiAgdXBwZXIgPSBjKC10X3Rlc3QkY29uZi5pbnRbMV0sIHN2eV90ZXN0JGNvbmYuaW50WzJdKSwgICAgICAgICAgICAgICAgICAgICAjIEludmVydGEgbG93ZXIgKHZhaSBwYXJhIHVwcGVyKQ0KICB0eXBlID0gYygiVC10ZXN0IiwgIlN2eSBULXRlc3QiKSkNCg0KcGxvdF9kYXRhIDwtIGJpbmRfcm93cyhyZXN1bHRzLCBtZWFuX2VmZmVjdHMpDQoNCmcxIDwtIGdncGxvdCgpICsNCiAgIyBlZmVpdG9zIHF1YW50w61saWNvcw0KICBnZW9tX2xpbmUoZGF0YSA9IHJlc3VsdHMsIGFlcyh4ID0gdGF1LCB5ID0gY29lZiwgY29sb3IgPSB0eXBlKSwgc2l6ZSA9IDEpICsNCiAgZ2VvbV9wb2ludChkYXRhID0gcmVzdWx0cywgYWVzKHggPSB0YXUsIHkgPSBjb2VmLCBjb2xvciA9IHR5cGUpLCBzaXplID0gMikgKw0KICBnZW9tX3JpYmJvbihkYXRhID0gcmVzdWx0cywgYWVzKHggPSB0YXUsIHltaW4gPSBsb3dlciwgeW1heCA9IHVwcGVyLCBmaWxsID0gdHlwZSksIGFscGhhID0gMC4xNSkgKw0KDQogICMgcsOzdHVsb3Mgbm9zIGVmZWl0b3MgcXVhbnTDrWxpY29zDQogIGdlb21fdGV4dChkYXRhID0gcmVzdWx0cywgDQogICAgICAgICAgICBhZXMoeCA9IHRhdSwgeSA9IGNvZWYsIGxhYmVsID0gcm91bmQoY29lZiwgMSksIGNvbG9yID0gdHlwZSksIA0KICAgICAgICAgICAgdmp1c3QgPSAtMSwgc2l6ZSA9IDMuNSwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKw0KDQogICMgbcOpZGlhcyBkZXN0YWNhZGFzDQogIGdlb21fcG9pbnQoZGF0YSA9IG1lYW5fZWZmZWN0cywgYWVzKHggPSB0YXUsIHkgPSBjb2VmLCBzaGFwZSA9IHR5cGUsIGNvbG9yID0gdHlwZSksIHNpemUgPSA0KSArDQogIGdlb21fZXJyb3JiYXIoZGF0YSA9IG1lYW5fZWZmZWN0cywgYWVzKHggPSB0YXUsIHltaW4gPSBsb3dlciwgeW1heCA9IHVwcGVyLCBjb2xvciA9IHR5cGUpLCANCiAgICAgICAgICAgICAgICB3aWR0aCA9IDAuMDUsIHNpemUgPSAxKSArDQoNCiAgIyByw7N0dWxvcyBuYXMgbcOpZGlhcw0KICBnZW9tX3RleHQoZGF0YSA9IG1lYW5fZWZmZWN0cywgDQogICAgICAgICAgICBhZXMoeCA9IHRhdSwgeSA9IGNvZWYsIGxhYmVsID0gcm91bmQoY29lZiwgMSksIGNvbG9yID0gdHlwZSksIA0KICAgICAgICAgICAgdmp1c3QgPSAtMS4yLCBzaXplID0gNCwgZm9udGZhY2UgPSAiYm9sZCIsIHNob3cubGVnZW5kID0gRkFMU0UpICsNCg0KICAjIGxpbmhhIGRlIHJlZmVyw6puY2lhDQogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG9yID0gInJlZCIpICsNCg0KICAjIGVpeG8gZGUgMCUgYSAxMDAlDQogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoMCwgMSwgMC4xKSwgICMgZGVjaWwgYSBkZWNpbA0KICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gc2NhbGVzOjpwZXJjZW50KSArDQoNCiAgbGFicyh4ID0gIlF1YW50aWwgZGEgZGlzdHJpYnVpw6fDo28gc2FsYXJpYWwiLA0KICAgICAgIHkgPSAiRGlmZXJlbsOnYSAoRm9ybWFsIC0gQ29udGEgcHLDs3ByaWEpIiwNCiAgICAgICB0aXRsZSA9ICJEaWZlcmVuw6dhIFNhbMOhcmlvLUhvcmEgKEZvcm1hbCB2cyBQSikgcG9yIERlY2lsIC0gVXNhbmRvIFBTTSBcbiBFZmVpdG9zIG3DqWRpb3MgKHQtdGVzdCAvIHN1cnZleSB0LXRlc3QpIHZzIHF1YW50w61saWNvcyIpICsNCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxNCkNCg0KZzENCmBgYA0KDQojIyMgQ29tcG9zacOnw6NvIGRvcyBRdWFudGlzDQoNCmBgYHtyLCB3YXJuaW5nPUYsIG1lc3NhZ2U9RiwgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9Nn0NCg0KbGlicmFyeShIbWlzYykNCg0KIyBDYWxjdWxhciBvcyBjb3J0ZXMgZGUgc2Fsw6FyaW8taG9yYSBwb25kZXJhZG9zDQpxdWFudGlsZV9jdXRzIDwtIEhtaXNjOjp3dGQucXVhbnRpbGUobWF0Y2hlZF9kYXRhJHNhbGFyaW9faG9yYSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3ZWlnaHRzID0gbWF0Y2hlZF9kYXRhJGZpbmFsX3dlaWdodHMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvYnMgPSB0YXVzKQ0KDQpxdWFudGlsZV9jdXRzDQoNCiMgQ2xhc3NpZmljYXIgY2FkYSBpbmRpdsOtZHVvIG5vIHNldSBpbnRlcnZhbG8gZGUgcXVhbnRpbA0KbWF0Y2hlZF9kYXRhIDwtIG1hdGNoZWRfZGF0YSB8Pg0KICBtdXRhdGUocXVhbnRpbCA9IGN1dChzYWxhcmlvX2hvcmEsDQogICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHF1YW50aWxlX2N1dHMsDQogICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIjAtMTAlIiwgIjEwLTIwJSIsICIyMC0zMCUiLCAiMzAtNDAlIiwgIjQwLTUwJSIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICI1MC02MCUiLCAiNjAtNzAlIiwgIjcwLTgwJSIsICI4MC05MCUiLCAiOTAtMTAwJSIpLA0KICAgICAgICAgICAgICAgICAgICAgICByaWdodCA9IFRSVUUsDQogICAgICAgICAgICAgICAgICAgICAgIGluY2x1ZGUubG93ZXN0ID0gVFJVRSkpDQoNCmRpc3RfcXVhbnRpcyA8LSBtYXRjaGVkX2RhdGEgfD4NCiAgZ3JvdXBfYnkocXVhbnRpbCwgZm9ybWFsKSB8Pg0KICBzdW1tYXJpc2Uobl9wb25kZXJhZG8gPSBzdW0oZmluYWxfd2VpZ2h0cywgbmEucm0gPSBUUlVFKSwgLmdyb3VwcyA9ICJkcm9wIikgfD4NCiAgZmlsdGVyKCFpcy5uYShxdWFudGlsKSkgfD4NCiAgbXV0YXRlKHByb3BfdG90YWwgPSBuX3BvbmRlcmFkbyAvIHN1bShuX3BvbmRlcmFkbykpDQoNCmcyIDwtIGdncGxvdChkaXN0X3F1YW50aXMsIGFlcyh4ID0gcXVhbnRpbCwgeSA9IHByb3BfdG90YWwsIGZpbGwgPSBmb3JtYWwpKSArDQogIGdlb21fY29sKHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjgpLCB3aWR0aCA9IDAuNykgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gc2NhbGVzOjpwZXJjZW50KHByb3BfdG90YWwsIGFjY3VyYWN5ID0gMC4xKSksDQogICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC44KSwNCiAgICAgICAgICAgIHZqdXN0ID0gLTAuMywgc2l6ZSA9IDMuNSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50X2Zvcm1hdChhY2N1cmFjeSA9IDEpKSArDQogIGxhYnModGl0bGUgPSAiUHJvcG9yw6fDo28gZGUgRm9ybWFsIHZzIENvbnRhIFByw7NwcmlhIFxuIHBvciBRdWFudGlsIChjb20gUFNNKSIsDQogICAgICAgeCA9ICJRdWFudGlzIGRvIHNhbMOhcmlvLWhvcmEiLCB5ID0gIlByb3BvcsOnw6NvIGRvIHRvdGFsIGdlcmFsIiwNCiAgICAgICBmaWxsID0gIkNhdGVnb3JpYSBkZSBlbXByZWdvIikgKw0KICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDE0KQ0KDQpnMg0KYGBgDQoNCiMjIyBNw6lkaWEgc2FsYXJpYWwNCg0KYGBge3IsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD02fQ0KDQptZWRpYXNfZGVjaXMgPC0gbWF0Y2hlZF9kYXRhIHw+DQogIGdyb3VwX2J5KHF1YW50aWwsIGZvcm1hbCkgfD4NCiAgc3VtbWFyaXNlKG1lZGlhX3NhbGFyaW8gPSB3ZWlnaHRlZC5tZWFuKHNhbGFyaW9faG9yYSwgdyA9IGZpbmFsX3dlaWdodHMsIG5hLnJtID0gVFJVRSksDQogICAgICAgICAgICAuZ3JvdXBzID0gImRyb3AiKQ0KDQojIHNlIG9zIHF1YW50aXMgZXN0w6NvIGNvbW8gZmF0b3IsIGNvbnZlcnRlciBwYXJhIG51bcOpcmljbyBwYXJhIGFsaW5oYXIgbm8gZWl4bw0KbWVkaWFzX2RlY2lzIDwtIG1lZGlhc19kZWNpcyB8Pg0KICBtdXRhdGUocXVhbnRpbF9udW0gPSBhcy5udW1lcmljKGdzdWIoIiglfFxcLSkuKiIsICIiLCBxdWFudGlsKSkgLyAxMDApICNwb250byBtw6lkaW8NCg0KbWVkaWFzX2RlY2lzIDwtIG1lZGlhc19kZWNpcyB8PiBmaWx0ZXIoIWlzLm5hKHF1YW50aWwpKQ0KDQpnMyA8LSBnZ3Bsb3QobWVkaWFzX2RlY2lzLCBhZXMoeCA9IHF1YW50aWwsIHkgPSBtZWRpYV9zYWxhcmlvLCBmaWxsID0gZm9ybWFsKSkgKw0KICBnZW9tX2NvbChwb3NpdGlvbiA9ICJkb2RnZSIsIGFscGhhID0gMC44KSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSByb3VuZChtZWRpYV9zYWxhcmlvLCAxKSksDQogICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC45KSwNCiAgICAgICAgICAgIHZqdXN0ID0gLTAuMSwgc2l6ZSA9IDMuNSkgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIlNhbMOhcmlvLUhvcmEgTcOpZGlvIHBvciBEZWNpbCBkYSBEaXN0cmlidWnDp8OjbyIsDQogICAgc3VidGl0bGUgPSAiQ29tcGFyYcOnw6NvIGVudHJlIHRyYWJhbGhhZG9yZXMgZm9ybWFpcyBlIGNvbnRhIHByw7NwcmlhIFxuIGNvbSBQU00iLA0KICAgIHggPSAiUXVhbnRpbCBkYSBkaXN0cmlidWnDp8OjbyBzYWxhcmlhbCIsDQogICAgeSA9ICJTYWzDoXJpby1ob3JhIG3DqWRpbyAoUiQpIiwNCiAgICBmaWxsID0gIkNhdGVnb3JpYSIpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6ZG9sbGFyX2Zvcm1hdChwcmVmaXggPSAiUiQgIiwgYmlnLm1hcmsgPSAiLiIsIGRlY2ltYWwubWFyayA9ICIsIikpICsNCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxNCkNCg0KZzMNCmBgYA0KDQojIyBRdWFudMOtbGljYSBzZW0gUFNNDQoNCiMjIyBSZXN1bHRhZG9zDQoNCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9MTJ9DQoNCnRfdGVzdCA8LSB0LnRlc3Qoc2FsYXJpb19ob3JhIH4gZm9ybWFsLCBkYXRhID0gb2N1cGFkb3NfcHNtLCB3ZWlnaHRzID0gVjEwMjgpDQp0X3Rlc3QNCg0KcnFfbW9kZWxfYWxsX1NFTVBTTSA8LSBycShzYWxhcmlvX2hvcmEgfiBmb3JtYWwsIA0KICAgICAgICAgICAgICAgICAgIGRhdGEgPSBvY3VwYWRvc19wc20sIA0KICAgICAgICAgICAgICAgICAgIHRhdSA9IHRhdXMsIA0KICAgICAgICAgICAgICAgICAgIHdlaWdodHMgPSBWMTAyOCkNCg0KI2Jvb3QgY29tIFIgPSA1MCBwYXJhIGRpbWludWlyIG8gdGVtcG8gZGUgcHJvY2Vzc2FtZW50by4gRGltaW51aXUgZGUgMWgyMCBwYXJhIDMwbQ0Kc3lzdGVtLnRpbWUoew0KcnFfc3VtbWFyeV9TRU1QU00gPC0gc3VtbWFyeShycV9tb2RlbF9hbGxfU0VNUFNNLCBzZSA9ICJib290IiwgUj01MCkNCn0pDQoNCnJlc3VsdHNfU0VNUFNNIDwtIGRvLmNhbGwocmJpbmQsIGxhcHBseShycV9zdW1tYXJ5X1NFTVBTTSwgZnVuY3Rpb24ocykgew0KICBkYXRhLmZyYW1lKA0KICAgIHRhdSA9IHMkdGF1LA0KICAgIGNvZWYgPSBzJGNvZWZmaWNpZW50c1siZm9ybWFsRm9ybWFsIiwgMV0sDQogICAgc2UgICA9IHMkY29lZmZpY2llbnRzWyJmb3JtYWxGb3JtYWwiLCAyXSl9KSkNCg0KcmVzdWx0c19TRU1QU00gPC0gcmVzdWx0c19TRU1QU00gfD4NCiAgbXV0YXRlKGxvd2VyID0gY29lZiAtIDEuOTYgKiBzZSwNCiAgICAgICAgIHVwcGVyID0gY29lZiArIDEuOTYgKiBzZSwNCiAgICAgICAgIHR5cGUgPSAiUXVhbnTDrWxpY28iKQ0KDQpnNCA8LSBnZ3Bsb3QoKSArDQogICMgZWZlaXRvcyBxdWFudMOtbGljb3MNCiAgZ2VvbV9saW5lKGRhdGEgPSByZXN1bHRzX1NFTVBTTSwgYWVzKHggPSB0YXUsIHkgPSBjb2VmLCBjb2xvciA9IHR5cGUpLCBzaXplID0gMSkgKw0KICBnZW9tX3BvaW50KGRhdGEgPSByZXN1bHRzX1NFTVBTTSwgYWVzKHggPSB0YXUsIHkgPSBjb2VmLCBjb2xvciA9IHR5cGUpLCBzaXplID0gMikgKw0KICBnZW9tX3JpYmJvbihkYXRhID0gcmVzdWx0c19TRU1QU00sIGFlcyh4ID0gdGF1LCB5bWluID0gbG93ZXIsIHltYXggPSB1cHBlciwgZmlsbCA9IHR5cGUpLCANCiAgICAgICAgICAgICAgYWxwaGEgPSAwLjE1KSArDQoNCiAgIyByw7N0dWxvcyBub3MgZWZlaXRvcyBxdWFudMOtbGljb3MNCiAgZ2VvbV90ZXh0KGRhdGEgPSByZXN1bHRzX1NFTVBTTSwgDQogICAgICAgICAgICBhZXMoeCA9IHRhdSwgeSA9IGNvZWYsIGxhYmVsID0gcm91bmQoY29lZiwgMSksIGNvbG9yID0gdHlwZSksIA0KICAgICAgICAgICAgdmp1c3QgPSAtMC4zLCBzaXplID0gMy41LCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArDQoNCiAgIyBsaW5oYSBkZSByZWZlcsOqbmNpYQ0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvciA9ICJyZWQiKSArDQoNCiAgIyBlaXhvIGRlIDAlIGEgMTAwJQ0KICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDEsIDAuMSksICAjIGRlY2lsIGEgZGVjaWwNCiAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IHNjYWxlczo6cGVyY2VudCkgKw0KICANCiAgbGFicyh4ID0gIlF1YW50aWwgZGEgZGlzdHJpYnVpw6fDo28gc2FsYXJpYWwiLA0KICAgICAgIHkgPSAiRGlmZXJlbsOnYSAoRm9ybWFsIC0gQ29udGEgcHLDs3ByaWEpIiwNCiAgICAgICB0aXRsZSA9ICJEaWZlcmVuw6dhIFNhbMOhcmlvLUhvcmEgKEZvcm1hbCB2cyBQSikgcG9yIERlY2lsIC0gU2VtIFBTTSIpICsNCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxNCkNCg0KbGlicmFyeShwYXRjaHdvcmspDQpnMSAvIGc0DQpgYGANCg0KIyMjIENvbXBvc2nDp8OjbyBkb3MgUXVhbnRpcw0KDQpgYGB7ciwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTEyfQ0KcXVhbnRpbGVfY3V0c19wdXJvIDwtIEhtaXNjOjp3dGQucXVhbnRpbGUob2N1cGFkb3NfcHNtJHNhbGFyaW9faG9yYSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdlaWdodHMgPSBvY3VwYWRvc19wc20kVjEwMjgsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9icyA9IHRhdXMpDQoNCm9jdXBhZG9zX3BzbSA8LSBvY3VwYWRvc19wc20gfD4NCiAgbXV0YXRlKHF1YW50aWwgPSBjdXQoc2FsYXJpb19ob3JhLA0KICAgICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBxdWFudGlsZV9jdXRzX3B1cm8sDQogICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIjAtMTAlIiwgIjEwLTIwJSIsICIyMC0zMCUiLCAiMzAtNDAlIiwgIjQwLTUwJSIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICI1MC02MCUiLCAiNjAtNzAlIiwgIjcwLTgwJSIsICI4MC05MCUiLCAiOTAtMTAwJSIpLA0KICAgICAgICAgICAgICAgICAgICAgICBpbmNsdWRlLmxvd2VzdCA9IFRSVUUpKQ0KDQpkaXN0X3F1YW50aXNfcHVybyA8LSBvY3VwYWRvc19wc20gfD4NCiAgZ3JvdXBfYnkocXVhbnRpbCwgZm9ybWFsKSB8Pg0KICBzdW1tYXJpc2Uobl9wb25kZXJhZG8gPSBzdW0oVjEwMjgsIG5hLnJtID0gVFJVRSksIC5ncm91cHMgPSAiZHJvcCIpIHw+DQogIGZpbHRlcighaXMubmEocXVhbnRpbCkpIHw+DQogIG11dGF0ZShwcm9wX3RvdGFsID0gbl9wb25kZXJhZG8gLyBzdW0obl9wb25kZXJhZG8pKQ0KDQpnNSA8LSBnZ3Bsb3QoZGlzdF9xdWFudGlzX3B1cm8sIGFlcyh4ID0gcXVhbnRpbCwgeSA9IHByb3BfdG90YWwsIGZpbGwgPSBmb3JtYWwpKSArDQogIGdlb21fY29sKHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjgpLCB3aWR0aCA9IDAuNykgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gc2NhbGVzOjpwZXJjZW50KHByb3BfdG90YWwsIGFjY3VyYWN5ID0gMC4xKSksDQogICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC44KSwNCiAgICAgICAgICAgIHZqdXN0ID0gLTAuMywgc2l6ZSA9IDMuNSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50X2Zvcm1hdChhY2N1cmFjeSA9IDEpKSArDQogIGxhYnModGl0bGUgPSAiUHJvcG9yw6fDo28gZGUgRm9ybWFsIHZzIENvbnRhIFByw7NwcmlhIFxuIHBvciBRdWFudGlsIChzZW0gUFNNKSIsDQogICAgICAgeCA9ICJRdWFudGlzIGRvIHNhbMOhcmlvLWhvcmEiLCB5ID0gIlByb3BvcsOnw6NvIGRvIHRvdGFsIGdlcmFsIiwNCiAgICAgICBmaWxsID0gIkNhdGVnb3JpYSBkZSBlbXByZWdvIikgKw0KICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDE0KQ0KDQoNCiMjIENvbXBhcmHDp8OjbyBsYWRvIGEgbGFkbw0KZzIgLyBnNQ0KDQp0YWJsZShtYXRjaGVkX2RhdGEkZm9ybWFsKQ0KdGFibGUob2N1cGFkb3NfcHNtJGZvcm1hbCkNCg0KcHJvcC50YWJsZSh0YWJsZShtYXRjaGVkX2RhdGEkZm9ybWFsKSkNCnByb3AudGFibGUodGFibGUob2N1cGFkb3NfcHNtJGZvcm1hbCkpDQpgYGANCg0KIyMjIE3DqWRpYSBTYWxhcmlhbA0KDQpgYGB7ciwgZmlnLndpZHRoPTEyLCBmaWcuaGVpZ2h0PTEyfQ0KDQptZWRpYXNfc2VtcHNtIDwtIG9jdXBhZG9zX3BzbSB8Pg0KICBncm91cF9ieShxdWFudGlsLCBmb3JtYWwpIHw+DQogIHN1bW1hcmlzZShtZWRpYV9zYWxhcmlvID0gd2VpZ2h0ZWQubWVhbihzYWxhcmlvX2hvcmEsIHcgPSBWMTAyOCwgbmEucm0gPSBUUlVFKSwNCiAgICAgICAgICAgIC5ncm91cHMgPSAiZHJvcCIpIHw+DQogIGZpbHRlcighaXMubmEocXVhbnRpbCkpIHw+DQogIG11dGF0ZSh0aXBvID0gIlNlbSBQU00iKQ0KDQoNCmc2IDwtIGdncGxvdChtZWRpYXNfc2VtcHNtLCBhZXMoeCA9IHF1YW50aWwsIHkgPSBtZWRpYV9zYWxhcmlvLCBmaWxsID0gZm9ybWFsKSkgKw0KICBnZW9tX2NvbChwb3NpdGlvbiA9ICJkb2RnZSIsIGFscGhhID0gMC44KSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSByb3VuZChtZWRpYV9zYWxhcmlvLCAxKSksDQogICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC45KSwNCiAgICAgICAgICAgIHZqdXN0ID0gLTAuMSwgc2l6ZSA9IDMuNSkgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIlNhbMOhcmlvLUhvcmEgTcOpZGlvIHBvciBEZWNpbCBkYSBEaXN0cmlidWnDp8OjbyIsDQogICAgc3VidGl0bGUgPSAiQ29tcGFyYcOnw6NvIGVudHJlIHRyYWJhbGhhZG9yZXMgZm9ybWFpcyBlIGNvbnRhIHByw7NwcmlhIFxuIHNlbSBQU00iLA0KICAgIHggPSAiUXVhbnRpbCBkYSBkaXN0cmlidWnDp8OjbyBzYWxhcmlhbCIsDQogICAgeSA9ICJTYWzDoXJpby1ob3JhIG3DqWRpbyAoUiQpIiwNCiAgICBmaWxsID0gIkNhdGVnb3JpYSIpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6ZG9sbGFyX2Zvcm1hdChwcmVmaXggPSAiUiQgIiwgYmlnLm1hcmsgPSAiLiIsIGRlY2ltYWwubWFyayA9ICIsIikpICsNCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxNCkNCg0KDQpnMyAvIGc2DQpgYGANCg0KIyMjIENvbmNsdXPDtWVzIFBhcmNpYWlzDQoNCkEgZm9ybWFsaWRhZGUgZXN0YWJpbGl6YSAobWVub3MgZGlzcGVyc8OjbyksIG1hcyBubyB0b3BvIGltcGxpY2EgZW0NCnNhbMOhcmlvcy1ob3JhIGNvbnNpc3RlbnRlbWVudGUgbWFpcyBiYWl4b3MuDQoNCk8gZWZlaXRvIG7Do28gw6kgY29uc3RhbnRlOiDDqSBwZXF1ZW5vIG5hIGJhc2UgZSBncmFuZGUgbm8gdG9wby4NCg0KSXNzbyBpbmRpY2EgcXVlIGEgZm9ybWFsaWRhZGUgYXR1YSBjb21vIHVtYSDigJzDom5jb3Jh4oCdIHNhbGFyaWFsOiBwcm90ZWdlDQpjb250cmEgcmVuZGFzIG11aXRvIGJhaXhhcywgbWFzIHRhbWLDqW0gbGltaXRhIGEgY2hhbmNlIGRlIHJlbmRhcyBtdWl0bw0KYWx0YXMuDQoNCk5vIHBlcmNlbnRpbCAxMCwgYSBkaWZlcmVuw6dhIMOpIHBvc2l0aXZhIHBhcmEgZm9ybWFpcywgYSBtZWRpZGEgcXVlIG8NCnNhbMOhcmlvLWhvcmEgc29iZSBhIGRpZmVyZW7Dp2Egc2UgaW52ZXJ0ZSwgbWFzIMOpIGdyYWR1YWwuDQoNCklzc28gY29uZmlybWEgcXVlIGEgZm9ybWFsaWRhZGUgY3Jlc2NlIGFvIGxvbmdvIGRhIGRpc3RyaWJ1acOnw6NvOiBxdWFudG8NCm1haXMgYWx0byBvIGRlY2lsLCBtYWlvciBhIHBlcmRhIHJlbGF0aXZhIGRvcyBmb3JtYWlzLg0KDQpKw6Egb3MgcG9udG9zIGRlIHQtdGVzdCBlIHN1cnZleSB0LXRlc3QgZmljYW0gcHLDs3hpbW9zIGRlIC0xMyBSXCQvaCwNCnJlZmxldGluZG8gYSBkaWZlcmVuw6dhIG3DqWRpYSBlbmNvbnRyYWRhIGFudGVzLCBtYXMgZGVtb25zdHJhbmRvIGNvbW8gYQ0KYW7DoWxpc2UgcXVhbnTDrWxpY2Egw6kgcmVsZXZhbnRlLg0KDQpPIHJlc3VsdGFkbyBtw6lkaW8gbWFzY2FyYSBhIGhldGVyb2dlbmVpZGFkZTogc2VyIGZvcm1hbCBpbXBsaWNhLCBlbQ0KbcOpZGlhLCBzYWzDoXJpby1ob3JhIG1lbm9yLCBtYXMgYSBtYWduaXR1ZGUgZGVwZW5kZSBmb3J0ZW1lbnRlIGRhIHBvc2nDp8Ojbw0KbmEgZGlzdHJpYnVpw6fDo28uDQo=