1. Introducción

Este cuaderno , correspone al anexo número dos del informe final correspondiente a la asignatura geomÔtica bÔsica .En el se ilustra el método de interpolación con polígonos de thiessen para los datos de precipitación en el Departameno de Vichada

3. Preprocesamiento de datos

Los puntos correspondientes a los datos de precipitación en el departamento de Vichada , fueron obtenidos y almacenados en un archivo geojson.Ahora , usando la función geojson_read() , se leen estos puntos

(precip.points <- geojsonio::geojson_read("./chirps/ppoints.geojson", what="sp"))
class       : SpatialPointsDataFrame 
features    : 3248 
extent      : -71.075, -67.475, 2.774999, 6.274999  (xmin, xmax, ymin, ymax)
crs         : +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0 
variables   : 1
names       :            lluvia 
min values  : 0.541795015335083 
max values  :  85.8214721679688 
There were 24 warnings (use warnings() to see them)

Se lee de nuevo el archivo shapefile correspondiente al Ɣrea de estudio

(Vichada <- shapefile("./ADMINISTRATIVO/MGN_MPIO_POLITICO.shp"))
class       : SpatialPolygonsDataFrame 
features    : 4 
extent      : -71.07793, -67.4098, 2.737109, 6.324317  (xmin, xmax, ymin, ymax)
crs         : +proj=longlat +datum=WGS84 +no_defs  
variables   : 9
names       : DPTO_CCDGO, MPIO_CCDGO,    MPIO_CNMBR,                           MPIO_CRSLC,    MPIO_NAREA, MPIO_NANO, DPTO_CNMBR,    Shape_Leng,     Shape_Area 
min values  :         99,      99001,      CUMARIBO,       Decreto 1594 de Ago 5  de 1974, 3898.56891769,      2017,    VICHADA, 3.29670807195, 0.316732435778 
max values  :         99,      99773, SANTA ROSALƍA, Ordenanza 66 de Noviembre 22 de 1996, 65599.7022767,      2017,    VICHADA,  18.794382661,   5.3085802966 

Posteriormente, se convierte a un objeto sf empleando la función st_as_sf y se disuelven los límites internos como se ilustra en el siguiente código

Vichada_sf <-  sf::st_as_sf(Vichada)
(border_sf <- Vichada_sf %>%summarise(area = sum(MPIO_NAREA)))
Simple feature collection with 1 feature and 1 field
geometry type:  POLYGON
dimension:      XY
bbox:           xmin: -71.07793 ymin: 2.737109 xmax: -67.4098 ymax: 6.324317
CRS:            +proj=longlat +datum=WGS84 +no_defs 
      area                       geometry
1 100065.9 POLYGON ((-67.814 5.342584,...

Se convierte el objeto sf a un Dataframe Espacial . En este caso, se refiere a un polĆ­gono que contiene atributos

 (border <- as(border_sf, 'Spatial')) 
class       : SpatialPolygonsDataFrame 
features    : 1 
extent      : -71.07793, -67.4098, 2.737109, 6.324317  (xmin, xmax, ymin, ymax)
crs         : +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0 
variables   : 1
names       :            area 
value       : 100065.86486549 

Al objeto Vichadasf , se le agregan las nuevas columnas ā€œMUNICā€ y ā€œCODIGOā€ , que tienen el mismo contenido que ā€œMPIO_CNMBRā€ y ā€œMPIO_CCDGOā€ y debido a que estas nuevas columnas se agregan al final del conjunto de datos , se usa la función select() para que solo se vean estas variables en la salida del código

(Vichada.sf <- st_as_sf(Vichada) %>% mutate(MUNIC = MPIO_CNMBR, CODIGO = MPIO_CCDGO) %>% select(MUNIC, CODIGO))
Simple feature collection with 4 features and 2 fields
geometry type:  POLYGON
dimension:      XY
bbox:           xmin: -71.07793 ymin: 2.737109 xmax: -67.4098 ymax: 6.324317
CRS:            +proj=longlat +datum=WGS84 +no_defs 
           MUNIC CODIGO                       geometry
1  SANTA ROSALƍA  99624 POLYGON ((-70.65378 5.37297...
2 PUERTO CARREƑO  99001 POLYGON ((-67.80972 6.32431...
3   LA PRIMAVERA  99524 POLYGON ((-69.03359 6.21869...
4       CUMARIBO  99773 POLYGON ((-68.47074 5.55046...

Los puntos de datos de precipitación , también son convertidos a un objeto sf

p.sf <- st_as_sf(precip.points)

Usando la función st_intersect de la libreria sf, se realizarÔ una intersección de los polígonos con los puntos, manteniendo la información de los 2

(precip.sf = st_intersection(Vichada.sf, p.sf))
although coordinates are longitude/latitude, st_intersection assumes that they are planar
Simple feature collection with 3248 features and 3 fields
geometry type:  POINT
dimension:      XY
bbox:           xmin: -71.075 ymin: 2.774999 xmax: -67.475 ymax: 6.274999
CRS:            +proj=longlat +datum=WGS84 +no_defs 
First 10 features:
             MUNIC CODIGO    lluvia                 geometry
2   PUERTO CARREƑO  99001 0.8161542 POINT (-67.875 6.274999)
2.1 PUERTO CARREƑO  99001 0.8258479 POINT (-67.825 6.274999)
2.2 PUERTO CARREƑO  99001 0.8074083 POINT (-67.775 6.274999)
2.3 PUERTO CARREƑO  99001 0.8239177 POINT (-67.725 6.274999)
2.4 PUERTO CARREƑO  99001 0.7755996 POINT (-67.675 6.274999)
2.5 PUERTO CARREƑO  99001 0.7823746 POINT (-67.625 6.274999)
2.6 PUERTO CARREƑO  99001 3.5164738 POINT (-68.125 6.224999)
2.7 PUERTO CARREƑO  99001 3.2473364 POINT (-68.075 6.224999)
2.8 PUERTO CARREƑO  99001 0.7987307 POINT (-67.925 6.224999)
2.9 PUERTO CARREƑO  99001 0.7961798 POINT (-67.875 6.224999)

Se realiza una tarea de reproyección en los 2 objetos

p.sf.magna <- st_transform(precip.sf, crs=3116)
Vichada.sf.magna <- st_transform(Vichada.sf, crs=3116)

Luego, se hace una conversión del objeto ā€œp.sf.magmaā€

(precip2 <- as(p.sf.magna, 'Spatial'))
class       : SpatialPointsDataFrame 
features    : 3248 
extent      : 1333188, 1732620, 799126.6, 1190067  (xmin, xmax, ymin, ymax)
CRS object has comment, which is lost in output
crs         : +proj=tmerc +lat_0=4.596200416666666 +lon_0=-74.07750791666666 +k=1 +x_0=1000000 +y_0=1000000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs 
variables   : 3
names       :         MUNIC, CODIGO,            lluvia 
min values  :      CUMARIBO,  99001, 0.541795015335083 
max values  : SANTA ROSALƍA,  99773,  85.8214721679688 

Se puede guardar el conjunto de datos en la carpeta chirps del directorio de trabajo para que pueda ser usado de forma posterior

shapefile(precip2, filename='./chirps/precip2.shp', overwrite=TRUE)

Ahora, se aproximan los valores que toma la variable ā€œlluviaā€ a un decimal.A la columna que tiene estos valores redondeados, se le asignarĆ” el nombre ā€œprecipitaciónā€

precip2$precipitacion <- round(precip2$lluvia, 1)
precip2
class       : SpatialPointsDataFrame 
features    : 3248 
extent      : 1333188, 1732620, 799126.6, 1190067  (xmin, xmax, ymin, ymax)
CRS object has comment, which is lost in output
crs         : +proj=tmerc +lat_0=4.596200416666666 +lon_0=-74.07750791666666 +k=1 +x_0=1000000 +y_0=1000000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs 
variables   : 4
names       :         MUNIC, CODIGO,            lluvia, precipitacion 
min values  :      CUMARIBO,  99001, 0.541795015335083,           0.5 
max values  : SANTA ROSALƍA,  99773,  85.8214721679688,          85.8 

El se realiza una conversión al objeto sf (ā€œVichada.sf.magmaā€) ,

(Vichada2 <- as(Vichada.sf.magna, 'Spatial'))
class       : SpatialPolygonsDataFrame 
features    : 4 
extent      : 1332850, 1739856, 794950.2, 1195302  (xmin, xmax, ymin, ymax)
CRS object has comment, which is lost in output
crs         : +proj=tmerc +lat_0=4.596200416666666 +lon_0=-74.07750791666666 +k=1 +x_0=1000000 +y_0=1000000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs 
variables   : 2
names       :         MUNIC, CODIGO 
min values  :      CUMARIBO,  99001 
max values  : SANTA ROSALƍA,  99773 
shapefile(Vichada2, filename='./chirps/Vichada2.shp', overwrite=TRUE)

Para asegurarse de que las dos extensiones coincidan se reemplaza la extensión del lĆ­mite de los puntos con la del nuevo objeto ā€œVichada 2ā€

precip2@bbox <- Vichada2@bbox

Se plotean los datos obtenidos luego del preprocesamiento

tm_shape(Vichada2) + tm_polygons() +tm_shape(precip2) +tm_dots(col="precipitacion", palette = "RdBu", midpoint = 42, title="Muestras de precipitacion \n(mm)", size=0.08) + tm_legend(legend.outside=TRUE)

4.Interpolación con polígonos de Thiessen

Se representa el patron de puntos bidimensionales como formato ppp para que se pueda usar la función dirichlet() de la libreria spatstat .Esta función es la que permite crear la superficie teselada de los polígonos de Thiessen , la superficie generada no tiene información de proyección por tanto, también se añade de forma manual

th  <-  as(dirichlet(as.ppp(precip2)), "SpatialPolygons")
crs(th) <- crs(precip2)
crs(Vichada2) <- crs(precip2)

Como , no almacena información de atributos de la capa de puntos. se usa la función over() (del paquete sp) para unir los atributos del punto a la superficie mediante una unión espacial. Posteriormente , se recorta la superficie al tamaño del departamento

th.z     <- over(th, precip2, fn=mean)
th.spdf  <-  SpatialPolygonsDataFrame(th, th.z)
th.clp   <- raster::intersect(Vichada2,th.spdf)

Ahora, se plotea la superficie interpolada

tm_shape(th.clp) + tm_polygons(col="precipitacion", palette="RdBu", midpoint=43.0, title="Poligonos de Thiessen \n para precipitación \n(mm)") + tm_legend(legend.outside=TRUE,title.size=1.2, text.size= 0.8)

5.Otra forma de interpolación con poígonos de Thiessen

Con la función sample(),se toma una muestra aleatoria de la mitad los datos del objeto ā€œprecip2ā€ .Para obtener los datos de ā€œprecip2ā€ que no estĆ”n en la variable creada , se hace uso de la función setdiff()

train_index <- sample(1:nrow(precip2), 0.5 * nrow(precip2))
test_index <- setdiff(1:nrow(precip2), train_index)
ptos_train <- precip2[train_index, ]
ptos_test  <- precip2[test_index,]

Se crea un mapa que permite de la visualización de los 2 conjuntos de datos con ayuda de las librerias leaflet, htmltools y leaflet.extras

# Se agrega la capa rÔster de datos de precipitación 
lplot <- leaflet(data = precip2) %>% addProviderTiles("CartoDB.Positron") %>% addRasterImage(precip.mask, colors = pal, opacity = 0.6, project=FALSE) %>% 
# Se agrega el primer conjunto de datos
addCircleMarkers(data = ptrain, radius = 1, fillOpacity = .7, stroke = FALSE, popup = ~htmlEscape(precipitacion), color = pal(ptos_train$precipitacion), clusterOptions = markerClusterOptions(),group = "Training") %>% 
# Se agrega el segundo conjunto de datos  
addCircleMarkers(data = ptest, radius = 10, fillOpacity = .7, stroke = FALSE, popup = ~htmlEscape(precipitacion), color = pal(ptos_test$precipitacion), clusterOptions = markerClusterOptions(), group = "Test") %>% 
# Se ajustan las opciones de la leyenda y las opciones para activar o desactivar las capas  
addLegend(position = "bottomright",values = ~precipitacion, opacity = .7, pal = pal, title = "Precipitacion") %>% leaflet::addLayersControl(overlayGroups = c("Training", "Test"), options = layersControlOptions(collapsed = FALSE)) %>% addResetMapButton()
lplot

Se reproyectan los datos seleccionados

ptrain <- spTransform(ptos_train, crs(precip.mask))
ptest <- spTransform(ptos_test, crs(precip.mask))

Se crea la superficie teselada , luego de convertir los datos a formato ppp

thiessen  <-  as(dirichlet(as.ppp(ptos_train)), "SpatialPolygons")

Se añade la información de proyección

crs(thiessen) <- crs(ptos_train)
crs(Vichada2) <- crs(ptos_train)

Se unen los atributos a la superficie teselada

thiessen.z     <- over(thiessen, ptos_train, fn=mean)
thiessen.spdf  <-  SpatialPolygonsDataFrame(thiessen, thiessen.z)

Se recortan la superficie al tamaƱo de la zona de interƩs

thiessen.clp   <- raster::intersect(Vichada2,thiessen.spdf)

Se plotean los polĆ­gonos de thiessen obtenidos para el departamento de Vichada

tm_shape(thiessen.clp) + tm_polygons(col="precipitacion", palette="RdBu" , midpoint=43.0, title="Poligonos de Thiessen \npara precipitación \n(mm)") + tm_legend(legend.outside=TRUE, title.size=1.2, text.size= 0.8)

LS0tCnRpdGxlOiAiSW50ZXJwb2xhY2nDs24gcG9saWdvbm9zIGRlIFRoaWVzc2VuIHBhcmEgZGF0b3MgZGUgcHJlY2lwaXRhY2nDs24gZW4gVmljaGFkYSIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKPGRpdiBzdHlsZT0idGV4dC1hbGlnbjoganVzdGlmeSI+CgojIyMgMS4gSW50cm9kdWNjacOzbgoKRXN0ZSBjdWFkZXJubyAsIGNvcnJlc3BvbmUgYWwgYW5leG8gbsO6bWVybyBkb3MgZGVsIGluZm9ybWUgZmluYWwgY29ycmVzcG9uZGllbnRlIGEgbGEgYXNpZ25hdHVyYSBnZW9tw6F0aWNhIGLDoXNpY2EgLkVuIGVsIHNlIGlsdXN0cmEgZWwgbcOpdG9kbyBkZSBpbnRlcnBvbGFjacOzbiBjb24gcG9sw61nb25vcyBkZSB0aGllc3NlbiBwYXJhIGxvcyBkYXRvcyBkZSBwcmVjaXBpdGFjacOzbiBlbiBlbCBEZXBhcnRhbWVubyBkZSBWaWNoYWRhCgoKIyMjIDMuIFByZXByb2Nlc2FtaWVudG8gZGUgZGF0b3MgCkxvcyBwdW50b3MgY29ycmVzcG9uZGllbnRlcyBhICBsb3MgZGF0b3MgZGUgcHJlY2lwaXRhY2nDs24gZW4gZWwgZGVwYXJ0YW1lbnRvIGRlIFZpY2hhZGEgLCBmdWVyb24gb2J0ZW5pZG9zIHkgYWxtYWNlbmFkb3MgZW4gdW4gYXJjaGl2byBnZW9qc29uLkFob3JhICwgdXNhbmRvIGxhIGZ1bmNpw7NuIGdlb2pzb25fcmVhZCgpICwgc2UgbGVlbiBlc3RvcyBwdW50b3MKCjxkaXYvPgoKYGBge3Igd2FybmluZz1GQUxTRX0KKHByZWNpcC5wb2ludHMgPC0gZ2VvanNvbmlvOjpnZW9qc29uX3JlYWQoIi4vY2hpcnBzL3Bwb2ludHMuZ2VvanNvbiIsIHdoYXQ9InNwIikpCmBgYApTZSBsZWUgZGUgbnVldm8gZWwgYXJjaGl2byBzaGFwZWZpbGUgY29ycmVzcG9uZGllbnRlIGFsIMOhcmVhIGRlIGVzdHVkaW8KYGBge3J9CihWaWNoYWRhIDwtIHNoYXBlZmlsZSgiLi9BRE1JTklTVFJBVElWTy9NR05fTVBJT19QT0xJVElDTy5zaHAiKSkKYGBgClBvc3Rlcmlvcm1lbnRlLCBzZSBjb252aWVydGUgYSB1biBvYmpldG8gc2YgZW1wbGVhbmRvIGxhIGZ1bmNpw7NuIHN0X2FzX3NmIHkgc2UgZGlzdWVsdmVuIGxvcyBsw61taXRlcyBpbnRlcm5vcyBjb21vIHNlIGlsdXN0cmEgZW4gZWwgc2lndWllbnRlIGPDs2RpZ28KYGBge3J9ClZpY2hhZGFfc2YgPC0gIHNmOjpzdF9hc19zZihWaWNoYWRhKQooYm9yZGVyX3NmIDwtIFZpY2hhZGFfc2YgJT4lc3VtbWFyaXNlKGFyZWEgPSBzdW0oTVBJT19OQVJFQSkpKQpgYGAKU2UgY29udmllcnRlIGVsIG9iamV0byBzZiBhIHVuIERhdGFmcmFtZSBFc3BhY2lhbCAuIEVuIGVzdGUgY2Fzbywgc2UgcmVmaWVyZSBhIHVuIHBvbMOtZ29ubyBxdWUgY29udGllbmUgYXRyaWJ1dG9zCmBgYHtyIHdhcm5pbmc9RkFMU0V9CiAoYm9yZGVyIDwtIGFzKGJvcmRlcl9zZiwgJ1NwYXRpYWwnKSkgCmBgYApBbCBvYmpldG8gVmljaGFkYXNmICwgc2UgbGUgYWdyZWdhbiBsYXMgbnVldmFzIGNvbHVtbmFzICJNVU5JQyIgeSAiQ09ESUdPIiAsIHF1ZSB0aWVuZW4gZWwgbWlzbW8gY29udGVuaWRvIHF1ZSAiTVBJT19DTk1CUiIgeSAiTVBJT19DQ0RHTyIgeSBkZWJpZG8gYSBxdWUgZXN0YXMgbnVldmFzIGNvbHVtbmFzIHNlIGFncmVnYW4gYWwgZmluYWwgZGVsIGNvbmp1bnRvIGRlIGRhdG9zICwgc2UgdXNhIGxhIGZ1bmNpw7NuIHNlbGVjdCgpIHBhcmEgcXVlIHNvbG8gc2UgdmVhbiBlc3RhcyB2YXJpYWJsZXMgZW4gbGEgc2FsaWRhIGRlbCBjw7NkaWdvCmBgYHtyfQooVmljaGFkYS5zZiA8LSBzdF9hc19zZihWaWNoYWRhKSAlPiUgbXV0YXRlKE1VTklDID0gTVBJT19DTk1CUiwgQ09ESUdPID0gTVBJT19DQ0RHTykgJT4lIHNlbGVjdChNVU5JQywgQ09ESUdPKSkKYGBgCkxvcyBwdW50b3MgZGUgIGRhdG9zIGRlIHByZWNpcGl0YWNpw7NuICwgdGFtYmnDqW4gc29uIGNvbnZlcnRpZG9zIGEgdW4gb2JqZXRvIHNmCmBgYHtyIHdhcm5pbmc9RkFMU0V9CnAuc2YgPC0gc3RfYXNfc2YocHJlY2lwLnBvaW50cykKYGBgClVzYW5kbyBsYSBmdW5jacOzbiBzdF9pbnRlcnNlY3QgZGUgbGEgbGlicmVyaWEgc2YsIHNlIHJlYWxpemFyw6EgdW5hIGludGVyc2VjY2nDs24gZGUgbG9zIHBvbMOtZ29ub3MgY29uIGxvcyBwdW50b3MsIG1hbnRlbmllbmRvIGxhIGluZm9ybWFjacOzbiBkZSBsb3MgMgpgYGB7ciB3YXJuaW5nPUZBTFNFfQoocHJlY2lwLnNmID0gc3RfaW50ZXJzZWN0aW9uKFZpY2hhZGEuc2YsIHAuc2YpKQpgYGAKU2UgcmVhbGl6YSB1bmEgdGFyZWEgZGUgcmVwcm95ZWNjacOzbiBlbiBsb3MgMiBvYmpldG9zCmBgYHtyfQpwLnNmLm1hZ25hIDwtIHN0X3RyYW5zZm9ybShwcmVjaXAuc2YsIGNycz0zMTE2KQpWaWNoYWRhLnNmLm1hZ25hIDwtIHN0X3RyYW5zZm9ybShWaWNoYWRhLnNmLCBjcnM9MzExNikKYGBgCkx1ZWdvLCBzZSBoYWNlIHVuYSBjb252ZXJzacOzbiBkZWwgb2JqZXRvICJwLnNmLm1hZ21hIgpgYGB7cn0KKHByZWNpcDIgPC0gYXMocC5zZi5tYWduYSwgJ1NwYXRpYWwnKSkKYGBgClNlIHB1ZWRlIGd1YXJkYXIgZWwgY29uanVudG8gZGUgZGF0b3MgZW4gbGEgY2FycGV0YSBjaGlycHMgZGVsIGRpcmVjdG9yaW8gZGUgdHJhYmFqbyBwYXJhIHF1ZSBwdWVkYSBzZXIgdXNhZG8gZGUgZm9ybWEgcG9zdGVyaW9yCmBgYHtyfQpzaGFwZWZpbGUocHJlY2lwMiwgZmlsZW5hbWU9Jy4vY2hpcnBzL3ByZWNpcDIuc2hwJywgb3ZlcndyaXRlPVRSVUUpCmBgYApBaG9yYSwgc2UgYXByb3hpbWFuIGxvcyB2YWxvcmVzIHF1ZSB0b21hIGxhIHZhcmlhYmxlICJsbHV2aWEiIGEgdW4gZGVjaW1hbC5BIGxhIGNvbHVtbmEgcXVlIHRpZW5lIGVzdG9zIHZhbG9yZXMgcmVkb25kZWFkb3MsIHNlIGxlIGFzaWduYXLDoSBlbCBub21icmUgInByZWNpcGl0YWNpw7NuIgpgYGB7cn0KcHJlY2lwMiRwcmVjaXBpdGFjaW9uIDwtIHJvdW5kKHByZWNpcDIkbGx1dmlhLCAxKQpwcmVjaXAyCmBgYApFbCBzZSByZWFsaXphIHVuYSBjb252ZXJzacOzbiBhbCBvYmpldG8gc2YgKCJWaWNoYWRhLnNmLm1hZ21hIikgLCAKYGBge3J9CihWaWNoYWRhMiA8LSBhcyhWaWNoYWRhLnNmLm1hZ25hLCAnU3BhdGlhbCcpKQpzaGFwZWZpbGUoVmljaGFkYTIsIGZpbGVuYW1lPScuL2NoaXJwcy9WaWNoYWRhMi5zaHAnLCBvdmVyd3JpdGU9VFJVRSkKYGBgClBhcmEgYXNlZ3VyYXJzZSBkZSBxdWUgbGFzIGRvcyBleHRlbnNpb25lcyBjb2luY2lkYW4gc2UgcmVlbXBsYXphIGxhIGV4dGVuc2nDs24gZGVsIGzDrW1pdGUgZGUgbG9zIHB1bnRvcyBjb24gbGEgZGVsIG51ZXZvIG9iamV0byAiVmljaGFkYSAyIgpgYGB7cn0KcHJlY2lwMkBiYm94IDwtIFZpY2hhZGEyQGJib3gKYGBgClNlIHBsb3RlYW4gbG9zIGRhdG9zIG9idGVuaWRvcyBsdWVnbyBkZWwgcHJlcHJvY2VzYW1pZW50bwpgYGB7ciB3YXJuaW5nPUZBTFNFfQp0bV9zaGFwZShWaWNoYWRhMikgKyB0bV9wb2x5Z29ucygpICt0bV9zaGFwZShwcmVjaXAyKSArdG1fZG90cyhjb2w9InByZWNpcGl0YWNpb24iLCBwYWxldHRlID0gIlJkQnUiLCBtaWRwb2ludCA9IDQyLCB0aXRsZT0iTXVlc3RyYXMgZGUgcHJlY2lwaXRhY2lvbiBcbihtbSkiLCBzaXplPTAuMDgpICsgdG1fbGVnZW5kKGxlZ2VuZC5vdXRzaWRlPVRSVUUpCmBgYAojIyMgNC5JbnRlcnBvbGFjacOzbiBjb24gcG9sw61nb25vcyBkZSBUaGllc3NlbgpgYGB7ciBpbmNsdWRlPUZBTFNFfQpsaWJyYXJ5KHNwYXRzdGF0KQpsaWJyYXJ5KG1hcHRvb2xzKQpsaWJyYXJ5KHJhc3RlcikgICAgCmxpYnJhcnkoZGVsZGlyKQpgYGAKU2UgcmVwcmVzZW50YSBlbCBwYXRyb24gZGUgcHVudG9zIGJpZGltZW5zaW9uYWxlcyBjb21vIGZvcm1hdG8gcHBwIHBhcmEgcXVlIHNlIHB1ZWRhIHVzYXIgbGEgZnVuY2nDs24gZGlyaWNobGV0KCkgZGUgbGEgbGlicmVyaWEgc3BhdHN0YXQgLkVzdGEgZnVuY2nDs24gZXMgbGEgcXVlIHBlcm1pdGUgY3JlYXIgbGEgc3VwZXJmaWNpZSB0ZXNlbGFkYSBkZSBsb3MgcG9sw61nb25vcyBkZSBUaGllc3NlbiAsIGxhIHN1cGVyZmljaWUgZ2VuZXJhZGEgbm8gdGllbmUgaW5mb3JtYWNpw7NuIGRlIHByb3llY2Npw7NuIHBvciB0YW50bywgdGFtYmnDqW4gc2UgYcOxYWRlIGRlIGZvcm1hIG1hbnVhbCAgCmBgYHtyfQp0aCAgPC0gIGFzKGRpcmljaGxldChhcy5wcHAocHJlY2lwMikpLCAiU3BhdGlhbFBvbHlnb25zIikKY3JzKHRoKSA8LSBjcnMocHJlY2lwMikKY3JzKFZpY2hhZGEyKSA8LSBjcnMocHJlY2lwMikKYGBgCkNvbW8gLCAgbm8gYWxtYWNlbmEgaW5mb3JtYWNpw7NuIGRlIGF0cmlidXRvcyBkZSBsYSBjYXBhIGRlIHB1bnRvcy4gc2UgdXNhIGxhIGZ1bmNpw7NuIG92ZXIoKSAoZGVsIHBhcXVldGUgc3ApIHBhcmEgdW5pciBsb3MgYXRyaWJ1dG9zIGRlbCBwdW50byBhIGxhIHN1cGVyZmljaWUgbWVkaWFudGUgdW5hIHVuacOzbiBlc3BhY2lhbC4gUG9zdGVyaW9ybWVudGUgLCBzZSByZWNvcnRhIGxhIHN1cGVyZmljaWUgYWwgdGFtYcOxbyBkZWwgZGVwYXJ0YW1lbnRvCmBgYHtyfQp0aC56ICAgICA8LSBvdmVyKHRoLCBwcmVjaXAyLCBmbj1tZWFuKQp0aC5zcGRmICA8LSAgU3BhdGlhbFBvbHlnb25zRGF0YUZyYW1lKHRoLCB0aC56KQp0aC5jbHAgICA8LSByYXN0ZXI6OmludGVyc2VjdChWaWNoYWRhMix0aC5zcGRmKQpgYGAKQWhvcmEsIHNlIHBsb3RlYSBsYSBzdXBlcmZpY2llIGludGVycG9sYWRhCmBgYHtyfQp0bV9zaGFwZSh0aC5jbHApICsgdG1fcG9seWdvbnMoY29sPSJwcmVjaXBpdGFjaW9uIiwgcGFsZXR0ZT0iUmRCdSIsIG1pZHBvaW50PTQzLjAsIHRpdGxlPSJQb2xpZ29ub3MgZGUgVGhpZXNzZW4gXG4gcGFyYSBwcmVjaXBpdGFjacOzbiBcbihtbSkiKSArIHRtX2xlZ2VuZChsZWdlbmQub3V0c2lkZT1UUlVFLHRpdGxlLnNpemU9MS4yLCB0ZXh0LnNpemU9IDAuOCkKYGBgCiMjIyA1Lk90cmEgZm9ybWEgZGUgaW50ZXJwb2xhY2nDs24gY29uIHBvw61nb25vcyBkZSBUaGllc3NlbgpDb24gbGEgZnVuY2nDs24gc2FtcGxlKCksc2UgdG9tYSB1bmEgbXVlc3RyYSBhbGVhdG9yaWEgZGUgbGEgbWl0YWQgbG9zIGRhdG9zIGRlbCBvYmpldG8gInByZWNpcDIiIC5QYXJhIG9idGVuZXIgbG9zIGRhdG9zIGRlICJwcmVjaXAyIiBxdWUgbm8gZXN0w6FuIGVuIGxhIHZhcmlhYmxlIGNyZWFkYSAsIHNlIGhhY2UgdXNvIGRlIGxhIGZ1bmNpw7NuIHNldGRpZmYoKSAgCmBgYHtyfQp0cmFpbl9pbmRleCA8LSBzYW1wbGUoMTpucm93KHByZWNpcDIpLCAwLjUgKiBucm93KHByZWNpcDIpKQp0ZXN0X2luZGV4IDwtIHNldGRpZmYoMTpucm93KHByZWNpcDIpLCB0cmFpbl9pbmRleCkKcHRvc190cmFpbiA8LSBwcmVjaXAyW3RyYWluX2luZGV4LCBdCnB0b3NfdGVzdCAgPC0gcHJlY2lwMlt0ZXN0X2luZGV4LF0KYGBgClNlIGNyZWEgdW4gbWFwYSBxdWUgcGVybWl0ZSBkZSBsYSB2aXN1YWxpemFjacOzbiBkZSBsb3MgMiBjb25qdW50b3MgZGUgZGF0b3MgY29uIGF5dWRhIGRlIGxhcyBsaWJyZXJpYXMgIGxlYWZsZXQsIGh0bWx0b29scyB5IGxlYWZsZXQuZXh0cmFzCmBgYHtyIFdhcm5pbmc9RkFMU0V9CiMgU2UgYWdyZWdhIGxhIGNhcGEgcsOhc3RlciBkZSBkYXRvcyBkZSBwcmVjaXBpdGFjacOzbiAKbHBsb3QgPC0gbGVhZmxldChkYXRhID0gcHJlY2lwMikgJT4lIGFkZFByb3ZpZGVyVGlsZXMoIkNhcnRvREIuUG9zaXRyb24iKSAlPiUgYWRkUmFzdGVySW1hZ2UocHJlY2lwLm1hc2ssIGNvbG9ycyA9IHBhbCwgb3BhY2l0eSA9IDAuNiwgcHJvamVjdD1GQUxTRSkgJT4lIAojIFNlIGFncmVnYSBlbCBwcmltZXIgY29uanVudG8gZGUgZGF0b3MKYWRkQ2lyY2xlTWFya2VycyhkYXRhID0gcHRyYWluLCByYWRpdXMgPSAxLCBmaWxsT3BhY2l0eSA9IC43LCBzdHJva2UgPSBGQUxTRSwgcG9wdXAgPSB+aHRtbEVzY2FwZShwcmVjaXBpdGFjaW9uKSwgY29sb3IgPSBwYWwocHRvc190cmFpbiRwcmVjaXBpdGFjaW9uKSwgY2x1c3Rlck9wdGlvbnMgPSBtYXJrZXJDbHVzdGVyT3B0aW9ucygpLGdyb3VwID0gIlRyYWluaW5nIikgJT4lIAojIFNlIGFncmVnYSBlbCBzZWd1bmRvIGNvbmp1bnRvIGRlIGRhdG9zICAKYWRkQ2lyY2xlTWFya2VycyhkYXRhID0gcHRlc3QsIHJhZGl1cyA9IDEwLCBmaWxsT3BhY2l0eSA9IC43LCBzdHJva2UgPSBGQUxTRSwgcG9wdXAgPSB+aHRtbEVzY2FwZShwcmVjaXBpdGFjaW9uKSwgY29sb3IgPSBwYWwocHRvc190ZXN0JHByZWNpcGl0YWNpb24pLCBjbHVzdGVyT3B0aW9ucyA9IG1hcmtlckNsdXN0ZXJPcHRpb25zKCksIGdyb3VwID0gIlRlc3QiKSAlPiUgCiMgU2UgYWp1c3RhbiBsYXMgb3BjaW9uZXMgZGUgbGEgbGV5ZW5kYSB5IGxhcyBvcGNpb25lcyBwYXJhIGFjdGl2YXIgbyBkZXNhY3RpdmFyIGxhcyBjYXBhcyAgCmFkZExlZ2VuZChwb3NpdGlvbiA9ICJib3R0b21yaWdodCIsdmFsdWVzID0gfnByZWNpcGl0YWNpb24sIG9wYWNpdHkgPSAuNywgcGFsID0gcGFsLCB0aXRsZSA9ICJQcmVjaXBpdGFjaW9uIikgJT4lIGxlYWZsZXQ6OmFkZExheWVyc0NvbnRyb2wob3ZlcmxheUdyb3VwcyA9IGMoIlRyYWluaW5nIiwgIlRlc3QiKSwgb3B0aW9ucyA9IGxheWVyc0NvbnRyb2xPcHRpb25zKGNvbGxhcHNlZCA9IEZBTFNFKSkgJT4lIGFkZFJlc2V0TWFwQnV0dG9uKCkKYGBgCmBgYHtyfQpscGxvdApgYGAKClNlIHJlcHJveWVjdGFuIGxvcyBkYXRvcyBzZWxlY2Npb25hZG9zIApgYGB7cn0KcHRyYWluIDwtIHNwVHJhbnNmb3JtKHB0b3NfdHJhaW4sIGNycyhwcmVjaXAubWFzaykpCnB0ZXN0IDwtIHNwVHJhbnNmb3JtKHB0b3NfdGVzdCwgY3JzKHByZWNpcC5tYXNrKSkKYGBgClNlIGNyZWEgbGEgc3VwZXJmaWNpZSB0ZXNlbGFkYSAsIGx1ZWdvIGRlIGNvbnZlcnRpciBsb3MgZGF0b3MgYSBmb3JtYXRvIHBwcAoKYGBge3J9CnRoaWVzc2VuICA8LSAgYXMoZGlyaWNobGV0KGFzLnBwcChwdG9zX3RyYWluKSksICJTcGF0aWFsUG9seWdvbnMiKQpgYGAKU2UgYcOxYWRlIGxhIGluZm9ybWFjacOzbiBkZSBwcm95ZWNjacOzbgpgYGB7cn0KY3JzKHRoaWVzc2VuKSA8LSBjcnMocHRvc190cmFpbikKY3JzKFZpY2hhZGEyKSA8LSBjcnMocHRvc190cmFpbikKYGBgClNlIHVuZW4gbG9zIGF0cmlidXRvcyBhIGxhIHN1cGVyZmljaWUgdGVzZWxhZGEKYGBge3J9CnRoaWVzc2VuLnogICAgIDwtIG92ZXIodGhpZXNzZW4sIHB0b3NfdHJhaW4sIGZuPW1lYW4pCnRoaWVzc2VuLnNwZGYgIDwtICBTcGF0aWFsUG9seWdvbnNEYXRhRnJhbWUodGhpZXNzZW4sIHRoaWVzc2VuLnopCmBgYApTZSByZWNvcnRhbiBsYSBzdXBlcmZpY2llIGFsIHRhbWHDsW8gZGUgbGEgem9uYSBkZSBpbnRlcsOpcwpgYGB7cn0KdGhpZXNzZW4uY2xwICAgPC0gcmFzdGVyOjppbnRlcnNlY3QoVmljaGFkYTIsdGhpZXNzZW4uc3BkZikKYGBgClNlIHBsb3RlYW4gbG9zIHBvbMOtZ29ub3MgZGUgdGhpZXNzZW4gb2J0ZW5pZG9zIHBhcmEgZWwgZGVwYXJ0YW1lbnRvIGRlIFZpY2hhZGEKYGBge3J9CnRtX3NoYXBlKHRoaWVzc2VuLmNscCkgKyB0bV9wb2x5Z29ucyhjb2w9InByZWNpcGl0YWNpb24iLCBwYWxldHRlPSJSZEJ1IiAsIG1pZHBvaW50PTQzLjAsIHRpdGxlPSJQb2xpZ29ub3MgZGUgVGhpZXNzZW4gXG5wYXJhIHByZWNpcGl0YWNpw7NuIFxuKG1tKSIpICsgdG1fbGVnZW5kKGxlZ2VuZC5vdXRzaWRlPVRSVUUsIHRpdGxlLnNpemU9MS4yLCB0ZXh0LnNpemU9IDAuOCkKYGBg