Este documento presenta algunos de los códigos y funciones que nos
ayudarán a realizar un análisis exploratorio de datos univariado. De
forma introductoria se presenta un ejemplo sobre el proceso de lectura y
depuración de datos, así como la realización de gráficos, distribuciones
de frecuencia y obtención de indicadores de dispersión.
#Lectura de datos directamente desde una url. Instalamos y cargamos la librería "readr"
#install.packages("readr") Instalación
library(readr) #cargamos la librería
url <- "https://www.datos.gov.co/api/views/kx2f-xjdq/rows.csv?accessType=DOWNLOAD" #Declaramos la url
df <- read_csv(url, progress = TRUE) #Leemos los datos de la url
saveRDS(df, "inclusion_financiera.rds") #Guardamos los datos en formato RDS para no tener que volver a leerlos desde la url después.
getwd() #Verificamos cuál es el directorio de trabajo en el que estamos.
En caso de necesitar cambiar el directorio usar: setwd(“ubicacion del
directorio de trabajo”).
#Leemos los datos
df <- readRDS("inclusion_financiera.rds")
dim(df) #Obtenemos el tamaño de la matriz de datos. 1566595 filas (registros) y 99 columnas (variables)
head(df) #podemos observar un fragmento de los datos
table(df$NOMBRE_ENTIDAD) #Extraemos una tabla de frecuencias para la variable nombre de entidad.
Debemos corregir las categorías de la variable usando las funciones
de la librería dplyr.
#install.packages("dplyr") #instalamos la librería
library(dplyr) #cargamos la librería
df2<-df %>%
mutate(
NOMBRE_ENTIDAD = recode(
NOMBRE_ENTIDAD,
"Bancar TecnologÃa C.F." = "Bancar Tecnologia C.F.",
"Bancar Tecnología C.F." = "Bancar Tecnologia C.F.",
"Banco de Bogotá" = "Banco de Bogota",
"Banco de Bogotá" = "Banco de Bogota",
"Banco Pichióncha S.A." = "Banco Pichincha S.A.",
"Banco Serfiónanza S.A."= "Banco Serfinanza S.A.",
"Coltefiónanciera" = "Coltefinanciera",
"Cooperativa Fiónanciera de Antioquia" = "Cooperativa Financiera de Antioquia",
"Fiónanciera Juriscoop C.F." = "Financiera Juriscoop C.F.",
"Fiónandióna" = "Finandina",
"GM Financial Colombia S.A. CompañÃa De Financiamiento" = "GM Financial Colombia S.A. Compania De Financiamiento",
"GM Financial Colombia S.A. Compañía De Financiamiento" = "GM Financial Colombia S.A. Compania De Financiamiento",
"Itaú" = "Itau",
"JFK Cooperativa Fiónanciera"= "JFK Cooperativa Financiera"
)
)
table(df2$NOMBRE_ENTIDAD)
#las distribuciones de frecuencia se visualizan mejor como dataframe.
DisFNombre<-as.data.frame(table(df2$NOMBRE_ENTIDAD))
barplot(DisFNombre$Freq~DisFNombre$Var1) #gráfico por defecto
#se puede mejorar usando la librería ggplot2
#install.packages("ggplot2") #Instalamos la librería
library(ggplot2) #cargamos la librería.
ggplot(df2, aes(x = NOMBRE_ENTIDAD)) +
geom_bar(fill = "lightgray") +
labs(
title = " ",
x = "Entidad financiera",
y = "Frecuencia"
) +
theme_minimal()+
theme(
axis.text.x = element_text(size = 16),
axis.text.y = element_text(size = 16),
axis.title.x = element_text(size = 16),
axis.title.y = element_text(size = 16)
)
¿Cómo podemos mejorar la visualización?
ggplot(df2, aes(x = NOMBRE_ENTIDAD)) +
geom_bar(fill = "lightgray") +
labs(
title = " ",
x = "Entidad financiera",
y = "Frecuencia"
) +
coord_flip() +
theme_minimal()+
theme(
axis.text.x = element_text(size = 9),
axis.text.y = element_text(size = 9),
axis.title.x = element_text(size = 12),
axis.title.y = element_text(size = 12)
)
¿Otra idea?
df2top10<-as.data.frame(sort(table(df2$NOMBRE_ENTIDAD), decreasing=T)[1:10])
ggplot(df2top10, aes(x = Var1, y=Freq)) +
geom_col(fill = "lightgray") +
labs(
title = " ",
x = "Entidad financiera",
y = "Frecuencia"
) +
coord_flip() +
theme_minimal()+
theme(
axis.text.x = element_text(size = 11),
axis.text.y = element_text(size = 11),
axis.title.x = element_text(size = 12),
axis.title.y = element_text(size = 12)
)
La distribución de frecuencias la podemos completar con la frecuencia
relativa y el porcentaje de participación.
df2top102 <- df2top10 %>%
mutate(
FreqRel = Freq / sum(Freq),
Porcentaje =100*FreqRel
)
Ejemplo de diagrama de sectores
###Diagrama de sectores
ggplot(df2top102, aes(x = "", y=Freq, fill = Var1)) +
geom_col(width = 1, color="white") +
coord_polar(theta = "y") +
geom_text(
aes(label = scales::percent(round(FreqRel,2))),
position = position_stack(vjust = 0.5),
size = 3)+
theme_void() +
labs(title = "Distribución por entidad financiera", fill = "Var1") +
theme(
plot.title = element_text(hjust = 0.5, size = 16, face = "bold")
)
Podemos agregar totales.
##agregamos fila de totales
df2top102T <- df2top102 %>%
bind_rows(
data.frame(
Var1 = "Total",
Freq = sum(df2top102$Freq),
FreqRel = sum(df2top102$FreqRel),
Porcentaje= sum(df2top102$Porcentaje)
)
)
Tabla de frecuencias para datos agrupados en intervalos de clase.
#Estad?sticas descriptivas sin datos agrupados
summary(df$`(20) SALDO_CTAS_AHORRO_HASTA_1SMMLV`)
Min. 1st Qu. Median Mean 3rd Qu. Max.
0.000e+00 0.000e+00 0.000e+00 1.439e+08 0.000e+00 2.266e+12
Ejemplo de histograma
amplitud
[1] 102984442603
ggplot(df, aes(x = `(20) SALDO_CTAS_AHORRO_HASTA_1SMMLV`)) +
geom_histogram(binwidth=amplitud, fill = "lightblue") +
labs(
title = " ",
x = "Saldo cuentas de ahorro hasta 1SMMLV",
y = "Frecuencia"
) +
theme_minimal()
Excluyendo los valores iguales a cero.
X<-df$`(20) SALDO_CTAS_AHORRO_HASTA_1SMMLV`
NumCuentas<-X[which((X>=100000) & (X<=200000))]
round(summary(NumCuentas),1)
class(NumCuentas)
NumCuentas2<-as.data.frame(NumCuentas)
ggplot(NumCuentas2, aes(x =NumCuentas)) +
geom_histogram(fill = "lightblue", color="black") +
labs(
title = " ",
x = "Saldo cuentas de ahorro hasta 1SMMLV eliminando ceros",
y = "Frecuencia"
) +
theme_minimal()
numcuentasdis<-fdt(NumCuentas, breaks="Sturges", right = T)
Percentiles y medidas de dispersión de la variable saldo de cuentas
de ahorros
percs<-c(0.1, 0.25, 0.5, 0.75, 0.8, 0.9, 0.95)
quantile(X, percs)
var(X) #Varianza
sd(X) #Desviación estándar
LS0tDQp0aXRsZTogIkFuw6FsaXNpcyBFeHBsb3JhdG9yaW8gZGUgRGF0b3MgVW5pdmFyaWFkb3MiDQpvdXRwdXQ6DQogIGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQpFc3RlIGRvY3VtZW50byBwcmVzZW50YSBhbGd1bm9zIGRlIGxvcyBjw7NkaWdvcyB5IGZ1bmNpb25lcyBxdWUgbm9zIGF5dWRhcsOhbiBhIHJlYWxpemFyIHVuIGFuw6FsaXNpcyBleHBsb3JhdG9yaW8gZGUgZGF0b3MgdW5pdmFyaWFkby4gRGUgZm9ybWEgaW50cm9kdWN0b3JpYSBzZSBwcmVzZW50YSB1biBlamVtcGxvIHNvYnJlIGVsIHByb2Nlc28gZGUgbGVjdHVyYSB5IGRlcHVyYWNpw7NuIGRlIGRhdG9zLCBhc8OtIGNvbW8gbGEgcmVhbGl6YWNpw7NuIGRlIGdyw6FmaWNvcywgZGlzdHJpYnVjaW9uZXMgZGUgZnJlY3VlbmNpYSB5IG9idGVuY2nDs24gZGUgaW5kaWNhZG9yZXMgZGUgZGlzcGVyc2nDs24uDQoNCg0KYGBge3J9DQojTGVjdHVyYSBkZSBkYXRvcyBkaXJlY3RhbWVudGUgZGVzZGUgdW5hIHVybC4gSW5zdGFsYW1vcyB5IGNhcmdhbW9zIGxhIGxpYnJlcsOtYSAicmVhZHIiDQojaW5zdGFsbC5wYWNrYWdlcygicmVhZHIiKSBJbnN0YWxhY2nDs24NCmxpYnJhcnkocmVhZHIpICNjYXJnYW1vcyBsYSBsaWJyZXLDrWENCnVybCA8LSAiaHR0cHM6Ly93d3cuZGF0b3MuZ292LmNvL2FwaS92aWV3cy9reDJmLXhqZHEvcm93cy5jc3Y/YWNjZXNzVHlwZT1ET1dOTE9BRCIgI0RlY2xhcmFtb3MgbGEgdXJsDQoNCmRmIDwtIHJlYWRfY3N2KHVybCwgcHJvZ3Jlc3MgPSBUUlVFKSAjTGVlbW9zIGxvcyBkYXRvcyBkZSBsYSB1cmwNCg0Kc2F2ZVJEUyhkZiwgImluY2x1c2lvbl9maW5hbmNpZXJhLnJkcyIpICNHdWFyZGFtb3MgbG9zIGRhdG9zIGVuIGZvcm1hdG8gUkRTIHBhcmEgbm8gdGVuZXIgcXVlIHZvbHZlciBhIGxlZXJsb3MgZGVzZGUgbGEgdXJsIGRlc3B1w6lzLg0KDQpgYGANCg0KYGBge3J9DQpnZXR3ZCgpICNWZXJpZmljYW1vcyBjdcOhbCBlcyBlbCBkaXJlY3RvcmlvIGRlIHRyYWJham8gZW4gZWwgcXVlIGVzdGFtb3MuDQoNCmBgYA0KRW4gY2FzbyBkZSBuZWNlc2l0YXIgY2FtYmlhciBlbCBkaXJlY3RvcmlvIHVzYXI6IHNldHdkKCJ1YmljYWNpb24gZGVsIGRpcmVjdG9yaW8gZGUgdHJhYmFqbyIpLg0KDQpgYGB7cn0NCiNMZWVtb3MgbG9zIGRhdG9zDQpkZiA8LSByZWFkUkRTKCJpbmNsdXNpb25fZmluYW5jaWVyYS5yZHMiKQ0KZGltKGRmKSAjT2J0ZW5lbW9zIGVsIHRhbWHDsW8gZGUgbGEgbWF0cml6IGRlIGRhdG9zLiAxNTY2NTk1IGZpbGFzIChyZWdpc3Ryb3MpIHkgOTkgY29sdW1uYXMgKHZhcmlhYmxlcykNCmhlYWQoZGYpICNwb2RlbW9zIG9ic2VydmFyIHVuIGZyYWdtZW50byBkZSBsb3MgZGF0b3MNCnRhYmxlKGRmJE5PTUJSRV9FTlRJREFEKSAjRXh0cmFlbW9zIHVuYSB0YWJsYSBkZSBmcmVjdWVuY2lhcyBwYXJhIGxhIHZhcmlhYmxlIG5vbWJyZSBkZSBlbnRpZGFkLg0KYGBgDQoNCkRlYmVtb3MgY29ycmVnaXIgbGFzIGNhdGVnb3LDrWFzIGRlIGxhIHZhcmlhYmxlIHVzYW5kbyBsYXMgZnVuY2lvbmVzIGRlIGxhIGxpYnJlcsOtYSBkcGx5ci4NCg0KYGBge3J9DQojaW5zdGFsbC5wYWNrYWdlcygiZHBseXIiKSAjaW5zdGFsYW1vcyBsYSBsaWJyZXLDrWENCmxpYnJhcnkoZHBseXIpICNjYXJnYW1vcyBsYSBsaWJyZXLDrWENCmRmMjwtZGYgJT4lDQogIG11dGF0ZSgNCiAgICBOT01CUkVfRU5USURBRCA9IHJlY29kZSgNCiAgICAgIE5PTUJSRV9FTlRJREFELA0KICAgICAgIkJhbmNhciBUZWNub2xvZ8ODwq1hIEMuRi4iID0gIkJhbmNhciBUZWNub2xvZ2lhIEMuRi4iLA0KICAgICAgIkJhbmNhciBUZWNub2xvZ8OtYSBDLkYuIiA9ICJCYW5jYXIgVGVjbm9sb2dpYSBDLkYuIiwNCiAgICAgICJCYW5jbyBkZSBCb2dvdMODwqEiID0gIkJhbmNvIGRlIEJvZ290YSIsDQogICAgICAiQmFuY28gZGUgQm9nb3TDoSIgPSAiQmFuY28gZGUgQm9nb3RhIiwNCiAgICAgICJCYW5jbyBQaWNoacODwrNuY2hhIFMuQS4iID0gIkJhbmNvIFBpY2hpbmNoYSBTLkEuIiwNCiAgICAgICJCYW5jbyBTZXJmacODwrNuYW56YSBTLkEuIj0gIkJhbmNvIFNlcmZpbmFuemEgUy5BLiIsDQogICAgICAiQ29sdGVmacODwrNuYW5jaWVyYSIgPSAiQ29sdGVmaW5hbmNpZXJhIiwNCiAgICAgICJDb29wZXJhdGl2YSBGacODwrNuYW5jaWVyYSBkZSBBbnRpb3F1aWEiID0gIkNvb3BlcmF0aXZhIEZpbmFuY2llcmEgZGUgQW50aW9xdWlhIiwNCiAgICAgICJGacODwrNuYW5jaWVyYSBKdXJpc2Nvb3AgQy5GLiIgPSAiRmluYW5jaWVyYSBKdXJpc2Nvb3AgQy5GLiIsDQogICAgICAiRmnDg8KzbmFuZGnDg8KzbmEiID0gIkZpbmFuZGluYSIsDQogICAgICAiR00gRmluYW5jaWFsIENvbG9tYmlhIFMuQS4gQ29tcGHDg8Kxw4PCrWEgRGUgRmluYW5jaWFtaWVudG8iID0gIkdNIEZpbmFuY2lhbCBDb2xvbWJpYSBTLkEuIENvbXBhbmlhIERlIEZpbmFuY2lhbWllbnRvIiwNCiAgICAgICJHTSBGaW5hbmNpYWwgQ29sb21iaWEgUy5BLiBDb21wYcOxw61hIERlIEZpbmFuY2lhbWllbnRvIiA9ICJHTSBGaW5hbmNpYWwgQ29sb21iaWEgUy5BLiBDb21wYW5pYSBEZSBGaW5hbmNpYW1pZW50byIsDQogICAgICAiSXRhw4PCuiIgPSAiSXRhdSIsDQogICAgICAiSkZLIENvb3BlcmF0aXZhIEZpw4PCs25hbmNpZXJhIj0gIkpGSyBDb29wZXJhdGl2YSBGaW5hbmNpZXJhIg0KICAgICkNCiAgKQ0KdGFibGUoZGYyJE5PTUJSRV9FTlRJREFEKQ0KI2xhcyBkaXN0cmlidWNpb25lcyBkZSBmcmVjdWVuY2lhIHNlIHZpc3VhbGl6YW4gbWVqb3IgY29tbyBkYXRhZnJhbWUuDQpEaXNGTm9tYnJlPC1hcy5kYXRhLmZyYW1lKHRhYmxlKGRmMiROT01CUkVfRU5USURBRCkpDQpiYXJwbG90KERpc0ZOb21icmUkRnJlcX5EaXNGTm9tYnJlJFZhcjEpICNncsOhZmljbyBwb3IgZGVmZWN0bw0KI3NlIHB1ZWRlIG1lam9yYXIgdXNhbmRvIGxhIGxpYnJlcsOtYSBnZ3Bsb3QyDQpgYGANCg0KYGBge3J9DQojaW5zdGFsbC5wYWNrYWdlcygiZ2dwbG90MiIpICNJbnN0YWxhbW9zIGxhIGxpYnJlcsOtYQ0KbGlicmFyeShnZ3Bsb3QyKSAjY2FyZ2Ftb3MgbGEgbGlicmVyw61hLg0KDQpnZ3Bsb3QoZGYyLCBhZXMoeCA9IE5PTUJSRV9FTlRJREFEKSkgKw0KICBnZW9tX2JhcihmaWxsID0gImxpZ2h0Z3JheSIpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICIgIiwNCiAgICB4ID0gIkVudGlkYWQgZmluYW5jaWVyYSIsDQogICAgeSA9ICJGcmVjdWVuY2lhIg0KICApICsNCiAgdGhlbWVfbWluaW1hbCgpKw0KICB0aGVtZSgNCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYpLA0KICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiksDQogICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiksDQogICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNikNCiAgKQ0KDQpgYGANCg0Kwr9Dw7NtbyBwb2RlbW9zIG1lam9yYXIgbGEgdmlzdWFsaXphY2nDs24/DQpgYGB7cn0NCmdncGxvdChkZjIsIGFlcyh4ID0gTk9NQlJFX0VOVElEQUQpKSArDQogIGdlb21fYmFyKGZpbGwgPSAibGlnaHRncmF5IikgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIiAiLA0KICAgIHggPSAiRW50aWRhZCBmaW5hbmNpZXJhIiwNCiAgICB5ID0gIkZyZWN1ZW5jaWEiDQogICkgKw0KICBjb29yZF9mbGlwKCkgKw0KICB0aGVtZV9taW5pbWFsKCkrDQogIHRoZW1lKA0KICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSA5KSwNCiAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gOSksDQogICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksDQogICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMikNCiAgKQ0KYGBgDQoNCsK/T3RyYSBpZGVhPw0KDQpgYGB7cn0NCg0KZGYydG9wMTA8LWFzLmRhdGEuZnJhbWUoc29ydCh0YWJsZShkZjIkTk9NQlJFX0VOVElEQUQpLCBkZWNyZWFzaW5nPVQpWzE6MTBdKQ0KDQpnZ3Bsb3QoZGYydG9wMTAsIGFlcyh4ID0gVmFyMSwgeT1GcmVxKSkgKw0KICBnZW9tX2NvbChmaWxsID0gImxpZ2h0Z3JheSIpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICIgIiwNCiAgICB4ID0gIkVudGlkYWQgZmluYW5jaWVyYSIsDQogICAgeSA9ICJGcmVjdWVuY2lhIg0KICApICsNCiAgY29vcmRfZmxpcCgpICsNCiAgdGhlbWVfbWluaW1hbCgpKw0KICB0aGVtZSgNCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTEpLA0KICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMSksDQogICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksDQogICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMikNCiAgKQ0KYGBgDQoNCkxhIGRpc3RyaWJ1Y2nDs24gZGUgZnJlY3VlbmNpYXMgbGEgcG9kZW1vcyBjb21wbGV0YXIgY29uIGxhIGZyZWN1ZW5jaWEgcmVsYXRpdmEgeSBlbCBwb3JjZW50YWplIGRlIHBhcnRpY2lwYWNpw7NuLg0KYGBge3J9DQpkZjJ0b3AxMDIgPC0gZGYydG9wMTAgJT4lDQogIG11dGF0ZSgNCiAgICBGcmVxUmVsID0gRnJlcSAvIHN1bShGcmVxKSwNCiAgICBQb3JjZW50YWplID0xMDAqRnJlcVJlbA0KICApDQpgYGANCg0KDQpFamVtcGxvIGRlIGRpYWdyYW1hIGRlIHNlY3RvcmVzDQpgYGB7cn0NCiMjI0RpYWdyYW1hIGRlIHNlY3RvcmVzDQpnZ3Bsb3QoZGYydG9wMTAyLCBhZXMoeCA9ICIiLCB5PUZyZXEsIGZpbGwgPSBWYXIxKSkgKw0KICBnZW9tX2NvbCh3aWR0aCA9IDEsIGNvbG9yPSJ3aGl0ZSIpICsNCiAgY29vcmRfcG9sYXIodGhldGEgPSAieSIpICsNCiAgZ2VvbV90ZXh0KA0KICAgIGFlcyhsYWJlbCA9IHNjYWxlczo6cGVyY2VudChyb3VuZChGcmVxUmVsLDIpKSksDQogICAgcG9zaXRpb24gPSBwb3NpdGlvbl9zdGFjayh2anVzdCA9IDAuNSksDQogICAgc2l6ZSA9IDMpKw0KICB0aGVtZV92b2lkKCkgKw0KICBsYWJzKHRpdGxlID0gIkRpc3RyaWJ1Y2nDs24gcG9yIGVudGlkYWQgZmluYW5jaWVyYSIsIGZpbGwgPSAiVmFyMSIpICsNCiAgdGhlbWUoDQogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDE2LCBmYWNlID0gImJvbGQiKQ0KICApDQoNCmBgYA0KDQpQb2RlbW9zIGFncmVnYXIgdG90YWxlcy4NCmBgYHtyfQ0KIyNhZ3JlZ2Ftb3MgZmlsYSBkZSB0b3RhbGVzDQpkZjJ0b3AxMDJUIDwtIGRmMnRvcDEwMiAlPiUNCiAgYmluZF9yb3dzKA0KICAgIGRhdGEuZnJhbWUoDQogICAgICBWYXIxID0gIlRvdGFsIiwNCiAgICAgIEZyZXEgPSBzdW0oZGYydG9wMTAyJEZyZXEpLA0KICAgICAgRnJlcVJlbCA9IHN1bShkZjJ0b3AxMDIkRnJlcVJlbCksDQogICAgICBQb3JjZW50YWplPSBzdW0oZGYydG9wMTAyJFBvcmNlbnRhamUpDQogICAgKQ0KICApDQpgYGANCg0KVGFibGEgZGUgZnJlY3VlbmNpYXMgcGFyYSBkYXRvcyBhZ3J1cGFkb3MgZW4gaW50ZXJ2YWxvcyBkZSBjbGFzZS4NCmBgYHtyfQ0KI2luc3RhbGwucGFja2FnZXMoImZkdGgiKSAjTGlicmVyw61hIHF1ZSBub3MgYXl1ZGEgYSBhZ3J1cGFyIGRhdG9zIGVuIGludGVydmFsb3MgZGUgY2xhc2UuDQpsaWJyYXJ5KGZkdGgpDQoNCmRmU0FMRE9DVEFTQUhPUlJPPC1mZHQoZGYkYCgyMCkgU0FMRE9fQ1RBU19BSE9SUk9fSEFTVEFfMVNNTUxWYCwgYnJlYWtzPSJTdHVyZ2VzIiwgcmlnaHQgPSBUKQ0KI0VzdGFkP3N0aWNhcyBkZXNjcmlwdGl2YXMgc2luIGRhdG9zIGFncnVwYWRvcw0Kc3VtbWFyeShkZiRgKDIwKSBTQUxET19DVEFTX0FIT1JST19IQVNUQV8xU01NTFZgKSAjRXN0YWTDrXN0aWNhcyBkZSByZXN1bWVuIHBhcmEgdW5hIHZhcmlhYmxlIGN1YW50aXRhdGl2YQ0KYGBgDQpFamVtcGxvIGRlIGhpc3RvZ3JhbWENCmBgYHtyfQ0KbmludD1yb3VuZCgxKygzLjMyMipsb2cxMChkaW0oZGYpWzFdKSksMCkNCnJhbmdvPW1heChkZiRgKDIwKSBTQUxET19DVEFTX0FIT1JST19IQVNUQV8xU01NTFZgKS1taW4oZGYkYCgyMCkgU0FMRE9fQ1RBU19BSE9SUk9fSEFTVEFfMVNNTUxWYCkNCmFtcGxpdHVkPXJhbmdvL25pbnQNCmBgYA0KDQoNCmBgYHtyfQ0KZ2dwbG90KGRmLCBhZXMoeCA9IGAoMjApIFNBTERPX0NUQVNfQUhPUlJPX0hBU1RBXzFTTU1MVmApKSArDQogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoPWFtcGxpdHVkLCBmaWxsID0gImxpZ2h0Ymx1ZSIpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICIgIiwNCiAgICB4ID0gIlNhbGRvIGN1ZW50YXMgZGUgYWhvcnJvIGhhc3RhIDFTTU1MViIsDQogICAgeSA9ICJGcmVjdWVuY2lhIg0KICApICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCg0KRXhjbHV5ZW5kbyBsb3MgdmFsb3JlcyBpZ3VhbGVzIGEgY2Vyby4NCg0KYGBge3J9DQpYPC1kZiRgKDIwKSBTQUxET19DVEFTX0FIT1JST19IQVNUQV8xU01NTFZgDQpOdW1DdWVudGFzPC1YW3doaWNoKChYPj0xMDAwMDApICYgKFg8PTIwMDAwMCkpXQ0Kcm91bmQoc3VtbWFyeShOdW1DdWVudGFzKSwxKQ0KYGBgDQoNCmBgYHtyfQ0KY2xhc3MoTnVtQ3VlbnRhcykNCmBgYA0KDQoNCg0KYGBge3J9DQpOdW1DdWVudGFzMjwtYXMuZGF0YS5mcmFtZShOdW1DdWVudGFzKQ0KDQpnZ3Bsb3QoTnVtQ3VlbnRhczIsIGFlcyh4ID1OdW1DdWVudGFzKSkgKw0KICBnZW9tX2hpc3RvZ3JhbShmaWxsID0gImxpZ2h0Ymx1ZSIsIGNvbG9yPSJibGFjayIpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICIgIiwNCiAgICB4ID0gIlNhbGRvIGN1ZW50YXMgZGUgYWhvcnJvIGhhc3RhIDFTTU1MViBlbGltaW5hbmRvIGNlcm9zIiwNCiAgICB5ID0gIkZyZWN1ZW5jaWEiDQogICkgKw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KDQpgYGB7cn0NCm51bWN1ZW50YXNkaXM8LWZkdChOdW1DdWVudGFzLCBicmVha3M9IlN0dXJnZXMiLCByaWdodCA9IFQpDQpgYGANClBlcmNlbnRpbGVzIHkgbWVkaWRhcyBkZSBkaXNwZXJzacOzbiBkZSBsYSB2YXJpYWJsZSBzYWxkbyBkZSBjdWVudGFzIGRlIGFob3Jyb3MNCg0KYGBge3J9DQpwZXJjczwtYygwLjEsIDAuMjUsIDAuNSwgMC43NSwgMC44LCAwLjksIDAuOTUpDQpxdWFudGlsZShYLCBwZXJjcykNCnZhcihYKSAjVmFyaWFuemENCnNkKFgpICNEZXN2aWFjacOzbiBlc3TDoW5kYXINCmBgYA0KDQoNCg0KDQoNCg==