Exercises 7.5.1.1
1. Cancelled vs Non-Cancelled Flight Departure Times
flights2 <- flights %>%
mutate(
cancelled = is.na(dep_time),
sched_hour = sched_dep_time %/% 100,
sched_min = sched_dep_time %/% 100,
sched_time = sched_hour + sched_min / 60
)
p1 <- ggplot(flights2, aes(x = cancelled, y = sched_time)) +
geom_boxplot() +
labs(
title = "Scheduled Departure Time by Cancellation Status",
x = "Cancelled",
y = "Scheduled Time (Hours)"
)
p1

ggsave("exercise-7-5-1-1.png", plot = p1, width = 8, height = 5)
Answer:
A boxplot is a better way to compare cancelled and non-cancelled flights
because it clearly shows the center and spread of scheduled departure
times. Cancelled flights appear more common later in the day, which
suggests delays and operational issues build up as the day goes on.
2. Most Important Predictor of Diamond Price
p2 <- ggplot(diamonds, aes(x = carat, y = price)) +
geom_point(alpha = 0.1) +
labs(
title = "Price vs Carat",
x = "Carat",
y = "Price"
)
p2

ggsave("exercise-7-5-1-2.png", plot = p2, width = 8, height = 5)
p2b <- ggplot(diamonds, aes(x = cut, y = carat)) +
geom_boxplot() +
labs(
title = "Carat by Cut",
x = "Cut",
y = "Carat"
)
p2b

ggsave("exercise-7-5-1-2b.png", plot = p2b, width = 8, height = 5)
Answer:
The most important variable for predicting the price of a diamond is
carat. The scatterplot shows a strong positive
relationship between carat and price, meaning larger diamonds tend to
cost more.
Carat is related to cut because diamonds with lower cut quality tend
to have larger carat values on average. This helps explain why lower
quality diamonds can sometimes appear more expensive overall: the effect
of larger size on price is stronger than the effect of cut quality
alone.
3. Horizontal Boxplots using ggstance
##
## Attaching package: 'ggstance'
## The following objects are masked from 'package:ggplot2':
##
## geom_errorbarh, GeomErrorbarh
p3 <- ggplot(mpg, aes(y = class, x = hwy, group = class)) +
geom_boxploth() +
labs(
title = "Highway MPG by Vehicle Class",
x = "Highway MPG",
y = "Class"
)
p3
## Warning: The following aesthetics were dropped during statistical transformation: x.
## ℹ This can happen when ggplot fails to infer the correct grouping structure in
## the data.
## ℹ Did you forget to specify a `group` aesthetic or to convert a numerical
## variable into a factor?
## Warning: Using the `size` aesthetic with geom_segment was deprecated in ggplot2 3.4.0.
## ℹ Please use the `linewidth` aesthetic instead.
## This warning is displayed once per session.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
## Warning: Using the `size` aesthetic with geom_polygon was deprecated in ggplot2 3.4.0.
## ℹ Please use the `linewidth` aesthetic instead.
## This warning is displayed once per session.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.

ggsave("exercise-7-5-1-3.png", plot = p3, width = 8, height = 5)
## Warning: The following aesthetics were dropped during statistical transformation: x.
## ℹ This can happen when ggplot fails to infer the correct grouping structure in
## the data.
## ℹ Did you forget to specify a `group` aesthetic or to convert a numerical
## variable into a factor?
p3_flip <- ggplot(mpg, aes(x = class, y = hwy)) +
geom_boxplot() +
coord_flip() +
labs(
title = "Highway MPG by Vehicle Class (Using coord_flip)",
x = "Class",
y = "Highway MPG"
)
p3_flip

ggsave("exercise-7-5-1-3b.png", plot = p3_flip, width = 8, height = 5)
Answer: The ggstance package creates a
horizontal boxplot directly using geom_boxploth(), while
coord_flip() starts with a regular vertical boxplot and
then flips the axes. The two plots look very similar, but
ggstance is more direct because it is designed specifically
for horizontal geoms. In contrast, coord_flip() is a
convenient way to rotate an existing plot without changing the
underlying geom.
4. Letter Value Plot (geom_lv)
##
## Attaching package: 'lvplot'
## The following object is masked from 'package:openintro':
##
## census
p4 <- ggplot(diamonds, aes(x = cut, y = price)) +
geom_lv() +
labs(
title = "Diamond Price by Cut (Letter Value Plot)",
x = "Cut",
y = "Price"
)
p4

ggsave("exercise-7-5-1-4.png", plot = p4, width = 8, height = 5)
Answer:
The letter-value plot shows the distribution of diamond prices across
cut categories using more quantiles than a standard boxplot. This makes
it especially useful for large datasets like diamonds,
where a regular boxplot can display too many outliers and become
cluttered.
The plot suggests that diamond prices vary widely within each cut
category. It also shows that lower cut categories can still have higher
prices, likely because larger diamonds tend to have lower cut grades,
and carat has a strong influence on price. I interpret the letter-value
plot as a more detailed version of a boxplot that better represents the
shape and spread of large datasets. ``
5. Comparing Visualization Methods
p5_violin <- ggplot(diamonds, aes(x = cut, y = price)) +
geom_violin() +
labs(
title = "Diamond Price by Cut (Violin Plot)",
x = "Cut",
y = "Price"
)
p5_violin

ggsave("exercise-7-5-1-5a.png", plot = p5_violin, width = 8, height = 5)
p5_hist <- ggplot(diamonds, aes(x = price)) +
geom_histogram(binwidth = 500) +
facet_wrap(~cut) +
labs(
title = "Diamond Price by Cut (Faceted Histogram)",
x = "Price",
y = "Count"
)
p5_hist

ggsave("exercise-7-5-1-5b.png", plot = p5_hist, width = 8, height = 5)
p5_freq <- ggplot(diamonds, aes(x = price, color = cut)) +
geom_freqpoly(binwidth = 500) +
labs(
title = "Diamond Price by Cut (Frequency Polygon)",
x = "Price",
y = "Count",
color = "Cut"
)
p5_freq

ggsave("exercise-7-5-1-5c.png", plot = p5_freq, width = 8, height = 5)
Answer: geom_violin() is useful because
it shows the overall shape and density of the distribution for each
group in a compact way. It is especially helpful for comparing how
spread out values are across categories. However, because it uses
smoothing, it may hide some of the finer details of the raw
distribution.
A faceted geom_histogram() is easier to interpret
because it shows the actual distribution of values within each category.
It makes it easier to see peaks, skewness, and gaps in the data. The
downside is that it takes up more space and can be harder to compare
groups directly across separate panels.
A colored geom_freqpoly() is good for comparing multiple
groups on the same axes. It allows direct comparison of trends across
categories without using separate panels. However, the lines can overlap
and become cluttered, especially when there are many groups or large
differences in counts.
Violin plots are compact and show shape well, faceted histograms are
the most detailed and easiest to interpret, and frequency polygons are
useful for comparison but can become visually messy.
6. Jitter Alternatives with ggbeeswarm
p6 <- ggplot(mpg, aes(x = class, y = hwy)) +
geom_beeswarm() +
labs(
title = "Highway MPG by Vehicle Class (Beeswarm Plot)",
x = "Class",
y = "Highway MPG"
)
p6

ggsave("exercise-7-5-1-6.png", plot = p6, width = 8, height = 5)
Answer:
The ggbeeswarm package provides several methods similar to
geom_jitter() that help reduce overplotting while still
showing individual observations.
geom_beeswarm() arranges points to avoid overlap by
spreading them out in a controlled way, making the distribution easier
to see.
geom_quasirandom() adds small offsets to points using a
quasirandom approach, so the points are spread out but still reflect the
shape of the distribution.
geom_sina() spreads points based on local density, so
wider sections of the plot represent areas with more observations.
Compared with geom_jitter(), these methods do a better
job of preserving the structure of the data while still preventing
points from overlapping.
Exercises 7.5.2.1
1. Rescaling Counts to Proportions
cut_color <- diamonds %>%
count(color, cut)
cut_color
## # A tibble: 35 × 3
## color cut n
## <ord> <ord> <int>
## 1 D Fair 163
## 2 D Good 662
## 3 D Very Good 1513
## 4 D Premium 1603
## 5 D Ideal 2834
## 6 E Fair 224
## 7 E Good 933
## 8 E Very Good 2400
## 9 E Premium 2337
## 10 E Ideal 3903
## # ℹ 25 more rows
cut_within_color <- cut_color %>%
group_by(color) %>%
mutate(prop = n / sum(n))
cut_within_color
## # A tibble: 35 × 4
## # Groups: color [7]
## color cut n prop
## <ord> <ord> <int> <dbl>
## 1 D Fair 163 0.0241
## 2 D Good 662 0.0977
## 3 D Very Good 1513 0.223
## 4 D Premium 1603 0.237
## 5 D Ideal 2834 0.418
## 6 E Fair 224 0.0229
## 7 E Good 933 0.0952
## 8 E Very Good 2400 0.245
## 9 E Premium 2337 0.239
## 10 E Ideal 3903 0.398
## # ℹ 25 more rows
p721_1a <- ggplot(cut_within_color, aes(x = color, y = cut, fill = prop)) +
geom_tile() +
labs(
title = "Distribution of Cut Within Color",
x = "Color",
y = "Cut",
fill = "Proportion"
)
p721_1a

ggsave("exercise-7-5-2-1-1a.png", plot = p721_1a, width = 8, height = 5)
color_within_cut <- cut_color %>%
group_by(cut) %>%
mutate(prop = n / sum(n))
color_within_cut
## # A tibble: 35 × 4
## # Groups: cut [5]
## color cut n prop
## <ord> <ord> <int> <dbl>
## 1 D Fair 163 0.101
## 2 D Good 662 0.135
## 3 D Very Good 1513 0.125
## 4 D Premium 1603 0.116
## 5 D Ideal 2834 0.132
## 6 E Fair 224 0.139
## 7 E Good 933 0.190
## 8 E Very Good 2400 0.199
## 9 E Premium 2337 0.169
## 10 E Ideal 3903 0.181
## # ℹ 25 more rows
p721_1b <- ggplot(color_within_cut, aes(x = color, y = cut, fill = prop)) +
geom_tile() +
labs(
title = "Distribution of Color Within Cut",
x = "Color",
y = "Cut",
fill = "Proportion"
)
p721_1b

ggsave("exercise-7-5-2-1-1b.png", plot = p721_1b, width = 8, height = 5)
Answer:
The count dataset can be rescaled by converting raw counts into
proportions within each group. To show the distribution of cut within
colour, each count should be divided by the total count for that colour.
To show the distribution of colour within cut, each count should be
divided by the total count for that cut. This makes the patterns easier
to compare because the values are standardized instead of being driven
by group size.
2. Average Flight Delays by Detination and Month
delay_by_dest_month <- flights %>%
mutate(total_delay = dep_delay + arr_delay) %>%
filter(!is.na(total_delay)) %>%
group_by(month, dest) %>%
summarise(avg_delay = mean(total_delay), .groups = "drop")
delay_by_dest_month
## # A tibble: 1,112 × 3
## month dest avg_delay
## <int> <chr> <dbl>
## 1 1 ALB 76.6
## 2 1 ATL 8.57
## 3 1 AUS 19.0
## 4 1 AVL 49
## 5 1 BDL 32.1
## 6 1 BHM 47.0
## 7 1 BNA 25.9
## 8 1 BOS 2.70
## 9 1 BQN 8.52
## 10 1 BTV 18.4
## # ℹ 1,102 more rows
p721_2 <- ggplot(delay_by_dest_month, aes(x = month, y = dest, fill = avg_delay)) +
geom_tile() +
labs(
title = "Average Flight Delay by Destination and Month",
x = "Month",
y = "Destination",
fill = "Average Delay"
)
p721_2

ggsave("exercise-7-5-2-1-2.png", plot = p721_2, width = 8, height = 8)
delay_by_dest_month2 <- delay_by_dest_month %>%
group_by(dest) %>%
mutate(overall_avg = mean(avg_delay)) %>%
ungroup()
p721_2_improved <- ggplot(
delay_by_dest_month2,
aes(x = month, y = reorder(dest, overall_avg), fill = avg_delay)
) +
geom_tile() +
labs(
title = "Average Flight Delay by Destination and Month (Reordered)",
x = "Month",
y = "Destination",
fill = "Average Delay"
)
p721_2_improved

ggsave("exercise-7-5-2-1-2-improved.png", plot = p721_2_improved, width = 8, height = 8)
Answer:
The tile plot shows how average flight delays vary by destination and
month, but it is difficult to read because there are many destinations
and the y-axis becomes crowded. The large number of destination labels
makes it hard to compare patterns clearly. The plot can be improved by
reordering destinations, filtering to only a subset of destinations, or
using faceting or a different visualization that reduces clutter. A
reordered heatmap makes the overall pattern easier to interpret.
3. Axis Choice in Tile Plots
Answer:
It is slightly better to use aes(x = color, y = cut)
because color has more categories than cut,
and placing the variable with more levels on the x-axis generally makes
the plot easier to read. The x-axis labels are often easier to scan,
while the y-axis works well for the variable with fewer levels. Since
cut has fewer categories, putting it on the y-axis creates
a cleaner and more balanced display
Exercises 7.5.3.1
1. cut_width vs cut_number
diamonds_width <- diamonds %>%
mutate(price_group = cut_width(price, width = 5000))
p731_1a <- ggplot(diamonds_width, aes(x = carat, color = price_group)) +
geom_freqpoly(binwidth = 0.1) +
labs(
title = "Carat Distribution by Price Group (cut_width)",
x = "Carat",
y = "Count",
color = "Price Group"
)
p731_1a

ggsave("exercise-7-5-3-1-1a.png", plot = p731_1a, width = 8, height = 5)
diamonds_number <- diamonds %>%
mutate(price_group = cut_number(price, n = 6))
p731_1b <- ggplot(diamonds_number, aes(x = carat, color = price_group)) +
geom_freqpoly(binwidth = 0.1) +
labs(
title = "Carat Distribution by Price Group (cut_number)",
x = "Carat",
y = "Count",
color = "Price Group"
)
p731_1b

ggsave("exercise-7-5-3-1-1b.png", plot = p731_1b, width = 8, height = 5)
Answer:
When using a frequency polygon to summarize the conditional
distribution, it is important to think about how the continuous variable
is being grouped. cut_width() creates bins with equal
numeric width, while cut_number() creates bins with roughly
equal numbers of observations.
With cut_width(), the groups are easier to interpret
because each bin represents the same range of price values, but some
groups may contain very different numbers of diamonds. With
cut_number(), the group sizes are more balanced, which can
make the comparison of distributions easier, but the price ranges are no
longer equally spaced.
This affects a visualization of the 2d distribution of
carat and price because the apparent patterns
can change depending on how the groups are formed. Equal-width bins
emphasize the actual scale of price, while equal-count bins emphasize
comparability between groups.
2. Carat Distribution by Price
diamonds_price_groups <- diamonds %>%
mutate(price_group = cut_number(price, n = 6))
p731_2 <- ggplot(diamonds_price_groups, aes(x = carat, color = price_group)) +
geom_freqpoly(binwidth = 0.1) +
labs(
title = "Distribution of Carat Partitioned by Price",
x = "Carat",
y = "Count",
color = "Price Group"
)
p731_2

ggsave("exercise-7-5-3-1-2.png", plot = p731_2, width = 8, height = 5)
Answer:
The frequency polygon shows that higher price groups tend to be
associated with larger carat values. Lower price groups are concentrated
at smaller carat sizes, while higher price groups shift to the right.
This suggests a strong positive relationship between carat and
price.
3. Price Comparison by Diamond Size
diamonds_size_compare <- diamonds %>%
mutate(size_group = case_when(
carat < 1 ~ "Small (<1 carat)",
carat >= 2.5 ~ "Very large (>=2.5 carats)",
TRUE ~ NA_character_
)) %>%
filter(!is.na(size_group))
p731_3 <- ggplot(diamonds_size_compare, aes(x = price, y = after_stat(density), color = size_group)) +
geom_freqpoly(binwidth = 500) +
labs(
title = "Price Distribution: Small vs Very Large Diamonds",
x = "Price",
y = "Density",
color = "Size Group"
)
p731_3

ggsave("exercise-7-5-3-1-3.png", plot = p731_3, width = 8, height = 5)
Answer: Very large diamonds have a price
distribution that is shifted much farther to the right than small
diamonds, meaning they are generally much more expensive. This is what I
would expect, since larger diamonds are rarer and carat has a strong
positive relationship with price. Using density instead of count makes
the comparison clearer because it shows the shape of the price
distributions without letting the much larger number of small diamonds
dominate the graph.
4. Combined Visualization of Cut, Carat, and Price
diamonds_carat_groups <- diamonds %>%
filter(carat > 0, carat <= 3) %>%
mutate(carat_group = cut_width(carat, width = 0.5))
p731_4 <- ggplot(diamonds_carat_groups, aes(x = cut, y = price)) +
geom_boxplot() +
facet_wrap(~carat_group) +
labs(
title = "Price by Cut, Faceted by Carat Group",
x = "Cut",
y = "Price"
)
p731_4

ggsave("exercise-7-5-3-1-4.png", plot = p731_4, width = 12, height = 8)
Answer:
This plot combines boxplots and faceting to show the joint distribution
of cut, carat, and price. The boxplots compare price across cut
categories, while the facets separate diamonds into carat groups. This
makes it easier to see how price varies by cut when diamonds are grouped
into similar carat ranges. The plot also shows that price generally
increases as carat increases. Overall, carat appears to have a strong
effect on price, and the influence of cut becomes easier to interpret
when diamonds are compared within similar carat ranges.
5. Why Scatterplots Reveal 2D Outliers
p731_5 <- ggplot(diamonds, aes(x = x, y = y)) +
geom_point() +
coord_cartesian(xlim = c(4, 11), ylim = c(4, 11)) +
labs(
title = "Scatterplot of Diamond x and y Dimensions",
x = "x",
y = "y"
)
p731_5

ggsave("exercise-7-5-3-1-5.png", plot = p731_5, width = 8, height = 5)
Answer: A scatterplot is a better display in this
case because it shows each observation individually and makes unusual
combinations of x and y easier to detect. Some
diamonds have x and y values that look normal
when examined separately, but together they do not follow the main
pattern of the data. A binned plot would group nearby observations into
tiles or bins, which could smooth over those unusual points and make
them harder to identify. Because the goal is to find outliers in the
two-dimensional relationship, the scatterplot is more informative. ``
…
LS0tCnRpdGxlOiAiV2VlayA0IEhvbWV3b3JrIC0gQ2hhcHRlciA3IEV4ZXJjaXNlcyIKYXV0aG9yOiAiQ2FpdGxpbiBLZW5uZWR5IgpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDogb3BlbmludHJvOjpsYWJfcmVwb3J0Ci0tLQoKYGBge3IgbG9hZC1wYWNrYWdlcywgbWVzc2FnZT1GQUxTRX0KbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkob3BlbmludHJvKQpsaWJyYXJ5KG55Y2ZsaWdodHMxMykKYGBgCgojIyBFeGVyY2lzZXMgNy41LjEuMQoKIyMjIDEuIENhbmNlbGxlZCB2cyBOb24tQ2FuY2VsbGVkIEZsaWdodCBEZXBhcnR1cmUgVGltZXMKCmBgYHtyfQpmbGlnaHRzMiA8LSBmbGlnaHRzICU+JQogIG11dGF0ZSgKICAgIGNhbmNlbGxlZCA9IGlzLm5hKGRlcF90aW1lKSwKICAgIHNjaGVkX2hvdXIgPSBzY2hlZF9kZXBfdGltZSAlLyUgMTAwLAogICAgc2NoZWRfbWluID0gc2NoZWRfZGVwX3RpbWUgJS8lIDEwMCwKICAgIHNjaGVkX3RpbWUgPSBzY2hlZF9ob3VyICsgc2NoZWRfbWluIC8gNjAKICApCgpwMSA8LSBnZ3Bsb3QoZmxpZ2h0czIsIGFlcyh4ID0gY2FuY2VsbGVkLCB5ID0gc2NoZWRfdGltZSkpICsKICBnZW9tX2JveHBsb3QoKSArCiAgbGFicygKICAgIHRpdGxlID0gIlNjaGVkdWxlZCBEZXBhcnR1cmUgVGltZSBieSBDYW5jZWxsYXRpb24gU3RhdHVzIiwKICAgIHggPSAiQ2FuY2VsbGVkIiwKICAgIHkgPSAiU2NoZWR1bGVkIFRpbWUgKEhvdXJzKSIKICApCgpwMQpgYGAKCmBgYHtyfQpnZ3NhdmUoImV4ZXJjaXNlLTctNS0xLTEucG5nIiwgcGxvdCA9IHAxLCB3aWR0aCA9IDgsIGhlaWdodCA9IDUpCmBgYAoKKipBbnN3ZXI6KiogIApBIGJveHBsb3QgaXMgYSBiZXR0ZXIgd2F5IHRvIGNvbXBhcmUgY2FuY2VsbGVkIGFuZCBub24tY2FuY2VsbGVkIGZsaWdodHMgYmVjYXVzZSBpdCBjbGVhcmx5IHNob3dzIHRoZSBjZW50ZXIgYW5kIHNwcmVhZCBvZiBzY2hlZHVsZWQgZGVwYXJ0dXJlIHRpbWVzLiBDYW5jZWxsZWQgZmxpZ2h0cyBhcHBlYXIgbW9yZSBjb21tb24gbGF0ZXIgaW4gdGhlIGRheSwgd2hpY2ggc3VnZ2VzdHMgZGVsYXlzIGFuZCBvcGVyYXRpb25hbCBpc3N1ZXMgYnVpbGQgdXAgYXMgdGhlIGRheSBnb2VzIG9uLgoKIyMjIDIuIE1vc3QgSW1wb3J0YW50IFByZWRpY3RvciBvZiBEaWFtb25kIFByaWNlCgpgYGB7cn0KcDIgPC0gZ2dwbG90KGRpYW1vbmRzLCBhZXMoeCA9IGNhcmF0LCB5ID0gcHJpY2UpKSArCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuMSkgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJQcmljZSB2cyBDYXJhdCIsCiAgICB4ID0gIkNhcmF0IiwKICAgIHkgPSAiUHJpY2UiCiAgKQoKcDIKYGBgCgpgYGB7cn0KZ2dzYXZlKCJleGVyY2lzZS03LTUtMS0yLnBuZyIsIHBsb3QgPSBwMiwgd2lkdGggPSA4LCBoZWlnaHQgPSA1KQpgYGAKCmBgYHtyfQpwMmIgPC0gZ2dwbG90KGRpYW1vbmRzLCBhZXMoeCA9IGN1dCwgeSA9IGNhcmF0KSkgKwogIGdlb21fYm94cGxvdCgpICsKICBsYWJzKAogICAgdGl0bGUgPSAiQ2FyYXQgYnkgQ3V0IiwKICAgIHggPSAiQ3V0IiwKICAgIHkgPSAiQ2FyYXQiCiAgKQoKcDJiCmBgYAoKYGBge3J9Cmdnc2F2ZSgiZXhlcmNpc2UtNy01LTEtMmIucG5nIiwgcGxvdCA9IHAyYiwgd2lkdGggPSA4LCBoZWlnaHQgPSA1KQpgYGAKCioqQW5zd2VyOioqICAKVGhlIG1vc3QgaW1wb3J0YW50IHZhcmlhYmxlIGZvciBwcmVkaWN0aW5nIHRoZSBwcmljZSBvZiBhIGRpYW1vbmQgaXMgKipjYXJhdCoqLiBUaGUgc2NhdHRlcnBsb3Qgc2hvd3MgYSBzdHJvbmcgcG9zaXRpdmUgcmVsYXRpb25zaGlwIGJldHdlZW4gY2FyYXQgYW5kIHByaWNlLCBtZWFuaW5nIGxhcmdlciBkaWFtb25kcyB0ZW5kIHRvIGNvc3QgbW9yZS4KCkNhcmF0IGlzIHJlbGF0ZWQgdG8gY3V0IGJlY2F1c2UgZGlhbW9uZHMgd2l0aCBsb3dlciBjdXQgcXVhbGl0eSB0ZW5kIHRvIGhhdmUgbGFyZ2VyIGNhcmF0IHZhbHVlcyBvbiBhdmVyYWdlLiBUaGlzIGhlbHBzIGV4cGxhaW4gd2h5IGxvd2VyIHF1YWxpdHkgZGlhbW9uZHMgY2FuIHNvbWV0aW1lcyBhcHBlYXIgbW9yZSBleHBlbnNpdmUgb3ZlcmFsbDogdGhlIGVmZmVjdCBvZiBsYXJnZXIgc2l6ZSBvbiBwcmljZSBpcyBzdHJvbmdlciB0aGFuIHRoZSBlZmZlY3Qgb2YgY3V0IHF1YWxpdHkgYWxvbmUuCgojIyMgMy4gSG9yaXpvbnRhbCBCb3hwbG90cyB1c2luZyBnZ3N0YW5jZQoKYGBge3J9CmxpYnJhcnkoZ2dzdGFuY2UpCmBgYAoKYGBge3J9CnAzIDwtIGdncGxvdChtcGcsIGFlcyh5ID0gY2xhc3MsIHggPSBod3ksIGdyb3VwID0gY2xhc3MpKSArCiAgZ2VvbV9ib3hwbG90aCgpICsKICBsYWJzKAogICAgdGl0bGUgPSAiSGlnaHdheSBNUEcgYnkgVmVoaWNsZSBDbGFzcyIsCiAgICB4ID0gIkhpZ2h3YXkgTVBHIiwKICAgIHkgPSAiQ2xhc3MiCiAgKQoKcDMKYGBgCgpgYGB7cn0KZ2dzYXZlKCJleGVyY2lzZS03LTUtMS0zLnBuZyIsIHBsb3QgPSBwMywgd2lkdGggPSA4LCBoZWlnaHQgPSA1KQpgYGAKCmBgYHtyfQpwM19mbGlwIDwtIGdncGxvdChtcGcsIGFlcyh4ID0gY2xhc3MsIHkgPSBod3kpKSArCiAgZ2VvbV9ib3hwbG90KCkgKwogIGNvb3JkX2ZsaXAoKSArCiAgbGFicygKICAgIHRpdGxlID0gIkhpZ2h3YXkgTVBHIGJ5IFZlaGljbGUgQ2xhc3MgKFVzaW5nIGNvb3JkX2ZsaXApIiwKICAgIHggPSAiQ2xhc3MiLAogICAgeSA9ICJIaWdod2F5IE1QRyIKICApCgpwM19mbGlwCmBgYAoKYGBge3J9Cmdnc2F2ZSgiZXhlcmNpc2UtNy01LTEtM2IucG5nIiwgcGxvdCA9IHAzX2ZsaXAsIHdpZHRoID0gOCwgaGVpZ2h0ID0gNSkKYGBgCgoqKkFuc3dlcjoqKgpUaGUgYGdnc3RhbmNlYCBwYWNrYWdlIGNyZWF0ZXMgYSBob3Jpem9udGFsIGJveHBsb3QgZGlyZWN0bHkgdXNpbmcgYGdlb21fYm94cGxvdGgoKWAsIHdoaWxlIGBjb29yZF9mbGlwKClgIHN0YXJ0cyB3aXRoIGEgcmVndWxhciB2ZXJ0aWNhbCBib3hwbG90IGFuZCB0aGVuIGZsaXBzIHRoZSBheGVzLiBUaGUgdHdvIHBsb3RzIGxvb2sgdmVyeSBzaW1pbGFyLCBidXQgYGdnc3RhbmNlYCBpcyBtb3JlIGRpcmVjdCBiZWNhdXNlIGl0IGlzIGRlc2lnbmVkIHNwZWNpZmljYWxseSBmb3IgaG9yaXpvbnRhbCBnZW9tcy4gSW4gY29udHJhc3QsIGBjb29yZF9mbGlwKClgIGlzIGEgY29udmVuaWVudCB3YXkgdG8gcm90YXRlIGFuIGV4aXN0aW5nIHBsb3Qgd2l0aG91dCBjaGFuZ2luZyB0aGUgdW5kZXJseWluZyBnZW9tLgoKIyMjIDQuIExldHRlciBWYWx1ZSBQbG90IChnZW9tX2x2KQoKYGBge3J9CmxpYnJhcnkobHZwbG90KQpgYGAKCmBgYHtyfQoKcDQgPC0gZ2dwbG90KGRpYW1vbmRzLCBhZXMoeCA9IGN1dCwgeSA9IHByaWNlKSkgKwogIGdlb21fbHYoKSArCiAgbGFicygKICAgIHRpdGxlID0gIkRpYW1vbmQgUHJpY2UgYnkgQ3V0IChMZXR0ZXIgVmFsdWUgUGxvdCkiLAogICAgeCA9ICJDdXQiLAogICAgeSA9ICJQcmljZSIKICApCgpwNApgYGAKCmBgYHtyfQpnZ3NhdmUoImV4ZXJjaXNlLTctNS0xLTQucG5nIiwgcGxvdCA9IHA0LCB3aWR0aCA9IDgsIGhlaWdodCA9IDUpCmBgYAoKCioqQW5zd2VyOioqICAKVGhlIGxldHRlci12YWx1ZSBwbG90IHNob3dzIHRoZSBkaXN0cmlidXRpb24gb2YgZGlhbW9uZCBwcmljZXMgYWNyb3NzIGN1dCBjYXRlZ29yaWVzIHVzaW5nIG1vcmUgcXVhbnRpbGVzIHRoYW4gYSBzdGFuZGFyZCBib3hwbG90LiBUaGlzIG1ha2VzIGl0IGVzcGVjaWFsbHkgdXNlZnVsIGZvciBsYXJnZSBkYXRhc2V0cyBsaWtlIGBkaWFtb25kc2AsIHdoZXJlIGEgcmVndWxhciBib3hwbG90IGNhbiBkaXNwbGF5IHRvbyBtYW55IG91dGxpZXJzIGFuZCBiZWNvbWUgY2x1dHRlcmVkLgoKVGhlIHBsb3Qgc3VnZ2VzdHMgdGhhdCBkaWFtb25kIHByaWNlcyB2YXJ5IHdpZGVseSB3aXRoaW4gZWFjaCBjdXQgY2F0ZWdvcnkuIEl0IGFsc28gc2hvd3MgdGhhdCBsb3dlciBjdXQgY2F0ZWdvcmllcyBjYW4gc3RpbGwgaGF2ZSBoaWdoZXIgcHJpY2VzLCBsaWtlbHkgYmVjYXVzZSBsYXJnZXIgZGlhbW9uZHMgdGVuZCB0byBoYXZlIGxvd2VyIGN1dCBncmFkZXMsIGFuZCBjYXJhdCBoYXMgYSBzdHJvbmcgaW5mbHVlbmNlIG9uIHByaWNlLiBJIGludGVycHJldCB0aGUgbGV0dGVyLXZhbHVlIHBsb3QgYXMgYSBtb3JlIGRldGFpbGVkIHZlcnNpb24gb2YgYSBib3hwbG90IHRoYXQgYmV0dGVyIHJlcHJlc2VudHMgdGhlIHNoYXBlIGFuZCBzcHJlYWQgb2YgbGFyZ2UgZGF0YXNldHMuCmBgCgojIyMgNS4gQ29tcGFyaW5nIFZpc3VhbGl6YXRpb24gTWV0aG9kcwoKYGBge3J9CnA1X3Zpb2xpbiA8LSBnZ3Bsb3QoZGlhbW9uZHMsIGFlcyh4ID0gY3V0LCB5ID0gcHJpY2UpKSArCiAgZ2VvbV92aW9saW4oKSArCiAgbGFicygKICAgIHRpdGxlID0gIkRpYW1vbmQgUHJpY2UgYnkgQ3V0IChWaW9saW4gUGxvdCkiLAogICAgeCA9ICJDdXQiLAogICAgeSA9ICJQcmljZSIKICApCgpwNV92aW9saW4KYGBgCgpgYGB7cn0KZ2dzYXZlKCJleGVyY2lzZS03LTUtMS01YS5wbmciLCBwbG90ID0gcDVfdmlvbGluLCB3aWR0aCA9IDgsIGhlaWdodCA9IDUpCmBgYAoKYGBge3J9CnA1X2hpc3QgPC0gZ2dwbG90KGRpYW1vbmRzLCBhZXMoeCA9IHByaWNlKSkgKwogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gNTAwKSArCiAgZmFjZXRfd3JhcCh+Y3V0KSArCiAgbGFicygKICAgIHRpdGxlID0gIkRpYW1vbmQgUHJpY2UgYnkgQ3V0IChGYWNldGVkIEhpc3RvZ3JhbSkiLAogICAgeCA9ICJQcmljZSIsCiAgICB5ID0gIkNvdW50IgogICkKCnA1X2hpc3QKYGBgCgpgYGB7cn0KZ2dzYXZlKCJleGVyY2lzZS03LTUtMS01Yi5wbmciLCBwbG90ID0gcDVfaGlzdCwgd2lkdGggPSA4LCBoZWlnaHQgPSA1KQpgYGAKCmBgYHtyfQpwNV9mcmVxIDwtIGdncGxvdChkaWFtb25kcywgYWVzKHggPSBwcmljZSwgY29sb3IgPSBjdXQpKSArCiAgZ2VvbV9mcmVxcG9seShiaW53aWR0aCA9IDUwMCkgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJEaWFtb25kIFByaWNlIGJ5IEN1dCAoRnJlcXVlbmN5IFBvbHlnb24pIiwKICAgIHggPSAiUHJpY2UiLAogICAgeSA9ICJDb3VudCIsCiAgICBjb2xvciA9ICJDdXQiCiAgKQoKcDVfZnJlcQpgYGAKCmBgYHtyfQpnZ3NhdmUoImV4ZXJjaXNlLTctNS0xLTVjLnBuZyIsIHBsb3QgPSBwNV9mcmVxLCB3aWR0aCA9IDgsIGhlaWdodCA9IDUpCmBgYAoKKipBbnN3ZXI6KioKYGdlb21fdmlvbGluKClgIGlzIHVzZWZ1bCBiZWNhdXNlIGl0IHNob3dzIHRoZSBvdmVyYWxsIHNoYXBlIGFuZCBkZW5zaXR5IG9mIHRoZSBkaXN0cmlidXRpb24gZm9yIGVhY2ggZ3JvdXAgaW4gYSBjb21wYWN0IHdheS4gSXQgaXMgZXNwZWNpYWxseSBoZWxwZnVsIGZvciBjb21wYXJpbmcgaG93IHNwcmVhZCBvdXQgdmFsdWVzIGFyZSBhY3Jvc3MgY2F0ZWdvcmllcy4gSG93ZXZlciwgYmVjYXVzZSBpdCB1c2VzIHNtb290aGluZywgaXQgbWF5IGhpZGUgc29tZSBvZiB0aGUgZmluZXIgZGV0YWlscyBvZiB0aGUgcmF3IGRpc3RyaWJ1dGlvbi4KCkEgZmFjZXRlZCBgZ2VvbV9oaXN0b2dyYW0oKWAgaXMgZWFzaWVyIHRvIGludGVycHJldCBiZWNhdXNlIGl0IHNob3dzIHRoZSBhY3R1YWwgZGlzdHJpYnV0aW9uIG9mIHZhbHVlcyB3aXRoaW4gZWFjaCBjYXRlZ29yeS4gSXQgbWFrZXMgaXQgZWFzaWVyIHRvIHNlZSBwZWFrcywgc2tld25lc3MsIGFuZCBnYXBzIGluIHRoZSBkYXRhLiBUaGUgZG93bnNpZGUgaXMgdGhhdCBpdCB0YWtlcyB1cCBtb3JlIHNwYWNlIGFuZCBjYW4gYmUgaGFyZGVyIHRvIGNvbXBhcmUgZ3JvdXBzIGRpcmVjdGx5IGFjcm9zcyBzZXBhcmF0ZSBwYW5lbHMuCgpBIGNvbG9yZWQgYGdlb21fZnJlcXBvbHkoKWAgaXMgZ29vZCBmb3IgY29tcGFyaW5nIG11bHRpcGxlIGdyb3VwcyBvbiB0aGUgc2FtZSBheGVzLiBJdCBhbGxvd3MgZGlyZWN0IGNvbXBhcmlzb24gb2YgdHJlbmRzIGFjcm9zcyBjYXRlZ29yaWVzIHdpdGhvdXQgdXNpbmcgc2VwYXJhdGUgcGFuZWxzLiBIb3dldmVyLCB0aGUgbGluZXMgY2FuIG92ZXJsYXAgYW5kIGJlY29tZSBjbHV0dGVyZWQsIGVzcGVjaWFsbHkgd2hlbiB0aGVyZSBhcmUgbWFueSBncm91cHMgb3IgbGFyZ2UgZGlmZmVyZW5jZXMgaW4gY291bnRzLgoKVmlvbGluIHBsb3RzIGFyZSBjb21wYWN0IGFuZCBzaG93IHNoYXBlIHdlbGwsIGZhY2V0ZWQgaGlzdG9ncmFtcyBhcmUgdGhlIG1vc3QgZGV0YWlsZWQgYW5kIGVhc2llc3QgdG8gaW50ZXJwcmV0LCBhbmQgZnJlcXVlbmN5IHBvbHlnb25zIGFyZSB1c2VmdWwgZm9yIGNvbXBhcmlzb24gYnV0IGNhbiBiZWNvbWUgdmlzdWFsbHkgbWVzc3kuCgojIyMgNi4gSml0dGVyIEFsdGVybmF0aXZlcyB3aXRoIGdnYmVlc3dhcm0KCmBgYHtyfQpsaWJyYXJ5KGdnYmVlc3dhcm0pCmBgYAoKYGBge3J9CgpwNiA8LSBnZ3Bsb3QobXBnLCBhZXMoeCA9IGNsYXNzLCB5ID0gaHd5KSkgKwogIGdlb21fYmVlc3dhcm0oKSArCiAgbGFicygKICAgIHRpdGxlID0gIkhpZ2h3YXkgTVBHIGJ5IFZlaGljbGUgQ2xhc3MgKEJlZXN3YXJtIFBsb3QpIiwKICAgIHggPSAiQ2xhc3MiLAogICAgeSA9ICJIaWdod2F5IE1QRyIKICApCgpwNgpgYGAKCmBgYHtyfQpnZ3NhdmUoImV4ZXJjaXNlLTctNS0xLTYucG5nIiwgcGxvdCA9IHA2LCB3aWR0aCA9IDgsIGhlaWdodCA9IDUpCmBgYAoKCioqQW5zd2VyOioqICAKVGhlIGBnZ2JlZXN3YXJtYCBwYWNrYWdlIHByb3ZpZGVzIHNldmVyYWwgbWV0aG9kcyBzaW1pbGFyIHRvIGBnZW9tX2ppdHRlcigpYCB0aGF0IGhlbHAgcmVkdWNlIG92ZXJwbG90dGluZyB3aGlsZSBzdGlsbCBzaG93aW5nIGluZGl2aWR1YWwgb2JzZXJ2YXRpb25zLgoKLSBgZ2VvbV9iZWVzd2FybSgpYCBhcnJhbmdlcyBwb2ludHMgdG8gYXZvaWQgb3ZlcmxhcCBieSBzcHJlYWRpbmcgdGhlbSBvdXQgaW4gYSBjb250cm9sbGVkIHdheSwgbWFraW5nIHRoZSBkaXN0cmlidXRpb24gZWFzaWVyIHRvIHNlZS4KLSBgZ2VvbV9xdWFzaXJhbmRvbSgpYCBhZGRzIHNtYWxsIG9mZnNldHMgdG8gcG9pbnRzIHVzaW5nIGEgcXVhc2lyYW5kb20gYXBwcm9hY2gsIHNvIHRoZSBwb2ludHMgYXJlIHNwcmVhZCBvdXQgYnV0IHN0aWxsIHJlZmxlY3QgdGhlIHNoYXBlIG9mIHRoZSBkaXN0cmlidXRpb24uCi0gYGdlb21fc2luYSgpYCBzcHJlYWRzIHBvaW50cyBiYXNlZCBvbiBsb2NhbCBkZW5zaXR5LCBzbyB3aWRlciBzZWN0aW9ucyBvZiB0aGUgcGxvdCByZXByZXNlbnQgYXJlYXMgd2l0aCBtb3JlIG9ic2VydmF0aW9ucy4KCkNvbXBhcmVkIHdpdGggYGdlb21faml0dGVyKClgLCB0aGVzZSBtZXRob2RzIGRvIGEgYmV0dGVyIGpvYiBvZiBwcmVzZXJ2aW5nIHRoZSBzdHJ1Y3R1cmUgb2YgdGhlIGRhdGEgd2hpbGUgc3RpbGwgcHJldmVudGluZyBwb2ludHMgZnJvbSBvdmVybGFwcGluZy4KCiMjIEV4ZXJjaXNlcyA3LjUuMi4xCgojIyMgMS4gUmVzY2FsaW5nIENvdW50cyB0byBQcm9wb3J0aW9ucwoKYGBge3J9CgpjdXRfY29sb3IgPC0gZGlhbW9uZHMgJT4lCiAgY291bnQoY29sb3IsIGN1dCkKCmN1dF9jb2xvcgpgYGAKCmBgYHtyfQpjdXRfd2l0aGluX2NvbG9yIDwtIGN1dF9jb2xvciAlPiUKICBncm91cF9ieShjb2xvcikgJT4lCiAgbXV0YXRlKHByb3AgPSBuIC8gc3VtKG4pKQoKY3V0X3dpdGhpbl9jb2xvcgpgYGAKCmBgYHtyfQpwNzIxXzFhIDwtIGdncGxvdChjdXRfd2l0aGluX2NvbG9yLCBhZXMoeCA9IGNvbG9yLCB5ID0gY3V0LCBmaWxsID0gcHJvcCkpICsKICBnZW9tX3RpbGUoKSArCiAgbGFicygKICAgIHRpdGxlID0gIkRpc3RyaWJ1dGlvbiBvZiBDdXQgV2l0aGluIENvbG9yIiwKICAgIHggPSAiQ29sb3IiLAogICAgeSA9ICJDdXQiLAogICAgZmlsbCA9ICJQcm9wb3J0aW9uIgogICkKCnA3MjFfMWEKYGBgCgpgYGB7cn0KZ2dzYXZlKCJleGVyY2lzZS03LTUtMi0xLTFhLnBuZyIsIHBsb3QgPSBwNzIxXzFhLCB3aWR0aCA9IDgsIGhlaWdodCA9IDUpCmBgYAoKYGBge3J9CmNvbG9yX3dpdGhpbl9jdXQgPC0gY3V0X2NvbG9yICU+JQogIGdyb3VwX2J5KGN1dCkgJT4lCiAgbXV0YXRlKHByb3AgPSBuIC8gc3VtKG4pKQoKY29sb3Jfd2l0aGluX2N1dApgYGAKCmBgYHtyfQpwNzIxXzFiIDwtIGdncGxvdChjb2xvcl93aXRoaW5fY3V0LCBhZXMoeCA9IGNvbG9yLCB5ID0gY3V0LCBmaWxsID0gcHJvcCkpICsKICBnZW9tX3RpbGUoKSArCiAgbGFicygKICAgIHRpdGxlID0gIkRpc3RyaWJ1dGlvbiBvZiBDb2xvciBXaXRoaW4gQ3V0IiwKICAgIHggPSAiQ29sb3IiLAogICAgeSA9ICJDdXQiLAogICAgZmlsbCA9ICJQcm9wb3J0aW9uIgogICkKCnA3MjFfMWIKYGBgCgpgYGB7cn0KZ2dzYXZlKCJleGVyY2lzZS03LTUtMi0xLTFiLnBuZyIsIHBsb3QgPSBwNzIxXzFiLCB3aWR0aCA9IDgsIGhlaWdodCA9IDUpCmBgYAoKKipBbnN3ZXI6KiogIApUaGUgY291bnQgZGF0YXNldCBjYW4gYmUgcmVzY2FsZWQgYnkgY29udmVydGluZyByYXcgY291bnRzIGludG8gcHJvcG9ydGlvbnMgd2l0aGluIGVhY2ggZ3JvdXAuIFRvIHNob3cgdGhlIGRpc3RyaWJ1dGlvbiBvZiBjdXQgd2l0aGluIGNvbG91ciwgZWFjaCBjb3VudCBzaG91bGQgYmUgZGl2aWRlZCBieSB0aGUgdG90YWwgY291bnQgZm9yIHRoYXQgY29sb3VyLiBUbyBzaG93IHRoZSBkaXN0cmlidXRpb24gb2YgY29sb3VyIHdpdGhpbiBjdXQsIGVhY2ggY291bnQgc2hvdWxkIGJlIGRpdmlkZWQgYnkgdGhlIHRvdGFsIGNvdW50IGZvciB0aGF0IGN1dC4gVGhpcyBtYWtlcyB0aGUgcGF0dGVybnMgZWFzaWVyIHRvIGNvbXBhcmUgYmVjYXVzZSB0aGUgdmFsdWVzIGFyZSBzdGFuZGFyZGl6ZWQgaW5zdGVhZCBvZiBiZWluZyBkcml2ZW4gYnkgZ3JvdXAgc2l6ZS4KCiMjIyAyLiBBdmVyYWdlIEZsaWdodCBEZWxheXMgYnkgRGV0aW5hdGlvbiBhbmQgTW9udGgKCmBgYHtyfQpkZWxheV9ieV9kZXN0X21vbnRoIDwtIGZsaWdodHMgJT4lCiAgbXV0YXRlKHRvdGFsX2RlbGF5ID0gZGVwX2RlbGF5ICsgYXJyX2RlbGF5KSAlPiUKICBmaWx0ZXIoIWlzLm5hKHRvdGFsX2RlbGF5KSkgJT4lCiAgZ3JvdXBfYnkobW9udGgsIGRlc3QpICU+JQogIHN1bW1hcmlzZShhdmdfZGVsYXkgPSBtZWFuKHRvdGFsX2RlbGF5KSwgLmdyb3VwcyA9ICJkcm9wIikKCmRlbGF5X2J5X2Rlc3RfbW9udGgKYGBgCgpgYGB7cn0KcDcyMV8yIDwtIGdncGxvdChkZWxheV9ieV9kZXN0X21vbnRoLCBhZXMoeCA9IG1vbnRoLCB5ID0gZGVzdCwgZmlsbCA9IGF2Z19kZWxheSkpICsKICBnZW9tX3RpbGUoKSArCiAgbGFicygKICAgIHRpdGxlID0gIkF2ZXJhZ2UgRmxpZ2h0IERlbGF5IGJ5IERlc3RpbmF0aW9uIGFuZCBNb250aCIsCiAgICB4ID0gIk1vbnRoIiwKICAgIHkgPSAiRGVzdGluYXRpb24iLAogICAgZmlsbCA9ICJBdmVyYWdlIERlbGF5IgogICkKCnA3MjFfMgpgYGAKCmBgYHtyfQpnZ3NhdmUoImV4ZXJjaXNlLTctNS0yLTEtMi5wbmciLCBwbG90ID0gcDcyMV8yLCB3aWR0aCA9IDgsIGhlaWdodCA9IDgpCmBgYAoKYGBge3J9CmRlbGF5X2J5X2Rlc3RfbW9udGgyIDwtIGRlbGF5X2J5X2Rlc3RfbW9udGggJT4lCiAgZ3JvdXBfYnkoZGVzdCkgJT4lCiAgbXV0YXRlKG92ZXJhbGxfYXZnID0gbWVhbihhdmdfZGVsYXkpKSAlPiUKICB1bmdyb3VwKCkKCnA3MjFfMl9pbXByb3ZlZCA8LSBnZ3Bsb3QoCiAgZGVsYXlfYnlfZGVzdF9tb250aDIsCiAgYWVzKHggPSBtb250aCwgeSA9IHJlb3JkZXIoZGVzdCwgb3ZlcmFsbF9hdmcpLCBmaWxsID0gYXZnX2RlbGF5KQopICsKICBnZW9tX3RpbGUoKSArCiAgbGFicygKICAgIHRpdGxlID0gIkF2ZXJhZ2UgRmxpZ2h0IERlbGF5IGJ5IERlc3RpbmF0aW9uIGFuZCBNb250aCAoUmVvcmRlcmVkKSIsCiAgICB4ID0gIk1vbnRoIiwKICAgIHkgPSAiRGVzdGluYXRpb24iLAogICAgZmlsbCA9ICJBdmVyYWdlIERlbGF5IgogICkKCnA3MjFfMl9pbXByb3ZlZApgYGAKCmBgYHtyfQpnZ3NhdmUoImV4ZXJjaXNlLTctNS0yLTEtMi1pbXByb3ZlZC5wbmciLCBwbG90ID0gcDcyMV8yX2ltcHJvdmVkLCB3aWR0aCA9IDgsIGhlaWdodCA9IDgpCmBgYAoKKipBbnN3ZXI6KiogIApUaGUgdGlsZSBwbG90IHNob3dzIGhvdyBhdmVyYWdlIGZsaWdodCBkZWxheXMgdmFyeSBieSBkZXN0aW5hdGlvbiBhbmQgbW9udGgsIGJ1dCBpdCBpcyBkaWZmaWN1bHQgdG8gcmVhZCBiZWNhdXNlIHRoZXJlIGFyZSBtYW55IGRlc3RpbmF0aW9ucyBhbmQgdGhlIHktYXhpcyBiZWNvbWVzIGNyb3dkZWQuIFRoZSBsYXJnZSBudW1iZXIgb2YgZGVzdGluYXRpb24gbGFiZWxzIG1ha2VzIGl0IGhhcmQgdG8gY29tcGFyZSBwYXR0ZXJucyBjbGVhcmx5LiBUaGUgcGxvdCBjYW4gYmUgaW1wcm92ZWQgYnkgcmVvcmRlcmluZyBkZXN0aW5hdGlvbnMsIGZpbHRlcmluZyB0byBvbmx5IGEgc3Vic2V0IG9mIGRlc3RpbmF0aW9ucywgb3IgdXNpbmcgZmFjZXRpbmcgb3IgYSBkaWZmZXJlbnQgdmlzdWFsaXphdGlvbiB0aGF0IHJlZHVjZXMgY2x1dHRlci4gQSByZW9yZGVyZWQgaGVhdG1hcCBtYWtlcyB0aGUgb3ZlcmFsbCBwYXR0ZXJuIGVhc2llciB0byBpbnRlcnByZXQuCgojIyMgMy4gQXhpcyBDaG9pY2UgaW4gVGlsZSBQbG90cwoKKipBbnN3ZXI6KiogIApJdCBpcyBzbGlnaHRseSBiZXR0ZXIgdG8gdXNlIGBhZXMoeCA9IGNvbG9yLCB5ID0gY3V0KWAgYmVjYXVzZSBgY29sb3JgIGhhcyBtb3JlIGNhdGVnb3JpZXMgdGhhbiBgY3V0YCwgYW5kIHBsYWNpbmcgdGhlIHZhcmlhYmxlIHdpdGggbW9yZSBsZXZlbHMgb24gdGhlIHgtYXhpcyBnZW5lcmFsbHkgbWFrZXMgdGhlIHBsb3QgZWFzaWVyIHRvIHJlYWQuIFRoZSB4LWF4aXMgbGFiZWxzIGFyZSBvZnRlbiBlYXNpZXIgdG8gc2Nhbiwgd2hpbGUgdGhlIHktYXhpcyB3b3JrcyB3ZWxsIGZvciB0aGUgdmFyaWFibGUgd2l0aCBmZXdlciBsZXZlbHMuIFNpbmNlIGBjdXRgIGhhcyBmZXdlciBjYXRlZ29yaWVzLCBwdXR0aW5nIGl0IG9uIHRoZSB5LWF4aXMgY3JlYXRlcyBhIGNsZWFuZXIgYW5kIG1vcmUgYmFsYW5jZWQgZGlzcGxheQoKIyMgRXhlcmNpc2VzIDcuNS4zLjEKCiMjIyAxLiBjdXRfd2lkdGggdnMgY3V0X251bWJlcgoKYGBge3J9CmRpYW1vbmRzX3dpZHRoIDwtIGRpYW1vbmRzICU+JQogIG11dGF0ZShwcmljZV9ncm91cCA9IGN1dF93aWR0aChwcmljZSwgd2lkdGggPSA1MDAwKSkKCnA3MzFfMWEgPC0gZ2dwbG90KGRpYW1vbmRzX3dpZHRoLCBhZXMoeCA9IGNhcmF0LCBjb2xvciA9IHByaWNlX2dyb3VwKSkgKwogIGdlb21fZnJlcXBvbHkoYmlud2lkdGggPSAwLjEpICsKICBsYWJzKAogICAgdGl0bGUgPSAiQ2FyYXQgRGlzdHJpYnV0aW9uIGJ5IFByaWNlIEdyb3VwIChjdXRfd2lkdGgpIiwKICAgIHggPSAiQ2FyYXQiLAogICAgeSA9ICJDb3VudCIsCiAgICBjb2xvciA9ICJQcmljZSBHcm91cCIKICApCgpwNzMxXzFhCmBgYAoKYGBge3J9Cmdnc2F2ZSgiZXhlcmNpc2UtNy01LTMtMS0xYS5wbmciLCBwbG90ID0gcDczMV8xYSwgd2lkdGggPSA4LCBoZWlnaHQgPSA1KQpgYGAKCmBgYHtyfQpkaWFtb25kc19udW1iZXIgPC0gZGlhbW9uZHMgJT4lCiAgbXV0YXRlKHByaWNlX2dyb3VwID0gY3V0X251bWJlcihwcmljZSwgbiA9IDYpKQoKcDczMV8xYiA8LSBnZ3Bsb3QoZGlhbW9uZHNfbnVtYmVyLCBhZXMoeCA9IGNhcmF0LCBjb2xvciA9IHByaWNlX2dyb3VwKSkgKwogIGdlb21fZnJlcXBvbHkoYmlud2lkdGggPSAwLjEpICsKICBsYWJzKAogICAgdGl0bGUgPSAiQ2FyYXQgRGlzdHJpYnV0aW9uIGJ5IFByaWNlIEdyb3VwIChjdXRfbnVtYmVyKSIsCiAgICB4ID0gIkNhcmF0IiwKICAgIHkgPSAiQ291bnQiLAogICAgY29sb3IgPSAiUHJpY2UgR3JvdXAiCiAgKQoKcDczMV8xYgpgYGAKCmBgYHtyfQpnZ3NhdmUoImV4ZXJjaXNlLTctNS0zLTEtMWIucG5nIiwgcGxvdCA9IHA3MzFfMWIsIHdpZHRoID0gOCwgaGVpZ2h0ID0gNSkKYGBgCgoqKkFuc3dlcjoqKiAgCldoZW4gdXNpbmcgYSBmcmVxdWVuY3kgcG9seWdvbiB0byBzdW1tYXJpemUgdGhlIGNvbmRpdGlvbmFsIGRpc3RyaWJ1dGlvbiwgaXQgaXMgaW1wb3J0YW50IHRvIHRoaW5rIGFib3V0IGhvdyB0aGUgY29udGludW91cyB2YXJpYWJsZSBpcyBiZWluZyBncm91cGVkLiBgY3V0X3dpZHRoKClgIGNyZWF0ZXMgYmlucyB3aXRoIGVxdWFsIG51bWVyaWMgd2lkdGgsIHdoaWxlIGBjdXRfbnVtYmVyKClgIGNyZWF0ZXMgYmlucyB3aXRoIHJvdWdobHkgZXF1YWwgbnVtYmVycyBvZiBvYnNlcnZhdGlvbnMuIAoKV2l0aCBgY3V0X3dpZHRoKClgLCB0aGUgZ3JvdXBzIGFyZSBlYXNpZXIgdG8gaW50ZXJwcmV0IGJlY2F1c2UgZWFjaCBiaW4gcmVwcmVzZW50cyB0aGUgc2FtZSByYW5nZSBvZiBwcmljZSB2YWx1ZXMsIGJ1dCBzb21lIGdyb3VwcyBtYXkgY29udGFpbiB2ZXJ5IGRpZmZlcmVudCBudW1iZXJzIG9mIGRpYW1vbmRzLiBXaXRoIGBjdXRfbnVtYmVyKClgLCB0aGUgZ3JvdXAgc2l6ZXMgYXJlIG1vcmUgYmFsYW5jZWQsIHdoaWNoIGNhbiBtYWtlIHRoZSBjb21wYXJpc29uIG9mIGRpc3RyaWJ1dGlvbnMgZWFzaWVyLCBidXQgdGhlIHByaWNlIHJhbmdlcyBhcmUgbm8gbG9uZ2VyIGVxdWFsbHkgc3BhY2VkLiAKClRoaXMgYWZmZWN0cyBhIHZpc3VhbGl6YXRpb24gb2YgdGhlIDJkIGRpc3RyaWJ1dGlvbiBvZiBgY2FyYXRgIGFuZCBgcHJpY2VgIGJlY2F1c2UgdGhlIGFwcGFyZW50IHBhdHRlcm5zIGNhbiBjaGFuZ2UgZGVwZW5kaW5nIG9uIGhvdyB0aGUgZ3JvdXBzIGFyZSBmb3JtZWQuIEVxdWFsLXdpZHRoIGJpbnMgZW1waGFzaXplIHRoZSBhY3R1YWwgc2NhbGUgb2YgcHJpY2UsIHdoaWxlIGVxdWFsLWNvdW50IGJpbnMgZW1waGFzaXplIGNvbXBhcmFiaWxpdHkgYmV0d2VlbiBncm91cHMuCgojIyMgMi4gQ2FyYXQgRGlzdHJpYnV0aW9uIGJ5IFByaWNlCgpgYGB7cn0KZGlhbW9uZHNfcHJpY2VfZ3JvdXBzIDwtIGRpYW1vbmRzICU+JQogIG11dGF0ZShwcmljZV9ncm91cCA9IGN1dF9udW1iZXIocHJpY2UsIG4gPSA2KSkKCnA3MzFfMiA8LSBnZ3Bsb3QoZGlhbW9uZHNfcHJpY2VfZ3JvdXBzLCBhZXMoeCA9IGNhcmF0LCBjb2xvciA9IHByaWNlX2dyb3VwKSkgKwogIGdlb21fZnJlcXBvbHkoYmlud2lkdGggPSAwLjEpICsKICBsYWJzKAogICAgdGl0bGUgPSAiRGlzdHJpYnV0aW9uIG9mIENhcmF0IFBhcnRpdGlvbmVkIGJ5IFByaWNlIiwKICAgIHggPSAiQ2FyYXQiLAogICAgeSA9ICJDb3VudCIsCiAgICBjb2xvciA9ICJQcmljZSBHcm91cCIKICApCgpwNzMxXzIKYGBgCgpgYGB7cn0KZ2dzYXZlKCJleGVyY2lzZS03LTUtMy0xLTIucG5nIiwgcGxvdCA9IHA3MzFfMiwgd2lkdGggPSA4LCBoZWlnaHQgPSA1KQpgYGAKCioqQW5zd2VyOioqICAKVGhlIGZyZXF1ZW5jeSBwb2x5Z29uIHNob3dzIHRoYXQgaGlnaGVyIHByaWNlIGdyb3VwcyB0ZW5kIHRvIGJlIGFzc29jaWF0ZWQgd2l0aCBsYXJnZXIgY2FyYXQgdmFsdWVzLiBMb3dlciBwcmljZSBncm91cHMgYXJlIGNvbmNlbnRyYXRlZCBhdCBzbWFsbGVyIGNhcmF0IHNpemVzLCB3aGlsZSBoaWdoZXIgcHJpY2UgZ3JvdXBzIHNoaWZ0IHRvIHRoZSByaWdodC4gVGhpcyBzdWdnZXN0cyBhIHN0cm9uZyBwb3NpdGl2ZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBjYXJhdCBhbmQgcHJpY2UuCgojIyMgMy4gUHJpY2UgQ29tcGFyaXNvbiBieSBEaWFtb25kIFNpemUKCmBgYHtyfQoKZGlhbW9uZHNfc2l6ZV9jb21wYXJlIDwtIGRpYW1vbmRzICU+JQogIG11dGF0ZShzaXplX2dyb3VwID0gY2FzZV93aGVuKAogICAgY2FyYXQgPCAxIH4gIlNtYWxsICg8MSBjYXJhdCkiLAogICAgY2FyYXQgPj0gMi41IH4gIlZlcnkgbGFyZ2UgKD49Mi41IGNhcmF0cykiLAogICAgVFJVRSB+IE5BX2NoYXJhY3Rlcl8KICApKSAlPiUKICBmaWx0ZXIoIWlzLm5hKHNpemVfZ3JvdXApKQoKcDczMV8zIDwtIGdncGxvdChkaWFtb25kc19zaXplX2NvbXBhcmUsIGFlcyh4ID0gcHJpY2UsIHkgPSBhZnRlcl9zdGF0KGRlbnNpdHkpLCBjb2xvciA9IHNpemVfZ3JvdXApKSArCiAgZ2VvbV9mcmVxcG9seShiaW53aWR0aCA9IDUwMCkgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJQcmljZSBEaXN0cmlidXRpb246IFNtYWxsIHZzIFZlcnkgTGFyZ2UgRGlhbW9uZHMiLAogICAgeCA9ICJQcmljZSIsCiAgICB5ID0gIkRlbnNpdHkiLAogICAgY29sb3IgPSAiU2l6ZSBHcm91cCIKICApCgpwNzMxXzMKYGBgCgpgYGB7cn0KZ2dzYXZlKCJleGVyY2lzZS03LTUtMy0xLTMucG5nIiwgcGxvdCA9IHA3MzFfMywgd2lkdGggPSA4LCBoZWlnaHQgPSA1KQpgYGAKCioqQW5zd2VyOioqClZlcnkgbGFyZ2UgZGlhbW9uZHMgaGF2ZSBhIHByaWNlIGRpc3RyaWJ1dGlvbiB0aGF0IGlzIHNoaWZ0ZWQgbXVjaCBmYXJ0aGVyIHRvIHRoZSByaWdodCB0aGFuIHNtYWxsIGRpYW1vbmRzLCBtZWFuaW5nIHRoZXkgYXJlIGdlbmVyYWxseSBtdWNoIG1vcmUgZXhwZW5zaXZlLiBUaGlzIGlzIHdoYXQgSSB3b3VsZCBleHBlY3QsIHNpbmNlIGxhcmdlciBkaWFtb25kcyBhcmUgcmFyZXIgYW5kIGNhcmF0IGhhcyBhIHN0cm9uZyBwb3NpdGl2ZSByZWxhdGlvbnNoaXAgd2l0aCBwcmljZS4gVXNpbmcgZGVuc2l0eSBpbnN0ZWFkIG9mIGNvdW50IG1ha2VzIHRoZSBjb21wYXJpc29uIGNsZWFyZXIgYmVjYXVzZSBpdCBzaG93cyB0aGUgc2hhcGUgb2YgdGhlIHByaWNlIGRpc3RyaWJ1dGlvbnMgd2l0aG91dCBsZXR0aW5nIHRoZSBtdWNoIGxhcmdlciBudW1iZXIgb2Ygc21hbGwgZGlhbW9uZHMgZG9taW5hdGUgdGhlIGdyYXBoLgoKIyMjIDQuIENvbWJpbmVkIFZpc3VhbGl6YXRpb24gb2YgQ3V0LCBDYXJhdCwgYW5kIFByaWNlCgpgYGB7cn0KZGlhbW9uZHNfY2FyYXRfZ3JvdXBzIDwtIGRpYW1vbmRzICU+JQogIGZpbHRlcihjYXJhdCA+IDAsIGNhcmF0IDw9IDMpICU+JQogIG11dGF0ZShjYXJhdF9ncm91cCA9IGN1dF93aWR0aChjYXJhdCwgd2lkdGggPSAwLjUpKQoKcDczMV80IDwtIGdncGxvdChkaWFtb25kc19jYXJhdF9ncm91cHMsIGFlcyh4ID0gY3V0LCB5ID0gcHJpY2UpKSArCiAgZ2VvbV9ib3hwbG90KCkgKwogIGZhY2V0X3dyYXAofmNhcmF0X2dyb3VwKSArCiAgbGFicygKICAgIHRpdGxlID0gIlByaWNlIGJ5IEN1dCwgRmFjZXRlZCBieSBDYXJhdCBHcm91cCIsCiAgICB4ID0gIkN1dCIsCiAgICB5ID0gIlByaWNlIgogICkKCnA3MzFfNApgYGAKCmBgYHtyfQpnZ3NhdmUoImV4ZXJjaXNlLTctNS0zLTEtNC5wbmciLCBwbG90ID0gcDczMV80LCB3aWR0aCA9IDEyLCBoZWlnaHQgPSA4KQpgYGAKCioqQW5zd2VyOioqICAKVGhpcyBwbG90IGNvbWJpbmVzIGJveHBsb3RzIGFuZCBmYWNldGluZyB0byBzaG93IHRoZSBqb2ludCBkaXN0cmlidXRpb24gb2YgY3V0LCBjYXJhdCwgYW5kIHByaWNlLiBUaGUgYm94cGxvdHMgY29tcGFyZSBwcmljZSBhY3Jvc3MgY3V0IGNhdGVnb3JpZXMsIHdoaWxlIHRoZSBmYWNldHMgc2VwYXJhdGUgZGlhbW9uZHMgaW50byBjYXJhdCBncm91cHMuIFRoaXMgbWFrZXMgaXQgZWFzaWVyIHRvIHNlZSBob3cgcHJpY2UgdmFyaWVzIGJ5IGN1dCB3aGVuIGRpYW1vbmRzIGFyZSBncm91cGVkIGludG8gc2ltaWxhciBjYXJhdCByYW5nZXMuIFRoZSBwbG90IGFsc28gc2hvd3MgdGhhdCBwcmljZSBnZW5lcmFsbHkgaW5jcmVhc2VzIGFzIGNhcmF0IGluY3JlYXNlcy4gT3ZlcmFsbCwgY2FyYXQgYXBwZWFycyB0byBoYXZlIGEgc3Ryb25nIGVmZmVjdCBvbiBwcmljZSwgYW5kIHRoZSBpbmZsdWVuY2Ugb2YgY3V0IGJlY29tZXMgZWFzaWVyIHRvIGludGVycHJldCB3aGVuIGRpYW1vbmRzIGFyZSBjb21wYXJlZCB3aXRoaW4gc2ltaWxhciBjYXJhdCByYW5nZXMuCgojIyMgNS4gV2h5IFNjYXR0ZXJwbG90cyBSZXZlYWwgMkQgT3V0bGllcnMKCmBgYHtyfQpwNzMxXzUgPC0gZ2dwbG90KGRpYW1vbmRzLCBhZXMoeCA9IHgsIHkgPSB5KSkgKwogIGdlb21fcG9pbnQoKSArCiAgY29vcmRfY2FydGVzaWFuKHhsaW0gPSBjKDQsIDExKSwgeWxpbSA9IGMoNCwgMTEpKSArCiAgbGFicygKICAgIHRpdGxlID0gIlNjYXR0ZXJwbG90IG9mIERpYW1vbmQgeCBhbmQgeSBEaW1lbnNpb25zIiwKICAgIHggPSAieCIsCiAgICB5ID0gInkiCiAgKQoKcDczMV81CmBgYAoKYGBge3J9Cmdnc2F2ZSgiZXhlcmNpc2UtNy01LTMtMS01LnBuZyIsIHBsb3QgPSBwNzMxXzUsIHdpZHRoID0gOCwgaGVpZ2h0ID0gNSkKYGBgCgoqKkFuc3dlcjoqKgpBIHNjYXR0ZXJwbG90IGlzIGEgYmV0dGVyIGRpc3BsYXkgaW4gdGhpcyBjYXNlIGJlY2F1c2UgaXQgc2hvd3MgZWFjaCBvYnNlcnZhdGlvbiBpbmRpdmlkdWFsbHkgYW5kIG1ha2VzIHVudXN1YWwgY29tYmluYXRpb25zIG9mIGB4YCBhbmQgYHlgIGVhc2llciB0byBkZXRlY3QuIFNvbWUgZGlhbW9uZHMgaGF2ZSBgeGAgYW5kIGB5YCB2YWx1ZXMgdGhhdCBsb29rIG5vcm1hbCB3aGVuIGV4YW1pbmVkIHNlcGFyYXRlbHksIGJ1dCB0b2dldGhlciB0aGV5IGRvIG5vdCBmb2xsb3cgdGhlIG1haW4gcGF0dGVybiBvZiB0aGUgZGF0YS4gQSBiaW5uZWQgcGxvdCB3b3VsZCBncm91cCBuZWFyYnkgb2JzZXJ2YXRpb25zIGludG8gdGlsZXMgb3IgYmlucywgd2hpY2ggY291bGQgc21vb3RoIG92ZXIgdGhvc2UgdW51c3VhbCBwb2ludHMgYW5kIG1ha2UgdGhlbSBoYXJkZXIgdG8gaWRlbnRpZnkuIEJlY2F1c2UgdGhlIGdvYWwgaXMgdG8gZmluZCBvdXRsaWVycyBpbiB0aGUgdHdvLWRpbWVuc2lvbmFsIHJlbGF0aW9uc2hpcCwgdGhlIHNjYXR0ZXJwbG90IGlzIG1vcmUgaW5mb3JtYXRpdmUuCmBgCi4uLgoK