In the realm of data analysis and visualization, the ability to
effectively communicate insights through graphical representations is
paramount. One of the most powerful tools for achieving this is the
ggplot2 library in R. This library allows for the creation
of sophisticated and aesthetically pleasing visualizations that can
convey complex data in an accessible manner.
A foundational ggplot visualization serves as the starting point for
exploring and presenting data. It involves the basic construction of
plots using the ggplot() function, which specifies the
variables for the x and y axes. By leveraging the
geom_line() function, one can create line plots that
illustrate trends and patterns over time. Additionally, the
customization of axis labels and plot colors enhances the clarity and
interpretability of the visualizations.
Throughout this introduction, we will delve into the essential steps
for creating these foundational visualizations, using the
mtcars dataset as a practical example.
3. Explore data
glimpse(mtcars)
Rows: 32
Columns: 11
$ mpg <dbl> 21.0, 21.0, 22.8, 21.4, 18.7, 18.1, 14.3, 24.4, 22.…
$ cyl <dbl> 6, 6, 4, 6, 8, 6, 8, 4, 4, 6, 6, 8, 8, 8, 8, 8, 8, …
$ disp <dbl> 160.0, 160.0, 108.0, 258.0, 360.0, 225.0, 360.0, 14…
$ hp <dbl> 110, 110, 93, 110, 175, 105, 245, 62, 95, 123, 123,…
$ drat <dbl> 3.90, 3.90, 3.85, 3.08, 3.15, 2.76, 3.21, 3.69, 3.9…
$ wt <dbl> 2.620, 2.875, 2.320, 3.215, 3.440, 3.460, 3.570, 3.…
$ qsec <dbl> 16.46, 17.02, 18.61, 19.44, 17.02, 20.22, 15.84, 20…
$ vs <dbl> 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, …
$ am <dbl> 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, …
$ gear <dbl> 4, 4, 4, 3, 3, 3, 3, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, …
$ carb <dbl> 4, 4, 1, 1, 2, 1, 4, 2, 2, 4, 4, 3, 3, 3, 4, 4, 4, …
4. Create Basic Charts with ggplot2
4.1 Bar chart
Bar charts are crucial for visualizing categorical data and comparing
different groups. They are effective because they allow for quick
comparison between different categories or groups, help identify
patterns or trends in the data, and provide a clear and straightforward
representation of quantitative information, making it easier to
interpret and communicate. Bar charts are widely used in various fields
such as economics, social sciences, and business due to their simplicity
and effectiveness in conveying complex information in an accessible
manner.
qplot(mtcars$cyl,
geom = "bar",
fill = I("red"),
colour = I("black"),
xlab = "Cylinders",
ylab = "Number of Vehicles",
main = "Cylinders in mtcars") +
theme_classic() +
theme(
plot.title = element_text(hjust = 0.5, size = 16, face = "bold"),
axis.title.x = element_text(size = 14),
axis.title.y = element_text(size = 14)
)

The bar chart represents the number of vehicles in the
mtcars dataset based on the number of cylinders they have.
The horizontal axis (x-axis) shows the categories for the number of
cylinders (4, 6, and 8), while the vertical axis (y-axis) shows the
count of vehicles.
4.2 Histograms
Histograms are essential for visualizing the distribution of a
dataset, allowing us to understand the frequency of data points within
specified ranges (bins). They help identify patterns such as skewness,
central tendency, and the spread of the data, as well as detect outliers
and anomalies. By providing a clear graphical representation of the
data’s distribution, histograms facilitate better decision-making and
insights in various fields, including statistics, data analysis, and
research.
qplot(mtcars$hp,
geom = "histogram",
binwidth = 20,
fill = I("blue"),
colour = I("black"),
xlab = "Horsepower",
ylab = "Number of Cars",
alpha = I(1),
main = "Histogram of Horsepower") +
theme_classic() +
theme(
plot.title = element_text(hjust = 0.5, size = 16, face = "bold"),
axis.title.x = element_text(size = 14),
axis.title.y = element_text(size = 14)
)

NA
NA
The histogram illustrates the distribution of cars based on their
horsepower. The horizontal axis (x-axis) represents horsepower, ranging
from 0 to over 300 horsepower. The vertical axis (y-axis) shows the
number of cars, ranging from 0 to over 7.5.
The histogram features several blue bars, each representing different
ranges of horsepower and the corresponding number of cars within each
range. The tallest bar is in the range between approximately 75 and 100
horsepower, indicating that there are about 7.5 cars in this range.
Another significant peak is observed between the ranges of approximately
125 and 150 horsepower, with around 4 cars.
Overall, most cars have horsepower below 150, with a notable decrease
in frequency as horsepower increases beyond this range. There are very
few cars with horsepower above 250.
4.3 Pie Chart
Pie charts are important for visualizing the proportions of different
categories within a dataset. They clearly show the relative sizes of
parts to the whole, making it easy to compare proportions. This type of
chart provides a straightforward and intuitive way to understand the
distribution of categories, which is particularly useful when you want
to highlight the composition of a dataset. Additionally, pie charts are
visually engaging and can quickly convey information at a glance, making
them a popular choice in business, marketing, and social sciences for
presenting data in an easily interpretable manner.
# Convert cyl to factor
mtcars <- mtcars %>%
mutate(cyl_factor = as.factor(cyl))
In this code, the mutate function from the dplyr package
is used to create a new column called cyl_factor by
converting the existing cyl column into a factor. This
transformation is useful for categorical data analysis and
visualization.
ggplot(data = mtcars, aes(x = cyl_factor, fill = cyl_factor)) +
geom_bar(position = "dodge") +
labs(
title = "Number of Cars by Cylinder Count",
x = "Number of Cylinders",
y = "Count of Cars",
fill = "Cylinders"
) +
theme_classic() +
theme(
plot.title = element_text(hjust = 0.5, size = 16, face = "bold"),
axis.title.x = element_text(size = 14),
axis.title.y = element_text(size = 14),
legend.title = element_text(size = 12),
legend.text = element_text(size = 10)
)

The bar chart illustrates the number of cars based on their cylinder
count. The vertical axis represents the “Count of
Cars,” while the horizontal axis shows the “Number of
Cylinders.” There are three bars, each representing a different
cylinder count: 4, 6, and 8.
- The red bar represents cars with 4 cylinders.
- The green bar represents cars with 6 cylinders.
- The blue bar represents cars with 8 cylinders.
The height of each bar indicates the number of cars with that
specific cylinder count. From the chart, we can see that cars with 8
cylinders are the most common, followed by cars with 4 cylinders, and
then cars with 6 cylinders.
4.4 Stacked bar chart
Stacked bar charts are important for visualizing the composition of
different categories within a dataset, allowing for a detailed
comparison of sub-groups within each category. They enable the
comparison of multiple sub-groups within each category, providing a more
granular view of the data. By showing the proportion of each sub-group
relative to the total, stacked bar charts make it easy to see how each
part contributes to the whole. This type of chart helps identify trends
and patterns across different categories and sub-groups, facilitating
better understanding of the data.
ggplot(data = mtcars, aes(x = "", fill = cyl_factor)) +
geom_bar(position = "stack") +
labs(
title = "Distribution of Cars by Cylinder Count",
x = "",
y = "Count of Cars",
fill = "Cylinders"
) +
theme_classic() +
theme(
plot.title = element_text(hjust = 0.5, size = 16, face = "bold"),
axis.title.y = element_text(size = 14),
legend.title = element_text(size = 12),
legend.text = element_text(size = 10)
)

ggplot( data = mtcars,
aes(x = " " ,
fill = cyl_factor))+
geom_bar(position = "stack") +
coord_polar(theta = "y") +
scale_fill_brewer(palette = "Dark2") +
theme_classic()

From this pie chart, you can gain several insights about the
distribution of cars based on their cylinder count in the mtcars
dataset. The chart visually represents the proportion of cars with
different cylinder counts, making it easy to see which cylinder count is
most common and which is least common among the cars in the dataset. The
largest segment of the pie chart indicates the most prevalent cylinder
count. In this case, cars with 8 cylinders form the largest segment,
suggesting they are the most common in the dataset.
By comparing the sizes of the segments, you can easily understand the
relative frequency of each cylinder count. For example, cars with 4
cylinders are more common than those with 6 cylinders, but less common
than those with 8 cylinders. This comparison helps in understanding the
distribution and prevalence of different cylinder counts within the
dataset.
The pie chart provides a clear and immediate understanding of how the
dataset is composed in terms of cylinder counts. This visualization is
useful for quickly grasping the overall composition of the dataset,
which can be beneficial for further analysis or decision-making.
Example of GGPLOT2
ggplot(mtcars, aes(x = hp, y = mpg, color = factor(cyl), shape = factor(cyl))) +
geom_point(size=2) +
labs(x = "Gross horsepower",
y = "Miles/gallon",
color = "Cylinders",
shape = "Cylinders",
title = "Mileage by horsepower and number of cylinders",
subtitle = "Data source: 1974 Motor Trend US magazine") +
theme_dark() +
scale_color_brewer(palette = "Set2")

The graph shows the relationship between mileage (miles per gallon)
and gross horsepower of vehicles, differentiated by the number of
cylinders. The data is from the 1974 Motor Trend US magazine. On the
vertical axis, we have miles per gallon, ranging from 10 to 35. On the
horizontal axis, we have gross horsepower, ranging from 50 to 350. The
points on the graph are color-coded and shaped to represent different
numbers of cylinders: green for 4 cylinders, orange for 6 cylinders, and
blue for 8 cylinders.
There is a clear inverse relationship between horsepower and miles
per gallon. As horsepower increases, the miles per gallon tend to
decrease. This indicates that more powerful cars generally have lower
fuel efficiency. Cars with 4 cylinders tend to have higher fuel
efficiency (higher mpg) and lower horsepower, clustering towards the
top-left of the graph. Cars with 6 cylinders have a moderate range of
horsepower and fuel efficiency, positioned in the middle of the graph.
Cars with 8 cylinders generally have higher horsepower and lower fuel
efficiency, clustering towards the bottom-right of the graph.
The most fuel-efficient cars (highest mpg) are those with 4 cylinders
and lower horsepower. Conversely, the least fuel-efficient cars are
those with 8 cylinders and higher horsepower. The graph highlights the
trade-off between performance (horsepower) and fuel efficiency (mpg).
Higher performance vehicles (more horsepower) tend to sacrifice fuel
efficiency.
This visualization helps in understanding how the number of cylinders
and horsepower affect the fuel efficiency of vehicles, providing
valuable insights for both consumers and manufacturers.
4.5 Scatter Plots
Scatter plots are an essential tool in data visualization and
analysis, offering numerous benefits that enhance our understanding of
data. One of the primary advantages of scatter plots is their ability to
visualize relationships between two quantitative variables. By plotting
data points on a two-dimensional graph, scatter plots help identify
patterns, trends, and correlations, making it easier to understand how
one variable affects another. This visual representation is crucial for
making data-driven decisions and forming hypotheses.
ggplot(mtcars, aes(x = mpg, y = wt, shape = cyl_factor, color = cyl_factor)) +
geom_point(size = 3) + # Size of the points
labs(title = "Relationship Between MPG and Weight of Cars",
x = "Miles Per Gallon (MPG)",
y = "Weight (1000 lbs)",
shape = "Number of Cylinders",
color = "Number of Cylinders") + # Custom labels
theme_minimal() # Minimalist theme for a clean look

The scatter plot reveals a negative correlation between miles per
gallon (MPG) and the weight of cars. Generally, as the weight of the car
increases, the MPG decreases. This indicates that heavier cars tend to
be less fuel-efficient. Understanding this relationship is crucial for
assessing how vehicle weight impacts fuel efficiency.
4.6 Box Plot
A box plot is a crucial tool in data analysis as it visually
summarizes the distribution of a dataset, highlighting the median,
quartiles, and potential outliers, which helps in quickly understanding
the central tendency, spread, and overall range of the data, making it
easier to compare multiple datasets, identify anomalies, and support
informed decision-making across various fields.
ggplot(mtcars, aes(x = factor(cyl), y = mpg)) +
geom_boxplot() +
labs(
title = "Distribution of Miles per Gallon by Number of Cylinders",
x = "Number of Cylinders",
y = "Miles per Gallon"
) +
theme_classic()

The box plot illustrates the relationship between the number of
cylinders in a vehicle and its miles per gallon (MPG) performance.
Vehicles with 4 cylinders have a median MPG of around 25, with an
interquartile range (IQR) from approximately 22 to 30. Vehicles with 6
cylinders have a median MPG of about 18, with an IQR from roughly 16 to
20. Vehicles with 8 cylinders have a median MPG of around 14, with an
IQR from about 13 to 15. The plot also highlights that vehicles with
fewer cylinders generally achieve higher MPG, and it identifies some
outliers, particularly among vehicles with more cylinders.
LS0tDQp0aXRsZTogIioqQ3JlYXRpbmcgYSBmb3VuZGF0aW9uYWwgZ2dwbG90IHZpc3VhbGl6YXRpb24uKioiDQphdXRob3I6IE1pZ3VlbGFuZ2VsIFBhbG1hIFJvamFzDQpvdXRwdXQ6DQogIGh0bWxfbm90ZWJvb2s6DQogICAgZGZfcHJpbnQ6IHBhZ2VkDQogICAgdG9jOiB0cnVlDQogICAgdG9jX2Zsb2F0OiB0cnVlDQogICAgdG9jX2RlcHRoOiA1DQotLS0NCg0KSW4gdGhlIHJlYWxtIG9mIGRhdGEgYW5hbHlzaXMgYW5kIHZpc3VhbGl6YXRpb24sIHRoZSBhYmlsaXR5IHRvIGVmZmVjdGl2ZWx5IGNvbW11bmljYXRlIGluc2lnaHRzIHRocm91Z2ggZ3JhcGhpY2FsIHJlcHJlc2VudGF0aW9ucyBpcyBwYXJhbW91bnQuIE9uZSBvZiB0aGUgbW9zdCBwb3dlcmZ1bCB0b29scyBmb3IgYWNoaWV2aW5nIHRoaXMgaXMgdGhlIGBnZ3Bsb3QyYCBsaWJyYXJ5IGluIFIuIFRoaXMgbGlicmFyeSBhbGxvd3MgZm9yIHRoZSBjcmVhdGlvbiBvZiBzb3BoaXN0aWNhdGVkIGFuZCBhZXN0aGV0aWNhbGx5IHBsZWFzaW5nIHZpc3VhbGl6YXRpb25zIHRoYXQgY2FuIGNvbnZleSBjb21wbGV4IGRhdGEgaW4gYW4gYWNjZXNzaWJsZSBtYW5uZXIuDQoNCkEgZm91bmRhdGlvbmFsIGdncGxvdCB2aXN1YWxpemF0aW9uIHNlcnZlcyBhcyB0aGUgc3RhcnRpbmcgcG9pbnQgZm9yIGV4cGxvcmluZyBhbmQgcHJlc2VudGluZyBkYXRhLiBJdCBpbnZvbHZlcyB0aGUgYmFzaWMgY29uc3RydWN0aW9uIG9mIHBsb3RzIHVzaW5nIHRoZSBgZ2dwbG90KClgIGZ1bmN0aW9uLCB3aGljaCBzcGVjaWZpZXMgdGhlIHZhcmlhYmxlcyBmb3IgdGhlIHggYW5kIHkgYXhlcy4gQnkgbGV2ZXJhZ2luZyB0aGUgYGdlb21fbGluZSgpYCBmdW5jdGlvbiwgb25lIGNhbiBjcmVhdGUgbGluZSBwbG90cyB0aGF0IGlsbHVzdHJhdGUgdHJlbmRzIGFuZCBwYXR0ZXJucyBvdmVyIHRpbWUuIEFkZGl0aW9uYWxseSwgdGhlIGN1c3RvbWl6YXRpb24gb2YgYXhpcyBsYWJlbHMgYW5kIHBsb3QgY29sb3JzIGVuaGFuY2VzIHRoZSBjbGFyaXR5IGFuZCBpbnRlcnByZXRhYmlsaXR5IG9mIHRoZSB2aXN1YWxpemF0aW9ucy4NCg0KVGhyb3VnaG91dCB0aGlzIGludHJvZHVjdGlvbiwgd2Ugd2lsbCBkZWx2ZSBpbnRvIHRoZSBlc3NlbnRpYWwgc3RlcHMgZm9yIGNyZWF0aW5nIHRoZXNlIGZvdW5kYXRpb25hbCB2aXN1YWxpemF0aW9ucywgdXNpbmcgdGhlICoqbXRjYXJzKiogZGF0YXNldCBhcyBhIHByYWN0aWNhbCBleGFtcGxlLiANCg0KIyMjICoqMS4gTGlicmFyaWVzICoqDQoNCmBgYHtyIHNldHVwICwgbWVzc2FnZT1GQUxTRSAsIHdhcm5pbmc9RkFMU0V9DQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkocGxvdGx5KQ0KYGBgDQoNCiMjIyAqKjIuIERhdGFzZXQqKg0KDQpUaGUgKiptdGNhcnMqKiBkYXRhc2V0IGluIFIgaXMgZGVzaWduZWQgdG8gcHJvdmlkZSBhIGNvbXByZWhlbnNpdmUgb3ZlcnZpZXcgb2YgdmFyaW91cyBjYXIgbW9kZWxzLCBmb2N1c2luZyBvbiB0aGVpciBwZXJmb3JtYW5jZSBhbmQgY2hhcmFjdGVyaXN0aWNzLiBJdCBpcyB3aWRlbHkgdXNlZCBmb3Igc3RhdGlzdGljYWwgYW5hbHlzaXMgYW5kIG1hY2hpbmUgbGVhcm5pbmcgdGFza3MsIGFsbG93aW5nIHVzZXJzIHRvIGV4cGxvcmUgcmVsYXRpb25zaGlwcyBiZXR3ZWVuIGRpZmZlcmVudCBhc3BlY3RzIG9mIGNhciBwZXJmb3JtYW5jZSBhbmQgbWFrZSBwcmVkaWN0aW9ucyBiYXNlZCBvbiB0aGVzZSBkYXRhIHBvaW50cy4NCg0KDQpgYGB7cn0NCm10Y2Fycw0KYGBgDQpUaGUgX18qKm10Y2FycyoqX18gZGF0YXNldCBjb250YWlucyBkYXRhIG9uIDMyIGNhciBtb2RlbHMgYW5kIDExIHZhcmlhYmxlcyByZWxhdGVkIHRvIHRoZWlyIHBlcmZvcm1hbmNlIGFuZCBjaGFyYWN0ZXJpc3RpY3MuIFRoZSB2YXJpYWJsZXMgaW5jbHVkZToNCg0KLSAqKm1wZyoqOiBNaWxlcyBwZXIgZ2FsbG9uIChmdWVsIGVmZmljaWVuY3kpLg0KLSAqKmN5bCoqOiBOdW1iZXIgb2YgY3lsaW5kZXJzLg0KLSAqKmRpc3AqKjogRGlzcGxhY2VtZW50IChpbiBjdWJpYyBpbmNoZXMpLg0KLSAqKmhwKio6IEhvcnNlcG93ZXIuDQotICoqZHJhdCoqOiBSZWFyIGF4bGUgcmF0aW8uDQotICoqd3QqKjogV2VpZ2h0IChpbiAxMDAwIGxicykuDQotICoqcXNlYyoqOiAxLzQgbWlsZSB0aW1lLg0KLSAqKnZzKio6IEVuZ2luZSAoMCA9IFYtc2hhcGVkLCAxID0gU3RyYWlnaHQpLg0KLSAqKmFtKio6IFRyYW5zbWlzc2lvbiAoMCA9IGF1dG9tYXRpYywgMSA9IG1hbnVhbCkuDQotICoqZ2VhcioqOiBOdW1iZXIgb2YgZm9yd2FyZCBnZWFycy4NCi0gKipjYXJiKio6IE51bWJlciBvZiBjYXJidXJldG9ycy4NCg0KDQojIyMgKiozLiBFeHBsb3JlIGRhdGEqKg0KDQpgYGB7cn0NCmdsaW1wc2UobXRjYXJzKQ0KYGBgDQoNCiMjIyAgKio0LiBDcmVhdGUgQmFzaWMgQ2hhcnRzIHdpdGggZ2dwbG90MioqDQoNCg0KIyMjIyBfNC4xIEJhciBjaGFydF8NCg0KQmFyIGNoYXJ0cyBhcmUgY3J1Y2lhbCBmb3IgdmlzdWFsaXppbmcgY2F0ZWdvcmljYWwgZGF0YSBhbmQgY29tcGFyaW5nIGRpZmZlcmVudCBncm91cHMuIFRoZXkgYXJlIGVmZmVjdGl2ZSBiZWNhdXNlIHRoZXkgYWxsb3cgZm9yIHF1aWNrIGNvbXBhcmlzb24gYmV0d2VlbiBkaWZmZXJlbnQgY2F0ZWdvcmllcyBvciBncm91cHMsIGhlbHAgaWRlbnRpZnkgcGF0dGVybnMgb3IgdHJlbmRzIGluIHRoZSBkYXRhLCBhbmQgcHJvdmlkZSBhIGNsZWFyIGFuZCBzdHJhaWdodGZvcndhcmQgcmVwcmVzZW50YXRpb24gb2YgcXVhbnRpdGF0aXZlIGluZm9ybWF0aW9uLCBtYWtpbmcgaXQgZWFzaWVyIHRvIGludGVycHJldCBhbmQgY29tbXVuaWNhdGUuIEJhciBjaGFydHMgYXJlIHdpZGVseSB1c2VkIGluIHZhcmlvdXMgZmllbGRzIHN1Y2ggYXMgZWNvbm9taWNzLCBzb2NpYWwgc2NpZW5jZXMsIGFuZCBidXNpbmVzcyBkdWUgdG8gdGhlaXIgc2ltcGxpY2l0eSBhbmQgZWZmZWN0aXZlbmVzcyBpbiBjb252ZXlpbmcgY29tcGxleCBpbmZvcm1hdGlvbiBpbiBhbiBhY2Nlc3NpYmxlIG1hbm5lci4NCg0KYGBge3J9DQoNCnFwbG90KG10Y2FycyRjeWwsDQogICAgICBnZW9tID0gImJhciIsDQogICAgICBmaWxsID0gSSgicmVkIiksDQogICAgICBjb2xvdXIgPSBJKCJibGFjayIpLA0KICAgICAgeGxhYiA9ICJDeWxpbmRlcnMiLA0KICAgICAgeWxhYiA9ICJOdW1iZXIgb2YgVmVoaWNsZXMiLA0KICAgICAgbWFpbiA9ICJDeWxpbmRlcnMgaW4gbXRjYXJzIikgKw0KICB0aGVtZV9jbGFzc2ljKCkgKw0KICB0aGVtZSgNCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBzaXplID0gMTYsIGZhY2UgPSAiYm9sZCIpLA0KICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQpLA0KICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQpDQogICkNCg0KYGBgDQoNClRoZSBiYXIgY2hhcnQgcmVwcmVzZW50cyB0aGUgbnVtYmVyIG9mIHZlaGljbGVzIGluIHRoZSBgbXRjYXJzYCBkYXRhc2V0IGJhc2VkIG9uIHRoZSBudW1iZXIgb2YgY3lsaW5kZXJzIHRoZXkgaGF2ZS4gVGhlIGhvcml6b250YWwgYXhpcyAoeC1heGlzKSBzaG93cyB0aGUgY2F0ZWdvcmllcyBmb3IgdGhlIG51bWJlciBvZiBjeWxpbmRlcnMgKDQsIDYsIGFuZCA4KSwgd2hpbGUgdGhlIHZlcnRpY2FsIGF4aXMgKHktYXhpcykgc2hvd3MgdGhlIGNvdW50IG9mIHZlaGljbGVzLg0KDQoNCiMjIyMgXzQuMiBIaXN0b2dyYW1zXw0KDQpIaXN0b2dyYW1zIGFyZSBlc3NlbnRpYWwgZm9yIHZpc3VhbGl6aW5nIHRoZSBkaXN0cmlidXRpb24gb2YgYSBkYXRhc2V0LCBhbGxvd2luZyB1cyB0byB1bmRlcnN0YW5kIHRoZSBmcmVxdWVuY3kgb2YgZGF0YSBwb2ludHMgd2l0aGluIHNwZWNpZmllZCByYW5nZXMgKGJpbnMpLiBUaGV5IGhlbHAgaWRlbnRpZnkgcGF0dGVybnMgc3VjaCBhcyBza2V3bmVzcywgY2VudHJhbCB0ZW5kZW5jeSwgYW5kIHRoZSBzcHJlYWQgb2YgdGhlIGRhdGEsIGFzIHdlbGwgYXMgZGV0ZWN0IG91dGxpZXJzIGFuZCBhbm9tYWxpZXMuIEJ5IHByb3ZpZGluZyBhIGNsZWFyIGdyYXBoaWNhbCByZXByZXNlbnRhdGlvbiBvZiB0aGUgZGF0YSdzIGRpc3RyaWJ1dGlvbiwgaGlzdG9ncmFtcyBmYWNpbGl0YXRlIGJldHRlciBkZWNpc2lvbi1tYWtpbmcgYW5kIGluc2lnaHRzIGluIHZhcmlvdXMgZmllbGRzLCBpbmNsdWRpbmcgc3RhdGlzdGljcywgZGF0YSBhbmFseXNpcywgYW5kIHJlc2VhcmNoLg0KDQpgYGB7cn0NCg0KcXBsb3QobXRjYXJzJGhwLA0KICAgICAgZ2VvbSA9ICJoaXN0b2dyYW0iLA0KICAgICAgYmlud2lkdGggPSAyMCwNCiAgICAgIGZpbGwgPSBJKCJibHVlIiksDQogICAgICBjb2xvdXIgPSBJKCJibGFjayIpLA0KICAgICAgeGxhYiA9ICJIb3JzZXBvd2VyIiwNCiAgICAgIHlsYWIgPSAiTnVtYmVyIG9mIENhcnMiLA0KICAgICAgYWxwaGEgPSBJKDEpLA0KICAgICAgbWFpbiA9ICJIaXN0b2dyYW0gb2YgSG9yc2Vwb3dlciIpICsNCiAgdGhlbWVfY2xhc3NpYygpICsNCiAgdGhlbWUoDQogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDE2LCBmYWNlID0gImJvbGQiKSwNCiAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSwNCiAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KQ0KICApDQoNCg0KYGBgDQpUaGUgaGlzdG9ncmFtIGlsbHVzdHJhdGVzIHRoZSBkaXN0cmlidXRpb24gb2YgY2FycyBiYXNlZCBvbiB0aGVpciBob3JzZXBvd2VyLiBUaGUgaG9yaXpvbnRhbCBheGlzICh4LWF4aXMpIHJlcHJlc2VudHMgaG9yc2Vwb3dlciwgcmFuZ2luZyBmcm9tIDAgdG8gb3ZlciAzMDAgaG9yc2Vwb3dlci4gVGhlIHZlcnRpY2FsIGF4aXMgKHktYXhpcykgc2hvd3MgdGhlIG51bWJlciBvZiBjYXJzLCByYW5naW5nIGZyb20gMCB0byBvdmVyIDcuNS4NCg0KVGhlIGhpc3RvZ3JhbSBmZWF0dXJlcyBzZXZlcmFsIGJsdWUgYmFycywgZWFjaCByZXByZXNlbnRpbmcgZGlmZmVyZW50IHJhbmdlcyBvZiBob3JzZXBvd2VyIGFuZCB0aGUgY29ycmVzcG9uZGluZyBudW1iZXIgb2YgY2FycyB3aXRoaW4gZWFjaCByYW5nZS4gVGhlIHRhbGxlc3QgYmFyIGlzIGluIHRoZSByYW5nZSBiZXR3ZWVuIGFwcHJveGltYXRlbHkgNzUgYW5kIDEwMCBob3JzZXBvd2VyLCBpbmRpY2F0aW5nIHRoYXQgdGhlcmUgYXJlIGFib3V0IDcuNSBjYXJzIGluIHRoaXMgcmFuZ2UuIEFub3RoZXIgc2lnbmlmaWNhbnQgcGVhayBpcyBvYnNlcnZlZCBiZXR3ZWVuIHRoZSByYW5nZXMgb2YgYXBwcm94aW1hdGVseSAxMjUgYW5kIDE1MCBob3JzZXBvd2VyLCB3aXRoIGFyb3VuZCA0IGNhcnMuDQoNCk92ZXJhbGwsIG1vc3QgY2FycyBoYXZlIGhvcnNlcG93ZXIgYmVsb3cgMTUwLCB3aXRoIGEgbm90YWJsZSBkZWNyZWFzZSBpbiBmcmVxdWVuY3kgYXMgaG9yc2Vwb3dlciBpbmNyZWFzZXMgYmV5b25kIHRoaXMgcmFuZ2UuIFRoZXJlIGFyZSB2ZXJ5IGZldyBjYXJzIHdpdGggaG9yc2Vwb3dlciBhYm92ZSAyNTAuDQoNCg0KIyMjIyBfNC4zIFBpZSBDaGFydF8gDQoNClBpZSBjaGFydHMgYXJlIGltcG9ydGFudCBmb3IgdmlzdWFsaXppbmcgdGhlIHByb3BvcnRpb25zIG9mIGRpZmZlcmVudCBjYXRlZ29yaWVzIHdpdGhpbiBhIGRhdGFzZXQuIFRoZXkgY2xlYXJseSBzaG93IHRoZSByZWxhdGl2ZSBzaXplcyBvZiBwYXJ0cyB0byB0aGUgd2hvbGUsIG1ha2luZyBpdCBlYXN5IHRvIGNvbXBhcmUgcHJvcG9ydGlvbnMuIFRoaXMgdHlwZSBvZiBjaGFydCBwcm92aWRlcyBhIHN0cmFpZ2h0Zm9yd2FyZCBhbmQgaW50dWl0aXZlIHdheSB0byB1bmRlcnN0YW5kIHRoZSBkaXN0cmlidXRpb24gb2YgY2F0ZWdvcmllcywgd2hpY2ggaXMgcGFydGljdWxhcmx5IHVzZWZ1bCB3aGVuIHlvdSB3YW50IHRvIGhpZ2hsaWdodCB0aGUgY29tcG9zaXRpb24gb2YgYSBkYXRhc2V0LiBBZGRpdGlvbmFsbHksIHBpZSBjaGFydHMgYXJlIHZpc3VhbGx5IGVuZ2FnaW5nIGFuZCBjYW4gcXVpY2tseSBjb252ZXkgaW5mb3JtYXRpb24gYXQgYSBnbGFuY2UsIG1ha2luZyB0aGVtIGEgcG9wdWxhciBjaG9pY2UgaW4gYnVzaW5lc3MsIG1hcmtldGluZywgYW5kIHNvY2lhbCBzY2llbmNlcyBmb3IgcHJlc2VudGluZyBkYXRhIGluIGFuIGVhc2lseSBpbnRlcnByZXRhYmxlIG1hbm5lci4NCg0KYGBge3J9DQojIENvbnZlcnQgY3lsIHRvIGZhY3RvciANCg0KbXRjYXJzIDwtIG10Y2FycyAlPiUNCiAgbXV0YXRlKGN5bF9mYWN0b3IgPSBhcy5mYWN0b3IoY3lsKSkNCg0KYGBgDQoNCkluIHRoaXMgY29kZSwgdGhlIG11dGF0ZSBmdW5jdGlvbiBmcm9tIHRoZSBgZHBseXJgIHBhY2thZ2UgaXMgdXNlZCB0byBjcmVhdGUgYSBuZXcgY29sdW1uIGNhbGxlZCBgY3lsX2ZhY3RvcmAgYnkgY29udmVydGluZyB0aGUgZXhpc3RpbmcgYGN5bGAgY29sdW1uIGludG8gYSBmYWN0b3IuIFRoaXMgdHJhbnNmb3JtYXRpb24gaXMgdXNlZnVsIGZvciBjYXRlZ29yaWNhbCBkYXRhIGFuYWx5c2lzIGFuZCB2aXN1YWxpemF0aW9uLg0KDQoNCmBgYHtyfQ0KDQpnZ3Bsb3QoZGF0YSA9IG10Y2FycywgYWVzKHggPSBjeWxfZmFjdG9yLCBmaWxsID0gY3lsX2ZhY3RvcikpICsNCiAgZ2VvbV9iYXIocG9zaXRpb24gPSAiZG9kZ2UiKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiTnVtYmVyIG9mIENhcnMgYnkgQ3lsaW5kZXIgQ291bnQiLA0KICAgIHggPSAiTnVtYmVyIG9mIEN5bGluZGVycyIsDQogICAgeSA9ICJDb3VudCBvZiBDYXJzIiwNCiAgICBmaWxsID0gIkN5bGluZGVycyINCiAgKSArDQogIHRoZW1lX2NsYXNzaWMoKSArDQogIHRoZW1lKA0KICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIHNpemUgPSAxNiwgZmFjZSA9ICJib2xkIiksDQogICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksDQogICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCksDQogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksDQogICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKQ0KKQ0KDQpgYGANClRoZSBiYXIgY2hhcnQgaWxsdXN0cmF0ZXMgdGhlIG51bWJlciBvZiBjYXJzIGJhc2VkIG9uIHRoZWlyIGN5bGluZGVyIGNvdW50LiBUaGUgdmVydGljYWwgYXhpcyByZXByZXNlbnRzIHRoZSAqKiJDb3VudCBvZiBDYXJzLCIqKiB3aGlsZSB0aGUgaG9yaXpvbnRhbCBheGlzIHNob3dzIHRoZSAqKiJOdW1iZXIgb2YgQ3lsaW5kZXJzLiIqKiBUaGVyZSBhcmUgdGhyZWUgYmFycywgZWFjaCByZXByZXNlbnRpbmcgYSBkaWZmZXJlbnQgY3lsaW5kZXIgY291bnQ6IDQsIDYsIGFuZCA4Lg0KDQotIFRoZSByZWQgYmFyIHJlcHJlc2VudHMgY2FycyB3aXRoIDQgY3lsaW5kZXJzLg0KLSBUaGUgZ3JlZW4gYmFyIHJlcHJlc2VudHMgY2FycyB3aXRoIDYgY3lsaW5kZXJzLg0KLSBUaGUgYmx1ZSBiYXIgcmVwcmVzZW50cyBjYXJzIHdpdGggOCBjeWxpbmRlcnMuDQoNClRoZSBoZWlnaHQgb2YgZWFjaCBiYXIgaW5kaWNhdGVzIHRoZSBudW1iZXIgb2YgY2FycyB3aXRoIHRoYXQgc3BlY2lmaWMgY3lsaW5kZXIgY291bnQuIEZyb20gdGhlIGNoYXJ0LCB3ZSBjYW4gc2VlIHRoYXQgY2FycyB3aXRoIDggY3lsaW5kZXJzIGFyZSB0aGUgbW9zdCBjb21tb24sIGZvbGxvd2VkIGJ5IGNhcnMgd2l0aCA0IGN5bGluZGVycywgYW5kIHRoZW4gY2FycyB3aXRoIDYgY3lsaW5kZXJzLg0KDQoNCiMjIyMgXzQuNCBTdGFja2VkIGJhciBjaGFydF8NCg0KU3RhY2tlZCBiYXIgY2hhcnRzIGFyZSBpbXBvcnRhbnQgZm9yIHZpc3VhbGl6aW5nIHRoZSBjb21wb3NpdGlvbiBvZiBkaWZmZXJlbnQgY2F0ZWdvcmllcyB3aXRoaW4gYSBkYXRhc2V0LCBhbGxvd2luZyBmb3IgYSBkZXRhaWxlZCBjb21wYXJpc29uIG9mIHN1Yi1ncm91cHMgd2l0aGluIGVhY2ggY2F0ZWdvcnkuIFRoZXkgZW5hYmxlIHRoZSBjb21wYXJpc29uIG9mIG11bHRpcGxlIHN1Yi1ncm91cHMgd2l0aGluIGVhY2ggY2F0ZWdvcnksIHByb3ZpZGluZyBhIG1vcmUgZ3JhbnVsYXIgdmlldyBvZiB0aGUgZGF0YS4gQnkgc2hvd2luZyB0aGUgcHJvcG9ydGlvbiBvZiBlYWNoIHN1Yi1ncm91cCByZWxhdGl2ZSB0byB0aGUgdG90YWwsIHN0YWNrZWQgYmFyIGNoYXJ0cyBtYWtlIGl0IGVhc3kgdG8gc2VlIGhvdyBlYWNoIHBhcnQgY29udHJpYnV0ZXMgdG8gdGhlIHdob2xlLiBUaGlzIHR5cGUgb2YgY2hhcnQgaGVscHMgaWRlbnRpZnkgdHJlbmRzIGFuZCBwYXR0ZXJucyBhY3Jvc3MgZGlmZmVyZW50IGNhdGVnb3JpZXMgYW5kIHN1Yi1ncm91cHMsIGZhY2lsaXRhdGluZyBiZXR0ZXIgdW5kZXJzdGFuZGluZyBvZiB0aGUgZGF0YS4NCg0KYGBge3J9DQoNCmdncGxvdChkYXRhID0gbXRjYXJzLCBhZXMoeCA9ICIiLCBmaWxsID0gY3lsX2ZhY3RvcikpICsNCiAgZ2VvbV9iYXIocG9zaXRpb24gPSAic3RhY2siKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiRGlzdHJpYnV0aW9uIG9mIENhcnMgYnkgQ3lsaW5kZXIgQ291bnQiLA0KICAgIHggPSAiIiwNCiAgICB5ID0gIkNvdW50IG9mIENhcnMiLA0KICAgIGZpbGwgPSAiQ3lsaW5kZXJzIg0KICApICsNCiAgdGhlbWVfY2xhc3NpYygpICsNCiAgdGhlbWUoDQogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDE2LCBmYWNlID0gImJvbGQiKSwNCiAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0KSwNCiAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwNCiAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApDQogICkNCg0KYGBgDQoNCmBgYHtyfQ0KZ2dwbG90KCBkYXRhID0gbXRjYXJzLA0KICAgICAgICBhZXMoeCA9ICIgIiAsDQogICAgICAgICAgICBmaWxsID0gY3lsX2ZhY3RvcikpKw0KICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJzdGFjayIpICsNCiAgY29vcmRfcG9sYXIodGhldGEgPSAieSIpICsgDQogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiRGFyazIiKSArDQogIHRoZW1lX2NsYXNzaWMoKQ0KYGBgDQpGcm9tIHRoaXMgcGllIGNoYXJ0LCB5b3UgY2FuIGdhaW4gc2V2ZXJhbCBpbnNpZ2h0cyBhYm91dCB0aGUgZGlzdHJpYnV0aW9uIG9mIGNhcnMgYmFzZWQgb24gdGhlaXIgY3lsaW5kZXIgY291bnQgaW4gdGhlIG10Y2FycyBkYXRhc2V0LiBUaGUgY2hhcnQgdmlzdWFsbHkgcmVwcmVzZW50cyB0aGUgcHJvcG9ydGlvbiBvZiBjYXJzIHdpdGggZGlmZmVyZW50IGN5bGluZGVyIGNvdW50cywgbWFraW5nIGl0IGVhc3kgdG8gc2VlIHdoaWNoIGN5bGluZGVyIGNvdW50IGlzIG1vc3QgY29tbW9uIGFuZCB3aGljaCBpcyBsZWFzdCBjb21tb24gYW1vbmcgdGhlIGNhcnMgaW4gdGhlIGRhdGFzZXQuIFRoZSBsYXJnZXN0IHNlZ21lbnQgb2YgdGhlIHBpZSBjaGFydCBpbmRpY2F0ZXMgdGhlIG1vc3QgcHJldmFsZW50IGN5bGluZGVyIGNvdW50LiBJbiB0aGlzIGNhc2UsIGNhcnMgd2l0aCA4IGN5bGluZGVycyBmb3JtIHRoZSBsYXJnZXN0IHNlZ21lbnQsIHN1Z2dlc3RpbmcgdGhleSBhcmUgdGhlIG1vc3QgY29tbW9uIGluIHRoZSBkYXRhc2V0Lg0KDQpCeSBjb21wYXJpbmcgdGhlIHNpemVzIG9mIHRoZSBzZWdtZW50cywgeW91IGNhbiBlYXNpbHkgdW5kZXJzdGFuZCB0aGUgcmVsYXRpdmUgZnJlcXVlbmN5IG9mIGVhY2ggY3lsaW5kZXIgY291bnQuIEZvciBleGFtcGxlLCBjYXJzIHdpdGggNCBjeWxpbmRlcnMgYXJlIG1vcmUgY29tbW9uIHRoYW4gdGhvc2Ugd2l0aCA2IGN5bGluZGVycywgYnV0IGxlc3MgY29tbW9uIHRoYW4gdGhvc2Ugd2l0aCA4IGN5bGluZGVycy4gVGhpcyBjb21wYXJpc29uIGhlbHBzIGluIHVuZGVyc3RhbmRpbmcgdGhlIGRpc3RyaWJ1dGlvbiBhbmQgcHJldmFsZW5jZSBvZiBkaWZmZXJlbnQgY3lsaW5kZXIgY291bnRzIHdpdGhpbiB0aGUgZGF0YXNldC4NCg0KVGhlIHBpZSBjaGFydCBwcm92aWRlcyBhIGNsZWFyIGFuZCBpbW1lZGlhdGUgdW5kZXJzdGFuZGluZyBvZiBob3cgdGhlIGRhdGFzZXQgaXMgY29tcG9zZWQgaW4gdGVybXMgb2YgY3lsaW5kZXIgY291bnRzLiBUaGlzIHZpc3VhbGl6YXRpb24gaXMgdXNlZnVsIGZvciBxdWlja2x5IGdyYXNwaW5nIHRoZSBvdmVyYWxsIGNvbXBvc2l0aW9uIG9mIHRoZSBkYXRhc2V0LCB3aGljaCBjYW4gYmUgYmVuZWZpY2lhbCBmb3IgZnVydGhlciBhbmFseXNpcyBvciBkZWNpc2lvbi1tYWtpbmcuDQoNCiMjIyMjIF9FeGFtcGxlIG9mIEdHUExPVDJfDQoNCg0KYGBge3J9DQpnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IGhwLCB5ID0gbXBnLCBjb2xvciA9IGZhY3RvcihjeWwpLCBzaGFwZSA9IGZhY3RvcihjeWwpKSkgKw0KICAgIGdlb21fcG9pbnQoc2l6ZT0yKSArIA0KICAgIGxhYnMoeCA9ICJHcm9zcyBob3JzZXBvd2VyIiwgDQogICAgICAgICB5ID0gIk1pbGVzL2dhbGxvbiIsIA0KICAgICAgICAgY29sb3IgPSAiQ3lsaW5kZXJzIiwgDQogICAgICAgICBzaGFwZSA9ICJDeWxpbmRlcnMiLCANCiAgICAgICAgIHRpdGxlID0gIk1pbGVhZ2UgYnkgaG9yc2Vwb3dlciBhbmQgbnVtYmVyIG9mIGN5bGluZGVycyIsDQogICAgICAgICBzdWJ0aXRsZSA9ICJEYXRhIHNvdXJjZTogMTk3NCBNb3RvciBUcmVuZCBVUyBtYWdhemluZSIpICsNCiAgICB0aGVtZV9kYXJrKCkgKw0KICAgIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlID0gIlNldDIiKQ0KYGBgDQoNClRoZSBncmFwaCBzaG93cyB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gbWlsZWFnZSAobWlsZXMgcGVyIGdhbGxvbikgYW5kIGdyb3NzIGhvcnNlcG93ZXIgb2YgdmVoaWNsZXMsIGRpZmZlcmVudGlhdGVkIGJ5IHRoZSBudW1iZXIgb2YgY3lsaW5kZXJzLiBUaGUgZGF0YSBpcyBmcm9tIHRoZSAxOTc0IE1vdG9yIFRyZW5kIFVTIG1hZ2F6aW5lLiBPbiB0aGUgdmVydGljYWwgYXhpcywgd2UgaGF2ZSBtaWxlcyBwZXIgZ2FsbG9uLCByYW5naW5nIGZyb20gMTAgdG8gMzUuIE9uIHRoZSBob3Jpem9udGFsIGF4aXMsIHdlIGhhdmUgZ3Jvc3MgaG9yc2Vwb3dlciwgcmFuZ2luZyBmcm9tIDUwIHRvIDM1MC4gVGhlIHBvaW50cyBvbiB0aGUgZ3JhcGggYXJlIGNvbG9yLWNvZGVkIGFuZCBzaGFwZWQgdG8gcmVwcmVzZW50IGRpZmZlcmVudCBudW1iZXJzIG9mIGN5bGluZGVyczogZ3JlZW4gZm9yIDQgY3lsaW5kZXJzLCBvcmFuZ2UgZm9yIDYgY3lsaW5kZXJzLCBhbmQgYmx1ZSBmb3IgOCBjeWxpbmRlcnMuDQoNClRoZXJlIGlzIGEgY2xlYXIgaW52ZXJzZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBob3JzZXBvd2VyIGFuZCBtaWxlcyBwZXIgZ2FsbG9uLiBBcyBob3JzZXBvd2VyIGluY3JlYXNlcywgdGhlIG1pbGVzIHBlciBnYWxsb24gdGVuZCB0byBkZWNyZWFzZS4gVGhpcyBpbmRpY2F0ZXMgdGhhdCBtb3JlIHBvd2VyZnVsIGNhcnMgZ2VuZXJhbGx5IGhhdmUgbG93ZXIgZnVlbCBlZmZpY2llbmN5LiBDYXJzIHdpdGggNCBjeWxpbmRlcnMgdGVuZCB0byBoYXZlIGhpZ2hlciBmdWVsIGVmZmljaWVuY3kgKGhpZ2hlciBtcGcpIGFuZCBsb3dlciBob3JzZXBvd2VyLCBjbHVzdGVyaW5nIHRvd2FyZHMgdGhlIHRvcC1sZWZ0IG9mIHRoZSBncmFwaC4gQ2FycyB3aXRoIDYgY3lsaW5kZXJzIGhhdmUgYSBtb2RlcmF0ZSByYW5nZSBvZiBob3JzZXBvd2VyIGFuZCBmdWVsIGVmZmljaWVuY3ksIHBvc2l0aW9uZWQgaW4gdGhlIG1pZGRsZSBvZiB0aGUgZ3JhcGguIENhcnMgd2l0aCA4IGN5bGluZGVycyBnZW5lcmFsbHkgaGF2ZSBoaWdoZXIgaG9yc2Vwb3dlciBhbmQgbG93ZXIgZnVlbCBlZmZpY2llbmN5LCBjbHVzdGVyaW5nIHRvd2FyZHMgdGhlIGJvdHRvbS1yaWdodCBvZiB0aGUgZ3JhcGguDQoNClRoZSBtb3N0IGZ1ZWwtZWZmaWNpZW50IGNhcnMgKGhpZ2hlc3QgbXBnKSBhcmUgdGhvc2Ugd2l0aCA0IGN5bGluZGVycyBhbmQgbG93ZXIgaG9yc2Vwb3dlci4gQ29udmVyc2VseSwgdGhlIGxlYXN0IGZ1ZWwtZWZmaWNpZW50IGNhcnMgYXJlIHRob3NlIHdpdGggOCBjeWxpbmRlcnMgYW5kIGhpZ2hlciBob3JzZXBvd2VyLiBUaGUgZ3JhcGggaGlnaGxpZ2h0cyB0aGUgdHJhZGUtb2ZmIGJldHdlZW4gcGVyZm9ybWFuY2UgKGhvcnNlcG93ZXIpIGFuZCBmdWVsIGVmZmljaWVuY3kgKG1wZykuIEhpZ2hlciBwZXJmb3JtYW5jZSB2ZWhpY2xlcyAobW9yZSBob3JzZXBvd2VyKSB0ZW5kIHRvIHNhY3JpZmljZSBmdWVsIGVmZmljaWVuY3kuDQoNClRoaXMgdmlzdWFsaXphdGlvbiBoZWxwcyBpbiB1bmRlcnN0YW5kaW5nIGhvdyB0aGUgbnVtYmVyIG9mIGN5bGluZGVycyBhbmQgaG9yc2Vwb3dlciBhZmZlY3QgdGhlIGZ1ZWwgZWZmaWNpZW5jeSBvZiB2ZWhpY2xlcywgcHJvdmlkaW5nIHZhbHVhYmxlIGluc2lnaHRzIGZvciBib3RoIGNvbnN1bWVycyBhbmQgbWFudWZhY3R1cmVycy4NCg0KIyMjIyBfNC41IFNjYXR0ZXIgUGxvdHMgXw0KDQpTY2F0dGVyIHBsb3RzIGFyZSBhbiBlc3NlbnRpYWwgdG9vbCBpbiBkYXRhIHZpc3VhbGl6YXRpb24gYW5kIGFuYWx5c2lzLCBvZmZlcmluZyBudW1lcm91cyBiZW5lZml0cyB0aGF0IGVuaGFuY2Ugb3VyIHVuZGVyc3RhbmRpbmcgb2YgZGF0YS4gT25lIG9mIHRoZSBwcmltYXJ5IGFkdmFudGFnZXMgb2Ygc2NhdHRlciBwbG90cyBpcyB0aGVpciBhYmlsaXR5IHRvIHZpc3VhbGl6ZSByZWxhdGlvbnNoaXBzIGJldHdlZW4gdHdvIHF1YW50aXRhdGl2ZSB2YXJpYWJsZXMuIEJ5IHBsb3R0aW5nIGRhdGEgcG9pbnRzIG9uIGEgdHdvLWRpbWVuc2lvbmFsIGdyYXBoLCBzY2F0dGVyIHBsb3RzIGhlbHAgaWRlbnRpZnkgcGF0dGVybnMsIHRyZW5kcywgYW5kIGNvcnJlbGF0aW9ucywgbWFraW5nIGl0IGVhc2llciB0byB1bmRlcnN0YW5kIGhvdyBvbmUgdmFyaWFibGUgYWZmZWN0cyBhbm90aGVyLiBUaGlzIHZpc3VhbCByZXByZXNlbnRhdGlvbiBpcyBjcnVjaWFsIGZvciBtYWtpbmcgZGF0YS1kcml2ZW4gZGVjaXNpb25zIGFuZCBmb3JtaW5nIGh5cG90aGVzZXMuDQoNCmBgYHtyfQ0KDQpnZ3Bsb3QobXRjYXJzLCBhZXMoeCA9IG1wZywgeSA9IHd0LCBzaGFwZSA9IGN5bF9mYWN0b3IsIGNvbG9yID0gY3lsX2ZhY3RvcikpICsNCiAgZ2VvbV9wb2ludChzaXplID0gMykgKyAgIyBTaXplIG9mIHRoZSBwb2ludHMNCiAgbGFicyh0aXRsZSA9ICJSZWxhdGlvbnNoaXAgQmV0d2VlbiBNUEcgYW5kIFdlaWdodCBvZiBDYXJzIiwNCiAgICAgICB4ID0gIk1pbGVzIFBlciBHYWxsb24gKE1QRykiLA0KICAgICAgIHkgPSAiV2VpZ2h0ICgxMDAwIGxicykiLA0KICAgICAgIHNoYXBlID0gIk51bWJlciBvZiBDeWxpbmRlcnMiLA0KICAgICAgIGNvbG9yID0gIk51bWJlciBvZiBDeWxpbmRlcnMiKSArICMgQ3VzdG9tIGxhYmVscw0KICB0aGVtZV9taW5pbWFsKCkgIyBNaW5pbWFsaXN0IHRoZW1lIGZvciBhIGNsZWFuIGxvb2sNCg0KYGBgDQoNClRoZSBzY2F0dGVyIHBsb3QgcmV2ZWFscyBhIG5lZ2F0aXZlIGNvcnJlbGF0aW9uIGJldHdlZW4gbWlsZXMgcGVyIGdhbGxvbiAoTVBHKSBhbmQgdGhlIHdlaWdodCBvZiBjYXJzLiBHZW5lcmFsbHksIGFzIHRoZSB3ZWlnaHQgb2YgdGhlIGNhciBpbmNyZWFzZXMsIHRoZSBNUEcgZGVjcmVhc2VzLiBUaGlzIGluZGljYXRlcyB0aGF0IGhlYXZpZXIgY2FycyB0ZW5kIHRvIGJlIGxlc3MgZnVlbC1lZmZpY2llbnQuIFVuZGVyc3RhbmRpbmcgdGhpcyByZWxhdGlvbnNoaXAgaXMgY3J1Y2lhbCBmb3IgYXNzZXNzaW5nIGhvdyB2ZWhpY2xlIHdlaWdodCBpbXBhY3RzIGZ1ZWwgZWZmaWNpZW5jeS4NCg0KIyMjIyBfNC42IEJveCBQbG90Xw0KDQpBIGJveCBwbG90IGlzIGEgY3J1Y2lhbCB0b29sIGluIGRhdGEgYW5hbHlzaXMgYXMgaXQgdmlzdWFsbHkgc3VtbWFyaXplcyB0aGUgZGlzdHJpYnV0aW9uIG9mIGEgZGF0YXNldCwgaGlnaGxpZ2h0aW5nIHRoZSBtZWRpYW4sIHF1YXJ0aWxlcywgYW5kIHBvdGVudGlhbCBvdXRsaWVycywgd2hpY2ggaGVscHMgaW4gcXVpY2tseSB1bmRlcnN0YW5kaW5nIHRoZSBjZW50cmFsIHRlbmRlbmN5LCBzcHJlYWQsIGFuZCBvdmVyYWxsIHJhbmdlIG9mIHRoZSBkYXRhLCBtYWtpbmcgaXQgZWFzaWVyIHRvIGNvbXBhcmUgbXVsdGlwbGUgZGF0YXNldHMsIGlkZW50aWZ5IGFub21hbGllcywgYW5kIHN1cHBvcnQgaW5mb3JtZWQgZGVjaXNpb24tbWFraW5nIGFjcm9zcyB2YXJpb3VzIGZpZWxkcy4NCg0KDQpgYGB7cn0NCg0KZ2dwbG90KG10Y2FycywgYWVzKHggPSBmYWN0b3IoY3lsKSwgeSA9IG1wZykpICsgDQogIGdlb21fYm94cGxvdCgpICsNCiAgbGFicygNCiAgICB0aXRsZSA9ICJEaXN0cmlidXRpb24gb2YgTWlsZXMgcGVyIEdhbGxvbiBieSBOdW1iZXIgb2YgQ3lsaW5kZXJzIiwNCiAgICB4ID0gIk51bWJlciBvZiBDeWxpbmRlcnMiLA0KICAgIHkgPSAiTWlsZXMgcGVyIEdhbGxvbiINCiAgKSArDQogdGhlbWVfY2xhc3NpYygpDQoNCmBgYA0KVGhlIGJveCBwbG90IGlsbHVzdHJhdGVzIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgbnVtYmVyIG9mIGN5bGluZGVycyBpbiBhIHZlaGljbGUgYW5kIGl0cyBtaWxlcyBwZXIgZ2FsbG9uIChNUEcpIHBlcmZvcm1hbmNlLiBWZWhpY2xlcyB3aXRoIDQgY3lsaW5kZXJzIGhhdmUgYSBtZWRpYW4gTVBHIG9mIGFyb3VuZCAyNSwgd2l0aCBhbiBpbnRlcnF1YXJ0aWxlIHJhbmdlIChJUVIpIGZyb20gYXBwcm94aW1hdGVseSAyMiB0byAzMC4gVmVoaWNsZXMgd2l0aCA2IGN5bGluZGVycyBoYXZlIGEgbWVkaWFuIE1QRyBvZiBhYm91dCAxOCwgd2l0aCBhbiBJUVIgZnJvbSByb3VnaGx5IDE2IHRvIDIwLiBWZWhpY2xlcyB3aXRoIDggY3lsaW5kZXJzIGhhdmUgYSBtZWRpYW4gTVBHIG9mIGFyb3VuZCAxNCwgd2l0aCBhbiBJUVIgZnJvbSBhYm91dCAxMyB0byAxNS4gVGhlIHBsb3QgYWxzbyBoaWdobGlnaHRzIHRoYXQgdmVoaWNsZXMgd2l0aCBmZXdlciBjeWxpbmRlcnMgZ2VuZXJhbGx5IGFjaGlldmUgaGlnaGVyIE1QRywgYW5kIGl0IGlkZW50aWZpZXMgc29tZSBvdXRsaWVycywgcGFydGljdWxhcmx5IGFtb25nIHZlaGljbGVzIHdpdGggbW9yZSBjeWxpbmRlcnMuDQo=