Trabajo Final Ciencia de datos II: Características y Accesibilidad de Barrios Populares en Gran Buenos Aires

Introducción

Este análisis forma parte de la evaluación final del módulo Ciencia de Datos II. La idea es llevar adelante un análisis exploratorio acerca de la situación de los Barrios Populares a partir del relevamiento efectuado en el ReNaBap.

La pregunta principal que guía este artículo consiste en describir el escenario actual en terminos evolutivos y de infraestructura de los BP considerando, además, las condiciones de integración y accesibilidad de los mismos.

A los fines de recortar espacialmente nuestro objeto, se abordará la situación de los barrios populares del Gran Buenos Aires considerando la definición empleada por el INDEC 1 que define el área compuesta por 24 partidos sin considerar la Ciudad Autónoma de Buenos Aires. Para el agrupamiento de los partidos se puede establecer el criterio empleado por la Ley 13.473/06 2 excluyendo aquellas zonas y partidos que no se encuentren en la clasificación del INDEC. Estas son: (Zona del Sureste): Avellaneda, Quilmes, Berazategui, Florencio Varela y Alte. Brown. (Zona Sur): E. Echeverría, Ezeiza. (Zona Sur oeste): Lanús, Lomas de Zamora, La Matanza (Zona Noreste): Vicente López, San Isidro, San Fernando, Tigre (Zona Noroeste): Merlo y Moreno (Zona Norte Centro): San Martín, Tres de Febrero, San Miguel, Malvinas Argentinas, José C. Paz (Zona Oeste): Morón, Hurlingham, Ituzaingó.

(Nota: Este trabajo se encuentra publicado en mi blog y en mi sitio de GitHub)

Ideas - Objetivos:

  • Describir la situación de los BP en la región Amba en función de su evolución e infraestructura

  • Analizar las formas de crecimiento considerando los aspectos geográficos.

  • Pensar las dinámicas de accesibilidad de los BP en relación a servicios escenciales utilizando la información de OSM y vinculando la problemática con el concepto de ciudades de 15 minutos

Fuentes

Mapa Base AMBA: Disponible en el sitio

Barrios Populares: Disponible en el sitio

Datos adicionales: Open Street Map

Activación de librerías

###################################################################################
rm(list = ls())

# Instalamos librerías de trabajo
if (!require("pacman")) install.packages("pacman")
pacman::p_load("DT",
               "lubridate",
               "tidyverse",
               "leaflet",
               "leaflet.extras",
               "sf",
               "scales",
               "ggmap",
               "osmdata",
               "showtext",
               "ggtext",
               "gganimate",
               "gifski",
               "osrm")


sf_use_s2(FALSE)
###################################################################################

#fuentes

font_add_google(family = "montserrat", "Montserrat")
#font_add_google(family = "Oswald", "Oswald")
showtext_auto()

###################################################################################
#KEY
key <- "##################" 
#register_stadiamaps(key, write = TRUE)

Carga y limpieza de datos

#Partidos PBA (#https://catalogo.datos.gba.gob.ar/dataset/partidos/archivo/6cd47ea4-37af-4fdb-9d38-678c1067b7e9)

base_map_partidos <- read_sf("data/partidos_shp/partidos.shp")%>%
                        st_transform(crs = 4326)
#Barrios CABA#######################################################################
#base_map_caba <- read_sf("https://cdn.buenosaires.gob.ar/datosabiertos/datasets/ministerio-de-educacion/barrios/barrios.geojson")%>%
                        #st_transform(crs = 4326)
#Barrios Populares - Pais###########################################################
data_bp_geo <- read_sf("data/20231205_info_publica.geojson", stringsAsFactors = TRUE)

#Definimos area de estudio
area_amba <- c('Merlo','Morón','Moreno','Quilmes','José C. Paz','Ituzaingó','Lanús',
         'La Matanza','Lomas de Zamora','Malvinas Argentinas','San Miguel',
         'San Isidro','Tigre','Vicente López','Tres de Febrero','Almirante Brown',
         'Esteban Echeverría','Florencio Varela','Ezeiza','Hurlingham',
         'General San Martín','Berazategui','Avellaneda','San Fernando')

base_map_amba_agrup <- base_map_partidos %>% 
  filter(nam %in% area_amba) %>% 
  mutate(zona = case_when(nam %in% c('Avellaneda','Quilmes','Berazategui','Florencio Varela','Almirante Brown') ~ 'Zona del Sureste',
                          nam %in% c('Esteban Echeverría','Ezeiza') ~ 'Zona del Sur',
                          nam %in% c("Lanús",'Lomas de Zamora','La Matanza') ~ 'Zona Sur Oeste',
                          nam %in% c('Vicente López','San Isidro','San Fernando', 'Tigre') ~ 'Zona Noreste',
                          nam %in% c('Merlo','Moreno') ~ 'Zona Noroeste',
                          nam %in% c('General San Martín','Tres de Febrero','San Miguel', 'Malvinas Argentinas', 'José C. Paz') ~ 'Zona Norte Centro',
                          nam %in% c('Morón','Hurlingham','Ituzaingó') ~ 'Zona Oeste',
                          )) 

data_bp_geo_amba_agrup  <- data_bp_geo %>%
  mutate(departamento = case_when(departamento == "José M. Ezeiza" ~ "Ezeiza",
                            TRUE ~ departamento )) %>% 
  filter(departamento %in% area_amba,
         provincia == "Buenos Aires") %>% 
    mutate(zona = case_when(departamento %in% c('Avellaneda','Quilmes','Berazategui','Florencio Varela','Almirante Brown') ~ 'Zona del Sureste',
                          departamento %in% c('Esteban Echeverría','Ezeiza') ~ 'Zona del Sur',
                          departamento %in% c("Lanús",'Lomas de Zamora','La Matanza') ~ 'Zona Sur Oeste',
                          departamento %in% c('Vicente López','San Isidro','San Fernando', 'Tigre') ~ 'Zona Noreste',
                          departamento %in% c('Merlo','Moreno') ~ 'Zona Noroeste',
                          departamento %in% c('General San Martín','Tres de Febrero','San Miguel', 'Malvinas Argentinas', 'José C. Paz') ~ 'Zona Norte Centro',
                          departamento %in% c('Morón','Hurlingham','Ituzaingó') ~ 'Zona Oeste',
                          ))


casos_bp <- nrow(data_bp_geo)
casos_bp_amba <- nrow(data_bp_geo_amba_agrup)

La base de datos populares contiene 6467 registros a nivel nacional. Si delimitamos los casos al área de estudio (24 Partidos GBA), se obtienen 1195 barrios registrados.

Mediante la función summary, podemos ver las principales variables de la base:

summary(data_bp_geo_amba_agrup)
##    id_renabap            nombre_barrio                            provincia   
##  Min.   :  16.0   Sin Nombre    :  31   Buenos Aires                   :1195  
##  1st Qu.: 692.5   Dos de Abril  :   8   Catamarca                      :   0  
##  Median :1242.0   El Progreso   :   8   Chaco                          :   0  
##  Mean   :2103.8   La Esperanza  :   8   Chubut                         :   0  
##  3rd Qu.:4261.5   San Cayetano  :   8   Ciudad Autónoma de Buenos Aires:   0  
##  Max.   :6381.0   Nueve de Julio:   7   Córdoba                        :   0  
##                   (Other)       :1125   (Other)                        :   0  
##  departamento                 localidad   cantidad_viviendas_aproximadas
##  Length:1195        José C. Paz    : 53   Min.   :   8.0                
##  Class :character   Cuartel V      : 44   1st Qu.:  50.0                
##  Mode  :character   González Catán : 44   Median : 130.0                
##                     Pontevedra     : 39   Mean   : 315.3                
##                     Virrey Del Pino: 37   3rd Qu.: 347.0                
##                     Trujui         : 28   Max.   :7850.0                
##                     (Other)        :950                                 
##  cantidad_familias_aproximada   decada_de_creacion anio_de_creacion
##  Min.   :   9.0               Década 2000:256      Min.   :2010    
##  1st Qu.:  55.0               Década 1980:221      1st Qu.:2012    
##  Median : 143.0               Década 1990:189      Median :2014    
##  Mean   : 346.9               Década 2010:187      Mean   :2015    
##  3rd Qu.: 381.5               Década 1970:122      3rd Qu.:2018    
##  Max.   :8635.0               Década 1960:111      Max.   :2021    
##                               (Other)    :109      NA's   :994     
##                                                            energia_electrica
##  Conexión irregular a la red                                        :708    
##  Conexión formal a la red con medidor domiciliario con factura      :341    
##  Conexión regular a la red con medidor domiciliario pero sin factura: 54    
##  Conexión a la red con medidor comunitario                          : 41    
##  Conexión regular a la red con medidor prepago                      : 38    
##  No tiene conexión eléctrica                                        :  6    
##  (Other)                                                            :  7    
##                              efluentes_cloacales
##  Desagüe sólo a pozo negro/ciego u hoyo:659     
##  Desagüe a cámara séptica y pozo ciego :363     
##  Conexión formal a la red cloacal      : 81     
##  Conexión irregular a la red cloacal   : 40     
##  Red cloacal conectada a la red pluvial: 39     
##  Desagüe a intemperie o cuerpo de agua : 13     
##  (Other)                               :  0     
##                                             agua_corriente
##  Bomba de agua de pozo domiciliaria                :443   
##  Conexión irregular a la red de agua               :428   
##  Conexión formal a la red de agua con factura      :199   
##  Bomba de agua de pozo comunitaria                 : 80   
##  Conexión regular a la red de agua pero sin factura: 25   
##  Camión cisterna                                   : 12   
##  (Other)                                           :  8   
##                                          cocina    
##  Conexión formal a la red de gas con factura:  58  
##  Conexión irregular a la red de gas         :   0  
##  Energía eléctrica                          :   1  
##  Gas en garrafa                             :1131  
##  Leña o carbón                              :   5  
##                                                    
##                                                    
##                                       calefaccion  titulo_propiedad
##  Conexión formal a la red de gas con factura: 45   NO:1190         
##  Conexión irregular a la red de gas         :  0   SI:   5         
##  Energía eléctrica                          :579                   
##  Gas en garrafa                             : 93                   
##  Inexistente                                : 23                   
##  Leña o carbón                              : 95                   
##  Sin Datos                                  :360                   
##                         clasificacion_barrio superficie_m2    
##  Asentamiento                     :768       Min.   :    370  
##  Conjunto habitacional unifamiliar:  9       1st Qu.:  12542  
##  Villa                            :418       Median :  42641  
##                                              Mean   : 113989  
##                                              3rd Qu.: 119065  
##                                              Max.   :2092457  
##                                                               
##           geometry        zona          
##  MULTIPOLYGON :1195   Length:1195       
##  epsg:4326    :   0   Class :character  
##  +proj=long...:   0   Mode  :character  
##                                         
##                                         
##                                         
## 

Se observa que la base contiene variables que nos permiten ver las condiciones estructurales de las viviendas entre otros aspectos.

La última etapa del proceso de limpieza consiste en generar bases sin los atributos geoespaciales para generar tablas y gráficos con mayor prolijidad

data_bp <- st_drop_geometry(data_bp_geo) %>% 
  mutate("zona" = case_when( departamento %in% area_amba ~ "GBA",
                             TRUE ~ "Resto País"))
data_bp_amba <- st_drop_geometry(data_bp_geo_amba_agrup) 

Expansión e Infraestructura (Análisis descriptivo)

Evolución geográfica y estructural del surgimiento de Barrios Populares

A continuación se muestra un mapa de amba con sus barrios populares al dia de hoy.

ggplot()+
  geom_sf(data = base_map_amba_agrup, color='black', aes(fill = zona),  size = 0.1)+
  scale_fill_manual(values=c("#072448", "#54d2d2","#ffcb00","#679186","#f8aa4b","#ff6150","#543c52"))+
  geom_sf_text(data = base_map_amba_agrup , aes(label=nam),size=4, colour='#e3e3e3')+
  geom_sf(data = data_bp_geo_amba_agrup, color = "black")+
  theme_minimal()+
  theme_void()+
  labs(
    title = "<span style = 'color:#272643;'> Barrios Populares - Gran Buenos Aires",
    caption = "<b>Fuente</b>: ReNaBaP",
    y = "",
    x = ""
  )+
  theme(
    plot.title = element_markdown(size = 20, hjust = 0.5),
    plot.caption= element_markdown(size = 15),
    legend.position = "top",
    legend.title = element_blank(),
    legend.box.margin = margin(11, 16, 6, 6)
  )+
  guides(fill=guide_legend(nrow=1,byrow=TRUE))

Tambien es posible mostrar la misma información en un mapa interactivo, el cual permite acceder a mayor cantidad de datos al seleccionar los barrios

 mapa_interactivo <- leaflet() %>%
         addTiles() %>%
         #addProviderTiles(provider="CartoDB") %>% 
         addPolygons(data = data_bp_geo_amba_agrup, popup = ~ glue::glue("<b>Nombre</b>:{nombre_barrio}<br/>
                                                                    <b>Cantidad de Viviendas:</b>{cantidad_viviendas_aproximadas}<br/>
                                                                    <b>Cantidad de Familias:</b>{cantidad_familias_aproximada}<br/>
                                                                    <b>Decada de Creacion:</b>{decada_de_creacion}<br/>"), color = "#f55951")

mapa_interactivo

Veamos como fue la evolución del surgimiento de los barrios a nivel nacional por década:

tabla_1 <- data_bp %>% 
  mutate("decada_abr" = (substr(decada_de_creacion, 8,11))) %>%
  group_by(decada_abr) %>% 
  summarise(tot = n()) %>% 
  mutate(porcentaje = round(tot/sum(tot),4)) %>% 
  mutate(Total_Acum = cumsum(tot)) %>% 
  mutate(Porcentaje_Acum = cumsum(porcentaje))

ggplot(tabla_1, aes(x = decada_abr, y = tot))+
  geom_col(fill = "#122c91")+
  geom_text(aes(label = percent(porcentaje)), vjust = -0.25, size = 4)+
  theme_minimal()+
  labs(
    title = "<span style = 'color:#122c91;'> Evolución de Barrios Populares - Argentina",
    subtitle = "Creación de Barrios Populares por década",
    caption = "<b>Fuente</b>: ReNaBaP",
    x = "Decadas",
    y = "Barrios Populares"
  )+
  theme(
    plot.title = element_markdown(face = "bold", size = 18),
    plot.caption = element_markdown(size = 11),
  )

Se aprecia el primer dato relevante. De la totalidad de los barrios registrados, el 50% surgió en las décadas del 2000 y el 2010. Veamos como se dió esta situación agregando los casos de AMBA.

tabla_2 <- data_bp %>% 
  mutate("decada_abr" = (substr(decada_de_creacion, 8,11))) %>%
  group_by(decada_abr, zona) %>% 
  summarise(tot = n()) %>% 
  mutate(porcentaje = round(tot/sum(tot),4)) %>% 
  mutate(Total_Acum = cumsum(tot)) %>% 
  mutate(Porcentaje_Acum = cumsum(porcentaje))

ggplot(tabla_2, aes(x = decada_abr, y = tot, fill = zona))+
  geom_col(position = "dodge")+
  geom_text(aes(label = percent(porcentaje)), vjust = -0.5, check_overlap = TRUE, position = position_dodge(width = .9), size = 3)+
  scale_fill_manual(values = c("#f56038","#122c91"))+
  theme_minimal()+
  labs(
    title = "<span style = 'color:#272643;'> Evolución de Barrios Populares: <span style = 'color:#122c91;'> Argentina (Sin GBA) - <span style = 'color:#f56038;'>GBA",
    subtitle = "Creación de Barrios Populares por década",
    caption = "<b>Fuente</b>: ReNaBaP",
    x = "Decadas",
    y = "Barrios Populares"
  )+
  theme(
    legend.position = "none",
    plot.title = element_markdown(face = "bold", size = 15),
    plot.caption = element_markdown(size = 12),
  )

tabla_2 <- data_bp %>% 
  mutate("decada_abr" = (substr(decada_de_creacion, 8,11))) %>%
  group_by(decada_abr, zona) %>% 
  summarise(tot = n()) %>% 
  mutate(porcentaje = round(tot/sum(tot),4)) %>% 
  mutate(Porcentaje_Acum = cumsum(porcentaje)) 

tabla_2$total_acum <- ave(tabla_2$tot, tabla_2$zona, FUN=cumsum)

ggplot(tabla_2, aes(x = decada_abr, y = total_acum , group = zona , colour = zona))+
  geom_line()+
  geom_point()+
  scale_color_manual(values=c("#f56038","#122c91"))+
  #geom_text(aes(label = percent(porcentaje)), vjust = -0.25)+
  theme_minimal()+
  labs(
    title = "<span style = 'color:#122c91;'> Evolución de Barrios Populares - Argentina",
    subtitle = "Creación de Barrios Populares por década",
    caption = "<b>Fuente</b>: ReNaBaP",
    x = "Decadas",
    y = "Barrios Populares"
  )+
  theme(
    plot.title = element_markdown(face = "bold", size = 18),
    plot.caption = element_markdown(size = 12),
  )

Los casos de AMBA también evidencian una consolidad expansión en las décadas mencionadas. Resulta relevante indagar sobre el tipo de barrios generados en esta etapa junto con las características de esta expansión en términos geográficos.

tabla_bp_dep <- data_bp_amba %>% 
  group_by(departamento) %>% 
  summarise(Total = n()) %>% 
  rename("nam" = "departamento")

base_map_amba_agrup_totalbp <- left_join(base_map_amba_agrup,tabla_bp_dep)
  
ggplot()+
  geom_sf(data = base_map_amba_agrup_totalbp, color='black', aes(fill = Total),  size = 0.1)+
  geom_sf_text(data = base_map_amba_agrup_totalbp , aes(label=nam),size=3, alpha=0.8, colour='black')+
  theme_void()+
  labs(
    title = "<span style = 'color:#272643;'> Barrios Populares - Gran Buenos Aires",
    caption = "<b>Fuente</b>: ReNaBaP",
    y = "",
    x = ""
  )+
  scale_fill_distiller(direction = 1)+
  theme(
    plot.caption= element_markdown(size = 15),
    plot.title = element_markdown(size = 20, hjust = 0.5),
  )

Tal cual se observa, La Matanza y Moreno parecen ser los partidos que contienen la mayor cantidad de BP. Veamos de que modo podemos analizar esto en función del tiempo transcurrido y la antigüedad. Para ello, vamos a filtrar nuestra base de BP conservando solo aquellos cuya creación corresponde a las ultimas tres décadas.

ggplot()+
  geom_sf(data = base_map_amba_agrup, color='black', aes(fill = zona),  size = 0.1)+
  scale_fill_manual(values=c("#072448", "#54d2d2","#ffcb00","#679186","#f8aa4b","#ff6150","#543c52"))+
  geom_sf_text(data = base_map_amba_agrup , aes(label=nam),size=4, alpha=0.9, colour='#e3e3e3')+
  geom_sf(data = data_bp_geo_amba_agrup %>% 
            filter(decada_de_creacion %in% c("Década 2000","Década 2010","Década 2020")), color = "black")+
  theme_minimal()+
  theme_void()+
  labs(
    title = "<span style = 'color:#122c91;'> Barrios Populares - Gran Buenos Aires (2000 - 2020)",
    caption = "<b>Fuente</b>: ReNaBaP",
    y = "",
    x = ""
  )+
  theme(
    plot.title = element_markdown(size = 20, hjust = 0.5),
    plot.caption= element_markdown(size = 15),
    legend.position = "top",
    legend.title = element_blank(),
    legend.box.margin = margin(11, 16, 6, 6)
  )+
  guides(fill=guide_legend(nrow=1,byrow=TRUE))

Veamos como se efectuaron los surgimientos por década a partir de un mapa animado que grafique los cambios por década.

mapa_animado <- ggplot()+
  geom_sf(data = base_map_amba_agrup)+
  geom_sf_text(data = base_map_amba_agrup , aes(label=nam),size=3, alpha=0.8, colour='black')+
  geom_sf(data = data_bp_geo_amba_agrup,inherit.aes=FALSE, color = "red")+
  scale_fill_distiller(palette = "Spectral")+
  labs(title="Evolución de creación de Barrios Populares",
       subtitle = "GBA | {closest_state}",
    caption = "<b>Fuente</b>: ReNaBaP",
    y = "",
    x = "")+
  theme_void()+
    theme(
    plot.caption= element_markdown(size = 15)
  )+
  transition_states(decada_de_creacion,transition_length = 3, state_length = 2)

anim_save("map.gif", mapa_animado)

Puede apreciarse que las zonas de mayor distancia con respecto a CABA fueron en donde se generaron una mayor cantidad de BP durante los años 2000 y 2010.

tabla_3 <- data_bp_amba %>% 
  mutate("decada_abr" = (substr(decada_de_creacion, 8,11))) %>%
  group_by(decada_abr, clasificacion_barrio) %>% 
  summarise(tot = n()) %>% 
  mutate(porcentaje = round(tot/sum(tot),4))


ggplot(tabla_3, aes(x = decada_abr, y = tot, fill = clasificacion_barrio))+
  geom_col(position = "fill")+
  #geom_text(aes(label = percent(porcentaje)), vjust = -0.5, check_overlap = TRUE, position = position_dodge(width = .9), size = 3)+
  scale_fill_manual(values=c("#f9b4ab", "#fdebd3","#778490","#679186"))+
  theme_minimal()+
  labs(
    title = "<span style = 'color:#272643;'> Evolución de Barrios Populares: <span style = 'color:#f56038;'>GBA",
    subtitle = "Evolución de la clasificación",
    caption = "<b>Fuente</b>: ReNaBaP",
    x = "Decadas",
    y = "Barrios Populares"
  )+
  theme(
    legend.position = "top",
    plot.title = element_markdown(face = "bold", size = 15),
    plot.caption = element_markdown(size = 12),
  )

#VER

Se observa que en las últimas décadas predominó el asentamiento por sobre la villa. En la próxima sección se ahondará acerca de el tipo de accesibilidad y distancias a servicios esenciales que se manifiestan en algunos de estos tipos de barrios.

Accesibilidad e Integración - Distancias y Tiempos de viaje (Isócronas y Ruteos)

En función de los objetivos planteados, corresponde examinar la situación de los BP bajo la idea comparativa de evaluar el grado de accesibilidad que presentan los barrios de mayor antigüedad con respecto a aquellos cuya creación es más reciente. Para indagar esta cuestión vamos a tomar como referencia, en primer lugar el escenario de Villa Tranquila (Avellaneda - Decada de 1950)

En esta sección vamos a utilizar los recursos de OSM. En primer término vamos a mapear nuestra región de estudio construyendo su bbox

Caso Villa Tranquila (Avellaneda - Decada de 1950)

#https://ryanpeek.org/2016-10-19-animated-gif_maps_in_r/

bbox_amba <- st_bbox(base_map_amba_agrup %>% 
                       filter(nam == "Avellaneda"))
bbox_amba <- as.numeric(bbox_amba)
mapa_amba <- get_stadiamap(bbox = bbox_amba,
                           maptype = "alidade_smooth_dark",
                           zoom = 13)
ggmap(mapa_amba)+
  geom_sf(data = data_bp_geo %>% 
            filter(departamento == "Avellaneda"),inherit.aes=FALSE)+
  theme_void()

Una cuestión metodológica que descubrí en el proceso es que Avellaneda presenta un caso particular dado que es un partido que incluye un barrio con el mismo nombre, con lo cual resulta fundamental aclarar esta cuestión dentro de la función getbb para obtener el polígono del partido y no del barrio.

#Descarga de hospitales - escuelas - transporte

polygon_avellaneda <- getbb("Partido de Avellaneda, Buenos Aires",
                            format_out = "sf_polygon")

hospitales_avellaneda <- opq(bbox_amba)
hospitales_avellaneda <- add_osm_feature(hospitales_avellaneda, key = "amenity", value = c("clinic","hospital"))
hospitales_avellaneda <- osmdata_sf(hospitales_avellaneda)
hospitales_avellaneda <- hospitales_avellaneda$osm_points

escuelas_avellaneda <- opq(bbox_amba)
escuelas_avellaneda <- add_osm_feature(escuelas_avellaneda, key = "amenity", value = c("school","university","college"))
escuelas_avellaneda <- osmdata_sf(escuelas_avellaneda)
escuelas_avellaneda <- escuelas_avellaneda$osm_points

transporte_avellaneda <- opq(bbox_amba)
transporte_avellaneda <- add_osm_feature(transporte_avellaneda, key = "public_transport", value = c("stop_position","   platform","station","stop_area"))
transporte_avellaneda <- osmdata_sf(transporte_avellaneda)
transporte_avellaneda <- transporte_avellaneda$osm_points



hospitales_avellaneda <- st_intersection(hospitales_avellaneda, polygon_avellaneda) %>% 
  mutate("tipo" = "hospitales") %>% 
  select(name, tipo, geometry) %>% 
  filter(!is.na(name))
escuelas_avellaneda <- st_intersection(escuelas_avellaneda, polygon_avellaneda)%>% 
  mutate("tipo" = "escuelas")%>% 
  select(name, tipo, geometry) %>% 
  filter(!is.na(name))
transporte_avellaneda <- st_intersection(transporte_avellaneda, polygon_avellaneda) %>% 
  mutate("tipo" = "transporte")%>% 
  select(name, tipo, geometry) %>% 
  filter(!is.na(name))

lugares_avellaneda <- rbind(hospitales_avellaneda,escuelas_avellaneda,transporte_avellaneda)

#Definición de centroide

data_bp_geo_amba_centroide <- data_bp_geo_amba_agrup %>% 
  filter(departamento == "Avellaneda",
         nombre_barrio == "Villa Tranquila") %>% 
  st_centroid()

#Definición de isocrona

isocrona_vt <- osrmIsochrone(loc = data_bp_geo_amba_centroide$geometry,
                     breaks = seq(from=0,to=20,by=5),
                     res = 35,
                     osrm.profile = "foot")
leaflet(isocrona_vt) %>% 
  addTiles(group = "OSM (default)") %>%
  addProviderTiles(providers$CartoDB.Positron, group = "Positron (minimal)") %>%
  addProviderTiles(providers$CartoDB.DarkMatter, group = "DarkMatter") %>%
  addPolygons(fillColor = ~colorBin("YlOrRd", domain = isocrona_vt$isomax)(isomax),
  color = NA,
  fillOpacity = 0.5, group = "isocrona")%>%
  addPolygons(data = data_bp_geo_amba_agrup %>% 
            filter(departamento == "Avellaneda"),popup = ~ glue::glue("<b>Nombre</b>:{nombre_barrio}<br/>
                                                                    <b>Cantidad de Viviendas:</b>{cantidad_viviendas_aproximadas}<br/>
                                                                    <b>Cantidad de Familias:</b>{cantidad_familias_aproximada}<br/>
                                                                    <b>Decada de Creación:</b>{decada_de_creacion}<br/>"),group = "Barrios Populares", color = "#f55951") %>% 
  addCircleMarkers(data = data_bp_geo_amba_centroide, color = "black", group = "Villa Tranquila") %>% 
  addCircleMarkers(data = lugares_avellaneda %>% 
                          filter(tipo == "hospitales"), popup = ~ glue::glue("<b>Nombre</b>:{name}<br/>
                                                                   <b>tipo:</b>{tipo}<br/>"), group = "hospitales", color = "#001f7d") %>%
  addCircleMarkers(data = lugares_avellaneda%>% 
                          filter(tipo == "escuelas"), popup = ~ glue::glue("<b>Nombre</b>:{name}<br/>
                                                                   <b>tipo:</b>{tipo}<br/>"), group = "escuelas", color = "#58b368") %>%
  addCircleMarkers(data = lugares_avellaneda%>% 
                          filter(tipo == "transporte"), popup = ~ glue::glue("<b>Nombre</b>:{name}<br/>
                                                                   <b>tipo:</b>{tipo}<br/>"), group = "transporte", color = "#dad873") %>% 
  
    addLayersControl(
    baseGroups = c(
      "OSM (default)",
      "Positron (minimal)",
      "DarkMatter"
    ),
    overlayGroups = c("Villa Tranquila", "Barrios Populares","isocrona", "escuelas","transporte","hospitales"),
    options = layersControlOptions(collapsed = FALSE)
  )

dado que la descarga no aporta los nombres de los sitios, intentaremos trabajar con el catálogo de hospitales de #https://catalogo.datos.gba.gob.ar/dataset/establecimientos-salud/archivo/716c84ba-6ed7-490b-81f7-e3e97d746d44

hosp_ave_da <- read_sf("data/hospítales/Establecimientos_salud_publicos_alta_al20220721.geojson", stringsAsFactors = TRUE)
hosp_ave_da <- hosp_ave_da %>% 
  filter(nde == "AVELLANEDA")

hosp_ave_da <- st_intersection(hosp_ave_da, polygon_avellaneda)
data_villa_tranquila <- data_bp_geo_amba_centroide %>% 
  select(nombre_barrio,geometry) %>% 
  mutate("nde" = "AVELLANEDA") 
data_villa_tranquila <- cbind(data_villa_tranquila, st_coordinates(data_villa_tranquila)) %>%
                      st_set_geometry(NULL) %>% 
                      rename(LON_ORIGEN=X,
                             LAT_ORIGEN=Y)
hosp <- hosp_ave_da %>% 
  rename(LON_DESTINO=long,
         LAT_DESTINO=lat) %>% 
  select(LAT_DESTINO,LON_DESTINO,fna,nde) %>% 
  left_join(data_villa_tranquila)

Función de ruteo:

obtener_recorrido <- function(o_x, o_y, d_x, d_y) {
    
    ruta <- osrmRoute(src = c(o_x, o_y),
                      dst = c(d_x, d_y))
    
    #cbind(nombre_barrio = o_nombre, fna = d_nombre, ruta)
    
}


argumentos <- list(hosp$LON_ORIGEN, hosp$LAT_ORIGEN,
                  hosp$LON_DESTINO, hosp$LAT_DESTINO)

de_vt_a_hospitales <- pmap_df(argumentos, obtener_recorrido)

de_vt_a_hospitales <- de_vt_a_hospitales %>% 
  arrange(distance)

prom_dist_vt <- round(mean(de_vt_a_hospitales$distance),2)

prom_tiempo_vt <- round(mean(de_vt_a_hospitales$duration),2)

min_dist_vt <- round(min(de_vt_a_hospitales$distance),2)

min_tiempo_vt <- round(min(de_vt_a_hospitales$duration),2)


summary(de_vt_a_hospitales$distance)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##  0.4298  2.6759  4.9937  4.8992  6.7226  9.9845
summary(de_vt_a_hospitales$duration)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##  0.9167  4.1267  7.3250  7.3826  9.8433 13.5783

Los estadísticos nos muestran que existen 53 establecimientos cercanos a Villa Tranquila, entre los cuales la media de distancia equivale a 5 km y el mas cercano se encuentra a 0,42 km. Las duraciones promedio rondan los 7 minutos. A continuación se grafifcarán los ruteos obtenidos mediante un mapa interactivo, tomando solamente las 15 rutas más cercanas para facilitar la visualización.

leaflet() %>% 
  addTiles() %>% 
  #addPolygons(data = polygon_avellaneda)+
  addPolygons(data = data_bp_geo_amba_agrup %>% 
            filter(departamento == "Avellaneda"),popup = ~ glue::glue("<b>Nombre</b>:{nombre_barrio}<br/>
                                                                    <b>Cantidad de Viviendas:</b>{cantidad_viviendas_aproximadas}<br/>
                                                                    <b>Cantidad de Familias:</b>{cantidad_familias_aproximada}<br/>
                                                                    <b>Decada de Creación:</b>{decada_de_creacion}<br/>"), color = "#f55951") %>% 
  addCircleMarkers(data = data_bp_geo_amba_centroide, color = "green") %>% 
  addMarkers(data = hosp_ave_da, popup = ~ glue::glue("<b>Nombre</b>:{fna}<br/>
                                                                   <b>gna:</b>{gna}<br/>")) %>% 
  addPolylines(data = de_vt_a_hospitales %>% 
                 head(15),color = "red",
                 label = paste("Distancia:", round(de_vt_a_hospitales$distance,2), "|",
                               "Duración:", round(de_vt_a_hospitales$duration,2)))

Caso Asentamiento Primavera (La Matanza - Decada de 2000)

Vamos a analizar el grado de integración y accesibilidad del Asentamiento Primavera en la localidad de La Matanza. Volvemos a realizar los procesos de descarga para esta zona.

#https://ryanpeek.org/2016-10-19-animated-gif_maps_in_r/

bbox_lm <- st_bbox(base_map_amba_agrup %>% 
                       filter(nam == "La Matanza"))
bbox_lm <- as.numeric(bbox_lm)
mapa_lm <- get_stadiamap(bbox = bbox_lm,
                           maptype = "alidade_smooth_dark",
                           zoom = 13)
ggmap(mapa_lm)+
  geom_sf(data = data_bp_geo %>% 
            filter(departamento == "La Matanza"),inherit.aes=FALSE)+
  theme_void()

#Descarga de hospitales - escuelas - transporte

polygon_la_matanza <- getbb("La Matanza, Buenos Aires",
                            format_out = "sf_polygon")

hospitales_la_matanza  <- opq(bbox_lm)
hospitales_la_matanza  <- add_osm_feature(hospitales_la_matanza, key = "amenity", value = c("clinic","hospital"))
hospitales_la_matanza  <- osmdata_sf(hospitales_la_matanza)
hospitales_la_matanza  <- hospitales_la_matanza$osm_points

escuelas_la_matanza <- opq(bbox_lm)
escuelas_la_matanza <- add_osm_feature(escuelas_la_matanza, key = "amenity", value = c("school","university","college"))
escuelas_la_matanza <- osmdata_sf(escuelas_la_matanza)
escuelas_la_matanza <- escuelas_la_matanza$osm_points

transporte_la_matanza <- opq(bbox_lm)
transporte_la_matanza <- add_osm_feature(transporte_la_matanza, key = "public_transport", value = c("stop_position","   platform","station","stop_area"))
transporte_la_matanza <- osmdata_sf(transporte_la_matanza)
transporte_la_matanza <- transporte_la_matanza$osm_points



hospitales_la_matanza <- st_intersection(hospitales_la_matanza, polygon_la_matanza) %>% 
  mutate("tipo" = "hospitales") %>% 
  select(name, tipo, geometry) %>% 
  filter(!is.na(name))
escuelas_la_matanza <- st_intersection(escuelas_la_matanza, polygon_la_matanza)%>% 
  mutate("tipo" = "escuelas")%>% 
  select(name, tipo, geometry) %>% 
  filter(!is.na(name))
transporte_la_matanza <- st_intersection(transporte_la_matanza, polygon_la_matanza) %>% 
  mutate("tipo" = "transporte")%>% 
  select(name, tipo, geometry) %>% 
  filter(!is.na(name))

lugares_la_matanza <- rbind(hospitales_la_matanza,escuelas_la_matanza,transporte_la_matanza)

#Definición de centroide

data_bp_geo_lm_centroide <- data_bp_geo_amba_agrup %>% 
  filter(departamento == "La Matanza",
         nombre_barrio == "Primavera") %>% 
  st_centroid()

#Definición de isocrona

isocrona_lm <- osrmIsochrone(loc = data_bp_geo_lm_centroide$geometry,
                     breaks = seq(from=0,to=20,by=5),
                     res = 35,
                     osrm.profile = "foot")
leaflet(isocrona_lm) %>% 
  addTiles(group = "OSM (default)") %>%
  addProviderTiles(providers$CartoDB.Positron, group = "Positron (minimal)") %>%
  addProviderTiles(providers$CartoDB.DarkMatter, group = "DarkMatter") %>%
  addPolygons(fillColor = ~colorBin("Oranges", domain = isocrona_vt$isomax)(isomax),
  color = NA,
  fillOpacity = 0.5, group = "isocrona")%>%
  addPolygons(data = data_bp_geo_amba_agrup %>% 
            filter(departamento == "La Matanza"),popup = ~ glue::glue("<b>Nombre</b>:{nombre_barrio}<br/>
                                                                    <b>Cantidad de Viviendas:</b>{cantidad_viviendas_aproximadas}<br/>
                                                                    <b>Cantidad de Familias:</b>{cantidad_familias_aproximada}<br/>
                                                                    <b>Decada de Creación:</b>{decada_de_creacion}<br/>"), group = "Barrios Populares",color = "#f55951") %>% 
  addCircleMarkers(data = data_bp_geo_lm_centroide, color = "black", group = "Asentamiento Primavera") %>% 
  addCircleMarkers(data = lugares_la_matanza %>% 
                          filter(tipo == "hospitales"), popup = ~ glue::glue("<b>Nombre</b>:{name}<br/>
                                                                   <b>tipo:</b>{tipo}<br/>"), group = "hospitales", color = "#001f7d") %>%
  addCircleMarkers(data = lugares_la_matanza%>% 
                          filter(tipo == "escuelas"), popup = ~ glue::glue("<b>Nombre</b>:{name}<br/>
                                                                   <b>tipo:</b>{tipo}<br/>"), group = "escuelas", color = "#58b368") %>%
  addCircleMarkers(data = lugares_la_matanza%>% 
                          filter(tipo == "transporte"), popup = ~ glue::glue("<b>Nombre</b>:{name}<br/>
                                                                   <b>tipo:</b>{tipo}<br/>"), group = "transporte", color = "#dad873") %>% 
  
    addLayersControl(
    baseGroups = c(
      "OSM (default)",
      "Positron (minimal)",
      "DarkMatter"
    ),
    overlayGroups = c("Asentamiento Primavera","Barrios Populares", "isocrona","escuelas","transporte","hospitales"),
    options = layersControlOptions(collapsed = FALSE)
  )
hosp_ave_lm <- read_sf("data/hospítales/Establecimientos_salud_publicos_alta_al20220721.geojson", stringsAsFactors = TRUE)
hosp_ave_lm <- hosp_ave_lm %>% 
  filter(nde == "LA MATANZA")

hosp_ave_lm <- st_intersection(hosp_ave_lm, polygon_la_matanza)
data_asen_primavera <- data_bp_geo_lm_centroide %>% 
  select(nombre_barrio,geometry) %>% 
  mutate("nde" = "LA MATANZA") 
data_asen_primavera <- cbind(data_asen_primavera , st_coordinates(data_asen_primavera)) %>%
                      st_set_geometry(NULL) %>% 
                      rename(LON_ORIGEN=X,
                             LAT_ORIGEN=Y)

hosp_lm <- hosp_ave_lm %>% 
  rename(LON_DESTINO=long,
         LAT_DESTINO=lat) %>% 
  select(LAT_DESTINO,LON_DESTINO,fna,nde) %>% 
  left_join(data_asen_primavera)
obtener_recorrido <- function(o_x, o_y, d_x, d_y) {
    
    ruta <- osrmRoute(src = c(o_x, o_y),
                      dst = c(d_x, d_y))
    
    #cbind(nombre_barrio = o_nombre, fna = d_nombre, ruta)
    
}


argumentos <- list(hosp_lm$LON_ORIGEN, hosp_lm$LAT_ORIGEN,
                  hosp_lm$LON_DESTINO, hosp_lm$LAT_DESTINO)

de_lm_a_hospitales <- pmap_df(argumentos, obtener_recorrido)

de_lm_a_hospitales <- de_lm_a_hospitales %>% 
  arrange(distance)

summary(de_lm_a_hospitales$distance)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   1.496   7.194  11.600  11.223  14.570  20.447
summary(de_lm_a_hospitales$duration)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   3.227  12.203  17.078  16.366  20.634  25.153

Los estadísticos nos muestran, en este caso que existen 88 establecimientos cercanos al Asentamiento, entre los cuales la media de distancia equivale a 11 km y el mas cercano se encuentra a 1,46 km. Las duraciones promedio rondan los 16 minutos duplicando los valores obtenidos en Villa Tranquila. A continuación se graficarán los ruteos obtenidos mediante un mapa interactivo, tomando solamente las 15 rutas más cercanas para facilitar la visualización.

leaflet() %>% 
  addTiles() %>% 
  addPolygons(data = data_bp_geo_amba_agrup %>% 
            filter(departamento == "La Matanza"),popup = ~ glue::glue("<b>Nombre</b>:{nombre_barrio}<br/>
                                                                    <b>Cantidad de Viviendas:</b>{cantidad_viviendas_aproximadas}<br/>
                                                                    <b>Cantidad de Familias:</b>{cantidad_familias_aproximada}<br/>
                                                                    <b>Decada de Creación:</b>{decada_de_creacion}<br/>"), color = "#f55951") %>% 
  addCircleMarkers(data = data_bp_geo_lm_centroide, color = "green") %>% 
  addMarkers(data = hosp_ave_lm, popup = ~ glue::glue("<b>Nombre</b>:{fna}<br/>
                                                                   <b>gna:</b>{gna}<br/>")) %>% 
  addPolylines(data = de_lm_a_hospitales %>% 
                 head(15),color = "red",
                 label = paste("Distancia:", round(de_lm_a_hospitales$distance,2), "|",
                               "Duración:", round(de_lm_a_hospitales$duration,2)))

Conclusiones

A través de las herramientas de georeferenciación comprendidas en la materia, se analizó la situación de los Barrios Populares del Gran Buenos Aires a partir de sus clasificaciones y antigüedad de los mismos. En base a ello, se tomaron dos casos con el objeto de estudiar su grado de accesibilidad a servicios de salud, transporte y educación. Las técnicas utilizadas consistieron en descargar información de la API de OSM Y de datos abiertos de PBA para complementar lo que no se encuentre en el primero. Con estos datos, se obtuvo un isócrona para evaluar de manera visual en un mapa interactivo, las formas de integración de los barrios como un posible insumo para pensar estas problemáticas bajo la premisa de “ciudades de 15 minutos”. En este orden de ideas, pudo verse también que en el caso de Villa Tranquila, los tiempos y las distancias de los ruteos hacia servicios sanitarios marcaron cifras considerablemente menores que en el caso del Asentamiento Primavera de La Matanza.

Futuras Ideas

Construir una shiny app con toda la información recabada para facilitar las visualizaciones

Construir una función que mapee y rutee tomando como insumo el nombre del barrio y el partido.

LS0tDQp0aXRsZTogIkJhcnJpb3MgcG9wdWxhcmVzIg0KYXV0aG9yOiAiSnVhbiBHdWlsbGVybW8gRmVyY2hlcm8iDQpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgY29kZV9mb2xkaW5nOiBoaWRlDQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KICAgIGRmX3ByaW50OiBwYWdlZA0KICAgIHRvYzogeWVzDQogICAgdG9jX2Zsb2F0OiB5ZXMNCiAgcGRmX2RvY3VtZW50Og0KICAgIHRvYzogeWVzDQotLS0NCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFLCBkcGkgPSAxNTAsIGZpZy5zaG93dGV4dD1UUlVFKQ0Kb3B0aW9ucyhzY2lwZW4gPSA5OTkpDQoNCmBgYA0KDQojIFRyYWJham8gRmluYWwgQ2llbmNpYSBkZSBkYXRvcyBJSTogQ2FyYWN0ZXLDrXN0aWNhcyB5IEFjY2VzaWJpbGlkYWQgZGUgQmFycmlvcyBQb3B1bGFyZXMgZW4gR3JhbiBCdWVub3MgQWlyZXMNCg0KYGBge3IsIGVjaG89RkFMU0UsIG91dC53aWR0aD0iNTAlIiwgZmlnLmFsaWduPSdjZW50ZXInfQ0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoImltZy9yZW5hYmFwMjAyMy0xLmpwZyIpDQpgYGANCg0KIyMgSW50cm9kdWNjacOzbg0KDQo8ZGl2IHN0eWxlPSJ0ZXh0LWFsaWduOiBqdXN0aWZ5Ij4NCg0KRXN0ZSBhbsOhbGlzaXMgZm9ybWEgcGFydGUgZGUgbGEgZXZhbHVhY2nDs24gZmluYWwgZGVsIG3Ds2R1bG8gQ2llbmNpYSBkZSBEYXRvcyBJSS4gTGEgaWRlYSBlcyBsbGV2YXIgYWRlbGFudGUgdW4gYW7DoWxpc2lzIGV4cGxvcmF0b3JpbyBhY2VyY2EgZGUgbGEgc2l0dWFjacOzbiBkZSBsb3MgQmFycmlvcyBQb3B1bGFyZXMgYSBwYXJ0aXIgZGVsIHJlbGV2YW1pZW50byBlZmVjdHVhZG8gZW4gZWwgW1JlTmFCYXBdKGh0dHBzOi8vd3d3LmFyZ2VudGluYS5nb2IuYXIvaGFiaXRhdC9pbnRlZ3JhY2lvbi1zb2Npby11cmJhbmEvcmVuYWJhcCkuDQoNCkxhIHByZWd1bnRhIHByaW5jaXBhbCBxdWUgZ3XDrWEgZXN0ZSBhcnTDrWN1bG8gY29uc2lzdGUgZW4gZGVzY3JpYmlyIGVsIGVzY2VuYXJpbyBhY3R1YWwgZW4gdGVybWlub3MgZXZvbHV0aXZvcyB5IGRlIGluZnJhZXN0cnVjdHVyYSBkZSBsb3MgQlAgY29uc2lkZXJhbmRvLCBhZGVtw6FzLCBsYXMgY29uZGljaW9uZXMgZGUgaW50ZWdyYWNpw7NuIHkgYWNjZXNpYmlsaWRhZCBkZSBsb3MgbWlzbW9zLg0KDQpBIGxvcyBmaW5lcyBkZSByZWNvcnRhciBlc3BhY2lhbG1lbnRlIG51ZXN0cm8gb2JqZXRvLCBzZSBhYm9yZGFyw6EgbGEgc2l0dWFjacOzbiBkZSBsb3MgYmFycmlvcyBwb3B1bGFyZXMgZGVsIEdyYW4gQnVlbm9zIEFpcmVzIGNvbnNpZGVyYW5kbyBsYSBkZWZpbmljacOzbiBlbXBsZWFkYSBwb3IgZWwgSU5ERUMgW14xXSBxdWUgZGVmaW5lIGVsIMOhcmVhIGNvbXB1ZXN0YSBwb3IgMjQgcGFydGlkb3Mgc2luIGNvbnNpZGVyYXIgbGEgQ2l1ZGFkIEF1dMOzbm9tYSBkZSBCdWVub3MgQWlyZXMuIFBhcmEgZWwgYWdydXBhbWllbnRvIGRlIGxvcyBwYXJ0aWRvcyBzZSBwdWVkZSBlc3RhYmxlY2VyIGVsIGNyaXRlcmlvIGVtcGxlYWRvIHBvciBsYSBMZXkgMTMuNDczLzA2IFteMl0gZXhjbHV5ZW5kbyBhcXVlbGxhcyB6b25hcyB5IHBhcnRpZG9zIHF1ZSBubyBzZSBlbmN1ZW50cmVuIGVuIGxhIGNsYXNpZmljYWNpw7NuIGRlbCBJTkRFQy4gRXN0YXMgc29uOiAoWm9uYSBkZWwgU3VyZXN0ZSk6IEF2ZWxsYW5lZGEsIFF1aWxtZXMsIEJlcmF6YXRlZ3VpLCBGbG9yZW5jaW8gVmFyZWxhIHkgQWx0ZS4gQnJvd24uIChab25hIFN1cik6IEUuIEVjaGV2ZXJyw61hLCBFemVpemEuIChab25hIFN1ciBvZXN0ZSk6IExhbsO6cywgTG9tYXMgZGUgWmFtb3JhLCBMYSBNYXRhbnphIChab25hIE5vcmVzdGUpOiBWaWNlbnRlIEzDs3BleiwgU2FuIElzaWRybywgU2FuIEZlcm5hbmRvLCBUaWdyZSAoWm9uYSBOb3JvZXN0ZSk6IE1lcmxvIHkgTW9yZW5vIChab25hIE5vcnRlIENlbnRybyk6IFNhbiBNYXJ0w61uLCBUcmVzIGRlIEZlYnJlcm8sIFNhbiBNaWd1ZWwsIE1hbHZpbmFzIEFyZ2VudGluYXMsIEpvc8OpIEMuIFBheiAoWm9uYSBPZXN0ZSk6IE1vcsOzbiwgSHVybGluZ2hhbSwgSXR1emFpbmfDsy4NCg0KW14xXTogRGlzcG9uaWJsZSBlbjogPGh0dHBzOi8vd3d3LmluZGVjLmdvYi5hci9kYmluZGVjL2ZvbGxldG9fZ2JhLnBkZj4NCg0KW14yXTogRGlzcG9uaWJsZSBlbjogPGh0dHBzOi8vbm9ybWFzLmdiYS5nb2IuYXIvZG9jdW1lbnRvcy8wWjhKOElFQi5odG1sPiA6OjoNCg0KKCoqTm90YToqKiBFc3RlIHRyYWJham8gc2UgZW5jdWVudHJhIHB1YmxpY2FkbyBlbiBtaSBbYmxvZ10oaHR0cHM6Ly9ycHVicy5jb20vR3VpbGxlRmVyY2hlcm8vYmFycmlvc19wb3B1bGFyZXMpIHkgZW4gbWkgW3NpdGlvIGRlIEdpdEh1Yl0oaHR0cHM6Ly9naXRodWIuY29tL0d1aWxsZUZlcmNoZXJvL0JpZy1kYXRhLWUtSW50ZWxpZ2VuY2lhLXRlcnJpdG9yaWFsLS1GTEFDU08tL3RyZWUvbWFpbi9UcmFiYWpvLUZpbmFsKSkgDQoNCiMjIyBJZGVhcyAtIE9iamV0aXZvczoNCg0KLSAgIERlc2NyaWJpciBsYSBzaXR1YWNpw7NuIGRlIGxvcyBCUCBlbiBsYSByZWdpw7NuIEFtYmEgZW4gZnVuY2nDs24gZGUgc3UgZXZvbHVjacOzbiBlIGluZnJhZXN0cnVjdHVyYQ0KDQotICAgQW5hbGl6YXIgbGFzIGZvcm1hcyBkZSBjcmVjaW1pZW50byBjb25zaWRlcmFuZG8gbG9zIGFzcGVjdG9zIGdlb2dyw6FmaWNvcy4NCg0KLSAgIFBlbnNhciBsYXMgZGluw6FtaWNhcyBkZSBhY2Nlc2liaWxpZGFkIGRlIGxvcyBCUCBlbiByZWxhY2nDs24gYSBzZXJ2aWNpb3MgZXNjZW5jaWFsZXMgdXRpbGl6YW5kbyBsYSBpbmZvcm1hY2nDs24gZGUgT1NNIHkgdmluY3VsYW5kbyBsYSBwcm9ibGVtw6F0aWNhIGNvbiBlbCBjb25jZXB0byBkZSBbY2l1ZGFkZXMgZGUgMTUgbWludXRvc10oaHR0cHM6Ly9jZW5pdGFsLmNvbS9sYS1wYXJhbm9pYS1kZS1sb3MtMTUtbWludXRvcy8pDQoNCiMjIyBGdWVudGVzDQoNCk1hcGEgQmFzZSBBTUJBOiBEaXNwb25pYmxlIGVuIGVsIFtzaXRpb10oaHR0cHM6Ly9jYXRhbG9nby5kYXRvcy5nYmEuZ29iLmFyL2RhdGFzZXQvcGFydGlkb3MvYXJjaGl2by82Y2Q0N2VhNC0zN2FmLTRmZGItOWQzOC02NzhjMTA2N2I3ZTkpDQoNCkJhcnJpb3MgUG9wdWxhcmVzOiBEaXNwb25pYmxlIGVuIGVsIFtzaXRpb10oaHR0cHM6Ly9kYXRvc2FiaWVydG9zLmRlc2Fycm9sbG9zb2NpYWwuZ29iLmFyL2RhdGFzZXQvMGQwMjI3NjctOTM5MC00ODZhLWJmZjQtYmE1M2I4NWQ3MzBlL3Jlc291cmNlLzk3Y2M3ZDEwLWFkNGMtNDZjYi05ZWU0LWJlY2I0MDJhZGY5Zi8pDQoNCkRhdG9zIGFkaWNpb25hbGVzOiBPcGVuIFN0cmVldCBNYXANCg0KPGRpdi8+DQoNCiMjIyBBY3RpdmFjacOzbiBkZSBsaWJyZXLDrWFzDQoNCmBgYHtyIGxpYnIsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0Kcm0obGlzdCA9IGxzKCkpDQoNCiMgSW5zdGFsYW1vcyBsaWJyZXLDrWFzIGRlIHRyYWJham8NCmlmICghcmVxdWlyZSgicGFjbWFuIikpIGluc3RhbGwucGFja2FnZXMoInBhY21hbiIpDQpwYWNtYW46OnBfbG9hZCgiRFQiLA0KICAgICAgICAgICAgICAgImx1YnJpZGF0ZSIsDQogICAgICAgICAgICAgICAidGlkeXZlcnNlIiwNCiAgICAgICAgICAgICAgICJsZWFmbGV0IiwNCiAgICAgICAgICAgICAgICJsZWFmbGV0LmV4dHJhcyIsDQogICAgICAgICAgICAgICAic2YiLA0KICAgICAgICAgICAgICAgInNjYWxlcyIsDQogICAgICAgICAgICAgICAiZ2dtYXAiLA0KICAgICAgICAgICAgICAgIm9zbWRhdGEiLA0KICAgICAgICAgICAgICAgInNob3d0ZXh0IiwNCiAgICAgICAgICAgICAgICJnZ3RleHQiLA0KICAgICAgICAgICAgICAgImdnYW5pbWF0ZSIsDQogICAgICAgICAgICAgICAiZ2lmc2tpIiwNCiAgICAgICAgICAgICAgICJvc3JtIikNCg0KDQpzZl91c2VfczIoRkFMU0UpDQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KDQojZnVlbnRlcw0KDQpmb250X2FkZF9nb29nbGUoZmFtaWx5ID0gIm1vbnRzZXJyYXQiLCAiTW9udHNlcnJhdCIpDQojZm9udF9hZGRfZ29vZ2xlKGZhbWlseSA9ICJPc3dhbGQiLCAiT3N3YWxkIikNCnNob3d0ZXh0X2F1dG8oKQ0KDQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KI0tFWQ0Ka2V5IDwtICIjIyMjIyMjIyMjIyMjIyMjIyMiIA0KI3JlZ2lzdGVyX3N0YWRpYW1hcHMoa2V5LCB3cml0ZSA9IFRSVUUpDQoNCmBgYA0KDQojIyMgQ2FyZ2EgeSBsaW1waWV6YSBkZSBkYXRvcw0KDQpgYGB7ciBkYXRhLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KI1BhcnRpZG9zIFBCQSAoI2h0dHBzOi8vY2F0YWxvZ28uZGF0b3MuZ2JhLmdvYi5hci9kYXRhc2V0L3BhcnRpZG9zL2FyY2hpdm8vNmNkNDdlYTQtMzdhZi00ZmRiLTlkMzgtNjc4YzEwNjdiN2U5KQ0KDQpiYXNlX21hcF9wYXJ0aWRvcyA8LSByZWFkX3NmKCJkYXRhL3BhcnRpZG9zX3NocC9wYXJ0aWRvcy5zaHAiKSU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgc3RfdHJhbnNmb3JtKGNycyA9IDQzMjYpDQojQmFycmlvcyBDQUJBIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCiNiYXNlX21hcF9jYWJhIDwtIHJlYWRfc2YoImh0dHBzOi8vY2RuLmJ1ZW5vc2FpcmVzLmdvYi5hci9kYXRvc2FiaWVydG9zL2RhdGFzZXRzL21pbmlzdGVyaW8tZGUtZWR1Y2FjaW9uL2JhcnJpb3MvYmFycmlvcy5nZW9qc29uIiklPiUNCiAgICAgICAgICAgICAgICAgICAgICAgICNzdF90cmFuc2Zvcm0oY3JzID0gNDMyNikNCiNCYXJyaW9zIFBvcHVsYXJlcyAtIFBhaXMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KZGF0YV9icF9nZW8gPC0gcmVhZF9zZigiZGF0YS8yMDIzMTIwNV9pbmZvX3B1YmxpY2EuZ2VvanNvbiIsIHN0cmluZ3NBc0ZhY3RvcnMgPSBUUlVFKQ0KDQojRGVmaW5pbW9zIGFyZWEgZGUgZXN0dWRpbw0KYXJlYV9hbWJhIDwtIGMoJ01lcmxvJywnTW9yw7NuJywnTW9yZW5vJywnUXVpbG1lcycsJ0pvc8OpIEMuIFBheicsJ0l0dXphaW5nw7MnLCdMYW7DunMnLA0KICAgICAgICAgJ0xhIE1hdGFuemEnLCdMb21hcyBkZSBaYW1vcmEnLCdNYWx2aW5hcyBBcmdlbnRpbmFzJywnU2FuIE1pZ3VlbCcsDQogICAgICAgICAnU2FuIElzaWRybycsJ1RpZ3JlJywnVmljZW50ZSBMw7NwZXonLCdUcmVzIGRlIEZlYnJlcm8nLCdBbG1pcmFudGUgQnJvd24nLA0KICAgICAgICAgJ0VzdGViYW4gRWNoZXZlcnLDrWEnLCdGbG9yZW5jaW8gVmFyZWxhJywnRXplaXphJywnSHVybGluZ2hhbScsDQogICAgICAgICAnR2VuZXJhbCBTYW4gTWFydMOtbicsJ0JlcmF6YXRlZ3VpJywnQXZlbGxhbmVkYScsJ1NhbiBGZXJuYW5kbycpDQoNCmJhc2VfbWFwX2FtYmFfYWdydXAgPC0gYmFzZV9tYXBfcGFydGlkb3MgJT4lIA0KICBmaWx0ZXIobmFtICVpbiUgYXJlYV9hbWJhKSAlPiUgDQogIG11dGF0ZSh6b25hID0gY2FzZV93aGVuKG5hbSAlaW4lIGMoJ0F2ZWxsYW5lZGEnLCdRdWlsbWVzJywnQmVyYXphdGVndWknLCdGbG9yZW5jaW8gVmFyZWxhJywnQWxtaXJhbnRlIEJyb3duJykgfiAnWm9uYSBkZWwgU3VyZXN0ZScsDQogICAgICAgICAgICAgICAgICAgICAgICAgIG5hbSAlaW4lIGMoJ0VzdGViYW4gRWNoZXZlcnLDrWEnLCdFemVpemEnKSB+ICdab25hIGRlbCBTdXInLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBuYW0gJWluJSBjKCJMYW7DunMiLCdMb21hcyBkZSBaYW1vcmEnLCdMYSBNYXRhbnphJykgfiAnWm9uYSBTdXIgT2VzdGUnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBuYW0gJWluJSBjKCdWaWNlbnRlIEzDs3BleicsJ1NhbiBJc2lkcm8nLCdTYW4gRmVybmFuZG8nLCAnVGlncmUnKSB+ICdab25hIE5vcmVzdGUnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBuYW0gJWluJSBjKCdNZXJsbycsJ01vcmVubycpIH4gJ1pvbmEgTm9yb2VzdGUnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBuYW0gJWluJSBjKCdHZW5lcmFsIFNhbiBNYXJ0w61uJywnVHJlcyBkZSBGZWJyZXJvJywnU2FuIE1pZ3VlbCcsICdNYWx2aW5hcyBBcmdlbnRpbmFzJywgJ0pvc8OpIEMuIFBheicpIH4gJ1pvbmEgTm9ydGUgQ2VudHJvJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtICVpbiUgYygnTW9yw7NuJywnSHVybGluZ2hhbScsJ0l0dXphaW5nw7MnKSB+ICdab25hIE9lc3RlJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgKSkgDQoNCmRhdGFfYnBfZ2VvX2FtYmFfYWdydXAgIDwtIGRhdGFfYnBfZ2VvICU+JQ0KICBtdXRhdGUoZGVwYXJ0YW1lbnRvID0gY2FzZV93aGVuKGRlcGFydGFtZW50byA9PSAiSm9zw6kgTS4gRXplaXphIiB+ICJFemVpemEiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiBkZXBhcnRhbWVudG8gKSkgJT4lIA0KICBmaWx0ZXIoZGVwYXJ0YW1lbnRvICVpbiUgYXJlYV9hbWJhLA0KICAgICAgICAgcHJvdmluY2lhID09ICJCdWVub3MgQWlyZXMiKSAlPiUgDQogICAgbXV0YXRlKHpvbmEgPSBjYXNlX3doZW4oZGVwYXJ0YW1lbnRvICVpbiUgYygnQXZlbGxhbmVkYScsJ1F1aWxtZXMnLCdCZXJhemF0ZWd1aScsJ0Zsb3JlbmNpbyBWYXJlbGEnLCdBbG1pcmFudGUgQnJvd24nKSB+ICdab25hIGRlbCBTdXJlc3RlJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgZGVwYXJ0YW1lbnRvICVpbiUgYygnRXN0ZWJhbiBFY2hldmVycsOtYScsJ0V6ZWl6YScpIH4gJ1pvbmEgZGVsIFN1cicsDQogICAgICAgICAgICAgICAgICAgICAgICAgIGRlcGFydGFtZW50byAlaW4lIGMoIkxhbsO6cyIsJ0xvbWFzIGRlIFphbW9yYScsJ0xhIE1hdGFuemEnKSB+ICdab25hIFN1ciBPZXN0ZScsDQogICAgICAgICAgICAgICAgICAgICAgICAgIGRlcGFydGFtZW50byAlaW4lIGMoJ1ZpY2VudGUgTMOzcGV6JywnU2FuIElzaWRybycsJ1NhbiBGZXJuYW5kbycsICdUaWdyZScpIH4gJ1pvbmEgTm9yZXN0ZScsDQogICAgICAgICAgICAgICAgICAgICAgICAgIGRlcGFydGFtZW50byAlaW4lIGMoJ01lcmxvJywnTW9yZW5vJykgfiAnWm9uYSBOb3JvZXN0ZScsDQogICAgICAgICAgICAgICAgICAgICAgICAgIGRlcGFydGFtZW50byAlaW4lIGMoJ0dlbmVyYWwgU2FuIE1hcnTDrW4nLCdUcmVzIGRlIEZlYnJlcm8nLCdTYW4gTWlndWVsJywgJ01hbHZpbmFzIEFyZ2VudGluYXMnLCAnSm9zw6kgQy4gUGF6JykgfiAnWm9uYSBOb3J0ZSBDZW50cm8nLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBkZXBhcnRhbWVudG8gJWluJSBjKCdNb3LDs24nLCdIdXJsaW5naGFtJywnSXR1emFpbmfDsycpIH4gJ1pvbmEgT2VzdGUnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICApKQ0KDQoNCmNhc29zX2JwIDwtIG5yb3coZGF0YV9icF9nZW8pDQpjYXNvc19icF9hbWJhIDwtIG5yb3coZGF0YV9icF9nZW9fYW1iYV9hZ3J1cCkNCg0KYGBgDQoNCjxkaXYgc3R5bGU9InRleHQtYWxpZ246IGp1c3RpZnkiPg0KDQpMYSBiYXNlIGRlIGRhdG9zIHBvcHVsYXJlcyBjb250aWVuZSBgciBjYXNvc19icGAgcmVnaXN0cm9zIGEgbml2ZWwgbmFjaW9uYWwuIFNpIGRlbGltaXRhbW9zIGxvcyBjYXNvcyBhbCDDoXJlYSBkZSBlc3R1ZGlvICgyNCBQYXJ0aWRvcyBHQkEpLCBzZSBvYnRpZW5lbiBgciBjYXNvc19icF9hbWJhYCBiYXJyaW9zIHJlZ2lzdHJhZG9zLg0KDQpNZWRpYW50ZSBsYSBmdW5jacOzbiBzdW1tYXJ5LCBwb2RlbW9zIHZlciBsYXMgcHJpbmNpcGFsZXMgdmFyaWFibGVzIGRlIGxhIGJhc2U6DQoNCjxkaXYvPg0KDQpgYGB7ciBFREEgSSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCnN1bW1hcnkoZGF0YV9icF9nZW9fYW1iYV9hZ3J1cCkNCmBgYA0KDQpTZSBvYnNlcnZhIHF1ZSBsYSBiYXNlIGNvbnRpZW5lIHZhcmlhYmxlcyBxdWUgbm9zIHBlcm1pdGVuIHZlciBsYXMgY29uZGljaW9uZXMgZXN0cnVjdHVyYWxlcyBkZSBsYXMgdml2aWVuZGFzIGVudHJlIG90cm9zIGFzcGVjdG9zLg0KDQpMYSDDumx0aW1hIGV0YXBhIGRlbCBwcm9jZXNvIGRlIGxpbXBpZXphIGNvbnNpc3RlIGVuIGdlbmVyYXIgYmFzZXMgc2luIGxvcyBhdHJpYnV0b3MgZ2VvZXNwYWNpYWxlcyBwYXJhIGdlbmVyYXIgdGFibGFzIHkgZ3LDoWZpY29zIGNvbiBtYXlvciBwcm9saWppZGFkDQoNCmBgYHtyIEVEQSBJSSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmRhdGFfYnAgPC0gc3RfZHJvcF9nZW9tZXRyeShkYXRhX2JwX2dlbykgJT4lIA0KICBtdXRhdGUoInpvbmEiID0gY2FzZV93aGVuKCBkZXBhcnRhbWVudG8gJWluJSBhcmVhX2FtYmEgfiAiR0JBIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+ICJSZXN0byBQYcOtcyIpKQ0KZGF0YV9icF9hbWJhIDwtIHN0X2Ryb3BfZ2VvbWV0cnkoZGF0YV9icF9nZW9fYW1iYV9hZ3J1cCkgDQpgYGANCg0KIyMgRXhwYW5zacOzbiBlIEluZnJhZXN0cnVjdHVyYSAoQW7DoWxpc2lzIGRlc2NyaXB0aXZvKQ0KDQojIyMgRXZvbHVjacOzbiBnZW9ncsOhZmljYSB5IGVzdHJ1Y3R1cmFsIGRlbCBzdXJnaW1pZW50byBkZSBCYXJyaW9zIFBvcHVsYXJlcw0KDQpBIGNvbnRpbnVhY2nDs24gc2UgbXVlc3RyYSB1biBtYXBhIGRlIGFtYmEgY29uIHN1cyBiYXJyaW9zIHBvcHVsYXJlcyBhbCBkaWEgZGUgaG95Lg0KDQpgYGB7ciBmaWcuaGVpZ2h0PTksIGZpZy53aWR0aD0xMCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmdncGxvdCgpKw0KICBnZW9tX3NmKGRhdGEgPSBiYXNlX21hcF9hbWJhX2FncnVwLCBjb2xvcj0nYmxhY2snLCBhZXMoZmlsbCA9IHpvbmEpLCAgc2l6ZSA9IDAuMSkrDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCIjMDcyNDQ4IiwgIiM1NGQyZDIiLCIjZmZjYjAwIiwiIzY3OTE4NiIsIiNmOGFhNGIiLCIjZmY2MTUwIiwiIzU0M2M1MiIpKSsNCiAgZ2VvbV9zZl90ZXh0KGRhdGEgPSBiYXNlX21hcF9hbWJhX2FncnVwICwgYWVzKGxhYmVsPW5hbSksc2l6ZT00LCBjb2xvdXI9JyNlM2UzZTMnKSsNCiAgZ2VvbV9zZihkYXRhID0gZGF0YV9icF9nZW9fYW1iYV9hZ3J1cCwgY29sb3IgPSAiYmxhY2siKSsNCiAgdGhlbWVfbWluaW1hbCgpKw0KICB0aGVtZV92b2lkKCkrDQogIGxhYnMoDQogICAgdGl0bGUgPSAiPHNwYW4gc3R5bGUgPSAnY29sb3I6IzI3MjY0MzsnPiBCYXJyaW9zIFBvcHVsYXJlcyAtIEdyYW4gQnVlbm9zIEFpcmVzIiwNCiAgICBjYXB0aW9uID0gIjxiPkZ1ZW50ZTwvYj46IFJlTmFCYVAiLA0KICAgIHkgPSAiIiwNCiAgICB4ID0gIiINCiAgKSsNCiAgdGhlbWUoDQogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfbWFya2Rvd24oc2l6ZSA9IDIwLCBoanVzdCA9IDAuNSksDQogICAgcGxvdC5jYXB0aW9uPSBlbGVtZW50X21hcmtkb3duKHNpemUgPSAxNSksDQogICAgbGVnZW5kLnBvc2l0aW9uID0gInRvcCIsDQogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLA0KICAgIGxlZ2VuZC5ib3gubWFyZ2luID0gbWFyZ2luKDExLCAxNiwgNiwgNikNCiAgKSsNCiAgZ3VpZGVzKGZpbGw9Z3VpZGVfbGVnZW5kKG5yb3c9MSxieXJvdz1UUlVFKSkNCmBgYA0KDQpUYW1iaWVuIGVzIHBvc2libGUgbW9zdHJhciBsYSBtaXNtYSBpbmZvcm1hY2nDs24gZW4gdW4gbWFwYSBpbnRlcmFjdGl2bywgZWwgY3VhbCBwZXJtaXRlIGFjY2VkZXIgYSBtYXlvciBjYW50aWRhZCBkZSBkYXRvcyBhbCBzZWxlY2Npb25hciBsb3MgYmFycmlvcw0KDQpgYGB7cn0NCiBtYXBhX2ludGVyYWN0aXZvIDwtIGxlYWZsZXQoKSAlPiUNCiAgICAgICAgIGFkZFRpbGVzKCkgJT4lDQogICAgICAgICAjYWRkUHJvdmlkZXJUaWxlcyhwcm92aWRlcj0iQ2FydG9EQiIpICU+JSANCiAgICAgICAgIGFkZFBvbHlnb25zKGRhdGEgPSBkYXRhX2JwX2dlb19hbWJhX2FncnVwLCBwb3B1cCA9IH4gZ2x1ZTo6Z2x1ZSgiPGI+Tm9tYnJlPC9iPjp7bm9tYnJlX2JhcnJpb308YnIvPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8Yj5DYW50aWRhZCBkZSBWaXZpZW5kYXM6PC9iPntjYW50aWRhZF92aXZpZW5kYXNfYXByb3hpbWFkYXN9PGJyLz4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGI+Q2FudGlkYWQgZGUgRmFtaWxpYXM6PC9iPntjYW50aWRhZF9mYW1pbGlhc19hcHJveGltYWRhfTxici8+DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxiPkRlY2FkYSBkZSBDcmVhY2lvbjo8L2I+e2RlY2FkYV9kZV9jcmVhY2lvbn08YnIvPiIpLCBjb2xvciA9ICIjZjU1OTUxIikNCg0KbWFwYV9pbnRlcmFjdGl2bw0KYGBgDQoNClZlYW1vcyBjb21vIGZ1ZSBsYSBldm9sdWNpw7NuIGRlbCBzdXJnaW1pZW50byBkZSBsb3MgYmFycmlvcyBhIG5pdmVsIG5hY2lvbmFsIHBvciBkw6ljYWRhOg0KDQpgYGB7ciBFREEgSUlJLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KDQp0YWJsYV8xIDwtIGRhdGFfYnAgJT4lIA0KICBtdXRhdGUoImRlY2FkYV9hYnIiID0gKHN1YnN0cihkZWNhZGFfZGVfY3JlYWNpb24sIDgsMTEpKSkgJT4lDQogIGdyb3VwX2J5KGRlY2FkYV9hYnIpICU+JSANCiAgc3VtbWFyaXNlKHRvdCA9IG4oKSkgJT4lIA0KICBtdXRhdGUocG9yY2VudGFqZSA9IHJvdW5kKHRvdC9zdW0odG90KSw0KSkgJT4lIA0KICBtdXRhdGUoVG90YWxfQWN1bSA9IGN1bXN1bSh0b3QpKSAlPiUgDQogIG11dGF0ZShQb3JjZW50YWplX0FjdW0gPSBjdW1zdW0ocG9yY2VudGFqZSkpDQoNCmdncGxvdCh0YWJsYV8xLCBhZXMoeCA9IGRlY2FkYV9hYnIsIHkgPSB0b3QpKSsNCiAgZ2VvbV9jb2woZmlsbCA9ICIjMTIyYzkxIikrDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBwZXJjZW50KHBvcmNlbnRhamUpKSwgdmp1c3QgPSAtMC4yNSwgc2l6ZSA9IDQpKw0KICB0aGVtZV9taW5pbWFsKCkrDQogIGxhYnMoDQogICAgdGl0bGUgPSAiPHNwYW4gc3R5bGUgPSAnY29sb3I6IzEyMmM5MTsnPiBFdm9sdWNpw7NuIGRlIEJhcnJpb3MgUG9wdWxhcmVzIC0gQXJnZW50aW5hIiwNCiAgICBzdWJ0aXRsZSA9ICJDcmVhY2nDs24gZGUgQmFycmlvcyBQb3B1bGFyZXMgcG9yIGTDqWNhZGEiLA0KICAgIGNhcHRpb24gPSAiPGI+RnVlbnRlPC9iPjogUmVOYUJhUCIsDQogICAgeCA9ICJEZWNhZGFzIiwNCiAgICB5ID0gIkJhcnJpb3MgUG9wdWxhcmVzIg0KICApKw0KICB0aGVtZSgNCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF9tYXJrZG93bihmYWNlID0gImJvbGQiLCBzaXplID0gMTgpLA0KICAgIHBsb3QuY2FwdGlvbiA9IGVsZW1lbnRfbWFya2Rvd24oc2l6ZSA9IDExKSwNCiAgKQ0KDQoNCmBgYA0KDQpTZSBhcHJlY2lhIGVsIHByaW1lciBkYXRvIHJlbGV2YW50ZS4gRGUgbGEgdG90YWxpZGFkIGRlIGxvcyBiYXJyaW9zIHJlZ2lzdHJhZG9zLCBlbCA1MCUgc3VyZ2nDsyBlbiBsYXMgZMOpY2FkYXMgZGVsIDIwMDAgeSBlbCAyMDEwLiBWZWFtb3MgY29tbyBzZSBkacOzIGVzdGEgc2l0dWFjacOzbiBhZ3JlZ2FuZG8gbG9zIGNhc29zIGRlIEFNQkEuDQoNCmBgYHtyfQ0KdGFibGFfMiA8LSBkYXRhX2JwICU+JSANCiAgbXV0YXRlKCJkZWNhZGFfYWJyIiA9IChzdWJzdHIoZGVjYWRhX2RlX2NyZWFjaW9uLCA4LDExKSkpICU+JQ0KICBncm91cF9ieShkZWNhZGFfYWJyLCB6b25hKSAlPiUgDQogIHN1bW1hcmlzZSh0b3QgPSBuKCkpICU+JSANCiAgbXV0YXRlKHBvcmNlbnRhamUgPSByb3VuZCh0b3Qvc3VtKHRvdCksNCkpICU+JSANCiAgbXV0YXRlKFRvdGFsX0FjdW0gPSBjdW1zdW0odG90KSkgJT4lIA0KICBtdXRhdGUoUG9yY2VudGFqZV9BY3VtID0gY3Vtc3VtKHBvcmNlbnRhamUpKQ0KDQpnZ3Bsb3QodGFibGFfMiwgYWVzKHggPSBkZWNhZGFfYWJyLCB5ID0gdG90LCBmaWxsID0gem9uYSkpKw0KICBnZW9tX2NvbChwb3NpdGlvbiA9ICJkb2RnZSIpKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGVyY2VudChwb3JjZW50YWplKSksIHZqdXN0ID0gLTAuNSwgY2hlY2tfb3ZlcmxhcCA9IFRSVUUsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAuOSksIHNpemUgPSAzKSsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiI2Y1NjAzOCIsIiMxMjJjOTEiKSkrDQogIHRoZW1lX21pbmltYWwoKSsNCiAgbGFicygNCiAgICB0aXRsZSA9ICI8c3BhbiBzdHlsZSA9ICdjb2xvcjojMjcyNjQzOyc+IEV2b2x1Y2nDs24gZGUgQmFycmlvcyBQb3B1bGFyZXM6IDxzcGFuIHN0eWxlID0gJ2NvbG9yOiMxMjJjOTE7Jz4gQXJnZW50aW5hIChTaW4gR0JBKSAtIDxzcGFuIHN0eWxlID0gJ2NvbG9yOiNmNTYwMzg7Jz5HQkEiLA0KICAgIHN1YnRpdGxlID0gIkNyZWFjacOzbiBkZSBCYXJyaW9zIFBvcHVsYXJlcyBwb3IgZMOpY2FkYSIsDQogICAgY2FwdGlvbiA9ICI8Yj5GdWVudGU8L2I+OiBSZU5hQmFQIiwNCiAgICB4ID0gIkRlY2FkYXMiLA0KICAgIHkgPSAiQmFycmlvcyBQb3B1bGFyZXMiDQogICkrDQogIHRoZW1lKA0KICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwNCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF9tYXJrZG93bihmYWNlID0gImJvbGQiLCBzaXplID0gMTUpLA0KICAgIHBsb3QuY2FwdGlvbiA9IGVsZW1lbnRfbWFya2Rvd24oc2l6ZSA9IDEyKSwNCiAgKQ0KDQoNCg0KDQpgYGANCg0KYGBge3J9DQoNCg0KdGFibGFfMiA8LSBkYXRhX2JwICU+JSANCiAgbXV0YXRlKCJkZWNhZGFfYWJyIiA9IChzdWJzdHIoZGVjYWRhX2RlX2NyZWFjaW9uLCA4LDExKSkpICU+JQ0KICBncm91cF9ieShkZWNhZGFfYWJyLCB6b25hKSAlPiUgDQogIHN1bW1hcmlzZSh0b3QgPSBuKCkpICU+JSANCiAgbXV0YXRlKHBvcmNlbnRhamUgPSByb3VuZCh0b3Qvc3VtKHRvdCksNCkpICU+JSANCiAgbXV0YXRlKFBvcmNlbnRhamVfQWN1bSA9IGN1bXN1bShwb3JjZW50YWplKSkgDQoNCnRhYmxhXzIkdG90YWxfYWN1bSA8LSBhdmUodGFibGFfMiR0b3QsIHRhYmxhXzIkem9uYSwgRlVOPWN1bXN1bSkNCg0KZ2dwbG90KHRhYmxhXzIsIGFlcyh4ID0gZGVjYWRhX2FiciwgeSA9IHRvdGFsX2FjdW0gLCBncm91cCA9IHpvbmEgLCBjb2xvdXIgPSB6b25hKSkrDQogIGdlb21fbGluZSgpKw0KICBnZW9tX3BvaW50KCkrDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiI2Y1NjAzOCIsIiMxMjJjOTEiKSkrDQogICNnZW9tX3RleHQoYWVzKGxhYmVsID0gcGVyY2VudChwb3JjZW50YWplKSksIHZqdXN0ID0gLTAuMjUpKw0KICB0aGVtZV9taW5pbWFsKCkrDQogIGxhYnMoDQogICAgdGl0bGUgPSAiPHNwYW4gc3R5bGUgPSAnY29sb3I6IzEyMmM5MTsnPiBFdm9sdWNpw7NuIGRlIEJhcnJpb3MgUG9wdWxhcmVzIC0gQXJnZW50aW5hIiwNCiAgICBzdWJ0aXRsZSA9ICJDcmVhY2nDs24gZGUgQmFycmlvcyBQb3B1bGFyZXMgcG9yIGTDqWNhZGEiLA0KICAgIGNhcHRpb24gPSAiPGI+RnVlbnRlPC9iPjogUmVOYUJhUCIsDQogICAgeCA9ICJEZWNhZGFzIiwNCiAgICB5ID0gIkJhcnJpb3MgUG9wdWxhcmVzIg0KICApKw0KICB0aGVtZSgNCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF9tYXJrZG93bihmYWNlID0gImJvbGQiLCBzaXplID0gMTgpLA0KICAgIHBsb3QuY2FwdGlvbiA9IGVsZW1lbnRfbWFya2Rvd24oc2l6ZSA9IDEyKSwNCiAgKQ0KDQoNCmBgYA0KDQpMb3MgY2Fzb3MgZGUgQU1CQSB0YW1iacOpbiBldmlkZW5jaWFuIHVuYSBjb25zb2xpZGFkIGV4cGFuc2nDs24gZW4gbGFzIGTDqWNhZGFzIG1lbmNpb25hZGFzLiBSZXN1bHRhIHJlbGV2YW50ZSBpbmRhZ2FyIHNvYnJlIGVsIHRpcG8gZGUgYmFycmlvcyBnZW5lcmFkb3MgZW4gZXN0YSBldGFwYSBqdW50byBjb24gbGFzIGNhcmFjdGVyw61zdGljYXMgZGUgZXN0YSBleHBhbnNpw7NuIGVuIHTDqXJtaW5vcyBnZW9ncsOhZmljb3MuDQoNCmBgYHtyLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9OX0NCg0KdGFibGFfYnBfZGVwIDwtIGRhdGFfYnBfYW1iYSAlPiUgDQogIGdyb3VwX2J5KGRlcGFydGFtZW50bykgJT4lIA0KICBzdW1tYXJpc2UoVG90YWwgPSBuKCkpICU+JSANCiAgcmVuYW1lKCJuYW0iID0gImRlcGFydGFtZW50byIpDQoNCmJhc2VfbWFwX2FtYmFfYWdydXBfdG90YWxicCA8LSBsZWZ0X2pvaW4oYmFzZV9tYXBfYW1iYV9hZ3J1cCx0YWJsYV9icF9kZXApDQogIA0KZ2dwbG90KCkrDQogIGdlb21fc2YoZGF0YSA9IGJhc2VfbWFwX2FtYmFfYWdydXBfdG90YWxicCwgY29sb3I9J2JsYWNrJywgYWVzKGZpbGwgPSBUb3RhbCksICBzaXplID0gMC4xKSsNCiAgZ2VvbV9zZl90ZXh0KGRhdGEgPSBiYXNlX21hcF9hbWJhX2FncnVwX3RvdGFsYnAgLCBhZXMobGFiZWw9bmFtKSxzaXplPTMsIGFscGhhPTAuOCwgY29sb3VyPSdibGFjaycpKw0KICB0aGVtZV92b2lkKCkrDQogIGxhYnMoDQogICAgdGl0bGUgPSAiPHNwYW4gc3R5bGUgPSAnY29sb3I6IzI3MjY0MzsnPiBCYXJyaW9zIFBvcHVsYXJlcyAtIEdyYW4gQnVlbm9zIEFpcmVzIiwNCiAgICBjYXB0aW9uID0gIjxiPkZ1ZW50ZTwvYj46IFJlTmFCYVAiLA0KICAgIHkgPSAiIiwNCiAgICB4ID0gIiINCiAgKSsNCiAgc2NhbGVfZmlsbF9kaXN0aWxsZXIoZGlyZWN0aW9uID0gMSkrDQogIHRoZW1lKA0KICAgIHBsb3QuY2FwdGlvbj0gZWxlbWVudF9tYXJrZG93bihzaXplID0gMTUpLA0KICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X21hcmtkb3duKHNpemUgPSAyMCwgaGp1c3QgPSAwLjUpLA0KICApDQoNCg0KDQpgYGANCg0KVGFsIGN1YWwgc2Ugb2JzZXJ2YSwgTGEgTWF0YW56YSB5IE1vcmVubyBwYXJlY2VuIHNlciBsb3MgcGFydGlkb3MgcXVlIGNvbnRpZW5lbiBsYSBtYXlvciBjYW50aWRhZCBkZSBCUC4gVmVhbW9zIGRlIHF1ZSBtb2RvIHBvZGVtb3MgYW5hbGl6YXIgZXN0byBlbiBmdW5jacOzbiBkZWwgdGllbXBvIHRyYW5zY3VycmlkbyB5IGxhIGFudGlnw7xlZGFkLiBQYXJhIGVsbG8sIHZhbW9zIGEgZmlsdHJhciBudWVzdHJhIGJhc2UgZGUgQlAgY29uc2VydmFuZG8gc29sbyBhcXVlbGxvcyBjdXlhIGNyZWFjacOzbiBjb3JyZXNwb25kZSBhIGxhcyB1bHRpbWFzIHRyZXMgZMOpY2FkYXMuDQoNCmBgYHtyLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9OX0NCmdncGxvdCgpKw0KICBnZW9tX3NmKGRhdGEgPSBiYXNlX21hcF9hbWJhX2FncnVwLCBjb2xvcj0nYmxhY2snLCBhZXMoZmlsbCA9IHpvbmEpLCAgc2l6ZSA9IDAuMSkrDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCIjMDcyNDQ4IiwgIiM1NGQyZDIiLCIjZmZjYjAwIiwiIzY3OTE4NiIsIiNmOGFhNGIiLCIjZmY2MTUwIiwiIzU0M2M1MiIpKSsNCiAgZ2VvbV9zZl90ZXh0KGRhdGEgPSBiYXNlX21hcF9hbWJhX2FncnVwICwgYWVzKGxhYmVsPW5hbSksc2l6ZT00LCBhbHBoYT0wLjksIGNvbG91cj0nI2UzZTNlMycpKw0KICBnZW9tX3NmKGRhdGEgPSBkYXRhX2JwX2dlb19hbWJhX2FncnVwICU+JSANCiAgICAgICAgICAgIGZpbHRlcihkZWNhZGFfZGVfY3JlYWNpb24gJWluJSBjKCJEw6ljYWRhIDIwMDAiLCJEw6ljYWRhIDIwMTAiLCJEw6ljYWRhIDIwMjAiKSksIGNvbG9yID0gImJsYWNrIikrDQogIHRoZW1lX21pbmltYWwoKSsNCiAgdGhlbWVfdm9pZCgpKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIjxzcGFuIHN0eWxlID0gJ2NvbG9yOiMxMjJjOTE7Jz4gQmFycmlvcyBQb3B1bGFyZXMgLSBHcmFuIEJ1ZW5vcyBBaXJlcyAoMjAwMCAtIDIwMjApIiwNCiAgICBjYXB0aW9uID0gIjxiPkZ1ZW50ZTwvYj46IFJlTmFCYVAiLA0KICAgIHkgPSAiIiwNCiAgICB4ID0gIiINCiAgKSsNCiAgdGhlbWUoDQogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfbWFya2Rvd24oc2l6ZSA9IDIwLCBoanVzdCA9IDAuNSksDQogICAgcGxvdC5jYXB0aW9uPSBlbGVtZW50X21hcmtkb3duKHNpemUgPSAxNSksDQogICAgbGVnZW5kLnBvc2l0aW9uID0gInRvcCIsDQogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLA0KICAgIGxlZ2VuZC5ib3gubWFyZ2luID0gbWFyZ2luKDExLCAxNiwgNiwgNikNCiAgKSsNCiAgZ3VpZGVzKGZpbGw9Z3VpZGVfbGVnZW5kKG5yb3c9MSxieXJvdz1UUlVFKSkNCg0KYGBgDQoNClZlYW1vcyBjb21vIHNlIGVmZWN0dWFyb24gbG9zIHN1cmdpbWllbnRvcyBwb3IgZMOpY2FkYSBhIHBhcnRpciBkZSB1biBtYXBhIGFuaW1hZG8gcXVlIGdyYWZpcXVlIGxvcyBjYW1iaW9zIHBvciBkw6ljYWRhLg0KDQpgYGB7ciBtYXBfYW5pbSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSxmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9OX0NCm1hcGFfYW5pbWFkbyA8LSBnZ3Bsb3QoKSsNCiAgZ2VvbV9zZihkYXRhID0gYmFzZV9tYXBfYW1iYV9hZ3J1cCkrDQogIGdlb21fc2ZfdGV4dChkYXRhID0gYmFzZV9tYXBfYW1iYV9hZ3J1cCAsIGFlcyhsYWJlbD1uYW0pLHNpemU9MywgYWxwaGE9MC44LCBjb2xvdXI9J2JsYWNrJykrDQogIGdlb21fc2YoZGF0YSA9IGRhdGFfYnBfZ2VvX2FtYmFfYWdydXAsaW5oZXJpdC5hZXM9RkFMU0UsIGNvbG9yID0gInJlZCIpKw0KICBzY2FsZV9maWxsX2Rpc3RpbGxlcihwYWxldHRlID0gIlNwZWN0cmFsIikrDQogIGxhYnModGl0bGU9IkV2b2x1Y2nDs24gZGUgY3JlYWNpw7NuIGRlIEJhcnJpb3MgUG9wdWxhcmVzIiwNCiAgICAgICBzdWJ0aXRsZSA9ICJHQkEgfCB7Y2xvc2VzdF9zdGF0ZX0iLA0KICAgIGNhcHRpb24gPSAiPGI+RnVlbnRlPC9iPjogUmVOYUJhUCIsDQogICAgeSA9ICIiLA0KICAgIHggPSAiIikrDQogIHRoZW1lX3ZvaWQoKSsNCiAgICB0aGVtZSgNCiAgICBwbG90LmNhcHRpb249IGVsZW1lbnRfbWFya2Rvd24oc2l6ZSA9IDE1KQ0KICApKw0KICB0cmFuc2l0aW9uX3N0YXRlcyhkZWNhZGFfZGVfY3JlYWNpb24sdHJhbnNpdGlvbl9sZW5ndGggPSAzLCBzdGF0ZV9sZW5ndGggPSAyKQ0KDQphbmltX3NhdmUoIm1hcC5naWYiLCBtYXBhX2FuaW1hZG8pDQpgYGANCg0KIVtdKG1hcC5naWYpDQoNClB1ZWRlIGFwcmVjaWFyc2UgcXVlIGxhcyB6b25hcyBkZSBtYXlvciBkaXN0YW5jaWEgY29uIHJlc3BlY3RvIGEgQ0FCQSBmdWVyb24gZW4gZG9uZGUgc2UgZ2VuZXJhcm9uIHVuYSBtYXlvciBjYW50aWRhZCBkZSBCUCBkdXJhbnRlIGxvcyBhw7FvcyAyMDAwIHkgMjAxMC4NCg0KYGBge3IsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD05fQ0KDQp0YWJsYV8zIDwtIGRhdGFfYnBfYW1iYSAlPiUgDQogIG11dGF0ZSgiZGVjYWRhX2FiciIgPSAoc3Vic3RyKGRlY2FkYV9kZV9jcmVhY2lvbiwgOCwxMSkpKSAlPiUNCiAgZ3JvdXBfYnkoZGVjYWRhX2FiciwgY2xhc2lmaWNhY2lvbl9iYXJyaW8pICU+JSANCiAgc3VtbWFyaXNlKHRvdCA9IG4oKSkgJT4lIA0KICBtdXRhdGUocG9yY2VudGFqZSA9IHJvdW5kKHRvdC9zdW0odG90KSw0KSkNCg0KDQpnZ3Bsb3QodGFibGFfMywgYWVzKHggPSBkZWNhZGFfYWJyLCB5ID0gdG90LCBmaWxsID0gY2xhc2lmaWNhY2lvbl9iYXJyaW8pKSsNCiAgZ2VvbV9jb2wocG9zaXRpb24gPSAiZmlsbCIpKw0KICAjZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHBlcmNlbnQocG9yY2VudGFqZSkpLCB2anVzdCA9IC0wLjUsIGNoZWNrX292ZXJsYXAgPSBUUlVFLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gLjkpLCBzaXplID0gMykrDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCIjZjliNGFiIiwgIiNmZGViZDMiLCIjNzc4NDkwIiwiIzY3OTE4NiIpKSsNCiAgdGhlbWVfbWluaW1hbCgpKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIjxzcGFuIHN0eWxlID0gJ2NvbG9yOiMyNzI2NDM7Jz4gRXZvbHVjacOzbiBkZSBCYXJyaW9zIFBvcHVsYXJlczogPHNwYW4gc3R5bGUgPSAnY29sb3I6I2Y1NjAzODsnPkdCQSIsDQogICAgc3VidGl0bGUgPSAiRXZvbHVjacOzbiBkZSBsYSBjbGFzaWZpY2FjacOzbiIsDQogICAgY2FwdGlvbiA9ICI8Yj5GdWVudGU8L2I+OiBSZU5hQmFQIiwNCiAgICB4ID0gIkRlY2FkYXMiLA0KICAgIHkgPSAiQmFycmlvcyBQb3B1bGFyZXMiDQogICkrDQogIHRoZW1lKA0KICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLA0KICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X21hcmtkb3duKGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxNSksDQogICAgcGxvdC5jYXB0aW9uID0gZWxlbWVudF9tYXJrZG93bihzaXplID0gMTIpLA0KICApDQoNCg0KI1ZFUg0KDQpgYGANCg0KU2Ugb2JzZXJ2YSBxdWUgZW4gbGFzIMO6bHRpbWFzIGTDqWNhZGFzIHByZWRvbWluw7MgZWwgYXNlbnRhbWllbnRvIHBvciBzb2JyZSBsYSB2aWxsYS4gRW4gbGEgcHLDs3hpbWEgc2VjY2nDs24gc2UgYWhvbmRhcsOhIGFjZXJjYSBkZSBlbCB0aXBvIGRlIGFjY2VzaWJpbGlkYWQgeSBkaXN0YW5jaWFzIGEgc2VydmljaW9zIGVzZW5jaWFsZXMgcXVlIHNlIG1hbmlmaWVzdGFuIGVuIGFsZ3Vub3MgZGUgZXN0b3MgdGlwb3MgZGUgYmFycmlvcy4NCg0KIyMgQWNjZXNpYmlsaWRhZCBlIEludGVncmFjacOzbiAtIERpc3RhbmNpYXMgeSBUaWVtcG9zIGRlIHZpYWplIChJc8OzY3JvbmFzIHkgUnV0ZW9zKQ0KDQpFbiBmdW5jacOzbiBkZSBsb3Mgb2JqZXRpdm9zIHBsYW50ZWFkb3MsIGNvcnJlc3BvbmRlIGV4YW1pbmFyIGxhIHNpdHVhY2nDs24gZGUgbG9zIEJQIGJham8gbGEgaWRlYSBjb21wYXJhdGl2YSBkZSBldmFsdWFyIGVsIGdyYWRvIGRlIGFjY2VzaWJpbGlkYWQgcXVlIHByZXNlbnRhbiBsb3MgYmFycmlvcyBkZSBtYXlvciBhbnRpZ8O8ZWRhZCBjb24gcmVzcGVjdG8gYSBhcXVlbGxvcyBjdXlhIGNyZWFjacOzbiBlcyBtw6FzIHJlY2llbnRlLiBQYXJhIGluZGFnYXIgZXN0YSBjdWVzdGnDs24gdmFtb3MgYSB0b21hciBjb21vIHJlZmVyZW5jaWEsIGVuIHByaW1lciBsdWdhciBlbCBlc2NlbmFyaW8gZGUgVmlsbGEgVHJhbnF1aWxhIChBdmVsbGFuZWRhIC0gRGVjYWRhIGRlIDE5NTApDQoNCkVuIGVzdGEgc2VjY2nDs24gdmFtb3MgYSB1dGlsaXphciBsb3MgcmVjdXJzb3MgZGUgT1NNLiBFbiBwcmltZXIgdMOpcm1pbm8gdmFtb3MgYSBtYXBlYXIgbnVlc3RyYSByZWdpw7NuIGRlIGVzdHVkaW8gY29uc3RydXllbmRvIHN1IGJib3gNCg0KIyMjIENhc28gVmlsbGEgVHJhbnF1aWxhIChBdmVsbGFuZWRhIC0gRGVjYWRhIGRlIDE5NTApDQoNCmBgYHtyfQ0KDQojaHR0cHM6Ly9yeWFucGVlay5vcmcvMjAxNi0xMC0xOS1hbmltYXRlZC1naWZfbWFwc19pbl9yLw0KDQpiYm94X2FtYmEgPC0gc3RfYmJveChiYXNlX21hcF9hbWJhX2FncnVwICU+JSANCiAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKG5hbSA9PSAiQXZlbGxhbmVkYSIpKQ0KYmJveF9hbWJhIDwtIGFzLm51bWVyaWMoYmJveF9hbWJhKQ0KbWFwYV9hbWJhIDwtIGdldF9zdGFkaWFtYXAoYmJveCA9IGJib3hfYW1iYSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHR5cGUgPSAiYWxpZGFkZV9zbW9vdGhfZGFyayIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICB6b29tID0gMTMpDQoNCmBgYA0KDQpgYGB7cixmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9OX0NCmdnbWFwKG1hcGFfYW1iYSkrDQogIGdlb21fc2YoZGF0YSA9IGRhdGFfYnBfZ2VvICU+JSANCiAgICAgICAgICAgIGZpbHRlcihkZXBhcnRhbWVudG8gPT0gIkF2ZWxsYW5lZGEiKSxpbmhlcml0LmFlcz1GQUxTRSkrDQogIHRoZW1lX3ZvaWQoKQ0KDQoNCmBgYA0KVW5hIGN1ZXN0acOzbiBtZXRvZG9sw7NnaWNhIHF1ZSBkZXNjdWJyw60gZW4gZWwgcHJvY2VzbyBlcyBxdWUgQXZlbGxhbmVkYSBwcmVzZW50YSB1biBjYXNvIHBhcnRpY3VsYXIgZGFkbyBxdWUgZXMgdW4gcGFydGlkbyBxdWUgaW5jbHV5ZSB1biBiYXJyaW8gY29uIGVsIG1pc21vIG5vbWJyZSwgY29uIGxvIGN1YWwgcmVzdWx0YSBmdW5kYW1lbnRhbCBhY2xhcmFyIGVzdGEgY3Vlc3Rpw7NuIGRlbnRybyBkZSBsYSBmdW5jacOzbiBnZXRiYiBwYXJhIG9idGVuZXIgZWwgcG9sw61nb25vIGRlbCBwYXJ0aWRvIHkgbm8gZGVsIGJhcnJpby4gDQoNCmBgYHtyfQ0KI0Rlc2NhcmdhIGRlIGhvc3BpdGFsZXMgLSBlc2N1ZWxhcyAtIHRyYW5zcG9ydGUNCg0KcG9seWdvbl9hdmVsbGFuZWRhIDwtIGdldGJiKCJQYXJ0aWRvIGRlIEF2ZWxsYW5lZGEsIEJ1ZW5vcyBBaXJlcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9ybWF0X291dCA9ICJzZl9wb2x5Z29uIikNCg0KaG9zcGl0YWxlc19hdmVsbGFuZWRhIDwtIG9wcShiYm94X2FtYmEpDQpob3NwaXRhbGVzX2F2ZWxsYW5lZGEgPC0gYWRkX29zbV9mZWF0dXJlKGhvc3BpdGFsZXNfYXZlbGxhbmVkYSwga2V5ID0gImFtZW5pdHkiLCB2YWx1ZSA9IGMoImNsaW5pYyIsImhvc3BpdGFsIikpDQpob3NwaXRhbGVzX2F2ZWxsYW5lZGEgPC0gb3NtZGF0YV9zZihob3NwaXRhbGVzX2F2ZWxsYW5lZGEpDQpob3NwaXRhbGVzX2F2ZWxsYW5lZGEgPC0gaG9zcGl0YWxlc19hdmVsbGFuZWRhJG9zbV9wb2ludHMNCg0KZXNjdWVsYXNfYXZlbGxhbmVkYSA8LSBvcHEoYmJveF9hbWJhKQ0KZXNjdWVsYXNfYXZlbGxhbmVkYSA8LSBhZGRfb3NtX2ZlYXR1cmUoZXNjdWVsYXNfYXZlbGxhbmVkYSwga2V5ID0gImFtZW5pdHkiLCB2YWx1ZSA9IGMoInNjaG9vbCIsInVuaXZlcnNpdHkiLCJjb2xsZWdlIikpDQplc2N1ZWxhc19hdmVsbGFuZWRhIDwtIG9zbWRhdGFfc2YoZXNjdWVsYXNfYXZlbGxhbmVkYSkNCmVzY3VlbGFzX2F2ZWxsYW5lZGEgPC0gZXNjdWVsYXNfYXZlbGxhbmVkYSRvc21fcG9pbnRzDQoNCnRyYW5zcG9ydGVfYXZlbGxhbmVkYSA8LSBvcHEoYmJveF9hbWJhKQ0KdHJhbnNwb3J0ZV9hdmVsbGFuZWRhIDwtIGFkZF9vc21fZmVhdHVyZSh0cmFuc3BvcnRlX2F2ZWxsYW5lZGEsIGtleSA9ICJwdWJsaWNfdHJhbnNwb3J0IiwgdmFsdWUgPSBjKCJzdG9wX3Bvc2l0aW9uIiwiCXBsYXRmb3JtIiwic3RhdGlvbiIsInN0b3BfYXJlYSIpKQ0KdHJhbnNwb3J0ZV9hdmVsbGFuZWRhIDwtIG9zbWRhdGFfc2YodHJhbnNwb3J0ZV9hdmVsbGFuZWRhKQ0KdHJhbnNwb3J0ZV9hdmVsbGFuZWRhIDwtIHRyYW5zcG9ydGVfYXZlbGxhbmVkYSRvc21fcG9pbnRzDQoNCg0KDQpob3NwaXRhbGVzX2F2ZWxsYW5lZGEgPC0gc3RfaW50ZXJzZWN0aW9uKGhvc3BpdGFsZXNfYXZlbGxhbmVkYSwgcG9seWdvbl9hdmVsbGFuZWRhKSAlPiUgDQogIG11dGF0ZSgidGlwbyIgPSAiaG9zcGl0YWxlcyIpICU+JSANCiAgc2VsZWN0KG5hbWUsIHRpcG8sIGdlb21ldHJ5KSAlPiUgDQogIGZpbHRlcighaXMubmEobmFtZSkpDQplc2N1ZWxhc19hdmVsbGFuZWRhIDwtIHN0X2ludGVyc2VjdGlvbihlc2N1ZWxhc19hdmVsbGFuZWRhLCBwb2x5Z29uX2F2ZWxsYW5lZGEpJT4lIA0KICBtdXRhdGUoInRpcG8iID0gImVzY3VlbGFzIiklPiUgDQogIHNlbGVjdChuYW1lLCB0aXBvLCBnZW9tZXRyeSkgJT4lIA0KICBmaWx0ZXIoIWlzLm5hKG5hbWUpKQ0KdHJhbnNwb3J0ZV9hdmVsbGFuZWRhIDwtIHN0X2ludGVyc2VjdGlvbih0cmFuc3BvcnRlX2F2ZWxsYW5lZGEsIHBvbHlnb25fYXZlbGxhbmVkYSkgJT4lIA0KICBtdXRhdGUoInRpcG8iID0gInRyYW5zcG9ydGUiKSU+JSANCiAgc2VsZWN0KG5hbWUsIHRpcG8sIGdlb21ldHJ5KSAlPiUgDQogIGZpbHRlcighaXMubmEobmFtZSkpDQoNCmx1Z2FyZXNfYXZlbGxhbmVkYSA8LSByYmluZChob3NwaXRhbGVzX2F2ZWxsYW5lZGEsZXNjdWVsYXNfYXZlbGxhbmVkYSx0cmFuc3BvcnRlX2F2ZWxsYW5lZGEpDQoNCiNEZWZpbmljacOzbiBkZSBjZW50cm9pZGUNCg0KZGF0YV9icF9nZW9fYW1iYV9jZW50cm9pZGUgPC0gZGF0YV9icF9nZW9fYW1iYV9hZ3J1cCAlPiUgDQogIGZpbHRlcihkZXBhcnRhbWVudG8gPT0gIkF2ZWxsYW5lZGEiLA0KICAgICAgICAgbm9tYnJlX2JhcnJpbyA9PSAiVmlsbGEgVHJhbnF1aWxhIikgJT4lIA0KICBzdF9jZW50cm9pZCgpDQoNCiNEZWZpbmljacOzbiBkZSBpc29jcm9uYQ0KDQppc29jcm9uYV92dCA8LSBvc3JtSXNvY2hyb25lKGxvYyA9IGRhdGFfYnBfZ2VvX2FtYmFfY2VudHJvaWRlJGdlb21ldHJ5LA0KICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gc2VxKGZyb209MCx0bz0yMCxieT01KSwNCiAgICAgICAgICAgICAgICAgICAgIHJlcyA9IDM1LA0KICAgICAgICAgICAgICAgICAgICAgb3NybS5wcm9maWxlID0gImZvb3QiKQ0KDQpgYGANCg0KYGBge3J9DQoNCmxlYWZsZXQoaXNvY3JvbmFfdnQpICU+JSANCiAgYWRkVGlsZXMoZ3JvdXAgPSAiT1NNIChkZWZhdWx0KSIpICU+JQ0KICBhZGRQcm92aWRlclRpbGVzKHByb3ZpZGVycyRDYXJ0b0RCLlBvc2l0cm9uLCBncm91cCA9ICJQb3NpdHJvbiAobWluaW1hbCkiKSAlPiUNCiAgYWRkUHJvdmlkZXJUaWxlcyhwcm92aWRlcnMkQ2FydG9EQi5EYXJrTWF0dGVyLCBncm91cCA9ICJEYXJrTWF0dGVyIikgJT4lDQogIGFkZFBvbHlnb25zKGZpbGxDb2xvciA9IH5jb2xvckJpbigiWWxPclJkIiwgZG9tYWluID0gaXNvY3JvbmFfdnQkaXNvbWF4KShpc29tYXgpLA0KICBjb2xvciA9IE5BLA0KICBmaWxsT3BhY2l0eSA9IDAuNSwgZ3JvdXAgPSAiaXNvY3JvbmEiKSU+JQ0KICBhZGRQb2x5Z29ucyhkYXRhID0gZGF0YV9icF9nZW9fYW1iYV9hZ3J1cCAlPiUgDQogICAgICAgICAgICBmaWx0ZXIoZGVwYXJ0YW1lbnRvID09ICJBdmVsbGFuZWRhIikscG9wdXAgPSB+IGdsdWU6OmdsdWUoIjxiPk5vbWJyZTwvYj46e25vbWJyZV9iYXJyaW99PGJyLz4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGI+Q2FudGlkYWQgZGUgVml2aWVuZGFzOjwvYj57Y2FudGlkYWRfdml2aWVuZGFzX2Fwcm94aW1hZGFzfTxici8+DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxiPkNhbnRpZGFkIGRlIEZhbWlsaWFzOjwvYj57Y2FudGlkYWRfZmFtaWxpYXNfYXByb3hpbWFkYX08YnIvPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8Yj5EZWNhZGEgZGUgQ3JlYWNpw7NuOjwvYj57ZGVjYWRhX2RlX2NyZWFjaW9ufTxici8+IiksZ3JvdXAgPSAiQmFycmlvcyBQb3B1bGFyZXMiLCBjb2xvciA9ICIjZjU1OTUxIikgJT4lIA0KICBhZGRDaXJjbGVNYXJrZXJzKGRhdGEgPSBkYXRhX2JwX2dlb19hbWJhX2NlbnRyb2lkZSwgY29sb3IgPSAiYmxhY2siLCBncm91cCA9ICJWaWxsYSBUcmFucXVpbGEiKSAlPiUgDQogIGFkZENpcmNsZU1hcmtlcnMoZGF0YSA9IGx1Z2FyZXNfYXZlbGxhbmVkYSAlPiUgDQogICAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcih0aXBvID09ICJob3NwaXRhbGVzIiksIHBvcHVwID0gfiBnbHVlOjpnbHVlKCI8Yj5Ob21icmU8L2I+OntuYW1lfTxici8+DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGI+dGlwbzo8L2I+e3RpcG99PGJyLz4iKSwgZ3JvdXAgPSAiaG9zcGl0YWxlcyIsIGNvbG9yID0gIiMwMDFmN2QiKSAlPiUNCiAgYWRkQ2lyY2xlTWFya2VycyhkYXRhID0gbHVnYXJlc19hdmVsbGFuZWRhJT4lIA0KICAgICAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXIodGlwbyA9PSAiZXNjdWVsYXMiKSwgcG9wdXAgPSB+IGdsdWU6OmdsdWUoIjxiPk5vbWJyZTwvYj46e25hbWV9PGJyLz4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8Yj50aXBvOjwvYj57dGlwb308YnIvPiIpLCBncm91cCA9ICJlc2N1ZWxhcyIsIGNvbG9yID0gIiM1OGIzNjgiKSAlPiUNCiAgYWRkQ2lyY2xlTWFya2VycyhkYXRhID0gbHVnYXJlc19hdmVsbGFuZWRhJT4lIA0KICAgICAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXIodGlwbyA9PSAidHJhbnNwb3J0ZSIpLCBwb3B1cCA9IH4gZ2x1ZTo6Z2x1ZSgiPGI+Tm9tYnJlPC9iPjp7bmFtZX08YnIvPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxiPnRpcG86PC9iPnt0aXBvfTxici8+IiksIGdyb3VwID0gInRyYW5zcG9ydGUiLCBjb2xvciA9ICIjZGFkODczIikgJT4lIA0KICANCiAgICBhZGRMYXllcnNDb250cm9sKA0KICAgIGJhc2VHcm91cHMgPSBjKA0KICAgICAgIk9TTSAoZGVmYXVsdCkiLA0KICAgICAgIlBvc2l0cm9uIChtaW5pbWFsKSIsDQogICAgICAiRGFya01hdHRlciINCiAgICApLA0KICAgIG92ZXJsYXlHcm91cHMgPSBjKCJWaWxsYSBUcmFucXVpbGEiLCAiQmFycmlvcyBQb3B1bGFyZXMiLCJpc29jcm9uYSIsICJlc2N1ZWxhcyIsInRyYW5zcG9ydGUiLCJob3NwaXRhbGVzIiksDQogICAgb3B0aW9ucyA9IGxheWVyc0NvbnRyb2xPcHRpb25zKGNvbGxhcHNlZCA9IEZBTFNFKQ0KICApDQoNCmBgYA0KDQpkYWRvIHF1ZSBsYSBkZXNjYXJnYSBubyBhcG9ydGEgbG9zIG5vbWJyZXMgZGUgbG9zIHNpdGlvcywgaW50ZW50YXJlbW9zIHRyYWJhamFyIGNvbiBlbCBjYXTDoWxvZ28gZGUgaG9zcGl0YWxlcyBkZSBcIzxodHRwczovL2NhdGFsb2dvLmRhdG9zLmdiYS5nb2IuYXIvZGF0YXNldC9lc3RhYmxlY2ltaWVudG9zLXNhbHVkL2FyY2hpdm8vNzE2Yzg0YmEtNmVkNy00OTBiLTgxZjctZTNlOTdkNzQ2ZDQ0Pg0KDQpgYGB7cn0NCg0KaG9zcF9hdmVfZGEgPC0gcmVhZF9zZigiZGF0YS9ob3Nww610YWxlcy9Fc3RhYmxlY2ltaWVudG9zX3NhbHVkX3B1YmxpY29zX2FsdGFfYWwyMDIyMDcyMS5nZW9qc29uIiwgc3RyaW5nc0FzRmFjdG9ycyA9IFRSVUUpDQpob3NwX2F2ZV9kYSA8LSBob3NwX2F2ZV9kYSAlPiUgDQogIGZpbHRlcihuZGUgPT0gIkFWRUxMQU5FREEiKQ0KDQpob3NwX2F2ZV9kYSA8LSBzdF9pbnRlcnNlY3Rpb24oaG9zcF9hdmVfZGEsIHBvbHlnb25fYXZlbGxhbmVkYSkNCg0KDQpgYGANCg0KYGBge3J9DQoNCmRhdGFfdmlsbGFfdHJhbnF1aWxhIDwtIGRhdGFfYnBfZ2VvX2FtYmFfY2VudHJvaWRlICU+JSANCiAgc2VsZWN0KG5vbWJyZV9iYXJyaW8sZ2VvbWV0cnkpICU+JSANCiAgbXV0YXRlKCJuZGUiID0gIkFWRUxMQU5FREEiKSANCmRhdGFfdmlsbGFfdHJhbnF1aWxhIDwtIGNiaW5kKGRhdGFfdmlsbGFfdHJhbnF1aWxhLCBzdF9jb29yZGluYXRlcyhkYXRhX3ZpbGxhX3RyYW5xdWlsYSkpICU+JQ0KICAgICAgICAgICAgICAgICAgICAgIHN0X3NldF9nZW9tZXRyeShOVUxMKSAlPiUgDQogICAgICAgICAgICAgICAgICAgICAgcmVuYW1lKExPTl9PUklHRU49WCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTEFUX09SSUdFTj1ZKQ0KaG9zcCA8LSBob3NwX2F2ZV9kYSAlPiUgDQogIHJlbmFtZShMT05fREVTVElOTz1sb25nLA0KICAgICAgICAgTEFUX0RFU1RJTk89bGF0KSAlPiUgDQogIHNlbGVjdChMQVRfREVTVElOTyxMT05fREVTVElOTyxmbmEsbmRlKSAlPiUgDQogIGxlZnRfam9pbihkYXRhX3ZpbGxhX3RyYW5xdWlsYSkNCg0KYGBgDQoNCkZ1bmNpw7NuIGRlIHJ1dGVvOg0KDQpgYGB7cn0NCg0Kb2J0ZW5lcl9yZWNvcnJpZG8gPC0gZnVuY3Rpb24ob194LCBvX3ksIGRfeCwgZF95KSB7DQogICAgDQogICAgcnV0YSA8LSBvc3JtUm91dGUoc3JjID0gYyhvX3gsIG9feSksDQogICAgICAgICAgICAgICAgICAgICAgZHN0ID0gYyhkX3gsIGRfeSkpDQogICAgDQogICAgI2NiaW5kKG5vbWJyZV9iYXJyaW8gPSBvX25vbWJyZSwgZm5hID0gZF9ub21icmUsIHJ1dGEpDQogICAgDQp9DQoNCg0KYXJndW1lbnRvcyA8LSBsaXN0KGhvc3AkTE9OX09SSUdFTiwgaG9zcCRMQVRfT1JJR0VOLA0KICAgICAgICAgICAgICAgICAgaG9zcCRMT05fREVTVElOTywgaG9zcCRMQVRfREVTVElOTykNCg0KZGVfdnRfYV9ob3NwaXRhbGVzIDwtIHBtYXBfZGYoYXJndW1lbnRvcywgb2J0ZW5lcl9yZWNvcnJpZG8pDQoNCmRlX3Z0X2FfaG9zcGl0YWxlcyA8LSBkZV92dF9hX2hvc3BpdGFsZXMgJT4lIA0KICBhcnJhbmdlKGRpc3RhbmNlKQ0KDQpwcm9tX2Rpc3RfdnQgPC0gcm91bmQobWVhbihkZV92dF9hX2hvc3BpdGFsZXMkZGlzdGFuY2UpLDIpDQoNCnByb21fdGllbXBvX3Z0IDwtIHJvdW5kKG1lYW4oZGVfdnRfYV9ob3NwaXRhbGVzJGR1cmF0aW9uKSwyKQ0KDQptaW5fZGlzdF92dCA8LSByb3VuZChtaW4oZGVfdnRfYV9ob3NwaXRhbGVzJGRpc3RhbmNlKSwyKQ0KDQptaW5fdGllbXBvX3Z0IDwtIHJvdW5kKG1pbihkZV92dF9hX2hvc3BpdGFsZXMkZHVyYXRpb24pLDIpDQoNCg0Kc3VtbWFyeShkZV92dF9hX2hvc3BpdGFsZXMkZGlzdGFuY2UpDQpzdW1tYXJ5KGRlX3Z0X2FfaG9zcGl0YWxlcyRkdXJhdGlvbikNCg0KYGBgDQpMb3MgZXN0YWTDrXN0aWNvcyBub3MgbXVlc3RyYW4gcXVlIGV4aXN0ZW4gNTMgZXN0YWJsZWNpbWllbnRvcyBjZXJjYW5vcyBhIFZpbGxhIFRyYW5xdWlsYSwgZW50cmUgbG9zIGN1YWxlcyBsYSBtZWRpYSBkZSBkaXN0YW5jaWEgZXF1aXZhbGUgYSA1IGttIHkgZWwgbWFzIGNlcmNhbm8gc2UgZW5jdWVudHJhIGEgMCw0MiBrbS4gTGFzIGR1cmFjaW9uZXMgcHJvbWVkaW8gcm9uZGFuIGxvcyA3IG1pbnV0b3MuIEEgY29udGludWFjacOzbiBzZSBncmFmaWZjYXLDoW4gbG9zIHJ1dGVvcyBvYnRlbmlkb3MgbWVkaWFudGUgdW4gbWFwYSBpbnRlcmFjdGl2bywgdG9tYW5kbyBzb2xhbWVudGUgbGFzIDE1IHJ1dGFzIG3DoXMgY2VyY2FuYXMgcGFyYSBmYWNpbGl0YXIgbGEgdmlzdWFsaXphY2nDs24uIA0KDQoNCmBgYHtyfQ0KDQpsZWFmbGV0KCkgJT4lIA0KICBhZGRUaWxlcygpICU+JSANCiAgI2FkZFBvbHlnb25zKGRhdGEgPSBwb2x5Z29uX2F2ZWxsYW5lZGEpKw0KICBhZGRQb2x5Z29ucyhkYXRhID0gZGF0YV9icF9nZW9fYW1iYV9hZ3J1cCAlPiUgDQogICAgICAgICAgICBmaWx0ZXIoZGVwYXJ0YW1lbnRvID09ICJBdmVsbGFuZWRhIikscG9wdXAgPSB+IGdsdWU6OmdsdWUoIjxiPk5vbWJyZTwvYj46e25vbWJyZV9iYXJyaW99PGJyLz4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGI+Q2FudGlkYWQgZGUgVml2aWVuZGFzOjwvYj57Y2FudGlkYWRfdml2aWVuZGFzX2Fwcm94aW1hZGFzfTxici8+DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxiPkNhbnRpZGFkIGRlIEZhbWlsaWFzOjwvYj57Y2FudGlkYWRfZmFtaWxpYXNfYXByb3hpbWFkYX08YnIvPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8Yj5EZWNhZGEgZGUgQ3JlYWNpw7NuOjwvYj57ZGVjYWRhX2RlX2NyZWFjaW9ufTxici8+IiksIGNvbG9yID0gIiNmNTU5NTEiKSAlPiUgDQogIGFkZENpcmNsZU1hcmtlcnMoZGF0YSA9IGRhdGFfYnBfZ2VvX2FtYmFfY2VudHJvaWRlLCBjb2xvciA9ICJncmVlbiIpICU+JSANCiAgYWRkTWFya2VycyhkYXRhID0gaG9zcF9hdmVfZGEsIHBvcHVwID0gfiBnbHVlOjpnbHVlKCI8Yj5Ob21icmU8L2I+OntmbmF9PGJyLz4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8Yj5nbmE6PC9iPntnbmF9PGJyLz4iKSkgJT4lIA0KICBhZGRQb2x5bGluZXMoZGF0YSA9IGRlX3Z0X2FfaG9zcGl0YWxlcyAlPiUgDQogICAgICAgICAgICAgICAgIGhlYWQoMTUpLGNvbG9yID0gInJlZCIsDQogICAgICAgICAgICAgICAgIGxhYmVsID0gcGFzdGUoIkRpc3RhbmNpYToiLCByb3VuZChkZV92dF9hX2hvc3BpdGFsZXMkZGlzdGFuY2UsMiksICJ8IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRHVyYWNpw7NuOiIsIHJvdW5kKGRlX3Z0X2FfaG9zcGl0YWxlcyRkdXJhdGlvbiwyKSkpDQpgYGANCg0KDQoNCg0KDQoNCiMjIyBDYXNvIEFzZW50YW1pZW50byBQcmltYXZlcmEgKExhIE1hdGFuemEgLSBEZWNhZGEgZGUgMjAwMCkNCg0KVmFtb3MgYSBhbmFsaXphciBlbCBncmFkbyBkZSBpbnRlZ3JhY2nDs24geSBhY2Nlc2liaWxpZGFkIGRlbCBBc2VudGFtaWVudG8gUHJpbWF2ZXJhIGVuIGxhIGxvY2FsaWRhZCBkZSBMYSBNYXRhbnphLiBWb2x2ZW1vcyBhIHJlYWxpemFyIGxvcyBwcm9jZXNvcyBkZSBkZXNjYXJnYSBwYXJhIGVzdGEgem9uYS4gDQoNCmBgYHtyfQ0KDQojaHR0cHM6Ly9yeWFucGVlay5vcmcvMjAxNi0xMC0xOS1hbmltYXRlZC1naWZfbWFwc19pbl9yLw0KDQpiYm94X2xtIDwtIHN0X2Jib3goYmFzZV9tYXBfYW1iYV9hZ3J1cCAlPiUgDQogICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcihuYW0gPT0gIkxhIE1hdGFuemEiKSkNCmJib3hfbG0gPC0gYXMubnVtZXJpYyhiYm94X2xtKQ0KbWFwYV9sbSA8LSBnZXRfc3RhZGlhbWFwKGJib3ggPSBiYm94X2xtLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwdHlwZSA9ICJhbGlkYWRlX3Ntb290aF9kYXJrIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHpvb20gPSAxMykNCg0KYGBgDQoNCmBgYHtyLGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD05fQ0KZ2dtYXAobWFwYV9sbSkrDQogIGdlb21fc2YoZGF0YSA9IGRhdGFfYnBfZ2VvICU+JSANCiAgICAgICAgICAgIGZpbHRlcihkZXBhcnRhbWVudG8gPT0gIkxhIE1hdGFuemEiKSxpbmhlcml0LmFlcz1GQUxTRSkrDQogIHRoZW1lX3ZvaWQoKQ0KDQoNCmBgYA0KDQpgYGB7cn0NCiNEZXNjYXJnYSBkZSBob3NwaXRhbGVzIC0gZXNjdWVsYXMgLSB0cmFuc3BvcnRlDQoNCnBvbHlnb25fbGFfbWF0YW56YSA8LSBnZXRiYigiTGEgTWF0YW56YSwgQnVlbm9zIEFpcmVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb3JtYXRfb3V0ID0gInNmX3BvbHlnb24iKQ0KDQpob3NwaXRhbGVzX2xhX21hdGFuemEgIDwtIG9wcShiYm94X2xtKQ0KaG9zcGl0YWxlc19sYV9tYXRhbnphICA8LSBhZGRfb3NtX2ZlYXR1cmUoaG9zcGl0YWxlc19sYV9tYXRhbnphLCBrZXkgPSAiYW1lbml0eSIsIHZhbHVlID0gYygiY2xpbmljIiwiaG9zcGl0YWwiKSkNCmhvc3BpdGFsZXNfbGFfbWF0YW56YSAgPC0gb3NtZGF0YV9zZihob3NwaXRhbGVzX2xhX21hdGFuemEpDQpob3NwaXRhbGVzX2xhX21hdGFuemEgIDwtIGhvc3BpdGFsZXNfbGFfbWF0YW56YSRvc21fcG9pbnRzDQoNCmVzY3VlbGFzX2xhX21hdGFuemEgPC0gb3BxKGJib3hfbG0pDQplc2N1ZWxhc19sYV9tYXRhbnphIDwtIGFkZF9vc21fZmVhdHVyZShlc2N1ZWxhc19sYV9tYXRhbnphLCBrZXkgPSAiYW1lbml0eSIsIHZhbHVlID0gYygic2Nob29sIiwidW5pdmVyc2l0eSIsImNvbGxlZ2UiKSkNCmVzY3VlbGFzX2xhX21hdGFuemEgPC0gb3NtZGF0YV9zZihlc2N1ZWxhc19sYV9tYXRhbnphKQ0KZXNjdWVsYXNfbGFfbWF0YW56YSA8LSBlc2N1ZWxhc19sYV9tYXRhbnphJG9zbV9wb2ludHMNCg0KdHJhbnNwb3J0ZV9sYV9tYXRhbnphIDwtIG9wcShiYm94X2xtKQ0KdHJhbnNwb3J0ZV9sYV9tYXRhbnphIDwtIGFkZF9vc21fZmVhdHVyZSh0cmFuc3BvcnRlX2xhX21hdGFuemEsIGtleSA9ICJwdWJsaWNfdHJhbnNwb3J0IiwgdmFsdWUgPSBjKCJzdG9wX3Bvc2l0aW9uIiwiCXBsYXRmb3JtIiwic3RhdGlvbiIsInN0b3BfYXJlYSIpKQ0KdHJhbnNwb3J0ZV9sYV9tYXRhbnphIDwtIG9zbWRhdGFfc2YodHJhbnNwb3J0ZV9sYV9tYXRhbnphKQ0KdHJhbnNwb3J0ZV9sYV9tYXRhbnphIDwtIHRyYW5zcG9ydGVfbGFfbWF0YW56YSRvc21fcG9pbnRzDQoNCg0KDQpob3NwaXRhbGVzX2xhX21hdGFuemEgPC0gc3RfaW50ZXJzZWN0aW9uKGhvc3BpdGFsZXNfbGFfbWF0YW56YSwgcG9seWdvbl9sYV9tYXRhbnphKSAlPiUgDQogIG11dGF0ZSgidGlwbyIgPSAiaG9zcGl0YWxlcyIpICU+JSANCiAgc2VsZWN0KG5hbWUsIHRpcG8sIGdlb21ldHJ5KSAlPiUgDQogIGZpbHRlcighaXMubmEobmFtZSkpDQplc2N1ZWxhc19sYV9tYXRhbnphIDwtIHN0X2ludGVyc2VjdGlvbihlc2N1ZWxhc19sYV9tYXRhbnphLCBwb2x5Z29uX2xhX21hdGFuemEpJT4lIA0KICBtdXRhdGUoInRpcG8iID0gImVzY3VlbGFzIiklPiUgDQogIHNlbGVjdChuYW1lLCB0aXBvLCBnZW9tZXRyeSkgJT4lIA0KICBmaWx0ZXIoIWlzLm5hKG5hbWUpKQ0KdHJhbnNwb3J0ZV9sYV9tYXRhbnphIDwtIHN0X2ludGVyc2VjdGlvbih0cmFuc3BvcnRlX2xhX21hdGFuemEsIHBvbHlnb25fbGFfbWF0YW56YSkgJT4lIA0KICBtdXRhdGUoInRpcG8iID0gInRyYW5zcG9ydGUiKSU+JSANCiAgc2VsZWN0KG5hbWUsIHRpcG8sIGdlb21ldHJ5KSAlPiUgDQogIGZpbHRlcighaXMubmEobmFtZSkpDQoNCmx1Z2FyZXNfbGFfbWF0YW56YSA8LSByYmluZChob3NwaXRhbGVzX2xhX21hdGFuemEsZXNjdWVsYXNfbGFfbWF0YW56YSx0cmFuc3BvcnRlX2xhX21hdGFuemEpDQoNCiNEZWZpbmljacOzbiBkZSBjZW50cm9pZGUNCg0KZGF0YV9icF9nZW9fbG1fY2VudHJvaWRlIDwtIGRhdGFfYnBfZ2VvX2FtYmFfYWdydXAgJT4lIA0KICBmaWx0ZXIoZGVwYXJ0YW1lbnRvID09ICJMYSBNYXRhbnphIiwNCiAgICAgICAgIG5vbWJyZV9iYXJyaW8gPT0gIlByaW1hdmVyYSIpICU+JSANCiAgc3RfY2VudHJvaWQoKQ0KDQojRGVmaW5pY2nDs24gZGUgaXNvY3JvbmENCg0KaXNvY3JvbmFfbG0gPC0gb3NybUlzb2Nocm9uZShsb2MgPSBkYXRhX2JwX2dlb19sbV9jZW50cm9pZGUkZ2VvbWV0cnksDQogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBzZXEoZnJvbT0wLHRvPTIwLGJ5PTUpLA0KICAgICAgICAgICAgICAgICAgICAgcmVzID0gMzUsDQogICAgICAgICAgICAgICAgICAgICBvc3JtLnByb2ZpbGUgPSAiZm9vdCIpDQoNCmBgYA0KDQpgYGB7cn0NCg0KbGVhZmxldChpc29jcm9uYV9sbSkgJT4lIA0KICBhZGRUaWxlcyhncm91cCA9ICJPU00gKGRlZmF1bHQpIikgJT4lDQogIGFkZFByb3ZpZGVyVGlsZXMocHJvdmlkZXJzJENhcnRvREIuUG9zaXRyb24sIGdyb3VwID0gIlBvc2l0cm9uIChtaW5pbWFsKSIpICU+JQ0KICBhZGRQcm92aWRlclRpbGVzKHByb3ZpZGVycyRDYXJ0b0RCLkRhcmtNYXR0ZXIsIGdyb3VwID0gIkRhcmtNYXR0ZXIiKSAlPiUNCiAgYWRkUG9seWdvbnMoZmlsbENvbG9yID0gfmNvbG9yQmluKCJPcmFuZ2VzIiwgZG9tYWluID0gaXNvY3JvbmFfdnQkaXNvbWF4KShpc29tYXgpLA0KICBjb2xvciA9IE5BLA0KICBmaWxsT3BhY2l0eSA9IDAuNSwgZ3JvdXAgPSAiaXNvY3JvbmEiKSU+JQ0KICBhZGRQb2x5Z29ucyhkYXRhID0gZGF0YV9icF9nZW9fYW1iYV9hZ3J1cCAlPiUgDQogICAgICAgICAgICBmaWx0ZXIoZGVwYXJ0YW1lbnRvID09ICJMYSBNYXRhbnphIikscG9wdXAgPSB+IGdsdWU6OmdsdWUoIjxiPk5vbWJyZTwvYj46e25vbWJyZV9iYXJyaW99PGJyLz4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGI+Q2FudGlkYWQgZGUgVml2aWVuZGFzOjwvYj57Y2FudGlkYWRfdml2aWVuZGFzX2Fwcm94aW1hZGFzfTxici8+DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxiPkNhbnRpZGFkIGRlIEZhbWlsaWFzOjwvYj57Y2FudGlkYWRfZmFtaWxpYXNfYXByb3hpbWFkYX08YnIvPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8Yj5EZWNhZGEgZGUgQ3JlYWNpw7NuOjwvYj57ZGVjYWRhX2RlX2NyZWFjaW9ufTxici8+IiksIGdyb3VwID0gIkJhcnJpb3MgUG9wdWxhcmVzIixjb2xvciA9ICIjZjU1OTUxIikgJT4lIA0KICBhZGRDaXJjbGVNYXJrZXJzKGRhdGEgPSBkYXRhX2JwX2dlb19sbV9jZW50cm9pZGUsIGNvbG9yID0gImJsYWNrIiwgZ3JvdXAgPSAiQXNlbnRhbWllbnRvIFByaW1hdmVyYSIpICU+JSANCiAgYWRkQ2lyY2xlTWFya2VycyhkYXRhID0gbHVnYXJlc19sYV9tYXRhbnphICU+JSANCiAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKHRpcG8gPT0gImhvc3BpdGFsZXMiKSwgcG9wdXAgPSB+IGdsdWU6OmdsdWUoIjxiPk5vbWJyZTwvYj46e25hbWV9PGJyLz4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8Yj50aXBvOjwvYj57dGlwb308YnIvPiIpLCBncm91cCA9ICJob3NwaXRhbGVzIiwgY29sb3IgPSAiIzAwMWY3ZCIpICU+JQ0KICBhZGRDaXJjbGVNYXJrZXJzKGRhdGEgPSBsdWdhcmVzX2xhX21hdGFuemElPiUgDQogICAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcih0aXBvID09ICJlc2N1ZWxhcyIpLCBwb3B1cCA9IH4gZ2x1ZTo6Z2x1ZSgiPGI+Tm9tYnJlPC9iPjp7bmFtZX08YnIvPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxiPnRpcG86PC9iPnt0aXBvfTxici8+IiksIGdyb3VwID0gImVzY3VlbGFzIiwgY29sb3IgPSAiIzU4YjM2OCIpICU+JQ0KICBhZGRDaXJjbGVNYXJrZXJzKGRhdGEgPSBsdWdhcmVzX2xhX21hdGFuemElPiUgDQogICAgICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcih0aXBvID09ICJ0cmFuc3BvcnRlIiksIHBvcHVwID0gfiBnbHVlOjpnbHVlKCI8Yj5Ob21icmU8L2I+OntuYW1lfTxici8+DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGI+dGlwbzo8L2I+e3RpcG99PGJyLz4iKSwgZ3JvdXAgPSAidHJhbnNwb3J0ZSIsIGNvbG9yID0gIiNkYWQ4NzMiKSAlPiUgDQogIA0KICAgIGFkZExheWVyc0NvbnRyb2woDQogICAgYmFzZUdyb3VwcyA9IGMoDQogICAgICAiT1NNIChkZWZhdWx0KSIsDQogICAgICAiUG9zaXRyb24gKG1pbmltYWwpIiwNCiAgICAgICJEYXJrTWF0dGVyIg0KICAgICksDQogICAgb3ZlcmxheUdyb3VwcyA9IGMoIkFzZW50YW1pZW50byBQcmltYXZlcmEiLCJCYXJyaW9zIFBvcHVsYXJlcyIsICJpc29jcm9uYSIsImVzY3VlbGFzIiwidHJhbnNwb3J0ZSIsImhvc3BpdGFsZXMiKSwNCiAgICBvcHRpb25zID0gbGF5ZXJzQ29udHJvbE9wdGlvbnMoY29sbGFwc2VkID0gRkFMU0UpDQogICkNCg0KYGBgDQoNCg0KDQoNCmBgYHtyfQ0KDQpob3NwX2F2ZV9sbSA8LSByZWFkX3NmKCJkYXRhL2hvc3DDrXRhbGVzL0VzdGFibGVjaW1pZW50b3Nfc2FsdWRfcHVibGljb3NfYWx0YV9hbDIwMjIwNzIxLmdlb2pzb24iLCBzdHJpbmdzQXNGYWN0b3JzID0gVFJVRSkNCmhvc3BfYXZlX2xtIDwtIGhvc3BfYXZlX2xtICU+JSANCiAgZmlsdGVyKG5kZSA9PSAiTEEgTUFUQU5aQSIpDQoNCmhvc3BfYXZlX2xtIDwtIHN0X2ludGVyc2VjdGlvbihob3NwX2F2ZV9sbSwgcG9seWdvbl9sYV9tYXRhbnphKQ0KDQoNCmBgYA0KDQpgYGB7cn0NCg0KZGF0YV9hc2VuX3ByaW1hdmVyYSA8LSBkYXRhX2JwX2dlb19sbV9jZW50cm9pZGUgJT4lIA0KICBzZWxlY3Qobm9tYnJlX2JhcnJpbyxnZW9tZXRyeSkgJT4lIA0KICBtdXRhdGUoIm5kZSIgPSAiTEEgTUFUQU5aQSIpIA0KZGF0YV9hc2VuX3ByaW1hdmVyYSA8LSBjYmluZChkYXRhX2FzZW5fcHJpbWF2ZXJhICwgc3RfY29vcmRpbmF0ZXMoZGF0YV9hc2VuX3ByaW1hdmVyYSkpICU+JQ0KICAgICAgICAgICAgICAgICAgICAgIHN0X3NldF9nZW9tZXRyeShOVUxMKSAlPiUgDQogICAgICAgICAgICAgICAgICAgICAgcmVuYW1lKExPTl9PUklHRU49WCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTEFUX09SSUdFTj1ZKQ0KDQpob3NwX2xtIDwtIGhvc3BfYXZlX2xtICU+JSANCiAgcmVuYW1lKExPTl9ERVNUSU5PPWxvbmcsDQogICAgICAgICBMQVRfREVTVElOTz1sYXQpICU+JSANCiAgc2VsZWN0KExBVF9ERVNUSU5PLExPTl9ERVNUSU5PLGZuYSxuZGUpICU+JSANCiAgbGVmdF9qb2luKGRhdGFfYXNlbl9wcmltYXZlcmEpDQoNCmBgYA0KYGBge3J9DQoNCm9idGVuZXJfcmVjb3JyaWRvIDwtIGZ1bmN0aW9uKG9feCwgb195LCBkX3gsIGRfeSkgew0KICAgIA0KICAgIHJ1dGEgPC0gb3NybVJvdXRlKHNyYyA9IGMob194LCBvX3kpLA0KICAgICAgICAgICAgICAgICAgICAgIGRzdCA9IGMoZF94LCBkX3kpKQ0KICAgIA0KICAgICNjYmluZChub21icmVfYmFycmlvID0gb19ub21icmUsIGZuYSA9IGRfbm9tYnJlLCBydXRhKQ0KICAgIA0KfQ0KDQoNCmFyZ3VtZW50b3MgPC0gbGlzdChob3NwX2xtJExPTl9PUklHRU4sIGhvc3BfbG0kTEFUX09SSUdFTiwNCiAgICAgICAgICAgICAgICAgIGhvc3BfbG0kTE9OX0RFU1RJTk8sIGhvc3BfbG0kTEFUX0RFU1RJTk8pDQoNCmRlX2xtX2FfaG9zcGl0YWxlcyA8LSBwbWFwX2RmKGFyZ3VtZW50b3MsIG9idGVuZXJfcmVjb3JyaWRvKQ0KDQpkZV9sbV9hX2hvc3BpdGFsZXMgPC0gZGVfbG1fYV9ob3NwaXRhbGVzICU+JSANCiAgYXJyYW5nZShkaXN0YW5jZSkNCg0Kc3VtbWFyeShkZV9sbV9hX2hvc3BpdGFsZXMkZGlzdGFuY2UpDQpzdW1tYXJ5KGRlX2xtX2FfaG9zcGl0YWxlcyRkdXJhdGlvbikNCmBgYA0KDQpMb3MgZXN0YWTDrXN0aWNvcyBub3MgbXVlc3RyYW4sIGVuIGVzdGUgY2FzbyBxdWUgZXhpc3RlbiA4OCBlc3RhYmxlY2ltaWVudG9zIGNlcmNhbm9zIGFsIEFzZW50YW1pZW50bywgZW50cmUgbG9zIGN1YWxlcyBsYSBtZWRpYSBkZSBkaXN0YW5jaWEgZXF1aXZhbGUgYSAxMSBrbSB5IGVsIG1hcyBjZXJjYW5vIHNlIGVuY3VlbnRyYSBhIDEsNDYga20uIExhcyBkdXJhY2lvbmVzIHByb21lZGlvIHJvbmRhbiBsb3MgMTYgbWludXRvcyBkdXBsaWNhbmRvIGxvcyB2YWxvcmVzIG9idGVuaWRvcyBlbiBWaWxsYSBUcmFucXVpbGEuIEEgY29udGludWFjacOzbiBzZSBncmFmaWNhcsOhbiBsb3MgcnV0ZW9zIG9idGVuaWRvcyBtZWRpYW50ZSB1biBtYXBhIGludGVyYWN0aXZvLCB0b21hbmRvIHNvbGFtZW50ZSBsYXMgMTUgcnV0YXMgbcOhcyBjZXJjYW5hcyBwYXJhIGZhY2lsaXRhciBsYSB2aXN1YWxpemFjacOzbi4gDQoNCg0KYGBge3J9DQoNCmxlYWZsZXQoKSAlPiUgDQogIGFkZFRpbGVzKCkgJT4lIA0KICBhZGRQb2x5Z29ucyhkYXRhID0gZGF0YV9icF9nZW9fYW1iYV9hZ3J1cCAlPiUgDQogICAgICAgICAgICBmaWx0ZXIoZGVwYXJ0YW1lbnRvID09ICJMYSBNYXRhbnphIikscG9wdXAgPSB+IGdsdWU6OmdsdWUoIjxiPk5vbWJyZTwvYj46e25vbWJyZV9iYXJyaW99PGJyLz4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGI+Q2FudGlkYWQgZGUgVml2aWVuZGFzOjwvYj57Y2FudGlkYWRfdml2aWVuZGFzX2Fwcm94aW1hZGFzfTxici8+DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDxiPkNhbnRpZGFkIGRlIEZhbWlsaWFzOjwvYj57Y2FudGlkYWRfZmFtaWxpYXNfYXByb3hpbWFkYX08YnIvPg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8Yj5EZWNhZGEgZGUgQ3JlYWNpw7NuOjwvYj57ZGVjYWRhX2RlX2NyZWFjaW9ufTxici8+IiksIGNvbG9yID0gIiNmNTU5NTEiKSAlPiUgDQogIGFkZENpcmNsZU1hcmtlcnMoZGF0YSA9IGRhdGFfYnBfZ2VvX2xtX2NlbnRyb2lkZSwgY29sb3IgPSAiZ3JlZW4iKSAlPiUgDQogIGFkZE1hcmtlcnMoZGF0YSA9IGhvc3BfYXZlX2xtLCBwb3B1cCA9IH4gZ2x1ZTo6Z2x1ZSgiPGI+Tm9tYnJlPC9iPjp7Zm5hfTxici8+DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPGI+Z25hOjwvYj57Z25hfTxici8+IikpICU+JSANCiAgYWRkUG9seWxpbmVzKGRhdGEgPSBkZV9sbV9hX2hvc3BpdGFsZXMgJT4lIA0KICAgICAgICAgICAgICAgICBoZWFkKDE1KSxjb2xvciA9ICJyZWQiLA0KICAgICAgICAgICAgICAgICBsYWJlbCA9IHBhc3RlKCJEaXN0YW5jaWE6Iiwgcm91bmQoZGVfbG1fYV9ob3NwaXRhbGVzJGRpc3RhbmNlLDIpLCAifCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkR1cmFjacOzbjoiLCByb3VuZChkZV9sbV9hX2hvc3BpdGFsZXMkZHVyYXRpb24sMikpKQ0KYGBgDQoNCg0KIyMgQ29uY2x1c2lvbmVzDQoNCjxkaXYgc3R5bGU9InRleHQtYWxpZ246IGp1c3RpZnkiPg0KDQpBIHRyYXbDqXMgZGUgbGFzIGhlcnJhbWllbnRhcyBkZSBnZW9yZWZlcmVuY2lhY2nDs24gY29tcHJlbmRpZGFzIGVuIGxhIG1hdGVyaWEsIHNlIGFuYWxpesOzIGxhIHNpdHVhY2nDs24gZGUgbG9zIEJhcnJpb3MgUG9wdWxhcmVzIGRlbCBHcmFuIEJ1ZW5vcyBBaXJlcyBhIHBhcnRpciBkZSBzdXMgY2xhc2lmaWNhY2lvbmVzIHkgYW50aWfDvGVkYWQgZGUgbG9zIG1pc21vcy4gRW4gYmFzZSBhIGVsbG8sIHNlIHRvbWFyb24gZG9zIGNhc29zIGNvbiBlbCBvYmpldG8gZGUgZXN0dWRpYXIgc3UgZ3JhZG8gZGUgYWNjZXNpYmlsaWRhZCBhIHNlcnZpY2lvcyBkZSBzYWx1ZCwgdHJhbnNwb3J0ZSB5IGVkdWNhY2nDs24uIExhcyB0w6ljbmljYXMgdXRpbGl6YWRhcyBjb25zaXN0aWVyb24gZW4gZGVzY2FyZ2FyIGluZm9ybWFjacOzbiBkZSBsYSBBUEkgZGUgT1NNIFkgZGUgZGF0b3MgYWJpZXJ0b3MgZGUgUEJBIHBhcmEgY29tcGxlbWVudGFyIGxvIHF1ZSBubyBzZSBlbmN1ZW50cmUgZW4gZWwgcHJpbWVyby4gQ29uIGVzdG9zIGRhdG9zLCBzZSBvYnR1dm8gdW4gaXPDs2Nyb25hIHBhcmEgZXZhbHVhciBkZSBtYW5lcmEgdmlzdWFsIGVuIHVuIG1hcGEgaW50ZXJhY3Rpdm8sIGxhcyBmb3JtYXMgZGUgaW50ZWdyYWNpw7NuIGRlIGxvcyBiYXJyaW9zIGNvbW8gdW4gcG9zaWJsZSBpbnN1bW8gcGFyYSBwZW5zYXIgZXN0YXMgcHJvYmxlbcOhdGljYXMgYmFqbyBsYSBwcmVtaXNhIGRlICJjaXVkYWRlcyBkZSAxNSBtaW51dG9zIi4gDQpFbiBlc3RlIG9yZGVuIGRlIGlkZWFzLCBwdWRvIHZlcnNlIHRhbWJpw6luIHF1ZSBlbiBlbCBjYXNvIGRlIFZpbGxhIFRyYW5xdWlsYSwgbG9zIHRpZW1wb3MgeSBsYXMgZGlzdGFuY2lhcyBkZSBsb3MgcnV0ZW9zIGhhY2lhIHNlcnZpY2lvcyBzYW5pdGFyaW9zIG1hcmNhcm9uIGNpZnJhcyBjb25zaWRlcmFibGVtZW50ZSBtZW5vcmVzIHF1ZSBlbiBlbCBjYXNvIGRlbCBBc2VudGFtaWVudG8gUHJpbWF2ZXJhIGRlIExhIE1hdGFuemEuIA0KDQo8ZGl2Lz4NCg0KIyMgRnV0dXJhcyBJZGVhcw0KDQpDb25zdHJ1aXIgdW5hIHNoaW55IGFwcCBjb24gdG9kYSBsYSBpbmZvcm1hY2nDs24gcmVjYWJhZGEgcGFyYSBmYWNpbGl0YXIgbGFzIHZpc3VhbGl6YWNpb25lcw0KDQpDb25zdHJ1aXIgdW5hIGZ1bmNpw7NuIHF1ZSBtYXBlZSB5IHJ1dGVlIHRvbWFuZG8gY29tbyBpbnN1bW8gZWwgbm9tYnJlIGRlbCBiYXJyaW8geSBlbCBwYXJ0aWRvLg0KDQo=