Introduction
The ggplot2
package in R is one of the most popular and
versatile tools for creating stunning visualizations. It follows the
grammar of graphics concept, allowing users to layer
components of a plot in a structured way.
ggplot2
is included as part of the
tidyverse
package collection. When you install and load the
tidyverse
(e.g., install.packages("tidyverse")
and library(tidyverse)
), it automatically includes and
loads ggplot2
along with other core packages like
dplyr
, tidyr
, readr
,
purrr
, and more.
However, we can also install and load ggplot2 separately if you only
need its functionality for data visualization.
Understanding the
Grammar of Graphics
The basic structure of a ggplot
visualization
includes:
Data: The dataset you want to visualize.
Aesthetics (aes): The mappings of variables to
visual properties like x, y, color, size, etc.
Geometries (geom): The type of plot, such as points,
lines, bars, etc.
Creating Your First
Plot
Here is a simple scatter plot using the built-in mtcars dataset:
ggplot(data = mtcars, aes(x = wt, y = mpg)) +
geom_point() +
ggtitle("A simple scatter plot with ggplot()")

data = mtcars
: Specifies the dataset.
aes(x = wt, y = mpg)
: Maps the weight (wt) to the x-axis
and miles per gallon (mpg) to the y-axis.
geom_point()
: Adds points to the plot.
Adding Layers and
Customizing
You can layer additional components to enhance your plot. For
example:
ggplot(data = mtcars, aes(x = wt, y = mpg, color = factor(cyl))) +
geom_point(size = 3) +
geom_smooth(method = "lm", se = FALSE) +
labs(title = "Car Weight vs. MPG", x = "Weight (1000 lbs)", y = "Miles per Gallon", color = "Cylinders") +
ggtitle("A scatter plot \nwith more graphical layers in ggplot") +
theme_minimal()+
theme(plot.title = element_text(hjust = 0.5))

color = factor(cyl)
: Colors the points based on the
number of cylinders.
geom_smooth()
: Adds a linear regression line.
labs()
: Adds titles and axis labels.
theme_minimal()
: Applies a clean theme.
Some Key Elements in them_minima()
- Background
- Removes the panel background (no grid-like boxes around the
plot).
- Uses a white background for the plot.
- Grid Lines
- Displays only horizontal and vertical grid lines for major axis
ticks (no minor grid lines by default).
- Grid lines are subtle (gray and thin), ensuring they don’t overpower
the data visualization.
- Axes
- Keep axis lines simple and clean (thin gray lines).
- Axis ticks are present and minimal.
- Axis labels (x and y) are included with a clean font.
- Text
- Uses a sans-serif font for titles, axis labels, and other text
elements by default.
- Font sizes are balanced for a professional look.
- Legend
- Includes a minimalistic legend box.
- Legend background is removed, showing only the text and
symbols.
- Titles
- Plot titles and subtitles are included, aligned, and spaced
appropriately.
- Facets
- Facet strips (titles for faceted plots) have no background color or
borders, appearing clean and unobtrusive.
Common
Geometries
Here are some commonly used geometries:
ggplot(data = mtcars, aes(x = factor(cyl))) +
geom_bar() +
ggtitle("A simple gray bar plot")

ggplot(data = mtcars, aes(x = mpg)) +
geom_histogram(binwidth = 5, fill = "blue", color = "black")+
ggtitle("A simple histogram using ggplot")

ggplot(data = economics, aes(x = date, y = unemploy)) +
geom_line(color = "red")+
ggtitle("A simple line plot with ggplot")

Faceting
Faceting allows you to create multiple plots based on a factor
variable:
ggplot(data = mtcars, aes(x = wt, y = mpg)) +
geom_point() +
facet_wrap(~ cyl) +
ggtitle("Multi-panel plot in ggplot")

Themes and
Customization
You can modify the appearance of your plot using themes:
ggplot(data = mtcars, aes(x = wt, y = mpg)) +
geom_point() +
theme_classic() +
ggtitle("Scatter plot using base theme_classic()") +
theme(plot.title = element_text(hjust = 0.5))

Here’s an example of using a custom theme in ggplot2:
# Example dataset
data <- data.frame(
x = c("A", "B", "C", "D"),
y = c(3, 7, 2, 8)
)
# Create a plot with a custom theme
p <- ggplot(data, aes(x = x, y = y)) +
geom_col(fill = "steelblue") +
labs(
title = "Custom Theme Example",
x = "Categories",
y = "Values"
) +
theme_minimal(base_size = 14) + # Start with a minimal theme
theme(
plot.title = element_text(face = "bold", hjust = 0.5, color = "darkblue", size = 16),
axis.text = element_text(color = "black"),
axis.title = element_text(face = "bold", size = 14),
panel.grid.major = element_line(color = "gray80"),
panel.grid.minor = element_blank(), # Hide minor gridlines
plot.background = element_rect(fill = "lightgray", color = NA),
panel.background = element_rect(fill = "white"),
legend.position = "none" # Hide legend if not needed
)
# Print the plot
print(p)

Key Features of the Example:
Some Base Themes
This example demonstrates how you can tweak a ggplot
theme to suit your design preferences. There are other base themes like
theme_gray()
, theme_classic()
, or
theme_bw()
in ggplot2:
ggplot1
Default Theme - theme_gray()
In ggplot2, the theme_gray()
is the default theme used
for plots. It provides a light gray background with white grid lines,
offering good readability and focusing attention on the data. Below are
the key elements of theme_gray()
:
ggplot(data, aes(x, y)) +
geom_point() +
theme_gray() +
theme(panel.grid.major = element_line(color = "blue"))

theme_classic()
The theme_classic()
function in the ggplot2 package of R
is used to create a minimalistic theme for plots. It provides a clean
and simple aesthetic by removing unnecessary elements and emphasizing
the plot’s data. Here are the key elements of
theme_classic()
:
- Background
- The plot background is completely white.
- The panel background (behind the plot area) is also white.
- Grid Lines
- Major and minor grid lines are removed, both horizontally and
vertically.
- This gives the plot a cleaner look, focusing on the data points and
axes.
- Axis Lines
- The x-axis and y-axis lines are retained and drawn in black.
- These lines enhance the clarity of the axes without extra
clutter.
- Axis Ticks
- Ticks on the x and y axes are present and remain black.
- The tick marks are short and simple.
- Axis Text
- Labels for both axes (tick labels) are displayed in a standard font
and positioned close to the axis lines.
- Legend
- The legend box is included but has a minimal appearance.
- The background is transparent, and unnecessary decorations are
removed.
- Text and Title
- Plot title, axis labels, and other text elements follow a
straightforward and clean typographic style.
- Text elements can be customized using additional
theme()
modifications.
- Overall Simplicity
- There are no unnecessary borders, shaded regions, or decorative
elements, making the data visualization clean and professional.
This theme is ideal for creating publication-ready figures or when a
minimalist design is desired. It emphasizes data over styling while
retaining the essential visual elements of the plot.
theme_bw()
The theme_bw()
function in ggplot2 is a pre-defined
theme in R used to give plots a clean, black-and-white appearance. It
focuses on a minimalistic style, typically useful for publications or
presentations where color may not be as important. Key elements of
theme_bw()
include
- Background
- The panel background is set to white
(
panel.background = element_rect(fill = "white")
).
- The plot background (
plot.background
) is also white,
creating a clean look.
- Gridlines
- Light grey gridlines (
panel.grid.major
and
panel.grid.minor
) are used, which are slightly visible but
don’t overwhelm the plot.
- Axis
- Axis lines are black
(
axis.line = element_line(color = "black")
), which helps
define the boundaries of the plot.
- Axis text and titles are set to black for clarity.
- Panel Border
- The panel has a black border
(
panel.border = element_rect(color = "black")
).
- Minimalist Aesthetic
- The overall design removes unnecessary elements, keeping the focus
on the data itself.
Legends are placed outside the plot if required and can be styled
further, but they are kept simple in theme_bw()
. You can
further tweak any of these settings using theme()
in
conjunction with theme_bw()
if you need more specific
customization.
Saving Your Plot
To save your plot, use the ggsave()
function:
ggsave("my_plot.png", width = 6, height = 4)
Introducing Interactive
Features
ggplotly()
is a wrapper function from the
plotly package
in R that allows you to convert a
ggplot2
object into an interactive plotly
object. It takes a static ggplot and makes it interactive by adding
tooltips, zoom, and hover functionalities. This is useful when you want
to create more dynamic and engaging visualizations based on
ggplot2 syntax
but with the interactivity features provided
by Plotly
. The following is a simple example.
# need to use functions in ggplot2 and plotly
# library(ggplot2)
# library(plotly)
# Create a ggplot
p <- ggplot(mpg, aes(x = displ, y = hwy, color = class)) +
geom_point() +
ggtitle("Interactive scatter plot with color-coding")
# Convert to interactive plotly plot
ggplotly(p)
This code will generate a plot that behaves interactively, allowing
you to zoom, pan, and hover over data points to see additional
information.
LS0tDQp0aXRsZTogJ0EgVHV0b3JpYWwgb24gZ2dwbG90MiBpbiBSJw0KYXV0aG9yOiAiQ2hlbmcgUGVuZyINCmRhdGU6ICIgV2VzdCBDaGVzdGVyIFVuaXZlcnNpdHkiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6IA0KICAgIHRvYzogeWVzDQogICAgdG9jX2RlcHRoOiA0DQogICAgdG9jX2Zsb2F0OiB5ZXMNCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcw0KICAgIHRvY19jb2xsYXBzZWQ6IHllcw0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIGNvZGVfZG93bmxvYWQ6IHllcw0KICAgIHNtb290aF9zY3JvbGw6IHllcw0KICAgIHRoZW1lOiBsdW1lbg0KICB3b3JkX2RvY3VtZW50OiANCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogNA0KICAgIGZpZ19jYXB0aW9uOiB5ZXMNCiAgICBrZWVwX21kOiB5ZXMNCiAgcGRmX2RvY3VtZW50OiANCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogNA0KICAgIGZpZ19jYXB0aW9uOiB5ZXMNCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcw0KICAgIGZpZ193aWR0aDogMw0KICAgIGZpZ19oZWlnaHQ6IDMNCmVkaXRvcl9vcHRpb25zOiANCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQ0KLS0tDQoNCmBgYHs9aHRtbH0NCg0KPHN0eWxlIHR5cGU9InRleHQvY3NzIj4NCg0KLyogQ2FzY2FkaW5nIFN0eWxlIFNoZWV0cyAoQ1NTKSBpcyBhIHN0eWxlc2hlZXQgbGFuZ3VhZ2UgdXNlZCB0byBkZXNjcmliZSB0aGUgcHJlc2VudGF0aW9uIG9mIGEgZG9jdW1lbnQgd3JpdHRlbiBpbiBIVE1MIG9yIFhNTC4gaXQgaXMgYSBzaW1wbGUgbWVjaGFuaXNtIGZvciBhZGRpbmcgc3R5bGUgKGUuZy4sIGZvbnRzLCBjb2xvcnMsIHNwYWNpbmcpIHRvIFdlYiBkb2N1bWVudHMuICovDQoNCmgxLnRpdGxlIHsgIC8qIFRpdGxlIC0gZm9udCBzcGVjaWZpY2F0aW9ucyBvZiB0aGUgcmVwb3J0IHRpdGxlICovDQogIGZvbnQtc2l6ZTogMjRweDsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogIGNvbG9yOiBkYXJrcmVkOw0KICB0ZXh0LWFsaWduOiBjZW50ZXI7DQogIGZvbnQtZmFtaWx5OiAiR2lsbCBTYW5zIiwgc2Fucy1zZXJpZjsNCn0NCmg0LmF1dGhvciB7IC8qIEhlYWRlciA0IC0gZm9udCBzcGVjaWZpY2F0aW9ucyBmb3IgYXV0aG9ycyAgKi8NCiAgZm9udC1zaXplOiAxOHB4Ow0KICBmb250LWZhbWlseTogc3lzdGVtLXVpOw0KICBmb250LXdlaWdodDogYm9sZDsNCiAgY29sb3I6IG5hdnk7DQogIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCmg0LmRhdGUgeyAvKiBIZWFkZXIgNCAtIGZvbnQgc3BlY2lmaWNhdGlvbnMgZm9yIHRoZSBkYXRlICAqLw0KICBmb250LXNpemU6IDE4cHg7DQogIGZvbnQtZmFtaWx5OiBzeXN0ZW0tdWk7DQogIGNvbG9yOiBEYXJrQmx1ZTsNCiAgdGV4dC1hbGlnbjogY2VudGVyOw0KICBmb250LXdlaWdodDogYm9sZDsNCn0NCmgxIHsgLyogSGVhZGVyIDEgLSBmb250IHNwZWNpZmljYXRpb25zIGZvciBsZXZlbCAxIHNlY3Rpb24gdGl0bGUgICovDQogICAgZm9udC1zaXplOiAyMHB4Ow0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBuYXZ5Ow0KICAgIHRleHQtYWxpZ246IGNlbnRlcjsNCiAgICBmb250LXdlaWdodDogYm9sZDsNCn0NCmgyIHsgLyogSGVhZGVyIDIgLSBmb250IHNwZWNpZmljYXRpb25zIGZvciBsZXZlbCAyIHNlY3Rpb24gdGl0bGUgKi8NCiAgICBmb250LXNpemU6IDE4cHg7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IG5hdnk7DQogICAgdGV4dC1hbGlnbjogbGVmdDsNCiAgICBmb250LXdlaWdodDogYm9sZDsNCn0NCg0KaDMgeyAvKiBIZWFkZXIgMyAtIGZvbnQgc3BlY2lmaWNhdGlvbnMgb2YgbGV2ZWwgMyBzZWN0aW9uIHRpdGxlICAqLw0KICAgIGZvbnQtc2l6ZTogMTZweDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogbmF2eTsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KDQpoNCB7IC8qIEhlYWRlciA0IC0gZm9udCBzcGVjaWZpY2F0aW9ucyBvZiBsZXZlbCA0IHNlY3Rpb24gdGl0bGUgICovDQogICAgZm9udC1zaXplOiAxNHB4Ow0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBkYXJrcmVkOw0KICAgIHRleHQtYWxpZ246IGxlZnQ7DQp9DQoNCmJvZHkgeyBiYWNrZ3JvdW5kLWNvbG9yOndoaXRlOyB9DQoNCi5oaWdobGlnaHRtZSB7IGJhY2tncm91bmQtY29sb3I6eWVsbG93OyB9DQoNCnAgeyBiYWNrZ3JvdW5kLWNvbG9yOndoaXRlOyB9DQoNCjwvc3R5bGU+DQpgYGANCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQojIGNvZGUgY2h1bmsgc3BlY2lmaWVzIHdoZXRoZXIgdGhlIFIgY29kZSwgd2FybmluZ3MsIGFuZCBvdXRwdXQgDQojIHdpbGwgYmUgaW5jbHVkZWQgaW4gdGhlIG91dHB1dCBmaWxlcy4NCmlmICghcmVxdWlyZSgia25pdHIiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygia25pdHIiKQ0KICAgbGlicmFyeShrbml0cikNCn0NCmlmICghcmVxdWlyZSgidGlkeXZlcnNlIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoInRpZHl2ZXJzZSIpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCn0NCmlmICghcmVxdWlyZSgicGxvdGx5IikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoInBsb3RseSIpDQpsaWJyYXJ5KHBsb3RseSkNCn0NCg0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgd2FybmluZyA9IEZBTFNFLCAgICANCiAgICAgICAgICAgICAgICAgICAgICByZXN1bHRzID0gVFJVRSwgICAgIA0KICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSwNCiAgICAgICAgICAgICAgICAgICAgICBjb21tZW50ID0gTkEpICANCmBgYA0KDQpcDQoNClwNCg0KDQojIEludHJvZHVjdGlvbg0KDQpUaGUgYGdncGxvdDJgIHBhY2thZ2UgaW4gUiBpcyBvbmUgb2YgdGhlIG1vc3QgcG9wdWxhciBhbmQgdmVyc2F0aWxlIHRvb2xzIGZvciBjcmVhdGluZyBzdHVubmluZyB2aXN1YWxpemF0aW9ucy4gSXQgZm9sbG93cyB0aGUgKipncmFtbWFyIG9mIGdyYXBoaWNzKiogY29uY2VwdCwgYWxsb3dpbmcgdXNlcnMgdG8gbGF5ZXIgY29tcG9uZW50cyBvZiBhIHBsb3QgaW4gYSBzdHJ1Y3R1cmVkIHdheS4gDQoNCmBnZ3Bsb3QyYCBpcyBpbmNsdWRlZCBhcyBwYXJ0IG9mIHRoZSBgdGlkeXZlcnNlYCBwYWNrYWdlIGNvbGxlY3Rpb24uIFdoZW4geW91IGluc3RhbGwgYW5kIGxvYWQgdGhlIGB0aWR5dmVyc2VgIChlLmcuLCBgaW5zdGFsbC5wYWNrYWdlcygidGlkeXZlcnNlIilgIGFuZCBgbGlicmFyeSh0aWR5dmVyc2UpYCksIGl0IGF1dG9tYXRpY2FsbHkgaW5jbHVkZXMgYW5kIGxvYWRzIGBnZ3Bsb3QyYCBhbG9uZyB3aXRoIG90aGVyIGNvcmUgcGFja2FnZXMgbGlrZSBgZHBseXJgLCBgdGlkeXJgLCBgcmVhZHJgLCBgcHVycnJgLCBhbmQgbW9yZS4NCg0KSG93ZXZlciwgd2UgY2FuIGFsc28gaW5zdGFsbCBhbmQgbG9hZCBnZ3Bsb3QyIHNlcGFyYXRlbHkgaWYgeW91IG9ubHkgbmVlZCBpdHMgZnVuY3Rpb25hbGl0eSBmb3IgZGF0YSB2aXN1YWxpemF0aW9uLg0KDQoNCiMgVW5kZXJzdGFuZGluZyB0aGUgR3JhbW1hciBvZiBHcmFwaGljcw0KDQpUaGUgYmFzaWMgc3RydWN0dXJlIG9mIGEgYGdncGxvdGAgdmlzdWFsaXphdGlvbiBpbmNsdWRlczoNCg0KKipEYXRhKio6IFRoZSBkYXRhc2V0IHlvdSB3YW50IHRvIHZpc3VhbGl6ZS4NCg0KKipBZXN0aGV0aWNzIChhZXMpKio6IFRoZSBtYXBwaW5ncyBvZiB2YXJpYWJsZXMgdG8gdmlzdWFsIHByb3BlcnRpZXMgbGlrZSB4LCB5LCBjb2xvciwgc2l6ZSwgZXRjLg0KDQoqKkdlb21ldHJpZXMgKGdlb20pKio6IFRoZSB0eXBlIG9mIHBsb3QsIHN1Y2ggYXMgcG9pbnRzLCBsaW5lcywgYmFycywgZXRjLg0KDQoNCg0KIyBDcmVhdGluZyBZb3VyIEZpcnN0IFBsb3QNCg0KSGVyZSBpcyBhIHNpbXBsZSBzY2F0dGVyIHBsb3QgdXNpbmcgdGhlIGJ1aWx0LWluIG10Y2FycyBkYXRhc2V0Og0KDQoNCmBgYHtyfQ0KZ2dwbG90KGRhdGEgPSBtdGNhcnMsIGFlcyh4ID0gd3QsIHkgPSBtcGcpKSArDQogIGdlb21fcG9pbnQoKSArIA0KICBnZ3RpdGxlKCJBIHNpbXBsZSBzY2F0dGVyIHBsb3Qgd2l0aCBnZ3Bsb3QoKSIpDQpgYGANCg0KYGRhdGEgPSBtdGNhcnNgOiBTcGVjaWZpZXMgdGhlIGRhdGFzZXQuDQoNCmBhZXMoeCA9IHd0LCB5ID0gbXBnKWA6IE1hcHMgdGhlIHdlaWdodCAod3QpIHRvIHRoZSB4LWF4aXMgYW5kIG1pbGVzIHBlciBnYWxsb24gKG1wZykgdG8gdGhlIHktYXhpcy4NCg0KYGdlb21fcG9pbnQoKWA6IEFkZHMgcG9pbnRzIHRvIHRoZSBwbG90Lg0KDQoNCiMgQWRkaW5nIExheWVycyBhbmQgQ3VzdG9taXppbmcNCg0KWW91IGNhbiBsYXllciBhZGRpdGlvbmFsIGNvbXBvbmVudHMgdG8gZW5oYW5jZSB5b3VyIHBsb3QuIEZvciBleGFtcGxlOg0KDQpgYGB7cn0NCmdncGxvdChkYXRhID0gbXRjYXJzLCBhZXMoeCA9IHd0LCB5ID0gbXBnLCBjb2xvciA9IGZhY3RvcihjeWwpKSkgKw0KICBnZW9tX3BvaW50KHNpemUgPSAzKSArDQogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UpICsNCiAgbGFicyh0aXRsZSA9ICJDYXIgV2VpZ2h0IHZzLiBNUEciLCB4ID0gIldlaWdodCAoMTAwMCBsYnMpIiwgeSA9ICJNaWxlcyBwZXIgR2FsbG9uIiwgY29sb3IgPSAiQ3lsaW5kZXJzIikgKw0KICBnZ3RpdGxlKCJBIHNjYXR0ZXIgcGxvdCBcbndpdGggbW9yZSBncmFwaGljYWwgbGF5ZXJzIGluIGdncGxvdCIpICsNCiAgdGhlbWVfbWluaW1hbCgpKw0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkNCmBgYA0KDQpgY29sb3IgPSBmYWN0b3IoY3lsKWA6IENvbG9ycyB0aGUgcG9pbnRzIGJhc2VkIG9uIHRoZSBudW1iZXIgb2YgY3lsaW5kZXJzLg0KDQpgZ2VvbV9zbW9vdGgoKWA6IEFkZHMgYSBsaW5lYXIgcmVncmVzc2lvbiBsaW5lLg0KDQpgbGFicygpYDogQWRkcyB0aXRsZXMgYW5kIGF4aXMgbGFiZWxzLg0KDQpgdGhlbWVfbWluaW1hbCgpYDogQXBwbGllcyBhIGNsZWFuIHRoZW1lLiANCg0KXA0KDQoqKlNvbWUgS2V5IEVsZW1lbnRzIGluIHRoZW1fbWluaW1hKCkqKg0KDQoqICpCYWNrZ3JvdW5kKg0KICArIFJlbW92ZXMgdGhlIHBhbmVsIGJhY2tncm91bmQgKG5vIGdyaWQtbGlrZSBib3hlcyBhcm91bmQgdGhlIHBsb3QpLg0KICArIFVzZXMgYSB3aGl0ZSBiYWNrZ3JvdW5kIGZvciB0aGUgcGxvdC4NCg0KKiAqR3JpZCBMaW5lcyoNCiAgKyBEaXNwbGF5cyBvbmx5IGhvcml6b250YWwgYW5kIHZlcnRpY2FsIGdyaWQgbGluZXMgZm9yIG1ham9yIGF4aXMgdGlja3MgKG5vIG1pbm9yIGdyaWQgbGluZXMgYnkgZGVmYXVsdCkuDQogICsgR3JpZCBsaW5lcyBhcmUgc3VidGxlIChncmF5IGFuZCB0aGluKSwgZW5zdXJpbmcgdGhleSBkb24ndCBvdmVycG93ZXIgdGhlIGRhdGEgdmlzdWFsaXphdGlvbi4NCg0KKiAqQXhlcyoNCiAgKyBLZWVwIGF4aXMgbGluZXMgc2ltcGxlIGFuZCBjbGVhbiAodGhpbiBncmF5IGxpbmVzKS4NCiAgKyBBeGlzIHRpY2tzIGFyZSBwcmVzZW50IGFuZCBtaW5pbWFsLg0KICArIEF4aXMgbGFiZWxzICh4IGFuZCB5KSBhcmUgaW5jbHVkZWQgd2l0aCBhIGNsZWFuIGZvbnQuDQoNCiogKlRleHQqDQogICsgVXNlcyBhIHNhbnMtc2VyaWYgZm9udCBmb3IgdGl0bGVzLCBheGlzIGxhYmVscywgYW5kIG90aGVyIHRleHQgZWxlbWVudHMgYnkgZGVmYXVsdC4NCiAgKyBGb250IHNpemVzIGFyZSBiYWxhbmNlZCBmb3IgYSBwcm9mZXNzaW9uYWwgbG9vay4NCg0KKiAqTGVnZW5kKg0KICArIEluY2x1ZGVzIGEgbWluaW1hbGlzdGljIGxlZ2VuZCBib3guDQogICsgTGVnZW5kIGJhY2tncm91bmQgaXMgcmVtb3ZlZCwgc2hvd2luZyBvbmx5IHRoZSB0ZXh0IGFuZCBzeW1ib2xzLg0KDQoqICpUaXRsZXMqDQogICsgUGxvdCB0aXRsZXMgYW5kIHN1YnRpdGxlcyBhcmUgaW5jbHVkZWQsIGFsaWduZWQsIGFuZCBzcGFjZWQgYXBwcm9wcmlhdGVseS4NCg0KKiAqRmFjZXRzKg0KICArIEZhY2V0IHN0cmlwcyAodGl0bGVzIGZvciBmYWNldGVkIHBsb3RzKSBoYXZlIG5vIGJhY2tncm91bmQgY29sb3Igb3IgYm9yZGVycywgYXBwZWFyaW5nIGNsZWFuIGFuZCB1bm9idHJ1c2l2ZS4NCg0KXA0KDQojIyBDb21tb24gR2VvbWV0cmllcw0KDQpIZXJlIGFyZSBzb21lIGNvbW1vbmx5IHVzZWQgZ2VvbWV0cmllczoNCg0KKiBCYXIgUGxvdCANCg0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IG10Y2FycywgYWVzKHggPSBmYWN0b3IoY3lsKSkpICsNCiAgZ2VvbV9iYXIoKSArIA0KICBnZ3RpdGxlKCJBIHNpbXBsZSBncmF5IGJhciBwbG90IikNCmBgYA0KDQoqIEhpc3RvZ3JhbToNCg0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IG10Y2FycywgYWVzKHggPSBtcGcpKSArDQogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gNSwgZmlsbCA9ICJibHVlIiwgY29sb3IgPSAiYmxhY2siKSsNCiAgZ2d0aXRsZSgiQSBzaW1wbGUgaGlzdG9ncmFtIHVzaW5nIGdncGxvdCIpDQpgYGANCg0KKiBMaW5lIFBsb3Q6DQoNCmBgYHtyfQ0KZ2dwbG90KGRhdGEgPSBlY29ub21pY3MsIGFlcyh4ID0gZGF0ZSwgeSA9IHVuZW1wbG95KSkgKw0KICBnZW9tX2xpbmUoY29sb3IgPSAicmVkIikrDQogIGdndGl0bGUoIkEgc2ltcGxlIGxpbmUgcGxvdCB3aXRoIGdncGxvdCIpDQpgYGANCg0KIyAgRmFjZXRpbmcNCg0KRmFjZXRpbmcgYWxsb3dzIHlvdSB0byBjcmVhdGUgbXVsdGlwbGUgcGxvdHMgYmFzZWQgb24gYSBmYWN0b3IgdmFyaWFibGU6DQoNCmBgYHtyfQ0KZ2dwbG90KGRhdGEgPSBtdGNhcnMsIGFlcyh4ID0gd3QsIHkgPSBtcGcpKSArDQogIGdlb21fcG9pbnQoKSArDQogIGZhY2V0X3dyYXAofiBjeWwpICsNCiAgZ2d0aXRsZSgiTXVsdGktcGFuZWwgcGxvdCBpbiBnZ3Bsb3QiKQ0KYGBgDQoNCg0KIyBUaGVtZXMgYW5kIEN1c3RvbWl6YXRpb24NCg0KWW91IGNhbiBtb2RpZnkgdGhlIGFwcGVhcmFuY2Ugb2YgeW91ciBwbG90IHVzaW5nIHRoZW1lczoNCg0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IG10Y2FycywgYWVzKHggPSB3dCwgeSA9IG1wZykpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgdGhlbWVfY2xhc3NpYygpICsNCiAgZ2d0aXRsZSgiU2NhdHRlciBwbG90IHVzaW5nIGJhc2UgdGhlbWVfY2xhc3NpYygpIikgKyANCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpDQpgYGANCg0KDQpIZXJl4oCZcyBhbiBleGFtcGxlIG9mIHVzaW5nIGEgY3VzdG9tIHRoZW1lIGluIGdncGxvdDI6DQoNCmBgYHtyfQ0KIyBFeGFtcGxlIGRhdGFzZXQNCmRhdGEgPC0gZGF0YS5mcmFtZSgNCiAgeCA9IGMoIkEiLCAiQiIsICJDIiwgIkQiKSwNCiAgeSA9IGMoMywgNywgMiwgOCkNCikNCg0KIyBDcmVhdGUgYSBwbG90IHdpdGggYSBjdXN0b20gdGhlbWUNCnAgPC0gZ2dwbG90KGRhdGEsIGFlcyh4ID0geCwgeSA9IHkpKSArDQogIGdlb21fY29sKGZpbGwgPSAic3RlZWxibHVlIikgKw0KICBsYWJzKA0KICAgIHRpdGxlID0gIkN1c3RvbSBUaGVtZSBFeGFtcGxlIiwNCiAgICB4ID0gIkNhdGVnb3JpZXMiLA0KICAgIHkgPSAiVmFsdWVzIg0KICApICsNCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxNCkgKyAgIyBTdGFydCB3aXRoIGEgbWluaW1hbCB0aGVtZQ0KICB0aGVtZSgNCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIGhqdXN0ID0gMC41LCBjb2xvciA9ICJkYXJrYmx1ZSIsIHNpemUgPSAxNiksDQogICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KGNvbG9yID0gImJsYWNrIiksDQogICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBzaXplID0gMTQpLA0KICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2xpbmUoY29sb3IgPSAiZ3JheTgwIiksDQogICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwgIyBIaWRlIG1pbm9yIGdyaWRsaW5lcw0KICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gImxpZ2h0Z3JheSIsIGNvbG9yID0gTkEpLA0KICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ3aGl0ZSIpLA0KICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiAgIyBIaWRlIGxlZ2VuZCBpZiBub3QgbmVlZGVkDQogICkNCg0KIyBQcmludCB0aGUgcGxvdA0KcHJpbnQocCkNCmBgYA0KDQoNCktleSBGZWF0dXJlcyBvZiB0aGUgRXhhbXBsZToNCg0KKiBCYXNlIFRoZW1lOiBUaGUgYHRoZW1lX21pbmltYWwoKWAgaXMgdXNlZCBhcyBhIHN0YXJ0aW5nIHBvaW50Lg0KDQoqICoqQ3VzdG9taXphdGlvbnMqKg0KICArIFRpdGxlIGlzIGJvbGQsIGNlbnRlcmVkLCBhbmQgY29sb3JlZC4NCiAgKyBHcmlkbGluZXMgYW5kIGF4aXMgdGl0bGVzIGFyZSBzdHlsZWQuDQogICsgVGhlIGJhY2tncm91bmQgaXMgY3VzdG9taXplZCB3aXRoIGBwbG90LmJhY2tncm91bmRgIGFuZCBgcGFuZWwuYmFja2dyb3VuZGAuDQogICsgTWlub3IgZ3JpZGxpbmVzIGFyZSByZW1vdmVkIGZvciBzaW1wbGljaXR5Lg0KDQoqIExlZ2VuZDogSGlkZGVuIGFzIHRoaXMgcGxvdCBkb2VzbuKAmXQgbmVlZCBvbmUuDQoNCg0KIyBTb21lIEJhc2UgVGhlbWVzDQoNCg0KVGhpcyBleGFtcGxlIGRlbW9uc3RyYXRlcyBob3cgeW91IGNhbiB0d2VhayBhIGBnZ3Bsb3RgIHRoZW1lIHRvIHN1aXQgeW91ciBkZXNpZ24gcHJlZmVyZW5jZXMuIFRoZXJlIGFyZSBvdGhlciBiYXNlIHRoZW1lcyBsaWtlIGB0aGVtZV9ncmF5KClgLCBgdGhlbWVfY2xhc3NpYygpYCwgb3IgYHRoZW1lX2J3KClgIGluIGdncGxvdDI6DQoNCiMjIGBnZ3Bsb3QxYCBEZWZhdWx0IFRoZW1lIC0gYHRoZW1lX2dyYXkoKWANCg0KSW4gZ2dwbG90MiwgdGhlIGB0aGVtZV9ncmF5KClgIGlzIHRoZSBkZWZhdWx0IHRoZW1lIHVzZWQgZm9yIHBsb3RzLiBJdCBwcm92aWRlcyBhIGxpZ2h0IGdyYXkgYmFja2dyb3VuZCB3aXRoIHdoaXRlIGdyaWQgbGluZXMsIG9mZmVyaW5nIGdvb2QgcmVhZGFiaWxpdHkgYW5kIGZvY3VzaW5nIGF0dGVudGlvbiBvbiB0aGUgZGF0YS4gQmVsb3cgYXJlIHRoZSBrZXkgZWxlbWVudHMgb2YgYHRoZW1lX2dyYXkoKWA6DQoNCiogQmFja2dyb3VuZA0KDQogICArIFBsb3QgYmFja2dyb3VuZDogTGlnaHQgZ3JheSBjb2xvciAoI0YwRjBGMCkuDQogICArIFBhbmVsIGJhY2tncm91bmQ6IEEgc2xpZ2h0bHkgbGlnaHRlciBncmF5IGNvbG9yICgjRTZFNkU2KS4NCg0KKiBHcmlkIExpbmVzDQoNCiAgICsgTWFqb3IgZ3JpZCBsaW5lczogV2hpdGUgbGluZXMgZm9yIGJvdGggeCBhbmQgeSBheGVzLg0KICAgKyBNaW5vciBncmlkIGxpbmVzOiBUaGlubmVyIHdoaXRlIGxpbmVzIGZvciBib3RoIHggYW5kIHkgYXhlcyAobGVzcyBwcm9taW5lbnQgdGhhbiBtYWpvciBncmlkIGxpbmVzKS4NCg0KKiBBeGlzIEVsZW1lbnRzDQoNCiAgICsgQXhpcyB0ZXh0OiBCbGFjayB0ZXh0IHdpdGggZGVmYXVsdCBhbGlnbm1lbnQuDQogICArIEF4aXMgdGl0bGU6IEJvbGQgYmxhY2sgdGV4dCBmb3IgYXhpcyBsYWJlbHMuDQogICArIEF4aXMgdGlja3M6IEJsYWNrIHRpY2sgbWFya3MuDQoNCiogVGl0bGUgYW5kIFN1YnRpdGxlDQoNCiAgICsgUGxvdCB0aXRsZTogQ2VudGVyZWQgYXQgdGhlIHRvcCwgYm9sZCBibGFjayB0ZXh0Lg0KICAgKyBTdWJ0aXRsZTogU2xpZ2h0bHkgc21hbGxlciwgcGxhaW4gYmxhY2sgdGV4dCwgcG9zaXRpb25lZCBiZWxvdyB0aGUgdGl0bGUuDQoNCiogTGVnZW5kDQoNCiAgICsgQmFja2dyb3VuZDogVHJhbnNwYXJlbnQuDQogICArIFRleHQ6IEJsYWNrLg0KICAgKyBLZXk6IEdyYXkgcmVjdGFuZ2xlcyAobWF0Y2hpbmcgdGhlIHBhbmVsIGJhY2tncm91bmQpLg0KICAgKyBQb3NpdGlvbjogQnkgZGVmYXVsdCwgcGxhY2VkIGluc2lkZSB0aGUgcGxvdCBhcmVhLg0KDQoqIFRleHQgU3R5bGluZw0KDQogICArIEZvbnRzLCBzaXplcywgYW5kIHN0eWxlcyAoZS5nLiwgYm9sZCBmb3IgdGl0bGVzKSBmb2xsb3cgdGhlIGRlZmF1bHQgZ2dwbG90MiBzZXR0aW5ncy4NCiAgICsgQmFzZSBzaXplOiAxMSAobW9kaWZpYWJsZSB2aWEgYHRoZW1lX2dyYXkoYmFzZV9zaXplID0gLi4uKWApLg0KDQoqIEZhY2V0IEVsZW1lbnRzDQoNCiAgICsgRmFjZXQgYmFja2dyb3VuZDogVHJhbnNwYXJlbnQgb3IgbGlnaHQgZ3JheS4NCiAgICsgRmFjZXQgdGV4dDogQmxhY2ssIHR5cGljYWxseSBhbGlnbmVkIHRvIHRoZSBjZW50ZXIuDQoNCg0KKiAqKkN1c3RvbWl6aW5nIHRoZW1lX2dyYXkoKSoqOiBUbyBtb2RpZnkgb3IgZXh0ZW5kIGl0cyBlbGVtZW50cywgeW91IGNhbjoNCg0KICArIFVzZSBpdCBhcyBhIHN0YXJ0aW5nIHBvaW50OiBgdGhlbWVfZ3JheShiYXNlX3NpemUgPSAxMiwgYmFzZV9mYW1pbHkgPSAic2VyaWYiKWAuDQogICsgQ29tYmluZSBpdCB3aXRoIGB0aGVtZSgpYCBmb3Igc3BlY2lmaWMgY2hhbmdlczoNCg0KYGBge3J9DQpnZ3Bsb3QoZGF0YSwgYWVzKHgsIHkpKSArDQogIGdlb21fcG9pbnQoKSArDQogIHRoZW1lX2dyYXkoKSArDQogIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2xpbmUoY29sb3IgPSAiYmx1ZSIpKQ0KYGBgICANCiAgDQogIA0KXA0KDQojIyBgdGhlbWVfY2xhc3NpYygpYA0KDQpUaGUgYHRoZW1lX2NsYXNzaWMoKWAgZnVuY3Rpb24gaW4gdGhlIGdncGxvdDIgcGFja2FnZSBvZiBSIGlzIHVzZWQgdG8gY3JlYXRlIGEgbWluaW1hbGlzdGljIHRoZW1lIGZvciBwbG90cy4gSXQgcHJvdmlkZXMgYSBjbGVhbiBhbmQgc2ltcGxlIGFlc3RoZXRpYyBieSByZW1vdmluZyB1bm5lY2Vzc2FyeSBlbGVtZW50cyBhbmQgZW1waGFzaXppbmcgdGhlIHBsb3QncyBkYXRhLiBIZXJlIGFyZSB0aGUga2V5IGVsZW1lbnRzIG9mIGB0aGVtZV9jbGFzc2ljKClgOg0KDQoqIEJhY2tncm91bmQNCiAgKyBUaGUgcGxvdCBiYWNrZ3JvdW5kIGlzIGNvbXBsZXRlbHkgd2hpdGUuDQogICsgVGhlIHBhbmVsIGJhY2tncm91bmQgKGJlaGluZCB0aGUgcGxvdCBhcmVhKSBpcyBhbHNvIHdoaXRlLg0KDQoqIEdyaWQgTGluZXMNCiAgKyBNYWpvciBhbmQgbWlub3IgZ3JpZCBsaW5lcyBhcmUgcmVtb3ZlZCwgYm90aCBob3Jpem9udGFsbHkgYW5kIHZlcnRpY2FsbHkuDQogICsgVGhpcyBnaXZlcyB0aGUgcGxvdCBhIGNsZWFuZXIgbG9vaywgZm9jdXNpbmcgb24gdGhlIGRhdGEgcG9pbnRzIGFuZCBheGVzLg0KDQoqIEF4aXMgTGluZXMNCiAgKyBUaGUgeC1heGlzIGFuZCB5LWF4aXMgbGluZXMgYXJlIHJldGFpbmVkIGFuZCBkcmF3biBpbiBibGFjay4NCiAgKyBUaGVzZSBsaW5lcyBlbmhhbmNlIHRoZSBjbGFyaXR5IG9mIHRoZSBheGVzIHdpdGhvdXQgZXh0cmEgY2x1dHRlci4NCg0KKiBBeGlzIFRpY2tzDQogICsgVGlja3Mgb24gdGhlIHggYW5kIHkgYXhlcyBhcmUgcHJlc2VudCBhbmQgcmVtYWluIGJsYWNrLg0KICArIFRoZSB0aWNrIG1hcmtzIGFyZSBzaG9ydCBhbmQgc2ltcGxlLg0KDQoqIEF4aXMgVGV4dA0KICArIExhYmVscyBmb3IgYm90aCBheGVzICh0aWNrIGxhYmVscykgYXJlIGRpc3BsYXllZCBpbiBhIHN0YW5kYXJkIGZvbnQgYW5kIHBvc2l0aW9uZWQgY2xvc2UgdG8gdGhlIGF4aXMgbGluZXMuDQoNCiogTGVnZW5kDQogICsgVGhlIGxlZ2VuZCBib3ggaXMgaW5jbHVkZWQgYnV0IGhhcyBhIG1pbmltYWwgYXBwZWFyYW5jZS4NCiAgKyBUaGUgYmFja2dyb3VuZCBpcyB0cmFuc3BhcmVudCwgYW5kIHVubmVjZXNzYXJ5IGRlY29yYXRpb25zIGFyZSByZW1vdmVkLg0KDQoqIFRleHQgYW5kIFRpdGxlDQogICsgUGxvdCB0aXRsZSwgYXhpcyBsYWJlbHMsIGFuZCBvdGhlciB0ZXh0IGVsZW1lbnRzIGZvbGxvdyBhIHN0cmFpZ2h0Zm9yd2FyZCBhbmQgY2xlYW4gdHlwb2dyYXBoaWMgc3R5bGUuDQogICsgVGV4dCBlbGVtZW50cyBjYW4gYmUgY3VzdG9taXplZCB1c2luZyBhZGRpdGlvbmFsIGB0aGVtZSgpYCBtb2RpZmljYXRpb25zLg0KDQoqIE92ZXJhbGwgU2ltcGxpY2l0eQ0KICArIFRoZXJlIGFyZSBubyB1bm5lY2Vzc2FyeSBib3JkZXJzLCBzaGFkZWQgcmVnaW9ucywgb3IgZGVjb3JhdGl2ZSBlbGVtZW50cywgbWFraW5nIHRoZSBkYXRhIHZpc3VhbGl6YXRpb24gY2xlYW4gYW5kIHByb2Zlc3Npb25hbC4NCiAgDQogIA0KVGhpcyB0aGVtZSBpcyBpZGVhbCBmb3IgY3JlYXRpbmcgcHVibGljYXRpb24tcmVhZHkgZmlndXJlcyBvciB3aGVuIGEgbWluaW1hbGlzdCBkZXNpZ24gaXMgZGVzaXJlZC4gSXQgZW1waGFzaXplcyBkYXRhIG92ZXIgc3R5bGluZyB3aGlsZSByZXRhaW5pbmcgdGhlIGVzc2VudGlhbCB2aXN1YWwgZWxlbWVudHMgb2YgdGhlIHBsb3QuDQoNCg0KIyMgYHRoZW1lX2J3KClgDQoNClRoZSBgdGhlbWVfYncoKWAgZnVuY3Rpb24gaW4gZ2dwbG90MiBpcyBhIHByZS1kZWZpbmVkIHRoZW1lIGluIFIgdXNlZCB0byBnaXZlIHBsb3RzIGEgY2xlYW4sIGJsYWNrLWFuZC13aGl0ZSBhcHBlYXJhbmNlLiBJdCBmb2N1c2VzIG9uIGEgbWluaW1hbGlzdGljIHN0eWxlLCB0eXBpY2FsbHkgdXNlZnVsIGZvciBwdWJsaWNhdGlvbnMgb3IgcHJlc2VudGF0aW9ucyB3aGVyZSBjb2xvciBtYXkgbm90IGJlIGFzIGltcG9ydGFudC4gS2V5IGVsZW1lbnRzIG9mIGB0aGVtZV9idygpYCBpbmNsdWRlIA0KDQoqIEJhY2tncm91bmQgDQogICsgVGhlIHBhbmVsIGJhY2tncm91bmQgaXMgc2V0IHRvIHdoaXRlIChgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIndoaXRlIilgKS4NCiAgKyBUaGUgcGxvdCBiYWNrZ3JvdW5kIChgcGxvdC5iYWNrZ3JvdW5kYCkgaXMgYWxzbyB3aGl0ZSwgY3JlYXRpbmcgYSBjbGVhbiBsb29rLg0KDQoqIEdyaWRsaW5lcyANCiAgKyBMaWdodCBncmV5IGdyaWRsaW5lcyAoYHBhbmVsLmdyaWQubWFqb3JgIGFuZCBgcGFuZWwuZ3JpZC5taW5vcmApIGFyZSB1c2VkLCB3aGljaCBhcmUgc2xpZ2h0bHkgdmlzaWJsZSBidXQgZG9u4oCZdCBvdmVyd2hlbG0gdGhlIHBsb3QuDQoNCiogQXhpcw0KICArIEF4aXMgbGluZXMgYXJlIGJsYWNrIChgYXhpcy5saW5lID0gZWxlbWVudF9saW5lKGNvbG9yID0gImJsYWNrIilgKSwgd2hpY2ggaGVscHMgZGVmaW5lIHRoZSBib3VuZGFyaWVzIG9mIHRoZSBwbG90Lg0KICArIEF4aXMgdGV4dCBhbmQgdGl0bGVzIGFyZSBzZXQgdG8gYmxhY2sgZm9yIGNsYXJpdHkuDQoNCiogUGFuZWwgQm9yZGVyDQogICsgVGhlIHBhbmVsIGhhcyBhIGJsYWNrIGJvcmRlciAoYHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvciA9ICJibGFjayIpYCkuDQoNCiogTWluaW1hbGlzdCBBZXN0aGV0aWMgDQogICsgVGhlIG92ZXJhbGwgZGVzaWduIHJlbW92ZXMgdW5uZWNlc3NhcnkgZWxlbWVudHMsIGtlZXBpbmcgdGhlIGZvY3VzIG9uIHRoZSBkYXRhIGl0c2VsZi4NCg0KTGVnZW5kcyBhcmUgcGxhY2VkIG91dHNpZGUgdGhlIHBsb3QgaWYgcmVxdWlyZWQgYW5kIGNhbiBiZSBzdHlsZWQgZnVydGhlciwgYnV0IHRoZXkgYXJlIGtlcHQgc2ltcGxlIGluIGB0aGVtZV9idygpYC4NCllvdSBjYW4gZnVydGhlciB0d2VhayBhbnkgb2YgdGhlc2Ugc2V0dGluZ3MgdXNpbmcgYHRoZW1lKClgIGluIGNvbmp1bmN0aW9uIHdpdGggYHRoZW1lX2J3KClgIGlmIHlvdSBuZWVkIG1vcmUgc3BlY2lmaWMgY3VzdG9taXphdGlvbi4NCiAgDQoNCiMgU2F2aW5nIFlvdXIgUGxvdA0KDQpUbyBzYXZlIHlvdXIgcGxvdCwgdXNlIHRoZSBgZ2dzYXZlKClgIGZ1bmN0aW9uOg0KDQpgYGB7cn0NCmdnc2F2ZSgibXlfcGxvdC5wbmciLCB3aWR0aCA9IDYsIGhlaWdodCA9IDQpDQpgYGANCg0KDQojIEludHJvZHVjaW5nIEludGVyYWN0aXZlIEZlYXR1cmVzDQoNCmBnZ3Bsb3RseSgpYCBpcyBhIHdyYXBwZXIgZnVuY3Rpb24gZnJvbSB0aGUgYHBsb3RseSBwYWNrYWdlYCBpbiBSIHRoYXQgYWxsb3dzIHlvdSB0byBjb252ZXJ0IGEgYGdncGxvdDJgIG9iamVjdCBpbnRvIGFuIGludGVyYWN0aXZlIGBwbG90bHlgIG9iamVjdC4gSXQgdGFrZXMgYSBzdGF0aWMgZ2dwbG90IGFuZCBtYWtlcyBpdCBpbnRlcmFjdGl2ZSBieSBhZGRpbmcgdG9vbHRpcHMsIHpvb20sIGFuZCBob3ZlciBmdW5jdGlvbmFsaXRpZXMuIFRoaXMgaXMgdXNlZnVsIHdoZW4geW91IHdhbnQgdG8gY3JlYXRlIG1vcmUgZHluYW1pYyBhbmQgZW5nYWdpbmcgdmlzdWFsaXphdGlvbnMgYmFzZWQgb24gYGdncGxvdDIgc3ludGF4YCBidXQgd2l0aCB0aGUgaW50ZXJhY3Rpdml0eSBmZWF0dXJlcyBwcm92aWRlZCBieSBgUGxvdGx5YC4gVGhlIGZvbGxvd2luZyBpcyBhIHNpbXBsZSBleGFtcGxlLg0KDQpgYGB7cn0NCiMgbmVlZCB0byB1c2UgZnVuY3Rpb25zIGluIGdncGxvdDIgYW5kIHBsb3RseQ0KIyBsaWJyYXJ5KGdncGxvdDIpDQojIGxpYnJhcnkocGxvdGx5KQ0KDQojIENyZWF0ZSBhIGdncGxvdA0KcCA8LSBnZ3Bsb3QobXBnLCBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5LCBjb2xvciA9IGNsYXNzKSkgKyANCiAgZ2VvbV9wb2ludCgpICsNCiAgZ2d0aXRsZSgiSW50ZXJhY3RpdmUgc2NhdHRlciBwbG90IHdpdGggY29sb3ItY29kaW5nIikNCg0KIyBDb252ZXJ0IHRvIGludGVyYWN0aXZlIHBsb3RseSBwbG90DQpnZ3Bsb3RseShwKQ0KYGBgDQoNCg0KVGhpcyBjb2RlIHdpbGwgZ2VuZXJhdGUgYSBwbG90IHRoYXQgYmVoYXZlcyBpbnRlcmFjdGl2ZWx5LCBhbGxvd2luZyB5b3UgdG8gem9vbSwgcGFuLCBhbmQgaG92ZXIgb3ZlciBkYXRhIHBvaW50cyB0byBzZWUgYWRkaXRpb25hbCBpbmZvcm1hdGlvbi4NCg0KDQoNCg0K