Introducción

Objetivos

El objetivo de este trabajo es analizar de una forma más visual tres aspectos que consideramos curiosos de las pasadas elecciones del 28A. Nuestra primera intención es observar si los titulares de los medios de comunicación sobre la irrupción de VOX, especialmente en los municipios com mayor proporción de población extranjera, son ciertos. En el siguiente apartado veremos el coste que tiene para cada partido obtener representación en el Congreso de los Diputados. Finalizaremos con un análisis sobre las diferencias entre dos partidos nacionalistas: Compromis y ERC. Las diferencia en la propensión al voto y otros aspectos.

Fuente de los datos

Los datos utilizados provienen del Ministerio del Interior y del Instituto Nacional de Estadística. A continuación importamos los datos que previamente y tal y como se muestra en el apéndice técnico hemos hecho tidy. La fuentes de los datos (el MIR) presenta unos datos que son visualmente validos pero que a efectos de tratamiento no nos sirven. En el apéndice técnico se explica detalladamente el proceso llevado a cabo.

Aspectos previos

Primeros importamos las librerias básicas, utilizamos más librerias pero las llamamos cuando las necesitamos. Les remito al sessionInfo() para ver todos los paquetes utilizados.


library(tidyverse)
library(sf)
library(LAU2boundaries4spain)
library(viridis)

# cargamos todas las funciones muy últiles para el dearrollo del trabajo, elaboradas por nosotros
source("funciones.R")

Cargamos los datos que hemos hecho tidy previamente. Los datos originales se encuentran en la carpeta data/raw. A continuación le aplicamos la función partidosNom() para limpiar el nombre de los partidos y reducir en algunos casos su extensión.

# Cargamos df de las elecciones y limpiamos los nombre de los partidos
generales28A <- rio::import(here::here("./data/", "generales28A.rdata")) %>% partidosNom(.)
municipios28A <- rio::import(here::here("./data/", "municipios28A.rdata")) %>% partidosNom(.)
CCAAProvCodigos <- rio::import(here::here("./data/", "CCAAProvCodigos.rdata")) # With leading 0s

Sobre Vox y los medios de comunicación

Los medios de comunicación han jugado con los datos para mostrar que existia una correlación entre el voto a VOX y la inmigración. Es cierto que ha ganado en municipios con tasa de inmigración altas como El Ejido pero el número total de municipios es insignificante y destaca lo pequeños que son los municipios. Estableceremos una correleación que, a nuestro juicio, es más acertada.

Nos hemos centrado en los datos del INE de 2019 sobre las estadísticas del Padrón Continuo sobre el porcentaje de población inmigrante. Según la hipótesis de los medios de comunicación, el partido Vox saldría con mayor representación en aquellos lugares del Estado donde el porcentaje de población extranjera es más alto.

Como podemos observar, en los municipios en los que ha ganado VOX son:

# Importamos los datos que previamente hemos limpiado para todo el supuesto

pobExtEscanos <- rio::import("./data/poblacion_Extranjera.rdata")
pobExt <- rio::import("./data/poblacionExtranjera.rdata")
VOX28A <- municipios28A %>% group_by(comunidad, codigo.prov, codigo.muni) %>% top_n(1,votos) %>%
    filter(partido == "VOX") %>% ungroup() %>% group_by(codigo.prov) %>% 
  mutate(total.votos = sum(votos), total.muni = n()) %>%
    ungroup() %>%  distinct(provincia, total.muni, total.votos)

# con trimws quitamos los espacios en blanco que parece que no están pero sí y fastidian el gráfico
VOX28A$provincia <- VOX28A$provincia %>% gsub("Castellón / ", "", .) %>% gsub("Valencia / ", "", .)

ggplot(VOX28A, aes(forcats::fct_reorder(provincia, total.muni), total.muni)) + 
  geom_col(aes(fill = total.votos)) +
    geom_text(aes(label = total.votos), nudge_y = 2,  size=3) +
    scale_fill_viridis_c(option = "magma", name = "Votos", alpha = 0.8, begin = 0.3, end = 0.7, direction = 1,
                         guide = guide_colorbar( direction = "horizontal", barheight = unit(2, units = "mm"), 
                                                 barwidth = unit(50, units = "mm"), draw.ulim = F, 
                                                 title.position = 'top', title.hjust = 0.5, label.hjust = 0.5
                         )) +
    theme_plot() + theme(legend.text = element_text(size = 8)) +
    labs(title = "Provincias en las que Vox ha sido la fuerza más votada",
         subtitle = "Número total de municipios por provincias",
         caption = default_caption) + theme(axis.title.y = element_blank())

Es curioso como ha ganado con a penas un puñado de votos. Por ejemplo, en Soria ha sido la fuerza más votada en cinco municipios obteniendo un global de 50 votos. La provincia más destaca es Almería que ha ganado en tres municipios pero ha obtenido un número de votos exagerado. Como decíamos anteriomente, el lugar más destacada es El Ejido que es uno de los municipios con mayor porcentaje de población inmigrante.

Exceptuando Madrid, la mayor parte son provincias del interior de España. ¿Pero son estas las que tienen un mayor porcentaje de población extranejera?

prov_inmi <- pobExt %>% top_n(14, porcentaje) 

library(treemapify)
ggplot(prov_inmi, aes(area = porcentaje, fill = porcentaje, label = provincia)) +
    geom_treemap() +
    geom_treemap_text(fontface = "italic", colour = "white", place = "centre",
                      grow = FALSE) + 
    scale_fill_viridis_c(option = "viridis", name = "", alpha = 0.8, begin = 0.3, end = 0.7, direction = 1,
                         guide = guide_colorbar( title = "Porcentaje", direction = "horizontal", barheight = unit(2, units = "mm"), 
                                                 barwidth = unit(50, units = "mm"), draw.ulim = F, 
                                                 title.position = 'top', title.hjust = 0.5, label.hjust = 0.5
                         )) + 
    theme(legend.position = "bottom") +
    labs(title = "Provincias con mayor porcentaje de población extranjera",
         caption = "Estadísticas del Padrón Continuo. 1 de Enero de 2019.")

La realidad es que las diez primeras provincias con mayor porcentaje de población extranjera no se corresponden con el gráfico anteriormente obtenido. Guadalajara, que antes era la primera se encuentra en la catorceava posición. Por otro lado, es especialmente relevante el caso de Girona, ya que siendo una de las provincias con mayor porcentaje de población extranjera, no existe ningún municipio en el que VOX obtenga representación por pequeño que sea.

diputados28A <- pobExtEscanos %>% filter(complete.cases(.), diputados > 0) %>% mutate(dipu_quantile = cut(as.numeric(diputados), breaks = c(1,2,5,7,11), include.lowest = TRUE)) %>% 
    mutate(porc_quantile = cut(porcentaje, breaks = 4, labels = c("Bajo", "Medio", "Medio-Alto", "Alto")))

dipu_label = c("1-2", "3-5", "6-7", "8-11")

[Ampliar Imagen]

El gráfico anterior muestra la representación de los partidos políticos por provincia y por porcentaje de población extrajera residente. Además, la representación política se distribuye en una escala de colores, de oscuro a claro de menor a mayor representación. Para desmentir la idea de que Vox había ganado en provincias con un alto número de población extranjera comparamos los resultados del PSOE y PP. Concluimos que Vox ha tenido mayor representación en provincias grandes y naturalmente con mayor numero de población extranjera. Sin embargo, no se observa una correlación entre la representación y la población inmigrante —como es el caso de Ávila que como hemos podido observar anteriormente ha ganado en 9 municipios— pero si que se observa una correlación positiva entre el tamaño poblacional y la representación.

Sobre el coste por diputado y proporcionalidad

En este apartado vamos a valorar el coste en términos de votos que tiene un diputado por partido y provincia.

costeVotos <- generales28A %>% filter(diputados > 0) %>%  mutate(coste_dipu = votos/diputados) %>% mutate(pct = coste_dipu/poblacion)
costeVotos$partido <- as.factor(costeVotos$partido)

df3 <- costeVotos %>% group_by(partido) %>% top_n(1, coste_dipu) %>% ungroup()
df3$partido  <- forcats::fct_reorder(df3$partido , df3$coste_dipu)
p <- ggplot(df3, aes(partido, coste_dipu)) + geom_col(aes(fill = provincia)) + 
    theme_plot() + theme(legend.text = element_text(size=8), legend.position = "bottom") +
    scale_fill_viridis_d(option="magma", alpha = 0.8, begin = 0, end = 1, 
                         name = "", guide = guide_legend(nrow = 3, ncol = 4)) + 
    labs(title = "Provincia con el coste por diputados mas alto para cada partido") + ylab("")

plotly::ggplotly(p)

El diputado más costoso en términos de votos es el del PP por la provincia de Barcelona.

Lo relevante de este gráfico, podría ser que las únicas provincias donde es más costoso obtener un diputado en términos absolutos son provincias grandes y económicamente potentes, lo que nos da una primera visión del porqué los partidos grandes en sus campañas electorales centran su atención en provincias pequeñas donde se reparten mayor número de diputados en relación a la población.

        costeVotos$codigo.prov <- as.numeric(costeVotos$codigo.prov)
df4 <- costeVotos %>% filter(codigo.prov %in% c(17,25,43,1,20,48, 2, 13, 16, 19, 45, 8))

ggplot(df4, aes(forcats::fct_reorder(provincia, coste_dipu), coste_dipu/1000, fill=factor(partido))) + geom_col(stat = "identity", position = position_dodge()) + 
    theme_plot_facet() + 
    facet_grid(~comunidad, scales = "free", space = "free") + scale_fill_viridis_d(option="magma", alpha = 0.8, begin = 0.1, end = 0.9, name = "") +
    labs(title = "Votos necesarios para obtener un diputado",
         caption = default_caption)+
    ylab("Miles de personas") + xlab("")

Por otro lado, como hemos comentado, las provincias de la España interior tienen un coste por diputado en términos absolutos menor. En comunidades autónomas como Cataluña y País Vasco, donde hay provincias tanto industrializadas como rurales, se observa una notable diferencia en el coste por diputado.

Centrándonos en el caso de EH-Bildu, si lo comparamos con el interior de la comunidad, se observa la gran diferencia entre lo que le cuesta obtener un diputado en la provincia de Álava y lo que le cuesta en la provincia de Bizkaia que es sin lugar a dudas una región con más desarrollo económico.

Para el caso de Castilla-La Mancha, es destacable como el coste de diputados en promedio es realmente más bajo en comparación con las otras dos CCAA.

ggplot(df4, aes(forcats::fct_reorder(provincia, coste_dipu), pct, fill=factor(partido))) + geom_col(stat = "identity", position = position_dodge()) + 
    theme_plot_facet() + scale_y_continuous(labels = scales::percent) +
    facet_grid(~comunidad, scales = "free", space = "free") + scale_fill_viridis_d(option="magma", name = "", alpha = 0.8, begin = 0.1, end = 0.9) +
    labs(title = "Importancia relativa de un voto para la obtención de un diputado",
         subtitle = "A mayor porcentaje, más 'valor' tiene el voto del ciudadano", 
         caption = default_caption) +
    ylab("Cuánto representa el coste \n por diputado sobre la población") + xlab("")

Este grafico destaca la gran diferencia que supone el valor de un voto en Castilla-La Mancha, en general, respecto a la provincia de Barcelona, donde el valor del voto por persona es mínimo debido al gran número de habitantes que posee.

Finalmente, el mapa anterior es un mapa bivariante que muestra la relación entre la representatividad (diputados) y el total del censo electoral. Los colores que están en la linea diagonal serian aquellas provincias que están correctamente representadas. Aquellas provincias como Lleida o Lugo estarían sobrerrepresentadas, el número de diputados que reparten es proporcionalmente mayor al censo electoral. Por otro lado, Ourense o Zaragoza estarían infrarrepresentadas, en promedio los diputados que reparten son menores dado el censo electoral.

Sobre Compromís vs. ERC

compromisERC <- municipios28A %>% filter(codigo.prov %in% c("03","12","46", "08","17", "43", "25"), 
                                      partido %in% c("COMPROMIS-EUPV", "ERC"),
                                      votos > 0) %>% 
                mutate(INECodMuni = paste(codigo.prov, codigo.muni, sep = ""),
                       votos_quantile = ntile(votos, 5)) 

compromisERC_mapa <- left_join(compromisERC, loadGeometry(6, provincias = c("03","12","46", "08","17", "43", "25")))

provinciasLindes <- c("22", "44", "50", "16", "44", "30", "02", "07", "31", "19")

fraSF <- rnaturalearth::ne_countries(scale = "medium", returnclass = "sf") %>% filter(adm0_a3 == "FRA")

plot1 <- ggplot() + geom_sf(data = fraSF, aes(geometry = geometry)) +
    geom_sf(aes(geometry = geometry), data=filter(loadGeometry(1, provincias = provinciasLindes))) +
    geom_sf(aes(geometry = geometry, fill=votos_quantile), data=compromisERC_mapa) +
    scale_fill_viridis(
        option = "magma", 
        direction = -1,
        begin = 0.3, end = 0.8,
        name = "Votos (Quantiles)",
        # here we use guide_colourbar because it is still a continuous scale --> https://timogrossenbacher.ch/2016/12/beautiful-thematic-maps-with-ggplot2-only/
        guide = guide_colorbar(
            direction = "horizontal",
            barheight = unit(2, units = "mm"),
            barwidth = unit(50, units = "mm"),
            draw.ulim = F,
            title.position = 'top',
            # some shifting around
            title.hjust = 0.5,
            label.hjust = 0.5
        )) +
    coord_sf(xlim = c(-1.5, 4), ylim = c(38,42.7)) + theme_map() + 
  theme(legend.position = "bottom", plot.title = element_text(size = 12) ) + 
  labs(title="Densidad de votos a Compromís y ERC", caption = default_caption)

plot1

En esta sección queremos comparar el origen del voto de los partidos nacionalistas Compromís y Esquerra Republicana de Cataluña (ERC). En primer lugar, lo que percibimos es que el voto de Compromís, se ubica en el territorio que ocupa las grandes ciudades de la Comunidad Valenciana mientras que el voto de ERC no sigue el mismo patrón y obtiene gran representación uniformemente por todo el territorio catalán. Es relevante el caso de Lleida porque como anteriormente hemos resaltado, la provincia está sobrerrepresentada en el número de diputados por lo que cada voto a ERC tiene más valor.

votantes28A <- rio::import("./data/generales28ATipoVoto.rdata") %>% filter(tipo.voto == "total.censo.electoral",
                                                                           codigo.prov %in% c("03","12","46", "08","17", "43", "25"))

tableCompromis <- generales28A %>% filter(partido %in% c("COMPROMIS-EUPV", "ERC"), votos > 0) %>% left_join(votantes28A) %>% 
    select(c(3,5,6,7,10))
colnames(tableCompromis) <- c("Provincia", "Partido", "Nº votos", "Diputados", "Total censo electoral")
knitr::kable(tableCompromis)    
Provincia Partido Nº votos Diputados Total censo electoral
Barcelona ERC 716714 8 4178927
Girona ERC 114031 3 522860
Lleida ERC 75760 2 314558
Tarragona ERC 113887 2 571800
Alicante / Alacant COMPROMIS-EUPV 31030 0 1272928
Castellón / Castelló COMPROMIS-EUPV 16713 0 419714
Valencia / València COMPROMIS-EUPV 126078 1 1964556

La poca progresividad en la representatividad se puede observar con los resultados de Compromís en Valencia. Con 126.078 votos ha obtenido un solo diputado frente a ERC que en Lleida con menor número de votantes y censo electoral ha obtenido dos diputados. Recordamos que Compromís es el segundo partido con mayor coste en términos de votos por diputado solo por detrás del PP en Barcelona.

edadmedia <- rio::import(here::here("data", "edadMediaPob2019.rdata")) %>% filter(codigo.prov %in% c("03","12","46", "08","17", "43", "25"))

edadmedia_map <- left_join(edadmedia, loadGeometry(6, provincias = c("03","12","46", "08","17", "43", "25")))

plot2 <- ggplot() + geom_sf(data = fraSF, aes(geometry = geometry)) +
    geom_sf(data=loadGeometry(3, provinciasLindes), aes(geometry = geometry), alpha = 0.5) +
    geom_sf(data=edadmedia_map, aes(geometry = geometry, fill = quantile)) + 
    scale_fill_viridis(
        option = "magma", 
        direction = -1,
        begin = 0.3, end = 0.8,
        name = "Edad Media",
        # here we use guide_colourbar because it is still a continuous scale --> https://timogrossenbacher.ch/2016/12/beautiful-thematic-maps-with-ggplot2-only/
        guide = guide_colorbar(
            direction = "horizontal",
            barheight = unit(2, units = "mm"),
            barwidth = unit(50, units = "mm"),
            draw.ulim = F,
            title.position = 'top',
            # some shifting around
            title.hjust = 0.5,
            label.hjust = 0.5
        )) +
    coord_sf(xlim = c(-1.5, 4), ylim = c(38,42.7)) + theme_map() + theme(legend.position = "bottom") + 
  labs(title = "Edad media por municipios",
       subtitle = "Nota: datos de INE trameados cruzados con la población",
       caption = default_caption)

gridExtra::grid.arrange(plot1, plot2, ncol=2)

Finalmente, resulta relevante la relacción inversa entre la propensión al voto de estas dos formaciones y la edad media de los municipios. A falta de un análisis más exhaustivo podríamos decir que el perfil del votante de las formaciones es relativamente jóven.

Encuéntrate

library(DT)

infovotos <- rio::import("./data/municipios28ATipoVoto.rdata") %>%  select(c(2,4,7)) %>% unique()
dtable <- municipios28A %>% filter(votos > 0) %>% left_join(., infovotos) %>% select(-c(2,4))
dtable$provincia <- chartr('áéíóúñ','aeioun', dtable$provincia)
dtable$municipio <- chartr('áéíóúñ','aeioun', dtable$municipio)
dtable$comunidad <- chartr('áéíóúñ','aeioun', dtable$comunidad)



datatable(dtable)

Conclusión

Del primer supuesto concluimos que después de las elecciones del 29 de Abril, los medios han exagerado el resultado obtenido por VOX, cogiendo datos aislados buscando justificación a su titular.

Del segundo supuesto, concluimos que el sistema de representación que existe en España es claramente poco proporcional. Algunas provincias tienen asignados mayor número de diputado respecto a su censo electora, lo que perjudica a partidos de ámbito nacional en beneficio de partidos regionalistas como Esquerra Republicana de Cataluña y EH-Bildu.

Del tercer supuesto y en base a las investigaciones de los supuestos anteriores podemos concluir que ERC obtiene mayor representación de las provincias del interior de Cataluña debido a que algunas como Lleida estan sobrerepresentadas. EL votante de ambas formaciones serías más jóvenen. Compromis obtiene mayor reprentación de los municipios próximos a la costa y de tradición valenciano-parlante (en general) y ERC se centra también en la Cataluña más industrializada que es Barcelona y las poblaciones que lindan a la ciudad.

Sessión

sessionInfo()
#> R version 3.6.1 (2019-07-05)
#> Platform: x86_64-w64-mingw32/x64 (64-bit)
#> Running under: Windows 10 x64 (build 18362)
#> 
#> Matrix products: default
#> 
#> locale:
#> [1] LC_COLLATE=English_United Kingdom.1252 
#> [2] LC_CTYPE=English_United Kingdom.1252   
#> [3] LC_MONETARY=English_United Kingdom.1252
#> [4] LC_NUMERIC=C                           
#> [5] LC_TIME=English_United Kingdom.1252    
#> 
#> attached base packages:
#> [1] stats     graphics  grDevices utils     datasets  methods   base     
#> 
#> other attached packages:
#>  [1] DT_0.9                     treemapify_2.5.3          
#>  [3] viridis_0.5.1              viridisLite_0.3.0         
#>  [5] LAU2boundaries4spain_0.1.0 sf_0.8-0                  
#>  [7] forcats_0.4.0              stringr_1.4.0             
#>  [9] dplyr_0.8.3                purrr_0.3.3               
#> [11] readr_1.3.1                tidyr_1.0.0               
#> [13] tibble_2.1.3               ggplot2_3.2.1             
#> [15] tidyverse_1.2.1           
#> 
#> loaded via a namespace (and not attached):
#>  [1] nlme_3.1-140            lubridate_1.7.4        
#>  [3] httr_1.4.1              rprojroot_1.3-2        
#>  [5] tools_3.6.1             backports_1.1.5        
#>  [7] R6_2.4.1                KernSmooth_2.23-15     
#>  [9] rgeos_0.5-1             DBI_1.0.0              
#> [11] lazyeval_0.2.2          colorspace_1.4-1       
#> [13] withr_2.1.2             sp_1.3-1               
#> [15] tidyselect_0.2.5        rnaturalearthdata_0.1.0
#> [17] gridExtra_2.3           curl_4.2               
#> [19] compiler_3.6.1          cli_1.1.0              
#> [21] rvest_0.3.4             xml2_1.2.2             
#> [23] plotly_4.9.0            labeling_0.3           
#> [25] scales_1.0.0            classInt_0.4-2         
#> [27] digest_0.6.22           foreign_0.8-71         
#> [29] rmarkdown_1.15          rio_0.5.16             
#> [31] base64enc_0.1-3         pkgconfig_2.0.3        
#> [33] htmltools_0.3.6         highr_0.8              
#> [35] htmlwidgets_1.5.1       rlang_0.4.2            
#> [37] readxl_1.3.1            rstudioapi_0.10        
#> [39] shiny_1.3.2             generics_0.0.2         
#> [41] jsonlite_1.6            crosstalk_1.0.0        
#> [43] zip_2.0.4               magrittr_1.5           
#> [45] Rcpp_1.0.3              munsell_0.5.0          
#> [47] ggfittext_0.8.1         lifecycle_0.1.0        
#> [49] stringi_1.4.3           yaml_2.2.0             
#> [51] plyr_1.8.4              grid_3.6.1             
#> [53] promises_1.0.1          crayon_1.3.4           
#> [55] lattice_0.20-38         haven_2.1.1            
#> [57] hms_0.5.1               zeallot_0.1.0          
#> [59] knitr_1.25              pillar_1.4.2           
#> [61] reshape2_1.4.3          glue_1.3.1             
#> [63] evaluate_0.14           data.table_1.12.4      
#> [65] modelr_0.1.5            vctrs_0.2.0            
#> [67] httpuv_1.5.2            cellranger_1.1.0       
#> [69] gtable_0.3.0            assertthat_0.2.1       
#> [71] xfun_0.9                openxlsx_4.1.0.1       
#> [73] mime_0.7                xtable_1.8-4           
#> [75] broom_0.5.2             e1071_1.7-2            
#> [77] rnaturalearth_0.1.0     later_1.0.0            
#> [79] class_7.3-15            units_0.6-5            
#> [81] ellipsis_0.3.0          here_0.1

Apéndice Técnico

Archivo: preparacion_datos.R

Los datos están obtenidos del MIR y utilizando estas funciones los hemos preparado para su uso.

resultadoDiputados <- function(df, rows){
    g <- df
    rows <- rows
    
    ## Generamos un df solo con los datos de las provincias y su poblacion
    pobCom <- g[5:rows, 1:4]
    colnames(pobCom)[1:4] <- c("comunidad", "codigo.prov", "provincia", "poblacion")

    
    ## Generamos un df para los votos y diputados del 
    gen <- g %>% mutate("codigo.prov" = X2 ) %>% select(-c(1, 3:16)) %>% select(c(1, length(.), 2:(length(.)-1)))
    names(gen) <- as.character(gen[3,])
    
    even_indexes<-seq(2,length(gen),2)
    odd_indexes<-seq(1,length(gen),2)
    
    diputados <- gen[,even_indexes]
    votos <- gen[,odd_indexes]
    
    diputados <- diputados[5:rows,]
    colnames(diputados) <- colnames(votos)
    diputados <- gather(diputados, partido, diputados, 2:length(diputados))
    colnames(diputados)[1] <- "codigo.prov"
    
    votos <- votos[5:rows,]
    votos <- gather(votos, partido, votos, 2:length(votos))
    colnames(votos)[1] <- "codigo.prov"
    
    diputados <- left_join(pobCom, diputados, by="codigo.prov")
    
    
    votos <- left_join(pobCom, votos, by="codigo.prov")
    votos <- filter(votos, votos > 0)
    
    # Unimos los df para crear el definitivo
    gen <- full_join(votos, diputados)
    
    gen$codigo.prov <- as.numeric(gen$codigo.prov)
    gen$codigo.prov <- sprintf("%02d", gen$codigo.prov)
    gen$provincia <- trimws(gen$provincia, "r")
    
    gen[,c(4,6,7)] <- sapply(gen[,c(4,6,7)], as.numeric)

    rm(list = c("g", "pobCom", "votos", "diputados"))
    
    return(gen)
    
}

resultadoDiputadosTipoVotos <- function(df, rows){
    g <- df
    rows <- rows
    
    ## Generamos un df solo con los datos de las provincias y su poblacion
    pobCom <- g[4:rows, 1:16]
    colnames(pobCom) <- pobCom[1,] %>% tolower(.) %>% gsub(" de ", " ", .) %>% 
        gsub(" ", ".", .) %>% chartr('áéíóúñ','aeioun', .)
    colnames(pobCom)[1:3] <- c("comunidad", "codigo.prov", "provincia")
    pobCom <- pobCom[-c(1),] %>% gather(tipo.voto, tipo.voto.num, 6:16 )
    
    pobCom$codigo.prov <- as.numeric(pobCom$codigo.prov)
    pobCom$codigo.prov <- sprintf("%02d", pobCom$codigo.prov)
    pobCom$provincia <- trimws(pobCom$provincia, "r")

    pobCom[,c(4,5,7)] <- sapply(pobCom[,c(4,5,7)], as.numeric)
    
    rm(list = c("g", "rows"))
    
    return(pobCom)
    
}

Estas dos funciones utlizan el paquete TidyVerse y por un lado resultadosDiputados obtiene un dataframe con el número de votos y diputados que cada formación política ha obtenido en cada comunidad. La función resultadosDiputadosTipoVoto crea otro dataframe partiendo del mismo archivo pero con los datos relativos al tipo de voto: CER, CERA, abtensión, valido, nulo, censo electoral etc. Debido a la ingente cantidad de datos, el archivo original lo hemos separado en dos dataframes más manejables.

resultadoMunicipios <- function(df, rows){
    g <- df
    rows <- rows
    
    colnames(g) <- as.character(g[3,])
    # g <- janitor::clean_names(g)
    municipios <- g[4:rows,]
    municipios <- municipios %>% select(-c(7:13))
    municipios <- municipios %>% gather(partido, votos, 7:length(.))
    colnames(municipios) <- c("comunidad", "codigo.prov", "provincia", "codigo.muni", 
                              "municipio","poblacion", "partido", "votos")
    municipios$poblacion <- as.numeric(municipios$poblacion)
    municipios$votos <- as.numeric(municipios$votos)
    municipios$codigo.prov <- as.numeric(municipios$codigo.prov)
    municipios$codigo.prov <- sprintf("%02d", municipios$codigo.prov)
    municipios$codigo.muni <- as.numeric(municipios$codigo.muni)
    municipios$codigo.muni <- sprintf("%03d", municipios$codigo.muni)
    municipios$provincia <- trimws(municipios$provincia, "r")

    return(municipios)
    
    rm(list = c("g", "municipios", "rows"))
}

resultadoMunicipiosTipoVotos <- function(df, rows){
    g <- df
    rows <- rows
    
    colnames(g) <- as.character(g[3,])
    # g <- janitor::clean_names(g)
    municipios <- g[4:rows,1:13]
    municipios <- municipios %>% select(-c(7)) %>% gather(tipo.voto, tipo.voto.num, 8:length(.))
    colnames(municipios) <- c("comunidad", "codigo.prov", "provincia", "codigo.muni", 
                              "municipio","poblacion", "censo.electoral", "tipo.voto", "tipo.voto.num")
    municipios$poblacion <- as.numeric(municipios$poblacion)
    municipios$votos <- as.numeric(municipios$tipo.voto.num)
    municipios$codigo.prov <- as.numeric(municipios$codigo.prov)
    municipios$codigo.prov <- sprintf("%02d", municipios$codigo.prov)
    municipios$codigo.muni <- as.numeric(municipios$codigo.muni)
    municipios$codigo.muni <- sprintf("%03d", municipios$codigo.muni)
    municipios$provincia <- trimws(municipios$provincia, "r")
    
    return(municipios)
    
    rm(list = c("g", "municipios", "rows"))
}

Las funciones anteriores hacen la misma función que las descritas para los resultados generales pero estas se utilizan para los resultados municipales.

EL procedimiento para usar las funciones es el siguiente: resultadoDiputados(dataframe, filas). El atributo dataframe es el conjunto de datos sobre el que trabajará y el atributo filas es el número de filas útiles ya que estos archivos contiene filas en blanco o que muestran totales. Por praticidad decidimos eliminarlas y si necesitamos los totales los calularemos insitu. Para el resto de funciones es el mismo procedimiento, la función está programa para saber que columnas tiene que utilizar. Las funciones originales se encuentran en el archivo preparacion_datos.R

Archivo: funciones.R

Este archivo incluye una series de funciones que nos han sido muy útiles.

# Función para poder unir correctamente los df de los resultados con los códigos de las CCAA y provincias.

limpiarProv <- function(x){
    x <- tolower(x)
    x <- gsub(", comunidad de", "", x)
    x <- gsub(", regi\u00F3n de", "", x)
    x <- gsub(", comunidad foral de", "", x)
    x <- gsub(", principado de", "", x)
    x <- gsub("coruña, a", "A Coruña", x) 
    x <- gsub("balears, illes", "illes balears", x) 
    x <- gsub("rioja, la", "la rioja", x)
    x <- gsub("palmas, las", "las palmas", x) 
    x <- tools::toTitleCase(x)
}

Un poco de tunning para los mapas y graficos. Lo hacemos en una función para estandarizar el aspecto de los mapas y ahorrarnos escribir todo ese texto en cada uno de los que hemos hecho. Misma lógica para los gráficos y los gráficos con facet

theme_map <- function(...) {
    theme_minimal() +
        theme(panel.grid.major = element_line(color = "#dbdbd9", size = 0.2), 
              panel.grid.minor = element_line(colour = "gray99"), 
              plot.background = element_rect(fill = "#f5f5f2", color = NA),
              panel.background = element_rect(fill = "#f5f5f2", color = NA),
              legend.background = element_rect(fill = "#f5f5f2", color = NA),
              legend.key = element_rect(fill = NA),
              legend.position = "top",
              legend.direction = "horizontal",
              axis.line = element_blank(),
              axis.text.x = element_blank(),
              axis.text.y = element_blank(),
              axis.ticks = element_blank(),
              axis.title.x = element_blank(),
              axis.title.y = element_blank(),
              text = element_text(color = "#22211d"),
              plot.title = element_text(hjust = 0.5, face = "bold", lineheight = "20px", size = "15"),
              plot.subtitle = element_text(hjust = 0.5, size = "9"))

}

theme_plot <- function(...){
    theme_minimal() +
        theme(panel.grid.major = element_line(colour = "gray99"), 
              panel.grid.minor = element_line(colour = "gray90"), 
              plot.background = element_rect(fill = "#f5f5f2", color = NA),
              panel.background = element_rect(fill = "#f5f5f2", color = NA),
              legend.background = element_rect(fill = "#f5f5f2", color = NA),
              legend.position = "bottom",
              legend.direction = "horizontal",
              axis.text.x = element_text(angle = 90, hjust = 1),
              axis.title.x = element_blank(),
              text = element_text(family = "sans", color = "#22211d"),
              plot.title = element_text(hjust = 0.5, face = "bold", lineheight = "15", size = "12"),
              plot.subtitle = element_text(hjust = 0.5, size = "9"),
              plot.margin = margin(1, 1, 1, 1, "cm"))
}

theme_plot_facet <- function(...){
        theme(panel.grid.major = element_line(colour = "gray99"), 
              panel.grid.minor = element_line(colour = "gray90"), 
              plot.background = element_rect(fill = "#f5f5f2", color = NA),
              panel.background = element_rect(fill = "#f5f5f2", color = NA),
              legend.background = element_rect(fill = "#f5f5f2", color = NA),
              legend.position = "bottom",
              legend.direction = "horizontal",
              axis.text.x = element_text(angle = 90, hjust = 1),
              axis.title.x = element_blank(),
              text = element_text(family = "sans", color = "#22211d"),
              plot.title = element_text(hjust = 0.5, face = "bold", lineheight = "15", size = "12"),
              plot.subtitle = element_text(hjust = 0.5, size = "9"),
              plot.margin = margin(1, 1, 1, 1, "cm"))
}

default_caption <- "Elaboraci\u00F3n propia. Datos del Ministerio del Interior"

Función para cargar geometrias. Muy útil, tiene varios modos descritos posteriormente y que cargan las geometrias de España según nuestros criterios. Basado en el paquete LAU2boundaries4spain disponible en Github. loadGeometry(modo, provincias, municipios). provincias y municipios lo utilzaremos por si queremos obtener geoetrias concretas. Modos - 1: Solo península y baleares - 2: península, baleares y canarias - 3: filtrar provincias con su código - 4: municipios (2018) - 5: filtrar municipios por código de municipios del INE - 6: filtrar municipios por código de provincia

## Cargar geometria
# 1: solo peninsula, 2: canarias + peninsula, 3: provincias por codigo, 4: municipios 2018, 5-6: filtro municipios 2018
loadGeometry <- function(mode = 1, provincias = NULL, municipios = NULL){

    library(sf)
    library(LAU2boundaries4spain)
    # library(tidyverse)
    
    if(mode==1){
        peninsula <- Provincias %>% filter( !(INECodProv %in% c(35, 38)) )
        colnames(peninsula)[1] <- c("codigo.prov")
        return(peninsula)
    }
    
    if(mode==2){
        # https://github.com/perezp44/LAU2boundaries4spain
        canarias <- Provincias %>% filter(INECodProv %in% c(35,38))
        peninsula <- Provincias %>% filter( !(INECodProv %in% c(35, 38)) )
        my_shift <- st_bbox(peninsula)[c(1,2)]- (st_bbox(canarias)[c(1,2)]) + c(-2.4, -1.1)
        canarias$geometry <- canarias$geometry + my_shift
        st_crs(canarias)  <- st_crs(peninsula)
        peninsula_a <- rbind(peninsula, canarias)
        colnames(peninsula_a)[1] <- c("codigo.prov")
        return(peninsula_a)
    }
    
    if(mode==3){
        
        x <- Provincias %>% filter(INECodProv %in% provincias)
        colnames(x)[1] <- c("codigo.prov")
        return(x)
    }
    
    if(mode==4){
        x <- municipios_2018
        return(x)
    }
    
    if(mode==5){
        x <- municipios_2018 %>% filter(INECodMuni %in% municipios)
        return(x)
    }
    if(mode==6){
        x <- municipios_2018 %>% filter(INECodProv %in% provincias)
        return(x)
    }

}
LS0tDQp0aXRsZTogIkFsZ3Vub3MgbWl0b3MgeSByZWFsaWRhZGVzIGRlIGxhcyBlbGVjY2lvbmVzIGRlbCAyOEEiDQpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiDQphdXRob3I6ICJBbXBhcm8gTW9jaG9saSwgSHVnbyBTYWl6IHkgSmF2aWVyIENvdGFuZGEiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgdG9jOiB0cnVlDQogICAgdG9jX2Zsb2F0OiB5ZXMNCiAgICBzZWxmX2NvbnRhaW5lZDogeWVzDQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KICAgIGNvZGVfZm9sZGluZzogc2hvdw0KLS0tDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCBldmFsID0gVFJVRSwgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0UsIA0KICAgICAgICAgICAgICAgICAgICAgIGNhY2hlID0gRkFMU0UsIGNhY2hlLnBhdGggPSAiL2NhY2hlcy8iLCBjb21tZW50ID0gIiM+IiwNCiAgICAgICAgICAgICAgICAgICAgICBjb2xsYXBzZSA9IFRSVUUsICBmaWcuc2hvdyA9ICJob2xkIiwNCiAgICAgICAgICAgICAgICAgICAgICBvdXQud2lkdGggPSAiMTAwJSIsIGZpZy5hbGlnbiA9ICJjZW50ZXIiKQ0KDQpvcHRpb25zKGVuY29kaW5nID0gJ1VURi04JykNCmBgYA0KDQoNCiMjIEludHJvZHVjY2nDs24gey50YWJzZXR9DQoNCiMjIyBPYmpldGl2b3MNCg0KRWwgb2JqZXRpdm8gZGUgZXN0ZSB0cmFiYWpvIGVzIGFuYWxpemFyIGRlIHVuYSBmb3JtYSBtw6FzIHZpc3VhbCB0cmVzIGFzcGVjdG9zIHF1ZSBjb25zaWRlcmFtb3MgY3VyaW9zb3MgZGUgbGFzIHBhc2FkYXMgZWxlY2Npb25lcyBkZWwgMjhBLiBOdWVzdHJhIHByaW1lcmEgaW50ZW5jacOzbiBlcyBvYnNlcnZhciBzaSBsb3MgdGl0dWxhcmVzIGRlIGxvcyBtZWRpb3MgZGUgY29tdW5pY2FjacOzbiBzb2JyZSBsYSBpcnJ1cGNpw7NuIGRlIFZPWCwgZXNwZWNpYWxtZW50ZSBlbiBsb3MgbXVuaWNpcGlvcyBjb20gbWF5b3IgcHJvcG9yY2nDs24gZGUgcG9ibGFjacOzbiBleHRyYW5qZXJhLCBzb24gY2llcnRvcy4gRW4gZWwgc2lndWllbnRlIGFwYXJ0YWRvIHZlcmVtb3MgZWwgY29zdGUgcXVlIHRpZW5lIHBhcmEgY2FkYSBwYXJ0aWRvIG9idGVuZXIgcmVwcmVzZW50YWNpw7NuIGVuIGVsIENvbmdyZXNvIGRlIGxvcyBEaXB1dGFkb3MuIEZpbmFsaXphcmVtb3MgY29uIHVuIGFuw6FsaXNpcyBzb2JyZSBsYXMgZGlmZXJlbmNpYXMgZW50cmUgZG9zIHBhcnRpZG9zIG5hY2lvbmFsaXN0YXM6IENvbXByb21pcyB5IEVSQy4gTGFzIGRpZmVyZW5jaWEgZW4gbGEgcHJvcGVuc2nDs24gYWwgdm90byB5IG90cm9zIGFzcGVjdG9zLg0KDQojIyMgRnVlbnRlIGRlIGxvcyBkYXRvcw0KDQpMb3MgZGF0b3MgdXRpbGl6YWRvcyBwcm92aWVuZW4gZGVsIFtNaW5pc3RlcmlvIGRlbCBJbnRlcmlvcl0oaHR0cDovL3d3dy5pbmZvZWxlY3RvcmFsLm1pci5lcy9pbmZvZWxlY3RvcmFsL21pbi9hcmVhRGVzY2FyZ2EuaHRtbD9tZXRob2Q9aW5pY2lvKSB5IGRlbCBJbnN0aXR1dG8gTmFjaW9uYWwgZGUgRXN0YWTDrXN0aWNhLiBBIGNvbnRpbnVhY2nDs24gaW1wb3J0YW1vcyBsb3MgZGF0b3MgcXVlIHByZXZpYW1lbnRlIHkgdGFsIHkgY29tbyBzZSBtdWVzdHJhIGVuIGVsIGFww6luZGljZSB0w6ljbmljbyBoZW1vcyBoZWNobyB0aWR5LiBMYSBmdWVudGVzIGRlIGxvcyBkYXRvcyAoZWwgTUlSKSBwcmVzZW50YSB1bm9zIGRhdG9zIHF1ZSBzb24gdmlzdWFsbWVudGUgdmFsaWRvcyBwZXJvIHF1ZSBhIGVmZWN0b3MgZGUgdHJhdGFtaWVudG8gbm8gbm9zIHNpcnZlbi4gRW4gZWwgYXDDqW5kaWNlIHTDqWNuaWNvIHNlIGV4cGxpY2EgZGV0YWxsYWRhbWVudGUgZWwgcHJvY2VzbyBsbGV2YWRvIGEgY2Fiby4NCg0KIyMjIEFzcGVjdG9zIHByZXZpb3MNCg0KUHJpbWVyb3MgaW1wb3J0YW1vcyBsYXMgbGlicmVyaWFzIGLDoXNpY2FzLCB1dGlsaXphbW9zIG3DoXMgbGlicmVyaWFzIHBlcm8gbGFzIGxsYW1hbW9zIGN1YW5kbyBsYXMgbmVjZXNpdGFtb3MuIExlcyByZW1pdG8gYWwgYHNlc3Npb25JbmZvKClgIHBhcmEgdmVyIHRvZG9zIGxvcyBwYXF1ZXRlcyB1dGlsaXphZG9zLg0KDQpgYGB7ciBsaWJyYXJ5X3NldHVwfQ0KDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkoc2YpDQpsaWJyYXJ5KExBVTJib3VuZGFyaWVzNHNwYWluKQ0KbGlicmFyeSh2aXJpZGlzKQ0KDQojIGNhcmdhbW9zIHRvZGFzIGxhcyBmdW5jaW9uZXMgbXV5IMO6bHRpbGVzIHBhcmEgZWwgZGVhcnJvbGxvIGRlbCB0cmFiYWpvLCBlbGFib3JhZGFzIHBvciBub3NvdHJvcw0Kc291cmNlKCJmdW5jaW9uZXMuUiIpDQoNCmBgYA0KDQpDYXJnYW1vcyBsb3MgZGF0b3MgcXVlIGhlbW9zIGhlY2hvIHRpZHkgcHJldmlhbWVudGUuIExvcyBkYXRvcyBvcmlnaW5hbGVzIHNlIGVuY3VlbnRyYW4gZW4gbGEgY2FycGV0YSBgZGF0YS9yYXdgLiBBIGNvbnRpbnVhY2nDs24gbGUgYXBsaWNhbW9zIGxhIGZ1bmNpw7NuIGBwYXJ0aWRvc05vbSgpYCBwYXJhIGxpbXBpYXIgZWwgbm9tYnJlIGRlIGxvcyBwYXJ0aWRvcyB5IHJlZHVjaXIgZW4gYWxndW5vcyBjYXNvcyBzdSBleHRlbnNpw7NuLg0KDQpgYGB7ciBkZl9iYXNlfQ0KIyBDYXJnYW1vcyBkZiBkZSBsYXMgZWxlY2Npb25lcyB5IGxpbXBpYW1vcyBsb3Mgbm9tYnJlIGRlIGxvcyBwYXJ0aWRvcw0KZ2VuZXJhbGVzMjhBIDwtIHJpbzo6aW1wb3J0KGhlcmU6OmhlcmUoIi4vZGF0YS8iLCAiZ2VuZXJhbGVzMjhBLnJkYXRhIikpICU+JSBwYXJ0aWRvc05vbSguKQ0KbXVuaWNpcGlvczI4QSA8LSByaW86OmltcG9ydChoZXJlOjpoZXJlKCIuL2RhdGEvIiwgIm11bmljaXBpb3MyOEEucmRhdGEiKSkgJT4lIHBhcnRpZG9zTm9tKC4pDQpDQ0FBUHJvdkNvZGlnb3MgPC0gcmlvOjppbXBvcnQoaGVyZTo6aGVyZSgiLi9kYXRhLyIsICJDQ0FBUHJvdkNvZGlnb3MucmRhdGEiKSkgIyBXaXRoIGxlYWRpbmcgMHMNCmBgYA0KDQoNCiMjIFNvYnJlIFZveCB5IGxvcyBtZWRpb3MgZGUgY29tdW5pY2FjacOzbg0KDQpMb3MgbWVkaW9zIGRlIGNvbXVuaWNhY2nDs24gaGFuIGp1Z2FkbyBjb24gbG9zIGRhdG9zIHBhcmEgbW9zdHJhciBxdWUgZXhpc3RpYSB1bmEgY29ycmVsYWNpw7NuIGVudHJlIGVsIHZvdG8gYSBWT1ggeSBsYSBpbm1pZ3JhY2nDs24uIEVzIGNpZXJ0byBxdWUgaGEgZ2FuYWRvIGVuIG11bmljaXBpb3MgY29uIHRhc2EgZGUgaW5taWdyYWNpw7NuIGFsdGFzIGNvbW8gRWwgRWppZG8gcGVybyBlbCBuw7ptZXJvIHRvdGFsIGRlIG11bmljaXBpb3MgZXMgaW5zaWduaWZpY2FudGUgeSBkZXN0YWNhIGxvIHBlcXVlw7FvcyBxdWUgc29uIGxvcyBtdW5pY2lwaW9zLiBFc3RhYmxlY2VyZW1vcyB1bmEgY29ycmVsZWFjacOzbiBxdWUsIGEgbnVlc3RybyBqdWljaW8sIGVzIG3DoXMgYWNlcnRhZGEuDQoNCk5vcyBoZW1vcyBjZW50cmFkbyBlbiBsb3MgZGF0b3MgZGVsIElORSBkZSAyMDE5IHNvYnJlIGxhcyBlc3RhZMOtc3RpY2FzIGRlbCBQYWRyw7NuIENvbnRpbnVvIHNvYnJlIGVsIHBvcmNlbnRhamUgZGUgcG9ibGFjacOzbiBpbm1pZ3JhbnRlLiBTZWfDum4gbGEgaGlww7N0ZXNpcyBkZSBsb3MgbWVkaW9zIGRlIGNvbXVuaWNhY2nDs24sIGVsIHBhcnRpZG8gVm94IHNhbGRyw61hIGNvbiBtYXlvciByZXByZXNlbnRhY2nDs24gZW4gYXF1ZWxsb3MgbHVnYXJlcyBkZWwgRXN0YWRvIGRvbmRlIGVsIHBvcmNlbnRhamUgZGUgcG9ibGFjacOzbiBleHRyYW5qZXJhIGVzIG3DoXMgYWx0by4NCg0KQ29tbyBwb2RlbW9zIG9ic2VydmFyLCBlbiBsb3MgbXVuaWNpcGlvcyBlbiBsb3MgcXVlIGhhIGdhbmFkbyBWT1ggc29uOg0KDQpgYGB7ciB2b3hfcHJlZGZ9DQojIEltcG9ydGFtb3MgbG9zIGRhdG9zIHF1ZSBwcmV2aWFtZW50ZSBoZW1vcyBsaW1waWFkbyBwYXJhIHRvZG8gZWwgc3VwdWVzdG8NCg0KcG9iRXh0RXNjYW5vcyA8LSByaW86OmltcG9ydCgiLi9kYXRhL3BvYmxhY2lvbl9FeHRyYW5qZXJhLnJkYXRhIikNCnBvYkV4dCA8LSByaW86OmltcG9ydCgiLi9kYXRhL3BvYmxhY2lvbkV4dHJhbmplcmEucmRhdGEiKQ0KDQpgYGANCg0KDQpgYGB7ciB2b3hfZzEsIGV2YWw9VFJVRSwgaW5jbHVkZT1UUlVFfQ0KVk9YMjhBIDwtIG11bmljaXBpb3MyOEEgJT4lIGdyb3VwX2J5KGNvbXVuaWRhZCwgY29kaWdvLnByb3YsIGNvZGlnby5tdW5pKSAlPiUgdG9wX24oMSx2b3RvcykgJT4lDQogICAgZmlsdGVyKHBhcnRpZG8gPT0gIlZPWCIpICU+JSB1bmdyb3VwKCkgJT4lIGdyb3VwX2J5KGNvZGlnby5wcm92KSAlPiUgDQogIG11dGF0ZSh0b3RhbC52b3RvcyA9IHN1bSh2b3RvcyksIHRvdGFsLm11bmkgPSBuKCkpICU+JQ0KICAgIHVuZ3JvdXAoKSAlPiUgIGRpc3RpbmN0KHByb3ZpbmNpYSwgdG90YWwubXVuaSwgdG90YWwudm90b3MpDQoNCiMgY29uIHRyaW13cyBxdWl0YW1vcyBsb3MgZXNwYWNpb3MgZW4gYmxhbmNvIHF1ZSBwYXJlY2UgcXVlIG5vIGVzdMOhbiBwZXJvIHPDrSB5IGZhc3RpZGlhbiBlbCBncsOhZmljbw0KVk9YMjhBJHByb3ZpbmNpYSA8LSBWT1gyOEEkcHJvdmluY2lhICU+JSBnc3ViKCJDYXN0ZWxsw7NuIC8gIiwgIiIsIC4pICU+JSBnc3ViKCJWYWxlbmNpYSAvICIsICIiLCAuKQ0KDQpnZ3Bsb3QoVk9YMjhBLCBhZXMoZm9yY2F0czo6ZmN0X3Jlb3JkZXIocHJvdmluY2lhLCB0b3RhbC5tdW5pKSwgdG90YWwubXVuaSkpICsgDQogIGdlb21fY29sKGFlcyhmaWxsID0gdG90YWwudm90b3MpKSArDQogICAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHRvdGFsLnZvdG9zKSwgbnVkZ2VfeSA9IDIsICBzaXplPTMpICsNCiAgICBzY2FsZV9maWxsX3ZpcmlkaXNfYyhvcHRpb24gPSAibWFnbWEiLCBuYW1lID0gIlZvdG9zIiwgYWxwaGEgPSAwLjgsIGJlZ2luID0gMC4zLCBlbmQgPSAwLjcsIGRpcmVjdGlvbiA9IDEsDQogICAgICAgICAgICAgICAgICAgICAgICAgZ3VpZGUgPSBndWlkZV9jb2xvcmJhciggZGlyZWN0aW9uID0gImhvcml6b250YWwiLCBiYXJoZWlnaHQgPSB1bml0KDIsIHVuaXRzID0gIm1tIiksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhcndpZHRoID0gdW5pdCg1MCwgdW5pdHMgPSAibW0iKSwgZHJhdy51bGltID0gRiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGUucG9zaXRpb24gPSAndG9wJywgdGl0bGUuaGp1c3QgPSAwLjUsIGxhYmVsLmhqdXN0ID0gMC41DQogICAgICAgICAgICAgICAgICAgICAgICAgKSkgKw0KICAgIHRoZW1lX3Bsb3QoKSArIHRoZW1lKGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KSkgKw0KICAgIGxhYnModGl0bGUgPSAiUHJvdmluY2lhcyBlbiBsYXMgcXVlIFZveCBoYSBzaWRvIGxhIGZ1ZXJ6YSBtw6FzIHZvdGFkYSIsDQogICAgICAgICBzdWJ0aXRsZSA9ICJOw7ptZXJvIHRvdGFsIGRlIG11bmljaXBpb3MgcG9yIHByb3ZpbmNpYXMiLA0KICAgICAgICAgY2FwdGlvbiA9IGRlZmF1bHRfY2FwdGlvbikgKyB0aGVtZShheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCkpDQpgYGANCg0KDQpFcyBjdXJpb3NvIGNvbW8gaGEgZ2FuYWRvIGNvbiBhIHBlbmFzIHVuIHB1w7FhZG8gZGUgdm90b3MuIFBvciBlamVtcGxvLCBlbiBTb3JpYSBoYSBzaWRvIGxhIGZ1ZXJ6YSBtw6FzIHZvdGFkYSBlbiBjaW5jbyBtdW5pY2lwaW9zIG9idGVuaWVuZG8gdW4gZ2xvYmFsIGRlIDUwIHZvdG9zLiBMYSBwcm92aW5jaWEgbcOhcyBkZXN0YWNhIGVzIEFsbWVyw61hIHF1ZSBoYSBnYW5hZG8gZW4gdHJlcyBtdW5pY2lwaW9zIHBlcm8gaGEgb2J0ZW5pZG8gdW4gbsO6bWVybyBkZSB2b3RvcyBleGFnZXJhZG8uIENvbW8gZGVjw61hbW9zIGFudGVyaW9tZW50ZSwgZWwgbHVnYXIgbcOhcyBkZXN0YWNhZGEgZXMgRWwgRWppZG8gcXVlIGVzIHVubyBkZSBsb3MgbXVuaWNpcGlvcyBjb24gbWF5b3IgcG9yY2VudGFqZSBkZSBwb2JsYWNpw7NuIGlubWlncmFudGUuDQoNCkV4Y2VwdHVhbmRvIE1hZHJpZCwgbGEgbWF5b3IgcGFydGUgc29uIHByb3ZpbmNpYXMgZGVsIGludGVyaW9yIGRlIEVzcGHDsWEuIMK/UGVybyBzb24gZXN0YXMgbGFzIHF1ZSB0aWVuZW4gdW4gbWF5b3IgcG9yY2VudGFqZSBkZSBwb2JsYWNpw7NuIGV4dHJhbmVqZXJhPw0KDQpgYGB7ciwgaW5jbHVkZT1UUlVFLCBldmFsPVRSVUV9DQpwcm92X2lubWkgPC0gcG9iRXh0ICU+JSB0b3BfbigxNCwgcG9yY2VudGFqZSkgDQoNCmxpYnJhcnkodHJlZW1hcGlmeSkNCmdncGxvdChwcm92X2lubWksIGFlcyhhcmVhID0gcG9yY2VudGFqZSwgZmlsbCA9IHBvcmNlbnRhamUsIGxhYmVsID0gcHJvdmluY2lhKSkgKw0KICAgIGdlb21fdHJlZW1hcCgpICsNCiAgICBnZW9tX3RyZWVtYXBfdGV4dChmb250ZmFjZSA9ICJpdGFsaWMiLCBjb2xvdXIgPSAid2hpdGUiLCBwbGFjZSA9ICJjZW50cmUiLA0KICAgICAgICAgICAgICAgICAgICAgIGdyb3cgPSBGQUxTRSkgKyANCiAgICBzY2FsZV9maWxsX3ZpcmlkaXNfYyhvcHRpb24gPSAidmlyaWRpcyIsIG5hbWUgPSAiIiwgYWxwaGEgPSAwLjgsIGJlZ2luID0gMC4zLCBlbmQgPSAwLjcsIGRpcmVjdGlvbiA9IDEsDQogICAgICAgICAgICAgICAgICAgICAgICAgZ3VpZGUgPSBndWlkZV9jb2xvcmJhciggdGl0bGUgPSAiUG9yY2VudGFqZSIsIGRpcmVjdGlvbiA9ICJob3Jpem9udGFsIiwgYmFyaGVpZ2h0ID0gdW5pdCgyLCB1bml0cyA9ICJtbSIpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYXJ3aWR0aCA9IHVuaXQoNTAsIHVuaXRzID0gIm1tIiksIGRyYXcudWxpbSA9IEYsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlLnBvc2l0aW9uID0gJ3RvcCcsIHRpdGxlLmhqdXN0ID0gMC41LCBsYWJlbC5oanVzdCA9IDAuNQ0KICAgICAgICAgICAgICAgICAgICAgICAgICkpICsgDQogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICsNCiAgICBsYWJzKHRpdGxlID0gIlByb3ZpbmNpYXMgY29uIG1heW9yIHBvcmNlbnRhamUgZGUgcG9ibGFjacOzbiBleHRyYW5qZXJhIiwNCiAgICAgICAgIGNhcHRpb24gPSAiRXN0YWTDrXN0aWNhcyBkZWwgUGFkcsOzbiBDb250aW51by4gMSBkZSBFbmVybyBkZSAyMDE5LiIpDQpgYGANCg0KDQpMYSByZWFsaWRhZCBlcyBxdWUgbGFzIGRpZXogcHJpbWVyYXMgcHJvdmluY2lhcyBjb24gbWF5b3IgcG9yY2VudGFqZSBkZSBwb2JsYWNpw7NuIGV4dHJhbmplcmEgbm8gc2UgY29ycmVzcG9uZGVuIGNvbiBlbCBncsOhZmljbyBhbnRlcmlvcm1lbnRlIG9idGVuaWRvLiBHdWFkYWxhamFyYSwgcXVlIGFudGVzIGVyYSBsYSBwcmltZXJhIHNlIGVuY3VlbnRyYSBlbiBsYSBjYXRvcmNlYXZhIHBvc2ljacOzbi4gIFBvciBvdHJvIGxhZG8sIGVzIGVzcGVjaWFsbWVudGUgcmVsZXZhbnRlIGVsIGNhc28gZGUgR2lyb25hLCB5YSBxdWUgc2llbmRvIHVuYSBkZSBsYXMgcHJvdmluY2lhcyBjb24gbWF5b3IgcG9yY2VudGFqZSBkZSBwb2JsYWNpw7NuIGV4dHJhbmplcmEsIG5vIGV4aXN0ZSBuaW5nw7puIG11bmljaXBpbyBlbiBlbCBxdWUgVk9YIG9idGVuZ2EgcmVwcmVzZW50YWNpw7NuIHBvciBwZXF1ZcOxbyBxdWUgc2VhLiANCg0KYGBge3IsIGluY2x1ZGU9VFJVRSwgZXZhbD1UUlVFfQ0KZGlwdXRhZG9zMjhBIDwtIHBvYkV4dEVzY2Fub3MgJT4lIGZpbHRlcihjb21wbGV0ZS5jYXNlcyguKSwgZGlwdXRhZG9zID4gMCkgJT4lIG11dGF0ZShkaXB1X3F1YW50aWxlID0gY3V0KGFzLm51bWVyaWMoZGlwdXRhZG9zKSwgYnJlYWtzID0gYygxLDIsNSw3LDExKSwgaW5jbHVkZS5sb3dlc3QgPSBUUlVFKSkgJT4lIA0KICAgIG11dGF0ZShwb3JjX3F1YW50aWxlID0gY3V0KHBvcmNlbnRhamUsIGJyZWFrcyA9IDQsIGxhYmVscyA9IGMoIkJham8iLCAiTWVkaW8iLCAiTWVkaW8tQWx0byIsICJBbHRvIikpKQ0KDQpkaXB1X2xhYmVsID0gYygiMS0yIiwgIjMtNSIsICI2LTciLCAiOC0xMSIpDQoNCmBgYA0KDQpgYGB7ciwgZXZhbD1GQUxTRSwgZWNobz1GQUxTRX0NCg0KZ2dwbG90KGRpcHV0YWRvczI4QSwgYWVzKGZvcmNhdHM6OmZjdF9yZW9yZGVyKHByb3ZpbmNpYSwgcG9ibGFjaW9uKSwgZm9yY2F0czo6ZmN0X3Jlb3JkZXIocGFydGlkbywgcG9ibGFjaW9uKSkpICsgDQogICAgZ2VvbV9wb2ludChhZXMoc2l6ZT1wb3JjX3F1YW50aWxlLCBjb2xvciA9IGRpcHVfcXVhbnRpbGUpKSArIA0KICAgIHRoZW1lX3Bsb3QoKSArIHNjYWxlX3hfZGlzY3JldGUoYnJlYWtzID0gd2FpdmVyKCkpICsgDQogICAgdGhlbWUocGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAiZ3JheTgwIiksIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAxLCBzaXplID0gIjkiKSkgKw0KICAgIHNjYWxlX2ZpbGxfdmlyaWRpc19kKGFlc3RoZXRpY3MgPSAiY29sb3IiLCBkaXJlY3Rpb24gPSAxLCBvcHRpb24gPSAidmlyaWRpcyIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSAiRGlwdXRhZG9zIiwgYmVnaW4gPSAwLjEsIGVuZCA9IDAuOCwgbGFiZWwgPSBkaXB1X2xhYmVsKSArDQogICAgbGFicyh0aXRsZSA9ICJSZWxhY2nDs24gcmVwcmVzZW50YWNpw7NuLXBvYmxhY2nDs24gZXh0cmFuamVyYSBwb3IgcHJvdmluY2lhcyIsDQogICAgICAgICBzdWJ0aXRsZSA9ICJNYXlvciB0YW1hw7FvIHBvYmxhY2lvbmFsIOKftu+4jyIpICsgeWxhYigiIikgKyB4bGFiKCIiKQ0KYGBgDQoNCiFbXSguL2ltYWdlcy92b3hfcGxvdF8xLnBuZykNCg0KPGEgaHJlZj0iLi9pbWFnZXMvdm94X3Bsb3RfMS5wbmciIHRhcmdldD0iX2JsYW5rIj5bQW1wbGlhciBJbWFnZW5dPC9hPg0KDQpFbCBncsOhZmljbyBhbnRlcmlvciBtdWVzdHJhIGxhIHJlcHJlc2VudGFjacOzbiBkZSBsb3MgcGFydGlkb3MgcG9sw610aWNvcyBwb3IgcHJvdmluY2lhIHkgcG9yIHBvcmNlbnRhamUgZGUgcG9ibGFjacOzbiBleHRyYWplcmEgcmVzaWRlbnRlLiBBZGVtw6FzLCBsYSByZXByZXNlbnRhY2nDs24gcG9sw610aWNhIHNlIGRpc3RyaWJ1eWUgZW4gdW5hIGVzY2FsYSBkZSBjb2xvcmVzLCBkZSBvc2N1cm8gYSBjbGFybyBkZSBtZW5vciBhIG1heW9yIHJlcHJlc2VudGFjacOzbi4NClBhcmEgZGVzbWVudGlyIGxhIGlkZWEgZGUgcXVlIFZveCBoYWLDrWEgZ2FuYWRvIGVuIHByb3ZpbmNpYXMgY29uIHVuIGFsdG8gbsO6bWVybyBkZSBwb2JsYWNpw7NuIGV4dHJhbmplcmEgY29tcGFyYW1vcyBsb3MgcmVzdWx0YWRvcyBkZWwgUFNPRSB5IFBQLiBDb25jbHVpbW9zIHF1ZSBWb3ggaGEgdGVuaWRvIG1heW9yIHJlcHJlc2VudGFjacOzbiBlbiBwcm92aW5jaWFzIGdyYW5kZXMgeSBuYXR1cmFsbWVudGUgY29uIG1heW9yIG51bWVybyBkZSBwb2JsYWNpw7NuIGV4dHJhbmplcmEuIFNpbiBlbWJhcmdvLCBubyBzZSBvYnNlcnZhIHVuYSBjb3JyZWxhY2nDs24gZW50cmUgbGEgcmVwcmVzZW50YWNpw7NuIHkgbGEgcG9ibGFjacOzbiBpbm1pZ3JhbnRlIOKAlGNvbW8gZXMgZWwgY2FzbyBkZSDDgXZpbGEgcXVlIGNvbW8gaGVtb3MgcG9kaWRvIG9ic2VydmFyIGFudGVyaW9ybWVudGUgaGEgZ2FuYWRvIGVuIDkgbXVuaWNpcGlvc+KAlCBwZXJvIHNpIHF1ZSBzZSBvYnNlcnZhIHVuYSBjb3JyZWxhY2nDs24gcG9zaXRpdmEgZW50cmUgZWwgdGFtYcOxbyBwb2JsYWNpb25hbCB5IGxhIHJlcHJlc2VudGFjacOzbi4gDQoNCg0KIyMgU29icmUgZWwgY29zdGUgcG9yIGRpcHV0YWRvIHkgcHJvcG9yY2lvbmFsaWRhZA0KDQpFbiBlc3RlIGFwYXJ0YWRvIHZhbW9zIGEgdmFsb3JhciBlbCBjb3N0ZSBlbiB0w6lybWlub3MgZGUgdm90b3MgcXVlIHRpZW5lIHVuIGRpcHV0YWRvIHBvciBwYXJ0aWRvIHkgcHJvdmluY2lhLiANCg0KYGBge3IsIGNvc3RlX2RpcHVfMX0NCmNvc3RlVm90b3MgPC0gZ2VuZXJhbGVzMjhBICU+JSBmaWx0ZXIoZGlwdXRhZG9zID4gMCkgJT4lICBtdXRhdGUoY29zdGVfZGlwdSA9IHZvdG9zL2RpcHV0YWRvcykgJT4lIG11dGF0ZShwY3QgPSBjb3N0ZV9kaXB1L3BvYmxhY2lvbikNCmNvc3RlVm90b3MkcGFydGlkbyA8LSBhcy5mYWN0b3IoY29zdGVWb3RvcyRwYXJ0aWRvKQ0KDQpkZjMgPC0gY29zdGVWb3RvcyAlPiUgZ3JvdXBfYnkocGFydGlkbykgJT4lIHRvcF9uKDEsIGNvc3RlX2RpcHUpICU+JSB1bmdyb3VwKCkNCmRmMyRwYXJ0aWRvICA8LSBmb3JjYXRzOjpmY3RfcmVvcmRlcihkZjMkcGFydGlkbyAsIGRmMyRjb3N0ZV9kaXB1KQ0KcCA8LSBnZ3Bsb3QoZGYzLCBhZXMocGFydGlkbywgY29zdGVfZGlwdSkpICsgZ2VvbV9jb2woYWVzKGZpbGwgPSBwcm92aW5jaWEpKSArIA0KICAgIHRoZW1lX3Bsb3QoKSArIHRoZW1lKGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9OCksIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKSArDQogICAgc2NhbGVfZmlsbF92aXJpZGlzX2Qob3B0aW9uPSJtYWdtYSIsIGFscGhhID0gMC44LCBiZWdpbiA9IDAsIGVuZCA9IDEsIA0KICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSAiIiwgZ3VpZGUgPSBndWlkZV9sZWdlbmQobnJvdyA9IDMsIG5jb2wgPSA0KSkgKyANCiAgICBsYWJzKHRpdGxlID0gIlByb3ZpbmNpYSBjb24gZWwgY29zdGUgcG9yIGRpcHV0YWRvcyBtYXMgYWx0byBwYXJhIGNhZGEgcGFydGlkbyIpICsgeWxhYigiIikNCg0KcGxvdGx5OjpnZ3Bsb3RseShwKQ0KYGBgDQoNCg0KRWwgZGlwdXRhZG8gbcOhcyBjb3N0b3NvIGVuIHTDqXJtaW5vcyBkZSB2b3RvcyBlcyBlbCBkZWwgUFAgcG9yIGxhIHByb3ZpbmNpYSBkZSBCYXJjZWxvbmEuIA0KDQpMbyByZWxldmFudGUgZGUgZXN0ZSBncsOhZmljbywgcG9kcsOtYSBzZXIgcXVlIGxhcyDDum5pY2FzIHByb3ZpbmNpYXMgZG9uZGUgZXMgbcOhcyBjb3N0b3NvIG9idGVuZXIgdW4gZGlwdXRhZG8gZW4gdMOpcm1pbm9zIGFic29sdXRvcyBzb24gcHJvdmluY2lhcyBncmFuZGVzIHkgZWNvbsOzbWljYW1lbnRlIHBvdGVudGVzLCBsbyBxdWUgbm9zIGRhIHVuYSBwcmltZXJhIHZpc2nDs24gZGVsIHBvcnF1w6kgbG9zIHBhcnRpZG9zIGdyYW5kZXMgZW4gc3VzIGNhbXBhw7FhcyBlbGVjdG9yYWxlcyBjZW50cmFuIHN1IGF0ZW5jacOzbiBlbiBwcm92aW5jaWFzIHBlcXVlw7FhcyBkb25kZSBzZSByZXBhcnRlbiBtYXlvciBuw7ptZXJvIGRlIGRpcHV0YWRvcyBlbiByZWxhY2nDs24gYSBsYSBwb2JsYWNpw7NuLg0KDQpgYGB7ciwgY29zdGVfZGlwdV8yfQ0KICAgICAgICBjb3N0ZVZvdG9zJGNvZGlnby5wcm92IDwtIGFzLm51bWVyaWMoY29zdGVWb3RvcyRjb2RpZ28ucHJvdikNCmRmNCA8LSBjb3N0ZVZvdG9zICU+JSBmaWx0ZXIoY29kaWdvLnByb3YgJWluJSBjKDE3LDI1LDQzLDEsMjAsNDgsIDIsIDEzLCAxNiwgMTksIDQ1LCA4KSkNCg0KZ2dwbG90KGRmNCwgYWVzKGZvcmNhdHM6OmZjdF9yZW9yZGVyKHByb3ZpbmNpYSwgY29zdGVfZGlwdSksIGNvc3RlX2RpcHUvMTAwMCwgZmlsbD1mYWN0b3IocGFydGlkbykpKSArIGdlb21fY29sKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKCkpICsgDQogICAgdGhlbWVfcGxvdF9mYWNldCgpICsgDQogICAgZmFjZXRfZ3JpZCh+Y29tdW5pZGFkLCBzY2FsZXMgPSAiZnJlZSIsIHNwYWNlID0gImZyZWUiKSArIHNjYWxlX2ZpbGxfdmlyaWRpc19kKG9wdGlvbj0ibWFnbWEiLCBhbHBoYSA9IDAuOCwgYmVnaW4gPSAwLjEsIGVuZCA9IDAuOSwgbmFtZSA9ICIiKSArDQogICAgbGFicyh0aXRsZSA9ICJWb3RvcyBuZWNlc2FyaW9zIHBhcmEgb2J0ZW5lciB1biBkaXB1dGFkbyIsDQogICAgICAgICBjYXB0aW9uID0gZGVmYXVsdF9jYXB0aW9uKSsNCiAgICB5bGFiKCJNaWxlcyBkZSBwZXJzb25hcyIpICsgeGxhYigiIikNCmBgYA0KDQoNClBvciBvdHJvIGxhZG8sIGNvbW8gaGVtb3MgY29tZW50YWRvLCBsYXMgcHJvdmluY2lhcyBkZSBsYSBFc3Bhw7FhIGludGVyaW9yIHRpZW5lbiB1biBjb3N0ZSBwb3IgZGlwdXRhZG8gZW4gdMOpcm1pbm9zIGFic29sdXRvcyBtZW5vci4gRW4gY29tdW5pZGFkZXMgYXV0w7Nub21hcyBjb21vIENhdGFsdcOxYSB5IFBhw61zIFZhc2NvLCBkb25kZSBoYXkgcHJvdmluY2lhcyB0YW50byBpbmR1c3RyaWFsaXphZGFzIGNvbW8gcnVyYWxlcywgc2Ugb2JzZXJ2YSB1bmEgbm90YWJsZSBkaWZlcmVuY2lhIGVuIGVsIGNvc3RlIHBvciBkaXB1dGFkby4gDQoNCkNlbnRyw6FuZG9ub3MgZW4gZWwgY2FzbyBkZSBFSC1CaWxkdSwgc2kgbG8gY29tcGFyYW1vcyBjb24gZWwgaW50ZXJpb3IgZGUgbGEgY29tdW5pZGFkLCBzZSBvYnNlcnZhIGxhIGdyYW4gZGlmZXJlbmNpYSBlbnRyZSBsbyBxdWUgbGUgY3Vlc3RhIG9idGVuZXIgdW4gZGlwdXRhZG8gZW4gbGEgcHJvdmluY2lhIGRlIMOBbGF2YSB5IGxvIHF1ZSBsZSBjdWVzdGEgZW4gbGEgcHJvdmluY2lhIGRlIEJpemthaWEgcXVlIGVzIHNpbiBsdWdhciBhIGR1ZGFzIHVuYSByZWdpw7NuIGNvbiBtw6FzIGRlc2Fycm9sbG8gZWNvbsOzbWljby4gDQoNClBhcmEgZWwgY2FzbyBkZSBDYXN0aWxsYS1MYSBNYW5jaGEsIGVzIGRlc3RhY2FibGUgY29tbyBlbCBjb3N0ZSBkZSBkaXB1dGFkb3MgZW4gcHJvbWVkaW8gZXMgcmVhbG1lbnRlIG3DoXMgYmFqbyBlbiBjb21wYXJhY2nDs24gY29uIGxhcyBvdHJhcyBkb3MgQ0NBQS4gDQoNCmBgYHtyLCBjb3N0ZV9kaXB1XzN9DQpnZ3Bsb3QoZGY0LCBhZXMoZm9yY2F0czo6ZmN0X3Jlb3JkZXIocHJvdmluY2lhLCBjb3N0ZV9kaXB1KSwgcGN0LCBmaWxsPWZhY3RvcihwYXJ0aWRvKSkpICsgZ2VvbV9jb2woc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2UoKSkgKyANCiAgICB0aGVtZV9wbG90X2ZhY2V0KCkgKyBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50KSArDQogICAgZmFjZXRfZ3JpZCh+Y29tdW5pZGFkLCBzY2FsZXMgPSAiZnJlZSIsIHNwYWNlID0gImZyZWUiKSArIHNjYWxlX2ZpbGxfdmlyaWRpc19kKG9wdGlvbj0ibWFnbWEiLCBuYW1lID0gIiIsIGFscGhhID0gMC44LCBiZWdpbiA9IDAuMSwgZW5kID0gMC45KSArDQogICAgbGFicyh0aXRsZSA9ICJJbXBvcnRhbmNpYSByZWxhdGl2YSBkZSB1biB2b3RvIHBhcmEgbGEgb2J0ZW5jacOzbiBkZSB1biBkaXB1dGFkbyIsDQogICAgICAgICBzdWJ0aXRsZSA9ICJBIG1heW9yIHBvcmNlbnRhamUsIG3DoXMgJ3ZhbG9yJyB0aWVuZSBlbCB2b3RvIGRlbCBjaXVkYWRhbm8iLCANCiAgICAgICAgIGNhcHRpb24gPSBkZWZhdWx0X2NhcHRpb24pICsNCiAgICB5bGFiKCJDdcOhbnRvIHJlcHJlc2VudGEgZWwgY29zdGUgXG4gcG9yIGRpcHV0YWRvIHNvYnJlIGxhIHBvYmxhY2nDs24iKSArIHhsYWIoIiIpDQpgYGANCg0KDQpFc3RlIGdyYWZpY28gZGVzdGFjYSBsYSBncmFuIGRpZmVyZW5jaWEgcXVlIHN1cG9uZSBlbCB2YWxvciBkZSB1biB2b3RvIGVuIENhc3RpbGxhLUxhIE1hbmNoYSwgZW4gZ2VuZXJhbCwgcmVzcGVjdG8gYSBsYSBwcm92aW5jaWEgZGUgQmFyY2Vsb25hLCBkb25kZSBlbCB2YWxvciBkZWwgdm90byBwb3IgcGVyc29uYSBlcyBtw61uaW1vIGRlYmlkbyBhbCBncmFuIG7Dum1lcm8gZGUgaGFiaXRhbnRlcyBxdWUgcG9zZWUuDQoNCmBgYHtyLCBldmFsPUZBTFNFLCBlY2hvPUZBTFNFfQ0Kdm90b3NSZWxhY2lvbiA8LSBnZW5lcmFsZXMyOEEgJT4lIGdyb3VwX2J5KGNvZGlnby5wcm92KSAlPiUNCiAgICBmaWx0ZXIoZGlwdXRhZG9zID4gMCkgJT4lDQogICAgbXV0YXRlKHRvdGFsLmRpcHV0YWRvcyA9IHN1bShkaXB1dGFkb3MsIG5hLnJtPVRSVUUpKSAlPiUgDQogICAgdG9wX24oMSwgdm90b3MpICU+JSB1bmdyb3VwKCkNCiANCnZvdGFudGVzMjhBIDwtIHJpbzo6aW1wb3J0KCIuL2RhdGEvZ2VuZXJhbGVzMjhBVGlwb1ZvdG8ucmRhdGEiKSAlPiUgZmlsdGVyKHRpcG8udm90byA9PSAidG90YWwuY2Vuc28uZWxlY3RvcmFsIikNCg0Kdm90b3NSZWxhY2lvbiA8LSBsZWZ0X2pvaW4odm90b3NSZWxhY2lvbiwgdm90YW50ZXMyOEEpDQoNCnJtKCJ2b3RhbnRlczI4QSIpDQoNCnZvdG9zUmVsYWNpb24gPC0gdm90b3NSZWxhY2lvbiAlPiUgbXV0YXRlKGRpcHV0YWRvc19xdWFudGlsZSA9IGN1dCh0b3RhbC5kaXB1dGFkb3MsIGJyZWFrcyA9IGMoMSwzLDgsNDApLCBpbmNsdWRlLmxvd2VzdCA9IFRSVUUsIGxhYmVscyA9IGMoMSwyLDMpKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b3RhbC52b3RhbnRlc19xdWFudGlsZSA9IG50aWxlKHRpcG8udm90by5udW0sIDMpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0gcGFzdGUoZGlwdXRhZG9zX3F1YW50aWxlLCB0b3RhbC52b3RhbnRlc19xdWFudGlsZSwgc2VwID0gIiAtICIpKQ0KdW5pcXVlKHZvdG9zUmVsYWNpb24kZ3JvdXApDQoNCmJpdmFyaWF0ZV9jb2xvcl9zY2FsZSA8LSB0aWJibGUoDQogICAgIjMgLSAzIiA9ICIjM0YyOTQ5IiwgIyBoaWdoLCBoaWdoICMzRjI5NDkNCiAgICAiMiAtIDMiID0gIiM0MzU3ODYiLCAjIG1lZGl1bSwgaGlnaA0KICAgICIxIC0gMyIgPSAiIzQ4ODVDMSIsICMgbG93LCBoaWdoDQogICAgIjMgLSAyIiA9ICIjNzczMjRDIiwgIyBoaWdoLCBtZWRpdW0NCiAgICAiMiAtIDIiID0gIiM4MDZBOEEiLCAjIG1lZGl1bSwgbWVkaXVtICM4MDZBOEENCiAgICAiMSAtIDIiID0gIiM4OUExQzgiLCAjIGxvdywgbWVkaXVtDQogICAgIjMgLSAxIiA9ICIjQUUzQTRFIiwgIyBoaWdoLCBsb3cNCiAgICAiMiAtIDEiID0gIiNCQzdDOEYiLCAjIG1lZGl1bSwgbG93DQogICAgIjEgLSAxIiA9ICIjQ0FCRUQwIiAjIGxvdyAsIGxvdyAjQ0FCRUQwDQopICU+JQ0KICAgIGdhdGhlcigiZ3JvdXAiLCAiZmlsbCIpDQoNCnZvdG9zUmVsYWNpb24gPC0gbGVmdF9qb2luKHZvdG9zUmVsYWNpb24sIGJpdmFyaWF0ZV9jb2xvcl9zY2FsZSkNCg0Kdm90b3NSZWxhY2lvbl9tYXAgPC0gbGVmdF9qb2luKHZvdG9zUmVsYWNpb24sIGxvYWRHZW9tZXRyeSgyKSkNCg0KYm91bmRhcmllc1NoYXBlIDwtIHJuYXR1cmFsZWFydGg6Om5lX2NvdW50cmllcyhzY2FsZSA9ICJtZWRpdW0iLCByZXR1cm5jbGFzcyA9ICJzZiIpICU+JSANCiAgICBmaWx0ZXIoYWRtMF9hMyAlaW4lIGMoIkZSQSIsICJQUlQiLCAiTUFSIiwgIklUQSIsICJEWkEiKSkNCg0KcGxvdCA8LSBnZ3Bsb3Qodm90b3NSZWxhY2lvbl9tYXApICsgZ2VvbV9zZihkYXRhPWJvdW5kYXJpZXNTaGFwZSwgY29sb3IgPSAiZ3JheTg1IikgKyANCiAgICBnZW9tX3NmKGFlcyhnZW9tZXRyeSA9IGdlb21ldHJ5LCBmaWxsPWZpbGwpLCBzaG93LmxlZ2VuZCA9IEZBTFNFLCBjb2xvciA9ICJncmF5ODUiKSArIA0KICAgIGFubm90YXRlKCJ0ZXh0IiwgbGFiZWw9Ik1lZGlhIHJlcHJlc2VudGF0aXZpZGFkIFxuIENlbnNvIGVsZWN0b3JhbCBiYWpvIiwgeD01LCB5PTQyLjUpICsNCiAgICBhbm5vdGF0ZSgidGV4dCIsIGxhYmVsPSJNZWRpYSByZXByZXNlbnRhdGl2aWRhZCBcbiBDZW5zbyBlbGVjdG9yYWwgYWx0byIsIHg9Mi41LCB5PTM4KSArDQogICAgZ2VvbV9jdXJ2ZShhZXMoeCA9IDEsIHkgPSA0MiwgeGVuZCA9IDUsIHllbmQgPSA0MiksIGN1cnZhdHVyZSA9IDAuMikgKw0KICAgIGdlb21fY3VydmUoYWVzKHggPSAtMy41LCB5ID0gMzcsIHhlbmQgPSAyLjUsIHllbmQgPSAzNy41KSwgY3VydmF0dXJlID0gMC4yKSArDQogICAgc2NhbGVfZmlsbF9pZGVudGl0eSgpICsgY29vcmRfc2YoeGxpbSA9IGMoLTEyLDcpLCB5bGltID0gYygzNCw0NCkpICsNCiAgICBsYWJzKHRpdGxlID0gIsK/U29uIHRvZGFzIGxhcyBwcm92aW5jaWFzIGRlIEVzcGHDsWEgaWd1YWwgZGUgcmVwcmVzZW50YXRpdmFzPyIsDQogICAgICAgICBjYXB0aW9uID0gZGVmYXVsdF9jYXB0aW9uKSArIHRoZW1lX21hcCgpDQoNCiMgRHJhdyB0aGUgbGVnZW5kDQpiaXZhcmlhdGVfY29sb3Jfc2NhbGUgPC0gYml2YXJpYXRlX2NvbG9yX3NjYWxlICU+JQ0KICAgIHNlcGFyYXRlKGdyb3VwLCBpbnRvID0gYygiZGlwdXRhZG9zIiwgInZvdGFudGVzIiksIHNlcCA9ICIgLSAiKSAlPiUNCiAgICBtdXRhdGUodm90YW50ZXMgPSBhcy5mYWN0b3Iodm90YW50ZXMpLA0KICAgICAgICAgICBkaXB1dGFkb3MgPSBhcy5mYWN0b3IoZGlwdXRhZG9zKSkNCg0KbGVnZW5kIDwtIGdncGxvdCgpICsNCiAgICBnZW9tX3RpbGUoDQogICAgICAgIGRhdGEgPSBiaXZhcmlhdGVfY29sb3Jfc2NhbGUsDQogICAgICAgIG1hcHBpbmcgPSBhZXMoDQogICAgICAgICAgICB4ID0gZGlwdXRhZG9zLA0KICAgICAgICAgICAgeSA9IHZvdGFudGVzLA0KICAgICAgICAgICAgZmlsbCA9IGZpbGwpDQogICAgKSArDQogICAgc2NhbGVfZmlsbF9pZGVudGl0eSgpICsNCiAgICBsYWJzKHggPSAiTWF5b3IgcmVwcmVzZW50YWNpw7NuIC0+77iPIiwNCiAgICAgICAgIHkgPSAiTWF5b3IgY2Vuc28gZWxlY3RvcmFsIC0+77iPIikgKw0KICAgICMgbWFrZSBmb250IHNtYWxsIGVub3VnaA0KICAgIHRoZW1lKA0KICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA3KQ0KICAgICkgKw0KICAgICMgcXVhZHJhdGljIHRpbGVzDQogICAgY29vcmRfZml4ZWQoKSArDQogICAgdGhlbWUoYXhpcy50ZXh0ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gImdyYXk5NSIpLA0KICAgICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJncmF5OTUiKSwNCiAgICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9saW5lKGNvbG9yID0gImdyYXk5NSIpLA0KICAgICAgICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCkpDQoNCg0KbGlicmFyeShjb3dwbG90KQ0KZ2dkcmF3KCkgKw0KICAgIGRyYXdfcGxvdChwbG90LCAwLCAwLCAxLCAxKSArDQogICAgZHJhd19wbG90KGxlZ2VuZCwgMC42NSwgMC4xNSwgMC4yNSwgMC4yNSkNCg0KIyBubyB2YW1vcyBhIGluY2x1aXIgZWwgZ3JhZmljbyBxdWUgc2FsZSBkZSBlc3RlIGPDs2RpZ28gcG9ycXVlIG5vIHRlcm1pbmEgZGUgcXVlZGFyIGJpZW4sIGxvIGhlbW9zIGdlbmVyYWRvIGVuIGRhdG9zLlIgeSBndWFyZGFkbyBsYSBpbWFnZW4NCmBgYA0KDQoNCg0KIVtdKC4vaW1hZ2VzL21hcF9wbG90XzEucG5nKQ0KDQpGaW5hbG1lbnRlLCBlbCBtYXBhIGFudGVyaW9yIGVzIHVuIG1hcGEgYml2YXJpYW50ZSBxdWUgbXVlc3RyYSBsYSByZWxhY2nDs24gZW50cmUgbGEgcmVwcmVzZW50YXRpdmlkYWQgKGRpcHV0YWRvcykgeSBlbCB0b3RhbCBkZWwgY2Vuc28gZWxlY3RvcmFsLiBMb3MgY29sb3JlcyBxdWUgZXN0w6FuIGVuIGxhIGxpbmVhIGRpYWdvbmFsIHNlcmlhbiBhcXVlbGxhcyBwcm92aW5jaWFzIHF1ZSBlc3TDoW4gY29ycmVjdGFtZW50ZSByZXByZXNlbnRhZGFzLiBBcXVlbGxhcyBwcm92aW5jaWFzIGNvbW8gTGxlaWRhIG8gTHVnbyBlc3RhcsOtYW4gc29icmVycmVwcmVzZW50YWRhcywgZWwgbsO6bWVybyBkZSBkaXB1dGFkb3MgcXVlIHJlcGFydGVuIGVzIHByb3BvcmNpb25hbG1lbnRlIG1heW9yIGFsIGNlbnNvIGVsZWN0b3JhbC4gUG9yIG90cm8gbGFkbywgT3VyZW5zZSBvIFphcmFnb3phIGVzdGFyw61hbiBpbmZyYXJyZXByZXNlbnRhZGFzLCBlbiBwcm9tZWRpbyBsb3MgZGlwdXRhZG9zIHF1ZSByZXBhcnRlbiBzb24gbWVub3JlcyBkYWRvIGVsIGNlbnNvIGVsZWN0b3JhbC4NCg0KDQojIyBTb2JyZSBDb21wcm9tw61zIHZzLiBFUkMgICANCg0KYGBge3J9DQpjb21wcm9taXNFUkMgPC0gbXVuaWNpcGlvczI4QSAlPiUgZmlsdGVyKGNvZGlnby5wcm92ICVpbiUgYygiMDMiLCIxMiIsIjQ2IiwgIjA4IiwiMTciLCAiNDMiLCAiMjUiKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcnRpZG8gJWluJSBjKCJDT01QUk9NSVMtRVVQViIsICJFUkMiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdm90b3MgPiAwKSAlPiUgDQogICAgICAgICAgICAgICAgbXV0YXRlKElORUNvZE11bmkgPSBwYXN0ZShjb2RpZ28ucHJvdiwgY29kaWdvLm11bmksIHNlcCA9ICIiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgdm90b3NfcXVhbnRpbGUgPSBudGlsZSh2b3RvcywgNSkpIA0KDQpjb21wcm9taXNFUkNfbWFwYSA8LSBsZWZ0X2pvaW4oY29tcHJvbWlzRVJDLCBsb2FkR2VvbWV0cnkoNiwgcHJvdmluY2lhcyA9IGMoIjAzIiwiMTIiLCI0NiIsICIwOCIsIjE3IiwgIjQzIiwgIjI1IikpKQ0KDQpwcm92aW5jaWFzTGluZGVzIDwtIGMoIjIyIiwgIjQ0IiwgIjUwIiwgIjE2IiwgIjQ0IiwgIjMwIiwgIjAyIiwgIjA3IiwgIjMxIiwgIjE5IikNCg0KZnJhU0YgPC0gcm5hdHVyYWxlYXJ0aDo6bmVfY291bnRyaWVzKHNjYWxlID0gIm1lZGl1bSIsIHJldHVybmNsYXNzID0gInNmIikgJT4lIGZpbHRlcihhZG0wX2EzID09ICJGUkEiKQ0KDQpwbG90MSA8LSBnZ3Bsb3QoKSArIGdlb21fc2YoZGF0YSA9IGZyYVNGLCBhZXMoZ2VvbWV0cnkgPSBnZW9tZXRyeSkpICsNCiAgICBnZW9tX3NmKGFlcyhnZW9tZXRyeSA9IGdlb21ldHJ5KSwgZGF0YT1maWx0ZXIobG9hZEdlb21ldHJ5KDEsIHByb3ZpbmNpYXMgPSBwcm92aW5jaWFzTGluZGVzKSkpICsNCiAgICBnZW9tX3NmKGFlcyhnZW9tZXRyeSA9IGdlb21ldHJ5LCBmaWxsPXZvdG9zX3F1YW50aWxlKSwgZGF0YT1jb21wcm9taXNFUkNfbWFwYSkgKw0KICAgIHNjYWxlX2ZpbGxfdmlyaWRpcygNCiAgICAgICAgb3B0aW9uID0gIm1hZ21hIiwgDQogICAgICAgIGRpcmVjdGlvbiA9IC0xLA0KICAgICAgICBiZWdpbiA9IDAuMywgZW5kID0gMC44LA0KICAgICAgICBuYW1lID0gIlZvdG9zIChRdWFudGlsZXMpIiwNCiAgICAgICAgIyBoZXJlIHdlIHVzZSBndWlkZV9jb2xvdXJiYXIgYmVjYXVzZSBpdCBpcyBzdGlsbCBhIGNvbnRpbnVvdXMgc2NhbGUgLS0+IGh0dHBzOi8vdGltb2dyb3NzZW5iYWNoZXIuY2gvMjAxNi8xMi9iZWF1dGlmdWwtdGhlbWF0aWMtbWFwcy13aXRoLWdncGxvdDItb25seS8NCiAgICAgICAgZ3VpZGUgPSBndWlkZV9jb2xvcmJhcigNCiAgICAgICAgICAgIGRpcmVjdGlvbiA9ICJob3Jpem9udGFsIiwNCiAgICAgICAgICAgIGJhcmhlaWdodCA9IHVuaXQoMiwgdW5pdHMgPSAibW0iKSwNCiAgICAgICAgICAgIGJhcndpZHRoID0gdW5pdCg1MCwgdW5pdHMgPSAibW0iKSwNCiAgICAgICAgICAgIGRyYXcudWxpbSA9IEYsDQogICAgICAgICAgICB0aXRsZS5wb3NpdGlvbiA9ICd0b3AnLA0KICAgICAgICAgICAgIyBzb21lIHNoaWZ0aW5nIGFyb3VuZA0KICAgICAgICAgICAgdGl0bGUuaGp1c3QgPSAwLjUsDQogICAgICAgICAgICBsYWJlbC5oanVzdCA9IDAuNQ0KICAgICAgICApKSArDQogICAgY29vcmRfc2YoeGxpbSA9IGMoLTEuNSwgNCksIHlsaW0gPSBjKDM4LDQyLjcpKSArIHRoZW1lX21hcCgpICsgDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLCBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMikgKSArIA0KICBsYWJzKHRpdGxlPSJEZW5zaWRhZCBkZSB2b3RvcyBhIENvbXByb23DrXMgeSBFUkMiLCBjYXB0aW9uID0gZGVmYXVsdF9jYXB0aW9uKQ0KDQpwbG90MQ0KYGBgDQoNCg0KRW4gZXN0YSBzZWNjacOzbiBxdWVyZW1vcyBjb21wYXJhciBlbCBvcmlnZW4gZGVsIHZvdG8gZGUgbG9zIHBhcnRpZG9zIG5hY2lvbmFsaXN0YXMgQ29tcHJvbcOtcyB5IEVzcXVlcnJhIFJlcHVibGljYW5hIGRlIENhdGFsdcOxYSAoRVJDKS4gRW4gcHJpbWVyIGx1Z2FyLCBsbyBxdWUgcGVyY2liaW1vcyBlcyBxdWUgZWwgdm90byBkZSBDb21wcm9tw61zLCBzZSB1YmljYSBlbiBlbCB0ZXJyaXRvcmlvIHF1ZSBvY3VwYSBsYXMgZ3JhbmRlcyBjaXVkYWRlcyBkZSBsYSBDb211bmlkYWQgVmFsZW5jaWFuYSBtaWVudHJhcyBxdWUgZWwgdm90byBkZSBFUkMgbm8gc2lndWUgZWwgbWlzbW8gcGF0csOzbiB5IG9idGllbmUgZ3JhbiByZXByZXNlbnRhY2nDs24gdW5pZm9ybWVtZW50ZSBwb3IgdG9kbyBlbCB0ZXJyaXRvcmlvIGNhdGFsw6FuLiANCkVzIHJlbGV2YW50ZSBlbCBjYXNvIGRlIExsZWlkYSBwb3JxdWUgY29tbyBhbnRlcmlvcm1lbnRlIGhlbW9zIHJlc2FsdGFkbywgbGEgcHJvdmluY2lhIGVzdMOhIHNvYnJlcnJlcHJlc2VudGFkYSBlbiBlbCBuw7ptZXJvIGRlIGRpcHV0YWRvcyBwb3IgbG8gcXVlIGNhZGEgdm90byBhIEVSQyB0aWVuZSBtw6FzIHZhbG9yLiAgIA0KDQoNCmBgYHtyfQ0Kdm90YW50ZXMyOEEgPC0gcmlvOjppbXBvcnQoIi4vZGF0YS9nZW5lcmFsZXMyOEFUaXBvVm90by5yZGF0YSIpICU+JSBmaWx0ZXIodGlwby52b3RvID09ICJ0b3RhbC5jZW5zby5lbGVjdG9yYWwiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29kaWdvLnByb3YgJWluJSBjKCIwMyIsIjEyIiwiNDYiLCAiMDgiLCIxNyIsICI0MyIsICIyNSIpKQ0KDQp0YWJsZUNvbXByb21pcyA8LSBnZW5lcmFsZXMyOEEgJT4lIGZpbHRlcihwYXJ0aWRvICVpbiUgYygiQ09NUFJPTUlTLUVVUFYiLCAiRVJDIiksIHZvdG9zID4gMCkgJT4lIGxlZnRfam9pbih2b3RhbnRlczI4QSkgJT4lIA0KICAgIHNlbGVjdChjKDMsNSw2LDcsMTApKQ0KY29sbmFtZXModGFibGVDb21wcm9taXMpIDwtIGMoIlByb3ZpbmNpYSIsICJQYXJ0aWRvIiwgIk7CuiB2b3RvcyIsICJEaXB1dGFkb3MiLCAiVG90YWwgY2Vuc28gZWxlY3RvcmFsIikNCmtuaXRyOjprYWJsZSh0YWJsZUNvbXByb21pcykgICAgDQpgYGANCg0KDQpMYSBwb2NhIHByb2dyZXNpdmlkYWQgZW4gbGEgcmVwcmVzZW50YXRpdmlkYWQgc2UgcHVlZGUgb2JzZXJ2YXIgY29uIGxvcyByZXN1bHRhZG9zIGRlIENvbXByb23DrXMgZW4gVmFsZW5jaWEuIENvbiAxMjYuMDc4IHZvdG9zIGhhIG9idGVuaWRvIHVuIHNvbG8gZGlwdXRhZG8gZnJlbnRlIGEgRVJDIHF1ZSBlbiBMbGVpZGEgY29uIG1lbm9yIG7Dum1lcm8gZGUgdm90YW50ZXMgeSBjZW5zbyBlbGVjdG9yYWwgaGEgb2J0ZW5pZG8gZG9zIGRpcHV0YWRvcy4gUmVjb3JkYW1vcyBxdWUgQ29tcHJvbcOtcyBlcyBlbCBzZWd1bmRvIHBhcnRpZG8gY29uIG1heW9yIGNvc3RlIGVuIHTDqXJtaW5vcyBkZSB2b3RvcyBwb3IgZGlwdXRhZG8gc29sbyBwb3IgZGV0csOhcyBkZWwgUFAgZW4gQmFyY2Vsb25hLg0KDQpgYGB7cn0NCmVkYWRtZWRpYSA8LSByaW86OmltcG9ydChoZXJlOjpoZXJlKCJkYXRhIiwgImVkYWRNZWRpYVBvYjIwMTkucmRhdGEiKSkgJT4lIGZpbHRlcihjb2RpZ28ucHJvdiAlaW4lIGMoIjAzIiwiMTIiLCI0NiIsICIwOCIsIjE3IiwgIjQzIiwgIjI1IikpDQoNCmVkYWRtZWRpYV9tYXAgPC0gbGVmdF9qb2luKGVkYWRtZWRpYSwgbG9hZEdlb21ldHJ5KDYsIHByb3ZpbmNpYXMgPSBjKCIwMyIsIjEyIiwiNDYiLCAiMDgiLCIxNyIsICI0MyIsICIyNSIpKSkNCg0KcGxvdDIgPC0gZ2dwbG90KCkgKyBnZW9tX3NmKGRhdGEgPSBmcmFTRiwgYWVzKGdlb21ldHJ5ID0gZ2VvbWV0cnkpKSArDQogICAgZ2VvbV9zZihkYXRhPWxvYWRHZW9tZXRyeSgzLCBwcm92aW5jaWFzTGluZGVzKSwgYWVzKGdlb21ldHJ5ID0gZ2VvbWV0cnkpLCBhbHBoYSA9IDAuNSkgKw0KICAgIGdlb21fc2YoZGF0YT1lZGFkbWVkaWFfbWFwLCBhZXMoZ2VvbWV0cnkgPSBnZW9tZXRyeSwgZmlsbCA9IHF1YW50aWxlKSkgKyANCiAgICBzY2FsZV9maWxsX3ZpcmlkaXMoDQogICAgICAgIG9wdGlvbiA9ICJtYWdtYSIsIA0KICAgICAgICBkaXJlY3Rpb24gPSAtMSwNCiAgICAgICAgYmVnaW4gPSAwLjMsIGVuZCA9IDAuOCwNCiAgICAgICAgbmFtZSA9ICJFZGFkIE1lZGlhIiwNCiAgICAgICAgIyBoZXJlIHdlIHVzZSBndWlkZV9jb2xvdXJiYXIgYmVjYXVzZSBpdCBpcyBzdGlsbCBhIGNvbnRpbnVvdXMgc2NhbGUgLS0+IGh0dHBzOi8vdGltb2dyb3NzZW5iYWNoZXIuY2gvMjAxNi8xMi9iZWF1dGlmdWwtdGhlbWF0aWMtbWFwcy13aXRoLWdncGxvdDItb25seS8NCiAgICAgICAgZ3VpZGUgPSBndWlkZV9jb2xvcmJhcigNCiAgICAgICAgICAgIGRpcmVjdGlvbiA9ICJob3Jpem9udGFsIiwNCiAgICAgICAgICAgIGJhcmhlaWdodCA9IHVuaXQoMiwgdW5pdHMgPSAibW0iKSwNCiAgICAgICAgICAgIGJhcndpZHRoID0gdW5pdCg1MCwgdW5pdHMgPSAibW0iKSwNCiAgICAgICAgICAgIGRyYXcudWxpbSA9IEYsDQogICAgICAgICAgICB0aXRsZS5wb3NpdGlvbiA9ICd0b3AnLA0KICAgICAgICAgICAgIyBzb21lIHNoaWZ0aW5nIGFyb3VuZA0KICAgICAgICAgICAgdGl0bGUuaGp1c3QgPSAwLjUsDQogICAgICAgICAgICBsYWJlbC5oanVzdCA9IDAuNQ0KICAgICAgICApKSArDQogICAgY29vcmRfc2YoeGxpbSA9IGMoLTEuNSwgNCksIHlsaW0gPSBjKDM4LDQyLjcpKSArIHRoZW1lX21hcCgpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICsgDQogIGxhYnModGl0bGUgPSAiRWRhZCBtZWRpYSBwb3IgbXVuaWNpcGlvcyIsDQogICAgICAgc3VidGl0bGUgPSAiTm90YTogZGF0b3MgZGUgSU5FIHRyYW1lYWRvcyBjcnV6YWRvcyBjb24gbGEgcG9ibGFjacOzbiIsDQogICAgICAgY2FwdGlvbiA9IGRlZmF1bHRfY2FwdGlvbikNCg0KZ3JpZEV4dHJhOjpncmlkLmFycmFuZ2UocGxvdDEsIHBsb3QyLCBuY29sPTIpDQpgYGANCg0KDQpGaW5hbG1lbnRlLCByZXN1bHRhIHJlbGV2YW50ZSBsYSByZWxhY2Npw7NuIGludmVyc2EgZW50cmUgbGEgcHJvcGVuc2nDs24gYWwgdm90byBkZSBlc3RhcyBkb3MgZm9ybWFjaW9uZXMgeSBsYSBlZGFkIG1lZGlhIGRlIGxvcyBtdW5pY2lwaW9zLiBBIGZhbHRhIGRlIHVuIGFuw6FsaXNpcyBtw6FzIGV4aGF1c3Rpdm8gcG9kcsOtYW1vcyBkZWNpciBxdWUgZWwgcGVyZmlsIGRlbCB2b3RhbnRlIGRlIGxhcyBmb3JtYWNpb25lcyBlcyByZWxhdGl2YW1lbnRlIGrDs3Zlbi4NCg0KIyMgRW5jdcOpbnRyYXRlDQoNCmBgYHtyfQ0KbGlicmFyeShEVCkNCg0KaW5mb3ZvdG9zIDwtIHJpbzo6aW1wb3J0KCIuL2RhdGEvbXVuaWNpcGlvczI4QVRpcG9Wb3RvLnJkYXRhIikgJT4lICBzZWxlY3QoYygyLDQsNykpICU+JSB1bmlxdWUoKQ0KZHRhYmxlIDwtIG11bmljaXBpb3MyOEEgJT4lIGZpbHRlcih2b3RvcyA+IDApICU+JSBsZWZ0X2pvaW4oLiwgaW5mb3ZvdG9zKSAlPiUgc2VsZWN0KC1jKDIsNCkpDQpkdGFibGUkcHJvdmluY2lhIDwtIGNoYXJ0cignw6HDqcOtw7PDusOxJywnYWVpb3VuJywgZHRhYmxlJHByb3ZpbmNpYSkNCmR0YWJsZSRtdW5pY2lwaW8gPC0gY2hhcnRyKCfDocOpw63Ds8O6w7EnLCdhZWlvdW4nLCBkdGFibGUkbXVuaWNpcGlvKQ0KZHRhYmxlJGNvbXVuaWRhZCA8LSBjaGFydHIoJ8Ohw6nDrcOzw7rDsScsJ2FlaW91bicsIGR0YWJsZSRjb211bmlkYWQpDQoNCg0KDQpkYXRhdGFibGUoZHRhYmxlKQ0KDQpgYGANCg0KIyMgQ29uY2x1c2nDs24NCg0KRGVsIHByaW1lciBzdXB1ZXN0byBjb25jbHVpbW9zIHF1ZSBkZXNwdcOpcyBkZSBsYXMgZWxlY2Npb25lcyBkZWwgMjkgZGUgQWJyaWwsIGxvcyBtZWRpb3MgaGFuIGV4YWdlcmFkbyBlbCByZXN1bHRhZG8gb2J0ZW5pZG8gcG9yIFZPWCwgY29naWVuZG8gZGF0b3MgYWlzbGFkb3MgYnVzY2FuZG8ganVzdGlmaWNhY2nDs24gYSBzdSB0aXR1bGFyLiANCg0KRGVsIHNlZ3VuZG8gc3VwdWVzdG8sIGNvbmNsdWltb3MgcXVlIGVsIHNpc3RlbWEgZGUgcmVwcmVzZW50YWNpw7NuIHF1ZSBleGlzdGUgZW4gRXNwYcOxYSBlcyBjbGFyYW1lbnRlIHBvY28gcHJvcG9yY2lvbmFsLiBBbGd1bmFzIHByb3ZpbmNpYXMgdGllbmVuIGFzaWduYWRvcyBtYXlvciBuw7ptZXJvIGRlIGRpcHV0YWRvIHJlc3BlY3RvIGEgc3UgY2Vuc28gZWxlY3RvcmEsIGxvIHF1ZSBwZXJqdWRpY2EgYSBwYXJ0aWRvcyBkZSDDoW1iaXRvIG5hY2lvbmFsIGVuIGJlbmVmaWNpbyBkZSBwYXJ0aWRvcyByZWdpb25hbGlzdGFzIGNvbW8gRXNxdWVycmEgUmVwdWJsaWNhbmEgZGUgQ2F0YWx1w7FhIHkgRUgtQmlsZHUuIA0KDQpEZWwgdGVyY2VyIHN1cHVlc3RvIHkgZW4gYmFzZSBhIGxhcyBpbnZlc3RpZ2FjaW9uZXMgZGUgbG9zIHN1cHVlc3RvcyBhbnRlcmlvcmVzIHBvZGVtb3MgY29uY2x1aXIgcXVlIEVSQyBvYnRpZW5lIG1heW9yIHJlcHJlc2VudGFjacOzbiBkZSBsYXMgcHJvdmluY2lhcyBkZWwgaW50ZXJpb3IgZGUgQ2F0YWx1w7FhIGRlYmlkbyBhIHF1ZSBhbGd1bmFzIGNvbW8gTGxlaWRhIGVzdGFuIHNvYnJlcmVwcmVzZW50YWRhcy4gRUwgdm90YW50ZSBkZSBhbWJhcyBmb3JtYWNpb25lcyBzZXLDrWFzIG3DoXMgasOzdmVuZW4uIENvbXByb21pcyBvYnRpZW5lIG1heW9yIHJlcHJlbnRhY2nDs24gZGUgbG9zIG11bmljaXBpb3MgcHLDs3hpbW9zIGEgbGEgY29zdGEgeSBkZSB0cmFkaWNpw7NuIHZhbGVuY2lhbm8tcGFybGFudGUgKGVuIGdlbmVyYWwpIHkgRVJDIHNlIGNlbnRyYSB0YW1iacOpbiBlbiBsYSBDYXRhbHXDsWEgbcOhcyBpbmR1c3RyaWFsaXphZGEgcXVlIGVzIEJhcmNlbG9uYSB5IGxhcyBwb2JsYWNpb25lcyBxdWUgbGluZGFuIGEgbGEgY2l1ZGFkLg0KDQojIyBTZXNzacOzbg0KDQpgYGB7cn0NCnNlc3Npb25JbmZvKCkNCmBgYA0KIA0KDQojIyBBcMOpbmRpY2UgVMOpY25pY28NCg0KIyMjIEFyY2hpdm86IGBwcmVwYXJhY2lvbl9kYXRvcy5SYCANCg0KTG9zIGRhdG9zIGVzdMOhbiBvYnRlbmlkb3MgZGVsIE1JUiB5IHV0aWxpemFuZG8gZXN0YXMgZnVuY2lvbmVzIGxvcyBoZW1vcyBwcmVwYXJhZG8gcGFyYSBzdSB1c28uDQpgYGB7ciB9DQpyZXN1bHRhZG9EaXB1dGFkb3MgPC0gZnVuY3Rpb24oZGYsIHJvd3Mpew0KICAgIGcgPC0gZGYNCiAgICByb3dzIDwtIHJvd3MNCiAgICANCiAgICAjIyBHZW5lcmFtb3MgdW4gZGYgc29sbyBjb24gbG9zIGRhdG9zIGRlIGxhcyBwcm92aW5jaWFzIHkgc3UgcG9ibGFjaW9uDQogICAgcG9iQ29tIDwtIGdbNTpyb3dzLCAxOjRdDQogICAgY29sbmFtZXMocG9iQ29tKVsxOjRdIDwtIGMoImNvbXVuaWRhZCIsICJjb2RpZ28ucHJvdiIsICJwcm92aW5jaWEiLCAicG9ibGFjaW9uIikNCg0KICAgIA0KICAgICMjIEdlbmVyYW1vcyB1biBkZiBwYXJhIGxvcyB2b3RvcyB5IGRpcHV0YWRvcyBkZWwgDQogICAgZ2VuIDwtIGcgJT4lIG11dGF0ZSgiY29kaWdvLnByb3YiID0gWDIgKSAlPiUgc2VsZWN0KC1jKDEsIDM6MTYpKSAlPiUgc2VsZWN0KGMoMSwgbGVuZ3RoKC4pLCAyOihsZW5ndGgoLiktMSkpKQ0KICAgIG5hbWVzKGdlbikgPC0gYXMuY2hhcmFjdGVyKGdlblszLF0pDQogICAgDQogICAgZXZlbl9pbmRleGVzPC1zZXEoMixsZW5ndGgoZ2VuKSwyKQ0KICAgIG9kZF9pbmRleGVzPC1zZXEoMSxsZW5ndGgoZ2VuKSwyKQ0KICAgIA0KICAgIGRpcHV0YWRvcyA8LSBnZW5bLGV2ZW5faW5kZXhlc10NCiAgICB2b3RvcyA8LSBnZW5bLG9kZF9pbmRleGVzXQ0KICAgIA0KICAgIGRpcHV0YWRvcyA8LSBkaXB1dGFkb3NbNTpyb3dzLF0NCiAgICBjb2xuYW1lcyhkaXB1dGFkb3MpIDwtIGNvbG5hbWVzKHZvdG9zKQ0KICAgIGRpcHV0YWRvcyA8LSBnYXRoZXIoZGlwdXRhZG9zLCBwYXJ0aWRvLCBkaXB1dGFkb3MsIDI6bGVuZ3RoKGRpcHV0YWRvcykpDQogICAgY29sbmFtZXMoZGlwdXRhZG9zKVsxXSA8LSAiY29kaWdvLnByb3YiDQogICAgDQogICAgdm90b3MgPC0gdm90b3NbNTpyb3dzLF0NCiAgICB2b3RvcyA8LSBnYXRoZXIodm90b3MsIHBhcnRpZG8sIHZvdG9zLCAyOmxlbmd0aCh2b3RvcykpDQogICAgY29sbmFtZXModm90b3MpWzFdIDwtICJjb2RpZ28ucHJvdiINCiAgICANCiAgICBkaXB1dGFkb3MgPC0gbGVmdF9qb2luKHBvYkNvbSwgZGlwdXRhZG9zLCBieT0iY29kaWdvLnByb3YiKQ0KICAgIA0KICAgIA0KICAgIHZvdG9zIDwtIGxlZnRfam9pbihwb2JDb20sIHZvdG9zLCBieT0iY29kaWdvLnByb3YiKQ0KICAgIHZvdG9zIDwtIGZpbHRlcih2b3Rvcywgdm90b3MgPiAwKQ0KICAgIA0KICAgICMgVW5pbW9zIGxvcyBkZiBwYXJhIGNyZWFyIGVsIGRlZmluaXRpdm8NCiAgICBnZW4gPC0gZnVsbF9qb2luKHZvdG9zLCBkaXB1dGFkb3MpDQogICAgDQogICAgZ2VuJGNvZGlnby5wcm92IDwtIGFzLm51bWVyaWMoZ2VuJGNvZGlnby5wcm92KQ0KICAgIGdlbiRjb2RpZ28ucHJvdiA8LSBzcHJpbnRmKCIlMDJkIiwgZ2VuJGNvZGlnby5wcm92KQ0KICAgIGdlbiRwcm92aW5jaWEgPC0gdHJpbXdzKGdlbiRwcm92aW5jaWEsICJyIikNCiAgICANCiAgICBnZW5bLGMoNCw2LDcpXSA8LSBzYXBwbHkoZ2VuWyxjKDQsNiw3KV0sIGFzLm51bWVyaWMpDQoNCiAgICBybShsaXN0ID0gYygiZyIsICJwb2JDb20iLCAidm90b3MiLCAiZGlwdXRhZG9zIikpDQogICAgDQogICAgcmV0dXJuKGdlbikNCiAgICANCn0NCg0KcmVzdWx0YWRvRGlwdXRhZG9zVGlwb1ZvdG9zIDwtIGZ1bmN0aW9uKGRmLCByb3dzKXsNCiAgICBnIDwtIGRmDQogICAgcm93cyA8LSByb3dzDQogICAgDQogICAgIyMgR2VuZXJhbW9zIHVuIGRmIHNvbG8gY29uIGxvcyBkYXRvcyBkZSBsYXMgcHJvdmluY2lhcyB5IHN1IHBvYmxhY2lvbg0KICAgIHBvYkNvbSA8LSBnWzQ6cm93cywgMToxNl0NCiAgICBjb2xuYW1lcyhwb2JDb20pIDwtIHBvYkNvbVsxLF0gJT4lIHRvbG93ZXIoLikgJT4lIGdzdWIoIiBkZSAiLCAiICIsIC4pICU+JSANCiAgICAgICAgZ3N1YigiICIsICIuIiwgLikgJT4lIGNoYXJ0cignw6HDqcOtw7PDusOxJywnYWVpb3VuJywgLikNCiAgICBjb2xuYW1lcyhwb2JDb20pWzE6M10gPC0gYygiY29tdW5pZGFkIiwgImNvZGlnby5wcm92IiwgInByb3ZpbmNpYSIpDQogICAgcG9iQ29tIDwtIHBvYkNvbVstYygxKSxdICU+JSBnYXRoZXIodGlwby52b3RvLCB0aXBvLnZvdG8ubnVtLCA2OjE2ICkNCiAgICANCiAgICBwb2JDb20kY29kaWdvLnByb3YgPC0gYXMubnVtZXJpYyhwb2JDb20kY29kaWdvLnByb3YpDQogICAgcG9iQ29tJGNvZGlnby5wcm92IDwtIHNwcmludGYoIiUwMmQiLCBwb2JDb20kY29kaWdvLnByb3YpDQogICAgcG9iQ29tJHByb3ZpbmNpYSA8LSB0cmltd3MocG9iQ29tJHByb3ZpbmNpYSwgInIiKQ0KDQogICAgcG9iQ29tWyxjKDQsNSw3KV0gPC0gc2FwcGx5KHBvYkNvbVssYyg0LDUsNyldLCBhcy5udW1lcmljKQ0KICAgIA0KICAgIHJtKGxpc3QgPSBjKCJnIiwgInJvd3MiKSkNCiAgICANCiAgICByZXR1cm4ocG9iQ29tKQ0KICAgIA0KfQ0KYGBgDQoNCg0KRXN0YXMgZG9zIGZ1bmNpb25lcyB1dGxpemFuIGVsIHBhcXVldGUgYFRpZHlWZXJzZWAgeSBwb3IgdW4gbGFkbyBgcmVzdWx0YWRvc0RpcHV0YWRvc2Agb2J0aWVuZSB1biBkYXRhZnJhbWUgY29uIGVsIG7Dum1lcm8gZGUgdm90b3MgeSBkaXB1dGFkb3MgcXVlIGNhZGEgZm9ybWFjacOzbiBwb2zDrXRpY2EgaGEgb2J0ZW5pZG8gZW4gY2FkYSBjb211bmlkYWQuIExhIGZ1bmNpw7NuIGByZXN1bHRhZG9zRGlwdXRhZG9zVGlwb1ZvdG9gIGNyZWEgb3RybyBkYXRhZnJhbWUgcGFydGllbmRvIGRlbCBtaXNtbyBhcmNoaXZvIHBlcm8gY29uIGxvcyBkYXRvcyByZWxhdGl2b3MgYWwgdGlwbyBkZSB2b3RvOiBDRVIsIENFUkEsIGFidGVuc2nDs24sIHZhbGlkbywgbnVsbywgY2Vuc28gZWxlY3RvcmFsIGV0Yy4gRGViaWRvIGEgbGEgaW5nZW50ZSBjYW50aWRhZCBkZSBkYXRvcywgZWwgYXJjaGl2byBvcmlnaW5hbCBsbyBoZW1vcyBzZXBhcmFkbyBlbiBkb3MgZGF0YWZyYW1lcyBtw6FzIG1hbmVqYWJsZXMuDQoNCmBgYHtyIH0NCnJlc3VsdGFkb011bmljaXBpb3MgPC0gZnVuY3Rpb24oZGYsIHJvd3Mpew0KICAgIGcgPC0gZGYNCiAgICByb3dzIDwtIHJvd3MNCiAgICANCiAgICBjb2xuYW1lcyhnKSA8LSBhcy5jaGFyYWN0ZXIoZ1szLF0pDQogICAgIyBnIDwtIGphbml0b3I6OmNsZWFuX25hbWVzKGcpDQogICAgbXVuaWNpcGlvcyA8LSBnWzQ6cm93cyxdDQogICAgbXVuaWNpcGlvcyA8LSBtdW5pY2lwaW9zICU+JSBzZWxlY3QoLWMoNzoxMykpDQogICAgbXVuaWNpcGlvcyA8LSBtdW5pY2lwaW9zICU+JSBnYXRoZXIocGFydGlkbywgdm90b3MsIDc6bGVuZ3RoKC4pKQ0KICAgIGNvbG5hbWVzKG11bmljaXBpb3MpIDwtIGMoImNvbXVuaWRhZCIsICJjb2RpZ28ucHJvdiIsICJwcm92aW5jaWEiLCAiY29kaWdvLm11bmkiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJtdW5pY2lwaW8iLCJwb2JsYWNpb24iLCAicGFydGlkbyIsICJ2b3RvcyIpDQogICAgbXVuaWNpcGlvcyRwb2JsYWNpb24gPC0gYXMubnVtZXJpYyhtdW5pY2lwaW9zJHBvYmxhY2lvbikNCiAgICBtdW5pY2lwaW9zJHZvdG9zIDwtIGFzLm51bWVyaWMobXVuaWNpcGlvcyR2b3RvcykNCiAgICBtdW5pY2lwaW9zJGNvZGlnby5wcm92IDwtIGFzLm51bWVyaWMobXVuaWNpcGlvcyRjb2RpZ28ucHJvdikNCiAgICBtdW5pY2lwaW9zJGNvZGlnby5wcm92IDwtIHNwcmludGYoIiUwMmQiLCBtdW5pY2lwaW9zJGNvZGlnby5wcm92KQ0KICAgIG11bmljaXBpb3MkY29kaWdvLm11bmkgPC0gYXMubnVtZXJpYyhtdW5pY2lwaW9zJGNvZGlnby5tdW5pKQ0KICAgIG11bmljaXBpb3MkY29kaWdvLm11bmkgPC0gc3ByaW50ZigiJTAzZCIsIG11bmljaXBpb3MkY29kaWdvLm11bmkpDQogICAgbXVuaWNpcGlvcyRwcm92aW5jaWEgPC0gdHJpbXdzKG11bmljaXBpb3MkcHJvdmluY2lhLCAiciIpDQoNCiAgICByZXR1cm4obXVuaWNpcGlvcykNCiAgICANCiAgICBybShsaXN0ID0gYygiZyIsICJtdW5pY2lwaW9zIiwgInJvd3MiKSkNCn0NCg0KcmVzdWx0YWRvTXVuaWNpcGlvc1RpcG9Wb3RvcyA8LSBmdW5jdGlvbihkZiwgcm93cyl7DQogICAgZyA8LSBkZg0KICAgIHJvd3MgPC0gcm93cw0KICAgIA0KICAgIGNvbG5hbWVzKGcpIDwtIGFzLmNoYXJhY3RlcihnWzMsXSkNCiAgICAjIGcgPC0gamFuaXRvcjo6Y2xlYW5fbmFtZXMoZykNCiAgICBtdW5pY2lwaW9zIDwtIGdbNDpyb3dzLDE6MTNdDQogICAgbXVuaWNpcGlvcyA8LSBtdW5pY2lwaW9zICU+JSBzZWxlY3QoLWMoNykpICU+JSBnYXRoZXIodGlwby52b3RvLCB0aXBvLnZvdG8ubnVtLCA4Omxlbmd0aCguKSkNCiAgICBjb2xuYW1lcyhtdW5pY2lwaW9zKSA8LSBjKCJjb211bmlkYWQiLCAiY29kaWdvLnByb3YiLCAicHJvdmluY2lhIiwgImNvZGlnby5tdW5pIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAibXVuaWNpcGlvIiwicG9ibGFjaW9uIiwgImNlbnNvLmVsZWN0b3JhbCIsICJ0aXBvLnZvdG8iLCAidGlwby52b3RvLm51bSIpDQogICAgbXVuaWNpcGlvcyRwb2JsYWNpb24gPC0gYXMubnVtZXJpYyhtdW5pY2lwaW9zJHBvYmxhY2lvbikNCiAgICBtdW5pY2lwaW9zJHZvdG9zIDwtIGFzLm51bWVyaWMobXVuaWNpcGlvcyR0aXBvLnZvdG8ubnVtKQ0KICAgIG11bmljaXBpb3MkY29kaWdvLnByb3YgPC0gYXMubnVtZXJpYyhtdW5pY2lwaW9zJGNvZGlnby5wcm92KQ0KICAgIG11bmljaXBpb3MkY29kaWdvLnByb3YgPC0gc3ByaW50ZigiJTAyZCIsIG11bmljaXBpb3MkY29kaWdvLnByb3YpDQogICAgbXVuaWNpcGlvcyRjb2RpZ28ubXVuaSA8LSBhcy5udW1lcmljKG11bmljaXBpb3MkY29kaWdvLm11bmkpDQogICAgbXVuaWNpcGlvcyRjb2RpZ28ubXVuaSA8LSBzcHJpbnRmKCIlMDNkIiwgbXVuaWNpcGlvcyRjb2RpZ28ubXVuaSkNCiAgICBtdW5pY2lwaW9zJHByb3ZpbmNpYSA8LSB0cmltd3MobXVuaWNpcGlvcyRwcm92aW5jaWEsICJyIikNCiAgICANCiAgICByZXR1cm4obXVuaWNpcGlvcykNCiAgICANCiAgICBybShsaXN0ID0gYygiZyIsICJtdW5pY2lwaW9zIiwgInJvd3MiKSkNCn0NCg0KYGBgDQoNCkxhcyBmdW5jaW9uZXMgYW50ZXJpb3JlcyBoYWNlbiBsYSBtaXNtYSBmdW5jacOzbiBxdWUgbGFzIGRlc2NyaXRhcyBwYXJhIGxvcyByZXN1bHRhZG9zIGdlbmVyYWxlcyBwZXJvIGVzdGFzIHNlIHV0aWxpemFuIHBhcmEgbG9zIHJlc3VsdGFkb3MgbXVuaWNpcGFsZXMuDQoNCkVMIHByb2NlZGltaWVudG8gcGFyYSB1c2FyIGxhcyBmdW5jaW9uZXMgZXMgZWwgc2lndWllbnRlOiBgcmVzdWx0YWRvRGlwdXRhZG9zKGRhdGFmcmFtZSwgZmlsYXMpYC4gRWwgYXRyaWJ1dG8gZGF0YWZyYW1lIGVzIGVsIGNvbmp1bnRvIGRlIGRhdG9zIHNvYnJlIGVsIHF1ZSB0cmFiYWphcsOhIHkgZWwgYXRyaWJ1dG8gZmlsYXMgZXMgZWwgbsO6bWVybyBkZSBmaWxhcyDDunRpbGVzIHlhIHF1ZSBlc3RvcyBhcmNoaXZvcyBjb250aWVuZSBmaWxhcyBlbiBibGFuY28gbyBxdWUgbXVlc3RyYW4gdG90YWxlcy4gUG9yIHByYXRpY2lkYWQgZGVjaWRpbW9zIGVsaW1pbmFybGFzIHkgc2kgbmVjZXNpdGFtb3MgbG9zIHRvdGFsZXMgbG9zIGNhbHVsYXJlbW9zIGluc2l0dS4gUGFyYSBlbCByZXN0byBkZSBmdW5jaW9uZXMgZXMgZWwgbWlzbW8gcHJvY2VkaW1pZW50bywgbGEgZnVuY2nDs24gZXN0w6EgcHJvZ3JhbWEgcGFyYSBzYWJlciBxdWUgY29sdW1uYXMgdGllbmUgcXVlIHV0aWxpemFyLg0KTGFzIGZ1bmNpb25lcyBvcmlnaW5hbGVzIHNlIGVuY3VlbnRyYW4gZW4gZWwgYXJjaGl2byBgcHJlcGFyYWNpb25fZGF0b3MuUmANCg0KIyMjIEFyY2hpdm86IGBmdW5jaW9uZXMuUmANCg0KRXN0ZSBhcmNoaXZvIGluY2x1eWUgdW5hIHNlcmllcyBkZSBmdW5jaW9uZXMgcXVlIG5vcyBoYW4gc2lkbyBtdXkgw7p0aWxlcy4NCg0KYGBge3IgfQ0KIyBGdW5jacOzbiBwYXJhIHBvZGVyIHVuaXIgY29ycmVjdGFtZW50ZSBsb3MgZGYgZGUgbG9zIHJlc3VsdGFkb3MgY29uIGxvcyBjw7NkaWdvcyBkZSBsYXMgQ0NBQSB5IHByb3ZpbmNpYXMuDQoNCmxpbXBpYXJQcm92IDwtIGZ1bmN0aW9uKHgpew0KICAgIHggPC0gdG9sb3dlcih4KQ0KICAgIHggPC0gZ3N1YigiLCBjb211bmlkYWQgZGUiLCAiIiwgeCkNCiAgICB4IDwtIGdzdWIoIiwgcmVnaVx1MDBGM24gZGUiLCAiIiwgeCkNCiAgICB4IDwtIGdzdWIoIiwgY29tdW5pZGFkIGZvcmFsIGRlIiwgIiIsIHgpDQogICAgeCA8LSBnc3ViKCIsIHByaW5jaXBhZG8gZGUiLCAiIiwgeCkNCiAgICB4IDwtIGdzdWIoImNvcnXDsWEsIGEiLCAiQSBDb3J1w7FhIiwgeCkgDQogICAgeCA8LSBnc3ViKCJiYWxlYXJzLCBpbGxlcyIsICJpbGxlcyBiYWxlYXJzIiwgeCkgDQogICAgeCA8LSBnc3ViKCJyaW9qYSwgbGEiLCAibGEgcmlvamEiLCB4KQ0KICAgIHggPC0gZ3N1YigicGFsbWFzLCBsYXMiLCAibGFzIHBhbG1hcyIsIHgpIA0KICAgIHggPC0gdG9vbHM6OnRvVGl0bGVDYXNlKHgpDQp9DQpgYGANCg0KVW4gcG9jbyBkZSB0dW5uaW5nIHBhcmEgbG9zIG1hcGFzIHkgZ3JhZmljb3MuIExvIGhhY2Vtb3MgZW4gdW5hIGZ1bmNpw7NuIHBhcmEgZXN0YW5kYXJpemFyIGVsIGFzcGVjdG8gZGUgbG9zIG1hcGFzIHkgYWhvcnJhcm5vcyBlc2NyaWJpciB0b2RvIGVzZSB0ZXh0byBlbiBjYWRhIHVubyBkZSBsb3MgcXVlIGhlbW9zIGhlY2hvLiBNaXNtYSBsw7NnaWNhIHBhcmEgbG9zIGdyw6FmaWNvcyB5IGxvcyBncsOhZmljb3MgY29uIGZhY2V0IA0KDQpgYGB7ciwgfQ0KdGhlbWVfbWFwIDwtIGZ1bmN0aW9uKC4uLikgew0KICAgIHRoZW1lX21pbmltYWwoKSArDQogICAgICAgIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2xpbmUoY29sb3IgPSAiI2RiZGJkOSIsIHNpemUgPSAwLjIpLCANCiAgICAgICAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAiZ3JheTk5IiksIA0KICAgICAgICAgICAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICIjZjVmNWYyIiwgY29sb3IgPSBOQSksDQogICAgICAgICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICIjZjVmNWYyIiwgY29sb3IgPSBOQSksDQogICAgICAgICAgICAgIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiI2Y1ZjVmMiIsIGNvbG9yID0gTkEpLA0KICAgICAgICAgICAgICBsZWdlbmQua2V5ID0gZWxlbWVudF9yZWN0KGZpbGwgPSBOQSksDQogICAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLA0KICAgICAgICAgICAgICBsZWdlbmQuZGlyZWN0aW9uID0gImhvcml6b250YWwiLA0KICAgICAgICAgICAgICBheGlzLmxpbmUgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICAgICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgICAgIHRleHQgPSBlbGVtZW50X3RleHQoY29sb3IgPSAiIzIyMjExZCIpLA0KICAgICAgICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlID0gImJvbGQiLCBsaW5laGVpZ2h0ID0gIjIwcHgiLCBzaXplID0gIjE1IiksDQogICAgICAgICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIHNpemUgPSAiOSIpKQ0KDQp9DQoNCnRoZW1lX3Bsb3QgPC0gZnVuY3Rpb24oLi4uKXsNCiAgICB0aGVtZV9taW5pbWFsKCkgKw0KICAgICAgICB0aGVtZShwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9saW5lKGNvbG91ciA9ICJncmF5OTkiKSwgDQogICAgICAgICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gImdyYXk5MCIpLCANCiAgICAgICAgICAgICAgcGxvdC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiI2Y1ZjVmMiIsIGNvbG9yID0gTkEpLA0KICAgICAgICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiI2Y1ZjVmMiIsIGNvbG9yID0gTkEpLA0KICAgICAgICAgICAgICBsZWdlbmQuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIiNmNWY1ZjIiLCBjb2xvciA9IE5BKSwNCiAgICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsDQogICAgICAgICAgICAgIGxlZ2VuZC5kaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIsDQogICAgICAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSksDQogICAgICAgICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICAgICAgdGV4dCA9IGVsZW1lbnRfdGV4dChmYW1pbHkgPSAic2FucyIsIGNvbG9yID0gIiMyMjIxMWQiKSwNCiAgICAgICAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZSA9ICJib2xkIiwgbGluZWhlaWdodCA9ICIxNSIsIHNpemUgPSAiMTIiKSwNCiAgICAgICAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9ICI5IiksDQogICAgICAgICAgICAgIHBsb3QubWFyZ2luID0gbWFyZ2luKDEsIDEsIDEsIDEsICJjbSIpKQ0KfQ0KDQp0aGVtZV9wbG90X2ZhY2V0IDwtIGZ1bmN0aW9uKC4uLil7DQogICAgICAgIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gImdyYXk5OSIpLCANCiAgICAgICAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAiZ3JheTkwIiksIA0KICAgICAgICAgICAgICBwbG90LmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICIjZjVmNWYyIiwgY29sb3IgPSBOQSksDQogICAgICAgICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICIjZjVmNWYyIiwgY29sb3IgPSBOQSksDQogICAgICAgICAgICAgIGxlZ2VuZC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiI2Y1ZjVmMiIsIGNvbG9yID0gTkEpLA0KICAgICAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwNCiAgICAgICAgICAgICAgbGVnZW5kLmRpcmVjdGlvbiA9ICJob3Jpem9udGFsIiwNCiAgICAgICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxKSwNCiAgICAgICAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICAgICAgICB0ZXh0ID0gZWxlbWVudF90ZXh0KGZhbWlseSA9ICJzYW5zIiwgY29sb3IgPSAiIzIyMjExZCIpLA0KICAgICAgICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlID0gImJvbGQiLCBsaW5laGVpZ2h0ID0gIjE1Iiwgc2l6ZSA9ICIxMiIpLA0KICAgICAgICAgICAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBzaXplID0gIjkiKSwNCiAgICAgICAgICAgICAgcGxvdC5tYXJnaW4gPSBtYXJnaW4oMSwgMSwgMSwgMSwgImNtIikpDQp9DQoNCmRlZmF1bHRfY2FwdGlvbiA8LSAiRWxhYm9yYWNpXHUwMEYzbiBwcm9waWEuIERhdG9zIGRlbCBNaW5pc3RlcmlvIGRlbCBJbnRlcmlvciINCmBgYA0KDQpGdW5jacOzbiBwYXJhIGNhcmdhciBnZW9tZXRyaWFzLiBNdXkgw7p0aWwsIHRpZW5lIHZhcmlvcyBtb2RvcyBkZXNjcml0b3MgcG9zdGVyaW9ybWVudGUgeSBxdWUgY2FyZ2FuIGxhcyBnZW9tZXRyaWFzIGRlIEVzcGHDsWEgc2Vnw7puIG51ZXN0cm9zIGNyaXRlcmlvcy4gQmFzYWRvIGVuIGVsIHBhcXVldGUgYExBVTJib3VuZGFyaWVzNHNwYWluYCBkaXNwb25pYmxlIGVuIEdpdGh1Yi4gYGxvYWRHZW9tZXRyeShtb2RvLCBwcm92aW5jaWFzLCBtdW5pY2lwaW9zKWAuIGBwcm92aW5jaWFzYCB5IGBtdW5pY2lwaW9zYCBsbyB1dGlsemFyZW1vcyBwb3Igc2kgcXVlcmVtb3Mgb2J0ZW5lciBnZW9ldHJpYXMgY29uY3JldGFzLiBNb2Rvcw0KLSAxOiBTb2xvIHBlbsOtbnN1bGEgeSBiYWxlYXJlcw0KLSAyOiBwZW7DrW5zdWxhLCBiYWxlYXJlcyB5IGNhbmFyaWFzDQotIDM6IGZpbHRyYXIgcHJvdmluY2lhcyBjb24gc3UgY8OzZGlnbw0KLSA0OiBtdW5pY2lwaW9zICgyMDE4KQ0KLSA1OiBmaWx0cmFyIG11bmljaXBpb3MgcG9yIGPDs2RpZ28gZGUgbXVuaWNpcGlvcyBkZWwgSU5FDQotIDY6IGZpbHRyYXIgbXVuaWNpcGlvcyBwb3IgY8OzZGlnbyBkZSBwcm92aW5jaWENCg0KDQpgYGB7ciwgfQ0KIyMgQ2FyZ2FyIGdlb21ldHJpYQ0KIyAxOiBzb2xvIHBlbmluc3VsYSwgMjogY2FuYXJpYXMgKyBwZW5pbnN1bGEsIDM6IHByb3ZpbmNpYXMgcG9yIGNvZGlnbywgNDogbXVuaWNpcGlvcyAyMDE4LCA1LTY6IGZpbHRybyBtdW5pY2lwaW9zIDIwMTgNCmxvYWRHZW9tZXRyeSA8LSBmdW5jdGlvbihtb2RlID0gMSwgcHJvdmluY2lhcyA9IE5VTEwsIG11bmljaXBpb3MgPSBOVUxMKXsNCg0KICAgIGxpYnJhcnkoc2YpDQogICAgbGlicmFyeShMQVUyYm91bmRhcmllczRzcGFpbikNCiAgICAjIGxpYnJhcnkodGlkeXZlcnNlKQ0KICAgIA0KICAgIGlmKG1vZGU9PTEpew0KICAgICAgICBwZW5pbnN1bGEgPC0gUHJvdmluY2lhcyAlPiUgZmlsdGVyKCAhKElORUNvZFByb3YgJWluJSBjKDM1LCAzOCkpICkNCiAgICAgICAgY29sbmFtZXMocGVuaW5zdWxhKVsxXSA8LSBjKCJjb2RpZ28ucHJvdiIpDQogICAgICAgIHJldHVybihwZW5pbnN1bGEpDQogICAgfQ0KICAgIA0KICAgIGlmKG1vZGU9PTIpew0KICAgICAgICAjIGh0dHBzOi8vZ2l0aHViLmNvbS9wZXJlenA0NC9MQVUyYm91bmRhcmllczRzcGFpbg0KICAgICAgICBjYW5hcmlhcyA8LSBQcm92aW5jaWFzICU+JSBmaWx0ZXIoSU5FQ29kUHJvdiAlaW4lIGMoMzUsMzgpKQ0KICAgICAgICBwZW5pbnN1bGEgPC0gUHJvdmluY2lhcyAlPiUgZmlsdGVyKCAhKElORUNvZFByb3YgJWluJSBjKDM1LCAzOCkpICkNCiAgICAgICAgbXlfc2hpZnQgPC0gc3RfYmJveChwZW5pbnN1bGEpW2MoMSwyKV0tIChzdF9iYm94KGNhbmFyaWFzKVtjKDEsMildKSArIGMoLTIuNCwgLTEuMSkNCiAgICAgICAgY2FuYXJpYXMkZ2VvbWV0cnkgPC0gY2FuYXJpYXMkZ2VvbWV0cnkgKyBteV9zaGlmdA0KICAgICAgICBzdF9jcnMoY2FuYXJpYXMpICA8LSBzdF9jcnMocGVuaW5zdWxhKQ0KICAgICAgICBwZW5pbnN1bGFfYSA8LSByYmluZChwZW5pbnN1bGEsIGNhbmFyaWFzKQ0KICAgICAgICBjb2xuYW1lcyhwZW5pbnN1bGFfYSlbMV0gPC0gYygiY29kaWdvLnByb3YiKQ0KICAgICAgICByZXR1cm4ocGVuaW5zdWxhX2EpDQogICAgfQ0KICAgIA0KICAgIGlmKG1vZGU9PTMpew0KICAgICAgICANCiAgICAgICAgeCA8LSBQcm92aW5jaWFzICU+JSBmaWx0ZXIoSU5FQ29kUHJvdiAlaW4lIHByb3ZpbmNpYXMpDQogICAgICAgIGNvbG5hbWVzKHgpWzFdIDwtIGMoImNvZGlnby5wcm92IikNCiAgICAgICAgcmV0dXJuKHgpDQogICAgfQ0KICAgIA0KICAgIGlmKG1vZGU9PTQpew0KICAgICAgICB4IDwtIG11bmljaXBpb3NfMjAxOA0KICAgICAgICByZXR1cm4oeCkNCiAgICB9DQogICAgDQogICAgaWYobW9kZT09NSl7DQogICAgICAgIHggPC0gbXVuaWNpcGlvc18yMDE4ICU+JSBmaWx0ZXIoSU5FQ29kTXVuaSAlaW4lIG11bmljaXBpb3MpDQogICAgICAgIHJldHVybih4KQ0KICAgIH0NCiAgICBpZihtb2RlPT02KXsNCiAgICAgICAgeCA8LSBtdW5pY2lwaW9zXzIwMTggJT4lIGZpbHRlcihJTkVDb2RQcm92ICVpbiUgcHJvdmluY2lhcykNCiAgICAgICAgcmV0dXJuKHgpDQogICAgfQ0KDQp9DQoNCg0KYGBgDQoNCg0KDQo=