Neste tutorial, veremos algumas funções úteis para trabalhar com dados da COVID-19 na prática, a partir do repositório da Johns Hopkins University.
Vamos assumir conhecimento básico de R e usaremos o pacote tidyverse.
library(tidyverse)
[30m── [1mAttaching packages[22m ───────────────────────────────────────────────────────────────── tidyverse 1.2.1 ──[39m
[30m[32m✓[30m [34mggplot2[30m 3.2.1 [32m✓[30m [34mpurrr [30m 0.3.3
[32m✓[30m [34mtibble [30m 2.1.3 [32m✓[30m [34mdplyr [30m 0.8.5
[32m✓[30m [34mtidyr [30m 1.0.2 [32m✓[30m [34mstringr[30m 1.4.0
[32m✓[30m [34mreadr [30m 1.3.1 [32m✓[30m [34mforcats[30m 0.4.0[39m
[30m── [1mConflicts[22m ──────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
[31mx[30m [34mdplyr[30m::[32mfilter()[30m masks [34mstats[30m::filter()
[31mx[30m [34mdplyr[30m::[32mlag()[30m masks [34mstats[30m::lag()[39m
Importando os dados
O primeiro passo é baixar os dados e entender a sua estrutura.
# Vamos chamar o link com o CSV de "url"
url = 'https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_time_series/time_series_covid19_confirmed_global.csv'
# Agora, importamos o CSV no R...
dados = read.csv(url)
#... e o visualizamos
dados
Podemos ver que temos os seguintes campos:
- Province.State (província, por exemplo, Guiana Francesa)
- Country.Region (país, por exemplo, França)
- Lat (latitude)
- Long (longitude)
- E na sequência temos várias datas, registrando a série histórica de cada país. Cada dia é uma coluna.
Você pode navegar pela tabela utilizando a páginação acima.
Filtrando dados
Filtrar os registros é bem fácil. Abaixo, vamos criar um novo conjunto de dados (df) filtrando apenas os registros com Espanha e Itália no campo Country.Region. Depois, vamos excluir as colunas Province.State, Lat e Long, que não nos interessam.
Repare que podemos selecionar as colunas que não queremos com o sinal de negativo (-) com o comando select. Usaremos esse recurso novamente no comando seguinte. Repare também que a barra em pé (|) significa o operador “OU”.
df <- dados %>% filter(Country.Region == 'Italy' | Country.Region == 'Spain') %>%
select(-Province.State,-Lat,-Long)
df
Transformando textos em datas
Legal! Agora, precisamos definir que o campo “dia” deve ser encarado como uma data. Repare bem no padrão da data na tabela acima.
Ela é uma sequência de caraceteres (indicado pela sigla “chr” no cabeçalho). A primeira coisa que faremos é tirar este “X” e depois formatar a coluna como data.
Primeiro, vamos usar uma função para substituir (replace) uma sequência de caracteres (string ou str), a função str_replace. Com ela, vamos trocar no campo “dia” do banco de dados “df” qualquer ocorrência de X por uma sequência vazia, Ou seja, na prática, removeremos todos os “X”.
Depois, vamos mudar o campo para o formato de data. O ponto significa que pegaremos o resultado da operação anterior, ou seja, os números das datas sem o X. Também vamos explicitar o formato data que é mês (%m), dia (%d) e ano (%y) - separados por um ponto.
df$dia <- str_replace(df$dia,"X", "") %>%
as.Date(.,format='%m.%d.%y')
# Vamos checar se funcionou vendo o dia mais recente, já no formato correto
max(df$dia)
[1] "2020-04-02"
Agora, conseguimos visualizar os registros ordenados por data. Repare na tabela abaixo que agora o dia aparece como “date” o/
df %>% arrange(dia)
Identificando o dia zero
Uma métrica bastante comum em análise de epidemias é a contagem de quantos dias se passaram desde determinado limar de casos. Isso facilita a comparação de fenômenos que ocorreram em datas distintas.
Abaixo, vamos adicionar uma nova coluna que conte quantos dias se passaram desde o centésimo caso nos dois países. O primeiro dia que a Itália registrou mais que 100 casos foi dia 23 de fevereiro, enquanto na Espanha foi apenas no dia 2 de março.
df <- df %>%
# A ordem das datas é fundamental, então, vamos ordenar os dados por dia
arrange(dia) %>%
# E filtra os registros menores que 100. Você pode trocar por qualquer outro valor.
# Troque por 0 para pegar todos os dias desde o primeiro caso.
filter(casos > 100) %>%
# Então, vamos usar o group_by para que a operação a seguir seja feita para cada país (Country.Region)
group_by(Country.Region) %>%
# Vamos definir o dia 0 como o menor dia daquele país
mutate(dia0 = min(dia))
df
Contagem de dias
Já sabemos a data de registro e a data do primeiro caso, para cada registro de nossa tabela. Agora, está fácil calcularmos a diferença entre os dias. Assim, podemos analisar como cada país estava uma semana após a passar o limiar do centésimo caso, por exemplo.
Vamos criar uma nova variável (conta_dia) que vai ser o resultado da diferença entre a data de registro (dia) e o dia 0 (dia0) em dias.
# Vamos adicionar o novo campo
df$conta_dia <- difftime(df$dia,df$dia0,units = "days")
# E visualizar os dados ordernados por ele
df %>% arrange(conta_dia)
Calculando o número de casos novos por dia
Repare que a coluna “casos” traz o total de casos acumulado até a data especificada no campo “dia”. Mas e se quisermos saber o número de novos casos por dia?
Vamos criar uma nova coluna chamada novos_casos, que será resultado do número de casos do dia menos o número de casos do dia anterior, em cada país.
df <- df %>%
# Vamos remover a coluna day0 pois ela não é mais necessária
select(-dia0) %>%
# Agrupamos por país
group_by(Country.Region) %>%
# Lembrando que nossos casos já estão ordenados por dia
# Então, utilizamos a função lag() para retornar o último valor daquela coluna
mutate(novos_casos = casos - lag(casos))
df
Calculando o aumento percentual
Vamos incrementar ainda mais. Agora vamos adicionar um novo campo que vai mostrar o aumento percentual no número acumulado de casos confirmados em cada dia.
Para relembrar, para calculá-la, pegamos o número de casos de um dia (casos), dividimos pelo total dia anterior (lag(casos)), diminuimos por 1 e então multiplicamos por 100 para obter a taxa percentual. E também vamos arredondar o resultado, usando a função round().
df <- df %>% mutate(aumento_percent = round((novos_casos/lag(casos)*100)))
df
Casos por milhão de habitantes
Ainda que seja amplamente utilizada por órgãos oficias e pela imprensa, alguns especialistas desencorajam o uso de taxas populacionais para avaliação da taxa de contágio nos estágios iniciais de uma pandemia. Isto pois o número de pessoas contagiadas por cada infectada não é alterada pelo tamanho da população, porém, à medida que a epidemia progride este número passa a ser útil. A taxa também pode ser um bom indicador se queremos avaliar o impacto na infra-estrutura de saúde, por exemplo, então, vamos ver como realizá-la. Para se aprofundar mais nesta discussão, vide o item 4.4.2 deste artigo ou esta matéria do The New York Times.
Aqui, vamos adicionar uma coluna com a população dos países. Como este é apenas um exemplo e temos só 2 casos, podemos usar condicional simples. Se o país for a Itália, inserimos a população de 60 milhões (60483538), se não, então, será a Espanha, que tem população de 46 milhões (46750337).
#
df <- df %>% mutate(populacao = ifelse(Country.Region == "Italy",60483538,46750337)) %>%
# Uma vez que você insira a coluna de população, o cálculo da taxa é simples
mutate(taxa = round((casos/populacao) * 1000000))
df
Bônus: plotando o resultado em gráfico
Este não é um tutorial de visualização de dados, mas depois de chegar aqui nós merecemos ver o resultado do trabalho em um gráfico. Então, vamos lá!
# Vamos usar o tema da The Economist para deixar o gráfico bonito :)
library(ggthemes)
grafico <- ggplot(df, aes(x=conta_dia,y=casos, group = Country.Region, colour = Country.Region)) +
geom_line() +
theme_economist_white() +
labs(caption = "Gráfico: Escola de Dados \n Dados: John Hopkins") +
labs(x = "Dias desde o centésimo caso", y = "Total de casos",
title = "Evolução dos casos confirmados de COVID-19")
grafico

LS0tCnRpdGxlOiAiRnVuw6fDtWVzIMO6dGVpcyBwYXJhIG9yZ2FuaXphciBkYWRvcyBkYSBDT1ZJRC0xOSIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKTmVzdGUgdHV0b3JpYWwsIHZlcmVtb3MgYWxndW1hcyBmdW7Dp8O1ZXMgw7p0ZWlzIHBhcmEgdHJhYmFsaGFyIGNvbSBkYWRvcyBkYSBDT1ZJRC0xOSBuYSBwcsOhdGljYSwgYSBwYXJ0aXIgZG8gcmVwb3NpdMOzcmlvIGRhIFtKb2hucyBIb3BraW5zIFVuaXZlcnNpdHldKGh0dHBzOi8vZ2l0aHViLmNvbS9DU1NFR0lTYW5kRGF0YS9DT1ZJRC0xOSkuCgpWYW1vcyBhc3N1bWlyIGNvbmhlY2ltZW50byBiw6FzaWNvIGRlIFIgZSB1c2FyZW1vcyBvIHBhY290ZSBgdGlkeXZlcnNlYC4KCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKYGBgCgoKIyBJbXBvcnRhbmRvIG9zIGRhZG9zCk8gcHJpbWVpcm8gcGFzc28gw6kgYmFpeGFyIG9zIGRhZG9zIGUgZW50ZW5kZXIgYSBzdWEgZXN0cnV0dXJhLgoKYGBge3J9CgojIFZhbW9zIGNoYW1hciBvIGxpbmsgY29tIG8gQ1NWIGRlICJ1cmwiCnVybCA9ICdodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vQ1NTRUdJU2FuZERhdGEvQ09WSUQtMTkvbWFzdGVyL2Nzc2VfY292aWRfMTlfZGF0YS9jc3NlX2NvdmlkXzE5X3RpbWVfc2VyaWVzL3RpbWVfc2VyaWVzX2NvdmlkMTlfY29uZmlybWVkX2dsb2JhbC5jc3YnCgojIEFnb3JhLCBpbXBvcnRhbW9zIG8gQ1NWIG5vIFIuLi4KZGFkb3MgPSByZWFkLmNzdih1cmwpCgojLi4uIGUgbyB2aXN1YWxpemFtb3MKZGFkb3MKYGBgCgogUG9kZW1vcyB2ZXIgcXVlIHRlbW9zIG9zIHNlZ3VpbnRlcyBjYW1wb3M6CgoqIFByb3ZpbmNlLlN0YXRlIChwcm92w61uY2lhLCBwb3IgZXhlbXBsbywgR3VpYW5hIEZyYW5jZXNhKQoqIENvdW50cnkuUmVnaW9uIChwYcOtcywgcG9yIGV4ZW1wbG8sIEZyYW7Dp2EpCiogTGF0IChsYXRpdHVkZSkKKiBMb25nIChsb25naXR1ZGUpCiogRSBuYSBzZXF1w6puY2lhIHRlbW9zIHbDoXJpYXMgZGF0YXMsIHJlZ2lzdHJhbmRvIGEgc8OpcmllIGhpc3TDs3JpY2EgZGUgY2FkYSBwYcOtcy4gQ2FkYSBkaWEgw6kgdW1hIGNvbHVuYS4KClZvY8OqIHBvZGUgbmF2ZWdhciBwZWxhIHRhYmVsYSB1dGlsaXphbmRvIGEgcMOhZ2luYcOnw6NvIGFjaW1hLgoKIyBGaWx0cmFuZG8gZGFkb3MKCkZpbHRyYXIgb3MgcmVnaXN0cm9zIMOpIGJlbSBmw6FjaWwuIEFiYWl4bywgdmFtb3MgY3JpYXIgdW0gbm92byBjb25qdW50byBkZSBkYWRvcyAoYGRmYCkgZmlsdHJhbmRvIGFwZW5hcyBvcyByZWdpc3Ryb3MgY29tIEVzcGFuaGEgZSBJdMOhbGlhIG5vIGNhbXBvIGBDb3VudHJ5LlJlZ2lvbmAuIERlcG9pcywgdmFtb3MgZXhjbHVpciBhcyBjb2x1bmFzIGBQcm92aW5jZS5TdGF0ZWAsIGBMYXRgIGUgYExvbmdgLCBxdWUgbsOjbyBub3MgaW50ZXJlc3NhbS4gCgpSZXBhcmUgcXVlIHBvZGVtb3Mgc2VsZWNpb25hciBhcyBjb2x1bmFzIHF1ZSBuw6NvIHF1ZXJlbW9zIGNvbSBvIHNpbmFsIGRlIG5lZ2F0aXZvIChgLWApIGNvbSBvIGNvbWFuZG8gc2VsZWN0LiBVc2FyZW1vcyBlc3NlIHJlY3Vyc28gbm92YW1lbnRlIG5vIGNvbWFuZG8gc2VndWludGUuIFJlcGFyZSB0YW1iw6ltIHF1ZSBhIGJhcnJhIGVtIHDDqSAoYHxgKSBzaWduaWZpY2EgbyBvcGVyYWRvciAiT1UiLgoKYGBge3J9CmRmIDwtIGRhZG9zICU+JSBmaWx0ZXIoQ291bnRyeS5SZWdpb24gPT0gJ0l0YWx5JyB8IENvdW50cnkuUmVnaW9uID09ICdTcGFpbicpICU+JSAKICBzZWxlY3QoLVByb3ZpbmNlLlN0YXRlLC1MYXQsLUxvbmcpCgpkZgoKYGBgCgoKIyBUcmFuc2Zvcm1hbmRvIGNvbHVuYXMgZW0gbGluaGFzCgpQYXJhIGZhY2lsaXRhciBhIGFuw6FsaXNlIGUgdmlzdWFsaXphw6fDo28gZG9zIGRhZG9zLCBhbyBpbnbDqXMgZGUgdGVyIHbDoXJpYXMgY29sdW5hcywgdmFtb3MgY3JpYXIgdW1hIHZhcmnDoXZlbCAob3UgdW1hIG5vdmEgY29sdW5hKSBxdWUgY29udGVuaGEgbyBkaWEgZSBvdXRyYSBxdWUgdGVuaGEgbyBuw7ptZXJvIGRlIGNhc29zLiBBc3NpbSwgcG9kZW1vcyByZXN1bWlyIGFxdWVsYXMgdsOhcmlhcyBjb2x1bmFzIGVtIGFwZW5hcyBkdWFzLgoKVm9jw6ogcG9kZSB1dGlsaXphciBkaXZlcnNhcyBmdW7Dp8O1ZXMsIGNvbW8gYSBgZ2F0aGVyYCBvdSBhIGBwaXZvdF9sb25nZXJgLiBQYXJhIG5vc3NvIGV4ZW1wbG8sIGFtYmFzIHPDo28gbXVpdG9zIHNlbWVsaGFudGVzLCBtYXMgYSBwcmltZWlyYSBzZXLDoSBkZXNjb250aW51YWRhIHBlbGEgZXF1aXBlIGRlIGRlc2Vudm9sdmVkb3JlcywgZW50w6NvLCByZWNvbWVuZGFtb3MgdXRpbGl6YXIgYSBzZWd1bmRhLiAKCkJhc2ljYW1lbnRlLCBwcmVjaXNhbW9zIGRlZmluaXIgdHLDqnMgcGFyw6JtZXRyb3MgcGFyYSBlbGFzIHJlYWxpemFyZW0gc2V1IHRyYWJhbGhvOgoKKiBEYWRvczogUXVhaXMgYXMgY29sdW5hcyBzZXLDo28gYWx2b3MgZGEgdHJhbnNmb3JtYcOnw6NvPyBObyBub3NzbyBjYXNvLCBhcyBxdWUgcG9zc3VlbSBhIGNvbnRhZ2VtIGRlIGNhc29zIHBvciBkaWEsIG91IHNlamEsIHRvZGFzIG1lbm9zIGEgZG8gcGHDrXMuIAoKKiBDaGF2ZTogQ29tbyBzZXLDoSBjaGFtYWRhIGEgdmFyacOhdmVsIHF1ZSBndWFyZGFyw6EgbyBub21lIGRhcyBjb2x1bmFzPyBObyBub3NzbyBjYXNvLCAiZGlhIi4KCiogVmFsb3JlczogQ29tbyBzZXLDoSBjaGFtYWRhIGEgdmFyacOhdmVsIHF1ZSBndWFyZGFyw6Egb3MgdmFsb3JlcyBkYXMgY8OpbHVsYXM/IFZhbW9zIG5vbWXDoS1sYSBkZSAiY2Fzb3MiCgpWZWphIGFiYWl4byBjb21vIHV0aWxpemFtb3MgZXN0ZXMgcGFyw6JtZXRyb3MgZW0gYW1iYXMgYXMgZnVuw6fDtWVzLgoKYGBge3J9CiMgU2Ugdm9jw6ogbsOjbyBjb25zZWd1aXIgcm9kYXIgYSBmdW7Dp8OjbyBhYmFpeG8sIHRhbHZleiBwcmVjaXNlIGF0dWFsaXphciBvIHBhY290ZSAidGlkeXIiCiMgTmVzdGUgY2Fzbywgdm9vY8OqIHBvZGUgcm9kYXIgbyBjb21hbmRvIGluc3RhbGwucGFja2FnZXMoInRpZHlyIikgCiMgT3UgdXRpbGl6YXIgYSBmdW7Dp8OjbyBnYXRoZXIKCiMgZGYgPC0gZGYgJT4lIGdhdGhlcihkaWEsY2Fzb3MsLUNvdW50cnkuUmVnaW9uKQoKZGYgPC0gZGYgJT4lIHBpdm90X2xvbmdlcigtQ291bnRyeS5SZWdpb24sImRpYSIsdmFsdWVzX3RvID0gImNhc29zIikKCmRmCmBgYAoKIyBUcmFuc2Zvcm1hbmRvIHRleHRvcyBlbSBkYXRhcwoKTGVnYWwhIEFnb3JhLCBwcmVjaXNhbW9zIGRlZmluaXIgcXVlIG8gY2FtcG8gImRpYSIgZGV2ZSBzZXIgZW5jYXJhZG8gY29tbyB1bWEgZGF0YS4gUmVwYXJlIGJlbSBubyBwYWRyw6NvIGRhIGRhdGEgbmEgdGFiZWxhIGFjaW1hLgoKRWxhIMOpIHVtYSBzZXF1w6puY2lhIGRlIGNhcmFjZXRlcmVzIChpbmRpY2FkbyBwZWxhIHNpZ2xhICJjaHIiIG5vIGNhYmXDp2FsaG8pLiBBIHByaW1laXJhIGNvaXNhIHF1ZSBmYXJlbW9zIMOpIHRpcmFyIGVzdGUgIlgiIGUgZGVwb2lzIGZvcm1hdGFyIGEgY29sdW5hIGNvbW8gZGF0YS4KClByaW1laXJvLCB2YW1vcyB1c2FyIHVtYSBmdW7Dp8OjbyBwYXJhIHN1YnN0aXR1aXIgKHJlcGxhY2UpIHVtYSBzZXF1w6puY2lhIGRlIGNhcmFjdGVyZXMgKHN0cmluZyBvdSBzdHIpLCBhIGZ1bsOnw6NvIHN0cl9yZXBsYWNlLiBDb20gZWxhLCB2YW1vcyB0cm9jYXIgbm8gY2FtcG8gImRpYSIgZG8gYmFuY28gZGUgZGFkb3MgImRmIiBxdWFscXVlciBvY29ycsOqbmNpYSBkZSBYIHBvciB1bWEgc2VxdcOqbmNpYSB2YXppYSwgT3Ugc2VqYSwgbmEgcHLDoXRpY2EsIHJlbW92ZXJlbW9zIHRvZG9zIG9zICJYIi4KCkRlcG9pcywgdmFtb3MgbXVkYXIgbyBjYW1wbyBwYXJhIG8gZm9ybWF0byBkZSBkYXRhLiBPIHBvbnRvIHNpZ25pZmljYSBxdWUgcGVnYXJlbW9zIG8gcmVzdWx0YWRvIGRhIG9wZXJhw6fDo28gYW50ZXJpb3IsIG91IHNlamEsIG9zIG7Dum1lcm9zIGRhcyBkYXRhcyBzZW0gbyBYLiBUYW1iw6ltIHZhbW9zIGV4cGxpY2l0YXIgbyBmb3JtYXRvIGRhdGEgcXVlIMOpIG3DqnMgKCVtKSwgZGlhICglZCkgZSBhbm8gKCV5KSAtIHNlcGFyYWRvcyBwb3IgdW0gcG9udG8uCgpgYGB7cn0KZGYkZGlhIDwtIHN0cl9yZXBsYWNlKGRmJGRpYSwiWCIsICIiKSAlPiUKICBhcy5EYXRlKC4sZm9ybWF0PSclbS4lZC4leScpCgojIFZhbW9zIGNoZWNhciBzZSBmdW5jaW9ub3UgdmVuZG8gbyBkaWEgbWFpcyByZWNlbnRlLCBqw6Egbm8gZm9ybWF0byBjb3JyZXRvCm1heChkZiRkaWEpCmBgYAoKQWdvcmEsIGNvbnNlZ3VpbW9zIHZpc3VhbGl6YXIgb3MgcmVnaXN0cm9zIG9yZGVuYWRvcyBwb3IgZGF0YS4gUmVwYXJlIG5hIHRhYmVsYSBhYmFpeG8gcXVlIGFnb3JhIG8gZGlhIGFwYXJlY2UgY29tbyAiZGF0ZSIgby8KCgpgYGB7cn0KZGYgJT4lIGFycmFuZ2UoZGlhKQpgYGAKCgojIElkZW50aWZpY2FuZG8gbyBkaWEgemVybwoKVW1hIG3DqXRyaWNhIGJhc3RhbnRlIGNvbXVtIGVtIGFuw6FsaXNlIGRlIGVwaWRlbWlhcyDDqSBhIGNvbnRhZ2VtIGRlIHF1YW50b3MgZGlhcyBzZSBwYXNzYXJhbSBkZXNkZSBkZXRlcm1pbmFkbyBsaW1hciBkZSBjYXNvcy4gSXNzbyBmYWNpbGl0YSBhIGNvbXBhcmHDp8OjbyBkZSBmZW7DtG1lbm9zIHF1ZSBvY29ycmVyYW0gZW0gZGF0YXMgZGlzdGludGFzLiAKCkFiYWl4bywgdmFtb3MgYWRpY2lvbmFyIHVtYSBub3ZhIGNvbHVuYSBxdWUgY29udGUgcXVhbnRvcyBkaWFzIHNlIHBhc3NhcmFtIGRlc2RlIG8gY2VudMOpc2ltbyBjYXNvIG5vcyBkb2lzIHBhw61zZXMuIE8gcHJpbWVpcm8gZGlhIHF1ZSBhIEl0w6FsaWEgcmVnaXN0cm91IG1haXMgcXVlIDEwMCBjYXNvcyBmb2kgZGlhIDIzIGRlIGZldmVyZWlybywgZW5xdWFudG8gbmEgRXNwYW5oYSBmb2kgYXBlbmFzIG5vIGRpYSAyIGRlIG1hcsOnby4KCmBgYHtyfQpkZiA8LSBkZiAlPiUgCiAgIyBBIG9yZGVtIGRhcyBkYXRhcyDDqSBmdW5kYW1lbnRhbCwgZW50w6NvLCB2YW1vcyBvcmRlbmFyIG9zIGRhZG9zIHBvciBkaWEKICBhcnJhbmdlKGRpYSkgJT4lCiAgIyBFIGZpbHRyYSBvcyByZWdpc3Ryb3MgbWVub3JlcyBxdWUgMTAwLiBWb2PDqiBwb2RlIHRyb2NhciBwb3IgcXVhbHF1ZXIgb3V0cm8gdmFsb3IuCiAgIyBUcm9xdWUgcG9yIDAgcGFyYSBwZWdhciB0b2RvcyBvcyBkaWFzIGRlc2RlIG8gcHJpbWVpcm8gY2Fzby4KICBmaWx0ZXIoY2Fzb3MgPiAxMDApICAlPiUKICAjIEVudMOjbywgdmFtb3MgdXNhciBvIGdyb3VwX2J5IHBhcmEgcXVlIGEgb3BlcmHDp8OjbyBhIHNlZ3VpciBzZWphIGZlaXRhIHBhcmEgY2FkYSBwYcOtcyAoQ291bnRyeS5SZWdpb24pCiAgZ3JvdXBfYnkoQ291bnRyeS5SZWdpb24pICU+JQogICMgVmFtb3MgZGVmaW5pciBvIGRpYSAwIGNvbW8gbyBtZW5vciBkaWEgZGFxdWVsZSBwYcOtcwogIG11dGF0ZShkaWEwID0gbWluKGRpYSkpCgpkZgpgYGAKCiMgQ29udGFnZW0gZGUgZGlhcwoKSsOhIHNhYmVtb3MgYSBkYXRhIGRlIHJlZ2lzdHJvIGUgYSBkYXRhIGRvIHByaW1laXJvIGNhc28sIHBhcmEgY2FkYSByZWdpc3RybyBkZSBub3NzYSB0YWJlbGEuIEFnb3JhLCBlc3TDoSBmw6FjaWwgY2FsY3VsYXJtb3MgYSBkaWZlcmVuw6dhIGVudHJlIG9zIGRpYXMuIEFzc2ltLCBwb2RlbW9zIGFuYWxpc2FyIGNvbW8gY2FkYSBwYcOtcyBlc3RhdmEgdW1hIHNlbWFuYSBhcMOzcyBhIHBhc3NhciBvIGxpbWlhciBkbyBjZW50w6lzaW1vIGNhc28sIHBvciBleGVtcGxvLiAKClZhbW9zIGNyaWFyIHVtYSBub3ZhIHZhcmnDoXZlbCAoY29udGFfZGlhKSBxdWUgdmFpIHNlciBvIHJlc3VsdGFkbyBkYSBkaWZlcmVuw6dhIGVudHJlIGEgZGF0YSBkZSByZWdpc3RybyAoZGlhKSBlIG8gZGlhIDAgKGRpYTApIGVtIGRpYXMuCgpgYGB7cn0KIyBWYW1vcyBhZGljaW9uYXIgbyBub3ZvIGNhbXBvCmRmJGNvbnRhX2RpYSA8LSBkaWZmdGltZShkZiRkaWEsZGYkZGlhMCx1bml0cyA9ICJkYXlzIikKCiMgRSB2aXN1YWxpemFyIG9zIGRhZG9zIG9yZGVybmFkb3MgcG9yIGVsZQpkZiAlPiUgYXJyYW5nZShjb250YV9kaWEpIAoKYGBgCgojIENhbGN1bGFuZG8gbyBuw7ptZXJvIGRlIGNhc29zIG5vdm9zIHBvciBkaWEKClJlcGFyZSBxdWUgYSBjb2x1bmEgImNhc29zIiB0cmF6IG8gdG90YWwgZGUgY2Fzb3MgYWN1bXVsYWRvIGF0w6kgYSBkYXRhIGVzcGVjaWZpY2FkYSBubyBjYW1wbyAiZGlhIi4gTWFzIGUgc2UgcXVpc2VybW9zIHNhYmVyIG8gbsO6bWVybyBkZSBub3ZvcyBjYXNvcyBwb3IgZGlhPwoKVmFtb3MgY3JpYXIgdW1hIG5vdmEgY29sdW5hIGNoYW1hZGEgYG5vdm9zX2Nhc29zYCwgcXVlIHNlcsOhIHJlc3VsdGFkbyBkbyBuw7ptZXJvIGRlIGNhc29zIGRvIGRpYSBtZW5vcyBvIG7Dum1lcm8gZGUgY2Fzb3MgZG8gZGlhIGFudGVyaW9yLCBlbSBjYWRhIHBhw61zLgoKYGBge3J9CmRmIDwtIGRmICU+JSAKICAjIFZhbW9zIHJlbW92ZXIgYSBjb2x1bmEgZGF5MCBwb2lzIGVsYSBuw6NvIMOpIG1haXMgbmVjZXNzw6FyaWEKICBzZWxlY3QoLWRpYTApICU+JQogICMgQWdydXBhbW9zIHBvciBwYcOtcwogIGdyb3VwX2J5KENvdW50cnkuUmVnaW9uKSAlPiUgCiAgIyBMZW1icmFuZG8gcXVlIG5vc3NvcyBjYXNvcyBqw6EgZXN0w6NvIG9yZGVuYWRvcyBwb3IgZGlhCiAgIyBFbnTDo28sIHV0aWxpemFtb3MgYSBmdW7Dp8OjbyBsYWcoKSBwYXJhIHJldG9ybmFyIG8gw7psdGltbyB2YWxvciBkYXF1ZWxhIGNvbHVuYQogIG11dGF0ZShub3Zvc19jYXNvcyA9IGNhc29zIC0gbGFnKGNhc29zKSkKCmRmCgpgYGAKCiMgQ2FsY3VsYW5kbyBvIGF1bWVudG8gcGVyY2VudHVhbAoKVmFtb3MgaW5jcmVtZW50YXIgYWluZGEgbWFpcy4gQWdvcmEgdmFtb3MgYWRpY2lvbmFyIHVtIG5vdm8gY2FtcG8gcXVlIHZhaSBtb3N0cmFyIG8gYXVtZW50byBwZXJjZW50dWFsIG5vIG7Dum1lcm8gYWN1bXVsYWRvIGRlIGNhc29zIGNvbmZpcm1hZG9zIGVtIGNhZGEgZGlhLgoKUGFyYSByZWxlbWJyYXIsIHBhcmEgY2FsY3Vsw6EtbGEsIHBlZ2Ftb3MgbyBuw7ptZXJvIGRlIGNhc29zIGRlIHVtIGRpYSAoYGNhc29zYCksIGRpdmlkaW1vcyBwZWxvIHRvdGFsIGRpYSBhbnRlcmlvciAoYGxhZyhjYXNvcylgKSwgZGltaW51aW1vcyBwb3IgMSBlIGVudMOjbyBtdWx0aXBsaWNhbW9zIHBvciAxMDAgcGFyYSBvYnRlciBhIHRheGEgcGVyY2VudHVhbC4gRSB0YW1iw6ltIHZhbW9zIGFycmVkb25kYXIgbyByZXN1bHRhZG8sIHVzYW5kbyBhIGZ1bsOnw6NvIGByb3VuZCgpYC4KCgpgYGB7cn0KZGYgPC0gZGYgJT4lIG11dGF0ZShhdW1lbnRvX3BlcmNlbnQgPSByb3VuZCgobm92b3NfY2Fzb3MvbGFnKGNhc29zKSoxMDApKSkKCmRmCmBgYAoKIyBDYXNvcyBwb3IgbWlsaMOjbyBkZSBoYWJpdGFudGVzCkFpbmRhIHF1ZSBzZWphIGFtcGxhbWVudGUgdXRpbGl6YWRhIHBvciDDs3Jnw6NvcyBvZmljaWFzIGUgcGVsYSBpbXByZW5zYSwgYWxndW5zIGVzcGVjaWFsaXN0YXMgZGVzZW5jb3JhamFtIG8gdXNvIGRlIHRheGFzIHBvcHVsYWNpb25haXMgcGFyYSBhdmFsaWHDp8OjbyBkYSB0YXhhIGRlIGNvbnTDoWdpbyBub3MgZXN0w6FnaW9zIGluaWNpYWlzIGRlIHVtYSBwYW5kZW1pYS4gSXN0byBwb2lzIG8gbsO6bWVybyBkZSBwZXNzb2FzIGNvbnRhZ2lhZGFzIHBvciBjYWRhIGluZmVjdGFkYSBuw6NvIMOpIGFsdGVyYWRhIHBlbG8gdGFtYW5obyBkYSBwb3B1bGHDp8OjbywgcG9yw6ltLCDDoCBtZWRpZGEgcXVlIGEgZXBpZGVtaWEgcHJvZ3JpZGUgZXN0ZSBuw7ptZXJvIHBhc3NhIGEgc2VyIMO6dGlsLiBBIHRheGEgdGFtYsOpbSBwb2RlIHNlciB1bSBib20gaW5kaWNhZG9yIHNlIHF1ZXJlbW9zIGF2YWxpYXIgbyBpbXBhY3RvIG5hIGluZnJhLWVzdHJ1dHVyYSBkZSBzYcO6ZGUsIHBvciBleGVtcGxvLCBlbnTDo28sIHZhbW9zIHZlciBjb21vIHJlYWxpesOhLWxhLiBQYXJhIHNlIGFwcm9mdW5kYXIgbWFpcyBuZXN0YSBkaXNjdXNzw6NvLCB2aWRlIG8gW2l0ZW0gNC40LjIgZGVzdGUgYXJ0aWdvXShodHRwczovL2dpdGh1Yi5jb20vcGF1bG9odWJlcnQvY292aWRfZGlzY3Vzc2FvL2Jsb2IvbWFzdGVyL2NvbXBhcmFuZG9fcGFpc2VzX2NvdmlkLnBkZikgb3UgZXN0YSBtYXTDqXJpYSBkbyBbVGhlIE5ldyBZb3JrIFRpbWVzXShodHRwczovL3d3dy5ueXRpbWVzLmNvbS9pbnRlcmFjdGl2ZS8yMDIwLzAzLzI3L3Vwc2hvdC9jb3JvbmF2aXJ1cy1uZXcteW9yay1jb21wYXJpc29uLmh0bWwpLgoKQXF1aSwgdmFtb3MgYWRpY2lvbmFyIHVtYSBjb2x1bmEgY29tIGEgcG9wdWxhw6fDo28gZG9zIHBhw61zZXMuIENvbW8gZXN0ZSDDqSBhcGVuYXMgdW0gZXhlbXBsbyBlIHRlbW9zIHPDsyAyIGNhc29zLCBwb2RlbW9zIHVzYXIgY29uZGljaW9uYWwgc2ltcGxlcy4gU2UgbyBwYcOtcyBmb3IgYSBJdMOhbGlhLCBpbnNlcmltb3MgYSBwb3B1bGHDp8OjbyBkZSA2MCBtaWxow7VlcyAoNjA0ODM1MzgpLCBzZSBuw6NvLCBlbnTDo28sIHNlcsOhIGEgRXNwYW5oYSwgcXVlIHRlbSBwb3B1bGHDp8OjbyBkZSA0NiBtaWxow7VlcyAoNDY3NTAzMzcpLgoKYGBge3J9CiMgCmRmIDwtIGRmICU+JSBtdXRhdGUocG9wdWxhY2FvID0gaWZlbHNlKENvdW50cnkuUmVnaW9uID09ICJJdGFseSIsNjA0ODM1MzgsNDY3NTAzMzcpKSAlPiUKICAjIFVtYSB2ZXogcXVlIHZvY8OqIGluc2lyYSBhIGNvbHVuYSBkZSBwb3B1bGHDp8OjbywgbyBjw6FsY3VsbyBkYSB0YXhhIMOpIHNpbXBsZXMKbXV0YXRlKHRheGEgPSByb3VuZCgoY2Fzb3MvcG9wdWxhY2FvKSAqIDEwMDAwMDApKQoKZGYKYGBgCgoKIyBCw7RudXM6IHBsb3RhbmRvIG8gcmVzdWx0YWRvIGVtIGdyw6FmaWNvCkVzdGUgbsOjbyDDqSB1bSB0dXRvcmlhbCBkZSB2aXN1YWxpemHDp8OjbyBkZSBkYWRvcywgbWFzIGRlcG9pcyBkZSBjaGVnYXIgYXF1aSBuw7NzIG1lcmVjZW1vcyB2ZXIgbyByZXN1bHRhZG8gZG8gdHJhYmFsaG8gZW0gdW0gZ3LDoWZpY28uIEVudMOjbywgdmFtb3MgbMOhIQoKYGBge3J9CiMgVmFtb3MgdXNhciBvIHRlbWEgZGEgVGhlIEVjb25vbWlzdCBwYXJhIGRlaXhhciBvIGdyw6FmaWNvIGJvbml0byA6KQpsaWJyYXJ5KGdndGhlbWVzKQoKZ3JhZmljbyA8LSBnZ3Bsb3QoZGYsIGFlcyh4PWNvbnRhX2RpYSx5PWNhc29zLCBncm91cCA9IENvdW50cnkuUmVnaW9uLCBjb2xvdXIgPSBDb3VudHJ5LlJlZ2lvbikpICsgCiAgZ2VvbV9saW5lKCkgKwogIHRoZW1lX2Vjb25vbWlzdF93aGl0ZSgpICsKICBsYWJzKGNhcHRpb24gPSAiR3LDoWZpY286IEVzY29sYSBkZSBEYWRvcyBcbiBEYWRvczogSm9obiBIb3BraW5zIikgKwogICAgbGFicyh4ID0gIkRpYXMgZGVzZGUgbyBjZW50w6lzaW1vIGNhc28iLCB5ID0gIlRvdGFsIGRlIGNhc29zIiwKICAgICAgICAgdGl0bGUgPSAiRXZvbHXDp8OjbyBkb3MgY2Fzb3MgY29uZmlybWFkb3MgZGUgQ09WSUQtMTkiKSAKCmdyYWZpY28KYGBgCgojIyBCw7RudXMgZXh0cmE6IGVzY2FsYSBsb2dhcsOtdGltaWNhCgpNYWlzIHVtIGLDtG51czogYWdvcmEsIHZhbW9zIHBsb3RhciBvIG1lc21vIGdyw6FmaWNvLCBtYXMgY29tIGVzY2FsYSBsb2dhcsOtdGltaWNhLiBCYXN0YSBhZGljaW9uYXIgbyBjb21hbmRvIGArIHNjYWxlX3lfbG9nMTAoKWAuCgpSZXBhcmUgY29tbyBhcyBkdWFzIGVzY2FsYXMgcGVybWl0ZW0gYW7DoWxpc2VzIGRpZmVyZW50ZXMuCgpgYGB7cn0KZ3JhZmljbyA8LSBnZ3Bsb3QoZGYsIGFlcyh4PWFzLmRvdWJsZShjb250YV9kaWEpLHk9dGF4YSwgZ3JvdXAgPSBDb3VudHJ5LlJlZ2lvbiwgY29sb3VyID0gQ291bnRyeS5SZWdpb24pKSArIAogIGdlb21fbGluZSgpICsKICB0aGVtZV9lY29ub21pc3Rfd2hpdGUoKSArCiAgbGFicyhjYXB0aW9uID0gIkdyw6FmaWNvOiBFc2NvbGEgZGUgRGFkb3MgXG4gRGFkb3M6IEpvaG4gSG9wa2lucyIpICsKICAgIGxhYnMoeCA9ICJEaWFzIGRlc2RlIG8gY2VudMOpc2ltbyBjYXNvIiwgeSA9ICJUb3RhbCBkZSBjYXNvcyIsCiAgICAgICAgIHRpdGxlID0gIkV2b2x1w6fDo28gZG9zIGNhc29zIGNvbmZpcm1hZG9zIGRlIENPVklELTE5IiwKICAgICAgICAgc3VidGl0bGUgPSAiQ29tIGVzY2FsYSBsb2dhcsOtdGltaWNhIikgKyBzY2FsZV95X2xvZzEwKCkKCmdyYWZpY28gCmBgYAoKCgo=