Introdução


Contexto

O documento a seguir detalha o passo a passo da apuração da Variação da Despesa Assistencial (VDA) do ano de 2020 sobre o ano de 2019. Espera-se que esse documento possa auxiliar o público a replicar o cálculo da VDA 2020 e acompanhar a evolução da mesma ao longo do ano.

A VDA é um dos principais componentes do cálculo do Índice de Reajuste de Planos Individuais (IRPI), que estabelece o teto máximo para o reajuste anual por variação de custos das mensalidades dos planos de saúde de contratação individual ou familiar. A metodologia de cálculo do IRPI e da própria VDA foi estabelecida pela RN nº 441/2018 e está detalhada no Espaço do Consumidor no site da ANS.

A VDA expressa a variação da despesa assistencial média por beneficiário dos contratos dos planos individuais de cobertura médico-hospitalar regulamentados pela Lei nº 9.656, de 1998. A VDA, para fins do cálculo do IRPI, tem como base as despesas assistenciais incorridas de janeiro a dezembro e a média de beneficiários ao longo dos 12 meses de janeiro a dezembro nos dois anos imediatamente anteriores ao ano de divulgação do índice de reajuste.

A medida de tendência central do setor de saúde suplementar é a média da VDA das operadoras ponderada pelo número de beneficiários do período mais recente, conforme consignada no Anexo II da Resolução Normativa - RN nº 441, de 19 de dezembro de 2018. A fórmula para o cálculo da média ponderada da VDA das operadoras do setor em determinado ano é:

\[VDA_{p} = \sum_{i=1}^{n} \left[\left(\displaystyle\frac{\frac{DA_{p}}{Ben_{p}}}{\frac{DA_{p-1}}{Ben_{p-1}}} - 1\right) \times Ben_{p}\right]\div\sum_{i=1}^{n} Ben_{p}\]

Onde:
i = Operadora na base de cálculo
n = Todas as operadoras na base de cálculo
p = Período de janeiro a dezembro do ano calendário anterior ao início da aplicação do IRPI
DA = Despesa assistencial em carteira própria acumulada ao fim do período
Ben = Média mensal de beneficiários em carteira própria ao longo do período


Três conjuntos de dados do setor de saúde suplementar foram utilizados para extrair informações de despesa assistencial, quantidade de beneficiários com vínculos ativos e características das operadoras de planos de saúde. Esses conjuntos de dados podem ser acessadas pelo portal de dados abertos da Agência Nacional de Saúde Suplementar (ANS). Os links específicos para cada base utilizada neste cálculo estão disponíveis na respectiva seção de “Limpeza e Tratamento de Dados”.


Setup

Desenvolvido em R versão 4.0.5 e RStudio versão 1.4.1106

# Setup (bibliotecas, funções e variáveis globais) =============================
library(data.table)
library(tidyverse)
library(dtplyr)
library(lubridate)

# "Desliga" notação científica. 
options(scipen=999)

# função para exclusão de valores extremos por boxplot 1.5xIQR
trim.df <- function(df, metrica){
  df %>% filter((metrica > quantile(metrica, 0.25) - 1.5 * IQR(metrica)) 
                & (metrica < quantile(metrica, 0.75) + 1.5 * IQR(metrica)))
}

# função para gerar resumo de estatísticas descritivas
statsVDA <- function(df){
  df %>% 
    summarise(n_ops = n_distinct(cd_ops),
              benef = sum(benefm),
              mediaP = weighted.mean(vda, w = benefm),
              min = min(vda),
              q1 = quantile(vda, p = .25, names = F),
              median = median(vda),
              q3 = quantile(vda, p = .75, names = F),
              max = max(vda),
              dp = sd(vda),
              media = mean(vda),
              .groups = 'drop') %>%
    mutate(across( c(mediaP:media), ~ round(.x, 2) ))
}

# período de análise
(periodo <- c(make_date(2019,01,01), make_date(2020,12,01)))
[1] "2019-01-01" "2020-12-01"

Limpeza e tratamento dos dados


Despesa Assistencial

As informações das despesas incorridas na prestação de assistência médico-hospitalar são extraídas das Demonstrações Contábeis informadas pelas operadoras no Documento de Informações Periódicas das Operadoras de Planos de Assistência à Saúde (DIOPS). A data limite de envio das informações do 4º trimestre ao DIOPS é o dia 31 de março do ano subsequente.

Todas as demonstrações financeiras publicadas seguem os critérios do Plano de Contas Padrão da ANS para as operadoras de planos de saúde, conforme estabelecido pela RN nº 435, de 23 de novembro de 2018.

A base de dados do DIOPS referente ao 4º trimestre de 2020 pode ser acessada no Portal de Dados Abertos da ANS - Demonstrações Contábeis. Esse conjunto de dados detalha o saldo acumulado em reais ao final de cada trimestre nas contas contábeis de cada operadora (incluindo contas de balanço e demonstrações de resultado).

A base referente ao 4º trimestre de 2019 disponível no Portal de Dados Abertos foi publicada em abril de 2020. Assim, faz-se necessário consultar uma versão atualizada dos dados do 4º trimestre de 2019 que contemple as retificações feitas pelas operadoras desde então. A base de Demonstrações Contábeis referentes a 2019 atualizada em 16/04/2021 pode ser acessada no site da ANS em Espaço do Consumidor > Reajuste > Individual ou familiar > Metodologia de Cálculo.

O código a seguir faz a leitura dos arquivos *.csv:

# Load dataset juntando vários arquivos a partir de uma pasta ==================
files <- list.files(path = "./datasets/diops/", pattern = "*.csv", full.names = T)
diops <- rbindlist(lapply(files, fread, 
                          dec=",", drop='DESCRICAO', 
                          colClasses = c(CD_CONTA_CONTABIL="character"))) %>% 
  lazy_dt() %>%
  rename_with(tolower) %>% 
  filter(
    nchar(cd_conta_contabil) == 9, # filtra contas contábeis de 9 dígitos
    vl_saldo_final != 0            # exclui linhas sem saldo
  ) %>% 
  mutate(id_calendar = dmy(data) + months(2)) %>% # altera para último mês do trimestre
  rename(cd_ops = reg_ans) %>% 
  select(cd_ops, cd_conta_contabil, id_calendar, vl_saldo_final) %>% 
  as_tibble()

remove(files)


O alvo da análise é a despesa assistencial incorrida pela operadora em carteira própria. Os valores de Despesa Assistencial em Carteira Própria correspondem à totalização dos saldos dos seguintes grupos de contas contábeis do Plano de Contas Padrão da ANS para as operadoras de planos de saúde, conforme estabelecido pela RN nº 435, de 23 de novembro de 2018:

Conta contábil Descrição Totalização
411X1 Eventos/ Sinistros Conhecidos ou Avisados de Assistência a Saúde Medico Hospitalar (+)
411X1XX8 Corresponsabilidade Assumida (-)
31171 (-) Contraprestações de Corresponsabilidade Cedida de Assistência Médico-Hospitalar (-)

Dessa forma, o valor da despesa assistencial em carteira própria inclui valores de Eventos/ Sinistros conhecidos ou avisados e valores de gastos de corresponsabilidade de carteira própria cedida a terceiros (contas contábeis redutoras de receita 31171). Valores de corresponsabilidade assumida são desconsiderados, pois referem-se a despesas assistenciais incorridas em atendimento a carteira de terceiros (outras operadoras).

O código a seguir totaliza a despesa assistencial por trimestre, operadora e tipo de carteira:

# seleciona as contas contábeis relevantes (despesa e receita) =================
diops <- diops %>% 
  filter( # filtra contas contábeis relevantes para a análise
    # despesa / corresponsabilidade assumida médico-hospitalar
    (substr(cd_conta_contabil, 1, 3) == '411' & substr(cd_conta_contabil, 5, 5) == '1')
    # receita / corresponsabilidade cedida médico-hospitalar
    | (substr(cd_conta_contabil, 1, 5) == '31111' | substr(cd_conta_contabil, 1, 5) == '31171')
  ) %>% 
  mutate(
    gr_cc = case_when(
      substr(cd_conta_contabil, 1, 1) == '4' ~ 'eventos',
      substr(cd_conta_contabil, 1, 5) == '31111' ~ 'receita', 
      substr(cd_conta_contabil, 1, 5) == '31171' ~ 'corr_cedida', # redutora de receita
      TRUE ~ 'EXCLUIR'), 
  ) %>%
  group_by(cd_ops, cd_conta_contabil, id_calendar, gr_cc) %>% 
  summarise(vl_saldo_final = sum(vl_saldo_final), 
            .groups = 'drop') %>%  
  pivot_wider(names_from = gr_cc, values_from = vl_saldo_final, values_fill = 0) %>% 
  # identifica tipos de plano pela conta contábil
  mutate(
    vigencia = case_when(
      substr(cd_conta_contabil, 8, 8) == '8' ~ 'corr_assumida', 
      substr(cd_conta_contabil, 8, 8) %in% c('1','3','5') ~ 'A',
      substr(cd_conta_contabil, 8, 8) %in% c('2','4','6') ~ 'P',
      TRUE ~ 'EXCLUIR'), 
    contratacao = case_when(
      substr(cd_conta_contabil, 8, 8) == '8' ~ 'corr_assumida', 
      substr(cd_conta_contabil, 8, 8) %in% c('1','2') ~ 'Individual',
      substr(cd_conta_contabil, 8, 8) %in% c('3','4') ~ 'Adesão',
      substr(cd_conta_contabil, 8, 8) %in% c('5','6') ~ 'Empresarial',
      TRUE ~ 'EXCLUIR'), 
    financiamento = case_when(
      substr(cd_conta_contabil, 8, 8) == '8' ~ 'corr_assumida', 
      substr(cd_conta_contabil, 6, 6) == '1' ~ 'Pre-estabelecido',
      substr(cd_conta_contabil, 6, 6) == '2' ~ 'Pós-estabelecido',
      TRUE ~ 'EXCLUIR'), 
  ) %>% 
  filter(vigencia != 'corr_assumida') %>%     # exclui corr assumida
  mutate(despesa = eventos - corr_cedida,
         contratacao = as.factor(contratacao)) %>% # inclui corr cedida na despesa
  group_by(cd_ops, vigencia, contratacao, financiamento, id_calendar) %>% 
  summarise(receita = sum(receita), 
            despesa = sum(despesa), 
            .groups = 'drop')
  

diops %>% group_by(ano= year(id_calendar)) %>% 
  summarise(
    receita = round(sum(receita, na.rm = T)/1000000000, 1), # em R$ bilhões
    despesa = round(sum(despesa, na.rm = T)/1000000000, 1), # em R$ bilhões
    n_ops = n_distinct(cd_ops), 
    .groups = 'drop'
  ) %>% 
  mutate(pct_despesa = round(despesa/receita*100,2))


Filtra segmentos alvo da análise e totaliza por trimestre, operadora e tipo de plano:

diops <- diops %>% 
  filter( # filtra tipos de plano relevantes para a análise
    vigencia == 'P', # planos novos
    financiamento == 'Pre-estabelecido', # financiamento pre-estabelecido
  ) %>% 
  select(-vigencia, -financiamento)

diops %>% group_by(contratacao, ano= year(id_calendar)) %>% 
  summarise(
    receita = round(sum(receita, na.rm = T)/1000000000, 1), # em R$ bilhões
    despesa = round(sum(despesa, na.rm = T)/1000000000, 1), # em R$ bilhões
    n_ops = n_distinct(cd_ops),
    .groups = 'drop') %>% 
  mutate(pct_despesa = round(despesa/receita*100,2))

Beneficiários (semi-aditivo)

As informações de vínculos ativos de beneficiários são obtidas através da base do Sistema de Informação de Beneficiários (SIB), que é atualizado mensalmente. A versão utilizada nos cálculos da VDA 2020/2019 é a versão atualizada até março de 2021.

A base de dados do SIB referente aos anos de 2019 e 2020 pode ser acessada no Portal de Dados Abertos da ANS - Beneficiários por operadora e tipo de carteira para cálculo da VDA no site da ANS. Esse conjunto de dados informa a quantidade de vínculos ativos de beneficiários em planos de saúde médico-hospitalar mês a mês por operadora e tipo de plano.

O código a seguir faz a leitura dos arquivos *.csv:

# Load dataset
sib <- fread("./datasets/Beneficiarios_operadora_e_carteira.csv") %>%
  lazy_dt() %>%
  rename_with(tolower) %>% 
  mutate(
    id_calendar = make_date(as.integer(mes / 100), 
                            mes - as.integer(mes / 100) * 100, 1),
    modalidade = as.factor(gr_modalidade),
    vigencia = as.factor(vigencia_plano),
    contratacao = as.factor(gr_contratacao),
    financiamento = as.factor(tipo_financiamento),
  ) %>%
  filter(
    id_calendar >= periodo[1], id_calendar <= periodo[2],  # período de análise
    nr_benef != 0, !is.na(nr_benef)   # exclui zeros e nulos
  ) %>% 
  rename( cd_ops = cd_operadora, benef = nr_benef ) %>% 
  mutate(
    contratacao = case_when(
      contratacao == 'Coletivo empresarial' ~ 'Empresarial',
      contratacao == 'Coletivo por adesão' ~ 'Adesão',
      contratacao == 'Individual ou familiar' ~ 'Individual',
      TRUE ~ 'Não identificado')
  ) %>% 
  select(cd_ops, modalidade, 
         vigencia, contratacao, financiamento, 
         id_calendar, benef) %>% 
  as_tibble()

# segmenta porte da operadora pela quantidade de beneficiários médico-hospitalares
ops <- sib %>% 
  filter(id_calendar == periodo[2]) %>% 
  group_by(cd_ops) %>% 
  summarise(benef = sum(benef)) %>% 
  mutate(
    porte_ops = case_when(
      benef > 100000 ~ 'Grande',
      benef >= 20000 ~ 'Médio',
      TRUE ~ 'Pequeno' )
  )

sib %>% group_by(ano = year(id_calendar)) %>% 
  summarise(benef_media_agregada = round(sum(benef)/12,0),
            n_ops = n_distinct(cd_ops),
            .groups = 'drop') 


Filtra segmentos alvo da análise e totaliza por mês, operadora e tipo de plano.

sib <- sib %>% 
  filter(
    # operadoras médico-hospitalares
    modalidade %in% c('Autogestão', 'Cooperativa Médica', 'Filantropia',
                      'Medicina de Grupo','Seguradora'),
    vigencia == 'P', # planos novos
    financiamento != 'Pós-estabelecido', # financiamento pre-estabelecido
    contratacao %in% c('Empresarial', 'Individual', 'Adesão')) %>% 
  group_by(cd_ops, contratacao, id_calendar) %>% 
  summarise(benef = sum(benef), .groups = 'drop') 

sib %>% group_by(contratacao, ano = year(id_calendar)) %>% 
  summarise(benef_media_agregada = round(sum(benef)/12,0),
            n_ops = n_distinct(cd_ops),
            .groups = 'drop') 


Calcula média de beneficiários acumulada no ano por operadora e tipo de contratação:

sib <- sib %>% 
  arrange(cd_ops, contratacao, id_calendar) %>% 
  # cria coluna do ano
  mutate(id_calendar = ymd(id_calendar), 
         ano = as.integer(year(id_calendar))) %>% 
  # calcula a média por operadora, contratacao e ano
  group_by(cd_ops, contratacao, ano) %>% 
  mutate(
    benefm = cummean(benef),        # média acumulada no ano
    n_meses = length(benef),                 # qtd de meses com beneficiários
    mes = as.integer(month(id_calendar)),
    contratacao = as.factor(contratacao),
  ) %>% 
  ungroup() %>% 
  filter(mes %in% c(12)) %>% # seleciona o(s) período(s) alvo da análise
  select(-benef, -ano, -mes) 

sib %>% group_by(contratacao, ano = year(id_calendar)) %>% 
  summarise(benefm = round(sum(benefm),0), # soma das médias
            n_ops = n_distinct(cd_ops),
            .groups = 'drop')

Operadoras

As características das operadoras são obtidas do Sistema de Cadastro de Operadoras (CADOP).

Dois conjuntos de dados estão disponíveis no Portal de Dados Abertos da ANS: Cadastro das Operadoras de planos de saúde Ativas e das Operadoras de planos de saúde Canceladas. Esses conjuntos de dados incluem características como o razão social, modalidade da operadora, assim como as datas de início e fim de operação (respectivamente data do registro e data do cancelamento do registro).

O código a seguir faz a leitura dos arquivos *.csv:

# Load dataset juntando vários arquivos a partir de uma pasta
files <- list.files(path="./datasets/cadop/", pattern="*.csv", full.names=T)

cadop <- rbindlist(lapply(files, fread), fill=T) %>% 
  lazy_dt() %>%
  rename_with(tolower) %>% 
  mutate(
    dt_registro = dmy(data_registro_ans), 
    dt_cancelamento = dmy(data_descredenciamento),
    modalidade = ifelse(modalidade == 'Seguradora Especializada em Saúde',
                        'Seguradora',
                        modalidade)) %>% 
  mutate(modalidade = as.factor(modalidade)) %>% 
  rename(cd_ops = registro_ans) %>% 
  select(cd_ops, razao_social, modalidade, dt_registro, dt_cancelamento) %>%
  as_tibble() %>% 
  left_join(ops, by='cd_ops') %>% 
  select(-benef) %>% 
  mutate(porte_ops = as.factor(ifelse(is.na(porte_ops), 'Pequeno', porte_ops)))

remove(files)


Para o cálculo da VDA no IRPI selecionam-se as operadoras médico-hospitalares e são desconsideradas

  1. Operadoras que iniciaram operação entre janeiro de 2019 e dezembro de 2020.
  2. Operadoras que tiveram registro cancelado até dezembro de 2020.
  3. Operadoras com ressalvas nas demonstrações financeiras protocoladas junto à ANS referentes a 2019 ou 2020.

O código a seguir filtra operadoras médico-hospitalares e identifica operadoras a serem desconsideradas na base de cálculo da VDA:

ressalvas <- fread("./datasets/ressalvas.csv", encoding = 'UTF-8') %>% 
  distinct(cd_ops) %>% 
  mutate(lg_ressalva = 1) %>% 
  as_tibble()

cadop <- cadop %>% 
  filter(modalidade %in% c('Autogestão', 'Cooperativa Médica', 'Filantropia',
                           'Medicina de Grupo', 'Seguradora')) %>%  # ops médico-hospitalares
  mutate(
    lg_cancelada = ifelse(year(dt_cancelamento) <= year(periodo[2]) 
                          & !is.na(dt_cancelamento),
                          1, 0), # filtro de fim da operação
    lg_nova_ops  = ifelse(year(dt_registro) >= year(periodo[1]),
                          1, 0)) %>% # filtro de início de operação
  select(cd_ops, razao_social, modalidade, porte_ops, lg_cancelada, lg_nova_ops) %>%
  left_join(ressalvas, by = 'cd_ops') %>% 
  mutate(lg_ressalva = ifelse(is.na(lg_ressalva), 0, lg_ressalva))

remove(ops, ressalvas)
cadop %>% summarise(
  n_ops = n_distinct(cd_ops),
  n_canceladas = sum(lg_cancelada),
  n_nova_ops = sum(lg_nova_ops),
  n_ressalvas = sum(lg_ressalva)
)

Cálculo da VDA


Despesa por Beneficiário

Essa seção gera a base de despesa assistencial e beneficiários e calcula a despesa por beneficiário.

A despesa por beneficiário é a despesa assistencial da carteira própria de uma operadora incorrida em certo período, dividida pela média de vínculos ativos de beneficiários ao longo do mesmo período. Essa métrica representa o principal componente de custo de um plano de saúde e está expressa de forma a permitir compará-la entre operadoras por tipo de carteira e acompanhar sua evolução ao longo do tempo.

Nota:
Para facilitar a comparabilidade e acompanhamento da despesa por beneficiário ao longo do tempo, é possível normalizar a métrica dividindo-a pelo número de meses do período sem impacto sobre a VDA.

A base de cálculo da VDA considera apenas:

  • Operadoras válidas

  • Observações que apresentam valor positivo de despesa

  • Observações que apresentam uma sequência ininterrupta de 12 meses de beneficiários no ano

O código a seguir consolida os dados de operadoras, beneficiários e despesas, filtra as observações relevantes e calcula a Despesa por Beneficiário (média mensal):

df.vda <- diops %>% 
  select(-receita) %>% 
  inner_join(sib, by=c('cd_ops', 'contratacao', 'id_calendar')) %>% 
  inner_join(cadop, by='cd_ops') %>% 
  filter(
    lg_cancelada == 0, 
    lg_nova_ops  == 0, 
    lg_ressalva  == 0,
    despesa > 0,
    n_meses == 12 # ops com sequência ininterrupta de beneficiários no ano
  ) %>% 
  select(-c(lg_cancelada, lg_nova_ops, lg_ressalva, n_meses)) %>% 
  relocate(c(razao_social, modalidade, porte_ops), .after = cd_ops) %>% 
  arrange(cd_ops, contratacao, id_calendar) %>% 
  mutate(dpb = ifelse(benefm > 0, despesa/ benefm / month(id_calendar), NA))

df.vda %>% group_by(contratacao, ano= year(id_calendar)) %>% 
  summarise('Despesa (R$bn)' = round(sum(despesa)/1000000000,1),
            'Beneficiários (média)' = round(sum(benefm),0),
            'Qtd operadoras' = n_distinct(cd_ops),
            .groups = 'drop')


Visualização gráfica da distribuição da despesa por beneficiário das operadoras.
Nota: Excluíram-se os valores atípicos pelo método de boxplot 1,5xIQR para que fosse possível visualizar a distribuição da grande maioria dos dados.

trim.df(df.vda, df.vda$dpb) %>% ggplot(aes(x=dpb)) +
  geom_histogram(bins = 50, fill = 'white', color = "slategray") +
  theme(axis.line = element_line(color = 'gray'),
        panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        panel.border = element_blank(),
        panel.background = element_blank()) +
  labs(x = "Despesa mensal por beneficiário (R$)",
       y = "Frequência") + 
  facet_grid(contratacao ~ year(id_calendar))


VDA por operadora

A VDA de uma operadora é a variação da despesa por beneficiário desta operadora sobre o mesmo período do ano anterior, conforme a seguinte fórmula:

\[VDA_{ip} = \displaystyle\frac{\frac{DA_{ip}}{Ben_{ip}}}{\frac{DA_{i\ \left(p-1\right)}}{Ben_{i\ \left(p-1\right)}}} - 1\]

Onde:
i = Operadora na base de cálculo
p = Período de janeiro a dezembro do ano calendário anterior ao início da aplicação do IRPI
DA = Despesa assistencial em carteira própria acumulada ao fim do período
Ben = Média mensal de beneficiários em carteira própria ao longo do período

O código a seguir calcula a VDA por operadora:

df.vda <- df.vda %>%
  arrange(cd_ops, contratacao, id_calendar) %>% 
  mutate(vda = ifelse(lag(cd_ops) == cd_ops 
                      & lag(contratacao) == contratacao
                      & year(lag(id_calendar)) == year(id_calendar) - 1, 
                      (dpb/lag(dpb) - 1) * 100, NA)) %>% 
  filter(!is.na(vda)) %>% 
  select(-id_calendar)

VDA do setor

Estatísticas descritivas da base de cálculo da VDA.

df.vda %>% group_by(contratacao) %>% 
  statsVDA() 

Visualização gráfica da distribuição da VDA das operadoras através de um gráfico boxplot.

O código a seguir identifica valores atípicos pela metodologia BoxPlot 1,5xIQR e calcula a proporção de valores atípicos por carteira:

# === IDENTIFICA OUTLIERS === CRITÉRIO: BOX-PLOT 1.5x ===
df.vda <- df.vda %>%
  group_by(contratacao) %>% 
  mutate(lg_outlier = ifelse(vda >= (quantile(vda, 0.75, names = F) + 1.5 * IQR(vda)) 
                             | vda <= (quantile(vda, 0.25, names = F) - 1.5 * IQR(vda)),
                             1, 0)) %>% 
  ungroup()

# Proporção de outliers
df.vda %>%
  group_by(contratacao, lg_outlier) %>%
  summarise(n_obs = n()) %>%
  add_tally(wt = n_obs) %>%
  mutate(pct_obs = round(n_obs / n * 100, 1))


Boxplot da distribuição da VDA após a exclusão dos valores atípicos.


Histograma da distribuição da VDA sem os valores atípicos.


A metodologia de cálculo da VDA do setor para aplicação como componente do IRPI adota a VDA média ponderada pela quantidade de beneficiários no ano mais recente, após a exclusão dos valores atípicos. A seguir, apresenta-se a média ponderada da VDA (mediaP) e demais estatísticas descritivas da sua distribuição em cada carteira.

df.vda %>% filter(lg_outlier == 0) %>% 
  group_by(contratacao) %>% 
  statsVDA()

Base de cálculo


Gera a base completa que reúne todas as observações de receita, despesa e beneficiários informadas pelas operadoras para os dois anos e o cálculo da VDA por operadora.

sib2 <- sib %>% 
  mutate(ano = year(id_calendar)) %>% 
  select(-id_calendar) %>% 
  rename(ben = benefm) %>% 
  pivot_wider(names_from = ano, values_from = c(ben, n_meses), 
              values_fill = 0) %>% 
  mutate(
    lg_benef = ifelse( # marca obs sem sequencia ininterrupta de ben em 1 dos anos
      ben_2019 < 1 | ben_2020 < 1 | (n_meses_2019 + n_meses_2020) != 24, 
      1, 0)
  ) %>% 
  select(-starts_with('n_meses'))

diops2 <- diops %>% 
  mutate(ano = year(id_calendar)) %>% 
  select(-id_calendar) %>% 
  pivot_wider(names_from = ano, values_from = c(despesa, receita), 
              values_fill = 0) %>% 
  mutate(lg_despesa = ifelse(
    despesa_2019 <=0 | despesa_2020 <= 0, 1, 0 # marca obs sem despesa em 1 dos anos
  )) 

df.vda2 <- df.vda %>% 
  select(cd_ops, contratacao, vda, lg_outlier)

df.reunida <-  sib2 %>% 
  full_join(diops2, by=c('cd_ops', 'contratacao')) %>% 
  mutate(dpb_2019 = ifelse(despesa_2019 > 0 & ben_2019 > 0, 
                           round(despesa_2019 / ben_2019 / 12, 0), NA),
         dpb_2020 = ifelse(despesa_2020 > 0 & ben_2020 > 0, 
                           round(despesa_2020 / ben_2020 / 12, 0), NA)) %>% 
  full_join(df.vda2, by=c('cd_ops', 'contratacao')) %>% 
  inner_join(cadop, by = 'cd_ops') %>% 
  mutate(despesa_2019 = ifelse(despesa_2019 == 0, NA, despesa_2019),
         despesa_2020 = ifelse(despesa_2020 == 0, NA, despesa_2020),
         receita_2019 = ifelse(receita_2019 == 0, NA, receita_2019),
         receita_2020 = ifelse(receita_2020 == 0, NA, receita_2020),
         ben_2019   = ifelse(ben_2019 == 0, NA, ben_2019),
         ben_2020   = ifelse(ben_2020 == 0, NA, ben_2020),
         lg_benef   = ifelse(is.na(lg_benef), 1, lg_benef),
         lg_despesa = ifelse(is.na(lg_despesa), 1, lg_despesa)
  ) %>% 
  relocate(razao_social:lg_ressalva, .after = cd_ops) %>% 
  select(cd_ops:contratacao, 
         starts_with('lg_'),
         starts_with('receita'), 
         starts_with('despesa'), 
         starts_with('ben'), 
         everything())

remove(diops2, sib2, df.vda2)

df.reunida %>% filter(lg_outlier == 0) %>% 
  group_by(contratacao) %>% 
  rename(benefm = ben_2020) %>% 
  statsVDA()


Calcula a proporção (representatividade) da base de cálculo sobre as bases originais.

df1 <- df.reunida %>% filter(!is.na(lg_outlier)) %>% 
  group_by(contratacao) %>% 
  summarise(benef.VDA = sum(ben_2020),
            despesa.VDA = sum(despesa_2020), 
            n_ops.VDA = n_distinct(cd_ops))

df2 <- df.reunida %>% 
  group_by(contratacao) %>% 
  summarise(benef.orig   = sum(ben_2020, na.rm = T),
            despesa.orig = sum(despesa_2020, na.rm = T),
            n_ops.orig.ben   = n_distinct(cd_ops, ben_2020, na.rm = TRUE),
            n_ops.orig_desp = n_distinct(cd_ops, despesa_2020, na.rm = TRUE)) %>% 
  inner_join(df1, by='contratacao') %>% 
  mutate(benef.pct    = benef.VDA / benef.orig * 100, 
         despesa.pct  = despesa.VDA / despesa.orig * 100,
         n_ops.benef.pct   = n_ops.VDA / n_ops.orig.ben * 100,
         n_ops.despesa.pct = n_ops.VDA / n_ops.orig_desp * 100) %>% 
  select(contratacao, starts_with("benef"), starts_with("despesa"), starts_with("n_ops"))


df2 %>% select(c(contratacao, ends_with('.pct'))) %>% 
  pivot_longer(cols = ends_with(".pct"), 
               values_to = "percentual", names_to = 'Metrica') %>% 
  mutate(Metrica = sub('.pct', '', Metrica),
         Metrica = case_when(
           Metrica == 'benef' ~ 'Beneficiários',
           Metrica == 'despesa' ~ 'Despesa',
           Metrica == 'n_ops.benef' ~ 'Ops (SIB)',
           Metrica == 'n_ops.despesa' ~ 'Ops (DIOPS)', 
           TRUE ~ 'ERRO'),
         percentual = round(percentual, 1)
         ) %>% 
  ggplot(aes(y = contratacao, x=percentual)) +
  geom_col(position = 'dodge', fill = "slategray4") +
  geom_text(aes(label = percentual, hjust = 1.2), color = "white", 
            position = position_dodge(1)) +
  labs(x=NULL, y=NULL, 
       title = "Representatividade da base de cálculo da VDA sobre as bases originais\n") +
  theme(axis.line = element_line(color = 'gray'),
        panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(),
        panel.border = element_blank()) + 
  facet_grid(Metrica ~ .)


Glossário

Beneficiário: Indivíduo (pessoa física) beneficiário de cobertura de plano privado de assistência à saúde e consumidor de serviços de assistência à saúde.

Contratante: Pessoa física ou jurídica responsável pela contratação do plano privado de assistência à saúde.

Operadora: Pessoa jurídica constituída sob a modalidade de sociedade civil ou comercial, cooperativa ou entidade de autogestão, que opere produto, serviço ou contrato de plano privado de assistência à saúde.

Plano Privado de Assistência à Saúde: Prestação continuada de serviços ou cobertura de custos assistenciais a preço pré ou pós estabelecido, por prazo indeterminado, com a finalidade de garantir, sem limite financeiro, a assistência à saúde, pela faculdade de acesso e atendimento por profissionais ou serviços de saúde, livremente escolhidos, integrantes ou não de rede credenciada, contratada ou referenciada, visando a assistência médica, hospitalar e odontológica, a ser paga integral ou parcialmente às expensas da operadora contratada, mediante reembolso ou pagamento direto ao prestador, por conta e ordem do consumidor.

Tipo de contratação:

  • Individual ou Familiar, oferece cobertura da atenção prestada para a livre adesão de beneficiários, pessoas naturais, com ou sem grupo familiar

  • Coletivo empresarial, quando a contratação é feita por meio de pessoa jurídica para a cobertura de pessoas a ela vinculadas por relação empregatícia ou estatutária

  • Coletivo por adesão, quando a contratação é feita por meio de pessoa jurídica de caráter profissional, classista ou setorial (e.g. conselhos profissionais, entidades de classe, sindicatos, cooperativas, etc.)

Tipo de financiamento:

  • Pré-estabelecido, quando o valor da contraprestação pecuniária é pré-fixado mediante negociação anual, caracterizando contrato de risco.

  • Pós-estabelecido, quando o valor da contraprestação pecuniária é estabelecido após a ocorrência dos procedimentos de assistência à saúde.

LS0tDQp0aXRsZTogIlZhcmlhw6fDo28gZGEgRGVzcGVzYSBBc3Npc3RlbmNpYWwgKFZEQSkiDQphdXRob3I6ICJBZ8OqbmNpYSBOYWNpb25hbCBkZSBTYcO6ZGUgU3VwbGVtZW50YXIiDQpkYXRlOiAiMzAgZGUgYWJyaWwgZGUgMjAyMSINCm91dHB1dDoNCiAgaHRtbF9ub3RlYm9vazoNCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogMw0KICAgIHRvY19mbG9hdDogeWVzDQotLS0NCioqKg0KIyMgSW50cm9kdcOnw6NvDQoqKioNCg0KIyMjIENvbnRleHRvDQoNCk8gZG9jdW1lbnRvIGEgc2VndWlyIGRldGFsaGEgbyBwYXNzbyBhIHBhc3NvIGRhIGFwdXJhw6fDo28gZGEgKipWYXJpYcOnw6NvIGRhIERlc3Blc2EgQXNzaXN0ZW5jaWFsIChWREEpKiogZG8gYW5vIGRlIDIwMjAgc29icmUgbyBhbm8gZGUgMjAxOS4gRXNwZXJhLXNlIHF1ZSBlc3NlIGRvY3VtZW50byBwb3NzYSBhdXhpbGlhciBvIHDDumJsaWNvIGEgcmVwbGljYXIgbyBjw6FsY3VsbyBkYSBWREEgMjAyMCBlIGFjb21wYW5oYXIgYSBldm9sdcOnw6NvIGRhIG1lc21hIGFvIGxvbmdvIGRvIGFuby4gICAgDQoNCkEgVkRBIMOpIHVtIGRvcyBwcmluY2lwYWlzIGNvbXBvbmVudGVzIGRvIGPDoWxjdWxvIGRvICoqw41uZGljZSBkZSBSZWFqdXN0ZSBkZSBQbGFub3MgSW5kaXZpZHVhaXMgKElSUEkpKiosIHF1ZSBlc3RhYmVsZWNlIG8gdGV0byBtw6F4aW1vIHBhcmEgbyByZWFqdXN0ZSBhbnVhbCBwb3IgdmFyaWHDp8OjbyBkZSBjdXN0b3MgZGFzIG1lbnNhbGlkYWRlcyBkb3MgcGxhbm9zIGRlIHNhw7pkZSBkZSBjb250cmF0YcOnw6NvIGluZGl2aWR1YWwgb3UgZmFtaWxpYXIuICBBIG1ldG9kb2xvZ2lhIGRlIGPDoWxjdWxvIGRvIElSUEkgZSBkYSBwcsOzcHJpYSBWREEgZm9pIGVzdGFiZWxlY2lkYSBwZWxhIFtSTiBuwrogNDQxLzIwMThdKGh0dHA6Ly93d3cuYW5zLmdvdi5ici9jb21wb25lbnQvbGVnaXNsYWNhby8/dmlldz1sZWdpc2xhY2FvJnRhc2s9VGV4dG9MZWkmZm9ybWF0PXJhdyZpZD1NelkyTWc9PSkgZSBlc3TDoSBkZXRhbGhhZGEgbm8gW0VzcGHDp28gZG8gQ29uc3VtaWRvcl0oaHR0cDovL3d3dy5hbnMuZ292LmJyL3BsYW5vcy1kZS1zYXVkZS1lLW9wZXJhZG9yYXMvZXNwYWNvLWRvLWNvbnN1bWlkb3IvcmVhanVzdGUtdmFyaWFjYW8tZGUtbWVuc2FsaWRhZGUvcmVhanVzdGUtYW51YWwtZGUtcGxhbm9zLWluZGl2aWR1YWlzLWZhbWlsaWFyZXMpIG5vIHNpdGUgZGEgQU5TLiAgICAgICAgICAgICAgDQoNCkEgVkRBIGV4cHJlc3NhIGEgdmFyaWHDp8OjbyBkYSBkZXNwZXNhIGFzc2lzdGVuY2lhbCBtw6lkaWEgcG9yIGJlbmVmaWNpw6FyaW8gZG9zIGNvbnRyYXRvcyBkb3MgcGxhbm9zIGluZGl2aWR1YWlzIGRlIGNvYmVydHVyYSBtw6lkaWNvLWhvc3BpdGFsYXIgcmVndWxhbWVudGFkb3MgcGVsYSBMZWkgbsK6IDkuNjU2LCBkZSAxOTk4LiBBIFZEQSwgcGFyYSBmaW5zIGRvIGPDoWxjdWxvIGRvIElSUEksIHRlbSBjb21vIGJhc2UgYXMgZGVzcGVzYXMgYXNzaXN0ZW5jaWFpcyBpbmNvcnJpZGFzIGRlIGphbmVpcm8gYSBkZXplbWJybyBlIGEgbcOpZGlhIGRlIGJlbmVmaWNpw6FyaW9zIGFvIGxvbmdvIGRvcyAxMiBtZXNlcyBkZSBqYW5laXJvIGEgZGV6ZW1icm8gbm9zIGRvaXMgYW5vcyBpbWVkaWF0YW1lbnRlIGFudGVyaW9yZXMgYW8gYW5vIGRlIGRpdnVsZ2HDp8OjbyBkbyDDrW5kaWNlIGRlIHJlYWp1c3RlLiAgICANCg0KQSBtZWRpZGEgZGUgdGVuZMOqbmNpYSBjZW50cmFsIGRvIHNldG9yIGRlIHNhw7pkZSBzdXBsZW1lbnRhciDDqSBhIG3DqWRpYSBkYSBWREEgZGFzIG9wZXJhZG9yYXMgcG9uZGVyYWRhIHBlbG8gbsO6bWVybyBkZSBiZW5lZmljacOhcmlvcyBkbyBwZXLDrW9kbyBtYWlzIHJlY2VudGUsIGNvbmZvcm1lIGNvbnNpZ25hZGEgbm8gQW5leG8gSUkgZGEgW1Jlc29sdcOnw6NvIE5vcm1hdGl2YSAtIFJOIG7CuiA0NDEsIGRlIDE5IGRlIGRlemVtYnJvIGRlIDIwMThdKGh0dHA6Ly93d3cuYW5zLmdvdi5ici9jb21wb25lbnQvbGVnaXNsYWNhby8/dmlldz1sZWdpc2xhY2FvJnRhc2s9VGV4dG9MZWkmZm9ybWF0PXJhdyZpZD1NelkyTWc9PSkuIEEgZsOzcm11bGEgcGFyYSBvIGPDoWxjdWxvIGRhIG3DqWRpYSBwb25kZXJhZGEgZGEgVkRBIGRhcyBvcGVyYWRvcmFzIGRvIHNldG9yIGVtIGRldGVybWluYWRvIGFubyDDqTogICAgIA0KPGJyPg0KICAgIA0KDQokJFZEQV97cH0gPSBcc3VtX3tpPTF9XntufSBcbGVmdFtcbGVmdChcZGlzcGxheXN0eWxlXGZyYWN7XGZyYWN7REFfe3B9fXtCZW5fe3B9fX17XGZyYWN7REFfe3AtMX19e0Jlbl97cC0xfX19IC0gMVxyaWdodCkgXHRpbWVzIEJlbl97cH1ccmlnaHRdXGRpdlxzdW1fe2k9MX1ee259IEJlbl97cH0kJA0KPGJyPg0KPGRpdiBjbGFzcz0iYWxlcnQgYWxlcnQtYmxvY2sgYWxlcnQtaW5mbyI+DQo8Yj5PbmRlOjwvYj4gICAgIA0KICAgIGkgPSBPcGVyYWRvcmEgbmEgYmFzZSBkZSBjw6FsY3VsbyAgICAgICAgDQogICAgbiA9IFRvZGFzIGFzIG9wZXJhZG9yYXMgbmEgYmFzZSBkZSBjw6FsY3VsbyAgICAgICAgIA0KICAgIHAgPSBQZXLDrW9kbyBkZSBqYW5laXJvIGEgZGV6ZW1icm8gZG8gYW5vIGNhbGVuZMOhcmlvIGFudGVyaW9yIGFvIGluw61jaW8gZGEgYXBsaWNhw6fDo28gZG8gSVJQSSAgICANCiAgICBEQSA9IERlc3Blc2EgYXNzaXN0ZW5jaWFsIGVtIGNhcnRlaXJhIHByw7NwcmlhIGFjdW11bGFkYSBhbyBmaW0gZG8gcGVyw61vZG8gICAgIA0KICAgIEJlbiA9IE3DqWRpYSBtZW5zYWwgZGUgYmVuZWZpY2nDoXJpb3MgZW0gY2FydGVpcmEgcHLDs3ByaWEgYW8gbG9uZ28gZG8gcGVyw61vZG8gICAgIA0KPC9kaXY+DQoNCjxicj4NClRyw6pzIGNvbmp1bnRvcyBkZSBkYWRvcyBkbyBzZXRvciBkZSBzYcO6ZGUgc3VwbGVtZW50YXIgZm9yYW0gdXRpbGl6YWRvcyBwYXJhIGV4dHJhaXIgaW5mb3JtYcOnw7VlcyBkZSAqKmRlc3Blc2EgYXNzaXN0ZW5jaWFsKiosICoqcXVhbnRpZGFkZSBkZSBiZW5lZmljacOhcmlvcyBjb20gdsOtbmN1bG9zIGF0aXZvcyoqIGUgKipjYXJhY3RlcsOtc3RpY2FzIGRhcyBvcGVyYWRvcmFzIGRlIHBsYW5vcyBkZSBzYcO6ZGUqKi4gRXNzZXMgY29uanVudG9zIGRlIGRhZG9zIHBvZGVtIHNlciBhY2Vzc2FkYXMgcGVsbyBbcG9ydGFsIGRlIGRhZG9zIGFiZXJ0b3MgZGEgQWfDqm5jaWEgTmFjaW9uYWwgZGUgU2HDumRlIFN1cGxlbWVudGFyIChBTlMpXShodHRwczovL2RhZG9zLmdvdi5ici9vcmdhbml6YXRpb24vYWdlbmNpYS1uYWNpb25hbC1kZS1zYXVkZS1zdXBsZW1lbnRhci1hbnM/cGFnZT0xKS4gT3MgbGlua3MgZXNwZWPDrWZpY29zIHBhcmEgY2FkYSBiYXNlIHV0aWxpemFkYSBuZXN0ZSBjw6FsY3VsbyBlc3TDo28gZGlzcG9uw612ZWlzIG5hIHJlc3BlY3RpdmEgc2XDp8OjbyBkZSAqIkxpbXBlemEgZSBUcmF0YW1lbnRvIGRlIERhZG9zIiouICAgICAgIA0KICAgIA0KKioqDQojIyMgU2V0dXANCipEZXNlbnZvbHZpZG8gZW0gUiB2ZXJzw6NvIDQuMC41IGUgUlN0dWRpbyB2ZXJzw6NvIDEuNC4xMTA2Kg0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldCgNCiAgZWNobyA9IFRSVUUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UNCikNCg0Kc2V0d2QoIkM6L1VzZXJzL2NhdGFuLkNBS0VNSVQtTkIyL09uZURyaXZlIC0gQU5TLzAyLiBHRUZBUC9WREEvVkRBIDIwMjAiKQ0KDQpybShsaXN0PWxzKCkpICMgTGltcGEgbyBnbG9iYWwgZW52aXJvbm1lbnQNCg0KbGlicmFyeShSQ29sb3JCcmV3ZXIpDQoNCmBgYA0KDQoNCmBgYHtyIGluaWNpb30NCiMgU2V0dXAgKGJpYmxpb3RlY2FzLCBmdW7Dp8O1ZXMgZSB2YXJpw6F2ZWlzIGdsb2JhaXMpID09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQpsaWJyYXJ5KGRhdGEudGFibGUpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkoZHRwbHlyKQ0KbGlicmFyeShsdWJyaWRhdGUpDQoNCiMgIkRlc2xpZ2EiIG5vdGHDp8OjbyBjaWVudMOtZmljYS4gDQpvcHRpb25zKHNjaXBlbj05OTkpDQoNCiMgZnVuw6fDo28gcGFyYSBleGNsdXPDo28gZGUgdmFsb3JlcyBleHRyZW1vcyBwb3IgYm94cGxvdCAxLjV4SVFSDQp0cmltLmRmIDwtIGZ1bmN0aW9uKGRmLCBtZXRyaWNhKXsNCiAgZGYgJT4lIGZpbHRlcigobWV0cmljYSA+IHF1YW50aWxlKG1ldHJpY2EsIDAuMjUpIC0gMS41ICogSVFSKG1ldHJpY2EpKSANCiAgICAgICAgICAgICAgICAmIChtZXRyaWNhIDwgcXVhbnRpbGUobWV0cmljYSwgMC43NSkgKyAxLjUgKiBJUVIobWV0cmljYSkpKQ0KfQ0KDQojIGZ1bsOnw6NvIHBhcmEgZ2VyYXIgcmVzdW1vIGRlIGVzdGF0w61zdGljYXMgZGVzY3JpdGl2YXMNCnN0YXRzVkRBIDwtIGZ1bmN0aW9uKGRmKXsNCiAgZGYgJT4lIA0KICAgIHN1bW1hcmlzZShuX29wcyA9IG5fZGlzdGluY3QoY2Rfb3BzKSwNCiAgICAgICAgICAgICAgYmVuZWYgPSBzdW0oYmVuZWZtKSwNCiAgICAgICAgICAgICAgbWVkaWFQID0gd2VpZ2h0ZWQubWVhbih2ZGEsIHcgPSBiZW5lZm0pLA0KICAgICAgICAgICAgICBtaW4gPSBtaW4odmRhKSwNCiAgICAgICAgICAgICAgcTEgPSBxdWFudGlsZSh2ZGEsIHAgPSAuMjUsIG5hbWVzID0gRiksDQogICAgICAgICAgICAgIG1lZGlhbiA9IG1lZGlhbih2ZGEpLA0KICAgICAgICAgICAgICBxMyA9IHF1YW50aWxlKHZkYSwgcCA9IC43NSwgbmFtZXMgPSBGKSwNCiAgICAgICAgICAgICAgbWF4ID0gbWF4KHZkYSksDQogICAgICAgICAgICAgIGRwID0gc2QodmRhKSwNCiAgICAgICAgICAgICAgbWVkaWEgPSBtZWFuKHZkYSksDQogICAgICAgICAgICAgIC5ncm91cHMgPSAnZHJvcCcpICU+JQ0KICAgIG11dGF0ZShhY3Jvc3MoIGMobWVkaWFQOm1lZGlhKSwgfiByb3VuZCgueCwgMikgKSkNCn0NCg0KIyBwZXLDrW9kbyBkZSBhbsOhbGlzZQ0KKHBlcmlvZG8gPC0gYyhtYWtlX2RhdGUoMjAxOSwwMSwwMSksIG1ha2VfZGF0ZSgyMDIwLDEyLDAxKSkpDQpgYGANCg0KDQoqKioNCiMjIExpbXBlemEgZSB0cmF0YW1lbnRvIGRvcyBkYWRvcw0KKioqDQojIyMgRGVzcGVzYSBBc3Npc3RlbmNpYWwNCg0KQXMgaW5mb3JtYcOnw7VlcyBkYXMgZGVzcGVzYXMgaW5jb3JyaWRhcyBuYSBwcmVzdGHDp8OjbyBkZSBhc3Npc3TDqm5jaWEgbcOpZGljby1ob3NwaXRhbGFyIHPDo28gZXh0cmHDrWRhcyBkYXMgRGVtb25zdHJhw6fDtWVzIENvbnTDoWJlaXMgaW5mb3JtYWRhcyBwZWxhcyBvcGVyYWRvcmFzIG5vIERvY3VtZW50byBkZSBJbmZvcm1hw6fDtWVzIFBlcmnDs2RpY2FzIGRhcyBPcGVyYWRvcmFzIGRlIFBsYW5vcyBkZSBBc3Npc3TDqm5jaWEgw6AgU2HDumRlIChESU9QUykuICBBIGRhdGEgbGltaXRlIGRlIGVudmlvIGRhcyBpbmZvcm1hw6fDtWVzIGRvIDTCuiB0cmltZXN0cmUgYW8gRElPUFMgw6kgbyBkaWEgMzEgZGUgbWFyw6dvIGRvIGFubyBzdWJzZXF1ZW50ZS4gDQoNClRvZGFzIGFzIGRlbW9uc3RyYcOnw7VlcyBmaW5hbmNlaXJhcyBwdWJsaWNhZGFzIHNlZ3VlbSBvcyBjcml0w6lyaW9zIGRvIFBsYW5vIGRlIENvbnRhcyBQYWRyw6NvIGRhIEFOUyBwYXJhIGFzIG9wZXJhZG9yYXMgZGUgcGxhbm9zIGRlIHNhw7pkZSwgY29uZm9ybWUgZXN0YWJlbGVjaWRvIHBlbGEgW1JOIG7CuiA0MzUsIGRlIDIzIGRlIG5vdmVtYnJvIGRlIDIwMThdKGh0dHA6Ly93d3cuYW5zLmdvdi5ici9jb21wb25lbnQvbGVnaXNsYWNhby8/dmlldz1sZWdpc2xhY2FvJnRhc2s9VGV4dG9MZWkmZm9ybWF0PXJhdyZpZD1NelkwTWc9PSkuIA0KDQpBIGJhc2UgZGUgZGFkb3MgZG8gRElPUFMgcmVmZXJlbnRlIGFvIDTCuiB0cmltZXN0cmUgZGUgMjAyMCBwb2RlIHNlciBhY2Vzc2FkYSBubyBbUG9ydGFsIGRlIERhZG9zIEFiZXJ0b3MgZGEgQU5TIC0gRGVtb25zdHJhw6fDtWVzIENvbnTDoWJlaXNdKGh0dHBzOi8vZGFkb3MuZ292LmJyL2RhdGFzZXQvaHR0cC13d3ctYW5zLWdvdi1ici1wZXJmaWwtZG8tc2V0b3ItZGFkb3MtYWJlcnRvcy1kYWRvcy1hYmVydG9zLWRpc3Bvbml2ZWlzLW4zKS4gRXNzZSBjb25qdW50byBkZSBkYWRvcyBkZXRhbGhhIG8gc2FsZG8gYWN1bXVsYWRvIGVtIHJlYWlzIGFvIGZpbmFsIGRlIGNhZGEgdHJpbWVzdHJlIG5hcyBjb250YXMgY29udMOhYmVpcyBkZSBjYWRhIG9wZXJhZG9yYSAoaW5jbHVpbmRvIGNvbnRhcyBkZSBiYWxhbsOnbyBlIGRlbW9uc3RyYcOnw7VlcyBkZSByZXN1bHRhZG8pLiAgICANCg0KQSBiYXNlIHJlZmVyZW50ZSBhbyA0wrogdHJpbWVzdHJlIGRlIDIwMTkgZGlzcG9uw612ZWwgbm8gUG9ydGFsIGRlIERhZG9zIEFiZXJ0b3MgZm9pIHB1YmxpY2FkYSBlbSBhYnJpbCBkZSAyMDIwLiBBc3NpbSwgZmF6LXNlIG5lY2Vzc8OhcmlvIGNvbnN1bHRhciB1bWEgdmVyc8OjbyBhdHVhbGl6YWRhIGRvcyBkYWRvcyBkbyA0wrogdHJpbWVzdHJlIGRlIDIwMTkgcXVlIGNvbnRlbXBsZSBhcyByZXRpZmljYcOnw7VlcyBmZWl0YXMgcGVsYXMgb3BlcmFkb3JhcyBkZXNkZSBlbnTDo28uIEEgYmFzZSBkZSBEZW1vbnN0cmHDp8O1ZXMgQ29udMOhYmVpcyByZWZlcmVudGVzIGEgMjAxOSBhdHVhbGl6YWRhIGVtIDE2LzA0LzIwMjEgcG9kZSBzZXIgYWNlc3NhZGEgbm8gc2l0ZSBkYSBBTlMgZW0gW0VzcGHDp28gZG8gQ29uc3VtaWRvciA+IFJlYWp1c3RlID4gSW5kaXZpZHVhbCBvdSBmYW1pbGlhciA+IE1ldG9kb2xvZ2lhIGRlIEPDoWxjdWxvXShodHRwczovL3d3dy5nb3YuYnIvYW5zL3B0LWJyL2Fzc3VudG9zL2NvbnN1bWlkb3IvcmVhanVzdGUtdmFyaWFjYW8tZGUtbWVuc2FsaWRhZGUvcmVhanVzdGUtYW51YWwtZGUtcGxhbm9zLWluZGl2aWR1YWlzLWZhbWlsaWFyZXMtMS9tZXRvZG9sb2dpYS1kZS1jYWxjdWxvKS4NCg0KTyBjw7NkaWdvIGEgc2VndWlyIGZheiBhIGxlaXR1cmEgZG9zIGFycXVpdm9zICouY3N2Og0KDQpgYGB7ciBkZXNwZXNhMCwgZWNobz1UUlVFLCBwYWdlZC5wcmludD1UUlVFfQ0KIyBMb2FkIGRhdGFzZXQganVudGFuZG8gdsOhcmlvcyBhcnF1aXZvcyBhIHBhcnRpciBkZSB1bWEgcGFzdGEgPT09PT09PT09PT09PT09PT09DQpmaWxlcyA8LSBsaXN0LmZpbGVzKHBhdGggPSAiLi9kYXRhc2V0cy9kaW9wcy8iLCBwYXR0ZXJuID0gIiouY3N2IiwgZnVsbC5uYW1lcyA9IFQpDQpkaW9wcyA8LSByYmluZGxpc3QobGFwcGx5KGZpbGVzLCBmcmVhZCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgIGRlYz0iLCIsIGRyb3A9J0RFU0NSSUNBTycsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xDbGFzc2VzID0gYyhDRF9DT05UQV9DT05UQUJJTD0iY2hhcmFjdGVyIikpKSAlPiUgDQogIGxhenlfZHQoKSAlPiUNCiAgcmVuYW1lX3dpdGgodG9sb3dlcikgJT4lIA0KICBmaWx0ZXIoDQogICAgbmNoYXIoY2RfY29udGFfY29udGFiaWwpID09IDksICMgZmlsdHJhIGNvbnRhcyBjb250w6FiZWlzIGRlIDkgZMOtZ2l0b3MNCiAgICB2bF9zYWxkb19maW5hbCAhPSAwICAgICAgICAgICAgIyBleGNsdWkgbGluaGFzIHNlbSBzYWxkbw0KICApICU+JSANCiAgbXV0YXRlKGlkX2NhbGVuZGFyID0gZG15KGRhdGEpICsgbW9udGhzKDIpKSAlPiUgIyBhbHRlcmEgcGFyYSDDumx0aW1vIG3DqnMgZG8gdHJpbWVzdHJlDQogIHJlbmFtZShjZF9vcHMgPSByZWdfYW5zKSAlPiUgDQogIHNlbGVjdChjZF9vcHMsIGNkX2NvbnRhX2NvbnRhYmlsLCBpZF9jYWxlbmRhciwgdmxfc2FsZG9fZmluYWwpICU+JSANCiAgYXNfdGliYmxlKCkNCg0KcmVtb3ZlKGZpbGVzKQ0KYGBgDQoNCjxicj4NCk8gYWx2byBkYSBhbsOhbGlzZSDDqSBhIGRlc3Blc2EgYXNzaXN0ZW5jaWFsIGluY29ycmlkYSBwZWxhIG9wZXJhZG9yYSBlbSBjYXJ0ZWlyYSBwcsOzcHJpYS4gT3MgdmFsb3JlcyBkZSBEZXNwZXNhIEFzc2lzdGVuY2lhbCBlbSBDYXJ0ZWlyYSBQcsOzcHJpYSBjb3JyZXNwb25kZW0gw6AgdG90YWxpemHDp8OjbyBkb3Mgc2FsZG9zIGRvcyBzZWd1aW50ZXMgZ3J1cG9zIGRlIGNvbnRhcyBjb250w6FiZWlzIGRvIFBsYW5vIGRlIENvbnRhcyBQYWRyw6NvIGRhIEFOUyBwYXJhIGFzIG9wZXJhZG9yYXMgZGUgcGxhbm9zIGRlIHNhw7pkZSwgY29uZm9ybWUgZXN0YWJlbGVjaWRvIHBlbGEgW1JOIG7CuiA0MzUsIGRlIDIzIGRlIG5vdmVtYnJvIGRlIDIwMThdKGh0dHA6Ly93d3cuYW5zLmdvdi5ici9jb21wb25lbnQvbGVnaXNsYWNhby8/dmlldz1sZWdpc2xhY2FvJnRhc2s9VGV4dG9MZWkmZm9ybWF0PXJhdyZpZD1NelkwTWc9PSk6DQoNCg0KfCBDb250YSBjb250w6FiaWwgfCBEZXNjcmnDp8OjbyB8IFRvdGFsaXphw6fDo28gfA0KfDotLS0tLS18Oi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tfDotLS0tLS06fA0KfCA0MTFYMSB8IEV2ZW50b3MvIFNpbmlzdHJvcyBDb25oZWNpZG9zIG91IEF2aXNhZG9zIGRlIEFzc2lzdMOqbmNpYSBhIFNhw7pkZSBNZWRpY28gSG9zcGl0YWxhciB8ICgrKSB8DQp8IDQxMVgxWFg4IHwgQ29ycmVzcG9uc2FiaWxpZGFkZSBBc3N1bWlkYSB8ICgtKSB8DQp8IDMxMTcxIHwgKC0pIENvbnRyYXByZXN0YcOnw7VlcyBkZSBDb3JyZXNwb25zYWJpbGlkYWRlIENlZGlkYSBkZSBBc3Npc3TDqm5jaWEgTcOpZGljby1Ib3NwaXRhbGFyIHwgKC0pIHwNCg0KDQpEZXNzYSBmb3JtYSwgbyB2YWxvciBkYSBkZXNwZXNhIGFzc2lzdGVuY2lhbCBlbSBjYXJ0ZWlyYSBwcsOzcHJpYSBpbmNsdWkgdmFsb3JlcyBkZSBFdmVudG9zLyBTaW5pc3Ryb3MgY29uaGVjaWRvcyBvdSBhdmlzYWRvcyBlIHZhbG9yZXMgZGUgZ2FzdG9zIGRlIGNvcnJlc3BvbnNhYmlsaWRhZGUgZGUgY2FydGVpcmEgcHLDs3ByaWEgKmNlZGlkYSogYSB0ZXJjZWlyb3MgKGNvbnRhcyBjb250w6FiZWlzIHJlZHV0b3JhcyBkZSByZWNlaXRhIDMxMTcxKS4gVmFsb3JlcyBkZSBjb3JyZXNwb25zYWJpbGlkYWRlICphc3N1bWlkYSogc8OjbyBkZXNjb25zaWRlcmFkb3MsIHBvaXMgcmVmZXJlbS1zZSBhIGRlc3Blc2FzIGFzc2lzdGVuY2lhaXMgaW5jb3JyaWRhcyBlbSBhdGVuZGltZW50byBhIGNhcnRlaXJhIGRlIHRlcmNlaXJvcyAob3V0cmFzIG9wZXJhZG9yYXMpLiAgICAgICAgICANCg0KDQpPIGPDs2RpZ28gYSBzZWd1aXIgdG90YWxpemEgYSBkZXNwZXNhIGFzc2lzdGVuY2lhbCBwb3IgdHJpbWVzdHJlLCBvcGVyYWRvcmEgZSB0aXBvIGRlIGNhcnRlaXJhOiANCg0KYGBge3IgZGVzcGVzYTF9DQojIHNlbGVjaW9uYSBhcyBjb250YXMgY29udMOhYmVpcyByZWxldmFudGVzIChkZXNwZXNhIGUgcmVjZWl0YSkgPT09PT09PT09PT09PT09PT0NCmRpb3BzIDwtIGRpb3BzICU+JSANCiAgZmlsdGVyKCAjIGZpbHRyYSBjb250YXMgY29udMOhYmVpcyByZWxldmFudGVzIHBhcmEgYSBhbsOhbGlzZQ0KICAgICMgZGVzcGVzYSAvIGNvcnJlc3BvbnNhYmlsaWRhZGUgYXNzdW1pZGEgbcOpZGljby1ob3NwaXRhbGFyDQogICAgKHN1YnN0cihjZF9jb250YV9jb250YWJpbCwgMSwgMykgPT0gJzQxMScgJiBzdWJzdHIoY2RfY29udGFfY29udGFiaWwsIDUsIDUpID09ICcxJykNCiAgICAjIHJlY2VpdGEgLyBjb3JyZXNwb25zYWJpbGlkYWRlIGNlZGlkYSBtw6lkaWNvLWhvc3BpdGFsYXINCiAgICB8IChzdWJzdHIoY2RfY29udGFfY29udGFiaWwsIDEsIDUpID09ICczMTExMScgfCBzdWJzdHIoY2RfY29udGFfY29udGFiaWwsIDEsIDUpID09ICczMTE3MScpDQogICkgJT4lIA0KICBtdXRhdGUoDQogICAgZ3JfY2MgPSBjYXNlX3doZW4oDQogICAgICBzdWJzdHIoY2RfY29udGFfY29udGFiaWwsIDEsIDEpID09ICc0JyB+ICdldmVudG9zJywNCiAgICAgIHN1YnN0cihjZF9jb250YV9jb250YWJpbCwgMSwgNSkgPT0gJzMxMTExJyB+ICdyZWNlaXRhJywgDQogICAgICBzdWJzdHIoY2RfY29udGFfY29udGFiaWwsIDEsIDUpID09ICczMTE3MScgfiAnY29ycl9jZWRpZGEnLCAjIHJlZHV0b3JhIGRlIHJlY2VpdGENCiAgICAgIFRSVUUgfiAnRVhDTFVJUicpLCANCiAgKSAlPiUNCiAgZ3JvdXBfYnkoY2Rfb3BzLCBjZF9jb250YV9jb250YWJpbCwgaWRfY2FsZW5kYXIsIGdyX2NjKSAlPiUgDQogIHN1bW1hcmlzZSh2bF9zYWxkb19maW5hbCA9IHN1bSh2bF9zYWxkb19maW5hbCksIA0KICAgICAgICAgICAgLmdyb3VwcyA9ICdkcm9wJykgJT4lICANCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IGdyX2NjLCB2YWx1ZXNfZnJvbSA9IHZsX3NhbGRvX2ZpbmFsLCB2YWx1ZXNfZmlsbCA9IDApICU+JSANCiAgIyBpZGVudGlmaWNhIHRpcG9zIGRlIHBsYW5vIHBlbGEgY29udGEgY29udMOhYmlsDQogIG11dGF0ZSgNCiAgICB2aWdlbmNpYSA9IGNhc2Vfd2hlbigNCiAgICAgIHN1YnN0cihjZF9jb250YV9jb250YWJpbCwgOCwgOCkgPT0gJzgnIH4gJ2NvcnJfYXNzdW1pZGEnLCANCiAgICAgIHN1YnN0cihjZF9jb250YV9jb250YWJpbCwgOCwgOCkgJWluJSBjKCcxJywnMycsJzUnKSB+ICdBJywNCiAgICAgIHN1YnN0cihjZF9jb250YV9jb250YWJpbCwgOCwgOCkgJWluJSBjKCcyJywnNCcsJzYnKSB+ICdQJywNCiAgICAgIFRSVUUgfiAnRVhDTFVJUicpLCANCiAgICBjb250cmF0YWNhbyA9IGNhc2Vfd2hlbigNCiAgICAgIHN1YnN0cihjZF9jb250YV9jb250YWJpbCwgOCwgOCkgPT0gJzgnIH4gJ2NvcnJfYXNzdW1pZGEnLCANCiAgICAgIHN1YnN0cihjZF9jb250YV9jb250YWJpbCwgOCwgOCkgJWluJSBjKCcxJywnMicpIH4gJ0luZGl2aWR1YWwnLA0KICAgICAgc3Vic3RyKGNkX2NvbnRhX2NvbnRhYmlsLCA4LCA4KSAlaW4lIGMoJzMnLCc0JykgfiAnQWRlc8OjbycsDQogICAgICBzdWJzdHIoY2RfY29udGFfY29udGFiaWwsIDgsIDgpICVpbiUgYygnNScsJzYnKSB+ICdFbXByZXNhcmlhbCcsDQogICAgICBUUlVFIH4gJ0VYQ0xVSVInKSwgDQogICAgZmluYW5jaWFtZW50byA9IGNhc2Vfd2hlbigNCiAgICAgIHN1YnN0cihjZF9jb250YV9jb250YWJpbCwgOCwgOCkgPT0gJzgnIH4gJ2NvcnJfYXNzdW1pZGEnLCANCiAgICAgIHN1YnN0cihjZF9jb250YV9jb250YWJpbCwgNiwgNikgPT0gJzEnIH4gJ1ByZS1lc3RhYmVsZWNpZG8nLA0KICAgICAgc3Vic3RyKGNkX2NvbnRhX2NvbnRhYmlsLCA2LCA2KSA9PSAnMicgfiAnUMOzcy1lc3RhYmVsZWNpZG8nLA0KICAgICAgVFJVRSB+ICdFWENMVUlSJyksIA0KICApICU+JSANCiAgZmlsdGVyKHZpZ2VuY2lhICE9ICdjb3JyX2Fzc3VtaWRhJykgJT4lICAgICAjIGV4Y2x1aSBjb3JyIGFzc3VtaWRhDQogIG11dGF0ZShkZXNwZXNhID0gZXZlbnRvcyAtIGNvcnJfY2VkaWRhLA0KICAgICAgICAgY29udHJhdGFjYW8gPSBhcy5mYWN0b3IoY29udHJhdGFjYW8pKSAlPiUgIyBpbmNsdWkgY29yciBjZWRpZGEgbmEgZGVzcGVzYQ0KICBncm91cF9ieShjZF9vcHMsIHZpZ2VuY2lhLCBjb250cmF0YWNhbywgZmluYW5jaWFtZW50bywgaWRfY2FsZW5kYXIpICU+JSANCiAgc3VtbWFyaXNlKHJlY2VpdGEgPSBzdW0ocmVjZWl0YSksIA0KICAgICAgICAgICAgZGVzcGVzYSA9IHN1bShkZXNwZXNhKSwgDQogICAgICAgICAgICAuZ3JvdXBzID0gJ2Ryb3AnKQ0KICANCg0KZGlvcHMgJT4lIGdyb3VwX2J5KGFubz0geWVhcihpZF9jYWxlbmRhcikpICU+JSANCiAgc3VtbWFyaXNlKA0KICAgIHJlY2VpdGEgPSByb3VuZChzdW0ocmVjZWl0YSwgbmEucm0gPSBUKS8xMDAwMDAwMDAwLCAxKSwgIyBlbSBSJCBiaWxow7Vlcw0KICAgIGRlc3Blc2EgPSByb3VuZChzdW0oZGVzcGVzYSwgbmEucm0gPSBUKS8xMDAwMDAwMDAwLCAxKSwgIyBlbSBSJCBiaWxow7Vlcw0KICAgIG5fb3BzID0gbl9kaXN0aW5jdChjZF9vcHMpLCANCiAgICAuZ3JvdXBzID0gJ2Ryb3AnDQogICkgJT4lIA0KICBtdXRhdGUocGN0X2Rlc3Blc2EgPSByb3VuZChkZXNwZXNhL3JlY2VpdGEqMTAwLDIpKQ0KYGBgDQoNCjxicj4NCkZpbHRyYSBzZWdtZW50b3MgYWx2byBkYSBhbsOhbGlzZSBlIHRvdGFsaXphIHBvciB0cmltZXN0cmUsIG9wZXJhZG9yYSBlIHRpcG8gZGUgcGxhbm86DQoNCmBgYHtyIGRlc3Blc2EyfQ0KZGlvcHMgPC0gZGlvcHMgJT4lIA0KICBmaWx0ZXIoICMgZmlsdHJhIHRpcG9zIGRlIHBsYW5vIHJlbGV2YW50ZXMgcGFyYSBhIGFuw6FsaXNlDQogICAgdmlnZW5jaWEgPT0gJ1AnLCAjIHBsYW5vcyBub3Zvcw0KICAgIGZpbmFuY2lhbWVudG8gPT0gJ1ByZS1lc3RhYmVsZWNpZG8nLCAjIGZpbmFuY2lhbWVudG8gcHJlLWVzdGFiZWxlY2lkbw0KICApICU+JSANCiAgc2VsZWN0KC12aWdlbmNpYSwgLWZpbmFuY2lhbWVudG8pDQoNCmRpb3BzICU+JSBncm91cF9ieShjb250cmF0YWNhbywgYW5vPSB5ZWFyKGlkX2NhbGVuZGFyKSkgJT4lIA0KICBzdW1tYXJpc2UoDQogICAgcmVjZWl0YSA9IHJvdW5kKHN1bShyZWNlaXRhLCBuYS5ybSA9IFQpLzEwMDAwMDAwMDAsIDEpLCAjIGVtIFIkIGJpbGjDtWVzDQogICAgZGVzcGVzYSA9IHJvdW5kKHN1bShkZXNwZXNhLCBuYS5ybSA9IFQpLzEwMDAwMDAwMDAsIDEpLCAjIGVtIFIkIGJpbGjDtWVzDQogICAgbl9vcHMgPSBuX2Rpc3RpbmN0KGNkX29wcyksDQogICAgLmdyb3VwcyA9ICdkcm9wJykgJT4lIA0KICBtdXRhdGUocGN0X2Rlc3Blc2EgPSByb3VuZChkZXNwZXNhL3JlY2VpdGEqMTAwLDIpKQ0KYGBgDQoNCioqKg0KDQojIyMgQmVuZWZpY2nDoXJpb3MgKHNlbWktYWRpdGl2bykNCg0KQXMgaW5mb3JtYcOnw7VlcyBkZSB2w61uY3Vsb3MgYXRpdm9zIGRlIGJlbmVmaWNpw6FyaW9zIHPDo28gb2J0aWRhcyBhdHJhdsOpcyBkYSBiYXNlIGRvIFNpc3RlbWEgZGUgSW5mb3JtYcOnw6NvIGRlIEJlbmVmaWNpw6FyaW9zIChTSUIpLCBxdWUgw6kgYXR1YWxpemFkbyBtZW5zYWxtZW50ZS4gQSB2ZXJzw6NvIHV0aWxpemFkYSBub3MgY8OhbGN1bG9zIGRhIFZEQSAyMDIwLzIwMTkgw6kgYSB2ZXJzw6NvIGF0dWFsaXphZGEgYXTDqSBtYXLDp28gZGUgMjAyMS4gICAgICAgICAgIA0KDQpBIGJhc2UgZGUgZGFkb3MgZG8gU0lCIHJlZmVyZW50ZSBhb3MgYW5vcyBkZSAyMDE5IGUgMjAyMCBwb2RlIHNlciBhY2Vzc2FkYSBubyBbUG9ydGFsIGRlIERhZG9zIEFiZXJ0b3MgZGEgQU5TIC0gIEJlbmVmaWNpw6FyaW9zIHBvciBvcGVyYWRvcmEgZSB0aXBvIGRlIGNhcnRlaXJhIHBhcmEgY8OhbGN1bG8gZGEgVkRBXShodHRwczovL2RhZG9zLmdvdi5ici9kYXRhc2V0L2JlbmVmaWNpYXJpb3MtY29tLXZpbmN1bG9zLWF0aXZvcy1wb3ItdGlwby1kZS1jb250cmF0YWNhby1wYXJhLWNhbGN1bG8tZGEtdmRhKSBubyBzaXRlIGRhIEFOUy4gRXNzZSBjb25qdW50byBkZSBkYWRvcyBpbmZvcm1hIGEgcXVhbnRpZGFkZSBkZSB2w61uY3Vsb3MgYXRpdm9zIGRlIGJlbmVmaWNpw6FyaW9zIGVtIHBsYW5vcyBkZSBzYcO6ZGUgbcOpZGljby1ob3NwaXRhbGFyIG3DqnMgYSBtw6pzIHBvciBvcGVyYWRvcmEgZSB0aXBvIGRlIHBsYW5vLiAgICAgICANCg0KTyBjw7NkaWdvIGEgc2VndWlyIGZheiBhIGxlaXR1cmEgZG9zIGFycXVpdm9zICouY3N2Og0KDQpgYGB7ciBiZW5lZjAsIGVjaG89VFJVRSwgcGFnZWQucHJpbnQ9VFJVRX0NCiMgTG9hZCBkYXRhc2V0DQpzaWIgPC0gZnJlYWQoIi4vZGF0YXNldHMvQmVuZWZpY2lhcmlvc19vcGVyYWRvcmFfZV9jYXJ0ZWlyYS5jc3YiKSAlPiUNCiAgbGF6eV9kdCgpICU+JQ0KICByZW5hbWVfd2l0aCh0b2xvd2VyKSAlPiUgDQogIG11dGF0ZSgNCiAgICBpZF9jYWxlbmRhciA9IG1ha2VfZGF0ZShhcy5pbnRlZ2VyKG1lcyAvIDEwMCksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1lcyAtIGFzLmludGVnZXIobWVzIC8gMTAwKSAqIDEwMCwgMSksDQogICAgbW9kYWxpZGFkZSA9IGFzLmZhY3Rvcihncl9tb2RhbGlkYWRlKSwNCiAgICB2aWdlbmNpYSA9IGFzLmZhY3Rvcih2aWdlbmNpYV9wbGFubyksDQogICAgY29udHJhdGFjYW8gPSBhcy5mYWN0b3IoZ3JfY29udHJhdGFjYW8pLA0KICAgIGZpbmFuY2lhbWVudG8gPSBhcy5mYWN0b3IodGlwb19maW5hbmNpYW1lbnRvKSwNCiAgKSAlPiUNCiAgZmlsdGVyKA0KICAgIGlkX2NhbGVuZGFyID49IHBlcmlvZG9bMV0sIGlkX2NhbGVuZGFyIDw9IHBlcmlvZG9bMl0sICAjIHBlcsOtb2RvIGRlIGFuw6FsaXNlDQogICAgbnJfYmVuZWYgIT0gMCwgIWlzLm5hKG5yX2JlbmVmKSAgICMgZXhjbHVpIHplcm9zIGUgbnVsb3MNCiAgKSAlPiUgDQogIHJlbmFtZSggY2Rfb3BzID0gY2Rfb3BlcmFkb3JhLCBiZW5lZiA9IG5yX2JlbmVmICkgJT4lIA0KICBtdXRhdGUoDQogICAgY29udHJhdGFjYW8gPSBjYXNlX3doZW4oDQogICAgICBjb250cmF0YWNhbyA9PSAnQ29sZXRpdm8gZW1wcmVzYXJpYWwnIH4gJ0VtcHJlc2FyaWFsJywNCiAgICAgIGNvbnRyYXRhY2FvID09ICdDb2xldGl2byBwb3IgYWRlc8OjbycgfiAnQWRlc8OjbycsDQogICAgICBjb250cmF0YWNhbyA9PSAnSW5kaXZpZHVhbCBvdSBmYW1pbGlhcicgfiAnSW5kaXZpZHVhbCcsDQogICAgICBUUlVFIH4gJ07Do28gaWRlbnRpZmljYWRvJykNCiAgKSAlPiUgDQogIHNlbGVjdChjZF9vcHMsIG1vZGFsaWRhZGUsIA0KICAgICAgICAgdmlnZW5jaWEsIGNvbnRyYXRhY2FvLCBmaW5hbmNpYW1lbnRvLCANCiAgICAgICAgIGlkX2NhbGVuZGFyLCBiZW5lZikgJT4lIA0KICBhc190aWJibGUoKQ0KDQojIHNlZ21lbnRhIHBvcnRlIGRhIG9wZXJhZG9yYSBwZWxhIHF1YW50aWRhZGUgZGUgYmVuZWZpY2nDoXJpb3MgbcOpZGljby1ob3NwaXRhbGFyZXMNCm9wcyA8LSBzaWIgJT4lIA0KICBmaWx0ZXIoaWRfY2FsZW5kYXIgPT0gcGVyaW9kb1syXSkgJT4lIA0KICBncm91cF9ieShjZF9vcHMpICU+JSANCiAgc3VtbWFyaXNlKGJlbmVmID0gc3VtKGJlbmVmKSkgJT4lIA0KICBtdXRhdGUoDQogICAgcG9ydGVfb3BzID0gY2FzZV93aGVuKA0KICAgICAgYmVuZWYgPiAxMDAwMDAgfiAnR3JhbmRlJywNCiAgICAgIGJlbmVmID49IDIwMDAwIH4gJ03DqWRpbycsDQogICAgICBUUlVFIH4gJ1BlcXVlbm8nICkNCiAgKQ0KDQpzaWIgJT4lIGdyb3VwX2J5KGFubyA9IHllYXIoaWRfY2FsZW5kYXIpKSAlPiUgDQogIHN1bW1hcmlzZShiZW5lZl9tZWRpYV9hZ3JlZ2FkYSA9IHJvdW5kKHN1bShiZW5lZikvMTIsMCksDQogICAgICAgICAgICBuX29wcyA9IG5fZGlzdGluY3QoY2Rfb3BzKSwNCiAgICAgICAgICAgIC5ncm91cHMgPSAnZHJvcCcpIA0KYGBgDQoNCjxicj4NCkZpbHRyYSBzZWdtZW50b3MgYWx2byBkYSBhbsOhbGlzZSBlIHRvdGFsaXphIHBvciBtw6pzLCBvcGVyYWRvcmEgZSB0aXBvIGRlIHBsYW5vLg0KDQpgYGB7ciBiZW5lZjF9DQpzaWIgPC0gc2liICU+JSANCiAgZmlsdGVyKA0KICAgICMgb3BlcmFkb3JhcyBtw6lkaWNvLWhvc3BpdGFsYXJlcw0KICAgIG1vZGFsaWRhZGUgJWluJSBjKCdBdXRvZ2VzdMOjbycsICdDb29wZXJhdGl2YSBNw6lkaWNhJywgJ0ZpbGFudHJvcGlhJywNCiAgICAgICAgICAgICAgICAgICAgICAnTWVkaWNpbmEgZGUgR3J1cG8nLCdTZWd1cmFkb3JhJyksDQogICAgdmlnZW5jaWEgPT0gJ1AnLCAjIHBsYW5vcyBub3Zvcw0KICAgIGZpbmFuY2lhbWVudG8gIT0gJ1DDs3MtZXN0YWJlbGVjaWRvJywgIyBmaW5hbmNpYW1lbnRvIHByZS1lc3RhYmVsZWNpZG8NCiAgICBjb250cmF0YWNhbyAlaW4lIGMoJ0VtcHJlc2FyaWFsJywgJ0luZGl2aWR1YWwnLCAnQWRlc8OjbycpKSAlPiUgDQogIGdyb3VwX2J5KGNkX29wcywgY29udHJhdGFjYW8sIGlkX2NhbGVuZGFyKSAlPiUgDQogIHN1bW1hcmlzZShiZW5lZiA9IHN1bShiZW5lZiksIC5ncm91cHMgPSAnZHJvcCcpIA0KDQpzaWIgJT4lIGdyb3VwX2J5KGNvbnRyYXRhY2FvLCBhbm8gPSB5ZWFyKGlkX2NhbGVuZGFyKSkgJT4lIA0KICBzdW1tYXJpc2UoYmVuZWZfbWVkaWFfYWdyZWdhZGEgPSByb3VuZChzdW0oYmVuZWYpLzEyLDApLA0KICAgICAgICAgICAgbl9vcHMgPSBuX2Rpc3RpbmN0KGNkX29wcyksDQogICAgICAgICAgICAuZ3JvdXBzID0gJ2Ryb3AnKSANCmBgYA0KDQo8YnI+DQpDYWxjdWxhIG3DqWRpYSBkZSBiZW5lZmljacOhcmlvcyBhY3VtdWxhZGEgbm8gYW5vIHBvciBvcGVyYWRvcmEgZSB0aXBvIGRlIGNvbnRyYXRhw6fDo286DQoNCmBgYHtyIGJlbmVmMn0NCnNpYiA8LSBzaWIgJT4lIA0KICBhcnJhbmdlKGNkX29wcywgY29udHJhdGFjYW8sIGlkX2NhbGVuZGFyKSAlPiUgDQogICMgY3JpYSBjb2x1bmEgZG8gYW5vDQogIG11dGF0ZShpZF9jYWxlbmRhciA9IHltZChpZF9jYWxlbmRhciksIA0KICAgICAgICAgYW5vID0gYXMuaW50ZWdlcih5ZWFyKGlkX2NhbGVuZGFyKSkpICU+JSANCiAgIyBjYWxjdWxhIGEgbcOpZGlhIHBvciBvcGVyYWRvcmEsIGNvbnRyYXRhY2FvIGUgYW5vDQogIGdyb3VwX2J5KGNkX29wcywgY29udHJhdGFjYW8sIGFubykgJT4lIA0KICBtdXRhdGUoDQogICAgYmVuZWZtID0gY3VtbWVhbihiZW5lZiksICAgICAgICAjIG3DqWRpYSBhY3VtdWxhZGEgbm8gYW5vDQogICAgbl9tZXNlcyA9IGxlbmd0aChiZW5lZiksICAgICAgICAgICAgICAgICAjIHF0ZCBkZSBtZXNlcyBjb20gYmVuZWZpY2nDoXJpb3MNCiAgICBtZXMgPSBhcy5pbnRlZ2VyKG1vbnRoKGlkX2NhbGVuZGFyKSksDQogICAgY29udHJhdGFjYW8gPSBhcy5mYWN0b3IoY29udHJhdGFjYW8pLA0KICApICU+JSANCiAgdW5ncm91cCgpICU+JSANCiAgZmlsdGVyKG1lcyAlaW4lIGMoMTIpKSAlPiUgIyBzZWxlY2lvbmEgbyhzKSBwZXLDrW9kbyhzKSBhbHZvIGRhIGFuw6FsaXNlDQogIHNlbGVjdCgtYmVuZWYsIC1hbm8sIC1tZXMpIA0KDQpzaWIgJT4lIGdyb3VwX2J5KGNvbnRyYXRhY2FvLCBhbm8gPSB5ZWFyKGlkX2NhbGVuZGFyKSkgJT4lIA0KICBzdW1tYXJpc2UoYmVuZWZtID0gcm91bmQoc3VtKGJlbmVmbSksMCksICMgc29tYSBkYXMgbcOpZGlhcw0KICAgICAgICAgICAgbl9vcHMgPSBuX2Rpc3RpbmN0KGNkX29wcyksDQogICAgICAgICAgICAuZ3JvdXBzID0gJ2Ryb3AnKQ0KYGBgDQoNCioqKg0KIyMjIE9wZXJhZG9yYXMNCg0KQXMgY2FyYWN0ZXLDrXN0aWNhcyBkYXMgb3BlcmFkb3JhcyBzw6NvIG9idGlkYXMgZG8gU2lzdGVtYSBkZSBDYWRhc3RybyBkZSBPcGVyYWRvcmFzIChDQURPUCkuICAgICAgIA0KDQpEb2lzIGNvbmp1bnRvcyBkZSBkYWRvcyBlc3TDo28gZGlzcG9uw612ZWlzIG5vIFBvcnRhbCBkZSBEYWRvcyBBYmVydG9zIGRhIEFOUzogQ2FkYXN0cm8gZGFzICBbT3BlcmFkb3JhcyBkZSBwbGFub3MgZGUgc2HDumRlIEF0aXZhc10oaHR0cHM6Ly9kYWRvcy5nb3YuYnIvZGF0YXNldC9vcGVyYWRvcmFzLWRlLXBsYW5vcy1wcml2YWRvcy1kZS1zYXVkZSkgZSBkYXMgW09wZXJhZG9yYXMgZGUgcGxhbm9zIGRlIHNhw7pkZSBDYW5jZWxhZGFzXShodHRwczovL2RhZG9zLmdvdi5ici9kYXRhc2V0L29wZXJhZG9yYXMtZGUtcGxhbm9zLWRlLXNhdWRlLWNvbS1yZWdpc3Ryby1jYW5jZWxhZG8pLiBFc3NlcyBjb25qdW50b3MgZGUgZGFkb3MgaW5jbHVlbSBjYXJhY3RlcsOtc3RpY2FzIGNvbW8gbyByYXrDo28gc29jaWFsLCBtb2RhbGlkYWRlIGRhIG9wZXJhZG9yYSwgYXNzaW0gY29tbyBhcyBkYXRhcyBkZSBpbsOtY2lvIGUgZmltIGRlIG9wZXJhw6fDo28gKHJlc3BlY3RpdmFtZW50ZSBkYXRhIGRvIHJlZ2lzdHJvIGUgZGF0YSBkbyBjYW5jZWxhbWVudG8gZG8gcmVnaXN0cm8pLiAgICAgIA0KDQpPIGPDs2RpZ28gYSBzZWd1aXIgZmF6IGEgbGVpdHVyYSBkb3MgYXJxdWl2b3MgKi5jc3Y6DQoNCmBgYHtyIG9wczAsIGVjaG89VFJVRSwgd2FybmluZz1GQUxTRSwgcGFnZWQucHJpbnQ9VFJVRX0NCiMgTG9hZCBkYXRhc2V0IGp1bnRhbmRvIHbDoXJpb3MgYXJxdWl2b3MgYSBwYXJ0aXIgZGUgdW1hIHBhc3RhDQpmaWxlcyA8LSBsaXN0LmZpbGVzKHBhdGg9Ii4vZGF0YXNldHMvY2Fkb3AvIiwgcGF0dGVybj0iKi5jc3YiLCBmdWxsLm5hbWVzPVQpDQoNCmNhZG9wIDwtIHJiaW5kbGlzdChsYXBwbHkoZmlsZXMsIGZyZWFkKSwgZmlsbD1UKSAlPiUgDQogIGxhenlfZHQoKSAlPiUNCiAgcmVuYW1lX3dpdGgodG9sb3dlcikgJT4lIA0KICBtdXRhdGUoDQogICAgZHRfcmVnaXN0cm8gPSBkbXkoZGF0YV9yZWdpc3Ryb19hbnMpLCANCiAgICBkdF9jYW5jZWxhbWVudG8gPSBkbXkoZGF0YV9kZXNjcmVkZW5jaWFtZW50byksDQogICAgbW9kYWxpZGFkZSA9IGlmZWxzZShtb2RhbGlkYWRlID09ICdTZWd1cmFkb3JhIEVzcGVjaWFsaXphZGEgZW0gU2HDumRlJywNCiAgICAgICAgICAgICAgICAgICAgICAgICdTZWd1cmFkb3JhJywNCiAgICAgICAgICAgICAgICAgICAgICAgIG1vZGFsaWRhZGUpKSAlPiUgDQogIG11dGF0ZShtb2RhbGlkYWRlID0gYXMuZmFjdG9yKG1vZGFsaWRhZGUpKSAlPiUgDQogIHJlbmFtZShjZF9vcHMgPSByZWdpc3Ryb19hbnMpICU+JSANCiAgc2VsZWN0KGNkX29wcywgcmF6YW9fc29jaWFsLCBtb2RhbGlkYWRlLCBkdF9yZWdpc3RybywgZHRfY2FuY2VsYW1lbnRvKSAlPiUNCiAgYXNfdGliYmxlKCkgJT4lIA0KICBsZWZ0X2pvaW4ob3BzLCBieT0nY2Rfb3BzJykgJT4lIA0KICBzZWxlY3QoLWJlbmVmKSAlPiUgDQogIG11dGF0ZShwb3J0ZV9vcHMgPSBhcy5mYWN0b3IoaWZlbHNlKGlzLm5hKHBvcnRlX29wcyksICdQZXF1ZW5vJywgcG9ydGVfb3BzKSkpDQoNCnJlbW92ZShmaWxlcykNCmBgYA0KDQo8YnI+DQpQYXJhIG8gY8OhbGN1bG8gZGEgVkRBIG5vIElSUEkgc2VsZWNpb25hbS1zZSBhcyBvcGVyYWRvcmFzICptw6lkaWNvLWhvc3BpdGFsYXJlcyogZSBzw6NvIGRlc2NvbnNpZGVyYWRhcyAgICAgIA0KDQoxLiBPcGVyYWRvcmFzIHF1ZSBpbmljaWFyYW0gb3BlcmHDp8OjbyBlbnRyZSBqYW5laXJvIGRlIDIwMTkgZSBkZXplbWJybyBkZSAyMDIwLg0KMi4gT3BlcmFkb3JhcyBxdWUgdGl2ZXJhbSByZWdpc3RybyBjYW5jZWxhZG8gYXTDqSBkZXplbWJybyBkZSAyMDIwLg0KMy4gT3BlcmFkb3JhcyBjb20gcmVzc2FsdmFzIG5hcyBkZW1vbnN0cmHDp8O1ZXMgZmluYW5jZWlyYXMgcHJvdG9jb2xhZGFzIGp1bnRvIMOgIEFOUyByZWZlcmVudGVzIGEgMjAxOSBvdSAyMDIwLg0KDQpPIGPDs2RpZ28gYSBzZWd1aXIgZmlsdHJhIG9wZXJhZG9yYXMgbcOpZGljby1ob3NwaXRhbGFyZXMgZSBpZGVudGlmaWNhIG9wZXJhZG9yYXMgYSBzZXJlbSBkZXNjb25zaWRlcmFkYXMgbmEgYmFzZSBkZSBjw6FsY3VsbyBkYSBWREE6DQoNCmBgYHtyIG9wczF9DQpyZXNzYWx2YXMgPC0gZnJlYWQoIi4vZGF0YXNldHMvcmVzc2FsdmFzLmNzdiIsIGVuY29kaW5nID0gJ1VURi04JykgJT4lIA0KICBkaXN0aW5jdChjZF9vcHMpICU+JSANCiAgbXV0YXRlKGxnX3Jlc3NhbHZhID0gMSkgJT4lIA0KICBhc190aWJibGUoKQ0KDQpjYWRvcCA8LSBjYWRvcCAlPiUgDQogIGZpbHRlcihtb2RhbGlkYWRlICVpbiUgYygnQXV0b2dlc3TDo28nLCAnQ29vcGVyYXRpdmEgTcOpZGljYScsICdGaWxhbnRyb3BpYScsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAnTWVkaWNpbmEgZGUgR3J1cG8nLCAnU2VndXJhZG9yYScpKSAlPiUgICMgb3BzIG3DqWRpY28taG9zcGl0YWxhcmVzDQogIG11dGF0ZSgNCiAgICBsZ19jYW5jZWxhZGEgPSBpZmVsc2UoeWVhcihkdF9jYW5jZWxhbWVudG8pIDw9IHllYXIocGVyaW9kb1syXSkgDQogICAgICAgICAgICAgICAgICAgICAgICAgICYgIWlzLm5hKGR0X2NhbmNlbGFtZW50byksDQogICAgICAgICAgICAgICAgICAgICAgICAgIDEsIDApLCAjIGZpbHRybyBkZSBmaW0gZGEgb3BlcmHDp8Ojbw0KICAgIGxnX25vdmFfb3BzICA9IGlmZWxzZSh5ZWFyKGR0X3JlZ2lzdHJvKSA+PSB5ZWFyKHBlcmlvZG9bMV0pLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAxLCAwKSkgJT4lICMgZmlsdHJvIGRlIGluw61jaW8gZGUgb3BlcmHDp8Ojbw0KICBzZWxlY3QoY2Rfb3BzLCByYXphb19zb2NpYWwsIG1vZGFsaWRhZGUsIHBvcnRlX29wcywgbGdfY2FuY2VsYWRhLCBsZ19ub3ZhX29wcykgJT4lDQogIGxlZnRfam9pbihyZXNzYWx2YXMsIGJ5ID0gJ2NkX29wcycpICU+JSANCiAgbXV0YXRlKGxnX3Jlc3NhbHZhID0gaWZlbHNlKGlzLm5hKGxnX3Jlc3NhbHZhKSwgMCwgbGdfcmVzc2FsdmEpKQ0KDQpyZW1vdmUob3BzLCByZXNzYWx2YXMpDQpjYWRvcCAlPiUgc3VtbWFyaXNlKA0KICBuX29wcyA9IG5fZGlzdGluY3QoY2Rfb3BzKSwNCiAgbl9jYW5jZWxhZGFzID0gc3VtKGxnX2NhbmNlbGFkYSksDQogIG5fbm92YV9vcHMgPSBzdW0obGdfbm92YV9vcHMpLA0KICBuX3Jlc3NhbHZhcyA9IHN1bShsZ19yZXNzYWx2YSkNCikNCmBgYA0KDQoqKioNCiMjIEPDoWxjdWxvIGRhIFZEQQ0KKioqDQojIyMgRGVzcGVzYSBwb3IgQmVuZWZpY2nDoXJpbw0KDQpFc3NhIHNlw6fDo28gZ2VyYSBhIGJhc2UgZGUgZGVzcGVzYSBhc3Npc3RlbmNpYWwgZSBiZW5lZmljacOhcmlvcyBlIGNhbGN1bGEgYSAqZGVzcGVzYSBwb3IgYmVuZWZpY2nDoXJpbyouICAgICAgICAgICANCg0KQSBkZXNwZXNhIHBvciBiZW5lZmljacOhcmlvIMOpIGEgKmRlc3Blc2EgYXNzaXN0ZW5jaWFsKiBkYSBjYXJ0ZWlyYSBwcsOzcHJpYSBkZSB1bWEgb3BlcmFkb3JhIGluY29ycmlkYSBlbSBjZXJ0byBwZXLDrW9kbywgZGl2aWRpZGEgcGVsYSAqbcOpZGlhIGRlIHbDrW5jdWxvcyBhdGl2b3MgZGUgYmVuZWZpY2nDoXJpb3MqIGFvIGxvbmdvIGRvIG1lc21vIHBlcsOtb2RvLiBFc3NhIG3DqXRyaWNhIHJlcHJlc2VudGEgbyBwcmluY2lwYWwgY29tcG9uZW50ZSBkZSBjdXN0byBkZSB1bSBwbGFubyBkZSBzYcO6ZGUgZSBlc3TDoSBleHByZXNzYSBkZSBmb3JtYSBhIHBlcm1pdGlyIGNvbXBhcsOhLWxhIGVudHJlIG9wZXJhZG9yYXMgcG9yIHRpcG8gZGUgY2FydGVpcmEgZSBhY29tcGFuaGFyIHN1YSBldm9sdcOnw6NvIGFvIGxvbmdvIGRvIHRlbXBvLiAgICAgICAgICAgDQogICAgICAgICAgICANCg0KPiBOb3RhOiAgICAgDQogIFBhcmEgZmFjaWxpdGFyIGEgY29tcGFyYWJpbGlkYWRlIGUgYWNvbXBhbmhhbWVudG8gZGEgZGVzcGVzYSBwb3IgYmVuZWZpY2nDoXJpbyBhbyBsb25nbyBkbyB0ZW1wbywgw6kgcG9zc8OtdmVsIG5vcm1hbGl6YXIgYSBtw6l0cmljYSBkaXZpZGluZG8tYSBwZWxvIG7Dum1lcm8gZGUgbWVzZXMgZG8gcGVyw61vZG8gc2VtIGltcGFjdG8gc29icmUgYSBWREEuDQoNCiAgICAgICAgICAgICAgDQpBIGJhc2UgZGUgY8OhbGN1bG8gZGEgVkRBIGNvbnNpZGVyYSBhcGVuYXM6ICAgICAgDQoNCiogT3BlcmFkb3JhcyB2w6FsaWRhcyAgICAgDQoNCiogT2JzZXJ2YcOnw7VlcyBxdWUgYXByZXNlbnRhbSB2YWxvciBwb3NpdGl2byBkZSBkZXNwZXNhICAgICAgICANCg0KKiBPYnNlcnZhw6fDtWVzIHF1ZSBhcHJlc2VudGFtIHVtYSBzZXF1w6puY2lhIGluaW50ZXJydXB0YSBkZSAxMiBtZXNlcyBkZSBiZW5lZmljacOhcmlvcyBubyBhbm8gICAgICAgIA0KDQpPIGPDs2RpZ28gYSBzZWd1aXIgY29uc29saWRhIG9zIGRhZG9zIGRlIG9wZXJhZG9yYXMsIGJlbmVmaWNpw6FyaW9zIGUgZGVzcGVzYXMsIGZpbHRyYSBhcyBvYnNlcnZhw6fDtWVzIHJlbGV2YW50ZXMgZSBjYWxjdWxhIGEgRGVzcGVzYSBwb3IgQmVuZWZpY2nDoXJpbyAobcOpZGlhIG1lbnNhbCk6DQoNCg0KYGBge3IgZHBiMH0NCmRmLnZkYSA8LSBkaW9wcyAlPiUgDQogIHNlbGVjdCgtcmVjZWl0YSkgJT4lIA0KICBpbm5lcl9qb2luKHNpYiwgYnk9YygnY2Rfb3BzJywgJ2NvbnRyYXRhY2FvJywgJ2lkX2NhbGVuZGFyJykpICU+JSANCiAgaW5uZXJfam9pbihjYWRvcCwgYnk9J2NkX29wcycpICU+JSANCiAgZmlsdGVyKA0KICAgIGxnX2NhbmNlbGFkYSA9PSAwLCANCiAgICBsZ19ub3ZhX29wcyAgPT0gMCwgDQogICAgbGdfcmVzc2FsdmEgID09IDAsDQogICAgZGVzcGVzYSA+IDAsDQogICAgbl9tZXNlcyA9PSAxMiAjIG9wcyBjb20gc2VxdcOqbmNpYSBpbmludGVycnVwdGEgZGUgYmVuZWZpY2nDoXJpb3Mgbm8gYW5vDQogICkgJT4lIA0KICBzZWxlY3QoLWMobGdfY2FuY2VsYWRhLCBsZ19ub3ZhX29wcywgbGdfcmVzc2FsdmEsIG5fbWVzZXMpKSAlPiUgDQogIHJlbG9jYXRlKGMocmF6YW9fc29jaWFsLCBtb2RhbGlkYWRlLCBwb3J0ZV9vcHMpLCAuYWZ0ZXIgPSBjZF9vcHMpICU+JSANCiAgYXJyYW5nZShjZF9vcHMsIGNvbnRyYXRhY2FvLCBpZF9jYWxlbmRhcikgJT4lIA0KICBtdXRhdGUoZHBiID0gaWZlbHNlKGJlbmVmbSA+IDAsIGRlc3Blc2EvIGJlbmVmbSAvIG1vbnRoKGlkX2NhbGVuZGFyKSwgTkEpKQ0KDQpkZi52ZGEgJT4lIGdyb3VwX2J5KGNvbnRyYXRhY2FvLCBhbm89IHllYXIoaWRfY2FsZW5kYXIpKSAlPiUgDQogIHN1bW1hcmlzZSgnRGVzcGVzYSAoUiRibiknID0gcm91bmQoc3VtKGRlc3Blc2EpLzEwMDAwMDAwMDAsMSksDQogICAgICAgICAgICAnQmVuZWZpY2nDoXJpb3MgKG3DqWRpYSknID0gcm91bmQoc3VtKGJlbmVmbSksMCksDQogICAgICAgICAgICAnUXRkIG9wZXJhZG9yYXMnID0gbl9kaXN0aW5jdChjZF9vcHMpLA0KICAgICAgICAgICAgLmdyb3VwcyA9ICdkcm9wJykNCmBgYA0KDQoNCjxicj4NClZpc3VhbGl6YcOnw6NvIGdyw6FmaWNhIGRhIGRpc3RyaWJ1acOnw6NvIGRhIGRlc3Blc2EgcG9yIGJlbmVmaWNpw6FyaW8gZGFzIG9wZXJhZG9yYXMuICAgICANCipOb3RhOiBFeGNsdcOtcmFtLXNlIG9zIHZhbG9yZXMgYXTDrXBpY29zIHBlbG8gbcOpdG9kbyBkZSBib3hwbG90IDEsNXhJUVIgcGFyYSBxdWUgZm9zc2UgcG9zc8OtdmVsIHZpc3VhbGl6YXIgYSBkaXN0cmlidWnDp8OjbyBkYSBncmFuZGUgbWFpb3JpYSBkb3MgZGFkb3MuKg0KDQpgYGB7ciBwbG90MX0NCnRyaW0uZGYoZGYudmRhLCBkZi52ZGEkZHBiKSAlPiUgZ2dwbG90KGFlcyh4PWRwYikpICsNCiAgZ2VvbV9oaXN0b2dyYW0oYmlucyA9IDUwLCBmaWxsID0gJ3doaXRlJywgY29sb3IgPSAic2xhdGVncmF5IikgKw0KICB0aGVtZShheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoY29sb3IgPSAnZ3JheScpLA0KICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCkpICsNCiAgbGFicyh4ID0gIkRlc3Blc2EgbWVuc2FsIHBvciBiZW5lZmljacOhcmlvIChSJCkiLA0KICAgICAgIHkgPSAiRnJlcXXDqm5jaWEiKSArIA0KICBmYWNldF9ncmlkKGNvbnRyYXRhY2FvIH4geWVhcihpZF9jYWxlbmRhcikpDQpgYGANCg0KDQoNCioqKg0KIyMjIFZEQSBwb3Igb3BlcmFkb3JhDQoNCkEgVkRBIGRlIHVtYSBvcGVyYWRvcmEgw6kgYSB2YXJpYcOnw6NvIGRhIGRlc3Blc2EgcG9yIGJlbmVmaWNpw6FyaW8gZGVzdGEgb3BlcmFkb3JhIHNvYnJlIG8gbWVzbW8gcGVyw61vZG8gZG8gYW5vIGFudGVyaW9yLCBjb25mb3JtZSBhIHNlZ3VpbnRlIGbDs3JtdWxhOg0KPGJyPg0KDQokJFZEQV97aXB9ID0gXGRpc3BsYXlzdHlsZVxmcmFje1xmcmFje0RBX3tpcH19e0Jlbl97aXB9fX17XGZyYWN7REFfe2lcIFxsZWZ0KHAtMVxyaWdodCl9fXtCZW5fe2lcIFxsZWZ0KHAtMVxyaWdodCl9fX0gLSAxJCQNCjxicj4NCiAgICANCg0KPGRpdiBjbGFzcz0iYWxlcnQgYWxlcnQtYmxvY2sgYWxlcnQtaW5mbyI+DQo8Yj5PbmRlOjwvYj4gICAgIA0KICAgIGkgPSBPcGVyYWRvcmEgbmEgYmFzZSBkZSBjw6FsY3VsbyAgICAgICAgIA0KICAgIHAgPSBQZXLDrW9kbyBkZSBqYW5laXJvIGEgZGV6ZW1icm8gZG8gYW5vIGNhbGVuZMOhcmlvIGFudGVyaW9yIGFvIGluw61jaW8gZGEgYXBsaWNhw6fDo28gZG8gSVJQSSAgICANCiAgICBEQSA9IERlc3Blc2EgYXNzaXN0ZW5jaWFsIGVtIGNhcnRlaXJhIHByw7NwcmlhIGFjdW11bGFkYSBhbyBmaW0gZG8gcGVyw61vZG8gICAgDQogICAgQmVuID0gTcOpZGlhIG1lbnNhbCBkZSBiZW5lZmljacOhcmlvcyBlbSBjYXJ0ZWlyYSBwcsOzcHJpYSBhbyBsb25nbyBkbyBwZXLDrW9kbyAgICANCjwvZGl2Pg0KDQpPIGPDs2RpZ28gYSBzZWd1aXIgY2FsY3VsYSBhIFZEQSBwb3Igb3BlcmFkb3JhOg0KDQpgYGB7ciB2ZGEwfQ0KZGYudmRhIDwtIGRmLnZkYSAlPiUNCiAgYXJyYW5nZShjZF9vcHMsIGNvbnRyYXRhY2FvLCBpZF9jYWxlbmRhcikgJT4lIA0KICBtdXRhdGUodmRhID0gaWZlbHNlKGxhZyhjZF9vcHMpID09IGNkX29wcyANCiAgICAgICAgICAgICAgICAgICAgICAmIGxhZyhjb250cmF0YWNhbykgPT0gY29udHJhdGFjYW8NCiAgICAgICAgICAgICAgICAgICAgICAmIHllYXIobGFnKGlkX2NhbGVuZGFyKSkgPT0geWVhcihpZF9jYWxlbmRhcikgLSAxLCANCiAgICAgICAgICAgICAgICAgICAgICAoZHBiL2xhZyhkcGIpIC0gMSkgKiAxMDAsIE5BKSkgJT4lIA0KICBmaWx0ZXIoIWlzLm5hKHZkYSkpICU+JSANCiAgc2VsZWN0KC1pZF9jYWxlbmRhcikNCg0KYGBgDQoNCioqKg0KIyMjIFZEQSBkbyBzZXRvcg0KDQpFc3RhdMOtc3RpY2FzIGRlc2NyaXRpdmFzIGRhIGJhc2UgZGUgY8OhbGN1bG8gZGEgVkRBLg0KDQoNCmBgYHtyIHZkYTBhfQ0KZGYudmRhICU+JSBncm91cF9ieShjb250cmF0YWNhbykgJT4lIA0KICBzdGF0c1ZEQSgpIA0KYGBgDQoNCg0KVmlzdWFsaXphw6fDo28gZ3LDoWZpY2EgZGEgZGlzdHJpYnVpw6fDo28gZGEgVkRBIGRhcyBvcGVyYWRvcmFzIGF0cmF2w6lzIGRlIHVtIGdyw6FmaWNvIGJveHBsb3QuDQoNCmBgYHtyIHBsb3QyYSwgZWNobz1GQUxTRX0NCmRmLnZkYSAlPiUgDQogIGdncGxvdChhZXMoeD12ZGEsIHk9Y29udHJhdGFjYW8pKSArDQogIGdlb21fYm94cGxvdChhZXMoZmlsbD1jb250cmF0YWNhbyksIHNob3cubGVnZW5kID0gRkFMU0UpICsgDQogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiRGFyazIiKSArDQogIGxhYnMoeT0iIikgKw0KICB0aGVtZShheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoY29sb3IgPSAnZ3JheScpLA0KICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X2JsYW5rKCkpDQpgYGANCg0KDQpgYGB7ciBwbG90MmIsIGVjaG89RkFMU0V9DQpkZi52ZGEgJT4lIGZpbHRlcihjb250cmF0YWNhbyA9PSAiSW5kaXZpZHVhbCIpICU+JSANCiAgZ2dwbG90KGFlcyh4PXZkYSwgeT1jb250cmF0YWNhbykpICsNCiAgZ2VvbV9ib3hwbG90KGZpbGw9JyM3NTcwQjMnLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArDQogIGxhYnMoeT0iIikgKw0KICB0aGVtZShheGlzLmxpbmUgPSBlbGVtZW50X2xpbmUoY29sb3IgPSAnZ3JheScpLA0KICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIGFzcGVjdC5yYXRpbyA9IDAuNC8yKSANCmBgYA0KDQoNCk8gY8OzZGlnbyBhIHNlZ3VpciBpZGVudGlmaWNhIHZhbG9yZXMgYXTDrXBpY29zIHBlbGEgbWV0b2RvbG9naWEgQm94UGxvdCAxLDV4SVFSIGUgY2FsY3VsYSBhIHByb3BvcsOnw6NvIGRlIHZhbG9yZXMgYXTDrXBpY29zIHBvciBjYXJ0ZWlyYTogDQoNCmBgYHtyIHZkYTEsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojID09PSBJREVOVElGSUNBIE9VVExJRVJTID09PSBDUklUw4lSSU86IEJPWC1QTE9UIDEuNXggPT09DQpkZi52ZGEgPC0gZGYudmRhICU+JQ0KICBncm91cF9ieShjb250cmF0YWNhbykgJT4lIA0KICBtdXRhdGUobGdfb3V0bGllciA9IGlmZWxzZSh2ZGEgPj0gKHF1YW50aWxlKHZkYSwgMC43NSwgbmFtZXMgPSBGKSArIDEuNSAqIElRUih2ZGEpKSANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCB2ZGEgPD0gKHF1YW50aWxlKHZkYSwgMC4yNSwgbmFtZXMgPSBGKSAtIDEuNSAqIElRUih2ZGEpKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMSwgMCkpICU+JSANCiAgdW5ncm91cCgpDQoNCiMgUHJvcG9yw6fDo28gZGUgb3V0bGllcnMNCmRmLnZkYSAlPiUNCiAgZ3JvdXBfYnkoY29udHJhdGFjYW8sIGxnX291dGxpZXIpICU+JQ0KICBzdW1tYXJpc2Uobl9vYnMgPSBuKCkpICU+JQ0KICBhZGRfdGFsbHkod3QgPSBuX29icykgJT4lDQogIG11dGF0ZShwY3Rfb2JzID0gcm91bmQobl9vYnMgLyBuICogMTAwLCAxKSkNCmBgYA0KDQo8YnI+DQpCb3hwbG90IGRhIGRpc3RyaWJ1acOnw6NvIGRhIFZEQSBhcMOzcyBhIGV4Y2x1c8OjbyBkb3MgdmFsb3JlcyBhdMOtcGljb3MuDQoNCmBgYHtyIHBsb3QzYiwgZWNobz1GQUxTRX0NCmRmLnZkYSAlPiUgZmlsdGVyKGxnX291dGxpZXIgPT0gMCkgJT4lIA0KICBnZ3Bsb3QoYWVzKHg9dmRhLCB5PWNvbnRyYXRhY2FvKSkgKw0KICBnZW9tX2JveHBsb3QoYWVzKGZpbGw9Y29udHJhdGFjYW8pLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArIA0KICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIkRhcmsyIikgKw0KICBsYWJzKHk9IiIpICsNCiAgdGhlbWUoYXhpcy5saW5lID0gZWxlbWVudF9saW5lKGNvbG9yID0gJ2dyYXknKSwNCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9ibGFuaygpKQ0KYGBgDQo8YnI+DQpIaXN0b2dyYW1hIGRhIGRpc3RyaWJ1acOnw6NvIGRhIFZEQSBzZW0gb3MgdmFsb3JlcyBhdMOtcGljb3MuDQoNCmBgYHtyIHBsb3QzYywgZWNobz1GQUxTRX0NCmRmLnZkYSAlPiUgZmlsdGVyKGxnX291dGxpZXIgPT0gMCkgJT4lIA0KICBnZ3Bsb3QoYWVzKHg9dmRhKSkgKw0KICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gNTAsIGZpbGwgPSAnd2hpdGUnLCBjb2xvciA9ICJzbGF0ZWdyYXkiKSArDQogIHRoZW1lKGF4aXMubGluZSA9IGVsZW1lbnRfbGluZShjb2xvciA9ICdncmF5JyksDQogICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSkgKw0KICBsYWJzKHggPSAiRGVzcGVzYSBtZW5zYWwgcG9yIGJlbmVmaWNpw6FyaW8gKFIkKSIsDQogICAgICAgeSA9ICJGcmVxdcOqbmNpYSIpICsgDQogIGZhY2V0X2dyaWQoY29udHJhdGFjYW8gfiAuKQ0KYGBgDQoNCg0KDQo8YnI+DQpBIG1ldG9kb2xvZ2lhIGRlIGPDoWxjdWxvIGRhIFZEQSBkbyBzZXRvciBwYXJhIGFwbGljYcOnw6NvIGNvbW8gY29tcG9uZW50ZSBkbyBJUlBJIGFkb3RhIGEgVkRBIG3DqWRpYSBwb25kZXJhZGEgcGVsYSBxdWFudGlkYWRlIGRlIGJlbmVmaWNpw6FyaW9zIG5vIGFubyBtYWlzIHJlY2VudGUsIGFww7NzIGEgZXhjbHVzw6NvIGRvcyB2YWxvcmVzIGF0w61waWNvcy4gQSBzZWd1aXIsIGFwcmVzZW50YS1zZSBhIG3DqWRpYSBwb25kZXJhZGEgZGEgVkRBIChtZWRpYVApIGUgZGVtYWlzIGVzdGF0w61zdGljYXMgZGVzY3JpdGl2YXMgZGEgc3VhIGRpc3RyaWJ1acOnw6NvIGVtIGNhZGEgY2FydGVpcmEuDQoNCmBgYHtyIHZkYTJ9DQpkZi52ZGEgJT4lIGZpbHRlcihsZ19vdXRsaWVyID09IDApICU+JSANCiAgZ3JvdXBfYnkoY29udHJhdGFjYW8pICU+JSANCiAgc3RhdHNWREEoKQ0KYGBgDQoqKioNCiMjIyBCYXNlIGRlIGPDoWxjdWxvDQoNCjxicj4NCkdlcmEgYSBiYXNlIGNvbXBsZXRhIHF1ZSByZcO6bmUgdG9kYXMgYXMgb2JzZXJ2YcOnw7VlcyBkZSByZWNlaXRhLCBkZXNwZXNhIGUgYmVuZWZpY2nDoXJpb3MgaW5mb3JtYWRhcyBwZWxhcyBvcGVyYWRvcmFzIHBhcmEgb3MgZG9pcyBhbm9zIGUgbyBjw6FsY3VsbyBkYSBWREEgcG9yIG9wZXJhZG9yYS4NCg0KDQpgYGB7ciBiYXNlX3JldW5pZGF9DQpzaWIyIDwtIHNpYiAlPiUgDQogIG11dGF0ZShhbm8gPSB5ZWFyKGlkX2NhbGVuZGFyKSkgJT4lIA0KICBzZWxlY3QoLWlkX2NhbGVuZGFyKSAlPiUgDQogIHJlbmFtZShiZW4gPSBiZW5lZm0pICU+JSANCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IGFubywgdmFsdWVzX2Zyb20gPSBjKGJlbiwgbl9tZXNlcyksIA0KICAgICAgICAgICAgICB2YWx1ZXNfZmlsbCA9IDApICU+JSANCiAgbXV0YXRlKA0KICAgIGxnX2JlbmVmID0gaWZlbHNlKCAjIG1hcmNhIG9icyBzZW0gc2VxdWVuY2lhIGluaW50ZXJydXB0YSBkZSBiZW4gZW0gMSBkb3MgYW5vcw0KICAgICAgYmVuXzIwMTkgPCAxIHwgYmVuXzIwMjAgPCAxIHwgKG5fbWVzZXNfMjAxOSArIG5fbWVzZXNfMjAyMCkgIT0gMjQsIA0KICAgICAgMSwgMCkNCiAgKSAlPiUgDQogIHNlbGVjdCgtc3RhcnRzX3dpdGgoJ25fbWVzZXMnKSkNCg0KZGlvcHMyIDwtIGRpb3BzICU+JSANCiAgbXV0YXRlKGFubyA9IHllYXIoaWRfY2FsZW5kYXIpKSAlPiUgDQogIHNlbGVjdCgtaWRfY2FsZW5kYXIpICU+JSANCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IGFubywgdmFsdWVzX2Zyb20gPSBjKGRlc3Blc2EsIHJlY2VpdGEpLCANCiAgICAgICAgICAgICAgdmFsdWVzX2ZpbGwgPSAwKSAlPiUgDQogIG11dGF0ZShsZ19kZXNwZXNhID0gaWZlbHNlKA0KICAgIGRlc3Blc2FfMjAxOSA8PTAgfCBkZXNwZXNhXzIwMjAgPD0gMCwgMSwgMCAjIG1hcmNhIG9icyBzZW0gZGVzcGVzYSBlbSAxIGRvcyBhbm9zDQogICkpIA0KDQpkZi52ZGEyIDwtIGRmLnZkYSAlPiUgDQogIHNlbGVjdChjZF9vcHMsIGNvbnRyYXRhY2FvLCB2ZGEsIGxnX291dGxpZXIpDQoNCmRmLnJldW5pZGEgPC0gIHNpYjIgJT4lIA0KICBmdWxsX2pvaW4oZGlvcHMyLCBieT1jKCdjZF9vcHMnLCAnY29udHJhdGFjYW8nKSkgJT4lIA0KICBtdXRhdGUoZHBiXzIwMTkgPSBpZmVsc2UoZGVzcGVzYV8yMDE5ID4gMCAmIGJlbl8yMDE5ID4gMCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICByb3VuZChkZXNwZXNhXzIwMTkgLyBiZW5fMjAxOSAvIDEyLCAwKSwgTkEpLA0KICAgICAgICAgZHBiXzIwMjAgPSBpZmVsc2UoZGVzcGVzYV8yMDIwID4gMCAmIGJlbl8yMDIwID4gMCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICByb3VuZChkZXNwZXNhXzIwMjAgLyBiZW5fMjAyMCAvIDEyLCAwKSwgTkEpKSAlPiUgDQogIGZ1bGxfam9pbihkZi52ZGEyLCBieT1jKCdjZF9vcHMnLCAnY29udHJhdGFjYW8nKSkgJT4lIA0KICBpbm5lcl9qb2luKGNhZG9wLCBieSA9ICdjZF9vcHMnKSAlPiUgDQogIG11dGF0ZShkZXNwZXNhXzIwMTkgPSBpZmVsc2UoZGVzcGVzYV8yMDE5ID09IDAsIE5BLCBkZXNwZXNhXzIwMTkpLA0KICAgICAgICAgZGVzcGVzYV8yMDIwID0gaWZlbHNlKGRlc3Blc2FfMjAyMCA9PSAwLCBOQSwgZGVzcGVzYV8yMDIwKSwNCiAgICAgICAgIHJlY2VpdGFfMjAxOSA9IGlmZWxzZShyZWNlaXRhXzIwMTkgPT0gMCwgTkEsIHJlY2VpdGFfMjAxOSksDQogICAgICAgICByZWNlaXRhXzIwMjAgPSBpZmVsc2UocmVjZWl0YV8yMDIwID09IDAsIE5BLCByZWNlaXRhXzIwMjApLA0KICAgICAgICAgYmVuXzIwMTkgICA9IGlmZWxzZShiZW5fMjAxOSA9PSAwLCBOQSwgYmVuXzIwMTkpLA0KICAgICAgICAgYmVuXzIwMjAgICA9IGlmZWxzZShiZW5fMjAyMCA9PSAwLCBOQSwgYmVuXzIwMjApLA0KICAgICAgICAgbGdfYmVuZWYgICA9IGlmZWxzZShpcy5uYShsZ19iZW5lZiksIDEsIGxnX2JlbmVmKSwNCiAgICAgICAgIGxnX2Rlc3Blc2EgPSBpZmVsc2UoaXMubmEobGdfZGVzcGVzYSksIDEsIGxnX2Rlc3Blc2EpDQogICkgJT4lIA0KICByZWxvY2F0ZShyYXphb19zb2NpYWw6bGdfcmVzc2FsdmEsIC5hZnRlciA9IGNkX29wcykgJT4lIA0KICBzZWxlY3QoY2Rfb3BzOmNvbnRyYXRhY2FvLCANCiAgICAgICAgIHN0YXJ0c193aXRoKCdsZ18nKSwNCiAgICAgICAgIHN0YXJ0c193aXRoKCdyZWNlaXRhJyksIA0KICAgICAgICAgc3RhcnRzX3dpdGgoJ2Rlc3Blc2EnKSwgDQogICAgICAgICBzdGFydHNfd2l0aCgnYmVuJyksIA0KICAgICAgICAgZXZlcnl0aGluZygpKQ0KDQpyZW1vdmUoZGlvcHMyLCBzaWIyLCBkZi52ZGEyKQ0KDQpkZi5yZXVuaWRhICU+JSBmaWx0ZXIobGdfb3V0bGllciA9PSAwKSAlPiUgDQogIGdyb3VwX2J5KGNvbnRyYXRhY2FvKSAlPiUgDQogIHJlbmFtZShiZW5lZm0gPSBiZW5fMjAyMCkgJT4lIA0KICBzdGF0c1ZEQSgpDQpgYGANCg0KPGJyPg0KQ2FsY3VsYSBhIHByb3BvcsOnw6NvIChyZXByZXNlbnRhdGl2aWRhZGUpIGRhIGJhc2UgZGUgY8OhbGN1bG8gc29icmUgYXMgYmFzZXMgb3JpZ2luYWlzLg0KDQpgYGB7ciBwbG90NH0NCmRmMSA8LSBkZi5yZXVuaWRhICU+JSBmaWx0ZXIoIWlzLm5hKGxnX291dGxpZXIpKSAlPiUgDQogIGdyb3VwX2J5KGNvbnRyYXRhY2FvKSAlPiUgDQogIHN1bW1hcmlzZShiZW5lZi5WREEgPSBzdW0oYmVuXzIwMjApLA0KICAgICAgICAgICAgZGVzcGVzYS5WREEgPSBzdW0oZGVzcGVzYV8yMDIwKSwgDQogICAgICAgICAgICBuX29wcy5WREEgPSBuX2Rpc3RpbmN0KGNkX29wcykpDQoNCmRmMiA8LSBkZi5yZXVuaWRhICU+JSANCiAgZ3JvdXBfYnkoY29udHJhdGFjYW8pICU+JSANCiAgc3VtbWFyaXNlKGJlbmVmLm9yaWcgICA9IHN1bShiZW5fMjAyMCwgbmEucm0gPSBUKSwNCiAgICAgICAgICAgIGRlc3Blc2Eub3JpZyA9IHN1bShkZXNwZXNhXzIwMjAsIG5hLnJtID0gVCksDQogICAgICAgICAgICBuX29wcy5vcmlnLmJlbiAgID0gbl9kaXN0aW5jdChjZF9vcHMsIGJlbl8yMDIwLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICAgICAgbl9vcHMub3JpZ19kZXNwID0gbl9kaXN0aW5jdChjZF9vcHMsIGRlc3Blc2FfMjAyMCwgbmEucm0gPSBUUlVFKSkgJT4lIA0KICBpbm5lcl9qb2luKGRmMSwgYnk9J2NvbnRyYXRhY2FvJykgJT4lIA0KICBtdXRhdGUoYmVuZWYucGN0ICAgID0gYmVuZWYuVkRBIC8gYmVuZWYub3JpZyAqIDEwMCwgDQogICAgICAgICBkZXNwZXNhLnBjdCAgPSBkZXNwZXNhLlZEQSAvIGRlc3Blc2Eub3JpZyAqIDEwMCwNCiAgICAgICAgIG5fb3BzLmJlbmVmLnBjdCAgID0gbl9vcHMuVkRBIC8gbl9vcHMub3JpZy5iZW4gKiAxMDAsDQogICAgICAgICBuX29wcy5kZXNwZXNhLnBjdCA9IG5fb3BzLlZEQSAvIG5fb3BzLm9yaWdfZGVzcCAqIDEwMCkgJT4lIA0KICBzZWxlY3QoY29udHJhdGFjYW8sIHN0YXJ0c193aXRoKCJiZW5lZiIpLCBzdGFydHNfd2l0aCgiZGVzcGVzYSIpLCBzdGFydHNfd2l0aCgibl9vcHMiKSkNCg0KDQpkZjIgJT4lIHNlbGVjdChjKGNvbnRyYXRhY2FvLCBlbmRzX3dpdGgoJy5wY3QnKSkpICU+JSANCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBlbmRzX3dpdGgoIi5wY3QiKSwgDQogICAgICAgICAgICAgICB2YWx1ZXNfdG8gPSAicGVyY2VudHVhbCIsIG5hbWVzX3RvID0gJ01ldHJpY2EnKSAlPiUgDQogIG11dGF0ZShNZXRyaWNhID0gc3ViKCcucGN0JywgJycsIE1ldHJpY2EpLA0KICAgICAgICAgTWV0cmljYSA9IGNhc2Vfd2hlbigNCiAgICAgICAgICAgTWV0cmljYSA9PSAnYmVuZWYnIH4gJ0JlbmVmaWNpw6FyaW9zJywNCiAgICAgICAgICAgTWV0cmljYSA9PSAnZGVzcGVzYScgfiAnRGVzcGVzYScsDQogICAgICAgICAgIE1ldHJpY2EgPT0gJ25fb3BzLmJlbmVmJyB+ICdPcHMgKFNJQiknLA0KICAgICAgICAgICBNZXRyaWNhID09ICduX29wcy5kZXNwZXNhJyB+ICdPcHMgKERJT1BTKScsIA0KICAgICAgICAgICBUUlVFIH4gJ0VSUk8nKSwNCiAgICAgICAgIHBlcmNlbnR1YWwgPSByb3VuZChwZXJjZW50dWFsLCAxKQ0KICAgICAgICAgKSAlPiUgDQogIGdncGxvdChhZXMoeSA9IGNvbnRyYXRhY2FvLCB4PXBlcmNlbnR1YWwpKSArDQogIGdlb21fY29sKHBvc2l0aW9uID0gJ2RvZGdlJywgZmlsbCA9ICJzbGF0ZWdyYXk0IikgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGVyY2VudHVhbCwgaGp1c3QgPSAxLjIpLCBjb2xvciA9ICJ3aGl0ZSIsIA0KICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgxKSkgKw0KICBsYWJzKHg9TlVMTCwgeT1OVUxMLCANCiAgICAgICB0aXRsZSA9ICJSZXByZXNlbnRhdGl2aWRhZGUgZGEgYmFzZSBkZSBjw6FsY3VsbyBkYSBWREEgc29icmUgYXMgYmFzZXMgb3JpZ2luYWlzXG4iKSArDQogIHRoZW1lKGF4aXMubGluZSA9IGVsZW1lbnRfbGluZShjb2xvciA9ICdncmF5JyksDQogICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfYmxhbmsoKSkgKyANCiAgZmFjZXRfZ3JpZChNZXRyaWNhIH4gLikNCmBgYA0KDQoNCg0KYGBge3IgZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0NCiMgbXVsdGlwbGUgZGF0YWZyYW1lcyB0byBhIGZvbGRlcg0KcmVtb3ZlKGRmMSxkZjIpDQoNCmRmcyA8LSBscygpW3NhcHBseShtZ2V0KGxzKCksIC5HbG9iYWxFbnYpLCBpcy5kYXRhLmZyYW1lKV0NCmZvciAoZGYgaW4gZGZzKSB7DQogIGdldChkZikgJT4lDQogICAgbXV0YXRlKGFjcm9zcyh3aGVyZShpcy5mYWN0b3IpLCB+IGVuYzJ1dGY4KGFzLmNoYXJhY3RlcigueCkpKSkgJT4lIA0KICAgIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMuY2hhcmFjdGVyKSwgfiBlbmMydXRmOChhcy5jaGFyYWN0ZXIoLngpKSkpICU+JSANCiAgICBmd3JpdGUoc3RyX2MoYygiLi9iYXNlc1IvIiwgZGYsICIuY3N2IiksIHNlcCA9ICIiLCBjb2xsYXBzZSA9ICIiKSkNCn0NCnJlbW92ZShkZiwgZGZzKQ0KDQpgYGANCioqKg0KIyMgR2xvc3PDoXJpbyAgICANCg0KKipCZW5lZmljacOhcmlvKio6IEluZGl2w61kdW8gKHBlc3NvYSBmw61zaWNhKSBiZW5lZmljacOhcmlvIGRlIGNvYmVydHVyYSBkZSBwbGFubyBwcml2YWRvIGRlIGFzc2lzdMOqbmNpYSDDoCBzYcO6ZGUgZSBjb25zdW1pZG9yIGRlIHNlcnZpw6dvcyBkZSBhc3Npc3TDqm5jaWEgw6Agc2HDumRlLiAgICAgICAgICAgICAgDQoNCioqQ29udHJhdGFudGUqKjogUGVzc29hIGbDrXNpY2Egb3UganVyw61kaWNhIHJlc3BvbnPDoXZlbCBwZWxhIGNvbnRyYXRhw6fDo28gZG8gcGxhbm8gcHJpdmFkbyBkZSBhc3Npc3TDqm5jaWEgw6Agc2HDumRlLiAgICAgICAgICANCg0KKipPcGVyYWRvcmEqKjogUGVzc29hIGp1csOtZGljYSBjb25zdGl0dcOtZGEgc29iIGEgbW9kYWxpZGFkZSBkZSBzb2NpZWRhZGUgY2l2aWwgb3UgY29tZXJjaWFsLCBjb29wZXJhdGl2YSBvdSBlbnRpZGFkZSBkZSBhdXRvZ2VzdMOjbywgcXVlIG9wZXJlIHByb2R1dG8sIHNlcnZpw6dvIG91IGNvbnRyYXRvIGRlIHBsYW5vIHByaXZhZG8gZGUgYXNzaXN0w6puY2lhIMOgIHNhw7pkZS4gICAgICAgICAgICAgDQoNCioqUGxhbm8gUHJpdmFkbyBkZSBBc3Npc3TDqm5jaWEgw6AgU2HDumRlKio6IFByZXN0YcOnw6NvIGNvbnRpbnVhZGEgZGUgc2VydmnDp29zIG91IGNvYmVydHVyYSBkZSBjdXN0b3MgYXNzaXN0ZW5jaWFpcyBhIHByZcOnbyBwcsOpIG91IHDDs3MgZXN0YWJlbGVjaWRvLCBwb3IgcHJhem8gaW5kZXRlcm1pbmFkbywgY29tIGEgZmluYWxpZGFkZSBkZSBnYXJhbnRpciwgc2VtIGxpbWl0ZSBmaW5hbmNlaXJvLCBhIGFzc2lzdMOqbmNpYSDDoCBzYcO6ZGUsIHBlbGEgZmFjdWxkYWRlIGRlIGFjZXNzbyBlIGF0ZW5kaW1lbnRvIHBvciBwcm9maXNzaW9uYWlzIG91IHNlcnZpw6dvcyBkZSBzYcO6ZGUsIGxpdnJlbWVudGUgZXNjb2xoaWRvcywgaW50ZWdyYW50ZXMgb3UgbsOjbyBkZSByZWRlIGNyZWRlbmNpYWRhLCBjb250cmF0YWRhIG91IHJlZmVyZW5jaWFkYSwgdmlzYW5kbyBhIGFzc2lzdMOqbmNpYSBtw6lkaWNhLCBob3NwaXRhbGFyIGUgb2RvbnRvbMOzZ2ljYSwgYSBzZXIgcGFnYSBpbnRlZ3JhbCBvdSBwYXJjaWFsbWVudGUgw6BzIGV4cGVuc2FzIGRhIG9wZXJhZG9yYSBjb250cmF0YWRhLCBtZWRpYW50ZSByZWVtYm9sc28gb3UgcGFnYW1lbnRvIGRpcmV0byBhbyBwcmVzdGFkb3IsIHBvciBjb250YSBlIG9yZGVtIGRvIGNvbnN1bWlkb3IuICAgICAgICAgICAgIA0KDQoqKlRpcG8gZGUgY29udHJhdGHDp8OjbyoqOiAgICAgICAgICAgDQoNCiAgKyAqSW5kaXZpZHVhbCBvdSBGYW1pbGlhciosIG9mZXJlY2UgY29iZXJ0dXJhIGRhIGF0ZW7Dp8OjbyBwcmVzdGFkYSBwYXJhIGEgbGl2cmUgYWRlc8OjbyBkZSBiZW5lZmljacOhcmlvcywgcGVzc29hcyBuYXR1cmFpcywgY29tIG91IHNlbSBncnVwbyBmYW1pbGlhciAgICAgICAgICAgIA0KICANCiAgKyAqQ29sZXRpdm8gZW1wcmVzYXJpYWwqLCBxdWFuZG8gYSBjb250cmF0YcOnw6NvIMOpIGZlaXRhIHBvciBtZWlvIGRlIHBlc3NvYSBqdXLDrWRpY2EgcGFyYSBhIGNvYmVydHVyYSBkZSBwZXNzb2FzIGEgZWxhIHZpbmN1bGFkYXMgcG9yIHJlbGHDp8OjbyBlbXByZWdhdMOtY2lhIG91IGVzdGF0dXTDoXJpYSAgICAgICAgICAgDQogIA0KICArICpDb2xldGl2byBwb3IgYWRlc8OjbyosIHF1YW5kbyBhIGNvbnRyYXRhw6fDo28gw6kgZmVpdGEgcG9yIG1laW8gZGUgcGVzc29hIGp1csOtZGljYSBkZSBjYXLDoXRlciBwcm9maXNzaW9uYWwsIGNsYXNzaXN0YSBvdSBzZXRvcmlhbCAoZS5nLiBjb25zZWxob3MgcHJvZmlzc2lvbmFpcywgZW50aWRhZGVzIGRlIGNsYXNzZSwgc2luZGljYXRvcywgY29vcGVyYXRpdmFzLCBldGMuKSAgICAgICAgICAgIA0KICANCiAgICAgICAgICAgICAgDQogICAgICAgICAgICAgIA0KKipUaXBvIGRlIGZpbmFuY2lhbWVudG8qKjogICAgICAgICAgICAgICANCg0KICArICpQcsOpLWVzdGFiZWxlY2lkbyosIHF1YW5kbyBvIHZhbG9yIGRhIGNvbnRyYXByZXN0YcOnw6NvIHBlY3VuacOhcmlhIMOpIHByw6ktZml4YWRvIG1lZGlhbnRlIG5lZ29jaWHDp8OjbyBhbnVhbCwgY2FyYWN0ZXJpemFuZG8gY29udHJhdG8gZGUgcmlzY28uICAgICAgICAgICAgDQogIA0KICArICpQw7NzLWVzdGFiZWxlY2lkbyosIHF1YW5kbyBvIHZhbG9yIGRhIGNvbnRyYXByZXN0YcOnw6NvIHBlY3VuacOhcmlhIMOpIGVzdGFiZWxlY2lkbyBhcMOzcyBhIG9jb3Jyw6puY2lhIGRvcyBwcm9jZWRpbWVudG9zIGRlIGFzc2lzdMOqbmNpYSDDoCBzYcO6ZGUuICAgICAgICAgICAgICAgDQo=