Required packages
library(readr)
library(magrittr)
library(tidyr)
library(Hmisc)
library(dplyr)
library(outliers)
Executive Summary
- The assignment makes use of the knowledge gained in the data pre-processing course to process the open data set.The data utilised in this assignment is about the flight delay and cancelation information in the United States. The three datasets used are aeroplane.csv,airport.csv and airlines.csv. This datasets are joined using left join by a variable that is common. In order to increase the ease of handelling the data, few non required variables are excluded.
- The variables are of different classes ,some variables are made into a factor. And the month and the week were changed from numeric value to the names of the month and week respectively.
- The dataset was already tidy. The variables which are of no used were removed. A new column was generated from the existing ones by utilising the mutate function.
- The missing values that belonged to numerical class were replaced by the mean and the missing values that belong to categorical were replaced by the mode.
- By utilising the boxplot the outliers were detected and capping techniques were utilised to remove the outliers to the maximum extend. Finally, transformation was conducted on few variables to decrease the skewness of the data and to normalise the data. A normalised data is appropriate to conduct statistical analysis.
Data
- The data is taken from the United States department of transportation’s Bureau of Transportation Statistics.
- The dataset is obtained from the following link:https://www.kaggle.com/usdot/flight-delays#flights.csv
- Three datasets have been utilised in this assignment. The primary dataset is the aeroplane.csv. The other datasets are airport.csv and airlines.csv.
- By utilising the readr package, the datasets are imported and read. The datas are in csv format so read_csv function is made use of.These datasets are analysed and then combined by a common variable.The 3 datasets are joined by using left join.
- The common variable in aeroplane and airlines is the variable AIRLINE which has the airline name.And the airports dataset is combined by the ORIGIN_AIRPORT variable which has the unique airport id.The variables in the airlines dataset has been changed accordingly.
aeroplane<-read_csv("flight-delays/flights.csv")
airports<-read_csv("flight-delays/airports.csv")
airlines<-read_csv("flight-delays/airlines.csv")
#Changing of one of the column names
colnames(airlines)[colnames(airlines)=="AIRLINE"] <- "Plane_Name"
#Changing of one of the column names
colnames(airlines)[colnames(airlines)=="IATA_CODE"] <- "AIRLINE"
air<-aeroplane %>% left_join(airlines, by = "AIRLINE")
#Changing of one of the column names
colnames(airports)[colnames(airports)=="IATA_CODE"] <- "ORIGIN_AIRPORT"
Air_details<-air %>% left_join(airports, by = "ORIGIN_AIRPORT")
head(Air_details, n=10)
Understand
- Inspection of the dataset Air_details is conducted.The dimension is checked there are 5819079 observations and 38 rows.Structure of the dataset is checked and few variables are conveterd to factor.The dataset is checked for incomplete rows and it is dealt with later on. The month and week variable are replaced with their respective month and week name and then converted to factor.
head(Air_details)
dim(Air_details)
[1] 5819079 38
#Any incomplete rows
Air_details[!complete.cases(Air_details),]
Air_details$STATE<-as.factor(Air_details$STATE)
levels(Air_details$STATE)
[1] "AK" "AL" "AR" "AS" "AZ" "CA" "CO" "CT" "DE" "FL" "GA" "GU" "HI" "IA" "ID" "IL" "IN" "KS" "KY" "LA" "MA" "MD" "ME" "MI"
[25] "MN" "MO" "MS" "MT" "NC" "ND" "NE" "NH" "NJ" "NM" "NV" "NY" "OH" "OK" "OR" "PA" "PR" "RI" "SC" "SD" "TN" "TX" "UT" "VA"
[49] "VI" "VT" "WA" "WI" "WV" "WY"
Air_details$ORIGIN_AIRPORT<-as.factor(Air_details$ORIGIN_AIRPORT)
is.factor(Air_details$ORIGIN_AIRPORT)
[1] TRUE
Air_details$DESTINATION_AIRPORT<-as.factor(Air_details$DESTINATION_AIRPORT)
is.factor(Air_details$DESTINATION_AIRPORT)
[1] TRUE
# Define numbers by actual days and months.
Air_details$DAY_OF_WEEK[Air_details$DAY_OF_WEEK == 1] <- 'Monday'
Air_details$DAY_OF_WEEK[Air_details$DAY_OF_WEEK == 2] <- 'Tuesday'
Air_details$DAY_OF_WEEK[Air_details$DAY_OF_WEEK == 3] <- 'Wednesday'
Air_details$DAY_OF_WEEK[Air_details$DAY_OF_WEEK == 4] <- 'Thursday'
Air_details$DAY_OF_WEEK[Air_details$DAY_OF_WEEK == 5] <- 'Friday'
Air_details$DAY_OF_WEEK[Air_details$DAY_OF_WEEK == 6] <- 'Saturday'
Air_details$DAY_OF_WEEK[Air_details$DAY_OF_WEEK == 7] <- 'Sunday'
Air_details$MONTH[Air_details$MONTH == 1] <- 'January'
Air_details$MONTH[Air_details$MONTH == 2] <- 'February'
Air_details$MONTH[Air_details$MONTH == 3] <- 'March'
Air_details$MONTH[Air_details$MONTH == 4] <- 'April'
Air_details$MONTH[Air_details$MONTH == 5] <- 'May'
Air_details$MONTH[Air_details$MONTH== 6] <- 'June'
Air_details$MONTH[Air_details$MONTH == 7] <-'July'
Air_details$MONTH[Air_details$MONTH == 8] <- 'August'
Air_details$MONTH[Air_details$MONTH == 9] <- 'September'
Air_details$MONTH[Air_details$MONTH == 10] <- 'October'
Air_details$MONTH[Air_details$MONTH == 11] <- 'November'
Air_details$MONTH[Air_details$MONTH == 12] <- 'December'
Air_details$DAY_OF_WEEK<-as.factor(Air_details$DAY_OF_WEEK)
levels(Air_details$DAY_OF_WEEK)
[1] "Friday" "Monday" "Saturday" "Sunday" "Thursday" "Tuesday" "Wednesday"
Air_details$MONTH<-as.factor(Air_details$MONTH)
levels(Air_details$MONTH)
[1] "April" "August" "December" "February" "January" "July" "June" "March" "May" "November"
[11] "October" "September"
Tidy & Manipulate Data I
The dataset choosen is already tidy. Here the unwanred variables are removed to increase the ease of anaysis.
#unwanted are removed
Air_details_tidy<- Air_details %>%
select(-DIVERTED,-`CANCELLED`,-`CANCELLATION_REASON`,-`AIR_SYSTEM_DELAY`,-SECURITY_DELAY,-AIRLINE_DELAY,-LATE_AIRCRAFT_DELAY,-WEATHER_DELAY)
Tidy & Manipulate Data II
In order to check the speed of aeroplane in km/hr.A mutate function is used to make a new variable that is the Speed_aeroplane by using Distance which is the distance between two airports and by using AIR_TIME.
Air_details_tidy<-mutate(Air_details_tidy,
Speed_aeroplane = DISTANCE / (AIR_TIME/60))
Scan I
The total number of missing observations are found by using colSums function and the percentage of missing values of total observation is gotten. By using which and is.na function the location of the missing values is found out.The missing values based whether they are mean or catergorical variable are replaced by mean or mode of the respective variable.
colSums(is.na(Air_details_tidy))
YEAR MONTH DAY DAY_OF_WEEK AIRLINE FLIGHT_NUMBER
0 0 0 0 0 0
TAIL_NUMBER ORIGIN_AIRPORT DESTINATION_AIRPORT SCHEDULED_DEPARTURE DEPARTURE_TIME DEPARTURE_DELAY
14721 0 0 0 86153 86153
TAXI_OUT WHEELS_OFF SCHEDULED_TIME ELAPSED_TIME AIR_TIME DISTANCE
89047 89047 6 105071 105071 0
WHEELS_ON TAXI_IN SCHEDULED_ARRIVAL ARRIVAL_TIME ARRIVAL_DELAY Plane_Name
92513 92513 0 92513 105071 0
AIRPORT CITY STATE COUNTRY LATITUDE LONGITUDE
486165 486165 486165 486165 490770 490770
Speed_aeroplane
105071
NA_DEPARTURE_DELAY<-which(is.na(Air_details_tidy$DEPARTURE_DELAY))
NA_ARRIVAL_DELAY<-which(is.na(Air_details_tidy$ARRIVAL_DELAY))
NA_TAILNUMBER<-which(is.na(Air_details_tidy$TAIL_NUMBER))
NA_AIR_TIME<-which(is.na(Air_details_tidy$AIR_TIME))
NA_Speed_aeroplane<-which(is.na(Air_details_tidy$Speed_aeroplane))
#Replace NA
Air_details_tidy$DEPARTURE_DELAY[NA_DEPARTURE_DELAY]<-mean(Air_details_tidy$DEPARTURE_DELAY,na.rm = T)
Air_details_tidy$ARRIVAL_DELAY[NA_ARRIVAL_DELAY]<-mean(Air_details_tidy$ARRIVAL_DELAY,na.rm = T)
Air_details_tidy$AIR_TIME[NA_AIR_TIME]<-mean(Air_details_tidy$AIR_TIME,na.rm = T)
Air_details_tidy$Speed_aeroplane[NA_Speed_aeroplane]<-mean(Air_details_tidy$Speed_aeroplane,na.rm = T)
colSums(is.na(Air_details_tidy))
YEAR MONTH DAY DAY_OF_WEEK AIRLINE FLIGHT_NUMBER
0 0 0 0 0 0
TAIL_NUMBER ORIGIN_AIRPORT DESTINATION_AIRPORT SCHEDULED_DEPARTURE DEPARTURE_TIME DEPARTURE_DELAY
14721 0 0 0 86153 0
TAXI_OUT WHEELS_OFF SCHEDULED_TIME ELAPSED_TIME AIR_TIME DISTANCE
89047 89047 6 105071 0 0
WHEELS_ON TAXI_IN SCHEDULED_ARRIVAL ARRIVAL_TIME ARRIVAL_DELAY Plane_Name
92513 92513 0 92513 0 0
AIRPORT CITY STATE COUNTRY LATITUDE LONGITUDE
486165 486165 486165 486165 490770 490770
Speed_aeroplane
0
Scan II
- The boxplot is utilised to scan the variables for the outliers.The z-score method is used but it is rather ineffective in removing the outliers.While z-score is calculated rescaling and centering of data takes place and data points away from zero are noticed.The points which are away from zero are outliers.A threshold of 3 is utilised it means if the value of z-score is greter than 3 taht data point is considered to be outliers.
- So the capping method is utilised to remove the outliers.In this methodology, the lower and upper percentile is utilised to replace the outliers.We used replace by median, replacing by 1st quad and replacing by 3r quad.
- In replace by median function, the upper and lower percentile limit is set to 25 and 75%.But it is not affective in this case.
- In the replacing by 1st quad function, it is affective to a certain extend.
- In the replacing by 3r quad function, the lower and upper percentile limit has been extended to 5 and 95% and it more effective than the other functions.
#z-score method
# Calculate z-score
z.scores.AIR_TIME <- Air_details_tidy$AIR_TIME %>% scores(type = "z")
z.scores.DISTANCE <- Air_details_tidy$DISTANCE %>% scores(type = "z")
clean_AIR_TIME <- Air_details_tidy[- which(abs(z.scores.AIR_TIME) >3 ),]
clean_DISTANCE<- Air_details_tidy[- which(abs(z.scores.DISTANCE) >3 ),]
par(mfrow=c(1,4))
boxplot(Air_details_tidy$AIR_TIME, main = "Box Plot of AIR_TIME",verticle=TRUE, col = "pink")
boxplot(Air_details_tidy$DISTANCE, main = "Box Plot of DISTANCE",verticle=TRUE, col = "pink")
clean_AIR_TIME$AIR_TIME %>% boxplot(main="Zscore Box Plot of AIR_TIME",
ylab="AIR_TIME($)", col = "pink")
clean_DISTANCE$DISTANCE %>% boxplot(main="zscore Box Plot of DISTANCE",
ylab="DISTANCE($)", col = "pink")
#Median method air time
Replace_by_median <- function(z) {
quantiles <- quantile( z, c( 0.25, 0.50, .75 ) )
z[ z < quantiles[1] - 1.5*IQR(z) ] <- quantiles[2]
z[ z > quantiles[3] + 1.5*IQR(z) ] <- quantiles[2]
z}
Replacing_by_1st_quad<- function(z) {
quantiles <- quantile( z, c( 0.25, 0.50, .75 ) )
z[ z < quantiles[1] - 1.5*IQR(z) ] <- quantiles[1]
z[ z > quantiles[3] + 1.5*IQR(z) ] <- quantiles[1]
z}
Replacing_by_3rd_quad<- function(z) {
quantiles <- quantile( z, c( 0.05,0.25, 0.75, .95 ) )
z[ z < quantiles[1] - 1.5*IQR(z) ] <- quantiles[3]
z[ z > quantiles[3] + 1.5*IQR(z) ] <- quantiles[3]
z}
par(mfrow=c(1,4))

boxplot(Air_details_tidy$AIR_TIME,main="Before Outlier Removal ", col= "pink")
After_Cap<-Air_details_tidy$AIR_TIME %>% Replace_by_median()
boxplot(After_Cap,main="AIR_TIME by Median", col= "pink")
After_Cap_1<-Air_details_tidy$AIR_TIME %>% Replacing_by_1st_quad()
boxplot(After_Cap_1,main="AIR_TIME by 1st Qu",col= "red")
After_Cap_2<-Air_details_tidy$AIR_TIME %>% Replacing_by_3rd_quad()
boxplot(After_Cap_2,main="AIR_TIME by 3rd Qu",col= "yellow")
#Median method dustance
Replacing_by_median <- function(z) {
quantiles <- quantile( z, c( 0.25, 0.50, .75 ) )
z[ z < quantiles[1] - 1.5*IQR(z) ] <- quantiles[2]
z[ z > quantiles[3] + 1.5*IQR(z) ] <- quantiles[2]
z}
Replacing_by_1st<- function(z) {
quantiles <- quantile( z, c( 0.25, 0.50, .75 ) )
z[ z < quantiles[1] - 1.5*IQR(z) ] <- quantiles[1]
z[ z > quantiles[3] + 1.5*IQR(z) ] <- quantiles[1]
z}
Replacing_by_3rd<- function(z) {
quantiles <- quantile( z, c( 0.05,0.25, 0.75, .95 ) )
z[ z < quantiles[1] - 1.5*IQR(z) ] <- quantiles[3]
z[ z > quantiles[3] + 1.5*IQR(z) ] <- quantiles[3]
z}
par(mfrow=c(1,4))

boxplot(Air_details_tidy$DISTANCE,main="Before Outlier Removal ", col= "red")
After_Cap<-Air_details_tidy$DISTANCE %>% Replacing_by_median()
boxplot(After_Cap,main="DISTANCE by Median", col= "red")
After_Cap_1<-Air_details_tidy$DISTANCE %>% Replacing_by_1st()
boxplot(After_Cap_1,main="DISTANCE by 1st Qudr",col= "blue")
After_Cap_2<-Air_details_tidy$DISTANCE %>% Replacing_by_3rd()
boxplot(After_Cap_2,main="DISTANCE by 3rd Qu",col= "pink")

LS0tCnRpdGxlOiAiTUFUSDIzNDkgU2VtZXN0ZXIgMiwgMjAxOSIKYXV0aG9yOiAiREhBQ0hBSU5FRSBNVVJVR0FZQUggKFMzNzk0MzM0KSAmIFJBQ0hFQUwgUk9OQUxEIENPRUxITyAoUzM4MDQ0NDgpIgpzdWJ0aXRsZTogQXNzaWdubWVudCAzCm91dHB1dDoKICBodG1sX25vdGVib29rOiBkZWZhdWx0Ci0tLQojIyBSZXF1aXJlZCBwYWNrYWdlcyAKYGBge3J9CmxpYnJhcnkocmVhZHIpCmxpYnJhcnkobWFncml0dHIpCmxpYnJhcnkodGlkeXIpCmxpYnJhcnkoSG1pc2MpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkob3V0bGllcnMpCmBgYAoKIyMgRXhlY3V0aXZlIFN1bW1hcnkgCiogVGhlIGFzc2lnbm1lbnQgbWFrZXMgdXNlIG9mIHRoZSBrbm93bGVkZ2UgZ2FpbmVkIGluIHRoZSBkYXRhIHByZS1wcm9jZXNzaW5nIGNvdXJzZSB0byBwcm9jZXNzIHRoZSBvcGVuIGRhdGEgc2V0LlRoZSBkYXRhIHV0aWxpc2VkIGluIHRoaXMgYXNzaWdubWVudCBpcyBhYm91dCB0aGUgZmxpZ2h0IGRlbGF5IGFuZCBjYW5jZWxhdGlvbiBpbmZvcm1hdGlvbiBpbiB0aGUgVW5pdGVkIFN0YXRlcy4gVGhlIHRocmVlIGRhdGFzZXRzIHVzZWQgYXJlIGFlcm9wbGFuZS5jc3YsYWlycG9ydC5jc3YgYW5kIGFpcmxpbmVzLmNzdi4gVGhpcyBkYXRhc2V0cyBhcmUgam9pbmVkIHVzaW5nIGxlZnQgam9pbiBieSBhIHZhcmlhYmxlIHRoYXQgaXMgY29tbW9uLiBJbiBvcmRlciB0byBpbmNyZWFzZSB0aGUgZWFzZSBvZiBoYW5kZWxsaW5nIHRoZSBkYXRhLCBmZXcgbm9uIHJlcXVpcmVkIHZhcmlhYmxlcyBhcmUgZXhjbHVkZWQuCiogVGhlIHZhcmlhYmxlcyBhcmUgb2YgZGlmZmVyZW50IGNsYXNzZXMgLHNvbWUgdmFyaWFibGVzIGFyZSBtYWRlIGludG8gYSBmYWN0b3IuIEFuZCB0aGUgbW9udGggYW5kIHRoZSB3ZWVrIHdlcmUgY2hhbmdlZCBmcm9tIG51bWVyaWMgdmFsdWUgdG8gdGhlIG5hbWVzIG9mIHRoZSBtb250aCBhbmQgd2VlayByZXNwZWN0aXZlbHkuCiogVGhlIGRhdGFzZXQgd2FzIGFscmVhZHkgdGlkeS4gVGhlIHZhcmlhYmxlcyB3aGljaCBhcmUgb2Ygbm8gdXNlZCB3ZXJlIHJlbW92ZWQuIEEgbmV3IGNvbHVtbiB3YXMgZ2VuZXJhdGVkIGZyb20gdGhlIGV4aXN0aW5nIG9uZXMgYnkgdXRpbGlzaW5nIHRoZSBtdXRhdGUgZnVuY3Rpb24uCiogVGhlIG1pc3NpbmcgdmFsdWVzIHRoYXQgYmVsb25nZWQgdG8gbnVtZXJpY2FsIGNsYXNzIHdlcmUgcmVwbGFjZWQgYnkgdGhlIG1lYW4gYW5kIHRoZSBtaXNzaW5nIHZhbHVlcyB0aGF0IGJlbG9uZyB0byBjYXRlZ29yaWNhbCB3ZXJlIHJlcGxhY2VkIGJ5IHRoZSBtb2RlLgoqIEJ5IHV0aWxpc2luZyB0aGUgYm94cGxvdCB0aGUgb3V0bGllcnMgd2VyZSBkZXRlY3RlZCBhbmQgY2FwcGluZyB0ZWNobmlxdWVzIHdlcmUgdXRpbGlzZWQgdG8gcmVtb3ZlIHRoZSBvdXRsaWVycyB0byB0aGUgbWF4aW11bSBleHRlbmQuIEZpbmFsbHksIHRyYW5zZm9ybWF0aW9uIHdhcyBjb25kdWN0ZWQgb24gZmV3IHZhcmlhYmxlcyB0byBkZWNyZWFzZSB0aGUgc2tld25lc3Mgb2YgdGhlIGRhdGEgYW5kIHRvIG5vcm1hbGlzZSB0aGUgZGF0YS4gQSBub3JtYWxpc2VkIGRhdGEgaXMgYXBwcm9wcmlhdGUgdG8gY29uZHVjdCBzdGF0aXN0aWNhbCBhbmFseXNpcy4KCiMjIERhdGEgCgoqIFRoZSBkYXRhIGlzIHRha2VuIGZyb20gdGhlIFVuaXRlZCBTdGF0ZXMgZGVwYXJ0bWVudCBvZiB0cmFuc3BvcnRhdGlvbidzIEJ1cmVhdSBvZiBUcmFuc3BvcnRhdGlvbiBTdGF0aXN0aWNzLgoqIFRoZSBkYXRhc2V0IGlzIG9idGFpbmVkIGZyb20gdGhlIGZvbGxvd2luZyBsaW5rOmh0dHBzOi8vd3d3LmthZ2dsZS5jb20vdXNkb3QvZmxpZ2h0LWRlbGF5cyNmbGlnaHRzLmNzdgoqIFRocmVlIGRhdGFzZXRzIGhhdmUgYmVlbiB1dGlsaXNlZCBpbiB0aGlzIGFzc2lnbm1lbnQuIFRoZSBwcmltYXJ5IGRhdGFzZXQgaXMgdGhlIGFlcm9wbGFuZS5jc3YuIFRoZSBvdGhlciBkYXRhc2V0cyBhcmUgYWlycG9ydC5jc3YgYW5kIGFpcmxpbmVzLmNzdi4KKiBCeSB1dGlsaXNpbmcgdGhlIHJlYWRyIHBhY2thZ2UsIHRoZSBkYXRhc2V0cyBhcmUgaW1wb3J0ZWQgYW5kIHJlYWQuIFRoZSBkYXRhcyBhcmUgaW4gY3N2IGZvcm1hdCBzbyByZWFkX2NzdiBmdW5jdGlvbiBpcyBtYWRlIHVzZSBvZi5UaGVzZSBkYXRhc2V0cyBhcmUgYW5hbHlzZWQgYW5kIHRoZW4gY29tYmluZWQgYnkgYSBjb21tb24gdmFyaWFibGUuVGhlIDMgZGF0YXNldHMgYXJlIGpvaW5lZCBieSB1c2luZyBsZWZ0IGpvaW4uCiogVGhlIGNvbW1vbiB2YXJpYWJsZSBpbiBhZXJvcGxhbmUgYW5kIGFpcmxpbmVzIGlzIHRoZSB2YXJpYWJsZSBBSVJMSU5FIHdoaWNoIGhhcyB0aGUgYWlybGluZSBuYW1lLkFuZCB0aGUgYWlycG9ydHMgZGF0YXNldCBpcyBjb21iaW5lZCBieSB0aGUgT1JJR0lOX0FJUlBPUlQgdmFyaWFibGUgd2hpY2ggaGFzIHRoZSB1bmlxdWUgYWlycG9ydCBpZC5UaGUgdmFyaWFibGVzIGluIHRoZSBhaXJsaW5lcyBkYXRhc2V0IGhhcyBiZWVuIGNoYW5nZWQgYWNjb3JkaW5nbHkuCmBgYHtyfQphZXJvcGxhbmU8LXJlYWRfY3N2KCJmbGlnaHQtZGVsYXlzL2ZsaWdodHMuY3N2IikKYWlycG9ydHM8LXJlYWRfY3N2KCJmbGlnaHQtZGVsYXlzL2FpcnBvcnRzLmNzdiIpCmFpcmxpbmVzPC1yZWFkX2NzdigiZmxpZ2h0LWRlbGF5cy9haXJsaW5lcy5jc3YiKQojQ2hhbmdpbmcgb2Ygb25lIG9mIHRoZSBjb2x1bW4gbmFtZXMKY29sbmFtZXMoYWlybGluZXMpW2NvbG5hbWVzKGFpcmxpbmVzKT09IkFJUkxJTkUiXSA8LSAiUGxhbmVfTmFtZSIKI0NoYW5naW5nIG9mIG9uZSBvZiB0aGUgY29sdW1uIG5hbWVzCmNvbG5hbWVzKGFpcmxpbmVzKVtjb2xuYW1lcyhhaXJsaW5lcyk9PSJJQVRBX0NPREUiXSA8LSAiQUlSTElORSIKYWlyPC1hZXJvcGxhbmUgJT4lIGxlZnRfam9pbihhaXJsaW5lcywgYnkgPSAiQUlSTElORSIpCiNDaGFuZ2luZyBvZiBvbmUgb2YgdGhlIGNvbHVtbiBuYW1lcwpjb2xuYW1lcyhhaXJwb3J0cylbY29sbmFtZXMoYWlycG9ydHMpPT0iSUFUQV9DT0RFIl0gPC0gIk9SSUdJTl9BSVJQT1JUIgpBaXJfZGV0YWlsczwtYWlyICU+JSBsZWZ0X2pvaW4oYWlycG9ydHMsIGJ5ID0gIk9SSUdJTl9BSVJQT1JUIikKaGVhZChBaXJfZGV0YWlscywgbj0xMCkKCmBgYAojIyBVbmRlcnN0YW5kIAoqIEluc3BlY3Rpb24gb2YgdGhlIGRhdGFzZXQgQWlyX2RldGFpbHMgaXMgY29uZHVjdGVkLlRoZSBkaW1lbnNpb24gaXMgY2hlY2tlZCB0aGVyZSBhcmUgNTgxOTA3OSBvYnNlcnZhdGlvbnMgYW5kIDM4IHJvd3MuU3RydWN0dXJlIG9mIHRoZSBkYXRhc2V0IGlzIGNoZWNrZWQgYW5kIGZldyB2YXJpYWJsZXMgYXJlIGNvbnZldGVyZCB0byBmYWN0b3IuVGhlIGRhdGFzZXQgaXMgY2hlY2tlZCBmb3IgaW5jb21wbGV0ZSByb3dzIGFuZCBpdCBpcyBkZWFsdCB3aXRoIGxhdGVyIG9uLiBUaGUgbW9udGggYW5kIHdlZWsgdmFyaWFibGUgYXJlIHJlcGxhY2VkIHdpdGggdGhlaXIgcmVzcGVjdGl2ZSBtb250aCBhbmQgd2VlayBuYW1lIGFuZCB0aGVuIGNvbnZlcnRlZCB0byBmYWN0b3IuCmBgYHtyfQpoZWFkKEFpcl9kZXRhaWxzKQpkaW0oQWlyX2RldGFpbHMpCiNBbnkgaW5jb21wbGV0ZSByb3dzCkFpcl9kZXRhaWxzWyFjb21wbGV0ZS5jYXNlcyhBaXJfZGV0YWlscyksXQpBaXJfZGV0YWlscyRTVEFURTwtYXMuZmFjdG9yKEFpcl9kZXRhaWxzJFNUQVRFKQpsZXZlbHMoQWlyX2RldGFpbHMkU1RBVEUpCkFpcl9kZXRhaWxzJE9SSUdJTl9BSVJQT1JUPC1hcy5mYWN0b3IoQWlyX2RldGFpbHMkT1JJR0lOX0FJUlBPUlQpCmlzLmZhY3RvcihBaXJfZGV0YWlscyRPUklHSU5fQUlSUE9SVCkKQWlyX2RldGFpbHMkREVTVElOQVRJT05fQUlSUE9SVDwtYXMuZmFjdG9yKEFpcl9kZXRhaWxzJERFU1RJTkFUSU9OX0FJUlBPUlQpCmlzLmZhY3RvcihBaXJfZGV0YWlscyRERVNUSU5BVElPTl9BSVJQT1JUKQojIERlZmluZSBudW1iZXJzIGJ5IGFjdHVhbCBkYXlzIGFuZCBtb250aHMuCkFpcl9kZXRhaWxzJERBWV9PRl9XRUVLW0Fpcl9kZXRhaWxzJERBWV9PRl9XRUVLID09IDFdIDwtICdNb25kYXknCkFpcl9kZXRhaWxzJERBWV9PRl9XRUVLW0Fpcl9kZXRhaWxzJERBWV9PRl9XRUVLID09IDJdIDwtICdUdWVzZGF5JwpBaXJfZGV0YWlscyREQVlfT0ZfV0VFS1tBaXJfZGV0YWlscyREQVlfT0ZfV0VFSyA9PSAzXSA8LSAnV2VkbmVzZGF5JwpBaXJfZGV0YWlscyREQVlfT0ZfV0VFS1tBaXJfZGV0YWlscyREQVlfT0ZfV0VFSyA9PSA0XSA8LSAnVGh1cnNkYXknCkFpcl9kZXRhaWxzJERBWV9PRl9XRUVLW0Fpcl9kZXRhaWxzJERBWV9PRl9XRUVLID09IDVdIDwtICdGcmlkYXknCkFpcl9kZXRhaWxzJERBWV9PRl9XRUVLW0Fpcl9kZXRhaWxzJERBWV9PRl9XRUVLID09IDZdIDwtICdTYXR1cmRheScKQWlyX2RldGFpbHMkREFZX09GX1dFRUtbQWlyX2RldGFpbHMkREFZX09GX1dFRUsgPT0gN10gPC0gJ1N1bmRheScKQWlyX2RldGFpbHMkTU9OVEhbQWlyX2RldGFpbHMkTU9OVEggPT0gMV0gPC0gJ0phbnVhcnknCkFpcl9kZXRhaWxzJE1PTlRIW0Fpcl9kZXRhaWxzJE1PTlRIID09IDJdIDwtICdGZWJydWFyeScKQWlyX2RldGFpbHMkTU9OVEhbQWlyX2RldGFpbHMkTU9OVEggPT0gM10gPC0gJ01hcmNoJwpBaXJfZGV0YWlscyRNT05USFtBaXJfZGV0YWlscyRNT05USCA9PSA0XSA8LSAnQXByaWwnCkFpcl9kZXRhaWxzJE1PTlRIW0Fpcl9kZXRhaWxzJE1PTlRIID09IDVdIDwtICdNYXknCkFpcl9kZXRhaWxzJE1PTlRIW0Fpcl9kZXRhaWxzJE1PTlRIPT0gNl0gPC0gJ0p1bmUnCkFpcl9kZXRhaWxzJE1PTlRIW0Fpcl9kZXRhaWxzJE1PTlRIID09IDddIDwtJ0p1bHknCkFpcl9kZXRhaWxzJE1PTlRIW0Fpcl9kZXRhaWxzJE1PTlRIID09IDhdIDwtICdBdWd1c3QnCkFpcl9kZXRhaWxzJE1PTlRIW0Fpcl9kZXRhaWxzJE1PTlRIID09IDldIDwtICdTZXB0ZW1iZXInCkFpcl9kZXRhaWxzJE1PTlRIW0Fpcl9kZXRhaWxzJE1PTlRIID09IDEwXSA8LSAnT2N0b2JlcicKQWlyX2RldGFpbHMkTU9OVEhbQWlyX2RldGFpbHMkTU9OVEggPT0gMTFdIDwtICdOb3ZlbWJlcicKQWlyX2RldGFpbHMkTU9OVEhbQWlyX2RldGFpbHMkTU9OVEggPT0gMTJdIDwtICdEZWNlbWJlcicKQWlyX2RldGFpbHMkREFZX09GX1dFRUs8LWFzLmZhY3RvcihBaXJfZGV0YWlscyREQVlfT0ZfV0VFSykKbGV2ZWxzKEFpcl9kZXRhaWxzJERBWV9PRl9XRUVLKQpBaXJfZGV0YWlscyRNT05USDwtYXMuZmFjdG9yKEFpcl9kZXRhaWxzJE1PTlRIKQpsZXZlbHMoQWlyX2RldGFpbHMkTU9OVEgpCmBgYAoKIyMJVGlkeSAmIE1hbmlwdWxhdGUgRGF0YSBJIApUaGUgZGF0YXNldCBjaG9vc2VuIGlzIGFscmVhZHkgdGlkeS4gSGVyZSB0aGUgdW53YW5yZWQgdmFyaWFibGVzIGFyZSByZW1vdmVkIHRvIGluY3JlYXNlIHRoZSBlYXNlIG9mIGFuYXlzaXMuCmBgYHtyfQojdW53YW50ZWQgYXJlIHJlbW92ZWQKQWlyX2RldGFpbHNfdGlkeTwtIEFpcl9kZXRhaWxzICU+JSAKICBzZWxlY3QoLURJVkVSVEVELC1gQ0FOQ0VMTEVEYCwtYENBTkNFTExBVElPTl9SRUFTT05gLC1gQUlSX1NZU1RFTV9ERUxBWWAsLVNFQ1VSSVRZX0RFTEFZLC1BSVJMSU5FX0RFTEFZLC1MQVRFX0FJUkNSQUZUX0RFTEFZLC1XRUFUSEVSX0RFTEFZKQpgYGAKIyMJVGlkeSAmIE1hbmlwdWxhdGUgRGF0YSBJSSAKSW4gb3JkZXIgdG8gY2hlY2sgdGhlIHNwZWVkIG9mIGFlcm9wbGFuZSBpbiBrbS9oci5BIG11dGF0ZSBmdW5jdGlvbiBpcyB1c2VkIHRvIG1ha2UgYSBuZXcgdmFyaWFibGUgdGhhdCBpcyB0aGUgU3BlZWRfYWVyb3BsYW5lIGJ5IHVzaW5nIERpc3RhbmNlIHdoaWNoIGlzIHRoZSBkaXN0YW5jZSBiZXR3ZWVuIHR3byBhaXJwb3J0cyBhbmQgYnkgdXNpbmcgQUlSX1RJTUUuCmBgYHtyfQpBaXJfZGV0YWlsc190aWR5PC1tdXRhdGUoQWlyX2RldGFpbHNfdGlkeSwKICAgICAgICBTcGVlZF9hZXJvcGxhbmUgPSBESVNUQU5DRSAvIChBSVJfVElNRS82MCkpCmBgYAoKIyMJU2NhbiBJIApUaGUgdG90YWwgbnVtYmVyIG9mIG1pc3Npbmcgb2JzZXJ2YXRpb25zIGFyZSBmb3VuZCBieSB1c2luZyBjb2xTdW1zIGZ1bmN0aW9uIGFuZCB0aGUgcGVyY2VudGFnZSBvZiBtaXNzaW5nIHZhbHVlcyBvZiB0b3RhbCBvYnNlcnZhdGlvbiBpcyBnb3R0ZW4uIEJ5IHVzaW5nIHdoaWNoIGFuZCBpcy5uYSBmdW5jdGlvbiB0aGUgbG9jYXRpb24gb2YgdGhlIG1pc3NpbmcgdmFsdWVzIGlzIGZvdW5kIG91dC5UaGUgbWlzc2luZyB2YWx1ZXMgYmFzZWQgd2hldGhlciB0aGV5IGFyZSBtZWFuIG9yIGNhdGVyZ29yaWNhbCB2YXJpYWJsZSBhcmUgcmVwbGFjZWQgYnkgbWVhbiBvciBtb2RlIG9mIHRoZSByZXNwZWN0aXZlIHZhcmlhYmxlLgpgYGB7cn0KY29sU3Vtcyhpcy5uYShBaXJfZGV0YWlsc190aWR5KSkKTkFfREVQQVJUVVJFX0RFTEFZPC13aGljaChpcy5uYShBaXJfZGV0YWlsc190aWR5JERFUEFSVFVSRV9ERUxBWSkpCk5BX0FSUklWQUxfREVMQVk8LXdoaWNoKGlzLm5hKEFpcl9kZXRhaWxzX3RpZHkkQVJSSVZBTF9ERUxBWSkpCk5BX1RBSUxOVU1CRVI8LXdoaWNoKGlzLm5hKEFpcl9kZXRhaWxzX3RpZHkkVEFJTF9OVU1CRVIpKQpOQV9BSVJfVElNRTwtd2hpY2goaXMubmEoQWlyX2RldGFpbHNfdGlkeSRBSVJfVElNRSkpCk5BX1NwZWVkX2Flcm9wbGFuZTwtd2hpY2goaXMubmEoQWlyX2RldGFpbHNfdGlkeSRTcGVlZF9hZXJvcGxhbmUpKQojUmVwbGFjZSBOQSAKQWlyX2RldGFpbHNfdGlkeSRERVBBUlRVUkVfREVMQVlbTkFfREVQQVJUVVJFX0RFTEFZXTwtbWVhbihBaXJfZGV0YWlsc190aWR5JERFUEFSVFVSRV9ERUxBWSxuYS5ybSA9IFQpCkFpcl9kZXRhaWxzX3RpZHkkQVJSSVZBTF9ERUxBWVtOQV9BUlJJVkFMX0RFTEFZXTwtbWVhbihBaXJfZGV0YWlsc190aWR5JEFSUklWQUxfREVMQVksbmEucm0gPSBUKQpBaXJfZGV0YWlsc190aWR5JEFJUl9USU1FW05BX0FJUl9USU1FXTwtbWVhbihBaXJfZGV0YWlsc190aWR5JEFJUl9USU1FLG5hLnJtID0gVCkKQWlyX2RldGFpbHNfdGlkeSRTcGVlZF9hZXJvcGxhbmVbTkFfU3BlZWRfYWVyb3BsYW5lXTwtbWVhbihBaXJfZGV0YWlsc190aWR5JFNwZWVkX2Flcm9wbGFuZSxuYS5ybSA9IFQpCmNvbFN1bXMoaXMubmEoQWlyX2RldGFpbHNfdGlkeSkpCmBgYAoKIyMJU2NhbiBJSQoqIFRoZSBib3hwbG90IGlzIHV0aWxpc2VkIHRvIHNjYW4gdGhlIHZhcmlhYmxlcyBmb3IgdGhlIG91dGxpZXJzLlRoZSB6LXNjb3JlIG1ldGhvZCBpcyB1c2VkIGJ1dCBpdCBpcyByYXRoZXIgaW5lZmZlY3RpdmUgaW4gcmVtb3ZpbmcgdGhlIG91dGxpZXJzLldoaWxlIHotc2NvcmUgaXMgY2FsY3VsYXRlZCByZXNjYWxpbmcgYW5kIGNlbnRlcmluZyBvZiBkYXRhIHRha2VzIHBsYWNlIGFuZCBkYXRhIHBvaW50cyBhd2F5IGZyb20gemVybyBhcmUgbm90aWNlZC5UaGUgcG9pbnRzIHdoaWNoIGFyZSBhd2F5IGZyb20gemVybyBhcmUgb3V0bGllcnMuQSB0aHJlc2hvbGQgb2YgMyBpcyB1dGlsaXNlZCBpdCBtZWFucyBpZiB0aGUgdmFsdWUgb2Ygei1zY29yZSBpcyBncmV0ZXIgdGhhbiAzIHRhaHQgZGF0YSBwb2ludCBpcyBjb25zaWRlcmVkIHRvIGJlIG91dGxpZXJzLiAKKiBTbyB0aGUgY2FwcGluZyBtZXRob2QgaXMgdXRpbGlzZWQgdG8gcmVtb3ZlIHRoZSBvdXRsaWVycy5JbiB0aGlzIG1ldGhvZG9sb2d5LCB0aGUgbG93ZXIgYW5kIHVwcGVyIHBlcmNlbnRpbGUgaXMgdXRpbGlzZWQgdG8gcmVwbGFjZSB0aGUgb3V0bGllcnMuV2UgdXNlZCByZXBsYWNlIGJ5IG1lZGlhbiwgcmVwbGFjaW5nIGJ5IDFzdCBxdWFkIGFuZCByZXBsYWNpbmcgYnkgM3IgcXVhZC4KKiBJbiByZXBsYWNlIGJ5IG1lZGlhbiBmdW5jdGlvbiwgdGhlIHVwcGVyIGFuZCBsb3dlciBwZXJjZW50aWxlIGxpbWl0IGlzIHNldCB0byAyNSBhbmQgNzUlLkJ1dCBpdCBpcyBub3QgYWZmZWN0aXZlIGluIHRoaXMgY2FzZS4KKiBJbiB0aGUgcmVwbGFjaW5nIGJ5IDFzdCBxdWFkIGZ1bmN0aW9uLCBpdCBpcyBhZmZlY3RpdmUgdG8gYSBjZXJ0YWluIGV4dGVuZC4KKiBJbiB0aGUgcmVwbGFjaW5nIGJ5IDNyIHF1YWQgZnVuY3Rpb24sIHRoZSBsb3dlciBhbmQgdXBwZXIgcGVyY2VudGlsZSBsaW1pdCBoYXMgYmVlbiBleHRlbmRlZCB0byA1IGFuZCA5NSUgYW5kIGl0IG1vcmUgZWZmZWN0aXZlIHRoYW4gdGhlIG90aGVyIGZ1bmN0aW9ucy4KCmBgYHtyfQoKI3otc2NvcmUgbWV0aG9kCiMgQ2FsY3VsYXRlIHotc2NvcmUKei5zY29yZXMuQUlSX1RJTUUgPC0gQWlyX2RldGFpbHNfdGlkeSRBSVJfVElNRSAlPiUgIHNjb3Jlcyh0eXBlID0gInoiKQp6LnNjb3Jlcy5ESVNUQU5DRSA8LSBBaXJfZGV0YWlsc190aWR5JERJU1RBTkNFICU+JSAgc2NvcmVzKHR5cGUgPSAieiIpCmNsZWFuX0FJUl9USU1FIDwtIEFpcl9kZXRhaWxzX3RpZHlbLSB3aGljaChhYnMoei5zY29yZXMuQUlSX1RJTUUpID4zICksXQpjbGVhbl9ESVNUQU5DRTwtIEFpcl9kZXRhaWxzX3RpZHlbLSB3aGljaChhYnMoei5zY29yZXMuRElTVEFOQ0UpID4zICksXQpwYXIobWZyb3c9YygxLDQpKQpib3hwbG90KEFpcl9kZXRhaWxzX3RpZHkkQUlSX1RJTUUsIG1haW4gPSAiQm94IFBsb3Qgb2YgQUlSX1RJTUUiLHZlcnRpY2xlPVRSVUUsIGNvbCA9ICJwaW5rIikKYm94cGxvdChBaXJfZGV0YWlsc190aWR5JERJU1RBTkNFLCBtYWluID0gIkJveCBQbG90IG9mIERJU1RBTkNFIix2ZXJ0aWNsZT1UUlVFLCBjb2wgPSAicGluayIpCmNsZWFuX0FJUl9USU1FJEFJUl9USU1FICU+JSAgYm94cGxvdChtYWluPSJac2NvcmUgQm94IFBsb3Qgb2YgQUlSX1RJTUUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bGFiPSJBSVJfVElNRSgkKSIsIGNvbCA9ICJwaW5rIikKY2xlYW5fRElTVEFOQ0UkRElTVEFOQ0UgJT4lICBib3hwbG90KG1haW49InpzY29yZSBCb3ggUGxvdCBvZiBESVNUQU5DRSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHlsYWI9IkRJU1RBTkNFKCQpIiwgY29sID0gInBpbmsiKQojTWVkaWFuIG1ldGhvZCBhaXIgdGltZQpSZXBsYWNlX2J5X21lZGlhbiA8LSBmdW5jdGlvbih6KSB7CiBxdWFudGlsZXMgPC0gcXVhbnRpbGUoIHosIGMoIDAuMjUsIDAuNTAsIC43NSApICkKIHpbIHogPCBxdWFudGlsZXNbMV0gLSAxLjUqSVFSKHopIF0gPC0gcXVhbnRpbGVzWzJdCiB6WyB6ID4gcXVhbnRpbGVzWzNdICsgMS41KklRUih6KSBdIDwtIHF1YW50aWxlc1syXQogen0KUmVwbGFjaW5nX2J5XzFzdF9xdWFkPC0gZnVuY3Rpb24oeikgewogcXVhbnRpbGVzIDwtIHF1YW50aWxlKCB6LCBjKCAwLjI1LCAwLjUwLCAuNzUgKSApCiB6WyB6IDwgcXVhbnRpbGVzWzFdIC0gMS41KklRUih6KSBdIDwtIHF1YW50aWxlc1sxXQogelsgeiA+IHF1YW50aWxlc1szXSArIDEuNSpJUVIoeikgXSA8LSBxdWFudGlsZXNbMV0KIHp9ClJlcGxhY2luZ19ieV8zcmRfcXVhZDwtIGZ1bmN0aW9uKHopIHsKIHF1YW50aWxlcyA8LSBxdWFudGlsZSggeiwgYyggMC4wNSwwLjI1LCAwLjc1LCAuOTUgKSApCiB6WyB6IDwgcXVhbnRpbGVzWzFdIC0gMS41KklRUih6KSBdIDwtIHF1YW50aWxlc1szXQogelsgeiA+IHF1YW50aWxlc1szXSArIDEuNSpJUVIoeikgXSA8LSBxdWFudGlsZXNbM10KIHp9CnBhcihtZnJvdz1jKDEsNCkpCmJveHBsb3QoQWlyX2RldGFpbHNfdGlkeSRBSVJfVElNRSxtYWluPSJCZWZvcmUgT3V0bGllciBSZW1vdmFsICAiLCBjb2w9ICJwaW5rIikKQWZ0ZXJfQ2FwPC1BaXJfZGV0YWlsc190aWR5JEFJUl9USU1FICU+JSBSZXBsYWNlX2J5X21lZGlhbigpCmJveHBsb3QoQWZ0ZXJfQ2FwLG1haW49IkFJUl9USU1FIGJ5IE1lZGlhbiIsIGNvbD0gInBpbmsiKQpBZnRlcl9DYXBfMTwtQWlyX2RldGFpbHNfdGlkeSRBSVJfVElNRSAlPiUgUmVwbGFjaW5nX2J5XzFzdF9xdWFkKCkKYm94cGxvdChBZnRlcl9DYXBfMSxtYWluPSJBSVJfVElNRSBieSAxc3QgUXUiLGNvbD0gInJlZCIpCkFmdGVyX0NhcF8yPC1BaXJfZGV0YWlsc190aWR5JEFJUl9USU1FICU+JSBSZXBsYWNpbmdfYnlfM3JkX3F1YWQoKQpib3hwbG90KEFmdGVyX0NhcF8yLG1haW49IkFJUl9USU1FIGJ5IDNyZCBRdSIsY29sPSAieWVsbG93IikKI01lZGlhbiBtZXRob2QgZHVzdGFuY2UKUmVwbGFjaW5nX2J5X21lZGlhbiA8LSBmdW5jdGlvbih6KSB7CiBxdWFudGlsZXMgPC0gcXVhbnRpbGUoIHosIGMoIDAuMjUsIDAuNTAsIC43NSApICkKIHpbIHogPCBxdWFudGlsZXNbMV0gLSAxLjUqSVFSKHopIF0gPC0gcXVhbnRpbGVzWzJdCiB6WyB6ID4gcXVhbnRpbGVzWzNdICsgMS41KklRUih6KSBdIDwtIHF1YW50aWxlc1syXQogen0KUmVwbGFjaW5nX2J5XzFzdDwtIGZ1bmN0aW9uKHopIHsKIHF1YW50aWxlcyA8LSBxdWFudGlsZSggeiwgYyggMC4yNSwgMC41MCwgLjc1ICkgKQogelsgeiA8IHF1YW50aWxlc1sxXSAtIDEuNSpJUVIoeikgXSA8LSBxdWFudGlsZXNbMV0KIHpbIHogPiBxdWFudGlsZXNbM10gKyAxLjUqSVFSKHopIF0gPC0gcXVhbnRpbGVzWzFdCiB6fQoKUmVwbGFjaW5nX2J5XzNyZDwtIGZ1bmN0aW9uKHopIHsKIHF1YW50aWxlcyA8LSBxdWFudGlsZSggeiwgYyggMC4wNSwwLjI1LCAwLjc1LCAuOTUgKSApCiB6WyB6IDwgcXVhbnRpbGVzWzFdIC0gMS41KklRUih6KSBdIDwtIHF1YW50aWxlc1szXQogelsgeiA+IHF1YW50aWxlc1szXSArIDEuNSpJUVIoeikgXSA8LSBxdWFudGlsZXNbM10KIHp9CnBhcihtZnJvdz1jKDEsNCkpCmJveHBsb3QoQWlyX2RldGFpbHNfdGlkeSRESVNUQU5DRSxtYWluPSJCZWZvcmUgT3V0bGllciBSZW1vdmFsICIsIGNvbD0gInJlZCIpCkFmdGVyX0NhcDwtQWlyX2RldGFpbHNfdGlkeSRESVNUQU5DRSAlPiUgUmVwbGFjaW5nX2J5X21lZGlhbigpCmJveHBsb3QoQWZ0ZXJfQ2FwLG1haW49IkRJU1RBTkNFIGJ5IE1lZGlhbiIsIGNvbD0gInJlZCIpCkFmdGVyX0NhcF8xPC1BaXJfZGV0YWlsc190aWR5JERJU1RBTkNFICU+JSBSZXBsYWNpbmdfYnlfMXN0KCkKYm94cGxvdChBZnRlcl9DYXBfMSxtYWluPSJESVNUQU5DRSBieSAxc3QgUXVkciIsY29sPSAiYmx1ZSIpCkFmdGVyX0NhcF8yPC1BaXJfZGV0YWlsc190aWR5JERJU1RBTkNFICU+JSBSZXBsYWNpbmdfYnlfM3JkKCkKYm94cGxvdChBZnRlcl9DYXBfMixtYWluPSJESVNUQU5DRSBieSAzcmQgUXUiLGNvbD0gInBpbmsiKQoKYGBgCgojIwlUcmFuc2Zvcm0gClRoZSB0cmFuc2Zvcm1hdGlvbiBoYXMgYmVlbiBjb25kdWN0ZWQgb24gQUlSX1RJTUUgYW5kIERJU1RBTkNFIHZhcmlhYmxlcy4gVGhlIGFpbSBpcyB0byBkZWNyZWFzZSB0aGUgc2tld25lc3MgYW5kIGNvbnZlcnQgaXQgdG8gbm9ybWFsaXNlZCBkYXRhLlRoZSBsb2cgdHJhbnNmb3JtYXRpb24gaGFzIGJlZW4gdXNlZCwgaXQgc3ByZWFkcyBvdXQgdGhlIGNvbmdlc3RlZCBkYXRhLkxvZyB0cmFuc2Zvcm1hdGlvbiBpcyB1c2VkIGZvciByaWdodCBza2V3ZWQuQSBub3JtYWwgZGlzdHJpYnV0aW9uIG9mIHRoZSBkYXRhIGlzIGFjaGlldmVkIGJ5IHRoaXMgbWV0aG9kLgpgYGB7cn0KcGFyKG1mcm93PWMoMSw0KSkKaGlzdChBaXJfZGV0YWlsc190aWR5JEFJUl9USU1FLG1haW49IkFJUl9USU1FIEJlZm9yZSBUcmFuc2Zvcm1hdGlvbiIsY29sID0gImdyZWVuIikKVGFpcjwtbG9nMTAoQWlyX2RldGFpbHNfdGlkeSRBSVJfVElNRSkKaGlzdChUYWlyLG1haW49IkFJUl9USU1FIEFmdGVyIFRyYW5zZm9ybWF0aW9uIixjb2wgPSAiZ3JlZW4iKQpoaXN0KEFpcl9kZXRhaWxzX3RpZHkkRElTVEFOQ0UsbWFpbj0iRElTVEFOQ0UgQmVmb3JlIFRyYW5zZm9ybWF0aW9uIixjb2wgPSAicGluayIpClRfZGlzdGFuY2U8LWxvZzEwKEFpcl9kZXRhaWxzX3RpZHkkRElTVEFOQ0UpCmhpc3QoVF9kaXN0YW5jZSxtYWluPSJESVNUQU5DRSBBZnRlciBUcmFuc2Zvcm1hdGlvbiIsY29sID0gInBpbmsiKQpgYGAKPGJyPgo8YnI+Cg==