Territorio y seguridad en Bogotá: un análisis de las denuncias por UPZ

Una exploración de las características demográficas y territoriales y su relación con las denuncias por delito en Bogotá

library(tidyverse)
library(scales)         
library(showtext)       
library(sysfonts)       
library(countrycode)    
library(DT)             
library(leaflet)        
library(sf)             
library(rnaturalearth)  
library(plotly)         
library(kableExtra)     

fuente_editorial <- "Fira Sans"
font_add_google(name = fuente_editorial, family = fuente_editorial)
showtext_auto()
# 1. cargar datos
upz <- read_csv('C:/Users/User/Desktop/jeison/Taller_Insights_UPZ_estudiantes/Taller_Insights_UPZ_estudiantes/Taller_Insights_UPZ_estudiantes/input/upz_variables.csv', show_col_types = FALSE)
## 2. cargar ´paleta de colores 
#--- Paleta y tema del curso (los mismos de todos los scripts) --------------
morado   <- "#351A4F"
magenta  <- "#D9006C"
turquesa <- "#168C86"
gris     <- "#D9D6DD"

tema_clase <- theme_minimal(base_size = 12) +
  theme(
    plot.title.position = "plot",
    plot.title = element_text(face = "bold", size = 15, hjust = 0),
    plot.subtitle = element_text(size = 10.5, color = "grey35", hjust = 0),
    panel.grid.minor = element_blank(),
    plot.caption = element_text(hjust = 0, color = "grey45", size = 8.5),
    plot.margin = margin(10, 20, 10, 10)
  )


estilo_plotly <- function(p) {
  p %>%
    config(displayModeBar = FALSE) %>%          
    layout(font = list(family = fuente_editorial)) 
}

tabla_bonita <- function(df, resaltar = NULL) {
  k <- df %>%
    kbl() %>%   
    kable_styling(bootstrap_options = c("hover", "condensed"), full_width = TRUE, font_size = 14) %>%
    row_spec(0, bold = TRUE, color = "white", background = morado)  # fila 0 = encabezado
  if (!is.null(resaltar)) {
    k <- k %>% row_spec(resaltar, background = "#F6EEF2", bold = TRUE, color = morado)
  }
  k
}

1. Introducción

En este informe se analizan las 112 UPZ de Bogotá, con el propósito de explorar las características demográficas y territoriales de cada una, así como su relación con las denuncias registradas entre enero y julio de 2026. adicional, se busca identificar posibles relaciones entre la composición de la población, las características del territorio y la cantidad y las tasas de denuncias asociadas a diferentes tipos de delito. De esta manera, se pretende reconocer patrones y diferencias entre las UPZ que permitan comprender mejor el comportamiento territorial de las denuncias en la ciudad.

2. Objetivos

Objetivo general: Analizar la relación entre las características demográficas y territoriales de las 112 UPZ de Bogotá y la cantidad y las tasas de denuncias registradas por diferentes tipos de delito, con el fin de identificar patrones y diferencias territoriales durante el periodo de estudio.

Objetivos específicos:

  1. Segmentar las UPZ de Bogotá a partir de sus variables como la población, la composición por grupos de edad, el área y la densidad poblacional.

  2. Describir y comparar la cantidad y las tasas de denuncias correspondientes a diferentes tipos de delito, identificando las UPZ que presentan mayores y menores registros.

  3. Explorar las posibles relaciones entre las características poblacionales y territoriales de las UPZ y el comportamiento de las denuncias, mediante herramientas estadísticas y visualizaciones que permitan identificar patrones y diferencias espaciales.

3. Fuentes de información

3.1 Dataset de estudio UPZ Bogotá

  1. Delitos: Secretaría Distrital de Seguridad, Convivencia y Justicia. Población y viviendas: proyecciones DANE (CNPV 2018).

  2. Luminarias: Datos Abiertos Bogotá. Encuesta Multipropósito 2021: DANE.

tibble(
  Variable = c(
    "area_km2",
    "poblacion",
    "densidad_hab_km2",
    "pct_0_14",
    "pct_15_29",
    "pct_60_mas",
    "casos_total",
    "tasa_total"
  ),
  Descripcion = c(
    "Área territorial de la UPZ en kilómetros cuadrados",
    "Cantidad de habitantes de la UPZ",
    "Densidad de habitantes por kilómetro cuadrado",
    "Porcentaje de población entre 0 y 14 años",
    "Porcentaje de población entre 15 y 29 años",
    "Porcentaje de población entre 15 y 29 años",
    "Cantidad total de denuncias registradas",
    "Tasa total de denuncias por cada 10.000 habitantes"
  )
) %>%
  tabla_bonita(resaltar = c(1,2))
Variable Descripcion
area_km2 Área territorial de la UPZ en kilómetros cuadrados
poblacion Cantidad de habitantes de la UPZ
densidad_hab_km2 Densidad de habitantes por kilómetro cuadrado
pct_0_14 Porcentaje de población entre 0 y 14 años
pct_15_29 Porcentaje de población entre 15 y 29 años
pct_60_mas Porcentaje de población entre 15 y 29 años
casos_total Cantidad total de denuncias registradas
tasa_total Tasa total de denuncias por cada 10.000 habitantes
n_upz <- n_distinct(upz$upz_cod)

poblacion_total <- sum(upz$poblacion, na.rm = TRUE)

area_total <- sum(upz$area_km2, na.rm = TRUE)

total_denuncias <- sum(upz$casos_total, na.rm = TRUE)

paste0(
  n_upz, " UPZ analizadas · ",
  comma(poblacion_total, big.mark = "."), " habitantes · ",
  comma(round(area_total, 2), big.mark = "."), " km² de extensión · ",
  comma(total_denuncias, big.mark = "."), " denuncias registradas","  Periodo: enero-julio de 2023"
)
## [1] "112 UPZ analizadas · 7.936.532 habitantes · 415 km² de extensión · 162.835 denuncias registradas  Periodo: enero-julio de 2023"

Bogotá en cifras: una mirada estadística a las UPZ:

variables <- c(
  "area_km2",
  "poblacion",
  "densidad_hab_km2",
  "pct_0_14",
  "pct_15_29",
  "pct_60_mas",
  "casos_total",
  "tasa_total"
)

tabla_descriptiva <- data.frame(
  Variable = variables,
  Media = sapply(upz[variables], mean, na.rm = TRUE),
  Mediana = sapply(upz[variables], median, na.rm = TRUE),
  Desviacion = sapply(upz[variables], sd, na.rm = TRUE),
  Minimo = sapply(upz[variables], min, na.rm = TRUE),
  Maximo = sapply(upz[variables], max, na.rm = TRUE)
)

# Redondear las estadísticas a 1 decimal
tabla_descriptiva[-1] <- lapply(tabla_descriptiva[-1], round, digits = 1)

# Mostrar tabla
tabla_descriptiva %>%
  tabla_bonita(resaltar = c(1, 2))
Variable Media Mediana Desviacion Minimo Maximo
area_km2 area_km2 3.7 3.5 1.7 0.9 9.3
poblacion poblacion 70861.9 54102.5 58406.4 30.0 305907.0
densidad_hab_km2 densidad_hab_km2 19119.4 20180.2 10801.9 9.4 46156.9
pct_0_14 pct_0_14 17.3 16.7 4.8 7.4 31.0
pct_15_29 pct_15_29 24.1 24.0 4.5 14.8 51.9
pct_60_mas pct_60_mas 15.7 14.6 5.1 7.5 29.9
casos_total casos_total 1453.9 1222.0 1023.1 16.0 5441.0
tasa_total tasa_total 503.6 192.5 1263.4 64.5 11333.3

¿Segmentar las poblaciones permite mejor analisis de la informacion?

p_poblacion_area <- ggplot(upz, aes(x = area_km2, y = poblacion)) +
  geom_point(
    color = "#6B4C8A",
    size = 2.5,
    alpha = 0.7,
    aes(text = paste0(
      "UPZ: ", upz_nombre,
      "<br>Área: ", round(area_km2, 2), " km²",
      "<br>Población: ",
      format(round(poblacion), big.mark = ".", decimal.mark = ",",
             scientific = FALSE)
    ))
  ) +
  geom_smooth(
    method = "lm",
    se = FALSE,
    color = "#D17A22"
  ) +
  scale_y_continuous(
    labels = scales::label_comma(
      big.mark = ".",
      decimal.mark = ","
    )
  ) +
  labs(
    title = "Relación entre población y área territorial de las UPZ",
    x = "Área territorial (km²)",
    y = "Población (habitantes)"
  ) +
  tema_clase +
  theme(
    panel.grid.major.x = element_blank()
  )

ggplotly(p_poblacion_area, tooltip = "text") %>%
  estilo_plotly()

Al revisar los datos, se evidencia que la población presenta una diferencia bastante amplia entre el valor mínimo y el máximo. Por esta razón, considero necesario dividir las UPZ en tres grupos: población baja, población media y población alta. Esto permitirá realizar comparaciones entre UPZ que tengan características poblacionales similares y analizar de una mejor manera las tasas de denuncias, teniendo en cuenta que estas pueden variar bastante dependiendo de la cantidad de habitantes de cada territorio.

Adicionalmente, se debe incluir el grupo de edad de 30 a 59 años, para tener una visión más completa de la composición de la población y poder analizar cómo se relacionan los diferentes rangos de edad con la cantidad y las tasas de denuncias registradas.

LS0tDQp0aXRsZTogIkJvZ290w6EgYmFqbyBsYSBsdXBhOiBwb2JsYWNpw7NuLCB0ZXJyaXRvcmlvIHkgZGVudW5jaWFzIGVuIGxhcyBVUFoiDQpzdWJ0aXRsZTogIsK/Q8OzbW8gc2UgcmVsYWNpb25hbiBsYSBjb21wb3NpY2nDs24gcG9yIHJhbmdvcyBkZSBlZGFkIGRlIGxhIHBvYmxhY2nDs24geSBlbCDDoXJlYSB0ZXJyaXRvcmlhbCBkZSBsYXMgVVBaIGNvbiBsYSBjYW50aWRhZCB5IGxhIHRhc2EgZGUgZGVudW5jaWFzIHBvciBkZWxpdG8gZW4gQm9nb3TDoT8iDQphdXRob3I6ICJKZWlzb24gRGlheiAtIFJvYmluc29uIEdpcmFsZG8iDQpkYXRlOiAiYHIgZm9ybWF0KFN5cy5EYXRlKCksICclZCBkZSAlQiBkZSAlWScpYCINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDoNCiAgICB0b2M6IHRydWUNCiAgICB0b2NfZmxvYXQ6IHRydWUNCiAgICB0aGVtZTogZmxhdGx5DQogICAgZGZfcHJpbnQ6IGthYmxlDQogICAgY29kZV9mb2xkaW5nOiBoaWRlDQogICAgY29kZV9kb3dubG9hZDogdHJ1ZSAgICMgYWdyZWdhIHVuIGJvdMOzbiBwYXJhIGRlc2NhcmdhciBlbCAuUm1kIG9yaWdpbmFsIC0tIHJlZnVlcnphIGxhIHJlcHJvZHVjaWJpbGlkYWQNCi0tLQ0KDQpgYGB7PWh0bWx9DQo8c3R5bGU+DQovKiBUaXBvZ3JhZsOtYSBlZGl0b3JpYWwgZGVsIGN1cnNvICAqLw0KQGltcG9ydCB1cmwoJ2h0dHBzOi8vZm9udHMuZ29vZ2xlYXBpcy5jb20vY3NzMj9mYW1pbHk9RmlyYStTYW5zOndnaHRANDAwOzYwMDs3MDAmZGlzcGxheT1zd2FwJyk7DQoNCmJvZHkgeyBmb250LWZhbWlseTogJ0ZpcmEgU2FucycsIC1hcHBsZS1zeXN0ZW0sIEJsaW5rTWFjU3lzdGVtRm9udCwgc2Fucy1zZXJpZjsgY29sb3I6ICMyQjI1MzA7IH0NCmgxLCBoMiwgaDMgeyBmb250LWZhbWlseTogJ0ZpcmEgU2FucycsIHNhbnMtc2VyaWY7IGNvbG9yOiAjMzUxQTRGOyB9DQpoMSB7IGJvcmRlci1ib3R0b206IDNweCBzb2xpZCAjRDkwMDZDOyBwYWRkaW5nLWJvdHRvbTogOHB4OyBtYXJnaW4tdG9wOiA0OHB4OyB9DQpoMiB7IG1hcmdpbi10b3A6IDM2cHg7IH0NCmEgeyBjb2xvcjogI0Q5MDA2QzsgfQ0KYTpob3ZlciB7IGNvbG9yOiAjMTY4Qzg2OyB9DQojVE9DIHsgYm9yZGVyLXJhZGl1czogMTBweDsgfQ0KLm5hdi1waWxscyA+IGxpLmFjdGl2ZSA+IGEsIC5uYXYtcGlsbHMgPiBsaS5hY3RpdmUgPiBhOmhvdmVyIHsgYmFja2dyb3VuZC1jb2xvcjogIzM1MUE0RiAhaW1wb3J0YW50OyB9DQpjYXB0aW9uIHsgY29sb3I6ICM1QTU1NjA7IGZvbnQtc3R5bGU6IGl0YWxpYzsgY2FwdGlvbi1zaWRlOiB0b3A7IH0NCmNvZGUgeyBjb2xvcjogIzhBMUE1QzsgYmFja2dyb3VuZDogI0Y2RUVGMjsgcGFkZGluZzogMXB4IDVweDsgYm9yZGVyLXJhZGl1czogNHB4OyB9DQp0YWJsZS5kYXRhVGFibGUgeyBmb250LXNpemU6IDAuOTJyZW07IH0NCi5sZWFmbGV0LWNvbnRhaW5lciB7IGJvcmRlci1yYWRpdXM6IDEwcHg7IGJhY2tncm91bmQ6ICNFQUYwRjQgIWltcG9ydGFudDsgfQ0KPC9zdHlsZT4NCmBgYA0KDQo6Ojo6Ojo6IHtzdHlsZT0iYmFja2dyb3VuZDogbGluZWFyLWdyYWRpZW50KDEzNWRlZywgIzM1MUE0RiAwJSwgI0Q5MDA2QyAxMDAlKTsgcGFkZGluZzogMjZweCAzMHB4OyBib3JkZXItcmFkaXVzOiAxNHB4OyBtYXJnaW4tYm90dG9tOiAzMHB4OyBkaXNwbGF5OiBmbGV4OyBhbGlnbi1pdGVtczogY2VudGVyOyBqdXN0aWZ5LWNvbnRlbnQ6IHNwYWNlLWJldHdlZW47IGZsZXgtd3JhcDogd3JhcDsgZ2FwOiAxOHB4OyJ9DQo6Ojo6OiB7c3R5bGU9Im1heC13aWR0aDogNjIwcHg7In0NCjo6OiB7c3R5bGU9ImNvbG9yOiB3aGl0ZTsgZm9udC1zaXplOiAxLjU1cmVtOyBmb250LXdlaWdodDogNzAwOyBsaW5lLWhlaWdodDogMS4yNTsifQ0KVGVycml0b3JpbyB5IHNlZ3VyaWRhZCBlbiBCb2dvdMOhOiB1biBhbsOhbGlzaXMgZGUgbGFzIGRlbnVuY2lhcyBwb3IgVVBaIA0KOjo6DQoNCjo6OiB7c3R5bGU9ImNvbG9yOiAjRjREQ0U5OyBmb250LXNpemU6IDFyZW07IG1hcmdpbi10b3A6IDZweDsifQ0KVW5hIGV4cGxvcmFjacOzbiBkZSBsYXMgY2FyYWN0ZXLDrXN0aWNhcyBkZW1vZ3LDoWZpY2FzIHkgdGVycml0b3JpYWxlcyB5IHN1IHJlbGFjacOzbiBjb24gbGFzIGRlbnVuY2lhcyBwb3IgZGVsaXRvIGVuIEJvZ290w6ENCjo6Og0KOjo6OjoNCg0KOjo6IHtzdHlsZT0iYmFja2dyb3VuZDogd2hpdGU7IHBhZGRpbmc6IDEwcHggMThweDsgYm9yZGVyLXJhZGl1czogMTBweDsgZmxleC1zaHJpbms6IDA7In0NCjxpbWcgc3JjPSJpbWcva29ucmFkX2xvZ28ucG5nIiBzdHlsZT0ibWF4LXdpZHRoOiAyMTBweDsgZGlzcGxheTogYmxvY2s7Ii8+DQo6OjoNCjo6Ojo6OjoNCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoDQogIGVjaG8gPSBUUlVFLA0KICB3YXJuaW5nID0gRkFMU0UsDQogIG1lc3NhZ2UgPSBGQUxTRSwNCiAgZmlnLmFsaWduID0gImNlbnRlciIsDQogIGZpZy53aWR0aCA9IDgsDQogIGZpZy5oZWlnaHQgPSA1DQopDQpgYGANCg0KYGBge3IgbGlicmVyaWFzfQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KHNjYWxlcykgICAgICAgICANCmxpYnJhcnkoc2hvd3RleHQpICAgICAgIA0KbGlicmFyeShzeXNmb250cykgICAgICAgDQpsaWJyYXJ5KGNvdW50cnljb2RlKSAgICANCmxpYnJhcnkoRFQpICAgICAgICAgICAgIA0KbGlicmFyeShsZWFmbGV0KSAgICAgICAgDQpsaWJyYXJ5KHNmKSAgICAgICAgICAgICANCmxpYnJhcnkocm5hdHVyYWxlYXJ0aCkgIA0KbGlicmFyeShwbG90bHkpICAgICAgICAgDQpsaWJyYXJ5KGthYmxlRXh0cmEpICAgICANCg0KZnVlbnRlX2VkaXRvcmlhbCA8LSAiRmlyYSBTYW5zIg0KZm9udF9hZGRfZ29vZ2xlKG5hbWUgPSBmdWVudGVfZWRpdG9yaWFsLCBmYW1pbHkgPSBmdWVudGVfZWRpdG9yaWFsKQ0Kc2hvd3RleHRfYXV0bygpDQpgYGANCg0KYGBge3IgZGF0b3N9DQojIDEuIGNhcmdhciBkYXRvcw0KdXB6IDwtIHJlYWRfY3N2KCdDOi9Vc2Vycy9Vc2VyL0Rlc2t0b3AvamVpc29uL1RhbGxlcl9JbnNpZ2h0c19VUFpfZXN0dWRpYW50ZXMvVGFsbGVyX0luc2lnaHRzX1VQWl9lc3R1ZGlhbnRlcy9UYWxsZXJfSW5zaWdodHNfVVBaX2VzdHVkaWFudGVzL2lucHV0L3Vwel92YXJpYWJsZXMuY3N2Jywgc2hvd19jb2xfdHlwZXMgPSBGQUxTRSkNCg0KYGBgDQoNCmBgYHtyIGVzdGlsb30NCiMjIDIuIGNhcmdhciDCtHBhbGV0YSBkZSBjb2xvcmVzIA0KIy0tLSBQYWxldGEgeSB0ZW1hIGRlbCBjdXJzbyAobG9zIG1pc21vcyBkZSB0b2RvcyBsb3Mgc2NyaXB0cykgLS0tLS0tLS0tLS0tLS0NCm1vcmFkbyAgIDwtICIjMzUxQTRGIg0KbWFnZW50YSAgPC0gIiNEOTAwNkMiDQp0dXJxdWVzYSA8LSAiIzE2OEM4NiINCmdyaXMgICAgIDwtICIjRDlENkREIg0KDQp0ZW1hX2NsYXNlIDwtIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTIpICsNCiAgdGhlbWUoDQogICAgcGxvdC50aXRsZS5wb3NpdGlvbiA9ICJwbG90IiwNCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxNSwgaGp1c3QgPSAwKSwNCiAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMC41LCBjb2xvciA9ICJncmV5MzUiLCBoanVzdCA9IDApLA0KICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksDQogICAgcGxvdC5jYXB0aW9uID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMCwgY29sb3IgPSAiZ3JleTQ1Iiwgc2l6ZSA9IDguNSksDQogICAgcGxvdC5tYXJnaW4gPSBtYXJnaW4oMTAsIDIwLCAxMCwgMTApDQogICkNCg0KDQplc3RpbG9fcGxvdGx5IDwtIGZ1bmN0aW9uKHApIHsNCiAgcCAlPiUNCiAgICBjb25maWcoZGlzcGxheU1vZGVCYXIgPSBGQUxTRSkgJT4lICAgICAgICAgIA0KICAgIGxheW91dChmb250ID0gbGlzdChmYW1pbHkgPSBmdWVudGVfZWRpdG9yaWFsKSkgDQp9DQoNCnRhYmxhX2Jvbml0YSA8LSBmdW5jdGlvbihkZiwgcmVzYWx0YXIgPSBOVUxMKSB7DQogIGsgPC0gZGYgJT4lDQogICAga2JsKCkgJT4lICAgDQogICAga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9IGMoImhvdmVyIiwgImNvbmRlbnNlZCIpLCBmdWxsX3dpZHRoID0gVFJVRSwgZm9udF9zaXplID0gMTQpICU+JQ0KICAgIHJvd19zcGVjKDAsIGJvbGQgPSBUUlVFLCBjb2xvciA9ICJ3aGl0ZSIsIGJhY2tncm91bmQgPSBtb3JhZG8pICAjIGZpbGEgMCA9IGVuY2FiZXphZG8NCiAgaWYgKCFpcy5udWxsKHJlc2FsdGFyKSkgew0KICAgIGsgPC0gayAlPiUgcm93X3NwZWMocmVzYWx0YXIsIGJhY2tncm91bmQgPSAiI0Y2RUVGMiIsIGJvbGQgPSBUUlVFLCBjb2xvciA9IG1vcmFkbykNCiAgfQ0KICBrDQp9DQpgYGANCg0KIyAxLiBJbnRyb2R1Y2Npw7NuDQoNCkVuIGVzdGUgaW5mb3JtZSBzZSBhbmFsaXphbiBsYXMgMTEyIFVQWiBkZSBCb2dvdMOhLCBjb24gZWwgcHJvcMOzc2l0byBkZSBleHBsb3JhciBsYXMgY2FyYWN0ZXLDrXN0aWNhcyBkZW1vZ3LDoWZpY2FzIHkgdGVycml0b3JpYWxlcyBkZSBjYWRhIHVuYSwgYXPDrSBjb21vIHN1IHJlbGFjacOzbiBjb24gbGFzIGRlbnVuY2lhcyByZWdpc3RyYWRhcyBlbnRyZSBlbmVybyB5IGp1bGlvIGRlIDIwMjYuIGFkaWNpb25hbCwgc2UgYnVzY2EgaWRlbnRpZmljYXIgcG9zaWJsZXMgcmVsYWNpb25lcyBlbnRyZSBsYSBjb21wb3NpY2nDs24gZGUgbGEgcG9ibGFjacOzbiwgbGFzIGNhcmFjdGVyw61zdGljYXMgZGVsIHRlcnJpdG9yaW8geSBsYSBjYW50aWRhZCB5IGxhcyB0YXNhcyBkZSBkZW51bmNpYXMgYXNvY2lhZGFzIGEgZGlmZXJlbnRlcyB0aXBvcyBkZSBkZWxpdG8uIERlIGVzdGEgbWFuZXJhLCBzZSBwcmV0ZW5kZSByZWNvbm9jZXIgcGF0cm9uZXMgeSBkaWZlcmVuY2lhcyBlbnRyZSBsYXMgVVBaIHF1ZSBwZXJtaXRhbiBjb21wcmVuZGVyIG1lam9yIGVsIGNvbXBvcnRhbWllbnRvIHRlcnJpdG9yaWFsIGRlIGxhcyBkZW51bmNpYXMgZW4gbGEgY2l1ZGFkLg0KDQojIDIuIE9iamV0aXZvcw0KDQoqKk9iamV0aXZvIGdlbmVyYWw6KiogQW5hbGl6YXIgbGEgcmVsYWNpw7NuIGVudHJlIGxhcyBjYXJhY3RlcsOtc3RpY2FzIGRlbW9ncsOhZmljYXMgeSB0ZXJyaXRvcmlhbGVzIGRlIGxhcyAxMTIgVVBaIGRlIEJvZ290w6EgeSBsYSBjYW50aWRhZCB5IGxhcyB0YXNhcyBkZSBkZW51bmNpYXMgcmVnaXN0cmFkYXMgcG9yIGRpZmVyZW50ZXMgdGlwb3MgZGUgZGVsaXRvLCBjb24gZWwgZmluIGRlIGlkZW50aWZpY2FyIHBhdHJvbmVzIHkgZGlmZXJlbmNpYXMgdGVycml0b3JpYWxlcyBkdXJhbnRlIGVsIHBlcmlvZG8gZGUgZXN0dWRpby4NCg0KKipPYmpldGl2b3MgZXNwZWPDrWZpY29zOioqDQoNCjEuIFNlZ21lbnRhciBsYXMgVVBaIGRlIEJvZ290w6EgYSBwYXJ0aXIgZGUgc3VzIHZhcmlhYmxlcyBjb21vIGxhIHBvYmxhY2nDs24sIGxhIGNvbXBvc2ljacOzbiBwb3IgZ3J1cG9zIGRlIGVkYWQsIGVsIMOhcmVhIHkgbGEgZGVuc2lkYWQgcG9ibGFjaW9uYWwuDQoNCjIuIERlc2NyaWJpciB5IGNvbXBhcmFyIGxhIGNhbnRpZGFkIHkgbGFzIHRhc2FzIGRlIGRlbnVuY2lhcyBjb3JyZXNwb25kaWVudGVzIGEgZGlmZXJlbnRlcyB0aXBvcyBkZSBkZWxpdG8sIGlkZW50aWZpY2FuZG8gbGFzIFVQWiBxdWUgcHJlc2VudGFuIG1heW9yZXMgeSBtZW5vcmVzIHJlZ2lzdHJvcy4NCg0KMy4gRXhwbG9yYXIgbGFzIHBvc2libGVzIHJlbGFjaW9uZXMgZW50cmUgbGFzIGNhcmFjdGVyw61zdGljYXMgcG9ibGFjaW9uYWxlcyB5IHRlcnJpdG9yaWFsZXMgZGUgbGFzIFVQWiB5IGVsIGNvbXBvcnRhbWllbnRvIGRlIGxhcyBkZW51bmNpYXMsIG1lZGlhbnRlIGhlcnJhbWllbnRhcyBlc3RhZMOtc3RpY2FzIHkgdmlzdWFsaXphY2lvbmVzIHF1ZSBwZXJtaXRhbiBpZGVudGlmaWNhciBwYXRyb25lcyB5IGRpZmVyZW5jaWFzIGVzcGFjaWFsZXMuDQoNCiMgMy4gRnVlbnRlcyBkZSBpbmZvcm1hY2nDs24NCg0KIyMgMy4xIERhdGFzZXQgZGUgZXN0dWRpbyBVUFogQm9nb3TDoQ0KDQoxLiBEZWxpdG9zOiBTZWNyZXRhcsOtYSBEaXN0cml0YWwgZGUgU2VndXJpZGFkLCBDb252aXZlbmNpYSB5IEp1c3RpY2lhLiBQb2JsYWNpw7NuIHkgdml2aWVuZGFzOiBwcm95ZWNjaW9uZXMNCkRBTkUgKENOUFYgMjAxOCkuIA0KDQoyLiBMdW1pbmFyaWFzOiBEYXRvcyBBYmllcnRvcyBCb2dvdMOhLiBFbmN1ZXN0YSBNdWx0aXByb3DDs3NpdG8gMjAyMTogREFORS4NCg0KDQpgYGB7ciB0YWJsYS12YXJpYWJsZXMtdXB6fQ0KdGliYmxlKA0KICBWYXJpYWJsZSA9IGMoDQogICAgImFyZWFfa20yIiwNCiAgICAicG9ibGFjaW9uIiwNCiAgICAiZGVuc2lkYWRfaGFiX2ttMiIsDQogICAgInBjdF8wXzE0IiwNCiAgICAicGN0XzE1XzI5IiwNCiAgICAicGN0XzYwX21hcyIsDQogICAgImNhc29zX3RvdGFsIiwNCiAgICAidGFzYV90b3RhbCINCiAgKSwNCiAgRGVzY3JpcGNpb24gPSBjKA0KICAgICLDgXJlYSB0ZXJyaXRvcmlhbCBkZSBsYSBVUFogZW4ga2lsw7NtZXRyb3MgY3VhZHJhZG9zIiwNCiAgICAiQ2FudGlkYWQgZGUgaGFiaXRhbnRlcyBkZSBsYSBVUFoiLA0KICAgICJEZW5zaWRhZCBkZSBoYWJpdGFudGVzIHBvciBraWzDs21ldHJvIGN1YWRyYWRvIiwNCiAgICAiUG9yY2VudGFqZSBkZSBwb2JsYWNpw7NuIGVudHJlIDAgeSAxNCBhw7FvcyIsDQogICAgIlBvcmNlbnRhamUgZGUgcG9ibGFjacOzbiBlbnRyZSAxNSB5IDI5IGHDsW9zIiwNCiAgICAiUG9yY2VudGFqZSBkZSBwb2JsYWNpw7NuIGVudHJlIDE1IHkgMjkgYcOxb3MiLA0KICAgICJDYW50aWRhZCB0b3RhbCBkZSBkZW51bmNpYXMgcmVnaXN0cmFkYXMiLA0KICAgICJUYXNhIHRvdGFsIGRlIGRlbnVuY2lhcyBwb3IgY2FkYSAxMC4wMDAgaGFiaXRhbnRlcyINCiAgKQ0KKSAlPiUNCiAgdGFibGFfYm9uaXRhKHJlc2FsdGFyID0gYygxLDIpKQ0KYGBgDQoNCmBgYHtyIHJlc3VtZW4tZ2VuZXJhbH0NCm5fdXB6IDwtIG5fZGlzdGluY3QodXB6JHVwel9jb2QpDQoNCnBvYmxhY2lvbl90b3RhbCA8LSBzdW0odXB6JHBvYmxhY2lvbiwgbmEucm0gPSBUUlVFKQ0KDQphcmVhX3RvdGFsIDwtIHN1bSh1cHokYXJlYV9rbTIsIG5hLnJtID0gVFJVRSkNCg0KdG90YWxfZGVudW5jaWFzIDwtIHN1bSh1cHokY2Fzb3NfdG90YWwsIG5hLnJtID0gVFJVRSkNCg0KcGFzdGUwKA0KICBuX3VweiwgIiBVUFogYW5hbGl6YWRhcyDCtyAiLA0KICBjb21tYShwb2JsYWNpb25fdG90YWwsIGJpZy5tYXJrID0gIi4iKSwgIiBoYWJpdGFudGVzIMK3ICIsDQogIGNvbW1hKHJvdW5kKGFyZWFfdG90YWwsIDIpLCBiaWcubWFyayA9ICIuIiksICIga23CsiBkZSBleHRlbnNpw7NuIMK3ICIsDQogIGNvbW1hKHRvdGFsX2RlbnVuY2lhcywgYmlnLm1hcmsgPSAiLiIpLCAiIGRlbnVuY2lhcyByZWdpc3RyYWRhcyIsIiAgUGVyaW9kbzogZW5lcm8tanVsaW8gZGUgMjAyMyINCikNCmBgYA0KDQoqKkJvZ290w6EgZW4gY2lmcmFzOiB1bmEgbWlyYWRhIGVzdGFkw61zdGljYSBhIGxhcyBVUFo6KioNCg0KYGBge3IgdGFibGEtZGVzY3JpcHRpdmF9DQp2YXJpYWJsZXMgPC0gYygNCiAgImFyZWFfa20yIiwNCiAgInBvYmxhY2lvbiIsDQogICJkZW5zaWRhZF9oYWJfa20yIiwNCiAgInBjdF8wXzE0IiwNCiAgInBjdF8xNV8yOSIsDQogICJwY3RfNjBfbWFzIiwNCiAgImNhc29zX3RvdGFsIiwNCiAgInRhc2FfdG90YWwiDQopDQoNCnRhYmxhX2Rlc2NyaXB0aXZhIDwtIGRhdGEuZnJhbWUoDQogIFZhcmlhYmxlID0gdmFyaWFibGVzLA0KICBNZWRpYSA9IHNhcHBseSh1cHpbdmFyaWFibGVzXSwgbWVhbiwgbmEucm0gPSBUUlVFKSwNCiAgTWVkaWFuYSA9IHNhcHBseSh1cHpbdmFyaWFibGVzXSwgbWVkaWFuLCBuYS5ybSA9IFRSVUUpLA0KICBEZXN2aWFjaW9uID0gc2FwcGx5KHVwelt2YXJpYWJsZXNdLCBzZCwgbmEucm0gPSBUUlVFKSwNCiAgTWluaW1vID0gc2FwcGx5KHVwelt2YXJpYWJsZXNdLCBtaW4sIG5hLnJtID0gVFJVRSksDQogIE1heGltbyA9IHNhcHBseSh1cHpbdmFyaWFibGVzXSwgbWF4LCBuYS5ybSA9IFRSVUUpDQopDQoNCiMgUmVkb25kZWFyIGxhcyBlc3RhZMOtc3RpY2FzIGEgMSBkZWNpbWFsDQp0YWJsYV9kZXNjcmlwdGl2YVstMV0gPC0gbGFwcGx5KHRhYmxhX2Rlc2NyaXB0aXZhWy0xXSwgcm91bmQsIGRpZ2l0cyA9IDEpDQoNCiMgTW9zdHJhciB0YWJsYQ0KdGFibGFfZGVzY3JpcHRpdmEgJT4lDQogIHRhYmxhX2Jvbml0YShyZXNhbHRhciA9IGMoMSwgMikpDQpgYGANCg0KKirCv1NlZ21lbnRhciBsYXMgcG9ibGFjaW9uZXMgcGVybWl0ZSBtZWpvciBhbmFsaXNpcyBkZSBsYSBpbmZvcm1hY2lvbj8qKg0KDQpgYGB7ciBoaXN0by1wb2JsYWNpb259DQpwX3BvYmxhY2lvbl9hcmVhIDwtIGdncGxvdCh1cHosIGFlcyh4ID0gYXJlYV9rbTIsIHkgPSBwb2JsYWNpb24pKSArDQogIGdlb21fcG9pbnQoDQogICAgY29sb3IgPSAiIzZCNEM4QSIsDQogICAgc2l6ZSA9IDIuNSwNCiAgICBhbHBoYSA9IDAuNywNCiAgICBhZXModGV4dCA9IHBhc3RlMCgNCiAgICAgICJVUFo6ICIsIHVwel9ub21icmUsDQogICAgICAiPGJyPsOBcmVhOiAiLCByb3VuZChhcmVhX2ttMiwgMiksICIga23CsiIsDQogICAgICAiPGJyPlBvYmxhY2nDs246ICIsDQogICAgICBmb3JtYXQocm91bmQocG9ibGFjaW9uKSwgYmlnLm1hcmsgPSAiLiIsIGRlY2ltYWwubWFyayA9ICIsIiwNCiAgICAgICAgICAgICBzY2llbnRpZmljID0gRkFMU0UpDQogICAgKSkNCiAgKSArDQogIGdlb21fc21vb3RoKA0KICAgIG1ldGhvZCA9ICJsbSIsDQogICAgc2UgPSBGQUxTRSwNCiAgICBjb2xvciA9ICIjRDE3QTIyIg0KICApICsNCiAgc2NhbGVfeV9jb250aW51b3VzKA0KICAgIGxhYmVscyA9IHNjYWxlczo6bGFiZWxfY29tbWEoDQogICAgICBiaWcubWFyayA9ICIuIiwNCiAgICAgIGRlY2ltYWwubWFyayA9ICIsIg0KICAgICkNCiAgKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiUmVsYWNpw7NuIGVudHJlIHBvYmxhY2nDs24geSDDoXJlYSB0ZXJyaXRvcmlhbCBkZSBsYXMgVVBaIiwNCiAgICB4ID0gIsOBcmVhIHRlcnJpdG9yaWFsIChrbcKyKSIsDQogICAgeSA9ICJQb2JsYWNpw7NuIChoYWJpdGFudGVzKSINCiAgKSArDQogIHRlbWFfY2xhc2UgKw0KICB0aGVtZSgNCiAgICBwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2JsYW5rKCkNCiAgKQ0KDQpnZ3Bsb3RseShwX3BvYmxhY2lvbl9hcmVhLCB0b29sdGlwID0gInRleHQiKSAlPiUNCiAgZXN0aWxvX3Bsb3RseSgpDQpgYGANCg0KQWwgcmV2aXNhciBsb3MgZGF0b3MsIHNlIGV2aWRlbmNpYSBxdWUgbGEgcG9ibGFjacOzbiBwcmVzZW50YSB1bmEgZGlmZXJlbmNpYSBiYXN0YW50ZSBhbXBsaWEgZW50cmUgZWwgdmFsb3IgbcOtbmltbyB5IGVsIG3DoXhpbW8uIFBvciBlc3RhIHJhesOzbiwgY29uc2lkZXJvIG5lY2VzYXJpbyBkaXZpZGlyIGxhcyBVUFogZW4gdHJlcyBncnVwb3M6IHBvYmxhY2nDs24gYmFqYSwgcG9ibGFjacOzbiBtZWRpYSB5IHBvYmxhY2nDs24gYWx0YS4gRXN0byBwZXJtaXRpcsOhIHJlYWxpemFyIGNvbXBhcmFjaW9uZXMgZW50cmUgVVBaIHF1ZSB0ZW5nYW4gY2FyYWN0ZXLDrXN0aWNhcyBwb2JsYWNpb25hbGVzIHNpbWlsYXJlcyB5IGFuYWxpemFyIGRlIHVuYSBtZWpvciBtYW5lcmEgbGFzIHRhc2FzIGRlIGRlbnVuY2lhcywgdGVuaWVuZG8gZW4gY3VlbnRhIHF1ZSBlc3RhcyBwdWVkZW4gdmFyaWFyIGJhc3RhbnRlIGRlcGVuZGllbmRvIGRlIGxhIGNhbnRpZGFkIGRlIGhhYml0YW50ZXMgZGUgY2FkYSB0ZXJyaXRvcmlvLg0KDQpBZGljaW9uYWxtZW50ZSwgc2UgZGViZSBpbmNsdWlyIGVsIGdydXBvIGRlIGVkYWQgZGUgMzAgYSA1OSBhw7FvcywgcGFyYSB0ZW5lciB1bmEgdmlzacOzbiBtw6FzIGNvbXBsZXRhIGRlIGxhIGNvbXBvc2ljacOzbiBkZSBsYSBwb2JsYWNpw7NuIHkgcG9kZXIgYW5hbGl6YXIgY8OzbW8gc2UgcmVsYWNpb25hbiBsb3MgZGlmZXJlbnRlcyByYW5nb3MgZGUgZWRhZCBjb24gbGEgY2FudGlkYWQgeSBsYXMgdGFzYXMgZGUgZGVudW5jaWFzIHJlZ2lzdHJhZGFzLg0K