Primeiro acesso

Olá! Nesse tutorial você irá aprender a replicar tudo que será exibido nessa página!

Para isso, você precisa ter instalado em seu computador 2 programas: o R e o RStudio.
O R é a linguagem de programação e o RStudio a interface gráfica,

Você pode baixar o R e o RStudio através do link https://posit.co/download/rstudio-desktop/

  1. Se é o seu primeiro acesso, clique na caixinha Code no canto superior direito para baixar o código no formato .Rmd, ou seja, RMarkdown.
  2. Abra o RStudio
  3. Clique em File -> Open file -> e selecione esse arquivo .Rmd que você baixou.
  4. Você deve chegar a uma tela semelhante a da figura abaixo

Na primeira vez em que for rodar os códigos aqui no R, será solicitado que instale pacotes. Quando aparecerem caixas de diálogo, clique em Yes.

Pode demorar um pouco esse processo. Para ter uma melhor visualização desse tutorial pressione as teclas Ctrl+Shift+K ou clique no botão Knit acima. Recomendo manter uma aba do navegador com o arquivo tutorial_R.html aberto.

Já podemos rodar o código pela primeira vez!
Para isso, aperte Ctrl+Alt+R ou clique em Run no menu superior e depois em Run All:

Enquanto os pacotes estão sendo instalados, prossiga com a leitura. Deixei alguns conteúdos nas Referências que irão complementar esse documento.

Quando quiser renderizar o código para ter a mesma visualização como a do formato .html use o comando de Knit, o Ctrl+Shift+K, ou caso esteja com um gráfico aberto, clique em Viewer na janela inferior direita.

1 Comandos mais utilizados

Ctrl+Alt+R -> executa TODOS os códigos de uma vez só.

Knit ou Ctrl+Shift+K -> roda TODOS os códigos de uma vez só e renderiza a visualização em formatos .html ou .pdf.

Ctrl+Enter -> executa um “parágrafo” de códigos.

Alt+Enter -> executa o “parágrafo” de códigos mas sem mover o cursor.

Ctrl+Shift+C -> para comentar ou descomentar um intervalo de linhas.

As linhas de código que começam com # são comentários. Elas não impactam o resultado final do código.

Ctrl+Alt+I -> cria um novo code chunk, isto é, “pedaço de código”, é a área executável das funções que iremos utilizar.

Ctrl+I -> Indenta o código (ajusta a tabulação entre as linhas, facilita a leitura do código).

A lista completa de atalhos pode ser conferida no menu superior Tools -> Keyboard Shortcuts Help, ou através do atalho Alt+Shift+K.

2 Passo-a-passo

Importante: Com esse arquivo .Rmd você deve chegar aos mesmos resultados que presentes no arquivo tutorial_R.html.

Vou deixar comentado os pedaços de código que necessitam de alteração obrigatória com a nomenclatura alteracao_ seguido de um número.

Para encontrar facilmente os locais que precisam ser ajustados, basta utilizar o comando Ctrl+F e procurar por alteracao_ e o respectivo número listado abaixo.

  1. Renomear a planilha a ser importada pra facilitar a leitura.
    • nesse caso renomeei a plan gerada pelo RSÁgua de Dados_20221222143305.xls para plan_litoral_medio.xls.
    • você pode usar Ctrl+F e substituir todas as ocorrências de plan_litoral_medio para o nome que você deu à planilha.
  2. Ajustar o caminho do arquivo. (alteracao_1)
    • nesse exemplo estou importando diretamente da pasta de downloads do meu computador: "C:/Users/Léo/Downloads/plan_litoral_medio.xls"
    • Futuramente quero implementar a integração com o Google Sheets.
  3. Verificar o intervalo de dados da planilha. As últimas 10 linhas costumam ser dos sumários, mas o R não entende isso.
    • verificar até qual linha a coluna Índice tem valores registrados, neste caso o Índice vai até 98 (+1 linha de cabeçalho) = linha 99
    • Alterar na parte de importação o intervalo para compreender somente os dados (alteracao_2)
    • Estou tentando descobrir como economizar essa etapa.

3 Pacotes necessários

No code chunk abaixo serão instalados todos os pacotes necessários. Cada pacote contém funções específicas que auxiliam no desenvolvimento da atividade, seja a importação do dado (readr, readxl), na manipulação dos dados (limpeza/tratamento com janitor e lubridate), na visualização (ggplot2, rmarkdown, kableExtra) ou pra praticamente tudo (tidyverse).

pacman::p_load(
  # ETL (extract, transform, load)
  janitor, readr, readxl, lubridate,
  dplyr, 
  tidyverse, 
  glue,
  # Visualização
  ggplot2,
  GGally, 
  rmarkdown, 
  knitr,
  kableExtra,
  ggbeeswarm, 
  ggtext
  # bookdown
)
#googlesheets4

Para acessar a página de ajuda dos pacotes ou das funções, basta usar um ? antes do que se está buscando.

No code chunk acima nós utilizamos uma função p_load que está dentro do pacote pacman. Para isso utilizamos o comando pacman::p_load, isto é, estamos dizendo para o R que dentro do pacote pacman quero usar especificamente a função p_load.

No exemplo abaixo estou verificando os argumentos dessa função. Na sequência abro o menu de ajuda do pacote tidyverse, um dos mais importantes da comunidade R. Outra maneira possível seria utilizando help(package = 'pacman').

?help

4 Importação dos dados

Utilizando o code chunk abaixo você estará importando a mesma planilha que utilizei. Salvei esse arquivo na nuvem, via GitHub. Estou importando-a utilizando o link para acessá-la online.

plan_litoral_medio <- read_delim(
  "https://raw.githubusercontent.com/leonardofwink/tutorial_R_fepam/main/planilha_rsagua/plan_litoral_medio%20-%20Dados_Ajustados.tsv", 
  delim = "\t", 
  escape_double = FALSE,
  col_types = cols(
    ÍNDICE = col_number(),
    `CÓD. ESTAÇÃO` = col_character(),
    LATITUDE = col_number(),
    LONGITUDE = col_number(),
    `BACIA HIDROGRÁFICA` = col_character(),
    `RECURSO HÍDRICO` = col_character(),
    REGIÃO = col_character(),
    MUNICÍPIO = col_character(),
    AMBIENTE = col_character(),
    `DATA COLETA` = col_date(format = "%m/%d/%Y"),
    `HORA COLETA` = col_time(format = "%H:%M:%S"),
    `CHUVA 24H` = col_character(),
    ALCALINIDADE = col_number(),
    ALUMÍNIO = col_number(),
    CÁDMIO = col_number(),
    CHUMBO = col_number(),
    CLORETO = col_number(),
    `CLOROFILA A` = col_number(),
    COBRE = col_number(),
    `COLIFORMES TERMOTOLERANTES` = col_number(),
    `COLIFORMES TOTAIS` = col_number(),
    CONDUTIVIDADE = col_number(),
    `CROMO TOTAL` = col_number(),
    `DEMANDA BIOQUÍMICA DE OXIGÊNIO` = col_number(),
    `DEMANDA QUÍMICA DE OXIGÊNIO` = col_number(),
    `ESCHERICHIA COLI` = col_number(),
    FERRO = col_number(),
    `FITOPLANCTON  - CIANOBACTÉRIAS` = col_number(),
    `FOSFATO ORTO` = col_number(),
    `FÓSFORO TOTAL` = col_number(),
    MANGANÊS = col_number(),
    `MERCÚRIO EM MICROGRAMA POR LITRO (UG/L)` = col_number(),
    NÍQUEL = col_number(),
    NITRATO = col_number(),
    `NITROGÊNIO AMONIACAL` = col_number(),
    `NITROGÊNIO ORGÂNICO` = col_number(),
    `NITROGÊNIO TOTAL KJELDAHL` = col_number(),
    `OXIGÊNIO DISSOLVIDO` = col_number(),
    PH = col_number(),
    `PROFUNDIDADE COLETA` = col_number(),
    `PROFUNDIDADE TOTAL` = col_number(),
    SALINIDADE = col_number(),
    `SÓLIDOS DISSOLVIDOS TOTAIS` = col_number(),
    `SÓLIDOS SUSPENSOS TOTAIS` = col_number(),
    `SÓLIDOS TOTAIS` = col_number(),
    `TEMPERATURA DA ÁGUA` = col_number(),
    `TEMPERATURA DO AR` = col_number(),
    `TRANSPARÊNCIA DA ÁGUA` = col_number(),
    TURBIDEZ = col_number(),
    `VAZÃO RECURSO HÍDRICO` = col_number(),
    ZINCO = col_number()
  ),
  locale = locale(
    date_names = "pt", 
    decimal_mark = ",",
    grouping_mark = ""
  ),
  trim_ws = TRUE
) %>%
  janitor::clean_names() %>%
  slice(
    1:(n() - 8) #retirando as ultimas 8 linhas
  ) %>% 
  rename(
    e_coli = escherichia_coli,
    dbo = demanda_bioquimica_de_oxigenio,
    mercurio = mercurio_em_micrograma_por_litro_ug_l
  ) %>%
  mutate(
    municipio = str_to_title(municipio),
    data_coleta = ymd(data_coleta),
    ano_coleta = year(data_coleta),
  ) %>%
  dplyr::select( #reordenando as colunas
    c(1:10),
    ano_coleta,
    everything()
  )

Você irá fazer as alterações nesse code chunk abaixo.
Será necessário que você altere o primeiro argumento da função read_excel, que é o caminho, ou seja: dizer ao R onde que a planilha está.

plan_litoral_medio_alterar <- read_excel(
  "C:/Users/Léo/Downloads/plan_litoral_medio.xls", #alteracao_1
  sheet = "Dados_Ajustados", 
  col_types = c(
    "numeric", "text", "numeric", "numeric", "text", 
    "text", "text", "text", "text", "date", 
    "date", "text", "numeric", "numeric", 
    "numeric", "numeric", "numeric", 
    "numeric", "numeric", "numeric", 
    "numeric", "numeric", "numeric", 
    "numeric", "numeric", "numeric", 
    "numeric", "numeric", "numeric", 
    "numeric", "numeric", "numeric", 
    "numeric", "numeric", "numeric", 
    "numeric", "numeric", "numeric", 
    "numeric", "numeric", "numeric", 
    "numeric", "numeric", "numeric", 
    "numeric", "numeric", "numeric", 
    "numeric", "numeric", "numeric", 
    "numeric"),
  range = "A1:AY99", #alteracao_2
  trim_ws = TRUE
) %>% 
  janitor::clean_names() %>% 
  rename(
    e_coli = escherichia_coli,
    dbo = demanda_bioquimica_de_oxigenio,
    mercurio = mercurio_em_micrograma_por_litro_ug_l
  ) %>% 
  mutate(
    municipio = str_to_title(municipio),
    data_coleta = ymd(data_coleta),
    ano_coleta = year(data_coleta),
    # hora_coleta = parse_datetime(hora_coleta),
  ) %>%
  dplyr::select( #reordenando as colunas
    c(1:10),
    ano_coleta,
    everything()
  )

5 Sumários estatísticos

sumario <- plan_litoral_medio %>%
  dplyr::select(cod_estacao, oxigenio_dissolvido, ano_coleta) %>%
  filter(ano_coleta > "2013" &
           ano_coleta <= "2025") %>%
  group_by(cod_estacao) %>%
  summarize(
    min =
      min(oxigenio_dissolvido,
          na.rm = TRUE),
    q1 =
      quantile(oxigenio_dissolvido, 0.20,
               na.rm = TRUE),
    median =
      median(oxigenio_dissolvido,
             na.rm = TRUE),
    mean =
      mean(oxigenio_dissolvido,
           na.rm= TRUE),
    q3 =
      quantile(oxigenio_dissolvido, 0.80,
               na.rm = TRUE),
    max =
      max(oxigenio_dissolvido,
          na.rm = TRUE))

sumario
output
## # A tibble: 6 × 7
##   cod_estacao   min    q1 median  mean    q3   max
##   <chr>       <dbl> <dbl>  <dbl> <dbl> <dbl> <dbl>
## 1 87332500     0     3.3    4.94  4.75  6.73  9.23
## 2 87420130     8.14  8.58   9.06  9.15  9.67 10.6 
## 3 87420150     6.7   8.19   8.41  8.49  8.64  9.83
## 4 87420350     5.93  6.96   8.34  8.07  9.23  9.64
## 5 87420500     4.65  6.43   7.25  7.50  8.73 11.0 
## 6 87510010     2.32  3.72   5.9   5.53  7.30  8.24

5.1 Visualização da estrutura de dados da planilha

Conferir se o tipo dos dados está correto, data em formato de data (date/dttm), código da estação como character (chr), valor medido dos parâmetros como double (dbl).

glimpse(plan_litoral_medio)
output
## Rows: 98
## Columns: 52
## $ indice                      <dbl> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,…
## $ cod_estacao                 <chr> "87332500", "87332500", "87332500", "87332…
## $ latitude                    <dbl> -29.91447, -29.91447, -29.91447, -29.91447…
## $ longitude                   <dbl> -50.31819, -50.31819, -50.31819, -50.31819…
## $ bacia_hidrografica          <chr> "Litoral Médio", "Litoral Médio", "Litoral…
## $ recurso_hidrico             <chr> "Lagoa dos Barros", "Lagoa dos Barros", "L…
## $ regiao                      <chr> "Litoral", "Litoral", "Litoral", "Litoral"…
## $ municipio                   <chr> "Osorio", "Osorio", "Osorio", "Osorio", "O…
## $ ambiente                    <chr> "Lêntico", "Lêntico", "Lêntico", "Lêntico"…
## $ data_coleta                 <date> 2016-06-29, 2016-09-26, 2016-12-14, 2017-…
## $ ano_coleta                  <dbl> 2016, 2016, 2016, 2017, 2017, 2017, 2017, …
## $ hora_coleta                 <time> 10:50:00, 11:05:00, 10:21:00, 11:00:00, 1…
## $ chuva_24h                   <chr> "AUSENTE", "AUSENTE", "AUSENTE", "AUSENTE"…
## $ alcalinidade                <dbl> 35.0, 11.0, 7.7, 42.5, 22.1, 14.9, 19.4, 3…
## $ aluminio                    <dbl> NA, NA, NA, NA, NA, NA, NA, 0.0015, 0.0120…
## $ cadmio                      <dbl> NA, NA, NA, NA, 0.003, 0.003, 0.001, 0.001…
## $ chumbo                      <dbl> NA, NA, NA, NA, NA, NA, NA, 0.002, 0.016, …
## $ cloreto                     <dbl> 27.80, 10.10, 9.60, 14.30, 10.10, 8.60, 8.…
## $ clorofila_a                 <dbl> NA, 2.19, 7.64, 40.10, 5.53, 3.56, 2.67, 1…
## $ cobre                       <dbl> NA, NA, NA, NA, 0.0040, 0.0020, 0.0030, 0.…
## $ coliformes_termotolerantes  <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
## $ coliformes_totais           <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
## $ condutividade               <dbl> 123.3, 81.0, 66.6, 139.1, 65.4, 69.0, 75.6…
## $ cromo_total                 <dbl> NA, NA, NA, NA, NA, NA, NA, 0.002, 0.009, …
## $ dbo                         <dbl> 3, 1, 2, 4, 2, 2, 2, 4, 4, 1, 3, 3, 1, 2, …
## $ demanda_quimica_de_oxigenio <dbl> 31, 15, 27, 24, 14, 17, 32, 40, 38, 23, 22…
## $ e_coli                      <dbl> 173.1, 28.8, 122.3, 770.1, 49.6, 34.7, 344…
## $ ferro                       <dbl> NA, NA, NA, NA, 3.120, 3.550, 1.940, 2.960…
## $ fitoplancton_cianobacterias <dbl> 171, 47, 1368, 129, 438, 68, 242, 2901, 18…
## $ fosfato_orto                <dbl> 0.071, 0.101, 0.089, 0.184, 0.109, 0.118, …
## $ fosforo_total               <dbl> 0.105, 0.202, 0.220, 0.233, 0.113, 0.184, …
## $ manganes                    <dbl> NA, NA, NA, NA, 0.051, 0.045, 0.066, 0.112…
## $ mercurio                    <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
## $ niquel                      <dbl> NA, NA, NA, NA, 0.0055, 0.0140, 0.0055, 0.…
## $ nitrato                     <dbl> NA, NA, 0.15, NA, NA, NA, NA, NA, NA, NA, …
## $ nitrogenio_amoniacal        <dbl> 0.032, 0.135, 0.530, 0.603, 0.174, 0.163, …
## $ nitrogenio_organico         <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
## $ nitrogenio_total_kjeldahl   <dbl> NA, 0.910, 1.350, 0.684, 1.120, NA, 1.907,…
## $ oxigenio_dissolvido         <dbl> 5.11, 6.39, 6.77, 3.25, 7.63, 7.50, 3.56, …
## $ ph                          <dbl> 6.48, 7.10, 6.21, 6.67, 6.73, 6.71, 6.27, …
## $ profundidade_coleta         <dbl> 0.88, 0.20, 0.20, 0.20, 0.20, 0.20, 0.20, …
## $ profundidade_total          <dbl> 2.40, 2.75, 2.75, 1.75, 2.15, 2.75, 3.00, …
## $ salinidade                  <dbl> NA, 0.04, NA, 0.07, 0.03, 0.03, 0.03, 0.07…
## $ solidos_dissolvidos_totais  <dbl> 100, 74, 123, 100, 87, 57, 86, 152, 20, 11…
## $ solidos_suspensos_totais    <dbl> 5.0, 15.0, 5.0, 13.0, 5.0, 21.0, 11.0, 15.…
## $ solidos_totais              <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
## $ temperatura_da_agua         <dbl> 14.40, 17.43, 24.89, 23.30, 16.01, 20.36, …
## $ temperatura_do_ar           <dbl> 13.00, 16.00, 19.50, 23.00, 17.16, 21.30, …
## $ transparencia_da_agua       <dbl> 0.4, 0.2, 0.3, 0.3, 0.3, 0.2, 0.3, 0.3, 0.…
## $ turbidez                    <dbl> 23.00, 12.00, 49.10, 23.50, 15.50, 79.60, …
## $ vazao_recurso_hidrico       <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA…
## $ zinco                       <dbl> NA, NA, NA, NA, 0.0150, 0.0240, 0.0190, 0.…
# str(plan_litoral_medio) #outra maneira de visualizar a eSTRutura 

6 Requisitos pra gerar os gráficos

6.1 Definir o theme

Definindo uma cor de letra e de fundo padrão a ser adotada nos gráficos.

theme_grafs <- function(bg = "white", 
                        coloracao_letra = "black") {
  theme(
    plot.title = 
      element_text(
        hjust = 0.5,
        color = coloracao_letra,
        size = 19),
    
    axis.title.x = 
      # element_text(
      # color = coloracao_letra,
      # size = 15,
      # angle = 0,),
      element_blank(),
    axis.title.y = element_text(
      color = coloracao_letra,
      size = 15,
      angle = 90),
    
    axis.text.x = element_text(
      color = coloracao_letra,
      size = 17),
    axis.text.y = element_text(
      color = coloracao_letra,
      size = 17,
      angle = 0),
    
    strip.background = element_rect(fill = bg,
                                    linetype = 1,
                                    size = 0.5,
                                    color = "black"),
    strip.text = element_text(size = 17),
    panel.background = element_rect(fill = bg),
    plot.background = element_rect(fill = bg),
    plot.margin = margin(l = 5, r = 10,
                         b = 5, t = 5)
  )
}

6.2 Criar função para gerar boxplots com percentis 20 e 80

f <- function(x) {
  r <- quantile(x, probs = c(0.10, 0.20, 0.50, 0.80, 0.90))
  names(r) <- c("ymin", "lower", "middle", "upper", "ymax")
  return(r)
}

7 Gráficos

7.1 Alterar nome e/ou ordem das estações

Atenção: Tomar muito cuidado com a ordem que estão dispostas as estações. Deve-se sempre respeitar o sentido nascente -> foz.

Conferir a ordem das estações através do mapa interativo, QGIS ou Google Earth Pro.

Elas acabam ficando fora de ordem por conta do código de ottobacias Para reordenar as estações, atente-se à função scale_x_discrete.

Neste exemplo iremos aprender a como mudar o nome das estações e reordená-las.

As estações estão na ordem certa, mas quero alterar o nome delas, como faço?


Utilizando o code chunk abaixo nós alteramos os nomes das estações para PM (ou Ponto de Monitoramento) seguido de um número. O PM1 representa o ponto mais próximo das nascentes, enquanto o PM6 o mais próximo da foz.

scale_x_discrete(
  limits = c(
    "87332500",
    "87420130",
    
    "87420150",
    "87420350",
    "87420500",
    "87510010"
  ),
  labels = c(
    "PM1", "PM2", "PM3", "PM4", "PM5", "PM6"
  )
)+

Perceba que iremos trocar a ordem das estações. Antes a estação 87332500 era a primeira a ser listada dentro da função limits = c(), ela era, portanto, o PM1. Agora o PM1 será a 87420130. Compare o código e o gráfico abaixo com o anterior.

scale_x_discrete(
  limits = c(
    "87420130",
    "87332500",
    
    "87420150",
    "87420350",
    "87420500",
    "87510010"
  ),
  labels = c(
    "PM1", "PM2", "PM3", "PM4", "PM5", "PM6"
  )
)+

“Ok mas… e se eu não quiser alterar o código ottobacias para PM1, PM2, só a ordem das estações, o que devo fazer?” Basta replicar a sequência correta das estações de limits = c() dentro da função labels = c().

   scale_x_discrete(
     limits = c(
       "87420130",
       "87332500",
       "87420150",
       "87420350",
       "87420500",
       "87510010"
     ),
     labels = c(
       "87420130",
       "87332500",
       "87420150",
       "87420350",
       "87420500",
       "87510010"
     )
   )+

Obs: Para a Bacia Hidrográfica do Rio Gravataí esse processo é necessário.

Sempre tomar cuidado com os limites do eixo y. Deixei como padrão o R buscar automaticamente qual o valor mínimo e máximo daquele parâmetro, mas o ideal é que se ajuste caso a caso.

Caso queira alterar o tamanho dos outliers, alterar o size nesse trecho dos códigos:

ggbeeswarm::geom_quasirandom(
     # grouponX = FALSE,
     size = 1.2, 
     alpha = .25,
     width = .07,
   )+

Todos os gráficos foram gerados utilizando como padrão os limites da Resolução nº 357/05 do CONAMA para ambientes lóticos. Caso queira alterar os limites para adequar aos ambientes lênticos, deve-se editar os ymin e ymax de cada retângulo (rect) do referido parâmetro.

Não esquecer que o R entende a casa decimal como ponto, e não como vírgula.

annotate("rect",
         xmin = -Inf, xmax = Inf,
         ymin = 13.3, ymax = Inf,
         alpha = 1,
         fill = "#ac5079")+ #>pior classe
annotate("rect",
         xmin = -Inf, xmax = Inf,
         ymin = 3.7, ymax = 13.3,
         alpha = 1,
         fill = "#fcf7ab")+ #classe 3
annotate("rect",
         xmin = -Inf, xmax = Inf,
         ymin = 0, ymax = 3.7,
         alpha = 1,
         fill = "#8dcdeb")+ #classe 1

7.2 Parâmetros de Qualidade da Água

7.2.1 Oxigênio Dissolvido

(graf_od <- plan_litoral_medio %>%
   ggplot(
     aes(
       x = cod_estacao,
       y = oxigenio_dissolvido,
     )
   )+
   annotate("rect",
            xmin = -Inf, xmax = Inf,
            ymin = -Inf, ymax = 2,
            alpha = 1,
            fill = "#ac5079")+ #>pior classe
   annotate("rect",
            xmin = -Inf, xmax = Inf,
            ymin = 2, ymax = 4,
            alpha = 1,
            fill = "#eb5661")+ #classe 4
   annotate("rect",
            xmin = -Inf, xmax = Inf,
            ymin = 4, ymax = 5,
            alpha = 1,
            fill = "#fcf7ab")+ #classe 3
   annotate("rect",
            xmin = -Inf, xmax = Inf,
            ymin = 5, ymax = 6,
            alpha = 1,
            fill = "#70c18c")+ #classe 2
   annotate("rect",
            xmin = -Inf, xmax = Inf,
            ymin= 6, ymax = Inf,
            alpha = 1,
            fill = "#8dcdeb")+ #classe 1
   stat_summary(
     fun.data = f,
     geom = 'errorbar',
     width = 0.3,
     position = position_dodge(width = 0.65),
   )+
   stat_summary(
     fun.data = f,
     geom = "boxplot",
     width = 0.7,
     fill = '#F8F8FF',
     color = "black",
     outlier.shape = 1, #se deixar NA fica só o jitter, se não, deixa 1
   )+
   # facet_wrap(~periodo)+
   labs(
     title = "Oxigênio Dissolvido",
     x= NULL,
     y="mg/L"
   )+
   ggbeeswarm::geom_quasirandom(
     size = 1.2,
     alpha = .25,
     width = .07,
   )+
   scale_y_continuous(
     expand = expansion(mult = c(0,0)),
     n.breaks = 11,
     # limits = c(-0.3,21)
     limits = c(
       min(plan_litoral_medio$oxigenio_dissolvido, na.rm = TRUE),
       max(plan_litoral_medio$oxigenio_dissolvido, na.rm = TRUE)+1)
   )+
   # scale_x_discrete(
   #   limits = c(
   #     "87332500",
   #     "87420130",
   #     "87420150",
   #     "87420350",
   #     "87420500",
   #     "87510010"
   #   ),
   #   labels = c(
   #     "PM1", "PM2", "PM3", "PM4", "PM5", "PM6"
   #   )
   # )+
   geom_smooth(
     method = "lm",
     se = FALSE, #se deixar TRUE gera o intervalo de confiança de 95%
     aes(group = 1),
     alpha = 0.5,
     na.rm = TRUE,
     size = 1
   )+
   theme_grafs()
)

Oxigênio Dissolvido

7.2.2 DBO

(graf_dbo <- ggplot(plan_litoral_medio,
                    aes(x = cod_estacao,
                   y = dbo))+
   annotate("rect",
            xmin = -Inf, xmax = Inf,
            ymin = 10, ymax = Inf,
            alpha = 1,
            fill = "#ac5079")+ #>pior classe
   annotate("rect",
            xmin = -Inf, xmax = Inf,
            ymin = 5, ymax = 10,
            alpha = 1,
            fill = "#fcf7ab")+ #classe 3
   annotate("rect",
            xmin = -Inf, xmax = Inf,
            ymin = 3, ymax = 5,
            alpha = 1,
            fill = "#70c18c")+ #classe 2
   annotate("rect",
            xmin = -Inf, xmax = Inf,
            ymin = 0, ymax = 3,
            alpha = 1,
            fill = "#8dcdeb")+ #classe 1
   stat_summary(
     fun.data = f,
     geom = 'errorbar',
     width = 0.3,
     position = position_dodge(width = 0.65),
   )+
   stat_summary(
     fun.data = f,
     geom = "boxplot",
     width = 0.7,
     fill = '#F8F8FF',
     color = "black",
     outlier.shape = 1, #se deixar NA fica só o jitter, se não, deixa 1
   )+
   # facet_wrap(~periodo)+
   labs(title = "Demanda Bioquímica de Oxigênio",
        x="Estação",
        y="mg/L")+
   ggbeeswarm::geom_quasirandom(
     # grouponX = FALSE,
     size = 1.2,
     alpha = .25,
     width = .07,
   )+
   # scale_x_discrete(limits = c("87398500", 
   #                             "87398980", 
   #                             "87398900", 
   #                             "87398950", 
   #                             "87405500", 
   #                             "87406900", 
   #                             "87409900"),
   #                  labels = c("PM1", "PM2", "PM3", "PM4", "PM5", "PM6", "PM7")
   # )+
   scale_y_continuous(expand = expansion(mult = c(0.03,0.03)),
                      n.breaks = 8,
                      limits = c(
                        min(plan_litoral_medio$dbo, na.rm = TRUE),
                        10
                        # max(plan_litoral_medio$dbo, na.rm = TRUE)
                        ),
                      trans = "log10")+
   geom_smooth(method = "lm",
               se=FALSE, #se deixar TRUE gera o intervalo de confiança de 95%
               aes(group=1),
               alpha=.5,
               na.rm = TRUE,
               size = 1)+
   theme_grafs()
)

Demanda Bioquímica de Oxigênio

7.2.3 Escherichia coli

(graf_ecoli <- plan_litoral_medio %>% 
   ggplot(aes(cod_estacao,
              e_coli))+
   annotate("rect",
            xmin = -Inf, xmax = Inf,
            ymin = 3200, ymax = Inf,
            alpha = 1,
            fill = "#ac5079")+ #>pior classe
   annotate("rect",
            xmin = -Inf, xmax = Inf,
            ymin = 800, ymax = 3200,
            alpha = 1,
            fill = "#fcf7ab")+ #classe 3
   annotate("rect",
            xmin = -Inf, xmax = Inf,
            ymin = 160, ymax = 800,
            alpha = 1,
            fill = "#70c18c")+ #classe 2
   annotate("rect",
            xmin = -Inf, xmax = Inf,
            ymin = 0, ymax = 160,
            alpha = 1,
            fill = "#8dcdeb")+ #classe 1
   stat_summary(
     fun.data = f,
     geom = 'errorbar',
     width = 0.3,
     position = position_dodge(width = 0.65),
   )+
   stat_summary(
     fun.data = f,
     geom = "boxplot",
     width = 0.7,
     fill = '#F8F8FF',
     color = "black",
     outlier.shape = 1, #se deixar NA fica só o jitter, se não, deixa 1
   )+
   # facet_wrap(~periodo)+
   labs(title = "*Escherichia coli*",
        x="Estação",
        y="NMP/100mL")+
   scale_y_continuous(expand = expansion(mult = c(0.01, 0.01)),
                      # n.breaks = 9,
                      n.breaks = 6,
                      limits = c(min(plan_litoral_medio$e_coli, na.rm = TRUE),
                                 max(plan_litoral_medio$e_coli, na.rm = TRUE)),
                      trans = "log10",
                      labels = scales::number_format(accuracy = 1,
                                                     decimal.mark = ",",
                                                     big.mark = " "))+
   ggbeeswarm::geom_quasirandom(
     size = 1.2,
     alpha = .25,
     width = .07,
   )+
 # scale_x_discrete(limits = c("87398500",
 #                             "87398980",
 #                             "87398900",
 #                             "87398950",
 #                             "87405500",
 #                             "87406900",
 #                             "87409900"),
 #                  labels = c("PM1", "PM2", "PM3", "PM4", "PM5", "PM6", "PM7")
 # )+
 geom_smooth(method = "lm",
 se=FALSE, #stardand error = desvio padrão -> se deixar TRUE gera o intervalo de confiança de 95%
             aes(group=1),
             alpha= 0.5, #transparencia de 50%
             na.rm = TRUE, #remover NAs
             size = 1)+
 theme_grafs()+
   theme(
     axis.text.y = element_text(
       angle = 90,
       # size=15,
       # face=2
     ),
     plot.title = 
       element_markdown(
         hjust = 0.5,
         color = "black",
         size = 19),
   )
)

Escherichia-coli

7.2.4 Fósforo Total

(graf_ptot <- ggplot(plan_litoral_medio,
                     aes(cod_estacao,
                         fosforo_total))+
   annotate("rect",
            xmin = -Inf, xmax = Inf,
            ymin = 0.15, ymax = Inf,
            alpha = 1,
            fill = "#ac5079")+ #>pior classe
   annotate("rect",
            xmin = -Inf, xmax = Inf,
            ymin = 0.1, ymax = 0.15,
            alpha = 1,
            fill = "#fcf7ab")+ #classe 3
   annotate("rect",
            xmin = -Inf, xmax = Inf,
            ymin = 0, ymax = 0.1,
            alpha = 1,
            fill = "#8dcdeb")+ #classe 1
   stat_summary(
     fun.data = f,
     geom = 'errorbar',
     width = 0.3,
     position = position_dodge(width = 0.65),
   )+
   stat_summary(
     fun.data = f,
     geom = "boxplot",
     width = 0.7,
     fill = '#F8F8FF',
     color = "black",
     outlier.shape = 1, #se deixar NA fica só o jitter, se não, deixa 1
   )+
   # facet_wrap(~periodo)+
   labs(title = "Fósforo total",
        x="Estação",
        y="mg/L")+
   scale_y_continuous(expand = expansion(mult = c(0.03,0.03)),
                      n.breaks = 8,
                      limits = c(min(plan_litoral_medio$fosforo_total, na.rm = TRUE),
                                 max(plan_litoral_medio$fosforo_total), na.rm = TRUE),
                      trans = "log10",
                      labels = scales::number_format(accuracy = .001,
                                                     decimal.mark = ",",
                                                     big.mark = " ")
   )+
   ggbeeswarm::geom_quasirandom(
     size = 1.2,
     alpha = .25,
     width = .07,
   )+
   # scale_x_discrete(limits = c("87398500", 
   #                             "87398980", 
   #                             "87398900", 
   #                             "87398950", 
   #                             "87405500", 
   #                             "87406900", 
   #                             "87409900"),
   #                  labels = c("PM1", "PM2", "PM3", "PM4", "PM5", "PM6", "PM7")
   # )+
   geom_smooth(method = "lm",
               se=FALSE, #se deixar TRUE gera o intervalo de confiança de 95%
               aes(group=1),
               alpha=.5,
               na.rm = TRUE,
               size = 1)+
   theme_grafs()
)

Fósforo total

7.2.5 Nitrogênio amoniacal

(graf_namon <- ggplot(plan_litoral_medio,
                 aes(cod_estacao,
                     nitrogenio_amoniacal))+
   annotate("rect",
            xmin = -Inf, xmax = Inf,
            ymin = 13.3, ymax = Inf,
            alpha = 1,
            fill = "#ac5079")+ #>pior classe
   annotate("rect",
            xmin = -Inf, xmax = Inf,
            ymin = 3.7, ymax = 13.3,
            alpha = 1,
            fill = "#fcf7ab")+ #classe 3
   annotate("rect",
            xmin = -Inf, xmax = Inf,
            ymin = 0, ymax = 3.7,
            alpha = 1,
            fill = "#8dcdeb")+ #classe 1
   stat_summary(
     fun.data = f,
     geom = 'errorbar',
     width = 0.3,
     position = position_dodge(width = 0.65),
   )+
   stat_summary(
     fun.data = f,
     geom = "boxplot",
     width = 0.7,
     fill = '#F8F8FF',
     color = "black",
     outlier.shape = 1, #se deixar NA fica só o jitter, se não, deixa 1
   )+
   # facet_wrap(~periodo)+
   labs(title = "Nitrogênio amoniacal",
        x="Estação",
        y="mg/L")+
   scale_y_continuous(expand = expansion(mult = c(0.01, 0.05)),
                      n.breaks = 9,
                      limits = c(min(plan_litoral_medio$nitrogenio_amoniacal, na.rm = TRUE),
                                 15
                                 # max(plan_litoral_medio$nitrogenio_amoniacal, na.rm = TRUE)
                                 ),
                      trans = "log10",
                      labels = scales::number_format(accuracy = .001,
                                                     decimal.mark = ",",
                                                     big.mark = " "))+
   ggbeeswarm::geom_quasirandom(
     size = 1.2,
     alpha = .25,
     width = .07,
   )+
   # scale_x_discrete(limits = c("87398500", 
   #                             "87398980", 
   #                             "87398900", 
   #                             "87398950", 
   #                             "87405500", 
   #                             "87406900", 
   #                             "87409900"),
   #                  labels = c("PM1", "PM2", "PM3", "PM4", "PM5", "PM6", "PM7")
   # )+
   geom_smooth(method = "lm",
               se=FALSE, #se deixar TRUE gera o intervalo de confiança de 95%
               aes(group=1),
               alpha=.5,
               na.rm = TRUE,
               size = 1)+
   theme_grafs()
)

Nitrogênio Amoniacal

7.2.6 Turbidez

(graf_turb <- ggplot(plan_litoral_medio,
                   aes(cod_estacao,
                       turbidez))+
   annotate("rect",
            xmin = -Inf, xmax = Inf,
            ymin = 100, ymax = Inf,
            alpha = 1,
            fill = "#ac5079")+ #>pior classe
   annotate("rect",
            xmin = -Inf, xmax = Inf,
            ymin = 40, ymax = 100,
            alpha = 1,
            fill = "#fcf7ab")+ #classe 3
   annotate("rect",
            xmin = -Inf, xmax = Inf,
            ymin = 0, ymax = 40,
            alpha = 1,
            fill = "#8dcdeb")+ #classe 1
   stat_summary(
     fun.data = f,
     geom = 'errorbar',
     width = 0.3,
     position = position_dodge(width = 0.65),
   )+
   stat_summary(
     fun.data = f,
     geom = "boxplot",
     width = 0.7,
     fill = '#F8F8FF',
     color = "black",
     outlier.shape = 1, #se deixar NA fica só o jitter, se não, deixa 1
   )+
   # facet_wrap(~periodo)+
   labs(title = "Turbidez",
        x="Estação",
        y="UNT")+
   scale_y_continuous(expand = expansion(mult = c(0.05, 0.05)),
                      n.breaks = 8,
                      limits = c(
                        # 1,
                        min(plan_litoral_medio$turbidez, na.rm = TRUE),
                        # 500
                        max(plan_litoral_medio$turbidez, na.rm = TRUE)
                      ),
                      trans = "log10",
                      labels = scales::number_format(accuracy = 1,
                                                     decimal.mark = ",",
                                                     big.mark = " "))+
    ggbeeswarm::geom_quasirandom(
     size = 1.2,
     alpha = .25,
     width = .07,
   )+
   # scale_x_discrete(limits = c("87398500", 
   #                             "87398980", 
   #                             "87398900", 
   #                             "87398950", 
   #                             "87405500", 
   #                             "87406900", 
   #                             "87409900"),
   #                  labels = c("PM1", "PM2", "PM3", "PM4", "PM5", "PM6", "PM7")
   # )+
   geom_smooth(method = "lm",
               se=FALSE, #se deixar TRUE gera o intervalo de confiança de 95%
               aes(group=1),
               alpha=.5,
               na.rm = TRUE,
               size = 1)+
   theme_grafs()
)

turbidez

7.2.7 pH

(graf_pH <- ggplot(plan_litoral_medio,
                 aes(cod_estacao,
                     ph))+
   annotate("rect",
            xmin=-Inf,
            xmax=Inf,
            ymin=-Inf,
            ymax=6,
            alpha=1,
            fill="#eb5661")+ #classe 4
   annotate("rect",
            xmin=-Inf,
            xmax=Inf,
            ymin=9,
            ymax=Inf,
            alpha=1,
            fill="#eb5661")+ #classe 4
   annotate("rect",
            xmin=-Inf,
            xmax=Inf,
            ymin=6,
            ymax=9,
            alpha=1,
            fill="#8dcdeb")+ #classe 1
   stat_summary(
     fun.data = f,
     geom = 'errorbar',
     width = 0.3,
     position = position_dodge(width = 0.65),
   )+
   stat_summary(
     fun.data = f,
     geom = "boxplot",
     width = 0.7,
     fill = '#F8F8FF',
     color = "black",
     outlier.shape = 1, #se deixar NA fica só o jitter, se não, deixa 1
   )+
   # facet_wrap(~periodo)+
   labs(title = "pH",
        x="Estação",
        y="")+
   scale_y_continuous(expand = expansion(mult = c(0.01, 0.01)),
                      n.breaks = 8,
                      limits = c(4,11),
                      labels = scales::number_format(accuracy = 1,
                                                     decimal.mark = ",",
                                                     big.mark = " ")
                      )+
    ggbeeswarm::geom_quasirandom(
     size = 1.2,
     alpha = .25,
     width = .07,
   )+
   # scale_x_discrete(limits = c("87398500", 
   #                             "87398980", 
   #                             "87398900", 
   #                             "87398950", 
   #                             "87405500", 
   #                             "87406900", 
   #                             "87409900"),
   #                  labels = c("PM1", "PM2", "PM3", "PM4", "PM5", "PM6", "PM7")
   # )+
   geom_smooth(method = "lm",
               se=FALSE, #se deixar TRUE gera o intervalo de confiança de 95%
               aes(group=1),
               alpha=.5,
               na.rm = TRUE,
               size = 1)+
   theme_grafs()
)

pH

7.2.8 Sólidos Totais

O parâmetro Sólidos Totais não teve medições no período analisado, então fica armazenado na tabela como valor vazio, ou rNA`. Quando você for fazer análise e tiver valores, altere o eval para TRUE.

(graf_solidos_totais <- ggplot(plan_litoral_medio,
                               aes(cod_estacao,
                                   solidos_totais))+
   annotate("rect",
            xmin = -Inf, xmax = Inf,
            ymin = 500, ymax = Inf,
            alpha = 1,
            fill="#ac5079")+ #>pior classe
   annotate("rect",
            xmin = -Inf, xmax = Inf,
            ymin = -Inf, ymax = 500,
            alpha = 1,
            fill="#8dcdeb")+ #classe 1
stat_summary(
     fun.data = f,
     geom = 'errorbar',
     width = 0.3,
     position = position_dodge(width = 0.65),
   )+
   stat_summary(
     fun.data = f,
     geom = "boxplot",
     width = 0.7,
     fill = '#F8F8FF',
     color = "black",
     outlier.shape = 1, #se deixar NA fica só o jitter, se não, deixa 1
   )+
   # facet_wrap(~periodo)+
   labs(title = "Sólidos totais",
        x="Estação",
        y="")+
   scale_y_continuous(expand = expansion(mult = c(0.01, 0.05)),
                      n.breaks = 8,
                      limits = c(0,
                                 max(plan_litoral_medio$solidos_totais, na.rm = TRUE)
                                 ),
                      labels = scales::number_format(accuracy = 1,
                                                     decimal.mark = ",",
                                                     big.mark = " "))+
   ggbeeswarm::geom_quasirandom(
     size = 1.2,
     alpha = .25,
     width = .07,
   )+
   # scale_x_discrete(limits = c("87398500",
   #                             "87398980",
   #                             "87398900",
   #                             "87398950",
   #                             "87405500",
   #                             "87406900",
   #                             "87409900"),
   #                  labels = c("PM1", "PM2", "PM3", "PM4", "PM5", "PM6", "PM7")
   # )+
   geom_smooth(method = "lm",
               se=FALSE, #se deixar TRUE gera o intervalo de confiança de 95%
               aes(group=1),
               alpha=.5,
               na.rm = TRUE,
               size = 1)+
   theme_grafs()
)

7.2.9 Condutividade

(graf_cond_elet <- ggplot(plan_litoral_medio,
                          aes(cod_estacao,
                              condutividade))+
   annotate("rect",
            xmin = -Inf, xmax = Inf,
            ymin = 500, ymax = Inf,
            alpha = 1,
            fill = "#eb5661")+ #classe 4
   annotate("rect",
            xmin = -Inf, xmax = Inf,
            ymin = 0, ymax = 500,
            alpha = 1,
            fill = "#8dcdeb")+ #classe 1
  stat_summary(
     fun.data = f,
     geom = 'errorbar',
     width = 0.3,
     position = position_dodge(width = 0.65),
   )+
   stat_summary(
     fun.data = f,
     geom = "boxplot",
     width = 0.7,
     fill = '#F8F8FF',
     color = "black",
     outlier.shape = 1, #se deixar NA fica só o jitter, se não, deixa 1
   )+
   # facet_wrap(~periodo)+
   labs(title = "Condutividade elétrica",
        x="Estação",
        y="µmhos/cm")+
   scale_y_continuous(expand = expansion(mult = c(0.05, 0.05)),
                      n.breaks = 8,
                      limits = c(min(plan_litoral_medio$condutividade, na.rm = TRUE),
                                 max(plan_litoral_medio$condutividade, na.rm = TRUE)),
                      trans = "log10",
                      labels = scales::number_format(accuracy = 1,
                                                     decimal.mark = ",",
                                                     big.mark = " "))+
   ggbeeswarm::geom_quasirandom(
     size = 1.2,
     alpha = .25,
     width = .07,
   )+
   # scale_x_discrete(limits = c("87398500", 
   #                             "87398980", 
   #                             "87398900", 
   #                             "87398950", 
   #                             "87405500", 
   #                             "87406900", 
   #                             "87409900"),
   #                  labels = c("PM1", "PM2", "PM3", "PM4", "PM5", "PM6", "PM7")
   # )+
   geom_smooth(method = "lm",
               se=FALSE, #se deixar TRUE gera o intervalo de confiança de 95%
               aes(group=1),
               alpha=.5,
               na.rm = TRUE,
               size = 1)+
   theme_grafs()+
   theme(
     axis.text.y = element_text(
       angle = 90,
       # size=15,
       # face=2
     )
   )
)

condutividade-eletrica

7.3 Análise ao longo do tempo

Para gerar um gráfico ao longo do tempo pra cada uma das estações é necessário alterar o ano_inicial e o ano_final. Também é necessário selecionar qual parâmetro que se quer fazer a visualização.

ano_inicial <- 2015
ano_final <- 2022

(timeline <- plan_litoral_medio %>%
  filter(ano_coleta > ano_inicial &
           ano_coleta <= ano_final) %>%
  dplyr::select(cod_estacao, e_coli, data_coleta) %>%
  group_by(cod_estacao) %>%
  ggplot(
    aes(x = data_coleta,
        y = e_coli,
        color = cod_estacao
    ))+
    geom_line(
      # aes(color = CODIGO),
      na.rm = TRUE)+
    geom_point(
      # aes(color = CODIGO),
      na.rm = TRUE)+
    scale_x_date(
      limits = as.Date(c(
        ymd(glue("{ano_inicial}-01-01")),
        ymd(glue("{ano_final}-01-01"))
        # NA #pode usar NA também
      )),
      expand = c(0.0, 0.0),
      date_breaks = "2 years",
      minor_breaks = "1 years",
      date_labels = "%Y",
    )+
  # geom_smooth(
  #   method = "lm", #regressao linear
  #   se = TRUE, #se deixar TRUE gera o intervalo de confiança de 95%
  #   aes(group = 1),
  #   alpha =.5,
  #   na.rm = TRUE,
  #   size = 0.3,
  #   # fullrange = TRUE,
  #   show.legend = TRUE
  # )+
  stat_smooth(
    geom = "smooth",
    # span = 0.2,
    se = TRUE, #se deixar TRUE gera o intervalo de confiança de 95%
    # aes(group = 1),
    # alpha =.5,
    na.rm = TRUE,
    # size = 0.3,
    fullrange = TRUE,
    show.legend = TRUE
  )+
  facet_wrap(
    ~cod_estacao,
    nrow = 4,
  )+
  theme_bw()
)

7.4 Correlação

parametros_iqa_lit_medio <- plan_litoral_medio %>%
  dplyr::select(cod_estacao,
         ph,
         dbo,
         e_coli,
         nitrogenio_amoniacal,
         # nitro_kjeldahl,
         # nitro_total,
         fosforo_total,
         temperatura_da_agua,
         turbidez,
         solidos_totais,
         oxigenio_dissolvido,
         condutividade,
         ano_coleta
         ) 

parametros_iqa_lit_medio %>% 
  dplyr::select(
    -cod_estacao,
    -ano_coleta,
    -solidos_totais
    ) %>%
  # group_by(cod_estacao) %>%
  rename(
    CE = condutividade,
    OD = oxigenio_dissolvido,
    # ST = solidos_totais,
    Turb = turbidez,
    Temp = temperatura_da_agua,
    Ptot = fosforo_total,
    NAmon = nitrogenio_amoniacal,
    pH = ph,
    DBO = dbo,
    E_coli = e_coli
    # NTK = nitro_kjeldahl
  ) %>% 
  ggcorr(
    method =
    "complete.obs",
    # "pearson",
    # "pairwise",
    name = "Correlação",
    label = TRUE,
    label_alpha = TRUE,
    digits = 3,
    low = "#3B9AB2",
    mid = "#EEEEEE",
    high = "#F21A00",
    # palette = "RdYlBu",
    layout.exp = 0,
    legend.position = "left",
    label_round = 3,
    # legend.size = 18,
    geom = "tile",
    nbreaks = 10,
  )+
  labs(title = "Correlação entre parâmetros físico-químicos na\nBacia Hidrográfica do Litoral Médio")+
  theme_linedraw()+
  theme(
    legend.position = c(0.15, 0.6),
    legend.title = element_text(size = 16),
    legend.text = element_text(size = 14),
    # legend.spacing = unit(element_text(),
                          # units = 5)
    plot.title = element_text(hjust = 0.5,
                              size = 16)
  )

correlação-parametros-qualidade-agua

7.4.1 Correlação entre parâmetros que compõem o IQA com significância estatística

Esse processo demanda bastante processamento, para desabilitá-lo deixe eval = FALSE.

correl_IQA_lit_medio <- parametros_iqa_lit_medio %>%
  dplyr::select(-cod_estacao) %>%
  ggpairs(title = "Correlação entre parâmetros que compõem o IQA",
          axisLabels = "show")
correl_IQA_lit_medio
plot

7.5 Salvar os gráficos

Replicar esse modelo pros gráficos que deseja salvar.
1. Criar novo code chunk (Ctrl+Alt+I)
2. Copiar a fórmula abaixo
3. Colar nesse novo code chunk

Os gráficos ficarão salvos em uma pasta que irá ser criada a partir do código.

ggsave("graf_od.png",
       plot = graf_od, #alteracao
       path = "./graficos",
       dpi = 300,
       type = "cairo")

8 Mapas

8.1 Pacotes pra geração de mapas

pacman::p_load(raster, leaflet, sf
               # prettymapr, rjson, rosm,
               # ggspatial
               # rgdal, rgeos,
               # gtools, tidyverse, rnaturalearth,
               # rnaturalearthdata, reticulate, maptools,
               # maps, ggplot2, ggspatial, rgeos, ggmap
               )

8.2 Mapa estático

Importando as informações necessárias pra gerar mapas de precipitação.
Fonte: GADM 1, 2

Brasil <- getData(
  'GADM',
  country = 'Brazil',
  level = 3
) %>%
  st_as_sf()
## Warning in getData("GADM", country = "Brazil", level = 3): getData will be removed in a future version of raster
## . Please use the geodata package instead
RS <- subset(Brasil,
             NAME_1 == "Rio Grande do Sul")

lbl <- data.frame(month_abb = month.abb,
                  mes = 1:12)

plan_litoral_medio %>%
  ggplot(
    # aes(x = longtitude,
    #     y = latitude,
    #     map_id = region)
  )+
  geom_sf(
    data = RS
  )+
  theme_bw()
plot

Mapa estático do RS

# Definindo o SRC
RS <- RS %>%
  st_transform (crs = 4674) #4326 = WGS84, 4674 = SIRGAS2000

8.3 Mapa interativo com localização dos pontos de monitoramento

leaflet(RS) %>% 
  addProviderTiles(
    "Esri.WorldImagery" #Imagem de satélite
    # "OpenStreetMap.Mapnik" #OpenStreetMap -> Software livre
  ) %>% 
  addCircleMarkers(
    data = plan_litoral_medio,
    lng = ~longitude,
    lat = ~latitude,
    popup = ~paste(
      "<b>Estação:</b>",{cod_estacao},"<br>",
      "<b>Recurso hídrico:</b>", recurso_hidrico, "<br>",
      "<b>Município:</b>", municipio,
      sep = " "
    )
  ) 

Mapa interativo

8.4 Mapa de precipitação anual

Esse processo demanda bastante processamento, para desabilitá-lo deixe eval = FALSE.

st_centroid(RS)
output
## Simple feature collection with 1174 features and 16 fields
## Geometry type: POINT
## Dimension:     XY
## Bounding box:  xmin: -57.33034 ymin: -33.6509 xmax: -49.78182 ymax: -27.14727
## Geodetic CRS:  SIRGAS 2000
## First 10 features:
##       GID_0 NAME_0    GID_1            NAME_1 NL_NAME_1      GID_2     NAME_2
## 28115   BRA Brazil BRA.21_1 Rio Grande do Sul      <NA> BRA.21.1_1 Água Santa
## 28139   BRA Brazil BRA.21_1 Rio Grande do Sul      <NA> BRA.21.1_1 Água Santa
## 28163   BRA Brazil BRA.21_1 Rio Grande do Sul      <NA> BRA.21.1_1 Água Santa
## 28689   BRA Brazil BRA.21_1 Rio Grande do Sul      <NA> BRA.21.2_1      Agudo
## 28107   BRA Brazil BRA.21_1 Rio Grande do Sul      <NA> BRA.21.3_1  Ajuricaba
## 28119   BRA Brazil BRA.21_1 Rio Grande do Sul      <NA> BRA.21.3_1  Ajuricaba
## 27837   BRA Brazil BRA.21_1 Rio Grande do Sul      <NA> BRA.21.4_1    Alecrim
## 28607   BRA Brazil BRA.21_1 Rio Grande do Sul      <NA> BRA.21.5_1   Alegrete
## 28840   BRA Brazil BRA.21_1 Rio Grande do Sul      <NA> BRA.21.5_1   Alegrete
## 28842   BRA Brazil BRA.21_1 Rio Grande do Sul      <NA> BRA.21.5_1   Alegrete
##       NL_NAME_2        GID_3                         NAME_3 VARNAME_3 NL_NAME_3
## 28115      <NA> BRA.21.1.1_1                     Água Santa      <NA>      <NA>
## 28139      <NA> BRA.21.1.2_1                 Engenho Grande      <NA>      <NA>
## 28163      <NA> BRA.21.1.3_1 Santo Antonio dos Pinheirinhos      <NA>      <NA>
## 28689      <NA> BRA.21.2.1_1                          Agudo      <NA>      <NA>
## 28107      <NA> BRA.21.3.1_1                      Ajuricaba      <NA>      <NA>
## 28119      <NA> BRA.21.3.2_1                     Medianeira      <NA>      <NA>
## 27837      <NA> BRA.21.4.1_1                        Alecrim      <NA>      <NA>
## 28607      <NA> BRA.21.5.1_1                       Alegrete      <NA>      <NA>
## 28840      <NA> BRA.21.5.2_1                        Central      <NA>      <NA>
## 28842      <NA> BRA.21.5.3_1                          Leste      <NA>      <NA>
##         TYPE_3 ENGTYPE_3 CC_3 HASC_3                    geometry
## 28115 Distrito  District <NA>   <NA> POINT (-52.01191 -28.20432)
## 28139 Distrito  District <NA>   <NA>  POINT (-52.12523 -28.2061)
## 28163 Distrito  District <NA>   <NA> POINT (-52.08645 -28.26863)
## 28689 Distrito  District <NA>   <NA> POINT (-53.22639 -29.60797)
## 28107 Distrito  District <NA>   <NA> POINT (-53.77303 -28.21167)
## 28119 Distrito  District <NA>   <NA> POINT (-53.66801 -28.20777)
## 27837 Distrito  District <NA>   <NA> POINT (-54.78171 -27.65349)
## 28607 Distrito  District <NA>   <NA> POINT (-55.93205 -29.75749)
## 28840 Distrito  District <NA>   <NA> POINT (-55.78896 -29.78455)
## 28842 Distrito  District <NA>   <NA> POINT (-55.76203 -29.80277)
Prec <- getData(
  "worldclim",
  var = "prec",
  res = 0.5,
  lat = c(-30.033056, -29.68417), #procurar lat long no google e alterar aqui
  lon = c(-51.230000, -53.80694)
)

Prec_RS <- Prec %>%
  crop(RS) %>%
  mask(RS, na.rm = TRUE)

plot(Prec_RS)
plot

PPAnual_RS <- do.call("sum",
                       unstack(Prec_RS))
plot(PPAnual_RS)
plot

vls <- rasterToPoints(Prec_RS) %>%
  as_tibble() %>%
  gather(var, value, -x, -y) %>%
  mutate(mes = parse_number(var)) %>%
  inner_join(., lbl, by = 'mes') %>%
  dplyr::select(x, y, month_abb, value) %>%
  mutate(month_abb = factor(month_abb, levels = month.abb))

vls %>%
  filter(month_abb == 'Jan')
output
## # A tibble: 217,860 × 4
##        x     y month_abb value
##    <dbl> <dbl> <fct>     <dbl>
##  1 -53.1 -27.1 Jan         165
##  2 -53.0 -27.1 Jan         165
##  3 -53.0 -27.1 Jan         165
##  4 -53.0 -27.1 Jan         166
##  5 -53.0 -27.1 Jan         166
##  6 -53.4 -27.1 Jan         161
##  7 -53.4 -27.1 Jan         161
##  8 -53.4 -27.1 Jan         161
##  9 -53.1 -27.1 Jan         165
## 10 -53.1 -27.1 Jan         165
## # … with 217,850 more rows
summary(vls$value) #descobre o valor mínimo, médio e máximo de precipitação
output
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##    39.0   128.0   141.0   140.3   154.0   206.0

8.5 Mapa com precipitação mensal

Caso queira gerar um mapa com a precipitação mensal, alternar o eval para TRUE. A geração desse mapa demanda bastante processamento, recomendável manter include = FALSE e echo = FALSE.

plot

Ainda precisa ser implementado/ajustado

  • RSÁgua deve buscar dados anteriores a 2015.
  • A Fepam tem os dados de altitude das estações. A partir disso pode ser calculado o % de saturação de Oxigênio Dissolvido, necessário para o cálculo do IQA.
  • Tornar a coluna de chuva_24h como factor.
  • A coluna hora_coleta está com formato incorreto.
  • Gerar um Shiny Web App
  • Tornar a coluna de municipio com apenas a primeira letra maiúscula.
  • Sincronização via GitHub
  • Aprender a gerar o mapa de precipitação mensal pra todo o RS
    • O RS está entre 2 fusos, então acaba “partindo no meio” a figura
  • Futuramente: integração via Google Sheets.

Informações adicionais

E-mail para contato: leonardofwink@gmail.com

GitHub: https://github.com/leonardofwink/

LinkedIn: https://www.linkedin.com/in/leonardofwink/

LS0tDQp0aXRsZTogIlR1dG9yaWFsIC0gY29tbyBnZXJhciBvcyBncsOhZmljb3MgYm94cGxvdCBubyBSIGEgcGFydGlyIGRvIFJTw4FndWEgLSBGZXBhbSINCmF1dGhvcjogIkxlb25hcmRvIEZlcm5hbmRlcyBXaW5rIg0KZW1haWw6ICJsZW9uYXJkb2Z3aW5rQGdtYWlsLmNvbSINCmRhdGU6ICJgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVkLyVtLyVZJylgIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIGRpc3RpbGw6OmRpc3RpbGxfYXJ0aWNsZToNCiAgICBoaWdobGlnaHQ6IGhhZGRvY2sNCiAgICBrZWVwX21kOiB5ZXMNCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcw0KICAgIHRvYzogeWVzDQogICAgdG9jX2Zsb2F0Og0KICAgICAgY29sbGFwc2VkOiBubw0KICAgICAgc21vb3RoX3Njcm9sbDogbm8NCiAgICB0aGVtZTogZmxhdGx5DQogICAgZmlnX3dpZHRoOiAxMA0KICAgIGZpZ19oZWlnaHQ6IDYuNjYNCiAgICBmaWdfY2FwdGlvbjogeWVzDQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KICAgIGNvZGVfZm9sZGluZzogc2hvdw0KICB3b3JkX2RvY3VtZW50OiANCiAgICB0b2M6IHllcw0KICAgIGtlZXBfbWQ6IHllcw0KICBwZGZfZG9jdW1lbnQ6DQogICAgdG9jOiB5ZXMNCiAgZ2l0aHViX2RvY3VtZW50Og0KICAgIGh0bWxfcHJldmlldzogdHJ1ZQ0KYWx3YXlzX2FsbG93X2h0bWw6IHllcw0KZWRpdG9yX29wdGlvbnM6IA0KICBjaHVua19vdXRwdXRfdHlwZTogY29uc29sZQ0KZmlnLmFsaWduOiBjZW50ZXINCi0tLQ0KDQojIFByaW1laXJvIGFjZXNzbyB7I3NlYy1wcmltZWlyby1hY2Vzc28gLnVubnVtYmVyZWR9DQoNCk9sw6EhIE5lc3NlIHR1dG9yaWFsIHZvY8OqIGlyw6EgYXByZW5kZXIgYSByZXBsaWNhciB0dWRvIHF1ZSBzZXLDoSBleGliaWRvIG5lc3NhIHDDoWdpbmEhXA0KDQpQYXJhIGlzc28sIHZvY8OqIHByZWNpc2EgdGVyIGluc3RhbGFkbyBlbSBzZXUgY29tcHV0YWRvciAyIHByb2dyYW1hczogbyBgUmAgZSBvIGBSU3R1ZGlvYC5cDQpPIFIgw6kgYSBsaW5ndWFnZW0gZGUgcHJvZ3JhbWHDp8OjbyBlIG8gUlN0dWRpbyBhIGludGVyZmFjZSBncsOhZmljYSwNCg0KVm9jw6ogcG9kZSBiYWl4YXIgbyBgUmAgZSBvIGBSU3R1ZGlvYCBhdHJhdsOpcyBkbyBsaW5rIDxodHRwczovL3Bvc2l0LmNvL2Rvd25sb2FkL3JzdHVkaW8tZGVza3RvcC8+XA0KDQoxLiAgU2Ugw6kgbyBzZXUgcHJpbWVpcm8gYWNlc3NvLCBjbGlxdWUgbmEgY2FpeGluaGEgYENvZGVgIG5vIGNhbnRvIHN1cGVyaW9yIGRpcmVpdG8gcGFyYSBiYWl4YXIgbyBjw7NkaWdvIG5vIGZvcm1hdG8gYC5SbWRgLCBvdSBzZWphLCBSTWFya2Rvd24uDQoyLiAgQWJyYSBvIFJTdHVkaW8NCjMuICBDbGlxdWUgZW0gRmlsZSAtXD4gT3BlbiBmaWxlIC1cPiBlIHNlbGVjaW9uZSBlc3NlIGFycXVpdm8gYC5SbWRgIHF1ZSB2b2PDqiBiYWl4b3UuDQo0LiAgVm9jw6ogZGV2ZSBjaGVnYXIgYSB1bWEgdGVsYSBzZW1lbGhhbnRlIGEgZGEgZmlndXJhIGFiYWl4bw0KDQohW10oaW1hZ2VzLzIwMjIxMjI3LTA0MDcyNi0wMDMucG5nKQ0KDQpOYSBwcmltZWlyYSB2ZXogZW0gcXVlIGZvciByb2RhciBvcyBjw7NkaWdvcyBhcXVpIG5vIFIsIHNlcsOhIHNvbGljaXRhZG8gcXVlIGluc3RhbGUgcGFjb3Rlcy4gUXVhbmRvIGFwYXJlY2VyZW0gY2FpeGFzIGRlIGRpw6Fsb2dvLCBjbGlxdWUgZW0gKipgWWVzYCoqLg0KDQpQb2RlIGRlbW9yYXIgdW0gcG91Y28gZXNzZSBwcm9jZXNzby4gUGFyYSB0ZXIgdW1hIG1lbGhvciB2aXN1YWxpemHDp8OjbyBkZXNzZSB0dXRvcmlhbCBwcmVzc2lvbmUgYXMgdGVjbGFzIGBDdHJsK1NoaWZ0K0tgIG91IGNsaXF1ZSBubyBib3TDo28gYEtuaXRgIGFjaW1hLiBSZWNvbWVuZG8gbWFudGVyIHVtYSBhYmEgZG8gbmF2ZWdhZG9yIGNvbSBvIGFycXVpdm8gYHR1dG9yaWFsX1IuaHRtbGAgYWJlcnRvLg0KDQpKw6EgcG9kZW1vcyByb2RhciBvIGPDs2RpZ28gcGVsYSBwcmltZWlyYSB2ZXohXA0KUGFyYSBpc3NvLCBhcGVydGUgYEN0cmwrQWx0K1JgIG91IGNsaXF1ZSBlbSBgUnVuYCBubyBtZW51IHN1cGVyaW9yIGUgZGVwb2lzIGVtIGBSdW4gQWxsYDpcDQohW10oaW1hZ2VzLzIwMjIxMjI3LTAzNTU0My0wMDEucG5nKQ0KDQpFbnF1YW50byBvcyBwYWNvdGVzIGVzdMOjbyBzZW5kbyBpbnN0YWxhZG9zLCBwcm9zc2lnYSBjb20gYSBsZWl0dXJhLiBEZWl4ZWkgYWxndW5zIGNvbnRlw7pkb3MgbmFzIFtSZWZlcsOqbmNpYXNdKCNzZWMtbGlua3Mtw7p0ZWlzKSBxdWUgaXLDo28gY29tcGxlbWVudGFyIGVzc2UgZG9jdW1lbnRvLg0KDQpRdWFuZG8gcXVpc2VyIHJlbmRlcml6YXIgbyBjw7NkaWdvIHBhcmEgdGVyIGEgbWVzbWEgdmlzdWFsaXphw6fDo28gY29tbyBhIGRvIGZvcm1hdG8gYC5odG1sYCB1c2UgbyBjb21hbmRvIGRlIGBLbml0YCwgbyBgQ3RybCtTaGlmdCtLYCwgb3UgY2FzbyBlc3RlamEgY29tIHVtIGdyw6FmaWNvIGFiZXJ0bywgY2xpcXVlIGVtIFZpZXdlciBuYSBqYW5lbGEgaW5mZXJpb3IgZGlyZWl0YS4NCg0KIVtdKGltYWdlcy9wYXN0ZS0xOTdGQ0FGQS5wbmcpDQoNCiMgQ29tYW5kb3MgbWFpcyB1dGlsaXphZG9zIHsjc2VjLWNvbWFuZG9zLW1haXMtdXRpbGl6YWRvc30NCg0KYEN0cmwrQWx0K1JgIC1cPiBleGVjdXRhIFRPRE9TIG9zIGPDs2RpZ29zIGRlIHVtYSB2ZXogc8OzLg0KDQpgS25pdGAgb3UgYEN0cmwrU2hpZnQrS2AgLVw+IHJvZGEgVE9ET1Mgb3MgY8OzZGlnb3MgZGUgdW1hIHZleiBzw7MgZSByZW5kZXJpemEgYSB2aXN1YWxpemHDp8OjbyBlbSBmb3JtYXRvcyBgLmh0bWxgIG91IGAucGRmYC4NCg0KYEN0cmwrRW50ZXJgIC1cPiBleGVjdXRhIHVtICJwYXLDoWdyYWZvIiBkZSBjw7NkaWdvcy4NCg0KYEFsdCtFbnRlcmAgLVw+IGV4ZWN1dGEgbyAicGFyw6FncmFmbyIgZGUgY8OzZGlnb3MgbWFzIHNlbSBtb3ZlciBvIGN1cnNvci4NCg0KYEN0cmwrU2hpZnQrQ2AgLVw+IHBhcmEgY29tZW50YXIgb3UgKmRlc2NvbWVudGFyKiB1bSBpbnRlcnZhbG8gZGUgbGluaGFzLg0KDQo+IEFzIGxpbmhhcyBkZSBjw7NkaWdvIHF1ZSBjb21lw6dhbSBjb20gYCNgIHPDo28gKipjb21lbnTDoXJpb3MqKi4gRWxhcyBuw6NvIGltcGFjdGFtIG8gcmVzdWx0YWRvIGZpbmFsIGRvIGPDs2RpZ28uDQoNCmBDdHJsK0FsdCtJYCAtXD4gY3JpYSB1bSBub3ZvICpjb2RlIGNodW5rKiwgaXN0byDDqSwgInBlZGHDp28gZGUgY8OzZGlnbyIsIMOpIGEgw6FyZWEgZXhlY3V0w6F2ZWwgZGFzIGZ1bsOnw7VlcyBxdWUgaXJlbW9zIHV0aWxpemFyLg0KDQpgQ3RybCtJYCAtXD4gSW5kZW50YSBvIGPDs2RpZ28gKGFqdXN0YSBhIHRhYnVsYcOnw6NvIGVudHJlIGFzIGxpbmhhcywgZmFjaWxpdGEgYSBsZWl0dXJhIGRvIGPDs2RpZ28pLg0KDQo+IEEgbGlzdGEgY29tcGxldGEgZGUgYXRhbGhvcyBwb2RlIHNlciBjb25mZXJpZGEgbm8gbWVudSBzdXBlcmlvciBUb29scyAtXD4gS2V5Ym9hcmQgU2hvcnRjdXRzIEhlbHAsIG91IGF0cmF2w6lzIGRvIGF0YWxobyBgQWx0K1NoaWZ0K0tgLg0KDQojIFBhc3NvLWEtcGFzc28geyNzZWMtcGFzc28tYS1wYXNzb30NCg0KPiAqKkltcG9ydGFudGUqKjogQ29tIGVzc2UgYXJxdWl2byBgLlJtZGAgdm9jw6ogZGV2ZSBjaGVnYXIgYW9zIG1lc21vcyByZXN1bHRhZG9zIHF1ZSBwcmVzZW50ZXMgbm8gYXJxdWl2byBgdHV0b3JpYWxfUi5odG1sYC4NCj4NCj4gVm91IGRlaXhhciBjb21lbnRhZG8gb3MgcGVkYcOnb3MgZGUgY8OzZGlnbyBxdWUgbmVjZXNzaXRhbSBkZSBhbHRlcmHDp8OjbyBvYnJpZ2F0w7NyaWEgY29tIGEgbm9tZW5jbGF0dXJhIGBhbHRlcmFjYW9fYCBzZWd1aWRvIGRlIHVtIG7Dum1lcm8uDQo+DQo+IFBhcmEgZW5jb250cmFyIGZhY2lsbWVudGUgb3MgbG9jYWlzIHF1ZSBwcmVjaXNhbSBzZXIgYWp1c3RhZG9zLCBiYXN0YSB1dGlsaXphciBvIGNvbWFuZG8gYEN0cmwrRmAgZSBwcm9jdXJhciBwb3IgYGFsdGVyYWNhb19gIGUgbyByZXNwZWN0aXZvIG7Dum1lcm8gbGlzdGFkbyBhYmFpeG8uDQoNCjEuICBSZW5vbWVhciBhIHBsYW5pbGhhIGEgc2VyIGltcG9ydGFkYSBwcmEgZmFjaWxpdGFyIGEgbGVpdHVyYS4NCiAgICAtICAgbmVzc2UgY2FzbyByZW5vbWVlaSBhIHBsYW4gZ2VyYWRhIHBlbG8gUlPDgWd1YSBkZSBgRGFkb3NfMjAyMjEyMjIxNDMzMDUueGxzYCBwYXJhIGBwbGFuX2xpdG9yYWxfbWVkaW8ueGxzYC4NCiAgICAtICAgdm9jw6ogcG9kZSB1c2FyIGBDdHJsK0ZgIGUgc3Vic3RpdHVpciB0b2RhcyBhcyBvY29ycsOqbmNpYXMgZGUgYHBsYW5fbGl0b3JhbF9tZWRpb2AgcGFyYSBvIG5vbWUgcXVlIHZvY8OqIGRldSDDoCBwbGFuaWxoYS4NCjIuICBBanVzdGFyIG8gY2FtaW5obyBkbyBhcnF1aXZvLiAoKiphbHRlcmFjYW9fMSoqKQ0KICAgIC0gICBuZXNzZSBleGVtcGxvIGVzdG91IGltcG9ydGFuZG8gZGlyZXRhbWVudGUgZGEgcGFzdGEgZGUgZG93bmxvYWRzIGRvIG1ldSBjb21wdXRhZG9yOiBgIkM6L1VzZXJzL0zDqW8vRG93bmxvYWRzL3BsYW5fbGl0b3JhbF9tZWRpby54bHMiYA0KICAgIC0gICBGdXR1cmFtZW50ZSBxdWVybyBpbXBsZW1lbnRhciBhIGludGVncmHDp8OjbyBjb20gbyBbR29vZ2xlIFNoZWV0c10oI3NlYy1haW5kYS1wcmVjaXNhLXNlci1pbXBsZW1lbnRhZG8pLg0KMy4gIFZlcmlmaWNhciBvIGludGVydmFsbyBkZSBkYWRvcyBkYSBwbGFuaWxoYS4gQXMgw7psdGltYXMgMTAgbGluaGFzIGNvc3R1bWFtIHNlciBkb3Mgc3Vtw6FyaW9zLCBtYXMgbyBSIG7Do28gZW50ZW5kZSBpc3NvLg0KICAgIC0gICB2ZXJpZmljYXIgYXTDqSBxdWFsIGxpbmhhIGEgY29sdW5hIGDDjW5kaWNlYCB0ZW0gdmFsb3JlcyByZWdpc3RyYWRvcywgbmVzdGUgY2FzbyBvIGDDjW5kaWNlYCB2YWkgYXTDqSA5OCAoKzEgbGluaGEgZGUgY2FiZcOnYWxobykgPSBsaW5oYSA5OQ0KICAgIC0gICBBbHRlcmFyIG5hIHBhcnRlIGRlIGltcG9ydGHDp8OjbyBvIGludGVydmFsbyBwYXJhIGNvbXByZWVuZGVyIHNvbWVudGUgb3MgZGFkb3MgKCoqYWx0ZXJhY2FvXzIqKikNCiAgICAtICAgRXN0b3UgdGVudGFuZG8gZGVzY29icmlyIGNvbW8gZWNvbm9taXphciBlc3NhIGV0YXBhLg0KDQojIFBhY290ZXMgbmVjZXNzw6FyaW9zIHsjc2VjLXBhY290ZXMtbmVjZXNzw6FyaW9zIC5wYWNvdGVzfQ0KDQpgYGB7ciBjb25maWd1cmFuZG8gZXhpYmlyL29jdWx0YXIgY8OzZGlnbyBlIHJlc3VsdGFkb3MsIGluY2x1ZGU9RkFMU0V9DQpob29rcyA9IGtuaXRyOjprbml0X2hvb2tzJGdldCgpDQoNCmhvb2tfZm9sZGFibGUgPSBmdW5jdGlvbih0eXBlKSB7DQogIGZvcmNlKHR5cGUpDQogIGZ1bmN0aW9uKHgsIG9wdGlvbnMpIHsNCiAgICByZXMgPSBob29rc1tbdHlwZV1dKHgsIG9wdGlvbnMpDQogICAgDQogICAgaWYgKGlzRkFMU0Uob3B0aW9uc1tbcGFzdGUwKCJmb2xkLiIsIHR5cGUpXV0pKSByZXR1cm4ocmVzKQ0KICAgIA0KICAgIHBhc3RlMCgNCiAgICAgICI8ZGV0YWlscz48c3VtbWFyeT4iLCB0eXBlLCAiPC9zdW1tYXJ5PlxuXG4iLA0KICAgICAgcmVzLA0KICAgICAgIlxuXG48L2RldGFpbHM+Ig0KICAgICkNCiAgfQ0KfQ0KDQprbml0cjo6a25pdF9ob29rcyRzZXQoDQogIG91dHB1dCA9IGhvb2tfZm9sZGFibGUoIm91dHB1dCIpLA0KICBwbG90ID0gaG9va19mb2xkYWJsZSgicGxvdCIpDQopDQoNCiMgRGlzYWJsZSBmb2xkaW5nDQoNCiMgYGBge3IsIGZvbGQub3V0cHV0PUZBTFNFLCBmb2xkLnBsb3Q9RkFMU0V9DQojIHJub3JtKDEwKQ0KIyBwbG90KGlyaXMpDQojIGBgYA0KYGBgDQoNCk5vIGBjb2RlIGNodW5rYCBhYmFpeG8gc2Vyw6NvIGluc3RhbGFkb3MgdG9kb3Mgb3MgcGFjb3RlcyBuZWNlc3PDoXJpb3MuIENhZGEgcGFjb3RlIGNvbnTDqW0gZnVuw6fDtWVzIGVzcGVjw61maWNhcyBxdWUgYXV4aWxpYW0gbm8gZGVzZW52b2x2aW1lbnRvIGRhIGF0aXZpZGFkZSwgc2VqYSBhIGltcG9ydGHDp8OjbyBkbyBkYWRvIChgcmVhZHJgLCBgcmVhZHhsYCksIG5hIG1hbmlwdWxhw6fDo28gZG9zIGRhZG9zIChsaW1wZXphL3RyYXRhbWVudG8gY29tIGBqYW5pdG9yYCBlIGBsdWJyaWRhdGVgKSwgbmEgdmlzdWFsaXphw6fDo28gKGBnZ3Bsb3QyYCwgYHJtYXJrZG93bmAsIGBrYWJsZUV4dHJhYCkgb3UgcHJhIHByYXRpY2FtZW50ZSB0dWRvIChgdGlkeXZlcnNlYCkuDQoNCmBgYHtyIFBhY290ZXMgbmVjZXNzw6FyaW9zLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBUUlVFfQ0KcGFjbWFuOjpwX2xvYWQoDQogICMgRVRMIChleHRyYWN0LCB0cmFuc2Zvcm0sIGxvYWQpDQogIGphbml0b3IsIHJlYWRyLCByZWFkeGwsIGx1YnJpZGF0ZSwNCiAgZHBseXIsIA0KICB0aWR5dmVyc2UsIA0KICBnbHVlLA0KICAjIFZpc3VhbGl6YcOnw6NvDQogIGdncGxvdDIsDQogIEdHYWxseSwgDQogIHJtYXJrZG93biwgDQogIGtuaXRyLA0KICBrYWJsZUV4dHJhLA0KICBnZ2JlZXN3YXJtLCANCiAgZ2d0ZXh0DQogICMgYm9va2Rvd24NCikNCiNnb29nbGVzaGVldHM0DQpgYGANCg0KUGFyYSBhY2Vzc2FyIGEgcMOhZ2luYSBkZSBhanVkYSBkb3MgcGFjb3RlcyBvdSBkYXMgZnVuw6fDtWVzLCBiYXN0YSB1c2FyIHVtIGA/YCBhbnRlcyBkbyBxdWUgc2UgZXN0w6EgYnVzY2FuZG8uDQoNCk5vIGBjb2RlIGNodW5rYCBhY2ltYSBuw7NzIHV0aWxpemFtb3MgdW1hIGZ1bsOnw6NvIGBwX2xvYWRgIHF1ZSBlc3TDoSBkZW50cm8gZG8gcGFjb3RlIGBwYWNtYW5gLiBQYXJhIGlzc28gdXRpbGl6YW1vcyBvIGNvbWFuZG8gYHBhY21hbjo6cF9sb2FkYCwgaXN0byDDqSwgZXN0YW1vcyBkaXplbmRvIHBhcmEgbyBgUmAgcXVlIGRlbnRybyBkbyBwYWNvdGUgYHBhY21hbmAgcXVlcm8gdXNhciBlc3BlY2lmaWNhbWVudGUgYSBmdW7Dp8OjbyBgcF9sb2FkYC4NCg0KTm8gZXhlbXBsbyBhYmFpeG8gZXN0b3UgdmVyaWZpY2FuZG8gb3MgYXJndW1lbnRvcyBkZXNzYSBmdW7Dp8Ojby4gTmEgc2VxdcOqbmNpYSBhYnJvIG8gbWVudSBkZSBhanVkYSBkbyBwYWNvdGUgYHRpZHl2ZXJzZWAsIHVtIGRvcyBtYWlzIGltcG9ydGFudGVzIGRhIGNvbXVuaWRhZGUgUi4gT3V0cmEgbWFuZWlyYSBwb3Nzw612ZWwgc2VyaWEgdXRpbGl6YW5kbyBgaGVscChwYWNrYWdlID0gJ3BhY21hbicpYC4NCg0KIVs/aGVscF0oaW1hZ2VzLzIwMjIxMjI3LTE2MjMzNS0wMDIucG5nKQ0KDQojIEltcG9ydGHDp8OjbyBkb3MgZGFkb3MgeyNzZWMtaW1wb3J0YcOnw6NvLWRvcy1kYWRvc30NCg0KVXRpbGl6YW5kbyBvIGBjb2RlIGNodW5rYCBhYmFpeG8gdm9jw6ogZXN0YXLDoSBpbXBvcnRhbmRvIGEgbWVzbWEgcGxhbmlsaGEgcXVlIHV0aWxpemVpLiBTYWx2ZWkgZXNzZSBhcnF1aXZvIG5hIG51dmVtLCB2aWEgR2l0SHViLiBFc3RvdSBpbXBvcnRhbmRvLWEgdXRpbGl6YW5kbyBvIGxpbmsgcGFyYSBhY2Vzc8OhLWxhIG9ubGluZS4gDQoNCg0KYGBge3IgcmVwbGljYW5kbyBpbXBvcnRhw6fDo28gZG9zIGRhZG9zLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQ0KcGxhbl9saXRvcmFsX21lZGlvIDwtIHJlYWRfZGVsaW0oDQogICJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vbGVvbmFyZG9md2luay90dXRvcmlhbF9SX2ZlcGFtL21haW4vcGxhbmlsaGFfcnNhZ3VhL3BsYW5fbGl0b3JhbF9tZWRpbyUyMC0lMjBEYWRvc19BanVzdGFkb3MudHN2IiwgDQogIGRlbGltID0gIlx0IiwgDQogIGVzY2FwZV9kb3VibGUgPSBGQUxTRSwNCiAgY29sX3R5cGVzID0gY29scygNCiAgICDDjU5ESUNFID0gY29sX251bWJlcigpLA0KICAgIGBDw5NELiBFU1RBw4fDg09gID0gY29sX2NoYXJhY3RlcigpLA0KICAgIExBVElUVURFID0gY29sX251bWJlcigpLA0KICAgIExPTkdJVFVERSA9IGNvbF9udW1iZXIoKSwNCiAgICBgQkFDSUEgSElEUk9HUsOBRklDQWAgPSBjb2xfY2hhcmFjdGVyKCksDQogICAgYFJFQ1VSU08gSMONRFJJQ09gID0gY29sX2NoYXJhY3RlcigpLA0KICAgIFJFR0nDg08gPSBjb2xfY2hhcmFjdGVyKCksDQogICAgTVVOSUPDjVBJTyA9IGNvbF9jaGFyYWN0ZXIoKSwNCiAgICBBTUJJRU5URSA9IGNvbF9jaGFyYWN0ZXIoKSwNCiAgICBgREFUQSBDT0xFVEFgID0gY29sX2RhdGUoZm9ybWF0ID0gIiVtLyVkLyVZIiksDQogICAgYEhPUkEgQ09MRVRBYCA9IGNvbF90aW1lKGZvcm1hdCA9ICIlSDolTTolUyIpLA0KICAgIGBDSFVWQSAyNEhgID0gY29sX2NoYXJhY3RlcigpLA0KICAgIEFMQ0FMSU5JREFERSA9IGNvbF9udW1iZXIoKSwNCiAgICBBTFVNw41OSU8gPSBjb2xfbnVtYmVyKCksDQogICAgQ8OBRE1JTyA9IGNvbF9udW1iZXIoKSwNCiAgICBDSFVNQk8gPSBjb2xfbnVtYmVyKCksDQogICAgQ0xPUkVUTyA9IGNvbF9udW1iZXIoKSwNCiAgICBgQ0xPUk9GSUxBIEFgID0gY29sX251bWJlcigpLA0KICAgIENPQlJFID0gY29sX251bWJlcigpLA0KICAgIGBDT0xJRk9STUVTIFRFUk1PVE9MRVJBTlRFU2AgPSBjb2xfbnVtYmVyKCksDQogICAgYENPTElGT1JNRVMgVE9UQUlTYCA9IGNvbF9udW1iZXIoKSwNCiAgICBDT05EVVRJVklEQURFID0gY29sX251bWJlcigpLA0KICAgIGBDUk9NTyBUT1RBTGAgPSBjb2xfbnVtYmVyKCksDQogICAgYERFTUFOREEgQklPUVXDjU1JQ0EgREUgT1hJR8OKTklPYCA9IGNvbF9udW1iZXIoKSwNCiAgICBgREVNQU5EQSBRVcONTUlDQSBERSBPWElHw4pOSU9gID0gY29sX251bWJlcigpLA0KICAgIGBFU0NIRVJJQ0hJQSBDT0xJYCA9IGNvbF9udW1iZXIoKSwNCiAgICBGRVJSTyA9IGNvbF9udW1iZXIoKSwNCiAgICBgRklUT1BMQU5DVE9OICAtIENJQU5PQkFDVMOJUklBU2AgPSBjb2xfbnVtYmVyKCksDQogICAgYEZPU0ZBVE8gT1JUT2AgPSBjb2xfbnVtYmVyKCksDQogICAgYEbDk1NGT1JPIFRPVEFMYCA9IGNvbF9udW1iZXIoKSwNCiAgICBNQU5HQU7DilMgPSBjb2xfbnVtYmVyKCksDQogICAgYE1FUkPDmlJJTyBFTSBNSUNST0dSQU1BIFBPUiBMSVRSTyAoVUcvTClgID0gY29sX251bWJlcigpLA0KICAgIE7DjVFVRUwgPSBjb2xfbnVtYmVyKCksDQogICAgTklUUkFUTyA9IGNvbF9udW1iZXIoKSwNCiAgICBgTklUUk9Hw4pOSU8gQU1PTklBQ0FMYCA9IGNvbF9udW1iZXIoKSwNCiAgICBgTklUUk9Hw4pOSU8gT1JHw4JOSUNPYCA9IGNvbF9udW1iZXIoKSwNCiAgICBgTklUUk9Hw4pOSU8gVE9UQUwgS0pFTERBSExgID0gY29sX251bWJlcigpLA0KICAgIGBPWElHw4pOSU8gRElTU09MVklET2AgPSBjb2xfbnVtYmVyKCksDQogICAgUEggPSBjb2xfbnVtYmVyKCksDQogICAgYFBST0ZVTkRJREFERSBDT0xFVEFgID0gY29sX251bWJlcigpLA0KICAgIGBQUk9GVU5ESURBREUgVE9UQUxgID0gY29sX251bWJlcigpLA0KICAgIFNBTElOSURBREUgPSBjb2xfbnVtYmVyKCksDQogICAgYFPDk0xJRE9TIERJU1NPTFZJRE9TIFRPVEFJU2AgPSBjb2xfbnVtYmVyKCksDQogICAgYFPDk0xJRE9TIFNVU1BFTlNPUyBUT1RBSVNgID0gY29sX251bWJlcigpLA0KICAgIGBTw5NMSURPUyBUT1RBSVNgID0gY29sX251bWJlcigpLA0KICAgIGBURU1QRVJBVFVSQSBEQSDDgUdVQWAgPSBjb2xfbnVtYmVyKCksDQogICAgYFRFTVBFUkFUVVJBIERPIEFSYCA9IGNvbF9udW1iZXIoKSwNCiAgICBgVFJBTlNQQVLDik5DSUEgREEgw4FHVUFgID0gY29sX251bWJlcigpLA0KICAgIFRVUkJJREVaID0gY29sX251bWJlcigpLA0KICAgIGBWQVrDg08gUkVDVVJTTyBIw41EUklDT2AgPSBjb2xfbnVtYmVyKCksDQogICAgWklOQ08gPSBjb2xfbnVtYmVyKCkNCiAgKSwNCiAgbG9jYWxlID0gbG9jYWxlKA0KICAgIGRhdGVfbmFtZXMgPSAicHQiLCANCiAgICBkZWNpbWFsX21hcmsgPSAiLCIsDQogICAgZ3JvdXBpbmdfbWFyayA9ICIiDQogICksDQogIHRyaW1fd3MgPSBUUlVFDQopICU+JQ0KICBqYW5pdG9yOjpjbGVhbl9uYW1lcygpICU+JQ0KICBzbGljZSgNCiAgICAxOihuKCkgLSA4KSAjcmV0aXJhbmRvIGFzIHVsdGltYXMgOCBsaW5oYXMNCiAgKSAlPiUgDQogIHJlbmFtZSgNCiAgICBlX2NvbGkgPSBlc2NoZXJpY2hpYV9jb2xpLA0KICAgIGRibyA9IGRlbWFuZGFfYmlvcXVpbWljYV9kZV9veGlnZW5pbywNCiAgICBtZXJjdXJpbyA9IG1lcmN1cmlvX2VtX21pY3JvZ3JhbWFfcG9yX2xpdHJvX3VnX2wNCiAgKSAlPiUNCiAgbXV0YXRlKA0KICAgIG11bmljaXBpbyA9IHN0cl90b190aXRsZShtdW5pY2lwaW8pLA0KICAgIGRhdGFfY29sZXRhID0geW1kKGRhdGFfY29sZXRhKSwNCiAgICBhbm9fY29sZXRhID0geWVhcihkYXRhX2NvbGV0YSksDQogICkgJT4lDQogIGRwbHlyOjpzZWxlY3QoICNyZW9yZGVuYW5kbyBhcyBjb2x1bmFzDQogICAgYygxOjEwKSwNCiAgICBhbm9fY29sZXRhLA0KICAgIGV2ZXJ5dGhpbmcoKQ0KICApDQpgYGANCg0KVm9jw6ogaXLDoSBmYXplciBhcyBhbHRlcmHDp8O1ZXMgbmVzc2UgYGNvZGUgY2h1bmtgIGFiYWl4by4gIA0KU2Vyw6EgbmVjZXNzw6FyaW8gcXVlIHZvY8OqIGFsdGVyZSBvIHByaW1laXJvIGFyZ3VtZW50byBkYSBmdW7Dp8OjbyBgcmVhZF9leGNlbGAsIHF1ZSDDqSBvIGNhbWluaG8sIG91IHNlamE6IGRpemVyIGFvIGBSYCBvbmRlIHF1ZSBhIHBsYW5pbGhhIGVzdMOhLiANCmBgYHtyIEltcG9ydGFuZG8gb3MgZGFkb3N9DQpwbGFuX2xpdG9yYWxfbWVkaW9fYWx0ZXJhciA8LSByZWFkX2V4Y2VsKA0KICAiQzovVXNlcnMvTMOpby9Eb3dubG9hZHMvcGxhbl9saXRvcmFsX21lZGlvLnhscyIsICNhbHRlcmFjYW9fMQ0KICBzaGVldCA9ICJEYWRvc19BanVzdGFkb3MiLCANCiAgY29sX3R5cGVzID0gYygNCiAgICAibnVtZXJpYyIsICJ0ZXh0IiwgIm51bWVyaWMiLCAibnVtZXJpYyIsICJ0ZXh0IiwgDQogICAgInRleHQiLCAidGV4dCIsICJ0ZXh0IiwgInRleHQiLCAiZGF0ZSIsIA0KICAgICJkYXRlIiwgInRleHQiLCAibnVtZXJpYyIsICJudW1lcmljIiwgDQogICAgIm51bWVyaWMiLCAibnVtZXJpYyIsICJudW1lcmljIiwgDQogICAgIm51bWVyaWMiLCAibnVtZXJpYyIsICJudW1lcmljIiwgDQogICAgIm51bWVyaWMiLCAibnVtZXJpYyIsICJudW1lcmljIiwgDQogICAgIm51bWVyaWMiLCAibnVtZXJpYyIsICJudW1lcmljIiwgDQogICAgIm51bWVyaWMiLCAibnVtZXJpYyIsICJudW1lcmljIiwgDQogICAgIm51bWVyaWMiLCAibnVtZXJpYyIsICJudW1lcmljIiwgDQogICAgIm51bWVyaWMiLCAibnVtZXJpYyIsICJudW1lcmljIiwgDQogICAgIm51bWVyaWMiLCAibnVtZXJpYyIsICJudW1lcmljIiwgDQogICAgIm51bWVyaWMiLCAibnVtZXJpYyIsICJudW1lcmljIiwgDQogICAgIm51bWVyaWMiLCAibnVtZXJpYyIsICJudW1lcmljIiwgDQogICAgIm51bWVyaWMiLCAibnVtZXJpYyIsICJudW1lcmljIiwgDQogICAgIm51bWVyaWMiLCAibnVtZXJpYyIsICJudW1lcmljIiwgDQogICAgIm51bWVyaWMiKSwNCiAgcmFuZ2UgPSAiQTE6QVk5OSIsICNhbHRlcmFjYW9fMg0KICB0cmltX3dzID0gVFJVRQ0KKSAlPiUgDQogIGphbml0b3I6OmNsZWFuX25hbWVzKCkgJT4lIA0KICByZW5hbWUoDQogICAgZV9jb2xpID0gZXNjaGVyaWNoaWFfY29saSwNCiAgICBkYm8gPSBkZW1hbmRhX2Jpb3F1aW1pY2FfZGVfb3hpZ2VuaW8sDQogICAgbWVyY3VyaW8gPSBtZXJjdXJpb19lbV9taWNyb2dyYW1hX3Bvcl9saXRyb191Z19sDQogICkgJT4lIA0KICBtdXRhdGUoDQogICAgbXVuaWNpcGlvID0gc3RyX3RvX3RpdGxlKG11bmljaXBpbyksDQogICAgZGF0YV9jb2xldGEgPSB5bWQoZGF0YV9jb2xldGEpLA0KICAgIGFub19jb2xldGEgPSB5ZWFyKGRhdGFfY29sZXRhKSwNCiAgICAjIGhvcmFfY29sZXRhID0gcGFyc2VfZGF0ZXRpbWUoaG9yYV9jb2xldGEpLA0KICApICU+JQ0KICBkcGx5cjo6c2VsZWN0KCAjcmVvcmRlbmFuZG8gYXMgY29sdW5hcw0KICAgIGMoMToxMCksDQogICAgYW5vX2NvbGV0YSwNCiAgICBldmVyeXRoaW5nKCkNCiAgKQ0KYGBgDQoNCiMgU3Vtw6FyaW9zIGVzdGF0w61zdGljb3MgeyNzZWMtc3Vtw6FyaW9zLWVzdGF0w61zdGljb3N9DQoNCmBgYHtyIHN1bWFyaW8sIGVjaG8gPSBUUlVFfQ0Kc3VtYXJpbyA8LSBwbGFuX2xpdG9yYWxfbWVkaW8gJT4lDQogIGRwbHlyOjpzZWxlY3QoY29kX2VzdGFjYW8sIG94aWdlbmlvX2Rpc3NvbHZpZG8sIGFub19jb2xldGEpICU+JQ0KICBmaWx0ZXIoYW5vX2NvbGV0YSA+ICIyMDEzIiAmDQogICAgICAgICAgIGFub19jb2xldGEgPD0gIjIwMjUiKSAlPiUNCiAgZ3JvdXBfYnkoY29kX2VzdGFjYW8pICU+JQ0KICBzdW1tYXJpemUoDQogICAgbWluID0NCiAgICAgIG1pbihveGlnZW5pb19kaXNzb2x2aWRvLA0KICAgICAgICAgIG5hLnJtID0gVFJVRSksDQogICAgcTEgPQ0KICAgICAgcXVhbnRpbGUob3hpZ2VuaW9fZGlzc29sdmlkbywgMC4yMCwNCiAgICAgICAgICAgICAgIG5hLnJtID0gVFJVRSksDQogICAgbWVkaWFuID0NCiAgICAgIG1lZGlhbihveGlnZW5pb19kaXNzb2x2aWRvLA0KICAgICAgICAgICAgIG5hLnJtID0gVFJVRSksDQogICAgbWVhbiA9DQogICAgICBtZWFuKG94aWdlbmlvX2Rpc3NvbHZpZG8sDQogICAgICAgICAgIG5hLnJtPSBUUlVFKSwNCiAgICBxMyA9DQogICAgICBxdWFudGlsZShveGlnZW5pb19kaXNzb2x2aWRvLCAwLjgwLA0KICAgICAgICAgICAgICAgbmEucm0gPSBUUlVFKSwNCiAgICBtYXggPQ0KICAgICAgbWF4KG94aWdlbmlvX2Rpc3NvbHZpZG8sDQogICAgICAgICAgbmEucm0gPSBUUlVFKSkNCg0Kc3VtYXJpbw0KYGBgDQoNCiMjIFZpc3VhbGl6YcOnw6NvIGRhIGVzdHJ1dHVyYSBkZSBkYWRvcyBkYSBwbGFuaWxoYSB7I3NlYy12aXN1YWxpemHDp8Ojby1kYS1lc3RydXR1cmEtZGUtZGFkb3MtZGEtcGxhbmlsaGF9DQoNCkNvbmZlcmlyIHNlIG8gdGlwbyBkb3MgZGFkb3MgZXN0w6EgY29ycmV0bywgZGF0YSBlbSBmb3JtYXRvIGRlIGRhdGEgKGRhdGUvZHR0bSksIGPDs2RpZ28gZGEgZXN0YcOnw6NvIGNvbW8gY2hhcmFjdGVyIChjaHIpLCB2YWxvciBtZWRpZG8gZG9zIHBhcsOibWV0cm9zIGNvbW8gZG91YmxlIChkYmwpLg0KDQpgYGB7ciBlc3RydXR1cmEgZGEgcGxhbmlsaGEsfQ0KZ2xpbXBzZShwbGFuX2xpdG9yYWxfbWVkaW8pDQojIHN0cihwbGFuX2xpdG9yYWxfbWVkaW8pICNvdXRyYSBtYW5laXJhIGRlIHZpc3VhbGl6YXIgYSBlU1RSdXR1cmEgDQpgYGANCg0KYGBge3IgVmlzdWFsaXphw6fDo28gZGEgcGxhbmlsaGEgaW1wb3J0YWRhLCBlY2hvID0gRkFMU0V9DQpwYWdlZF90YWJsZShwbGFuX2xpdG9yYWxfbWVkaW8sDQogICAgICAgICAgICBvcHRpb25zID0gbGlzdChyb3dzLnByaW50ID0gMTUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xzLnByaW50ID0gMTApKQ0KYGBgDQoNCiMgUmVxdWlzaXRvcyBwcmEgZ2VyYXIgb3MgZ3LDoWZpY29zIHsjc2VjLXJlcXVpc2l0b3MtcHJhLWdlcmFyLW9zLWdyw6FmaWNvc30NCg0KIyMgRGVmaW5pciBvICp0aGVtZSoNCg0KRGVmaW5pbmRvIHVtYSBjb3IgZGUgbGV0cmEgZSBkZSBmdW5kbyBwYWRyw6NvIGEgc2VyIGFkb3RhZGEgbm9zIGdyw6FmaWNvcy4NCg0KYGBge3Igc2V0dGluZyB0aGVtZX0NCnRoZW1lX2dyYWZzIDwtIGZ1bmN0aW9uKGJnID0gIndoaXRlIiwgDQogICAgICAgICAgICAgICAgICAgICAgICBjb2xvcmFjYW9fbGV0cmEgPSAiYmxhY2siKSB7DQogIHRoZW1lKA0KICAgIHBsb3QudGl0bGUgPSANCiAgICAgIGVsZW1lbnRfdGV4dCgNCiAgICAgICAgaGp1c3QgPSAwLjUsDQogICAgICAgIGNvbG9yID0gY29sb3JhY2FvX2xldHJhLA0KICAgICAgICBzaXplID0gMTkpLA0KICAgIA0KICAgIGF4aXMudGl0bGUueCA9IA0KICAgICAgIyBlbGVtZW50X3RleHQoDQogICAgICAjIGNvbG9yID0gY29sb3JhY2FvX2xldHJhLA0KICAgICAgIyBzaXplID0gMTUsDQogICAgICAjIGFuZ2xlID0gMCwpLA0KICAgICAgZWxlbWVudF9ibGFuaygpLA0KICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dCgNCiAgICAgIGNvbG9yID0gY29sb3JhY2FvX2xldHJhLA0KICAgICAgc2l6ZSA9IDE1LA0KICAgICAgYW5nbGUgPSA5MCksDQogICAgDQogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoDQogICAgICBjb2xvciA9IGNvbG9yYWNhb19sZXRyYSwNCiAgICAgIHNpemUgPSAxNyksDQogICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoDQogICAgICBjb2xvciA9IGNvbG9yYWNhb19sZXRyYSwNCiAgICAgIHNpemUgPSAxNywNCiAgICAgIGFuZ2xlID0gMCksDQogICAgDQogICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gYmcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsaW5ldHlwZSA9IDEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gMC41LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siKSwNCiAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNyksDQogICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gYmcpLA0KICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gYmcpLA0KICAgIHBsb3QubWFyZ2luID0gbWFyZ2luKGwgPSA1LCByID0gMTAsDQogICAgICAgICAgICAgICAgICAgICAgICAgYiA9IDUsIHQgPSA1KQ0KICApDQp9DQpgYGANCg0KIyMgQ3JpYXIgZnVuw6fDo28gcGFyYSBnZXJhciBib3hwbG90cyBjb20gcGVyY2VudGlzIDIwIGUgODANCg0KYGBge3IgZnVuY2FvIHBlcmNlbnRpbCAyMCBlIDgwfQ0KZiA8LSBmdW5jdGlvbih4KSB7DQogIHIgPC0gcXVhbnRpbGUoeCwgcHJvYnMgPSBjKDAuMTAsIDAuMjAsIDAuNTAsIDAuODAsIDAuOTApKQ0KICBuYW1lcyhyKSA8LSBjKCJ5bWluIiwgImxvd2VyIiwgIm1pZGRsZSIsICJ1cHBlciIsICJ5bWF4IikNCiAgcmV0dXJuKHIpDQp9DQpgYGANCg0KIyBHcsOhZmljb3MgeyNzZWMtZ3LDoWZpY29zIC5ncmFmaWNvc30NCg0KIyMgQWx0ZXJhciBub21lIGUvb3Ugb3JkZW0gZGFzIGVzdGHDp8O1ZXMgeyNzZWMtYWx0ZXJhci1ub21lLWVvdS1vcmRlbS1kYXMtZXN0YcOnw7Vlc30NCg0KPiAqKkF0ZW7Dp8OjbzoqKiBUb21hciBtdWl0byBjdWlkYWRvIGNvbSBhIG9yZGVtIHF1ZSBlc3TDo28gZGlzcG9zdGFzIGFzIGVzdGHDp8O1ZXMuIERldmUtc2Ugc2VtcHJlIHJlc3BlaXRhciBvIHNlbnRpZG8gbmFzY2VudGUgLVw+IGZvei4NCj4NCj4gQ29uZmVyaXIgYSBvcmRlbSBkYXMgZXN0YcOnw7VlcyBhdHJhdsOpcyBkbyBbbWFwYSBpbnRlcmF0aXZvXSgjc2VjLW1hcGEtaW50ZXJhdGl2by1jb20tbG9jYWxpemHDp8Ojby1kb3MtcG9udG9zLWRlLW1vbml0b3JhbWVudG8pLCBRR0lTIG91IEdvb2dsZSBFYXJ0aCBQcm8uDQo+DQo+IEVsYXMgYWNhYmFtIGZpY2FuZG8gZm9yYSBkZSBvcmRlbSBwb3IgY29udGEgZG8gY8OzZGlnbyBkZSBvdHRvYmFjaWFzIFBhcmEgcmVvcmRlbmFyIGFzIGVzdGHDp8O1ZXMsIGF0ZW50ZS1zZSDDoCBmdW7Dp8OjbyBgc2NhbGVfeF9kaXNjcmV0ZWAuDQoNCk5lc3RlIGV4ZW1wbG8gaXJlbW9zIGFwcmVuZGVyIGEgY29tbyBtdWRhciBvIG5vbWUgZGFzIGVzdGHDp8O1ZXMgZSByZW9yZGVuw6EtbGFzLg0KDQpBcyBlc3Rhw6fDtWVzIGVzdMOjbyBuYSBvcmRlbSBjZXJ0YSwgbWFzIHF1ZXJvIGFsdGVyYXIgbyBub21lIGRlbGFzLCBjb21vIGZhw6dvPw0KDQpgYGB7ciBncmFmIG9yZGVtIGNlcnRhLCBlY2hvPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCBmb2xkLnBsb3Q9RkFMU0V9DQoocGxhbl9saXRvcmFsX21lZGlvICU+JQ0KICAgZ2dwbG90KA0KICAgICBhZXMoDQogICAgICAgeCA9IGNvZF9lc3RhY2FvLA0KICAgICAgIHkgPSBveGlnZW5pb19kaXNzb2x2aWRvLA0KICAgICApDQogICApKw0KICAgYW5ub3RhdGUoInJlY3QiLA0KICAgICAgICAgICAgeG1pbiA9IC1JbmYsIHhtYXggPSBJbmYsDQogICAgICAgICAgICB5bWluID0gLUluZiwgeW1heCA9IDIsDQogICAgICAgICAgICBhbHBoYSA9IDEsDQogICAgICAgICAgICBmaWxsID0gIiNhYzUwNzkiKSsgIz5waW9yIGNsYXNzZQ0KICAgYW5ub3RhdGUoInJlY3QiLA0KICAgICAgICAgICAgeG1pbiA9IC1JbmYsIHhtYXggPSBJbmYsDQogICAgICAgICAgICB5bWluID0gMiwgeW1heCA9IDQsDQogICAgICAgICAgICBhbHBoYSA9IDEsDQogICAgICAgICAgICBmaWxsID0gIiNlYjU2NjEiKSsgI2NsYXNzZSA0DQogICBhbm5vdGF0ZSgicmVjdCIsDQogICAgICAgICAgICB4bWluID0gLUluZiwgeG1heCA9IEluZiwNCiAgICAgICAgICAgIHltaW4gPSA0LCB5bWF4ID0gNSwNCiAgICAgICAgICAgIGFscGhhID0gMSwNCiAgICAgICAgICAgIGZpbGwgPSAiI2ZjZjdhYiIpKyAjY2xhc3NlIDMNCiAgIGFubm90YXRlKCJyZWN0IiwNCiAgICAgICAgICAgIHhtaW4gPSAtSW5mLCB4bWF4ID0gSW5mLA0KICAgICAgICAgICAgeW1pbiA9IDUsIHltYXggPSA2LA0KICAgICAgICAgICAgYWxwaGEgPSAxLA0KICAgICAgICAgICAgZmlsbCA9ICIjNzBjMThjIikrICNjbGFzc2UgMg0KICAgYW5ub3RhdGUoInJlY3QiLA0KICAgICAgICAgICAgeG1pbiA9IC1JbmYsIHhtYXggPSBJbmYsDQogICAgICAgICAgICB5bWluPSA2LCB5bWF4ID0gSW5mLA0KICAgICAgICAgICAgYWxwaGEgPSAxLA0KICAgICAgICAgICAgZmlsbCA9ICIjOGRjZGViIikrICNjbGFzc2UgMQ0KICAgc3RhdF9zdW1tYXJ5KA0KICAgICBmdW4uZGF0YSA9IGYsDQogICAgIGdlb20gPSAnZXJyb3JiYXInLA0KICAgICB3aWR0aCA9IDAuMywNCiAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuNjUpLA0KICAgKSsNCiAgIHN0YXRfc3VtbWFyeSgNCiAgICAgZnVuLmRhdGEgPSBmLA0KICAgICBnZW9tID0gImJveHBsb3QiLA0KICAgICB3aWR0aCA9IDAuNywNCiAgICAgZmlsbCA9ICcjRjhGOEZGJywNCiAgICAgY29sb3IgPSAiYmxhY2siLA0KICAgICBvdXRsaWVyLnNoYXBlID0gMSwgI3NlIGRlaXhhciBOQSBmaWNhIHPDsyBvIGppdHRlciwgc2UgbsOjbywgZGVpeGEgMQ0KICAgKSsNCiAgICMgZmFjZXRfd3JhcCh+cGVyaW9kbykrDQogICBsYWJzKA0KICAgICB0aXRsZSA9ICJPeGlnw6puaW8gRGlzc29sdmlkbyIsDQogICAgIHg9IE5VTEwsDQogICAgIHk9Im1nL0wiDQogICApKw0KICAgZ2diZWVzd2FybTo6Z2VvbV9xdWFzaXJhbmRvbSgNCiAgICAgc2l6ZSA9IDEuMiwNCiAgICAgYWxwaGEgPSAuMjUsDQogICAgIHdpZHRoID0gLjA3LA0KICAgKSsNCiAgIHNjYWxlX3lfY29udGludW91cygNCiAgICAgZXhwYW5kID0gZXhwYW5zaW9uKG11bHQgPSBjKDAsMCkpLA0KICAgICBuLmJyZWFrcyA9IDExLA0KICAgICAjIGxpbWl0cyA9IGMoLTAuMywyMSkNCiAgICAgbGltaXRzID0gYygNCiAgICAgICBtaW4ocGxhbl9saXRvcmFsX21lZGlvJG94aWdlbmlvX2Rpc3NvbHZpZG8sIG5hLnJtID0gVFJVRSksDQogICAgICAgbWF4KHBsYW5fbGl0b3JhbF9tZWRpbyRveGlnZW5pb19kaXNzb2x2aWRvLCBuYS5ybSA9IFRSVUUpKzEpDQogICApKw0KICAgIyBzY2FsZV94X2Rpc2NyZXRlKA0KICAgIyAgIGxpbWl0cyA9IGMoDQogICAjICAgICAiODc0MjAxMzAiLA0KICAgIyAgICAgDQogICAjICAgICAiODczMzI1MDAiLA0KICAgIyAgICAgIjg3NDIwMTUwIiwNCiAgICMgICAgICI4NzQyMDM1MCIsDQogICAjICAgICAiODc0MjA1MDAiLA0KICAgIyAgICAgIjg3NTEwMDEwIg0KICAgIyAgICksDQogICAjICAgbGFiZWxzID0gYygNCiAgICMgICAgICJQTTEiLCAiUE0yIiwgIlBNMyIsICJQTTQiLCAiUE01IiwgIlBNNiINCiAgICMgICApDQogICAjICkrDQogICBnZW9tX3Ntb290aCgNCiAgICAgbWV0aG9kID0gImxtIiwNCiAgICAgc2UgPSBGQUxTRSwgI3NlIGRlaXhhciBUUlVFIGdlcmEgbyBpbnRlcnZhbG8gZGUgY29uZmlhbsOnYSBkZSA5NSUNCiAgICAgYWVzKGdyb3VwID0gMSksDQogICAgIGFscGhhID0gMC41LA0KICAgICBuYS5ybSA9IFRSVUUsDQogICAgIHNpemUgPSAxDQogICApKw0KICAgdGhlbWVfZ3JhZnMoKQ0KKQ0KYGBgDQoNCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQpVdGlsaXphbmRvIG8gYGNvZGUgY2h1bmtgIGFiYWl4byBuw7NzIGFsdGVyYW1vcyBvcyBub21lcyBkYXMgZXN0YcOnw7VlcyBwYXJhIFBNIChvdSBQb250byBkZSBNb25pdG9yYW1lbnRvKSBzZWd1aWRvIGRlIHVtIG7Dum1lcm8uIE8gYFBNMWAgcmVwcmVzZW50YSBvIHBvbnRvIG1haXMgcHLDs3hpbW8gZGFzIG5hc2NlbnRlcywgZW5xdWFudG8gbyBgUE02YCBvIG1haXMgcHLDs3hpbW8gZGEgZm96Lg0KDQpgYGB7ciByZW5vbWVhciBlc3Rhw6fDtWVzIG5vIGdyw6FmaWNvLCBldmFsID0gRkFMU0V9DQpzY2FsZV94X2Rpc2NyZXRlKA0KICBsaW1pdHMgPSBjKA0KICAgICI4NzMzMjUwMCIsDQogICAgIjg3NDIwMTMwIiwNCiAgICANCiAgICAiODc0MjAxNTAiLA0KICAgICI4NzQyMDM1MCIsDQogICAgIjg3NDIwNTAwIiwNCiAgICAiODc1MTAwMTAiDQogICksDQogIGxhYmVscyA9IGMoDQogICAgIlBNMSIsICJQTTIiLCAiUE0zIiwgIlBNNCIsICJQTTUiLCAiUE02Ig0KICApDQopKw0KYGBgDQoNCmBgYHtyIGdyYWYgYWx0ZXJhciBub21lIGVzdCwgZWNobz1GQUxTRSwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgZm9sZC5wbG90PUZBTFNFfQ0KKHBsYW5fbGl0b3JhbF9tZWRpbyAlPiUNCiAgIGdncGxvdCgNCiAgICAgYWVzKA0KICAgICAgIHggPSBjb2RfZXN0YWNhbywNCiAgICAgICB5ID0gb3hpZ2VuaW9fZGlzc29sdmlkbywNCiAgICAgKQ0KICAgKSsNCiAgIGFubm90YXRlKCJyZWN0IiwNCiAgICAgICAgICAgIHhtaW4gPSAtSW5mLCB4bWF4ID0gSW5mLA0KICAgICAgICAgICAgeW1pbiA9IC1JbmYsIHltYXggPSAyLA0KICAgICAgICAgICAgYWxwaGEgPSAxLA0KICAgICAgICAgICAgZmlsbCA9ICIjYWM1MDc5IikrICM+cGlvciBjbGFzc2UNCiAgIGFubm90YXRlKCJyZWN0IiwNCiAgICAgICAgICAgIHhtaW4gPSAtSW5mLCB4bWF4ID0gSW5mLA0KICAgICAgICAgICAgeW1pbiA9IDIsIHltYXggPSA0LA0KICAgICAgICAgICAgYWxwaGEgPSAxLA0KICAgICAgICAgICAgZmlsbCA9ICIjZWI1NjYxIikrICNjbGFzc2UgNA0KICAgYW5ub3RhdGUoInJlY3QiLA0KICAgICAgICAgICAgeG1pbiA9IC1JbmYsIHhtYXggPSBJbmYsDQogICAgICAgICAgICB5bWluID0gNCwgeW1heCA9IDUsDQogICAgICAgICAgICBhbHBoYSA9IDEsDQogICAgICAgICAgICBmaWxsID0gIiNmY2Y3YWIiKSsgI2NsYXNzZSAzDQogICBhbm5vdGF0ZSgicmVjdCIsDQogICAgICAgICAgICB4bWluID0gLUluZiwgeG1heCA9IEluZiwNCiAgICAgICAgICAgIHltaW4gPSA1LCB5bWF4ID0gNiwNCiAgICAgICAgICAgIGFscGhhID0gMSwNCiAgICAgICAgICAgIGZpbGwgPSAiIzcwYzE4YyIpKyAjY2xhc3NlIDINCiAgIGFubm90YXRlKCJyZWN0IiwNCiAgICAgICAgICAgIHhtaW4gPSAtSW5mLCB4bWF4ID0gSW5mLA0KICAgICAgICAgICAgeW1pbj0gNiwgeW1heCA9IEluZiwNCiAgICAgICAgICAgIGFscGhhID0gMSwNCiAgICAgICAgICAgIGZpbGwgPSAiIzhkY2RlYiIpKyAjY2xhc3NlIDENCiAgIHN0YXRfc3VtbWFyeSgNCiAgICAgZnVuLmRhdGEgPSBmLA0KICAgICBnZW9tID0gJ2Vycm9yYmFyJywNCiAgICAgd2lkdGggPSAwLjMsDQogICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjY1KSwNCiAgICkrDQogICBzdGF0X3N1bW1hcnkoDQogICAgIGZ1bi5kYXRhID0gZiwNCiAgICAgZ2VvbSA9ICJib3hwbG90IiwNCiAgICAgd2lkdGggPSAwLjcsDQogICAgIGZpbGwgPSAnI0Y4RjhGRicsDQogICAgIGNvbG9yID0gImJsYWNrIiwNCiAgICAgb3V0bGllci5zaGFwZSA9IDEsICNzZSBkZWl4YXIgTkEgZmljYSBzw7MgbyBqaXR0ZXIsIHNlIG7Do28sIGRlaXhhIDENCiAgICkrDQogICAjIGZhY2V0X3dyYXAofnBlcmlvZG8pKw0KICAgbGFicygNCiAgICAgdGl0bGUgPSAiT3hpZ8OqbmlvIERpc3NvbHZpZG8iLA0KICAgICB4PSBOVUxMLA0KICAgICB5PSJtZy9MIg0KICAgKSsNCiAgIGdnYmVlc3dhcm06Omdlb21fcXVhc2lyYW5kb20oDQogICAgIHNpemUgPSAxLjIsDQogICAgIGFscGhhID0gLjI1LA0KICAgICB3aWR0aCA9IC4wNywNCiAgICkrDQogICBzY2FsZV95X2NvbnRpbnVvdXMoDQogICAgIGV4cGFuZCA9IGV4cGFuc2lvbihtdWx0ID0gYygwLDApKSwNCiAgICAgbi5icmVha3MgPSAxMSwNCiAgICAgIyBsaW1pdHMgPSBjKC0wLjMsMjEpDQogICAgIGxpbWl0cyA9IGMoDQogICAgICAgbWluKHBsYW5fbGl0b3JhbF9tZWRpbyRveGlnZW5pb19kaXNzb2x2aWRvLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgIG1heChwbGFuX2xpdG9yYWxfbWVkaW8kb3hpZ2VuaW9fZGlzc29sdmlkbywgbmEucm0gPSBUUlVFKSsxKQ0KICAgKSsNCiAgIHNjYWxlX3hfZGlzY3JldGUoDQogICAgIGxpbWl0cyA9IGMoDQogICAgICAgIjg3MzMyNTAwIiwNCiAgICAgICAiODc0MjAxMzAiLA0KICAgICAgICI4NzQyMDE1MCIsDQogICAgICAgIjg3NDIwMzUwIiwNCiAgICAgICAiODc0MjA1MDAiLA0KICAgICAgICI4NzUxMDAxMCINCiAgICAgKSwNCiAgICAgbGFiZWxzID0gYygNCiAgICAgICAiUE0xIiwgIlBNMiIsICJQTTMiLCAiUE00IiwgIlBNNSIsICJQTTYiDQogICAgICkNCiAgICkrDQogICBnZW9tX3Ntb290aCgNCiAgICAgbWV0aG9kID0gImxtIiwNCiAgICAgc2UgPSBGQUxTRSwgI3NlIGRlaXhhciBUUlVFIGdlcmEgbyBpbnRlcnZhbG8gZGUgY29uZmlhbsOnYSBkZSA5NSUNCiAgICAgYWVzKGdyb3VwID0gMSksDQogICAgIGFscGhhID0gMC41LA0KICAgICBuYS5ybSA9IFRSVUUsDQogICAgIHNpemUgPSAxDQogICApKw0KICAgdGhlbWVfZ3JhZnMoKQ0KKQ0KYGBgDQoNCjwhLS0gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIC0tPg0KDQpQZXJjZWJhIHF1ZSBpcmVtb3MgdHJvY2FyIGEgb3JkZW0gZGFzIGVzdGHDp8O1ZXMuIEFudGVzIGEgZXN0YcOnw6NvIGA4NzMzMjUwMGAgZXJhIGEgcHJpbWVpcmEgYSBzZXIgbGlzdGFkYSBkZW50cm8gZGEgZnVuw6fDo28gYGxpbWl0cyA9IGMoKWAsIGVsYSBlcmEsIHBvcnRhbnRvLCBvIGBQTTFgLiBBZ29yYSBvIGBQTTFgIHNlcsOhIGEgYDg3NDIwMTMwYC4gQ29tcGFyZSBvIGPDs2RpZ28gZSBvIGdyw6FmaWNvIGFiYWl4byBjb20gbyBhbnRlcmlvci4NCg0KYGBge3IgcmVvcmRlbmFyIGVzdGHDp8O1ZXMgbm8gZ3LDoWZpY28sIGV2YWwgPSBGQUxTRX0NCnNjYWxlX3hfZGlzY3JldGUoDQogIGxpbWl0cyA9IGMoDQogICAgIjg3NDIwMTMwIiwNCiAgICAiODczMzI1MDAiLA0KICAgIA0KICAgICI4NzQyMDE1MCIsDQogICAgIjg3NDIwMzUwIiwNCiAgICAiODc0MjA1MDAiLA0KICAgICI4NzUxMDAxMCINCiAgKSwNCiAgbGFiZWxzID0gYygNCiAgICAiUE0xIiwgIlBNMiIsICJQTTMiLCAiUE00IiwgIlBNNSIsICJQTTYiDQogICkNCikrDQpgYGANCg0KYGBge3IgZ3JhZiBhbHRlcmFyIG9yZGVtIGRhcyBlc3QsIGVjaG89RkFMU0UsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGZvbGQucGxvdD1GQUxTRX0NCihwbGFuX2xpdG9yYWxfbWVkaW8gJT4lDQogICBnZ3Bsb3QoDQogICAgIGFlcygNCiAgICAgICB4ID0gY29kX2VzdGFjYW8sDQogICAgICAgeSA9IG94aWdlbmlvX2Rpc3NvbHZpZG8sDQogICAgICkNCiAgICkrDQogICBhbm5vdGF0ZSgicmVjdCIsDQogICAgICAgICAgICB4bWluID0gLUluZiwgeG1heCA9IEluZiwNCiAgICAgICAgICAgIHltaW4gPSAtSW5mLCB5bWF4ID0gMiwNCiAgICAgICAgICAgIGFscGhhID0gMSwNCiAgICAgICAgICAgIGZpbGwgPSAiI2FjNTA3OSIpKyAjPnBpb3IgY2xhc3NlDQogICBhbm5vdGF0ZSgicmVjdCIsDQogICAgICAgICAgICB4bWluID0gLUluZiwgeG1heCA9IEluZiwNCiAgICAgICAgICAgIHltaW4gPSAyLCB5bWF4ID0gNCwNCiAgICAgICAgICAgIGFscGhhID0gMSwNCiAgICAgICAgICAgIGZpbGwgPSAiI2ViNTY2MSIpKyAjY2xhc3NlIDQNCiAgIGFubm90YXRlKCJyZWN0IiwNCiAgICAgICAgICAgIHhtaW4gPSAtSW5mLCB4bWF4ID0gSW5mLA0KICAgICAgICAgICAgeW1pbiA9IDQsIHltYXggPSA1LA0KICAgICAgICAgICAgYWxwaGEgPSAxLA0KICAgICAgICAgICAgZmlsbCA9ICIjZmNmN2FiIikrICNjbGFzc2UgMw0KICAgYW5ub3RhdGUoInJlY3QiLA0KICAgICAgICAgICAgeG1pbiA9IC1JbmYsIHhtYXggPSBJbmYsDQogICAgICAgICAgICB5bWluID0gNSwgeW1heCA9IDYsDQogICAgICAgICAgICBhbHBoYSA9IDEsDQogICAgICAgICAgICBmaWxsID0gIiM3MGMxOGMiKSsgI2NsYXNzZSAyDQogICBhbm5vdGF0ZSgicmVjdCIsDQogICAgICAgICAgICB4bWluID0gLUluZiwgeG1heCA9IEluZiwNCiAgICAgICAgICAgIHltaW49IDYsIHltYXggPSBJbmYsDQogICAgICAgICAgICBhbHBoYSA9IDEsDQogICAgICAgICAgICBmaWxsID0gIiM4ZGNkZWIiKSsgI2NsYXNzZSAxDQogICBzdGF0X3N1bW1hcnkoDQogICAgIGZ1bi5kYXRhID0gZiwNCiAgICAgZ2VvbSA9ICdlcnJvcmJhcicsDQogICAgIHdpZHRoID0gMC4zLA0KICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC42NSksDQogICApKw0KICAgc3RhdF9zdW1tYXJ5KA0KICAgICBmdW4uZGF0YSA9IGYsDQogICAgIGdlb20gPSAiYm94cGxvdCIsDQogICAgIHdpZHRoID0gMC43LA0KICAgICBmaWxsID0gJyNGOEY4RkYnLA0KICAgICBjb2xvciA9ICJibGFjayIsDQogICAgIG91dGxpZXIuc2hhcGUgPSAxLCAjc2UgZGVpeGFyIE5BIGZpY2Egc8OzIG8gaml0dGVyLCBzZSBuw6NvLCBkZWl4YSAxDQogICApKw0KICAgIyBmYWNldF93cmFwKH5wZXJpb2RvKSsNCiAgIGxhYnMoDQogICAgIHRpdGxlID0gIk94aWfDqm5pbyBEaXNzb2x2aWRvIiwNCiAgICAgeD0gTlVMTCwNCiAgICAgeT0ibWcvTCINCiAgICkrDQogICBnZ2JlZXN3YXJtOjpnZW9tX3F1YXNpcmFuZG9tKA0KICAgICBzaXplID0gMS4yLA0KICAgICBhbHBoYSA9IC4yNSwNCiAgICAgd2lkdGggPSAuMDcsDQogICApKw0KICAgc2NhbGVfeV9jb250aW51b3VzKA0KICAgICBleHBhbmQgPSBleHBhbnNpb24obXVsdCA9IGMoMCwwKSksDQogICAgIG4uYnJlYWtzID0gMTEsDQogICAgICMgbGltaXRzID0gYygtMC4zLDIxKQ0KICAgICBsaW1pdHMgPSBjKA0KICAgICAgIG1pbihwbGFuX2xpdG9yYWxfbWVkaW8kb3hpZ2VuaW9fZGlzc29sdmlkbywgbmEucm0gPSBUUlVFKSwNCiAgICAgICBtYXgocGxhbl9saXRvcmFsX21lZGlvJG94aWdlbmlvX2Rpc3NvbHZpZG8sIG5hLnJtID0gVFJVRSkrMSkNCiAgICkrDQogICBzY2FsZV94X2Rpc2NyZXRlKA0KICBsaW1pdHMgPSBjKA0KICAgICI4NzQyMDEzMCIsDQogICAgDQogICAgIjg3MzMyNTAwIiwNCiAgICAiODc0MjAxNTAiLA0KICAgICI4NzQyMDM1MCIsDQogICAgIjg3NDIwNTAwIiwNCiAgICAiODc1MTAwMTAiDQogICksDQogIGxhYmVscyA9IGMoDQogICAgIlBNMSIsICJQTTIiLCAiUE0zIiwgIlBNNCIsICJQTTUiLCAiUE02Ig0KICApDQopKw0KICAgZ2VvbV9zbW9vdGgoDQogICAgIG1ldGhvZCA9ICJsbSIsDQogICAgIHNlID0gRkFMU0UsICNzZSBkZWl4YXIgVFJVRSBnZXJhIG8gaW50ZXJ2YWxvIGRlIGNvbmZpYW7Dp2EgZGUgOTUlDQogICAgIGFlcyhncm91cCA9IDEpLA0KICAgICBhbHBoYSA9IDAuNSwNCiAgICAgbmEucm0gPSBUUlVFLA0KICAgICBzaXplID0gMQ0KICAgKSsNCiAgIHRoZW1lX2dyYWZzKCkNCikNCmBgYA0KDQo8IS0tIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSAtLT4NCg0KIk9rIG1hcy4uLiBlIHNlIGV1IG7Do28gcXVpc2VyIGFsdGVyYXIgbyBjw7NkaWdvIG90dG9iYWNpYXMgcGFyYSBgUE0xYCwgYFBNMmAsIHPDsyBhIG9yZGVtIGRhcyBlc3Rhw6fDtWVzLCBvIHF1ZSBkZXZvIGZhemVyPyIgQmFzdGEgcmVwbGljYXIgYSBzZXF1w6puY2lhICpjb3JyZXRhKiBkYXMgZXN0YcOnw7VlcyBkZSBgbGltaXRzID0gYygpYCBkZW50cm8gZGEgZnVuw6fDo28gYGxhYmVscyA9IGMoKWAuDQoNCmBgYHtyIHJlb3JkZW5hciBlc3Rhw6fDtWVzIG5vIGdyw6FmaWNvIHNlbSBhbHRlcmFyIG5vbWUsIGV2YWwgPSBGQUxTRX0NCiAgIHNjYWxlX3hfZGlzY3JldGUoDQogICAgIGxpbWl0cyA9IGMoDQogICAgICAgIjg3NDIwMTMwIiwNCiAgICAgICAiODczMzI1MDAiLA0KICAgICAgICI4NzQyMDE1MCIsDQogICAgICAgIjg3NDIwMzUwIiwNCiAgICAgICAiODc0MjA1MDAiLA0KICAgICAgICI4NzUxMDAxMCINCiAgICAgKSwNCiAgICAgbGFiZWxzID0gYygNCiAgICAgICAiODc0MjAxMzAiLA0KICAgICAgICI4NzMzMjUwMCIsDQogICAgICAgIjg3NDIwMTUwIiwNCiAgICAgICAiODc0MjAzNTAiLA0KICAgICAgICI4NzQyMDUwMCIsDQogICAgICAgIjg3NTEwMDEwIg0KICAgICApDQogICApKw0KYGBgDQoNCmBgYHtyIGdyYWYgYWx0ZXJhciBvcmRlbSBkYXMgZXN0IHNlbSBhbHRlcmFyIG5vbWUsIGVjaG89RkFMU0UsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGZvbGQucGxvdD1GQUxTRX0NCihwbGFuX2xpdG9yYWxfbWVkaW8gJT4lDQogICBnZ3Bsb3QoDQogICAgIGFlcygNCiAgICAgICB4ID0gY29kX2VzdGFjYW8sDQogICAgICAgeSA9IG94aWdlbmlvX2Rpc3NvbHZpZG8sDQogICAgICkNCiAgICkrDQogICBhbm5vdGF0ZSgicmVjdCIsDQogICAgICAgICAgICB4bWluID0gLUluZiwgeG1heCA9IEluZiwNCiAgICAgICAgICAgIHltaW4gPSAtSW5mLCB5bWF4ID0gMiwNCiAgICAgICAgICAgIGFscGhhID0gMSwNCiAgICAgICAgICAgIGZpbGwgPSAiI2FjNTA3OSIpKyAjPnBpb3IgY2xhc3NlDQogICBhbm5vdGF0ZSgicmVjdCIsDQogICAgICAgICAgICB4bWluID0gLUluZiwgeG1heCA9IEluZiwNCiAgICAgICAgICAgIHltaW4gPSAyLCB5bWF4ID0gNCwNCiAgICAgICAgICAgIGFscGhhID0gMSwNCiAgICAgICAgICAgIGZpbGwgPSAiI2ViNTY2MSIpKyAjY2xhc3NlIDQNCiAgIGFubm90YXRlKCJyZWN0IiwNCiAgICAgICAgICAgIHhtaW4gPSAtSW5mLCB4bWF4ID0gSW5mLA0KICAgICAgICAgICAgeW1pbiA9IDQsIHltYXggPSA1LA0KICAgICAgICAgICAgYWxwaGEgPSAxLA0KICAgICAgICAgICAgZmlsbCA9ICIjZmNmN2FiIikrICNjbGFzc2UgMw0KICAgYW5ub3RhdGUoInJlY3QiLA0KICAgICAgICAgICAgeG1pbiA9IC1JbmYsIHhtYXggPSBJbmYsDQogICAgICAgICAgICB5bWluID0gNSwgeW1heCA9IDYsDQogICAgICAgICAgICBhbHBoYSA9IDEsDQogICAgICAgICAgICBmaWxsID0gIiM3MGMxOGMiKSsgI2NsYXNzZSAyDQogICBhbm5vdGF0ZSgicmVjdCIsDQogICAgICAgICAgICB4bWluID0gLUluZiwgeG1heCA9IEluZiwNCiAgICAgICAgICAgIHltaW49IDYsIHltYXggPSBJbmYsDQogICAgICAgICAgICBhbHBoYSA9IDEsDQogICAgICAgICAgICBmaWxsID0gIiM4ZGNkZWIiKSsgI2NsYXNzZSAxDQogICBzdGF0X3N1bW1hcnkoDQogICAgIGZ1bi5kYXRhID0gZiwNCiAgICAgZ2VvbSA9ICdlcnJvcmJhcicsDQogICAgIHdpZHRoID0gMC4zLA0KICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC42NSksDQogICApKw0KICAgc3RhdF9zdW1tYXJ5KA0KICAgICBmdW4uZGF0YSA9IGYsDQogICAgIGdlb20gPSAiYm94cGxvdCIsDQogICAgIHdpZHRoID0gMC43LA0KICAgICBmaWxsID0gJyNGOEY4RkYnLA0KICAgICBjb2xvciA9ICJibGFjayIsDQogICAgIG91dGxpZXIuc2hhcGUgPSAxLCAjc2UgZGVpeGFyIE5BIGZpY2Egc8OzIG8gaml0dGVyLCBzZSBuw6NvLCBkZWl4YSAxDQogICApKw0KICAgIyBmYWNldF93cmFwKH5wZXJpb2RvKSsNCiAgIGxhYnMoDQogICAgIHRpdGxlID0gIk94aWfDqm5pbyBEaXNzb2x2aWRvIiwNCiAgICAgeD0gTlVMTCwNCiAgICAgeT0ibWcvTCINCiAgICkrDQogICBnZ2JlZXN3YXJtOjpnZW9tX3F1YXNpcmFuZG9tKA0KICAgICBzaXplID0gMS4yLA0KICAgICBhbHBoYSA9IC4yNSwNCiAgICAgd2lkdGggPSAuMDcsDQogICApKw0KICAgc2NhbGVfeV9jb250aW51b3VzKA0KICAgICBleHBhbmQgPSBleHBhbnNpb24obXVsdCA9IGMoMCwwKSksDQogICAgIG4uYnJlYWtzID0gMTEsDQogICAgICMgbGltaXRzID0gYygtMC4zLDIxKQ0KICAgICBsaW1pdHMgPSBjKA0KICAgICAgIG1pbihwbGFuX2xpdG9yYWxfbWVkaW8kb3hpZ2VuaW9fZGlzc29sdmlkbywgbmEucm0gPSBUUlVFKSwNCiAgICAgICBtYXgocGxhbl9saXRvcmFsX21lZGlvJG94aWdlbmlvX2Rpc3NvbHZpZG8sIG5hLnJtID0gVFJVRSkrMSkNCiAgICkrDQogICBzY2FsZV94X2Rpc2NyZXRlKA0KICAgICBsaW1pdHMgPSBjKA0KICAgICAgICI4NzQyMDEzMCIsDQogICAgICAgIjg3MzMyNTAwIiwNCiAgICAgICAiODc0MjAxNTAiLA0KICAgICAgICI4NzQyMDM1MCIsDQogICAgICAgIjg3NDIwNTAwIiwNCiAgICAgICAiODc1MTAwMTAiDQogICAgICksDQogICAgIGxhYmVscyA9IGMoDQogICAgICAgIjg3NDIwMTMwIiwNCiAgICAgICAiODczMzI1MDAiLA0KICAgICAgICI4NzQyMDE1MCIsDQogICAgICAgIjg3NDIwMzUwIiwNCiAgICAgICAiODc0MjA1MDAiLA0KICAgICAgICI4NzUxMDAxMCINCiAgICAgKQ0KICAgKSsNCiAgIGdlb21fc21vb3RoKA0KICAgICBtZXRob2QgPSAibG0iLA0KICAgICBzZSA9IEZBTFNFLCAjc2UgZGVpeGFyIFRSVUUgZ2VyYSBvIGludGVydmFsbyBkZSBjb25maWFuw6dhIGRlIDk1JQ0KICAgICBhZXMoZ3JvdXAgPSAxKSwNCiAgICAgYWxwaGEgPSAwLjUsDQogICAgIG5hLnJtID0gVFJVRSwNCiAgICAgc2l6ZSA9IDENCiAgICkrDQogICB0aGVtZV9ncmFmcygpDQopDQpgYGANCg0KPCEtLSAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gLS0+DQoNCk9iczogUGFyYSBhIEJhY2lhIEhpZHJvZ3LDoWZpY2EgZG8gUmlvIEdyYXZhdGHDrSBlc3NlIHByb2Nlc3NvIMOpIG5lY2Vzc8OhcmlvLg0KDQo+IFNlbXByZSB0b21hciBjdWlkYWRvIGNvbSBvcyBsaW1pdGVzIGRvICoqZWl4byB5KiouIERlaXhlaSBjb21vIHBhZHLDo28gbyBSIGJ1c2NhciBhdXRvbWF0aWNhbWVudGUgcXVhbCBvIHZhbG9yIG3DrW5pbW8gZSBtw6F4aW1vIGRhcXVlbGUgcGFyw6JtZXRybywgbWFzIG8gaWRlYWwgw6kgcXVlIHNlIGFqdXN0ZSBjYXNvIGEgY2Fzby4NCg0KQ2FzbyBxdWVpcmEgYWx0ZXJhciBvIHRhbWFuaG8gZG9zIG91dGxpZXJzLCBhbHRlcmFyIG8gYHNpemVgIG5lc3NlIHRyZWNobyBkb3MgY8OzZGlnb3M6DQoNCmBgYHtyIGFsdGVyYXIgdGFtYW5obyBkbyBvdXRsaWVyLCBldmFsID0gRkFMU0V9DQpnZ2JlZXN3YXJtOjpnZW9tX3F1YXNpcmFuZG9tKA0KICAgICAjIGdyb3Vwb25YID0gRkFMU0UsDQogICAgIHNpemUgPSAxLjIsIA0KICAgICBhbHBoYSA9IC4yNSwNCiAgICAgd2lkdGggPSAuMDcsDQogICApKw0KYGBgDQoNCj4gVG9kb3Mgb3MgZ3LDoWZpY29zIGZvcmFtIGdlcmFkb3MgdXRpbGl6YW5kbyBjb21vIHBhZHLDo28gb3MgbGltaXRlcyBkYSBSZXNvbHXDp8OjbyBuwrogMzU3LzA1IGRvIENPTkFNQSBwYXJhIGFtYmllbnRlcyAqKmzDs3RpY29zKiouIENhc28gcXVlaXJhIGFsdGVyYXIgb3MgbGltaXRlcyBwYXJhIGFkZXF1YXIgYW9zIGFtYmllbnRlcyAqKmzDqm50aWNvcyoqLCBkZXZlLXNlIGVkaXRhciBvcyBgeW1pbmAgZSBgeW1heGAgZGUgY2FkYSByZXTDom5ndWxvIChgcmVjdGApIGRvIHJlZmVyaWRvIHBhcsOibWV0cm8uDQo+DQo+IE7Do28gZXNxdWVjZXIgcXVlIG8gUiBlbnRlbmRlIGEgY2FzYSBkZWNpbWFsIGNvbW8gcG9udG8sIGUgbsOjbyBjb21vIHbDrXJndWxhLg0KDQpgYGB7ciBhbWJpZW50ZSBsw7N0aWNvIHggbMOqbnRpY28sIGV2YWwgPSBGQUxTRX0NCmFubm90YXRlKCJyZWN0IiwNCiAgICAgICAgIHhtaW4gPSAtSW5mLCB4bWF4ID0gSW5mLA0KICAgICAgICAgeW1pbiA9IDEzLjMsIHltYXggPSBJbmYsDQogICAgICAgICBhbHBoYSA9IDEsDQogICAgICAgICBmaWxsID0gIiNhYzUwNzkiKSsgIz5waW9yIGNsYXNzZQ0KYW5ub3RhdGUoInJlY3QiLA0KICAgICAgICAgeG1pbiA9IC1JbmYsIHhtYXggPSBJbmYsDQogICAgICAgICB5bWluID0gMy43LCB5bWF4ID0gMTMuMywNCiAgICAgICAgIGFscGhhID0gMSwNCiAgICAgICAgIGZpbGwgPSAiI2ZjZjdhYiIpKyAjY2xhc3NlIDMNCmFubm90YXRlKCJyZWN0IiwNCiAgICAgICAgIHhtaW4gPSAtSW5mLCB4bWF4ID0gSW5mLA0KICAgICAgICAgeW1pbiA9IDAsIHltYXggPSAzLjcsDQogICAgICAgICBhbHBoYSA9IDEsDQogICAgICAgICBmaWxsID0gIiM4ZGNkZWIiKSsgI2NsYXNzZSAxDQpgYGANCg0KIyMgUGFyw6JtZXRyb3MgZGUgUXVhbGlkYWRlIGRhIMOBZ3VhIHsjc2VjLXBhcsOibWV0cm9zLWRlLXF1YWxpZGFkZS1kYS3DoWd1YX0NCg0KIyMjIE94aWfDqm5pbyBEaXNzb2x2aWRvIHsjc2VjLW94aWfDqm5pby1kaXNzb2x2aWRvfQ0KDQpgYGB7ciBHcsOhZmljbyBPRCwgZmlnLmNhcD0iT3hpZ8OqbmlvIERpc3NvbHZpZG8iLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBmb2xkLnBsb3Q9RkFMU0V9DQooZ3JhZl9vZCA8LSBwbGFuX2xpdG9yYWxfbWVkaW8gJT4lDQogICBnZ3Bsb3QoDQogICAgIGFlcygNCiAgICAgICB4ID0gY29kX2VzdGFjYW8sDQogICAgICAgeSA9IG94aWdlbmlvX2Rpc3NvbHZpZG8sDQogICAgICkNCiAgICkrDQogICBhbm5vdGF0ZSgicmVjdCIsDQogICAgICAgICAgICB4bWluID0gLUluZiwgeG1heCA9IEluZiwNCiAgICAgICAgICAgIHltaW4gPSAtSW5mLCB5bWF4ID0gMiwNCiAgICAgICAgICAgIGFscGhhID0gMSwNCiAgICAgICAgICAgIGZpbGwgPSAiI2FjNTA3OSIpKyAjPnBpb3IgY2xhc3NlDQogICBhbm5vdGF0ZSgicmVjdCIsDQogICAgICAgICAgICB4bWluID0gLUluZiwgeG1heCA9IEluZiwNCiAgICAgICAgICAgIHltaW4gPSAyLCB5bWF4ID0gNCwNCiAgICAgICAgICAgIGFscGhhID0gMSwNCiAgICAgICAgICAgIGZpbGwgPSAiI2ViNTY2MSIpKyAjY2xhc3NlIDQNCiAgIGFubm90YXRlKCJyZWN0IiwNCiAgICAgICAgICAgIHhtaW4gPSAtSW5mLCB4bWF4ID0gSW5mLA0KICAgICAgICAgICAgeW1pbiA9IDQsIHltYXggPSA1LA0KICAgICAgICAgICAgYWxwaGEgPSAxLA0KICAgICAgICAgICAgZmlsbCA9ICIjZmNmN2FiIikrICNjbGFzc2UgMw0KICAgYW5ub3RhdGUoInJlY3QiLA0KICAgICAgICAgICAgeG1pbiA9IC1JbmYsIHhtYXggPSBJbmYsDQogICAgICAgICAgICB5bWluID0gNSwgeW1heCA9IDYsDQogICAgICAgICAgICBhbHBoYSA9IDEsDQogICAgICAgICAgICBmaWxsID0gIiM3MGMxOGMiKSsgI2NsYXNzZSAyDQogICBhbm5vdGF0ZSgicmVjdCIsDQogICAgICAgICAgICB4bWluID0gLUluZiwgeG1heCA9IEluZiwNCiAgICAgICAgICAgIHltaW49IDYsIHltYXggPSBJbmYsDQogICAgICAgICAgICBhbHBoYSA9IDEsDQogICAgICAgICAgICBmaWxsID0gIiM4ZGNkZWIiKSsgI2NsYXNzZSAxDQogICBzdGF0X3N1bW1hcnkoDQogICAgIGZ1bi5kYXRhID0gZiwNCiAgICAgZ2VvbSA9ICdlcnJvcmJhcicsDQogICAgIHdpZHRoID0gMC4zLA0KICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC42NSksDQogICApKw0KICAgc3RhdF9zdW1tYXJ5KA0KICAgICBmdW4uZGF0YSA9IGYsDQogICAgIGdlb20gPSAiYm94cGxvdCIsDQogICAgIHdpZHRoID0gMC43LA0KICAgICBmaWxsID0gJyNGOEY4RkYnLA0KICAgICBjb2xvciA9ICJibGFjayIsDQogICAgIG91dGxpZXIuc2hhcGUgPSAxLCAjc2UgZGVpeGFyIE5BIGZpY2Egc8OzIG8gaml0dGVyLCBzZSBuw6NvLCBkZWl4YSAxDQogICApKw0KICAgIyBmYWNldF93cmFwKH5wZXJpb2RvKSsNCiAgIGxhYnMoDQogICAgIHRpdGxlID0gIk94aWfDqm5pbyBEaXNzb2x2aWRvIiwNCiAgICAgeD0gTlVMTCwNCiAgICAgeT0ibWcvTCINCiAgICkrDQogICBnZ2JlZXN3YXJtOjpnZW9tX3F1YXNpcmFuZG9tKA0KICAgICBzaXplID0gMS4yLA0KICAgICBhbHBoYSA9IC4yNSwNCiAgICAgd2lkdGggPSAuMDcsDQogICApKw0KICAgc2NhbGVfeV9jb250aW51b3VzKA0KICAgICBleHBhbmQgPSBleHBhbnNpb24obXVsdCA9IGMoMCwwKSksDQogICAgIG4uYnJlYWtzID0gMTEsDQogICAgICMgbGltaXRzID0gYygtMC4zLDIxKQ0KICAgICBsaW1pdHMgPSBjKA0KICAgICAgIG1pbihwbGFuX2xpdG9yYWxfbWVkaW8kb3hpZ2VuaW9fZGlzc29sdmlkbywgbmEucm0gPSBUUlVFKSwNCiAgICAgICBtYXgocGxhbl9saXRvcmFsX21lZGlvJG94aWdlbmlvX2Rpc3NvbHZpZG8sIG5hLnJtID0gVFJVRSkrMSkNCiAgICkrDQogICAjIHNjYWxlX3hfZGlzY3JldGUoDQogICAjICAgbGltaXRzID0gYygNCiAgICMgICAgICI4NzMzMjUwMCIsDQogICAjICAgICAiODc0MjAxMzAiLA0KICAgIyAgICAgIjg3NDIwMTUwIiwNCiAgICMgICAgICI4NzQyMDM1MCIsDQogICAjICAgICAiODc0MjA1MDAiLA0KICAgIyAgICAgIjg3NTEwMDEwIg0KICAgIyAgICksDQogICAjICAgbGFiZWxzID0gYygNCiAgICMgICAgICJQTTEiLCAiUE0yIiwgIlBNMyIsICJQTTQiLCAiUE01IiwgIlBNNiINCiAgICMgICApDQogICAjICkrDQogICBnZW9tX3Ntb290aCgNCiAgICAgbWV0aG9kID0gImxtIiwNCiAgICAgc2UgPSBGQUxTRSwgI3NlIGRlaXhhciBUUlVFIGdlcmEgbyBpbnRlcnZhbG8gZGUgY29uZmlhbsOnYSBkZSA5NSUNCiAgICAgYWVzKGdyb3VwID0gMSksDQogICAgIGFscGhhID0gMC41LA0KICAgICBuYS5ybSA9IFRSVUUsDQogICAgIHNpemUgPSAxDQogICApKw0KICAgdGhlbWVfZ3JhZnMoKQ0KKQ0KYGBgDQoNCiMjIyBEQk8geyNzZWMtZGJvfQ0KDQpgYGB7ciBHcsOhZmljbyBEQk8sIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFLCBmaWcuY2FwPSJEZW1hbmRhIEJpb3F1w61taWNhIGRlIE94aWfDqm5pbyIsIGZvbGQucGxvdD1GQUxTRX0NCihncmFmX2RibyA8LSBnZ3Bsb3QocGxhbl9saXRvcmFsX21lZGlvLA0KICAgICAgICAgICAgICAgICAgICBhZXMoeCA9IGNvZF9lc3RhY2FvLA0KICAgICAgICAgICAgICAgICAgIHkgPSBkYm8pKSsNCiAgIGFubm90YXRlKCJyZWN0IiwNCiAgICAgICAgICAgIHhtaW4gPSAtSW5mLCB4bWF4ID0gSW5mLA0KICAgICAgICAgICAgeW1pbiA9IDEwLCB5bWF4ID0gSW5mLA0KICAgICAgICAgICAgYWxwaGEgPSAxLA0KICAgICAgICAgICAgZmlsbCA9ICIjYWM1MDc5IikrICM+cGlvciBjbGFzc2UNCiAgIGFubm90YXRlKCJyZWN0IiwNCiAgICAgICAgICAgIHhtaW4gPSAtSW5mLCB4bWF4ID0gSW5mLA0KICAgICAgICAgICAgeW1pbiA9IDUsIHltYXggPSAxMCwNCiAgICAgICAgICAgIGFscGhhID0gMSwNCiAgICAgICAgICAgIGZpbGwgPSAiI2ZjZjdhYiIpKyAjY2xhc3NlIDMNCiAgIGFubm90YXRlKCJyZWN0IiwNCiAgICAgICAgICAgIHhtaW4gPSAtSW5mLCB4bWF4ID0gSW5mLA0KICAgICAgICAgICAgeW1pbiA9IDMsIHltYXggPSA1LA0KICAgICAgICAgICAgYWxwaGEgPSAxLA0KICAgICAgICAgICAgZmlsbCA9ICIjNzBjMThjIikrICNjbGFzc2UgMg0KICAgYW5ub3RhdGUoInJlY3QiLA0KICAgICAgICAgICAgeG1pbiA9IC1JbmYsIHhtYXggPSBJbmYsDQogICAgICAgICAgICB5bWluID0gMCwgeW1heCA9IDMsDQogICAgICAgICAgICBhbHBoYSA9IDEsDQogICAgICAgICAgICBmaWxsID0gIiM4ZGNkZWIiKSsgI2NsYXNzZSAxDQogICBzdGF0X3N1bW1hcnkoDQogICAgIGZ1bi5kYXRhID0gZiwNCiAgICAgZ2VvbSA9ICdlcnJvcmJhcicsDQogICAgIHdpZHRoID0gMC4zLA0KICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC42NSksDQogICApKw0KICAgc3RhdF9zdW1tYXJ5KA0KICAgICBmdW4uZGF0YSA9IGYsDQogICAgIGdlb20gPSAiYm94cGxvdCIsDQogICAgIHdpZHRoID0gMC43LA0KICAgICBmaWxsID0gJyNGOEY4RkYnLA0KICAgICBjb2xvciA9ICJibGFjayIsDQogICAgIG91dGxpZXIuc2hhcGUgPSAxLCAjc2UgZGVpeGFyIE5BIGZpY2Egc8OzIG8gaml0dGVyLCBzZSBuw6NvLCBkZWl4YSAxDQogICApKw0KICAgIyBmYWNldF93cmFwKH5wZXJpb2RvKSsNCiAgIGxhYnModGl0bGUgPSAiRGVtYW5kYSBCaW9xdcOtbWljYSBkZSBPeGlnw6puaW8iLA0KICAgICAgICB4PSJFc3Rhw6fDo28iLA0KICAgICAgICB5PSJtZy9MIikrDQogICBnZ2JlZXN3YXJtOjpnZW9tX3F1YXNpcmFuZG9tKA0KICAgICAjIGdyb3Vwb25YID0gRkFMU0UsDQogICAgIHNpemUgPSAxLjIsDQogICAgIGFscGhhID0gLjI1LA0KICAgICB3aWR0aCA9IC4wNywNCiAgICkrDQogICAjIHNjYWxlX3hfZGlzY3JldGUobGltaXRzID0gYygiODczOTg1MDAiLCANCiAgICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICI4NzM5ODk4MCIsIA0KICAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjg3Mzk4OTAwIiwgDQogICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiODczOTg5NTAiLCANCiAgICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICI4NzQwNTUwMCIsIA0KICAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjg3NDA2OTAwIiwgDQogICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiODc0MDk5MDAiKSwNCiAgICMgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJQTTEiLCAiUE0yIiwgIlBNMyIsICJQTTQiLCAiUE01IiwgIlBNNiIsICJQTTciKQ0KICAgIyApKw0KICAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGV4cGFuc2lvbihtdWx0ID0gYygwLjAzLDAuMDMpKSwNCiAgICAgICAgICAgICAgICAgICAgICBuLmJyZWFrcyA9IDgsDQogICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygNCiAgICAgICAgICAgICAgICAgICAgICAgIG1pbihwbGFuX2xpdG9yYWxfbWVkaW8kZGJvLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICAgICAgICAgICAgICAgICAgMTANCiAgICAgICAgICAgICAgICAgICAgICAgICMgbWF4KHBsYW5fbGl0b3JhbF9tZWRpbyRkYm8sIG5hLnJtID0gVFJVRSkNCiAgICAgICAgICAgICAgICAgICAgICAgICksDQogICAgICAgICAgICAgICAgICAgICAgdHJhbnMgPSAibG9nMTAiKSsNCiAgIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsDQogICAgICAgICAgICAgICBzZT1GQUxTRSwgI3NlIGRlaXhhciBUUlVFIGdlcmEgbyBpbnRlcnZhbG8gZGUgY29uZmlhbsOnYSBkZSA5NSUNCiAgICAgICAgICAgICAgIGFlcyhncm91cD0xKSwNCiAgICAgICAgICAgICAgIGFscGhhPS41LA0KICAgICAgICAgICAgICAgbmEucm0gPSBUUlVFLA0KICAgICAgICAgICAgICAgc2l6ZSA9IDEpKw0KICAgdGhlbWVfZ3JhZnMoKQ0KKQ0KYGBgDQoNCiMjIyAqRXNjaGVyaWNoaWEgY29saSoNCg0KYGBge3IgR3LDoWZpY28gRWNvbGksIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFLCBmaWcuY2FwPSJFc2NoZXJpY2hpYS1jb2xpIiwgZm9sZC5wbG90PUZBTFNFfQ0KKGdyYWZfZWNvbGkgPC0gcGxhbl9saXRvcmFsX21lZGlvICU+JSANCiAgIGdncGxvdChhZXMoY29kX2VzdGFjYW8sDQogICAgICAgICAgICAgIGVfY29saSkpKw0KICAgYW5ub3RhdGUoInJlY3QiLA0KICAgICAgICAgICAgeG1pbiA9IC1JbmYsIHhtYXggPSBJbmYsDQogICAgICAgICAgICB5bWluID0gMzIwMCwgeW1heCA9IEluZiwNCiAgICAgICAgICAgIGFscGhhID0gMSwNCiAgICAgICAgICAgIGZpbGwgPSAiI2FjNTA3OSIpKyAjPnBpb3IgY2xhc3NlDQogICBhbm5vdGF0ZSgicmVjdCIsDQogICAgICAgICAgICB4bWluID0gLUluZiwgeG1heCA9IEluZiwNCiAgICAgICAgICAgIHltaW4gPSA4MDAsIHltYXggPSAzMjAwLA0KICAgICAgICAgICAgYWxwaGEgPSAxLA0KICAgICAgICAgICAgZmlsbCA9ICIjZmNmN2FiIikrICNjbGFzc2UgMw0KICAgYW5ub3RhdGUoInJlY3QiLA0KICAgICAgICAgICAgeG1pbiA9IC1JbmYsIHhtYXggPSBJbmYsDQogICAgICAgICAgICB5bWluID0gMTYwLCB5bWF4ID0gODAwLA0KICAgICAgICAgICAgYWxwaGEgPSAxLA0KICAgICAgICAgICAgZmlsbCA9ICIjNzBjMThjIikrICNjbGFzc2UgMg0KICAgYW5ub3RhdGUoInJlY3QiLA0KICAgICAgICAgICAgeG1pbiA9IC1JbmYsIHhtYXggPSBJbmYsDQogICAgICAgICAgICB5bWluID0gMCwgeW1heCA9IDE2MCwNCiAgICAgICAgICAgIGFscGhhID0gMSwNCiAgICAgICAgICAgIGZpbGwgPSAiIzhkY2RlYiIpKyAjY2xhc3NlIDENCiAgIHN0YXRfc3VtbWFyeSgNCiAgICAgZnVuLmRhdGEgPSBmLA0KICAgICBnZW9tID0gJ2Vycm9yYmFyJywNCiAgICAgd2lkdGggPSAwLjMsDQogICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjY1KSwNCiAgICkrDQogICBzdGF0X3N1bW1hcnkoDQogICAgIGZ1bi5kYXRhID0gZiwNCiAgICAgZ2VvbSA9ICJib3hwbG90IiwNCiAgICAgd2lkdGggPSAwLjcsDQogICAgIGZpbGwgPSAnI0Y4RjhGRicsDQogICAgIGNvbG9yID0gImJsYWNrIiwNCiAgICAgb3V0bGllci5zaGFwZSA9IDEsICNzZSBkZWl4YXIgTkEgZmljYSBzw7MgbyBqaXR0ZXIsIHNlIG7Do28sIGRlaXhhIDENCiAgICkrDQogICAjIGZhY2V0X3dyYXAofnBlcmlvZG8pKw0KICAgbGFicyh0aXRsZSA9ICIqRXNjaGVyaWNoaWEgY29saSoiLA0KICAgICAgICB4PSJFc3Rhw6fDo28iLA0KICAgICAgICB5PSJOTVAvMTAwbUwiKSsNCiAgIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBleHBhbnNpb24obXVsdCA9IGMoMC4wMSwgMC4wMSkpLA0KICAgICAgICAgICAgICAgICAgICAgICMgbi5icmVha3MgPSA5LA0KICAgICAgICAgICAgICAgICAgICAgIG4uYnJlYWtzID0gNiwNCiAgICAgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKG1pbihwbGFuX2xpdG9yYWxfbWVkaW8kZV9jb2xpLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF4KHBsYW5fbGl0b3JhbF9tZWRpbyRlX2NvbGksIG5hLnJtID0gVFJVRSkpLA0KICAgICAgICAgICAgICAgICAgICAgIHRyYW5zID0gImxvZzEwIiwNCiAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBzY2FsZXM6Om51bWJlcl9mb3JtYXQoYWNjdXJhY3kgPSAxLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZWNpbWFsLm1hcmsgPSAiLCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJpZy5tYXJrID0gIiAiKSkrDQogICBnZ2JlZXN3YXJtOjpnZW9tX3F1YXNpcmFuZG9tKA0KICAgICBzaXplID0gMS4yLA0KICAgICBhbHBoYSA9IC4yNSwNCiAgICAgd2lkdGggPSAuMDcsDQogICApKw0KICMgc2NhbGVfeF9kaXNjcmV0ZShsaW1pdHMgPSBjKCI4NzM5ODUwMCIsDQogIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjg3Mzk4OTgwIiwNCiAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiODczOTg5MDAiLA0KICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICI4NzM5ODk1MCIsDQogIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjg3NDA1NTAwIiwNCiAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiODc0MDY5MDAiLA0KICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICI4NzQwOTkwMCIpLA0KICMgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJQTTEiLCAiUE0yIiwgIlBNMyIsICJQTTQiLCAiUE01IiwgIlBNNiIsICJQTTciKQ0KICMgKSsNCiBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLA0KIHNlPUZBTFNFLCAjc3RhcmRhbmQgZXJyb3IgPSBkZXN2aW8gcGFkcsOjbyAtPiBzZSBkZWl4YXIgVFJVRSBnZXJhIG8gaW50ZXJ2YWxvIGRlIGNvbmZpYW7Dp2EgZGUgOTUlDQogICAgICAgICAgICAgYWVzKGdyb3VwPTEpLA0KICAgICAgICAgICAgIGFscGhhPSAwLjUsICN0cmFuc3BhcmVuY2lhIGRlIDUwJQ0KICAgICAgICAgICAgIG5hLnJtID0gVFJVRSwgI3JlbW92ZXIgTkFzDQogICAgICAgICAgICAgc2l6ZSA9IDEpKw0KIHRoZW1lX2dyYWZzKCkrDQogICB0aGVtZSgNCiAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoDQogICAgICAgYW5nbGUgPSA5MCwNCiAgICAgICAjIHNpemU9MTUsDQogICAgICAgIyBmYWNlPTINCiAgICAgKSwNCiAgICAgcGxvdC50aXRsZSA9IA0KICAgICAgIGVsZW1lbnRfbWFya2Rvd24oDQogICAgICAgICBoanVzdCA9IDAuNSwNCiAgICAgICAgIGNvbG9yID0gImJsYWNrIiwNCiAgICAgICAgIHNpemUgPSAxOSksDQogICApDQopDQpgYGANCg0KIyMjIEbDs3Nmb3JvIFRvdGFsIHsjc2VjLWbDs3Nmb3JvLXRvdGFsfQ0KDQpgYGB7ciBHcsOhZmljbyBmw7NzZm9ybyB0b3RhbCwgd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0UsIGZpZy5jYXA9IkbDs3Nmb3JvIHRvdGFsIiwgZm9sZC5wbG90PUZBTFNFfQ0KKGdyYWZfcHRvdCA8LSBnZ3Bsb3QocGxhbl9saXRvcmFsX21lZGlvLA0KICAgICAgICAgICAgICAgICAgICAgYWVzKGNvZF9lc3RhY2FvLA0KICAgICAgICAgICAgICAgICAgICAgICAgIGZvc2Zvcm9fdG90YWwpKSsNCiAgIGFubm90YXRlKCJyZWN0IiwNCiAgICAgICAgICAgIHhtaW4gPSAtSW5mLCB4bWF4ID0gSW5mLA0KICAgICAgICAgICAgeW1pbiA9IDAuMTUsIHltYXggPSBJbmYsDQogICAgICAgICAgICBhbHBoYSA9IDEsDQogICAgICAgICAgICBmaWxsID0gIiNhYzUwNzkiKSsgIz5waW9yIGNsYXNzZQ0KICAgYW5ub3RhdGUoInJlY3QiLA0KICAgICAgICAgICAgeG1pbiA9IC1JbmYsIHhtYXggPSBJbmYsDQogICAgICAgICAgICB5bWluID0gMC4xLCB5bWF4ID0gMC4xNSwNCiAgICAgICAgICAgIGFscGhhID0gMSwNCiAgICAgICAgICAgIGZpbGwgPSAiI2ZjZjdhYiIpKyAjY2xhc3NlIDMNCiAgIGFubm90YXRlKCJyZWN0IiwNCiAgICAgICAgICAgIHhtaW4gPSAtSW5mLCB4bWF4ID0gSW5mLA0KICAgICAgICAgICAgeW1pbiA9IDAsIHltYXggPSAwLjEsDQogICAgICAgICAgICBhbHBoYSA9IDEsDQogICAgICAgICAgICBmaWxsID0gIiM4ZGNkZWIiKSsgI2NsYXNzZSAxDQogICBzdGF0X3N1bW1hcnkoDQogICAgIGZ1bi5kYXRhID0gZiwNCiAgICAgZ2VvbSA9ICdlcnJvcmJhcicsDQogICAgIHdpZHRoID0gMC4zLA0KICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC42NSksDQogICApKw0KICAgc3RhdF9zdW1tYXJ5KA0KICAgICBmdW4uZGF0YSA9IGYsDQogICAgIGdlb20gPSAiYm94cGxvdCIsDQogICAgIHdpZHRoID0gMC43LA0KICAgICBmaWxsID0gJyNGOEY4RkYnLA0KICAgICBjb2xvciA9ICJibGFjayIsDQogICAgIG91dGxpZXIuc2hhcGUgPSAxLCAjc2UgZGVpeGFyIE5BIGZpY2Egc8OzIG8gaml0dGVyLCBzZSBuw6NvLCBkZWl4YSAxDQogICApKw0KICAgIyBmYWNldF93cmFwKH5wZXJpb2RvKSsNCiAgIGxhYnModGl0bGUgPSAiRsOzc2Zvcm8gdG90YWwiLA0KICAgICAgICB4PSJFc3Rhw6fDo28iLA0KICAgICAgICB5PSJtZy9MIikrDQogICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gZXhwYW5zaW9uKG11bHQgPSBjKDAuMDMsMC4wMykpLA0KICAgICAgICAgICAgICAgICAgICAgIG4uYnJlYWtzID0gOCwNCiAgICAgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKG1pbihwbGFuX2xpdG9yYWxfbWVkaW8kZm9zZm9yb190b3RhbCwgbmEucm0gPSBUUlVFKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1heChwbGFuX2xpdG9yYWxfbWVkaW8kZm9zZm9yb190b3RhbCksIG5hLnJtID0gVFJVRSksDQogICAgICAgICAgICAgICAgICAgICAgdHJhbnMgPSAibG9nMTAiLA0KICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IHNjYWxlczo6bnVtYmVyX2Zvcm1hdChhY2N1cmFjeSA9IC4wMDEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlY2ltYWwubWFyayA9ICIsIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmlnLm1hcmsgPSAiICIpDQogICApKw0KICAgZ2diZWVzd2FybTo6Z2VvbV9xdWFzaXJhbmRvbSgNCiAgICAgc2l6ZSA9IDEuMiwNCiAgICAgYWxwaGEgPSAuMjUsDQogICAgIHdpZHRoID0gLjA3LA0KICAgKSsNCiAgICMgc2NhbGVfeF9kaXNjcmV0ZShsaW1pdHMgPSBjKCI4NzM5ODUwMCIsIA0KICAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjg3Mzk4OTgwIiwgDQogICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiODczOTg5MDAiLCANCiAgICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICI4NzM5ODk1MCIsIA0KICAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjg3NDA1NTAwIiwgDQogICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiODc0MDY5MDAiLCANCiAgICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICI4NzQwOTkwMCIpLA0KICAgIyAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIlBNMSIsICJQTTIiLCAiUE0zIiwgIlBNNCIsICJQTTUiLCAiUE02IiwgIlBNNyIpDQogICAjICkrDQogICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLA0KICAgICAgICAgICAgICAgc2U9RkFMU0UsICNzZSBkZWl4YXIgVFJVRSBnZXJhIG8gaW50ZXJ2YWxvIGRlIGNvbmZpYW7Dp2EgZGUgOTUlDQogICAgICAgICAgICAgICBhZXMoZ3JvdXA9MSksDQogICAgICAgICAgICAgICBhbHBoYT0uNSwNCiAgICAgICAgICAgICAgIG5hLnJtID0gVFJVRSwNCiAgICAgICAgICAgICAgIHNpemUgPSAxKSsNCiAgIHRoZW1lX2dyYWZzKCkNCikNCmBgYA0KDQojIyMgTml0cm9nw6puaW8gYW1vbmlhY2FsIHsjc2VjLW5pdHJvZ8OqbmlvLWFtb25pYWNhbH0NCg0KYGBge3IgR3LDoWZpY28gTml0cm9nw6puaW8gQW1vbmlhY2FsLCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRSwgZmlnLmNhcD0iTml0cm9nw6puaW8gQW1vbmlhY2FsIiwgZm9sZC5wbG90PUZBTFNFfQ0KKGdyYWZfbmFtb24gPC0gZ2dwbG90KHBsYW5fbGl0b3JhbF9tZWRpbywNCiAgICAgICAgICAgICAgICAgYWVzKGNvZF9lc3RhY2FvLA0KICAgICAgICAgICAgICAgICAgICAgbml0cm9nZW5pb19hbW9uaWFjYWwpKSsNCiAgIGFubm90YXRlKCJyZWN0IiwNCiAgICAgICAgICAgIHhtaW4gPSAtSW5mLCB4bWF4ID0gSW5mLA0KICAgICAgICAgICAgeW1pbiA9IDEzLjMsIHltYXggPSBJbmYsDQogICAgICAgICAgICBhbHBoYSA9IDEsDQogICAgICAgICAgICBmaWxsID0gIiNhYzUwNzkiKSsgIz5waW9yIGNsYXNzZQ0KICAgYW5ub3RhdGUoInJlY3QiLA0KICAgICAgICAgICAgeG1pbiA9IC1JbmYsIHhtYXggPSBJbmYsDQogICAgICAgICAgICB5bWluID0gMy43LCB5bWF4ID0gMTMuMywNCiAgICAgICAgICAgIGFscGhhID0gMSwNCiAgICAgICAgICAgIGZpbGwgPSAiI2ZjZjdhYiIpKyAjY2xhc3NlIDMNCiAgIGFubm90YXRlKCJyZWN0IiwNCiAgICAgICAgICAgIHhtaW4gPSAtSW5mLCB4bWF4ID0gSW5mLA0KICAgICAgICAgICAgeW1pbiA9IDAsIHltYXggPSAzLjcsDQogICAgICAgICAgICBhbHBoYSA9IDEsDQogICAgICAgICAgICBmaWxsID0gIiM4ZGNkZWIiKSsgI2NsYXNzZSAxDQogICBzdGF0X3N1bW1hcnkoDQogICAgIGZ1bi5kYXRhID0gZiwNCiAgICAgZ2VvbSA9ICdlcnJvcmJhcicsDQogICAgIHdpZHRoID0gMC4zLA0KICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC42NSksDQogICApKw0KICAgc3RhdF9zdW1tYXJ5KA0KICAgICBmdW4uZGF0YSA9IGYsDQogICAgIGdlb20gPSAiYm94cGxvdCIsDQogICAgIHdpZHRoID0gMC43LA0KICAgICBmaWxsID0gJyNGOEY4RkYnLA0KICAgICBjb2xvciA9ICJibGFjayIsDQogICAgIG91dGxpZXIuc2hhcGUgPSAxLCAjc2UgZGVpeGFyIE5BIGZpY2Egc8OzIG8gaml0dGVyLCBzZSBuw6NvLCBkZWl4YSAxDQogICApKw0KICAgIyBmYWNldF93cmFwKH5wZXJpb2RvKSsNCiAgIGxhYnModGl0bGUgPSAiTml0cm9nw6puaW8gYW1vbmlhY2FsIiwNCiAgICAgICAgeD0iRXN0YcOnw6NvIiwNCiAgICAgICAgeT0ibWcvTCIpKw0KICAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGV4cGFuc2lvbihtdWx0ID0gYygwLjAxLCAwLjA1KSksDQogICAgICAgICAgICAgICAgICAgICAgbi5icmVha3MgPSA5LA0KICAgICAgICAgICAgICAgICAgICAgIGxpbWl0cyA9IGMobWluKHBsYW5fbGl0b3JhbF9tZWRpbyRuaXRyb2dlbmlvX2Ftb25pYWNhbCwgbmEucm0gPSBUUlVFKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDE1DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIG1heChwbGFuX2xpdG9yYWxfbWVkaW8kbml0cm9nZW5pb19hbW9uaWFjYWwsIG5hLnJtID0gVFJVRSkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICksDQogICAgICAgICAgICAgICAgICAgICAgdHJhbnMgPSAibG9nMTAiLA0KICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IHNjYWxlczo6bnVtYmVyX2Zvcm1hdChhY2N1cmFjeSA9IC4wMDEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlY2ltYWwubWFyayA9ICIsIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmlnLm1hcmsgPSAiICIpKSsNCiAgIGdnYmVlc3dhcm06Omdlb21fcXVhc2lyYW5kb20oDQogICAgIHNpemUgPSAxLjIsDQogICAgIGFscGhhID0gLjI1LA0KICAgICB3aWR0aCA9IC4wNywNCiAgICkrDQogICAjIHNjYWxlX3hfZGlzY3JldGUobGltaXRzID0gYygiODczOTg1MDAiLCANCiAgICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICI4NzM5ODk4MCIsIA0KICAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjg3Mzk4OTAwIiwgDQogICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiODczOTg5NTAiLCANCiAgICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICI4NzQwNTUwMCIsIA0KICAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjg3NDA2OTAwIiwgDQogICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiODc0MDk5MDAiKSwNCiAgICMgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJQTTEiLCAiUE0yIiwgIlBNMyIsICJQTTQiLCAiUE01IiwgIlBNNiIsICJQTTciKQ0KICAgIyApKw0KICAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwNCiAgICAgICAgICAgICAgIHNlPUZBTFNFLCAjc2UgZGVpeGFyIFRSVUUgZ2VyYSBvIGludGVydmFsbyBkZSBjb25maWFuw6dhIGRlIDk1JQ0KICAgICAgICAgICAgICAgYWVzKGdyb3VwPTEpLA0KICAgICAgICAgICAgICAgYWxwaGE9LjUsDQogICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUsDQogICAgICAgICAgICAgICBzaXplID0gMSkrDQogICB0aGVtZV9ncmFmcygpDQopDQpgYGANCg0KIyMjIFR1cmJpZGV6IHsjc2VjLXR1cmJpZGV6fQ0KDQpgYGB7ciBHcsOhZmljbyBUdXJiaWRleiwgZmlnLmNhcD0idHVyYmlkZXoiLCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRSwgZm9sZC5wbG90PUZBTFNFfQ0KKGdyYWZfdHVyYiA8LSBnZ3Bsb3QocGxhbl9saXRvcmFsX21lZGlvLA0KICAgICAgICAgICAgICAgICAgIGFlcyhjb2RfZXN0YWNhbywNCiAgICAgICAgICAgICAgICAgICAgICAgdHVyYmlkZXopKSsNCiAgIGFubm90YXRlKCJyZWN0IiwNCiAgICAgICAgICAgIHhtaW4gPSAtSW5mLCB4bWF4ID0gSW5mLA0KICAgICAgICAgICAgeW1pbiA9IDEwMCwgeW1heCA9IEluZiwNCiAgICAgICAgICAgIGFscGhhID0gMSwNCiAgICAgICAgICAgIGZpbGwgPSAiI2FjNTA3OSIpKyAjPnBpb3IgY2xhc3NlDQogICBhbm5vdGF0ZSgicmVjdCIsDQogICAgICAgICAgICB4bWluID0gLUluZiwgeG1heCA9IEluZiwNCiAgICAgICAgICAgIHltaW4gPSA0MCwgeW1heCA9IDEwMCwNCiAgICAgICAgICAgIGFscGhhID0gMSwNCiAgICAgICAgICAgIGZpbGwgPSAiI2ZjZjdhYiIpKyAjY2xhc3NlIDMNCiAgIGFubm90YXRlKCJyZWN0IiwNCiAgICAgICAgICAgIHhtaW4gPSAtSW5mLCB4bWF4ID0gSW5mLA0KICAgICAgICAgICAgeW1pbiA9IDAsIHltYXggPSA0MCwNCiAgICAgICAgICAgIGFscGhhID0gMSwNCiAgICAgICAgICAgIGZpbGwgPSAiIzhkY2RlYiIpKyAjY2xhc3NlIDENCiAgIHN0YXRfc3VtbWFyeSgNCiAgICAgZnVuLmRhdGEgPSBmLA0KICAgICBnZW9tID0gJ2Vycm9yYmFyJywNCiAgICAgd2lkdGggPSAwLjMsDQogICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjY1KSwNCiAgICkrDQogICBzdGF0X3N1bW1hcnkoDQogICAgIGZ1bi5kYXRhID0gZiwNCiAgICAgZ2VvbSA9ICJib3hwbG90IiwNCiAgICAgd2lkdGggPSAwLjcsDQogICAgIGZpbGwgPSAnI0Y4RjhGRicsDQogICAgIGNvbG9yID0gImJsYWNrIiwNCiAgICAgb3V0bGllci5zaGFwZSA9IDEsICNzZSBkZWl4YXIgTkEgZmljYSBzw7MgbyBqaXR0ZXIsIHNlIG7Do28sIGRlaXhhIDENCiAgICkrDQogICAjIGZhY2V0X3dyYXAofnBlcmlvZG8pKw0KICAgbGFicyh0aXRsZSA9ICJUdXJiaWRleiIsDQogICAgICAgIHg9IkVzdGHDp8OjbyIsDQogICAgICAgIHk9IlVOVCIpKw0KICAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGV4cGFuc2lvbihtdWx0ID0gYygwLjA1LCAwLjA1KSksDQogICAgICAgICAgICAgICAgICAgICAgbi5icmVha3MgPSA4LA0KICAgICAgICAgICAgICAgICAgICAgIGxpbWl0cyA9IGMoDQogICAgICAgICAgICAgICAgICAgICAgICAjIDEsDQogICAgICAgICAgICAgICAgICAgICAgICBtaW4ocGxhbl9saXRvcmFsX21lZGlvJHR1cmJpZGV6LCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICAgICAgICAgICAgICAgICAgIyA1MDANCiAgICAgICAgICAgICAgICAgICAgICAgIG1heChwbGFuX2xpdG9yYWxfbWVkaW8kdHVyYmlkZXosIG5hLnJtID0gVFJVRSkNCiAgICAgICAgICAgICAgICAgICAgICApLA0KICAgICAgICAgICAgICAgICAgICAgIHRyYW5zID0gImxvZzEwIiwNCiAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBzY2FsZXM6Om51bWJlcl9mb3JtYXQoYWNjdXJhY3kgPSAxLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZWNpbWFsLm1hcmsgPSAiLCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJpZy5tYXJrID0gIiAiKSkrDQogICAgZ2diZWVzd2FybTo6Z2VvbV9xdWFzaXJhbmRvbSgNCiAgICAgc2l6ZSA9IDEuMiwNCiAgICAgYWxwaGEgPSAuMjUsDQogICAgIHdpZHRoID0gLjA3LA0KICAgKSsNCiAgICMgc2NhbGVfeF9kaXNjcmV0ZShsaW1pdHMgPSBjKCI4NzM5ODUwMCIsIA0KICAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjg3Mzk4OTgwIiwgDQogICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiODczOTg5MDAiLCANCiAgICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICI4NzM5ODk1MCIsIA0KICAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjg3NDA1NTAwIiwgDQogICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiODc0MDY5MDAiLCANCiAgICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICI4NzQwOTkwMCIpLA0KICAgIyAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIlBNMSIsICJQTTIiLCAiUE0zIiwgIlBNNCIsICJQTTUiLCAiUE02IiwgIlBNNyIpDQogICAjICkrDQogICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLA0KICAgICAgICAgICAgICAgc2U9RkFMU0UsICNzZSBkZWl4YXIgVFJVRSBnZXJhIG8gaW50ZXJ2YWxvIGRlIGNvbmZpYW7Dp2EgZGUgOTUlDQogICAgICAgICAgICAgICBhZXMoZ3JvdXA9MSksDQogICAgICAgICAgICAgICBhbHBoYT0uNSwNCiAgICAgICAgICAgICAgIG5hLnJtID0gVFJVRSwNCiAgICAgICAgICAgICAgIHNpemUgPSAxKSsNCiAgIHRoZW1lX2dyYWZzKCkNCikNCmBgYA0KDQojIyMgcEggeyNzZWMtcEh9DQoNCmBgYHtyIEdyw6FmaWNvIHBILCBmaWcuY2FwPSJwSCIsIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFLCBmb2xkLnBsb3Q9RkFMU0V9DQooZ3JhZl9wSCA8LSBnZ3Bsb3QocGxhbl9saXRvcmFsX21lZGlvLA0KICAgICAgICAgICAgICAgICBhZXMoY29kX2VzdGFjYW8sDQogICAgICAgICAgICAgICAgICAgICBwaCkpKw0KICAgYW5ub3RhdGUoInJlY3QiLA0KICAgICAgICAgICAgeG1pbj0tSW5mLA0KICAgICAgICAgICAgeG1heD1JbmYsDQogICAgICAgICAgICB5bWluPS1JbmYsDQogICAgICAgICAgICB5bWF4PTYsDQogICAgICAgICAgICBhbHBoYT0xLA0KICAgICAgICAgICAgZmlsbD0iI2ViNTY2MSIpKyAjY2xhc3NlIDQNCiAgIGFubm90YXRlKCJyZWN0IiwNCiAgICAgICAgICAgIHhtaW49LUluZiwNCiAgICAgICAgICAgIHhtYXg9SW5mLA0KICAgICAgICAgICAgeW1pbj05LA0KICAgICAgICAgICAgeW1heD1JbmYsDQogICAgICAgICAgICBhbHBoYT0xLA0KICAgICAgICAgICAgZmlsbD0iI2ViNTY2MSIpKyAjY2xhc3NlIDQNCiAgIGFubm90YXRlKCJyZWN0IiwNCiAgICAgICAgICAgIHhtaW49LUluZiwNCiAgICAgICAgICAgIHhtYXg9SW5mLA0KICAgICAgICAgICAgeW1pbj02LA0KICAgICAgICAgICAgeW1heD05LA0KICAgICAgICAgICAgYWxwaGE9MSwNCiAgICAgICAgICAgIGZpbGw9IiM4ZGNkZWIiKSsgI2NsYXNzZSAxDQogICBzdGF0X3N1bW1hcnkoDQogICAgIGZ1bi5kYXRhID0gZiwNCiAgICAgZ2VvbSA9ICdlcnJvcmJhcicsDQogICAgIHdpZHRoID0gMC4zLA0KICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC42NSksDQogICApKw0KICAgc3RhdF9zdW1tYXJ5KA0KICAgICBmdW4uZGF0YSA9IGYsDQogICAgIGdlb20gPSAiYm94cGxvdCIsDQogICAgIHdpZHRoID0gMC43LA0KICAgICBmaWxsID0gJyNGOEY4RkYnLA0KICAgICBjb2xvciA9ICJibGFjayIsDQogICAgIG91dGxpZXIuc2hhcGUgPSAxLCAjc2UgZGVpeGFyIE5BIGZpY2Egc8OzIG8gaml0dGVyLCBzZSBuw6NvLCBkZWl4YSAxDQogICApKw0KICAgIyBmYWNldF93cmFwKH5wZXJpb2RvKSsNCiAgIGxhYnModGl0bGUgPSAicEgiLA0KICAgICAgICB4PSJFc3Rhw6fDo28iLA0KICAgICAgICB5PSIiKSsNCiAgIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBleHBhbnNpb24obXVsdCA9IGMoMC4wMSwgMC4wMSkpLA0KICAgICAgICAgICAgICAgICAgICAgIG4uYnJlYWtzID0gOCwNCiAgICAgICAgICAgICAgICAgICAgICBsaW1pdHMgPSBjKDQsMTEpLA0KICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IHNjYWxlczo6bnVtYmVyX2Zvcm1hdChhY2N1cmFjeSA9IDEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlY2ltYWwubWFyayA9ICIsIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmlnLm1hcmsgPSAiICIpDQogICAgICAgICAgICAgICAgICAgICAgKSsNCiAgICBnZ2JlZXN3YXJtOjpnZW9tX3F1YXNpcmFuZG9tKA0KICAgICBzaXplID0gMS4yLA0KICAgICBhbHBoYSA9IC4yNSwNCiAgICAgd2lkdGggPSAuMDcsDQogICApKw0KICAgIyBzY2FsZV94X2Rpc2NyZXRlKGxpbWl0cyA9IGMoIjg3Mzk4NTAwIiwgDQogICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiODczOTg5ODAiLCANCiAgICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICI4NzM5ODkwMCIsIA0KICAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjg3Mzk4OTUwIiwgDQogICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiODc0MDU1MDAiLCANCiAgICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICI4NzQwNjkwMCIsIA0KICAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjg3NDA5OTAwIiksDQogICAjICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiUE0xIiwgIlBNMiIsICJQTTMiLCAiUE00IiwgIlBNNSIsICJQTTYiLCAiUE03IikNCiAgICMgKSsNCiAgIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsDQogICAgICAgICAgICAgICBzZT1GQUxTRSwgI3NlIGRlaXhhciBUUlVFIGdlcmEgbyBpbnRlcnZhbG8gZGUgY29uZmlhbsOnYSBkZSA5NSUNCiAgICAgICAgICAgICAgIGFlcyhncm91cD0xKSwNCiAgICAgICAgICAgICAgIGFscGhhPS41LA0KICAgICAgICAgICAgICAgbmEucm0gPSBUUlVFLA0KICAgICAgICAgICAgICAgc2l6ZSA9IDEpKw0KICAgdGhlbWVfZ3JhZnMoKQ0KKQ0KYGBgDQoNCiMjIyBTw7NsaWRvcyBUb3RhaXMgeyNzZWMtc8OzbGlkb3MtdG90YWlzfQ0KDQpPIHBhcsOibWV0cm8gYFPDs2xpZG9zIFRvdGFpc2AgbsOjbyB0ZXZlIG1lZGnDp8O1ZXMgbm8gcGVyw61vZG8gYW5hbGlzYWRvLCBlbnTDo28gZmljYSBhcm1hemVuYWRvIG5hIHRhYmVsYSBjb21vIHZhbG9yIHZhemlvLCBvdSBgcmBOQVxgLiBRdWFuZG8gdm9jw6ogZm9yIGZhemVyIGFuw6FsaXNlIGUgdGl2ZXIgdmFsb3JlcywgYWx0ZXJlIG8gYGV2YWxgIHBhcmEgYFRSVUVgLg0KDQpgYGB7ciBHcsOhZmljbyBTw7NsVG90LCBmaWcuY2FwPSJzw7NsaWRvcy10b3RhaXMiLCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRSwgZm9sZC5wbG90PUZBTFNFLCBlcnJvciA9IFRSVUUsIGV2YWw9RkFMU0V9DQooZ3JhZl9zb2xpZG9zX3RvdGFpcyA8LSBnZ3Bsb3QocGxhbl9saXRvcmFsX21lZGlvLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFlcyhjb2RfZXN0YWNhbywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc29saWRvc190b3RhaXMpKSsNCiAgIGFubm90YXRlKCJyZWN0IiwNCiAgICAgICAgICAgIHhtaW4gPSAtSW5mLCB4bWF4ID0gSW5mLA0KICAgICAgICAgICAgeW1pbiA9IDUwMCwgeW1heCA9IEluZiwNCiAgICAgICAgICAgIGFscGhhID0gMSwNCiAgICAgICAgICAgIGZpbGw9IiNhYzUwNzkiKSsgIz5waW9yIGNsYXNzZQ0KICAgYW5ub3RhdGUoInJlY3QiLA0KICAgICAgICAgICAgeG1pbiA9IC1JbmYsIHhtYXggPSBJbmYsDQogICAgICAgICAgICB5bWluID0gLUluZiwgeW1heCA9IDUwMCwNCiAgICAgICAgICAgIGFscGhhID0gMSwNCiAgICAgICAgICAgIGZpbGw9IiM4ZGNkZWIiKSsgI2NsYXNzZSAxDQpzdGF0X3N1bW1hcnkoDQogICAgIGZ1bi5kYXRhID0gZiwNCiAgICAgZ2VvbSA9ICdlcnJvcmJhcicsDQogICAgIHdpZHRoID0gMC4zLA0KICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC42NSksDQogICApKw0KICAgc3RhdF9zdW1tYXJ5KA0KICAgICBmdW4uZGF0YSA9IGYsDQogICAgIGdlb20gPSAiYm94cGxvdCIsDQogICAgIHdpZHRoID0gMC43LA0KICAgICBmaWxsID0gJyNGOEY4RkYnLA0KICAgICBjb2xvciA9ICJibGFjayIsDQogICAgIG91dGxpZXIuc2hhcGUgPSAxLCAjc2UgZGVpeGFyIE5BIGZpY2Egc8OzIG8gaml0dGVyLCBzZSBuw6NvLCBkZWl4YSAxDQogICApKw0KICAgIyBmYWNldF93cmFwKH5wZXJpb2RvKSsNCiAgIGxhYnModGl0bGUgPSAiU8OzbGlkb3MgdG90YWlzIiwNCiAgICAgICAgeD0iRXN0YcOnw6NvIiwNCiAgICAgICAgeT0iIikrDQogICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gZXhwYW5zaW9uKG11bHQgPSBjKDAuMDEsIDAuMDUpKSwNCiAgICAgICAgICAgICAgICAgICAgICBuLmJyZWFrcyA9IDgsDQogICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWF4KHBsYW5fbGl0b3JhbF9tZWRpbyRzb2xpZG9zX3RvdGFpcywgbmEucm0gPSBUUlVFKQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKSwNCiAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBzY2FsZXM6Om51bWJlcl9mb3JtYXQoYWNjdXJhY3kgPSAxLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZWNpbWFsLm1hcmsgPSAiLCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJpZy5tYXJrID0gIiAiKSkrDQogICBnZ2JlZXN3YXJtOjpnZW9tX3F1YXNpcmFuZG9tKA0KICAgICBzaXplID0gMS4yLA0KICAgICBhbHBoYSA9IC4yNSwNCiAgICAgd2lkdGggPSAuMDcsDQogICApKw0KICAgIyBzY2FsZV94X2Rpc2NyZXRlKGxpbWl0cyA9IGMoIjg3Mzk4NTAwIiwNCiAgICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICI4NzM5ODk4MCIsDQogICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiODczOTg5MDAiLA0KICAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjg3Mzk4OTUwIiwNCiAgICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICI4NzQwNTUwMCIsDQogICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiODc0MDY5MDAiLA0KICAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjg3NDA5OTAwIiksDQogICAjICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiUE0xIiwgIlBNMiIsICJQTTMiLCAiUE00IiwgIlBNNSIsICJQTTYiLCAiUE03IikNCiAgICMgKSsNCiAgIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsDQogICAgICAgICAgICAgICBzZT1GQUxTRSwgI3NlIGRlaXhhciBUUlVFIGdlcmEgbyBpbnRlcnZhbG8gZGUgY29uZmlhbsOnYSBkZSA5NSUNCiAgICAgICAgICAgICAgIGFlcyhncm91cD0xKSwNCiAgICAgICAgICAgICAgIGFscGhhPS41LA0KICAgICAgICAgICAgICAgbmEucm0gPSBUUlVFLA0KICAgICAgICAgICAgICAgc2l6ZSA9IDEpKw0KICAgdGhlbWVfZ3JhZnMoKQ0KKQ0KYGBgDQoNCiMjIyBDb25kdXRpdmlkYWRlIHsjc2VjLWNvbmR1dGl2aWRhZGV9DQoNCmBgYHtyIEdyw6FmaWNvIGNvbmRfZWxldCwgZmlnLmNhcD0iY29uZHV0aXZpZGFkZS1lbGV0cmljYSIsIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFLCBmb2xkLnBsb3Q9RkFMU0V9DQooZ3JhZl9jb25kX2VsZXQgPC0gZ2dwbG90KHBsYW5fbGl0b3JhbF9tZWRpbywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgYWVzKGNvZF9lc3RhY2FvLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uZHV0aXZpZGFkZSkpKw0KICAgYW5ub3RhdGUoInJlY3QiLA0KICAgICAgICAgICAgeG1pbiA9IC1JbmYsIHhtYXggPSBJbmYsDQogICAgICAgICAgICB5bWluID0gNTAwLCB5bWF4ID0gSW5mLA0KICAgICAgICAgICAgYWxwaGEgPSAxLA0KICAgICAgICAgICAgZmlsbCA9ICIjZWI1NjYxIikrICNjbGFzc2UgNA0KICAgYW5ub3RhdGUoInJlY3QiLA0KICAgICAgICAgICAgeG1pbiA9IC1JbmYsIHhtYXggPSBJbmYsDQogICAgICAgICAgICB5bWluID0gMCwgeW1heCA9IDUwMCwNCiAgICAgICAgICAgIGFscGhhID0gMSwNCiAgICAgICAgICAgIGZpbGwgPSAiIzhkY2RlYiIpKyAjY2xhc3NlIDENCiAgc3RhdF9zdW1tYXJ5KA0KICAgICBmdW4uZGF0YSA9IGYsDQogICAgIGdlb20gPSAnZXJyb3JiYXInLA0KICAgICB3aWR0aCA9IDAuMywNCiAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuNjUpLA0KICAgKSsNCiAgIHN0YXRfc3VtbWFyeSgNCiAgICAgZnVuLmRhdGEgPSBmLA0KICAgICBnZW9tID0gImJveHBsb3QiLA0KICAgICB3aWR0aCA9IDAuNywNCiAgICAgZmlsbCA9ICcjRjhGOEZGJywNCiAgICAgY29sb3IgPSAiYmxhY2siLA0KICAgICBvdXRsaWVyLnNoYXBlID0gMSwgI3NlIGRlaXhhciBOQSBmaWNhIHPDsyBvIGppdHRlciwgc2UgbsOjbywgZGVpeGEgMQ0KICAgKSsNCiAgICMgZmFjZXRfd3JhcCh+cGVyaW9kbykrDQogICBsYWJzKHRpdGxlID0gIkNvbmR1dGl2aWRhZGUgZWzDqXRyaWNhIiwNCiAgICAgICAgeD0iRXN0YcOnw6NvIiwNCiAgICAgICAgeT0iwrVtaG9zL2NtIikrDQogICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gZXhwYW5zaW9uKG11bHQgPSBjKDAuMDUsIDAuMDUpKSwNCiAgICAgICAgICAgICAgICAgICAgICBuLmJyZWFrcyA9IDgsDQogICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYyhtaW4ocGxhbl9saXRvcmFsX21lZGlvJGNvbmR1dGl2aWRhZGUsIG5hLnJtID0gVFJVRSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXgocGxhbl9saXRvcmFsX21lZGlvJGNvbmR1dGl2aWRhZGUsIG5hLnJtID0gVFJVRSkpLA0KICAgICAgICAgICAgICAgICAgICAgIHRyYW5zID0gImxvZzEwIiwNCiAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBzY2FsZXM6Om51bWJlcl9mb3JtYXQoYWNjdXJhY3kgPSAxLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZWNpbWFsLm1hcmsgPSAiLCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJpZy5tYXJrID0gIiAiKSkrDQogICBnZ2JlZXN3YXJtOjpnZW9tX3F1YXNpcmFuZG9tKA0KICAgICBzaXplID0gMS4yLA0KICAgICBhbHBoYSA9IC4yNSwNCiAgICAgd2lkdGggPSAuMDcsDQogICApKw0KICAgIyBzY2FsZV94X2Rpc2NyZXRlKGxpbWl0cyA9IGMoIjg3Mzk4NTAwIiwgDQogICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiODczOTg5ODAiLCANCiAgICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICI4NzM5ODkwMCIsIA0KICAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjg3Mzk4OTUwIiwgDQogICAjICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiODc0MDU1MDAiLCANCiAgICMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICI4NzQwNjkwMCIsIA0KICAgIyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjg3NDA5OTAwIiksDQogICAjICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiUE0xIiwgIlBNMiIsICJQTTMiLCAiUE00IiwgIlBNNSIsICJQTTYiLCAiUE03IikNCiAgICMgKSsNCiAgIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsDQogICAgICAgICAgICAgICBzZT1GQUxTRSwgI3NlIGRlaXhhciBUUlVFIGdlcmEgbyBpbnRlcnZhbG8gZGUgY29uZmlhbsOnYSBkZSA5NSUNCiAgICAgICAgICAgICAgIGFlcyhncm91cD0xKSwNCiAgICAgICAgICAgICAgIGFscGhhPS41LA0KICAgICAgICAgICAgICAgbmEucm0gPSBUUlVFLA0KICAgICAgICAgICAgICAgc2l6ZSA9IDEpKw0KICAgdGhlbWVfZ3JhZnMoKSsNCiAgIHRoZW1lKA0KICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dCgNCiAgICAgICBhbmdsZSA9IDkwLA0KICAgICAgICMgc2l6ZT0xNSwNCiAgICAgICAjIGZhY2U9Mg0KICAgICApDQogICApDQopDQpgYGANCg0KIyMgQW7DoWxpc2UgYW8gbG9uZ28gZG8gdGVtcG8geyNzZWMtYW7DoWxpc2UtYW8tbG9uZ28tZG8tdGVtcG99DQoNClBhcmEgZ2VyYXIgdW0gZ3LDoWZpY28gYW8gbG9uZ28gZG8gdGVtcG8gcHJhIGNhZGEgdW1hIGRhcyBlc3Rhw6fDtWVzIMOpIG5lY2Vzc8OhcmlvIGFsdGVyYXIgbyBgYW5vX2luaWNpYWxgIGUgbyBgYW5vX2ZpbmFsYC4gVGFtYsOpbSDDqSBuZWNlc3PDoXJpbyBzZWxlY2lvbmFyIHF1YWwgcGFyw6JtZXRybyBxdWUgc2UgcXVlciBmYXplciBhIHZpc3VhbGl6YcOnw6NvLg0KDQpgYGB7ciBncsOhZmljbyBhbyBsb25nbyBkbyB0ZW1wbywgd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0UsIGZvbGQucGxvdD1GQUxTRX0NCmFub19pbmljaWFsIDwtIDIwMTUNCmFub19maW5hbCA8LSAyMDIyDQoNCih0aW1lbGluZSA8LSBwbGFuX2xpdG9yYWxfbWVkaW8gJT4lDQogIGZpbHRlcihhbm9fY29sZXRhID4gYW5vX2luaWNpYWwgJg0KICAgICAgICAgICBhbm9fY29sZXRhIDw9IGFub19maW5hbCkgJT4lDQogIGRwbHlyOjpzZWxlY3QoY29kX2VzdGFjYW8sIGVfY29saSwgZGF0YV9jb2xldGEpICU+JQ0KICBncm91cF9ieShjb2RfZXN0YWNhbykgJT4lDQogIGdncGxvdCgNCiAgICBhZXMoeCA9IGRhdGFfY29sZXRhLA0KICAgICAgICB5ID0gZV9jb2xpLA0KICAgICAgICBjb2xvciA9IGNvZF9lc3RhY2FvDQogICAgKSkrDQogICAgZ2VvbV9saW5lKA0KICAgICAgIyBhZXMoY29sb3IgPSBDT0RJR08pLA0KICAgICAgbmEucm0gPSBUUlVFKSsNCiAgICBnZW9tX3BvaW50KA0KICAgICAgIyBhZXMoY29sb3IgPSBDT0RJR08pLA0KICAgICAgbmEucm0gPSBUUlVFKSsNCiAgICBzY2FsZV94X2RhdGUoDQogICAgICBsaW1pdHMgPSBhcy5EYXRlKGMoDQogICAgICAgIHltZChnbHVlKCJ7YW5vX2luaWNpYWx9LTAxLTAxIikpLA0KICAgICAgICB5bWQoZ2x1ZSgie2Fub19maW5hbH0tMDEtMDEiKSkNCiAgICAgICAgIyBOQSAjcG9kZSB1c2FyIE5BIHRhbWLDqW0NCiAgICAgICkpLA0KICAgICAgZXhwYW5kID0gYygwLjAsIDAuMCksDQogICAgICBkYXRlX2JyZWFrcyA9ICIyIHllYXJzIiwNCiAgICAgIG1pbm9yX2JyZWFrcyA9ICIxIHllYXJzIiwNCiAgICAgIGRhdGVfbGFiZWxzID0gIiVZIiwNCiAgICApKw0KICAjIGdlb21fc21vb3RoKA0KICAjICAgbWV0aG9kID0gImxtIiwgI3JlZ3Jlc3NhbyBsaW5lYXINCiAgIyAgIHNlID0gVFJVRSwgI3NlIGRlaXhhciBUUlVFIGdlcmEgbyBpbnRlcnZhbG8gZGUgY29uZmlhbsOnYSBkZSA5NSUNCiAgIyAgIGFlcyhncm91cCA9IDEpLA0KICAjICAgYWxwaGEgPS41LA0KICAjICAgbmEucm0gPSBUUlVFLA0KICAjICAgc2l6ZSA9IDAuMywNCiAgIyAgICMgZnVsbHJhbmdlID0gVFJVRSwNCiAgIyAgIHNob3cubGVnZW5kID0gVFJVRQ0KICAjICkrDQogIHN0YXRfc21vb3RoKA0KICAgIGdlb20gPSAic21vb3RoIiwNCiAgICAjIHNwYW4gPSAwLjIsDQogICAgc2UgPSBUUlVFLCAjc2UgZGVpeGFyIFRSVUUgZ2VyYSBvIGludGVydmFsbyBkZSBjb25maWFuw6dhIGRlIDk1JQ0KICAgICMgYWVzKGdyb3VwID0gMSksDQogICAgIyBhbHBoYSA9LjUsDQogICAgbmEucm0gPSBUUlVFLA0KICAgICMgc2l6ZSA9IDAuMywNCiAgICBmdWxscmFuZ2UgPSBUUlVFLA0KICAgIHNob3cubGVnZW5kID0gVFJVRQ0KICApKw0KICBmYWNldF93cmFwKA0KICAgIH5jb2RfZXN0YWNhbywNCiAgICBucm93ID0gNCwNCiAgKSsNCiAgdGhlbWVfYncoKQ0KKQ0KYGBgDQoNCiMjIENvcnJlbGHDp8OjbyB7I3NlYy1jb3JyZWxhw6fDo299DQoNCmBgYHtyIENvcnJlbGHDp8OjbywgZmlnLmNhcD0iY29ycmVsYcOnw6NvLXBhcmFtZXRyb3MtcXVhbGlkYWRlLWFndWEiLCB0aW1lX2l0ID0gVFJVRSwgd2FybmluZz1GQUxTRSwgbWVzc2FnZSA9IEZBTFNFLCBmb2xkLnBsb3Q9RkFMU0V9DQpwYXJhbWV0cm9zX2lxYV9saXRfbWVkaW8gPC0gcGxhbl9saXRvcmFsX21lZGlvICU+JQ0KICBkcGx5cjo6c2VsZWN0KGNvZF9lc3RhY2FvLA0KICAgICAgICAgcGgsDQogICAgICAgICBkYm8sDQogICAgICAgICBlX2NvbGksDQogICAgICAgICBuaXRyb2dlbmlvX2Ftb25pYWNhbCwNCiAgICAgICAgICMgbml0cm9fa2plbGRhaGwsDQogICAgICAgICAjIG5pdHJvX3RvdGFsLA0KICAgICAgICAgZm9zZm9yb190b3RhbCwNCiAgICAgICAgIHRlbXBlcmF0dXJhX2RhX2FndWEsDQogICAgICAgICB0dXJiaWRleiwNCiAgICAgICAgIHNvbGlkb3NfdG90YWlzLA0KICAgICAgICAgb3hpZ2VuaW9fZGlzc29sdmlkbywNCiAgICAgICAgIGNvbmR1dGl2aWRhZGUsDQogICAgICAgICBhbm9fY29sZXRhDQogICAgICAgICApIA0KDQpwYXJhbWV0cm9zX2lxYV9saXRfbWVkaW8gJT4lIA0KICBkcGx5cjo6c2VsZWN0KA0KICAgIC1jb2RfZXN0YWNhbywNCiAgICAtYW5vX2NvbGV0YSwNCiAgICAtc29saWRvc190b3RhaXMNCiAgICApICU+JQ0KICAjIGdyb3VwX2J5KGNvZF9lc3RhY2FvKSAlPiUNCiAgcmVuYW1lKA0KICAgIENFID0gY29uZHV0aXZpZGFkZSwNCiAgICBPRCA9IG94aWdlbmlvX2Rpc3NvbHZpZG8sDQogICAgIyBTVCA9IHNvbGlkb3NfdG90YWlzLA0KICAgIFR1cmIgPSB0dXJiaWRleiwNCiAgICBUZW1wID0gdGVtcGVyYXR1cmFfZGFfYWd1YSwNCiAgICBQdG90ID0gZm9zZm9yb190b3RhbCwNCiAgICBOQW1vbiA9IG5pdHJvZ2VuaW9fYW1vbmlhY2FsLA0KICAgIHBIID0gcGgsDQogICAgREJPID0gZGJvLA0KICAgIEVfY29saSA9IGVfY29saQ0KICAgICMgTlRLID0gbml0cm9fa2plbGRhaGwNCiAgKSAlPiUgDQogIGdnY29ycigNCiAgICBtZXRob2QgPQ0KICAgICJjb21wbGV0ZS5vYnMiLA0KICAgICMgInBlYXJzb24iLA0KICAgICMgInBhaXJ3aXNlIiwNCiAgICBuYW1lID0gIkNvcnJlbGHDp8OjbyIsDQogICAgbGFiZWwgPSBUUlVFLA0KICAgIGxhYmVsX2FscGhhID0gVFJVRSwNCiAgICBkaWdpdHMgPSAzLA0KICAgIGxvdyA9ICIjM0I5QUIyIiwNCiAgICBtaWQgPSAiI0VFRUVFRSIsDQogICAgaGlnaCA9ICIjRjIxQTAwIiwNCiAgICAjIHBhbGV0dGUgPSAiUmRZbEJ1IiwNCiAgICBsYXlvdXQuZXhwID0gMCwNCiAgICBsZWdlbmQucG9zaXRpb24gPSAibGVmdCIsDQogICAgbGFiZWxfcm91bmQgPSAzLA0KICAgICMgbGVnZW5kLnNpemUgPSAxOCwNCiAgICBnZW9tID0gInRpbGUiLA0KICAgIG5icmVha3MgPSAxMCwNCiAgKSsNCiAgbGFicyh0aXRsZSA9ICJDb3JyZWxhw6fDo28gZW50cmUgcGFyw6JtZXRyb3MgZsOtc2ljby1xdcOtbWljb3MgbmFcbkJhY2lhIEhpZHJvZ3LDoWZpY2EgZG8gTGl0b3JhbCBNw6lkaW8iKSsNCiAgdGhlbWVfbGluZWRyYXcoKSsNCiAgdGhlbWUoDQogICAgbGVnZW5kLnBvc2l0aW9uID0gYygwLjE1LCAwLjYpLA0KICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYpLA0KICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksDQogICAgIyBsZWdlbmQuc3BhY2luZyA9IHVuaXQoZWxlbWVudF90ZXh0KCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICMgdW5pdHMgPSA1KQ0KICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gMTYpDQogICkNCmBgYA0KDQojIyMgQ29ycmVsYcOnw6NvIGVudHJlIHBhcsOibWV0cm9zIHF1ZSBjb21ww7VlbSBvIElRQSBjb20gc2lnbmlmaWPDom5jaWEgZXN0YXTDrXN0aWNhDQoNCkVzc2UgcHJvY2Vzc28gZGVtYW5kYSBiYXN0YW50ZSBwcm9jZXNzYW1lbnRvLCBwYXJhIGRlc2FiaWxpdMOhLWxvIGRlaXhlIGBldmFsID0gRkFMU0VgLg0KYGBge3IgZ3JhZi1jb3JyZWwtZXN0YXRpc3RpY2EsIHRpbWVfaXQgPSBUUlVFLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlID0gRkFMU0UsIGV2YWwgPSBUUlVFfQ0KY29ycmVsX0lRQV9saXRfbWVkaW8gPC0gcGFyYW1ldHJvc19pcWFfbGl0X21lZGlvICU+JQ0KICBkcGx5cjo6c2VsZWN0KC1jb2RfZXN0YWNhbykgJT4lDQogIGdncGFpcnModGl0bGUgPSAiQ29ycmVsYcOnw6NvIGVudHJlIHBhcsOibWV0cm9zIHF1ZSBjb21ww7VlbSBvIElRQSIsDQogICAgICAgICAgYXhpc0xhYmVscyA9ICJzaG93IikNCmNvcnJlbF9JUUFfbGl0X21lZGlvDQpgYGANCg0KIyMgU2FsdmFyIG9zIGdyw6FmaWNvcyB7I3NlYy1zYWx2YXItb3MtZ3LDoWZpY29zfQ0KDQpSZXBsaWNhciBlc3NlIG1vZGVsbyBwcm9zIGdyw6FmaWNvcyBxdWUgZGVzZWphIHNhbHZhci5cDQoxLiBDcmlhciBub3ZvIGNvZGUgY2h1bmsgKGBDdHJsK0FsdCtJYClcDQoyLiBDb3BpYXIgYSBmw7NybXVsYSBhYmFpeG9cDQozLiBDb2xhciBuZXNzZSBub3ZvIGNvZGUgY2h1bmtcDQoNCk9zIGdyw6FmaWNvcyBmaWNhcsOjbyBzYWx2b3MgZW0gdW1hIHBhc3RhIHF1ZSBpcsOhIHNlciBjcmlhZGEgYSBwYXJ0aXIgZG8gY8OzZGlnby4NCg0KYGBge3Igc2FsdmFyLWdyYWZpY29zLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRX0NCmdnc2F2ZSgiZ3JhZl9vZC5wbmciLA0KICAgICAgIHBsb3QgPSBncmFmX29kLCAjYWx0ZXJhY2FvDQogICAgICAgcGF0aCA9ICIuL2dyYWZpY29zIiwNCiAgICAgICBkcGkgPSAzMDAsDQogICAgICAgdHlwZSA9ICJjYWlybyIpDQpgYGANCg0KIyBNYXBhcyB7I3NlYy1tYXBhc30NCg0KIyMgUGFjb3RlcyBwcmEgZ2VyYcOnw6NvIGRlIG1hcGFzIHsjc2VjLXBhY290ZXMtcHJhLWdlcmHDp8Ojby1kZS1tYXBhcyAucGFjb3Rlc30NCg0KYGBge3IgcGFjb3Rlcy1nZW9lc3BhY2lhaXMsIG1lc3NhZ2UgPSBUUlVFLCB3YXJuaW5nID0gRkFMU0V9DQpwYWNtYW46OnBfbG9hZChyYXN0ZXIsIGxlYWZsZXQsIHNmDQogICAgICAgICAgICAgICAjIHByZXR0eW1hcHIsIHJqc29uLCByb3NtLA0KICAgICAgICAgICAgICAgIyBnZ3NwYXRpYWwNCiAgICAgICAgICAgICAgICMgcmdkYWwsIHJnZW9zLA0KICAgICAgICAgICAgICAgIyBndG9vbHMsIHRpZHl2ZXJzZSwgcm5hdHVyYWxlYXJ0aCwNCiAgICAgICAgICAgICAgICMgcm5hdHVyYWxlYXJ0aGRhdGEsIHJldGljdWxhdGUsIG1hcHRvb2xzLA0KICAgICAgICAgICAgICAgIyBtYXBzLCBnZ3Bsb3QyLCBnZ3NwYXRpYWwsIHJnZW9zLCBnZ21hcA0KICAgICAgICAgICAgICAgKQ0KYGBgDQoNCiMjIE1hcGEgZXN0w6F0aWNvIHsjc2VjLW1hcGEtZXN0w6F0aWNvfQ0KDQpJbXBvcnRhbmRvIGFzIGluZm9ybWHDp8O1ZXMgbmVjZXNzw6FyaWFzIHByYSBnZXJhciBtYXBhcyBkZSBwcmVjaXBpdGHDp8Ojby5cDQpGb250ZTogR0FETSBbXjFdLCBbXjJdDQoNClteMV06IDxodHRwczovL2dhZG0ub3JnL21hcHMvQlJBLmh0bWw+DQoNClteMl06IDxodHRwczovL2dhZG0ub3JnL2RhdGEuaHRtbD4NCg0KYGBge3IgbWFwYS1lc3RhdGljbywgZmlnLmNhcCA9ICJNYXBhIGVzdMOhdGljbyBkbyBSUyJ9DQpCcmFzaWwgPC0gZ2V0RGF0YSgNCiAgJ0dBRE0nLA0KICBjb3VudHJ5ID0gJ0JyYXppbCcsDQogIGxldmVsID0gMw0KKSAlPiUNCiAgc3RfYXNfc2YoKQ0KDQpSUyA8LSBzdWJzZXQoQnJhc2lsLA0KICAgICAgICAgICAgIE5BTUVfMSA9PSAiUmlvIEdyYW5kZSBkbyBTdWwiKQ0KDQpsYmwgPC0gZGF0YS5mcmFtZShtb250aF9hYmIgPSBtb250aC5hYmIsDQogICAgICAgICAgICAgICAgICBtZXMgPSAxOjEyKQ0KDQpwbGFuX2xpdG9yYWxfbWVkaW8gJT4lDQogIGdncGxvdCgNCiAgICAjIGFlcyh4ID0gbG9uZ3RpdHVkZSwNCiAgICAjICAgICB5ID0gbGF0aXR1ZGUsDQogICAgIyAgICAgbWFwX2lkID0gcmVnaW9uKQ0KICApKw0KICBnZW9tX3NmKA0KICAgIGRhdGEgPSBSUw0KICApKw0KICB0aGVtZV9idygpDQoNCiMgRGVmaW5pbmRvIG8gU1JDDQpSUyA8LSBSUyAlPiUNCiAgc3RfdHJhbnNmb3JtIChjcnMgPSA0Njc0KSAjNDMyNiA9IFdHUzg0LCA0Njc0ID0gU0lSR0FTMjAwMA0KYGBgDQoNCiMjIE1hcGEgaW50ZXJhdGl2byBjb20gbG9jYWxpemHDp8OjbyBkb3MgcG9udG9zIGRlIG1vbml0b3JhbWVudG8geyNzZWMtbWFwYS1pbnRlcmF0aXZvLWNvbS1sb2NhbGl6YcOnw6NvLWRvcy1wb250b3MtZGUtbW9uaXRvcmFtZW50b30NCg0KYGBge3IgbWFwYS1pbnRlcmF0aXZvLCBmaWcuY2FwID0gIk1hcGEgaW50ZXJhdGl2byJ9DQpsZWFmbGV0KFJTKSAlPiUgDQogIGFkZFByb3ZpZGVyVGlsZXMoDQogICAgIkVzcmkuV29ybGRJbWFnZXJ5IiAjSW1hZ2VtIGRlIHNhdMOpbGl0ZQ0KICAgICMgIk9wZW5TdHJlZXRNYXAuTWFwbmlrIiAjT3BlblN0cmVldE1hcCAtPiBTb2Z0d2FyZSBsaXZyZQ0KICApICU+JSANCiAgYWRkQ2lyY2xlTWFya2VycygNCiAgICBkYXRhID0gcGxhbl9saXRvcmFsX21lZGlvLA0KICAgIGxuZyA9IH5sb25naXR1ZGUsDQogICAgbGF0ID0gfmxhdGl0dWRlLA0KICAgIHBvcHVwID0gfnBhc3RlKA0KICAgICAgIjxiPkVzdGHDp8Ojbzo8L2I+Iix7Y29kX2VzdGFjYW99LCI8YnI+IiwNCiAgICAgICI8Yj5SZWN1cnNvIGjDrWRyaWNvOjwvYj4iLCByZWN1cnNvX2hpZHJpY28sICI8YnI+IiwNCiAgICAgICI8Yj5NdW5pY8OtcGlvOjwvYj4iLCBtdW5pY2lwaW8sDQogICAgICBzZXAgPSAiICINCiAgICApDQogICkgDQpgYGANCg0KIyMgTWFwYSBkZSBwcmVjaXBpdGHDp8OjbyBhbnVhbA0KDQpFc3NlIHByb2Nlc3NvIGRlbWFuZGEgYmFzdGFudGUgcHJvY2Vzc2FtZW50bywgcGFyYSBkZXNhYmlsaXTDoS1sbyBkZWl4ZSBgZXZhbCA9IEZBTFNFYC4NCmBgYHtyIEV4dHJhaW5kbyBvcyBkYWRvcyByYXN0ZXIgZGUgcHJlY2lwaXRhw6fDo28sIGV2YWwgPSBUUlVFLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRX0NCnN0X2NlbnRyb2lkKFJTKQ0KDQpQcmVjIDwtIGdldERhdGEoDQogICJ3b3JsZGNsaW0iLA0KICB2YXIgPSAicHJlYyIsDQogIHJlcyA9IDAuNSwNCiAgbGF0ID0gYygtMzAuMDMzMDU2LCAtMjkuNjg0MTcpLCAjcHJvY3VyYXIgbGF0IGxvbmcgbm8gZ29vZ2xlIGUgYWx0ZXJhciBhcXVpDQogIGxvbiA9IGMoLTUxLjIzMDAwMCwgLTUzLjgwNjk0KQ0KKQ0KDQpQcmVjX1JTIDwtIFByZWMgJT4lDQogIGNyb3AoUlMpICU+JQ0KICBtYXNrKFJTLCBuYS5ybSA9IFRSVUUpDQoNCnBsb3QoUHJlY19SUykNCg0KUFBBbnVhbF9SUyA8LSBkby5jYWxsKCJzdW0iLA0KICAgICAgICAgICAgICAgICAgICAgICB1bnN0YWNrKFByZWNfUlMpKQ0KcGxvdChQUEFudWFsX1JTKQ0KYGBgDQoNCmBgYHtyIEVsYWJvcmFuZG8gb3MgbWVzZXMgZGUgcHJlY2lwaXRhw6fDo28sIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFLCBldmFsID0gVFJVRX0NCnZscyA8LSByYXN0ZXJUb1BvaW50cyhQcmVjX1JTKSAlPiUNCiAgYXNfdGliYmxlKCkgJT4lDQogIGdhdGhlcih2YXIsIHZhbHVlLCAteCwgLXkpICU+JQ0KICBtdXRhdGUobWVzID0gcGFyc2VfbnVtYmVyKHZhcikpICU+JQ0KICBpbm5lcl9qb2luKC4sIGxibCwgYnkgPSAnbWVzJykgJT4lDQogIGRwbHlyOjpzZWxlY3QoeCwgeSwgbW9udGhfYWJiLCB2YWx1ZSkgJT4lDQogIG11dGF0ZShtb250aF9hYmIgPSBmYWN0b3IobW9udGhfYWJiLCBsZXZlbHMgPSBtb250aC5hYmIpKQ0KDQp2bHMgJT4lDQogIGZpbHRlcihtb250aF9hYmIgPT0gJ0phbicpDQoNCnN1bW1hcnkodmxzJHZhbHVlKSAjZGVzY29icmUgbyB2YWxvciBtw61uaW1vLCBtw6lkaW8gZSBtw6F4aW1vIGRlIHByZWNpcGl0YcOnw6NvDQpgYGANCg0KIyMgTWFwYSBjb20gcHJlY2lwaXRhw6fDo28gbWVuc2FsDQoNCkNhc28gcXVlaXJhIGdlcmFyIHVtIG1hcGEgY29tIGEgcHJlY2lwaXRhw6fDo28gbWVuc2FsLCBhbHRlcm5hciBvIGBldmFsYCBwYXJhIGBUUlVFYC4gQSBnZXJhw6fDo28gZGVzc2UgbWFwYSBkZW1hbmRhIGJhc3RhbnRlIHByb2Nlc3NhbWVudG8sIHJlY29tZW5kw6F2ZWwgbWFudGVyIGBpbmNsdWRlID0gRkFMU0VgIGUgYGVjaG8gPSBGQUxTRWAuDQoNCmBgYHtyIG1hcGFzLXByZWNpcGl0YWNhby1tZW5zYWwsIGluY2x1ZGUgPSBUUlVFLCBlY2hvID0gRkFMU0UsIGV2YWw9VFJVRX0NCmNvcmVzMTwtIGMoJyNmZjQyMjMnLCcjZjE5ZTIxJywnI2ZmZWUyMScsJyMwMGZmZmYnLCAnIzEwYWViZScsICcjMTY1ZGZmJywnIzkzMzFkYycpDQpjb3JlczI8LSBjKCcjOTMzMWRjJywgJyMxNjVkZmYnLCAnIzEwYWViZScsICcjMDBmZmZmJywgJyNmZmVlMjEnLCAnI2YxOWUyMScsICcjZmY0MjIzJykNCg0KDQooZ2cgPC0gZ2dwbG90KHZscykgICsNCiAgICBnZW9tX3RpbGUoYWVzKHggPSB4LA0KICAgICAgICAgICAgICAgICAgeSA9IHksDQogICAgICAgICAgICAgICAgICBmaWxsID0gdmFsdWUpKSArDQogICAgc2NhbGVfZmlsbF9ncmFkaWVudG4oY29sb3VycyA9IGNvcmVzMSwNCiAgICAgICAgICAgICAgICAgICAgICAgICBuYS52YWx1ZSA9ICd3aGl0ZScsDQogICAgICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygwLCAyNTApLA0KICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHNlcSgwLCAyNTAsIDI1KSkgKw0KICAgIGdlb21fc2YoZGF0YSA9IFJTLA0KICAgICAgICAgICAgZmlsbCA9IE5BLA0KICAgICAgICAgICAgY29sb3IgPSAnYmxhY2snLA0KICAgICAgICAgICAgc2l6ZSA9IDAuMikrDQogICAgZmFjZXRfd3JhcCh+IG1vbnRoX2FiYikgKw0KICAgICMgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IGMoLTcyLjUsIC03MS4wLCAtNjkuNSkpICsNCiAgICBnZ3RpdGxlKCJQcmVjaXBpdGHDp8OjbyBtZW5zYWwgLSBSUyIpKw0KICAgIGxhYnModGl0bGUgPSAnUHJlY2lwaXRhw6fDo28gTWVuc2FsIC0gUlMnLA0KICAgICAgICAgZmlsbCA9ICdtbScsDQogICAgICAgICB4ID0gJ0xvbmdpdHVkZScsDQogICAgICAgICB5ID0gJ0xhdGl0dWRlJywNCiAgICAgICAgIGNhcHRpb24gPSAiTGVvbmFyZG8gRmVybmFuZGVzIFdpbmsiKSArDQogICAgbGFicygNCiAgICAgIGNhcHRpb24gPSAiRm9udGU6IGh0dHBzOi8vb3NtZGF0YS5vcGVuc3RyZWV0bWFwLmRlLyINCiAgICApKw0KICAgIHRoZW1lX2J3KCkgKw0KICAgIHRoZW1lKA0KICAgICAgcGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAid2hpdGUiKSwNCiAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KHNpemUgPSAyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yPSJ3aGl0ZSIpLA0KICAgICAgbGVnZW5kLmtleS53aWR0aCA9IHVuaXQoNSwgJ2xpbmUnKSwNCiAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICdib3R0b20nLA0KICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dCgNCiAgICAgICAgc2l6ZSA9IDE2LA0KICAgICAgICBoanVzdCA9IDAuNSwNCiAgICAgICAgY29sb3IgPSAiYmxhY2siLA0KICAgICAgICBmYWNlID0gImJvbGQiDQogICAgICApLA0KICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoDQogICAgICAgIGZhY2UgPSAiYm9sZCIsDQogICAgICAgIGNvbG9yID0gImJsYWNrIiwNCiAgICAgICAgc2l6ZSA9IDgNCiAgICAgICksDQogICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dCgNCiAgICAgICAgYW5nbGUgPSA5MCwNCiAgICAgICAgZmFjZSA9ICJib2xkIiwNCiAgICAgICAgY29sb3IgPSAiYmxhY2siLA0KICAgICAgICBzaXplID0gOA0KICAgICAgKSwNCiAgICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoDQogICAgICAgIGZhY2U9ICdib2xkJywNCiAgICAgICAgc2l6ZT0gMTQsDQogICAgICAgIGhqdXN0PSAwLjUsDQogICAgICAgIGNvbG9yPSAnYmxhY2snDQogICAgICApLA0KICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsPSd3aGl0ZScpLA0KICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dCgNCiAgICAgICAgc2l6ZSA9IDExLA0KICAgICAgICBoanVzdCA9IDAuOCwNCiAgICAgICAgZmFjZSA9ICJpdGFsaWMiLA0KICAgICAgICBjb2xvciA9ICJyZWQiLCAjIiM0ZTRkNDciDQogICAgICAgIGZhbWlseT0ic2VyaWYiDQogICAgICApLA0KICAgICAgcGxvdC5jYXB0aW9uID0gZWxlbWVudF90ZXh0KA0KICAgICAgICBzaXplID0gMTAsDQogICAgICAgIGhqdXN0ID0gMC45NSwNCiAgICAgICAgY29sb3IgPSAiYmxhY2siLA0KICAgICAgKQ0KICAgICkgKw0KICAgIGd1aWRlcyhzaGFwZSA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KHNpemUgPSAxMCkpKQ0KKQ0KYGBgDQoNCiMgUmVmZXLDqm5jaWFzIC0gTGlua3Mgw7p0ZWlzIHsjc2VjLWxpbmtzLcO6dGVpc30NCg0KUmVjb21lbmRvLCBhYmFpeG8sIGFsZ3VtYXMgcmVmZXLDqm5jaWFzLiBUYW1iw6ltIGRlaXhvIHVtYSB0cmlsaGEgZGUgYXByZW5kaXphZG8gcXVlIGp1bGdvIHNlciBtYWlzIGbDoWNpbCBkbyBxdWUgYSBxdWUgcGVyY29ycmksIGNvbmZvcm1lIGRpYWdyYW1hIGFiYWl4by4NCg0KYGBge3IgZGlhZ3JhbWF9DQpwYWNtYW46OnBfbG9hZCgNCiAgRGlhZ3JhbW1lUg0KKQ0KRGlhZ3JhbW1lUjo6Z3JWaXooDQogICJkaWdyYXBoIHsNCiAgZ3JhcGggWw0KICBsYXlvdXQgPSBkb3QsDQogIHJhbmtkaXIgPSBMUg0KICBdDQoNCiAgbm9kZSBbc2hhcGUgPSBvdmFsXSAjcmVjdGFuZ2xlDQogIHJlYzEgW2xhYmVsID0gJ1RlbnRhciByZXByb2R1emlyIGPDs2RpZ29zXG5kZSBvdXRyYXMgcGVzc29hcyddDQogIHJlYzIgW2xhYmVsID0gJ0VudGVuZGVyIGEgZ3JhbcOhdGljYVxuZG9zIGdyw6FmaWNvcyddDQogIHJlYzMgW2xhYmVsID0gJ0ZhemVyIHVtIHByb2pldG9cbmRvIHplcm8nXQ0KICByZWM0IFtsYWJlbCA9ICdBcHJlbmRlciBSTWFya2Rvd24nXQ0KICByZWM1IFtsYWJlbCA9ICdwcm9jdXJhciBubyBZb3V0dWJlL1xuU3RhY2tPdmVyRmxvdyddDQogIHJlYzYgW2xhYmVsID0gJ3BhY290ZXMnXQ0KICByZWM3IFtsYWJlbCA9ICd0aWR5dmVyc2UsIGdncGxvdDInXQ0KICByZWM4IFtsYWJlbCA9ICdEZXNlbnZvbHZlciB1bSBTaGlueSBBcHAnXQ0KDQogICMgZWRnZSBkZWZpbml0aW9ucyB3aXRoIHRoZSBub2RlIElEcw0KICByZWMxIC0+IHJlYzUNCiAgcmVjMiAtPiByZWM2IC0+IHJlYzcNCiAgcmVjMSAtPiByZWMyIC0+IHJlYzMgLT4gcmVjNCAtPiByZWM4DQogIH0iLA0KICAjIGhlaWdodCA9IDUwMA0KKQ0KYGBgDQoNCiMjIFINCg0KW1IgZm9yIERhdGEgU2NpZW5jZV0oaHR0cHM6Ly9yNGRzLmhhZC5jby5uei9pbnRyb2R1Y3Rpb24uaHRtbCkNCg0KPiBVbSBkb3MgcHJpbmNpcGFpcyBsaXZyb3MgcGFyYSBxdWVtIGVzdMOhIHF1ZXJlbmRvIGFwcmVuZGVyIFIuIEVzc2Egw6kgYSAxwqogdmVyc8OjbywgcHVibGljYWRhIGVtIDIwMTcuIEVtIDIwMjMgc2Vyw6EgcHVibGljYWRhIGEgMsKqLCBhdHJhdsOpcyBkbyBbbGlua10oaHR0cHM6Ly9yNGRzLmhhZGxleS5ueikuDQoNCiMjIENoZWF0c2hlZXRzIHsjc2VjLWNoZWF0c2hlZXRzfQ0KDQpbQ2hlYXRzaGVldHNdKGh0dHBzOi8vcG9zaXQuY28vcmVzb3VyY2VzL2NoZWF0c2hlZXRzLykNCg0KW0dpdEh1YiBjb20gYXMgdmVyc8O1ZXMgbWFpcyBhdHVhbGl6YWRhc10oaHR0cHM6Ly9naXRodWIuY29tL3JzdHVkaW8vY2hlYXRzaGVldHMvKQ0KDQpbZ2dwbG90MiBjaGVhdHNoZWV0XShodHRwczovL3Bvc2l0LmNvL3dwLWNvbnRlbnQvdXBsb2Fkcy8yMDIyLzEwL2RhdGEtdmlzdWFsaXphdGlvbi0xLnBkZikNCg0KW2dncGxvdDIgY2hlYXRzaGVldCBlbSBwb3J0dWd1w6pzXShodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vcnN0dWRpby9jaGVhdHNoZWV0cy9tYWluL3RyYW5zbGF0aW9ucy9wb3J0dWd1ZXNlL2RhdGEtdmlzdWFsaXphdGlvbl9wdC5wZGYpDQoNClttYW5pcHVsYcOnw6NvIGRlIGRhZG9zIGVtIHBvcnR1Z3XDqnNdKGh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9yc3R1ZGlvL2NoZWF0c2hlZXRzL21haW4vdHJhbnNsYXRpb25zL3BvcnR1Z3Vlc2UvZGF0YS13cmFuZ2xpbmdfcHQucGRmKQ0KDQpbZHBseXIgY2hlYXRzaGVldF0oaHR0cHM6Ly9wb3NpdC5jby93cC1jb250ZW50L3VwbG9hZHMvMjAyMi8xMC9kYXRhLXRyYW5zZm9ybWF0aW9uLTEucGRmKQ0KDQojIyBSbWFya2Rvd24geyNzZWMtcm1hcmtkb3dufQ0KDQpbVHV0b3JpYWwgc29icmUgUk1hcmtkb3duXShodHRwczovL3lvdXR1LmJlLzE4QVVaT1dBYXpnKQ0KDQpbUm1hcmtkb3duIGJhc2ljc10oaHR0cHM6Ly9ybWFya2Rvd24ucnN0dWRpby5jb20vYXV0aG9yaW5nX2Jhc2ljcy5odG1sKQ0KDQpbUk1hcmtkb3duOiBUaGUgZGVmaW5pdGl2ZSBndWlkZV0oaHR0cHM6Ly9ib29rZG93bi5vcmcveWlodWkvcm1hcmtkb3duLykNCg0KIyMgUGFjb3Rlcw0KDQpba25pdHJdKGh0dHBzOi8veWlodWkub3JnL2tuaXRyL29wdGlvbnMvKXsucGFjb3Rlc30NCg0KW2ludHJvMnJdKGh0dHBzOi8vaW50cm8yci5jb20vZ3JhcGhpY3Nfci5odG1sKQ0KDQotICAgR2V0dGluZyBzdGFydGVkIHdpdGggUiBhbmQgUlN0dWRpbw0KDQotICAgU29tZSBSIGJhc2ljcw0KDQotICAgRGF0YSBpbiBSDQoNCi0gICBHcmFwaGljcyB3aXRoIGdncGxvdA0KDQotICAgU2ltcGxlIFN0YXRpc3RpY3MgaW4gUg0KDQotICAgUmVwcm9kdWNpYmxlIHJlcG9ydHMgd2l0aCBSIG1hcmtkb3duDQoNCiMjIENhbmFpcyBubyBZb3V0dWJlIHsjc2VjLWNhbmFpcy1uby15b3V0dWJlfQ0KDQpbUGF0IFNjaGxvc3NdKGh0dHBzOi8vd3d3LnlvdXR1YmUuY29tL0BSaWZmb21vbmFzKSAjZXNzZSBjYXJhIMOpIGdlbmlhbA0KDQpbQW1iaWVudGFsIFBybyBEZXZdKGh0dHBzOi8vd3d3LnlvdXR1YmUuY29tL0BhbWJpZW50YWxwcm9kZXY1Mzc5KQ0KDQpbTWFyY2VsbyBDYXJ2YWxobyBSaWJlaXJvIC0gWW91dHViZV0oaHR0cHM6Ly93d3cueW91dHViZS5jb20vQGNhcnZhbGhvcmliZWlybykNCg0KLSAgIFRlbSBvIFtCbG9nXShodHRwczovL2NhcnZhbGhvcmliZWlyby5uZXRsaWZ5LmFwcC8pIGRlbGUgdGFtYsOpbS4NCg0KW0Zlcm5hbmRhIFBlcmVzXShodHRwczovL3d3dy55b3V0dWJlLmNvbS9ARmVybmFuZGFQZXJlcykNCg0KW01hcmluIFN0YXRzXShodHRwczovL3d3dy55b3V0dWJlLmNvbS9AbWFyaW5zdGF0bGVjdHVyZXMpDQoNCiMgQWluZGEgcHJlY2lzYSBzZXIgaW1wbGVtZW50YWRvL2FqdXN0YWRvIHsjc2VjLWFpbmRhLXByZWNpc2Etc2VyLWltcGxlbWVudGFkb2FqdXN0YWRvIC51bm51bWJlcmVkfQ0KDQotICAgUlPDgWd1YSBkZXZlIGJ1c2NhciBkYWRvcyBhbnRlcmlvcmVzIGEgMjAxNS4NCi0gICBBIEZlcGFtIHRlbSBvcyBkYWRvcyBkZSBgYWx0aXR1ZGVgIGRhcyBlc3Rhw6fDtWVzLiBBIHBhcnRpciBkaXNzbyBwb2RlIHNlciBjYWxjdWxhZG8gbyBgJSBkZSBzYXR1cmHDp8OjbyBkZSBPeGlnw6puaW8gRGlzc29sdmlkb2AsIG5lY2Vzc8OhcmlvIHBhcmEgbyBjw6FsY3VsbyBkbyBJUUEuDQotICAgVG9ybmFyIGEgY29sdW5hIGRlIGBjaHV2YV8yNGhgIGNvbW8gZmFjdG9yLg0KLSAgIEEgY29sdW5hIGBob3JhX2NvbGV0YWAgZXN0w6EgY29tIGZvcm1hdG8gaW5jb3JyZXRvLg0KLSAgIEdlcmFyIHVtIGBTaGlueSBXZWIgQXBwYA0KLSAgIH5+VG9ybmFyIGEgY29sdW5hIGRlIGBtdW5pY2lwaW9gIGNvbSBhcGVuYXMgYSBwcmltZWlyYSBsZXRyYSBtYWnDunNjdWxhLn5+DQotICAgU2luY3Jvbml6YcOnw6NvIHZpYSBHaXRIdWINCi0gICBBcHJlbmRlciBhIGdlcmFyIG8gbWFwYSBkZSBwcmVjaXBpdGHDp8OjbyBtZW5zYWwgcHJhIHRvZG8gbyBSUw0KICAgIC0gICBPIFJTIGVzdMOhIGVudHJlIDIgZnVzb3MsIGVudMOjbyBhY2FiYSAicGFydGluZG8gbm8gbWVpbyIgYSBmaWd1cmENCi0gICBGdXR1cmFtZW50ZTogaW50ZWdyYcOnw6NvIHZpYSBHb29nbGUgU2hlZXRzLg0KDQojIEluZm9ybWHDp8O1ZXMgYWRpY2lvbmFpcyB7I3NlYy1pbmZvcm1hw6fDtWVzLWFkaWNpb25haXMgLnVubnVtYmVyZWR9DQoNCkUtbWFpbCBwYXJhIGNvbnRhdG86IFtsZW9uYXJkb2Z3aW5rXEBnbWFpbC5jb21dKGxlb25hcmRvZndpbmtAZ21haWwuY29tKQ0KDQpHaXRIdWI6IDxodHRwczovL2dpdGh1Yi5jb20vbGVvbmFyZG9md2luay8+DQoNCkxpbmtlZEluOiA8aHR0cHM6Ly93d3cubGlua2VkaW4uY29tL2luL2xlb25hcmRvZndpbmsvPg0KDQpgYGB7ciBub21lLCBpbmNsdWRlID0gRkFMU0V9DQojIG5vIFlBTUwgZG8gY29kZSBjaHVuazoNCiMgcHJhIGVzY29uZGVyIG8gY8OzZGlnbw0KDQojIGNsYXNzLnNvdXJjZSA9ICdmb2xkLWhpZGUnIA0KIyBmb2xkLm91dHB1dD1GQUxTRSwgDQojIGZvbGQucGxvdD1GQUxTRQ0KYGBgDQo=