library(tidyverse)
library(openintro)
library(nycflights13)
library(DT)
Introduction
This report explores patterns of flight delays and cancellations in
the flights dataset from the nycflights13 R package. It will
investigate dates and times during 2013 when a large percentage of
flights were either canceled or delayed by more than one hour. After
identifying these problematic periods, this report will compare them to
historical New York weather data to see if those weather events explain
the flights’ disruptions.
The flights dataset contains 336,776 flights departing from
New York City (JFK, LGA or EWR) in 2013 and has 19 variables for each
flight; the relevant ones are: year, month, day (date of departure),
dep_time and arr_time (actual departure and arrival times),
sched_dep_time and sched_arr_time (scheduled departure and arrival
times), dep_delay and arr_delay (departure and arrival delay, in
minutes. Negative times represent early departures/arrivals), carrier
(Two letter carrier abbreviaition for airlines), flight (flight number),
origin(airport of departure), dest (destination airport), air_time
(amount of time spent in the air, in minutes), and distance (distance
between airports, in miles).
Identifying Problematic Dates
This problem will find the days in 2013 where more than 35% of
flights were cancelled or delayed by more than one hour.
flights_delayed_35 <- flights %>%
mutate(del_can_flights = is.na(dep_delay) | dep_delay > 60) %>%
group_by(year, month, day) %>%
summarize(perc_del_can_flights = mean(del_can_flights, na.rm = TRUE), .groups = "keep") %>%
filter(perc_del_can_flights > 0.35)
datatable(flights_delayed_35, options = list(scrollX = TRUE))
Weather Context of New York 2013
In February there was a major weather event called the Winter Storm
Nemo, which brought terrible blizzard conditions to the northeast and
affected the flights on the 8th and 9th. Just like in February, on March
8 there was a snowstorm that brought about a couple feet of snow along
with very low visibility. The weather in July, September, and December
was not quite as extreme as the other ones because there was just rain
and fog during the days the flights were either delayed or canceled.
Based off of these findings, it makes sense that a lot of these flights
were either canceled or delayed by more than one hour.
Flight Disruptions by Time of Day
This problem looks to group the flights by the hour they were
scheduled to depart and figure out the percentage of those flights that
were cancelled or delayed.
flights_by_hour <- flights %>%
mutate(del_can_flights = is.na(dep_delay) | dep_delay > 60) %>%
group_by(hour) %>%
summarize(perc_del_can_flights = mean(del_can_flights, na.rm = TRUE))
datatable(flights_by_hour, options = list(scrollX = TRUE))
Visualization of Flight Disruptions by Time of Day
ggplot(data = flights_by_hour, aes(x = hour, y = perc_del_can_flights*100)) +
geom_line() +
geom_point() +
labs(
title = "Percentage of Flight Cancellations/Long Delays by Hour of Day",
x = "Scheduled Departure Hour",
y = "Percent Canceled/Long Delayed Flights"
)

The plot, at a glance, has a skewness to the left with an outlier at
100% of flights being canceled or delayed. This outlier happened at 1 in
the morning and is the only flight scheduled to depart at this time,
which was canceled and the reason for the 100%. Looking at the overall
shape of the flights by hour of day, it would appear that later flights
(5-9pm) have a higher chance of being delayed longer or canceled than
morning flights (5-10am). It would make sense for the later flights to
have this pattern because any delays from previous flights would then be
accumulated into the later flights and the weather could change
throughout the day, creating conditions unsuitable to depart on
time.
On-Time Flights on Problematic Dates
on_time_flights <- flights %>%
group_by(year, month, day) %>%
mutate(perc_del_can_flights = mean(is.na(dep_delay) | dep_delay > 60, na.rm = TRUE)) %>%
filter(perc_del_can_flights > 0.35 & !is.na(dep_delay) & dep_delay <= 0)
datatable(on_time_flights, options = list(scrollX = TRUE))
This data set only shows the flights that departured early or on-time
during the problematic dates we found in the first problem.
Average Scheduled Departure Hour for Problematic Dates that are
On-Time
avg_dep_hour <- on_time_flights %>%
group_by(year, month, day) %>%
summarize(avg_sched_hour = mean(hour, na.rm = TRUE), .groups = "keep")
datatable(avg_dep_hour, options = list(scrollX = TRUE))
Looking at this table, we can see that the average scheduled
departure hour (ASDH) for flights on each day was before noon. This
confirms the guess that flights on problematic dates are able to depart
early or on time if they left in the morning. The only date that had an
ASDH in the afternoon was February 9, 2013. This date had flights
scheduled for departure at hour 16 on average and this is mainly due to
the weather that happened during that date. As stated above, during the
8th and 9th of February was the Winter Storm Nemo which carried
blizzards up the Northeast side of the United States and into Canada.
This terrible weather made later flights on the 8th get canceled and
morning flights were canceled on the 9th until enough snow on the ground
was cleared and the storm passes by during the day.
Conclusion
In summary, we can conclude through our findings that major weather
events and the cancellation or delay of flights in 2013 are related to
each other. After researching the weather forecast on the problematic
dates found, we can see that heavy snow storms or rain were the main
causes for affecting these flights’ departure time. We can also conclude
that earlier flights have less risk of delay or cancellation than later
flights do because there is less risk of weather getting worse over time
or the possible accumulation of previous delays.
…
LS0tDQp0aXRsZTogIkZsaWdodCBEZWxheXMgYW5kIENhbmNlbGxhdGlvbnMiDQphdXRob3I6ICJWaWt0b3IgQ2hodW4iDQpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiDQpvdXRwdXQ6IG9wZW5pbnRybzo6bGFiX3JlcG9ydA0KLS0tDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFKQ0KYGBgDQoNCmBgYHtyIGxvYWQtcGFja2FnZXMsIG1lc3NhZ2U9RkFMU0V9DQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkob3BlbmludHJvKQ0KbGlicmFyeShueWNmbGlnaHRzMTMpDQpsaWJyYXJ5KERUKQ0KYGBgDQoNCiMjIEludHJvZHVjdGlvbg0KDQpUaGlzIHJlcG9ydCBleHBsb3JlcyBwYXR0ZXJucyBvZiBmbGlnaHQgZGVsYXlzIGFuZCBjYW5jZWxsYXRpb25zIGluIHRoZSBfZmxpZ2h0c18gZGF0YXNldCBmcm9tIHRoZSBueWNmbGlnaHRzMTMgUiBwYWNrYWdlLiBJdCB3aWxsIGludmVzdGlnYXRlIGRhdGVzIGFuZCB0aW1lcyBkdXJpbmcgMjAxMyB3aGVuIGEgbGFyZ2UgcGVyY2VudGFnZSBvZiBmbGlnaHRzIHdlcmUgZWl0aGVyIGNhbmNlbGVkIG9yIGRlbGF5ZWQgYnkgbW9yZSB0aGFuIG9uZSBob3VyLiBBZnRlciBpZGVudGlmeWluZyB0aGVzZSBwcm9ibGVtYXRpYyBwZXJpb2RzLCB0aGlzIHJlcG9ydCB3aWxsIGNvbXBhcmUgdGhlbSB0byBoaXN0b3JpY2FsIE5ldyBZb3JrIHdlYXRoZXIgZGF0YSB0byBzZWUgaWYgdGhvc2Ugd2VhdGhlciBldmVudHMgZXhwbGFpbiB0aGUgZmxpZ2h0cycgZGlzcnVwdGlvbnMuIA0KDQpUaGUgX2ZsaWdodHNfIGRhdGFzZXQgY29udGFpbnMgMzM2LDc3NiBmbGlnaHRzIGRlcGFydGluZyBmcm9tIE5ldyBZb3JrIENpdHkgKEpGSywgTEdBIG9yIEVXUikgaW4gMjAxMyBhbmQgaGFzIDE5IHZhcmlhYmxlcyBmb3IgZWFjaCBmbGlnaHQ7IHRoZSByZWxldmFudCBvbmVzIGFyZTogeWVhciwgbW9udGgsIGRheSAoZGF0ZSBvZiBkZXBhcnR1cmUpLCBkZXBfdGltZSBhbmQgYXJyX3RpbWUgKGFjdHVhbCBkZXBhcnR1cmUgYW5kIGFycml2YWwgdGltZXMpLCBzY2hlZF9kZXBfdGltZSBhbmQgc2NoZWRfYXJyX3RpbWUgKHNjaGVkdWxlZCBkZXBhcnR1cmUgYW5kIGFycml2YWwgdGltZXMpLCBkZXBfZGVsYXkgYW5kIGFycl9kZWxheSAoZGVwYXJ0dXJlIGFuZCBhcnJpdmFsIGRlbGF5LCBpbiBtaW51dGVzLiBOZWdhdGl2ZSB0aW1lcyByZXByZXNlbnQgZWFybHkgZGVwYXJ0dXJlcy9hcnJpdmFscyksIGNhcnJpZXIgKFR3byBsZXR0ZXIgY2FycmllciBhYmJyZXZpYWl0aW9uIGZvciBhaXJsaW5lcyksIGZsaWdodCAoZmxpZ2h0IG51bWJlciksIG9yaWdpbihhaXJwb3J0IG9mIGRlcGFydHVyZSksIGRlc3QgKGRlc3RpbmF0aW9uIGFpcnBvcnQpLCBhaXJfdGltZSAoYW1vdW50IG9mIHRpbWUgc3BlbnQgaW4gdGhlIGFpciwgaW4gbWludXRlcyksIGFuZCBkaXN0YW5jZSAoZGlzdGFuY2UgYmV0d2VlbiBhaXJwb3J0cywgaW4gbWlsZXMpLiANCg0KIyMgSWRlbnRpZnlpbmcgUHJvYmxlbWF0aWMgRGF0ZXMNCg0KVGhpcyBwcm9ibGVtIHdpbGwgZmluZCB0aGUgZGF5cyBpbiAyMDEzIHdoZXJlIG1vcmUgdGhhbiAzNSUgb2YgZmxpZ2h0cyB3ZXJlIGNhbmNlbGxlZCBvciBkZWxheWVkIGJ5IG1vcmUgdGhhbiBvbmUgaG91ci4gDQoNCmBgYHtyfQ0KZmxpZ2h0c19kZWxheWVkXzM1IDwtIGZsaWdodHMgJT4lIA0KICBtdXRhdGUoZGVsX2Nhbl9mbGlnaHRzID0gaXMubmEoZGVwX2RlbGF5KSB8IGRlcF9kZWxheSA+IDYwKSAlPiUgDQogIGdyb3VwX2J5KHllYXIsIG1vbnRoLCBkYXkpICU+JSANCiAgc3VtbWFyaXplKHBlcmNfZGVsX2Nhbl9mbGlnaHRzID0gbWVhbihkZWxfY2FuX2ZsaWdodHMsIG5hLnJtID0gVFJVRSksIC5ncm91cHMgPSAia2VlcCIpICU+JSANCiAgZmlsdGVyKHBlcmNfZGVsX2Nhbl9mbGlnaHRzID4gMC4zNSkNCg0KZGF0YXRhYmxlKGZsaWdodHNfZGVsYXllZF8zNSwgb3B0aW9ucyA9IGxpc3Qoc2Nyb2xsWCA9IFRSVUUpKQ0KYGBgDQoNCiMjIFdlYXRoZXIgQ29udGV4dCBvZiBOZXcgWW9yayAyMDEzDQoNCkluIEZlYnJ1YXJ5IHRoZXJlIHdhcyBhIG1ham9yIHdlYXRoZXIgZXZlbnQgY2FsbGVkIHRoZSBXaW50ZXIgU3Rvcm0gTmVtbywgd2hpY2ggYnJvdWdodCB0ZXJyaWJsZSBibGl6emFyZCBjb25kaXRpb25zIHRvIHRoZSBub3J0aGVhc3QgYW5kIGFmZmVjdGVkIHRoZSBmbGlnaHRzIG9uIHRoZSA4dGggYW5kIDl0aC4gSnVzdCBsaWtlIGluIEZlYnJ1YXJ5LCBvbiBNYXJjaCA4IHRoZXJlIHdhcyBhIHNub3dzdG9ybSB0aGF0IGJyb3VnaHQgYWJvdXQgYSBjb3VwbGUgZmVldCBvZiBzbm93IGFsb25nIHdpdGggdmVyeSBsb3cgdmlzaWJpbGl0eS4gVGhlIHdlYXRoZXIgaW4gSnVseSwgU2VwdGVtYmVyLCBhbmQgRGVjZW1iZXIgd2FzIG5vdCBxdWl0ZSBhcyBleHRyZW1lIGFzIHRoZSBvdGhlciBvbmVzIGJlY2F1c2UgdGhlcmUgd2FzIGp1c3QgcmFpbiBhbmQgZm9nIGR1cmluZyB0aGUgZGF5cyB0aGUgZmxpZ2h0cyB3ZXJlIGVpdGhlciBkZWxheWVkIG9yIGNhbmNlbGVkLiBCYXNlZCBvZmYgb2YgdGhlc2UgZmluZGluZ3MsIGl0IG1ha2VzIHNlbnNlIHRoYXQgYSBsb3Qgb2YgdGhlc2UgZmxpZ2h0cyB3ZXJlIGVpdGhlciBjYW5jZWxlZCBvciBkZWxheWVkIGJ5IG1vcmUgdGhhbiBvbmUgaG91ci4NCg0KIyMgRmxpZ2h0IERpc3J1cHRpb25zIGJ5IFRpbWUgb2YgRGF5DQoNClRoaXMgcHJvYmxlbSBsb29rcyB0byBncm91cCB0aGUgZmxpZ2h0cyBieSB0aGUgaG91ciB0aGV5IHdlcmUgc2NoZWR1bGVkIHRvIGRlcGFydCBhbmQgZmlndXJlIG91dCB0aGUgcGVyY2VudGFnZSBvZiB0aG9zZSBmbGlnaHRzIHRoYXQgd2VyZSBjYW5jZWxsZWQgb3IgZGVsYXllZC4NCg0KYGBge3J9DQpmbGlnaHRzX2J5X2hvdXIgPC0gZmxpZ2h0cyAlPiUgDQogIG11dGF0ZShkZWxfY2FuX2ZsaWdodHMgPSBpcy5uYShkZXBfZGVsYXkpIHwgZGVwX2RlbGF5ID4gNjApICU+JSANCiAgZ3JvdXBfYnkoaG91cikgJT4lIA0KICBzdW1tYXJpemUocGVyY19kZWxfY2FuX2ZsaWdodHMgPSBtZWFuKGRlbF9jYW5fZmxpZ2h0cywgbmEucm0gPSBUUlVFKSkNCg0KZGF0YXRhYmxlKGZsaWdodHNfYnlfaG91ciwgb3B0aW9ucyA9IGxpc3Qoc2Nyb2xsWCA9IFRSVUUpKQ0KYGBgDQoNCiMjIFZpc3VhbGl6YXRpb24gb2YgRmxpZ2h0IERpc3J1cHRpb25zIGJ5IFRpbWUgb2YgRGF5DQoNCmBgYHtyfQ0KZ2dwbG90KGRhdGEgPSBmbGlnaHRzX2J5X2hvdXIsIGFlcyh4ID0gaG91ciwgeSA9IHBlcmNfZGVsX2Nhbl9mbGlnaHRzKjEwMCkpICsgDQogIGdlb21fbGluZSgpICsgDQogIGdlb21fcG9pbnQoKSArIA0KICBsYWJzKA0KICAgIHRpdGxlID0gIlBlcmNlbnRhZ2Ugb2YgRmxpZ2h0IENhbmNlbGxhdGlvbnMvTG9uZyBEZWxheXMgYnkgSG91ciBvZiBEYXkiLA0KICAgIHggPSAiU2NoZWR1bGVkIERlcGFydHVyZSBIb3VyIiwNCiAgICB5ID0gIlBlcmNlbnQgQ2FuY2VsZWQvTG9uZyBEZWxheWVkIEZsaWdodHMiDQogICkNCmBgYA0KDQpUaGUgcGxvdCwgYXQgYSBnbGFuY2UsIGhhcyBhIHNrZXduZXNzIHRvIHRoZSBsZWZ0IHdpdGggYW4gb3V0bGllciBhdCAxMDAlIG9mIGZsaWdodHMgYmVpbmcgY2FuY2VsZWQgb3IgZGVsYXllZC4gVGhpcyBvdXRsaWVyIGhhcHBlbmVkIGF0IDEgaW4gdGhlIG1vcm5pbmcgYW5kIGlzIHRoZSBvbmx5IGZsaWdodCBzY2hlZHVsZWQgdG8gZGVwYXJ0IGF0IHRoaXMgdGltZSwgd2hpY2ggd2FzIGNhbmNlbGVkIGFuZCB0aGUgcmVhc29uIGZvciB0aGUgMTAwJS4gTG9va2luZyBhdCB0aGUgb3ZlcmFsbCBzaGFwZSBvZiB0aGUgZmxpZ2h0cyBieSBob3VyIG9mIGRheSwgaXQgd291bGQgYXBwZWFyIHRoYXQgbGF0ZXIgZmxpZ2h0cyAoNS05cG0pIGhhdmUgYSBoaWdoZXIgY2hhbmNlIG9mIGJlaW5nIGRlbGF5ZWQgbG9uZ2VyIG9yIGNhbmNlbGVkIHRoYW4gbW9ybmluZyBmbGlnaHRzICg1LTEwYW0pLiBJdCB3b3VsZCBtYWtlIHNlbnNlIGZvciB0aGUgbGF0ZXIgZmxpZ2h0cyB0byBoYXZlIHRoaXMgcGF0dGVybiBiZWNhdXNlIGFueSBkZWxheXMgZnJvbSBwcmV2aW91cyBmbGlnaHRzIHdvdWxkIHRoZW4gYmUgYWNjdW11bGF0ZWQgaW50byB0aGUgbGF0ZXIgZmxpZ2h0cyBhbmQgdGhlIHdlYXRoZXIgY291bGQgY2hhbmdlIHRocm91Z2hvdXQgdGhlIGRheSwgY3JlYXRpbmcgY29uZGl0aW9ucyB1bnN1aXRhYmxlIHRvIGRlcGFydCBvbiB0aW1lLiANCg0KIyMgT24tVGltZSBGbGlnaHRzIG9uIFByb2JsZW1hdGljIERhdGVzDQoNCmBgYHtyfQ0Kb25fdGltZV9mbGlnaHRzIDwtIGZsaWdodHMgJT4lIA0KICBncm91cF9ieSh5ZWFyLCBtb250aCwgZGF5KSAlPiUNCiAgbXV0YXRlKHBlcmNfZGVsX2Nhbl9mbGlnaHRzID0gbWVhbihpcy5uYShkZXBfZGVsYXkpIHwgZGVwX2RlbGF5ID4gNjAsIG5hLnJtID0gVFJVRSkpICU+JQ0KICBmaWx0ZXIocGVyY19kZWxfY2FuX2ZsaWdodHMgPiAwLjM1ICYgIWlzLm5hKGRlcF9kZWxheSkgJiBkZXBfZGVsYXkgPD0gMCkNCg0KZGF0YXRhYmxlKG9uX3RpbWVfZmxpZ2h0cywgb3B0aW9ucyA9IGxpc3Qoc2Nyb2xsWCA9IFRSVUUpKQ0KYGBgDQoNClRoaXMgZGF0YSBzZXQgb25seSBzaG93cyB0aGUgZmxpZ2h0cyB0aGF0IGRlcGFydHVyZWQgZWFybHkgb3Igb24tdGltZSBkdXJpbmcgdGhlIHByb2JsZW1hdGljIGRhdGVzIHdlIGZvdW5kIGluIHRoZSBmaXJzdCBwcm9ibGVtLiANCg0KIyMgQXZlcmFnZSBTY2hlZHVsZWQgRGVwYXJ0dXJlIEhvdXIgZm9yIFByb2JsZW1hdGljIERhdGVzIHRoYXQgYXJlIE9uLVRpbWUNCg0KYGBge3J9DQphdmdfZGVwX2hvdXIgPC0gb25fdGltZV9mbGlnaHRzICU+JSANCiAgZ3JvdXBfYnkoeWVhciwgbW9udGgsIGRheSkgJT4lIA0KICBzdW1tYXJpemUoYXZnX3NjaGVkX2hvdXIgPSBtZWFuKGhvdXIsIG5hLnJtID0gVFJVRSksIC5ncm91cHMgPSAia2VlcCIpDQoNCmRhdGF0YWJsZShhdmdfZGVwX2hvdXIsIG9wdGlvbnMgPSBsaXN0KHNjcm9sbFggPSBUUlVFKSkNCmBgYA0KDQpMb29raW5nIGF0IHRoaXMgdGFibGUsIHdlIGNhbiBzZWUgdGhhdCB0aGUgYXZlcmFnZSBzY2hlZHVsZWQgZGVwYXJ0dXJlIGhvdXIgKEFTREgpIGZvciBmbGlnaHRzIG9uIGVhY2ggZGF5IHdhcyBiZWZvcmUgbm9vbi4gVGhpcyBjb25maXJtcyB0aGUgZ3Vlc3MgdGhhdCBmbGlnaHRzIG9uIHByb2JsZW1hdGljIGRhdGVzIGFyZSBhYmxlIHRvIGRlcGFydCBlYXJseSBvciBvbiB0aW1lIGlmIHRoZXkgbGVmdCBpbiB0aGUgbW9ybmluZy4gVGhlIG9ubHkgZGF0ZSB0aGF0IGhhZCBhbiBBU0RIIGluIHRoZSBhZnRlcm5vb24gd2FzIEZlYnJ1YXJ5IDksIDIwMTMuIFRoaXMgZGF0ZSBoYWQgZmxpZ2h0cyBzY2hlZHVsZWQgZm9yIGRlcGFydHVyZSBhdCBob3VyIDE2IG9uIGF2ZXJhZ2UgYW5kIHRoaXMgaXMgbWFpbmx5IGR1ZSB0byB0aGUgd2VhdGhlciB0aGF0IGhhcHBlbmVkIGR1cmluZyB0aGF0IGRhdGUuIEFzIHN0YXRlZCBhYm92ZSwgZHVyaW5nIHRoZSA4dGggYW5kIDl0aCBvZiBGZWJydWFyeSB3YXMgdGhlIFdpbnRlciBTdG9ybSBOZW1vIHdoaWNoIGNhcnJpZWQgYmxpenphcmRzIHVwIHRoZSBOb3J0aGVhc3Qgc2lkZSBvZiB0aGUgVW5pdGVkIFN0YXRlcyBhbmQgaW50byBDYW5hZGEuIFRoaXMgdGVycmlibGUgd2VhdGhlciBtYWRlIGxhdGVyIGZsaWdodHMgb24gdGhlIDh0aCBnZXQgY2FuY2VsZWQgYW5kIG1vcm5pbmcgZmxpZ2h0cyB3ZXJlIGNhbmNlbGVkIG9uIHRoZSA5dGggdW50aWwgZW5vdWdoIHNub3cgb24gdGhlIGdyb3VuZCB3YXMgY2xlYXJlZCBhbmQgdGhlIHN0b3JtIHBhc3NlcyBieSBkdXJpbmcgdGhlIGRheS4gDQoNCiMjIENvbmNsdXNpb24NCg0KSW4gc3VtbWFyeSwgd2UgY2FuIGNvbmNsdWRlIHRocm91Z2ggb3VyIGZpbmRpbmdzIHRoYXQgbWFqb3Igd2VhdGhlciBldmVudHMgYW5kIHRoZSBjYW5jZWxsYXRpb24gb3IgZGVsYXkgb2YgZmxpZ2h0cyBpbiAyMDEzIGFyZSByZWxhdGVkIHRvIGVhY2ggb3RoZXIuIEFmdGVyIHJlc2VhcmNoaW5nIHRoZSB3ZWF0aGVyIGZvcmVjYXN0IG9uIHRoZSBwcm9ibGVtYXRpYyBkYXRlcyBmb3VuZCwgd2UgY2FuIHNlZSB0aGF0IGhlYXZ5IHNub3cgc3Rvcm1zIG9yIHJhaW4gd2VyZSB0aGUgbWFpbiBjYXVzZXMgZm9yIGFmZmVjdGluZyB0aGVzZSBmbGlnaHRzJyBkZXBhcnR1cmUgdGltZS4gV2UgY2FuIGFsc28gY29uY2x1ZGUgdGhhdCBlYXJsaWVyIGZsaWdodHMgaGF2ZSBsZXNzIHJpc2sgb2YgZGVsYXkgb3IgY2FuY2VsbGF0aW9uIHRoYW4gbGF0ZXIgZmxpZ2h0cyBkbyBiZWNhdXNlIHRoZXJlIGlzIGxlc3MgcmlzayBvZiB3ZWF0aGVyIGdldHRpbmcgd29yc2Ugb3ZlciB0aW1lIG9yIHRoZSBwb3NzaWJsZSBhY2N1bXVsYXRpb24gb2YgcHJldmlvdXMgZGVsYXlzLg0KDQouLi4=