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=