library(tidyverse)
library(openintro)
data(nycflights)

Exercise 1

The three histograms display the same distribution of departure delays but with different levels of detail due to the choice of binwidth. All three plots show a strongly right-skewed distribution, with most flights having delays near zero and a long tail of larger delays. The histogram with the smaller binwidth reveals more detailed structure, including a sharp spike around 0 minutes and more variation across delay values, but it appears noisier. The default histogram provides a balanced view, showing the overall pattern without excessive noise. The histogram with the largest binwidth smooths the distribution significantly, clearly highlighting the overall trend but obscuring important details such as smaller clusters and variability. Overall, smaller binwidths reveal fine details, while larger binwidths emphasize the general shape but may hide meaningful patterns.

ggplot(data = nycflights, aes(x = dep_delay)) +
  geom_histogram()
## `stat_bin()` using `bins = 30`. Pick better value `binwidth`.

ggplot(data = nycflights, aes(x = dep_delay)) +
  geom_histogram(binwidth = 15)

ggplot(data = nycflights, aes(x = dep_delay)) +
  geom_histogram(binwidth = 150)

Exercise 2

A new data frame was created using filter() to include only flights with destination SFO in February. The number of flights that met this criteria is 68.

sfo_feb_flights <- nycflights %>%
  filter(dest == "SFO", month == 2)

nrow(sfo_feb_flights)
## [1] 68

Exercise 3

The histogram of arrival delays for flights to SFO in February shows a right-skewed distribution. Most flights are concentrated around values near zero, with many flights arriving early (negative delays), and a long right tail representing a small number of flights with large delays. Because the distribution is skewed and includes extreme values, the median and interquartile range (IQR) are more appropriate summary statistics than the mean and standard deviation. The median arrival delay is -11 minutes, indicating that a typical flight arrives slightly early. The IQR is 23.2 minutes, showing that the middle 50% of arrival delays fall within a range of about 23 minutes. Overall, most flights arrive close to or earlier than scheduled, but a small number of flights experience large delays, creating the long right tail of the distribution.

ggplot(sfo_feb_flights, aes(x = arr_delay)) +
  geom_histogram(binwidth = 15)

sfo_feb_flights %>%
  summarize(median_delay = median(arr_delay, na.rm = TRUE),
    IQR_delay = IQR(arr_delay, na.rm = TRUE))
## # A tibble: 1 × 2
##   median_delay IQR_delay
##          <dbl>     <dbl>
## 1          -11      23.2
sfo_feb_flights |>
  group_by(origin) |>
  summarise(median_dd = median(dep_delay), iqr_dd = IQR(dep_delay), n_flights = n())
## # A tibble: 2 × 4
##   origin median_dd iqr_dd n_flights
##   <chr>      <dbl>  <dbl>     <int>
## 1 EWR          0.5   5.75         8
## 2 JFK         -2.5  15.2         60

Exercise 4

Arrival delays (arr_delay) were summarized by carrier using the median and interquartile range (IQR). Since arrival delays are right-skewed with outliers, the median and IQR provide resistant measures of center and spread. Based on the results, DL and UA have the most variable arrival delays, each with an IQR of 22 minutes, meaning the middle 50% of their arrival delays span a wider range than the other carriers. DL and UA also have negative medians (DL = -15, UA = -10), meaning their typical flight arrived early, but variability across flights was still the greatest.

sfo_feb_flights %>%
  group_by(carrier) %>%
  summarize(median_delay = median(arr_delay, na.rm = TRUE),
    IQR_delay = IQR(arr_delay, na.rm = TRUE))
## # A tibble: 5 × 3
##   carrier median_delay IQR_delay
##   <chr>          <dbl>     <dbl>
## 1 AA               5        17.5
## 2 B6             -10.5      12.2
## 3 DL             -15        22  
## 4 UA             -10        22  
## 5 VX             -22.5      21.2
sfo_feb_flights %>%
  group_by(carrier) %>%
  summarize(
    median_delay = median(arr_delay, na.rm = TRUE),
    IQR_delay = IQR(arr_delay, na.rm = TRUE)
  ) %>%
  arrange(desc(IQR_delay))
## # A tibble: 5 × 3
##   carrier median_delay IQR_delay
##   <chr>          <dbl>     <dbl>
## 1 DL             -15        22  
## 2 UA             -10        22  
## 3 VX             -22.5      21.2
## 4 AA               5        17.5
## 5 B6             -10.5      12.2

Exercise 5

Choosing the month with the lowest mean departure delay minimizes the overall expected delay. This approach takes into account all flights, including those with extreme delays, and is useful if a traveler wants to reduce the average delay they might experience. However, the mean is sensitive to outliers, so a few unusually large delays (such as those caused by severe weather or congestion) can inflate the mean and make a month appear worse than the typical experience. Choosing the month with the lowest median departure delay focuses on the typical flight experience, since the median is resistant to extreme values. This is especially useful for skewed data, such as departure delays, which often have a long right tail. However, the median does not capture the risk of rare but severe delays and may underestimate the likelihood of experiencing a very long delay. In this dataset, October (month 10) has both the lowest mean delay (5.88 minutes) and a negative median delay (-3 minutes), indicating that flights typically depart early and delays are relatively small and consistent. In contrast, July (month 7) has the highest mean delay (20.8 minutes) and a median delay of 0 minutes, along with a much larger IQR (26 minutes). This suggests that while a typical flight in July may be on time, departure delays are much more variable and there is a greater risk of experiencing large delays. Overall, October is the best choice under both criteria, while July represents a less desirable option due to its higher average delays and greater variability. This comparison highlights how seasonal factors, such as summer travel volume, can increase both the frequency and variability of delays.

nycflights |>
  group_by(month) |>
  summarise(mean_dd = mean(dep_delay)) |>
  arrange(desc(mean_dd))
## # A tibble: 12 × 2
##    month mean_dd
##    <int>   <dbl>
##  1     7   20.8 
##  2     6   20.4 
##  3    12   17.4 
##  4     4   14.6 
##  5     3   13.5 
##  6     5   13.3 
##  7     8   12.6 
##  8     2   10.7 
##  9     1   10.2 
## 10     9    6.87
## 11    11    6.10
## 12    10    5.88
nycflights %>%
     group_by(month) %>%
     summarize(mean_dd = mean(dep_delay, na.rm = TRUE)) %>%
     arrange(mean_dd)
## # A tibble: 12 × 2
##    month mean_dd
##    <int>   <dbl>
##  1    10    5.88
##  2    11    6.10
##  3     9    6.87
##  4     1   10.2 
##  5     2   10.7 
##  6     8   12.6 
##  7     5   13.3 
##  8     3   13.5 
##  9     4   14.6 
## 10    12   17.4 
## 11     6   20.4 
## 12     7   20.8
nycflights %>%
     group_by(month) %>%
     summarize(
         mean_dd   = mean(dep_delay, na.rm = TRUE),
         median_dd = median(dep_delay, na.rm = TRUE),
         IQR_dd    = IQR(dep_delay, na.rm = TRUE),
         n         = sum(!is.na(dep_delay))) %>%
     arrange(mean_dd)
## # A tibble: 12 × 5
##    month mean_dd median_dd IQR_dd     n
##    <int>   <dbl>     <dbl>  <dbl> <int>
##  1    10    5.88        -3      9  2884
##  2    11    6.10        -2     10  2733
##  3     9    6.87        -3      8  2681
##  4     1   10.2         -2     12  2610
##  5     2   10.7         -2     15  2286
##  6     8   12.6         -1     15  2880
##  7     5   13.3         -1     19  2821
##  8     3   13.5         -1     17  2869
##  9     4   14.6         -2     16  2781
## 10    12   17.4          1     25  2716
## 11     6   20.4          0     25  2732
## 12     7   20.8          0     26  2742

Exercise 6

To determine which NYC airport has the highest on-time departure percentage, flights were classified as “on time” if the departure delay was less than 5 minutes. A stacked bar chart was also created to visualize the proportion of on-time and delayed flights by airport. The results show that LaGuardia Airport (LGA) has the highest on-time departure rate at 72.8%, followed by JFK (69.4%) and EWR (63.7%). The visualization supports this finding, as LGA has the largest proportion of on-time flights (teal) and the smallest proportion of delayed flights (red), while EWR shows the opposite pattern. Therefore, if selecting an airport based solely on on-time departure performance, LGA would be the best choice. The consistency between the numerical summary and the visual representation strengthens the conclusion that LGA has the best on-time performance.

nycflights <- nycflights |>
  mutate(dep_type = ifelse(dep_delay < 5, "on time", "delayed"))

nycflights |>
  group_by(origin) |>
  summarise(ot_dep_rate = sum(dep_type == "on time") / n()) |>
  arrange(desc(ot_dep_rate))
## # A tibble: 3 × 2
##   origin ot_dep_rate
##   <chr>        <dbl>
## 1 LGA          0.728
## 2 JFK          0.694
## 3 EWR          0.637
ggplot(data = nycflights, aes(x = origin, fill = dep_type)) +
  geom_bar()

Exercise 7

A new variable, avg_speed, was created by dividing distance (miles) by flight time in hours, converting air_time from minutes to hours.

nycflights <- nycflights %>%
  mutate(avg_speed = distance / (air_time / 60))

summary(nycflights$avg_speed)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##    76.8   357.4   404.0   394.1   438.8   703.4

Exercise 8

The scatterplot shows a positive relationship between distance and average speed. Flights covering longer distances tend to have higher average speeds. This pattern likely occurs because longer flights spend more time at cruising altitude, where planes travel more efficiently and at higher speeds. In contrast, shorter flights spend more time taking off and landing, which reduces their average speed.

ggplot(nycflights, aes(x = distance, y = avg_speed)) +
  geom_point(alpha = 0.3)

ggplot(nycflights, aes(x = distance, y = avg_speed)) +
  geom_point(alpha = 0.3) +
  geom_smooth()
## `geom_smooth()` using method = 'gam' and formula = 'y ~ s(x, bs = "cs")'

Exercise 9

The scatterplot of departure delay versus arrival delay for American (AA), Delta (DL), and United (UA) shows a strong positive relationship: flights that depart later tend to arrive later. However, there are many observations where flights with small departure delays still arrive on time or early (negative arrival delays). This suggests that airlines are often able to make up some lost time during the flight. Based on the plot, the approximate cutoff point appears to be around 30–60 minutes of departure delay. Flights delayed less than this range often still arrive on time, while flights with delays greater than this are much more likely to arrive late. Overall, this indicates that moderate departure delays can sometimes be recovered, but larger delays typically result in late arrivals.

selected_flights <- nycflights %>%
  filter(carrier %in% c("AA", "DL", "UA"))


ggplot(selected_flights, aes(x = dep_delay, y = arr_delay, color = carrier)) +
  geom_point(alpha = 0.5)

Exercises 3.5.1

  1. Faceting a continuous variable creates a panel for each unique value, which can result in a very large number of small plots. This is often not useful becasue the panels become too numerous, each panel may contain very few observations, and the plot becomes difficult to interpret. In practice, continuous variables should be binned or categorized before faceting.

  2. Empty cells represent combinations of variables that do not exist in the dataset. For example, if no cars have a certain combination of drive type and number of cylinders, ggplot still creates the panel, but it appears empty becasue no observations fall into that category. These empty cells highlight missing combination in the data, not errors.

3.First plot: Creates one column of plots. Each row = a different value of drive type. You get stacked panels vertically. Second plot: Creates one row of plots. Each column = a different value of number of cylinders. you get panels arranged horizontally. . means no “faceting in that direction”. In drz~. –> no columns, only rows; In .~cyl –> no rows, only columns

  1. Advantages of faceting: Separates groups into clear, individual panels. Makes patterns easier to compare without overlap. Reduces clutter in dense plots. Disadvantages of faceting: Takes up more space. Harder to compare values across panels directly. Can become overwhelming with many categories. Advantages of using color: all data shown in one plot. Easier direct comparison across groups. More compact. Disadvantages of color: Overplotting (points overlap). Hard to distinguish groups if many categories. Can be visually cluttered. With larger data sets, color can become cluttered, and faceting becomes more useful for clarity.

  2. In facet_wrap(), the arguments nrow and ncol control the layout of the panels. The nrow argument specifies the number of rows, while ncol specifies the number of columns used to arrange the panels. In contrast, facet_grid() does not include nrow and ncol arguments because its layout is determined entirely by the variables used for faceting. The number of rows and columns is fixed based on the number of levels in each variable, so the user does not manually control the layout.

  3. You should put the variable with more unique levels in the columns because screens are typically wider than they are tall. Putting more levels in columns uses horizontal space efficiently, prevents plots from becoming too tall and compressed, and makes the layout easier to read.

facet_grid(drv ~ cyl)
## <ggproto object: Class FacetGrid, Facet, gg>
##     attach_axes: function
##     attach_strips: function
##     compute_layout: function
##     draw_back: function
##     draw_front: function
##     draw_labels: function
##     draw_panel_content: function
##     draw_panels: function
##     finish_data: function
##     format_strip_labels: function
##     init_gtable: function
##     init_scales: function
##     map_data: function
##     params: list
##     set_panel_size: function
##     setup_data: function
##     setup_panel_params: function
##     setup_params: function
##     shrink: TRUE
##     train_scales: function
##     vars: function
##     super:  <ggproto object: Class FacetGrid, Facet, gg>
ggplot(data = mpg) + 
  geom_point(mapping = aes(x = drv, y = cyl))

ggplot(data = mpg) + 
  geom_point(mapping = aes(x = displ, y = hwy)) +
  facet_grid(drv ~ .)

ggplot(data = mpg) + 
  geom_point(mapping = aes(x = displ, y = hwy)) +
  facet_grid(. ~ cyl)

ggplot(data = mpg) + 
  geom_point(mapping = aes(x = displ, y = hwy)) + 
  facet_wrap(~ class, nrow = 2)

Exercises 3.7.1

  1. The default geom for stat_summary() is geom_pointrange(). To rewrite a plot using the geom instead of the stat, you specify stat = “summary” inside the geom:
    geom_pointrange(stat = “summary”, fun.data = “mean_cl_normal”)

  2. geom_col() creates bar plots using values that are already present in the dataset, meaning the heights of the bars are taken directly from a y variable. In contrast, geom_bar() calculates counts automatically (using stat = “count” by default) and does not require a y variable. Therefore, geom_col() is used when the data has already been summarized, while geom_bar() is used for raw data.

  3. Most geoms and stats come in pairs, such as geom_bar() with stat_count(), geom_histogram() with stat_bin(), and geom_smooth() with stat_smooth(). These pairs work together such that the stat computes a transformation of the data, and the geom controls how the result is displayed. They share the same underlying structure and can often be interchanged by specifying the stat or geom argument explicitly.

  4. stat_smooth() computes a smoothed trend line through the data and often includes a confidence interval around the estimate. Its behavior is controlled by parameters such as method (e.g., “lm” or “loess”), se (whether to display the confidence interval), and other arguments like span for controlling smoothness.

  5. The issue is that ggplot2 automatically groups data based on mapped aesthetics such as fill. As a result, proportions are calculated within each group instead of across the entire dataset. It creates gray, solid filled bars. By setting group = 1, we override this default grouping and ensure that the proportions are calculated relative to all observations. Without this specification, the graphs display incorrect proportions because each category is normalized separately rather than globally.

ggplot(data = diamonds) + 
  geom_bar(mapping = aes(x = cut, y = after_stat(prop)))

ggplot(data = diamonds) + 
  geom_bar(mapping = aes(x = cut, fill = color, y = after_stat(prop)))

Exercises 3.8.1

  1. The main problem with this plot is overplotting, since many observations share the same values of cty and hwy, causing points to overlap and obscure the true number of observations. This makes it difficult to assess the density of the data. The plot can be improved by using jittering (e.g., geom_jitter()), adding transparency, or using geom_count() to better display the frequency of overlapping points.

  2. The amount of jittering is controlled by the width and height parameters in geom_jitter(). The width argument determines the amount of horizontal movement, while the height argument controls vertical movement of points.

  3. geom_jitter() reduces overplotting by adding small random variation to the position of points, making overlapping observations visible. In contrast, geom_count() represents overlapping observations by increasing the size of the points based on their frequency. While jittering spreads the data visually, geom_count() preserves the exact values but encodes frequency through point size.

  4. The default position adjustment for geom_boxplot() is position = “dodge2”, which places boxplots side-by-side when there are multiple groups. This allows for easier comparison between categories.

ggplot(data = mpg, mapping = aes(x = cty, y = hwy)) + 
  geom_point()

Exercises 3.9.1

  1. A stacked bar chart can be converted into a pie chart by using coord_polar(theta = “y”), which transforms the y-values into angular space and wraps the bar chart into a circle.

  2. The labs() function is used to add and modify labels in a ggplot, including the title, subtitle, axis labels, legend labels, and caption. It is preferred over older functions such as xlab() and ggtitle(), which are now superseded. By improving labeling, labs() makes plots more interpretable and accessible to a broader audience.

  3. coord_map() applies a true map projection and preserves geographic accuracy, but it is computationally slower. In contrast, coord_quickmap() provides a faster approximation of a map projection and works well for smaller geographic regions where distortion is minimal.

  4. The plot shows a strong positive relationship between city (cty) and highway (hwy) mileage: vehicles with higher city MPG also tend to have higher highway MPG. Most points lie above the reference line, indicating that highway MPG is generally higher than city MPG. The function coord_fixed() is important because it ensures equal scaling on both axes, making the reference line meaningful and allowing accurate visual comparison between the two variables. The function geom_abline() adds a diagonal reference line (with slope = 1 and intercept = 0), representing where city MPG equals highway MPG. This helps highlight the difference between the two measures and makes it clear that most vehicles perform better on the highway than in the city.

ggplot(diamonds, aes(x = "", fill = cut)) +
  geom_bar(width = 1) +
  coord_polar(theta = "y")

ggplot(data = mpg, mapping = aes(x = cty, y = hwy)) +
  geom_point() + 
  geom_abline() +
  coord_fixed()

Exercises 4.4

  1. This code does not work because the assignment operator is not written correctly. In R, the assignment must use the exact operator <-. If an incorrect dash or formatting is used, R does not recognize the assignment, and the variable is not created, resulting in the error.

  2. The corrected commands are:

library(tidyverse)

ggplot(data = mpg) + geom_point(mapping = aes(x = displ, y = hwy))

filter(mpg, cyl == 8)

filter(diamonds, carat > 3)

The errors included a misspelled argument name (dota instead of data), using = instead of == for comparison, and reference the dataset diamond instead of diamonds.

  1. Pressing Alt + Shift + K in RStudio opens the keyboard shortcuts help menu. This menu provides a list of useful shortcuts to improve efficiency when coding. The same menu can be accessed by navigating to Help → Keyboard Shortcuts Help in the RStudio toolbar.
library(tidyverse)

ggplot(data = mpg) +
  geom_point(mapping = aes(x = displ, y = hwy))

filter(mpg, cyl == 8)
## # A tibble: 70 × 11
##    manufacturer model      displ  year   cyl trans drv     cty   hwy fl    class
##    <chr>        <chr>      <dbl> <int> <int> <chr> <chr> <int> <int> <chr> <chr>
##  1 audi         a6 quattro   4.2  2008     8 auto… 4        16    23 p     mids…
##  2 chevrolet    c1500 sub…   5.3  2008     8 auto… r        14    20 r     suv  
##  3 chevrolet    c1500 sub…   5.3  2008     8 auto… r        11    15 e     suv  
##  4 chevrolet    c1500 sub…   5.3  2008     8 auto… r        14    20 r     suv  
##  5 chevrolet    c1500 sub…   5.7  1999     8 auto… r        13    17 r     suv  
##  6 chevrolet    c1500 sub…   6    2008     8 auto… r        12    17 r     suv  
##  7 chevrolet    corvette     5.7  1999     8 manu… r        16    26 p     2sea…
##  8 chevrolet    corvette     5.7  1999     8 auto… r        15    23 p     2sea…
##  9 chevrolet    corvette     6.2  2008     8 manu… r        16    26 p     2sea…
## 10 chevrolet    corvette     6.2  2008     8 auto… r        15    25 p     2sea…
## # ℹ 60 more rows
filter(diamonds, carat > 3)
## # A tibble: 32 × 10
##    carat cut     color clarity depth table price     x     y     z
##    <dbl> <ord>   <ord> <ord>   <dbl> <dbl> <int> <dbl> <dbl> <dbl>
##  1  3.01 Premium I     I1       62.7    58  8040  9.1   8.97  5.67
##  2  3.11 Fair    J     I1       65.9    57  9823  9.15  9.02  5.98
##  3  3.01 Premium F     I1       62.2    56  9925  9.24  9.13  5.73
##  4  3.05 Premium E     I1       60.9    58 10453  9.26  9.25  5.66
##  5  3.02 Fair    I     I1       65.2    56 10577  9.11  9.02  5.91
##  6  3.01 Fair    H     I1       56.1    62 10761  9.54  9.38  5.31
##  7  3.65 Fair    H     I1       67.1    53 11668  9.53  9.48  6.38
##  8  3.24 Premium H     I1       62.1    58 12300  9.44  9.4   5.85
##  9  3.22 Ideal   I     I1       62.6    55 12545  9.49  9.42  5.92
## 10  3.5  Ideal   H     I1       62.8    57 12587  9.65  9.59  6.03
## # ℹ 22 more rows
LS0tCnRpdGxlOiAiTGFiIDI6IEludHJvIHRvIERhdGEiCmF1dGhvcjogIkNhaXRsaW4gS2VubmVkeSIKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6IG9wZW5pbnRybzo6bGFiX3JlcG9ydAotLS0KCmBgYHtyIGxvYWQtcGFja2FnZXMsIG1lc3NhZ2U9RkFMU0V9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KG9wZW5pbnRybykKZGF0YShueWNmbGlnaHRzKQpgYGAKCiMjIyBFeGVyY2lzZSAxCgpUaGUgdGhyZWUgaGlzdG9ncmFtcyBkaXNwbGF5IHRoZSBzYW1lIGRpc3RyaWJ1dGlvbiBvZiBkZXBhcnR1cmUgZGVsYXlzIGJ1dCB3aXRoIGRpZmZlcmVudCBsZXZlbHMgb2YgZGV0YWlsIGR1ZSB0byB0aGUgY2hvaWNlIG9mIGJpbndpZHRoLiBBbGwgdGhyZWUgcGxvdHMgc2hvdyBhIHN0cm9uZ2x5IHJpZ2h0LXNrZXdlZCBkaXN0cmlidXRpb24sIHdpdGggbW9zdCBmbGlnaHRzIGhhdmluZyBkZWxheXMgbmVhciB6ZXJvIGFuZCBhIGxvbmcgdGFpbCBvZiBsYXJnZXIgZGVsYXlzLgpUaGUgaGlzdG9ncmFtIHdpdGggdGhlIHNtYWxsZXIgYmlud2lkdGggcmV2ZWFscyBtb3JlIGRldGFpbGVkIHN0cnVjdHVyZSwgaW5jbHVkaW5nIGEgc2hhcnAgc3Bpa2UgYXJvdW5kIDAgbWludXRlcyBhbmQgbW9yZSB2YXJpYXRpb24gYWNyb3NzIGRlbGF5IHZhbHVlcywgYnV0IGl0IGFwcGVhcnMgbm9pc2llci4gVGhlIGRlZmF1bHQgaGlzdG9ncmFtIHByb3ZpZGVzIGEgYmFsYW5jZWQgdmlldywgc2hvd2luZyB0aGUgb3ZlcmFsbCBwYXR0ZXJuIHdpdGhvdXQgZXhjZXNzaXZlIG5vaXNlLiBUaGUgaGlzdG9ncmFtIHdpdGggdGhlIGxhcmdlc3QgYmlud2lkdGggc21vb3RocyB0aGUgZGlzdHJpYnV0aW9uIHNpZ25pZmljYW50bHksIGNsZWFybHkgaGlnaGxpZ2h0aW5nIHRoZSBvdmVyYWxsIHRyZW5kIGJ1dCBvYnNjdXJpbmcgaW1wb3J0YW50IGRldGFpbHMgc3VjaCBhcyBzbWFsbGVyIGNsdXN0ZXJzIGFuZCB2YXJpYWJpbGl0eS4KT3ZlcmFsbCwgc21hbGxlciBiaW53aWR0aHMgcmV2ZWFsIGZpbmUgZGV0YWlscywgd2hpbGUgbGFyZ2VyIGJpbndpZHRocyBlbXBoYXNpemUgdGhlIGdlbmVyYWwgc2hhcGUgYnV0IG1heSBoaWRlIG1lYW5pbmdmdWwgcGF0dGVybnMuCgpgYGB7ciBjb2RlLWNodW5rLWxhYmVsfQpnZ3Bsb3QoZGF0YSA9IG55Y2ZsaWdodHMsIGFlcyh4ID0gZGVwX2RlbGF5KSkgKwogIGdlb21faGlzdG9ncmFtKCkKCmdncGxvdChkYXRhID0gbnljZmxpZ2h0cywgYWVzKHggPSBkZXBfZGVsYXkpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAxNSkKCmdncGxvdChkYXRhID0gbnljZmxpZ2h0cywgYWVzKHggPSBkZXBfZGVsYXkpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAxNTApCmBgYAoKIyMjIEV4ZXJjaXNlIDIKCkEgbmV3IGRhdGEgZnJhbWUgd2FzIGNyZWF0ZWQgdXNpbmcgZmlsdGVyKCkgdG8gaW5jbHVkZSBvbmx5IGZsaWdodHMgd2l0aCBkZXN0aW5hdGlvbiBTRk8gaW4gRmVicnVhcnkuClRoZSBudW1iZXIgb2YgZmxpZ2h0cyB0aGF0IG1ldCB0aGlzIGNyaXRlcmlhIGlzIDY4LgoKYGBge3J9CgpzZm9fZmViX2ZsaWdodHMgPC0gbnljZmxpZ2h0cyAlPiUKICBmaWx0ZXIoZGVzdCA9PSAiU0ZPIiwgbW9udGggPT0gMikKCm5yb3coc2ZvX2ZlYl9mbGlnaHRzKQoKYGBgCgojIyMgRXhlcmNpc2UgMwoKVGhlIGhpc3RvZ3JhbSBvZiBhcnJpdmFsIGRlbGF5cyBmb3IgZmxpZ2h0cyB0byBTRk8gaW4gRmVicnVhcnkgc2hvd3MgYSByaWdodC1za2V3ZWQgZGlzdHJpYnV0aW9uLiBNb3N0IGZsaWdodHMgYXJlIGNvbmNlbnRyYXRlZCBhcm91bmQgdmFsdWVzIG5lYXIgemVybywgd2l0aCBtYW55IGZsaWdodHMgYXJyaXZpbmcgZWFybHkgKG5lZ2F0aXZlIGRlbGF5cyksIGFuZCBhIGxvbmcgcmlnaHQgdGFpbCByZXByZXNlbnRpbmcgYSBzbWFsbCBudW1iZXIgb2YgZmxpZ2h0cyB3aXRoIGxhcmdlIGRlbGF5cy4KQmVjYXVzZSB0aGUgZGlzdHJpYnV0aW9uIGlzIHNrZXdlZCBhbmQgaW5jbHVkZXMgZXh0cmVtZSB2YWx1ZXMsIHRoZSBtZWRpYW4gYW5kIGludGVycXVhcnRpbGUgcmFuZ2UgKElRUikgYXJlIG1vcmUgYXBwcm9wcmlhdGUgc3VtbWFyeSBzdGF0aXN0aWNzIHRoYW4gdGhlIG1lYW4gYW5kIHN0YW5kYXJkIGRldmlhdGlvbi4KVGhlIG1lZGlhbiBhcnJpdmFsIGRlbGF5IGlzIC0xMSBtaW51dGVzLCBpbmRpY2F0aW5nIHRoYXQgYSB0eXBpY2FsIGZsaWdodCBhcnJpdmVzIHNsaWdodGx5IGVhcmx5LiBUaGUgSVFSIGlzIDIzLjIgbWludXRlcywgc2hvd2luZyB0aGF0IHRoZSBtaWRkbGUgNTAlIG9mIGFycml2YWwgZGVsYXlzIGZhbGwgd2l0aGluIGEgcmFuZ2Ugb2YgYWJvdXQgMjMgbWludXRlcy4KT3ZlcmFsbCwgbW9zdCBmbGlnaHRzIGFycml2ZSBjbG9zZSB0byBvciBlYXJsaWVyIHRoYW4gc2NoZWR1bGVkLCBidXQgYSBzbWFsbCBudW1iZXIgb2YgZmxpZ2h0cyBleHBlcmllbmNlIGxhcmdlIGRlbGF5cywgY3JlYXRpbmcgdGhlIGxvbmcgcmlnaHQgdGFpbCBvZiB0aGUgZGlzdHJpYnV0aW9uLgoKYGBge3J9CgpnZ3Bsb3Qoc2ZvX2ZlYl9mbGlnaHRzLCBhZXMoeCA9IGFycl9kZWxheSkpICsKICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDE1KQoKCnNmb19mZWJfZmxpZ2h0cyAlPiUKICBzdW1tYXJpemUobWVkaWFuX2RlbGF5ID0gbWVkaWFuKGFycl9kZWxheSwgbmEucm0gPSBUUlVFKSwKICAgIElRUl9kZWxheSA9IElRUihhcnJfZGVsYXksIG5hLnJtID0gVFJVRSkpCiAgCnNmb19mZWJfZmxpZ2h0cyB8PgogIGdyb3VwX2J5KG9yaWdpbikgfD4KICBzdW1tYXJpc2UobWVkaWFuX2RkID0gbWVkaWFuKGRlcF9kZWxheSksIGlxcl9kZCA9IElRUihkZXBfZGVsYXkpLCBuX2ZsaWdodHMgPSBuKCkpCmBgYAoKIyMjIEV4ZXJjaXNlIDQKCkFycml2YWwgZGVsYXlzIChhcnJfZGVsYXkpIHdlcmUgc3VtbWFyaXplZCBieSBjYXJyaWVyIHVzaW5nIHRoZSBtZWRpYW4gYW5kIGludGVycXVhcnRpbGUgcmFuZ2UgKElRUikuIFNpbmNlIGFycml2YWwgZGVsYXlzIGFyZSByaWdodC1za2V3ZWQgd2l0aCBvdXRsaWVycywgdGhlIG1lZGlhbiBhbmQgSVFSIHByb3ZpZGUgcmVzaXN0YW50IG1lYXN1cmVzIG9mIGNlbnRlciBhbmQgc3ByZWFkLgpCYXNlZCBvbiB0aGUgcmVzdWx0cywgREwgYW5kIFVBIGhhdmUgdGhlIG1vc3QgdmFyaWFibGUgYXJyaXZhbCBkZWxheXMsIGVhY2ggd2l0aCBhbiBJUVIgb2YgMjIgbWludXRlcywgbWVhbmluZyB0aGUgbWlkZGxlIDUwJSBvZiB0aGVpciBhcnJpdmFsIGRlbGF5cyBzcGFuIGEgd2lkZXIgcmFuZ2UgdGhhbiB0aGUgb3RoZXIgY2FycmllcnMuCkRMIGFuZCBVQSBhbHNvIGhhdmUgbmVnYXRpdmUgbWVkaWFucyAoREwgPSAtMTUsIFVBID0gLTEwKSwgbWVhbmluZyB0aGVpciB0eXBpY2FsIGZsaWdodCBhcnJpdmVkIGVhcmx5LCBidXQgdmFyaWFiaWxpdHkgYWNyb3NzIGZsaWdodHMgd2FzIHN0aWxsIHRoZSBncmVhdGVzdC4KCmBgYHtyfQoKc2ZvX2ZlYl9mbGlnaHRzICU+JQogIGdyb3VwX2J5KGNhcnJpZXIpICU+JQogIHN1bW1hcml6ZShtZWRpYW5fZGVsYXkgPSBtZWRpYW4oYXJyX2RlbGF5LCBuYS5ybSA9IFRSVUUpLAogICAgSVFSX2RlbGF5ID0gSVFSKGFycl9kZWxheSwgbmEucm0gPSBUUlVFKSkKCgpzZm9fZmViX2ZsaWdodHMgJT4lCiAgZ3JvdXBfYnkoY2FycmllcikgJT4lCiAgc3VtbWFyaXplKAogICAgbWVkaWFuX2RlbGF5ID0gbWVkaWFuKGFycl9kZWxheSwgbmEucm0gPSBUUlVFKSwKICAgIElRUl9kZWxheSA9IElRUihhcnJfZGVsYXksIG5hLnJtID0gVFJVRSkKICApICU+JQogIGFycmFuZ2UoZGVzYyhJUVJfZGVsYXkpKQoKYGBgCgojIyMgRXhlcmNpc2UgNQoKQ2hvb3NpbmcgdGhlIG1vbnRoIHdpdGggdGhlIGxvd2VzdCBtZWFuIGRlcGFydHVyZSBkZWxheSBtaW5pbWl6ZXMgdGhlIG92ZXJhbGwgZXhwZWN0ZWQgZGVsYXkuIFRoaXMgYXBwcm9hY2ggdGFrZXMgaW50byBhY2NvdW50IGFsbCBmbGlnaHRzLCBpbmNsdWRpbmcgdGhvc2Ugd2l0aCBleHRyZW1lIGRlbGF5cywgYW5kIGlzIHVzZWZ1bCBpZiBhIHRyYXZlbGVyIHdhbnRzIHRvIHJlZHVjZSB0aGUgYXZlcmFnZSBkZWxheSB0aGV5IG1pZ2h0IGV4cGVyaWVuY2UuIEhvd2V2ZXIsIHRoZSBtZWFuIGlzIHNlbnNpdGl2ZSB0byBvdXRsaWVycywgc28gYSBmZXcgdW51c3VhbGx5IGxhcmdlIGRlbGF5cyAoc3VjaCBhcyB0aG9zZSBjYXVzZWQgYnkgc2V2ZXJlIHdlYXRoZXIgb3IgY29uZ2VzdGlvbikgY2FuIGluZmxhdGUgdGhlIG1lYW4gYW5kIG1ha2UgYSBtb250aCBhcHBlYXIgd29yc2UgdGhhbiB0aGUgdHlwaWNhbCBleHBlcmllbmNlLgpDaG9vc2luZyB0aGUgbW9udGggd2l0aCB0aGUgbG93ZXN0IG1lZGlhbiBkZXBhcnR1cmUgZGVsYXkgZm9jdXNlcyBvbiB0aGUgdHlwaWNhbCBmbGlnaHQgZXhwZXJpZW5jZSwgc2luY2UgdGhlIG1lZGlhbiBpcyByZXNpc3RhbnQgdG8gZXh0cmVtZSB2YWx1ZXMuIFRoaXMgaXMgZXNwZWNpYWxseSB1c2VmdWwgZm9yIHNrZXdlZCBkYXRhLCBzdWNoIGFzIGRlcGFydHVyZSBkZWxheXMsIHdoaWNoIG9mdGVuIGhhdmUgYSBsb25nIHJpZ2h0IHRhaWwuIEhvd2V2ZXIsIHRoZSBtZWRpYW4gZG9lcyBub3QgY2FwdHVyZSB0aGUgcmlzayBvZiByYXJlIGJ1dCBzZXZlcmUgZGVsYXlzIGFuZCBtYXkgdW5kZXJlc3RpbWF0ZSB0aGUgbGlrZWxpaG9vZCBvZiBleHBlcmllbmNpbmcgYSB2ZXJ5IGxvbmcgZGVsYXkuCkluIHRoaXMgZGF0YXNldCwgT2N0b2JlciAobW9udGggMTApIGhhcyBib3RoIHRoZSBsb3dlc3QgbWVhbiBkZWxheSAoNS44OCBtaW51dGVzKSBhbmQgYSBuZWdhdGl2ZSBtZWRpYW4gZGVsYXkgKC0zIG1pbnV0ZXMpLCBpbmRpY2F0aW5nIHRoYXQgZmxpZ2h0cyB0eXBpY2FsbHkgZGVwYXJ0IGVhcmx5IGFuZCBkZWxheXMgYXJlIHJlbGF0aXZlbHkgc21hbGwgYW5kIGNvbnNpc3RlbnQuCkluIGNvbnRyYXN0LCBKdWx5IChtb250aCA3KSBoYXMgdGhlIGhpZ2hlc3QgbWVhbiBkZWxheSAoMjAuOCBtaW51dGVzKSBhbmQgYSBtZWRpYW4gZGVsYXkgb2YgMCBtaW51dGVzLCBhbG9uZyB3aXRoIGEgbXVjaCBsYXJnZXIgSVFSICgyNiBtaW51dGVzKS4gVGhpcyBzdWdnZXN0cyB0aGF0IHdoaWxlIGEgdHlwaWNhbCBmbGlnaHQgaW4gSnVseSBtYXkgYmUgb24gdGltZSwgZGVwYXJ0dXJlIGRlbGF5cyBhcmUgbXVjaCBtb3JlIHZhcmlhYmxlIGFuZCB0aGVyZSBpcyBhIGdyZWF0ZXIgcmlzayBvZiBleHBlcmllbmNpbmcgbGFyZ2UgZGVsYXlzLgpPdmVyYWxsLCBPY3RvYmVyIGlzIHRoZSBiZXN0IGNob2ljZSB1bmRlciBib3RoIGNyaXRlcmlhLCB3aGlsZSBKdWx5IHJlcHJlc2VudHMgYSBsZXNzIGRlc2lyYWJsZSBvcHRpb24gZHVlIHRvIGl0cyBoaWdoZXIgYXZlcmFnZSBkZWxheXMgYW5kIGdyZWF0ZXIgdmFyaWFiaWxpdHkuClRoaXMgY29tcGFyaXNvbiBoaWdobGlnaHRzIGhvdyBzZWFzb25hbCBmYWN0b3JzLCBzdWNoIGFzIHN1bW1lciB0cmF2ZWwgdm9sdW1lLCBjYW4gaW5jcmVhc2UgYm90aCB0aGUgZnJlcXVlbmN5IGFuZCB2YXJpYWJpbGl0eSBvZiBkZWxheXMuCgpgYGB7cn0KbnljZmxpZ2h0cyB8PgogIGdyb3VwX2J5KG1vbnRoKSB8PgogIHN1bW1hcmlzZShtZWFuX2RkID0gbWVhbihkZXBfZGVsYXkpKSB8PgogIGFycmFuZ2UoZGVzYyhtZWFuX2RkKSkKCm55Y2ZsaWdodHMgJT4lCiAgICAgZ3JvdXBfYnkobW9udGgpICU+JQogICAgIHN1bW1hcml6ZShtZWFuX2RkID0gbWVhbihkZXBfZGVsYXksIG5hLnJtID0gVFJVRSkpICU+JQogICAgIGFycmFuZ2UobWVhbl9kZCkKCm55Y2ZsaWdodHMgJT4lCiAgICAgZ3JvdXBfYnkobW9udGgpICU+JQogICAgIHN1bW1hcml6ZSgKICAgICAgICAgbWVhbl9kZCAgID0gbWVhbihkZXBfZGVsYXksIG5hLnJtID0gVFJVRSksCiAgICAgICAgIG1lZGlhbl9kZCA9IG1lZGlhbihkZXBfZGVsYXksIG5hLnJtID0gVFJVRSksCiAgICAgICAgIElRUl9kZCAgICA9IElRUihkZXBfZGVsYXksIG5hLnJtID0gVFJVRSksCiAgICAgICAgIG4gICAgICAgICA9IHN1bSghaXMubmEoZGVwX2RlbGF5KSkpICU+JQogICAgIGFycmFuZ2UobWVhbl9kZCkKYGBgCgoKIyMjIEV4ZXJjaXNlIDYKClRvIGRldGVybWluZSB3aGljaCBOWUMgYWlycG9ydCBoYXMgdGhlIGhpZ2hlc3Qgb24tdGltZSBkZXBhcnR1cmUgcGVyY2VudGFnZSwgZmxpZ2h0cyB3ZXJlIGNsYXNzaWZpZWQgYXMg4oCcb24gdGltZeKAnSBpZiB0aGUgZGVwYXJ0dXJlIGRlbGF5IHdhcyBsZXNzIHRoYW4gNSBtaW51dGVzLgpBIHN0YWNrZWQgYmFyIGNoYXJ0IHdhcyBhbHNvIGNyZWF0ZWQgdG8gdmlzdWFsaXplIHRoZSBwcm9wb3J0aW9uIG9mIG9uLXRpbWUgYW5kIGRlbGF5ZWQgZmxpZ2h0cyBieSBhaXJwb3J0LgpUaGUgcmVzdWx0cyBzaG93IHRoYXQgTGFHdWFyZGlhIEFpcnBvcnQgKExHQSkgaGFzIHRoZSBoaWdoZXN0IG9uLXRpbWUgZGVwYXJ0dXJlIHJhdGUgYXQgNzIuOCUsIGZvbGxvd2VkIGJ5IEpGSyAoNjkuNCUpIGFuZCBFV1IgKDYzLjclKS4KVGhlIHZpc3VhbGl6YXRpb24gc3VwcG9ydHMgdGhpcyBmaW5kaW5nLCBhcyBMR0EgaGFzIHRoZSBsYXJnZXN0IHByb3BvcnRpb24gb2Ygb24tdGltZSBmbGlnaHRzICh0ZWFsKSBhbmQgdGhlIHNtYWxsZXN0IHByb3BvcnRpb24gb2YgZGVsYXllZCBmbGlnaHRzIChyZWQpLCB3aGlsZSBFV1Igc2hvd3MgdGhlIG9wcG9zaXRlIHBhdHRlcm4uClRoZXJlZm9yZSwgaWYgc2VsZWN0aW5nIGFuIGFpcnBvcnQgYmFzZWQgc29sZWx5IG9uIG9uLXRpbWUgZGVwYXJ0dXJlIHBlcmZvcm1hbmNlLCBMR0Egd291bGQgYmUgdGhlIGJlc3QgY2hvaWNlLgpUaGUgY29uc2lzdGVuY3kgYmV0d2VlbiB0aGUgbnVtZXJpY2FsIHN1bW1hcnkgYW5kIHRoZSB2aXN1YWwgcmVwcmVzZW50YXRpb24gc3RyZW5ndGhlbnMgdGhlIGNvbmNsdXNpb24gdGhhdCBMR0EgaGFzIHRoZSBiZXN0IG9uLXRpbWUgcGVyZm9ybWFuY2UuCgpgYGB7cn0KbnljZmxpZ2h0cyA8LSBueWNmbGlnaHRzIHw+CiAgbXV0YXRlKGRlcF90eXBlID0gaWZlbHNlKGRlcF9kZWxheSA8IDUsICJvbiB0aW1lIiwgImRlbGF5ZWQiKSkKCm55Y2ZsaWdodHMgfD4KICBncm91cF9ieShvcmlnaW4pIHw+CiAgc3VtbWFyaXNlKG90X2RlcF9yYXRlID0gc3VtKGRlcF90eXBlID09ICJvbiB0aW1lIikgLyBuKCkpIHw+CiAgYXJyYW5nZShkZXNjKG90X2RlcF9yYXRlKSkKCmdncGxvdChkYXRhID0gbnljZmxpZ2h0cywgYWVzKHggPSBvcmlnaW4sIGZpbGwgPSBkZXBfdHlwZSkpICsKICBnZW9tX2JhcigpCgpgYGAKCiMjIyBFeGVyY2lzZSA3CgpBIG5ldyB2YXJpYWJsZSwgYXZnX3NwZWVkLCB3YXMgY3JlYXRlZCBieSBkaXZpZGluZyBkaXN0YW5jZSAobWlsZXMpIGJ5IGZsaWdodCB0aW1lIGluIGhvdXJzLCBjb252ZXJ0aW5nIGFpcl90aW1lIGZyb20gbWludXRlcyB0byBob3Vycy4KCmBgYHtyfQoKCm55Y2ZsaWdodHMgPC0gbnljZmxpZ2h0cyAlPiUKICBtdXRhdGUoYXZnX3NwZWVkID0gZGlzdGFuY2UgLyAoYWlyX3RpbWUgLyA2MCkpCgpzdW1tYXJ5KG55Y2ZsaWdodHMkYXZnX3NwZWVkKQoKYGBgCgojIyMgRXhlcmNpc2UgOAoKVGhlIHNjYXR0ZXJwbG90IHNob3dzIGEgcG9zaXRpdmUgcmVsYXRpb25zaGlwIGJldHdlZW4gZGlzdGFuY2UgYW5kIGF2ZXJhZ2Ugc3BlZWQuIEZsaWdodHMgY292ZXJpbmcgbG9uZ2VyIGRpc3RhbmNlcyB0ZW5kIHRvIGhhdmUgaGlnaGVyIGF2ZXJhZ2Ugc3BlZWRzLgpUaGlzIHBhdHRlcm4gbGlrZWx5IG9jY3VycyBiZWNhdXNlIGxvbmdlciBmbGlnaHRzIHNwZW5kIG1vcmUgdGltZSBhdCBjcnVpc2luZyBhbHRpdHVkZSwgd2hlcmUgcGxhbmVzIHRyYXZlbCBtb3JlIGVmZmljaWVudGx5IGFuZCBhdCBoaWdoZXIgc3BlZWRzLiBJbiBjb250cmFzdCwgc2hvcnRlciBmbGlnaHRzIHNwZW5kIG1vcmUgdGltZSB0YWtpbmcgb2ZmIGFuZCBsYW5kaW5nLCB3aGljaCByZWR1Y2VzIHRoZWlyIGF2ZXJhZ2Ugc3BlZWQuCgpgYGB7cn0KCmdncGxvdChueWNmbGlnaHRzLCBhZXMoeCA9IGRpc3RhbmNlLCB5ID0gYXZnX3NwZWVkKSkgKwogIGdlb21fcG9pbnQoYWxwaGEgPSAwLjMpCgoKZ2dwbG90KG55Y2ZsaWdodHMsIGFlcyh4ID0gZGlzdGFuY2UsIHkgPSBhdmdfc3BlZWQpKSArCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuMykgKwogIGdlb21fc21vb3RoKCkKCgpgYGAKCiMjIyBFeGVyY2lzZSA5CgpUaGUgc2NhdHRlcnBsb3Qgb2YgZGVwYXJ0dXJlIGRlbGF5IHZlcnN1cyBhcnJpdmFsIGRlbGF5IGZvciBBbWVyaWNhbiAoQUEpLCBEZWx0YSAoREwpLCBhbmQgVW5pdGVkIChVQSkgc2hvd3MgYSBzdHJvbmcgcG9zaXRpdmUgcmVsYXRpb25zaGlwOiBmbGlnaHRzIHRoYXQgZGVwYXJ0IGxhdGVyIHRlbmQgdG8gYXJyaXZlIGxhdGVyLgpIb3dldmVyLCB0aGVyZSBhcmUgbWFueSBvYnNlcnZhdGlvbnMgd2hlcmUgZmxpZ2h0cyB3aXRoIHNtYWxsIGRlcGFydHVyZSBkZWxheXMgc3RpbGwgYXJyaXZlIG9uIHRpbWUgb3IgZWFybHkgKG5lZ2F0aXZlIGFycml2YWwgZGVsYXlzKS4gVGhpcyBzdWdnZXN0cyB0aGF0IGFpcmxpbmVzIGFyZSBvZnRlbiBhYmxlIHRvIG1ha2UgdXAgc29tZSBsb3N0IHRpbWUgZHVyaW5nIHRoZSBmbGlnaHQuCkJhc2VkIG9uIHRoZSBwbG90LCB0aGUgYXBwcm94aW1hdGUgY3V0b2ZmIHBvaW50IGFwcGVhcnMgdG8gYmUgYXJvdW5kIDMw4oCTNjAgbWludXRlcyBvZiBkZXBhcnR1cmUgZGVsYXkuIEZsaWdodHMgZGVsYXllZCBsZXNzIHRoYW4gdGhpcyByYW5nZSBvZnRlbiBzdGlsbCBhcnJpdmUgb24gdGltZSwgd2hpbGUgZmxpZ2h0cyB3aXRoIGRlbGF5cyBncmVhdGVyIHRoYW4gdGhpcyBhcmUgbXVjaCBtb3JlIGxpa2VseSB0byBhcnJpdmUgbGF0ZS4KT3ZlcmFsbCwgdGhpcyBpbmRpY2F0ZXMgdGhhdCBtb2RlcmF0ZSBkZXBhcnR1cmUgZGVsYXlzIGNhbiBzb21ldGltZXMgYmUgcmVjb3ZlcmVkLCBidXQgbGFyZ2VyIGRlbGF5cyB0eXBpY2FsbHkgcmVzdWx0IGluIGxhdGUgYXJyaXZhbHMuCgpgYGB7cn0KCnNlbGVjdGVkX2ZsaWdodHMgPC0gbnljZmxpZ2h0cyAlPiUKICBmaWx0ZXIoY2FycmllciAlaW4lIGMoIkFBIiwgIkRMIiwgIlVBIikpCgoKZ2dwbG90KHNlbGVjdGVkX2ZsaWdodHMsIGFlcyh4ID0gZGVwX2RlbGF5LCB5ID0gYXJyX2RlbGF5LCBjb2xvciA9IGNhcnJpZXIpKSArCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuNSkKCgpgYGAKCiMjIyBFeGVyY2lzZXMgMy41LjEKCjEuIEZhY2V0aW5nIGEgY29udGludW91cyB2YXJpYWJsZSBjcmVhdGVzIGEgcGFuZWwgZm9yIGVhY2ggdW5pcXVlIHZhbHVlLCB3aGljaCBjYW4gcmVzdWx0IGluIGEgdmVyeSBsYXJnZSBudW1iZXIgb2Ygc21hbGwgcGxvdHMuIFRoaXMgaXMgb2Z0ZW4gbm90IHVzZWZ1bCBiZWNhc3VlIHRoZSBwYW5lbHMgYmVjb21lIHRvbyBudW1lcm91cywgZWFjaCBwYW5lbCBtYXkgY29udGFpbiB2ZXJ5IGZldyBvYnNlcnZhdGlvbnMsIGFuZCB0aGUgcGxvdCBiZWNvbWVzIGRpZmZpY3VsdCB0byBpbnRlcnByZXQuIEluIHByYWN0aWNlLCBjb250aW51b3VzIHZhcmlhYmxlcyBzaG91bGQgYmUgYmlubmVkIG9yIGNhdGVnb3JpemVkIGJlZm9yZSBmYWNldGluZy4KCjIuIEVtcHR5IGNlbGxzIHJlcHJlc2VudCBjb21iaW5hdGlvbnMgb2YgdmFyaWFibGVzIHRoYXQgZG8gbm90IGV4aXN0IGluIHRoZSBkYXRhc2V0LiBGb3IgZXhhbXBsZSwgaWYgbm8gY2FycyBoYXZlIGEgY2VydGFpbiBjb21iaW5hdGlvbiBvZiBkcml2ZSB0eXBlIGFuZCBudW1iZXIgb2YgY3lsaW5kZXJzLCBnZ3Bsb3Qgc3RpbGwgY3JlYXRlcyB0aGUgcGFuZWwsIGJ1dCBpdCBhcHBlYXJzIGVtcHR5IGJlY2FzdWUgbm8gb2JzZXJ2YXRpb25zIGZhbGwgaW50byB0aGF0IGNhdGVnb3J5LiBUaGVzZSBlbXB0eSBjZWxscyBoaWdobGlnaHQgbWlzc2luZyBjb21iaW5hdGlvbiBpbiB0aGUgZGF0YSwgbm90IGVycm9ycy4gCgozLkZpcnN0IHBsb3Q6IENyZWF0ZXMgb25lIGNvbHVtbiBvZiBwbG90cy4gRWFjaCByb3cgPSBhIGRpZmZlcmVudCB2YWx1ZSBvZiBkcml2ZSB0eXBlLiBZb3UgZ2V0IHN0YWNrZWQgcGFuZWxzIHZlcnRpY2FsbHkuIFNlY29uZCBwbG90OiBDcmVhdGVzIG9uZSByb3cgb2YgcGxvdHMuIEVhY2ggY29sdW1uID0gYSBkaWZmZXJlbnQgdmFsdWUgb2YgbnVtYmVyIG9mIGN5bGluZGVycy4geW91IGdldCBwYW5lbHMgYXJyYW5nZWQgaG9yaXpvbnRhbGx5LgouIG1lYW5zIG5vICJmYWNldGluZyBpbiB0aGF0IGRpcmVjdGlvbiIuIEluIGRyen4uIC0tPiBubyBjb2x1bW5zLCBvbmx5IHJvd3M7IEluIC5+Y3lsIC0tPiBubyByb3dzLCBvbmx5IGNvbHVtbnMKCjQuIEFkdmFudGFnZXMgb2YgZmFjZXRpbmc6IFNlcGFyYXRlcyBncm91cHMgaW50byBjbGVhciwgaW5kaXZpZHVhbCBwYW5lbHMuIE1ha2VzIHBhdHRlcm5zIGVhc2llciB0byBjb21wYXJlIHdpdGhvdXQgb3ZlcmxhcC4gUmVkdWNlcyBjbHV0dGVyIGluIGRlbnNlIHBsb3RzLgpEaXNhZHZhbnRhZ2VzIG9mIGZhY2V0aW5nOiBUYWtlcyB1cCBtb3JlIHNwYWNlLiBIYXJkZXIgdG8gY29tcGFyZSB2YWx1ZXMgYWNyb3NzIHBhbmVscyBkaXJlY3RseS4gQ2FuIGJlY29tZSBvdmVyd2hlbG1pbmcgd2l0aCBtYW55IGNhdGVnb3JpZXMuCkFkdmFudGFnZXMgb2YgdXNpbmcgY29sb3I6IGFsbCBkYXRhIHNob3duIGluIG9uZSBwbG90LiBFYXNpZXIgZGlyZWN0IGNvbXBhcmlzb24gYWNyb3NzIGdyb3Vwcy4gTW9yZSBjb21wYWN0LgpEaXNhZHZhbnRhZ2VzIG9mIGNvbG9yOiBPdmVycGxvdHRpbmcgKHBvaW50cyBvdmVybGFwKS4gSGFyZCB0byBkaXN0aW5ndWlzaCBncm91cHMgaWYgbWFueSBjYXRlZ29yaWVzLiBDYW4gYmUgdmlzdWFsbHkgY2x1dHRlcmVkLiAKV2l0aCBsYXJnZXIgZGF0YSBzZXRzLCBjb2xvciBjYW4gYmVjb21lIGNsdXR0ZXJlZCwgYW5kIGZhY2V0aW5nIGJlY29tZXMgbW9yZSB1c2VmdWwgZm9yIGNsYXJpdHkuCgo1LiBJbiBmYWNldF93cmFwKCksIHRoZSBhcmd1bWVudHMgbnJvdyBhbmQgbmNvbCBjb250cm9sIHRoZSBsYXlvdXQgb2YgdGhlIHBhbmVscy4gVGhlIG5yb3cgYXJndW1lbnQgc3BlY2lmaWVzIHRoZSBudW1iZXIgb2Ygcm93cywgd2hpbGUgbmNvbCBzcGVjaWZpZXMgdGhlIG51bWJlciBvZiBjb2x1bW5zIHVzZWQgdG8gYXJyYW5nZSB0aGUgcGFuZWxzLiBJbiBjb250cmFzdCwgZmFjZXRfZ3JpZCgpIGRvZXMgbm90IGluY2x1ZGUgbnJvdyBhbmQgbmNvbCBhcmd1bWVudHMgYmVjYXVzZSBpdHMgbGF5b3V0IGlzIGRldGVybWluZWQgZW50aXJlbHkgYnkgdGhlIHZhcmlhYmxlcyB1c2VkIGZvciBmYWNldGluZy4gVGhlIG51bWJlciBvZiByb3dzIGFuZCBjb2x1bW5zIGlzIGZpeGVkIGJhc2VkIG9uIHRoZSBudW1iZXIgb2YgbGV2ZWxzIGluIGVhY2ggdmFyaWFibGUsIHNvIHRoZSB1c2VyIGRvZXMgbm90IG1hbnVhbGx5IGNvbnRyb2wgdGhlIGxheW91dC4KCjYuIFlvdSBzaG91bGQgcHV0IHRoZSB2YXJpYWJsZSB3aXRoIG1vcmUgdW5pcXVlIGxldmVscyBpbiB0aGUgY29sdW1ucyBiZWNhdXNlIHNjcmVlbnMgYXJlIHR5cGljYWxseSB3aWRlciB0aGFuIHRoZXkgYXJlIHRhbGwuIFB1dHRpbmcgbW9yZSBsZXZlbHMgaW4gY29sdW1ucyB1c2VzIGhvcml6b250YWwgc3BhY2UgZWZmaWNpZW50bHksIHByZXZlbnRzIHBsb3RzIGZyb20gYmVjb21pbmcgdG9vIHRhbGwgYW5kIGNvbXByZXNzZWQsIGFuZCBtYWtlcyB0aGUgbGF5b3V0IGVhc2llciB0byByZWFkLiAKCmBgYHtyfQpmYWNldF9ncmlkKGRydiB+IGN5bCkKCmdncGxvdChkYXRhID0gbXBnKSArIAogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gZHJ2LCB5ID0gY3lsKSkKCmdncGxvdChkYXRhID0gbXBnKSArIAogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3kpKSArCiAgZmFjZXRfZ3JpZChkcnYgfiAuKQoKZ2dwbG90KGRhdGEgPSBtcGcpICsgCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSBkaXNwbCwgeSA9IGh3eSkpICsKICBmYWNldF9ncmlkKC4gfiBjeWwpCgpnZ3Bsb3QoZGF0YSA9IG1wZykgKyAKICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5KSkgKyAKICBmYWNldF93cmFwKH4gY2xhc3MsIG5yb3cgPSAyKQoKYGBgCgojIyMgRXhlcmNpc2VzIDMuNy4xCgoxLiBUaGUgZGVmYXVsdCBnZW9tIGZvciBzdGF0X3N1bW1hcnkoKSBpcyBnZW9tX3BvaW50cmFuZ2UoKS4gVG8gcmV3cml0ZSBhIHBsb3QgdXNpbmcgdGhlIGdlb20gaW5zdGVhZCBvZiB0aGUgc3RhdCwgeW91IHNwZWNpZnkgc3RhdCA9ICJzdW1tYXJ5IiBpbnNpZGUgdGhlIGdlb206ICAKZ2VvbV9wb2ludHJhbmdlKHN0YXQgPSAic3VtbWFyeSIsIGZ1bi5kYXRhID0gIm1lYW5fY2xfbm9ybWFsIikKCjIuIGdlb21fY29sKCkgY3JlYXRlcyBiYXIgcGxvdHMgdXNpbmcgdmFsdWVzIHRoYXQgYXJlIGFscmVhZHkgcHJlc2VudCBpbiB0aGUgZGF0YXNldCwgbWVhbmluZyB0aGUgaGVpZ2h0cyBvZiB0aGUgYmFycyBhcmUgdGFrZW4gZGlyZWN0bHkgZnJvbSBhIHkgdmFyaWFibGUuIEluIGNvbnRyYXN0LCBnZW9tX2JhcigpIGNhbGN1bGF0ZXMgY291bnRzIGF1dG9tYXRpY2FsbHkgKHVzaW5nIHN0YXQgPSAiY291bnQiIGJ5IGRlZmF1bHQpIGFuZCBkb2VzIG5vdCByZXF1aXJlIGEgeSB2YXJpYWJsZS4gVGhlcmVmb3JlLCBnZW9tX2NvbCgpIGlzIHVzZWQgd2hlbiB0aGUgZGF0YSBoYXMgYWxyZWFkeSBiZWVuIHN1bW1hcml6ZWQsIHdoaWxlIGdlb21fYmFyKCkgaXMgdXNlZCBmb3IgcmF3IGRhdGEuCgozLiBNb3N0IGdlb21zIGFuZCBzdGF0cyBjb21lIGluIHBhaXJzLCBzdWNoIGFzIGdlb21fYmFyKCkgd2l0aCBzdGF0X2NvdW50KCksIGdlb21faGlzdG9ncmFtKCkgd2l0aCBzdGF0X2JpbigpLCBhbmQgZ2VvbV9zbW9vdGgoKSB3aXRoIHN0YXRfc21vb3RoKCkuIFRoZXNlIHBhaXJzIHdvcmsgdG9nZXRoZXIgc3VjaCB0aGF0IHRoZSBzdGF0IGNvbXB1dGVzIGEgdHJhbnNmb3JtYXRpb24gb2YgdGhlIGRhdGEsIGFuZCB0aGUgZ2VvbSBjb250cm9scyBob3cgdGhlIHJlc3VsdCBpcyBkaXNwbGF5ZWQuIFRoZXkgc2hhcmUgdGhlIHNhbWUgdW5kZXJseWluZyBzdHJ1Y3R1cmUgYW5kIGNhbiBvZnRlbiBiZSBpbnRlcmNoYW5nZWQgYnkgc3BlY2lmeWluZyB0aGUgc3RhdCBvciBnZW9tIGFyZ3VtZW50IGV4cGxpY2l0bHkuCgo0LiBzdGF0X3Ntb290aCgpIGNvbXB1dGVzIGEgc21vb3RoZWQgdHJlbmQgbGluZSB0aHJvdWdoIHRoZSBkYXRhIGFuZCBvZnRlbiBpbmNsdWRlcyBhIGNvbmZpZGVuY2UgaW50ZXJ2YWwgYXJvdW5kIHRoZSBlc3RpbWF0ZS4gSXRzIGJlaGF2aW9yIGlzIGNvbnRyb2xsZWQgYnkgcGFyYW1ldGVycyBzdWNoIGFzIG1ldGhvZCAoZS5nLiwgImxtIiBvciAibG9lc3MiKSwgc2UgKHdoZXRoZXIgdG8gZGlzcGxheSB0aGUgY29uZmlkZW5jZSBpbnRlcnZhbCksIGFuZCBvdGhlciBhcmd1bWVudHMgbGlrZSBzcGFuIGZvciBjb250cm9sbGluZyBzbW9vdGhuZXNzLgoKNS4gVGhlIGlzc3VlIGlzIHRoYXQgZ2dwbG90MiBhdXRvbWF0aWNhbGx5IGdyb3VwcyBkYXRhIGJhc2VkIG9uIG1hcHBlZCBhZXN0aGV0aWNzIHN1Y2ggYXMgZmlsbC4gQXMgYSByZXN1bHQsIHByb3BvcnRpb25zIGFyZSBjYWxjdWxhdGVkIHdpdGhpbiBlYWNoIGdyb3VwIGluc3RlYWQgb2YgYWNyb3NzIHRoZSBlbnRpcmUgZGF0YXNldC4gSXQgY3JlYXRlcyBncmF5LCBzb2xpZCBmaWxsZWQgYmFycy4gQnkgc2V0dGluZyBncm91cCA9IDEsIHdlIG92ZXJyaWRlIHRoaXMgZGVmYXVsdCBncm91cGluZyBhbmQgZW5zdXJlIHRoYXQgdGhlIHByb3BvcnRpb25zIGFyZSBjYWxjdWxhdGVkIHJlbGF0aXZlIHRvIGFsbCBvYnNlcnZhdGlvbnMuIFdpdGhvdXQgdGhpcyBzcGVjaWZpY2F0aW9uLCB0aGUgZ3JhcGhzIGRpc3BsYXkgaW5jb3JyZWN0IHByb3BvcnRpb25zIGJlY2F1c2UgZWFjaCBjYXRlZ29yeSBpcyBub3JtYWxpemVkIHNlcGFyYXRlbHkgcmF0aGVyIHRoYW4gZ2xvYmFsbHkuCgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBkaWFtb25kcykgKyAKICBnZW9tX2JhcihtYXBwaW5nID0gYWVzKHggPSBjdXQsIHkgPSBhZnRlcl9zdGF0KHByb3ApKSkKCmdncGxvdChkYXRhID0gZGlhbW9uZHMpICsgCiAgZ2VvbV9iYXIobWFwcGluZyA9IGFlcyh4ID0gY3V0LCBmaWxsID0gY29sb3IsIHkgPSBhZnRlcl9zdGF0KHByb3ApKSkKCmBgYAoKIyMjIEV4ZXJjaXNlcyAzLjguMQoKMS4gVGhlIG1haW4gcHJvYmxlbSB3aXRoIHRoaXMgcGxvdCBpcyBvdmVycGxvdHRpbmcsIHNpbmNlIG1hbnkgb2JzZXJ2YXRpb25zIHNoYXJlIHRoZSBzYW1lIHZhbHVlcyBvZiBjdHkgYW5kIGh3eSwgY2F1c2luZyBwb2ludHMgdG8gb3ZlcmxhcCBhbmQgb2JzY3VyZSB0aGUgdHJ1ZSBudW1iZXIgb2Ygb2JzZXJ2YXRpb25zLiBUaGlzIG1ha2VzIGl0IGRpZmZpY3VsdCB0byBhc3Nlc3MgdGhlIGRlbnNpdHkgb2YgdGhlIGRhdGEuIFRoZSBwbG90IGNhbiBiZSBpbXByb3ZlZCBieSB1c2luZyBqaXR0ZXJpbmcgKGUuZy4sIGdlb21faml0dGVyKCkpLCBhZGRpbmcgdHJhbnNwYXJlbmN5LCBvciB1c2luZyBnZW9tX2NvdW50KCkgdG8gYmV0dGVyIGRpc3BsYXkgdGhlIGZyZXF1ZW5jeSBvZiBvdmVybGFwcGluZyBwb2ludHMuCgoyLiBUaGUgYW1vdW50IG9mIGppdHRlcmluZyBpcyBjb250cm9sbGVkIGJ5IHRoZSB3aWR0aCBhbmQgaGVpZ2h0IHBhcmFtZXRlcnMgaW4gZ2VvbV9qaXR0ZXIoKS4gVGhlIHdpZHRoIGFyZ3VtZW50IGRldGVybWluZXMgdGhlIGFtb3VudCBvZiBob3Jpem9udGFsIG1vdmVtZW50LCB3aGlsZSB0aGUgaGVpZ2h0IGFyZ3VtZW50IGNvbnRyb2xzIHZlcnRpY2FsIG1vdmVtZW50IG9mIHBvaW50cy4KCjMuIGdlb21faml0dGVyKCkgcmVkdWNlcyBvdmVycGxvdHRpbmcgYnkgYWRkaW5nIHNtYWxsIHJhbmRvbSB2YXJpYXRpb24gdG8gdGhlIHBvc2l0aW9uIG9mIHBvaW50cywgbWFraW5nIG92ZXJsYXBwaW5nIG9ic2VydmF0aW9ucyB2aXNpYmxlLiBJbiBjb250cmFzdCwgZ2VvbV9jb3VudCgpIHJlcHJlc2VudHMgb3ZlcmxhcHBpbmcgb2JzZXJ2YXRpb25zIGJ5IGluY3JlYXNpbmcgdGhlIHNpemUgb2YgdGhlIHBvaW50cyBiYXNlZCBvbiB0aGVpciBmcmVxdWVuY3kuIFdoaWxlIGppdHRlcmluZyBzcHJlYWRzIHRoZSBkYXRhIHZpc3VhbGx5LCBnZW9tX2NvdW50KCkgcHJlc2VydmVzIHRoZSBleGFjdCB2YWx1ZXMgYnV0IGVuY29kZXMgZnJlcXVlbmN5IHRocm91Z2ggcG9pbnQgc2l6ZS4KCjQuIFRoZSBkZWZhdWx0IHBvc2l0aW9uIGFkanVzdG1lbnQgZm9yIGdlb21fYm94cGxvdCgpIGlzIHBvc2l0aW9uID0gImRvZGdlMiIsIHdoaWNoIHBsYWNlcyBib3hwbG90cyBzaWRlLWJ5LXNpZGUgd2hlbiB0aGVyZSBhcmUgbXVsdGlwbGUgZ3JvdXBzLiBUaGlzIGFsbG93cyBmb3IgZWFzaWVyIGNvbXBhcmlzb24gYmV0d2VlbiBjYXRlZ29yaWVzLiAKCgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBtcGcsIG1hcHBpbmcgPSBhZXMoeCA9IGN0eSwgeSA9IGh3eSkpICsgCiAgZ2VvbV9wb2ludCgpCmBgYAoKIyMjIEV4ZXJjaXNlcyAzLjkuMQoKMS4gQSBzdGFja2VkIGJhciBjaGFydCBjYW4gYmUgY29udmVydGVkIGludG8gYSBwaWUgY2hhcnQgYnkgdXNpbmcgY29vcmRfcG9sYXIodGhldGEgPSAieSIpLCB3aGljaCB0cmFuc2Zvcm1zIHRoZSB5LXZhbHVlcyBpbnRvIGFuZ3VsYXIgc3BhY2UgYW5kIHdyYXBzIHRoZSBiYXIgY2hhcnQgaW50byBhIGNpcmNsZS4KCjIuIFRoZSBsYWJzKCkgZnVuY3Rpb24gaXMgdXNlZCB0byBhZGQgYW5kIG1vZGlmeSBsYWJlbHMgaW4gYSBnZ3Bsb3QsIGluY2x1ZGluZyB0aGUgdGl0bGUsIHN1YnRpdGxlLCBheGlzIGxhYmVscywgbGVnZW5kIGxhYmVscywgYW5kIGNhcHRpb24uIEl0IGlzIHByZWZlcnJlZCBvdmVyIG9sZGVyIGZ1bmN0aW9ucyBzdWNoIGFzIHhsYWIoKSBhbmQgZ2d0aXRsZSgpLCB3aGljaCBhcmUgbm93IHN1cGVyc2VkZWQuIEJ5IGltcHJvdmluZyBsYWJlbGluZywgbGFicygpIG1ha2VzIHBsb3RzIG1vcmUgaW50ZXJwcmV0YWJsZSBhbmQgYWNjZXNzaWJsZSB0byBhIGJyb2FkZXIgYXVkaWVuY2UuCgozLiBjb29yZF9tYXAoKSBhcHBsaWVzIGEgdHJ1ZSBtYXAgcHJvamVjdGlvbiBhbmQgcHJlc2VydmVzIGdlb2dyYXBoaWMgYWNjdXJhY3ksIGJ1dCBpdCBpcyBjb21wdXRhdGlvbmFsbHkgc2xvd2VyLiBJbiBjb250cmFzdCwgY29vcmRfcXVpY2ttYXAoKSBwcm92aWRlcyBhIGZhc3RlciBhcHByb3hpbWF0aW9uIG9mIGEgbWFwIHByb2plY3Rpb24gYW5kIHdvcmtzIHdlbGwgZm9yIHNtYWxsZXIgZ2VvZ3JhcGhpYyByZWdpb25zIHdoZXJlIGRpc3RvcnRpb24gaXMgbWluaW1hbC4KCjQuIFRoZSBwbG90IHNob3dzIGEgc3Ryb25nIHBvc2l0aXZlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGNpdHkgKGN0eSkgYW5kIGhpZ2h3YXkgKGh3eSkgbWlsZWFnZTogdmVoaWNsZXMgd2l0aCBoaWdoZXIgY2l0eSBNUEcgYWxzbyB0ZW5kIHRvIGhhdmUgaGlnaGVyIGhpZ2h3YXkgTVBHLiBNb3N0IHBvaW50cyBsaWUgYWJvdmUgdGhlIHJlZmVyZW5jZSBsaW5lLCBpbmRpY2F0aW5nIHRoYXQgaGlnaHdheSBNUEcgaXMgZ2VuZXJhbGx5IGhpZ2hlciB0aGFuIGNpdHkgTVBHLgpUaGUgZnVuY3Rpb24gY29vcmRfZml4ZWQoKSBpcyBpbXBvcnRhbnQgYmVjYXVzZSBpdCBlbnN1cmVzIGVxdWFsIHNjYWxpbmcgb24gYm90aCBheGVzLCBtYWtpbmcgdGhlIHJlZmVyZW5jZSBsaW5lIG1lYW5pbmdmdWwgYW5kIGFsbG93aW5nIGFjY3VyYXRlIHZpc3VhbCBjb21wYXJpc29uIGJldHdlZW4gdGhlIHR3byB2YXJpYWJsZXMuClRoZSBmdW5jdGlvbiBnZW9tX2FibGluZSgpIGFkZHMgYSBkaWFnb25hbCByZWZlcmVuY2UgbGluZSAod2l0aCBzbG9wZSA9IDEgYW5kIGludGVyY2VwdCA9IDApLCByZXByZXNlbnRpbmcgd2hlcmUgY2l0eSBNUEcgZXF1YWxzIGhpZ2h3YXkgTVBHLiBUaGlzIGhlbHBzIGhpZ2hsaWdodCB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSB0d28gbWVhc3VyZXMgYW5kIG1ha2VzIGl0IGNsZWFyIHRoYXQgbW9zdCB2ZWhpY2xlcyBwZXJmb3JtIGJldHRlciBvbiB0aGUgaGlnaHdheSB0aGFuIGluIHRoZSBjaXR5LgoKYGBge3J9CmdncGxvdChkaWFtb25kcywgYWVzKHggPSAiIiwgZmlsbCA9IGN1dCkpICsKICBnZW9tX2Jhcih3aWR0aCA9IDEpICsKICBjb29yZF9wb2xhcih0aGV0YSA9ICJ5IikKCgpnZ3Bsb3QoZGF0YSA9IG1wZywgbWFwcGluZyA9IGFlcyh4ID0gY3R5LCB5ID0gaHd5KSkgKwogIGdlb21fcG9pbnQoKSArIAogIGdlb21fYWJsaW5lKCkgKwogIGNvb3JkX2ZpeGVkKCkKYGBgCgojIyMgRXhlcmNpc2VzIDQuNAoKMS4gVGhpcyBjb2RlIGRvZXMgbm90IHdvcmsgYmVjYXVzZSB0aGUgYXNzaWdubWVudCBvcGVyYXRvciBpcyBub3Qgd3JpdHRlbiBjb3JyZWN0bHkuIEluIFIsIHRoZSBhc3NpZ25tZW50IG11c3QgdXNlIHRoZSBleGFjdCBvcGVyYXRvciA8LS4gSWYgYW4gaW5jb3JyZWN0IGRhc2ggb3IgZm9ybWF0dGluZyBpcyB1c2VkLCBSIGRvZXMgbm90IHJlY29nbml6ZSB0aGUgYXNzaWdubWVudCwgYW5kIHRoZSB2YXJpYWJsZSBpcyBub3QgY3JlYXRlZCwgcmVzdWx0aW5nIGluIHRoZSBlcnJvci4KCjIuIFRoZSBjb3JyZWN0ZWQgY29tbWFuZHMgYXJlOgoKbGlicmFyeSh0aWR5dmVyc2UpCgpnZ3Bsb3QoZGF0YSA9IG1wZykgKwogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gZGlzcGwsIHkgPSBod3kpKQoKZmlsdGVyKG1wZywgY3lsID09IDgpCgpmaWx0ZXIoZGlhbW9uZHMsIGNhcmF0ID4gMykKClRoZSBlcnJvcnMgaW5jbHVkZWQgYSBtaXNzcGVsbGVkIGFyZ3VtZW50IG5hbWUgKGRvdGEgaW5zdGVhZCBvZiBkYXRhKSwgdXNpbmcgPSBpbnN0ZWFkIG9mID09IGZvciBjb21wYXJpc29uLCBhbmQgcmVmZXJlbmNlIHRoZSBkYXRhc2V0IGRpYW1vbmQgaW5zdGVhZCBvZiBkaWFtb25kcy4KCjMuIFByZXNzaW5nIEFsdCArIFNoaWZ0ICsgSyBpbiBSU3R1ZGlvIG9wZW5zIHRoZSBrZXlib2FyZCBzaG9ydGN1dHMgaGVscCBtZW51LiBUaGlzIG1lbnUgcHJvdmlkZXMgYSBsaXN0IG9mIHVzZWZ1bCBzaG9ydGN1dHMgdG8gaW1wcm92ZSBlZmZpY2llbmN5IHdoZW4gY29kaW5nLiBUaGUgc2FtZSBtZW51IGNhbiBiZSBhY2Nlc3NlZCBieSBuYXZpZ2F0aW5nIHRvIEhlbHAg4oaSIEtleWJvYXJkIFNob3J0Y3V0cyBIZWxwIGluIHRoZSBSU3R1ZGlvIHRvb2xiYXIuCgpgYGB7cn0KCmxpYnJhcnkodGlkeXZlcnNlKQoKZ2dwbG90KGRhdGEgPSBtcGcpICsKICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5KSkKCmZpbHRlcihtcGcsIGN5bCA9PSA4KQoKZmlsdGVyKGRpYW1vbmRzLCBjYXJhdCA+IDMpCgpgYGAKCg==