Disclaimer
This tutorial is converted from my 2025 30 Day Map Challenge Day 3
Polygon. All code is written by myself, but converted to R Markdown with
Gemini 3 assistance.
Here is the screenshot of my chat with Gemini 3 for this conversion:

Introduction
In this tutorial, we will create a choropleth map—a thematic map
where areas are shaded in proportion to a statistical variable.
Specifically, we will map Population Density in Philadelphia using data
from the US Census Bureau.
We will cover:
- Acquiring spatial data using
tidycensus.
- Projecting coordinate systems for accurate area calculations.
- Calculating population density.
- Incorporating external geographic layers (water bodies).
- Designing an aesthetic map using
ggplot2 and custom
color scales.
Prequisites
You will need the following R packages. If you don’t have them,
install them using install.packages().
library(tidyverse) # For data manipulation and visualization
library(tidycensus) # For accessing US Census data
library(sf) # For spatial data handling
library(scales) # For formatting numbers (commas, percentages)
library(units) # For handling measurement units (km^2)
API Key Setup
To use tidycensus, you need an API key from the US Census Bureau. You
can sign up for one here.
Once you have your key, load it into your environment (uncomment the
line below and replace with your key):
# census_api_key("YOUR_CENSUS_API_KEY_HERE", install = TRUE)
Step 1: Acquiring Census Data
We use the get_acs() function to fetch American
Community Survey (ACS) data. We are requesting the Total Population
(variable B01003_001) for Census Tracts in Philadelphia,
PA.
census_data <- get_acs(
geography = "tract",
variables = c(population = "B01003_001"), # Renaming variable to 'population'
state = "PA",
county = "Philadelphia",
geometry = TRUE, # Downloads the shapefiles along with data
year = 2023,
progress= FALSE
)
Step 3: Data Binning (Quantiles)
To make the map easier to read, we often group continuous data into
“bins.” Here, we use ntile() to split the tracts into 5
equal groups (quintiles) based on density.
census_data <- census_data %>%
mutate(
pop_density_bin = ntile(pop_density, 5)
)
Step 4: Adding Context (Water Layer)
A map of Philadelphia looks incomplete without the Delaware and
Schuylkill rivers. We can fetch water polygon data from an open data
source (ArcGIS Hub) via a GeoJSON URL.
Crucial Step: We must transform the water layer to
EPSG:2272 to match our census data, and then clip it
(st_intersection) so we only show water that is actually
inside Philadelphia.
# 1. Read GeoJSON data directly from URL
water_url <- "https://hub.arcgis.com/api/v3/datasets/2b10034796f34c81a0eb44c676d86729_1/downloads/data?format=geojson&spatialRefId=4326&where=1%3D1"
water <- st_read(water_url, quiet = TRUE)
# 2. Transform to match our census data projection
water <- st_transform(water, crs = 2272)
# 3. Clip water to the boundary of our census data
# st_union(census_data) creates one big outline of Philadelphia to clip against
water_phila <- st_intersection(water, st_union(census_data))
Step 5: Visualization
Creating Custom Labels
Instead of showing “1, 2, 3, 4, 5” in the legend, we want to show the
actual population ranges (e.g., “10,000 – 20,000”).
# Calculate the break points for the 5 bins
qs <- quantile(census_data$pop_density, probs = seq(0, 1, by = 0.2), na.rm = TRUE)
# Create label strings with commas
labs <- paste0(comma(round(qs[-length(qs)])), " – ", comma(round(qs[-1])))
# Assign these labels to the numbers 1 through 5
labs_named <- setNames(labs, as.character(1:5))
The Final Plot
We use ggplot2 with geom_sf. Note the use
of factor(pop_density_bin) to treat the bins as discrete
categories rather than a continuous gradient.
ggplot(data = census_data) +
# Layer 1: Census Tracts
geom_sf(aes(fill = factor(pop_density_bin)), color = NA) +
# Layer 2: Custom Colors and Legend
scale_fill_manual(
values = c(
"1" = "#ffccd5", # Lightest
"2" = "#ffb3c1",
"3" = "#ff758f",
"4" = "#c9184a",
"5" = "#800f2f" # Darkest
),
breaks = c("1","2","3","4","5"),
labels = labs_named,
drop = FALSE,
name = "People per km²"
) +
# Layer 3: Water Overlay
geom_sf(data = water_phila, fill = "#3f88c5", color = NA, alpha = 0.5) +
# Layer 4: Text and Theme
labs(
title = "Population Density by Census Tract in Philadelphia",
subtitle = "Data Source: 2023 ACS 5-Year Estimates",
caption = "Visualization Tutorial based on tidycensus"
) +
theme_void() +
theme(
plot.title = element_text(size = 18, face = "bold", margin = margin(b=10)),
plot.subtitle = element_text(size = 12, color = "grey40", margin = margin(b=20)),
plot.caption = element_text(size = 8, hjust = 0, color = "grey60"),
legend.position = "right",
legend.title = element_text(face = "bold")
)

LS0tCnRpdGxlOiAiQ3JlYXRpbmcgYSBQb3B1bGF0aW9uIERlbnNpdHkgQ2hvcm9wbGV0aCBNYXAgaW4gUiIKYXV0aG9yOiAiWmhhbmNoYW8gWWFuZyIKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIHRoZW1lOiBmbGF0bHkKICAgIGhpZ2hsaWdodDogdGFuZ28KICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgIGNvZGVfZG93bmxvYWQ6IHllcwogICAgbWF0aGpheDogZGVmYXVsdAotLS0KCiMjIERpc2NsYWltZXIKVGhpcyB0dXRvcmlhbCBpcyBjb252ZXJ0ZWQgZnJvbSBteSAyMDI1IDMwIERheSBNYXAgQ2hhbGxlbmdlIERheSAzIFBvbHlnb24uIEFsbCBjb2RlIGlzIHdyaXR0ZW4gYnkgbXlzZWxmLCBidXQgY29udmVydGVkIHRvIFIgTWFya2Rvd24gd2l0aCBHZW1pbmkgMyBhc3Npc3RhbmNlLgoKSGVyZSBpcyB0aGUgc2NyZWVuc2hvdCBvZiBteSBjaGF0IHdpdGggR2VtaW5pIDMgZm9yIHRoaXMgY29udmVyc2lvbjoKIVtHZW1pbmkgMyBDaGF0IFNjcmVlbnNob3RdKC9Vc2Vycy96aGFuY2hhb3lhbmcvRGVza3RvcC9jaGF0LnBuZykKCiMgSW50cm9kdWN0aW9uCgpJbiB0aGlzIHR1dG9yaWFsLCB3ZSB3aWxsIGNyZWF0ZSBhIGNob3JvcGxldGggbWFw4oCUYSB0aGVtYXRpYyBtYXAgd2hlcmUgYXJlYXMgYXJlIHNoYWRlZCBpbiBwcm9wb3J0aW9uIHRvIGEgc3RhdGlzdGljYWwgdmFyaWFibGUuIFNwZWNpZmljYWxseSwgd2Ugd2lsbCBtYXAgUG9wdWxhdGlvbiBEZW5zaXR5IGluIFBoaWxhZGVscGhpYSB1c2luZyBkYXRhIGZyb20gdGhlIFVTIENlbnN1cyBCdXJlYXUuCgpXZSB3aWxsIGNvdmVyOgoKMS4gQWNxdWlyaW5nIHNwYXRpYWwgZGF0YSB1c2luZyBgdGlkeWNlbnN1c2AuCjIuIFByb2plY3RpbmcgY29vcmRpbmF0ZSBzeXN0ZW1zIGZvciBhY2N1cmF0ZSBhcmVhIGNhbGN1bGF0aW9ucy4KMy4gQ2FsY3VsYXRpbmcgcG9wdWxhdGlvbiBkZW5zaXR5Lgo0LiBJbmNvcnBvcmF0aW5nIGV4dGVybmFsIGdlb2dyYXBoaWMgbGF5ZXJzICh3YXRlciBib2RpZXMpLgo1LiBEZXNpZ25pbmcgYW4gYWVzdGhldGljIG1hcCB1c2luZyBgZ2dwbG90MmAgYW5kIGN1c3RvbSBjb2xvciBzY2FsZXMuCgojIFByZXF1aXNpdGVzCgpZb3Ugd2lsbCBuZWVkIHRoZSBmb2xsb3dpbmcgUiBwYWNrYWdlcy4gSWYgeW91IGRvbid0IGhhdmUgdGhlbSwgaW5zdGFsbCB0aGVtIHVzaW5nIGBpbnN0YWxsLnBhY2thZ2VzKClgLgoKYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmxpYnJhcnkodGlkeXZlcnNlKSAgIyBGb3IgZGF0YSBtYW5pcHVsYXRpb24gYW5kIHZpc3VhbGl6YXRpb24KbGlicmFyeSh0aWR5Y2Vuc3VzKSAjIEZvciBhY2Nlc3NpbmcgVVMgQ2Vuc3VzIGRhdGEKbGlicmFyeShzZikgICAgICAgICAjIEZvciBzcGF0aWFsIGRhdGEgaGFuZGxpbmcKbGlicmFyeShzY2FsZXMpICAgICAjIEZvciBmb3JtYXR0aW5nIG51bWJlcnMgKGNvbW1hcywgcGVyY2VudGFnZXMpCmxpYnJhcnkodW5pdHMpICAgICAgIyBGb3IgaGFuZGxpbmcgbWVhc3VyZW1lbnQgdW5pdHMgKGttXjIpCmBgYAoKIyMgQVBJIEtleSBTZXR1cAoKVG8gdXNlIHRpZHljZW5zdXMsIHlvdSBuZWVkIGFuIEFQSSBrZXkgZnJvbSB0aGUgVVMgQ2Vuc3VzIEJ1cmVhdS4gWW91IGNhbiBzaWduIHVwIGZvciBvbmUgW2hlcmVdKGh0dHBzOi8vYXBpLmNlbnN1cy5nb3YvZGF0YS9rZXlfc2lnbnVwLmh0bWwpLgoKT25jZSB5b3UgaGF2ZSB5b3VyIGtleSwgbG9hZCBpdCBpbnRvIHlvdXIgZW52aXJvbm1lbnQgKHVuY29tbWVudCB0aGUgbGluZSBiZWxvdyBhbmQgcmVwbGFjZSB3aXRoIHlvdXIga2V5KToKYGBge3J9CiMgY2Vuc3VzX2FwaV9rZXkoIllPVVJfQ0VOU1VTX0FQSV9LRVlfSEVSRSIsIGluc3RhbGwgPSBUUlVFKQpgYGAKCiMgU3RlcCAxOiBBY3F1aXJpbmcgQ2Vuc3VzIERhdGEKV2UgdXNlIHRoZSBgZ2V0X2FjcygpYCBmdW5jdGlvbiB0byBmZXRjaCBBbWVyaWNhbiBDb21tdW5pdHkgU3VydmV5IChBQ1MpIGRhdGEuIFdlIGFyZSByZXF1ZXN0aW5nIHRoZSBUb3RhbCBQb3B1bGF0aW9uICh2YXJpYWJsZSBgQjAxMDAzXzAwMWApIGZvciBDZW5zdXMgVHJhY3RzIGluIFBoaWxhZGVscGhpYSwgUEEuCgpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KY2Vuc3VzX2RhdGEgPC0gZ2V0X2FjcygKICBnZW9ncmFwaHkgPSAidHJhY3QiLAogIHZhcmlhYmxlcyA9IGMocG9wdWxhdGlvbiA9ICJCMDEwMDNfMDAxIiksICMgUmVuYW1pbmcgdmFyaWFibGUgdG8gJ3BvcHVsYXRpb24nCiAgc3RhdGUgPSAiUEEiLAogIGNvdW50eSA9ICJQaGlsYWRlbHBoaWEiLAogIGdlb21ldHJ5ID0gVFJVRSwgIyBEb3dubG9hZHMgdGhlIHNoYXBlZmlsZXMgYWxvbmcgd2l0aCBkYXRhCiAgeWVhciA9IDIwMjMsCiAgcHJvZ3Jlc3M9IEZBTFNFCikKCmBgYAoKIyBTdGVwIDI6IFNwYXRpYWwgVHJhbnNmb3JtYXRpb24gJiBEZW5zaXR5IENhbGN1bGF0aW9uCgojIyBQcm9qZWN0aW5nIHRoZSBEYXRhCgpDZW5zdXMgZGF0YSB1c3VhbGx5IGNvbWVzIGluIHRoZSBXR1M4NCBjb29yZGluYXRlIHN5c3RlbSAobGF0L2xvbmcpLiBUbyBjYWxjdWxhdGUgYXJlYSBhY2N1cmF0ZWx5LCB3ZSBzaG91bGQgcHJvamVjdCBpdCB0byBhIGNvb3JkaW5hdGUgc3lzdGVtIGRlc2lnbmVkIGZvciB0aGUgc3BlY2lmaWMgcmVnaW9uLiBGb3IgUGhpbGFkZWxwaGlhLCAqKkVQU0c6MjI3MiAoTkFEODMgLyBQZW5uc3lsdmFuaWEgU291dGgpKiogaXMgdGhlIHN0YW5kYXJkLgpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyBUcmFuc2Zvcm0gdG8gcHJvamVjdGVkIENSUyAoRVBTRzoyMjcyKQpjZW5zdXNfZGF0YSA8LSBzdF90cmFuc2Zvcm0oY2Vuc3VzX2RhdGEsIGNycyA9IDIyNzIpCmBgYAoKIyMgQ2FsY3VsYXRpbmcgUG9wdWxhdGlvbiBEZW5zaXR5CgpOb3cgdGhhdCBvdXIgbWFwIGlzIHByb2plY3RlZCwgd2UgY2FuIGNhbGN1bGF0ZSB0aGUgYXJlYSBvZiBlYWNoIHRyYWN0LgoKMS4gQ2FsY3VsYXRlIGFyZWEgdXNpbmcgc3RfYXJlYSgpLgoyLiBDb252ZXJ0IHRoYXQgYXJlYSB0byBzcXVhcmUga2lsb21ldGVycy4KMy4gRGl2aWRlIHBvcHVsYXRpb24gYnkgYXJlYSB0byBnZXQgZGVuc2l0eS4KYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmNlbnN1c19kYXRhIDwtIGNlbnN1c19kYXRhICU+JQogIG11dGF0ZSgKICAgICMgQ2FsY3VsYXRlIGFyZWEgYW5kIGNvbnZlcnQgdG8ga21eMgogICAgYXJlYV9zcV9rbSA9IHN0X2FyZWEoZ2VvbWV0cnkpICU+JSBzZXRfdW5pdHMoImttXjIiKSwKICAgIAogICAgIyBDYWxjdWxhdGUgZGVuc2l0eQogICAgcG9wX2RlbnNpdHkgPSBlc3RpbWF0ZSAvIGFyZWFfc3Ffa20KICApCgojIFJlbW92ZSB0aGUgJ3VuaXRzJyBjbGFzcyB0byBtYWtlIGl0IGEgcmVndWxhciBudW1lcmljIGNvbHVtbiBmb3IgcGxvdHRpbmcKY2Vuc3VzX2RhdGEkcG9wX2RlbnNpdHkgPC0gZHJvcF91bml0cyhjZW5zdXNfZGF0YSRwb3BfZGVuc2l0eSkKYGBgCgojIFN0ZXAgMzogRGF0YSBCaW5uaW5nIChRdWFudGlsZXMpClRvIG1ha2UgdGhlIG1hcCBlYXNpZXIgdG8gcmVhZCwgd2Ugb2Z0ZW4gZ3JvdXAgY29udGludW91cyBkYXRhIGludG8gImJpbnMuIiBIZXJlLCB3ZSB1c2UgYG50aWxlKClgIHRvIHNwbGl0IHRoZSB0cmFjdHMgaW50byA1IGVxdWFsIGdyb3VwcyAocXVpbnRpbGVzKSBiYXNlZCBvbiBkZW5zaXR5LgpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KY2Vuc3VzX2RhdGEgPC0gY2Vuc3VzX2RhdGEgJT4lCiAgbXV0YXRlKAogICAgcG9wX2RlbnNpdHlfYmluID0gbnRpbGUocG9wX2RlbnNpdHksIDUpCiAgKQoKYGBgCgojIFN0ZXAgNDogQWRkaW5nIENvbnRleHQgKFdhdGVyIExheWVyKQoKQSBtYXAgb2YgUGhpbGFkZWxwaGlhIGxvb2tzIGluY29tcGxldGUgd2l0aG91dCB0aGUgRGVsYXdhcmUgYW5kIFNjaHV5bGtpbGwgcml2ZXJzLiBXZSBjYW4gZmV0Y2ggd2F0ZXIgcG9seWdvbiBkYXRhIGZyb20gYW4gb3BlbiBkYXRhIHNvdXJjZSAoQXJjR0lTIEh1YikgdmlhIGEgR2VvSlNPTiBVUkwuCgoqKkNydWNpYWwgU3RlcCoqOiBXZSBtdXN0IHRyYW5zZm9ybSB0aGUgd2F0ZXIgbGF5ZXIgdG8gKipFUFNHOjIyNzIqKiB0byBtYXRjaCBvdXIgY2Vuc3VzIGRhdGEsIGFuZCB0aGVuIGNsaXAgaXQgKGBzdF9pbnRlcnNlY3Rpb25gKSBzbyB3ZSBvbmx5IHNob3cgd2F0ZXIgdGhhdCBpcyBhY3R1YWxseSAqaW5zaWRlKiBQaGlsYWRlbHBoaWEuCgpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyAxLiBSZWFkIEdlb0pTT04gZGF0YSBkaXJlY3RseSBmcm9tIFVSTAp3YXRlcl91cmwgPC0gImh0dHBzOi8vaHViLmFyY2dpcy5jb20vYXBpL3YzL2RhdGFzZXRzLzJiMTAwMzQ3OTZmMzRjODFhMGViNDRjNjc2ZDg2NzI5XzEvZG93bmxvYWRzL2RhdGE/Zm9ybWF0PWdlb2pzb24mc3BhdGlhbFJlZklkPTQzMjYmd2hlcmU9MSUzRDEiCndhdGVyIDwtIHN0X3JlYWQod2F0ZXJfdXJsLCBxdWlldCA9IFRSVUUpCgojIDIuIFRyYW5zZm9ybSB0byBtYXRjaCBvdXIgY2Vuc3VzIGRhdGEgcHJvamVjdGlvbgp3YXRlciA8LSBzdF90cmFuc2Zvcm0od2F0ZXIsIGNycyA9IDIyNzIpCgojIDMuIENsaXAgd2F0ZXIgdG8gdGhlIGJvdW5kYXJ5IG9mIG91ciBjZW5zdXMgZGF0YQojIHN0X3VuaW9uKGNlbnN1c19kYXRhKSBjcmVhdGVzIG9uZSBiaWcgb3V0bGluZSBvZiBQaGlsYWRlbHBoaWEgdG8gY2xpcCBhZ2FpbnN0CndhdGVyX3BoaWxhIDwtIHN0X2ludGVyc2VjdGlvbih3YXRlciwgc3RfdW5pb24oY2Vuc3VzX2RhdGEpKQpgYGAKCiMgU3RlcCA1OiBWaXN1YWxpemF0aW9uCiMjIENyZWF0aW5nIEN1c3RvbSBMYWJlbHMKSW5zdGVhZCBvZiBzaG93aW5nICIxLCAyLCAzLCA0LCA1IiBpbiB0aGUgbGVnZW5kLCB3ZSB3YW50IHRvIHNob3cgdGhlIGFjdHVhbCBwb3B1bGF0aW9uIHJhbmdlcyAoZS5nLiwgIjEwLDAwMCDigJMgMjAsMDAwIikuCgpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyBDYWxjdWxhdGUgdGhlIGJyZWFrIHBvaW50cyBmb3IgdGhlIDUgYmlucwpxcyA8LSBxdWFudGlsZShjZW5zdXNfZGF0YSRwb3BfZGVuc2l0eSwgcHJvYnMgPSBzZXEoMCwgMSwgYnkgPSAwLjIpLCBuYS5ybSA9IFRSVUUpCgojIENyZWF0ZSBsYWJlbCBzdHJpbmdzIHdpdGggY29tbWFzCmxhYnMgPC0gcGFzdGUwKGNvbW1hKHJvdW5kKHFzWy1sZW5ndGgocXMpXSkpLCAiIOKAkyAiLCBjb21tYShyb3VuZChxc1stMV0pKSkKCiMgQXNzaWduIHRoZXNlIGxhYmVscyB0byB0aGUgbnVtYmVycyAxIHRocm91Z2ggNQpsYWJzX25hbWVkIDwtIHNldE5hbWVzKGxhYnMsIGFzLmNoYXJhY3RlcigxOjUpKQpgYGAKCiMjIFRoZSBGaW5hbCBQbG90CldlIHVzZSBgZ2dwbG90MmAgd2l0aCBgZ2VvbV9zZmAuIE5vdGUgdGhlIHVzZSBvZiBgZmFjdG9yKHBvcF9kZW5zaXR5X2JpbilgIHRvIHRyZWF0IHRoZSBiaW5zIGFzIGRpc2NyZXRlIGNhdGVnb3JpZXMgcmF0aGVyIHRoYW4gYSBjb250aW51b3VzIGdyYWRpZW50LgoKYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmdncGxvdChkYXRhID0gY2Vuc3VzX2RhdGEpICsKICAjIExheWVyIDE6IENlbnN1cyBUcmFjdHMKICBnZW9tX3NmKGFlcyhmaWxsID0gZmFjdG9yKHBvcF9kZW5zaXR5X2JpbikpLCBjb2xvciA9IE5BKSArCiAgCiAgIyBMYXllciAyOiBDdXN0b20gQ29sb3JzIGFuZCBMZWdlbmQKICBzY2FsZV9maWxsX21hbnVhbCgKICAgIHZhbHVlcyA9IGMoCiAgICAgICIxIiA9ICIjZmZjY2Q1IiwgIyBMaWdodGVzdAogICAgICAiMiIgPSAiI2ZmYjNjMSIsCiAgICAgICIzIiA9ICIjZmY3NThmIiwKICAgICAgIjQiID0gIiNjOTE4NGEiLAogICAgICAiNSIgPSAiIzgwMGYyZiIgICMgRGFya2VzdAogICAgKSwKICAgIGJyZWFrcyA9IGMoIjEiLCIyIiwiMyIsIjQiLCI1IiksCiAgICBsYWJlbHMgPSBsYWJzX25hbWVkLAogICAgZHJvcCA9IEZBTFNFLAogICAgbmFtZSA9ICJQZW9wbGUgcGVyIGttwrIiCiAgKSArCiAgCiAgIyBMYXllciAzOiBXYXRlciBPdmVybGF5CiAgZ2VvbV9zZihkYXRhID0gd2F0ZXJfcGhpbGEsIGZpbGwgPSAiIzNmODhjNSIsIGNvbG9yID0gTkEsIGFscGhhID0gMC41KSArCiAgCiAgIyBMYXllciA0OiBUZXh0IGFuZCBUaGVtZQogIGxhYnMoCiAgICB0aXRsZSA9ICJQb3B1bGF0aW9uIERlbnNpdHkgYnkgQ2Vuc3VzIFRyYWN0IGluIFBoaWxhZGVscGhpYSIsCiAgICBzdWJ0aXRsZSA9ICJEYXRhIFNvdXJjZTogMjAyMyBBQ1MgNS1ZZWFyIEVzdGltYXRlcyIsCiAgICBjYXB0aW9uID0gIlZpc3VhbGl6YXRpb24gVHV0b3JpYWwgYmFzZWQgb24gdGlkeWNlbnN1cyIKICApICsKICB0aGVtZV92b2lkKCkgKwogIHRoZW1lKAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTgsIGZhY2UgPSAiYm9sZCIsIG1hcmdpbiA9IG1hcmdpbihiPTEwKSksCiAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgY29sb3IgPSAiZ3JleTQwIiwgbWFyZ2luID0gbWFyZ2luKGI9MjApKSwKICAgIHBsb3QuY2FwdGlvbiA9IGVsZW1lbnRfdGV4dChzaXplID0gOCwgaGp1c3QgPSAwLCBjb2xvciA9ICJncmV5NjAiKSwKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIsCiAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIikKICApCmBgYAo=