Data exploration is a vital aspect of statistical analysis and provides crucial insight in the information and patterns of the data.This document demonstrates some useful code for basic data exploration and organisation.
1. Data preparation
str(poddata) # Investigate the structure of the object poddata.
'data.frame': 54742 obs. of 15 variables:
$ Deployment_fk : int 2573 2573 2573 2573 2573 2573 2573 2573 2573 2573 ...
$ Time : Factor w/ 20000 levels "2014-06-23 00:00:00",..: 1 2 3 4 5 6 7 8 9 10 ...
$ Species : Factor w/ 1 level "NBHF": 1 1 1 1 1 1 1 1 1 1 ...
$ Milliseconds : int 0 0 0 0 0 0 0 0 0 0 ...
$ Number_clicks_filtered: int 0 0 0 0 0 0 0 0 0 0 ...
$ Number_clicks_total : int 0 0 0 0 0 0 0 0 10760 0 ...
$ Lost_minutes : int 0 0 0 0 0 0 0 0 2 0 ...
$ Recorded : int 0 0 0 0 0 0 0 0 6 0 ...
$ Dpm : int 0 0 0 0 0 0 0 0 0 0 ...
$ Dp10m : int 0 0 0 0 0 0 0 0 0 0 ...
$ Station : Factor w/ 16 levels "bpns-Belwind C05",..: 5 5 5 5 5 5 5 5 5 5 ...
$ Latitude : num 51.6 51.6 51.6 51.6 51.6 ...
$ Longitude : num 2.98 2.98 2.98 2.98 2.98 ...
$ Mooring_type : Factor w/ 2 levels "bottom-mooring",..: 2 2 2 2 2 2 2 2 2 2 ...
$ Receiver : Factor w/ 16 levels "POD-2420","POD-2421",..: 4 4 4 4 4 4 4 4 4 4 ...
Some explanation on the different variables:
- Deployment_fk = An identifying number assigned to each deployment
- Time = Date and time
- Species = NBHF (Narrow Band High Frequency)
- Milliseconds = The sum of milliseconds in which a porpoise was detected
- Number_clicks_filtered = The amount of clicks, identified as porpoise clicks
- Number_clicks_total = The total amount of clicks, from different sources
- Lost_minutes = The number of minutes for which the C-POD reached a detection threshold and recorded the minute only partially.
- Recorded = The number of minutes that the C-POD was on.
- Dpm = The sum of Detection Positive Minutes.
- Dp10m = The sum of Detection Positive 10 Minutes.
- Station = The name of the station.
- Latitude
- Longitude
- Mooring_type = Indicates whether the C-POD was deployed on a surface-buoy or a bottom mooring.
- Receiver = The name of the receiver.
A first exploration with the str() function already indicates some issues and possibilites for improvement:
Receiver, Station, Mooring_type and Species are considered character variables.
Time is considered a factor, while is a time variable.
1.1 Organizing the data and adding relevant variables
Adding the variable quality might be useful for future reference.
poddata$Quality <- "hi+mod"
Detection positive hour, Dph, will indicate whether there was a detection within the hour (1) or not (0).
poddata$Dph <- ifelse(poddata$Dpm >0, 1, 0)
The exact locations for some C-POD deployments changed slightly over the years. Adding a variable Zone will be useful to link the data of adjacent stations.
poddata$Zone<- ifelse(poddata$Station=="bpns-Oostendebank Oost", "Oostende",
ifelse(poddata$Station=="bpns-Reefballs-cpower", "bnps-Reefballs-cpower",
ifelse(poddata$Station== "bpns-Wenduinebankw", "Oostende",
ifelse(poddata$Station=="bpns-WK16", "Oostende",
ifelse(poddata$Station=="bpns-Belwind C05", "bpns-Belwind C05",
ifelse(poddata$Station== "bpns-D1", "Middelkerke",
ifelse(poddata$Station=="bpns-WK9", "WK9en12",
ifelse(poddata$Station=="bpns-Gootebank", "Gootebank",
ifelse(poddata$Station=="bpns-VG2" , "Gootebank",
ifelse(poddata$Station== "bpns-WK12", "WK9en12",
ifelse(poddata$Station== "bpns-Reefballs Belwind", "bpns-Reefballs Belwind",
ifelse(poddata$Station== "bpns-Oostdyck West", "bpns-Oostdyck West",
ifelse(poddata$Station== "bpns-LST420", "Middelkerke",
ifelse(poddata$Station== "bpns-Middelkerke South", "Middelkerke",
ifelse(poddata$Station== "bpns-Lottobuoy", "bpns-Lottobuoy",
ifelse(poddata$Station== "bpns-Birkenfels", "bpns-Birkenfels", NA))))))))))))))))
Click frequency (also called PPM, Porpoise Positive Minutes) and Click intensity are common metrics in acoustic porpoise research.
poddata$Click_frequency <- poddata$Dpm/poddata$Recorded
poddata$Click_intensity <- poddata$Number_clicks_filtered/poddata$Click_frequency
Understanding the content of a variable, we can assign an appropriate data type.
poddata$Receiver <- as.factor(poddata$Receiver)
poddata$Station <- as.factor(poddata$Station)
poddata$Mooring_type <- as.factor(poddata$Mooring_type)
poddata$Quality <- as.factor(poddata$Quality)
poddata$Species <- as.factor(poddata$Species)
poddata$Zone <- as.factor(poddata$Zone)
The lubridate package provides some useful tools to handle dates and times.
library(lubridate)
To install a package use the install.packages() function.
Some explanation on the package:
today()
[1] "2017-10-27"
now()
[1] "2017-10-27 15:41:26 CEST"
The parse_date_time() function transforms the character variable to the POSIXct format, enabling you to extract features of time from the variable (eg. year(), month(), day(), hour(), minute()). Be careful to specify the orders argument correctly! For example: in these data, datetime was in a different format than the installation and activation dates.
day(moonlanding)
[1] 24
date(moonlanding)
[1] "1969-07-24"
We can now transform our own variable Time.
poddata$Time <- parse_date_time(poddata$Time, orders = "ymd HMS")
The summary function gives a quick peek at our data.
summary(poddata)
Deployment_fk Time Species Milliseconds
Min. :2554 Min. :2014-06-23 00:00:00 NBHF:54742 Min. : 0
1st Qu.:2578 1st Qu.:2016-04-28 04:00:00 1st Qu.: 0
Median :2587 Median :2016-10-04 10:00:00 Median : 0
Mean :2589 Mean :2016-08-20 09:46:23 Mean : 2552
3rd Qu.:2597 3rd Qu.:2017-02-11 09:00:00 3rd Qu.: 429
Max. :2626 Max. :2017-08-09 12:00:00 Max. :352309
Number_clicks_filtered Number_clicks_total Lost_minutes Recorded Dpm
Min. : 0.00 Min. : 0 Min. : 0.00 Min. : 0.00 Min. : 0.000
1st Qu.: 0.00 1st Qu.: 8926 1st Qu.: 0.00 1st Qu.:60.00 1st Qu.: 0.000
Median : 0.00 Median : 59279 Median : 0.00 Median :60.00 Median : 0.000
Mean : 98.25 Mean : 99658 Mean :16.01 Mean :55.23 Mean : 2.024
3rd Qu.: 18.00 3rd Qu.:214452 3rd Qu.:33.00 3rd Qu.:60.00 3rd Qu.: 1.000
Max. :17679.00 Max. :245760 Max. :60.00 Max. :60.00 Max. :104.000
Dp10m Station Latitude Longitude
Min. :0.0000 bpns-Reefballs Belwind:10628 Min. :51.23 Min. :2.439
1st Qu.:0.0000 bpns-WK9 : 7338 1st Qu.:51.29 1st Qu.:2.813
Median :0.0000 bpns-Reefballs-cpower : 5881 Median :51.46 Median :2.865
Mean :0.6029 bpns-Gootebank : 5134 Mean :51.48 Mean :2.869
3rd Qu.:1.0000 bpns-Oostendebank Oost: 4498 3rd Qu.:51.58 3rd Qu.:2.995
Max. :6.0000 bpns-Lottobuoy : 3576 Max. :51.70 Max. :3.107
(Other) :17687
Mooring_type Receiver Quality Dph
bottom-mooring:13247 POD-2729: 7133 hi+mod:54742 Min. :0.0000
surface-buoy :41495 POD-2724: 6835 1st Qu.:0.0000
POD-2421: 5983 Median :0.0000
POD-2725: 4858 Mean :0.2969
POD-2422: 4737 3rd Qu.:1.0000
POD-2730: 3795 Max. :1.0000
(Other) :21401
Zone Click_frequency Click_intensity
bpns-Reefballs Belwind:10628 Min. :0.0000 Min. : 36.0
WK9en12 : 8670 1st Qu.:0.0000 1st Qu.: 902.3
Gootebank : 8114 Median :0.0000 Median : 1560.0
Oostende : 7357 Mean :0.0362 Mean : 2010.2
Middelkerke : 5945 3rd Qu.:0.0167 3rd Qu.: 2610.0
bnps-Reefballs-cpower : 5881 Max. :2.0000 Max. :25290.0
(Other) : 8147 NA's :429 NA's :38487
1.2 Data subsetting
Subset the data with generic R code: some examples.
poddata[1,]
poddata[1:5,]
poddata[,1]
poddata[,c(2,4)]
unique(poddata$Station)
poddata[poddata$Station == "bpns-Lottobuoy",]
The R package dplyr provides useful functions for data organization.
library(dplyr)
The select() function allows for a straightforward selection of columns (useful select syntaxis).
select(poddata, Receiver)
select(poddata, -Receiver)
select(poddata, Station, Latitude, Longitude)
The equivalent function for rows is filter() (useful filter syntaxis).
filter(poddata, Station == "bpns-Lottobuoy")
filter(poddata, Station == "bpns-Lottobuoy" | Station == "bpns-WK12")
filter(poddata, Station != "bpns-Lottobuoy")
filter(poddata, Dpm > 0)
filter(poddata, Dpm > 0 & Station == "bpns-Lottobuoy")
Side note: some function names of dplyr are identical to function names of other packages. This can cause an error when using the function. In this case, write the package name and :: before the function.
dplyr::select(poddata, Receiver)
Side note: this can be combined with the lubridate functions.
filter(poddata, year(Time) == 2017)
A value of zero for the variable Recorded indicates the C-POD was not ‘on’ during the entire hour. Hence, we can filter out these rows.
poddata <- filter(poddata, Recorded > 0)
A value of 60 for the variable Recorded indicates the C-POD was not ‘on’ for some minutes during the hour. We can choose whether to filter out these rows.
poddata <- filter(poddata, Recorded == 60)
1.3 Summarizing data
Combining the functions group_by and summarise allows for simple organization: an example.
First, we group our dataframe by Zone.
poddata_group <- group_by(poddata, Zone)
groups(poddata_group) # Check the grouping variable
[[1]]
Zone
Next, we can calculate some summary statistics for each Zone seperately.
poddata_sum <- summarise(poddata_group,
Dpm_median = median(Dpm),
Dpm_mean = mean(Dpm),
Dpm_max = max(Dpm))
rm(poddata_group, poddata_sum) # Remove the example data frames
We will now apply these functions to get a new data frame that summarizes the detections per day.
poddata_day <- poddata # Copy the data in a new data frame.
Three ways to take the date out of our time variable. Using the lubridate::date() function is very elegant, HOWEVER: lubridate has some bugs when combined with the packages dplyr/plyr.
poddata_day$Time <- date(poddata_day$Time)
poddata_day$Time <- parse_date_time(paste(year(poddata$Time), month(poddata$Time), day(poddata$Time), sep = "-"), orders = "ymd")
poddata_day$Time <- as.POSIXct(paste(year(poddata$Time), month(poddata$Time), day(poddata$Time), sep = "-"),format="%Y-%m-%d", tz="UTC")
Now we can group by Time.
poddata_group <- dplyr::group_by(poddata_day, Deployment_fk, Receiver, Station, Zone, Latitude, Longitude, Mooring_type, Quality, Time)
poddata_day <- dplyr::summarise(poddata_group,
Milliseconds = sum(Milliseconds),
Number_clicks_filtered = sum(Number_clicks_filtered),
Number_clicks_total = sum(Number_clicks_total),
Lost_minutes = sum(Lost_minutes),
Dpm = sum(Dpm),
Dp10m = sum(Dp10m),
Dph = sum(Dph),
Recorded = sum(Recorded))
poddata_day$Click_frequency <- poddata_day$Dpm/poddata_day$Recorded
poddata_day$Click_intensity <- poddata_day$Number_clicks_filtered/poddata_day$Click_frequency
rm(poddata_group)
Again, we can choose to only use full days.
poddata_day <- filter(poddata_day, Recorded == 24*60)
2. Data exploration
The R package ggplot2 enables the construction of complex, illustrious graphs with simple code (useful ggplot syntax). We will first use this to make simple plots for exploration and later apply more advanced plotting techniques.
library(ggplot2)
2.1 A first look at the data availability
Making a graph in ggplot: an example to test the data availability.
ggplot(data = poddata_day, aes(x= Time, y = Quality)) # This makes an empty plot
Three ways to code the same plot.
ggplot(data = poddata_day, aes(x= Time, y = Quality)) + geom_point()
ggplot() + geom_point(data = poddata_day, aes(x= Time, y = Quality))
ggplot(data = poddata_day) + geom_point(aes(x= Time, y = Quality))
Now we can investigate the data availability per station.
ggplot(data = poddata_day) + geom_point(aes(x= Time, y = Station))
Same for zones. By defining the theme argument, we can change the graphics of our plot.
ggplot(data = poddata_day) + geom_point(aes(x= Time, y = Zone)) +
theme_bw() +
theme(axis.text = element_text(size = 16),
axis.title = element_blank())
2.2 In line with Zuur’s protocol for data exploration
In the next steps, we will visually explore the data in line with the first four steps of Zuur’s protocol.
2.2.1 Step 1: Are there outliers in Y and X?
Construct a basic boxplot to visualize the spread of the data and check for outliers.
ggplot(data = poddata_day) +
geom_boxplot(aes(x = factor(0), y = Dpm), fill="#008EAA") +
theme_bw() +
theme(axis.title = element_text(size = 20),
axis.text = element_text(size = 16),
axis.title.x = element_blank()) +
labs(y = "DPM per day")
ggplot(data = poddata_day) +
geom_boxplot(aes(x = factor(0), y = Click_frequency), fill="#008EAA") +
theme_bw() +
theme(axis.title = element_text(size = 20),
axis.text = element_text(size = 16),
axis.title.x = element_blank()) +
labs(y = "Click frequency per day")
We can do the same for Dp10m and Dph.
ggplot(data = poddata_day) +
geom_boxplot(aes(x = factor(0), y = Dp10m), fill="#008EAA") +
theme_bw() +
theme(axis.title = element_text(size = 20),
axis.text = element_text(size = 16),
axis.title.x = element_blank()) +
labs(y = "DP10M per day")
ggplot(data = poddata_day) +
geom_boxplot(aes(x = factor(0), y = Dph), fill="#008EAA") +
theme_bw() +
theme(axis.title = element_text(size = 20),
axis.text = element_text(size = 16),
axis.title.x = element_blank()) +
scale_y_continuous(limits = c(0,24), breaks = c(0, 4, 8, 12, 16, 20, 24)) +
labs(y = "DPH per day")
Cleveland dotplots allow for a further inspection of outliers.
ggplot(data = poddata_day) +
geom_point(aes(x= Dpm, y = Time)) +
theme_bw() +
theme(axis.title = element_text(size = 20),
axis.title.y = element_blank(),
axis.text = element_text(size = 16),
legend.title = element_blank()) +
labs(x = "DPM per day")
ggplot(data = poddata_day) +
geom_point(aes(x= Dpm, y = Station)) +
theme_bw() +
theme(axis.title = element_text(size = 20),
axis.title.y = element_blank(),
axis.text = element_text(size = 16),
legend.title = element_blank()) +
labs(x = "DPM per day")
ggplot(data = poddata_day) +
geom_point(aes(x= Dpm, y = Zone)) +
theme_bw() +
theme(axis.title = element_text(size = 20),
axis.title.y = element_blank(),
axis.text = element_text(size = 16),
legend.title = element_blank()) +
labs(x = "DPM per day")
2.2.2 Step 2: Do we have homogeneity of variance?
To check for homogeinity of variance, we can make conditional boxplots.
ggplot(data = poddata_day) +
geom_boxplot(aes(x = as.factor(month(Time)), y = Dpm), fill="#008EAA") +
theme_bw() +
theme(axis.title = element_text(size = 20),
axis.text = element_text(size = 16),
axis.title.x = element_blank()) +
labs(y = "DPM per day")
ggplot(data = poddata_day) +
geom_boxplot(aes(x = Zone, y = Dpm), fill="#008EAA") +
theme_bw() +
theme(axis.text.x = element_text(angle = 45, hjust = 1),
axis.title = element_text(size = 20),
axis.text = element_text(size = 16),
axis.title.x = element_blank()) +
labs(y = "DPM per day")
Additionally, the data distribution can be explored per month or station with the facet_wrap() argument.
ggplot(data = poddata_day) +
geom_boxplot(aes(x = as.factor(month(Time)), y = Dpm), fill="#008EAA") +
theme_bw() +
theme(axis.title = element_text(size = 20),
axis.text = element_text(size = 14),
axis.title.x = element_blank(),
axis.text.x = element_text(angle = 45, hjust = 1)) +
labs(y = "DPM per day") +
facet_wrap(~Zone)
2.2.3 Step 3: Are the data normally distributed?
Although we can already suspect the data are not normally distributed, a histogram can shed light on the distribution of a variable.
ggplot(data = poddata_day) +
geom_histogram(aes(x = Dpm), fill="#008EAA") +
theme_bw() +
theme(axis.title = element_text(size = 20),
axis.title.y = element_blank(),
axis.text = element_text(size = 16),
legend.title = element_blank()) +
labs(x = "DPM per day")
ggplot(data = poddata_day) +
geom_histogram(aes(x = Dpm), fill="#008EAA",binwidth = 10) +
theme_bw() +
theme(axis.title = element_text(size = 20),
axis.title.y = element_blank(),
axis.text = element_text(size = 16),
legend.title = element_blank()) +
labs(x = "DPM per day")
2.2.4 Step 4: Are there lots of zeros in the data?
Next, Zuur advises to make a frequency plot to check for the amount of zeros in the data. The geom_rug argument facilitates the
ggplot(data = poddata_day) +
geom_histogram(aes(x = Dpm), fill="#008EAA", binwidth = 1, position = "dodge", size = 0.5) +
geom_rug(aes(x = Dpm))+
theme_bw() +
theme(axis.title = element_text(size = 20),
axis.title.y = element_blank(),
axis.text = element_text(size = 16),
legend.title = element_blank()) +
labs(x = "DPM per day")
Depending on the research question, there are many more options for exploration of the data! Step 5-7 of Zuur’s protocol might be useful when using metadata!
LS0tDQp0aXRsZTogJ0MtUE9EIGRhdGEgd29ya3Nob3A6IERhdGEgcHJlcGFyYXRpb24gYW5kIGV4cGxvcmF0aW9uJw0KYXV0aG9yOiAiVkxJWiAtIEZsYW5kZXJzIE1hcmluZSBJbnN0aXR1dGUiDQpkYXRlOiAiT2N0b2JlciA1LTYsIDIwMTciDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQpEYXRhIGV4cGxvcmF0aW9uIGlzIGEgdml0YWwgYXNwZWN0IG9mIHN0YXRpc3RpY2FsIGFuYWx5c2lzIGFuZCBwcm92aWRlcyBjcnVjaWFsIGluc2lnaHQgaW4gdGhlIGluZm9ybWF0aW9uIGFuZCBwYXR0ZXJucyBvZiB0aGUgZGF0YS5UaGlzIGRvY3VtZW50IGRlbW9uc3RyYXRlcyBzb21lIHVzZWZ1bCBjb2RlIGZvciBiYXNpYyBkYXRhIGV4cGxvcmF0aW9uIGFuZCBvcmdhbmlzYXRpb24uIA0KDQojIDAuIExvYWQgdGhlIGRhdGENCkRlZmluaW5nIGEgd29ya2luZyBkaXJlY3RvcnkgZmFjaWxpdGF0ZXMgdGhlIGFjY2VzcyB0byBmb2xkZXJzIGFuZCBkb2N1bWVudHMuIFRoaXMgY2FuIGJlIGRvbmUgYnkgY3JlYXRpbmcgYW4gUiBwcm9qZWN0IG9yIGJ5IGNvZGUgc2V0d2QoKS4NCmBgYHtyLCBpbmNsdWRlPVQsIHJlc3VsdHM9J2hpZGUnfQ0KZ2V0d2QoKSAjIENoZWNrIHlvdXIgY3VycmVudCB3b3JraW5nIGRpcmVjdG9yeS4NCmBgYA0KYGBge3IsIGluY2x1ZGU9VCwgcmVzdWx0cz0naGlkZSd9DQpsaXN0LmZpbGVzKCkgIyBTZWUgdGhlIGZpbGVzIGluIHlvdXIgd29ya2luZyBkaXJlY3RvcnkNCmBgYA0KDQpJbiB0aGUgZm9sZGVyICoqRGF0YSoqLCB5b3UgY2FuIGZpbmQgc2V2ZXJhbCBkYXRhIHRhYmxlcywgZG93bmxvYWRlZCBmcm9tIHRoZSBSU2hpbnkgYXBwbGljYXRpb24uIFRoZSBuYW1lcyBpbmRpY2F0ZSB0aGUgcXVhbGl0eSBvZiB0aGUgZGV0ZWN0ZWQgcG9ycG9pc2UgY2xpY2tzLiANCg0KYGBge3J9DQpsaXN0LmZpbGVzKCJEYXRhIGRheSAxIikNCmBgYA0KDQpUaGUgZmlsZSAqKmhpX21vZC50YWIqKiBjb250YWlucyB0aGUgZGV0ZWN0aW9ucyBvZiBxdWFsaXR5IGhpIGFuZCBtb2QgcG9vbGVkIHRvZ2V0aGVyIGZvciBlYWNoIGhvdXIuIFdlIHdpbGwgdXNlIHRoaXMgZmlsZSBmb3IgdGhpcyBzZXNzaW9uLg0KDQpJbXBvcnRpbmcgdGhlIGRhdGEgaXMgcG9zc2libGUgYnkgY29kZSBvciBieSB0aGUgJ0ltcG9ydCBEYXRhc2V0JyBidXR0b24gaW4gdGhlIEVudmlyb25tZW50IHdpbmRvdyBvbiB0aGUgcmlnaHQuDQoNCmBgYHtyLCBpbmNsdWRlPVR9DQpwb2RkYXRhIDwtIHJlYWQudGFibGUoIkRhdGEgZGF5IDEvaGlfbW9kXzFoci50YWIiLCAiXHQiLCBoZWFkZXIgPSBUKQ0KYGBgDQoNCiMgMS4gRGF0YSBwcmVwYXJhdGlvbg0KYGBge3J9DQpzdHIocG9kZGF0YSkgIyBJbnZlc3RpZ2F0ZSB0aGUgc3RydWN0dXJlIG9mIHRoZSBvYmplY3QgcG9kZGF0YS4NCmBgYA0KU29tZSBleHBsYW5hdGlvbiBvbiB0aGUgZGlmZmVyZW50IHZhcmlhYmxlczoNCg0KICAtICpEZXBsb3ltZW50X2ZrKiAgICAgICAgICAgPSBBbiBpZGVudGlmeWluZyBudW1iZXIgYXNzaWduZWQgdG8gZWFjaCBkZXBsb3ltZW50DQogIC0gKlRpbWUqICAgICAgICAgICAgICAgICAgICA9IERhdGUgYW5kIHRpbWUNCiAgLSAqU3BlY2llcyogICAgICAgICAgICAgICAgID0gTkJIRiAoTmFycm93IEJhbmQgSGlnaCBGcmVxdWVuY3kpDQogIC0gKk1pbGxpc2Vjb25kcyogICAgICAgICAgICA9IFRoZSBzdW0gb2YgbWlsbGlzZWNvbmRzIGluIHdoaWNoIGEgcG9ycG9pc2Ugd2FzIGRldGVjdGVkDQogIC0gKk51bWJlcl9jbGlja3NfZmlsdGVyZWQqICA9IFRoZSBhbW91bnQgb2YgY2xpY2tzLCBpZGVudGlmaWVkIGFzIHBvcnBvaXNlIGNsaWNrcw0KICAtICpOdW1iZXJfY2xpY2tzX3RvdGFsKiAgICAgPSBUaGUgdG90YWwgYW1vdW50IG9mIGNsaWNrcywgZnJvbSBkaWZmZXJlbnQgc291cmNlcw0KICAtICpMb3N0X21pbnV0ZXMqICAgICAgICAgICAgPSBUaGUgbnVtYmVyIG9mIG1pbnV0ZXMgZm9yIHdoaWNoIHRoZSBDLVBPRCByZWFjaGVkIGEgZGV0ZWN0aW9uIHRocmVzaG9sZCBhbmQgcmVjb3JkZWQgdGhlIG1pbnV0ZSBvbmx5IHBhcnRpYWxseS4NCiAgLSAqUmVjb3JkZWQqICAgICAgICAgICAgICAgID0gVGhlIG51bWJlciBvZiBtaW51dGVzIHRoYXQgdGhlIEMtUE9EIHdhcyBvbi4NCiAgLSAqRHBtKiAgICAgICAgICAgICAgICAgICAgID0gVGhlIHN1bSBvZiBEZXRlY3Rpb24gUG9zaXRpdmUgTWludXRlcy4NCiAgLSAqRHAxMG0qICAgICAgICAgICAgICAgICAgID0gVGhlIHN1bSBvZiBEZXRlY3Rpb24gUG9zaXRpdmUgMTAgTWludXRlcy4NCiAgLSAqU3RhdGlvbiogICAgICAgICAgICAgICAgID0gVGhlIG5hbWUgb2YgdGhlIHN0YXRpb24uDQogIC0gKkxhdGl0dWRlKg0KICAtICpMb25naXR1ZGUqDQogIC0gKk1vb3JpbmdfdHlwZSogICAgICAgICAgICA9IEluZGljYXRlcyB3aGV0aGVyIHRoZSBDLVBPRCB3YXMgZGVwbG95ZWQgb24gYSBzdXJmYWNlLWJ1b3kgb3IgYSBib3R0b20gbW9vcmluZy4NCiAgLSAqUmVjZWl2ZXIqICAgICAgICAgICAgICAgID0gVGhlIG5hbWUgb2YgdGhlIHJlY2VpdmVyLg0KDQpBIGZpcnN0IGV4cGxvcmF0aW9uIHdpdGggdGhlICoqc3RyKCkqKiBmdW5jdGlvbiBhbHJlYWR5IGluZGljYXRlcyBzb21lIGlzc3VlcyBhbmQgcG9zc2liaWxpdGVzIGZvciBpbXByb3ZlbWVudDoNCg0KICAtICpSZWNlaXZlciosICpTdGF0aW9uKiwgKk1vb3JpbmdfdHlwZSogYW5kICpTcGVjaWVzKiBhcmUgY29uc2lkZXJlZCBjaGFyYWN0ZXIgdmFyaWFibGVzLg0KICANCiAgLSAqVGltZSogaXMgY29uc2lkZXJlZCBhIGZhY3Rvciwgd2hpbGUgaXMgYSB0aW1lIHZhcmlhYmxlLg0KDQojIyAxLjEgT3JnYW5pemluZyB0aGUgZGF0YSBhbmQgYWRkaW5nIHJlbGV2YW50IHZhcmlhYmxlcw0KQWRkaW5nIHRoZSB2YXJpYWJsZSBxdWFsaXR5IG1pZ2h0IGJlIHVzZWZ1bCBmb3IgZnV0dXJlIHJlZmVyZW5jZS4NCmBgYHtyLCBpbmNsdWRlPVR9DQpwb2RkYXRhJFF1YWxpdHkgPC0gImhpK21vZCINCmBgYA0KDQpEZXRlY3Rpb24gcG9zaXRpdmUgaG91ciwgKkRwaCosIHdpbGwgaW5kaWNhdGUgd2hldGhlciB0aGVyZSB3YXMgYSBkZXRlY3Rpb24gd2l0aGluIHRoZSBob3VyICgxKSBvciBub3QgKDApLg0KYGBge3IsIGluY2x1ZGU9VH0NCnBvZGRhdGEkRHBoIDwtIGlmZWxzZShwb2RkYXRhJERwbSA+MCwgMSwgMCkNCmBgYA0KDQpUaGUgZXhhY3QgbG9jYXRpb25zIGZvciBzb21lIEMtUE9EIGRlcGxveW1lbnRzIGNoYW5nZWQgc2xpZ2h0bHkgb3ZlciB0aGUgeWVhcnMuIEFkZGluZyBhIHZhcmlhYmxlICpab25lKiB3aWxsIGJlIHVzZWZ1bCB0byBsaW5rIHRoZSBkYXRhIG9mIGFkamFjZW50IHN0YXRpb25zLg0KDQpgYGB7ciwgZXZhbD1GLGluY2x1ZGU9VH0NCnBvZGRhdGEkWm9uZTwtIGlmZWxzZShwb2RkYXRhJFN0YXRpb249PSJicG5zLU9vc3RlbmRlYmFuayBPb3N0IiwgIk9vc3RlbmRlIiwNCiAgICAgICAgICAgICAgaWZlbHNlKHBvZGRhdGEkU3RhdGlvbj09ImJwbnMtUmVlZmJhbGxzLWNwb3dlciIsICJibnBzLVJlZWZiYWxscy1jcG93ZXIiLA0KICAgICAgICAgICAgICBpZmVsc2UocG9kZGF0YSRTdGF0aW9uPT0gImJwbnMtV2VuZHVpbmViYW5rdyIsICJPb3N0ZW5kZSIsDQogICAgICAgICAgICAgIGlmZWxzZShwb2RkYXRhJFN0YXRpb249PSJicG5zLVdLMTYiLCAiT29zdGVuZGUiLA0KICAgICAgICAgICAgICBpZmVsc2UocG9kZGF0YSRTdGF0aW9uPT0iYnBucy1CZWx3aW5kIEMwNSIsICJicG5zLUJlbHdpbmQgQzA1IiwNCiAgICAgICAgICAgICAgaWZlbHNlKHBvZGRhdGEkU3RhdGlvbj09ICJicG5zLUQxIiwgIk1pZGRlbGtlcmtlIiwNCiAgICAgICAgICAgICAgaWZlbHNlKHBvZGRhdGEkU3RhdGlvbj09ImJwbnMtV0s5IiwgIldLOWVuMTIiLA0KICAgICAgICAgICAgICBpZmVsc2UocG9kZGF0YSRTdGF0aW9uPT0iYnBucy1Hb290ZWJhbmsiLCAiR29vdGViYW5rIiwNCiAgICAgICAgICAgICAgaWZlbHNlKHBvZGRhdGEkU3RhdGlvbj09ImJwbnMtVkcyIiAsICJHb290ZWJhbmsiLA0KICAgICAgICAgICAgICBpZmVsc2UocG9kZGF0YSRTdGF0aW9uPT0gImJwbnMtV0sxMiIsICJXSzllbjEyIiwNCiAgICAgICAgICAgICAgaWZlbHNlKHBvZGRhdGEkU3RhdGlvbj09ICJicG5zLVJlZWZiYWxscyBCZWx3aW5kIiwgImJwbnMtUmVlZmJhbGxzIEJlbHdpbmQiLA0KICAgICAgICAgICAgICBpZmVsc2UocG9kZGF0YSRTdGF0aW9uPT0gICJicG5zLU9vc3RkeWNrIFdlc3QiLCAgImJwbnMtT29zdGR5Y2sgV2VzdCIsIA0KICAgICAgICAgICAgICBpZmVsc2UocG9kZGF0YSRTdGF0aW9uPT0gImJwbnMtTFNUNDIwIiwgIk1pZGRlbGtlcmtlIiwNCiAgICAgICAgICAgICAgaWZlbHNlKHBvZGRhdGEkU3RhdGlvbj09ICJicG5zLU1pZGRlbGtlcmtlIFNvdXRoIiwgIk1pZGRlbGtlcmtlIiwNCiAgICAgICAgICAgICAgaWZlbHNlKHBvZGRhdGEkU3RhdGlvbj09ICJicG5zLUxvdHRvYnVveSIsICJicG5zLUxvdHRvYnVveSIsDQogICAgICAgICAgICAgIGlmZWxzZShwb2RkYXRhJFN0YXRpb249PSAiYnBucy1CaXJrZW5mZWxzIiwgImJwbnMtQmlya2VuZmVscyIsIE5BKSkpKSkpKSkpKSkpKSkpKQ0KYGBgDQoNCkNsaWNrIGZyZXF1ZW5jeSAoYWxzbyBjYWxsZWQgUFBNLCBQb3Jwb2lzZSBQb3NpdGl2ZSBNaW51dGVzKSBhbmQgQ2xpY2sgaW50ZW5zaXR5IGFyZSBjb21tb24gbWV0cmljcyBpbiBhY291c3RpYyBwb3Jwb2lzZSByZXNlYXJjaC4NCg0KYGBge3IsIGluY2x1ZGUgPVR9DQpwb2RkYXRhJENsaWNrX2ZyZXF1ZW5jeSA8LSBwb2RkYXRhJERwbS9wb2RkYXRhJFJlY29yZGVkDQpwb2RkYXRhJENsaWNrX2ludGVuc2l0eSA8LSBwb2RkYXRhJE51bWJlcl9jbGlja3NfZmlsdGVyZWQvcG9kZGF0YSRDbGlja19mcmVxdWVuY3kNCmBgYA0KDQpVbmRlcnN0YW5kaW5nIHRoZSBjb250ZW50IG9mIGEgdmFyaWFibGUsIHdlIGNhbiBhc3NpZ24gYW4gYXBwcm9wcmlhdGUgZGF0YSB0eXBlLg0KDQpgYGB7ciwgaW5jbHVkZT1UfQ0KcG9kZGF0YSRSZWNlaXZlciA8LSBhcy5mYWN0b3IocG9kZGF0YSRSZWNlaXZlcikNCnBvZGRhdGEkU3RhdGlvbiA8LSBhcy5mYWN0b3IocG9kZGF0YSRTdGF0aW9uKQ0KcG9kZGF0YSRNb29yaW5nX3R5cGUgPC0gYXMuZmFjdG9yKHBvZGRhdGEkTW9vcmluZ190eXBlKQ0KcG9kZGF0YSRRdWFsaXR5IDwtIGFzLmZhY3Rvcihwb2RkYXRhJFF1YWxpdHkpDQpwb2RkYXRhJFNwZWNpZXMgPC0gYXMuZmFjdG9yKHBvZGRhdGEkU3BlY2llcykNCnBvZGRhdGEkWm9uZSA8LSBhcy5mYWN0b3IocG9kZGF0YSRab25lKQ0KYGBgDQoNClRoZSBbbHVicmlkYXRlXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvbHVicmlkYXRlL2x1YnJpZGF0ZS5wZGYpIHBhY2thZ2UgcHJvdmlkZXMgc29tZSB1c2VmdWwgdG9vbHMgdG8gaGFuZGxlIGRhdGVzIGFuZCB0aW1lcy4NCmBgYHtyfQ0KbGlicmFyeShsdWJyaWRhdGUpDQpgYGANCg0KVG8gaW5zdGFsbCBhIHBhY2thZ2UgdXNlIHRoZSAqKmluc3RhbGwucGFja2FnZXMoKSoqIGZ1bmN0aW9uLg0KDQpTb21lIGV4cGxhbmF0aW9uIG9uIHRoZSBwYWNrYWdlOg0KYGBge3J9DQp0b2RheSgpDQpgYGANCmBgYHtyfQ0Kbm93KCkNCmBgYA0KYGBge3IsIGluY2x1ZGU9VH0NCm1vb25sYW5kaW5nIDwtICIyNC0wNy0xOTY5IDE2OjUwOjM1Ig0KYGBgDQpgYGB7ciwgaW5jbHVkZT1UfQ0KbW9vbmxhbmRpbmcgPC0gcGFyc2VfZGF0ZV90aW1lKG1vb25sYW5kaW5nLCBvcmRlcnMgPSAiZG15IEhNUyIpDQpgYGANClRoZSAqKnBhcnNlX2RhdGVfdGltZSgpKiogZnVuY3Rpb24gdHJhbnNmb3JtcyB0aGUgY2hhcmFjdGVyIHZhcmlhYmxlIHRvIHRoZSBQT1NJWGN0IGZvcm1hdCwgZW5hYmxpbmcgeW91IHRvIGV4dHJhY3QgZmVhdHVyZXMgb2YgdGltZSBmcm9tIHRoZSB2YXJpYWJsZSAoZWcuICoqeWVhcigpKiosICoqbW9udGgoKSoqLCAqKmRheSgpKiosICoqaG91cigpKiosICoqbWludXRlKCkqKikuIEJlIGNhcmVmdWwgdG8gc3BlY2lmeSB0aGUgKm9yZGVycyogYXJndW1lbnQgY29ycmVjdGx5ISBGb3IgZXhhbXBsZTogaW4gdGhlc2UgZGF0YSwgZGF0ZXRpbWUgd2FzIGluIGEgZGlmZmVyZW50IGZvcm1hdCB0aGFuIHRoZSBpbnN0YWxsYXRpb24gYW5kIGFjdGl2YXRpb24gZGF0ZXMuDQpgYGB7cn0NCmRheShtb29ubGFuZGluZykNCmRhdGUobW9vbmxhbmRpbmcpDQpgYGANCg0KV2UgY2FuIG5vdyB0cmFuc2Zvcm0gb3VyIG93biB2YXJpYWJsZSAqVGltZSouDQpgYGB7ciwgaW5jbHVkZT1UfQ0KcG9kZGF0YSRUaW1lIDwtIHBhcnNlX2RhdGVfdGltZShwb2RkYXRhJFRpbWUsIG9yZGVycyA9ICJ5bWQgSE1TIikNCmBgYA0KDQpUaGUgc3VtbWFyeSBmdW5jdGlvbiBnaXZlcyBhIHF1aWNrIHBlZWsgYXQgb3VyIGRhdGEuDQpgYGB7cn0NCnN1bW1hcnkocG9kZGF0YSkNCmBgYA0KDQojIyAxLjIgRGF0YSBzdWJzZXR0aW5nDQpTdWJzZXQgdGhlIGRhdGEgd2l0aCBnZW5lcmljIFIgY29kZTogc29tZSBleGFtcGxlcy4NCmBgYHtyIGluY2x1ZGU9VH0NCnBvZGRhdGFbMSxdDQpgYGANCmBgYHtyLCBpbmNsdWRlPVR9DQpwb2RkYXRhWzE6NSxdDQpgYGANCmBgYHtyLCBpbmNsdWRlPVR9DQpwb2RkYXRhWywxXQ0KYGBgDQoNCmBgYHtyLCBpbmNsdWRlPVR9DQpwb2RkYXRhWyxjKDIsNCldDQpgYGANCg0KYGBge3IsIGluY2x1ZGU9VH0NCnVuaXF1ZShwb2RkYXRhJFN0YXRpb24pIA0KcG9kZGF0YVtwb2RkYXRhJFN0YXRpb24gPT0gImJwbnMtTG90dG9idW95IixdDQpgYGANCg0KVGhlIFIgcGFja2FnZSBbZHBseXJdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9kcGx5ci9kcGx5ci5wZGYpIHByb3ZpZGVzIHVzZWZ1bCBmdW5jdGlvbnMgZm9yIGRhdGEgb3JnYW5pemF0aW9uLg0KYGBge3IsIGluY2x1ZGU9VH0NCmxpYnJhcnkoZHBseXIpDQpgYGANCg0KVGhlICoqc2VsZWN0KCkqKiBmdW5jdGlvbiBhbGxvd3MgZm9yIGEgc3RyYWlnaHRmb3J3YXJkIHNlbGVjdGlvbiBvZiBjb2x1bW5zIChbdXNlZnVsIHNlbGVjdCBzeW50YXhpc10oaHR0cHM6Ly93d3cucmRvY3VtZW50YXRpb24ub3JnL3BhY2thZ2VzL2RwbHlyL3ZlcnNpb25zLzAuNS4wL3RvcGljcy9zZWxlY3QpKS4gDQpgYGB7cn0NCnNlbGVjdChwb2RkYXRhLCBSZWNlaXZlcikNCnNlbGVjdChwb2RkYXRhLCAtUmVjZWl2ZXIpDQpzZWxlY3QocG9kZGF0YSwgU3RhdGlvbiwgTGF0aXR1ZGUsIExvbmdpdHVkZSkNCmBgYA0KDQpUaGUgZXF1aXZhbGVudCBmdW5jdGlvbiBmb3Igcm93cyBpcyAqKmZpbHRlcigpKiogKFt1c2VmdWwgZmlsdGVyIHN5bnRheGlzXShodHRwczovL3d3dy5yZG9jdW1lbnRhdGlvbi5vcmcvcGFja2FnZXMvZHBseXIvdmVyc2lvbnMvMC43LjIvdG9waWNzL2ZpbHRlcikpLiANCmBgYHtyfQ0KZmlsdGVyKHBvZGRhdGEsIFN0YXRpb24gPT0gImJwbnMtTG90dG9idW95IikNCmZpbHRlcihwb2RkYXRhLCBTdGF0aW9uID09ICJicG5zLUxvdHRvYnVveSIgfCBTdGF0aW9uID09ICJicG5zLVdLMTIiKQ0KZmlsdGVyKHBvZGRhdGEsIFN0YXRpb24gIT0gImJwbnMtTG90dG9idW95IikNCmZpbHRlcihwb2RkYXRhLCBEcG0gPiAwKQ0KZmlsdGVyKHBvZGRhdGEsIERwbSA+IDAgJiBTdGF0aW9uID09ICJicG5zLUxvdHRvYnVveSIpDQpgYGANCg0KU2lkZSBub3RlOiBzb21lIGZ1bmN0aW9uIG5hbWVzIG9mIGRwbHlyIGFyZSBpZGVudGljYWwgdG8gZnVuY3Rpb24gbmFtZXMgb2Ygb3RoZXIgcGFja2FnZXMuIFRoaXMgY2FuIGNhdXNlIGFuIGVycm9yIHdoZW4gdXNpbmcgdGhlIGZ1bmN0aW9uLiBJbiB0aGlzIGNhc2UsIHdyaXRlIHRoZSBwYWNrYWdlIG5hbWUgYW5kIDo6IGJlZm9yZSB0aGUgZnVuY3Rpb24uDQpgYGB7cn0NCmRwbHlyOjpzZWxlY3QocG9kZGF0YSwgUmVjZWl2ZXIpDQpgYGANCg0KU2lkZSBub3RlOiB0aGlzIGNhbiBiZSBjb21iaW5lZCB3aXRoIHRoZSBsdWJyaWRhdGUgZnVuY3Rpb25zLg0KYGBge3J9DQpmaWx0ZXIocG9kZGF0YSwgeWVhcihUaW1lKSA9PSAyMDE3KQ0KYGBgDQoNCkEgdmFsdWUgb2YgemVybyBmb3IgdGhlIHZhcmlhYmxlIFJlY29yZGVkIGluZGljYXRlcyB0aGUgQy1QT0Qgd2FzIG5vdCAnb24nIGR1cmluZyB0aGUgZW50aXJlIGhvdXIuIEhlbmNlLCB3ZSBjYW4gZmlsdGVyIG91dCB0aGVzZSByb3dzLg0KYGBge3IsIGluY2x1ZGU9VH0NCnBvZGRhdGEgPC0gZmlsdGVyKHBvZGRhdGEsIFJlY29yZGVkID4gMCkNCmBgYA0KDQpBIHZhbHVlIG9mIDYwIGZvciB0aGUgdmFyaWFibGUgUmVjb3JkZWQgaW5kaWNhdGVzIHRoZSBDLVBPRCB3YXMgbm90ICdvbicgZm9yIHNvbWUgbWludXRlcyBkdXJpbmcgdGhlIGhvdXIuIFdlIGNhbiBjaG9vc2Ugd2hldGhlciB0byBmaWx0ZXIgb3V0IHRoZXNlIHJvd3MuDQpgYGB7cn0NCnBvZGRhdGEgPC0gZmlsdGVyKHBvZGRhdGEsIFJlY29yZGVkID09IDYwKQ0KYGBgDQoNCiMjIDEuMyBTdW1tYXJpemluZyBkYXRhDQpDb21iaW5pbmcgdGhlIGZ1bmN0aW9ucyBncm91cF9ieSBhbmQgc3VtbWFyaXNlIGFsbG93cyBmb3Igc2ltcGxlIG9yZ2FuaXphdGlvbjogYW4gZXhhbXBsZS4NCg0KRmlyc3QsIHdlIGdyb3VwIG91ciBkYXRhZnJhbWUgYnkgKlpvbmUqLg0KYGBge3IsIGluY2x1ZGU9VH0NCnBvZGRhdGFfZ3JvdXAgPC0gZ3JvdXBfYnkocG9kZGF0YSwgWm9uZSkNCmBgYA0KYGBge3J9DQpncm91cHMocG9kZGF0YV9ncm91cCkgIyBDaGVjayB0aGUgZ3JvdXBpbmcgdmFyaWFibGUNCmBgYA0KDQpOZXh0LCB3ZSBjYW4gY2FsY3VsYXRlIHNvbWUgc3VtbWFyeSBzdGF0aXN0aWNzIGZvciBlYWNoICpab25lKiBzZXBlcmF0ZWx5Lg0KYGBge3IsIGluY2x1ZGU9VH0NCnBvZGRhdGFfc3VtIDwtIHN1bW1hcmlzZShwb2RkYXRhX2dyb3VwLA0KICAgICAgICAgICAgICAgICAgICAgICAgIERwbV9tZWRpYW4gPSBtZWRpYW4oRHBtKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICBEcG1fbWVhbiA9IG1lYW4oRHBtKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICBEcG1fbWF4ID0gbWF4KERwbSkpDQpgYGANCmBgYHtyfQ0KcG9kZGF0YV9zdW0NCmBgYA0KDQpgYGB7cn0NCnJtKHBvZGRhdGFfZ3JvdXAsIHBvZGRhdGFfc3VtKSAjIFJlbW92ZSB0aGUgZXhhbXBsZSBkYXRhIGZyYW1lcw0KYGBgDQoNCldlIHdpbGwgbm93IGFwcGx5IHRoZXNlIGZ1bmN0aW9ucyB0byBnZXQgYSBuZXcgZGF0YSBmcmFtZSB0aGF0IHN1bW1hcml6ZXMgdGhlIGRldGVjdGlvbnMgcGVyIGRheS4NCmBgYHtyLCBpbmNsdWRlPVR9DQpwb2RkYXRhX2RheSA8LSBwb2RkYXRhICMgQ29weSB0aGUgZGF0YSBpbiBhIG5ldyBkYXRhIGZyYW1lLg0KYGBgDQoNClRocmVlIHdheXMgdG8gdGFrZSB0aGUgZGF0ZSBvdXQgb2Ygb3VyIHRpbWUgdmFyaWFibGUuIFVzaW5nIHRoZSBsdWJyaWRhdGU6OmRhdGUoKSBmdW5jdGlvbiBpcyB2ZXJ5IGVsZWdhbnQsIEhPV0VWRVI6IGx1YnJpZGF0ZSBoYXMgc29tZSBidWdzIHdoZW4gY29tYmluZWQgd2l0aCB0aGUgcGFja2FnZXMgZHBseXIvcGx5ci4NCmBgYHtyLCBpbmNsdWRlPVR9DQpwb2RkYXRhX2RheSRUaW1lIDwtIGRhdGUocG9kZGF0YV9kYXkkVGltZSkNCnBvZGRhdGFfZGF5JFRpbWUgPC0gcGFyc2VfZGF0ZV90aW1lKHBhc3RlKHllYXIocG9kZGF0YSRUaW1lKSwgbW9udGgocG9kZGF0YSRUaW1lKSwgZGF5KHBvZGRhdGEkVGltZSksIHNlcCA9ICItIiksIG9yZGVycyA9ICJ5bWQiKQ0KcG9kZGF0YV9kYXkkVGltZSA8LSBhcy5QT1NJWGN0KHBhc3RlKHllYXIocG9kZGF0YSRUaW1lKSwgbW9udGgocG9kZGF0YSRUaW1lKSwgZGF5KHBvZGRhdGEkVGltZSksIHNlcCA9ICItIiksZm9ybWF0PSIlWS0lbS0lZCIsIHR6PSJVVEMiKQ0KYGBgDQoNCk5vdyB3ZSBjYW4gZ3JvdXAgYnkgVGltZS4NCmBgYHtyLCBpbmNsdWRlPVR9DQpwb2RkYXRhX2dyb3VwIDwtIGRwbHlyOjpncm91cF9ieShwb2RkYXRhX2RheSwgRGVwbG95bWVudF9maywgUmVjZWl2ZXIsIFN0YXRpb24sIFpvbmUsIExhdGl0dWRlLCBMb25naXR1ZGUsIE1vb3JpbmdfdHlwZSwgUXVhbGl0eSwgVGltZSkNCnBvZGRhdGFfZGF5IDwtIGRwbHlyOjpzdW1tYXJpc2UocG9kZGF0YV9ncm91cCwNCiAgICAgICAgICAgICAgICAgICAgICAgICBNaWxsaXNlY29uZHMgPSBzdW0oTWlsbGlzZWNvbmRzKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICBOdW1iZXJfY2xpY2tzX2ZpbHRlcmVkID0gc3VtKE51bWJlcl9jbGlja3NfZmlsdGVyZWQpLA0KICAgICAgICAgICAgICAgICAgICAgICAgIE51bWJlcl9jbGlja3NfdG90YWwgPSBzdW0oTnVtYmVyX2NsaWNrc190b3RhbCksDQogICAgICAgICAgICAgICAgICAgICAgICAgTG9zdF9taW51dGVzID0gc3VtKExvc3RfbWludXRlcyksDQogICAgICAgICAgICAgICAgICAgICAgICAgRHBtID0gc3VtKERwbSksDQogICAgICAgICAgICAgICAgICAgICAgICAgRHAxMG0gPSBzdW0oRHAxMG0pLA0KICAgICAgICAgICAgICAgICAgICAgICAgIERwaCA9IHN1bShEcGgpLA0KICAgICAgICAgICAgICAgICAgICAgICAgIFJlY29yZGVkID0gc3VtKFJlY29yZGVkKSkNCnBvZGRhdGFfZGF5JENsaWNrX2ZyZXF1ZW5jeSA8LSBwb2RkYXRhX2RheSREcG0vcG9kZGF0YV9kYXkkUmVjb3JkZWQNCnBvZGRhdGFfZGF5JENsaWNrX2ludGVuc2l0eSA8LSBwb2RkYXRhX2RheSROdW1iZXJfY2xpY2tzX2ZpbHRlcmVkL3BvZGRhdGFfZGF5JENsaWNrX2ZyZXF1ZW5jeQ0Kcm0ocG9kZGF0YV9ncm91cCkNCmBgYA0KDQpBZ2Fpbiwgd2UgY2FuIGNob29zZSB0byBvbmx5IHVzZSBmdWxsIGRheXMuDQpgYGB7ciwgaW5jbHVkZT1UfQ0KcG9kZGF0YV9kYXkgPC0gZmlsdGVyKHBvZGRhdGFfZGF5LCBSZWNvcmRlZCA9PSAyNCo2MCkNCmBgYA0KDQojIDIuIERhdGEgZXhwbG9yYXRpb24NClRoZSBSIHBhY2thZ2UgW2dncGxvdDJdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9nZ3Bsb3QyL2dncGxvdDIucGRmKSBlbmFibGVzIHRoZSBjb25zdHJ1Y3Rpb24gb2YgY29tcGxleCwgaWxsdXN0cmlvdXMgZ3JhcGhzIHdpdGggc2ltcGxlIGNvZGUgKFt1c2VmdWwgZ2dwbG90IHN5bnRheF0oaHR0cDovL2dncGxvdDIudGlkeXZlcnNlLm9yZy9yZWZlcmVuY2UvKSkuIFdlIHdpbGwgZmlyc3QgdXNlIHRoaXMgdG8gbWFrZSBzaW1wbGUgcGxvdHMgZm9yIGV4cGxvcmF0aW9uIGFuZCBsYXRlciBhcHBseSBtb3JlIGFkdmFuY2VkIHBsb3R0aW5nIHRlY2huaXF1ZXMuDQpgYGB7cn0NCmxpYnJhcnkoZ2dwbG90MikNCmBgYA0KDQojIyAyLjEgQSBmaXJzdCBsb29rIGF0IHRoZSBkYXRhIGF2YWlsYWJpbGl0eSANCk1ha2luZyBhIGdyYXBoIGluIGdncGxvdDogYW4gZXhhbXBsZSB0byB0ZXN0IHRoZSBkYXRhIGF2YWlsYWJpbGl0eS4NCmBgYHtyfQ0KZ2dwbG90KGRhdGEgPSBwb2RkYXRhX2RheSwgYWVzKHg9IFRpbWUsIHkgPSBRdWFsaXR5KSkgIyBUaGlzIG1ha2VzIGFuIGVtcHR5IHBsb3QNCmBgYA0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IHBvZGRhdGFfZGF5LCBhZXMoeD0gVGltZSwgeSA9IFF1YWxpdHkpKSAjIFRoaXMgbWFrZXMgYW4gZW1wdHkgcGxvdA0KYGBgDQoNClRocmVlIHdheXMgdG8gY29kZSB0aGUgc2FtZSBwbG90Lg0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IHBvZGRhdGFfZGF5LCBhZXMoeD0gVGltZSwgeSA9IFF1YWxpdHkpKSArIGdlb21fcG9pbnQoKQ0KZ2dwbG90KCkgKyBnZW9tX3BvaW50KGRhdGEgPSBwb2RkYXRhX2RheSwgYWVzKHg9IFRpbWUsIHkgPSBRdWFsaXR5KSkNCmdncGxvdChkYXRhID0gcG9kZGF0YV9kYXkpICsgZ2VvbV9wb2ludChhZXMoeD0gVGltZSwgeSA9IFF1YWxpdHkpKQ0KYGBgDQpgYGB7cn0NCmdncGxvdChkYXRhID0gcG9kZGF0YV9kYXksIGFlcyh4PSBUaW1lLCB5ID0gUXVhbGl0eSkpICsgZ2VvbV9wb2ludCgpDQpgYGANCg0KTm93IHdlIGNhbiBpbnZlc3RpZ2F0ZSB0aGUgZGF0YSBhdmFpbGFiaWxpdHkgcGVyIHN0YXRpb24uDQpgYGB7cn0NCmdncGxvdChkYXRhID0gcG9kZGF0YV9kYXkpICsgZ2VvbV9wb2ludChhZXMoeD0gVGltZSwgeSA9IFN0YXRpb24pKQ0KYGBgDQpgYGB7cn0NCmdncGxvdChkYXRhID0gcG9kZGF0YV9kYXkpICsgZ2VvbV9wb2ludChhZXMoeD0gVGltZSwgeSA9IFN0YXRpb24pKQ0KYGBgDQoNClNhbWUgZm9yIHpvbmVzLiBCeSBkZWZpbmluZyB0aGUgdGhlbWUgYXJndW1lbnQsIHdlIGNhbiBjaGFuZ2UgdGhlIGdyYXBoaWNzIG9mIG91ciBwbG90Lg0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IHBvZGRhdGFfZGF5KSArIGdlb21fcG9pbnQoYWVzKHg9IFRpbWUsIHkgPSBab25lKSkgKyANCiAgdGhlbWVfYncoKSArIA0KICB0aGVtZShheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2KSwNCiAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkNCmBgYA0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IHBvZGRhdGFfZGF5KSArIGdlb21fcG9pbnQoYWVzKHg9IFRpbWUsIHkgPSBab25lKSkgKyANCiAgdGhlbWVfYncoKSArIA0KICB0aGVtZShheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2KSwNCiAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkNCmBgYA0KDQojIyAyLjIgSW4gbGluZSB3aXRoIFp1dXIncyBwcm90b2NvbCBmb3IgZGF0YSBleHBsb3JhdGlvbg0KSW4gdGhlIG5leHQgc3RlcHMsIHdlIHdpbGwgdmlzdWFsbHkgZXhwbG9yZSB0aGUgZGF0YSBpbiBsaW5lIHdpdGggdGhlIGZpcnN0IGZvdXIgc3RlcHMgb2YgWnV1cidzIHByb3RvY29sLg0KDQojIyAyLjIuMSBTdGVwIDE6IEFyZSB0aGVyZSBvdXRsaWVycyBpbiBZIGFuZCBYPw0KQ29uc3RydWN0IGEgYmFzaWMgYm94cGxvdCB0byB2aXN1YWxpemUgdGhlIHNwcmVhZCBvZiB0aGUgZGF0YSBhbmQgY2hlY2sgZm9yIG91dGxpZXJzLg0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IHBvZGRhdGFfZGF5KSArIA0KICBnZW9tX2JveHBsb3QoYWVzKHggPSBmYWN0b3IoMCksIHkgPSBEcG0pLCBmaWxsPSIjMDA4RUFBIikgKyANCiAgdGhlbWVfYncoKSArDQogIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwKSwNCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiksDQogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSkgKw0KICBsYWJzKHkgPSAiRFBNIHBlciBkYXkiKQ0KYGBgDQpgYGB7cn0NCmdncGxvdChkYXRhID0gcG9kZGF0YV9kYXkpICsgDQogIGdlb21fYm94cGxvdChhZXMoeCA9IGZhY3RvcigwKSwgeSA9IERwbSksIGZpbGw9IiMwMDhFQUEiKSArIA0KICB0aGVtZV9idygpICsNCiAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjApLA0KICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2KSwNCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpKSArDQogIGxhYnMoeSA9ICJEUE0gcGVyIGRheSIpDQpgYGANCg0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IHBvZGRhdGFfZGF5KSArIA0KICBnZW9tX2JveHBsb3QoYWVzKHggPSBmYWN0b3IoMCksIHkgPSBDbGlja19mcmVxdWVuY3kpLCBmaWxsPSIjMDA4RUFBIikgKyANCiAgdGhlbWVfYncoKSArDQogIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwKSwNCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiksDQogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSkgKw0KICBsYWJzKHkgPSAiQ2xpY2sgZnJlcXVlbmN5IHBlciBkYXkiKQ0KYGBgDQpgYGB7cn0NCmdncGxvdChkYXRhID0gcG9kZGF0YV9kYXkpICsgDQogIGdlb21fYm94cGxvdChhZXMoeCA9IGZhY3RvcigwKSwgeSA9IENsaWNrX2ZyZXF1ZW5jeSksIGZpbGw9IiMwMDhFQUEiKSArIA0KICB0aGVtZV9idygpICsNCiAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjApLA0KICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2KSwNCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpKSArDQogIGxhYnMoeSA9ICJDbGljayBmcmVxdWVuY3kgcGVyIGRheSIpDQpgYGANCg0KV2UgY2FuIGRvIHRoZSBzYW1lIGZvciBEcDEwbSBhbmQgRHBoLg0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IHBvZGRhdGFfZGF5KSArIA0KICBnZW9tX2JveHBsb3QoYWVzKHggPSBmYWN0b3IoMCksIHkgPSBEcDEwbSksIGZpbGw9IiMwMDhFQUEiKSArIA0KICB0aGVtZV9idygpICsNCiAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjApLA0KICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2KSwNCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpKSArDQogIGxhYnMoeSA9ICJEUDEwTSBwZXIgZGF5IikNCmBgYA0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IHBvZGRhdGFfZGF5KSArIA0KICBnZW9tX2JveHBsb3QoYWVzKHggPSBmYWN0b3IoMCksIHkgPSBEcDEwbSksIGZpbGw9IiMwMDhFQUEiKSArIA0KICB0aGVtZV9idygpICsNCiAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjApLA0KICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2KSwNCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpKSArDQogIGxhYnMoeSA9ICJEUDEwTSBwZXIgZGF5IikNCmBgYA0KDQpgYGB7cn0NCmdncGxvdChkYXRhID0gcG9kZGF0YV9kYXkpICsgDQogIGdlb21fYm94cGxvdChhZXMoeCA9IGZhY3RvcigwKSwgeSA9IERwaCksIGZpbGw9IiMwMDhFQUEiKSArIA0KICB0aGVtZV9idygpICsNCiAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjApLA0KICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2KSwNCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpKSArDQogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDAsMjQpLCBicmVha3MgPSBjKDAsIDQsIDgsIDEyLCAxNiwgMjAsIDI0KSkgKyANCiAgbGFicyh5ID0gIkRQSCBwZXIgZGF5IikNCmBgYA0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IHBvZGRhdGFfZGF5KSArIA0KICBnZW9tX2JveHBsb3QoYWVzKHggPSBmYWN0b3IoMCksIHkgPSBEcGgpLCBmaWxsPSIjMDA4RUFBIikgKyANCiAgdGhlbWVfYncoKSArDQogIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwKSwNCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiksDQogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygwLDI0KSwgYnJlYWtzID0gYygwLCA0LCA4LCAxMiwgMTYsIDIwLCAyNCkpICsgDQogIGxhYnMoeSA9ICJEUEggcGVyIGRheSIpDQpgYGANCg0KQ2xldmVsYW5kIGRvdHBsb3RzIGFsbG93IGZvciBhIGZ1cnRoZXIgaW5zcGVjdGlvbiBvZiBvdXRsaWVycy4NCmBgYHtyfQ0KZ2dwbG90KGRhdGEgPSBwb2RkYXRhX2RheSkgKyANCiAgZ2VvbV9wb2ludChhZXMoeD0gRHBtLCB5ID0gVGltZSkpICsNCiAgdGhlbWVfYncoKSArIA0KICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMCksDQogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiksDQogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkgKw0KICBsYWJzKHggPSAiRFBNIHBlciBkYXkiKQ0KYGBgDQpgYGB7cn0NCmdncGxvdChkYXRhID0gcG9kZGF0YV9kYXkpICsgDQogIGdlb21fcG9pbnQoYWVzKHg9IERwbSwgeSA9IFRpbWUpKSArDQogIHRoZW1lX2J3KCkgKyANCiAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjApLA0KICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYpLA0KICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpICsNCiAgbGFicyh4ID0gIkRQTSBwZXIgZGF5IikNCmBgYA0KDQpgYGB7cn0NCmdncGxvdChkYXRhID0gcG9kZGF0YV9kYXkpICsgDQogIGdlb21fcG9pbnQoYWVzKHg9IERwbSwgeSA9IFN0YXRpb24pKSArDQogIHRoZW1lX2J3KCkgKyANCiAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjApLA0KICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYpLA0KICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpICsNCiAgbGFicyh4ID0gIkRQTSBwZXIgZGF5IikNCmBgYA0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IHBvZGRhdGFfZGF5KSArIA0KICBnZW9tX3BvaW50KGFlcyh4PSBEcG0sIHkgPSBTdGF0aW9uKSkgKw0KICB0aGVtZV9idygpICsgDQogIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwKSwNCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2KSwNCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArDQogIGxhYnMoeCA9ICJEUE0gcGVyIGRheSIpDQpgYGANCg0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IHBvZGRhdGFfZGF5KSArIA0KICBnZW9tX3BvaW50KGFlcyh4PSBEcG0sIHkgPSBab25lKSkgKw0KICB0aGVtZV9idygpICsgDQogIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwKSwNCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2KSwNCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArDQogIGxhYnMoeCA9ICJEUE0gcGVyIGRheSIpDQpgYGANCmBgYHtyfQ0KZ2dwbG90KGRhdGEgPSBwb2RkYXRhX2RheSkgKyANCiAgZ2VvbV9wb2ludChhZXMoeD0gRHBtLCB5ID0gWm9uZSkpICsNCiAgdGhlbWVfYncoKSArIA0KICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMCksDQogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiksDQogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkgKw0KICBsYWJzKHggPSAiRFBNIHBlciBkYXkiKQ0KYGBgDQoNCiMjIDIuMi4yIFN0ZXAgMjogRG8gd2UgaGF2ZSBob21vZ2VuZWl0eSBvZiB2YXJpYW5jZT8NClRvIGNoZWNrIGZvciBob21vZ2Vpbml0eSBvZiB2YXJpYW5jZSwgd2UgY2FuIG1ha2UgY29uZGl0aW9uYWwgYm94cGxvdHMuDQpgYGB7cn0NCmdncGxvdChkYXRhID0gcG9kZGF0YV9kYXkpICsgDQogIGdlb21fYm94cGxvdChhZXMoeCA9IGFzLmZhY3Rvcihtb250aChUaW1lKSksIHkgPSBEcG0pLCBmaWxsPSIjMDA4RUFBIikgKyANCiAgdGhlbWVfYncoKSArDQogIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwKSwNCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiksDQogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSkgKw0KICBsYWJzKHkgPSAiRFBNIHBlciBkYXkiKQ0KYGBgDQpgYGB7cn0NCmdncGxvdChkYXRhID0gcG9kZGF0YV9kYXkpICsgDQogIGdlb21fYm94cGxvdChhZXMoeCA9IGFzLmZhY3Rvcihtb250aChUaW1lKSksIHkgPSBEcG0pLCBmaWxsPSIjMDA4RUFBIikgKyANCiAgdGhlbWVfYncoKSArDQogIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwKSwNCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiksDQogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSkgKw0KICBsYWJzKHkgPSAiRFBNIHBlciBkYXkiKQ0KYGBgDQoNCmBgYHtyfQ0KZ2dwbG90KGRhdGEgPSBwb2RkYXRhX2RheSkgKyANCiAgZ2VvbV9ib3hwbG90KGFlcyh4ID0gWm9uZSwgeSA9IERwbSksIGZpbGw9IiMwMDhFQUEiKSArIA0KICB0aGVtZV9idygpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSwNCiAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjApLA0KICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2KSwNCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpKSArDQogIGxhYnMoeSA9ICJEUE0gcGVyIGRheSIpDQpgYGANCmBgYHtyfQ0KZ2dwbG90KGRhdGEgPSBwb2RkYXRhX2RheSkgKyANCiAgZ2VvbV9ib3hwbG90KGFlcyh4ID0gWm9uZSwgeSA9IERwbSksIGZpbGw9IiMwMDhFQUEiKSArIA0KICB0aGVtZV9idygpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSwNCiAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjApLA0KICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2KSwNCiAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpKSArDQogIGxhYnMoeSA9ICJEUE0gcGVyIGRheSIpDQpgYGANCg0KQWRkaXRpb25hbGx5LCB0aGUgZGF0YSBkaXN0cmlidXRpb24gY2FuIGJlIGV4cGxvcmVkIHBlciBtb250aCBvciBzdGF0aW9uIHdpdGggdGhlICpmYWNldF93cmFwKCkqIGFyZ3VtZW50Lg0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IHBvZGRhdGFfZGF5KSArIA0KICBnZW9tX2JveHBsb3QoYWVzKHggPSBhcy5mYWN0b3IobW9udGgoVGltZSkpLCB5ID0gRHBtKSwgZmlsbD0iIzAwOEVBQSIpICsgDQogIHRoZW1lX2J3KCkgKw0KICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMCksDQogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQpLA0KICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpICsNCiAgbGFicyh5ID0gIkRQTSBwZXIgZGF5IikgKyANCiAgZmFjZXRfd3JhcCh+Wm9uZSkNCmBgYA0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IHBvZGRhdGFfZGF5KSArIA0KICBnZW9tX2JveHBsb3QoYWVzKHggPSBhcy5mYWN0b3IobW9udGgoVGltZSkpLCB5ID0gRHBtKSwgZmlsbD0iIzAwOEVBQSIpICsgDQogIHRoZW1lX2J3KCkgKw0KICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMCksDQogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQpLA0KICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpICsNCiAgbGFicyh5ID0gIkRQTSBwZXIgZGF5IikgKyANCiAgZmFjZXRfd3JhcCh+Wm9uZSkNCmBgYA0KDQojIyAyLjIuMyBTdGVwIDM6IEFyZSB0aGUgZGF0YSBub3JtYWxseSBkaXN0cmlidXRlZD8NCkFsdGhvdWdoIHdlIGNhbiBhbHJlYWR5IHN1c3BlY3QgdGhlIGRhdGEgYXJlIG5vdCBub3JtYWxseSBkaXN0cmlidXRlZCwgYSBoaXN0b2dyYW0gY2FuIHNoZWQgbGlnaHQgb24gdGhlIGRpc3RyaWJ1dGlvbiBvZiBhIHZhcmlhYmxlLg0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IHBvZGRhdGFfZGF5KSArIA0KICBnZW9tX2hpc3RvZ3JhbShhZXMoeCA9IERwbSksIGZpbGw9IiMwMDhFQUEiKSArIA0KICB0aGVtZV9idygpICsgDQogIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwKSwNCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2KSwNCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArDQogIGxhYnMoeCA9ICJEUE0gcGVyIGRheSIpDQpgYGANCmBgYHtyfQ0KZ2dwbG90KGRhdGEgPSBwb2RkYXRhX2RheSkgKyANCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKHggPSBEcG0pLCBmaWxsPSIjMDA4RUFBIikgKyANCiAgdGhlbWVfYncoKSArIA0KICB0aGVtZShheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMCksDQogICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiksDQogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkgKw0KICBsYWJzKHggPSAiRFBNIHBlciBkYXkiKQ0KYGBgDQoNCmBgYHtyfQ0KZ2dwbG90KGRhdGEgPSBwb2RkYXRhX2RheSkgKyANCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKHggPSBEcG0pLCBmaWxsPSIjMDA4RUFBIixiaW53aWR0aCA9IDEwKSArIA0KICB0aGVtZV9idygpICsgDQogIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwKSwNCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2KSwNCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArDQogIGxhYnMoeCA9ICJEUE0gcGVyIGRheSIpDQpgYGANCmBgYHtyfQ0KZ2dwbG90KGRhdGEgPSBwb2RkYXRhX2RheSkgKyANCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKHggPSBEcG0pLCBmaWxsPSIjMDA4RUFBIixiaW53aWR0aCA9IDEwKSArIA0KICB0aGVtZV9idygpICsgDQogIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwKSwNCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2KSwNCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArDQogIGxhYnMoeCA9ICJEUE0gcGVyIGRheSIpDQpgYGANCg0KIyMgMi4yLjQgU3RlcCA0OiBBcmUgdGhlcmUgbG90cyBvZiB6ZXJvcyBpbiB0aGUgZGF0YT8NCk5leHQsIFp1dXIgYWR2aXNlcyB0byBtYWtlIGEgZnJlcXVlbmN5IHBsb3QgdG8gY2hlY2sgZm9yIHRoZSBhbW91bnQgb2YgemVyb3MgaW4gdGhlIGRhdGEuIFRoZSBnZW9tX3J1ZyBhcmd1bWVudCBmYWNpbGl0YXRlcyB0aGUgDQpgYGB7cn0NCmdncGxvdChkYXRhID0gcG9kZGF0YV9kYXkpICsgDQogIGdlb21faGlzdG9ncmFtKGFlcyh4ID0gRHBtKSwgZmlsbD0iIzAwOEVBQSIsIGJpbndpZHRoID0gMSwgcG9zaXRpb24gPSAiZG9kZ2UiLCBzaXplID0gMC41KSArDQogIGdlb21fcnVnKGFlcyh4ID0gRHBtKSkrDQogIHRoZW1lX2J3KCkgKyANCiAgdGhlbWUoYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjApLA0KICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYpLA0KICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpICsNCiAgbGFicyh4ID0gIkRQTSBwZXIgZGF5IikNCmBgYA0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IHBvZGRhdGFfZGF5KSArIA0KICBnZW9tX2hpc3RvZ3JhbShhZXMoeCA9IERwbSksIGZpbGw9IiMwMDhFQUEiLCBiaW53aWR0aCA9IDEsIHBvc2l0aW9uID0gImRvZGdlIiwgc2l6ZSA9IDAuNSkgKw0KICBnZW9tX3J1ZyhhZXMoeCA9IERwbSkpKw0KICB0aGVtZV9idygpICsgDQogIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwKSwNCiAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2KSwNCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArDQogIGxhYnMoeCA9ICJEUE0gcGVyIGRheSIpDQpgYGANCg0KRGVwZW5kaW5nIG9uIHRoZSByZXNlYXJjaCBxdWVzdGlvbiwgdGhlcmUgYXJlIG1hbnkgbW9yZSBvcHRpb25zIGZvciBleHBsb3JhdGlvbiBvZiB0aGUgZGF0YSEgU3RlcCA1LTcgb2YgWnV1cidzIHByb3RvY29sIG1pZ2h0IGJlIHVzZWZ1bCB3aGVuIHVzaW5nIG1ldGFkYXRhIQ0K