Data Visualization in R
Data visualization is an important part of exploring, understanding,
and sharing our data.
Data visualization is a critical part of the data science workflow.
Through visualization we can explore and understand our own data,
ultimately informing further analyses. Additionally, data visualizations
are a powerful tool for communicating data and research findings to
other people. Visuals can often more efficiently and more effectively
tell the story of your data, rather than only relying on writing. Well
done data visualizations will often have the biggest impact on an
audience in a science communication context.
Source
In this session we have a few main goals:
Introduction to types of data visualizations
Discussion of what makes a good visualization
Review and critique some data visualization examples
Introduction to ggplot to generate visualizations in R
Let’s get started!
Types of Data Visualization
Data visualizations can be descriptive in nature, such as portraying
the demographic distribution of a group of people, or can represent
statistical findings, such as a regression line with a confidence
interval overlaid on a scatter plot of data. In certain contexts it is
also common to present data and information in more easily digestible
infographics (check out some
examples here) that enter more of a graphic design space. Different
data visualizations fulfill different goals. Having a toolbox of a
variety of data visualization types can help you pick the best type to
fit your needs for a given project.
Table
Tables to collect and organize data are one of the most common and
basic data visualizations. But don’t discount them! They can be
efficient ways to convey a large amount of information about your data
all at once.

Pie Chart
A classic pie chart is useful for representing parts that add up to a
whole. This also allows for comparing group sizes. They are often used
for demographic variables, with the whole representing the whole sample,
or for representing money, with the whole representing a budget or total
money spent/made. Be careful to use a pie chart only when it really adds
to the story. For instance, if there are only two parts to the whole, a
pie chart might not convey much more information. Conversely, if there
are many groups, it can become difficult to really see all of them and
compare them.

Box Plots
Box plots (also known as box and whisker plots) are good for
understanding and comparing variance between groups. They typically
depict the median and minimum/maximum of each group for a certain
variable. The box portion represents the 1st and 3rd quartiles of the
distribution. You can also show change over time with this type of
plot.

Histogram
Histograms display the distribution of one variable. The height of
the bar represents how many times that value was represented in the
data. This is typically what you view if you want to visually inspect if
a variable is normally distributed.

Bar Chart
Bar charts are good for representing data from groups or categories,
with the bars representing different categories. The bar height usually
represent a mean, a count, or a percentage, by category. These can be
useful for comparing groups or showing change over time.

Scatter Plot
Scatter plots include data points that are plotted along an x and y
axis, showing the relationship between these two variables. Often
researchers add a line to these plots to show the statistical
relationship between the variables.

Line Chart
Line charts use connected straight lines to display data. They are
good for showing change over time on a continuous variable. They are
often similar in purpose to bar charts, but visually simpler if there
are many time points. An example of where we often see line charts used
in the news is to visualize the stock market. (Plotting the various age
groups here is not particularly meaningful since this data was only
collected at one time point, but is used to illustrate this type of data
visualization.)

Interactive Data Visualizations
As research and publications move more online and away from print,
this can allow for more interactive data visualizations. These are types
of data visualizations that allow a person to select and change what is
being shown. Check out this great example from
Gapminder.
The default visualization shows GDP and life expectancy over time, and
by country. However, you can change the variables included to view other
data.
So many more!
- Heat Map
- Stacked Bar or Stacked Area Chart
- Violin Plot
- Gantt Chart
- Choropleth Map
What Makes a Good Visualization?
There is an art to picking the best data visualization that fits your
data and the story you are telling. By nature, data visualizations are
abstract representations of our data, with color, shape, and position
representing the data points. This both hides the exact data itself,
while also allowing us to highlight bigger picture ideas about the data,
depending on what we choose to emphasize. When deciding on what type of
data visualization to use, consider the following:
- What question are you exploring with your data and how will it
inform future analyses?
- What is your data visualization adding to your science
communication?
- What take-away message are you conveying with the image?
- What type of variables do you have? Continuous? Categorical? And
what type of abstraction (e.g., color, shape) best suits that
variable?
- Are you comparing groups?
- Are you showing change over time?
- Are you visualizing a relationship between variables?
It can be easy to get in the habit of using the same types of data
visualization over and over again. Check out this website that gives
many creative data visualization options (with R code!), categorized by
goal:
https://r-graph-gallery.com/
Good Data Visualization Princicples
Once you pick the format that fits your needs best, these are some
principles to keep in mind when crafting your visualization to make sure
it is clear to your audience.
Clear Data |
Consider the format of your data when you include it.
Your data needs to be unambiguously communicated to your audience. For
instance, do you have so many groups that they are difficult to
differentiate? Are your data points stacked on the same spot so the
audience can’t see the density of your data points? |
Clear Labels |
All data visualizations need labels. This may be the
axis on a scatter plot, legends for your bar graph, or percentages on
your pie chart. You must tell the audience what they are looking at. If
different colors are used, they should represent some aspect of the data
and be clearly labeled. |
Clear Scales |
Clear and consistent scales are important to avoid
misinterpretation of your data visualization. An axis should be clearly
labeled and include the full scale range. Make it clear if the scale
does not start at 0. Scales should be consistent across visualizations
to allow for comparisons. |
Simplicity |
Aim to have uncluttered data visualizations. It is easy
to get excited about all you can do creatively in the world of data
visualizations, but sometimes adding too much (e.g., extra colors,
pictures) can actually obscure your main message. Avoid extra info that
doesn’t add to the story you are telling. |
Accessibility |
Consider how your data visualization design would be
viewed by a variety of people. Text font and size for legends and axis
labels should be clear and not too small. Try not to rely only on color
to distinguish groups (e.g., lines can be dashed or dotted), or pick
colors/hues that are distinguishable by people who are colorblind.
Include alternative text descriptions that can be read aloud by a screen
reader. |
For more information on design principles and the visual hierarchy of
elements, check out
this
article. Size, color, contrast, alignment, repetition, proximity,
whitespace, and texture can all be used to draw focus to particular
visual elements.
Your Turn!
One of the best ways to get into data visualization is to get
inspired from some of the amazing data visualizations that already
exist!
We have two websites with a variety of data visualization
examples.
R
Graph Gallery Includes many examples of data visualizations created
in R. These also include tutorials/R Code used to make them. These
examples go beyond what we will cover in this workshop, but serve as
great inspiration for how much you can do in R!
Tableau Viz
Gallery Includes examples created with the platform Tableau. This is
a proprietary (paid) platform which we are not using in this workshop,
but this gallery still has some great examples to help inspire your data
visualization creativity!
In small groups, on either of these websites, find a data
visualization example that jumps out to you as interesting and then
answer the following questions.
- What captured your attention about this data visualization? The
topic? The design?
- What is the story this example is trying to tell? What is one of the
take-away messages it is conveying?
- What do you like about this visualization? Does it convey
information about the data in a uniquely effective way? Does it adhere
to the principles we discussed?
- Is there anything you find confusing about this example? Anything
you think is missing or that you would change to improve it?
ggplot R Package
Now that we have our data visualization imaginations going, let’s get
into how we can visually represent our data in R.
The go-to package for data visualization in R is
ggplot2
, which is part of the tidyverse. You can find more
information about ggplot2
on the
tidyverse website.
This package approaches data visualization through “a grammar of
graphics.” In other words, using the same syntax, you can create an
infinite number of data visualizations. Although there are a lot of
functions and components to learn at first, once you understand the
overall structure of building graphics in ggplot2
, you can
replicate and expand on this structure to visualize data in an unlimited
number of ways.
If you have installed the tidyverse, then ggplot2
is
included. Otherwise you can install it now. Let’s also load our dataset
for today.
#install.packages("ggplot2")
#library(ggplot2)
There are many ways to make data visualizations in R; however, other
approaches tend to be more automatic and consequently limit the amount
you can change and adapt your visualization to your needs.
ggplot2
works in layers, allowing for maximum control and
flexibility.
Here are some of the most common layers (i.e., functions) used in
ggplot2
. Typically you connect these layers using the
+
symbol. There is often more than one way to build the
same plot with the ggplot
package.
- ggplot()
: how you will start most
plots you build in ggplot2
. The rest of the information
goes within this function.
- aes()
: this is the aesthetic mapping
function, in which you can control aesthetic components of the plot. You
can add colors, axis labels, font sizes and more within this function.
Color and shape can be defined both within and outside of the aesthetic
function.
- geom_point()
: used for making a
scatter plot
- geom_line()
: used for adding a line
to a plot
- geom_histogram()
: used for making a
histogram
- geom_col()
: used for making a bar
plot
- xlab
, ylab
, and
labs(title = )
: used for adding axis labels and an
overall title to plots
- color
: assigns a color to part of the
plot, such as different groups or the data points
- fill
: assigns the interior color of
part of the plot, such as a confidence band or the bars in bar plots
- alpha
: used to change the
transparency of a component of the plot. Useful if you lots of have
overlapping data points or distributions from multiple groups.
- size
: used to set the size of part of
the plot, such as how big the data points or text should be
There are many more data visualization options in ggplot
but to get started today we are going to focus on making a bar plot
(good for categorical data) and a scatter plot (good for continuous
data).
Basic Bar Plot: Counts
Let’s make our first plot in R! We are going to slowly add layers,
building up to a box plot representing the number of people in each
group in the isFeelRushed
variable.
First we create the blank plot on which we will add our data. We
nearly always start with the function ggplot
and then
telling the function what dataset to use.
ggplot(js_data)

This creates our blank canvas.
Next we tell ggplot what variable we want to use and put it in the
aes()
function. If you want a bar chart representing the
number of people in each group, you can add just one variable to the
aes()
function. We include the as.factor
function around the isFeelRushed
variable so it is treated
as a categorical variable for the box plot instead of a numeric
variable.
ggplot(js_data, aes(x = as.factor(isFeelRushed)))

You now see that the grid represents a scale relevant to that
variable.
Next, we tell ggplot what type of data visualization we want. To
create a bar chart we use the function geom_bar()
. To see
how many people are in each of the isFeelRushed
groups, we
use the default geom_bar(stat = "count")
. Remember that we
connect layers with a +
symbol.
ggplot(js_data, aes(x = as.factor(isFeelRushed))) +
geom_bar(stat = "count")

We’ve got a bar chart!
Lastly, let’s add some labels to the x-axis and y-axis to make it
clear what is being plotted.
ggplot(js_data, aes(x = as.factor(isFeelRushed))) +
geom_bar(stat = "count") +
xlab("Feeling Rushed") +
ylab ("Number of Participants")

Basic Bar Plot: Group Means
Building from yesterday, let’s see if people who feel rushed tend to
work more than people who do not feel rushed. To represent the mean for
each group or some other variable, you add both an x and a y variable to
the aes()
function and use the
geom_bar(stat = "summary")
. Note that the Y-axis scale has
now adjusted to a scale that matches the variable we are using (i.e.,
mean number of minutes spent working for each group).
ggplot(js_data, aes(x = as.factor(isFeelRushed), y = durWork)) +
geom_bar(stat = "summary") +
xlab("Feeling Rushed") +
ylab ("Average Minutes Working")

- Most plots will start with the
ggplot()
function
- You have to include the object where
ggplot()
will get
the information for the plot from. In this case, it’s our dataset
js_data
- Within the
aes()
function, we identify what the x and y
variables are for this plot
- We add layers using the
+
sign
- Next we tell
ggplot()
what type of plot we are making;
in this case we are creating a bar plot using the function
geom_bar()
- Then we add what type of statistic we want presented on the plot.
Here we ask for the mean of each group for the variable durWork using
the function
geom_bar(stat = "summary")
- We add a label to the x-axis with
lab("Feeling Rushed")
- We add the label to the y-axis with
ylab ("Time Working")
Improved Box Plot!
This plot gets the idea across, but we can add more layers and
functions to make more adjustments. See the walkthrough below for how we
made all these changes.
plotlabels <- c("Not Rushed", "Rushed", "Did Not Respond")
ggplot(js_data, aes(x = as.factor(isFeelRushed), y = durWork)) +
geom_bar(stat = "summary", fill = "#2D5E7F") +
xlab("Feeling Rushed") +
ylab ("Average Minutes Working") +
labs(title = "Working and Feeling Rushed") +
scale_x_discrete(labels = plotlabels) +
theme(text = element_text(size = 18),
axis.text.x = element_text(angle = 25, hjust = 1))

- We can change the color of the bars using
fill =
. Here
we added the specific color using a hex code. But you can also write in
the names of colors such as “blue”.
- Using
labs(title = "")
we added an overall title to the
plot
- We probably want to indicate what each category represents, rather
than the “0”, “1” and “NA” labels. To add text labels, we first create
an object with each of those labels in order
(
plotlabels <- c("Not Rushed", "Rushed", "Did Not Respond")
).
Then in the scale_x_discrete(labels = plotlabels)
function
we call to that object we created as the labels for the x-axis. There
are many other ways to adjust the labels for each axis, but this method
works well for a small number of groups.
- In the
theme()
layer you can add many different
specifications. Here we added
text = element_text(size = 18)
to make the text size bigger
than the default and made the x-axis labels angled so they fit better
using axis.text.x = element_text(angle = 25, hjust = 1)
.
The hjust =
adjusts the vertical location of the axis
labels so they don’t overlap with the plot itself. vjust =
can be used to move the labels right and left.
Try manipulating this plot in some way. Can you change the color of
the bars? What happens if you change angle = 90
?
Basic Scatter Plot
Now let’s make a scatter plot to visualize two continuous variables.
We are going to check if it looks like there is a correlation between
how much time people work (durWork) and how much they sleep
(durSleep).
ggplot(js_data, aes(durWork, durSleep)) +
geom_point() +
geom_smooth() +
xlab("Minutes Spent Working") +
ylab ("Minutes Spent Sleeping")

- Again we start with the
ggplot()
function, including
telling it to use the dataset js_data
- In the
aes()
function we list the x and y variables
(here durWork and durSleep)
- The
geom_point()
function is what makes a scatter
plot
- The geom_smooth() is what adds the correlation line to the plot
- The
xlab()
and ylab()
add the x-axis and
y-axis labels to the plot
Improved Scatter Plot!
Now let’s add some layers and aesthetic adjustments to improve this
plot.
ggplot(js_data, aes(durWork, durSleep)) +
geom_point(color = "#2D5E7F", alpha = .2) +
geom_smooth(method = lm, color = "black") +
xlab("Minutes Spent Working") +
ylab ("Minutes Spent Sleeping") +
scale_x_continuous(breaks = seq(0, 1500, 250)) +
labs(title = "Association Between Working and Sleeping") +
theme(text = element_text(size = 18))

- We can change the color of the data points by adding
color = "#2D5E7F"
and change the transparency of the data
points (so you can see where there are overlapping clusters) with the
addition of alpha = .2
.
- In the
geom_smooth()
function we changed the method for
calculating the line to be linear (instead of the ggplot default) using
method = lm
and adjusted the color of the line with
color =
. Remember that you can write hex code numbers or
the names of colors to adjust colors. Make sure both are in quotes to
avoid error messages.
- We adjust the x-axis tick marks with the
scale_x_continuous(breaks = seq(0, 1500, 250))
part, which
tells R to plot the x-axis on a sequence from 0 to 1500 (this captures
all of the responses in our data), with labels every 250 minutes.
- The
labs(title = "Association Between Working and Sleeping")
adds an overall title to the plot
- Lastly,
theme(text = element_text(size = 18))
adjust
the text size
Try manipulating this plot in some way. Can you make the data points
more and less transparent? Can you change the color of the line? What
happens if the x-axis has labels every 100 minutes?
Your Turn!
Take a look at our data set and make two new plots.
Make a plot comparing groups (i.e., a categorical variable) on
one of the duration variables (i.e., a continuous variable).
Make a plot comparing two continuous variables.
Challenge: What is one component of your plot you
would like to change? Can you look up a solution?
LS0tCnRpdGxlOiAiUjogRGF0YSBWaXN1YWxpemF0aW9uIgpwYWdldGl0bGU6ICJSOiBEYXRhIFZpc3VhbGl6YXRpb24iCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgY29kZV9mb2xkaW5nOiBzaG93ICMgYWxsb3dzIHRvZ2dsaW5nIG9mIHNob3dpbmcgYW5kIGhpZGluZyBjb2RlLiBSZW1vdmUgaWYgbm90IHVzaW5nIGNvZGUuCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlICMgYWxsb3dzIHRoZSB1c2VyIHRvIGRvd25sb2FkIHRoZSBzb3VyY2UgLlJtZCBmaWxlLiBSZW1vdmUgaWYgbm90IHVzaW5nIGNvZGUuCiAgICBpbmNsdWRlczoKICAgICAgYWZ0ZXJfYm9keTogZm9vdGVyLmh0bWwgIyBpbmNsdWRlIGEgY3VzdG9tIGZvb3Rlci4KICAgIHRvYzogdHJ1ZQogICAgdG9jX2RlcHRoOiAzCiAgICB0b2NfZmxvYXQ6CiAgICAgIGNvbGxhcHNlZDogZmFsc2UKICAgICAgc21vb3RoX3Njcm9sbDogZmFsc2UKLS0tCgpgYGB7ciwgbGlicmFyaWVzLCBpbmNsdWRlID0gRkFMU0V9CmxpYnJhcnkoa2FibGVFeHRyYSkKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGRwbHlyKQpgYGAKCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZ3MgPSBGQUxTRSkKYGBgCgpgYGB7ciwgaW5jbHVkZSA9IEZBTFNFfQpsb2FkKCJkYXRhL3RpbWV1c2VfZGF5M18yLlJEYXRhIikKYGBgCgoKCiMjIERhdGEgVmlzdWFsaXphdGlvbiBpbiBSCgo6OjppbnRybwpEYXRhIHZpc3VhbGl6YXRpb24gaXMgYW4gaW1wb3J0YW50IHBhcnQgb2YgZXhwbG9yaW5nLCB1bmRlcnN0YW5kaW5nLCBhbmQgc2hhcmluZyBvdXIgZGF0YS4KOjo6CgpEYXRhIHZpc3VhbGl6YXRpb24gaXMgYSBjcml0aWNhbCBwYXJ0IG9mIHRoZSBkYXRhIHNjaWVuY2Ugd29ya2Zsb3cuIFRocm91Z2ggdmlzdWFsaXphdGlvbiB3ZSBjYW4gZXhwbG9yZSBhbmQgdW5kZXJzdGFuZCBvdXIgb3duIGRhdGEsIHVsdGltYXRlbHkgaW5mb3JtaW5nIGZ1cnRoZXIgYW5hbHlzZXMuIEFkZGl0aW9uYWxseSwgZGF0YSB2aXN1YWxpemF0aW9ucyBhcmUgYSBwb3dlcmZ1bCB0b29sIGZvciBjb21tdW5pY2F0aW5nIGRhdGEgYW5kIHJlc2VhcmNoIGZpbmRpbmdzIHRvIG90aGVyIHBlb3BsZS4gVmlzdWFscyBjYW4gb2Z0ZW4gbW9yZSBlZmZpY2llbnRseSBhbmQgbW9yZSBlZmZlY3RpdmVseSB0ZWxsIHRoZSBzdG9yeSBvZiB5b3VyIGRhdGEsIHJhdGhlciB0aGFuIG9ubHkgcmVseWluZyBvbiB3cml0aW5nLiBXZWxsIGRvbmUgZGF0YSB2aXN1YWxpemF0aW9ucyB3aWxsIG9mdGVuIGhhdmUgdGhlIGJpZ2dlc3QgaW1wYWN0IG9uIGFuIGF1ZGllbmNlIGluIGEgc2NpZW5jZSBjb21tdW5pY2F0aW9uIGNvbnRleHQuIAoKIVtdKGltYWdlcy90aWR5dmVyc2Utd29ya2Zsb3cucG5nKQpbU291cmNlXShodHRwczovL3RlbGFwcHMubG9uZG9uLmVkdS9hbmFseXRpY3Nfd2l0aF9SL3RpZHl2ZXJzZS5odG1sKQoKOjo6bm90ZQpJbiB0aGlzIHNlc3Npb24gd2UgaGF2ZSBhIGZldyBtYWluIGdvYWxzOgoKMS4gSW50cm9kdWN0aW9uIHRvIHR5cGVzIG9mIGRhdGEgdmlzdWFsaXphdGlvbnMKCjIuIERpc2N1c3Npb24gb2Ygd2hhdCBtYWtlcyBhIGdvb2QgdmlzdWFsaXphdGlvbgoKMy4gUmV2aWV3IGFuZCBjcml0aXF1ZSBzb21lIGRhdGEgdmlzdWFsaXphdGlvbiBleGFtcGxlcwoKNC4gSW50cm9kdWN0aW9uIHRvIGdncGxvdCB0byBnZW5lcmF0ZSB2aXN1YWxpemF0aW9ucyBpbiBSCgo6OjoKCkxldCdzIGdldCBzdGFydGVkISAKCiMjIyBUeXBlcyBvZiBEYXRhIFZpc3VhbGl6YXRpb24KCkRhdGEgdmlzdWFsaXphdGlvbnMgY2FuIGJlIGRlc2NyaXB0aXZlIGluIG5hdHVyZSwgc3VjaCBhcyBwb3J0cmF5aW5nIHRoZSBkZW1vZ3JhcGhpYyBkaXN0cmlidXRpb24gb2YgYSBncm91cCBvZiBwZW9wbGUsIG9yIGNhbiByZXByZXNlbnQgc3RhdGlzdGljYWwgZmluZGluZ3MsIHN1Y2ggYXMgYSByZWdyZXNzaW9uIGxpbmUgd2l0aCBhIGNvbmZpZGVuY2UgaW50ZXJ2YWwgb3ZlcmxhaWQgb24gYSBzY2F0dGVyIHBsb3Qgb2YgZGF0YS4gSW4gY2VydGFpbiBjb250ZXh0cyBpdCBpcyBhbHNvIGNvbW1vbiB0byBwcmVzZW50IGRhdGEgYW5kIGluZm9ybWF0aW9uIGluIG1vcmUgZWFzaWx5IGRpZ2VzdGlibGUgaW5mb2dyYXBoaWNzIDxhIGhyZWY9Imh0dHBzOi8vY29vbGluZm9ncmFwaGljcy5jb20vIj4oY2hlY2sgb3V0IHNvbWUgZXhhbXBsZXMgaGVyZSk8L2E+IHRoYXQgZW50ZXIgbW9yZSBvZiBhIGdyYXBoaWMgZGVzaWduIHNwYWNlLiBEaWZmZXJlbnQgZGF0YSB2aXN1YWxpemF0aW9ucyBmdWxmaWxsIGRpZmZlcmVudCBnb2Fscy4gSGF2aW5nIGEgdG9vbGJveCBvZiBhIHZhcmlldHkgb2YgZGF0YSB2aXN1YWxpemF0aW9uIHR5cGVzIGNhbiBoZWxwIHlvdSBwaWNrIHRoZSBiZXN0IHR5cGUgdG8gZml0IHlvdXIgbmVlZHMgZm9yIGEgZ2l2ZW4gcHJvamVjdC4gCgojIyMjICoqVGFibGUqKgpUYWJsZXMgdG8gY29sbGVjdCBhbmQgb3JnYW5pemUgZGF0YSBhcmUgb25lIG9mIHRoZSBtb3N0IGNvbW1vbiBhbmQgYmFzaWMgZGF0YSB2aXN1YWxpemF0aW9ucy4gQnV0IGRvbid0IGRpc2NvdW50IHRoZW0hIFRoZXkgY2FuIGJlIGVmZmljaWVudCB3YXlzIHRvIGNvbnZleSBhIGxhcmdlIGFtb3VudCBvZiBpbmZvcm1hdGlvbiBhYm91dCB5b3VyIGRhdGEgYWxsIGF0IG9uY2UuIAoKIVtdKGltYWdlcy9kYXk0X2V4YW1wbGV0YWJsZS5wbmcpCgojIyMjICoqUGllIENoYXJ0KioKQSBjbGFzc2ljIHBpZSBjaGFydCBpcyB1c2VmdWwgZm9yIHJlcHJlc2VudGluZyBwYXJ0cyB0aGF0IGFkZCB1cCB0byBhIHdob2xlLiBUaGlzIGFsc28gYWxsb3dzIGZvciBjb21wYXJpbmcgZ3JvdXAgc2l6ZXMuIFRoZXkgYXJlIG9mdGVuIHVzZWQgZm9yIGRlbW9ncmFwaGljIHZhcmlhYmxlcywgd2l0aCB0aGUgd2hvbGUgcmVwcmVzZW50aW5nIHRoZSB3aG9sZSBzYW1wbGUsIG9yIGZvciByZXByZXNlbnRpbmcgbW9uZXksIHdpdGggdGhlIHdob2xlIHJlcHJlc2VudGluZyBhIGJ1ZGdldCBvciB0b3RhbCBtb25leSBzcGVudC9tYWRlLiBCZSBjYXJlZnVsIHRvIHVzZSBhIHBpZSBjaGFydCBvbmx5IHdoZW4gaXQgcmVhbGx5IGFkZHMgdG8gdGhlIHN0b3J5LiBGb3IgaW5zdGFuY2UsIGlmIHRoZXJlIGFyZSBvbmx5IHR3byBwYXJ0cyB0byB0aGUgd2hvbGUsIGEgcGllIGNoYXJ0IG1pZ2h0IG5vdCBjb252ZXkgbXVjaCBtb3JlIGluZm9ybWF0aW9uLiBDb252ZXJzZWx5LCBpZiB0aGVyZSBhcmUgbWFueSBncm91cHMsIGl0IGNhbiBiZWNvbWUgZGlmZmljdWx0IHRvIHJlYWxseSBzZWUgYWxsIG9mIHRoZW0gYW5kIGNvbXBhcmUgdGhlbS4gCgohW10oaW1hZ2VzL2RheTRfcGllY2hhcnRleGFtcGxlLnBuZykKCiMjIyMgKipCb3ggUGxvdHMqKgpCb3ggcGxvdHMgKGFsc28ga25vd24gYXMgYm94IGFuZCB3aGlza2VyIHBsb3RzKSBhcmUgZ29vZCBmb3IgdW5kZXJzdGFuZGluZyBhbmQgY29tcGFyaW5nIHZhcmlhbmNlIGJldHdlZW4gZ3JvdXBzLiBUaGV5IHR5cGljYWxseSBkZXBpY3QgdGhlIG1lZGlhbiBhbmQgbWluaW11bS9tYXhpbXVtIG9mIGVhY2ggZ3JvdXAgZm9yIGEgY2VydGFpbiB2YXJpYWJsZS4gVGhlIGJveCBwb3J0aW9uIHJlcHJlc2VudHMgdGhlIDFzdCBhbmQgM3JkIHF1YXJ0aWxlcyBvZiB0aGUgZGlzdHJpYnV0aW9uLiBZb3UgY2FuIGFsc28gc2hvdyBjaGFuZ2Ugb3ZlciB0aW1lIHdpdGggdGhpcyB0eXBlIG9mIHBsb3QuIAoKYGBge3IsIGVjaG8gPSBGQUxTRX0KZ2dwbG90KGpzX2RhdGEsIGFlcyh4PWFzLmZhY3Rvcihwcm92aW5jZV9mYWN0KSwgeT1kdXJTbGVlcCkpICsgCiAgICBnZW9tX2JveHBsb3QoZmlsbD0iIzJENUU3RiIsIGFscGhhPTAuNikgKyAKICAgIHhsYWIoIlByb3ZpbmNlIikgKwogICAgeWxhYigiTWludXRlcyBTbGVlcGluZyIpICsKIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE4KSkKYGBgCgojIyMjICoqSGlzdG9ncmFtKiogCkhpc3RvZ3JhbXMgZGlzcGxheSB0aGUgZGlzdHJpYnV0aW9uIG9mIG9uZSB2YXJpYWJsZS4gVGhlIGhlaWdodCBvZiB0aGUgYmFyIHJlcHJlc2VudHMgaG93IG1hbnkgdGltZXMgdGhhdCB2YWx1ZSB3YXMgcmVwcmVzZW50ZWQgaW4gdGhlIGRhdGEuIFRoaXMgaXMgdHlwaWNhbGx5IHdoYXQgeW91IHZpZXcgaWYgeW91IHdhbnQgdG8gdmlzdWFsbHkgaW5zcGVjdCBpZiBhIHZhcmlhYmxlIGlzIG5vcm1hbGx5IGRpc3RyaWJ1dGVkLiAKCmBgYCB7ciwgZWNobyA9IEZBTFNFfQoKZ2dwbG90KGpzX2RhdGEsIGFlcyh4PWR1clNsZWVwKSkgKyAKICBnZW9tX2hpc3RvZ3JhbShmaWxsID0gIiMyRDVFN0YiLCBjb2xvciA9ICJibGFjayIpKwogIHhsYWIoIk51bWJlciBvZiBNaW51dGVzIFNsZWVwaW5nIikgKwogIHlsYWIgKCJOdW1iZXIgb2YgUGFydGljaXBhbnRzIikgKwogIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE4KSkKYGBgCgojIyMjICoqQmFyIENoYXJ0KiogCkJhciBjaGFydHMgYXJlIGdvb2QgZm9yIHJlcHJlc2VudGluZyBkYXRhIGZyb20gZ3JvdXBzIG9yIGNhdGVnb3JpZXMsIHdpdGggdGhlIGJhcnMgcmVwcmVzZW50aW5nIGRpZmZlcmVudCBjYXRlZ29yaWVzLiBUaGUgYmFyIGhlaWdodCB1c3VhbGx5IHJlcHJlc2VudCBhIG1lYW4sIGEgY291bnQsIG9yIGEgcGVyY2VudGFnZSwgYnkgY2F0ZWdvcnkuIFRoZXNlIGNhbiBiZSB1c2VmdWwgZm9yIGNvbXBhcmluZyBncm91cHMgb3Igc2hvd2luZyBjaGFuZ2Ugb3ZlciB0aW1lLiAKCmBgYCB7ciwgZWNobyA9IEZBTFNFfQpnZ3Bsb3QoanNfZGF0YSwgYWVzKHg9bWFyaXRhbFN0YXRfZmFjdCwgZmlsbCA9IGFzLmZhY3RvcihtYXJpdGFsU3RhdF9mYWN0KSkpICsKICBnZW9tX2JhcigpICsgCiAgeGxhYigiTWFyaXRhbCBTdGF0dXMiKSArCiAgeWxhYiAoIk51bWJlciBvZiBQYXJ0aWNpcGFudHMiKSArCiAgc2NhbGVfZmlsbF9odWUoYyA9IDYwKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgIHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE4KSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDM1LCBoanVzdCA9IDEpKQpgYGAKCiMjIyMgKipTY2F0dGVyIFBsb3QqKiAKU2NhdHRlciBwbG90cyBpbmNsdWRlIGRhdGEgcG9pbnRzIHRoYXQgYXJlIHBsb3R0ZWQgYWxvbmcgYW4geCBhbmQgeSBheGlzLCBzaG93aW5nIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGVzZSB0d28gdmFyaWFibGVzLiBPZnRlbiByZXNlYXJjaGVycyBhZGQgYSBsaW5lIHRvIHRoZXNlIHBsb3RzIHRvIHNob3cgdGhlIHN0YXRpc3RpY2FsIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoZSB2YXJpYWJsZXMuIAoKYGBge3IsIGVjaG8gPSBGQUxTRX0KZ2dwbG90KGpzX2RhdGEsIGFlcyhkdXJXb3JrLCBkdXJTbGVlcCkpICsKICBnZW9tX3BvaW50KGNvbG9yID0gIiMyRDVFN0YiLCBhbHBoYSA9IC4yKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kPWxtLCBzZT1UUlVFLCBjb2xvciA9ICJibGFjayIpICsKICB4bGFiKCJNaW51dGVzIFNwZW50IFdvcmtpbmciKSArCiAgeWxhYiAoIk1pbnV0ZXMgU3BlbnQgU2xlZXBpbmciKSArCiAgbGFicyh0aXRsZSA9ICJBc3NvY2lhdGlvbiBCZXR3ZWVuIFdvcmtpbmcgYW5kIFNsZWVwaW5nIikgKwogIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE4KSkKYGBgCgojIyMjICoqTGluZSBDaGFydCoqIApMaW5lIGNoYXJ0cyB1c2UgY29ubmVjdGVkIHN0cmFpZ2h0IGxpbmVzIHRvIGRpc3BsYXkgZGF0YS4gVGhleSBhcmUgZ29vZCBmb3Igc2hvd2luZyBjaGFuZ2Ugb3ZlciB0aW1lIG9uIGEgY29udGludW91cyB2YXJpYWJsZS4gVGhleSBhcmUgb2Z0ZW4gc2ltaWxhciBpbiBwdXJwb3NlIHRvIGJhciBjaGFydHMsIGJ1dCB2aXN1YWxseSBzaW1wbGVyIGlmIHRoZXJlIGFyZSBtYW55IHRpbWUgcG9pbnRzLiBBbiBleGFtcGxlIG9mIHdoZXJlIHdlIG9mdGVuIHNlZSBsaW5lIGNoYXJ0cyB1c2VkIGluIHRoZSBuZXdzIGlzIHRvIHZpc3VhbGl6ZSB0aGUgc3RvY2sgbWFya2V0LiAoUGxvdHRpbmcgdGhlIHZhcmlvdXMgYWdlIGdyb3VwcyBoZXJlIGlzIG5vdCBwYXJ0aWN1bGFybHkgbWVhbmluZ2Z1bCBzaW5jZSB0aGlzIGRhdGEgd2FzIG9ubHkgY29sbGVjdGVkIGF0IG9uZSB0aW1lIHBvaW50LCBidXQgaXMgdXNlZCB0byBpbGx1c3RyYXRlIHRoaXMgdHlwZSBvZiBkYXRhIHZpc3VhbGl6YXRpb24uKQoKYGBge3IsIGVjaG8gPSBGQUxTRX0KeFZhbHVlIDwtIDE6Nwp5VmFsdWUgPC0gYygxMzAzLCAyMTI3LCAyNTk3LCAyNzg5LCAzNzQxLCAyOTU4LCAxODc1KQpwbG90ZGF0YSA8LSBkYXRhLmZyYW1lKHhWYWx1ZSx5VmFsdWUpCgpnZ3Bsb3QocGxvdGRhdGEsIGFlcyh4PXhWYWx1ZSwgeT15VmFsdWUpKSArCiAgZ2VvbV9saW5lKGNvbG9yID0gIiMyRDVFN0YiKSArCiAgeGxhYigiQWdlIEdyb3VwcyIpICsKICB5bGFiICgiTnVtYmVyIG9mIFBhcnRpY2lwYW50cyIpICsKICBsYWJzKHRpdGxlID0gIk51bWJlciBvZiBQYXJ0aWNpcGFudHMgcGVyIEFnZSBHcm91cCIpICsKICB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxOCkpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDEsIDcsIDEpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLCA0MDAwLCA1MDApKQoKYGBgCgojIyMjICoqSW50ZXJhY3RpdmUgRGF0YSBWaXN1YWxpemF0aW9ucyoqIApBcyByZXNlYXJjaCBhbmQgcHVibGljYXRpb25zIG1vdmUgbW9yZSBvbmxpbmUgYW5kIGF3YXkgZnJvbSBwcmludCwgdGhpcyBjYW4gYWxsb3cgZm9yIG1vcmUgaW50ZXJhY3RpdmUgZGF0YSB2aXN1YWxpemF0aW9ucy4gVGhlc2UgYXJlIHR5cGVzIG9mIGRhdGEgdmlzdWFsaXphdGlvbnMgdGhhdCBhbGxvdyBhIHBlcnNvbiB0byBzZWxlY3QgYW5kIGNoYW5nZSB3aGF0IGlzIGJlaW5nIHNob3duLiBDaGVjayBvdXQgdGhpcyBncmVhdCBleGFtcGxlIGZyb20gPGEgaHJlZj0iaHR0cHM6Ly93d3cuZ2FwbWluZGVyLm9yZy90b29scy8jJGNoYXJ0LXR5cGU9YnViYmxlcyZ1cmw9djIpIj5HYXBtaW5kZXI8L2E+LiBUaGUgZGVmYXVsdCB2aXN1YWxpemF0aW9uIHNob3dzIEdEUCBhbmQgbGlmZSBleHBlY3RhbmN5IG92ZXIgdGltZSwgYW5kIGJ5IGNvdW50cnkuIEhvd2V2ZXIsIHlvdSBjYW4gY2hhbmdlIHRoZSB2YXJpYWJsZXMgaW5jbHVkZWQgdG8gdmlldyBvdGhlciBkYXRhLiAKCiMjIyMgKipTbyBtYW55IG1vcmUhKiogCi0gSGVhdCBNYXAKLSBTdGFja2VkIEJhciBvciBTdGFja2VkIEFyZWEgQ2hhcnQKLSBWaW9saW4gUGxvdAotIEdhbnR0IENoYXJ0Ci0gQ2hvcm9wbGV0aCBNYXAKCiMjIyBXaGF0IE1ha2VzIGEgR29vZCBWaXN1YWxpemF0aW9uPwpUaGVyZSBpcyBhbiBhcnQgdG8gcGlja2luZyB0aGUgYmVzdCBkYXRhIHZpc3VhbGl6YXRpb24gdGhhdCBmaXRzIHlvdXIgZGF0YSBhbmQgdGhlIHN0b3J5IHlvdSBhcmUgdGVsbGluZy4gQnkgbmF0dXJlLCBkYXRhIHZpc3VhbGl6YXRpb25zIGFyZSBhYnN0cmFjdCByZXByZXNlbnRhdGlvbnMgb2Ygb3VyIGRhdGEsIHdpdGggY29sb3IsIHNoYXBlLCBhbmQgcG9zaXRpb24gcmVwcmVzZW50aW5nIHRoZSBkYXRhIHBvaW50cy4gVGhpcyBib3RoIGhpZGVzIHRoZSBleGFjdCBkYXRhIGl0c2VsZiwgd2hpbGUgYWxzbyBhbGxvd2luZyB1cyB0byBoaWdobGlnaHQgYmlnZ2VyIHBpY3R1cmUgaWRlYXMgYWJvdXQgdGhlIGRhdGEsIGRlcGVuZGluZyBvbiB3aGF0IHdlIGNob29zZSB0byBlbXBoYXNpemUuIFdoZW4gZGVjaWRpbmcgb24gd2hhdCB0eXBlIG9mIGRhdGEgdmlzdWFsaXphdGlvbiB0byB1c2UsIGNvbnNpZGVyIHRoZSBmb2xsb3dpbmc6IAoKLSBXaGF0IHF1ZXN0aW9uIGFyZSB5b3UgZXhwbG9yaW5nIHdpdGggeW91ciBkYXRhIGFuZCBob3cgd2lsbCBpdCBpbmZvcm0gZnV0dXJlIGFuYWx5c2VzPwotIFdoYXQgaXMgeW91ciBkYXRhIHZpc3VhbGl6YXRpb24gYWRkaW5nIHRvIHlvdXIgc2NpZW5jZSBjb21tdW5pY2F0aW9uPyAKLSBXaGF0IHRha2UtYXdheSBtZXNzYWdlIGFyZSB5b3UgY29udmV5aW5nIHdpdGggdGhlIGltYWdlPyAKLSBXaGF0IHR5cGUgb2YgdmFyaWFibGVzIGRvIHlvdSBoYXZlPyBDb250aW51b3VzPyBDYXRlZ29yaWNhbD8gQW5kIHdoYXQgdHlwZSBvZiBhYnN0cmFjdGlvbiAoZS5nLiwgY29sb3IsIHNoYXBlKSBiZXN0IHN1aXRzIHRoYXQgdmFyaWFibGU/Ci0gQXJlIHlvdSBjb21wYXJpbmcgZ3JvdXBzPwotIEFyZSB5b3Ugc2hvd2luZyBjaGFuZ2Ugb3ZlciB0aW1lPwotIEFyZSB5b3UgdmlzdWFsaXppbmcgYSByZWxhdGlvbnNoaXAgYmV0d2VlbiB2YXJpYWJsZXM/CgpJdCBjYW4gYmUgZWFzeSB0byBnZXQgaW4gdGhlIGhhYml0IG9mIHVzaW5nIHRoZSBzYW1lIHR5cGVzIG9mIGRhdGEgdmlzdWFsaXphdGlvbiBvdmVyIGFuZCBvdmVyIGFnYWluLiBDaGVjayBvdXQgdGhpcyB3ZWJzaXRlIHRoYXQgZ2l2ZXMgbWFueSBjcmVhdGl2ZSBkYXRhIHZpc3VhbGl6YXRpb24gb3B0aW9ucyAod2l0aCBSIGNvZGUhKSwgY2F0ZWdvcml6ZWQgYnkgZ29hbDogPGEgaHJlZj0iaHR0cHM6Ly9yLWdyYXBoLWdhbGxlcnkuY29tLyAiPmh0dHBzOi8vci1ncmFwaC1nYWxsZXJ5LmNvbS8gPC9hPgoKIyMjIyBHb29kIERhdGEgVmlzdWFsaXphdGlvbiBQcmluY2ljcGxlcwoKT25jZSB5b3UgcGljayB0aGUgZm9ybWF0IHRoYXQgZml0cyB5b3VyIG5lZWRzIGJlc3QsIHRoZXNlIGFyZSBzb21lIHByaW5jaXBsZXMgdG8ga2VlcCBpbiBtaW5kIHdoZW4gY3JhZnRpbmcgeW91ciB2aXN1YWxpemF0aW9uIHRvIG1ha2Ugc3VyZSBpdCBpcyBjbGVhciB0byB5b3VyIGF1ZGllbmNlLgoKOjo6bWQtdGFibGUKfCBQcmluY2lwbGUgfCBDb25zaWRlcmF0aW9ucyB8CnwgOi0tLSB8IDotLS0gfAp8IENsZWFyIERhdGEgfCBDb25zaWRlciB0aGUgZm9ybWF0IG9mIHlvdXIgZGF0YSB3aGVuIHlvdSBpbmNsdWRlIGl0LiBZb3VyIGRhdGEgbmVlZHMgdG8gYmUgdW5hbWJpZ3VvdXNseSBjb21tdW5pY2F0ZWQgdG8geW91ciBhdWRpZW5jZS4gRm9yIGluc3RhbmNlLCBkbyB5b3UgaGF2ZSBzbyBtYW55IGdyb3VwcyB0aGF0IHRoZXkgYXJlIGRpZmZpY3VsdCB0byBkaWZmZXJlbnRpYXRlPyBBcmUgeW91ciBkYXRhIHBvaW50cyBzdGFja2VkIG9uIHRoZSBzYW1lIHNwb3Qgc28gdGhlIGF1ZGllbmNlIGNhbid0IHNlZSB0aGUgZGVuc2l0eSBvZiB5b3VyIGRhdGEgcG9pbnRzPyB8CnwgQ2xlYXIgTGFiZWxzIHwgQWxsIGRhdGEgdmlzdWFsaXphdGlvbnMgbmVlZCBsYWJlbHMuIFRoaXMgbWF5IGJlIHRoZSBheGlzIG9uIGEgc2NhdHRlciBwbG90LCBsZWdlbmRzIGZvciB5b3VyIGJhciBncmFwaCwgb3IgcGVyY2VudGFnZXMgb24geW91ciBwaWUgY2hhcnQuIFlvdSBtdXN0IHRlbGwgdGhlIGF1ZGllbmNlIHdoYXQgdGhleSBhcmUgbG9va2luZyBhdC4gSWYgZGlmZmVyZW50IGNvbG9ycyBhcmUgdXNlZCwgdGhleSBzaG91bGQgcmVwcmVzZW50IHNvbWUgYXNwZWN0IG9mIHRoZSBkYXRhIGFuZCBiZSBjbGVhcmx5IGxhYmVsZWQuIHwKfCBDbGVhciBTY2FsZXMgfCBDbGVhciBhbmQgY29uc2lzdGVudCBzY2FsZXMgYXJlIGltcG9ydGFudCB0byBhdm9pZCBtaXNpbnRlcnByZXRhdGlvbiBvZiB5b3VyIGRhdGEgdmlzdWFsaXphdGlvbi4gQW4gYXhpcyBzaG91bGQgYmUgY2xlYXJseSBsYWJlbGVkIGFuZCBpbmNsdWRlIHRoZSBmdWxsIHNjYWxlIHJhbmdlLiBNYWtlIGl0IGNsZWFyIGlmIHRoZSBzY2FsZSBkb2VzIG5vdCBzdGFydCBhdCAwLiBTY2FsZXMgc2hvdWxkIGJlIGNvbnNpc3RlbnQgYWNyb3NzIHZpc3VhbGl6YXRpb25zIHRvIGFsbG93IGZvciBjb21wYXJpc29ucy4gfAp8IFNpbXBsaWNpdHkgfCBBaW0gdG8gaGF2ZSB1bmNsdXR0ZXJlZCBkYXRhIHZpc3VhbGl6YXRpb25zLiBJdCBpcyBlYXN5IHRvIGdldCBleGNpdGVkIGFib3V0IGFsbCB5b3UgY2FuIGRvIGNyZWF0aXZlbHkgaW4gdGhlIHdvcmxkIG9mIGRhdGEgdmlzdWFsaXphdGlvbnMsIGJ1dCBzb21ldGltZXMgYWRkaW5nIHRvbyBtdWNoIChlLmcuLCBleHRyYSBjb2xvcnMsIHBpY3R1cmVzKSBjYW4gYWN0dWFsbHkgb2JzY3VyZSB5b3VyIG1haW4gbWVzc2FnZS4gQXZvaWQgZXh0cmEgaW5mbyB0aGF0IGRvZXNuJ3QgYWRkIHRvIHRoZSBzdG9yeSB5b3UgYXJlIHRlbGxpbmcuIHwKfCBBY2Nlc3NpYmlsaXR5IHwgQ29uc2lkZXIgaG93IHlvdXIgZGF0YSB2aXN1YWxpemF0aW9uIGRlc2lnbiB3b3VsZCBiZSB2aWV3ZWQgYnkgYSB2YXJpZXR5IG9mIHBlb3BsZS4gVGV4dCBmb250IGFuZCBzaXplIGZvciBsZWdlbmRzIGFuZCBheGlzIGxhYmVscyBzaG91bGQgYmUgY2xlYXIgYW5kIG5vdCB0b28gc21hbGwuIFRyeSBub3QgdG8gcmVseSBvbmx5IG9uIGNvbG9yIHRvIGRpc3Rpbmd1aXNoIGdyb3VwcyAoZS5nLiwgbGluZXMgY2FuIGJlIGRhc2hlZCBvciBkb3R0ZWQpLCBvciBwaWNrIGNvbG9ycy9odWVzIHRoYXQgYXJlIGRpc3Rpbmd1aXNoYWJsZSBieSBwZW9wbGUgd2hvIGFyZSBjb2xvcmJsaW5kLiBJbmNsdWRlIGFsdGVybmF0aXZlIHRleHQgZGVzY3JpcHRpb25zIHRoYXQgY2FuIGJlIHJlYWQgYWxvdWQgYnkgYSBzY3JlZW4gcmVhZGVyLiB8Cjo6OgoKRm9yIG1vcmUgaW5mb3JtYXRpb24gb24gZGVzaWduIHByaW5jaXBsZXMgYW5kIHRoZSB2aXN1YWwgaGllcmFyY2h5IG9mIGVsZW1lbnRzLCBjaGVjayBvdXQgPGEgaHJlZj0iaHR0cHM6Ly93d3cuaW50ZXJhY3Rpb24tZGVzaWduLm9yZy9saXRlcmF0dXJlL3RvcGljcy92aXN1YWwtaGllcmFyY2h5P3Nyc2x0aWQ9QWZtQk9vb1U3N1hQaVZzWFNrRTd0MkdxQWF5YU95aDBWeGR3R2ozYkphUDFRajN4Y2M1QTQ0QlciPnRoaXMgYXJ0aWNsZTwvYT4uIFNpemUsIGNvbG9yLCBjb250cmFzdCwgYWxpZ25tZW50LCByZXBldGl0aW9uLCBwcm94aW1pdHksIHdoaXRlc3BhY2UsIGFuZCB0ZXh0dXJlIGNhbiBhbGwgYmUgdXNlZCB0byBkcmF3IGZvY3VzIHRvIHBhcnRpY3VsYXIgdmlzdWFsIGVsZW1lbnRzLiAKCgojIyMgWW91ciBUdXJuIQpPbmUgb2YgdGhlIGJlc3Qgd2F5cyB0byBnZXQgaW50byBkYXRhIHZpc3VhbGl6YXRpb24gaXMgdG8gZ2V0IGluc3BpcmVkIGZyb20gc29tZSBvZiB0aGUgYW1hemluZyBkYXRhIHZpc3VhbGl6YXRpb25zIHRoYXQgYWxyZWFkeSBleGlzdCEgCgpXZSBoYXZlIHR3byB3ZWJzaXRlcyB3aXRoIGEgdmFyaWV0eSBvZiBkYXRhIHZpc3VhbGl6YXRpb24gZXhhbXBsZXMuIAoKLSA8YSBocmVmPSJodHRwczovL3ItZ3JhcGgtZ2FsbGVyeS5jb20vYmVzdC1yLWNoYXJ0LWV4YW1wbGVzIj5SIEdyYXBoIEdhbGxlcnk8L2E+CkluY2x1ZGVzIG1hbnkgZXhhbXBsZXMgb2YgZGF0YSB2aXN1YWxpemF0aW9ucyBjcmVhdGVkIGluIFIuIFRoZXNlIGFsc28gaW5jbHVkZSB0dXRvcmlhbHMvUiBDb2RlIHVzZWQgdG8gbWFrZSB0aGVtLiBUaGVzZSBleGFtcGxlcyBnbyBiZXlvbmQgd2hhdCB3ZSB3aWxsIGNvdmVyIGluIHRoaXMgd29ya3Nob3AsIGJ1dCBzZXJ2ZSBhcyBncmVhdCBpbnNwaXJhdGlvbiBmb3IgaG93IG11Y2ggeW91IGNhbiBkbyBpbiBSIQoKLSA8YSBocmVmPSJodHRwczovL3d3dy50YWJsZWF1LmNvbS92aXotZ2FsbGVyeSI+VGFibGVhdSBWaXogR2FsbGVyeTwvYT4KSW5jbHVkZXMgZXhhbXBsZXMgY3JlYXRlZCB3aXRoIHRoZSBwbGF0Zm9ybSBUYWJsZWF1LiBUaGlzIGlzIGEgcHJvcHJpZXRhcnkgKHBhaWQpIHBsYXRmb3JtIHdoaWNoIHdlIGFyZSBub3QgdXNpbmcgaW4gdGhpcyB3b3Jrc2hvcCwgYnV0IHRoaXMgZ2FsbGVyeSBzdGlsbCBoYXMgc29tZSBncmVhdCBleGFtcGxlcyB0byBoZWxwIGluc3BpcmUgeW91ciBkYXRhIHZpc3VhbGl6YXRpb24gY3JlYXRpdml0eSEgCgo6OjpxdWVzdGlvbgpJbiBzbWFsbCBncm91cHMsIG9uIGVpdGhlciBvZiB0aGVzZSB3ZWJzaXRlcywgZmluZCBhIGRhdGEgdmlzdWFsaXphdGlvbiBleGFtcGxlIHRoYXQganVtcHMgb3V0IHRvIHlvdSBhcyBpbnRlcmVzdGluZyBhbmQgdGhlbiBhbnN3ZXIgdGhlIGZvbGxvd2luZyBxdWVzdGlvbnMuIAoKMS4gV2hhdCBjYXB0dXJlZCB5b3VyIGF0dGVudGlvbiBhYm91dCB0aGlzIGRhdGEgdmlzdWFsaXphdGlvbj8gVGhlIHRvcGljPyBUaGUgZGVzaWduPyAKMi4gV2hhdCBpcyB0aGUgc3RvcnkgdGhpcyBleGFtcGxlIGlzIHRyeWluZyB0byB0ZWxsPyBXaGF0IGlzIG9uZSBvZiB0aGUgdGFrZS1hd2F5IG1lc3NhZ2VzIGl0IGlzIGNvbnZleWluZz8KMy4gV2hhdCBkbyB5b3UgbGlrZSBhYm91dCB0aGlzIHZpc3VhbGl6YXRpb24/IERvZXMgaXQgY29udmV5IGluZm9ybWF0aW9uIGFib3V0IHRoZSBkYXRhIGluIGEgdW5pcXVlbHkgZWZmZWN0aXZlIHdheT8gRG9lcyBpdCBhZGhlcmUgdG8gdGhlIHByaW5jaXBsZXMgd2UgZGlzY3Vzc2VkPyAKNC4gSXMgdGhlcmUgYW55dGhpbmcgeW91IGZpbmQgY29uZnVzaW5nIGFib3V0IHRoaXMgZXhhbXBsZT8gQW55dGhpbmcgeW91IHRoaW5rIGlzIG1pc3Npbmcgb3IgdGhhdCB5b3Ugd291bGQgY2hhbmdlIHRvIGltcHJvdmUgaXQ/IAo6OjoKCiMjIyBnZ3Bsb3QgUiBQYWNrYWdlCgpOb3cgdGhhdCB3ZSBoYXZlIG91ciBkYXRhIHZpc3VhbGl6YXRpb24gaW1hZ2luYXRpb25zIGdvaW5nLCBsZXQncyBnZXQgaW50byBob3cgd2UgY2FuIHZpc3VhbGx5IHJlcHJlc2VudCBvdXIgZGF0YSBpbiBSLgoKVGhlIGdvLXRvIHBhY2thZ2UgZm9yIGRhdGEgdmlzdWFsaXphdGlvbiBpbiBSIGlzIGBnZ3Bsb3QyYCwgd2hpY2ggaXMgcGFydCBvZiB0aGUgdGlkeXZlcnNlLiBZb3UgY2FuIGZpbmQgbW9yZSBpbmZvcm1hdGlvbiBhYm91dCBgZ2dwbG90MmAgb24gdGhlIDxhIGhyZWY9Imh0dHBzOi8vZ2dwbG90Mi50aWR5dmVyc2Uub3JnLyI+dGlkeXZlcnNlIHdlYnNpdGU8L2E+LgoKVGhpcyBwYWNrYWdlIGFwcHJvYWNoZXMgZGF0YSB2aXN1YWxpemF0aW9uIHRocm91Z2ggImEgZ3JhbW1hciBvZiBncmFwaGljcy4iIEluIG90aGVyIHdvcmRzLCB1c2luZyB0aGUgc2FtZSBzeW50YXgsIHlvdSBjYW4gY3JlYXRlIGFuIGluZmluaXRlIG51bWJlciBvZiBkYXRhIHZpc3VhbGl6YXRpb25zLiBBbHRob3VnaCB0aGVyZSBhcmUgYSBsb3Qgb2YgZnVuY3Rpb25zIGFuZCBjb21wb25lbnRzIHRvIGxlYXJuIGF0IGZpcnN0LCBvbmNlIHlvdSB1bmRlcnN0YW5kIHRoZSBvdmVyYWxsIHN0cnVjdHVyZSBvZiBidWlsZGluZyBncmFwaGljcyBpbiBgZ2dwbG90MmAsIHlvdSBjYW4gcmVwbGljYXRlIGFuZCBleHBhbmQgb24gdGhpcyBzdHJ1Y3R1cmUgdG8gdmlzdWFsaXplIGRhdGEgaW4gYW4gdW5saW1pdGVkIG51bWJlciBvZiB3YXlzLiAKCklmIHlvdSBoYXZlIGluc3RhbGxlZCB0aGUgdGlkeXZlcnNlLCB0aGVuIGBnZ3Bsb3QyYCBpcyBpbmNsdWRlZC4gT3RoZXJ3aXNlIHlvdSBjYW4gaW5zdGFsbCBpdCBub3cuIExldCdzIGFsc28gbG9hZCBvdXIgZGF0YXNldCBmb3IgdG9kYXkuCgpgYGB7cn0KI2luc3RhbGwucGFja2FnZXMoImdncGxvdDIiKQojbGlicmFyeShnZ3Bsb3QyKQpgYGAKClRoZXJlIGFyZSBtYW55IHdheXMgdG8gbWFrZSBkYXRhIHZpc3VhbGl6YXRpb25zIGluIFI7IGhvd2V2ZXIsIG90aGVyIGFwcHJvYWNoZXMgdGVuZCB0byBiZSBtb3JlIGF1dG9tYXRpYyBhbmQgY29uc2VxdWVudGx5IGxpbWl0IHRoZSBhbW91bnQgeW91IGNhbiBjaGFuZ2UgYW5kIGFkYXB0IHlvdXIgdmlzdWFsaXphdGlvbiB0byB5b3VyIG5lZWRzLiBgZ2dwbG90MmAgd29ya3MgaW4gbGF5ZXJzLCBhbGxvd2luZyBmb3IgbWF4aW11bSBjb250cm9sIGFuZCBmbGV4aWJpbGl0eS4gCgpIZXJlIGFyZSBzb21lIG9mIHRoZSBtb3N0IGNvbW1vbiBsYXllcnMgKGkuZS4sIGZ1bmN0aW9ucykgdXNlZCBpbiBgZ2dwbG90MmAuIFR5cGljYWxseSB5b3UgY29ubmVjdCB0aGVzZSBsYXllcnMgdXNpbmcgdGhlIGArYCBzeW1ib2wuIFRoZXJlIGlzIG9mdGVuIG1vcmUgdGhhbiBvbmUgd2F5IHRvIGJ1aWxkIHRoZSBzYW1lIHBsb3Qgd2l0aCB0aGUgYGdncGxvdGAgcGFja2FnZS4gCgoqKi0gYGdncGxvdCgpYDoqKiBob3cgeW91IHdpbGwgc3RhcnQgbW9zdCBwbG90cyB5b3UgYnVpbGQgaW4gYGdncGxvdDJgLiBUaGUgcmVzdCBvZiB0aGUgaW5mb3JtYXRpb24gZ29lcyB3aXRoaW4gdGhpcyBmdW5jdGlvbi4KCioqLSBgYWVzKClgOioqIHRoaXMgaXMgdGhlIGFlc3RoZXRpYyBtYXBwaW5nIGZ1bmN0aW9uLCBpbiB3aGljaCB5b3UgY2FuIGNvbnRyb2wgYWVzdGhldGljIGNvbXBvbmVudHMgb2YgdGhlIHBsb3QuIFlvdSBjYW4gYWRkIGNvbG9ycywgYXhpcyBsYWJlbHMsIGZvbnQgc2l6ZXMgYW5kIG1vcmUgd2l0aGluIHRoaXMgZnVuY3Rpb24uIENvbG9yIGFuZCBzaGFwZSBjYW4gYmUgZGVmaW5lZCBib3RoIHdpdGhpbiBhbmQgb3V0c2lkZSBvZiB0aGUgYWVzdGhldGljIGZ1bmN0aW9uLiAKCioqLSBgZ2VvbV9wb2ludCgpYDoqKiB1c2VkIGZvciBtYWtpbmcgYSBzY2F0dGVyIHBsb3QKCioqLSBgZ2VvbV9saW5lKClgOioqIHVzZWQgZm9yIGFkZGluZyBhIGxpbmUgdG8gYSBwbG90CgoqKi0gYGdlb21faGlzdG9ncmFtKClgOioqIHVzZWQgZm9yIG1ha2luZyBhIGhpc3RvZ3JhbQoKKiotIGBnZW9tX2NvbCgpYDoqKiB1c2VkIGZvciBtYWtpbmcgYSBiYXIgcGxvdAoKKiotIGB4bGFiYCwgYHlsYWJgLCBhbmQgYGxhYnModGl0bGUgPSApYDoqKiB1c2VkIGZvciBhZGRpbmcgYXhpcyBsYWJlbHMgYW5kIGFuIG92ZXJhbGwgdGl0bGUgdG8gcGxvdHMKCioqLSBgY29sb3JgOioqIGFzc2lnbnMgYSBjb2xvciB0byBwYXJ0IG9mIHRoZSBwbG90LCBzdWNoIGFzIGRpZmZlcmVudCBncm91cHMgb3IgdGhlIGRhdGEgcG9pbnRzCgoqKi0gYGZpbGxgOioqIGFzc2lnbnMgdGhlIGludGVyaW9yIGNvbG9yIG9mIHBhcnQgb2YgdGhlIHBsb3QsIHN1Y2ggYXMgYSBjb25maWRlbmNlIGJhbmQgb3IgdGhlIGJhcnMgaW4gYmFyIHBsb3RzCgoqKi0gYGFscGhhYDoqKiB1c2VkIHRvIGNoYW5nZSB0aGUgdHJhbnNwYXJlbmN5IG9mIGEgY29tcG9uZW50IG9mIHRoZSBwbG90LiBVc2VmdWwgaWYgeW91IGxvdHMgb2YgaGF2ZSBvdmVybGFwcGluZyBkYXRhIHBvaW50cyBvciBkaXN0cmlidXRpb25zIGZyb20gbXVsdGlwbGUgZ3JvdXBzLiAKCioqLSBgc2l6ZWA6KiogdXNlZCB0byBzZXQgdGhlIHNpemUgb2YgcGFydCBvZiB0aGUgcGxvdCwgc3VjaCBhcyBob3cgYmlnIHRoZSBkYXRhIHBvaW50cyBvciB0ZXh0IHNob3VsZCBiZQoKVGhlcmUgYXJlIG1hbnkgbW9yZSBkYXRhIHZpc3VhbGl6YXRpb24gb3B0aW9ucyBpbiBgZ2dwbG90YCBidXQgdG8gZ2V0IHN0YXJ0ZWQgdG9kYXkgd2UgYXJlIGdvaW5nIHRvIGZvY3VzIG9uIG1ha2luZyBhIGJhciBwbG90IChnb29kIGZvciBjYXRlZ29yaWNhbCBkYXRhKSBhbmQgYSBzY2F0dGVyIHBsb3QgKGdvb2QgZm9yIGNvbnRpbnVvdXMgZGF0YSkuIAoKIyMjIEJhc2ljIEJhciBQbG90OiBDb3VudHMKTGV0J3MgbWFrZSBvdXIgZmlyc3QgcGxvdCBpbiBSISBXZSBhcmUgZ29pbmcgdG8gc2xvd2x5IGFkZCBsYXllcnMsIGJ1aWxkaW5nIHVwIHRvIGEgYm94IHBsb3QgcmVwcmVzZW50aW5nIHRoZSBudW1iZXIgb2YgcGVvcGxlIGluIGVhY2ggZ3JvdXAgaW4gdGhlIGBpc0ZlZWxSdXNoZWRgIHZhcmlhYmxlLiAKCkZpcnN0IHdlIGNyZWF0ZSB0aGUgYmxhbmsgcGxvdCBvbiB3aGljaCB3ZSB3aWxsIGFkZCBvdXIgZGF0YS4gV2UgbmVhcmx5IGFsd2F5cyBzdGFydCB3aXRoIHRoZSBmdW5jdGlvbiBgZ2dwbG90YCBhbmQgdGhlbiB0ZWxsaW5nIHRoZSBmdW5jdGlvbiB3aGF0IGRhdGFzZXQgdG8gdXNlLiAKCmBgYHtyfQpnZ3Bsb3QoanNfZGF0YSkKYGBgCgpUaGlzIGNyZWF0ZXMgb3VyIGJsYW5rIGNhbnZhcy4KCk5leHQgd2UgdGVsbCBnZ3Bsb3Qgd2hhdCB2YXJpYWJsZSB3ZSB3YW50IHRvIHVzZSBhbmQgcHV0IGl0IGluIHRoZSBgYWVzKClgIGZ1bmN0aW9uLiBJZiB5b3Ugd2FudCBhIGJhciBjaGFydCByZXByZXNlbnRpbmcgdGhlIG51bWJlciBvZiBwZW9wbGUgaW4gZWFjaCBncm91cCwgeW91IGNhbiBhZGQganVzdCBvbmUgdmFyaWFibGUgdG8gdGhlIGBhZXMoKWAgZnVuY3Rpb24uIFdlIGluY2x1ZGUgdGhlIGBhcy5mYWN0b3JgIGZ1bmN0aW9uIGFyb3VuZCB0aGUgYGlzRmVlbFJ1c2hlZGAgdmFyaWFibGUgc28gaXQgaXMgdHJlYXRlZCBhcyBhIGNhdGVnb3JpY2FsIHZhcmlhYmxlIGZvciB0aGUgYm94IHBsb3QgaW5zdGVhZCBvZiBhIG51bWVyaWMgdmFyaWFibGUuIAoKYGBge3J9CmdncGxvdChqc19kYXRhLCBhZXMoeCA9IGFzLmZhY3Rvcihpc0ZlZWxSdXNoZWQpKSkKYGBgCgpZb3Ugbm93IHNlZSB0aGF0IHRoZSBncmlkIHJlcHJlc2VudHMgYSBzY2FsZSByZWxldmFudCB0byB0aGF0IHZhcmlhYmxlLiAKCk5leHQsIHdlIHRlbGwgZ2dwbG90IHdoYXQgdHlwZSBvZiBkYXRhIHZpc3VhbGl6YXRpb24gd2Ugd2FudC4gVG8gY3JlYXRlIGEgYmFyIGNoYXJ0IHdlIHVzZSB0aGUgZnVuY3Rpb24gYGdlb21fYmFyKClgLiBUbyBzZWUgaG93IG1hbnkgcGVvcGxlIGFyZSBpbiBlYWNoIG9mIHRoZSBgaXNGZWVsUnVzaGVkYCBncm91cHMsIHdlIHVzZSB0aGUgZGVmYXVsdCBgZ2VvbV9iYXIoc3RhdCA9ICJjb3VudCIpYC4gUmVtZW1iZXIgdGhhdCB3ZSBjb25uZWN0IGxheWVycyB3aXRoIGEgYCtgIHN5bWJvbC4gCgpgYGB7cn0KZ2dwbG90KGpzX2RhdGEsIGFlcyh4ID0gYXMuZmFjdG9yKGlzRmVlbFJ1c2hlZCkpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJjb3VudCIpCmBgYAoKV2UndmUgZ290IGEgYmFyIGNoYXJ0IQoKTGFzdGx5LCBsZXQncyBhZGQgc29tZSBsYWJlbHMgdG8gdGhlIHgtYXhpcyBhbmQgeS1heGlzIHRvIG1ha2UgaXQgY2xlYXIgd2hhdCBpcyBiZWluZyBwbG90dGVkLiAKCmBgYHtyfQpnZ3Bsb3QoanNfZGF0YSwgYWVzKHggPSBhcy5mYWN0b3IoaXNGZWVsUnVzaGVkKSkpICsKICBnZW9tX2JhcihzdGF0ID0gImNvdW50IikgKyAKICB4bGFiKCJGZWVsaW5nIFJ1c2hlZCIpICsKICB5bGFiICgiTnVtYmVyIG9mIFBhcnRpY2lwYW50cyIpIApgYGAKCiMjIyBCYXNpYyBCYXIgUGxvdDogR3JvdXAgTWVhbnMKCkJ1aWxkaW5nIGZyb20geWVzdGVyZGF5LCBsZXQncyBzZWUgaWYgcGVvcGxlIHdobyBmZWVsIHJ1c2hlZCB0ZW5kIHRvIHdvcmsgbW9yZSB0aGFuIHBlb3BsZSB3aG8gZG8gbm90IGZlZWwgcnVzaGVkLiBUbyByZXByZXNlbnQgdGhlIG1lYW4gZm9yIGVhY2ggZ3JvdXAgb3Igc29tZSBvdGhlciB2YXJpYWJsZSwgeW91IGFkZCBib3RoIGFuIHggYW5kIGEgeSB2YXJpYWJsZSB0byB0aGUgYGFlcygpYCBmdW5jdGlvbiBhbmQgdXNlIHRoZSBgZ2VvbV9iYXIoc3RhdCA9ICJzdW1tYXJ5IilgLiBOb3RlIHRoYXQgdGhlIFktYXhpcyBzY2FsZSBoYXMgbm93IGFkanVzdGVkIHRvIGEgc2NhbGUgdGhhdCBtYXRjaGVzIHRoZSB2YXJpYWJsZSB3ZSBhcmUgdXNpbmcgKGkuZS4sIG1lYW4gbnVtYmVyIG9mIG1pbnV0ZXMgc3BlbnQgd29ya2luZyBmb3IgZWFjaCBncm91cCkuIAoKYGBge3J9CmdncGxvdChqc19kYXRhLCBhZXMoeCA9IGFzLmZhY3Rvcihpc0ZlZWxSdXNoZWQpLCB5ID0gZHVyV29yaykpICsKICBnZW9tX2JhcihzdGF0ID0gInN1bW1hcnkiKSArIAogIHhsYWIoIkZlZWxpbmcgUnVzaGVkIikgKwogIHlsYWIgKCJBdmVyYWdlIE1pbnV0ZXMgV29ya2luZyIpIApgYGAKCjo6OndhbGt0aHJvdWdoCiAgLSBNb3N0IHBsb3RzIHdpbGwgc3RhcnQgd2l0aCB0aGUgYGdncGxvdCgpYGZ1bmN0aW9uCiAgLSBZb3UgaGF2ZSB0byBpbmNsdWRlIHRoZSBvYmplY3Qgd2hlcmUgYGdncGxvdCgpYCB3aWxsIGdldCB0aGUgaW5mb3JtYXRpb24gZm9yIHRoZSBwbG90IGZyb20uIEluIHRoaXMgY2FzZSwgaXQncyBvdXIgZGF0YXNldCBganNfZGF0YWAKICAtIFdpdGhpbiB0aGUgYGFlcygpYCBmdW5jdGlvbiwgd2UgaWRlbnRpZnkgd2hhdCB0aGUgeCBhbmQgeSB2YXJpYWJsZXMgYXJlIGZvciB0aGlzIHBsb3QKICAtIFdlIGFkZCBsYXllcnMgdXNpbmcgdGhlIGArYCBzaWduCiAgLSBOZXh0IHdlIHRlbGwgYGdncGxvdCgpYCB3aGF0IHR5cGUgb2YgcGxvdCB3ZSBhcmUgbWFraW5nOyBpbiB0aGlzIGNhc2Ugd2UgYXJlIGNyZWF0aW5nIGEgYmFyIHBsb3QgdXNpbmcgdGhlIGZ1bmN0aW9uIGBnZW9tX2JhcigpYAogIC0gVGhlbiB3ZSBhZGQgd2hhdCB0eXBlIG9mIHN0YXRpc3RpYyB3ZSB3YW50IHByZXNlbnRlZCBvbiB0aGUgcGxvdC4gSGVyZSB3ZSBhc2sgZm9yIHRoZSBtZWFuIG9mIGVhY2ggZ3JvdXAgZm9yIHRoZSB2YXJpYWJsZSBkdXJXb3JrIHVzaW5nIHRoZSBmdW5jdGlvbiBgZ2VvbV9iYXIoc3RhdCA9ICJzdW1tYXJ5IilgCiAgLSBXZSBhZGQgYSBsYWJlbCB0byB0aGUgeC1heGlzIHdpdGggYGxhYigiRmVlbGluZyBSdXNoZWQiKWAKICAtIFdlIGFkZCB0aGUgbGFiZWwgdG8gdGhlIHktYXhpcyB3aXRoIGB5bGFiICgiVGltZSBXb3JraW5nIilgCiAgCjo6OgoKIyMjIEltcHJvdmVkIEJveCBQbG90ISAKVGhpcyBwbG90IGdldHMgdGhlIGlkZWEgYWNyb3NzLCBidXQgd2UgY2FuIGFkZCBtb3JlIGxheWVycyBhbmQgZnVuY3Rpb25zIHRvIG1ha2UgbW9yZSBhZGp1c3RtZW50cy4gU2VlIHRoZSB3YWxrdGhyb3VnaCBiZWxvdyBmb3IgaG93IHdlIG1hZGUgYWxsIHRoZXNlIGNoYW5nZXMuCgpgYGB7cn0KCnBsb3RsYWJlbHMgPC0gYygiTm90IFJ1c2hlZCIsICJSdXNoZWQiLCAiRGlkIE5vdCBSZXNwb25kIikKCmdncGxvdChqc19kYXRhLCBhZXMoeCA9IGFzLmZhY3Rvcihpc0ZlZWxSdXNoZWQpLCB5ID0gZHVyV29yaykpICsKICBnZW9tX2JhcihzdGF0ID0gInN1bW1hcnkiLCBmaWxsID0gIiMyRDVFN0YiKSArIAogIHhsYWIoIkZlZWxpbmcgUnVzaGVkIikgKwogIHlsYWIgKCJBdmVyYWdlIE1pbnV0ZXMgV29ya2luZyIpICsKICBsYWJzKHRpdGxlID0gIldvcmtpbmcgYW5kIEZlZWxpbmcgUnVzaGVkIikgKwogIHNjYWxlX3hfZGlzY3JldGUobGFiZWxzID0gcGxvdGxhYmVscykgKwogIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE4KSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDI1LCBoanVzdCA9IDEpKQogIApgYGAKCjo6OndhbGt0aHJvdWdoCiAgLSBXZSBjYW4gY2hhbmdlIHRoZSBjb2xvciBvZiB0aGUgYmFycyB1c2luZyBgZmlsbCA9IGAuIEhlcmUgd2UgYWRkZWQgdGhlIHNwZWNpZmljIGNvbG9yIHVzaW5nIGEgaGV4IGNvZGUuIEJ1dCB5b3UgY2FuIGFsc28gd3JpdGUgaW4gdGhlIG5hbWVzIG9mIGNvbG9ycyBzdWNoIGFzICJibHVlIi4KICAtIFVzaW5nIGBsYWJzKHRpdGxlID0gIiIpYCB3ZSBhZGRlZCBhbiBvdmVyYWxsIHRpdGxlIHRvIHRoZSBwbG90CiAgLSBXZSBwcm9iYWJseSB3YW50IHRvIGluZGljYXRlIHdoYXQgZWFjaCBjYXRlZ29yeSByZXByZXNlbnRzLCByYXRoZXIgdGhhbiB0aGUgIjAiLCAiMSIgYW5kICJOQSIgbGFiZWxzLiBUbyBhZGQgdGV4dCBsYWJlbHMsIHdlIGZpcnN0IGNyZWF0ZSBhbiBvYmplY3Qgd2l0aCBlYWNoIG9mIHRob3NlIGxhYmVscyBpbiBvcmRlciAoYHBsb3RsYWJlbHMgPC0gYygiTm90IFJ1c2hlZCIsICJSdXNoZWQiLCAiRGlkIE5vdCBSZXNwb25kIilgKS4gVGhlbiBpbiB0aGUgYHNjYWxlX3hfZGlzY3JldGUobGFiZWxzID0gcGxvdGxhYmVscylgIGZ1bmN0aW9uIHdlIGNhbGwgdG8gdGhhdCBvYmplY3Qgd2UgY3JlYXRlZCBhcyB0aGUgbGFiZWxzIGZvciB0aGUgeC1heGlzLiBUaGVyZSBhcmUgbWFueSBvdGhlciB3YXlzIHRvIGFkanVzdCB0aGUgbGFiZWxzIGZvciBlYWNoIGF4aXMsIGJ1dCB0aGlzIG1ldGhvZCB3b3JrcyB3ZWxsIGZvciBhIHNtYWxsIG51bWJlciBvZiBncm91cHMuCiAgLSBJbiB0aGUgYHRoZW1lKClgIGxheWVyIHlvdSBjYW4gYWRkIG1hbnkgZGlmZmVyZW50IHNwZWNpZmljYXRpb25zLiBIZXJlIHdlIGFkZGVkIGB0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxOClgIHRvIG1ha2UgdGhlIHRleHQgc2l6ZSBiaWdnZXIgdGhhbiB0aGUgZGVmYXVsdCBhbmQgbWFkZSB0aGUgeC1heGlzIGxhYmVscyBhbmdsZWQgc28gdGhleSBmaXQgYmV0dGVyIHVzaW5nIGBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDI1LCBoanVzdCA9IDEpYC4gVGhlIGBoanVzdCA9IGAgYWRqdXN0cyB0aGUgdmVydGljYWwgbG9jYXRpb24gb2YgdGhlIGF4aXMgbGFiZWxzIHNvIHRoZXkgZG9uJ3Qgb3ZlcmxhcCB3aXRoIHRoZSBwbG90IGl0c2VsZi4gYHZqdXN0ID0gYCBjYW4gYmUgdXNlZCB0byBtb3ZlIHRoZSBsYWJlbHMgcmlnaHQgYW5kIGxlZnQuIAogIAo6OjoKCjo6OnF1ZXN0aW9uClRyeSBtYW5pcHVsYXRpbmcgdGhpcyBwbG90IGluIHNvbWUgd2F5LiBDYW4geW91IGNoYW5nZSB0aGUgY29sb3Igb2YgdGhlIGJhcnM/IFdoYXQgaGFwcGVucyBpZiB5b3UgY2hhbmdlIGBhbmdsZSA9IDkwYD8KOjo6CgojIyMgQmFzaWMgU2NhdHRlciBQbG90Ck5vdyBsZXQncyBtYWtlIGEgc2NhdHRlciBwbG90IHRvIHZpc3VhbGl6ZSB0d28gY29udGludW91cyB2YXJpYWJsZXMuIFdlIGFyZSBnb2luZyB0byBjaGVjayBpZiBpdCBsb29rcyBsaWtlIHRoZXJlIGlzIGEgY29ycmVsYXRpb24gYmV0d2VlbiBob3cgbXVjaCB0aW1lIHBlb3BsZSB3b3JrIChkdXJXb3JrKSBhbmQgaG93IG11Y2ggdGhleSBzbGVlcCAoZHVyU2xlZXApLgoKYGBge3J9CmdncGxvdChqc19kYXRhLCBhZXMoZHVyV29yaywgZHVyU2xlZXApKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX3Ntb290aCgpICsKICB4bGFiKCJNaW51dGVzIFNwZW50IFdvcmtpbmciKSArCiAgeWxhYiAoIk1pbnV0ZXMgU3BlbnQgU2xlZXBpbmciKQogICAgICAKYGBgCgo6Ojp3YWxrdGhyb3VnaAogIC0gQWdhaW4gd2Ugc3RhcnQgd2l0aCB0aGUgYGdncGxvdCgpYCBmdW5jdGlvbiwgaW5jbHVkaW5nIHRlbGxpbmcgaXQgdG8gdXNlIHRoZSBkYXRhc2V0IGBqc19kYXRhYAogIC0gSW4gdGhlIGBhZXMoKWAgZnVuY3Rpb24gd2UgbGlzdCB0aGUgeCBhbmQgeSB2YXJpYWJsZXMgKGhlcmUgZHVyV29yayBhbmQgZHVyU2xlZXApCiAgLSBUaGUgYGdlb21fcG9pbnQoKWAgZnVuY3Rpb24gaXMgd2hhdCBtYWtlcyBhIHNjYXR0ZXIgcGxvdAogIC0gVGhlIGdlb21fc21vb3RoKCkgaXMgd2hhdCBhZGRzIHRoZSBjb3JyZWxhdGlvbiBsaW5lIHRvIHRoZSBwbG90CiAgLSBUaGUgYHhsYWIoKWAgYW5kIGB5bGFiKClgIGFkZCB0aGUgeC1heGlzIGFuZCB5LWF4aXMgbGFiZWxzIHRvIHRoZSBwbG90CiAgCjo6OgojIyMgSW1wcm92ZWQgU2NhdHRlciBQbG90IQoKTm93IGxldCdzIGFkZCBzb21lIGxheWVycyBhbmQgYWVzdGhldGljIGFkanVzdG1lbnRzIHRvIGltcHJvdmUgdGhpcyBwbG90LgoKYGBge3J9CmdncGxvdChqc19kYXRhLCBhZXMoZHVyV29yaywgZHVyU2xlZXApKSArCiAgZ2VvbV9wb2ludChjb2xvciA9ICIjMkQ1RTdGIiwgYWxwaGEgPSAuMikgKwogIGdlb21fc21vb3RoKG1ldGhvZCA9IGxtLCBjb2xvciA9ICJibGFjayIpICsKICB4bGFiKCJNaW51dGVzIFNwZW50IFdvcmtpbmciKSArCiAgeWxhYiAoIk1pbnV0ZXMgU3BlbnQgU2xlZXBpbmciKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLCAxNTAwLCAyNTApKSArCiAgbGFicyh0aXRsZSA9ICJBc3NvY2lhdGlvbiBCZXR3ZWVuIFdvcmtpbmcgYW5kIFNsZWVwaW5nIikgKwogIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE4KSkKYGBgCgo6Ojp3YWxrdGhyb3VnaAogIC0gV2UgY2FuIGNoYW5nZSB0aGUgY29sb3Igb2YgdGhlIGRhdGEgcG9pbnRzIGJ5IGFkZGluZyBgY29sb3IgPSAiIzJENUU3RiJgIGFuZCBjaGFuZ2UgdGhlIHRyYW5zcGFyZW5jeSBvZiB0aGUgZGF0YSBwb2ludHMgKHNvIHlvdSBjYW4gc2VlIHdoZXJlIHRoZXJlIGFyZSBvdmVybGFwcGluZyBjbHVzdGVycykgd2l0aCB0aGUgYWRkaXRpb24gb2YgYGFscGhhID0gLjJgLiAKICAtIEluIHRoZSBgZ2VvbV9zbW9vdGgoKWAgZnVuY3Rpb24gd2UgY2hhbmdlZCB0aGUgbWV0aG9kIGZvciBjYWxjdWxhdGluZyB0aGUgbGluZSB0byBiZSBsaW5lYXIgKGluc3RlYWQgb2YgdGhlIGdncGxvdCBkZWZhdWx0KSB1c2luZyBgbWV0aG9kID0gbG1gIGFuZCBhZGp1c3RlZCB0aGUgY29sb3Igb2YgdGhlIGxpbmUgd2l0aCBgY29sb3IgPSBgLiBSZW1lbWJlciB0aGF0IHlvdSBjYW4gd3JpdGUgaGV4IGNvZGUgbnVtYmVycyBvciB0aGUgbmFtZXMgb2YgY29sb3JzIHRvIGFkanVzdCBjb2xvcnMuIE1ha2Ugc3VyZSBib3RoIGFyZSBpbiBxdW90ZXMgdG8gYXZvaWQgZXJyb3IgbWVzc2FnZXMuIAogIC0gV2UgYWRqdXN0IHRoZSB4LWF4aXMgdGljayBtYXJrcyB3aXRoIHRoZSBgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgwLCAxNTAwLCAyNTApKWAgcGFydCwgd2hpY2ggdGVsbHMgUiB0byBwbG90IHRoZSB4LWF4aXMgb24gYSBzZXF1ZW5jZSBmcm9tIDAgdG8gMTUwMCAodGhpcyBjYXB0dXJlcyBhbGwgb2YgdGhlIHJlc3BvbnNlcyBpbiBvdXIgZGF0YSksIHdpdGggbGFiZWxzIGV2ZXJ5IDI1MCBtaW51dGVzLiAKICAtIFRoZSBgbGFicyh0aXRsZSA9ICJBc3NvY2lhdGlvbiBCZXR3ZWVuIFdvcmtpbmcgYW5kIFNsZWVwaW5nIilgIGFkZHMgYW4gb3ZlcmFsbCB0aXRsZSB0byB0aGUgcGxvdAogIC0gTGFzdGx5LCBgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTgpKWAgYWRqdXN0IHRoZSB0ZXh0IHNpemUKICAKOjo6Cgo6OjpxdWVzdGlvbgpUcnkgbWFuaXB1bGF0aW5nIHRoaXMgcGxvdCBpbiBzb21lIHdheS4gQ2FuIHlvdSBtYWtlIHRoZSBkYXRhIHBvaW50cyBtb3JlIGFuZCBsZXNzIHRyYW5zcGFyZW50PyBDYW4geW91IGNoYW5nZSB0aGUgY29sb3Igb2YgdGhlIGxpbmU/IFdoYXQgaGFwcGVucyBpZiB0aGUgeC1heGlzIGhhcyBsYWJlbHMgZXZlcnkgMTAwIG1pbnV0ZXM/Cjo6OgoKIyMjIFlvdXIgVHVybiEKOjo6IHF1ZXN0aW9uClRha2UgYSBsb29rIGF0IG91ciBkYXRhIHNldCBhbmQgbWFrZSB0d28gbmV3IHBsb3RzLiAKCjEuIE1ha2UgYSBwbG90IGNvbXBhcmluZyBncm91cHMgKGkuZS4sIGEgY2F0ZWdvcmljYWwgdmFyaWFibGUpIG9uIG9uZSBvZiB0aGUgZHVyYXRpb24gdmFyaWFibGVzIChpLmUuLCBhIGNvbnRpbnVvdXMgdmFyaWFibGUpLgoKMi4gTWFrZSBhIHBsb3QgY29tcGFyaW5nIHR3byBjb250aW51b3VzIHZhcmlhYmxlcy4gCjo6OgoKOjo6IHF1ZXN0aW9uCgoqKkNoYWxsZW5nZToqKiBXaGF0IGlzIG9uZSBjb21wb25lbnQgb2YgeW91ciBwbG90IHlvdSB3b3VsZCBsaWtlIHRvIGNoYW5nZT8gQ2FuIHlvdSBsb29rIHVwIGEgc29sdXRpb24/IAo6OjoKCg==