suppressPackageStartupMessages(library("tidyverse"))
package 㤼㸱tidyverse㤼㸲 was built under R version 3.6.3
suppressPackageStartupMessages(library("lubridate"))
suppressPackageStartupMessages(library("nycflights13"))
package 㤼㸱nycflights13㤼㸲 was built under R version 3.6.3
The following code from the chapter is used
make_datetime_100 <- function(year, month, day, time) {
make_datetime(year, month, day, time %/% 100, time %% 100)
}
flights_dt <- flights %>%
filter(!is.na(dep_time), !is.na(arr_time)) %>%
mutate(
dep_time = make_datetime_100(year, month, day, dep_time),
arr_time = make_datetime_100(year, month, day, arr_time),
sched_dep_time = make_datetime_100(year, month, day, sched_dep_time),
sched_arr_time = make_datetime_100(year, month, day, sched_arr_time)
) %>%
select(origin, dest, ends_with("delay"), ends_with("time"))
sched_dep <- flights_dt %>%
mutate(minute = minute(sched_dep_time)) %>%
group_by(minute) %>%
summarise(
avg_delay = mean(arr_delay, na.rm = TRUE),
n = n()
)
In the previous code, the difference between rounded and un-rounded dates provides the within-period time.
1. How does the distribution of flight times within a day change over the course of the year?
Let’s try plotting this by month:
flights_dt %>%
filter(!is.na(dep_time)) %>%
mutate(dep_hour = update(dep_time, yday = 1)) %>%
mutate(month = factor(month(dep_time))) %>%
ggplot(aes(dep_hour, color = month)) +
geom_freqpoly(binwidth = 60 * 60)

This will look better if everything is normalized within groups. The reason that February is lower is that there are fewer days and thus fewer flights.
flights_dt %>%
filter(!is.na(dep_time)) %>%
mutate(dep_hour = update(dep_time, yday = 1)) %>%
mutate(month = factor(month(dep_time))) %>%
ggplot(aes(dep_hour, color = month)) +
geom_freqpoly(aes(y = ..density..), binwidth = 60 * 60)

At least to me there doesn’t appear to much difference in within-day distribution over the year, but I maybe thinking about it incorrectly.
2. Compare dep_time
, sched_dep_time
and dep_delay
. Are they consistent? Explain your findings.
If they are consistent, then dep_time
= sched_dep_time
+ dep_delay
.
flights_dt %>%
mutate(dep_time_ = sched_dep_time + dep_delay * 60) %>%
filter(dep_time_ != dep_time) %>%
select(dep_time_, dep_time, sched_dep_time, dep_delay)
There exist discrepancies. It looks like there are mistakes in the dates. These are flights in which the actual departure time is on the next day relative to the scheduled departure time. We forgot to account for this when creating the date-times using make_datetime_100()
function. The code would have had to check if the departure time is less than the scheduled departure time plus departure delay (in minutes). Alternatively, simply adding the departure delay to the scheduled departure time is a more robust way to construct the departure time because it will automatically account for crossing into the next day.
3. Compare air_time
with the duration between the departure and arrival. Explain your findings.
flights_dt %>%
mutate(
flight_duration = as.numeric(arr_time - dep_time),
air_time_mins = air_time,
diff = flight_duration - air_time_mins
) %>%
select(origin, dest, flight_duration, air_time_mins, diff)
4. How does the average delay time change over the course of a day? Should you use dep_time
or sched_dep_time
? Why?
Use sched_dep_time
because that is the relevant metric for someone scheduling a flight. Also, using dep_time
will always bias delays to later in the day since delays will push flights later.
flights_dt %>%
mutate(sched_dep_hour = hour(sched_dep_time)) %>%
group_by(sched_dep_hour) %>%
summarise(dep_delay = mean(dep_delay)) %>%
ggplot(aes(y = dep_delay, x = sched_dep_hour)) +
geom_point() +
geom_smooth()

5. On what day of the week should you leave if you want to minimize the chance of a delay?
Saturday has the lowest average departure delay time and the lowest average arrival delay time.
flights_dt %>%
mutate(dow = wday(sched_dep_time)) %>%
group_by(dow) %>%
summarise(
dep_delay = mean(dep_delay),
arr_delay = mean(arr_delay, na.rm = TRUE)
) %>%
print(n = Inf)
flights_dt %>%
mutate(wday = wday(dep_time, label = TRUE)) %>%
group_by(wday) %>%
summarize(ave_dep_delay = mean(dep_delay, na.rm = TRUE)) %>%
ggplot(aes(x = wday, y = ave_dep_delay)) +
geom_bar(stat = "identity")

flights_dt %>%
mutate(wday = wday(dep_time, label = TRUE)) %>%
group_by(wday) %>%
summarize(ave_arr_delay = mean(arr_delay, na.rm = TRUE)) %>%
ggplot(aes(x = wday, y = ave_arr_delay)) +
geom_bar(stat = "identity")

6. What makes the distribution of diamonds$carat
and flights$sched_dep_time
similar?
ggplot(diamonds, aes(x = carat)) +
geom_density()

In both carat
and sched_dep_time
there are abnormally large numbers of values are at nice “human” numbers. In sched_dep_time
it is at 00 and 30 minutes. In carats, it is at 0, 1/3, 1/2, 2/3,
ggplot(diamonds, aes(x = carat %% 1 * 100)) +
geom_histogram(binwidth = 1)

In scheduled departure times it is 00 and 30 minutes, and minutes ending in 0 and 5.
ggplot(flights_dt, aes(x = minute(sched_dep_time))) +
geom_histogram(binwidth = 1)

7. Confirm my hypothesis that the early departures of flights in minutes 20-30 and 50-60 are caused by scheduled flights that leave early. Hint: create a binary variable that tells you whether or not a flight was delayed.
First, I create a binary variable early
that is equal to 1 if a flight leaves early, and 0 if it does not. Then, I group flights by the minute of departure. This shows that the proportion of flights that are early departures is highest between minutes 20–30 and 50–60.
flights_dt %>%
mutate(
minute = minute(dep_time),
early = dep_delay < 0
) %>%
group_by(minute) %>%
summarise(
early = mean(early, na.rm = TRUE),
n = n()
) %>%
ggplot(aes(minute, early)) +
geom_line()

LS0tDQp0aXRsZTogIkRhdGUtdGltZSBjb21wb25lbnRzIg0Kb3V0cHV0OiANCiAgaHRtbF9ub3RlYm9vazoNCiAgICB0b2M6IHRydWUNCiAgICB0b2NfZmxvYXQ6IHRydWUNCi0tLQ0KDQpgYGB7cn0NCnN1cHByZXNzUGFja2FnZVN0YXJ0dXBNZXNzYWdlcyhsaWJyYXJ5KCJ0aWR5dmVyc2UiKSkNCnN1cHByZXNzUGFja2FnZVN0YXJ0dXBNZXNzYWdlcyhsaWJyYXJ5KCJsdWJyaWRhdGUiKSkNCnN1cHByZXNzUGFja2FnZVN0YXJ0dXBNZXNzYWdlcyhsaWJyYXJ5KCJueWNmbGlnaHRzMTMiKSkNCmBgYA0KDQpUaGUgZm9sbG93aW5nIGNvZGUgZnJvbSB0aGUgY2hhcHRlciBpcyB1c2VkDQoNCmBgYHtyfQ0KbWFrZV9kYXRldGltZV8xMDAgPC0gZnVuY3Rpb24oeWVhciwgbW9udGgsIGRheSwgdGltZSkgew0KICBtYWtlX2RhdGV0aW1lKHllYXIsIG1vbnRoLCBkYXksIHRpbWUgJS8lIDEwMCwgdGltZSAlJSAxMDApDQp9DQoNCmZsaWdodHNfZHQgPC0gZmxpZ2h0cyAlPiUNCiAgZmlsdGVyKCFpcy5uYShkZXBfdGltZSksICFpcy5uYShhcnJfdGltZSkpICU+JQ0KICBtdXRhdGUoDQogICAgZGVwX3RpbWUgPSBtYWtlX2RhdGV0aW1lXzEwMCh5ZWFyLCBtb250aCwgZGF5LCBkZXBfdGltZSksDQogICAgYXJyX3RpbWUgPSBtYWtlX2RhdGV0aW1lXzEwMCh5ZWFyLCBtb250aCwgZGF5LCBhcnJfdGltZSksDQogICAgc2NoZWRfZGVwX3RpbWUgPSBtYWtlX2RhdGV0aW1lXzEwMCh5ZWFyLCBtb250aCwgZGF5LCBzY2hlZF9kZXBfdGltZSksDQogICAgc2NoZWRfYXJyX3RpbWUgPSBtYWtlX2RhdGV0aW1lXzEwMCh5ZWFyLCBtb250aCwgZGF5LCBzY2hlZF9hcnJfdGltZSkNCiAgKSAlPiUNCiAgc2VsZWN0KG9yaWdpbiwgZGVzdCwgZW5kc193aXRoKCJkZWxheSIpLCBlbmRzX3dpdGgoInRpbWUiKSkNCg0Kc2NoZWRfZGVwIDwtIGZsaWdodHNfZHQgJT4lDQogIG11dGF0ZShtaW51dGUgPSBtaW51dGUoc2NoZWRfZGVwX3RpbWUpKSAlPiUNCiAgZ3JvdXBfYnkobWludXRlKSAlPiUNCiAgc3VtbWFyaXNlKA0KICAgIGF2Z19kZWxheSA9IG1lYW4oYXJyX2RlbGF5LCBuYS5ybSA9IFRSVUUpLA0KICAgIG4gPSBuKCkNCiAgKQ0KYGBgDQoNCkluIHRoZSBwcmV2aW91cyBjb2RlLCB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIHJvdW5kZWQgYW5kIHVuLXJvdW5kZWQgZGF0ZXMgcHJvdmlkZXMgdGhlIHdpdGhpbi1wZXJpb2QgdGltZS4NCg0KIyMjIDEuIEhvdyBkb2VzIHRoZSBkaXN0cmlidXRpb24gb2YgZmxpZ2h0IHRpbWVzIHdpdGhpbiBhIGRheSBjaGFuZ2Ugb3ZlciB0aGUgY291cnNlIG9mIHRoZSB5ZWFyPw0KDQpMZXTigJlzIHRyeSBwbG90dGluZyB0aGlzIGJ5IG1vbnRoOg0KDQpgYGB7cn0NCmZsaWdodHNfZHQgJT4lDQogIGZpbHRlcighaXMubmEoZGVwX3RpbWUpKSAlPiUNCiAgbXV0YXRlKGRlcF9ob3VyID0gdXBkYXRlKGRlcF90aW1lLCB5ZGF5ID0gMSkpICU+JQ0KICBtdXRhdGUobW9udGggPSBmYWN0b3IobW9udGgoZGVwX3RpbWUpKSkgJT4lDQogIGdncGxvdChhZXMoZGVwX2hvdXIsIGNvbG9yID0gbW9udGgpKSArDQogIGdlb21fZnJlcXBvbHkoYmlud2lkdGggPSA2MCAqIDYwKQ0KYGBgDQoNClRoaXMgd2lsbCBsb29rIGJldHRlciBpZiBldmVyeXRoaW5nIGlzIG5vcm1hbGl6ZWQgd2l0aGluIGdyb3Vwcy4gVGhlIHJlYXNvbiB0aGF0IEZlYnJ1YXJ5IGlzIGxvd2VyIGlzIHRoYXQgdGhlcmUgYXJlIGZld2VyIGRheXMgYW5kIHRodXMgZmV3ZXIgZmxpZ2h0cy4NCg0KYGBge3J9DQpmbGlnaHRzX2R0ICU+JQ0KICBmaWx0ZXIoIWlzLm5hKGRlcF90aW1lKSkgJT4lDQogIG11dGF0ZShkZXBfaG91ciA9IHVwZGF0ZShkZXBfdGltZSwgeWRheSA9IDEpKSAlPiUNCiAgbXV0YXRlKG1vbnRoID0gZmFjdG9yKG1vbnRoKGRlcF90aW1lKSkpICU+JQ0KICBnZ3Bsb3QoYWVzKGRlcF9ob3VyLCBjb2xvciA9IG1vbnRoKSkgKw0KICBnZW9tX2ZyZXFwb2x5KGFlcyh5ID0gLi5kZW5zaXR5Li4pLCBiaW53aWR0aCA9IDYwICogNjApDQpgYGANCg0KQXQgbGVhc3QgdG8gbWUgdGhlcmUgZG9lc27igJl0IGFwcGVhciB0byBtdWNoIGRpZmZlcmVuY2UgaW4gd2l0aGluLWRheSBkaXN0cmlidXRpb24gb3ZlciB0aGUgeWVhciwgYnV0IEkgbWF5YmUgdGhpbmtpbmcgYWJvdXQgaXQgaW5jb3JyZWN0bHkuDQoNCiMjIyAyLiBDb21wYXJlIGBkZXBfdGltZWAsIGBzY2hlZF9kZXBfdGltZWAgYW5kIGBkZXBfZGVsYXlgLiBBcmUgdGhleSBjb25zaXN0ZW50PyBFeHBsYWluIHlvdXIgZmluZGluZ3MuDQoNCklmIHRoZXkgYXJlIGNvbnNpc3RlbnQsIHRoZW4gYGRlcF90aW1lYCA9IGBzY2hlZF9kZXBfdGltZWAgKyBgZGVwX2RlbGF5YC4NCg0KYGBge3J9DQpmbGlnaHRzX2R0ICU+JQ0KICBtdXRhdGUoZGVwX3RpbWVfID0gc2NoZWRfZGVwX3RpbWUgKyBkZXBfZGVsYXkgKiA2MCkgJT4lDQogIGZpbHRlcihkZXBfdGltZV8gIT0gZGVwX3RpbWUpICU+JQ0KICBzZWxlY3QoZGVwX3RpbWVfLCBkZXBfdGltZSwgc2NoZWRfZGVwX3RpbWUsIGRlcF9kZWxheSkNCmBgYA0KDQpUaGVyZSBleGlzdCBkaXNjcmVwYW5jaWVzLiBJdCBsb29rcyBsaWtlIHRoZXJlIGFyZSBtaXN0YWtlcyBpbiB0aGUgZGF0ZXMuIFRoZXNlIGFyZSBmbGlnaHRzIGluIHdoaWNoIHRoZSBhY3R1YWwgZGVwYXJ0dXJlIHRpbWUgaXMgb24gdGhlIG5leHQgZGF5IHJlbGF0aXZlIHRvIHRoZSBzY2hlZHVsZWQgZGVwYXJ0dXJlIHRpbWUuIFdlIGZvcmdvdCB0byBhY2NvdW50IGZvciB0aGlzIHdoZW4gY3JlYXRpbmcgdGhlIGRhdGUtdGltZXMgdXNpbmcgYG1ha2VfZGF0ZXRpbWVfMTAwKClgIGZ1bmN0aW9uLiBUaGUgY29kZSB3b3VsZCBoYXZlIGhhZCB0byBjaGVjayBpZiB0aGUgZGVwYXJ0dXJlIHRpbWUgaXMgbGVzcyB0aGFuIHRoZSBzY2hlZHVsZWQgZGVwYXJ0dXJlIHRpbWUgcGx1cyBkZXBhcnR1cmUgZGVsYXkgKGluIG1pbnV0ZXMpLiBBbHRlcm5hdGl2ZWx5LCBzaW1wbHkgYWRkaW5nIHRoZSBkZXBhcnR1cmUgZGVsYXkgdG8gdGhlIHNjaGVkdWxlZCBkZXBhcnR1cmUgdGltZSBpcyBhIG1vcmUgcm9idXN0IHdheSB0byBjb25zdHJ1Y3QgdGhlIGRlcGFydHVyZSB0aW1lIGJlY2F1c2UgaXQgd2lsbCBhdXRvbWF0aWNhbGx5IGFjY291bnQgZm9yIGNyb3NzaW5nIGludG8gdGhlIG5leHQgZGF5Lg0KDQojIyMgMy4gQ29tcGFyZSBgYWlyX3RpbWVgIHdpdGggdGhlIGR1cmF0aW9uIGJldHdlZW4gdGhlIGRlcGFydHVyZSBhbmQgYXJyaXZhbC4gRXhwbGFpbiB5b3VyIGZpbmRpbmdzLg0KDQpgYGB7cn0NCmZsaWdodHNfZHQgJT4lDQogIG11dGF0ZSgNCiAgICBmbGlnaHRfZHVyYXRpb24gPSBhcy5udW1lcmljKGFycl90aW1lIC0gZGVwX3RpbWUpLA0KICAgIGFpcl90aW1lX21pbnMgPSBhaXJfdGltZSwNCiAgICBkaWZmID0gZmxpZ2h0X2R1cmF0aW9uIC0gYWlyX3RpbWVfbWlucw0KICApICU+JQ0KICBzZWxlY3Qob3JpZ2luLCBkZXN0LCBmbGlnaHRfZHVyYXRpb24sIGFpcl90aW1lX21pbnMsIGRpZmYpDQpgYGANCg0KIyMjIDQuIEhvdyBkb2VzIHRoZSBhdmVyYWdlIGRlbGF5IHRpbWUgY2hhbmdlIG92ZXIgdGhlIGNvdXJzZSBvZiBhIGRheT8gU2hvdWxkIHlvdSB1c2UgYGRlcF90aW1lYCBvciBgc2NoZWRfZGVwX3RpbWVgPyBXaHk/DQoNClVzZSBgc2NoZWRfZGVwX3RpbWVgIGJlY2F1c2UgdGhhdCBpcyB0aGUgcmVsZXZhbnQgbWV0cmljIGZvciBzb21lb25lIHNjaGVkdWxpbmcgYSBmbGlnaHQuIEFsc28sIHVzaW5nIGBkZXBfdGltZWAgd2lsbCBhbHdheXMgYmlhcyBkZWxheXMgdG8gbGF0ZXIgaW4gdGhlIGRheSBzaW5jZSBkZWxheXMgd2lsbCBwdXNoIGZsaWdodHMgbGF0ZXIuDQoNCmBgYHtyfQ0KZmxpZ2h0c19kdCAlPiUNCiAgbXV0YXRlKHNjaGVkX2RlcF9ob3VyID0gaG91cihzY2hlZF9kZXBfdGltZSkpICU+JQ0KICBncm91cF9ieShzY2hlZF9kZXBfaG91cikgJT4lDQogIHN1bW1hcmlzZShkZXBfZGVsYXkgPSBtZWFuKGRlcF9kZWxheSkpICU+JQ0KICBnZ3Bsb3QoYWVzKHkgPSBkZXBfZGVsYXksIHggPSBzY2hlZF9kZXBfaG91cikpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgZ2VvbV9zbW9vdGgoKQ0KYGBgDQoNCg0KIyMjIDUuIE9uIHdoYXQgZGF5IG9mIHRoZSB3ZWVrIHNob3VsZCB5b3UgbGVhdmUgaWYgeW91IHdhbnQgdG8gbWluaW1pemUgdGhlIGNoYW5jZSBvZiBhIGRlbGF5Pw0KDQpTYXR1cmRheSBoYXMgdGhlIGxvd2VzdCBhdmVyYWdlIGRlcGFydHVyZSBkZWxheSB0aW1lIGFuZCB0aGUgbG93ZXN0IGF2ZXJhZ2UgYXJyaXZhbCBkZWxheSB0aW1lLg0KDQpgYGB7cn0NCmZsaWdodHNfZHQgJT4lDQogIG11dGF0ZShkb3cgPSB3ZGF5KHNjaGVkX2RlcF90aW1lKSkgJT4lDQogIGdyb3VwX2J5KGRvdykgJT4lDQogIHN1bW1hcmlzZSgNCiAgICBkZXBfZGVsYXkgPSBtZWFuKGRlcF9kZWxheSksDQogICAgYXJyX2RlbGF5ID0gbWVhbihhcnJfZGVsYXksIG5hLnJtID0gVFJVRSkNCiAgKSAlPiUNCiAgcHJpbnQobiA9IEluZikNCmZsaWdodHNfZHQgJT4lDQogIG11dGF0ZSh3ZGF5ID0gd2RheShkZXBfdGltZSwgbGFiZWwgPSBUUlVFKSkgJT4lDQogIGdyb3VwX2J5KHdkYXkpICU+JQ0KICBzdW1tYXJpemUoYXZlX2RlcF9kZWxheSA9IG1lYW4oZGVwX2RlbGF5LCBuYS5ybSA9IFRSVUUpKSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gd2RheSwgeSA9IGF2ZV9kZXBfZGVsYXkpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKQ0KZmxpZ2h0c19kdCAlPiUNCiAgbXV0YXRlKHdkYXkgPSB3ZGF5KGRlcF90aW1lLCBsYWJlbCA9IFRSVUUpKSAlPiUNCiAgZ3JvdXBfYnkod2RheSkgJT4lDQogIHN1bW1hcml6ZShhdmVfYXJyX2RlbGF5ID0gbWVhbihhcnJfZGVsYXksIG5hLnJtID0gVFJVRSkpICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSB3ZGF5LCB5ID0gYXZlX2Fycl9kZWxheSkpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpDQpgYGANCg0KIyMjIDYuIFdoYXQgbWFrZXMgdGhlIGRpc3RyaWJ1dGlvbiBvZiBgZGlhbW9uZHMkY2FyYXRgIGFuZCBgZmxpZ2h0cyRzY2hlZF9kZXBfdGltZWAgc2ltaWxhcj8NCg0KYGBge3J9DQpnZ3Bsb3QoZGlhbW9uZHMsIGFlcyh4ID0gY2FyYXQpKSArDQogIGdlb21fZGVuc2l0eSgpDQpgYGANCg0KSW4gYm90aCBgY2FyYXRgIGFuZCBgc2NoZWRfZGVwX3RpbWVgIHRoZXJlIGFyZSBhYm5vcm1hbGx5IGxhcmdlIG51bWJlcnMgb2YgdmFsdWVzIGFyZSBhdCBuaWNlIOKAnGh1bWFu4oCdIG51bWJlcnMuIEluIGBzY2hlZF9kZXBfdGltZWAgaXQgaXMgYXQgMDAgYW5kIDMwIG1pbnV0ZXMuIEluIGNhcmF0cywgaXQgaXMgYXQgMCwgMS8zLCAxLzIsIDIvMywNCg0KYGBgYHtyfQ0KZ2dwbG90KGRpYW1vbmRzLCBhZXMoeCA9IGNhcmF0ICUlIDEgKiAxMDApKSArDQogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gMSkNCmBgYA0KDQpJbiBzY2hlZHVsZWQgZGVwYXJ0dXJlIHRpbWVzIGl0IGlzIDAwIGFuZCAzMCBtaW51dGVzLCBhbmQgbWludXRlcyBlbmRpbmcgaW4gMCBhbmQgNS4NCg0KYGBge3J9DQpnZ3Bsb3QoZmxpZ2h0c19kdCwgYWVzKHggPSBtaW51dGUoc2NoZWRfZGVwX3RpbWUpKSkgKw0KICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDEpDQpgYGANCg0KIyMjIDcuIENvbmZpcm0gbXkgaHlwb3RoZXNpcyB0aGF0IHRoZSBlYXJseSBkZXBhcnR1cmVzIG9mIGZsaWdodHMgaW4gbWludXRlcyAyMC0zMCBhbmQgNTAtNjAgYXJlIGNhdXNlZCBieSBzY2hlZHVsZWQgZmxpZ2h0cyB0aGF0IGxlYXZlIGVhcmx5LiBIaW50OiBjcmVhdGUgYSBiaW5hcnkgdmFyaWFibGUgdGhhdCB0ZWxscyB5b3Ugd2hldGhlciBvciBub3QgYSBmbGlnaHQgd2FzIGRlbGF5ZWQuDQoNCkZpcnN0LCBJIGNyZWF0ZSBhIGJpbmFyeSB2YXJpYWJsZSBgZWFybHlgIHRoYXQgaXMgZXF1YWwgdG8gMSBpZiBhIGZsaWdodCBsZWF2ZXMgZWFybHksIGFuZCAwIGlmIGl0IGRvZXMgbm90LiBUaGVuLCBJIGdyb3VwIGZsaWdodHMgYnkgdGhlIG1pbnV0ZSBvZiBkZXBhcnR1cmUuIFRoaXMgc2hvd3MgdGhhdCB0aGUgcHJvcG9ydGlvbiBvZiBmbGlnaHRzIHRoYXQgYXJlIGVhcmx5IGRlcGFydHVyZXMgaXMgaGlnaGVzdCBiZXR3ZWVuIG1pbnV0ZXMgMjDigJMzMCBhbmQgNTDigJM2MC4NCg0KYGBge3J9DQpmbGlnaHRzX2R0ICU+JQ0KICBtdXRhdGUoDQogICAgbWludXRlID0gbWludXRlKGRlcF90aW1lKSwNCiAgICBlYXJseSA9IGRlcF9kZWxheSA8IDANCiAgKSAlPiUNCiAgZ3JvdXBfYnkobWludXRlKSAlPiUNCiAgc3VtbWFyaXNlKA0KICAgIGVhcmx5ID0gbWVhbihlYXJseSwgbmEucm0gPSBUUlVFKSwNCiAgICBuID0gbigpDQogICkgJT4lDQogIGdncGxvdChhZXMobWludXRlLCBlYXJseSkpICsNCiAgZ2VvbV9saW5lKCkNCmBgYA0KDQo=