1. Introducción

El paquete sf (Simple Features) es una herramienta para trabajar con datos espaciales, ya que cuenta con diferentes funciones básicas para leer, visualizar y manipular archivos shapefile, integrando librerías como dplyr y ggplot2 para el análisis y la representación gráfica. En este caso, la base será el shapefile MGN2023_MPIO_POLITICO del DANE (2023).
El objetivo de este cuaderno es representar espacialmente los municipios y ciudades del departamento de Boyacá mediante un mapa temático elaborado con sf, ggplot2 y ggspatial.

2. Configuración

Se cargan las librerías necesarias para el análisis sf, dplyr, ggplot2 y ggspatial, instaladas previamente.
library(sf)
library(dplyr)
library(ggplot2)
library(ggspatial)

3. Lectura y Escritura de Datos Espaciales

3.1. Lectura de datos espaciales con st_read

Primero se utiliza la función list.files() para visualizar los archivos de la carpeta donde está ubicado el shapefile.
list.files("D:/GB2/P3/Notebook/Municipios")
[1] "MGN_ADM_MPIO_GRAFICO.cpg"     "MGN_ADM_MPIO_GRAFICO.dbf"     "MGN_ADM_MPIO_GRAFICO.prj"     "MGN_ADM_MPIO_GRAFICO.shp"     "MGN_ADM_MPIO_GRAFICO.shp.xml"
[6] "MGN_ADM_MPIO_GRAFICO.shx"    
Ahora, se especifica la ruta del archivo shapefile Municipios y se lee con la función st_read. La información se guarda en la variable colombia.
colombia <- st_read("D:/GB2/P3/Notebook/Municipios/MGN_ADM_MPIO_GRAFICO.shp")
Reading layer `MGN_ADM_MPIO_GRAFICO' from data source `D:\GB2\P3\Notebook\Municipios\MGN_ADM_MPIO_GRAFICO.shp' using driver `ESRI Shapefile'
Simple feature collection with 1121 features and 12 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: -81.73562 ymin: -4.229406 xmax: -66.84722 ymax: 13.39473
Geodetic CRS:  MAGNA-SIRGAS
Después se visualiza el encabezado de los datos de la variable colombia, utilizando las funciones head() y paged_table().
rmarkdown::paged_table(head(colombia))

3.2. Escritura de datos espaciales con st_write

Se usa la función st_write() para guardar el objeto colombia en formato gpkg. Luego, se verifica que el nuevo archivo geopackage se haya creado correctamente, para después relizar una nueva lectura.
st_write(colombia, "municipios.gpkg", driver = "GPKG", append = F)
Deleting layer `municipios' using driver `GPKG'
Writing layer `municipios' to data source `municipios.gpkg' using driver `GPKG'
Writing 1121 features with 12 fields and geometry type Multi Polygon.
list.files(pattern="gpkg")
[1] "boyaca_munic.gpkg" "municipios.gpkg"   "stder_munic.gpkg" 
colombia2 <- st_read("./municipios.gpkg")
Reading layer `municipios' from data source `D:\GB2\P3\Notebook\municipios.gpkg' using driver `GPKG'
Simple feature collection with 1121 features and 12 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: -81.73562 ymin: -4.229406 xmax: -66.84722 ymax: 13.39473
Geodetic CRS:  MAGNA-SIRGAS

4. Seleccionar departamento

4.1. Seleccionar por atributo

Para realizar la selección por atributo, se utiliza la función filter(), especificando los criterios ncesarios para seleccionar únicamente los municipios de Boyacá.
rmarkdown::paged_table((boyaca <- dplyr::filter(colombia, dpto_cnmbr=="BOYACÁ")))
Después de verificar que la informcaión coincide con la información del departamento de Boyacá, se construye un gráfico sencillo con los polígonos de sus municipios.
plot(st_geometry(boyaca), col = sf.colors(12, categorical = TRUE), border = 'grey', 
     axes = TRUE)
plot(st_geometry(st_centroid(boyaca)), pch = 3, col = 'red', add = TRUE)

Por último, los polígonos seleccionados se guardan en un nuevo archivo geopackage.
st_write(boyaca, "boyaca_munic.gpkg", driver = "GPKG", append = F)
Deleting layer `boyaca_munic' using driver `GPKG'
Writing layer `boyaca_munic' to data source `boyaca_munic.gpkg' using driver `GPKG'
Writing 123 features with 12 fields and geometry type Multi Polygon.

5. Seleccionar por ubicación

Se utiliza la función de selección por ubicación con un archivo CSV que contiene los datos de las ciudades del mundo. Primero, se lee el archivo y se convierte en un objeto espacial con st_as_sf() especificando las columnas de longitud y latitud, junto al sistema de referencia EPSG:4326.
cities = read.csv('D:/GB2/P3/Notebook/simplemaps_worldcities_basicv1.77/worldcities.csv') %>%
  st_as_sf(coords=c("lng","lat"), crs=4326)
A continuación, se visualiza el contenido de la variable cities.
rmarkdown::paged_table(cities)
Se verifica que los CRS de ambos conjuntos de datos (cities y boyaca) coincidan.
st_crs(cities)$epsg
[1] 4326
st_crs(boyaca)$epsg
[1] 4686
De no ser así, se debe transformar el CRS de cities para que coincida con el CRS de boyaca, utilizando la función st_transform().
ncities <- st_transform(cities, crs= st_crs(boyaca))
Luego, se crea la variable boyaca_cities para guardar únicamente las ciudades del departamento de Boyacá. Para la selección se usa st_within.
boyaca_cities <- ncities[boyaca, , op = st_within]
Una vez hecha la transformación, se construye un gráfico más detallado que el anterior, donde se muestra los municipios del departamento, y con puntos, sus ciudades.
plot(st_geometry(boyaca), col = sf.colors(12, categorical = TRUE), border = 'grey', axes = TRUE)
plot(st_geometry(boyaca_cities), pch = 20, col = 'red', add = TRUE)

6. Gráfica detallada

6.1. usando ggplot

Ahora, se utiliza ggplot para generar un gráfico más estético de los municipios del departamento de Boyacá y de sus ciudades.
Se representa el contorno de los municipios con geom_sf(), y se añaden las ciudades mediante una capa adicional con puntos que varían según el nombre de la ciudad.
ggplot() +
  #Add  municipalities
  geom_sf(data = boyaca) +
  #Add cities layer
  geom_sf(data = boyaca_cities, aes(color = city, label = city), size = 3) +
  #Add titles
  labs(x = "Longitud", y = "Latitud", title = "Ciudades de Boyacá") +
  #Add theme
  theme_bw()

Finalmente, se mejora la presentación del mapa agregando una barra de escala y una flecha de norte mediante el paquete ggspatial. De esta manera se obtiene el mapa final con los municipios y las ciudades del departamento de Boyacá representados de forma clara y estética.
ggplot() +
  #Crop Virginia boundary to spatial extent of cities and add Virginia layer
  geom_sf(data = boyaca) +
  #Add cities layer
  geom_sf(data = boyaca_cities, aes(color = city, label = city), size = 3) +
  #Add scale bar to bottom left from ggspatial
  annotation_scale(location = "tl", height = unit(.25, "cm"), 
                   width = unit(1, "cm"), pad_x = unit(0.3, "in"), 
                   pad_y = unit(0.5, "in")) +
  #Add north arrow to bottom left from ggspatial
  annotation_north_arrow(height = unit(1, "cm"), width = unit(1, "cm"),
                         which_north = "true", location = "tl", 
                         pad_x = unit(0.5, "in"), pad_y = unit(0.05, "in")) +
  #Add titles
  labs(x = "Longitud", y = "Latitud", title = "Ciudades de Boyacá") +
  #Add theme
  theme_bw()

7. Detalles del entorno computacional

sessionInfo()
R version 4.3.2 (2023-10-31 ucrt)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 11 x64 (build 22631)

Matrix products: default


locale:
[1] LC_COLLATE=Spanish_Colombia.utf8  LC_CTYPE=Spanish_Colombia.utf8    LC_MONETARY=Spanish_Colombia.utf8
[4] LC_NUMERIC=C                      LC_TIME=Spanish_Colombia.utf8    

time zone: America/Bogota
tzcode source: internal

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] ggspatial_1.1.9 ggplot2_3.4.4   dplyr_1.1.4     sf_1.0-20      

loaded via a namespace (and not attached):
 [1] gtable_0.3.4       jsonlite_1.8.8     compiler_4.3.2     tidyselect_1.2.1   Rcpp_1.0.12        jquerylib_0.1.4   
 [7] scales_1.3.0       yaml_2.3.8         fastmap_1.1.1      R6_2.5.1           generics_0.1.3     classInt_0.4-11   
[13] s2_1.1.7           knitr_1.45         tibble_3.2.1       units_0.8-7        munsell_0.5.0      DBI_1.2.3         
[19] bslib_0.6.1        pillar_1.9.0       rlang_1.1.3        utf8_1.2.4         cachem_1.0.8       xfun_0.52         
[25] sass_0.4.8         cli_3.6.2          withr_3.0.0        magrittr_2.0.3     wk_0.9.4           class_7.3-22      
[31] digest_0.6.34      grid_4.3.2         rstudioapi_0.17.1  lifecycle_1.0.4    vctrs_0.6.5        KernSmooth_2.23-22
[37] proxy_0.4-27       evaluate_0.23      glue_1.7.0         farver_2.1.1       rsconnect_1.4.1    colorspace_2.1-0  
[43] fansi_1.0.6        e1071_1.7-16       rmarkdown_2.25     tools_4.3.2        pkgconfig_2.0.3    htmltools_0.5.7   
LS0tDQp0aXRsZTogIkludHJvZHVjY2nDs24gYSBlbGVtZW50b3Mgc2ltcGxlcyBlbiBSIg0KYXV0aG9yOiAiWWFuZXRoIEFsZXhhbmRyYSBBcmVuYXMgR2FycmlkbyINCmRhdGU6ICIyMS8wNS8yMDI1Ig0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCiMgMS4gSW50cm9kdWNjacOzbg0KIyMjIyMgRWwgcGFxdWV0ZSAqKnNmICgqU2ltcGxlIEZlYXR1cmVzKikqKiBlcyB1bmEgaGVycmFtaWVudGEgcGFyYSB0cmFiYWphciBjb24gZGF0b3MgZXNwYWNpYWxlcywgeWEgcXVlIGN1ZW50YSBjb24gZGlmZXJlbnRlcyBmdW5jaW9uZXMgYsOhc2ljYXMgcGFyYSBsZWVyLCB2aXN1YWxpemFyIHkgbWFuaXB1bGFyIGFyY2hpdm9zICpzaGFwZWZpbGUqLCBpbnRlZ3JhbmRvIGxpYnJlcsOtYXMgY29tbyBkcGx5ciB5IGdncGxvdDIgcGFyYSBlbCBhbsOhbGlzaXMgeSBsYSByZXByZXNlbnRhY2nDs24gZ3LDoWZpY2EuIEVuIGVzdGUgY2FzbywgbGEgYmFzZSBzZXLDoSBlbCAqc2hhcGVmaWxlKiBNR04yMDIzX01QSU9fUE9MSVRJQ08gZGVsIERBTkUgKDIwMjMpLg0KDQojIyMjIyBFbCBvYmpldGl2byBkZSBlc3RlIGN1YWRlcm5vIGVzIHJlcHJlc2VudGFyIGVzcGFjaWFsbWVudGUgbG9zIG11bmljaXBpb3MgeSBjaXVkYWRlcyBkZWwgZGVwYXJ0YW1lbnRvIGRlIEJveWFjw6EgbWVkaWFudGUgdW4gbWFwYSB0ZW3DoXRpY28gZWxhYm9yYWRvIGNvbiBzZiwgZ2dwbG90MiB5IGdnc3BhdGlhbC4NCg0KIyAyLiBDb25maWd1cmFjacOzbg0KIyMjIyMgU2UgY2FyZ2FuIGxhcyBsaWJyZXLDrWFzIG5lY2VzYXJpYXMgcGFyYSBlbCBhbsOhbGlzaXMgKipzZioqLCAqKmRwbHlyKiosICoqZ2dwbG90MioqIHkgKipnZ3NwYXRpYWwqKiwgaW5zdGFsYWRhcyBwcmV2aWFtZW50ZS4NCg0KYGBge3IgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0V9DQpsaWJyYXJ5KHNmKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoZ2dzcGF0aWFsKQ0KYGBgDQoNCiMgMy4gTGVjdHVyYSB5IEVzY3JpdHVyYSBkZSBEYXRvcyBFc3BhY2lhbGVzDQojIyMgMy4xLiBMZWN0dXJhIGRlIGRhdG9zIGVzcGFjaWFsZXMgY29uIHN0X3JlYWQNCiMjIyMjIFByaW1lcm8gc2UgdXRpbGl6YSBsYSBmdW5jacOzbiBsaXN0LmZpbGVzKCkgcGFyYSB2aXN1YWxpemFyIGxvcyBhcmNoaXZvcyBkZSBsYSBjYXJwZXRhIGRvbmRlIGVzdMOhIHViaWNhZG8gZWwgc2hhcGVmaWxlLiANCg0KYGBge3J9DQpsaXN0LmZpbGVzKCJEOi9HQjIvUDMvTm90ZWJvb2svTXVuaWNpcGlvcyIpDQpgYGANCg0KIyMjIyMgQWhvcmEsIHNlIGVzcGVjaWZpY2EgbGEgcnV0YSBkZWwgYXJjaGl2byBzaGFwZWZpbGUgKipNdW5pY2lwaW9zKiogeSBzZSBsZWUgY29uIGxhIGZ1bmNpw7NuIHN0X3JlYWQuIExhIGluZm9ybWFjacOzbiBzZSBndWFyZGEgZW4gbGEgdmFyaWFibGUgKipjb2xvbWJpYSoqLg0KDQpgYGB7cn0NCmNvbG9tYmlhIDwtIHN0X3JlYWQoIkQ6L0dCMi9QMy9Ob3RlYm9vay9NdW5pY2lwaW9zL01HTl9BRE1fTVBJT19HUkFGSUNPLnNocCIpDQpgYGANCg0KIyMjIyMgRGVzcHXDqXMgc2UgdmlzdWFsaXphIGVsIGVuY2FiZXphZG8gZGUgbG9zIGRhdG9zIGRlIGxhIHZhcmlhYmxlIGNvbG9tYmlhLCB1dGlsaXphbmRvIGxhcyBmdW5jaW9uZXMgaGVhZCgpIHkgcGFnZWRfdGFibGUoKS4NCg0KYGBge3J9DQpybWFya2Rvd246OnBhZ2VkX3RhYmxlKGhlYWQoY29sb21iaWEpKQ0KYGBgDQoNCg0KIyMjIDMuMi4gRXNjcml0dXJhIGRlIGRhdG9zIGVzcGFjaWFsZXMgY29uIHN0X3dyaXRlDQojIyMjIyBTZSB1c2EgbGEgZnVuY2nDs24gc3Rfd3JpdGUoKSBwYXJhIGd1YXJkYXIgZWwgb2JqZXRvICoqY29sb21iaWEqKiBlbiBmb3JtYXRvICoqZ3BrZyoqLiBMdWVnbywgc2UgdmVyaWZpY2EgcXVlIGVsIG51ZXZvIGFyY2hpdm8gZ2VvcGFja2FnZSBzZSBoYXlhIGNyZWFkbyBjb3JyZWN0YW1lbnRlLCBwYXJhIGRlc3B1w6lzIHJlbGl6YXIgdW5hIG51ZXZhIGxlY3R1cmEuDQoNCmBgYHtyfQ0Kc3Rfd3JpdGUoY29sb21iaWEsICJtdW5pY2lwaW9zLmdwa2ciLCBkcml2ZXIgPSAiR1BLRyIsIGFwcGVuZCA9IEYpDQpgYGANCg0KYGBge3J9DQpsaXN0LmZpbGVzKHBhdHRlcm49Imdwa2ciKQ0KYGBgDQoNCmBgYHtyfQ0KY29sb21iaWEyIDwtIHN0X3JlYWQoIi4vbXVuaWNpcGlvcy5ncGtnIikNCmBgYA0KDQojIDQuIFNlbGVjY2lvbmFyIGRlcGFydGFtZW50bw0KIyMjIDQuMS4gU2VsZWNjaW9uYXIgcG9yIGF0cmlidXRvDQojIyMjIyBQYXJhIHJlYWxpemFyIGxhIHNlbGVjY2nDs24gcG9yIGF0cmlidXRvLCBzZSB1dGlsaXphIGxhIGZ1bmNpw7NuIGZpbHRlcigpLCBlc3BlY2lmaWNhbmRvIGxvcyBjcml0ZXJpb3MgbmNlc2FyaW9zIHBhcmEgc2VsZWNjaW9uYXIgw7puaWNhbWVudGUgbG9zIG11bmljaXBpb3MgZGUgQm95YWPDoS4NCg0KYGBge3J9DQpybWFya2Rvd246OnBhZ2VkX3RhYmxlKChib3lhY2EgPC0gZHBseXI6OmZpbHRlcihjb2xvbWJpYSwgZHB0b19jbm1icj09IkJPWUFDw4EiKSkpDQpgYGANCg0KIyMjIyMgRGVzcHXDqXMgZGUgdmVyaWZpY2FyIHF1ZSBsYSBpbmZvcm1jYWnDs24gY29pbmNpZGUgY29uIGxhIGluZm9ybWFjacOzbiBkZWwgZGVwYXJ0YW1lbnRvIGRlIEJveWFjw6EsIHNlIGNvbnN0cnV5ZSB1biBncsOhZmljbyBzZW5jaWxsbyBjb24gbG9zIHBvbMOtZ29ub3MgZGUgc3VzIG11bmljaXBpb3MuDQoNCmBgYHtyIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFfQ0KcGxvdChzdF9nZW9tZXRyeShib3lhY2EpLCBjb2wgPSBzZi5jb2xvcnMoMTIsIGNhdGVnb3JpY2FsID0gVFJVRSksIGJvcmRlciA9ICdncmV5JywgDQogICAgIGF4ZXMgPSBUUlVFKQ0KcGxvdChzdF9nZW9tZXRyeShzdF9jZW50cm9pZChib3lhY2EpKSwgcGNoID0gMywgY29sID0gJ3JlZCcsIGFkZCA9IFRSVUUpDQpgYGANCg0KIyMjIyMgUG9yIMO6bHRpbW8sIGxvcyBwb2zDrWdvbm9zIHNlbGVjY2lvbmFkb3Mgc2UgZ3VhcmRhbiBlbiB1biBudWV2byBhcmNoaXZvIGdlb3BhY2thZ2UuDQoNCmBgYHtyfQ0Kc3Rfd3JpdGUoYm95YWNhLCAiYm95YWNhX211bmljLmdwa2ciLCBkcml2ZXIgPSAiR1BLRyIsIGFwcGVuZCA9IEYpDQpgYGANCg0KIyA1LiBTZWxlY2Npb25hciBwb3IgdWJpY2FjacOzbg0KIyMjIyMgU2UgdXRpbGl6YSBsYSBmdW5jacOzbiBkZSBzZWxlY2Npw7NuIHBvciB1YmljYWNpw7NuIGNvbiB1biBhcmNoaXZvIENTViBxdWUgY29udGllbmUgbG9zIGRhdG9zIGRlIGxhcyBjaXVkYWRlcyBkZWwgbXVuZG8uIFByaW1lcm8sIHNlIGxlZSBlbCBhcmNoaXZvIHkgc2UgY29udmllcnRlIGVuIHVuIG9iamV0byBlc3BhY2lhbCBjb24gYHN0X2FzX3NmKClgIGVzcGVjaWZpY2FuZG8gbGFzIGNvbHVtbmFzIGRlICoqbG9uZ2l0dWQqKiB5ICoqbGF0aXR1ZCoqLCBqdW50byBhbCBzaXN0ZW1hIGRlIHJlZmVyZW5jaWEgRVBTRzo0MzI2Lg0KDQpgYGB7cn0NCmNpdGllcyA9IHJlYWQuY3N2KCdEOi9HQjIvUDMvTm90ZWJvb2svc2ltcGxlbWFwc193b3JsZGNpdGllc19iYXNpY3YxLjc3L3dvcmxkY2l0aWVzLmNzdicpICU+JQ0KICBzdF9hc19zZihjb29yZHM9YygibG5nIiwibGF0IiksIGNycz00MzI2KQ0KYGBgDQoNCiMjIyMjIEEgY29udGludWFjacOzbiwgc2UgdmlzdWFsaXphIGVsIGNvbnRlbmlkbyBkZSBsYSB2YXJpYWJsZSAqKmNpdGllcyoqLg0KDQpgYGB7cn0NCnJtYXJrZG93bjo6cGFnZWRfdGFibGUoY2l0aWVzKQ0KYGBgDQoNCiMjIyMjIFNlIHZlcmlmaWNhIHF1ZSBsb3MgQ1JTIGRlIGFtYm9zIGNvbmp1bnRvcyBkZSBkYXRvcyAoY2l0aWVzIHkgYm95YWNhKSBjb2luY2lkYW4uDQoNCmBgYHtyfQ0Kc3RfY3JzKGNpdGllcykkZXBzZw0KYGBgDQoNCmBgYHtyfQ0Kc3RfY3JzKGJveWFjYSkkZXBzZw0KYGBgDQoNCiMjIyMjIERlIG5vIHNlciBhc8OtLCBzZSBkZWJlIHRyYW5zZm9ybWFyIGVsIENSUyBkZSAqY2l0aWVzKiBwYXJhIHF1ZSBjb2luY2lkYSBjb24gZWwgQ1JTIGRlIGJveWFjYSwgdXRpbGl6YW5kbyBsYSBmdW5jacOzbiBzdF90cmFuc2Zvcm0oKS4NCg0KYGBge3J9DQpuY2l0aWVzIDwtIHN0X3RyYW5zZm9ybShjaXRpZXMsIGNycz0gc3RfY3JzKGJveWFjYSkpDQpgYGANCg0KIyMjIyMgTHVlZ28sIHNlIGNyZWEgbGEgdmFyaWFibGUgKipib3lhY2FfY2l0aWVzKiogcGFyYSBndWFyZGFyIMO6bmljYW1lbnRlIGxhcyBjaXVkYWRlcyBkZWwgZGVwYXJ0YW1lbnRvIGRlIEJveWFjw6EuIFBhcmEgbGEgc2VsZWNjacOzbiBzZSB1c2Egc3Rfd2l0aGluLg0KDQpgYGB7cn0NCmJveWFjYV9jaXRpZXMgPC0gbmNpdGllc1tib3lhY2EsICwgb3AgPSBzdF93aXRoaW5dDQpgYGANCg0KIyMjIyMgVW5hIHZleiBoZWNoYSBsYSB0cmFuc2Zvcm1hY2nDs24sIHNlIGNvbnN0cnV5ZSB1biBncsOhZmljbyBtw6FzIGRldGFsbGFkbyBxdWUgZWwgYW50ZXJpb3IsIGRvbmRlIHNlIG11ZXN0cmEgbG9zIG11bmljaXBpb3MgZGVsIGRlcGFydGFtZW50bywgeSBjb24gcHVudG9zLCBzdXMgY2l1ZGFkZXMuDQoNCmBgYHtyfQ0KcGxvdChzdF9nZW9tZXRyeShib3lhY2EpLCBjb2wgPSBzZi5jb2xvcnMoMTIsIGNhdGVnb3JpY2FsID0gVFJVRSksIGJvcmRlciA9ICdncmV5JywgYXhlcyA9IFRSVUUpDQpwbG90KHN0X2dlb21ldHJ5KGJveWFjYV9jaXRpZXMpLCBwY2ggPSAyMCwgY29sID0gJ3JlZCcsIGFkZCA9IFRSVUUpDQpgYGANCg0KIyA2LiBHcsOhZmljYSBkZXRhbGxhZGENCiMjIyA2LjEuIHVzYW5kbyBnZ3Bsb3QNCiMjIyMjIEFob3JhLCBzZSB1dGlsaXphICoqZ2dwbG90KiogcGFyYSBnZW5lcmFyIHVuIGdyw6FmaWNvIG3DoXMgZXN0w6l0aWNvIGRlIGxvcyBtdW5pY2lwaW9zIGRlbCBkZXBhcnRhbWVudG8gZGUgQm95YWPDoSB5IGRlIHN1cyBjaXVkYWRlcy4NCg0KIyMjIyMgU2UgcmVwcmVzZW50YSBlbCBjb250b3JubyBkZSBsb3MgbXVuaWNpcGlvcyBjb24gKipnZW9tX3NmKCkqKiwgeSBzZSBhw7FhZGVuIGxhcyBjaXVkYWRlcyBtZWRpYW50ZSB1bmEgY2FwYSBhZGljaW9uYWwgY29uIHB1bnRvcyBxdWUgdmFyw61hbiBzZWfDum4gZWwgbm9tYnJlIGRlIGxhIGNpdWRhZC4NCg0KYGBge3IgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0V9DQpnZ3Bsb3QoKSArDQogICNBZGQgIG11bmljaXBhbGl0aWVzDQogIGdlb21fc2YoZGF0YSA9IGJveWFjYSkgKw0KICAjQWRkIGNpdGllcyBsYXllcg0KICBnZW9tX3NmKGRhdGEgPSBib3lhY2FfY2l0aWVzLCBhZXMoY29sb3IgPSBjaXR5LCBsYWJlbCA9IGNpdHkpLCBzaXplID0gMykgKw0KICAjQWRkIHRpdGxlcw0KICBsYWJzKHggPSAiTG9uZ2l0dWQiLCB5ID0gIkxhdGl0dWQiLCB0aXRsZSA9ICJDaXVkYWRlcyBkZSBCb3lhY8OhIikgKw0KICAjQWRkIHRoZW1lDQogIHRoZW1lX2J3KCkNCmBgYA0KDQojIyMjIyBGaW5hbG1lbnRlLCBzZSBtZWpvcmEgbGEgcHJlc2VudGFjacOzbiBkZWwgbWFwYSBhZ3JlZ2FuZG8gdW5hIGJhcnJhIGRlIGVzY2FsYSB5IHVuYSBmbGVjaGEgZGUgbm9ydGUgbWVkaWFudGUgZWwgcGFxdWV0ZSBnZ3NwYXRpYWwuIERlIGVzdGEgbWFuZXJhIHNlIG9idGllbmUgZWwgbWFwYSBmaW5hbCBjb24gbG9zIG11bmljaXBpb3MgeSBsYXMgY2l1ZGFkZXMgZGVsIGRlcGFydGFtZW50byBkZSBCb3lhY8OhIHJlcHJlc2VudGFkb3MgZGUgZm9ybWEgY2xhcmEgeSBlc3TDqXRpY2EuDQoNCmBgYHtyIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFfQ0KZ2dwbG90KCkgKw0KICAjQ3JvcCBWaXJnaW5pYSBib3VuZGFyeSB0byBzcGF0aWFsIGV4dGVudCBvZiBjaXRpZXMgYW5kIGFkZCBWaXJnaW5pYSBsYXllcg0KICBnZW9tX3NmKGRhdGEgPSBib3lhY2EpICsNCiAgI0FkZCBjaXRpZXMgbGF5ZXINCiAgZ2VvbV9zZihkYXRhID0gYm95YWNhX2NpdGllcywgYWVzKGNvbG9yID0gY2l0eSwgbGFiZWwgPSBjaXR5KSwgc2l6ZSA9IDMpICsNCiAgI0FkZCBzY2FsZSBiYXIgdG8gYm90dG9tIGxlZnQgZnJvbSBnZ3NwYXRpYWwNCiAgYW5ub3RhdGlvbl9zY2FsZShsb2NhdGlvbiA9ICJ0bCIsIGhlaWdodCA9IHVuaXQoLjI1LCAiY20iKSwgDQogICAgICAgICAgICAgICAgICAgd2lkdGggPSB1bml0KDEsICJjbSIpLCBwYWRfeCA9IHVuaXQoMC4zLCAiaW4iKSwgDQogICAgICAgICAgICAgICAgICAgcGFkX3kgPSB1bml0KDAuNSwgImluIikpICsNCiAgI0FkZCBub3J0aCBhcnJvdyB0byBib3R0b20gbGVmdCBmcm9tIGdnc3BhdGlhbA0KICBhbm5vdGF0aW9uX25vcnRoX2Fycm93KGhlaWdodCA9IHVuaXQoMSwgImNtIiksIHdpZHRoID0gdW5pdCgxLCAiY20iKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICB3aGljaF9ub3J0aCA9ICJ0cnVlIiwgbG9jYXRpb24gPSAidGwiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICBwYWRfeCA9IHVuaXQoMC41LCAiaW4iKSwgcGFkX3kgPSB1bml0KDAuMDUsICJpbiIpKSArDQogICNBZGQgdGl0bGVzDQogIGxhYnMoeCA9ICJMb25naXR1ZCIsIHkgPSAiTGF0aXR1ZCIsIHRpdGxlID0gIkNpdWRhZGVzIGRlIEJveWFjw6EiKSArDQogICNBZGQgdGhlbWUNCiAgdGhlbWVfYncoKQ0KYGBgDQoNCiMgNy4gRGV0YWxsZXMgZGVsIGVudG9ybm8gY29tcHV0YWNpb25hbA0KDQpgYGB7cn0NCnNlc3Npb25JbmZvKCkNCmBgYA0KDQo=