Exercise 1

ramen_ratings <- readr::read_csv(
  "https://raw.githubusercontent.com/rfordatascience/tidytuesday/master/data/2019/2019-06-04/ramen_ratings.csv"
)

Exercise 2

Dataset Summary

The ramen ratings dataset contains 3,180 observations and 6 variables, including review number, brand, variety, style, country, and star rating.

The dataset includes both categorical variables (brand, variety, style, and country) and numerical variables (review_number and stars). A total of 456 unique brands, 44 countries, and 8 ramen styles are represented.

The star rating ranges from 0 to 5, with:

Mean rating = 3.69 Median rating = 3.75

Most ratings fall between 3.25 and 4.5, indicating generally favorable reviews. There are 14 missing values in the star rating variable.

ramen_ratings %>%
  filter(style == "Pack", !is.na(stars)) %>%
  ggplot(aes(x = stars)) +
  geom_histogram(binwidth = 0.5) +
  labs(
    title = "Distribution of Ramen Ratings (Pack)",
    x = "Stars",
    y = "Count"
  )

Exercise 3

Interpretation of Distribution (Pack Style)

The distribution of ramen ratings for the “Pack” style shows that most products receive relatively high ratings. The majority of observations fall between 3 and 5 stars, with a clear concentration around 3.5 to 4 stars.

The distribution is left-skewed, indicating that while most ramen products are rated favorably, there are a smaller number of low-rated products extending toward 0. Ratings below 2 stars are uncommon.

Overall, this suggests that “Pack” style ramen is generally well-reviewed, with most products receiving moderate to high ratings.

This pattern aligns with the overall dataset summary, where the mean (3.69) and median (3.75) also indicate generally positive ratings.

ramen_ratings %>%
  filter(style == "Pack", !is.na(stars)) %>%
  ggplot(aes(x = stars)) +
  geom_histogram(binwidth = 0.5) +
  labs(
    title = "Distribution of Ramen Ratings (Pack)",
    x = "Stars",
    y = "Count"
  )

Exercise 4

Comparison of Ramen Ratings by Style

The faceted histograms illustrate the distribution of star ratings across different ramen styles. Overall, most styles show a similar pattern, with ratings concentrated between 3 and 5 stars, indicating generally favorable reviews regardless of packaging type.

The Pack style has the largest number of observations and shows a strong concentration of ratings between 3.5 and 5 stars, suggesting consistently high ratings. Similarly, Cup and Bowl styles also display a high frequency of ratings in this range, though with fewer observations than Pack.

In contrast, styles such as Bar, Can, Box, and Restaurant have very few observations, making it difficult to draw meaningful conclusions about their rating distributions. These smaller categories show limited variability due to the small sample sizes.

Overall, while most ramen styles are well-rated, the Pack, Cup, and Bowl styles dominate the dataset and demonstrate consistently higher ratings compared to less common styles.

ggplot(ramen_ratings %>% filter(!is.na(stars)), aes(x = stars)) +
  geom_histogram(binwidth = 0.5) +
  facet_wrap(~style) +
  labs(title = "Ramen Ratings by Style",
       x = "Stars",
       y = "Count")

Exercise 5

Ramen Products by Country

The bar chart shows that Japan produces the highest number of ramen products by a wide margin, significantly exceeding all other countries in the dataset. This highlights Japan’s central role in the global ramen market.

A second tier of countries, including the United States, South Korea, Taiwan, China and Thailand, also contribute a substantial number of products, though at much lower levels than Japan.

Beyond these top contributors, there is a sharp decline in the number of products by country. Most countries have relatively few ramen products represented, with many contributing fewer than 100 observations.

Overall, the distribution is highly skewed, with a small number of countries dominating production and a long tail of countries with minimal representation.

I noticed some duplicate country entries (United States and Philippines) and cleaned the data. Before creating the final bar chart, I standardized country labels to correct inconsistent entries and typographical errors so that duplicate country categories were combined into a single, accurate count. This data cleaning did not change the interpretation.

ramen_ratings %>%
  count(country) %>%
  arrange(desc(n)) %>%
  ggplot(aes(x = reorder(country, n), y = n)) +
  geom_col() +
  coord_flip() +
  labs(title = "Ramen Products by Country",
       x = "Country",
       y = "Count")

ramen_ratings_clean <- ramen_ratings %>%
  mutate(country = if_else(country == "USA", "United States", country))


ramen_ratings_clean %>%
  count(country) %>%
  arrange(desc(n)) %>%
  ggplot(aes(x = reorder(country, n), y = n)) +
  geom_col() +
  coord_flip() +
  labs(title = "Ramen Products by Country",
       x = "Country",
       y = "Count")

Exercise 6

Highest Mean Stars Rating by Country

After grouping the data by country and calculating the average star rating, Cambodia had the highest mean stars rating at 4.20 stars. This indicates that, on average, ramen products from Cambodia received the strongest ratings in the dataset

Because some countries have far fewer observations than others, the highest average rating may be based on a relatively small number of ramen products. So while Cambodia has the highest mean rating in this dataset, countries with more products may provide a more stable estimate of average quality.

ramen_ratings_clean %>%
  group_by(country) %>%
  summarise(mean_stars = mean(stars, na.rm = TRUE)) %>%
  arrange(desc(mean_stars)) %>%
  print(n = Inf)
## # A tibble: 43 × 2
##    country       mean_stars
##    <chr>              <dbl>
##  1 Cambodia            4.2 
##  2 France              4.19
##  3 Malaysia            4.16
##  4 Indonesia           4.11
##  5 Singapore           4.10
##  6 Brazil              4.04
##  7 Sarawak             4   
##  8 Myanmar             3.95
##  9 Japan               3.91
## 10 Fiji                3.88
## 11 South Korea         3.81
## 12 Hong Kong           3.81
## 13 Taiwan              3.79
## 14 Mexico              3.69
## 15 Hungary             3.61
## 16 Bangladesh          3.59
## 17 Dubai               3.58
## 18 Finland             3.58
## 19 Ukraine             3.58
## 20 Germany             3.58
## 21 Holland             3.56
## 22 Nepal               3.52
## 23 United States       3.51
## 24 Estonia             3.5 
## 25 Ghana               3.5 
## 26 Phlippines          3.5 
## 27 China               3.47
## 28 Thailand            3.41
## 29 India               3.37
## 30 Philippines         3.36
## 31 Italy               3.33
## 32 Colombia            3.29
## 33 Australia           3.26
## 34 Russia              3.25
## 35 Sweden              3.25
## 36 Vietnam             3.17
## 37 Poland              3.08
## 38 New Zealand         3   
## 39 UK                  2.99
## 40 Pakistan            2.92
## 41 Netherlands         2.5 
## 42 Nigeria             2.38
## 43 Canada              2.26

Exercises 5.4.1

library(dplyr)
library(nycflights13)

flights <- nycflights13::flights

1

There are multiple ways to select variables in a dataset. Columns can be selected directly by name, or by using helper functions such as starts_with(), ends_with(), and contains(). Another flexible option is to create a vector of variable names and use all_of() to select those variables.

# Basic select
select(flights, dep_time, dep_delay, arr_time, arr_delay)
## # A tibble: 336,776 × 4
##    dep_time dep_delay arr_time arr_delay
##       <int>     <dbl>    <int>     <dbl>
##  1      517         2      830        11
##  2      533         4      850        20
##  3      542         2      923        33
##  4      544        -1     1004       -18
##  5      554        -6      812       -25
##  6      554        -4      740        12
##  7      555        -5      913        19
##  8      557        -3      709       -14
##  9      557        -3      838        -8
## 10      558        -2      753         8
## # ℹ 336,766 more rows
# Using starts_with
select(flights, starts_with("dep"), starts_with("arr"))
## # A tibble: 336,776 × 4
##    dep_time dep_delay arr_time arr_delay
##       <int>     <dbl>    <int>     <dbl>
##  1      517         2      830        11
##  2      533         4      850        20
##  3      542         2      923        33
##  4      544        -1     1004       -18
##  5      554        -6      812       -25
##  6      554        -4      740        12
##  7      555        -5      913        19
##  8      557        -3      709       -14
##  9      557        -3      838        -8
## 10      558        -2      753         8
## # ℹ 336,766 more rows
# Using ends_with
select(flights, ends_with("time"), ends_with("delay"))
## # A tibble: 336,776 × 7
##    dep_time sched_dep_time arr_time sched_arr_time air_time dep_delay arr_delay
##       <int>          <int>    <int>          <int>    <dbl>     <dbl>     <dbl>
##  1      517            515      830            819      227         2        11
##  2      533            529      850            830      227         4        20
##  3      542            540      923            850      160         2        33
##  4      544            545     1004           1022      183        -1       -18
##  5      554            600      812            837      116        -6       -25
##  6      554            558      740            728      150        -4        12
##  7      555            600      913            854      158        -5        19
##  8      557            600      709            723       53        -3       -14
##  9      557            600      838            846      140        -3        -8
## 10      558            600      753            745      138        -2         8
## # ℹ 336,766 more rows
# Using contains
select(flights, contains("time"), contains("delay"))
## # A tibble: 336,776 × 8
##    dep_time sched_dep_time arr_time sched_arr_time air_time time_hour          
##       <int>          <int>    <int>          <int>    <dbl> <dttm>             
##  1      517            515      830            819      227 2013-01-01 05:00:00
##  2      533            529      850            830      227 2013-01-01 05:00:00
##  3      542            540      923            850      160 2013-01-01 05:00:00
##  4      544            545     1004           1022      183 2013-01-01 05:00:00
##  5      554            600      812            837      116 2013-01-01 06:00:00
##  6      554            558      740            728      150 2013-01-01 05:00:00
##  7      555            600      913            854      158 2013-01-01 06:00:00
##  8      557            600      709            723       53 2013-01-01 06:00:00
##  9      557            600      838            846      140 2013-01-01 06:00:00
## 10      558            600      753            745      138 2013-01-01 06:00:00
## # ℹ 336,766 more rows
## # ℹ 2 more variables: dep_delay <dbl>, arr_delay <dbl>
# Using a vector
vars <- c("dep_time", "dep_delay", "arr_time", "arr_delay")
select(flights, all_of(vars))
## # A tibble: 336,776 × 4
##    dep_time dep_delay arr_time arr_delay
##       <int>     <dbl>    <int>     <dbl>
##  1      517         2      830        11
##  2      533         4      850        20
##  3      542         2      923        33
##  4      544        -1     1004       -18
##  5      554        -6      812       -25
##  6      554        -4      740        12
##  7      555        -5      913        19
##  8      557        -3      709       -14
##  9      557        -3      838        -8
## 10      558        -2      753         8
## # ℹ 336,766 more rows

2

If a variable is included multiple times in a select() statement, it will only appear once in the resulting dataset. The select() function automatically removes duplicate columns.

dplyr::select(flights, dep_time, dep_time, arr_time)
## # A tibble: 336,776 × 2
##    dep_time arr_time
##       <int>    <int>
##  1      517      830
##  2      533      850
##  3      542      923
##  4      544     1004
##  5      554      812
##  6      554      740
##  7      555      913
##  8      557      709
##  9      557      838
## 10      558      753
## # ℹ 336,766 more rows

3

The any_of() function selects variables from a vector but does not produce an error if some variables are missing. Instead, it only selects the variables that exist in the dataset. This is useful when working with variable lists that may not always match the dataset exactly.

vars <- c("year", "month", "day", "dep_delay", "arr_delay")

dplyr::select(flights, any_of(vars))
## # A tibble: 336,776 × 5
##     year month   day dep_delay arr_delay
##    <int> <int> <int>     <dbl>     <dbl>
##  1  2013     1     1         2        11
##  2  2013     1     1         4        20
##  3  2013     1     1         2        33
##  4  2013     1     1        -1       -18
##  5  2013     1     1        -6       -25
##  6  2013     1     1        -4        12
##  7  2013     1     1        -5        19
##  8  2013     1     1        -3       -14
##  9  2013     1     1        -3        -8
## 10  2013     1     1        -2         8
## # ℹ 336,766 more rows

4

The result may be surprising because contains("TIME") still matches variables such as dep_time and arr_time. This is because select helper functions are case-insensitive by default. This behavior can be changed by setting ignore.case = FALSE, which forces case-sensitive matching.

select(flights, contains("TIME"))
## # A tibble: 336,776 × 6
##    dep_time sched_dep_time arr_time sched_arr_time air_time time_hour          
##       <int>          <int>    <int>          <int>    <dbl> <dttm>             
##  1      517            515      830            819      227 2013-01-01 05:00:00
##  2      533            529      850            830      227 2013-01-01 05:00:00
##  3      542            540      923            850      160 2013-01-01 05:00:00
##  4      544            545     1004           1022      183 2013-01-01 05:00:00
##  5      554            600      812            837      116 2013-01-01 06:00:00
##  6      554            558      740            728      150 2013-01-01 05:00:00
##  7      555            600      913            854      158 2013-01-01 06:00:00
##  8      557            600      709            723       53 2013-01-01 06:00:00
##  9      557            600      838            846      140 2013-01-01 06:00:00
## 10      558            600      753            745      138 2013-01-01 06:00:00
## # ℹ 336,766 more rows

Exercises 5.5.2

1

The variables dep_time and sched_dep_time are stored in HHMM format, which makes them difficult to analyze. By converting them into minutes since midnight, we create continuous numeric variables that are easier to use in calculations and comparisons.

flights <- flights %>%
  mutate(
    dep_time_minutes = (dep_time %/% 100) * 60 + (dep_time %% 100),
    sched_dep_time_minutes = (sched_dep_time %/% 100) * 60 + (sched_dep_time %% 100)
  )

2

We would expect air_time to be similar to the difference between arrival and departure times. However, this difference can be inaccurate due to issues such as crossing midnight or differences in time zones. To fix this, time variables should first be converted into a continuous format (such as minutes since midnight), and adjustments should be made for overnight flights.

flights <- flights %>%
  mutate(
    travel_time = arr_time - dep_time
  )

summary(flights$air_time)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max.     NAs 
##    20.0    82.0   129.0   150.7   192.0   695.0    9430
summary(flights$travel_time)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max.     NAs 
## -2346.0   156.0   216.0   153.2   292.0  1170.0    8713

3

We would expect the departure delay to equal the difference between actual and scheduled departure times. However, because times are stored in HHMM format, the relationship is not exact without converting them into continuous time. After conversion, the calculated delay should closely match the recorded dep_delay.

flights <- flights %>%
  dplyr::mutate(
    calculated_delay = dep_time - sched_dep_time
  )

dplyr::select(flights, dep_time, sched_dep_time, dep_delay, calculated_delay) %>%
  head()
## # A tibble: 6 × 4
##   dep_time sched_dep_time dep_delay calculated_delay
##      <int>          <int>     <dbl>            <int>
## 1      517            515         2                2
## 2      533            529         4                4
## 3      542            540         2                2
## 4      544            545        -1               -1
## 5      554            600        -6              -46
## 6      554            558        -4               -4

4

The min_rank() function assigns the same rank to tied values, which means that if multiple flights share the same delay, they will receive the same rank. This can result in more than 10 rows being returned when ties are present.

flights %>%
  mutate(rank = min_rank(desc(dep_delay))) %>%
  filter(rank <= 10) %>%
  select(year, month, day, dep_time, dep_delay, rank)
## # A tibble: 10 × 6
##     year month   day dep_time dep_delay  rank
##    <int> <int> <int>    <int>     <dbl> <int>
##  1  2013     1     9      641      1301     1
##  2  2013     1    10     1121      1126     3
##  3  2013    12     5      756       896    10
##  4  2013     3    17     2321       911     7
##  5  2013     4    10     1100       960     6
##  6  2013     6    15     1432      1137     2
##  7  2013     6    27      959       899     8
##  8  2013     7    22      845      1005     5
##  9  2013     7    22     2257       898     9
## 10  2013     9    20     1139      1014     4

5

The expression 1:3 + 1:10 returns a numeric vector of length 10. This occurs because of R’s vector recycling behavior, where the shorter vector (1:3) is repeated to match the length of the longer vector (1:10) before performing element-wise addition.

However, since the length of the longer vector (10) is not a multiple of the shorter vector (3), R produces a warning indicating that the recycling is uneven. This results in the shorter vector repeating partially through its sequence.

1:3 + 1:10
##  [1]  2  4  6  5  7  9  8 10 12 11

6

R provides a full set of trigonometric functions, including sin(), cos(), tan(), as well as their inverses such as asin(), acos(), and atan(). These functions operate on numeric inputs and return values in radians by default.

Exercises 5.6.7

not_cancelled <- flights %>%
  filter(!is.na(dep_delay), !is.na(arr_delay))

1

There are several ways to assess typical delay characteristics:

  1. Mean delay – provides the average delay but can be heavily influenced by extreme values.
  2. Median delay – gives the typical delay and is more robust to outliers.
  3. Standard deviation – measures variability in delays.
  4. Distribution (histogram or quantiles) – shows the full spread of delays.
  5. Proportion of delayed flights – shows how frequently delays occur.
  6. Maximum delay or extreme values – highlights rare but important events.

For the given scenarios: - Flights that are equally early and late will have a mean near zero but high variability. - Flights that are always late will have a consistent delay and low variability. - Rare extreme delays (e.g., 1% very late flights) will increase the mean but not the median.

Arrival delay is generally more important than departure delay, since it reflects the total impact on passengers reaching their destination, including delays incurred during the flight.

2

The same result as count() can be created using group_by() and summarise().

  • count(dest) is equivalent to grouping by dest and using summarise(n = n()).
  • count(tailnum, wt = distance) is equivalent to grouping by tailnum and summing the distance variable with summarise(n = sum(distance, na.rm = TRUE)).

This works because count() is essentially a shortcut for grouping observations and then summarizing them.

# Equivalent to: not_cancelled %>% count(dest)
not_cancelled %>%
  group_by(dest) %>%
  summarise(n = n())
## # A tibble: 104 × 2
##    dest      n
##    <chr> <int>
##  1 ABQ     254
##  2 ACK     264
##  3 ALB     418
##  4 ANC       8
##  5 ATL   16837
##  6 AUS    2411
##  7 AVL     261
##  8 BDL     412
##  9 BGR     358
## 10 BHM     269
## # ℹ 94 more rows
# Equivalent to: not_cancelled %>% count(tailnum, wt = distance)
not_cancelled %>%
  group_by(tailnum) %>%
  summarise(n = sum(distance, na.rm = TRUE))
## # A tibble: 4,037 × 2
##    tailnum      n
##    <chr>    <dbl>
##  1 D942DN    3418
##  2 N0EGMQ  239143
##  3 N10156  109664
##  4 N102UW   25722
##  5 N103US   24619
##  6 N104UW   24616
##  7 N10575  139903
##  8 N105UW   23618
##  9 N107US   21677
## 10 N108UW   32070
## # ℹ 4,027 more rows

3

The definition is.na(dep_delay) | is.na(arr_delay) is suboptimal because missing arrival delay does not always indicate cancellation. In my summary, arr_delay had more missing values (9,430) than dep_time and dep_delay (8,255 each), suggesting that some flights have missing arrival delay for other reasons. The most important column is dep_time, since a missing departure time is the clearest indicator that a flight was cancelled.

flights %>%
  summarise(
    missing_dep_time = sum(is.na(dep_time)),
    missing_dep_delay = sum(is.na(dep_delay)),
    missing_arr_delay = sum(is.na(arr_delay))
  )
## # A tibble: 1 × 3
##   missing_dep_time missing_dep_delay missing_arr_delay
##              <int>             <int>             <int>
## 1             8255              8255              9430

4

The daily summary shows that the number of cancelled flights varies across the year. While the overall cancellation rate is relatively low, it fluctuates from day to day, indicating that cancellations are not evenly distributed. For example, in early January, the number of cancelled flights ranges from 1 to 10 per day, with corresponding variation in cancellation rates.

Average departure delay also varies across days. Some days with higher cancellation counts tend to also have higher average delays, suggesting that disruptions affecting airline operations—such as weather or congestion—may impact both cancellations and delays simultaneously. For example, January 2 and January 3 show relatively higher cancellation rates and higher average delays compared to later days with fewer cancellations and lower delays.

Overall, there appears to be a potential relationship between cancellation rates and average delay, where more disruptive days may lead to both increased cancellations and longer delays. However, this relationship is not entirely clear from the table alone, and a visual analysis (such as a scatterplot) would provide a better assessment of the strength of this relationship.

flights %>%
  mutate(cancelled = is.na(dep_time)) %>%
  group_by(year, month, day) %>%
  summarise(
    total_flights = n(),
    cancelled_flights = sum(cancelled),
    cancel_rate = cancelled_flights / total_flights,
    avg_delay = mean(dep_delay, na.rm = TRUE)
  )
## # A tibble: 365 × 7
## # Groups:   year, month [12]
##     year month   day total_flights cancelled_flights cancel_rate avg_delay
##    <int> <int> <int>         <int>             <int>       <dbl>     <dbl>
##  1  2013     1     1           842                 4     0.00475     11.5 
##  2  2013     1     2           943                 8     0.00848     13.9 
##  3  2013     1     3           914                10     0.0109      11.0 
##  4  2013     1     4           915                 6     0.00656      8.95
##  5  2013     1     5           720                 3     0.00417      5.73
##  6  2013     1     6           832                 1     0.00120      7.15
##  7  2013     1     7           933                 3     0.00322      5.42
##  8  2013     1     8           899                 4     0.00445      2.55
##  9  2013     1     9           902                 5     0.00554      2.28
## 10  2013     1    10           932                 3     0.00322      2.84
## # ℹ 355 more rows

5

The results show clear differences in average arrival delays across carriers. Some airlines appear to have significantly higher delays than others. For example, carriers such as F9 and FL have the highest average delays, at approximately 21.9 and 20.1 minutes, respectively. In contrast, carriers such as AS and HA have negative average delays, indicating that their flights tend to arrive earlier than scheduled on average.

Although this summary suggests that some airlines perform worse than others, the comparison is potentially misleading. It does not account for differences in routes, destinations, or operating conditions. For instance, some carriers may fly more frequently to congested airports or over longer distances, both of which can increase delays.

Additionally, airlines serving specific regions or operating long-haul flights may experience different patterns of delay than those operating shorter or less congested routes. As a result, the observed differences in average delays may reflect factors beyond the airlines’ control rather than true differences in performance.

Overall, while the analysis identifies carriers with higher average delays, a fair comparison would require controlling for factors such as route, distance, and airport conditions.

A more accurate analysis would compare airlines operating on similar routes or adjust for factors such as distance and airport congestion.

flights %>%
  group_by(carrier) %>%
  summarise(avg_delay = mean(arr_delay, na.rm = TRUE)) %>%
  arrange(desc(avg_delay))
## # A tibble: 16 × 2
##    carrier avg_delay
##    <chr>       <dbl>
##  1 F9         21.9  
##  2 FL         20.1  
##  3 EV         15.8  
##  4 YV         15.6  
##  5 OO         11.9  
##  6 MQ         10.8  
##  7 WN          9.65 
##  8 B6          9.46 
##  9 9E          7.38 
## 10 UA          3.56 
## 11 US          2.13 
## 12 VX          1.76 
## 13 DL          1.64 
## 14 AA          0.364
## 15 HA         -6.92 
## 16 AS         -9.93

6

R provides a full set of trigonometric functions, including sin(), cos(), and tan(), as well as their inverse functions such as asin(), acos(), and atan(). These functions operate on numeric inputs and return values based on angles measured in radians.

For example, sin(pi / 2) = 1, cos(0) = 1, and tan(pi / 4) = 1, which are expected values for these standard angles. This confirms that R uses radians rather than degrees by default.

These functions are vectorized, meaning they can be applied to entire vectors of values efficiently, making them useful for mathematical and statistical computations.

sin(pi / 2)
## [1] 1
cos(0)
## [1] 1
tan(pi / 4)
## [1] 1

Exercises 5.7.1

1

When mutate() is used with group_by(), the calculations are performed within each group rather than across the entire dataset. For example, means or ranks are computed separately for each group instead of globally.

Similarly, when filter() is used with group_by(), the filtering conditions are applied within each group. For example, filtering for the maximum value will return the maximum within each group rather than the overall maximum.

Overall, grouping changes the context of operations so that they are applied to each subgroup independently rather than the dataset as a whole.

2

After filtering to include only planes with at least 20 flights, the plane with the worst on-time record was N203FR, with an average arrival delay of 59.1 minutes across 41 flights.

This is a more reliable result than the initial ranking because it excludes planes with only one or two flights, which can produce misleadingly high average delays. By restricting the analysis to planes with more observations, the average delay provides a more stable estimate of a plane’s typical performance.

flights %>%
  group_by(tailnum) %>%
  summarise(avg_delay = mean(arr_delay, na.rm = TRUE),
            n = n()) %>%
  arrange(desc(avg_delay))
## # A tibble: 4,044 × 3
##    tailnum avg_delay     n
##    <chr>       <dbl> <int>
##  1 N844MH       320      1
##  2 N911DA       294      1
##  3 N922EV       276      1
##  4 N587NW       264      1
##  5 N851NW       219      1
##  6 N928DN       201      1
##  7 N7715E       188      1
##  8 N654UA       185      1
##  9 N665MQ       175.     6
## 10 N427SW       157      1
## # ℹ 4,034 more rows
flights %>%
  group_by(tailnum) %>%
  summarise(
    avg_delay = mean(arr_delay, na.rm = TRUE),
    n = n()
  ) %>%
  filter(n >= 20) %>%
  arrange(desc(avg_delay))
## # A tibble: 3,164 × 3
##    tailnum avg_delay     n
##    <chr>       <dbl> <int>
##  1 N203FR       59.1    41
##  2 N645MQ       51      25
##  3 N956AT       47.6    36
##  4 N988AT       44.3    37
##  5 N521VA       42.2    27
##  6 N353AT       41.2    21
##  7 N942AT       41.2    20
##  8 N6716C       40.3    25
##  9 N908MQ       38.5    22
## 10 N657MQ       38.5    39
## # ℹ 3,154 more rows

3

Flights departing earlier in the day tend to have the lowest average delays. In this dataset, flights leaving at 5 AM had the smallest average delay, followed by departures at 6 AM and 7 AM. Average delays increase steadily later in the day, with evening flights showing the largest delays. This suggests that early morning is the best time to fly to minimize delays, likely because delays accumulate as the day progresses.

flights %>%
  group_by(hour) %>%
  summarise(avg_delay = mean(dep_delay, na.rm = TRUE)) %>%
  arrange(avg_delay)
## # A tibble: 20 × 2
##     hour avg_delay
##    <dbl>     <dbl>
##  1     5     0.688
##  2     6     1.64 
##  3     7     1.91 
##  4     8     4.13 
##  5     9     4.58 
##  6    10     6.50 
##  7    11     7.19 
##  8    12     8.61 
##  9    13    11.4  
## 10    14    13.8  
## 11    23    14.0  
## 12    15    16.9  
## 13    16    18.8  
## 14    22    18.8  
## 15    17    21.1  
## 16    18    21.1  
## 17    21    24.2  
## 18    20    24.3  
## 19    19    24.8  
## 20     1   NaN
flights %>%
  group_by(hour) %>%
  summarise(avg_delay = mean(dep_delay, na.rm = TRUE)) %>%
  filter(!is.nan(avg_delay)) %>%
  arrange(avg_delay)
## # A tibble: 19 × 2
##     hour avg_delay
##    <dbl>     <dbl>
##  1     5     0.688
##  2     6     1.64 
##  3     7     1.91 
##  4     8     4.13 
##  5     9     4.58 
##  6    10     6.50 
##  7    11     7.19 
##  8    12     8.61 
##  9    13    11.4  
## 10    14    13.8  
## 11    23    14.0  
## 12    15    16.9  
## 13    16    18.8  
## 14    22    18.8  
## 15    17    21.1  
## 16    18    21.1  
## 17    21    24.2  
## 18    20    24.3  
## 19    19    24.8

4

By grouping flights by destination and calculating the total arrival delay within each group, this analysis shows how much each flight contributes to the overall delay experienced at its destination. Flights with larger positive delay_prop values account for a greater share of delays, while negative values represent flights that arrived early.

This approach is useful for identifying whether delays at a destination are concentrated in a few unusually delayed flights or distributed more evenly across many flights. In the output, destinations with relatively small total delay can show larger proportional contributions from a single delayed flight, whereas destinations with very large total delay tend to have much smaller proportions for individual flights.

flights %>%
  group_by(dest) %>%
  mutate(
    total_delay = sum(arr_delay, na.rm = TRUE),
    delay_prop = arr_delay / total_delay
  ) %>%
  select(dest, arr_delay, total_delay, delay_prop)
## # A tibble: 336,776 × 4
## # Groups:   dest [105]
##    dest  arr_delay total_delay delay_prop
##    <chr>     <dbl>       <dbl>      <dbl>
##  1 IAH          11       30046  0.000366 
##  2 IAH          20       30046  0.000666 
##  3 MIA          33        3467  0.00952  
##  4 BQN         -18        7322 -0.00246  
##  5 ATL         -25      190260 -0.000131 
##  6 ORD          12       97352  0.000123 
##  7 FLL          19       96153  0.000198 
##  8 IAD         -14       74631 -0.000188 
##  9 MCO          -8       76185 -0.000105 
## 10 ORD           8       97352  0.0000822
## # ℹ 336,766 more rows

5

The correlation results show a positive relationship between a flight’s delay and the delay of the immediately preceding flight at each airport. The correlations were 0.254 for EWR, 0.238 for JFK, and 0.282 for LGA, indicating that delays tend to carry forward over time.

Although the correlations are only moderate, they provide evidence that delays are not completely independent. Instead, earlier delays may contribute to later delays, likely because operational disruptions can affect multiple flights in sequence.

flights %>%
  arrange(origin, time_hour) %>%
  group_by(origin) %>%
  mutate(prev_delay = lag(dep_delay)) %>%
  select(origin, time_hour, dep_delay, prev_delay) %>%
  print(n = 20)
## # A tibble: 336,776 × 4
## # Groups:   origin [3]
##    origin time_hour           dep_delay prev_delay
##    <chr>  <dttm>                  <dbl>      <dbl>
##  1 EWR    2013-01-01 05:00:00         2         NA
##  2 EWR    2013-01-01 05:00:00        -4          2
##  3 EWR    2013-01-01 06:00:00        -5         -4
##  4 EWR    2013-01-01 06:00:00        -2         -5
##  5 EWR    2013-01-01 06:00:00        -1         -2
##  6 EWR    2013-01-01 06:00:00         1         -1
##  7 EWR    2013-01-01 06:00:00        -4          1
##  8 EWR    2013-01-01 06:00:00         0         -4
##  9 EWR    2013-01-01 06:00:00         8          0
## 10 EWR    2013-01-01 06:00:00         0          8
## 11 EWR    2013-01-01 06:00:00        -8          0
## 12 EWR    2013-01-01 06:00:00        -6         -8
## 13 EWR    2013-01-01 06:00:00        -2         -6
## 14 EWR    2013-01-01 06:00:00        -1         -2
## 15 EWR    2013-01-01 06:00:00        24         -1
## 16 EWR    2013-01-01 06:00:00        -3         24
## 17 EWR    2013-01-01 06:00:00        -2         -3
## 18 EWR    2013-01-01 06:00:00         8         -2
## 19 EWR    2013-01-01 06:00:00         1          8
## 20 EWR    2013-01-01 06:00:00        47          1
## # ℹ 336,756 more rows
flights %>%
  arrange(origin, year, month, day, sched_dep_time) %>%
  group_by(origin) %>%
  mutate(prev_delay = lag(dep_delay)) %>%
  select(origin, year, month, day, sched_dep_time, dep_delay, prev_delay)
## # A tibble: 336,776 × 7
## # Groups:   origin [3]
##    origin  year month   day sched_dep_time dep_delay prev_delay
##    <chr>  <int> <int> <int>          <int>     <dbl>      <dbl>
##  1 EWR     2013     1     1            515         2         NA
##  2 EWR     2013     1     1            558        -4          2
##  3 EWR     2013     1     1            600        -5         -4
##  4 EWR     2013     1     1            600        -2         -5
##  5 EWR     2013     1     1            600        -1         -2
##  6 EWR     2013     1     1            600         1         -1
##  7 EWR     2013     1     1            600         8          1
##  8 EWR     2013     1     1            607         0          8
##  9 EWR     2013     1     1            608        24          0
## 10 EWR     2013     1     1            610        -4         24
## # ℹ 336,766 more rows
flights %>%
  arrange(origin, year, month, day, sched_dep_time) %>%
  group_by(origin) %>%
  mutate(prev_delay = lag(dep_delay)) %>%
  summarise(correlation = cor(dep_delay, prev_delay, use = "complete.obs"))
## # A tibble: 3 × 2
##   origin correlation
##   <chr>        <dbl>
## 1 EWR          0.254
## 2 JFK          0.238
## 3 LGA          0.282

6

By comparing each flight’s air time to the minimum observed air time for the same destination, this analysis creates a relative measure of flight duration. A time_ratio of 1 indicates that a flight matched the shortest observed time for that route, while larger values indicate longer flights relative to the route minimum.

The current output is dominated by flights with a ratio of 1 because the results were sorted in ascending order. This highlights the fastest flights for each destination. To identify flights that were unusually slow relative to the minimum, it would be more informative to sort the output in descending order of time_ratio.

flights %>%
  filter(!is.na(air_time)) %>%
  group_by(dest) %>%
  mutate(
    min_air_time = min(air_time, na.rm = TRUE),
    time_ratio = air_time / min_air_time
  ) %>%
  arrange(time_ratio) %>%
  select(dest, air_time, min_air_time, time_ratio) %>%
  print(n = 20)
## # A tibble: 327,346 × 4
## # Groups:   dest [104]
##    dest  air_time min_air_time time_ratio
##    <chr>    <dbl>        <dbl>      <dbl>
##  1 BWI         31           31          1
##  2 PBI        105          105          1
##  3 PWM         38           38          1
##  4 BDL         20           20          1
##  5 PWM         38           38          1
##  6 PWM         38           38          1
##  7 ACK         35           35          1
##  8 ACK         35           35          1
##  9 MSN        102          102          1
## 10 MDW         92           92          1
## 11 CAK         53           53          1
## 12 DCA         32           32          1
## 13 ORF         36           36          1
## 14 BUF         38           38          1
## 15 BHM        105          105          1
## 16 ILM         63           63          1
## 17 BQN        173          173          1
## 18 BQN        173          173          1
## 19 PSE        179          179          1
## 20 SJU        170          170          1
## # ℹ 327,326 more rows

7

Top shared destinations: ATL, BOS, CLT, ORD, TPA –> 7 carriers

Highest average delays: F9 (21.9), FL (20.3), EV (15.7), YV (15.6) Lowest average delays: HA (-6.92), (-9.93)

After restricting the analysis to destinations served by at least two carriers, the ranking of airlines becomes more comparable because the carriers are being evaluated on overlapping routes rather than completely different destination mixes.

The results show that F9 and FL have the highest average arrival delays, at approximately 21.9 minutes and 20.3 minutes, respectively. In contrast, AS and HA have negative average delays, indicating that they tend to arrive early on average.

This comparison is more fair than ranking airlines across all destinations because it reduces the influence of route-specific factors such as distance, weather, and airport congestion. Although differences in performance still remain, the results are more interpretable when airlines are compared only on destinations they have in common.

flights %>%
  distinct(dest, carrier) %>%
  group_by(dest) %>%
  summarise(n_carriers = n()) %>%
  filter(n_carriers >= 2) %>%
  arrange(desc(n_carriers))
## # A tibble: 76 × 2
##    dest  n_carriers
##    <chr>      <int>
##  1 ATL            7
##  2 BOS            7
##  3 CLT            7
##  4 ORD            7
##  5 TPA            7
##  6 AUS            6
##  7 DCA            6
##  8 DTW            6
##  9 IAD            6
## 10 MSP            6
## # ℹ 66 more rows
shared_dests <- flights %>%
  distinct(dest, carrier) %>%
  group_by(dest) %>%
  summarise(n_carriers = n()) %>%
  filter(n_carriers >= 2)

flights %>%
  semi_join(shared_dests, by = "dest") %>%
  group_by(carrier) %>%
  summarise(avg_delay = mean(arr_delay, na.rm = TRUE)) %>%
  arrange(desc(avg_delay))
## # A tibble: 16 × 2
##    carrier avg_delay
##    <chr>       <dbl>
##  1 F9         21.9  
##  2 FL         20.3  
##  3 EV         15.7  
##  4 YV         15.6  
##  5 OO         11.9  
##  6 MQ         10.8  
##  7 B6          9.67 
##  8 WN          8.29 
##  9 9E          7.38 
## 10 UA          3.72 
## 11 US          2.13 
## 12 VX          1.82 
## 13 DL          1.64 
## 14 AA          0.364
## 15 HA         -6.92 
## 16 AS         -9.93

8

This analysis counts how many flights each plane completed before experiencing its first departure delay greater than 60 minutes. By arranging flights chronologically within each tail number and tracking when the first major delay occurred, it is possible to measure how long each plane operated before a substantial delay appeared.

The results show that tail number N954UW completed the most flights before its first major delay, with 206 flights. Other planes with long runs before a major delay included N952UW with 163 flights and N957UW with 142 flights.

Planes with higher values may reflect more stable operations or more favorable scheduling conditions. However, the results should be interpreted with caution, because some planes may appear to perform well simply because they did not experience a delay greater than 60 minutes during the time period covered by the dataset.

N954UW had the highest number of flights before its first major departure delay, with 206 flights.

flights %>%
  filter(!is.na(tailnum)) %>%
  arrange(tailnum, year, month, day, sched_dep_time) %>%
  group_by(tailnum) %>%
  mutate(
    big_delay = if_else(!is.na(dep_delay) & dep_delay > 60, TRUE, FALSE),
    delay_seen = cumsum(big_delay)
  ) %>%
  filter(delay_seen == 0) %>%
  summarise(flights_before_delay = n()) %>%
  arrange(desc(flights_before_delay))
## # A tibble: 3,815 × 2
##    tailnum flights_before_delay
##    <chr>                  <int>
##  1 N954UW                   206
##  2 N952UW                   163
##  3 N957UW                   142
##  4 N5FAAA                   117
##  5 N516JB                   102
##  6 N38727                    99
##  7 N3742C                    98
##  8 N5EWAA                    98
##  9 N705TW                    97
## 10 N765US                    97
## # ℹ 3,805 more rows

LS0tCnRpdGxlOiAiSFcgMzogRGF0YSBUcmFuc2Zvcm1hdGlvbiIKYXV0aG9yOiAiQ2FpdGxpbiBLZW5uZWR5IgpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDogb3BlbmludHJvOjpsYWJfcmVwb3J0Ci0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0UpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KG9wZW5pbnRybykKCmBgYAoKIyMjIEV4ZXJjaXNlIDEKCmBgYHtyIGxvYWQtZGF0YX0KcmFtZW5fcmF0aW5ncyA8LSByZWFkcjo6cmVhZF9jc3YoCiAgImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9yZm9yZGF0YXNjaWVuY2UvdGlkeXR1ZXNkYXkvbWFzdGVyL2RhdGEvMjAxOS8yMDE5LTA2LTA0L3JhbWVuX3JhdGluZ3MuY3N2IgopCmBgYAoKCiMjIyBFeGVyY2lzZSAyCgpEYXRhc2V0IFN1bW1hcnkKClRoZSByYW1lbiByYXRpbmdzIGRhdGFzZXQgY29udGFpbnMgMywxODAgb2JzZXJ2YXRpb25zIGFuZCA2IHZhcmlhYmxlcywgaW5jbHVkaW5nIHJldmlldyBudW1iZXIsIGJyYW5kLCB2YXJpZXR5LCBzdHlsZSwgY291bnRyeSwgYW5kIHN0YXIgcmF0aW5nLgoKVGhlIGRhdGFzZXQgaW5jbHVkZXMgYm90aCBjYXRlZ29yaWNhbCB2YXJpYWJsZXMgKGJyYW5kLCB2YXJpZXR5LCBzdHlsZSwgYW5kIGNvdW50cnkpIGFuZCBudW1lcmljYWwgdmFyaWFibGVzIChyZXZpZXdfbnVtYmVyIGFuZCBzdGFycykuIEEgdG90YWwgb2YgNDU2IHVuaXF1ZSBicmFuZHMsIDQ0IGNvdW50cmllcywgYW5kIDggcmFtZW4gc3R5bGVzIGFyZSByZXByZXNlbnRlZC4KClRoZSBzdGFyIHJhdGluZyByYW5nZXMgZnJvbSAwIHRvIDUsIHdpdGg6CgpNZWFuIHJhdGluZyA9IDMuNjkKTWVkaWFuIHJhdGluZyA9IDMuNzUKCk1vc3QgcmF0aW5ncyBmYWxsIGJldHdlZW4gMy4yNSBhbmQgNC41LCBpbmRpY2F0aW5nIGdlbmVyYWxseSBmYXZvcmFibGUgcmV2aWV3cy4gVGhlcmUgYXJlIDE0IG1pc3NpbmcgdmFsdWVzIGluIHRoZSBzdGFyIHJhdGluZyB2YXJpYWJsZS4KCmBgYHtyIHBhY2stcGxvdH0KcmFtZW5fcmF0aW5ncyAlPiUKICBmaWx0ZXIoc3R5bGUgPT0gIlBhY2siLCAhaXMubmEoc3RhcnMpKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBzdGFycykpICsKICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDAuNSkgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJEaXN0cmlidXRpb24gb2YgUmFtZW4gUmF0aW5ncyAoUGFjaykiLAogICAgeCA9ICJTdGFycyIsCiAgICB5ID0gIkNvdW50IgogICkKYGBgCgojIyMgRXhlcmNpc2UgMwoKSW50ZXJwcmV0YXRpb24gb2YgRGlzdHJpYnV0aW9uIChQYWNrIFN0eWxlKQoKVGhlIGRpc3RyaWJ1dGlvbiBvZiByYW1lbiByYXRpbmdzIGZvciB0aGUg4oCcUGFja+KAnSBzdHlsZSBzaG93cyB0aGF0IG1vc3QgcHJvZHVjdHMgcmVjZWl2ZSByZWxhdGl2ZWx5IGhpZ2ggcmF0aW5ncy4gVGhlIG1ham9yaXR5IG9mIG9ic2VydmF0aW9ucyBmYWxsIGJldHdlZW4gMyBhbmQgNSBzdGFycywgd2l0aCBhIGNsZWFyIGNvbmNlbnRyYXRpb24gYXJvdW5kIDMuNSB0byA0IHN0YXJzLgoKVGhlIGRpc3RyaWJ1dGlvbiBpcyBsZWZ0LXNrZXdlZCwgaW5kaWNhdGluZyB0aGF0IHdoaWxlIG1vc3QgcmFtZW4gcHJvZHVjdHMgYXJlIHJhdGVkIGZhdm9yYWJseSwgdGhlcmUgYXJlIGEgc21hbGxlciBudW1iZXIgb2YgbG93LXJhdGVkIHByb2R1Y3RzIGV4dGVuZGluZyB0b3dhcmQgMC4gUmF0aW5ncyBiZWxvdyAyIHN0YXJzIGFyZSB1bmNvbW1vbi4KCk92ZXJhbGwsIHRoaXMgc3VnZ2VzdHMgdGhhdCDigJxQYWNr4oCdIHN0eWxlIHJhbWVuIGlzIGdlbmVyYWxseSB3ZWxsLXJldmlld2VkLCB3aXRoIG1vc3QgcHJvZHVjdHMgcmVjZWl2aW5nIG1vZGVyYXRlIHRvIGhpZ2ggcmF0aW5ncy4KClRoaXMgcGF0dGVybiBhbGlnbnMgd2l0aCB0aGUgb3ZlcmFsbCBkYXRhc2V0IHN1bW1hcnksIHdoZXJlIHRoZSBtZWFuICgzLjY5KSBhbmQgbWVkaWFuICgzLjc1KSBhbHNvIGluZGljYXRlIGdlbmVyYWxseSBwb3NpdGl2ZSByYXRpbmdzLgoKYGBge3IgcGFjay1wbG90LTF9CnJhbWVuX3JhdGluZ3MgJT4lCiAgZmlsdGVyKHN0eWxlID09ICJQYWNrIiwgIWlzLm5hKHN0YXJzKSkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gc3RhcnMpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAwLjUpICsKICBsYWJzKAogICAgdGl0bGUgPSAiRGlzdHJpYnV0aW9uIG9mIFJhbWVuIFJhdGluZ3MgKFBhY2spIiwKICAgIHggPSAiU3RhcnMiLAogICAgeSA9ICJDb3VudCIKICApCmBgYAoKIyMjIEV4ZXJjaXNlIDQKCkNvbXBhcmlzb24gb2YgUmFtZW4gUmF0aW5ncyBieSBTdHlsZQoKVGhlIGZhY2V0ZWQgaGlzdG9ncmFtcyBpbGx1c3RyYXRlIHRoZSBkaXN0cmlidXRpb24gb2Ygc3RhciByYXRpbmdzIGFjcm9zcyBkaWZmZXJlbnQgcmFtZW4gc3R5bGVzLiBPdmVyYWxsLCBtb3N0IHN0eWxlcyBzaG93IGEgc2ltaWxhciBwYXR0ZXJuLCB3aXRoIHJhdGluZ3MgY29uY2VudHJhdGVkIGJldHdlZW4gMyBhbmQgNSBzdGFycywgaW5kaWNhdGluZyBnZW5lcmFsbHkgZmF2b3JhYmxlIHJldmlld3MgcmVnYXJkbGVzcyBvZiBwYWNrYWdpbmcgdHlwZS4KClRoZSBQYWNrIHN0eWxlIGhhcyB0aGUgbGFyZ2VzdCBudW1iZXIgb2Ygb2JzZXJ2YXRpb25zIGFuZCBzaG93cyBhIHN0cm9uZyBjb25jZW50cmF0aW9uIG9mIHJhdGluZ3MgYmV0d2VlbiAzLjUgYW5kIDUgc3RhcnMsIHN1Z2dlc3RpbmcgY29uc2lzdGVudGx5IGhpZ2ggcmF0aW5ncy4gU2ltaWxhcmx5LCBDdXAgYW5kIEJvd2wgc3R5bGVzIGFsc28gZGlzcGxheSBhIGhpZ2ggZnJlcXVlbmN5IG9mIHJhdGluZ3MgaW4gdGhpcyByYW5nZSwgdGhvdWdoIHdpdGggZmV3ZXIgb2JzZXJ2YXRpb25zIHRoYW4gUGFjay4KCkluIGNvbnRyYXN0LCBzdHlsZXMgc3VjaCBhcyBCYXIsIENhbiwgQm94LCBhbmQgUmVzdGF1cmFudCBoYXZlIHZlcnkgZmV3IG9ic2VydmF0aW9ucywgbWFraW5nIGl0IGRpZmZpY3VsdCB0byBkcmF3IG1lYW5pbmdmdWwgY29uY2x1c2lvbnMgYWJvdXQgdGhlaXIgcmF0aW5nIGRpc3RyaWJ1dGlvbnMuIFRoZXNlIHNtYWxsZXIgY2F0ZWdvcmllcyBzaG93IGxpbWl0ZWQgdmFyaWFiaWxpdHkgZHVlIHRvIHRoZSBzbWFsbCBzYW1wbGUgc2l6ZXMuCgpPdmVyYWxsLCB3aGlsZSBtb3N0IHJhbWVuIHN0eWxlcyBhcmUgd2VsbC1yYXRlZCwgdGhlIFBhY2ssIEN1cCwgYW5kIEJvd2wgc3R5bGVzIGRvbWluYXRlIHRoZSBkYXRhc2V0IGFuZCBkZW1vbnN0cmF0ZSBjb25zaXN0ZW50bHkgaGlnaGVyIHJhdGluZ3MgY29tcGFyZWQgdG8gbGVzcyBjb21tb24gc3R5bGVzLgoKYGBge3J9CmdncGxvdChyYW1lbl9yYXRpbmdzICU+JSBmaWx0ZXIoIWlzLm5hKHN0YXJzKSksIGFlcyh4ID0gc3RhcnMpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAwLjUpICsKICBmYWNldF93cmFwKH5zdHlsZSkgKwogIGxhYnModGl0bGUgPSAiUmFtZW4gUmF0aW5ncyBieSBTdHlsZSIsCiAgICAgICB4ID0gIlN0YXJzIiwKICAgICAgIHkgPSAiQ291bnQiKQpgYGAKCiMjIyBFeGVyY2lzZSA1CgpSYW1lbiBQcm9kdWN0cyBieSBDb3VudHJ5CgpUaGUgYmFyIGNoYXJ0IHNob3dzIHRoYXQgSmFwYW4gcHJvZHVjZXMgdGhlIGhpZ2hlc3QgbnVtYmVyIG9mIHJhbWVuIHByb2R1Y3RzIGJ5IGEgd2lkZSBtYXJnaW4sIHNpZ25pZmljYW50bHkgZXhjZWVkaW5nIGFsbCBvdGhlciBjb3VudHJpZXMgaW4gdGhlIGRhdGFzZXQuIFRoaXMgaGlnaGxpZ2h0cyBKYXBhbuKAmXMgY2VudHJhbCByb2xlIGluIHRoZSBnbG9iYWwgcmFtZW4gbWFya2V0LgoKQSBzZWNvbmQgdGllciBvZiBjb3VudHJpZXMsIGluY2x1ZGluZyB0aGUgVW5pdGVkIFN0YXRlcywgU291dGggS29yZWEsIFRhaXdhbiwgQ2hpbmEgYW5kIFRoYWlsYW5kLCBhbHNvIGNvbnRyaWJ1dGUgYSBzdWJzdGFudGlhbCBudW1iZXIgb2YgcHJvZHVjdHMsIHRob3VnaCBhdCBtdWNoIGxvd2VyIGxldmVscyB0aGFuIEphcGFuLgoKQmV5b25kIHRoZXNlIHRvcCBjb250cmlidXRvcnMsIHRoZXJlIGlzIGEgc2hhcnAgZGVjbGluZSBpbiB0aGUgbnVtYmVyIG9mIHByb2R1Y3RzIGJ5IGNvdW50cnkuIE1vc3QgY291bnRyaWVzIGhhdmUgcmVsYXRpdmVseSBmZXcgcmFtZW4gcHJvZHVjdHMgcmVwcmVzZW50ZWQsIHdpdGggbWFueSBjb250cmlidXRpbmcgZmV3ZXIgdGhhbiAxMDAgb2JzZXJ2YXRpb25zLgoKT3ZlcmFsbCwgdGhlIGRpc3RyaWJ1dGlvbiBpcyBoaWdobHkgc2tld2VkLCB3aXRoIGEgc21hbGwgbnVtYmVyIG9mIGNvdW50cmllcyBkb21pbmF0aW5nIHByb2R1Y3Rpb24gYW5kIGEgbG9uZyB0YWlsIG9mIGNvdW50cmllcyB3aXRoIG1pbmltYWwgcmVwcmVzZW50YXRpb24uCgpJIG5vdGljZWQgc29tZSBkdXBsaWNhdGUgY291bnRyeSBlbnRyaWVzIChVbml0ZWQgU3RhdGVzIGFuZCBQaGlsaXBwaW5lcykgYW5kIGNsZWFuZWQgdGhlIGRhdGEuIEJlZm9yZSBjcmVhdGluZyB0aGUgZmluYWwgYmFyIGNoYXJ0LCBJIHN0YW5kYXJkaXplZCBjb3VudHJ5IGxhYmVscyB0byBjb3JyZWN0IGluY29uc2lzdGVudCBlbnRyaWVzIGFuZCB0eXBvZ3JhcGhpY2FsIGVycm9ycyBzbyB0aGF0IGR1cGxpY2F0ZSBjb3VudHJ5IGNhdGVnb3JpZXMgd2VyZSBjb21iaW5lZCBpbnRvIGEgc2luZ2xlLCBhY2N1cmF0ZSBjb3VudC4gVGhpcyBkYXRhIGNsZWFuaW5nIGRpZCBub3QgY2hhbmdlIHRoZSBpbnRlcnByZXRhdGlvbi4KCmBgYHtyfQpyYW1lbl9yYXRpbmdzICU+JQogIGNvdW50KGNvdW50cnkpICU+JQogIGFycmFuZ2UoZGVzYyhuKSkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gcmVvcmRlcihjb3VudHJ5LCBuKSwgeSA9IG4pKSArCiAgZ2VvbV9jb2woKSArCiAgY29vcmRfZmxpcCgpICsKICBsYWJzKHRpdGxlID0gIlJhbWVuIFByb2R1Y3RzIGJ5IENvdW50cnkiLAogICAgICAgeCA9ICJDb3VudHJ5IiwKICAgICAgIHkgPSAiQ291bnQiKQoKCnJhbWVuX3JhdGluZ3NfY2xlYW4gPC0gcmFtZW5fcmF0aW5ncyAlPiUKICBtdXRhdGUoY291bnRyeSA9IGlmX2Vsc2UoY291bnRyeSA9PSAiVVNBIiwgIlVuaXRlZCBTdGF0ZXMiLCBjb3VudHJ5KSkKCgpyYW1lbl9yYXRpbmdzX2NsZWFuICU+JQogIGNvdW50KGNvdW50cnkpICU+JQogIGFycmFuZ2UoZGVzYyhuKSkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gcmVvcmRlcihjb3VudHJ5LCBuKSwgeSA9IG4pKSArCiAgZ2VvbV9jb2woKSArCiAgY29vcmRfZmxpcCgpICsKICBsYWJzKHRpdGxlID0gIlJhbWVuIFByb2R1Y3RzIGJ5IENvdW50cnkiLAogICAgICAgeCA9ICJDb3VudHJ5IiwKICAgICAgIHkgPSAiQ291bnQiKQpgYGAKCiMjIyBFeGVyY2lzZSA2CgpIaWdoZXN0IE1lYW4gU3RhcnMgUmF0aW5nIGJ5IENvdW50cnkKCkFmdGVyIGdyb3VwaW5nIHRoZSBkYXRhIGJ5IGNvdW50cnkgYW5kIGNhbGN1bGF0aW5nIHRoZSBhdmVyYWdlIHN0YXIgcmF0aW5nLCBDYW1ib2RpYSBoYWQgdGhlIGhpZ2hlc3QgbWVhbiBzdGFycyByYXRpbmcgYXQgNC4yMCBzdGFycy4gVGhpcyBpbmRpY2F0ZXMgdGhhdCwgb24gYXZlcmFnZSwgcmFtZW4gcHJvZHVjdHMgZnJvbSBDYW1ib2RpYSByZWNlaXZlZCB0aGUgc3Ryb25nZXN0IHJhdGluZ3MgaW4gdGhlIGRhdGFzZXQKCkJlY2F1c2Ugc29tZSBjb3VudHJpZXMgaGF2ZSBmYXIgZmV3ZXIgb2JzZXJ2YXRpb25zIHRoYW4gb3RoZXJzLCB0aGUgaGlnaGVzdCBhdmVyYWdlIHJhdGluZyBtYXkgYmUgYmFzZWQgb24gYSByZWxhdGl2ZWx5IHNtYWxsIG51bWJlciBvZiByYW1lbiBwcm9kdWN0cy4gU28gd2hpbGUgQ2FtYm9kaWEgaGFzIHRoZSBoaWdoZXN0IG1lYW4gcmF0aW5nIGluIHRoaXMgZGF0YXNldCwgY291bnRyaWVzIHdpdGggbW9yZSBwcm9kdWN0cyBtYXkgcHJvdmlkZSBhIG1vcmUgc3RhYmxlIGVzdGltYXRlIG9mIGF2ZXJhZ2UgcXVhbGl0eS4KCmBgYHtyfQoKcmFtZW5fcmF0aW5nc19jbGVhbiAlPiUKICBncm91cF9ieShjb3VudHJ5KSAlPiUKICBzdW1tYXJpc2UobWVhbl9zdGFycyA9IG1lYW4oc3RhcnMsIG5hLnJtID0gVFJVRSkpICU+JQogIGFycmFuZ2UoZGVzYyhtZWFuX3N0YXJzKSkgJT4lCiAgcHJpbnQobiA9IEluZikKYGBgCgojIyMgRXhlcmNpc2VzIDUuNC4xCgpgYGB7ciBsb2FkLWZsaWdodHN9CmxpYnJhcnkoZHBseXIpCmxpYnJhcnkobnljZmxpZ2h0czEzKQoKZmxpZ2h0cyA8LSBueWNmbGlnaHRzMTM6OmZsaWdodHMKYGBgCgoKIyMjIDEKClRoZXJlIGFyZSBtdWx0aXBsZSB3YXlzIHRvIHNlbGVjdCB2YXJpYWJsZXMgaW4gYSBkYXRhc2V0LiBDb2x1bW5zIGNhbiBiZSBzZWxlY3RlZCBkaXJlY3RseSBieSBuYW1lLCBvciBieSB1c2luZyBoZWxwZXIgZnVuY3Rpb25zIHN1Y2ggYXMgYHN0YXJ0c193aXRoKClgLCBgZW5kc193aXRoKClgLCBhbmQgYGNvbnRhaW5zKClgLiBBbm90aGVyIGZsZXhpYmxlIG9wdGlvbiBpcyB0byBjcmVhdGUgYSB2ZWN0b3Igb2YgdmFyaWFibGUgbmFtZXMgYW5kIHVzZSBgYWxsX29mKClgIHRvIHNlbGVjdCB0aG9zZSB2YXJpYWJsZXMuCgpgYGB7ciBzZWxlY3QtbWV0aG9kc30KIyBCYXNpYyBzZWxlY3QKc2VsZWN0KGZsaWdodHMsIGRlcF90aW1lLCBkZXBfZGVsYXksIGFycl90aW1lLCBhcnJfZGVsYXkpCgojIFVzaW5nIHN0YXJ0c193aXRoCnNlbGVjdChmbGlnaHRzLCBzdGFydHNfd2l0aCgiZGVwIiksIHN0YXJ0c193aXRoKCJhcnIiKSkKCiMgVXNpbmcgZW5kc193aXRoCnNlbGVjdChmbGlnaHRzLCBlbmRzX3dpdGgoInRpbWUiKSwgZW5kc193aXRoKCJkZWxheSIpKQoKIyBVc2luZyBjb250YWlucwpzZWxlY3QoZmxpZ2h0cywgY29udGFpbnMoInRpbWUiKSwgY29udGFpbnMoImRlbGF5IikpCgojIFVzaW5nIGEgdmVjdG9yCnZhcnMgPC0gYygiZGVwX3RpbWUiLCAiZGVwX2RlbGF5IiwgImFycl90aW1lIiwgImFycl9kZWxheSIpCnNlbGVjdChmbGlnaHRzLCBhbGxfb2YodmFycykpCmBgYAoKIyMjIDIKCklmIGEgdmFyaWFibGUgaXMgaW5jbHVkZWQgbXVsdGlwbGUgdGltZXMgaW4gYSBgc2VsZWN0KClgIHN0YXRlbWVudCwgaXQgd2lsbCBvbmx5IGFwcGVhciBvbmNlIGluIHRoZSByZXN1bHRpbmcgZGF0YXNldC4gVGhlIGBzZWxlY3QoKWAgZnVuY3Rpb24gYXV0b21hdGljYWxseSByZW1vdmVzIGR1cGxpY2F0ZSBjb2x1bW5zLgoKYGBge3IgZHVwbGljYXRlLXNlbGVjdH0KZHBseXI6OnNlbGVjdChmbGlnaHRzLCBkZXBfdGltZSwgZGVwX3RpbWUsIGFycl90aW1lKQpgYGAKCiMjIyAzCgpUaGUgYGFueV9vZigpYCBmdW5jdGlvbiBzZWxlY3RzIHZhcmlhYmxlcyBmcm9tIGEgdmVjdG9yIGJ1dCBkb2VzIG5vdCBwcm9kdWNlIGFuIGVycm9yIGlmIHNvbWUgdmFyaWFibGVzIGFyZSBtaXNzaW5nLiBJbnN0ZWFkLCBpdCBvbmx5IHNlbGVjdHMgdGhlIHZhcmlhYmxlcyB0aGF0IGV4aXN0IGluIHRoZSBkYXRhc2V0LiBUaGlzIGlzIHVzZWZ1bCB3aGVuIHdvcmtpbmcgd2l0aCB2YXJpYWJsZSBsaXN0cyB0aGF0IG1heSBub3QgYWx3YXlzIG1hdGNoIHRoZSBkYXRhc2V0IGV4YWN0bHkuCgpgYGB7ciBhbnktb2Z9CnZhcnMgPC0gYygieWVhciIsICJtb250aCIsICJkYXkiLCAiZGVwX2RlbGF5IiwgImFycl9kZWxheSIpCgpkcGx5cjo6c2VsZWN0KGZsaWdodHMsIGFueV9vZih2YXJzKSkKYGBgCgojIyMgNAoKVGhlIHJlc3VsdCBtYXkgYmUgc3VycHJpc2luZyBiZWNhdXNlIGBjb250YWlucygiVElNRSIpYCBzdGlsbCBtYXRjaGVzIHZhcmlhYmxlcyBzdWNoIGFzIGBkZXBfdGltZWAgYW5kIGBhcnJfdGltZWAuIFRoaXMgaXMgYmVjYXVzZSBzZWxlY3QgaGVscGVyIGZ1bmN0aW9ucyBhcmUgY2FzZS1pbnNlbnNpdGl2ZSBieSBkZWZhdWx0LiBUaGlzIGJlaGF2aW9yIGNhbiBiZSBjaGFuZ2VkIGJ5IHNldHRpbmcgYGlnbm9yZS5jYXNlID0gRkFMU0VgLCB3aGljaCBmb3JjZXMgY2FzZS1zZW5zaXRpdmUgbWF0Y2hpbmcuCgpgYGB7ciBjb250YWlucy1jYXNlfQpzZWxlY3QoZmxpZ2h0cywgY29udGFpbnMoIlRJTUUiKSkKCmBgYAoKIyMjIEV4ZXJjaXNlcyA1LjUuMgoKIyMjIDEKClRoZSB2YXJpYWJsZXMgYGRlcF90aW1lYCBhbmQgYHNjaGVkX2RlcF90aW1lYCBhcmUgc3RvcmVkIGluIEhITU0gZm9ybWF0LCB3aGljaCBtYWtlcyB0aGVtIGRpZmZpY3VsdCB0byBhbmFseXplLiBCeSBjb252ZXJ0aW5nIHRoZW0gaW50byBtaW51dGVzIHNpbmNlIG1pZG5pZ2h0LCB3ZSBjcmVhdGUgY29udGludW91cyBudW1lcmljIHZhcmlhYmxlcyB0aGF0IGFyZSBlYXNpZXIgdG8gdXNlIGluIGNhbGN1bGF0aW9ucyBhbmQgY29tcGFyaXNvbnMuCgpgYGB7ciBjb252ZXJ0LXRpbWV9CmZsaWdodHMgPC0gZmxpZ2h0cyAlPiUKICBtdXRhdGUoCiAgICBkZXBfdGltZV9taW51dGVzID0gKGRlcF90aW1lICUvJSAxMDApICogNjAgKyAoZGVwX3RpbWUgJSUgMTAwKSwKICAgIHNjaGVkX2RlcF90aW1lX21pbnV0ZXMgPSAoc2NoZWRfZGVwX3RpbWUgJS8lIDEwMCkgKiA2MCArIChzY2hlZF9kZXBfdGltZSAlJSAxMDApCiAgKQpgYGAKCiMjIyAyCgpXZSB3b3VsZCBleHBlY3QgYGFpcl90aW1lYCB0byBiZSBzaW1pbGFyIHRvIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gYXJyaXZhbCBhbmQgZGVwYXJ0dXJlIHRpbWVzLiBIb3dldmVyLCB0aGlzIGRpZmZlcmVuY2UgY2FuIGJlIGluYWNjdXJhdGUgZHVlIHRvIGlzc3VlcyBzdWNoIGFzIGNyb3NzaW5nIG1pZG5pZ2h0IG9yIGRpZmZlcmVuY2VzIGluIHRpbWUgem9uZXMuIFRvIGZpeCB0aGlzLCB0aW1lIHZhcmlhYmxlcyBzaG91bGQgZmlyc3QgYmUgY29udmVydGVkIGludG8gYSBjb250aW51b3VzIGZvcm1hdCAoc3VjaCBhcyBtaW51dGVzIHNpbmNlIG1pZG5pZ2h0KSwgYW5kIGFkanVzdG1lbnRzIHNob3VsZCBiZSBtYWRlIGZvciBvdmVybmlnaHQgZmxpZ2h0cy4KCmBgYHtyIGZsaWdodC10aW1lLWNvbXBhcmlzb259CmZsaWdodHMgPC0gZmxpZ2h0cyAlPiUKICBtdXRhdGUoCiAgICB0cmF2ZWxfdGltZSA9IGFycl90aW1lIC0gZGVwX3RpbWUKICApCgpzdW1tYXJ5KGZsaWdodHMkYWlyX3RpbWUpCnN1bW1hcnkoZmxpZ2h0cyR0cmF2ZWxfdGltZSkKYGBgCgojIyMgMwoKV2Ugd291bGQgZXhwZWN0IHRoZSBkZXBhcnR1cmUgZGVsYXkgdG8gZXF1YWwgdGhlIGRpZmZlcmVuY2UgYmV0d2VlbiBhY3R1YWwgYW5kIHNjaGVkdWxlZCBkZXBhcnR1cmUgdGltZXMuIEhvd2V2ZXIsIGJlY2F1c2UgdGltZXMgYXJlIHN0b3JlZCBpbiBISE1NIGZvcm1hdCwgdGhlIHJlbGF0aW9uc2hpcCBpcyBub3QgZXhhY3Qgd2l0aG91dCBjb252ZXJ0aW5nIHRoZW0gaW50byBjb250aW51b3VzIHRpbWUuIEFmdGVyIGNvbnZlcnNpb24sIHRoZSBjYWxjdWxhdGVkIGRlbGF5IHNob3VsZCBjbG9zZWx5IG1hdGNoIHRoZSByZWNvcmRlZCBgZGVwX2RlbGF5YC4KCmBgYHtyIGRlcC1kZWxheS1yZWxhdGlvbnNoaXB9CmZsaWdodHMgPC0gZmxpZ2h0cyAlPiUKICBkcGx5cjo6bXV0YXRlKAogICAgY2FsY3VsYXRlZF9kZWxheSA9IGRlcF90aW1lIC0gc2NoZWRfZGVwX3RpbWUKICApCgpkcGx5cjo6c2VsZWN0KGZsaWdodHMsIGRlcF90aW1lLCBzY2hlZF9kZXBfdGltZSwgZGVwX2RlbGF5LCBjYWxjdWxhdGVkX2RlbGF5KSAlPiUKICBoZWFkKCkKYGBgCgoKIyMjIDQKClRoZSBgbWluX3JhbmsoKWAgZnVuY3Rpb24gYXNzaWducyB0aGUgc2FtZSByYW5rIHRvIHRpZWQgdmFsdWVzLCB3aGljaCBtZWFucyB0aGF0IGlmIG11bHRpcGxlIGZsaWdodHMgc2hhcmUgdGhlIHNhbWUgZGVsYXksIHRoZXkgd2lsbCByZWNlaXZlIHRoZSBzYW1lIHJhbmsuIFRoaXMgY2FuIHJlc3VsdCBpbiBtb3JlIHRoYW4gMTAgcm93cyBiZWluZyByZXR1cm5lZCB3aGVuIHRpZXMgYXJlIHByZXNlbnQuCgpgYGB7ciBtb3N0LWRlbGF5ZWR9CmZsaWdodHMgJT4lCiAgbXV0YXRlKHJhbmsgPSBtaW5fcmFuayhkZXNjKGRlcF9kZWxheSkpKSAlPiUKICBmaWx0ZXIocmFuayA8PSAxMCkgJT4lCiAgc2VsZWN0KHllYXIsIG1vbnRoLCBkYXksIGRlcF90aW1lLCBkZXBfZGVsYXksIHJhbmspCmBgYAoKIyMjIDUKClRoZSBleHByZXNzaW9uIDE6MyArIDE6MTAgcmV0dXJucyBhIG51bWVyaWMgdmVjdG9yIG9mIGxlbmd0aCAxMC4gVGhpcyBvY2N1cnMgYmVjYXVzZSBvZiBS4oCZcyB2ZWN0b3IgcmVjeWNsaW5nIGJlaGF2aW9yLCB3aGVyZSB0aGUgc2hvcnRlciB2ZWN0b3IgKDE6MykgaXMgcmVwZWF0ZWQgdG8gbWF0Y2ggdGhlIGxlbmd0aCBvZiB0aGUgbG9uZ2VyIHZlY3RvciAoMToxMCkgYmVmb3JlIHBlcmZvcm1pbmcgZWxlbWVudC13aXNlIGFkZGl0aW9uLgoKSG93ZXZlciwgc2luY2UgdGhlIGxlbmd0aCBvZiB0aGUgbG9uZ2VyIHZlY3RvciAoMTApIGlzIG5vdCBhIG11bHRpcGxlIG9mIHRoZSBzaG9ydGVyIHZlY3RvciAoMyksIFIgcHJvZHVjZXMgYSB3YXJuaW5nIGluZGljYXRpbmcgdGhhdCB0aGUgcmVjeWNsaW5nIGlzIHVuZXZlbi4gVGhpcyByZXN1bHRzIGluIHRoZSBzaG9ydGVyIHZlY3RvciByZXBlYXRpbmcgcGFydGlhbGx5IHRocm91Z2ggaXRzIHNlcXVlbmNlLgoKYGBge3IgdmVjdG9yLXJlY3ljbGluZ30KMTozICsgMToxMApgYGAKCiMjIyA2CgpSIHByb3ZpZGVzIGEgZnVsbCBzZXQgb2YgdHJpZ29ub21ldHJpYyBmdW5jdGlvbnMsIGluY2x1ZGluZyBgc2luKClgLCBgY29zKClgLCBgdGFuKClgLCBhcyB3ZWxsIGFzIHRoZWlyIGludmVyc2VzIHN1Y2ggYXMgYGFzaW4oKWAsIGBhY29zKClgLCBhbmQgYGF0YW4oKWAuIFRoZXNlIGZ1bmN0aW9ucyBvcGVyYXRlIG9uIG51bWVyaWMgaW5wdXRzIGFuZCByZXR1cm4gdmFsdWVzIGluIHJhZGlhbnMgYnkgZGVmYXVsdC4KCiMjIyBFeGVyY2lzZXMgNS42LjcKCmBgYHtyIGNyZWF0ZS1ub3QtY2FuY2VsbGVkfQpub3RfY2FuY2VsbGVkIDwtIGZsaWdodHMgJT4lCiAgZmlsdGVyKCFpcy5uYShkZXBfZGVsYXkpLCAhaXMubmEoYXJyX2RlbGF5KSkKCmBgYAoKIyMjIDEKClRoZXJlIGFyZSBzZXZlcmFsIHdheXMgdG8gYXNzZXNzIHR5cGljYWwgZGVsYXkgY2hhcmFjdGVyaXN0aWNzOgoKMS4gKipNZWFuIGRlbGF5Kiog4oCTIHByb3ZpZGVzIHRoZSBhdmVyYWdlIGRlbGF5IGJ1dCBjYW4gYmUgaGVhdmlseSBpbmZsdWVuY2VkIGJ5IGV4dHJlbWUgdmFsdWVzLgoyLiAqKk1lZGlhbiBkZWxheSoqIOKAkyBnaXZlcyB0aGUgdHlwaWNhbCBkZWxheSBhbmQgaXMgbW9yZSByb2J1c3QgdG8gb3V0bGllcnMuCjMuICoqU3RhbmRhcmQgZGV2aWF0aW9uKiog4oCTIG1lYXN1cmVzIHZhcmlhYmlsaXR5IGluIGRlbGF5cy4KNC4gKipEaXN0cmlidXRpb24gKGhpc3RvZ3JhbSBvciBxdWFudGlsZXMpKiog4oCTIHNob3dzIHRoZSBmdWxsIHNwcmVhZCBvZiBkZWxheXMuCjUuICoqUHJvcG9ydGlvbiBvZiBkZWxheWVkIGZsaWdodHMqKiDigJMgc2hvd3MgaG93IGZyZXF1ZW50bHkgZGVsYXlzIG9jY3VyLgo2LiAqKk1heGltdW0gZGVsYXkgb3IgZXh0cmVtZSB2YWx1ZXMqKiDigJMgaGlnaGxpZ2h0cyByYXJlIGJ1dCBpbXBvcnRhbnQgZXZlbnRzLgoKRm9yIHRoZSBnaXZlbiBzY2VuYXJpb3M6Ci0gRmxpZ2h0cyB0aGF0IGFyZSBlcXVhbGx5IGVhcmx5IGFuZCBsYXRlIHdpbGwgaGF2ZSBhIG1lYW4gbmVhciB6ZXJvIGJ1dCBoaWdoIHZhcmlhYmlsaXR5LgotIEZsaWdodHMgdGhhdCBhcmUgYWx3YXlzIGxhdGUgd2lsbCBoYXZlIGEgY29uc2lzdGVudCBkZWxheSBhbmQgbG93IHZhcmlhYmlsaXR5LgotIFJhcmUgZXh0cmVtZSBkZWxheXMgKGUuZy4sIDElIHZlcnkgbGF0ZSBmbGlnaHRzKSB3aWxsIGluY3JlYXNlIHRoZSBtZWFuIGJ1dCBub3QgdGhlIG1lZGlhbi4KCioqQXJyaXZhbCBkZWxheSBpcyBnZW5lcmFsbHkgbW9yZSBpbXBvcnRhbnQgdGhhbiBkZXBhcnR1cmUgZGVsYXkqKiwgc2luY2UgaXQgcmVmbGVjdHMgdGhlIHRvdGFsIGltcGFjdCBvbiBwYXNzZW5nZXJzIHJlYWNoaW5nIHRoZWlyIGRlc3RpbmF0aW9uLCBpbmNsdWRpbmcgZGVsYXlzIGluY3VycmVkIGR1cmluZyB0aGUgZmxpZ2h0LgoKIyMjIDIKClRoZSBzYW1lIHJlc3VsdCBhcyBgY291bnQoKWAgY2FuIGJlIGNyZWF0ZWQgdXNpbmcgYGdyb3VwX2J5KClgIGFuZCBgc3VtbWFyaXNlKClgLiAKCi0gYGNvdW50KGRlc3QpYCBpcyBlcXVpdmFsZW50IHRvIGdyb3VwaW5nIGJ5IGBkZXN0YCBhbmQgdXNpbmcgYHN1bW1hcmlzZShuID0gbigpKWAuCi0gYGNvdW50KHRhaWxudW0sIHd0ID0gZGlzdGFuY2UpYCBpcyBlcXVpdmFsZW50IHRvIGdyb3VwaW5nIGJ5IGB0YWlsbnVtYCBhbmQgc3VtbWluZyB0aGUgYGRpc3RhbmNlYCB2YXJpYWJsZSB3aXRoIGBzdW1tYXJpc2UobiA9IHN1bShkaXN0YW5jZSwgbmEucm0gPSBUUlVFKSlgLgoKVGhpcyB3b3JrcyBiZWNhdXNlIGBjb3VudCgpYCBpcyBlc3NlbnRpYWxseSBhIHNob3J0Y3V0IGZvciBncm91cGluZyBvYnNlcnZhdGlvbnMgYW5kIHRoZW4gc3VtbWFyaXppbmcgdGhlbS4KCmBgYHtyIGNvdW50LWFsdGVybmF0aXZlfQojIEVxdWl2YWxlbnQgdG86IG5vdF9jYW5jZWxsZWQgJT4lIGNvdW50KGRlc3QpCm5vdF9jYW5jZWxsZWQgJT4lCiAgZ3JvdXBfYnkoZGVzdCkgJT4lCiAgc3VtbWFyaXNlKG4gPSBuKCkpCgojIEVxdWl2YWxlbnQgdG86IG5vdF9jYW5jZWxsZWQgJT4lIGNvdW50KHRhaWxudW0sIHd0ID0gZGlzdGFuY2UpCm5vdF9jYW5jZWxsZWQgJT4lCiAgZ3JvdXBfYnkodGFpbG51bSkgJT4lCiAgc3VtbWFyaXNlKG4gPSBzdW0oZGlzdGFuY2UsIG5hLnJtID0gVFJVRSkpCmBgYAoKIyMjIDMKClRoZSBkZWZpbml0aW9uIGBpcy5uYShkZXBfZGVsYXkpIHwgaXMubmEoYXJyX2RlbGF5KWAgaXMgc3Vib3B0aW1hbCBiZWNhdXNlIG1pc3NpbmcgYXJyaXZhbCBkZWxheSBkb2VzIG5vdCBhbHdheXMgaW5kaWNhdGUgY2FuY2VsbGF0aW9uLiBJbiBteSBzdW1tYXJ5LCBgYXJyX2RlbGF5YCBoYWQgbW9yZSBtaXNzaW5nIHZhbHVlcyAoOSw0MzApIHRoYW4gYGRlcF90aW1lYCBhbmQgYGRlcF9kZWxheWAgKDgsMjU1IGVhY2gpLCBzdWdnZXN0aW5nIHRoYXQgc29tZSBmbGlnaHRzIGhhdmUgbWlzc2luZyBhcnJpdmFsIGRlbGF5IGZvciBvdGhlciByZWFzb25zLiBUaGUgbW9zdCBpbXBvcnRhbnQgY29sdW1uIGlzIGBkZXBfdGltZWAsIHNpbmNlIGEgbWlzc2luZyBkZXBhcnR1cmUgdGltZSBpcyB0aGUgY2xlYXJlc3QgaW5kaWNhdG9yIHRoYXQgYSBmbGlnaHQgd2FzIGNhbmNlbGxlZC4KCmBgYHtyIGNoZWNrLW1pc3NpbmctdmFsdWVzfQpmbGlnaHRzICU+JQogIHN1bW1hcmlzZSgKICAgIG1pc3NpbmdfZGVwX3RpbWUgPSBzdW0oaXMubmEoZGVwX3RpbWUpKSwKICAgIG1pc3NpbmdfZGVwX2RlbGF5ID0gc3VtKGlzLm5hKGRlcF9kZWxheSkpLAogICAgbWlzc2luZ19hcnJfZGVsYXkgPSBzdW0oaXMubmEoYXJyX2RlbGF5KSkKICApCmBgYAoKIyMjIDQKClRoZSBkYWlseSBzdW1tYXJ5IHNob3dzIHRoYXQgdGhlIG51bWJlciBvZiBjYW5jZWxsZWQgZmxpZ2h0cyB2YXJpZXMgYWNyb3NzIHRoZSB5ZWFyLiBXaGlsZSB0aGUgb3ZlcmFsbCBjYW5jZWxsYXRpb24gcmF0ZSBpcyByZWxhdGl2ZWx5IGxvdywgaXQgZmx1Y3R1YXRlcyBmcm9tIGRheSB0byBkYXksIGluZGljYXRpbmcgdGhhdCBjYW5jZWxsYXRpb25zIGFyZSBub3QgZXZlbmx5IGRpc3RyaWJ1dGVkLiBGb3IgZXhhbXBsZSwgaW4gZWFybHkgSmFudWFyeSwgdGhlIG51bWJlciBvZiBjYW5jZWxsZWQgZmxpZ2h0cyByYW5nZXMgZnJvbSAxIHRvIDEwIHBlciBkYXksIHdpdGggY29ycmVzcG9uZGluZyB2YXJpYXRpb24gaW4gY2FuY2VsbGF0aW9uIHJhdGVzLgoKQXZlcmFnZSBkZXBhcnR1cmUgZGVsYXkgYWxzbyB2YXJpZXMgYWNyb3NzIGRheXMuIFNvbWUgZGF5cyB3aXRoIGhpZ2hlciBjYW5jZWxsYXRpb24gY291bnRzIHRlbmQgdG8gYWxzbyBoYXZlIGhpZ2hlciBhdmVyYWdlIGRlbGF5cywgc3VnZ2VzdGluZyB0aGF0IGRpc3J1cHRpb25zIGFmZmVjdGluZyBhaXJsaW5lIG9wZXJhdGlvbnPigJRzdWNoIGFzIHdlYXRoZXIgb3IgY29uZ2VzdGlvbuKAlG1heSBpbXBhY3QgYm90aCBjYW5jZWxsYXRpb25zIGFuZCBkZWxheXMgc2ltdWx0YW5lb3VzbHkuIEZvciBleGFtcGxlLCBKYW51YXJ5IDIgYW5kIEphbnVhcnkgMyBzaG93IHJlbGF0aXZlbHkgaGlnaGVyIGNhbmNlbGxhdGlvbiByYXRlcyBhbmQgaGlnaGVyIGF2ZXJhZ2UgZGVsYXlzIGNvbXBhcmVkIHRvIGxhdGVyIGRheXMgd2l0aCBmZXdlciBjYW5jZWxsYXRpb25zIGFuZCBsb3dlciBkZWxheXMuCgpPdmVyYWxsLCB0aGVyZSBhcHBlYXJzIHRvIGJlIGEgcG90ZW50aWFsIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGNhbmNlbGxhdGlvbiByYXRlcyBhbmQgYXZlcmFnZSBkZWxheSwgd2hlcmUgbW9yZSBkaXNydXB0aXZlIGRheXMgbWF5IGxlYWQgdG8gYm90aCBpbmNyZWFzZWQgY2FuY2VsbGF0aW9ucyBhbmQgbG9uZ2VyIGRlbGF5cy4gSG93ZXZlciwgdGhpcyByZWxhdGlvbnNoaXAgaXMgbm90IGVudGlyZWx5IGNsZWFyIGZyb20gdGhlIHRhYmxlIGFsb25lLCBhbmQgYSB2aXN1YWwgYW5hbHlzaXMgKHN1Y2ggYXMgYSBzY2F0dGVycGxvdCkgd291bGQgcHJvdmlkZSBhIGJldHRlciBhc3Nlc3NtZW50IG9mIHRoZSBzdHJlbmd0aCBvZiB0aGlzIHJlbGF0aW9uc2hpcC4KCmBgYHtyIGNhbmNlbGxhdGlvbnMtcGVyLWRheX0KZmxpZ2h0cyAlPiUKICBtdXRhdGUoY2FuY2VsbGVkID0gaXMubmEoZGVwX3RpbWUpKSAlPiUKICBncm91cF9ieSh5ZWFyLCBtb250aCwgZGF5KSAlPiUKICBzdW1tYXJpc2UoCiAgICB0b3RhbF9mbGlnaHRzID0gbigpLAogICAgY2FuY2VsbGVkX2ZsaWdodHMgPSBzdW0oY2FuY2VsbGVkKSwKICAgIGNhbmNlbF9yYXRlID0gY2FuY2VsbGVkX2ZsaWdodHMgLyB0b3RhbF9mbGlnaHRzLAogICAgYXZnX2RlbGF5ID0gbWVhbihkZXBfZGVsYXksIG5hLnJtID0gVFJVRSkKICApCmBgYAoKIyMjIDUKClRoZSByZXN1bHRzIHNob3cgY2xlYXIgZGlmZmVyZW5jZXMgaW4gYXZlcmFnZSBhcnJpdmFsIGRlbGF5cyBhY3Jvc3MgY2FycmllcnMuIFNvbWUgYWlybGluZXMgYXBwZWFyIHRvIGhhdmUgc2lnbmlmaWNhbnRseSBoaWdoZXIgZGVsYXlzIHRoYW4gb3RoZXJzLiBGb3IgZXhhbXBsZSwgY2FycmllcnMgc3VjaCBhcyBGOSBhbmQgRkwgaGF2ZSB0aGUgaGlnaGVzdCBhdmVyYWdlIGRlbGF5cywgYXQgYXBwcm94aW1hdGVseSAyMS45IGFuZCAyMC4xIG1pbnV0ZXMsIHJlc3BlY3RpdmVseS4gSW4gY29udHJhc3QsIGNhcnJpZXJzIHN1Y2ggYXMgQVMgYW5kIEhBIGhhdmUgbmVnYXRpdmUgYXZlcmFnZSBkZWxheXMsIGluZGljYXRpbmcgdGhhdCB0aGVpciBmbGlnaHRzIHRlbmQgdG8gYXJyaXZlIGVhcmxpZXIgdGhhbiBzY2hlZHVsZWQgb24gYXZlcmFnZS4KCkFsdGhvdWdoIHRoaXMgc3VtbWFyeSBzdWdnZXN0cyB0aGF0IHNvbWUgYWlybGluZXMgcGVyZm9ybSB3b3JzZSB0aGFuIG90aGVycywgdGhlIGNvbXBhcmlzb24gaXMgcG90ZW50aWFsbHkgbWlzbGVhZGluZy4gSXQgZG9lcyBub3QgYWNjb3VudCBmb3IgZGlmZmVyZW5jZXMgaW4gcm91dGVzLCBkZXN0aW5hdGlvbnMsIG9yIG9wZXJhdGluZyBjb25kaXRpb25zLiBGb3IgaW5zdGFuY2UsIHNvbWUgY2FycmllcnMgbWF5IGZseSBtb3JlIGZyZXF1ZW50bHkgdG8gY29uZ2VzdGVkIGFpcnBvcnRzIG9yIG92ZXIgbG9uZ2VyIGRpc3RhbmNlcywgYm90aCBvZiB3aGljaCBjYW4gaW5jcmVhc2UgZGVsYXlzLgoKQWRkaXRpb25hbGx5LCBhaXJsaW5lcyBzZXJ2aW5nIHNwZWNpZmljIHJlZ2lvbnMgb3Igb3BlcmF0aW5nIGxvbmctaGF1bCBmbGlnaHRzIG1heSBleHBlcmllbmNlIGRpZmZlcmVudCBwYXR0ZXJucyBvZiBkZWxheSB0aGFuIHRob3NlIG9wZXJhdGluZyBzaG9ydGVyIG9yIGxlc3MgY29uZ2VzdGVkIHJvdXRlcy4gQXMgYSByZXN1bHQsIHRoZSBvYnNlcnZlZCBkaWZmZXJlbmNlcyBpbiBhdmVyYWdlIGRlbGF5cyBtYXkgcmVmbGVjdCBmYWN0b3JzIGJleW9uZCB0aGUgYWlybGluZXPigJkgY29udHJvbCByYXRoZXIgdGhhbiB0cnVlIGRpZmZlcmVuY2VzIGluIHBlcmZvcm1hbmNlLgoKT3ZlcmFsbCwgd2hpbGUgdGhlIGFuYWx5c2lzIGlkZW50aWZpZXMgY2FycmllcnMgd2l0aCBoaWdoZXIgYXZlcmFnZSBkZWxheXMsIGEgZmFpciBjb21wYXJpc29uIHdvdWxkIHJlcXVpcmUgY29udHJvbGxpbmcgZm9yIGZhY3RvcnMgc3VjaCBhcyByb3V0ZSwgZGlzdGFuY2UsIGFuZCBhaXJwb3J0IGNvbmRpdGlvbnMuCgpBIG1vcmUgYWNjdXJhdGUgYW5hbHlzaXMgd291bGQgY29tcGFyZSBhaXJsaW5lcyBvcGVyYXRpbmcgb24gc2ltaWxhciByb3V0ZXMgb3IgYWRqdXN0IGZvciBmYWN0b3JzIHN1Y2ggYXMgZGlzdGFuY2UgYW5kIGFpcnBvcnQgY29uZ2VzdGlvbi4KCmBgYHtyIHdvcnN0LWNhcnJpZXJzfQpmbGlnaHRzICU+JQogIGdyb3VwX2J5KGNhcnJpZXIpICU+JQogIHN1bW1hcmlzZShhdmdfZGVsYXkgPSBtZWFuKGFycl9kZWxheSwgbmEucm0gPSBUUlVFKSkgJT4lCiAgYXJyYW5nZShkZXNjKGF2Z19kZWxheSkpCmBgYAoKIyMjIDYKClIgcHJvdmlkZXMgYSBmdWxsIHNldCBvZiB0cmlnb25vbWV0cmljIGZ1bmN0aW9ucywgaW5jbHVkaW5nIGBzaW4oKWAsIGBjb3MoKWAsIGFuZCBgdGFuKClgLCBhcyB3ZWxsIGFzIHRoZWlyIGludmVyc2UgZnVuY3Rpb25zIHN1Y2ggYXMgYGFzaW4oKWAsIGBhY29zKClgLCBhbmQgYGF0YW4oKWAuIFRoZXNlIGZ1bmN0aW9ucyBvcGVyYXRlIG9uIG51bWVyaWMgaW5wdXRzIGFuZCByZXR1cm4gdmFsdWVzIGJhc2VkIG9uIGFuZ2xlcyBtZWFzdXJlZCBpbiByYWRpYW5zLgoKRm9yIGV4YW1wbGUsIGBzaW4ocGkgLyAyKSA9IDFgLCBgY29zKDApID0gMWAsIGFuZCBgdGFuKHBpIC8gNCkgPSAxYCwgd2hpY2ggYXJlIGV4cGVjdGVkIHZhbHVlcyBmb3IgdGhlc2Ugc3RhbmRhcmQgYW5nbGVzLiBUaGlzIGNvbmZpcm1zIHRoYXQgUiB1c2VzIHJhZGlhbnMgcmF0aGVyIHRoYW4gZGVncmVlcyBieSBkZWZhdWx0LgoKVGhlc2UgZnVuY3Rpb25zIGFyZSB2ZWN0b3JpemVkLCBtZWFuaW5nIHRoZXkgY2FuIGJlIGFwcGxpZWQgdG8gZW50aXJlIHZlY3RvcnMgb2YgdmFsdWVzIGVmZmljaWVudGx5LCBtYWtpbmcgdGhlbSB1c2VmdWwgZm9yIG1hdGhlbWF0aWNhbCBhbmQgc3RhdGlzdGljYWwgY29tcHV0YXRpb25zLgoKYGBge3IgdHJpZy1mdW5jdGlvbnN9CnNpbihwaSAvIDIpCmNvcygwKQp0YW4ocGkgLyA0KQoKYGBgCgojIyMgRXhlcmNpc2VzIDUuNy4xCgojIyMgMQoKV2hlbiBgbXV0YXRlKClgIGlzIHVzZWQgd2l0aCBgZ3JvdXBfYnkoKWAsIHRoZSBjYWxjdWxhdGlvbnMgYXJlIHBlcmZvcm1lZCB3aXRoaW4gZWFjaCBncm91cCByYXRoZXIgdGhhbiBhY3Jvc3MgdGhlIGVudGlyZSBkYXRhc2V0LiBGb3IgZXhhbXBsZSwgbWVhbnMgb3IgcmFua3MgYXJlIGNvbXB1dGVkIHNlcGFyYXRlbHkgZm9yIGVhY2ggZ3JvdXAgaW5zdGVhZCBvZiBnbG9iYWxseS4KClNpbWlsYXJseSwgd2hlbiBgZmlsdGVyKClgIGlzIHVzZWQgd2l0aCBgZ3JvdXBfYnkoKWAsIHRoZSBmaWx0ZXJpbmcgY29uZGl0aW9ucyBhcmUgYXBwbGllZCB3aXRoaW4gZWFjaCBncm91cC4gRm9yIGV4YW1wbGUsIGZpbHRlcmluZyBmb3IgdGhlIG1heGltdW0gdmFsdWUgd2lsbCByZXR1cm4gdGhlIG1heGltdW0gd2l0aGluIGVhY2ggZ3JvdXAgcmF0aGVyIHRoYW4gdGhlIG92ZXJhbGwgbWF4aW11bS4KCk92ZXJhbGwsIGdyb3VwaW5nIGNoYW5nZXMgdGhlIGNvbnRleHQgb2Ygb3BlcmF0aW9ucyBzbyB0aGF0IHRoZXkgYXJlIGFwcGxpZWQgdG8gZWFjaCBzdWJncm91cCBpbmRlcGVuZGVudGx5IHJhdGhlciB0aGFuIHRoZSBkYXRhc2V0IGFzIGEgd2hvbGUuCgojIyMgMgoKQWZ0ZXIgZmlsdGVyaW5nIHRvIGluY2x1ZGUgb25seSBwbGFuZXMgd2l0aCBhdCBsZWFzdCAyMCBmbGlnaHRzLCB0aGUgcGxhbmUgd2l0aCB0aGUgd29yc3Qgb24tdGltZSByZWNvcmQgd2FzICoqTjIwM0ZSKiosIHdpdGggYW4gYXZlcmFnZSBhcnJpdmFsIGRlbGF5IG9mICoqNTkuMSBtaW51dGVzKiogYWNyb3NzICoqNDEgZmxpZ2h0cyoqLgoKVGhpcyBpcyBhIG1vcmUgcmVsaWFibGUgcmVzdWx0IHRoYW4gdGhlIGluaXRpYWwgcmFua2luZyBiZWNhdXNlIGl0IGV4Y2x1ZGVzIHBsYW5lcyB3aXRoIG9ubHkgb25lIG9yIHR3byBmbGlnaHRzLCB3aGljaCBjYW4gcHJvZHVjZSBtaXNsZWFkaW5nbHkgaGlnaCBhdmVyYWdlIGRlbGF5cy4gQnkgcmVzdHJpY3RpbmcgdGhlIGFuYWx5c2lzIHRvIHBsYW5lcyB3aXRoIG1vcmUgb2JzZXJ2YXRpb25zLCB0aGUgYXZlcmFnZSBkZWxheSBwcm92aWRlcyBhIG1vcmUgc3RhYmxlIGVzdGltYXRlIG9mIGEgcGxhbmXigJlzIHR5cGljYWwgcGVyZm9ybWFuY2UuCgpgYGB7ciB3b3JzdC1wbGFuZX0KZmxpZ2h0cyAlPiUKICBncm91cF9ieSh0YWlsbnVtKSAlPiUKICBzdW1tYXJpc2UoYXZnX2RlbGF5ID0gbWVhbihhcnJfZGVsYXksIG5hLnJtID0gVFJVRSksCiAgICAgICAgICAgIG4gPSBuKCkpICU+JQogIGFycmFuZ2UoZGVzYyhhdmdfZGVsYXkpKQoKZmxpZ2h0cyAlPiUKICBncm91cF9ieSh0YWlsbnVtKSAlPiUKICBzdW1tYXJpc2UoCiAgICBhdmdfZGVsYXkgPSBtZWFuKGFycl9kZWxheSwgbmEucm0gPSBUUlVFKSwKICAgIG4gPSBuKCkKICApICU+JQogIGZpbHRlcihuID49IDIwKSAlPiUKICBhcnJhbmdlKGRlc2MoYXZnX2RlbGF5KSkKYGBgCgojIyMgMwoKRmxpZ2h0cyBkZXBhcnRpbmcgZWFybGllciBpbiB0aGUgZGF5IHRlbmQgdG8gaGF2ZSB0aGUgbG93ZXN0IGF2ZXJhZ2UgZGVsYXlzLiBJbiB0aGlzIGRhdGFzZXQsIGZsaWdodHMgbGVhdmluZyBhdCAqKjUgQU0qKiBoYWQgdGhlIHNtYWxsZXN0IGF2ZXJhZ2UgZGVsYXksIGZvbGxvd2VkIGJ5IGRlcGFydHVyZXMgYXQgKio2IEFNKiogYW5kICoqNyBBTSoqLiBBdmVyYWdlIGRlbGF5cyBpbmNyZWFzZSBzdGVhZGlseSBsYXRlciBpbiB0aGUgZGF5LCB3aXRoIGV2ZW5pbmcgZmxpZ2h0cyBzaG93aW5nIHRoZSBsYXJnZXN0IGRlbGF5cy4gVGhpcyBzdWdnZXN0cyB0aGF0ICoqZWFybHkgbW9ybmluZyBpcyB0aGUgYmVzdCB0aW1lIHRvIGZseSoqIHRvIG1pbmltaXplIGRlbGF5cywgbGlrZWx5IGJlY2F1c2UgZGVsYXlzIGFjY3VtdWxhdGUgYXMgdGhlIGRheSBwcm9ncmVzc2VzLgoKYGBge3IgZGVsYXlzLWJ5LWhvdXJ9CmZsaWdodHMgJT4lCiAgZ3JvdXBfYnkoaG91cikgJT4lCiAgc3VtbWFyaXNlKGF2Z19kZWxheSA9IG1lYW4oZGVwX2RlbGF5LCBuYS5ybSA9IFRSVUUpKSAlPiUKICBhcnJhbmdlKGF2Z19kZWxheSkKCmZsaWdodHMgJT4lCiAgZ3JvdXBfYnkoaG91cikgJT4lCiAgc3VtbWFyaXNlKGF2Z19kZWxheSA9IG1lYW4oZGVwX2RlbGF5LCBuYS5ybSA9IFRSVUUpKSAlPiUKICBmaWx0ZXIoIWlzLm5hbihhdmdfZGVsYXkpKSAlPiUKICBhcnJhbmdlKGF2Z19kZWxheSkKYGBgCgojIyMgNAoKQnkgZ3JvdXBpbmcgZmxpZ2h0cyBieSBkZXN0aW5hdGlvbiBhbmQgY2FsY3VsYXRpbmcgdGhlIHRvdGFsIGFycml2YWwgZGVsYXkgd2l0aGluIGVhY2ggZ3JvdXAsIHRoaXMgYW5hbHlzaXMgc2hvd3MgaG93IG11Y2ggZWFjaCBmbGlnaHQgY29udHJpYnV0ZXMgdG8gdGhlIG92ZXJhbGwgZGVsYXkgZXhwZXJpZW5jZWQgYXQgaXRzIGRlc3RpbmF0aW9uLiBGbGlnaHRzIHdpdGggbGFyZ2VyIHBvc2l0aXZlIGBkZWxheV9wcm9wYCB2YWx1ZXMgYWNjb3VudCBmb3IgYSBncmVhdGVyIHNoYXJlIG9mIGRlbGF5cywgd2hpbGUgbmVnYXRpdmUgdmFsdWVzIHJlcHJlc2VudCBmbGlnaHRzIHRoYXQgYXJyaXZlZCBlYXJseS4KClRoaXMgYXBwcm9hY2ggaXMgdXNlZnVsIGZvciBpZGVudGlmeWluZyB3aGV0aGVyIGRlbGF5cyBhdCBhIGRlc3RpbmF0aW9uIGFyZSBjb25jZW50cmF0ZWQgaW4gYSBmZXcgdW51c3VhbGx5IGRlbGF5ZWQgZmxpZ2h0cyBvciBkaXN0cmlidXRlZCBtb3JlIGV2ZW5seSBhY3Jvc3MgbWFueSBmbGlnaHRzLiBJbiB0aGUgb3V0cHV0LCBkZXN0aW5hdGlvbnMgd2l0aCByZWxhdGl2ZWx5IHNtYWxsIHRvdGFsIGRlbGF5IGNhbiBzaG93IGxhcmdlciBwcm9wb3J0aW9uYWwgY29udHJpYnV0aW9ucyBmcm9tIGEgc2luZ2xlIGRlbGF5ZWQgZmxpZ2h0LCB3aGVyZWFzIGRlc3RpbmF0aW9ucyB3aXRoIHZlcnkgbGFyZ2UgdG90YWwgZGVsYXkgdGVuZCB0byBoYXZlIG11Y2ggc21hbGxlciBwcm9wb3J0aW9ucyBmb3IgaW5kaXZpZHVhbCBmbGlnaHRzLgoKYGBge3IgZGVsYXktYnktZGVzdGluYXRpb259CmZsaWdodHMgJT4lCiAgZ3JvdXBfYnkoZGVzdCkgJT4lCiAgbXV0YXRlKAogICAgdG90YWxfZGVsYXkgPSBzdW0oYXJyX2RlbGF5LCBuYS5ybSA9IFRSVUUpLAogICAgZGVsYXlfcHJvcCA9IGFycl9kZWxheSAvIHRvdGFsX2RlbGF5CiAgKSAlPiUKICBzZWxlY3QoZGVzdCwgYXJyX2RlbGF5LCB0b3RhbF9kZWxheSwgZGVsYXlfcHJvcCkKYGBgCgojIyMgNQoKVGhlIGNvcnJlbGF0aW9uIHJlc3VsdHMgc2hvdyBhIHBvc2l0aXZlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGEgZmxpZ2h04oCZcyBkZWxheSBhbmQgdGhlIGRlbGF5IG9mIHRoZSBpbW1lZGlhdGVseSBwcmVjZWRpbmcgZmxpZ2h0IGF0IGVhY2ggYWlycG9ydC4gVGhlIGNvcnJlbGF0aW9ucyB3ZXJlICoqMC4yNTQgZm9yIEVXUioqLCAqKjAuMjM4IGZvciBKRksqKiwgYW5kICoqMC4yODIgZm9yIExHQSoqLCBpbmRpY2F0aW5nIHRoYXQgZGVsYXlzIHRlbmQgdG8gY2FycnkgZm9yd2FyZCBvdmVyIHRpbWUuCgpBbHRob3VnaCB0aGUgY29ycmVsYXRpb25zIGFyZSBvbmx5IG1vZGVyYXRlLCB0aGV5IHByb3ZpZGUgZXZpZGVuY2UgdGhhdCBkZWxheXMgYXJlIG5vdCBjb21wbGV0ZWx5IGluZGVwZW5kZW50LiBJbnN0ZWFkLCBlYXJsaWVyIGRlbGF5cyBtYXkgY29udHJpYnV0ZSB0byBsYXRlciBkZWxheXMsIGxpa2VseSBiZWNhdXNlIG9wZXJhdGlvbmFsIGRpc3J1cHRpb25zIGNhbiBhZmZlY3QgbXVsdGlwbGUgZmxpZ2h0cyBpbiBzZXF1ZW5jZS4KCmBgYHtyIGxhZy1kZWxheX0KZmxpZ2h0cyAlPiUKICBhcnJhbmdlKG9yaWdpbiwgdGltZV9ob3VyKSAlPiUKICBncm91cF9ieShvcmlnaW4pICU+JQogIG11dGF0ZShwcmV2X2RlbGF5ID0gbGFnKGRlcF9kZWxheSkpICU+JQogIHNlbGVjdChvcmlnaW4sIHRpbWVfaG91ciwgZGVwX2RlbGF5LCBwcmV2X2RlbGF5KSAlPiUKICBwcmludChuID0gMjApCgpmbGlnaHRzICU+JQogIGFycmFuZ2Uob3JpZ2luLCB5ZWFyLCBtb250aCwgZGF5LCBzY2hlZF9kZXBfdGltZSkgJT4lCiAgZ3JvdXBfYnkob3JpZ2luKSAlPiUKICBtdXRhdGUocHJldl9kZWxheSA9IGxhZyhkZXBfZGVsYXkpKSAlPiUKICBzZWxlY3Qob3JpZ2luLCB5ZWFyLCBtb250aCwgZGF5LCBzY2hlZF9kZXBfdGltZSwgZGVwX2RlbGF5LCBwcmV2X2RlbGF5KQoKZmxpZ2h0cyAlPiUKICBhcnJhbmdlKG9yaWdpbiwgeWVhciwgbW9udGgsIGRheSwgc2NoZWRfZGVwX3RpbWUpICU+JQogIGdyb3VwX2J5KG9yaWdpbikgJT4lCiAgbXV0YXRlKHByZXZfZGVsYXkgPSBsYWcoZGVwX2RlbGF5KSkgJT4lCiAgc3VtbWFyaXNlKGNvcnJlbGF0aW9uID0gY29yKGRlcF9kZWxheSwgcHJldl9kZWxheSwgdXNlID0gImNvbXBsZXRlLm9icyIpKQpgYGAKCiMjIyA2CgpCeSBjb21wYXJpbmcgZWFjaCBmbGlnaHTigJlzIGFpciB0aW1lIHRvIHRoZSBtaW5pbXVtIG9ic2VydmVkIGFpciB0aW1lIGZvciB0aGUgc2FtZSBkZXN0aW5hdGlvbiwgdGhpcyBhbmFseXNpcyBjcmVhdGVzIGEgcmVsYXRpdmUgbWVhc3VyZSBvZiBmbGlnaHQgZHVyYXRpb24uIEEgYHRpbWVfcmF0aW9gIG9mIDEgaW5kaWNhdGVzIHRoYXQgYSBmbGlnaHQgbWF0Y2hlZCB0aGUgc2hvcnRlc3Qgb2JzZXJ2ZWQgdGltZSBmb3IgdGhhdCByb3V0ZSwgd2hpbGUgbGFyZ2VyIHZhbHVlcyBpbmRpY2F0ZSBsb25nZXIgZmxpZ2h0cyByZWxhdGl2ZSB0byB0aGUgcm91dGUgbWluaW11bS4KClRoZSBjdXJyZW50IG91dHB1dCBpcyBkb21pbmF0ZWQgYnkgZmxpZ2h0cyB3aXRoIGEgcmF0aW8gb2YgMSBiZWNhdXNlIHRoZSByZXN1bHRzIHdlcmUgc29ydGVkIGluIGFzY2VuZGluZyBvcmRlci4gVGhpcyBoaWdobGlnaHRzIHRoZSBmYXN0ZXN0IGZsaWdodHMgZm9yIGVhY2ggZGVzdGluYXRpb24uIFRvIGlkZW50aWZ5IGZsaWdodHMgdGhhdCB3ZXJlIHVudXN1YWxseSBzbG93IHJlbGF0aXZlIHRvIHRoZSBtaW5pbXVtLCBpdCB3b3VsZCBiZSBtb3JlIGluZm9ybWF0aXZlIHRvIHNvcnQgdGhlIG91dHB1dCBpbiBkZXNjZW5kaW5nIG9yZGVyIG9mIGB0aW1lX3JhdGlvYC4KCmBgYHtyIHN1c3BpY2lvdXNseS1mYXN0LWZsaWdodHN9CmZsaWdodHMgJT4lCiAgZmlsdGVyKCFpcy5uYShhaXJfdGltZSkpICU+JQogIGdyb3VwX2J5KGRlc3QpICU+JQogIG11dGF0ZSgKICAgIG1pbl9haXJfdGltZSA9IG1pbihhaXJfdGltZSwgbmEucm0gPSBUUlVFKSwKICAgIHRpbWVfcmF0aW8gPSBhaXJfdGltZSAvIG1pbl9haXJfdGltZQogICkgJT4lCiAgYXJyYW5nZSh0aW1lX3JhdGlvKSAlPiUKICBzZWxlY3QoZGVzdCwgYWlyX3RpbWUsIG1pbl9haXJfdGltZSwgdGltZV9yYXRpbykgJT4lCiAgcHJpbnQobiA9IDIwKQpgYGAKCiMjIyA3CgpUb3Agc2hhcmVkIGRlc3RpbmF0aW9uczogQVRMLCBCT1MsIENMVCwgT1JELCBUUEEgLS0+IDcgY2FycmllcnMKCkhpZ2hlc3QgYXZlcmFnZSBkZWxheXM6IEY5ICgyMS45KSwgRkwgKDIwLjMpLCBFViAoMTUuNyksIFlWICgxNS42KQpMb3dlc3QgYXZlcmFnZSBkZWxheXM6IEhBICgtNi45MiksICgtOS45MykKCkFmdGVyIHJlc3RyaWN0aW5nIHRoZSBhbmFseXNpcyB0byBkZXN0aW5hdGlvbnMgc2VydmVkIGJ5IGF0IGxlYXN0IHR3byBjYXJyaWVycywgdGhlIHJhbmtpbmcgb2YgYWlybGluZXMgYmVjb21lcyBtb3JlIGNvbXBhcmFibGUgYmVjYXVzZSB0aGUgY2FycmllcnMgYXJlIGJlaW5nIGV2YWx1YXRlZCBvbiBvdmVybGFwcGluZyByb3V0ZXMgcmF0aGVyIHRoYW4gY29tcGxldGVseSBkaWZmZXJlbnQgZGVzdGluYXRpb24gbWl4ZXMuCgpUaGUgcmVzdWx0cyBzaG93IHRoYXQgKipGOSoqIGFuZCAqKkZMKiogaGF2ZSB0aGUgaGlnaGVzdCBhdmVyYWdlIGFycml2YWwgZGVsYXlzLCBhdCBhcHByb3hpbWF0ZWx5ICoqMjEuOSBtaW51dGVzKiogYW5kICoqMjAuMyBtaW51dGVzKiosIHJlc3BlY3RpdmVseS4gSW4gY29udHJhc3QsICoqQVMqKiBhbmQgKipIQSoqIGhhdmUgbmVnYXRpdmUgYXZlcmFnZSBkZWxheXMsIGluZGljYXRpbmcgdGhhdCB0aGV5IHRlbmQgdG8gYXJyaXZlIGVhcmx5IG9uIGF2ZXJhZ2UuCgpUaGlzIGNvbXBhcmlzb24gaXMgbW9yZSBmYWlyIHRoYW4gcmFua2luZyBhaXJsaW5lcyBhY3Jvc3MgYWxsIGRlc3RpbmF0aW9ucyBiZWNhdXNlIGl0IHJlZHVjZXMgdGhlIGluZmx1ZW5jZSBvZiByb3V0ZS1zcGVjaWZpYyBmYWN0b3JzIHN1Y2ggYXMgZGlzdGFuY2UsIHdlYXRoZXIsIGFuZCBhaXJwb3J0IGNvbmdlc3Rpb24uIEFsdGhvdWdoIGRpZmZlcmVuY2VzIGluIHBlcmZvcm1hbmNlIHN0aWxsIHJlbWFpbiwgdGhlIHJlc3VsdHMgYXJlIG1vcmUgaW50ZXJwcmV0YWJsZSB3aGVuIGFpcmxpbmVzIGFyZSBjb21wYXJlZCBvbmx5IG9uIGRlc3RpbmF0aW9ucyB0aGV5IGhhdmUgaW4gY29tbW9uLgoKYGBge3IgbXVsdGktY2Fycmllci1kZXN0aW5hdGlvbnN9CmZsaWdodHMgJT4lCiAgZGlzdGluY3QoZGVzdCwgY2FycmllcikgJT4lCiAgZ3JvdXBfYnkoZGVzdCkgJT4lCiAgc3VtbWFyaXNlKG5fY2FycmllcnMgPSBuKCkpICU+JQogIGZpbHRlcihuX2NhcnJpZXJzID49IDIpICU+JQogIGFycmFuZ2UoZGVzYyhuX2NhcnJpZXJzKSkKCnNoYXJlZF9kZXN0cyA8LSBmbGlnaHRzICU+JQogIGRpc3RpbmN0KGRlc3QsIGNhcnJpZXIpICU+JQogIGdyb3VwX2J5KGRlc3QpICU+JQogIHN1bW1hcmlzZShuX2NhcnJpZXJzID0gbigpKSAlPiUKICBmaWx0ZXIobl9jYXJyaWVycyA+PSAyKQoKZmxpZ2h0cyAlPiUKICBzZW1pX2pvaW4oc2hhcmVkX2Rlc3RzLCBieSA9ICJkZXN0IikgJT4lCiAgZ3JvdXBfYnkoY2FycmllcikgJT4lCiAgc3VtbWFyaXNlKGF2Z19kZWxheSA9IG1lYW4oYXJyX2RlbGF5LCBuYS5ybSA9IFRSVUUpKSAlPiUKICBhcnJhbmdlKGRlc2MoYXZnX2RlbGF5KSkKYGBgCgojIyMgOAoKVGhpcyBhbmFseXNpcyBjb3VudHMgaG93IG1hbnkgZmxpZ2h0cyBlYWNoIHBsYW5lIGNvbXBsZXRlZCBiZWZvcmUgZXhwZXJpZW5jaW5nIGl0cyBmaXJzdCBkZXBhcnR1cmUgZGVsYXkgZ3JlYXRlciB0aGFuIDYwIG1pbnV0ZXMuIEJ5IGFycmFuZ2luZyBmbGlnaHRzIGNocm9ub2xvZ2ljYWxseSB3aXRoaW4gZWFjaCB0YWlsIG51bWJlciBhbmQgdHJhY2tpbmcgd2hlbiB0aGUgZmlyc3QgbWFqb3IgZGVsYXkgb2NjdXJyZWQsIGl0IGlzIHBvc3NpYmxlIHRvIG1lYXN1cmUgaG93IGxvbmcgZWFjaCBwbGFuZSBvcGVyYXRlZCBiZWZvcmUgYSBzdWJzdGFudGlhbCBkZWxheSBhcHBlYXJlZC4KClRoZSByZXN1bHRzIHNob3cgdGhhdCAqKnRhaWwgbnVtYmVyIE45NTRVVyoqIGNvbXBsZXRlZCB0aGUgbW9zdCBmbGlnaHRzIGJlZm9yZSBpdHMgZmlyc3QgbWFqb3IgZGVsYXksIHdpdGggKioyMDYgZmxpZ2h0cyoqLiBPdGhlciBwbGFuZXMgd2l0aCBsb25nIHJ1bnMgYmVmb3JlIGEgbWFqb3IgZGVsYXkgaW5jbHVkZWQgKipOOTUyVVcqKiB3aXRoICoqMTYzIGZsaWdodHMqKiBhbmQgKipOOTU3VVcqKiB3aXRoICoqMTQyIGZsaWdodHMqKi4KClBsYW5lcyB3aXRoIGhpZ2hlciB2YWx1ZXMgbWF5IHJlZmxlY3QgbW9yZSBzdGFibGUgb3BlcmF0aW9ucyBvciBtb3JlIGZhdm9yYWJsZSBzY2hlZHVsaW5nIGNvbmRpdGlvbnMuIEhvd2V2ZXIsIHRoZSByZXN1bHRzIHNob3VsZCBiZSBpbnRlcnByZXRlZCB3aXRoIGNhdXRpb24sIGJlY2F1c2Ugc29tZSBwbGFuZXMgbWF5IGFwcGVhciB0byBwZXJmb3JtIHdlbGwgc2ltcGx5IGJlY2F1c2UgdGhleSBkaWQgbm90IGV4cGVyaWVuY2UgYSBkZWxheSBncmVhdGVyIHRoYW4gNjAgbWludXRlcyBkdXJpbmcgdGhlIHRpbWUgcGVyaW9kIGNvdmVyZWQgYnkgdGhlIGRhdGFzZXQuCgpOOTU0VVcgaGFkIHRoZSBoaWdoZXN0IG51bWJlciBvZiBmbGlnaHRzIGJlZm9yZSBpdHMgZmlyc3QgbWFqb3IgZGVwYXJ0dXJlIGRlbGF5LCB3aXRoIDIwNiBmbGlnaHRzLgoKYGBge3IgZmxpZ2h0cy1iZWZvcmUtbWFqb3ItZGVsYXl9CmZsaWdodHMgJT4lCiAgZmlsdGVyKCFpcy5uYSh0YWlsbnVtKSkgJT4lCiAgYXJyYW5nZSh0YWlsbnVtLCB5ZWFyLCBtb250aCwgZGF5LCBzY2hlZF9kZXBfdGltZSkgJT4lCiAgZ3JvdXBfYnkodGFpbG51bSkgJT4lCiAgbXV0YXRlKAogICAgYmlnX2RlbGF5ID0gaWZfZWxzZSghaXMubmEoZGVwX2RlbGF5KSAmIGRlcF9kZWxheSA+IDYwLCBUUlVFLCBGQUxTRSksCiAgICBkZWxheV9zZWVuID0gY3Vtc3VtKGJpZ19kZWxheSkKICApICU+JQogIGZpbHRlcihkZWxheV9zZWVuID09IDApICU+JQogIHN1bW1hcmlzZShmbGlnaHRzX2JlZm9yZV9kZWxheSA9IG4oKSkgJT4lCiAgYXJyYW5nZShkZXNjKGZsaWdodHNfYmVmb3JlX2RlbGF5KSkKYGBgCgouLi4KCg==