Luisa Fernanda Carrión Ramírez

02/04/2020

Este cuaderno creado en R tiene como objetivo ilustrar algunas funcionalidades contenidas en este programa que son útiles para el procesamiento y visualización de unos modelos digitales de elevación. Para esta práctica se seleccionó el municipio de Yopal.

title: “introducción a elevart” Los datos de elevación pueden ser utilizados de diferentes maneras por su amplia gama de aplicaciones. Es por ello que anteriormente se requerían instalar varios paquetes aunque, en la actualidad se utilizan API’s que simplifican el proceso. El paquete elevatr fue programado con el propósito de estandarizar el acceso de los datos de elevación desde las API web. El paquete elevatr emplea mosaicos de terrenos de Amazon Web Services para acceder a los datos de elevación de los ráster. Para iniciar, se deben descargar los paquetes rgdal, raster, elevatr, rasterVis y rgl.

install.packages("rgdal")
install.packages("raster")
install.packages("elevatr")
install.packages("rasterVis")
install.packages("rgl")

Luego, se corren los paquetes usando la función library()

library(rgdal)
library(raster)
library(elevatr)
library(rgl)
library(rasterVis)

En adición, se requieren los paquetes sp, lattice y latticeExtra

library(sp)
library(latticeExtra)
library(lattice)

Obtenga datos de elevación de ráster

Hay varias fuentes para los modelos de elevación digital y cada uno de estos DEM tiene ventajas y desventajas para su uso. Antes de su cierre en enero de 2018, Mapzen combinó varias de estas fuentes para crear un producto de elevación de síntesis con un nivel de zoom determinado. Aunque cerró estos fueron compilados por Mapzen y pueden ser consultados en Amazon Web Services (AWS).

En este cuaderno, cargaremos se trabajará con un shapefile descargado del geoportal del DANE ,que contiene datos correspondientes al departamento de Casanare que se cargará con el siguiente código.

list.files("C:/Users/LUISA CARRION/Documents/Geomática/85_CASANARE/ADMINISTRATIVO")
 [1] "MGN_DPTO_POLITICO.cpg"     "MGN_DPTO_POLITICO.dbf"     "MGN_DPTO_POLITICO.prj"    
 [4] "MGN_DPTO_POLITICO.sbn"     "MGN_DPTO_POLITICO.sbx"     "MGN_DPTO_POLITICO.shp"    
 [7] "MGN_DPTO_POLITICO.shp.xml" "MGN_DPTO_POLITICO.shx"     "MGN_MPIO_POLITICO.cpg"    
[10] "MGN_MPIO_POLITICO.dbf"     "MGN_MPIO_POLITICO.prj"     "MGN_MPIO_POLITICO.sbn"    
[13] "MGN_MPIO_POLITICO.sbx"     "MGN_MPIO_POLITICO.shp"     "MGN_MPIO_POLITICO.shp.xml"
[16] "MGN_MPIO_POLITICO.shx"    

Luego se lee el shapefile:

(munic <- shapefile("C:/Users/LUISA CARRION/Documents/Geomática/85_CASANARE/ADMINISTRATIVO/MGN_MPIO_POLITICO.shp"))
class       : SpatialPolygonsDataFrame 
features    : 19 
extent      : -73.07777, -69.83591, 4.287476, 6.346111  (xmin, xmax, ymin, ymax)
crs         : +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0 
variables   : 9
names       : DPTO_CCDGO, MPIO_CCDGO, MPIO_CNMBR,                            MPIO_CRSLC,    MPIO_NAREA, MPIO_NANO, DPTO_CNMBR,     Shape_Leng,      Shape_Area 
min values  :         85,      85001,    AGUAZUL,                                  1748,  181.22675497,      2017,   CASANARE, 0.674577402276, 0.0147760191324 
max values  :         85,      85440,      YOPAL, Ordenanza 0038 del 8 de Julio de 1942, 12115.0422213,      2017,   CASANARE,  8.57006487338,  0.985967805522 

Por medio de la función head() vemos los archivos

head(munic)

Ahora, se selecciona únicamente la capital del departamento

yopal <- munic[munic$MPIO_CNMBR=="YOPAL",]
plot(yopal, main="Yopal", axes=TRUE)
plot(munic, add=TRUE)
invisible(text(coordinates(munic), labels=as.character(munic$MPIO_CNMBR), cex=0.6))

Procedemos a crear el objeto elevacion.

elevacion <- get_elev_raster(yopal, z=8)

Mediante el siguiente comando se puede ver lo que compone el objeto elevacion:

elevacion
class      : RasterLayer 
dimensions : 1034, 1033, 1068122  (nrow, ncol, ncell)
resolution : 0.00275, 0.00274  (x, y)
extent     : -73.13875, -70.298, 2.796526, 5.629686  (xmin, xmax, ymin, ymax)
crs        : +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0 
source     : memory
names      : layer 
values     : -42.2496, 3841.442  (min, max)

En el objeto elevacion se tienen las dimensiones, número de filas y columnas en los datos, el número total de píxeles, la resolución cada píxel y la extensión espacial de la trama. Además, también se puede ver que el ráster esta en coordenadas geográficas WGS 84.

Para trazar el DEM se escribe el siguiente código:

plot(elevacion, main="DEM descargado (metros)")
plot(yopal, add=TRUE)

Recorte los datos de elevación para que coincidan con la extensión del área de estudio

Como se pudo observar en la aterior gráfica, el área correpsondieente a Yopal es muy pequeña, por ello, debemos cortar el área que necesitamos. Sin embargo, es mejor guardar la capa sin cortar:

writeRaster(rep_elev, filename = "C:/Users/LUISA CARRION/Documents/Geomática/85_CASANARE/elevacion", dataType='INT4S', overwrite=TRUE)
argument "datatype" misspelled as "dataType"
class      : RasterLayer 
dimensions : 739, 716, 529124  (nrow, ncol, ncell)
resolution : 100, 100  (x, y)
extent     : 1165579, 1237179, 1034149, 1108049  (xmin, xmax, ymin, ymax)
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 
source     : C:/Users/LUISA CARRION/Documents/Geomática/85_CASANARE/elevacion.grd 
names      : layer 
values     : 161, 2421  (min, max)

Por medio del siguiente código se recorta el departamento

elev_crop = crop(elevacion, yopal)
plot(elev_crop, main="Modelo de elevación digital recortado")
plot(yopal, add=TRUE)

Ahora, visualizamos el nuevo objeto

elev_crop
class      : RasterLayer 
dimensions : 243, 234, 56862  (nrow, ncol, ncell)
resolution : 0.00275, 0.00274  (x, y)
extent     : -72.58325, -71.93975, 4.903586, 5.569406  (xmin, xmax, ymin, ymax)
crs        : +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0 
source     : memory
names      : layer 
values     : 160.9496, 2428.565  (min, max)

Reproyectar los datos de elevación

Cuando se trabaja con DEM, es preferible utilizar las coordenadas del lugar en donde se esta trabajando. Es por ello quese visitará (epsg.io) y se buscará la proyección “MAGNA- SIRGAS Colombia Bogota zone”. Necesitamos obtener la definición de esta referencia espacial en formato PROJ.4 ( Pues esta es la que se usa para las bibliotecas sp y raster ). Copiemamos el texto PROJ.4 y lo guardamos.

spatialref <- "+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"
pr3 <- projectExtent(elev_crop, spatialref)

res(pr3) <- 100

rep_elev <- projectRaster(elev_crop, pr3)
ning昼㹡n argumento finito para min; retornando Infningun argumento finito para max; retornando -Inf

Posteriormente, se reproyectarán las coordenadas:

rep_elev
class      : RasterLayer 
dimensions : 739, 716, 529124  (nrow, ncol, ncell)
resolution : 100, 100  (x, y)
extent     : 1165579, 1237179, 1034149, 1108049  (xmin, xmax, ymin, ymax)
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 
source     : memory
names      : layer 
values     : 160.9715, 2420.886  (min, max)

Ahora, debemos reproyectar el poligono de atributos de Yopal:

(rep_yopal = spTransform(yopal,spatialref))
class       : SpatialPolygonsDataFrame 
features    : 1 
extent      : 1165549, 1237211, 1034289, 1107987  (xmin, xmax, ymin, ymax)
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   : 9
names       : DPTO_CCDGO, MPIO_CCDGO, MPIO_CNMBR,                            MPIO_CRSLC,   MPIO_NAREA, MPIO_NANO, DPTO_CNMBR,    Shape_Leng,     Shape_Area 
value       :         85,      85001,      YOPAL, Ordenanza 0038 del 8 de Julio de 1942, 2482.9042923,      2017,   CASANARE, 3.15923255859, 0.202336772314 

Luego, se traza el objeto obtenido

plot(rep_elev, main="Reprojected Digital elevation model")
plot(rep_yopal, add=TRUE)

Ahora, se guarda el DEM

writeRaster(rep_elev, filename="C:/Users/LUISA CARRION/Documents/Geomática/85_CASANARE/elevacion.tif", datatype='INT4S', overwrite=TRUE)

Estadísticas básicas de los datos de elevación

Se exploran algunas estadísticas contenidas en el DEM empezando por el histograma:

hist(rep_elev)

Luego, miramos la elevación por metros:

promedio <- cellStats(rep_elev, 'mean')
minimo <- cellStats(rep_elev, 'min')
maximo <- cellStats(rep_elev, 'max')
desviacion  <- cellStats(rep_elev, 'sd')
metricas <- c('mean', 'min', 'max', 'std')
valores <- c(promedio, minimo, maximo, desviacion)
(df_estadisticas <- data.frame(metricas, valores))

Obtención de Variables geomorfomótricas

En esta sección se calcula la pendiente, el aspecto y el sombreado

slope = terrain(rep_elev,opt='slope', unit='degrees')
aspect = terrain(rep_elev,opt='aspect',unit='degrees')
hill = hillShade(slope,aspect,40,315)

Luego, se trazan la pendieente, aspecto y sombreado:

plot(rep_elev,main="DEM para Yopal [metros]", col=terrain.colors(25,alpha=0.7))

Grafiamos la pendiente:

plot(slope,main="Pendiente para Yopal [grados]", col=topo.colors(25,alpha=0.7))

Graficamos el aspecto:

plot(aspect,main="Aspecto de Yopal [Grados]", col=rainbow(25,alpha=0.7))

Podemos cambiar la paleta de colores, en este caso, escogí “Viridis”

install.packages("viridis")
library(viridis)

Graficamos e aspecto con “Viridis”

plot(aspect,main="Aspecto de Yopal [Grados]", col=viridis(25,alpha=0.7))

Se puede hacer un plot combinado:

plot(hill,
        col=grey(1:100/100),  
        legend=FALSE,         
        main="DEM de Yopal",
        axes=FALSE)          

plot(rep_elev, 
        axes=FALSE,
        col=terrain.colors(12, alpha=0.35), add=TRUE)

Mapeo de datos de elevación con rayshader.

La librería rayshader es un paquete que permite visualizar los datos en formato 2D y 3D. Instalamos y cargamos la libreri:

install.packages("rayshader")

Ahora, ase debe convertir el DEM en matríz:

library(rayshader)

Ahora, se le asigna una textura RGB a un sombreado:

elmat = raster_to_matrix(rep_elev)
[1] "Dimensions of matrix are: 716x739."
elmat %>%
  sphere_shade(texture = "imhof2") %>%
  plot_map()

Con “detect_water” se pueden detectar cuerpos de agua.

elmat %>%
  sphere_shade(texture = "desert") %>%
  add_water(detect_water(elmat), color = "desert") %>%
  plot_map()

Se puede agregar una capa de trazado de rayos:

elmat %>%
  sphere_shade(texture = "desert") %>%
  add_water(detect_water(elmat), color = "desert") %>%
  add_shadow(ray_shade(elmat), 0.5) %>%
  plot_map()

Otra forma de visualización

Para llevarla a cabo, se necesita instalar el paquete “jpeg”

install.packages("jpeg")
library(jpeg)

Luego, se ejecuta el siguiente código:

getv=function(i,a,s){
  ct = dim(i)[1:2]/2
  sx = values(s)/90 * ct[1]
  sy = values(s)/90 * ct[2]
  a = values(a) * 0.01745
  px = floor(ct[1] + sx * -sin(a))
  py = floor(ct[2] + sy * cos(a))
  
  
  template = brick(s,s,s)
  values(template)=NA
  
  cellr = px + py * ct[1]*2
  cellg = px + py * ct[1]*2 + (ct[1]*2*ct[2]*2)
  cellb = px + py * ct[1]*2 + 2*(ct[1]*2*ct[2]*2)
  
  template[[1]] = i[cellr]
  template[[2]] = i[cellg]
  template[[3]] = i[cellb]
  
  template = template * 256
  
  template
}

Por ultimo, se escribe:

map=readJPEG("C:/Users/LUISA CARRION/Documents/Geomática/85_CASANARE/elevacion.jgp")

out = getv(map, aspect, slope)

plotRGB(out,main="Montañas de Yopal")
LS0tDQp0aXRsZTogIkRhdG9zIGRlIGVsZXZhY2nDs24gZW4gUiINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQpMdWlzYSBGZXJuYW5kYSBDYXJyacOzbiBSYW3DrXJleg0KDQowMi8wNC8yMDIwDQoNCkVzdGUgY3VhZGVybm8gY3JlYWRvIGVuIFIgdGllbmUgY29tbyBvYmpldGl2byBpbHVzdHJhciBhbGd1bmFzIGZ1bmNpb25hbGlkYWRlcyBjb250ZW5pZGFzIGVuIGVzdGUgcHJvZ3JhbWEgcXVlIHNvbiDDunRpbGVzIHBhcmEgZWwgcHJvY2VzYW1pZW50byB5IHZpc3VhbGl6YWNpw7NuIGRlIHVub3MgbW9kZWxvcyBkaWdpdGFsZXMgZGUgZWxldmFjacOzbi4gUGFyYSBlc3RhIHByw6FjdGljYSBzZSBzZWxlY2Npb27DsyBlbCBtdW5pY2lwaW8gZGUgWW9wYWwuDQoNCnRpdGxlOiAiaW50cm9kdWNjacOzbiBhIGVsZXZhcnQiDQpMb3MgZGF0b3MgZGUgZWxldmFjacOzbiBwdWVkZW4gc2VyIHV0aWxpemFkb3MgZGUgZGlmZXJlbnRlcyBtYW5lcmFzIHBvciBzdSBhbXBsaWEgZ2FtYSBkZSBhcGxpY2FjaW9uZXMuIEVzIHBvciBlbGxvIHF1ZSBhbnRlcmlvcm1lbnRlIHNlIHJlcXVlcsOtYW4gaW5zdGFsYXIgdmFyaW9zIHBhcXVldGVzIGF1bnF1ZSwgZW4gbGEgYWN0dWFsaWRhZCBzZSB1dGlsaXphbiBBUEnigJlzIHF1ZSBzaW1wbGlmaWNhbiBlbCBwcm9jZXNvLiBFbCBwYXF1ZXRlIGVsZXZhdHIgZnVlIHByb2dyYW1hZG8gY29uIGVsIHByb3DDs3NpdG8gZGUgZXN0YW5kYXJpemFyIGVsIGFjY2VzbyBkZSBsb3MgZGF0b3MgZGUgZWxldmFjacOzbiBkZXNkZSBsYXMgQVBJIHdlYi4NCkVsIHBhcXVldGUgZWxldmF0ciBlbXBsZWEgbW9zYWljb3MgZGUgdGVycmVub3MgZGUgQW1hem9uIFdlYiBTZXJ2aWNlcyBwYXJhIGFjY2VkZXIgYSBsb3MgZGF0b3MgZGUgZWxldmFjacOzbiBkZSBsb3MgcsOhc3Rlci4NClBhcmEgaW5pY2lhciwgc2UgZGViZW4gZGVzY2FyZ2FyIGxvcyBwYXF1ZXRlcyByZ2RhbCwgcmFzdGVyLCBlbGV2YXRyLCByYXN0ZXJWaXMgeSByZ2wuDQpgYGB7cn0NCmluc3RhbGwucGFja2FnZXMoInJnZGFsIikNCmluc3RhbGwucGFja2FnZXMoInJhc3RlciIpDQppbnN0YWxsLnBhY2thZ2VzKCJlbGV2YXRyIikNCmluc3RhbGwucGFja2FnZXMoInJhc3RlclZpcyIpDQppbnN0YWxsLnBhY2thZ2VzKCJyZ2wiKQ0KYGBgDQpMdWVnbywgc2UgY29ycmVuIGxvcyBwYXF1ZXRlcyB1c2FuZG8gbGEgZnVuY2nDs24gbGlicmFyeSgpDQpgYGB7cn0NCmxpYnJhcnkocmdkYWwpDQpsaWJyYXJ5KHJhc3RlcikNCmxpYnJhcnkoZWxldmF0cikNCmxpYnJhcnkocmdsKQ0KbGlicmFyeShyYXN0ZXJWaXMpDQpgYGANCkVuIGFkaWNpw7NuLCBzZSByZXF1aWVyZW4gbG9zIHBhcXVldGVzIHNwLCBsYXR0aWNlIHkgbGF0dGljZUV4dHJhDQpgYGB7cn0NCmxpYnJhcnkoc3ApDQpsaWJyYXJ5KGxhdHRpY2VFeHRyYSkNCmxpYnJhcnkobGF0dGljZSkNCmBgYA0KIyMjIE9idGVuZ2EgZGF0b3MgZGUgZWxldmFjacOzbiBkZSByw6FzdGVyDQpIYXkgdmFyaWFzIGZ1ZW50ZXMgcGFyYSBsb3MgbW9kZWxvcyBkZSBlbGV2YWNpw7NuIGRpZ2l0YWwgeSBjYWRhIHVubyBkZSBlc3RvcyBERU0gdGllbmUgdmVudGFqYXMgeSBkZXN2ZW50YWphcyBwYXJhIHN1IHVzby4gQW50ZXMgZGUgc3UgY2llcnJlIGVuIGVuZXJvIGRlIDIwMTgsIE1hcHplbiBjb21iaW7DsyB2YXJpYXMgZGUgZXN0YXMgZnVlbnRlcyBwYXJhIGNyZWFyIHVuIHByb2R1Y3RvIGRlIGVsZXZhY2nDs24gZGUgc8OtbnRlc2lzIGNvbiB1biBuaXZlbCBkZSB6b29tIGRldGVybWluYWRvLiBBdW5xdWUgY2VycsOzIGVzdG9zIGZ1ZXJvbiBjb21waWxhZG9zIHBvciBNYXB6ZW4geSBwdWVkZW4gc2VyIGNvbnN1bHRhZG9zIGVuIEFtYXpvbiBXZWIgU2VydmljZXMgKEFXUykuDQoNCkVuIGVzdGUgY3VhZGVybm8sIGNhcmdhcmVtb3Mgc2UgdHJhYmFqYXLDoSBjb24gdW4gc2hhcGVmaWxlIGRlc2NhcmdhZG8gZGVsIGdlb3BvcnRhbCBkZWwgREFORSAscXVlIGNvbnRpZW5lIGRhdG9zIGNvcnJlc3BvbmRpZW50ZXMgYWwgZGVwYXJ0YW1lbnRvIGRlIENhc2FuYXJlIHF1ZSBzZSBjYXJnYXLDoSBjb24gZWwgc2lndWllbnRlIGPDs2RpZ28uDQoNCmBgYHtyfQ0KbGlzdC5maWxlcygiQzovVXNlcnMvTFVJU0EgQ0FSUklPTi9Eb2N1bWVudHMvR2VvbcOhdGljYS84NV9DQVNBTkFSRS9BRE1JTklTVFJBVElWTyIpDQoNCmBgYA0KTHVlZ28gc2UgbGVlIGVsIHNoYXBlZmlsZToNCg0KYGBge3J9DQoobXVuaWMgPC0gc2hhcGVmaWxlKCJDOi9Vc2Vycy9MVUlTQSBDQVJSSU9OL0RvY3VtZW50cy9HZW9tw6F0aWNhLzg1X0NBU0FOQVJFL0FETUlOSVNUUkFUSVZPL01HTl9NUElPX1BPTElUSUNPLnNocCIpKQ0KYGBgDQpQb3IgbWVkaW8gZGUgbGEgZnVuY2nDs24gaGVhZCgpIHZlbW9zIGxvcyBhcmNoaXZvcw0KYGBge3J9DQpoZWFkKG11bmljKQ0KYGBgDQoNCkFob3JhLCBzZSBzZWxlY2Npb25hIMO6bmljYW1lbnRlIGxhIGNhcGl0YWwgZGVsIGRlcGFydGFtZW50bw0KYGBge3J9DQp5b3BhbCA8LSBtdW5pY1ttdW5pYyRNUElPX0NOTUJSPT0iWU9QQUwiLF0NCnBsb3QoeW9wYWwsIG1haW49IllvcGFsIiwgYXhlcz1UUlVFKQ0KcGxvdChtdW5pYywgYWRkPVRSVUUpDQppbnZpc2libGUodGV4dChjb29yZGluYXRlcyhtdW5pYyksIGxhYmVscz1hcy5jaGFyYWN0ZXIobXVuaWMkTVBJT19DTk1CUiksIGNleD0wLjYpKQ0KDQpgYGANClByb2NlZGVtb3MgYSBjcmVhciBlbCBvYmpldG8gZWxldmFjaW9uLg0KYGBge3J9DQplbGV2YWNpb24gPC0gZ2V0X2VsZXZfcmFzdGVyKHlvcGFsLCB6PTgpDQpgYGANCk1lZGlhbnRlIGVsIHNpZ3VpZW50ZSBjb21hbmRvIHNlIHB1ZWRlIHZlciBsbyBxdWUgY29tcG9uZSBlbCBvYmpldG8gZWxldmFjaW9uOg0KYGBge3J9DQplbGV2YWNpb24NCmBgYA0KRW4gZWwgb2JqZXRvIGVsZXZhY2lvbiBzZSB0aWVuZW4gbGFzIGRpbWVuc2lvbmVzLCBuw7ptZXJvIGRlIGZpbGFzIHkgY29sdW1uYXMgZW4gbG9zIGRhdG9zLCBlbCBuw7ptZXJvIHRvdGFsIGRlIHDDrXhlbGVzLCBsYSByZXNvbHVjacOzbiBjYWRhIHDDrXhlbCB5IGxhIGV4dGVuc2nDs24gZXNwYWNpYWwgZGUgbGEgdHJhbWEuIEFkZW3DoXMsIHRhbWJpw6luIHNlIHB1ZWRlIHZlciBxdWUgZWwgcsOhc3RlciBlc3RhIGVuIGNvb3JkZW5hZGFzIGdlb2dyw6FmaWNhcyBXR1MgODQuDQoNClBhcmEgdHJhemFyIGVsIERFTSBzZSBlc2NyaWJlIGVsIHNpZ3VpZW50ZSBjw7NkaWdvOg0KYGBge3J9DQpwbG90KGVsZXZhY2lvbiwgbWFpbj0iREVNIGRlc2NhcmdhZG8gKG1ldHJvcykiKQ0KcGxvdCh5b3BhbCwgYWRkPVRSVUUpDQpgYGANCiMjIyBSZWNvcnRlIGxvcyBkYXRvcyBkZSBlbGV2YWNpw7NuIHBhcmEgcXVlIGNvaW5jaWRhbiBjb24gbGEgZXh0ZW5zacOzbiBkZWwgw6FyZWEgZGUgZXN0dWRpbw0KQ29tbyBzZSBwdWRvIG9ic2VydmFyIGVuIGxhIGF0ZXJpb3IgZ3LDoWZpY2EsIGVsIMOhcmVhIGNvcnJlcHNvbmRpZWVudGUgYSBZb3BhbCBlcyBtdXkgcGVxdWXDsWEsIHBvciBlbGxvLCBkZWJlbW9zIGNvcnRhciBlbCDDoXJlYSBxdWUgbmVjZXNpdGFtb3MuIFNpbiBlbWJhcmdvLCBlcyBtZWpvciBndWFyZGFyIGxhIGNhcGEgc2luIGNvcnRhcjogIA0KDQpgYGB7cn0NCndyaXRlUmFzdGVyKHJlcF9lbGV2LCBmaWxlbmFtZSA9ICJDOi9Vc2Vycy9MVUlTQSBDQVJSSU9OL0RvY3VtZW50cy9HZW9tw6F0aWNhLzg1X0NBU0FOQVJFL2VsZXZhY2lvbiIsIGRhdGFUeXBlPSdJTlQ0UycsIG92ZXJ3cml0ZT1UUlVFKQ0KYGBgDQoNClBvciBtZWRpbyBkZWwgc2lndWllbnRlIGPDs2RpZ28gc2UgcmVjb3J0YSBlbCBkZXBhcnRhbWVudG8NCg0KYGBge3J9DQplbGV2X2Nyb3AgPSBjcm9wKGVsZXZhY2lvbiwgeW9wYWwpDQpwbG90KGVsZXZfY3JvcCwgbWFpbj0iTW9kZWxvIGRlIGVsZXZhY2nDs24gZGlnaXRhbCByZWNvcnRhZG8iKQ0KcGxvdCh5b3BhbCwgYWRkPVRSVUUpDQpgYGANCkFob3JhLCB2aXN1YWxpemFtb3MgZWwgbnVldm8gb2JqZXRvDQoNCmBgYHtyfQ0KZWxldl9jcm9wDQpgYGANCiMjIFJlcHJveWVjdGFyIGxvcyBkYXRvcyBkZSBlbGV2YWNpw7NuDQoNCkN1YW5kbyBzZSB0cmFiYWphIGNvbiBERU0sIGVzIHByZWZlcmlibGUgdXRpbGl6YXIgbGFzIGNvb3JkZW5hZGFzIGRlbCBsdWdhciBlbiBkb25kZSBzZSBlc3RhIHRyYWJhamFuZG8uDQpFcyBwb3IgZWxsbyBxdWVzZSB2aXNpdGFyw6EgKGVwc2cuaW8pIHkgc2UgYnVzY2Fyw6EgbGEgcHJveWVjY2nDs24gKiJNQUdOQS0gU0lSR0FTIENvbG9tYmlhIEJvZ290YSB6b25lIiouIE5lY2VzaXRhbW9zIG9idGVuZXIgbGEgZGVmaW5pY2nDs24gZGUgZXN0YSByZWZlcmVuY2lhIGVzcGFjaWFsIGVuIGZvcm1hdG8gUFJPSi40ICggUHVlcyBlc3RhIGVzIGxhIHF1ZSBzZSB1c2EgcGFyYSBsYXMgYmlibGlvdGVjYXMgc3AgeSByYXN0ZXIgKS4gQ29waWVtYW1vcyBlbCB0ZXh0byBQUk9KLjQgeSBsbyBndWFyZGFtb3MuDQoNCg0KYGBge3J9DQpzcGF0aWFscmVmIDwtICIrcHJvaj10bWVyYyArbGF0XzA9NC41OTYyMDA0MTY2NjY2NjYgK2xvbl8wPS03NC4wNzc1MDc5MTY2NjY2NiAraz0xICt4XzA9MTAwMDAwMCAreV8wPTEwMDAwMDAgK2VsbHBzPUdSUzgwICt0b3dnczg0PTAsMCwwLDAsMCwwLDAgK3VuaXRzPW0gK25vX2RlZnMiDQpgYGANCg0KDQpgYGB7cn0NCnByMyA8LSBwcm9qZWN0RXh0ZW50KGVsZXZfY3JvcCwgc3BhdGlhbHJlZikNCg0KcmVzKHByMykgPC0gMTAwDQoNCnJlcF9lbGV2IDwtIHByb2plY3RSYXN0ZXIoZWxldl9jcm9wLCBwcjMpDQpgYGANClBvc3Rlcmlvcm1lbnRlLCBzZSByZXByb3llY3RhcsOhbiBsYXMgY29vcmRlbmFkYXM6DQoNCmBgYHtyfQ0KcmVwX2VsZXYNCmBgYA0KQWhvcmEsIGRlYmVtb3MgcmVwcm95ZWN0YXIgZWwgcG9saWdvbm8gZGUgYXRyaWJ1dG9zIGRlIFlvcGFsOg0KYGBge3J9DQoocmVwX3lvcGFsID0gc3BUcmFuc2Zvcm0oeW9wYWwsc3BhdGlhbHJlZikpDQpgYGANCkx1ZWdvLCBzZSB0cmF6YSBlbCBvYmpldG8gb2J0ZW5pZG8NCmBgYHtyfQ0KcGxvdChyZXBfZWxldiwgbWFpbj0iUmVwcm9qZWN0ZWQgRGlnaXRhbCBlbGV2YXRpb24gbW9kZWwiKQ0KcGxvdChyZXBfeW9wYWwsIGFkZD1UUlVFKQ0KYGBgDQoNCkFob3JhLCBzZSBndWFyZGEgZWwgREVNDQpgYGB7cn0NCndyaXRlUmFzdGVyKHJlcF9lbGV2LCBmaWxlbmFtZT0iQzovVXNlcnMvTFVJU0EgQ0FSUklPTi9Eb2N1bWVudHMvR2VvbcOhdGljYS84NV9DQVNBTkFSRS9lbGV2YWNpb24udGlmIiwgZGF0YXR5cGU9J0lOVDRTJywgb3ZlcndyaXRlPVRSVUUpDQpgYGANCg0KIyMjIEVzdGFkw61zdGljYXMgYsOhc2ljYXMgZGUgbG9zIGRhdG9zIGRlIGVsZXZhY2nDs24NClNlIGV4cGxvcmFuIGFsZ3VuYXMgZXN0YWTDrXN0aWNhcyBjb250ZW5pZGFzIGVuIGVsIERFTSBlbXBlemFuZG8gcG9yIGVsIGhpc3RvZ3JhbWE6DQoNCmBgYHtyfQ0KaGlzdChyZXBfZWxldikNCmBgYA0KTHVlZ28sIG1pcmFtb3MgbGEgZWxldmFjacOzbiBwb3IgbWV0cm9zOg0KYGBge3J9DQpwcm9tZWRpbyA8LSBjZWxsU3RhdHMocmVwX2VsZXYsICdtZWFuJykNCm1pbmltbyA8LSBjZWxsU3RhdHMocmVwX2VsZXYsICdtaW4nKQ0KbWF4aW1vIDwtIGNlbGxTdGF0cyhyZXBfZWxldiwgJ21heCcpDQpkZXN2aWFjaW9uICA8LSBjZWxsU3RhdHMocmVwX2VsZXYsICdzZCcpDQpgYGANCg0KDQpgYGB7cn0NCm1ldHJpY2FzIDwtIGMoJ21lYW4nLCAnbWluJywgJ21heCcsICdzdGQnKQ0KdmFsb3JlcyA8LSBjKHByb21lZGlvLCBtaW5pbW8sIG1heGltbywgZGVzdmlhY2lvbikNCmBgYA0KDQpgYGB7cn0NCihkZl9lc3RhZGlzdGljYXMgPC0gZGF0YS5mcmFtZShtZXRyaWNhcywgdmFsb3JlcykpDQpgYGANCiMjIE9idGVuY2nDs24gZGUgVmFyaWFibGVzIGdlb21vcmZvbcOzdHJpY2FzDQoNCkVuIGVzdGEgc2VjY2nDs24gc2UgY2FsY3VsYSBsYSBwZW5kaWVudGUsIGVsIGFzcGVjdG8geSBlbCBzb21icmVhZG8NCg0KYGBge3J9DQpzbG9wZSA9IHRlcnJhaW4ocmVwX2VsZXYsb3B0PSdzbG9wZScsIHVuaXQ9J2RlZ3JlZXMnKQ0KYXNwZWN0ID0gdGVycmFpbihyZXBfZWxldixvcHQ9J2FzcGVjdCcsdW5pdD0nZGVncmVlcycpDQpoaWxsID0gaGlsbFNoYWRlKHNsb3BlLGFzcGVjdCw0MCwzMTUpDQpgYGANCkx1ZWdvLCBzZSB0cmF6YW4gbGEgcGVuZGllZW50ZSwgYXNwZWN0byB5IHNvbWJyZWFkbzoNCg0KYGBge3J9DQpwbG90KHJlcF9lbGV2LG1haW49IkRFTSBwYXJhIFlvcGFsIFttZXRyb3NdIiwgY29sPXRlcnJhaW4uY29sb3JzKDI1LGFscGhhPTAuNykpDQpgYGANCkdyYWZpYW1vcyBsYSBwZW5kaWVudGU6DQoNCmBgYHtyfQ0KcGxvdChzbG9wZSxtYWluPSJQZW5kaWVudGUgcGFyYSBZb3BhbCBbZ3JhZG9zXSIsIGNvbD10b3BvLmNvbG9ycygyNSxhbHBoYT0wLjcpKQ0KYGBgDQoNCkdyYWZpY2Ftb3MgZWwgYXNwZWN0bzoNCmBgYHtyfQ0KcGxvdChhc3BlY3QsbWFpbj0iQXNwZWN0byBkZSBZb3BhbCBbR3JhZG9zXSIsIGNvbD1yYWluYm93KDI1LGFscGhhPTAuNykpDQpgYGANCg0KUG9kZW1vcyBjYW1iaWFyIGxhIHBhbGV0YSBkZSBjb2xvcmVzLCBlbiBlc3RlIGNhc28sIGVzY29nw60gIlZpcmlkaXMiDQpgYGB7cn0NCmluc3RhbGwucGFja2FnZXMoInZpcmlkaXMiKQ0KYGBgDQoNCmBgYHtyfQ0KbGlicmFyeSh2aXJpZGlzKQ0KYGBgDQoNCkdyYWZpY2Ftb3MgZSBhc3BlY3RvIGNvbiAiVmlyaWRpcyINCmBgYHtyfQ0KcGxvdChhc3BlY3QsbWFpbj0iQXNwZWN0byBkZSBZb3BhbCBbR3JhZG9zXSIsIGNvbD12aXJpZGlzKDI1LGFscGhhPTAuNykpDQpgYGANCg0KU2UgcHVlZGUgaGFjZXIgdW4gcGxvdCBjb21iaW5hZG86DQoNCmBgYHtyfQ0KcGxvdChoaWxsLA0KICAgICAgICBjb2w9Z3JleSgxOjEwMC8xMDApLCAgDQogICAgICAgIGxlZ2VuZD1GQUxTRSwgICAgICAgICANCiAgICAgICAgbWFpbj0iREVNIGRlIFlvcGFsIiwNCiAgICAgICAgYXhlcz1GQUxTRSkgICAgICAgICAgDQoNCnBsb3QocmVwX2VsZXYsIA0KICAgICAgICBheGVzPUZBTFNFLA0KICAgICAgICBjb2w9dGVycmFpbi5jb2xvcnMoMTIsIGFscGhhPTAuMzUpLCBhZGQ9VFJVRSkNCmBgYA0KIyMgTWFwZW8gZGUgZGF0b3MgZGUgZWxldmFjacOzbiBjb24gcmF5c2hhZGVyLg0KDQpMYSBsaWJyZXLDrWEgcmF5c2hhZGVyIGVzIHVuIHBhcXVldGUgIHF1ZSBwZXJtaXRlIHZpc3VhbGl6YXIgbG9zIGRhdG9zIGVuIGZvcm1hdG8gMkQgeSAzRC4gDQpJbnN0YWxhbW9zIHkgY2FyZ2Ftb3MgbGEgbGlicmVyaToNCmBgYHtyfQ0KaW5zdGFsbC5wYWNrYWdlcygicmF5c2hhZGVyIikNCmBgYA0KQWhvcmEsIGFzZSBkZWJlIGNvbnZlcnRpciBlbCBERU0gZW4gbWF0csOtejoNCmBgYHtyfQ0KbGlicmFyeShyYXlzaGFkZXIpDQpgYGANCg0KQWhvcmEsIHNlIGxlIGFzaWduYSB1bmEgdGV4dHVyYSBSR0IgYSB1biBzb21icmVhZG86DQpgYGB7cn0NCmVsbWF0ID0gcmFzdGVyX3RvX21hdHJpeChyZXBfZWxldikNCmBgYA0KDQoNCmBgYHtyfQ0KZWxtYXQgJT4lDQogIHNwaGVyZV9zaGFkZSh0ZXh0dXJlID0gImltaG9mMiIpICU+JQ0KICBwbG90X21hcCgpDQpgYGANCg0KQ29uICJkZXRlY3Rfd2F0ZXIiIHNlIHB1ZWRlbiBkZXRlY3RhciBjdWVycG9zIGRlIGFndWEuDQpgYGB7cn0NCmVsbWF0ICU+JQ0KICBzcGhlcmVfc2hhZGUodGV4dHVyZSA9ICJkZXNlcnQiKSAlPiUNCiAgYWRkX3dhdGVyKGRldGVjdF93YXRlcihlbG1hdCksIGNvbG9yID0gImRlc2VydCIpICU+JQ0KICBwbG90X21hcCgpDQpgYGANCg0KU2UgcHVlZGUgYWdyZWdhciB1bmEgY2FwYSBkZSB0cmF6YWRvIGRlIHJheW9zOg0KYGBge3J9DQplbG1hdCAlPiUNCiAgc3BoZXJlX3NoYWRlKHRleHR1cmUgPSAiZGVzZXJ0IikgJT4lDQogIGFkZF93YXRlcihkZXRlY3Rfd2F0ZXIoZWxtYXQpLCBjb2xvciA9ICJkZXNlcnQiKSAlPiUNCiAgYWRkX3NoYWRvdyhyYXlfc2hhZGUoZWxtYXQpLCAwLjUpICU+JQ0KICBwbG90X21hcCgpDQpgYGANCg0KDQojIyMgT3RyYSBmb3JtYSBkZSB2aXN1YWxpemFjacOzbg0KDQpQYXJhIGxsZXZhcmxhIGEgY2Fibywgc2UgbmVjZXNpdGEgaW5zdGFsYXIgZWwgcGFxdWV0ZSAianBlZyINCg0KYGBge3J9DQppbnN0YWxsLnBhY2thZ2VzKCJqcGVnIikNCmBgYA0KDQpgYGB7cn0NCmxpYnJhcnkoanBlZykNCmBgYA0KTHVlZ28sIHNlIGVqZWN1dGEgZWwgc2lndWllbnRlIGPDs2RpZ286DQoNCmBgYHtyfQ0KZ2V0dj1mdW5jdGlvbihpLGEscyl7DQogIGN0ID0gZGltKGkpWzE6Ml0vMg0KICBzeCA9IHZhbHVlcyhzKS85MCAqIGN0WzFdDQogIHN5ID0gdmFsdWVzKHMpLzkwICogY3RbMl0NCiAgYSA9IHZhbHVlcyhhKSAqIDAuMDE3NDUNCiAgcHggPSBmbG9vcihjdFsxXSArIHN4ICogLXNpbihhKSkNCiAgcHkgPSBmbG9vcihjdFsyXSArIHN5ICogY29zKGEpKQ0KICANCiAgDQogIHRlbXBsYXRlID0gYnJpY2socyxzLHMpDQogIHZhbHVlcyh0ZW1wbGF0ZSk9TkENCiAgDQogIGNlbGxyID0gcHggKyBweSAqIGN0WzFdKjINCiAgY2VsbGcgPSBweCArIHB5ICogY3RbMV0qMiArIChjdFsxXSoyKmN0WzJdKjIpDQogIGNlbGxiID0gcHggKyBweSAqIGN0WzFdKjIgKyAyKihjdFsxXSoyKmN0WzJdKjIpDQogIA0KICB0ZW1wbGF0ZVtbMV1dID0gaVtjZWxscl0NCiAgdGVtcGxhdGVbWzJdXSA9IGlbY2VsbGddDQogIHRlbXBsYXRlW1szXV0gPSBpW2NlbGxiXQ0KICANCiAgdGVtcGxhdGUgPSB0ZW1wbGF0ZSAqIDI1Ng0KICANCiAgdGVtcGxhdGUNCn0NCmBgYA0KDQpQb3IgdWx0aW1vLCBzZSBlc2NyaWJlOg0KDQpgYGB7cn0NCm1hcD1yZWFkSlBFRygiQzovVXNlcnMvTFVJU0EgQ0FSUklPTi9Eb2N1bWVudHMvR2VvbcOhdGljYS84NV9DQVNBTkFSRS9lbGV2YWNpb24uamdwIikNCg0Kb3V0ID0gZ2V0dihtYXAsIGFzcGVjdCwgc2xvcGUpDQoNCnBsb3RSR0Iob3V0LG1haW49Ik1vbnRhw7FhcyBkZSBZb3BhbCIpDQpgYGANCg0K