Luisa Fernanda Carrión Ramírez 24/03/2020

Este cuaderno tiene como objetivo mostrar la utilidad de algunas funciones de R para el manejo de datos geoespaciales. Para ello, se deben instalar dos bibliotecas denominadas sf (simple features) y tidyverse. Se empezará con instalar la biblioteca “sf” con el siguiente comando:

#install.packages("sf")

Posteriormente, se instalará el paquete tidyverse de la misma manera.

#install.packages("tidyverse")

Luego, se deben cargar ambas bibliotecas empezando con sf:

library(sf)
Linking to GEOS 3.6.1, GDAL 2.2.3, PROJ 4.9.3

Se aplicará el mismo comando para la biblioteca tidyverse:

library(tidyverse)
Registered S3 method overwritten by 'dplyr':
  method           from
  print.rowwise_df     
Registered S3 methods overwritten by 'dbplyr':
  method         from
  print.tbl_lazy     
  print.tbl_sql      
-- Attaching packages --------------------------------------- tidyverse 1.3.0 --
v ggplot2 3.3.0     v purrr   0.3.3
v tibble  2.1.3     v dplyr   0.8.4
v tidyr   1.0.2     v stringr 1.4.0
v readr   1.3.1     v forcats 0.5.0
-- Conflicts ------------------------------------------ tidyverse_conflicts() --
x dplyr::filter() masks stats::filter()
x dplyr::lag()    masks stats::lag()

Lectura de datos vectoriales

En este apartado, se quiere leer un archivo shapefile previamente descargado en la página DIVA-GIS que contiene la división politica departamental de Colombia. Para ello, se emplea el siguiente comando:

deptos <- read_sf("C:/Users/LUISA CARRION/Documents/Geomática/COL_adm1.shp")

Para saber la información que el shapefile relacionada a los departamentos se procede a escribir el siguiente comando:

head(deptos)
Simple feature collection with 6 features and 9 fields
geometry type:  MULTIPOLYGON
dimension:      XY
bbox:           xmin: -77.149 ymin: -4.228429 xmax: -69.36835 ymax: 11.10792
epsg (SRID):    4326
proj4string:    +proj=longlat +datum=WGS84 +no_defs

En la biblioteca sf existe una función que permite saber cuál es el sistema de referencia de coordenadas de los datos vectoriales almacenados. En este caso, se quiere conocer esta información en el objeto deptos aplicando el siguiente comando:

st_crs(deptos)
Coordinate Reference System:
  EPSG: 4326 
  proj4string: "+proj=longlat +datum=WGS84 +no_defs"

Usando ggplot para visualizar datos geoespaciales

R nos permite gráficar los datos contenidos en un shapefile mediante la función ggplot():

ggplot()+ geom_sf(data = deptos)

Cualquier sistema de referencia de coordenadas puede ser empleado desde que este diseñado para se aplicado en la región geográfica deseada. En la página epsg.io/ se puede obtner información a cerca de que sistemas de referencia de coordenadas pueden usarse en cada país y explica brevemente en que consite.

ggplot() + geom_sf(data = deptos) + coord_sf(crs=st_crs(3978))

En el gráfico anterior se usó el CRS 3978 que es un sistema diseñado para Canadá y algunas zonas de Estados Unidos por lo cual, para trabajar en Colombia se requiere otro CRS. Al buscar en la página anteriormente mencionada, encontramos que un sistema referenciado de coordenadas referenciadas apto para este caso es el 32618. Para hacer el cambio de CRS se emplean los siguientes comandos:

deptos_utm <- st_transform(deptos, crs = st_crs(32618))
deptos_utm
Simple feature collection with 32 features and 9 fields
geometry type:  MULTIPOLYGON
dimension:      XY
bbox:           xmin: -245935.3 ymin: -469204.3 xmax: 1407491 ymax: 1763314
epsg (SRID):    32618
proj4string:    +proj=utm +zone=18 +datum=WGS84 +units=m +no_defs
ggplot() + geom_sf(data = deptos_utm)

Filtrar datos geoespaciales basados en atributos

A lo largo del semestre cada alumno investigará sobre un departamento colombiano de su elección. En mi caso en particular, escogí Casanare por lo cual, debo filtrar este departamento mediante el siguiente comando:

casanare <- deptos %>%  filter(NAME_1 == "Casanare")

Para obtener la gráfica se debe escribir:

ggplot() + geom_sf(data = casanare)

Como se requiere más información para completar el mapa de Casanare, se debe importar el archivo COL_adm2.shp. Luego, se filtra y por último se usa la función ggplot () para graficar los datos:

munic <- read_sf("C:/Users/LUISA CARRION/Documents/Geomática/COL_adm2.shp")
mun_casanare <- munic %>% filter(NAME_1 == "Casanare")
ggplot() + geom_sf(data = mun_casanare)

Si se usa el comando mun_casanare, se puede observar una tabla que nos muestra los municipios pertenecientes a Casanare:

mun_casanare
Simple feature collection with 19 features and 11 fields
geometry type:  MULTIPOLYGON
dimension:      XY
bbox:           xmin: -73.0989 ymin: 4.246699 xmax: -69.84787 ymax: 6.250501
epsg (SRID):    4326
proj4string:    +proj=longlat +datum=WGS84 +no_defs

A continuación, se quiere ponen una numeración a los municipios del departamento. Se intentó realizar este proceso con dos comandos que arrojaron error:

casanare_points <- st_centroid(mun_casanare)
st_centroid assumes attributes are constant over geometries of xst_centroid does not give correct centroids for longitude/latitude data
casanare_points <- cbind(mun_casanare, st_coordinates(st_centroid(mun_casanare$geometry)))
st_centroid does not give correct centroids for longitude/latitude data

Teniendo esto en cuenta, se optó por escribir un comando más extenso y especícico que se puede observar a continuación:

ggplot(casanare) +
    geom_sf() +
    geom_sf(data = casanare_points, fill = "mistyrose2") + 
    geom_text(data = casanare_points, aes(x=X, y=Y,label = ID_2), size = 2.3) +
    coord_sf(xlim = c(-73.5, -69.5), ylim = c(4, 6.5), expand = FALSE)

Luego, se carga la librería scales

library(scales)

Attaching package: 㤼㸱scales㤼㸲

The following object is masked from 㤼㸱package:purrr㤼㸲:

    discard

The following object is masked from 㤼㸱package:readr㤼㸲:

    col_factor

Con esta librería se puede agregar color al gráfico mediante el siguiente comando:

ggplot(casanare) + 
  geom_sf(data=casanare_points, aes(x=X, y=Y, fill =
                                       ID_2), color = "black", size = 0.50) +
  geom_text(data = casanare_points, aes(x=X, y=Y,label = ID_2), size = 2.5) +
  theme(aspect.ratio=1)+
  scale_fill_distiller(name="ID_2", palette ="YlOrRd", breaks = pretty_breaks(n = 5))+
  labs(title="Otro Mapa de Casanare")
Ignoring unknown aesthetics: x, y

En el gráfico se pueden visualizar distintos colores para cada municipio dependiendo de su número pero, no puede considerarse como un mapa real. De igual manera, es posible descargar este grafico como un pdf o un png con los siguientes comandos:

ggsave("casanare_municipios.pdf")
Saving 7 x 7 in image
ggsave("map_casanare.png", width = 6, height = 6, dpi = "screen")

**Usar leaflet para visualizar datos:

Para los siguientes pasos, es necesario instalar el paquete leaflet:

#install.packages("leaflet")

Luego, se debe rodar esta función:

library(leaflet)

Ahora, se debe convertir simple features a spatial points:

ant_points <- as(casanare_points, 'Spatial')

Usando la opción head() se puede visualizar lo que contiene el objeto casanare_points.

head(casanare_points)
Simple feature collection with 6 features and 13 fields
geometry type:  MULTIPOLYGON
dimension:      XY
bbox:           xmin: -73.0102 ymin: 4.3456 xmax: -69.92316 ymax: 6.250501
epsg (SRID):    4326
proj4string:    +proj=longlat +datum=WGS84 +no_defs
  ID_0 ISO   NAME_0 ID_1   NAME_1 ID_2       NAME_2    TYPE_2    ENGTYPE_2 NL_NAME_2 VARNAME_2         X
1   53 COL Colombia   10 Casanare  388      Aguazul Municipio Municipality      <NA>      <NA> -72.57165
2   53 COL Colombia   10 Casanare  389      Chámeza Municipio Municipality      <NA>      <NA> -72.88951
3   53 COL Colombia   10 Casanare  390 Hato Corozal Municipio Municipality      <NA>      <NA> -71.20900
4   53 COL Colombia   10 Casanare  391    La Salina Municipio Municipality      <NA>      <NA> -72.36621
5   53 COL Colombia   10 Casanare  392         Maní Municipio Municipality      <NA>      <NA> -72.23162
6   53 COL Colombia   10 Casanare  393    Monterrey Municipio Municipality      <NA>      <NA> -72.87900
         Y                       geometry
1 5.099226 MULTIPOLYGON (((-72.5075 4....
2 5.192376 MULTIPOLYGON (((-72.7872 5....
3 6.077862 MULTIPOLYGON (((-72.0873 6....
4 6.135512 MULTIPOLYGON (((-72.4195 6....
5 4.648025 MULTIPOLYGON (((-72.2622 4....
6 4.820158 MULTIPOLYGON (((-72.93552 5...

Para obtener el área de cada municipio se usa el paquete “lwgeom” que debe ser instalado con el siguiente comando:

#install.packages("lwgeom")

Luego, se debe hacer rodar la biblioteca de la siguiente manera:

library(lwgeom)
Linking to liblwgeom 3.0.0beta1 r16016, GEOS 3.6.1, PROJ 4.9.3

Ahora, se escribe el siguiente comando para conocer el área en metros cuadrados(m^2) de cada municipio que conforma Casanare:

mun_casanare$area <- st_area(mun_casanare)

Para cambiar la unidad de medida a kilometros cuadrados (km^2) se escribe:

mun_casanare$km2 <- mun_casanare$area/(1000000)

Se puede verificar este cambio escribiendo el siguiente comando:

mun_casanare$km2
Units: [m^2]
 [1]  1433.3676   328.6694  5063.0322   152.3924  3862.1055   720.9689  1046.8378  4742.7239 12435.9210
[10]   784.1395   179.3627   278.6638   495.2043  3238.2907  1105.4737  2441.8742  3037.4892   755.1099
[19]  2520.3069

Ahora, se debe cambiar de simple featuresa spatial polygons aplicando el siguiente comando:

casanare_mun <- as(mun_casanare, 'Spatial')

Usando la función head() corroboramos la información contenida en el objeto.

#head(casanare_mun)

Ahora, se crean algunos vectores:

bins <- c(0, 50, 100, 200, 300, 500, 1000, 2000, Inf)
pal <- colorBin("PuRd", domain = casanare_mun$km2, bins = bins)


labels <- mun_casanare$NAME_2

labels
 [1] "Aguazul"              "Chámeza"              "Hato Corozal"         "La Salina"           
 [5] "Maní"                 "Monterrey"            "Nunchía"              "Orocué"              
 [9] "Paz de Ariporo"       "Pore"                 "Recetor"              "Sácama"              
[13] "Sabanalarga"          "San Luis de Palenque" "Támara"               "Tauramena"           
[17] "Trinidad"             "Villanueva"           "Yopal"               

Se escribe el siguiente comando para generar un mapa:

m <- leaflet(casanare_mun) %>%
  setView(-71.8, 5.1, zoom = 7.8)  %>% addPolygons(  
  fillColor = ~pal(km2),
  weight = 2,
  opacity = 1,
  color = "white",
  dashArray = "3",
  fillOpacity = 0.7,
  highlight = highlightOptions(
    weight = 5,
    color = "#2",
    dashArray = "",
    fillOpacity = 0.7,
    bringToFront = TRUE),
  label = labels) %>%
  addLegend(pal = pal, values = ~km2, opacity = 0.7, title = NULL,
    position = "bottomright")

Se escribe la letra m en un chunck para observar el mapa:

m

Otra manera para generar un mapa de manera más sintetizada puede ser:

leaflet() %>%
  addProviderTiles(providers$Esri.WorldImagery, options= providerTileOptions(opacity = 0.99)) %>%
  addPolygons(data = casanare_mun, popup= casanare_mun$NAME_2,
    stroke = TRUE, fillOpacity = 0.25, smoothFactor = 0.25)

Ahora, nos enfocaremos en crear una ilustración para Yopal, la capital del departamento:

#library(leaflet)

En esta gráfica podemos ver un mapa normal del territorio:

l <- leaflet() %>%
  addTiles() %>% addMarkers(lng=-72.403, lat=5.327, popup="Yopal")
l  

Sin embargo, al emplear la opción de leaflet providers el gráfico puede tomar diferentes formas y verse un poc más profesionales. A continuación, se pueden ver dos ejemplos:

library(leaflet)
leaflet() %>% setView(lng = -72.4, lat = 5.35, zoom = 13) %>%
  addProviderTiles(providers$OpenTopoMap)
leaflet() %>%setView(lng = -72.4, lat = 5.35, zoom = 9)%>%
  addProviderTiles(providers$Esri.NatGeoWorldMap, options= providerTileOptions(opacity = 1))
LS0tDQp0aXRsZTogIkxlY3R1cmEsIGZpbHRyYWRvIHkgdmlzdWFsaXphY2nDs24gZGUgZGF0b3MgdmVjdG9yaWFsZXMgZ2VvZXNwYWNpYWxlcyBlbiBSIg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KTHVpc2EgRmVybmFuZGEgQ2FycmnDs24gUmFtw61yZXoNCjI0LzAzLzIwMjANCg0KRXN0ZSBjdWFkZXJubyB0aWVuZSBjb21vIG9iamV0aXZvIG1vc3RyYXIgbGEgdXRpbGlkYWQgZGUgYWxndW5hcyBmdW5jaW9uZXMgZGUgUiBwYXJhIGVsIG1hbmVqbyBkZSBkYXRvcyBnZW9lc3BhY2lhbGVzLg0KUGFyYSBlbGxvLCBzZSBkZWJlbiBpbnN0YWxhciBkb3MgYmlibGlvdGVjYXMgZGVub21pbmFkYXMgKnNmIChzaW1wbGUgZmVhdHVyZXMpKiB5ICp0aWR5dmVyc2UqLg0KU2UgZW1wZXphcsOhIGNvbiBpbnN0YWxhciBsYSBiaWJsaW90ZWNhICJzZiIgY29uIGVsIHNpZ3VpZW50ZSBjb21hbmRvOg0KYGBge3J9DQojaW5zdGFsbC5wYWNrYWdlcygic2YiKQ0KYGBgDQpQb3N0ZXJpb3JtZW50ZSwgc2UgaW5zdGFsYXLDoSBlbCBwYXF1ZXRlIHRpZHl2ZXJzZSBkZSBsYSBtaXNtYSBtYW5lcmEuDQpgYGB7cn0NCiNpbnN0YWxsLnBhY2thZ2VzKCJ0aWR5dmVyc2UiKQ0KYGBgDQpMdWVnbywgc2UgZGViZW4gY2FyZ2FyIGFtYmFzIGJpYmxpb3RlY2FzIGVtcGV6YW5kbyBjb24gKnNmKjoNCmBgYHtyfQ0KbGlicmFyeShzZikNCmBgYA0KU2UgYXBsaWNhcsOhIGVsIG1pc21vIGNvbWFuZG8gcGFyYSBsYSBiaWJsaW90ZWNhICp0aWR5dmVyc2UqOiANCmBgYHtyfQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpgYGANCioqTGVjdHVyYSBkZSBkYXRvcyB2ZWN0b3JpYWxlcyoqDQoNCkVuIGVzdGUgYXBhcnRhZG8sIHNlIHF1aWVyZSBsZWVyIHVuIGFyY2hpdm8gc2hhcGVmaWxlIHByZXZpYW1lbnRlIGRlc2NhcmdhZG8gZW4gbGEgcMOhZ2luYSBESVZBLUdJUyBxdWUgY29udGllbmUgbGEgZGl2aXNpw7NuIHBvbGl0aWNhIGRlcGFydGFtZW50YWwgZGUgQ29sb21iaWEuIFBhcmEgZWxsbywgc2UgZW1wbGVhIGVsIHNpZ3VpZW50ZSBjb21hbmRvOg0KYGBge3J9DQpkZXB0b3MgPC0gcmVhZF9zZigiQzovVXNlcnMvTFVJU0EgQ0FSUklPTi9Eb2N1bWVudHMvR2VvbcOhdGljYS9DT0xfYWRtMS5zaHAiKQ0KYGBgDQpQYXJhIHNhYmVyIGxhIGluZm9ybWFjacOzbiBxdWUgZWwgc2hhcGVmaWxlIHJlbGFjaW9uYWRhIGEgbG9zIGRlcGFydGFtZW50b3Mgc2UgcHJvY2VkZSBhIGVzY3JpYmlyIGVsIHNpZ3VpZW50ZSBjb21hbmRvOg0KYGBge3J9DQpoZWFkKGRlcHRvcykNCmBgYA0KRW4gbGEgYmlibGlvdGVjYSBzZiBleGlzdGUgdW5hIGZ1bmNpw7NuIHF1ZSBwZXJtaXRlIHNhYmVyIGN1w6FsIGVzIGVsIHNpc3RlbWEgZGUgcmVmZXJlbmNpYSBkZSBjb29yZGVuYWRhcyBkZSBsb3MgZGF0b3MgdmVjdG9yaWFsZXMgYWxtYWNlbmFkb3MuIEVuIGVzdGUgY2Fzbywgc2UgcXVpZXJlIGNvbm9jZXIgZXN0YSBpbmZvcm1hY2nDs24gZW4gZWwgb2JqZXRvIGRlcHRvcyBhcGxpY2FuZG8gZWwgc2lndWllbnRlIGNvbWFuZG86DQpgYGB7cn0NCnN0X2NycyhkZXB0b3MpDQpgYGANCioqVXNhbmRvIGdncGxvdCBwYXJhIHZpc3VhbGl6YXIgZGF0b3MgZ2VvZXNwYWNpYWxlcyoqDQoNClIgbm9zIHBlcm1pdGUgZ3LDoWZpY2FyIGxvcyBkYXRvcyBjb250ZW5pZG9zIGVuIHVuIHNoYXBlZmlsZSBtZWRpYW50ZSBsYSBmdW5jacOzbiBnZ3Bsb3QoKToNCmBgYHtyfQ0KZ2dwbG90KCkrIGdlb21fc2YoZGF0YSA9IGRlcHRvcykNCmBgYA0KQ3VhbHF1aWVyIHNpc3RlbWEgZGUgcmVmZXJlbmNpYSBkZSBjb29yZGVuYWRhcyBwdWVkZSBzZXIgZW1wbGVhZG8gZGVzZGUgcXVlIGVzdGUgZGlzZcOxYWRvIHBhcmEgc2UgYXBsaWNhZG8gZW4gbGEgcmVnacOzbiBnZW9ncsOhZmljYSBkZXNlYWRhLiBFbiBsYSBww6FnaW5hIGVwc2cuaW8vIHNlIHB1ZWRlIG9idG5lciBpbmZvcm1hY2nDs24gYSBjZXJjYSBkZSBxdWUgc2lzdGVtYXMgZGUgcmVmZXJlbmNpYSBkZSBjb29yZGVuYWRhcyBwdWVkZW4gdXNhcnNlIGVuIGNhZGEgcGHDrXMgeSBleHBsaWNhIGJyZXZlbWVudGUgZW4gcXVlIGNvbnNpdGUuIA0KYGBge3J9DQpnZ3Bsb3QoKSArIGdlb21fc2YoZGF0YSA9IGRlcHRvcykgKyBjb29yZF9zZihjcnM9c3RfY3JzKDM5NzgpKQ0KYGBgDQpFbiBlbCBncsOhZmljbyBhbnRlcmlvciBzZSB1c8OzIGVsIENSUyAzOTc4IHF1ZSBlcyB1biBzaXN0ZW1hIGRpc2XDsWFkbyBwYXJhIENhbmFkw6EgeSBhbGd1bmFzIHpvbmFzIGRlIEVzdGFkb3MgVW5pZG9zIHBvciBsbyBjdWFsLCBwYXJhIHRyYWJhamFyIGVuIENvbG9tYmlhIHNlIHJlcXVpZXJlIG90cm8gQ1JTLiANCkFsIGJ1c2NhciBlbiBsYSBww6FnaW5hIGFudGVyaW9ybWVudGUgbWVuY2lvbmFkYSwgZW5jb250cmFtb3MgcXVlIHVuIHNpc3RlbWEgcmVmZXJlbmNpYWRvIGRlIGNvb3JkZW5hZGFzIHJlZmVyZW5jaWFkYXMgYXB0byBwYXJhIGVzdGUgY2FzbyBlcyBlbCAzMjYxOC4gUGFyYSBoYWNlciBlbCBjYW1iaW8gZGUgQ1JTIHNlIGVtcGxlYW4gbG9zIHNpZ3VpZW50ZXMgY29tYW5kb3M6DQoNCmBgYHtyfQ0KZGVwdG9zX3V0bSA8LSBzdF90cmFuc2Zvcm0oZGVwdG9zLCBjcnMgPSBzdF9jcnMoMzI2MTgpKQ0KYGBgDQoNCmBgYHtyfQ0KZGVwdG9zX3V0bQ0KYGBgDQpgYGB7cn0NCmdncGxvdCgpICsgZ2VvbV9zZihkYXRhID0gZGVwdG9zX3V0bSkNCmBgYA0KKipGaWx0cmFyIGRhdG9zIGdlb2VzcGFjaWFsZXMgYmFzYWRvcyBlbiBhdHJpYnV0b3MqKg0KDQpBIGxvIGxhcmdvIGRlbCBzZW1lc3RyZSBjYWRhIGFsdW1ubyBpbnZlc3RpZ2Fyw6Egc29icmUgdW4gZGVwYXJ0YW1lbnRvIGNvbG9tYmlhbm8gZGUgc3UgZWxlY2Npw7NuLiBFbiBtaSBjYXNvIGVuIHBhcnRpY3VsYXIsIGVzY29nw60gQ2FzYW5hcmUgcG9yIGxvIGN1YWwsIGRlYm8gZmlsdHJhciBlc3RlIGRlcGFydGFtZW50byBtZWRpYW50ZSBlbCBzaWd1aWVudGUgY29tYW5kbzoNCg0KYGBge3J9DQpjYXNhbmFyZSA8LSBkZXB0b3MgJT4lICBmaWx0ZXIoTkFNRV8xID09ICJDYXNhbmFyZSIpDQpgYGANClBhcmEgb2J0ZW5lciBsYSBncsOhZmljYSBzZSBkZWJlIGVzY3JpYmlyOg0KYGBge3J9DQpnZ3Bsb3QoKSArIGdlb21fc2YoZGF0YSA9IGNhc2FuYXJlKQ0KYGBgDQpDb21vIHNlIHJlcXVpZXJlIG3DoXMgaW5mb3JtYWNpw7NuIHBhcmEgY29tcGxldGFyIGVsIG1hcGEgZGUgQ2FzYW5hcmUsIHNlIGRlYmUgaW1wb3J0YXIgZWwgYXJjaGl2byBDT0xfYWRtMi5zaHAuIEx1ZWdvLCBzZSBmaWx0cmEgeSBwb3Igw7psdGltbyBzZSB1c2EgbGEgZnVuY2nDs24gZ2dwbG90ICgpIHBhcmEgZ3JhZmljYXIgbG9zIGRhdG9zOg0KYGBge3J9DQptdW5pYyA8LSByZWFkX3NmKCJDOi9Vc2Vycy9MVUlTQSBDQVJSSU9OL0RvY3VtZW50cy9HZW9tw6F0aWNhL0NPTF9hZG0yLnNocCIpDQptdW5fY2FzYW5hcmUgPC0gbXVuaWMgJT4lIGZpbHRlcihOQU1FXzEgPT0gIkNhc2FuYXJlIikNCmdncGxvdCgpICsgZ2VvbV9zZihkYXRhID0gbXVuX2Nhc2FuYXJlKQ0KYGBgDQpTaSBzZSB1c2EgZWwgY29tYW5kbyBtdW5fY2FzYW5hcmUsIHNlIHB1ZWRlIG9ic2VydmFyIHVuYSB0YWJsYSBxdWUgbm9zIG11ZXN0cmEgbG9zIG11bmljaXBpb3MgcGVydGVuZWNpZW50ZXMgYSBDYXNhbmFyZToNCmBgYHtyfQ0KbXVuX2Nhc2FuYXJlDQpgYGANCkEgY29udGludWFjacOzbiwgc2UgcXVpZXJlIHBvbmVuIHVuYSBudW1lcmFjacOzbiBhIGxvcyBtdW5pY2lwaW9zIGRlbCBkZXBhcnRhbWVudG8uIFNlIGludGVudMOzIHJlYWxpemFyIGVzdGUgcHJvY2VzbyBjb24gZG9zIGNvbWFuZG9zIHF1ZSBhcnJvamFyb24gZXJyb3I6DQpgYGB7cn0NCmNhc2FuYXJlX3BvaW50cyA8LSBzdF9jZW50cm9pZChtdW5fY2FzYW5hcmUpDQpgYGANCg0KYGBge3J9DQpjYXNhbmFyZV9wb2ludHMgPC0gY2JpbmQobXVuX2Nhc2FuYXJlLCBzdF9jb29yZGluYXRlcyhzdF9jZW50cm9pZChtdW5fY2FzYW5hcmUkZ2VvbWV0cnkpKSkNCmBgYA0KVGVuaWVuZG8gZXN0byBlbiBjdWVudGEsIHNlIG9wdMOzIHBvciBlc2NyaWJpciB1biBjb21hbmRvIG3DoXMgZXh0ZW5zbyB5IGVzcGVjw61jaWNvIHF1ZSBzZSBwdWVkZSBvYnNlcnZhciBhIGNvbnRpbnVhY2nDs246DQoNCmBgYHtyfQ0KZ2dwbG90KGNhc2FuYXJlKSArDQogICAgZ2VvbV9zZigpICsNCiAgICBnZW9tX3NmKGRhdGEgPSBjYXNhbmFyZV9wb2ludHMsIGZpbGwgPSAibWlzdHlyb3NlMiIpICsgDQogICAgZ2VvbV90ZXh0KGRhdGEgPSBjYXNhbmFyZV9wb2ludHMsIGFlcyh4PVgsIHk9WSxsYWJlbCA9IElEXzIpLCBzaXplID0gMi4zKSArDQogICAgY29vcmRfc2YoeGxpbSA9IGMoLTczLjUsIC02OS41KSwgeWxpbSA9IGMoNCwgNi41KSwgZXhwYW5kID0gRkFMU0UpDQpgYGANCkx1ZWdvLCBzZSBjYXJnYSBsYSBsaWJyZXLDrWEgKnNjYWxlcyogDQoNCmBgYHtyfQ0KbGlicmFyeShzY2FsZXMpDQpgYGANCg0KQ29uIGVzdGEgbGlicmVyw61hIHNlIHB1ZWRlIGFncmVnYXIgY29sb3IgYWwgZ3LDoWZpY28gbWVkaWFudGUgZWwgc2lndWllbnRlIGNvbWFuZG86DQpgYGB7cn0NCmdncGxvdChjYXNhbmFyZSkgKyANCiAgZ2VvbV9zZihkYXRhPWNhc2FuYXJlX3BvaW50cywgYWVzKHg9WCwgeT1ZLCBmaWxsID0NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIElEXzIpLCBjb2xvciA9ICJibGFjayIsIHNpemUgPSAwLjUwKSArDQogIGdlb21fdGV4dChkYXRhID0gY2FzYW5hcmVfcG9pbnRzLCBhZXMoeD1YLCB5PVksbGFiZWwgPSBJRF8yKSwgc2l6ZSA9IDIuNSkgKw0KICB0aGVtZShhc3BlY3QucmF0aW89MSkrDQogIHNjYWxlX2ZpbGxfZGlzdGlsbGVyKG5hbWU9IklEXzIiLCBwYWxldHRlID0iWWxPclJkIiwgYnJlYWtzID0gcHJldHR5X2JyZWFrcyhuID0gNSkpKw0KICBsYWJzKHRpdGxlPSJPdHJvIE1hcGEgZGUgQ2FzYW5hcmUiKQ0KYGBgDQpFbiBlbCBncsOhZmljbyBzZSBwdWVkZW4gdmlzdWFsaXphciBkaXN0aW50b3MgY29sb3JlcyBwYXJhIGNhZGEgbXVuaWNpcGlvIGRlcGVuZGllbmRvIGRlIHN1IG7Dum1lcm8gcGVybywgbm8gcHVlZGUgY29uc2lkZXJhcnNlIGNvbW8gdW4gbWFwYSByZWFsLiBEZSBpZ3VhbCBtYW5lcmEsIGVzIHBvc2libGUgZGVzY2FyZ2FyIGVzdGUgZ3JhZmljbyBjb21vIHVuIHBkZiBvIHVuIHBuZyBjb24gbG9zIHNpZ3VpZW50ZXMgY29tYW5kb3M6DQoNCmBgYHtyfQ0KZ2dzYXZlKCJjYXNhbmFyZV9tdW5pY2lwaW9zLnBkZiIpDQpgYGANCg0KYGBge3J9DQpnZ3NhdmUoIm1hcF9jYXNhbmFyZS5wbmciLCB3aWR0aCA9IDYsIGhlaWdodCA9IDYsIGRwaSA9ICJzY3JlZW4iKQ0KYGBgDQoqKlVzYXIgbGVhZmxldCBwYXJhIHZpc3VhbGl6YXIgZGF0b3M6DQoNClBhcmEgbG9zIHNpZ3VpZW50ZXMgcGFzb3MsIGVzIG5lY2VzYXJpbyBpbnN0YWxhciBlbCBwYXF1ZXRlICpsZWFmbGV0KjoNCmBgYHtyfQ0KI2luc3RhbGwucGFja2FnZXMoImxlYWZsZXQiKQ0KYGBgDQpMdWVnbywgc2UgZGViZSByb2RhciBlc3RhIGZ1bmNpw7NuOiANCmBgYHtyfQ0KbGlicmFyeShsZWFmbGV0KQ0KYGBgDQpBaG9yYSwgc2UgZGViZSBjb252ZXJ0aXIgKnNpbXBsZSBmZWF0dXJlcyogYSAqc3BhdGlhbCBwb2ludHMqOg0KYGBge3J9DQphbnRfcG9pbnRzIDwtIGFzKGNhc2FuYXJlX3BvaW50cywgJ1NwYXRpYWwnKQ0KYGBgDQpVc2FuZG8gbGEgb3BjacOzbiAqaGVhZCgpKiBzZSBwdWVkZSB2aXN1YWxpemFyIGxvIHF1ZSBjb250aWVuZSBlbCBvYmpldG8gY2FzYW5hcmVfcG9pbnRzLg0KYGBge3J9DQpoZWFkKGNhc2FuYXJlX3BvaW50cykNCmBgYA0KUGFyYSBvYnRlbmVyIGVsIMOhcmVhIGRlIGNhZGEgbXVuaWNpcGlvIHNlIHVzYSBlbCBwYXF1ZXRlICoibHdnZW9tIiogcXVlIGRlYmUgc2VyIGluc3RhbGFkbyBjb24gZWwgc2lndWllbnRlIGNvbWFuZG86DQpgYGB7cn0NCiNpbnN0YWxsLnBhY2thZ2VzKCJsd2dlb20iKQ0KYGBgDQpMdWVnbywgc2UgZGViZSBoYWNlciByb2RhciBsYSBiaWJsaW90ZWNhIGRlIGxhIHNpZ3VpZW50ZSBtYW5lcmE6DQpgYGB7cn0NCmxpYnJhcnkobHdnZW9tKQ0KYGBgDQpBaG9yYSwgc2UgZXNjcmliZSBlbCBzaWd1aWVudGUgY29tYW5kbyBwYXJhIGNvbm9jZXIgZWwgw6FyZWEgZW4gbWV0cm9zIGN1YWRyYWRvcyhtXjIpIGRlIGNhZGEgbXVuaWNpcGlvIHF1ZSBjb25mb3JtYSBDYXNhbmFyZToNCmBgYHtyfQ0KbXVuX2Nhc2FuYXJlJGFyZWEgPC0gc3RfYXJlYShtdW5fY2FzYW5hcmUpDQpgYGANClBhcmEgY2FtYmlhciBsYSB1bmlkYWQgZGUgbWVkaWRhIGEga2lsb21ldHJvcyBjdWFkcmFkb3MgKGttXjIpIHNlIGVzY3JpYmU6DQpgYGB7cn0NCm11bl9jYXNhbmFyZSRrbTIgPC0gbXVuX2Nhc2FuYXJlJGFyZWEvKDEwMDAwMDApDQpgYGANClNlIHB1ZWRlIHZlcmlmaWNhciBlc3RlIGNhbWJpbyBlc2NyaWJpZW5kbyBlbCBzaWd1aWVudGUgY29tYW5kbzoNCmBgYHtyfQ0KbXVuX2Nhc2FuYXJlJGttMg0KYGBgDQpBaG9yYSwgc2UgZGViZSBjYW1iaWFyIGRlICpzaW1wbGUgZmVhdHVyZXMqYSAqc3BhdGlhbCBwb2x5Z29ucyogYXBsaWNhbmRvIGVsIHNpZ3VpZW50ZSBjb21hbmRvOg0KYGBge3J9DQpjYXNhbmFyZV9tdW4gPC0gYXMobXVuX2Nhc2FuYXJlLCAnU3BhdGlhbCcpDQpgYGANClVzYW5kbyBsYSBmdW5jacOzbiAqaGVhZCgpKiBjb3Jyb2JvcmFtb3MgbGEgaW5mb3JtYWNpw7NuIGNvbnRlbmlkYSBlbiBlbCBvYmpldG8uDQpgYGB7cn0NCiNoZWFkKGNhc2FuYXJlX211bikNCmBgYA0KQWhvcmEsIHNlIGNyZWFuIGFsZ3Vub3MgdmVjdG9yZXM6DQpgYGB7cn0NCmJpbnMgPC0gYygwLCA1MCwgMTAwLCAyMDAsIDMwMCwgNTAwLCAxMDAwLCAyMDAwLCBJbmYpDQpwYWwgPC0gY29sb3JCaW4oIlB1UmQiLCBkb21haW4gPSBjYXNhbmFyZV9tdW4ka20yLCBiaW5zID0gYmlucykNCg0KDQpsYWJlbHMgPC0gbXVuX2Nhc2FuYXJlJE5BTUVfMg0KDQpsYWJlbHMNCmBgYA0KU2UgZXNjcmliZSBlbCBzaWd1aWVudGUgY29tYW5kbyBwYXJhIGdlbmVyYXIgdW4gbWFwYToNCg0KYGBge3J9DQptIDwtIGxlYWZsZXQoY2FzYW5hcmVfbXVuKSAlPiUNCiAgc2V0VmlldygtNzEuOCwgNS4xLCB6b29tID0gNy44KSAgJT4lIGFkZFBvbHlnb25zKCAgDQogIGZpbGxDb2xvciA9IH5wYWwoa20yKSwNCiAgd2VpZ2h0ID0gMiwNCiAgb3BhY2l0eSA9IDEsDQogIGNvbG9yID0gIndoaXRlIiwNCiAgZGFzaEFycmF5ID0gIjMiLA0KICBmaWxsT3BhY2l0eSA9IDAuNywNCiAgaGlnaGxpZ2h0ID0gaGlnaGxpZ2h0T3B0aW9ucygNCiAgICB3ZWlnaHQgPSA1LA0KICAgIGNvbG9yID0gIiMyIiwNCiAgICBkYXNoQXJyYXkgPSAiIiwNCiAgICBmaWxsT3BhY2l0eSA9IDAuNywNCiAgICBicmluZ1RvRnJvbnQgPSBUUlVFKSwNCiAgbGFiZWwgPSBsYWJlbHMpICU+JQ0KICBhZGRMZWdlbmQocGFsID0gcGFsLCB2YWx1ZXMgPSB+a20yLCBvcGFjaXR5ID0gMC43LCB0aXRsZSA9IE5VTEwsDQogICAgcG9zaXRpb24gPSAiYm90dG9tcmlnaHQiKQ0KYGBgDQpTZSBlc2NyaWJlIGxhIGxldHJhIG0gZW4gdW4gY2h1bmNrIHBhcmEgb2JzZXJ2YXIgZWwgbWFwYToNCg0KYGBge3J9DQptDQpgYGANCg0KT3RyYSBtYW5lcmEgcGFyYSBnZW5lcmFyIHVuIG1hcGEgZGUgbWFuZXJhIG3DoXMgc2ludGV0aXphZGEgcHVlZGUgc2VyOg0KYGBge3J9DQpsZWFmbGV0KCkgJT4lDQogIGFkZFByb3ZpZGVyVGlsZXMocHJvdmlkZXJzJEVzcmkuV29ybGRJbWFnZXJ5LCBvcHRpb25zPSBwcm92aWRlclRpbGVPcHRpb25zKG9wYWNpdHkgPSAwLjk5KSkgJT4lDQogIGFkZFBvbHlnb25zKGRhdGEgPSBjYXNhbmFyZV9tdW4sIHBvcHVwPSBjYXNhbmFyZV9tdW4kTkFNRV8yLA0KICAgIHN0cm9rZSA9IFRSVUUsIGZpbGxPcGFjaXR5ID0gMC4yNSwgc21vb3RoRmFjdG9yID0gMC4yNSkNCmBgYA0KQWhvcmEsIG5vcyBlbmZvY2FyZW1vcyBlbiBjcmVhciB1bmEgaWx1c3RyYWNpw7NuIHBhcmEgWW9wYWwsIGxhIGNhcGl0YWwgZGVsIGRlcGFydGFtZW50bzoNCg0KYGBge3J9DQojbGlicmFyeShsZWFmbGV0KQ0KYGBgDQpFbiBlc3RhIGdyw6FmaWNhIHBvZGVtb3MgdmVyIHVuIG1hcGEgbm9ybWFsIGRlbCB0ZXJyaXRvcmlvOg0KYGBge3J9DQpsIDwtIGxlYWZsZXQoKSAlPiUNCiAgYWRkVGlsZXMoKSAlPiUgYWRkTWFya2Vycyhsbmc9LTcyLjQwMywgbGF0PTUuMzI3LCBwb3B1cD0iWW9wYWwiKQ0KbCAgDQpgYGANClNpbiBlbWJhcmdvLCBhbCBlbXBsZWFyIGxhIG9wY2nDs24gZGUgbGVhZmxldCBwcm92aWRlcnMgZWwgZ3LDoWZpY28gcHVlZGUgdG9tYXIgZGlmZXJlbnRlcyBmb3JtYXMgeSB2ZXJzZSB1biBwb2MgbcOhcyBwcm9mZXNpb25hbGVzLiBBIGNvbnRpbnVhY2nDs24sIHNlIHB1ZWRlbiB2ZXIgZG9zIGVqZW1wbG9zOg0KIA0KDQpgYGB7cn0NCmxpYnJhcnkobGVhZmxldCkNCmxlYWZsZXQoKSAlPiUgc2V0VmlldyhsbmcgPSAtNzIuNCwgbGF0ID0gNS4zNSwgem9vbSA9IDEzKSAlPiUNCiAgYWRkUHJvdmlkZXJUaWxlcyhwcm92aWRlcnMkT3BlblRvcG9NYXApDQpgYGANCg0KDQpgYGB7cn0NCmxlYWZsZXQoKSAlPiVzZXRWaWV3KGxuZyA9IC03Mi40LCBsYXQgPSA1LjM1LCB6b29tID0gOSklPiUNCiAgYWRkUHJvdmlkZXJUaWxlcyhwcm92aWRlcnMkRXNyaS5OYXRHZW9Xb3JsZE1hcCwgb3B0aW9ucz0gcHJvdmlkZXJUaWxlT3B0aW9ucyhvcGFjaXR5ID0gMSkpDQpgYGANCg0K