Neste arquivo nós buscamos explorar o uso de sumários estatísticos e visualização de dados para descrever os dois conjuntos de dados que temos num momento:
Como temos dois conjuntos de dados separamos nossa análise em dois momentos, iremos começar pela análise dos dados experimento-avaliacao-humana.
Análise dos dados “experimento-avaliacao-humana”
Dependências
Antes de falarmos dos dados iremos importar as dependências para executar tanto esta análise quanto a próxima.
library(tidyverse) # carrega os pacotes ggplot2, readr, tidyr e dplyr
library(stringr) # biblioteca para lidar com strings
Importando os dados
Estes dados foram coletados na sala de aula e consistem do nosso entendimento sobre a instatisfação presente em reclamações do site www.reclameaqui.com.br.
Analisamos 15 reclamações, cada reclamação é identificada por um número inteiro único no intervalo [1, 15]. Utilizamos as reclamações de 1 a 5 para calibragem, para assim chegarmos a um “consenso” de que tipo de reclamação é um 2, que tipo de reclamação é um 5, etc.
Cada aluno analisou um número não definido de reclamações e este valor não foi controlado.
# Importando os dados
avaliacoes = read_csv("../data/experimento-avaliacao-humana/experimento-de-avaliacao.csv",
col_types = "ccd")
# Renomeando colunas
avaliacoes = avaliacoes %>%
select(avaliador = `Sua matrícula`,
id_reclamacao = `Id da reclamação`,
insatisfacao = Insatisfação)
# Olhando os dados
glimpse(avaliacoes)
Observations: 178
Variables: 3
$ avaliador <chr> "116110089", "116110089", "116110089", "116110089", "116110089...
$ id_reclamacao <chr> "13", "7", "9", "12", "14", "15", "2", "6", "7", "9", "12", "1...
$ insatisfacao <dbl> 5, 4, 3, 4, 3, 4, 2, 5, 3, 2, 2, 3, 4, 4, 2, 4, 5, 1, 3, 3, 5,...
# Sumário dos dados
summary(avaliacoes)
avaliador id_reclamacao insatisfacao
Length:178 Length:178 Min. :1.000
Class :character Class :character 1st Qu.:2.000
Mode :character Mode :character Median :3.000
Mean :3.121
3rd Qu.:4.000
Max. :5.000
Como podemos ver, o dataframe importado tem 3 colunas:
- avaliador (char): matrícula do aluno que avaliou esta reclamação.
- id_reclamacao (char): número inteiro no intervalo de [1, 5] que identifica cada reclamação unicamente.
- insatisfacao (dbl): número real de 1 a 5 que identifica a insatisfação avaliada por um certo aluno para uma certa reclamação. Onde 1 é o menor valor de insatisfação identificado e 5 o maior valor de insatisfação.
Temos 178 análises de reclamações no total.
Limpeza inicial
Removendo reclamações de 1 a 5
Como dito anteriormente as reclamações de 1 a 5 foram utilizadas para calibragem, e portanto não iremos utilizá-las.
# Removendo avaliações [1, 5] dos dados
avaliacoes = avaliacoes %>%
filter(! (id_reclamacao %in% 1:5 ))
# Olhando os dados
glimpse(avaliacoes)
Observations: 154
Variables: 3
$ avaliador <chr> "116110089", "116110089", "116110089", "116110089", "116110089...
$ id_reclamacao <chr> "13", "7", "9", "12", "14", "15", "6", "7", "9", "12", "14", "...
$ insatisfacao <dbl> 5, 4, 3, 4, 3, 4, 5, 3, 2, 2, 3, 4, 4, 5, 1, 3, 3, 5, 3, 4, 1,...
Agora temos 154 análises de reclamações.
Checando inconsistências
É sempre interessante procurar por valores “nulos” no dataframe.
# Checando se há valores faltando por coluna
sapply(avaliacoes, function(x) sum(is.na(x)))
avaliador id_reclamacao insatisfacao
0 0 0
Não há valores faltando em nenhuma coluna.
Outra inconsistência que pode vir a ocorrer é algum aluno (avaliador) analisar a mesma reclamação mais de uma vez. Vamos checar por isso utilizando a função duplicated.
avaliacoes[duplicated(avaliacoes[,1:2]), ]
Encontramos uma linha, do avaliador 112210437, de fato se procurarmos por este avaliador temos duas “notas” de insatisfação diferentes para a reclamação 10.
avaliacoes[avaliacoes$avaliador == '112210437' & avaliacoes$id_reclamacao == '10', ]
Por enquanto não iremos remover este dado, mas é algo a considerar para os próximos experimentos.
Outro erro manual possível é alguém inserir um dado errado, seja a matrícula, o id da reclamação ou até a nota de instatisfação, mas não conseguimos checar isso de maneira eficáz.
Número de análises por reclamação
Como foi dito anteriormente durante a análise das reclamações não foi definido um número de análises que cada aluno deveria fazer, nem quais reclamações cada aluno deveria analisar podendo portanto haver alguma reclamação que tenha sido analisada mais (ou menos) vezes que outras. Nesta subseção buscamos explorar estas possibilidades.
# Função auxiliar para calcular moda (não encontramos uma função builtin no R)
getmode <- function(v) {
uniqv <- unique(v)
uniqv[which.max(tabulate(match(v, uniqv)))]
}
# Calculando média, mediana e moda do número de análises por reclamação
avaliacoes %>%
group_by(id_reclamacao) %>%
count() %>%
ungroup() %>%
summarise(media = mean(n),
mediana = median(n),
moda = getmode(n))
Em média cada reclamação foi analisada por 15.4 alunos (ou 15.4 vezes) e 13 foi o número de análises mais recorrentes. Vamos plotar um gráfico para facilitar a visualização.
avaliacoes %>% group_by(id_reclamacao) %>%
summarize(count=n()) %>%
ggplot(aes(x=reorder(id_reclamacao, count), y=count)) + geom_bar(stat = "identity")

De fato podemos ver que a moda é 13, as reclamações 11, 6 e 8 foram análisadas 13 vezes. E também podemos ver que a reclamação 10 foi analisada menos vezes (10 vezes) e a reclamação 9 mais vezes (~24 vezes).
Número de análises feita por aluno
Outra valor que deve ser “investigado” é o número de análises feitas por alunos, já que é possível que algum aluno tenha analisado muito mais (ou menos) reclamações que os demais alunos e isso acarreta em um certo viés nos dados.
Além disso saber o número de revisões que cada aluno fez pode ser útil para estimar o esforço e a velocidade de revisão de uma reclamação.
# Calculando média, mediana e moda do número de análises feita por aluno
avaliacoes %>%
group_by(avaliador) %>%
count() %>%
ungroup() %>%
summarise(media = mean(n),
mediana = median(n),
moda = getmode(n))
Ou seja em média cada aluno fez 6.41 análises, ou em outras palavras cada aluno analisou 6.41 reclamações, e a maioria dos alunos analisaram 7 reclamações.
avaliacoes %>% group_by(avaliador) %>%
summarize(count=n()) %>%
ggplot(aes(x=reorder(avaliador, count), y=count)) + geom_bar(stat = "identity") + theme(axis.text.x=element_text(color = "black", angle=90, vjust=.8, hjust=0.8))

Este gráfico nos ajuda a ver que a grande parte dos alunos analisaram 7 reclamações, 1 aluno analisou apenas 2 reclamações e 2 alunos revisaram 10 reclamações. Acreditamos que um número baixo de análises não é um problema tão grave dado que o aluno estava presente durante a calibragem, e que 3 reclamações a mais não é um valor tão acima dos demais, porém para futuros experimentos acreditamos que vale a pena “controlar” este valor para evitar dados enviesados.
Valores de insatisfação
Nesta subseção queremos focar num dos pontos principais da pesquisa que é saber se há consenso em relação ao grau de insatisfação identificado nas reclamações.
Para tal iremos visualizar os dados através de um boxplot que nos oferece uma maneira fácil e intuitiva de visualizar a distribuição destes dados.
avaliacoes %>%
ggplot(aes(x = reorder(id_reclamacao, insatisfacao, fun = median), y = insatisfacao)) +
geom_boxplot() #+ geom_jitter(width = .1, alpha = .7)

A partir deste gráfico parece razoável definir consenso como:
Existe consenso se a diferença entre o terceiro quartil e primeiro quartil é <= 1.
A partir desta “definição” poderíamos dizer que não houve consenso apenas na reclamação 10. É importante notar que seria interessante usar como base uma explicação/base mais “científica” para de fator definir consenso, estamos apenas dando uma sugestão pelo que vemos neste experimento e parece razoável.
Podemos também utilizar esta mesma definição no futuro para verificar se os léxicos erraram ou acertaram em sua “análise” verificando se o valor normalizado da saída dos léxicos está entre o primeiro e terceiro quartil.
Como o boxplot não mostra todos os dados realizamos um segundo plot que pode ser visto abaixo para visualizar de fato todas as análises num mesmo gráfico separadas por reclamação.
avaliacoes %>%
group_by(id_reclamacao) %>%
ggplot(aes(reorder(id_reclamacao, insatisfacao, FUN = median), insatisfacao, colour = id_reclamacao)) +
geom_jitter()

A partir do gráfico acima podemos ver em mais detalhes como as reclamações foram analisadas e que o “consenso” não é tão simples quanto parece no gráfico do boxplot. Importante também notar que a reclamação 10, em que aparentemente não houve consenso, foi a reclamação menos analisada (10 pessoa analisaram).
Análide dos dados “reclamacoes-raw”
Importando os dados
Foram coletadas reclamações de 16 órgãos com pelo menos 20 reclamações no site www.reclameaqui.com.br. Em seguida foram então escolhidas 20 reclamações de cada órgão aleatoriamente.
Estes dados foram coletados a partir de um script que pode ser encontrado aqui.
# Importando os dados
rec_completo = read_csv("../data/reclamacoes-raw/reclamacoes-raw.csv",
col_types = "cccc")
# Olhando os dados
glimpse(rec_completo)
Observations: 320
Variables: 4
$ orgao <chr> "http://http://www.cultura.gov.br", "http://http://www.cultura.go...
$ link <chr> "https://cidadao.reclameaqui.com.br/277684/ministerio-da-cultura/...
$ titulo <chr> "Ministério da cultura libera verba para biografia da cantora Cla...
$ reclamacao <chr> "\r\n Indignada com a liberação da verba de R$365.000,00 p...
# Sumário dos dados
summary(rec_completo)
orgao link titulo reclamacao
Length:320 Length:320 Length:320 Length:320
Class :character Class :character Class :character Class :character
Mode :character Mode :character Mode :character Mode :character
Há 320 linhas (esperado já que 20 x 16 = 320), em que cada linha tem 4 colunas:
- orgao (char): link para site do órgão da reclamação.
- link (char): link para acessar a reclamação.
- titulo (char): título da reclamação.
- reclamação (char): reclamação em formato textual.
Limpeza inicial
Iremos primeiramente checar se há valores faltando nas colunas.
# Checando se há valores faltando por coluna
sapply(rec_completo, function(x) sum(is.na(x)))
orgao link titulo reclamacao
60 0 0 0
Aparentemente o script para obter as reclamações não conseguiu obter (ou não havia essa informação no site) o link para o órgão de todas as reclamações. Além disso é pouco intuitivo trabalhar com o link do órgão, portanto criaremos uma nova coluna contendo apenas o nome do órgão a partir da URL do reclame aqui que tem um campo que representa o órgão.
# Salvando nome legivel do órgão da reclamação na coluna "nome_orgao"
rec_completo <- rec_completo %>%
mutate(nome_orgao = str_split(link, "/") %>% map_chr(~ .[[5]]))
# Remove coluna orgao já que não é mais necessária
rec_completo <- subset(rec_completo, select = -c(orgao))
# Olhando os dados
glimpse(rec_completo)
Observations: 320
Variables: 4
$ link <chr> "https://cidadao.reclameaqui.com.br/277684/ministerio-da-cultura/...
$ titulo <chr> "Ministério da cultura libera verba para biografia da cantora Cla...
$ reclamacao <chr> "\r\n Indignada com a liberação da verba de R$365.000,00 p...
$ nome_orgao <chr> "ministerio-da-cultura", "ministerio-da-cultura", "ministerio-da-...
# Checando se há valores faltando por coluna
sapply(rec_completo, function(x) sum(is.na(x)))
link titulo reclamacao nome_orgao
0 0 0 0
Dessa forma conseguimos remover os valores faltando e temos uma nova coluna chamando nome_orgao que é mais intuitiva.
Criando novas colunas para ajudar na análise
Algumas colunas serão bastante úteis para as análises, estas são:
Uma coluna chamada comprimento_reclamacao para contar número de caractéres por reclamação.
# Calculando comprimento da reclamação e salvando a coluna "comprimento_reclamacao"
rec_completo <- rec_completo %>%
mutate(comprimento_reclamacao = str_length(reclamacao))
Uma coluna chamada numero_de_capslock, que mapeia o número de palavras em capslock das reclamações da coluna reclamacao do mesmo dataframe. O cálculo dessa série de valores incluiu o emprego de uma expressão regular.
rec_completo$numero_de_capslock <- str_count(rec_completo$reclamacao, "\\b[A-Z\u00C0-\u00DC]{2,}\\b")
Uma coluna chamada texto_capslock, a qual mapeia a lista de palavras em capslock das reclamações da coluna reclamacao do mesmo dataframe. O cálculo dessa série de valores incluiu o emprego de uma expressão regular.
rec_completo$texto_capslock <- str_extract_all(rec_completo$reclamacao, "\\b[A-Z\u00C0-\u00DC]{2,}\\b")
# Olhando os dados
glimpse(rec_completo)
Observations: 320
Variables: 7
$ link <chr> "https://cidadao.reclameaqui.com.br/277684/ministerio...
$ titulo <chr> "Ministério da cultura libera verba para biografia da...
$ reclamacao <chr> "\r\n Indignada com a liberação da verba de R$...
$ nome_orgao <chr> "ministerio-da-cultura", "ministerio-da-cultura", "mi...
$ comprimento_reclamacao <int> 1109, 755, 356, 808, 370, 1908, 635, 175, 266, 1291, ...
$ numero_de_capslock <int> 0, 26, 0, 0, 10, 0, 1, 0, 1, 5, 0, 0, 30, 0, 0, 2, 8,...
$ texto_capslock <list> [<>, <"URGENTE", "DA", "PATRIA", "EDUCADORA", "SERÁ"...
Agora iremos partir para a análise de fato.
Comprimento da reclamação
Para iniciar nossa análise iremos observar como é a distribuição do comprimento das reclamações nos dados coletados a partir de um histograma.
ggplot(data=rec_completo, aes(rec_completo$comprimento_reclamacao)) +
geom_histogram(bins = 30, color="darkblue", fill="lightblue") +
labs(x="Comrprimento da Reclamações", y="Count") + scale_x_continuous(breaks=seq(0, 20000, 1000))

Podemos perceber que mais de 50% das reclamações tem menos que 1000 caractéres, e quase todas as reclamações tem menos que 5000 caractéres. Apesar disso existem algumas poucas reclamações com um grande número de reclamações uma delas inclusive tendo quase 20000 caractéres.
Relação entre o órgão e o comprimento da reclamação
Para verificar a relação entre o órgão e o comprimento das reclamações iremos utilizar um boxplot. Decidimos dividir por orgão para sabermos se existe alguma relação aparente entre os órgãos e o tamanho das reclamaçõs. Pelo gráfico, nós acreditamos que não.
rec_completo %>% group_by(nome_orgao) %>%
ggplot(aes(x=reorder(nome_orgao, comprimento_reclamacao), y=comprimento_reclamacao)) + geom_boxplot() + theme(axis.text.x=element_text(color = "black", angle=90, vjust=.8, hjust=0.8)) + scale_y_continuous(breaks=seq(0, 20000, 1000))

Número de palavras em capslock
Um dos grupos mencionou a possibilidade utilizar o número de palavras em capslock para analisar/detectar insatisfação, achamos a ideia interessante e buscamos observar o número de palavras em capslock em cada reclamação, segue abaixo um histograma de tal métrica.
ggplot(data=rec_completo, aes(rec_completo$numero_de_capslock)) +
geom_histogram(bins = 30, color="darkblue", fill="lightblue") +
labs(x="Número de palavras em capslock", y="Count") + scale_y_continuous(breaks=seq(0, 250, 10)) +
scale_x_continuous(breaks=seq(0, 2000, 10))

Aproximadamente 85% das reclamações tem menos de 10 palavras em capslock. É importante notar também que existem muitas siglas nos dados, por exemplo, se buscarmos apenas as palavras em capslock das reclamações com 5 palavras em capslock, temos:
# Buscando apenas as palavras em capslock das reclamações que tem 5 palavras em capslock
rec_completo[rec_completo$numero_de_capslock == 5, ]$texto_capslock
[[1]]
[1] "MEC" "MEC" "SESU" "MEC" "MEC"
[[2]]
[1] "ASSOCIAÇÃO" "DE" "BANCOS" "SIGEPE" "SIAPENET"
[[3]]
[1] "INMETRO" "SELO" "DE" "OURO" "INMETRO"
[[4]]
[1] "RJ" "SAC" "CEG" "SAC" "CEG"
[[5]]
[1] "BOLETO" "DE" "PAGAMENTO" "DO" "ESOCIAL"
[[6]]
[1] "CIVP" "ANVISA" "NÃO" "FUNCIONA" "ÚNICA"
[[7]]
[1] "PS" "SETE" "SETE" "UM" "ANO"
[[8]]
[1] "CPC" "SP" "NADA" "STJ" "NADA"
[[9]]
[1] "PRF" "NADA" "CONSTA" "RENAVAN" "INVÁLIDO"
[[10]]
[1] "GOL" "GOL" "GOL" "RIDÍCULO" "PÉSSIMA"
[[11]]
[1] "DECOLAR" "GOL" "CURITIBA" "SAO" "PAULO"
[[12]]
[1] "RFB" "ICMS" "GEARA" "RFB" "RFB"
[[13]]
[1] "CEDAE" "CÓDIGO" "DO" "ATENDIMENTO" "CEDAE"
Apesar de algumas palavras em capslock aparentemente demostrarem insatisfação outras reclamações, como por exemplo a 1, 4 e 12, apresentam apenas siglas. Portanto acreditamos que se este dado for utilizado seria interessante fazer um filtro para retirar as siglas.
Relação entre o órgão e número de palavras em capslock
Também decidimos avaliar o número de palavras em capslock nas reclamações por órgão utilizando um boxplot para cada órgão.
rec_completo %>% group_by(nome_orgao) %>%
ggplot(aes(x=reorder(nome_orgao, numero_de_capslock), y=numero_de_capslock)) + geom_boxplot() + theme(axis.text.x=element_text(color = "black", angle=90, vjust=.8, hjust=0.8)) + labs(x="Órgãos", y="Número de palavras em capslock")

Pelo gráfico podemos ver que parece haver maior relação entre o órgão e o número de palavras em capslock do que relação entre o órgão e o comprimento da reclamação por exemplo.
Porém não é possível presumir se o número de capslock é devido a insatisfação ou não, nós acreditamos que é possível que seja simplesmente mais comum o uso de siglas em certos órgãos que em outros.
O órgão que apresenta uma distribuição mais “esparsa” e que contém reclamações com um grande número de palavras em capslock é o ministério da saúde.
rec_completo %>%
group_by(nome_orgao) %>%
ggplot(aes(reorder(nome_orgao, numero_de_capslock), numero_de_capslock, colour = nome_orgao)) +
geom_jitter() + theme(axis.title.x=element_blank(),
axis.text.x=element_blank(),
axis.ticks.x=element_blank()) + labs(x="Órgãos", y="Número de palavras em capslock")

LS0tCnRpdGxlOiAiRURBIGRvcyBkYWRvcyBkZSBlc3RpbWF0aXZhIGRlIGluc2F0aXNmYcOnw6NvIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgoqKkdydXBvOioqCgogIC0gSWFyb24gQXJhw7pqbwogIC0gSm9zw6kgQmVuYXJkaQogIC0gTWFyaWFubmUgTGluaGFyZXMKICAtIFJhZmFlbCBLbHluZ2VyCiAgLSBSYXZpIExlaXRlCgpOZXN0ZSBhcnF1aXZvIG7Ds3MgYnVzY2Ftb3MgZXhwbG9yYXIgbyB1c28gZGUgc3Vtw6FyaW9zIGVzdGF0w61zdGljb3MgZSB2aXN1YWxpemHDp8OjbyBkZSBkYWRvcyBwYXJhIGRlc2NyZXZlciBvcyBkb2lzIGNvbmp1bnRvcyBkZSBkYWRvcyBxdWUgdGVtb3MgbnVtIG1vbWVudG86CiAKIC0gZGFkb3MgZG8gZXhwZXJpbWVudG8gZGUgdmFsaWRhw6fDo28gZGEgYXZhbGlhw6fDo28gcG9yIGh1bWFub3M6IFtleHBlcmltZW50by1hdmFsaWFjYW8taHVtYW5hXShodHRwczovL2dpdGh1Yi5jb20vbmF6YXJlbm8vcmVjbGFtYWNvZXMtZG8tZ2YvdHJlZS9tYXN0ZXIvZGF0YS9leHBlcmltZW50by1hdmFsaWFjYW8taHVtYW5hKS4KIC0gZGFkb3MgZGUgMzIwIHJlY2xhbWHDp8O1ZXMgZG8gc2l0ZSB3d3cucmVjbGFtZWFxdWkuY29tLmJyIGRlIDE2IMOzcmfDo29zIGRpc3RpbnRvczogW3JlY2xhbWFjb2VzLXJhd10oaHR0cHM6Ly9naXRodWIuY29tL25hemFyZW5vL3JlY2xhbWFjb2VzLWRvLWdmL3RyZWUvbWFzdGVyL2RhdGEvcmVjbGFtYWNvZXMtcmF3ICkuCiAKQ29tbyB0ZW1vcyBkb2lzIGNvbmp1bnRvcyBkZSBkYWRvcyBzZXBhcmFtb3Mgbm9zc2EgYW7DoWxpc2UgZW0gZG9pcyBtb21lbnRvcywgaXJlbW9zIGNvbWXDp2FyIHBlbGEgYW7DoWxpc2UgZG9zIGRhZG9zIFtleHBlcmltZW50by1hdmFsaWFjYW8taHVtYW5hXShodHRwczovL2dpdGh1Yi5jb20vbmF6YXJlbm8vcmVjbGFtYWNvZXMtZG8tZ2YvdHJlZS9tYXN0ZXIvZGF0YS9leHBlcmltZW50by1hdmFsaWFjYW8taHVtYW5hKS4KCiMjIEFuw6FsaXNlIGRvcyBkYWRvcyAiZXhwZXJpbWVudG8tYXZhbGlhY2FvLWh1bWFuYSIKCiMjIyBEZXBlbmTDqm5jaWFzCgpBbnRlcyBkZSBmYWxhcm1vcyBkb3MgZGFkb3MgaXJlbW9zIGltcG9ydGFyIGFzIGRlcGVuZMOqbmNpYXMgcGFyYSBleGVjdXRhciB0YW50byBlc3RhIGFuw6FsaXNlIHF1YW50byBhIHByw7N4aW1hLgogCmBgYHtyIHdhcm5pbmc9RkFMU0V9CmxpYnJhcnkodGlkeXZlcnNlKSAgIyBjYXJyZWdhIG9zIHBhY290ZXMgZ2dwbG90MiwgcmVhZHIsIHRpZHlyIGUgZHBseXIKbGlicmFyeShzdHJpbmdyKSAgIyBiaWJsaW90ZWNhIHBhcmEgbGlkYXIgY29tIHN0cmluZ3MKYGBgCgojIyMgSW1wb3J0YW5kbyBvcyBkYWRvcwoKRXN0ZXMgZGFkb3MgZm9yYW0gY29sZXRhZG9zIG5hIHNhbGEgZGUgYXVsYSBlIGNvbnNpc3RlbSBkbyBub3NzbyBlbnRlbmRpbWVudG8gc29icmUgYSBpbnN0YXRpc2Zhw6fDo28gcHJlc2VudGUgZW0gcmVjbGFtYcOnw7VlcyBkbyBzaXRlIHd3dy5yZWNsYW1lYXF1aS5jb20uYnIuCgpBbmFsaXNhbW9zIDE1IHJlY2xhbWHDp8O1ZXMsIGNhZGEgcmVjbGFtYcOnw6NvIMOpIGlkZW50aWZpY2FkYSBwb3IgdW0gbsO6bWVybyBpbnRlaXJvIMO6bmljbyBubyBpbnRlcnZhbG8gWzEsIDE1XS4gVXRpbGl6YW1vcyBhcyByZWNsYW1hw6fDtWVzIGRlIDEgYSA1IHBhcmEgY2FsaWJyYWdlbSwgcGFyYSBhc3NpbSBjaGVnYXJtb3MgYSB1bSAiY29uc2Vuc28iIGRlIHF1ZSB0aXBvIGRlIHJlY2xhbWHDp8OjbyDDqSB1bSAyLCBxdWUgdGlwbyBkZSByZWNsYW1hw6fDo28gw6kgdW0gNSwgZXRjLgoKQ2FkYSBhbHVubyBhbmFsaXNvdSB1bSBuw7ptZXJvIG7Do28gZGVmaW5pZG8gZGUgcmVjbGFtYcOnw7VlcyBlIGVzdGUgdmFsb3IgbsOjbyBmb2kgY29udHJvbGFkby4KCmBgYHtyfQojIEltcG9ydGFuZG8gb3MgZGFkb3MKYXZhbGlhY29lcyA9IHJlYWRfY3N2KCIuLi9kYXRhL2V4cGVyaW1lbnRvLWF2YWxpYWNhby1odW1hbmEvZXhwZXJpbWVudG8tZGUtYXZhbGlhY2FvLmNzdiIsIAogICAgICAgICAgICAgICAgICAgICAgY29sX3R5cGVzID0gImNjZCIpCgojIFJlbm9tZWFuZG8gY29sdW5hcwphdmFsaWFjb2VzID0gYXZhbGlhY29lcyAlPiUgCiAgICBzZWxlY3QoYXZhbGlhZG9yID0gYFN1YSBtYXRyw61jdWxhYCwgCiAgICAgICAgICAgaWRfcmVjbGFtYWNhbyA9IGBJZCBkYSByZWNsYW1hw6fDo29gLCAKICAgICAgICAgICBpbnNhdGlzZmFjYW8gPSBJbnNhdGlzZmHDp8OjbykKCiMgT2xoYW5kbyBvcyBkYWRvcwpnbGltcHNlKGF2YWxpYWNvZXMpCgojIFN1bcOhcmlvIGRvcyBkYWRvcwpzdW1tYXJ5KGF2YWxpYWNvZXMpCmBgYAoKQ29tbyBwb2RlbW9zIHZlciwgbyBkYXRhZnJhbWUgaW1wb3J0YWRvIHRlbSAzIGNvbHVuYXM6CgogIC0gYXZhbGlhZG9yIChjaGFyKTogbWF0csOtY3VsYSBkbyBhbHVubyBxdWUgYXZhbGlvdSBlc3RhIHJlY2xhbWHDp8Ojby4KICAtIGlkX3JlY2xhbWFjYW8gKGNoYXIpOiBuw7ptZXJvIGludGVpcm8gbm8gaW50ZXJ2YWxvIGRlIFsxLCA1XSBxdWUgaWRlbnRpZmljYSBjYWRhIHJlY2xhbWHDp8OjbyB1bmljYW1lbnRlLgogIC0gaW5zYXRpc2ZhY2FvIChkYmwpOiBuw7ptZXJvIHJlYWwgZGUgMSBhIDUgcXVlIGlkZW50aWZpY2EgYSBpbnNhdGlzZmHDp8OjbyBhdmFsaWFkYSBwb3IgdW0gY2VydG8gYWx1bm8gcGFyYSB1bWEgY2VydGEgcmVjbGFtYcOnw6NvLiBPbmRlIDEgw6kgbyBtZW5vciB2YWxvciBkZSBpbnNhdGlzZmHDp8OjbyBpZGVudGlmaWNhZG8gZSA1IG8gbWFpb3IgdmFsb3IgZGUgaW5zYXRpc2Zhw6fDo28uCgpUZW1vcyAxNzggYW7DoWxpc2VzIGRlIHJlY2xhbWHDp8O1ZXMgbm8gdG90YWwuCgojIyMgTGltcGV6YSBpbmljaWFsCgojIyMjIFJlbW92ZW5kbyByZWNsYW1hw6fDtWVzIGRlIDEgYSA1CgpDb21vIGRpdG8gYW50ZXJpb3JtZW50ZSBhcyByZWNsYW1hw6fDtWVzIGRlIDEgYSA1IGZvcmFtIHV0aWxpemFkYXMgcGFyYSBjYWxpYnJhZ2VtLCBlIHBvcnRhbnRvIG7Do28gaXJlbW9zIHV0aWxpesOhLWxhcy4KCmBgYHtyfQojIFJlbW92ZW5kbyBhdmFsaWHDp8O1ZXMgWzEsIDVdIGRvcyBkYWRvcwphdmFsaWFjb2VzID0gYXZhbGlhY29lcyAlPiUgCiAgICBmaWx0ZXIoISAoaWRfcmVjbGFtYWNhbyAlaW4lIDE6NSApKQoKIyBPbGhhbmRvIG9zIGRhZG9zCmdsaW1wc2UoYXZhbGlhY29lcykKYGBgCgpBZ29yYSB0ZW1vcyAxNTQgYW7DoWxpc2VzIGRlIHJlY2xhbWHDp8O1ZXMuCgojIyMjIENoZWNhbmRvIGluY29uc2lzdMOqbmNpYXMKCsOJIHNlbXByZSBpbnRlcmVzc2FudGUgcHJvY3VyYXIgcG9yIHZhbG9yZXMgIm51bG9zIiBubyBkYXRhZnJhbWUuCgpgYGB7cn0KIyBDaGVjYW5kbyBzZSBow6EgdmFsb3JlcyBmYWx0YW5kbyBwb3IgY29sdW5hCnNhcHBseShhdmFsaWFjb2VzLCBmdW5jdGlvbih4KSBzdW0oaXMubmEoeCkpKQpgYGAKCk7Do28gaMOhIHZhbG9yZXMgZmFsdGFuZG8gZW0gbmVuaHVtYSBjb2x1bmEuCgpPdXRyYSBpbmNvbnNpc3TDqm5jaWEgcXVlIHBvZGUgdmlyIGEgb2NvcnJlciDDqSBhbGd1bSBhbHVubyAoYXZhbGlhZG9yKSBhbmFsaXNhciBhIG1lc21hIHJlY2xhbWHDp8OjbyBtYWlzIGRlIHVtYSB2ZXouIFZhbW9zIGNoZWNhciBwb3IgaXNzbyB1dGlsaXphbmRvIGEgZnVuw6fDo28gZHVwbGljYXRlZC4KCmBgYHtyfQphdmFsaWFjb2VzW2R1cGxpY2F0ZWQoYXZhbGlhY29lc1ssMToyXSksIF0KYGBgCgpFbmNvbnRyYW1vcyB1bWEgbGluaGEsIGRvIGF2YWxpYWRvciAxMTIyMTA0MzcsIGRlIGZhdG8gc2UgcHJvY3VyYXJtb3MgcG9yIGVzdGUgYXZhbGlhZG9yIHRlbW9zIGR1YXMgIm5vdGFzIiBkZSBpbnNhdGlzZmHDp8OjbyBkaWZlcmVudGVzIHBhcmEgYSByZWNsYW1hw6fDo28gMTAuCgpgYGB7cn0KYXZhbGlhY29lc1thdmFsaWFjb2VzJGF2YWxpYWRvciA9PSAnMTEyMjEwNDM3JyAmIGF2YWxpYWNvZXMkaWRfcmVjbGFtYWNhbyA9PSAnMTAnLCBdCmBgYAoKUG9yIGVucXVhbnRvIG7Do28gaXJlbW9zIHJlbW92ZXIgZXN0ZSBkYWRvLCBtYXMgw6kgYWxnbyBhIGNvbnNpZGVyYXIgcGFyYSBvcyBwcsOzeGltb3MgZXhwZXJpbWVudG9zLgoKT3V0cm8gZXJybyBtYW51YWwgcG9zc8OtdmVsIMOpIGFsZ3XDqW0gaW5zZXJpciB1bSBkYWRvIGVycmFkbywgc2VqYSBhIG1hdHLDrWN1bGEsIG8gaWQgZGEgcmVjbGFtYcOnw6NvIG91IGF0w6kgYSBub3RhIGRlIGluc3RhdGlzZmHDp8OjbywgbWFzIG7Do28gY29uc2VndWltb3MgY2hlY2FyIGlzc28gZGUgbWFuZWlyYSBlZmljw6F6LgoKIyMjIE7Dum1lcm8gZGUgYW7DoWxpc2VzIHBvciByZWNsYW1hw6fDo28gCgpDb21vIGZvaSBkaXRvIGFudGVyaW9ybWVudGUgZHVyYW50ZSBhIGFuw6FsaXNlIGRhcyByZWNsYW1hw6fDtWVzIG7Do28gZm9pIGRlZmluaWRvIHVtIG7Dum1lcm8gZGUgYW7DoWxpc2VzIHF1ZSBjYWRhIGFsdW5vIGRldmVyaWEgZmF6ZXIsIG5lbSBxdWFpcyByZWNsYW1hw6fDtWVzIGNhZGEgYWx1bm8gZGV2ZXJpYSBhbmFsaXNhciBwb2RlbmRvIHBvcnRhbnRvIGhhdmVyIGFsZ3VtYSByZWNsYW1hw6fDo28gcXVlIHRlbmhhIHNpZG8gYW5hbGlzYWRhIG1haXMgKG91IG1lbm9zKSB2ZXplcyBxdWUgb3V0cmFzLiBOZXN0YSBzdWJzZcOnw6NvIGJ1c2NhbW9zIGV4cGxvcmFyIGVzdGFzIHBvc3NpYmlsaWRhZGVzLgoKYGBge3J9CiMgRnVuw6fDo28gYXV4aWxpYXIgcGFyYSBjYWxjdWxhciBtb2RhIChuw6NvIGVuY29udHJhbW9zIHVtYSBmdW7Dp8OjbyBidWlsdGluIG5vIFIpCmdldG1vZGUgPC0gZnVuY3Rpb24odikgewogICB1bmlxdiA8LSB1bmlxdWUodikKICAgdW5pcXZbd2hpY2gubWF4KHRhYnVsYXRlKG1hdGNoKHYsIHVuaXF2KSkpXQp9CgojIENhbGN1bGFuZG8gbcOpZGlhLCBtZWRpYW5hIGUgbW9kYSBkbyBuw7ptZXJvIGRlIGFuw6FsaXNlcyBwb3IgcmVjbGFtYcOnw6NvCmF2YWxpYWNvZXMgJT4lIAogICAgZ3JvdXBfYnkoaWRfcmVjbGFtYWNhbykgJT4lIAogICAgY291bnQoKSAlPiUKICAgIHVuZ3JvdXAoKSAlPiUgCiAgICBzdW1tYXJpc2UobWVkaWEgPSBtZWFuKG4pLCAKICAgICAgICAgICAgICBtZWRpYW5hID0gbWVkaWFuKG4pLAogICAgICAgICAgICAgIG1vZGEgPSBnZXRtb2RlKG4pKQpgYGAKCkVtIG3DqWRpYSBjYWRhIHJlY2xhbWHDp8OjbyBmb2kgYW5hbGlzYWRhIHBvciAxNS40IGFsdW5vcyAob3UgMTUuNCB2ZXplcykgZSAxMyBmb2kgbyBuw7ptZXJvIGRlIGFuw6FsaXNlcyBtYWlzIHJlY29ycmVudGVzLiBWYW1vcyBwbG90YXIgdW0gZ3LDoWZpY28gcGFyYSBmYWNpbGl0YXIgYSB2aXN1YWxpemHDp8Ojby4KCmBgYHtyfQphdmFsaWFjb2VzICU+JSBncm91cF9ieShpZF9yZWNsYW1hY2FvKSAlPiUgCiAgICAgICAgICBzdW1tYXJpemUoY291bnQ9bigpKSAlPiUgCiAgICAgICAgICBnZ3Bsb3QoYWVzKHg9cmVvcmRlcihpZF9yZWNsYW1hY2FvLCBjb3VudCksIHk9Y291bnQpKSArIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKQpgYGAKCkRlIGZhdG8gcG9kZW1vcyB2ZXIgcXVlIGEgbW9kYSDDqSAxMywgYXMgcmVjbGFtYcOnw7VlcyAxMSwgNiBlIDggZm9yYW0gYW7DoWxpc2FkYXMgMTMgdmV6ZXMuIEUgdGFtYsOpbSBwb2RlbW9zIHZlciBxdWUgYSByZWNsYW1hw6fDo28gMTAgZm9pIGFuYWxpc2FkYSBtZW5vcyB2ZXplcyAoMTAgdmV6ZXMpIGUgYSByZWNsYW1hw6fDo28gOSBtYWlzIHZlemVzICh+MjQgdmV6ZXMpLgoKIyMjIE7Dum1lcm8gZGUgYW7DoWxpc2VzIGZlaXRhIHBvciBhbHVubwoKT3V0cmEgdmFsb3IgcXVlIGRldmUgc2VyICJpbnZlc3RpZ2FkbyIgw6kgbyBuw7ptZXJvIGRlIGFuw6FsaXNlcyBmZWl0YXMgcG9yIGFsdW5vcywgasOhIHF1ZSDDqSBwb3Nzw612ZWwgcXVlIGFsZ3VtIGFsdW5vIHRlbmhhIGFuYWxpc2FkbyBtdWl0byBtYWlzIChvdSBtZW5vcykgcmVjbGFtYcOnw7VlcyBxdWUgb3MgZGVtYWlzIGFsdW5vcyBlIGlzc28gYWNhcnJldGEgZW0gdW0gY2VydG8gdmnDqXMgbm9zIGRhZG9zLgoKQWzDqW0gZGlzc28gc2FiZXIgbyBuw7ptZXJvIGRlIHJldmlzw7VlcyBxdWUgY2FkYSBhbHVubyBmZXogcG9kZSBzZXIgw7p0aWwgcGFyYSBlc3RpbWFyIG8gZXNmb3LDp28gZSBhIHZlbG9jaWRhZGUgZGUgcmV2aXPDo28gZGUgdW1hIHJlY2xhbWHDp8Ojby4KCmBgYHtyfQojIENhbGN1bGFuZG8gbcOpZGlhLCBtZWRpYW5hIGUgbW9kYSBkbyBuw7ptZXJvIGRlIGFuw6FsaXNlcyBmZWl0YSBwb3IgYWx1bm8KYXZhbGlhY29lcyAlPiUgCiAgICBncm91cF9ieShhdmFsaWFkb3IpICU+JSAKICAgIGNvdW50KCkgJT4lCiAgICB1bmdyb3VwKCkgJT4lIAogICAgc3VtbWFyaXNlKG1lZGlhID0gbWVhbihuKSwgCiAgICAgICAgICAgICAgbWVkaWFuYSA9IG1lZGlhbihuKSwKICAgICAgICAgICAgICBtb2RhID0gZ2V0bW9kZShuKSkKYGBgCgpPdSBzZWphIGVtIG3DqWRpYSBjYWRhIGFsdW5vIGZleiA2LjQxIGFuw6FsaXNlcywgb3UgZW0gb3V0cmFzIHBhbGF2cmFzIGNhZGEgYWx1bm8gYW5hbGlzb3UgNi40MSByZWNsYW1hw6fDtWVzLCBlIGEgbWFpb3JpYSBkb3MgYWx1bm9zIGFuYWxpc2FyYW0gNyByZWNsYW1hw6fDtWVzLgoKYGBge3J9CmF2YWxpYWNvZXMgJT4lIGdyb3VwX2J5KGF2YWxpYWRvcikgJT4lIAogIHN1bW1hcml6ZShjb3VudD1uKCkpICU+JSAKICBnZ3Bsb3QoYWVzKHg9cmVvcmRlcihhdmFsaWFkb3IsIGNvdW50KSwgeT1jb3VudCkpICsgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KGNvbG9yID0gImJsYWNrIiwgYW5nbGU9OTAsIHZqdXN0PS44LCBoanVzdD0wLjgpKQpgYGAKCkVzdGUgZ3LDoWZpY28gbm9zIGFqdWRhIGEgdmVyIHF1ZSBhIGdyYW5kZSBwYXJ0ZSBkb3MgYWx1bm9zIGFuYWxpc2FyYW0gNyByZWNsYW1hw6fDtWVzLCAxIGFsdW5vIGFuYWxpc291IGFwZW5hcyAyIHJlY2xhbWHDp8O1ZXMgZSAyIGFsdW5vcyByZXZpc2FyYW0gMTAgcmVjbGFtYcOnw7Vlcy4gQWNyZWRpdGFtb3MgcXVlIHVtIG7Dum1lcm8gYmFpeG8gZGUgYW7DoWxpc2VzIG7Do28gw6kgdW0gcHJvYmxlbWEgdMOjbyBncmF2ZSBkYWRvIHF1ZSBvIGFsdW5vIGVzdGF2YSBwcmVzZW50ZSBkdXJhbnRlIGEgY2FsaWJyYWdlbSwgZSBxdWUgMyByZWNsYW1hw6fDtWVzIGEgbWFpcyBuw6NvIMOpIHVtIHZhbG9yIHTDo28gYWNpbWEgZG9zIGRlbWFpcywgcG9yw6ltIHBhcmEgZnV0dXJvcyBleHBlcmltZW50b3MgYWNyZWRpdGFtb3MgcXVlIHZhbGUgYSBwZW5hICJjb250cm9sYXIiIGVzdGUgdmFsb3IgcGFyYSBldml0YXIgZGFkb3MgZW52aWVzYWRvcy4KCiMjIyBWYWxvcmVzIGRlIGluc2F0aXNmYcOnw6NvCgpOZXN0YSBzdWJzZcOnw6NvIHF1ZXJlbW9zIGZvY2FyIG51bSBkb3MgcG9udG9zIHByaW5jaXBhaXMgZGEgcGVzcXVpc2EgcXVlIMOpIHNhYmVyIHNlIGjDoSBjb25zZW5zbwplbSByZWxhw6fDo28gYW8gZ3JhdSBkZSBpbnNhdGlzZmHDp8OjbyBpZGVudGlmaWNhZG8gbmFzIHJlY2xhbWHDp8O1ZXMuCgpQYXJhIHRhbCBpcmVtb3MgdmlzdWFsaXphciBvcyBkYWRvcyBhdHJhdsOpcyBkZSB1bSBib3hwbG90IHF1ZSBub3Mgb2ZlcmVjZSB1bWEgbWFuZWlyYSBmw6FjaWwgZSBpbnR1aXRpdmEgZGUgdmlzdWFsaXphciBhIGRpc3RyaWJ1acOnw6NvIGRlc3RlcyBkYWRvcy4KCmBgYHtyfQphdmFsaWFjb2VzICU+JSAKICAgIGdncGxvdChhZXMoeCA9IHJlb3JkZXIoaWRfcmVjbGFtYWNhbywgaW5zYXRpc2ZhY2FvLCBmdW4gPSBtZWRpYW4pLCB5ID0gaW5zYXRpc2ZhY2FvKSkgKyAKICAgIGdlb21fYm94cGxvdCgpICMrICAgICBnZW9tX2ppdHRlcih3aWR0aCA9IC4xLCBhbHBoYSA9IC43KQpgYGAKCkEgcGFydGlyIGRlc3RlIGdyw6FmaWNvIHBhcmVjZSByYXpvw6F2ZWwgZGVmaW5pciBjb25zZW5zbyBjb21vOgoKKipFeGlzdGUgY29uc2Vuc28gc2UgYSBkaWZlcmVuw6dhIGVudHJlIG8gdGVyY2Vpcm8gcXVhcnRpbCBlIHByaW1laXJvIHF1YXJ0aWwgw6kgPD0gMSoqLgoKQSBwYXJ0aXIgZGVzdGEgImRlZmluacOnw6NvIiBwb2RlcsOtYW1vcyBkaXplciBxdWUgbsOjbyBob3V2ZSBjb25zZW5zbyBhcGVuYXMgbmEgcmVjbGFtYcOnw6NvIDEwLiDDiSBpbXBvcnRhbnRlIG5vdGFyIHF1ZSBzZXJpYSBpbnRlcmVzc2FudGUgdXNhciBjb21vIGJhc2UgdW1hIGV4cGxpY2HDp8Ojby9iYXNlIG1haXMgImNpZW50w61maWNhIiBwYXJhIGRlIGZhdG9yIGRlZmluaXIgY29uc2Vuc28sIGVzdGFtb3MgYXBlbmFzIGRhbmRvIHVtYSBzdWdlc3TDo28gcGVsbyBxdWUgdmVtb3MgbmVzdGUgZXhwZXJpbWVudG8gZSBwYXJlY2UgcmF6b8OhdmVsLiAKClBvZGVtb3MgdGFtYsOpbSB1dGlsaXphciBlc3RhIG1lc21hIGRlZmluacOnw6NvIG5vIGZ1dHVybyBwYXJhIHZlcmlmaWNhciBzZSBvcyBsw6l4aWNvcyBlcnJhcmFtIG91IGFjZXJ0YXJhbSBlbSBzdWEgImFuw6FsaXNlIiB2ZXJpZmljYW5kbyBzZSBvIHZhbG9yIG5vcm1hbGl6YWRvIGRhIHNhw61kYSBkb3MgbMOpeGljb3MgZXN0w6EgZW50cmUgbyBwcmltZWlybyBlIHRlcmNlaXJvIHF1YXJ0aWwuCgpDb21vIG8gYm94cGxvdCBuw6NvIG1vc3RyYSB0b2RvcyBvcyBkYWRvcyByZWFsaXphbW9zIHVtIHNlZ3VuZG8gcGxvdCBxdWUgcG9kZSBzZXIgdmlzdG8gYWJhaXhvIHBhcmEgdmlzdWFsaXphciBkZSBmYXRvIHRvZGFzIGFzIGFuw6FsaXNlcyBudW0gbWVzbW8gZ3LDoWZpY28gc2VwYXJhZGFzIHBvciByZWNsYW1hw6fDo28uCgpgYGB7cn0KYXZhbGlhY29lcyAlPiUgCiAgICBncm91cF9ieShpZF9yZWNsYW1hY2FvKSAlPiUgCiAgICBnZ3Bsb3QoYWVzKHJlb3JkZXIoaWRfcmVjbGFtYWNhbywgaW5zYXRpc2ZhY2FvLCBGVU4gPSBtZWRpYW4pLCBpbnNhdGlzZmFjYW8sIGNvbG91ciA9IGlkX3JlY2xhbWFjYW8pKSArIAogICAgZ2VvbV9qaXR0ZXIoKQpgYGAKCkEgcGFydGlyIGRvIGdyw6FmaWNvIGFjaW1hIHBvZGVtb3MgdmVyIGVtIG1haXMgZGV0YWxoZXMgY29tbyBhcyByZWNsYW1hw6fDtWVzIGZvcmFtIGFuYWxpc2FkYXMgZSBxdWUgbyAiY29uc2Vuc28iIG7Do28gw6kgdMOjbyBzaW1wbGVzIHF1YW50byBwYXJlY2Ugbm8gZ3LDoWZpY28gZG8gYm94cGxvdC4gSW1wb3J0YW50ZSB0YW1iw6ltIG5vdGFyIHF1ZSBhIHJlY2xhbWHDp8OjbyAxMCwgZW0gcXVlIGFwYXJlbnRlbWVudGUgbsOjbyBob3V2ZSBjb25zZW5zbywgZm9pIGEgcmVjbGFtYcOnw6NvIG1lbm9zIGFuYWxpc2FkYSAoMTAgcGVzc29hIGFuYWxpc2FyYW0pLgoKIyMgQW7DoWxpZGUgZG9zIGRhZG9zICJyZWNsYW1hY29lcy1yYXciCgojIyMgSW1wb3J0YW5kbyBvcyBkYWRvcwoKRm9yYW0gY29sZXRhZGFzIHJlY2xhbWHDp8O1ZXMgZGUgMTYgw7NyZ8Ojb3MgY29tIHBlbG8gbWVub3MgMjAgcmVjbGFtYcOnw7VlcyBubyBzaXRlIHd3dy5yZWNsYW1lYXF1aS5jb20uYnIuIEVtIHNlZ3VpZGEgZm9yYW0gZW50w6NvIGVzY29saGlkYXMgMjAgcmVjbGFtYcOnw7VlcyBkZSBjYWRhIMOzcmfDo28gYWxlYXRvcmlhbWVudGUuCgpFc3RlcyBkYWRvcyBmb3JhbSBjb2xldGFkb3MgYSBwYXJ0aXIgZGUgdW0gc2NyaXB0IHF1ZSBwb2RlIHNlciBlbmNvbnRyYWRvIFthcXVpXShodHRwczovL2dpdGh1Yi5jb20vbmF6YXJlbm8vcmVjbGFtYWNvZXMtZG8tZ2YvYmxvYi9tYXN0ZXIvY29kZS9jb2xldGFfcmVjbGFtYWNvZXMuUikuCgpgYGB7cn0KIyBJbXBvcnRhbmRvIG9zIGRhZG9zCnJlY19jb21wbGV0byA9IHJlYWRfY3N2KCIuLi9kYXRhL3JlY2xhbWFjb2VzLXJhdy9yZWNsYW1hY29lcy1yYXcuY3N2IiwgCiAgICAgICAgICAgICAgICAgICAgICBjb2xfdHlwZXMgPSAiY2NjYyIpCgojIE9saGFuZG8gb3MgZGFkb3MKZ2xpbXBzZShyZWNfY29tcGxldG8pCgojIFN1bcOhcmlvIGRvcyBkYWRvcwpzdW1tYXJ5KHJlY19jb21wbGV0bykKYGBgCgpIw6EgMzIwIGxpbmhhcyAoZXNwZXJhZG8gasOhIHF1ZSAyMCB4IDE2ID0gMzIwKSwgZW0gcXVlIGNhZGEgbGluaGEgdGVtIDQgY29sdW5hczoKICAKICAtIG9yZ2FvIChjaGFyKTogbGluayBwYXJhIHNpdGUgZG8gw7NyZ8OjbyBkYSByZWNsYW1hw6fDo28uCiAgLSBsaW5rIChjaGFyKTogbGluayBwYXJhIGFjZXNzYXIgYSByZWNsYW1hw6fDo28uCiAgLSB0aXR1bG8gKGNoYXIpOiB0w610dWxvIGRhIHJlY2xhbWHDp8Ojby4KICAtIHJlY2xhbWHDp8OjbyAoY2hhcik6IHJlY2xhbWHDp8OjbyBlbSBmb3JtYXRvIHRleHR1YWwuCgojIyMgTGltcGV6YSBpbmljaWFsCgpJcmVtb3MgcHJpbWVpcmFtZW50ZSBjaGVjYXIgc2UgaMOhIHZhbG9yZXMgZmFsdGFuZG8gbmFzIGNvbHVuYXMuCgpgYGB7cn0KIyBDaGVjYW5kbyBzZSBow6EgdmFsb3JlcyBmYWx0YW5kbyBwb3IgY29sdW5hCnNhcHBseShyZWNfY29tcGxldG8sIGZ1bmN0aW9uKHgpIHN1bShpcy5uYSh4KSkpCmBgYAoKQXBhcmVudGVtZW50ZSBvIHNjcmlwdCBwYXJhIG9idGVyIGFzIHJlY2xhbWHDp8O1ZXMgbsOjbyBjb25zZWd1aXUgb2J0ZXIgKG91IG7Do28gaGF2aWEgZXNzYSBpbmZvcm1hw6fDo28gbm8gc2l0ZSkgbyBsaW5rIHBhcmEgbyDDs3Jnw6NvIGRlIHRvZGFzIGFzIHJlY2xhbWHDp8O1ZXMuIEFsw6ltIGRpc3NvIMOpIHBvdWNvIGludHVpdGl2byB0cmFiYWxoYXIgY29tIG8gbGluayBkbyDDs3Jnw6NvLCBwb3J0YW50byBjcmlhcmVtb3MgdW1hIG5vdmEgY29sdW5hIGNvbnRlbmRvIGFwZW5hcyBvIG5vbWUgZG8gw7NyZ8OjbyBhIHBhcnRpciBkYSBVUkwgZG8gcmVjbGFtZSBhcXVpIHF1ZSB0ZW0gdW0gY2FtcG8gcXVlIHJlcHJlc2VudGEgbyDDs3Jnw6NvLgoKYGBge3J9CiMgU2FsdmFuZG8gbm9tZSBsZWdpdmVsIGRvIMOzcmfDo28gZGEgcmVjbGFtYcOnw6NvIG5hIGNvbHVuYSAibm9tZV9vcmdhbyIKcmVjX2NvbXBsZXRvIDwtIHJlY19jb21wbGV0byAlPiUgIAogICAgbXV0YXRlKG5vbWVfb3JnYW8gPSBzdHJfc3BsaXQobGluaywgIi8iKSAlPiUgbWFwX2Nocih+IC5bWzVdXSkpCgojIFJlbW92ZSBjb2x1bmEgb3JnYW8gasOhIHF1ZSBuw6NvIMOpIG1haXMgbmVjZXNzw6FyaWEKcmVjX2NvbXBsZXRvIDwtIHN1YnNldChyZWNfY29tcGxldG8sIHNlbGVjdCA9IC1jKG9yZ2FvKSkKCiMgT2xoYW5kbyBvcyBkYWRvcwpnbGltcHNlKHJlY19jb21wbGV0bykKCiMgQ2hlY2FuZG8gc2UgaMOhIHZhbG9yZXMgZmFsdGFuZG8gcG9yIGNvbHVuYQpzYXBwbHkocmVjX2NvbXBsZXRvLCBmdW5jdGlvbih4KSBzdW0oaXMubmEoeCkpKQpgYGAKCkRlc3NhIGZvcm1hIGNvbnNlZ3VpbW9zIHJlbW92ZXIgb3MgdmFsb3JlcyBmYWx0YW5kbyBlIHRlbW9zIHVtYSBub3ZhIGNvbHVuYSBjaGFtYW5kbyBub21lX29yZ2FvIHF1ZSDDqSBtYWlzIGludHVpdGl2YS4KCiMjIyBDcmlhbmRvIG5vdmFzIGNvbHVuYXMgcGFyYSBhanVkYXIgbmEgYW7DoWxpc2UKCkFsZ3VtYXMgY29sdW5hcyBzZXLDo28gYmFzdGFudGUgw7p0ZWlzIHBhcmEgYXMgYW7DoWxpc2VzLCBlc3RhcyBzw6NvOgoKVW1hIGNvbHVuYSBjaGFtYWRhIGNvbXByaW1lbnRvX3JlY2xhbWFjYW8gcGFyYSBjb250YXIgbsO6bWVybyBkZSBjYXJhY3TDqXJlcyBwb3IgcmVjbGFtYcOnw6NvLgpgYGB7cn0KIyBDYWxjdWxhbmRvIGNvbXByaW1lbnRvIGRhIHJlY2xhbWHDp8OjbyBlIHNhbHZhbmRvIGEgY29sdW5hICJjb21wcmltZW50b19yZWNsYW1hY2FvIgpyZWNfY29tcGxldG8gPC0gcmVjX2NvbXBsZXRvICU+JSAgCiAgICBtdXRhdGUoY29tcHJpbWVudG9fcmVjbGFtYWNhbyA9IHN0cl9sZW5ndGgocmVjbGFtYWNhbykpCmBgYAoKVW1hIGNvbHVuYSBjaGFtYWRhIG51bWVyb19kZV9jYXBzbG9jaywgcXVlIG1hcGVpYSBvIG7Dum1lcm8gZGUgcGFsYXZyYXMgZW0gY2Fwc2xvY2sgZGFzIHJlY2xhbWHDp8O1ZXMgZGEgY29sdW5hIHJlY2xhbWFjYW8gZG8gbWVzbW8gZGF0YWZyYW1lLiBPIGPDoWxjdWxvIGRlc3NhIHPDqXJpZSBkZSB2YWxvcmVzIGluY2x1aXUgbyBlbXByZWdvIGRlIHVtYSBleHByZXNzw6NvIHJlZ3VsYXIuCgpgYGB7cn0KcmVjX2NvbXBsZXRvJG51bWVyb19kZV9jYXBzbG9jayA8LSBzdHJfY291bnQocmVjX2NvbXBsZXRvJHJlY2xhbWFjYW8sICJcXGJbQS1aXHUwMEMwLVx1MDBEQ117Mix9XFxiIikKYGBgCgpVbWEgY29sdW5hIGNoYW1hZGEgdGV4dG9fY2Fwc2xvY2ssIGEgcXVhbCBtYXBlaWEgYSBsaXN0YSBkZSBwYWxhdnJhcyBlbSBjYXBzbG9jayBkYXMgcmVjbGFtYcOnw7VlcyBkYSBjb2x1bmEgcmVjbGFtYWNhbyBkbyBtZXNtbyBkYXRhZnJhbWUuIE8gY8OhbGN1bG8gZGVzc2Egc8OpcmllIGRlIHZhbG9yZXMgaW5jbHVpdSBvIGVtcHJlZ28gZGUgdW1hIGV4cHJlc3PDo28gcmVndWxhci4KCmBgYHtyfQpyZWNfY29tcGxldG8kdGV4dG9fY2Fwc2xvY2sgPC0gc3RyX2V4dHJhY3RfYWxsKHJlY19jb21wbGV0byRyZWNsYW1hY2FvLCAiXFxiW0EtWlx1MDBDMC1cdTAwRENdezIsfVxcYiIpCmBgYAoKYGBge3J9CiMgT2xoYW5kbyBvcyBkYWRvcwpnbGltcHNlKHJlY19jb21wbGV0bykKYGBgCgpBZ29yYSBpcmVtb3MgcGFydGlyIHBhcmEgYSBhbsOhbGlzZSBkZSBmYXRvLgoKIyMjIENvbXByaW1lbnRvIGRhIHJlY2xhbWHDp8OjbwoKUGFyYSBpbmljaWFyIG5vc3NhIGFuw6FsaXNlIGlyZW1vcyBvYnNlcnZhciBjb21vIMOpIGEgZGlzdHJpYnVpw6fDo28gZG8gY29tcHJpbWVudG8gZGFzIHJlY2xhbWHDp8O1ZXMgbm9zIGRhZG9zIGNvbGV0YWRvcyBhIHBhcnRpciBkZSB1bSBoaXN0b2dyYW1hLgoKYGBge3IsIGZpZy53aWR0aCA9IDEyLCBmaWcuaGVpZ2h0ID0gMTB9CmdncGxvdChkYXRhPXJlY19jb21wbGV0bywgYWVzKHJlY19jb21wbGV0byRjb21wcmltZW50b19yZWNsYW1hY2FvKSkgKyAKICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gMzAsIGNvbG9yPSJkYXJrYmx1ZSIsIGZpbGw9ImxpZ2h0Ymx1ZSIpICsKICBsYWJzKHg9IkNvbXJwcmltZW50byBkYSBSZWNsYW1hw6fDtWVzIiwgeT0iQ291bnQiKSArIHNjYWxlX3hfY29udGludW91cyhicmVha3M9c2VxKDAsIDIwMDAwLCAxMDAwKSkKYGBgCgpQb2RlbW9zIHBlcmNlYmVyIHF1ZSBtYWlzIGRlIDUwJSBkYXMgcmVjbGFtYcOnw7VlcyB0ZW0gbWVub3MgcXVlIDEwMDAgY2FyYWN0w6lyZXMsIGUgcXVhc2UgdG9kYXMgYXMgcmVjbGFtYcOnw7VlcyB0ZW0gbWVub3MgcXVlIDUwMDAgY2FyYWN0w6lyZXMuIEFwZXNhciBkaXNzbyBleGlzdGVtIGFsZ3VtYXMgcG91Y2FzIHJlY2xhbWHDp8O1ZXMgY29tIHVtIGdyYW5kZSBuw7ptZXJvIGRlIHJlY2xhbWHDp8O1ZXMgdW1hIGRlbGFzIGluY2x1c2l2ZSB0ZW5kbyBxdWFzZSAyMDAwMCBjYXJhY3TDqXJlcy4KCiMjIyBSZWxhw6fDo28gZW50cmUgbyDDs3Jnw6NvIGUgbyBjb21wcmltZW50byBkYSByZWNsYW1hw6fDo28KClBhcmEgdmVyaWZpY2FyIGEgcmVsYcOnw6NvIGVudHJlIG8gw7NyZ8OjbyBlIG8gY29tcHJpbWVudG8gZGFzIHJlY2xhbWHDp8O1ZXMgaXJlbW9zIHV0aWxpemFyIHVtIGJveHBsb3QuIERlY2lkaW1vcyBkaXZpZGlyIHBvciBvcmfDo28gcGFyYSBzYWJlcm1vcyBzZSBleGlzdGUgYWxndW1hIHJlbGHDp8OjbyBhcGFyZW50ZSBlbnRyZSBvcyDDs3Jnw6NvcyBlIG8gdGFtYW5obyBkYXMgcmVjbGFtYcOnw7VzLiBQZWxvIGdyw6FmaWNvLCBuw7NzIGFjcmVkaXRhbW9zIHF1ZSBuw6NvLgoKYGBge3IsIGZpZy53aWR0aCA9IDEyLCBmaWcuaGVpZ2h0ID0gMTB9CnJlY19jb21wbGV0byAlPiUgZ3JvdXBfYnkobm9tZV9vcmdhbykgJT4lIAogIGdncGxvdChhZXMoeD1yZW9yZGVyKG5vbWVfb3JnYW8sIGNvbXByaW1lbnRvX3JlY2xhbWFjYW8pLCB5PWNvbXByaW1lbnRvX3JlY2xhbWFjYW8pKSArIGdlb21fYm94cGxvdCgpICsgIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChjb2xvciA9ICJibGFjayIsIGFuZ2xlPTkwLCB2anVzdD0uOCwgaGp1c3Q9MC44KSkgKyBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzPXNlcSgwLCAyMDAwMCwgMTAwMCkpCmBgYAoKIyMjIE7Dum1lcm8gZGUgcGFsYXZyYXMgZW0gY2Fwc2xvY2sKClVtIGRvcyBncnVwb3MgbWVuY2lvbm91IGEgcG9zc2liaWxpZGFkZSB1dGlsaXphciBvIG7Dum1lcm8gZGUgcGFsYXZyYXMgZW0gY2Fwc2xvY2sgcGFyYSBhbmFsaXNhci9kZXRlY3RhciBpbnNhdGlzZmHDp8OjbywgYWNoYW1vcyBhIGlkZWlhIGludGVyZXNzYW50ZSBlIGJ1c2NhbW9zIG9ic2VydmFyIG8gbsO6bWVybyBkZSBwYWxhdnJhcyBlbSBjYXBzbG9jayBlbSBjYWRhIHJlY2xhbWHDp8Ojbywgc2VndWUgYWJhaXhvIHVtIGhpc3RvZ3JhbWEgZGUgdGFsIG3DqXRyaWNhLgoKYGBge3IsIGZpZy53aWR0aCA9IDEyLCBmaWcuaGVpZ2h0ID0gMTB9CmdncGxvdChkYXRhPXJlY19jb21wbGV0bywgYWVzKHJlY19jb21wbGV0byRudW1lcm9fZGVfY2Fwc2xvY2spKSArIAogIGdlb21faGlzdG9ncmFtKGJpbnMgPSAzMCwgY29sb3I9ImRhcmtibHVlIiwgZmlsbD0ibGlnaHRibHVlIikgKwogIGxhYnMoeD0iTsO6bWVybyBkZSBwYWxhdnJhcyBlbSBjYXBzbG9jayIsIHk9IkNvdW50IikgKyBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzPXNlcSgwLCAyNTAsIDEwKSkgKwogIHNjYWxlX3hfY29udGludW91cyhicmVha3M9c2VxKDAsIDIwMDAsIDEwKSkKYGBgCgpBcHJveGltYWRhbWVudGUgODUlIGRhcyByZWNsYW1hw6fDtWVzIHRlbSBtZW5vcyBkZSAxMCBwYWxhdnJhcyBlbSBjYXBzbG9jay4gw4kgaW1wb3J0YW50ZSBub3RhciB0YW1iw6ltIHF1ZSBleGlzdGVtIG11aXRhcyBzaWdsYXMgbm9zIGRhZG9zLCBwb3IgZXhlbXBsbywgc2UgYnVzY2FybW9zIGFwZW5hcyBhcyBwYWxhdnJhcyBlbSBjYXBzbG9jayBkYXMgcmVjbGFtYcOnw7VlcyBjb20gNSBwYWxhdnJhcyBlbSBjYXBzbG9jaywgdGVtb3M6CgpgYGB7cn0KIyBCdXNjYW5kbyBhcGVuYXMgYXMgcGFsYXZyYXMgZW0gY2Fwc2xvY2sgZGFzIHJlY2xhbWHDp8O1ZXMgcXVlIHRlbSA1IHBhbGF2cmFzIGVtIGNhcHNsb2NrCnJlY19jb21wbGV0b1tyZWNfY29tcGxldG8kbnVtZXJvX2RlX2NhcHNsb2NrID09IDUsIF0kdGV4dG9fY2Fwc2xvY2sKYGBgCgpBcGVzYXIgZGUgYWxndW1hcyBwYWxhdnJhcyBlbSBjYXBzbG9jayBhcGFyZW50ZW1lbnRlIGRlbW9zdHJhcmVtIGluc2F0aXNmYcOnw6NvIG91dHJhcyByZWNsYW1hw6fDtWVzLCBjb21vIHBvciBleGVtcGxvIGEgMSwgNCBlIDEyLCBhcHJlc2VudGFtIGFwZW5hcyBzaWdsYXMuIFBvcnRhbnRvIGFjcmVkaXRhbW9zIHF1ZSBzZSBlc3RlIGRhZG8gZm9yIHV0aWxpemFkbyBzZXJpYSBpbnRlcmVzc2FudGUgZmF6ZXIgdW0gZmlsdHJvIHBhcmEgcmV0aXJhciBhcyBzaWdsYXMuCgojIyMgUmVsYcOnw6NvIGVudHJlIG8gw7NyZ8OjbyBlIG7Dum1lcm8gZGUgcGFsYXZyYXMgZW0gY2Fwc2xvY2sKClRhbWLDqW0gZGVjaWRpbW9zIGF2YWxpYXIgbyBuw7ptZXJvIGRlIHBhbGF2cmFzIGVtIGNhcHNsb2NrIG5hcyByZWNsYW1hw6fDtWVzIHBvciDDs3Jnw6NvIHV0aWxpemFuZG8gdW0gYm94cGxvdCBwYXJhIGNhZGEgw7NyZ8Ojby4KCmBgYHtyLCBmaWcud2lkdGggPSAxMiwgZmlnLmhlaWdodCA9IDEyfQpyZWNfY29tcGxldG8gJT4lIGdyb3VwX2J5KG5vbWVfb3JnYW8pICU+JSAKICBnZ3Bsb3QoYWVzKHg9cmVvcmRlcihub21lX29yZ2FvLCBudW1lcm9fZGVfY2Fwc2xvY2spLCB5PW51bWVyb19kZV9jYXBzbG9jaykpICsgZ2VvbV9ib3hwbG90KCkgKyB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoY29sb3IgPSAiYmxhY2siLCBhbmdsZT05MCwgdmp1c3Q9LjgsIGhqdXN0PTAuOCkpICsgbGFicyh4PSLDk3Jnw6NvcyIsIHk9Ik7Dum1lcm8gZGUgcGFsYXZyYXMgZW0gY2Fwc2xvY2siKQpgYGAKClBlbG8gZ3LDoWZpY28gcG9kZW1vcyB2ZXIgcXVlIHBhcmVjZSBoYXZlciBtYWlvciByZWxhw6fDo28gZW50cmUgbyDDs3Jnw6NvIGUgbyBuw7ptZXJvIGRlIHBhbGF2cmFzIGVtIGNhcHNsb2NrIGRvIHF1ZSByZWxhw6fDo28gZW50cmUgbyDDs3Jnw6NvIGUgbyBjb21wcmltZW50byBkYSByZWNsYW1hw6fDo28gcG9yIGV4ZW1wbG8uCgpQb3LDqW0gbsOjbyDDqSBwb3Nzw612ZWwgcHJlc3VtaXIgc2UgbyBuw7ptZXJvIGRlIGNhcHNsb2NrIMOpIGRldmlkbyBhIGluc2F0aXNmYcOnw6NvIG91IG7Do28sIG7Ds3MgYWNyZWRpdGFtb3MgcXVlIMOpIHBvc3PDrXZlbCBxdWUgc2VqYSBzaW1wbGVzbWVudGUgbWFpcyBjb211bSBvIHVzbyBkZSBzaWdsYXMgZW0gY2VydG9zIMOzcmfDo29zIHF1ZSBlbSBvdXRyb3MuCgpPIMOzcmfDo28gcXVlIGFwcmVzZW50YSB1bWEgZGlzdHJpYnVpw6fDo28gbWFpcyAiZXNwYXJzYSIgZSBxdWUgY29udMOpbSByZWNsYW1hw6fDtWVzIGNvbSB1bSBncmFuZGUgbsO6bWVybyBkZSBwYWxhdnJhcyBlbSBjYXBzbG9jayDDqSBvIG1pbmlzdMOpcmlvIGRhIHNhw7pkZS4KCmBgYHtyLCBmaWcud2lkdGggPSAxMiwgZmlnLmhlaWdodCA9IDEyfQpyZWNfY29tcGxldG8gJT4lIAogICAgZ3JvdXBfYnkobm9tZV9vcmdhbykgJT4lIAogICAgZ2dwbG90KGFlcyhyZW9yZGVyKG5vbWVfb3JnYW8sIG51bWVyb19kZV9jYXBzbG9jayksIG51bWVyb19kZV9jYXBzbG9jaywgY29sb3VyID0gbm9tZV9vcmdhbykpICsKICAgIGdlb21faml0dGVyKCkgKyB0aGVtZShheGlzLnRpdGxlLng9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dC54PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzLng9ZWxlbWVudF9ibGFuaygpKSArIGxhYnMoeD0iw5NyZ8Ojb3MiLCB5PSJOw7ptZXJvIGRlIHBhbGF2cmFzIGVtIGNhcHNsb2NrIikgCmBgYA==