Introdução

No dia 28/01/2020 eu tive a experiencia incrível de passar um pouco do meu conhecimento sobre Shiny no R-Ladies Rio. Assim, vou fazer um passo a passo de toda a construção do aplicativo que pode ser acessado pelo link: https://llvia-rodrigues.shinyapps.io/shiny_app/, desta forma vou abordar da construção da base de dados até o aplicativo publicado em um série de postagens. Primeiro, precisamos da base, então o primeiro passo será construir essa base baixando os dados dos fundos diretamente do site da CVM (Comissão de Valores Mobiliários). A primeira publicação da série será: BAIXANDO OS DADOS DA CVM.

Download dos dados no site da CVM

Para começa vamos chamar os meus, os seus, os nossos pacotes favoritos. Os pacotes para manipulação da base de dados que eu SEMPRE uso são: tidyverse e magrittr; para fazer gráfico bonitinhos eu uso o ggplot2 e o plotly Shiny. Vou mostrar a base de dados através do pacote DT e por fim para trabalhar com datas uso o lubridate e o bizdays.

#pacote de manipulacao da base de dados -- meu top1
library(tidyverse)
package 㤼㸱tidyverse㤼㸲 was built under R version 3.6.1package 㤼㸱dplyr㤼㸲 was built under R version 3.6.1
#tabela html
library(DT)
#pacote para gráficos
library(ggplot2)
#pacote de manipulacao da base de dados
library(magrittr)
#pacote para gráficos html
library(plotly)
#pacote para datas
library(lubridate)
#pacote para dias uteis que tem o calendario Anbima cadastrado 
library(bizdays)

1. Dados cadastrais dos fundos

No site da CVM podemos capturar informações cadastrais de todos os fundos, como classe, nome, CNPJ, CNPJ do gestor, entre outras. A chave para linkar a cota é o CNPJ do fundo, então não podemos remover essa coluna. O arquivo será acessado via função read.csv2, com o caminho apresentado no código e o formato de data “AnoMêsDia” (YYYMMDD).

2. Dados de mercado do Fundo

Agora iremos capturar os dados de mercado, como valor de cota, patrimônio liquido, número de cotistas, resgate (normalmente situado em d-2), de todos os fundos disponibilizados. Um ponto importante é que o caminho será sempre no formato “AnoMês” (YYMM). Se você quiser pegar apenas do mês corrente, leia apenas o mês atual, como o código abaixo.

    datatable( head(fund,2)  ,selection = "single",escape = F
               ,rownames = T
               , extensions = 'Buttons'
               , options = list( 
                 
                 orientation ='landscape',
                 dom = "Blfrtip", scrollX = T,
                 searching = F,
                 paging = F
               ) # end of options
               
    )
It seems your data is too big for client-side DataTables. You may consider server-side processing: https://rstudio.github.io/DT/server.htmlIt seems your data is too big for client-side DataTables. You may consider server-side processing: https://rstudio.github.io/DT/server.html

Como eu quero criar uma série de retornos, vou montar uma base de dados que vai andar mês a mês.Como a base de dados é enorme, vou filtrar apenas os fundos que tenho na minha carteira, seja ela fictícia ou real.Esse processo de construção da base de dados é demorado e para isso preciso do CNPJ do fundo para filtrar e chavear com os dados cadastrais. Meus fundos: Alaska Black (26.673.556/0001-32), Trend Ibovespa (31.204.199/0001-01), Western (19.831.126/0001-36), AZ Quest (07.279.657/0001-89) e Trend Inflação (31.145.833/0001-74).

#ultimo dia do mes
ultimo_dia_mes <- data_atual - months(0:11)-ddays(day(data_atual))

#base de dados vazia
df_fundos <- tibble()
#cnpj meus fundos
meus_fundos <- c("26.673.556/0001-32","31.204.199/0001-01","19.831.126/0001-36",
                 "07.279.657/0001-89","31.145.833/0001-74")


data_atual <- today()-2


for(i in 1:length(ultimo_dia_mes)){
 
  ano <- year(ultimo_dia_mes[i])
  mes <- month(ultimo_dia_mes[i])
  dia <- day(ultimo_dia_mes[i])
  
  if (nchar(mes)==1){
    mes <- paste0("0",mes)
  }
  
  if (nchar(dia)==1){
    dia <- paste0("0",dia)
  }
  
  caminho <- paste0("http://dados.cvm.gov.br/dados/FI/DOC/INF_DIARIO/DADOS/inf_diario_fi_", ano, mes, ".csv")
  fund <- read.csv2(caminho)
  ref_fundos <- as_tibble(fund) %>% 
    dplyr::filter(CNPJ_FUNDO%in% meus_fundos)
  
  df_fundos <- rbind(df_fundos,ref_fundos)
}

Agora que já montei uma base de dados que começa no dia 2019-04-01 e termina em 2020-03-31, vamos formatar a base e fazer o join com os dados cadastrais dos meus fundos.

tt_fundos <- df_fundos %>% left_join( fund_names,by = "CNPJ_FUNDO")
Column `CNPJ_FUNDO` joining character vector and factor, coercing into character vector
tt_fundos <- as_tibble(tt_fundos)
tt_fundos$DENOM_SOCIAL %<>% substr(1,10) %<>% as.factor()
tt_fundos$DT_COMPTC %<>% as.Date()
tt_fundos$VL_QUOTA %<>% as.numeric()
 
    datatable( tt_fundos  ,selection = "single",escape = F
               ,rownames = F
               
               , options = list( 
                 
                 orientation ='landscape',
                 dom = "Blfrtip", scrollX = T,
                 searching = T,
                 paging = T
               ) # end of options
               
    )
It seems your data is too big for client-side DataTables. You may consider server-side processing: https://rstudio.github.io/DT/server.htmlIt seems your data is too big for client-side DataTables. You may consider server-side processing: https://rstudio.github.io/DT/server.html

Para fechar este post, vamos fazer um gráfico porque sempre traz credibilidade e nos ajuda a entender o comportamento dos nossos fundos. Assim, vamos ver a evolução da cota do fundo Alaska Black (bom que eu lembro o ferro que estou tomando).Na próxima publicação, vou mostrar um passo a passo dos gráficos que criei no aplicativo, assim iremos calcular o retorno através das cotas.

graficos <- tt_fundos %>% filter(CNPJ_FUNDO=="26.673.556/0001-32")
fundo <- as.character(unique(graficos$DENOM_SOCIAL))
p <- ggplot2::ggplot(graficos) +
  geom_line(aes(DT_COMPTC,VL_QUOTA),color='blue') +
  labs(x = 'Data', y= 'cota',title= paste0('Evolução de Cota ',fundo[1]),subtitle = fundo[1])
LS0tDQp0aXRsZTogIkRvd25sb2FkIGRvcyBkYWRvcyBDVk0iDQphdXRob3I6ICJMw612aWEgRmVycmVpcmEgUm9kcmlndWVzIg0KZGF0ZTogIjIzIGRlIEFicmlsIGRlIDIwMjAiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQoNCiMjIEludHJvZHXDp8Ojbw0KTm8gZGlhIDI4LzAxLzIwMjAgZXUgdGl2ZSBhIGV4cGVyaWVuY2lhIGluY3LDrXZlbCBkZSBwYXNzYXIgdW0gcG91Y28gZG8gbWV1IGNvbmhlY2ltZW50byBzb2JyZSBTaGlueSBubyBSLUxhZGllcyBSaW8uIEFzc2ltLCB2b3UgZmF6ZXIgdW0gcGFzc28gYSBwYXNzbyBkZSB0b2RhIGEgY29uc3RydcOnw6NvIGRvIGFwbGljYXRpdm8gcXVlIHBvZGUgc2VyIGFjZXNzYWRvIHBlbG8gbGluazogIGh0dHBzOi8vbGx2aWEtcm9kcmlndWVzLnNoaW55YXBwcy5pby9zaGlueV9hcHAvLCBkZXN0YSBmb3JtYSB2b3UgYWJvcmRhciBkYSBjb25zdHJ1w6fDo28gZGEgYmFzZSBkZSBkYWRvcyBhdMOpIG8gYXBsaWNhdGl2byBwdWJsaWNhZG8gZW0gdW0gc8OpcmllIGRlIHBvc3RhZ2Vucy4NClByaW1laXJvLCBwcmVjaXNhbW9zIGRhIGJhc2UsIGVudMOjbyBvIHByaW1laXJvIHBhc3NvIHNlcsOhIGNvbnN0cnVpciBlc3NhIGJhc2UgYmFpeGFuZG8gb3MgZGFkb3MgZG9zIGZ1bmRvcyBkaXJldGFtZW50ZSBkbyBzaXRlIGRhIENWTSAoQ29taXNzw6NvIGRlIFZhbG9yZXMgTW9iaWxpw6FyaW9zKS4gQSBwcmltZWlyYSBwdWJsaWNhw6fDo28gZGEgc8OpcmllIHNlcsOhOiBCQUlYQU5ETyBPUyBEQURPUyBEQSBDVk0uDQoNCg0KIyBEb3dubG9hZCBkb3MgZGFkb3Mgbm8gc2l0ZSBkYSBDVk0NCg0KUGFyYSBjb21lw6dhIHZhbW9zIGNoYW1hciBvcyBtZXVzLCBvcyBzZXVzLCBvcyBub3Nzb3MgcGFjb3RlcyBmYXZvcml0b3MuIA0KT3MgcGFjb3RlcyBwYXJhIG1hbmlwdWxhw6fDo28gZGEgYmFzZSBkZSBkYWRvcyBxdWUgZXUgU0VNUFJFIHVzbyBzw6NvOiB0aWR5dmVyc2UgZSBtYWdyaXR0cjsgcGFyYSBmYXplciBncsOhZmljbyBib25pdGluaG9zIGV1IHVzbyBvIGdncGxvdDIgZSBvIHBsb3RseSBTaGlueS4gVm91IG1vc3RyYXIgYSBiYXNlIGRlIGRhZG9zIGF0cmF2w6lzIGRvIHBhY290ZSBEVCBlIHBvciBmaW0gcGFyYSB0cmFiYWxoYXIgY29tIGRhdGFzIHVzbyBvIGx1YnJpZGF0ZSBlIG8gYml6ZGF5cy4NCg0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFfQ0KI3BhY290ZSBkZSBtYW5pcHVsYWNhbyBkYSBiYXNlIGRlIGRhZG9zIC0tIG1ldSB0b3AxDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCiN0YWJlbGEgaHRtbA0KbGlicmFyeShEVCkNCiNwYWNvdGUgcGFyYSBncsOhZmljb3MNCmxpYnJhcnkoZ2dwbG90MikNCiNwYWNvdGUgZGUgbWFuaXB1bGFjYW8gZGEgYmFzZSBkZSBkYWRvcw0KbGlicmFyeShtYWdyaXR0cikNCiNwYWNvdGUgcGFyYSBncsOhZmljb3MgaHRtbA0KbGlicmFyeShwbG90bHkpDQojcGFjb3RlIHBhcmEgZGF0YXMNCmxpYnJhcnkobHVicmlkYXRlKQ0KI3BhY290ZSBwYXJhIGRpYXMgdXRlaXMgcXVlIHRlbSBvIGNhbGVuZGFyaW8gQW5iaW1hIGNhZGFzdHJhZG8gDQpsaWJyYXJ5KGJpemRheXMpDQpgYGANCg0KIyMjMS4gRGFkb3MgY2FkYXN0cmFpcyBkb3MgZnVuZG9zDQoNCk5vIHNpdGUgZGEgQ1ZNIHBvZGVtb3MgY2FwdHVyYXIgaW5mb3JtYcOnw7VlcyBjYWRhc3RyYWlzIGRlIHRvZG9zIG9zIGZ1bmRvcywgY29tbyBjbGFzc2UsIG5vbWUsIENOUEosIENOUEogZG8gZ2VzdG9yLCBlbnRyZSBvdXRyYXMuIEEgY2hhdmUgcGFyYSBsaW5rYXIgYSBjb3RhIMOpIG8gQ05QSiBkbyBmdW5kbywgZW50w6NvIG7Do28gcG9kZW1vcyByZW1vdmVyIGVzc2EgY29sdW5hLiBPIGFycXVpdm8gc2Vyw6EgYWNlc3NhZG8gdmlhIGZ1bsOnw6NvIHJlYWQuY3N2MiwgY29tIG8gY2FtaW5obyBhcHJlc2VudGFkbyBubyBjw7NkaWdvIGUgbyBmb3JtYXRvIGRlIGRhdGEgIkFub03DqnNEaWEiIChZWVlNTUREKS4NCg0KDQpgYGB7ciB3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0V9DQpkYXRhX2F0dWFsIDwtIHRvZGF5KCkNCg0KYW5vIDwtIHllYXIoZGF0YV9hdHVhbCkNCm1lcyA8LSBtb250aChkYXRhX2F0dWFsKQ0KZGlhIDwtIGRheShkYXRhX2F0dWFsKS0yDQoNCmlmIChuY2hhcihtZXMpPT0xKXsNCiAgbWVzIDwtIHBhc3RlMCgiMCIsbWVzKQ0KfQ0KDQppZiAobmNoYXIoZGlhKT09MSl7DQogIGRpYSA8LSBwYXN0ZTAoIjAiLGRpYSkNCn0NCg0KY2FtaW5ob19uYW1lcyA8LXBhc3RlMCgiaHR0cDovL2RhZG9zLmN2bS5nb3YuYnIvZGFkb3MvRkkvQ0FEL0RBRE9TL2luZl9jYWRhc3RyYWxfZmlfIiwgYW5vLCBtZXMsIGRpYSwgIi5jc3YiKQ0KZnVuZF9uYW1lcyA8LSByZWFkLmNzdjIoY2FtaW5ob19uYW1lcykNCg0KDQogICAgZGF0YXRhYmxlKCBoZWFkKGZ1bmRfbmFtZXMsMikgICxzZWxlY3Rpb24gPSAic2luZ2xlIixlc2NhcGUgPSBGDQogICAgICAgICAgICAgICAscm93bmFtZXMgPSBGDQogICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICwgb3B0aW9ucyA9IGxpc3QoIA0KICAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgb3JpZW50YXRpb24gPSdsYW5kc2NhcGUnLA0KICAgICAgICAgICAgICAgICBkb20gPSAiQmxmcnRpcCIsIHNjcm9sbFggPSBULA0KICAgICAgICAgICAgICAgICBzZWFyY2hpbmcgPSBGLA0KICAgICAgICAgICAgICAgICBwYWdpbmcgPSBGDQogICAgICAgICAgICAgICApICMgZW5kIG9mIG9wdGlvbnMNCiAgICAgICAgICAgICAgIA0KICAgICkNCg0KDQpgYGANCiMjIzIuIERhZG9zIGRlIG1lcmNhZG8gZG8gRnVuZG8NCg0KQWdvcmEgaXJlbW9zIGNhcHR1cmFyIG9zIGRhZG9zIGRlIG1lcmNhZG8sIGNvbW8gdmFsb3IgZGUgY290YSwgcGF0cmltw7RuaW8gbGlxdWlkbywgbsO6bWVybyBkZSBjb3Rpc3RhcywgcmVzZ2F0ZSAobm9ybWFsbWVudGUgc2l0dWFkbyBlbSBkLTIpLCBkZSB0b2RvcyBvcyBmdW5kb3MgZGlzcG9uaWJpbGl6YWRvcy4gVW0gcG9udG8gaW1wb3J0YW50ZSDDqSBxdWUgbyBjYW1pbmhvIHNlcsOhIHNlbXByZSBubyBmb3JtYXRvICJBbm9Nw6pzIiAoWVlNTSkuDQpTZSB2b2PDqiBxdWlzZXIgcGVnYXIgYXBlbmFzIGRvIG3DqnMgY29ycmVudGUsIGxlaWEgYXBlbmFzIG8gbcOqcyBhdHVhbCwgY29tbyBvIGPDs2RpZ28gYWJhaXhvLg0KDQpgYGB7ciB3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0V9DQpjYW1pbmhvIDwtIHBhc3RlMCgiaHR0cDovL2RhZG9zLmN2bS5nb3YuYnIvZGFkb3MvRkkvRE9DL0lORl9ESUFSSU8vREFET1MvaW5mX2RpYXJpb19maV8iLCBhbm8sIG1lcywgIi5jc3YiKQ0KDQpmdW5kIDwtIHJlYWQuY3N2MihjYW1pbmhvKQ0KDQoNCiAgICBkYXRhdGFibGUoIGhlYWQoZnVuZCwyKSAgLHNlbGVjdGlvbiA9ICJzaW5nbGUiLGVzY2FwZSA9IEYNCiAgICAgICAgICAgICAgICxyb3duYW1lcyA9IEYNCiAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgLCBvcHRpb25zID0gbGlzdCggDQogICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICBvcmllbnRhdGlvbiA9J2xhbmRzY2FwZScsDQogICAgICAgICAgICAgICAgIGRvbSA9ICJCbGZydGlwIiwgc2Nyb2xsWCA9IFQsDQogICAgICAgICAgICAgICAgIHNlYXJjaGluZyA9IEYsDQogICAgICAgICAgICAgICAgIHBhZ2luZyA9IEYNCiAgICAgICAgICAgICAgICkgIyBlbmQgb2Ygb3B0aW9ucw0KICAgICAgICAgICAgICAgDQogICAgKQ0KDQoNCmBgYA0KDQpDb21vIGV1IHF1ZXJvIGNyaWFyIHVtYSBzw6lyaWUgZGUgcmV0b3Jub3MsIHZvdSBtb250YXIgdW1hIGJhc2UgZGUgZGFkb3MgcXVlIHZhaSBhbmRhciBtw6pzIGEgbcOqcy5Db21vIGEgYmFzZSBkZSBkYWRvcyDDqSBlbm9ybWUsIHZvdSBmaWx0cmFyIGFwZW5hcyBvcyBmdW5kb3MgcXVlIHRlbmhvIG5hIG1pbmhhIGNhcnRlaXJhLCBzZWphIGVsYSBmaWN0w61jaWEgb3UgcmVhbC5Fc3NlIHByb2Nlc3NvIGRlIGNvbnN0cnXDp8OjbyBkYSBiYXNlIGRlIGRhZG9zIMOpIGRlbW9yYWRvIGUgcGFyYSBpc3NvIHByZWNpc28gZG8gQ05QSiBkbyBmdW5kbyBwYXJhIGZpbHRyYXIgZSBjaGF2ZWFyIGNvbSBvcyBkYWRvcyBjYWRhc3RyYWlzLiANCk1ldXMgZnVuZG9zOiBBbGFza2EgQmxhY2sgKDI2LjY3My41NTYvMDAwMS0zMiksIFRyZW5kIElib3Zlc3BhICgzMS4yMDQuMTk5LzAwMDEtMDEpLCBXZXN0ZXJuICgxOS44MzEuMTI2LzAwMDEtMzYpLCBBWiBRdWVzdCAoMDcuMjc5LjY1Ny8wMDAxLTg5KSBlIFRyZW5kIEluZmxhw6fDo28gKDMxLjE0NS44MzMvMDAwMS03NCkuDQoNCg0KYGBge3Igd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFfQ0KI3VsdGltbyBkaWEgZG8gbWVzDQp1bHRpbW9fZGlhX21lcyA8LSBkYXRhX2F0dWFsIC0gbW9udGhzKDA6MTEpLWRkYXlzKGRheShkYXRhX2F0dWFsKSkNCg0KI2Jhc2UgZGUgZGFkb3MgdmF6aWENCmRmX2Z1bmRvcyA8LSB0aWJibGUoKQ0KI2NucGogbWV1cyBmdW5kb3MNCm1ldXNfZnVuZG9zIDwtIGMoIjI2LjY3My41NTYvMDAwMS0zMiIsIjMxLjIwNC4xOTkvMDAwMS0wMSIsIjE5LjgzMS4xMjYvMDAwMS0zNiIsDQogICAgICAgICAgICAgICAgICIwNy4yNzkuNjU3LzAwMDEtODkiLCIzMS4xNDUuODMzLzAwMDEtNzQiKQ0KDQoNCmRhdGFfYXR1YWwgPC0gdG9kYXkoKS0yDQoNCg0KZm9yKGkgaW4gMTpsZW5ndGgodWx0aW1vX2RpYV9tZXMpKXsNCiANCiAgYW5vIDwtIHllYXIodWx0aW1vX2RpYV9tZXNbaV0pDQogIG1lcyA8LSBtb250aCh1bHRpbW9fZGlhX21lc1tpXSkNCiAgZGlhIDwtIGRheSh1bHRpbW9fZGlhX21lc1tpXSkNCiAgDQogIGlmIChuY2hhcihtZXMpPT0xKXsNCiAgICBtZXMgPC0gcGFzdGUwKCIwIixtZXMpDQogIH0NCiAgDQogIGlmIChuY2hhcihkaWEpPT0xKXsNCiAgICBkaWEgPC0gcGFzdGUwKCIwIixkaWEpDQogIH0NCiAgDQogIGNhbWluaG8gPC0gcGFzdGUwKCJodHRwOi8vZGFkb3MuY3ZtLmdvdi5ici9kYWRvcy9GSS9ET0MvSU5GX0RJQVJJTy9EQURPUy9pbmZfZGlhcmlvX2ZpXyIsIGFubywgbWVzLCAiLmNzdiIpDQogIGZ1bmQgPC0gcmVhZC5jc3YyKGNhbWluaG8pDQogIHJlZl9mdW5kb3MgPC0gYXNfdGliYmxlKGZ1bmQpICU+JSANCiAgICBkcGx5cjo6ZmlsdGVyKENOUEpfRlVORE8laW4lIG1ldXNfZnVuZG9zKQ0KICANCiAgZGZfZnVuZG9zIDwtIHJiaW5kKGRmX2Z1bmRvcyxyZWZfZnVuZG9zKQ0KfQ0KDQoNCmBgYA0KDQoNCkFnb3JhIHF1ZSBqw6EgbW9udGVpIHVtYSBiYXNlIGRlIGRhZG9zIHF1ZSBjb21lw6dhIG5vIGRpYSAgYHIgbWluKGFzLkRhdGUoZGZfZnVuZG9zJERUX0NPTVBUQykpYCBlIHRlcm1pbmEgZW0gIGByIG1heChhcy5EYXRlKGRmX2Z1bmRvcyREVF9DT01QVEMpKWAsIHZhbW9zIGZvcm1hdGFyIGEgYmFzZSBlIGZhemVyIG8gKmpvaW4qIGNvbSBvcyBkYWRvcyBjYWRhc3RyYWlzIGRvcyBtZXVzIGZ1bmRvcy4NCg0KDQoNCmBgYHtyIGluY2x1ZGU9RkFMU0V9DQpkZl9mdW5kb3MkVkxfUVVPVEEgJTw+JSBhcy5jaGFyYWN0ZXIoKQ0KZGZfZnVuZG9zPC0gYXNfdGliYmxlKGRmX2Z1bmRvcykNCmBgYA0KDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0V9DQp0dF9mdW5kb3MgPC0gZGZfZnVuZG9zICU+JSBsZWZ0X2pvaW4oIGZ1bmRfbmFtZXMsYnkgPSAiQ05QSl9GVU5ETyIpDQp0dF9mdW5kb3MgPC0gYXNfdGliYmxlKHR0X2Z1bmRvcykNCnR0X2Z1bmRvcyRERU5PTV9TT0NJQUwgJTw+JSBzdWJzdHIoMSwxMCkgJTw+JSBhcy5mYWN0b3IoKQ0KdHRfZnVuZG9zJERUX0NPTVBUQyAlPD4lIGFzLkRhdGUoKQ0KdHRfZnVuZG9zJFZMX1FVT1RBICU8PiUgYXMubnVtZXJpYygpDQoNCiANCiAgICBkYXRhdGFibGUoIHR0X2Z1bmRvcyAgLHNlbGVjdGlvbiA9ICJzaW5nbGUiLGVzY2FwZSA9IEYNCiAgICAgICAgICAgICAgICxyb3duYW1lcyA9IEYNCiAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgLCBvcHRpb25zID0gbGlzdCggDQogICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICBvcmllbnRhdGlvbiA9J2xhbmRzY2FwZScsDQogICAgICAgICAgICAgICAgIGRvbSA9ICJCbGZydGlwIiwgc2Nyb2xsWCA9IFQsDQogICAgICAgICAgICAgICAgIHNlYXJjaGluZyA9IFQsDQogICAgICAgICAgICAgICAgIHBhZ2luZyA9IFQNCiAgICAgICAgICAgICAgICkgIyBlbmQgb2Ygb3B0aW9ucw0KICAgICAgICAgICAgICAgDQogICAgKQ0KDQoNCmBgYA0KDQoNClBhcmEgZmVjaGFyIGVzdGUgKnBvc3QqLCB2YW1vcyBmYXplciB1bSBncsOhZmljbyBwb3JxdWUgc2VtcHJlIHRyYXogY3JlZGliaWxpZGFkZSBlIG5vcyBhanVkYSBhIGVudGVuZGVyIG8gY29tcG9ydGFtZW50byBkb3Mgbm9zc29zIGZ1bmRvcy4gQXNzaW0sIHZhbW9zIHZlciBhIGV2b2x1w6fDo28gZGEgY290YSBkbyBmdW5kbyBBbGFza2EgQmxhY2sgKGJvbSBxdWUgZXUgbGVtYnJvIG8gZmVycm8gcXVlIGVzdG91IHRvbWFuZG8pLk5hIHByw7N4aW1hIHB1YmxpY2HDp8Ojbywgdm91IG1vc3RyYXIgdW0gcGFzc28gYSBwYXNzbyBkb3MgZ3LDoWZpY29zIHF1ZSBjcmllaSBubyBhcGxpY2F0aXZvLCBhc3NpbSBpcmVtb3MgY2FsY3VsYXIgbyByZXRvcm5vIGF0cmF2w6lzIGRhcyBjb3Rhcy4NCg0KDQpgYGB7ciBpbmNsdWRlPVRSVUV9DQpncmFmaWNvcyA8LSB0dF9mdW5kb3MgJT4lIGZpbHRlcihDTlBKX0ZVTkRPPT0iMjYuNjczLjU1Ni8wMDAxLTMyIikNCmZ1bmRvIDwtIGFzLmNoYXJhY3Rlcih1bmlxdWUoZ3JhZmljb3MkREVOT01fU09DSUFMKSkNCnAgPC0gZ2dwbG90Mjo6Z2dwbG90KGdyYWZpY29zKSArDQogIGdlb21fbGluZShhZXMoRFRfQ09NUFRDLFZMX1FVT1RBKSxjb2xvcj0nYmx1ZScpICsNCiAgbGFicyh4ID0gJ0RhdGEnLCB5PSAnY290YScsdGl0bGU9IHBhc3RlMCgnRXZvbHXDp8OjbyBkZSBDb3RhICcsZnVuZG9bMV0pLHN1YnRpdGxlID0gZnVuZG9bMV0pDQoNCmBgYA0KDQpgYGB7ciBpbmNsdWRlPVRSVUV9DQpncmFmaWNvcyA8LSB0dF9mdW5kb3MgJT4lIGZpbHRlcihDTlBKX0ZVTkRPPT0iMjYuNjczLjU1Ni8wMDAxLTMyIikNCmZ1bmRvIDwtIGFzLmNoYXJhY3Rlcih1bmlxdWUoZ3JhZmljb3MkREVOT01fU09DSUFMKSkNCnAgPC0gZ2dwbG90Mjo6Z2dwbG90KGdyYWZpY29zKSArDQogIGdlb21fbGluZShhZXMoRFRfQ09NUFRDLFZMX1FVT1RBKSxjb2xvcj0nYmx1ZScpICsNCiAgbGFicyh4ID0gJ0RhdGEnLCB5PSAnY290YScsdGl0bGU9IHBhc3RlMCgnRXZvbHXDp8OjbyBkZSBDb3RhICcsZnVuZG9bMV0pLHN1YnRpdGxlID0gZnVuZG9bMV0pDQoNCg0KDQpwbG90bHk6OmdncGxvdGx5KHApDQoNCg0KYGBgDQoNCg0KDQoNCg==