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.

0. Load the data

Defining a working directory facilitates the access to folders and documents. This can be done by creating an R project or by code setwd().

getwd() # Check your current working directory.
list.files() # See the files in your working directory

In the folder Data, you can find several data tables, downloaded from the RShiny application. The names indicate the quality of the detected porpoise clicks.

list.files("Data day 1")
[1] "hi_mod_1hr.tab" "Mapping"        "Metadata"      

The file hi_mod.tab contains the detections of quality hi and mod pooled together for each hour. We will use this file for this session.

Importing the data is possible by code or by the ‘Import Dataset’ button in the Environment window on the right.

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:

A first exploration with the str() function already indicates some issues and possibilites for improvement:

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