Required packages
library(readr)
library(dplyr)
library(ggplot2)
library(outliers)
library(knitr)
library(tidyr)
library(Hmisc)
library(lubridate)
Executive Summary
The main objective of this assignment is to utilize the knowledge gained on preprocessing the data throughout this course.To achieve this, diverse preprocessing techniques has been used to pre-process the data.
Initially, the data sets were collected from the internet(open source).In this process two data sets were opted as choice which deal about the “pay stay parking restrictions” and “sign plates located in each pay stay zone”.
Secondly, both the data sets has been imported into the R Studio from the working directory. For better understanding, they were filtered and scraped accordingly. The two data sets were joined respectively by “pay_stay_zone” variable.
The joined data set was assigned to an object called ‘Final_data’ and this object is used for the further operations. On checking the structure of the data, it is clear that the data set is perfectly tidy.
Later, the structure of the variables has been scrutinized for understanding their data types and had performed required conversions which were needed to fit the requirements.The variables that require factor was made into factor and was leveled.
All the errors and missing values were identified and were replaced by the mean value in the case of numeric variables and were replaced by mode value in the case of categorical variables.
Finally, boxplots has been created for the numeric variables to identify the outliers. On performing this, it was identified that there were outliers for the ‘maximum_stay’. These were handled using ‘CAPPING’ approach.
Last but not the least, logarithm transformation is done to change the distribution of ‘maximum_stay’ from right_skewed to normal successfully.
Data
DATA SET-1
SIGN PLATES LOCATED IN EACH PAY STAY ZONE
DESCRIPTION: This data set contains data about the sign plates located in each pay stay zone. A sign plate is where the parking restrictions are displayed. There can be multiple restrictions per Pay Stay zone.
The data set was fetched from an open source.The refrence is as follows:
SOURCE: https://data.melbourne.vic.gov.au/Transport-Movement/Sign-plates-located-in-each-Pay-Stay-zone/wwkr-v8s7
VARIABLE DESCRIPTION: The variables of this data set can be explained as follows:
- pay_stay_zone- A collection of one or more parking bays in which the same restrictions apply.
- restriction_and_payment_display- The parking conditions as displayed on the parking sign.
- sign_exemptions- Any exemptions displayed on the sign.
- days_of_restriction- The days the restrictions applies.
- time_restrictions_start- Time the restrictions start.
- time_restrictions_finish- Time the restrictions finish.
DATA SET-2
PAY STAY PARKING RESTRICTIONS
DESCRIPTION: This dataset contains detailed daily information on parking restrictions in each Pay Stay zone. There can be multiple restrictions per Pay Stay zone per day.
The data set was fetched from an open source.The refrence is as follows:
SOURCE: https://data.melbourne.vic.gov.au/Transport-Movement/Pay-Stay-parking-restrictions/ambt-72qg
VARIABLE DESCRIPTION: The variables of this data set can be explained as follows:
- pay_stay_zone- A collection of one or more parking bays in which the same restrictions apply.
- day_of_week- Day of the week the restriction applies. 1 - Sunday,2- Monday,3- Tuesday,4- Wednesday,5- Thursday,6- Friday 7- Saturday.
- start_time- What time the restriction starts.
- end_time- What time the restriction ends.
- minimum_stay- The minimum stay in minutes.
- maximum_stay- The maximum stay in minutes.
- cost_per_hour- The cost per hour in cents.
STEPS PERFORMED
In this section, both data sets were imported into the R Studio using a readr function called ‘read_csv()’ and their head part is displayed using ‘head()’ function.
On successfully fetching the data into the R Studio the two data sets were joined together using a function called ‘inner_join()’. The data sets were joined by the ‘pay_stay_zone’ variable.
Now, the newly obtained combined data frame is assigned a new name called ‘Final_data()’ on which the later operations in the assignment were worked. Then the dimensions of the new data frame were observed using ‘dim()’ function which tend to have 12 variables in it.
Later, the structure of the new data frame has been observed. It has given a tremondous result showing all the variables were systematically arranged.
Sign_plates_located_in_each_Pay_Stay_zone <- read_csv("Sign_plates_located_in_each_Pay_Stay_zone.csv")
Parsed with column specification:
cols(
pay_stay_zone = col_integer(),
restriction_and_payment_display = col_character(),
sign_exemptions = col_character(),
days_of_restriction = col_character(),
time_restrictions_start = col_time(format = ""),
time_restrictions_finish = col_time(format = "")
)
head(Sign_plates_located_in_each_Pay_Stay_zone)
Pay_Stay_parking_restrictions <- read_csv("Pay_Stay_parking_restrictions.csv")
Parsed with column specification:
cols(
pay_stay_zone = col_integer(),
day_of_week = col_integer(),
start_time = col_time(format = ""),
end_time = col_time(format = ""),
minimum_stay = col_integer(),
maximum_stay = col_integer(),
cost_per_hour = col_integer()
)
head(Pay_Stay_parking_restrictions)
Final_data <- inner_join(Sign_plates_located_in_each_Pay_Stay_zone,Pay_Stay_parking_restrictions)
Joining, by = "pay_stay_zone"
str(Final_data)
Classes ‘tbl_df’, ‘tbl’ and 'data.frame': 11300 obs. of 12 variables:
$ pay_stay_zone : int 30001095 30001095 30001095 30001095 30001095 30001095 30001082 30001082 30001082 30001082 ...
$ restriction_and_payment_display: chr "1P Ticket" "1P Ticket" "1P Ticket" "1P Ticket" ...
$ sign_exemptions : chr NA NA NA NA ...
$ days_of_restriction : chr "MF" "MF" "MF" "MF" ...
$ time_restrictions_start : 'hms' num 07:30:00 07:30:00 07:30:00 07:30:00 ...
..- attr(*, "units")= chr "secs"
$ time_restrictions_finish : 'hms' num 18:30:00 18:30:00 18:30:00 18:30:00 ...
..- attr(*, "units")= chr "secs"
$ day_of_week : int 2 3 4 5 6 7 2 3 4 5 ...
$ start_time : 'hms' num 07:30:00 07:30:00 07:30:00 07:30:00 ...
..- attr(*, "units")= chr "secs"
$ end_time : 'hms' num 18:30:00 18:30:00 18:30:00 18:30:00 ...
..- attr(*, "units")= chr "secs"
$ minimum_stay : int 0 0 0 0 0 0 0 0 0 0 ...
$ maximum_stay : int 60 60 60 60 60 60 660 660 660 660 ...
$ cost_per_hour : int 320 320 320 320 320 320 80 80 80 80 ...
head(Final_data)
dim(Final_data)
[1] 11300 12
Understand
STEPS PERFORMED
In this section, all the types of the varaibles were investigated using ‘typeof()’ function. In prior to that ‘days_of_restriction’ variable is fcatorized and was assigned levels to it. It depicts that the order priority is MF<SA<SS.
‘hms()’ function was applied to the time variables which shows the time in a format of hours-minutes-seconds.This was done for the easy understanding of the future operations that had been performed in the next sections like ‘mutate()’.
Then the class of the start_time and end_time was observed as ‘Period’.
The ‘class()’ function was used to verify the class of the factored and ordered variable “days_of_restriction” and it was observed to be ordered, factored successfully.
Finally, the data types of the variables were summarised using ‘typeof()’ function for all the varibales.
Final_data$days_of_restriction <- factor(Final_data$days_of_restriction, levels = c("MF", "SA","SS"), labels = c("Mon-Fri", "Sat","Sun"),ordered = TRUE)
Final_data$start_time <- hms(Final_data$start_time)
Final_data$end_time <- hms(Final_data$end_time)
class(Final_data$start_time)
[1] "Period"
attr(,"package")
[1] "lubridate"
class(Final_data$end_time)
[1] "Period"
attr(,"package")
[1] "lubridate"
head(Final_data$days_of_restriction)
[1] Mon-Fri Mon-Fri Mon-Fri Mon-Fri Mon-Fri Mon-Fri
Levels: Mon-Fri < Sat < Sun
class(Final_data$days_of_restriction)
[1] "ordered" "factor"
typeof(Final_data$pay_stay_zone)
[1] "integer"
typeof(Final_data$sign_exemptions)
[1] "character"
typeof(Final_data$restriction_and_payment_display)
[1] "character"
typeof(Final_data$time_restrictions_start)
[1] "double"
typeof(Final_data$time_restrictions_finish)
[1] "double"
typeof(Final_data$day_of_week)
[1] "integer"
typeof(Final_data$minimum_stay)
[1] "integer"
typeof(Final_data$maximum_stay)
[1] "integer"
typeof(Final_data$cost_per_hour)
[1] "integer"
Tidy & Manipulate Data I
Our data set was already in tidy format. So, it doesn’t need any changes or alterations. The ‘Final_data’ is in tidy format because of the following reasons:
1)Each variable have its own column.
2)Each observation have its own row.
3)Each value have its own cell.
Tidy & Manipulate Data II
STEPS PERFORMED
In this section, a new variable called “Total_number_of_hours_restricted” has been created using ‘mutate()’ function. This gives the total number of restricted hours for vehicles in a day. This was obtained by subtracting the restriction start_time from the end_time of the parking space. As mentioned in the previous step, the hms() function gives the exact time format of the total restriction hours in a day. By using the ‘head()’ function it is clearly visible that the new variable(“Total_number_of_hours_restricted”) is added into the data set.
Final_data<- mutate(Final_data,Total_number_of_hours_restricted=Final_data$end_time-Final_data$start_time)
head(Final_data)
Scan I
STEPS PERFORMED
In this section, ‘sum(is.na())’ function has been used to find the count of NA’s in the data frame(‘Final_data’).
Then, ‘colSums(is.na())’ has been used to find the missing values in each column of the data frame seperately. It was observed that few variables contain missing values.
All the variables of the data frame were checked whether ‘not a number’ or not by using ‘sum(is.nan())’.It has returned ‘0’ which means not a number (FALSE).
‘sign_exemptions’ was removed using ‘Final_data[-3]’ beacause the entire column has no values. So, imputing that particular column won’t be that efficient.
‘Impute()’ function has been used handle The variables having missing values. This has been achieved by replacing the missing values by their mean and mode values.
Finally, again by observing the result of ‘sum(is.na())’, it has been proved that all the missing values were handled successfully.
sum(is.na(Final_data))
[1] 15346
# Checking NA's
colSums(is.na(Final_data))
pay_stay_zone restriction_and_payment_display sign_exemptions
0 0 11300
days_of_restriction time_restrictions_start time_restrictions_finish
4031 0 0
day_of_week start_time end_time
0 0 0
minimum_stay maximum_stay cost_per_hour
15 0 0
Total_number_of_hours_restricted
0
sum(is.nan(Final_data$pay_stay_zone))
[1] 0
sum(is.nan(Final_data$days_of_restriction))
[1] 0
sum(is.nan(Final_data$time_restrictions_start))
[1] 0
sum(is.nan(Final_data$time_restrictions_finish))
[1] 0
sum(is.nan(Final_data$day_of_week))
[1] 0
sum(is.nan(Final_data$start_time))
[1] 0
sum(is.nan(Final_data$end_time))
[1] 0
sum(is.nan(Final_data$minimum_stay))
[1] 0
sum(is.nan(Final_data$maximum_stay))
[1] 0
sum(is.nan(Final_data$cost_per_hour))
[1] 0
sum(is.nan(Final_data$Total_number_of_hours_restricted))
[1] 0
sum(is.nan(Final_data$restriction_and_payment_display))
[1] 0
Final_data<-Final_data[-3]
# Replacing NA's
Final_data$days_of_restriction <- impute(Final_data$days_of_restriction,fun = mode)
Final_data$minimum_stay <- impute(Final_data$minimum_stay,fun = mean)
colSums(is.na(Final_data))
pay_stay_zone restriction_and_payment_display days_of_restriction
0 0 0
time_restrictions_start time_restrictions_finish day_of_week
0 0 0
start_time end_time minimum_stay
0 0 0
maximum_stay cost_per_hour Total_number_of_hours_restricted
0 0 0
Scan II
STEPS PERFORMED
The main aim of this section is to scrutinize the numeric data for outliers. For this purpose, all the numeric data were cosidered.
By using ‘boxplot()’ function boxplots were created for the all the numeric variables. As our data set contains 5 numeric variables, 5 box plots were created.
It has been noted from the below box plot that, ‘maximum_stay’ do have outliers as it has data points falling outside the bound.
Later, the outliers of this variable were handled using ‘capping’ method. This method helped in replacing the outliers with the nearest neighbours that are not outliers. A user defined function() was used to cap the outliers.
Finally, it has been justified that outliers were handled from the boxplot(After handling outliers).’par(mfrow())’function has been used to create a side by side box plot for easy visualization.
# Boxplot for showing outliers
Final_data$pay_stay_zone<-as.numeric(Final_data$pay_stay_zone)
boxplot(Final_data$pay_stay_zone, main="boxplot of pay_stay_zone", col = "burlywood")

Final_data$day_of_week<-as.numeric(Final_data$day_of_week)
boxplot(Final_data$day_of_week, main="boxplot of day_of_week", col = "burlywood")

Final_data$cost_per_hour<-as.numeric(Final_data$cost_per_hour)
boxplot(Final_data$cost_per_hour, main="boxplot of cost_per_hour", col = "burlywood")

Final_data$minimum_stay<-as.numeric(Final_data$minimum_stay )
boxplot(Final_data$minimum_stay, main="boxplot of minimum_stay", col = "burlywood")

Final_data$maximum_stay<-as.numeric(Final_data$maximum_stay)
boxplot(Final_data$maximum_stay, main="boxplot of maximum stay", col = "burlywood")

# Handing outliers
cap <- function(x){
quantiles <- quantile( x, c(.05, 0.25, 0.75 ) )
x[ x < quantiles[2] - 1.5*IQR(x) ] <- quantiles[1]
x[ x > quantiles[3] + 1.5*IQR(x) ] <- quantiles[4]
x
}
par(mfrow=c(1,2))
boxplot(Final_data$maximum_stay,main="Before handling outliers", col = "burlywood")
max_capped <- Final_data$maximum_stay %>% cap()
boxplot(max_capped, main="After handling outliers", col = "burlywood")

LS0tCnRpdGxlOiAiTUFUSDIzNDkgU2VtZXN0ZXIgMiwgMjAxOCIKYXV0aG9yOiBNb3VuaWthIEd1ZGFwYXRpKHMzNzQ4MzE2KSwgQ2hhaXRhbnlhR29waSBBbWlyaW5lbmkoczM3MzQxMzQpLCBTYWkgTWFoZXNoIFRhdGlrb25kYShzMzcxMTYzOCkKc3VidGl0bGU6IEFzc2lnbm1lbnQgMwpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazogZGVmYXVsdAogIGh0bWxfZG9jdW1lbnQ6CiAgICBkZl9wcmludDogcGFnZWQKICBwZGZfZG9jdW1lbnQ6IGRlZmF1bHQKLS0tCgojIyBSZXF1aXJlZCBwYWNrYWdlcyAKCmBgYHtyfQoKbGlicmFyeShyZWFkcikKbGlicmFyeShkcGx5cikKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KG91dGxpZXJzKQpsaWJyYXJ5KGtuaXRyKQpsaWJyYXJ5KHRpZHlyKQpsaWJyYXJ5KEhtaXNjKQpsaWJyYXJ5KGx1YnJpZGF0ZSkKCmBgYAoKCgojIyBFeGVjdXRpdmUgU3VtbWFyeSAKClRoZSBtYWluIG9iamVjdGl2ZSBvZiB0aGlzIGFzc2lnbm1lbnQgaXMgdG8gdXRpbGl6ZSB0aGUga25vd2xlZGdlIGdhaW5lZCBvbiBwcmVwcm9jZXNzaW5nIHRoZSBkYXRhIHRocm91Z2hvdXQgdGhpcyBjb3Vyc2UuVG8gYWNoaWV2ZSB0aGlzLCBkaXZlcnNlIHByZXByb2Nlc3NpbmcgdGVjaG5pcXVlcyBoYXMgYmVlbiB1c2VkIHRvIHByZS1wcm9jZXNzIHRoZSBkYXRhLgoKSW5pdGlhbGx5LCB0aGUgZGF0YSBzZXRzIHdlcmUgY29sbGVjdGVkIGZyb20gdGhlIGludGVybmV0KG9wZW4gc291cmNlKS5JbiB0aGlzIHByb2Nlc3MgdHdvIGRhdGEgc2V0cyB3ZXJlIG9wdGVkIGFzIGNob2ljZSB3aGljaCBkZWFsIGFib3V0IHRoZSAicGF5IHN0YXkgcGFya2luZyByZXN0cmljdGlvbnMiIGFuZCAic2lnbiBwbGF0ZXMgbG9jYXRlZCBpbiBlYWNoIHBheSBzdGF5IHpvbmUiLgoKU2Vjb25kbHksIGJvdGggdGhlIGRhdGEgc2V0cyBoYXMgYmVlbiBpbXBvcnRlZCBpbnRvIHRoZSBSIFN0dWRpbyBmcm9tIHRoZSB3b3JraW5nIGRpcmVjdG9yeS4gRm9yIGJldHRlciB1bmRlcnN0YW5kaW5nLCB0aGV5IHdlcmUgZmlsdGVyZWQgYW5kIHNjcmFwZWQgYWNjb3JkaW5nbHkuIFRoZSB0d28gZGF0YSBzZXRzIHdlcmUgam9pbmVkIHJlc3BlY3RpdmVseSBieSAicGF5X3N0YXlfem9uZSIgdmFyaWFibGUuCgpUaGUgam9pbmVkIGRhdGEgc2V0IHdhcyBhc3NpZ25lZCB0byBhbiBvYmplY3QgY2FsbGVkICdGaW5hbF9kYXRhJyBhbmQgdGhpcyBvYmplY3QgaXMgdXNlZCBmb3IgdGhlIGZ1cnRoZXIgb3BlcmF0aW9ucy4gT24gY2hlY2tpbmcgdGhlIHN0cnVjdHVyZSBvZiB0aGUgZGF0YSwgaXQgaXMgY2xlYXIgdGhhdCB0aGUgZGF0YSBzZXQgaXMgcGVyZmVjdGx5IHRpZHkuCgpMYXRlciwgdGhlIHN0cnVjdHVyZSBvZiB0aGUgdmFyaWFibGVzIGhhcyBiZWVuIHNjcnV0aW5pemVkIGZvciB1bmRlcnN0YW5kaW5nIHRoZWlyIGRhdGEgdHlwZXMgYW5kIGhhZCBwZXJmb3JtZWQgcmVxdWlyZWQgY29udmVyc2lvbnMgd2hpY2ggd2VyZSBuZWVkZWQgdG8gZml0IHRoZSByZXF1aXJlbWVudHMuVGhlIHZhcmlhYmxlcyB0aGF0IHJlcXVpcmUgZmFjdG9yIHdhcyBtYWRlIGludG8gZmFjdG9yIGFuZCB3YXMgbGV2ZWxlZC4KCkFsbCB0aGUgZXJyb3JzIGFuZCBtaXNzaW5nIHZhbHVlcyB3ZXJlIGlkZW50aWZpZWQgYW5kIHdlcmUgcmVwbGFjZWQgYnkgdGhlIG1lYW4gdmFsdWUgaW4gdGhlIGNhc2Ugb2YgbnVtZXJpYyB2YXJpYWJsZXMgYW5kIHdlcmUgcmVwbGFjZWQgYnkgbW9kZSB2YWx1ZSBpbiB0aGUgY2FzZSBvZiBjYXRlZ29yaWNhbCB2YXJpYWJsZXMuCgpGaW5hbGx5LCBib3hwbG90cyBoYXMgYmVlbiBjcmVhdGVkIGZvciB0aGUgbnVtZXJpYyB2YXJpYWJsZXMgdG8gaWRlbnRpZnkgdGhlIG91dGxpZXJzLiBPbiBwZXJmb3JtaW5nIHRoaXMsIGl0IHdhcyBpZGVudGlmaWVkIHRoYXQgdGhlcmUgd2VyZSBvdXRsaWVycyBmb3IgdGhlICdtYXhpbXVtX3N0YXknLiBUaGVzZSB3ZXJlIGhhbmRsZWQgdXNpbmcgJ0NBUFBJTkcnIGFwcHJvYWNoLgoKTGFzdCBidXQgbm90IHRoZSBsZWFzdCwgbG9nYXJpdGhtIHRyYW5zZm9ybWF0aW9uIGlzIGRvbmUgdG8gY2hhbmdlIHRoZSBkaXN0cmlidXRpb24gb2YgJ21heGltdW1fc3RheScgZnJvbSByaWdodF9za2V3ZWQgdG8gbm9ybWFsIHN1Y2Nlc3NmdWxseS4KCiMjIERhdGEgCgoqKkRBVEEgU0VULTEqKgoKKlNJR04gUExBVEVTIExPQ0FURUQgSU4gRUFDSCBQQVkgU1RBWSBaT05FKgoKMS4gKipERVNDUklQVElPTioqOiBUaGlzIGRhdGEgc2V0IGNvbnRhaW5zIGRhdGEgYWJvdXQgdGhlIHNpZ24gcGxhdGVzIGxvY2F0ZWQgaW4gZWFjaCBwYXkgc3RheSB6b25lLiBBIHNpZ24gcGxhdGUgaXMgd2hlcmUgdGhlIHBhcmtpbmcgcmVzdHJpY3Rpb25zIGFyZSBkaXNwbGF5ZWQuIFRoZXJlIGNhbiBiZSBtdWx0aXBsZSByZXN0cmljdGlvbnMgcGVyIFBheSBTdGF5IHpvbmUuCgoyLiBUaGUgZGF0YSBzZXQgd2FzIGZldGNoZWQgZnJvbSBhbiBvcGVuIHNvdXJjZS5UaGUgcmVmcmVuY2UgaXMgYXMgZm9sbG93czoKCiAgICAqKlNPVVJDRSoqOiBodHRwczovL2RhdGEubWVsYm91cm5lLnZpYy5nb3YuYXUvVHJhbnNwb3J0LU1vdmVtZW50L1NpZ24tcGxhdGVzLWxvY2F0ZWQtaW4tZWFjaC1QYXktU3RheS16b25lL3d3a3ItdjhzNwoKMy4gKipWQVJJQUJMRSBERVNDUklQVElPTioqOiBUaGUgdmFyaWFibGVzIG9mIHRoaXMgZGF0YSBzZXQgY2FuIGJlIGV4cGxhaW5lZCBhcyBmb2xsb3dzOgoKICAgIDEuIHBheV9zdGF5X3pvbmUtIEEgY29sbGVjdGlvbiBvZiBvbmUgb3IgbW9yZSBwYXJraW5nIGJheXMgaW4gd2hpY2ggdGhlIHNhbWUgcmVzdHJpY3Rpb25zIGFwcGx5LgogICAgMi4gcmVzdHJpY3Rpb25fYW5kX3BheW1lbnRfZGlzcGxheS0gVGhlIHBhcmtpbmcgY29uZGl0aW9ucyBhcyBkaXNwbGF5ZWQgb24gdGhlIHBhcmtpbmcgc2lnbi4KICAgIDMuIHNpZ25fZXhlbXB0aW9ucy0gQW55IGV4ZW1wdGlvbnMgZGlzcGxheWVkIG9uIHRoZSBzaWduLgogICAgNC4gZGF5c19vZl9yZXN0cmljdGlvbi0gVGhlIGRheXMgdGhlIHJlc3RyaWN0aW9ucyBhcHBsaWVzLgogICAgNS4gdGltZV9yZXN0cmljdGlvbnNfc3RhcnQtIFRpbWUgdGhlIHJlc3RyaWN0aW9ucyBzdGFydC4KICAgIDYuIHRpbWVfcmVzdHJpY3Rpb25zX2ZpbmlzaC0gVGltZSB0aGUgcmVzdHJpY3Rpb25zIGZpbmlzaC4KCioqREFUQSBTRVQtMioqCgoqUEFZIFNUQVkgUEFSS0lORyBSRVNUUklDVElPTlMqCgoxLiAqKkRFU0NSSVBUSU9OKio6IFRoaXMgZGF0YXNldCBjb250YWlucyBkZXRhaWxlZCBkYWlseSBpbmZvcm1hdGlvbiBvbiBwYXJraW5nIHJlc3RyaWN0aW9ucyBpbiBlYWNoIFBheSBTdGF5IHpvbmUuIFRoZXJlIGNhbiBiZSBtdWx0aXBsZSByZXN0cmljdGlvbnMgcGVyIFBheSBTdGF5IHpvbmUgcGVyIGRheS4KICAgIAoyLiBUaGUgZGF0YSBzZXQgd2FzIGZldGNoZWQgZnJvbSBhbiBvcGVuIHNvdXJjZS5UaGUgcmVmcmVuY2UgaXMgYXMgZm9sbG93czoKCiAgICAqKlNPVVJDRSoqOiBodHRwczovL2RhdGEubWVsYm91cm5lLnZpYy5nb3YuYXUvVHJhbnNwb3J0LU1vdmVtZW50L1BheS1TdGF5LXBhcmtpbmctcmVzdHJpY3Rpb25zL2FtYnQtNzJxZwoKMy4gKipWQVJJQUJMRSBERVNDUklQVElPTioqOiBUaGUgdmFyaWFibGVzIG9mIHRoaXMgZGF0YSBzZXQgY2FuIGJlIGV4cGxhaW5lZCBhcyBmb2xsb3dzOiAgCgogICAgMS4gcGF5X3N0YXlfem9uZS0gQSBjb2xsZWN0aW9uIG9mIG9uZSBvciBtb3JlIHBhcmtpbmcgYmF5cyBpbiB3aGljaCB0aGUgc2FtZSByZXN0cmljdGlvbnMgYXBwbHkuCiAgICAyLiBkYXlfb2Zfd2Vlay0gRGF5IG9mIHRoZSB3ZWVrIHRoZSByZXN0cmljdGlvbiBhcHBsaWVzLiAxIC0gU3VuZGF5LDItIE1vbmRheSwzLSBUdWVzZGF5LDQtIFdlZG5lc2RheSw1LSBUaHVyc2RheSw2LSBGcmlkYXkgICAgICAgICAgICAgICAgICAgICA3LSBTYXR1cmRheS4KICAgIDMuIHN0YXJ0X3RpbWUtIFdoYXQgdGltZSB0aGUgcmVzdHJpY3Rpb24gc3RhcnRzLgogICAgNC4gZW5kX3RpbWUtIFdoYXQgdGltZSB0aGUgcmVzdHJpY3Rpb24gZW5kcy4KICAgIDUuIG1pbmltdW1fc3RheS0gVGhlIG1pbmltdW0gc3RheSBpbiBtaW51dGVzLgogICAgNi4gbWF4aW11bV9zdGF5LSBUaGUgbWF4aW11bSBzdGF5IGluIG1pbnV0ZXMuCiAgICA3LiBjb3N0X3Blcl9ob3VyLSBUaGUgY29zdCBwZXIgaG91ciBpbiBjZW50cy4KICAgIAoqKlNURVBTIFBFUkZPUk1FRCoqCgoxLiBJbiB0aGlzIHNlY3Rpb24sIGJvdGggZGF0YSBzZXRzIHdlcmUgaW1wb3J0ZWQgaW50byB0aGUgUiBTdHVkaW8gdXNpbmcgYSByZWFkciBmdW5jdGlvbiBjYWxsZWQgJ3JlYWRfY3N2KCknIGFuZCB0aGVpciBoZWFkIHBhcnQgaXMgZGlzcGxheWVkIHVzaW5nICdoZWFkKCknIGZ1bmN0aW9uLgoKMi4gT24gc3VjY2Vzc2Z1bGx5IGZldGNoaW5nIHRoZSBkYXRhIGludG8gdGhlIFIgU3R1ZGlvIHRoZSB0d28gZGF0YSBzZXRzIHdlcmUgam9pbmVkIHRvZ2V0aGVyIHVzaW5nIGEgZnVuY3Rpb24gY2FsbGVkICdpbm5lcl9qb2luKCknLiBUaGUgZGF0YSBzZXRzIHdlcmUgam9pbmVkIGJ5IHRoZSAncGF5X3N0YXlfem9uZScgdmFyaWFibGUuCgozLiBOb3csIHRoZSBuZXdseSBvYnRhaW5lZCBjb21iaW5lZCBkYXRhIGZyYW1lIGlzIGFzc2lnbmVkIGEgbmV3IG5hbWUgY2FsbGVkICdGaW5hbF9kYXRhKCknIG9uIHdoaWNoIHRoZSBsYXRlciBvcGVyYXRpb25zIGluIHRoZSBhc3NpZ25tZW50IHdlcmUgd29ya2VkLiBUaGVuIHRoZSBkaW1lbnNpb25zIG9mIHRoZSBuZXcgZGF0YSBmcmFtZSB3ZXJlIG9ic2VydmVkIHVzaW5nICdkaW0oKScgZnVuY3Rpb24gd2hpY2ggdGVuZCB0byBoYXZlIDEyIHZhcmlhYmxlcyBpbiBpdC4KCjQuIExhdGVyLCB0aGUgc3RydWN0dXJlIG9mIHRoZSBuZXcgZGF0YSBmcmFtZSBoYXMgYmVlbiBvYnNlcnZlZC4gSXQgaGFzIGdpdmVuIGEgdHJlbW9uZG91cyByZXN1bHQgc2hvd2luZyBhbGwgdGhlIHZhcmlhYmxlcyB3ZXJlIHN5c3RlbWF0aWNhbGx5IGFycmFuZ2VkLgoKCmBgYHtyfQoKU2lnbl9wbGF0ZXNfbG9jYXRlZF9pbl9lYWNoX1BheV9TdGF5X3pvbmUgPC0gcmVhZF9jc3YoIlNpZ25fcGxhdGVzX2xvY2F0ZWRfaW5fZWFjaF9QYXlfU3RheV96b25lLmNzdiIpCmhlYWQoU2lnbl9wbGF0ZXNfbG9jYXRlZF9pbl9lYWNoX1BheV9TdGF5X3pvbmUpCgpgYGAKCmBgYHtyfQoKUGF5X1N0YXlfcGFya2luZ19yZXN0cmljdGlvbnMgPC0gcmVhZF9jc3YoIlBheV9TdGF5X3BhcmtpbmdfcmVzdHJpY3Rpb25zLmNzdiIpCmhlYWQoUGF5X1N0YXlfcGFya2luZ19yZXN0cmljdGlvbnMpCgpgYGAKCmBgYHtyfQoKRmluYWxfZGF0YSA8LSBpbm5lcl9qb2luKFNpZ25fcGxhdGVzX2xvY2F0ZWRfaW5fZWFjaF9QYXlfU3RheV96b25lLFBheV9TdGF5X3BhcmtpbmdfcmVzdHJpY3Rpb25zKQpzdHIoRmluYWxfZGF0YSkKaGVhZChGaW5hbF9kYXRhKQpkaW0oRmluYWxfZGF0YSkKCmBgYAoKCiMjIFVuZGVyc3RhbmQgCgoqKlNURVBTIFBFUkZPUk1FRCoqCgoxLiBJbiB0aGlzIHNlY3Rpb24sIGFsbCB0aGUgdHlwZXMgb2YgdGhlIHZhcmFpYmxlcyB3ZXJlIGludmVzdGlnYXRlZCB1c2luZyAndHlwZW9mKCknIGZ1bmN0aW9uLiBJbiBwcmlvciB0byB0aGF0ICdkYXlzX29mX3Jlc3RyaWN0aW9uJyB2YXJpYWJsZSBpcyBmY2F0b3JpemVkIGFuZCB3YXMgYXNzaWduZWQgbGV2ZWxzIHRvIGl0LiBJdCBkZXBpY3RzIHRoYXQgdGhlIG9yZGVyIHByaW9yaXR5IGlzIE1GPFNBPFNTLgoKMi4gJ2htcygpJyBmdW5jdGlvbiB3YXMgYXBwbGllZCB0byB0aGUgdGltZSB2YXJpYWJsZXMgd2hpY2ggc2hvd3MgdGhlIHRpbWUgaW4gYSBmb3JtYXQgb2YgaG91cnMtbWludXRlcy1zZWNvbmRzLlRoaXMgd2FzIGRvbmUgZm9yIHRoZSBlYXN5IHVuZGVyc3RhbmRpbmcgb2YgdGhlIGZ1dHVyZSBvcGVyYXRpb25zIHRoYXQgaGFkIGJlZW4gcGVyZm9ybWVkIGluIHRoZSBuZXh0IHNlY3Rpb25zIGxpa2UgJ211dGF0ZSgpJy4KCjMuIFRoZW4gdGhlIGNsYXNzIG9mIHRoZSBzdGFydF90aW1lIGFuZCBlbmRfdGltZSB3YXMgb2JzZXJ2ZWQgYXMgJ1BlcmlvZCcuCgo0LiBUaGUgJ2NsYXNzKCknIGZ1bmN0aW9uIHdhcyB1c2VkIHRvIHZlcmlmeSB0aGUgY2xhc3Mgb2YgdGhlIGZhY3RvcmVkIGFuZCBvcmRlcmVkIHZhcmlhYmxlICJkYXlzX29mX3Jlc3RyaWN0aW9uIiBhbmQgaXQgd2FzIG9ic2VydmVkIHRvIGJlIG9yZGVyZWQsIGZhY3RvcmVkIHN1Y2Nlc3NmdWxseS4KCjUuIEZpbmFsbHksIHRoZSBkYXRhIHR5cGVzIG9mIHRoZSB2YXJpYWJsZXMgd2VyZSBzdW1tYXJpc2VkIHVzaW5nICd0eXBlb2YoKScgZnVuY3Rpb24gZm9yIGFsbCB0aGUgdmFyaWJhbGVzLgoKYGBge3J9CgpGaW5hbF9kYXRhJGRheXNfb2ZfcmVzdHJpY3Rpb24gPC0gZmFjdG9yKEZpbmFsX2RhdGEkZGF5c19vZl9yZXN0cmljdGlvbiwgbGV2ZWxzID0gYygiTUYiLCAiU0EiLCJTUyIpLCBsYWJlbHMgPSBjKCJNb24tRnJpIiwgIlNhdCIsIlN1biIpLG9yZGVyZWQgPSBUUlVFKQoKRmluYWxfZGF0YSRzdGFydF90aW1lIDwtIGhtcyhGaW5hbF9kYXRhJHN0YXJ0X3RpbWUpCkZpbmFsX2RhdGEkZW5kX3RpbWUgPC0gaG1zKEZpbmFsX2RhdGEkZW5kX3RpbWUpCgpjbGFzcyhGaW5hbF9kYXRhJHN0YXJ0X3RpbWUpCmNsYXNzKEZpbmFsX2RhdGEkZW5kX3RpbWUpCgpoZWFkKEZpbmFsX2RhdGEkZGF5c19vZl9yZXN0cmljdGlvbikKY2xhc3MoRmluYWxfZGF0YSRkYXlzX29mX3Jlc3RyaWN0aW9uKQoKdHlwZW9mKEZpbmFsX2RhdGEkcGF5X3N0YXlfem9uZSkKdHlwZW9mKEZpbmFsX2RhdGEkc2lnbl9leGVtcHRpb25zKQp0eXBlb2YoRmluYWxfZGF0YSRyZXN0cmljdGlvbl9hbmRfcGF5bWVudF9kaXNwbGF5KQp0eXBlb2YoRmluYWxfZGF0YSR0aW1lX3Jlc3RyaWN0aW9uc19zdGFydCkKdHlwZW9mKEZpbmFsX2RhdGEkdGltZV9yZXN0cmljdGlvbnNfZmluaXNoKQp0eXBlb2YoRmluYWxfZGF0YSRkYXlfb2Zfd2VlaykKdHlwZW9mKEZpbmFsX2RhdGEkbWluaW11bV9zdGF5KQp0eXBlb2YoRmluYWxfZGF0YSRtYXhpbXVtX3N0YXkpCnR5cGVvZihGaW5hbF9kYXRhJGNvc3RfcGVyX2hvdXIpCgoKYGBgCgoKIyMJVGlkeSAmIE1hbmlwdWxhdGUgRGF0YSBJIAoKT3VyIGRhdGEgc2V0IHdhcyBhbHJlYWR5IGluIHRpZHkgZm9ybWF0LiBTbywgaXQgZG9lc24ndCBuZWVkIGFueSBjaGFuZ2VzIG9yIGFsdGVyYXRpb25zLiBUaGUgJ0ZpbmFsX2RhdGEnIGlzIGluIHRpZHkgZm9ybWF0IGJlY2F1c2Ugb2YgdGhlIGZvbGxvd2luZyByZWFzb25zOgoKMSlFYWNoIHZhcmlhYmxlIGhhdmUgaXRzIG93biBjb2x1bW4uCgoyKUVhY2ggb2JzZXJ2YXRpb24gaGF2ZSBpdHMgb3duIHJvdy4KCjMpRWFjaCB2YWx1ZSBoYXZlIGl0cyBvd24gY2VsbC4KCiMjCVRpZHkgJiBNYW5pcHVsYXRlIERhdGEgSUkgCgoqKlNURVBTIFBFUkZPUk1FRCoqCgpJbiB0aGlzIHNlY3Rpb24sIGEgbmV3IHZhcmlhYmxlIGNhbGxlZCAiVG90YWxfbnVtYmVyX29mX2hvdXJzX3Jlc3RyaWN0ZWQiIGhhcyBiZWVuIGNyZWF0ZWQgdXNpbmcgJ211dGF0ZSgpJyBmdW5jdGlvbi4gVGhpcyBnaXZlcyB0aGUgdG90YWwgbnVtYmVyIG9mIHJlc3RyaWN0ZWQgaG91cnMgZm9yIHZlaGljbGVzIGluIGEgZGF5LiBUaGlzIHdhcyBvYnRhaW5lZCBieSBzdWJ0cmFjdGluZyB0aGUgcmVzdHJpY3Rpb24gc3RhcnRfdGltZSBmcm9tIHRoZSBlbmRfdGltZSBvZiB0aGUgcGFya2luZyBzcGFjZS4gQXMgbWVudGlvbmVkIGluIHRoZSBwcmV2aW91cyBzdGVwLCB0aGUgaG1zKCkgZnVuY3Rpb24gZ2l2ZXMgdGhlIGV4YWN0IHRpbWUgZm9ybWF0IG9mIHRoZSB0b3RhbCByZXN0cmljdGlvbiBob3VycyBpbiBhIGRheS4KQnkgdXNpbmcgdGhlICdoZWFkKCknIGZ1bmN0aW9uIGl0IGlzIGNsZWFybHkgdmlzaWJsZSB0aGF0IHRoZSBuZXcgdmFyaWFibGUoIlRvdGFsX251bWJlcl9vZl9ob3Vyc19yZXN0cmljdGVkIikgaXMgYWRkZWQgaW50byB0aGUgZGF0YSBzZXQuCgoKYGBge3J9CgpGaW5hbF9kYXRhPC0gbXV0YXRlKEZpbmFsX2RhdGEsVG90YWxfbnVtYmVyX29mX2hvdXJzX3Jlc3RyaWN0ZWQ9RmluYWxfZGF0YSRlbmRfdGltZS1GaW5hbF9kYXRhJHN0YXJ0X3RpbWUpCmhlYWQoRmluYWxfZGF0YSkKCmBgYAoKCiMjCVNjYW4gSSAKCioqU1RFUFMgUEVSRk9STUVEKioKCjEuIEluIHRoaXMgc2VjdGlvbiwgJ3N1bShpcy5uYSgpKScgZnVuY3Rpb24gaGFzIGJlZW4gdXNlZCB0byBmaW5kIHRoZSBjb3VudCBvZiBOQSdzIGluIHRoZSBkYXRhIGZyYW1lKCdGaW5hbF9kYXRhJykuCgoyLiBUaGVuLCAnY29sU3Vtcyhpcy5uYSgpKScgaGFzIGJlZW4gdXNlZCB0byBmaW5kIHRoZSBtaXNzaW5nIHZhbHVlcyBpbiBlYWNoIGNvbHVtbiBvZiB0aGUgZGF0YSBmcmFtZSBzZXBlcmF0ZWx5LiBJdCB3YXMgb2JzZXJ2ZWQgdGhhdCBmZXcgdmFyaWFibGVzIGNvbnRhaW4gbWlzc2luZyB2YWx1ZXMuCgozLiBBbGwgdGhlIHZhcmlhYmxlcyBvZiB0aGUgZGF0YSBmcmFtZSB3ZXJlIGNoZWNrZWQgd2hldGhlciAnbm90IGEgbnVtYmVyJyBvciBub3QgYnkgdXNpbmcgJ3N1bShpcy5uYW4oKSknLkl0IGhhcyByZXR1cm5lZCAnMCcKd2hpY2ggbWVhbnMgbm90IGEgbnVtYmVyIChGQUxTRSkuCgo0LiAnc2lnbl9leGVtcHRpb25zJyB3YXMgcmVtb3ZlZCB1c2luZyAnRmluYWxfZGF0YVstM10nIGJlYWNhdXNlIHRoZSBlbnRpcmUgY29sdW1uIGhhcyBubyB2YWx1ZXMuIFNvLCBpbXB1dGluZyB0aGF0IHBhcnRpY3VsYXIgY29sdW1uIHdvbid0IGJlIHRoYXQgZWZmaWNpZW50LiAgCgo1LiAnSW1wdXRlKCknIGZ1bmN0aW9uIGhhcyBiZWVuIHVzZWQgaGFuZGxlIFRoZSB2YXJpYWJsZXMgaGF2aW5nIG1pc3NpbmcgdmFsdWVzLiBUaGlzIGhhcyBiZWVuIGFjaGlldmVkIGJ5IHJlcGxhY2luZyB0aGUgbWlzc2luZyB2YWx1ZXMgYnkgdGhlaXIgbWVhbiBhbmQgbW9kZSB2YWx1ZXMuCgo2LiBGaW5hbGx5LCBhZ2FpbiBieSBvYnNlcnZpbmcgdGhlIHJlc3VsdCBvZiAnc3VtKGlzLm5hKCkpJywgaXQgaGFzIGJlZW4gcHJvdmVkIHRoYXQgYWxsIHRoZSBtaXNzaW5nIHZhbHVlcyB3ZXJlIGhhbmRsZWQgc3VjY2Vzc2Z1bGx5LgoKCmBgYHtyfQoKc3VtKGlzLm5hKEZpbmFsX2RhdGEpKQoKIyBDaGVja2luZyBOQSdzCmNvbFN1bXMoaXMubmEoRmluYWxfZGF0YSkpCgpzdW0oaXMubmFuKEZpbmFsX2RhdGEkcGF5X3N0YXlfem9uZSkpCnN1bShpcy5uYW4oRmluYWxfZGF0YSRkYXlzX29mX3Jlc3RyaWN0aW9uKSkKc3VtKGlzLm5hbihGaW5hbF9kYXRhJHRpbWVfcmVzdHJpY3Rpb25zX3N0YXJ0KSkKc3VtKGlzLm5hbihGaW5hbF9kYXRhJHRpbWVfcmVzdHJpY3Rpb25zX2ZpbmlzaCkpCnN1bShpcy5uYW4oRmluYWxfZGF0YSRkYXlfb2Zfd2VlaykpCnN1bShpcy5uYW4oRmluYWxfZGF0YSRzdGFydF90aW1lKSkKc3VtKGlzLm5hbihGaW5hbF9kYXRhJGVuZF90aW1lKSkKc3VtKGlzLm5hbihGaW5hbF9kYXRhJG1pbmltdW1fc3RheSkpCnN1bShpcy5uYW4oRmluYWxfZGF0YSRtYXhpbXVtX3N0YXkpKQpzdW0oaXMubmFuKEZpbmFsX2RhdGEkY29zdF9wZXJfaG91cikpCnN1bShpcy5uYW4oRmluYWxfZGF0YSRUb3RhbF9udW1iZXJfb2ZfaG91cnNfcmVzdHJpY3RlZCkpCnN1bShpcy5uYW4oRmluYWxfZGF0YSRyZXN0cmljdGlvbl9hbmRfcGF5bWVudF9kaXNwbGF5KSkKCkZpbmFsX2RhdGE8LUZpbmFsX2RhdGFbLTNdCgojIFJlcGxhY2luZyBOQSdzCkZpbmFsX2RhdGEkZGF5c19vZl9yZXN0cmljdGlvbiA8LSBpbXB1dGUoRmluYWxfZGF0YSRkYXlzX29mX3Jlc3RyaWN0aW9uLGZ1biA9IG1vZGUpCkZpbmFsX2RhdGEkbWluaW11bV9zdGF5IDwtIGltcHV0ZShGaW5hbF9kYXRhJG1pbmltdW1fc3RheSxmdW4gPSBtZWFuKQoKY29sU3Vtcyhpcy5uYShGaW5hbF9kYXRhKSkKCgpgYGAKCgojIwlTY2FuIElJCgoqKlNURVBTIFBFUkZPUk1FRCoqCgoxLiBUaGUgbWFpbiBhaW0gb2YgdGhpcyBzZWN0aW9uIGlzIHRvIHNjcnV0aW5pemUgdGhlIG51bWVyaWMgZGF0YSBmb3Igb3V0bGllcnMuIEZvciB0aGlzIHB1cnBvc2UsIGFsbCB0aGUgbnVtZXJpYyBkYXRhIHdlcmUgY29zaWRlcmVkLgoKMi4gQnkgdXNpbmcgJ2JveHBsb3QoKScgZnVuY3Rpb24gYm94cGxvdHMgd2VyZSBjcmVhdGVkIGZvciB0aGUgYWxsIHRoZSBudW1lcmljIHZhcmlhYmxlcy4gQXMgb3VyIGRhdGEgc2V0IGNvbnRhaW5zIDUgbnVtZXJpYyB2YXJpYWJsZXMsIDUgYm94IHBsb3RzIHdlcmUgY3JlYXRlZC4KCjMuIEl0IGhhcyBiZWVuIG5vdGVkIGZyb20gdGhlIGJlbG93IGJveCBwbG90IHRoYXQsICdtYXhpbXVtX3N0YXknIGRvIGhhdmUgb3V0bGllcnMgYXMgaXQgaGFzIGRhdGEgcG9pbnRzIGZhbGxpbmcgb3V0c2lkZSB0aGUgYm91bmQuCgo0LiBMYXRlciwgdGhlIG91dGxpZXJzIG9mIHRoaXMgdmFyaWFibGUgd2VyZSBoYW5kbGVkIHVzaW5nICdjYXBwaW5nJyBtZXRob2QuIFRoaXMgbWV0aG9kIGhlbHBlZCBpbiByZXBsYWNpbmcgdGhlIG91dGxpZXJzIHdpdGggdGhlIG5lYXJlc3QgbmVpZ2hib3VycyB0aGF0IGFyZSBub3Qgb3V0bGllcnMuIEEgdXNlciBkZWZpbmVkIGZ1bmN0aW9uKCkgd2FzIHVzZWQgdG8gY2FwIHRoZSBvdXRsaWVycy4KCjUuIEZpbmFsbHksIGl0IGhhcyBiZWVuIGp1c3RpZmllZCB0aGF0IG91dGxpZXJzIHdlcmUgaGFuZGxlZCBmcm9tIHRoZSBib3hwbG90KEFmdGVyIGhhbmRsaW5nIG91dGxpZXJzKS4ncGFyKG1mcm93KCkpJ2Z1bmN0aW9uIGhhcyBiZWVuIHVzZWQgdG8gY3JlYXRlIGEgc2lkZSBieSBzaWRlIGJveCBwbG90IGZvciBlYXN5IHZpc3VhbGl6YXRpb24uCgpgYGB7cn0KCiMgQm94cGxvdCBmb3Igc2hvd2luZyBvdXRsaWVycwoKRmluYWxfZGF0YSRwYXlfc3RheV96b25lPC1hcy5udW1lcmljKEZpbmFsX2RhdGEkcGF5X3N0YXlfem9uZSkKYm94cGxvdChGaW5hbF9kYXRhJHBheV9zdGF5X3pvbmUsIG1haW49ImJveHBsb3Qgb2YgcGF5X3N0YXlfem9uZSIsIGNvbCA9ICJidXJseXdvb2QiKQoKRmluYWxfZGF0YSRkYXlfb2Zfd2VlazwtYXMubnVtZXJpYyhGaW5hbF9kYXRhJGRheV9vZl93ZWVrKQpib3hwbG90KEZpbmFsX2RhdGEkZGF5X29mX3dlZWssIG1haW49ImJveHBsb3Qgb2YgZGF5X29mX3dlZWsiLCBjb2wgPSAiYnVybHl3b29kIikKCkZpbmFsX2RhdGEkY29zdF9wZXJfaG91cjwtYXMubnVtZXJpYyhGaW5hbF9kYXRhJGNvc3RfcGVyX2hvdXIpCmJveHBsb3QoRmluYWxfZGF0YSRjb3N0X3Blcl9ob3VyLCBtYWluPSJib3hwbG90IG9mIGNvc3RfcGVyX2hvdXIiLCBjb2wgPSAiYnVybHl3b29kIikKCkZpbmFsX2RhdGEkbWluaW11bV9zdGF5PC1hcy5udW1lcmljKEZpbmFsX2RhdGEkbWluaW11bV9zdGF5ICkKYm94cGxvdChGaW5hbF9kYXRhJG1pbmltdW1fc3RheSwgbWFpbj0iYm94cGxvdCBvZiBtaW5pbXVtX3N0YXkiLCBjb2wgPSAiYnVybHl3b29kIikKCkZpbmFsX2RhdGEkbWF4aW11bV9zdGF5PC1hcy5udW1lcmljKEZpbmFsX2RhdGEkbWF4aW11bV9zdGF5KQpib3hwbG90KEZpbmFsX2RhdGEkbWF4aW11bV9zdGF5LCBtYWluPSJib3hwbG90IG9mIG1heGltdW0gc3RheSIsIGNvbCA9ICJidXJseXdvb2QiKQoKCmBgYAoKCmBgYHtyfQojIEhhbmRpbmcgb3V0bGllcnMKCmNhcCA8LSBmdW5jdGlvbih4KXsKICAgIHF1YW50aWxlcyA8LSBxdWFudGlsZSggeCwgYyguMDUsIDAuMjUsIDAuNzUgKSApCiAgICB4WyB4IDwgcXVhbnRpbGVzWzJdIC0gMS41KklRUih4KSBdIDwtIHF1YW50aWxlc1sxXQogICAgeFsgeCA+IHF1YW50aWxlc1szXSArIDEuNSpJUVIoeCkgXSA8LSBxdWFudGlsZXNbNF0KICAgIHgKfQoKcGFyKG1mcm93PWMoMSwyKSkKCmJveHBsb3QoRmluYWxfZGF0YSRtYXhpbXVtX3N0YXksbWFpbj0iQmVmb3JlIGhhbmRsaW5nIG91dGxpZXJzIiwgY29sID0gImJ1cmx5d29vZCIpCgptYXhfY2FwcGVkIDwtIEZpbmFsX2RhdGEkbWF4aW11bV9zdGF5ICU+JSBjYXAoKQoKYm94cGxvdChtYXhfY2FwcGVkLCBtYWluPSJBZnRlciBoYW5kbGluZyBvdXRsaWVycyIsIGNvbCA9ICJidXJseXdvb2QiKQpgYGAKIyMJVHJhbnNmb3JtIAoKKipTVEVQUyBQRVJGT1JNRUQqKgoKSW4gdGhpcyBzZWN0aW9uLCB0d28gaGlzdG9ncmFtcyBoYXMgYmVlbiBjcmVhdGVkIHVzaW5nICdoaXN0KCknIGZ1bmN0aW9uLiBCZWZvcmUgdHJhbnNmb3JtYXRpb24sIHRoZSBoaXN0b2dyYW0gdGVuZCB0byBiZSByaWdodCBza2V3ZWQuIFNvLCAnbG9nMTAoKScgZnVuY3Rpb24gaGFzIGJlZW4gdXNlZCB0byBnYWluIHRoZSBub3JtYWxseSBkaXN0cmlidXRlZCBoaXN0b2dyYW0uIE9uIHVzaW5nIHRoaXMsIGEgbm9ybWFsIGRpc3RyaWJ1dGVkIGhpc3RvZ3JhbSBoYXMgYmVlbiBjcmVhdGVkIHdoaWNoIHdhcyB0aXRsZWQgYXMgJ2hpc3QgYWZ0ZXIgdHJhbnNmb3JtYXRpb24nLgoKCmBgYHtyfQoKcGFyKG1mcm93PWMoMSwyKSkKCmhpc3QoRmluYWxfZGF0YSRtYXhpbXVtX3N0YXksbWFpbiA9ICJIaXN0IEJlZm9yZSBUcmFuc2Zvcm1hdGlvbiIsIGNvbCA9ICJidXJseXdvb2QiKQoKTWF4X3N0YXlfbG9nIDwtIGxvZzEwKEZpbmFsX2RhdGEkbWF4aW11bV9zdGF5KQoKaGlzdChNYXhfc3RheV9sb2csbWFpbiA9ICJIaXN0IEFmdGVyIFRyYW5zZm9ybWF0aW9uIiwgY29sID0gImJ1cmx5d29vZCIpCgpgYGAKCgo=