Spatial Data Handling

rm(list = ls()) # 清除任何現有的R物件之前執行批次工作的程式碼

library(sf)
library(tmap)
library(pals) # collection of color palettes
library(cartography) # classification methods

#setwd("C:/Wen_Files/SA_2024")
load("./data/Sample.RData")

0. sf format and coordinates

class(blocks_sf)
[1] "sf"         "data.frame"
head(blocks_sf)
Simple feature collection with 6 features and 28 fields
Geometry type: POLYGON
Dimension:     XY
Bounding box:  xmin: 534687.6 ymin: 177306.3 xmax: 569625.3 ymax: 188464.6
Projected CRS:  +proj=lcc +datum=NAD27 +lon_0=-72d45 +lat_1=41d52 +lat_2=41d12 +lat_0=40d50 +x_0=182880.3657607315 +y_0=0 +units=us-ft +no_defs +ellps=clrk66 +nadgrids=@conus,@alaska,@ntv2_0.gsb,@ntv1_can.dat
  NEWH075H_ NEWH075H_I HSE_UNITS OCCUPIED VACANT  P_VACANT P_OWNEROCC P_RENTROCC NEWH075P_
0         2         69       763      725     38  4.980341   0.393185  94.626474         2
1         3         72       510      480     30  5.882353  20.392157  73.725490         3
2         4         64       389      362     27  6.940874  57.840617  35.218509         4
3         5         68       429      397     32  7.459207  19.813520  72.727273         5
4         6         67       443      385     58 13.092551  80.361174   6.546275         6
5         7        133       588      548     40  6.802721  52.551020  40.646259         7
  NEWH075P_I POP1990  P_MALES P_FEMALES   P_WHITE   P_BLACK P_AMERI_ES P_ASIAN_PI  P_OTHER
0        380    2396 40.02504  59.97496  7.095159 87.020033   0.584307   0.041736 5.258765
1        385    3071 39.07522  60.92478 87.105177 10.452621   0.195376   0.521003 1.725822
2        394     996 47.38956  52.61044 32.931727 66.265060   0.100402   0.200803 0.502008
3        399    1336 42.66467  57.33533 11.452096 85.553892   0.523952   0.523952 1.946108
4        404     915 46.22951  53.77049 73.442623 24.371585   0.327869   1.420765 0.437158
5        406    1318 50.91047  49.08953 87.784522  7.435508   0.758725   0.834598 3.186646
   P_UNDER5    P_5_13  P_14_17   P_18_24   P_25_34   P_35_44  P_45_54  P_55_64   P_65_74
0 12.813022 24.707846 7.888147 12.479132 16.026711  8.555927 5.759599 4.924875  4.048414
1  1.921198  2.474764 0.814067 71.149463  7.359166  4.037773 1.595571 1.758385  3.712146
2 10.441767 13.554217 5.722892  8.835341 17.670683 17.871486 8.734940 5.923695  7.931727
3 10.853293 17.739521 7.709581 12.425150 18.113772 10.853293 9.056886 6.287425  4.266467
4  6.229508  8.633880 2.950820  7.103825 17.267760 16.830601 8.415301 7.431694 14.426230
5  8.725341  8.194234 3.641882 10.091047 29.286798 12.898331 7.814871 7.814871  6.904401
    P_75_UP                       geometry
0  2.796327 POLYGON ((540989.5 186028.3...
1  5.177467 POLYGON ((539949.9 187487.6...
2  3.313253 POLYGON ((537497.6 184616.7...
3  2.694611 POLYGON ((537497.6 184616.7...
4 10.710383 POLYGON ((536589.3 184217.5...
5  4.628225 POLYGON ((568032.4 183170.2...

Extracing as a new layer

new_sf <- blocks_sf[,6]
new2_sf <- blocks_sf[1:3,]

Attribute table

blocks_df <- as.data.frame(blocks_sf)
class(blocks_df)
[1] "data.frame"
head(blocks_df)

Coordinate system

st_crs(blocks_sf)
Coordinate Reference System:
  User input:  +proj=lcc +datum=NAD27 +lon_0=-72d45 +lat_1=41d52 +lat_2=41d12 +lat_0=40d50 +x_0=182880.3657607315 +y_0=0 +units=us-ft +no_defs +ellps=clrk66 +nadgrids=@conus,@alaska,@ntv2_0.gsb,@ntv1_can.dat 
  wkt:
BOUNDCRS[
    SOURCECRS[
        PROJCRS["unknown",
            BASEGEOGCRS["unknown",
                DATUM["North American Datum 1927",
                    ELLIPSOID["Clarke 1866",6378206.4,294.978698213898,
                        LENGTHUNIT["metre",1]],
                    ID["EPSG",6267]],
                PRIMEM["Greenwich",0,
                    ANGLEUNIT["degree",0.0174532925199433],
                    ID["EPSG",8901]]],
            CONVERSION["unknown",
                METHOD["Lambert Conic Conformal (2SP)",
                    ID["EPSG",9802]],
                PARAMETER["Latitude of false origin",40.8333333333333,
                    ANGLEUNIT["degree",0.0174532925199433],
                    ID["EPSG",8821]],
                PARAMETER["Longitude of false origin",-72.75,
                    ANGLEUNIT["degree",0.0174532925199433],
                    ID["EPSG",8822]],
                PARAMETER["Latitude of 1st standard parallel",41.8666666666667,
                    ANGLEUNIT["degree",0.0174532925199433],
                    ID["EPSG",8823]],
                PARAMETER["Latitude of 2nd standard parallel",41.2,
                    ANGLEUNIT["degree",0.0174532925199433],
                    ID["EPSG",8824]],
                PARAMETER["Easting at false origin",600000,
                    LENGTHUNIT["US survey foot",0.304800609601219],
                    ID["EPSG",8826]],
                PARAMETER["Northing at false origin",0,
                    LENGTHUNIT["US survey foot",0.304800609601219],
                    ID["EPSG",8827]]],
            CS[Cartesian,2],
                AXIS["(E)",east,
                    ORDER[1],
                    LENGTHUNIT["US survey foot",0.304800609601219,
                        ID["EPSG",9003]]],
                AXIS["(N)",north,
                    ORDER[2],
                    LENGTHUNIT["US survey foot",0.304800609601219,
                        ID["EPSG",9003]]]]],
    TARGETCRS[
        GEOGCRS["WGS 84",
            DATUM["World Geodetic System 1984",
                ELLIPSOID["WGS 84",6378137,298.257223563,
                    LENGTHUNIT["metre",1]]],
            PRIMEM["Greenwich",0,
                ANGLEUNIT["degree",0.0174532925199433]],
            CS[ellipsoidal,2],
                AXIS["latitude",north,
                    ORDER[1],
                    ANGLEUNIT["degree",0.0174532925199433]],
                AXIS["longitude",east,
                    ORDER[2],
                    ANGLEUNIT["degree",0.0174532925199433]],
            ID["EPSG",4326]]],
    ABRIDGEDTRANSFORMATION["unknown to WGS84",
        METHOD["NTv2",
            ID["EPSG",9615]],
        PARAMETERFILE["Latitude and longitude difference file","@conus,@alaska,@ntv2_0.gsb,@ntv1_can.dat",
            ID["EPSG",8656]]]]
st_crs(roads_sf)
Coordinate Reference System:
  User input:  +proj=lcc +datum=NAD27 +lon_0=-72d45 +lat_1=41d52 +lat_2=41d12 +lat_0=40d50 +x_0=182880.3657607315 +y_0=0 +units=us-ft +no_defs +ellps=clrk66 +nadgrids=@conus,@alaska,@ntv2_0.gsb,@ntv1_can.dat 
  wkt:
BOUNDCRS[
    SOURCECRS[
        PROJCRS["unknown",
            BASEGEOGCRS["unknown",
                DATUM["North American Datum 1927",
                    ELLIPSOID["Clarke 1866",6378206.4,294.978698213898,
                        LENGTHUNIT["metre",1]],
                    ID["EPSG",6267]],
                PRIMEM["Greenwich",0,
                    ANGLEUNIT["degree",0.0174532925199433],
                    ID["EPSG",8901]]],
            CONVERSION["unknown",
                METHOD["Lambert Conic Conformal (2SP)",
                    ID["EPSG",9802]],
                PARAMETER["Latitude of false origin",40.8333333333333,
                    ANGLEUNIT["degree",0.0174532925199433],
                    ID["EPSG",8821]],
                PARAMETER["Longitude of false origin",-72.75,
                    ANGLEUNIT["degree",0.0174532925199433],
                    ID["EPSG",8822]],
                PARAMETER["Latitude of 1st standard parallel",41.8666666666667,
                    ANGLEUNIT["degree",0.0174532925199433],
                    ID["EPSG",8823]],
                PARAMETER["Latitude of 2nd standard parallel",41.2,
                    ANGLEUNIT["degree",0.0174532925199433],
                    ID["EPSG",8824]],
                PARAMETER["Easting at false origin",600000,
                    LENGTHUNIT["US survey foot",0.304800609601219],
                    ID["EPSG",8826]],
                PARAMETER["Northing at false origin",0,
                    LENGTHUNIT["US survey foot",0.304800609601219],
                    ID["EPSG",8827]]],
            CS[Cartesian,2],
                AXIS["(E)",east,
                    ORDER[1],
                    LENGTHUNIT["US survey foot",0.304800609601219,
                        ID["EPSG",9003]]],
                AXIS["(N)",north,
                    ORDER[2],
                    LENGTHUNIT["US survey foot",0.304800609601219,
                        ID["EPSG",9003]]]]],
    TARGETCRS[
        GEOGCRS["WGS 84",
            DATUM["World Geodetic System 1984",
                ELLIPSOID["WGS 84",6378137,298.257223563,
                    LENGTHUNIT["metre",1]]],
            PRIMEM["Greenwich",0,
                ANGLEUNIT["degree",0.0174532925199433]],
            CS[ellipsoidal,2],
                AXIS["latitude",north,
                    ORDER[1],
                    ANGLEUNIT["degree",0.0174532925199433]],
                AXIS["longitude",east,
                    ORDER[2],
                    ANGLEUNIT["degree",0.0174532925199433]],
            ID["EPSG",4326]]],
    ABRIDGEDTRANSFORMATION["unknown to WGS84",
        METHOD["NTv2",
            ID["EPSG",9615]],
        PARAMETERFILE["Latitude and longitude difference file","@conus,@alaska,@ntv2_0.gsb,@ntv1_can.dat",
            ID["EPSG",8656]]]]
st_crs(roads_sf) <- st_crs(blocks_sf)
st_crs(roads_sf)
Coordinate Reference System:
  User input:  +proj=lcc +datum=NAD27 +lon_0=-72d45 +lat_1=41d52 +lat_2=41d12 +lat_0=40d50 +x_0=182880.3657607315 +y_0=0 +units=us-ft +no_defs +ellps=clrk66 +nadgrids=@conus,@alaska,@ntv2_0.gsb,@ntv1_can.dat 
  wkt:
BOUNDCRS[
    SOURCECRS[
        PROJCRS["unknown",
            BASEGEOGCRS["unknown",
                DATUM["North American Datum 1927",
                    ELLIPSOID["Clarke 1866",6378206.4,294.978698213898,
                        LENGTHUNIT["metre",1]],
                    ID["EPSG",6267]],
                PRIMEM["Greenwich",0,
                    ANGLEUNIT["degree",0.0174532925199433],
                    ID["EPSG",8901]]],
            CONVERSION["unknown",
                METHOD["Lambert Conic Conformal (2SP)",
                    ID["EPSG",9802]],
                PARAMETER["Latitude of false origin",40.8333333333333,
                    ANGLEUNIT["degree",0.0174532925199433],
                    ID["EPSG",8821]],
                PARAMETER["Longitude of false origin",-72.75,
                    ANGLEUNIT["degree",0.0174532925199433],
                    ID["EPSG",8822]],
                PARAMETER["Latitude of 1st standard parallel",41.8666666666667,
                    ANGLEUNIT["degree",0.0174532925199433],
                    ID["EPSG",8823]],
                PARAMETER["Latitude of 2nd standard parallel",41.2,
                    ANGLEUNIT["degree",0.0174532925199433],
                    ID["EPSG",8824]],
                PARAMETER["Easting at false origin",600000,
                    LENGTHUNIT["US survey foot",0.304800609601219],
                    ID["EPSG",8826]],
                PARAMETER["Northing at false origin",0,
                    LENGTHUNIT["US survey foot",0.304800609601219],
                    ID["EPSG",8827]]],
            CS[Cartesian,2],
                AXIS["(E)",east,
                    ORDER[1],
                    LENGTHUNIT["US survey foot",0.304800609601219,
                        ID["EPSG",9003]]],
                AXIS["(N)",north,
                    ORDER[2],
                    LENGTHUNIT["US survey foot",0.304800609601219,
                        ID["EPSG",9003]]]]],
    TARGETCRS[
        GEOGCRS["WGS 84",
            DATUM["World Geodetic System 1984",
                ELLIPSOID["WGS 84",6378137,298.257223563,
                    LENGTHUNIT["metre",1]]],
            PRIMEM["Greenwich",0,
                ANGLEUNIT["degree",0.0174532925199433]],
            CS[ellipsoidal,2],
                AXIS["latitude",north,
                    ORDER[1],
                    ANGLEUNIT["degree",0.0174532925199433]],
                AXIS["longitude",east,
                    ORDER[2],
                    ANGLEUNIT["degree",0.0174532925199433]],
            ID["EPSG",4326]]],
    ABRIDGEDTRANSFORMATION["unknown to WGS84",
        METHOD["NTv2",
            ID["EPSG",9615]],
        PARAMETERFILE["Latitude and longitude difference file","@conus,@alaska,@ntv2_0.gsb,@ntv1_can.dat",
            ID["EPSG",8656]]]]

Taiwan Coordinate System

TWCOUNTY <- st_read("./data/TaiwanCounty.shp", options="ENCODING=utf-8")
options:        ENCODING=utf-8 
Reading layer `TaiwanCounty' from data source 
  `C:\Users\wenth\Desktop\WK02\data\TaiwanCounty.shp' using driver `ESRI Shapefile'
Simple feature collection with 19 features and 9 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: 147522.2 ymin: 2422005 xmax: 351690.1 ymax: 2799149
Projected CRS: TWD97 / TM2 zone 121
st_crs(TWCOUNTY)
Coordinate Reference System:
  User input: TWD97 / TM2 zone 121 
  wkt:
PROJCRS["TWD97 / TM2 zone 121",
    BASEGEOGCRS["TWD97",
        DATUM["Taiwan Datum 1997",
            ELLIPSOID["GRS 1980",6378137,298.257222101,
                LENGTHUNIT["metre",1]]],
        PRIMEM["Greenwich",0,
            ANGLEUNIT["degree",0.0174532925199433]],
        ID["EPSG",3824]],
    CONVERSION["Taiwan 2-degree TM zone 121",
        METHOD["Transverse Mercator",
            ID["EPSG",9807]],
        PARAMETER["Latitude of natural origin",0,
            ANGLEUNIT["degree",0.0174532925199433],
            ID["EPSG",8801]],
        PARAMETER["Longitude of natural origin",121,
            ANGLEUNIT["degree",0.0174532925199433],
            ID["EPSG",8802]],
        PARAMETER["Scale factor at natural origin",0.9999,
            SCALEUNIT["unity",1],
            ID["EPSG",8805]],
        PARAMETER["False easting",250000,
            LENGTHUNIT["metre",1],
            ID["EPSG",8806]],
        PARAMETER["False northing",0,
            LENGTHUNIT["metre",1],
            ID["EPSG",8807]]],
    CS[Cartesian,2],
        AXIS["easting (X)",east,
            ORDER[1],
            LENGTHUNIT["metre",1]],
        AXIS["northing (Y)",north,
            ORDER[2],
            LENGTHUNIT["metre",1]],
    USAGE[
        SCOPE["Engineering survey, topographic mapping."],
        AREA["Taiwan, Republic of China - between 120°E and 122°E, onshore and offshore - Taiwan Island."],
        BBOX[20.41,119.99,26.72,122.06]],
    ID["EPSG",3826]]

Export/import shapefiles

st_write(blocks_sf,"blocks.shp", delete_layer = TRUE)
Deleting layer `blocks' using driver `ESRI Shapefile'
Writing layer `blocks' to data source `blocks.shp' using driver `ESRI Shapefile'
Writing 129 features with 30 fields and geometry type Polygon.

1. Mapping Spatial Objects

using plot

plot(blocks_sf)
警告: plotting the first 10 out of 30 attributes; use max.plot = 30 to plot all

plot(blocks_sf["P_VACANT"], breaks = "jenks", nbreaks = 6)

#(blocks_sf$P_VACANT ?)

brewer.blues(6)
[1] "#EFF3FF" "#C6DBEF" "#9ECAE1" "#6BAED6" "#3182BD" "#08519C"
plot(blocks_sf["P_VACANT"], breaks = "jenks", nbreaks = 6, pal=brewer.blues(6))

using tmap package

quick tmap

qtm(blocks_sf, fill="orange", style="natural")

# colors()

Qick tmap: choropleth

qtm(blocks_sf, fill="P_VACANT", fill.title="Vacant %", title="My Map 1")

Qick tmap: bubble map

qtm(blocks_sf, symbols.size="P_VACANT", symbols.title.size="Vacant %", title="My Bubble Map")

Overlay multiple plots

lyr1 <- qtm(blocks_sf, fill="P_VACANT", fill.title="Vacant %", title="My Map 1")
lyr_road <- tm_shape(roads_sf)+tm_lines(col="gray") # lines
lyr_crimes <- tm_shape(breach_sf)+tm_dots(col="red", size= 0.1) # points

# overlay multiple plots
lyr1 + lyr_road + lyr_crimes

Showing multiple plots/maps

library(grid)
# open a new plot page

grid.newpage()
# set up the layout
pushViewport(viewport(layout=grid.layout(1,2)))

# plot using the print command
print(lyr1, vp=viewport(layout.pos.col = 1))
print(lyr_road, vp=viewport(layout.pos.col = 2))


# dev.off() # close plotting device

2. Attribute Query

index <- (blocks_sf$P_VACANT > 10)
newblocks_sf <- blocks_sf[index,]
lyr3 <- qtm(newblocks_sf, fill="red", title="Vacant > 10%", style="natural")
lyr_bg <- qtm(blocks_sf, fill="grey")
lyr_bg + lyr3
Note that tm_style("natural") resets all options set with tm_layout, tm_view, tm_format, or tm_legend. It is therefore recommended to place the tm_style element prior to the other tm_layout/tm_view/tm_format/tm_legend elements.

3. Calculating Fields

create a field

x <- st_area(blocks_sf) # unit: foot

library(units)
x2 <- set_units(x, km^2)
blocks_sf$AREA1 <- x2
colnames(blocks_sf)
 [1] "NEWH075H_"  "NEWH075H_I" "HSE_UNITS"  "OCCUPIED"   "VACANT"     "P_VACANT"  
 [7] "P_OWNEROCC" "P_RENTROCC" "NEWH075P_"  "NEWH075P_I" "POP1990"    "P_MALES"   
[13] "P_FEMALES"  "P_WHITE"    "P_BLACK"    "P_AMERI_ES" "P_ASIAN_PI" "P_OTHER"   
[19] "P_UNDER5"   "P_5_13"     "P_14_17"    "P_18_24"    "P_25_34"    "P_35_44"   
[25] "P_45_54"    "P_55_64"    "P_65_74"    "P_75_UP"    "geometry"   "AREA1"     
[31] "POPDEN"    

remove a field

blocks_sf <- subset(blocks_sf, select = -c(AREA1))
colnames(blocks_sf)
 [1] "NEWH075H_"  "NEWH075H_I" "HSE_UNITS"  "OCCUPIED"   "VACANT"     "P_VACANT"  
 [7] "P_OWNEROCC" "P_RENTROCC" "NEWH075P_"  "NEWH075P_I" "POP1990"    "P_MALES"   
[13] "P_FEMALES"  "P_WHITE"    "P_BLACK"    "P_AMERI_ES" "P_ASIAN_PI" "P_OTHER"   
[19] "P_UNDER5"   "P_5_13"     "P_14_17"    "P_18_24"    "P_25_34"    "P_35_44"   
[25] "P_45_54"    "P_55_64"    "P_65_74"    "P_75_UP"    "geometry"   "POPDEN"    

calculating values

x2 <- set_units(x, km^2)
blocks_sf$AREA1 <- x2

blocks_sf$POPDEN <- blocks_sf$POP1990 / blocks_sf$AREA1

plot(blocks_sf["POPDEN"], breaks = "jenks", nbreaks = 6, pal= brewer.blues(6))

qtm(blocks_sf, fill="POPDEN", fill.title="Population Density", title="Popn Map", style="natural")

4. Detailed Settings for Mapping

breakv<- getBreaks(v = blocks_sf$P_OWNEROCC, nclass = 6, method = "jenks")
# classification method:"fixed", "sd", "equal", "pretty", "quantile", "kmeans", 
# "hclust", "bclust", "fisher", "jenks", "dpih", "q6", "geom", "arith", "em", "msd" 

tm_shape(blocks_sf) +
  tm_polygons("P_OWNEROCC", title = "Owner Occ", palette = "-GnBu", 
              breaks = c(breakv), 
              legend.hist = T) +
  tm_scale_bar(width = 0.22) +
  tm_compass(position = c(0.8, 0.08)) +
  tm_layout(frame = F, title = "New Haven", 
            title.size = 2, title.position = c(0.55, "top"), 
            legend.hist.size = 0.5)

5. Statistical Plots

Histogram

hist(blocks_sf$P_VACANT, breaks = 40, col = "grey", 
     border = "red", 
     main = "The histogram of vacant property percentages", 
     xlab = "percentage vacant", xlim = c(0,40))

using ggplot2: histogram

library(ggplot2)
blocks_df <- as.data.frame(blocks_sf)
head(blocks_df)

plot1<- ggplot(blocks_df) + aes(P_VACANT) +
          geom_histogram(col = "red", fill = "grey", bins = 40) +
          xlab("percentage vacant") +
          labs(title = "The histogram of vacant property percentages")

plot1

Boxplot

boxplot(blocks_sf$P_WHIT, blocks_sf$P_BLACK, names=c("White", "Black"), 
        xlab="Race", ylab="Percentage")

using ggplot2: boxplot

library(reshape2)
block_prop <- melt(blocks_df[, c("P_WHITE", "P_BLACK", "P_AMERI_ES")])
No id variables; using all as measure variables
head(block_prop)

plot2 <- ggplot(block_prop) + 
           aes(variable, value) +
           geom_boxplot()

plot2

Showing map + plot

grid.newpage()
pushViewport(viewport(layout=grid.layout(1,2)))
print(lyr1+lyr_crimes, vp=viewport(layout.pos.col = 1))
print(plot2, vp=viewport(layout.pos.col = 2))


#dev.off()
LS0tDQp0aXRsZTogIlNwYXRpYWwgQW5hbHlzaXM6MDIiDQphdXRob3I6ICJUemFpLUh1bmcgV2VuIg0KZGF0ZTogJzIwMjUtMDMtMDMnDQpvdXRwdXQ6DQogIGh0bWxfbm90ZWJvb2s6DQogICAgdG9jOiB0cnVlDQogICAgdG9jX2RlcHRoOiA2DQogICAgdG9jX2Zsb2F0OiB0cnVlDQotLS0NCg0KIyBTcGF0aWFsIERhdGEgSGFuZGxpbmcNCg0KYGBge3J9DQpybShsaXN0ID0gbHMoKSkgIyDmuIXpmaTku7vkvZXnj77mnInnmoRS54mp5Lu25LmL5YmN5Z+36KGM5om55qyh5bel5L2c55qE56iL5byP56K8DQoNCmxpYnJhcnkoc2YpDQpsaWJyYXJ5KHRtYXApDQpsaWJyYXJ5KHBhbHMpICMgY29sbGVjdGlvbiBvZiBjb2xvciBwYWxldHRlcw0KbGlicmFyeShjYXJ0b2dyYXBoeSkgIyBjbGFzc2lmaWNhdGlvbiBtZXRob2RzDQoNCiNzZXR3ZCgiQzovV2VuX0ZpbGVzL1NBXzIwMjQiKQ0KbG9hZCgiLi9kYXRhL1NhbXBsZS5SRGF0YSIpDQpgYGANCg0KIyAwLiBzZiBmb3JtYXQgYW5kIGNvb3JkaW5hdGVzDQpgYGB7cn0NCmNsYXNzKGJsb2Nrc19zZikNCmhlYWQoYmxvY2tzX3NmKQ0KYGBgDQoNCiMjIEV4dHJhY2luZyBhcyBhIG5ldyBsYXllcg0KDQpgYGB7cn0NCm5ld19zZiA8LSBibG9ja3Nfc2ZbLDZdDQpuZXcyX3NmIDwtIGJsb2Nrc19zZlsxOjMsXQ0KYGBgDQoNCiMjIEF0dHJpYnV0ZSB0YWJsZQ0KDQpgYGB7cn0NCmJsb2Nrc19kZiA8LSBhcy5kYXRhLmZyYW1lKGJsb2Nrc19zZikNCmNsYXNzKGJsb2Nrc19kZikNCmhlYWQoYmxvY2tzX2RmKQ0KYGBgDQoNCiMjIENvb3JkaW5hdGUgc3lzdGVtDQoNCmBgYHtyfQ0Kc3RfY3JzKGJsb2Nrc19zZikNCmBgYA0KYGBge3J9DQpzdF9jcnMocm9hZHNfc2YpDQpgYGANCg0KYGBge3J9DQpzdF9jcnMocm9hZHNfc2YpIDwtIHN0X2NycyhibG9ja3Nfc2YpDQpzdF9jcnMocm9hZHNfc2YpDQpgYGANCiMjIyBUYWl3YW4gQ29vcmRpbmF0ZSBTeXN0ZW0NCmBgYHtyfQ0KVFdDT1VOVFkgPC0gc3RfcmVhZCgiLi9kYXRhL1RhaXdhbkNvdW50eS5zaHAiLCBvcHRpb25zPSJFTkNPRElORz11dGYtOCIpDQpzdF9jcnMoVFdDT1VOVFkpDQpgYGANCg0KIyMgRXhwb3J0L2ltcG9ydCBzaGFwZWZpbGVzDQoNCmBgYHtyfQ0Kc3Rfd3JpdGUoYmxvY2tzX3NmLCJibG9ja3Muc2hwIiwgZGVsZXRlX2xheWVyID0gVFJVRSkNCmBgYA0KDQojICAxLiBNYXBwaW5nIFNwYXRpYWwgT2JqZWN0cw0KDQojIyB1c2luZyBwbG90DQoNCmBgYHtyfQ0KcGxvdChibG9ja3Nfc2YpDQpwbG90KGJsb2Nrc19zZlsiUF9WQUNBTlQiXSwgYnJlYWtzID0gImplbmtzIiwgbmJyZWFrcyA9IDYpDQojKGJsb2Nrc19zZiRQX1ZBQ0FOVCA/KQ0KDQpicmV3ZXIuYmx1ZXMoNikNCnBsb3QoYmxvY2tzX3NmWyJQX1ZBQ0FOVCJdLCBicmVha3MgPSAiamVua3MiLCBuYnJlYWtzID0gNiwgcGFsPWJyZXdlci5ibHVlcyg2KSkNCmBgYA0KIyMgdXNpbmcgdG1hcCBwYWNrYWdlDQoNCiMjIyBxdWljayB0bWFwDQoNCmBgYHtyfQ0KcXRtKGJsb2Nrc19zZiwgZmlsbD0ib3JhbmdlIiwgc3R5bGU9Im5hdHVyYWwiKQ0KIyBjb2xvcnMoKQ0KYGBgDQojIyMgUWljayB0bWFwOiBjaG9yb3BsZXRoDQpgYGB7cn0NCnF0bShibG9ja3Nfc2YsIGZpbGw9IlBfVkFDQU5UIiwgZmlsbC50aXRsZT0iVmFjYW50ICUiLCB0aXRsZT0iTXkgTWFwIDEiKQ0KYGBgDQojIyMgUWljayB0bWFwOiBidWJibGUgbWFwDQpgYGB7cn0NCnF0bShibG9ja3Nfc2YsIHN5bWJvbHMuc2l6ZT0iUF9WQUNBTlQiLCBzeW1ib2xzLnRpdGxlLnNpemU9IlZhY2FudCAlIiwgdGl0bGU9Ik15IEJ1YmJsZSBNYXAiKQ0KYGBgDQojIyMgT3ZlcmxheSBtdWx0aXBsZSBwbG90cw0KYGBge3J9DQpseXIxIDwtIHF0bShibG9ja3Nfc2YsIGZpbGw9IlBfVkFDQU5UIiwgZmlsbC50aXRsZT0iVmFjYW50ICUiLCB0aXRsZT0iTXkgTWFwIDEiKQ0KbHlyX3JvYWQgPC0gdG1fc2hhcGUocm9hZHNfc2YpK3RtX2xpbmVzKGNvbD0iZ3JheSIpICMgbGluZXMNCmx5cl9jcmltZXMgPC0gdG1fc2hhcGUoYnJlYWNoX3NmKSt0bV9kb3RzKGNvbD0icmVkIiwgc2l6ZT0gMC4xKSAjIHBvaW50cw0KDQojIG92ZXJsYXkgbXVsdGlwbGUgcGxvdHMNCmx5cjEgKyBseXJfcm9hZCArIGx5cl9jcmltZXMNCmBgYA0KIyMjIFNob3dpbmcgbXVsdGlwbGUgcGxvdHMvbWFwcw0KDQpgYGB7cn0NCmxpYnJhcnkoZ3JpZCkNCiMgb3BlbiBhIG5ldyBwbG90IHBhZ2UNCg0KZ3JpZC5uZXdwYWdlKCkNCiMgc2V0IHVwIHRoZSBsYXlvdXQNCnB1c2hWaWV3cG9ydCh2aWV3cG9ydChsYXlvdXQ9Z3JpZC5sYXlvdXQoMSwyKSkpDQoNCiMgcGxvdCB1c2luZyB0aGUgcHJpbnQgY29tbWFuZA0KcHJpbnQobHlyMSwgdnA9dmlld3BvcnQobGF5b3V0LnBvcy5jb2wgPSAxKSkNCnByaW50KGx5cl9yb2FkLCB2cD12aWV3cG9ydChsYXlvdXQucG9zLmNvbCA9IDIpKQ0KDQojIGRldi5vZmYoKSAjIGNsb3NlIHBsb3R0aW5nIGRldmljZQ0KDQpgYGANCg0KIyAyLiBBdHRyaWJ1dGUgUXVlcnkNCg0KYGBge3J9DQppbmRleCA8LSAoYmxvY2tzX3NmJFBfVkFDQU5UID4gMTApDQpuZXdibG9ja3Nfc2YgPC0gYmxvY2tzX3NmW2luZGV4LF0NCmx5cjMgPC0gcXRtKG5ld2Jsb2Nrc19zZiwgZmlsbD0icmVkIiwgdGl0bGU9IlZhY2FudCA+IDEwJSIsIHN0eWxlPSJuYXR1cmFsIikNCmx5cl9iZyA8LSBxdG0oYmxvY2tzX3NmLCBmaWxsPSJncmV5IikNCmx5cl9iZyArIGx5cjMNCmBgYA0KDQojIDMuIENhbGN1bGF0aW5nIEZpZWxkcw0KDQojIyBjcmVhdGUgYSBmaWVsZA0KYGBge3J9DQp4IDwtIHN0X2FyZWEoYmxvY2tzX3NmKSAjIHVuaXQ6IGZvb3QNCg0KbGlicmFyeSh1bml0cykNCngyIDwtIHNldF91bml0cyh4LCBrbV4yKQ0KYmxvY2tzX3NmJEFSRUExIDwtIHgyDQpjb2xuYW1lcyhibG9ja3Nfc2YpDQpgYGANCiMjIHJlbW92ZSBhIGZpZWxkDQpgYGB7cn0NCmJsb2Nrc19zZiA8LSBzdWJzZXQoYmxvY2tzX3NmLCBzZWxlY3QgPSAtYyhBUkVBMSkpDQpjb2xuYW1lcyhibG9ja3Nfc2YpDQpgYGANCg0KIyMgY2FsY3VsYXRpbmcgdmFsdWVzDQpgYGB7cn0NCngyIDwtIHNldF91bml0cyh4LCBrbV4yKQ0KYmxvY2tzX3NmJEFSRUExIDwtIHgyDQoNCmJsb2Nrc19zZiRQT1BERU4gPC0gYmxvY2tzX3NmJFBPUDE5OTAgLyBibG9ja3Nfc2YkQVJFQTENCg0KcGxvdChibG9ja3Nfc2ZbIlBPUERFTiJdLCBicmVha3MgPSAiamVua3MiLCBuYnJlYWtzID0gNiwgcGFsPSBicmV3ZXIuYmx1ZXMoNikpDQpxdG0oYmxvY2tzX3NmLCBmaWxsPSJQT1BERU4iLCBmaWxsLnRpdGxlPSJQb3B1bGF0aW9uIERlbnNpdHkiLCB0aXRsZT0iUG9wbiBNYXAiLCBzdHlsZT0ibmF0dXJhbCIpDQpgYGANCiMgNC4gRGV0YWlsZWQgU2V0dGluZ3MgZm9yIE1hcHBpbmcNCmBgYHtyfQ0KYnJlYWt2PC0gZ2V0QnJlYWtzKHYgPSBibG9ja3Nfc2YkUF9PV05FUk9DQywgbmNsYXNzID0gNiwgbWV0aG9kID0gImplbmtzIikNCiMgY2xhc3NpZmljYXRpb24gbWV0aG9kOiJmaXhlZCIsICJzZCIsICJlcXVhbCIsICJwcmV0dHkiLCAicXVhbnRpbGUiLCAia21lYW5zIiwgDQojICJoY2x1c3QiLCAiYmNsdXN0IiwgImZpc2hlciIsICJqZW5rcyIsICJkcGloIiwgInE2IiwgImdlb20iLCAiYXJpdGgiLCAiZW0iLCAibXNkIiANCg0KdG1fc2hhcGUoYmxvY2tzX3NmKSArDQogIHRtX3BvbHlnb25zKCJQX09XTkVST0NDIiwgdGl0bGUgPSAiT3duZXIgT2NjIiwgcGFsZXR0ZSA9ICItR25CdSIsIA0KICAgICAgICAgICAgICBicmVha3MgPSBjKGJyZWFrdiksIA0KICAgICAgICAgICAgICBsZWdlbmQuaGlzdCA9IFQpICsNCiAgdG1fc2NhbGVfYmFyKHdpZHRoID0gMC4yMikgKw0KICB0bV9jb21wYXNzKHBvc2l0aW9uID0gYygwLjgsIDAuMDgpKSArDQogIHRtX2xheW91dChmcmFtZSA9IEYsIHRpdGxlID0gIk5ldyBIYXZlbiIsIA0KICAgICAgICAgICAgdGl0bGUuc2l6ZSA9IDIsIHRpdGxlLnBvc2l0aW9uID0gYygwLjU1LCAidG9wIiksIA0KICAgICAgICAgICAgbGVnZW5kLmhpc3Quc2l6ZSA9IDAuNSkNCmBgYA0KDQoNCiMgNS4gU3RhdGlzdGljYWwgUGxvdHMNCg0KIyMgSGlzdG9ncmFtDQpgYGB7cn0NCmhpc3QoYmxvY2tzX3NmJFBfVkFDQU5ULCBicmVha3MgPSA0MCwgY29sID0gImdyZXkiLCANCiAgICAgYm9yZGVyID0gInJlZCIsIA0KICAgICBtYWluID0gIlRoZSBoaXN0b2dyYW0gb2YgdmFjYW50IHByb3BlcnR5IHBlcmNlbnRhZ2VzIiwgDQogICAgIHhsYWIgPSAicGVyY2VudGFnZSB2YWNhbnQiLCB4bGltID0gYygwLDQwKSkNCmBgYA0KIyMgdXNpbmcgZ2dwbG90MjogaGlzdG9ncmFtDQpgYGB7cn0NCmxpYnJhcnkoZ2dwbG90MikNCmJsb2Nrc19kZiA8LSBhcy5kYXRhLmZyYW1lKGJsb2Nrc19zZikNCmhlYWQoYmxvY2tzX2RmKQ0KDQpwbG90MTwtIGdncGxvdChibG9ja3NfZGYpICsgYWVzKFBfVkFDQU5UKSArDQogICAgICAgICAgZ2VvbV9oaXN0b2dyYW0oY29sID0gInJlZCIsIGZpbGwgPSAiZ3JleSIsIGJpbnMgPSA0MCkgKw0KICAgICAgICAgIHhsYWIoInBlcmNlbnRhZ2UgdmFjYW50IikgKw0KICAgICAgICAgIGxhYnModGl0bGUgPSAiVGhlIGhpc3RvZ3JhbSBvZiB2YWNhbnQgcHJvcGVydHkgcGVyY2VudGFnZXMiKQ0KDQpwbG90MQ0KYGBgDQoNCiMjIEJveHBsb3QNCmBgYHtyfQ0KYm94cGxvdChibG9ja3Nfc2YkUF9XSElULCBibG9ja3Nfc2YkUF9CTEFDSywgbmFtZXM9YygiV2hpdGUiLCAiQmxhY2siKSwgDQogICAgICAgIHhsYWI9IlJhY2UiLCB5bGFiPSJQZXJjZW50YWdlIikNCmBgYA0KDQojIyB1c2luZyBnZ3Bsb3QyOiBib3hwbG90DQpgYGB7cn0NCmxpYnJhcnkocmVzaGFwZTIpDQpibG9ja19wcm9wIDwtIG1lbHQoYmxvY2tzX2RmWywgYygiUF9XSElURSIsICJQX0JMQUNLIiwgIlBfQU1FUklfRVMiKV0pDQpoZWFkKGJsb2NrX3Byb3ApDQoNCnBsb3QyIDwtIGdncGxvdChibG9ja19wcm9wKSArIA0KICAgICAgICAgICBhZXModmFyaWFibGUsIHZhbHVlKSArDQogICAgICAgICAgIGdlb21fYm94cGxvdCgpDQoNCnBsb3QyDQoNCmBgYA0KIyMgU2hvd2luZyBtYXAgKyBwbG90DQoNCmBgYHtyfQ0KZ3JpZC5uZXdwYWdlKCkNCnB1c2hWaWV3cG9ydCh2aWV3cG9ydChsYXlvdXQ9Z3JpZC5sYXlvdXQoMSwyKSkpDQpwcmludChseXIxK2x5cl9jcmltZXMsIHZwPXZpZXdwb3J0KGxheW91dC5wb3MuY29sID0gMSkpDQpwcmludChwbG90MiwgdnA9dmlld3BvcnQobGF5b3V0LnBvcy5jb2wgPSAyKSkNCg0KI2Rldi5vZmYoKQ0KDQpgYGANCg0K