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
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.
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
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.
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.
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.
## <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
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”)
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.
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.
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.
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
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.
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.
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.
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
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.
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.
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.
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
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.
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.
- 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))

## # 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==