knitr::opts_chunk$set(echo = TRUE)

#1. En este cuaderno trabajaremos las exploraciones estadisticas no espaciales del departamento de Caqueta, es fundamental para comprender lo que sucede en los territorios. Varias bibliotecas de R, en particular dplyr y tidyverse, son muy útiles para explorar y resumir estadísticas.

Comenzamos removiendo el contenido de la memoria

rm(list=ls())

Intalamos la librerias que necesitamos y las llamamos

library(here)
library(tidyverse)
library(rgeos)
library(maptools)
library(raster)
library(sf)
library(viridis)

#2. Descargamos los datos de Caqueta de las “Estadisticas municipales agropecuarias” y lo llamamos en formato CVS

En este objeto vamos a asignar los datos no espaciales asociados a las evaluaciones agropecuarias del departamento, donde se hace un resumen de los cultivos producidos en cada municipio, ademas de datos estadisticos como el area cultivada por cada elemento ademas de valores de produccion anual de los mismos

datos <- read_csv2("d:/Users/Janus/Documents/Geomatica basica/18_CAQUETA/Caqueta_EVA.csv")
Using ',' as decimal and '.' as grouping mark. Use read_delim() for more control.
Parsed with column specification:
cols(
  COD_DEP = col_double(),
  DEPARTAMENTO = col_character(),
  COD_MUN = col_double(),
  MUNICIPIO = col_character(),
  GRUPO = col_character(),
  SUBGRUPO = col_character(),
  CULTIVO = col_character(),
  YEAR = col_double(),
  PERIODO = col_character(),
  H_Sembrada = col_double(),
  H_Cosechada = col_double(),
  PRODUCCION = col_double(),
  REN = col_character(),
  ESTADO_FRUTO = col_character(),
  CICLO = col_character()
)

Observamos los atributos de los datos

head(datos)
tail(datos)
library(dplyr)

#3. Vamos a iniciar el trabajo mostrando el rendimiento promedio de la produccion de los diferentes cultivos en cada uno de los muncipios, con esto podemos ver que grupo de cultivos predominan en tema de rendimiento anual en cada municipio

datos %>%
  group_by(MUNICIPIO, GRUPO) %>%
  summarise(rend_prom = mean(REN, na.rm = TRUE)) -> REN_resumen
argument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NAargument is not numeric or logical: returning NA`summarise()` regrouping output by 'MUNICIPIO' (override with `.groups` argument)
REN_resumen
NA
NA
datos %>% group_by(GRUPO) %>% summarise(PRODUCCION=mean(PRODUCCION,na.rm= TRUE))->PROD_caqueta
`summarise()` ungrouping output (override with `.groups` argument)
PROD_caqueta
datos %>% 
  filter(YEAR==2.018) %>% 
  
  group_by(GRUPO, MUNICIPIO) %>%
  
  summarize(max_ren = max(REN, na.rm = TRUE)) %>%
    slice(which.max(max_ren)) -> ren_max_16
`summarise()` regrouping output by 'GRUPO' (override with `.groups` argument)
ren_max_16

Aqui vamos a mostrar que municipio tuvo un mayor rendimiento para cada grupo de cultivo especificamente en el año 2018

datos %>%filter(YEAR==2.018) %>% group_by(GRUPO, MUNICIPIO) %>%
  summarize(max_H_Cosechada = max(H_Cosechada, na.rm = TRUE)) %>%
    slice(which.max(max_H_Cosechada)) -> H_cosecha_max
`summarise()` regrouping output by 'GRUPO' (override with `.groups` argument)
H_cosecha_max

#4. Para esta nueva visualizacion, realizaremos un filtro de los datos donde que municipio tuvo una mayor area cosechada para cada grupo de cultivo, observando que hay municipios que destinan una gran superficie para el tema agricola

datos %>% filter(GRUPO=="OTROS PERMANENTES") %>% 
  group_by(MUNICIPIO, SUBGRUPO="CACAO") %>% 
  summarise (max_PROD=max(PRODUCCION, na.rm = TRUE)) %>% slice(which.max(max_PROD))->PROD_max
`summarise()` regrouping output by 'MUNICIPIO' (override with `.groups` argument)
PROD_max

Aqui realizamos un filtro de los datos para explorar el grupo de cultivo Otros permanentes para ver que cual fue la maxima produccion de estos cultivos dentro del tiempo que cubren los datos

datos %>% 
  filter(MUNICIPIO=="FLORENCIA" & SUBGRUPO=="CACAO") %>% 
  group_by(YEAR, CULTIVO) ->  VICEN_CACAO
VICEN_CACAO

Para ver estos datos de una forma grafica, nos aprovecharemos de la funcion ggplot para vrlos de forma grafica y analizarlos de mejor manera, donde observamos que el año de mayor produccion en el municipio fue el 2013 llegando a las 200 toneladas en ese año

g <- ggplot(aes(x=YEAR, y=PRODUCCION/100), data = VICEN_CACAO) + geom_bar(stat='identity') + labs(y='Cacao Production [Ton x 1000]')

g + ggtitle("Evolution of cacao production in FLORENCIA from 2013 to 2018") + labs(caption= "Based on EMA data (DANE, 2018)")

Realizamos otra consulta, esta vez para observar la superficie cosechada total por cada grupo de cultivo en el año 2018, donde se observa que los cultivos Otros Permanentes detacan ampliamente sobre el resto

datos %>% 
  filter(YEAR==2.018) %>% 
  group_by(GRUPO) %>%
  summarize(sum_H_Cosechada = sum(H_Cosechada, na.rm = TRUE)) %>%
     arrange(desc(sum_H_Cosechada)) -> total_area_cosecha
`summarise()` ungrouping output (override with `.groups` argument)
total_area_cosecha

Basados en lo anterior, vamos a realizar un filtro sobre el mismo año, pero tomando solo los cultivos otros permanentes, esto para ver cual cultivo en especifico es el que predomina respecto al area cosechada en el departamento

datos %>%
  filter(GRUPO=="OTROS PERMANENTES" & YEAR==2.018) %>%
  group_by(CULTIVO) %>%
  summarize(sum_cosecha = sum(H_Cosechada, na.rm = TRUE)) %>%
     arrange(desc(sum_cosecha)) -> total_cosecha
`summarise()` ungrouping output (override with `.groups` argument)
total_cosecha

Ahora que ya sabemos que la caña panalera es el cultivo de mayor area cosechada, con este nuevo filtro veremos que municipio presenta una mayor area cosechada de caña panelera en el año 2018.

datos %>% 
  filter(YEAR==2.018 & GRUPO=="OTROS PERMANENTES") %>% 
  group_by(CULTIVO, MUNICIPIO) %>%
  summarize(max_area2 = max(H_Cosechada, na.rm = TRUE)) %>%
    slice(which.max(max_area2)) -> area_cosecha2
`summarise()` regrouping output by 'CULTIVO' (override with `.groups` argument)
area_cosecha2

antes de realizar el ploteo, a cada una de las clases, que seran los grupos de cultivo, vamos a realizarles una abreviatura, para que se pueda leer con claridad en el ploteo

total_area_cosecha$CROP <- abbreviate(total_area_cosecha$GRUPO, 3)
g <- ggplot(aes(x=CROP, y=sum_H_Cosechada), data = total_area_cosecha) + geom_bar(stat='identity') + labs(y='Total Harvested Area [Ha]')
library(ggplot2)

g+ ggtitle(“Total harvested area by crop groups in 2018 for FLORENCIA”) + theme(plot.title = element_text(hjust = 0.5)) + labs(caption= “Based on EMA data (DANE, 2018)”)

g+ ggtitle("Total harvested area by crop groups in 2018 for Caqueta") + theme(plot.title = element_text(hjust = 0.5)) +
   labs(caption= "Based on EMA data (DANE, 2018)")

NA
NA

#5. La segunda parte del informe consistira en realizar una union entre los datos no espacilaes mostrados en la primeraparte y un archivo de datos espaciales proveniente del marco geoestadistico del pais provenineto del DANE

ant_munic <- sf::st_read("d:/Users/Janus/Documents/Geomatica basica/18_CAQUETA/ADMINISTRATIVO/MGN_MPIO_POLITICO.shp")
Reading layer `MGN_MPIO_POLITICO' from data source `D:\Users\Janus\Documents\Geomatica basica\18_CAQUETA\ADMINISTRATIVO\MGN_MPIO_POLITICO.shp' using driver `ESRI Shapefile'
Simple feature collection with 16 features and 9 fields
geometry type:  POLYGON
dimension:      XY
bbox:           xmin: -76.30622 ymin: -0.70584 xmax: -71.25385 ymax: 2.964148
geographic CRS: WGS 84
ant_munic
Simple feature collection with 16 features and 9 fields
geometry type:  POLYGON
dimension:      XY
bbox:           xmin: -76.30622 ymin: -0.70584 xmax: -71.25385 ymax: 2.964148
geographic CRS: WGS 84
First 10 features:
   DPTO_CCDGO MPIO_CCDGO             MPIO_CNMBR
1          18      18001              FLORENCIA
2          18      18029                ALBANIA
3          18      18094 BELÉN DE LOS ANDAQUÍES
4          18      18247            EL DONCELLO
5          18      18256              EL PAUJIL
6          18      18410           LA MONTAÑITA
7          18      18460                  MILÁN
8          18      18479                MORELIA
9          18      18610    SAN JOSÉ DEL FRAGUA
10         18      18860             VALPARAÍSO
                              MPIO_CRSLC MPIO_NAREA MPIO_NANO DPTO_CNMBR
1        Decreto 642 de Junio 17 de 1912  2547.6384      2017    CAQUETÁ
2    Ordenanza 3 de Noviembre 12 de 1985   414.1220      2017    CAQUETÁ
3        Decreto 963 de Marzo 14 de 1950  1191.6187      2017    CAQUETÁ
4   Decreto 1678 de Septiembre 7 de 1967  1105.8029      2017    CAQUETÁ
5  Decreto 1678 de Septiembret 7 de 1967  1234.7427      2017    CAQUETÁ
6          Decreto 83 de Julio 6 de 1955  1701.0522      2017    CAQUETÁ
7    Ordenanza 3 de Noviembre 12 de 1985  1220.5726      2017    CAQUETÁ
8    Ordenanza 3 de Noviembre 12 de 1985   462.4799      2017    CAQUETÁ
9    Ordenanza 3 de Noviembre 12 de 1985  1304.7690      2017    CAQUETÁ
10   Ordenanza 3 de Noviembre 12 de 1985  1330.2126      2017    CAQUETÁ
   Shape_Leng Shape_Area                       geometry
1    2.942508 0.20692777 POLYGON ((-75.42074 2.19413...
2    1.112829 0.03361758 POLYGON ((-75.89506 1.36569...
3    2.234657 0.09674460 POLYGON ((-75.78705 1.74982...
4    3.154370 0.08986744 POLYGON ((-75.36167 2.32142...
5    3.529316 0.10030928 POLYGON ((-75.36691 2.21234...
6    3.402939 0.13817351 POLYGON ((-75.40404 1.76944...
7    1.863197 0.09912782 POLYGON ((-75.39362 1.35738...
8    1.518688 0.03755356 POLYGON ((-75.77185 1.57991...
9    2.040837 0.10589313 POLYGON ((-76.16722 1.58752...
10   2.313848 0.10800551 POLYGON ((-75.73128 1.32740...

Para realizar el join necesitamos un campo en comun entre ambos paquetes de datos, por lo que usaremos el codigo de municipio para ello, estas dos lineas nos serviran para crear dos campos nuevos a los datos no espaciales, conel objetivo de convertir la columna COD_MUN que es un objeto de tipo numerico a un objeto de tipo factor, cosa fundamental para realizar el join

datos %>% filter (MUNICIPIO =="FLORENCIA") ->  caq_datos
caq_datos
class(caq_datos$COD_MUN)
[1] "numeric"
datos2 <- datos
datos2$TEMP <-  as.character(datos2$COD_MUN)
datos2$MPIO_CCDGO <- as.factor(paste(0, datos2$TEMP, sep=""))
head(datos2)
NA

Para poder hacer la unión, necesitamos cambiar tanto el tipo de datos como el contenido del código que identifica a cada municipio. Para esta tarea, es una buena idea crear una copia de los datos estadísticos originales. Con este enfoque, cualquier movimiento falso no estropeará los datos originales.

datos2 %>% filter(CULTIVO == "CACAO")  -> datos3
head(datos3)
NA
class(datos3)
[1] "spec_tbl_df" "tbl_df"      "tbl"         "data.frame" 
datos4 <- datos3 %>% dplyr::select(MUNICIPIO, MPIO_CCDGO, YEAR, PRODUCCION, REN) 
datos4
NA
datos4 %>% 
  gather("YEAR", "PRODUCCION", "REN" , key = variable, value = number)
head(datos4)
NA

Ésta tarea es clave. Implica varios pasos para poder convertir la tabla de atributos de formato largo a formato ancho.

datos4 %>% 
  group_by(MPIO_CCDGO) %>% 
  mutate(Visit = 1:n()) %>% 
  gather("YEAR", "PRODUCCION", "REN", key = variable, value = number) %>% 
  unite(combi, variable, Visit) %>%
  spread(combi, number) -> datos5
head(datos5)
NA
tail(datos5)
NA

Realizamos una copia de la colección de características simples

ant_munic2 <- ant_munic
ant_munic_stat = left_join(ant_munic2, datos5, by="MPIO_CCDGO")
summary(ant_munic_stat)
  DPTO_CCDGO         MPIO_CCDGO         MPIO_CNMBR       
 Length:16          Length:16          Length:16         
 Class :character   Class :character   Class :character  
 Mode  :character   Mode  :character   Mode  :character  
                                                         
                                                         
                                                         
  MPIO_CRSLC          MPIO_NAREA        MPIO_NANO     DPTO_CNMBR       
 Length:16          Min.   :  403.4   Min.   :2017   Length:16         
 Class :character   1st Qu.:  948.6   1st Qu.:2017   Class :character  
 Mode  :character   Median : 1269.8   Median :2017   Mode  :character  
                    Mean   : 5631.4   Mean   :2017                     
                    3rd Qu.: 2947.4   3rd Qu.:2017                     
                    Max.   :42312.8   Max.   :2017                     
   Shape_Leng       Shape_Area       MUNICIPIO         PRODUCCION_1      
 Min.   : 1.113   Min.   :0.03274   Length:16          Length:16         
 1st Qu.: 1.794   1st Qu.:0.07708   Class :character   Class :character  
 Median : 2.628   Median :0.10310   Mode  :character   Mode  :character  
 Mean   : 4.483   Mean   :0.45741                                        
 3rd Qu.: 3.713   3rd Qu.:0.23944                                        
 Max.   :20.046   Max.   :3.43579                                        
 PRODUCCION_10      PRODUCCION_11      PRODUCCION_12     
 Length:16          Length:16          Length:16         
 Class :character   Class :character   Class :character  
 Mode  :character   Mode  :character   Mode  :character  
                                                         
                                                         
                                                         
 PRODUCCION_2       PRODUCCION_3       PRODUCCION_4      
 Length:16          Length:16          Length:16         
 Class :character   Class :character   Class :character  
 Mode  :character   Mode  :character   Mode  :character  
                                                         
                                                         
                                                         
 PRODUCCION_5       PRODUCCION_6       PRODUCCION_7      
 Length:16          Length:16          Length:16         
 Class :character   Class :character   Class :character  
 Mode  :character   Mode  :character   Mode  :character  
                                                         
                                                         
                                                         
 PRODUCCION_8       PRODUCCION_9          REN_1          
 Length:16          Length:16          Length:16         
 Class :character   Class :character   Class :character  
 Mode  :character   Mode  :character   Mode  :character  
                                                         
                                                         
                                                         
    REN_10             REN_11             REN_12         
 Length:16          Length:16          Length:16         
 Class :character   Class :character   Class :character  
 Mode  :character   Mode  :character   Mode  :character  
                                                         
                                                         
                                                         
    REN_2              REN_3              REN_4          
 Length:16          Length:16          Length:16         
 Class :character   Class :character   Class :character  
 Mode  :character   Mode  :character   Mode  :character  
                                                         
                                                         
                                                         
    REN_5              REN_6              REN_7          
 Length:16          Length:16          Length:16         
 Class :character   Class :character   Class :character  
 Mode  :character   Mode  :character   Mode  :character  
                                                         
                                                         
                                                         
    REN_8              REN_9              YEAR_1         
 Length:16          Length:16          Length:16         
 Class :character   Class :character   Class :character  
 Mode  :character   Mode  :character   Mode  :character  
                                                         
                                                         
                                                         
   YEAR_10            YEAR_11            YEAR_12         
 Length:16          Length:16          Length:16         
 Class :character   Class :character   Class :character  
 Mode  :character   Mode  :character   Mode  :character  
                                                         
                                                         
                                                         
    YEAR_2             YEAR_3             YEAR_4         
 Length:16          Length:16          Length:16         
 Class :character   Class :character   Class :character  
 Mode  :character   Mode  :character   Mode  :character  
                                                         
                                                         
                                                         
    YEAR_5             YEAR_6             YEAR_7         
 Length:16          Length:16          Length:16         
 Class :character   Class :character   Class :character  
 Mode  :character   Mode  :character   Mode  :character  
                                                         
                                                         
                                                         
    YEAR_8             YEAR_9                   geometry 
 Length:16          Length:16          POLYGON      :16  
 Class :character   Class :character   epsg:4326    : 0  
 Mode  :character   Mode  :character   +proj=long...: 0  
                                                         
                                                         
                                                         

#6. Intalamos las librerias necesarias para Plotear

library(RColorBrewer)
library(leaflet)

Esta instruccion nos permite ver en un mapa del departamento los valores de produccion de cada departamente en un año especifico

bins <- c(0, 250, 500, 1000, 2000, 5000, 10000, 15000)
pal <- colorBin("YlOrRd", domain = ant_munic_stat$PRODUCCION_12, bins = bins)

  mapa <- leaflet(data = ant_munic_stat) %>%
  addTiles() %>%
  addPolygons(label = ~PRODUCCION_12,
              popup = ~MPIO_CNMBR,
              fillColor = ~pal(PRODUCCION_12),
              color = "#444444",
              weight = 1,
              smoothFactor = 0.5,
              opacity = 1.0,
              fillOpacity = 0.5,
              highlightOptions = highlightOptions(color = "white", weight = 2, bringToFront = TRUE)
              ) %>%
  addProviderTiles(providers$OpenStreetMap) %>%
  addLegend("bottomright", pal = pal, values = ~PRODUCCION_12,
    title = "CACAO production in Caqueta [Ton] (2018)",
    opacity = 1
  )

#7. Este es resultado de nuestro mapa de cultivo de CACAO en Caqueta

mapa
LS0tDQp0aXRsZTogIklORk9STUUoMSkgQ0FRVUVUQSINCmF1dGhvcjogIkx1aXMgQ2FzdGlsbG8iDQpvdXRwdXQ6DQogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQNCiAgaHRtbF9kb2N1bWVudDogZGVmYXVsdA0KLS0tDQoNCmBgYHtyfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQ0KDQpgYGANCiMxLg0KRW4gZXN0ZSBjdWFkZXJubyB0cmFiYWphcmVtb3MgbGFzIGV4cGxvcmFjaW9uZXMgZXN0YWRpc3RpY2FzIG5vIGVzcGFjaWFsZXMgZGVsIGRlcGFydGFtZW50byBkZSBDYXF1ZXRhLCBlcyBmdW5kYW1lbnRhbCBwYXJhIGNvbXByZW5kZXIgbG8gcXVlIHN1Y2VkZSBlbiBsb3MgdGVycml0b3Jpb3MuIFZhcmlhcyBiaWJsaW90ZWNhcyBkZSBSLCBlbiBwYXJ0aWN1bGFyIGRwbHlyIHkgdGlkeXZlcnNlLCBzb24gbXV5IMO6dGlsZXMgcGFyYSBleHBsb3JhciB5IHJlc3VtaXIgZXN0YWTDrXN0aWNhcy4NCg0KQ29tZW56YW1vcyByZW1vdmllbmRvIGVsIGNvbnRlbmlkbyBkZSBsYSBtZW1vcmlhIA0KYGBge3J9DQpybShsaXN0PWxzKCkpDQpgYGANCkludGFsYW1vcyBsYSBsaWJyZXJpYXMgcXVlIG5lY2VzaXRhbW9zIHkgbGFzIGxsYW1hbW9zDQpgYGB7cn0NCmxpYnJhcnkoaGVyZSkNCmBgYA0KYGBge3J9DQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmBgYA0KYGBge3J9DQpsaWJyYXJ5KHJnZW9zKQ0KYGBgDQpgYGB7cn0NCmxpYnJhcnkobWFwdG9vbHMpDQpgYGANCg0KYGBge3J9DQpsaWJyYXJ5KHJhc3RlcikNCg0KYGBgDQpgYGB7cn0NCmxpYnJhcnkoc2YpDQpgYGANCmBgYHtyfQ0KbGlicmFyeSh2aXJpZGlzKQ0KYGBgDQoNCiMyLg0KRGVzY2FyZ2Ftb3MgbG9zIGRhdG9zIGRlIENhcXVldGEgZGUgbGFzICJFc3RhZGlzdGljYXMgbXVuaWNpcGFsZXMgYWdyb3BlY3VhcmlhcyINCnkgbG8gbGxhbWFtb3MgZW4gZm9ybWF0byBDVlMNCg0KRW4gZXN0ZSBvYmpldG8gdmFtb3MgYSBhc2lnbmFyIGxvcyBkYXRvcyBubyBlc3BhY2lhbGVzIGFzb2NpYWRvcyBhIGxhcyBldmFsdWFjaW9uZXMgYWdyb3BlY3VhcmlhcyBkZWwgZGVwYXJ0YW1lbnRvLCBkb25kZSBzZSBoYWNlIHVuIHJlc3VtZW4gZGUgbG9zIGN1bHRpdm9zIHByb2R1Y2lkb3MgZW4gY2FkYSBtdW5pY2lwaW8sIGFkZW1hcyBkZSBkYXRvcyBlc3RhZGlzdGljb3MgY29tbyBlbCBhcmVhIGN1bHRpdmFkYSBwb3IgY2FkYSBlbGVtZW50byBhZGVtYXMgZGUgdmFsb3JlcyBkZSBwcm9kdWNjaW9uIGFudWFsIGRlIGxvcyBtaXNtb3MNCmBgYHtyfQ0KZGF0b3MgPC0gcmVhZF9jc3YyKCJkOi9Vc2Vycy9KYW51cy9Eb2N1bWVudHMvR2VvbWF0aWNhIGJhc2ljYS8xOF9DQVFVRVRBL0NhcXVldGFfRVZBLmNzdiIpDQpgYGANCg0KT2JzZXJ2YW1vcyBsb3MgYXRyaWJ1dG9zIGRlIGxvcyBkYXRvcw0KDQpgYGB7cn0NCmhlYWQoZGF0b3MpDQpgYGANCmBgYHtyfQ0KdGFpbChkYXRvcykNCmBgYA0KDQoNCmBgYHtyfQ0KbGlicmFyeShkcGx5cikNCmBgYA0KDQojMy4NClZhbW9zIGEgaW5pY2lhciBlbCB0cmFiYWpvIG1vc3RyYW5kbyBlbCByZW5kaW1pZW50byBwcm9tZWRpbyBkZSBsYSBwcm9kdWNjaW9uIGRlIGxvcyBkaWZlcmVudGVzIGN1bHRpdm9zIGVuIGNhZGEgdW5vIGRlIGxvcyBtdW5jaXBpb3MsIGNvbiBlc3RvIHBvZGVtb3MgdmVyIHF1ZSBncnVwbyBkZSBjdWx0aXZvcyBwcmVkb21pbmFuIGVuIHRlbWEgZGUgcmVuZGltaWVudG8gYW51YWwgZW4gY2FkYSBtdW5pY2lwaW8NCg0KYGBge3J9DQpkYXRvcyAlPiUNCiAgZ3JvdXBfYnkoTVVOSUNJUElPLCBHUlVQTykgJT4lDQogIHN1bW1hcmlzZShyZW5kX3Byb20gPSBtZWFuKFJFTiwgbmEucm0gPSBUUlVFKSkgLT4gUkVOX3Jlc3VtZW4NClJFTl9yZXN1bWVuDQoNCg0KYGBgDQoNCmBgYHtyfQ0KZGF0b3MgJT4lIGdyb3VwX2J5KEdSVVBPKSAlPiUgc3VtbWFyaXNlKFBST0RVQ0NJT049bWVhbihQUk9EVUNDSU9OLG5hLnJtPSBUUlVFKSktPlBST0RfY2FxdWV0YQ0KUFJPRF9jYXF1ZXRhDQpgYGANCg0KYGBge3J9DQpkYXRvcyAlPiUgDQogIGZpbHRlcihZRUFSPT0yLjAxOCkgJT4lIA0KICANCiAgZ3JvdXBfYnkoR1JVUE8sIE1VTklDSVBJTykgJT4lDQogIA0KICBzdW1tYXJpemUobWF4X3JlbiA9IG1heChSRU4sIG5hLnJtID0gVFJVRSkpICU+JQ0KICAgIHNsaWNlKHdoaWNoLm1heChtYXhfcmVuKSkgLT4gcmVuX21heF8xNg0KDQpyZW5fbWF4XzE2DQpgYGANCkFxdWkgdmFtb3MgYSBtb3N0cmFyIHF1ZSBtdW5pY2lwaW8gdHV2byB1biBtYXlvciByZW5kaW1pZW50byBwYXJhIGNhZGEgZ3J1cG8gZGUgY3VsdGl2byBlc3BlY2lmaWNhbWVudGUgZW4gZWwgYcOxbyAyMDE4DQoNCg0KYGBge3J9IA0KZGF0b3MgJT4lZmlsdGVyKFlFQVI9PTIuMDE4KSAlPiUgZ3JvdXBfYnkoR1JVUE8sIE1VTklDSVBJTykgJT4lDQogIHN1bW1hcml6ZShtYXhfSF9Db3NlY2hhZGEgPSBtYXgoSF9Db3NlY2hhZGEsIG5hLnJtID0gVFJVRSkpICU+JQ0KICAgIHNsaWNlKHdoaWNoLm1heChtYXhfSF9Db3NlY2hhZGEpKSAtPiBIX2Nvc2VjaGFfbWF4DQoNCkhfY29zZWNoYV9tYXgNCmBgYA0KDQojNC4NClBhcmEgZXN0YSBudWV2YSB2aXN1YWxpemFjaW9uLCByZWFsaXphcmVtb3MgdW4gZmlsdHJvIGRlIGxvcyBkYXRvcyBkb25kZSBxdWUgbXVuaWNpcGlvIHR1dm8gdW5hIG1heW9yIGFyZWEgY29zZWNoYWRhIHBhcmEgY2FkYSBncnVwbyBkZSBjdWx0aXZvLCBvYnNlcnZhbmRvIHF1ZSBoYXkgbXVuaWNpcGlvcyBxdWUgZGVzdGluYW4gdW5hIGdyYW4gc3VwZXJmaWNpZSBwYXJhIGVsIHRlbWEgYWdyaWNvbGENCg0KYGBge3J9DQpkYXRvcyAlPiUgZmlsdGVyKEdSVVBPPT0iT1RST1MgUEVSTUFORU5URVMiKSAlPiUgDQogIGdyb3VwX2J5KE1VTklDSVBJTywgU1VCR1JVUE89IkNBQ0FPIikgJT4lIA0KICBzdW1tYXJpc2UgKG1heF9QUk9EPW1heChQUk9EVUNDSU9OLCBuYS5ybSA9IFRSVUUpKSAlPiUgc2xpY2Uod2hpY2gubWF4KG1heF9QUk9EKSktPlBST0RfbWF4DQpQUk9EX21heA0KYGBgDQpBcXVpIHJlYWxpemFtb3MgdW4gZmlsdHJvIGRlIGxvcyBkYXRvcyBwYXJhIGV4cGxvcmFyIGVsIGdydXBvIGRlIGN1bHRpdm8gT3Ryb3MgcGVybWFuZW50ZXMgcGFyYSB2ZXIgcXVlIGN1YWwgZnVlIGxhIG1heGltYSBwcm9kdWNjaW9uIGRlIGVzdG9zIGN1bHRpdm9zIGRlbnRybyBkZWwgdGllbXBvIHF1ZSBjdWJyZW4gbG9zIGRhdG9zDQoNCg0KYGBge3J9DQpkYXRvcyAlPiUgDQogIGZpbHRlcihNVU5JQ0lQSU89PSJGTE9SRU5DSUEiICYgU1VCR1JVUE89PSJDQUNBTyIpICU+JSANCiAgZ3JvdXBfYnkoWUVBUiwgQ1VMVElWTykgLT4gIFZJQ0VOX0NBQ0FPDQpWSUNFTl9DQUNBTw0KYGBgDQoNClBhcmEgdmVyIGVzdG9zIGRhdG9zIGRlIHVuYSBmb3JtYSBncmFmaWNhLCBub3MgYXByb3ZlY2hhcmVtb3MgZGUgbGEgZnVuY2lvbiBnZ3Bsb3QgcGFyYSB2cmxvcyBkZSBmb3JtYSBncmFmaWNhIHkgYW5hbGl6YXJsb3MgZGUgbWVqb3IgbWFuZXJhLCBkb25kZSBvYnNlcnZhbW9zIHF1ZSBlbCBhw7FvIGRlIG1heW9yIHByb2R1Y2Npb24gZW4gZWwgbXVuaWNpcGlvIGZ1ZSBlbCAyMDEzIGxsZWdhbmRvIGEgbGFzIDIwMCB0b25lbGFkYXMgZW4gZXNlIGHDsW8NCg0KYGBge3J9DQpnIDwtIGdncGxvdChhZXMoeD1ZRUFSLCB5PVBST0RVQ0NJT04vMTAwKSwgZGF0YSA9IFZJQ0VOX0NBQ0FPKSArIGdlb21fYmFyKHN0YXQ9J2lkZW50aXR5JykgKyBsYWJzKHk9J0NhY2FvIFByb2R1Y3Rpb24gW1RvbiB4IDEwMDBdJykNCg0KZyArIGdndGl0bGUoIkV2b2x1dGlvbiBvZiBjYWNhbyBwcm9kdWN0aW9uIGluIEZMT1JFTkNJQSBmcm9tIDIwMTMgdG8gMjAxOCIpICsgbGFicyhjYXB0aW9uPSAiQmFzZWQgb24gRU1BIGRhdGEgKERBTkUsIDIwMTgpIikNCmBgYA0KDQpSZWFsaXphbW9zIG90cmEgY29uc3VsdGEsIGVzdGEgdmV6IHBhcmEgb2JzZXJ2YXIgbGEgc3VwZXJmaWNpZSBjb3NlY2hhZGEgdG90YWwgcG9yIGNhZGEgZ3J1cG8gZGUgY3VsdGl2byBlbiBlbCBhw7FvIDIwMTgsIGRvbmRlIHNlIG9ic2VydmEgcXVlIGxvcyBjdWx0aXZvcyBPdHJvcyBQZXJtYW5lbnRlcyBkZXRhY2FuIGFtcGxpYW1lbnRlIHNvYnJlIGVsIHJlc3RvDQoNCmBgYHtyfQ0KZGF0b3MgJT4lIA0KICBmaWx0ZXIoWUVBUj09Mi4wMTgpICU+JSANCiAgZ3JvdXBfYnkoR1JVUE8pICU+JQ0KICBzdW1tYXJpemUoc3VtX0hfQ29zZWNoYWRhID0gc3VtKEhfQ29zZWNoYWRhLCBuYS5ybSA9IFRSVUUpKSAlPiUNCiAgICAgYXJyYW5nZShkZXNjKHN1bV9IX0Nvc2VjaGFkYSkpIC0+IHRvdGFsX2FyZWFfY29zZWNoYQ0KDQp0b3RhbF9hcmVhX2Nvc2VjaGENCmBgYA0KQmFzYWRvcyBlbiBsbyBhbnRlcmlvciwgdmFtb3MgYSByZWFsaXphciB1biBmaWx0cm8gc29icmUgZWwgbWlzbW8gYcOxbywgcGVybyB0b21hbmRvIHNvbG8gbG9zIGN1bHRpdm9zIG90cm9zIHBlcm1hbmVudGVzLCBlc3RvIHBhcmEgdmVyIGN1YWwgY3VsdGl2byBlbiBlc3BlY2lmaWNvIGVzIGVsIHF1ZSBwcmVkb21pbmEgcmVzcGVjdG8gYWwgYXJlYSBjb3NlY2hhZGEgZW4gZWwgZGVwYXJ0YW1lbnRvDQoNCg0KYGBge3J9DQpkYXRvcyAlPiUNCiAgZmlsdGVyKEdSVVBPPT0iT1RST1MgUEVSTUFORU5URVMiICYgWUVBUj09Mi4wMTgpICU+JQ0KICBncm91cF9ieShDVUxUSVZPKSAlPiUNCiAgc3VtbWFyaXplKHN1bV9jb3NlY2hhID0gc3VtKEhfQ29zZWNoYWRhLCBuYS5ybSA9IFRSVUUpKSAlPiUNCiAgICAgYXJyYW5nZShkZXNjKHN1bV9jb3NlY2hhKSkgLT4gdG90YWxfY29zZWNoYQ0KDQoNCnRvdGFsX2Nvc2VjaGENCmBgYA0KDQpBaG9yYSBxdWUgeWEgc2FiZW1vcyBxdWUgbGEgY2HDsWEgcGFuYWxlcmEgZXMgZWwgY3VsdGl2byAgZGUgbWF5b3IgYXJlYSBjb3NlY2hhZGEsIGNvbiBlc3RlIG51ZXZvIGZpbHRybyB2ZXJlbW9zIHF1ZSBtdW5pY2lwaW8gcHJlc2VudGEgdW5hIG1heW9yIGFyZWEgY29zZWNoYWRhIGRlIGNhw7FhIHBhbmVsZXJhIGVuIGVsIGHDsW8gMjAxOC4NCg0KYGBge3J9DQpkYXRvcyAlPiUgDQogIGZpbHRlcihZRUFSPT0yLjAxOCAmIEdSVVBPPT0iT1RST1MgUEVSTUFORU5URVMiKSAlPiUgDQogIGdyb3VwX2J5KENVTFRJVk8sIE1VTklDSVBJTykgJT4lDQogIHN1bW1hcml6ZShtYXhfYXJlYTIgPSBtYXgoSF9Db3NlY2hhZGEsIG5hLnJtID0gVFJVRSkpICU+JQ0KICAgIHNsaWNlKHdoaWNoLm1heChtYXhfYXJlYTIpKSAtPiBhcmVhX2Nvc2VjaGEyDQoNCmFyZWFfY29zZWNoYTINCmBgYA0KDQoNCg0KDQphbnRlcyBkZSByZWFsaXphciBlbCBwbG90ZW8sIGEgY2FkYSB1bmEgZGUgbGFzIGNsYXNlcywgcXVlIHNlcmFuIGxvcyBncnVwb3MgZGUgY3VsdGl2bywgdmFtb3MgYSByZWFsaXphcmxlcyB1bmEgYWJyZXZpYXR1cmEsIHBhcmEgcXVlIHNlIHB1ZWRhIGxlZXIgY29uIGNsYXJpZGFkIGVuIGVsIHBsb3Rlbw0KDQpgYGB7cn0NCnRvdGFsX2FyZWFfY29zZWNoYSRDUk9QIDwtIGFiYnJldmlhdGUodG90YWxfYXJlYV9jb3NlY2hhJEdSVVBPLCAzKQ0KDQoNCmBgYA0KDQpgYGB7cn0NCmcgPC0gZ2dwbG90KGFlcyh4PUNST1AsIHk9c3VtX0hfQ29zZWNoYWRhKSwgZGF0YSA9IHRvdGFsX2FyZWFfY29zZWNoYSkgKyBnZW9tX2JhcihzdGF0PSdpZGVudGl0eScpICsgbGFicyh5PSdUb3RhbCBIYXJ2ZXN0ZWQgQXJlYSBbSGFdJykNCmBgYA0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpDQpgYGANCmcrIGdndGl0bGUoIlRvdGFsIGhhcnZlc3RlZCBhcmVhIGJ5IGNyb3AgZ3JvdXBzIGluIDIwMTggZm9yIEZMT1JFTkNJQSIpICsgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpICsNCiAgIGxhYnMoY2FwdGlvbj0gIkJhc2VkIG9uIEVNQSBkYXRhIChEQU5FLCAyMDE4KSIpDQoNCmBgYHtyfQ0KZysgZ2d0aXRsZSgiVG90YWwgaGFydmVzdGVkIGFyZWEgYnkgY3JvcCBncm91cHMgaW4gMjAxOCBmb3IgQ2FxdWV0YSIpICsgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpICsNCiAgIGxhYnMoY2FwdGlvbj0gIkJhc2VkIG9uIEVNQSBkYXRhIChEQU5FLCAyMDE4KSIpDQoNCiAgDQpgYGANCg0KIzUuDQpMYSBzZWd1bmRhIHBhcnRlIGRlbCBpbmZvcm1lIGNvbnNpc3RpcmEgZW4gcmVhbGl6YXIgdW5hIHVuaW9uIGVudHJlIGxvcyBkYXRvcyBubyBlc3BhY2lsYWVzIG1vc3RyYWRvcyBlbiBsYSBwcmltZXJhcGFydGUgeSB1biBhcmNoaXZvIGRlIGRhdG9zIGVzcGFjaWFsZXMgcHJvdmVuaWVudGUgZGVsIG1hcmNvIGdlb2VzdGFkaXN0aWNvIGRlbCBwYWlzIHByb3ZlbmluZXRvIGRlbCBEQU5FDQoNCg0KYGBge3J9DQphbnRfbXVuaWMgPC0gc2Y6OnN0X3JlYWQoImQ6L1VzZXJzL0phbnVzL0RvY3VtZW50cy9HZW9tYXRpY2EgYmFzaWNhLzE4X0NBUVVFVEEvQURNSU5JU1RSQVRJVk8vTUdOX01QSU9fUE9MSVRJQ08uc2hwIikNCmBgYA0KYGBge3J9DQphbnRfbXVuaWMNCmBgYA0KUGFyYSByZWFsaXphciBlbCBqb2luIG5lY2VzaXRhbW9zIHVuIGNhbXBvIGVuIGNvbXVuIGVudHJlIGFtYm9zIHBhcXVldGVzIGRlIGRhdG9zLCBwb3IgbG8gcXVlIHVzYXJlbW9zIGVsIGNvZGlnbyBkZSBtdW5pY2lwaW8gcGFyYSBlbGxvLCBlc3RhcyBkb3MgbGluZWFzIG5vcyBzZXJ2aXJhbiBwYXJhIGNyZWFyIGRvcyBjYW1wb3MgbnVldm9zIGEgbG9zIGRhdG9zIG5vIGVzcGFjaWFsZXMsIGNvbmVsIG9iamV0aXZvIGRlIGNvbnZlcnRpciBsYSBjb2x1bW5hIENPRF9NVU4gcXVlIGVzIHVuIG9iamV0byBkZSB0aXBvIG51bWVyaWNvIGEgdW4gb2JqZXRvIGRlIHRpcG8gZmFjdG9yLCBjb3NhIGZ1bmRhbWVudGFsIHBhcmEgcmVhbGl6YXIgZWwgam9pbg0KDQpgYGB7cn0NCmRhdG9zICU+JSBmaWx0ZXIgKE1VTklDSVBJTyA9PSJGTE9SRU5DSUEiKSAtPiAgY2FxX2RhdG9zDQoNCmBgYA0KYGBge3J9DQpjYXFfZGF0b3MNCmBgYA0KDQpgYGB7cn0NCmNsYXNzKGNhcV9kYXRvcyRDT0RfTVVOKQ0KDQpgYGANCmBgYHtyfQ0KZGF0b3MyIDwtIGRhdG9zDQoNCmBgYA0KYGBge3J9DQpkYXRvczIkVEVNUCA8LSAgYXMuY2hhcmFjdGVyKGRhdG9zMiRDT0RfTVVOKQ0KDQpgYGANCmBgYHtyfQ0KZGF0b3MyJE1QSU9fQ0NER08gPC0gYXMuZmFjdG9yKHBhc3RlKDAsIGRhdG9zMiRURU1QLCBzZXA9IiIpKQ0KDQpgYGANCmBgYHtyfQ0KaGVhZChkYXRvczIpDQoNCmBgYA0KDQpQYXJhIHBvZGVyIGhhY2VyIGxhIHVuacOzbiwgbmVjZXNpdGFtb3MgY2FtYmlhciB0YW50byBlbCB0aXBvIGRlIGRhdG9zIGNvbW8gZWwgY29udGVuaWRvIGRlbCBjw7NkaWdvIHF1ZSBpZGVudGlmaWNhIGEgY2FkYSBtdW5pY2lwaW8uIFBhcmEgZXN0YSB0YXJlYSwgZXMgdW5hIGJ1ZW5hIGlkZWEgY3JlYXIgdW5hIGNvcGlhIGRlIGxvcyBkYXRvcyBlc3RhZMOtc3RpY29zIG9yaWdpbmFsZXMuIENvbiBlc3RlIGVuZm9xdWUsIGN1YWxxdWllciBtb3ZpbWllbnRvIGZhbHNvIG5vIGVzdHJvcGVhcsOhIGxvcyBkYXRvcyBvcmlnaW5hbGVzLg0KDQoNCmBgYHtyfQ0KZGF0b3MyICU+JSBmaWx0ZXIoQ1VMVElWTyA9PSAiQ0FDQU8iKSAgLT4gZGF0b3MzDQoNCmBgYA0KYGBge3J9DQpoZWFkKGRhdG9zMykNCg0KYGBgDQoNCmBgYHtyfQ0KY2xhc3MoZGF0b3MzKQ0KDQpgYGANCg0KYGBge3J9DQpkYXRvczQgPC0gZGF0b3MzICU+JSBkcGx5cjo6c2VsZWN0KE1VTklDSVBJTywgTVBJT19DQ0RHTywgWUVBUiwgUFJPRFVDQ0lPTiwgUkVOKSANCg0KYGBgDQpgYGB7cn0NCmRhdG9zNA0KDQpgYGANCg0KYGBge3J9DQpkYXRvczQgJT4lIA0KICBnYXRoZXIoIllFQVIiLCAiUFJPRFVDQ0lPTiIsICJSRU4iICwga2V5ID0gdmFyaWFibGUsIHZhbHVlID0gbnVtYmVyKQ0KYGBgDQpgYGB7cn0NCmhlYWQoZGF0b3M0KQ0KDQpgYGANCsOJc3RhICB0YXJlYSBlcyBjbGF2ZS4gSW1wbGljYSB2YXJpb3MgcGFzb3MgcGFyYSBwb2RlciBjb252ZXJ0aXIgbGEgdGFibGEgZGUgYXRyaWJ1dG9zIGRlIGZvcm1hdG8gbGFyZ28gYSBmb3JtYXRvIGFuY2hvLg0KDQpgYGB7cn0NCmRhdG9zNCAlPiUgDQogIGdyb3VwX2J5KE1QSU9fQ0NER08pICU+JSANCiAgbXV0YXRlKFZpc2l0ID0gMTpuKCkpICU+JSANCiAgZ2F0aGVyKCJZRUFSIiwgIlBST0RVQ0NJT04iLCAiUkVOIiwga2V5ID0gdmFyaWFibGUsIHZhbHVlID0gbnVtYmVyKSAlPiUgDQogIHVuaXRlKGNvbWJpLCB2YXJpYWJsZSwgVmlzaXQpICU+JQ0KICBzcHJlYWQoY29tYmksIG51bWJlcikgLT4gZGF0b3M1DQpgYGANCmBgYHtyfQ0KaGVhZChkYXRvczUpDQoNCmBgYA0KYGBge3J9DQp0YWlsKGRhdG9zNSkNCg0KYGBgDQpSZWFsaXphbW9zIHVuYSBjb3BpYSBkZSBsYSBjb2xlY2Npw7NuIGRlIGNhcmFjdGVyw61zdGljYXMgc2ltcGxlcw0KDQpgYGB7cn0NCmFudF9tdW5pYzIgPC0gYW50X211bmljDQoNCmBgYA0KYGBge3J9DQphbnRfbXVuaWNfc3RhdCA9IGxlZnRfam9pbihhbnRfbXVuaWMyLCBkYXRvczUsIGJ5PSJNUElPX0NDREdPIikNCmBgYA0KYGBge3J9DQpzdW1tYXJ5KGFudF9tdW5pY19zdGF0KQ0KDQpgYGANCiM2LiANCkludGFsYW1vcyBsYXMgbGlicmVyaWFzIG5lY2VzYXJpYXMgcGFyYSBQbG90ZWFyIA0KDQpgYGB7cn0NCmxpYnJhcnkoUkNvbG9yQnJld2VyKQ0KbGlicmFyeShsZWFmbGV0KQ0KYGBgDQpFc3RhIGluc3RydWNjaW9uIG5vcyBwZXJtaXRlIHZlciBlbiB1biBtYXBhIGRlbCBkZXBhcnRhbWVudG8gbG9zIHZhbG9yZXMgZGUgcHJvZHVjY2lvbiBkZSBjYWRhIGRlcGFydGFtZW50ZSBlbiB1biBhw7FvIGVzcGVjaWZpY28NCg0KYGBge3J9DQpiaW5zIDwtIGMoMCwgMjUwLCA1MDAsIDEwMDAsIDIwMDAsIDUwMDAsIDEwMDAwLCAxNTAwMCkNCnBhbCA8LSBjb2xvckJpbigiWWxPclJkIiwgZG9tYWluID0gYW50X211bmljX3N0YXQkUFJPRFVDQ0lPTl8xMiwgYmlucyA9IGJpbnMpDQoNCiAgbWFwYSA8LSBsZWFmbGV0KGRhdGEgPSBhbnRfbXVuaWNfc3RhdCkgJT4lDQogIGFkZFRpbGVzKCkgJT4lDQogIGFkZFBvbHlnb25zKGxhYmVsID0gflBST0RVQ0NJT05fMTIsDQogICAgICAgICAgICAgIHBvcHVwID0gfk1QSU9fQ05NQlIsDQogICAgICAgICAgICAgIGZpbGxDb2xvciA9IH5wYWwoUFJPRFVDQ0lPTl8xMiksDQogICAgICAgICAgICAgIGNvbG9yID0gIiM0NDQ0NDQiLA0KICAgICAgICAgICAgICB3ZWlnaHQgPSAxLA0KICAgICAgICAgICAgICBzbW9vdGhGYWN0b3IgPSAwLjUsDQogICAgICAgICAgICAgIG9wYWNpdHkgPSAxLjAsDQogICAgICAgICAgICAgIGZpbGxPcGFjaXR5ID0gMC41LA0KICAgICAgICAgICAgICBoaWdobGlnaHRPcHRpb25zID0gaGlnaGxpZ2h0T3B0aW9ucyhjb2xvciA9ICJ3aGl0ZSIsIHdlaWdodCA9IDIsIGJyaW5nVG9Gcm9udCA9IFRSVUUpDQogICAgICAgICAgICAgICkgJT4lDQogIGFkZFByb3ZpZGVyVGlsZXMocHJvdmlkZXJzJE9wZW5TdHJlZXRNYXApICU+JQ0KICBhZGRMZWdlbmQoImJvdHRvbXJpZ2h0IiwgcGFsID0gcGFsLCB2YWx1ZXMgPSB+UFJPRFVDQ0lPTl8xMiwNCiAgICB0aXRsZSA9ICJDQUNBTyBwcm9kdWN0aW9uIGluIENhcXVldGEgW1Rvbl0gKDIwMTgpIiwNCiAgICBvcGFjaXR5ID0gMQ0KICApDQpgYGANCiM3Lg0KRXN0ZSBlcyByZXN1bHRhZG8gZGUgbnVlc3RybyBtYXBhIGRlIGN1bHRpdm8gZGUgQ0FDQU8gZW4gQ2FxdWV0YQ0KDQpgYGB7cn0NCm1hcGENCmBgYA0KDQo=