Project Overview

Goal:

We are analyzing 2019 US domestic flights data to help people better understand the factors that are associated with flight delays.

Main Procedures:

  1. Data extraction, merge and features selection
  2. Data cleaning and transformation
  3. Delay visualizations
  4. Conclusion

Data Extraction and Cleaning:

We collected data from https://www.transtats.bts.gov/DL_SelectFields.asp?Table_ID=236, which is under the maintenance of Bureau of Transportation Statistics. The dataset we employed contained more than 7.6 million domestic flights in 2019. Meanwhile, we also wrangled and transformed new features to present the data plot more properly.

Some Key Variables:

  • Month: month of the flights
  • Time: flight time of the day, morning, afternoon and night.
  • City: flights departure city’s name
  • State_Name: flights departure state’s name
  • IATA_Code: Code assigned by IATA and commonly used to identify a carrier.
  • NAS: National Air System Delay, in Minutes
  • DEP_DELAY & ARR_DELAY: Departure delay and arrival delay, in minutes
  • Delay: whether flights are on time, short time delay, or long time delay
  • AIRLINE: names of different airline
  • AIR_TIME: Flight length
  • Description: Full name of the airport.
library(readr)
library(dplyr)
library(forcats)
library(ggplot2)
library(ggthemes)
library(ggpubr)
library(ggrepel)
library(plotly)
library(plotrix)
library(RColorBrewer)
library(ggmap)
library(leaflet)
library(leafsync)
library(leaflet.extras)
library(leafletCN)
setwd("C:/Users/Yuhua_Ding/OneDrive/Documents/QMSS Spring 2020/GR5063 Data Visualization/Final_project")
all_2019 <- read_rds("all_2019.Rds")
df <- all_2019
city <- strsplit(df$ORIGIN_CITY_NAME, ",")
mat <- matrix(unlist(city), ncol=2, byrow=TRUE)
city <- as.data.frame(mat)
df$ORIGIN_CITY_NAME  <- city$V1

names(df)[12] <- "city"
names(df)[13] <- 'state_name'
names(df)[8] <- "IATA_CODE"
df$city <- as.character(df$city)
df$state_name <- as.character(df$state_name)
df$IATA_CODE <- as.character(df$IATA_CODE)
lon_lat <- read_csv("data/uscities.csv")
lon_lat <- lon_lat %>%
  dplyr::select(city,state_name,lat,lng,population)

airlines <- read.csv("data/airlines.csv")
airlines$IATA_CODE <- as.character(airlines$IATA_CODE)
lon_lat$city <- as.character(lon_lat$city)
lon_lat$state_name <- as.character(lon_lat$state_name)

df1 <- left_join(df, lon_lat, by = c('city'='city', 'state_name'='state_name'))
df2 <- left_join(df1, airlines)

airport <- read.csv("data/L_AIRPORT_ID.csv")
names(airport)[1] = "ORIGIN_AIRPORT_ID"
df2 <- left_join(df2, airport)
all_2019 <- all_2019 %>% mutate(TOT_DELAY = DEP_DELAY + ARR_DELAY)

all_2019$al_name <- all_2019$OP_CARRIER

all_2019$al_name <- recode(all_2019$al_name, "AS" = "Alaska Airlines", "G4" = "Allegiant Air",
                           "AA" = "American Airlines", "DL" = "Delta Air Lines", "F9" = "Frontier Airlines",
                           "HA" = "Hawaiian Airlines", "B6" = "JetBlue Airways", "WN" = "Southwest Airlines", 
                           "NK" = "Spirit Airlines", "UA" = "United Airlines", 
                           .default = "Other", .missing = "Other")

all_2019$lc_airlines <- fct_collapse(all_2019$OP_CARRIER, "Budget Airlines" = c("NK", "F9", "WN", "B6", "G4"), 
                                     "Other Major Airlines" = c("AS", "AA", "DL", "HA", "UA"))
all_2019$lc_airlines <- as.vector(all_2019$lc_airlines)

all_2019$lc_airlines <- recode(all_2019$lc_airlines, "Budget Airlines" = "Budget Airlines", 
                               "Other Major Airlines" = "Other Major Airlines", .default = "Other smaller airlines",
                               .missing = "Other smaller airlines")
summary_by_al <- all_2019 %>% group_by(lc_airlines, al_name) %>% 
                              summarise(ARR_DELAY = round(mean(ARR_DELAY, na.rm = TRUE), 1), 
                                                               DEP_DELAY = round(mean(DEP_DELAY, na.rm = TRUE), 1),
                                                               TOT_DELAY = ARR_DELAY + DEP_DELAY)

Visualizations

1. Overview of U.S. Domestic Flight Delays

a) Delay and air traffic volume by U.S. states and cities

We first process the data and get all the airports flights delay information (departure delay and arrival delay) from each of the US cities. From the state of Alabama to Wyoming.

library(DT)

summary_2019 <- all_2019 %>% group_by(State = ORIGIN_STATE_NM, City = ORIGIN_CITY_NAME) %>% 
                             dplyr::summarise("Departure Delay" = round(mean(DEP_DELAY, 
                                                                             na.rm = TRUE), 1),                                                     "Arrival Delay" = round(mean(ARR_DELAY,                                                                                             na.rm = TRUE), 1),
                                              "Flight Volumne (in Thousands)" = round(n() / 1000), 1)

summary_2019 %>% datatable(rownames = FALSE, filter = list(position = "top"), 
                            options = list(language = list(sSearch = "Filter:"))) %>%
  formatStyle(columns = 1:5, color = 'black')

b) U.S. Delay Map by States

We use choropleth maps to see how the delays are distributed. As it shows from the graph, northern states like North Dakota and South Dakota have longer delays. Some New England states also have longer delays. We were thinking that the reason could be cold weather.

library(rgdal)
library(raster)
#US_SHP <- readOGR(dsn = "C:/Users/Yuhua_Ding/OneDrive/Documents/QMSS Spring 2020/GR5063 Data Visualization/Final_project", layer = "cb_2018_us_state_500k")


US_SHP <- shapefile("C:/Users/Yuhua_Ding/OneDrive/Documents/QMSS Spring 2020/GR5063 Data Visualization/Final_project/shpfile/cb_2018_us_state_500k.shp")
US_sp <- spTransform(US_SHP, CRS("+init=epsg:4326"))
By_state <- all_2019 %>% group_by(ORIGIN_STATE_NM) %>% 
                         summarise(TOT_DELAY = round(mean(TOT_DELAY, na.rm = TRUE), 0),
                                                                 FL_COUNT = n())

US_sp@data <- US_sp@data %>% left_join(By_state, by = c("NAME" = "ORIGIN_STATE_NM"))
Label_Content <- paste("State Name:", US_sp@data$NAME, "<br/>",
                           "Average Delay Time (Minutes):", US_sp@data$TOT_DELAY, "<br/>",
                           "Flight Count (Thousands):", round(US_sp@data$FL_COUNT / 1000, 2))

bins <- c(-Inf, 10, 15, 20, 25, Inf)
pal3 <- colorBin("YlOrRd", domain = US_sp@data$TOT_DELAY, bins = bins, na.color = "transparent")

m4 <- leaflet(data = US_sp, options = leafletOptions(minZoom = 4, maxZoom = 7)) %>% 
                          setView(lng = -96.20, lat = 39.50, zoom = 4) %>% 
                          addProviderTiles(providers$CartoDB.Positron) %>%
                          addPolygons(stroke = TRUE, smoothFactor = 0.5,
                                       weight=1, color='#333333', opacity=1, 
                                       fillColor = ~pal3(TOT_DELAY), 
                                       fillOpacity = 1, 
                                       label = ~stringr::str_c(NAME, " ",
                                       "Average Delay: ",                         
                                       formatC(TOT_DELAY, big.mark = ',', format='d')),
                                       labelOptions = labelOptions(direction = 'auto'),
                                       highlightOptions = highlightOptions(
                                       color='#9a8ee8', weight = 3,
                                       bringToFront = TRUE, sendToBack = TRUE),
                                       popup = Label_Content) %>%
                          addLegend(pal = pal3, values = ~TOT_DELAY, 
                                    opacity = 0.75, position = "bottomleft",
                                    title = "Average Delay Time And Air Traffic Volume By State")

m4

c) Treemap of delayed flight count, by U.S. states

Treemap was used to distinguish US states’ flights delay situation. The larger area each state occupies, the more delayed flights that state has.

delayed_count <- all_2019 %>% filter(TOT_DELAY > 0) %>%
                              group_by(state = ORIGIN_STATE_NM) %>% dplyr::summarise(count = n())
tree1 <- treemap(delayed_count, index = "state", vSize = "count", type = "index", 
        palette = "Purples", title = "Count of Delayed Flights By State")

2. Delay By Airlines

a) Airline Market Share

A simple illustration of market share breakdown for commercial airlines. We made a bar chart to show each major airlines’ market share (in percentage). Budget airlines like Southwest Airlines occupy around 20% of the aviation market share while small regional airlines like Hawaiian Airlines only occupy less than 5% market share in total.

b) Airline Mean Delay Time

Before we draw the Airline’s main delay time chart, we summarised the average total delay (arrival delay plus departure delay) of the major airlines. Among the 12 airlines, Jetblue and Atlantic Southeast airlines have the longest mean delay time (over 20 mins) while Hawaiian Airlines has the mean delay time of 6 minutes. A barplot was used to visualize the result.

sum <- df2%>%
  dplyr::select(AIRLINE,ARR_DELAY_NEW)%>%
  filter(!is.na(ARR_DELAY_NEW), !is.na(AIRLINE))%>%
  group_by(AIRLINE)%>%
  summarise(mean=round(mean(ARR_DELAY_NEW)), max = round(max(ARR_DELAY_NEW)), min= round(min(ARR_DELAY_NEW)))%>%
  arrange(desc(mean))

c) Departure and arrival delay for low-cost airlines versus others.

We wanted to use one chart to show each airline’s departure and arrival delays. From the plot, we can tell that Hawaiian airlines has the shortest departure delay and arrival delay. Jetblue Airways has the longest departure and arrival delays (all in minutes). After we finished drawing the plot, we also would like to see if budget airlines and other major airlines have different departure and delay time. By making the calculation, we found out that budget airlines have the mean departure delay of 13.1 mins and departure delay of 7.6 mins. At the same time, other major airlines have the mean departure delay of 8.2 mins and arrival delays of 4.0 mins. The pyramid chart also shows us that budget airlines usually have worse delays than others (JetBlue’s delay is notoriously longer, as illustrated)

summary_by_al_volume <- all_2019 %>% filter(al_name != "Other") %>% 
                                     group_by(lc_airlines, al_name) %>% 
                                     summarise(TOT_DELAY = round(mean(ARR_DELAY + DEP_DELAY, 
                                                                      na.rm = TRUE), 1),
                                                                      Volume = n())

d) Do larger airlines have longer delays?

Overall, budget airlines have longer delays, but the delay time decreases as the company size increases. For other large traditional airlines, larger size resulted in longer delays (maybe due to operational deficiency)

p5 <- ggplot(data = summary_by_al_volume, aes(x = log(Volume), y = TOT_DELAY)) + 
      geom_point(aes(color = lc_airlines, size = log(Volume))) + 
      geom_text_repel(label = summary_by_al_volume$al_name) + 
      geom_smooth(aes(color = lc_airlines), method = "lm", se = FALSE, alpha = 0.1) + 
      theme_economist() + 
      labs(y = "Total delay (minutes)", x = "Number of flights in 2019, in natural log form", 
        title = "Do larger airlines have longer delays?") + 
      scale_color_discrete(name = "") +
      scale_size(guide = 'none')

p5

3. Delay By Time

a) Delay map by quarters of 2019

The flight map is designed to show us which area has the longest average delay time in the USA. If the color around the area is light pink, then the average delay time will be 0-15 mins. However, if the color is dark red, then the delay time is above 45 mins. The size of the circle represents the air traffic volume in that area. The map shows that delay is not necessarily related to the large traffic volume. In the first quarter, the cities in the north like Michigan overall had much worse delays. However, the situation changed in the second quarter. In the second quarter, the cities in the south like Miami overall had much worse delays. It makes sense because summer is the season for extreme weathers like thunderstorms.

cities <- readRDS("cities.Rds")
cities <- cities %>% rename(City_name = "ORIGIN_CITY_NAME")
city_delays <- all_2019 %>% group_by(QUARTER, ORIGIN_CITY_NAME) %>% 
                            summarise(TOT_DELAY = round(mean(TOT_DELAY, na.rm = TRUE), 0),
                                      FL_COUNT = n()) %>% 
                            rename(City_name = ORIGIN_CITY_NAME)
city_delays <- right_join(city_delays, cities, by = "City_name")


FY <- city_delays %>% group_by(City_name, lon, lat) %>% summarise(TOT_DELAY = mean(TOT_DELAY),
                                                                  FL_COUNT = sum(FL_COUNT))
Q1 <- city_delays %>% filter(QUARTER == 1)
Q2 <- city_delays %>% filter(QUARTER == 2)
Q3 <- city_delays %>% filter(QUARTER == 3)
Q4 <- city_delays %>% filter(QUARTER == 4)


FY_Content <- paste("City Name:", FY$City_name, "<br/>",
                           "Average Delay Time (Minutes):", FY$TOT_DELAY, "<br/>",
                           "Total Flight Count (in Thousands):", round(FY$FL_COUNT / 1000, 2))
Q1_Content <- paste("City Name:", Q1$City_name, "<br/>",
                           "Average Delay Time (Minutes):", Q1$TOT_DELAY, "<br/>",
                           "Total Flight Count (in Thousands):", round(Q1$FL_COUNT / 1000, 2))
Q2_Content <- paste("City Name:", Q2$City_name, "<br/>",
                           "Average Delay Time (Minutes):", Q2$TOT_DELAY, "<br/>",
                           "Total Flight Count (in Thousands):", round(Q2$FL_COUNT / 1000, 2))
Q3_Content <- paste("City Name:", Q3$City_name, "<br/>",
                           "Average Delay Time (Minutes):", Q3$TOT_DELAY, "<br/>",
                           "Total Flight Count (in Thousands):", round(Q3$FL_COUNT / 1000, 2))
Q4_Content <- paste("City Name:", Q4$City_name, "<br/>",
                           "Average Delay Time (Minutes):", Q4$TOT_DELAY, "<br/>",
                           "Total Flight Count (in Thousands):", round(Q4$FL_COUNT / 1000, 2))


bins <- c(-Inf, 15, 30, 45, Inf)
pal1 <- colorBin("Reds", domain = city_delays$TOT_DELAY, bins = bins, na.color = "transparent")

m1 <- leaflet(city_delays, options = leafletOptions(minZoom = 4, maxZoom = 7)) %>% 
        setView(lng = -96.20, lat = 39.50, zoom = 4) %>%
        addProviderTiles(providers$CartoDB.Positron) %>%
        addCircles(data = FY, lng = ~lon, lat = ~lat, radius = ~ FL_COUNT / 4, 
                   color = ~pal1(TOT_DELAY), opacity = 0.8, popup = FY_Content, group = "FY") %>%
        addCircles(data = Q1, lng = ~lon, lat = ~lat, radius = ~ FL_COUNT, 
                   color = ~pal1(TOT_DELAY), opacity = 0.8, popup = Q1_Content, group = "Q1") %>%
        addCircles(data = Q2, lng = ~lon, lat = ~lat, radius = ~ FL_COUNT, 
                   color = ~pal1(TOT_DELAY), opacity = 0.8, popup = Q2_Content, group = "Q2") %>%
        addCircles(data = Q3, lng = ~lon, lat = ~lat, radius = ~ FL_COUNT, 
                   color = ~pal1(TOT_DELAY), opacity = 0.8, popup = Q3_Content, group = "Q3") %>%
        addCircles(data = Q4, lng = ~lon, lat = ~lat, radius = ~ FL_COUNT, 
                   color = ~pal1(TOT_DELAY), opacity = 0.8, popup = Q4_Content, group = "Q4") %>%
        addLegend(pal = pal1, values = ~TOT_DELAY, position = "bottomleft", 
                  title = "Average Total Delay (in minutes)", 
                  opacity = 0.75) %>%
        addLayersControl(baseGroups = c("FY", "Q1", "Q2", "Q3", "Q4"), 
                         options = layersControlOptions(collapsed = TRUE))

m1
worst_delays <- all_2019 %>% filter(TOT_DELAY >= 360) %>% 
                             select(MONTH, DAY_OF_WEEK, OP_CARRIER, TOT_DELAY, 
                                    City_name = ORIGIN_CITY_NAME)

worst_delays <- right_join(worst_delays, cities, by = "City_name")

worst_delays$DAY_OF_WEEK <- recode(worst_delays$DAY_OF_WEEK, "1" = "Monday", "2" = "Tuesday", 
                                   "3" = "Wednesday", "4" = "Thursday", "5" = "Friday", 
                                   "6" = "Saturday", "7" = "Sunday")
red_eye_flights <- all_2019 %>% filter(CRS_DEP_TIME >= 2100 & CRS_ARR_TIME <= 0600)
normal_flights <- all_2019 %>% filter(DEP_TIME < 2100 | ARR_TIME > 0600)

red_eye_flights_summ <- red_eye_flights %>% group_by(City_name = ORIGIN_CITY_NAME) %>% 
                                            summarise(TOT_DELAY = round(mean(TOT_DELAY, 
                                                                        na.rm = TRUE), 0)) %>%
                                            right_join(cities, by = "City_name")

normal_flights_summ <- normal_flights %>% group_by(City_name = ORIGIN_CITY_NAME) %>% 
                                            summarise(TOT_DELAY = round(mean(TOT_DELAY, 
                                                                        na.rm = TRUE), 0))%>%
                                            right_join(cities, by = "City_name")
## function borrowed from package leafletCN
##' @title Add title to the leaflet
##'
##' @description Function for creating a h1 title to the leaflet

addTitle = function(object,
                    text,
                    color = "black",
                    fontSize = "20px",
                    fontFamily = "Sans",
                    leftPosition = 50,
                    topPosition = 2){

  htmlwidgets::onRender(object, paste0("
                                       function(el,x){
                                       h1 = document.createElement('h1');
                                       h1.innerHTML = '", text ,"';
                                       h1.id='titleh1';
                                       h1.style.color = '", color ,"';
                                       h1.style.fontSize = '",fontSize,"';
                                       h1.style.fontFamily='",fontFamily,"';
                                       h1.style.position = 'fixed';
                                       h1.style['-webkit-transform']='translateX(-50%)';
                                       h1.style.left='",leftPosition ,"%';
                                       h1.style.top='",topPosition,"%';
                                       document.body.appendChild(h1);
                                       }"))
}

b) Are the worst delays usually associated with Red Eye Flights?

Red Eye flights are defined as flights that departs after 9 p.m. and arrives before 6 a.m. In the following two maps, the “worst delays” are defined as delays that are over 6 hours, which is usually the delay time to trigger delay protection. The comparison below provides a fine illustration of the worst delays’ frequency between Red Eye flights and normal flights (the upper map represents Red Eye flights whereas the lower represents regulars). From the visualization we can easily tell Red Eye flights are commonly associated with delays that are over 6 hours (good lucks if you are traveling on those flights)

c) Worst delays by days of week

It is interesting to see that from Monday to Thursday, almost all of the worst delays are concentrated in New York and Chicago metropolitan areas. And when Friday and weekend days come, the worst delays start to spread to other popular getaway destinations (LA, Florida, New Orleans, e.g.) It might be because of the air traffic volume of the airports. From Monday to Thursday, people are more likely to travel for business. Thus, large cities for business like New York and Chicago have more air traffic volume. However, from Friday to Sunday, people are more likely to travel for vacation. Thus, the air traffic and delays spread to the south.

worst_delays <- all_2019 %>% filter(TOT_DELAY >= 360) %>% 
                             dplyr::select(MONTH, DAY_OF_WEEK, OP_CARRIER, TOT_DELAY, 
                                    City_name = ORIGIN_CITY_NAME) 

worst_delays <- right_join(worst_delays, cities, by = "City_name")

worst_delays$DAY_OF_WEEK <- factor(worst_delays$DAY_OF_WEEK, levels = 1:7, 
                                   labels = c("Monday", "Tuesday", "Wednesday",
                                              "Thursday", "Friday", "Saturday",
                                              "Sunday"))

worst_delays <- worst_delays %>% filter(!is.na(DAY_OF_WEEK))
map_USA <- get_map(location = c(lon = -96.20, lat = 39.50), zoom = 4, source="stamen", maptype="toner-lite")

m5 <- ggmap(map_USA) + stat_density2d(data = worst_delays, aes(x = lon, y = lat, fill = ..level..),
                                bins = 4, alpha = 0.5, geom = "polygon", size = 0.05
                                ) + 
                 theme(axis.title = element_blank(), 
                       axis.text = element_blank(),
                       axis.ticks = element_blank(),
                       legend.position = "none") + 
                 facet_wrap(~DAY_OF_WEEK, ncol = 4)
m5

d) Delay by month

We separated delays into three categories by delay status: long delay, short delay, and no delay, and we drew the bar chart to see how each category changed for each month. We found that in each year’s June, airplanes have the most long delay (marked in pink color) and short delay cases, on average. And in September, the delay cases are the fewest.

df2$delay <- "On_Time"
df2[which(df2$DEP_DELAY_NEW ==0), ]$delay = "On_Time"
df2[which(df2$DEP_DELAY_NEW >0 & df2$DEP_DELAY_NEW <30 ), ]$delay = "Short_Delay"
df2[which(df2$DEP_DELAY_NEW >30 ), ]$delay = "Long_Delay"

df2$MONTH <- as.factor(df2$MONTH)
a<- df2%>%
  dplyr::select(MONTH,delay)%>%
  group_by(MONTH)


b <-df2%>%
  dplyr::select(MONTH,delay)%>%
  filter(delay == "Long_Delay")%>%
  group_by(MONTH)%>%
  count(delay)%>%
  summarise(countT = sum(n))

p6 <- ggplot()+ geom_bar(data = a, aes(x = MONTH, fill = delay), position = 'dodge') + geom_line(data = b, aes(x = MONTH, y=countT, group = 1))+ xlab('Month') + ylab('Number of Flights')+ labs(title="Month and Flights number", caption = "Data source: Bureau of Transportation")+ theme_economist() + scale_colour_economist()+ theme(axis.title.x = element_text(vjust= -2), axis.title.y = element_text(vjust= 3), plot.caption = element_text(vjust= -5,hjust=1,face="italic",size = 8) )

p6

e) Delay length by time of the day

During the time of a day, morning has the smallest number of delays and the biggest number of on time flights. During the afternoon and night, the delay cases increase. The proportional bar plot also helps us to visually see the distributions.

c<- df2%>%
  dplyr::select(time,delay)%>%
  group_by(time)%>%
  count(delay)
ggplot()+ geom_bar(data = c, aes(x = time, fill = delay, y=n), 
                   position = 'fill', stat = 'identity') + 
          xlab('Time of the day') + ylab('Number of Flights') + 
          labs(title="Delay Type and Time of the Day", 
               caption = "Data source: Bureau of Transportation") + 
          theme_economist() +     scale_colour_economist()+ 
          theme(axis.title.x = element_text(vjust= -2), 
                axis.title.y = element_text(vjust= 3), 
                plot.caption = element_text(vjust= -5,hjust=1,face="italic",size = 8))

4. Miscellaenous (other interesting findings)

a) Delay length type by airline

We want to make comparisons between airlines’ delays. Among the 12 airlines, Southwest has the most delayed flights (both long and short delays, due to its large number of flights).

c<- df2%>%
  dplyr::select(AIRLINE,delay)%>%
  filter(!is.na(AIRLINE)) %>%
  group_by(AIRLINE)

ggplot()+ geom_bar(data = c, aes(x = AIRLINE, fill = delay), position = 'dodge') + xlab('Airlines') + ylab('Number of Flights')+ labs(title="Airlines and Type of Delay", caption = "Data source: Bureau of Transportation")+ theme_economist() + scale_colour_economist()+ theme(axis.title.x = element_text(vjust= -2), axis.title.y = element_text(vjust= 3), plot.caption = element_text(vjust= -5,hjust=1,face="italic",size = 8)) + coord_flip()

b) Offical Delay Reasons

We found out 5 major reasons that cause the flight delay. Among the 5 reasons, Security reasons barely cause delays. But bad weather like storms may cause delays, but with big storms. However, NAS reasons, airline companies’ specific reasons and flight late arrival are the most common reasons.

reason <- df2%>%
  dplyr::select(CARRIER_DELAY,WEATHER_DELAY,NAS_DELAY,SECURITY_DELAY,LATE_AIRCRAFT_DELAY)%>%
  na.omit()%>%
  transmute(carrier = mean(CARRIER_DELAY),weather = mean(WEATHER_DELAY), nas = mean(NAS_DELAY), 
         security = mean(SECURITY_DELAY),late= mean(LATE_AIRCRAFT_DELAY))%>%
  unique()%>%
  tidyr::gather(key = "reason", value = "mean_length")

ggplot(data = reason, aes(x = reorder(reason,mean_length), y = mean_length, fill = reason))+ geom_col() + xlab('Reason') + ylab('Mean Length')+ labs(title="Delay Reasons and Length", caption = "Data source: Bureau of Transportation")+ theme_economist() + scale_colour_economist()+  theme(legend.position = "none")+ theme(axis.title.x = element_text(vjust= -2),                                                                axis.title.y = element_text(vjust= 3),
                                          plot.caption = element_text(vjust= -5,hjust=1,face="italic",size = 8) )

c) Delay by flight length

The plot shows us that with the increase of flight time, the delay also decreases. The result suggests that when you take longer flights (from NYC to Hawaii, for instance), the flight barely delays. But if you choose to fly from Orlando to Charlotte, the flight might have a worse delay.

df3 <- df2[sample(nrow(df2), 10000), ]# sample 10000 rows

ggplot(data = df3, aes(x = AIR_TIME, y = DEP_DELAY_NEW),position = 'dodge')+ 
  geom_point(color = "orange") + xlab('Flight Time') + 
  ylab('Delay Time')+ labs(title="Flight time and Delay Time", 
                           caption = "Data source: Bureau of Transportation")+ 
  theme_economist() + scale_colour_economist()+ 
  theme(axis.title.x = element_text(vjust= -2), 
        axis.title.y = element_text(vjust= 3), 
        plot.caption = element_text(vjust= -5, hjust=1, face="italic", size = 8))

d) Airports with worst delays (avoid if possible)

The chart shows 10 airports that have the longest overall delay time among the whole country. The one with the longest delay time (Mammoth lakes airport) has 40 minutes delay time. The 10th rank airport (Aspen) has an averaged delay time of 30 minutes.

airp <- df2%>%
  dplyr::select(Description,ARR_DELAY_NEW)%>%
  filter(!is.na(ARR_DELAY_NEW))%>%
  group_by(Description)%>%
  summarise(mean=round(mean(ARR_DELAY_NEW)), max = round(max(ARR_DELAY_NEW)), min= round(min(ARR_DELAY_NEW)))%>%
  arrange(desc(mean))%>%
  head(10)

ggplot(data = airp, aes(x = reorder(Description,mean), y=mean,fill=Description))+geom_col()+xlab('Airpots') + 
  ylab('Delay Length')+ labs(title="Airports and Delay Time", caption = "Data source: Bureau of Transportation")+ theme_economist() + scale_colour_economist()+ coord_flip()+ theme(legend.position = "none")+ theme(axis.title.x = element_text(vjust= -2),                                                                axis.title.y = element_text(vjust= 3),
                                          plot.caption = element_text(vjust= -5,hjust=1,face="italic",size = 8) )

Conclusions

Overall, we found that northern states like North Dakota, South Dakota or New England states have longer delays which might be due to cold weather. From the treemap we can see states like Texas, California, NewYork, and Florida also have longer delays which might be due to popularity. Analyzed by Airlines, we found out that Jetblue and Atalantic Southeast airlines have the longest mean delay, so try to avoid those large airlines. Local airlines tend to have less average delay time. However, by analyzing the pyramid chart we found that budget airlines usually have worse delays than others.

Furthermore, try to avoid budget airlines like JetBlue for best experience. Analyzed by time, we found out an obvious pattern in quarter one and quarter two flights. In the first quarter, the cities in the north like Michigan overall had much worse delays. In the second quarter, the cities in the south like Miami overall had much worse delays. Also Red Eye flights are commonly associated with long delays that are over 6 hours, so try to avoid Red Eye flights. What’s more, from Monday to Thursday, almost all of the worst delays are concentrated in New York and Chicago metropolitan areas. And when Friday and weekend days come, the worst delays start to spread to other popular getaway destinations. Thus, we recommend you to adjust your flight schedule according to this pattern as much as possible to avoid long delays.

Analyzed by other interesting facts, we found that longer flight time usually corresponds to shorter average delay time.

Hopefully, this project will help you with your flight selection in the future! Have a safe and on-time trip!

LS0tDQp0aXRsZTogIlUuUy4gRG9tZXN0aWMgRmxpZ2h0IERlbGF5IEFuYWx5c2lzIg0Kb3V0cHV0OiANCiAgaHRtbF9ub3RlYm9vazoNCiAgICBkZl9wcmludDogcGFnZWQNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCi0tLQ0KIyBQcm9qZWN0IE92ZXJ2aWV3DQoNCiMjIyBHb2FsOiANCg0KV2UgYXJlIGFuYWx5emluZyAyMDE5IFVTIGRvbWVzdGljIGZsaWdodHMgZGF0YSB0byBoZWxwIHBlb3BsZSBiZXR0ZXIgdW5kZXJzdGFuZCB0aGUgZmFjdG9ycyB0aGF0IGFyZSBhc3NvY2lhdGVkIHdpdGggZmxpZ2h0IGRlbGF5cy4NCg0KIyMjIE1haW4gUHJvY2VkdXJlczoNCg0KMS4JRGF0YSBleHRyYWN0aW9uLCBtZXJnZSBhbmQgZmVhdHVyZXMgc2VsZWN0aW9uDQoyLiAgRGF0YSBjbGVhbmluZyBhbmQgdHJhbnNmb3JtYXRpb24gDQozLglEZWxheSB2aXN1YWxpemF0aW9ucw0KNC4JQ29uY2x1c2lvbg0KDQojIERhdGEgRXh0cmFjdGlvbiBhbmQgQ2xlYW5pbmc6DQoNCldlIGNvbGxlY3RlZCBkYXRhIGZyb20gaHR0cHM6Ly93d3cudHJhbnN0YXRzLmJ0cy5nb3YvRExfU2VsZWN0RmllbGRzLmFzcD9UYWJsZV9JRD0yMzYsIHdoaWNoIGlzIHVuZGVyIHRoZSBtYWludGVuYW5jZSBvZiBCdXJlYXUgb2YgVHJhbnNwb3J0YXRpb24gU3RhdGlzdGljcy4gVGhlIGRhdGFzZXQgd2UgZW1wbG95ZWQgY29udGFpbmVkIG1vcmUgdGhhbiA3LjYgbWlsbGlvbiBkb21lc3RpYyBmbGlnaHRzIGluIDIwMTkuIE1lYW53aGlsZSwgd2UgYWxzbyB3cmFuZ2xlZCBhbmQgdHJhbnNmb3JtZWQgbmV3IGZlYXR1cmVzIHRvIHByZXNlbnQgdGhlIGRhdGEgcGxvdCBtb3JlIHByb3Blcmx5LiAgDQoNCiMjIyBTb21lIEtleSBWYXJpYWJsZXM6DQoNCiogTW9udGg6IG1vbnRoIG9mIHRoZSBmbGlnaHRzDQoqIFRpbWU6IGZsaWdodCB0aW1lIG9mIHRoZSBkYXksIG1vcm5pbmcsIGFmdGVybm9vbiBhbmQgbmlnaHQuDQoqIENpdHk6IGZsaWdodHMgZGVwYXJ0dXJlIGNpdHnigJlzIG5hbWUNCiogU3RhdGVfTmFtZTogZmxpZ2h0cyBkZXBhcnR1cmUgc3RhdGXigJlzIG5hbWUNCiogSUFUQV9Db2RlOiBDb2RlIGFzc2lnbmVkIGJ5IElBVEEgYW5kIGNvbW1vbmx5IHVzZWQgdG8gaWRlbnRpZnkgYSBjYXJyaWVyLiANCiogTkFTOiBOYXRpb25hbCBBaXIgU3lzdGVtIERlbGF5LCBpbiBNaW51dGVzDQoqIERFUF9ERUxBWSAmIEFSUl9ERUxBWTogRGVwYXJ0dXJlIGRlbGF5IGFuZCBhcnJpdmFsIGRlbGF5LCBpbiBtaW51dGVzDQoqIERlbGF5OiAgd2hldGhlciBmbGlnaHRzIGFyZSBvbiB0aW1lLCBzaG9ydCB0aW1lIGRlbGF5LCBvciBsb25nIHRpbWUgZGVsYXkNCiogQUlSTElORTogbmFtZXMgb2YgZGlmZmVyZW50IGFpcmxpbmUNCiogQUlSX1RJTUU6IEZsaWdodCBsZW5ndGgNCiogRGVzY3JpcHRpb246IEZ1bGwgbmFtZSBvZiB0aGUgYWlycG9ydC4NCg0KYGBge3IgbWVzc2FnZSA9IEZBTFNFfQ0KbGlicmFyeShyZWFkcikNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGZvcmNhdHMpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KGdndGhlbWVzKQ0KbGlicmFyeShnZ3B1YnIpDQpsaWJyYXJ5KGdncmVwZWwpDQpsaWJyYXJ5KHBsb3RseSkNCmxpYnJhcnkocGxvdHJpeCkNCmxpYnJhcnkoUkNvbG9yQnJld2VyKQ0KbGlicmFyeShnZ21hcCkNCmxpYnJhcnkobGVhZmxldCkNCmxpYnJhcnkobGVhZnN5bmMpDQpsaWJyYXJ5KGxlYWZsZXQuZXh0cmFzKQ0KbGlicmFyeShsZWFmbGV0Q04pDQpsaWJyYXJ5KHRyZWVtYXApDQpgYGANCg0KYGBge3J9DQpzZXR3ZCgiQzovVXNlcnMvWXVodWFfRGluZy9PbmVEcml2ZS9Eb2N1bWVudHMvUU1TUyBTcHJpbmcgMjAyMC9HUjUwNjMgRGF0YSBWaXN1YWxpemF0aW9uL0ZpbmFsX3Byb2plY3QiKQ0KYGBgDQoNCmBgYHtyIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGluY2x1ZGU9RkFMU0V9DQpKYW4gPC0gcmVhZF9jc3YoIkphbi5jc3YiKQ0KRmViIDwtIHJlYWRfY3N2KCJGZWIuY3N2IikNCk1hciA8LSByZWFkX2NzdigiTWFyLmNzdiIpDQpBcHIgPC0gcmVhZF9jc3YoIkFwci5jc3YiKQ0KTWF5IDwtIHJlYWRfY3N2KCJNYXkuY3N2IikNCkp1biA8LSByZWFkX2NzdigiSnVuLmNzdiIpDQpKdWwgPC0gcmVhZF9jc3YoIkp1bC5jc3YiKQ0KQXVnIDwtIHJlYWRfY3N2KCJBdWcuY3N2IikNClNlcCA8LSByZWFkX2NzdigiU2VwLmNzdiIpDQpPY3QgPC0gcmVhZF9jc3YoIk9jdC5jc3YiKQ0KTm92IDwtIHJlYWRfY3N2KCJOb3YuY3N2IikNCkRlYyA8LSByZWFkX2NzdigiRGVjLmNzdiIpDQpgYGANCg0KYGBge3IgZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0NCmFsbF8yMDE5IDwtIHJiaW5kKEphbiwgRmViLCBNYXIsIEFwciwgTWF5LCBKdW4sIEp1bCwgQXVnLCBTZXAsIE9jdCwgTm92LCBEZWMpDQpzYXZlUkRTKGFsbF8yMDE5LCAiYWxsXzIwMTkuUmRzIikNCmBgYA0KDQoNCmBgYHtyfQ0KYWxsXzIwMTkgPC0gcmVhZF9yZHMoImFsbF8yMDE5LlJkcyIpDQpgYGANCg0KDQpgYGB7cn0NCmRmIDwtIGFsbF8yMDE5DQpjaXR5IDwtIHN0cnNwbGl0KGRmJE9SSUdJTl9DSVRZX05BTUUsICIsIikNCm1hdCA8LSBtYXRyaXgodW5saXN0KGNpdHkpLCBuY29sPTIsIGJ5cm93PVRSVUUpDQpjaXR5IDwtIGFzLmRhdGEuZnJhbWUobWF0KQ0KZGYkT1JJR0lOX0NJVFlfTkFNRSAgPC0gY2l0eSRWMQ0KDQpuYW1lcyhkZilbMTJdIDwtICJjaXR5Ig0KbmFtZXMoZGYpWzEzXSA8LSAnc3RhdGVfbmFtZScNCm5hbWVzKGRmKVs4XSA8LSAiSUFUQV9DT0RFIg0KZGYkY2l0eSA8LSBhcy5jaGFyYWN0ZXIoZGYkY2l0eSkNCmRmJHN0YXRlX25hbWUgPC0gYXMuY2hhcmFjdGVyKGRmJHN0YXRlX25hbWUpDQpkZiRJQVRBX0NPREUgPC0gYXMuY2hhcmFjdGVyKGRmJElBVEFfQ09ERSkNCmBgYA0KDQpgYGB7ciBtZXNzYWdlID0gRkFMU0V9DQpsb25fbGF0IDwtIHJlYWRfY3N2KCJkYXRhL3VzY2l0aWVzLmNzdiIpDQpsb25fbGF0IDwtIGxvbl9sYXQgJT4lDQogIGRwbHlyOjpzZWxlY3QoY2l0eSxzdGF0ZV9uYW1lLGxhdCxsbmcscG9wdWxhdGlvbikNCg0KYWlybGluZXMgPC0gcmVhZC5jc3YoImRhdGEvYWlybGluZXMuY3N2IikNCmFpcmxpbmVzJElBVEFfQ09ERSA8LSBhcy5jaGFyYWN0ZXIoYWlybGluZXMkSUFUQV9DT0RFKQ0KbG9uX2xhdCRjaXR5IDwtIGFzLmNoYXJhY3Rlcihsb25fbGF0JGNpdHkpDQpsb25fbGF0JHN0YXRlX25hbWUgPC0gYXMuY2hhcmFjdGVyKGxvbl9sYXQkc3RhdGVfbmFtZSkNCg0KZGYxIDwtIGxlZnRfam9pbihkZiwgbG9uX2xhdCwgYnkgPSBjKCdjaXR5Jz0nY2l0eScsICdzdGF0ZV9uYW1lJz0nc3RhdGVfbmFtZScpKQ0KZGYyIDwtIGxlZnRfam9pbihkZjEsIGFpcmxpbmVzKQ0KDQphaXJwb3J0IDwtIHJlYWQuY3N2KCJkYXRhL0xfQUlSUE9SVF9JRC5jc3YiKQ0KbmFtZXMoYWlycG9ydClbMV0gPSAiT1JJR0lOX0FJUlBPUlRfSUQiDQpkZjIgPC0gbGVmdF9qb2luKGRmMiwgYWlycG9ydCkNCmBgYA0KDQpgYGB7cn0NCmFsbF8yMDE5IDwtIGFsbF8yMDE5ICU+JSBtdXRhdGUoVE9UX0RFTEFZID0gREVQX0RFTEFZICsgQVJSX0RFTEFZKQ0KDQphbGxfMjAxOSRhbF9uYW1lIDwtIGFsbF8yMDE5JE9QX0NBUlJJRVINCg0KYWxsXzIwMTkkYWxfbmFtZSA8LSByZWNvZGUoYWxsXzIwMTkkYWxfbmFtZSwgIkFTIiA9ICJBbGFza2EgQWlybGluZXMiLCAiRzQiID0gIkFsbGVnaWFudCBBaXIiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIkFBIiA9ICJBbWVyaWNhbiBBaXJsaW5lcyIsICJETCIgPSAiRGVsdGEgQWlyIExpbmVzIiwgIkY5IiA9ICJGcm9udGllciBBaXJsaW5lcyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAiSEEiID0gIkhhd2FpaWFuIEFpcmxpbmVzIiwgIkI2IiA9ICJKZXRCbHVlIEFpcndheXMiLCAiV04iID0gIlNvdXRod2VzdCBBaXJsaW5lcyIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIk5LIiA9ICJTcGlyaXQgQWlybGluZXMiLCAiVUEiID0gIlVuaXRlZCBBaXJsaW5lcyIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgLmRlZmF1bHQgPSAiT3RoZXIiLCAubWlzc2luZyA9ICJPdGhlciIpDQoNCmFsbF8yMDE5JGxjX2FpcmxpbmVzIDwtIGZjdF9jb2xsYXBzZShhbGxfMjAxOSRPUF9DQVJSSUVSLCAiQnVkZ2V0IEFpcmxpbmVzIiA9IGMoIk5LIiwgIkY5IiwgIldOIiwgIkI2IiwgIkc0IiksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJPdGhlciBNYWpvciBBaXJsaW5lcyIgPSBjKCJBUyIsICJBQSIsICJETCIsICJIQSIsICJVQSIpKQ0KYWxsXzIwMTkkbGNfYWlybGluZXMgPC0gYXMudmVjdG9yKGFsbF8yMDE5JGxjX2FpcmxpbmVzKQ0KDQphbGxfMjAxOSRsY19haXJsaW5lcyA8LSByZWNvZGUoYWxsXzIwMTkkbGNfYWlybGluZXMsICJCdWRnZXQgQWlybGluZXMiID0gIkJ1ZGdldCBBaXJsaW5lcyIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJPdGhlciBNYWpvciBBaXJsaW5lcyIgPSAiT3RoZXIgTWFqb3IgQWlybGluZXMiLCAuZGVmYXVsdCA9ICJPdGhlciBzbWFsbGVyIGFpcmxpbmVzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAubWlzc2luZyA9ICJPdGhlciBzbWFsbGVyIGFpcmxpbmVzIikNCg0KDQpgYGANCg0KYGBge3J9DQpzdW1tYXJ5X2J5X2FsIDwtIGFsbF8yMDE5ICU+JSBncm91cF9ieShsY19haXJsaW5lcywgYWxfbmFtZSkgJT4lIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3VtbWFyaXNlKEFSUl9ERUxBWSA9IHJvdW5kKG1lYW4oQVJSX0RFTEFZLCBuYS5ybSA9IFRSVUUpLCAxKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBERVBfREVMQVkgPSByb3VuZChtZWFuKERFUF9ERUxBWSwgbmEucm0gPSBUUlVFKSwgMSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUT1RfREVMQVkgPSBBUlJfREVMQVkgKyBERVBfREVMQVkpDQpgYGANCg0KIyBWaXN1YWxpemF0aW9ucyB7LnRhYnNldCAudGFic2V0LWZhZGUgLnRhYnNldC1waWxsc30NCg0KIyMgMS4gT3ZlcnZpZXcgb2YgVS5TLiBEb21lc3RpYyBGbGlnaHQgRGVsYXlzIHsudGFic2V0IC50YWJzZXQtZmFkZSAudGFic2V0LXBpbGxzfQ0KDQojIyMgYSkgRGVsYXkgYW5kIGFpciB0cmFmZmljIHZvbHVtZSBieSBVLlMuIHN0YXRlcyBhbmQgY2l0aWVzDQoNCldlIGZpcnN0IHByb2Nlc3MgdGhlIGRhdGEgYW5kIGdldCBhbGwgdGhlIGFpcnBvcnRzIGZsaWdodHMgZGVsYXkgaW5mb3JtYXRpb24gKGRlcGFydHVyZSBkZWxheSBhbmQgYXJyaXZhbCBkZWxheSkgZnJvbSBlYWNoIG9mIHRoZSBVUyBjaXRpZXMuIEZyb20gdGhlIHN0YXRlIG9mIEFsYWJhbWEgdG8gV3lvbWluZy4gDQpgYGB7cn0NCmxpYnJhcnkoRFQpDQoNCnN1bW1hcnlfMjAxOSA8LSBhbGxfMjAxOSAlPiUgZ3JvdXBfYnkoU3RhdGUgPSBPUklHSU5fU1RBVEVfTk0sIENpdHkgPSBPUklHSU5fQ0lUWV9OQU1FKSAlPiUgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRwbHlyOjpzdW1tYXJpc2UoIkRlcGFydHVyZSBEZWxheSIgPSByb3VuZChtZWFuKERFUF9ERUxBWSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hLnJtID0gVFJVRSksIDEpLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkFycml2YWwgRGVsYXkiID0gcm91bmQobWVhbihBUlJfREVMQVksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmEucm0gPSBUUlVFKSwgMSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkZsaWdodCBWb2x1bW5lIChpbiBUaG91c2FuZHMpIiA9IHJvdW5kKG4oKSAvIDEwMDApLCAxKQ0KDQpzdW1tYXJ5XzIwMTkgJT4lIGRhdGF0YWJsZShyb3duYW1lcyA9IEZBTFNFLCBmaWx0ZXIgPSBsaXN0KHBvc2l0aW9uID0gInRvcCIpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBvcHRpb25zID0gbGlzdChsYW5ndWFnZSA9IGxpc3Qoc1NlYXJjaCA9ICJGaWx0ZXI6IikpKSAlPiUNCiAgZm9ybWF0U3R5bGUoY29sdW1ucyA9IDE6NSwgY29sb3IgPSAnYmxhY2snKQ0KYGBgDQoNCiMjIyBiKSBVLlMuIERlbGF5IE1hcCBieSBTdGF0ZXMNCg0KV2UgdXNlIGNob3JvcGxldGggbWFwcyB0byBzZWUgaG93IHRoZSBkZWxheXMgYXJlIGRpc3RyaWJ1dGVkLiBBcyBpdCBzaG93cyBmcm9tIHRoZSBncmFwaCwgbm9ydGhlcm4gc3RhdGVzIGxpa2UgTm9ydGggRGFrb3RhIGFuZCBTb3V0aCBEYWtvdGEgaGF2ZSBsb25nZXIgZGVsYXlzLiBTb21lIE5ldyBFbmdsYW5kIHN0YXRlcyBhbHNvIGhhdmUgbG9uZ2VyIGRlbGF5cy4gV2Ugd2VyZSB0aGlua2luZyB0aGF0IHRoZSByZWFzb24gY291bGQgYmUgY29sZCB3ZWF0aGVyLg0KDQpgYGB7ciBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRX0NCmxpYnJhcnkocmdkYWwpDQpsaWJyYXJ5KHJhc3RlcikNCiNVU19TSFAgPC0gcmVhZE9HUihkc24gPSAiQzovVXNlcnMvWXVodWFfRGluZy9PbmVEcml2ZS9Eb2N1bWVudHMvUU1TUyBTcHJpbmcgMjAyMC9HUjUwNjMgRGF0YSBWaXN1YWxpemF0aW9uL0ZpbmFsX3Byb2plY3QiLCBsYXllciA9ICJjYl8yMDE4X3VzX3N0YXRlXzUwMGsiKQ0KDQoNClVTX1NIUCA8LSBzaGFwZWZpbGUoIkM6L1VzZXJzL1l1aHVhX0RpbmcvT25lRHJpdmUvRG9jdW1lbnRzL1FNU1MgU3ByaW5nIDIwMjAvR1I1MDYzIERhdGEgVmlzdWFsaXphdGlvbi9GaW5hbF9wcm9qZWN0L3NocGZpbGUvY2JfMjAxOF91c19zdGF0ZV81MDBrLnNocCIpDQpVU19zcCA8LSBzcFRyYW5zZm9ybShVU19TSFAsIENSUygiK2luaXQ9ZXBzZzo0MzI2IikpDQpgYGANCg0KYGBge3J9DQpCeV9zdGF0ZSA8LSBhbGxfMjAxOSAlPiUgZ3JvdXBfYnkoT1JJR0lOX1NUQVRFX05NKSAlPiUgDQogICAgICAgICAgICAgICAgICAgICAgICAgc3VtbWFyaXNlKFRPVF9ERUxBWSA9IHJvdW5kKG1lYW4oVE9UX0RFTEFZLCBuYS5ybSA9IFRSVUUpLCAwKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRkxfQ09VTlQgPSBuKCkpDQoNClVTX3NwQGRhdGEgPC0gVVNfc3BAZGF0YSAlPiUgbGVmdF9qb2luKEJ5X3N0YXRlLCBieSA9IGMoIk5BTUUiID0gIk9SSUdJTl9TVEFURV9OTSIpKQ0KYGBgDQoNCg0KYGBge3J9DQpMYWJlbF9Db250ZW50IDwtIHBhc3RlKCJTdGF0ZSBOYW1lOiIsIFVTX3NwQGRhdGEkTkFNRSwgIjxici8+IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJBdmVyYWdlIERlbGF5IFRpbWUgKE1pbnV0ZXMpOiIsIFVTX3NwQGRhdGEkVE9UX0RFTEFZLCAiPGJyLz4iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIkZsaWdodCBDb3VudCAoVGhvdXNhbmRzKToiLCByb3VuZChVU19zcEBkYXRhJEZMX0NPVU5UIC8gMTAwMCwgMikpDQoNCmJpbnMgPC0gYygtSW5mLCAxMCwgMTUsIDIwLCAyNSwgSW5mKQ0KcGFsMyA8LSBjb2xvckJpbigiWWxPclJkIiwgZG9tYWluID0gVVNfc3BAZGF0YSRUT1RfREVMQVksIGJpbnMgPSBiaW5zLCBuYS5jb2xvciA9ICJ0cmFuc3BhcmVudCIpDQoNCm00IDwtIGxlYWZsZXQoZGF0YSA9IFVTX3NwLCBvcHRpb25zID0gbGVhZmxldE9wdGlvbnMobWluWm9vbSA9IDQsIG1heFpvb20gPSA3KSkgJT4lIA0KICAgICAgICAgICAgICAgICAgICAgICAgICBzZXRWaWV3KGxuZyA9IC05Ni4yMCwgbGF0ID0gMzkuNTAsIHpvb20gPSA0KSAlPiUgDQogICAgICAgICAgICAgICAgICAgICAgICAgIGFkZFByb3ZpZGVyVGlsZXMocHJvdmlkZXJzJENhcnRvREIuUG9zaXRyb24pICU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgICBhZGRQb2x5Z29ucyhzdHJva2UgPSBUUlVFLCBzbW9vdGhGYWN0b3IgPSAwLjUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB3ZWlnaHQ9MSwgY29sb3I9JyMzMzMzMzMnLCBvcGFjaXR5PTEsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbENvbG9yID0gfnBhbDMoVE9UX0RFTEFZKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsT3BhY2l0eSA9IDEsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSB+c3RyaW5ncjo6c3RyX2MoTkFNRSwgIiAiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkF2ZXJhZ2UgRGVsYXk6ICIsICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9ybWF0QyhUT1RfREVMQVksIGJpZy5tYXJrID0gJywnLCBmb3JtYXQ9J2QnKSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbE9wdGlvbnMgPSBsYWJlbE9wdGlvbnMoZGlyZWN0aW9uID0gJ2F1dG8nKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhpZ2hsaWdodE9wdGlvbnMgPSBoaWdobGlnaHRPcHRpb25zKA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3I9JyM5YThlZTgnLCB3ZWlnaHQgPSAzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJpbmdUb0Zyb250ID0gVFJVRSwgc2VuZFRvQmFjayA9IFRSVUUpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcG9wdXAgPSBMYWJlbF9Db250ZW50KSAlPiUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgYWRkTGVnZW5kKHBhbCA9IHBhbDMsIHZhbHVlcyA9IH5UT1RfREVMQVksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3BhY2l0eSA9IDAuNzUsIHBvc2l0aW9uID0gImJvdHRvbWxlZnQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGUgPSAiQXZlcmFnZSBEZWxheSBUaW1lIEFuZCBBaXIgVHJhZmZpYyBWb2x1bWUgQnkgU3RhdGUiKQ0KDQptNA0KYGBgDQoNCiMjIyBjKSBUcmVlbWFwIG9mIGRlbGF5ZWQgZmxpZ2h0IGNvdW50LCBieSBVLlMuIHN0YXRlcw0KDQpUcmVlbWFwIHdhcyB1c2VkIHRvIGRpc3Rpbmd1aXNoIFVTIHN0YXRlc+KAmSBmbGlnaHRzIGRlbGF5IHNpdHVhdGlvbi4gVGhlIGxhcmdlciBhcmVhIGVhY2ggc3RhdGUgb2NjdXBpZXMsIHRoZSBtb3JlIGRlbGF5ZWQgZmxpZ2h0cyB0aGF0IHN0YXRlIGhhcy4NCmBgYHtyfQ0KZGVsYXllZF9jb3VudCA8LSBhbGxfMjAxOSAlPiUgZmlsdGVyKFRPVF9ERUxBWSA+IDApICU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXBfYnkoc3RhdGUgPSBPUklHSU5fU1RBVEVfTk0pICU+JSBkcGx5cjo6c3VtbWFyaXNlKGNvdW50ID0gbigpKQ0KDQpgYGANCg0KYGBge3J9DQp0cmVlMSA8LSB0cmVlbWFwKGRlbGF5ZWRfY291bnQsIGluZGV4ID0gInN0YXRlIiwgdlNpemUgPSAiY291bnQiLCB0eXBlID0gImluZGV4IiwgDQogICAgICAgIHBhbGV0dGUgPSAiUHVycGxlcyIsIHRpdGxlID0gIkNvdW50IG9mIERlbGF5ZWQgRmxpZ2h0cyBCeSBTdGF0ZSIpDQpgYGANCg0KDQojIyAyLiBEZWxheSBCeSBBaXJsaW5lcyB7LnRhYnNldCAudGFic2V0LWZhZGUgLnRhYnNldC1waWxsc30NCiMjIyBhKSBBaXJsaW5lIE1hcmtldCBTaGFyZQ0KDQpBIHNpbXBsZSBpbGx1c3RyYXRpb24gb2YgbWFya2V0IHNoYXJlIGJyZWFrZG93biBmb3IgY29tbWVyY2lhbCBhaXJsaW5lcy4gV2UgbWFkZSBhIGJhciBjaGFydCB0byBzaG93IGVhY2ggbWFqb3IgYWlybGluZXPigJkgbWFya2V0IHNoYXJlIChpbiBwZXJjZW50YWdlKS4gQnVkZ2V0IGFpcmxpbmVzIGxpa2UgU291dGh3ZXN0IEFpcmxpbmVzIG9jY3VweSBhcm91bmQgMjAlIG9mIHRoZSBhdmlhdGlvbiBtYXJrZXQgc2hhcmUgd2hpbGUgc21hbGwgcmVnaW9uYWwgYWlybGluZXMgbGlrZSBIYXdhaWlhbiBBaXJsaW5lcyBvbmx5IG9jY3VweSBsZXNzIHRoYW4gNSUgbWFya2V0IHNoYXJlIGluIHRvdGFsLg0KYGBge3Igd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0V9DQpwZXJjZW50IDwtZGYyJT4lDQogIGRwbHlyOjpzZWxlY3QoQUlSTElORSklPiUNCiAgZmlsdGVyKCFpcy5uYShBSVJMSU5FKSkgJT4lDQogIGNvdW50KEFJUkxJTkUpJT4lDQogIG11dGF0ZShjb3VudFQgPSBzdW0obikpJT4lDQogIG11dGF0ZShwZXI9cm91bmQobi9jb3VudFQsMikpJT4lDQogIGFycmFuZ2UoZGVzYyhwZXIpKQ0KDQptYXJrZXRfc2hhcmUgPC0gZ2dwbG90KGRhdGEgPSBwZXJjZW50LCBhZXMoeCA9IHJlb3JkZXIoQUlSTElORSxwZXIpLCB5PXBlcixmaWxsPUFJUkxJTkUpKStnZW9tX2NvbCgpK3hsYWIoJ0FpcmxpbmUnKSArIHlsYWIoJ1BlcmNlbnRhZ2UnKSsgDQogIGxhYnModGl0bGU9IkFpcmxpbmVzIE1hcmtldCBTaGFyZSIsIGNhcHRpb24gPSAiRGF0YSBzb3VyY2U6IEJ1cmVhdSBvZiBUcmFuc3BvcnRhdGlvbiIpKyB0aGVtZV9lY29ub21pc3QoKSArIHNjYWxlX2NvbG91cl9lY29ub21pc3QoKSsgY29vcmRfZmxpcCgpKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpKyB0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQodmp1c3Q9IC0yKSwgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHZqdXN0PSAzKSwgcGxvdC5jYXB0aW9uID0gZWxlbWVudF90ZXh0KHZqdXN0PSAtNSxoanVzdD0xLGZhY2U9Iml0YWxpYyIsc2l6ZSA9IDgpICkNCiAgDQptYXJrZXRfc2hhcmUNCmBgYA0KDQojIyMgYikgQWlybGluZSBNZWFuIERlbGF5IFRpbWUNCg0KQmVmb3JlIHdlIGRyYXcgdGhlIEFpcmxpbmXigJlzIG1haW4gZGVsYXkgdGltZSBjaGFydCwgd2Ugc3VtbWFyaXNlZCB0aGUgYXZlcmFnZSB0b3RhbCBkZWxheSAoYXJyaXZhbCBkZWxheSBwbHVzIGRlcGFydHVyZSBkZWxheSkgb2YgdGhlIG1ham9yIGFpcmxpbmVzLiBBbW9uZyB0aGUgMTIgYWlybGluZXMsIEpldGJsdWUgYW5kIEF0bGFudGljIFNvdXRoZWFzdCBhaXJsaW5lcyBoYXZlIHRoZSBsb25nZXN0IG1lYW4gZGVsYXkgdGltZSAob3ZlciAyMCBtaW5zKSB3aGlsZSBIYXdhaWlhbiBBaXJsaW5lcyBoYXMgdGhlIG1lYW4gZGVsYXkgdGltZSBvZiA2IG1pbnV0ZXMuIEEgYmFycGxvdCB3YXMgdXNlZCB0byB2aXN1YWxpemUgdGhlIHJlc3VsdC4gDQpgYGB7ciB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRX0NCnN1bSA8LSBkZjIlPiUNCiAgZHBseXI6OnNlbGVjdChBSVJMSU5FLEFSUl9ERUxBWV9ORVcpJT4lDQogIGZpbHRlcighaXMubmEoQVJSX0RFTEFZX05FVyksICFpcy5uYShBSVJMSU5FKSklPiUNCiAgZ3JvdXBfYnkoQUlSTElORSklPiUNCiAgc3VtbWFyaXNlKG1lYW49cm91bmQobWVhbihBUlJfREVMQVlfTkVXKSksIG1heCA9IHJvdW5kKG1heChBUlJfREVMQVlfTkVXKSksIG1pbj0gcm91bmQobWluKEFSUl9ERUxBWV9ORVcpKSklPiUNCiAgYXJyYW5nZShkZXNjKG1lYW4pKQ0KYGBgDQoNCmBgYHtyfQ0KbWVhbl9kZWxheSA8LSBnZ3Bsb3QoZGF0YSA9IHN1bSwgYWVzKHggPSByZW9yZGVyKEFJUkxJTkUsbWVhbiksIHk9bWVhbixmaWxsPUFJUkxJTkUpKStnZW9tX2NvbCgpK3hsYWIoJ0FpcmxpbmUnKSArIHlsYWIoJ0RlbGF5IExlbmd0aCcpKyBsYWJzKHRpdGxlPSJBaXJsaW5lcyBNZWFuIERlbGF5IFRpbWUiLCBjYXB0aW9uID0gIkRhdGEgc291cmNlOiBCdXJlYXUgb2YgVHJhbnNwb3J0YXRpb24iKSsgdGhlbWVfZWNvbm9taXN0KCkgKyBzY2FsZV9jb2xvdXJfZWNvbm9taXN0KCkrIGNvb3JkX2ZsaXAoKSsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSsgdGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHZqdXN0PSAtMiksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dCh2anVzdD0gMyksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwbG90LmNhcHRpb24gPSBlbGVtZW50X3RleHQodmp1c3Q9IC01LGhqdXN0PTEsZmFjZT0iaXRhbGljIixzaXplID0gOCkgKQ0KDQptZWFuX2RlbGF5DQpgYGANCg0KDQojIyMgYykgRGVwYXJ0dXJlIGFuZCBhcnJpdmFsIGRlbGF5IGZvciBsb3ctY29zdCBhaXJsaW5lcyB2ZXJzdXMgb3RoZXJzLiAgDQoNCldlIHdhbnRlZCB0byB1c2Ugb25lIGNoYXJ0IHRvIHNob3cgZWFjaCBhaXJsaW5l4oCZcyBkZXBhcnR1cmUgYW5kIGFycml2YWwgZGVsYXlzLiBGcm9tIHRoZSBwbG90LCB3ZSBjYW4gdGVsbCB0aGF0IEhhd2FpaWFuIGFpcmxpbmVzIGhhcyB0aGUgc2hvcnRlc3QgZGVwYXJ0dXJlIGRlbGF5IGFuZCBhcnJpdmFsIGRlbGF5LiBKZXRibHVlIEFpcndheXMgaGFzIHRoZSBsb25nZXN0IGRlcGFydHVyZSBhbmQgYXJyaXZhbCBkZWxheXMgKGFsbCBpbiBtaW51dGVzKS4gQWZ0ZXIgd2UgZmluaXNoZWQgZHJhd2luZyB0aGUgcGxvdCwgd2UgYWxzbyB3b3VsZCBsaWtlIHRvIHNlZSBpZiBidWRnZXQgYWlybGluZXMgYW5kIG90aGVyIG1ham9yIGFpcmxpbmVzIGhhdmUgZGlmZmVyZW50IGRlcGFydHVyZSBhbmQgZGVsYXkgdGltZS4gQnkgbWFraW5nIHRoZSBjYWxjdWxhdGlvbiwgd2UgZm91bmQgb3V0IHRoYXQgYnVkZ2V0IGFpcmxpbmVzIGhhdmUgdGhlIG1lYW4gZGVwYXJ0dXJlIGRlbGF5IG9mIDEzLjEgbWlucyBhbmQgZGVwYXJ0dXJlIGRlbGF5IG9mIDcuNiBtaW5zLiBBdCB0aGUgc2FtZSB0aW1lLCBvdGhlciBtYWpvciBhaXJsaW5lcyBoYXZlIHRoZSBtZWFuIGRlcGFydHVyZSBkZWxheSBvZiA4LjIgbWlucyBhbmQgYXJyaXZhbCBkZWxheXMgb2YgNC4wIG1pbnMuIFRoZSBweXJhbWlkIGNoYXJ0IGFsc28gc2hvd3MgdXMgdGhhdCBidWRnZXQgYWlybGluZXMgdXN1YWxseSBoYXZlIHdvcnNlIGRlbGF5cyB0aGFuIG90aGVycyAoSmV0Qmx1ZeKAmXMgZGVsYXkgaXMgbm90b3Jpb3VzbHkgbG9uZ2VyLCBhcyBpbGx1c3RyYXRlZCkNCmBgYHtyfQ0Kc3VtbWFyeV9ieV9hbF92b2x1bWUgPC0gYWxsXzIwMTkgJT4lIGZpbHRlcihhbF9uYW1lICE9ICJPdGhlciIpICU+JSANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cF9ieShsY19haXJsaW5lcywgYWxfbmFtZSkgJT4lIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1bW1hcmlzZShUT1RfREVMQVkgPSByb3VuZChtZWFuKEFSUl9ERUxBWSArIERFUF9ERUxBWSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmEucm0gPSBUUlVFKSwgMSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVm9sdW1lID0gbigpKQ0KYGBgDQoNCmBgYHtyfQ0Kc3VtbWFyeV9ieV9hbCA8LSBzdW1tYXJ5X2J5X2FsICU+JSBmaWx0ZXIobGNfYWlybGluZXMgIT0gIk90aGVyIHNtYWxsZXIgYWlybGluZXMiKQ0KDQpwMiA8LSBnZ3Bsb3QoZGF0YSA9IHN1bW1hcnlfYnlfYWwsIGFlcyh4ID0gcmVvcmRlcihhbF9uYW1lLCBUT1RfREVMQVkpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBERVBfREVMQVksIGZpbGwgPSBsY19haXJsaW5lcykpICsgDQogICAgICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKyANCiAgICAgIGdlb21fdGV4dChsYWJlbCA9IHN1bW1hcnlfYnlfYWwkREVQX0RFTEFZLCBzaXplID0gMywgaGp1c3QgPSAwLjQpICsNCiAgICAgIGNvb3JkX2ZsaXAoKSArIA0KICAgICAgdGhlbWVfZWNvbm9taXN0KCkgKw0KICAgICAgbGFicyh4ID0gIiIsIHkgPSAiRGVwYXJ0dXJlIGRlbGF5IChtaW51dGVzKSIpICsNCiAgICAgIHNjYWxlX2ZpbGxfZGlzY3JldGUobmFtZSA9ICIiKSArIHNjYWxlX3lfcmV2ZXJzZSgpDQoNCg0KcDMgPC0gZ2dwbG90KGRhdGEgPSBzdW1tYXJ5X2J5X2FsLCBhZXMoeCA9IHJlb3JkZXIoYWxfbmFtZSwgVE9UX0RFTEFZKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gQVJSX0RFTEFZLCBmaWxsID0gbGNfYWlybGluZXMpKSArIA0KICAgICAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsgDQogICAgICBnZW9tX3RleHQobGFiZWwgPSBzdW1tYXJ5X2J5X2FsJEFSUl9ERUxBWSwgc2l6ZSA9IDMpICsNCiAgICAgIGNvb3JkX2ZsaXAoKSArIA0KICAgICAgdGhlbWVfZWNvbm9taXN0KCkgKw0KICAgICAgbGFicyh4ID0gIiIsIHkgPSAiQXJyaXZhbCBkZWxheSAobWludXRlcykiKSArDQogICAgICBzY2FsZV9maWxsX2Rpc2NyZXRlKG5hbWUgPSAiIikNCg0KcDQgPC0gZ2dhcnJhbmdlKHAyLCBwMywgbmNvbCA9IDIsIGNvbW1vbi5sZWdlbmQgPSBUUlVFKQ0KDQpwNA0KYGBgDQojIyMgZCkgRG8gbGFyZ2VyIGFpcmxpbmVzIGhhdmUgbG9uZ2VyIGRlbGF5cz8NCg0KT3ZlcmFsbCwgYnVkZ2V0IGFpcmxpbmVzIGhhdmUgbG9uZ2VyIGRlbGF5cywgYnV0IHRoZSBkZWxheSB0aW1lIGRlY3JlYXNlcyBhcyB0aGUgY29tcGFueSBzaXplIGluY3JlYXNlcy4gRm9yIG90aGVyIGxhcmdlIHRyYWRpdGlvbmFsIGFpcmxpbmVzLCBsYXJnZXIgc2l6ZSByZXN1bHRlZCBpbiBsb25nZXIgZGVsYXlzIChtYXliZSBkdWUgdG8gb3BlcmF0aW9uYWwgZGVmaWNpZW5jeSkNCmBgYHtyIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFfQ0KcDUgPC0gZ2dwbG90KGRhdGEgPSBzdW1tYXJ5X2J5X2FsX3ZvbHVtZSwgYWVzKHggPSBsb2coVm9sdW1lKSwgeSA9IFRPVF9ERUxBWSkpICsgDQogICAgICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IGxjX2FpcmxpbmVzLCBzaXplID0gbG9nKFZvbHVtZSkpKSArIA0KICAgICAgZ2VvbV90ZXh0X3JlcGVsKGxhYmVsID0gc3VtbWFyeV9ieV9hbF92b2x1bWUkYWxfbmFtZSkgKyANCiAgICAgIGdlb21fc21vb3RoKGFlcyhjb2xvciA9IGxjX2FpcmxpbmVzKSwgbWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSwgYWxwaGEgPSAwLjEpICsgDQogICAgICB0aGVtZV9lY29ub21pc3QoKSArIA0KICAgICAgbGFicyh5ID0gIlRvdGFsIGRlbGF5IChtaW51dGVzKSIsIHggPSAiTnVtYmVyIG9mIGZsaWdodHMgaW4gMjAxOSwgaW4gbmF0dXJhbCBsb2cgZm9ybSIsIA0KICAgICAgICB0aXRsZSA9ICJEbyBsYXJnZXIgYWlybGluZXMgaGF2ZSBsb25nZXIgZGVsYXlzPyIpICsgDQogICAgICBzY2FsZV9jb2xvcl9kaXNjcmV0ZShuYW1lID0gIiIpICsNCiAgICAgIHNjYWxlX3NpemUoZ3VpZGUgPSAnbm9uZScpDQoNCnA1DQpgYGANCg0KIyMgMy4gRGVsYXkgQnkgVGltZSB7LnRhYnNldCAudGFic2V0LWZhZGUgLnRhYnNldC1waWxsc30NCiMjIyBhKSBEZWxheSBtYXAgYnkgcXVhcnRlcnMgb2YgMjAxOQ0KDQpUaGUgZmxpZ2h0IG1hcCBpcyBkZXNpZ25lZCB0byBzaG93IHVzIHdoaWNoIGFyZWEgaGFzIHRoZSBsb25nZXN0IGF2ZXJhZ2UgZGVsYXkgdGltZSBpbiB0aGUgVVNBLiBJZiB0aGUgY29sb3IgYXJvdW5kIHRoZSBhcmVhIGlzIGxpZ2h0IHBpbmssIHRoZW4gdGhlIGF2ZXJhZ2UgZGVsYXkgdGltZSB3aWxsIGJlIDAtMTUgbWlucy4gSG93ZXZlciwgaWYgdGhlIGNvbG9yIGlzIGRhcmsgcmVkLCB0aGVuIHRoZSBkZWxheSB0aW1lIGlzIGFib3ZlIDQ1IG1pbnMuIFRoZSBzaXplIG9mIHRoZSBjaXJjbGUgcmVwcmVzZW50cyB0aGUgYWlyIHRyYWZmaWMgdm9sdW1lIGluIHRoYXQgYXJlYS4gVGhlIG1hcCBzaG93cyB0aGF0IGRlbGF5IGlzIG5vdCBuZWNlc3NhcmlseSByZWxhdGVkIHRvIHRoZSBsYXJnZSB0cmFmZmljIHZvbHVtZS4gSW4gdGhlIGZpcnN0IHF1YXJ0ZXIsIHRoZSBjaXRpZXMgaW4gdGhlIG5vcnRoIGxpa2UgTWljaGlnYW4gb3ZlcmFsbCBoYWQgbXVjaCB3b3JzZSBkZWxheXMuIEhvd2V2ZXIsIHRoZSBzaXR1YXRpb24gY2hhbmdlZCBpbiB0aGUgc2Vjb25kIHF1YXJ0ZXIuIEluIHRoZSBzZWNvbmQgcXVhcnRlciwgdGhlIGNpdGllcyBpbiB0aGUgc291dGggbGlrZSBNaWFtaSBvdmVyYWxsIGhhZCBtdWNoIHdvcnNlIGRlbGF5cy4gSXQgbWFrZXMgc2Vuc2UgYmVjYXVzZSBzdW1tZXIgaXMgdGhlIHNlYXNvbiBmb3IgZXh0cmVtZSB3ZWF0aGVycyBsaWtlIHRodW5kZXJzdG9ybXMuIA0KYGBge3IgZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0NCmNpdGllcyA8LSBhbGxfMjAxOSAlPiUgZGlzdGluY3QoT1JJR0lOX0NJVFlfTkFNRSkNCg0KY2l0aWVzJGxvbiA8LSBOQQ0KY2l0aWVzJGxhdCA8LSBOQQ0KDQpmb3IoaSBpbiAxOm5yb3coY2l0aWVzKSkgew0KICBjb29yZCA8LSBnZW9jb2RlKGNpdGllcyRPUklHSU5fQ0lUWV9OQU1FW2ldKQ0KICBjaXRpZXMkbG9uW2ldIDwtIGNvb3JkJGxvbg0KICBjaXRpZXMkbGF0W2ldIDwtIGNvb3JkJGxhdA0KfQ0KDQpzYXZlUkRTKGNpdGllcywgImNpdGllcy5SZHMiKQ0KYGBgDQoNCmBgYHtyfQ0KY2l0aWVzIDwtIHJlYWRSRFMoImNpdGllcy5SZHMiKQ0KY2l0aWVzIDwtIGNpdGllcyAlPiUgcmVuYW1lKENpdHlfbmFtZSA9ICJPUklHSU5fQ0lUWV9OQU1FIikNCmBgYA0KDQpgYGB7ciBtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRX0NCmNpdHlfZGVsYXlzIDwtIGFsbF8yMDE5ICU+JSBncm91cF9ieShRVUFSVEVSLCBPUklHSU5fQ0lUWV9OQU1FKSAlPiUgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgc3VtbWFyaXNlKFRPVF9ERUxBWSA9IHJvdW5kKG1lYW4oVE9UX0RFTEFZLCBuYS5ybSA9IFRSVUUpLCAwKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRkxfQ09VTlQgPSBuKCkpICU+JSANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZW5hbWUoQ2l0eV9uYW1lID0gT1JJR0lOX0NJVFlfTkFNRSkNCmNpdHlfZGVsYXlzIDwtIHJpZ2h0X2pvaW4oY2l0eV9kZWxheXMsIGNpdGllcywgYnkgPSAiQ2l0eV9uYW1lIikNCg0KDQpGWSA8LSBjaXR5X2RlbGF5cyAlPiUgZ3JvdXBfYnkoQ2l0eV9uYW1lLCBsb24sIGxhdCkgJT4lIHN1bW1hcmlzZShUT1RfREVMQVkgPSBtZWFuKFRPVF9ERUxBWSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGTF9DT1VOVCA9IHN1bShGTF9DT1VOVCkpDQpRMSA8LSBjaXR5X2RlbGF5cyAlPiUgZmlsdGVyKFFVQVJURVIgPT0gMSkNClEyIDwtIGNpdHlfZGVsYXlzICU+JSBmaWx0ZXIoUVVBUlRFUiA9PSAyKQ0KUTMgPC0gY2l0eV9kZWxheXMgJT4lIGZpbHRlcihRVUFSVEVSID09IDMpDQpRNCA8LSBjaXR5X2RlbGF5cyAlPiUgZmlsdGVyKFFVQVJURVIgPT0gNCkNCg0KDQpGWV9Db250ZW50IDwtIHBhc3RlKCJDaXR5IE5hbWU6IiwgRlkkQ2l0eV9uYW1lLCAiPGJyLz4iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIkF2ZXJhZ2UgRGVsYXkgVGltZSAoTWludXRlcyk6IiwgRlkkVE9UX0RFTEFZLCAiPGJyLz4iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRvdGFsIEZsaWdodCBDb3VudCAoaW4gVGhvdXNhbmRzKToiLCByb3VuZChGWSRGTF9DT1VOVCAvIDEwMDAsIDIpKQ0KUTFfQ29udGVudCA8LSBwYXN0ZSgiQ2l0eSBOYW1lOiIsIFExJENpdHlfbmFtZSwgIjxici8+IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJBdmVyYWdlIERlbGF5IFRpbWUgKE1pbnV0ZXMpOiIsIFExJFRPVF9ERUxBWSwgIjxici8+IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJUb3RhbCBGbGlnaHQgQ291bnQgKGluIFRob3VzYW5kcyk6Iiwgcm91bmQoUTEkRkxfQ09VTlQgLyAxMDAwLCAyKSkNClEyX0NvbnRlbnQgPC0gcGFzdGUoIkNpdHkgTmFtZToiLCBRMiRDaXR5X25hbWUsICI8YnIvPiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAiQXZlcmFnZSBEZWxheSBUaW1lIChNaW51dGVzKToiLCBRMiRUT1RfREVMQVksICI8YnIvPiIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAiVG90YWwgRmxpZ2h0IENvdW50IChpbiBUaG91c2FuZHMpOiIsIHJvdW5kKFEyJEZMX0NPVU5UIC8gMTAwMCwgMikpDQpRM19Db250ZW50IDwtIHBhc3RlKCJDaXR5IE5hbWU6IiwgUTMkQ2l0eV9uYW1lLCAiPGJyLz4iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIkF2ZXJhZ2UgRGVsYXkgVGltZSAoTWludXRlcyk6IiwgUTMkVE9UX0RFTEFZLCAiPGJyLz4iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRvdGFsIEZsaWdodCBDb3VudCAoaW4gVGhvdXNhbmRzKToiLCByb3VuZChRMyRGTF9DT1VOVCAvIDEwMDAsIDIpKQ0KUTRfQ29udGVudCA8LSBwYXN0ZSgiQ2l0eSBOYW1lOiIsIFE0JENpdHlfbmFtZSwgIjxici8+IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJBdmVyYWdlIERlbGF5IFRpbWUgKE1pbnV0ZXMpOiIsIFE0JFRPVF9ERUxBWSwgIjxici8+IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICJUb3RhbCBGbGlnaHQgQ291bnQgKGluIFRob3VzYW5kcyk6Iiwgcm91bmQoUTQkRkxfQ09VTlQgLyAxMDAwLCAyKSkNCg0KDQpiaW5zIDwtIGMoLUluZiwgMTUsIDMwLCA0NSwgSW5mKQ0KcGFsMSA8LSBjb2xvckJpbigiUmVkcyIsIGRvbWFpbiA9IGNpdHlfZGVsYXlzJFRPVF9ERUxBWSwgYmlucyA9IGJpbnMsIG5hLmNvbG9yID0gInRyYW5zcGFyZW50IikNCg0KbTEgPC0gbGVhZmxldChjaXR5X2RlbGF5cywgb3B0aW9ucyA9IGxlYWZsZXRPcHRpb25zKG1pblpvb20gPSA0LCBtYXhab29tID0gNykpICU+JSANCiAgICAgICAgc2V0VmlldyhsbmcgPSAtOTYuMjAsIGxhdCA9IDM5LjUwLCB6b29tID0gNCkgJT4lDQogICAgICAgIGFkZFByb3ZpZGVyVGlsZXMocHJvdmlkZXJzJENhcnRvREIuUG9zaXRyb24pICU+JQ0KICAgICAgICBhZGRDaXJjbGVzKGRhdGEgPSBGWSwgbG5nID0gfmxvbiwgbGF0ID0gfmxhdCwgcmFkaXVzID0gfiBGTF9DT1VOVCAvIDQsIA0KICAgICAgICAgICAgICAgICAgIGNvbG9yID0gfnBhbDEoVE9UX0RFTEFZKSwgb3BhY2l0eSA9IDAuOCwgcG9wdXAgPSBGWV9Db250ZW50LCBncm91cCA9ICJGWSIpICU+JQ0KICAgICAgICBhZGRDaXJjbGVzKGRhdGEgPSBRMSwgbG5nID0gfmxvbiwgbGF0ID0gfmxhdCwgcmFkaXVzID0gfiBGTF9DT1VOVCwgDQogICAgICAgICAgICAgICAgICAgY29sb3IgPSB+cGFsMShUT1RfREVMQVkpLCBvcGFjaXR5ID0gMC44LCBwb3B1cCA9IFExX0NvbnRlbnQsIGdyb3VwID0gIlExIikgJT4lDQogICAgICAgIGFkZENpcmNsZXMoZGF0YSA9IFEyLCBsbmcgPSB+bG9uLCBsYXQgPSB+bGF0LCByYWRpdXMgPSB+IEZMX0NPVU5ULCANCiAgICAgICAgICAgICAgICAgICBjb2xvciA9IH5wYWwxKFRPVF9ERUxBWSksIG9wYWNpdHkgPSAwLjgsIHBvcHVwID0gUTJfQ29udGVudCwgZ3JvdXAgPSAiUTIiKSAlPiUNCiAgICAgICAgYWRkQ2lyY2xlcyhkYXRhID0gUTMsIGxuZyA9IH5sb24sIGxhdCA9IH5sYXQsIHJhZGl1cyA9IH4gRkxfQ09VTlQsIA0KICAgICAgICAgICAgICAgICAgIGNvbG9yID0gfnBhbDEoVE9UX0RFTEFZKSwgb3BhY2l0eSA9IDAuOCwgcG9wdXAgPSBRM19Db250ZW50LCBncm91cCA9ICJRMyIpICU+JQ0KICAgICAgICBhZGRDaXJjbGVzKGRhdGEgPSBRNCwgbG5nID0gfmxvbiwgbGF0ID0gfmxhdCwgcmFkaXVzID0gfiBGTF9DT1VOVCwgDQogICAgICAgICAgICAgICAgICAgY29sb3IgPSB+cGFsMShUT1RfREVMQVkpLCBvcGFjaXR5ID0gMC44LCBwb3B1cCA9IFE0X0NvbnRlbnQsIGdyb3VwID0gIlE0IikgJT4lDQogICAgICAgIGFkZExlZ2VuZChwYWwgPSBwYWwxLCB2YWx1ZXMgPSB+VE9UX0RFTEFZLCBwb3NpdGlvbiA9ICJib3R0b21sZWZ0IiwgDQogICAgICAgICAgICAgICAgICB0aXRsZSA9ICJBdmVyYWdlIFRvdGFsIERlbGF5IChpbiBtaW51dGVzKSIsIA0KICAgICAgICAgICAgICAgICAgb3BhY2l0eSA9IDAuNzUpICU+JQ0KICAgICAgICBhZGRMYXllcnNDb250cm9sKGJhc2VHcm91cHMgPSBjKCJGWSIsICJRMSIsICJRMiIsICJRMyIsICJRNCIpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICBvcHRpb25zID0gbGF5ZXJzQ29udHJvbE9wdGlvbnMoY29sbGFwc2VkID0gVFJVRSkpDQoNCm0xDQpgYGANCg0KDQpgYGB7cn0NCndvcnN0X2RlbGF5cyA8LSBhbGxfMjAxOSAlPiUgZmlsdGVyKFRPVF9ERUxBWSA+PSAzNjApICU+JSANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KE1PTlRILCBEQVlfT0ZfV0VFSywgT1BfQ0FSUklFUiwgVE9UX0RFTEFZLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIENpdHlfbmFtZSA9IE9SSUdJTl9DSVRZX05BTUUpDQoNCndvcnN0X2RlbGF5cyA8LSByaWdodF9qb2luKHdvcnN0X2RlbGF5cywgY2l0aWVzLCBieSA9ICJDaXR5X25hbWUiKQ0KDQp3b3JzdF9kZWxheXMkREFZX09GX1dFRUsgPC0gcmVjb2RlKHdvcnN0X2RlbGF5cyREQVlfT0ZfV0VFSywgIjEiID0gIk1vbmRheSIsICIyIiA9ICJUdWVzZGF5IiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIzIiA9ICJXZWRuZXNkYXkiLCAiNCIgPSAiVGh1cnNkYXkiLCAiNSIgPSAiRnJpZGF5IiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICI2IiA9ICJTYXR1cmRheSIsICI3IiA9ICJTdW5kYXkiKQ0KYGBgDQoNCmBgYHtyfQ0KcmVkX2V5ZV9mbGlnaHRzIDwtIGFsbF8yMDE5ICU+JSBmaWx0ZXIoQ1JTX0RFUF9USU1FID49IDIxMDAgJiBDUlNfQVJSX1RJTUUgPD0gMDYwMCkNCm5vcm1hbF9mbGlnaHRzIDwtIGFsbF8yMDE5ICU+JSBmaWx0ZXIoREVQX1RJTUUgPCAyMTAwIHwgQVJSX1RJTUUgPiAwNjAwKQ0KDQpyZWRfZXllX2ZsaWdodHNfc3VtbSA8LSByZWRfZXllX2ZsaWdodHMgJT4lIGdyb3VwX2J5KENpdHlfbmFtZSA9IE9SSUdJTl9DSVRZX05BTUUpICU+JSANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3VtbWFyaXNlKFRPVF9ERUxBWSA9IHJvdW5kKG1lYW4oVE9UX0RFTEFZLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hLnJtID0gVFJVRSksIDApKSAlPiUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmlnaHRfam9pbihjaXRpZXMsIGJ5ID0gIkNpdHlfbmFtZSIpDQoNCm5vcm1hbF9mbGlnaHRzX3N1bW0gPC0gbm9ybWFsX2ZsaWdodHMgJT4lIGdyb3VwX2J5KENpdHlfbmFtZSA9IE9SSUdJTl9DSVRZX05BTUUpICU+JSANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3VtbWFyaXNlKFRPVF9ERUxBWSA9IHJvdW5kKG1lYW4oVE9UX0RFTEFZLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hLnJtID0gVFJVRSksIDApKSU+JQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByaWdodF9qb2luKGNpdGllcywgYnkgPSAiQ2l0eV9uYW1lIikNCmBgYA0KDQpgYGB7cn0NCiMjIGZ1bmN0aW9uIGJvcnJvd2VkIGZyb20gcGFja2FnZSBsZWFmbGV0Q04NCiMjJyBAdGl0bGUgQWRkIHRpdGxlIHRvIHRoZSBsZWFmbGV0DQojIycNCiMjJyBAZGVzY3JpcHRpb24gRnVuY3Rpb24gZm9yIGNyZWF0aW5nIGEgaDEgdGl0bGUgdG8gdGhlIGxlYWZsZXQNCg0KYWRkVGl0bGUgPSBmdW5jdGlvbihvYmplY3QsDQogICAgICAgICAgICAgICAgICAgIHRleHQsDQogICAgICAgICAgICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwNCiAgICAgICAgICAgICAgICAgICAgZm9udFNpemUgPSAiMjBweCIsDQogICAgICAgICAgICAgICAgICAgIGZvbnRGYW1pbHkgPSAiU2FucyIsDQogICAgICAgICAgICAgICAgICAgIGxlZnRQb3NpdGlvbiA9IDUwLA0KICAgICAgICAgICAgICAgICAgICB0b3BQb3NpdGlvbiA9IDIpew0KDQogIGh0bWx3aWRnZXRzOjpvblJlbmRlcihvYmplY3QsIHBhc3RlMCgiDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbihlbCx4KXsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGgxID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnaDEnKTsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGgxLmlubmVySFRNTCA9ICciLCB0ZXh0ICwiJzsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGgxLmlkPSd0aXRsZWgxJzsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGgxLnN0eWxlLmNvbG9yID0gJyIsIGNvbG9yICwiJzsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGgxLnN0eWxlLmZvbnRTaXplID0gJyIsZm9udFNpemUsIic7DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoMS5zdHlsZS5mb250RmFtaWx5PSciLGZvbnRGYW1pbHksIic7DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoMS5zdHlsZS5wb3NpdGlvbiA9ICdmaXhlZCc7DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoMS5zdHlsZVsnLXdlYmtpdC10cmFuc2Zvcm0nXT0ndHJhbnNsYXRlWCgtNTAlKSc7DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoMS5zdHlsZS5sZWZ0PSciLGxlZnRQb3NpdGlvbiAsIiUnOw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaDEuc3R5bGUudG9wPSciLHRvcFBvc2l0aW9uLCIlJzsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRvY3VtZW50LmJvZHkuYXBwZW5kQ2hpbGQoaDEpOw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSIpKQ0KfQ0KYGBgDQoNCiMjIyBiKSBBcmUgdGhlIHdvcnN0IGRlbGF5cyB1c3VhbGx5IGFzc29jaWF0ZWQgd2l0aCBSZWQgRXllIEZsaWdodHM/DQoNClJlZCBFeWUgZmxpZ2h0cyBhcmUgZGVmaW5lZCBhcyBmbGlnaHRzIHRoYXQgZGVwYXJ0cyBhZnRlciA5IHAubS4gYW5kIGFycml2ZXMgYmVmb3JlIDYgYS5tLiBJbiB0aGUgZm9sbG93aW5nIHR3byBtYXBzLCB0aGUg4oCcd29yc3QgZGVsYXlz4oCdIGFyZSBkZWZpbmVkIGFzIGRlbGF5cyB0aGF0IGFyZSBvdmVyIDYgaG91cnMsIHdoaWNoIGlzIHVzdWFsbHkgdGhlIGRlbGF5IHRpbWUgdG8gdHJpZ2dlciBkZWxheSBwcm90ZWN0aW9uLiBUaGUgY29tcGFyaXNvbiBiZWxvdyBwcm92aWRlcyBhIGZpbmUgaWxsdXN0cmF0aW9uIG9mIHRoZSB3b3JzdCBkZWxheXPigJkgZnJlcXVlbmN5IGJldHdlZW4gUmVkIEV5ZSBmbGlnaHRzIGFuZCBub3JtYWwgZmxpZ2h0cyAodGhlIHVwcGVyIG1hcCByZXByZXNlbnRzIFJlZCBFeWUgZmxpZ2h0cyB3aGVyZWFzIHRoZSBsb3dlciByZXByZXNlbnRzIHJlZ3VsYXJzKS4gRnJvbSB0aGUgdmlzdWFsaXphdGlvbiB3ZSBjYW4gZWFzaWx5IHRlbGwgUmVkIEV5ZSBmbGlnaHRzIGFyZSBjb21tb25seSBhc3NvY2lhdGVkIHdpdGggZGVsYXlzIHRoYXQgYXJlIG92ZXIgNiBob3VycyAoZ29vZCBsdWNrcyBpZiB5b3UgYXJlIHRyYXZlbGluZyBvbiB0aG9zZSBmbGlnaHRzKQ0KDQpgYGB7ciB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRX0NClJFRl9DT05URU5UIDwtIHBhc3RlKCJDaXR5IE5hbWU6IiwgcmVkX2V5ZV9mbGlnaHRzX3N1bW0kQ2l0eV9uYW1lLCAiPGJyLz4iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIkF2ZXJhZ2UgRGVsYXkgVGltZSAoTWludXRlcyk6IiwgcmVkX2V5ZV9mbGlnaHRzX3N1bW0kVE9UX0RFTEFZKQ0KTkZfQ09OVEVOVCA8LSBwYXN0ZSgiQ2l0eSBOYW1lOiIsIG5vcm1hbF9mbGlnaHRzX3N1bW0kQ2l0eV9uYW1lLCAiPGJyLz4iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIkF2ZXJhZ2UgRGVsYXkgVGltZSAoTWludXRlcyk6Iiwgbm9ybWFsX2ZsaWdodHNfc3VtbSRUT1RfREVMQVkpDQoNCg0KYmlucyA8LSBjKC1JbmYsIDE1LCAzMCwgNDUsIEluZikNCnBhbDIgPC0gY29sb3JCaW4oIlJlZHMiLCBkb21haW4gPSByZWRfZXllX2ZsaWdodHNfc3VtbSRUT1RfREVMQVksIGJpbnMgPSBiaW5zLCBuYS5jb2xvciA9ICJ0cmFuc3BhcmVudCIpDQoNCm0yIDwtIGxlYWZsZXQocmVkX2V5ZV9mbGlnaHRzX3N1bW0sIG9wdGlvbnMgPSBsZWFmbGV0T3B0aW9ucyhtaW5ab29tID0gNCwgbWF4Wm9vbSA9IDcpKSAlPiUgDQogICAgICAgIHNldFZpZXcobG5nID0gLTk2LjIwLCBsYXQgPSAzOS41MCwgem9vbSA9IDQpICU+JQ0KICAgICAgICBhZGRQcm92aWRlclRpbGVzKHByb3ZpZGVycyRDYXJ0b0RCLkRhcmtNYXR0ZXIpICU+JQ0KICAgICAgICBhZGRDaXJjbGVzKGxuZyA9IH5sb24sIGxhdCA9IH5sYXQsIHJhZGl1cyA9IH4gVE9UX0RFTEFZICogMzAwLCANCiAgICAgICAgICAgICAgICAgICBjb2xvciA9ICIjYWQxMTExIiwgb3BhY2l0eSA9IDAuOCwgcG9wdXAgPSBSRUZfQ09OVEVOVCkgJT4lDQogICAgICAgIGxlYWZlbQ0KDQoNCm0zIDwtIGxlYWZsZXQobm9ybWFsX2ZsaWdodHNfc3VtbSwgb3B0aW9ucyA9IGxlYWZsZXRPcHRpb25zKG1pblpvb20gPSA0LCBtYXhab29tID0gNykpICU+JSANCiAgICAgICAgc2V0VmlldyhsbmcgPSAtOTYuMjAsIGxhdCA9IDM5LjUwLCB6b29tID0gNCkgJT4lDQogICAgICAgIGFkZFByb3ZpZGVyVGlsZXMocHJvdmlkZXJzJENhcnRvREIuUG9zaXRyb24pICU+JQ0KICAgICAgICBhZGRDaXJjbGVzKGxuZyA9IH5sb24sIGxhdCA9IH5sYXQsIHJhZGl1cyA9IH4gVE9UX0RFTEFZICogMzAwLCANCiAgICAgICAgICAgICAgICAgICBjb2xvciA9ICIjZmE5ZGE0Iiwgb3BhY2l0eSA9IDAuOCwgcG9wdXAgPSBORl9DT05URU5UKQ0KDQpsYXR0aWNldmlldyhtMiwgbTMsIG5jb2wgPSAxLCBzeW5jLmN1cnNvciA9IFRSVUUsIG5vLmluaXRpYWwuc3luYyA9IEZBTFNFKQ0KYGBgDQoNCiMjIyBjKSBXb3JzdCBkZWxheXMgYnkgZGF5cyBvZiB3ZWVrDQoNCkl0IGlzIGludGVyZXN0aW5nIHRvIHNlZSB0aGF0IGZyb20gTW9uZGF5IHRvIFRodXJzZGF5LCBhbG1vc3QgYWxsIG9mIHRoZSB3b3JzdCBkZWxheXMgYXJlIGNvbmNlbnRyYXRlZCBpbiBOZXcgWW9yayBhbmQgQ2hpY2FnbyBtZXRyb3BvbGl0YW4gYXJlYXMuIEFuZCB3aGVuIEZyaWRheSBhbmQgd2Vla2VuZCBkYXlzIGNvbWUsIHRoZSB3b3JzdCBkZWxheXMgc3RhcnQgdG8gc3ByZWFkIHRvIG90aGVyIHBvcHVsYXIgZ2V0YXdheSBkZXN0aW5hdGlvbnMgKExBLCBGbG9yaWRhLCBOZXcgT3JsZWFucywgZS5nLikgIEl0IG1pZ2h0IGJlIGJlY2F1c2Ugb2YgdGhlIGFpciB0cmFmZmljIHZvbHVtZSBvZiB0aGUgYWlycG9ydHMuIEZyb20gTW9uZGF5IHRvIFRodXJzZGF5LCBwZW9wbGUgYXJlIG1vcmUgbGlrZWx5IHRvIHRyYXZlbCBmb3IgYnVzaW5lc3MuIFRodXMsIGxhcmdlIGNpdGllcyBmb3IgYnVzaW5lc3MgbGlrZSBOZXcgWW9yayBhbmQgQ2hpY2FnbyBoYXZlIG1vcmUgYWlyIHRyYWZmaWMgdm9sdW1lLiBIb3dldmVyLCAgZnJvbSBGcmlkYXkgdG8gU3VuZGF5LCBwZW9wbGUgYXJlIG1vcmUgbGlrZWx5IHRvIHRyYXZlbCBmb3IgdmFjYXRpb24uIFRodXMsIHRoZSBhaXIgdHJhZmZpYyBhbmQgZGVsYXlzIHNwcmVhZCB0byB0aGUgc291dGguDQpgYGB7cn0NCndvcnN0X2RlbGF5cyA8LSBhbGxfMjAxOSAlPiUgZmlsdGVyKFRPVF9ERUxBWSA+PSAzNjApICU+JSANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHBseXI6OnNlbGVjdChNT05USCwgREFZX09GX1dFRUssIE9QX0NBUlJJRVIsIFRPVF9ERUxBWSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBDaXR5X25hbWUgPSBPUklHSU5fQ0lUWV9OQU1FKSANCg0Kd29yc3RfZGVsYXlzIDwtIHJpZ2h0X2pvaW4od29yc3RfZGVsYXlzLCBjaXRpZXMsIGJ5ID0gIkNpdHlfbmFtZSIpDQoNCndvcnN0X2RlbGF5cyREQVlfT0ZfV0VFSyA8LSBmYWN0b3Iod29yc3RfZGVsYXlzJERBWV9PRl9XRUVLLCBsZXZlbHMgPSAxOjcsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJNb25kYXkiLCAiVHVlc2RheSIsICJXZWRuZXNkYXkiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJUaHVyc2RheSIsICJGcmlkYXkiLCAiU2F0dXJkYXkiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJTdW5kYXkiKSkNCg0Kd29yc3RfZGVsYXlzIDwtIHdvcnN0X2RlbGF5cyAlPiUgZmlsdGVyKCFpcy5uYShEQVlfT0ZfV0VFSykpDQpgYGANCg0KDQpgYGB7ciB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRX0NCm1hcF9VU0EgPC0gZ2V0X21hcChsb2NhdGlvbiA9IGMobG9uID0gLTk2LjIwLCBsYXQgPSAzOS41MCksIHpvb20gPSA0LCBzb3VyY2U9InN0YW1lbiIsIG1hcHR5cGU9InRvbmVyLWxpdGUiKQ0KDQptNSA8LSBnZ21hcChtYXBfVVNBKSArIHN0YXRfZGVuc2l0eTJkKGRhdGEgPSB3b3JzdF9kZWxheXMsIGFlcyh4ID0gbG9uLCB5ID0gbGF0LCBmaWxsID0gLi5sZXZlbC4uKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmlucyA9IDQsIGFscGhhID0gMC41LCBnZW9tID0gInBvbHlnb24iLCBzaXplID0gMC4wNQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApICsgDQogICAgICAgICAgICAgICAgIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksIA0KICAgICAgICAgICAgICAgICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgICAgICAgICAgICAgIGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKyANCiAgICAgICAgICAgICAgICAgZmFjZXRfd3JhcCh+REFZX09GX1dFRUssIG5jb2wgPSA0KQ0KbTUNCmBgYA0KDQojIyMgZCkgRGVsYXkgYnkgbW9udGgNCg0KV2Ugc2VwYXJhdGVkIGRlbGF5cyBpbnRvIHRocmVlIGNhdGVnb3JpZXMgYnkgZGVsYXkgc3RhdHVzOiBsb25nIGRlbGF5LCBzaG9ydCBkZWxheSwgYW5kIG5vIGRlbGF5LCBhbmQgd2UgZHJldyB0aGUgYmFyIGNoYXJ0IHRvIHNlZSBob3cgZWFjaCBjYXRlZ29yeSBjaGFuZ2VkIGZvciBlYWNoIG1vbnRoLiAgV2UgIGZvdW5kIHRoYXQgaW4gZWFjaCB5ZWFy4oCZcyBKdW5lLCBhaXJwbGFuZXMgaGF2ZSB0aGUgbW9zdCBsb25nIGRlbGF5IChtYXJrZWQgaW4gcGluayBjb2xvcikgYW5kIHNob3J0IGRlbGF5IGNhc2VzLCBvbiBhdmVyYWdlLiBBbmQgIGluIFNlcHRlbWJlciwgdGhlIGRlbGF5IGNhc2VzIGFyZSB0aGUgZmV3ZXN0Lg0KYGBge3J9DQpkZjIkZGVsYXkgPC0gIk9uX1RpbWUiDQpkZjJbd2hpY2goZGYyJERFUF9ERUxBWV9ORVcgPT0wKSwgXSRkZWxheSA9ICJPbl9UaW1lIg0KZGYyW3doaWNoKGRmMiRERVBfREVMQVlfTkVXID4wICYgZGYyJERFUF9ERUxBWV9ORVcgPDMwICksIF0kZGVsYXkgPSAiU2hvcnRfRGVsYXkiDQpkZjJbd2hpY2goZGYyJERFUF9ERUxBWV9ORVcgPjMwICksIF0kZGVsYXkgPSAiTG9uZ19EZWxheSINCg0KZGYyJE1PTlRIIDwtIGFzLmZhY3RvcihkZjIkTU9OVEgpDQphPC0gZGYyJT4lDQogIGRwbHlyOjpzZWxlY3QoTU9OVEgsZGVsYXkpJT4lDQogIGdyb3VwX2J5KE1PTlRIKQ0KDQoNCmIgPC1kZjIlPiUNCiAgZHBseXI6OnNlbGVjdChNT05USCxkZWxheSklPiUNCiAgZmlsdGVyKGRlbGF5ID09ICJMb25nX0RlbGF5IiklPiUNCiAgZ3JvdXBfYnkoTU9OVEgpJT4lDQogIGNvdW50KGRlbGF5KSU+JQ0KICBzdW1tYXJpc2UoY291bnRUID0gc3VtKG4pKQ0KDQpwNiA8LSBnZ3Bsb3QoKSsgZ2VvbV9iYXIoZGF0YSA9IGEsIGFlcyh4ID0gTU9OVEgsIGZpbGwgPSBkZWxheSksIHBvc2l0aW9uID0gJ2RvZGdlJykgKyBnZW9tX2xpbmUoZGF0YSA9IGIsIGFlcyh4ID0gTU9OVEgsIHk9Y291bnRULCBncm91cCA9IDEpKSsgeGxhYignTW9udGgnKSArIHlsYWIoJ051bWJlciBvZiBGbGlnaHRzJykrIGxhYnModGl0bGU9Ik1vbnRoIGFuZCBGbGlnaHRzIG51bWJlciIsIGNhcHRpb24gPSAiRGF0YSBzb3VyY2U6IEJ1cmVhdSBvZiBUcmFuc3BvcnRhdGlvbiIpKyB0aGVtZV9lY29ub21pc3QoKSArIHNjYWxlX2NvbG91cl9lY29ub21pc3QoKSsgdGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHZqdXN0PSAtMiksIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dCh2anVzdD0gMyksIHBsb3QuY2FwdGlvbiA9IGVsZW1lbnRfdGV4dCh2anVzdD0gLTUsaGp1c3Q9MSxmYWNlPSJpdGFsaWMiLHNpemUgPSA4KSApDQoNCnA2DQpgYGANCiANCiMjIyBlKSBEZWxheSBsZW5ndGggYnkgdGltZSBvZiB0aGUgZGF5DQoNCkR1cmluZyB0aGUgdGltZSBvZiBhIGRheSwgbW9ybmluZyBoYXMgdGhlIHNtYWxsZXN0IG51bWJlciBvZiBkZWxheXMgYW5kIHRoZSBiaWdnZXN0IG51bWJlciBvZiBvbiB0aW1lIGZsaWdodHMuIER1cmluZyB0aGUgYWZ0ZXJub29uIGFuZCBuaWdodCwgdGhlIGRlbGF5IGNhc2VzIGluY3JlYXNlLiBUaGUgcHJvcG9ydGlvbmFsIGJhciBwbG90IGFsc28gaGVscHMgdXMgdG8gdmlzdWFsbHkgc2VlIHRoZSBkaXN0cmlidXRpb25zLg0KYGBge3IgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0V9DQpkZjIkREVQX1RJTUUgPC0gYXMubnVtZXJpYyhkZjIkREVQX1RJTUUpDQpyYW5nZShkZjIkREVQX1RJTUUpDQpkZjIkdGltZSA8LSAiTW9ybmluZyINCmRmMlt3aGljaChkZjIkREVQX1RJTUUgPjYwMCAmIGRmMiRERVBfVElNRSA8MTIwMCksIF0kdGltZSA9ICJNb3JuaW5nIg0KZGYyW3doaWNoKGRmMiRERVBfVElNRSA+PSAxMjAwICYgZGYyJERFUF9USU1FIDwxODAwICksIF0kdGltZSA9ICJBZnRlcm5vb24iDQpkZjJbd2hpY2goZGYyJERFUF9USU1FID49IDE4MDAgJiBkZjIkREVQX1RJTUUgPD0gMjQwMDAgKSwgXSR0aW1lID0gIk5pZ2h0Ig0KDQpnZ3Bsb3QoKSsgZ2VvbV9iYXIoZGF0YSA9IGRmMiwgYWVzKHggPSB0aW1lLCBmaWxsID0gZGVsYXkpLHBvc2l0aW9uID0gJ2RvZGdlJykgKyB4bGFiKCdUaW1lIG9mIHRoZSBkYXknKSArIHlsYWIoJ051bWJlciBvZiBGbGlnaHRzJykrIGxhYnModGl0bGU9IkRlbGF5IFR5cGUgYW5kIFRpbWUgb2YgdGhlIERheSIsIGNhcHRpb24gPSAiRGF0YSBzb3VyY2U6IEJ1cmVhdSBvZiBUcmFuc3BvcnRhdGlvbiIpKyB0aGVtZV9lY29ub21pc3QoKSArIHNjYWxlX2NvbG91cl9lY29ub21pc3QoKSsgdGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHZqdXN0PSAtMiksIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dCh2anVzdD0gMyksIHBsb3QuY2FwdGlvbiA9IGVsZW1lbnRfdGV4dCh2anVzdD0gLTUsaGp1c3Q9MSxmYWNlPSJpdGFsaWMiLHNpemUgPSA4KSkNCmBgYA0KYGBge3J9DQpjPC0gZGYyJT4lDQogIGRwbHlyOjpzZWxlY3QodGltZSxkZWxheSklPiUNCiAgZ3JvdXBfYnkodGltZSklPiUNCiAgY291bnQoZGVsYXkpDQpnZ3Bsb3QoKSsgZ2VvbV9iYXIoZGF0YSA9IGMsIGFlcyh4ID0gdGltZSwgZmlsbCA9IGRlbGF5LCB5PW4pLCANCiAgICAgICAgICAgICAgICAgICBwb3NpdGlvbiA9ICdmaWxsJywgc3RhdCA9ICdpZGVudGl0eScpICsgDQogICAgICAgICAgeGxhYignVGltZSBvZiB0aGUgZGF5JykgKyB5bGFiKCdOdW1iZXIgb2YgRmxpZ2h0cycpICsgDQogICAgICAgICAgbGFicyh0aXRsZT0iRGVsYXkgVHlwZSBhbmQgVGltZSBvZiB0aGUgRGF5IiwgDQogICAgICAgICAgICAgICBjYXB0aW9uID0gIkRhdGEgc291cmNlOiBCdXJlYXUgb2YgVHJhbnNwb3J0YXRpb24iKSArIA0KICAgICAgICAgIHRoZW1lX2Vjb25vbWlzdCgpICsgICAgIHNjYWxlX2NvbG91cl9lY29ub21pc3QoKSsgDQogICAgICAgICAgdGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHZqdXN0PSAtMiksIA0KICAgICAgICAgICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dCh2anVzdD0gMyksIA0KICAgICAgICAgICAgICAgIHBsb3QuY2FwdGlvbiA9IGVsZW1lbnRfdGV4dCh2anVzdD0gLTUsaGp1c3Q9MSxmYWNlPSJpdGFsaWMiLHNpemUgPSA4KSkNCg0KYGBgDQoNCiMjIDQuIE1pc2NlbGxhZW5vdXMgKG90aGVyIGludGVyZXN0aW5nIGZpbmRpbmdzKSB7LnRhYnNldCAudGFic2V0LWZhZGUgLnRhYnNldC1waWxsc30NCiMjIyBhKSBEZWxheSBsZW5ndGggdHlwZSBieSBhaXJsaW5lDQoNCldlIHdhbnQgdG8gbWFrZSBjb21wYXJpc29ucyBiZXR3ZWVuIGFpcmxpbmVz4oCZIGRlbGF5cy4gQW1vbmcgdGhlIDEyIGFpcmxpbmVzLCBTb3V0aHdlc3QgaGFzIHRoZSBtb3N0IGRlbGF5ZWQgZmxpZ2h0cyAoYm90aCBsb25nIGFuZCBzaG9ydCBkZWxheXMsIGR1ZSB0byBpdHMgbGFyZ2UgbnVtYmVyIG9mIGZsaWdodHMpLg0KYGBge3Igd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0V9DQpjPC0gZGYyJT4lDQogIGRwbHlyOjpzZWxlY3QoQUlSTElORSxkZWxheSklPiUNCiAgZmlsdGVyKCFpcy5uYShBSVJMSU5FKSkgJT4lDQogIGdyb3VwX2J5KEFJUkxJTkUpDQoNCmdncGxvdCgpKyBnZW9tX2JhcihkYXRhID0gYywgYWVzKHggPSBBSVJMSU5FLCBmaWxsID0gZGVsYXkpLCBwb3NpdGlvbiA9ICdkb2RnZScpICsgeGxhYignQWlybGluZXMnKSArIHlsYWIoJ051bWJlciBvZiBGbGlnaHRzJykrIGxhYnModGl0bGU9IkFpcmxpbmVzIGFuZCBUeXBlIG9mIERlbGF5IiwgY2FwdGlvbiA9ICJEYXRhIHNvdXJjZTogQnVyZWF1IG9mIFRyYW5zcG9ydGF0aW9uIikrIHRoZW1lX2Vjb25vbWlzdCgpICsgc2NhbGVfY29sb3VyX2Vjb25vbWlzdCgpKyB0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQodmp1c3Q9IC0yKSwgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHZqdXN0PSAzKSwgcGxvdC5jYXB0aW9uID0gZWxlbWVudF90ZXh0KHZqdXN0PSAtNSxoanVzdD0xLGZhY2U9Iml0YWxpYyIsc2l6ZSA9IDgpKSArIGNvb3JkX2ZsaXAoKQ0KYGBgDQoNCiMjIyBiKSBPZmZpY2FsIERlbGF5IFJlYXNvbnMNCg0KV2UgZm91bmQgb3V0IDUgbWFqb3IgcmVhc29ucyB0aGF0IGNhdXNlIHRoZSBmbGlnaHQgZGVsYXkuIEFtb25nIHRoZSA1IHJlYXNvbnMsIFNlY3VyaXR5IHJlYXNvbnMgYmFyZWx5IGNhdXNlIGRlbGF5cy4gQnV0IGJhZCB3ZWF0aGVyIGxpa2Ugc3Rvcm1zIG1heSBjYXVzZSBkZWxheXMsIGJ1dCB3aXRoIGJpZyBzdG9ybXMuIEhvd2V2ZXIsIE5BUyByZWFzb25zLCBhaXJsaW5lIGNvbXBhbmllc+KAmSBzcGVjaWZpYyByZWFzb25zIGFuZCBmbGlnaHQgbGF0ZSBhcnJpdmFsIGFyZSB0aGUgbW9zdCBjb21tb24gcmVhc29ucy4gDQpgYGB7cn0NCnJlYXNvbiA8LSBkZjIlPiUNCiAgZHBseXI6OnNlbGVjdChDQVJSSUVSX0RFTEFZLFdFQVRIRVJfREVMQVksTkFTX0RFTEFZLFNFQ1VSSVRZX0RFTEFZLExBVEVfQUlSQ1JBRlRfREVMQVkpJT4lDQogIG5hLm9taXQoKSU+JQ0KICB0cmFuc211dGUoY2FycmllciA9IG1lYW4oQ0FSUklFUl9ERUxBWSksd2VhdGhlciA9IG1lYW4oV0VBVEhFUl9ERUxBWSksIG5hcyA9IG1lYW4oTkFTX0RFTEFZKSwgDQogICAgICAgICBzZWN1cml0eSA9IG1lYW4oU0VDVVJJVFlfREVMQVkpLGxhdGU9IG1lYW4oTEFURV9BSVJDUkFGVF9ERUxBWSkpJT4lDQogIHVuaXF1ZSgpJT4lDQogIHRpZHlyOjpnYXRoZXIoa2V5ID0gInJlYXNvbiIsIHZhbHVlID0gIm1lYW5fbGVuZ3RoIikNCg0KZ2dwbG90KGRhdGEgPSByZWFzb24sIGFlcyh4ID0gcmVvcmRlcihyZWFzb24sbWVhbl9sZW5ndGgpLCB5ID0gbWVhbl9sZW5ndGgsIGZpbGwgPSByZWFzb24pKSsgZ2VvbV9jb2woKSArIHhsYWIoJ1JlYXNvbicpICsgeWxhYignTWVhbiBMZW5ndGgnKSsgbGFicyh0aXRsZT0iRGVsYXkgUmVhc29ucyBhbmQgTGVuZ3RoIiwgY2FwdGlvbiA9ICJEYXRhIHNvdXJjZTogQnVyZWF1IG9mIFRyYW5zcG9ydGF0aW9uIikrIHRoZW1lX2Vjb25vbWlzdCgpICsgc2NhbGVfY29sb3VyX2Vjb25vbWlzdCgpKyAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSsgdGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHZqdXN0PSAtMiksICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dCh2anVzdD0gMyksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwbG90LmNhcHRpb24gPSBlbGVtZW50X3RleHQodmp1c3Q9IC01LGhqdXN0PTEsZmFjZT0iaXRhbGljIixzaXplID0gOCkgKQ0KYGBgDQoNCiMjIyBjKSBEZWxheSBieSBmbGlnaHQgbGVuZ3RoDQoNClRoZSBwbG90IHNob3dzIHVzIHRoYXQgd2l0aCB0aGUgaW5jcmVhc2Ugb2YgZmxpZ2h0IHRpbWUsIHRoZSBkZWxheSBhbHNvIGRlY3JlYXNlcy4gVGhlIHJlc3VsdCBzdWdnZXN0cyB0aGF0IHdoZW4geW91IHRha2UgbG9uZ2VyIGZsaWdodHMgKGZyb20gTllDIHRvIEhhd2FpaSwgZm9yIGluc3RhbmNlKSwgdGhlIGZsaWdodCBiYXJlbHkgZGVsYXlzLiBCdXQgaWYgeW91IGNob29zZSB0byBmbHkgZnJvbSBPcmxhbmRvIHRvIENoYXJsb3R0ZSwgdGhlIGZsaWdodCBtaWdodCBoYXZlIGEgd29yc2UgZGVsYXkuDQpgYGB7cn0NCmRmMyA8LSBkZjJbc2FtcGxlKG5yb3coZGYyKSwgMTAwMDApLCBdIyBzYW1wbGUgMTAwMDAgcm93cw0KDQpnZ3Bsb3QoZGF0YSA9IGRmMywgYWVzKHggPSBBSVJfVElNRSwgeSA9IERFUF9ERUxBWV9ORVcpLHBvc2l0aW9uID0gJ2RvZGdlJykrIA0KICBnZW9tX3BvaW50KGNvbG9yID0gIm9yYW5nZSIpICsgeGxhYignRmxpZ2h0IFRpbWUnKSArIA0KICB5bGFiKCdEZWxheSBUaW1lJykrIGxhYnModGl0bGU9IkZsaWdodCB0aW1lIGFuZCBEZWxheSBUaW1lIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICBjYXB0aW9uID0gIkRhdGEgc291cmNlOiBCdXJlYXUgb2YgVHJhbnNwb3J0YXRpb24iKSsgDQogIHRoZW1lX2Vjb25vbWlzdCgpICsgc2NhbGVfY29sb3VyX2Vjb25vbWlzdCgpKyANCiAgdGhlbWUoYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHZqdXN0PSAtMiksIA0KICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQodmp1c3Q9IDMpLCANCiAgICAgICAgcGxvdC5jYXB0aW9uID0gZWxlbWVudF90ZXh0KHZqdXN0PSAtNSwgaGp1c3Q9MSwgZmFjZT0iaXRhbGljIiwgc2l6ZSA9IDgpKQ0KYGBgDQoNCiMjIyBkKSBBaXJwb3J0cyB3aXRoIHdvcnN0IGRlbGF5cyAoYXZvaWQgaWYgcG9zc2libGUpDQoNClRoZSBjaGFydCBzaG93cyAxMCBhaXJwb3J0cyB0aGF0IGhhdmUgdGhlIGxvbmdlc3Qgb3ZlcmFsbCBkZWxheSB0aW1lIGFtb25nIHRoZSB3aG9sZSBjb3VudHJ5LiBUaGUgb25lIHdpdGggdGhlIGxvbmdlc3QgZGVsYXkgdGltZSAoTWFtbW90aCBsYWtlcyBhaXJwb3J0KSBoYXMgNDAgbWludXRlcyBkZWxheSB0aW1lLiBUaGUgMTB0aCByYW5rIGFpcnBvcnQgKEFzcGVuKSBoYXMgYW4gYXZlcmFnZWQgZGVsYXkgdGltZSBvZiAzMCBtaW51dGVzLg0KYGBge3J9DQphaXJwIDwtIGRmMiU+JQ0KICBkcGx5cjo6c2VsZWN0KERlc2NyaXB0aW9uLEFSUl9ERUxBWV9ORVcpJT4lDQogIGZpbHRlcighaXMubmEoQVJSX0RFTEFZX05FVykpJT4lDQogIGdyb3VwX2J5KERlc2NyaXB0aW9uKSU+JQ0KICBzdW1tYXJpc2UobWVhbj1yb3VuZChtZWFuKEFSUl9ERUxBWV9ORVcpKSwgbWF4ID0gcm91bmQobWF4KEFSUl9ERUxBWV9ORVcpKSwgbWluPSByb3VuZChtaW4oQVJSX0RFTEFZX05FVykpKSU+JQ0KICBhcnJhbmdlKGRlc2MobWVhbikpJT4lDQogIGhlYWQoMTApDQoNCmdncGxvdChkYXRhID0gYWlycCwgYWVzKHggPSByZW9yZGVyKERlc2NyaXB0aW9uLG1lYW4pLCB5PW1lYW4sZmlsbD1EZXNjcmlwdGlvbikpK2dlb21fY29sKCkreGxhYignQWlycG90cycpICsgDQogIHlsYWIoJ0RlbGF5IExlbmd0aCcpKyBsYWJzKHRpdGxlPSJBaXJwb3J0cyBhbmQgRGVsYXkgVGltZSIsIGNhcHRpb24gPSAiRGF0YSBzb3VyY2U6IEJ1cmVhdSBvZiBUcmFuc3BvcnRhdGlvbiIpKyB0aGVtZV9lY29ub21pc3QoKSArIHNjYWxlX2NvbG91cl9lY29ub21pc3QoKSsgY29vcmRfZmxpcCgpKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpKyB0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQodmp1c3Q9IC0yKSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHZqdXN0PSAzKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBsb3QuY2FwdGlvbiA9IGVsZW1lbnRfdGV4dCh2anVzdD0gLTUsaGp1c3Q9MSxmYWNlPSJpdGFsaWMiLHNpemUgPSA4KSApDQpgYGANCg0KIyBDb25jbHVzaW9ucw0KDQpPdmVyYWxsLCB3ZSBmb3VuZCB0aGF0IG5vcnRoZXJuIHN0YXRlcyBsaWtlIE5vcnRoIERha290YSwgU291dGggRGFrb3RhIG9yIE5ldyBFbmdsYW5kIHN0YXRlcyBoYXZlIGxvbmdlciBkZWxheXMgd2hpY2ggbWlnaHQgYmUgZHVlIHRvIGNvbGQgd2VhdGhlci4gIEZyb20gdGhlIHRyZWVtYXAgd2UgY2FuIHNlZSBzdGF0ZXMgbGlrZSBUZXhhcywgQ2FsaWZvcm5pYSwgIE5ld1lvcmssIGFuZCBGbG9yaWRhIGFsc28gaGF2ZSBsb25nZXIgZGVsYXlzIHdoaWNoIG1pZ2h0IGJlIGR1ZSB0byBwb3B1bGFyaXR5LiANCkFuYWx5emVkIGJ5IEFpcmxpbmVzLCB3ZSBmb3VuZCBvdXQgdGhhdCBKZXRibHVlIGFuZCBBdGFsYW50aWMgU291dGhlYXN0IGFpcmxpbmVzIGhhdmUgdGhlIGxvbmdlc3QgbWVhbiBkZWxheSwgc28gdHJ5IHRvIGF2b2lkIHRob3NlIGxhcmdlIGFpcmxpbmVzLiBMb2NhbCBhaXJsaW5lcyB0ZW5kIHRvIGhhdmUgbGVzcyBhdmVyYWdlIGRlbGF5IHRpbWUuICBIb3dldmVyLCBieSBhbmFseXppbmcgdGhlICBweXJhbWlkIGNoYXJ0IHdlIGZvdW5kIHRoYXQgYnVkZ2V0IGFpcmxpbmVzIHVzdWFsbHkgaGF2ZSB3b3JzZSBkZWxheXMgdGhhbiBvdGhlcnMuDQoNCkZ1cnRoZXJtb3JlLCB0cnkgdG8gYXZvaWQgYnVkZ2V0IGFpcmxpbmVzIGxpa2UgSmV0Qmx1ZSBmb3IgYmVzdCBleHBlcmllbmNlLiBBbmFseXplZCBieSB0aW1lLCB3ZSBmb3VuZCBvdXQgYW4gb2J2aW91cyBwYXR0ZXJuIGluIHF1YXJ0ZXIgb25lIGFuZCBxdWFydGVyIHR3byBmbGlnaHRzLiBJbiB0aGUgZmlyc3QgcXVhcnRlciwgdGhlIGNpdGllcyBpbiB0aGUgbm9ydGggbGlrZSBNaWNoaWdhbiBvdmVyYWxsIGhhZCBtdWNoIHdvcnNlIGRlbGF5cy4gSW4gdGhlIHNlY29uZCBxdWFydGVyLCB0aGUgY2l0aWVzIGluIHRoZSBzb3V0aCBsaWtlIE1pYW1pIG92ZXJhbGwgaGFkIG11Y2ggd29yc2UgZGVsYXlzLiAgQWxzbyBSZWQgRXllIGZsaWdodHMgYXJlIGNvbW1vbmx5IGFzc29jaWF0ZWQgd2l0aCBsb25nIGRlbGF5cyB0aGF0IGFyZSBvdmVyIDYgaG91cnMsIHNvIHRyeSB0byBhdm9pZCBSZWQgRXllIGZsaWdodHMuIFdoYXTigJlzIG1vcmUsIGZyb20gTW9uZGF5IHRvIFRodXJzZGF5LCBhbG1vc3QgYWxsIG9mIHRoZSB3b3JzdCBkZWxheXMgYXJlIGNvbmNlbnRyYXRlZCBpbiBOZXcgWW9yayBhbmQgQ2hpY2FnbyBtZXRyb3BvbGl0YW4gYXJlYXMuIEFuZCB3aGVuIEZyaWRheSBhbmQgd2Vla2VuZCBkYXlzIGNvbWUsIHRoZSB3b3JzdCBkZWxheXMgc3RhcnQgdG8gc3ByZWFkIHRvIG90aGVyIHBvcHVsYXIgZ2V0YXdheSBkZXN0aW5hdGlvbnMuIFRodXMsIHdlIHJlY29tbWVuZCB5b3UgdG8gYWRqdXN0IHlvdXIgZmxpZ2h0IHNjaGVkdWxlIGFjY29yZGluZyB0byB0aGlzIHBhdHRlcm4gYXMgbXVjaCBhcyBwb3NzaWJsZSB0byBhdm9pZCBsb25nIGRlbGF5cy4NCg0KQW5hbHl6ZWQgYnkgb3RoZXIgaW50ZXJlc3RpbmcgZmFjdHMsIHdlIGZvdW5kIHRoYXQgbG9uZ2VyIGZsaWdodCB0aW1lIHVzdWFsbHkgY29ycmVzcG9uZHMgdG8gc2hvcnRlciBhdmVyYWdlIGRlbGF5IHRpbWUuIA0KDQpIb3BlZnVsbHksIHRoaXMgcHJvamVjdCB3aWxsIGhlbHAgeW91IHdpdGggeW91ciBmbGlnaHQgc2VsZWN0aW9uIGluIHRoZSBmdXR1cmUhIEhhdmUgYSBzYWZlIGFuZCBvbi10aW1lIHRyaXAhDQoNCg==