santiago delgado franco

Mapas de la produccion agricola

1.Introducción

Este cuaderno explica cómo hacer mapas temáticos para la producción agrícola. Para ello necesitamos dos archivos para empezar: un archivo CSV con los datos de la producción agrícola por municipio (EVA2020) y un geopackage con los municipios de nuestro departamento de estudio. Más adelante usaremos un archivo con las vías de los municipios.

2.preparacción

requerimos tener instaladas las librerias y cargarlas dpyar,tmap y sf

library(dplyr)
Aviso: package ‘dplyr’ was built under R version 4.4.2

Adjuntando el paquete: ‘dplyr’

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

    filter, lag

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

    intersect, setdiff, setequal, union
library(tmap)
Aviso: package ‘tmap’ was built under R version 4.4.3
library(sf)
Linking to GEOS 3.13.0, GDAL 3.10.1, PROJ 9.5.1; sf_use_s2() is TRUE
library(readr)
Aviso: package ‘readr’ was built under R version 4.4.3

3.lectura de los archivos de los municipios y cultivos

para este cuaderno trabajaremos con el departamento de antioquia antes de empezar trabajaremos en el folder /GB02/proyecto 6 en donde se encuentran nuestros archivos a analizar geopackage del departamento de antioquia y sus municipios y csv file con EVA 2020 con las estadiscticas de los cultivos

list.files()
 [1] "cuarderno 6.nb.html"                                      
 [2] "cuarderno 6.Rmd"                                          
 [3] "cuarderno.nb.html"                                        
 [4] "EVA"                                                      
 [5] "FRUTALES.csv"                                             
 [6] "How to read and subset .xlsx agricultural statistics data"
 [7] "mapa produccion final.Rmd"                                
 [8] "mapa produccion.nb.html"                                  
 [9] "mapa produccion.Rmd"                                      
[10] "MGN2025_ADM_MPIO_GRAFICO_(Geopackage)"                    

ahora procedemos a leer y cargar el archivo csv


frutales <- read_delim("FRUTALES.csv", delim = ";", locale = locale(encoding = "UTF-8"))
Rows: 654 Columns: 18
── Column specification ────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ";"
chr (10): Departamento, Código Dane municipio, Municipio, Grupo cultivo, Subgrupo, Cultivo, Desagregación cu...
dbl  (8): Código Dane departamento, Año, Periodo, Área sembrada, Área cosechada, Producción, Rendimiento, Có...

ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.

y cargamos los municipios del Geopackage

(municipios =  st_read('municipios.gpkg'))
Reading layer `municipios' from data source 
  `C:\Users\Biblio\Desktop\proyecto 5-20261108T170448Z-1-001-20261111T154808Z-1-001\proyecto 5-20261108T170448Z-1-001\proyecto 5\entrega\municipios.gpkg' 
  using driver `GPKG'
Simple feature collection with 1122 features and 11 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: -81.73562 ymin: -4.229406 xmax: -66.84722 ymax: 13.39473
Geodetic CRS:  WGS 84
Simple feature collection with 1122 features and 11 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: -81.73562 ymin: -4.229406 xmax: -66.84722 ymax: 13.39473
Geodetic CRS:  WGS 84
First 10 features:
   dpto_ccdgo mpio_ccdgo mpio_cdpmp dpto_cnmbr  mpio_cnmbr                           mpio_crslc mpio_tipo
1          05        001      05001  ANTIOQUIA    MEDELLÍN                                 1965 MUNICIPIO
2          05        002      05002  ANTIOQUIA   ABEJORRAL                                 1814 MUNICIPIO
3          05        004      05004  ANTIOQUIA    ABRIAQUÍ                                 1912 MUNICIPIO
4          05        021      05021  ANTIOQUIA  ALEJANDRÍA    Decreto departamental 304 de 1907 MUNICIPIO
5          05        030      05030  ANTIOQUIA       AMAGÁ                                 1912 MUNICIPIO
6          05        031      05031  ANTIOQUIA      AMALFI                                 1843 MUNICIPIO
7          05        034      05034  ANTIOQUIA       ANDES                                 1853 MUNICIPIO
8          05        036      05036  ANTIOQUIA ANGELÓPOLIS Ordenanza 16 del 12 de julio de 1896 MUNICIPIO
9          05        038      05038  ANTIOQUIA   ANGOSTURA                                 1821 MUNICIPIO
10         05        040      05040  ANTIOQUIA       ANORÍ                                 1821 MUNICIPIO
   mpio_narea mpio_nano shape_Leng  shape_Area                           geom
1   374.74148      2025  1.0353795 0.030607649 MULTIPOLYGON (((-75.4857 6....
2   506.95978      2024  1.1585036 0.041383896 MULTIPOLYGON (((-75.46938 5...
3   296.97419      2025  0.8106670 0.024253315 MULTIPOLYGON (((-76.09047 6...
4   128.85643      2024  0.7051995 0.010534527 MULTIPOLYGON (((-75.0332 6....
5    84.11714      2024  0.4455330 0.006866507 MULTIPOLYGON (((-75.67587 6...
6  1208.34619      2025  2.0584824 0.098921100 MULTIPOLYGON (((-74.91364 7...
7   402.45060      2024  1.1469836 0.032816580 MULTIPOLYGON (((-75.86822 5...
8    81.86177      2024  0.4274956 0.006683387 MULTIPOLYGON (((-75.69149 6...
9   338.36185      2024  0.9164653 0.027679560 MULTIPOLYGON (((-75.27173 6...
10 1412.95696      2024  1.8476441 0.115706037 MULTIPOLYGON (((-74.90935 7...

para poder analizar los datos de la produccion de los frutales y los datos de los municipios haremos un join para eso los datos deben estar en el mismo formato

class(municipios$mpio_cdpmp)
[1] "character"
(stder.crs <- sf::st_crs(municipios))
Coordinate Reference System:
  User input: WGS 84 
  wkt:
GEOGCRS["WGS 84",
    ENSEMBLE["World Geodetic System 1984 ensemble",
        MEMBER["World Geodetic System 1984 (Transit)"],
        MEMBER["World Geodetic System 1984 (G730)"],
        MEMBER["World Geodetic System 1984 (G873)"],
        MEMBER["World Geodetic System 1984 (G1150)"],
        MEMBER["World Geodetic System 1984 (G1674)"],
        MEMBER["World Geodetic System 1984 (G1762)"],
        MEMBER["World Geodetic System 1984 (G2139)"],
        MEMBER["World Geodetic System 1984 (G2296)"],
        ELLIPSOID["WGS 84",6378137,298.257223563,
            LENGTHUNIT["metre",1]],
        ENSEMBLEACCURACY[2.0]],
    PRIMEM["Greenwich",0,
        ANGLEUNIT["degree",0.0174532925199433]],
    CS[ellipsoidal,2],
        AXIS["geodetic latitude (Lat)",north,
            ORDER[1],
            ANGLEUNIT["degree",0.0174532925199433]],
        AXIS["geodetic longitude (Lon)",east,
            ORDER[2],
            ANGLEUNIT["degree",0.0174532925199433]],
    USAGE[
        SCOPE["Horizontal component of 3D system."],
        AREA["World."],
        BBOX[-90,-180,90,180]],
    ID["EPSG",4326]]

4.Vias de colombia

vamos a añadir las vias de los municipios para ello descargamos los datos en un geoapackage de la siguiente pagina https://data.humdata.org/dataset/hotosm_col_roads, lo guerdaremos en el directorio de trabajo y usando la libreria sf filtraremos para obtener solo las vias de nuestro interes

list.files('/roads')
(sf.roads = st_read('roads.gpkg'))
Reading layer `roads' from data source 
  `C:\Users\Biblio\Desktop\proyecto 5-20261108T170448Z-1-001-20261111T154808Z-1-001\proyecto 5-20261108T170448Z-1-001\proyecto 5\entrega\roads.gpkg' 
  using driver `GPKG'
Simple feature collection with 1238606 features and 24 fields
Geometry type: GEOMETRY
Dimension:     XY
Bounding box:  xmin: -81.73539 ymin: -4.258755 xmax: -66.83066 ymax: 13.38636
Geodetic CRS:  WGS 84
Simple feature collection with 1238606 features and 24 fields
Geometry type: GEOMETRY
Dimension:     XY
Bounding box:  xmin: -81.73539 ymin: -4.258755 xmax: -66.83066 ymax: 13.38636
Geodetic CRS:  WGS 84
First 10 features:
               id       name name_en name_es     highway surface smoothness width lanes oneway bridge layer
1   way/332900376       <NA>    <NA>    <NA>     service    <NA>       <NA>  <NA>  <NA>   <NA>   <NA>  <NA>
2   way/180388997 Carrera 17    <NA>    <NA> residential unpaved       <NA>  <NA>  <NA>   <NA>   <NA>  <NA>
3   way/822292471       <NA>    <NA>    <NA>     service unpaved       <NA>     3  <NA>   <NA>   <NA>  <NA>
4   way/835847133  Carrera 7    <NA>    <NA> residential unpaved       <NA>  <NA>  <NA>   <NA>   <NA>  <NA>
5    way/76531894   Calle 24    <NA>    <NA> residential unpaved       <NA>  <NA>  <NA>    yes   <NA>  <NA>
6   way/180781725       <NA>    <NA>    <NA>     footway    <NA>       <NA>  <NA>  <NA>   <NA>   <NA>  <NA>
7   way/180380289 Carrera 18    <NA>    <NA> residential    <NA>       <NA>  <NA>  <NA>    yes   <NA>  <NA>
8   way/574904069 Carrera 12    <NA>    <NA> residential asphalt       <NA>  <NA>  <NA>    yes   <NA>  <NA>
9  way/1431563600       <NA>    <NA>    <NA>     service    <NA>       <NA>  <NA>  <NA>   <NA>   <NA>  <NA>
10  way/233980193       <NA>    <NA>    <NA>       track    <NA>       <NA>  <NA>  <NA>   <NA>   <NA>  <NA>
   source adm0_pcode adm0_name adm1_pcode adm1_name adm2_pcode adm2_name adm3_pcode adm3_name adm4_pcode
1    <NA>        COL  Colombia       CO81    Arauca    CO81001    Arauca       <NA>      <NA>       <NA>
2    <NA>        COL  Colombia       CO81    Arauca    CO81736  Saravena       <NA>      <NA>       <NA>
3    <NA>        COL  Colombia       CO81    Arauca    CO81736  Saravena       <NA>      <NA>       <NA>
4    <NA>        COL  Colombia       CO81    Arauca    CO81736  Saravena       <NA>      <NA>       <NA>
5    <NA>        COL  Colombia       CO81    Arauca    CO81736  Saravena       <NA>      <NA>       <NA>
6    <NA>        COL  Colombia       CO81    Arauca    CO81736  Saravena       <NA>      <NA>       <NA>
7    <NA>        COL  Colombia       CO81    Arauca    CO81736  Saravena       <NA>      <NA>       <NA>
8    <NA>        COL  Colombia       CO81    Arauca    CO81736  Saravena       <NA>      <NA>       <NA>
9    <NA>        COL  Colombia       CO81    Arauca    CO81736  Saravena       <NA>      <NA>       <NA>
10   <NA>        COL  Colombia       CO81    Arauca    CO81065 Arauquita       <NA>      <NA>       <NA>
   adm4_name name_latin                           geom
1       <NA>       <NA> LINESTRING (-71.09269 6.957...
2       <NA> Carrera 17 LINESTRING (-71.87846 6.956...
3       <NA>       <NA> LINESTRING (-71.83405 6.955...
4       <NA>  Carrera 7 LINESTRING (-71.86707 6.955...
5       <NA>   Calle 24 LINESTRING (-71.86982 6.957...
6       <NA>       <NA> LINESTRING (-71.87532 6.956...
7       <NA> Carrera 18 LINESTRING (-71.87999 6.956...
8       <NA> Carrera 12 LINESTRING (-71.87189 6.955...
9       <NA>       <NA> LINESTRING (-71.87497 6.956...
10      <NA>       <NA> LINESTRING (-71.16664 6.963...

se pude obervar que estos vectores tipo de geometria LINESTRING es un tipo de geometría que representa una línea formada por una secuencia de puntos conectados (vértices). Es el tipo que se usa para elementos lineales son y hay 1.203.341 registros u objetos espaciales (organizados en 24 campos de atributos). por lo que vamos a filtrar solo en los datos que necessitamos

cambiamos los datos para que los municipios y las vias tengan el mismo CRS

nroads <- st_transform(sf.roads, crs= stder.crs)

aplicamos el filtro (el valor co05 varia de departamento en departamento)

(stder.roads.tmp = dplyr::filter(nroads, adm1_pcode=="CO05"))
Simple feature collection with 170634 features and 24 fields
Geometry type: GEOMETRY
Dimension:     XY
Bounding box:  xmin: -76.9709 ymin: 5.477896 xmax: -73.88851 ymax: 8.865483
Geodetic CRS:  WGS 84
First 10 features:
               id                name name_en name_es      highway surface smoothness width lanes oneway bridge
1  way/1284729480                <NA>    <NA>    <NA>        track unpaved       <NA>  <NA>  <NA>   <NA>   <NA>
2   way/251861484                <NA>    <NA>    <NA>        track    <NA>       <NA>  <NA>  <NA>   <NA>   <NA>
3   way/251862287                <NA>    <NA>    <NA>  residential    <NA>       <NA>  <NA>  <NA>   <NA>   <NA>
4   way/251862161                <NA>    <NA>    <NA>        track    <NA>       <NA>  <NA>  <NA>   <NA>   <NA>
5   way/493380005                <NA>    <NA>    <NA>  residential    <NA>       <NA>  <NA>  <NA>   <NA>   <NA>
6   way/493379972                <NA>    <NA>    <NA>  residential    <NA>       <NA>  <NA>  <NA>   <NA>   <NA>
7  way/1495645394                <NA>    <NA>    <NA>        track    <NA>       <NA>  <NA>  <NA>   <NA>   <NA>
8  way/1284729479 Norcasia-San Miguel    <NA>    <NA> unclassified  gravel       <NA>  <NA>  <NA>   <NA>    yes
9   way/251861268                <NA>    <NA>    <NA>        track    <NA>       <NA>  <NA>  <NA>   <NA>   <NA>
10  way/251862288                <NA>    <NA>    <NA>        track    <NA>       <NA>  <NA>  <NA>   <NA>   <NA>
   layer source adm0_pcode adm0_name adm1_pcode adm1_name adm2_pcode adm2_name adm3_pcode adm3_name adm4_pcode
1   <NA>   <NA>        COL  Colombia       CO05 Antioquia    CO05756    Sonsón       <NA>      <NA>       <NA>
2   <NA>   <NA>        COL  Colombia       CO05 Antioquia    CO05756    Sonsón       <NA>      <NA>       <NA>
3   <NA>   <NA>        COL  Colombia       CO05 Antioquia    CO05756    Sonsón       <NA>      <NA>       <NA>
4   <NA>   <NA>        COL  Colombia       CO05 Antioquia    CO05756    Sonsón       <NA>      <NA>       <NA>
5   <NA>   <NA>        COL  Colombia       CO05 Antioquia    CO05756    Sonsón       <NA>      <NA>       <NA>
6   <NA>   <NA>        COL  Colombia       CO05 Antioquia    CO05756    Sonsón       <NA>      <NA>       <NA>
7   <NA>   <NA>        COL  Colombia       CO05 Antioquia    CO05756    Sonsón       <NA>      <NA>       <NA>
8      1   <NA>        COL  Colombia       CO05 Antioquia    CO05756    Sonsón       <NA>      <NA>       <NA>
9   <NA>   <NA>        COL  Colombia       CO05 Antioquia    CO05756    Sonsón       <NA>      <NA>       <NA>
10  <NA>   <NA>        COL  Colombia       CO05 Antioquia    CO05756    Sonsón       <NA>      <NA>       <NA>
   adm4_name          name_latin                           geom
1       <NA>                <NA> LINESTRING (-74.76013 5.711...
2       <NA>                <NA> LINESTRING (-74.78925 5.717...
3       <NA>                <NA> LINESTRING (-74.81217 5.717...
4       <NA>                <NA> LINESTRING (-74.81175 5.718...
5       <NA>                <NA> LINESTRING (-74.81583 5.718...
6       <NA>                <NA> LINESTRING (-74.81386 5.718...
7       <NA>                <NA> LINESTRING (-74.79754 5.726...
8       <NA> Norcasia-San Miguel LINESTRING (-74.72984 5.725...
9       <NA>                <NA> LINESTRING (-74.80196 5.729...
10      <NA>                <NA> LINESTRING (-74.81869 5.738...

seleccionamos las columnas importantes

stder.roads.tmp %>% select('id', 'name', 'highway',  'adm2_pcode', 'adm2_name') -> stder.roads

5. unir los datos

tenemos que asegurararnos que los datos que vamos a unir sean del mismo tipo ademas vamos a usar la libreria janitor para ajustar y limpiar nuestros datos para que no ocurran errores ademas usamos stringr para los codigos de los municipios sean iguales, aplicamos filtros y realizamos el joint

library(janitor)
library(stringr)

# Limpiar nombres de columnas
frutales <- clean_names(frutales)

# Asegurar que el código DANE tenga 5 dígitos (agrega el 0 a la izquierda para Antioquia: "05XXX")
frutales <- frutales %>%
  mutate(mpio_cdpmp = sprintf("%05d", as.numeric(codigo_dane_municipio)))

# Filtrar SOLO los municipios de Antioquia (cuyo código DANE inicia por "05")
municipios_antioquia <- municipios %>%
  filter(startsWith(as.character(mpio_cdpmp), "05"))

# Realizar el join solo con los municipios de Antioquia
munic_frutales <- left_join(municipios_antioquia, frutales, by = "mpio_cdpmp")

munic_frutales <- munic_frutales %>%
  mutate(etiqueta_mapa = ifelse(is.na(cultivo), 
                                mpio_cnmbr, 
                                paste0(mpio_cnmbr, "\n(", cultivo, ")")))

6. creacion del mapa

para crear el mapa debemos indicar las diferentes capas y objetos que vamos a utizar en nuestro mapa

frutales_map2 =  
  # CAPA 1: Municipios de Antioquia con Producción
  tm_shape(munic_frutales) + 
  # Se quita tm_view para que encuadre automáticamente en Antioquia
  tm_polygons(
    fill = "produccion",
    fill.scale = tm_scale_intervals(
      style = "jenks",
      n = 8),
    fill.legend = tm_legend(title = "Producción (t)")
  ) + 
  tm_text(
    text = "mpio_cnmbr", 
    size = 0.50, 
    fontfamily = "sans",
    col = "#222222",
    alpha = 0.85
  ) +
  
  # CAPA 2: Vías de Antioquia
  tm_shape(stder.roads) + 
  tm_lines(col = "darkgrey", lwd = 1.2, lty = "solid") + 
  
  # COMPONENTES DEL MAPA
  tm_credits("Fuente: UPRA (2020)", fontface = "bold") +
  tm_title("Producción de frutales en Antioquia (2020)",
           fontface = "bold.italic", 
           fontfamily = "monospace") +
  tm_scalebar(position = c("left", "bottom"))

── tmap v3 code detected ──────────────────────────────────────────────────────────

Ahora el mapa con el cultivo que hay en el departamento

frutales_map3 =  
  # CAPA 1: Municipios de Antioquia
  tm_shape(munic_frutales) + 
  tm_polygons(
    fill = "produccion",
    fill.scale = tm_scale_intervals(
      style = "jenks",
      n = 8),
    fill.legend = tm_legend(title = "Producción (t)")
  ) + 
  # ETIQUETAS: Muestra el nombre del municipio y el cultivo debajo
  tm_text(
    text = "cultivo", # Muestra la combinación de municipio y cultivo
    size = 0.45,            # Reducido ligeramente para evitar amontonamiento
    fontfamily = "sans",
    col = "#222222",
    alpha = 0.85
  ) +
  
  # CAPA 2: Vías
  tm_shape(stder.roads) + 
  tm_lines(col = "darkgrey", lwd = 1.2, lty = "solid") + 
  
  # COMPONENTES DEL MAPA
  tm_credits("Fuente: UPRA (2020)", fontface = "bold") +
  tm_title("Cultivo principal y producción de frutales en Antioquia",
           fontface = "bold.italic", 
           fontfamily = "monospace") +
  tm_scalebar(position = c("left", "bottom"))

── tmap v3 code detected ───────────────────────────────────────────────────────────────────────────────────────────────────────────

ahoras visualisamos el mapa creado

frutales_map2
Aviso en graphics::strwidth(comp$text, units = "inch", family = comp$fontfamily,  :
  font family not found in Windows font database
[plot mode] fit legend/component: Some legend items or map compoments do not fit well, and are therefore
rescaled.
ℹ Set the tmap option `component.autoscale = FALSE` to disable rescaling.
Aviso en grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y,  :
  font family not found in Windows font database

frutales_map3
Aviso en graphics::strwidth(comp$text, units = "inch", family = comp$fontfamily,  :
  font family not found in Windows font database
[plot mode] fit legend/component: Some legend items or map compoments do not fit well, and are therefore rescaled.
ℹ Set the tmap option `component.autoscale = FALSE` to disable rescaling.
Aviso en grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y,  :
  font family not found in Windows font database

##7. Referencias

Lizarazo, I. 2026. How to make a map of agricultural production. Available at https:rpubs.com/ials2un/MakeEVAmap

LS0tDQp0aXRsZTogIk1hcGFzIEFncmljdWx0dXJhIEVWQSINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQpzYW50aWFnbyBkZWxnYWRvIGZyYW5jbw0KDQoNCiMjIyBNYXBhcyBkZSBsYSBwcm9kdWNjaW9uIGFncmljb2xhIA0KIyMgMS5JbnRyb2R1Y2Npw7NuIA0KRXN0ZSBjdWFkZXJubyBleHBsaWNhIGPDs21vIGhhY2VyIG1hcGFzIHRlbcOhdGljb3MgcGFyYSBsYSBwcm9kdWNjacOzbiBhZ3LDrWNvbGEuIFBhcmEgZWxsbyBuZWNlc2l0YW1vcyBkb3MgYXJjaGl2b3MgcGFyYSBlbXBlemFyOiB1biBhcmNoaXZvIENTViBjb24gbG9zIGRhdG9zIGRlIGxhIHByb2R1Y2Npw7NuIGFncsOtY29sYSBwb3IgbXVuaWNpcGlvIChFVkEyMDIwKSB5IHVuIGdlb3BhY2thZ2UgY29uIGxvcyBtdW5pY2lwaW9zIGRlIG51ZXN0cm8gZGVwYXJ0YW1lbnRvIGRlIGVzdHVkaW8uIE3DoXMgYWRlbGFudGUgdXNhcmVtb3MgdW4gYXJjaGl2byBjb24gbGFzIHbDrWFzIGRlIGxvcyBtdW5pY2lwaW9zLg0KDQoNCiMjIDIucHJlcGFyYWNjacOzbiANCg0KcmVxdWVyaW1vcyB0ZW5lciBpbnN0YWxhZGFzIGxhcyBsaWJyZXJpYXMgeSBjYXJnYXJsYXMgKipkcHlhcioqLCoqdG1hcCoqIHkgKipzZioqIA0KYGBge3J9DQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeSh0bWFwKQ0KbGlicmFyeShzZikNCmxpYnJhcnkocmVhZHIpDQpgYGANCg0KIyMgMy5sZWN0dXJhIGRlIGxvcyBhcmNoaXZvcyBkZSBsb3MgbXVuaWNpcGlvcyB5IGN1bHRpdm9zDQoNCg0KcGFyYSBlc3RlIGN1YWRlcm5vIHRyYWJhamFyZW1vcyBjb24gZWwgZGVwYXJ0YW1lbnRvIGRlIGFudGlvcXVpYSBhbnRlcyBkZSBlbXBlemFyIHRyYWJhamFyZW1vcyBlbiBlbCBmb2xkZXIgL0dCMDIvcHJveWVjdG8gNiBlbiBkb25kZSBzZSBlbmN1ZW50cmFuIG51ZXN0cm9zIGFyY2hpdm9zIGEgYW5hbGl6YXIgZ2VvcGFja2FnZSBkZWwgZGVwYXJ0YW1lbnRvIGRlIGFudGlvcXVpYSB5IHN1cyBtdW5pY2lwaW9zIHkgIGNzdiBmaWxlIGNvbiBFVkEgMjAyMCBjb24gbGFzIGVzdGFkaXNjdGljYXMgZGUgbG9zIGN1bHRpdm9zIA0KDQpgYGB7cn0NCmxpc3QuZmlsZXMoKQ0KYGBgDQoNCmFob3JhIHByb2NlZGVtb3MgYSBsZWVyIHkgY2FyZ2FyIGVsIGFyY2hpdm8gY3N2DQpgYGB7cn0NCg0KZnJ1dGFsZXMgPC0gcmVhZF9kZWxpbSgiRlJVVEFMRVMuY3N2IiwgZGVsaW0gPSAiOyIsIGxvY2FsZSA9IGxvY2FsZShlbmNvZGluZyA9ICJVVEYtOCIpKQ0KYGBgDQoNCnkgY2FyZ2Ftb3MgbG9zIG11bmljaXBpb3MgZGVsIEdlb3BhY2thZ2UNCg0KYGBge3J9DQoobXVuaWNpcGlvcyA9ICBzdF9yZWFkKCdtdW5pY2lwaW9zLmdwa2cnKSkNCg0KYGBgDQoNCnBhcmEgcG9kZXIgYW5hbGl6YXIgbG9zIGRhdG9zIGRlIGxhIHByb2R1Y2Npb24gZGUgbG9zIGZydXRhbGVzIHkgbG9zIGRhdG9zIGRlIGxvcyBtdW5pY2lwaW9zIGhhcmVtb3MgdW4gam9pbiBwYXJhIGVzbyBsb3MgZGF0b3MgZGViZW4gZXN0YXIgZW4gZWwgbWlzbW8gZm9ybWF0byANCg0KYGBge3J9DQpjbGFzcyhtdW5pY2lwaW9zJG1waW9fY2RwbXApDQpgYGANCg0KYGBge3J9DQooc3RkZXIuY3JzIDwtIHNmOjpzdF9jcnMobXVuaWNpcGlvcykpDQpgYGANCiMjIDQuVmlhcyBkZSBjb2xvbWJpYSANCg0KdmFtb3MgYSBhw7FhZGlyIGxhcyB2aWFzIGRlIGxvcyBtdW5pY2lwaW9zIHBhcmEgZWxsbyBkZXNjYXJnYW1vcyBsb3MgZGF0b3MgZW4gdW4gZ2VvYXBhY2thZ2UgZGUgbGEgc2lndWllbnRlIHBhZ2luYSAqKmh0dHBzOi8vZGF0YS5odW1kYXRhLm9yZy9kYXRhc2V0L2hvdG9zbV9jb2xfcm9hZHMqKiwgbG8gZ3VlcmRhcmVtb3MgZW4gZWwgZGlyZWN0b3JpbyBkZSB0cmFiYWpvIHkgdXNhbmRvIGxhIGxpYnJlcmlhICoqc2YqKiBmaWx0cmFyZW1vcyBwYXJhIG9idGVuZXIgc29sbyBsYXMgdmlhcyBkZSBudWVzdHJvIGludGVyZXMgDQoNCmBgYHtyfQ0KbGlzdC5maWxlcygnL3JvYWRzJykNCmBgYA0KDQpgYGB7cn0NCihzZi5yb2FkcyA9IHN0X3JlYWQoJ3JvYWRzLmdwa2cnKSkNCmBgYA0KDQoNCnNlIHB1ZGUgb2JlcnZhciBxdWUgZXN0b3MgdmVjdG9yZXMgdGlwbyBkZSBnZW9tZXRyaWEgTElORVNUUklORyBlcyB1biB0aXBvIGRlIGdlb21ldHLDrWEgcXVlIHJlcHJlc2VudGEgdW5hIGzDrW5lYSBmb3JtYWRhIHBvciB1bmEgc2VjdWVuY2lhIGRlIHB1bnRvcyBjb25lY3RhZG9zICh2w6lydGljZXMpLiBFcyBlbCB0aXBvIHF1ZSBzZSB1c2EgcGFyYSBlbGVtZW50b3MgbGluZWFsZXMgc29uICB5IGhheSAxLjIwMy4zNDEgcmVnaXN0cm9zIHUgb2JqZXRvcyBlc3BhY2lhbGVzIChvcmdhbml6YWRvcyBlbiAyNCBjYW1wb3MgZGUgYXRyaWJ1dG9zKS4gcG9yIGxvIHF1ZSB2YW1vcyBhIGZpbHRyYXIgc29sbyBlbiBsb3MgZGF0b3MgcXVlIG5lY2Vzc2l0YW1vcyANCg0KY2FtYmlhbW9zIGxvcyBkYXRvcyBwYXJhIHF1ZSBsb3MgbXVuaWNpcGlvcyB5IGxhcyB2aWFzIHRlbmdhbiBlbCBtaXNtbyBDUlMNCmBgYHtyfQ0KbnJvYWRzIDwtIHN0X3RyYW5zZm9ybShzZi5yb2FkcywgY3JzPSBzdGRlci5jcnMpDQpgYGANCg0KDQphcGxpY2Ftb3MgZWwgZmlsdHJvIChlbCB2YWxvciBjbzA1IHZhcmlhIGRlIGRlcGFydGFtZW50byBlbiBkZXBhcnRhbWVudG8pDQoNCmBgYHtyfQ0KKHN0ZGVyLnJvYWRzLnRtcCA9IGRwbHlyOjpmaWx0ZXIobnJvYWRzLCBhZG0xX3Bjb2RlPT0iQ08wNSIpKQ0KYGBgDQoNCnNlbGVjY2lvbmFtb3MgbGFzIGNvbHVtbmFzIGltcG9ydGFudGVzIA0KDQpgYGB7cn0NCnN0ZGVyLnJvYWRzLnRtcCAlPiUgc2VsZWN0KCdpZCcsICduYW1lJywgJ2hpZ2h3YXknLCAgJ2FkbTJfcGNvZGUnLCAnYWRtMl9uYW1lJykgLT4gc3RkZXIucm9hZHMNCmBgYA0KDQoNCiMjIDUuIHVuaXIgbG9zIGRhdG9zIA0KDQp0ZW5lbW9zIHF1ZSBhc2VndXJhcmFybm9zIHF1ZSBsb3MgZGF0b3MgcXVlIHZhbW9zIGEgdW5pciBzZWFuIGRlbCBtaXNtbyB0aXBvIGFkZW1hcyB2YW1vcyBhIHVzYXIgbGEgbGlicmVyaWEgamFuaXRvciBwYXJhIGFqdXN0YXIgeSBsaW1waWFyIG51ZXN0cm9zIGRhdG9zIHBhcmEgcXVlIG5vIG9jdXJyYW4gZXJyb3JlcyBhZGVtYXMgdXNhbW9zIHN0cmluZ3IgcGFyYSBsb3MgY29kaWdvcyBkZSBsb3MgbXVuaWNpcGlvcyBzZWFuIGlndWFsZXMsIGFwbGljYW1vcyBmaWx0cm9zIHkgcmVhbGl6YW1vcyBlbCBqb2ludA0KDQoNCg0KYGBge3J9DQpsaWJyYXJ5KGphbml0b3IpDQpsaWJyYXJ5KHN0cmluZ3IpDQoNCiMgTGltcGlhciBub21icmVzIGRlIGNvbHVtbmFzDQpmcnV0YWxlcyA8LSBjbGVhbl9uYW1lcyhmcnV0YWxlcykNCg0KIyBBc2VndXJhciBxdWUgZWwgY8OzZGlnbyBEQU5FIHRlbmdhIDUgZMOtZ2l0b3MgKGFncmVnYSBlbCAwIGEgbGEgaXpxdWllcmRhIHBhcmEgQW50aW9xdWlhOiAiMDVYWFgiKQ0KZnJ1dGFsZXMgPC0gZnJ1dGFsZXMgJT4lDQogIG11dGF0ZShtcGlvX2NkcG1wID0gc3ByaW50ZigiJTA1ZCIsIGFzLm51bWVyaWMoY29kaWdvX2RhbmVfbXVuaWNpcGlvKSkpDQoNCiMgRmlsdHJhciBTT0xPIGxvcyBtdW5pY2lwaW9zIGRlIEFudGlvcXVpYSAoY3V5byBjw7NkaWdvIERBTkUgaW5pY2lhIHBvciAiMDUiKQ0KbXVuaWNpcGlvc19hbnRpb3F1aWEgPC0gbXVuaWNpcGlvcyAlPiUNCiAgZmlsdGVyKHN0YXJ0c1dpdGgoYXMuY2hhcmFjdGVyKG1waW9fY2RwbXApLCAiMDUiKSkNCg0KIyBSZWFsaXphciBlbCBqb2luIHNvbG8gY29uIGxvcyBtdW5pY2lwaW9zIGRlIEFudGlvcXVpYQ0KbXVuaWNfZnJ1dGFsZXMgPC0gbGVmdF9qb2luKG11bmljaXBpb3NfYW50aW9xdWlhLCBmcnV0YWxlcywgYnkgPSAibXBpb19jZHBtcCIpDQoNCm11bmljX2ZydXRhbGVzIDwtIG11bmljX2ZydXRhbGVzICU+JQ0KICBtdXRhdGUoZXRpcXVldGFfbWFwYSA9IGlmZWxzZShpcy5uYShjdWx0aXZvKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1waW9fY25tYnIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXN0ZTAobXBpb19jbm1iciwgIlxuKCIsIGN1bHRpdm8sICIpIikpKQ0KYGBgDQoNCg0KIyMgNi4gY3JlYWNpb24gZGVsIG1hcGENCg0KDQpwYXJhIGNyZWFyIGVsIG1hcGEgZGViZW1vcyBpbmRpY2FyIGxhcyBkaWZlcmVudGVzIGNhcGFzIHkgb2JqZXRvcyBxdWUgdmFtb3MgYSB1dGl6YXIgZW4gbnVlc3RybyBtYXBhDQpgYGB7cn0NCmZydXRhbGVzX21hcDIgPSAgDQogICMgQ0FQQSAxOiBNdW5pY2lwaW9zIGRlIEFudGlvcXVpYSBjb24gUHJvZHVjY2nDs24NCiAgdG1fc2hhcGUobXVuaWNfZnJ1dGFsZXMpICsgDQogICMgU2UgcXVpdGEgdG1fdmlldyBwYXJhIHF1ZSBlbmN1YWRyZSBhdXRvbcOhdGljYW1lbnRlIGVuIEFudGlvcXVpYQ0KICB0bV9wb2x5Z29ucygNCiAgICBmaWxsID0gInByb2R1Y2Npb24iLA0KICAgIGZpbGwuc2NhbGUgPSB0bV9zY2FsZV9pbnRlcnZhbHMoDQogICAgICBzdHlsZSA9ICJqZW5rcyIsDQogICAgICBuID0gOCksDQogICAgZmlsbC5sZWdlbmQgPSB0bV9sZWdlbmQodGl0bGUgPSAiUHJvZHVjY2nDs24gKHQpIikNCiAgKSArIA0KICB0bV90ZXh0KA0KICAgIHRleHQgPSAibXBpb19jbm1iciIsIA0KICAgIHNpemUgPSAwLjUwLCANCiAgICBmb250ZmFtaWx5ID0gInNhbnMiLA0KICAgIGNvbCA9ICIjMjIyMjIyIiwNCiAgICBhbHBoYSA9IDAuODUNCiAgKSArDQogIA0KICAjIENBUEEgMjogVsOtYXMgZGUgQW50aW9xdWlhDQogIHRtX3NoYXBlKHN0ZGVyLnJvYWRzKSArIA0KICB0bV9saW5lcyhjb2wgPSAiZGFya2dyZXkiLCBsd2QgPSAxLjIsIGx0eSA9ICJzb2xpZCIpICsgDQogIA0KICAjIENPTVBPTkVOVEVTIERFTCBNQVBBDQogIHRtX2NyZWRpdHMoIkZ1ZW50ZTogVVBSQSAoMjAyMCkiLCBmb250ZmFjZSA9ICJib2xkIikgKw0KICB0bV90aXRsZSgiUHJvZHVjY2nDs24gZGUgZnJ1dGFsZXMgZW4gQW50aW9xdWlhICgyMDIwKSIsDQogICAgICAgICAgIGZvbnRmYWNlID0gImJvbGQuaXRhbGljIiwgDQogICAgICAgICAgIGZvbnRmYW1pbHkgPSAibW9ub3NwYWNlIikgKw0KICB0bV9zY2FsZWJhcihwb3NpdGlvbiA9IGMoImxlZnQiLCAiYm90dG9tIikpDQpgYGANCkFob3JhIGVsIG1hcGEgY29uIGVsIGN1bHRpdm8gcXVlIGhheSBlbiBlbCBkZXBhcnRhbWVudG8NCmBgYHtyfQ0KZnJ1dGFsZXNfbWFwMyA9ICANCiAgIyBDQVBBIDE6IE11bmljaXBpb3MgZGUgQW50aW9xdWlhDQogIHRtX3NoYXBlKG11bmljX2ZydXRhbGVzKSArIA0KICB0bV9wb2x5Z29ucygNCiAgICBmaWxsID0gInByb2R1Y2Npb24iLA0KICAgIGZpbGwuc2NhbGUgPSB0bV9zY2FsZV9pbnRlcnZhbHMoDQogICAgICBzdHlsZSA9ICJqZW5rcyIsDQogICAgICBuID0gOCksDQogICAgZmlsbC5sZWdlbmQgPSB0bV9sZWdlbmQodGl0bGUgPSAiUHJvZHVjY2nDs24gKHQpIikNCiAgKSArIA0KICAjIEVUSVFVRVRBUzogTXVlc3RyYSBlbCBub21icmUgZGVsIG11bmljaXBpbyB5IGVsIGN1bHRpdm8gZGViYWpvDQogIHRtX3RleHQoDQogICAgdGV4dCA9ICJjdWx0aXZvIiwgIyBNdWVzdHJhIGxhIGNvbWJpbmFjacOzbiBkZSBtdW5pY2lwaW8geSBjdWx0aXZvDQogICAgc2l6ZSA9IDAuNDUsICAgICAgICAgICAgIyBSZWR1Y2lkbyBsaWdlcmFtZW50ZSBwYXJhIGV2aXRhciBhbW9udG9uYW1pZW50bw0KICAgIGZvbnRmYW1pbHkgPSAic2FucyIsDQogICAgY29sID0gIiMyMjIyMjIiLA0KICAgIGFscGhhID0gMC44NQ0KICApICsNCiAgDQogICMgQ0FQQSAyOiBWw61hcw0KICB0bV9zaGFwZShzdGRlci5yb2FkcykgKyANCiAgdG1fbGluZXMoY29sID0gImRhcmtncmV5IiwgbHdkID0gMS4yLCBsdHkgPSAic29saWQiKSArIA0KICANCiAgIyBDT01QT05FTlRFUyBERUwgTUFQQQ0KICB0bV9jcmVkaXRzKCJGdWVudGU6IFVQUkEgKDIwMjApIiwgZm9udGZhY2UgPSAiYm9sZCIpICsNCiAgdG1fdGl0bGUoIkN1bHRpdm8gcHJpbmNpcGFsIHkgcHJvZHVjY2nDs24gZGUgZnJ1dGFsZXMgZW4gQW50aW9xdWlhIiwNCiAgICAgICAgICAgZm9udGZhY2UgPSAiYm9sZC5pdGFsaWMiLCANCiAgICAgICAgICAgZm9udGZhbWlseSA9ICJtb25vc3BhY2UiKSArDQogIHRtX3NjYWxlYmFyKHBvc2l0aW9uID0gYygibGVmdCIsICJib3R0b20iKSkNCmBgYA0KDQoNCmFob3JhcyB2aXN1YWxpc2Ftb3MgZWwgbWFwYSBjcmVhZG8NCmBgYHtyfQ0KZnJ1dGFsZXNfbWFwMg0KYGBgDQoNCg0KDQoNCg0KYGBge3J9DQpmcnV0YWxlc19tYXAzDQpgYGANCg0KDQojIzcuIFJlZmVyZW5jaWFzIA0KDQpMaXphcmF6bywgSS4gMjAyNi4gSG93IHRvIG1ha2UgYSBtYXAgb2YgYWdyaWN1bHR1cmFsIHByb2R1Y3Rpb24uIEF2YWlsYWJsZSBhdCBodHRwczpycHVicy5jb20vaWFsczJ1bi9NYWtlRVZBbWFwDQoNCg0KDQo=