Last week, we started talking about spatial operations. This week, we will work on geometry operations: these are spatial operations that require us to transform the geometry of our data. As you’ll see, many of these operations perform similar tasks as the functions we learned last week. Topic 5 and topic 6 are intended to help you build your toolkit of spatial operations; next class, we will practice those skills.

#load in packages
library(sf)     
library(dplyr)   
library(spData) 
library(urbnmapr)
library(ggplot2)
#Load in our rivers data
setwd("~/Binghamton/geog380/rivers")
Warning: The working directory was changed to C:/Users/mhaller/Documents/Binghamton/geog380/rivers inside a notebook chunk. The working directory will be reset when the chunk is finished running. Use the knitr root.dir option in the setup chunk to change the working directory for notebook chunks.

#That map is pretty hard to see - let's focus on Broome county
broome <- counties %>% filter(county_name == "Broome County")
broome_hydro <- river_shape[broome,]

ggplot() +
  geom_sf(data = broome,
    mapping = aes(), color = "lightgray")+
  geom_sf(data = broome_hydro,
          mapping = aes(), color = "blue")+
  theme_minimal()

Our first geometry operation involves simplification - sometimes, we won’t need a large degree of geographic detail in order to effectively convey spatial information. Simplified map layers may be easier to visualize and more efficient to work with than larger, more complex shape files.

#Let's simplify those lines!

river_simp = st_simplify(broome_hydro, dTolerance = 10000)

ggplot() +
  geom_sf(data = broome,
    mapping = aes(), color = "lightgray")+
  geom_sf(data = river_simp,
          mapping = aes(), color = "blue")+
  theme_minimal()

Now, let’s compare the two!


a <- ggplot() +
  geom_sf(data = broome,
    mapping = aes(), color = "lightgray")+
  geom_sf(data = broome_hydro,
          mapping = aes(), color = "blue")+
  theme_minimal()

b <- ggplot() +
  geom_sf(data = broome,
    mapping = aes(), color = "lightgray")+
  geom_sf(data = river_simp,
          mapping = aes(), color = "blue")+
  theme_minimal()

library(cowplot)

plot_grid(a, b)

Last week, we also learned how to find the centroid of a spatial unit (e.g. polygon) using st_centroid(). One thing to note is that the most central point on a polygon doesn’t always fall within that polygon - here we’ll learn another function that we can use to ensure that our centroids are within the polygons.


#Create centroids
points <- st_point_on_surface(counties)
Warning: st_point_on_surface assumes attributes are constant over geometries of x
 ggplot() +
  geom_sf(data = counties,
    mapping = aes(), color = "lightgray")+
  geom_sf(data = points,
          mapping = aes(), color = "blue")+
  theme_minimal()

NA
NA

This is what a centroid actually looks like! Again, these become most useful for calculating distances.

Let’s compare the two methods:


centroids <- st_centroid(counties)
Warning: st_centroid assumes attributes are constant over geometries of x
ggplot() +
  geom_sf(data = counties,
    mapping = aes(), color = "lightgray")+
  geom_sf(data = points,
          mapping = aes(color = "Point on Surface"))+
  geom_sf(data = centroids, mapping = aes(color = "Centroids"))+
  theme_minimal()+
  scale_color_manual(labels = c("Point on Surface", "Centroids"),
                     values = c("blue", "red"))+
  labs(color = "Point Type")

Next, we’ll move on to buffers! I’ll show you what it is, and then we’ll talk about the ways that you might use a buffer. Buffering creates a new polygon that is within a certain distance of the original, and it looks like this:

river_buff_500 = st_buffer(broome_hydro, dist = 500)


ggplot() +
  geom_sf(data = broome,
    mapping = aes(), color = "lightgray")+
    geom_sf(data = river_buff_500,
          mapping = aes(), color = "yellow")+
  geom_sf(data = broome_hydro,
          mapping = aes(), color = "blue")+
  theme_minimal()

How or why would you use this? Let’s say I am trying to figure out the location for a new building. I don’t want it to be too close to any rivers, or flooding would be a risk - I can use a buffer to visualize locations that are a certain distance (e.g. 1 km) away.

Next, we’ll move on to spatial clipping.

With spatial clipping, I can create a new map layer with its own geometry based on the intersection of two existing layers. In order to technically use spatial clipping, we need somewhat complex geometry types (e.g. lines and polygons - points technically don’t work here). In this line example, the road lines will be cut off to only retain the road segments that intersected with rivers.

What makes this a geometry operation? I’m not just selecting features based on the intersection of two spatial layers - I am creating a new object with its own unique geometry. That is technically what sets geometry operations apart from other kinds of spatial operations (don’t worry though, I won’t quiz you on that).

So, this is helpful, but what if I wanted the actual points where the bridges are located? This is not technically clipping, but we can do that, too!

Finally, we’ll look at geometry unions! This will typically involve aggregating/summarising spatial information at one level (e.g. the county level) up to a higher scale (e.g. the regional level). For example, using our NYS data:

Resources

Lovelace, R., Nowosad, J., Muenchow. J. (2019). Geocomputation with R. Retrieved from: https://geocompr.robinlovelace.net/.

New York State (2022). New York State Statewide Covid-19 Testing. [Data Set]. Retreived from: https://health.data.ny.gov/Health/New-York-State-Statewide-COVID-19-Testing/xdss-u53e.

NYS GIS Clearinghouse (2022). NYS Streets. [Data Set]. Retrieved from: http://gis.ny.gov/gisdata/.

NYS GIS Clearinghouse (2022). NYS Hydrography. [Data Set]. Retrieved from: http://gis.ny.gov/gisdata/.

LS0tDQp0aXRsZTogIkdlb2cgMzgwQSBUb3BpYyA2OiBHZW9tZXRyeSBPcGVyYXRpb25zIg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCkxhc3Qgd2Vlaywgd2Ugc3RhcnRlZCB0YWxraW5nIGFib3V0IHNwYXRpYWwgb3BlcmF0aW9ucy4gVGhpcyB3ZWVrLCB3ZSB3aWxsIHdvcmsgb24gZ2VvbWV0cnkgb3BlcmF0aW9uczogdGhlc2UgYXJlIHNwYXRpYWwgb3BlcmF0aW9ucyB0aGF0IHJlcXVpcmUgdXMgdG8gdHJhbnNmb3JtIHRoZSBnZW9tZXRyeSBvZiBvdXIgZGF0YS4gQXMgeW91J2xsIHNlZSwgbWFueSBvZiB0aGVzZSBvcGVyYXRpb25zIHBlcmZvcm0gc2ltaWxhciB0YXNrcyBhcyB0aGUgZnVuY3Rpb25zIHdlIGxlYXJuZWQgbGFzdCB3ZWVrLiBUb3BpYyA1IGFuZCB0b3BpYyA2IGFyZSBpbnRlbmRlZCB0byBoZWxwIHlvdSBidWlsZCB5b3VyIHRvb2xraXQgb2Ygc3BhdGlhbCBvcGVyYXRpb25zOyBuZXh0IGNsYXNzLCB3ZSB3aWxsIHByYWN0aWNlIHRob3NlIHNraWxscy4gDQoNCg0KYGBge3J9DQojbG9hZCBpbiBwYWNrYWdlcw0KbGlicmFyeShzZikgICAgIA0KbGlicmFyeShkcGx5cikgICANCmxpYnJhcnkoc3BEYXRhKSANCmxpYnJhcnkodXJibm1hcHIpDQpsaWJyYXJ5KGdncGxvdDIpDQpgYGANCg0KYGBge3J9DQojTG9hZCBpbiBvdXIgcml2ZXJzIGRhdGENCnNldHdkKCJ+L0JpbmdoYW10b24vZ2VvZzM4MC9yaXZlcnMiKQ0Kcml2ZXJfc2hhcGUgPC0gc3RfcmVhZCgiTGluZWFySHlkcm9ncmFwaHkuc2hwIikNCg0Kcml2ZXJfc2hhcGUgPC0gcml2ZXJfc2hhcGUgJT4lIHN0X3RyYW5zZm9ybSgiRVBTRzozMjExNiIpDQpgYGANCmBgYHtyfQ0KI01hcCBpdCENCg0KI2xvYWQgaW4gTllTIGNvdW50eSBzaGFwZSBmaWxlIGFuZCBzZXQgY3JzDQpjb3VudGllcyA8LSBnZXRfdXJibl9tYXAoImNvdW50aWVzIiwgc2YgPSBUUlVFKQ0KDQojZmlsdGVyIHRoZSBkYXRhIHRvIGdldCBqdXN0IE5ZUw0KY291bnRpZXMgPC0gY291bnRpZXMgJT4lIA0KICBmaWx0ZXIoc3RhdGVfYWJidiA9PSAiTlkiKSAlPiUgDQogIHN0X3RyYW5zZm9ybSgiRVBTRzozMjExNiIpDQoNCiNMZXQncyBtYXAgdGhlbSBub3chDQpnZ3Bsb3QoKSArDQogIGdlb21fc2YoZGF0YSA9IGNvdW50aWVzLA0KICAgIG1hcHBpbmcgPSBhZXMoKSwgY29sb3IgPSAibGlnaHRncmF5IikrDQogIGdlb21fc2YoZGF0YSA9IHJpdmVyX3NoYXBlLA0KICAgICAgICAgIG1hcHBpbmcgPSBhZXMoKSwgY29sb3IgPSAiYmx1ZSIpKw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KDQpgYGB7cn0NCiNUaGF0IG1hcCBpcyBwcmV0dHkgaGFyZCB0byBzZWUgLSBsZXQncyBmb2N1cyBvbiBCcm9vbWUgY291bnR5DQpicm9vbWUgPC0gY291bnRpZXMgJT4lIGZpbHRlcihjb3VudHlfbmFtZSA9PSAiQnJvb21lIENvdW50eSIpDQpicm9vbWVfaHlkcm8gPC0gcml2ZXJfc2hhcGVbYnJvb21lLF0NCg0KZ2dwbG90KCkgKw0KICBnZW9tX3NmKGRhdGEgPSBicm9vbWUsDQogICAgbWFwcGluZyA9IGFlcygpLCBjb2xvciA9ICJsaWdodGdyYXkiKSsNCiAgZ2VvbV9zZihkYXRhID0gYnJvb21lX2h5ZHJvLA0KICAgICAgICAgIG1hcHBpbmcgPSBhZXMoKSwgY29sb3IgPSAiYmx1ZSIpKw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KDQpPdXIgZmlyc3QgZ2VvbWV0cnkgb3BlcmF0aW9uIGludm9sdmVzIHNpbXBsaWZpY2F0aW9uIC0gc29tZXRpbWVzLCB3ZSB3b24ndCBuZWVkIGEgbGFyZ2UgZGVncmVlIG9mIGdlb2dyYXBoaWMgZGV0YWlsIGluIG9yZGVyIHRvIGVmZmVjdGl2ZWx5IGNvbnZleSBzcGF0aWFsIGluZm9ybWF0aW9uLiBTaW1wbGlmaWVkIG1hcCBsYXllcnMgbWF5IGJlIGVhc2llciB0byB2aXN1YWxpemUgYW5kIG1vcmUgZWZmaWNpZW50IHRvIHdvcmsgd2l0aCB0aGFuIGxhcmdlciwgbW9yZSBjb21wbGV4IHNoYXBlIGZpbGVzLiANCmBgYHtyfQ0KI0xldCdzIHNpbXBsaWZ5IHRob3NlIGxpbmVzIQ0KDQpyaXZlcl9zaW1wID0gc3Rfc2ltcGxpZnkoYnJvb21lX2h5ZHJvLCBkVG9sZXJhbmNlID0gMTAwMDApDQoNCmdncGxvdCgpICsNCiAgZ2VvbV9zZihkYXRhID0gYnJvb21lLA0KICAgIG1hcHBpbmcgPSBhZXMoKSwgY29sb3IgPSAibGlnaHRncmF5IikrDQogIGdlb21fc2YoZGF0YSA9IHJpdmVyX3NpbXAsDQogICAgICAgICAgbWFwcGluZyA9IGFlcygpLCBjb2xvciA9ICJibHVlIikrDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQoNCk5vdywgbGV0J3MgY29tcGFyZSB0aGUgdHdvIQ0KDQpgYGB7cn0NCg0KYSA8LSBnZ3Bsb3QoKSArDQogIGdlb21fc2YoZGF0YSA9IGJyb29tZSwNCiAgICBtYXBwaW5nID0gYWVzKCksIGNvbG9yID0gImxpZ2h0Z3JheSIpKw0KICBnZW9tX3NmKGRhdGEgPSBicm9vbWVfaHlkcm8sDQogICAgICAgICAgbWFwcGluZyA9IGFlcygpLCBjb2xvciA9ICJibHVlIikrDQogIHRoZW1lX21pbmltYWwoKQ0KDQpiIDwtIGdncGxvdCgpICsNCiAgZ2VvbV9zZihkYXRhID0gYnJvb21lLA0KICAgIG1hcHBpbmcgPSBhZXMoKSwgY29sb3IgPSAibGlnaHRncmF5IikrDQogIGdlb21fc2YoZGF0YSA9IHJpdmVyX3NpbXAsDQogICAgICAgICAgbWFwcGluZyA9IGFlcygpLCBjb2xvciA9ICJibHVlIikrDQogIHRoZW1lX21pbmltYWwoKQ0KDQpsaWJyYXJ5KGNvd3Bsb3QpDQoNCnBsb3RfZ3JpZChhLCBiKQ0KDQpgYGANCkxhc3Qgd2Vlaywgd2UgYWxzbyBsZWFybmVkIGhvdyB0byBmaW5kIHRoZSBjZW50cm9pZCBvZiBhIHNwYXRpYWwgdW5pdCAoZS5nLiBwb2x5Z29uKSB1c2luZyBzdF9jZW50cm9pZCgpLiBPbmUgdGhpbmcgdG8gbm90ZSBpcyB0aGF0IHRoZSBtb3N0IGNlbnRyYWwgcG9pbnQgb24gYSBwb2x5Z29uIGRvZXNuJ3QgYWx3YXlzIGZhbGwgd2l0aGluIHRoYXQgcG9seWdvbiAtIGhlcmUgd2UnbGwgbGVhcm4gYW5vdGhlciBmdW5jdGlvbiB0aGF0IHdlIGNhbiB1c2UgdG8gZW5zdXJlIHRoYXQgb3VyIGNlbnRyb2lkcyBhcmUgd2l0aGluIHRoZSBwb2x5Z29ucy4NCmBgYHtyfQ0KDQojQ3JlYXRlIGNlbnRyb2lkcw0KcG9pbnRzIDwtIHN0X3BvaW50X29uX3N1cmZhY2UoY291bnRpZXMpDQoNCiBnZ3Bsb3QoKSArDQogIGdlb21fc2YoZGF0YSA9IGNvdW50aWVzLA0KICAgIG1hcHBpbmcgPSBhZXMoKSwgY29sb3IgPSAibGlnaHRncmF5IikrDQogIGdlb21fc2YoZGF0YSA9IHBvaW50cywNCiAgICAgICAgICBtYXBwaW5nID0gYWVzKCksIGNvbG9yID0gImJsdWUiKSsNCiAgdGhlbWVfbWluaW1hbCgpDQoNCg0KYGBgDQpUaGlzIGlzIHdoYXQgYSBjZW50cm9pZCBhY3R1YWxseSBsb29rcyBsaWtlISBBZ2FpbiwgdGhlc2UgYmVjb21lIG1vc3QgdXNlZnVsIGZvciBjYWxjdWxhdGluZyBkaXN0YW5jZXMuIA0KDQpMZXQncyBjb21wYXJlIHRoZSB0d28gbWV0aG9kczoNCg0KYGBge3J9DQoNCmNlbnRyb2lkcyA8LSBzdF9jZW50cm9pZChjb3VudGllcykNCg0KZ2dwbG90KCkgKw0KICBnZW9tX3NmKGRhdGEgPSBjb3VudGllcywNCiAgICBtYXBwaW5nID0gYWVzKCksIGNvbG9yID0gImxpZ2h0Z3JheSIpKw0KICBnZW9tX3NmKGRhdGEgPSBwb2ludHMsDQogICAgICAgICAgbWFwcGluZyA9IGFlcyhjb2xvciA9ICJQb2ludCBvbiBTdXJmYWNlIikpKw0KICBnZW9tX3NmKGRhdGEgPSBjZW50cm9pZHMsIG1hcHBpbmcgPSBhZXMoY29sb3IgPSAiQ2VudHJvaWRzIikpKw0KICB0aGVtZV9taW5pbWFsKCkrDQogIHNjYWxlX2NvbG9yX21hbnVhbChsYWJlbHMgPSBjKCJQb2ludCBvbiBTdXJmYWNlIiwgIkNlbnRyb2lkcyIpLA0KICAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gYygiYmx1ZSIsICJyZWQiKSkrDQogIGxhYnMoY29sb3IgPSAiUG9pbnQgVHlwZSIpDQpgYGANCg0KDQpOZXh0LCB3ZSdsbCBtb3ZlIG9uIHRvIGJ1ZmZlcnMhIEknbGwgc2hvdyB5b3Ugd2hhdCBpdCBpcywgYW5kIHRoZW4gd2UnbGwgdGFsayBhYm91dCB0aGUgd2F5cyB0aGF0IHlvdSBtaWdodCB1c2UgYSBidWZmZXIuIEJ1ZmZlcmluZyBjcmVhdGVzIGEgbmV3IHBvbHlnb24gdGhhdCBpcyB3aXRoaW4gYSBjZXJ0YWluIGRpc3RhbmNlIG9mIHRoZSBvcmlnaW5hbCwgYW5kIGl0IGxvb2tzIGxpa2UgdGhpczoNCg0KYGBge3J9DQpyaXZlcl9idWZmXzUwMCA9IHN0X2J1ZmZlcihicm9vbWVfaHlkcm8sIGRpc3QgPSA1MDApDQoNCg0KZ2dwbG90KCkgKw0KICBnZW9tX3NmKGRhdGEgPSBicm9vbWUsDQogICAgbWFwcGluZyA9IGFlcygpLCBjb2xvciA9ICJsaWdodGdyYXkiKSsNCiAgICBnZW9tX3NmKGRhdGEgPSByaXZlcl9idWZmXzUwMCwNCiAgICAgICAgICBtYXBwaW5nID0gYWVzKCksIGNvbG9yID0gInllbGxvdyIpKw0KICBnZW9tX3NmKGRhdGEgPSBicm9vbWVfaHlkcm8sDQogICAgICAgICAgbWFwcGluZyA9IGFlcygpLCBjb2xvciA9ICJibHVlIikrDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQpIb3cgb3Igd2h5IHdvdWxkIHlvdSB1c2UgdGhpcz8gTGV0J3Mgc2F5IEkgYW0gdHJ5aW5nIHRvIGZpZ3VyZSBvdXQgdGhlIGxvY2F0aW9uIGZvciBhIG5ldyBidWlsZGluZy4gSSBkb24ndCB3YW50IGl0IHRvIGJlIHRvbyBjbG9zZSB0byBhbnkgcml2ZXJzLCBvciBmbG9vZGluZyB3b3VsZCBiZSBhIHJpc2sgLSBJIGNhbiB1c2UgYSBidWZmZXIgdG8gdmlzdWFsaXplIGxvY2F0aW9ucyB0aGF0IGFyZSBhIGNlcnRhaW4gZGlzdGFuY2UgKGUuZy4gMSBrbSkgYXdheS4gDQoNCk5leHQsIHdlJ2xsIG1vdmUgb24gdG8gc3BhdGlhbCBjbGlwcGluZy4gDQoNCmBgYHtyfQ0Kc2V0d2QoIn4vQmluZ2hhbXRvbi9nZW9nMzgwL1NpbXBsaWZpZWRTdHJlZXRzX1NIUCIpDQpzdHJlZXRfc2hhcGUgPC0gc3RfcmVhZCgiU2ltcGxpZmllZFN0cmVldFNlZ21lbnRRcnQuc2hwIikNCg0Kc3RyZWV0X3NoYXBlIDwtIHN0cmVldF9zaGFwZSAlPiUgc3RfdHJhbnNmb3JtKCJFUFNHOjMyMTE2IikNCmJyb29tZV9zdHJlZXRzIDwtIHN0cmVldF9zaGFwZVticm9vbWUsICwgb3AgPSBzdF93aXRoaW5dDQpicm9vbWVfc3RyZWV0czEgPC0gc3RyZWV0X3NoYXBlW2Jyb29tZSwgLCBvcCA9IHN0X2ludGVyc2VjdHNdDQoNCmdncGxvdCgpICsNCiAgZ2VvbV9zZihkYXRhID0gYnJvb21lLA0KICAgIG1hcHBpbmcgPSBhZXMoKSwgY29sb3IgPSAibGlnaHRncmF5IikrDQogIGdlb21fc2YoZGF0YSA9IGJyb29tZV9zdHJlZXRzLA0KICAgICAgICAgIG1hcHBpbmcgPSBhZXMoKSwgY29sb3IgPSAiZ3JheTEwIikrDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQpXaXRoIHNwYXRpYWwgY2xpcHBpbmcsIEkgY2FuIGNyZWF0ZSBhIG5ldyBtYXAgbGF5ZXIgd2l0aCBpdHMgb3duIGdlb21ldHJ5IGJhc2VkIG9uIHRoZSBpbnRlcnNlY3Rpb24gb2YgdHdvIGV4aXN0aW5nIGxheWVycy4gSW4gb3JkZXIgdG8gdGVjaG5pY2FsbHkgdXNlIHNwYXRpYWwgY2xpcHBpbmcsIHdlIG5lZWQgc29tZXdoYXQgY29tcGxleCBnZW9tZXRyeSB0eXBlcyAoZS5nLiBsaW5lcyBhbmQgcG9seWdvbnMgLSBwb2ludHMgdGVjaG5pY2FsbHkgZG9uJ3Qgd29yayBoZXJlKS4gSW4gdGhpcyBsaW5lIGV4YW1wbGUsIHRoZSByb2FkIGxpbmVzIHdpbGwgYmUgY3V0IG9mZiB0byBvbmx5IHJldGFpbiB0aGUgcm9hZCBzZWdtZW50cyB0aGF0IGludGVyc2VjdGVkIHdpdGggcml2ZXJzLg0KDQpXaGF0IG1ha2VzIHRoaXMgYSBnZW9tZXRyeSBvcGVyYXRpb24/IEknbSBub3QganVzdCBzZWxlY3RpbmcgZmVhdHVyZXMgYmFzZWQgb24gdGhlIGludGVyc2VjdGlvbiBvZiB0d28gc3BhdGlhbCBsYXllcnMgLSBJIGFtIGNyZWF0aW5nIGEgbmV3IG9iamVjdCB3aXRoIGl0cyBvd24gdW5pcXVlIGdlb21ldHJ5LiBUaGF0IGlzIHRlY2huaWNhbGx5IHdoYXQgc2V0cyBnZW9tZXRyeSBvcGVyYXRpb25zIGFwYXJ0IGZyb20gb3RoZXIga2luZHMgb2Ygc3BhdGlhbCBvcGVyYXRpb25zIChkb24ndCB3b3JyeSB0aG91Z2gsIEkgd29uJ3QgcXVpeiB5b3Ugb24gdGhhdCkuDQoNCmBgYHtyfQ0KI0xldCdzIGdldCBicmlkZ2VzIGluIEJyb29tZSBjb3VudHkNCmJyaWRnZXMgPSBsZW5ndGhzKHN0X2ludGVyc2VjdHMoYnJvb21lX2h5ZHJvLCBicm9vbWVfc3RyZWV0cykpID4gMA0KDQpicm9vbWVfYnJpZGdlcyA8LSBicm9vbWVfaHlkcm9bYnJpZGdlcyxdDQoNCmdncGxvdCgpICsNCiAgZ2VvbV9zZihkYXRhID0gYnJvb21lLA0KICAgIG1hcHBpbmcgPSBhZXMoKSwgY29sb3IgPSAibGlnaHRncmF5IikrDQogIGdlb21fc2YoZGF0YSA9IGJyb29tZV9zdHJlZXRzLCBtYXBwaW5nID0gYWVzKCksIGNvbG9yID0gImdyYXkiKSsNCiAgICBnZW9tX3NmKGRhdGEgPSBicm9vbWVfaHlkcm8sDQogICAgICAgICAgbWFwcGluZyA9IGFlcygpLCBjb2xvciA9ICJibHVlIikrDQogICAgZ2VvbV9zZihkYXRhID0gYnJvb21lX2JyaWRnZXMsDQogICAgICAgICAgbWFwcGluZyA9IGFlcygpLCBjb2xvciA9ICJicm93biIsIHNpemUgPSAxLjIpKw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KDQpTbywgdGhpcyBpcyBoZWxwZnVsLCBidXQgd2hhdCBpZiBJIHdhbnRlZCB0aGUgYWN0dWFsIHBvaW50cyB3aGVyZSB0aGUgYnJpZGdlcyBhcmUgbG9jYXRlZD8gVGhpcyBpcyBub3QgdGVjaG5pY2FsbHkgY2xpcHBpbmcsIGJ1dCB3ZSBjYW4gZG8gdGhhdCwgdG9vIQ0KDQpgYGB7cn0NCiNGaXJzdCwgSSBuZWVkIHRvIGNvbnZlcnQgbXkgcml2ZXIgbGF5ZXIgZnJvbSBsaW5lcyB0byBwb2ludHMgLSB3ZSdsbCB1c2UgdGhlIGludGVyc2VjdGlvbiBvZiB0aGVzZSBwb2ludHMgdG8gZmluZCBicmlkZ2UgbG9jYXRpb25zDQpyaXZlcl9wb2ludHMgPSBzdF9jYXN0KGJyb29tZV9oeWRybywgIlBPSU5UIikNCg0KZ2dwbG90KCkgKw0KICBnZW9tX3NmKGRhdGEgPSBicm9vbWUsDQogICAgbWFwcGluZyA9IGFlcygpLCBjb2xvciA9ICJsaWdodGdyYXkiKSsNCiAgICBnZW9tX3NmKGRhdGEgPSByaXZlcl9wb2ludHMsDQogICAgICAgICAgbWFwcGluZyA9IGFlcygpLCBjb2xvciA9ICJibHVlIiwgc2l6ZSA9IDAuMikrDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQpgYGB7cn0NCiNDcmVhdGUgYSBsb2dpY2FsIHZlY3RvciB0byBzdWJzZXQgb3VyIHJpdmVyIHBvaW50cyBsYXllciBieSAtIHRoaXMgaXMgZXF1YWwgdG8gVFJVRSBpZiB0aGUgcG9pbnRzIGxheWVyIGFuZCBicm9vbWUgc3RyZWV0cyBpbnRlcnNlY3QsIGFuZCBGQUxTRSBvdGhlcndpc2UNCiNIZXJlIHdlIGFyZSBmaW5kaW5nIGFsbCB0aGUgcG9pbnRzIHRoYXQgaW50ZXJzZWN0IHdpdGggYnJvb21lIHN0cmVldHMgLSBpZiBhIHBvaW50IGludGVyc2VjdHMsIGluIHRoZSByZXN1bHQgaXQgd2lsbCBoYXZlIGEgbGVuZ3RoID4gMA0KI0NyZWF0ZSBhIGxvZ2ljYWwgdmVjdG9yIGJhc2VkIG9uIHdoZXRoZXIgdGhlIGxlbmdodGhzIGFyZSBncmVhdGVyIHRoYW4gMA0KYnJpZGdlcyA9IGxlbmd0aHMoc3RfaW50ZXJzZWN0cyhyaXZlcl9wb2ludHMsIGJyb29tZV9zdHJlZXRzKSkgPiAwDQoNCmJyaWRnZXNfbmV3IDwtIHJpdmVyX3BvaW50c1ticmlkZ2VzLF0NCg0KZ2dwbG90KCkgKw0KICBnZW9tX3NmKGRhdGEgPSBicm9vbWUsDQogICAgbWFwcGluZyA9IGFlcygpLCBjb2xvciA9ICJsaWdodGdyYXkiKSsNCiAgICBnZW9tX3NmKGRhdGEgPSBicmlkZ2VzX25ldywNCiAgICAgICAgICBtYXBwaW5nID0gYWVzKCksIGNvbG9yID0gImJyb3duIiwgc2l6ZSA9IDEuMikrDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQoNCkZpbmFsbHksIHdlJ2xsIGxvb2sgYXQgZ2VvbWV0cnkgdW5pb25zISBUaGlzIHdpbGwgdHlwaWNhbGx5IGludm9sdmUgYWdncmVnYXRpbmcvc3VtbWFyaXNpbmcgc3BhdGlhbCBpbmZvcm1hdGlvbiBhdCBvbmUgbGV2ZWwgKGUuZy4gdGhlIGNvdW50eSBsZXZlbCkgdXAgdG8gYSBoaWdoZXIgc2NhbGUgKGUuZy4gdGhlIHJlZ2lvbmFsIGxldmVsKS4gRm9yIGV4YW1wbGUsIHVzaW5nIG91ciBOWVMgZGF0YToNCg0KYGBge3J9DQojTG9hZCBpbiBDb3ZpZCBkYXRhIHdpdGggcmVnaW9uIGluZm9ybWF0aW9uDQpzZXR3ZCgifi9CaW5naGFtdG9uL2dlb2czODAiKQ0KY292aWQgPC0gcmVhZC5jc3YoImNvdmlkX2RhdGFfbnkuY3N2IikNCg0KbGlicmFyeSh0aWR5cikNCmNvdW50aWVzMSA8LSBjb3VudGllcyAlPiUgDQogIHNlcGFyYXRlKGNvdW50eV9uYW1lLCBjKCJjb3VudHlfbmFtZSIsICJjb3VudHkiKSwgc2VwID0gIiBDb3VudHkiKSAlPiUgDQogIHNlbGVjdCgtY291bnR5KQ0KDQpjb3VudGllczEgPC0gY291bnRpZXMxICU+JQ0KICBsZWZ0X2pvaW4oY292aWQsIGJ5ID0gYygiY291bnR5X25hbWUiID0gIkNvdW50eSIpKQ0KDQojSSBkb24ndCBhY3R1YWxseSBjYXJlIGFib3V0IENvdmlkIGNhc2VzIC0gc3VtbWFyaXNlIGNvdmlkIGNhc2VzIHRvIGdldCBvdXIgc3BhdGlhbCBkYXRhIGdyb3VwZWQgYnkgcmVnaW9uDQpyZWdpb25zIDwtIGNvdW50aWVzMSAlPiUgZ3JvdXBfYnkocmVnaW9uKSAlPiUNCiAgc3VtbWFyaXplKGNhc2VzID0gc3VtKG5ld19wb3NpdGl2ZSwgbmEucm0gPSBUUlVFKSkNCg0KI25vdyB3ZSdsbCBtYXAgaXQhDQpnZ3Bsb3QoKSArDQogIGdlb21fc2YoZGF0YSA9IHJlZ2lvbnMsDQogICAgbWFwcGluZyA9IGFlcyhmaWxsID0gcmVnaW9uKSkrDQogIGdlb21fc2YoZGF0YSA9IGNvdW50aWVzLCBtYXBwaW5nID0gYWVzKCksIGZpbGwgPSAidHJhbnNwYXJlbnQiLCBjb2xvciA9ICJ3aGl0ZSIpKw0KICB0aGVtZV9taW5pbWFsKCkrDQogIGxhYnMoZmlsbCA9ICJSZWdpb24iLCB0aXRsZSA9ICJSZWdpb25zIG9mIE5ZUyIpKw0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkNCg0KYGBgDQpSZXNvdXJjZXMgDQoNCkxvdmVsYWNlLCBSLiwgTm93b3NhZCwgSi4sIE11ZW5jaG93LiBKLiAoMjAxOSkuIEdlb2NvbXB1dGF0aW9uIHdpdGggUi4gUmV0cmlldmVkIGZyb206IGh0dHBzOi8vZ2VvY29tcHIucm9iaW5sb3ZlbGFjZS5uZXQvLg0KDQpOZXcgWW9yayBTdGF0ZSAoMjAyMikuIE5ldyBZb3JrIFN0YXRlIFN0YXRld2lkZSBDb3ZpZC0xOSBUZXN0aW5nLiBbRGF0YSBTZXRdLiBSZXRyZWl2ZWQgZnJvbTogaHR0cHM6Ly9oZWFsdGguZGF0YS5ueS5nb3YvSGVhbHRoL05ldy1Zb3JrLVN0YXRlLVN0YXRld2lkZS1DT1ZJRC0xOS1UZXN0aW5nL3hkc3MtdTUzZS4gDQoNCk5ZUyBHSVMgQ2xlYXJpbmdob3VzZSAoMjAyMikuIE5ZUyBTdHJlZXRzLiBbRGF0YSBTZXRdLiBSZXRyaWV2ZWQgZnJvbTogaHR0cDovL2dpcy5ueS5nb3YvZ2lzZGF0YS8uIA0KDQpOWVMgR0lTIENsZWFyaW5naG91c2UgKDIwMjIpLiBOWVMgSHlkcm9ncmFwaHkuIFtEYXRhIFNldF0uIFJldHJpZXZlZCBmcm9tOiBodHRwOi8vZ2lzLm55Lmdvdi9naXNkYXRhLy4gDQo=