Caso práctico: Gráficos de ingresos - EPH
Para esta práctica utilizaremos las variables de ingresos captadas por la Encuesta Permanente de Hogares
A continuación utilzaremos los conceptos abordados, para realizar gráficos a partir de las variables de ingresos.
#Cargamos las librerías a utilizar
library(tidyverse) # tiene ggplot, dplyr, tidyr, y otros
library(ggthemes) # estilos de gráficos
library(ggrepel) # etiquetas de texto más prolijas que las de ggplot
library(scales)
Individual_t119 <- read.table("../fuentes/usu_individual_t119.txt",
sep=";", dec=",", header = TRUE, fill = TRUE)
Por ejemplo, si observamos el ingreso de la ocupación principal:
hist_data <-Individual_t119 %>%
filter(P21>0)
ggplot(hist_data, aes(x = P21,weights = PONDIIO))+
geom_histogram(fill='salmon', color='grey25')+
scale_x_continuous(limits = c(0,50000))

En este gráfico, los posibles valores de p21 se dividen en 30 bins consecutivos y el gráfico muestra cuantas observaciones caen en cada uno de ellos
La función geom_density()
nos permite construir kernels de la distribución. Es particularmente útil cuando tenemos una variable continua, dado que los histogramas rompen esa sensación de continuidad.
Veamos un ejemplo sencillo con los ingresos de la ocupación principal. Luego iremos complejizandolo
kernel_data <-Individual_t119 %>%
filter(P21>0)
ggplot(kernel_data, aes(x = P21,weights = PONDIIO))+
geom_density(fill='salmon', color='grey25')+
scale_x_continuous(limits = c(0,50000))

El eje y no tiene demasiada interpretabilidad en los Kernel, porque hace a la forma en que se construyen las distribuciones.
El parametro adjust, dentro de la función geom_density
nos permite reducir o ampliar el rango de suavizado de la distribución. Su valor por default es 1. Veamos que sucede si lo seteamos en 2
ggplot(kernel_data, aes(x = P21,weights = PONDIIO))+
geom_density(adjust = 2,fill='salmon', color='grey25')+
scale_x_continuous(limits = c(0,50000))

Como es esperable, la distribución del ingreso tiene “picos” en los valores redondos, ya que la gente suele declarar un valor aproximado al ingreso efectivo que percibe. Nadie declara ingresos de 30001. Al suavizar la serie con un kernel, eliminamos ese efecto.Si seteamos el rango para el suavizado en valores menores a 1, podemos observar estos picos.
ggplot(kernel_data, aes(x = P21,weights = PONDIIO))+
geom_density(adjust = 0.01,fill='salmon', color='grey25')+
scale_x_continuous(limits = c(0,50000))

Geom Smooth
Para realizar estos gráficos, vamos a modificar un poco los datos:
- filtramos los ingresos iguales a 0.
- eliminamos las no respuestas de nivel educativo y las personas con educación especial.
- eliminamos las respuestas de tipo de establecimiento = ‘otros’.
- recodificamos las variables para que tengan nombres más sugestivos:
- Nivel educativo además la convertimos a factor, porque queremos explicitarle el orden de los valores con
levels()
. El “\n”" es un caracter especial que permite que el string continúe en la siguiente línea.
- Sexo.
- Tipo de establecimiento.
ggdata <- Individual_t119 %>%
filter(P21>0,
!is.na(NIVEL_ED),
NIVEL_ED!=7,
PP04A !=3) %>%
mutate(NIVEL_ED = factor(case_when(NIVEL_ED == 1 ~ 'Primaria \n Incompleta', # '\n' significa carriage return, o enter
NIVEL_ED == 2 ~ 'Primaria \n Completa',
NIVEL_ED == 3 ~ 'Secundaria \nIncompleta',
NIVEL_ED == 4 ~ 'Secundaria \nCompleta',
NIVEL_ED == 5 ~ 'Superior \nUniversitaria \nIncompleta',
NIVEL_ED == 6 ~ 'Superior \nUniversitaria \nCompleta',
FALSE ~ 'Otro'),
levels= c('Primaria \n Incompleta',
'Primaria \n Completa',
'Secundaria \nIncompleta',
'Secundaria \nCompleta',
'Superior \nUniversitaria \nIncompleta',
'Superior \nUniversitaria \nCompleta')),
Sexo = case_when(CH04 == 1 ~ 'Varón',
CH04 == 2 ~ 'Mujer'),
Establecimiento = case_when(PP04A == 1 ~ 'Estatal',
PP04A == 2 ~ 'Privado',
FALSE ~ 'Otro'))
ggdata
Para graficar un suavizado de las series, se utiliza la función geom_smooth()
. Con suavizado nos referimos al gráfico de un modelo realizado sobre los datos, que estima el valor en el punto x,y (para el grupo). Las regresiones lineales son un ejemplo de esto, aunque no el único, ni el que viene por default.
ggplot(ggdata, aes(CH06, P21, colour = Sexo, shape = Sexo, alpha = P21))+
geom_smooth() +
labs(
x = 'Edad',
y = 'ingreso',
title = 'Ingreso por ocupación principal',
subtitle = 'Según edad, nivel educativo y sexo') +
theme_minimal()+
scale_y_continuous(labels = comma)+
scale_alpha(guide = FALSE)+
facet_grid(.~NIVEL_ED)

Si corremos el comando geom_smooth()
por default, nos advierte que esta utilizando el método GAM, de general additive models.
el sombreado gris que envuelve cada línea es el intervalo de confianza de dicho punto (95% por default).
También podemos utilizar métodos lineales, agregando el parámetro method = 'lm'
. Haciendo esto, el gráfico muestra una regresión lineal simple. Si queremos otro tipo de regresión lineal, le podemos explicitar la fórmula.
En el ejemplo siguiente, utilizamos la formula \(y = \beta_0 +\beta_1x +\beta_2 x^2\).
ggplot(ggdata, aes(CH06, P21, colour = Sexo, weight = PONDIIO)) +
geom_smooth(method = "lm", formula = y ~ poly(x, 2)) +
labs(x = 'Edad',
y = 'ingreso',
title = 'Regresion cuadrática del Ingreso por ocupación principal respecto de la Edad',
subtitle = 'Según Nivel educativo y sexo') +
theme_minimal()+
facet_grid(. ~ NIVEL_ED)

Si quisiéramos, además de ver la relación entre ingreso, Edad, Sexo y Nivel educativo, incorporar el tipo de establecimiento,público o privado. Podemos facetear el gráfico por dos variables en lugar de una, lo que crea una matriz de gráficos según los cruces.
ggplot(ggdata, aes(CH06, P21, colour = Establecimiento, weight = PONDIIO)) +
geom_smooth(method = "lm") +
labs(
x = 'Edad',
y = 'ingreso',
title = 'Tendencia del ingreso por ocupación principal',
subtitle = 'Según edad, nivel educativo, sexo y tipo de establecimiento') +
theme_minimal()+
facet_grid(Sexo ~ NIVEL_ED)

ggsave(filename = paste0("../resultados/", "regresion lineal.png"),scale = 2)
Saving 16 x 10 in image
Treemaps (bonus track)
library(treemapify)
Trabajo doméstico no remunerado
trabajo_no_remunerado <- read_csv('../fuentes/prom_t_simul_dom_16_sexo__annio__g_edad_limpio.csv')
trabajo_no_remunerado %>%
filter(sexo != 'TOTAL', grupo_edad != 'TOTAL') %>%
mutate(promedio_hs_diarias = as.numeric(promedio_hs_diarias),
sexo = case_when(sexo=='m'~'Mujer',
sexo=='v'~'Varón')) %>%
ggplot(., aes(area = promedio_hs_diarias, fill = promedio_hs_diarias, label = grupo_edad,
subgroup = sexo)) +
geom_treemap() +
geom_treemap_subgroup_border() +
geom_treemap_subgroup_text(place = "centre", grow = T, alpha = 0.5, colour =
"black", fontface = "italic", min.size = 0) +
geom_treemap_text(colour = "white", place = "topleft", reflow = T)+
theme(legend.position = 'none')

LS0tCnRpdGxlOiAgVmlzdWFsaXphY2nDs24gZGUgbGEgaW5mb3JtYWNpw7NuCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgdG9jOiB5ZXMKICAgIHRvY19mbG9hdDogeWVzCmRhdGU6ICIiCnN1YnRpdGxlOiBQcsOhY3RpY2EgR3VpYWRhCi0tLQoKIyMjIENhc28gcHLDoWN0aWNvOiBHcsOhZmljb3MgZGUgaW5ncmVzb3MgLSBFUEgKClBhcmEgZXN0YSBwcsOhY3RpY2EgdXRpbGl6YXJlbW9zIGxhcyB2YXJpYWJsZXMgZGUgaW5ncmVzb3MgY2FwdGFkYXMgcG9yIGxhIFtFbmN1ZXN0YSBQZXJtYW5lbnRlIGRlIEhvZ2FyZXNdKGh0dHBzOi8vd3d3LmluZGVjLmdvYi5hci9pbmRlYy93ZWIvSW5zdGl0dWNpb25hbC1JbmRlYy1CYXNlc0RlRGF0b3MpCgpBIGNvbnRpbnVhY2nDs24gdXRpbHphcmVtb3MgbG9zIGNvbmNlcHRvcyBhYm9yZGFkb3MsIHBhcmEgcmVhbGl6YXIgZ3LDoWZpY29zIGEgcGFydGlyIGRlIGxhcyB2YXJpYWJsZXMgZGUgaW5ncmVzb3MuICAgICAgICAKCmBgYHtyLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQojQ2FyZ2Ftb3MgbGFzIGxpYnJlcsOtYXMgYSB1dGlsaXphcgoKbGlicmFyeSh0aWR5dmVyc2UpICMgdGllbmUgZ2dwbG90LCBkcGx5ciwgdGlkeXIsIHkgb3Ryb3MKbGlicmFyeShnZ3RoZW1lcykgICMgZXN0aWxvcyBkZSBncsOhZmljb3MKbGlicmFyeShnZ3JlcGVsKSAgICMgZXRpcXVldGFzIGRlIHRleHRvIG3DoXMgcHJvbGlqYXMgcXVlIGxhcyBkZSBnZ3Bsb3QKbGlicmFyeShzY2FsZXMpCmBgYAoKCmBgYHtyIHN0cmlwLndoaXRlPUZBTFNFfQoKSW5kaXZpZHVhbF90MTE5IDwtIHJlYWQudGFibGUoIi4uL2Z1ZW50ZXMvdXN1X2luZGl2aWR1YWxfdDExOS50eHQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXA9IjsiLCBkZWM9IiwiLCBoZWFkZXIgPSBUUlVFLCBmaWxsID0gVFJVRSkKCmBgYAoKCiMjIyMgW0hpc3RvZ3JhbWFzXShodHRwczovL2dncGxvdDIudGlkeXZlcnNlLm9yZy9yZWZlcmVuY2UvZ2VvbV9oaXN0b2dyYW0uaHRtbCkKCgpQb3IgZWplbXBsbywgc2kgb2JzZXJ2YW1vcyBlbCBpbmdyZXNvIGRlIGxhIG9jdXBhY2nDs24gcHJpbmNpcGFsOgoKYGBge3Igd2FybmluZz1GQUxTRX0KaGlzdF9kYXRhIDwtSW5kaXZpZHVhbF90MTE5ICU+JQogIGZpbHRlcihQMjE+MCkgCgpnZ3Bsb3QoaGlzdF9kYXRhLCBhZXMoeCA9IFAyMSx3ZWlnaHRzID0gUE9ORElJTykpKyAKZ2VvbV9oaXN0b2dyYW0oZmlsbD0nc2FsbW9uJywgY29sb3I9J2dyZXkyNScpKwpzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygwLDUwMDAwKSkKYGBgCgpFbiBlc3RlIGdyw6FmaWNvLCBsb3MgcG9zaWJsZXMgdmFsb3JlcyBkZSBwMjEgc2UgZGl2aWRlbiBlbiAzMCBfX2JpbnNfXyBjb25zZWN1dGl2b3MgeSBlbCBncsOhZmljbyBtdWVzdHJhIGN1YW50YXMgb2JzZXJ2YWNpb25lcyBjYWVuIGVuIGNhZGEgdW5vIGRlIGVsbG9zCgoKIyMjIyBbS2VybmVsc10oaHR0cHM6Ly9wbG90Lmx5L2dncGxvdDIvZ2VvbV9kZW5zaXR5LykKCkxhIGZ1bmNpw7NuICBgYGBnZW9tX2RlbnNpdHkoKWBgYCBub3MgcGVybWl0ZSBjb25zdHJ1aXIgX19rZXJuZWxzX18gZGUgbGEgZGlzdHJpYnVjacOzbi4gRXMgcGFydGljdWxhcm1lbnRlIMO6dGlsIGN1YW5kbyB0ZW5lbW9zIHVuYSB2YXJpYWJsZSBjb250aW51YSwgZGFkbyBxdWUgbG9zIGhpc3RvZ3JhbWFzIHJvbXBlbiBlc2Egc2Vuc2FjacOzbiBkZSBjb250aW51aWRhZC4KCgpWZWFtb3MgdW4gZWplbXBsbyBzZW5jaWxsbyBjb24gbG9zIGluZ3Jlc29zIGRlIGxhIG9jdXBhY2nDs24gcHJpbmNpcGFsLiBMdWVnbyBpcmVtb3MgY29tcGxlaml6YW5kb2xvIAoKCmBgYHtyIHdhcm5pbmc9RkFMU0V9Cmtlcm5lbF9kYXRhIDwtSW5kaXZpZHVhbF90MTE5ICU+JQogIGZpbHRlcihQMjE+MCkgCgpnZ3Bsb3Qoa2VybmVsX2RhdGEsIGFlcyh4ID0gUDIxLHdlaWdodHMgPSBQT05ESUlPKSkrIApnZW9tX2RlbnNpdHkoZmlsbD0nc2FsbW9uJywgY29sb3I9J2dyZXkyNScpKwpzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzID0gYygwLDUwMDAwKSkKYGBgCioqRWwgZWplIHkgbm8gdGllbmUgZGVtYXNpYWRhIGludGVycHJldGFiaWxpZGFkIGVuIGxvcyBLZXJuZWwsIHBvcnF1ZSBoYWNlIGEgbGEgZm9ybWEgZW4gcXVlIHNlIGNvbnN0cnV5ZW4gbGFzIGRpc3RyaWJ1Y2lvbmVzKiouIAoKRWwgcGFyYW1ldHJvIGFkanVzdCwgZGVudHJvIGRlIGxhIGZ1bmNpw7NuIGBgYGdlb21fZGVuc2l0eWBgYG5vcyBwZXJtaXRlIHJlZHVjaXIgbyBhbXBsaWFyIGVsIHJhbmdvIGRlIHN1YXZpemFkbyBkZSBsYSBkaXN0cmlidWNpw7NuLiBTdSB2YWxvciBwb3IgZGVmYXVsdCBlcyAxLiBWZWFtb3MgcXVlIHN1Y2VkZSBzaSBsbyBzZXRlYW1vcyBlbiAyIApgYGB7ciB3YXJuaW5nPUZBTFNFfQpnZ3Bsb3Qoa2VybmVsX2RhdGEsIGFlcyh4ID0gUDIxLHdlaWdodHMgPSBQT05ESUlPKSkrIApnZW9tX2RlbnNpdHkoYWRqdXN0ID0gMixmaWxsPSdzYWxtb24nLCBjb2xvcj0nZ3JleTI1JykrCnNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKDAsNTAwMDApKQoKYGBgCgpDb21vIGVzIGVzcGVyYWJsZSwgbGEgZGlzdHJpYnVjacOzbiBkZWwgaW5ncmVzbyB0aWVuZSAicGljb3MiIGVuIGxvcyB2YWxvcmVzIHJlZG9uZG9zLCB5YSBxdWUgbGEgZ2VudGUgc3VlbGUgZGVjbGFyYXIgdW4gdmFsb3IgYXByb3hpbWFkbyBhbCBpbmdyZXNvIGVmZWN0aXZvIHF1ZSBwZXJjaWJlLiBOYWRpZSBkZWNsYXJhIGluZ3Jlc29zIGRlIDMwMDAxLiBBbCBzdWF2aXphciBsYSBzZXJpZSBjb24gdW4ga2VybmVsLCBlbGltaW5hbW9zIGVzZSBlZmVjdG8uU2kgc2V0ZWFtb3MgZWwgcmFuZ28gcGFyYSBlbCBzdWF2aXphZG8gZW4gdmFsb3JlcyBtZW5vcmVzIGEgMSwgcG9kZW1vcyBvYnNlcnZhciBlc3RvcyBwaWNvcy4KCmBgYHtyIHdhcm5pbmc9RkFMU0V9CmdncGxvdChrZXJuZWxfZGF0YSwgYWVzKHggPSBQMjEsd2VpZ2h0cyA9IFBPTkRJSU8pKSsgCmdlb21fZGVuc2l0eShhZGp1c3QgPSAwLjAxLGZpbGw9J3NhbG1vbicsIGNvbG9yPSdncmV5MjUnKSsKc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMoMCw1MDAwMCkpCmBgYAoKCiMjIyMgR2VvbSBTbW9vdGgKClBhcmEgcmVhbGl6YXIgZXN0b3MgZ3LDoWZpY29zLCB2YW1vcyBhIG1vZGlmaWNhciB1biBwb2NvIGxvcyBkYXRvczoKCi0gZmlsdHJhbW9zIGxvcyBpbmdyZXNvcyBpZ3VhbGVzIGEgMC4KLSBlbGltaW5hbW9zIGxhcyBubyByZXNwdWVzdGFzIGRlIG5pdmVsIGVkdWNhdGl2byB5IGxhcyBwZXJzb25hcyBjb24gZWR1Y2FjacOzbiBlc3BlY2lhbC4KLSBlbGltaW5hbW9zIGxhcyByZXNwdWVzdGFzIGRlIHRpcG8gZGUgZXN0YWJsZWNpbWllbnRvID0gJ290cm9zJy4KLSByZWNvZGlmaWNhbW9zIGxhcyB2YXJpYWJsZXMgcGFyYSBxdWUgdGVuZ2FuIG5vbWJyZXMgbcOhcyBzdWdlc3Rpdm9zOgogICAgLSBfX05pdmVsIGVkdWNhdGl2b19fIGFkZW3DoXMgbGEgY29udmVydGltb3MgYSBmYWN0b3IsIHBvcnF1ZSBxdWVyZW1vcyBleHBsaWNpdGFybGUgZWwgb3JkZW4gZGUgbG9zIHZhbG9yZXMgY29uIGBgYGxldmVscygpYGBgLiBFbCAiXFxuIiIgZXMgdW4gX2NhcmFjdGVyIGVzcGVjaWFsXyBxdWUgcGVybWl0ZSBxdWUgZWwgc3RyaW5nIGNvbnRpbsO6ZSBlbiBsYSBzaWd1aWVudGUgbMOtbmVhLgogICAgLSBTZXhvLgogICAgLSBUaXBvIGRlIGVzdGFibGVjaW1pZW50by4KICAgIAogICAgCmBgYHtyIH0KZ2dkYXRhIDwtIEluZGl2aWR1YWxfdDExOSAlPiUgCiAgZmlsdGVyKFAyMT4wLAogICAgICAgICAhaXMubmEoTklWRUxfRUQpLAogICAgICAgICBOSVZFTF9FRCE9NywgCiAgICAgICAgIFBQMDRBICE9MykgJT4lIAogIG11dGF0ZShOSVZFTF9FRCA9IGZhY3RvcihjYXNlX3doZW4oTklWRUxfRUQgPT0gMSAgfiAnUHJpbWFyaWEgXG4gSW5jb21wbGV0YScsICMgJ1xuJyBzaWduaWZpY2EgY2FycmlhZ2UgcmV0dXJuLCBvIGVudGVyCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBOSVZFTF9FRCA9PSAyICB+ICdQcmltYXJpYSBcbiBDb21wbGV0YScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBOSVZFTF9FRCA9PSAzICB+ICdTZWN1bmRhcmlhIFxuSW5jb21wbGV0YScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBOSVZFTF9FRCA9PSA0ICB+ICdTZWN1bmRhcmlhIFxuQ29tcGxldGEnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTklWRUxfRUQgPT0gNSAgfiAnU3VwZXJpb3IgXG5Vbml2ZXJzaXRhcmlhIFxuSW5jb21wbGV0YScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBOSVZFTF9FRCA9PSA2ICB+ICdTdXBlcmlvciBcblVuaXZlcnNpdGFyaWEgXG5Db21wbGV0YScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGQUxTRSAgICAgICAgICB+ICdPdHJvJyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscz0gYygnUHJpbWFyaWEgXG4gSW5jb21wbGV0YScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnUHJpbWFyaWEgXG4gQ29tcGxldGEnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ1NlY3VuZGFyaWEgXG5JbmNvbXBsZXRhJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdTZWN1bmRhcmlhIFxuQ29tcGxldGEnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ1N1cGVyaW9yIFxuVW5pdmVyc2l0YXJpYSBcbkluY29tcGxldGEnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ1N1cGVyaW9yIFxuVW5pdmVyc2l0YXJpYSBcbkNvbXBsZXRhJykpLAogICAgICAgICBTZXhvICAgICA9IGNhc2Vfd2hlbihDSDA0ID09IDEgfiAnVmFyw7NuJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQ0gwNCA9PSAyIH4gJ011amVyJyksCiAgICAgICAgIEVzdGFibGVjaW1pZW50byAgICA9IGNhc2Vfd2hlbihQUDA0QSA9PSAxIH4gJ0VzdGF0YWwnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUFAwNEEgPT0gMiB+ICdQcml2YWRvJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZBTFNFICAgICAgfiAnT3RybycpKQoKZ2dkYXRhCmBgYAoKUGFyYSBncmFmaWNhciB1biBzdWF2aXphZG8gZGUgbGFzIHNlcmllcywgc2UgdXRpbGl6YSBsYSBmdW5jacOzbiBbYGBgZ2VvbV9zbW9vdGgoKWBgYF0oaHR0cDovL2dncGxvdDIudGlkeXZlcnNlLm9yZy9yZWZlcmVuY2UvZ2VvbV9zbW9vdGguaHRtbCkuIENvbiBzdWF2aXphZG8gbm9zIHJlZmVyaW1vcyBhbCBncsOhZmljbyBkZSB1biBtb2RlbG8gcmVhbGl6YWRvIHNvYnJlIGxvcyBkYXRvcywgcXVlIGVzdGltYSBlbCB2YWxvciBlbiBlbCBwdW50byB4LHkgKHBhcmEgZWwgZ3J1cG8pLiBMYXMgcmVncmVzaW9uZXMgbGluZWFsZXMgc29uIHVuIGVqZW1wbG8gZGUgZXN0bywgYXVucXVlIG5vIGVsIMO6bmljbywgbmkgZWwgcXVlIHZpZW5lIHBvciBkZWZhdWx0LgoKYGBge3IgZmlnLmhlaWdodD01LCBmaWcud2lkdGg9OH0KZ2dwbG90KGdnZGF0YSwgYWVzKENIMDYsIFAyMSwgY29sb3VyID0gU2V4bywgc2hhcGUgPSBTZXhvLCBhbHBoYSA9IFAyMSkpKwogIGdlb21fc21vb3RoKCkgKyAKICBsYWJzKAogICAgeCA9ICdFZGFkJywKICAgIHkgPSAnaW5ncmVzbycsCiAgICB0aXRsZSA9ICdJbmdyZXNvIHBvciBvY3VwYWNpw7NuIHByaW5jaXBhbCcsCiAgICBzdWJ0aXRsZSA9ICdTZWfDum4gZWRhZCwgbml2ZWwgZWR1Y2F0aXZvIHkgc2V4bycpICsKICB0aGVtZV9taW5pbWFsKCkrCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGNvbW1hKSsKICBzY2FsZV9hbHBoYShndWlkZSA9IEZBTFNFKSsKICBmYWNldF9ncmlkKC5+TklWRUxfRUQpCmBgYAoKClNpIGNvcnJlbW9zIGVsIGNvbWFuZG8gYGBgZ2VvbV9zbW9vdGgoKWBgYCAgcG9yIGRlZmF1bHQsIG5vcyBhZHZpZXJ0ZSBxdWUgZXN0YSB1dGlsaXphbmRvIGVsIG3DqXRvZG8gR0FNLCBkZSBbZ2VuZXJhbCBhZGRpdGl2ZSBtb2RlbHNdKGh0dHBzOi8vbS1jbGFyay5naXRodWIuaW8vZ2VuZXJhbGl6ZWQtYWRkaXRpdmUtbW9kZWxzL2J1aWxkaW5nX2dhbS5odG1sKS4gICAgICAKCmVsIF9fc29tYnJlYWRvIGdyaXNfXyBxdWUgZW52dWVsdmUgY2FkYSBsw61uZWEgZXMgZWwgaW50ZXJ2YWxvIGRlIGNvbmZpYW56YSBkZSBkaWNobyBwdW50byAoOTUlIHBvciBkZWZhdWx0KS4KClRhbWJpw6luIHBvZGVtb3MgdXRpbGl6YXIgbcOpdG9kb3MgbGluZWFsZXMsIGFncmVnYW5kbyBlbCBwYXLDoW1ldHJvIGBgYG1ldGhvZCA9ICdsbSdgYGAuIEhhY2llbmRvIGVzdG8sIGVsIGdyw6FmaWNvIG11ZXN0cmEgdW5hIHJlZ3Jlc2nDs24gbGluZWFsIHNpbXBsZS4gU2kgcXVlcmVtb3Mgb3RybyB0aXBvIGRlIHJlZ3Jlc2nDs24gbGluZWFsLCBsZSBwb2RlbW9zIGV4cGxpY2l0YXIgbGEgZsOzcm11bGEuICAgIApFbiBlbCBlamVtcGxvIHNpZ3VpZW50ZSwgdXRpbGl6YW1vcyBsYSBmb3JtdWxhICR5ID0gXGJldGFfMCArXGJldGFfMXggK1xiZXRhXzIgeF4yJC4KCmBgYHtyIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTh9CgpnZ3Bsb3QoZ2dkYXRhLCBhZXMoQ0gwNiwgUDIxLCBjb2xvdXIgPSBTZXhvLCB3ZWlnaHQgPSBQT05ESUlPKSkgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIGZvcm11bGEgPSB5IH4gcG9seSh4LCAyKSkgKwogIGxhYnMoeCA9ICdFZGFkJywKICAgICAgIHkgPSAnaW5ncmVzbycsCiAgICAgICB0aXRsZSA9ICdSZWdyZXNpb24gY3VhZHLDoXRpY2EgZGVsIEluZ3Jlc28gcG9yIG9jdXBhY2nDs24gcHJpbmNpcGFsIHJlc3BlY3RvIGRlIGxhIEVkYWQnLAogICAgICAgc3VidGl0bGUgPSAnU2Vnw7puIE5pdmVsIGVkdWNhdGl2byB5IHNleG8nKSArCiAgdGhlbWVfbWluaW1hbCgpKwogIGZhY2V0X2dyaWQoLiB+IE5JVkVMX0VEKQpgYGAKCgpTaSBxdWlzacOpcmFtb3MsIGFkZW3DoXMgZGUgdmVyIGxhIHJlbGFjacOzbiBlbnRyZSBpbmdyZXNvLCBFZGFkLCBTZXhvIHkgTml2ZWwgZWR1Y2F0aXZvLCBpbmNvcnBvcmFyIGVsIHRpcG8gZGUgZXN0YWJsZWNpbWllbnRvLHDDumJsaWNvIG8gcHJpdmFkby4gUG9kZW1vcyBmYWNldGVhciBlbCBncsOhZmljbyBwb3IgZG9zIHZhcmlhYmxlcyBlbiBsdWdhciBkZSB1bmEsIGxvIHF1ZSBjcmVhIHVuYSBfX21hdHJpeiBkZSBncsOhZmljb3NfXyBzZWfDum4gbG9zIGNydWNlcy4KCmBgYHtyIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTh9CmdncGxvdChnZ2RhdGEsIGFlcyhDSDA2LCBQMjEsIGNvbG91ciA9IEVzdGFibGVjaW1pZW50bywgd2VpZ2h0ID0gUE9ORElJTykpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iKSArCiAgbGFicygKICB4ID0gJ0VkYWQnLAogIHkgPSAnaW5ncmVzbycsCiAgdGl0bGUgPSAnVGVuZGVuY2lhIGRlbCBpbmdyZXNvIHBvciBvY3VwYWNpw7NuIHByaW5jaXBhbCcsCiAgc3VidGl0bGUgPSAnU2Vnw7puIGVkYWQsIG5pdmVsIGVkdWNhdGl2bywgc2V4byB5IHRpcG8gZGUgZXN0YWJsZWNpbWllbnRvJykgKwogIHRoZW1lX21pbmltYWwoKSsKICBmYWNldF9ncmlkKFNleG8gfiBOSVZFTF9FRCkKCmdnc2F2ZShmaWxlbmFtZSA9IHBhc3RlMCgiLi4vcmVzdWx0YWRvcy8iLCAicmVncmVzaW9uIGxpbmVhbC5wbmciKSxzY2FsZSA9IDIpCmBgYAoKCgojIyMjIFRyZWVtYXBzIChib251cyB0cmFjaykKCmBgYHtyfQpsaWJyYXJ5KHRyZWVtYXBpZnkpCmBgYAoKCltUcmFiYWpvIGRvbcOpc3RpY28gbm8gcmVtdW5lcmFkb10oaHR0cHM6Ly9kYXRhLmJ1ZW5vc2FpcmVzLmdvYi5hci9kYXRhc2V0L3RyYWJham8tZG9tZXN0aWNvLW5vLXJlbXVuZXJhZG8pCgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KdHJhYmFqb19ub19yZW11bmVyYWRvIDwtIHJlYWRfY3N2KCcuLi9mdWVudGVzL3Byb21fdF9zaW11bF9kb21fMTZfc2V4b19fYW5uaW9fX2dfZWRhZF9saW1waW8uY3N2JykKYGBgCgpgYGB7cn0KIHRyYWJham9fbm9fcmVtdW5lcmFkbyAlPiUgCiAgZmlsdGVyKHNleG8gIT0gJ1RPVEFMJywgZ3J1cG9fZWRhZCAhPSAnVE9UQUwnKSAlPiUKICAgbXV0YXRlKHByb21lZGlvX2hzX2RpYXJpYXMgPSBhcy5udW1lcmljKHByb21lZGlvX2hzX2RpYXJpYXMpLAogICAgICAgICAgc2V4byA9IGNhc2Vfd2hlbihzZXhvPT0nbSd+J011amVyJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgc2V4bz09J3YnfidWYXLDs24nKSkgJT4lIAogIGdncGxvdCguLCBhZXMoYXJlYSA9IHByb21lZGlvX2hzX2RpYXJpYXMsIGZpbGwgPSBwcm9tZWRpb19oc19kaWFyaWFzLCBsYWJlbCA9IGdydXBvX2VkYWQsCiAgICAgICAgICAgICAgICBzdWJncm91cCA9IHNleG8pKSArCiAgZ2VvbV90cmVlbWFwKCkgKwogIGdlb21fdHJlZW1hcF9zdWJncm91cF9ib3JkZXIoKSArCiAgZ2VvbV90cmVlbWFwX3N1Ymdyb3VwX3RleHQocGxhY2UgPSAiY2VudHJlIiwgZ3JvdyA9IFQsIGFscGhhID0gMC41LCBjb2xvdXIgPQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJibGFjayIsIGZvbnRmYWNlID0gIml0YWxpYyIsIG1pbi5zaXplID0gMCkgKwogIGdlb21fdHJlZW1hcF90ZXh0KGNvbG91ciA9ICJ3aGl0ZSIsIHBsYWNlID0gInRvcGxlZnQiLCByZWZsb3cgPSBUKSsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAnbm9uZScpCmBgYAoKCgoK