Ya se tiene descargado los datos de precipitación formato tif
De los global-pentad nombre: Chirps.v.2.0 2020.03.6
Arreglo de los datos
library(rgdal)
Loading required package: sp
rgdal: version: 1.5-10, (SVN revision 1006)
Geospatial Data Abstraction Library extensions to R successfully loaded
Loaded GDAL runtime: GDAL 3.0.4, released 2020/01/28
Path to GDAL shared files: C:/Users/amor/Documents/R/win-library/4.0/rgdal/gdal
GDAL binary built with GEOS: TRUE
Loaded PROJ runtime: Rel. 6.3.1, February 10th, 2020, [PJ_VERSION: 631]
Path to PROJ shared files: C:/Users/amor/Documents/R/win-library/4.0/rgdal/proj
Linking to sp version:1.4-2
To mute warnings of possible GDAL/OSR exportToProj4() degradation,
use options("rgdal_show_exportToProj4_warnings"="none") before loading rgdal.
library(raster)
library(sf)
Linking to GEOS 3.8.0, GDAL 3.0.4, PROJ 6.3.1
library(tidyverse)
Registered S3 methods overwritten by 'dbplyr':
method from
print.tbl_lazy
print.tbl_sql
-- Attaching packages --------------------------------------- tidyverse 1.3.0 --
v ggplot2 3.3.2 v purrr 0.3.4
v tibble 3.0.1 v dplyr 1.0.0
v tidyr 1.1.0 v stringr 1.4.0
v readr 1.3.1 v forcats 0.5.0
-- Conflicts ------------------------------------------ tidyverse_conflicts() --
x tidyr::extract() masks raster::extract()
x dplyr::filter() masks stats::filter()
x dplyr::lag() masks stats::lag()
x dplyr::select() masks raster::select()
library(tmap)
library(gstat)
library(sp)
3. Preprocesamiento de datos CHIRPS
Lea el archivo CHIRPS sin comprimir:
precip <- raster("C:/Users/amor/Desktop/Rstudio/chirps-v2.0.2020.03.6.tif")
Como ya habrá notado, este archivo representa la lluvia acumulada en los últimos días de marzo de 2020 (es decir, la precipitación del 26 al 31 de marzo).
Verifique el contenido del objeto precip
precip
class : RasterLayer
dimensions : 2000, 7200, 14400000 (nrow, ncol, ncell)
resolution : 0.05, 0.05 (x, y)
extent : -180, 180, -50, 50 (xmin, xmax, ymin, ymax)
crs : +proj=longlat +datum=WGS84 +no_defs
source : C:/Users/amor/Desktop/Rstudio/chirps-v2.0.2020.03.6.tif
names : chirps.v2.0.2020.03.6
Tenga en cuenta que este es un conjunto de datos con cobertura global. Su CRS es un sistema de coordenadas geográficas.
Carguemos un archivo shape que represente nuestra área de interés:
(aoi <- shapefile("C:/Users/amor/Desktop/Rstudio/MGN2017_50_META/50_META/ADMINISTRATIVO/MGN_MPIO_POLITICO.shp"))
class : SpatialPolygonsDataFrame
features : 29
extent : -74.89921, -71.07753, 1.604238, 4.899101 (xmin, xmax, ymin, ymax)
CRS object has comment, which is lost in output
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 : 50, 50001, ACACÃAS, 1840, 117.34108343, 2017, META, 0.43640580036, 0.00955216818621
max values : 50, 50711, VISTAHERMOSA, Ordenanza 63 de Noviembre 21 de 1965, 17247.6864753, 2017, META, 8.63318071739, 1.40216640329
Tenga en cuenta que los sistemas de referencia de coordenadas para ambos conjuntos de datos son los mismos.
Ahora, recortemos los datos de precipitación:
# Datos de precipitación de cultivos por extensión de área de interés
precip.crop <- raster::crop(precip, extent(aoi))
Ahora, enmascarar la capa de trama:
precip.mask <- mask(x = precip.crop, mask = aoi)
Verifique la salida:
precip.mask
class : RasterLayer
dimensions : 66, 76, 5016 (nrow, ncol, ncell)
resolution : 0.05, 0.05 (x, y)
extent : -74.9, -71.1, 1.599999, 4.899999 (xmin, xmax, ymin, ymax)
crs : +proj=longlat +datum=WGS84 +no_defs
source : memory
names : chirps.v2.0.2020.03.6
values : 0.9892889, 34.25411 (min, max)
Luego, se plotea la capa Raster recortada:
plot(precip.mask, main= "CHIRPS precipitaciones en Meta desde 26.03. hasta 30.03 en 2020 [mm] ")
plot(aoi, add=TRUE)

Se puede hacer un mejor mapa con Leaflet usando la función addRasterImage:
library(leaflet)
library(RColorBrewer)
pal <- colorNumeric(c("red", "orange", "yellow", "blue", "darkblue"), values(precip.mask),
na.color = "transparent")
leaflet() %>% addTiles() %>%
addRasterImage(precip.mask, colors = pal, opacity = 0.6) %>%
addLegend(pal = pal, values = values(precip.mask),
title = "CHIRPS precipitaciones en Meta desde 26.03. hasta 30.03 en 2020 [mm]")
Discarded ellps WGS 84 in CRS definition: +proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defsDiscarded datum WGS_1984 in CRS definitionUsing PROJ not WKT2 stringsDiscarded ellps WGS 84 in CRS definition: +proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defsDiscarded datum WGS_1984 in CRS definitionDiscarded ellps WGS 84 in CRS definition: +proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defsDiscarded datum WGS_1984 in CRS definitionUsing PROJ not WKT2 stringsDiscarded ellps WGS 84 in CRS definition: +proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defsDiscarded datum WGS_1984 in CRS definitionDiscarded ellps WGS 84 in CRS definition: +proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defsDiscarded datum WGS_1984 in CRS definitionUsing PROJ not WKT2 stringsDiscarded ellps WGS 84 in CRS definition: +proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defsDiscarded datum WGS_1984 in CRS definitionUsing PROJ not WKT2 stringsDiscarded ellps WGS 84 in CRS definition: +proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defsDiscarded datum WGS_1984 in CRS definitionDiscarded ellps WGS 84 in CRS definition: +proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defsDiscarded datum WGS_1984 in CRS definitionUsing PROJ not WKT2 strings
La conversión de ráster en puntos se puede realizar utilizando la función rasterToPoints de la biblioteca ráster:
precip.points <- rasterToPoints(precip.mask, spatial = TRUE)
precip.points
class : SpatialPointsDataFrame
features : 2765
extent : -74.875, -71.125, 1.624999, 4.824999 (xmin, xmax, ymin, ymax)
CRS object has comment, which is lost in output
crs : +proj=longlat +datum=WGS84 +no_defs
variables : 1
names : chirps.v2.0.2020.03.6
min values : 0.989288926124573
max values : 34.2541122436523
names(precip.points) <- "Lluvia"
precip.points
class : SpatialPointsDataFrame
features : 2765
extent : -74.875, -71.125, 1.624999, 4.824999 (xmin, xmax, ymin, ymax)
CRS object has comment, which is lost in output
crs : +proj=longlat +datum=WGS84 +no_defs
variables : 1
names : Lluvia
min values : 0.989288926124573
max values : 34.2541122436523
str(precip.points)
Formal class 'SpatialPointsDataFrame' [package "sp"] with 5 slots
..@ data :'data.frame': 2765 obs. of 1 variable:
.. ..$ Lluvia: num [1:2765] 8 7.8 6.26 7.17 8.09 ...
..@ coords.nrs : num(0)
..@ coords : num [1:2765, 1:2] -71.2 -71.1 -71.3 -71.2 -71.2 ...
.. ..- attr(*, "dimnames")=List of 2
.. .. ..$ : NULL
.. .. ..$ : chr [1:2] "x" "y"
..@ bbox : num [1:2, 1:2] -74.87 1.62 -71.12 4.82
.. ..- attr(*, "dimnames")=List of 2
.. .. ..$ : chr [1:2] "x" "y"
.. .. ..$ : chr [1:2] "min" "max"
..@ proj4string:Formal class 'CRS' [package "sp"] with 1 slot
.. .. ..@ projargs: chr "+proj=longlat +datum=WGS84 +no_defs"
Tracemos los puntos:
plot(precip.mask, main= "CHIRPS precipitaciones en Meta desde 26.03. hasta 30.03 en 2020 [mm]")
plot(aoi, add=TRUE)
points(precip.points$x, precip.points$y, col = "red", cex = .4)

Escribamos los objetos espaciales de puntos en un archivo de disco. Solo para ahorrar tiempo y trabajo en caso de que algo salga mal.
geojsonio::geojson_write(precip.points, file = "C:/Users/amor/Desktop/Rstudio/ppoints.geojson")
Success! File is at C:/Users/amor/Desktop/Rstudio/ppoints.geojson
<geojson-file>
Path: C:/Users/amor/Desktop/Rstudio/ppoints.geojson
From class: SpatialPointsDataFrame
Leamos los puntos de precipitación. Consulte la documentación de geojsonio para comprender qué parámetros deben pasarse a la función geojson_read.
precip.points <- geojsonio::geojson_read("C:/Users/amor/Desktop/Rstudio/ppoints.geojson", what="sp")
Verifiquemos cuál es el objeto de puntos precip.:
precip.points
class : SpatialPointsDataFrame
features : 2765
extent : -74.875, -71.125, 1.624999, 4.824999 (xmin, xmax, ymin, ymax)
CRS object has comment, which is lost in output
crs : +proj=longlat +datum=WGS84 +no_defs
variables : 1
names : Lluvia
min values : 0.989288926124573
max values : 34.2541122436523
¿Cuál es el punto de convertir los datos de precipitación ráster en datos de precipitación puntual?
Bueno, hay pocas estaciones meteorológicas de la Organización Meteorológica Mundial (OMM) en nuestro país:
Por lo tanto, CHIRPS puede ser una opción para obtener los datos de precipitación puntuales necesarios para obtener una superficie de precipitación continua.
Preparación adicional
Necesitamos convertirlo a una característica espacial:
meta_sf <- sf::st_as_sf(aoi)
Ahora, disuelva los límites internos:
(border_sf <-
meta_sf %>%
summarise(area = sum(MPIO_NAREA)))
Simple feature collection with 1 feature and 1 field
geometry type: POLYGON
dimension: XY
bbox: xmin: -74.89921 ymin: 1.604238 xmax: -71.07753 ymax: 4.899101
geographic CRS: WGS 84
area geometry
1 85524.79 POLYGON ((-73.44639 2.38595...
Convertir de característica espacial a dataframe espacial:
(border <- as(border_sf, 'Spatial'))
class : SpatialPolygonsDataFrame
features : 1
extent : -74.89921, -71.07753, 1.604238, 4.899101 (xmin, xmax, ymin, ymax)
CRS object has comment, which is lost in output
crs : +proj=longlat +datum=WGS84 +no_defs
variables : 1
names : area
value : 85524.79262911
otra conversion
(meta.sf <- st_as_sf(aoi) %>% mutate(MUNIC = MPIO_CNMBR, CODIGO = MPIO_CCDGO) %>% select(MUNIC, CODIGO))
Simple feature collection with 29 features and 2 fields
geometry type: POLYGON
dimension: XY
bbox: xmin: -74.89921 ymin: 1.604238 xmax: -71.07753 ymax: 4.899101
geographic CRS: WGS 84
First 10 features:
MUNIC CODIGO geometry
1 VILLAVICENCIO 50001 POLYGON ((-73.69288 4.28821...
2 ACACÃ\u008dAS 50006 POLYGON ((-73.80268 4.19734...
3 BARRANCA DE UPIA 50110 POLYGON ((-73.01607 4.63503...
4 CABUYARO 50124 POLYGON ((-73.08865 4.46048...
5 CASTILLA LA NUEVA 50150 POLYGON ((-73.7252 3.91777,...
6 CUBARRAL 50223 POLYGON ((-74.20143 4.0118,...
7 CUMARAL 50226 POLYGON ((-73.55407 4.31821...
8 EL CALVARIO 50245 POLYGON ((-73.74639 4.45008...
9 EL CASTILLO 50251 POLYGON ((-73.92004 3.74881...
10 EL DORADO 50270 POLYGON ((-73.83554 3.76362...
# conversion
p.sf <- st_as_sf(precip.points)
## intersecta polígonos con puntos, manteniendo la información de ambos
(precip.sf = st_intersection(meta.sf, p.sf))
although coordinates are longitude/latitude, st_intersection assumes that they are planar
attribute variables are assumed to be spatially constant throughout all geometries
Simple feature collection with 2765 features and 3 fields
geometry type: POINT
dimension: XY
bbox: xmin: -74.875 ymin: 1.624999 xmax: -71.125 ymax: 4.824999
geographic CRS: WGS 84
First 10 features:
MUNIC CODIGO Lluvia geometry
29 PUERTO GAITÃ\u0081N 50568 7.996710 POINT (-71.175 4.824999)
29.1 PUERTO GAITÃ\u0081N 50568 7.801209 POINT (-71.125 4.824999)
29.2 PUERTO GAITÃ\u0081N 50568 6.263782 POINT (-71.275 4.774999)
29.3 PUERTO GAITÃ\u0081N 50568 7.165887 POINT (-71.225 4.774999)
29.4 PUERTO GAITÃ\u0081N 50568 8.093927 POINT (-71.175 4.774999)
29.5 PUERTO GAITÃ\u0081N 50568 8.186864 POINT (-71.125 4.774999)
29.6 PUERTO GAITÃ\u0081N 50568 5.463953 POINT (-71.425 4.724999)
29.7 PUERTO GAITÃ\u0081N 50568 8.316946 POINT (-71.375 4.724999)
29.8 PUERTO GAITÃ\u0081N 50568 6.087829 POINT (-71.325 4.724999)
29.9 PUERTO GAITÃ\u0081N 50568 6.038989 POINT (-71.275 4.724999)
Dos tareas reproyecciones
p.sf.magna <- st_transform(precip.sf, crs=3116)
meta.sf.magna <- st_transform(meta.sf, crs=3116)
Una conversion
(precip2 <- as(p.sf.magna, 'Spatial'))
Discarded datum Unknown based on GRS80 ellipsoid in CRS definition,
but +towgs84= values preserved
class : SpatialPointsDataFrame
features : 2765
extent : 911335.8, 1328392, 671451.4, 1026012 (xmin, xmax, ymin, ymax)
CRS object has comment, which is lost in output
crs : +proj=tmerc +lat_0=4.59620041666667 +lon_0=-74.0775079166667 +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 : ACACÃAS, 50001, 0.989288926124573
max values : VISTAHERMOSA, 50711, 34.2541122436523
Nuevamente, podemos escribir el conjunto de datos intermedio (por si acaso):
shapefile(precip2, filename='C:/Users/amor/Desktop/Rstudio/precip2.shp', overwrite=TRUE)
Si es necesario, léelo. De lo contrario, sigue adelante
precip2$precipitaciones<- round(precip2$Lluvia, 1)
Lo que tenemos
precip2
class : SpatialPointsDataFrame
features : 2765
extent : 911335.8, 1328392, 671451.4, 1026012 (xmin, xmax, ymin, ymax)
CRS object has comment, which is lost in output
crs : +proj=tmerc +lat_0=4.59620041666667 +lon_0=-74.0775079166667 +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, precipitaciones
min values : ACACÃAS, 50001, 0.989288926124573, 1
max values : VISTAHERMOSA, 50711, 34.2541122436523, 34.3
(meta2 <- as(meta.sf.magna, 'Spatial'))
Discarded datum Unknown based on GRS80 ellipsoid in CRS definition,
but +towgs84= values preserved
class : SpatialPolygonsDataFrame
features : 29
extent : 908647.3, 1333690, 669155.7, 1034240 (xmin, xmax, ymin, ymax)
CRS object has comment, which is lost in output
crs : +proj=tmerc +lat_0=4.59620041666667 +lon_0=-74.0775079166667 +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 : ACACÃAS, 50001
max values : VISTAHERMOSA, 50711
Es posible que desee escribir el nuevo objeto (por si acaso):
shapefile(meta2, filename='C:/Users/amor/Desktop/Rstudio/meta2.shp', overwrite=TRUE)
Asegúrese de que las dos extensiones coincidan:
# Replace point boundary extent with that of meta
precip2@bbox <- meta2@bbox
División de datos en conjuntos de datos de capacitación y validación
train_index <- sample(1:nrow(precip2), 0.75 * nrow(precip2))
test_index <- setdiff(1:nrow(precip2), train_index)
ptos_train <- precip2[train_index, ]
ptos_test <- precip2[test_index,]
ptrain <- spTransform(ptos_train, crs(precip.mask))
ptest <- spTransform(ptos_test, crs(precip.mask))
#install.packages("htmltools")
library(htmltools)
library(leaflet.extras)
# Primero preparar leaflet plot ...
lplot <- leaflet(data = precip2) %>% # data = cuerpo original - para obtener el zoom correcto
addProviderTiles("CartoDB.Positron") %>%
addRasterImage(precip.mask, colors = pal, opacity = 0.6) %>%
addCircleMarkers(data = ptrain, # primer grupo
radius = 1,
fillOpacity = .7,
stroke = FALSE,
popup = ~htmlEscape(precipitaciones),
color = pal(ptos_train$precipitaciones), # usando una paleta ya creada
clusterOptions = markerClusterOptions(),
group = "Training") %>%
addCircleMarkers(data = ptest, # segundo grupo
radius = 10,
fillOpacity = .7,
stroke = FALSE,
popup = ~htmlEscape(precipitaciones),
color = pal(ptos_test$precipitaciones), # using already created palette
clusterOptions = markerClusterOptions(),
group = "Test") %>%
addLegend(position = "bottomright",
values = ~precipitaciones,
opacity = .7,
pal = pal, # palette declared previously
title = "CHIRPS precipitaciones en Meta \ndesde 26.03. hasta 30.03 en 2020 [mm]") %>%
leaflet::addLayersControl(overlayGroups = c("Training", "Test"),
options = layersControlOptions(collapsed = FALSE)) %>%
addResetMapButton()
Discarded ellps WGS 84 in CRS definition: +proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defsDiscarded datum WGS_1984 in CRS definitionUsing PROJ not WKT2 stringsDiscarded ellps WGS 84 in CRS definition: +proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defsDiscarded datum WGS_1984 in CRS definitionDiscarded ellps WGS 84 in CRS definition: +proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defsDiscarded datum WGS_1984 in CRS definitionUsing PROJ not WKT2 stringsDiscarded ellps WGS 84 in CRS definition: +proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defsDiscarded datum WGS_1984 in CRS definitionDiscarded ellps WGS 84 in CRS definition: +proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defsDiscarded datum WGS_1984 in CRS definitionUsing PROJ not WKT2 stringsDiscarded ellps WGS 84 in CRS definition: +proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defsDiscarded datum WGS_1984 in CRS definitionUsing PROJ not WKT2 stringsDiscarded ellps WGS 84 in CRS definition: +proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defsDiscarded datum WGS_1984 in CRS definitionDiscarded ellps WGS 84 in CRS definition: +proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defsDiscarded datum WGS_1984 in CRS definitionUsing PROJ not WKT2 stringsSome values were outside the color scale and will be treated as NASome values were outside the color scale and will be treated as NA
lplot # ... display the map
LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQojIyMjIFlhIHNlIHRpZW5lIGRlc2NhcmdhZG8gbG9zIGRhdG9zIGRlIHByZWNpcGl0YWNpw7NuIGZvcm1hdG8gdGlmIA0KIyMjIyBEZSBsb3MgZ2xvYmFsLXBlbnRhZCBub21icmU6IENoaXJwcy52LjIuMCAyMDIwLjAzLjYNCiMjIyMgQXJyZWdsbyBkZSBsb3MgZGF0b3MgDQoNCg0KDQpgYGB7cn0NCmxpYnJhcnkocmdkYWwpDQpgYGANCg0KYGBge3J9DQpsaWJyYXJ5KHJhc3RlcikNCmxpYnJhcnkoc2YpDQpgYGANCmBgYHtyfQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpgYGANCmBgYHtyfQ0KbGlicmFyeSh0bWFwKQ0KbGlicmFyeShnc3RhdCkNCmxpYnJhcnkoc3ApDQpgYGANCg0KIyMjIyAzLiBQcmVwcm9jZXNhbWllbnRvIGRlIGRhdG9zIENISVJQUw0KIyMjIyBMZWEgZWwgYXJjaGl2byBDSElSUFMgc2luIGNvbXByaW1pcjoNCmBgYHtyfQ0KcHJlY2lwIDwtIHJhc3RlcigiQzovVXNlcnMvYW1vci9EZXNrdG9wL1JzdHVkaW8vY2hpcnBzLXYyLjAuMjAyMC4wMy42LnRpZiIpDQpgYGANCg0KIyMjIyBDb21vIHlhIGhhYnLDoSBub3RhZG8sIGVzdGUgYXJjaGl2byByZXByZXNlbnRhIGxhIGxsdXZpYSBhY3VtdWxhZGEgZW4gbG9zIMO6bHRpbW9zIGTDrWFzIGRlIG1hcnpvIGRlIDIwMjAgKGVzIGRlY2lyLCBsYSBwcmVjaXBpdGFjacOzbiBkZWwgMjYgYWwgMzEgZGUgbWFyem8pLg0KDQojIyMgVmVyaWZpcXVlIGVsIGNvbnRlbmlkbyBkZWwgb2JqZXRvIHByZWNpcA0KDQpgYGB7cn0NCnByZWNpcA0KYGBgDQoNCiMjIyBUZW5nYSBlbiBjdWVudGEgcXVlIGVzdGUgZXMgdW4gY29uanVudG8gZGUgZGF0b3MgY29uIGNvYmVydHVyYSBnbG9iYWwuIFN1IENSUyBlcyB1biBzaXN0ZW1hIGRlIGNvb3JkZW5hZGFzIGdlb2dyw6FmaWNhcy4NCg0KIyMjIENhcmd1ZW1vcyB1biBhcmNoaXZvIHNoYXBlIHF1ZSByZXByZXNlbnRlIG51ZXN0cmEgw6FyZWEgZGUgaW50ZXLDqXM6DQoNCmBgYHtyfQ0KKGFvaSA8LSBzaGFwZWZpbGUoIkM6L1VzZXJzL2Ftb3IvRGVza3RvcC9Sc3R1ZGlvL01HTjIwMTdfNTBfTUVUQS81MF9NRVRBL0FETUlOSVNUUkFUSVZPL01HTl9NUElPX1BPTElUSUNPLnNocCIpKQ0KYGBgDQoNCg0KIyMjIFRlbmdhIGVuIGN1ZW50YSBxdWUgbG9zIHNpc3RlbWFzIGRlIHJlZmVyZW5jaWEgZGUgY29vcmRlbmFkYXMgcGFyYSBhbWJvcyBjb25qdW50b3MgZGUgZGF0b3Mgc29uIGxvcyBtaXNtb3MuDQoNCiMjIyBBaG9yYSwgcmVjb3J0ZW1vcyBsb3MgZGF0b3MgZGUgcHJlY2lwaXRhY2nDs246DQoNCmBgYHtyfQ0KIyBEYXRvcyBkZSBwcmVjaXBpdGFjacOzbiBkZSBjdWx0aXZvcyBwb3IgZXh0ZW5zacOzbiBkZSDDoXJlYSBkZSBpbnRlcsOpcw0KcHJlY2lwLmNyb3AgPC0gcmFzdGVyOjpjcm9wKHByZWNpcCwgZXh0ZW50KGFvaSkpDQpgYGANCiMjIyMgQWhvcmEsIGVubWFzY2FyYXIgbGEgY2FwYSBkZSB0cmFtYToNCmBgYHtyfQ0KcHJlY2lwLm1hc2sgPC0gbWFzayh4ID0gcHJlY2lwLmNyb3AsIG1hc2sgPSBhb2kpDQpgYGANCiMjIyBWZXJpZmlxdWUgbGEgc2FsaWRhOg0KYGBge3J9DQpwcmVjaXAubWFzayANCmBgYA0KIyMjIEx1ZWdvLCBzZSBwbG90ZWEgbGEgY2FwYSBSYXN0ZXIgcmVjb3J0YWRhOg0KDQpgYGB7cn0NCnBsb3QocHJlY2lwLm1hc2ssIG1haW49ICJDSElSUFMgcHJlY2lwaXRhY2lvbmVzIGVuIE1ldGEgZGVzZGUgMjYuMDMuIGhhc3RhIDMwLjAzIGVuIDIwMjAgW21tXSAiKQ0KcGxvdChhb2ksIGFkZD1UUlVFKQ0KYGBgDQojIyMjIFNlIHB1ZWRlIGhhY2VyIHVuIG1lam9yIG1hcGEgY29uIExlYWZsZXQgdXNhbmRvIGxhIGZ1bmNpw7NuIGFkZFJhc3RlckltYWdlOg0KDQpgYGB7cn0NCmxpYnJhcnkobGVhZmxldCkNCmxpYnJhcnkoUkNvbG9yQnJld2VyKQ0KcGFsIDwtIGNvbG9yTnVtZXJpYyhjKCJyZWQiLCAib3JhbmdlIiwgInllbGxvdyIsICJibHVlIiwgImRhcmtibHVlIiksIHZhbHVlcyhwcmVjaXAubWFzayksDQogIG5hLmNvbG9yID0gInRyYW5zcGFyZW50IikNCg0KbGVhZmxldCgpICU+JSBhZGRUaWxlcygpICU+JQ0KICBhZGRSYXN0ZXJJbWFnZShwcmVjaXAubWFzaywgY29sb3JzID0gcGFsLCBvcGFjaXR5ID0gMC42KSAlPiUNCiAgYWRkTGVnZW5kKHBhbCA9IHBhbCwgdmFsdWVzID0gdmFsdWVzKHByZWNpcC5tYXNrKSwNCiAgICB0aXRsZSA9ICJDSElSUFMgcHJlY2lwaXRhY2lvbmVzIGVuIE1ldGEgZGVzZGUgMjYuMDMuIGhhc3RhIDMwLjAzIGVuIDIwMjAgW21tXSIpDQpgYGANCg0KIyMjIExhIGNvbnZlcnNpw7NuIGRlIHLDoXN0ZXIgZW4gcHVudG9zIHNlIHB1ZWRlIHJlYWxpemFyIHV0aWxpemFuZG8gbGEgZnVuY2nDs24gcmFzdGVyVG9Qb2ludHMgZGUgbGEgYmlibGlvdGVjYSByw6FzdGVyOg0KYGBge3J9DQpwcmVjaXAucG9pbnRzIDwtIHJhc3RlclRvUG9pbnRzKHByZWNpcC5tYXNrLCBzcGF0aWFsID0gVFJVRSkNCmBgYA0KYGBge3J9DQpwcmVjaXAucG9pbnRzDQpgYGANCmBgYHtyfQ0KbmFtZXMocHJlY2lwLnBvaW50cykgPC0gIkxsdXZpYSINCmBgYA0KYGBge3J9DQpwcmVjaXAucG9pbnRzDQpgYGANCmBgYHtyfQ0Kc3RyKHByZWNpcC5wb2ludHMpDQpgYGANCg0KIyMjIyBUcmFjZW1vcyBsb3MgcHVudG9zOg0KYGBge3J9DQpwbG90KHByZWNpcC5tYXNrLCBtYWluPSAiQ0hJUlBTIHByZWNpcGl0YWNpb25lcyBlbiBNZXRhIGRlc2RlIDI2LjAzLiBoYXN0YSAzMC4wMyBlbiAyMDIwIFttbV0iKQ0KcGxvdChhb2ksIGFkZD1UUlVFKQ0KcG9pbnRzKHByZWNpcC5wb2ludHMkeCwgcHJlY2lwLnBvaW50cyR5LCBjb2wgPSAicmVkIiwgY2V4ID0gLjQpDQpgYGANCg0KIyMjIyBFc2NyaWJhbW9zIGxvcyBvYmpldG9zIGVzcGFjaWFsZXMgZGUgcHVudG9zIGVuIHVuIGFyY2hpdm8gZGUgZGlzY28uIFNvbG8gcGFyYSBhaG9ycmFyIHRpZW1wbyB5IHRyYWJham8gZW4gY2FzbyBkZSBxdWUgYWxnbyBzYWxnYSBtYWwuDQoNCmBgYHtyfQ0KZ2VvanNvbmlvOjpnZW9qc29uX3dyaXRlKHByZWNpcC5wb2ludHMsIGZpbGUgPSAiQzovVXNlcnMvYW1vci9EZXNrdG9wL1JzdHVkaW8vcHBvaW50cy5nZW9qc29uIikNCmBgYA0KDQojIyMjIExlYW1vcyBsb3MgcHVudG9zIGRlIHByZWNpcGl0YWNpw7NuLiBDb25zdWx0ZSBsYSBkb2N1bWVudGFjacOzbiBkZSBnZW9qc29uaW8gcGFyYSBjb21wcmVuZGVyIHF1w6kgcGFyw6FtZXRyb3MgZGViZW4gcGFzYXJzZSBhIGxhIGZ1bmNpw7NuIGdlb2pzb25fcmVhZC4NCg0KYGBge3J9DQpwcmVjaXAucG9pbnRzIDwtIGdlb2pzb25pbzo6Z2VvanNvbl9yZWFkKCJDOi9Vc2Vycy9hbW9yL0Rlc2t0b3AvUnN0dWRpby9wcG9pbnRzLmdlb2pzb24iLCB3aGF0PSJzcCIpDQpgYGANCg0KIyMjIFZlcmlmaXF1ZW1vcyBjdcOhbCBlcyBlbCBvYmpldG8gZGUgcHVudG9zIHByZWNpcC46DQpgYGB7cn0NCnByZWNpcC5wb2ludHMNCmBgYA0KDQojIyMjIMK/Q3XDoWwgZXMgZWwgcHVudG8gZGUgY29udmVydGlyIGxvcyBkYXRvcyBkZSBwcmVjaXBpdGFjacOzbiByw6FzdGVyIGVuIGRhdG9zIGRlIHByZWNpcGl0YWNpw7NuIHB1bnR1YWw/DQoNCiMjIyMgQnVlbm8sIGhheSBwb2NhcyBlc3RhY2lvbmVzIG1ldGVvcm9sw7NnaWNhcyBkZSBsYSBPcmdhbml6YWNpw7NuIE1ldGVvcm9sw7NnaWNhIE11bmRpYWwgKE9NTSkgZW4gbnVlc3RybyBwYcOtczoNCg0KIyMjIyBQb3IgbG8gdGFudG8sIENISVJQUyBwdWVkZSBzZXIgdW5hIG9wY2nDs24gcGFyYSBvYnRlbmVyIGxvcyBkYXRvcyBkZSBwcmVjaXBpdGFjacOzbiBwdW50dWFsZXMgbmVjZXNhcmlvcyBwYXJhIG9idGVuZXIgdW5hIHN1cGVyZmljaWUgZGUgcHJlY2lwaXRhY2nDs24gY29udGludWEuDQoNCiMjIyMgUHJlcGFyYWNpw7NuIGFkaWNpb25hbA0KIyMjIyBFbiBjYXNvIGRlIHF1ZSBzZSBwaWVyZGEgbGEgY29uZXhpw7NuLCBwb2RlbW9zIGxlZXIgbnVldmFtZW50ZSBlbCBhcmNoaXZvIGRlIGZvcm1hIGNvbiBlbCDDoXJlYSBkZSBpbnRlcsOpczoNCmBgYHtyfQ0KKGFvaSA8LSBzaGFwZWZpbGUoIkM6L1VzZXJzL2Ftb3IvRGVza3RvcC9Sc3R1ZGlvL01HTjIwMTdfNTBfTUVUQS81MF9NRVRBL0FETUlOSVNUUkFUSVZPL01HTl9NUElPX1BPTElUSUNPLnNocCIpKQ0KYGBgDQoNCiMjIyMgTmVjZXNpdGFtb3MgY29udmVydGlybG8gYSB1bmEgY2FyYWN0ZXLDrXN0aWNhIGVzcGFjaWFsOg0KDQpgYGB7cn0NCm1ldGFfc2YgPC0gIHNmOjpzdF9hc19zZihhb2kpDQpgYGANCiMjIyMgQWhvcmEsIGRpc3VlbHZhIGxvcyBsw61taXRlcyBpbnRlcm5vczoNCmBgYHtyfQ0KKGJvcmRlcl9zZiA8LQ0KICBtZXRhX3NmICU+JQ0KICBzdW1tYXJpc2UoYXJlYSA9IHN1bShNUElPX05BUkVBKSkpDQpgYGANCg0KIyMjIyBDb252ZXJ0aXIgZGUgY2FyYWN0ZXLDrXN0aWNhIGVzcGFjaWFsIGEgZGF0YWZyYW1lIGVzcGFjaWFsOg0KDQoNCmBgYHtyfQ0KIChib3JkZXIgPC0gYXMoYm9yZGVyX3NmLCAnU3BhdGlhbCcpKSANCmBgYA0KDQojIyMjIG90cmEgY29udmVyc2lvbiANCg0KYGBge3J9DQoobWV0YS5zZiA8LSBzdF9hc19zZihhb2kpICU+JSBtdXRhdGUoTVVOSUMgPSBNUElPX0NOTUJSLCBDT0RJR08gPSBNUElPX0NDREdPKSAlPiUgc2VsZWN0KE1VTklDLCBDT0RJR08pKQ0KYGBgDQojIyMjIEFob3JhLCBpbnRlbnRhcmVtb3MgdW5hIHRhcmVhIHN0X2ludGVyc2VjdGlvbi4gKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9zZi92aWduZXR0ZXMvc2YzLmh0bWwjZ2VvbWV0cmljYWxfb3BlcmF0aW9ucykgc2UgaGFjZSB1c2FuZG8gbGEgYmlibGlvdGVjYSBzZg0KDQpgYGB7cn0NCiMgY29udmVyc2lvbg0KcC5zZiA8LSBzdF9hc19zZihwcmVjaXAucG9pbnRzKQ0KYGBgDQpgYGB7cn0NCiMjIGludGVyc2VjdGEgcG9sw61nb25vcyBjb24gcHVudG9zLCBtYW50ZW5pZW5kbyBsYSBpbmZvcm1hY2nDs24gZGUgYW1ib3MNCihwcmVjaXAuc2YgPSBzdF9pbnRlcnNlY3Rpb24obWV0YS5zZiwgcC5zZikpDQpgYGANCiMjIyMgRG9zIHRhcmVhcyByZXByb3llY2Npb25lcyANCmBgYHtyfQ0KcC5zZi5tYWduYSA8LSBzdF90cmFuc2Zvcm0ocHJlY2lwLnNmLCBjcnM9MzExNikNCmBgYA0KYGBge3J9DQptZXRhLnNmLm1hZ25hIDwtIHN0X3RyYW5zZm9ybShtZXRhLnNmLCBjcnM9MzExNikNCmBgYA0KIyMjIFVuYSBjb252ZXJzaW9uIA0KYGBge3J9DQoocHJlY2lwMiA8LSBhcyhwLnNmLm1hZ25hLCAnU3BhdGlhbCcpKQ0KYGBgDQojIyMjIE51ZXZhbWVudGUsIHBvZGVtb3MgZXNjcmliaXIgZWwgY29uanVudG8gZGUgZGF0b3MgaW50ZXJtZWRpbyAocG9yIHNpIGFjYXNvKToNCmBgYHtyfQ0Kc2hhcGVmaWxlKHByZWNpcDIsIGZpbGVuYW1lPSdDOi9Vc2Vycy9hbW9yL0Rlc2t0b3AvUnN0dWRpby9wcmVjaXAyLnNocCcsIG92ZXJ3cml0ZT1UUlVFKQ0KYGBgDQojIyMgU2kgZXMgbmVjZXNhcmlvLCBsw6llbG8uIERlIGxvIGNvbnRyYXJpbywgc2lndWUgYWRlbGFudGUNCg0KYGBge3J9DQpwcmVjaXAyJHByZWNpcGl0YWNpb25lczwtIHJvdW5kKHByZWNpcDIkTGx1dmlhLCAxKQ0KYGBgDQoNCiMjIyMgTG8gcXVlIHRlbmVtb3MNCmBgYHtyfQ0KcHJlY2lwMg0KYGBgDQpgYGB7cn0NCihtZXRhMiA8LSBhcyhtZXRhLnNmLm1hZ25hLCAnU3BhdGlhbCcpKQ0KYGBgDQojIyMjIEVzIHBvc2libGUgcXVlIGRlc2VlIGVzY3JpYmlyIGVsIG51ZXZvIG9iamV0byAocG9yIHNpIGFjYXNvKToNCg0KYGBge3J9DQpzaGFwZWZpbGUobWV0YTIsIGZpbGVuYW1lPSdDOi9Vc2Vycy9hbW9yL0Rlc2t0b3AvUnN0dWRpby9tZXRhMi5zaHAnLCBvdmVyd3JpdGU9VFJVRSkNCmBgYA0KIyMjIyBBc2Vnw7pyZXNlIGRlIHF1ZSBsYXMgZG9zIGV4dGVuc2lvbmVzIGNvaW5jaWRhbjoNCg0KYGBge3J9DQojIFJlcGxhY2UgcG9pbnQgYm91bmRhcnkgZXh0ZW50IHdpdGggdGhhdCBvZiBtZXRhDQpwcmVjaXAyQGJib3ggPC0gbWV0YTJAYmJveA0KYGBgDQoNCg0KIyMjIERpdmlzacOzbiBkZSBkYXRvcyBlbiBjb25qdW50b3MgZGUgZGF0b3MgZGUgY2FwYWNpdGFjacOzbiB5IHZhbGlkYWNpw7NuDQpgYGB7cn0NCnRyYWluX2luZGV4IDwtIHNhbXBsZSgxOm5yb3cocHJlY2lwMiksIDAuNzUgKiBucm93KHByZWNpcDIpKQ0KdGVzdF9pbmRleCA8LSBzZXRkaWZmKDE6bnJvdyhwcmVjaXAyKSwgdHJhaW5faW5kZXgpDQpwdG9zX3RyYWluIDwtIHByZWNpcDJbdHJhaW5faW5kZXgsIF0NCnB0b3NfdGVzdCAgPC0gcHJlY2lwMlt0ZXN0X2luZGV4LF0NCnB0cmFpbiA8LSBzcFRyYW5zZm9ybShwdG9zX3RyYWluLCBjcnMocHJlY2lwLm1hc2spKQ0KcHRlc3QgPC0gc3BUcmFuc2Zvcm0ocHRvc190ZXN0LCBjcnMocHJlY2lwLm1hc2spKQ0KYGBgDQoNCmBgYHtyfQ0KI2luc3RhbGwucGFja2FnZXMoImh0bWx0b29scyIpDQpsaWJyYXJ5KGh0bWx0b29scykNCmxpYnJhcnkobGVhZmxldC5leHRyYXMpDQpgYGANCg0KDQpgYGB7cn0NCiMgUHJpbWVybyBwcmVwYXJhciBsZWFmbGV0IHBsb3QgLi4uDQpscGxvdCA8LSBsZWFmbGV0KGRhdGEgPSBwcmVjaXAyKSAlPiUgIyBkYXRhID0gY3VlcnBvIG9yaWdpbmFsIC0gcGFyYSBvYnRlbmVyIGVsIHpvb20gY29ycmVjdG8NCiAgYWRkUHJvdmlkZXJUaWxlcygiQ2FydG9EQi5Qb3NpdHJvbiIpICU+JSANCiAgYWRkUmFzdGVySW1hZ2UocHJlY2lwLm1hc2ssIGNvbG9ycyA9IHBhbCwgb3BhY2l0eSA9IDAuNikgJT4lDQogIGFkZENpcmNsZU1hcmtlcnMoZGF0YSA9IHB0cmFpbiwgIyBwcmltZXIgZ3J1cG8NCiAgICAgICAgICAgICAgICAgICByYWRpdXMgPSAxLA0KICAgICAgICAgICAgICAgICAgIGZpbGxPcGFjaXR5ID0gLjcsDQogICAgICAgICAgICAgICAgICAgc3Ryb2tlID0gRkFMU0UsDQogICAgICAgICAgICAgICAgICAgcG9wdXAgPSB+aHRtbEVzY2FwZShwcmVjaXBpdGFjaW9uZXMpLA0KICAgICAgICAgICAgICAgICAgIGNvbG9yID0gcGFsKHB0b3NfdHJhaW4kcHJlY2lwaXRhY2lvbmVzKSwgIyB1c2FuZG8gdW5hIHBhbGV0YSB5YSBjcmVhZGENCiAgICAgICAgICAgICAgICAgICBjbHVzdGVyT3B0aW9ucyA9IG1hcmtlckNsdXN0ZXJPcHRpb25zKCksDQogICAgICAgICAgICAgICAgICAgZ3JvdXAgPSAiVHJhaW5pbmciKSAlPiUgDQogIGFkZENpcmNsZU1hcmtlcnMoZGF0YSA9IHB0ZXN0LCAjIHNlZ3VuZG8gZ3J1cG8NCiAgICAgICAgICAgICAgICAgICByYWRpdXMgPSAxMCwNCiAgICAgICAgICAgICAgICAgICBmaWxsT3BhY2l0eSA9IC43LA0KICAgICAgICAgICAgICAgICAgIHN0cm9rZSA9IEZBTFNFLA0KICAgICAgICAgICAgICAgICAgIHBvcHVwID0gfmh0bWxFc2NhcGUocHJlY2lwaXRhY2lvbmVzKSwNCiAgICAgICAgICAgICAgICAgICBjb2xvciA9IHBhbChwdG9zX3Rlc3QkcHJlY2lwaXRhY2lvbmVzKSwgIyB1c2luZyBhbHJlYWR5IGNyZWF0ZWQgcGFsZXR0ZQ0KICAgICAgICAgICAgICAgICAgIGNsdXN0ZXJPcHRpb25zID0gbWFya2VyQ2x1c3Rlck9wdGlvbnMoKSwNCiAgICAgICAgICAgICAgICAgICBncm91cCA9ICJUZXN0IikgJT4lIA0KICBhZGRMZWdlbmQocG9zaXRpb24gPSAiYm90dG9tcmlnaHQiLA0KICAgICAgICAgICAgdmFsdWVzID0gfnByZWNpcGl0YWNpb25lcywNCiAgICAgICAgICAgIG9wYWNpdHkgPSAuNywNCiAgICAgICAgICAgIHBhbCA9IHBhbCwgIyBwYWxldHRlIGRlY2xhcmVkIHByZXZpb3VzbHkNCiAgICAgICAgICAgIHRpdGxlID0gIkNISVJQUyBwcmVjaXBpdGFjaW9uZXMgZW4gTWV0YSBcbmRlc2RlIDI2LjAzLiBoYXN0YSAzMC4wMyBlbiAyMDIwIFttbV0iKSAlPiUgDQogIGxlYWZsZXQ6OmFkZExheWVyc0NvbnRyb2wob3ZlcmxheUdyb3VwcyA9IGMoIlRyYWluaW5nIiwgIlRlc3QiKSwNCiAgICAgICAgICAgICAgICAgICBvcHRpb25zID0gbGF5ZXJzQ29udHJvbE9wdGlvbnMoY29sbGFwc2VkID0gRkFMU0UpKSAlPiUgDQogIGFkZFJlc2V0TWFwQnV0dG9uKCkNCmBgYA0KDQpgYGB7cn0NCmxwbG90ICMgIC4uLiBkaXNwbGF5IHRoZSBtYXANCmBgYA0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg==