Introduction
• Spatial data provide insights
• Spread of a disease, or
• Situation of an outbreak
• Where are the current disease hotspots?
• How have the hotspots changed over time?
• How is the access to health facilities?

• Today, why to use R to address these tasks.
Learning
objectives
Define what is a geospatial analysis.
Identify the main analytical task that a GIS
software need to solve.
Identify the advantages of R as a GIS
software.
Prerequisites
This lesson requires familiarity with basic R and
{ggplot2}
: if you need to brush up, have a look at our
introductory course on R and data visualization.
if(!require('pacman')) install.packages('pacman')
pacman::p_load_gh("wmgeolab/rgeoboundaries")
pacman::p_load(tidyverse,
ggspatial,
leaflet,
mapview,
raster,
spData,
stars,
tmap,
here,
sf)
What is Geospatial
analysis?
• Data with geographic locations or coordinates
• Related to positions on the Earth’s surface.
• Essential to epidemiology.
• Identify hot-spots and potential high-risk
areas for communicable disease spread;
• Map of malaria prevalence predictions in The Gambia (Moraga,
2019)

• Let’s see how the code looks like!
# 👉 first, get packages:
if(!require('pacman')) install.packages('pacman')
pacman::p_load_gh("wmgeolab/rgeoboundaries")
pacman::p_load(tidyverse, ggspatial, leaflet,
raster, stars, here, prettymapr)
# 👉 second, get data:
# country boundaries
gambia_boundaries <- geoboundaries(country = "Gambia", adm_lvl = 1)
# malaria prevalence
gambia_prevalence <- read_rds(here("data", "gambia_prevalence.rds"))
# 👉 third, plot data:
ggplot() +
# with a background
annotation_map_tile(data = gambia_boundaries, zoomin = 0) +
# plus a prevalence surface
geom_stars(data = st_as_stars(gambia_prevalence)) +
# with a color scale
scale_fill_viridis_c(na.value = "transparent", alpha = 0.75) +
# and a coordinate system
coord_sf()

• Here, skills for geospatial visualization,
• To make accurate, elegant and
informative maps.
R as a GIS
• Geospatial analysis needs a geographic information system
(GIS).
• Manage, analyze, and visualize spatial
data.
• Popular platforms, ArcGIS and
QGIS, are graphic-user-interface (GUI).
• So why use R for geospatial work?
• Here five of its merits:
(1/5)
Reproducibility:
• Code is straightforward for anyone to re-run,
• Easily build on other people’s work
• Facilitates collaboration
• Paste this code and reproduce in your computer:
# 👉 packages
if(!require('pacman')) install.packages('pacman')
pacman::p_load(sf, ggplot2)
# 👉 data
nc <- st_read(system.file("shape/nc.shp", package = "sf"),
quiet = TRUE)
# 👉 plot
ggplot(data = nc) +
geom_sf(aes(fill = SID74)) +
scale_fill_viridis_c()

(2/5)Reporting:
• {Rmarkdown}
, {flexdashboard}
and
{shiny}
to generate reports and dashboards.
• Interactive maps with {leaflet}
instead of
{ggplot2}
:
# 👉 packages
if(!require('pacman')) install.packages('pacman')
pacman::p_load(sf, leaflet)
# 👉 data
nc <- st_read(system.file("shape/nc.shp", package = "sf"),
quiet = TRUE)
# 👉 plot
pal <- colorNumeric("YlOrRd", domain = nc$SID74)
leaflet(nc) %>%
addTiles() %>%
addPolygons(color = "white", fillColor = ~ pal(SID74),
fillOpacity = 1) %>%
addLegend(pal = pal, values = ~SID74, opacity = 1)
(3/5) Rich
ecosystem:
• R with rapidly growing libraries
• highly-active open-source community,
• ready-to-use packages or tutorials.
• interactive map with one line of code!
• {mapview}
instead of {leaflet}
:
# 👉 packages
if(!require('pacman')) install.packages('pacman')
pacman::p_load(sf, mapview)
# 👉 data
nc <- st_read(system.file("shape/nc.shp", package = "sf"),
quiet = TRUE)
# 👉 plot
mapview(nc, zcol = "SID74")
(4/5)
Convenience:
• You already know R!
• Explore new pieces of code.
As an example, we will use the {tmap}
package and make
minor modifications to it!
First, run this chunk:
# 👉 packages
if(!require('pacman')) install.packages('pacman')
pacman::p_load(tmap, spData)
# 👉 data
load(here("data/nz_elev.rda"))
# 👉 plot
tm_shape(nz_elev) +
tm_raster(title = "Elevation (m)", # Add units to the legend title
style = "cont",
palette = "-BuGn") +
tm_shape(nz) +
tm_borders(col = "black",
lwd = 1) + # Reduce line width
tm_scale_bar(breaks = c(0, 100, 200),
text.size = 1) +
tm_compass(position = c("RIGHT", "top"),
type = "rose",
size = 2) +
tm_credits(text = "O A Lawal, 2024") +
tm_layout(main.title = "New Zealand",
bg.color = "lightgreen", # Change background color
inner.margins = c(0, 0, 0, 0), legend.title.size = 1.5) # Adjust legend title size

Now, apply any of the following suggestions to get used to how this
package works:
- Change the map title from “My map” to “New
Zealand”.
- Update the map credits with your own name and
today’s date.
- Change the color palette to “BuGn”.
- Try other palettes from http://colorbrewer2.org/
- Put the north arrow in the top right corner of the
map.
- Improve the legend title by adding the legend
units.
- Increase the number of breaks in the scale
bar.
- Change the borders’ color of the New Zealand’s
regions to black.
- Decrease the line width.
- Change the background color to any color of your
choice.
Wrap up
• We learned why to use R as a GIS software,
• take advantage of its coding environment.
• But, which maps are we going to built?
Figure 1. Thematic maps: (A) Choropleth map, (B)
Dot map, (C) Density map, and (D) Basemap for a dot map.
• How to built -step by step- different types of Thematic
maps using the {ggplot2}
package,
• different data sources and illustrative annotations.
Figure 2. {ggplot2} map with text annotations, a
scale bar and north arrow.
Contributors
The following team members contributed to this lesson:
References
Some material in this lesson was adapted from the following
sources:
Batra, Neale, et al. (2021). The Epidemiologist R Handbook.
Chapter 28: GIS Basics. (2021). Retrieved 01 April 2022, from https://epirhandbook.com/en/gis-basics.html
Baumer, Benjamin S., Kaplan, Daniel T., and Horton, Nicholas
J. Modern Data Science with R. Chapter 17: Working with geospatial
data. (2021). Retrieved 05 June 2022, from https://mdsr-book.github.io/mdsr2e/ch-spatial.html
Lovelace, R., Nowosad, J., & Muenchow, J. Geocomputation
with R. Chapter 2: Geographic data in R. (2019). Retrieved 01 April
2022, from https://geocompr.robinlovelace.net/spatial-class.html
Moraga, Paula. Geospatial Health Data: Modeling and
Visualization with R-INLA and Shiny. Chapter 12: Building a dashboard to
visualize spatial data with flexdashboard. (2019). Retrieved 13
September 2022, from https://www.paulamoraga.com/book-geospatial/sec-flexdashboard.html
Moreno, M., and Bastille, M. Drawing beautiful maps
programmatically with R, sf and ggplot2 — Part 1: Basics. (2018).
Retrieved 13 September 2022, from https://r-spatial.org/r/2018/10/25/ggplot2-sf.html.
Nowosad, J. Basics of Spatial Data Analysis Workshop.
(2019). Retrieved 13 September 2022, from https://github.com/Nowosad/whyr_19w/blob/master/code/spatial_vis.R
Nowosad, J. The Landscape of Spatial Data Analysis in R.
(2019). Retrieved 13 September 2022, from https://jakubnowosad.com/whyr_19/#1
This work is licensed under the Creative Commons Attribution Share Alike license. 
LS0tDQp0aXRsZTogJ1IgZm9yIEdJUycNCmF1dGhvcjoNCiAgLSBuYW1lOiAiQW5kcmVlIFZhbGxlIENhbXBvcyINCiAgLSBuYW1lOiAiS2VuZSBEYXZpZCBOd29zdSINCmRhdGU6ICIyMDI0LTExLTIyIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIGNvZGVfZm9sZGluZzogInNob3ciDQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQ0KICAgIHRvYzogdHJ1ZQ0KICAgIGNzczogIWV4cHIgaGVyZTo6aGVyZSgiZ2xvYmFsL3N0eWxlL3N0eWxlLmNzcyIpDQogICAgaGlnaGxpZ2h0OiBrYXRlDQogICAgcGFuZG9jX2FyZ3M6IC0tc2hpZnQtaGVhZGluZy1sZXZlbC1ieT0tMQ0KZWRpdG9yX29wdGlvbnM6DQogIG1hcmtkb3duOg0KICAgIHdyYXA6IDEwMA0KICBjYW5vbmljYWw6IHRydWUNCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQ0KLS0tDQoNCmBgYHtyLCBpbmNsdWRlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFfQ0KIyBMb2FkIHBhY2thZ2VzIA0KaWYoIXJlcXVpcmUocGFjbWFuKSkgaW5zdGFsbC5wYWNrYWdlcygicGFjbWFuIikNCnBhY21hbjo6cF9sb2FkKHRpZHl2ZXJzZSwga25pdHIsIGhlcmUpDQoNCiMgU291cmNlIGZ1bmN0aW9ucyANCnNvdXJjZShoZXJlKCJnbG9iYWwvZnVuY3Rpb25zL21pc2NfZnVuY3Rpb25zLlIiKSkNCg0KIyBrbml0ciBzZXR0aW5ncw0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KHdhcm5pbmcgPSBGLCBtZXNzYWdlID0gRiwgY2xhc3Muc291cmNlID0gInRnYy1jb2RlLWJsb2NrIiwgZXJyb3IgPSBUKQ0KYGBgDQoNCmBgYHtyLGVjaG89RkFMU0V9DQpnZ3Bsb3QyOjp0aGVtZV9zZXQobmV3ID0gdGhlbWVfYncoKSkNCm9wdGlvbnMoc2NpcGVuPTEwMDAwKQ0KYGBgDQoNCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQo8IS0tICMgR2Vvc3BhdGlhbCBhbmFseXNpczogUiBmb3IgR0lTIC0tPg0KDQojIyBJbnRyb2R1Y3Rpb24NCg0K4oCiIFNwYXRpYWwgZGF0YSBwcm92aWRlIGluc2lnaHRzDQoNCuKAoiAqU3ByZWFkKiBvZiBhIGRpc2Vhc2UsIG9yDQoNCuKAoiAqU2l0dWF0aW9uKiBvZiBhbiBvdXRicmVhaw0KDQrigKIgKipXaGVyZSoqIGFyZSB0aGUgY3VycmVudCBkaXNlYXNlIGhvdHNwb3RzPw0KDQrigKIgSG93IGhhdmUgdGhlIGhvdHNwb3RzICoqY2hhbmdlZCBvdmVyIHRpbWUqKj8NCg0K4oCiIEhvdyBpcyB0aGUgKiphY2Nlc3MqKiB0byBoZWFsdGggZmFjaWxpdGllcz8NCg0KIVtdKGltYWdlcy9naXNfaGVhZF9pbWFnZS5wbmcpDQoNCuKAoiBUb2RheSwgKip3aHkgdG8gdXNlIFIqKiB0byBhZGRyZXNzIHRoZXNlIHRhc2tzLg0KDQojIyBMZWFybmluZyBvYmplY3RpdmVzDQoNCjEuICBEZWZpbmUgd2hhdCBpcyBhICoqZ2Vvc3BhdGlhbCBhbmFseXNpcyoqLg0KDQoyLiAgSWRlbnRpZnkgdGhlIG1haW4gYW5hbHl0aWNhbCB0YXNrIHRoYXQgYSAqKkdJUyBzb2Z0d2FyZSoqIG5lZWQgdG8gc29sdmUuDQoNCjMuICBJZGVudGlmeSB0aGUgKiphZHZhbnRhZ2VzKiogb2YgUiBhcyBhIEdJUyBzb2Z0d2FyZS4NCg0KIyMgUHJlcmVxdWlzaXRlcw0KDQpUaGlzIGxlc3NvbiByZXF1aXJlcyBmYW1pbGlhcml0eSB3aXRoIGJhc2ljIFIgYW5kIGB7Z2dwbG90Mn1gOiBpZiB5b3UgbmVlZCB0byBicnVzaCB1cCwgaGF2ZSBhIGxvb2sgYXQgb3VyIGludHJvZHVjdG9yeSBjb3Vyc2Ugb24gUiBhbmQgZGF0YSB2aXN1YWxpemF0aW9uLg0KDQpgYGB7cixldmFsPVRSVUUsZWNobz1UUlVFLG1lc3NhZ2U9RkFMU0V9DQppZighcmVxdWlyZSgncGFjbWFuJykpIGluc3RhbGwucGFja2FnZXMoJ3BhY21hbicpDQpwYWNtYW46OnBfbG9hZF9naCgid21nZW9sYWIvcmdlb2JvdW5kYXJpZXMiKQ0KcGFjbWFuOjpwX2xvYWQodGlkeXZlcnNlLCANCiAgICAgICAgICAgICAgIGdnc3BhdGlhbCwgDQogICAgICAgICAgICAgICBsZWFmbGV0LCANCiAgICAgICAgICAgICAgIG1hcHZpZXcsDQogICAgICAgICAgICAgICByYXN0ZXIsDQogICAgICAgICAgICAgICBzcERhdGEsDQogICAgICAgICAgICAgICBzdGFycywgDQogICAgICAgICAgICAgICB0bWFwLCANCiAgICAgICAgICAgICAgIGhlcmUsDQogICAgICAgICAgICAgICBzZikNCmBgYA0KDQojIyBXaGF0IGlzIEdlb3NwYXRpYWwgYW5hbHlzaXM/DQoNCuKAoiBEYXRhIHdpdGggKmdlb2dyYXBoaWMqIGxvY2F0aW9ucyBvciBjb29yZGluYXRlcw0KDQrigKIgUmVsYXRlZCB0byBwb3NpdGlvbnMgb24gdGhlIEVhcnRoJ3Mgc3VyZmFjZS4NCg0K4oCiIEVzc2VudGlhbCB0byBlcGlkZW1pb2xvZ3kuDQoNCuKAoiBJZGVudGlmeSAqKmhvdC1zcG90cyoqIGFuZCBwb3RlbnRpYWwgKipoaWdoLXJpc2sgYXJlYXMqKiBmb3IgY29tbXVuaWNhYmxlIGRpc2Vhc2Ugc3ByZWFkOw0KDQrigKIgTWFwIG9mIG1hbGFyaWEgcHJldmFsZW5jZSBwcmVkaWN0aW9ucyBpbiBUaGUgR2FtYmlhIChNb3JhZ2EsIDIwMTkpDQoNCiFbXShpbWFnZXMvbWFsYXJpYV9nYW1iaWFfMDEucG5nKQ0KDQrigKIgTGV0J3Mgc2VlIGhvdyB0aGUgY29kZSBsb29rcyBsaWtlIQ0KDQpgYGB7cixtZXNzYWdlPUZBTFNFLHdhcm5pbmc9RkFMU0V9DQojIPCfkYkgZmlyc3QsIGdldCBwYWNrYWdlczoNCg0KaWYoIXJlcXVpcmUoJ3BhY21hbicpKSBpbnN0YWxsLnBhY2thZ2VzKCdwYWNtYW4nKQ0KcGFjbWFuOjpwX2xvYWRfZ2goIndtZ2VvbGFiL3JnZW9ib3VuZGFyaWVzIikNCnBhY21hbjo6cF9sb2FkKHRpZHl2ZXJzZSwgZ2dzcGF0aWFsLCBsZWFmbGV0LCANCiAgICAgICAgICAgICAgIHJhc3Rlciwgc3RhcnMsIGhlcmUsIHByZXR0eW1hcHIpDQpgYGANCg0KYGBge3J9DQojIPCfkYkgc2Vjb25kLCBnZXQgZGF0YToNCg0KIyBjb3VudHJ5IGJvdW5kYXJpZXMNCmdhbWJpYV9ib3VuZGFyaWVzIDwtIGdlb2JvdW5kYXJpZXMoY291bnRyeSA9ICJHYW1iaWEiLCBhZG1fbHZsID0gMSkNCiMgbWFsYXJpYSBwcmV2YWxlbmNlDQpnYW1iaWFfcHJldmFsZW5jZSA8LSByZWFkX3JkcyhoZXJlKCJkYXRhIiwgImdhbWJpYV9wcmV2YWxlbmNlLnJkcyIpKQ0KYGBgDQoNCmBgYHtyfQ0KIyDwn5GJIHRoaXJkLCBwbG90IGRhdGE6DQoNCmdncGxvdCgpICsNCiAgIyB3aXRoIGEgYmFja2dyb3VuZA0KICBhbm5vdGF0aW9uX21hcF90aWxlKGRhdGEgPSBnYW1iaWFfYm91bmRhcmllcywgem9vbWluID0gMCkgKw0KICAjIHBsdXMgYSBwcmV2YWxlbmNlIHN1cmZhY2UNCiAgZ2VvbV9zdGFycyhkYXRhID0gc3RfYXNfc3RhcnMoZ2FtYmlhX3ByZXZhbGVuY2UpKSArDQogICMgd2l0aCBhIGNvbG9yIHNjYWxlDQogIHNjYWxlX2ZpbGxfdmlyaWRpc19jKG5hLnZhbHVlID0gInRyYW5zcGFyZW50IiwgYWxwaGEgPSAwLjc1KSArDQogICMgYW5kIGEgY29vcmRpbmF0ZSBzeXN0ZW0NCiAgY29vcmRfc2YoKQ0KYGBgDQoNCuKAoiBIZXJlLCBza2lsbHMgZm9yICoqZ2Vvc3BhdGlhbCB2aXN1YWxpemF0aW9uKiosDQoNCuKAoiBUbyBtYWtlICphY2N1cmF0ZSosICplbGVnYW50KiBhbmQgKmluZm9ybWF0aXZlKiBtYXBzLg0KDQojIyBSIGFzIGEgR0lTDQoNCuKAoiBHZW9zcGF0aWFsIGFuYWx5c2lzIG5lZWRzIGEgKipnZW9ncmFwaGljIGluZm9ybWF0aW9uIHN5c3RlbSAoR0lTKSoqLg0KDQrigKIgKk1hbmFnZSosICphbmFseXplKiwgYW5kICp2aXN1YWxpemUqIHNwYXRpYWwgZGF0YS4NCg0K4oCiIFBvcHVsYXIgcGxhdGZvcm1zLCAqKkFyY0dJUyoqIGFuZCAqKlFHSVMqKiwgYXJlICpncmFwaGljLXVzZXItaW50ZXJmYWNlIChHVUkpKi4NCg0K4oCiIFNvICoqd2h5IHVzZSBSIGZvciBnZW9zcGF0aWFsIHdvcms/KioNCg0K4oCiIEhlcmUgZml2ZSBvZiBpdHMgbWVyaXRzOg0KDQojIyMgKDEvNSkgUmVwcm9kdWNpYmlsaXR5Og0KDQrigKIgQ29kZSBpcyBzdHJhaWdodGZvcndhcmQgZm9yIGFueW9uZSB0byByZS1ydW4sDQoNCuKAoiBFYXNpbHkgYnVpbGQgb24gb3RoZXIgcGVvcGxlJ3Mgd29yaw0KDQrigKIgRmFjaWxpdGF0ZXMgY29sbGFib3JhdGlvbg0KDQrigKIgUGFzdGUgdGhpcyBjb2RlIGFuZCByZXByb2R1Y2UgaW4geW91ciBjb21wdXRlcjoNCg0KYGBge3IsbWVzc2FnZT1GQUxTRX0NCiMg8J+RiSBwYWNrYWdlcw0KaWYoIXJlcXVpcmUoJ3BhY21hbicpKSBpbnN0YWxsLnBhY2thZ2VzKCdwYWNtYW4nKQ0KcGFjbWFuOjpwX2xvYWQoc2YsIGdncGxvdDIpDQoNCiMg8J+RiSBkYXRhIA0KbmMgPC0gc3RfcmVhZChzeXN0ZW0uZmlsZSgic2hhcGUvbmMuc2hwIiwgcGFja2FnZSA9ICJzZiIpLA0KICAgICAgICAgICAgICBxdWlldCA9IFRSVUUpDQojIPCfkYkgcGxvdA0KZ2dwbG90KGRhdGEgPSBuYykgKyANCiAgZ2VvbV9zZihhZXMoZmlsbCA9IFNJRDc0KSkgKw0KICBzY2FsZV9maWxsX3ZpcmlkaXNfYygpDQpgYGANCg0KIyMjICgyLzUpUmVwb3J0aW5nOg0KDQrigKIgYHtSbWFya2Rvd259YCwgYHtmbGV4ZGFzaGJvYXJkfWAgYW5kIGB7c2hpbnl9YCB0byBnZW5lcmF0ZSByZXBvcnRzIGFuZCAqZGFzaGJvYXJkcyouDQoNCuKAoiAqSW50ZXJhY3RpdmUqIG1hcHMgd2l0aCBge2xlYWZsZXR9YCBpbnN0ZWFkIG9mIGB7Z2dwbG90Mn1gOg0KDQpgYGB7cixtZXNzYWdlPUZBTFNFfQ0KIyDwn5GJIHBhY2thZ2VzDQppZighcmVxdWlyZSgncGFjbWFuJykpIGluc3RhbGwucGFja2FnZXMoJ3BhY21hbicpDQpwYWNtYW46OnBfbG9hZChzZiwgbGVhZmxldCkNCg0KIyDwn5GJIGRhdGENCm5jIDwtIHN0X3JlYWQoc3lzdGVtLmZpbGUoInNoYXBlL25jLnNocCIsIHBhY2thZ2UgPSAic2YiKSwNCiAgICAgICAgICAgICAgcXVpZXQgPSBUUlVFKQ0KDQojIPCfkYkgcGxvdA0KcGFsIDwtIGNvbG9yTnVtZXJpYygiWWxPclJkIiwgZG9tYWluID0gbmMkU0lENzQpDQpsZWFmbGV0KG5jKSAlPiUNCiAgYWRkVGlsZXMoKSAlPiUNCiAgYWRkUG9seWdvbnMoY29sb3IgPSAid2hpdGUiLCBmaWxsQ29sb3IgPSB+IHBhbChTSUQ3NCksDQogICAgICAgICAgICAgIGZpbGxPcGFjaXR5ID0gMSkgJT4lDQogIGFkZExlZ2VuZChwYWwgPSBwYWwsIHZhbHVlcyA9IH5TSUQ3NCwgb3BhY2l0eSA9IDEpDQpgYGANCg0KIyMjICgzLzUpIFJpY2ggZWNvc3lzdGVtOg0KDQrigKIgUiB3aXRoIHJhcGlkbHkgKmdyb3dpbmcgbGlicmFyaWVzKg0KDQrigKIgaGlnaGx5LWFjdGl2ZSBvcGVuLXNvdXJjZSBjb21tdW5pdHksDQoNCuKAoiByZWFkeS10by11c2UgcGFja2FnZXMgb3IgdHV0b3JpYWxzLg0KDQrigKIgKmludGVyYWN0aXZlKiBtYXAgd2l0aCBvbmUgbGluZSBvZiBjb2RlIQ0KDQrigKIgYHttYXB2aWV3fWAgaW5zdGVhZCBvZiBge2xlYWZsZXR9YDoNCg0KYGBge3IsbWVzc2FnZT1GQUxTRX0NCiMg8J+RiSBwYWNrYWdlcw0KaWYoIXJlcXVpcmUoJ3BhY21hbicpKSBpbnN0YWxsLnBhY2thZ2VzKCdwYWNtYW4nKQ0KcGFjbWFuOjpwX2xvYWQoc2YsIG1hcHZpZXcpDQoNCiMg8J+RiSBkYXRhDQpuYyA8LSBzdF9yZWFkKHN5c3RlbS5maWxlKCJzaGFwZS9uYy5zaHAiLCBwYWNrYWdlID0gInNmIiksDQogICAgICAgICAgICAgIHF1aWV0ID0gVFJVRSkNCg0KIyDwn5GJIHBsb3QNCm1hcHZpZXcobmMsIHpjb2wgPSAiU0lENzQiKQ0KYGBgDQoNCiMjIyAoNC81KSBDb252ZW5pZW5jZToNCg0K4oCiIFlvdSBhbHJlYWR5IGtub3cgUiENCg0K4oCiIEV4cGxvcmUgbmV3IHBpZWNlcyBvZiBjb2RlLg0KDQo6OjogcnN0dWRpby1jbG91ZA0KDQpBcyBhbiBleGFtcGxlLCB3ZSB3aWxsIHVzZSB0aGUgYHt0bWFwfWAgcGFja2FnZSBhbmQgbWFrZSBtaW5vciBtb2RpZmljYXRpb25zIHRvIGl0IQ0KDQpGaXJzdCwgcnVuIHRoaXMgY2h1bms6DQoNCmBgYHtyLHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRX0NCiMg8J+RiSBwYWNrYWdlcw0KaWYoIXJlcXVpcmUoJ3BhY21hbicpKSBpbnN0YWxsLnBhY2thZ2VzKCdwYWNtYW4nKQ0KcGFjbWFuOjpwX2xvYWQodG1hcCwgc3BEYXRhKQ0KDQojIPCfkYkgZGF0YQ0KbG9hZChoZXJlKCJkYXRhL256X2VsZXYucmRhIikpDQoNCiMg8J+RiSBwbG90DQp0bV9zaGFwZShuel9lbGV2KSAgKw0KICB0bV9yYXN0ZXIodGl0bGUgPSAiRWxldmF0aW9uIChtKSIsICAjIEFkZCB1bml0cyB0byB0aGUgbGVnZW5kIHRpdGxlDQogICAgICAgICAgICBzdHlsZSA9ICJjb250IiwNCiAgICAgICAgICAgIHBhbGV0dGUgPSAiLUJ1R24iKSArDQogIHRtX3NoYXBlKG56KSArDQogIHRtX2JvcmRlcnMoY29sID0gImJsYWNrIiwgDQogICAgICAgICAgICAgbHdkID0gMSkgKyAjIFJlZHVjZSBsaW5lIHdpZHRoDQogIHRtX3NjYWxlX2JhcihicmVha3MgPSBjKDAsIDEwMCwgMjAwKSwNCiAgICAgICAgICAgICAgIHRleHQuc2l6ZSA9IDEpICsNCiAgdG1fY29tcGFzcyhwb3NpdGlvbiA9IGMoIlJJR0hUIiwgInRvcCIpLA0KICAgICAgICAgICAgIHR5cGUgPSAicm9zZSIsIA0KICAgICAgICAgICAgIHNpemUgPSAyKSArDQogIHRtX2NyZWRpdHModGV4dCA9ICJPIEEgTGF3YWwsIDIwMjQiKSArDQogIHRtX2xheW91dChtYWluLnRpdGxlID0gIk5ldyBaZWFsYW5kIiwNCiAgICAgICAgICAgIGJnLmNvbG9yID0gImxpZ2h0Z3JlZW4iLCAgIyBDaGFuZ2UgYmFja2dyb3VuZCBjb2xvcg0KICAgICAgICAgICAgaW5uZXIubWFyZ2lucyA9IGMoMCwgMCwgMCwgMCksICBsZWdlbmQudGl0bGUuc2l6ZSA9IDEuNSkgIyBBZGp1c3QgbGVnZW5kIHRpdGxlIHNpemUNCmBgYA0KDQpOb3csIGFwcGx5IGFueSBvZiB0aGUgZm9sbG93aW5nIHN1Z2dlc3Rpb25zIHRvIGdldCB1c2VkIHRvIGhvdyB0aGlzIHBhY2thZ2Ugd29ya3M6DQoNCjEuICBDaGFuZ2UgdGhlICoqbWFwIHRpdGxlKiogZnJvbSAiTXkgbWFwIiB0byAiTmV3IFplYWxhbmQiLg0KMi4gIFVwZGF0ZSB0aGUgKiptYXAgY3JlZGl0cyoqIHdpdGggeW91ciBvd24gbmFtZSBhbmQgdG9kYXkncyBkYXRlLg0KMy4gIENoYW5nZSB0aGUgKipjb2xvciBwYWxldHRlKiogdG8gIkJ1R24iLg0KNC4gIFRyeSAqKm90aGVyIHBhbGV0dGVzKiogZnJvbSA8aHR0cDovL2NvbG9yYnJld2VyMi5vcmcvPg0KNS4gIFB1dCB0aGUgKipub3J0aCBhcnJvdyoqIGluIHRoZSB0b3AgcmlnaHQgY29ybmVyIG9mIHRoZSBtYXAuDQo2LiAgSW1wcm92ZSB0aGUgKipsZWdlbmQgdGl0bGUqKiBieSBhZGRpbmcgdGhlIGxlZ2VuZCB1bml0cy4NCjcuICBJbmNyZWFzZSB0aGUgbnVtYmVyIG9mIGJyZWFrcyBpbiB0aGUgKipzY2FsZSBiYXIqKi4NCjguICBDaGFuZ2UgdGhlICoqYm9yZGVycycgY29sb3IqKiBvZiB0aGUgTmV3IFplYWxhbmQncyByZWdpb25zIHRvIGJsYWNrLg0KOS4gIERlY3JlYXNlIHRoZSBsaW5lIHdpZHRoLg0KMTAuIENoYW5nZSB0aGUgKipiYWNrZ3JvdW5kIGNvbG9yKiogdG8gYW55IGNvbG9yIG9mIHlvdXIgY2hvaWNlLg0KOjo6DQoNCiMjIyAoNS81KSBJbnRlZ3JhdGVkIHdvcmtmbG93Og0KDQrigKIgQ29tYmluZSBnZW9zcGF0aWFsIHZpc3VhbGl6YXRpb24gYW5kIHN0YXRpc3RpY2FsIGFuYWx5c2VzLA0KDQrigKIgYWxsIHdpdGhpbiBhIHNpbmdsZSBzY3JpcHQuDQoNCuKAoiBGb3IgZXhhbXBsZSwgYnVpbHQgM0QgbWFwcyBvZiB0aGUgTW9udGVyZXkgQmF5IHVzaW5nIGB7cmF5c2hhZGVyfWANCg0K4oCiIFR1dG9yaWFsIGF2YWlsYWJsZTogPGh0dHBzOi8vd3d3LnR5bGVybXcuY29tLzNkLW1hcHMtd2l0aC1yYXlzaGFkZXIvPg0KDQohW10oaW1hZ2VzL21vbnRiYXlhYm92ZS5naWYpDQoNCuKAoiBCaXZhcmlhdGUgbWFwcyBvZiB1bmVxdWFsIGRpc3RyaWJ1dGlvbiBvZiB0aGUgaW5jb21lLg0KDQrigKIgVHV0b3JpYWwgYXZhaWxhYmxlOiA8aHR0cHM6Ly90aW1vZ3Jvc3NlbmJhY2hlci5jaC8yMDE5LzA0L2JpdmFyaWF0ZS1tYXBzLXdpdGgtZ2dwbG90Mi1hbmQtc2YvPg0KDQohW10oaW1hZ2VzL2JpdmFyaWF0ZS1tYXAtc3cucG5nKXt3aWR0aD0iNDk5In0NCg0KYGBge3J9DQoNCmBgYA0KDQojIyBXcmFwIHVwDQoNCuKAoiBXZSBsZWFybmVkIHdoeSB0byB1c2UgUiBhcyBhIEdJUyBzb2Z0d2FyZSwNCg0K4oCiIHRha2UgYWR2YW50YWdlIG9mIGl0cyBjb2RpbmcgZW52aXJvbm1lbnQuDQoNCuKAoiBCdXQsIHdoaWNoIG1hcHMgYXJlIHdlIGdvaW5nIHRvIGJ1aWx0Pw0KDQohW0ZpZ3VyZSAxLiBUaGVtYXRpYyBtYXBzOiAoQSkgQ2hvcm9wbGV0aCBtYXAsIChCKSBEb3QgbWFwLCAoQykgRGVuc2l0eSBtYXAsIGFuZCAoRCkgQmFzZW1hcCBmb3IgYSBkb3QgbWFwLl0oaW1hZ2VzL2ludHJvX3RoZW1hdGljX21hcF8wNi5wbmcpe3dpZHRoPSI0ODQifQ0KDQrigKIgSG93IHRvIGJ1aWx0IC1zdGVwIGJ5IHN0ZXAtIGRpZmZlcmVudCB0eXBlcyBvZiAqKlRoZW1hdGljIG1hcHMqKiB1c2luZyB0aGUgYHtnZ3Bsb3QyfWAgcGFja2FnZSwNCg0K4oCiIGRpZmZlcmVudCBkYXRhIHNvdXJjZXMgYW5kIGlsbHVzdHJhdGl2ZSBhbm5vdGF0aW9ucy4NCg0KIVtGaWd1cmUgMi4ge2dncGxvdDJ9IG1hcCB3aXRoIHRleHQgYW5ub3RhdGlvbnMsIGEgc2NhbGUgYmFyIGFuZCBub3J0aCBhcnJvdy5dKGltYWdlcy9tdWx0aWxheWVyX21hcF8wMS5wbmcpe3dpZHRoPSI0MDkifQ0KDQojIyBDb250cmlidXRvcnMgey51bmxpc3RlZCAudW5udW1iZXJlZH0NCg0KVGhlIGZvbGxvd2luZyB0ZWFtIG1lbWJlcnMgY29udHJpYnV0ZWQgdG8gdGhpcyBsZXNzb246DQoNCmByIHRnY19jb250cmlidXRvcnNfbGlzdChpZHMgPSBjKCJhdmFsbGVjYW0iLCAia2VuZGF2aWRuIikpYA0KDQojIyBSZWZlcmVuY2VzIHsudW5saXN0ZWQgLnVubnVtYmVyZWR9DQoNClNvbWUgbWF0ZXJpYWwgaW4gdGhpcyBsZXNzb24gd2FzIGFkYXB0ZWQgZnJvbSB0aGUgZm9sbG93aW5nIHNvdXJjZXM6DQoNCi0gICAqQmF0cmEsIE5lYWxlLCBldCBhbC4gKDIwMjEpLiBUaGUgRXBpZGVtaW9sb2dpc3QgUiBIYW5kYm9vay4gQ2hhcHRlciAyODogR0lTIEJhc2ljcyouICgyMDIxKS4gUmV0cmlldmVkIDAxIEFwcmlsIDIwMjIsIGZyb20gPGh0dHBzOi8vZXBpcmhhbmRib29rLmNvbS9lbi9naXMtYmFzaWNzLmh0bWw+DQoNCi0gICAqQmF1bWVyLCBCZW5qYW1pbiBTLiwgS2FwbGFuLCBEYW5pZWwgVC4sIGFuZCBIb3J0b24sIE5pY2hvbGFzIEouIE1vZGVybiBEYXRhIFNjaWVuY2Ugd2l0aCBSLiBDaGFwdGVyIDE3OiBXb3JraW5nIHdpdGggZ2Vvc3BhdGlhbCBkYXRhKi4gKDIwMjEpLiBSZXRyaWV2ZWQgMDUgSnVuZSAyMDIyLCBmcm9tIDxodHRwczovL21kc3ItYm9vay5naXRodWIuaW8vbWRzcjJlL2NoLXNwYXRpYWwuaHRtbD4NCg0KLSAgICpMb3ZlbGFjZSwgUi4sIE5vd29zYWQsIEouLCAmIE11ZW5jaG93LCBKLiBHZW9jb21wdXRhdGlvbiB3aXRoIFIuIENoYXB0ZXIgMjogR2VvZ3JhcGhpYyBkYXRhIGluIFIuKiAoMjAxOSkuIFJldHJpZXZlZCAwMSBBcHJpbCAyMDIyLCBmcm9tIDxodHRwczovL2dlb2NvbXByLnJvYmlubG92ZWxhY2UubmV0L3NwYXRpYWwtY2xhc3MuaHRtbD4NCg0KLSAgICpNb3JhZ2EsIFBhdWxhLiBHZW9zcGF0aWFsIEhlYWx0aCBEYXRhOiBNb2RlbGluZyBhbmQgVmlzdWFsaXphdGlvbiB3aXRoIFItSU5MQSBhbmQgU2hpbnkuIENoYXB0ZXIgMTI6IEJ1aWxkaW5nIGEgZGFzaGJvYXJkIHRvIHZpc3VhbGl6ZSBzcGF0aWFsIGRhdGEgd2l0aCBmbGV4ZGFzaGJvYXJkKi4gKDIwMTkpLiBSZXRyaWV2ZWQgMTMgU2VwdGVtYmVyIDIwMjIsIGZyb20gPGh0dHBzOi8vd3d3LnBhdWxhbW9yYWdhLmNvbS9ib29rLWdlb3NwYXRpYWwvc2VjLWZsZXhkYXNoYm9hcmQuaHRtbD4NCg0KLSAgICpNb3Jlbm8sIE0uLCBhbmQgQmFzdGlsbGUsIE0uIERyYXdpbmcgYmVhdXRpZnVsIG1hcHMgcHJvZ3JhbW1hdGljYWxseSB3aXRoIFIsIHNmIGFuZCBnZ3Bsb3QyIC0tLSBQYXJ0IDE6IEJhc2ljcy4qICgyMDE4KS4gUmV0cmlldmVkIDEzIFNlcHRlbWJlciAyMDIyLCBmcm9tIDxodHRwczovL3Itc3BhdGlhbC5vcmcvci8yMDE4LzEwLzI1L2dncGxvdDItc2YuaHRtbC4+DQoNCi0gICAqTm93b3NhZCwgSi4gQmFzaWNzIG9mIFNwYXRpYWwgRGF0YSBBbmFseXNpcyBXb3Jrc2hvcC4qICgyMDE5KS4gUmV0cmlldmVkIDEzIFNlcHRlbWJlciAyMDIyLCBmcm9tIDxodHRwczovL2dpdGh1Yi5jb20vTm93b3NhZC93aHlyXzE5dy9ibG9iL21hc3Rlci9jb2RlL3NwYXRpYWxfdmlzLlI+DQoNCi0gICAqTm93b3NhZCwgSi4gVGhlIExhbmRzY2FwZSBvZiBTcGF0aWFsIERhdGEgQW5hbHlzaXMgaW4gUi4qICgyMDE5KS4gUmV0cmlldmVkIDEzIFNlcHRlbWJlciAyMDIyLCBmcm9tIDxodHRwczovL2pha3Vibm93b3NhZC5jb20vd2h5cl8xOS8jMT4NCg0KYHIgdGdjX2xpY2Vuc2UoKWANCg==