Required packages

knitr::opts_chunk$set(warning = FALSE, message = FALSE)
# This is the R chunk for the required packages
library(dplyr)
library(tidyr)
library(ggplot2)
library(forecast)
library(outliers)
library(MVN)

Executive Summary

In this data processing, three data sets are used. Firstly, the three data sets are read and then joined. Secondly, the variables of the joined data set are converted into proper types. Then, it is tidyed and a new variable is created using existing variables. Furthermore, missing values are processed and a transformation is done to normalrise a variable. Finally, the outliers of numeric variable is handled.

Data

The data sets used is retrieved from Australia & New Zealand Road Crash Dataset. The used data sets and brief descriptions of the variables are as follows:

Crash:

Description:

Casualties:

The later two sets are joined into crash using left_join() regarding the foreign keys respectively.

# This is the R chunk for the Data Section
crash.raw <- read.csv("./data/Crash.csv") %>% 
              select(crash_id,lat_long,casualties_id, description_id)
description.raw <- read.csv("./data/Description.csv", stringsAsFactors = TRUE) %>% 
                    select(description_id, severity,speed_limit,midblock,intersection,weather,crash_type,lighting,traffic_controls,drugs_alcohol)
casualties.raw <- read.csv("./data/Casualties.csv") %>% 
                    select(casualties_id, fatalities,serious_injuries,minor_injuries)
crash <- crash.raw %>% left_join(description.raw, by = "description_id") %>% 
                        left_join(casualties.raw, by = "casualties_id")
crash %>% head()

Understand

Summarise all the variables in the data frame.

str(crash)
'data.frame':   1519455 obs. of  16 variables:
 $ crash_id        : chr  "SA2012-1-21/08/2019" "SA2012-2-21/08/2019" "SA2012-3-21/08/2019" "SA2012-4-21/08/2019" ...
 $ lat_long        : chr  "(-34.914968707994774, 138.62326191400015)" "(-34.945411892314496, 138.61069073873753)" "(-35.348782706688546, 138.4547384995269)" "(-34.91089013663556, 138.56464045685533)" ...
 $ casualties_id   : chr  "0c" "0c" "0c" "0c" ...
 $ description_id  : int  0 1 2 3 4 5 6 7 8 9 ...
 $ severity        : Factor w/ 4 levels "fatality","minor_injury",..: 3 3 3 3 3 3 3 3 3 3 ...
 $ speed_limit     : Factor w/ 37 levels "","0 - 50 km/h",..: 23 17 5 23 23 23 23 23 23 21 ...
 $ midblock        : Factor w/ 2 levels "False","True": 2 2 2 1 1 1 2 1 1 1 ...
 $ intersection    : Factor w/ 2 levels "False","True": 1 1 1 2 2 2 1 2 2 2 ...
 $ weather         : Factor w/ 11 levels "","fine","fog",..: 2 2 2 2 2 2 2 2 2 2 ...
 $ crash_type      : Factor w/ 61 levels "","Collision with a fixed object",..: 42 21 34 36 36 36 53 36 36 36 ...
 $ lighting        : Factor w/ 7 levels "","darkness_lit",..: 5 5 5 5 5 5 5 5 5 5 ...
 $ traffic_controls: Factor w/ 10 levels "","giveway_sign",..: 4 4 4 9 10 10 4 10 10 10 ...
 $ drugs_alcohol   : Factor w/ 2 levels "","Y": 1 1 1 1 1 1 1 1 1 1 ...
 $ fatalities      : num  0 0 0 0 0 0 0 0 0 0 ...
 $ serious_injuries: num  0 0 0 0 0 0 0 0 0 0 ...
 $ minor_injuries  : num  0 0 0 0 0 0 0 0 0 0 ...

midblock, intersection and drugs_alcohol should be converted into logical variables. drugs_alcohol contains only "Y" and "", thus "Y" is treated as TRUE value and the other as FALSE.

crash$midblock <- as.logical(crash$midblock)
crash$intersection <- as.logical(crash$intersection)
drugs_alcohol <- as.character(crash$drugs_alcohol)
drugs_alcohol[drugs_alcohol == "Y"] <- TRUE
drugs_alcohol[drugs_alcohol == ""] <- FALSE
drugs_alcohol <- as.logical(drugs_alcohol)
crash$drugs_alcohol <- drugs_alcohol
str(crash)
'data.frame':   1519455 obs. of  16 variables:
 $ crash_id        : chr  "SA2012-1-21/08/2019" "SA2012-2-21/08/2019" "SA2012-3-21/08/2019" "SA2012-4-21/08/2019" ...
 $ lat_long        : chr  "(-34.914968707994774, 138.62326191400015)" "(-34.945411892314496, 138.61069073873753)" "(-35.348782706688546, 138.4547384995269)" "(-34.91089013663556, 138.56464045685533)" ...
 $ casualties_id   : chr  "0c" "0c" "0c" "0c" ...
 $ description_id  : int  0 1 2 3 4 5 6 7 8 9 ...
 $ severity        : Factor w/ 4 levels "fatality","minor_injury",..: 3 3 3 3 3 3 3 3 3 3 ...
 $ speed_limit     : Factor w/ 37 levels "","0 - 50 km/h",..: 23 17 5 23 23 23 23 23 23 21 ...
 $ midblock        : logi  TRUE TRUE TRUE FALSE FALSE FALSE ...
 $ intersection    : logi  FALSE FALSE FALSE TRUE TRUE TRUE ...
 $ weather         : Factor w/ 11 levels "","fine","fog",..: 2 2 2 2 2 2 2 2 2 2 ...
 $ crash_type      : Factor w/ 61 levels "","Collision with a fixed object",..: 42 21 34 36 36 36 53 36 36 36 ...
 $ lighting        : Factor w/ 7 levels "","darkness_lit",..: 5 5 5 5 5 5 5 5 5 5 ...
 $ traffic_controls: Factor w/ 10 levels "","giveway_sign",..: 4 4 4 9 10 10 4 10 10 10 ...
 $ drugs_alcohol   : logi  FALSE FALSE FALSE FALSE FALSE FALSE ...
 $ fatalities      : num  0 0 0 0 0 0 0 0 0 0 ...
 $ serious_injuries: num  0 0 0 0 0 0 0 0 0 0 ...
 $ minor_injuries  : num  0 0 0 0 0 0 0 0 0 0 ...

Tidy & Manipulate Data I

The lat_long column contains two variables, which makes the data set untidy. This column is separated into lat and lng using extract().

crash.ex <- crash %>% extract(lat_long, into=c("lat", "lng"), regex = "\\((-?[[:digit:]]+\\.[[:digit:]]+), ([[:digit:]]+\\.[[:digit:]]+)\\)")
head(crash.ex)

Tidy & Manipulate Data II

A new variable casualties is created using mutate() as a sum of fatalities, serious_injuries and minor_injuries to reflect the total casualties of crashes.

crash.nv <- crash.ex %>% mutate(casualties = fatalities + serious_injuries + minor_injuries)
str(crash.nv$casualties)
 num [1:1519455] 0 0 0 0 0 0 0 0 0 0 ...

Scan I

Scan the data frame for missing values.

crash.nv %>% is.na() %>% colSums()
        crash_id              lat              lng    casualties_id   description_id 
               0            66175            66175                0                0 
        severity      speed_limit         midblock     intersection          weather 
               0                0                0                0                0 
      crash_type         lighting traffic_controls    drugs_alcohol       fatalities 
               0                0                0                0           212390 
serious_injuries   minor_injuries       casualties 
          212390           212390           212390 

For lat and lng, the two variables together defines the exact places where crashes happened. In order not to affect the potential analysis of current geographical data, missing values in these two columns are replaced with N/A. While for the four numeric variables fatalities, serious_injuries, minor_injuries and casualties, they are replaced with 0.0.

crash.na <- replace_na(crash.nv, list(lat="N/A", lng="N/A", fatalities=0.0, serious_injuries=0.0, minor_injuries=0.0, casualties=0.0))
crash.na %>% is.na() %>% colSums()
        crash_id              lat              lng    casualties_id   description_id 
               0                0                0                0                0 
        severity      speed_limit         midblock     intersection          weather 
               0                0                0                0                0 
      crash_type         lighting traffic_controls    drugs_alcohol       fatalities 
               0                0                0                0                0 
serious_injuries   minor_injuries       casualties 
               0                0                0 

Transform

To understand the current distribution of the numeric variable casualties, a histograph is drawn.

crash.na %>% ggplot(aes(x=casualties)) +
              geom_histogram(bins = 10) +
              scale_y_log10()

Given the distribution is non-normal, Box-Cox transformation is used. Transformed values is appended to the data set as casualties_boxcox and using another histograph to demonstrate the new distribution.

Scan II

Using a box plot, it can be seen that there are existing outliers after the transformation.

crash.tr %>% ggplot(aes(y=casualties_boxcox)) +
              geom_boxplot()

To find the number of outliers, z-score is calculated.

z.scores <- crash.tr$casualties_boxcox %>% scores(type="z")
length (which( abs(z.scores) >3 ))
[1] 262

As the very slight chances that there are input errors in this data set, capping is used to handle those outliers. A box plot of the variable post-capping is used to illustrate the handled outliers.

quantiles <- quantile( crash.tr$casualties_boxcox, c(.05, 0.25, 0.75, .95 ) )
ca.iqr <- IQR(crash.tr$casualties_boxcox)
crash.cp <- crash.tr
crash.cp$casualties_boxcox[ crash.cp$casualties_boxcox < quantiles[2] - 1.5*ca.iqr ] <- quantiles[1]
crash.cp$casualties_boxcox[ crash.cp$casualties_boxcox > quantiles[3] + 1.5*ca.iqr ] <- quantiles[4]
crash.cp %>% ggplot(aes(y=casualties_boxcox)) +
              geom_boxplot()

LS0tDQp0aXRsZTogIk1BVEgyMzQ5IERhdGEgV3JhbmdsaW5nIg0KYXV0aG9yOiAiQm9oYW4gSGFvIHMzNTY3OTE4Ig0Kc3VidGl0bGU6IEFzc2lnbm1lbnQgMg0Kb3V0cHV0Og0KICBodG1sX25vdGVib29rOiBkZWZhdWx0DQogIHBkZl9kb2N1bWVudDogZGVmYXVsdA0KLS0tDQoNCiMjIFJlcXVpcmVkIHBhY2thZ2VzIA0KDQpgYGB7ciBzZXR1cH0NCmtuaXRyOjpvcHRzX2NodW5rJHNldCh3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRSkNCiMgVGhpcyBpcyB0aGUgUiBjaHVuayBmb3IgdGhlIHJlcXVpcmVkIHBhY2thZ2VzDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeSh0aWR5cikNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoZm9yZWNhc3QpDQpsaWJyYXJ5KG91dGxpZXJzKQ0KbGlicmFyeShNVk4pDQpgYGANCg0KIyMgRXhlY3V0aXZlIFN1bW1hcnkgDQoNCkluIHRoaXMgZGF0YSBwcm9jZXNzaW5nLCB0aHJlZSBkYXRhIHNldHMgYXJlIHVzZWQuIEZpcnN0bHksIHRoZSB0aHJlZSBkYXRhIHNldHMgYXJlIHJlYWQgYW5kIHRoZW4gam9pbmVkLiBTZWNvbmRseSwgdGhlIHZhcmlhYmxlcyBvZiB0aGUgam9pbmVkIGRhdGEgc2V0IGFyZSBjb252ZXJ0ZWQgaW50byBwcm9wZXIgdHlwZXMuIFRoZW4sIGl0IGlzIHRpZHllZCBhbmQgYSBuZXcgdmFyaWFibGUgaXMgY3JlYXRlZCB1c2luZyBleGlzdGluZyB2YXJpYWJsZXMuIEZ1cnRoZXJtb3JlLCBtaXNzaW5nIHZhbHVlcyBhcmUgcHJvY2Vzc2VkIGFuZCBhIHRyYW5zZm9ybWF0aW9uIGlzIGRvbmUgdG8gbm9ybWFscmlzZSBhIHZhcmlhYmxlLiBGaW5hbGx5LCB0aGUgb3V0bGllcnMgb2YgbnVtZXJpYyB2YXJpYWJsZSBpcyBoYW5kbGVkLg0KDQojIyBEYXRhIA0KDQpUaGUgZGF0YSBzZXRzIHVzZWQgaXMgcmV0cmlldmVkIGZyb20gW0F1c3RyYWxpYSAmIE5ldyBaZWFsYW5kIFJvYWQgQ3Jhc2ggRGF0YXNldF0oaHR0cHM6Ly93d3cua2FnZ2xlLmNvbS9tZ3JheTM5L2F1c3RyYWxpYS1uZXctemVhbGFuZC1yb2FkLWNyYXNoLWRhdGFzZXQpLiBUaGUgdXNlZCBkYXRhIHNldHMgYW5kIGJyaWVmIGRlc2NyaXB0aW9ucyBvZiB0aGUgdmFyaWFibGVzIGFyZSBhcyBmb2xsb3dzOg0KDQpDcmFzaDoNCg0KKiBgY3Jhc2hfaWRgOiB1bmlxdWUgY2hhcmFjdG9yIHZhcmlhYmxlIHRvIGlkZW50aWZ5IGVhY2ggY3Jhc2guDQoqIGBsYXRfbG9uZ2A6IGNoYXJhY3RvciBvZiBsYXRpdHVkZSBhbmQgbG9uZ2l0dWRlIGNvbXBvdW5kLg0KKiBgZGVzY3JpcHRpb25faWRgOiBmb3JlaWduIGtleSBmb3IgZGVzY3JpcHRpb24gb2YgdGhlIGNyYXNoLg0KKiBgY2FzdWFsdGllc19pZGA6IGZvcmVpZ24ga2V5IGZvciB0aGUgY2FzdWFsdGllcyBvZiB0aGUgY3Jhc2guDQoNCkRlc2NyaXB0aW9uOg0KDQoqIGBkZXNjcmlwdGlvbl9pZGA6IHVuaXF1ZSB2YXJpYWJsZSB0byBpZGVudGlmeSBlYWNoIGRlc2NyaXB0aW9uLg0KKiBgc2V2ZXJpdHlgOiBjYXRlZ29yaWNhbCB2YXJpYWJsZS4NCiogYHNwZWVkX2xpbWl0YDogY2F0ZWdvcmljYWwgdmFyaWFibGUuDQoqIGBtaWRibG9ja2A6IG5vbWluYWwgdmFyaWFibGUgb2YgdHJ1ZSBhbmQgZmFsc2UuDQoqIGBpbnRlcnNlY3Rpb25gOiBub21pbmFsIHZhcmlhYmxlIG9mIHRydWUgYW5kIGZhbHNlLg0KKiBgd2VhdGhlcmA6IGNhdGVnb3JpY2FsIHZhcmlhYmxlLg0KKiBgY3Jhc2hfdHlwZWA6IGNhdGVnb3JpY2FsIHZhcmlhYmxlLg0KKiBgbGlnaHRpbmdgOiBjYXRlZ29yaWNhbCB2YXJpYWJsZS4NCiogYHRyYWZmaWNfY29udHJvbHNgOiBjYXRlZ29yaWNhbCB2YXJpYWJsZS4NCiogYGRydWdzX2FsY29ob2xgOiBsb2dpY2FsIHZhcmlhYmxlLg0KDQpDYXN1YWx0aWVzOg0KDQoqIGBjYXN1YWx0aWVzX2lkYDogdW5pcXVlIHZhcmlhYmxlIHRvIGlkZW50aWZ5IGVhY2ggY2FzdWFsdHkgY29uZGl0aW9uLg0KKiBgZmF0YWxpdGllc2A6IGRpc2NyZXRlIHF1YW50aXRhdGl2ZSB2YXJpYWJsZS4NCiogYHNlcmlvdXNfaW5qdXJpZXNgOiBkaXNjcmV0ZSBxdWFudGl0YXRpdmUgdmFyaWFibGUuDQoqIGBtaW5vcl9pbmp1cmllc2A6IGRpc2NyZXRlIHF1YW50aXRhdGl2ZSB2YXJpYWJsZS4NCg0KVGhlIGxhdGVyIHR3byBzZXRzIGFyZSBqb2luZWQgaW50byBjcmFzaCB1c2luZyBgbGVmdF9qb2luKClgIHJlZ2FyZGluZyB0aGUgZm9yZWlnbiBrZXlzIHJlc3BlY3RpdmVseS4NCg0KYGBge3J9DQojIFRoaXMgaXMgdGhlIFIgY2h1bmsgZm9yIHRoZSBEYXRhIFNlY3Rpb24NCmNyYXNoLnJhdyA8LSByZWFkLmNzdigiLi9kYXRhL0NyYXNoLmNzdiIpICU+JSANCiAgICAgICAgICAgICAgc2VsZWN0KGNyYXNoX2lkLGxhdF9sb25nLGNhc3VhbHRpZXNfaWQsIGRlc2NyaXB0aW9uX2lkKQ0KZGVzY3JpcHRpb24ucmF3IDwtIHJlYWQuY3N2KCIuL2RhdGEvRGVzY3JpcHRpb24uY3N2Iiwgc3RyaW5nc0FzRmFjdG9ycyA9IFRSVUUpICU+JSANCiAgICAgICAgICAgICAgICAgICAgc2VsZWN0KGRlc2NyaXB0aW9uX2lkLCBzZXZlcml0eSxzcGVlZF9saW1pdCxtaWRibG9jayxpbnRlcnNlY3Rpb24sd2VhdGhlcixjcmFzaF90eXBlLGxpZ2h0aW5nLHRyYWZmaWNfY29udHJvbHMsZHJ1Z3NfYWxjb2hvbCkNCmNhc3VhbHRpZXMucmF3IDwtIHJlYWQuY3N2KCIuL2RhdGEvQ2FzdWFsdGllcy5jc3YiKSAlPiUgDQogICAgICAgICAgICAgICAgICAgIHNlbGVjdChjYXN1YWx0aWVzX2lkLCBmYXRhbGl0aWVzLHNlcmlvdXNfaW5qdXJpZXMsbWlub3JfaW5qdXJpZXMpDQpjcmFzaCA8LSBjcmFzaC5yYXcgJT4lIGxlZnRfam9pbihkZXNjcmlwdGlvbi5yYXcsIGJ5ID0gImRlc2NyaXB0aW9uX2lkIikgJT4lIA0KICAgICAgICAgICAgICAgICAgICAgICAgbGVmdF9qb2luKGNhc3VhbHRpZXMucmF3LCBieSA9ICJjYXN1YWx0aWVzX2lkIikNCmNyYXNoICU+JSBoZWFkKCkNCmBgYA0KDQojIyBVbmRlcnN0YW5kIA0KDQpTdW1tYXJpc2UgYWxsIHRoZSB2YXJpYWJsZXMgaW4gdGhlIGRhdGEgZnJhbWUuDQoNCmBgYHtyfQ0Kc3RyKGNyYXNoKQ0KYGBgDQoNCmBtaWRibG9ja2AsIGBpbnRlcnNlY3Rpb25gIGFuZCBgZHJ1Z3NfYWxjb2hvbGAgc2hvdWxkIGJlIGNvbnZlcnRlZCBpbnRvIGxvZ2ljYWwgdmFyaWFibGVzLiBgZHJ1Z3NfYWxjb2hvbGAgY29udGFpbnMgb25seSBgIlkiYCBhbmQgYCIiYCwgdGh1cyBgIlkiYCBpcyB0cmVhdGVkIGFzIGBUUlVFYCB2YWx1ZSBhbmQgdGhlIG90aGVyIGFzIGBGQUxTRWAuDQoNCmBgYHtyfQ0KY3Jhc2gkbWlkYmxvY2sgPC0gYXMubG9naWNhbChjcmFzaCRtaWRibG9jaykNCmNyYXNoJGludGVyc2VjdGlvbiA8LSBhcy5sb2dpY2FsKGNyYXNoJGludGVyc2VjdGlvbikNCmRydWdzX2FsY29ob2wgPC0gYXMuY2hhcmFjdGVyKGNyYXNoJGRydWdzX2FsY29ob2wpDQpkcnVnc19hbGNvaG9sW2RydWdzX2FsY29ob2wgPT0gIlkiXSA8LSBUUlVFDQpkcnVnc19hbGNvaG9sW2RydWdzX2FsY29ob2wgPT0gIiJdIDwtIEZBTFNFDQpkcnVnc19hbGNvaG9sIDwtIGFzLmxvZ2ljYWwoZHJ1Z3NfYWxjb2hvbCkNCmNyYXNoJGRydWdzX2FsY29ob2wgPC0gZHJ1Z3NfYWxjb2hvbA0Kc3RyKGNyYXNoKQ0KYGBgDQoNCiMjCVRpZHkgJiBNYW5pcHVsYXRlIERhdGEgSSANCg0KVGhlIGBsYXRfbG9uZ2AgY29sdW1uIGNvbnRhaW5zIHR3byB2YXJpYWJsZXMsIHdoaWNoIG1ha2VzIHRoZSBkYXRhIHNldCB1bnRpZHkuIFRoaXMgY29sdW1uIGlzIHNlcGFyYXRlZCBpbnRvIGBsYXRgIGFuZCBgbG5nYCB1c2luZyBgZXh0cmFjdCgpYC4NCg0KYGBge3J9DQpjcmFzaC5leCA8LSBjcmFzaCAlPiUgZXh0cmFjdChsYXRfbG9uZywgaW50bz1jKCJsYXQiLCAibG5nIiksIHJlZ2V4ID0gIlxcKCgtP1tbOmRpZ2l0Ol1dK1xcLltbOmRpZ2l0Ol1dKyksIChbWzpkaWdpdDpdXStcXC5bWzpkaWdpdDpdXSspXFwpIikNCmhlYWQoY3Jhc2guZXgpDQpgYGANCg0KIyMJVGlkeSAmIE1hbmlwdWxhdGUgRGF0YSBJSSANCg0KQSBuZXcgdmFyaWFibGUgYGNhc3VhbHRpZXNgIGlzIGNyZWF0ZWQgdXNpbmcgYG11dGF0ZSgpYCBhcyBhIHN1bSBvZiBgZmF0YWxpdGllc2AsIGBzZXJpb3VzX2luanVyaWVzYCBhbmQgYG1pbm9yX2luanVyaWVzYCB0byByZWZsZWN0IHRoZSB0b3RhbCBjYXN1YWx0aWVzIG9mIGNyYXNoZXMuDQoNCmBgYHtyfQ0KY3Jhc2gubnYgPC0gY3Jhc2guZXggJT4lIG11dGF0ZShjYXN1YWx0aWVzID0gZmF0YWxpdGllcyArIHNlcmlvdXNfaW5qdXJpZXMgKyBtaW5vcl9pbmp1cmllcykNCnN0cihjcmFzaC5udiRjYXN1YWx0aWVzKQ0KYGBgDQoNCg0KIyMJU2NhbiBJIA0KDQpTY2FuIHRoZSBkYXRhIGZyYW1lIGZvciBtaXNzaW5nIHZhbHVlcy4NCg0KYGBge3J9DQpjcmFzaC5udiAlPiUgaXMubmEoKSAlPiUgY29sU3VtcygpDQpgYGANCg0KRm9yIGBsYXRgIGFuZCBgbG5nYCwgdGhlIHR3byB2YXJpYWJsZXMgdG9nZXRoZXIgZGVmaW5lcyB0aGUgZXhhY3QgcGxhY2VzIHdoZXJlIGNyYXNoZXMgaGFwcGVuZWQuIEluIG9yZGVyIG5vdCB0byBhZmZlY3QgdGhlIHBvdGVudGlhbCBhbmFseXNpcyBvZiBjdXJyZW50IGdlb2dyYXBoaWNhbCBkYXRhLCBtaXNzaW5nIHZhbHVlcyBpbiB0aGVzZSB0d28gY29sdW1ucyBhcmUgcmVwbGFjZWQgd2l0aCBgTi9BYC4gV2hpbGUgZm9yIHRoZSBmb3VyIG51bWVyaWMgdmFyaWFibGVzIGBmYXRhbGl0aWVzYCwgYHNlcmlvdXNfaW5qdXJpZXNgLCBgbWlub3JfaW5qdXJpZXNgIGFuZCBgY2FzdWFsdGllc2AsIHRoZXkgYXJlIHJlcGxhY2VkIHdpdGggYDAuMGAuDQoNCmBgYHtyfQ0KY3Jhc2gubmEgPC0gcmVwbGFjZV9uYShjcmFzaC5udiwgbGlzdChsYXQ9Ik4vQSIsIGxuZz0iTi9BIiwgZmF0YWxpdGllcz0wLjAsIHNlcmlvdXNfaW5qdXJpZXM9MC4wLCBtaW5vcl9pbmp1cmllcz0wLjAsIGNhc3VhbHRpZXM9MC4wKSkNCmNyYXNoLm5hICU+JSBpcy5uYSgpICU+JSBjb2xTdW1zKCkNCmBgYA0KDQojIwlUcmFuc2Zvcm0gDQoNClRvIHVuZGVyc3RhbmQgdGhlIGN1cnJlbnQgZGlzdHJpYnV0aW9uIG9mIHRoZSBudW1lcmljIHZhcmlhYmxlIGBjYXN1YWx0aWVzYCwgYSBoaXN0b2dyYXBoIGlzIGRyYXduLg0KDQpgYGB7cn0NCmNyYXNoLm5hICU+JSBnZ3Bsb3QoYWVzKHg9Y2FzdWFsdGllcykpICsNCiAgICAgICAgICAgICAgZ2VvbV9oaXN0b2dyYW0oYmlucyA9IDEwKSArDQogICAgICAgICAgICAgIHNjYWxlX3lfbG9nMTAoKQ0KYGBgDQoNCkdpdmVuIHRoZSBkaXN0cmlidXRpb24gaXMgbm9uLW5vcm1hbCwgQm94LUNveCB0cmFuc2Zvcm1hdGlvbiBpcyB1c2VkLiBUcmFuc2Zvcm1lZCB2YWx1ZXMgaXMgYXBwZW5kZWQgdG8gdGhlIGRhdGEgc2V0IGFzIGBjYXN1YWx0aWVzX2JveGNveGAgYW5kIHVzaW5nIGFub3RoZXIgaGlzdG9ncmFwaCB0byBkZW1vbnN0cmF0ZSB0aGUgbmV3IGRpc3RyaWJ1dGlvbi4NCg0KYGBge3Igd2FybmluZz1GQUxTRX0NCmNhX2JveGNveCA8LSBCb3hDb3goY2EkY2FzdWFsdGllcywgbGFtYmRhID0gImF1dG8iKQ0KY3Jhc2gudHIgPC0gZGF0YS5mcmFtZShjYXN1YWx0aWVzX2JveGNveD1jYV9ib3hjb3gpICU+JSB7YmluZF9jb2xzKGNyYXNoLm5hLCAuKX0NCmNyYXNoLnRyICU+JSBnZ3Bsb3QoYWVzKHg9Y2FzdWFsdGllc19ib3hjb3gpKSArDQogICAgICAgICAgICAgIGdlb21faGlzdG9ncmFtKGJpbnMgPSAxMCkgKw0KICAgICAgICAgICAgICBzY2FsZV95X2xvZzEwKCkNCmBgYA0KDQojIwlTY2FuIElJDQoNClVzaW5nIGEgYm94IHBsb3QsIGl0IGNhbiBiZSBzZWVuIHRoYXQgdGhlcmUgYXJlIGV4aXN0aW5nIG91dGxpZXJzIGFmdGVyIHRoZSB0cmFuc2Zvcm1hdGlvbi4NCg0KYGBge3J9DQpjcmFzaC50ciAlPiUgZ2dwbG90KGFlcyh5PWNhc3VhbHRpZXNfYm94Y294KSkgKw0KICAgICAgICAgICAgICBnZW9tX2JveHBsb3QoKQ0KYGBgDQoNClRvIGZpbmQgdGhlIG51bWJlciBvZiBvdXRsaWVycywgKnoqLXNjb3JlIGlzIGNhbGN1bGF0ZWQuDQoNCmBgYHtyfQ0Kei5zY29yZXMgPC0gY3Jhc2gudHIkY2FzdWFsdGllc19ib3hjb3ggJT4lIHNjb3Jlcyh0eXBlPSJ6IikNCmxlbmd0aCAod2hpY2goIGFicyh6LnNjb3JlcykgPjMgKSkNCmBgYA0KDQpBcyB0aGUgdmVyeSBzbGlnaHQgY2hhbmNlcyB0aGF0IHRoZXJlIGFyZSBpbnB1dCBlcnJvcnMgaW4gdGhpcyBkYXRhIHNldCwgY2FwcGluZyBpcyB1c2VkIHRvIGhhbmRsZSB0aG9zZSBvdXRsaWVycy4gQSBib3ggcGxvdCBvZiB0aGUgdmFyaWFibGUgcG9zdC1jYXBwaW5nIGlzIHVzZWQgdG8gaWxsdXN0cmF0ZSB0aGUgaGFuZGxlZCBvdXRsaWVycy4NCg0KYGBge3J9DQpxdWFudGlsZXMgPC0gcXVhbnRpbGUoIGNyYXNoLnRyJGNhc3VhbHRpZXNfYm94Y294LCBjKC4wNSwgMC4yNSwgMC43NSwgLjk1ICkgKQ0KY2EuaXFyIDwtIElRUihjcmFzaC50ciRjYXN1YWx0aWVzX2JveGNveCkNCmNyYXNoLmNwIDwtIGNyYXNoLnRyDQpjcmFzaC5jcCRjYXN1YWx0aWVzX2JveGNveFsgY3Jhc2guY3AkY2FzdWFsdGllc19ib3hjb3ggPCBxdWFudGlsZXNbMl0gLSAxLjUqY2EuaXFyIF0gPC0gcXVhbnRpbGVzWzFdDQpjcmFzaC5jcCRjYXN1YWx0aWVzX2JveGNveFsgY3Jhc2guY3AkY2FzdWFsdGllc19ib3hjb3ggPiBxdWFudGlsZXNbM10gKyAxLjUqY2EuaXFyIF0gPC0gcXVhbnRpbGVzWzRdDQpjcmFzaC5jcCAlPiUgZ2dwbG90KGFlcyh5PWNhc3VhbHRpZXNfYm94Y294KSkgKw0KICAgICAgICAgICAgICBnZW9tX2JveHBsb3QoKQ0KYGBgDQoNCg==