Bibliotecas
library(tidyverse) # Manipulación de datos_eva y gráficos
library(janitor) # Edición de nombres en bases de datos_eva
library(readxl) # Lectura de archivos de excel
library(DT) # Tablas interactivas en documentos HTML
library(plotly) # Gráficos interactivos en documentos HTML
datos_eva
datos_eva <-
read_csv("Evaluaciones_Agropecuarias_Municipales___EVA._2019_-_2021._Base_Agr_cola.csv") %>%
clean_names() %>%
mutate(area_perdida_p = (1 - (area_cosechada / area_sembrada)) * 100,
area_perdida_ha = area_sembrada - area_cosechada)
datos_eva %>% head()
Datos encuesta
mis_nombres <- c(
"promedio_academico",
"tiempo_casa_u",
"distancia_casa_u",
"abandonar_universidad",
"medio_transporte",
"electivas",
"numero_azar",
"trabajo",
"matematicas",
"pregunta_tiempo",
"sistema_educativo"
)
encuesta <- read_excel("Encuesta-Respuestas.xlsx") %>%
set_names(mis_nombres) %>%
mutate(
promedio_academico = as.numeric(promedio_academico),
tiempo_casa_u = str_extract_all(
string = tiempo_casa_u,
pattern = "[0-9]+",
simplify = TRUE
),
tiempo_casa_u = as.numeric(tiempo_casa_u),
distancia_casa_u = str_replace_all(distancia_casa_u,
pattern = "km",
replacement = ""),
distancia_casa_u = str_replace_all(distancia_casa_u,
pattern = ",",
replacement = "."),
distancia_casa_u = as.numeric(distancia_casa_u),
matematicas = as.numeric(matematicas),
velocidad = distancia_casa_u / tiempo_casa_u
)
encuesta
ggplot2
Guía
Capas
ggplot2
Estructura
básica
data %>%
ggplot(mapping = aes(x = ..., y = ...)) +
geom_...
Tipos de gráficos
Cantidades
- ¿Cuántos registros hay por cada número elegido al azar de la
encuesta?
encuesta %>%
count(numero_azar) %>%
ggplot(aes(x = numero_azar, y = n)) +
geom_col()

- ¿Cuál es el top 10 de cultivos con mayor número de registros?
datos_eva %>%
count(cultivo, sort = TRUE) %>%
slice(1:10) %>%
ggplot(aes(x = cultivo, y = n)) +
geom_col()

- Podemos mejorar el gráfico agregando varias características
adicionales:
- Reordenar los cultivos por número de registros
- Colores a las barras
- Etiquetas al eje x, al eje y y título del gráfico
datos_eva %>%
count(cultivo, sort = TRUE) %>%
slice(1:10) %>%
ggplot(aes(x = reorder(cultivo, n), y = n)) +
geom_col(color = "black", fill = "red") +
labs(x = "Cultivo", y = "Total",
title = "Top 10 de cultivos con mayor registros",
subtitle = "EVAs Colombia - 2021")

- Colores para cada barra: con “show.legend = FALSE” quitamos la
leyenda.
datos_eva %>%
count(cultivo, sort = TRUE) %>%
slice(1:10) %>%
ggplot(aes(x = reorder(cultivo, n), y = n, color = cultivo, fill = cultivo)) +
geom_col(show.legend = FALSE) +
labs(x = "Cultivo", y = "n",
title = "Top 10 de cultivos con mayor registros")

- Colores para cada barra: con “show.legend = FALSE” quitamos la
leyenda y además rotamos las coordenadas:
datos_eva %>%
count(cultivo, sort = TRUE) %>%
slice(1:10) %>%
ggplot(aes(x = reorder(cultivo, n), y = n, color = cultivo, fill = cultivo)) +
geom_col(show.legend = FALSE) +
labs(x = "Cultivo", y = "n",
title = "Top 10 de cultivos con mayor registros") +
coord_flip()

- Podemos representar con barras cualquier otra cantidad, no sólo las
frecuencias (conteos). Por ejemplo, podemos graficar el top 10 del
promedio de rendimiento.
datos_eva %>%
group_by(cultivo) %>%
summarise(promedio = mean(rendimiento)) %>%
ungroup() %>%
arrange(desc(promedio)) %>%
slice(1:10) %>%
ggplot(aes(x = reorder(cultivo, promedio), y = promedio)) +
geom_col() +
coord_flip() +
labs(x = "Cultivo", y = "Rendimiento (ton/ha)")

- ¿Cuál es el top 10 de cultivos con mayor área perdida (%) promedio?
Nota: aplicamos un filtro para mantener sólo cultivos
que superan los 5 municipios con registro.
datos_eva %>%
group_by(cultivo) %>%
summarise(promedio = mean(area_perdida_p),
N = n()) %>%
ungroup() %>%
filter(N > 5) %>%
arrange(desc(promedio)) %>%
slice(1:10) %>%
ggplot(aes(x = reorder(cultivo, promedio), y = promedio)) +
geom_col() +
coord_flip()

Proporciones
- ¿Cómo es la distribución porcencual de las personas que trabajan y
aquellos que han pensado en abandonar la universidad?
encuesta %>%
count(trabajo, abandonar_universidad) %>%
ggplot(aes(x = trabajo, y = n, fill = abandonar_universidad)) +
geom_col(position = "fill")

Distribuciones
Individuales
- ¿Cómo es la distribución del rendimiento para el cultivo de
café?
datos_eva %>%
filter(cultivo == "Café") %>%
ggplot(aes(x = rendimiento)) +
geom_histogram(color = "black")

- El mismo gráfico anterior puede ser representado a través de
densidades:
datos_eva %>%
filter(cultivo == "Café") %>%
ggplot(aes(x = rendimiento)) +
geom_density(fill = "orange")

- Podemos calcular el promedio y la mediana y agregarlo al gráfico
anterior:
promedio_rto_cafe <-
datos_eva %>%
filter(cultivo == "Café") %>%
pull(rendimiento) %>%
mean()
mediana_rto_cafe <-
datos_eva %>%
filter(cultivo == "Café") %>%
pull(rendimiento) %>%
median()
datos_eva %>%
filter(cultivo == "Café") %>%
ggplot(aes(x = rendimiento)) +
geom_density() +
geom_vline(xintercept = promedio_rto_cafe, color = "blue", lty = 2) +
geom_vline(xintercept = mediana_rto_cafe, color = "red", lty = 2)

Comparativas
- ¿Cómo es la distribución de cada departamento para el rendimiento en
el cultivo de café?
datos_eva %>%
filter(cultivo == "Café") %>%
ggplot(aes(x = departamento, y = rendimiento)) +
geom_boxplot() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))

- Teniendo en cuenta que el cultivo de maíz es transitorio, ¿cuál
período presenta mayor uniformidad en el rendimiento?
datos_eva %>%
filter(cultivo == "Maíz") %>%
ggplot(aes(x = periodo, y = rendimiento)) +
geom_boxplot()

- El mismo resultado anterior puede ser representado a través de
densidades:
datos_eva %>%
filter(cultivo == "Maíz") %>%
ggplot(aes(x = rendimiento, color = periodo)) +
geom_density()

- ¿Podemos agregar una tercera variable al gráfico anterior?
datos_eva %>%
filter(cultivo == "Maíz") %>%
ggplot(aes(x = departamento, y = rendimiento, fill = periodo)) +
geom_boxplot() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))

- ¿Existen diferencias en la distribución del promedio académico para
las personas que poseen trabajo?
encuesta %>%
ggplot(aes(x = trabajo, y = promedio_academico)) +
geom_boxplot()

Relaciones x-y
- ¿Existe alguna asociación entre el área perdida (%) y el rendimiento
para el cultivo de maíz?
datos_eva %>%
filter(cultivo == "Maíz") %>%
ggplot(aes(x = area_perdida_p, y = rendimiento)) +
geom_point()

- Con los datos de la encuesta, ¿Cuál es la relación de la distancia
con la velocidad?
encuesta %>%
ggplot(aes(x = distancia_casa_u, y = velocidad)) +
geom_point()

Gráficos
interactivos
Gráfico 1
ggplotly(
encuesta %>%
ggplot(aes(x = distancia_casa_u, y = velocidad)) +
geom_point()
)
Gráfico 2
ggplotly(
datos_eva %>%
filter(cultivo == "Maíz") %>%
ggplot(aes(x = rendimiento, color = periodo)) +
geom_density()
)
LS0tDQp0aXRsZTogIlZpc3VhbGl6YWNpb25lcyBjb24gUiINCnN1YnRpdGxlOiAiZ2dwbG90MiINCmF1dGhvcjogIkVkaW1lciBEYXZpZCBKYXJhbWlsbG8iDQpkYXRlOiAiMzEtMTAtMjAyMiINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDoNCiAgICB0b2M6IHRydWUNCiAgICB0b2NfZGVwdGg6IDUNCiAgICB0b2NfZmxvYXQ6IHRydWUNCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUNCiAgICB0aGVtZTogY29zbW8NCiAgICBoaWdobGlnaHQ6IGJyZWV6ZWRhcmsNCiAgICBkZl9wcmludDogcGFnZWQNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQotLS0NCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsIGV2YWwgPSBUUlVFLCBmaWcuYWxpZ24gPSAiY2VudGVyIiwNCiAgICAgICAgICAgICAgICAgICAgICBmaWcud2lkdGggPSA1LjUsIGZpZy5oZWlnaHQgPSA0LjUsIHdhcm5pbmcgPSBGQUxTRSwNCiAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlID0gRkFMU0UpDQpgYGANCg0KIyBCaWJsaW90ZWNhcw0KDQpgYGB7cn0NCmxpYnJhcnkodGlkeXZlcnNlKSAjIE1hbmlwdWxhY2nDs24gZGUgZGF0b3NfZXZhIHkgZ3LDoWZpY29zDQpsaWJyYXJ5KGphbml0b3IpICAgIyBFZGljacOzbiBkZSBub21icmVzIGVuIGJhc2VzIGRlIGRhdG9zX2V2YQ0KbGlicmFyeShyZWFkeGwpICAgICMgTGVjdHVyYSBkZSBhcmNoaXZvcyBkZSBleGNlbA0KbGlicmFyeShEVCkgICAgICAgICMgVGFibGFzIGludGVyYWN0aXZhcyBlbiBkb2N1bWVudG9zIEhUTUwNCmxpYnJhcnkocGxvdGx5KSAgICAjIEdyw6FmaWNvcyBpbnRlcmFjdGl2b3MgZW4gZG9jdW1lbnRvcyBIVE1MDQpgYGANCg0KIyBSZWZlcmVuY2lhcw0KDQotIFtGcm9tIERhdGEgdG8gVml6XShodHRwczovL3d3dy5kYXRhLXRvLXZpei5jb20vKQ0KLSBbVGhlIFIgR3JhcGggR2FsbGVyeV0oaHR0cHM6Ly9yLWdyYXBoLWdhbGxlcnkuY29tL2luZGV4Lmh0bWwpDQotIFtgZ2dwbG90MmBdKGh0dHBzOi8vci1ncmFwaC1nYWxsZXJ5LmNvbS9nZ3Bsb3QyLXBhY2thZ2UuaHRtbCkNCi0gW0NvbG9ycyBpbiBSXShodHRwOi8vd3d3LnN0YXQuY29sdW1iaWEuZWR1L350emhlbmcvZmlsZXMvUmNvbG9yLnBkZikNCi0gW0NvbG9ycyBpbiBSXShodHRwOi8vd3d3LnN0aGRhLmNvbS9lbmdsaXNoL3dpa2kvY29sb3JzLWluLXIpDQotIFtIZXhhZGVjaW1hbCBDb2xvcnNdKGh0dHBzOi8vd3d3Lnczc2Nob29scy5jb20vY29sb3JzL2NvbG9yc19oZXhhZGVjaW1hbC5hc3ApDQotIFtHYWxlcsOtYSBkZSBncsOhZmljb3NdKGh0dHBzOi8vd3d3LmRhdGF2aXotaW5zcGlyYXRpb24uY29tLykNCg0KIyBkYXRvc19ldmENCg0KYGBge3J9DQpkYXRvc19ldmEgPC0NCiAgcmVhZF9jc3YoIkV2YWx1YWNpb25lc19BZ3JvcGVjdWFyaWFzX011bmljaXBhbGVzX19fRVZBLl8yMDE5Xy1fMjAyMS5fQmFzZV9BZ3JfY29sYS5jc3YiKSAlPiUNCiAgY2xlYW5fbmFtZXMoKSAlPiUgDQogIG11dGF0ZShhcmVhX3BlcmRpZGFfcCA9ICgxIC0gKGFyZWFfY29zZWNoYWRhIC8gYXJlYV9zZW1icmFkYSkpICogMTAwLA0KICAgICAgICAgYXJlYV9wZXJkaWRhX2hhID0gYXJlYV9zZW1icmFkYSAtIGFyZWFfY29zZWNoYWRhKQ0KDQpkYXRvc19ldmEgJT4lIGhlYWQoKQ0KYGBgDQoNCiMgRGF0b3MgZW5jdWVzdGENCg0KYGBge3J9DQptaXNfbm9tYnJlcyA8LSBjKA0KICAicHJvbWVkaW9fYWNhZGVtaWNvIiwNCiAgInRpZW1wb19jYXNhX3UiLA0KICAiZGlzdGFuY2lhX2Nhc2FfdSIsDQogICJhYmFuZG9uYXJfdW5pdmVyc2lkYWQiLA0KICAibWVkaW9fdHJhbnNwb3J0ZSIsDQogICJlbGVjdGl2YXMiLA0KICAibnVtZXJvX2F6YXIiLA0KICAidHJhYmFqbyIsDQogICJtYXRlbWF0aWNhcyIsDQogICJwcmVndW50YV90aWVtcG8iLA0KICAic2lzdGVtYV9lZHVjYXRpdm8iDQopDQoNCmVuY3Vlc3RhIDwtIHJlYWRfZXhjZWwoIkVuY3Vlc3RhLVJlc3B1ZXN0YXMueGxzeCIpICU+JQ0KICBzZXRfbmFtZXMobWlzX25vbWJyZXMpICU+JQ0KICBtdXRhdGUoDQogICAgcHJvbWVkaW9fYWNhZGVtaWNvID0gYXMubnVtZXJpYyhwcm9tZWRpb19hY2FkZW1pY28pLA0KICAgIHRpZW1wb19jYXNhX3UgPSBzdHJfZXh0cmFjdF9hbGwoDQogICAgICBzdHJpbmcgPSB0aWVtcG9fY2FzYV91LA0KICAgICAgcGF0dGVybiA9ICJbMC05XSsiLA0KICAgICAgc2ltcGxpZnkgPSBUUlVFDQogICAgKSwNCiAgICB0aWVtcG9fY2FzYV91ID0gYXMubnVtZXJpYyh0aWVtcG9fY2FzYV91KSwNCiAgICBkaXN0YW5jaWFfY2FzYV91ID0gc3RyX3JlcGxhY2VfYWxsKGRpc3RhbmNpYV9jYXNhX3UsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXR0ZXJuID0gImttIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcGxhY2VtZW50ID0gIiIpLA0KICAgIGRpc3RhbmNpYV9jYXNhX3UgPSBzdHJfcmVwbGFjZV9hbGwoZGlzdGFuY2lhX2Nhc2FfdSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiLCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXBsYWNlbWVudCA9ICIuIiksDQogICAgZGlzdGFuY2lhX2Nhc2FfdSA9IGFzLm51bWVyaWMoZGlzdGFuY2lhX2Nhc2FfdSksDQogICAgbWF0ZW1hdGljYXMgPSBhcy5udW1lcmljKG1hdGVtYXRpY2FzKSwNCiAgICB2ZWxvY2lkYWQgPSBkaXN0YW5jaWFfY2FzYV91IC8gdGllbXBvX2Nhc2FfdQ0KICApIA0KDQplbmN1ZXN0YQ0KYGBgDQoNCiMgYGdncGxvdDJgDQoNCiMjIEd1w61hDQoNCi0gW0d1w61hIGRlIHZpc3VhbGl6YWNpw7NuIHVzYW5kbyBnZ3Bsb3QyXShodHRwczovL2RpZWdva296LmdpdGh1Yi5pby9pbnRyb19kcy9mdWVudGVzL2dncGxvdDItY2hlYXRzaGVldC0yLjEtU3BhbmlzaC5wZGYpDQoNCjxjZW50ZXI+DQo8aW1nIHNyYyA9ICJodHRwczovL3ItZ3JhcGgtZ2FsbGVyeS5jb20vaW1nL290aGVyL2dncGxvdDJIZXguanBnIiAvPg0KPC9jZW50ZXI+DQoNCiMjIENhcGFzIGBnZ3Bsb3QyYA0KDQo8Y2VudGVyPg0KPGltZyBzcmMgPSAiaHR0cHM6Ly9yLnFjYnMuY2Evd29ya3Nob3AwMy93b3Jrc2hvcDAzLWZyL2ltYWdlcy9nZ2xheWVycy5wbmciIHdpZHRoID0gNzAwLz4NCjwvY2VudGVyPg0KDQojIyBFc3RydWN0dXJhIGLDoXNpY2ENCg0KYGBgDQpkYXRhICU+JSANCiAgZ2dwbG90KG1hcHBpbmcgPSBhZXMoeCA9IC4uLiwgeSA9IC4uLikpICsNCiAgZ2VvbV8uLi4NCmBgYA0KDQojIFRpcG9zIGRlIGdyw6FmaWNvcw0KDQo8Y2VudGVyPg0KPGltZyBzcmMgPSAiaHR0cHM6Ly9ycHJvamVjdC11ZGVhLm5ldGxpZnkuYXBwL3RlbWFzL3N0YXRpc3RpY3MvMDQtZXN0YWQtZGVzY3JpcHRpdmEtcjIvaW1nL2dyYWZpY29zLnBuZyIgLz4NCjwvY2VudGVyPg0KDQojIyBDYW50aWRhZGVzDQoNCi0gwr9DdcOhbnRvcyByZWdpc3Ryb3MgaGF5IHBvciBjYWRhIG7Dum1lcm8gZWxlZ2lkbyBhbCBhemFyIGRlIGxhIGVuY3Vlc3RhPw0KDQpgYGB7cn0NCmVuY3Vlc3RhICU+JSANCiAgY291bnQobnVtZXJvX2F6YXIpICU+JSANCiAgZ2dwbG90KGFlcyh4ID0gbnVtZXJvX2F6YXIsIHkgPSBuKSkgKw0KICBnZW9tX2NvbCgpDQpgYGANCg0KDQotIMK/Q3XDoWwgZXMgZWwgdG9wIDEwIGRlIGN1bHRpdm9zIGNvbiBtYXlvciBuw7ptZXJvIGRlIHJlZ2lzdHJvcz8NCg0KYGBge3J9DQpkYXRvc19ldmEgJT4lIA0KICBjb3VudChjdWx0aXZvLCBzb3J0ID0gVFJVRSkgJT4lIA0KICBzbGljZSgxOjEwKSAlPiUgDQogIGdncGxvdChhZXMoeCA9IGN1bHRpdm8sIHkgPSBuKSkgKw0KICBnZW9tX2NvbCgpDQpgYGANCg0KLSBQb2RlbW9zIG1lam9yYXIgZWwgZ3LDoWZpY28gYWdyZWdhbmRvIHZhcmlhcyBjYXJhY3RlcsOtc3RpY2FzIGFkaWNpb25hbGVzOg0KICAtIFJlb3JkZW5hciBsb3MgY3VsdGl2b3MgcG9yIG7Dum1lcm8gZGUgcmVnaXN0cm9zDQogIC0gQ29sb3JlcyBhIGxhcyBiYXJyYXMNCiAgLSBFdGlxdWV0YXMgYWwgZWplIHgsIGFsIGVqZSB5IHkgdMOtdHVsbyBkZWwgZ3LDoWZpY28NCiAgDQpgYGB7cn0NCmRhdG9zX2V2YSAlPiUgDQogIGNvdW50KGN1bHRpdm8sIHNvcnQgPSBUUlVFKSAlPiUgDQogIHNsaWNlKDE6MTApICU+JSANCiAgZ2dwbG90KGFlcyh4ID0gcmVvcmRlcihjdWx0aXZvLCBuKSwgeSA9IG4pKSArDQogIGdlb21fY29sKGNvbG9yID0gImJsYWNrIiwgZmlsbCA9ICJyZWQiKSArDQogIGxhYnMoeCA9ICJDdWx0aXZvIiwgeSA9ICJUb3RhbCIsDQogICAgICAgdGl0bGUgPSAiVG9wIDEwIGRlIGN1bHRpdm9zIGNvbiBtYXlvciByZWdpc3Ryb3MiLA0KICAgICAgIHN1YnRpdGxlID0gIkVWQXMgQ29sb21iaWEgLSAyMDIxIikNCmBgYA0KDQotIENvbG9yZXMgcGFyYSBjYWRhIGJhcnJhOiBjb24gInNob3cubGVnZW5kID0gRkFMU0UiIHF1aXRhbW9zIGxhIGxleWVuZGEuDQoNCmBgYHtyfQ0KZGF0b3NfZXZhICU+JSANCiAgY291bnQoY3VsdGl2bywgc29ydCA9IFRSVUUpICU+JSANCiAgc2xpY2UoMToxMCkgJT4lIA0KICBnZ3Bsb3QoYWVzKHggPSByZW9yZGVyKGN1bHRpdm8sIG4pLCB5ID0gbiwgY29sb3IgPSBjdWx0aXZvLCBmaWxsID0gY3VsdGl2bykpICsNCiAgZ2VvbV9jb2woc2hvdy5sZWdlbmQgPSBGQUxTRSkgKw0KICBsYWJzKHggPSAiQ3VsdGl2byIsIHkgPSAibiIsDQogICAgICAgdGl0bGUgPSAiVG9wIDEwIGRlIGN1bHRpdm9zIGNvbiBtYXlvciByZWdpc3Ryb3MiKQ0KYGBgDQoNCi0gQ29sb3JlcyBwYXJhIGNhZGEgYmFycmE6IGNvbiAic2hvdy5sZWdlbmQgPSBGQUxTRSIgcXVpdGFtb3MgbGEgbGV5ZW5kYSB5IGFkZW3DoXMgcm90YW1vcyBsYXMgY29vcmRlbmFkYXM6DQoNCmBgYHtyfQ0KZGF0b3NfZXZhICU+JSANCiAgY291bnQoY3VsdGl2bywgc29ydCA9IFRSVUUpICU+JSANCiAgc2xpY2UoMToxMCkgJT4lIA0KICBnZ3Bsb3QoYWVzKHggPSByZW9yZGVyKGN1bHRpdm8sIG4pLCB5ID0gbiwgY29sb3IgPSBjdWx0aXZvLCBmaWxsID0gY3VsdGl2bykpICsNCiAgZ2VvbV9jb2woc2hvdy5sZWdlbmQgPSBGQUxTRSkgKw0KICBsYWJzKHggPSAiQ3VsdGl2byIsIHkgPSAibiIsDQogICAgICAgdGl0bGUgPSAiVG9wIDEwIGRlIGN1bHRpdm9zIGNvbiBtYXlvciByZWdpc3Ryb3MiKSArDQogIGNvb3JkX2ZsaXAoKQ0KYGBgDQoNCi0gUG9kZW1vcyByZXByZXNlbnRhciBjb24gYmFycmFzIGN1YWxxdWllciBvdHJhIGNhbnRpZGFkLCBubyBzw7NsbyBsYXMgZnJlY3VlbmNpYXMgKGNvbnRlb3MpLiBQb3IgZWplbXBsbywgcG9kZW1vcyBncmFmaWNhciBlbCB0b3AgMTAgZGVsIHByb21lZGlvIGRlIHJlbmRpbWllbnRvLg0KDQpgYGB7cn0NCmRhdG9zX2V2YSAlPiUgDQogIGdyb3VwX2J5KGN1bHRpdm8pICU+JSANCiAgc3VtbWFyaXNlKHByb21lZGlvID0gbWVhbihyZW5kaW1pZW50bykpICU+JSANCiAgdW5ncm91cCgpICU+JSANCiAgYXJyYW5nZShkZXNjKHByb21lZGlvKSkgJT4lIA0KICBzbGljZSgxOjEwKSAlPiUgDQogIGdncGxvdChhZXMoeCA9IHJlb3JkZXIoY3VsdGl2bywgcHJvbWVkaW8pLCB5ID0gcHJvbWVkaW8pKSArDQogIGdlb21fY29sKCkgKw0KICBjb29yZF9mbGlwKCkgKw0KICBsYWJzKHggPSAiQ3VsdGl2byIsIHkgPSAiUmVuZGltaWVudG8gKHRvbi9oYSkiKQ0KYGBgDQoNCg0KLSDCv0N1w6FsIGVzIGVsIHRvcCAxMCBkZSBjdWx0aXZvcyBjb24gbWF5b3Igw6FyZWEgcGVyZGlkYSAoJSkgcHJvbWVkaW8/ICoqTm90YToqKiBhcGxpY2Ftb3MgdW4gZmlsdHJvIHBhcmEgbWFudGVuZXIgc8OzbG8gY3VsdGl2b3MgcXVlIHN1cGVyYW4gbG9zIDUgbXVuaWNpcGlvcyBjb24gcmVnaXN0cm8uDQoNCmBgYHtyfQ0KZGF0b3NfZXZhICU+JSANCiAgZ3JvdXBfYnkoY3VsdGl2bykgJT4lIA0KICBzdW1tYXJpc2UocHJvbWVkaW8gPSBtZWFuKGFyZWFfcGVyZGlkYV9wKSwNCiAgICAgICAgICAgIE4gPSBuKCkpICU+JSANCiAgdW5ncm91cCgpICU+JSANCiAgZmlsdGVyKE4gPiA1KSAlPiUgDQogIGFycmFuZ2UoZGVzYyhwcm9tZWRpbykpICU+JSANCiAgc2xpY2UoMToxMCkgJT4lIA0KICBnZ3Bsb3QoYWVzKHggPSByZW9yZGVyKGN1bHRpdm8sIHByb21lZGlvKSwgeSA9IHByb21lZGlvKSkgKw0KICBnZW9tX2NvbCgpICsNCiAgY29vcmRfZmxpcCgpDQpgYGANCg0KIyMgUHJvcG9yY2lvbmVzDQoNCi0gwr9Dw7NtbyBlcyBsYSBkaXN0cmlidWNpw7NuIHBvcmNlbmN1YWwgZGUgbGFzIHBlcnNvbmFzIHF1ZSB0cmFiYWphbiB5IGFxdWVsbG9zIHF1ZSBoYW4gcGVuc2FkbyBlbiBhYmFuZG9uYXIgbGEgdW5pdmVyc2lkYWQ/DQoNCmBgYHtyfQ0KZW5jdWVzdGEgJT4lIA0KICBjb3VudCh0cmFiYWpvLCBhYmFuZG9uYXJfdW5pdmVyc2lkYWQpICU+JSANCiAgZ2dwbG90KGFlcyh4ID0gdHJhYmFqbywgeSA9IG4sIGZpbGwgPSBhYmFuZG9uYXJfdW5pdmVyc2lkYWQpKSArDQogIGdlb21fY29sKHBvc2l0aW9uID0gImZpbGwiKQ0KYGBgDQoNCg0KIyMgRGlzdHJpYnVjaW9uZXMNCg0KIyMjIEluZGl2aWR1YWxlcw0KDQotIMK/Q8OzbW8gZXMgbGEgZGlzdHJpYnVjacOzbiBkZWwgcmVuZGltaWVudG8gcGFyYSBlbCBjdWx0aXZvIGRlIGNhZsOpPw0KDQpgYGB7cn0NCmRhdG9zX2V2YSAlPiUgDQogIGZpbHRlcihjdWx0aXZvID09ICJDYWbDqSIpICU+JSANCiAgZ2dwbG90KGFlcyh4ID0gcmVuZGltaWVudG8pKSArDQogIGdlb21faGlzdG9ncmFtKGNvbG9yID0gImJsYWNrIikNCmBgYA0KDQotIEVsIG1pc21vIGdyw6FmaWNvIGFudGVyaW9yIHB1ZWRlIHNlciByZXByZXNlbnRhZG8gYSB0cmF2w6lzIGRlIGRlbnNpZGFkZXM6DQoNCmBgYHtyfQ0KZGF0b3NfZXZhICU+JSANCiAgZmlsdGVyKGN1bHRpdm8gPT0gIkNhZsOpIikgJT4lIA0KICBnZ3Bsb3QoYWVzKHggPSByZW5kaW1pZW50bykpICsNCiAgZ2VvbV9kZW5zaXR5KGZpbGwgPSAib3JhbmdlIikNCmBgYA0KDQotIFBvZGVtb3MgY2FsY3VsYXIgZWwgcHJvbWVkaW8geSBsYSBtZWRpYW5hIHkgYWdyZWdhcmxvIGFsIGdyw6FmaWNvIGFudGVyaW9yOg0KDQpgYGB7cn0NCnByb21lZGlvX3J0b19jYWZlIDwtDQogIGRhdG9zX2V2YSAlPiUNCiAgZmlsdGVyKGN1bHRpdm8gPT0gIkNhZsOpIikgJT4lDQogIHB1bGwocmVuZGltaWVudG8pICU+JQ0KICBtZWFuKCkNCg0KbWVkaWFuYV9ydG9fY2FmZSA8LQ0KICBkYXRvc19ldmEgJT4lDQogIGZpbHRlcihjdWx0aXZvID09ICJDYWbDqSIpICU+JQ0KICBwdWxsKHJlbmRpbWllbnRvKSAlPiUNCiAgbWVkaWFuKCkNCg0KZGF0b3NfZXZhICU+JSANCiAgZmlsdGVyKGN1bHRpdm8gPT0gIkNhZsOpIikgJT4lIA0KICBnZ3Bsb3QoYWVzKHggPSByZW5kaW1pZW50bykpICsNCiAgZ2VvbV9kZW5zaXR5KCkgKw0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBwcm9tZWRpb19ydG9fY2FmZSwgY29sb3IgPSAiYmx1ZSIsIGx0eSA9IDIpICsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gbWVkaWFuYV9ydG9fY2FmZSwgY29sb3IgPSAicmVkIiwgbHR5ID0gMikNCmBgYA0KDQojIyMgQ29tcGFyYXRpdmFzDQoNCi0gwr9Dw7NtbyBlcyBsYSBkaXN0cmlidWNpw7NuIGRlIGNhZGEgZGVwYXJ0YW1lbnRvIHBhcmEgZWwgcmVuZGltaWVudG8gZW4gZWwgY3VsdGl2byBkZSBjYWbDqT8NCg0KYGBge3J9DQpkYXRvc19ldmEgJT4lIA0KICBmaWx0ZXIoY3VsdGl2byA9PSAiQ2Fmw6kiKSAlPiUgDQogIGdncGxvdChhZXMoeCA9IGRlcGFydGFtZW50bywgeSA9IHJlbmRpbWllbnRvKSkgKw0KICBnZW9tX2JveHBsb3QoKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpDQpgYGANCg0KLSBUZW5pZW5kbyBlbiBjdWVudGEgcXVlIGVsIGN1bHRpdm8gZGUgbWHDrXogZXMgdHJhbnNpdG9yaW8sIMK/Y3XDoWwgcGVyw61vZG8gcHJlc2VudGEgbWF5b3IgdW5pZm9ybWlkYWQgZW4gZWwgcmVuZGltaWVudG8/DQoNCmBgYHtyfQ0KZGF0b3NfZXZhICU+JSANCiAgZmlsdGVyKGN1bHRpdm8gPT0gIk1hw616IikgJT4lIA0KICBnZ3Bsb3QoYWVzKHggPSBwZXJpb2RvLCB5ID0gcmVuZGltaWVudG8pKSArDQogIGdlb21fYm94cGxvdCgpDQpgYGANCg0KLSBFbCBtaXNtbyByZXN1bHRhZG8gYW50ZXJpb3IgcHVlZGUgc2VyIHJlcHJlc2VudGFkbyBhIHRyYXbDqXMgZGUgZGVuc2lkYWRlczoNCg0KYGBge3J9DQpkYXRvc19ldmEgJT4lIA0KICBmaWx0ZXIoY3VsdGl2byA9PSAiTWHDrXoiKSAlPiUgDQogIGdncGxvdChhZXMoeCA9IHJlbmRpbWllbnRvLCBjb2xvciA9IHBlcmlvZG8pKSArDQogIGdlb21fZGVuc2l0eSgpDQpgYGANCg0KLSDCv1BvZGVtb3MgYWdyZWdhciB1bmEgdGVyY2VyYSB2YXJpYWJsZSBhbCBncsOhZmljbyBhbnRlcmlvcj8NCg0KYGBge3IsIGZpZy53aWR0aD04fQ0KZGF0b3NfZXZhICU+JSANCiAgZmlsdGVyKGN1bHRpdm8gPT0gIk1hw616IikgJT4lIA0KICBnZ3Bsb3QoYWVzKHggPSBkZXBhcnRhbWVudG8sIHkgPSByZW5kaW1pZW50bywgZmlsbCA9IHBlcmlvZG8pKSArDQogIGdlb21fYm94cGxvdCgpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkNCmBgYA0KDQotIMK/RXhpc3RlbiBkaWZlcmVuY2lhcyBlbiBsYSBkaXN0cmlidWNpw7NuIGRlbCBwcm9tZWRpbyBhY2Fkw6ltaWNvIHBhcmEgbGFzIHBlcnNvbmFzIHF1ZSBwb3NlZW4gdHJhYmFqbz8NCg0KYGBge3J9DQplbmN1ZXN0YSAlPiUgDQogIGdncGxvdChhZXMoeCA9IHRyYWJham8sIHkgPSBwcm9tZWRpb19hY2FkZW1pY28pKSArDQogIGdlb21fYm94cGxvdCgpDQpgYGANCg0KDQojIyBSZWxhY2lvbmVzIHgteQ0KDQotIMK/RXhpc3RlIGFsZ3VuYSBhc29jaWFjacOzbiBlbnRyZSBlbCDDoXJlYSBwZXJkaWRhICglKSB5IGVsIHJlbmRpbWllbnRvIHBhcmEgZWwgY3VsdGl2byBkZSBtYcOtej8NCg0KYGBge3J9DQpkYXRvc19ldmEgJT4lIA0KICBmaWx0ZXIoY3VsdGl2byA9PSAiTWHDrXoiKSAlPiUgDQogIGdncGxvdChhZXMoeCA9IGFyZWFfcGVyZGlkYV9wLCB5ID0gcmVuZGltaWVudG8pKSArDQogIGdlb21fcG9pbnQoKSANCmBgYA0KDQotIENvbiBsb3MgZGF0b3MgZGUgbGEgZW5jdWVzdGEsIMK/Q3XDoWwgZXMgbGEgcmVsYWNpw7NuIGRlIGxhIGRpc3RhbmNpYSBjb24gbGEgdmVsb2NpZGFkPw0KDQpgYGB7cn0NCmVuY3Vlc3RhICU+JSANCiAgZ2dwbG90KGFlcyh4ID0gZGlzdGFuY2lhX2Nhc2FfdSwgeSA9IHZlbG9jaWRhZCkpICsNCiAgZ2VvbV9wb2ludCgpDQpgYGANCg0KDQoNCg0KIyBHcsOhZmljb3MgaW50ZXJhY3Rpdm9zDQoNCiMjIEdyw6FmaWNvIDENCg0KYGBge3J9DQpnZ3Bsb3RseSgNCiAgZW5jdWVzdGEgJT4lIA0KICBnZ3Bsb3QoYWVzKHggPSBkaXN0YW5jaWFfY2FzYV91LCB5ID0gdmVsb2NpZGFkKSkgKw0KICBnZW9tX3BvaW50KCkNCikNCmBgYA0KDQojIyBHcsOhZmljbyAyDQoNCmBgYHtyfQ0KZ2dwbG90bHkoDQogIGRhdG9zX2V2YSAlPiUgDQogIGZpbHRlcihjdWx0aXZvID09ICJNYcOteiIpICU+JSANCiAgZ2dwbG90KGFlcyh4ID0gcmVuZGltaWVudG8sIGNvbG9yID0gcGVyaW9kbykpICsNCiAgZ2VvbV9kZW5zaXR5KCkNCikNCmBgYA==