Librerías utilizadas

if (!require(pacman)) install.packages("pacman")
library(pacman) ; p_load("readxl", 
                         "dplyr", 
                         "tidyverse", 
                         "writexl", 
                         "sf",
                         "leaflet",
                         "plotly",
                         "ggplot2",
                         "tidyr",
                         "patchwork",
                         "stringr",
                         "svglite",
                         "scales",
                         "viridis")

Construcción de las bases

Carga de archivo y selección de variables

La base que utilizaremos contiene información de los Centros de Atención Infantil (CAI) de cuatro fuentes distintas: SNDIF, DENUE, IMSS e ISSSTE. Esta base contiene 47 variables, de las cuales utilizaremos 25 que contienen la información que necesitamos

base_cai <- read_excel("BASE_FINAL_CAI.xlsx", 
                       sheet = "CAI_FINAL") %>% 
  mutate(
    base = case_when(base == "SNIDF" ~ "SNDIF",
                     TRUE ~ base),
    telefono = as.character(telefono),
    correoelec = as.character(correoelec),
         www = as.character(www),
         latitud = as.numeric(latitud),
         longitud = as.numeric(longitud)) %>% 
  select(-codigo_act, -per_ocu:-manzana,-tipoUniEco, -fecha_alta)

str(base_cai)
## tibble [10,014 × 25] (S3: tbl_df/tbl/data.frame)
##  $ base         : chr [1:10014] "SNDIF" "SNDIF" "SNDIF" "SNDIF" ...
##  $ cve_ent      : chr [1:10014] "01" "01" "01" "02" ...
##  $ nom_ent      : chr [1:10014] "Aguascalientes" "Aguascalientes" "Aguascalientes" "Baja California" ...
##  $ cve_mun      : chr [1:10014] "007" "001" "001" "004" ...
##  $ nom_mun      : chr [1:10014] "Rincón De Romos" "Aguascalientes" "Aguascalientes" "Tijuana" ...
##  $ cve_integrada: chr [1:10014] "01007" "01001" "01001" "02004" ...
##  $ nom_cai_guard: chr [1:10014] "CENDI DIF MA DEL ROSARIO LUEVANO MARTINEZ" "CAI SAN MARCOS" "CENTRO DE DESARROLLO INFANTIL TERESA DE CALCUTA" "CARITAS FELICES" ...
##  $ tipo_asent   : chr [1:10014] "MIGUEL HIDALGO" "SAN MARCOS" "INSURGENTES" "COLONIA" ...
##  $ nom_asent    : chr [1:10014] "COLONIA" "COLONIA" "COLONIA" "VALLE VERDE" ...
##  $ tipo_vial    : chr [1:10014] "CALLE" "CALLE" "CALLE" "CALLE" ...
##  $ nom_vial     : chr [1:10014] "BAJA CALIFORNIA SUR" "ALEJANDRO TOPETE DEL VALLE" "SERAPIO RENDON" "NOVENA" ...
##  $ num_ext      : chr [1:10014] "304" "105" "SN" "22397" ...
##  $ cp           : chr [1:10014] "20417" "20070" "20287" "22204" ...
##  $ nombre_act   : chr [1:10014] "Sector Público" "Sector Público" "Sector Público" "Sector Público" ...
##  $ telefono     : chr [1:10014] NA NA NA NA ...
##  $ correoelec   : chr [1:10014] NA NA NA NA ...
##  $ www          : chr [1:10014] NA NA NA NA ...
##  $ latitud      : num [1:10014] NA NA NA NA NA NA NA NA NA NA ...
##  $ longitud     : num [1:10014] NA NA NA NA NA NA NA NA NA NA ...
##  $ pob_est      : num [1:10014] 152797 152797 152797 333375 333375 ...
##  $ hom_est      : num [1:10014] 77786 77786 77786 170403 170403 ...
##  $ muj_est      : num [1:10014] 75011 75011 75011 162972 162972 ...
##  $ pob_mun      : num [1:10014] 5838 77580 77580 141718 141718 ...
##  $ hom_mun      : num [1:10014] 2958 39476 39476 72606 72606 ...
##  $ muj_mun      : num [1:10014] 2880 38104 38104 69112 69112 ...

Descripción de variables

Variables Descripción
base Fuente de información a la que pertenece el registro (SNDIF, DENUE, IMSS o ISSSTE)
cve_ent, nom_ent Clave y nombre de entidad federativa en donde se encuentra el CAI.
cve_mun, nom_mun Clave y nombre del municipio en donde se encuentra el CAI.
cve_integrada Clave única, se compone por la clave de entidad y la de municipio.
nom_cai_guard Nombre del CAI o guardería

tipo_asent, nom_asent, tipo_vial,

nom_vial, num_ext, cp

Información de ubicación del CAI: tipo y nombre de asentamiento, tipo y nombre de vialidad, número exterior del CAI y código postal.
nombre_act Tipo de CAI (público o privado)

telefono,

correoelec, www

Información de contacto del CAI: teléfono, correo electrónico y página web.

latitud,

longitud

Latitud y longitud de ubicación del CAI.
pob_est, hom_est, muj_est Proyección de población de 0 a 5 años a nivel estatal total y por sexo (hombre, mujer).
pob_mun, hom_mun, muj_mun Proyección de población de 0 a 4 años a nivel municipal total y por sexo (hombre, mujer).

Datos por municipio

# Para obtener el número y tipo de CAI por municipio, primero agrupamos por clave y tipo de CAI para después sumar por cada grupo creado. Posteriormente transformamos la base de formato largo (una fila por cada tipo de CAI en cada municipio) a formato ancho (una fila por municipio con una columna por cada tipo de CAI).

tipo_cai <- base_cai %>% 
  group_by(cve_integrada, base) %>% 
  summarize(count = n()) %>% 
  pivot_wider(names_from = base, 
              values_from = count, 
              values_fill = 0)

# A la base creada, se agrega una variable que sume el total de CAI en el municipio
tipo_cai$tot_cai <- rowSums(tipo_cai[,2:5]) 
tipo_cai$cve_ent <- substr(tipo_cai$cve_integrada, 1, 2)

# Para obtener los valores de población, primero se seleccionan las variables y luego se filtran los valores únicos en cve_integrada
poblaciones <- base_cai %>%
  select(cve_integrada, nom_ent, nom_mun, pob_est:muj_mun) %>% 
  distinct(cve_integrada, .keep_all = TRUE)

#La base final se obtiene uniendo las dos anteriores
cai_mun <- left_join(poblaciones, 
                     tipo_cai, 
                     by = "cve_integrada") %>% 
  arrange(cve_integrada)

La base de datos creada contiene información por municipio de la proyección de población a nivel estatal y municipal, además del número y tipo de CAI.

head(cai_mun)
write_xlsx(cai_mun, path = "cai_mun.xlsx")

Datos por entidad federativa

# Utilizando la base de CAI por municipio, primero agrupamos por entidad y después sumamos las filas por cada tipo de CAI.
agregados <- cai_mun %>%
  group_by(cve_ent) %>% 
  summarize(SNDIF = sum(SNDIF, na.rm=T),
            DENUE = sum(DENUE, na.rm=T),
            IMSS = sum(IMSS, na.rm=T),
            ISSSTE = sum(ISSSTE, na.rm=T))

cai_ef <- cai_mun %>% 
  select(cve_ent, nom_ent, pob_est) %>% 
  left_join(agregados, by = "cve_ent") %>% 
  distinct(cve_ent, .keep_all = TRUE)

# Asimismo, agregamos una columna que sume el total de CAI en la entidad
cai_ef$tot_cai = rowSums(cai_ef[,4:7])
cai_ef$tasa = cai_ef$tot_cai/(cai_ef$pob_est/1000)

head(cai_ef)
# Exportamos la base a Excel
write_xlsx(cai_ef, path = "cai_ef.xlsx")

Mapas

Información geoespacial

La información geoespacial para elaborar los mapas la tomaremos del Marco Geoestadístico de INEGI. Para ello tenemos dos archivos:

# Los archivos .shp contienen la información geográfica de los polígonos por municipio y por entidad federativa que uniremos a sus respectivas bases de CAI
ef_shp <- read_sf("geo_ef/dest22gw.shp")

mun_shp <- read_sf("geo_mun/mun22gw.shp")

# Con estos comandos verificamos que la información corresponda a información geográfica
plot(ef_shp, max.plot = 2)

plot(mun_shp, max.plot = 2)

# Por último, unimos la información geográfica a cada base de datos y eliminamos variables repetidas
cai_ef <- left_join(ef_shp, 
                    cai_ef, 
                    by = c("CVEGEO" = "cve_ent")) %>% 
  select(-CVE_CAP,-NOM_CAP, -nom_ent) 

cai_ef <- cai_ef %>% mutate(NOM_ENT = str_trim(NOM_ENT))

cai_mun <- left_join(mun_shp, 
                     cai_mun, 
                     by = c("CVEGEO" = "cve_integrada")) %>% 
  select(-nom_ent, -nom_mun, -cve_ent)

Tasa CAI por niñas, niños y adolescentes a nivel nacional

plt_tasa <- cai_ef %>% 
  mutate(gpo_tasa = case_when(tasa < 0.5 ~ "0.0 - 0.5",
                              between(tasa, 0.5,1) ~ "0.5 - 1.0",
                              between(tasa, 1,1.5) ~ "1.0 - 1.5",
                              tasa > 2 ~ "Mayor a 2.0")) %>% 
  ggplot(aes(fill = gpo_tasa)) + 
  geom_sf(color = "transparent") + 
  geom_sf(data = ef_shp, fill = NA, linewidth = 0.43) + 
    scale_fill_manual(values = c("0.0 - 0.5" = "#D2ADCD",
                                 "0.5 - 1.0" = "#629DCA",
                                 "1.0 - 1.5" = "#206D9F",
                                 "Mayor a 2.0" = "#153468"),
                      guide = guide_legend(
                        keyheight = unit(6, units = "mm"),
                        keywidth = unit(6, units = "mm"),
                        label.position = "left",
                        title.position = "top",
                        ncol = 1)) + 
  scale_x_continuous(expand = expansion(c(0.19, 0))) +
  scale_y_continuous(expand = expansion(c(0.10, 0))) +
  labs(title = "Número de CAI por cada mil niñas y niños de 0 a 5 años") + 
  theme_void() + 
  theme(text = element_text(color = "#22211d"),
        legend.position = c(0.8, 0.85),
        legend.text = element_text(size = 14),
        legend.title = element_blank(),
        plot.margin = margin(t = 0, 
                             r = 0, 
                             b = 0, 
                             l = 0, 
                             unit = "cm"),
        plot.title = element_text(size = 24, 
                                  face = "bold",
                                  color = "#003366", 
                                  hjust = 0.5, 
                                  vjust = 0.5,
                                  margin = margin(t = 0, 
                                                  b = 1, 
                                                  unit = "cm"))
  )

plt_tasa_b <- cai_ef %>% arrange(desc(tasa)) %>%
  mutate(gpo_tasa = case_when(tasa < 0.5 ~ "0.0 - 0.5",
                              between(tasa, 0.5,1) ~ "0.5 - 1.0",
                              between(tasa, 1,1.5) ~ "1.0 - 1.5",
                              tasa > 2 ~ "Mayor a 2.0"),
         NOM_ENT = case_when(
           NOM_ENT == "Michoacán de Ocampo" ~ "Michoacán",
           NOM_ENT == "Coahuila de Zaragoza" ~ "Coahuila",
           NOM_ENT == "Veracruz de Ignacio de la Llave" 
           ~ "Veracruz", 
           TRUE ~ NOM_ENT)) %>% 
  ggplot(aes(x = reorder(NOM_ENT, -tasa), 
             y = tasa, 
             color = gpo_tasa)) +
  geom_point(size = 3) +
  geom_hline(yintercept = 0, 
             color = "#4e4d47", 
             linewidth = 0.5) +
  geom_segment(aes(x = NOM_ENT, 
                   xend = NOM_ENT, 
                   y = 0, 
                   yend = tasa)) +
  geom_text(aes(label = round(tasa,2)),
            ize = 3, hjust = -0.8) +
  coord_flip() +
  scale_color_manual(values = c("0.0 - 0.5" = "#D2ADCD",
                                 "0.5 - 1.0" = "#629DCA",
                                 "1.0 - 1.5" = "#206D9F",
                                 "Mayor a 2.0" = "#153468")) +
    theme_void() +
    theme(axis.line.x =element_blank(),
          axis.line.y=element_blank(),
          axis.title.x=element_blank(),
          axis.title.y=element_blank(),
          axis.text.x = element_blank(),
          axis.text.y = element_text(size = 11, 
                                     hjust = 1, 
                                     face = "bold",
                                     margin = margin(t = 0,
                                                     r = -1,
                                                     b = 0,
                                                     l = 0,
                                                     unit = "cm")),
          axis.ticks.x =element_blank(),
          axis.ticks.y=element_blank(),
          legend.position = "none",
          text = element_text(color = "#22211d")
          ) +
  labs(color = NULL)

combined_plot <- plt_tasa + inset_element(plt_tasa_b, 
                                          left = 0,
                                          bottom = 0, 
                                          right = 0.9, 
                                          top =0.6)
ggsave(str_c("Mapas/Tasa CAI Nacional_comb",".png"),
       height = 8, width = 12, dpi = 1000)

combined_plot

Número de CAI por municipio

# Mapa nacional con el total de CAI
plt_mun <- cai_mun %>% 
  mutate(cat_cai = cut(tot_cai,
                       breaks = c(-Inf, 10, 20, 30, Inf),
                       labels = c("1-10", "11-20", "21-30", "Más de 30"))) %>% 
  ggplot(aes(fill = cat_cai)) + 
  geom_sf(color = "#5F5F5F") + 
  geom_sf(data = ef_shp, fill = NA, linewidth = 0.5) + 
    scale_fill_manual(values = c("1-10" = "#D2ADCD",
                                 "11-20" = "#629DCA",
                                 "21-30" = "#206D9F",
                                 "Más de 30" = "#153468"),
                      na.value = "#7F7F7F",
                      labels = c("1-10", 
                                 "11-20", 
                                 "21-30", 
                                 "Más de 30", "Ninguno"),
                      guide = guide_legend(
                        keyheight = unit(6, units = "mm"),
                        keywidth = unit(6, units = "mm"),
                        label.position = "right",
                        title.position = "top",
                        ncol = 1)) + 
  scale_x_continuous(expand = expansion(c(0.19, 0))) +
  scale_y_continuous(expand = expansion(c(0.10, 0))) +
  labs(title = "Número de CAI a nivel municipal",
       fill = "Número de CAI") +
  theme_void() + 
  theme(text = element_text(color = "#22211d"),
        legend.position = c(0.85, 0.75),
        legend.text = element_text(size = 14),
        legend.title = element_text(size = 16, 
                                    face = "bold", 
                                    hjust = 0.5),
        plot.title = element_text(size = 24, 
                                  face = "bold",
                                  color = "#003366", 
                                  hjust = 0.5, vjust = 0.5,
                                  margin = margin(t = 0, 
                                                  b = 1, 
                                                  unit = "cm")),
        plot.margin = margin(t = 0.1, 
                             r = 0.2, 
                             b = 0.5, 
                             l = 0, 
                             unit = "cm")
        )
  
totales_cai <- cai_ef %>% 
  st_set_geometry(NULL) %>% 
  summarise(Privados = sum(DENUE, na.rm = TRUE),
            IMSS = sum(IMSS, na.rm = TRUE),
            ISSSTE = sum(ISSSTE, na.rm = TRUE),
            SNDIF = sum(SNDIF, na.rm = TRUE)) %>%
  pivot_longer(cols = everything(), 
               names_to = "categoria", 
               values_to = "total") %>% 
  mutate(text_color = ifelse(categoria == "DENUE", 
                             "#FFFFFF", 
                             "#22211d"))

plt_tot<-ggplot(totales_cai, 
                aes(x = reorder(categoria, -total), 
                    y = total, 
                    fill = categoria)) +
  geom_bar(stat = "identity") +
  labs(title = "Número de CAI por categoría",
       y = "Número de CAI") +
  coord_flip() +
  scale_fill_manual(values = c("Privados" = "#536493",
                               "IMSS" = "#CC99FF",
                               "ISSSTE" = "#EBB452",
                               "SNDIF" = "#0099CC")) +
  geom_text(aes(label = comma(total), color = text_color),
            position = position_stack(vjust = 0.5),
            hjust = -0.1,
            size = 4,
            color = "#22211d") +
  scale_y_continuous(labels = label_comma(scale = 1e-3, 
                                          suffix = "k")) +
  scale_color_identity() +
  theme_void() + 
  theme(text = element_text(color = "#22211d"),
        title = element_text(hjust = -0.5, face = "bold"),
        axis.text.x = element_blank(),
        axis.text.y = element_text(size = 10, hjust = 0),
        legend.position = "none",
        legend.text = element_text(size = 14),
        legend.title = element_text(size = 16, 
                                    face = "bold", 
                                    hjust = 0.5),
        plot.title = element_text(size = 16, 
                                  face = "bold", 
                                  hjust = 0),
        plot.margin = margin(t = 0, r = 0, b = 0, l = 0, 
                             unit = "cm")
        )

comb_plt_numcai <- plt_mun + inset_element(plt_tot, 
                                           left = 0,
                                           bottom = 0, 
                                           right = 0.7, 
                                           top =0.6)

comb_plt_numcai

ggsave(str_c("Mapas/Num CAI Nacional_comb",".png"),
       height = 8, width = 12, dpi = 1000)

Mapas por entidad federativa

Dada la forma de las entidades federativas, se debe acomodar la leyenda del gráfico para pueda visualizarse correctamente. A continuación se presentan los valores que se deben sustituir en legend.position = c()

CVE_ENT legend.position
1:4, 11, 13:16, 18, 21:23, c(0.06, 0.75)
5, 7:10, c(1.1, 0.75)
12, 19, 20, 24, 25, 27, 29, 30 c(0.9, 0.85)
17 c(0.03, 0.85)
26, 28 c(0.06, 0.6)
6 c(0.85, 0.75)
31 c(0.06, 0.75)
32 c(0.03, 0.75)

En el caso de Colima (6) y Yucatán (31), se tiene que reducir la superficie graficada, esto se hace con el comando coord_sf(xlim= c(), ylim=c()). Dentro de este comando se colocan los límites inferior y superior de X y Y para los cuales se va a graficar, estos límites se obtuvieron de Google Maps y corresponden a la longitud y latitud geográfica de cada entidad federativa.

CVE_ENT coord_sf()
6 xlim = c(-105,-103), ylim = c(18.65, 19.6)
31 xlim = c(-90.7,-87.4), ylim = c(19.55117, 21.9)

Los valores tanto de legend.position como de coord_sf() se deben sustituir para cada caso (a menos que se incorporen como una variable o valor dentro de la función, tipo ifelse)

sel_edo = 32

num_cai_mun <- function(sel_edo){
  
map_cai <- cai_mun %>% 
  filter(as.numeric(CVE_ENT) == sel_edo) %>% 
  mutate(tot_cai = replace_na(tot_cai, 0),
         cat_cai = case_when(tot_cai == 0 ~ "Ninguno",
                             between(tot_cai, 1,10) ~ "1 - 10",
                             between(tot_cai, 11,20) ~ "11 - 20",
                             between(tot_cai, 21,30) ~ "21 - 30",
                             tot_cai > 30 ~ "Más de 30")
         )

nombre_entidad <- map_cai$NOM_ENT %>% unique() 
num_ent <- map_cai$CVE_ENT %>% unique()

f_plt <- ggplot(map_cai) +
  geom_sf(aes(fill = cat_cai), lwd = 0.45, color = "black") +
  # coord_sf(xlim = c(-90.7,-87.4), ylim = c(19.55117, 21.9)) +
  scale_fill_manual(values = c("Ninguno" = "#7F7F7F",
                               "1 - 10" = "#D2ADCD",
                               "11 - 20" = "#629DCA",
                               "21 - 30" = "#206D9F",
                               "Más de 30" = "#153468"),
                    guide = guide_legend(
                      keyheight = unit(6, units = "mm"),
                      keywidth = unit(6, units = "mm"),
                      label.position = "right",
                      title.position = "top",
                      ncol = 1,
                      shape = 16,
                      size = 6)) +
  labs(fill = "Número de CAI",
       title = nombre_entidad) +
  theme_void() +
  theme(text = element_text(color = "#22211d"),
        plot.title = element_text(size = 24, 
                                  face = "bold",
                                  color = "#003366", 
                                  hjust = 0.5, 
                                  vjust = 0.5,
                                  margin = margin(t = 5, b = 5)),
        legend.position = c(0.06, 0.75),
        legend.text = element_text(size = 14),
        legend.title = element_text(size = 16, 
                                    face = "bold", 
                                    hjust = 0.5),
        legend.key = element_rect(fill = "transparent", 
                                  color = "transparent"),
        plot.margin = margin(t = 0, r = 0, 
                             b = 0, l = 0, 
                             unit = "cm")
        )

ggsave(str_c("Mapas/CAI_", num_ent, nombre_entidad, ".png"),
         plot = f_plt, height = 8, width = 12, dpi = 1000)


}

num_cai_mun(sel_edo = 32)

for (estado_para_mapa in 1:32){
  num_cai_mun(sel_edo = estado_para_mapa)
  print(str_c("Mapa_", estado_para_mapa, "/32 generado"))
}

Gráficas de proporción de CAI por tipo

sel_edo = 32

prop_cai_mun <- function(sel_edo){
  
prop_cai <- cai_mun %>% 
  filter(as.numeric(CVE_ENT) == sel_edo ) %>%
  filter(!is.na(tot_cai)) %>% 
  select(CVE_ENT, NOM_ENT, NOMGEO, DENUE, IMSS, ISSSTE, SNDIF) %>%
  pivot_longer(cols = c(DENUE, IMSS, ISSSTE, SNDIF), 
               names_to = "categoria", 
               values_to = "valor") %>% 
  group_by(CVE_ENT, NOMGEO) %>% 
  mutate(total_geo = sum(valor)) %>%           
  ungroup() %>% 
  mutate(porcentaje = round(valor / total_geo * 100,2)) 

nombre_entidad <- prop_cai$NOM_ENT %>% unique() 
num_ent <- prop_cai$CVE_ENT %>% unique()

orden_municipios <- prop_cai %>% 
  filter(categoria == "DENUE") %>% 
  arrange(porcentaje) %>% 
  pull(NOMGEO)

prop_cai <- prop_cai %>%  filter(porcentaje > 0)
  

plt_prop_mun <-ggplot(prop_cai,
                aes(x = factor(NOMGEO, 
                               levels = orden_municipios),
                    y = porcentaje,
                    fill = categoria)) +
  geom_bar(stat = "identity") +
  geom_text(aes(label = ifelse(porcentaje >= 6,
                               sprintf("%.2f%%", porcentaje), "")),
            position = position_stack(vjust = 0.5),
            size = 3.5,
            color = "white",
            fontface = "bold") +
  labs(title = nombre_entidad,
       subtitle = "Porcentaje de CAI en los municipios por categoría",
       y = "Porcentaje (%)") +
  coord_flip() +
  scale_fill_manual(values = c("DENUE" = "#536493",
                               "IMSS" = "#CC99FF",
                               "ISSSTE" = "#EBB452",
                               "SNDIF" = "#0099CC"),
                    labels = c("DENUE" = "Privados",
                               "IMSS" = "IMSS",
                               "ISSSTE" = "ISSSTE",
                               "SNDIF" = "SNDIF")) +
  scale_color_identity() +
  theme_void() +
  theme(text = element_text(color = "#22211d"),
        axis.text.y = element_text(size = 11, 
                                   hjust = 1, 
                                   face = "bold",
                                   margin = margin(t = 0, 
                                                   r = -1, 
                                                   b = 0, 
                                                   l = 0, 
                                                   unit = "cm")),
        legend.position = "top",
        legend.text = element_text(size = 11),
        legend.title = element_blank(),
        plot.title = element_text(size = 24, 
                                  face = "bold", 
                                  color = "#003366", 
                                  hjust = 0, 
                                  vjust = 0.5,
                                  margin = margin(t = 5, b = 5)),
        plot.subtitle = element_text(size = 20, 
                                     face = "bold",
                                     color = "#4e4d47", 
                                     hjust = 0, 
                                     vjust = 0.5,
                                     margin = margin(t = 0, 
                                                     b = 1, 
                                                     unit = "cm")),
        plot.margin = margin(t = 0, 
                             r = 0, 
                             b = 0, 
                             l = 0.5, 
                             unit = "cm")
        )

ggsave(str_c("Mapas/Prop CAI_", num_ent, nombre_entidad, ".svg"),
         plot = plt_prop_mun, height = 8, width = 12, dpi = 1000)
}

prop_cai_mun(sel_edo = 32)

for (estado_para_barra in 1:32){
  prop_cai_mun(sel_edo = estado_para_barra)
  print(str_c("Grafico_", estado_para_barra, "/32 generado"))
}

Entidades federativas con muchos municipios

Los gráficos de entidades federativas con muchos municipios se tienen que dividir para poder visualizar correctamente los datos. Las siguientes entidades federativas se dividen en:

  • Puebla y Edo. Mex: 4 gráficos

  • Chiapas, Jalisco y Michoacán: 3 gráficos

  • Hidalgo: 2 gráficos

prop_cai <- cai_mun %>% 
  filter(as.numeric(CVE_ENT) == 11) %>% #aquí se debe indicar el número del estado
  filter(!is.na(tot_cai)) %>% 
  select(CVE_ENT, NOM_ENT, NOMGEO, DENUE, IMSS, ISSSTE, SNDIF) %>%  
  pivot_longer(cols = c(DENUE, IMSS, ISSSTE, SNDIF), 
               names_to = "categoria", 
               values_to = "valor") %>% 
  group_by(CVE_ENT, NOMGEO) %>% 
  mutate(total_geo = sum(valor)) %>%           
  ungroup() %>% 
  mutate(porcentaje = round(valor / total_geo * 100,2)) 

nombre_entidad <- prop_cai$NOM_ENT %>% unique() 
num_ent <- prop_cai$CVE_ENT %>% unique()

orden_municipios <- prop_cai %>% 
  filter(categoria == "DENUE") %>% 
  arrange(porcentaje) %>% 
  pull(NOMGEO)

prop_cai <- prop_cai %>%  filter(porcentaje > 0)

num_municipios <- length(orden_municipios)

mun_split <- split(orden_municipios, 
                   ceiling(seq_along(orden_municipios) / (num_municipios / 2)))

crear_grafico <- function(municipios, indice) {
  plt <- ggplot(prop_cai %>% filter(NOMGEO %in% municipios),
                aes(x = factor(NOMGEO, levels = municipios),
                    y = porcentaje,
                    fill = categoria)) +
    geom_bar(stat = "identity") +
    geom_text(aes(label = ifelse(porcentaje >= 6,
                                 sprintf("%.2f%%", porcentaje), "")),
              position = position_stack(vjust = 0.5),
              size = 3.5, color = "white", fontface = "bold") +
    labs(title = nombre_entidad,
         subtitle = paste("Porcentaje de CAI en los municipios por categoría (",
                          indice, " de 2)", sep = ""),
         y = "Porcentaje (%)") +
    coord_flip() +
    scale_fill_manual(values = c("DENUE" = "#536493",
                                 "IMSS" = "#CC99FF",
                                 "ISSSTE" = "#EBB452",
                                 "SNDIF" = "#0099CC"),
                      labels = c("DENUE" = "Privados",
                                 "IMSS" = "IMSS",
                                 "ISSSTE" = "ISSSTE",
                                 "SNDIF" = "SNDIF")) +
    theme_void() +
    theme(text = element_text(color = "#22211d"),
          axis.text.y = element_text(size = 11, hjust = 1, face = "bold",
                                     margin = margin(t = 0, 
                                                     r = -1, 
                                                     b = 0, 
                                                     l = 0, 
                                                     unit = "cm")),
          legend.position = "top",
          legend.text = element_text(size = 11),
          legend.title = element_blank(),
          plot.title = element_text(size = 24, 
                                    face = "bold",
                                    color = "#003366", 
                                    hjust = 0, 
                                    vjust = 0.5,
                                    margin = margin(t = 5, b = 5)),
          plot.subtitle = element_text(size = 20, 
                                       face = "bold",
                                       color = "#4e4d47", 
                                       hjust = 0, 
                                       vjust = 0.5,
                                       margin = margin(t = 0, 
                                                       b = 1, 
                                                       unit = "cm")),
          plot.margin = margin(t = 0, 
                               r = 0, 
                               b = 0, 
                               l = 0.5, 
                               unit = "cm")
          )
  
  ggsave(str_c("Mapas/Prop CAI_", num_ent, nombre_entidad, "_", indice, ".svg"),
         plot = plt, height = 8, width = 12, dpi = 1000)
}

# Esta parte se modifica según la entidad federativa y el número de gráficos que se deben generar
crear_grafico(mun_split[[2]], 1)
crear_grafico(mun_split[[1]], 2)
# crear_grafico(mun_split[[2]], 3)
# crear_grafico(mun_split[[1]], 4)
LS0tCnRpdGxlOiAiQ2VudHJvcyBkZSBBdGVuY2nDs24gSW5mYW50aWwgcG9yIG11bmljaXBpbyIKYXV0aG9yOiAiTWFydmluIEl2YW4gVHJlam8gTWVuZGV6IgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIHRoZW1lOiBqb3VybmFsCiAgICBkZl9wcmludDogcGFnZWQKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICBtYWluZm9udDogQmllcnN0YWR0CiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgcGRmX2RvY3VtZW50OgogICAgdG9jOiB0cnVlCi0tLQoKIyBMaWJyZXLDrWFzIHV0aWxpemFkYXMKCmBgYHtyLCBlY2hvID0gVFJVRSwgcmVzdWx0cz0naGlkZScsd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KaWYgKCFyZXF1aXJlKHBhY21hbikpIGluc3RhbGwucGFja2FnZXMoInBhY21hbiIpCmxpYnJhcnkocGFjbWFuKSA7IHBfbG9hZCgicmVhZHhsIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAiZHBseXIiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICJ0aWR5dmVyc2UiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICJ3cml0ZXhsIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAic2YiLAogICAgICAgICAgICAgICAgICAgICAgICAgImxlYWZsZXQiLAogICAgICAgICAgICAgICAgICAgICAgICAgInBsb3RseSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAiZ2dwbG90MiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAidGlkeXIiLAogICAgICAgICAgICAgICAgICAgICAgICAgInBhdGNod29yayIsCiAgICAgICAgICAgICAgICAgICAgICAgICAic3RyaW5nciIsCiAgICAgICAgICAgICAgICAgICAgICAgICAic3ZnbGl0ZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAic2NhbGVzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICJ2aXJpZGlzIikKYGBgCgojIENvbnN0cnVjY2nDs24gZGUgbGFzIGJhc2VzCgojIyBDYXJnYSBkZSBhcmNoaXZvIHkgc2VsZWNjacOzbiBkZSB2YXJpYWJsZXMKCkxhIGJhc2UgcXVlIHV0aWxpemFyZW1vcyBjb250aWVuZSBpbmZvcm1hY2nDs24gZGUgbG9zIENlbnRyb3MgZGUgQXRlbmNpw7NuIEluZmFudGlsIChDQUkpIGRlIGN1YXRybyBmdWVudGVzIGRpc3RpbnRhczogU05ESUYsIERFTlVFLCBJTVNTIGUgSVNTU1RFLiBFc3RhIGJhc2UgY29udGllbmUgNDcgdmFyaWFibGVzLCBkZSBsYXMgY3VhbGVzIHV0aWxpemFyZW1vcyAyNSBxdWUgY29udGllbmVuIGxhIGluZm9ybWFjacOzbiBxdWUgbmVjZXNpdGFtb3MKCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQpiYXNlX2NhaSA8LSByZWFkX2V4Y2VsKCJCQVNFX0ZJTkFMX0NBSS54bHN4IiwgCiAgICAgICAgICAgICAgICAgICAgICAgc2hlZXQgPSAiQ0FJX0ZJTkFMIikgJT4lIAogIG11dGF0ZSgKICAgIGJhc2UgPSBjYXNlX3doZW4oYmFzZSA9PSAiU05JREYiIH4gIlNORElGIiwKICAgICAgICAgICAgICAgICAgICAgVFJVRSB+IGJhc2UpLAogICAgdGVsZWZvbm8gPSBhcy5jaGFyYWN0ZXIodGVsZWZvbm8pLAogICAgY29ycmVvZWxlYyA9IGFzLmNoYXJhY3Rlcihjb3JyZW9lbGVjKSwKICAgICAgICAgd3d3ID0gYXMuY2hhcmFjdGVyKHd3dyksCiAgICAgICAgIGxhdGl0dWQgPSBhcy5udW1lcmljKGxhdGl0dWQpLAogICAgICAgICBsb25naXR1ZCA9IGFzLm51bWVyaWMobG9uZ2l0dWQpKSAlPiUgCiAgc2VsZWN0KC1jb2RpZ29fYWN0LCAtcGVyX29jdTotbWFuemFuYSwtdGlwb1VuaUVjbywgLWZlY2hhX2FsdGEpCgpzdHIoYmFzZV9jYWkpCmBgYAoKIyMgRGVzY3JpcGNpw7NuIGRlIHZhcmlhYmxlcwoKKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKwp8IFZhcmlhYmxlcyAgICAgICAgICAgICAgICAgICAgICAgICB8IERlc2NyaXBjacOzbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAorPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0rPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0rCnwgYmFzZSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgRnVlbnRlIGRlIGluZm9ybWFjacOzbiBhIGxhIHF1ZSBwZXJ0ZW5lY2UgZWwgcmVnaXN0cm8gKFNORElGLCBERU5VRSwgSU1TUyBvIElTU1NURSkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8CistLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSsKfCBjdmVfZW50LCBub21fZW50ICAgICAgICAgICAgICAgICAgfCBDbGF2ZSB5IG5vbWJyZSBkZSBlbnRpZGFkIGZlZGVyYXRpdmEgZW4gZG9uZGUgc2UgZW5jdWVudHJhIGVsIENBSS4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAorLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rCnwgY3ZlX211biwgbm9tX211biAgICAgICAgICAgICAgICAgIHwgQ2xhdmUgeSBub21icmUgZGVsIG11bmljaXBpbyBlbiBkb25kZSBzZSBlbmN1ZW50cmEgZWwgQ0FJLiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKwp8IGN2ZV9pbnRlZ3JhZGEgICAgICAgICAgICAgICAgICAgICB8IENsYXZlIMO6bmljYSwgc2UgY29tcG9uZSBwb3IgbGEgY2xhdmUgZGUgZW50aWRhZCB5IGxhIGRlIG11bmljaXBpby4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAorLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rCnwgbm9tX2NhaV9ndWFyZCAgICAgICAgICAgICAgICAgICAgIHwgTm9tYnJlIGRlbCBDQUkgbyBndWFyZGVyw61hICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8CistLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSsKfCB0aXBvX2FzZW50LCBub21fYXNlbnQsIHRpcG9fdmlhbCwgfCBJbmZvcm1hY2nDs24gZGUgdWJpY2FjacOzbiBkZWwgQ0FJOiB0aXBvIHkgbm9tYnJlIGRlIGFzZW50YW1pZW50bywgdGlwbyB5IG5vbWJyZSBkZSB2aWFsaWRhZCwgbsO6bWVybyBleHRlcmlvciBkZWwgQ0FJIHkgY8OzZGlnbyBwb3N0YWwuIHwKfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAp8IG5vbV92aWFsLCBudW1fZXh0LCBjcCAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8CistLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSsKfCBub21icmVfYWN0ICAgICAgICAgICAgICAgICAgICAgICAgfCBUaXBvIGRlIENBSSAocMO6YmxpY28gbyBwcml2YWRvKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKwp8IHRlbGVmb25vLCAgICAgICAgICAgICAgICAgICAgICAgICB8IEluZm9ybWFjacOzbiBkZSBjb250YWN0byBkZWwgQ0FJOiB0ZWzDqWZvbm8sIGNvcnJlbyBlbGVjdHLDs25pY28geSBww6FnaW5hIHdlYi4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAp8ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8CnwgY29ycmVvZWxlYywgd3d3ICAgICAgICAgICAgICAgICAgIHwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKwp8IGxhdGl0dWQsICAgICAgICAgICAgICAgICAgICAgICAgICB8IExhdGl0dWQgeSBsb25naXR1ZCBkZSB1YmljYWNpw7NuIGRlbCBDQUkuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAp8ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8CnwgbG9uZ2l0dWQgICAgICAgICAgICAgICAgICAgICAgICAgIHwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKwp8IHBvYl9lc3QsIGhvbV9lc3QsIG11al9lc3QgICAgICAgICB8IFByb3llY2Npw7NuIGRlIHBvYmxhY2nDs24gZGUgMCBhIDUgYcOxb3MgYSBuaXZlbCBlc3RhdGFsIHRvdGFsIHkgcG9yIHNleG8gKGhvbWJyZSwgbXVqZXIpLiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8CistLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSstLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSsKfCBwb2JfbXVuLCBob21fbXVuLCBtdWpfbXVuICAgICAgICAgfCBQcm95ZWNjacOzbiBkZSBwb2JsYWNpw7NuIGRlIDAgYSA0IGHDsW9zIGEgbml2ZWwgbXVuaWNpcGFsIHRvdGFsIHkgcG9yIHNleG8gKGhvbWJyZSwgbXVqZXIpLiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAorLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0rCgojIyBEYXRvcyBwb3IgbXVuaWNpcGlvCgpgYGB7ciwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KIyBQYXJhIG9idGVuZXIgZWwgbsO6bWVybyB5IHRpcG8gZGUgQ0FJIHBvciBtdW5pY2lwaW8sIHByaW1lcm8gYWdydXBhbW9zIHBvciBjbGF2ZSB5IHRpcG8gZGUgQ0FJIHBhcmEgZGVzcHXDqXMgc3VtYXIgcG9yIGNhZGEgZ3J1cG8gY3JlYWRvLiBQb3N0ZXJpb3JtZW50ZSB0cmFuc2Zvcm1hbW9zIGxhIGJhc2UgZGUgZm9ybWF0byBsYXJnbyAodW5hIGZpbGEgcG9yIGNhZGEgdGlwbyBkZSBDQUkgZW4gY2FkYSBtdW5pY2lwaW8pIGEgZm9ybWF0byBhbmNobyAodW5hIGZpbGEgcG9yIG11bmljaXBpbyBjb24gdW5hIGNvbHVtbmEgcG9yIGNhZGEgdGlwbyBkZSBDQUkpLgoKdGlwb19jYWkgPC0gYmFzZV9jYWkgJT4lIAogIGdyb3VwX2J5KGN2ZV9pbnRlZ3JhZGEsIGJhc2UpICU+JSAKICBzdW1tYXJpemUoY291bnQgPSBuKCkpICU+JSAKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gYmFzZSwgCiAgICAgICAgICAgICAgdmFsdWVzX2Zyb20gPSBjb3VudCwgCiAgICAgICAgICAgICAgdmFsdWVzX2ZpbGwgPSAwKQoKIyBBIGxhIGJhc2UgY3JlYWRhLCBzZSBhZ3JlZ2EgdW5hIHZhcmlhYmxlIHF1ZSBzdW1lIGVsIHRvdGFsIGRlIENBSSBlbiBlbCBtdW5pY2lwaW8KdGlwb19jYWkkdG90X2NhaSA8LSByb3dTdW1zKHRpcG9fY2FpWywyOjVdKSAKdGlwb19jYWkkY3ZlX2VudCA8LSBzdWJzdHIodGlwb19jYWkkY3ZlX2ludGVncmFkYSwgMSwgMikKCiMgUGFyYSBvYnRlbmVyIGxvcyB2YWxvcmVzIGRlIHBvYmxhY2nDs24sIHByaW1lcm8gc2Ugc2VsZWNjaW9uYW4gbGFzIHZhcmlhYmxlcyB5IGx1ZWdvIHNlIGZpbHRyYW4gbG9zIHZhbG9yZXMgw7puaWNvcyBlbiBjdmVfaW50ZWdyYWRhCnBvYmxhY2lvbmVzIDwtIGJhc2VfY2FpICU+JQogIHNlbGVjdChjdmVfaW50ZWdyYWRhLCBub21fZW50LCBub21fbXVuLCBwb2JfZXN0Om11al9tdW4pICU+JSAKICBkaXN0aW5jdChjdmVfaW50ZWdyYWRhLCAua2VlcF9hbGwgPSBUUlVFKQoKI0xhIGJhc2UgZmluYWwgc2Ugb2J0aWVuZSB1bmllbmRvIGxhcyBkb3MgYW50ZXJpb3JlcwpjYWlfbXVuIDwtIGxlZnRfam9pbihwb2JsYWNpb25lcywgCiAgICAgICAgICAgICAgICAgICAgIHRpcG9fY2FpLCAKICAgICAgICAgICAgICAgICAgICAgYnkgPSAiY3ZlX2ludGVncmFkYSIpICU+JSAKICBhcnJhbmdlKGN2ZV9pbnRlZ3JhZGEpCmBgYAoKTGEgYmFzZSBkZSBkYXRvcyBjcmVhZGEgY29udGllbmUgaW5mb3JtYWNpw7NuIHBvciBtdW5pY2lwaW8gZGUgbGEgcHJveWVjY2nDs24gZGUgcG9ibGFjacOzbiBhIG5pdmVsIGVzdGF0YWwgeSBtdW5pY2lwYWwsIGFkZW3DoXMgZGVsIG7Dum1lcm8geSB0aXBvIGRlIENBSS4KCmBgYHtyfQpoZWFkKGNhaV9tdW4pCgp3cml0ZV94bHN4KGNhaV9tdW4sIHBhdGggPSAiY2FpX211bi54bHN4IikKYGBgCgojIyBEYXRvcyBwb3IgZW50aWRhZCBmZWRlcmF0aXZhCgpgYGB7cn0KIyBVdGlsaXphbmRvIGxhIGJhc2UgZGUgQ0FJIHBvciBtdW5pY2lwaW8sIHByaW1lcm8gYWdydXBhbW9zIHBvciBlbnRpZGFkIHkgZGVzcHXDqXMgc3VtYW1vcyBsYXMgZmlsYXMgcG9yIGNhZGEgdGlwbyBkZSBDQUkuCmFncmVnYWRvcyA8LSBjYWlfbXVuICU+JQogIGdyb3VwX2J5KGN2ZV9lbnQpICU+JSAKICBzdW1tYXJpemUoU05ESUYgPSBzdW0oU05ESUYsIG5hLnJtPVQpLAogICAgICAgICAgICBERU5VRSA9IHN1bShERU5VRSwgbmEucm09VCksCiAgICAgICAgICAgIElNU1MgPSBzdW0oSU1TUywgbmEucm09VCksCiAgICAgICAgICAgIElTU1NURSA9IHN1bShJU1NTVEUsIG5hLnJtPVQpKQoKY2FpX2VmIDwtIGNhaV9tdW4gJT4lIAogIHNlbGVjdChjdmVfZW50LCBub21fZW50LCBwb2JfZXN0KSAlPiUgCiAgbGVmdF9qb2luKGFncmVnYWRvcywgYnkgPSAiY3ZlX2VudCIpICU+JSAKICBkaXN0aW5jdChjdmVfZW50LCAua2VlcF9hbGwgPSBUUlVFKQoKIyBBc2ltaXNtbywgYWdyZWdhbW9zIHVuYSBjb2x1bW5hIHF1ZSBzdW1lIGVsIHRvdGFsIGRlIENBSSBlbiBsYSBlbnRpZGFkCmNhaV9lZiR0b3RfY2FpID0gcm93U3VtcyhjYWlfZWZbLDQ6N10pCmNhaV9lZiR0YXNhID0gY2FpX2VmJHRvdF9jYWkvKGNhaV9lZiRwb2JfZXN0LzEwMDApCgpoZWFkKGNhaV9lZikKCiMgRXhwb3J0YW1vcyBsYSBiYXNlIGEgRXhjZWwKd3JpdGVfeGxzeChjYWlfZWYsIHBhdGggPSAiY2FpX2VmLnhsc3giKQpgYGAKCiMgTWFwYXMKCiMjIEluZm9ybWFjacOzbiBnZW9lc3BhY2lhbAoKTGEgaW5mb3JtYWNpw7NuIGdlb2VzcGFjaWFsIHBhcmEgZWxhYm9yYXIgbG9zIG1hcGFzIGxhIHRvbWFyZW1vcyBkZWwgTWFyY28gR2VvZXN0YWTDrXN0aWNvIGRlIElORUdJLiBQYXJhIGVsbG8gdGVuZW1vcyBkb3MgYXJjaGl2b3M6CgotICAgRXN0YXRhbDogW2BodHRwOi8vd3d3LmNvbmFiaW8uZ29iLm14L2luZm9ybWFjaW9uL2dpcy9tYXBzL2dlby9kZXN0MjJndy56aXBgXShodHRwOi8vd3d3LmNvbmFiaW8uZ29iLm14L2luZm9ybWFjaW9uL2dpcy9tYXBzL2dlby9kZXN0MjJndy56aXApCgotICAgTXVuaWNpcGFsOiBbYGh0dHA6Ly93d3cuY29uYWJpby5nb2IubXgvaW5mb3JtYWNpb24vZ2lzL21hcHMvZ2VvL211bjIyZ3cuemlwYF0oaHR0cDovL3d3dy5jb25hYmlvLmdvYi5teC9pbmZvcm1hY2lvbi9naXMvbWFwcy9nZW8vbXVuMjJndy56aXApCgpgYGB7cn0KIyBMb3MgYXJjaGl2b3MgLnNocCBjb250aWVuZW4gbGEgaW5mb3JtYWNpw7NuIGdlb2dyw6FmaWNhIGRlIGxvcyBwb2zDrWdvbm9zIHBvciBtdW5pY2lwaW8geSBwb3IgZW50aWRhZCBmZWRlcmF0aXZhIHF1ZSB1bmlyZW1vcyBhIHN1cyByZXNwZWN0aXZhcyBiYXNlcyBkZSBDQUkKZWZfc2hwIDwtIHJlYWRfc2YoImdlb19lZi9kZXN0MjJndy5zaHAiKQoKbXVuX3NocCA8LSByZWFkX3NmKCJnZW9fbXVuL211bjIyZ3cuc2hwIikKCiMgQ29uIGVzdG9zIGNvbWFuZG9zIHZlcmlmaWNhbW9zIHF1ZSBsYSBpbmZvcm1hY2nDs24gY29ycmVzcG9uZGEgYSBpbmZvcm1hY2nDs24gZ2VvZ3LDoWZpY2EKcGxvdChlZl9zaHAsIG1heC5wbG90ID0gMikKIApwbG90KG11bl9zaHAsIG1heC5wbG90ID0gMikKCiMgUG9yIMO6bHRpbW8sIHVuaW1vcyBsYSBpbmZvcm1hY2nDs24gZ2VvZ3LDoWZpY2EgYSBjYWRhIGJhc2UgZGUgZGF0b3MgeSBlbGltaW5hbW9zIHZhcmlhYmxlcyByZXBldGlkYXMKY2FpX2VmIDwtIGxlZnRfam9pbihlZl9zaHAsIAogICAgICAgICAgICAgICAgICAgIGNhaV9lZiwgCiAgICAgICAgICAgICAgICAgICAgYnkgPSBjKCJDVkVHRU8iID0gImN2ZV9lbnQiKSkgJT4lIAogIHNlbGVjdCgtQ1ZFX0NBUCwtTk9NX0NBUCwgLW5vbV9lbnQpIAoKY2FpX2VmIDwtIGNhaV9lZiAlPiUgbXV0YXRlKE5PTV9FTlQgPSBzdHJfdHJpbShOT01fRU5UKSkKCmNhaV9tdW4gPC0gbGVmdF9qb2luKG11bl9zaHAsIAogICAgICAgICAgICAgICAgICAgICBjYWlfbXVuLCAKICAgICAgICAgICAgICAgICAgICAgYnkgPSBjKCJDVkVHRU8iID0gImN2ZV9pbnRlZ3JhZGEiKSkgJT4lIAogIHNlbGVjdCgtbm9tX2VudCwgLW5vbV9tdW4sIC1jdmVfZW50KQoKYGBgCgojIyBUYXNhIENBSSBwb3IgbmnDsWFzLCBuacOxb3MgeSBhZG9sZXNjZW50ZXMgYSBuaXZlbCBuYWNpb25hbAoKYGBge3IsIHdhcm5pbmc9RkFMU0V9CnBsdF90YXNhIDwtIGNhaV9lZiAlPiUgCiAgbXV0YXRlKGdwb190YXNhID0gY2FzZV93aGVuKHRhc2EgPCAwLjUgfiAiMC4wIC0gMC41IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmV0d2Vlbih0YXNhLCAwLjUsMSkgfiAiMC41IC0gMS4wIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmV0d2Vlbih0YXNhLCAxLDEuNSkgfiAiMS4wIC0gMS41IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGFzYSA+IDIgfiAiTWF5b3IgYSAyLjAiKSkgJT4lIAogIGdncGxvdChhZXMoZmlsbCA9IGdwb190YXNhKSkgKyAKICBnZW9tX3NmKGNvbG9yID0gInRyYW5zcGFyZW50IikgKyAKICBnZW9tX3NmKGRhdGEgPSBlZl9zaHAsIGZpbGwgPSBOQSwgbGluZXdpZHRoID0gMC40MykgKyAKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIjAuMCAtIDAuNSIgPSAiI0QyQURDRCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIwLjUgLSAxLjAiID0gIiM2MjlEQ0EiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMS4wIC0gMS41IiA9ICIjMjA2RDlGIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1heW9yIGEgMi4wIiA9ICIjMTUzNDY4IiksCiAgICAgICAgICAgICAgICAgICAgICBndWlkZSA9IGd1aWRlX2xlZ2VuZCgKICAgICAgICAgICAgICAgICAgICAgICAga2V5aGVpZ2h0ID0gdW5pdCg2LCB1bml0cyA9ICJtbSIpLAogICAgICAgICAgICAgICAgICAgICAgICBrZXl3aWR0aCA9IHVuaXQoNiwgdW5pdHMgPSAibW0iKSwKICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWwucG9zaXRpb24gPSAibGVmdCIsCiAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlLnBvc2l0aW9uID0gInRvcCIsCiAgICAgICAgICAgICAgICAgICAgICAgIG5jb2wgPSAxKSkgKyAKICBzY2FsZV94X2NvbnRpbnVvdXMoZXhwYW5kID0gZXhwYW5zaW9uKGMoMC4xOSwgMCkpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGV4cGFuc2lvbihjKDAuMTAsIDApKSkgKwogIGxhYnModGl0bGUgPSAiTsO6bWVybyBkZSBDQUkgcG9yIGNhZGEgbWlsIG5pw7FhcyB5IG5pw7FvcyBkZSAwIGEgNSBhw7FvcyIpICsgCiAgdGhlbWVfdm9pZCgpICsgCiAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChjb2xvciA9ICIjMjIyMTFkIiksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gYygwLjgsIDAuODUpLAogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIHBsb3QubWFyZ2luID0gbWFyZ2luKHQgPSAwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICByID0gMCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYiA9IDAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGwgPSAwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1bml0ID0gImNtIiksCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjQsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFjZSA9ICJib2xkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gIiMwMDMzNjYiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhqdXN0ID0gMC41LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZqdXN0ID0gMC41LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFyZ2luID0gbWFyZ2luKHQgPSAwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiID0gMSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdW5pdCA9ICJjbSIpKQogICkKCnBsdF90YXNhX2IgPC0gY2FpX2VmICU+JSBhcnJhbmdlKGRlc2ModGFzYSkpICU+JQogIG11dGF0ZShncG9fdGFzYSA9IGNhc2Vfd2hlbih0YXNhIDwgMC41IH4gIjAuMCAtIDAuNSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJldHdlZW4odGFzYSwgMC41LDEpIH4gIjAuNSAtIDEuMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJldHdlZW4odGFzYSwgMSwxLjUpIH4gIjEuMCAtIDEuNSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRhc2EgPiAyIH4gIk1heW9yIGEgMi4wIiksCiAgICAgICAgIE5PTV9FTlQgPSBjYXNlX3doZW4oCiAgICAgICAgICAgTk9NX0VOVCA9PSAiTWljaG9hY8OhbiBkZSBPY2FtcG8iIH4gIk1pY2hvYWPDoW4iLAogICAgICAgICAgIE5PTV9FTlQgPT0gIkNvYWh1aWxhIGRlIFphcmFnb3phIiB+ICJDb2FodWlsYSIsCiAgICAgICAgICAgTk9NX0VOVCA9PSAiVmVyYWNydXogZGUgSWduYWNpbyBkZSBsYSBMbGF2ZSIgCiAgICAgICAgICAgfiAiVmVyYWNydXoiLCAKICAgICAgICAgICBUUlVFIH4gTk9NX0VOVCkpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSByZW9yZGVyKE5PTV9FTlQsIC10YXNhKSwgCiAgICAgICAgICAgICB5ID0gdGFzYSwgCiAgICAgICAgICAgICBjb2xvciA9IGdwb190YXNhKSkgKwogIGdlb21fcG9pbnQoc2l6ZSA9IDMpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCAKICAgICAgICAgICAgIGNvbG9yID0gIiM0ZTRkNDciLCAKICAgICAgICAgICAgIGxpbmV3aWR0aCA9IDAuNSkgKwogIGdlb21fc2VnbWVudChhZXMoeCA9IE5PTV9FTlQsIAogICAgICAgICAgICAgICAgICAgeGVuZCA9IE5PTV9FTlQsIAogICAgICAgICAgICAgICAgICAgeSA9IDAsIAogICAgICAgICAgICAgICAgICAgeWVuZCA9IHRhc2EpKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHJvdW5kKHRhc2EsMikpLAogICAgICAgICAgICBpemUgPSAzLCBoanVzdCA9IC0wLjgpICsKICBjb29yZF9mbGlwKCkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKCIwLjAgLSAwLjUiID0gIiNEMkFEQ0QiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMC41IC0gMS4wIiA9ICIjNjI5RENBIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjEuMCAtIDEuNSIgPSAiIzIwNkQ5RiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJNYXlvciBhIDIuMCIgPSAiIzE1MzQ2OCIpKSArCiAgICB0aGVtZV92b2lkKCkgKwogICAgdGhlbWUoYXhpcy5saW5lLnggPWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIGF4aXMubGluZS55PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIGF4aXMudGl0bGUueD1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgICBheGlzLnRpdGxlLnk9ZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGp1c3QgPSAxLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZhY2UgPSAiYm9sZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXJnaW4gPSBtYXJnaW4odCA9IDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgciA9IC0xLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGIgPSAwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGwgPSAwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVuaXQgPSAiY20iKSksCiAgICAgICAgICBheGlzLnRpY2tzLnggPWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIGF4aXMudGlja3MueT1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgICB0ZXh0ID0gZWxlbWVudF90ZXh0KGNvbG9yID0gIiMyMjIxMWQiKQogICAgICAgICAgKSArCiAgbGFicyhjb2xvciA9IE5VTEwpCgpjb21iaW5lZF9wbG90IDwtIHBsdF90YXNhICsgaW5zZXRfZWxlbWVudChwbHRfdGFzYV9iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVmdCA9IDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJvdHRvbSA9IDAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByaWdodCA9IDAuOSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvcCA9MC42KQpnZ3NhdmUoc3RyX2MoIk1hcGFzL1Rhc2EgQ0FJIE5hY2lvbmFsX2NvbWIiLCIucG5nIiksCiAgICAgICBoZWlnaHQgPSA4LCB3aWR0aCA9IDEyLCBkcGkgPSAxMDAwKQoKY29tYmluZWRfcGxvdApgYGAKCiMjIE7Dum1lcm8gZGUgQ0FJIHBvciBtdW5pY2lwaW8KCmBgYHtyfQojIE1hcGEgbmFjaW9uYWwgY29uIGVsIHRvdGFsIGRlIENBSQpwbHRfbXVuIDwtIGNhaV9tdW4gJT4lIAogIG11dGF0ZShjYXRfY2FpID0gY3V0KHRvdF9jYWksCiAgICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gYygtSW5mLCAxMCwgMjAsIDMwLCBJbmYpLAogICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIjEtMTAiLCAiMTEtMjAiLCAiMjEtMzAiLCAiTcOhcyBkZSAzMCIpKSkgJT4lIAogIGdncGxvdChhZXMoZmlsbCA9IGNhdF9jYWkpKSArIAogIGdlb21fc2YoY29sb3IgPSAiIzVGNUY1RiIpICsgCiAgZ2VvbV9zZihkYXRhID0gZWZfc2hwLCBmaWxsID0gTkEsIGxpbmV3aWR0aCA9IDAuNSkgKyAKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIjEtMTAiID0gIiNEMkFEQ0QiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMTEtMjAiID0gIiM2MjlEQ0EiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMjEtMzAiID0gIiMyMDZEOUYiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTcOhcyBkZSAzMCIgPSAiIzE1MzQ2OCIpLAogICAgICAgICAgICAgICAgICAgICAgbmEudmFsdWUgPSAiIzdGN0Y3RiIsCiAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCIxLTEwIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIxMS0yMCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMjEtMzAiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk3DoXMgZGUgMzAiLCAiTmluZ3VubyIpLAogICAgICAgICAgICAgICAgICAgICAgZ3VpZGUgPSBndWlkZV9sZWdlbmQoCiAgICAgICAgICAgICAgICAgICAgICAgIGtleWhlaWdodCA9IHVuaXQoNiwgdW5pdHMgPSAibW0iKSwKICAgICAgICAgICAgICAgICAgICAgICAga2V5d2lkdGggPSB1bml0KDYsIHVuaXRzID0gIm1tIiksCiAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsLnBvc2l0aW9uID0gInJpZ2h0IiwKICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGUucG9zaXRpb24gPSAidG9wIiwKICAgICAgICAgICAgICAgICAgICAgICAgbmNvbCA9IDEpKSArIAogIHNjYWxlX3hfY29udGludW91cyhleHBhbmQgPSBleHBhbnNpb24oYygwLjE5LCAwKSkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gZXhwYW5zaW9uKGMoMC4xMCwgMCkpKSArCiAgbGFicyh0aXRsZSA9ICJOw7ptZXJvIGRlIENBSSBhIG5pdmVsIG11bmljaXBhbCIsCiAgICAgICBmaWxsID0gIk7Dum1lcm8gZGUgQ0FJIikgKwogIHRoZW1lX3ZvaWQoKSArIAogIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoY29sb3IgPSAiIzIyMjExZCIpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC44NSwgMC43NSksCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSwKICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFjZSA9ICJib2xkIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhqdXN0ID0gMC41KSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAyNCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYWNlID0gImJvbGQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSAiIzAwMzM2NiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGp1c3QgPSAwLjUsIHZqdXN0ID0gMC41LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFyZ2luID0gbWFyZ2luKHQgPSAwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiID0gMSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdW5pdCA9ICJjbSIpKSwKICAgICAgICBwbG90Lm1hcmdpbiA9IG1hcmdpbih0ID0gMC4xLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICByID0gMC4yLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiID0gMC41LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsID0gMCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdW5pdCA9ICJjbSIpCiAgICAgICAgKQogIAp0b3RhbGVzX2NhaSA8LSBjYWlfZWYgJT4lIAogIHN0X3NldF9nZW9tZXRyeShOVUxMKSAlPiUgCiAgc3VtbWFyaXNlKFByaXZhZG9zID0gc3VtKERFTlVFLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICBJTVNTID0gc3VtKElNU1MsIG5hLnJtID0gVFJVRSksCiAgICAgICAgICAgIElTU1NURSA9IHN1bShJU1NTVEUsIG5hLnJtID0gVFJVRSksCiAgICAgICAgICAgIFNORElGID0gc3VtKFNORElGLCBuYS5ybSA9IFRSVUUpKSAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IGV2ZXJ5dGhpbmcoKSwgCiAgICAgICAgICAgICAgIG5hbWVzX3RvID0gImNhdGVnb3JpYSIsIAogICAgICAgICAgICAgICB2YWx1ZXNfdG8gPSAidG90YWwiKSAlPiUgCiAgbXV0YXRlKHRleHRfY29sb3IgPSBpZmVsc2UoY2F0ZWdvcmlhID09ICJERU5VRSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICIjRkZGRkZGIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIiMyMjIxMWQiKSkKCnBsdF90b3Q8LWdncGxvdCh0b3RhbGVzX2NhaSwgCiAgICAgICAgICAgICAgICBhZXMoeCA9IHJlb3JkZXIoY2F0ZWdvcmlhLCAtdG90YWwpLCAKICAgICAgICAgICAgICAgICAgICB5ID0gdG90YWwsIAogICAgICAgICAgICAgICAgICAgIGZpbGwgPSBjYXRlZ29yaWEpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsKICBsYWJzKHRpdGxlID0gIk7Dum1lcm8gZGUgQ0FJIHBvciBjYXRlZ29yw61hIiwKICAgICAgIHkgPSAiTsO6bWVybyBkZSBDQUkiKSArCiAgY29vcmRfZmxpcCgpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJQcml2YWRvcyIgPSAiIzUzNjQ5MyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiSU1TUyIgPSAiI0NDOTlGRiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiSVNTU1RFIiA9ICIjRUJCNDUyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTTkRJRiIgPSAiIzAwOTlDQyIpKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IGNvbW1hKHRvdGFsKSwgY29sb3IgPSB0ZXh0X2NvbG9yKSwKICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9zdGFjayh2anVzdCA9IDAuNSksCiAgICAgICAgICAgIGhqdXN0ID0gLTAuMSwKICAgICAgICAgICAgc2l6ZSA9IDQsCiAgICAgICAgICAgIGNvbG9yID0gIiMyMjIxMWQiKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGxhYmVsX2NvbW1hKHNjYWxlID0gMWUtMywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1ZmZpeCA9ICJrIikpICsKICBzY2FsZV9jb2xvcl9pZGVudGl0eSgpICsKICB0aGVtZV92b2lkKCkgKyAKICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KGNvbG9yID0gIiMyMjIxMWQiKSwKICAgICAgICB0aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IC0wLjUsIGZhY2UgPSAiYm9sZCIpLAogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCwgaGp1c3QgPSAwKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSwKICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFjZSA9ICJib2xkIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhqdXN0ID0gMC41KSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYWNlID0gImJvbGQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhqdXN0ID0gMCksCiAgICAgICAgcGxvdC5tYXJnaW4gPSBtYXJnaW4odCA9IDAsIHIgPSAwLCBiID0gMCwgbCA9IDAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVuaXQgPSAiY20iKQogICAgICAgICkKCmNvbWJfcGx0X251bWNhaSA8LSBwbHRfbXVuICsgaW5zZXRfZWxlbWVudChwbHRfdG90LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlZnQgPSAwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYm90dG9tID0gMCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByaWdodCA9IDAuNywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b3AgPTAuNikKCmNvbWJfcGx0X251bWNhaQoKZ2dzYXZlKHN0cl9jKCJNYXBhcy9OdW0gQ0FJIE5hY2lvbmFsX2NvbWIiLCIucG5nIiksCiAgICAgICBoZWlnaHQgPSA4LCB3aWR0aCA9IDEyLCBkcGkgPSAxMDAwKQoKYGBgCgojIyBNYXBhcyBwb3IgZW50aWRhZCBmZWRlcmF0aXZhCgpEYWRhIGxhIGZvcm1hIGRlIGxhcyBlbnRpZGFkZXMgZmVkZXJhdGl2YXMsIHNlIGRlYmUgYWNvbW9kYXIgbGEgbGV5ZW5kYSBkZWwgZ3LDoWZpY28gcGFyYSBwdWVkYSB2aXN1YWxpemFyc2UgY29ycmVjdGFtZW50ZS4gQSBjb250aW51YWNpw7NuIHNlIHByZXNlbnRhbiBsb3MgdmFsb3JlcyBxdWUgc2UgZGViZW4gc3VzdGl0dWlyIGVuIGBsZWdlbmQucG9zaXRpb24gPSBjKClgCgp8IENWRV9FTlQgICAgICAgICAgICAgICAgICAgICAgICB8IGxlZ2VuZC5wb3NpdGlvbiB8CnwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLXwKfCAxOjQsIDExLCAxMzoxNiwgMTgsIDIxOjIzLCAgICAgfCBjKDAuMDYsIDAuNzUpICAgfAp8IDUsIDc6MTAsICAgICAgICAgICAgICAgICAgICAgICB8IGMoMS4xLCAwLjc1KSAgICB8CnwgMTIsIDE5LCAyMCwgMjQsIDI1LCAyNywgMjksIDMwIHwgYygwLjksIDAuODUpICAgIHwKfCAxNyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCBjKDAuMDMsIDAuODUpICAgfAp8IDI2LCAyOCAgICAgICAgICAgICAgICAgICAgICAgICB8IGMoMC4wNiwgMC42KSAgICB8CnwgNiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgYygwLjg1LCAwLjc1KSAgIHwKfCAzMSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfCBjKDAuMDYsIDAuNzUpICAgfAp8IDMyICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8IGMoMC4wMywgMC43NSkgICB8CgpFbiBlbCBjYXNvIGRlIENvbGltYSAoNikgeSBZdWNhdMOhbiAoMzEpLCBzZSB0aWVuZSBxdWUgcmVkdWNpciBsYSBzdXBlcmZpY2llIGdyYWZpY2FkYSwgZXN0byBzZSBoYWNlIGNvbiBlbCBjb21hbmRvIGBjb29yZF9zZih4bGltPSBjKCksIHlsaW09YygpKWAuIERlbnRybyBkZSBlc3RlIGNvbWFuZG8gc2UgY29sb2NhbiBsb3MgbMOtbWl0ZXMgaW5mZXJpb3IgeSBzdXBlcmlvciBkZSBYIHkgWSBwYXJhIGxvcyBjdWFsZXMgc2UgdmEgYSBncmFmaWNhciwgZXN0b3MgbMOtbWl0ZXMgc2Ugb2J0dXZpZXJvbiBkZSBHb29nbGUgTWFwcyB5IGNvcnJlc3BvbmRlbiBhIGxhIGxvbmdpdHVkIHkgbGF0aXR1ZCBnZW9ncsOhZmljYSBkZSBjYWRhIGVudGlkYWQgZmVkZXJhdGl2YS4KCnwgQ1ZFX0VOVCB8IGNvb3JkX3NmKCkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfC0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tfAp8IDYgICAgICAgfCB4bGltID0gYygtMTA1LC0xMDMpLCB5bGltID0gYygxOC42NSwgMTkuNikgICAgICB8CnwgMzEgICAgICB8IHhsaW0gPSBjKC05MC43LC04Ny40KSwgeWxpbSA9IGMoMTkuNTUxMTcsIDIxLjkpIHwKCkxvcyB2YWxvcmVzIHRhbnRvIGRlIGBsZWdlbmQucG9zaXRpb25gIGNvbW8gZGUgYGNvb3JkX3NmKClgIHNlIGRlYmVuIHN1c3RpdHVpciBwYXJhIGNhZGEgY2FzbyAoYSBtZW5vcyBxdWUgc2UgaW5jb3Jwb3JlbiBjb21vIHVuYSB2YXJpYWJsZSBvIHZhbG9yIGRlbnRybyBkZSBsYSBmdW5jacOzbiwgdGlwbyBgaWZlbHNlYCkKCmBgYHtyLCByZXN1bHRzPSdoaWRlJywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KCnNlbF9lZG8gPSAzMgoKbnVtX2NhaV9tdW4gPC0gZnVuY3Rpb24oc2VsX2Vkbyl7CiAgCm1hcF9jYWkgPC0gY2FpX211biAlPiUgCiAgZmlsdGVyKGFzLm51bWVyaWMoQ1ZFX0VOVCkgPT0gc2VsX2VkbykgJT4lIAogIG11dGF0ZSh0b3RfY2FpID0gcmVwbGFjZV9uYSh0b3RfY2FpLCAwKSwKICAgICAgICAgY2F0X2NhaSA9IGNhc2Vfd2hlbih0b3RfY2FpID09IDAgfiAiTmluZ3VubyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmV0d2Vlbih0b3RfY2FpLCAxLDEwKSB+ICIxIC0gMTAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJldHdlZW4odG90X2NhaSwgMTEsMjApIH4gIjExIC0gMjAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJldHdlZW4odG90X2NhaSwgMjEsMzApIH4gIjIxIC0gMzAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvdF9jYWkgPiAzMCB+ICJNw6FzIGRlIDMwIikKICAgICAgICAgKQoKbm9tYnJlX2VudGlkYWQgPC0gbWFwX2NhaSROT01fRU5UICU+JSB1bmlxdWUoKSAKbnVtX2VudCA8LSBtYXBfY2FpJENWRV9FTlQgJT4lIHVuaXF1ZSgpCgpmX3BsdCA8LSBnZ3Bsb3QobWFwX2NhaSkgKwogIGdlb21fc2YoYWVzKGZpbGwgPSBjYXRfY2FpKSwgbHdkID0gMC40NSwgY29sb3IgPSAiYmxhY2siKSArCiAgIyBjb29yZF9zZih4bGltID0gYygtOTAuNywtODcuNCksIHlsaW0gPSBjKDE5LjU1MTE3LCAyMS45KSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIk5pbmd1bm8iID0gIiM3RjdGN0YiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjEgLSAxMCIgPSAiI0QyQURDRCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMTEgLSAyMCIgPSAiIzYyOURDQSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMjEgLSAzMCIgPSAiIzIwNkQ5RiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTcOhcyBkZSAzMCIgPSAiIzE1MzQ2OCIpLAogICAgICAgICAgICAgICAgICAgIGd1aWRlID0gZ3VpZGVfbGVnZW5kKAogICAgICAgICAgICAgICAgICAgICAga2V5aGVpZ2h0ID0gdW5pdCg2LCB1bml0cyA9ICJtbSIpLAogICAgICAgICAgICAgICAgICAgICAga2V5d2lkdGggPSB1bml0KDYsIHVuaXRzID0gIm1tIiksCiAgICAgICAgICAgICAgICAgICAgICBsYWJlbC5wb3NpdGlvbiA9ICJyaWdodCIsCiAgICAgICAgICAgICAgICAgICAgICB0aXRsZS5wb3NpdGlvbiA9ICJ0b3AiLAogICAgICAgICAgICAgICAgICAgICAgbmNvbCA9IDEsCiAgICAgICAgICAgICAgICAgICAgICBzaGFwZSA9IDE2LAogICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDYpKSArCiAgbGFicyhmaWxsID0gIk7Dum1lcm8gZGUgQ0FJIiwKICAgICAgIHRpdGxlID0gbm9tYnJlX2VudGlkYWQpICsKICB0aGVtZV92b2lkKCkgKwogIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoY29sb3IgPSAiIzIyMjExZCIpLAogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDI0LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZhY2UgPSAiYm9sZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9ICIjMDAzMzY2IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoanVzdCA9IDAuNSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2anVzdCA9IDAuNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcmdpbiA9IG1hcmdpbih0ID0gNSwgYiA9IDUpKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSBjKDAuMDYsIDAuNzUpLAogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZhY2UgPSAiYm9sZCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoanVzdCA9IDAuNSksCiAgICAgICAgbGVnZW5kLmtleSA9IGVsZW1lbnRfcmVjdChmaWxsID0gInRyYW5zcGFyZW50IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9ICJ0cmFuc3BhcmVudCIpLAogICAgICAgIHBsb3QubWFyZ2luID0gbWFyZ2luKHQgPSAwLCByID0gMCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYiA9IDAsIGwgPSAwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1bml0ID0gImNtIikKICAgICAgICApCgpnZ3NhdmUoc3RyX2MoIk1hcGFzL0NBSV8iLCBudW1fZW50LCBub21icmVfZW50aWRhZCwgIi5wbmciKSwKICAgICAgICAgcGxvdCA9IGZfcGx0LCBoZWlnaHQgPSA4LCB3aWR0aCA9IDEyLCBkcGkgPSAxMDAwKQoKCn0KCm51bV9jYWlfbXVuKHNlbF9lZG8gPSAzMikKCmZvciAoZXN0YWRvX3BhcmFfbWFwYSBpbiAxOjMyKXsKICBudW1fY2FpX211bihzZWxfZWRvID0gZXN0YWRvX3BhcmFfbWFwYSkKICBwcmludChzdHJfYygiTWFwYV8iLCBlc3RhZG9fcGFyYV9tYXBhLCAiLzMyIGdlbmVyYWRvIikpCn0KYGBgCgojIyBHcsOhZmljYXMgZGUgcHJvcG9yY2nDs24gZGUgQ0FJIHBvciB0aXBvCgpgYGB7ciwgcmVzdWx0cz0naGlkZScsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgpzZWxfZWRvID0gMzIKCnByb3BfY2FpX211biA8LSBmdW5jdGlvbihzZWxfZWRvKXsKICAKcHJvcF9jYWkgPC0gY2FpX211biAlPiUgCiAgZmlsdGVyKGFzLm51bWVyaWMoQ1ZFX0VOVCkgPT0gc2VsX2VkbyApICU+JQogIGZpbHRlcighaXMubmEodG90X2NhaSkpICU+JSAKICBzZWxlY3QoQ1ZFX0VOVCwgTk9NX0VOVCwgTk9NR0VPLCBERU5VRSwgSU1TUywgSVNTU1RFLCBTTkRJRikgJT4lCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBjKERFTlVFLCBJTVNTLCBJU1NTVEUsIFNORElGKSwgCiAgICAgICAgICAgICAgIG5hbWVzX3RvID0gImNhdGVnb3JpYSIsIAogICAgICAgICAgICAgICB2YWx1ZXNfdG8gPSAidmFsb3IiKSAlPiUgCiAgZ3JvdXBfYnkoQ1ZFX0VOVCwgTk9NR0VPKSAlPiUgCiAgbXV0YXRlKHRvdGFsX2dlbyA9IHN1bSh2YWxvcikpICU+JSAgICAgICAgICAgCiAgdW5ncm91cCgpICU+JSAKICBtdXRhdGUocG9yY2VudGFqZSA9IHJvdW5kKHZhbG9yIC8gdG90YWxfZ2VvICogMTAwLDIpKSAKCm5vbWJyZV9lbnRpZGFkIDwtIHByb3BfY2FpJE5PTV9FTlQgJT4lIHVuaXF1ZSgpIApudW1fZW50IDwtIHByb3BfY2FpJENWRV9FTlQgJT4lIHVuaXF1ZSgpCgpvcmRlbl9tdW5pY2lwaW9zIDwtIHByb3BfY2FpICU+JSAKICBmaWx0ZXIoY2F0ZWdvcmlhID09ICJERU5VRSIpICU+JSAKICBhcnJhbmdlKHBvcmNlbnRhamUpICU+JSAKICBwdWxsKE5PTUdFTykKCnByb3BfY2FpIDwtIHByb3BfY2FpICU+JSAgZmlsdGVyKHBvcmNlbnRhamUgPiAwKQogIAoKcGx0X3Byb3BfbXVuIDwtZ2dwbG90KHByb3BfY2FpLAogICAgICAgICAgICAgICAgYWVzKHggPSBmYWN0b3IoTk9NR0VPLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IG9yZGVuX211bmljaXBpb3MpLAogICAgICAgICAgICAgICAgICAgIHkgPSBwb3JjZW50YWplLAogICAgICAgICAgICAgICAgICAgIGZpbGwgPSBjYXRlZ29yaWEpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gaWZlbHNlKHBvcmNlbnRhamUgPj0gNiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNwcmludGYoIiUuMmYlJSIsIHBvcmNlbnRhamUpLCAiIikpLAogICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX3N0YWNrKHZqdXN0ID0gMC41KSwKICAgICAgICAgICAgc2l6ZSA9IDMuNSwKICAgICAgICAgICAgY29sb3IgPSAid2hpdGUiLAogICAgICAgICAgICBmb250ZmFjZSA9ICJib2xkIikgKwogIGxhYnModGl0bGUgPSBub21icmVfZW50aWRhZCwKICAgICAgIHN1YnRpdGxlID0gIlBvcmNlbnRhamUgZGUgQ0FJIGVuIGxvcyBtdW5pY2lwaW9zIHBvciBjYXRlZ29yw61hIiwKICAgICAgIHkgPSAiUG9yY2VudGFqZSAoJSkiKSArCiAgY29vcmRfZmxpcCgpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJERU5VRSIgPSAiIzUzNjQ5MyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiSU1TUyIgPSAiI0NDOTlGRiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiSVNTU1RFIiA9ICIjRUJCNDUyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTTkRJRiIgPSAiIzAwOTlDQyIpLAogICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIkRFTlVFIiA9ICJQcml2YWRvcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiSU1TUyIgPSAiSU1TUyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiSVNTU1RFIiA9ICJJU1NTVEUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNORElGIiA9ICJTTkRJRiIpKSArCiAgc2NhbGVfY29sb3JfaWRlbnRpdHkoKSArCiAgdGhlbWVfdm9pZCgpICsKICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KGNvbG9yID0gIiMyMjIxMWQiKSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhqdXN0ID0gMSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFjZSA9ICJib2xkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXJnaW4gPSBtYXJnaW4odCA9IDAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByID0gLTEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiID0gMCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGwgPSAwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdW5pdCA9ICJjbSIpKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAidG9wIiwKICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTEpLAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAyNCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYWNlID0gImJvbGQiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gIiMwMDMzNjYiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhqdXN0ID0gMCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2anVzdCA9IDAuNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcmdpbiA9IG1hcmdpbih0ID0gNSwgYiA9IDUpKSwKICAgICAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYWNlID0gImJvbGQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSAiIzRlNGQ0NyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGp1c3QgPSAwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZqdXN0ID0gMC41LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFyZ2luID0gbWFyZ2luKHQgPSAwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiID0gMSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdW5pdCA9ICJjbSIpKSwKICAgICAgICBwbG90Lm1hcmdpbiA9IG1hcmdpbih0ID0gMCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgciA9IDAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGIgPSAwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsID0gMC41LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1bml0ID0gImNtIikKICAgICAgICApCgpnZ3NhdmUoc3RyX2MoIk1hcGFzL1Byb3AgQ0FJXyIsIG51bV9lbnQsIG5vbWJyZV9lbnRpZGFkLCAiLnN2ZyIpLAogICAgICAgICBwbG90ID0gcGx0X3Byb3BfbXVuLCBoZWlnaHQgPSA4LCB3aWR0aCA9IDEyLCBkcGkgPSAxMDAwKQp9Cgpwcm9wX2NhaV9tdW4oc2VsX2VkbyA9IDMyKQoKZm9yIChlc3RhZG9fcGFyYV9iYXJyYSBpbiAxOjMyKXsKICBwcm9wX2NhaV9tdW4oc2VsX2VkbyA9IGVzdGFkb19wYXJhX2JhcnJhKQogIHByaW50KHN0cl9jKCJHcmFmaWNvXyIsIGVzdGFkb19wYXJhX2JhcnJhLCAiLzMyIGdlbmVyYWRvIikpCn0KYGBgCgojIyMgRW50aWRhZGVzIGZlZGVyYXRpdmFzIGNvbiBtdWNob3MgbXVuaWNpcGlvcwoKTG9zIGdyw6FmaWNvcyBkZSBlbnRpZGFkZXMgZmVkZXJhdGl2YXMgY29uIG11Y2hvcyBtdW5pY2lwaW9zIHNlIHRpZW5lbiBxdWUgZGl2aWRpciBwYXJhIHBvZGVyIHZpc3VhbGl6YXIgY29ycmVjdGFtZW50ZSBsb3MgZGF0b3MuIExhcyBzaWd1aWVudGVzIGVudGlkYWRlcyBmZWRlcmF0aXZhcyBzZSBkaXZpZGVuIGVuOgoKLSAgIFB1ZWJsYSB5IEVkby4gTWV4OiA0IGdyw6FmaWNvcwoKLSAgIENoaWFwYXMsIEphbGlzY28geSBNaWNob2Fjw6FuOiAzIGdyw6FmaWNvcwoKLSAgIEhpZGFsZ286IDIgZ3LDoWZpY29zCgpgYGB7cn0KcHJvcF9jYWkgPC0gY2FpX211biAlPiUgCiAgZmlsdGVyKGFzLm51bWVyaWMoQ1ZFX0VOVCkgPT0gMTEpICU+JSAjYXF1w60gc2UgZGViZSBpbmRpY2FyIGVsIG7Dum1lcm8gZGVsIGVzdGFkbwogIGZpbHRlcighaXMubmEodG90X2NhaSkpICU+JSAKICBzZWxlY3QoQ1ZFX0VOVCwgTk9NX0VOVCwgTk9NR0VPLCBERU5VRSwgSU1TUywgSVNTU1RFLCBTTkRJRikgJT4lICAKICBwaXZvdF9sb25nZXIoY29scyA9IGMoREVOVUUsIElNU1MsIElTU1NURSwgU05ESUYpLCAKICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAiY2F0ZWdvcmlhIiwgCiAgICAgICAgICAgICAgIHZhbHVlc190byA9ICJ2YWxvciIpICU+JSAKICBncm91cF9ieShDVkVfRU5ULCBOT01HRU8pICU+JSAKICBtdXRhdGUodG90YWxfZ2VvID0gc3VtKHZhbG9yKSkgJT4lICAgICAgICAgICAKICB1bmdyb3VwKCkgJT4lIAogIG11dGF0ZShwb3JjZW50YWplID0gcm91bmQodmFsb3IgLyB0b3RhbF9nZW8gKiAxMDAsMikpIAoKbm9tYnJlX2VudGlkYWQgPC0gcHJvcF9jYWkkTk9NX0VOVCAlPiUgdW5pcXVlKCkgCm51bV9lbnQgPC0gcHJvcF9jYWkkQ1ZFX0VOVCAlPiUgdW5pcXVlKCkKCm9yZGVuX211bmljaXBpb3MgPC0gcHJvcF9jYWkgJT4lIAogIGZpbHRlcihjYXRlZ29yaWEgPT0gIkRFTlVFIikgJT4lIAogIGFycmFuZ2UocG9yY2VudGFqZSkgJT4lIAogIHB1bGwoTk9NR0VPKQoKcHJvcF9jYWkgPC0gcHJvcF9jYWkgJT4lICBmaWx0ZXIocG9yY2VudGFqZSA+IDApCgpudW1fbXVuaWNpcGlvcyA8LSBsZW5ndGgob3JkZW5fbXVuaWNpcGlvcykKCm11bl9zcGxpdCA8LSBzcGxpdChvcmRlbl9tdW5pY2lwaW9zLCAKICAgICAgICAgICAgICAgICAgIGNlaWxpbmcoc2VxX2Fsb25nKG9yZGVuX211bmljaXBpb3MpIC8gKG51bV9tdW5pY2lwaW9zIC8gMikpKQoKY3JlYXJfZ3JhZmljbyA8LSBmdW5jdGlvbihtdW5pY2lwaW9zLCBpbmRpY2UpIHsKICBwbHQgPC0gZ2dwbG90KHByb3BfY2FpICU+JSBmaWx0ZXIoTk9NR0VPICVpbiUgbXVuaWNpcGlvcyksCiAgICAgICAgICAgICAgICBhZXMoeCA9IGZhY3RvcihOT01HRU8sIGxldmVscyA9IG11bmljaXBpb3MpLAogICAgICAgICAgICAgICAgICAgIHkgPSBwb3JjZW50YWplLAogICAgICAgICAgICAgICAgICAgIGZpbGwgPSBjYXRlZ29yaWEpKSArCiAgICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogICAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IGlmZWxzZShwb3JjZW50YWplID49IDYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNwcmludGYoIiUuMmYlJSIsIHBvcmNlbnRhamUpLCAiIikpLAogICAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fc3RhY2sodmp1c3QgPSAwLjUpLAogICAgICAgICAgICAgIHNpemUgPSAzLjUsIGNvbG9yID0gIndoaXRlIiwgZm9udGZhY2UgPSAiYm9sZCIpICsKICAgIGxhYnModGl0bGUgPSBub21icmVfZW50aWRhZCwKICAgICAgICAgc3VidGl0bGUgPSBwYXN0ZSgiUG9yY2VudGFqZSBkZSBDQUkgZW4gbG9zIG11bmljaXBpb3MgcG9yIGNhdGVnb3LDrWEgKCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgaW5kaWNlLCAiIGRlIDIpIiwgc2VwID0gIiIpLAogICAgICAgICB5ID0gIlBvcmNlbnRhamUgKCUpIikgKwogICAgY29vcmRfZmxpcCgpICsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIkRFTlVFIiA9ICIjNTM2NDkzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIklNU1MiID0gIiNDQzk5RkYiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiSVNTU1RFIiA9ICIjRUJCNDUyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlNORElGIiA9ICIjMDA5OUNDIiksCiAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJERU5VRSIgPSAiUHJpdmFkb3MiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiSU1TUyIgPSAiSU1TUyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJJU1NTVEUiID0gIklTU1NURSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTTkRJRiIgPSAiU05ESUYiKSkgKwogICAgdGhlbWVfdm9pZCgpICsKICAgIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoY29sb3IgPSAiIzIyMjExZCIpLAogICAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDExLCBoanVzdCA9IDEsIGZhY2UgPSAiYm9sZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXJnaW4gPSBtYXJnaW4odCA9IDAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHIgPSAtMSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYiA9IDAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGwgPSAwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1bml0ID0gImNtIikpLAogICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gInRvcCIsCiAgICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTEpLAogICAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjQsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYWNlID0gImJvbGQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9ICIjMDAzMzY2IiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhqdXN0ID0gMCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZqdXN0ID0gMC41LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXJnaW4gPSBtYXJnaW4odCA9IDUsIGIgPSA1KSksCiAgICAgICAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZhY2UgPSAiYm9sZCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gIiM0ZTRkNDciLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGp1c3QgPSAwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmp1c3QgPSAwLjUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcmdpbiA9IG1hcmdpbih0ID0gMCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiID0gMSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1bml0ID0gImNtIikpLAogICAgICAgICAgcGxvdC5tYXJnaW4gPSBtYXJnaW4odCA9IDAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgciA9IDAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYiA9IDAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbCA9IDAuNSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB1bml0ID0gImNtIikKICAgICAgICAgICkKICAKICBnZ3NhdmUoc3RyX2MoIk1hcGFzL1Byb3AgQ0FJXyIsIG51bV9lbnQsIG5vbWJyZV9lbnRpZGFkLCAiXyIsIGluZGljZSwgIi5zdmciKSwKICAgICAgICAgcGxvdCA9IHBsdCwgaGVpZ2h0ID0gOCwgd2lkdGggPSAxMiwgZHBpID0gMTAwMCkKfQoKIyBFc3RhIHBhcnRlIHNlIG1vZGlmaWNhIHNlZ8O6biBsYSBlbnRpZGFkIGZlZGVyYXRpdmEgeSBlbCBuw7ptZXJvIGRlIGdyw6FmaWNvcyBxdWUgc2UgZGViZW4gZ2VuZXJhcgpjcmVhcl9ncmFmaWNvKG11bl9zcGxpdFtbMl1dLCAxKQpjcmVhcl9ncmFmaWNvKG11bl9zcGxpdFtbMV1dLCAyKQojIGNyZWFyX2dyYWZpY28obXVuX3NwbGl0W1syXV0sIDMpCiMgY3JlYXJfZ3JhZmljbyhtdW5fc3BsaXRbWzFdXSwgNCkKYGBgCg==