For noise, I downloaded the noise raster data from NPS (link). The data are based on this study. The data I pulled is the impact level – which is defined as the difference between existing sound levels and natural sound levels (which is why the values were so much lower than you expected).
For urban classification, I used the NLCD classified land cover from MRLC, downloaded using their viewer tool (link) medium- and high-intensity development for the NLCD classified land cover data.
Process raster data
- Read raster files into R
library(tidyverse)
noise_big <-
raster::raster(
'CONUS_sumDay_L50dBA_imp.tiff')
nlcd_big <-
raster::raster(
'NLCD_CNBBEbkS1lK4LBmchsNP/NLCD_2016_Land_Cover_L48_20190424_CNBBEbkS1lK4LBmchsNP.tiff')
nlcd_legend <-
read_csv('NLCD_CNBBEbkS1lK4LBmchsNP/NLCD_landcover_legend_2018_12_17_CNBBEbkS1lK4LBmchsNP.csv') %>%
dplyr::filter(!is.na(Legend))
- Define a regional subset by pulling the inner metro DC counties. Note: I figured counties would be the way to go about this. My first thought was to use all counties in the DMV, but most are pretty rural, so I though we might choose just the inner core counties of the DC metro region. Here’s how they look:
county_names_dmv <-
c("District of Columbia",
"Montgomery",
"Prince George's",
"Alexandria",
"Arlington",
"Fairfax County",
"Fairfax",
"Falls Church")
counties_dmv <-
purrr::map_dfr(
c('Virginia', 'Maryland', 'District of Columbia'),
~ tigris::counties(state = ., cb = TRUE)) %>%
dplyr::filter(NAME %in% county_names_dmv) %>%
sf::st_transform(crs = "+init=epsg:4326") %>%
# Removing a Montgomery County in Virginia:
dplyr::filter(GEOID != 51121) %>%
dplyr::mutate(NAME = factor(NAME))
counties_sp <-
sf::as_Spatial(counties_dmv)
county_pal <-
leaflet::colorFactor(
viridis::viridis(8),
counties_dmv$NAME)
leaflet::leaflet(counties_dmv) %>%
leaflet::addTiles() %>%
leaflet::addPolygons(
color = "#777777",
weight = 1.25,
opacity = 1,
fillOpacity = 0.4,
fillColor = ~county_pal(NAME))
- Crop rasters to the extent of the counties file (to reduce memory load):
noise_cropped <-
noise_big %>%
raster::crop(
counties_dmv %>%
sf::st_transform(projection(noise_big)) %>%
sf::as_Spatial() %>%
raster::extent()) %>%
raster::projectRaster(crs = '+init=epsg:4326') %>%
raster::trim()
nlcd_cropped <-
nlcd_big %>%
raster::crop(
counties_dmv %>%
sf::st_transform(projection(noise_big)) %>%
sf::as_Spatial() %>%
raster::extent()) %>%
raster::projectRaster(crs = '+init=epsg:4326') %>%
raster::trim()
- Mask the rasters to the county file:
noise_masked <-
raster::mask(
noise_cropped,
sf::as_Spatial(counties_dmv))
nlcd_masked <-
raster::mask(
nlcd_cropped,
sf::as_Spatial(counties_dmv))
- Resample the nlcd raster (30m resolution) to match the origin and resolution of noise raster (270m):
nlcd_resampled <-
raster::resample(
x = nlcd_masked,
y = noise_masked,
method = 'ngb')
Here’s what the noise raster looks like:
noise_palette <-
leaflet::colorNumeric(
c("#0000ff", "#ffff00", "#ff0000"),
raster::values(noise_masked),
na.color = "transparent")
leaflet::leaflet(counties_dmv) %>%
leaflet::addTiles() %>%
leaflet::addRasterImage(
noise_resampled,
colors = noise_palette,
opacity = 0.85) %>%
leaflet::addLegend(
pal = noise_palette,
values = raster::values(noise_masked),
title = "Anthropogenic noise") %>%
leaflet::addPolygons(
color = "#777777",
weight = 1.25,
opacity = 1,
fillOpacity = 0)
Binary rasters: Noisy vs. loud
I thought a good way to establish cutoffs for the noise data might be the quartiles of the distribution.
tibble(noise = raster::values(noise_masked)) %>%
na.omit() %>%
ggplot2:::ggplot(aes(x = noise)) +
ggplot2::geom_histogram(fill = "#dcdcdc", color = '#000000', bins = 50) +
ggplot2::theme_bw()

I’m questioning that now:
quiet_cutoff <-
quantile(noise_masked, .25)
loud_cutoff <-
quantile(noise_masked, .75)
quiet_cutoff
25%
10.73598
loud_cutoff
75%
13.83388
tibble(noise = raster::values(noise_masked)) %>%
na.omit() %>%
ggplot2:::ggplot(aes(x = noise)) +
ggplot2::geom_histogram(fill = "#dcdcdc", color = '#000000', bins = 50) +
ggplot2::geom_vline(xintercept = quiet_cutoff, color = '#0000ff') +
ggplot2::geom_vline(xintercept = loud_cutoff, color = '#ff0000') +
ggplot2::theme_bw()

This yields the following areas for quiet sites:
noise_quiet <-
raster::reclassify(
noise_masked,
rcl =
matrix(
c(0, quiet_cutoff, 1, quiet_cutoff, Inf, NA),
byrow = TRUE,
nrow = 2),
include.lowest = TRUE)
quiet_palette <-
leaflet::colorNumeric(
c("#0000ff"),
raster::values(noise_quiet),
na.color = "transparent")
leaflet::leaflet(counties_dmv) %>%
leaflet::addTiles() %>%
leaflet::addRasterImage(
noise_quiet,
colors = quiet_palette,
opacity = 0.5) %>%
leaflet::addPolygons(
color = "#777777",
weight = 1.25,
opacity = 1,
fillOpacity = 0)
And these areas for loud sites:
noise_loud <-
raster::reclassify(
noise_masked,
rcl =
matrix(
c(0, loud_cutoff, NA, loud_cutoff, Inf, 1),
byrow = TRUE,
nrow = 2))
loud_palette <-
leaflet::colorNumeric(
c("#ff0000"),
raster::values(noise_loud),
na.color = "transparent")
leaflet::leaflet(counties_dmv) %>%
leaflet::addTiles() %>%
leaflet::addRasterImage(
noise_loud,
colors = loud_palette,
opacity = 0.5) %>%
leaflet::addPolygons(
color = "#777777",
weight = 1.25,
opacity = 1,
fillOpacity = 0)
Maybe it’s okay? Hard to say … the spatial distributions look pretty doable, and reasonable for sampling, but is such a small difference biologically meaningful? Maybe there’s a better cutoff than quartiles? For example, here’s what the upper and lower 10% look like:
q10 <-
quantile(noise_masked, .1)
q90 <-
quantile(noise_masked, .9)
tibble(noise = raster::values(noise_masked)) %>%
na.omit() %>%
ggplot2:::ggplot(aes(x = noise)) +
ggplot2::geom_histogram(fill = "#dcdcdc", color = '#000000', bins = 50) +
ggplot2::geom_vline(xintercept = q10, color = '#0000ff') +
ggplot2::geom_vline(xintercept = q90, color = '#ff0000') +
ggplot2::theme_bw()

And here’s the quiet areas with a 10% cutoff:
noise_quiet10 <-
raster::reclassify(
noise_masked,
rcl =
matrix(
c(0, q10, 1, q10, Inf, NA),
byrow = TRUE,
nrow = 2),
include.lowest = TRUE)
quiet_palette10 <-
leaflet::colorNumeric(
c("#0000ff"),
raster::values(noise_quiet10),
na.color = "transparent")
leaflet::leaflet(counties_dmv) %>%
leaflet::addTiles() %>%
leaflet::addRasterImage(
noise_quiet10,
colors = quiet_palette10,
opacity = 0.5) %>%
leaflet::addPolygons(
color = "#777777",
weight = 1.25,
opacity = 1,
fillOpacity = 0)
And loud areas with a 10% cutoff:
noise_loud90 <-
raster::reclassify(
noise_masked,
rcl =
matrix(
c(0, q90, NA, q90, Inf, 1),
byrow = TRUE,
nrow = 2))
loud_palette90 <-
leaflet::colorNumeric(
c("#ff0000"),
raster::values(noise_loud90),
na.color = "transparent")
leaflet::leaflet(counties_dmv) %>%
leaflet::addTiles() %>%
leaflet::addRasterImage(
noise_loud90,
colors = loud_palette90,
opacity = 0.5) %>%
leaflet::addPolygons(
color = "#777777",
weight = 1.25,
opacity = 1,
fillOpacity = 0)
Long story short: Not many options for quiet sites within a reasonable driving distance at the 10% cutoff. Loud areas look reasonable. My house is classified within the upper 10% and I can verify that it’s louder than heck at my house, though mostly it’s the damned ice cream trucks and staging for weekend street races – not sure if they included those in their model. At the 25% cutoff, lots of options – but, whether it’s biologically meaningful remains a question.
Binary rasters: Urban vs. rural
Using the cut-off of medium and high-intensity development, I reclassified urban land cover as “1” and aggregated cells (aggregation factor = 7, function = max). Here’s the geographic distribution of urban land cover within the study area:
urban_rc <- nlcd_resampled
urban_rc[!values(urban_rc) %in% c(23, 24)] <- NA
urban_rc[values(urban_rc) %in% c(23, 24)] <- 1
urban_palette <-
leaflet::colorNumeric(
c("#ff0000"),
raster::values(urban_rc),
na.color = "transparent")
leaflet::leaflet(counties_dmv) %>%
leaflet::addTiles() %>%
leaflet::addRasterImage(
urban_rc,
colors = urban_palette,
opacity = 0.75) %>%
leaflet::addPolygons(
color = "#777777",
weight = 1.25,
opacity = 1,
fillOpacity = 0)
NA
One thing that I would say with the result (if you zoom in, especially to suburban areas) is that the nlcd does pretty poorly at predicting urban development, but it’s a starting point.
… and here’s the geographic distribution of non-urban land cover within the study area (unsurprisingly, almost everything):
nonurban_rc <- nlcd_resampled
nonurban_rc[values(nonurban_rc) %in% c(0, 11, 23, 24)] <- NA
nonurban_rc[!is.na(values(nonurban_rc))] <- 1
nonurban_palette <-
leaflet::colorNumeric(
c("#0000ff"),
raster::values(nonurban_rc),
na.color = "transparent")
leaflet::leaflet(counties_dmv) %>%
leaflet::addTiles() %>%
leaflet::addRasterImage(
nonurban_rc,
colors = nonurban_palette,
opacity = 0.75) %>%
leaflet::addPolygons(
color = "#777777",
weight = 1.25,
opacity = 1,
fillOpacity = 0)
Combining noisy, quiet, urban and not-urban:
Just a bit of raster math for this one. I’m back to using the quartile cutoff for noise.
We’ll start with the easy one. Here’s noisy urban sites:
leaflet::leaflet(counties_dmv) %>%
leaflet::addTiles() %>%
leaflet::addRasterImage(
urban_rc*noise_loud,
colors = urban_palette,
opacity = 0.75) %>%
leaflet::addPolygons(
color = "#777777",
weight = 1.25,
opacity = 1,
fillOpacity = 0)
Here’s quiet sites that are classified as urban:
urban_quiet <-
urban_rc*noise_quiet
leaflet::leaflet(counties_dmv) %>%
leaflet::addTiles() %>%
leaflet::addRasterImage(
urban_quiet,
colors = urban_palette,
opacity = 0.75) %>%
leaflet::addPolygons(
color = "#777777",
weight = 1.25,
opacity = 1,
fillOpacity = 0)
The problem with the urban classification really shines here. If you explore around, you can see those few red pixels in the mix. What you can’t see them Shawn? I’ve made them into points to better show off the results:
urban_quiet_points <-
raster::rasterToPoints(urban_quiet, spatial = TRUE)
leaflet::leaflet(counties_dmv) %>%
leaflet::addTiles() %>%
leaflet::addRasterImage(
urban_quiet,
colors = urban_palette,
opacity = 0) %>%
leaflet::addMarkers(urban_quiet_points@coords[,1], urban_quiet_points@coords[,2]) %>%
leaflet::addPolygons(
color = "#777777",
weight = 1.25,
opacity = 1,
fillOpacity = 0)
I’d be hard pressed to call any of these places urban (and you’d have to drive all over hell to get to them). Of course, there’s also the issue to the noise map. Because urban land cover / roads have such a big impact on modeled noise, it isn’t likely going to predict much in the way of quiet urban sites. This may be related to the truth on the ground and limitations of the model.
You can get to quite a few “non-urban” areas that are loud:
leaflet::leaflet(counties_dmv) %>%
leaflet::addTiles() %>%
leaflet::addRasterImage(
nonurban_rc*noise_loud,
colors = urban_palette,
opacity = 0.75) %>%
leaflet::addPolygons(
color = "#777777",
weight = 1.25,
opacity = 1,
fillOpacity = 0)
And, of course, quite a bit of “non-urban” areas that are quiet:
leaflet::leaflet(counties_dmv) %>%
leaflet::addTiles() %>%
leaflet::addRasterImage(
nonurban_rc*noise_quiet,
colors = urban_palette,
opacity = 0.75) %>%
leaflet::addPolygons(
color = "#777777",
weight = 1.25,
opacity = 1,
fillOpacity = 0)
Despite the limitations, if you decide to use the urban v. rural and loud v. quiet layers to select your sampling locations, it’ll be pretty easy to lay some points on these surfaces.
LS0tCnRpdGxlOiAiQ2hvb3NpbmcgcmVjb3JkaW5nIGxvY2F0aW9ucyBmcm9tIG1vZGVsZWQgc291bmQgZGF0YSBhbmQgdXJiYW4gbGFuZCBjb3Zlcj8iCm91dHB1dDogCiAgaHRtbF9ub3RlYm9vazoKICAgIGNvZGVfZm9sZGluZzogaGlkZQotLS0KCmBgYHtyLCBlY2hvID0gRkFMU0V9CmxpYnJhcnkodGlkeXZlcnNlKQpgYGAKCjxocj4KCkZvciAqKm5vaXNlKiosIEkgZG93bmxvYWRlZCB0aGUgbm9pc2UgcmFzdGVyIGRhdGEgZnJvbSBOUFMgKDxhIGhyZWYgPSAiaHR0cHM6Ly9pcm1hLm5wcy5nb3YvRGF0YVN0b3JlL1JlZmVyZW5jZS9Qcm9maWxlLzIyMTczNTYiIHRhcmdldCA9ICJfYmxhbmsiPmxpbms8L2E+KS4gVGhlIGRhdGEgYXJlIGJhc2VkIG9uIDxhIGhyZWYgPSAiaHR0cHM6Ly9zaXRlcy53YXJuZXJjbnIuY29sb3N0YXRlLmVkdS9zb3VuZGFuZGxpZ2h0ZWNvbG9neXRlYW0vd3AtY29udGVudC91cGxvYWRzL3NpdGVzLzE0Ni8yMDIwLzExL2phY291c3RpY2Fsc29jaWV0eTIwMTQucGRmIiB0YXJnZXQgPSAiX2JsYW5rIj50aGlzIHN0dWR5PC9hPi4gVGhlIGRhdGEgSSBwdWxsZWQgaXMgdGhlIGltcGFjdCBsZXZlbCAtLSB3aGljaCBpcyBkZWZpbmVkIGFzIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gZXhpc3Rpbmcgc291bmQgbGV2ZWxzIGFuZCBuYXR1cmFsIHNvdW5kIGxldmVscyAod2hpY2ggaXMgd2h5IHRoZSB2YWx1ZXMgd2VyZSBzbyBtdWNoIGxvd2VyIHRoYW4geW91IGV4cGVjdGVkKS4KCkZvciB1cmJhbiBjbGFzc2lmaWNhdGlvbiwgSSB1c2VkIHRoZSBOTENEIGNsYXNzaWZpZWQgbGFuZCBjb3ZlciBmcm9tIE1STEMsIGRvd25sb2FkZWQgdXNpbmcgdGhlaXIgdmlld2VyIHRvb2wgKDxhIGhyZWYgPSAiaHR0cHM6Ly93d3cubXJsYy5nb3Yvdmlld2VyLyIgdGFyZ2V0ID0gIl9ibGFuayI+bGluazwvYT4pIG1lZGl1bS0gYW5kIGhpZ2gtaW50ZW5zaXR5IGRldmVsb3BtZW50IGZvciB0aGUgTkxDRCBjbGFzc2lmaWVkIGxhbmQgY292ZXIgZGF0YS4KCjxocj4KIyMjIFByb2Nlc3MgcmFzdGVyIGRhdGEKCjEuIFJlYWQgcmFzdGVyIGZpbGVzIGludG8gUgpgYGB7ciwgZXZhbCA9IFRSVUUsIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKCm5vaXNlX2JpZyA8LQogIHJhc3Rlcjo6cmFzdGVyKAogICAgJ0NPTlVTX3N1bURheV9MNTBkQkFfaW1wLnRpZmYnKQoKbmxjZF9iaWcgPC0KICByYXN0ZXI6OnJhc3RlcigKICAgICdOTENEX0NOQkJFYmtTMWxLNExCbWNoc05QL05MQ0RfMjAxNl9MYW5kX0NvdmVyX0w0OF8yMDE5MDQyNF9DTkJCRWJrUzFsSzRMQm1jaHNOUC50aWZmJykKCm5sY2RfbGVnZW5kIDwtCiAgcmVhZF9jc3YoJ05MQ0RfQ05CQkVia1MxbEs0TEJtY2hzTlAvTkxDRF9sYW5kY292ZXJfbGVnZW5kXzIwMThfMTJfMTdfQ05CQkVia1MxbEs0TEJtY2hzTlAuY3N2JykgJT4lCiAgZHBseXI6OmZpbHRlcighaXMubmEoTGVnZW5kKSkKYGBgCgoyLiBEZWZpbmUgYSByZWdpb25hbCBzdWJzZXQgYnkgcHVsbGluZyB0aGUgaW5uZXIgbWV0cm8gREMgY291bnRpZXMuICpOb3RlOiBJIGZpZ3VyZWQgY291bnRpZXMgd291bGQgYmUgdGhlIHdheSB0byBnbyBhYm91dCB0aGlzLiBNeSBmaXJzdCB0aG91Z2h0IHdhcyB0byB1c2UgYWxsIGNvdW50aWVzIGluIHRoZSBETVYsIGJ1dCBtb3N0IGFyZSBwcmV0dHkgcnVyYWwsIHNvIEkgdGhvdWdoIHdlIG1pZ2h0IGNob29zZSBqdXN0IHRoZSBpbm5lciBjb3JlIGNvdW50aWVzIG9mIHRoZSBEQyBtZXRybyByZWdpb24uKiBIZXJlJ3MgaG93IHRoZXkgbG9vazoKCmBgYHtyLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRX0KY291bnR5X25hbWVzX2RtdiA8LQogIGMoIkRpc3RyaWN0IG9mIENvbHVtYmlhIiwKICAgICJNb250Z29tZXJ5IiwKICAgICJQcmluY2UgR2VvcmdlJ3MiLAogICAgIkFsZXhhbmRyaWEiLAogICAgIkFybGluZ3RvbiIsCiAgICAiRmFpcmZheCBDb3VudHkiLAogICAgIkZhaXJmYXgiLAogICAgIkZhbGxzIENodXJjaCIpCgpjb3VudGllc19kbXYgPC0KICBwdXJycjo6bWFwX2RmcigKICAgIGMoJ1ZpcmdpbmlhJywgJ01hcnlsYW5kJywgJ0Rpc3RyaWN0IG9mIENvbHVtYmlhJyksCiAgICB+IHRpZ3Jpczo6Y291bnRpZXMoc3RhdGUgPSAuLCBjYiA9IFRSVUUpKSAlPiUgCiAgZHBseXI6OmZpbHRlcihOQU1FICVpbiUgY291bnR5X25hbWVzX2RtdikgJT4lIAogIHNmOjpzdF90cmFuc2Zvcm0oY3JzID0gIitpbml0PWVwc2c6NDMyNiIpICU+JQogICMgUmVtb3ZpbmcgYSBNb250Z29tZXJ5IENvdW50eSBpbiBWaXJnaW5pYToKICBkcGx5cjo6ZmlsdGVyKEdFT0lEICE9IDUxMTIxKSAlPiUgCiAgZHBseXI6Om11dGF0ZShOQU1FID0gZmFjdG9yKE5BTUUpKQoKY291bnRpZXNfc3AgPC0KICBzZjo6YXNfU3BhdGlhbChjb3VudGllc19kbXYpCgpjb3VudHlfcGFsIDwtIAogIGxlYWZsZXQ6OmNvbG9yRmFjdG9yKAogICAgdmlyaWRpczo6dmlyaWRpcyg4KSwgCiAgICBjb3VudGllc19kbXYkTkFNRSkKCmxlYWZsZXQ6OmxlYWZsZXQoY291bnRpZXNfZG12KSAlPiUKICBsZWFmbGV0OjphZGRUaWxlcygpICU+JQogIGxlYWZsZXQ6OmFkZFBvbHlnb25zKAogICAgY29sb3IgPSAiIzc3Nzc3NyIsIAogICAgd2VpZ2h0ID0gMS4yNSwgCiAgICBvcGFjaXR5ID0gMSwgCiAgICBmaWxsT3BhY2l0eSA9IDAuNCwKICAgIGZpbGxDb2xvciA9IH5jb3VudHlfcGFsKE5BTUUpKQpgYGAKPGJyPgoKMy4gQ3JvcCByYXN0ZXJzIHRvIHRoZSBleHRlbnQgb2YgdGhlIGNvdW50aWVzIGZpbGUgKHRvIHJlZHVjZSBtZW1vcnkgbG9hZCk6CmBgYHtyIGV2YWwgPSBUUlVFfQpub2lzZV9jcm9wcGVkIDwtCiAgbm9pc2VfYmlnICU+JSAKICByYXN0ZXI6OmNyb3AoCiAgICBjb3VudGllc19kbXYgJT4lIAogICAgICBzZjo6c3RfdHJhbnNmb3JtKHByb2plY3Rpb24obm9pc2VfYmlnKSkgJT4lIAogICAgICBzZjo6YXNfU3BhdGlhbCgpICU+JSAKICAgIHJhc3Rlcjo6ZXh0ZW50KCkpICU+JSAKICByYXN0ZXI6OnByb2plY3RSYXN0ZXIoY3JzID0gJytpbml0PWVwc2c6NDMyNicpICU+JSAKICByYXN0ZXI6OnRyaW0oKQoKbmxjZF9jcm9wcGVkIDwtCiAgbmxjZF9iaWcgJT4lIAogIHJhc3Rlcjo6Y3JvcCgKICAgIGNvdW50aWVzX2RtdiAlPiUgCiAgICAgIHNmOjpzdF90cmFuc2Zvcm0ocHJvamVjdGlvbihub2lzZV9iaWcpKSAlPiUgCiAgICAgIHNmOjphc19TcGF0aWFsKCkgJT4lIAogICAgcmFzdGVyOjpleHRlbnQoKSkgJT4lIAogIHJhc3Rlcjo6cHJvamVjdFJhc3RlcihjcnMgPSAnK2luaXQ9ZXBzZzo0MzI2JykgJT4lIAogIHJhc3Rlcjo6dHJpbSgpCmBgYAo0LiBNYXNrIHRoZSByYXN0ZXJzIHRvIHRoZSBjb3VudHkgZmlsZToKYGBge3IgZXZhbCA9IFRSVUV9Cm5vaXNlX21hc2tlZCA8LQogIHJhc3Rlcjo6bWFzaygKICAgIG5vaXNlX2Nyb3BwZWQsIAogICAgc2Y6OmFzX1NwYXRpYWwoY291bnRpZXNfZG12KSkKCm5sY2RfbWFza2VkIDwtCiAgcmFzdGVyOjptYXNrKAogICAgbmxjZF9jcm9wcGVkLCAKICAgIHNmOjphc19TcGF0aWFsKGNvdW50aWVzX2RtdikpCmBgYAo1LiBSZXNhbXBsZSB0aGUgbmxjZCByYXN0ZXIgKDMwbSByZXNvbHV0aW9uKSB0byBtYXRjaCB0aGUgb3JpZ2luIGFuZCByZXNvbHV0aW9uIG9mIG5vaXNlIHJhc3RlciAoMjcwbSk6CmBgYHtyIGV2YWwgPSBUUlVFfQpubGNkX3Jlc2FtcGxlZCA8LQogIHJhc3Rlcjo6cmVzYW1wbGUoCiAgICB4ID0gbmxjZF9tYXNrZWQsCiAgICB5ID0gbm9pc2VfbWFza2VkLAogICAgbWV0aG9kID0gJ25nYicpCmBgYAo8YnI+CkhlcmUncyB3aGF0IHRoZSBub2lzZSByYXN0ZXIgbG9va3MgbGlrZToKYGBge3IsIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFfQoKbm9pc2VfcGFsZXR0ZSA8LSAKICBsZWFmbGV0Ojpjb2xvck51bWVyaWMoCiAgICBjKCIjMDAwMGZmIiwgIiNmZmZmMDAiLCAiI2ZmMDAwMCIpLCAKICAgIHJhc3Rlcjo6dmFsdWVzKG5vaXNlX21hc2tlZCksCiAgbmEuY29sb3IgPSAidHJhbnNwYXJlbnQiKQoKbGVhZmxldDo6bGVhZmxldChjb3VudGllc19kbXYpICU+JQogIGxlYWZsZXQ6OmFkZFRpbGVzKCkgJT4lCiAgbGVhZmxldDo6YWRkUmFzdGVySW1hZ2UoCiAgICBub2lzZV9yZXNhbXBsZWQsCiAgICBjb2xvcnMgPSBub2lzZV9wYWxldHRlLAogICAgb3BhY2l0eSA9IDAuODUpICU+JQogIGxlYWZsZXQ6OmFkZExlZ2VuZCgKICAgIHBhbCA9IG5vaXNlX3BhbGV0dGUsCiAgICB2YWx1ZXMgPSByYXN0ZXI6OnZhbHVlcyhub2lzZV9tYXNrZWQpLAogICAgdGl0bGUgPSAiQW50aHJvcG9nZW5pYyBub2lzZSIpICU+JSAKICBsZWFmbGV0OjphZGRQb2x5Z29ucygKICAgIGNvbG9yID0gIiM3Nzc3NzciLCAKICAgIHdlaWdodCA9IDEuMjUsIAogICAgb3BhY2l0eSA9IDEsIAogICAgZmlsbE9wYWNpdHkgPSAwKQpgYGAKCjxocj4KIyMjIEJpbmFyeSByYXN0ZXJzOiBOb2lzeSB2cy4gbG91ZAoKSSB0aG91Z2h0IGEgZ29vZCB3YXkgdG8gZXN0YWJsaXNoIGN1dG9mZnMgZm9yIHRoZSBub2lzZSBkYXRhIG1pZ2h0IGJlIHRoZSBxdWFydGlsZXMgb2YgdGhlIGRpc3RyaWJ1dGlvbi4KCmBgYHtyfQp0aWJibGUobm9pc2UgPSByYXN0ZXI6OnZhbHVlcyhub2lzZV9tYXNrZWQpKSAlPiUKICBuYS5vbWl0KCkgJT4lIAogIGdncGxvdDI6OjpnZ3Bsb3QoYWVzKHggPSBub2lzZSkpICsKICBnZ3Bsb3QyOjpnZW9tX2hpc3RvZ3JhbShmaWxsID0gIiNkY2RjZGMiLCBjb2xvciA9ICcjMDAwMDAwJywgYmlucyA9IDUwKSArCiAgZ2dwbG90Mjo6dGhlbWVfYncoKQpgYGAKSSdtIHF1ZXN0aW9uaW5nIHRoYXQgbm93OgoKYGBge3J9CgpxdWlldF9jdXRvZmYgPC0KICBxdWFudGlsZShub2lzZV9tYXNrZWQsIC4yNSkKCmxvdWRfY3V0b2ZmIDwtCiAgcXVhbnRpbGUobm9pc2VfbWFza2VkLCAuNzUpCgpxdWlldF9jdXRvZmYKCmxvdWRfY3V0b2ZmCmBgYAoKYGBge3J9CnRpYmJsZShub2lzZSA9IHJhc3Rlcjo6dmFsdWVzKG5vaXNlX21hc2tlZCkpICU+JQogIG5hLm9taXQoKSAlPiUgCiAgZ2dwbG90Mjo6OmdncGxvdChhZXMoeCA9IG5vaXNlKSkgKwogIGdncGxvdDI6Omdlb21faGlzdG9ncmFtKGZpbGwgPSAiI2RjZGNkYyIsIGNvbG9yID0gJyMwMDAwMDAnLCBiaW5zID0gNTApICsKICBnZ3Bsb3QyOjpnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBxdWlldF9jdXRvZmYsIGNvbG9yID0gJyMwMDAwZmYnKSArCiAgZ2dwbG90Mjo6Z2VvbV92bGluZSh4aW50ZXJjZXB0ID0gbG91ZF9jdXRvZmYsIGNvbG9yID0gJyNmZjAwMDAnKSArCiAgZ2dwbG90Mjo6dGhlbWVfYncoKQpgYGAKPGJyPgpUaGlzIHlpZWxkcyB0aGUgZm9sbG93aW5nIGFyZWFzIGZvciBxdWlldCBzaXRlczoKYGBge3IsIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFfQpub2lzZV9xdWlldCA8LQogIHJhc3Rlcjo6cmVjbGFzc2lmeSgKICAgIG5vaXNlX21hc2tlZCwKICAgIHJjbCA9IAogICAgICBtYXRyaXgoCiAgICAgICAgYygwLCBxdWlldF9jdXRvZmYsIDEsIHF1aWV0X2N1dG9mZiwgSW5mLCBOQSksCiAgICAgICAgYnlyb3cgPSBUUlVFLAogICAgICAgIG5yb3cgPSAyKSwKICAgIGluY2x1ZGUubG93ZXN0ID0gVFJVRSkKCnF1aWV0X3BhbGV0dGUgPC0gCiAgbGVhZmxldDo6Y29sb3JOdW1lcmljKAogICAgYygiIzAwMDBmZiIpLCAKICAgIHJhc3Rlcjo6dmFsdWVzKG5vaXNlX3F1aWV0KSwKICBuYS5jb2xvciA9ICJ0cmFuc3BhcmVudCIpCgpsZWFmbGV0OjpsZWFmbGV0KGNvdW50aWVzX2RtdikgJT4lCiAgbGVhZmxldDo6YWRkVGlsZXMoKSAlPiUKICBsZWFmbGV0OjphZGRSYXN0ZXJJbWFnZSgKICAgIG5vaXNlX3F1aWV0LAogICAgY29sb3JzID0gcXVpZXRfcGFsZXR0ZSwKICAgIG9wYWNpdHkgPSAwLjUpICU+JQogIGxlYWZsZXQ6OmFkZFBvbHlnb25zKAogICAgY29sb3IgPSAiIzc3Nzc3NyIsIAogICAgd2VpZ2h0ID0gMS4yNSwgCiAgICBvcGFjaXR5ID0gMSwgCiAgICBmaWxsT3BhY2l0eSA9IDApCmBgYAoKQW5kIHRoZXNlIGFyZWFzIGZvciBsb3VkIHNpdGVzOgpgYGB7ciwgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0V9Cm5vaXNlX2xvdWQgPC0KICByYXN0ZXI6OnJlY2xhc3NpZnkoCiAgICBub2lzZV9tYXNrZWQsCiAgICByY2wgPSAKICAgICAgbWF0cml4KAogICAgICAgIGMoMCwgbG91ZF9jdXRvZmYsIE5BLCBsb3VkX2N1dG9mZiwgSW5mLCAxKSwKICAgICAgICBieXJvdyA9IFRSVUUsCiAgICAgICAgbnJvdyA9IDIpKQoKbG91ZF9wYWxldHRlIDwtIAogIGxlYWZsZXQ6OmNvbG9yTnVtZXJpYygKICAgIGMoIiNmZjAwMDAiKSwgCiAgICByYXN0ZXI6OnZhbHVlcyhub2lzZV9sb3VkKSwKICBuYS5jb2xvciA9ICJ0cmFuc3BhcmVudCIpCgpsZWFmbGV0OjpsZWFmbGV0KGNvdW50aWVzX2RtdikgJT4lCiAgbGVhZmxldDo6YWRkVGlsZXMoKSAlPiUKICBsZWFmbGV0OjphZGRSYXN0ZXJJbWFnZSgKICAgIG5vaXNlX2xvdWQsCiAgICBjb2xvcnMgPSBsb3VkX3BhbGV0dGUsCiAgICBvcGFjaXR5ID0gMC41KSAlPiUKICBsZWFmbGV0OjphZGRQb2x5Z29ucygKICAgIGNvbG9yID0gIiM3Nzc3NzciLCAKICAgIHdlaWdodCA9IDEuMjUsIAogICAgb3BhY2l0eSA9IDEsIAogICAgZmlsbE9wYWNpdHkgPSAwKQpgYGAKCk1heWJlIGl0J3Mgb2theT8gSGFyZCB0byBzYXkgLi4uIHRoZSBzcGF0aWFsIGRpc3RyaWJ1dGlvbnMgbG9vayBwcmV0dHkgZG9hYmxlLCBhbmQgcmVhc29uYWJsZSBmb3Igc2FtcGxpbmcsIGJ1dCBpcyBzdWNoIGEgc21hbGwgZGlmZmVyZW5jZSBiaW9sb2dpY2FsbHkgbWVhbmluZ2Z1bD8gTWF5YmUgdGhlcmUncyBhIGJldHRlciBjdXRvZmYgdGhhbiBxdWFydGlsZXM/IEZvciBleGFtcGxlLCBoZXJlJ3Mgd2hhdCB0aGUgdXBwZXIgYW5kIGxvd2VyIDEwJSBsb29rIGxpa2U6CgpgYGB7cn0KcTEwIDwtCiAgcXVhbnRpbGUobm9pc2VfbWFza2VkLCAuMSkKCnE5MCA8LQogIHF1YW50aWxlKG5vaXNlX21hc2tlZCwgLjkpCgp0aWJibGUobm9pc2UgPSByYXN0ZXI6OnZhbHVlcyhub2lzZV9tYXNrZWQpKSAlPiUKICBuYS5vbWl0KCkgJT4lIAogIGdncGxvdDI6OjpnZ3Bsb3QoYWVzKHggPSBub2lzZSkpICsKICBnZ3Bsb3QyOjpnZW9tX2hpc3RvZ3JhbShmaWxsID0gIiNkY2RjZGMiLCBjb2xvciA9ICcjMDAwMDAwJywgYmlucyA9IDUwKSArCiAgZ2dwbG90Mjo6Z2VvbV92bGluZSh4aW50ZXJjZXB0ID0gcTEwLCBjb2xvciA9ICcjMDAwMGZmJykgKwogIGdncGxvdDI6Omdlb21fdmxpbmUoeGludGVyY2VwdCA9IHE5MCwgY29sb3IgPSAnI2ZmMDAwMCcpICsKICBnZ3Bsb3QyOjp0aGVtZV9idygpCmBgYAoKQW5kIGhlcmUncyB0aGUgcXVpZXQgYXJlYXMgd2l0aCBhIDEwJSBjdXRvZmY6CgpgYGB7ciwgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0V9Cm5vaXNlX3F1aWV0MTAgPC0KICByYXN0ZXI6OnJlY2xhc3NpZnkoCiAgICBub2lzZV9tYXNrZWQsCiAgICByY2wgPSAKICAgICAgbWF0cml4KAogICAgICAgIGMoMCwgcTEwLCAxLCBxMTAsIEluZiwgTkEpLAogICAgICAgIGJ5cm93ID0gVFJVRSwKICAgICAgICBucm93ID0gMiksCiAgICBpbmNsdWRlLmxvd2VzdCA9IFRSVUUpCgpxdWlldF9wYWxldHRlMTAgPC0gCiAgbGVhZmxldDo6Y29sb3JOdW1lcmljKAogICAgYygiIzAwMDBmZiIpLCAKICAgIHJhc3Rlcjo6dmFsdWVzKG5vaXNlX3F1aWV0MTApLAogIG5hLmNvbG9yID0gInRyYW5zcGFyZW50IikKCmxlYWZsZXQ6OmxlYWZsZXQoY291bnRpZXNfZG12KSAlPiUKICBsZWFmbGV0OjphZGRUaWxlcygpICU+JQogIGxlYWZsZXQ6OmFkZFJhc3RlckltYWdlKAogICAgbm9pc2VfcXVpZXQxMCwKICAgIGNvbG9ycyA9IHF1aWV0X3BhbGV0dGUxMCwKICAgIG9wYWNpdHkgPSAwLjUpICU+JQogIGxlYWZsZXQ6OmFkZFBvbHlnb25zKAogICAgY29sb3IgPSAiIzc3Nzc3NyIsIAogICAgd2VpZ2h0ID0gMS4yNSwgCiAgICBvcGFjaXR5ID0gMSwgCiAgICBmaWxsT3BhY2l0eSA9IDApCmBgYAoKCkFuZCBsb3VkIGFyZWFzIHdpdGggYSAxMCUgY3V0b2ZmOgoKYGBge3IsIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFfQpub2lzZV9sb3VkOTAgPC0KICByYXN0ZXI6OnJlY2xhc3NpZnkoCiAgICBub2lzZV9tYXNrZWQsCiAgICByY2wgPSAKICAgICAgbWF0cml4KAogICAgICAgIGMoMCwgcTkwLCBOQSwgcTkwLCBJbmYsIDEpLAogICAgICAgIGJ5cm93ID0gVFJVRSwKICAgICAgICBucm93ID0gMikpCgpsb3VkX3BhbGV0dGU5MCA8LSAKICBsZWFmbGV0Ojpjb2xvck51bWVyaWMoCiAgICBjKCIjZmYwMDAwIiksIAogICAgcmFzdGVyOjp2YWx1ZXMobm9pc2VfbG91ZDkwKSwKICBuYS5jb2xvciA9ICJ0cmFuc3BhcmVudCIpCgpsZWFmbGV0OjpsZWFmbGV0KGNvdW50aWVzX2RtdikgJT4lCiAgbGVhZmxldDo6YWRkVGlsZXMoKSAlPiUKICBsZWFmbGV0OjphZGRSYXN0ZXJJbWFnZSgKICAgIG5vaXNlX2xvdWQ5MCwKICAgIGNvbG9ycyA9IGxvdWRfcGFsZXR0ZTkwLAogICAgb3BhY2l0eSA9IDAuNSkgJT4lCiAgbGVhZmxldDo6YWRkUG9seWdvbnMoCiAgICBjb2xvciA9ICIjNzc3Nzc3IiwgCiAgICB3ZWlnaHQgPSAxLjI1LCAKICAgIG9wYWNpdHkgPSAxLCAKICAgIGZpbGxPcGFjaXR5ID0gMCkKYGBgCgo8YnI+Ckxvbmcgc3Rvcnkgc2hvcnQ6IE5vdCBtYW55IG9wdGlvbnMgZm9yIHF1aWV0IHNpdGVzIHdpdGhpbiBhIHJlYXNvbmFibGUgZHJpdmluZyBkaXN0YW5jZSBhdCB0aGUgMTAlIGN1dG9mZi4gTG91ZCBhcmVhcyBsb29rIHJlYXNvbmFibGUuICpNeSBob3VzZSBpcyBjbGFzc2lmaWVkIHdpdGhpbiB0aGUgdXBwZXIgMTAlIGFuZCBJIGNhbiB2ZXJpZnkgdGhhdCBpdCdzIGxvdWRlciB0aGFuIGhlY2sgYXQgbXkgaG91c2UsIHRob3VnaCBtb3N0bHkgaXQncyB0aGUgZGFtbmVkIGljZSBjcmVhbSB0cnVja3MgYW5kIHN0YWdpbmcgZm9yIHdlZWtlbmQgc3RyZWV0IHJhY2VzIC0tIG5vdCBzdXJlIGlmIHRoZXkgaW5jbHVkZWQgdGhvc2UgaW4gdGhlaXIgbW9kZWwqLiBBdCB0aGUgMjUlIGN1dG9mZiwgbG90cyBvZiBvcHRpb25zIC0tIGJ1dCwgd2hldGhlciBpdCdzIGJpb2xvZ2ljYWxseSBtZWFuaW5nZnVsIHJlbWFpbnMgYSBxdWVzdGlvbi4KPGJyPgoKIyMjIEJpbmFyeSByYXN0ZXJzOiBVcmJhbiB2cy4gcnVyYWwKClVzaW5nIHRoZSBjdXQtb2ZmIG9mIG1lZGl1bSBhbmQgaGlnaC1pbnRlbnNpdHkgZGV2ZWxvcG1lbnQsIEkgcmVjbGFzc2lmaWVkIHVyYmFuIGxhbmQgY292ZXIgYXMgIjEiIGFuZCBhZ2dyZWdhdGVkIGNlbGxzIChhZ2dyZWdhdGlvbiBmYWN0b3IgPSA3LCBmdW5jdGlvbiA9IG1heCkuIEhlcmUncyB0aGUgZ2VvZ3JhcGhpYyBkaXN0cmlidXRpb24gb2YgdXJiYW4gbGFuZCBjb3ZlciB3aXRoaW4gdGhlIHN0dWR5IGFyZWE6CgpgYGB7ciwgd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0V9CnVyYmFuX3JjIDwtIG5sY2RfcmVzYW1wbGVkCgp1cmJhbl9yY1shdmFsdWVzKHVyYmFuX3JjKSAlaW4lIGMoMjMsIDI0KV0gPC0gTkEKCnVyYmFuX3JjW3ZhbHVlcyh1cmJhbl9yYykgJWluJSBjKDIzLCAyNCldIDwtIDEKCnVyYmFuX3BhbGV0dGUgPC0KICBsZWFmbGV0Ojpjb2xvck51bWVyaWMoCiAgICBjKCIjZmYwMDAwIiksCiAgICByYXN0ZXI6OnZhbHVlcyh1cmJhbl9yYyksCiAgbmEuY29sb3IgPSAidHJhbnNwYXJlbnQiKQoKbGVhZmxldDo6bGVhZmxldChjb3VudGllc19kbXYpICU+JQogIGxlYWZsZXQ6OmFkZFRpbGVzKCkgJT4lCiAgbGVhZmxldDo6YWRkUmFzdGVySW1hZ2UoCiAgICB1cmJhbl9yYywKICAgIGNvbG9ycyA9IHVyYmFuX3BhbGV0dGUsCiAgICBvcGFjaXR5ID0gMC43NSkgJT4lCiAgbGVhZmxldDo6YWRkUG9seWdvbnMoCiAgICBjb2xvciA9ICIjNzc3Nzc3IiwKICAgIHdlaWdodCA9IDEuMjUsCiAgICBvcGFjaXR5ID0gMSwKICAgIGZpbGxPcGFjaXR5ID0gMCkKCmBgYAoKT25lIHRoaW5nIHRoYXQgSSB3b3VsZCBzYXkgd2l0aCB0aGUgcmVzdWx0IChpZiB5b3Ugem9vbSBpbiwgZXNwZWNpYWxseSB0byBzdWJ1cmJhbiBhcmVhcykgaXMgdGhhdCB0aGUgbmxjZCBkb2VzIHByZXR0eSBwb29ybHkgYXQgcHJlZGljdGluZyB1cmJhbiBkZXZlbG9wbWVudCwgYnV0IGl0J3MgYSBzdGFydGluZyBwb2ludC4KCi4uLiBhbmQgaGVyZSdzIHRoZSBnZW9ncmFwaGljIGRpc3RyaWJ1dGlvbiBvZiBub24tdXJiYW4gbGFuZCBjb3ZlciB3aXRoaW4gdGhlIHN0dWR5IGFyZWEgKHVuc3VycHJpc2luZ2x5LCBhbG1vc3QgZXZlcnl0aGluZyk6CgoKYGBge3IsIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFfQoKbm9udXJiYW5fcmMgPC0gbmxjZF9yZXNhbXBsZWQKCm5vbnVyYmFuX3JjW3ZhbHVlcyhub251cmJhbl9yYykgJWluJSBjKDAsIDExLCAyMywgMjQpXSA8LSBOQQoKbm9udXJiYW5fcmNbIWlzLm5hKHZhbHVlcyhub251cmJhbl9yYykpXSA8LSAxCgpub251cmJhbl9wYWxldHRlIDwtCiAgbGVhZmxldDo6Y29sb3JOdW1lcmljKAogICAgYygiIzAwMDBmZiIpLAogICAgcmFzdGVyOjp2YWx1ZXMobm9udXJiYW5fcmMpLAogIG5hLmNvbG9yID0gInRyYW5zcGFyZW50IikKCmxlYWZsZXQ6OmxlYWZsZXQoY291bnRpZXNfZG12KSAlPiUKICBsZWFmbGV0OjphZGRUaWxlcygpICU+JQogIGxlYWZsZXQ6OmFkZFJhc3RlckltYWdlKAogICAgbm9udXJiYW5fcmMsCiAgICBjb2xvcnMgPSBub251cmJhbl9wYWxldHRlLAogICAgb3BhY2l0eSA9IDAuNzUpICU+JQogIGxlYWZsZXQ6OmFkZFBvbHlnb25zKAogICAgY29sb3IgPSAiIzc3Nzc3NyIsCiAgICB3ZWlnaHQgPSAxLjI1LAogICAgb3BhY2l0eSA9IDEsCiAgICBmaWxsT3BhY2l0eSA9IDApCmBgYAoKPGhyPgoKIyMjIENvbWJpbmluZyBub2lzeSwgcXVpZXQsIHVyYmFuIGFuZCBub3QtdXJiYW46CgpKdXN0IGEgYml0IG9mIHJhc3RlciBtYXRoIGZvciB0aGlzIG9uZS4gSSdtIGJhY2sgdG8gdXNpbmcgdGhlIHF1YXJ0aWxlIGN1dG9mZiBmb3Igbm9pc2UuCgpXZSdsbCBzdGFydCB3aXRoIHRoZSBlYXN5IG9uZS4gSGVyZSdzIG5vaXN5IHVyYmFuIHNpdGVzOgoKYGBge3IsIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFfQpsZWFmbGV0OjpsZWFmbGV0KGNvdW50aWVzX2RtdikgJT4lCiAgbGVhZmxldDo6YWRkVGlsZXMoKSAlPiUKICBsZWFmbGV0OjphZGRSYXN0ZXJJbWFnZSgKICAgIHVyYmFuX3JjKm5vaXNlX2xvdWQsCiAgICBjb2xvcnMgPSB1cmJhbl9wYWxldHRlLAogICAgb3BhY2l0eSA9IDAuNzUpICU+JQogIGxlYWZsZXQ6OmFkZFBvbHlnb25zKAogICAgY29sb3IgPSAiIzc3Nzc3NyIsCiAgICB3ZWlnaHQgPSAxLjI1LAogICAgb3BhY2l0eSA9IDEsCiAgICBmaWxsT3BhY2l0eSA9IDApCmBgYAoKSGVyZSdzIHF1aWV0IHNpdGVzIHRoYXQgYXJlIGNsYXNzaWZpZWQgYXMgdXJiYW46CgpgYGB7ciwgd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0V9CnVyYmFuX3F1aWV0IDwtCiAgdXJiYW5fcmMqbm9pc2VfcXVpZXQKCmxlYWZsZXQ6OmxlYWZsZXQoY291bnRpZXNfZG12KSAlPiUKICBsZWFmbGV0OjphZGRUaWxlcygpICU+JQogIGxlYWZsZXQ6OmFkZFJhc3RlckltYWdlKAogICAgdXJiYW5fcXVpZXQsCiAgICBjb2xvcnMgPSB1cmJhbl9wYWxldHRlLAogICAgb3BhY2l0eSA9IDAuNzUpICU+JQogIGxlYWZsZXQ6OmFkZFBvbHlnb25zKAogICAgY29sb3IgPSAiIzc3Nzc3NyIsCiAgICB3ZWlnaHQgPSAxLjI1LAogICAgb3BhY2l0eSA9IDEsCiAgICBmaWxsT3BhY2l0eSA9IDApCmBgYAo8YnI+ClRoZSBwcm9ibGVtIHdpdGggdGhlIHVyYmFuIGNsYXNzaWZpY2F0aW9uIHJlYWxseSBzaGluZXMgaGVyZS4gSWYgeW91IGV4cGxvcmUgYXJvdW5kLCB5b3UgY2FuIHNlZSB0aG9zZSBmZXcgcmVkIHBpeGVscyBpbiB0aGUgbWl4LiBXaGF0IHlvdSBjYW4ndCBzZWUgdGhlbSBTaGF3bj8gSSd2ZSBtYWRlIHRoZW0gaW50byBwb2ludHMgdG8gYmV0dGVyIHNob3cgb2ZmIHRoZSByZXN1bHRzOgoKYGBge3IsIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFfQoKdXJiYW5fcXVpZXRfcG9pbnRzIDwtCiAgcmFzdGVyOjpyYXN0ZXJUb1BvaW50cyh1cmJhbl9xdWlldCwgc3BhdGlhbCA9IFRSVUUpCgpsZWFmbGV0OjpsZWFmbGV0KGNvdW50aWVzX2RtdikgJT4lCiAgbGVhZmxldDo6YWRkVGlsZXMoKSAlPiUKICBsZWFmbGV0OjphZGRSYXN0ZXJJbWFnZSgKICAgIHVyYmFuX3F1aWV0LAogICAgY29sb3JzID0gdXJiYW5fcGFsZXR0ZSwKICAgIG9wYWNpdHkgPSAwKSAlPiUKICBsZWFmbGV0OjphZGRNYXJrZXJzKHVyYmFuX3F1aWV0X3BvaW50c0Bjb29yZHNbLDFdLCB1cmJhbl9xdWlldF9wb2ludHNAY29vcmRzWywyXSkgJT4lIAogIGxlYWZsZXQ6OmFkZFBvbHlnb25zKAogICAgY29sb3IgPSAiIzc3Nzc3NyIsCiAgICB3ZWlnaHQgPSAxLjI1LAogICAgb3BhY2l0eSA9IDEsCiAgICBmaWxsT3BhY2l0eSA9IDApCmBgYAoKPGJyPgpJJ2QgYmUgaGFyZCBwcmVzc2VkIHRvIGNhbGwgYW55IG9mIHRoZXNlIHBsYWNlcyB1cmJhbiAoYW5kIHlvdSdkIGhhdmUgdG8gZHJpdmUgYWxsIG92ZXIgaGVsbCB0byBnZXQgdG8gdGhlbSkuIE9mIGNvdXJzZSwgdGhlcmUncyBhbHNvIHRoZSBpc3N1ZSB0byB0aGUgbm9pc2UgbWFwLiBCZWNhdXNlIHVyYmFuIGxhbmQgY292ZXIgLyByb2FkcyBoYXZlIHN1Y2ggYSBiaWcgaW1wYWN0IG9uIG1vZGVsZWQgbm9pc2UsIGl0IGlzbid0IGxpa2VseSBnb2luZyB0byBwcmVkaWN0IG11Y2ggaW4gdGhlIHdheSBvZiBxdWlldCB1cmJhbiBzaXRlcy4gVGhpcyBtYXkgYmUgcmVsYXRlZCB0byB0aGUgdHJ1dGggb24gdGhlIGdyb3VuZCBhbmQgbGltaXRhdGlvbnMgb2YgdGhlIG1vZGVsLgoKWW91IGNhbiBnZXQgdG8gcXVpdGUgYSBmZXcgIm5vbi11cmJhbiIgYXJlYXMgdGhhdCBhcmUgbG91ZDoKCmBgYHtyLCBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRX0KCmxlYWZsZXQ6OmxlYWZsZXQoY291bnRpZXNfZG12KSAlPiUKICBsZWFmbGV0OjphZGRUaWxlcygpICU+JQogIGxlYWZsZXQ6OmFkZFJhc3RlckltYWdlKAogICAgbm9udXJiYW5fcmMqbm9pc2VfbG91ZCwKICAgIGNvbG9ycyA9IHVyYmFuX3BhbGV0dGUsCiAgICBvcGFjaXR5ID0gMC43NSkgJT4lCiAgbGVhZmxldDo6YWRkUG9seWdvbnMoCiAgICBjb2xvciA9ICIjNzc3Nzc3IiwKICAgIHdlaWdodCA9IDEuMjUsCiAgICBvcGFjaXR5ID0gMSwKICAgIGZpbGxPcGFjaXR5ID0gMCkKYGBgCgpBbmQsIG9mIGNvdXJzZSwgcXVpdGUgYSBiaXQgb2YgIm5vbi11cmJhbiIgYXJlYXMgdGhhdCBhcmUgcXVpZXQ6CgpgYGB7ciwgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0V9CgpsZWFmbGV0OjpsZWFmbGV0KGNvdW50aWVzX2RtdikgJT4lCiAgbGVhZmxldDo6YWRkVGlsZXMoKSAlPiUKICBsZWFmbGV0OjphZGRSYXN0ZXJJbWFnZSgKICAgIG5vbnVyYmFuX3JjKm5vaXNlX3F1aWV0LAogICAgY29sb3JzID0gdXJiYW5fcGFsZXR0ZSwKICAgIG9wYWNpdHkgPSAwLjc1KSAlPiUKICBsZWFmbGV0OjphZGRQb2x5Z29ucygKICAgIGNvbG9yID0gIiM3Nzc3NzciLAogICAgd2VpZ2h0ID0gMS4yNSwKICAgIG9wYWNpdHkgPSAxLAogICAgZmlsbE9wYWNpdHkgPSAwKQpgYGAKPGJyPgpEZXNwaXRlIHRoZSBsaW1pdGF0aW9ucywgaWYgeW91IGRlY2lkZSB0byB1c2UgdGhlIHVyYmFuIHYuIHJ1cmFsIGFuZCBsb3VkIHYuIHF1aWV0IGxheWVycyB0byBzZWxlY3QgeW91ciBzYW1wbGluZyBsb2NhdGlvbnMsIGl0J2xsIGJlIHByZXR0eSBlYXN5IHRvIGxheSBzb21lIHBvaW50cyBvbiB0aGVzZSBzdXJmYWNlcy4K