7.2 芝加哥汽車竊案、資料探索
7.2.1 讀進、轉換資料
# Load our data:
mvt = read.csv("data/mvt.csv", stringsAsFactors=FALSE) #we have a text field, and we want to make sure it's read in properly.
str(mvt)
'data.frame': 191641 obs. of 3 variables:
$ Date : chr "12/31/12 23:15" "12/31/12 22:00" "12/31/12 22:00" "12/31/12 22:00" ...
$ Latitude : num 41.8 41.9 42 41.8 41.8 ...
$ Longitude: num -87.6 -87.7 -87.8 -87.7 -87.6 ...
# Convert the Date variable to a format that R will recognize:
mvt$Date = strptime(mvt$Date, format="%m/%d/%y %H:%M") #這樣就會有日期跟時間
7.2.2 星期換算
# Extract the hour and the day of the week:
mvt$Weekday = weekdays(mvt$Date)
mvt$Hour = mvt$Date$hour
str(mvt)
'data.frame': 191641 obs. of 5 variables:
$ Date : POSIXlt, format: "2012-12-31 23:15:00" ...
$ Latitude : num 41.8 41.9 42 41.8 41.8 ...
$ Longitude: num -87.6 -87.7 -87.8 -87.7 -87.6 ...
$ Weekday : chr "Monday" "Monday" "Monday" "Monday" ...
$ Hour : int 23 22 22 22 21 20 20 20 19 18 ...
# Create a simple line plot - need the total number of crimes on
# each day of the week. We can get this information by creating a table:
table(mvt$Weekday)
Friday Monday Saturday Sunday Thursday Tuesday
29284 27397 27118 26316 27319 26791
Wednesday
27416
# Save this table as a data frame:
WeekdayCounts = as.data.frame(table(mvt$Weekday))
str(WeekdayCounts)
'data.frame': 7 obs. of 2 variables:
$ Var1: Factor w/ 7 levels "Friday","Monday",..: 1 2 3 4 5 6 7
$ Freq: int 29284 27397 27118 26316 27319 26791 27416
7.2.3 簡單線圖
# Load the ggplot2 library:
library(ggplot2)
ggplot(WeekdayCounts, aes(x=Var1, y=Freq)) +
geom_line(aes(group=1)) #This just groups all of our data into one line,since we want one line in our plot.

7.2.4 星期類別順序
# Make the "Var1" variable an ORDERED factor variable
WeekdayCounts$Var1 = factor(WeekdayCounts$Var1, ordered=TRUE,
levels=c("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday",
"Friday","Saturday")) #會按照這個順序畫
# Try again:
ggplot(WeekdayCounts, aes(x=Var1, y=Freq)) +
geom_line(aes(group=1))

7.2.5 改變X、Y軸標題
# Change our x and y labels:
ggplot(WeekdayCounts, aes(x=Var1, y=Freq)) +
geom_line(aes(group=1), alpha=0.3) +
xlab("Day of the Week") + ylab("Total Motor Vehicle Thefts")

7.2.5 七天、24小時
# VIDEO 4 - Adding the Hour of the Day
# Create a counts table for the weekday and hour:
table(mvt$Weekday, mvt$Hour)
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
星期一 1900 825 712 527 415 542 772 1123 1323 1235 971 737 1129 824 958 1059
星期二 1691 777 603 464 414 520 845 1118 1175 1174 948 786 1108 762 908 1071
星期三 1814 790 619 469 396 561 862 1140 1329 1237 947 763 1225 804 863 1075
星期五 1873 932 743 560 473 602 839 1203 1268 1286 938 822 1207 857 937 1140
星期六 2050 1267 985 836 652 508 541 650 858 1039 946 789 1204 767 963 1086
星期日 2028 1236 1019 838 607 461 478 483 615 864 884 787 1192 789 959 1037
星期四 1856 816 696 508 400 534 799 1135 1298 1301 932 731 1093 752 831 1044
16 17 18 19 20 21 22 23
星期一 1136 1252 1518 1503 1622 1815 2009 1490
星期二 1090 1274 1553 1496 1696 1816 2044 1458
星期三 1076 1289 1580 1507 1718 1748 2093 1511
星期五 1165 1318 1623 1652 1736 1881 2308 1921
星期六 1055 1084 1348 1390 1570 1702 2078 1750
星期日 1083 1160 1389 1342 1706 1696 2079 1584
星期四 1131 1258 1510 1537 1668 1776 2134 1579
# Save this to a data frame:
DayHourCounts = as.data.frame(table(mvt$Weekday, mvt$Hour))
str(DayHourCounts)
'data.frame': 168 obs. of 3 variables:
$ Var1: Factor w/ 7 levels "星期一","星期二",..: 1 2 3 4 5 6 7 1 2 3 ...
$ Var2: Factor w/ 24 levels "0","1","2","3",..: 1 1 1 1 1 1 1 2 2 2 ...
$ Freq: int 1900 1691 1814 1873 2050 2028 1856 825 777 790 ...
# Convert the second variable, Var2, to numbers and call it Hour:
DayHourCounts$Hour = as.numeric(as.character(DayHourCounts$Var2))
7.2.6 畫出 7 x 24 趨勢線圖
# Create out plot:
ggplot(DayHourCounts, aes(x=Hour, y=Freq)) +
geom_line(aes(group=Var1)) #Var1就是weekday

# Change the colors
ggplot(DayHourCounts, aes(x=Hour, y=Freq)) +
geom_line(aes(group=Var1, color=Var1), size=2)

# 區分周末、周間
DayHourCounts$Type = ifelse(
(DayHourCounts$Var1 == "Sunday") | (DayHourCounts$Var1 == "Saturday"),
"Weekend", "Weekday")
Warning message:
In strsplit(code, "\n", fixed = TRUE) :
input string 1 is invalid in this locale
# Redo our plot, this time coloring by Type:
ggplot(DayHourCounts, aes(x=Hour, y=Freq)) +
geom_line(aes(group=Var1, color=Type), size=2)

# Make the lines a little transparent:
ggplot(DayHourCounts, aes(x=Hour, y=Freq)) +
geom_line(aes(group=Var1, color=Type), size=2, alpha=0.5) #alpha變透明
Warning message:
In strsplit(code, "\n", fixed = TRUE) :
input string 1 is invalid in this locale

7.2.6 畫出 7 x 24 熱圖
# 星期類別順序重整 #The x and y-axes in a heat map don't need to be continuous.
DayHourCounts$Var1 = factor(DayHourCounts$Var1, ordered=TRUE,
levels=c("Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
"Saturday", "Sunday")) #the third argument is the order we want the days of the week to show up in.
Warning message:
In strsplit(code, "\n", fixed = TRUE) :
input string 1 is invalid in this locale
# Make a heatmap:
ggplot(DayHourCounts, aes(x = Hour, y = Var1)) +
geom_tile(aes(fill = Freq)) #geom_tile畫熱圖

# Change the label on the legend, and get rid of the y-label:
ggplot(DayHourCounts, aes(x = Hour, y = Var1)) +
geom_tile(aes(fill = Freq)) +
scale_fill_gradient(name="Total MV Thefts") +
theme(axis.title.y = element_blank())

# Change the color scheme
ggplot(DayHourCounts, aes(x = Hour, y = Var1)) +
geom_tile(aes(fill = Freq)) +
scale_fill_gradient(name="Total MV Thefts", low="white", high="red") +
theme(axis.title.y = element_blank())

7.2.7 互動式熱圖
table(format(mvt$Date,'%H'), format(mvt$Date,'%w'))%>% t %>%
heatmap(NA,NA,scale='none',col=cm.colors(25))

7.2 芝加哥汽車竊案、地圖套製
7.2.8 透過 maps 和 ggmap 套件抓取地圖
library(maps)
Warning message:
In strsplit(code, "\n", fixed = TRUE) :
input string 1 is invalid in this locale
library(ggmap)
# Load a map of Chicago into R:
chicago = get_map(location = "chicago", zoom = 11) #先把地圖抓下來存在一個地方
Map from URL : http://maps.googleapis.com/maps/api/staticmap?center=chicago&zoom=11&size=640x640&scale=2&maptype=terrain&language=en-EN&sensor=false
Information from URL : http://maps.googleapis.com/maps/api/geocode/json?address=chicago&sensor=false
# Look at the map
chicago = ggmap(chicago) #ggmap畫地圖
chicago

# 可以畫高雄市嗎 ?
ggmap(get_map(location = "kaohsiung", zoom = 12))
Map from URL : http://maps.googleapis.com/maps/api/staticmap?center=kaohsiung&zoom=12&size=640x640&scale=2&maptype=terrain&language=en-EN&sensor=false
Information from URL : http://maps.googleapis.com/maps/api/geocode/json?address=kaohsiung&sensor=false
Warning message:
In strsplit(code, "\n", fixed = TRUE) :
input string 1 is invalid in this locale

7.2.9 標記單一事件
# Plot the first 100 motor vehicle thefts:
chicago + geom_point(
data = mvt[1:100,], aes(x = Longitude, y = Latitude)) #經緯度
Warning message:
In strsplit(code, "\n", fixed = TRUE) :
input string 1 is invalid in this locale

7.2.9 依座標集收事件
# Round our latitude and longitude to 2 digits of accuracy,
# and create a crime counts data frame for each area:
LatLonCounts = as.data.frame(table(round(mvt$Longitude,2), #把小數點2位以下集收起來
round(mvt$Latitude,2)))
Warning message:
In strsplit(code, "\n", fixed = TRUE) :
input string 1 is invalid in this locale
str(LatLonCounts)
'data.frame': 1638 obs. of 3 variables:
$ Var1: Factor w/ 42 levels "-87.93","-87.92",..: 1 2 3 4 5 6 7 8 9 10 ...
$ Var2: Factor w/ 39 levels "41.64","41.65",..: 1 1 1 1 1 1 1 1 1 1 ...
$ Freq: int 0 0 0 0 0 0 0 0 0 0 ...
# Convert our Longitude and Latitude variable to numbers:
LatLonCounts$Long = as.numeric(as.character(LatLonCounts$Var1))
LatLonCounts$Lat = as.numeric(as.character(LatLonCounts$Var2))
# Plot these points on our map:
chicago + geom_point(data = LatLonCounts,
aes(x = Long, y = Lat, color = Freq, size=Freq))

# Change the color scheme:
chicago + geom_point(data = LatLonCounts,
aes(x=Long, y=Lat, color=Freq, size=Freq)) +
scale_colour_gradient(low="yellow", high="red")

7.2.10 格狀圖
# We can also use the geom_tile geometry
chicago + geom_tile(data = LatLonCounts,
aes(x = Long, y = Lat, alpha = Freq),
fill="red")

# 移除沒有事件的區格(0的濾掉)
LatLonCounts2 = subset(LatLonCounts, Freq > 0)
Warning message:
In strsplit(code, "\n", fixed = TRUE) :
input string 1 is invalid in this locale
chicago + geom_tile(data = LatLonCounts2,
aes(x = Long, y = Lat, alpha = Freq),
fill="red")

7.2.11 事件密度圖
# density plot
chicago + stat_density_2d(data=mvt,
aes(x=Longitude, y=Latitude, alpha=..level..),
fill='orange', color='pink', size=0.01, bins=8, geom='polygon') +
scale_alpha(range = c(0.05, 0.45))

7.2 槍枝持有率與謀殺比率
# VIDEO 6 - Geographical Map on US
# Load our data:
murders = read.csv("data/murders.csv")
str(murders)
'data.frame': 51 obs. of 6 variables:
$ State : Factor w/ 51 levels "Alabama","Alaska",..: 1 2 3 4 5 6 7 8 9 10 ...
$ Population : int 4779736 710231 6392017 2915918 37253956 5029196 3574097 897934 601723 19687653 ...
$ PopulationDensity: num 94.65 1.26 57.05 56.43 244.2 ...
$ Murders : int 199 31 352 130 1811 117 131 48 131 987 ...
$ GunMurders : int 135 19 232 93 1257 65 97 38 99 669 ...
$ GunOwnership : num 0.517 0.578 0.311 0.553 0.213 0.347 0.167 0.255 0.036 0.245 ...
7.2.12 Read and Plot US Map
# Load the map of the US
statesMap = map_data("state") #map_data("state")將行政州界圖抓下來
Warning message:
In strsplit(code, "\n", fixed = TRUE) :
input string 1 is invalid in this locale
str(statesMap)
'data.frame': 15537 obs. of 6 variables:
$ long : num -87.5 -87.5 -87.5 -87.5 -87.6 ...
$ lat : num 30.4 30.4 30.4 30.3 30.3 ...
$ group : num 1 1 1 1 1 1 1 1 1 1 ...
$ order : int 1 2 3 4 5 6 7 8 9 10 ...
$ region : chr "alabama" "alabama" "alabama" "alabama" ...
$ subregion: chr NA NA NA NA ...
# Plot the map:
ggplot(statesMap, aes(x = long, y = lat, group = group)) +
geom_polygon(fill = "white", color = "black")

7.2.13 Merge the Dataframes (stateMap and murders)
# Create a new variable called region with the lowercase names to
# match the statesMap:
murders$region = tolower(murders$State)
Warning message:
In strsplit(code, "\n", fixed = TRUE) :
input string 1 is invalid in this locale
# Join the statesMap data and the murders data into one dataframe:
murderMap = merge(statesMap, murders, by="region")
str(murderMap) #15537之所以會那麼多是因為他會把很多個多邊形接起來變成州界
'data.frame': 15537 obs. of 12 variables:
$ region : chr "alabama" "alabama" "alabama" "alabama" ...
$ long : num -87.5 -87.5 -87.5 -87.5 -87.6 ...
$ lat : num 30.4 30.4 30.4 30.3 30.3 ...
$ group : num 1 1 1 1 1 1 1 1 1 1 ...
$ order : int 1 2 3 4 5 6 7 8 9 10 ...
$ subregion : chr NA NA NA NA ...
$ State : Factor w/ 51 levels "Alabama","Alaska",..: 1 1 1 1 1 1 1 1 1 1 ...
$ Population : int 4779736 4779736 4779736 4779736 4779736 4779736 4779736 4779736 4779736 4779736 ...
$ PopulationDensity: num 94.7 94.7 94.7 94.7 94.7 ...
$ Murders : int 199 199 199 199 199 199 199 199 199 199 ...
$ GunMurders : int 135 135 135 135 135 135 135 135 135 135 ...
$ GunOwnership : num 0.517 0.517 0.517 0.517 0.517 0.517 0.517 0.517 0.517 0.517 ...
#group要整理,否則資料不順會畫不出來
7.2.14 Map-1: No. Murders per State
# Plot the number of murder on our map of the United States:
ggplot(murderMap, aes(x = long, y = lat, group = group, fill = Murders)) +
geom_polygon(color = "black") +
scale_fill_gradient(low = "black", high = "red", guide = "legend")

7.2.15 Map-2: Populations per State
# Plot a map of the population:
ggplot(murderMap, aes(x = long, y = lat, group = group, fill = Population)) +
geom_polygon(color = "black") +
scale_fill_gradient(low = "black", high = "red", guide = "legend")

7.2.16 Map-3: No. Murders per 100K Population
# Create a new variable that is the number of murders per 100,000 population:
murderMap$MurderRate = murderMap$Murders / murderMap$Population * 100000
# Redo our plot with murder rate:
ggplot(murderMap, aes(x = long, y = lat, group = group, fill = MurderRate)) +
geom_polygon(color = "black") +
scale_fill_gradient(low = "black", high = "red", guide = "legend")

7.2.17 Map-4: No. Murders per 100K Population with Filter
# Redo the plot, Cap the Murderrate at 10:
ggplot(murderMap, aes(x = long, y = lat, group = group, fill = MurderRate)) +
geom_polygon(color = "black") +
scale_fill_gradient(low = "black", high = "red",
guide = "legend", limits = c(0,10))

7.2.18 Map-5: Gun Ownership (%) by States
ggplot(murderMap,aes(x=long,y=lat,group=group,fill=GunOwnership)) +
geom_polygon(color = "black") +
scale_fill_gradient(low = "black", high = "red", guide = "legend")

7.2.19 Gun Ownership (%) by States
tapply(murderMap$GunOwnership, murderMap$region, mean) %>% sort %>%
barplot(las=2, cex.names=0.6, main="Averge GunOwnerShip (%)")

LS0tDQp0aXRsZTogIkFTNy0wQiDlnLDnkIbos4fmlpnoo73lnJYiDQphdXRob3I6ICLkvZXoqp7lqZUgTTA2NDAyMDA0MCwgMjAxOC8wNy8zMSINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCjxicj4NCg0KYGBge3IgZWNobz1ULCBtZXNzYWdlPUYsIGNhY2hlPUYsIHdhcm5pbmc9Rn0NCnJtKGxpc3Q9bHMoYWxsPVQpKQ0Kb3B0aW9ucyhkaWdpdHM9NCwgc2NpcGVuPTEyKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkobWFwcykNCmxpYnJhcnkoZ2dtYXApDQpgYGANCg0KLSAtIC0NCg0KIyMjIDcuMiDoip3liqDlk6Xmsb3ou4rnq4rmoYjjgIHos4fmlpnmjqLntKINCg0KIyMjIyMgNy4yLjEg6K6A6YCy44CB6L2J5o+b6LOH5paZDQpgYGB7cn0NCiMgTG9hZCBvdXIgZGF0YToNCm12dCA9IHJlYWQuY3N2KCJkYXRhL212dC5jc3YiLCBzdHJpbmdzQXNGYWN0b3JzPUZBTFNFKSAjd2UgaGF2ZSBhIHRleHQgZmllbGQsIGFuZCB3ZSB3YW50IHRvIG1ha2Ugc3VyZSBpdCdzIHJlYWQgaW4gcHJvcGVybHkuDQpzdHIobXZ0KQ0KDQojIENvbnZlcnQgdGhlIERhdGUgdmFyaWFibGUgdG8gYSBmb3JtYXQgdGhhdCBSIHdpbGwgcmVjb2duaXplOg0KbXZ0JERhdGUgPSBzdHJwdGltZShtdnQkRGF0ZSwgZm9ybWF0PSIlbS8lZC8leSAlSDolTSIpICAj6YCZ5qij5bCx5pyD5pyJ5pel5pyf6Lef5pmC6ZaTDQpgYGANCg0KIyMjIyMgNy4yLjIg5pif5pyf5o+b566XDQpgYGB7cn0NCiMgRXh0cmFjdCB0aGUgaG91ciBhbmQgdGhlIGRheSBvZiB0aGUgd2VlazoNCm12dCRXZWVrZGF5ID0gd2Vla2RheXMobXZ0JERhdGUpDQptdnQkSG91ciA9IG12dCREYXRlJGhvdXINCnN0cihtdnQpDQoNCiMgQ3JlYXRlIGEgc2ltcGxlIGxpbmUgcGxvdCAtIG5lZWQgdGhlIHRvdGFsIG51bWJlciBvZiBjcmltZXMgb24gDQojIGVhY2ggZGF5IG9mIHRoZSB3ZWVrLiBXZSBjYW4gZ2V0IHRoaXMgaW5mb3JtYXRpb24gYnkgY3JlYXRpbmcgYSB0YWJsZToNCnRhYmxlKG12dCRXZWVrZGF5KQ0KDQojIFNhdmUgdGhpcyB0YWJsZSBhcyBhIGRhdGEgZnJhbWU6DQpXZWVrZGF5Q291bnRzID0gYXMuZGF0YS5mcmFtZSh0YWJsZShtdnQkV2Vla2RheSkpDQpzdHIoV2Vla2RheUNvdW50cykgDQpgYGANCg0KIyMjIyMgNy4yLjMg57Ch5Zau57ea5ZyWDQpgYGB7cn0NCiMgTG9hZCB0aGUgZ2dwbG90MiBsaWJyYXJ5Og0KbGlicmFyeShnZ3Bsb3QyKQ0KZ2dwbG90KFdlZWtkYXlDb3VudHMsIGFlcyh4PVZhcjEsIHk9RnJlcSkpICsgDQogIGdlb21fbGluZShhZXMoZ3JvdXA9MSkpICAjVGhpcyBqdXN0IGdyb3VwcyBhbGwgb2Ygb3VyIGRhdGEgaW50byBvbmUgbGluZSxzaW5jZSB3ZSB3YW50IG9uZSBsaW5lIGluIG91ciBwbG90Lg0KYGBgDQoNCiMjIyMjIDcuMi40IOaYn+acn+mhnuWIpemghuW6jw0KYGBge3J9DQojIE1ha2UgdGhlICJWYXIxIiB2YXJpYWJsZSBhbiBPUkRFUkVEIGZhY3RvciB2YXJpYWJsZQ0KV2Vla2RheUNvdW50cyRWYXIxID0gZmFjdG9yKFdlZWtkYXlDb3VudHMkVmFyMSwgb3JkZXJlZD1UUlVFLCANCiAgbGV2ZWxzPWMoIlN1bmRheSIsICJNb25kYXkiLCAiVHVlc2RheSIsICJXZWRuZXNkYXkiLCAiVGh1cnNkYXkiLCANCiAgICAgICAgICAgIkZyaWRheSIsIlNhdHVyZGF5IikpICAgI+acg+aMieeFp+mAmeWAi+mghuW6j+eVqw0KDQojIFRyeSBhZ2FpbjoNCmdncGxvdChXZWVrZGF5Q291bnRzLCBhZXMoeD1WYXIxLCB5PUZyZXEpKSArIA0KICBnZW9tX2xpbmUoYWVzKGdyb3VwPTEpKQ0KYGBgDQoNCiMjIyMjIDcuMi41IOaUueiuiljjgIFZ6Lu45qiZ6aGMDQpgYGB7cn0NCiMgQ2hhbmdlIG91ciB4IGFuZCB5IGxhYmVsczoNCmdncGxvdChXZWVrZGF5Q291bnRzLCBhZXMoeD1WYXIxLCB5PUZyZXEpKSArIA0KICBnZW9tX2xpbmUoYWVzKGdyb3VwPTEpLCBhbHBoYT0wLjMpICsgDQogIHhsYWIoIkRheSBvZiB0aGUgV2VlayIpICsgeWxhYigiVG90YWwgTW90b3IgVmVoaWNsZSBUaGVmdHMiKQ0KYGBgDQoNCiMjIyMjIDcuMi41IOS4g+WkqeOAgTI05bCP5pmCDQpgYGB7cn0NCiMgVklERU8gNCAtIEFkZGluZyB0aGUgSG91ciBvZiB0aGUgRGF5DQojIENyZWF0ZSBhIGNvdW50cyB0YWJsZSBmb3IgdGhlIHdlZWtkYXkgYW5kIGhvdXI6DQp0YWJsZShtdnQkV2Vla2RheSwgbXZ0JEhvdXIpDQoNCiMgU2F2ZSB0aGlzIHRvIGEgZGF0YSBmcmFtZToNCkRheUhvdXJDb3VudHMgPSBhcy5kYXRhLmZyYW1lKHRhYmxlKG12dCRXZWVrZGF5LCBtdnQkSG91cikpDQpzdHIoRGF5SG91ckNvdW50cykNCg0KIyBDb252ZXJ0IHRoZSBzZWNvbmQgdmFyaWFibGUsIFZhcjIsIHRvIG51bWJlcnMgYW5kIGNhbGwgaXQgSG91cjoNCkRheUhvdXJDb3VudHMkSG91ciA9IGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKERheUhvdXJDb3VudHMkVmFyMikpDQpgYGANCg0KIyMjIyMgNy4yLjYg55Wr5Ye6IDcgeCAyNCDotqjli6Lnt5rlnJYgDQpgYGB7cn0NCiMgQ3JlYXRlIG91dCBwbG90Og0KZ2dwbG90KERheUhvdXJDb3VudHMsIGFlcyh4PUhvdXIsIHk9RnJlcSkpICsNCiAgZ2VvbV9saW5lKGFlcyhncm91cD1WYXIxKSkgICNWYXIx5bCx5pivd2Vla2RheQ0KYGBgDQoNCmBgYHtyfQ0KIyBDaGFuZ2UgdGhlIGNvbG9ycw0KZ2dwbG90KERheUhvdXJDb3VudHMsIGFlcyh4PUhvdXIsIHk9RnJlcSkpICsgDQogIGdlb21fbGluZShhZXMoZ3JvdXA9VmFyMSwgY29sb3I9VmFyMSksIHNpemU9MikNCmBgYA0KDQpgYGB7cn0NCiMg5Y2A5YiG5ZGo5pyr44CB5ZGo6ZaTDQpEYXlIb3VyQ291bnRzJFR5cGUgPSBpZmVsc2UoDQogIChEYXlIb3VyQ291bnRzJFZhcjEgPT0gIlN1bmRheSIpIHwgKERheUhvdXJDb3VudHMkVmFyMSA9PSAiU2F0dXJkYXkiKSwgDQogICJXZWVrZW5kIiwgIldlZWtkYXkiKQ0KDQojIFJlZG8gb3VyIHBsb3QsIHRoaXMgdGltZSBjb2xvcmluZyBieSBUeXBlOg0KZ2dwbG90KERheUhvdXJDb3VudHMsIGFlcyh4PUhvdXIsIHk9RnJlcSkpICsgDQogIGdlb21fbGluZShhZXMoZ3JvdXA9VmFyMSwgY29sb3I9VHlwZSksIHNpemU9MikgDQpgYGANCg0KYGBge3J9DQojIE1ha2UgdGhlIGxpbmVzIGEgbGl0dGxlIHRyYW5zcGFyZW50Og0KZ2dwbG90KERheUhvdXJDb3VudHMsIGFlcyh4PUhvdXIsIHk9RnJlcSkpICsgDQogIGdlb21fbGluZShhZXMoZ3JvdXA9VmFyMSwgY29sb3I9VHlwZSksIHNpemU9MiwgYWxwaGE9MC41KSAgI2FscGhh6K6K6YCP5piODQpgYGANCg0KIyMjIyMgNy4yLjYg55Wr5Ye6IDcgeCAyNCDnhrHlnJYNCg0KYGBge3J9DQojIOaYn+acn+mhnuWIpemghuW6j+mHjeaVtCAgI1RoZSB4IGFuZCB5LWF4ZXMgaW4gYSBoZWF0IG1hcCBkb24ndCBuZWVkIHRvIGJlIGNvbnRpbnVvdXMuDQpEYXlIb3VyQ291bnRzJFZhcjEgPSBmYWN0b3IoRGF5SG91ckNvdW50cyRWYXIxLCBvcmRlcmVkPVRSVUUsIA0KICBsZXZlbHM9YygiTW9uZGF5IiwgIlR1ZXNkYXkiLCAiV2VkbmVzZGF5IiwgIlRodXJzZGF5IiwgIkZyaWRheSIsIA0KICAgICAgICAgICAiU2F0dXJkYXkiLCAiU3VuZGF5IikpICAjdGhlIHRoaXJkIGFyZ3VtZW50IGlzIHRoZSBvcmRlciB3ZSB3YW50IHRoZSBkYXlzIG9mIHRoZSB3ZWVrIHRvIHNob3cgdXAgaW4uDQoNCiMgTWFrZSBhIGhlYXRtYXA6DQpnZ3Bsb3QoRGF5SG91ckNvdW50cywgYWVzKHggPSBIb3VyLCB5ID0gVmFyMSkpICsgDQogIGdlb21fdGlsZShhZXMoZmlsbCA9IEZyZXEpKSAgI2dlb21fdGlsZeeVq+eGseWclg0KYGBgDQoNCmBgYHtyfQ0KIyBDaGFuZ2UgdGhlIGxhYmVsIG9uIHRoZSBsZWdlbmQsIGFuZCBnZXQgcmlkIG9mIHRoZSB5LWxhYmVsOg0KZ2dwbG90KERheUhvdXJDb3VudHMsIGFlcyh4ID0gSG91ciwgeSA9IFZhcjEpKSArIA0KICBnZW9tX3RpbGUoYWVzKGZpbGwgPSBGcmVxKSkgKyANCiAgc2NhbGVfZmlsbF9ncmFkaWVudChuYW1lPSJUb3RhbCBNViBUaGVmdHMiKSArIA0KICB0aGVtZShheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCkpDQpgYGANCg0KYGBge3J9DQojIENoYW5nZSB0aGUgY29sb3Igc2NoZW1lDQpnZ3Bsb3QoRGF5SG91ckNvdW50cywgYWVzKHggPSBIb3VyLCB5ID0gVmFyMSkpICsgDQogIGdlb21fdGlsZShhZXMoZmlsbCA9IEZyZXEpKSArIA0KICBzY2FsZV9maWxsX2dyYWRpZW50KG5hbWU9IlRvdGFsIE1WIFRoZWZ0cyIsIGxvdz0id2hpdGUiLCBoaWdoPSJyZWQiKSArIA0KICB0aGVtZShheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCkpDQpgYGANCg0KIyMjIyMgNy4yLjcg5LqS5YuV5byP54ax5ZyWDQpgYGB7cn0NCnRhYmxlKGZvcm1hdChtdnQkRGF0ZSwnJUgnKSwgZm9ybWF0KG12dCREYXRlLCcldycpKSU+JSB0ICU+JSANCiAgaGVhdG1hcChOQSxOQSxzY2FsZT0nbm9uZScsY29sPWNtLmNvbG9ycygyNSkpDQpgYGANCjxicj4NCg0KLSAtIC0NCg0KIyMjIDcuMiDoip3liqDlk6Xmsb3ou4rnq4rmoYjjgIHlnLDlnJblpZfoo70NCg0KIyMjIyMgNy4yLjgg6YCP6YGOIGBtYXBzYCDlkowgYGdnbWFwYCDlpZfku7bmipPlj5blnLDlnJYNCmBgYHtyfQ0KbGlicmFyeShtYXBzKQ0KbGlicmFyeShnZ21hcCkNCg0KIyBMb2FkIGEgbWFwIG9mIENoaWNhZ28gaW50byBSOg0KY2hpY2FnbyA9IGdldF9tYXAobG9jYXRpb24gPSAiY2hpY2FnbyIsIHpvb20gPSAxMSkgICPlhYjmiorlnLDlnJbmipPkuIvkvoblrZjlnKjkuIDlgIvlnLDmlrkNCg0KIyBMb29rIGF0IHRoZSBtYXANCmNoaWNhZ28gPSBnZ21hcChjaGljYWdvKSAgI2dnbWFw55Wr5Zyw5ZyWDQpjaGljYWdvDQpgYGANCg0KYGBge3J9DQojIOWPr+S7peeVq+mrmOmbhOW4guWXjiA/IA0KZ2dtYXAoZ2V0X21hcChsb2NhdGlvbiA9ICJrYW9oc2l1bmciLCB6b29tID0gMTIpKQ0KYGBgDQoNCiMjIyMjIDcuMi45IOaomeiomOWWruS4gOS6i+S7tg0KYGBge3J9DQojIFBsb3QgdGhlIGZpcnN0IDEwMCBtb3RvciB2ZWhpY2xlIHRoZWZ0czoNCmNoaWNhZ28gKyBnZW9tX3BvaW50KA0KICBkYXRhID0gbXZ0WzE6MTAwLF0sIGFlcyh4ID0gTG9uZ2l0dWRlLCB5ID0gTGF0aXR1ZGUpKSAgI+e2k+e3r+W6pg0KYGBgDQoNCiMjIyMjIDcuMi45IOS+neW6p+aomembhuaUtuS6i+S7tg0KYGBge3J9DQojIFJvdW5kIG91ciBsYXRpdHVkZSBhbmQgbG9uZ2l0dWRlIHRvIDIgZGlnaXRzIG9mIGFjY3VyYWN5LCANCiMgYW5kIGNyZWF0ZSBhIGNyaW1lIGNvdW50cyBkYXRhIGZyYW1lIGZvciBlYWNoIGFyZWE6DQpMYXRMb25Db3VudHMgPSBhcy5kYXRhLmZyYW1lKHRhYmxlKHJvdW5kKG12dCRMb25naXR1ZGUsMiksICAgI+aKiuWwj+aVuOm7njLkvY3ku6XkuIvpm4bmlLbotbfkvoYNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcm91bmQobXZ0JExhdGl0dWRlLDIpKSkNCnN0cihMYXRMb25Db3VudHMpDQoNCiMgQ29udmVydCBvdXIgTG9uZ2l0dWRlIGFuZCBMYXRpdHVkZSB2YXJpYWJsZSB0byBudW1iZXJzOg0KTGF0TG9uQ291bnRzJExvbmcgPSBhcy5udW1lcmljKGFzLmNoYXJhY3RlcihMYXRMb25Db3VudHMkVmFyMSkpDQpMYXRMb25Db3VudHMkTGF0ID0gYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoTGF0TG9uQ291bnRzJFZhcjIpKQ0KDQojIFBsb3QgdGhlc2UgcG9pbnRzIG9uIG91ciBtYXA6DQpjaGljYWdvICsgZ2VvbV9wb2ludChkYXRhID0gTGF0TG9uQ291bnRzLCANCiAgICAgICAgICAgICAgICAgICAgIGFlcyh4ID0gTG9uZywgeSA9IExhdCwgY29sb3IgPSBGcmVxLCBzaXplPUZyZXEpKQ0KYGBgDQoNCmBgYHtyfQ0KIyBDaGFuZ2UgdGhlIGNvbG9yIHNjaGVtZToNCmNoaWNhZ28gKyBnZW9tX3BvaW50KGRhdGEgPSBMYXRMb25Db3VudHMsIA0KICAgICAgICAgICAgICAgICAgICAgYWVzKHg9TG9uZywgeT1MYXQsIGNvbG9yPUZyZXEsIHNpemU9RnJlcSkpICsgDQogIHNjYWxlX2NvbG91cl9ncmFkaWVudChsb3c9InllbGxvdyIsIGhpZ2g9InJlZCIpDQpgYGANCg0KIyMjIyMgNy4yLjEwIOagvOeLgOWclg0KYGBge3J9DQojIFdlIGNhbiBhbHNvIHVzZSB0aGUgZ2VvbV90aWxlIGdlb21ldHJ5DQpjaGljYWdvICsgZ2VvbV90aWxlKGRhdGEgPSBMYXRMb25Db3VudHMsIA0KICAgICAgICAgICAgICAgICAgICBhZXMoeCA9IExvbmcsIHkgPSBMYXQsIGFscGhhID0gRnJlcSksIA0KICAgICAgICAgICAgICAgICAgICBmaWxsPSJyZWQiKQ0KYGBgDQoNCmBgYHtyfQ0KIyDnp7vpmaTmspLmnInkuovku7bnmoTljYDmoLwoMOeahOa/vuaOiSkNCkxhdExvbkNvdW50czIgPSBzdWJzZXQoTGF0TG9uQ291bnRzLCBGcmVxID4gMCkNCmNoaWNhZ28gKyBnZW9tX3RpbGUoZGF0YSA9IExhdExvbkNvdW50czIsIA0KICAgICAgICAgICAgICAgICAgICBhZXMoeCA9IExvbmcsIHkgPSBMYXQsIGFscGhhID0gRnJlcSksIA0KICAgICAgICAgICAgICAgICAgICBmaWxsPSJyZWQiKQ0KYGBgDQoNCiMjIyMjIDcuMi4xMSDkuovku7blr4bluqblnJYNCmBgYHtyfQ0KIyBkZW5zaXR5IHBsb3QNCmNoaWNhZ28gKyBzdGF0X2RlbnNpdHlfMmQoZGF0YT1tdnQsIA0KICAgIGFlcyh4PUxvbmdpdHVkZSwgeT1MYXRpdHVkZSwgYWxwaGE9Li5sZXZlbC4uKSwgDQogICAgZmlsbD0nb3JhbmdlJywgY29sb3I9J3BpbmsnLCBzaXplPTAuMDEsIGJpbnM9OCwgZ2VvbT0ncG9seWdvbicpICsNCiAgc2NhbGVfYWxwaGEocmFuZ2UgPSBjKDAuMDUsIDAuNDUpKQ0KYGBgDQo8YnI+DQoNCi0gLSAtDQoNCiMjIyA3LjIg5qeN5p6d5oyB5pyJ546H6IiH6KyA5q665q+U546HDQoNCmBgYHtyfQ0KIyBWSURFTyA2IC0gR2VvZ3JhcGhpY2FsIE1hcCBvbiBVUw0KIyBMb2FkIG91ciBkYXRhOg0KbXVyZGVycyA9IHJlYWQuY3N2KCJkYXRhL211cmRlcnMuY3N2IikNCnN0cihtdXJkZXJzKQ0KYGBgDQoNCiMjIyMjIDcuMi4xMiBSZWFkIGFuZCBQbG90IFVTIE1hcA0KYGBge3J9DQojIExvYWQgdGhlIG1hcCBvZiB0aGUgVVMgICAgDQpzdGF0ZXNNYXAgPSBtYXBfZGF0YSgic3RhdGUiKSAgI21hcF9kYXRhKCJzdGF0ZSIp5bCH6KGM5pS/5bee55WM5ZyW5oqT5LiL5L6GDQpzdHIoc3RhdGVzTWFwKQ0KDQojIFBsb3QgdGhlIG1hcDoNCmdncGxvdChzdGF0ZXNNYXAsIGFlcyh4ID0gbG9uZywgeSA9IGxhdCwgZ3JvdXAgPSBncm91cCkpICsgDQogIGdlb21fcG9seWdvbihmaWxsID0gIndoaXRlIiwgY29sb3IgPSAiYmxhY2siKSANCg0KYGBgDQoNCiMjIyMjIDcuMi4xMyBNZXJnZSB0aGUgRGF0YWZyYW1lcyAoYHN0YXRlTWFwYCBhbmQgYG11cmRlcnNgKQ0KYGBge3J9DQojIENyZWF0ZSBhIG5ldyB2YXJpYWJsZSBjYWxsZWQgcmVnaW9uIHdpdGggdGhlIGxvd2VyY2FzZSBuYW1lcyB0byANCiMgbWF0Y2ggdGhlIHN0YXRlc01hcDoNCm11cmRlcnMkcmVnaW9uID0gdG9sb3dlcihtdXJkZXJzJFN0YXRlKQ0KDQojIEpvaW4gdGhlIHN0YXRlc01hcCBkYXRhIGFuZCB0aGUgbXVyZGVycyBkYXRhIGludG8gb25lIGRhdGFmcmFtZToNCm11cmRlck1hcCA9IG1lcmdlKHN0YXRlc01hcCwgbXVyZGVycywgYnk9InJlZ2lvbiIpDQpzdHIobXVyZGVyTWFwKSAgIzE1NTM35LmL5omA5Lul5pyD6YKj6bq85aSa5piv5Zug54K65LuW5pyD5oqK5b6I5aSa5YCL5aSa6YKK5b2i5o6l6LW35L6G6K6K5oiQ5bee55WMDQogICAgICAgICAgICAgICAgI2dyb3Vw6KaB5pW055CG77yM5ZCm5YmH6LOH5paZ5LiN6aCG5pyD55Wr5LiN5Ye65L6GDQpgYGANCg0KIyMjIyMgNy4yLjE0IE1hcC0xOiBOby4gTXVyZGVycyBwZXIgU3RhdGUNCmBgYHtyfQ0KIyBQbG90IHRoZSBudW1iZXIgb2YgbXVyZGVyIG9uIG91ciBtYXAgb2YgdGhlIFVuaXRlZCBTdGF0ZXM6DQpnZ3Bsb3QobXVyZGVyTWFwLCBhZXMoeCA9IGxvbmcsIHkgPSBsYXQsIGdyb3VwID0gZ3JvdXAsIGZpbGwgPSBNdXJkZXJzKSkgKyANCiAgZ2VvbV9wb2x5Z29uKGNvbG9yID0gImJsYWNrIikgKyANCiAgc2NhbGVfZmlsbF9ncmFkaWVudChsb3cgPSAiYmxhY2siLCBoaWdoID0gInJlZCIsIGd1aWRlID0gImxlZ2VuZCIpDQpgYGANCg0KIyMjIyMgNy4yLjE1IE1hcC0yOiBQb3B1bGF0aW9ucyBwZXIgU3RhdGUNCmBgYHtyfQ0KIyBQbG90IGEgbWFwIG9mIHRoZSBwb3B1bGF0aW9uOg0KZ2dwbG90KG11cmRlck1hcCwgYWVzKHggPSBsb25nLCB5ID0gbGF0LCBncm91cCA9IGdyb3VwLCBmaWxsID0gUG9wdWxhdGlvbikpICsgDQogIGdlb21fcG9seWdvbihjb2xvciA9ICJibGFjayIpICsgDQogIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93ID0gImJsYWNrIiwgaGlnaCA9ICJyZWQiLCBndWlkZSA9ICJsZWdlbmQiKQ0KYGBgDQoNCiMjIyMjIDcuMi4xNiBNYXAtMzogTm8uIE11cmRlcnMgcGVyIDEwMEsgUG9wdWxhdGlvbg0KYGBge3J9DQojIENyZWF0ZSBhIG5ldyB2YXJpYWJsZSB0aGF0IGlzIHRoZSBudW1iZXIgb2YgbXVyZGVycyBwZXIgMTAwLDAwMCBwb3B1bGF0aW9uOg0KbXVyZGVyTWFwJE11cmRlclJhdGUgPSBtdXJkZXJNYXAkTXVyZGVycyAvIG11cmRlck1hcCRQb3B1bGF0aW9uICogMTAwMDAwDQoNCiMgUmVkbyBvdXIgcGxvdCB3aXRoIG11cmRlciByYXRlOg0KZ2dwbG90KG11cmRlck1hcCwgYWVzKHggPSBsb25nLCB5ID0gbGF0LCBncm91cCA9IGdyb3VwLCBmaWxsID0gTXVyZGVyUmF0ZSkpICsgDQogIGdlb21fcG9seWdvbihjb2xvciA9ICJibGFjayIpICsgDQogIHNjYWxlX2ZpbGxfZ3JhZGllbnQobG93ID0gImJsYWNrIiwgaGlnaCA9ICJyZWQiLCBndWlkZSA9ICJsZWdlbmQiKQ0KYGBgDQoNCiMjIyMjIDcuMi4xNyBNYXAtNDogTm8uIE11cmRlcnMgcGVyIDEwMEsgUG9wdWxhdGlvbiB3aXRoIEZpbHRlcg0KYGBge3J9DQojIFJlZG8gdGhlIHBsb3QsIENhcCB0aGUgTXVyZGVycmF0ZSBhdCAxMDoNCmdncGxvdChtdXJkZXJNYXAsIGFlcyh4ID0gbG9uZywgeSA9IGxhdCwgZ3JvdXAgPSBncm91cCwgZmlsbCA9IE11cmRlclJhdGUpKSArIA0KICBnZW9tX3BvbHlnb24oY29sb3IgPSAiYmxhY2siKSArIA0KICBzY2FsZV9maWxsX2dyYWRpZW50KGxvdyA9ICJibGFjayIsIGhpZ2ggPSAicmVkIiwgDQogICAgICAgICAgICAgICAgICAgICAgZ3VpZGUgPSAibGVnZW5kIiwgbGltaXRzID0gYygwLDEwKSkNCmBgYA0KDQojIyMjIyA3LjIuMTggTWFwLTU6IEd1biBPd25lcnNoaXAgKCUpIGJ5IFN0YXRlcw0KYGBge3J9DQpnZ3Bsb3QobXVyZGVyTWFwLGFlcyh4PWxvbmcseT1sYXQsZ3JvdXA9Z3JvdXAsZmlsbD1HdW5Pd25lcnNoaXApKSArIA0KICBnZW9tX3BvbHlnb24oY29sb3IgPSAiYmxhY2siKSArIA0KICBzY2FsZV9maWxsX2dyYWRpZW50KGxvdyA9ICJibGFjayIsIGhpZ2ggPSAicmVkIiwgZ3VpZGUgPSAibGVnZW5kIikNCmBgYA0KDQojIyMjIyA3LjIuMTkgR3VuIE93bmVyc2hpcCAoJSkgYnkgU3RhdGVzDQpgYGB7ciBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD0zLjJ9DQp0YXBwbHkobXVyZGVyTWFwJEd1bk93bmVyc2hpcCwgbXVyZGVyTWFwJHJlZ2lvbiwgbWVhbikgJT4lIHNvcnQgJT4lIA0KICBiYXJwbG90KGxhcz0yLCBjZXgubmFtZXM9MC42LCBtYWluPSJBdmVyZ2UgR3VuT3duZXJTaGlwICglKSIpDQpgYGANCjxicj4NCg0KLSAtIC0NCg0KPGJyPjxicj48YnI+PGJyPjxicj4NCg0KPHN0eWxlPg0KLmNhcHRpb24gew0KICBjb2xvcjogIzc3NzsNCiAgbWFyZ2luLXRvcDogMTBweDsNCn0NCnAgY29kZSB7DQogIHdoaXRlLXNwYWNlOiBpbmhlcml0Ow0KfQ0KcHJlIHsNCiAgd29yZC1icmVhazogbm9ybWFsOw0KICB3b3JkLXdyYXA6IG5vcm1hbDsNCiAgbGluZS1oZWlnaHQ6IDE7DQp9DQpwcmUgY29kZSB7DQogIHdoaXRlLXNwYWNlOiBpbmhlcml0Ow0KfQ0KcCxsaSB7DQogIGZvbnQtZmFtaWx5OiAiVHJlYnVjaGV0IE1TIiwgIuW+rui7n+ato+m7kemrlCIsICJNaWNyb3NvZnQgSmhlbmdIZWkiOw0KfQ0KDQoucnsNCiAgbGluZS1oZWlnaHQ6IDEuMjsNCn0NCg0KdGl0bGV7DQogIGNvbG9yOiAjY2MwMDAwOw0KICBmb250LWZhbWlseTogIlRyZWJ1Y2hldCBNUyIsICLlvq7ou5/mraPpu5Hpq5QiLCAiTWljcm9zb2Z0IEpoZW5nSGVpIjsNCn0NCg0KYm9keXsNCiAgZm9udC1mYW1pbHk6ICJUcmVidWNoZXQgTVMiLCAi5b6u6Luf5q2j6buR6auUIiwgIk1pY3Jvc29mdCBKaGVuZ0hlaSI7DQp9DQoNCmgxLGgyLGgzLGg0LGg1ew0KICBjb2xvcjogIzAwODgwMDsNCiAgZm9udC1mYW1pbHk6ICJUcmVidWNoZXQgTVMiLCAi5b6u6Luf5q2j6buR6auUIiwgIk1pY3Jvc29mdCBKaGVuZ0hlaSI7DQp9DQoNCmgzew0KICBjb2xvcjogI2IzNmIwMDsNCiAgYmFja2dyb3VuZDogI2ZmZTBiMzsNCiAgbGluZS1oZWlnaHQ6IDI7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KfQ0KDQpoNXsNCiAgY29sb3I6ICMwMDYwMDA7DQogIGJhY2tncm91bmQ6ICNmZmZmZTA7DQogIGxpbmUtaGVpZ2h0OiAyOw0KICBmb250LXdlaWdodDogYm9sZDsNCn0NCg0KZW17DQogIGNvbG9yOiAjMDAwMGMwOw0KICBiYWNrZ3JvdW5kOiAjZjBmMGYwOw0KICB9DQo8L3N0eWxlPg0KDQo=