This is an R Markdown Notebook. When you execute code within the notebook, the results appear beneath the code.
Try executing this chunk by clicking the Run button within the chunk or by placing your cursor inside it and pressing Cmd+Shift+Enter.
install.packages(c("sf","devtools","tidyverse","broom"))
devtools::install_github("tidyverse/ggplot2")
lapply(c("sf","devtools","tidyverse","broom","ggplot2"),library,character.only=TRUE)
setwd("/Users/blossomtang/Documents/40.hass Making Maps/02221-Lab10")
munis <- st_read("gem_2016.geojson",crs = 28992)
munis <- munis %>%
filter(WATER == 'NEE') %>%
select(GM_CODE, GM_NAAM)
provinces <- st_read("provinces.geojson") %>%
st_transform(crs = 28992)
utrecht <- provinces %>%
filter(name=='Utrecht')
munis <- munis %>%
filter(st_intersects(utrecht,st_centroid(munis),sparse=F))
The st_intersects function identifies whether the area of utrecht and the centroid of the selected city in munis intersect. Setting sparse=F returns a list of whether each row intersects or not, while setting it to T would only return the indexes of the rows that do intersect.
commute <- read_csv("commuting.csv") %>%
select(source,sink,weight) %>%
rename(interaction=weight)
Parsed with column specification:
cols(
source = col_integer(),
sink = col_integer(),
count = col_integer(),
weight = col_integer()
)
Now the %in% can match values as they both exist.
commute <- commute %>%
left_join(munis.centroid, by=c("source"="id")) %>%
left_join(munis.centroid, by=c("sink"="id")) %>%
rowwise() %>%
mutate(geometry=st_combine(c(geometry.x,geometry.y)) %>% st_cast("LINESTRING")) %>%
select(-geometry.x, -geometry.y) %>%
st_as_sf(crs=28992)
Error in mutate_impl(.data, dots) :
Evaluation error: no applicable method for 'st_geometry' applied to an object of class "NULL".
This chunk matches the coordinates to the entries in commute, groups them by rows, combines the coordinates into a geometry column, then converts the data frame to a simple features (sf) object, which is a collection of points.

The region where many thick lines intersect could be a big city where people travel to every day for work. Alternatively, it could be a very dense housing area where many people live, and offices are for some reason in the outskirts of Utrecht.
residents <- read_csv("residents.csv") %>%
select(id,weight)
jobs <- read_csv("jobs.csv") %>%
select(id,weight)
#couldn't get st_distance to work on my computer, so I got a distance matrix from a classmate
#dist <- st_distance(x=munis.centroid, y=munis.centroid)
#rownames(dist) <- munis.centroid$id
#colnames(dist) <- munis.centroid$id
#dist <- list(
# source = rownames(dist)[row(dist)] %||% row(dist),
# sink = colnames(dist)[col(dist)] %||% col(dist),
# distance = dist
# )
# dist <- dist %>%
# map_dfc(as.vector) %>%
# mutate(source=as.numeric(source)) %>%
# mutate(sink=as.numeric(sink))
dist <- read.csv("dist.csv")
commute <- commute %>%
left_join(dist) %>%
left_join(residents, by = c('source'='id')) %>%
rename(residents=weight) %>%
left_join(jobs, by=c('sink'='id')) %>%
rename(jobs=weight)
ggplot(commute, aes(interaction, distance)) + geom_point()
ggplot(commute, aes(log(interaction),log(distance))) + geom_point()
lm(data = commute, formula = interaction ~ residents + jobs + distance) %>% summary()
Call:
lm(formula = interaction ~ residents + jobs + distance, data = commute)
Residuals:
Min 1Q Median 3Q Max
-15770 -1150 -309 922 40734
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 2.553e+03 5.241e+02 4.872 1.47e-06 ***
residents 3.234e-02 3.423e-03 9.449 < 2e-16 ***
jobs 9.666e-02 4.960e-03 19.486 < 2e-16 ***
distance -1.965e-01 2.255e-02 -8.713 < 2e-16 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 4632 on 515 degrees of freedom
Multiple R-squared: 0.5032, Adjusted R-squared: 0.5003
F-statistic: 173.9 on 3 and 515 DF, p-value: < 2.2e-16
The R squared value is 0.5003, which means the linear regression only explains about half the variation in data. But each factor has a very small p-value, indicating that they are each important to the model.
summary(model)
Call:
glm(formula = interaction ~ log(residents) + log(jobs) + log(distance),
family = poisson(), data = commute)
Deviance Residuals:
Min 1Q Median 3Q Max
-94.452 -13.305 -7.521 2.780 119.174
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) 3.3571141 0.0211541 158.7 <2e-16 ***
log(residents) 0.8585323 0.0009390 914.3 <2e-16 ***
log(jobs) 0.9836158 0.0006917 1422.1 <2e-16 ***
log(distance) -1.5120231 0.0017421 -867.9 <2e-16 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
(Dispersion parameter for poisson family taken to be 1)
Null deviance: 3474337 on 518 degrees of freedom
Residual deviance: 251357 on 515 degrees of freedom
AIC: 255608
Number of Fisher Scoring iterations: 5
The R^2 value is 0.864, better than the previous linear model. From the summary of the model, we see that each of the factors are still significant as their p-values are very small. Here we are doing a level-log regression, so the coefficients mean that, say, if we increase number of residents by 1%, the interaction would increase by 0.859/100 units.
commute <- commute %>%
mutate(fitted = fitted(model)) %>%
mutate(residual = interaction - fitted) %>%
mutate(residualSign = sign(residual))
commute %>%
mutate(lineWidth = fitted / max(fitted)*10) %>%
ggplot() + geom_sf(aes(size=lineWidth)) +
scale_size_identity()

The line widths are more balanced now, with previously invisible connections becoming more visible.

Assignment
Visualizing all commuting relations

Summary of commuting destinations
commute2 %>%
arrange(desc(count))
Simple feature collection with 390 features and 2 fields
geometry type: MULTILINESTRING
dimension: XY
bbox: xmin: 24537.79 ymin: 309545.2 xmax: 271400.9 ymax: 612030
epsg (SRID): 28992
proj4string: +proj=sterea +lat_0=52.15616055555555 +lon_0=5.38763888888889 +k=0.9999079 +x_0=155000 +y_0=463000 +ellps=bessel +towgs84=565.4171,50.3319,465.5524,-0.398957,0.343988,-1.87740,4.0725 +units=m +no_defs
The municipalities with the most incoming number of commuters are Amsterdam, Rotterdam, and ’s-Gravenhage.
Spatial interaction
#add residents and jobs
commute <- commute %>%
left_join(dist.w) %>%
left_join(residents, by = c('source'='id')) %>%
rename(residents=weight) %>%
left_join(jobs, by=c('sink'='id')) %>%
rename(jobs=weight)
Error in UseMethod("left_join") :
no applicable method for 'left_join' applied to an object of class "c('gg', 'ggplot')"
The R^2 value is 0.183, much lower than the fit for just Utrecht. This could be because there are factors other than residents, jobs, and distance that affect interaction when looking at the scale of a whole country instead of a city. It would take more for people to travel to a different city, maybe to visit family or there could be patterns of tourism or logistics aside from traveling for work. The three factors all have smaller magnitude coefficients than before, explaining less of the interaction variation although they are still significant. However, their signs remain the same, which makes sense - there is more interaction if there are more residents and jobs, but less between places far from each other.

The largest residuals are at a couple of cities on the West side of the Netherlands. There are also a lot of negative residuals around North Holland and the places with high interaction.
#finding top 3 based on fitted values
commute %>%
mutate(fitted = fitted(model)) %>%
group_by(sink) %>%
summarize(sum = sum(fitted)) %>%
left_join(as.data.frame(munis.w.centroid3), by=c("sink"="id")) %>%
arrange(desc(sum))
Simple feature collection with 388 features and 3 fields
Active geometry column: geometry.x
geometry type: GEOMETRY
dimension: XY
bbox: xmin: 24537.79 ymin: 309545.2 xmax: 271400.9 ymax: 607189.8
epsg (SRID): 28992
proj4string: +proj=sterea +lat_0=52.15616055555555 +lon_0=5.38763888888889 +k=0.9999079 +x_0=155000 +y_0=463000 +ellps=bessel +towgs84=565.4171,50.3319,465.5524,-0.398957,0.343988,-1.87740,4.0725 +units=m +no_defs
This is a table of the top three destinations with the highest fitted interaction. When ordered by fitted interaction instead of actual counts, the top three destinations are Rotterdam, Amsterdam, and Utrecht. Maybe the fitting over-estimates the interaction for Rotterdam because it is quite central or has a large population/number of jobs without people actually traveling there.
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKVGhpcyBpcyBhbiBbUiBNYXJrZG93bl0oaHR0cDovL3JtYXJrZG93bi5yc3R1ZGlvLmNvbSkgTm90ZWJvb2suIFdoZW4geW91IGV4ZWN1dGUgY29kZSB3aXRoaW4gdGhlIG5vdGVib29rLCB0aGUgcmVzdWx0cyBhcHBlYXIgYmVuZWF0aCB0aGUgY29kZS4gCgpUcnkgZXhlY3V0aW5nIHRoaXMgY2h1bmsgYnkgY2xpY2tpbmcgdGhlICpSdW4qIGJ1dHRvbiB3aXRoaW4gdGhlIGNodW5rIG9yIGJ5IHBsYWNpbmcgeW91ciBjdXJzb3IgaW5zaWRlIGl0IGFuZCBwcmVzc2luZyAqQ21kK1NoaWZ0K0VudGVyKi4gCgpgYGB7cn0KaW5zdGFsbC5wYWNrYWdlcyhjKCJzZiIsImRldnRvb2xzIiwidGlkeXZlcnNlIiwiYnJvb20iKSkKZGV2dG9vbHM6Omluc3RhbGxfZ2l0aHViKCJ0aWR5dmVyc2UvZ2dwbG90MiIpCmxhcHBseShjKCJzZiIsImRldnRvb2xzIiwidGlkeXZlcnNlIiwiYnJvb20iLCJnZ3Bsb3QyIiksbGlicmFyeSxjaGFyYWN0ZXIub25seT1UUlVFKQoKYGBgCmBgYHtyfQpzZXR3ZCgiL1VzZXJzL2Jsb3Nzb210YW5nL0RvY3VtZW50cy80MC5oYXNzIE1ha2luZyBNYXBzLzAyMjIxLUxhYjEwIikKbXVuaXMgPC0gc3RfcmVhZCgiZ2VtXzIwMTYuZ2VvanNvbiIsY3JzID0gMjg5OTIpCm11bmlzIDwtIG11bmlzICU+JQogIGZpbHRlcihXQVRFUiA9PSAnTkVFJykgJT4lCiAgc2VsZWN0KEdNX0NPREUsIEdNX05BQU0pCgpwcm92aW5jZXMgPC0gc3RfcmVhZCgicHJvdmluY2VzLmdlb2pzb24iKSAlPiUKICBzdF90cmFuc2Zvcm0oY3JzID0gMjg5OTIpCnV0cmVjaHQgPC0gcHJvdmluY2VzICU+JQogIGZpbHRlcihuYW1lPT0nVXRyZWNodCcpCm11bmlzIDwtIG11bmlzICU+JQogIGZpbHRlcihzdF9pbnRlcnNlY3RzKHV0cmVjaHQsc3RfY2VudHJvaWQobXVuaXMpLHNwYXJzZT1GKSkKCmBgYAoKVGhlIHN0X2ludGVyc2VjdHMgZnVuY3Rpb24gaWRlbnRpZmllcyB3aGV0aGVyIHRoZSBhcmVhIG9mIHV0cmVjaHQgYW5kIHRoZSBjZW50cm9pZCBvZiB0aGUgc2VsZWN0ZWQgY2l0eSBpbiBtdW5pcyBpbnRlcnNlY3QuIFNldHRpbmcgc3BhcnNlPUYgcmV0dXJucyBhIGxpc3Qgb2Ygd2hldGhlciBlYWNoIHJvdyBpbnRlcnNlY3RzIG9yIG5vdCwgd2hpbGUgc2V0dGluZyBpdCB0byBUIHdvdWxkIG9ubHkgcmV0dXJuIHRoZSBpbmRleGVzIG9mIHRoZSByb3dzIHRoYXQgZG8gaW50ZXJzZWN0LgoKYGBge3J9CmNvbW11dGUgPC0gcmVhZF9jc3YoImNvbW11dGluZy5jc3YiKSAlPiUKICBzZWxlY3Qoc291cmNlLHNpbmssd2VpZ2h0KSAlPiUKICByZW5hbWUoaW50ZXJhY3Rpb249d2VpZ2h0KQoKI2NvbW11dGUgPC0gY29tbXV0ZSAlPiUKIyAgZmlsdGVyKHNvdXJjZSAlaW4lIG11bmlzJGlkICYgc2luayAlaW4lIG11bmlzJGlkKQojY29tbXV0ZSBoYXMgMCByb3dzIG5vdyBiZWNhdXNlIG11bmlzIGRvZXMgbm90IGhhdmUgYW4gaWQgY29sdW1uCgptdW5pcyA8LSBtdW5pcyAlPiUKICBtdXRhdGUoaWQ9YXMubnVtZXJpYyhzdHJfcmVwbGFjZShHTV9DT0RFLCAiR00iLCIiKSkpCmNvbW11dGUgPC0gY29tbXV0ZSAlPiUKIGZpbHRlcihzb3VyY2UgJWluJSBtdW5pcyRpZCAmIHNpbmsgJWluJSBtdW5pcyRpZCkKYGBgCk5vdyB0aGUgJWluJSBjYW4gbWF0Y2ggdmFsdWVzIGFzIHRoZXkgYm90aCBleGlzdC4KYGBge3J9Cm11bmlzLmNlbnRyb2lkIDwtIHN0X2NlbnRyb2lkKG11bmlzKSAlPiUKICBzZWxlY3QoaWQpCgpjb21tdXRlIDwtIGNvbW11dGUgJT4lCiAgbGVmdF9qb2luKG11bmlzLmNlbnRyb2lkLCBieT1jKCJzb3VyY2UiPSJpZCIpKSAlPiUKICBsZWZ0X2pvaW4obXVuaXMuY2VudHJvaWQsIGJ5PWMoInNpbmsiPSJpZCIpKSAlPiUKICByb3d3aXNlKCkgJT4lCiAgbXV0YXRlKGdlb21ldHJ5PXN0X2NvbWJpbmUoYyhnZW9tZXRyeS54LGdlb21ldHJ5LnkpKSAlPiUgc3RfY2FzdCgiTElORVNUUklORyIpKSAlPiUKICBzZWxlY3QoLWdlb21ldHJ5LngsIC1nZW9tZXRyeS55KSAlPiUKICBzdF9hc19zZihjcnM9Mjg5OTIpCmBgYApUaGlzIGNodW5rIG1hdGNoZXMgdGhlIGNvb3JkaW5hdGVzIHRvIHRoZSBlbnRyaWVzIGluIGNvbW11dGUsIGdyb3VwcyB0aGVtIGJ5IHJvd3MsIGNvbWJpbmVzIHRoZSBjb29yZGluYXRlcyBpbnRvIGEgZ2VvbWV0cnkgY29sdW1uLCB0aGVuIGNvbnZlcnRzIHRoZSBkYXRhIGZyYW1lIHRvIGEgc2ltcGxlIGZlYXR1cmVzIChzZikgb2JqZWN0LCB3aGljaCBpcyBhIGNvbGxlY3Rpb24gb2YgcG9pbnRzLgoKYGBge3J9CmdncGxvdChjb21tdXRlKSArIGdlb21fc2YoKQpnZ3Bsb3QobXVuaXMpICsgZ2VvbV9zZigpICsgZ2VvbV9zZihkYXRhPWNvbW11dGUpCmNvbW11dGUgPC0gY29tbXV0ZSAlPiUKICBmaWx0ZXIoc2luayAhPSBzb3VyY2UpICU+JQogIGZpbHRlcihpbnRlcmFjdGlvbiA+IDIwKSAlPiUKICBtdXRhdGUobGluZVdpZHRoPWFzLm51bWVyaWMoaW50ZXJhY3Rpb24pL21heChhcy5udW1lcmljKGludGVyYWN0aW9uKSkqMTApCmdncGxvdChjb21tdXRlKSArIGdlb21fc2YoYWVzKHNpemU9bGluZVdpZHRoKSkgKyBzY2FsZV9zaXplX2lkZW50aXR5KCkKYGBgClRoZSByZWdpb24gd2hlcmUgbWFueSB0aGljayBsaW5lcyBpbnRlcnNlY3QgY291bGQgYmUgYSBiaWcgY2l0eSB3aGVyZSBwZW9wbGUgdHJhdmVsIHRvIGV2ZXJ5IGRheSBmb3Igd29yay4gQWx0ZXJuYXRpdmVseSwgaXQgY291bGQgYmUgYSB2ZXJ5IGRlbnNlIGhvdXNpbmcgYXJlYSB3aGVyZSBtYW55IHBlb3BsZSBsaXZlLCBhbmQgb2ZmaWNlcyBhcmUgZm9yIHNvbWUgcmVhc29uIGluIHRoZSBvdXRza2lydHMgb2YgVXRyZWNodC4KCmBgYHtyfQpyZXNpZGVudHMgPC0gcmVhZF9jc3YoInJlc2lkZW50cy5jc3YiKSAlPiUKICBzZWxlY3QoaWQsd2VpZ2h0KSAKam9icyA8LSByZWFkX2Nzdigiam9icy5jc3YiKSAlPiUKICBzZWxlY3QoaWQsd2VpZ2h0KQojY291bGRuJ3QgZ2V0IHN0X2Rpc3RhbmNlIHRvIHdvcmsgb24gbXkgY29tcHV0ZXIsIHNvIEkgZ290IGEgZGlzdGFuY2UgbWF0cml4IGZyb20gYSBjbGFzc21hdGUKI2Rpc3QgPC0gc3RfZGlzdGFuY2UoeD1tdW5pcy5jZW50cm9pZCwgeT1tdW5pcy5jZW50cm9pZCkKCiNyb3duYW1lcyhkaXN0KSA8LSBtdW5pcy5jZW50cm9pZCRpZAojY29sbmFtZXMoZGlzdCkgPC0gbXVuaXMuY2VudHJvaWQkaWQKI2Rpc3QgPC0gbGlzdCgKIyAgIHNvdXJjZSA9IHJvd25hbWVzKGRpc3QpW3JvdyhkaXN0KV0gJXx8JSByb3coZGlzdCksCiMgICBzaW5rID0gY29sbmFtZXMoZGlzdClbY29sKGRpc3QpXSAlfHwlIGNvbChkaXN0KSwKIyAgIGRpc3RhbmNlID0gZGlzdAojICkgCiMgZGlzdCA8LSBkaXN0ICU+JQojICAgbWFwX2RmYyhhcy52ZWN0b3IpICU+JQojICAgbXV0YXRlKHNvdXJjZT1hcy5udW1lcmljKHNvdXJjZSkpICU+JQojICAgbXV0YXRlKHNpbms9YXMubnVtZXJpYyhzaW5rKSkKZGlzdCA8LSByZWFkLmNzdigiZGlzdC5jc3YiKQoKY29tbXV0ZSA8LSBjb21tdXRlICU+JQogIGxlZnRfam9pbihkaXN0KSAlPiUKICBsZWZ0X2pvaW4ocmVzaWRlbnRzLCBieSA9IGMoJ3NvdXJjZSc9J2lkJykpICU+JQogIHJlbmFtZShyZXNpZGVudHM9d2VpZ2h0KSAlPiUKICBsZWZ0X2pvaW4oam9icywgYnk9Yygnc2luayc9J2lkJykpICU+JQogIHJlbmFtZShqb2JzPXdlaWdodCkKCmdncGxvdChjb21tdXRlLCBhZXMoaW50ZXJhY3Rpb24sIGRpc3RhbmNlKSkgKyBnZW9tX3BvaW50KCkKZ2dwbG90KGNvbW11dGUsIGFlcyhsb2coaW50ZXJhY3Rpb24pLGxvZyhkaXN0YW5jZSkpKSArIGdlb21fcG9pbnQoKQoKYGBgCmBgYHtyfQpsbShkYXRhID0gY29tbXV0ZSwgZm9ybXVsYSA9IGludGVyYWN0aW9uIH4gcmVzaWRlbnRzICsgam9icyArIGRpc3RhbmNlKSAlPiUgc3VtbWFyeSgpCmBgYApUaGUgUiBzcXVhcmVkIHZhbHVlIGlzIDAuNTAwMywgd2hpY2ggbWVhbnMgdGhlIGxpbmVhciByZWdyZXNzaW9uIG9ubHkgZXhwbGFpbnMgYWJvdXQgaGFsZiB0aGUgdmFyaWF0aW9uIGluIGRhdGEuIEJ1dCBlYWNoIGZhY3RvciBoYXMgYSB2ZXJ5IHNtYWxsIHAtdmFsdWUsIGluZGljYXRpbmcgdGhhdCB0aGV5IGFyZSBlYWNoIGltcG9ydGFudCB0byB0aGUgbW9kZWwuCgpgYGB7cn0KZ2dwbG90KGNvbW11dGUsYWVzKGludGVyYWN0aW9uKSkgKyBnZW9tX2hpc3RvZ3JhbSgpCgptb2RlbCA8LSBnbG0oZGF0YSA9IGNvbW11dGUsIGZvcm11bGEgPSBpbnRlcmFjdGlvbiB+IGxvZyhyZXNpZGVudHMpICsgbG9nKGpvYnMpICsgbG9nKGRpc3RhbmNlKSwgZmFtaWx5ID0gcG9pc3NvbigpKQoKcjIgPC0gZnVuY3Rpb24oZW1waXJpY2FsLCBmaXR0ZWQpIHsKICByZXR1cm4oY29yKGVtcGlyaWNhbCwgZml0dGVkKV4yKQp9CnIyKGNvbW11dGUkaW50ZXJhY3Rpb24sIGZpdHRlZChtb2RlbCkpCnN1bW1hcnkobW9kZWwpCgpgYGAKVGhlIFJeMiB2YWx1ZSBpcyAwLjg2NCwgYmV0dGVyIHRoYW4gdGhlIHByZXZpb3VzIGxpbmVhciBtb2RlbC4gRnJvbSB0aGUgc3VtbWFyeSBvZiB0aGUgbW9kZWwsIHdlIHNlZSB0aGF0IGVhY2ggb2YgdGhlIGZhY3RvcnMgYXJlIHN0aWxsIHNpZ25pZmljYW50IGFzIHRoZWlyIHAtdmFsdWVzIGFyZSB2ZXJ5IHNtYWxsLiBIZXJlIHdlIGFyZSBkb2luZyBhIGxldmVsLWxvZyByZWdyZXNzaW9uLCBzbyB0aGUgY29lZmZpY2llbnRzIG1lYW4gdGhhdCwgc2F5LCBpZiB3ZSBpbmNyZWFzZSBudW1iZXIgb2YgcmVzaWRlbnRzIGJ5IDElLCB0aGUgaW50ZXJhY3Rpb24gd291bGQgaW5jcmVhc2UgYnkgMC44NTkvMTAwIHVuaXRzLgoKYGBge3J9CmNvbW11dGUgPC0gY29tbXV0ZSAlPiUKICBtdXRhdGUoZml0dGVkID0gZml0dGVkKG1vZGVsKSkgJT4lCiAgbXV0YXRlKHJlc2lkdWFsID0gaW50ZXJhY3Rpb24gLSBmaXR0ZWQpICU+JQogIG11dGF0ZShyZXNpZHVhbFNpZ24gPSBzaWduKHJlc2lkdWFsKSkKCmNvbW11dGUgJT4lCiAgbXV0YXRlKGxpbmVXaWR0aCA9IGZpdHRlZCAvIG1heChmaXR0ZWQpKjEwKSAlPiUKICBnZ3Bsb3QoKSArIGdlb21fc2YoYWVzKHNpemU9bGluZVdpZHRoKSkgKwogIHNjYWxlX3NpemVfaWRlbnRpdHkoKQpgYGAKVGhlIGxpbmUgd2lkdGhzIGFyZSBtb3JlIGJhbGFuY2VkIG5vdywgd2l0aCBwcmV2aW91c2x5IGludmlzaWJsZSBjb25uZWN0aW9ucyBiZWNvbWluZyBtb3JlIHZpc2libGUuCmBgYHtyfQpjb21tdXRlICU+JQogIG11dGF0ZShsaW5lV2lkdGggPSBhYnMocmVzaWR1YWwpL21heChyZXNpZHVhbCkqMTApICU+JQogIGdncGxvdCgpICsgZ2VvbV9zZihhZXMoY29sb3IgPSBmYWN0b3IocmVzaWR1YWxTaWduKSxzaXplPWxpbmVXaWR0aCkpICsgc2NhbGVfc2l6ZV9pZGVudGl0eSgpCmBgYAoKPGI+QXNzaWdubWVudDwvYj4KClZpc3VhbGl6aW5nIGFsbCBjb21tdXRpbmcgcmVsYXRpb25zCmBgYHtyfQptdW5pcy53IDwtIHN0X3JlYWQoImdlbV8yMDE2Lmdlb2pzb24iLGNycyA9IDI4OTkyKQptdW5pcy53IDwtIG11bmlzLncgJT4lCiAgZmlsdGVyKFdBVEVSID09ICdORUUnKSAlPiUKICBzZWxlY3QoR01fQ09ERSwgR01fTkFBTSkKCmNvbW11dGUgPC0gcmVhZF9jc3YoImNvbW11dGluZy5jc3YiKSAlPiUKICBzZWxlY3Qoc291cmNlLHNpbmssd2VpZ2h0LGNvdW50KSAlPiUKICByZW5hbWUoaW50ZXJhY3Rpb249d2VpZ2h0KSAlPiUKICBmaWx0ZXIoY291bnQgPiA3NTApCgptdW5pcy53IDwtIG11bmlzLncgJT4lCiAgbXV0YXRlKGlkPWFzLm51bWVyaWMoc3RyX3JlcGxhY2UoR01fQ09ERSwgIkdNIiwiIikpKQpjb21tdXRlIDwtIGNvbW11dGUgJT4lCiBmaWx0ZXIoc291cmNlICVpbiUgbXVuaXMudyRpZCAmIHNpbmsgJWluJSBtdW5pcy53JGlkKQoKbXVuaXMudy5jZW50cm9pZCA8LSBzdF9jZW50cm9pZChtdW5pcy53KSAlPiUKICBzZWxlY3QoaWQpCgpjb21tdXRlIDwtIGNvbW11dGUgJT4lCiAgbGVmdF9qb2luKG11bmlzLncuY2VudHJvaWQsIGJ5PWMoInNvdXJjZSI9ImlkIikpICU+JQogIGxlZnRfam9pbihtdW5pcy53LmNlbnRyb2lkLCBieT1jKCJzaW5rIj0iaWQiKSkgJT4lCiAgcm93d2lzZSgpICU+JQogIG11dGF0ZShnZW9tZXRyeT1zdF9jb21iaW5lKGMoZ2VvbWV0cnkueCxnZW9tZXRyeS55KSkgJT4lIHN0X2Nhc3QoIkxJTkVTVFJJTkciKSkgJT4lCiAgc2VsZWN0KC1nZW9tZXRyeS54LCAtZ2VvbWV0cnkueSkgJT4lCiAgc3RfYXNfc2YoY3JzPTI4OTkyKQoKY29tbXV0ZSA8LSBjb21tdXRlICU+JQogIGZpbHRlcihzaW5rICE9IHNvdXJjZSkgJT4lCiAgZmlsdGVyKGludGVyYWN0aW9uID4gMjApICU+JQogIG11dGF0ZShsaW5lV2lkdGg9YXMubnVtZXJpYyhpbnRlcmFjdGlvbikvbWF4KGFzLm51bWVyaWMoaW50ZXJhY3Rpb24pKSoxMCkgCmdncGxvdChtdW5pcy53KSArIGdlb21fc2YoKSArIGdlb21fc2YoZGF0YT1jb21tdXRlLGFlcyhzaXplPWxpbmVXaWR0aCkpICsgc2NhbGVfc2l6ZV9pZGVudGl0eSgpCgpgYGAKClN1bW1hcnkgb2YgY29tbXV0aW5nIGRlc3RpbmF0aW9ucwpgYGB7cn0KCm11bmlzLncgPC0gc3RfcmVhZCgiZ2VtXzIwMTYuZ2VvanNvbiIsY3JzID0gMjg5OTIpCm11bmlzLncgPC0gbXVuaXMudyAlPiUKICBmaWx0ZXIoV0FURVIgPT0gJ05FRScpICU+JQogIHNlbGVjdChHTV9DT0RFLCBHTV9OQUFNKQoKY29tbXV0ZTIgPC0gcmVhZF9jc3YoImNvbW11dGluZy5jc3YiKSAlPiUKICBzZWxlY3Qoc291cmNlLHNpbmssd2VpZ2h0LGNvdW50KSAlPiUKICByZW5hbWUoaW50ZXJhY3Rpb249d2VpZ2h0KQoKbXVuaXMudyA8LSBtdW5pcy53ICU+JQogIG11dGF0ZShpZD1hcy5udW1lcmljKHN0cl9yZXBsYWNlKEdNX0NPREUsICJHTSIsIiIpKSkKY29tbXV0ZSA8LSBjb21tdXRlICU+JQogZmlsdGVyKHNvdXJjZSAlaW4lIG11bmlzLnckaWQgJiBzaW5rICVpbiUgbXVuaXMudyRpZCkKCm11bmlzLncuY2VudHJvaWQyIDwtIHN0X2NlbnRyb2lkKG11bmlzLncpICU+JQogIHNlbGVjdChpZCxHTV9OQUFNKQoKY29tbXV0ZTIgPC0gY29tbXV0ZTIgJT4lCiAgbGVmdF9qb2luKG11bmlzLncuY2VudHJvaWQyLCBieT1jKCJzb3VyY2UiPSJpZCIpKSAlPiUKICBsZWZ0X2pvaW4obXVuaXMudy5jZW50cm9pZDIsIGJ5PWMoInNpbmsiPSJpZCIpKSAlPiUKICByb3d3aXNlKCkgJT4lCiAgbXV0YXRlKGdlb21ldHJ5PXN0X2NvbWJpbmUoYyhnZW9tZXRyeS54LGdlb21ldHJ5LnkpKSAlPiUgc3RfY2FzdCgiTElORVNUUklORyIpKSAlPiUKICBzZWxlY3QoLWdlb21ldHJ5LngsIC1nZW9tZXRyeS55KSAlPiUKICBzdF9hc19zZihjcnM9Mjg5OTIpCgpjb21tdXRlMiA8LSBjb21tdXRlMiAlPiUKICBncm91cF9ieShHTV9OQUFNLnkpICU+JQogIHN1bW1hcml6ZShjb3VudCA9IHN1bShjb3VudCkpCmluc3RhbGwucGFja2FnZXMoImRwbHlyIikKbGlicmFyeShkcGx5cikKY29tbXV0ZTIgJT4lCiAgYXJyYW5nZShkZXNjKGNvdW50KSkKCgoKCmBgYApUaGUgbXVuaWNpcGFsaXRpZXMgd2l0aCB0aGUgbW9zdCBpbmNvbWluZyBudW1iZXIgb2YgY29tbXV0ZXJzIGFyZSBBbXN0ZXJkYW0sIFJvdHRlcmRhbSwgYW5kICdzLUdyYXZlbmhhZ2UuCgpTcGF0aWFsIGludGVyYWN0aW9uCmBgYHtyfQojZGlzdCA8LSBzdF9kaXN0YW5jZSh4PW11bmlzLmNlbnRyb2lkLncsIHk9bXVuaXMuY2VudHJvaWQudykKCiNkaXN0YW5jZSBtYXRyaXgKIyBkaXN0MiA8LSByZWFkLmNzdigiZGlzdG9yaWcuY3N2IikKIyAKIyByb3duYW1lcyhkaXN0MikgPC0gbXVuaXMudy5jZW50cm9pZCRpZAojIGNvbG5hbWVzKGRpc3QyKSA8LSBtdW5pcy53LmNlbnRyb2lkJGlkCiMgZGlzdDIgPC0gbGlzdCgKIyAgIHNvdXJjZSA9IHJvd25hbWVzKGRpc3QyKVtyb3coZGlzdDIpXSAlfHwlIHJvdyhkaXN0MiksCiMgICBzaW5rID0gY29sbmFtZXMoZGlzdDIpW2NvbChkaXN0MildICV8fCUgY29sKGRpc3QyKSwKIyAgIGRpc3RhbmNlID0gZGlzdDIKIyApIAojIGRpc3QyICU+JQojICAgbWFwX2RmYyhhcy52ZWN0b3IpICU+JQojICAgbXV0YXRlKHNvdXJjZT1hcy5udW1lcmljKHNvdXJjZSkpICU+JQojICAgbXV0YXRlKHNpbms9YXMubnVtZXJpYyhzaW5rKSkKZGlzdC53IDwtIHJlYWQuY3N2KCJkaXN0Y29vbC5jc3YiKQoKCiNhZGQgcmVzaWRlbnRzIGFuZCBqb2JzCmNvbW11dGUgPC0gY29tbXV0ZSAlPiUKICBsZWZ0X2pvaW4oZGlzdC53KSAlPiUKICBsZWZ0X2pvaW4ocmVzaWRlbnRzLCBieSA9IGMoJ3NvdXJjZSc9J2lkJykpICU+JQogIHJlbmFtZShyZXNpZGVudHM9d2VpZ2h0KSAlPiUKICBsZWZ0X2pvaW4oam9icywgYnk9Yygnc2luayc9J2lkJykpICU+JQogIHJlbmFtZShqb2JzPXdlaWdodCkKCm1vZGVsIDwtIGdsbShkYXRhID0gY29tbXV0ZSwgZm9ybXVsYSA9IGludGVyYWN0aW9uIH4gbG9nKHJlc2lkZW50cykgKyBsb2coam9icykgKyBsb2coZGlzdGFuY2UpLCBmYW1pbHkgPSBwb2lzc29uKCkpCgpyMihjb21tdXRlJGludGVyYWN0aW9uLCBmaXR0ZWQobW9kZWwpKQpzdW1tYXJ5KG1vZGVsKQpgYGAKVGhlIFJeMiB2YWx1ZSBpcyAwLjE4MywgbXVjaCBsb3dlciB0aGFuIHRoZSBmaXQgZm9yIGp1c3QgVXRyZWNodC4gVGhpcyBjb3VsZCBiZSBiZWNhdXNlIHRoZXJlIGFyZSBmYWN0b3JzIG90aGVyIHRoYW4gcmVzaWRlbnRzLCBqb2JzLCBhbmQgZGlzdGFuY2UgdGhhdCBhZmZlY3QgaW50ZXJhY3Rpb24gd2hlbiBsb29raW5nIGF0IHRoZSBzY2FsZSBvZiBhIHdob2xlIGNvdW50cnkgaW5zdGVhZCBvZiBhIGNpdHkuIEl0IHdvdWxkIHRha2UgbW9yZSBmb3IgcGVvcGxlIHRvIHRyYXZlbCB0byBhIGRpZmZlcmVudCBjaXR5LCBtYXliZSB0byB2aXNpdCBmYW1pbHkgb3IgdGhlcmUgY291bGQgYmUgcGF0dGVybnMgb2YgdG91cmlzbSBvciBsb2dpc3RpY3MgYXNpZGUgZnJvbSB0cmF2ZWxpbmcgZm9yIHdvcmsuIFRoZSB0aHJlZSBmYWN0b3JzIGFsbCBoYXZlIHNtYWxsZXIgbWFnbml0dWRlIGNvZWZmaWNpZW50cyB0aGFuIGJlZm9yZSwgZXhwbGFpbmluZyBsZXNzIG9mIHRoZSBpbnRlcmFjdGlvbiB2YXJpYXRpb24gYWx0aG91Z2ggdGhleSBhcmUgc3RpbGwgc2lnbmlmaWNhbnQuIEhvd2V2ZXIsIHRoZWlyIHNpZ25zIHJlbWFpbiB0aGUgc2FtZSwgd2hpY2ggbWFrZXMgc2Vuc2UgLSB0aGVyZSBpcyBtb3JlIGludGVyYWN0aW9uIGlmIHRoZXJlIGFyZSBtb3JlIHJlc2lkZW50cyBhbmQgam9icywgYnV0IGxlc3MgYmV0d2VlbiBwbGFjZXMgZmFyIGZyb20gZWFjaCBvdGhlci4KCmBgYHtyfQpjb21tdXRlICU+JQogIG11dGF0ZShmaXR0ZWQgPSBmaXR0ZWQobW9kZWwpKSAlPiUKICBtdXRhdGUocmVzaWR1YWwgPSBpbnRlcmFjdGlvbiAtIGZpdHRlZCkgJT4lCiAgbXV0YXRlKHJlc2lkdWFsU2lnbiA9IHNpZ24ocmVzaWR1YWwpKSAlPiUKICBtdXRhdGUobGluZVdpZHRoID0gYWJzKHJlc2lkdWFsKS9tYXgocmVzaWR1YWwpKjUpICU+JSAgCiAgZ2dwbG90KCkgKyBnZW9tX3NmKGFlcyhjb2xvciA9IGZhY3RvcihyZXNpZHVhbFNpZ24pLHNpemU9bGluZVdpZHRoKSkgKwogIHNjYWxlX3NpemVfaWRlbnRpdHkoKQoKYGBgCgpUaGUgbGFyZ2VzdCByZXNpZHVhbHMgYXJlIGF0IGEgY291cGxlIG9mIGNpdGllcyBvbiB0aGUgV2VzdCBzaWRlIG9mIHRoZSBOZXRoZXJsYW5kcy4gVGhlcmUgYXJlIGFsc28gYSBsb3Qgb2YgbmVnYXRpdmUgcmVzaWR1YWxzIGFyb3VuZCBOb3J0aCBIb2xsYW5kIGFuZCB0aGUgcGxhY2VzIHdpdGggaGlnaCBpbnRlcmFjdGlvbi4KCmBgYHtyfQptdW5pcy53LmNlbnRyb2lkMyA8LSBzdF9jZW50cm9pZChtdW5pcy53KSAlPiUKICBzZWxlY3QoaWQsR01fTkFBTSkKI2ZpbmRpbmcgdG9wIDMgYmFzZWQgb24gZml0dGVkIHZhbHVlcwpjb21tdXRlICU+JQogIG11dGF0ZShmaXR0ZWQgPSBmaXR0ZWQobW9kZWwpKSAlPiUKICBncm91cF9ieShzaW5rKSAlPiUKICBzdW1tYXJpemUoc3VtID0gc3VtKGZpdHRlZCkpICU+JQogIGxlZnRfam9pbihhcy5kYXRhLmZyYW1lKG11bmlzLncuY2VudHJvaWQzKSwgYnk9Yygic2luayI9ImlkIikpICU+JQogIGFycmFuZ2UoZGVzYyhzdW0pKQoKYGBgCgpUaGlzIGlzIGEgdGFibGUgb2YgdGhlIHRvcCB0aHJlZSBkZXN0aW5hdGlvbnMgd2l0aCB0aGUgaGlnaGVzdCBmaXR0ZWQgaW50ZXJhY3Rpb24uIFdoZW4gb3JkZXJlZCBieSBmaXR0ZWQgaW50ZXJhY3Rpb24gaW5zdGVhZCBvZiBhY3R1YWwgY291bnRzLCB0aGUgdG9wIHRocmVlIGRlc3RpbmF0aW9ucyBhcmUgUm90dGVyZGFtLCBBbXN0ZXJkYW0sIGFuZCBVdHJlY2h0LiBNYXliZSB0aGUgZml0dGluZyBvdmVyLWVzdGltYXRlcyB0aGUgaW50ZXJhY3Rpb24gZm9yIFJvdHRlcmRhbSBiZWNhdXNlIGl0IGlzIHF1aXRlIGNlbnRyYWwgb3IgaGFzIGEgbGFyZ2UgcG9wdWxhdGlvbi9udW1iZXIgb2Ygam9icyB3aXRob3V0IHBlb3BsZSBhY3R1YWxseSB0cmF2ZWxpbmcgdGhlcmUuCgo=