VISUALIZACIÓN DE DATOS

Inseguridad y territorio en Bogotá:
¿qué nos cuentan las UPZ?
Docente: Carlos Amortegui

Logo de la institución

Preparación de los datos

a. Instalación de paquetes

Para realizar la exploración de los datos se utilizarán paquetes de R que permiten importar archivos, organizar la información y realizar cálculos estadísticos.

El siguiente código instala los paquetes necesarios para trabajar con archivos Excel y CSV, manipular datos y elaborar gráficos.

# Instalación de paquetes necesarios para el proyecto

install.packages("tidyverse")  # Manipulación, transformación y exploración de datos. Incluye dplyr, tidyr, ggplot2 y readr.
install.packages("sf")         # Lectura y manejo de información geográfica. Permite trabajar con los polígonos de las UPZ y localidades.
install.packages("leaflet")    # Creación de mapas interactivos con zoom, etiquetas y resaltado de territorios.
install.packages("scales")     # Formato de números, porcentajes, tasas y escalas en gráficos.
install.packages("knitr")      # Organización y presentación de tablas y resultados dentro del informe R Markdown.

b. Carga de paquetes

Una vez instalados, los paquetes se cargan para poder utilizar sus funciones durante el análisis.

# Cargar las librerías necesarias
library(tidyverse)
library(sf)
library(leaflet)
library(scales)
library(knitr)

c. Configuración general del documento

Configuración del comportamiento general del documento

# Definir la paleta de colores del proyecto
morado   <- "#351A4F"
magenta  <- "#D9006C"
turquesa <- "#168C86"
gris     <- "#D9D6DD"

# Configuración general de los gráficos
tema_clase <- theme_minimal(base_size = 12) +
  theme(
    plot.title.position = "plot",
    plot.title = element_text(
      face = "bold", size = 15, color = morado
    ),
    plot.subtitle = element_text(
      size = 10.5, color = "grey35"
    ),
    panel.grid.minor = element_blank(),
    plot.caption = element_text(
      hjust = 0, color = "grey45", size = 8.5
    ),
    plot.margin = margin(10, 20, 10, 10)
  )

# Opciones generales de presentación del informe
knitr::opts_chunk$set(
  echo = TRUE,
  warning = FALSE,
  message = FALSE,
  fig.align = "center",
  fig.width = 8,
  fig.height = 5,
  dpi = 120
)

1. Introducción

La seguridad ciudadana es una de las dimensiones que influye en la calidad de vida y en las condiciones de convivencia de una ciudad. Sin embargo, su comportamiento no necesariamente es igual en todos los territorios, ya que cada zona presenta características particulares relacionadas con su población, infraestructura, condiciones socioeconómicas y entorno urbano.

En Bogotá, las Unidades de Planeamiento Zonal (UPZ) permiten observar estas diferencias desde una perspectiva territorial. A través de ellas es posible comparar las condiciones de distintos sectores de la ciudad y explorar cómo se relacionan con los registros de delitos y la percepción de inseguridad de sus habitantes.

Este trabajo desarrolla un análisis exploratorio de datos (EDA) sobre las 112 UPZ urbanas de Bogotá, utilizando información relacionada con delitos denunciados, población, vivienda, alumbrado público y condiciones socioeconómicas.

El propósito es identificar patrones, diferencias y posibles relaciones entre las características de cada territorio y los indicadores de seguridad disponibles. Para ello, se utilizarán herramientas estadísticas y visualizaciones que faciliten la interpretación de los resultados, incluyendo representaciones geográficas que permitan reconocer las diferencias entre las zonas de la ciudad.

El análisis no busca establecer relaciones de causalidad ni afirmar que una característica territorial sea la causa directa de determinados comportamientos delictivos. Su alcance es exploratorio y pretende comprender mejor la información disponible, reconocer patrones y generar preguntas que puedan orientar investigaciones posteriores.

1.1. Objetivo general

Explorar las condiciones de seguridad y las características territoriales, demográficas y socioeconómicas de las UPZ urbanas de Bogotá, mediante técnicas de análisis exploratorio de datos y visualización, con el propósito de identificar patrones, diferencias y posibles relaciones que permitan comprender el comportamiento de los indicadores de inseguridad en la ciudad.

1.2. Objetivos específicos

  • Describir la estructura y las características de la información disponible para las 112 UPZ de Bogotá.

  • Explorar la distribución de los indicadores de delitos, población, vivienda, infraestructura y condiciones socioeconómicas.

  • Identificar diferencias territoriales mediante el uso de estadísticas descriptivas, comparaciones y mapas.

  • Examinar posibles relaciones entre los indicadores de seguridad y las características de cada UPZ.

  • Comunicar los principales hallazgos mediante visualizaciones y una narrativa basada en los datos.

2. Descripción de los datos

Para desarrollar el análisis se utiliza una base de datos consolidada que contiene información de 112 Unidades de Planeamiento Zonal de Bogotá. Cada registro representa una UPZ e incluye variables relacionadas con su territorio, población, condiciones de vivienda, infraestructura, delitos denunciados y características socioeconómicas.

La información se encuentra organizada en cinco grandes bloques:

  1. Territorio: identificación de la UPZ, localidad y extensión geográfica.

  2. Demografía: población, densidad poblacional y composición por grupos de edad.

  3. Vivienda e infraestructura: características de las viviendas y disponibilidad de alumbrado público.

  4. Delitos: registros de denuncias y tasas por cada 10.000 habitantes para diez categorías de delitos.

  5. Encuesta Multipropósito: información relacionada con pobreza, ingresos, estrato, educación, percepción de inseguridad y condiciones del entorno.

Adicionalmente, se dispone de archivos geográficos que representan los límites de las UPZ y las localidades urbanas de Bogotá. Estos archivos permitirán integrar la información estadística con su ubicación territorial.

3. Carga de la información

Vamos a conectar nuestro informe con los archivos.

Se cargaran tres fuentes: 1. La base estadística de las UPZ. 2. El mapa de las UPZ. 3. El mapa de las localidades.

# 3.1. Importación de la base estadística

upz <- read_csv(
  "input/upz_variables.csv",
  show_col_types = FALSE
)

# 3.2. Importación de los archivos geográficos

upz_shp <- st_read(
  "input/shp/upz_bogota.shp",
  quiet = TRUE
)

localidades_shp <- st_read(
  "input/shp/localidades_bogota.shp",
  quiet = TRUE
)

Notas:

  • read_csv() permite importar la información estadística.

  • st_read() permite leer los archivos geográficos.

  • Los objetos terminados en **_shp** contienen geometrías que representan los límites territoriales.

4. Exploración inicial de los datos

Antes de realizar los análisis estadísticos y las visualizaciones, es necesario conocer la estructura de la información disponible y verificar sus características generales.

Esta primera exploración permite identificar la cantidad de registros y variables, los tipos de datos utilizados y las condiciones generales de la base. De esta manera, se busca establecer un punto de partida que facilite el desarrollo de las siguientes etapas del análisis.

4.1. Dimensiones y estructura de la información

La base de datos contiene información de diferentes características de las UPZ de Bogotá. Para comenzar, se revisa su dimensión general, identificando cuántos registros y variables están disponibles.

Cada registro representa una UPZ, mientras que las columnas corresponden a las diferentes características e indicadores recopilados para el análisis.

# Consultar las dimensiones generales de la base
dim(upz)
## [1] 112  67
# Identificar la cantidad de registros
nrow(upz)
## [1] 112
# Identificar la cantidad de variables
ncol(upz)
## [1] 67
# Consultar los primeros registros
head(upz)
upz_cod upz_nombre localidad_cod localidad area_km2 poblacion densidad_hab_km2 pct_mujeres pct_0_14 pct_15_29 pct_60_mas viviendas_totales viviendas_ocupadas pct_viviendas_desocupadas personas_por_vivienda luminarias luminarias_km2 luminarias_1000hab pct_luminarias_led casos_homicidios casos_lesiones casos_hurto_personas casos_hurto_residencias casos_hurto_automotor casos_hurto_bicicletas casos_hurto_comercio casos_hurto_celulares casos_hurto_motos casos_violencia_intrafamiliar casos_total tasa_homicidios tasa_lesiones tasa_hurto_personas tasa_hurto_residencias tasa_hurto_automotor tasa_hurto_bicicletas tasa_hurto_comercio tasa_hurto_celulares tasa_hurto_motos tasa_violencia_intrafamiliar tasa_total em_agrupada pct_pobreza edad_promedio salario_promedio pct_estrato_1_2 pct_estrato_3_4 pct_estrato_5_6 pct_vivienda_propia pct_arriendo anios_educacion_15mas pct_padre_universitario pct_madre_universitaria pct_percibe_inseguridad pct_cerca_ollas pct_cerca_bares pct_cerca_lotes_oscuros pct_cerca_basureros pct_cerca_terminales pct_cerca_fabricas min_transmilenio min_sitp min_parque min_cai_policia min_centro_medico min_cultura min_ciclorruta
1 Paseo De Los Libertadores 1 Usaquén 6.33 2690 424.81 51.26 18.85 26.13 12.94 1087 1022 5.98 2.63 524 82.75 194.80 28.44 0 8 44 1 0 1 3 17 0 0 74 0.00 29.74 163.57 3.72 0.00 3.72 11.15 63.20 0.00 0.00 275.09 TRUE 1.37 36.54 3937004 13.92 83.87 2.21 54.45 38.00 12.16 24.14 17.37 36.18 17.53 15.68 24.15 6.13 20.93 11.55 13.01 9.99 7.00 21.66 29.82 33.90 9.00
2 La Academia 11 Suba 6.74 5260 779.85 51.35 24.11 18.46 9.26 1554 1515 2.51 3.47 534 79.17 101.52 0.37 1 3 75 0 3 1 9 26 0 5 123 1.90 5.70 142.59 0.00 5.70 1.90 17.11 49.43 0.00 9.51 233.84 TRUE 0.86 38.71 4280663 0.63 87.06 12.31 57.98 36.81 13.57 24.16 14.82 40.88 7.43 17.03 16.71 1.35 26.66 1.70 10.78 9.56 5.44 24.50 34.17 29.61 13.45
3 Guaymaral 11 Suba 4.55 2692 591.30 51.63 18.31 20.88 14.04 789 698 11.53 3.86 184 40.42 68.35 0.00 0 1 29 0 0 2 2 9 0 2 45 0.00 3.71 107.73 0.00 0.00 7.43 7.43 33.43 0.00 7.43 167.16 TRUE 0.86 38.71 4280663 0.63 87.06 12.31 57.98 36.81 13.57 24.16 14.82 40.88 7.43 17.03 16.71 1.35 26.66 1.70 10.78 9.56 5.44 24.50 34.17 29.61 13.45
9 Verbenal 1 Usaquén 3.57 131999 36967.66 52.77 20.15 25.15 11.61 46809 45055 3.75 2.93 3555 995.61 26.93 65.77 3 104 386 29 19 17 26 125 30 205 944 0.23 7.88 29.24 2.20 1.44 1.29 1.97 9.47 2.27 15.53 71.52 FALSE 3.12 33.28 1933709 31.32 66.05 2.63 36.78 55.53 12.16 8.36 6.13 65.43 17.53 15.68 24.15 6.13 20.93 11.55 6.96 5.96 8.60 18.39 34.18 42.77 14.45
10 La Uribe 1 Usaquén 3.47 37014 10682.12 54.34 17.24 20.18 15.62 14399 13763 4.42 2.69 1328 383.26 35.88 49.25 1 26 328 31 4 14 47 129 1 40 621 0.27 7.02 88.62 8.38 1.08 3.78 12.70 34.85 0.27 10.81 167.77 TRUE 1.37 36.54 3937004 13.92 83.87 2.21 54.45 38.00 12.16 24.14 17.37 36.18 17.53 15.68 24.15 6.13 20.93 11.55 13.01 9.99 7.00 21.66 29.82 33.90 9.00
11 San Cristobal Norte 1 Usaquén 2.76 72939 26401.70 52.65 19.59 24.65 14.38 24886 24401 1.95 2.99 2578 933.16 35.34 49.34 4 73 351 27 5 11 39 117 9 157 793 0.55 10.01 48.12 3.70 0.69 1.51 5.35 16.04 1.23 21.52 108.72 FALSE 5.19 34.50 1368739 29.48 68.87 1.65 28.86 58.05 10.95 4.76 3.31 49.84 25.91 15.41 19.15 8.30 3.38 5.99 17.76 11.43 10.39 25.32 29.71 28.10 18.27

4.2. Tipos de variables y estructura

Además de conocer el tamaño de la base, es importante identificar el tipo de información que contiene cada variable.

Esta revisión permite diferenciar los campos que representan cantidades, porcentajes, tasas, categorías territoriales y otras características.

La identificación de estos tipos de datos es importante porque no todas las variables pueden analizarse de la misma manera. Por ejemplo, una variable de población permite realizar cálculos estadísticos, mientras que una variable como el nombre de la localidad se utiliza principalmente para clasificar y agrupar la información.

# Consultar la estructura y los tipos de variables
glimpse(upz)
## Rows: 112
## Columns: 67
## $ upz_cod                       <dbl> 1, 2, 3, 9, 10, 11, 12, 13, 14, 15, 16, …
## $ upz_nombre                    <chr> "Paseo De Los Libertadores", "La Academi…
## $ localidad_cod                 <dbl> 1, 11, 11, 1, 1, 1, 1, 1, 1, 1, 1, 11, 1…
## $ localidad                     <chr> "Usaquén", "Suba", "Suba", "Usaquén", "U…
## $ area_km2                      <dbl> 6.33, 6.74, 4.55, 3.57, 3.47, 2.76, 2.92…
## $ poblacion                     <dbl> 2690, 5260, 2692, 131999, 37014, 72939, …
## $ densidad_hab_km2              <dbl> 424.81, 779.85, 591.30, 36967.66, 10682.…
## $ pct_mujeres                   <dbl> 51.26, 51.35, 51.63, 52.77, 54.34, 52.65…
## $ pct_0_14                      <dbl> 18.85, 24.11, 18.31, 20.15, 17.24, 19.59…
## $ pct_15_29                     <dbl> 26.13, 18.46, 20.88, 25.15, 20.18, 24.65…
## $ pct_60_mas                    <dbl> 12.94, 9.26, 14.04, 11.61, 15.62, 14.38,…
## $ viviendas_totales             <dbl> 1087, 1554, 789, 46809, 14399, 24886, 24…
## $ viviendas_ocupadas            <dbl> 1022, 1515, 698, 45055, 13763, 24401, 23…
## $ pct_viviendas_desocupadas     <dbl> 5.98, 2.51, 11.53, 3.75, 4.42, 1.95, 3.6…
## $ personas_por_vivienda         <dbl> 2.63, 3.47, 3.86, 2.93, 2.69, 2.99, 2.68…
## $ luminarias                    <dbl> 524, 534, 184, 3555, 1328, 2578, 2734, 5…
## $ luminarias_km2                <dbl> 82.75, 79.17, 40.42, 995.61, 383.26, 933…
## $ luminarias_1000hab            <dbl> 194.80, 101.52, 68.35, 26.93, 35.88, 35.…
## $ pct_luminarias_led            <dbl> 28.44, 0.37, 0.00, 65.77, 49.25, 49.34, …
## $ casos_homicidios              <dbl> 0, 1, 0, 3, 1, 4, 1, 0, 0, 0, 3, 1, 2, 0…
## $ casos_lesiones                <dbl> 8, 3, 1, 104, 26, 73, 52, 75, 36, 14, 49…
## $ casos_hurto_personas          <dbl> 44, 75, 29, 386, 328, 351, 500, 1189, 78…
## $ casos_hurto_residencias       <dbl> 1, 0, 0, 29, 31, 27, 19, 87, 35, 24, 76,…
## $ casos_hurto_automotor         <dbl> 0, 3, 0, 19, 4, 5, 7, 11, 3, 1, 8, 14, 1…
## $ casos_hurto_bicicletas        <dbl> 1, 1, 2, 17, 14, 11, 38, 71, 26, 12, 32,…
## $ casos_hurto_comercio          <dbl> 3, 9, 2, 26, 47, 39, 58, 95, 72, 28, 125…
## $ casos_hurto_celulares         <dbl> 17, 26, 9, 125, 129, 117, 170, 368, 262,…
## $ casos_hurto_motos             <dbl> 0, 0, 0, 30, 1, 9, 6, 3, 3, 0, 5, 8, 8, …
## $ casos_violencia_intrafamiliar <dbl> 0, 5, 2, 205, 40, 157, 92, 92, 73, 14, 4…
## $ casos_total                   <dbl> 74, 123, 45, 944, 621, 793, 943, 1991, 1…
## $ tasa_homicidios               <dbl> 0.00, 1.90, 0.00, 0.23, 0.27, 0.55, 0.16…
## $ tasa_lesiones                 <dbl> 29.74, 5.70, 3.71, 7.88, 7.02, 10.01, 8.…
## $ tasa_hurto_personas           <dbl> 163.57, 142.59, 107.73, 29.24, 88.62, 48…
## $ tasa_hurto_residencias        <dbl> 3.72, 0.00, 0.00, 2.20, 8.38, 3.70, 3.01…
## $ tasa_hurto_automotor          <dbl> 0.00, 5.70, 0.00, 1.44, 1.08, 0.69, 1.11…
## $ tasa_hurto_bicicletas         <dbl> 3.72, 1.90, 7.43, 1.29, 3.78, 1.51, 6.03…
## $ tasa_hurto_comercio           <dbl> 11.15, 17.11, 7.43, 1.97, 12.70, 5.35, 9…
## $ tasa_hurto_celulares          <dbl> 63.20, 49.43, 33.43, 9.47, 34.85, 16.04,…
## $ tasa_hurto_motos              <dbl> 0.00, 0.00, 0.00, 2.27, 0.27, 1.23, 0.95…
## $ tasa_violencia_intrafamiliar  <dbl> 0.00, 9.51, 7.43, 15.53, 10.81, 21.52, 1…
## $ tasa_total                    <dbl> 275.09, 233.84, 167.16, 71.52, 167.77, 1…
## $ em_agrupada                   <lgl> TRUE, TRUE, TRUE, FALSE, TRUE, FALSE, FA…
## $ pct_pobreza                   <dbl> 1.37, 0.86, 0.86, 3.12, 1.37, 5.19, 0.84…
## $ edad_promedio                 <dbl> 36.54, 38.71, 38.71, 33.28, 36.54, 34.50…
## $ salario_promedio              <dbl> 3937004, 4280663, 4280663, 1933709, 3937…
## $ pct_estrato_1_2               <dbl> 13.92, 0.63, 0.63, 31.32, 13.92, 29.48, …
## $ pct_estrato_3_4               <dbl> 83.87, 87.06, 87.06, 66.05, 83.87, 68.87…
## $ pct_estrato_5_6               <dbl> 2.21, 12.31, 12.31, 2.63, 2.21, 1.65, 0.…
## $ pct_vivienda_propia           <dbl> 54.45, 57.98, 57.98, 36.78, 54.45, 28.86…
## $ pct_arriendo                  <dbl> 38.00, 36.81, 36.81, 55.53, 38.00, 58.05…
## $ anios_educacion_15mas         <dbl> 12.16, 13.57, 13.57, 12.16, 12.16, 10.95…
## $ pct_padre_universitario       <dbl> 24.14, 24.16, 24.16, 8.36, 24.14, 4.76, …
## $ pct_madre_universitaria       <dbl> 17.37, 14.82, 14.82, 6.13, 17.37, 3.31, …
## $ pct_percibe_inseguridad       <dbl> 36.18, 40.88, 40.88, 65.43, 36.18, 49.84…
## $ pct_cerca_ollas               <dbl> 17.53, 7.43, 7.43, 17.53, 17.53, 25.91, …
## $ pct_cerca_bares               <dbl> 15.68, 17.03, 17.03, 15.68, 15.68, 15.41…
## $ pct_cerca_lotes_oscuros       <dbl> 24.15, 16.71, 16.71, 24.15, 24.15, 19.15…
## $ pct_cerca_basureros           <dbl> 6.13, 1.35, 1.35, 6.13, 6.13, 8.30, 11.7…
## $ pct_cerca_terminales          <dbl> 20.93, 26.66, 26.66, 20.93, 20.93, 3.38,…
## $ pct_cerca_fabricas            <dbl> 11.55, 1.70, 1.70, 11.55, 11.55, 5.99, 2…
## $ min_transmilenio              <dbl> 13.01, 10.78, 10.78, 6.96, 13.01, 17.76,…
## $ min_sitp                      <dbl> 9.99, 9.56, 9.56, 5.96, 9.99, 11.43, 6.8…
## $ min_parque                    <dbl> 7.00, 5.44, 5.44, 8.60, 7.00, 10.39, 5.1…
## $ min_cai_policia               <dbl> 21.66, 24.50, 24.50, 18.39, 21.66, 25.32…
## $ min_centro_medico             <dbl> 29.82, 34.17, 34.17, 34.18, 29.82, 29.71…
## $ min_cultura                   <dbl> 33.90, 29.61, 29.61, 42.77, 33.90, 28.10…
## $ min_ciclorruta                <dbl> 9.00, 13.45, 13.45, 14.45, 9.00, 18.27, …

4.3. Revisión de valores faltantes

Los valores faltantes representan información que no se encuentra disponible para una o varias variables. Su identificación es importante porque pueden afectar los cálculos estadísticos, las comparaciones y las relaciones entre variables.

En esta etapa se revisa la cantidad de datos faltantes en cada columna, con el propósito de determinar si existen limitaciones en la información disponible.

# Calcular la cantidad de valores faltantes por variable

faltantes <- upz %>%
  summarise(
    across(
      everything(),
      ~ sum(is.na(.))
    )
  ) %>%
  pivot_longer(
    cols = everything(),
    names_to = "Variable",
    values_to = "Cantidad_faltantes"
  ) %>%
  filter(Cantidad_faltantes > 0) %>%
  arrange(desc(Cantidad_faltantes))

# Presentar los resultados

if (nrow(faltantes) == 0) {

  cat("No se encontraron valores faltantes en la base de datos.")

} else {

  knitr::kable(
    faltantes,
    caption = "Variables con valores faltantes"
  )

}
## No se encontraron valores faltantes en la base de datos.

4.4. Identificación de registros duplicados

Debido a que cada registro representa una UPZ, el código de identificación territorial debe ser único dentro de la base de datos.

Por esta razón, se revisa si existen códigos repetidos que puedan generar duplicidad de información o afectar las comparaciones posteriores.

# Identificar códigos UPZ repetidos

duplicados_upz <- upz %>%
  count(upz_cod, name = "Frecuencia") %>%
  filter(Frecuencia > 1)

# Presentar el resultado

if (nrow(duplicados_upz) == 0) {

  cat("No se encontraron códigos UPZ duplicados.")

} else {

  knitr::kable(
    duplicados_upz,
    caption = "Códigos UPZ duplicados"
  )

}
## No se encontraron códigos UPZ duplicados.

4.5. Resumen general de la exploración inicial

Una vez realizadas las verificaciones iniciales, se consolida un resumen de las principales características de la base de datos.

Este resultado permite establecer las condiciones generales de la información con la que se desarrollará el análisis exploratorio.

resumen_base <- tibble(
  Indicador = c(
    "Cantidad de registros",
    "Cantidad de variables",
    "Códigos UPZ únicos",
    "Valores faltantes",
    "Códigos UPZ duplicados"
  ),

  Resultado = c(
    nrow(upz),
    ncol(upz),
    n_distinct(upz$upz_cod),
    sum(is.na(upz)),
    nrow(duplicados_upz)
  )
)

knitr::kable(
  resumen_base,
  col.names = c("Indicador", "Resultado"),
  caption = "Resumen de la exploración inicial"
)
Resumen de la exploración inicial
Indicador Resultado
Cantidad de registros 112
Cantidad de variables 67
Códigos UPZ únicos 112
Valores faltantes 0
Códigos UPZ duplicados 0

Interpretación de la revisión inicial

Los resultados muestran que la base de datos está conformada por 112 registros y 67 variables, con una correspondencia de un registro por cada código UPZ.

En la revisión realizada no se identificaron valores faltantes ni códigos territoriales duplicados. Esto representa una condición favorable para continuar con el análisis exploratorio.

Sin embargo, la ausencia de valores faltantes y duplicados no garantiza por sí sola la calidad de toda la información. Todavía es necesario revisar la distribución de las variables, identificar posibles valores extremos y evaluar la coherencia de los indicadores calculados.

Por lo tanto, esta primera revisión constituye un punto de partida para profundizar en el comportamiento estadístico de las variables.

5. Análisis exploratorio de las variables

Una vez revisada la estructura general de la información, se inicia el análisis exploratorio de las variables con el propósito de comprender su comportamiento, identificar diferencias entre los territorios y reconocer posibles patrones que puedan orientar la investigación.

En esta etapa se utilizarán estadísticas descriptivas y representaciones gráficas para examinar las principales características de las UPZ de Bogotá.

5.1. Análisis demográfico: población y distribución territorial

La población constituye una de las variables fundamentales para comprender las diferencias entre las UPZ, ya que permite dimensionar el tamaño de cada territorio en términos de habitantes.

Su análisis es especialmente importante para este trabajo, porque los indicadores de delitos se expresan tanto en cantidades absolutas como en tasas por cada 10.000 habitantes. Por lo tanto, conocer cómo se distribuye la población permitirá interpretar posteriormente las diferencias en los indicadores de seguridad.

5.1.1. Distribución de la población por UPZ

Inicialmente se analiza la cantidad de habitantes registrados en cada UPZ, con el propósito de identificar las diferencias existentes entre los territorios y reconocer cuáles concentran una mayor o menor población.

a. Estadísticas descriptivas de población

Primero vamos a calcular las principales medidas estadísticas.

# Calcular las principales medidas descriptivas
# de la población de las UPZ

estadisticas_poblacion <- upz %>%
  summarise(
    Total_UPZ = n(),
    Poblacion_total = sum(poblacion),
    Media = mean(poblacion),
    Mediana = median(poblacion),
    Desviacion_estandar = sd(poblacion),
    Minimo = min(poblacion),
    Q1 = quantile(poblacion, 0.25),
    Q3 = quantile(poblacion, 0.75),
    Maximo = max(poblacion)
  )


# Presentar resultados

estadisticas_poblacion %>%
  tidyr::pivot_longer(
    cols = everything(),
    names_to = "Estadística",
    values_to = "Valor"
  ) %>%
  knitr::kable(
    col.names = c("Estadística", "Resultado"),
    caption = "Estadísticas descriptivas de población por UPZ"
  )
Estadísticas descriptivas de población por UPZ
Estadística Resultado
Total_UPZ 112.00
Poblacion_total 7936532.00
Media 70861.89
Mediana 54102.50
Desviacion_estandar 58406.41
Minimo 30.00
Q1 30081.75
Q3 100972.25
Maximo 305907.00

¿Qué estamos calculando?

Medida Qué nos permite conocer
Media Población promedio por UPZ.
Mediana Valor que divide las UPZ en dos grupos iguales.
Desviación estándar Qué tan dispersa está la población respecto a la media.
Mínimo y máximo Los extremos de población.
Q1 El 25 % de las UPZ tiene una población igual o inferior a este valor.
Q3 El 75 % de las UPZ tiene una población igual o inferior a este valor.

Una comparación especialmente importante será la media frente a la mediana. Si la primera es considerablemente mayor, puede indicar que algunas UPZ con poblaciones muy elevadas están influyendo en el promedio.

b. Distribución gráfica de la población

Ahora vamos a visualizar cómo se distribuye la población entre las 112 UPZ

# Histograma de la población por UPZ

ggplot(upz, aes(x = poblacion)) +

  geom_histogram(
    bins = 20,
    fill = magenta,
    color = "white",
    alpha = 0.85
  ) +

  labs(
    title = "Distribución de la población por UPZ",
    subtitle = "Población proyectada para el año 2023",
    x = "Cantidad de habitantes",
    y = "Número de UPZ",
    caption = "Fuente: Base de datos del taller."
  ) +

  scale_x_continuous(
    labels = scales::label_number(
      big.mark = ".",
      decimal.mark = ","
    )
  ) +

  tema_clase

¿Qué buscamos identificar?

El histograma nos permite observar dónde se concentra la mayor cantidad de UPZ según su población.

También nos ayuda a identificar si la distribución es simétrica o si presenta una concentración de territorios con poblaciones pequeñas y unos pocos territorios con poblaciones considerablemente mayores.

No debemos asumir que la población se distribuye de manera uniforme entre las UPZ.

c. Identificación de las UPZ con mayor y menor población

Y como el histograma nos muestra el comportamiento general, pero ahora necesitamos identificar los territorios que se encuentran en los extremos.

Vamos a construir dos rankings: las 10 UPZ más pobladas y las 10 menos pobladas.

# 10 UPZ con mayor población

upz_mayor_poblacion <- upz %>%
  arrange(desc(poblacion)) %>%
  select(
    upz_nombre,
    localidad,
    poblacion
  ) %>%
  slice_head(n = 10)

# 10 UPZ con menor población

upz_menor_poblacion <- upz %>%
  arrange(poblacion) %>%
  select(
    upz_nombre,
    localidad,
    poblacion
  ) %>%
  slice_head(n = 10)

# Presentar las UPZ más pobladas

knitr::kable(
  upz_mayor_poblacion,
  col.names = c("UPZ", "Localidad", "Habitantes"),
  caption = "Las 10 UPZ con mayor población",
  digits = 0
)
Las 10 UPZ con mayor población
UPZ Localidad Habitantes
Tibabuyes Suba 305907
El Rincon Suba 295322
Bosa Central Bosa 237111
Bosa Occidental Bosa 199365
Suba Suba 186728
Garces Navas Engativá 168657
Ismael Perdomo Ciudad Bolívar 166602
Lucero Ciudad Bolívar 163588
El Porvenir Bosa 143758
Engativa Engativá 142612
# Presentar las UPZ menos pobladas

knitr::kable(
  upz_menor_poblacion,
  col.names = c("UPZ", "Localidad", "Habitantes"),
  caption = "Las 10 UPZ con menor población",
  digits = 0
)
Las 10 UPZ con menor población
UPZ Localidad Habitantes
El Mochuelo Ciudad Bolívar 30
Aeropuerto El Dorado Fontibón 883
Parque Entrenubes Usme 1169
Parque Salitre Barrios Unidos 1442
Paseo De Los Libertadores Usaquén 2690
Guaymaral Suba 2692
Jardin Botanico Engativá 2900
Parque Simon Bolivar - Can Teusaquillo 3323
La Academia Suba 5260
Monte Blanco Ciudad Bolívar 6575

d. Visualización - Grafico

Ahora vamos a representar visualmente estos resultados.

# Preparar los datos de las 10 UPZ más pobladas

ggplot(
  upz_mayor_poblacion,
  aes(
    x = reorder(upz_nombre, poblacion),
    y = poblacion
  )
) +

  geom_col(
    fill = morado,
    width = 0.7
  ) +

  coord_flip() +

  labs(
    title = "Las UPZ con mayor concentración de población",
    subtitle = "Ranking de las 10 UPZ más pobladas de Bogotá",
    x = NULL,
    y = "Cantidad de habitantes",
    caption = "Fuente: Base de datos del taller."
  ) +

  scale_y_continuous(
    labels = scales::label_number(
      big.mark = ".",
      decimal.mark = ","
    )
  ) +

  tema_clase

5.1.2. Análisis de la densidad poblacional

La cantidad de habitantes no es el único elemento que permite caracterizar un territorio. También es importante considerar su extensión geográfica para comprender qué tan concentrada se encuentra la población.

Para ello se utiliza la densidad poblacional, medida en habitantes por kilómetro cuadrado (hab/km²). Este indicador relaciona la población de cada UPZ con el área que ocupa.

Su análisis permite diferenciar territorios con grandes poblaciones y extensiones amplias de aquellos que presentan una mayor concentración de habitantes en superficies más reducidas.

a. Estadísticas descriptivas de densidad

# Estadísticas descriptivas de densidad poblacional

estadisticas_densidad <- upz %>%
  summarise(
    Media = mean(densidad_hab_km2),
    Mediana = median(densidad_hab_km2),
    Desviacion_estandar = sd(densidad_hab_km2),
    Minimo = min(densidad_hab_km2),
    Q1 = quantile(densidad_hab_km2, 0.25),
    Q3 = quantile(densidad_hab_km2, 0.75),
    Maximo = max(densidad_hab_km2)
  )

knitr::kable(
  estadisticas_densidad,
  digits = 2,
  caption = "Estadísticas descriptivas de la densidad poblacional"
)
Estadísticas descriptivas de la densidad poblacional
Media Mediana Desviacion_estandar Minimo Q1 Q3 Maximo
19119.36 20180.22 10801.85 9.44 11160.41 25826.54 46156.87

b. UPZ con mayor y menor densidad

# Identificar las UPZ con mayor densidad poblacional

ranking_densidad <- upz %>%
  arrange(desc(densidad_hab_km2)) %>%
  select(
    upz_nombre,
    localidad,
    poblacion,
    area_km2,
    densidad_hab_km2
  )

# Presentar las 10 UPZ con mayor densidad

knitr::kable(
  ranking_densidad %>% slice_head(n = 10),
  col.names = c(
    "UPZ",
    "Localidad",
    "Habitantes",
    "Área (km²)",
    "Densidad (hab/km²)"
  ),
  digits = 2,
  caption = "Las 10 UPZ con mayor densidad poblacional"
)
Las 10 UPZ con mayor densidad poblacional
UPZ Localidad Habitantes Área (km²) Densidad (hab/km²)
Bosa Occidental Bosa 199365 4.32 46156.87
Patio Bonito Kennedy 137776 3.18 43262.66
Calandaima Kennedy 134340 3.20 41970.43
Tibabuyes Suba 305907 7.29 41963.01
El Rincon Suba 295322 7.13 41440.43
San Francisco Ciudad Bolívar 72057 1.79 40199.86
Verbenal Usaquén 131999 3.57 36967.66
Diana Turbay Rafael Uribe Uribe 76093 2.12 35859.94
Gran Britalia Kennedy 62139 1.81 34416.53
Marruecos Rafael Uribe Uribe 123085 3.64 33796.36
# Presentar las 10 UPZ con menor densidad

knitr::kable(
  ranking_densidad %>% arrange(densidad_hab_km2) %>% slice_head(n = 10),
  col.names = c(
    "UPZ",
    "Localidad",
    "Habitantes",
    "Área (km²)",
    "Densidad (hab/km²)"
  ),
  digits = 2,
  caption = "Las 10 UPZ con menor densidad poblacional"
)
Las 10 UPZ con menor densidad poblacional
UPZ Localidad Habitantes Área (km²) Densidad (hab/km²)
El Mochuelo Ciudad Bolívar 30 3.18 9.44
Aeropuerto El Dorado Fontibón 883 7.46 118.40
Parque Entrenubes Usme 1169 4.21 277.97
Paseo De Los Libertadores Usaquén 2690 6.33 424.81
Guaymaral Suba 2692 4.55 591.30
La Academia Suba 5260 6.74 779.85
Parque Simon Bolivar - Can Teusaquillo 3323 4.00 830.50
Parque Salitre Barrios Unidos 1442 1.66 869.50
Monte Blanco Ciudad Bolívar 6575 6.98 941.73
Jardin Botanico Engativá 2900 1.62 1786.96

c. Comparación gráfica de densidad

# Visualizar las 10 UPZ con mayor densidad poblacional

ggplot(
  ranking_densidad %>% slice_head(n = 10),
  aes(
    x = reorder(upz_nombre, densidad_hab_km2),
    y = densidad_hab_km2
  )
) +

  geom_col(
    fill = turquesa,
    width = 0.7
  ) +

  coord_flip() +

  labs(
    title = "Concentración de población en las UPZ",
    subtitle = "Territorios con mayor densidad poblacional",
    x = NULL,
    y = "Habitantes por km²",
    caption = "Fuente: Base de datos del taller."
  ) +

  scale_y_continuous(
    labels = scales::label_number(
      big.mark = ".",
      decimal.mark = ","
    )
  ) +

  tema_clase

5.1.3. Relación entre población y extensión territorial

Para complementar el análisis anterior, se examina la relación entre la población y el área geográfica de cada UPZ.

Esta comparación permite observar si los territorios con mayor extensión también concentran una mayor cantidad de habitantes o si existen diferencias importantes en la ocupación del espacio.

La visualización se realiza mediante un diagrama de dispersión, en el que cada punto representa una UPZ.

# Relación entre población y área territorial

ggplot(
  upz,
  aes(
    x = area_km2,
    y = poblacion
  )
) +

  geom_point(
    color = magenta,
    size = 2.8,
    alpha = 0.75
  ) +

  geom_smooth(
    method = "lm",
    se = FALSE,
    color = morado,
    linewidth = 0.9
  ) +

  labs(
    title = "Relación entre población y área de las UPZ",
    subtitle = "Cada punto representa una unidad territorial",
    x = "Área de la UPZ (km²)",
    y = "Cantidad de habitantes",
    caption = "Fuente: Base de datos del taller."
  ) +

  scale_y_continuous(
    labels = scales::label_number(
      big.mark = ".",
      decimal.mark = ","
    )
  ) +

  tema_clase

¿Qué debemos observar?

  • Si existe una tendencia positiva entre el área y la población.

  • Si las UPZ de mayor extensión concentran necesariamente más habitantes.

  • Si existen territorios que se apartan del comportamiento general.

La línea representa una tendencia lineal de referencia. No significa que el área territorial explique por sí sola la cantidad de habitantes.

5.1.4. Identificación de valores extremos en la población

Durante el análisis de la población es importante identificar territorios que presenten valores considerablemente diferentes al comportamiento general de las UPZ.

Para ello se utiliza el rango intercuartílico (IQR), que corresponde a la diferencia entre el tercer y el primer cuartil de la distribución.

Mediante este procedimiento se identifican posibles valores atípicos, entendidos como observaciones que se encuentran por fuera de los límites estadísticos establecidos.

La identificación de estos valores no significa que deban eliminarse de la información. Por el contrario, permite reconocer territorios con características particulares que deben considerarse en las comparaciones posteriores.

# Calcular los límites para identificar posibles valores atípicos

q1_poblacion <- quantile(upz$poblacion, 0.25)

q3_poblacion <- quantile(upz$poblacion, 0.75)

iqr_poblacion <- IQR(upz$poblacion)

limite_inferior <- q1_poblacion - 1.5 * iqr_poblacion

limite_superior <- q3_poblacion + 1.5 * iqr_poblacion

# Identificar las UPZ que se encuentran fuera de los límites

valores_extremos <- upz %>%
  filter(
    poblacion < limite_inferior |
    poblacion > limite_superior
  ) %>%
  select(
    upz_nombre,
    localidad,
    poblacion,
    area_km2,
    densidad_hab_km2
  ) %>%
  arrange(desc(poblacion))

# Presentar resultados

knitr::kable(
  valores_extremos,
  col.names = c(
    "UPZ",
    "Localidad",
    "Habitantes",
    "Área (km²)",
    "Densidad (hab/km²)"
  ),
  digits = 2,
  caption = "UPZ identificadas como posibles valores atípicos en población"
)
UPZ identificadas como posibles valores atípicos en población
UPZ Localidad Habitantes Área (km²) Densidad (hab/km²)
Tibabuyes Suba 305907 7.29 41963.01
El Rincon Suba 295322 7.13 41440.43
Bosa Central Bosa 237111 7.17 33059.28
# Mostrar los límites estadísticos

cat("Límite inferior:", round(limite_inferior, 2), "\n")
## Límite inferior: -76254
cat("Límite superior:", round(limite_superior, 2), "\n")
## Límite superior: 207308
cat("Cantidad de posibles valores atípicos:", nrow(valores_extremos))
## Cantidad de posibles valores atípicos: 3

5.1.5. Interpretación del análisis demográfico

El análisis demográfico permite reconocer que las UPZ presentan características diferentes en cuanto a su población, extensión y densidad.

Estas diferencias son relevantes para el desarrollo de la investigación, debido a que los indicadores de seguridad pueden presentar comportamientos distintos dependiendo del tamaño y las características de cada territorio.

La identificación de posibles valores extremos también permite reconocer que algunas UPZ pueden tener condiciones particulares que requieren un tratamiento diferenciado al momento de realizar comparaciones estadísticas.

A partir de estos resultados será posible establecer una base más sólida para analizar los indicadores de delitos, diferenciando las cantidades absolutas de las tasas calculadas por habitante.

LS0tDQp0aXRsZTogIlRBTExFUiBERSBJTlNJR0hUUyDCtyBBTsOBTElTSVMgRVhQTE9SQVRPUklPIChFREEpIg0KYXV0aG9yOiAiSmVyc29uIERhdmlkIEN1ZWxsYXIgVmFuZWdhcyB5IEpvc2UgRWZyYWluIENhc3RpbGxvIg0KZGF0ZTogImByIGZvcm1hdChTeXMuRGF0ZSgpLCAnJWQgZGUgJUIgZGUgJVknKWAiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgdG9jOiB0cnVlDQogICAgdG9jX2Zsb2F0OiB0cnVlDQogICAgdGhlbWU6IGZsYXRseQ0KICAgIGRmX3ByaW50OiBrYWJsZQ0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUgICAjIGFncmVnYSB1biBib3TDs24gcGFyYSBkZXNjYXJnYXIgZWwgLlJtZCBvcmlnaW5hbCAtLSByZWZ1ZXJ6YSBsYSByZXByb2R1Y2liaWxpZGFkDQotLS0NCg0KDQpgYGB7PWh0bWx9DQo8c3R5bGU+DQovKiBUaXBvZ3JhZsOtYSBlZGl0b3JpYWwgZGVsIGN1cnNvIChtaXNtYSBxdWUgbGxldmFuIGxvcyBncsOhZmljb3MgdsOtYQ0KICAgc2hvd3RleHQpIHRhbWJpw6luIHBhcmEgZWwgdGV4dG8gZGVsIGRvY3VtZW50byAtLSBxdWUgdG9kbyBlbCBpbmZvcm1lDQogICBzZSBzaWVudGEgY29tbyB1bmEgc29sYSBwaWV6YSwgbm8gdW4gSFRNTCBnZW7DqXJpY28gY29uIGdyw6FmaWNvcyBwZWdhZG9zLiAqLw0KQGltcG9ydCB1cmwoJ2h0dHBzOi8vZm9udHMuZ29vZ2xlYXBpcy5jb20vY3NzMj9mYW1pbHk9RmlyYStTYW5zOndnaHRANDAwOzYwMDs3MDAmZGlzcGxheT1zd2FwJyk7DQoNCmJvZHkgeyBmb250LWZhbWlseTogJ0ZpcmEgU2FucycsIC1hcHBsZS1zeXN0ZW0sIEJsaW5rTWFjU3lzdGVtRm9udCwgc2Fucy1zZXJpZjsgY29sb3I6ICMyQjI1MzA7IH0NCmgxLCBoMiwgaDMgeyBmb250LWZhbWlseTogJ0ZpcmEgU2FucycsIHNhbnMtc2VyaWY7IGNvbG9yOiAjMzUxQTRGOyB9DQpoMSB7IGJvcmRlci1ib3R0b206IDNweCBzb2xpZCAjRDkwMDZDOyBwYWRkaW5nLWJvdHRvbTogOHB4OyBtYXJnaW4tdG9wOiA0OHB4OyB9DQpoMiB7IG1hcmdpbi10b3A6IDM2cHg7IH0NCmEgeyBjb2xvcjogI0Q5MDA2QzsgfQ0KYTpob3ZlciB7IGNvbG9yOiAjMTY4Qzg2OyB9DQojVE9DIHsgYm9yZGVyLXJhZGl1czogMTBweDsgfQ0KLm5hdi1waWxscyA+IGxpLmFjdGl2ZSA+IGEsIC5uYXYtcGlsbHMgPiBsaS5hY3RpdmUgPiBhOmhvdmVyIHsgYmFja2dyb3VuZC1jb2xvcjogIzM1MUE0RiAhaW1wb3J0YW50OyB9DQpjYXB0aW9uIHsgY29sb3I6ICM1QTU1NjA7IGZvbnQtc3R5bGU6IGl0YWxpYzsgY2FwdGlvbi1zaWRlOiB0b3A7IH0NCmNvZGUgeyBjb2xvcjogIzhBMUE1QzsgYmFja2dyb3VuZDogI0Y2RUVGMjsgcGFkZGluZzogMXB4IDVweDsgYm9yZGVyLXJhZGl1czogNHB4OyB9DQp0YWJsZS5kYXRhVGFibGUgeyBmb250LXNpemU6IDAuOTJyZW07IH0NCi5sZWFmbGV0LWNvbnRhaW5lciB7IGJvcmRlci1yYWRpdXM6IDEwcHg7IGJhY2tncm91bmQ6ICNFQUYwRjQgIWltcG9ydGFudDsgfQ0KPC9zdHlsZT4NCmBgYA0KDQoNCjo6Ojo6Ojoge3N0eWxlPSJiYWNrZ3JvdW5kOiBsaW5lYXItZ3JhZGllbnQoMTM1ZGVnLCAjMzUxQTRGIDAlLCAjRDkwMDZDIDEwMCUpOyBwYWRkaW5nOiAyNnB4IDMwcHg7IGJvcmRlci1yYWRpdXM6IDE0cHg7IG1hcmdpbi1ib3R0b206IDMwcHg7IGRpc3BsYXk6IGZsZXg7IGFsaWduLWl0ZW1zOiBjZW50ZXI7IGp1c3RpZnktY29udGVudDogc3BhY2UtYmV0d2VlbjsgZmxleC13cmFwOiB3cmFwOyBnYXA6IDE4cHg7In0NCjo6Ojo6IHtzdHlsZT0ibWF4LXdpZHRoOiA2MjBweDsifQ0KOjo6IHtzdHlsZT0iY29sb3I6IHdoaXRlOyBmb250LXNpemU6IDEuNTVyZW07IGZvbnQtd2VpZ2h0OiA3MDA7IGxpbmUtaGVpZ2h0OiAxLjI1OyJ9DQpWSVNVQUxJWkFDScOTTiBERSBEQVRPUw0KOjo6DQoNCjo6OiB7c3R5bGU9ImNvbG9yOiAjRjREQ0U5OyBmb250LXNpemU6IDFyZW07IG1hcmdpbi10b3A6IDZweDsifQ0KSW5zZWd1cmlkYWQgeSB0ZXJyaXRvcmlvIGVuIEJvZ290w6E6IDxicj4NCsK/cXXDqSBub3MgY3VlbnRhbiBsYXMgVVBaPyA8YnI+DQpEb2NlbnRlOiBDYXJsb3MgQW1vcnRlZ3VpDQo6OjoNCjo6Ojo6DQoNCjo6OiB7c3R5bGU9ImJhY2tncm91bmQ6IHdoaXRlOyBwYWRkaW5nOiAxMHB4IDE4cHg7IGJvcmRlci1yYWRpdXM6IDEwcHg7IGZsZXgtc2hyaW5rOiAwOyJ9DQo8aW1nIHNyYz0iQzovVXNlcnMvamVyc28vT25lRHJpdmUvRG9jdW1lbnRvcy9FZHVjYWNpb24vUiUyME1hcmtkb3duL1Byb3llY3RvX1Zpc3VhbGl6YWNpb24vX290cm9zL2xvZ29fS29ucmFkX0xvcmVuei5wbmciDQogICAgIGFsdD0iTG9nbyBkZSBsYSBpbnN0aXR1Y2nDs24iDQogICAgIHN0eWxlPSJtYXgtd2lkdGg6IDIxMHB4OyBkaXNwbGF5OiBibG9jazsiLz4NCjo6Og0KOjo6Ojo6Og0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCiMgaW5jbHVkZT1GQUxTRTogZXN0ZSBjaHVuayBjb25maWd1cmEgZWwgZG9jdW1lbnRvIHBlcm8gbm8gYXBhcmVjZSBlbiBlbA0KIyBIVE1MIGZpbmFsIC0tIG5pIGVsIGPDs2RpZ28gbmkgbmluZ8O6biByZXN1bHRhZG8uDQojDQojIGtuaXRyOjpvcHRzX2NodW5rJHNldCgpIGNhbWJpYSBlbCBjb21wb3J0YW1pZW50byBkZSBUT0RPUyBsb3MgY2h1bmtzDQojIHF1ZSB2aWVuZW4gZGVzcHXDqXMsIGRlIHVuYSBzb2xhIHZleiwgZW4gdmV6IGRlIHJlcGV0aXIgbGEgbWlzbWEgb3BjacOzbg0KIyBjaHVuayBwb3IgY2h1bmsuDQprbml0cjo6b3B0c19jaHVuayRzZXQoDQogIGVjaG8gPSBUUlVFLCAgICAgICAgIyBtdWVzdHJhIGVsIGPDs2RpZ28gZGUgUiBlbiBlbCBIVE1MIChjb24gImNvZGVfZm9sZGluZzogaGlkZSIgYXJyaWJhLCBxdWVkYSBvY3VsdG8gcG9yIGRlZmVjdG8gcGVybyBzZSBwdWVkZSBkZXNwbGVnYXIpDQogIHdhcm5pbmcgPSBGQUxTRSwgICAgICMgbm8gbXVlc3RyYSB3YXJuaW5ncyBkZSBSIGVuIGVsIHJlcG9ydGUNCiAgbWVzc2FnZSA9IEZBTFNFLCAgICAgIyBubyBtdWVzdHJhIG1lbnNhamVzIGluZm9ybWF0aXZvcyAoY29tbyBsb3MgZGUgbGlicmFyeSgpKQ0KICBmaWcuYWxpZ24gPSAiY2VudGVyIiwNCiAgZmlnLndpZHRoID0gOCwNCiAgZmlnLmhlaWdodCA9IDUNCikNCmBgYA0KDQojIFByZXBhcmFjacOzbiBkZSBsb3MgZGF0b3MNCg0KIyMgYS4gSW5zdGFsYWNpw7NuIGRlIHBhcXVldGVzDQpQYXJhIHJlYWxpemFyIGxhIGV4cGxvcmFjacOzbiBkZSBsb3MgZGF0b3Mgc2UgdXRpbGl6YXLDoW4gcGFxdWV0ZXMNCmRlIFIgcXVlIHBlcm1pdGVuIGltcG9ydGFyIGFyY2hpdm9zLCBvcmdhbml6YXIgbGEgaW5mb3JtYWNpw7NuDQp5IHJlYWxpemFyIGPDoWxjdWxvcyBlc3RhZMOtc3RpY29zLg0KDQpFbCBzaWd1aWVudGUgY8OzZGlnbyBpbnN0YWxhIGxvcyBwYXF1ZXRlcyBuZWNlc2FyaW9zIHBhcmEgdHJhYmFqYXINCmNvbiBhcmNoaXZvcyBFeGNlbCB5IENTViwgbWFuaXB1bGFyIGRhdG9zIHkgZWxhYm9yYXIgZ3LDoWZpY29zLg0KDQpgYGB7ciBpbnN0YWxhY2lvbi1wYXF1ZXRlcywgZXZhbD1GQUxTRX0NCg0KIyBJbnN0YWxhY2nDs24gZGUgcGFxdWV0ZXMgbmVjZXNhcmlvcyBwYXJhIGVsIHByb3llY3RvDQoNCmluc3RhbGwucGFja2FnZXMoInRpZHl2ZXJzZSIpICAjIE1hbmlwdWxhY2nDs24sIHRyYW5zZm9ybWFjacOzbiB5IGV4cGxvcmFjacOzbiBkZSBkYXRvcy4gSW5jbHV5ZSBkcGx5ciwgdGlkeXIsIGdncGxvdDIgeSByZWFkci4NCmluc3RhbGwucGFja2FnZXMoInNmIikgICAgICAgICAjIExlY3R1cmEgeSBtYW5lam8gZGUgaW5mb3JtYWNpw7NuIGdlb2dyw6FmaWNhLiBQZXJtaXRlIHRyYWJhamFyIGNvbiBsb3MgcG9sw61nb25vcyBkZSBsYXMgVVBaIHkgbG9jYWxpZGFkZXMuDQppbnN0YWxsLnBhY2thZ2VzKCJsZWFmbGV0IikgICAgIyBDcmVhY2nDs24gZGUgbWFwYXMgaW50ZXJhY3Rpdm9zIGNvbiB6b29tLCBldGlxdWV0YXMgeSByZXNhbHRhZG8gZGUgdGVycml0b3Jpb3MuDQppbnN0YWxsLnBhY2thZ2VzKCJzY2FsZXMiKSAgICAgIyBGb3JtYXRvIGRlIG7Dum1lcm9zLCBwb3JjZW50YWplcywgdGFzYXMgeSBlc2NhbGFzIGVuIGdyw6FmaWNvcy4NCmluc3RhbGwucGFja2FnZXMoImtuaXRyIikgICAgICAjIE9yZ2FuaXphY2nDs24geSBwcmVzZW50YWNpw7NuIGRlIHRhYmxhcyB5IHJlc3VsdGFkb3MgZGVudHJvIGRlbCBpbmZvcm1lIFIgTWFya2Rvd24uDQpgYGANCg0KIyMgYi4gQ2FyZ2EgZGUgcGFxdWV0ZXMNClVuYSB2ZXogaW5zdGFsYWRvcywgbG9zIHBhcXVldGVzIHNlIGNhcmdhbiBwYXJhIHBvZGVyIHV0aWxpemFyDQpzdXMgZnVuY2lvbmVzIGR1cmFudGUgZWwgYW7DoWxpc2lzLg0KDQpgYGB7ciBjYXJnYS1wYXF1ZXRlcywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCg0KIyBDYXJnYXIgbGFzIGxpYnJlcsOtYXMgbmVjZXNhcmlhcw0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KHNmKQ0KbGlicmFyeShsZWFmbGV0KQ0KbGlicmFyeShzY2FsZXMpDQpsaWJyYXJ5KGtuaXRyKQ0KYGBgDQoNCiMjIGMuIENvbmZpZ3VyYWNpw7NuIGdlbmVyYWwgZGVsIGRvY3VtZW50bw0KQ29uZmlndXJhY2nDs24gZGVsIGNvbXBvcnRhbWllbnRvIGdlbmVyYWwgZGVsIGRvY3VtZW50bw0KDQpgYGB7ciBDb25maWd1cmFjaW9uLWRvYywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCg0KIyBEZWZpbmlyIGxhIHBhbGV0YSBkZSBjb2xvcmVzIGRlbCBwcm95ZWN0bw0KbW9yYWRvICAgPC0gIiMzNTFBNEYiDQptYWdlbnRhICA8LSAiI0Q5MDA2QyINCnR1cnF1ZXNhIDwtICIjMTY4Qzg2Ig0KZ3JpcyAgICAgPC0gIiNEOUQ2REQiDQoNCiMgQ29uZmlndXJhY2nDs24gZ2VuZXJhbCBkZSBsb3MgZ3LDoWZpY29zDQp0ZW1hX2NsYXNlIDwtIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTIpICsNCiAgdGhlbWUoDQogICAgcGxvdC50aXRsZS5wb3NpdGlvbiA9ICJwbG90IiwNCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KA0KICAgICAgZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDE1LCBjb2xvciA9IG1vcmFkbw0KICAgICksDQogICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dCgNCiAgICAgIHNpemUgPSAxMC41LCBjb2xvciA9ICJncmV5MzUiDQogICAgKSwNCiAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLA0KICAgIHBsb3QuY2FwdGlvbiA9IGVsZW1lbnRfdGV4dCgNCiAgICAgIGhqdXN0ID0gMCwgY29sb3IgPSAiZ3JleTQ1Iiwgc2l6ZSA9IDguNQ0KICAgICksDQogICAgcGxvdC5tYXJnaW4gPSBtYXJnaW4oMTAsIDIwLCAxMCwgMTApDQogICkNCg0KIyBPcGNpb25lcyBnZW5lcmFsZXMgZGUgcHJlc2VudGFjacOzbiBkZWwgaW5mb3JtZQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KA0KICBlY2hvID0gVFJVRSwNCiAgd2FybmluZyA9IEZBTFNFLA0KICBtZXNzYWdlID0gRkFMU0UsDQogIGZpZy5hbGlnbiA9ICJjZW50ZXIiLA0KICBmaWcud2lkdGggPSA4LA0KICBmaWcuaGVpZ2h0ID0gNSwNCiAgZHBpID0gMTIwDQopDQoNCmBgYA0KDQoNCiMgMS4gSW50cm9kdWNjacOzbg0KDQpMYSBzZWd1cmlkYWQgY2l1ZGFkYW5hIGVzIHVuYSBkZSBsYXMgZGltZW5zaW9uZXMgcXVlIGluZmx1eWUNCmVuIGxhIGNhbGlkYWQgZGUgdmlkYSB5IGVuIGxhcyBjb25kaWNpb25lcyBkZSBjb252aXZlbmNpYSBkZQ0KdW5hIGNpdWRhZC4gU2luIGVtYmFyZ28sIHN1IGNvbXBvcnRhbWllbnRvIG5vIG5lY2VzYXJpYW1lbnRlDQplcyBpZ3VhbCBlbiB0b2RvcyBsb3MgdGVycml0b3Jpb3MsIHlhIHF1ZSBjYWRhIHpvbmEgcHJlc2VudGENCmNhcmFjdGVyw61zdGljYXMgcGFydGljdWxhcmVzIHJlbGFjaW9uYWRhcyBjb24gc3UgcG9ibGFjacOzbiwNCmluZnJhZXN0cnVjdHVyYSwgY29uZGljaW9uZXMgc29jaW9lY29uw7NtaWNhcyB5IGVudG9ybm8gdXJiYW5vLg0KDQpFbiBCb2dvdMOhLCBsYXMgVW5pZGFkZXMgZGUgUGxhbmVhbWllbnRvIFpvbmFsIChVUFopIHBlcm1pdGVuDQpvYnNlcnZhciBlc3RhcyBkaWZlcmVuY2lhcyBkZXNkZSB1bmEgcGVyc3BlY3RpdmEgdGVycml0b3JpYWwuDQpBIHRyYXbDqXMgZGUgZWxsYXMgZXMgcG9zaWJsZSBjb21wYXJhciBsYXMgY29uZGljaW9uZXMgZGUNCmRpc3RpbnRvcyBzZWN0b3JlcyBkZSBsYSBjaXVkYWQgeSBleHBsb3JhciBjw7NtbyBzZSByZWxhY2lvbmFuDQpjb24gbG9zIHJlZ2lzdHJvcyBkZSBkZWxpdG9zIHkgbGEgcGVyY2VwY2nDs24gZGUgaW5zZWd1cmlkYWQNCmRlIHN1cyBoYWJpdGFudGVzLg0KDQpFc3RlIHRyYWJham8gZGVzYXJyb2xsYSB1biBhbsOhbGlzaXMgZXhwbG9yYXRvcmlvIGRlIGRhdG9zDQooRURBKSBzb2JyZSBsYXMgMTEyIFVQWiB1cmJhbmFzIGRlIEJvZ290w6EsIHV0aWxpemFuZG8NCmluZm9ybWFjacOzbiByZWxhY2lvbmFkYSBjb24gZGVsaXRvcyBkZW51bmNpYWRvcywgcG9ibGFjacOzbiwNCnZpdmllbmRhLCBhbHVtYnJhZG8gcMO6YmxpY28geSBjb25kaWNpb25lcyBzb2Npb2Vjb27Ds21pY2FzLg0KDQpFbCBwcm9ww7NzaXRvIGVzIGlkZW50aWZpY2FyIHBhdHJvbmVzLCBkaWZlcmVuY2lhcyB5IHBvc2libGVzDQpyZWxhY2lvbmVzIGVudHJlIGxhcyBjYXJhY3RlcsOtc3RpY2FzIGRlIGNhZGEgdGVycml0b3JpbyB5DQpsb3MgaW5kaWNhZG9yZXMgZGUgc2VndXJpZGFkIGRpc3BvbmlibGVzLiBQYXJhIGVsbG8sIHNlDQp1dGlsaXphcsOhbiBoZXJyYW1pZW50YXMgZXN0YWTDrXN0aWNhcyB5IHZpc3VhbGl6YWNpb25lcw0KcXVlIGZhY2lsaXRlbiBsYSBpbnRlcnByZXRhY2nDs24gZGUgbG9zIHJlc3VsdGFkb3MsIGluY2x1eWVuZG8NCnJlcHJlc2VudGFjaW9uZXMgZ2VvZ3LDoWZpY2FzIHF1ZSBwZXJtaXRhbiByZWNvbm9jZXIgbGFzDQpkaWZlcmVuY2lhcyBlbnRyZSBsYXMgem9uYXMgZGUgbGEgY2l1ZGFkLg0KDQpFbCBhbsOhbGlzaXMgbm8gYnVzY2EgZXN0YWJsZWNlciByZWxhY2lvbmVzIGRlIGNhdXNhbGlkYWQNCm5pIGFmaXJtYXIgcXVlIHVuYSBjYXJhY3RlcsOtc3RpY2EgdGVycml0b3JpYWwgc2VhIGxhIGNhdXNhDQpkaXJlY3RhIGRlIGRldGVybWluYWRvcyBjb21wb3J0YW1pZW50b3MgZGVsaWN0aXZvcy4gU3UNCmFsY2FuY2UgZXMgZXhwbG9yYXRvcmlvIHkgcHJldGVuZGUgY29tcHJlbmRlciBtZWpvciBsYQ0KaW5mb3JtYWNpw7NuIGRpc3BvbmlibGUsIHJlY29ub2NlciBwYXRyb25lcyB5IGdlbmVyYXINCnByZWd1bnRhcyBxdWUgcHVlZGFuIG9yaWVudGFyIGludmVzdGlnYWNpb25lcyBwb3N0ZXJpb3Jlcy4NCg0KDQojIyAxLjEuIE9iamV0aXZvIGdlbmVyYWwNCg0KRXhwbG9yYXIgbGFzIGNvbmRpY2lvbmVzIGRlIHNlZ3VyaWRhZCB5IGxhcyBjYXJhY3RlcsOtc3RpY2FzDQp0ZXJyaXRvcmlhbGVzLCBkZW1vZ3LDoWZpY2FzIHkgc29jaW9lY29uw7NtaWNhcyBkZSBsYXMgVVBaDQp1cmJhbmFzIGRlIEJvZ290w6EsIG1lZGlhbnRlIHTDqWNuaWNhcyBkZSBhbsOhbGlzaXMgZXhwbG9yYXRvcmlvDQpkZSBkYXRvcyB5IHZpc3VhbGl6YWNpw7NuLCBjb24gZWwgcHJvcMOzc2l0byBkZSBpZGVudGlmaWNhcg0KcGF0cm9uZXMsIGRpZmVyZW5jaWFzIHkgcG9zaWJsZXMgcmVsYWNpb25lcyBxdWUgcGVybWl0YW4NCmNvbXByZW5kZXIgZWwgY29tcG9ydGFtaWVudG8gZGUgbG9zIGluZGljYWRvcmVzIGRlDQppbnNlZ3VyaWRhZCBlbiBsYSBjaXVkYWQuDQoNCg0KIyMgMS4yLiBPYmpldGl2b3MgZXNwZWPDrWZpY29zDQoNCi0gRGVzY3JpYmlyIGxhIGVzdHJ1Y3R1cmEgeSBsYXMgY2FyYWN0ZXLDrXN0aWNhcyBkZSBsYQ0KICBpbmZvcm1hY2nDs24gZGlzcG9uaWJsZSBwYXJhIGxhcyAxMTIgVVBaIGRlIEJvZ290w6EuDQoNCi0gRXhwbG9yYXIgbGEgZGlzdHJpYnVjacOzbiBkZSBsb3MgaW5kaWNhZG9yZXMgZGUgZGVsaXRvcywNCiAgcG9ibGFjacOzbiwgdml2aWVuZGEsIGluZnJhZXN0cnVjdHVyYSB5IGNvbmRpY2lvbmVzDQogIHNvY2lvZWNvbsOzbWljYXMuDQoNCi0gSWRlbnRpZmljYXIgZGlmZXJlbmNpYXMgdGVycml0b3JpYWxlcyBtZWRpYW50ZSBlbCB1c28NCiAgZGUgZXN0YWTDrXN0aWNhcyBkZXNjcmlwdGl2YXMsIGNvbXBhcmFjaW9uZXMgeSBtYXBhcy4NCg0KLSBFeGFtaW5hciBwb3NpYmxlcyByZWxhY2lvbmVzIGVudHJlIGxvcyBpbmRpY2Fkb3JlcyBkZQ0KICBzZWd1cmlkYWQgeSBsYXMgY2FyYWN0ZXLDrXN0aWNhcyBkZSBjYWRhIFVQWi4NCg0KLSBDb211bmljYXIgbG9zIHByaW5jaXBhbGVzIGhhbGxhemdvcyBtZWRpYW50ZQ0KICB2aXN1YWxpemFjaW9uZXMgeSB1bmEgbmFycmF0aXZhIGJhc2FkYSBlbiBsb3MgZGF0b3MuDQoNCg0KIyAyLiBEZXNjcmlwY2nDs24gZGUgbG9zIGRhdG9zDQoNClBhcmEgZGVzYXJyb2xsYXIgZWwgYW7DoWxpc2lzIHNlIHV0aWxpemEgdW5hIGJhc2UgZGUgZGF0b3MNCmNvbnNvbGlkYWRhIHF1ZSBjb250aWVuZSBpbmZvcm1hY2nDs24gZGUgMTEyIFVuaWRhZGVzIGRlDQpQbGFuZWFtaWVudG8gWm9uYWwgZGUgQm9nb3TDoS4gQ2FkYSByZWdpc3RybyByZXByZXNlbnRhIHVuYQ0KVVBaIGUgaW5jbHV5ZSB2YXJpYWJsZXMgcmVsYWNpb25hZGFzIGNvbiBzdSB0ZXJyaXRvcmlvLA0KcG9ibGFjacOzbiwgY29uZGljaW9uZXMgZGUgdml2aWVuZGEsIGluZnJhZXN0cnVjdHVyYSwNCmRlbGl0b3MgZGVudW5jaWFkb3MgeSBjYXJhY3RlcsOtc3RpY2FzIHNvY2lvZWNvbsOzbWljYXMuDQoNCkxhIGluZm9ybWFjacOzbiBzZSBlbmN1ZW50cmEgb3JnYW5pemFkYSBlbiBjaW5jbyBncmFuZGVzDQpibG9xdWVzOg0KDQoxLiAqKlRlcnJpdG9yaW86KiogaWRlbnRpZmljYWNpw7NuIGRlIGxhIFVQWiwgbG9jYWxpZGFkDQogICB5IGV4dGVuc2nDs24gZ2VvZ3LDoWZpY2EuDQoNCjIuICoqRGVtb2dyYWbDrWE6KiogcG9ibGFjacOzbiwgZGVuc2lkYWQgcG9ibGFjaW9uYWwgeQ0KICAgY29tcG9zaWNpw7NuIHBvciBncnVwb3MgZGUgZWRhZC4NCg0KMy4gKipWaXZpZW5kYSBlIGluZnJhZXN0cnVjdHVyYToqKiBjYXJhY3RlcsOtc3RpY2FzIGRlDQogICBsYXMgdml2aWVuZGFzIHkgZGlzcG9uaWJpbGlkYWQgZGUgYWx1bWJyYWRvIHDDumJsaWNvLg0KDQo0LiAqKkRlbGl0b3M6KiogcmVnaXN0cm9zIGRlIGRlbnVuY2lhcyB5IHRhc2FzIHBvciBjYWRhDQogICAxMC4wMDAgaGFiaXRhbnRlcyBwYXJhIGRpZXogY2F0ZWdvcsOtYXMgZGUgZGVsaXRvcy4NCg0KNS4gKipFbmN1ZXN0YSBNdWx0aXByb3DDs3NpdG86KiogaW5mb3JtYWNpw7NuIHJlbGFjaW9uYWRhDQogICBjb24gcG9icmV6YSwgaW5ncmVzb3MsIGVzdHJhdG8sIGVkdWNhY2nDs24sIHBlcmNlcGNpw7NuDQogICBkZSBpbnNlZ3VyaWRhZCB5IGNvbmRpY2lvbmVzIGRlbCBlbnRvcm5vLg0KDQpBZGljaW9uYWxtZW50ZSwgc2UgZGlzcG9uZSBkZSBhcmNoaXZvcyBnZW9ncsOhZmljb3MgcXVlDQpyZXByZXNlbnRhbiBsb3MgbMOtbWl0ZXMgZGUgbGFzIFVQWiB5IGxhcyBsb2NhbGlkYWRlcw0KdXJiYW5hcyBkZSBCb2dvdMOhLiBFc3RvcyBhcmNoaXZvcyBwZXJtaXRpcsOhbiBpbnRlZ3Jhcg0KbGEgaW5mb3JtYWNpw7NuIGVzdGFkw61zdGljYSBjb24gc3UgdWJpY2FjacOzbiB0ZXJyaXRvcmlhbC4NCg0KIyAzLiBDYXJnYSBkZSBsYSBpbmZvcm1hY2nDs24NClZhbW9zIGEgY29uZWN0YXIgbnVlc3RybyBpbmZvcm1lIGNvbiBsb3MgYXJjaGl2b3MuDQoNClNlIGNhcmdhcmFuIHRyZXMgZnVlbnRlczoNCjEuIExhIGJhc2UgZXN0YWTDrXN0aWNhIGRlIGxhcyBVUFouDQoyLiBFbCBtYXBhIGRlIGxhcyBVUFouDQozLiBFbCBtYXBhIGRlIGxhcyBsb2NhbGlkYWRlcy4NCg0KDQpgYGB7ciBpbXBvcnRhY2lvbi1kYXRvc30NCg0KIyAzLjEuIEltcG9ydGFjacOzbiBkZSBsYSBiYXNlIGVzdGFkw61zdGljYQ0KDQp1cHogPC0gcmVhZF9jc3YoDQogICJpbnB1dC91cHpfdmFyaWFibGVzLmNzdiIsDQogIHNob3dfY29sX3R5cGVzID0gRkFMU0UNCikNCg0KIyAzLjIuIEltcG9ydGFjacOzbiBkZSBsb3MgYXJjaGl2b3MgZ2VvZ3LDoWZpY29zDQoNCnVwel9zaHAgPC0gc3RfcmVhZCgNCiAgImlucHV0L3NocC91cHpfYm9nb3RhLnNocCIsDQogIHF1aWV0ID0gVFJVRQ0KKQ0KDQpsb2NhbGlkYWRlc19zaHAgPC0gc3RfcmVhZCgNCiAgImlucHV0L3NocC9sb2NhbGlkYWRlc19ib2dvdGEuc2hwIiwNCiAgcXVpZXQgPSBUUlVFDQopDQoNCmBgYA0KKipOb3RhczoqKiANCg0KLSAqKnJlYWRfY3N2KCkqKiBwZXJtaXRlIGltcG9ydGFyIGxhIGluZm9ybWFjacOzbiBlc3RhZMOtc3RpY2EuDQoNCi0gKipzdF9yZWFkKCkqKiBwZXJtaXRlIGxlZXIgbG9zIGFyY2hpdm9zIGdlb2dyw6FmaWNvcy4NCg0KLSBMb3Mgb2JqZXRvcyB0ZXJtaW5hZG9zIGVuICoqX3NocCoqIGNvbnRpZW5lbiBnZW9tZXRyw61hcyBxdWUgcmVwcmVzZW50YW4gbG9zIGzDrW1pdGVzIHRlcnJpdG9yaWFsZXMuDQoNCg0KIyA0LiBFeHBsb3JhY2nDs24gaW5pY2lhbCBkZSBsb3MgZGF0b3MNCg0KQW50ZXMgZGUgcmVhbGl6YXIgbG9zIGFuw6FsaXNpcyBlc3RhZMOtc3RpY29zIHkgbGFzDQp2aXN1YWxpemFjaW9uZXMsIGVzIG5lY2VzYXJpbyBjb25vY2VyIGxhIGVzdHJ1Y3R1cmENCmRlIGxhIGluZm9ybWFjacOzbiBkaXNwb25pYmxlIHkgdmVyaWZpY2FyIHN1cw0KY2FyYWN0ZXLDrXN0aWNhcyBnZW5lcmFsZXMuDQoNCkVzdGEgcHJpbWVyYSBleHBsb3JhY2nDs24gcGVybWl0ZSBpZGVudGlmaWNhciBsYSBjYW50aWRhZA0KZGUgcmVnaXN0cm9zIHkgdmFyaWFibGVzLCBsb3MgdGlwb3MgZGUgZGF0b3MgdXRpbGl6YWRvcw0KeSBsYXMgY29uZGljaW9uZXMgZ2VuZXJhbGVzIGRlIGxhIGJhc2UuIERlIGVzdGEgbWFuZXJhLA0Kc2UgYnVzY2EgZXN0YWJsZWNlciB1biBwdW50byBkZSBwYXJ0aWRhIHF1ZSBmYWNpbGl0ZQ0KZWwgZGVzYXJyb2xsbyBkZSBsYXMgc2lndWllbnRlcyBldGFwYXMgZGVsIGFuw6FsaXNpcy4NCiANCiMjIDQuMS4gRGltZW5zaW9uZXMgeSBlc3RydWN0dXJhIGRlIGxhIGluZm9ybWFjacOzbg0KDQpMYSBiYXNlIGRlIGRhdG9zIGNvbnRpZW5lIGluZm9ybWFjacOzbiBkZSBkaWZlcmVudGVzDQpjYXJhY3RlcsOtc3RpY2FzIGRlIGxhcyBVUFogZGUgQm9nb3TDoS4gUGFyYSBjb21lbnphciwNCnNlIHJldmlzYSBzdSBkaW1lbnNpw7NuIGdlbmVyYWwsIGlkZW50aWZpY2FuZG8gY3XDoW50b3MNCnJlZ2lzdHJvcyB5IHZhcmlhYmxlcyBlc3TDoW4gZGlzcG9uaWJsZXMuDQoNCkNhZGEgcmVnaXN0cm8gcmVwcmVzZW50YSB1bmEgVVBaLCBtaWVudHJhcyBxdWUgbGFzDQpjb2x1bW5hcyBjb3JyZXNwb25kZW4gYSBsYXMgZGlmZXJlbnRlcyBjYXJhY3RlcsOtc3RpY2FzDQplIGluZGljYWRvcmVzIHJlY29waWxhZG9zIHBhcmEgZWwgYW7DoWxpc2lzLg0KDQoNCmBgYHtyIGRpbWVuc2lvbmVzLWJhc2V9DQoNCiMgQ29uc3VsdGFyIGxhcyBkaW1lbnNpb25lcyBnZW5lcmFsZXMgZGUgbGEgYmFzZQ0KZGltKHVweikNCg0KIyBJZGVudGlmaWNhciBsYSBjYW50aWRhZCBkZSByZWdpc3Ryb3MNCm5yb3codXB6KQ0KDQojIElkZW50aWZpY2FyIGxhIGNhbnRpZGFkIGRlIHZhcmlhYmxlcw0KbmNvbCh1cHopDQoNCiMgQ29uc3VsdGFyIGxvcyBwcmltZXJvcyByZWdpc3Ryb3MNCmhlYWQodXB6KQ0KDQpgYGANCg0KIyMgNC4yLiBUaXBvcyBkZSB2YXJpYWJsZXMgeSBlc3RydWN0dXJhDQoNCkFkZW3DoXMgZGUgY29ub2NlciBlbCB0YW1hw7FvIGRlIGxhIGJhc2UsIGVzIGltcG9ydGFudGUNCmlkZW50aWZpY2FyIGVsIHRpcG8gZGUgaW5mb3JtYWNpw7NuIHF1ZSBjb250aWVuZSBjYWRhDQp2YXJpYWJsZS4NCg0KRXN0YSByZXZpc2nDs24gcGVybWl0ZSBkaWZlcmVuY2lhciBsb3MgY2FtcG9zIHF1ZQ0KcmVwcmVzZW50YW4gY2FudGlkYWRlcywgcG9yY2VudGFqZXMsIHRhc2FzLCBjYXRlZ29yw61hcw0KdGVycml0b3JpYWxlcyB5IG90cmFzIGNhcmFjdGVyw61zdGljYXMuDQoNCkxhIGlkZW50aWZpY2FjacOzbiBkZSBlc3RvcyB0aXBvcyBkZSBkYXRvcyBlcyBpbXBvcnRhbnRlDQpwb3JxdWUgbm8gdG9kYXMgbGFzIHZhcmlhYmxlcyBwdWVkZW4gYW5hbGl6YXJzZSBkZSBsYQ0KbWlzbWEgbWFuZXJhLiBQb3IgZWplbXBsbywgdW5hIHZhcmlhYmxlIGRlIHBvYmxhY2nDs24NCnBlcm1pdGUgcmVhbGl6YXIgY8OhbGN1bG9zIGVzdGFkw61zdGljb3MsIG1pZW50cmFzIHF1ZQ0KdW5hIHZhcmlhYmxlIGNvbW8gZWwgbm9tYnJlIGRlIGxhIGxvY2FsaWRhZCBzZSB1dGlsaXphDQpwcmluY2lwYWxtZW50ZSBwYXJhIGNsYXNpZmljYXIgeSBhZ3J1cGFyIGxhIGluZm9ybWFjacOzbi4NCg0KDQpgYGB7ciBlc3RydWN0dXJhLXZhcmlhYmxlc30NCg0KIyBDb25zdWx0YXIgbGEgZXN0cnVjdHVyYSB5IGxvcyB0aXBvcyBkZSB2YXJpYWJsZXMNCmdsaW1wc2UodXB6KQ0KDQpgYGANCg0KDQojIyA0LjMuIFJldmlzacOzbiBkZSB2YWxvcmVzIGZhbHRhbnRlcw0KDQpMb3MgdmFsb3JlcyBmYWx0YW50ZXMgcmVwcmVzZW50YW4gaW5mb3JtYWNpw7NuIHF1ZSBubw0Kc2UgZW5jdWVudHJhIGRpc3BvbmlibGUgcGFyYSB1bmEgbyB2YXJpYXMgdmFyaWFibGVzLg0KU3UgaWRlbnRpZmljYWNpw7NuIGVzIGltcG9ydGFudGUgcG9ycXVlIHB1ZWRlbiBhZmVjdGFyDQpsb3MgY8OhbGN1bG9zIGVzdGFkw61zdGljb3MsIGxhcyBjb21wYXJhY2lvbmVzIHkgbGFzDQpyZWxhY2lvbmVzIGVudHJlIHZhcmlhYmxlcy4NCg0KRW4gZXN0YSBldGFwYSBzZSByZXZpc2EgbGEgY2FudGlkYWQgZGUgZGF0b3MgZmFsdGFudGVzDQplbiBjYWRhIGNvbHVtbmEsIGNvbiBlbCBwcm9ww7NzaXRvIGRlIGRldGVybWluYXIgc2kNCmV4aXN0ZW4gbGltaXRhY2lvbmVzIGVuIGxhIGluZm9ybWFjacOzbiBkaXNwb25pYmxlLg0KDQoNCmBgYHtyIHJldmlzaW9uLWZhbHRhbnRlc30NCg0KIyBDYWxjdWxhciBsYSBjYW50aWRhZCBkZSB2YWxvcmVzIGZhbHRhbnRlcyBwb3IgdmFyaWFibGUNCg0KZmFsdGFudGVzIDwtIHVweiAlPiUNCiAgc3VtbWFyaXNlKA0KICAgIGFjcm9zcygNCiAgICAgIGV2ZXJ5dGhpbmcoKSwNCiAgICAgIH4gc3VtKGlzLm5hKC4pKQ0KICAgICkNCiAgKSAlPiUNCiAgcGl2b3RfbG9uZ2VyKA0KICAgIGNvbHMgPSBldmVyeXRoaW5nKCksDQogICAgbmFtZXNfdG8gPSAiVmFyaWFibGUiLA0KICAgIHZhbHVlc190byA9ICJDYW50aWRhZF9mYWx0YW50ZXMiDQogICkgJT4lDQogIGZpbHRlcihDYW50aWRhZF9mYWx0YW50ZXMgPiAwKSAlPiUNCiAgYXJyYW5nZShkZXNjKENhbnRpZGFkX2ZhbHRhbnRlcykpDQoNCiMgUHJlc2VudGFyIGxvcyByZXN1bHRhZG9zDQoNCmlmIChucm93KGZhbHRhbnRlcykgPT0gMCkgew0KDQogIGNhdCgiTm8gc2UgZW5jb250cmFyb24gdmFsb3JlcyBmYWx0YW50ZXMgZW4gbGEgYmFzZSBkZSBkYXRvcy4iKQ0KDQp9IGVsc2Ugew0KDQogIGtuaXRyOjprYWJsZSgNCiAgICBmYWx0YW50ZXMsDQogICAgY2FwdGlvbiA9ICJWYXJpYWJsZXMgY29uIHZhbG9yZXMgZmFsdGFudGVzIg0KICApDQoNCn0NCg0KYGBgDQoNCiMjIDQuNC4gSWRlbnRpZmljYWNpw7NuIGRlIHJlZ2lzdHJvcyBkdXBsaWNhZG9zDQoNCkRlYmlkbyBhIHF1ZSBjYWRhIHJlZ2lzdHJvIHJlcHJlc2VudGEgdW5hIFVQWiwgZWwNCmPDs2RpZ28gZGUgaWRlbnRpZmljYWNpw7NuIHRlcnJpdG9yaWFsIGRlYmUgc2VyIMO6bmljbw0KZGVudHJvIGRlIGxhIGJhc2UgZGUgZGF0b3MuDQoNClBvciBlc3RhIHJhesOzbiwgc2UgcmV2aXNhIHNpIGV4aXN0ZW4gY8OzZGlnb3MgcmVwZXRpZG9zDQpxdWUgcHVlZGFuIGdlbmVyYXIgZHVwbGljaWRhZCBkZSBpbmZvcm1hY2nDs24gbyBhZmVjdGFyDQpsYXMgY29tcGFyYWNpb25lcyBwb3N0ZXJpb3Jlcy4NCg0KDQpgYGB7ciByZXZpc2lvbi1kdXBsaWNhZG9zfQ0KDQojIElkZW50aWZpY2FyIGPDs2RpZ29zIFVQWiByZXBldGlkb3MNCg0KZHVwbGljYWRvc191cHogPC0gdXB6ICU+JQ0KICBjb3VudCh1cHpfY29kLCBuYW1lID0gIkZyZWN1ZW5jaWEiKSAlPiUNCiAgZmlsdGVyKEZyZWN1ZW5jaWEgPiAxKQ0KDQojIFByZXNlbnRhciBlbCByZXN1bHRhZG8NCg0KaWYgKG5yb3coZHVwbGljYWRvc191cHopID09IDApIHsNCg0KICBjYXQoIk5vIHNlIGVuY29udHJhcm9uIGPDs2RpZ29zIFVQWiBkdXBsaWNhZG9zLiIpDQoNCn0gZWxzZSB7DQoNCiAga25pdHI6OmthYmxlKA0KICAgIGR1cGxpY2Fkb3NfdXB6LA0KICAgIGNhcHRpb24gPSAiQ8OzZGlnb3MgVVBaIGR1cGxpY2Fkb3MiDQogICkNCg0KfQ0KDQpgYGANCg0KIyMgNC41LiBSZXN1bWVuIGdlbmVyYWwgZGUgbGEgZXhwbG9yYWNpw7NuIGluaWNpYWwNCg0KVW5hIHZleiByZWFsaXphZGFzIGxhcyB2ZXJpZmljYWNpb25lcyBpbmljaWFsZXMsDQpzZSBjb25zb2xpZGEgdW4gcmVzdW1lbiBkZSBsYXMgcHJpbmNpcGFsZXMNCmNhcmFjdGVyw61zdGljYXMgZGUgbGEgYmFzZSBkZSBkYXRvcy4NCg0KRXN0ZSByZXN1bHRhZG8gcGVybWl0ZSBlc3RhYmxlY2VyIGxhcyBjb25kaWNpb25lcw0KZ2VuZXJhbGVzIGRlIGxhIGluZm9ybWFjacOzbiBjb24gbGEgcXVlIHNlIGRlc2Fycm9sbGFyw6ENCmVsIGFuw6FsaXNpcyBleHBsb3JhdG9yaW8uDQoNCg0KYGBge3IgcmVzdW1lbi1leHBsb3JhY2lvbn0NCg0KcmVzdW1lbl9iYXNlIDwtIHRpYmJsZSgNCiAgSW5kaWNhZG9yID0gYygNCiAgICAiQ2FudGlkYWQgZGUgcmVnaXN0cm9zIiwNCiAgICAiQ2FudGlkYWQgZGUgdmFyaWFibGVzIiwNCiAgICAiQ8OzZGlnb3MgVVBaIMO6bmljb3MiLA0KICAgICJWYWxvcmVzIGZhbHRhbnRlcyIsDQogICAgIkPDs2RpZ29zIFVQWiBkdXBsaWNhZG9zIg0KICApLA0KDQogIFJlc3VsdGFkbyA9IGMoDQogICAgbnJvdyh1cHopLA0KICAgIG5jb2wodXB6KSwNCiAgICBuX2Rpc3RpbmN0KHVweiR1cHpfY29kKSwNCiAgICBzdW0oaXMubmEodXB6KSksDQogICAgbnJvdyhkdXBsaWNhZG9zX3VweikNCiAgKQ0KKQ0KDQprbml0cjo6a2FibGUoDQogIHJlc3VtZW5fYmFzZSwNCiAgY29sLm5hbWVzID0gYygiSW5kaWNhZG9yIiwgIlJlc3VsdGFkbyIpLA0KICBjYXB0aW9uID0gIlJlc3VtZW4gZGUgbGEgZXhwbG9yYWNpw7NuIGluaWNpYWwiDQopDQoNCmBgYA0KDQoNCiMjIyBJbnRlcnByZXRhY2nDs24gZGUgbGEgcmV2aXNpw7NuIGluaWNpYWwNCg0KTG9zIHJlc3VsdGFkb3MgbXVlc3RyYW4gcXVlIGxhIGJhc2UgZGUgZGF0b3MgZXN0w6ENCmNvbmZvcm1hZGEgcG9yIDExMiByZWdpc3Ryb3MgeSA2NyB2YXJpYWJsZXMsIGNvbiB1bmENCmNvcnJlc3BvbmRlbmNpYSBkZSB1biByZWdpc3RybyBwb3IgY2FkYSBjw7NkaWdvIFVQWi4NCg0KRW4gbGEgcmV2aXNpw7NuIHJlYWxpemFkYSBubyBzZSBpZGVudGlmaWNhcm9uIHZhbG9yZXMNCmZhbHRhbnRlcyBuaSBjw7NkaWdvcyB0ZXJyaXRvcmlhbGVzIGR1cGxpY2Fkb3MuIEVzdG8NCnJlcHJlc2VudGEgdW5hIGNvbmRpY2nDs24gZmF2b3JhYmxlIHBhcmEgY29udGludWFyIGNvbg0KZWwgYW7DoWxpc2lzIGV4cGxvcmF0b3Jpby4NCg0KU2luIGVtYmFyZ28sIGxhIGF1c2VuY2lhIGRlIHZhbG9yZXMgZmFsdGFudGVzIHkNCmR1cGxpY2Fkb3Mgbm8gZ2FyYW50aXphIHBvciBzw60gc29sYSBsYSBjYWxpZGFkIGRlDQp0b2RhIGxhIGluZm9ybWFjacOzbi4gVG9kYXbDrWEgZXMgbmVjZXNhcmlvIHJldmlzYXINCmxhIGRpc3RyaWJ1Y2nDs24gZGUgbGFzIHZhcmlhYmxlcywgaWRlbnRpZmljYXIgcG9zaWJsZXMNCnZhbG9yZXMgZXh0cmVtb3MgeSBldmFsdWFyIGxhIGNvaGVyZW5jaWEgZGUgbG9zDQppbmRpY2Fkb3JlcyBjYWxjdWxhZG9zLg0KDQpQb3IgbG8gdGFudG8sIGVzdGEgcHJpbWVyYSByZXZpc2nDs24gY29uc3RpdHV5ZSB1bg0KcHVudG8gZGUgcGFydGlkYSBwYXJhIHByb2Z1bmRpemFyIGVuIGVsIGNvbXBvcnRhbWllbnRvDQplc3RhZMOtc3RpY28gZGUgbGFzIHZhcmlhYmxlcy4NCg0KDQojIDUuIEFuw6FsaXNpcyBleHBsb3JhdG9yaW8gZGUgbGFzIHZhcmlhYmxlcw0KDQpVbmEgdmV6IHJldmlzYWRhIGxhIGVzdHJ1Y3R1cmEgZ2VuZXJhbCBkZSBsYSBpbmZvcm1hY2nDs24sDQpzZSBpbmljaWEgZWwgYW7DoWxpc2lzIGV4cGxvcmF0b3JpbyBkZSBsYXMgdmFyaWFibGVzIGNvbg0KZWwgcHJvcMOzc2l0byBkZSBjb21wcmVuZGVyIHN1IGNvbXBvcnRhbWllbnRvLCBpZGVudGlmaWNhcg0KZGlmZXJlbmNpYXMgZW50cmUgbG9zIHRlcnJpdG9yaW9zIHkgcmVjb25vY2VyIHBvc2libGVzDQpwYXRyb25lcyBxdWUgcHVlZGFuIG9yaWVudGFyIGxhIGludmVzdGlnYWNpw7NuLg0KDQpFbiBlc3RhIGV0YXBhIHNlIHV0aWxpemFyw6FuIGVzdGFkw61zdGljYXMgZGVzY3JpcHRpdmFzDQp5IHJlcHJlc2VudGFjaW9uZXMgZ3LDoWZpY2FzIHBhcmEgZXhhbWluYXIgbGFzIHByaW5jaXBhbGVzDQpjYXJhY3RlcsOtc3RpY2FzIGRlIGxhcyBVUFogZGUgQm9nb3TDoS4NCg0KIyMgNS4xLiBBbsOhbGlzaXMgZGVtb2dyw6FmaWNvOiBwb2JsYWNpw7NuIHkgZGlzdHJpYnVjacOzbiB0ZXJyaXRvcmlhbA0KDQpMYSBwb2JsYWNpw7NuIGNvbnN0aXR1eWUgdW5hIGRlIGxhcyB2YXJpYWJsZXMgZnVuZGFtZW50YWxlcw0KcGFyYSBjb21wcmVuZGVyIGxhcyBkaWZlcmVuY2lhcyBlbnRyZSBsYXMgVVBaLCB5YSBxdWUNCnBlcm1pdGUgZGltZW5zaW9uYXIgZWwgdGFtYcOxbyBkZSBjYWRhIHRlcnJpdG9yaW8gZW4NCnTDqXJtaW5vcyBkZSBoYWJpdGFudGVzLg0KDQpTdSBhbsOhbGlzaXMgZXMgZXNwZWNpYWxtZW50ZSBpbXBvcnRhbnRlIHBhcmEgZXN0ZSB0cmFiYWpvLA0KcG9ycXVlIGxvcyBpbmRpY2Fkb3JlcyBkZSBkZWxpdG9zIHNlIGV4cHJlc2FuIHRhbnRvIGVuDQpjYW50aWRhZGVzIGFic29sdXRhcyBjb21vIGVuIHRhc2FzIHBvciBjYWRhIDEwLjAwMA0KaGFiaXRhbnRlcy4gUG9yIGxvIHRhbnRvLCBjb25vY2VyIGPDs21vIHNlIGRpc3RyaWJ1eWUgbGENCnBvYmxhY2nDs24gcGVybWl0aXLDoSBpbnRlcnByZXRhciBwb3N0ZXJpb3JtZW50ZSBsYXMNCmRpZmVyZW5jaWFzIGVuIGxvcyBpbmRpY2Fkb3JlcyBkZSBzZWd1cmlkYWQuDQoNCiMjIyA1LjEuMS4gRGlzdHJpYnVjacOzbiBkZSBsYSBwb2JsYWNpw7NuIHBvciBVUFoNCg0KSW5pY2lhbG1lbnRlIHNlIGFuYWxpemEgbGEgY2FudGlkYWQgZGUgaGFiaXRhbnRlcw0KcmVnaXN0cmFkb3MgZW4gY2FkYSBVUFosIGNvbiBlbCBwcm9ww7NzaXRvIGRlIGlkZW50aWZpY2FyDQpsYXMgZGlmZXJlbmNpYXMgZXhpc3RlbnRlcyBlbnRyZSBsb3MgdGVycml0b3Jpb3MgeQ0KcmVjb25vY2VyIGN1w6FsZXMgY29uY2VudHJhbiB1bmEgbWF5b3IgbyBtZW5vciBwb2JsYWNpw7NuLg0KDQojIyMjIGEuIEVzdGFkw61zdGljYXMgZGVzY3JpcHRpdmFzIGRlIHBvYmxhY2nDs24NClByaW1lcm8gdmFtb3MgYSBjYWxjdWxhciBsYXMgcHJpbmNpcGFsZXMgbWVkaWRhcyBlc3RhZMOtc3RpY2FzLg0KYGBge3IgZXN0YWRpc3RpY2FzLXBvYmxhY2lvbn0NCg0KIyBDYWxjdWxhciBsYXMgcHJpbmNpcGFsZXMgbWVkaWRhcyBkZXNjcmlwdGl2YXMNCiMgZGUgbGEgcG9ibGFjacOzbiBkZSBsYXMgVVBaDQoNCmVzdGFkaXN0aWNhc19wb2JsYWNpb24gPC0gdXB6ICU+JQ0KICBzdW1tYXJpc2UoDQogICAgVG90YWxfVVBaID0gbigpLA0KICAgIFBvYmxhY2lvbl90b3RhbCA9IHN1bShwb2JsYWNpb24pLA0KICAgIE1lZGlhID0gbWVhbihwb2JsYWNpb24pLA0KICAgIE1lZGlhbmEgPSBtZWRpYW4ocG9ibGFjaW9uKSwNCiAgICBEZXN2aWFjaW9uX2VzdGFuZGFyID0gc2QocG9ibGFjaW9uKSwNCiAgICBNaW5pbW8gPSBtaW4ocG9ibGFjaW9uKSwNCiAgICBRMSA9IHF1YW50aWxlKHBvYmxhY2lvbiwgMC4yNSksDQogICAgUTMgPSBxdWFudGlsZShwb2JsYWNpb24sIDAuNzUpLA0KICAgIE1heGltbyA9IG1heChwb2JsYWNpb24pDQogICkNCg0KDQojIFByZXNlbnRhciByZXN1bHRhZG9zDQoNCmVzdGFkaXN0aWNhc19wb2JsYWNpb24gJT4lDQogIHRpZHlyOjpwaXZvdF9sb25nZXIoDQogICAgY29scyA9IGV2ZXJ5dGhpbmcoKSwNCiAgICBuYW1lc190byA9ICJFc3RhZMOtc3RpY2EiLA0KICAgIHZhbHVlc190byA9ICJWYWxvciINCiAgKSAlPiUNCiAga25pdHI6OmthYmxlKA0KICAgIGNvbC5uYW1lcyA9IGMoIkVzdGFkw61zdGljYSIsICJSZXN1bHRhZG8iKSwNCiAgICBjYXB0aW9uID0gIkVzdGFkw61zdGljYXMgZGVzY3JpcHRpdmFzIGRlIHBvYmxhY2nDs24gcG9yIFVQWiINCiAgKQ0KDQpgYGANCiMjIyMgwr9RdcOpIGVzdGFtb3MgY2FsY3VsYW5kbz8NCg0KfCAqKk1lZGlkYSoqIHwgKipRdcOpIG5vcyBwZXJtaXRlIGNvbm9jZXIqKiB8DQp8Oi0tLXw6LS0tfA0KfCBNZWRpYSB8IFBvYmxhY2nDs24gcHJvbWVkaW8gcG9yIFVQWi4gfA0KfCBNZWRpYW5hIHwgVmFsb3IgcXVlIGRpdmlkZSBsYXMgVVBaIGVuIGRvcyBncnVwb3MgaWd1YWxlcy4gfA0KfCBEZXN2aWFjacOzbiBlc3TDoW5kYXIgfCBRdcOpIHRhbiBkaXNwZXJzYSBlc3TDoSBsYSBwb2JsYWNpw7NuIHJlc3BlY3RvIGEgbGEgbWVkaWEuIHwNCnwgTcOtbmltbyB5IG3DoXhpbW8gfCBMb3MgZXh0cmVtb3MgZGUgcG9ibGFjacOzbi4gfA0KfCBRMSB8IEVsIDI1ICUgZGUgbGFzIFVQWiB0aWVuZSB1bmEgcG9ibGFjacOzbiBpZ3VhbCBvIGluZmVyaW9yIGEgZXN0ZSB2YWxvci4gfA0KfCBRMyB8IEVsIDc1ICUgZGUgbGFzIFVQWiB0aWVuZSB1bmEgcG9ibGFjacOzbiBpZ3VhbCBvIGluZmVyaW9yIGEgZXN0ZSB2YWxvci4gfA0KDQpVbmEgY29tcGFyYWNpw7NuIGVzcGVjaWFsbWVudGUgaW1wb3J0YW50ZSBzZXLDoSBsYSBtZWRpYSBmcmVudGUgYSBsYSBtZWRpYW5hLiBTaSBsYSBwcmltZXJhIGVzIGNvbnNpZGVyYWJsZW1lbnRlIG1heW9yLCBwdWVkZSBpbmRpY2FyIHF1ZSBhbGd1bmFzIFVQWiBjb24gcG9ibGFjaW9uZXMgbXV5IGVsZXZhZGFzIGVzdMOhbiBpbmZsdXllbmRvIGVuIGVsIHByb21lZGlvLg0KDQojIyMjIGIuIERpc3RyaWJ1Y2nDs24gZ3LDoWZpY2EgZGUgbGEgcG9ibGFjacOzbg0KDQpBaG9yYSB2YW1vcyBhIHZpc3VhbGl6YXIgY8OzbW8gc2UgZGlzdHJpYnV5ZSBsYSBwb2JsYWNpw7NuIGVudHJlIGxhcyAxMTIgVVBaDQoNCmBgYHtyIGdyYWZpY28tZGlzdHJpYnVjaW9uLXBvYmxhY2lvbn0NCg0KIyBIaXN0b2dyYW1hIGRlIGxhIHBvYmxhY2nDs24gcG9yIFVQWg0KDQpnZ3Bsb3QodXB6LCBhZXMoeCA9IHBvYmxhY2lvbikpICsNCg0KICBnZW9tX2hpc3RvZ3JhbSgNCiAgICBiaW5zID0gMjAsDQogICAgZmlsbCA9IG1hZ2VudGEsDQogICAgY29sb3IgPSAid2hpdGUiLA0KICAgIGFscGhhID0gMC44NQ0KICApICsNCg0KICBsYWJzKA0KICAgIHRpdGxlID0gIkRpc3RyaWJ1Y2nDs24gZGUgbGEgcG9ibGFjacOzbiBwb3IgVVBaIiwNCiAgICBzdWJ0aXRsZSA9ICJQb2JsYWNpw7NuIHByb3llY3RhZGEgcGFyYSBlbCBhw7FvIDIwMjMiLA0KICAgIHggPSAiQ2FudGlkYWQgZGUgaGFiaXRhbnRlcyIsDQogICAgeSA9ICJOw7ptZXJvIGRlIFVQWiIsDQogICAgY2FwdGlvbiA9ICJGdWVudGU6IEJhc2UgZGUgZGF0b3MgZGVsIHRhbGxlci4iDQogICkgKw0KDQogIHNjYWxlX3hfY29udGludW91cygNCiAgICBsYWJlbHMgPSBzY2FsZXM6OmxhYmVsX251bWJlcigNCiAgICAgIGJpZy5tYXJrID0gIi4iLA0KICAgICAgZGVjaW1hbC5tYXJrID0gIiwiDQogICAgKQ0KICApICsNCg0KICB0ZW1hX2NsYXNlDQoNCmBgYA0KDQojIyMgwr9RdcOpIGJ1c2NhbW9zIGlkZW50aWZpY2FyPw0KDQpFbCBoaXN0b2dyYW1hIG5vcyBwZXJtaXRlIG9ic2VydmFyIGTDs25kZSBzZSBjb25jZW50cmEgbGEgbWF5b3IgY2FudGlkYWQgZGUgVVBaIHNlZ8O6biBzdSBwb2JsYWNpw7NuLg0KDQpUYW1iacOpbiBub3MgYXl1ZGEgYSBpZGVudGlmaWNhciBzaSBsYSBkaXN0cmlidWNpw7NuIGVzIHNpbcOpdHJpY2EgbyBzaSBwcmVzZW50YSB1bmEgY29uY2VudHJhY2nDs24gZGUgdGVycml0b3Jpb3MgY29uIHBvYmxhY2lvbmVzIHBlcXVlw7FhcyB5IHVub3MgcG9jb3MgdGVycml0b3Jpb3MgY29uIHBvYmxhY2lvbmVzIGNvbnNpZGVyYWJsZW1lbnRlIG1heW9yZXMuDQoNCk5vIGRlYmVtb3MgYXN1bWlyIHF1ZSBsYSBwb2JsYWNpw7NuIHNlIGRpc3RyaWJ1eWUgZGUgbWFuZXJhIHVuaWZvcm1lIGVudHJlIGxhcyBVUFouDQoNCiMjIyMgYy4gSWRlbnRpZmljYWNpw7NuIGRlIGxhcyBVUFogY29uIG1heW9yIHkgbWVub3IgcG9ibGFjacOzbg0KDQpZIGNvbW8gZWwgaGlzdG9ncmFtYSBub3MgbXVlc3RyYSBlbCBjb21wb3J0YW1pZW50byBnZW5lcmFsLCBwZXJvIGFob3JhIG5lY2VzaXRhbW9zIGlkZW50aWZpY2FyIGxvcyB0ZXJyaXRvcmlvcyBxdWUgc2UgZW5jdWVudHJhbiBlbiBsb3MgZXh0cmVtb3MuDQoNClZhbW9zIGEgY29uc3RydWlyIGRvcyByYW5raW5nczogbGFzIDEwIFVQWiBtw6FzIHBvYmxhZGFzIHkgbGFzIDEwIG1lbm9zIHBvYmxhZGFzLg0KDQpgYGB7ciByYW5raW5nLXBvYmxhY2lvbn0NCg0KIyAxMCBVUFogY29uIG1heW9yIHBvYmxhY2nDs24NCg0KdXB6X21heW9yX3BvYmxhY2lvbiA8LSB1cHogJT4lDQogIGFycmFuZ2UoZGVzYyhwb2JsYWNpb24pKSAlPiUNCiAgc2VsZWN0KA0KICAgIHVwel9ub21icmUsDQogICAgbG9jYWxpZGFkLA0KICAgIHBvYmxhY2lvbg0KICApICU+JQ0KICBzbGljZV9oZWFkKG4gPSAxMCkNCg0KIyAxMCBVUFogY29uIG1lbm9yIHBvYmxhY2nDs24NCg0KdXB6X21lbm9yX3BvYmxhY2lvbiA8LSB1cHogJT4lDQogIGFycmFuZ2UocG9ibGFjaW9uKSAlPiUNCiAgc2VsZWN0KA0KICAgIHVwel9ub21icmUsDQogICAgbG9jYWxpZGFkLA0KICAgIHBvYmxhY2lvbg0KICApICU+JQ0KICBzbGljZV9oZWFkKG4gPSAxMCkNCg0KIyBQcmVzZW50YXIgbGFzIFVQWiBtw6FzIHBvYmxhZGFzDQoNCmtuaXRyOjprYWJsZSgNCiAgdXB6X21heW9yX3BvYmxhY2lvbiwNCiAgY29sLm5hbWVzID0gYygiVVBaIiwgIkxvY2FsaWRhZCIsICJIYWJpdGFudGVzIiksDQogIGNhcHRpb24gPSAiTGFzIDEwIFVQWiBjb24gbWF5b3IgcG9ibGFjacOzbiIsDQogIGRpZ2l0cyA9IDANCikNCg0KIyBQcmVzZW50YXIgbGFzIFVQWiBtZW5vcyBwb2JsYWRhcw0KDQprbml0cjo6a2FibGUoDQogIHVwel9tZW5vcl9wb2JsYWNpb24sDQogIGNvbC5uYW1lcyA9IGMoIlVQWiIsICJMb2NhbGlkYWQiLCAiSGFiaXRhbnRlcyIpLA0KICBjYXB0aW9uID0gIkxhcyAxMCBVUFogY29uIG1lbm9yIHBvYmxhY2nDs24iLA0KICBkaWdpdHMgPSAwDQopDQoNCmBgYA0KDQojIyMjIGQuIFZpc3VhbGl6YWNpw7NuIC0gR3JhZmljbw0KDQpBaG9yYSB2YW1vcyBhIHJlcHJlc2VudGFyIHZpc3VhbG1lbnRlIGVzdG9zIHJlc3VsdGFkb3MuDQpgYGB7ciBncmFmaWNvLXJhbmtpbmctcG9ibGFjaW9ufQ0KDQojIFByZXBhcmFyIGxvcyBkYXRvcyBkZSBsYXMgMTAgVVBaIG3DoXMgcG9ibGFkYXMNCg0KZ2dwbG90KA0KICB1cHpfbWF5b3JfcG9ibGFjaW9uLA0KICBhZXMoDQogICAgeCA9IHJlb3JkZXIodXB6X25vbWJyZSwgcG9ibGFjaW9uKSwNCiAgICB5ID0gcG9ibGFjaW9uDQogICkNCikgKw0KDQogIGdlb21fY29sKA0KICAgIGZpbGwgPSBtb3JhZG8sDQogICAgd2lkdGggPSAwLjcNCiAgKSArDQoNCiAgY29vcmRfZmxpcCgpICsNCg0KICBsYWJzKA0KICAgIHRpdGxlID0gIkxhcyBVUFogY29uIG1heW9yIGNvbmNlbnRyYWNpw7NuIGRlIHBvYmxhY2nDs24iLA0KICAgIHN1YnRpdGxlID0gIlJhbmtpbmcgZGUgbGFzIDEwIFVQWiBtw6FzIHBvYmxhZGFzIGRlIEJvZ290w6EiLA0KICAgIHggPSBOVUxMLA0KICAgIHkgPSAiQ2FudGlkYWQgZGUgaGFiaXRhbnRlcyIsDQogICAgY2FwdGlvbiA9ICJGdWVudGU6IEJhc2UgZGUgZGF0b3MgZGVsIHRhbGxlci4iDQogICkgKw0KDQogIHNjYWxlX3lfY29udGludW91cygNCiAgICBsYWJlbHMgPSBzY2FsZXM6OmxhYmVsX251bWJlcigNCiAgICAgIGJpZy5tYXJrID0gIi4iLA0KICAgICAgZGVjaW1hbC5tYXJrID0gIiwiDQogICAgKQ0KICApICsNCg0KICB0ZW1hX2NsYXNlDQoNCmBgYA0KDQoNCiMjIyA1LjEuMi4gQW7DoWxpc2lzIGRlIGxhIGRlbnNpZGFkIHBvYmxhY2lvbmFsDQoNCkxhIGNhbnRpZGFkIGRlIGhhYml0YW50ZXMgbm8gZXMgZWwgw7puaWNvIGVsZW1lbnRvDQpxdWUgcGVybWl0ZSBjYXJhY3Rlcml6YXIgdW4gdGVycml0b3Jpby4gVGFtYmnDqW4gZXMNCmltcG9ydGFudGUgY29uc2lkZXJhciBzdSBleHRlbnNpw7NuIGdlb2dyw6FmaWNhIHBhcmENCmNvbXByZW5kZXIgcXXDqSB0YW4gY29uY2VudHJhZGEgc2UgZW5jdWVudHJhIGxhIHBvYmxhY2nDs24uDQoNClBhcmEgZWxsbyBzZSB1dGlsaXphIGxhIGRlbnNpZGFkIHBvYmxhY2lvbmFsLCBtZWRpZGENCmVuIGhhYml0YW50ZXMgcG9yIGtpbMOzbWV0cm8gY3VhZHJhZG8gKGhhYi9rbcKyKS4NCkVzdGUgaW5kaWNhZG9yIHJlbGFjaW9uYSBsYSBwb2JsYWNpw7NuIGRlIGNhZGEgVVBaDQpjb24gZWwgw6FyZWEgcXVlIG9jdXBhLg0KDQpTdSBhbsOhbGlzaXMgcGVybWl0ZSBkaWZlcmVuY2lhciB0ZXJyaXRvcmlvcyBjb24NCmdyYW5kZXMgcG9ibGFjaW9uZXMgeSBleHRlbnNpb25lcyBhbXBsaWFzIGRlIGFxdWVsbG9zDQpxdWUgcHJlc2VudGFuIHVuYSBtYXlvciBjb25jZW50cmFjacOzbiBkZSBoYWJpdGFudGVzDQplbiBzdXBlcmZpY2llcyBtw6FzIHJlZHVjaWRhcy4NCg0KIyMjIyBhLiBFc3RhZMOtc3RpY2FzIGRlc2NyaXB0aXZhcyBkZSBkZW5zaWRhZA0KDQpgYGB7ciBlc3RhZGlzdGljYXMtZGVuc2lkYWR9DQoNCiMgRXN0YWTDrXN0aWNhcyBkZXNjcmlwdGl2YXMgZGUgZGVuc2lkYWQgcG9ibGFjaW9uYWwNCg0KZXN0YWRpc3RpY2FzX2RlbnNpZGFkIDwtIHVweiAlPiUNCiAgc3VtbWFyaXNlKA0KICAgIE1lZGlhID0gbWVhbihkZW5zaWRhZF9oYWJfa20yKSwNCiAgICBNZWRpYW5hID0gbWVkaWFuKGRlbnNpZGFkX2hhYl9rbTIpLA0KICAgIERlc3ZpYWNpb25fZXN0YW5kYXIgPSBzZChkZW5zaWRhZF9oYWJfa20yKSwNCiAgICBNaW5pbW8gPSBtaW4oZGVuc2lkYWRfaGFiX2ttMiksDQogICAgUTEgPSBxdWFudGlsZShkZW5zaWRhZF9oYWJfa20yLCAwLjI1KSwNCiAgICBRMyA9IHF1YW50aWxlKGRlbnNpZGFkX2hhYl9rbTIsIDAuNzUpLA0KICAgIE1heGltbyA9IG1heChkZW5zaWRhZF9oYWJfa20yKQ0KICApDQoNCmtuaXRyOjprYWJsZSgNCiAgZXN0YWRpc3RpY2FzX2RlbnNpZGFkLA0KICBkaWdpdHMgPSAyLA0KICBjYXB0aW9uID0gIkVzdGFkw61zdGljYXMgZGVzY3JpcHRpdmFzIGRlIGxhIGRlbnNpZGFkIHBvYmxhY2lvbmFsIg0KKQ0KDQpgYGANCg0KIyMjIyBiLiBVUFogY29uIG1heW9yIHkgbWVub3IgZGVuc2lkYWQNCg0KDQpgYGB7ciByYW5raW5nLWRlbnNpZGFkfQ0KDQojIElkZW50aWZpY2FyIGxhcyBVUFogY29uIG1heW9yIGRlbnNpZGFkIHBvYmxhY2lvbmFsDQoNCnJhbmtpbmdfZGVuc2lkYWQgPC0gdXB6ICU+JQ0KICBhcnJhbmdlKGRlc2MoZGVuc2lkYWRfaGFiX2ttMikpICU+JQ0KICBzZWxlY3QoDQogICAgdXB6X25vbWJyZSwNCiAgICBsb2NhbGlkYWQsDQogICAgcG9ibGFjaW9uLA0KICAgIGFyZWFfa20yLA0KICAgIGRlbnNpZGFkX2hhYl9rbTINCiAgKQ0KDQojIFByZXNlbnRhciBsYXMgMTAgVVBaIGNvbiBtYXlvciBkZW5zaWRhZA0KDQprbml0cjo6a2FibGUoDQogIHJhbmtpbmdfZGVuc2lkYWQgJT4lIHNsaWNlX2hlYWQobiA9IDEwKSwNCiAgY29sLm5hbWVzID0gYygNCiAgICAiVVBaIiwNCiAgICAiTG9jYWxpZGFkIiwNCiAgICAiSGFiaXRhbnRlcyIsDQogICAgIsOBcmVhIChrbcKyKSIsDQogICAgIkRlbnNpZGFkIChoYWIva23CsikiDQogICksDQogIGRpZ2l0cyA9IDIsDQogIGNhcHRpb24gPSAiTGFzIDEwIFVQWiBjb24gbWF5b3IgZGVuc2lkYWQgcG9ibGFjaW9uYWwiDQopDQoNCiMgUHJlc2VudGFyIGxhcyAxMCBVUFogY29uIG1lbm9yIGRlbnNpZGFkDQoNCmtuaXRyOjprYWJsZSgNCiAgcmFua2luZ19kZW5zaWRhZCAlPiUgYXJyYW5nZShkZW5zaWRhZF9oYWJfa20yKSAlPiUgc2xpY2VfaGVhZChuID0gMTApLA0KICBjb2wubmFtZXMgPSBjKA0KICAgICJVUFoiLA0KICAgICJMb2NhbGlkYWQiLA0KICAgICJIYWJpdGFudGVzIiwNCiAgICAiw4FyZWEgKGttwrIpIiwNCiAgICAiRGVuc2lkYWQgKGhhYi9rbcKyKSINCiAgKSwNCiAgZGlnaXRzID0gMiwNCiAgY2FwdGlvbiA9ICJMYXMgMTAgVVBaIGNvbiBtZW5vciBkZW5zaWRhZCBwb2JsYWNpb25hbCINCikNCg0KYGBgDQoNCiMjIyMgYy4gQ29tcGFyYWNpw7NuIGdyw6FmaWNhIGRlIGRlbnNpZGFkDQoNCmBgYHtyIGdyYWZpY28tZGVuc2lkYWR9DQoNCiMgVmlzdWFsaXphciBsYXMgMTAgVVBaIGNvbiBtYXlvciBkZW5zaWRhZCBwb2JsYWNpb25hbA0KDQpnZ3Bsb3QoDQogIHJhbmtpbmdfZGVuc2lkYWQgJT4lIHNsaWNlX2hlYWQobiA9IDEwKSwNCiAgYWVzKA0KICAgIHggPSByZW9yZGVyKHVwel9ub21icmUsIGRlbnNpZGFkX2hhYl9rbTIpLA0KICAgIHkgPSBkZW5zaWRhZF9oYWJfa20yDQogICkNCikgKw0KDQogIGdlb21fY29sKA0KICAgIGZpbGwgPSB0dXJxdWVzYSwNCiAgICB3aWR0aCA9IDAuNw0KICApICsNCg0KICBjb29yZF9mbGlwKCkgKw0KDQogIGxhYnMoDQogICAgdGl0bGUgPSAiQ29uY2VudHJhY2nDs24gZGUgcG9ibGFjacOzbiBlbiBsYXMgVVBaIiwNCiAgICBzdWJ0aXRsZSA9ICJUZXJyaXRvcmlvcyBjb24gbWF5b3IgZGVuc2lkYWQgcG9ibGFjaW9uYWwiLA0KICAgIHggPSBOVUxMLA0KICAgIHkgPSAiSGFiaXRhbnRlcyBwb3Iga23CsiIsDQogICAgY2FwdGlvbiA9ICJGdWVudGU6IEJhc2UgZGUgZGF0b3MgZGVsIHRhbGxlci4iDQogICkgKw0KDQogIHNjYWxlX3lfY29udGludW91cygNCiAgICBsYWJlbHMgPSBzY2FsZXM6OmxhYmVsX251bWJlcigNCiAgICAgIGJpZy5tYXJrID0gIi4iLA0KICAgICAgZGVjaW1hbC5tYXJrID0gIiwiDQogICAgKQ0KICApICsNCg0KICB0ZW1hX2NsYXNlDQoNCmBgYA0KDQoNCiMjIyA1LjEuMy4gUmVsYWNpw7NuIGVudHJlIHBvYmxhY2nDs24geSBleHRlbnNpw7NuIHRlcnJpdG9yaWFsDQoNClBhcmEgY29tcGxlbWVudGFyIGVsIGFuw6FsaXNpcyBhbnRlcmlvciwgc2UgZXhhbWluYQ0KbGEgcmVsYWNpw7NuIGVudHJlIGxhIHBvYmxhY2nDs24geSBlbCDDoXJlYSBnZW9ncsOhZmljYQ0KZGUgY2FkYSBVUFouDQoNCkVzdGEgY29tcGFyYWNpw7NuIHBlcm1pdGUgb2JzZXJ2YXIgc2kgbG9zIHRlcnJpdG9yaW9zDQpjb24gbWF5b3IgZXh0ZW5zacOzbiB0YW1iacOpbiBjb25jZW50cmFuIHVuYSBtYXlvcg0KY2FudGlkYWQgZGUgaGFiaXRhbnRlcyBvIHNpIGV4aXN0ZW4gZGlmZXJlbmNpYXMNCmltcG9ydGFudGVzIGVuIGxhIG9jdXBhY2nDs24gZGVsIGVzcGFjaW8uDQoNCkxhIHZpc3VhbGl6YWNpw7NuIHNlIHJlYWxpemEgbWVkaWFudGUgdW4gZGlhZ3JhbWENCmRlIGRpc3BlcnNpw7NuLCBlbiBlbCBxdWUgY2FkYSBwdW50byByZXByZXNlbnRhIHVuYSBVUFouDQoNCg0KYGBge3IgcmVsYWNpb24tcG9ibGFjaW9uLWFyZWF9DQoNCiMgUmVsYWNpw7NuIGVudHJlIHBvYmxhY2nDs24geSDDoXJlYSB0ZXJyaXRvcmlhbA0KDQpnZ3Bsb3QoDQogIHVweiwNCiAgYWVzKA0KICAgIHggPSBhcmVhX2ttMiwNCiAgICB5ID0gcG9ibGFjaW9uDQogICkNCikgKw0KDQogIGdlb21fcG9pbnQoDQogICAgY29sb3IgPSBtYWdlbnRhLA0KICAgIHNpemUgPSAyLjgsDQogICAgYWxwaGEgPSAwLjc1DQogICkgKw0KDQogIGdlb21fc21vb3RoKA0KICAgIG1ldGhvZCA9ICJsbSIsDQogICAgc2UgPSBGQUxTRSwNCiAgICBjb2xvciA9IG1vcmFkbywNCiAgICBsaW5ld2lkdGggPSAwLjkNCiAgKSArDQoNCiAgbGFicygNCiAgICB0aXRsZSA9ICJSZWxhY2nDs24gZW50cmUgcG9ibGFjacOzbiB5IMOhcmVhIGRlIGxhcyBVUFoiLA0KICAgIHN1YnRpdGxlID0gIkNhZGEgcHVudG8gcmVwcmVzZW50YSB1bmEgdW5pZGFkIHRlcnJpdG9yaWFsIiwNCiAgICB4ID0gIsOBcmVhIGRlIGxhIFVQWiAoa23CsikiLA0KICAgIHkgPSAiQ2FudGlkYWQgZGUgaGFiaXRhbnRlcyIsDQogICAgY2FwdGlvbiA9ICJGdWVudGU6IEJhc2UgZGUgZGF0b3MgZGVsIHRhbGxlci4iDQogICkgKw0KDQogIHNjYWxlX3lfY29udGludW91cygNCiAgICBsYWJlbHMgPSBzY2FsZXM6OmxhYmVsX251bWJlcigNCiAgICAgIGJpZy5tYXJrID0gIi4iLA0KICAgICAgZGVjaW1hbC5tYXJrID0gIiwiDQogICAgKQ0KICApICsNCg0KICB0ZW1hX2NsYXNlDQoNCmBgYA0KDQojIyMjIMK/UXXDqSBkZWJlbW9zIG9ic2VydmFyPw0KDQotIFNpIGV4aXN0ZSB1bmEgdGVuZGVuY2lhIHBvc2l0aXZhIGVudHJlIGVsIMOhcmVhIHkgbGEgcG9ibGFjacOzbi4NCg0KLSBTaSBsYXMgVVBaIGRlIG1heW9yIGV4dGVuc2nDs24gY29uY2VudHJhbiBuZWNlc2FyaWFtZW50ZSBtw6FzIGhhYml0YW50ZXMuDQoNCi0gU2kgZXhpc3RlbiB0ZXJyaXRvcmlvcyBxdWUgc2UgYXBhcnRhbiBkZWwgY29tcG9ydGFtaWVudG8gZ2VuZXJhbC4NCg0KTGEgbMOtbmVhIHJlcHJlc2VudGEgdW5hIHRlbmRlbmNpYSBsaW5lYWwgZGUgcmVmZXJlbmNpYS4gTm8gc2lnbmlmaWNhIHF1ZSBlbCDDoXJlYSB0ZXJyaXRvcmlhbCBleHBsaXF1ZSBwb3Igc8OtIHNvbGEgbGEgY2FudGlkYWQgZGUgaGFiaXRhbnRlcy4NCg0KDQojIyMgNS4xLjQuIElkZW50aWZpY2FjacOzbiBkZSB2YWxvcmVzIGV4dHJlbW9zIGVuIGxhIHBvYmxhY2nDs24NCg0KRHVyYW50ZSBlbCBhbsOhbGlzaXMgZGUgbGEgcG9ibGFjacOzbiBlcyBpbXBvcnRhbnRlDQppZGVudGlmaWNhciB0ZXJyaXRvcmlvcyBxdWUgcHJlc2VudGVuIHZhbG9yZXMNCmNvbnNpZGVyYWJsZW1lbnRlIGRpZmVyZW50ZXMgYWwgY29tcG9ydGFtaWVudG8NCmdlbmVyYWwgZGUgbGFzIFVQWi4NCg0KUGFyYSBlbGxvIHNlIHV0aWxpemEgZWwgcmFuZ28gaW50ZXJjdWFydMOtbGljbyAoSVFSKSwNCnF1ZSBjb3JyZXNwb25kZSBhIGxhIGRpZmVyZW5jaWEgZW50cmUgZWwgdGVyY2VyDQp5IGVsIHByaW1lciBjdWFydGlsIGRlIGxhIGRpc3RyaWJ1Y2nDs24uDQoNCk1lZGlhbnRlIGVzdGUgcHJvY2VkaW1pZW50byBzZSBpZGVudGlmaWNhbiBwb3NpYmxlcw0KdmFsb3JlcyBhdMOtcGljb3MsIGVudGVuZGlkb3MgY29tbyBvYnNlcnZhY2lvbmVzIHF1ZQ0Kc2UgZW5jdWVudHJhbiBwb3IgZnVlcmEgZGUgbG9zIGzDrW1pdGVzIGVzdGFkw61zdGljb3MNCmVzdGFibGVjaWRvcy4NCg0KTGEgaWRlbnRpZmljYWNpw7NuIGRlIGVzdG9zIHZhbG9yZXMgbm8gc2lnbmlmaWNhDQpxdWUgZGViYW4gZWxpbWluYXJzZSBkZSBsYSBpbmZvcm1hY2nDs24uIFBvciBlbA0KY29udHJhcmlvLCBwZXJtaXRlIHJlY29ub2NlciB0ZXJyaXRvcmlvcyBjb24NCmNhcmFjdGVyw61zdGljYXMgcGFydGljdWxhcmVzIHF1ZSBkZWJlbiBjb25zaWRlcmFyc2UNCmVuIGxhcyBjb21wYXJhY2lvbmVzIHBvc3RlcmlvcmVzLg0KDQoNCmBgYHtyIHZhbG9yZXMtZXh0cmVtb3MtcG9ibGFjaW9ufQ0KDQojIENhbGN1bGFyIGxvcyBsw61taXRlcyBwYXJhIGlkZW50aWZpY2FyIHBvc2libGVzIHZhbG9yZXMgYXTDrXBpY29zDQoNCnExX3BvYmxhY2lvbiA8LSBxdWFudGlsZSh1cHokcG9ibGFjaW9uLCAwLjI1KQ0KDQpxM19wb2JsYWNpb24gPC0gcXVhbnRpbGUodXB6JHBvYmxhY2lvbiwgMC43NSkNCg0KaXFyX3BvYmxhY2lvbiA8LSBJUVIodXB6JHBvYmxhY2lvbikNCg0KbGltaXRlX2luZmVyaW9yIDwtIHExX3BvYmxhY2lvbiAtIDEuNSAqIGlxcl9wb2JsYWNpb24NCg0KbGltaXRlX3N1cGVyaW9yIDwtIHEzX3BvYmxhY2lvbiArIDEuNSAqIGlxcl9wb2JsYWNpb24NCg0KIyBJZGVudGlmaWNhciBsYXMgVVBaIHF1ZSBzZSBlbmN1ZW50cmFuIGZ1ZXJhIGRlIGxvcyBsw61taXRlcw0KDQp2YWxvcmVzX2V4dHJlbW9zIDwtIHVweiAlPiUNCiAgZmlsdGVyKA0KICAgIHBvYmxhY2lvbiA8IGxpbWl0ZV9pbmZlcmlvciB8DQogICAgcG9ibGFjaW9uID4gbGltaXRlX3N1cGVyaW9yDQogICkgJT4lDQogIHNlbGVjdCgNCiAgICB1cHpfbm9tYnJlLA0KICAgIGxvY2FsaWRhZCwNCiAgICBwb2JsYWNpb24sDQogICAgYXJlYV9rbTIsDQogICAgZGVuc2lkYWRfaGFiX2ttMg0KICApICU+JQ0KICBhcnJhbmdlKGRlc2MocG9ibGFjaW9uKSkNCg0KIyBQcmVzZW50YXIgcmVzdWx0YWRvcw0KDQprbml0cjo6a2FibGUoDQogIHZhbG9yZXNfZXh0cmVtb3MsDQogIGNvbC5uYW1lcyA9IGMoDQogICAgIlVQWiIsDQogICAgIkxvY2FsaWRhZCIsDQogICAgIkhhYml0YW50ZXMiLA0KICAgICLDgXJlYSAoa23CsikiLA0KICAgICJEZW5zaWRhZCAoaGFiL2ttwrIpIg0KICApLA0KICBkaWdpdHMgPSAyLA0KICBjYXB0aW9uID0gIlVQWiBpZGVudGlmaWNhZGFzIGNvbW8gcG9zaWJsZXMgdmFsb3JlcyBhdMOtcGljb3MgZW4gcG9ibGFjacOzbiINCikNCg0KIyBNb3N0cmFyIGxvcyBsw61taXRlcyBlc3RhZMOtc3RpY29zDQoNCmNhdCgiTMOtbWl0ZSBpbmZlcmlvcjoiLCByb3VuZChsaW1pdGVfaW5mZXJpb3IsIDIpLCAiXG4iKQ0KDQpjYXQoIkzDrW1pdGUgc3VwZXJpb3I6Iiwgcm91bmQobGltaXRlX3N1cGVyaW9yLCAyKSwgIlxuIikNCg0KY2F0KCJDYW50aWRhZCBkZSBwb3NpYmxlcyB2YWxvcmVzIGF0w61waWNvczoiLCBucm93KHZhbG9yZXNfZXh0cmVtb3MpKQ0KDQpgYGANCg0KDQojIyMgNS4xLjUuIEludGVycHJldGFjacOzbiBkZWwgYW7DoWxpc2lzIGRlbW9ncsOhZmljbw0KDQpFbCBhbsOhbGlzaXMgZGVtb2dyw6FmaWNvIHBlcm1pdGUgcmVjb25vY2VyIHF1ZSBsYXMgVVBaDQpwcmVzZW50YW4gY2FyYWN0ZXLDrXN0aWNhcyBkaWZlcmVudGVzIGVuIGN1YW50byBhIHN1DQpwb2JsYWNpw7NuLCBleHRlbnNpw7NuIHkgZGVuc2lkYWQuDQoNCkVzdGFzIGRpZmVyZW5jaWFzIHNvbiByZWxldmFudGVzIHBhcmEgZWwgZGVzYXJyb2xsbw0KZGUgbGEgaW52ZXN0aWdhY2nDs24sIGRlYmlkbyBhIHF1ZSBsb3MgaW5kaWNhZG9yZXMNCmRlIHNlZ3VyaWRhZCBwdWVkZW4gcHJlc2VudGFyIGNvbXBvcnRhbWllbnRvcw0KZGlzdGludG9zIGRlcGVuZGllbmRvIGRlbCB0YW1hw7FvIHkgbGFzIGNhcmFjdGVyw61zdGljYXMNCmRlIGNhZGEgdGVycml0b3Jpby4NCg0KTGEgaWRlbnRpZmljYWNpw7NuIGRlIHBvc2libGVzIHZhbG9yZXMgZXh0cmVtb3MgdGFtYmnDqW4NCnBlcm1pdGUgcmVjb25vY2VyIHF1ZSBhbGd1bmFzIFVQWiBwdWVkZW4gdGVuZXINCmNvbmRpY2lvbmVzIHBhcnRpY3VsYXJlcyBxdWUgcmVxdWllcmVuIHVuIHRyYXRhbWllbnRvDQpkaWZlcmVuY2lhZG8gYWwgbW9tZW50byBkZSByZWFsaXphciBjb21wYXJhY2lvbmVzDQplc3RhZMOtc3RpY2FzLg0KDQpBIHBhcnRpciBkZSBlc3RvcyByZXN1bHRhZG9zIHNlcsOhIHBvc2libGUgZXN0YWJsZWNlcg0KdW5hIGJhc2UgbcOhcyBzw7NsaWRhIHBhcmEgYW5hbGl6YXIgbG9zIGluZGljYWRvcmVzDQpkZSBkZWxpdG9zLCBkaWZlcmVuY2lhbmRvIGxhcyBjYW50aWRhZGVzIGFic29sdXRhcw0KZGUgbGFzIHRhc2FzIGNhbGN1bGFkYXMgcG9yIGhhYml0YW50ZS4NCg0K