Introduction
The book “Applied Analytics Through Case Studies Using SAS and R:
Implementing Predictive Models and Machine Learning Techniques” is a
guide book for statisticians, data analysts, and others who are
interested in trying to learn/transition into data science. The book,
authored by Deepti Gupta, use case studies to explore how to answer
various business questions using statistical and machine learning
methods using programming platforms SAS and R.
One of those case studies involves predicting flight delays based on
several factors. In the book, Gupta uses statistical learning methods to
analyze the data and determine which factors influence how long a flight
a will be delayed for. For this project, the goal is to use data
visualization and regression methods to determine which factors are
influential to flight delays.
The data set that will be used for this analysis will be the same one
used in the case study. The data set was downloaded from a data set
repository and uploaded to Github. Analysis for this report will be done
via R.
flights <- read.csv("https://raw.githubusercontent.com/IV246/R_DataSets/refs/heads/main/Flight_delay-data.csv")
Data Preparation
This portion of the report will focus on preparing the data set for
visual exploratory data analysis and regression analysis. Here, data
exploration, preparation and visualization will be done to the data set
to prepare for analysis.
Structure of the Data
Set
The data used in the case study was synthetically generated. It
contains 3593 observations and 11 variables. The variables are as
follows:
# Create an interactive data dictionary
data_dictionary <- tribble(
~Variable_Name, ~Description, ~Variable_Type,
"[", "[Brief description of variable 1 — what it measures, units]", "[Numeric/Categorical/Date/Text]",
"[var2]", "[Brief description of variable 2 — what it measures, categories]", "[Numeric/Categorical/Date/Text]",
"[var3]", "[Brief description of variable 3 — what it measures]", "[Numeric/Categorical/Date/Text]",
"[var4]", "[Brief description of variable 4 — what it measures, categories]", "[Numeric/Categorical/Date/Text]"
# Add more rows as needed
)
datatable(
data_dictionary,
caption = "Table 1: Variable definitions and types for the analysis dataset",
rownames = FALSE,
options = list(pageLength = 10, dom = 'tip')
)
Next, we can check a summary of the data set:
Carrier Airport_Distance Number_of_flights Weather
Length:3593 Min. :376.0 Min. :29475 Min. :5.000
Class :character 1st Qu.:431.0 1st Qu.:41634 1st Qu.:5.000
Mode :character Median :443.0 Median :43424 Median :5.000
Mean :442.4 Mean :43311 Mean :5.353
3rd Qu.:454.0 3rd Qu.:45140 3rd Qu.:6.000
Max. :499.0 Max. :53461 Max. :6.000
Support_Crew_Available Baggage_loading_time Late_Arrival_o Cleaning_o
Min. : 0 Min. :14.00 Min. :15.00 Min. :-4.00
1st Qu.: 56 1st Qu.:17.00 1st Qu.:18.00 1st Qu.: 8.00
Median : 83 Median :17.00 Median :19.00 Median :10.00
Mean : 85 Mean :16.98 Mean :18.74 Mean :10.02
3rd Qu.:112 3rd Qu.:17.00 3rd Qu.:19.00 3rd Qu.:12.00
Max. :222 Max. :19.00 Max. :22.00 Max. :23.00
Fueling_o Security_o Arr_Delay
Min. :13.00 Min. :13.00 Min. : 0.0
1st Qu.:23.00 1st Qu.:32.00 1st Qu.: 49.0
Median :25.00 Median :37.00 Median : 70.0
Mean :25.01 Mean :37.09 Mean : 69.8
3rd Qu.:27.00 3rd Qu.:42.00 3rd Qu.: 90.0
Max. :36.00 Max. :63.00 Max. :180.0
If we pay close attention to the summary, a red flag immediately
jumps out: The min of Cleaning_o is below 0, and since it’s a time
variable, it can’t have values below 0. We can verify if it’s a mistake
by either sorting the values of Cleaning_o or by summing up the values
of the variable that are less than 0. To keep output simplistic, we can
find out which specific observations have values of Cleaning_o of less
than 0, as well as their respective values.
which(flights$Cleaning_o < 0)
[1] 624 1243 2357 2684 2786
flights$Cleaning_o[c(624, 1243, 2357, 2684, 2786)]
[1] -1 -4 -1 -1 -1
It appears that we only have 5 observations that have values less
than 0. For this report, i will assume that they probably were just
entry mistakes and will multiply them by -1 to make them positive so
that no observations have to be dropped.
flights$Cleaning_o <- ifelse(flights$Cleaning_o < 0, flights$Cleaning_o*-1, flights$Cleaning_o)
To verify that the change worked, we can use the sort() function:
head(sort(flights$Cleaning_o))
[1] 0 0 0 0 0 0
The change worked. We will continue with data preparation.
Missing Values
Next we will check for missing values. Missing values, especially
large amounts of them, can complicate analysis and lead to incorrect
results and conclusions.
The summary of the data set that was ran earlier shows that there are
no missing values. To verify, we can generate a lollipop plot of missing
values to and run the sum() and is.na() functions to check how many
missing values are in the data set.
# Add Up Total Missing Values
# Check for Missing Values
sum(is.na(flights))
[1] 0
The sum of missing values is 0, which means there are no missing
values in the data set. Next, let’s generate the lollipop plot using the
gg_miss_var() function from the naniar package:
# Generate Lollipop Plot
# library(naniar)
miss <- gg_miss_var(flights) +
labs(title = "Missing Values Per Variable") +
theme(plot.title = element_text(hjust = 0.5),
plot.margin = margin(t = 35, r = 10, b = 25, l = 30))
ggplotly(miss)
All of the dots on are on 0, and there does not appear to be any
stems. So it’s safe to say that we have a clean data set.
In the event that missing values were present, they could either just
be dropped from the data set or imputed in some way.
Variable
Screening
According to Gupta, the reasons airlines report for delays fall into
5 broad categories:
Extreme Weather: When extreme weather
conditions like hurricanes or tornadoes occur, or when conditions are
not ideal like in a snow storm, flights often have to change schedules,
which results in delays or cancellations.
Late Arrival: This is the problem airlines
report most often. When an airplane makes multiple flights and just even
one time arrives late, it can make other flights using the same plane
late, which will inevitably cause delays.
Air Carrier: Reasons such as aircraft
maintenance issues, cleaning, baggage loading, fueling, and others
contribute to the delays or cancellations that occur.
Security: Reasons such as inoperative
screening equpiment, long queues in screening areas, reboarding of
aircraft, and more contribute to flight delays.
National Aviation System (NAS): Airport
operations, heavy volume/traffic, air traffic control and more can
contribute to flight delays and cancellations.
It seems that all of our bases are covered with the variables
generated for the data set. So for now, we won’t add or drop any
variables. However, since weather is a rating variable, and seems to
only have values of either 5 or 6 (despite being on a rating scale of
0-10), I will convert that variable into a factor:
flights$Weather <- factor(flights$Weather, ordered = TRUE)
The data is now prepared for analysis. Analysis will be done via
visualization and regression. To do so, we will turn our attention to a
shinyapp dashboard built specifically built for the analysis of this
data set.
LS0tDQp0aXRsZTogIkEgU3R1ZHkgb2YgQWlybGluZSBGbGlnaHQgRGVsYXlzIFVzaW5nIE11bHRpcGxlIExpbmVhciBSZWdyZXNzaW9uIg0KYXV0aG9yOiAiSWFuIFZhbldyaWdodCINCmRhdGU6ICIwNi8yOS8yMDI2Ig0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIHRoZW1lOiB5ZXRpDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDQNCiAgICB0b2NfZmxvYXQ6IHllcw0KICAgIG51bWJlcl9zZWN0aW9uczogeWVzDQogICAgdG9jX2NvbGxhcHNlZDogeWVzDQogICAgY29kZV9mb2xkaW5nOiBoaWRlDQogICAgY29kZV9kb3dubG9hZDogeWVzDQogICAgc21vb3RoX3Njcm9sbDogeWVzDQogICAgaGlnaGxpZ2h0OiB0YW5nbw0KICAgIGNzczogc3R5bGVzLmNzcw0KLS0tDQoNCg0KYGBge2NzcyBlY2hvID0gRkFMU0V9DQovKiA9PT09PT09PT09PT0gQ1NTIFN0eWxpbmcgZm9yIExlY3R1cmUgTm90ZXMgPT09PT09PT09PT09ICovDQoNCmJvZHkgew0KICBmb250LWZhbWlseTogJ1NlZ29lIFVJJywgJ0ludGVyJywgc3lzdGVtLXVpLCAtYXBwbGUtc3lzdGVtLCBzYW5zLXNlcmlmOw0KICBsaW5lLWhlaWdodDogMS43Ow0KICBjb2xvcjogIzJkMWIyOTsNCiAgYmFja2dyb3VuZC1jb2xvcjogI2ZkZmFmZDsNCn0NCg0KI1RPQzo6YmVmb3JlIHsNCiAgY29udGVudDogIlRhYmxlIG9mIENvbnRlbnRzIjsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogIGZvbnQtc2l6ZTogMS4yZW07DQogIGRpc3BsYXk6IGJsb2NrOw0KICBjb2xvcjogbmF2eTsNCiAgbWFyZ2luLWJvdHRvbTogMTBweDsNCn0NCg0KDQpkaXYjVE9DIGxpIHsgICAgIC8qIHRhYmxlIG9mIGNvbnRlbnQgICovDQogICAgbGlzdC1zdHlsZTp1cHBlci1yb21hbjsNCiAgICBiYWNrZ3JvdW5kLWltYWdlOm5vbmU7DQogICAgYmFja2dyb3VuZC1yZXBlYXQ6bm9uZTsNCiAgICBiYWNrZ3JvdW5kLXBvc2l0aW9uOjA7DQogICAgLypmb250LXdlaWdodDogYm9sZDsgKi8NCiAgICBmb250LXNpemU6IDEuMWVtOw0KICAgIGZvbnQtd2VpZ2h0OiA1MDA7DQogICAgY29sb3I6ICM2RTMwNjE7DQp9DQoNCg0KaDEudGl0bGUgew0KICBmb250LXNpemU6IDI2cHg7DQogIGNvbG9yOiAjNkUzMDYxOw0KICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KDQpoNC5hdXRob3IgeyAvKiBIZWFkZXIgNCAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICBmb250LXNpemU6IDE4cHg7DQogIC8qZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7Ki8NCiAgY29sb3I6ICM2RTMwNjE7DQogIHRleHQtYWxpZ246IGxlZnQ7DQp9DQpoNC5kYXRlIHsgLyogSGVhZGVyIDQgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgZm9udC1zaXplOiAxOHB4Ow0KICAvKmZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOyovDQogIGNvbG9yOiAjNkUzMDYxOw0KICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KDQoNCmgxIHsNCiAgY29sb3I6ICM2RTMwNjE7DQogIGJvcmRlci1ib3R0b206IDNweCBzb2xpZCAjNkUzMDYxOw0KICBwYWRkaW5nLWJvdHRvbTogOHB4Ow0KICBtYXJnaW4tdG9wOiA0MHB4Ow0KICBmb250LXdlaWdodDogYm9sZDsNCiAgZm9udC1zaXplOiAyLjJyZW07DQp9DQoNCmgyIHsNCiAgY29sb3I6ICM2RTMwNjE7DQogIGJvcmRlci1sZWZ0OiA1cHggc29saWQgIzZFMzA2MTsNCiAgcGFkZGluZy1sZWZ0OiAxMnB4Ow0KICBtYXJnaW4tdG9wOiAzMHB4Ow0KICBmb250LXdlaWdodDogYm9sZDsNCiAgZm9udC1zaXplOiAxLjhyZW07DQp9DQoNCmgzIHsNCiAgY29sb3I6ICM4YjRhN2Q7DQogIG1hcmdpbi10b3A6IDI0cHg7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KICBmb250LXNpemU6IDEuOG07DQp9DQoNCmg0IHsNCiAgY29sb3I6ICNhMDVmOTI7DQogIG1hcmdpbi10b3A6IDE4cHg7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KICBmb250LXNpemU6IDEuNHJlbTsNCn0NCg0KY29kZSB7DQogIGJhY2tncm91bmQtY29sb3I6ICNmNGVkZjM7DQogIGNvbG9yOiAjNGEyMDQwOw0KICBwYWRkaW5nOiAycHggNnB4Ow0KICBib3JkZXItcmFkaXVzOiA0cHg7DQogIGZvbnQtZmFtaWx5OiAnRmlyYSBDb2RlJywgJ0pldEJyYWlucyBNb25vJywgJ0NvbnNvbGFzJywgbW9ub3NwYWNlOw0KICBmb250LXNpemU6IDAuOWVtOw0KICBib3JkZXI6IDFweCBzb2xpZCAjZDRjMGQxOw0KfQ0KDQpwcmUgew0KICBiYWNrZ3JvdW5kLWNvbG9yOiAjZjlmNWY5Ow0KICBib3JkZXI6IDFweCBzb2xpZCAjZDRjMGQxOw0KICBib3JkZXItbGVmdDogNHB4IHNvbGlkICM2RTMwNjE7DQogIGJvcmRlci1yYWRpdXM6IDZweDsNCiAgcGFkZGluZzogMTRweDsNCn0NCg0KcHJlIGNvZGUgew0KICBiYWNrZ3JvdW5kLWNvbG9yOiB0cmFuc3BhcmVudDsNCiAgYm9yZGVyOiBub25lOw0KICBwYWRkaW5nOiAwOw0KfQ0KDQpibG9ja3F1b3RlIHsNCiAgYmFja2dyb3VuZC1jb2xvcjogI2Y0ZWRmMzsNCiAgYm9yZGVyLWxlZnQ6IDRweCBzb2xpZCAjNkUzMDYxOw0KICBwYWRkaW5nOiAxMnB4IDE4cHg7DQogIG1hcmdpbjogMTZweCAwOw0KICBib3JkZXItcmFkaXVzOiAwIDZweCA2cHggMDsNCiAgY29sb3I6ICM0YTIwNDA7DQp9DQoNCi5ub3RlLWJveCB7DQogIGJhY2tncm91bmQtY29sb3I6ICNmMGU2ZWU7DQogIGJvcmRlcjogMXB4IHNvbGlkICNjNDliYjg7DQogIGJvcmRlci1yYWRpdXM6IDhweDsNCiAgcGFkZGluZzogMTZweCAyMHB4Ow0KICBtYXJnaW46IDE4cHggMDsNCn0NCg0KLm5vdGUtYm94IHN0cm9uZyB7DQogIGNvbG9yOiAjNkUzMDYxOw0KfQ0KDQoudGlwLWJveCB7DQogIGJhY2tncm91bmQtY29sb3I6ICNlOGY1ZTk7DQogIGJvcmRlcjogMXB4IHNvbGlkICM4MWM3ODQ7DQogIGJvcmRlci1yYWRpdXM6IDhweDsNCiAgcGFkZGluZzogMTZweCAyMHB4Ow0KICBtYXJnaW46IDE4cHggMDsNCn0NCg0KLnRpcC1ib3ggc3Ryb25nIHsNCiAgY29sb3I6ICMyZTdkMzI7DQp9DQoNCi53YXJuaW5nLWJveCB7DQogIGJhY2tncm91bmQtY29sb3I6ICNmZmYzZTA7DQogIGJvcmRlcjogMXB4IHNvbGlkICNmZmI3NGQ7DQogIGJvcmRlci1yYWRpdXM6IDhweDsNCiAgcGFkZGluZzogMTZweCAyMHB4Ow0KICBtYXJnaW46IDE4cHggMDsNCn0NCg0KLndhcm5pbmctYm94IHN0cm9uZyB7DQogIGNvbG9yOiAjZTY1MTAwOw0KfQ0KDQp0YWJsZSB7DQogIHdpZHRoOiAxMDAlOw0KICBib3JkZXItY29sbGFwc2U6IGNvbGxhcHNlOw0KICBtYXJnaW46IDE2cHggMDsNCn0NCg0KdGFibGUgdGggew0KICBiYWNrZ3JvdW5kLWNvbG9yOiAjNkUzMDYxOw0KICBjb2xvcjogd2hpdGU7DQogIHBhZGRpbmc6IDEwcHggMTJweDsNCiAgdGV4dC1hbGlnbjogbGVmdDsNCiAgZm9udC13ZWlnaHQ6IDYwMDsNCn0NCg0KdGFibGUgdGQgew0KICBwYWRkaW5nOiA4cHggMTJweDsNCiAgYm9yZGVyLWJvdHRvbTogMXB4IHNvbGlkICNkNGMwZDE7DQp9DQoNCnRhYmxlIHRyOm50aC1jaGlsZChldmVuKSB0ZCB7DQogIGJhY2tncm91bmQtY29sb3I6ICNmYWY1Zjk7DQp9DQoNCnRhYmxlIHRyOmhvdmVyIHRkIHsNCiAgYmFja2dyb3VuZC1jb2xvcjogI2YwZTZlZTsNCn0NCg0KLnRvYyB7DQogIGJhY2tncm91bmQtY29sb3I6ICNmYWY1Zjk7DQogIGJvcmRlcjogMXB4IHNvbGlkICNkNGMwZDE7DQogIGJvcmRlci1yYWRpdXM6IDhweDsNCiAgcGFkZGluZzogMTZweCAyMHB4Ow0KICBtYXJnaW4tYm90dG9tOiAyNHB4Ow0KfQ0KDQouZmlndXJlIHsNCiAgYm9yZGVyOiAxcHggc29saWQgI2UwZDFkYjsNCiAgYm9yZGVyLXJhZGl1czogOHB4Ow0KICBwYWRkaW5nOiA4cHg7DQogIG1hcmdpbjogMTZweCAwOw0KICBib3gtc2hhZG93OiAwIDJweCA4cHggcmdiYSgxMTAsIDQ4LCA5NywgMC4wOCk7DQp9DQpgYGANCg0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCiMgPT09PT09PT09PT09PT09PT09PT09PT09DQojICBSRVFVSVJFRCBQQUNLQUdFUw0KIyA9PT09PT09PT09PT09PT09PT09PT09PT0NCiMgUXVpY2sgaW5zdGFsbCBhbmQgbG9hZCBmb3IgUiBNYXJrZG93bg0KcGFja2FnZXMgPC0gYygia25pdHIiLCAicmVhZHIiLCAidGlkeXZlcnNlIiwgInBsb3RseSIsICJsZWFmbGV0IiwgIkRUIiwgImNvcnJwbG90IiwgIkdHYWxseSIsICJjYXIiLCAiTUFTUyIsICJwYXRjaHdvcmsiLCAic2NhbGVzIiwgInZpcmlkaXMiLCAiUkNvbG9yQnJld2VyIiwgImdncmlkZ2VzIiwgImdnaGlnaGxpZ2h0IiwgImNvd3Bsb3QiLCAic2YiLCAiZ2dzcGF0aWFsIiwgImtuaXRyIiwgImthYmxlRXh0cmEiLCAiZ3JpZEV4dHJhIiwgImxlYXBzIiwgImdnZm9ydGlmeSIsICJwYW5kZXIiLCAic2NhbGVzIiwgImdhcG1pbmRlciIsICJodG1sd2lkZ2V0cyIsICJ2aXNkYXQiLCAibmFuaWFyIikNCg0KIyBJbnN0YWxsIG1pc3NpbmcgcGFja2FnZXMNCmlmKGFueSghKHBhY2thZ2VzICVpbiUgaW5zdGFsbGVkLnBhY2thZ2VzKCkpKSkgew0KICBpbnN0YWxsLnBhY2thZ2VzKHBhY2thZ2VzWyEocGFja2FnZXMgJWluJSBpbnN0YWxsZWQucGFja2FnZXMoKSldKQ0KfQ0KDQojIExvYWQgYWxsIHBhY2thZ2VzDQppbnZpc2libGUobGFwcGx5KHBhY2thZ2VzLCBsaWJyYXJ5LCBjaGFyYWN0ZXIub25seSA9IFRSVUUpKQ0KDQojIw0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCANCiAgICAgICAgICAgICAgICAgICAgICB3YXJuaW5nID0gRkFMU0UsIA0KICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSwgDQogICAgICAgICAgICAgICAgICAgICAgZmlnLndpZHRoPTgsIA0KICAgICAgICAgICAgICAgICAgICAgIGZpZy5oZWlnaHQ9NSwNCiAgICAgICAgICAgICAgICAgICAgICBmaWcuYWxpZ24gPSAiY2VudGVyIiwNCiAgICAgICAgICAgICAgICAgICAgICBjb21tZW50ID0gTkEpDQpgYGANCg0KIyBJbnRyb2R1Y3Rpb24NClRoZSBib29rICJBcHBsaWVkIEFuYWx5dGljcyBUaHJvdWdoIENhc2UgU3R1ZGllcyBVc2luZyBTQVMgYW5kIFI6IEltcGxlbWVudGluZyBQcmVkaWN0aXZlIE1vZGVscyBhbmQgTWFjaGluZSBMZWFybmluZyBUZWNobmlxdWVzIiBpcyBhIGd1aWRlIGJvb2sgZm9yIHN0YXRpc3RpY2lhbnMsIGRhdGEgYW5hbHlzdHMsIGFuZCBvdGhlcnMgd2hvIGFyZSBpbnRlcmVzdGVkIGluIHRyeWluZyB0byBsZWFybi90cmFuc2l0aW9uIGludG8gZGF0YSBzY2llbmNlLiBUaGUgYm9vaywgYXV0aG9yZWQgYnkgRGVlcHRpIEd1cHRhLCB1c2UgY2FzZSBzdHVkaWVzIHRvIGV4cGxvcmUgaG93IHRvIGFuc3dlciB2YXJpb3VzIGJ1c2luZXNzIHF1ZXN0aW9ucyB1c2luZyBzdGF0aXN0aWNhbCBhbmQgbWFjaGluZSBsZWFybmluZyBtZXRob2RzIHVzaW5nIHByb2dyYW1taW5nIHBsYXRmb3JtcyBTQVMgYW5kIFIuIA0KDQpPbmUgb2YgdGhvc2UgY2FzZSBzdHVkaWVzIGludm9sdmVzIHByZWRpY3RpbmcgZmxpZ2h0IGRlbGF5cyBiYXNlZCBvbiBzZXZlcmFsIGZhY3RvcnMuIEluIHRoZSBib29rLCBHdXB0YSB1c2VzIHN0YXRpc3RpY2FsIGxlYXJuaW5nIG1ldGhvZHMgdG8gYW5hbHl6ZSB0aGUgZGF0YSBhbmQgZGV0ZXJtaW5lIHdoaWNoIGZhY3RvcnMgaW5mbHVlbmNlIGhvdyBsb25nIGEgZmxpZ2h0IGEgd2lsbCBiZSBkZWxheWVkIGZvci4gRm9yIHRoaXMgcHJvamVjdCwgdGhlIGdvYWwgaXMgdG8gdXNlIGRhdGEgdmlzdWFsaXphdGlvbiBhbmQgcmVncmVzc2lvbiBtZXRob2RzIHRvIGRldGVybWluZSB3aGljaCBmYWN0b3JzIGFyZSBpbmZsdWVudGlhbCB0byBmbGlnaHQgZGVsYXlzLg0KDQpUaGUgZGF0YSBzZXQgdGhhdCB3aWxsIGJlIHVzZWQgZm9yIHRoaXMgYW5hbHlzaXMgd2lsbCBiZSB0aGUgc2FtZSBvbmUgdXNlZCBpbiB0aGUgY2FzZSBzdHVkeS4gVGhlIGRhdGEgc2V0IHdhcyBkb3dubG9hZGVkIGZyb20gYSBkYXRhIHNldCByZXBvc2l0b3J5IGFuZCB1cGxvYWRlZCB0byBHaXRodWIuIEFuYWx5c2lzIGZvciB0aGlzIHJlcG9ydCB3aWxsIGJlIGRvbmUgdmlhIFIuDQpgYGB7cn0NCmZsaWdodHMgPC0gcmVhZC5jc3YoImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9JVjI0Ni9SX0RhdGFTZXRzL3JlZnMvaGVhZHMvbWFpbi9GbGlnaHRfZGVsYXktZGF0YS5jc3YiKQ0KYGBgDQoNCiMgRGF0YSBQcmVwYXJhdGlvbg0KVGhpcyBwb3J0aW9uIG9mIHRoZSByZXBvcnQgd2lsbCBmb2N1cyBvbiBwcmVwYXJpbmcgdGhlIGRhdGEgc2V0IGZvciB2aXN1YWwgZXhwbG9yYXRvcnkgZGF0YSBhbmFseXNpcyBhbmQgcmVncmVzc2lvbiBhbmFseXNpcy4gSGVyZSwgZGF0YSBleHBsb3JhdGlvbiwgcHJlcGFyYXRpb24gYW5kIHZpc3VhbGl6YXRpb24gd2lsbCBiZSBkb25lIHRvIHRoZSBkYXRhIHNldCB0byBwcmVwYXJlIGZvciBhbmFseXNpcy4NCg0KIyMgU3RydWN0dXJlIG9mIHRoZSBEYXRhIFNldA0KVGhlIGRhdGEgdXNlZCBpbiB0aGUgY2FzZSBzdHVkeSB3YXMgc3ludGhldGljYWxseSBnZW5lcmF0ZWQuIEl0IGNvbnRhaW5zIDM1OTMgb2JzZXJ2YXRpb25zIGFuZCAxMSB2YXJpYWJsZXMuIFRoZSB2YXJpYWJsZXMgYXJlIGFzIGZvbGxvd3M6DQoNCmBgYHtyfQ0KIyBDcmVhdGUgYW4gaW50ZXJhY3RpdmUgZGF0YSBkaWN0aW9uYXJ5DQpkYXRhX2RpY3Rpb25hcnkgPC0gdHJpYmJsZSgNCiAgflZhcmlhYmxlX05hbWUsICAgIH5EZXNjcmlwdGlvbiwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH5WYXJpYWJsZV9UeXBlLA0KICAiWyIsICAgICAgICAgICJbQnJpZWYgZGVzY3JpcHRpb24gb2YgdmFyaWFibGUgMSDigJQgd2hhdCBpdCBtZWFzdXJlcywgdW5pdHNdIiwgICAgICAgIltOdW1lcmljL0NhdGVnb3JpY2FsL0RhdGUvVGV4dF0iLA0KICAiW3ZhcjJdIiwgICAgICAgICAgIltCcmllZiBkZXNjcmlwdGlvbiBvZiB2YXJpYWJsZSAyIOKAlCB3aGF0IGl0IG1lYXN1cmVzLCBjYXRlZ29yaWVzXSIsICAiW051bWVyaWMvQ2F0ZWdvcmljYWwvRGF0ZS9UZXh0XSIsDQogICJbdmFyM10iLCAgICAgICAgICAiW0JyaWVmIGRlc2NyaXB0aW9uIG9mIHZhcmlhYmxlIDMg4oCUIHdoYXQgaXQgbWVhc3VyZXNdIiwgICAgICAgICAgICAgICJbTnVtZXJpYy9DYXRlZ29yaWNhbC9EYXRlL1RleHRdIiwNCiAgIlt2YXI0XSIsICAgICAgICAgICJbQnJpZWYgZGVzY3JpcHRpb24gb2YgdmFyaWFibGUgNCDigJQgd2hhdCBpdCBtZWFzdXJlcywgY2F0ZWdvcmllc10iLCAgIltOdW1lcmljL0NhdGVnb3JpY2FsL0RhdGUvVGV4dF0iDQogICMgQWRkIG1vcmUgcm93cyBhcyBuZWVkZWQNCikNCg0KZGF0YXRhYmxlKA0KICBkYXRhX2RpY3Rpb25hcnksDQogIGNhcHRpb24gPSAiVGFibGUgMTogVmFyaWFibGUgZGVmaW5pdGlvbnMgYW5kIHR5cGVzIGZvciB0aGUgYW5hbHlzaXMgZGF0YXNldCIsDQogIHJvd25hbWVzID0gRkFMU0UsDQogIG9wdGlvbnMgPSBsaXN0KHBhZ2VMZW5ndGggPSAxMCwgZG9tID0gJ3RpcCcpDQopDQpgYGANCg0KTmV4dCwgd2UgY2FuIGNoZWNrIGEgc3VtbWFyeSBvZiB0aGUgZGF0YSBzZXQ6DQpgYGB7cn0NCnN1bW1hcnkoZmxpZ2h0cykNCmBgYA0KSWYgd2UgcGF5IGNsb3NlIGF0dGVudGlvbiB0byB0aGUgc3VtbWFyeSwgYSByZWQgZmxhZyBpbW1lZGlhdGVseSBqdW1wcyBvdXQ6IFRoZSBtaW4gb2YgQ2xlYW5pbmdfbyBpcyBiZWxvdyAwLCBhbmQgc2luY2UgaXQncyBhIHRpbWUgdmFyaWFibGUsIGl0IGNhbid0IGhhdmUgdmFsdWVzIGJlbG93IDAuIFdlIGNhbiB2ZXJpZnkgaWYgaXQncyBhIG1pc3Rha2UgYnkgZWl0aGVyIHNvcnRpbmcgdGhlIHZhbHVlcyBvZiBDbGVhbmluZ19vIG9yIGJ5IHN1bW1pbmcgdXAgdGhlIHZhbHVlcyBvZiB0aGUgdmFyaWFibGUgdGhhdCBhcmUgbGVzcyB0aGFuIDAuIFRvIGtlZXAgb3V0cHV0IHNpbXBsaXN0aWMsIHdlIGNhbiBmaW5kIG91dCB3aGljaCBzcGVjaWZpYyBvYnNlcnZhdGlvbnMgaGF2ZSB2YWx1ZXMgb2YgQ2xlYW5pbmdfbyBvZiBsZXNzIHRoYW4gMCwgYXMgd2VsbCBhcyB0aGVpciByZXNwZWN0aXZlIHZhbHVlcy4NCg0KYGBge3J9DQp3aGljaChmbGlnaHRzJENsZWFuaW5nX28gPCAwKQ0KZmxpZ2h0cyRDbGVhbmluZ19vW2MoNjI0LCAxMjQzLCAyMzU3LCAyNjg0LCAyNzg2KV0NCmBgYA0KSXQgYXBwZWFycyB0aGF0IHdlIG9ubHkgaGF2ZSA1IG9ic2VydmF0aW9ucyB0aGF0IGhhdmUgdmFsdWVzIGxlc3MgdGhhbiAwLiBGb3IgdGhpcyByZXBvcnQsIGkgd2lsbCBhc3N1bWUgdGhhdCB0aGV5IHByb2JhYmx5IHdlcmUganVzdCBlbnRyeSBtaXN0YWtlcyBhbmQgd2lsbCBtdWx0aXBseSB0aGVtIGJ5IC0xIHRvIG1ha2UgdGhlbSBwb3NpdGl2ZSBzbyB0aGF0IG5vIG9ic2VydmF0aW9ucyBoYXZlIHRvIGJlIGRyb3BwZWQuDQoNCmBgYHtyfQ0KZmxpZ2h0cyRDbGVhbmluZ19vIDwtIGlmZWxzZShmbGlnaHRzJENsZWFuaW5nX28gPCAwLCBmbGlnaHRzJENsZWFuaW5nX28qLTEsIGZsaWdodHMkQ2xlYW5pbmdfbykNCmBgYA0KDQpUbyB2ZXJpZnkgdGhhdCB0aGUgY2hhbmdlIHdvcmtlZCwgd2UgY2FuIHVzZSB0aGUgc29ydCgpIGZ1bmN0aW9uOg0KYGBge3J9DQpoZWFkKHNvcnQoZmxpZ2h0cyRDbGVhbmluZ19vKSkNCmBgYA0KVGhlIGNoYW5nZSB3b3JrZWQuIFdlIHdpbGwgY29udGludWUgd2l0aCBkYXRhIHByZXBhcmF0aW9uLiANCg0KIyMgTWlzc2luZyBWYWx1ZXMNCk5leHQgd2Ugd2lsbCBjaGVjayBmb3IgbWlzc2luZyB2YWx1ZXMuIE1pc3NpbmcgdmFsdWVzLCBlc3BlY2lhbGx5IGxhcmdlIGFtb3VudHMgb2YgdGhlbSwgY2FuIGNvbXBsaWNhdGUgYW5hbHlzaXMgYW5kIGxlYWQgdG8gaW5jb3JyZWN0IHJlc3VsdHMgYW5kIGNvbmNsdXNpb25zLg0KDQpUaGUgc3VtbWFyeSBvZiB0aGUgZGF0YSBzZXQgdGhhdCB3YXMgcmFuIGVhcmxpZXIgc2hvd3MgdGhhdCB0aGVyZSBhcmUgbm8gbWlzc2luZyB2YWx1ZXMuIFRvIHZlcmlmeSwgd2UgY2FuIGdlbmVyYXRlIGEgbG9sbGlwb3AgcGxvdCBvZiBtaXNzaW5nIHZhbHVlcyB0byBhbmQgcnVuIHRoZSBzdW0oKSBhbmQgaXMubmEoKSBmdW5jdGlvbnMgdG8gY2hlY2sgaG93IG1hbnkgbWlzc2luZyB2YWx1ZXMgYXJlIGluIHRoZSBkYXRhIHNldC4NCg0KYGBge3J9DQojIEFkZCBVcCBUb3RhbCBNaXNzaW5nIFZhbHVlcyANCg0KIyBDaGVjayBmb3IgTWlzc2luZyBWYWx1ZXMNCnN1bShpcy5uYShmbGlnaHRzKSkNCmBgYA0KDQpUaGUgc3VtIG9mIG1pc3NpbmcgdmFsdWVzIGlzIDAsIHdoaWNoIG1lYW5zIHRoZXJlIGFyZSBubyBtaXNzaW5nIHZhbHVlcyBpbiB0aGUgZGF0YSBzZXQuIE5leHQsIGxldCdzIGdlbmVyYXRlIHRoZSBsb2xsaXBvcCBwbG90IHVzaW5nIHRoZSBnZ19taXNzX3ZhcigpIGZ1bmN0aW9uIGZyb20gdGhlIGBuYW5pYXJgIHBhY2thZ2U6DQpgYGB7cn0NCiMgR2VuZXJhdGUgTG9sbGlwb3AgUGxvdCANCg0KIyBsaWJyYXJ5KG5hbmlhcikNCm1pc3MgPC0gZ2dfbWlzc192YXIoZmxpZ2h0cykgKyANCiAgbGFicyh0aXRsZSA9ICJNaXNzaW5nIFZhbHVlcyBQZXIgVmFyaWFibGUiKSArDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpLA0KICAgICAgICBwbG90Lm1hcmdpbiA9IG1hcmdpbih0ID0gMzUsIHIgPSAxMCwgYiA9IDI1LCBsID0gMzApKQ0KZ2dwbG90bHkobWlzcykNCmBgYA0KQWxsIG9mIHRoZSBkb3RzIG9uIGFyZSBvbiAwLCBhbmQgdGhlcmUgZG9lcyBub3QgYXBwZWFyIHRvIGJlIGFueSBzdGVtcy4gU28gaXQncyBzYWZlIHRvIHNheSB0aGF0IHdlIGhhdmUgYSBjbGVhbiBkYXRhIHNldC4NCg0KSW4gdGhlIGV2ZW50IHRoYXQgbWlzc2luZyB2YWx1ZXMgd2VyZSBwcmVzZW50LCB0aGV5IGNvdWxkIGVpdGhlciBqdXN0IGJlIGRyb3BwZWQgZnJvbSB0aGUgZGF0YSBzZXQgb3IgaW1wdXRlZCBpbiBzb21lIHdheS4NCg0KIyMgVmFyaWFibGUgU2NyZWVuaW5nDQpBY2NvcmRpbmcgdG8gR3VwdGEsIHRoZSByZWFzb25zIGFpcmxpbmVzIHJlcG9ydCBmb3IgZGVsYXlzIGZhbGwgaW50byA1IGJyb2FkIGNhdGVnb3JpZXM6DQoNCioqKkV4dHJlbWUgV2VhdGhlcjoqKiogV2hlbiBleHRyZW1lIHdlYXRoZXIgY29uZGl0aW9ucyBsaWtlIGh1cnJpY2FuZXMgb3IgdG9ybmFkb2VzIG9jY3VyLCBvciB3aGVuIGNvbmRpdGlvbnMgYXJlIG5vdCBpZGVhbCBsaWtlIGluIGEgc25vdyBzdG9ybSwgZmxpZ2h0cyBvZnRlbiBoYXZlIHRvIGNoYW5nZSBzY2hlZHVsZXMsIHdoaWNoIHJlc3VsdHMgaW4gZGVsYXlzIG9yIGNhbmNlbGxhdGlvbnMuDQoNCioqKkxhdGUgQXJyaXZhbDoqKiogVGhpcyBpcyB0aGUgcHJvYmxlbSBhaXJsaW5lcyByZXBvcnQgbW9zdCBvZnRlbi4gV2hlbiBhbiBhaXJwbGFuZSBtYWtlcyBtdWx0aXBsZSBmbGlnaHRzIGFuZCBqdXN0IGV2ZW4gb25lIHRpbWUgYXJyaXZlcyBsYXRlLCBpdCBjYW4gbWFrZSBvdGhlciBmbGlnaHRzIHVzaW5nIHRoZSBzYW1lIHBsYW5lIGxhdGUsIHdoaWNoIHdpbGwgaW5ldml0YWJseSBjYXVzZSBkZWxheXMuDQoNCioqKkFpciBDYXJyaWVyOioqKiBSZWFzb25zIHN1Y2ggYXMgYWlyY3JhZnQgbWFpbnRlbmFuY2UgaXNzdWVzLCBjbGVhbmluZywgYmFnZ2FnZSBsb2FkaW5nLCBmdWVsaW5nLCBhbmQgb3RoZXJzIGNvbnRyaWJ1dGUgdG8gdGhlIGRlbGF5cyBvciBjYW5jZWxsYXRpb25zIHRoYXQgb2NjdXIuDQoNCioqKlNlY3VyaXR5OioqKiBSZWFzb25zIHN1Y2ggYXMgaW5vcGVyYXRpdmUgc2NyZWVuaW5nIGVxdXBpbWVudCwgbG9uZyBxdWV1ZXMgaW4gc2NyZWVuaW5nIGFyZWFzLCByZWJvYXJkaW5nIG9mIGFpcmNyYWZ0LCBhbmQgbW9yZSBjb250cmlidXRlIHRvIGZsaWdodCBkZWxheXMuDQoNCioqKk5hdGlvbmFsIEF2aWF0aW9uIFN5c3RlbSAoTkFTKToqKiogQWlycG9ydCBvcGVyYXRpb25zLCBoZWF2eSB2b2x1bWUvdHJhZmZpYywgYWlyIHRyYWZmaWMgY29udHJvbCBhbmQgbW9yZSBjYW4gY29udHJpYnV0ZSB0byBmbGlnaHQgZGVsYXlzIGFuZCBjYW5jZWxsYXRpb25zLg0KDQpJdCBzZWVtcyB0aGF0IGFsbCBvZiBvdXIgYmFzZXMgYXJlIGNvdmVyZWQgd2l0aCB0aGUgdmFyaWFibGVzIGdlbmVyYXRlZCBmb3IgdGhlIGRhdGEgc2V0LiBTbyBmb3Igbm93LCB3ZSB3b24ndCBhZGQgb3IgZHJvcCBhbnkgdmFyaWFibGVzLiBIb3dldmVyLCBzaW5jZSB3ZWF0aGVyIGlzIGEgcmF0aW5nIHZhcmlhYmxlLCBhbmQgc2VlbXMgdG8gb25seSBoYXZlIHZhbHVlcyBvZiBlaXRoZXIgNSBvciA2IChkZXNwaXRlIGJlaW5nIG9uIGEgcmF0aW5nIHNjYWxlIG9mIDAtMTApLCBJIHdpbGwgY29udmVydCB0aGF0IHZhcmlhYmxlIGludG8gYSBmYWN0b3I6DQpgYGB7cn0NCmZsaWdodHMkV2VhdGhlciA8LSBmYWN0b3IoZmxpZ2h0cyRXZWF0aGVyLCBvcmRlcmVkID0gVFJVRSkNCmBgYA0KDQpUaGUgZGF0YSBpcyBub3cgcHJlcGFyZWQgZm9yIGFuYWx5c2lzLiBBbmFseXNpcyB3aWxsIGJlIGRvbmUgdmlhIHZpc3VhbGl6YXRpb24gYW5kIHJlZ3Jlc3Npb24uIFRvIGRvIHNvLCB3ZSB3aWxsIHR1cm4gb3VyIGF0dGVudGlvbiB0byBhIHNoaW55YXBwIGRhc2hib2FyZCBidWlsdCBzcGVjaWZpY2FsbHkgYnVpbHQgZm9yIHRoZSBhbmFseXNpcyBvZiB0aGlzIGRhdGEgc2V0Lg0KDQojIFZpc3VhbCBFeHBsb3JhdG9yeSBEYXRhIEFuYWx5c2lzDQpUaGlzIHNlY3Rpb24gb2YgdGhlIHJlcG9ydCB3aWxsIGZvY3VzIG9uIGV4cGxvcmF0b3J5IGRhdGEgYW5hbHlzaXMuIEluIHRoaXMgc2VjdGlvbiwgd2Ugd2lsbCBwbG90IHZhcmlhYmxlIGRpc3RyaWJ1dGlvbnMgYW5kIGV4cGxvcmUgcmVsYXRpb25zaGlwcyBiZXR3ZWVuIHZhcmlhYmxlcy4gVGhpcyBwb3J0aW9uIGFuZCB0aGUgcmVncmVzc2lvbiBwb3J0aW9uIHdpbGwgcmVseSBlbnRpcmVseSBvbiB0aGUgc2hpbnlhcHAgZGFzaGJvYXJkIGJ1aWx0IGZvciB0aGlzIGRhdGEgc2V0LiA=