Introdução ao Tidyverse: tibble e dplyr
Aula 1 – Recomendações
Objetivo: instalar os pacotes necessários
# o símbolo # no início da linha indica que temos um comentário
# essa linha de comentário não é executada quando der o comando run (ctrl+enter)
#Para instalar o pacote (somente 1 vez)
#install.packages("tidyverse")
#Como o tidyverse é um pacote que contém vário pacotes, podemos
#Ter o mesmo efeito se instalarmos os seguintes pacotes
#Um por Um .
# install.packages(c(
# "broom", "dplyr", "feather",
# "forcats","ggplot2", "haven",
# "httr", "hms", "jsonlite",
# "lubridate", "magrittr",
# "modelr", "purrr", "readr",
# "readxl", "stringr", "tibble",
# "rvest", "tidyr", "xml2"
#))
#Lembrando que não é preciso instalar todos esses pacotes
#Se intalarmos o tidyverse já vamos obetê-los todos.
#Para carregar o pacote (sempre que for usá-lo)
library(tidyverse) #Ou require(tidyverse)
#Para finalizar esta aula, assista o vídeo
browseURL("https://youtu.be/dvkFWm6Th54")
#Parabéns, você completou a primeira aula!
Aula 2 – Tibble
Objetivo: apresentar a estrutura tibble
#1)Instalando O Pacote Tibble
#install.packages("tibble")
#2)Chamando o Pacote Tibble
#library(tibble)
#3)O Tibble so mostra as 10 primeiras linhas
tibble(x=1:100, y=100:1, z=rep("A",100))
#4)Montando tribble linha por linha
tribble(
~x,~y,~z,
10, 20,"A",
20, 30,"B",
40, 50,"C"
)
#4)Lendo Data.frame como tibble
DF=data.frame(Nome=c('Rafaela','Felipe','Rodolfo'),Idade=c(18,14,20),Nota=c(10,6,8))
DFT=as_tibble(DF)
DFT
#Comandos extras
#5)Criando Tibble com nomes de colunas nada convencionais
tibble(
':)' = 'simile', #Diferente do Data.frame, podemos usar simbolos como nome de colunass
' ' = 1:4,
x = 5:2,
y =x+1
)
#6)Podemos modificar a Quantidade De linhas que visualizamos
#Por padrão o sistema tidy exibe 10 linhas, mas podemos modificar esta opção
m=30
n=20
options(tibble.print_max = m, tibble.print_min = n)
#Ou seja:Se passar de 'm' linhas, printar 'n' linhas) )
#Podemos usar 'tibble.print_min = Inf' para printar todas as linhas
tibble(x=1:100, y=100:1, z=rep("A",100))
#Ou coloque a opção como argumento
tibble(x=1:100, y=100:1, z=rep("A",100), options(tibble.print_min = 15))
#7)Acessando partes do tibble
t=tibble(
x=1:5,
y=x+1,
z=x^2+y
)
t
t$x #Mostra a coluna X(ou t[['x']])
[1] 1 2 3 4 5
t[[2,3]] #Linha2,Coluna3
[1] 7
Aula 3 – Select e Distinct
Objetivo: manipular colunas de uma tabela de dados (tibble)
library(nycflights13)
flights
select(flights,dep_time, arr_delay)
select(flights, "dep_time", "arr_delay")
select(flights, -day, -dep_time)
select(flights, dep_time:arr_delay)
select(flights, 3:9)
select(flights, starts_with("arr"))
select(flights, ends_with("time"))
select(flights, contains("dep"))
select(flights, time_hour, air_time, everything())
#renomear
flights <- select(flights,x1=year, x2=dep_time, x3=arr_delay, everything() )
select(flights, num_range("x", 1:3))
# Distinc
distinct(flights, day)
Aula 4 – Filter, Arrange, count e pipe
Objetivo: filtrar, arrumar e contar observações de uma tabela de dados
## filter, arrange, count e pipe
## Carregando o pacote e os dados
# Para carregar o pacote podemos utilizar
require(tidyverse)
# As funções são do pacote dplyr: require(dplyr)
# Tabela de dados:
starwars
## Utilizando a função filter
## Utilizando comparadores lógicos:
# maior, menor, maior ou igual, menor ou igual, igual e diferente
filter(starwars, height > 160)
filter(starwars, height <= 150)
filter(starwars, height == 79)
# Vírgula funciona como 'E' (&)
filter(starwars, species == "Droid", homeworld == "Tatooine", skin_color == "gold")
# Utilizando operador OU (|)
filter(starwars, height > 185 | eye_color == "blue")
## Utilizando a função arrange
# Ordem crescente
arrange(starwars, mass)
# Ordem decrescente
arrange(starwars, desc(mass))
# Ou então
arrange(starwars, -mass)
# Mais de uma variável
arrange(starwars, mass, -birth_year)
## Utilizando a função count
# Apenas uma variável
count(starwars, gender)
count(starwars, species)
# Mais de uma variável
count(starwars, hair_color, eye_color)
##Utilizando o operador Pipe: %>% (Ctrl + Shift + M)
filter(starwars,species == "Human") %>%
select(contains("color"))
starwars %>%
filter(species == "Human") %>%
count(eye_color) %>%
arrange(-n)
Aula 5 – Mutate e transmute
Objetivo: criar novas colunas em um tibble
## Mutate e Transmute
## Carregando o pacote e os dados
# Para carregar o pacote podemos utilizar
require(tidyverse)
#As funções são do pacote dplyr: require(dplyr)
# Tabela de dados
cars
## Utilizando a função mutate
cars %>%
mutate(dist2 = dist*2)
### Mutate e ifelse
cars %>%
mutate(classe_speed = ifelse(speed > 10, "A","B"))
### Operador %in%
cars %>%
mutate(classe_dist = ifelse(dist %in% 10:20, "A","B"))
## Utilizando a função Transmute
cars %>%
transmute(classe_speed = ifelse(speed > 10,"A","B"))
cars %>%
transmute(tempo = speed * dist,
classe_speed = ifelse(speed > 10,"A","B"))
Aula 6 – Summarise, group_by e n_distinct
Objetivo: operar sobre linhas e colunas de um tibble
## summarise, group_by, n_distinct
## Carregando pacotes
# dplyr ou tidyverse
# install.packages("dplyr")
require(dplyr)
# install.packages("tidyverse")
require(tidyverse)
# install.packages("nycflights13") # Pacote com os dados
require(nycflights13)
# Tabela com dados
flights
## Estatísticas, media, mediana, max, min...
flights %>%
summarise(Tempo_voo_medio = mean(air_time, na.rm = T),
MaiorDistancia = max(distance))
# Podemos fazer uma sumarização
flights %>%
group_by(year, month, day) %>%
summarise(MenorDistancia = min(distance),
MaiorDistancia = max(distance))
Error in grouped_df_impl(data, unname(vars), drop) :
Column `year` is unknown
Aula 7 – Joins
Objetivo: unir através de chave comum dois tibbles
# inner_join e left_join
# Carregando o pacote
library(tidyverse)
# ou library(dplyr)
# Base de dados
x <- tribble(
~Chave, ~valor_x,
1, "x1",
2, "x2",
3, "x3"
)
y <- tribble(
~Chave, ~valor_y,
1, "y1",
2, "y2",
4, "y3"
)
# inner_join (Junta as observações quando chaves nas duas bases são iguais)
inner_join(x, y, by = "Chave")
# left_join (Mantem todas as observações de x)
left_join(x, y, by = "Chave")
# right_join (Mantem todas as observações de y)
right_join(x, y, by = "Chave")
# full_join (Mantem todas as observações de x e y)
full_join(x, y, by = "Chave")
Aula 8 – Exercício 1
Objetivo: praticar comandos do pacote dplyr
Abra um script no Rstudio para realizar estes exercícios Usaremos a base de dados starwars do pacote dplyr •1-Quantas species distintas há na base de dados? •2-Selecione todas as observações da species “Human” •3-Selecione o name e hair_color de todas as observações da species “Human” •4-Faça um agrupamento da base de dados considerando apenas species “Human”, de acordo com gender e resumindo para cada gender a altura média (height)
library(tidyverse)
starwars
#1-Quantas species distintas há na base de dados?
starwars %>%
select(species) %>%
n_distinct()
[1] 38
#2-Selecione todas as observações da species Human
starwars %>%
filter(species == "Human")
#3-Selecione o name e hair_color de todas as observações da species Human
starwars %>%
filter(species == "Human") %>%
select(name, hair_color)
#4-Faça um agrupamento da species Human por gender e resuma pela média da altura (height)
starwars %>%
filter(species == "Human") %>%
group_by(gender) %>%
summarise(media=mean(height, na.rm=T))
Aula 9 – Exercício 2
Objetivo: praticar comandos do pacote dplyr
•1-Crie 2 tibbles: tbb1 = tibble( setor = rep(c(“F”, “M”, “I”), 2) , peso = runif(6, 50, 100)) tbb2 = tibble( setor = rep(c(“I”),2) , altura = c(167, 180) •2- Una tbb1 e tbb2 com a função inner_join •3- Una tbb1 e tbb2 com a função full_join •4- Una tbb1 e tbb2 com a função left_join •5- Una tbb1 e tbb2 com a função right_join •6- Ordene o tbb1 por ordem crescente do peso •7- Agrupe tbb1 por setor e sumarize com o peso médio
#1-Crie 2 tibbles:
tbb1 = tibble( setor = rep(c("F", "M", "I"), 2) , peso = runif(6, 50, 100))
tbb2 = tibble( setor = rep(c("I"),2) , altura = c(167, 180) )
# 2- Una tbb1 e tbb2 com a função inner_join
tbb1
tbb2
inner_join(tbb1, tbb2, chave="setor")
Joining, by = "setor"
#3- Una tbb1 e tbb2 com a função full_join
full_join(tbb1,tbb2,chave="setor")
Joining, by = "setor"
#4- Una tbb1 e tbb2 com a função left_join
left_join(tbb1,tbb2,chave="setor")
Joining, by = "setor"
#5- Una tbb1 e tbb2 com a função right_join
right_join(tbb1,tbb2,chave="setor")
Joining, by = "setor"
#6- Ordene o tbb1 por ordem crescente do peso
tbb1 %>% arrange(peso)
#7- Agrupe tbb1 por setor e sumarize com o peso médio
tbb1 %>%
group_by(setor) %>%
summarise("peso medio"=mean(peso)) %>%
ungroup()
LS0tDQp0aXRsZTogIm1pbmljdXJzbyB0aWR5dmVyc2UgLSBJViBTRVIgIg0KYXV0aG9yOiAiTGVvbmksIFIuIEMuIFByb2YuIERyLiINCm91dHB1dDogDQogIGh0bWxfbm90ZWJvb2s6IA0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIHRoZW1lOiBqb3VybmFsDQogICAgdG9jOiB5ZXMNCi0tLQ0KDQojIEludHJvZHXDp8OjbyBhbyBUaWR5dmVyc2U6IHRpYmJsZSBlIGRwbHlyDQoNCiMgQXVsYSAxIOKAkyBSZWNvbWVuZGHDp8O1ZXMNCg0KICAgIE9iamV0aXZvOiBpbnN0YWxhciBvcyBwYWNvdGVzIG5lY2Vzc8Ohcmlvcw0KDQpgYGB7cn0NCiMgbyBzw61tYm9sbyAjIG5vIGluw61jaW8gZGEgbGluaGEgaW5kaWNhIHF1ZSB0ZW1vcyB1bSBjb21lbnTDoXJpbw0KIyBlc3NhIGxpbmhhIGRlIGNvbWVudMOhcmlvIG7Do28gw6kgZXhlY3V0YWRhIHF1YW5kbyBkZXIgbyBjb21hbmRvIHJ1biAoY3RybCtlbnRlcikNCg0KDQojUGFyYSBpbnN0YWxhciBvIHBhY290ZSAoc29tZW50ZSAxIHZleikNCiNpbnN0YWxsLnBhY2thZ2VzKCJ0aWR5dmVyc2UiKQ0KDQojQ29tbyBvIHRpZHl2ZXJzZSDDqSB1bSBwYWNvdGUgcXVlIGNvbnTDqW0gdsOhcmlvIHBhY290ZXMsIHBvZGVtb3MNCiNUZXIgbyBtZXNtbyBlZmVpdG8gc2UgaW5zdGFsYXJtb3Mgb3Mgc2VndWludGVzIHBhY290ZXMNCiNVbSBwb3IgVW0gLg0KDQojIGluc3RhbGwucGFja2FnZXMoYygNCiMgICJicm9vbSIsICJkcGx5ciIsICJmZWF0aGVyIiwNCiMgICJmb3JjYXRzIiwiZ2dwbG90MiIsICJoYXZlbiIsDQojICAiaHR0ciIsICJobXMiLCAianNvbmxpdGUiLA0KIyAgImx1YnJpZGF0ZSIsICJtYWdyaXR0ciIsDQojICAibW9kZWxyIiwgInB1cnJyIiwgInJlYWRyIiwNCiMgICJyZWFkeGwiLCAic3RyaW5nciIsICJ0aWJibGUiLA0KIyAgInJ2ZXN0IiwgInRpZHlyIiwgInhtbDIiDQojKSkNCg0KI0xlbWJyYW5kbyBxdWUgbsOjbyDDqSBwcmVjaXNvIGluc3RhbGFyIHRvZG9zIGVzc2VzIHBhY290ZXMNCiNTZSBpbnRhbGFybW9zIG8gdGlkeXZlcnNlIGrDoSB2YW1vcyBvYmV0w6otbG9zIHRvZG9zLg0KDQojUGFyYSBjYXJyZWdhciBvIHBhY290ZSAoc2VtcHJlIHF1ZSBmb3IgdXPDoS1sbykNCmxpYnJhcnkodGlkeXZlcnNlKSAgI091IHJlcXVpcmUodGlkeXZlcnNlKQ0KDQojUGFyYSBmaW5hbGl6YXIgZXN0YSBhdWxhLCBhc3Npc3RhIG8gdsOtZGVvDQpicm93c2VVUkwoImh0dHBzOi8veW91dHUuYmUvZHZrRldtNlRoNTQiKQ0KDQojUGFyYWLDqW5zLCB2b2PDqiBjb21wbGV0b3UgYSBwcmltZWlyYSBhdWxhIQ0KDQpgYGANCg0KIyBBdWxhIDIg4oCTIFRpYmJsZQ0KDQogICAgT2JqZXRpdm86IGFwcmVzZW50YXIgYSBlc3RydXR1cmEgdGliYmxlDQoNCmBgYHtyfQ0KIzEpSW5zdGFsYW5kbyBPIFBhY290ZSBUaWJibGUNCiNpbnN0YWxsLnBhY2thZ2VzKCJ0aWJibGUiKQ0KDQojMilDaGFtYW5kbyBvIFBhY290ZSBUaWJibGUNCiNsaWJyYXJ5KHRpYmJsZSkNCg0KIzMpTyBUaWJibGUgc28gbW9zdHJhIGFzIDEwIHByaW1laXJhcyBsaW5oYXMNCnRpYmJsZSh4PTE6MTAwLCB5PTEwMDoxLCB6PXJlcCgiQSIsMTAwKSkgDQoNCiM0KU1vbnRhbmRvIHRyaWJibGUgbGluaGEgcG9yIGxpbmhhDQp0cmliYmxlKA0KICB+eCx+eSx+eiwNCiAgMTAsIDIwLCJBIiwNCiAgMjAsIDMwLCJCIiwNCiAgNDAsIDUwLCJDIiANCiAgKQ0KDQojNClMZW5kbyBEYXRhLmZyYW1lIGNvbW8gdGliYmxlDQogIERGPWRhdGEuZnJhbWUoTm9tZT1jKCdSYWZhZWxhJywnRmVsaXBlJywnUm9kb2xmbycpLElkYWRlPWMoMTgsMTQsMjApLE5vdGE9YygxMCw2LDgpKQ0KICBERlQ9YXNfdGliYmxlKERGKQ0KICBERlQNCg0KI0NvbWFuZG9zIGV4dHJhcw0KIzUpQ3JpYW5kbyBUaWJibGUgY29tIG5vbWVzIGRlIGNvbHVuYXMgbmFkYSBjb252ZW5jaW9uYWlzDQogIHRpYmJsZSgNCiAgICc6KScgPSAnc2ltaWxlJywgI0RpZmVyZW50ZSBkbyBEYXRhLmZyYW1lLCBwb2RlbW9zIHVzYXIgc2ltYm9sb3MgY29tbyBub21lIGRlIGNvbHVuYXNzDQogICAgJyAnICA9IDE6NCwgDQogICAgeCAgICA9IDU6MiwNCiAgIHkgICAgPXgrMQ0KICApDQoNCiM2KVBvZGVtb3MgbW9kaWZpY2FyIGEgUXVhbnRpZGFkZSBEZSBsaW5oYXMgcXVlIHZpc3VhbGl6YW1vcw0KI1BvciBwYWRyw6NvIG8gc2lzdGVtYSB0aWR5IGV4aWJlIDEwIGxpbmhhcywgbWFzIHBvZGVtb3MgbW9kaWZpY2FyIGVzdGEgb3DDp8Ojbw0KICBtPTMwDQogIG49MjANCiAgb3B0aW9ucyh0aWJibGUucHJpbnRfbWF4ID0gbSwgdGliYmxlLnByaW50X21pbiA9IG4pIA0KICAjT3Ugc2VqYTpTZSBwYXNzYXIgZGUgJ20nIGxpbmhhcywgcHJpbnRhciAnbicgbGluaGFzKSApDQogICNQb2RlbW9zIHVzYXIgJ3RpYmJsZS5wcmludF9taW4gPSBJbmYnIHBhcmEgcHJpbnRhciB0b2RhcyBhcyBsaW5oYXMNCiAgdGliYmxlKHg9MToxMDAsIHk9MTAwOjEsIHo9cmVwKCJBIiwxMDApKQ0KICANCiNPdSBjb2xvcXVlIGEgb3DDp8OjbyBjb21vIGFyZ3VtZW50bw0KICB0aWJibGUoeD0xOjEwMCwgeT0xMDA6MSwgej1yZXAoIkEiLDEwMCksIG9wdGlvbnModGliYmxlLnByaW50X21pbiA9IDE1KSkNCiAgDQojNylBY2Vzc2FuZG8gcGFydGVzIGRvIHRpYmJsZQ0KICB0PXRpYmJsZSgNCiAgICB4PTE6NSwNCiAgICB5PXgrMSwNCiAgICB6PXheMit5DQogICkNCiAgdA0KICB0JHggI01vc3RyYSBhIGNvbHVuYSBYKG91IHRbWyd4J11dKQ0KICB0W1syLDNdXSAgI0xpbmhhMixDb2x1bmEzDQoNCmBgYA0KDQoNCiMgQXVsYSAzIOKAkyBTZWxlY3QgZSBEaXN0aW5jdA0KDQogICAgT2JqZXRpdm86IG1hbmlwdWxhciBjb2x1bmFzIGRlIHVtYSB0YWJlbGEgZGUgZGFkb3MgKHRpYmJsZSkNCg0KYGBge3J9DQpsaWJyYXJ5KG55Y2ZsaWdodHMxMykNCmZsaWdodHMNCnNlbGVjdChmbGlnaHRzLGRlcF90aW1lLCBhcnJfZGVsYXkpDQpzZWxlY3QoZmxpZ2h0cywgImRlcF90aW1lIiwgImFycl9kZWxheSIpDQoNCnNlbGVjdChmbGlnaHRzLCAtZGF5LCAtZGVwX3RpbWUpDQoNCnNlbGVjdChmbGlnaHRzLCBkZXBfdGltZTphcnJfZGVsYXkpDQoNCnNlbGVjdChmbGlnaHRzLCAzOjkpDQoNCnNlbGVjdChmbGlnaHRzLCBzdGFydHNfd2l0aCgiYXJyIikpDQoNCnNlbGVjdChmbGlnaHRzLCBlbmRzX3dpdGgoInRpbWUiKSkNCg0Kc2VsZWN0KGZsaWdodHMsIGNvbnRhaW5zKCJkZXAiKSkNCg0Kc2VsZWN0KGZsaWdodHMsIHRpbWVfaG91ciwgYWlyX3RpbWUsIGV2ZXJ5dGhpbmcoKSkNCg0KI3Jlbm9tZWFyDQpmbGlnaHRzIDwtIHNlbGVjdChmbGlnaHRzLHgxPXllYXIsIHgyPWRlcF90aW1lLCB4Mz1hcnJfZGVsYXksIGV2ZXJ5dGhpbmcoKSAgKQ0KDQpzZWxlY3QoZmxpZ2h0cywgbnVtX3JhbmdlKCJ4IiwgMTozKSkNCg0KIyBEaXN0aW5jDQoNCmRpc3RpbmN0KGZsaWdodHMsIGRheSkNCmBgYA0KDQoNCg0KIyBBdWxhIDQg4oCTIEZpbHRlciwgQXJyYW5nZSwgY291bnQgZSBwaXBlIA0KDQogICAgT2JqZXRpdm86IGZpbHRyYXIsIGFycnVtYXIgZSBjb250YXIgb2JzZXJ2YcOnw7VlcyBkZSB1bWEgdGFiZWxhIGRlIGRhZG9zDQoNCmBgYHtyfQ0KIyMgZmlsdGVyLCBhcnJhbmdlLCBjb3VudCBlIHBpcGUNCg0KIyMgQ2FycmVnYW5kbyBvIHBhY290ZSBlIG9zIGRhZG9zDQoNCiMgUGFyYSBjYXJyZWdhciBvIHBhY290ZSBwb2RlbW9zIHV0aWxpemFyDQoNCnJlcXVpcmUodGlkeXZlcnNlKSANCiMgQXMgZnVuw6fDtWVzIHPDo28gZG8gcGFjb3RlIGRwbHlyOiByZXF1aXJlKGRwbHlyKQ0KDQojIFRhYmVsYSBkZSBkYWRvczoNCg0Kc3RhcndhcnMNCg0KIyMgVXRpbGl6YW5kbyBhIGZ1bsOnw6NvIGZpbHRlcg0KDQojIyBVdGlsaXphbmRvIGNvbXBhcmFkb3JlcyBsw7NnaWNvczoNCiMgbWFpb3IsIG1lbm9yLCBtYWlvciBvdSBpZ3VhbCwgbWVub3Igb3UgaWd1YWwsIGlndWFsIGUgZGlmZXJlbnRlDQoNCmZpbHRlcihzdGFyd2FycywgaGVpZ2h0ID4gMTYwKQ0KZmlsdGVyKHN0YXJ3YXJzLCBoZWlnaHQgPD0gMTUwKQ0KZmlsdGVyKHN0YXJ3YXJzLCBoZWlnaHQgPT0gNzkpDQoNCiMgVsOtcmd1bGEgZnVuY2lvbmEgY29tbyAnRScgKCYpDQoNCmZpbHRlcihzdGFyd2Fycywgc3BlY2llcyA9PSAiRHJvaWQiLCBob21ld29ybGQgPT0gIlRhdG9vaW5lIiwgc2tpbl9jb2xvciA9PSAiZ29sZCIpDQoNCiMgVXRpbGl6YW5kbyBvcGVyYWRvciBPVSAofCkNCg0KZmlsdGVyKHN0YXJ3YXJzLCBoZWlnaHQgPiAxODUgfCBleWVfY29sb3IgPT0gImJsdWUiKQ0KDQojIyBVdGlsaXphbmRvIGEgZnVuw6fDo28gYXJyYW5nZQ0KDQojIE9yZGVtIGNyZXNjZW50ZQ0KYXJyYW5nZShzdGFyd2FycywgbWFzcykNCg0KIyBPcmRlbSBkZWNyZXNjZW50ZQ0KYXJyYW5nZShzdGFyd2FycywgZGVzYyhtYXNzKSkNCiMgT3UgZW50w6NvDQphcnJhbmdlKHN0YXJ3YXJzLCAtbWFzcykNCg0KIyBNYWlzIGRlIHVtYSB2YXJpw6F2ZWwNCg0KYXJyYW5nZShzdGFyd2FycywgbWFzcywgLWJpcnRoX3llYXIpDQoNCiMjIFV0aWxpemFuZG8gYSBmdW7Dp8OjbyBjb3VudA0KDQojIEFwZW5hcyB1bWEgdmFyacOhdmVsDQpjb3VudChzdGFyd2FycywgZ2VuZGVyKQ0KY291bnQoc3RhcndhcnMsIHNwZWNpZXMpDQoNCiMgTWFpcyBkZSB1bWEgdmFyacOhdmVsDQpjb3VudChzdGFyd2FycywgaGFpcl9jb2xvciwgZXllX2NvbG9yKQ0KDQojI1V0aWxpemFuZG8gbyBvcGVyYWRvciBQaXBlOiAlPiUgKEN0cmwgKyBTaGlmdCArIE0pDQoNCmZpbHRlcihzdGFyd2FycyxzcGVjaWVzID09ICJIdW1hbiIpICU+JSANCiAgc2VsZWN0KGNvbnRhaW5zKCJjb2xvciIpKQ0KDQpzdGFyd2FycyAlPiUgDQogIGZpbHRlcihzcGVjaWVzID09ICJIdW1hbiIpICU+JSANCiAgY291bnQoZXllX2NvbG9yKSAlPiUgDQogIGFycmFuZ2UoLW4pDQoNCg0KYGBgDQoNCg0KIyBBdWxhIDUg4oCTIE11dGF0ZSBlIHRyYW5zbXV0ZQ0KDQogICAgT2JqZXRpdm86IGNyaWFyIG5vdmFzIGNvbHVuYXMgZW0gdW0gdGliYmxlDQoNCmBgYHtyfQ0KIyMgTXV0YXRlIGUgVHJhbnNtdXRlDQoNCiMjIENhcnJlZ2FuZG8gbyBwYWNvdGUgZSBvcyBkYWRvcw0KDQojIFBhcmEgY2FycmVnYXIgbyBwYWNvdGUgcG9kZW1vcyB1dGlsaXphcg0KcmVxdWlyZSh0aWR5dmVyc2UpDQoNCiNBcyBmdW7Dp8O1ZXMgc8OjbyBkbyBwYWNvdGUgZHBseXI6IHJlcXVpcmUoZHBseXIpDQoNCiMgVGFiZWxhIGRlIGRhZG9zDQpjYXJzDQoNCiMjIFV0aWxpemFuZG8gYSBmdW7Dp8OjbyBtdXRhdGUNCmNhcnMgJT4lIA0KICBtdXRhdGUoZGlzdDIgPSBkaXN0KjIpDQoNCiMjIyBNdXRhdGUgZSBpZmVsc2UNCmNhcnMgJT4lIA0KICBtdXRhdGUoY2xhc3NlX3NwZWVkID0gaWZlbHNlKHNwZWVkID4gMTAsICJBIiwiQiIpKQ0KDQojIyMgT3BlcmFkb3IgJWluJQ0KY2FycyAlPiUgDQogIG11dGF0ZShjbGFzc2VfZGlzdCA9IGlmZWxzZShkaXN0ICVpbiUgMTA6MjAsICJBIiwiQiIpKQ0KDQojIyBVdGlsaXphbmRvIGEgZnVuw6fDo28gVHJhbnNtdXRlDQpjYXJzICU+JSANCiAgdHJhbnNtdXRlKGNsYXNzZV9zcGVlZCA9IGlmZWxzZShzcGVlZCA+IDEwLCJBIiwiQiIpKQ0KDQpjYXJzICU+JSANCiAgdHJhbnNtdXRlKHRlbXBvID0gc3BlZWQgKiBkaXN0LCANCiAgICAgICAgICAgIGNsYXNzZV9zcGVlZCA9IGlmZWxzZShzcGVlZCA+IDEwLCJBIiwiQiIpKQ0KDQpgYGANCg0KDQojIEF1bGEgNiDigJMgU3VtbWFyaXNlLCBncm91cF9ieSBlIG5fZGlzdGluY3QNCg0KICAgIE9iamV0aXZvOiBvcGVyYXIgc29icmUgbGluaGFzIGUgY29sdW5hcyBkZSB1bSB0aWJibGUNCg0KYGBge3J9DQojIyBzdW1tYXJpc2UsIGdyb3VwX2J5LCBuX2Rpc3RpbmN0DQoNCiMjIENhcnJlZ2FuZG8gcGFjb3RlcyANCg0KIyBkcGx5ciBvdSB0aWR5dmVyc2UNCg0KIyBpbnN0YWxsLnBhY2thZ2VzKCJkcGx5ciIpDQpyZXF1aXJlKGRwbHlyKQ0KIyBpbnN0YWxsLnBhY2thZ2VzKCJ0aWR5dmVyc2UiKQ0KcmVxdWlyZSh0aWR5dmVyc2UpDQojIGluc3RhbGwucGFja2FnZXMoIm55Y2ZsaWdodHMxMyIpICMgUGFjb3RlIGNvbSBvcyBkYWRvcw0KcmVxdWlyZShueWNmbGlnaHRzMTMpDQoNCiMgVGFiZWxhIGNvbSBkYWRvcw0KZmxpZ2h0cw0KDQojIyBFc3RhdMOtc3RpY2FzLCBtZWRpYSwgbWVkaWFuYSwgbWF4LCBtaW4uLi4NCmZsaWdodHMgJT4lIA0KICBzdW1tYXJpc2UoVGVtcG9fdm9vX21lZGlvID0gbWVhbihhaXJfdGltZSwgbmEucm0gPSBUKSwNCiAgICAgICAgICAgIE1haW9yRGlzdGFuY2lhID0gbWF4KGRpc3RhbmNlKSkgDQoNCiMgUG9kZW1vcyBmYXplciB1bWEgc3VtYXJpemHDp8Ojbw0KZmxpZ2h0cyAlPiUgDQogIGdyb3VwX2J5KHllYXIsIG1vbnRoLCBkYXkpICU+JSANCiAgc3VtbWFyaXNlKE1lbm9yRGlzdGFuY2lhID0gbWluKGRpc3RhbmNlKSwNCiAgICAgICAgICAgIE1haW9yRGlzdGFuY2lhID0gbWF4KGRpc3RhbmNlKSkNCg0KIyMgQ29udGFnZW0NCiMgbigpIChudW1lcm8gdG90YWwgZGUgZWxlbWVudG9zKQ0KZmxpZ2h0cyAlPiUgDQogIGdyb3VwX2J5KHllYXIsIG1vbnRoLCBkYXkpICU+JSANCiAgc3VtbWFyaXNlKFZvb3NQb3JEaWEgPSBuKCkpDQoNCiMgbl9kaXN0aW5jdCAoRWxlbWVudG9zIGRpc3RpbnRvcykNCmZsaWdodHMgJT4lIA0KICBncm91cF9ieShkZXN0KSAlPiUgDQogIHN1bW1hcmlzZShRdWFudENvbXAgPSBuX2Rpc3RpbmN0KGNhcnJpZXIpKSAlPiUgDQogIGFycmFuZ2UoZGVzYyhRdWFudENvbXApKSAjb3JkZW5hbmRvDQoNCmV4IDwtIGZsaWdodHMgJT4lIA0KICBmaWx0ZXIob3JpZ2luID09ICJKRksiLCBkZXN0ID09ICJBVEwiKSAlPiUgDQogIGdyb3VwX2J5KGNhcnJpZXIpICU+JSANCiAgc3VtbWFyaXNlKG1lZGlhID0gbWVhbihhaXJfdGltZSwgbmEucm0gPSBUKSkNCg0KIyMgRGVzYWdydXBhbmRvDQpleCAlPiUNCiAgdW5ncm91cCgpICU+JQ0KICBzdW1tYXJpc2UobWVhbihtZWRpYSkpDQogIA0KDQpgYGANCg0KIyBBdWxhIDcg4oCTIEpvaW5zDQoNCiAgICBPYmpldGl2bzogdW5pciBhdHJhdsOpcyBkZSBjaGF2ZSBjb211bSBkb2lzIHRpYmJsZXMNCg0KYGBge3J9DQojIGlubmVyX2pvaW4gZSBsZWZ0X2pvaW4NCg0KIyBDYXJyZWdhbmRvIG8gcGFjb3RlIA0KDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCg0KIyBvdSBsaWJyYXJ5KGRwbHlyKQ0KDQojIEJhc2UgZGUgZGFkb3MgDQoNCnggPC0gdHJpYmJsZSgNCiAgfkNoYXZlLCB+dmFsb3JfeCwNCiAgMSwgIngxIiwNCiAgMiwgIngyIiwNCiAgMywgIngzIg0KKQ0KDQp5IDwtIHRyaWJibGUoDQogIH5DaGF2ZSwgfnZhbG9yX3ksDQogIDEsICJ5MSIsDQogIDIsICJ5MiIsDQogIDQsICJ5MyINCikNCg0KI0lubmVyX2pvaW46IHVuZSBjb20gYmFzZSBuYSBpbnRlcnNlw6fDo28sIHR1ZG8gcXVlIGNvaW5jaWRlIG5hcyBkdWFzIGJhc2VzIHggZSB5DQoj4oCiTGVmdF9qb2luOiB1bmUgw6AgZXNxdWVyZGEsIHR1ZG8gZGUgeCBxdWUgY29pbmNpZGUgY29tIHkNCiPigKJSaWdodF9qb2luOiB1bmUgw6AgZGlyZWl0YSwgdHVkbyBkZSB5IHF1ZSBjb2luY2lkZSBjb20geA0KI+KAokZ1bGxfam9pbjogdW5lIGNvbSBiYXNlIG5hIHVuacOjbywgdHVkbyBkZSB4IG91IHkNCg0KIyBpbm5lcl9qb2luIChKdW50YSBhcyBvYnNlcnZhw6fDtWVzIHF1YW5kbyBjaGF2ZXMgbmFzIGR1YXMgYmFzZXMgc8OjbyBpZ3VhaXMpDQoNCmlubmVyX2pvaW4oeCwgeSwgYnkgPSAiQ2hhdmUiKQ0KDQojIGxlZnRfam9pbiAoTWFudGVtIHRvZGFzIGFzIG9ic2VydmHDp8O1ZXMgZGUgeCkNCg0KbGVmdF9qb2luKHgsIHksIGJ5ID0gIkNoYXZlIikNCg0KIyByaWdodF9qb2luIChNYW50ZW0gdG9kYXMgYXMgb2JzZXJ2YcOnw7VlcyBkZSB5KQ0KDQpyaWdodF9qb2luKHgsIHksIGJ5ID0gIkNoYXZlIikNCg0KIyBmdWxsX2pvaW4gKE1hbnRlbSB0b2RhcyBhcyBvYnNlcnZhw6fDtWVzIGRlIHggZSB5KQ0KDQpmdWxsX2pvaW4oeCwgeSwgYnkgPSAiQ2hhdmUiKQ0KDQoNCg0KYGBgDQoNCg0KIyBBdWxhIDgg4oCTIEV4ZXJjw61jaW8gMQ0KICAgIA0KICAgIE9iamV0aXZvOiBwcmF0aWNhciBjb21hbmRvcyBkbyBwYWNvdGUgZHBseXINCg0KDQpBYnJhIHVtIHNjcmlwdCBubyBSc3R1ZGlvIHBhcmEgcmVhbGl6YXIgZXN0ZXMgZXhlcmPDrWNpb3MNClVzYXJlbW9zIGEgYmFzZSBkZSBkYWRvcyBzdGFyd2FycyBkbyBwYWNvdGUgZHBseXINCuKAojEtUXVhbnRhcyBzcGVjaWVzIGRpc3RpbnRhcyBow6EgbmEgYmFzZSBkZSBkYWRvcz8NCuKAojItU2VsZWNpb25lIHRvZGFzIGFzIG9ic2VydmHDp8O1ZXMgZGEgc3BlY2llcyDigJxIdW1hbuKAnQ0K4oCiMy1TZWxlY2lvbmUgbyBuYW1lIGUgaGFpcl9jb2xvciBkZSB0b2RhcyBhcyBvYnNlcnZhw6fDtWVzIGRhIHNwZWNpZXMg4oCcSHVtYW7igJ0NCuKAojQtRmHDp2EgdW0gYWdydXBhbWVudG8gZGEgYmFzZSBkZSBkYWRvcyBjb25zaWRlcmFuZG8gYXBlbmFzIHNwZWNpZXMg4oCcSHVtYW7igJ0sIGRlIGFjb3JkbyBjb20gZ2VuZGVyIGUgcmVzdW1pbmRvIHBhcmEgY2FkYSBnZW5kZXIgYSBhbHR1cmEgbcOpZGlhIChoZWlnaHQpDQoNCmBgYHtyfQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpzdGFyd2Fycw0KDQojMS1RdWFudGFzIHNwZWNpZXMgZGlzdGludGFzIGjDoSBuYSBiYXNlIGRlIGRhZG9zPw0Kc3RhcndhcnMgJT4lIA0KICBzZWxlY3Qoc3BlY2llcykgJT4lIA0KICBuX2Rpc3RpbmN0KCkNCg0KIzItU2VsZWNpb25lIHRvZGFzIGFzIG9ic2VydmHDp8O1ZXMgZGEgc3BlY2llcyBIdW1hbg0Kc3RhcndhcnMgJT4lIA0KICBmaWx0ZXIoc3BlY2llcyA9PSAiSHVtYW4iKSANCg0KIzMtU2VsZWNpb25lIG8gbmFtZSBlIGhhaXJfY29sb3IgZGUgdG9kYXMgYXMgb2JzZXJ2YcOnw7VlcyBkYSBzcGVjaWVzIEh1bWFuDQoNCnN0YXJ3YXJzICU+JSANCiAgZmlsdGVyKHNwZWNpZXMgPT0gIkh1bWFuIikgJT4lIA0KICBzZWxlY3QobmFtZSwgaGFpcl9jb2xvcikNCg0KIzQtRmHDp2EgdW0gYWdydXBhbWVudG8gZGEgc3BlY2llcyBIdW1hbiBwb3IgZ2VuZGVyIGUgcmVzdW1hIHBlbGEgbcOpZGlhIGRhIGFsdHVyYSAoaGVpZ2h0KQ0Kc3RhcndhcnMgJT4lIA0KICBmaWx0ZXIoc3BlY2llcyA9PSAiSHVtYW4iKSAlPiUgDQogIGdyb3VwX2J5KGdlbmRlcikgJT4lIA0KICBzdW1tYXJpc2UobWVkaWE9bWVhbihoZWlnaHQsIG5hLnJtPVQpKQ0KYGBgDQoNCg0KIyBBdWxhIDkg4oCTIEV4ZXJjw61jaW8gMg0KDQogICAgT2JqZXRpdm86IHByYXRpY2FyIGNvbWFuZG9zIGRvIHBhY290ZSBkcGx5cg0KDQoNCuKAojEtQ3JpZSAyIHRpYmJsZXM6DQp0YmIxID0gdGliYmxlKCBzZXRvciA9IHJlcChjKCJGIiwgIk0iLCAiSSIpLCAyKSAsIHBlc28gPSBydW5pZig2LCA1MCwgMTAwKSkNCnRiYjIgPSB0aWJibGUoIHNldG9yID0gcmVwKGMoIkkiKSwyKSAsIGFsdHVyYSA9IGMoMTY3LCAxODApDQrigKIyLSBVbmEgdGJiMSBlIHRiYjIgY29tIGEgZnVuw6fDo28gaW5uZXJfam9pbg0K4oCiMy0gVW5hIHRiYjEgZSB0YmIyIGNvbSBhIGZ1bsOnw6NvIGZ1bGxfam9pbg0K4oCiNC0gVW5hIHRiYjEgZSB0YmIyIGNvbSBhIGZ1bsOnw6NvIGxlZnRfam9pbg0K4oCiNS0gVW5hIHRiYjEgZSB0YmIyIGNvbSBhIGZ1bsOnw6NvIHJpZ2h0X2pvaW4NCuKAojYtIE9yZGVuZSBvIHRiYjEgcG9yIG9yZGVtIGNyZXNjZW50ZSBkbyBwZXNvDQrigKI3LSBBZ3J1cGUgdGJiMSBwb3Igc2V0b3IgZSBzdW1hcml6ZSBjb20gbyBwZXNvIG3DqWRpbw0KDQpgYGB7cn0NCiMxLUNyaWUgMiB0aWJibGVzOg0KdGJiMSA9IHRpYmJsZSggc2V0b3IgPSByZXAoYygiRiIsICJNIiwgIkkiKSwgMikgLCBwZXNvID0gcnVuaWYoNiwgNTAsIDEwMCkpDQp0YmIyID0gdGliYmxlKCBzZXRvciA9IHJlcChjKCJJIiksMikgLCBhbHR1cmEgPSBjKDE2NywgMTgwKSApDQogICAgICAgICAgICAgIA0KIyAyLSBVbmEgdGJiMSBlIHRiYjIgY29tIGEgZnVuw6fDo28gaW5uZXJfam9pbiANCiAgICAgICAgICAgICAgIA0KdGJiMQ0KdGJiMg0KaW5uZXJfam9pbih0YmIxLCB0YmIyLCBjaGF2ZT0ic2V0b3IiKQ0KDQojMy0gVW5hIHRiYjEgZSB0YmIyIGNvbSBhIGZ1bsOnw6NvIGZ1bGxfam9pbg0KDQpmdWxsX2pvaW4odGJiMSx0YmIyLGNoYXZlPSJzZXRvciIpDQoNCiM0LSBVbmEgdGJiMSBlIHRiYjIgY29tIGEgZnVuw6fDo28gbGVmdF9qb2luDQoNCmxlZnRfam9pbih0YmIxLHRiYjIsY2hhdmU9InNldG9yIikNCg0KIzUtIFVuYSB0YmIxIGUgdGJiMiBjb20gYSBmdW7Dp8OjbyByaWdodF9qb2luIA0KDQpyaWdodF9qb2luKHRiYjEsdGJiMixjaGF2ZT0ic2V0b3IiKQ0KDQojNi0gT3JkZW5lIG8gdGJiMSBwb3Igb3JkZW0gY3Jlc2NlbnRlIGRvIHBlc28NCg0KdGJiMSAlPiUgYXJyYW5nZShwZXNvKQ0KDQojNy0gQWdydXBlIHRiYjEgcG9yIHNldG9yIGUgc3VtYXJpemUgY29tIG8gcGVzbyBtw6lkaW8NCg0KdGJiMSAlPiUgDQogIGdyb3VwX2J5KHNldG9yKSAlPiUgDQogIHN1bW1hcmlzZSgicGVzbyBtZWRpbyI9bWVhbihwZXNvKSkgJT4lIA0KICB1bmdyb3VwKCkNCmBgYA0KDQoNCg==