Dependencies
This notebook requires
# primary package
library(areal)
# tidyverse packages
library(dplyr)
# spatial packages
library(sf)
library(tidycensus)
library(tigris)
To enable
caching of data, set `options(tigris_use_cache = TRUE)` in your R script or .Rprofile.
Attaching package: ‘tigris’
The following object is masked from ‘package:graphics’:
plot
# other packages
library(gridExtra)
Attaching package: ‘gridExtra’
The following object is masked from ‘package:dplyr’:
combine
library(microbenchmark)
library(testthat)
Comparisons with sf
Produce Estimates
First, we’ll create three spatially extensive estimates for comparison. Two will use the areal
package, varying the type of weight applied to the estimate:
# areal package, spatially extensive using total
areal_exT <- aw_interpolate(ar_stl_wards, tid = WARD, source = ar_stl_race, sid = GEOID,
weight = "total", output = "tibble", extensive = "TOTAL_E")
# areal package, spatially extensive using sum
areal_exS <- aw_interpolate(ar_stl_wards, tid = WARD, source = ar_stl_race, sid = GEOID,
weight = "sum", output = "tibble", extensive = "TOTAL_E")
Next, we’ll replicate the process using sf
:
# sf package, spatially extensive
sf_ex <- st_interpolate_aw(ar_stl_race["TOTAL_E"], ar_stl_wards, extensive = TRUE)
st_interpolate_aw assumes attributes are constant over areas of x
We’ll also produce a spatially intensive estimate using areal
:
# areal package, spatially intensive
areal_in <- aw_interpolate(ar_stl_wards, tid = WARD, source = ar_stl_asthma, sid = GEOID,
weight = "sum", output = "tibble", intensive = "ASTHMA")
And finally, we’ll replicate the spatially intensive estimate using sf
:
# sf package, spatially intensive
sf_in <- st_interpolate_aw(ar_stl_asthma["ASTHMA"], ar_stl_wards, extensive = FALSE)
st_interpolate_aw assumes attributes are constant over areas of x
Compile Results
First, we’ll compile the extensive results:
# areal, extensive sum
areal_exS <- areal_exS %>%
select(WARD, TOTAL_E) %>%
rename(areal_exS = TOTAL_E)
# areal, extensive total
areal_exT <- areal_exT %>%
select(WARD, TOTAL_E) %>%
rename(areal_exT = TOTAL_E)
# sf, extensive total
sf_ex <- sf_ex %>%
rename(sf_ex = TOTAL_E)
st_geometry(sf_ex) <- NULL
# combine
extensive <- left_join(sf_ex, areal_exT, by = c("Group.1" = "WARD")) %>%
left_join(., areal_exS, by = c("Group.1" = "WARD")) %>%
mutate(delta = areal_exT-areal_exS) %>%
rename(Ward = Group.1) %>%
as_tibble()
We’ll make a similar compliation of the intensive results:
# areal, intensive
areal_in <- areal_in %>%
select(WARD, ASTHMA) %>%
rename(areal_in = ASTHMA)
# sf, intensive
sf_in <- sf_in %>%
rename(sf_in = ASTHMA)
st_geometry(sf_in) <- NULL
# combine
intensive <- left_join(sf_in, areal_in, by = c("Group.1" = "WARD")) %>%
rename(Ward = Group.1) %>%
as_tibble()
Print Tables
The following code chunk produces two tables for the manuscript:
# produce rounded extensive estimates
extensiveSub <- extensive %>%
filter(Ward >= 1 & Ward <= 10) %>%
mutate(
sf_ex = round(sf_ex, digits = 3),
areal_exT = round(areal_exT, digits = 3),
areal_exS = round(areal_exS, digits = 3),
delta = round(delta, digits = 3)
) %>%
rename(
`sf` = sf_ex,
`areal, total weight` = areal_exT,
`areal, sum weight` = areal_exS
)
# print extensive table
png(filename = "paper/extensiveTable.png", width = 480, height = 300, bg = "white", type = "cairo-png")
grid.arrange(tableGrob(extensiveSub, rows = NULL), top = "Comparison of sf and areal Output\nSpatially Extensive Interpolation")
dev.off()
null device
1
# produce rounded intensive estimates
intensiveSub <- intensive %>%
filter(Ward >= 1 & Ward <= 10) %>%
mutate(
sf_in = round(sf_in, digits = 3),
areal_in = round(areal_in, digits = 3)
) %>%
rename(
`sf` = sf_in,
`areal` = areal_in
)
# print intensive table
png(filename = "paper/intensiveTable.png", width = 480, height = 300, bg = "white", type = "cairo-png")
grid.arrange(tableGrob(intensiveSub, rows = NULL), top = "Comparison of sf and areal Output\nSpatially Intensive Interpolation")
dev.off()
null device
1
Compare Results
We can verify that the areal
workflow with weight = "total"
matches the sf
extensive output:
expect_equal(extensive$sf_ex, extensive$areal_exT)
We can do the same for the intensive interpolations:
expect_equal(intensive$sf_in, intensive$areal_in)
Benchmark
Next, we’ll benchmark the extensive estimation times:
# compare spatially extensive interpolations
microbenchmark(
aw_interpolate(ar_stl_wards, tid = WARD, source = ar_stl_race, sid = GEOID,
weight = "total", output = "tibble", extensive = "TOTAL_E"),
suppressWarnings(st_interpolate_aw(ar_stl_race["TOTAL_E"], ar_stl_wards, extensive = TRUE))
)
We’ll repeat the process for the intensive estimations:
# compare spatially intensive interpolations
microbenchmark(
aw_interpolate(ar_stl_wards, tid = WARD, source = ar_stl_asthma, sid = GEOID,
weight = "sum", output = "tibble", intensive = "ASTHMA"),
suppressWarnings(st_interpolate_aw(ar_stl_asthma["ASTHMA"], ar_stl_wards, extensive = FALSE))
)
Geometry Collections
Finally, we’ll provide an example of a more intensive estimation process that also triggers the geometry collection workflow, which will add to the estimation time. We need to download several data sets using tigris
and tidycensus
:
Here are the sample sizes for both data sets:
nrow(moPop)
nrow(moBlockGroups)
Here is the benchmark for the estimates produced with these data:
microbenchmark(
aw_interpolate(moBlockGroups, tid = GEOID, source = moPop, sid = GEOID,
weight = "sum", output = "tibble", intensive = "totalPop")
)
LS0tCnRpdGxlOiAiQXBwZW5kaXggZm9yIEpPU1MgUGFwZXIiCmF1dGhvcjogIkNocmlzdG9waGVyIFByZW5lciwgUGguRC4iCmRhdGU6ICcoYHIgZm9ybWF0KFN5cy50aW1lKCksICIlQiAlZCwgJVkiKWApJwpvdXRwdXQ6IAogIGdpdGh1Yl9kb2N1bWVudDogZGVmYXVsdAogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQgCi0tLQoKIyMgSW50cm9kdWN0aW9uClRoaXMgZG9jdW1lbnQgY29udGFpbnMgcmVwbGljYXRpb24gY29kZSBmb3IgdGhlIGV4YW1wbGVzIHByb3ZpZGVkIGluIG91ciAqSm91cm5hbCBvZiBPcGVuIFNvdXJjZSBTb2Z0d2FyZSogbWFudXNjcmlwdC4KCiMjIERlcGVuZGVuY2llcwpUaGlzIG5vdGVib29rIHJlcXVpcmVzCgpgYGB7ciBsb2FkLXBhY2thZ2VzfQojIHByaW1hcnkgcGFja2FnZQpsaWJyYXJ5KGFyZWFsKQoKIyB0aWR5dmVyc2UgcGFja2FnZXMKbGlicmFyeShkcGx5cikKCiMgc3BhdGlhbCBwYWNrYWdlcwpsaWJyYXJ5KHNmKQpsaWJyYXJ5KHRpZHljZW5zdXMpCmxpYnJhcnkodGlncmlzKQoKIyBvdGhlciBwYWNrYWdlcwpsaWJyYXJ5KGdyaWRFeHRyYSkKbGlicmFyeShtaWNyb2JlbmNobWFyaykKbGlicmFyeSh0ZXN0dGhhdCkKYGBgCgojIyBDb21wYXJpc29ucyB3aXRoIGBzZmAKIyMjIFByb2R1Y2UgRXN0aW1hdGVzCkZpcnN0LCB3ZSdsbCBjcmVhdGUgdGhyZWUgc3BhdGlhbGx5IGV4dGVuc2l2ZSBlc3RpbWF0ZXMgZm9yIGNvbXBhcmlzb24uIFR3byB3aWxsIHVzZSB0aGUgYGFyZWFsYCBwYWNrYWdlLCB2YXJ5aW5nIHRoZSB0eXBlIG9mIHdlaWdodCBhcHBsaWVkIHRvIHRoZSBlc3RpbWF0ZToKCmBgYHtyIGFyZWFsLWV4dGVuc2l2ZX0KIyBhcmVhbCBwYWNrYWdlLCBzcGF0aWFsbHkgZXh0ZW5zaXZlIHVzaW5nIHRvdGFsCmFyZWFsX2V4VCA8LSBhd19pbnRlcnBvbGF0ZShhcl9zdGxfd2FyZHMsIHRpZCA9IFdBUkQsIHNvdXJjZSA9IGFyX3N0bF9yYWNlLCBzaWQgPSBHRU9JRCwKICAgICAgICAgICAgICAgd2VpZ2h0ID0gInRvdGFsIiwgb3V0cHV0ID0gInRpYmJsZSIsIGV4dGVuc2l2ZSA9ICJUT1RBTF9FIikKCiMgYXJlYWwgcGFja2FnZSwgc3BhdGlhbGx5IGV4dGVuc2l2ZSB1c2luZyBzdW0KYXJlYWxfZXhTIDwtIGF3X2ludGVycG9sYXRlKGFyX3N0bF93YXJkcywgdGlkID0gV0FSRCwgc291cmNlID0gYXJfc3RsX3JhY2UsIHNpZCA9IEdFT0lELAogICAgICAgICAgICAgICAgICAgICAgICAgICAgd2VpZ2h0ID0gInN1bSIsIG91dHB1dCA9ICJ0aWJibGUiLCBleHRlbnNpdmUgPSAiVE9UQUxfRSIpCmBgYAoKTmV4dCwgd2UnbGwgcmVwbGljYXRlIHRoZSBwcm9jZXNzIHVzaW5nIGBzZmA6CgpgYGB7ciBzZi1leHRlbnNpdmV9CiMgc2YgcGFja2FnZSwgc3BhdGlhbGx5IGV4dGVuc2l2ZQpzZl9leCA8LSBzdF9pbnRlcnBvbGF0ZV9hdyhhcl9zdGxfcmFjZVsiVE9UQUxfRSJdLCBhcl9zdGxfd2FyZHMsIGV4dGVuc2l2ZSA9IFRSVUUpCmBgYAoKV2UnbGwgYWxzbyBwcm9kdWNlIGEgc3BhdGlhbGx5IGludGVuc2l2ZSBlc3RpbWF0ZSB1c2luZyBgYXJlYWxgOgoKYGBge3IgYXJlYWwtaW50ZW5zaXZlfQojIGFyZWFsIHBhY2thZ2UsIHNwYXRpYWxseSBpbnRlbnNpdmUKYXJlYWxfaW4gPC0gYXdfaW50ZXJwb2xhdGUoYXJfc3RsX3dhcmRzLCB0aWQgPSBXQVJELCBzb3VyY2UgPSBhcl9zdGxfYXN0aG1hLCBzaWQgPSBHRU9JRCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdlaWdodCA9ICJzdW0iLCBvdXRwdXQgPSAidGliYmxlIiwgaW50ZW5zaXZlID0gIkFTVEhNQSIpCmBgYAoKQW5kIGZpbmFsbHksIHdlJ2xsIHJlcGxpY2F0ZSB0aGUgc3BhdGlhbGx5IGludGVuc2l2ZSBlc3RpbWF0ZSB1c2luZyBgc2ZgOgoKYGBge3Igc2YtaW50ZW5zaXZlfQojIHNmIHBhY2thZ2UsIHNwYXRpYWxseSBpbnRlbnNpdmUKc2ZfaW4gPC0gc3RfaW50ZXJwb2xhdGVfYXcoYXJfc3RsX2FzdGhtYVsiQVNUSE1BIl0sIGFyX3N0bF93YXJkcywgZXh0ZW5zaXZlID0gRkFMU0UpCmBgYAoKIyMjIENvbXBpbGUgUmVzdWx0cwpGaXJzdCwgd2UnbGwgY29tcGlsZSB0aGUgZXh0ZW5zaXZlIHJlc3VsdHM6CgpgYGB7ciBjb21waWxlLWV4dGVuc2l2ZX0KIyBhcmVhbCwgZXh0ZW5zaXZlIHN1bQphcmVhbF9leFMgPC0gYXJlYWxfZXhTICU+JQogIHNlbGVjdChXQVJELCBUT1RBTF9FKSAlPiUKICByZW5hbWUoYXJlYWxfZXhTID0gVE9UQUxfRSkKCiMgYXJlYWwsIGV4dGVuc2l2ZSB0b3RhbAphcmVhbF9leFQgPC0gYXJlYWxfZXhUICU+JQogIHNlbGVjdChXQVJELCBUT1RBTF9FKSAlPiUKICByZW5hbWUoYXJlYWxfZXhUID0gVE9UQUxfRSkKCiMgc2YsIGV4dGVuc2l2ZSB0b3RhbApzZl9leCA8LSBzZl9leCAlPiUKICByZW5hbWUoc2ZfZXggPSBUT1RBTF9FKQpzdF9nZW9tZXRyeShzZl9leCkgPC0gTlVMTAoKIyBjb21iaW5lCmV4dGVuc2l2ZSA8LSBsZWZ0X2pvaW4oc2ZfZXgsIGFyZWFsX2V4VCwgYnkgPSBjKCJHcm91cC4xIiA9ICJXQVJEIikpICU+JQogIGxlZnRfam9pbiguLCBhcmVhbF9leFMsIGJ5ID0gYygiR3JvdXAuMSIgPSAiV0FSRCIpKSAlPiUKICBtdXRhdGUoZGVsdGEgPSBhcmVhbF9leFQtYXJlYWxfZXhTKSAlPiUKICByZW5hbWUoV2FyZCA9IEdyb3VwLjEpICU+JQogIGFzX3RpYmJsZSgpCmBgYAoKV2UnbGwgbWFrZSBhIHNpbWlsYXIgY29tcGxpYXRpb24gb2YgdGhlIGludGVuc2l2ZSByZXN1bHRzOgoKYGBge3IgY29tcGlsZS1pbnRlbnNpdmV9CiMgYXJlYWwsIGludGVuc2l2ZQphcmVhbF9pbiA8LSBhcmVhbF9pbiAlPiUKICBzZWxlY3QoV0FSRCwgQVNUSE1BKSAlPiUKICByZW5hbWUoYXJlYWxfaW4gPSBBU1RITUEpCgojIHNmLCBpbnRlbnNpdmUKc2ZfaW4gPC0gc2ZfaW4gJT4lCiAgcmVuYW1lKHNmX2luID0gQVNUSE1BKQpzdF9nZW9tZXRyeShzZl9pbikgPC0gTlVMTAoKIyBjb21iaW5lCmludGVuc2l2ZSA8LSBsZWZ0X2pvaW4oc2ZfaW4sIGFyZWFsX2luLCBieSA9IGMoIkdyb3VwLjEiID0gIldBUkQiKSkgJT4lCiAgcmVuYW1lKFdhcmQgPSBHcm91cC4xKSAlPiUKICBhc190aWJibGUoKQpgYGAKCiMjIyBQcmludCBUYWJsZXMKVGhlIGZvbGxvd2luZyBjb2RlIGNodW5rIHByb2R1Y2VzIHR3byB0YWJsZXMgZm9yIHRoZSBtYW51c2NyaXB0OgoKYGBge3IgcHJpbnQtdGFibGVzfQojIHByb2R1Y2Ugcm91bmRlZCBleHRlbnNpdmUgZXN0aW1hdGVzCmV4dGVuc2l2ZVN1YiA8LSBleHRlbnNpdmUgJT4lCiAgZmlsdGVyKFdhcmQgPj0gMSAmIFdhcmQgPD0gMTApICU+JQogIG11dGF0ZSgKICAgIHNmX2V4ID0gcm91bmQoc2ZfZXgsIGRpZ2l0cyA9IDMpLAogICAgYXJlYWxfZXhUID0gcm91bmQoYXJlYWxfZXhULCBkaWdpdHMgPSAzKSwKICAgIGFyZWFsX2V4UyA9IHJvdW5kKGFyZWFsX2V4UywgZGlnaXRzID0gMyksCiAgICBkZWx0YSA9IHJvdW5kKGRlbHRhLCBkaWdpdHMgPSAzKQogICkgJT4lCiAgcmVuYW1lKAogICAgYHNmYCA9IHNmX2V4LAogICAgYGFyZWFsLCB0b3RhbCB3ZWlnaHRgID0gYXJlYWxfZXhULAogICAgYGFyZWFsLCBzdW0gd2VpZ2h0YCA9IGFyZWFsX2V4UwogICkKCiMgcHJpbnQgZXh0ZW5zaXZlIHRhYmxlCnBuZyhmaWxlbmFtZSA9ICJwYXBlci9leHRlbnNpdmVUYWJsZS5wbmciLCB3aWR0aCA9IDQ4MCwgaGVpZ2h0ID0gMzAwLCBiZyA9ICJ3aGl0ZSIsIHR5cGUgPSAiY2Fpcm8tcG5nIikKZ3JpZC5hcnJhbmdlKHRhYmxlR3JvYihleHRlbnNpdmVTdWIsIHJvd3MgPSBOVUxMKSwgdG9wID0gIkNvbXBhcmlzb24gb2Ygc2YgYW5kIGFyZWFsIE91dHB1dFxuU3BhdGlhbGx5IEV4dGVuc2l2ZSBJbnRlcnBvbGF0aW9uIikKZGV2Lm9mZigpCgojIHByb2R1Y2Ugcm91bmRlZCBpbnRlbnNpdmUgZXN0aW1hdGVzCmludGVuc2l2ZVN1YiA8LSBpbnRlbnNpdmUgJT4lCiAgZmlsdGVyKFdhcmQgPj0gMSAmIFdhcmQgPD0gMTApICU+JQogIG11dGF0ZSgKICAgIHNmX2luID0gcm91bmQoc2ZfaW4sIGRpZ2l0cyA9IDMpLAogICAgYXJlYWxfaW4gPSByb3VuZChhcmVhbF9pbiwgZGlnaXRzID0gMykKICApICU+JQogIHJlbmFtZSgKICAgIGBzZmAgPSBzZl9pbiwKICAgIGBhcmVhbGAgPSBhcmVhbF9pbgogICkKCiMgcHJpbnQgaW50ZW5zaXZlIHRhYmxlCnBuZyhmaWxlbmFtZSA9ICJwYXBlci9pbnRlbnNpdmVUYWJsZS5wbmciLCB3aWR0aCA9IDQ4MCwgaGVpZ2h0ID0gMzAwLCBiZyA9ICJ3aGl0ZSIsIHR5cGUgPSAiY2Fpcm8tcG5nIikKZ3JpZC5hcnJhbmdlKHRhYmxlR3JvYihpbnRlbnNpdmVTdWIsIHJvd3MgPSBOVUxMKSwgdG9wID0gIkNvbXBhcmlzb24gb2Ygc2YgYW5kIGFyZWFsIE91dHB1dFxuU3BhdGlhbGx5IEludGVuc2l2ZSBJbnRlcnBvbGF0aW9uIikKZGV2Lm9mZigpCmBgYAoKIyMjIENvbXBhcmUgUmVzdWx0cwpXZSBjYW4gdmVyaWZ5IHRoYXQgdGhlIGBhcmVhbGAgd29ya2Zsb3cgd2l0aCBgd2VpZ2h0ID0gInRvdGFsImAgbWF0Y2hlcyB0aGUgYHNmYCBleHRlbnNpdmUgb3V0cHV0OgoKYGBge3IgdmVyaWZ5LWV4dGVuc2l2ZX0KZXhwZWN0X2VxdWFsKGV4dGVuc2l2ZSRzZl9leCwgZXh0ZW5zaXZlJGFyZWFsX2V4VCkKYGBgCgpXZSBjYW4gZG8gdGhlIHNhbWUgZm9yIHRoZSBpbnRlbnNpdmUgaW50ZXJwb2xhdGlvbnM6CgpgYGB7ciB2ZXJpZnktaW50ZW5zaXZlfQpleHBlY3RfZXF1YWwoaW50ZW5zaXZlJHNmX2luLCBpbnRlbnNpdmUkYXJlYWxfaW4pCmBgYAoKIyMjIEJlbmNobWFyawpOZXh0LCB3ZSdsbCBiZW5jaG1hcmsgdGhlIGV4dGVuc2l2ZSBlc3RpbWF0aW9uIHRpbWVzOgoKYGBge3IgZXh0ZW5zaXZlLWJlbmNobWFya30KIyBjb21wYXJlIHNwYXRpYWxseSBleHRlbnNpdmUgaW50ZXJwb2xhdGlvbnMKbWljcm9iZW5jaG1hcmsoCiAgYXdfaW50ZXJwb2xhdGUoYXJfc3RsX3dhcmRzLCB0aWQgPSBXQVJELCBzb3VyY2UgPSBhcl9zdGxfcmFjZSwgc2lkID0gR0VPSUQsCiAgICAgICAgICAgICAgICAgd2VpZ2h0ID0gInRvdGFsIiwgb3V0cHV0ID0gInRpYmJsZSIsIGV4dGVuc2l2ZSA9ICJUT1RBTF9FIiksCiAgc3VwcHJlc3NXYXJuaW5ncyhzdF9pbnRlcnBvbGF0ZV9hdyhhcl9zdGxfcmFjZVsiVE9UQUxfRSJdLCBhcl9zdGxfd2FyZHMsIGV4dGVuc2l2ZSA9IFRSVUUpKQopCmBgYAoKV2UnbGwgcmVwZWF0IHRoZSBwcm9jZXNzIGZvciB0aGUgaW50ZW5zaXZlIGVzdGltYXRpb25zOgoKYGBge3IgaW50ZW5zaXZlLWJlbmNobWFya30KIyBjb21wYXJlIHNwYXRpYWxseSBpbnRlbnNpdmUgaW50ZXJwb2xhdGlvbnMKbWljcm9iZW5jaG1hcmsoCiAgYXdfaW50ZXJwb2xhdGUoYXJfc3RsX3dhcmRzLCB0aWQgPSBXQVJELCBzb3VyY2UgPSBhcl9zdGxfYXN0aG1hLCBzaWQgPSBHRU9JRCwKICAgICAgICAgICAgICAgICB3ZWlnaHQgPSAic3VtIiwgb3V0cHV0ID0gInRpYmJsZSIsIGludGVuc2l2ZSA9ICJBU1RITUEiKSwKICBzdXBwcmVzc1dhcm5pbmdzKHN0X2ludGVycG9sYXRlX2F3KGFyX3N0bF9hc3RobWFbIkFTVEhNQSJdLCBhcl9zdGxfd2FyZHMsIGV4dGVuc2l2ZSA9IEZBTFNFKSkKKQpgYGAKCiMjIEdlb21ldHJ5IENvbGxlY3Rpb25zCkZpbmFsbHksIHdlJ2xsIHByb3ZpZGUgYW4gZXhhbXBsZSBvZiBhIG1vcmUgaW50ZW5zaXZlIGVzdGltYXRpb24gcHJvY2VzcyB0aGF0IGFsc28gdHJpZ2dlcnMgdGhlIGdlb21ldHJ5IGNvbGxlY3Rpb24gd29ya2Zsb3csIHdoaWNoIHdpbGwgYWRkIHRvIHRoZSBlc3RpbWF0aW9uIHRpbWUuIFdlIG5lZWQgdG8gZG93bmxvYWQgc2V2ZXJhbCBkYXRhIHNldHMgdXNpbmcgYHRpZ3Jpc2AgYW5kIGB0aWR5Y2Vuc3VzYDoKCmBgYHtyIGRvd25sb2FkLWNlbnN1cywgaW5jbHVkZT1GQUxTRX0KIyBjb3VudHkgcG9wdWxhdGlvbnMKbW9Qb3AgPC0gZ2V0X2FjcyhnZW9ncmFwaHkgPSAiY291bnR5IiwgdmFyaWFibGVzID0gIkIwMTAwM18wMDEiLCBvdXRwdXQgPSAid2lkZSIsIHN0YXRlID0gMjksIGdlb21ldHJ5ID0gVFJVRSkgJT4lCiAgc3RfdHJhbnNmb3JtKGNycyA9IDI2OTE1KSAlPiUKICBzZWxlY3QoR0VPSUQsIEIwMTAwM18wMDFFKSAlPiUKICByZW5hbWUodG90YWxQb3AgPSBCMDEwMDNfMDAxRSkKCiMgYmxvY2sgZ3JvdXAgZ2VvbWV0cnkKbW9CbG9ja0dyb3VwcyA8LSBibG9ja19ncm91cHMoc3RhdGUgPSAyOSwgY2xhc3MgPSAic2YiKSAlPiUKICBzdF90cmFuc2Zvcm0oY3JzID0gMjY5MTUpICU+JQogIHNlbGVjdChHRU9JRCkKYGBgCgpIZXJlIGFyZSB0aGUgc2FtcGxlIHNpemVzIGZvciBib3RoIGRhdGEgc2V0czoKCmBgYHtyIGNlbnN1cy1ufQpucm93KG1vUG9wKQpucm93KG1vQmxvY2tHcm91cHMpCmBgYAoKSGVyZSBpcyB0aGUgYmVuY2htYXJrIGZvciB0aGUgZXN0aW1hdGVzIHByb2R1Y2VkIHdpdGggdGhlc2UgZGF0YToKCmBgYHtyIGJlbmNobWFyay1nZW8tY29sbGVjdGlvbn0KbWljcm9iZW5jaG1hcmsoCiAgYXdfaW50ZXJwb2xhdGUobW9CbG9ja0dyb3VwcywgdGlkID0gR0VPSUQsIHNvdXJjZSA9IG1vUG9wLCBzaWQgPSBHRU9JRCwKICAgICAgICAgICAgICAgICB3ZWlnaHQgPSAic3VtIiwgb3V0cHV0ID0gInRpYmJsZSIsIGludGVuc2l2ZSA9ICJ0b3RhbFBvcCIpCikKYGBgCg==