Section 1 - Loading the Data
1.1
How many rows of data (observations) are in this dataset?
D=read.csv("C:/bussiness analytics/data/mvtWeek1.csv")
nrow(D)
[1] 191641
nrow()觀察列的數量
1.2
How many variables are in this dataset?
ncol(D)
[1] 11
ncol()觀察行的數量
1.3
Using the “max” function, what is the maximum value of the variable “ID”?
max(D$ID)
[1] 9181151
$是指定的意思
1.4
What is the minimum value of the variable “Beat”?
min(D$Beat)
[1] 111
1.5
How many observations have value TRUE in the Arrest variable (this is the number of crimes for which an arrest was made)?
sum(D$Arrest==TRUE)
[1] 15536
==是等於的意思
1.6
How many observations have a LocationDescription value of ALLEY?
sum(D$LocationDescription=="ALLEY")
[1] 2308
sum for 個數, mean for ratio mean(D$LocationDescription==“ALLEY”) 會出現比率
Section 2 - Understanding Dates in R
In many datasets, like this one, you have a date field. Unfortunately, R does not automatically recognize entries that look like dates. We need to use a function in R to extract the date and time. Take a look at the first entry of Date (remember to use square brackets when looking at a certain entry of a variable).
2.1
In what format are the entries in the variable Date?
- Month/Day/Year Hour:Minute
- Day/Month/Year Hour:Minute
- Hour:Minute Month/Day/Year
- Hour:Minute Day/Month/Year
D$Date = as.character(D$Date)
head(D$Date,5)
[1] "12/31/12 23:15" "12/31/12 22:00" "12/31/12 22:00" "12/31/12 22:00"
[5] "12/31/12 21:30"
# Month/Day/Year Hour:Minute
head()整串數列中預設值為前六項,但若加“,”在加“數字”,則僅出現受指定的前幾項數字
2.2
Now, let’s convert these characters into a Date object in R. In your R console, type
DateConvert = as.Date(strptime(mvt$Date, "%m/%d/%y %H:%M"))
This converts the variable “Date” into a Date object in R. Take a look at the variable DateConvert using the summary function.
What is the month and year of the median date in our dataset? Enter your answer as “Month Year”, without the quotes. (Ex: if the answer was 2008-03-28, you would give the answer “March 2008”, without the quotes.)
ts = as.POSIXct(D$Date, format="%m/%d/%y %H:%M")
median(ts)
[1] "2006-05-21 12:30:00 CST"
as.POSIXct(x, format=指定的時間格式)是處理時間->精準到日月年 時分
as.Date()是處理時間->僅能到天數
ts是指設定完as.POSIXct()後要放置的位置
median()計算中位數的函數
2.3
Now, let’s extract the month and the day of the week, and add these variables to our data frame mvt. We can do this with two simple functions. Type the following commands in R:
mvt$Month = months(DateConvert)
mvt$Weekday = weekdays(DateConvert)
This creates two new variables in our data frame, Month and Weekday, and sets them equal to the month and weekday values that we can extract from the Date object. Lastly, replace the old Date variable with DateConvert by typing:
mvt$Date = DateConvert
Using the table command, answer the following questions.
D$Month = format(ts, "%m")
D$Weekday = format(ts, "%w")
指定D當中的Month->D\(Month -> 在定義D\)Month=format(ts,“%m”) 指定D當中的Weekday->D\(Weekday->在定義D\)Weekday=format(ts,“%w”)
In which month did the fewest motor vehicle thefts occur?
sort(table(D$Month))
02 04 03 06 05 01 09 11 12 08 07 10
13511 15280 15758 16002 16035 16047 16060 16063 16426 16572 16801 17086
table()將數列字串表格化,才能看出最少的 sort()以遞增的方式排列字串
2.4
On which weekday did the most motor vehicle thefts occur?
sort(table(D$Weekday))
0 2 6 4 1 3 5
26316 26791 27118 27319 27397 27416 29284
2.5
Each observation in the dataset represents a motor vehicle theft, and the Arrest variable indicates whether an arrest was later made for this theft. Which month has the largest number of motor vehicle thefts for which an arrest was made?
library(dplyr)
package 愼㸱愼㸵dplyr愼㸱愼㸶 was built under R version 3.5.1
Attaching package: 愼㸱愼㸵dplyr愼㸱愼㸶
The following objects are masked from 愼㸱愼㸵package:stats愼㸱愼㸶:
filter, lag
The following objects are masked from 愼㸱愼㸵package:base愼㸱愼㸶:
intersect, setdiff, setequal, union
library(dplyr) 是可以做為更有效率地作資料處理
tapply(D$Arrest, D$Month, sum) %>% sort
05 06 02 09 04 11 03 07 08 10 12 01
1187 1230 1238 1248 1252 1256 1298 1324 1329 1342 1397 1435
tapply()是the sum of Arrest by month 或the mean of Arrest by month %>%是第二層 或第三層括號的意思
Section 3 - Visualizing Crime Trends
3.1
Now, let’s make some plots to help us better understand how crime has changed over time in Chicago. Throughout this problem, and in general, you can save your plot to a file. For more information, this website very clearly explains the process.
First, let’s make a histogram of the variable Date. We’ll add an extra argument, to specify the number of bars we want in our histogram. In your R console, type
hist(mvt$Date, breaks=100)
par(cex=0.7)
hist(ts, "year", las=2, main="No. Motor Crimes by year")

par()下繪圖指令 cex是指設置文本和符合的尺度 hist()直方圖 X軸的日期從水平變成垂直,要下以下的命令 las=1水平 las=2垂直 Y軸有兩種單位Density指令下freq=F和Frequency指令下freq=T,預設為Density本題改成Frequency,在hist()中下freq=T main=“No. Motor Crimes by Quarter”下圖形主題 加上主題的直方圖 hist(ts, “Date”, las=2, freq=T, main=“No. Motor Crimes by Quarter”)
Looking at the histogram, answer the following questions.
In general, does it look like crime increases or decreases from 2002 - 2012?
hist(ts,'year',las=2)
# Decreases
In general, does it look like crime increases or decreases from 2005 - 2008?
hist(ts,'year',las=2)
# Decreases
3.2
Now, let’s see how arrests have changed over time. Create a boxplot of the variable “Date”, sorted by the variable “Arrest” (if you are not familiar with boxplots and would like to learn more, check out this tutorial). In a boxplot, the bold horizontal line is the median value of the data, the box shows the range of values between the first quartile and third quartile, and the whiskers (the dotted lines extending outside the box) show the minimum and maximum values, excluding any outliers (which are plotted as circles). Outliers are defined by first computing the difference between the first and third quartile values, or the height of the box. This number is called the Inter-Quartile Range (IQR). Any point that is greater than the third quartile plus the IQR or less than the first quartile minus the IQR is considered an outlier.
boxplot( ts ~ D$Arrest )

boxplot(ts ~ D$Arrest)用boxplot畫圖
Does it look like there were more crimes for which arrests were made in the first half of the time period or the second half of the time period? (Note that the time period is from 2001 to 2012, so the middle of the time period is the beginning of 2007.)
tapply(D$Arrest, ts > as.POSIXct("2007-01-01"), sum)
FALSE TRUE
10588 4948
tapply(D$Arrest, ts > as.POSIXct(“2007-01-01”), sum) ts > as.POSIXct(“2007-01-01”)找出資料中大於2007年的開始的數量 sum加總
3.3
Let’s investigate this further. Use the table function for the next few questions.
For what proportion of motor vehicle thefts in 2001 was an arrest made?
Note: in this question and many others in the course, we are asking for an answer as a proportion. Therefore, your answer should take a value between 0 and 1.
table(D$Arrest, D$Year)
2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012
FALSE 18517 16638 14859 15169 14956 14796 13068 13425 11327 14796 15012 13542
TRUE 2152 2115 1798 1693 1528 1302 1212 1020 840 701 625 550
tapply(D$Arrest, D$Year, mean) %>% round(3)
2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012
0.104 0.113 0.108 0.100 0.093 0.081 0.085 0.071 0.069 0.045 0.040 0.039
先用table畫出表格 tapply找到比率,再用 %>% round(3)計算小數點到第三位
3.4
For what proportion of motor vehicle thefts in 2007 was an arrest made?
# 0.085
3.5
For what proportion of motor vehicle thefts in 2012 was an arrest made?
#0.039
Since there may still be open investigations for recent crimes, this could explain the trend we are seeing in the data. There could also be other factors at play, and this trend should be investigated further. However, since we don’t know when the arrests were actually made, our detective work in this area has reached a dead end.
Section 4 - Popular Locations
4.1
Analyzing this data could be useful to the Chicago Police Department when deciding where to allocate resources. If they want to increase the number of arrests that are made for motor vehicle thefts, where should they focus their efforts?
We want to find the top five locations where motor vehicle thefts occur. If you create a table of the LocationDescription variable, it is unfortunately very hard to read since there are 78 different locations in the data set. By using the sort function, we can view this same table, but sorted by the number of observations in each category. In your R console, type:
sort(table(mvt$LocationDescription))
Which locations are the top five locations for motor vehicle thefts, excluding the “Other” category? You should select 5 of the following options.
- Bank
- Gas Station
- Hotel/Motel
- Street
- Car Wash
- Restaurant
- Parking Lot/Garage (Non-Residential)
- Alley
- Driveway (Residential)
- Vacant Lot/Land
table(D$LocationDescription) %>% sort %>% tail
DRIVEWAY - RESIDENTIAL GAS STATION
1675 2111
ALLEY OTHER
2308 4573
PARKING LOT/GARAGE(NON.RESID.) STREET
14852 156564
tail()字串數列中最後的幾項,若無設定數字,則會用預設值六項呈現
4.2
Create a subset of your data, only taking observations for which the theft happened in one of these five locations, and call this new data set “Top5”. To do this, you can use the | symbol. In lecture, we used the & symbol to use two criteria to make a subset of the data. To only take observations that have a certain value in one variable or the other, the | character can be used in place of the & symbol. This is also called a logical “or” operation.
Alternately, you could create five different subsets, and then merge them together into one data frame using rbind.
How many observations are in Top5?
(Top5=names(table(D$LocationDescription) %>% sort %>% tail(6))[-4])
[1] "DRIVEWAY - RESIDENTIAL" "GAS STATION"
[3] "ALLEY" "PARKING LOT/GARAGE(NON.RESID.)"
[5] "STREET"
sum(D$LocationDescription %in% Top5)
[1] 177510
subset()= %in% 篩選子資料,例如LocationDescription和TopLocations
4.3
R will remember the other categories of the LocationDescription variable from the original dataset, so running table(Top5$LocationDescription) will have a lot of unnecessary output. To make our tables a bit nicer to read, we can refresh this factor variable. In your R console, type:
Top5$LocationDescription = factor(Top5$LocationDescription)
If you run the str or table function on Top5 now, you should see that LocationDescription now only has 5 values, as we expect.
Use the Top5 data frame to answer the remaining questions.
One of the locations has a much higher arrest rate than the other locations. Which is it? Please enter the text in exactly the same way as how it looks in the answer options for Problem 4.1.
Top5 = subset(D, LocationDescription %in% Top5)
tapply(Top5$Arrest, Top5$LocationDescription, mean) %>% sort %>% round(3)
STREET DRIVEWAY - RESIDENTIAL
0.074 0.079
ALLEY PARKING LOT/GARAGE(NON.RESID.)
0.108 0.108
GAS STATION
0.208
as.character換格式
4.4
On which day of the week do the most motor vehicle thefts at gas stations happen? (Monday~Sunday)
ts[Top5$Location == "GAS STATION"] %>% format('%w') %>% table %>% sort
.
3 2 0 4 6 1 5
293 305 315 321 325 329 344
Warning message:
In strsplit(code, "\n", fixed = TRUE) :
input string 1 is invalid in this locale
# 星期六"
如果要在更複雜的子集合 tapply(Top5\(Arrest, list(Top5\)LocationDescription, Top5$Weekday), mean) %>% round(3)
4.5
On which day of the week do the fewest motor vehicle thefts in residential driveways happen?(Monday~Sunday)
ts[Top5$Location == "DRIVEWAY - RESIDENTIAL"] %>% format('%w') %>% table %>% sort
.
2 4 3 0 1 6 5
223 237 239 247 270 282 293
Warning message:
In strsplit(code, "\n", fixed = TRUE) :
input string 1 is invalid in this locale
#星期四"
LS0tDQp0aXRsZTogIkFTMS0xIEFuIEFuYWx5dGljYWwgRGV0ZWN0aXZlIg0KYXV0aG9yOiAiPG5hbWU+IDxzdHVkZW50IElEPiINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCi0gLSAtIA0KDQojIyMgU2VjdGlvbiAxIC0gTG9hZGluZyB0aGUgRGF0YQ0KDQojIyMjIDEuMSANCkhvdyBtYW55IHJvd3Mgb2YgZGF0YSAob2JzZXJ2YXRpb25zKSBhcmUgaW4gdGhpcyBkYXRhc2V0Pw0KDQpgYGB7cn0NCkQ9cmVhZC5jc3YoIkM6L2J1c3NpbmVzcyBhbmFseXRpY3MvZGF0YS9tdnRXZWVrMS5jc3YiKQ0KbnJvdyhEKQ0KYGBgDQpucm93KCnop4Dlr5/liJfnmoTmlbjph48NCg0KIyMjIyAxLjIgDQpIb3cgbWFueSB2YXJpYWJsZXMgYXJlIGluIHRoaXMgZGF0YXNldD8NCmBgYHtyfQ0KbmNvbChEKQ0KYGBgDQpuY29sKCnop4Dlr5/ooYznmoTmlbjph48NCg0KIyMjIyAxLjMgDQpVc2luZyB0aGUgIm1heCIgZnVuY3Rpb24sIHdoYXQgaXMgdGhlIG1heGltdW0gdmFsdWUgb2YgdGhlIHZhcmlhYmxlICJJRCI/DQoNCmBgYHtyfQ0KbWF4KEQkSUQpDQpgYGANCiTmmK/mjIflrprnmoTmhI/mgJ0NCg0KIyMjIyAxLjQgDQpXaGF0IGlzIHRoZSBtaW5pbXVtIHZhbHVlIG9mIHRoZSB2YXJpYWJsZSAiQmVhdCI/DQpgYGB7cn0NCm1pbihEJEJlYXQpDQpgYGANCg0KIyMjIyAxLjUgDQpIb3cgbWFueSBvYnNlcnZhdGlvbnMgaGF2ZSB2YWx1ZSBUUlVFIGluIHRoZSBBcnJlc3QgdmFyaWFibGUgKHRoaXMgaXMgdGhlIG51bWJlciBvZiBjcmltZXMgZm9yIHdoaWNoIGFuIGFycmVzdCB3YXMgbWFkZSk/DQoNCmBgYHtyfQ0Kc3VtKEQkQXJyZXN0PT1UUlVFKQ0KYGBgDQo9PeaYr+etieaWvOeahOaEj+aAnQ0KDQoNCiMjIyMgMS42IA0KSG93IG1hbnkgb2JzZXJ2YXRpb25zIGhhdmUgYSBMb2NhdGlvbkRlc2NyaXB0aW9uIHZhbHVlIG9mIEFMTEVZPw0KDQpgYGB7cn0NCnN1bShEJExvY2F0aW9uRGVzY3JpcHRpb249PSJBTExFWSIpDQpgYGANCnN1bSBmb3Ig5YCL5pW477yMIG1lYW4gZm9yIHJhdGlvDQptZWFuKEQkTG9jYXRpb25EZXNjcmlwdGlvbj09IkFMTEVZIikg5pyD5Ye654++5q+U546HDQoNCiMjIyBTZWN0aW9uIDIgLSBVbmRlcnN0YW5kaW5nIERhdGVzIGluIFINCg0KDQpJbiBtYW55IGRhdGFzZXRzLCBsaWtlIHRoaXMgb25lLCB5b3UgaGF2ZSBhIGRhdGUgZmllbGQuIFVuZm9ydHVuYXRlbHksIFIgZG9lcyBub3QgYXV0b21hdGljYWxseSByZWNvZ25pemUgZW50cmllcyB0aGF0IGxvb2sgbGlrZSBkYXRlcy4gV2UgbmVlZCB0byB1c2UgYSBmdW5jdGlvbiBpbiBSIHRvIGV4dHJhY3QgdGhlIGRhdGUgYW5kIHRpbWUuIFRha2UgYSBsb29rIGF0IHRoZSBmaXJzdCBlbnRyeSBvZiBEYXRlIChyZW1lbWJlciB0byB1c2Ugc3F1YXJlIGJyYWNrZXRzIHdoZW4gbG9va2luZyBhdCBhIGNlcnRhaW4gZW50cnkgb2YgYSB2YXJpYWJsZSkuDQoNCiMjIyMgMi4xIA0KSW4gd2hhdCBmb3JtYXQgYXJlIHRoZSBlbnRyaWVzIGluIHRoZSB2YXJpYWJsZSBEYXRlPw0KDQorIE1vbnRoL0RheS9ZZWFyIEhvdXI6TWludXRlDQorIERheS9Nb250aC9ZZWFyIEhvdXI6TWludXRlDQorIEhvdXI6TWludXRlIE1vbnRoL0RheS9ZZWFyDQorIEhvdXI6TWludXRlIERheS9Nb250aC9ZZWFyDQoNCmBgYHtyfQ0KRCREYXRlID0gYXMuY2hhcmFjdGVyKEQkRGF0ZSkNCmhlYWQoRCREYXRlLDUpDQojIE1vbnRoL0RheS9ZZWFyIEhvdXI6TWludXRlDQpgYGANCmhlYWQoKeaVtOS4suaVuOWIl+S4remgkOioreWAvOeCuuWJjeWFremghe+8jOS9huiLpeWKoCIsIuWcqOWKoCLmlbjlrZci77yM5YmH5YOF5Ye654++5Y+X5oyH5a6a55qE5YmN5bm+6aCF5pW45a2XDQoNCg0KIyMjIyAyLjIgDQoNCk5vdywgbGV0J3MgY29udmVydCB0aGVzZSBjaGFyYWN0ZXJzIGludG8gYSBEYXRlIG9iamVjdCBpbiBSLiBJbiB5b3VyIFIgY29uc29sZSwgdHlwZQ0KDQogICAgRGF0ZUNvbnZlcnQgPSBhcy5EYXRlKHN0cnB0aW1lKG12dCREYXRlLCAiJW0vJWQvJXkgJUg6JU0iKSkNCg0KVGhpcyBjb252ZXJ0cyB0aGUgdmFyaWFibGUgIkRhdGUiIGludG8gYSBEYXRlIG9iamVjdCBpbiBSLiBUYWtlIGEgbG9vayBhdCB0aGUgdmFyaWFibGUgRGF0ZUNvbnZlcnQgdXNpbmcgdGhlIHN1bW1hcnkgZnVuY3Rpb24uDQoNCldoYXQgaXMgdGhlIG1vbnRoIGFuZCB5ZWFyIG9mIHRoZSBtZWRpYW4gZGF0ZSBpbiBvdXIgZGF0YXNldD8gRW50ZXIgeW91ciBhbnN3ZXIgYXMgIk1vbnRoIFllYXIiLCB3aXRob3V0IHRoZSBxdW90ZXMuIChFeDogaWYgdGhlIGFuc3dlciB3YXMgMjAwOC0wMy0yOCwgeW91IHdvdWxkIGdpdmUgdGhlIGFuc3dlciAiTWFyY2ggMjAwOCIsIHdpdGhvdXQgdGhlIHF1b3Rlcy4pDQoNCmBgYHtyfQ0KdHMgPSBhcy5QT1NJWGN0KEQkRGF0ZSwgZm9ybWF0PSIlbS8lZC8leSAlSDolTSIpDQptZWRpYW4odHMpDQpgYGANCmFzLlBPU0lYY3QoeCwgZm9ybWF0PeaMh+WumueahOaZgumWk+agvOW8jynmmK/omZXnkIbmmYLplpMtPueyvua6luWIsOaXpeaciOW5tCDmmYLliIYNCg0KYXMuRGF0ZSgp5piv6JmV55CG5pmC6ZaTLT7lg4Xog73liLDlpKnmlbgNCg0KdHPmmK/mjIfoqK3lrprlroxhcy5QT1NJWGN0KCnlvozopoHmlL7nva7nmoTkvY3nva4NCg0KbWVkaWFuKCnoqIjnrpfkuK3kvY3mlbjnmoTlh73mlbgNCg0KIyMjIyAyLjMNCk5vdywgbGV0J3MgZXh0cmFjdCB0aGUgbW9udGggYW5kIHRoZSBkYXkgb2YgdGhlIHdlZWssIGFuZCBhZGQgdGhlc2UgdmFyaWFibGVzIHRvIG91ciBkYXRhIGZyYW1lIG12dC4gV2UgY2FuIGRvIHRoaXMgd2l0aCB0d28gc2ltcGxlIGZ1bmN0aW9ucy4gVHlwZSB0aGUgZm9sbG93aW5nIGNvbW1hbmRzIGluIFI6DQoNCiAgICBtdnQkTW9udGggPSBtb250aHMoRGF0ZUNvbnZlcnQpDQoNCiAgICBtdnQkV2Vla2RheSA9IHdlZWtkYXlzKERhdGVDb252ZXJ0KQ0KDQpUaGlzIGNyZWF0ZXMgdHdvIG5ldyB2YXJpYWJsZXMgaW4gb3VyIGRhdGEgZnJhbWUsIE1vbnRoIGFuZCBXZWVrZGF5LCBhbmQgc2V0cyB0aGVtIGVxdWFsIHRvIHRoZSBtb250aCBhbmQgd2Vla2RheSB2YWx1ZXMgdGhhdCB3ZSBjYW4gZXh0cmFjdCBmcm9tIHRoZSBEYXRlIG9iamVjdC4gTGFzdGx5LCByZXBsYWNlIHRoZSBvbGQgRGF0ZSB2YXJpYWJsZSB3aXRoIERhdGVDb252ZXJ0IGJ5IHR5cGluZzoNCg0KICAgIG12dCREYXRlID0gRGF0ZUNvbnZlcnQNCg0KVXNpbmcgdGhlIHRhYmxlIGNvbW1hbmQsIGFuc3dlciB0aGUgZm9sbG93aW5nIHF1ZXN0aW9ucy4NCg0KYGBge3J9DQpEJE1vbnRoID0gZm9ybWF0KHRzLCAiJW0iKQ0KRCRXZWVrZGF5ID0gZm9ybWF0KHRzLCAiJXciKQ0KYGBgDQrmjIflrppE55W25Lit55qETW9udGgtPkQkTW9udGggLT4g5Zyo5a6a576pRCRNb250aD1mb3JtYXQodHMsIiVtIikNCuaMh+WumkTnlbbkuK3nmoRXZWVrZGF5LT5EJFdlZWtkYXktPuWcqOWumue+qUQkV2Vla2RheT1mb3JtYXQodHMsIiV3IikNCg0KDQpJbiB3aGljaCBtb250aCBkaWQgdGhlIGZld2VzdCBtb3RvciB2ZWhpY2xlIHRoZWZ0cyBvY2N1cj8NCg0KYGBge3J9DQpzb3J0KHRhYmxlKEQkTW9udGgpKQ0KIyAy5pyIDQpgYGANCnRhYmxlKCnlsIfmlbjliJflrZfkuLLooajmoLzljJbvvIzmiY3og73nnIvlh7rmnIDlsJHnmoQNCnNvcnQoKeS7pemBnuWinueahOaWueW8j+aOkuWIl+Wtl+S4sg0KDQoNCiMjIyMgMi40IA0KT24gd2hpY2ggd2Vla2RheSBkaWQgdGhlIG1vc3QgbW90b3IgdmVoaWNsZSB0aGVmdHMgb2NjdXI/DQoNCmBgYHtyfQ0Kc29ydCh0YWJsZShEJFdlZWtkYXkpKQ0KIyDmmJ/mnJ/kupQNCmBgYA0KDQojIyMjIDIuNSANCkVhY2ggb2JzZXJ2YXRpb24gaW4gdGhlIGRhdGFzZXQgcmVwcmVzZW50cyBhIG1vdG9yIHZlaGljbGUgdGhlZnQsIGFuZCB0aGUgQXJyZXN0IHZhcmlhYmxlIGluZGljYXRlcyB3aGV0aGVyIGFuIGFycmVzdCB3YXMgbGF0ZXIgbWFkZSBmb3IgdGhpcyB0aGVmdC4gV2hpY2ggbW9udGggaGFzIHRoZSBsYXJnZXN0IG51bWJlciBvZiBtb3RvciB2ZWhpY2xlIHRoZWZ0cyBmb3Igd2hpY2ggYW4gYXJyZXN0IHdhcyBtYWRlPw0KDQpgYGB7cn0NCmxpYnJhcnkoZHBseXIpDQpgYGANCmxpYnJhcnkoZHBseXIpIOaYr+WPr+S7peWBmueCuuabtOacieaViOeOh+WcsOS9nOizh+aWmeiZleeQhg0KDQoNCmBgYHtyfQ0KdGFwcGx5KEQkQXJyZXN0LCBEJE1vbnRoLCBzdW0pICU+JSBzb3J0IA0KIyAx5pyIDQpgYGANCnRhcHBseSgp5pivdGhlIHN1bSBvZiBBcnJlc3QgYnkgbW9udGgNCiAgICAgICAg5oiWdGhlIG1lYW4gb2YgQXJyZXN0IGJ5IG1vbnRoDQolPiXmmK/nrKzkuozlsaQg5oiW56ys5LiJ5bGk5ous6Jmf55qE5oSP5oCdDQoNCiMjIyBTZWN0aW9uIDMgLSBWaXN1YWxpemluZyBDcmltZSBUcmVuZHMNCg0KIyMjIyAzLjENCg0KTm93LCBsZXQncyBtYWtlIHNvbWUgcGxvdHMgdG8gaGVscCB1cyBiZXR0ZXIgdW5kZXJzdGFuZCBob3cgY3JpbWUgaGFzIGNoYW5nZWQgb3ZlciB0aW1lIGluIENoaWNhZ28uIFRocm91Z2hvdXQgdGhpcyBwcm9ibGVtLCBhbmQgaW4gZ2VuZXJhbCwgeW91IGNhbiBzYXZlIHlvdXIgcGxvdCB0byBhIGZpbGUuIEZvciBtb3JlIGluZm9ybWF0aW9uLCB0aGlzIHdlYnNpdGUgdmVyeSBjbGVhcmx5IGV4cGxhaW5zIHRoZSBwcm9jZXNzLg0KDQpGaXJzdCwgbGV0J3MgbWFrZSBhIGhpc3RvZ3JhbSBvZiB0aGUgdmFyaWFibGUgRGF0ZS4gV2UnbGwgYWRkIGFuIGV4dHJhIGFyZ3VtZW50LCB0byBzcGVjaWZ5IHRoZSBudW1iZXIgb2YgYmFycyB3ZSB3YW50IGluIG91ciBoaXN0b2dyYW0uIEluIHlvdXIgUiBjb25zb2xlLCB0eXBlDQoNCmhpc3QobXZ0JERhdGUsIGJyZWFrcz0xMDApDQoNCmBgYHtyfQ0KcGFyKGNleD0wLjcpDQpoaXN0KHRzLCAieWVhciIsIGxhcz0yLCBtYWluPSJOby4gTW90b3IgQ3JpbWVzIGJ5IHllYXIiKQ0KYGBgDQpwYXIoKeS4i+e5quWcluaMh+S7pA0KY2V45piv5oyH6Kit572u5paH5pys5ZKM56ym5ZCI55qE5bC65bqmDQpoaXN0KCnnm7TmlrnlnJYNCljou7jnmoTml6XmnJ/lvp7msLTlubPorormiJDlnoLnm7TvvIzopoHkuIvku6XkuIvnmoTlkb3ku6QNCmxhcz0x5rC05bmzICBsYXM9MuWeguebtA0KWei7uOacieWFqeeoruWWruS9jURlbnNpdHnmjIfku6TkuItmcmVxPUblkoxGcmVxdWVuY3nmjIfku6TkuItmcmVxPVTvvIzpoJDoqK3ngrpEZW5zaXR55pys6aGM5pS55oiQRnJlcXVlbmN577yM5ZyoaGlzdCgp5Lit5LiLZnJlcT1UDQptYWluPSJOby4gTW90b3IgQ3JpbWVzIGJ5IFF1YXJ0ZXIi5LiL5ZyW5b2i5Li76aGMDQrliqDkuIrkuLvpoYznmoTnm7TmlrnlnJYNCmhpc3QodHMsICJEYXRlIiwgbGFzPTIsIGZyZXE9VCwgbWFpbj0iTm8uIE1vdG9yIENyaW1lcyBieSBRdWFydGVyIikNCg0KDQpMb29raW5nIGF0IHRoZSBoaXN0b2dyYW0sIGFuc3dlciB0aGUgZm9sbG93aW5nIHF1ZXN0aW9ucy4NCg0KSW4gZ2VuZXJhbCwgZG9lcyBpdCBsb29rIGxpa2UgY3JpbWUgaW5jcmVhc2VzIG9yIGRlY3JlYXNlcyBmcm9tIDIwMDIgLSAyMDEyPw0KDQorIEluY3JlYXNlcw0KKyBEZWNyZWFzZXMNCg0KYGBge3J9DQpoaXN0KHRzLCd5ZWFyJyxsYXM9MikNCiMgIERlY3JlYXNlcw0KYGBgDQoNCkluIGdlbmVyYWwsIGRvZXMgaXQgbG9vayBsaWtlIGNyaW1lIGluY3JlYXNlcyBvciBkZWNyZWFzZXMgZnJvbSAyMDA1IC0gMjAwOD8NCg0KKyBJbmNyZWFzZXMNCisgRGVjcmVhc2VzDQoNCmBgYHtyfQ0KaGlzdCh0cywneWVhcicsbGFzPTIpDQojICBEZWNyZWFzZXMNCmBgYA0KDQojIyMjIDMuMg0KTm93LCBsZXQncyBzZWUgaG93IGFycmVzdHMgaGF2ZSBjaGFuZ2VkIG92ZXIgdGltZS4gQ3JlYXRlIGEgYm94cGxvdCBvZiB0aGUgdmFyaWFibGUgIkRhdGUiLCBzb3J0ZWQgYnkgdGhlIHZhcmlhYmxlICJBcnJlc3QiIChpZiB5b3UgYXJlIG5vdCBmYW1pbGlhciB3aXRoIGJveHBsb3RzIGFuZCB3b3VsZCBsaWtlIHRvIGxlYXJuIG1vcmUsIGNoZWNrIG91dCB0aGlzIHR1dG9yaWFsKS4gSW4gYSBib3hwbG90LCB0aGUgYm9sZCBob3Jpem9udGFsIGxpbmUgaXMgdGhlIG1lZGlhbiB2YWx1ZSBvZiB0aGUgZGF0YSwgdGhlIGJveCBzaG93cyB0aGUgcmFuZ2Ugb2YgdmFsdWVzIGJldHdlZW4gdGhlIGZpcnN0IHF1YXJ0aWxlIGFuZCB0aGlyZCBxdWFydGlsZSwgYW5kIHRoZSB3aGlza2VycyAodGhlIGRvdHRlZCBsaW5lcyBleHRlbmRpbmcgb3V0c2lkZSB0aGUgYm94KSBzaG93IHRoZSBtaW5pbXVtIGFuZCBtYXhpbXVtIHZhbHVlcywgZXhjbHVkaW5nIGFueSBvdXRsaWVycyAod2hpY2ggYXJlIHBsb3R0ZWQgYXMgY2lyY2xlcykuIE91dGxpZXJzIGFyZSBkZWZpbmVkIGJ5IGZpcnN0IGNvbXB1dGluZyB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSBmaXJzdCBhbmQgdGhpcmQgcXVhcnRpbGUgdmFsdWVzLCBvciB0aGUgaGVpZ2h0IG9mIHRoZSBib3guIFRoaXMgbnVtYmVyIGlzIGNhbGxlZCB0aGUgSW50ZXItUXVhcnRpbGUgUmFuZ2UgKElRUikuIEFueSBwb2ludCB0aGF0IGlzIGdyZWF0ZXIgdGhhbiB0aGUgdGhpcmQgcXVhcnRpbGUgcGx1cyB0aGUgSVFSIG9yIGxlc3MgdGhhbiB0aGUgZmlyc3QgcXVhcnRpbGUgbWludXMgdGhlIElRUiBpcyBjb25zaWRlcmVkIGFuIG91dGxpZXIuDQoNCg0KYGBge3J9DQpib3hwbG90KCB0cyB+IEQkQXJyZXN0ICkNCmBgYA0KYm94cGxvdCh0cyB+IEQkQXJyZXN0KeeUqGJveHBsb3TnlavlnJYNCg0KDQpEb2VzIGl0IGxvb2sgbGlrZSB0aGVyZSB3ZXJlIG1vcmUgY3JpbWVzIGZvciB3aGljaCBhcnJlc3RzIHdlcmUgbWFkZSBpbiB0aGUgZmlyc3QgaGFsZiBvZiB0aGUgdGltZSBwZXJpb2Qgb3IgdGhlIHNlY29uZCBoYWxmIG9mIHRoZSB0aW1lIHBlcmlvZD8gKE5vdGUgdGhhdCB0aGUgdGltZSBwZXJpb2QgaXMgZnJvbSAyMDAxIHRvIDIwMTIsIHNvIHRoZSBtaWRkbGUgb2YgdGhlIHRpbWUgcGVyaW9kIGlzIHRoZSBiZWdpbm5pbmcgb2YgMjAwNy4pDQoNCisgRmlyc3QgaGFsZg0KKyBTZWNvbmQgaGFsZg0KDQpgYGB7cn0NCnRhcHBseShEJEFycmVzdCwgdHMgPiBhcy5QT1NJWGN0KCIyMDA3LTAxLTAxIiksIHN1bSkNCmBgYA0KdGFwcGx5KEQkQXJyZXN0LCB0cyA+IGFzLlBPU0lYY3QoIjIwMDctMDEtMDEiKSwgc3VtKQ0KdHMgPiBhcy5QT1NJWGN0KCIyMDA3LTAxLTAxIinmib7lh7ros4fmlpnkuK3lpKfmlrwyMDA35bm055qE6ZaL5aeL55qE5pW46YePDQpzdW3liqDnuL0NCg0KDQojIyMjIDMuMw0KTGV0J3MgaW52ZXN0aWdhdGUgdGhpcyBmdXJ0aGVyLiBVc2UgdGhlIHRhYmxlIGZ1bmN0aW9uIGZvciB0aGUgbmV4dCBmZXcgcXVlc3Rpb25zLg0KDQpGb3Igd2hhdCBwcm9wb3J0aW9uIG9mIG1vdG9yIHZlaGljbGUgdGhlZnRzIGluIDIwMDEgd2FzIGFuIGFycmVzdCBtYWRlPw0KDQpOb3RlOiBpbiB0aGlzIHF1ZXN0aW9uIGFuZCBtYW55IG90aGVycyBpbiB0aGUgY291cnNlLCB3ZSBhcmUgYXNraW5nIGZvciBhbiBhbnN3ZXIgYXMgYSBwcm9wb3J0aW9uLiBUaGVyZWZvcmUsIHlvdXIgYW5zd2VyIHNob3VsZCB0YWtlIGEgdmFsdWUgYmV0d2VlbiAwIGFuZCAxLg0KDQpgYGB7cn0NCnRhYmxlKEQkQXJyZXN0LCBEJFllYXIpDQp0YXBwbHkoRCRBcnJlc3QsIEQkWWVhciwgbWVhbikgJT4lIHJvdW5kKDMpDQojIDAuMTA0DQpgYGANCuWFiOeUqHRhYmxl55Wr5Ye66KGo5qC8DQp0YXBwbHnmib7liLDmr5TnjofvvIzlho3nlKggJT4lDQpyb3VuZCgzKeioiOeul+Wwj+aVuOm7nuWIsOesrOS4ieS9jQ0KDQoNCiMjIyMgMy40DQpGb3Igd2hhdCBwcm9wb3J0aW9uIG9mIG1vdG9yIHZlaGljbGUgdGhlZnRzIGluIDIwMDcgd2FzIGFuIGFycmVzdCBtYWRlPw0KDQpgYGB7cn0NCiMgMC4wODUNCmBgYA0KDQojIyMjIDMuNQ0KRm9yIHdoYXQgcHJvcG9ydGlvbiBvZiBtb3RvciB2ZWhpY2xlIHRoZWZ0cyBpbiAyMDEyIHdhcyBhbiBhcnJlc3QgbWFkZT8NCg0KYGBge3J9DQojMC4wMzkNCg0KYGBgDQoNClNpbmNlIHRoZXJlIG1heSBzdGlsbCBiZSBvcGVuIGludmVzdGlnYXRpb25zIGZvciByZWNlbnQgY3JpbWVzLCB0aGlzIGNvdWxkIGV4cGxhaW4gdGhlIHRyZW5kIHdlIGFyZSBzZWVpbmcgaW4gdGhlIGRhdGEuIFRoZXJlIGNvdWxkIGFsc28gYmUgb3RoZXIgZmFjdG9ycyBhdCBwbGF5LCBhbmQgdGhpcyB0cmVuZCBzaG91bGQgYmUgaW52ZXN0aWdhdGVkIGZ1cnRoZXIuIEhvd2V2ZXIsIHNpbmNlIHdlIGRvbid0IGtub3cgd2hlbiB0aGUgYXJyZXN0cyB3ZXJlIGFjdHVhbGx5IG1hZGUsIG91ciBkZXRlY3RpdmUgd29yayBpbiB0aGlzIGFyZWEgaGFzIHJlYWNoZWQgYSBkZWFkIGVuZC4NCg0KIyMjIFNlY3Rpb24gNCAtIFBvcHVsYXIgTG9jYXRpb25zDQoNCiMjIyMgNC4xDQpBbmFseXppbmcgdGhpcyBkYXRhIGNvdWxkIGJlIHVzZWZ1bCB0byB0aGUgQ2hpY2FnbyBQb2xpY2UgRGVwYXJ0bWVudCB3aGVuIGRlY2lkaW5nIHdoZXJlIHRvIGFsbG9jYXRlIHJlc291cmNlcy4gSWYgdGhleSB3YW50IHRvIGluY3JlYXNlIHRoZSBudW1iZXIgb2YgYXJyZXN0cyB0aGF0IGFyZSBtYWRlIGZvciBtb3RvciB2ZWhpY2xlIHRoZWZ0cywgd2hlcmUgc2hvdWxkIHRoZXkgZm9jdXMgdGhlaXIgZWZmb3J0cz8NCg0KV2Ugd2FudCB0byBmaW5kIHRoZSB0b3AgZml2ZSBsb2NhdGlvbnMgd2hlcmUgbW90b3IgdmVoaWNsZSB0aGVmdHMgb2NjdXIuIElmIHlvdSBjcmVhdGUgYSB0YWJsZSBvZiB0aGUgTG9jYXRpb25EZXNjcmlwdGlvbiB2YXJpYWJsZSwgaXQgaXMgdW5mb3J0dW5hdGVseSB2ZXJ5IGhhcmQgdG8gcmVhZCBzaW5jZSB0aGVyZSBhcmUgNzggZGlmZmVyZW50IGxvY2F0aW9ucyBpbiB0aGUgZGF0YSBzZXQuIEJ5IHVzaW5nIHRoZSBzb3J0IGZ1bmN0aW9uLCB3ZSBjYW4gdmlldyB0aGlzIHNhbWUgdGFibGUsIGJ1dCBzb3J0ZWQgYnkgdGhlIG51bWJlciBvZiBvYnNlcnZhdGlvbnMgaW4gZWFjaCBjYXRlZ29yeS4gSW4geW91ciBSIGNvbnNvbGUsIHR5cGU6DQoNCiAgICBzb3J0KHRhYmxlKG12dCRMb2NhdGlvbkRlc2NyaXB0aW9uKSkNCg0KV2hpY2ggbG9jYXRpb25zIGFyZSB0aGUgdG9wIGZpdmUgbG9jYXRpb25zIGZvciBtb3RvciB2ZWhpY2xlIHRoZWZ0cywgZXhjbHVkaW5nIHRoZSAiT3RoZXIiIGNhdGVnb3J5PyBZb3Ugc2hvdWxkIHNlbGVjdCA1IG9mIHRoZSBmb2xsb3dpbmcgb3B0aW9ucy4NCg0KKyBCYW5rDQorIEdhcyBTdGF0aW9uDQorIEhvdGVsL01vdGVsDQorIFN0cmVldA0KKyBDYXIgV2FzaA0KKyBSZXN0YXVyYW50DQorIFBhcmtpbmcgTG90L0dhcmFnZSAoTm9uLVJlc2lkZW50aWFsKQ0KKyBBbGxleQ0KKyBEcml2ZXdheSAoUmVzaWRlbnRpYWwpDQorIFZhY2FudCBMb3QvTGFuZA0KDQpgYGB7cn0NCnRhYmxlKEQkTG9jYXRpb25EZXNjcmlwdGlvbikgJT4lIHNvcnQgJT4lIHRhaWwNCmBgYA0KdGFpbCgp5a2X5Liy5pW45YiX5Lit5pyA5b6M55qE5bm+6aCF77yM6Iul54Sh6Kit5a6a5pW45a2X77yM5YmH5pyD55So6aCQ6Kit5YC85YWt6aCF5ZGI54++DQoNCiMjIyMgNC4yIA0KQ3JlYXRlIGEgc3Vic2V0IG9mIHlvdXIgZGF0YSwgb25seSB0YWtpbmcgb2JzZXJ2YXRpb25zIGZvciB3aGljaCB0aGUgdGhlZnQgaGFwcGVuZWQgaW4gb25lIG9mIHRoZXNlIGZpdmUgbG9jYXRpb25zLCBhbmQgY2FsbCB0aGlzIG5ldyBkYXRhIHNldCAiVG9wNSIuIFRvIGRvIHRoaXMsIHlvdSBjYW4gdXNlIHRoZSB8IHN5bWJvbC4gSW4gbGVjdHVyZSwgd2UgdXNlZCB0aGUgJiBzeW1ib2wgdG8gdXNlIHR3byBjcml0ZXJpYSB0byBtYWtlIGEgc3Vic2V0IG9mIHRoZSBkYXRhLiBUbyBvbmx5IHRha2Ugb2JzZXJ2YXRpb25zIHRoYXQgaGF2ZSBhIGNlcnRhaW4gdmFsdWUgaW4gb25lIHZhcmlhYmxlIG9yIHRoZSBvdGhlciwgdGhlIHwgY2hhcmFjdGVyIGNhbiBiZSB1c2VkIGluIHBsYWNlIG9mIHRoZSAmIHN5bWJvbC4gVGhpcyBpcyBhbHNvIGNhbGxlZCBhIGxvZ2ljYWwgIm9yIiBvcGVyYXRpb24uDQoNCkFsdGVybmF0ZWx5LCB5b3UgY291bGQgY3JlYXRlIGZpdmUgZGlmZmVyZW50IHN1YnNldHMsIGFuZCB0aGVuIG1lcmdlIHRoZW0gdG9nZXRoZXIgaW50byBvbmUgZGF0YSBmcmFtZSB1c2luZyByYmluZC4NCg0KSG93IG1hbnkgb2JzZXJ2YXRpb25zIGFyZSBpbiBUb3A1Pw0KDQpgYGB7cn0NCihUb3A1PW5hbWVzKHRhYmxlKEQkTG9jYXRpb25EZXNjcmlwdGlvbikgJT4lIHNvcnQgJT4lIHRhaWwoNikpWy00XSkNCg0Kc3VtKEQkTG9jYXRpb25EZXNjcmlwdGlvbiAlaW4lIFRvcDUpDQojIDE3NzUxMA0KDQpgYGANCnN1YnNldCgpPSAlaW4lIOevqemBuOWtkOizh+aWme+8jOS+i+WmgkxvY2F0aW9uRGVzY3JpcHRpb27lkoxUb3BMb2NhdGlvbnMNCg0KDQojIyMjIDQuMw0KUiB3aWxsIHJlbWVtYmVyIHRoZSBvdGhlciBjYXRlZ29yaWVzIG9mIHRoZSBMb2NhdGlvbkRlc2NyaXB0aW9uIHZhcmlhYmxlIGZyb20gdGhlIG9yaWdpbmFsIGRhdGFzZXQsIHNvIHJ1bm5pbmcgdGFibGUoVG9wNSRMb2NhdGlvbkRlc2NyaXB0aW9uKSB3aWxsIGhhdmUgYSBsb3Qgb2YgdW5uZWNlc3Nhcnkgb3V0cHV0LiBUbyBtYWtlIG91ciB0YWJsZXMgYSBiaXQgbmljZXIgdG8gcmVhZCwgd2UgY2FuIHJlZnJlc2ggdGhpcyBmYWN0b3IgdmFyaWFibGUuIEluIHlvdXIgUiBjb25zb2xlLCB0eXBlOg0KDQogICAgVG9wNSRMb2NhdGlvbkRlc2NyaXB0aW9uID0gZmFjdG9yKFRvcDUkTG9jYXRpb25EZXNjcmlwdGlvbikNCg0KSWYgeW91IHJ1biB0aGUgc3RyIG9yIHRhYmxlIGZ1bmN0aW9uIG9uIFRvcDUgbm93LCB5b3Ugc2hvdWxkIHNlZSB0aGF0IExvY2F0aW9uRGVzY3JpcHRpb24gbm93IG9ubHkgaGFzIDUgdmFsdWVzLCBhcyB3ZSBleHBlY3QuDQoNClVzZSB0aGUgVG9wNSBkYXRhIGZyYW1lIHRvIGFuc3dlciB0aGUgcmVtYWluaW5nIHF1ZXN0aW9ucy4NCg0KT25lIG9mIHRoZSBsb2NhdGlvbnMgaGFzIGEgbXVjaCBoaWdoZXIgYXJyZXN0IHJhdGUgdGhhbiB0aGUgb3RoZXIgbG9jYXRpb25zLiBXaGljaCBpcyBpdD8gUGxlYXNlIGVudGVyIHRoZSB0ZXh0IGluIGV4YWN0bHkgdGhlIHNhbWUgd2F5IGFzIGhvdyBpdCBsb29rcyBpbiB0aGUgYW5zd2VyIG9wdGlvbnMgZm9yIFByb2JsZW0gNC4xLg0KDQpgYGB7cn0NClRvcDUgPSBzdWJzZXQoRCwgTG9jYXRpb25EZXNjcmlwdGlvbiAlaW4lIFRvcDUpDQp0YXBwbHkoVG9wNSRBcnJlc3QsIFRvcDUkTG9jYXRpb25EZXNjcmlwdGlvbiwgbWVhbikgJT4lIHNvcnQgJT4lIHJvdW5kKDMpDQoNCmBgYA0KYXMuY2hhcmFjdGVy5o+b5qC85byPDQoNCiMjIyMgNC40IA0KT24gd2hpY2ggZGF5IG9mIHRoZSB3ZWVrIGRvIHRoZSBtb3N0IG1vdG9yIHZlaGljbGUgdGhlZnRzIGF0IGdhcyBzdGF0aW9ucyBoYXBwZW4/DQooTW9uZGF5flN1bmRheSkNCg0KYGBge3J9DQp0c1tUb3A1JExvY2F0aW9uID09ICJHQVMgU1RBVElPTiJdICU+JSBmb3JtYXQoJyV3JykgJT4lIHRhYmxlICU+JSBzb3J0DQojIOaYn+acn+S6lA0KDQpgYGANCuWmguaenOimgeWcqOabtOikh+mbnOeahOWtkOmbhuWQiA0KdGFwcGx5KFRvcDUkQXJyZXN0LCBsaXN0KFRvcDUkTG9jYXRpb25EZXNjcmlwdGlvbiwgVG9wNSRXZWVrZGF5KSwgbWVhbikgJT4lIHJvdW5kKDMpDQoNCiMjIyMgNC41DQpPbiB3aGljaCBkYXkgb2YgdGhlIHdlZWsgZG8gdGhlIGZld2VzdCBtb3RvciB2ZWhpY2xlIHRoZWZ0cyBpbiByZXNpZGVudGlhbCBkcml2ZXdheXMgaGFwcGVuPyhNb25kYXl+U3VuZGF5KQ0KDQpgYGB7cn0NCnRzW1RvcDUkTG9jYXRpb24gPT0gIkRSSVZFV0FZIC0gUkVTSURFTlRJQUwiXSAlPiUgZm9ybWF0KCcldycpICU+JSB0YWJsZSAlPiUgc29ydA0KDQoj5pif5pyf5LqUDQpgYGANCg0KDQoNCg0KDQo=