Desenho da Base
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
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")
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()

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))
Análise Descritiva
Iniciais - Por
Categoria
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")

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()

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")

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()

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))
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")
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
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)

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)

Análise
Inferencial
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.
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))
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?
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
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.
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

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
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
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

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

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

Quantílica sem
PSM
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

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
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

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=