Este documento es un Notebook de R Markdown. En principio, cuando se ejecuta un trozo de código los resultados se ven debajo del mismo.

Está basado en un documento desarrollado por Robin Lovelace (R.Lovelace@leeds.ac.uk), James Cheshire, Rachel Oldroyd y otros dentro del contexto de la vista espacial del repositorio CRAN https://cran.r-project.org/doc/contrib/intro-spatial-rl.pdf

Comenzamos cargando las librerías necesarias

x <- c("ggmap", "rgdal", "rgeos", "maptools", "dplyr", "tidyr", "tmap","sf")
x
[1] "ggmap"    "rgdal"    "rgeos"    "maptools" "dplyr"    "tidyr"    "tmap"     "sf"      
lapply(x, library, character.only = TRUE) # load the required packages
Google Maps API Terms of Service: http://developers.google.com/maps/terms.
Please cite ggmap if you use it: see citation('ggmap') for details.
package ‘rgdal’ was built under R version 3.4.3rgdal: version: 1.2-16, (SVN revision 701)
 Geospatial Data Abstraction Library extensions to R successfully loaded
 Loaded GDAL runtime: GDAL 2.1.3, released 2017/20/01
 Path to GDAL shared files: /Users/agus/Library/R/3.4/library/rgdal/gdal
 GDAL binary built with GEOS: FALSE 
 Loaded PROJ.4 runtime: Rel. 4.9.3, 15 August 2016, [PJ_VERSION: 493]
 Path to PROJ.4 shared files: /Users/agus/Library/R/3.4/library/rgdal/proj
 Linking to sp version: 1.2-5 
package ‘rgeos’ was built under R version 3.4.2rgeos version: 0.3-26, (SVN revision 560)
 GEOS runtime version: 3.6.1-CAPI-1.10.1 r0 
 Linking to sp version: 1.2-5 
 Polygon checking: TRUE 

Checking rgeos availability: TRUE
package ‘dplyr’ was built under R version 3.4.2
Attaching package: ‘dplyr’

The following objects are masked from ‘package:rgeos’:

    intersect, setdiff, union

The following objects are masked from ‘package:stats’:

    filter, lag

The following objects are masked from ‘package:base’:

    intersect, setdiff, setequal, union

package ‘tidyr’ was built under R version 3.4.3package ‘tmap’ was built under R version 3.4.3package ‘sf’ was built under R version 3.4.3Linking to GEOS 3.6.1, GDAL 2.1.3, proj.4 4.9.3
[[1]]
 [1] "ggmap"     "ggrepel"   "ggplot2"   "knitr"     "RJSONIO"   "sp"        "stats"    
 [8] "graphics"  "grDevices" "utils"     "datasets"  "methods"   "base"     

[[2]]
 [1] "rgdal"     "ggmap"     "ggrepel"   "ggplot2"   "knitr"     "RJSONIO"   "sp"       
 [8] "stats"     "graphics"  "grDevices" "utils"     "datasets"  "methods"   "base"     

[[3]]
 [1] "rgeos"     "rgdal"     "ggmap"     "ggrepel"   "ggplot2"   "knitr"     "RJSONIO"  
 [8] "sp"        "stats"     "graphics"  "grDevices" "utils"     "datasets"  "methods"  
[15] "base"     

[[4]]
 [1] "maptools"  "rgeos"     "rgdal"     "ggmap"     "ggrepel"   "ggplot2"   "knitr"    
 [8] "RJSONIO"   "sp"        "stats"     "graphics"  "grDevices" "utils"     "datasets" 
[15] "methods"   "base"     

[[5]]
 [1] "dplyr"     "maptools"  "rgeos"     "rgdal"     "ggmap"     "ggrepel"   "ggplot2"  
 [8] "knitr"     "RJSONIO"   "sp"        "stats"     "graphics"  "grDevices" "utils"    
[15] "datasets"  "methods"   "base"     

[[6]]
 [1] "tidyr"     "dplyr"     "maptools"  "rgeos"     "rgdal"     "ggmap"     "ggrepel"  
 [8] "ggplot2"   "knitr"     "RJSONIO"   "sp"        "stats"     "graphics"  "grDevices"
[15] "utils"     "datasets"  "methods"   "base"     

[[7]]
 [1] "tmap"      "tidyr"     "dplyr"     "maptools"  "rgeos"     "rgdal"     "ggmap"    
 [8] "ggrepel"   "ggplot2"   "knitr"     "RJSONIO"   "sp"        "stats"     "graphics" 
[15] "grDevices" "utils"     "datasets"  "methods"   "base"     

[[8]]
 [1] "sf"        "tmap"      "tidyr"     "dplyr"     "maptools"  "rgeos"     "rgdal"    
 [8] "ggmap"     "ggrepel"   "ggplot2"   "knitr"     "RJSONIO"   "sp"        "stats"    
[15] "graphics"  "grDevices" "utils"     "datasets"  "methods"   "base"     

Una vez que tenemos los paquetes vamos a cargar algunos datos, de momento los cogeremos de:

https://github.com/Robinlovelace/Creating-maps-in-R Una vez descargados y descomprimidos ya estamos listos para cargarlos en nuestro proyecto. Daros cuenta de que además de cargar los datos estamos poniendo una serie de condiciones en los mismos, la primera que los enteros de 64 bits nos los convierta en enteros de 32 bits (la opción contraria sería convertirlos a texto) y la segunda es que los atributos de texto no sean factores.

#setwd("/Users/agus/Documents/curso_r/Creating-maps-in-R-master/data")
#lnd <- readOGR(dsn = ".", layer = "london_sport", integer64="allow.loss",stringsAsFactors = FALSE)
#save(lnd, file="lnd.Rdata")
load("/Users/agus/Documents/curso_r/Creating-maps-in-R-master/vignettes/data/lnd.RData")

En la segunda línea del código anterior, la función readOGR se usa para cargar un archivo sho y asignarlo a un nuevo objeto espacial llamado “lnd”; abreviatura de Londres. readOGR es una función que acepta dos argumentos: dsn que significa “nombre de fuente de datos” y especifica el directorio en el que se almacena el archivo, y la capa que especifica el nombre del archivo (tened en cuenta que no es necesario incluir la extensión de archivo .shp ) Los argumentos están separados por una coma y el orden en que se especifican es importante. No hay que escribir explícitamente dsn = o layer = como R sabe qué orden aparecen, por lo que readOGR (“datos”, “london_sport”) funcionaría igual de bien. Para mayor claridad, es una buena práctica incluir nombres de argumento al aprender nuevas funciones, así que continuaremos haciéndolo. El archivo que le asignamos al objeto Lnd contiene la población de los distritos londinenses en 2001 y el porcentaje de la población que participa en actividades deportivas. Estos datos provienen de la Encuesta de personas activas. Los datos de límites provienen de la Ordenance Survey equivalente a nuestro IGN. Para obtener información sobre cómo cargar diferentes tipos de datos espaciales, consultad la documentación de ayuda para readOGR. Se puede llegar a ella escribiendo: ? ReadOGR Para otro ejemplo, en el que se carga una traza de GPS, vea Cheshire y Lovelace (2014).

Los objetos espaciales como ‘Lnd’ están formados por bloques diferentes, los bloques clave son @data (datos de atributos no geográficos) y @polygons (o @lines para datos de línea). El bloque de datos puede considerarse como una tabla de atributos y el de geometría son los polígonos que conforman los límites físicos. A cada uno de ellos se puede acceder usando el símbolo @. Analicemos ahora el objeto ‘lndp’ con algunos comandos básicos:

Siempre podemos conventir los atributos a datos de otra clase

lnd$Pop_2001 <- as.numeric(as.character(lnd$Pop_2001))

Ahora que ya tenemos más o menos claro lo que hay en el archivo vamos a hacer una primera impresión.

plot(lnd)

El que este familiarizado con Londres a lo mejor lo entiende. Como hemos visto en sesiones anteriores una de las cosas buenas que tiene R es la capacidad de seleccionar datos. Por ejemplo, podríamos seleccionar los distritos en los que la participación es inferior al 15%

Pero claro ya que hemos llegado hasta aquí lo que nos gustaría es hacer un mapa que cumpla determinadas condiciones. Vamos a tratar de dibujar los distritos en los que el índice de participación es entre el 20 y 25 %

head(sel) # test output of previous selection (not shown)
[1]  TRUE FALSE  TRUE FALSE  TRUE FALSE

Pero claro ahora, yo que conozco poco Londres, no tengo idea de donde están esos barrios. Por ello, lo mejor sería ponerlos encima del mapa base y pintarlos con algún color. Eso se puede hacer de diferentes maneras pero una es superponiendo el segundo gráfico al primero.

plot(lnd, col = "darkgrey") # plot the london_sport object
sel <- lnd$Partic_Per > 25
plot(lnd[ sel, ], col = "red", add = TRUE) # add selected zones to map

Ahora vamos a ver cuantos de esos distritos están cerca del centro de Londres, para ello calcularemos un radio de 10 Km y lo añadiremos a nuestro mapa. Pero vayamos por partes, primero hallamos el centro de Londres.

file.edit("data/intro-spatial.Rmd")
lat <- coordinates(gCentroid(lnd))[[1]]
long <- coordinates(gCentroid(lnd))[[2]]
longlat<-cbind(long,lat)

Vamos a tratar de quedarnos solo con los distritos que están cerca del centro, una vez hemos hallado el centro, solo tenemos que hacer un área de influencia de 10 Km a su alrededor.

SpatialPoints(coords=cbind(long,lat))
class       : SpatialPoints 
features    : 1 
extent      : 179643.4, 179643.4, 531334, 531334  (xmin, xmax, ymin, ymax)
coord. ref. : NA 
gb<-gBuffer(SpatialPoints(coords=cbind(lat,long)),width=10000,byid = FALSE)
gb@proj4string<-lnd@proj4string
lnd@proj4string
CRS arguments:
 +proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 +x_0=400000 +y_0=-100000 +ellps=airy
+units=m +no_defs 
plot(lnd)
plot(lnd[ sel, ], col = "turquoise", add = TRUE)
plot(gb,add=TRUE,border=2,lwd=2)

También podemos recortarlos

require(raster)
#plot(intersect(gb,lnd))
plot(gIntersection(gb, lnd))
plot(lnd[ sel, ], col = "turquoise", add = TRUE)

En este caso el resultado es el que buscábamos pero no siempre tiene porque se así. Para eso tenemos que instalar otros paquetes

require(devtools)
Loading required package: devtools
package ‘devtools’ was built under R version 3.4.3
#devtools::install_github("tidyverse/ggplot2")

Ahora podemos intentar dibujar lo que que queríamos haciendo uso de objetos ‘sf’ que puede que sean el futuro de los objetos espaciales en R. Primero dibujamos todos los porcentajes, luego los barrios ‘tocados’ por la selección

plot(st_join(st_as_sf(lnd[,3]),st_as_sf(gb), left = TRUE)) # Sale el conjunto completo

plot(st_join(st_as_sf(lnd[,3]),st_as_sf(gb), left = FALSE))

plot(st_join(st_as_sf(lnd[ sel, ][3]),st_as_sf(gb), left = TRUE))
n same as number of different finite values\neach different finite value is a separate class

plot(st_join(st_as_sf(lnd[ sel, ][3]),st_as_sf(gb), left = FALSE))
n same as number of different finite values\neach different finite value is a separate class
plot(gb,add=TRUE,border=2,lwd=2)
plot(lnd,add=TRUE)

Cuadrantes También podemos hallar los cuadrantes de forma más o menos sencilla, hay paquetes que lo hacen de otra forma, basándonos simplemente en las coordenadas del centro

east <- sapply(coordinates(lnd)[,1], function(x) x > lat)
north <- sapply(coordinates(lnd)[,2], function(x) x > long)

Añadimos esa información a la tabla de atributos

lnd@data$quadrant[east & north] <- "northeast"

Comprobamos que hemos obtenido el resultado que queríamos

lnd@data$quadrant
 [1] NA          NA          NA          "northeast" NA          NA          NA         
 [8] NA          NA          NA          NA          NA          NA          NA         
[15] NA          NA          NA          NA          NA          NA          "northeast"
[22] "northeast" "northeast" NA          "northeast" "northeast" "northeast" NA         
[29] NA          NA          NA          "northeast" "northeast"

Hacemos lo mimos con el resto de cuadrantes

west <- sapply(coordinates(lnd)[,1], function(x) x < lat)
south <- sapply(coordinates(lnd)[,2], function(x) x < long)
lnd@data$quadrant[east & south] <- "southeast"
lnd@data$quadrant[west & north] <- "northwest"
lnd@data$quadrant[south & west] <- "southwest"

Comprobamos el resultado final.

lnd@data$quadrant
 [1] "southeast" "southwest" "northwest" "northeast" "southwest" "southwest" "southwest"
 [8] "southwest" "southwest" "southeast" "southwest" "southeast" "southeast" "southeast"
[15] "northwest" "southwest" "northwest" "northwest" "northwest" "northwest" "northeast"
[22] "northeast" "northeast" "northwest" "northeast" "northeast" "northeast" "southeast"
[29] "southwest" "northwest" "northwest" "northeast" "northeast"

Ya estamos listo para dibujar los cuadrantes. Para ello, convertimos la información en factorial y usamos esos valores para escoger los colores de cada cuadrante, si usamos los mismos valores para dibujar los límites conseguimos un efecto de continuidad que no esta en los datos. Le ponemos algunos adornos.

plot(lnd,col=as.factor(lnd@data$quadrant),border=as.factor(lnd@data$quadrant))
box()
grid()
title("Cuadrantes geográficos", xlab="Este-Oeste",
   ylab="Sur-Norte")
for (i in c(1,2,4))
    {axis(i)}

LS0tCnRpdGxlOiAiRGF0b3MgZXNwYWNpYWxlcyBjb24gUiIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQKICBodG1sX2RvY3VtZW50OgogICAgZGZfcHJpbnQ6IHBhZ2VkCiAgcGRmX2RvY3VtZW50OiBkZWZhdWx0Ci0tLQoKRXN0ZSBkb2N1bWVudG8gZXMgdW4gTm90ZWJvb2sgZGUgW1IgTWFya2Rvd25dKGh0dHA6Ly9ybWFya2Rvd24ucnN0dWRpby5jb20pLiAgRW4gcHJpbmNpcGlvLCBjdWFuZG8gc2UgZWplY3V0YSB1biB0cm96byBkZSBjw7NkaWdvIGxvcyByZXN1bHRhZG9zIHNlIHZlbiBkZWJham8gZGVsIG1pc21vLgoKRXN0w6EgYmFzYWRvIGVuIHVuIGRvY3VtZW50byBkZXNhcnJvbGxhZG8gcG9yIFJvYmluIExvdmVsYWNlIChSLkxvdmVsYWNlQGxlZWRzLmFjLnVrKSwgSmFtZXMgQ2hlc2hpcmUsIFJhY2hlbCBPbGRyb3lkIHkgb3Ryb3MgZGVudHJvIGRlbCBjb250ZXh0byBkZSBsYSB2aXN0YSBlc3BhY2lhbCBkZWwgcmVwb3NpdG9yaW8gQ1JBTgpodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy9kb2MvY29udHJpYi9pbnRyby1zcGF0aWFsLXJsLnBkZgoKQ29tZW56YW1vcyBjYXJnYW5kbyBsYXMgbGlicmVyw61hcyBuZWNlc2FyaWFzCmBgYHtyLCBlY2hvPVRSVUV9CnggPC0gYygiZ2dtYXAiLCAicmdkYWwiLCAicmdlb3MiLCAibWFwdG9vbHMiLCAiZHBseXIiLCAidGlkeXIiLCAidG1hcCIsInNmIikKeApsYXBwbHkoeCwgbGlicmFyeSwgY2hhcmFjdGVyLm9ubHkgPSBUUlVFKSAjIGxvYWQgdGhlIHJlcXVpcmVkIHBhY2thZ2VzCmBgYAoKVW5hIHZleiBxdWUgdGVuZW1vcyBsb3MgcGFxdWV0ZXMgdmFtb3MgYSBjYXJnYXIgYWxndW5vcyBkYXRvcywgZGUgbW9tZW50byBsb3MgY29nZXJlbW9zIGRlOgoKaHR0cHM6Ly9naXRodWIuY29tL1JvYmlubG92ZWxhY2UvQ3JlYXRpbmctbWFwcy1pbi1SClVuYSB2ZXogZGVzY2FyZ2Fkb3MgeSBkZXNjb21wcmltaWRvcyB5YSBlc3RhbW9zIGxpc3RvcyBwYXJhIGNhcmdhcmxvcyBlbiBudWVzdHJvIHByb3llY3RvLgpEYXJvcyBjdWVudGEgZGUgcXVlIGFkZW3DoXMgZGUgY2FyZ2FyIGxvcyBkYXRvcyBlc3RhbW9zIHBvbmllbmRvIHVuYSBzZXJpZSBkZSBjb25kaWNpb25lcyBlbiBsb3MgbWlzbW9zLCBsYSBwcmltZXJhIHF1ZSBsb3MgZW50ZXJvcyBkZSA2NCBiaXRzIG5vcyBsb3MgY29udmllcnRhIGVuIGVudGVyb3MgZGUgMzIgYml0cyAobGEgb3BjacOzbiBjb250cmFyaWEgc2Vyw61hIGNvbnZlcnRpcmxvcyBhIHRleHRvKSB5IGxhIHNlZ3VuZGEgZXMgcXVlIGxvcyBhdHJpYnV0b3MgZGUgdGV4dG8gbm8gc2VhbiBmYWN0b3Jlcy4KCmBgYHtyfQojc2V0d2QoIi9Vc2Vycy9hZ3VzL0RvY3VtZW50cy9jdXJzb19yL0NyZWF0aW5nLW1hcHMtaW4tUi1tYXN0ZXIvZGF0YSIpCiNsbmQgPC0gcmVhZE9HUihkc24gPSAiLiIsIGxheWVyID0gImxvbmRvbl9zcG9ydCIsIGludGVnZXI2ND0iYWxsb3cubG9zcyIsc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQojc2F2ZShsbmQsIGZpbGU9ImxuZC5SZGF0YSIpCmxvYWQoIi9Vc2Vycy9hZ3VzL0RvY3VtZW50cy9jdXJzb19yL0NyZWF0aW5nLW1hcHMtaW4tUi1tYXN0ZXIvdmlnbmV0dGVzL2RhdGEvbG5kLlJEYXRhIikKYGBgCgpFbiBsYSBzZWd1bmRhIGzDrW5lYSBkZWwgY8OzZGlnbyBhbnRlcmlvciwgbGEgZnVuY2nDs24gcmVhZE9HUiBzZSB1c2EgcGFyYSBjYXJnYXIgdW4gYXJjaGl2byBzaG8geSBhc2lnbmFybG8gYSB1biBudWV2byBvYmpldG8gZXNwYWNpYWwgbGxhbWFkbyAibG5kIjsgYWJyZXZpYXR1cmEgZGUgTG9uZHJlcy4gcmVhZE9HUiBlcyB1bmEgZnVuY2nDs24gcXVlIGFjZXB0YSBkb3MgYXJndW1lbnRvczogZHNuIHF1ZSBzaWduaWZpY2EgIm5vbWJyZSBkZSBmdWVudGUgZGUgZGF0b3MiIHkgZXNwZWNpZmljYSBlbCBkaXJlY3RvcmlvIGVuIGVsIHF1ZSBzZSBhbG1hY2VuYSBlbCBhcmNoaXZvLCB5IGxhIGNhcGEgcXVlIGVzcGVjaWZpY2EgZWwgbm9tYnJlIGRlbCBhcmNoaXZvICh0ZW5lZCBlbiBjdWVudGEgcXVlIG5vIGVzIG5lY2VzYXJpbyBpbmNsdWlyIGxhIGV4dGVuc2nDs24gZGUgYXJjaGl2byAuc2hwICkgTG9zIGFyZ3VtZW50b3MgZXN0w6FuIHNlcGFyYWRvcyBwb3IgdW5hIGNvbWEgeSBlbCBvcmRlbiBlbiBxdWUgc2UgZXNwZWNpZmljYW4gZXMgaW1wb3J0YW50ZS4gTm8gaGF5IHF1ZSBlc2NyaWJpciBleHBsw61jaXRhbWVudGUgZHNuID0gbyBsYXllciA9IGNvbW8gUiBzYWJlIHF1w6kgb3JkZW4gYXBhcmVjZW4sIHBvciBsbyBxdWUgcmVhZE9HUiAoImRhdG9zIiwgImxvbmRvbl9zcG9ydCIpIGZ1bmNpb25hcsOtYSBpZ3VhbCBkZSBiaWVuLiBQYXJhIG1heW9yIGNsYXJpZGFkLCBlcyB1bmEgYnVlbmEgcHLDoWN0aWNhIGluY2x1aXIgbm9tYnJlcyBkZSBhcmd1bWVudG8gYWwgYXByZW5kZXIgbnVldmFzIGZ1bmNpb25lcywgYXPDrSBxdWUgY29udGludWFyZW1vcyBoYWNpw6luZG9sby4KRWwgYXJjaGl2byBxdWUgbGUgYXNpZ25hbW9zIGFsIG9iamV0byBMbmQgY29udGllbmUgbGEgcG9ibGFjacOzbiBkZSBsb3MgZGlzdHJpdG9zIGxvbmRpbmVuc2VzIGVuIDIwMDEgeSBlbCBwb3JjZW50YWplIGRlIGxhIHBvYmxhY2nDs24gcXVlIHBhcnRpY2lwYSBlbiBhY3RpdmlkYWRlcyBkZXBvcnRpdmFzLiBFc3RvcyBkYXRvcyBwcm92aWVuZW4gZGUgbGEgRW5jdWVzdGEgZGUgcGVyc29uYXMgYWN0aXZhcy4gTG9zIGRhdG9zIGRlIGzDrW1pdGVzIHByb3ZpZW5lbiBkZSBsYSBPcmRlbmFuY2UgU3VydmV5IGVxdWl2YWxlbnRlIGEgbnVlc3RybyBJR04uClBhcmEgb2J0ZW5lciBpbmZvcm1hY2nDs24gc29icmUgY8OzbW8gY2FyZ2FyIGRpZmVyZW50ZXMgdGlwb3MgZGUgZGF0b3MgZXNwYWNpYWxlcywgY29uc3VsdGFkIGxhIGRvY3VtZW50YWNpw7NuIGRlIGF5dWRhIHBhcmEgcmVhZE9HUi4gU2UgcHVlZGUgbGxlZ2FyIGEgZWxsYSBlc2NyaWJpZW5kbzoKPyBSZWFkT0dSClBhcmEgb3RybyBlamVtcGxvLCBlbiBlbCBxdWUgc2UgY2FyZ2EgdW5hIHRyYXphIGRlIEdQUywgdmVhIENoZXNoaXJlIHkgTG92ZWxhY2UgKDIwMTQpLgoKTG9zIG9iamV0b3MgZXNwYWNpYWxlcyBjb21vICdMbmQnIGVzdMOhbiBmb3JtYWRvcyBwb3IgYmxvcXVlcyBkaWZlcmVudGVzLCBsb3MgYmxvcXVlcyBjbGF2ZSBzb24gQGRhdGEgKGRhdG9zIGRlIGF0cmlidXRvcyBubyBnZW9ncsOhZmljb3MpIHkgQHBvbHlnb25zIChvIEBsaW5lcyBwYXJhIGRhdG9zIGRlIGzDrW5lYSkuIEVsIGJsb3F1ZSBkZSBkYXRvcyBwdWVkZSBjb25zaWRlcmFyc2UgY29tbyB1bmEgdGFibGEgZGUgYXRyaWJ1dG9zIHkgZWwgZGUgZ2VvbWV0csOtYSBzb24gbG9zIHBvbMOtZ29ub3MgcXVlIGNvbmZvcm1hbiBsb3MgbMOtbWl0ZXMgZsOtc2ljb3MuIEEgY2FkYSB1bm8gZGUgZWxsb3Mgc2UgcHVlZGUgYWNjZWRlciB1c2FuZG8gZWwgc8OtbWJvbG8gQC4gQW5hbGljZW1vcyBhaG9yYSBlbCBvYmpldG8gJ2xuZHAnIGNvbiBhbGd1bm9zIGNvbWFuZG9zIGLDoXNpY29zOgpgYGB7cn0Kc3RyKGxuZCkKaGVhZChsbmRAZGF0YSwgbiA9IDcpCnJvdW5kKG1lYW4obG5kJFBhcnRpY19QZXIpLDIpICMgc2hvcnQgZm9yIG1lYW4obG5kQGRhdGEkUGFydGljX1BlcikKc2FwcGx5KGxuZEBkYXRhLCBjbGFzcykKYGBgClNpZW1wcmUgcG9kZW1vcyBjb252ZW50aXIgbG9zIGF0cmlidXRvcyBhIGRhdG9zIGRlIG90cmEgY2xhc2UKYGBge3J9CmxuZCRQb3BfMjAwMSA8LSBhcy5udW1lcmljKGFzLmNoYXJhY3RlcihsbmQkUG9wXzIwMDEpKQpgYGAKQWhvcmEgcXVlIHlhIHRlbmVtb3MgbcOhcyBvIG1lbm9zIGNsYXJvIGxvIHF1ZSBoYXkgZW4gZWwgYXJjaGl2byB2YW1vcyBhIGhhY2VyIHVuYSBwcmltZXJhIGltcHJlc2nDs24uCmBgYHtyfQpwbG90KGxuZCkKYGBgCkVsIHF1ZSBlc3RlIGZhbWlsaWFyaXphZG8gY29uIExvbmRyZXMgYSBsbyBtZWpvciBsbyBlbnRpZW5kZS4gCkNvbW8gaGVtb3MgdmlzdG8gZW4gc2VzaW9uZXMgYW50ZXJpb3JlcyB1bmEgZGUgbGFzIGNvc2FzIGJ1ZW5hcyBxdWUgdGllbmUgUiBlcyBsYSBjYXBhY2lkYWQgZGUgc2VsZWNjaW9uYXIgZGF0b3MuIFBvciBlamVtcGxvLCBwb2Ryw61hbW9zIHNlbGVjY2lvbmFyIGxvcyBkaXN0cml0b3MgZW4gbG9zIHF1ZSBsYSBwYXJ0aWNpcGFjacOzbiBlcyBpbmZlcmlvciBhbCAxNSUKYGBge3J9CmxuZEBkYXRhW2xuZCRQYXJ0aWNfUGVyIDwgMTUsIF0KYGBgClBlcm8gY2xhcm8geWEgcXVlIGhlbW9zIGxsZWdhZG8gaGFzdGEgYXF1w60gbG8gcXVlIG5vcyBndXN0YXLDrWEgZXMgaGFjZXIgdW4gbWFwYSBxdWUgY3VtcGxhIGRldGVybWluYWRhcyBjb25kaWNpb25lcy4gVmFtb3MgYSB0cmF0YXIgZGUgZGlidWphciBsb3MgZGlzdHJpdG9zIGVuIGxvcyBxdWUgZWwgw61uZGljZSBkZSBwYXJ0aWNpcGFjacOzbiBlcyBlbnRyZSBlbCAyMCB5IDI1ICUKYGBge3J9CnNlbCA8LSBsbmQkUGFydGljX1BlciA+IDIwICYgbG5kJFBhcnRpY19QZXIgPCAyNQpwbG90KGxuZFtzZWwsIF0pICMgb3V0cHV0IG5vdCBzaG93biBoZXJlCmhlYWQoc2VsKSAjIHRlc3Qgb3V0cHV0IG9mIHByZXZpb3VzIHNlbGVjdGlvbiAobm90IHNob3duKQpgYGAKUGVybyBjbGFybyBhaG9yYSwgeW8gcXVlIGNvbm96Y28gcG9jbyBMb25kcmVzLCBubyB0ZW5nbyBpZGVhIGRlIGRvbmRlIGVzdMOhbiBlc29zIGJhcnJpb3MuIFBvciBlbGxvLCBsbyBtZWpvciBzZXLDrWEgcG9uZXJsb3MgZW5jaW1hIGRlbCBtYXBhIGJhc2UgeSBwaW50YXJsb3MgY29uIGFsZ8O6biBjb2xvci4gRXNvIHNlIHB1ZWRlIGhhY2VyIGRlIGRpZmVyZW50ZXMgbWFuZXJhcyBwZXJvIHVuYSBlcyBzdXBlcnBvbmllbmRvIGVsIHNlZ3VuZG8gZ3LDoWZpY28gYWwgcHJpbWVyby4KYGBge3J9CnBsb3QobG5kLCBjb2wgPSAiZGFya2dyZXkiKSAjIHBsb3QgdGhlIGxvbmRvbl9zcG9ydCBvYmplY3QKc2VsIDwtIGxuZCRQYXJ0aWNfUGVyID4gMjUKcGxvdChsbmRbIHNlbCwgXSwgY29sID0gInJlZCIsIGFkZCA9IFRSVUUpICMgYWRkIHNlbGVjdGVkIHpvbmVzIHRvIG1hcApgYGAKQWhvcmEgdmFtb3MgYSB2ZXIgY3VhbnRvcyBkZSBlc29zIGRpc3RyaXRvcyBlc3TDoW4gY2VyY2EgZGVsIGNlbnRybyBkZSBMb25kcmVzLCBwYXJhIGVsbG8gY2FsY3VsYXJlbW9zIHVuIHJhZGlvIGRlIDEwIEttIHkgbG8gYcOxYWRpcmVtb3MgYSBudWVzdHJvIG1hcGEuIFBlcm8gdmF5YW1vcyBwb3IgcGFydGVzLCBwcmltZXJvIGhhbGxhbW9zIGVsIGNlbnRybyBkZSBMb25kcmVzLgpgYGB7cn0KZmlsZS5lZGl0KCJkYXRhL2ludHJvLXNwYXRpYWwuUm1kIikKbGF0IDwtIGNvb3JkaW5hdGVzKGdDZW50cm9pZChsbmQpKVtbMV1dCmxvbmcgPC0gY29vcmRpbmF0ZXMoZ0NlbnRyb2lkKGxuZCkpW1syXV0KbG9uZ2xhdDwtY2JpbmQobG9uZyxsYXQpCmBgYApWYW1vcyBhIHRyYXRhciBkZSBxdWVkYXJub3Mgc29sbyBjb24gbG9zIGRpc3RyaXRvcyBxdWUgZXN0w6FuIGNlcmNhIGRlbCBjZW50cm8sIHVuYSB2ZXogaGVtb3MgaGFsbGFkbyBlbCBjZW50cm8sIHNvbG8gdGVuZW1vcyBxdWUgaGFjZXIgdW4gw6FyZWEgZGUgaW5mbHVlbmNpYSBkZSAxMCBLbSBhIHN1IGFscmVkZWRvci4KYGBge3J9ClNwYXRpYWxQb2ludHMoY29vcmRzPWNiaW5kKGxvbmcsbGF0KSkKZ2I8LWdCdWZmZXIoU3BhdGlhbFBvaW50cyhjb29yZHM9Y2JpbmQobGF0LGxvbmcpKSx3aWR0aD0xMDAwMCxieWlkID0gRkFMU0UpCmdiQHByb2o0c3RyaW5nPC1sbmRAcHJvajRzdHJpbmcKbG5kQHByb2o0c3RyaW5nCnBsb3QobG5kKQpwbG90KGxuZFsgc2VsLCBdLCBjb2wgPSAidHVycXVvaXNlIiwgYWRkID0gVFJVRSkKcGxvdChnYixhZGQ9VFJVRSxib3JkZXI9Mixsd2Q9MikKYGBgCgpUYW1iacOpbiBwb2RlbW9zIHJlY29ydGFybG9zCmBgYHtyfQpyZXF1aXJlKHJhc3RlcikKI3Bsb3QoaW50ZXJzZWN0KGdiLGxuZCkpCnBsb3QoZ0ludGVyc2VjdGlvbihnYiwgbG5kKSkKcGxvdChsbmRbIHNlbCwgXSwgY29sID0gInR1cnF1b2lzZSIsIGFkZCA9IFRSVUUpCmBgYApFbiBlc3RlIGNhc28gZWwgcmVzdWx0YWRvIGVzIGVsIHF1ZSBidXNjw6FiYW1vcyBwZXJvIG5vIHNpZW1wcmUgdGllbmUgcG9ycXVlIHNlIGFzw60uIFBhcmEgZXNvIHRlbmVtb3MgcXVlIGluc3RhbGFyIG90cm9zIHBhcXVldGVzCgpgYGB7cn0KcmVxdWlyZShkZXZ0b29scykKI2RldnRvb2xzOjppbnN0YWxsX2dpdGh1YigidGlkeXZlcnNlL2dncGxvdDIiKQpgYGAKQWhvcmEgcG9kZW1vcyBpbnRlbnRhciBkaWJ1amFyIGxvIHF1ZSBxdWUgcXVlcsOtYW1vcyBoYWNpZW5kbyB1c28gZGUgb2JqZXRvcyAnc2YnIHF1ZSBwdWVkZSBxdWUgc2VhbiBlbCBmdXR1cm8gZGUgbG9zIG9iamV0b3MgZXNwYWNpYWxlcyBlbiBSLgpQcmltZXJvIGRpYnVqYW1vcyB0b2RvcyBsb3MgcG9yY2VudGFqZXMsCmx1ZWdvIGxvcyBiYXJyaW9zICd0b2NhZG9zJyBwb3IgbGEgc2VsZWNjacOzbgpgYGB7cn0KcGxvdChzdF9qb2luKHN0X2FzX3NmKGxuZFssM10pLHN0X2FzX3NmKGdiKSwgbGVmdCA9IFRSVUUpKSAjIFNhbGUgZWwgY29uanVudG8gY29tcGxldG8KcGxvdChzdF9qb2luKHN0X2FzX3NmKGxuZFssM10pLHN0X2FzX3NmKGdiKSwgbGVmdCA9IEZBTFNFKSkKcGxvdChzdF9qb2luKHN0X2FzX3NmKGxuZFsgc2VsLCBdWzNdKSxzdF9hc19zZihnYiksIGxlZnQgPSBUUlVFKSkKcGxvdChzdF9qb2luKHN0X2FzX3NmKGxuZFsgc2VsLCBdWzNdKSxzdF9hc19zZihnYiksIGxlZnQgPSBGQUxTRSkpCnBsb3QoZ2IsYWRkPVRSVUUsYm9yZGVyPTIsbHdkPTIpCnBsb3QobG5kLGFkZD1UUlVFKQpgYGAKQ3VhZHJhbnRlcwpUYW1iacOpbiBwb2RlbW9zIGhhbGxhciBsb3MgY3VhZHJhbnRlcyBkZSBmb3JtYSBtw6FzIG8gbWVub3Mgc2VuY2lsbGEsIGhheSBwYXF1ZXRlcyBxdWUgbG8gaGFjZW4gZGUgb3RyYSBmb3JtYSwgYmFzw6FuZG9ub3Mgc2ltcGxlbWVudGUgZW4gbGFzIGNvb3JkZW5hZGFzIGRlbCBjZW50cm8KYGBge3J9CmVhc3QgPC0gc2FwcGx5KGNvb3JkaW5hdGVzKGxuZClbLDFdLCBmdW5jdGlvbih4KSB4ID4gbGF0KQpub3J0aCA8LSBzYXBwbHkoY29vcmRpbmF0ZXMobG5kKVssMl0sIGZ1bmN0aW9uKHgpIHggPiBsb25nKQpgYGAKQcOxYWRpbW9zIGVzYSBpbmZvcm1hY2nDs24gYSBsYSB0YWJsYSBkZSBhdHJpYnV0b3MKYGBge3J9CmxuZEBkYXRhJHF1YWRyYW50W2Vhc3QgJiBub3J0aF0gPC0gIm5vcnRoZWFzdCIKYGBgCkNvbXByb2JhbW9zIHF1ZSBoZW1vcyBvYnRlbmlkbyBlbCByZXN1bHRhZG8gcXVlIHF1ZXLDrWFtb3MKCmBgYHtyfQpsbmRAZGF0YSRxdWFkcmFudApgYGAKSGFjZW1vcyBsbyBtaW1vcyBjb24gZWwgcmVzdG8gZGUgY3VhZHJhbnRlcwpgYGB7cn0Kd2VzdCA8LSBzYXBwbHkoY29vcmRpbmF0ZXMobG5kKVssMV0sIGZ1bmN0aW9uKHgpIHggPCBsYXQpCnNvdXRoIDwtIHNhcHBseShjb29yZGluYXRlcyhsbmQpWywyXSwgZnVuY3Rpb24oeCkgeCA8IGxvbmcpCmxuZEBkYXRhJHF1YWRyYW50W2Vhc3QgJiBzb3V0aF0gPC0gInNvdXRoZWFzdCIKbG5kQGRhdGEkcXVhZHJhbnRbd2VzdCAmIG5vcnRoXSA8LSAibm9ydGh3ZXN0IgpsbmRAZGF0YSRxdWFkcmFudFtzb3V0aCAmIHdlc3RdIDwtICJzb3V0aHdlc3QiCmBgYApDb21wcm9iYW1vcyBlbCByZXN1bHRhZG8gZmluYWwuCmBgYHtyfQpsbmRAZGF0YSRxdWFkcmFudApgYGAKWWEgZXN0YW1vcyBsaXN0byBwYXJhIGRpYnVqYXIgbG9zIGN1YWRyYW50ZXMuIFBhcmEgZWxsbywgY29udmVydGltb3MgbGEgaW5mb3JtYWNpw7NuIGVuIGZhY3RvcmlhbCB5IHVzYW1vcyBlc29zIHZhbG9yZXMgcGFyYSBlc2NvZ2VyIGxvcyBjb2xvcmVzIGRlIGNhZGEgY3VhZHJhbnRlLCBzaSB1c2Ftb3MgbG9zIG1pc21vcyB2YWxvcmVzIHBhcmEgZGlidWphciBsb3MgbMOtbWl0ZXMgY29uc2VndWltb3MgdW4gZWZlY3RvIGRlIGNvbnRpbnVpZGFkIHF1ZSBubyBlc3RhIGVuIGxvcyBkYXRvcy4KTGUgcG9uZW1vcyBhbGd1bm9zIGFkb3Jub3MuCmBgYHtyfQpwbG90KGxuZCxjb2w9YXMuZmFjdG9yKGxuZEBkYXRhJHF1YWRyYW50KSxib3JkZXI9YXMuZmFjdG9yKGxuZEBkYXRhJHF1YWRyYW50KSkKYm94KCkKZ3JpZCgpCnRpdGxlKCJDdWFkcmFudGVzIGdlb2dyw6FmaWNvcyIsIHhsYWI9IkVzdGUtT2VzdGUiLAogICB5bGFiPSJTdXItTm9ydGUiKQpmb3IgKGkgaW4gYygxLDIsNCkpCiAgICB7YXhpcyhpKX0KYGBgCgo=