Erika Aparicio
02/04/2020

Datos de elevación en R

1. Introducción a elevatr

Los datos de elevación se utilizan para una amplia gama de aplicaciones, que incluyen, por ejemplo, visualización, hidrología y modelado ecológico. Obtener acceso a estos datos en R no ha tenido una sola interfaz, está disponible a través de funciones en muchos paquetes o requiere acceso local a los datos. Esto ya no es necesario, ya que ahora existe una variedad de API que proporcionan acceso programático a los datos de elevación. El paquete elevatr se escribió para estandarizar el acceso a los datos de elevación desde las API web.
Para acceder a los datos de elevación ráster (por ejemplo, un DEM), el paquete elevatr utiliza los mosaicos de terreno de Amazon Web Services. Exploraremos esta funcionalidad en este cuaderno.
library(rasterVis)
Loading required package: raster
Loading required package: sp
Loading required package: lattice
Loading required package: latticeExtra
library(raster)
library(rgl)
Registered S3 methods overwritten by 'htmltools':
  method               from         
  print.html           tools:rstudio
  print.shiny.tag      tools:rstudio
  print.shiny.tag.list tools:rstudio
Registered S3 method overwritten by 'htmlwidgets':
  method           from         
  print.htmlwidget tools:rstudio
library(rgdal)
rgdal: version: 1.4-8, (SVN revision 845)
 Geospatial Data Abstraction Library extensions to R successfully loaded
 Loaded GDAL runtime: GDAL 2.2.3, released 2017/11/20
 Path to GDAL shared files: C:/Users/oaparicio15/Documents/R/win-library/3.6/rgdal/gdal
 GDAL binary built with GEOS: TRUE 
 Loaded PROJ.4 runtime: Rel. 4.9.3, 15 August 2016, [PJ_VERSION: 493]
 Path to PROJ.4 shared files: C:/Users/oaparicio15/Documents/R/win-library/3.6/rgdal/proj
 Linking to sp version: 1.4-1 

2. Obtenga datos de elevación de ráster

Existen varias fuentes para modelos digitales de elevación como la Misión de Topografía por Radar Shuttle (SRTM), el Conjunto de datos de elevación nacional (NED) de USGS, el DEM global (GDEM) y otros. 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 que utiliza los mejores datos de elevación disponibles para una región dada a un nivel de zoom dado. Aunque cerrado, estos datos compilados por Mapzen son actualmente accesibles a través de Terrain Tiles en Amazon Web Services (AWS).
La entrada para get_elev_raster () es un data.frame con ubicaciones x (longitud) e y (latitud) como las dos primeras columnas, cualquier objeto sp o cualquier objeto ráster y devuelve un RasterLayer de los mosaicos que se superponen al cuadro delimitador de la entrada Si se recuperan múltiples mosaicos, la salida resultante es una capa ráster fusionada.
Usando get_elev_raster () para acceder a los Terrain Tiles en AWS.
se mencionó, un marco de datos con columnas x e y, un objeto sp o un objeto ráster debe ser la entrada y el src debe establecerse en “mapzen” (este es el valor predeterminado).
No hay diferencia en el uso de los tipos de datos de entrada sp y ráster. El marco de datos requiere un prj. Mostraré ejemplos usando un SpatialPolygonsDataFrame. El nivel de zoom (z) predeterminado es 9 (una compensación entre la resolución y el tiempo de descarga), pero no pude obtener nada con este zoom. Tuve que usar un zoom inferior igual a 8. De lo contrario, el portátil RStudio Cloud se bloquearía una y otra vez. Muy a menudo, tuve que “volver a cargar” la página y comenzarla de nuevo.
Primero, se necesita cargar un archivo shape que represente a los municipios del departamento Meta. En este cuaderno, cargaremos el archivo de forma descargado del geoportal del DANE.

#####Revisemos el contenido de la carpeta:

list.files("C:/Users/oaparicio15/Desktop/QGIS/ColombiaDatos/50_META/ADMINISTRATIVO")
 [1] "MGN_DPTO_POLITICO.cpg"                            
 [2] "MGN_DPTO_POLITICO.dbf"                            
 [3] "MGN_DPTO_POLITICO.prj"                            
 [4] "MGN_DPTO_POLITICO.sbn"                            
 [5] "MGN_DPTO_POLITICO.sbx"                            
 [6] "MGN_DPTO_POLITICO.shp"                            
 [7] "MGN_DPTO_POLITICO.shp.DG_EST118.1768.8604.sr.lock"
 [8] "MGN_DPTO_POLITICO.shp.xml"                        
 [9] "MGN_DPTO_POLITICO.shx"                            
[10] "MGN_MPIO_POLITICO.cpg"                            
[11] "MGN_MPIO_POLITICO.dbf"                            
[12] "MGN_MPIO_POLITICO.prj"                            
[13] "MGN_MPIO_POLITICO.sbn"                            
[14] "MGN_MPIO_POLITICO.sbx"                            
[15] "MGN_MPIO_POLITICO.shp"                            
[16] "MGN_MPIO_POLITICO.shp.DG_EST118.1768.8604.sr.lock"
[17] "MGN_MPIO_POLITICO.shp.xml"                        
[18] "MGN_MPIO_POLITICO.shx"                            
Ahora, leamos el archivo de forma usando una función provista por el paquete ráster:
¿Cuáles son los atributos del objeto munic?
Seleccionemos solo la ciudad capital del departamento (Meta)

Descomente la siguiente línea para descargar los datos de elevación:
#elevation <- get_elev_raster(vila, z = 8)
elevation <- get_elev_raster(villa, z = 8)

Downloading DEMs [========>------------------]  33% eta:  2s
Downloading DEMs [=============>-------------]  50% eta:  3s
Downloading DEMs [=================>---------]  67% eta:  2s
Downloading DEMs [=====================>-----]  83% eta:  1s
Downloading DEMs [===========================] 100% eta:  0s
Merging DEMs
Reprojecting DEM to original projection
ning昼㹡n argumento finito para min; retornando Infningun argumento finito para max; retornando -InfNote: Elevation units are in meters.
Note: The coordinate reference system is:
 +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0
Como ya he descargado y guardado los datos de elevación, necesito leerlos usando la función ráster proporcionada por el paquete ráster. No deberia correrlo
#elevation <-  raster("./dem/elev_z8.tif")
Ahora, verifiquemos qué hay dentro del objeto de elevación:
elevation
class      : RasterLayer 
dimensions : 1546, 1033, 1597018  (nrow, ncol, ncell)
resolution : 0.00275, 0.00274  (x, y)
extent     : -74.545, -71.70425, 1.393646, 5.629686  (xmin, xmax, ymin, ymax)
crs        : +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0 
source     : memory
names      : layer 
values     : -1.570384, 4150.449  (min, max)

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

Tenga en cuenta que el DEM cubre una extensión mayor que la que necesitamos. Esto se debe a la disposición espacial de los mosaicos de elevación en AWS.
De todos modos, es una buena idea guardar el DEM para el futuro.
writeRaster(elevation, filename="C:/Users/oaparicio15/Documents/R/win-library/3.6/elevatr", datatype='INT4S', overwrite=TRUE)
class      : RasterLayer 
dimensions : 1546, 1033, 1597018  (nrow, ncol, ncell)
resolution : 0.00275, 0.00274  (x, y)
extent     : -74.545, -71.70425, 1.393646, 5.629686  (xmin, xmax, ymin, ymax)
crs        : +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0 
source     : C:/Users/oaparicio15/Documents/R/win-library/3.6/elevatr.grd 
names      : layer 
values     : -2, 4150  (min, max)
Ahora, recortemos los datos de elevación correspondientes a Villavicencio

Veamos el nuevo objeto:
elev_crop
class      : RasterLayer 
dimensions : 129, 216, 27864  (nrow, ncol, ncell)
resolution : 0.00275, 0.00274  (x, y)
extent     : -73.7695, -73.1755, 3.936366, 4.289826  (xmin, xmax, ymin, ymax)
crs        : +proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0 
source     : memory
names      : layer 
values     : 203.7742, 3577.458  (min, max)

4. Reproyectar los datos de elevación

#####Cuando se trabaja con DEM, siempre es una buena idea usar coordenadas de mapa en lugar de coordenadas geográficas. Esto se debe al hecho de que, en coordenadas geográficas, las unidades de dimensiones horizontales son grados decimales, PERO la unidad de dimensión vertical es metros. Vuelva a proyectar los datos de elevación.

Podemos ir a epsg.io y buscar la proyección de la zona MAGNA Colombia Bogotá. Necesitamos obtener la definición de esta referencia espacial en formato PROJ.4 (la que se usa para las bibliotecas sp y raster. Copiemos el texto PROJ.4 y guárdelo.
Ahora, podemos reproyectar los datos de elevación de las coordenadas geográficas WGS84 en la zona MAGNA Colombia Bogotá.
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
rep_elev
class      : RasterLayer 
dimensions : 391, 660, 258060  (nrow, ncol, ncell)
resolution : 100, 100  (x, y)
extent     : 1034192, 1100192, 927079.8, 966179.8  (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     : 201.3911, 3585.355  (min, max)
Ahora, reproyectemos el SpatialPolygonsDataFrame que representa la capital del departamento del Meta:
(rep_villa = spTransform(villa,spatialref))
class       : SpatialPolygonsDataFrame 
features    : 1 
extent      : 1034342, 1100224, 926940.8, 965985.1  (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       :         50,      50001, VILLAVICENCIO,       1840, 1285.93087074,      2017,       META, 2.03977418027, 0.104718109413 
Está tramando el tiempo:

Para evitar un dolor de cabeza, guardemos nuestra DEM
writeRaster(rep_elev, filename = "C:/Users/oaparicio15/Desktop/Rstudio/rep_villa_elev", dataType='INT4S', overwrite=TRUE)
argument "datatype" misspelled as "dataType"
class      : RasterLayer 
dimensions : 391, 660, 258060  (nrow, ncol, ncell)
resolution : 100, 100  (x, y)
extent     : 1034192, 1100192, 927079.8, 966179.8  (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/oaparicio15/Desktop/Rstudio/rep_villa_elev.grd 
names      : layer 
values     : 201, 3585  (min, max)

5. Estadísticas básicas de datos de elevación

Una exploración rápida de las estadísticas DEM:

crear vector unidimensional
creación de marco de datos con estadísticas de elevación [metros]

6. Obtención de variables geomorfométricas.

#####Primero, calcule la pendiente, el aspecto y el sombreado:

Parcela de elevación. Tenga en cuenta la paleta de colores utilizada aquí.

Pendiente de la trama. Tenga en cuenta la paleta de colores utilizada aquí.

Aspecto de la trama. Tenga en cuenta la paleta de colores utilizada aquí

Una trama combinada:

7. Mapeo de datos de elevación con sombreador de rayos

#####La biblioteca rayshader es un paquete de código abierto para producir visualizaciones de datos 2D y 3D en R. rayshader utiliza datos de elevación en una matriz base R y una combinación de trazado de rayos, mapeo de texturas esféricas, superposiciones y oclusión ambiental para generar hermosos mapas topográficos 2D y 3D . Además de los mapas, rayshader también permite al usuario traducir objetos ggplot2 en visualizaciones de datos 3D.

#install.packages("rayshader")
Convertir el DEM en una matriz:
elmat = raster_to_matrix(rep_elev)
[1] "Dimensions of matrix are: 660x391."
Usamos otra de las texturas incorporadas del sombreador de rayos:

######detect_water y add_water agrega una capa de agua al mapa:

Y también podemos agregar una capa de trazado de rayos desde esa dirección del sol:

8. Otra forma de visualización.

Un experto en R sugiere otra forma de visualización aquí.
Vamos a intentarlo:
#install.packages("jpeg")
Función de sombreado de mapeo de entorno esférico:
out = getv(map, aspect, slope)
ning昼㹡n argumento finito para min; retornando Infningun argumento finito para max; retornando -Infning昼㹡n argumento finito para min; retornando Infningun argumento finito para max; retornando -Infning昼㹡n argumento finito para min; retornando Infningun argumento finito para max; retornando -Infning昼㹡n argumento finito para min; retornando Infningun argumento finito para max; retornando -Infning昼㹡n argumento finito para min; retornando Infningun argumento finito para max; retornando -Infning昼㹡n argumento finito para min; retornando Infningun argumento finito para max; retornando -Inf

LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQojIyMjIyBFcmlrYSBBcGFyaWNpbw0KIyMjIyMgMDIvMDQvMjAyMA0KDQojIyBEYXRvcyBkZSBlbGV2YWNpw7NuIGVuIFINCg0KIyMjIDEuIEludHJvZHVjY2nDs24gYSBlbGV2YXRyDQojIyMjIyBMb3MgZGF0b3MgZGUgZWxldmFjacOzbiBzZSB1dGlsaXphbiBwYXJhIHVuYSBhbXBsaWEgZ2FtYSBkZSBhcGxpY2FjaW9uZXMsIHF1ZSBpbmNsdXllbiwgcG9yIGVqZW1wbG8sIHZpc3VhbGl6YWNpw7NuLCBoaWRyb2xvZ8OtYSB5IG1vZGVsYWRvIGVjb2zDs2dpY28uIE9idGVuZXIgYWNjZXNvIGEgZXN0b3MgZGF0b3MgZW4gUiBubyBoYSB0ZW5pZG8gdW5hIHNvbGEgaW50ZXJmYXosIGVzdMOhIGRpc3BvbmlibGUgYSB0cmF2w6lzIGRlIGZ1bmNpb25lcyBlbiBtdWNob3MgcGFxdWV0ZXMgbyByZXF1aWVyZSBhY2Nlc28gbG9jYWwgYSBsb3MgZGF0b3MuIEVzdG8geWEgbm8gZXMgbmVjZXNhcmlvLCB5YSBxdWUgYWhvcmEgZXhpc3RlIHVuYSB2YXJpZWRhZCBkZSBBUEkgcXVlIHByb3BvcmNpb25hbiBhY2Nlc28gcHJvZ3JhbcOhdGljbyBhIGxvcyBkYXRvcyBkZSBlbGV2YWNpw7NuLiBFbCBwYXF1ZXRlIGVsZXZhdHIgc2UgZXNjcmliacOzIHBhcmEgZXN0YW5kYXJpemFyIGVsIGFjY2VzbyBhIGxvcyBkYXRvcyBkZSBlbGV2YWNpw7NuIGRlc2RlIGxhcyBBUEkgd2ViLg0KDQojIyMjIyMgUGFyYSBhY2NlZGVyIGEgbG9zIGRhdG9zIGRlIGVsZXZhY2nDs24gcsOhc3RlciAocG9yIGVqZW1wbG8sIHVuIERFTSksIGVsIHBhcXVldGUgZWxldmF0ciB1dGlsaXphIGxvcyBtb3NhaWNvcyBkZSB0ZXJyZW5vIGRlIEFtYXpvbiBXZWIgU2VydmljZXMuIEV4cGxvcmFyZW1vcyBlc3RhIGZ1bmNpb25hbGlkYWQgZW4gZXN0ZSBjdWFkZXJuby4NCg0KYGBge3J9DQojIGluc3RhbGwucGFja2FnZXMoInJnZGFsIikNCiMgaW5zdGFsbC5wYWNrYWdlcygicmFzdGVyIikNCiMgaW5zdGFsbC5wYWNrYWdlcygiZWxldmF0ciIpDQojaW5zdGFsbC5wYWNrYWdlcygicmFzdGVyVmlzIikNCiNpbnN0YWxsLnBhY2thZ2VzKCJyZ2wiKQ0KYGBgDQpgYGB7cn0NCmxpYnJhcnkocmFzdGVyVmlzKQ0KYGBgDQpgYGB7cn0NCmxpYnJhcnkocmFzdGVyKQ0KbGlicmFyeShyZ2wpDQpsaWJyYXJ5KHJnZGFsKQ0KYGBgDQoNCmBgYHtyfQ0KbGlicmFyeShlbGV2YXRyKQ0KYGBgDQojIyMgMi4gT2J0ZW5nYSBkYXRvcyBkZSBlbGV2YWNpw7NuIGRlIHLDoXN0ZXINCiMjIyMjIEV4aXN0ZW4gdmFyaWFzIGZ1ZW50ZXMgcGFyYSBtb2RlbG9zIGRpZ2l0YWxlcyBkZSBlbGV2YWNpw7NuIGNvbW8gbGEgTWlzacOzbiBkZSBUb3BvZ3JhZsOtYSBwb3IgUmFkYXIgU2h1dHRsZSAoU1JUTSksIGVsIENvbmp1bnRvIGRlIGRhdG9zIGRlIGVsZXZhY2nDs24gbmFjaW9uYWwgKE5FRCkgZGUgVVNHUywgZWwgREVNIGdsb2JhbCAoR0RFTSkgeSBvdHJvcy4gQ2FkYSB1bm8gZGUgZXN0b3MgREVNIHRpZW5lIHZlbnRhamFzIHkgZGVzdmVudGFqYXMgcGFyYSBzdSB1c28uIEFudGVzIGRlIHN1IGNpZXJyZSBlbiBlbmVybyBkZSAyMDE4LCBNYXB6ZW4gY29tYmluw7MgdmFyaWFzIGRlIGVzdGFzIGZ1ZW50ZXMgcGFyYSBjcmVhciB1biBwcm9kdWN0byBkZSBlbGV2YWNpw7NuIGRlIHPDrW50ZXNpcyBxdWUgdXRpbGl6YSBsb3MgbWVqb3JlcyBkYXRvcyBkZSBlbGV2YWNpw7NuIGRpc3BvbmlibGVzIHBhcmEgdW5hIHJlZ2nDs24gZGFkYSBhIHVuIG5pdmVsIGRlIHpvb20gZGFkby4gQXVucXVlIGNlcnJhZG8sIGVzdG9zIGRhdG9zIGNvbXBpbGFkb3MgcG9yIE1hcHplbiBzb24gYWN0dWFsbWVudGUgYWNjZXNpYmxlcyBhIHRyYXbDqXMgZGUgVGVycmFpbiBUaWxlcyBlbiBBbWF6b24gV2ViIFNlcnZpY2VzIChBV1MpLg0KIyMjIyMgTGEgZW50cmFkYSBwYXJhIGdldF9lbGV2X3Jhc3RlciAoKSBlcyB1biBkYXRhLmZyYW1lIGNvbiB1YmljYWNpb25lcyB4IChsb25naXR1ZCkgZSB5IChsYXRpdHVkKSBjb21vIGxhcyBkb3MgcHJpbWVyYXMgY29sdW1uYXMsIGN1YWxxdWllciBvYmpldG8gc3AgbyBjdWFscXVpZXIgb2JqZXRvIHLDoXN0ZXIgeSBkZXZ1ZWx2ZSB1biBSYXN0ZXJMYXllciBkZSBsb3MgbW9zYWljb3MgcXVlIHNlIHN1cGVycG9uZW4gYWwgY3VhZHJvIGRlbGltaXRhZG9yIGRlIGxhIGVudHJhZGEgU2kgc2UgcmVjdXBlcmFuIG3Dumx0aXBsZXMgbW9zYWljb3MsIGxhIHNhbGlkYSByZXN1bHRhbnRlIGVzIHVuYSBjYXBhIHLDoXN0ZXIgZnVzaW9uYWRhLg0KDQojIyMjIyBVc2FuZG8gZ2V0X2VsZXZfcmFzdGVyICgpIHBhcmEgYWNjZWRlciBhIGxvcyBUZXJyYWluIFRpbGVzIGVuIEFXUy4NCiMjIyMjIHNlIG1lbmNpb27DsywgdW4gbWFyY28gZGUgZGF0b3MgY29uIGNvbHVtbmFzIHggZSB5LCB1biBvYmpldG8gc3AgbyB1biBvYmpldG8gcsOhc3RlciBkZWJlIHNlciBsYSBlbnRyYWRhIHkgZWwgc3JjIGRlYmUgZXN0YWJsZWNlcnNlIGVuICJtYXB6ZW4iIChlc3RlIGVzIGVsIHZhbG9yIHByZWRldGVybWluYWRvKS4NCg0KIyMjIyMgTm8gaGF5IGRpZmVyZW5jaWEgZW4gZWwgdXNvIGRlIGxvcyB0aXBvcyBkZSBkYXRvcyBkZSBlbnRyYWRhIHNwIHkgcsOhc3Rlci4gRWwgbWFyY28gZGUgZGF0b3MgcmVxdWllcmUgdW4gcHJqLiBNb3N0cmFyw6kgZWplbXBsb3MgdXNhbmRvIHVuIFNwYXRpYWxQb2x5Z29uc0RhdGFGcmFtZS4gRWwgbml2ZWwgZGUgem9vbSAoeikgcHJlZGV0ZXJtaW5hZG8gZXMgOSAodW5hIGNvbXBlbnNhY2nDs24gZW50cmUgbGEgcmVzb2x1Y2nDs24geSBlbCB0aWVtcG8gZGUgZGVzY2FyZ2EpLCBwZXJvIG5vIHB1ZGUgb2J0ZW5lciBuYWRhIGNvbiBlc3RlIHpvb20uIFR1dmUgcXVlIHVzYXIgdW4gem9vbSBpbmZlcmlvciBpZ3VhbCBhIDguIERlIGxvIGNvbnRyYXJpbywgZWwgcG9ydMOhdGlsIFJTdHVkaW8gQ2xvdWQgc2UgYmxvcXVlYXLDrWEgdW5hIHkgb3RyYSB2ZXouIE11eSBhIG1lbnVkbywgdHV2ZSBxdWUgInZvbHZlciBhIGNhcmdhciIgbGEgcMOhZ2luYSB5IGNvbWVuemFybGEgZGUgbnVldm8uDQoNCiMjIyMjIFByaW1lcm8sIHNlIG5lY2VzaXRhIGNhcmdhciB1biBhcmNoaXZvIHNoYXBlIHF1ZSByZXByZXNlbnRlIGEgbG9zIG11bmljaXBpb3MgZGVsIGRlcGFydGFtZW50byBNZXRhLiBFbiBlc3RlIGN1YWRlcm5vLCBjYXJnYXJlbW9zIGVsIGFyY2hpdm8gZGUgZm9ybWEgZGVzY2FyZ2FkbyBkZWwgZ2VvcG9ydGFsIGRlbCBEQU5FLg0KIyMjIyNSZXZpc2Vtb3MgZWwgY29udGVuaWRvIGRlIGxhIGNhcnBldGE6DQpgYGB7cn0NCmxpc3QuZmlsZXMoIkM6L1VzZXJzL29hcGFyaWNpbzE1L0Rlc2t0b3AvUUdJUy9Db2xvbWJpYURhdG9zLzUwX01FVEEvQURNSU5JU1RSQVRJVk8iKQ0KYGBgDQoNCiMjIyMjIEFob3JhLCBsZWFtb3MgZWwgYXJjaGl2byBkZSBmb3JtYSB1c2FuZG8gdW5hIGZ1bmNpw7NuIHByb3Zpc3RhIHBvciBlbCBwYXF1ZXRlIHLDoXN0ZXI6DQoNCmBgYHtyfQ0KbXVuaWMgPC0gIHNoYXBlZmlsZSgiQzovVXNlcnMvb2FwYXJpY2lvMTUvRGVza3RvcC9RR0lTL0NvbG9tYmlhRGF0b3MvNTBfTUVUQS9BRE1JTklTVFJBVElWTy9NR05fTVBJT19QT0xJVElDTy5zaHAiKQ0KYGBgDQojIyMjIyMgwr9DdcOhbGVzIHNvbiBsb3MgYXRyaWJ1dG9zIGRlbCBvYmpldG8gbXVuaWM/DQpgYGB7cn0NCmhlYWQobXVuaWMpDQpgYGANCiMjIyMjIyBTZWxlY2Npb25lbW9zIHNvbG8gbGEgY2l1ZGFkIGNhcGl0YWwgZGVsIGRlcGFydGFtZW50byAoTWV0YSkNCmBgYHtyfQ0KdmlsbGEgPC0gbXVuaWNbbXVuaWMkTVBJT19DTk1CUj09IlZJTExBVklDRU5DSU8iLF0NCnBsb3QodmlsbGEsIG1haW49IlZpbGxhdmljZW5jaW8iLCBheGVzPVRSVUUpDQpwbG90KG11bmljLCBhZGQ9VFJVRSkNCmludmlzaWJsZSh0ZXh0KGNvb3JkaW5hdGVzKG11bmljKSwgbGFiZWxzPWFzLmNoYXJhY3RlcihtdW5pYyRNUElPX0NOTUJSKSwgY2V4PTAuOCkpDQpgYGANCg0KIyMjIyMgRGVzY29tZW50ZSBsYSBzaWd1aWVudGUgbMOtbmVhIHBhcmEgZGVzY2FyZ2FyIGxvcyBkYXRvcyBkZSBlbGV2YWNpw7NuOg0KYGBge3J9DQojZWxldmF0aW9uIDwtIGdldF9lbGV2X3Jhc3Rlcih2aWxhLCB6ID0gOCkNCmBgYA0KDQpgYGB7cn0NCmVsZXZhdGlvbiA8LSBnZXRfZWxldl9yYXN0ZXIodmlsbGEsIHogPSA4KQ0KYGBgDQoNCiMjIyMjIENvbW8geWEgaGUgZGVzY2FyZ2FkbyB5IGd1YXJkYWRvIGxvcyBkYXRvcyBkZSBlbGV2YWNpw7NuLCBuZWNlc2l0byBsZWVybG9zIHVzYW5kbyBsYSBmdW5jacOzbiByw6FzdGVyIHByb3BvcmNpb25hZGEgcG9yIGVsIHBhcXVldGUgcsOhc3Rlci4gTm8gZGViZXJpYSBjb3JyZXJsbyANCmBgYHtyfQ0KI2VsZXZhdGlvbiA8LSAgcmFzdGVyKCIuL2RlbS9lbGV2X3o4LnRpZiIpDQpgYGANCiMjIyMjIEFob3JhLCB2ZXJpZmlxdWVtb3MgcXXDqSBoYXkgZGVudHJvIGRlbCBvYmpldG8gZGUgZWxldmFjacOzbjoNCmBgYHtyfQ0KZWxldmF0aW9uDQpgYGANCmBgYHtyfQ0KcGxvdChlbGV2YXRpb24sIG1haW49IkVzdGUgZXMgZWwgREVNIGRlc2NhcmdhZG8gW21ldHJvc10iKQ0KcGxvdCh2aWxsYSwgYWRkPVRSVUUpDQpgYGANCg0KIyMjIDMuIFJlY29ydGUgbG9zIGRhdG9zIGRlIGVsZXZhY2nDs24gcGFyYSBxdWUgY29pbmNpZGFuIGNvbiBsYSBleHRlbnNpw7NuIGRlbCDDoXJlYSBkZSBlc3R1ZGlvDQojIyMjIyMgVGVuZ2EgZW4gY3VlbnRhIHF1ZSBlbCBERU0gY3VicmUgdW5hIGV4dGVuc2nDs24gbWF5b3IgcXVlIGxhIHF1ZSBuZWNlc2l0YW1vcy4gRXN0byBzZSBkZWJlIGEgbGEgZGlzcG9zaWNpw7NuIGVzcGFjaWFsIGRlIGxvcyBtb3NhaWNvcyBkZSBlbGV2YWNpw7NuIGVuIEFXUy4NCg0KIyMjIyMjIERlIHRvZG9zIG1vZG9zLCBlcyB1bmEgYnVlbmEgaWRlYSBndWFyZGFyIGVsIERFTSBwYXJhIGVsIGZ1dHVyby4NCg0KYGBge3J9DQp3cml0ZVJhc3RlcihlbGV2YXRpb24sIGZpbGVuYW1lPSJDOi9Vc2Vycy9vYXBhcmljaW8xNS9Eb2N1bWVudHMvUi93aW4tbGlicmFyeS8zLjYvZWxldmF0ciIsIGRhdGF0eXBlPSdJTlQ0UycsIG92ZXJ3cml0ZT1UUlVFKQ0KYGBgDQoNCiMjIyMjIEFob3JhLCByZWNvcnRlbW9zIGxvcyBkYXRvcyBkZSBlbGV2YWNpw7NuIGNvcnJlc3BvbmRpZW50ZXMgYSBWaWxsYXZpY2VuY2lvDQpgYGB7cn0NCmVsZXZfY3JvcCA9IGNyb3AoZWxldmF0aW9uLCB2aWxsYSkNCnBsb3QoZWxldl9jcm9wLCBtYWluPSJNb2RlbG8gZGUgZWxldmFjacOzbiBkaWdpdGFsIHJlY29ydGFkbyIpDQpwbG90KHZpbGxhLCBhZGQ9VFJVRSkNCmBgYA0KDQojIyMjIyBWZWFtb3MgZWwgbnVldm8gb2JqZXRvOg0KYGBge3J9DQplbGV2X2Nyb3ANCmBgYA0KDQojIyMgNC4gUmVwcm95ZWN0YXIgbG9zIGRhdG9zIGRlIGVsZXZhY2nDs24NCiMjIyMjQ3VhbmRvIHNlIHRyYWJhamEgY29uIERFTSwgc2llbXByZSBlcyB1bmEgYnVlbmEgaWRlYSB1c2FyIGNvb3JkZW5hZGFzIGRlIG1hcGEgZW4gbHVnYXIgZGUgY29vcmRlbmFkYXMgZ2VvZ3LDoWZpY2FzLiBFc3RvIHNlIGRlYmUgYWwgaGVjaG8gZGUgcXVlLCBlbiBjb29yZGVuYWRhcyBnZW9ncsOhZmljYXMsIGxhcyB1bmlkYWRlcyBkZSBkaW1lbnNpb25lcyBob3Jpem9udGFsZXMgc29uIGdyYWRvcyBkZWNpbWFsZXMsIFBFUk8gbGEgdW5pZGFkIGRlIGRpbWVuc2nDs24gdmVydGljYWwgZXMgbWV0cm9zLiBWdWVsdmEgYSBwcm95ZWN0YXIgbG9zIGRhdG9zIGRlIGVsZXZhY2nDs24uDQoNCiMjIyMjIFBvZGVtb3MgaXIgYSBlcHNnLmlvIHkgYnVzY2FyIGxhIHByb3llY2Npw7NuIGRlIGxhIHpvbmEgTUFHTkEgQ29sb21iaWEgQm9nb3TDoS4gTmVjZXNpdGFtb3Mgb2J0ZW5lciBsYSBkZWZpbmljacOzbiBkZSBlc3RhIHJlZmVyZW5jaWEgZXNwYWNpYWwgZW4gZm9ybWF0byBQUk9KLjQgKGxhIHF1ZSBzZSB1c2EgcGFyYSBsYXMgYmlibGlvdGVjYXMgc3AgeSByYXN0ZXIuIENvcGllbW9zIGVsIHRleHRvIFBST0ouNCB5IGd1w6FyZGVsby4NCg0KYGBge3J9DQpzcGF0aWFscmVmIDwtICIrcHJvaj10bWVyYyArbGF0XzA9NC41OTYyMDA0MTY2NjY2NjYgK2xvbl8wPS03NC4wNzc1MDc5MTY2NjY2NiAraz0xICt4XzA9MTAwMDAwMCAreV8wPTEwMDAwMDAgK2VsbHBzPUdSUzgwICt0b3dnczg0PTAsMCwwLDAsMCwwLDAgK3VuaXRzPW0gK25vX2RlZnMiDQpgYGANCiMjIyMjIEFob3JhLCBwb2RlbW9zIHJlcHJveWVjdGFyIGxvcyBkYXRvcyBkZSBlbGV2YWNpw7NuIGRlIGxhcyBjb29yZGVuYWRhcyBnZW9ncsOhZmljYXMgV0dTODQgZW4gbGEgem9uYSBNQUdOQSBDb2xvbWJpYSBCb2dvdMOhLg0KYGBge3J9DQpwcjMgPSBwcm9qZWN0RXh0ZW50KGVsZXZfY3JvcCwgc3BhdGlhbHJlZikNCnJlcyhwcjMpID0gIDEwMA0KcmVwX2VsZXYgPSBwcm9qZWN0UmFzdGVyKGVsZXZfY3JvcCwgcHIzKQ0KYGBgDQpgYGB7cn0NCnJlcF9lbGV2DQpgYGANCg0KIyMjIyMgQWhvcmEsIHJlcHJveWVjdGVtb3MgZWwgU3BhdGlhbFBvbHlnb25zRGF0YUZyYW1lIHF1ZSByZXByZXNlbnRhIGxhIGNhcGl0YWwgZGVsIGRlcGFydGFtZW50byBkZWwgTWV0YToNCmBgYHtyfQ0KKHJlcF92aWxsYSA9IHNwVHJhbnNmb3JtKHZpbGxhLHNwYXRpYWxyZWYpKQ0KYGBgDQojIyMjIyBFc3TDoSB0cmFtYW5kbyBlbCB0aWVtcG86DQpgYGB7cn0NCnBsb3QocmVwX2VsZXYsIG1haW49IlJlcHJveWVjY2nDs24gZGlnaXRhbCBkZWwgbW9kZWxvIGRlIGVsZXZhY2nDs24iKQ0KcGxvdChyZXBfdmlsbGEsIGFkZD1UUlVFKQ0KYGBgDQoNCiMjIyMjIFBhcmEgZXZpdGFyIHVuIGRvbG9yIGRlIGNhYmV6YSwgZ3VhcmRlbW9zIG51ZXN0cmEgREVNDQpgYGB7cn0NCndyaXRlUmFzdGVyKHJlcF9lbGV2LCBmaWxlbmFtZSA9ICJDOi9Vc2Vycy9vYXBhcmljaW8xNS9EZXNrdG9wL1JzdHVkaW8vcmVwX3ZpbGxhX2VsZXYiLCBkYXRhVHlwZT0nSU5UNFMnLCBvdmVyd3JpdGU9VFJVRSkNCmBgYA0KIyMjIDUuIEVzdGFkw61zdGljYXMgYsOhc2ljYXMgZGUgZGF0b3MgZGUgZWxldmFjacOzbg0KIyMjIyMgVW5hIGV4cGxvcmFjacOzbiByw6FwaWRhIGRlIGxhcyBlc3RhZMOtc3RpY2FzIERFTToNCmBgYHtyfQ0KaGlzdChyZXBfZWxldikNCmBgYA0KDQpgYGB7cn0NCnByb21lZGlvIDwtIGNlbGxTdGF0cyhyZXBfZWxldiwgJ21lYW4nKQ0KbWluaW1vIDwtIGNlbGxTdGF0cyhyZXBfZWxldiwgJ21pbicpDQptYXhpbW8gPC0gY2VsbFN0YXRzKHJlcF9lbGV2LCAnbWF4JykNCmRlc3ZpYWNpb24gIDwtIGNlbGxTdGF0cyhyZXBfZWxldiwgJ3NkJykNCmBgYA0KIyMjIyMgY3JlYXIgdmVjdG9yIHVuaWRpbWVuc2lvbmFsDQpgYGB7cn0NCm1ldHJpY2FzIDwtIGMoJ21lYW4nLCAnbWluJywgJ21heCcsICdzdGQnKQ0KdmFsb3JlcyA8LSBjKHByb21lZGlvLCBtaW5pbW8sIG1heGltbywgZGVzdmlhY2lvbikNCmBgYA0KIyMjIyMgY3JlYWNpw7NuIGRlIG1hcmNvIGRlIGRhdG9zIGNvbiBlc3RhZMOtc3RpY2FzIGRlIGVsZXZhY2nDs24gW21ldHJvc10NCmBgYHtyfQ0KKGRmX2VzdGFkaXN0aWNhcyA8LSBkYXRhLmZyYW1lKG1ldHJpY2FzLCB2YWxvcmVzKSkNCmBgYA0KDQojIyMgNi4gT2J0ZW5jacOzbiBkZSB2YXJpYWJsZXMgZ2VvbW9yZm9tw6l0cmljYXMuDQojIyMjI1ByaW1lcm8sIGNhbGN1bGUgbGEgcGVuZGllbnRlLCBlbCBhc3BlY3RvIHkgZWwgc29tYnJlYWRvOg0KYGBge3J9DQpzbG9wZSA9IHRlcnJhaW4ocmVwX2VsZXYsb3B0PSdzbG9wZScsIHVuaXQ9J2RlZ3JlZXMnKQ0KYXNwZWN0ID0gdGVycmFpbihyZXBfZWxldixvcHQ9J2FzcGVjdCcsdW5pdD0nZGVncmVlcycpDQpoaWxsID0gaGlsbFNoYWRlKHNsb3BlLGFzcGVjdCw0MCwzMTUpDQpgYGANCiMjIyMjIFBhcmNlbGEgZGUgZWxldmFjacOzbi4gVGVuZ2EgZW4gY3VlbnRhIGxhIHBhbGV0YSBkZSBjb2xvcmVzIHV0aWxpemFkYSBhcXXDrS4NCmBgYHtyfQ0KcGxvdChyZXBfZWxldixtYWluPSJERU0gcGFyYSBWaWxsYXZpY2VuY2lvIFttZXRyb3NdIiwgY29sPXRlcnJhaW4uY29sb3JzKDI1LGFscGhhPTAuNykpDQpgYGANCiMjIyMjIFBlbmRpZW50ZSBkZSBsYSB0cmFtYS4gVGVuZ2EgZW4gY3VlbnRhIGxhIHBhbGV0YSBkZSBjb2xvcmVzIHV0aWxpemFkYSBhcXXDrS4NCmBgYHtyfQ0KcGxvdChzbG9wZSxtYWluPSJQZW5kaWVudGUgcGFyYSBWaWxsYXZpY2VuY2lvIFtncmFkb3NdIiwgY29sPXRvcG8uY29sb3JzKDI1LGFscGhhPTAuNykpDQpgYGANCiMjIyMjICBBc3BlY3RvIGRlIGxhIHRyYW1hLiBUZW5nYSBlbiBjdWVudGEgbGEgcGFsZXRhIGRlIGNvbG9yZXMgdXRpbGl6YWRhIGFxdcOtDQpgYGB7cn0NCnBsb3QoYXNwZWN0LG1haW49IkFzcGVjdG8gcGFyYSBWaWxsYXZpY2VuY2lvIFtncmFkb3NdIiwgY29sPXJhaW5ib3coMjUsYWxwaGE9MC43KSkNCmBgYA0KIyMjIyMgVW5hIHRyYW1hIGNvbWJpbmFkYToNCmBgYHtyfQ0KcGxvdChoaWxsLA0KICAgICAgICBjb2w9Z3JleSgxOjEwMC8xMDApLCAgDQogICAgICAgIGxlZ2VuZD1GQUxTRSwgICAgICAgICANCiAgICAgICAgbWFpbj0iREVNIHBhcmEgVmlsbGF2aWNlbmNpbyIsDQogICAgICAgIGF4ZXM9RkFMU0UpICAgICAgICAgICANCg0KcGxvdChyZXBfZWxldiwgDQogICAgICAgIGF4ZXM9RkFMU0UsDQogICAgICAgIGNvbD10ZXJyYWluLmNvbG9ycygxMiwgYWxwaGE9MC4zNSksIGFkZD1UUlVFKSANCmBgYA0KIyMjIDcuIE1hcGVvIGRlIGRhdG9zIGRlIGVsZXZhY2nDs24gY29uIHNvbWJyZWFkb3IgZGUgcmF5b3MNCiMjIyMjTGEgYmlibGlvdGVjYSByYXlzaGFkZXIgZXMgdW4gcGFxdWV0ZSBkZSBjw7NkaWdvIGFiaWVydG8gcGFyYSBwcm9kdWNpciB2aXN1YWxpemFjaW9uZXMgZGUgZGF0b3MgMkQgeSAzRCBlbiBSLiByYXlzaGFkZXIgdXRpbGl6YSBkYXRvcyBkZSBlbGV2YWNpw7NuIGVuIHVuYSBtYXRyaXogYmFzZSBSIHkgdW5hIGNvbWJpbmFjacOzbiBkZSB0cmF6YWRvIGRlIHJheW9zLCBtYXBlbyBkZSB0ZXh0dXJhcyBlc2bDqXJpY2FzLCBzdXBlcnBvc2ljaW9uZXMgeSBvY2x1c2nDs24gYW1iaWVudGFsIHBhcmEgZ2VuZXJhciBoZXJtb3NvcyBtYXBhcyB0b3BvZ3LDoWZpY29zIDJEIHkgM0QgLiBBZGVtw6FzIGRlIGxvcyBtYXBhcywgcmF5c2hhZGVyIHRhbWJpw6luIHBlcm1pdGUgYWwgdXN1YXJpbyB0cmFkdWNpciBvYmpldG9zIGdncGxvdDIgZW4gIHZpc3VhbGl6YWNpb25lcyBkZSBkYXRvcyAzRC4NCmBgYHtyfQ0KI2luc3RhbGwucGFja2FnZXMoInJheXNoYWRlciIpDQpgYGANCmBgYHtyfQ0KbGlicmFyeShyYXlzaGFkZXIpDQpgYGANCg0KIyMjIyMjIENvbnZlcnRpciBlbCBERU0gZW4gdW5hIG1hdHJpejoNCmBgYHtyfQ0KZWxtYXQgPSByYXN0ZXJfdG9fbWF0cml4KHJlcF9lbGV2KQ0KYGBgDQojIyMjIyMgVXNhbW9zIG90cmEgZGUgbGFzIHRleHR1cmFzIGluY29ycG9yYWRhcyBkZWwgc29tYnJlYWRvciBkZSByYXlvczoNCmBgYHtyfQ0KZWxtYXQgJT4lDQogIHNwaGVyZV9zaGFkZSh0ZXh0dXJlID0gImltaG9mMiIpICU+JQ0KICBwbG90X21hcCgpDQpgYGANCg0KIyMjIyMjZGV0ZWN0X3dhdGVyIHkgYWRkX3dhdGVyIGFncmVnYSB1bmEgY2FwYSBkZSBhZ3VhIGFsIG1hcGE6DQpgYGB7cn0NCmVsbWF0ICU+JQ0KICBzcGhlcmVfc2hhZGUodGV4dHVyZSA9ICJkZXNlcnQiKSAlPiUNCiAgYWRkX3dhdGVyKGRldGVjdF93YXRlcihlbG1hdCksIGNvbG9yID0gImRlc2VydCIpICU+JQ0KICBwbG90X21hcCgpDQpgYGANCiMjIyMjIyBZIHRhbWJpw6luIHBvZGVtb3MgYWdyZWdhciB1bmEgY2FwYSBkZSB0cmF6YWRvIGRlIHJheW9zIGRlc2RlIGVzYSBkaXJlY2Npw7NuIGRlbCBzb2w6DQpgYGB7cn0NCmVsbWF0ICU+JQ0KICBzcGhlcmVfc2hhZGUodGV4dHVyZSA9ICJkZXNlcnQiKSAlPiUNCiAgYWRkX3dhdGVyKGRldGVjdF93YXRlcihlbG1hdCksIGNvbG9yID0gImRlc2VydCIpICU+JQ0KICBhZGRfc2hhZG93KHJheV9zaGFkZShlbG1hdCksIDAuNSkgJT4lDQogIHBsb3RfbWFwKCkNCmBgYA0KDQojIyMgOC4gT3RyYSBmb3JtYSBkZSB2aXN1YWxpemFjacOzbi4NCiMjIyMjIFVuIGV4cGVydG8gZW4gUiBzdWdpZXJlIG90cmEgZm9ybWEgZGUgdmlzdWFsaXphY2nDs24gYXF1w60uDQojIyMjIyBWYW1vcyBhIGludGVudGFybG86DQpgYGB7cn0NCiNpbnN0YWxsLnBhY2thZ2VzKCJqcGVnIikNCmBgYA0KDQpgYGB7cn0NCmxpYnJhcnkoanBlZykNCmBgYA0KIyMjIyMjIEZ1bmNpw7NuIGRlIHNvbWJyZWFkbyBkZSBtYXBlbyBkZSBlbnRvcm5vIGVzZsOpcmljbzoNCmBgYHtyfQ0KZ2V0dj1mdW5jdGlvbihpLGEscyl7DQogIGN0ID0gZGltKGkpWzE6Ml0vMg0KICBzeCA9IHZhbHVlcyhzKS85MCAqIGN0WzFdDQogIHN5ID0gdmFsdWVzKHMpLzkwICogY3RbMl0NCiAgYSA9IHZhbHVlcyhhKSAqIDAuMDE3NDUNCiAgcHggPSBmbG9vcihjdFsxXSArIHN4ICogLXNpbihhKSkNCiAgcHkgPSBmbG9vcihjdFsyXSArIHN5ICogY29zKGEpKQ0KICANCiAgDQogIHRlbXBsYXRlID0gYnJpY2socyxzLHMpDQogIHZhbHVlcyh0ZW1wbGF0ZSk9TkENCiAgDQogIGNlbGxyID0gcHggKyBweSAqIGN0WzFdKjINCiAgY2VsbGcgPSBweCArIHB5ICogY3RbMV0qMiArIChjdFsxXSoyKmN0WzJdKjIpDQogIGNlbGxiID0gcHggKyBweSAqIGN0WzFdKjIgKyAyKihjdFsxXSoyKmN0WzJdKjIpDQogIA0KICB0ZW1wbGF0ZVtbMV1dID0gaVtjZWxscl0NCiAgdGVtcGxhdGVbWzJdXSA9IGlbY2VsbGddDQogIHRlbXBsYXRlW1szXV0gPSBpW2NlbGxiXQ0KICANCiAgdGVtcGxhdGUgPSB0ZW1wbGF0ZSAqIDI1Ng0KICANCiAgdGVtcGxhdGUNCn0NCmBgYA0KYGBge3J9DQptYXA9cmVhZEpQRUcoIkM6L1VzZXJzL29hcGFyaWNpbzE1L1BpY3R1cmVzL0RFTS85cHZiSGpOLmpwZyIpDQpgYGANCmBgYHtyfQ0Kb3V0ID0gZ2V0dihtYXAsIGFzcGVjdCwgc2xvcGUpDQpgYGANCmBgYHtyfQ0KcGxvdFJHQiAob3V0LCBtYWluID0gIk1vbnRhw7FhcyBlbiBWaWxsYXZpY2VuY2lvIikNCmBgYA0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQo=