Este documento tem como objetivo contribuir para o entendimento de programação em R sobre os seguintes temas:

Basicamente, é um resumo do curso Intermediate R do DataCamp (2017). Recomendo que você faça o curso para um entendimento mais detalhado dos temas estudados.

OPERADORES RELACIONAIS

Comumente temos que fazer escolhas dada uma condição. Se alguma coisa for verdade, então iremos agir de uma maneira, caso contrário, então podemos tomar outra ação. Você pode fazer isso também em uma análise de dados e por meio do R.

Abaixo, veremos quais são os operadores relacionais usados para testar condições como as citadas acima.

################################
####     IGUALDADE         #####
################################

# Comparação de valores lógicos
TRUE == FALSE

# Comparação de valores numéricos
-6 * 14 != 17 - 101

# Comparação de strings
"useR" == "user"

# Comparação de um valor numérico com outro lógico
TRUE == 1

################################
####  MAIOR OU MENOR QUE   #####
################################

# Comparação de números (resultado de cada lado)
-6 * 5 + 2 >= -10 + 1

# Comparação de strings
"raining" <= "raining dogs"

# Comparação de strings
TRUE > FALSE

################################
####   COMPARAR VETORES    #####
################################

# Vetores com acessos ao LinkedIn and Facebook
linkedin <- c(16, 9, 13, 5, 2, 17, 14)
facebook <- c(17, 7, 5, 16, 8, 13, 14)

# Dias populares
linkedin > 15

# Dias com pouco acesso
linkedin <= 5

# Dias em que o LinkedIn foi mais popular que o Facebook
linkedin > facebook

################################
####   COMPARAR MATRIZES   #####
################################

# Matriz com as visualizações do LinkedIn e Facebook
views <- matrix(c(linkedin, facebook), nrow = 2, byrow = TRUE)

# Quando as visualizações foram iguais a 13?
views == 13

# Quando as visualizações foram menores ou iguais a 14?
views <= 14

# Com que frequência o Facebook tem visualizações iguais ou superiores às do LinkedIn multiplicado por 2?
sum(facebook >= linkedin * 2)

OPERADORES LÓGICOS

Até o momento, nos operadores relacionais estávamos testando apenas uma condição. Agora, com a inserção dos operadores lógicos podemos testar mais de uma condição, o que é útil no dia a dia.

Abaixo, códigos em R que exemplificam como usar os operadores lógicos.

################################
####         & e |         #####
################################

# Quando o LinkedIn excede 10 e Facebook menor que 10?
linkedin > 10 & facebook < 10

# Quando um ou outro foi visitado mais que 12 vezes?
linkedin > 12 | facebook > 12

# Quando as visitas foram maiores que 11 e menores ou iguais a 14?
views > 11 & views <= 14

################################
####         NOT           #####
################################

# Contrário do resultado da condição
!(5 > 3)

CONDIÇÕES

Indepedente do operador utilizado anteriormente (relacional ou lógico) tínhamos como resultado os valores TRUE ou FALSE. Porém, nenhuma ação era tomada a partir dos testes.

Agora, usaremos condições e a partir dos resultados uma ação será executada como mostram os códigos em R abaixo.

################################
####         IFELSE        #####
################################

# Último dia de visualização do LinkedIn e Facebook
li <- 15
fb <- 9

# Ifelse para testar condições
if (li >= 15 & fb >= 15) {          # Testar se em ambos temos 15 ou mais visitas
  sms <- (li + fb) * 2              # Se for verdade, execute a soma das visitas multiplicado por 2 
} else if (li < 10 & fb < 10) {     # Caso contrário, teste se em ambos temos menos que 10 visitas
  sms <- (li + fb) / 2              # Se for verdade, execute a média de visitas
} else {                            # Caso contrário, apenas some as visitas
  sms <- (li + fb)
}

# resultado
print(sms)

LOOPS

Muitas vezes pode ser preciso reescrever o seu código em função da necessidade de se repetir uma atividade. Isso pode ser trabalhoso e consumir bastante tempo. Felizmente, temos em programação a opção de usar loops (no R, as funções for(), while() e repeat()).

Nos códigos abaixo, temos exemplos de como usar os loops no R.

################################
####      WHILE LOOP       #####
################################

# Uma variável de velocidade
speed <- 64

# Enquanto a velocidade for maior que 30 execute
while (speed > 30 ) {
  print('Desacelerando!')
  speed <- speed - 7   # Desacelerar a velocidade        
}
# Mostre o resultado
print(speed)

################################
####       FOR LOOP        #####
################################

#  Versão 1
for (views in linkedin) {       # Para cada valor da matriz views que existe no vetor linkedin
  print(views)                  # Mostre o valor
}

# Versão 2
for (i in 1:length(linkedin)) { # Para cada índice da sequência de 1 a length(linkedin) 
  print(linkedin[i])            # Mostre o valor do vetor do respectivo índice
}

# Versão 3: Usando a função seq_along. Ela cria um vetor 
# de inteiros com índices para acompanhar o objeto. 
for (i in seq_along(linkedin)) { # Para cada índice do vetor linkdedin
  print(linkedin[i])             # Mostre os resultados
}

################################
###   LOOP SOBRE UMA LISTA   ###
################################

# Criando uma lista
nyc <- list(pop = 8405837, bairros = c("Manhattan", "Bronx", "Brooklyn", "Queens", "Staten Island"), 
            capital = FALSE)

# Versão 1
for (value in nyc) {             # Para cada item da lista 
  print(value)                   # Mostre os valores contidos em cada item da lista
}

# Versão 2
for (i in 1:length(nyc)) {       # Para cada índice da sequência de 1 até o tamanho de itens na lista
  print(nyc[[i]])                # Mostre os valores contidos em cada item da lista usando o índice
}

################################
###   LOOP SOBRE UMA MATRIZ  ###
################################

# Criar uma matriz
ttt <- matrix(c("O", NA, "X", NA, "O", NA, "X", "O", "X"), nrow = 3, ncol = 3)

# Executar o loop 
for (i in 1:nrow(ttt)) {        # Para cada linha da matriz (1:nrow(ttt) criará os índices das linhas)
  for (j in 1:ncol(ttt)) {      # Para cada coluna da matriz (1:ncol(ttt) criará os índices das colunas)
  print(paste("Na linha",i,"e coluna",j,"temos",ttt[i,j]))  # Mostre os resultados 
  }
}

################################
####  LOOP COM CONDIÇÕES    ####
################################

# Executar o loop
for (li in linkedin) {            # Para cada índice do vetor linkedin (chamamos o índice de li)
  if (li > 10) {                  # Se o índice for maior que 10
    print("Você é popular")       # Mostre a mensagem "Você é popular"
  } else {                        # Caso contrário, se o índice for <= 10
    print("Seja mais visível!")   # Mostre outra mensagem "Seja mais visível"
  }
}

FUNÇÕES

Durante a programação em R você pode fazer uso de funções “prontas” de pacotes do R, mas em alguns casos você pode optar por criar sua própria função. Desta forma, você evita repetir códigos para executar a mesma tarefa.

Nos códigos abaixo, temos códigos em R que mostram como acessar a documentação de uma função nativa do R e como criar sua própria função.

################################
####   FUNÇÕES NATIVAS     #####
################################

# Para acessar a documentação de uma função nativa.
help(mean)
help(sd)

# Existem argumentos obrigatórios e opcionais em funções. Exemplo:
sd(x, na.rm = FALSE)

################################
###   FUNÇÕES PRÓPRIAS       ###
################################

# Criando a função quadrado que recebe o argumento x
quadrado <- function(x) {
 result <- x^2
 return(result)
}

# Usando a função quadrado
quadrado(12)

# Criando a função somar_abs() que recebe os argumentos x e y
somar_abs <- function(x, y) {
  result <- abs(x) + abs(y)
  return(result)
}

# Usando a função somar_abs
somar_abs(-2, 3)


# Expandir a função quadrado() para receber os argumentos x e print_info
quadrado <- function(x, print_info = T) {         # argumentos da função
  y <- x ^ 2                                      # tarefa a ser executada
  if (print_info == T) {                          # verificar o argumento print_info
    print(paste(x, 'elevado ao quadrado é',y))    # se TRUE, mostrar a mensagem
  }
  return(y)                                       # a função deve retornar como saído os valores de y
}

quadrado(5)
quadrado(5, print_info=F)
A FAMÍLIA DE FUNÇÕES APPLY

Escrever loops da forma tradicional pode ser uma verdadeira tortura, tanto para o usuário quanto para o computador em função de performance.

Em função disso, surgiram as funções apply() que são muito úteis na manipulação de dados e simplificam e aceleram o processo. Tudo que você conseguiria fazer com um for() pode ser realizado com funções da família apply().

  • apply():

Aplica uma função nas margens de um array qualquer. Geralmente é aplicado em uma matriz/dataframe de forma a executar uma mesma função em todas as linhas ou colunas daquele objeto. Recebe como argumento um array, a marginal sobre a qual a função será aplicada (linha ou coluna) e a função.

  • lapply():

É uma função que é aplicada em cada elemento de um vetor ou cada nó de uma lista. O output é uma lista obrigatoriamente. Recebe como argumentos um vetor/lista e uma função.

  • sapply():

Similar ao lapply, porém a saída geralmente é simplificada, sendo apenas um vetor. Caso sua saída seja mais de um elemento, a saída deixa de ser um vetor e passa a ser uma matriz. Recebe como argumentos um vetor/lista e uma função. A diferença para o lapply é que o sapply tenta simplificar o resultado, retornando assim um vetor ou algo parecido.

  • tapply():

Função com o objetivo de aplicar funções em grupos diferentes. Suponha que você tenha um dataframe com 2 colunas, uma com altura e outra com gênero, e você queira calcula a média de idade para cada um dos gẽneros, então neste caso a função tapply se aplica perfeitamente. Recebe como argumentos um vetor, um vetor com os fatores que irão estratificar o resultado e a função a ser aplicada em cada estrato.

Abaixo, códigos em R que mostram como fazer uso de cada uma das funções da família de funções apply.

################################
######       APPLY         #####
################################

# matriz com 20 colunas e 10 linhas
x <- matrix(rnorm(200), ncol=20)

# média na linha (MARGIN = 1)
media_linha <- apply(x, MARGIN = 1, mean)   # aplicar a função mean nas linhas

# média na coluna (MARGIN = 2)
media_coluna <- apply(x, MARGIN = 2, mean)  # aplicar a função mean nas colunas

################################
######       LAPPLY        #####
################################

# Uma lista qualquer com 7 vetores de temperaturas em cada dia
temp <- list(
  c(3, 7,  9,  6, -1),
  c(6,  9, 12, 13,  5),
  c(4,  8,  3, -1, -3),
  c(1,  4,  7,  2, -2),
  c(5, 7, 9, 4, 2),
  c(-3,  5,  8,  9,  4),
  c(3, 6, 9, 4, 1)
  )

# Temperatura mínima em cada dia. Retorna uma lista.
lapply(temp, min)

# Temperatura máxima em cada dia. Retorna uma lista. 
lapply(temp, max)

# Temperatura média em cada dia. Retorna uma lista.
lapply(temp, mean)

################################
######       SAPPLY        #####
################################

# Temperatura mínima em cada dia. Retorna um vetor.
sapply(temp, min)

# Temperatura máxima em cada dia. Retorna um vetor.
sapply(temp, max)

# Temperatura média em cada dia. Retorna um vetor.
sapply(temp, mean)

# Teste que retorna apenas em formato diferente, mas com resultados iguais
unlist(lapply(temp, max)) == sapply(temp, max)

# Função que calcula a média do mínimo e máximo de um vetor
extremes_avg <- function(x) {
 avg <- mean(c(min(x), max(x)))
 return(avg)
}

# Usando ela com o sapply(). Poderíamos usar ela em lapply() ou apply().
sapply(temp, extremes_avg)
TRABALHANDO COM DATAS

A data ou tempo é um dado que necessita de uma manipulação específica. Como trabalharemos com séries temporais, é de suma importância o bom entendimento de como lidar com dados temporais que, necessáriamente, serão armazenados cronológicamente.

No R temos várias formas de trabalhar com datas. Abaixo, alguns exemplos que podem nos ajudar.

################################
#####    DATA/TEMPO        #####
################################

# A data atual. A função primitiva Sys.Date() cria uma data no formato correto
today <- Sys.Date()

# Se excluirmos a classe vemos que teremos um número que não é interpretável 
unclass(today)

# A hora corrente
now <- Sys.time()

################################
####  CRIANDO DATA/TEMPO   #####
################################

# Definindo datas em um formato qualquer como character
str1 <- "2012-3-15"
str2 <- "02/27/92"

# Convertendo para datas no formato que o R reconhece
date1 <- as.Date(str1, format = "%Y-%m-%d")
date2 <- as.Date(str2, format = "%m/%d/%y")

# Definindo tempo em formato de string
str1 <- "2012-3-12 14:23:08"

# Converter as string para um objecto POSIXct
time1 <- as.POSIXct(str1, format = "%Y-%m-%d %T")

################################
####  CÁLCULO DATA/TEMPO   #####
################################

# Datas
day1 <- as.Date("2017-03-12")
day2 <- as.Date("2017-03-14")
day3 <- as.Date("2017-03-19")
day4 <- as.Date("2017-03-25")
day5 <- as.Date("2017-03-30")

# Diferença entre o primeiro e o último dia
day5-day1

# Criar um vetor com as datas
pizza <- c(day1, day2, day3, day4, day5)
pizza

# Criar um vetor com a diferença entre os dias consecutivos
day_diff <- diff(pizza)
day_diff

# Período médio entre dois dias consecutivos 
mean(day_diff)
PACOTES

Como comentado anteriormente, você pode fazer uso de funcionalidades de pacotes do R. Neste caso, você precisa adicionar esse pacote no conjunto de bibliotecas disponíveis no R para que seja possível usar suas funções.

Isto é necessário porque quando iniciamos o RStudio apenas alguns pacotes básicos são carregados automaticamente. Para que os outros também sejam carregados, é preciso acioná-los.

Abaixo, veremos como fazer a instalação de pacotes bem como seu carregamento no RStudio.

################################
#####      INSTALAR        #####
################################

# Além dessa opção você pode instalar pacotes diretamente no painel inferior direito do RStudio
install.packages("dplyr")
install.packages(c("dplyr", "data.table"))

################################
#####       CARREGAR       #####
################################

# Forma tradicional. Aqui, não precisamos das aspas porque o R já reconhece que há o pacote no ambiente
require(dplyr)
require(data.table)

# Alternativa para no momento de carregamento do pacote não aparecerem mensagens
suppressMessages(require(dplyr))
suppressMessages(require(data.table))

# Acionando todas as funções disponíveis no pacote
help(dplyr)
help(data.table)

REFERÊNCIAS

DataCamp, Inc. 2017. “Intermediate R.” https://www.datacamp.com/courses/intermediate-r.

Wickham, Hadley. 2014. Advanced R. CRC Press.

2018. “Curso-R.” http://material.curso-r.com/.

LS0tCnRpdGxlOiA8Y2VudGVyPiA8aDI+IDxiPlByb2dyYW1hw6fDo28gZW0gUiAtIEludGVybWVkacOhcmlvIDwvYj4gPC9oMj4gPC9jZW50ZXI+IAphdXRob3I6IDxjZW50ZXI+IEZyYW5rIE1hZ2FsaMOjZXMgZGUgUGluaG8gLSBJQk1FQy9NRyA8L2NlbnRlcj4KZ3JhcGhpY3M6IHllcwpsaW5rY29sb3I6IGJsdWUKb3V0cHV0OiAKICBodG1sX25vdGVib29rOgogICAgdGhlbWU6IGNlcnVsZWFuCiAgICBmaWdfY2FwdGlvbjogeWVzCnJlZmVyZW5jZXM6Ci0gaWQ6IHdpY2toYW0yMDE0YWR2YW5jZWQKICB0aXRsZTogQWR2YW5jZWQgUgogIGF1dGhvcjoKICAtIGZhbWlseTogV2lja2hhbQogICAgZ2l2ZW46IEhhZGxleQogIHB1Ymxpc2hlcjogQ1JDIFByZXNzCiAgdHlwZTogYm9vawogIGlzc3VlZDoKICAgIHllYXI6IDIwMTQKLSBpZDogZGF0YWNhbXAKICB0aXRsZTogSW50ZXJtZWRpYXRlIFIKICBhdXRob3I6IAogIC0gZmFtaWx5OiBEYXRhQ2FtcAogICAgZ2l2ZW46IEluYwogIFVSTDogaHR0cHM6Ly93d3cuZGF0YWNhbXAuY29tL2NvdXJzZXMvaW50ZXJtZWRpYXRlLXIKICBpc3N1ZWQ6CiAgICB5ZWFyOiAyMDE3Ci0gaWQ6IGN1cnNvUgogIHRpdGxlOiBDdXJzby1SCiAgYXV0aG9yOgogIC0gZmFtaWx5OgogICAgZ2l2ZW46CiAgVVJMOiBodHRwOi8vbWF0ZXJpYWwuY3Vyc28tci5jb20vCiAgaXNzdWVkOgogICAgeWVhcjogMjAxOApub2NpdGU6IHwgCiAgQHdpY2toYW0yMDE0YWR2YW5jZWQsIEBkYXRhY2FtcCwgQGN1cnNvUgotLS0KCkVzdGUgZG9jdW1lbnRvIHRlbSBjb21vIG9iamV0aXZvIGNvbnRyaWJ1aXIgcGFyYSBvIGVudGVuZGltZW50byBkZSBwcm9ncmFtYcOnw6NvIGVtIFtSXShodHRwczovL3d3dy5yLXByb2plY3Qub3JnLykgc29icmUgb3Mgc2VndWludGVzIHRlbWFzOgoKKiBPcGVyYWRvcmVzIHJlbGFjaW9uYWlzIGA9PWAgYDxgIGA+YCAgZSBsw7NnaWNvcyBgYW5kYCBgb3JgIGBub3RgOwoqIENvbmRpw6fDtWVzIGBpZmAgYGVsc2VgOwoqIExvb3BzOwoqIEZ1bsOnw7VlczsKKiBBIGZhbcOtbGlhIGRlIGZ1bsOnw7VlcyBhcHBseTsKKiBEYXRhczsKKiBQYWNvdGVzCgpCYXNpY2FtZW50ZSwgw6kgdW0gcmVzdW1vIGRvIGN1cnNvIFtJbnRlcm1lZGlhdGUgUl0oaHR0cHM6Ly93d3cuZGF0YWNhbXAuY29tL2NvdXJzZXMvaW50ZXJtZWRpYXRlLXIpIGRvIEBkYXRhY2FtcC4gUmVjb21lbmRvIHF1ZSB2b2PDqiBmYcOnYSBvIGN1cnNvIHBhcmEgdW0gZW50ZW5kaW1lbnRvIG1haXMgZGV0YWxoYWRvIGRvcyB0ZW1hcyBlc3R1ZGFkb3MuCgojIyMjICoqT1BFUkFET1JFUyBSRUxBQ0lPTkFJUyoqCgpDb211bWVudGUgdGVtb3MgcXVlIGZhemVyIGVzY29saGFzIGRhZGEgdW1hIGNvbmRpw6fDo28uIFNlIGFsZ3VtYSBjb2lzYSBmb3IgdmVyZGFkZSwgZW50w6NvIGlyZW1vcyBhZ2lyIGRlIHVtYSBtYW5laXJhLCBjYXNvIGNvbnRyw6FyaW8sIGVudMOjbyBwb2RlbW9zIHRvbWFyIG91dHJhIGHDp8Ojby4gVm9jw6ogcG9kZSBmYXplciBpc3NvIHRhbWLDqW0gZW0gdW1hIGFuw6FsaXNlIGRlIGRhZG9zIGUgcG9yIG1laW8gZG8gUi4gCgpBYmFpeG8sIHZlcmVtb3MgcXVhaXMgc8OjbyBvcyBvcGVyYWRvcmVzIHJlbGFjaW9uYWlzIHVzYWRvcyBwYXJhIHRlc3RhciBjb25kacOnw7VlcyBjb21vIGFzIGNpdGFkYXMgYWNpbWEuIAoKYGBge3IsIHdhcm5pbmc9RkFMU0V9CiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMjIyMgICAgIElHVUFMREFERSAgICAgICAgICMjIyMjCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgojIENvbXBhcmHDp8OjbyBkZSB2YWxvcmVzIGzDs2dpY29zClRSVUUgPT0gRkFMU0UKCiMgQ29tcGFyYcOnw6NvIGRlIHZhbG9yZXMgbnVtw6lyaWNvcwotNiAqIDE0ICE9IDE3IC0gMTAxCgojIENvbXBhcmHDp8OjbyBkZSBzdHJpbmdzCiJ1c2VSIiA9PSAidXNlciIKCiMgQ29tcGFyYcOnw6NvIGRlIHVtIHZhbG9yIG51bcOpcmljbyBjb20gb3V0cm8gbMOzZ2ljbwpUUlVFID09IDEKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMjIyMgIE1BSU9SIE9VIE1FTk9SIFFVRSAgICMjIyMjCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgojIENvbXBhcmHDp8OjbyBkZSBuw7ptZXJvcyAocmVzdWx0YWRvIGRlIGNhZGEgbGFkbykKLTYgKiA1ICsgMiA+PSAtMTAgKyAxCgojIENvbXBhcmHDp8OjbyBkZSBzdHJpbmdzCiJyYWluaW5nIiA8PSAicmFpbmluZyBkb2dzIgoKIyBDb21wYXJhw6fDo28gZGUgc3RyaW5ncwpUUlVFID4gRkFMU0UKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMjIyMgICBDT01QQVJBUiBWRVRPUkVTICAgICMjIyMjCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgojIFZldG9yZXMgY29tIGFjZXNzb3MgYW8gTGlua2VkSW4gYW5kIEZhY2Vib29rCmxpbmtlZGluIDwtIGMoMTYsIDksIDEzLCA1LCAyLCAxNywgMTQpCmZhY2Vib29rIDwtIGMoMTcsIDcsIDUsIDE2LCA4LCAxMywgMTQpCgojIERpYXMgcG9wdWxhcmVzCmxpbmtlZGluID4gMTUKCiMgRGlhcyBjb20gcG91Y28gYWNlc3NvCmxpbmtlZGluIDw9IDUKCiMgRGlhcyBlbSBxdWUgbyBMaW5rZWRJbiBmb2kgbWFpcyBwb3B1bGFyIHF1ZSBvIEZhY2Vib29rCmxpbmtlZGluID4gZmFjZWJvb2sKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMjIyMgICBDT01QQVJBUiBNQVRSSVpFUyAgICMjIyMjCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgojIE1hdHJpeiBjb20gYXMgdmlzdWFsaXphw6fDtWVzIGRvIExpbmtlZEluIGUgRmFjZWJvb2sKdmlld3MgPC0gbWF0cml4KGMobGlua2VkaW4sIGZhY2Vib29rKSwgbnJvdyA9IDIsIGJ5cm93ID0gVFJVRSkKCiMgUXVhbmRvIGFzIHZpc3VhbGl6YcOnw7VlcyBmb3JhbSBpZ3VhaXMgYSAxMz8Kdmlld3MgPT0gMTMKCiMgUXVhbmRvIGFzIHZpc3VhbGl6YcOnw7VlcyBmb3JhbSBtZW5vcmVzIG91IGlndWFpcyBhIDE0Pwp2aWV3cyA8PSAxNAoKIyBDb20gcXVlIGZyZXF1w6puY2lhIG8gRmFjZWJvb2sgdGVtIHZpc3VhbGl6YcOnw7VlcyBpZ3VhaXMgb3Ugc3VwZXJpb3JlcyDDoHMgZG8gTGlua2VkSW4gbXVsdGlwbGljYWRvIHBvciAyPwpzdW0oZmFjZWJvb2sgPj0gbGlua2VkaW4gKiAyKQpgYGAKCiMjIyMgKipPUEVSQURPUkVTIEzDk0dJQ09TKioKCkF0w6kgbyBtb21lbnRvLCBub3Mgb3BlcmFkb3JlcyByZWxhY2lvbmFpcyBlc3TDoXZhbW9zIHRlc3RhbmRvIGFwZW5hcyB1bWEgY29uZGnDp8Ojby4gQWdvcmEsIGNvbSBhIGluc2Vyw6fDo28gZG9zIG9wZXJhZG9yZXMgbMOzZ2ljb3MgcG9kZW1vcyB0ZXN0YXIgbWFpcyBkZSB1bWEgY29uZGnDp8OjbywgbyBxdWUgw6kgw7p0aWwgbm8gZGlhIGEgZGlhLiAKCkFiYWl4bywgY8OzZGlnb3MgZW0gUiBxdWUgZXhlbXBsaWZpY2FtIGNvbW8gdXNhciBvcyBvcGVyYWRvcmVzIGzDs2dpY29zLgoKYGBge3J9CiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMjIyMgICAgICAgICAmIGUgfCAgICAgICAgICMjIyMjCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgojIFF1YW5kbyBvIExpbmtlZEluIGV4Y2VkZSAxMCBlIEZhY2Vib29rIG1lbm9yIHF1ZSAxMD8KbGlua2VkaW4gPiAxMCAmIGZhY2Vib29rIDwgMTAKCiMgUXVhbmRvIHVtIG91IG91dHJvIGZvaSB2aXNpdGFkbyBtYWlzIHF1ZSAxMiB2ZXplcz8KbGlua2VkaW4gPiAxMiB8IGZhY2Vib29rID4gMTIKCiMgUXVhbmRvIGFzIHZpc2l0YXMgZm9yYW0gbWFpb3JlcyBxdWUgMTEgZSBtZW5vcmVzIG91IGlndWFpcyBhIDE0Pwp2aWV3cyA+IDExICYgdmlld3MgPD0gMTQKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMjIyMgICAgICAgICBOT1QgICAgICAgICAgICMjIyMjCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgojIENvbnRyw6FyaW8gZG8gcmVzdWx0YWRvIGRhIGNvbmRpw6fDo28KISg1ID4gMykKCmBgYAoKIyMjIyAqKkNPTkRJw4fDlUVTKioKCkluZGVwZWRlbnRlIGRvIG9wZXJhZG9yIHV0aWxpemFkbyBhbnRlcmlvcm1lbnRlIChyZWxhY2lvbmFsIG91IGzDs2dpY28pIHTDrW5oYW1vcyBjb21vIHJlc3VsdGFkbyBvcyB2YWxvcmVzICoqVFJVRSoqIG91ICoqRkFMU0UqKi4gUG9yw6ltLCBuZW5odW1hIGHDp8OjbyBlcmEgdG9tYWRhIGEgcGFydGlyIGRvcyB0ZXN0ZXMuIAoKQWdvcmEsIHVzYXJlbW9zIGNvbmRpw6fDtWVzIGUgYSBwYXJ0aXIgZG9zIHJlc3VsdGFkb3MgdW1hIGHDp8OjbyBzZXLDoSBleGVjdXRhZGEgY29tbyBtb3N0cmFtIG9zIGPDs2RpZ29zIGVtIFIgYWJhaXhvLgoKYGBge3J9CiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMjIyMgICAgICAgICBJRkVMU0UgICAgICAgICMjIyMjCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgojIMOabHRpbW8gZGlhIGRlIHZpc3VhbGl6YcOnw6NvIGRvIExpbmtlZEluIGUgRmFjZWJvb2sKbGkgPC0gMTUKZmIgPC0gOQoKIyBJZmVsc2UgcGFyYSB0ZXN0YXIgY29uZGnDp8O1ZXMKaWYgKGxpID49IDE1ICYgZmIgPj0gMTUpIHsgICAgICAgICAgIyBUZXN0YXIgc2UgZW0gYW1ib3MgdGVtb3MgMTUgb3UgbWFpcyB2aXNpdGFzCiAgc21zIDwtIChsaSArIGZiKSAqIDIgICAgICAgICAgICAgICMgU2UgZm9yIHZlcmRhZGUsIGV4ZWN1dGUgYSBzb21hIGRhcyB2aXNpdGFzIG11bHRpcGxpY2FkbyBwb3IgMiAKfSBlbHNlIGlmIChsaSA8IDEwICYgZmIgPCAxMCkgeyAgICAgIyBDYXNvIGNvbnRyw6FyaW8sIHRlc3RlIHNlIGVtIGFtYm9zIHRlbW9zIG1lbm9zIHF1ZSAxMCB2aXNpdGFzCiAgc21zIDwtIChsaSArIGZiKSAvIDIgICAgICAgICAgICAgICMgU2UgZm9yIHZlcmRhZGUsIGV4ZWN1dGUgYSBtw6lkaWEgZGUgdmlzaXRhcwp9IGVsc2UgeyAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIENhc28gY29udHLDoXJpbywgYXBlbmFzIHNvbWUgYXMgdmlzaXRhcwogIHNtcyA8LSAobGkgKyBmYikKfQoKIyByZXN1bHRhZG8KcHJpbnQoc21zKQpgYGAKCiMjIyMgKipMT09QUyoqCgpNdWl0YXMgdmV6ZXMgcG9kZSBzZXIgcHJlY2lzbyByZWVzY3JldmVyIG8gc2V1IGPDs2RpZ28gZW0gZnVuw6fDo28gZGEgbmVjZXNzaWRhZGUgZGUgc2UgcmVwZXRpciB1bWEgYXRpdmlkYWRlLiBJc3NvIHBvZGUgc2VyIHRyYWJhbGhvc28gZSBjb25zdW1pciBiYXN0YW50ZSB0ZW1wby4gRmVsaXptZW50ZSwgdGVtb3MgZW0gcHJvZ3JhbWHDp8OjbyBhIG9ww6fDo28gZGUgdXNhciBgbG9vcHNgIChubyBSLCBhcyBmdW7Dp8O1ZXMgYGZvcigpYCwgYHdoaWxlKClgIGUgYHJlcGVhdCgpYCkuIAoKTm9zIGPDs2RpZ29zIGFiYWl4bywgdGVtb3MgZXhlbXBsb3MgZGUgY29tbyB1c2FyIG9zIGBsb29wc2Agbm8gUi4KCmBgYHtyfQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIyMjICAgICAgV0hJTEUgTE9PUCAgICAgICAjIyMjIwojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKIyBVbWEgdmFyacOhdmVsIGRlIHZlbG9jaWRhZGUKc3BlZWQgPC0gNjQKCiMgRW5xdWFudG8gYSB2ZWxvY2lkYWRlIGZvciBtYWlvciBxdWUgMzAgZXhlY3V0ZQp3aGlsZSAoc3BlZWQgPiAzMCApIHsKICBwcmludCgnRGVzYWNlbGVyYW5kbyEnKQogIHNwZWVkIDwtIHNwZWVkIC0gNyAgICMgRGVzYWNlbGVyYXIgYSB2ZWxvY2lkYWRlICAgICAgICAKfQojIE1vc3RyZSBvIHJlc3VsdGFkbwpwcmludChzcGVlZCkKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMjIyMgICAgICAgRk9SIExPT1AgICAgICAgICMjIyMjCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgojICBWZXJzw6NvIDEKZm9yICh2aWV3cyBpbiBsaW5rZWRpbikgeyAgICAgICAjIFBhcmEgY2FkYSB2YWxvciBkYSBtYXRyaXogdmlld3MgcXVlIGV4aXN0ZSBubyB2ZXRvciBsaW5rZWRpbgogIHByaW50KHZpZXdzKSAgICAgICAgICAgICAgICAgICMgTW9zdHJlIG8gdmFsb3IKfQoKIyBWZXJzw6NvIDIKZm9yIChpIGluIDE6bGVuZ3RoKGxpbmtlZGluKSkgeyAjIFBhcmEgY2FkYSDDrW5kaWNlIGRhIHNlcXXDqm5jaWEgZGUgMSBhIGxlbmd0aChsaW5rZWRpbikgCiAgcHJpbnQobGlua2VkaW5baV0pICAgICAgICAgICAgIyBNb3N0cmUgbyB2YWxvciBkbyB2ZXRvciBkbyByZXNwZWN0aXZvIMOtbmRpY2UKfQoKIyBWZXJzw6NvIDM6IFVzYW5kbyBhIGZ1bsOnw6NvIHNlcV9hbG9uZy4gRWxhIGNyaWEgdW0gdmV0b3IgCiMgZGUgaW50ZWlyb3MgY29tIMOtbmRpY2VzIHBhcmEgYWNvbXBhbmhhciBvIG9iamV0by4gCmZvciAoaSBpbiBzZXFfYWxvbmcobGlua2VkaW4pKSB7ICMgUGFyYSBjYWRhIMOtbmRpY2UgZG8gdmV0b3IgbGlua2RlZGluCiAgcHJpbnQobGlua2VkaW5baV0pICAgICAgICAgICAgICMgTW9zdHJlIG9zIHJlc3VsdGFkb3MKfQoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyMjICAgTE9PUCBTT0JSRSBVTUEgTElTVEEgICAjIyMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKCiMgQ3JpYW5kbyB1bWEgbGlzdGEKbnljIDwtIGxpc3QocG9wID0gODQwNTgzNywgYmFpcnJvcyA9IGMoIk1hbmhhdHRhbiIsICJCcm9ueCIsICJCcm9va2x5biIsICJRdWVlbnMiLCAiU3RhdGVuIElzbGFuZCIpLCAKICAgICAgICAgICAgY2FwaXRhbCA9IEZBTFNFKQoKIyBWZXJzw6NvIDEKZm9yICh2YWx1ZSBpbiBueWMpIHsgICAgICAgICAgICAgIyBQYXJhIGNhZGEgaXRlbSBkYSBsaXN0YSAKICBwcmludCh2YWx1ZSkgICAgICAgICAgICAgICAgICAgIyBNb3N0cmUgb3MgdmFsb3JlcyBjb250aWRvcyBlbSBjYWRhIGl0ZW0gZGEgbGlzdGEKfQoKIyBWZXJzw6NvIDIKZm9yIChpIGluIDE6bGVuZ3RoKG55YykpIHsgICAgICAgIyBQYXJhIGNhZGEgw61uZGljZSBkYSBzZXF1w6puY2lhIGRlIDEgYXTDqSBvIHRhbWFuaG8gZGUgaXRlbnMgbmEgbGlzdGEKICBwcmludChueWNbW2ldXSkgICAgICAgICAgICAgICAgIyBNb3N0cmUgb3MgdmFsb3JlcyBjb250aWRvcyBlbSBjYWRhIGl0ZW0gZGEgbGlzdGEgdXNhbmRvIG8gw61uZGljZQp9CgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIyMgICBMT09QIFNPQlJFIFVNQSBNQVRSSVogICMjIwojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKIyBDcmlhciB1bWEgbWF0cml6CnR0dCA8LSBtYXRyaXgoYygiTyIsIE5BLCAiWCIsIE5BLCAiTyIsIE5BLCAiWCIsICJPIiwgIlgiKSwgbnJvdyA9IDMsIG5jb2wgPSAzKQoKIyBFeGVjdXRhciBvIGxvb3AgCmZvciAoaSBpbiAxOm5yb3codHR0KSkgeyAgICAgICAgIyBQYXJhIGNhZGEgbGluaGEgZGEgbWF0cml6ICgxOm5yb3codHR0KSBjcmlhcsOhIG9zIMOtbmRpY2VzIGRhcyBsaW5oYXMpCiAgZm9yIChqIGluIDE6bmNvbCh0dHQpKSB7ICAgICAgIyBQYXJhIGNhZGEgY29sdW5hIGRhIG1hdHJpeiAoMTpuY29sKHR0dCkgY3JpYXLDoSBvcyDDrW5kaWNlcyBkYXMgY29sdW5hcykKICBwcmludChwYXN0ZSgiTmEgbGluaGEiLGksImUgY29sdW5hIixqLCJ0ZW1vcyIsdHR0W2ksal0pKSAgIyBNb3N0cmUgb3MgcmVzdWx0YWRvcyAKICB9Cn0KCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMjIyMgIExPT1AgQ09NIENPTkRJw4fDlUVTICAgICMjIyMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKCiMgRXhlY3V0YXIgbyBsb29wCmZvciAobGkgaW4gbGlua2VkaW4pIHsgICAgICAgICAgICAjIFBhcmEgY2FkYSDDrW5kaWNlIGRvIHZldG9yIGxpbmtlZGluIChjaGFtYW1vcyBvIMOtbmRpY2UgZGUgbGkpCiAgaWYgKGxpID4gMTApIHsgICAgICAgICAgICAgICAgICAjIFNlIG8gw61uZGljZSBmb3IgbWFpb3IgcXVlIDEwCiAgICBwcmludCgiVm9jw6ogw6kgcG9wdWxhciIpICAgICAgICMgTW9zdHJlIGEgbWVuc2FnZW0gIlZvY8OqIMOpIHBvcHVsYXIiCiAgfSBlbHNlIHsgICAgICAgICAgICAgICAgICAgICAgICAjIENhc28gY29udHLDoXJpbywgc2UgbyDDrW5kaWNlIGZvciA8PSAxMAogICAgcHJpbnQoIlNlamEgbWFpcyB2aXPDrXZlbCEiKSAgICMgTW9zdHJlIG91dHJhIG1lbnNhZ2VtICJTZWphIG1haXMgdmlzw612ZWwiCiAgfQp9CgpgYGAKCiMjIyMgKipGVU7Dh8OVRVMqKgoKRHVyYW50ZSBhIHByb2dyYW1hw6fDo28gZW0gUiB2b2PDqiBwb2RlIGZhemVyIHVzbyBkZSBmdW7Dp8O1ZXMgInByb250YXMiIGRlIHBhY290ZXMgZG8gUiwgbWFzIGVtIGFsZ3VucyBjYXNvcyB2b2PDqiBwb2RlIG9wdGFyIHBvciBjcmlhciBzdWEgcHLDs3ByaWEgZnVuw6fDo28uIERlc3RhIGZvcm1hLCB2b2PDqiBldml0YSByZXBldGlyIGPDs2RpZ29zIHBhcmEgZXhlY3V0YXIgYSBtZXNtYSB0YXJlZmEuCgpOb3MgY8OzZGlnb3MgYWJhaXhvLCB0ZW1vcyBjw7NkaWdvcyBlbSBSIHF1ZSBtb3N0cmFtIGNvbW8gYWNlc3NhciBhIGRvY3VtZW50YcOnw6NvIGRlIHVtYSBmdW7Dp8OjbyBuYXRpdmEgZG8gUiBlIGNvbW8gY3JpYXIgc3VhIHByw7NwcmlhIGZ1bsOnw6NvLiAKCmBgYHtyfQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIyMjICAgRlVOw4fDlUVTIE5BVElWQVMgICAgICMjIyMjCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgojIFBhcmEgYWNlc3NhciBhIGRvY3VtZW50YcOnw6NvIGRlIHVtYSBmdW7Dp8OjbyBuYXRpdmEuCmhlbHAobWVhbikKaGVscChzZCkKCiMgRXhpc3RlbSBhcmd1bWVudG9zIG9icmlnYXTDs3Jpb3MgZSBvcGNpb25haXMgZW0gZnVuw6fDtWVzLiBFeGVtcGxvOgpzZCh4LCBuYS5ybSA9IEZBTFNFKQoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyMjICAgRlVOw4fDlUVTIFBSw5NQUklBUyAgICAgICAjIyMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKCiMgQ3JpYW5kbyBhIGZ1bsOnw6NvIHF1YWRyYWRvIHF1ZSByZWNlYmUgbyBhcmd1bWVudG8geApxdWFkcmFkbyA8LSBmdW5jdGlvbih4KSB7CiByZXN1bHQgPC0geF4yCiByZXR1cm4ocmVzdWx0KQp9CgojIFVzYW5kbyBhIGZ1bsOnw6NvIHF1YWRyYWRvCnF1YWRyYWRvKDEyKQoKIyBDcmlhbmRvIGEgZnVuw6fDo28gc29tYXJfYWJzKCkgcXVlIHJlY2ViZSBvcyBhcmd1bWVudG9zIHggZSB5CnNvbWFyX2FicyA8LSBmdW5jdGlvbih4LCB5KSB7CiAgcmVzdWx0IDwtIGFicyh4KSArIGFicyh5KQogIHJldHVybihyZXN1bHQpCn0KCiMgVXNhbmRvIGEgZnVuw6fDo28gc29tYXJfYWJzCnNvbWFyX2FicygtMiwgMykKCgojIEV4cGFuZGlyIGEgZnVuw6fDo28gcXVhZHJhZG8oKSBwYXJhIHJlY2ViZXIgb3MgYXJndW1lbnRvcyB4IGUgcHJpbnRfaW5mbwpxdWFkcmFkbyA8LSBmdW5jdGlvbih4LCBwcmludF9pbmZvID0gVCkgeyAgICAgICAgICMgYXJndW1lbnRvcyBkYSBmdW7Dp8OjbwogIHkgPC0geCBeIDIgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgdGFyZWZhIGEgc2VyIGV4ZWN1dGFkYQogIGlmIChwcmludF9pbmZvID09IFQpIHsgICAgICAgICAgICAgICAgICAgICAgICAgICMgdmVyaWZpY2FyIG8gYXJndW1lbnRvIHByaW50X2luZm8KICAgIHByaW50KHBhc3RlKHgsICdlbGV2YWRvIGFvIHF1YWRyYWRvIMOpJyx5KSkgICAgIyBzZSBUUlVFLCBtb3N0cmFyIGEgbWVuc2FnZW0KICB9CiAgcmV0dXJuKHkpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBhIGZ1bsOnw6NvIGRldmUgcmV0b3JuYXIgY29tbyBzYcOtZG8gb3MgdmFsb3JlcyBkZSB5Cn0KCnF1YWRyYWRvKDUpCnF1YWRyYWRvKDUsIHByaW50X2luZm89RikKYGBgCgojIyMjIyAqKkEgRkFNw41MSUEgREUgRlVOw4fDlUVTIEFQUExZKioKCkVzY3JldmVyIGxvb3BzIGRhIGZvcm1hIHRyYWRpY2lvbmFsIHBvZGUgc2VyIHVtYSB2ZXJkYWRlaXJhIHRvcnR1cmEsIHRhbnRvIHBhcmEgbyB1c3XDoXJpbyBxdWFudG8gcGFyYSBvIGNvbXB1dGFkb3IgZW0gZnVuw6fDo28gZGUgcGVyZm9ybWFuY2UuIAoKRW0gZnVuw6fDo28gZGlzc28sIHN1cmdpcmFtIGFzIGZ1bsOnw7VlcyBgYXBwbHkoKWAgcXVlIHPDo28gbXVpdG8gw7p0ZWlzIG5hIG1hbmlwdWxhw6fDo28gZGUgZGFkb3MgZSBzaW1wbGlmaWNhbSBlIGFjZWxlcmFtIG8gcHJvY2Vzc28uIFR1ZG8gcXVlIHZvY8OqIGNvbnNlZ3VpcmlhIGZhemVyIGNvbSB1bSBgZm9yKClgIHBvZGUgc2VyIHJlYWxpemFkbyBjb20gZnVuw6fDtWVzIGRhIGZhbcOtbGlhIGBhcHBseSgpYC4gCgoqICoqYGFwcGx5KClgKio6CgpBcGxpY2EgdW1hIGZ1bsOnw6NvIG5hcyBtYXJnZW5zIGRlIHVtIGFycmF5IHF1YWxxdWVyLiBHZXJhbG1lbnRlIMOpIGFwbGljYWRvIGVtIHVtYSBtYXRyaXovZGF0YWZyYW1lIGRlIGZvcm1hIGEgZXhlY3V0YXIgdW1hIG1lc21hIGZ1bsOnw6NvIGVtIHRvZGFzIGFzIGxpbmhhcyBvdSBjb2x1bmFzIGRhcXVlbGUgb2JqZXRvLiBSZWNlYmUgY29tbyBhcmd1bWVudG8gdW0gYXJyYXksIGEgbWFyZ2luYWwgc29icmUgYSBxdWFsIGEgZnVuw6fDo28gc2Vyw6EgYXBsaWNhZGEgKGxpbmhhIG91IGNvbHVuYSkgZSBhIGZ1bsOnw6NvLgoKKiAqKmBsYXBwbHkoKWAqKjoKCsOJIHVtYSBmdW7Dp8OjbyBxdWUgw6kgYXBsaWNhZGEgZW0gY2FkYSBlbGVtZW50byBkZSB1bSB2ZXRvciBvdSBjYWRhIG7DsyBkZSB1bWEgbGlzdGEuIE8gb3V0cHV0IMOpIHVtYSBsaXN0YSBvYnJpZ2F0b3JpYW1lbnRlLiBSZWNlYmUgY29tbyBhcmd1bWVudG9zIHVtIHZldG9yL2xpc3RhIGUgdW1hIGZ1bsOnw6NvLgoKKiAqKmBzYXBwbHkoKWAqKjoKClNpbWlsYXIgYW8gbGFwcGx5LCBwb3LDqW0gYSBzYcOtZGEgZ2VyYWxtZW50ZSDDqSBzaW1wbGlmaWNhZGEsIHNlbmRvIGFwZW5hcyB1bSB2ZXRvci4gQ2FzbyBzdWEgc2HDrWRhIHNlamEgbWFpcyBkZSB1bSBlbGVtZW50bywgYSBzYcOtZGEgZGVpeGEgZGUgc2VyIHVtIHZldG9yIGUgcGFzc2EgYSBzZXIgdW1hIG1hdHJpei4gUmVjZWJlIGNvbW8gYXJndW1lbnRvcyB1bSB2ZXRvci9saXN0YSBlIHVtYSBmdW7Dp8Ojby4gQSBkaWZlcmVuw6dhIHBhcmEgbyBsYXBwbHkgw6kgcXVlIG8gc2FwcGx5IHRlbnRhIHNpbXBsaWZpY2FyIG8gcmVzdWx0YWRvLCByZXRvcm5hbmRvIGFzc2ltIHVtIHZldG9yIG91IGFsZ28gcGFyZWNpZG8uCgoqICoqYHRhcHBseSgpYCoqOgoKRnVuw6fDo28gY29tIG8gb2JqZXRpdm8gZGUgYXBsaWNhciBmdW7Dp8O1ZXMgZW0gZ3J1cG9zIGRpZmVyZW50ZXMuIFN1cG9uaGEgcXVlIHZvY8OqIHRlbmhhIHVtIGRhdGFmcmFtZSBjb20gMiBjb2x1bmFzLCB1bWEgY29tIGFsdHVyYSBlIG91dHJhIGNvbSBnw6puZXJvLCBlIHZvY8OqIHF1ZWlyYSBjYWxjdWxhIGEgbcOpZGlhIGRlIGlkYWRlIHBhcmEgY2FkYSB1bSBkb3MgZ+G6vW5lcm9zLCBlbnTDo28gbmVzdGUgY2FzbyBhIGZ1bsOnw6NvIHRhcHBseSBzZSBhcGxpY2EgcGVyZmVpdGFtZW50ZS4gUmVjZWJlIGNvbW8gYXJndW1lbnRvcyB1bSB2ZXRvciwgdW0gdmV0b3IgY29tIG9zIGZhdG9yZXMgcXVlIGlyw6NvIGVzdHJhdGlmaWNhciBvIHJlc3VsdGFkbyBlIGEgZnVuw6fDo28gYSBzZXIgYXBsaWNhZGEgZW0gY2FkYSBlc3RyYXRvLgoKQWJhaXhvLCBjw7NkaWdvcyBlbSBSIHF1ZSBtb3N0cmFtIGNvbW8gZmF6ZXIgdXNvIGRlIGNhZGEgdW1hIGRhcyBmdW7Dp8O1ZXMgZGEgZmFtw61saWEgZGUgZnVuw6fDtWVzIGFwcGx5LiAKCmBgYHtyfQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIyMjIyMgICAgICAgQVBQTFkgICAgICAgICAjIyMjIwojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKIyBtYXRyaXogY29tIDIwIGNvbHVuYXMgZSAxMCBsaW5oYXMKeCA8LSBtYXRyaXgocm5vcm0oMjAwKSwgbmNvbD0yMCkKCiMgbcOpZGlhIG5hIGxpbmhhIChNQVJHSU4gPSAxKQptZWRpYV9saW5oYSA8LSBhcHBseSh4LCBNQVJHSU4gPSAxLCBtZWFuKSAgICMgYXBsaWNhciBhIGZ1bsOnw6NvIG1lYW4gbmFzIGxpbmhhcwoKIyBtw6lkaWEgbmEgY29sdW5hIChNQVJHSU4gPSAyKQptZWRpYV9jb2x1bmEgPC0gYXBwbHkoeCwgTUFSR0lOID0gMiwgbWVhbikgICMgYXBsaWNhciBhIGZ1bsOnw6NvIG1lYW4gbmFzIGNvbHVuYXMKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMjIyMjIyAgICAgICBMQVBQTFkgICAgICAgICMjIyMjCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgojIFVtYSBsaXN0YSBxdWFscXVlciBjb20gNyB2ZXRvcmVzIGRlIHRlbXBlcmF0dXJhcyBlbSBjYWRhIGRpYQp0ZW1wIDwtIGxpc3QoCiAgYygzLCA3LCAgOSwgIDYsIC0xKSwKICBjKDYsICA5LCAxMiwgMTMsICA1KSwKICBjKDQsICA4LCAgMywgLTEsIC0zKSwKICBjKDEsICA0LCAgNywgIDIsIC0yKSwKICBjKDUsIDcsIDksIDQsIDIpLAogIGMoLTMsICA1LCAgOCwgIDksICA0KSwKICBjKDMsIDYsIDksIDQsIDEpCiAgKQoKIyBUZW1wZXJhdHVyYSBtw61uaW1hIGVtIGNhZGEgZGlhLiBSZXRvcm5hIHVtYSBsaXN0YS4KbGFwcGx5KHRlbXAsIG1pbikKCiMgVGVtcGVyYXR1cmEgbcOheGltYSBlbSBjYWRhIGRpYS4gUmV0b3JuYSB1bWEgbGlzdGEuIApsYXBwbHkodGVtcCwgbWF4KQoKIyBUZW1wZXJhdHVyYSBtw6lkaWEgZW0gY2FkYSBkaWEuIFJldG9ybmEgdW1hIGxpc3RhLgpsYXBwbHkodGVtcCwgbWVhbikKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMjIyMjIyAgICAgICBTQVBQTFkgICAgICAgICMjIyMjCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgojIFRlbXBlcmF0dXJhIG3DrW5pbWEgZW0gY2FkYSBkaWEuIFJldG9ybmEgdW0gdmV0b3IuCnNhcHBseSh0ZW1wLCBtaW4pCgojIFRlbXBlcmF0dXJhIG3DoXhpbWEgZW0gY2FkYSBkaWEuIFJldG9ybmEgdW0gdmV0b3IuCnNhcHBseSh0ZW1wLCBtYXgpCgojIFRlbXBlcmF0dXJhIG3DqWRpYSBlbSBjYWRhIGRpYS4gUmV0b3JuYSB1bSB2ZXRvci4Kc2FwcGx5KHRlbXAsIG1lYW4pCgojIFRlc3RlIHF1ZSByZXRvcm5hIGFwZW5hcyBlbSBmb3JtYXRvIGRpZmVyZW50ZSwgbWFzIGNvbSByZXN1bHRhZG9zIGlndWFpcwp1bmxpc3QobGFwcGx5KHRlbXAsIG1heCkpID09IHNhcHBseSh0ZW1wLCBtYXgpCgojIEZ1bsOnw6NvIHF1ZSBjYWxjdWxhIGEgbcOpZGlhIGRvIG3DrW5pbW8gZSBtw6F4aW1vIGRlIHVtIHZldG9yCmV4dHJlbWVzX2F2ZyA8LSBmdW5jdGlvbih4KSB7CiBhdmcgPC0gbWVhbihjKG1pbih4KSwgbWF4KHgpKSkKIHJldHVybihhdmcpCn0KCiMgVXNhbmRvIGVsYSBjb20gbyBzYXBwbHkoKS4gUG9kZXLDrWFtb3MgdXNhciBlbGEgZW0gbGFwcGx5KCkgb3UgYXBwbHkoKS4Kc2FwcGx5KHRlbXAsIGV4dHJlbWVzX2F2ZykKYGBgCgojIyMjIyAqKlRSQUJBTEhBTkRPIENPTSBEQVRBUyoqCgpBIGRhdGEgb3UgdGVtcG8gw6kgdW0gZGFkbyBxdWUgbmVjZXNzaXRhIGRlIHVtYSBtYW5pcHVsYcOnw6NvIGVzcGVjw61maWNhLiBDb21vIHRyYWJhbGhhcmVtb3MgY29tIHPDqXJpZXMgdGVtcG9yYWlzLCDDqSBkZSBzdW1hIGltcG9ydMOibmNpYSBvIGJvbSBlbnRlbmRpbWVudG8gZGUgY29tbyBsaWRhciBjb20gZGFkb3MgdGVtcG9yYWlzIHF1ZSwgbmVjZXNzw6FyaWFtZW50ZSwgc2Vyw6NvIGFybWF6ZW5hZG9zIGNyb25vbMOzZ2ljYW1lbnRlLiAKCk5vIFIgdGVtb3MgdsOhcmlhcyBmb3JtYXMgZGUgdHJhYmFsaGFyIGNvbSBkYXRhcy4gQWJhaXhvLCBhbGd1bnMgZXhlbXBsb3MgcXVlIHBvZGVtIG5vcyBhanVkYXIuCgpgYGB7cn0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyMjIyMgICAgREFUQS9URU1QTyAgICAgICAgIyMjIyMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKCiMgQSBkYXRhIGF0dWFsLiBBIGZ1bsOnw6NvIHByaW1pdGl2YSBTeXMuRGF0ZSgpIGNyaWEgdW1hIGRhdGEgbm8gZm9ybWF0byBjb3JyZXRvCnRvZGF5IDwtIFN5cy5EYXRlKCkKCiMgU2UgZXhjbHVpcm1vcyBhIGNsYXNzZSB2ZW1vcyBxdWUgdGVyZW1vcyB1bSBuw7ptZXJvIHF1ZSBuw6NvIMOpIGludGVycHJldMOhdmVsIAp1bmNsYXNzKHRvZGF5KQoKIyBBIGhvcmEgY29ycmVudGUKbm93IDwtIFN5cy50aW1lKCkKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMjIyMgIENSSUFORE8gREFUQS9URU1QTyAgICMjIyMjCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCgojIERlZmluaW5kbyBkYXRhcyBlbSB1bSBmb3JtYXRvIHF1YWxxdWVyIGNvbW8gY2hhcmFjdGVyCnN0cjEgPC0gIjIwMTItMy0xNSIKc3RyMiA8LSAiMDIvMjcvOTIiCgojIENvbnZlcnRlbmRvIHBhcmEgZGF0YXMgbm8gZm9ybWF0byBxdWUgbyBSIHJlY29uaGVjZQpkYXRlMSA8LSBhcy5EYXRlKHN0cjEsIGZvcm1hdCA9ICIlWS0lbS0lZCIpCmRhdGUyIDwtIGFzLkRhdGUoc3RyMiwgZm9ybWF0ID0gIiVtLyVkLyV5IikKCiMgRGVmaW5pbmRvIHRlbXBvIGVtIGZvcm1hdG8gZGUgc3RyaW5nCnN0cjEgPC0gIjIwMTItMy0xMiAxNDoyMzowOCIKCiMgQ29udmVydGVyIGFzIHN0cmluZyBwYXJhIHVtIG9iamVjdG8gUE9TSVhjdAp0aW1lMSA8LSBhcy5QT1NJWGN0KHN0cjEsIGZvcm1hdCA9ICIlWS0lbS0lZCAlVCIpCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIyMjICBDw4FMQ1VMTyBEQVRBL1RFTVBPICAgIyMjIyMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKCiMgRGF0YXMKZGF5MSA8LSBhcy5EYXRlKCIyMDE3LTAzLTEyIikKZGF5MiA8LSBhcy5EYXRlKCIyMDE3LTAzLTE0IikKZGF5MyA8LSBhcy5EYXRlKCIyMDE3LTAzLTE5IikKZGF5NCA8LSBhcy5EYXRlKCIyMDE3LTAzLTI1IikKZGF5NSA8LSBhcy5EYXRlKCIyMDE3LTAzLTMwIikKCiMgRGlmZXJlbsOnYSBlbnRyZSBvIHByaW1laXJvIGUgbyDDumx0aW1vIGRpYQpkYXk1LWRheTEKCiMgQ3JpYXIgdW0gdmV0b3IgY29tIGFzIGRhdGFzCnBpenphIDwtIGMoZGF5MSwgZGF5MiwgZGF5MywgZGF5NCwgZGF5NSkKcGl6emEKCiMgQ3JpYXIgdW0gdmV0b3IgY29tIGEgZGlmZXJlbsOnYSBlbnRyZSBvcyBkaWFzIGNvbnNlY3V0aXZvcwpkYXlfZGlmZiA8LSBkaWZmKHBpenphKQpkYXlfZGlmZgoKIyBQZXLDrW9kbyBtw6lkaW8gZW50cmUgZG9pcyBkaWFzIGNvbnNlY3V0aXZvcyAKbWVhbihkYXlfZGlmZikKYGBgCgojIyMjIyAqKlBBQ09URVMqKgoKQ29tbyBjb21lbnRhZG8gYW50ZXJpb3JtZW50ZSwgdm9jw6ogcG9kZSBmYXplciB1c28gZGUgZnVuY2lvbmFsaWRhZGVzIGRlIHBhY290ZXMgZG8gUi4gTmVzdGUgY2Fzbywgdm9jw6ogcHJlY2lzYSBhZGljaW9uYXIgZXNzZSBwYWNvdGUgbm8gY29uanVudG8gZGUgYmlibGlvdGVjYXMgZGlzcG9uw612ZWlzIG5vIFIgcGFyYSBxdWUgc2VqYSBwb3Nzw612ZWwgdXNhciBzdWFzIGZ1bsOnw7Vlcy4gCgpJc3RvIMOpIG5lY2Vzc8OhcmlvIHBvcnF1ZSBxdWFuZG8gaW5pY2lhbW9zIG8gUlN0dWRpbyBhcGVuYXMgYWxndW5zIHBhY290ZXMgYsOhc2ljb3Mgc8OjbyBjYXJyZWdhZG9zIGF1dG9tYXRpY2FtZW50ZS4gUGFyYSBxdWUgb3Mgb3V0cm9zIHRhbWLDqW0gc2VqYW0gY2FycmVnYWRvcywgw6kgcHJlY2lzbyBhY2lvbsOhLWxvcy4gCgpBYmFpeG8sIHZlcmVtb3MgY29tbyBmYXplciBhIGluc3RhbGHDp8OjbyBkZSBwYWNvdGVzIGJlbSBjb21vIHNldSBjYXJyZWdhbWVudG8gbm8gUlN0dWRpby4KCmBgYHtyfQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIyMjIyAgICAgIElOU1RBTEFSICAgICAgICAjIyMjIwojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKIyBBbMOpbSBkZXNzYSBvcMOnw6NvIHZvY8OqIHBvZGUgaW5zdGFsYXIgcGFjb3RlcyBkaXJldGFtZW50ZSBubyBwYWluZWwgaW5mZXJpb3IgZGlyZWl0byBkbyBSU3R1ZGlvCmluc3RhbGwucGFja2FnZXMoImRwbHlyIikKaW5zdGFsbC5wYWNrYWdlcyhjKCJkcGx5ciIsICJkYXRhLnRhYmxlIikpCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIyMjIyAgICAgICBDQVJSRUdBUiAgICAgICAjIyMjIwojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwoKIyBGb3JtYSB0cmFkaWNpb25hbC4gQXF1aSwgbsOjbyBwcmVjaXNhbW9zIGRhcyBhc3BhcyBwb3JxdWUgbyBSIGrDoSByZWNvbmhlY2UgcXVlIGjDoSBvIHBhY290ZSBubyBhbWJpZW50ZQpyZXF1aXJlKGRwbHlyKQpyZXF1aXJlKGRhdGEudGFibGUpCgojIEFsdGVybmF0aXZhIHBhcmEgbm8gbW9tZW50byBkZSBjYXJyZWdhbWVudG8gZG8gcGFjb3RlIG7Do28gYXBhcmVjZXJlbSBtZW5zYWdlbnMKc3VwcHJlc3NNZXNzYWdlcyhyZXF1aXJlKGRwbHlyKSkKc3VwcHJlc3NNZXNzYWdlcyhyZXF1aXJlKGRhdGEudGFibGUpKQoKIyBBY2lvbmFuZG8gdG9kYXMgYXMgZnVuw6fDtWVzIGRpc3BvbsOtdmVpcyBubyBwYWNvdGUKaGVscChkcGx5cikKaGVscChkYXRhLnRhYmxlKQpgYGAKCiMjIyMgKipSRUZFUsOKTkNJQVMqKg==