#Trabalho da disciplina de Ciclo de Vida e Introdução à Linguagem R

#REALIZADO PELOs PARTICIPANTES

#FLAVIO ADMILSON SANTOS DE SOUZA — MATRICULA: 202503699836

#Jennifer Coutinho de Souza —– MATRICULA: 202503699879

#Julyanne de Souza Teixeira —– MATRICULA: 202503700001

#Marcella Francisco da Silva Carrilio —– MATRICULA: 202503699976

CONTEXTUALIZAÇÃO

1. Indicação da lista de bibliotecas usadas no início do trabalho

#instala um pacote 
#install.packages("tidyverse") #Manipulando o dataframe com tidyverse()

#Manipulando o dataframe com dplyr()
install.packages("dplyr")
install.packages("psych")
install.packages("readxl")
install.packages("ggplot2")
install.packages("readxl") #Importação de dados .xls para resultar em um dataframe

#importação da biblioteca --- CARREGAMENTO DOS PACOTES

# Para manipulação de dados
library(dplyr)

Anexando pacote: ‘dplyr’

Os seguintes objetos são mascarados por ‘package:stats’:

    filter, lag

Os seguintes objetos são mascarados por ‘package:base’:

    intersect, setdiff, setequal, union
library(readxl)## Alternativa mais robusta ao read.table

# Para análise estatística
library(psych)

# Para visualização
library(ggplot2)#analise de graficos barras

Anexando pacote: ‘ggplot2’

Os seguintes objetos são mascarados por ‘package:psych’:

    %+%, alpha
library(corrplot) # Ótimo para visualizar matrizes de correlação
corrplot 0.95 loaded
#library(tidyverse)
#remover objetos da memória
#rm(sexo) #remove somente o objeto X

#———————————————————————– # ETL (Extração - Transformação - Carga) #———————————————————————–

2. Indicação da fonte dos dados

#A fonte de dados é o arquivo “Tabela de atendimentos por convenio.xlsx”. - base de atendimentos onde transformei em um dataframe chamado teste2

4. Escrever o código para a importação do dataset

#Importação de dados .xlsx, o resultado é um dataframe
install.packages("readxl")
library(readxl)
tabela_atendimentos<- read_excel("Tabela de atendimentos por convenio.xlsx")
is.data.frame(tabela_atendimentos)
#Importação de dados .xlsx, o resultado é um dataframe
install.packages("readxl")
library(readxl)
tabela_atendimentos2023<- read_excel("Tabela de atendimentos por convenio 2023.xlsx")
is.data.frame(tabela_atendimentos2023)

3. Apresentar o metadado (dicionário de dados) do dataset

Para entender a estrutura do dataset, usamos a função str() após a importação.

#verificando a estrutura
str(tabela_atendimentos)
tibble [37 × 15] (S3: tbl_df/tbl/data.frame)
 $ Código  : chr [1:37] "15" "44" "9" "73" ...
 $ Convênio: chr [1:37] "Appai" "Particular" "Intermédica" "Bradesco" ...
 $ Jan/2022: num [1:37] 241 193 48 69 53 51 39 34 11 17 ...
 $ Fev/2022: num [1:37] 257 188 44 44 73 34 50 27 28 26 ...
 $ Mar/2022: num [1:37] 342 259 77 70 84 46 70 38 27 29 ...
 $ Abr/2022: num [1:37] 270 186 81 61 45 46 44 26 28 17 ...
 $ Mai/2022: num [1:37] 293 225 74 76 59 60 69 40 38 23 ...
 $ Jun/2022: num [1:37] 285 185 83 97 59 59 44 42 37 27 ...
 $ Jul/2022: num [1:37] 291 198 86 67 48 81 64 37 30 29 ...
 $ Ago/2022: num [1:37] 361 195 86 78 69 60 62 59 47 34 ...
 $ Set/2022: num [1:37] 305 167 73 57 72 54 54 53 39 20 ...
 $ Out/2022: num [1:37] 331 161 82 61 63 64 53 64 26 28 ...
 $ Nov/2022: num [1:37] 292 134 79 73 33 48 50 50 32 37 ...
 $ Dez/2022: num [1:37] 246 144 71 55 34 48 42 44 29 31 ...
 $ Total   : num [1:37] 3514 2235 884 808 692 ...

#———————————————————————– # Análise Exploratória de Dados básica #———————————————————————–

#Para visualizar o conteúdo dos dados importados
View(tabela_atendimentos) 

4. Escrever o código para importação do dataset

Criamos um banco de teste para manusear toda a nosso trabalho para evitar qualquer problema com o banco original


teste2 <- tabela_atendimentos
is.data.frame(teste2)
[1] TRUE

3. Apresentar o metadado (dicionário de dados) do dataset

Para entender a estrutura do dataset, usamos a função str() após a importação.

#verificando a estrutura
str(teste2)
tibble [37 × 15] (S3: tbl_df/tbl/data.frame)
 $ Código  : chr [1:37] "15" "44" "9" "73" ...
 $ Convênio: chr [1:37] "Appai" "Particular" "Intermédica" "Bradesco" ...
 $ Jan/2022: num [1:37] 241 193 48 69 53 51 39 34 11 17 ...
 $ Fev/2022: num [1:37] 257 188 44 44 73 34 50 27 28 26 ...
 $ Mar/2022: num [1:37] 342 259 77 70 84 46 70 38 27 29 ...
 $ Abr/2022: num [1:37] 270 186 81 61 45 46 44 26 28 17 ...
 $ Mai/2022: num [1:37] 293 225 74 76 59 60 69 40 38 23 ...
 $ Jun/2022: num [1:37] 285 185 83 97 59 59 44 42 37 27 ...
 $ Jul/2022: num [1:37] 291 198 86 67 48 81 64 37 30 29 ...
 $ Ago/2022: num [1:37] 361 195 86 78 69 60 62 59 47 34 ...
 $ Set/2022: num [1:37] 305 167 73 57 72 54 54 53 39 20 ...
 $ Out/2022: num [1:37] 331 161 82 61 63 64 53 64 26 28 ...
 $ Nov/2022: num [1:37] 292 134 79 73 33 48 50 50 32 37 ...
 $ Dez/2022: num [1:37] 246 144 71 55 34 48 42 44 29 31 ...
 $ Total   : num [1:37] 3514 2235 884 808 692 ...
#Manipulando o data frame
#toda a 5º linha
teste2 [5,]

# convertendo-o para um vetor primeiro
maior_valor_5linha <- max(as.matrix(dados_numericos), na.rm = TRUE)
#consultando uma coluna do dataframe
teste2["Convênio"]

5. Destacar os valores máximos das 20 primeiras linhas

#amostrando os valores maximos dos 20 primeiras linhas do nosso projeto de dados 
head(teste2, 20)

# 5. Destacar os convênios com mais atendimentos em Janeiro
# O arrange(desc(...)) ordena do maior para o menor
top_20_convenios_jan <- teste2 %>%
  arrange(desc(teste2$`Jan/2022`)) %>%
  head(20)

print("Top 20 convênios em Janeiro/2022:")
[1] "Top 20 convênios em Janeiro/2022:"
print(top_20_convenios_jan)

6. Destacar os valores minimos das 20 ultimas linhas

#retorna os 6 últimos
tail(teste2,20)
# 6. Destacar os convênios com menos atendimentos em Janeiro
bottom_20_convenios_jan <- teste2 %>%
  arrange(`Jan/2022`) %>% # Ordem crescente
  head(20)

print("Os 20 Convênios com menos atendimentos em Janeiro/2022:")
[1] "Os 20 Convênios com menos atendimentos em Janeiro/2022:"
print(bottom_20_convenios_jan)

7. Listar os nomes das colunas

#listar objetos do dataframe
ls(teste2)
 [1] "Abr/2022" "Ago/2022" "Código"   "Convênio" "Dez/2022" "Fev/2022" "Jan/2022" "Jul/2022" "Jun/2022" "Mai/2022" "Mar/2022" "Nov/2022"
[13] "Out/2022" "Set/2022" "Total"   
#listar objetos do dataframe
names(teste2)
 [1] "Código"   "Convênio" "Jan/2022" "Fev/2022" "Mar/2022" "Abr/2022" "Mai/2022" "Jun/2022" "Jul/2022" "Ago/2022" "Set/2022" "Out/2022"
[13] "Nov/2022" "Dez/2022" "Total"   

8. Verificar a dimensão do dataset (total de linhas e colunas)

dim(teste2)
[1] 37 15

9. Contar o total de amostras por uma das variáveis categóricas

#Representação de amostras de atendimentos realizados em janeiro de 2022 com amostra da totalização do mês


total_atendimentos <- teste2$`Jan/2022`

total_atendimentos <- table(total_atendimentos)

print(total_atendimentos)
total_atendimentos
  0   1   2   3   4   6   7   8   9  10  11  12  16  17  22  34  39  48  51  53  69 193 241 875 
  9   2   2   3   1   1   1   1   1   2   1   1   1   1   1   1   1   1   1   1   1   1   1   1 

10. Apresentar a estatística básica para o dataset – summary()

#resumo estatístico
summary(teste2)
    Código            Convênio            Jan/2022        Fev/2022         Mar/2022          Abr/2022         Mai/2022      
 Length:37          Length:37          Min.   :  0.0   Min.   :  0.00   Min.   :   0.00   Min.   :  0.00   Min.   :   0.00  
 Class :character   Class :character   1st Qu.:  1.0   1st Qu.:  1.00   1st Qu.:   1.00   1st Qu.:  2.00   1st Qu.:   1.00  
 Mode  :character   Mode  :character   Median :  7.0   Median :  9.00   Median :   9.00   Median :  6.00   Median :   9.00  
                                       Mean   : 47.3   Mean   : 48.65   Mean   :  65.19   Mean   : 51.08   Mean   :  60.54  
                                       3rd Qu.: 22.0   3rd Qu.: 27.00   3rd Qu.:  29.00   3rd Qu.: 28.00   3rd Qu.:  38.00  
                                       Max.   :875.0   Max.   :900.00   Max.   :1206.00   Max.   :945.00   Max.   :1120.00  
    Jun/2022          Jul/2022          Ago/2022          Set/2022          Out/2022          Nov/2022        Dez/2022     
 Min.   :   0.00   Min.   :   0.00   Min.   :   0.00   Min.   :   0.00   Min.   :   0.00   Min.   :  0.0   Min.   :  0.00  
 1st Qu.:   1.00   1st Qu.:   1.00   1st Qu.:   1.00   1st Qu.:   1.00   1st Qu.:   1.00   1st Qu.:  1.0   1st Qu.:  0.00  
 Median :   8.00   Median :   7.00   Median :   9.00   Median :  10.00   Median :  10.00   Median :  5.0   Median :  4.00  
 Mean   :  58.38   Mean   :  58.86   Mean   :  65.95   Mean   :  56.54   Mean   :  60.38   Mean   : 52.7   Mean   : 46.11  
 3rd Qu.:  37.00   3rd Qu.:  32.00   3rd Qu.:  47.00   3rd Qu.:  39.00   3rd Qu.:  29.00   3rd Qu.: 33.0   3rd Qu.: 31.00  
 Max.   :1080.00   Max.   :1089.00   Max.   :1220.00   Max.   :1046.00   Max.   :1117.00   Max.   :975.0   Max.   :853.00  
     Total        
 Min.   :    1.0  
 1st Qu.:   11.0  
 Median :   93.0  
 Mean   :  671.7  
 3rd Qu.:  372.0  
 Max.   :12426.0  

11. Realizar a análise de correlação via linha de comando

# 11. Realizar a análise de correlação entre os meses

# Usando o dataframe 'dados_numericos' que criamos
cor_resultado <- corr.test(dados_numericos, method = "pearson")

print(cor_resultado, short = FALSE) # 'short = FALSE' mostra mais detalhes
Call:corr.test(x = dados_numericos, method = "pearson")
Correlation matrix 
         Jan/2022 Fev/2022 Mar/2022 Abr/2022 Mai/2022 Jun/2022 Jul/2022 Ago/2022 Set/2022 Out/2022 Nov/2022 Dez/2022 Total
Jan/2022     1.00     1.00        1        1        1        1        1        1        1        1     0.99        1     1
Fev/2022     1.00     1.00        1        1        1        1        1        1        1        1     0.99        1     1
Mar/2022     1.00     1.00        1        1        1        1        1        1        1        1     1.00        1     1
Abr/2022     1.00     1.00        1        1        1        1        1        1        1        1     1.00        1     1
Mai/2022     1.00     1.00        1        1        1        1        1        1        1        1     1.00        1     1
Jun/2022     1.00     1.00        1        1        1        1        1        1        1        1     1.00        1     1
Jul/2022     1.00     1.00        1        1        1        1        1        1        1        1     1.00        1     1
Ago/2022     1.00     1.00        1        1        1        1        1        1        1        1     1.00        1     1
Set/2022     1.00     1.00        1        1        1        1        1        1        1        1     1.00        1     1
Out/2022     1.00     1.00        1        1        1        1        1        1        1        1     1.00        1     1
Nov/2022     0.99     0.99        1        1        1        1        1        1        1        1     1.00        1     1
Dez/2022     1.00     1.00        1        1        1        1        1        1        1        1     1.00        1     1
Total        1.00     1.00        1        1        1        1        1        1        1        1     1.00        1     1
Sample Size 
[1] 37
Probability values (Entries above the diagonal are adjusted for multiple tests.) 
         Jan/2022 Fev/2022 Mar/2022 Abr/2022 Mai/2022 Jun/2022 Jul/2022 Ago/2022 Set/2022 Out/2022 Nov/2022 Dez/2022 Total
Jan/2022        0        0        0        0        0        0        0        0        0        0        0        0     0
Fev/2022        0        0        0        0        0        0        0        0        0        0        0        0     0
Mar/2022        0        0        0        0        0        0        0        0        0        0        0        0     0
Abr/2022        0        0        0        0        0        0        0        0        0        0        0        0     0
Mai/2022        0        0        0        0        0        0        0        0        0        0        0        0     0
Jun/2022        0        0        0        0        0        0        0        0        0        0        0        0     0
Jul/2022        0        0        0        0        0        0        0        0        0        0        0        0     0
Ago/2022        0        0        0        0        0        0        0        0        0        0        0        0     0
Set/2022        0        0        0        0        0        0        0        0        0        0        0        0     0
Out/2022        0        0        0        0        0        0        0        0        0        0        0        0     0
Nov/2022        0        0        0        0        0        0        0        0        0        0        0        0     0
Dez/2022        0        0        0        0        0        0        0        0        0        0        0        0     0
Total           0        0        0        0        0        0        0        0        0        0        0        0     0

 Confidence intervals based upon normal theory.  To get bootstrapped values, try cor.ci

#———————————————————————– # Análise Exploratória de Dados com gráficos # Os gráficos serão exibidos na aba ‘Plots’ do RStudio ou em uma nova janela. #———————————————————————–

12. Criar um gráfico heatmap a partir das variáveis usadas na correlação

data <- as.matrix(dados_numericos)
heatmap(data)

13. Criar um scatterplot para o par de variáveis com maior correlação

FIZ UMA ADAPTAÇÃO POR CAUSA DA MINHA BASE DE DADOS E COM ISSO UTILIZEI OS ATENDIMENTOS POR MÊS PARA COMPARAÇÃPO DE PAR DE VARIÁVEIS

# (Código para encontrar var1 e var2 continua o mesmo)
# ...

# Gráfico atualizado sem o aviso de depreciação
ggplot(teste2, aes(x = .data[[var1]], y = .data[[var2]])) +
  geom_point(aes(color = Total), size = 4, alpha = 0.7) +
  geom_smooth(method = "lm", se = FALSE, color = "red") +
  labs(
    title = paste("Scatterplot de Maior Correlação:", var1, "vs", var2),
    x = paste("Atendimentos em", var1),
    y = paste("Atendimentos em", var2)
  ) +
  theme_minimal()

14. Realizar a análise bivariada por meio de scatterplots

#COMPARANDO 2 MESES DE ATENDIMENTOS MÉDICOS REALIZADOS, ONDE TIVEMOS O LEVE AUMENTO DO CONVÊNIO APPAI QUE EM JANEIRO TEVE MENOS ATENDIMENTOS DO QUE O NORMAL. 

a <- dados_numericos$`Jan/2022`; b <- dados_numericos$`Fev/2022`
plot(a,b) #plotando com pontos

plot(a, b, type = "l") #agora com linha
#Ainda, é possível realizar mudanças nas características das linhas. Basta utilizar os comandos “lwd=” e “lty=” que modificam, respectivamente, a largura e o estilo da linha:
lines(a, 2*b, lwd = 4)  #alterando a espessura da linha
lines(a, 0.5*b, lty = 2) #linha tracejada
lines(a, 3*b, lty = 3)   #linha pontilhada
lines(a, 4*b, lty = 2, lwd = 4) #linha tracejada grossa

15. Realizar a análise univariada com um histograma para uma variável numérica

# 15. Histograma da variável 'Total'
ggplot(teste20, aes(x = Total)) +
  geom_histogram(binwidth = 500, fill = "lightblue", color = "black") +
  labs(title = "Distribuição do Total de Atendimentos Anuais por Convênio", x = "Total de Atendimentos", y = "Frequência (Nº de Convênios)") +
  theme_classic()

16. Apresentar em apenas um gráfico vários histogramas para as variáveis numéricas

# 16. Múltiplos Histogramas (usando o objeto 'dados_long' correto)

ggplot(dados_long, aes(x = Atendimentos, fill = Mes)) +
  geom_histogram(binwidth = 20, show.legend = FALSE, color = "black") +
  facet_wrap(~ Mes, scales = "free") + # Cria um mini-gráfico para cada mês
  labs(title = "Histogramas de Atendimentos para Cada Mês",
       x = "Nº de Atendimentos",
       y = "Frequência") +
  theme_light()

17. Verificar com boxplots a presença de possíveis outliers

#Boxplot
x = c(teste2$`Jan/2022`)
y = c(teste2$`Fev/2022`)
z = c(teste2$`Mar/2022`)

boxplot(x,y,z) #para plotar no mesmo gráfico (comparação)

18. Criar um gráfico de barras ou colunas

# --- Código para o Item 18 (com ordenação) ---

# Primeiro, resumimos os dados
atendimentos_mensais <- dados_numericos %>%
  select(-Total) %>%
  summarise_all(sum) %>%
  pivot_longer(cols = everything(), names_to = "Mes", values_to = "Total_Atendimentos")

# Criamos um fator para ordenar os meses corretamente
ordem_meses <- c("Jan/2022", "Fev/2022", "Mar/2022", "Abr/2022", "Mai/2022", "Jun/2022", 
                 "Jul/2022", "Ago/2022", "Set/2022", "Out/2022", "Nov/2022", "Dez/2022")
atendimentos_mensais$Mes <- factor(atendimentos_mensais$Mes, levels = ordem_meses)

# Agora, o gráfico de barras com a sintaxe corrigida e ordenado
ggplot(atendimentos_mensais, aes(x = Mes, y = Total_Atendimentos, fill = Mes)) +
  geom_bar(stat = "identity", show.legend = FALSE) +
  geom_text(aes(label = Total_Atendimentos), vjust = -0.5) +
  labs(title = "Total de Atendimentos por Mês em 2022",
       x = "Mês",
       y = "Nº Total de Atendimentos") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

#amostrando os valores maximos dos 20 primeiras linhas do nosso projeto de dados 
head(teste2, 20)

19. Criar um gráfico de pizza ou setores para uma variável categórica com porcentagens

# 19. Gráfico de Pizza para os 10 Principais Convênios (sem a linha de Total)

# Prepara os dados
top_10_convenios <- teste2 %>%
  filter(!is.na(Convênio)) %>%  # <<< ESTA É A LINHA QUE REMOVE O N/A
  arrange(desc(Total)) %>%
  head(10) %>%
  select(Convênio, Total)

# Cria o gráfico
ggplot(top_10_convenios, aes(x = "", y = Total, fill = Convênio)) +
  geom_bar(stat = "identity", width = 1, color = "white") + # Adiciona uma borda branca
  coord_polar(theta = "y") + # Transforma em pizza
  geom_text(
    aes(label = paste0(round(Total / sum(Total) * 100), "%")),
    position = position_stack(vjust = 0.5), # Posiciona o texto no meio da fatia
    color = "white", # Cor do texto para melhor contraste
    size = 4
  ) +
  labs(title = "Proporção de Atendimentos Anuais (Top 10 Convênios)") +
  theme_void() + # Remove fundo, eixos e texto desnecessários
  guides(fill = guide_legend(title = "Convênio")) # Mantém uma legenda clara

#———————————————————————– # Análise dos Dados #———————————————————————–

20. Interpretar os gráficos gerados

cat(“— Passo 20: Interpretação dos Gráficos —”,

” ### 20. Análise dos Dados e Interpretação dos Gráficos

A análise exploratória dos dados de atendimentos por convênio em 2022 forneceu os seguintes insights estratégicos:

Conclusão Estratégica: A análise sugere que a estratégia de negócio deve se concentrar em manter e fortalecer o relacionamento com os convênios de maior volume (‘Appai’ e ‘Particular’), ao mesmo tempo que se prepara para as flutuações sazonais de demanda, especialmente para os picos de Março e Agosto. ” “)

This is an R Markdown Notebook. When you execute code within the notebook, the results appear beneath the code.

Try executing this chunk by clicking the Run button within the chunk or by placing your cursor inside it and pressing Ctrl+Shift+Enter.

plot(cars)

Add a new chunk by clicking the Insert Chunk button on the toolbar or by pressing Ctrl+Alt+I.

When you save the notebook, an HTML file containing the code and output will be saved alongside it (click the Preview button or press Ctrl+Shift+K to preview the HTML file).

The preview shows you a rendered HTML copy of the contents of the editor. Consequently, unlike Knit, Preview does not run any R code chunks. Instead, the output of the chunk when it was last run in the editor is displayed.

LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KI1RyYWJhbGhvIGRhIGRpc2NpcGxpbmEgZGUgQ2ljbG8gZGUgVmlkYSBlIEludHJvZHXDp8OjbyDDoCBMaW5ndWFnZW0gUg0KDQojUkVBTElaQURPIFBFTE9zIFBBUlRJQ0lQQU5URVMNCg0KI0ZMQVZJTyBBRE1JTFNPTiBTQU5UT1MgREUgU09VWkEgLS0tIE1BVFJJQ1VMQTogMjAyNTAzNjk5ODM2DQoNCiNKZW5uaWZlciBDb3V0aW5obyBkZSBTb3V6YSAtLS0tLSBNQVRSSUNVTEE6IDIwMjUwMzY5OTg3OQ0KDQojSnVseWFubmUgZGUgU291emEgVGVpeGVpcmEgLS0tLS0gTUFUUklDVUxBOiAyMDI1MDM3MDAwMDENCg0KI01hcmNlbGxhIEZyYW5jaXNjbyBkYSBTaWx2YSBDYXJyaWxpbyAtLS0tLSBNQVRSSUNVTEE6IDIwMjUwMzY5OTk3Ng0KDQojIENPTlRFWFRVQUxJWkHDh8ODTw0KDQojIDEuIEluZGljYcOnw6NvIGRhIGxpc3RhIGRlIGJpYmxpb3RlY2FzIHVzYWRhcyBubyBpbsOtY2lvIGRvIHRyYWJhbGhvDQoNCmBgYHtyfQ0KI2luc3RhbGEgdW0gcGFjb3RlIA0KI2luc3RhbGwucGFja2FnZXMoInRpZHl2ZXJzZSIpICNNYW5pcHVsYW5kbyBvIGRhdGFmcmFtZSBjb20gdGlkeXZlcnNlKCkNCg0KI01hbmlwdWxhbmRvIG8gZGF0YWZyYW1lIGNvbSBkcGx5cigpDQppbnN0YWxsLnBhY2thZ2VzKCJkcGx5ciIpDQppbnN0YWxsLnBhY2thZ2VzKCJwc3ljaCIpDQppbnN0YWxsLnBhY2thZ2VzKCJyZWFkeGwiKQ0KaW5zdGFsbC5wYWNrYWdlcygiZ2dwbG90MiIpDQppbnN0YWxsLnBhY2thZ2VzKCJyZWFkeGwiKSAjSW1wb3J0YcOnw6NvIGRlIGRhZG9zIC54bHMgcGFyYSByZXN1bHRhciBlbSB1bSBkYXRhZnJhbWUNCg0KYGBgDQoNCmBgYHtyfQ0KDQojaW1wb3J0YcOnw6NvIGRhIGJpYmxpb3RlY2EgLS0tIENBUlJFR0FNRU5UTyBET1MgUEFDT1RFUw0KDQojIDEuIEJpYmxpb3RlY2FzIFV0aWxpemFkYXMNCg0KIyBDYXJyZWdhbmRvIGFzIGJpYmxpb3RlY2FzIG5lY2Vzc8Ohcmlhcw0KbGlicmFyeShkcGx5cikgICAgIyBVc2FkYSBwYXJhIG1hbmlwdWxhw6fDo28gZGUgZGFkb3MgZGUgZm9ybWEgZWZpY2llbnRlIGUgbGVnw612ZWwuDQpsaWJyYXJ5KGdncGxvdDIpICAjIEVzc2VuY2lhbCBwYXJhIGEgY3JpYcOnw6NvIGRlIGdyw6FmaWNvcyBkZWNsYXJhdGl2b3MgZSBlbGVnYW50ZXMuDQpsaWJyYXJ5KGNvcnJwbG90KSAjIFV0aWxpemFkYSBwYXJhIHZpc3VhbGl6YXIgbWF0cml6ZXMgZGUgY29ycmVsYcOnw6NvIGRlIGZvcm1hIGNsYXJhLg0KbGlicmFyeShyZWFkeGwpICAgIyBOZWNlc3PDoXJpYSBwYXJhIGEgaW1wb3J0YcOnw6NvIGRlIGRhZG9zIGRvIGFycXVpdm8gLnhsc3guDQpsaWJyYXJ5KHBzeWNoKSAgICAjIFVzYWRhIHBhcmEgYSBhbsOhbGlzZSBkZSBjb3JyZWxhw6fDo28gZGV0YWxoYWRhIChjb3JyLnRlc3QpLg0KYGBgDQoNCmBgYHtyfQ0KI3JlbW92ZXIgb2JqZXRvcyBkYSBtZW3Ds3JpYQ0KI3JtKHNleG8pICNyZW1vdmUgc29tZW50ZSBvIG9iamV0byBYDQpgYGANCg0KIy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQojIEVUTCAoRXh0cmHDp8OjbyAtIFRyYW5zZm9ybWHDp8OjbyAtIENhcmdhKQ0KIy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCiMgMi4gSW5kaWNhw6fDo28gZGEgZm9udGUgZG9zIGRhZG9zDQoNCg0KI0EgZm9udGUgZGUgZGFkb3Mgw6kgbyBhcnF1aXZvICJUYWJlbGEgZGUgYXRlbmRpbWVudG9zIHBvciBjb252ZW5pby54bHN4Ii4gLSBiYXNlIGRlIGF0ZW5kaW1lbnRvcyBvbmRlIHRyYW5zZm9ybWVpIGVtIHVtIGRhdGFmcmFtZSBjaGFtYWRvIHRlc3RlMg0KDQoNCg0KIyA0LiBFc2NyZXZlciBvIGPDs2RpZ28gcGFyYSBhIGltcG9ydGHDp8OjbyBkbyBkYXRhc2V0DQoNCmBgYHtyfQ0KI0ltcG9ydGHDp8OjbyBkZSBkYWRvcyAueGxzeCwgbyByZXN1bHRhZG8gw6kgdW0gZGF0YWZyYW1lDQppbnN0YWxsLnBhY2thZ2VzKCJyZWFkeGwiKQ0KbGlicmFyeShyZWFkeGwpDQp0YWJlbGFfYXRlbmRpbWVudG9zPC0gcmVhZF9leGNlbCgiVGFiZWxhIGRlIGF0ZW5kaW1lbnRvcyBwb3IgY29udmVuaW8ueGxzeCIpDQppcy5kYXRhLmZyYW1lKHRhYmVsYV9hdGVuZGltZW50b3MpDQpgYGANCmBgYHtyfQ0KI0ltcG9ydGHDp8OjbyBkZSBkYWRvcyAueGxzeCwgbyByZXN1bHRhZG8gw6kgdW0gZGF0YWZyYW1lDQppbnN0YWxsLnBhY2thZ2VzKCJyZWFkeGwiKQ0KbGlicmFyeShyZWFkeGwpDQp0YWJlbGFfYXRlbmRpbWVudG9zMjAyMzwtIHJlYWRfZXhjZWwoIlRhYmVsYSBkZSBhdGVuZGltZW50b3MgcG9yIGNvbnZlbmlvIDIwMjMueGxzeCIpDQppcy5kYXRhLmZyYW1lKHRhYmVsYV9hdGVuZGltZW50b3MyMDIzKQ0KYGBgDQoNCiMgMy4gQXByZXNlbnRhciBvIG1ldGFkYWRvIChkaWNpb27DoXJpbyBkZSBkYWRvcykgZG8gZGF0YXNldA0KIyBQYXJhIGVudGVuZGVyIGEgZXN0cnV0dXJhIGRvIGRhdGFzZXQsIHVzYW1vcyBhIGZ1bsOnw6NvIHN0cigpIGFww7NzIGEgaW1wb3J0YcOnw6NvLg0KDQoNCmBgYHtyfQ0KI3ZlcmlmaWNhbmRvIGEgZXN0cnV0dXJhDQpzdHIodGFiZWxhX2F0ZW5kaW1lbnRvcykNCmBgYA0KDQojLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCiMgQW7DoWxpc2UgRXhwbG9yYXTDs3JpYSBkZSBEYWRvcyBiw6FzaWNhDQojLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KYGBge3J9DQojUGFyYSB2aXN1YWxpemFyIG8gY29udGXDumRvIGRvcyBkYWRvcyBpbXBvcnRhZG9zDQpWaWV3KHRhYmVsYV9hdGVuZGltZW50b3MpIA0KYGBgDQoNCg0KIyA0LiBFc2NyZXZlciBvIGPDs2RpZ28gcGFyYSBpbXBvcnRhw6fDo28gZG8gZGF0YXNldA0KIyBDcmlhbW9zIHVtIGJhbmNvIGRlIHRlc3RlIHBhcmEgbWFudXNlYXIgdG9kYSBhIG5vc3NvIHRyYWJhbGhvIHBhcmEgZXZpdGFyIHF1YWxxdWVyIHByb2JsZW1hIGNvbSBvIGJhbmNvIG9yaWdpbmFsDQpgYGB7cn0NCg0KdGVzdGUyIDwtIHRhYmVsYV9hdGVuZGltZW50b3MNCmlzLmRhdGEuZnJhbWUodGVzdGUyKQ0KYGBgDQoNCiMgMy4gQXByZXNlbnRhciBvIG1ldGFkYWRvIChkaWNpb27DoXJpbyBkZSBkYWRvcykgZG8gZGF0YXNldA0KIyBQYXJhIGVudGVuZGVyIGEgZXN0cnV0dXJhIGRvIGRhdGFzZXQsIHVzYW1vcyBhIGZ1bsOnw6NvIHN0cigpIGFww7NzIGEgaW1wb3J0YcOnw6NvLg0KDQpgYGB7cn0NCiN2ZXJpZmljYW5kbyBhIGVzdHJ1dHVyYQ0Kc3RyKHRlc3RlMikNCmBgYA0KDQoNCmBgYHtyfQ0KI01hbmlwdWxhbmRvIG8gZGF0YSBmcmFtZQ0KI3RvZGEgYSA1wrogbGluaGENCnRlc3RlMiBbNSxdDQoNCiMgY29udmVydGVuZG8tbyBwYXJhIHVtIHZldG9yIHByaW1laXJvDQptYWlvcl92YWxvcl81bGluaGEgPC0gbWF4KGFzLm1hdHJpeChkYWRvc19udW1lcmljb3MpLCBuYS5ybSA9IFRSVUUpDQpgYGANCg0KYGBge3J9DQojY29uc3VsdGFuZG8gdW1hIGNvbHVuYSBkbyBkYXRhZnJhbWUNCnRlc3RlMlsiQ29udsOqbmlvIl0NCmBgYA0KDQoNCiMgNS4gRGVzdGFjYXIgb3MgdmFsb3JlcyBtw6F4aW1vcyBkYXMgMjAgcHJpbWVpcmFzIGxpbmhhcw0KDQpgYGB7cn0NCiNhbW9zdHJhbmRvIG9zIHZhbG9yZXMgbWF4aW1vcyBkb3MgMjAgcHJpbWVpcmFzIGxpbmhhcyBkbyBub3NzbyBwcm9qZXRvIGRlIGRhZG9zIA0KaGVhZCh0ZXN0ZTIsIDIwKQ0KYGBgDQoNCg0KYGBge3J9DQoNCiMgNS4gRGVzdGFjYXIgb3MgY29udsOqbmlvcyBjb20gbWFpcyBhdGVuZGltZW50b3MgZW0gSmFuZWlybw0KIyBPIGFycmFuZ2UoZGVzYyguLi4pKSBvcmRlbmEgZG8gbWFpb3IgcGFyYSBvIG1lbm9yDQp0b3BfMjBfY29udmVuaW9zX2phbiA8LSB0ZXN0ZTIgJT4lDQogIGFycmFuZ2UoZGVzYyh0ZXN0ZTIkYEphbi8yMDIyYCkpICU+JQ0KICBoZWFkKDIwKQ0KDQpwcmludCgiVG9wIDIwIGNvbnbDqm5pb3MgZW0gSmFuZWlyby8yMDIyOiIpDQpwcmludCh0b3BfMjBfY29udmVuaW9zX2phbikNCmBgYA0KDQoNCiMgNi4gRGVzdGFjYXIgb3MgdmFsb3JlcyBtaW5pbW9zIGRhcyAyMCB1bHRpbWFzIGxpbmhhcw0KYGBge3J9DQojcmV0b3JuYSBvcyA2IMO6bHRpbW9zDQp0YWlsKHRlc3RlMiwyMCkNCmBgYA0KDQpgYGB7cn0NCiMgNi4gRGVzdGFjYXIgb3MgY29udsOqbmlvcyBjb20gbWVub3MgYXRlbmRpbWVudG9zIGVtIEphbmVpcm8NCmJvdHRvbV8yMF9jb252ZW5pb3NfamFuIDwtIHRlc3RlMiAlPiUNCiAgYXJyYW5nZShgSmFuLzIwMjJgKSAlPiUgIyBPcmRlbSBjcmVzY2VudGUNCiAgaGVhZCgyMCkNCg0KcHJpbnQoIk9zIDIwIENvbnbDqm5pb3MgY29tIG1lbm9zIGF0ZW5kaW1lbnRvcyBlbSBKYW5laXJvLzIwMjI6IikNCnByaW50KGJvdHRvbV8yMF9jb252ZW5pb3NfamFuKQ0KYGBgDQoNCiMgNy4gTGlzdGFyIG9zIG5vbWVzIGRhcyBjb2x1bmFzDQoNCmBgYHtyfQ0KI2xpc3RhciBvYmpldG9zIGRvIGRhdGFmcmFtZQ0KbHModGVzdGUyKQ0KDQpgYGANCmBgYHtyfQ0KI2xpc3RhciBvYmpldG9zIGRvIGRhdGFmcmFtZQ0KbmFtZXModGVzdGUyKQ0KDQpgYGANCiMgOC4gVmVyaWZpY2FyIGEgZGltZW5zw6NvIGRvIGRhdGFzZXQgKHRvdGFsIGRlIGxpbmhhcyBlIGNvbHVuYXMpDQoNCmBgYHtyfQ0KZGltKHRlc3RlMikNCg0KYGBgDQoNCiMgOS4gQ29udGFyIG8gdG90YWwgZGUgYW1vc3RyYXMgcG9yIHVtYSBkYXMgdmFyacOhdmVpcyBjYXRlZ8OzcmljYXMNCg0KI1JlcHJlc2VudGHDp8OjbyBkZSBhbW9zdHJhcyBkZSBhdGVuZGltZW50b3MgcmVhbGl6YWRvcyBlbSBqYW5laXJvIGRlIDIwMjIgY29tIGFtb3N0cmEgZGEgdG90YWxpemHDp8OjbyBkbyBtw6pzDQpgYGB7cn0NCg0KdG90YWxfYXRlbmRpbWVudG9zIDwtIHRlc3RlMiRgSmFuLzIwMjJgDQoNCnRvdGFsX2F0ZW5kaW1lbnRvcyA8LSB0YWJsZSh0b3RhbF9hdGVuZGltZW50b3MpDQoNCnByaW50KHRvdGFsX2F0ZW5kaW1lbnRvcykNCg0KYGBgDQoNCg0KDQojIDEwLiBBcHJlc2VudGFyIGEgZXN0YXTDrXN0aWNhIGLDoXNpY2EgcGFyYSBvIGRhdGFzZXQg4oCTIHN1bW1hcnkoKQ0KDQpgYGB7cn0NCiNyZXN1bW8gZXN0YXTDrXN0aWNvDQpzdW1tYXJ5KHRlc3RlMikNCmBgYA0KDQojIDExLiBSZWFsaXphciBhIGFuw6FsaXNlIGRlIGNvcnJlbGHDp8OjbyB2aWEgbGluaGEgZGUgY29tYW5kbw0KDQpgYGB7cn0NCiMgMTEuIFJlYWxpemFyIGEgYW7DoWxpc2UgZGUgY29ycmVsYcOnw6NvIGVudHJlIG9zIG1lc2VzDQoNCiMgVXNhbmRvIG8gZGF0YWZyYW1lICdkYWRvc19udW1lcmljb3MnIHF1ZSBjcmlhbW9zDQpjb3JfcmVzdWx0YWRvIDwtIGNvcnIudGVzdChkYWRvc19udW1lcmljb3MsIG1ldGhvZCA9ICJwZWFyc29uIikNCg0KcHJpbnQoY29yX3Jlc3VsdGFkbywgc2hvcnQgPSBGQUxTRSkgIyAnc2hvcnQgPSBGQUxTRScgbW9zdHJhIG1haXMgZGV0YWxoZXMNCg0KDQpgYGANCiMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KIyBBbsOhbGlzZSBFeHBsb3JhdMOzcmlhIGRlIERhZG9zIGNvbSBncsOhZmljb3MNCiMgT3MgZ3LDoWZpY29zIHNlcsOjbyBleGliaWRvcyBuYSBhYmEgJ1Bsb3RzJyBkbyBSU3R1ZGlvIG91IGVtIHVtYSBub3ZhIGphbmVsYS4NCiMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQojIDEyLiBDcmlhciB1bSBncsOhZmljbyBoZWF0bWFwIGEgcGFydGlyIGRhcyB2YXJpw6F2ZWlzIHVzYWRhcyBuYSBjb3JyZWxhw6fDo28NCg0KYGBge3J9DQpkYXRhIDwtIGFzLm1hdHJpeChkYWRvc19udW1lcmljb3MpDQpoZWF0bWFwKGRhdGEpDQoNCmBgYA0KDQoNCg0KIyAxMy4gQ3JpYXIgdW0gc2NhdHRlcnBsb3QgcGFyYSBvIHBhciBkZSB2YXJpw6F2ZWlzIGNvbSBtYWlvciBjb3JyZWxhw6fDo28NCg0KIyBGSVogVU1BIEFEQVBUQcOHw4NPIFBPUiBDQVVTQSBEQSBNSU5IQSBCQVNFIERFIERBRE9TIEUgQ09NIElTU08gVVRJTElaRUkgT1MgQVRFTkRJTUVOVE9TIFBPUiBNw4pTIFBBUkEgQ09NUEFSQcOHw4NQTyBERSBQQVIgREUgVkFSScOBVkVJUw0KDQoNCmBgYHtyfQ0KIyAoQ8OzZGlnbyBwYXJhIGVuY29udHJhciB2YXIxIGUgdmFyMiBjb250aW51YSBvIG1lc21vKQ0KIyAuLi4NCg0KIyBHcsOhZmljbyBhdHVhbGl6YWRvIHNlbSBvIGF2aXNvIGRlIGRlcHJlY2lhw6fDo28NCmdncGxvdCh0ZXN0ZTIsIGFlcyh4ID0gLmRhdGFbW3ZhcjFdXSwgeSA9IC5kYXRhW1t2YXIyXV0pKSArDQogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gVG90YWwpLCBzaXplID0gNCwgYWxwaGEgPSAwLjcpICsNCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSwgY29sb3IgPSAicmVkIikgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gcGFzdGUoIlNjYXR0ZXJwbG90IGRlIE1haW9yIENvcnJlbGHDp8OjbzoiLCB2YXIxLCAidnMiLCB2YXIyKSwNCiAgICB4ID0gcGFzdGUoIkF0ZW5kaW1lbnRvcyBlbSIsIHZhcjEpLA0KICAgIHkgPSBwYXN0ZSgiQXRlbmRpbWVudG9zIGVtIiwgdmFyMikNCiAgKSArDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQoNCg0KIyAxNC4gUmVhbGl6YXIgYSBhbsOhbGlzZSBiaXZhcmlhZGEgcG9yIG1laW8gZGUgc2NhdHRlcnBsb3RzDQoNCmBgYHtyfQ0KI0NPTVBBUkFORE8gMiBNRVNFUyBERSBBVEVORElNRU5UT1MgTcOJRElDT1MgUkVBTElaQURPUywgT05ERSBUSVZFTU9TIE8gTEVWRSBBVU1FTlRPIERPIENPTlbDik5JTyBBUFBBSSBRVUUgRU0gSkFORUlSTyBURVZFIE1FTk9TIEFURU5ESU1FTlRPUyBETyBRVUUgTyBOT1JNQUwuIA0KDQphIDwtIGRhZG9zX251bWVyaWNvcyRgSmFuLzIwMjJgOyBiIDwtIGRhZG9zX251bWVyaWNvcyRgRmV2LzIwMjJgDQpwbG90KGEsYikgI3Bsb3RhbmRvIGNvbSBwb250b3MNCnBsb3QoYSwgYiwgdHlwZSA9ICJsIikgI2Fnb3JhIGNvbSBsaW5oYQ0KI0FpbmRhLCDDqSBwb3Nzw612ZWwgcmVhbGl6YXIgbXVkYW7Dp2FzIG5hcyBjYXJhY3RlcsOtc3RpY2FzIGRhcyBsaW5oYXMuIEJhc3RhIHV0aWxpemFyIG9zIGNvbWFuZG9zIOKAnGx3ZD3igJ0gZSDigJxsdHk94oCdIHF1ZSBtb2RpZmljYW0sIHJlc3BlY3RpdmFtZW50ZSwgYSBsYXJndXJhIGUgbyBlc3RpbG8gZGEgbGluaGE6DQpsaW5lcyhhLCAyKmIsIGx3ZCA9IDQpICAjYWx0ZXJhbmRvIGEgZXNwZXNzdXJhIGRhIGxpbmhhDQpsaW5lcyhhLCAwLjUqYiwgbHR5ID0gMikgI2xpbmhhIHRyYWNlamFkYQ0KbGluZXMoYSwgMypiLCBsdHkgPSAzKSAgICNsaW5oYSBwb250aWxoYWRhDQpsaW5lcyhhLCA0KmIsIGx0eSA9IDIsIGx3ZCA9IDQpICNsaW5oYSB0cmFjZWphZGEgZ3Jvc3NhDQoNCmBgYA0KDQoNCg0KDQojIDE1LiBSZWFsaXphciBhIGFuw6FsaXNlIHVuaXZhcmlhZGEgY29tIHVtIGhpc3RvZ3JhbWEgcGFyYSB1bWEgdmFyacOhdmVsIG51bcOpcmljYQ0KDQoNCmBgYHtyfQ0KIyAxNS4gSGlzdG9ncmFtYSBkYSB2YXJpw6F2ZWwgJ1RvdGFsJw0KZ2dwbG90KHRlc3RlMjAsIGFlcyh4ID0gVG90YWwpKSArDQogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gNTAwLCBmaWxsID0gImxpZ2h0Ymx1ZSIsIGNvbG9yID0gImJsYWNrIikgKw0KICBsYWJzKHRpdGxlID0gIkRpc3RyaWJ1acOnw6NvIGRvIFRvdGFsIGRlIEF0ZW5kaW1lbnRvcyBBbnVhaXMgcG9yIENvbnbDqm5pbyIsIHggPSAiVG90YWwgZGUgQXRlbmRpbWVudG9zIiwgeSA9ICJGcmVxdcOqbmNpYSAoTsK6IGRlIENvbnbDqm5pb3MpIikgKw0KICB0aGVtZV9jbGFzc2ljKCkNCg0KYGBgDQoNCg0KDQoNCiMgMTYuIEFwcmVzZW50YXIgZW0gYXBlbmFzIHVtIGdyw6FmaWNvIHbDoXJpb3MgaGlzdG9ncmFtYXMgcGFyYSBhcyB2YXJpw6F2ZWlzIG51bcOpcmljYXMNCg0KYGBge3J9DQojIDE2LiBNw7psdGlwbG9zIEhpc3RvZ3JhbWFzICh1c2FuZG8gbyBvYmpldG8gJ2RhZG9zX2xvbmcnIGNvcnJldG8pDQoNCmdncGxvdChkYWRvc19sb25nLCBhZXMoeCA9IEF0ZW5kaW1lbnRvcywgZmlsbCA9IE1lcykpICsNCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAyMCwgc2hvdy5sZWdlbmQgPSBGQUxTRSwgY29sb3IgPSAiYmxhY2siKSArDQogIGZhY2V0X3dyYXAofiBNZXMsIHNjYWxlcyA9ICJmcmVlIikgKyAjIENyaWEgdW0gbWluaS1ncsOhZmljbyBwYXJhIGNhZGEgbcOqcw0KICBsYWJzKHRpdGxlID0gIkhpc3RvZ3JhbWFzIGRlIEF0ZW5kaW1lbnRvcyBwYXJhIENhZGEgTcOqcyIsDQogICAgICAgeCA9ICJOwrogZGUgQXRlbmRpbWVudG9zIiwNCiAgICAgICB5ID0gIkZyZXF1w6puY2lhIikgKw0KICB0aGVtZV9saWdodCgpDQoNCmBgYA0KDQoNCg0KIyAxNy4gVmVyaWZpY2FyIGNvbSBib3hwbG90cyBhIHByZXNlbsOnYSBkZSBwb3Nzw612ZWlzIG91dGxpZXJzDQoNCg0KYGBge3J9DQojQm94cGxvdA0KeCA9IGModGVzdGUyJGBKYW4vMjAyMmApDQp5ID0gYyh0ZXN0ZTIkYEZldi8yMDIyYCkNCnogPSBjKHRlc3RlMiRgTWFyLzIwMjJgKQ0KDQpib3hwbG90KHgseSx6KSAjcGFyYSBwbG90YXIgbm8gbWVzbW8gZ3LDoWZpY28gKGNvbXBhcmHDp8OjbykNCg0KYGBgDQoNCg0KIyAxOC4gQ3JpYXIgdW0gZ3LDoWZpY28gZGUgYmFycmFzIG91IGNvbHVuYXMNCg0KDQpgYGB7cn0NCiMgLS0tIEPDs2RpZ28gcGFyYSBvIEl0ZW0gMTggKGNvbSBvcmRlbmHDp8OjbykgLS0tDQoNCiMgUHJpbWVpcm8sIHJlc3VtaW1vcyBvcyBkYWRvcw0KYXRlbmRpbWVudG9zX21lbnNhaXMgPC0gZGFkb3NfbnVtZXJpY29zICU+JQ0KICBzZWxlY3QoLVRvdGFsKSAlPiUNCiAgc3VtbWFyaXNlX2FsbChzdW0pICU+JQ0KICBwaXZvdF9sb25nZXIoY29scyA9IGV2ZXJ5dGhpbmcoKSwgbmFtZXNfdG8gPSAiTWVzIiwgdmFsdWVzX3RvID0gIlRvdGFsX0F0ZW5kaW1lbnRvcyIpDQoNCiMgQ3JpYW1vcyB1bSBmYXRvciBwYXJhIG9yZGVuYXIgb3MgbWVzZXMgY29ycmV0YW1lbnRlDQpvcmRlbV9tZXNlcyA8LSBjKCJKYW4vMjAyMiIsICJGZXYvMjAyMiIsICJNYXIvMjAyMiIsICJBYnIvMjAyMiIsICJNYWkvMjAyMiIsICJKdW4vMjAyMiIsIA0KICAgICAgICAgICAgICAgICAiSnVsLzIwMjIiLCAiQWdvLzIwMjIiLCAiU2V0LzIwMjIiLCAiT3V0LzIwMjIiLCAiTm92LzIwMjIiLCAiRGV6LzIwMjIiKQ0KYXRlbmRpbWVudG9zX21lbnNhaXMkTWVzIDwtIGZhY3RvcihhdGVuZGltZW50b3NfbWVuc2FpcyRNZXMsIGxldmVscyA9IG9yZGVtX21lc2VzKQ0KDQojIEFnb3JhLCBvIGdyw6FmaWNvIGRlIGJhcnJhcyBjb20gYSBzaW50YXhlIGNvcnJpZ2lkYSBlIG9yZGVuYWRvDQpnZ3Bsb3QoYXRlbmRpbWVudG9zX21lbnNhaXMsIGFlcyh4ID0gTWVzLCB5ID0gVG90YWxfQXRlbmRpbWVudG9zLCBmaWxsID0gTWVzKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5Iiwgc2hvdy5sZWdlbmQgPSBGQUxTRSkgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gVG90YWxfQXRlbmRpbWVudG9zKSwgdmp1c3QgPSAtMC41KSArDQogIGxhYnModGl0bGUgPSAiVG90YWwgZGUgQXRlbmRpbWVudG9zIHBvciBNw6pzIGVtIDIwMjIiLA0KICAgICAgIHggPSAiTcOqcyIsDQogICAgICAgeSA9ICJOwrogVG90YWwgZGUgQXRlbmRpbWVudG9zIikgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKQ0KDQpgYGANCg0KDQpgYGB7cn0NCiNhbW9zdHJhbmRvIG9zIHZhbG9yZXMgbWF4aW1vcyBkb3MgMjAgcHJpbWVpcmFzIGxpbmhhcyBkbyBub3NzbyBwcm9qZXRvIGRlIGRhZG9zIA0KaGVhZCh0ZXN0ZTIsIDIwKQ0KYGBgDQojIDE5LiBDcmlhciB1bSBncsOhZmljbyBkZSBwaXp6YSBvdSBzZXRvcmVzIHBhcmEgdW1hIHZhcmnDoXZlbCBjYXRlZ8OzcmljYSBjb20gcG9yY2VudGFnZW5zDQoNCg0KYGBge3J9DQojIDE5LiBHcsOhZmljbyBkZSBQaXp6YSBwYXJhIG9zIDEwIFByaW5jaXBhaXMgQ29udsOqbmlvcyAoc2VtIGEgbGluaGEgZGUgVG90YWwpDQoNCiMgUHJlcGFyYSBvcyBkYWRvcw0KdG9wXzEwX2NvbnZlbmlvcyA8LSB0ZXN0ZTIgJT4lDQogIGZpbHRlcighaXMubmEoQ29udsOqbmlvKSkgJT4lICAjIDw8PCBFU1RBIMOJIEEgTElOSEEgUVVFIFJFTU9WRSBPIE4vQQ0KICBhcnJhbmdlKGRlc2MoVG90YWwpKSAlPiUNCiAgaGVhZCgxMCkgJT4lDQogIHNlbGVjdChDb252w6puaW8sIFRvdGFsKQ0KDQojIENyaWEgbyBncsOhZmljbw0KZ2dwbG90KHRvcF8xMF9jb252ZW5pb3MsIGFlcyh4ID0gIiIsIHkgPSBUb3RhbCwgZmlsbCA9IENvbnbDqm5pbykpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHdpZHRoID0gMSwgY29sb3IgPSAid2hpdGUiKSArICMgQWRpY2lvbmEgdW1hIGJvcmRhIGJyYW5jYQ0KICBjb29yZF9wb2xhcih0aGV0YSA9ICJ5IikgKyAjIFRyYW5zZm9ybWEgZW0gcGl6emENCiAgZ2VvbV90ZXh0KA0KICAgIGFlcyhsYWJlbCA9IHBhc3RlMChyb3VuZChUb3RhbCAvIHN1bShUb3RhbCkgKiAxMDApLCAiJSIpKSwNCiAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX3N0YWNrKHZqdXN0ID0gMC41KSwgIyBQb3NpY2lvbmEgbyB0ZXh0byBubyBtZWlvIGRhIGZhdGlhDQogICAgY29sb3IgPSAid2hpdGUiLCAjIENvciBkbyB0ZXh0byBwYXJhIG1lbGhvciBjb250cmFzdGUNCiAgICBzaXplID0gNA0KICApICsNCiAgbGFicyh0aXRsZSA9ICJQcm9wb3LDp8OjbyBkZSBBdGVuZGltZW50b3MgQW51YWlzIChUb3AgMTAgQ29udsOqbmlvcykiKSArDQogIHRoZW1lX3ZvaWQoKSArICMgUmVtb3ZlIGZ1bmRvLCBlaXhvcyBlIHRleHRvIGRlc25lY2Vzc8Ohcmlvcw0KICBndWlkZXMoZmlsbCA9IGd1aWRlX2xlZ2VuZCh0aXRsZSA9ICJDb252w6puaW8iKSkgIyBNYW50w6ltIHVtYSBsZWdlbmRhIGNsYXJhDQpgYGANCg0KDQojLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCiMgQW7DoWxpc2UgZG9zIERhZG9zDQojLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KIyAyMC4gSW50ZXJwcmV0YXIgb3MgZ3LDoWZpY29zIGdlcmFkb3MNCg0KY2F0KCJcbi0tLSBQYXNzbyAyMDogSW50ZXJwcmV0YcOnw6NvIGRvcyBHcsOhZmljb3MgLS0tXG5cbiIsDQoNCg0KICINCiMjIyAyMC4gQW7DoWxpc2UgZG9zIERhZG9zIGUgSW50ZXJwcmV0YcOnw6NvIGRvcyBHcsOhZmljb3MNCg0KQSBhbsOhbGlzZSBleHBsb3JhdMOzcmlhIGRvcyBkYWRvcyBkZSBhdGVuZGltZW50b3MgcG9yIGNvbnbDqm5pbyBlbSAyMDIyIGZvcm5lY2V1IG9zIHNlZ3VpbnRlcyBpbnNpZ2h0cyBlc3RyYXTDqWdpY29zOg0KDQoqICoqQ29uY2VudHJhw6fDo28gZGUgVm9sdW1lIGVtIFBvdWNvcyBDb252w6puaW9zOioqIEV4aXN0ZSB1bWEgbm90w6F2ZWwgY29uY2VudHJhw6fDo28gZGUgYXRlbmRpbWVudG9zLiBPIGdyw6FmaWNvIGRlIHBpenphIChJdGVtIDE5KSBkZW1vbnN0cmEgcXVlICdBcHBhaScgZSAnUGFydGljdWxhcicgc296aW5ob3MgcmVwcmVzZW50YW0gYSBtYWlvciBwYXJ0ZSBkbyB2b2x1bWUgYW51YWwgZW50cmUgb3MgMTAgcHJpbmNpcGFpcyBjb252w6puaW9zLiBJc3NvIGluZGljYSB1bWEgYWx0YSBkZXBlbmTDqm5jaWEgZSBpbXBvcnTDom5jaWEgZXN0cmF0w6lnaWNhIGRlc3NlcyBkb2lzIHBhcmNlaXJvcy4NCg0KKiAqKlNhem9uYWxpZGFkZSBkYSBEZW1hbmRhOioqIE8gZ3LDoWZpY28gZGUgYmFycmFzIChJdGVtIDE4KSByZXZlbGEgdW1hIGNsYXJhIHZhcmlhw6fDo28gc2F6b25hbCBub3MgYXRlbmRpbWVudG9zIGFvIGxvbmdvIGRvIGFuby4gT2JzZXJ2YW0tc2UgcGljb3MgZGUgZGVtYW5kYSBlbSAqKk1hcsOnbyBlIEFnb3N0byoqLCBjb20gdW1hIHF1ZWRhIG5vdMOhdmVsIGVtICoqQWJyaWwqKi4gRXN0ZSBwYWRyw6NvIMOpIGZ1bmRhbWVudGFsIHBhcmEgbyBwbGFuZWphbWVudG8gZGUgcmVjdXJzb3MsIHBlc3NvYWwgZSBlc3RvcXVlLg0KDQoqICoqQ29uc2lzdMOqbmNpYSBlIFByZXZpc2liaWxpZGFkZSBkb3MgQ29udsOqbmlvczoqKiBPIGhlYXRtYXAgZGUgY29ycmVsYcOnw6NvIChJdGVtIDEyKSBtb3N0cmEgY29lZmljaWVudGVzIG11aXRvIHByw7N4aW1vcyBkZSAxLjAwIGVudHJlIHRvZG9zIG9zIG1lc2VzLiBJc3NvIGluZGljYSBxdWUgb3MgY29udsOqbmlvcyBtYW50w6ptIHNldSB2b2x1bWUgcmVsYXRpdm8gZGUgZm9ybWEgY29uc2lzdGVudGU7IHVtIGNvbnbDqm5pbyBjb20gYWx0byB2b2x1bWUgZW0gamFuZWlybyBwcm92YXZlbG1lbnRlIHRlcsOhIGFsdG8gdm9sdW1lIG5vcyBtZXNlcyBzZWd1aW50ZXMuIEVzc2EgYWx0YSBjb3JyZWxhw6fDo28gY29uZmVyZSBwcmV2aXNpYmlsaWRhZGUgYW8gZmF0dXJhbWVudG8gcG9yIGNvbnbDqm5pby4NCg0KKiAqKkRpc3RyaWJ1acOnw6NvIGUgSWRlbnRpZmljYcOnw6NvIGRlIE91dGxpZXJzOioqIE9zIGJveHBsb3RzIChJdGVtIDE3KSBjb25maXJtYW0gdmlzdWFsbWVudGUgYSBjb25jZW50cmHDp8OjbyBkZSB2b2x1bWUuIEEgbWFpb3JpYSBkb3MgY29udsOqbmlvcyBhcHJlc2VudGEgdW0gbsO6bWVybyBiYWl4byBlIHNlbWVsaGFudGUgZGUgYXRlbmRpbWVudG9zIChyZXByZXNlbnRhZG8gcGVsYSAnY2FpeGEnIGRvIGJveHBsb3QpLCBlbnF1YW50byBhbGd1bnMgcG91Y29zLCBjb21vICdBcHBhaScgZSAnUGFydGljdWxhcicsIGFwYXJlY2VtIGNvbW8gb3V0bGllcnMgc2lnbmlmaWNhdGl2b3MgbmEgZXh0cmVtaWRhZGUgc3VwZXJpb3IsIHJlZm9yw6dhbmRvIHN1YSBpbXBvcnTDom5jaWEgZXN0cmF0w6lnaWNhLg0KDQoqKkNvbmNsdXPDo28gRXN0cmF0w6lnaWNhOioqIEEgYW7DoWxpc2Ugc3VnZXJlIHF1ZSBhIGVzdHJhdMOpZ2lhIGRlIG5lZ8OzY2lvIGRldmUgc2UgY29uY2VudHJhciBlbSBtYW50ZXIgZSBmb3J0YWxlY2VyIG8gcmVsYWNpb25hbWVudG8gY29tIG9zIGNvbnbDqm5pb3MgZGUgbWFpb3Igdm9sdW1lICgnQXBwYWknIGUgJ1BhcnRpY3VsYXInKSwgYW8gbWVzbW8gdGVtcG8gcXVlIHNlIHByZXBhcmEgcGFyYSBhcyBmbHV0dWHDp8O1ZXMgc2F6b25haXMgZGUgZGVtYW5kYSwgZXNwZWNpYWxtZW50ZSBwYXJhIG9zIHBpY29zIGRlIE1hcsOnbyBlIEFnb3N0by4NCiINClxuIikNCg0KDQoNCg0KDQoNCg0KDQoNCg0KVGhpcyBpcyBhbiBbUiBNYXJrZG93bl0oaHR0cDovL3JtYXJrZG93bi5yc3R1ZGlvLmNvbSkgTm90ZWJvb2suIFdoZW4geW91IGV4ZWN1dGUgY29kZSB3aXRoaW4gdGhlIG5vdGVib29rLCB0aGUgcmVzdWx0cyBhcHBlYXIgYmVuZWF0aCB0aGUgY29kZS4gDQoNClRyeSBleGVjdXRpbmcgdGhpcyBjaHVuayBieSBjbGlja2luZyB0aGUgKlJ1biogYnV0dG9uIHdpdGhpbiB0aGUgY2h1bmsgb3IgYnkgcGxhY2luZyB5b3VyIGN1cnNvciBpbnNpZGUgaXQgYW5kIHByZXNzaW5nICpDdHJsK1NoaWZ0K0VudGVyKi4gDQoNCmBgYHtyfQ0KcGxvdChjYXJzKQ0KYGBgDQoNCkFkZCBhIG5ldyBjaHVuayBieSBjbGlja2luZyB0aGUgKkluc2VydCBDaHVuayogYnV0dG9uIG9uIHRoZSB0b29sYmFyIG9yIGJ5IHByZXNzaW5nICpDdHJsK0FsdCtJKi4NCg0KV2hlbiB5b3Ugc2F2ZSB0aGUgbm90ZWJvb2ssIGFuIEhUTUwgZmlsZSBjb250YWluaW5nIHRoZSBjb2RlIGFuZCBvdXRwdXQgd2lsbCBiZSBzYXZlZCBhbG9uZ3NpZGUgaXQgKGNsaWNrIHRoZSAqUHJldmlldyogYnV0dG9uIG9yIHByZXNzICpDdHJsK1NoaWZ0K0sqIHRvIHByZXZpZXcgdGhlIEhUTUwgZmlsZSkuDQoNClRoZSBwcmV2aWV3IHNob3dzIHlvdSBhIHJlbmRlcmVkIEhUTUwgY29weSBvZiB0aGUgY29udGVudHMgb2YgdGhlIGVkaXRvci4gQ29uc2VxdWVudGx5LCB1bmxpa2UgKktuaXQqLCAqUHJldmlldyogZG9lcyBub3QgcnVuIGFueSBSIGNvZGUgY2h1bmtzLiBJbnN0ZWFkLCB0aGUgb3V0cHV0IG9mIHRoZSBjaHVuayB3aGVuIGl0IHdhcyBsYXN0IHJ1biBpbiB0aGUgZWRpdG9yIGlzIGRpc3BsYXllZC4NCg==