This analysis was created as a self-selected case study for the Google Data Analytics Certificate. The data from this case study was found on Kaggle, was posted by Akul Bahl, and is originally from the US Department of Transportation https://www.kaggle.com/akulbahl/covid19-airline-flight-delays-and-cancellations/metadata. The purpose of this script is to reduce the data size (to make it compatible with the free version of rstudio), clean the data, and then answer the question: “Which airline has the most reliable flights to and from Austin?”
Step 4: Clean Data and Prepare for Analysis
#Looks for total number of null values (NA)
sum(is.na(flight_data_v2))
[1] 5196
#Displays rows with nulls. Looks like most are in column DEP_DELAY when a flight was also marked as cancelled.
flight_data_v2[rowSums(is.na(flight_data_v2)) > 0, ]
#This shows that there are no null values outside of DEP_DELAY.
flight_data_v2[rowSums(is.na(flight_data_v2)) > 0 & !is.na(flight_data_v2$DEP_DELAY), ]
#This shows that the only null values in DEP_DELAY occur when the flight was cancelled.
flight_data_v2[sum(is.na(flight_data_v2$DEP_DELAY)) > 0 & isTRUE(flight_data_v2$CANCELLED == 1), ]
#Change FL_DATE from chr (character) to date in format: YYYY-MM-DD
flight_data_v2$FL_DATE = as.Date(flight_data_v2$FL_DATE, "%m/%d/%Y")
head(flight_data_v2)
#Check that all dates are within expected bounds (January, 1st to October 7th, 2020)
if (flight_data_v2$FL_DATE < "2020-01-01" | flight_data_v2$FL_DATE > "2020-10-07") {
print("There is at least one date out of range.")
} else {print("No dates are out of range.")}
[1] "No dates are out of range."
Step 6: Graphical Representation
AA: American Airlines
AS: Alaska Airlines
B6: JetBlue
DL: Delta Air Lines
F9: Frontier Airlines
G4: Allegiant Air
HA: Hawaiian Airlines
NK: Spirit Airlines
UA: United Airlines
WN: Southwest Airlines
To determine which airlines were the least reliable, I first looked at the breakdown of flight delays for each airline. For the purposes of analysis, I categorized delays based on their impact to connecting flights/chance of missing planned meetings.
On Time: Flight arrived early or exactly at scheduled time
Mild Delay: Flight is less than 15 minutes late
Moderate Delay: Flight is between 15 and 60 minutes late (inclusive)
Extreme Delay: Flight is more than 60 minutes late
Cancelled: Flight is cancelled
# graph of percent cancelled flights
grouped_data_by_airline$MKT_UNIQUE_CARRIER <- as.factor(grouped_data_by_airline$MKT_UNIQUE_CARRIER)
library(RColorBrewer)
chart_data <- pivot_longer(select(grouped_data_by_airline, c('MKT_UNIQUE_CARRIER', 'cancelled', 'extreme_delay', 'mild_delay', 'moderate_delay', 'on_time', 'total_flights')), cols = c(cancelled, extreme_delay, moderate_delay, mild_delay, on_time), names_to = "Flight_Status", values_to = "Percent")
chart_data$Flight_Status <- as.factor(chart_data$Flight_Status)
chart_data$Flight_Status <- factor(chart_data$Flight_Status, levels = c("cancelled", "extreme_delay", "moderate_delay", "mild_delay", "on_time"))
chart_data$MKT_UNIQUE_CARRIER <- as.factor(chart_data$MKT_UNIQUE_CARRIER)
head(chart_data)
ggplot(chart_data, aes(fill = Flight_Status, y = Percent, x = MKT_UNIQUE_CARRIER)) +
geom_bar(position = "dodge", stat = "identity") +
theme(plot.title = element_text(size = 10)) +
ggtitle("Percent of Cancelled, Delayed, On-Time Flights By Airline in Austin") +
xlab("Airline")

# This graph shows the breakdown of flights to/from Austin by flight delay status for each airline.
grouped_data_by_airline %>%
ggplot( aes(x = MKT_UNIQUE_CARRIER, y = cancelled, fill = MKT_UNIQUE_CARRIER)) +
geom_bar(stat = "identity") +
ggtitle("Percent of Flights Cancelled Per Airline") +
xlab("Airline") +
ylab("Percent of Flights Cancelled") +
geom_text(aes(label = round(cancelled, digits = 1)), position = position_dodge(width = 0.9), vjust = -0.25) +
theme(legend.position = "none")

grouped_data_by_airline %>%
ggplot( aes(x = MKT_UNIQUE_CARRIER, y = extreme_delay, fill = MKT_UNIQUE_CARRIER)) +
geom_bar(stat = "identity") +
ggtitle("Percent of Flights Extremely Delayed Per Airline") +
xlab("Airline") +
ylab("Percent of Flights Extremely Delayed") +
geom_text(aes(label = round(extreme_delay, digits = 1)), position = position_dodge(width = 0.9), vjust = -0.25) +
theme(legend.position = "none")

# This graph shows that the airline G4, which is Alliegent Air, is the least reliable.
grouped_data_by_airline %>%
ggplot( aes(x = MKT_UNIQUE_CARRIER, y = extreme_delay + cancelled, fill = MKT_UNIQUE_CARRIER)) +
geom_bar(stat = "identity") +
ggtitle("Percent of Flights Cancelled or Extremely Delayed Per Airline") +
xlab("Airline") +
ylab("Percent of Flights Cancelled or Extremely Delayed") +
geom_text(aes(label = round(extreme_delay + cancelled, digits = 1)), position = position_dodge(width = 0.9), vjust = -0.25) +
theme(legend.position = "none")

grouped_data_by_airline %>%
ggplot( aes(x = MKT_UNIQUE_CARRIER, y = moderate_delay, fill = MKT_UNIQUE_CARRIER)) +
geom_bar(stat = "identity") +
ggtitle("Percent of Flights Moderately Delayed Per Airline") +
xlab("Airline") +
ylab("Percent of Flights Moderately Delayed (between 15 min. and 1 hour") +
geom_text(aes(label = round(moderate_delay, digits = 1)), position = position_dodge(width = 0.9), vjust = -0.25) +
theme(legend.position = "none")

grouped_data_by_airline %>%
ggplot( aes(x = MKT_UNIQUE_CARRIER, y = mild_delay, fill = MKT_UNIQUE_CARRIER)) +
geom_bar(stat = "identity") +
ggtitle("Percent of Flights Mildly Delayed (15 min or less) Per Airline") +
xlab("Airline") +
ylab("Percent of Flights Mildly Delayed") +
geom_text(aes(label = round(mild_delay, digits = 1)), position = position_dodge(width = 0.9), vjust = -0.25) +
theme(legend.position = "none")

grouped_data_by_airline %>%
ggplot( aes(x = MKT_UNIQUE_CARRIER, y = on_time, fill = MKT_UNIQUE_CARRIER)) +
geom_bar(stat = "identity") +
ggtitle("Percent of Flights On Time Per Airline") +
xlab("Airline") +
ylab("Percent of Flights On Time") +
geom_text(aes(label = round(on_time, digits = 1)), position = position_dodge(width = 0.9), vjust = -0.25) +
theme(legend.position = "none")

# This boxplot of delay times per airline shows that airlines typically had about 75% of flights on time. I excluded this graph from my actual analysis because I had to exclude extreme delays for the graph to be readable.
flight_data_v2 %>%
ggplot( aes(x = MKT_UNIQUE_CARRIER, y = DEP_DELAY, fill = MKT_UNIQUE_CARRIER)) +
geom_boxplot(outlier.shape = NA) +
ylim(-20, 15) +
scale_fill_viridis(discrete = TRUE, alpha = 0.6) +
ggtitle("Airline Delay Times") +
xlab("Airline") +
ylab("Delay Time")

# This graph looks at the distribution of delays less than or equal to 1 hour.
delayed_mild_mod <- flight_data_v2[flight_data_v2$DEP_DELAY > 0 & flight_data_v2$DEP_DELAY <= 60, ]
delayed_mild_mod %>%
ggplot( aes(x = DEP_DELAY, group = MKT_UNIQUE_CARRIER, fill = MKT_UNIQUE_CARRIER)) +
geom_density(adjust = 1.5) +
facet_wrap(~MKT_UNIQUE_CARRIER) +
ggtitle("Airline Delay Times") +
xlab("Airline") +
ylab("Delay Time")

# This graph shows the distribution of delays and has quartile lines to better show the distribution of flight delays. Based on this graph, of the mild-moderate delays, WN, which is Southwest Airlines, has the shortest mild-moderate delays.
delayed_mild_mod %>%
ggplot( aes(x = DEP_DELAY, y = MKT_UNIQUE_CARRIER, fill = factor(stat(quantile)))) +
stat_density_ridges(geom = "density_ridges_gradient", calc_ecdf = TRUE, quantiles = 4, quantile_lines = TRUE) +
scale_fill_viridis_d(name = "Quartiles") +
theme_ridges() +
theme(legend.position = "none")
Picking joint bandwidth of 3.78

# Overall, the most reliable airline is NK, which is Spirit Airlines.
grouped_data_by_airline %>%
ggplot( aes(x = MKT_UNIQUE_CARRIER, y = on_time + mild_delay, fill = MKT_UNIQUE_CARRIER)) +
geom_bar(stat = "identity") +
ggtitle("Percent of Flights On Time or Delayed Less Than 15 Min") +
xlab("Airline") +
ylab("Percent of Flights On Time or Mildly Delayed") +
geom_text(aes(label = round(on_time + mild_delay, digits = 1)), position = position_dodge(width = 0.9), vjust = -0.25) +
theme(legend.position = "none")

LS0tCnRpdGxlOiBGbGlnaHRzX0Zyb21fQXVzdGluCm91dHB1dDogaHRtbF9ub3RlYm9vawpkYXRlOiAyLzcvMjAyMgphdXRob3I6IE1hbG9yeSBXb2RrYQotLS0KClRoaXMgYW5hbHlzaXMgd2FzIGNyZWF0ZWQgYXMgYSBzZWxmLXNlbGVjdGVkIGNhc2Ugc3R1ZHkgZm9yIHRoZSBHb29nbGUgRGF0YSBBbmFseXRpY3MgQ2VydGlmaWNhdGUuIFRoZSBkYXRhIGZyb20gdGhpcyBjYXNlIHN0dWR5IHdhcyBmb3VuZCBvbiBLYWdnbGUsIHdhcyBwb3N0ZWQgYnkgQWt1bCBCYWhsLCBhbmQgaXMgb3JpZ2luYWxseSBmcm9tIHRoZSBVUyBEZXBhcnRtZW50IG9mIFRyYW5zcG9ydGF0aW9uIDxodHRwczovL3d3dy5rYWdnbGUuY29tL2FrdWxiYWhsL2NvdmlkMTktYWlybGluZS1mbGlnaHQtZGVsYXlzLWFuZC1jYW5jZWxsYXRpb25zL21ldGFkYXRhPi4gVGhlIHB1cnBvc2Ugb2YgdGhpcyBzY3JpcHQgaXMgdG8gcmVkdWNlIHRoZSBkYXRhIHNpemUgKHRvIG1ha2UgaXQgY29tcGF0aWJsZSB3aXRoIHRoZSBmcmVlIHZlcnNpb24gb2YgcnN0dWRpbyksIGNsZWFuIHRoZSBkYXRhLCBhbmQgdGhlbiBhbnN3ZXIgdGhlIHF1ZXN0aW9uOiAiV2hpY2ggYWlybGluZSBoYXMgdGhlIG1vc3QgcmVsaWFibGUgZmxpZ2h0cyB0byBhbmQgZnJvbSBBdXN0aW4/IiAKCiMgU3RlcCAxOiBMb2FkIHJlcXVpcmVkIHBhY2thZ2VzCiogdGlkeXZlcnNlIGZvciBkYXRhIHdyYW5nbGluZwoqIHJlYWRyIGZvciBsb2FkaW5nIGNzdiBmaWxlCiogbHVicmlkYXRlIGZvciB0aW1lIGZ1bmN0aW9ucwoqIGRwbHlyIGZvciBkYXRhIHRyYW5zZm9ybWF0aW9uCiogZ2dwbG90MiwgdmlyaWRpcywgYW5kIGdncmlkZ2VzIGZvciBncmFwaGluZwoKYGBge3IgU3RlcCAxLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShyZWFkcikKbGlicmFyeShsdWJyaWRhdGUpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeSh2aXJpZGlzKQpsaWJyYXJ5KGdncmlkZ2VzKQpgYGAKCiMgU3RlcCAyOiBTZWxlY3QgcG90ZW50aWFsbHkgdXNlZnVsIGNvbHVtbnMgZnJvbSBvcmlnaW5hbCBkYXRhc2V0CiogVGhlIG9yaWdpbmFsIGRhdGFzZXQgd2FzIHRvbyBsYXJnZSBmb3IgdGhlIGZyZWUgdmVyc2lvbiBvZiByc3R1ZGlvIHRvIGhhbmRsZSB3aXRob3V0IGNyYXNoaW5nLCBzbyBJIHNlbGVjdGVkIHRoZSBjb2x1bW5zICh1c2luZyBLYWdnbGUpIHRvIGV4cG9ydCB0aGUgc21hbGxlciBkYXRhc2V0ICdmbGlnaHRfZGF0YV92MicuCgpUaGUgZm9sbG93aW5nIHdhcyBjb21wbGV0ZWQgaW4gYSBLYWdnbGUgbm90ZWJvb2suCi0tLS0tClRoaXMgY29kZSBjcmVhdGVzIGEgc3Vic2V0IG9mIHRoZSBvcmlnaW5hbCBkYXRhc2V0IGZyb20gPGh0dHBzOi8vd3d3LmthZ2dsZS5jb20vYWt1bGJhaGwvY292aWQxOS1haXJsaW5lLWZsaWdodC1kZWxheXMtYW5kLWNhbmNlbGxhdGlvbnMvbWV0YWRhdGE+IG9mIHRoZSBjb2x1bW5zIEkgbWlnaHQgbGlrZWx5IHVzZSBmb3IgbXkgZGF0YSBhbmFseXNpcy4KCjEuIGxpYnJhcnkodGlkeXZlcnNlKSAKCiAvLyBtZXRhcGFja2FnZSBvZiBhbGwgdGlkeXZlcnNlIHBhY2thZ2VzCgoyLiBmbGlnaHRfZGF0YSA8LSByZWFkX2NzdigiLi4vaW5wdXQvY292aWQxOS1haXJsaW5lLWZsaWdodC1kZWxheXMtYW5kLWNhbmNlbGxhdGlvbnMvamFudG9qdW4yMDIwLmNzdiIpCgozLiBsaWJyYXJ5KHJlYWRyKQoKNC4gY29sbmFtZXMoZmxpZ2h0X2RhdGEpCgo1LiBmbGlnaHRfZGF0YV92MiA8LSBzZWxlY3QoZmxpZ2h0X2RhdGEsIEZMX0RBVEUsIE1LVF9VTklRVUVfQ0FSUklFUiwgIE9SSUdJTl9DSVRZX05BTUUsIERFU1RfU1RBVEVfQUJSLCBERVNUX0NJVFlfTkFNRSwgREVQX0RFTEFZLCBDQU5DRUxMRUQpCgo2LiBoZWFkKGZsaWdodF9kYXRhX3YyKQoKLy9DaGVja2VkIHRvIGVuc3VyZSBjb3JyZWN0IGNvbHVtbnMgd2l0aCBjb3JyZXNwb25kaW5nIHZhbHVlcyB3ZXJlIHNlbGVjdGVkCgo3LiBjb2xuYW1lcyhmbGlnaHRfZGF0YV92MikKCi8vIFRoZSBjb2x1bW5zIHNlbGVjdGVkIHRvIGV4cG9ydCBhbmQgZG91YmxlLWNoZWNrZWQgd2l0aCBjb2xuYW1lcygpIHdlcmUgRkxfREFURSwgTUtUX1VOSVFVRV9DQVJSSUVSLCBPUklHSU5fQ0lUWV9OQU1FLCBERVNUX1NUQVRFX0FCUiwgREVTVF9DSVRZX05BTUUsIERFUF9ERUxBWSwgQ0FOQ0VMTEVECgo4LiBmbGlnaHRfZGF0YV92MiA8LSBmaWx0ZXIoZmxpZ2h0X2RhdGFfdjIsIE9SSUdJTl9DSVRZX05BTUUgPT0gIkF1c3RpbiwgVFgiIHwgREVTVF9DSVRZX05BTUUgPT0gIkF1c3RpbiwgVFgiKQoKLy9JIHdhcyBvbmx5IGludGVyZXN0ZWQgaW4gZmxpZ2h0cyBsZWF2aW5nIEF1c3RpbiBvciByZXR1cm5pbmcgdG8gQXVzdGluIGZvciB0aGlzIGNhc2Ugc3R1ZHkuCgo5LiB3cml0ZS5jc3YoZmxpZ2h0X2RhdGFfdjIsICJmbGlnaHRfZGF0YV92Mi5jc3YiLCByb3cubmFtZXMgPSBGKQoKLy8gVGhpcyBjcmVhdGVzIHRoZSBuZXcgY3N2IGZpbGUgdGhhdCBJIGRvd25sb2FkZWQgdG8gbXkgY29tcHV0ZXIgYW5kIHVwbG9hZGVkIHRvIFJTdHVkaW8uCgojIFN0ZXAgMzogSW1wb3J0IERhdGEgdG8gUlN0dWRpbwoKYGBge3IgU3RlcCAzLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpmbGlnaHRfZGF0YV92MiA8LSByZWFkX2NzdigiRmxpZ2h0X0RhdGFfS2FnZ2xlL2ZsaWdodF9kYXRhX3YyLmNzdiIpCmhlYWQoZmxpZ2h0X2RhdGFfdjIpCmBgYAoKIyBTdGVwIDQ6IENsZWFuIERhdGEgYW5kIFByZXBhcmUgZm9yIEFuYWx5c2lzCgpgYGB7ciBTdGVwIDQ6IERhdGEgQ2xlYW5pbmcsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiNMb29rcyBmb3IgdG90YWwgbnVtYmVyIG9mIG51bGwgdmFsdWVzIChOQSkKc3VtKGlzLm5hKGZsaWdodF9kYXRhX3YyKSkKCiNEaXNwbGF5cyByb3dzIHdpdGggbnVsbHMuIExvb2tzIGxpa2UgbW9zdCBhcmUgaW4gY29sdW1uIERFUF9ERUxBWSB3aGVuIGEgZmxpZ2h0IHdhcyBhbHNvIG1hcmtlZCBhcyBjYW5jZWxsZWQuCmZsaWdodF9kYXRhX3YyW3Jvd1N1bXMoaXMubmEoZmxpZ2h0X2RhdGFfdjIpKSA+IDAsIF0KCiNUaGlzIHNob3dzIHRoYXQgdGhlcmUgYXJlIG5vIG51bGwgdmFsdWVzIG91dHNpZGUgb2YgREVQX0RFTEFZLgpmbGlnaHRfZGF0YV92Mltyb3dTdW1zKGlzLm5hKGZsaWdodF9kYXRhX3YyKSkgPiAwICYgIWlzLm5hKGZsaWdodF9kYXRhX3YyJERFUF9ERUxBWSksIF0KCiNUaGlzIHNob3dzIHRoYXQgdGhlIG9ubHkgbnVsbCB2YWx1ZXMgaW4gREVQX0RFTEFZIG9jY3VyIHdoZW4gdGhlIGZsaWdodCB3YXMgY2FuY2VsbGVkLgpmbGlnaHRfZGF0YV92MltzdW0oaXMubmEoZmxpZ2h0X2RhdGFfdjIkREVQX0RFTEFZKSkgPiAwICYgaXNUUlVFKGZsaWdodF9kYXRhX3YyJENBTkNFTExFRCA9PSAxKSwgXQoKI0NoYW5nZSBGTF9EQVRFIGZyb20gY2hyIChjaGFyYWN0ZXIpIHRvIGRhdGUgaW4gZm9ybWF0OiBZWVlZLU1NLURECmZsaWdodF9kYXRhX3YyJEZMX0RBVEUgPSBhcy5EYXRlKGZsaWdodF9kYXRhX3YyJEZMX0RBVEUsICIlbS8lZC8lWSIpCmhlYWQoZmxpZ2h0X2RhdGFfdjIpCgojQ2hlY2sgdGhhdCBhbGwgZGF0ZXMgYXJlIHdpdGhpbiBleHBlY3RlZCBib3VuZHMgKEphbnVhcnksIDFzdCB0byBPY3RvYmVyIDd0aCwgMjAyMCkKaWYgKGZsaWdodF9kYXRhX3YyJEZMX0RBVEUgPCAiMjAyMC0wMS0wMSIgfCBmbGlnaHRfZGF0YV92MiRGTF9EQVRFID4gIjIwMjAtMTAtMDciKSB7CiAgcHJpbnQoIlRoZXJlIGlzIGF0IGxlYXN0IG9uZSBkYXRlIG91dCBvZiByYW5nZS4iKQogIH0gZWxzZSB7cHJpbnQoIk5vIGRhdGVzIGFyZSBvdXQgb2YgcmFuZ2UuIil9CgpgYGAKIyBTdGVwIDU6IERlc2NyaXB0aXZlIEFuYWx5c2lzCgpgYGB7ciBTdGVwIDU6IERlc2NyaXB0aXZlIEFuYWx5c2lzLCBtZXNzYWdlPVRSVUUsIHdhcm5pbmc9RkFMU0UsIHBhZ2VkLnByaW50PVRSVUV9Cgpncm91cGVkX2RhdGFfYnlfYWlybGluZSA8LSBmbGlnaHRfZGF0YV92MiAlPiUKICBncm91cF9ieShNS1RfVU5JUVVFX0NBUlJJRVIpICU+JQogIHN1bW1hcmlzZShtZWFuX2RlcF9kZWxheSA9IG1lYW4oREVQX0RFTEFZLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICBtZWRpYW5fZGVwX2RlbGF5ID0gbWVkaWFuKERFUF9ERUxBWSwgbmEucm0gPSBUUlVFKSwKICAgICAgICAgICAgdG90YWxfZmxpZ2h0c19jYW5jZWxsZWQgPSBzdW0oQ0FOQ0VMTEVEKSwKICAgICAgICAgICAgdG90YWxfZmxpZ2h0c19mcm9tX2F1c3RpbiA9IHN1bShPUklHSU5fQ0lUWV9OQU1FID09ICJBdXN0aW4sIFRYIiksCiAgICAgICAgICAgIHRvdGFsX2NhbmNlbGxlZF9mcm9tX2F1c3RpbiA9IHN1bShDQU5DRUxMRUQgJiBPUklHSU5fQ0lUWV9OQU1FID09ICJBdXN0aW4sIFRYIiksCiAgICAgICAgICAgIHRvdGFsX2ZsaWdodHNfdG9fYXVzdGluID0gc3VtKERFU1RfQ0lUWV9OQU1FID09ICJBdXN0aW4sIFRYIiksCiAgICAgICAgICAgIHRvdGFsX2NhbmNlbGxlZF90b19hdXN0aW4gPSBzdW0oQ0FOQ0VMTEVEICYgREVTVF9DSVRZX05BTUUgPT0gIkF1c3RpbiwgVFgiKSwKICAgICAgICAgICAgdG90YWxfZmxpZ2h0cyA9IHN1bSh0b3RhbF9mbGlnaHRzX2Zyb21fYXVzdGluLCB0b3RhbF9mbGlnaHRzX3RvX2F1c3RpbiksCiAgICAgICAgICAgIGV4dHJlbWVfZGVsYXlfbiA9IHN1bShERVBfREVMQVkgPiA2MCAmICFpcy5uYShERVBfREVMQVkpKSwKICAgICAgICAgICAgbW9kZXJhdGVfZGVsYXlfbiA9IHN1bShERVBfREVMQVkgPiAxNSAmIERFUF9ERUxBWSA8PSA2MCAmICFpcy5uYShERVBfREVMQVkpKSwKICAgICAgICAgICAgbWlsZF9kZWxheV9uID0gc3VtKERFUF9ERUxBWSA+IDAgJiBERVBfREVMQVkgPD0gMTUgJiAhaXMubmEoREVQX0RFTEFZKSkpCgpncm91cGVkX2RhdGFfYnlfYWlybGluZSA8LSBtdXRhdGUoZ3JvdXBlZF9kYXRhX2J5X2FpcmxpbmUsIGNhbmNlbGxlZCA9ICh0b3RhbF9mbGlnaHRzX2NhbmNlbGxlZCAvIHRvdGFsX2ZsaWdodHMpKjEwMCkKCmdyb3VwZWRfZGF0YV9ieV9haXJsaW5lIDwtIG11dGF0ZShncm91cGVkX2RhdGFfYnlfYWlybGluZSwgZXh0cmVtZV9kZWxheSA9ICAoZXh0cmVtZV9kZWxheV9uIC8gdG90YWxfZmxpZ2h0cykqMTAwKQogIApncm91cGVkX2RhdGFfYnlfYWlybGluZSA8LSBtdXRhdGUoZ3JvdXBlZF9kYXRhX2J5X2FpcmxpbmUsIG1vZGVyYXRlX2RlbGF5ID0gIChtb2RlcmF0ZV9kZWxheV9uIC8gdG90YWxfZmxpZ2h0cykqMTAwKQoKZ3JvdXBlZF9kYXRhX2J5X2FpcmxpbmUgPC0gbXV0YXRlKGdyb3VwZWRfZGF0YV9ieV9haXJsaW5lLCBtaWxkX2RlbGF5ID0gIChtaWxkX2RlbGF5X24gLyB0b3RhbF9mbGlnaHRzKSoxMDApCgpncm91cGVkX2RhdGFfYnlfYWlybGluZSA8LSBtdXRhdGUoZ3JvdXBlZF9kYXRhX2J5X2FpcmxpbmUsIG9uX3RpbWUgPSAgKDEwMCAtIChtaWxkX2RlbGF5X24gKyBtb2RlcmF0ZV9kZWxheV9uICsgZXh0cmVtZV9kZWxheV9uICsgdG90YWxfZmxpZ2h0c19jYW5jZWxsZWQpIC8gdG90YWxfZmxpZ2h0cyoxMDApKQoKdmlldyhncm91cGVkX2RhdGFfYnlfYWlybGluZSkKCmBgYAoKIyBTdGVwIDY6IEdyYXBoaWNhbCBSZXByZXNlbnRhdGlvbgoKICAgICAgICBBQTogQW1lcmljYW4gQWlybGluZXMKCQkJCUFTOiBBbGFza2EgQWlybGluZXMKCQkJCUI2OiBKZXRCbHVlCgkJCQlETDogRGVsdGEgQWlyIExpbmVzCgkJCQlGOTogRnJvbnRpZXIgQWlybGluZXMKCQkJCUc0OiBBbGxlZ2lhbnQgQWlyCgkJCQlIQTogSGF3YWlpYW4gQWlybGluZXMKCQkJCU5LOiBTcGlyaXQgQWlybGluZXMKCQkJCVVBOiBVbml0ZWQgQWlybGluZXMKCQkJCVdOOiBTb3V0aHdlc3QgQWlybGluZXMKCQkJCQpUbyBkZXRlcm1pbmUgd2hpY2ggYWlybGluZXMgd2VyZSB0aGUgbGVhc3QgcmVsaWFibGUsIEkgZmlyc3QgbG9va2VkIGF0IHRoZSBicmVha2Rvd24gb2YgZmxpZ2h0IGRlbGF5cyBmb3IgZWFjaCBhaXJsaW5lLiBGb3IgdGhlIHB1cnBvc2VzIG9mIGFuYWx5c2lzLCBJIGNhdGVnb3JpemVkIGRlbGF5cyBiYXNlZCBvbiB0aGVpciBpbXBhY3QgdG8gY29ubmVjdGluZyBmbGlnaHRzL2NoYW5jZSBvZiBtaXNzaW5nIHBsYW5uZWQgbWVldGluZ3MuIAoKICAgIE9uIFRpbWU6IEZsaWdodCBhcnJpdmVkIGVhcmx5IG9yIGV4YWN0bHkgYXQgc2NoZWR1bGVkIHRpbWUKICAgIE1pbGQgRGVsYXk6IEZsaWdodCBpcyBsZXNzIHRoYW4gMTUgbWludXRlcyBsYXRlCiAgICBNb2RlcmF0ZSBEZWxheTogRmxpZ2h0IGlzIGJldHdlZW4gMTUgYW5kIDYwIG1pbnV0ZXMgbGF0ZSAoaW5jbHVzaXZlKQogICAgRXh0cmVtZSBEZWxheTogRmxpZ2h0IGlzIG1vcmUgdGhhbiA2MCBtaW51dGVzIGxhdGUKICAgIENhbmNlbGxlZDogRmxpZ2h0IGlzIGNhbmNlbGxlZApgYGB7ciBTdGVwIDY6IEdyYXBoaWNhbCBSZXByZXNlbnRhdGlvbiwgZWNobz1UUlVFLCBtZXNzYWdlPVRSVUUsIHdhcm5pbmc9RkFMU0UsIHBhZ2VkLnByaW50PVRSVUV9CgojIGdyYXBoIG9mIHBlcmNlbnQgY2FuY2VsbGVkIGZsaWdodHMKZ3JvdXBlZF9kYXRhX2J5X2FpcmxpbmUkTUtUX1VOSVFVRV9DQVJSSUVSIDwtIGFzLmZhY3Rvcihncm91cGVkX2RhdGFfYnlfYWlybGluZSRNS1RfVU5JUVVFX0NBUlJJRVIpCmxpYnJhcnkoUkNvbG9yQnJld2VyKQoKY2hhcnRfZGF0YSA8LSBwaXZvdF9sb25nZXIoc2VsZWN0KGdyb3VwZWRfZGF0YV9ieV9haXJsaW5lLCBjKCdNS1RfVU5JUVVFX0NBUlJJRVInLCAnY2FuY2VsbGVkJywgJ2V4dHJlbWVfZGVsYXknLCAnbWlsZF9kZWxheScsICdtb2RlcmF0ZV9kZWxheScsICdvbl90aW1lJywgJ3RvdGFsX2ZsaWdodHMnKSksIGNvbHMgPSBjKGNhbmNlbGxlZCwgZXh0cmVtZV9kZWxheSwgbW9kZXJhdGVfZGVsYXksIG1pbGRfZGVsYXksIG9uX3RpbWUpLCBuYW1lc190byA9ICJGbGlnaHRfU3RhdHVzIiwgdmFsdWVzX3RvID0gIlBlcmNlbnQiKQoKY2hhcnRfZGF0YSRGbGlnaHRfU3RhdHVzIDwtIGFzLmZhY3RvcihjaGFydF9kYXRhJEZsaWdodF9TdGF0dXMpCmNoYXJ0X2RhdGEkRmxpZ2h0X1N0YXR1cyA8LSBmYWN0b3IoY2hhcnRfZGF0YSRGbGlnaHRfU3RhdHVzLCBsZXZlbHMgPSBjKCJjYW5jZWxsZWQiLCAiZXh0cmVtZV9kZWxheSIsICJtb2RlcmF0ZV9kZWxheSIsICJtaWxkX2RlbGF5IiwgIm9uX3RpbWUiKSkKY2hhcnRfZGF0YSRNS1RfVU5JUVVFX0NBUlJJRVIgPC0gYXMuZmFjdG9yKGNoYXJ0X2RhdGEkTUtUX1VOSVFVRV9DQVJSSUVSKQoKaGVhZChjaGFydF9kYXRhKQoKZ2dwbG90KGNoYXJ0X2RhdGEsIGFlcyhmaWxsID0gRmxpZ2h0X1N0YXR1cywgeSA9IFBlcmNlbnQsIHggPSBNS1RfVU5JUVVFX0NBUlJJRVIpKSArCiAgZ2VvbV9iYXIocG9zaXRpb24gPSAiZG9kZ2UiLCBzdGF0ID0gImlkZW50aXR5IikgKyAKICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCkpICsgCiAgZ2d0aXRsZSgiUGVyY2VudCBvZiBDYW5jZWxsZWQsIERlbGF5ZWQsIE9uLVRpbWUgRmxpZ2h0cyBCeSBBaXJsaW5lIGluIEF1c3RpbiIpICsgCiAgeGxhYigiQWlybGluZSIpCiMgVGhpcyBncmFwaCBzaG93cyB0aGUgYnJlYWtkb3duIG9mIGZsaWdodHMgdG8vZnJvbSBBdXN0aW4gYnkgZmxpZ2h0IGRlbGF5IHN0YXR1cyBmb3IgZWFjaCBhaXJsaW5lLiAKCmdyb3VwZWRfZGF0YV9ieV9haXJsaW5lICU+JSAKICBnZ3Bsb3QoIGFlcyh4ID0gTUtUX1VOSVFVRV9DQVJSSUVSLCB5ID0gY2FuY2VsbGVkLCBmaWxsID0gTUtUX1VOSVFVRV9DQVJSSUVSKSkgKyAKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogIGdndGl0bGUoIlBlcmNlbnQgb2YgRmxpZ2h0cyBDYW5jZWxsZWQgUGVyIEFpcmxpbmUiKSArCiAgeGxhYigiQWlybGluZSIpICsKICB5bGFiKCJQZXJjZW50IG9mIEZsaWdodHMgQ2FuY2VsbGVkIikgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSByb3VuZChjYW5jZWxsZWQsIGRpZ2l0cyA9IDEpKSwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOSksIHZqdXN0ID0gLTAuMjUpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCgpncm91cGVkX2RhdGFfYnlfYWlybGluZSAlPiUgCiAgZ2dwbG90KCBhZXMoeCA9IE1LVF9VTklRVUVfQ0FSUklFUiwgeSA9IGV4dHJlbWVfZGVsYXksIGZpbGwgPSBNS1RfVU5JUVVFX0NBUlJJRVIpKSArIAogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgZ2d0aXRsZSgiUGVyY2VudCBvZiBGbGlnaHRzIEV4dHJlbWVseSBEZWxheWVkIFBlciBBaXJsaW5lIikgKwogIHhsYWIoIkFpcmxpbmUiKSArCiAgeWxhYigiUGVyY2VudCBvZiBGbGlnaHRzIEV4dHJlbWVseSBEZWxheWVkIikgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSByb3VuZChleHRyZW1lX2RlbGF5LCBkaWdpdHMgPSAxKSksIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjkpLCB2anVzdCA9IC0wLjI1KSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKIyBUaGlzIGdyYXBoIHNob3dzIHRoYXQgdGhlIGFpcmxpbmUgRzQsIHdoaWNoIGlzIEFsbGllZ2VudCBBaXIsIGlzIHRoZSBsZWFzdCByZWxpYWJsZS4KZ3JvdXBlZF9kYXRhX2J5X2FpcmxpbmUgJT4lIAogIGdncGxvdCggYWVzKHggPSBNS1RfVU5JUVVFX0NBUlJJRVIsIHkgPSBleHRyZW1lX2RlbGF5ICsgY2FuY2VsbGVkLCBmaWxsID0gTUtUX1VOSVFVRV9DQVJSSUVSKSkgKyAKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogIGdndGl0bGUoIlBlcmNlbnQgb2YgRmxpZ2h0cyBDYW5jZWxsZWQgb3IgRXh0cmVtZWx5IERlbGF5ZWQgUGVyIEFpcmxpbmUiKSArCiAgeGxhYigiQWlybGluZSIpICsKICB5bGFiKCJQZXJjZW50IG9mIEZsaWdodHMgQ2FuY2VsbGVkIG9yIEV4dHJlbWVseSBEZWxheWVkIikgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSByb3VuZChleHRyZW1lX2RlbGF5ICsgY2FuY2VsbGVkLCBkaWdpdHMgPSAxKSksIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjkpLCB2anVzdCA9IC0wLjI1KSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKZ3JvdXBlZF9kYXRhX2J5X2FpcmxpbmUgJT4lIAogIGdncGxvdCggYWVzKHggPSBNS1RfVU5JUVVFX0NBUlJJRVIsIHkgPSBtb2RlcmF0ZV9kZWxheSwgZmlsbCA9IE1LVF9VTklRVUVfQ0FSUklFUikpICsgCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsKICBnZ3RpdGxlKCJQZXJjZW50IG9mIEZsaWdodHMgTW9kZXJhdGVseSBEZWxheWVkIFBlciBBaXJsaW5lIikgKwogIHhsYWIoIkFpcmxpbmUiKSArCiAgeWxhYigiUGVyY2VudCBvZiBGbGlnaHRzIE1vZGVyYXRlbHkgRGVsYXllZCAoYmV0d2VlbiAxNSBtaW4uIGFuZCAxIGhvdXIiKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHJvdW5kKG1vZGVyYXRlX2RlbGF5LCBkaWdpdHMgPSAxKSksIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjkpLCB2anVzdCA9IC0wLjI1KSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKZ3JvdXBlZF9kYXRhX2J5X2FpcmxpbmUgJT4lIAogIGdncGxvdCggYWVzKHggPSBNS1RfVU5JUVVFX0NBUlJJRVIsIHkgPSBtaWxkX2RlbGF5LCBmaWxsID0gTUtUX1VOSVFVRV9DQVJSSUVSKSkgKyAKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogIGdndGl0bGUoIlBlcmNlbnQgb2YgRmxpZ2h0cyBNaWxkbHkgRGVsYXllZCAoMTUgbWluIG9yIGxlc3MpIFBlciBBaXJsaW5lIikgKwogIHhsYWIoIkFpcmxpbmUiKSArCiAgeWxhYigiUGVyY2VudCBvZiBGbGlnaHRzIE1pbGRseSBEZWxheWVkIikgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSByb3VuZChtaWxkX2RlbGF5LCBkaWdpdHMgPSAxKSksIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjkpLCB2anVzdCA9IC0wLjI1KSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQoKZ3JvdXBlZF9kYXRhX2J5X2FpcmxpbmUgJT4lIAogIGdncGxvdCggYWVzKHggPSBNS1RfVU5JUVVFX0NBUlJJRVIsIHkgPSBvbl90aW1lLCBmaWxsID0gTUtUX1VOSVFVRV9DQVJSSUVSKSkgKyAKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogIGdndGl0bGUoIlBlcmNlbnQgb2YgRmxpZ2h0cyBPbiBUaW1lIFBlciBBaXJsaW5lIikgKwogIHhsYWIoIkFpcmxpbmUiKSArCiAgeWxhYigiUGVyY2VudCBvZiBGbGlnaHRzIE9uIFRpbWUiKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHJvdW5kKG9uX3RpbWUsIGRpZ2l0cyA9IDEpKSwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOSksIHZqdXN0ID0gLTAuMjUpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCgojIFRoaXMgYm94cGxvdCBvZiBkZWxheSB0aW1lcyBwZXIgYWlybGluZSBzaG93cyB0aGF0IGFpcmxpbmVzIHR5cGljYWxseSBoYWQgYWJvdXQgNzUlIG9mIGZsaWdodHMgb24gdGltZS4gSSBleGNsdWRlZCB0aGlzIGdyYXBoIGZyb20gbXkgYWN0dWFsIGFuYWx5c2lzIGJlY2F1c2UgSSBoYWQgdG8gZXhjbHVkZSBleHRyZW1lIGRlbGF5cyBmb3IgdGhlIGdyYXBoIHRvIGJlIHJlYWRhYmxlLiAKZmxpZ2h0X2RhdGFfdjIgJT4lIAogIGdncGxvdCggYWVzKHggPSBNS1RfVU5JUVVFX0NBUlJJRVIsIHkgPSBERVBfREVMQVksIGZpbGwgPSBNS1RfVU5JUVVFX0NBUlJJRVIpKSArCiAgZ2VvbV9ib3hwbG90KG91dGxpZXIuc2hhcGUgPSBOQSkgKyAKICB5bGltKC0yMCwgMTUpICsKICBzY2FsZV9maWxsX3ZpcmlkaXMoZGlzY3JldGUgPSBUUlVFLCBhbHBoYSA9IDAuNikgKyAKICBnZ3RpdGxlKCJBaXJsaW5lIERlbGF5IFRpbWVzIikgKwogIHhsYWIoIkFpcmxpbmUiKSArIAogIHlsYWIoIkRlbGF5IFRpbWUiKQoKIyBUaGlzIGdyYXBoIGxvb2tzIGF0IHRoZSBkaXN0cmlidXRpb24gb2YgZGVsYXlzIGxlc3MgdGhhbiBvciBlcXVhbCB0byAxIGhvdXIuCmRlbGF5ZWRfbWlsZF9tb2QgPC0gZmxpZ2h0X2RhdGFfdjJbZmxpZ2h0X2RhdGFfdjIkREVQX0RFTEFZID4gMCAmIGZsaWdodF9kYXRhX3YyJERFUF9ERUxBWSA8PSA2MCwgXQpkZWxheWVkX21pbGRfbW9kICU+JSAKICBnZ3Bsb3QoIGFlcyh4ID0gREVQX0RFTEFZLCBncm91cCA9IE1LVF9VTklRVUVfQ0FSUklFUiwgZmlsbCA9IE1LVF9VTklRVUVfQ0FSUklFUikpICsKICBnZW9tX2RlbnNpdHkoYWRqdXN0ID0gMS41KSArIAogIGZhY2V0X3dyYXAofk1LVF9VTklRVUVfQ0FSUklFUikgKwogIGdndGl0bGUoIkFpcmxpbmUgRGVsYXkgVGltZXMiKSArCiAgeGxhYigiQWlybGluZSIpICsgCiAgeWxhYigiRGVsYXkgVGltZSIpCgojIFRoaXMgZ3JhcGggc2hvd3MgdGhlIGRpc3RyaWJ1dGlvbiBvZiBkZWxheXMgYW5kIGhhcyBxdWFydGlsZSBsaW5lcyB0byBiZXR0ZXIgc2hvdyB0aGUgZGlzdHJpYnV0aW9uIG9mIGZsaWdodCBkZWxheXMuIEJhc2VkIG9uIHRoaXMgZ3JhcGgsIG9mIHRoZSBtaWxkLW1vZGVyYXRlIGRlbGF5cywgV04sIHdoaWNoIGlzIFNvdXRod2VzdCBBaXJsaW5lcywgaGFzIHRoZSBzaG9ydGVzdCBtaWxkLW1vZGVyYXRlIGRlbGF5cy4KZGVsYXllZF9taWxkX21vZCAlPiUgCiAgZ2dwbG90KCBhZXMoeCA9IERFUF9ERUxBWSwgeSA9IE1LVF9VTklRVUVfQ0FSUklFUiwgZmlsbCA9IGZhY3RvcihzdGF0KHF1YW50aWxlKSkpKSArIAogIHN0YXRfZGVuc2l0eV9yaWRnZXMoZ2VvbSA9ICJkZW5zaXR5X3JpZGdlc19ncmFkaWVudCIsIGNhbGNfZWNkZiA9IFRSVUUsIHF1YW50aWxlcyA9IDQsIHF1YW50aWxlX2xpbmVzID0gVFJVRSkgKyAKICBzY2FsZV9maWxsX3ZpcmlkaXNfZChuYW1lID0gIlF1YXJ0aWxlcyIpICsKICB0aGVtZV9yaWRnZXMoKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKCiMgT3ZlcmFsbCwgdGhlIG1vc3QgcmVsaWFibGUgYWlybGluZSBpcyBOSywgd2hpY2ggaXMgU3Bpcml0IEFpcmxpbmVzLgpncm91cGVkX2RhdGFfYnlfYWlybGluZSAlPiUgCiAgZ2dwbG90KCBhZXMoeCA9IE1LVF9VTklRVUVfQ0FSUklFUiwgeSA9IG9uX3RpbWUgKyBtaWxkX2RlbGF5LCBmaWxsID0gTUtUX1VOSVFVRV9DQVJSSUVSKSkgKyAKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogIGdndGl0bGUoIlBlcmNlbnQgb2YgRmxpZ2h0cyBPbiBUaW1lIG9yIERlbGF5ZWQgTGVzcyBUaGFuIDE1IE1pbiIpICsKICB4bGFiKCJBaXJsaW5lIikgKwogIHlsYWIoIlBlcmNlbnQgb2YgRmxpZ2h0cyBPbiBUaW1lIG9yIE1pbGRseSBEZWxheWVkIikgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSByb3VuZChvbl90aW1lICsgbWlsZF9kZWxheSwgZGlnaXRzID0gMSkpLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC45KSwgdmp1c3QgPSAtMC4yNSkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKCmBgYAoK