Image source: thenewstack
Why visualize?
Data visualization is the graphical representation of information and
data. By using visual elements like charts, graphs, and maps, data
visualization tools provide an accessible way to see and understand
trends, outliers, and patterns in data. Hidden within your data lie
important insights. But the challenge is that you can’t always connect
the dots by looking at raw numbers alone. When you look at your data
presented in a visual format, patterns, connections, and other “a-ha”
insights emerge that would otherwise remain out of sight.
The earliest form of data visualization can be traced back to the
Egyptians in the pre-17th century, largely used to assist in navigation.
As time progressed, people leveraged data visualizations for broader
applications, such as in economic, social, health, and environmental
disciplines.
There are many different ways to visualize data. Some of the most
common techniques are:
Tables: This consists of rows and columns used
to compare variables. Tables can show a great deal of information in a
structured way, but they can also overwhelm users that are simply
looking for high-level trends.
Bar graphs and boxplots: These are used to
represent and compare groups or categorical variables. Boxplots in
addition also represent numerous descriptive statistics about each
category like its mean and range.
Scatter plots: These visuals are beneficial in
reveling the relationship between two variables, and they are commonly
used within regression data analysis. However, these can sometimes be
confused with bubble charts, which are used to visualize three variables
via the x-axis, the y-axis, and the size of the bubble.
Pie charts and stacked bar charts: These graphs
are divided into sections that represent parts (portions or percentages)
of a whole. They provide a simple way to organize data and compare the
size of each component to one other.
Line charts and area charts: These visuals show
change in one or more quantities by plotting a series of data points
over time and are frequently used within predictive analytics. Line
graphs utilize lines to demonstrate these changes while area charts
connect data points with line segments, stacking variables on top of one
another and using color to distinguish between variables.
Histograms: This graph plots a distribution of
numbers using a bar chart (with no spaces between the bars),
representing the quantity of data (or frequency) that falls within a
particular range. This visual makes it easy for an end user to identify
outliers within a given dataset.
Important: By convention, the x-axis is the
independent variable and the dependent
variable is plotted on the y-axis.
So far we have been using base R visualization tools (e.g. when you
used the command: plot). However, there are various other
packages that we can use to produce nicer and more sophisticated graphs.
One of the most popular of such packages is called
ggplot2.
But what are R packages?
One of the primary reasons for R’s popularity is its extensive
package ecosystem. On R’s main package repository: Comprehensive R Archive Network
(CRAN) alone you have over 10,000 packages available to choose from. You
can see the list of available packages on CRAN here.
Yet, when you first install R you only get a very limited set of core
packages “out of the box”. Any further packages that you’d like to use
you have to install yourself.
Installing packages
To be able to use a (non-base) package for the first time, we will
need to first install it on our system. Installing packages from CRAN
couldn’t be easier! Simply type install.packages() with the name of your
desired package in quotes as first argument.
install.packages("ggplot2")
Installing package into ‘/home/kazanjian/R/x86_64-pc-linux-gnu-library/4.3’
(as ‘lib’ is unspecified)
trying URL 'https://cloud.r-project.org/src/contrib/ggplot2_3.4.4.tar.gz'
Content type 'application/x-gzip' length 3159578 bytes (3.0 MB)
==================================================
downloaded 3.0 MB
* installing *source* package ‘ggplot2’ ...
** package ‘ggplot2’ successfully unpacked and MD5 sums checked
** using staged installation
** R
** data
*** moving datasets to lazyload DB
** inst
** byte-compile and prepare package for lazy loading
** help
*** installing help indices
*** copying figures
** building package indices
** installing vignettes
** testing if installed package can be loaded from temporary location
** testing if installed package can be loaded from final location
** testing if installed package keeps a record of temporary installation path
* DONE (ggplot2)
The downloaded source packages are in
‘/tmp/Rtmpxwm0IQ/downloaded_packages’
Note: Although I have included and executed the code within my
notebook here (to show you how it is done), it is usually advisable to
not include this in R notebooks but directly in your console (the box at
the lower left corner usually in RStudio) as
- You will only need to install it once on each computer you
use.
- It will often produce very long codes that will make your html (or
pdf) outputs very messy.
Once a package is installed on your system, you can load it to R by
using the command: library(package name). You will have
to do this every time after you restart R. Thus, unlike the
install.packages command, it is recommended to include this at
the top of each of your notebooks, to make sure the packages you need
are loaded.
library(ggplot2)
ggplot2
ggplot2 is a powerful data visualization package in the R
programming language. It is based on the grammar of graphics, which is a
way of describing and building graphs using a structured approach.
ggplot2 allows you to create a wide variety of plots and
graphics, including scatter plots, bar plots, line plots, histograms,
and more, with a high degree of customization and flexibility. It is now
over 10 years old and is widely used in the data science and statistical
communities for creating visually appealing and informative plots from
data.
While it is slightly more complex to execute than the simple plots in
base R, once you understand its syntax (by practicing!) you will get the
hang of it quickly. It is best to imagine how ggplot2 works as
making graphs with different layers. In most cases you start with
ggplot(), supply a dataset and aesthetic mapping (with aes()) This
will be the background and axes of your graph. You then add on
layers (like geom_point() or geom_histogram()) These will be the
points, lines or bars on top of your background, scales (like
scale_colour_brewer()), faceting specifications (like facet_wrap()) and
coordinate systems (like coord_flip()). We will cover some of these in
this lecture and more throughout our course.
Let’s try it!
Now that we’ve loaded the ggplot library into R, let’s test it out.
But before we can put it to use, we’ll need to add one more vital
component we’re still missing. The actual data!
Let’s start with the dataset we used last week: fish_size.csv and
recreate the boxplot we made but with ggplot2 this time.
setwd("/home/kazanjian/Documents/R projects/ESS103/")
Warning: The working directory was changed to /home/kazanjian/Documents/R projects/ESS103 inside a notebook chunk. The working directory will be reset when the chunk is finished running. Use the knitr root.dir option in the setup chunk to change the working directory for notebook chunks.
fish = read.csv ("Data/fish_size.csv", header=T, sep=",")
head(fish)
In this dataset, we have 2 variables:
- 1 continues variable: size (or length) of the fish
- 1 categorical variable: the type of the fish
As the size of the fish is often dependent on its type, we will
assume that former is the dependent variable (so
y-axis) and the latter is the independent variable (so
x-axis)
The simplest ggplot2 syntax follows the following logic: > ggplot
(dataset, aes (x-axis, y-axis)) + graph_type() #you will often get a
small pop-up in R studio while typing the command to help you choose the
syntax for the graph type you want.
So for our specific example, we need to rewrite the above as:
ggplot(fish, aes(fish_types, size)) + geom_boxplot()

Alternatively, if we do not want to view our data as a boxplot but
visualize all measurements as separate points, you can choose
geom_point() as a graph type instead of *geom_boxplot()
ggplot(fish, aes(fish_types, size)) + geom_point()

Now let us make some modifications to the above graph. Assume our
points are too small, so we want to make them bigger, and make them red
to pop out! We can add these details within the parantheses of
geom_point():
ggplot(fish, aes(fish_types, size)) + geom_point(size=3, color="red")

The flexibility of ggplot2 comes to the fore with the
ability to add multiple visualization types at once. For the fun of it,
let’s try to combine both previous graphs (boxplot and points) in one
graph. We can even add some transparency to the points (alpha = 0 for
full transparency to 1 for no transparency) to not fully shield the
boxplots below them.
ggplot(fish, aes(fish_types, size)) +
geom_boxplot() +
geom_point(size=3, color="red", alpha = 0.2)

Our figure though is still missing a title, however. This can be
added with the command labs. To also show our x and y-axes
titles more professionally, we can use the commands xlab and
ylab, respectively. Lastly, you can experiment with different
color themes like black and white (bw), a dark theme, a minimal theme,
etc. See below:
ggplot(fish, aes(fish_types, size)) +
geom_boxplot() +
geom_point(size=3, color="red", alpha = 0.2) +
labs(title= "Size of fishes by type",
x="Fish Types",
y="Length in cm") +
theme_bw()

Now we have a professional-looking graph that we can export and use
anywhere.
How to export a graph
To export any graph produced by ggplot2, we can simply use
the ggsave command, as follows: > ggsave(filename of image
to be saved,device = filetype #(e.g. png, jpeg, tiff, png, bmp, svg, or
pdf).
Unless otherwise specified, it defaults to last plot displayed.
ggsave("Fish sizes by type", device=jpeg)
Saving 7 x 7 in image
The image should now appear in your working directory.
Alternatively, you can also right-click on the generated image and
select ‘Save image as…’. Codes executed in the console also
appear in the ‘Plots’ tab in the bottom right window, where you can also
graphically export them.
Time series and line graphs
Recall that when we had a continuous or time series data, then the
most common type of graph to use was the line graph.
For this example, we will use the BOD dataset in the base R
package.
head(BOD)
As you can see, we have 2 columns: 1 indicating time, the other
oxygen demand. We want to plot the O2 demand vs time. As O2 is the
dependent variable and time is the independent variable, the former goes
onto the y-axis.
Replace geom_point() with geom_line() to draw a
line instead of scatter points.
ggplot(BOD, aes(Time, demand))+
geom_line()

You can still show the points if you’d like to clarify when the
measurements were made. To do so, you can use both geom_point()
with geom_line() commands in your code.
ggplot(BOD, aes(Time, demand))+
geom_line() +
geom_point(aes(color="red", alpha = 0.6, size = 2), show.legend = F)

Visualization of multiparameter data
So far, we’ve only looked into 2 parameters (fish type vs size or one
parameter vs time). What if we had several parameters that we wanted to
visualize simultaneously?
Consider the dataset called CO2, which shows carbon dioxide uptake in
grass plants from an experiment on the cold tolerance of the grass
species Echinochloa crus-galli. The data has 5 columns as can
be seen below:
print(CO2)
As you can see, this dataset has 1 independent numeric variable
(conc), 1 dependent numeric variable (uptake), and 3 categorical
variables (Plant, Type, and Treatment)
If we were to plot this like the first example, we’d plot
concentration vs uptake. As uptake is the dependent variable, it goes to
the y-axis. So we’ll have:
ggplot(CO2, aes(conc, uptake))+
geom_point()

But what if we want to see a 3rd parameter (such as Treatment) also
to investigate any relations with it too? We can add the treatment
parameter to be represented by different shapes to the above graph.
ggplot(CO2, aes(conc, uptake, shape=Treatment))+
geom_point()

As you see, we have the exact same graph produced but instead of the
dots we have 2 different shapes, circle and triangle, representing the
nonchilled and chilled treatments, respectively.
Finally, we want to add a 4th parameter as well: Plant. For
this variable we will use different colors to distinguish the different
plants in our dataset.
In the previous graph, things were already slightly difficult to
distinguish due to the small sizes of the points. Now with the extra
parameter, it might be even harder to analyze. So to improve the above
graph, let’s make the dots slightly bigger and increase their
transparency:
ggplot(CO2, aes(conc, uptake, color=Plant, shape=Treatment))+
geom_point(size=4, alpha=0.6)

Facets
Sometimes, when you have a complex dataset with too many variables,
you’ll reach the limit to how many of the variables you can add into a
single graph while still keeping it simple enough to read, understand,
or analyze.
In those cases, sometimes it is better to split the data into subsets
and display them as multi panel plots. This functionality in
ggplot2 is called facets.
Take the above example. Only now, we also want to add the
Type as well into the graph. We want to do that by splitting
the data into 2 panels, distinguished by the Type
parameter.
ggplot(CO2, aes(conc, uptake, color=Plant, shape=Treatment))+
geom_point(size=4, alpha=0.6)+
facet_wrap(~Type)

Now to analyze, we can deduce that there is a clear distinction
between the Quebec and Mississippi types, with uptake being relatively
higher in the former. There is also a clear Treatment effect in
Mississippi plants, with chilled plants having lower uptake than
nonchilled plants. However, this distinction is less clear in the Quebec
plants.
Finally, to complete our graph, we want to add a title and fix the
axis labels:
ggplot(CO2, aes(conc, uptake, color=Plant, shape=Treatment))+
geom_point(size=4, alpha=0.6)+
facet_wrap(~Type)+
labs (title="Uptake of CO2 per plant and treatment type",
x="concentration",
y= "uptake")

Try on your own
Select data(economics) This dataset was produced from US economic
time series data available from https://fred.stlouisfed.org/. It is a data frame with 6
population variables and 574 rows.
First of all, view the first 6 rows of the dataset so you have an
idea what it looks like.
Now plot the number of unemployed vs date. Make sure the dependent
variable is on the y-axis. Add onto your figure the median duration of
unemployment (uempmed) as size of the dots and the personal
savings rate (psavert) as the color of the dots.
Export the figure. Analyze!
Tip: The figure should look like this: 
Thirsty for more? Here are some additional resources
There are a plethora of resources that you can find freely online for
data visualization, in general and ggplot2, specifically. But here are a
few good suggestions if you want to delve deeper into the topic:
LS0tCnRpdGxlOiAiRGF0YSB2aXN1YWxpemF0aW9uIgpzdWJ0aXRsZTogIkFtZXJpY2FuIFVuaXZlcnNpdHkgb2YgQXJtZW5pYSIKYXV0aG9yOiAiRVNTIDEwMyAtIFNwcmluZyAyMDI0IgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgohW0ltYWdlIHNvdXJjZTogdGhlbmV3c3RhY2tdKGh0dHBzOi8vY2RuLnRoZW5ld3N0YWNrLmlvL21lZGlhLzIwMjMvMDEvMjg1ZDY4ZGQtY2hhcnRzLTEwMjR4NTgxLmpwZykKCiMjIyBXaHkgdmlzdWFsaXplPwoKRGF0YSB2aXN1YWxpemF0aW9uIGlzIHRoZSBncmFwaGljYWwgcmVwcmVzZW50YXRpb24gb2YgaW5mb3JtYXRpb24gYW5kIGRhdGEuIEJ5IHVzaW5nIHZpc3VhbCBlbGVtZW50cyBsaWtlIGNoYXJ0cywgZ3JhcGhzLCBhbmQgbWFwcywgZGF0YSB2aXN1YWxpemF0aW9uIHRvb2xzIHByb3ZpZGUgYW4gYWNjZXNzaWJsZSB3YXkgdG8gc2VlIGFuZCB1bmRlcnN0YW5kIHRyZW5kcywgb3V0bGllcnMsIGFuZCBwYXR0ZXJucyBpbiBkYXRhLiBIaWRkZW4gd2l0aGluIHlvdXIgZGF0YSBsaWUgaW1wb3J0YW50IGluc2lnaHRzLiBCdXQgdGhlIGNoYWxsZW5nZSBpcyB0aGF0IHlvdSBjYW7igJl0IGFsd2F5cyBjb25uZWN0IHRoZSBkb3RzIGJ5IGxvb2tpbmcgYXQgcmF3IG51bWJlcnMgYWxvbmUuIFdoZW4geW91IGxvb2sgYXQgeW91ciBkYXRhIHByZXNlbnRlZCBpbiBhIHZpc3VhbCBmb3JtYXQsIHBhdHRlcm5zLCBjb25uZWN0aW9ucywgYW5kIG90aGVyIOKAnGEtaGHigJ0gaW5zaWdodHMgZW1lcmdlIHRoYXQgd291bGQgb3RoZXJ3aXNlIHJlbWFpbiBvdXQgb2Ygc2lnaHQuCgpUaGUgZWFybGllc3QgZm9ybSBvZiBkYXRhIHZpc3VhbGl6YXRpb24gY2FuIGJlIHRyYWNlZCBiYWNrIHRvIHRoZSBFZ3lwdGlhbnMgaW4gdGhlIHByZS0xN3RoIGNlbnR1cnksIGxhcmdlbHkgdXNlZCB0byBhc3Npc3QgaW4gbmF2aWdhdGlvbi4gQXMgdGltZSBwcm9ncmVzc2VkLCBwZW9wbGUgbGV2ZXJhZ2VkIGRhdGEgdmlzdWFsaXphdGlvbnMgZm9yIGJyb2FkZXIgYXBwbGljYXRpb25zLCBzdWNoIGFzIGluIGVjb25vbWljLCBzb2NpYWwsIGhlYWx0aCwgYW5kIGVudmlyb25tZW50YWwgZGlzY2lwbGluZXMuCgpUaGVyZSBhcmUgbWFueSBkaWZmZXJlbnQgd2F5cyB0byB2aXN1YWxpemUgZGF0YS4gU29tZSBvZiB0aGUgbW9zdCBjb21tb24gdGVjaG5pcXVlcyBhcmU6CgotICAgKipUYWJsZXMqKjogVGhpcyBjb25zaXN0cyBvZiByb3dzIGFuZCBjb2x1bW5zIHVzZWQgdG8gY29tcGFyZSB2YXJpYWJsZXMuIFRhYmxlcyBjYW4gc2hvdyBhIGdyZWF0IGRlYWwgb2YgaW5mb3JtYXRpb24gaW4gYSBzdHJ1Y3R1cmVkIHdheSwgYnV0IHRoZXkgY2FuIGFsc28gb3ZlcndoZWxtIHVzZXJzIHRoYXQgYXJlIHNpbXBseSBsb29raW5nIGZvciBoaWdoLWxldmVsIHRyZW5kcy4KCi0gICAqKkJhciBncmFwaHMgYW5kIGJveHBsb3RzKio6IFRoZXNlIGFyZSB1c2VkIHRvIHJlcHJlc2VudCBhbmQgY29tcGFyZSBncm91cHMgb3IgY2F0ZWdvcmljYWwgdmFyaWFibGVzLiBCb3hwbG90cyBpbiBhZGRpdGlvbiBhbHNvIHJlcHJlc2VudCBudW1lcm91cyBkZXNjcmlwdGl2ZSBzdGF0aXN0aWNzIGFib3V0IGVhY2ggY2F0ZWdvcnkgbGlrZSBpdHMgbWVhbiBhbmQgcmFuZ2UuCgotICAgKipTY2F0dGVyIHBsb3RzKio6IFRoZXNlIHZpc3VhbHMgYXJlIGJlbmVmaWNpYWwgaW4gcmV2ZWxpbmcgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHR3byB2YXJpYWJsZXMsIGFuZCB0aGV5IGFyZSBjb21tb25seSB1c2VkIHdpdGhpbiByZWdyZXNzaW9uIGRhdGEgYW5hbHlzaXMuIEhvd2V2ZXIsIHRoZXNlIGNhbiBzb21ldGltZXMgYmUgY29uZnVzZWQgd2l0aCBidWJibGUgY2hhcnRzLCB3aGljaCBhcmUgdXNlZCB0byB2aXN1YWxpemUgdGhyZWUgdmFyaWFibGVzIHZpYSB0aGUgeC1heGlzLCB0aGUgeS1heGlzLCBhbmQgdGhlIHNpemUgb2YgdGhlIGJ1YmJsZS4KCi0gICAqKlBpZSBjaGFydHMgYW5kIHN0YWNrZWQgYmFyIGNoYXJ0cyoqOiBUaGVzZSBncmFwaHMgYXJlIGRpdmlkZWQgaW50byBzZWN0aW9ucyB0aGF0IHJlcHJlc2VudCBwYXJ0cyAocG9ydGlvbnMgb3IgcGVyY2VudGFnZXMpIG9mIGEgd2hvbGUuIFRoZXkgcHJvdmlkZSBhIHNpbXBsZSB3YXkgdG8gb3JnYW5pemUgZGF0YSBhbmQgY29tcGFyZSB0aGUgc2l6ZSBvZiBlYWNoIGNvbXBvbmVudCB0byBvbmUgb3RoZXIuCgotICAgKipMaW5lIGNoYXJ0cyBhbmQgYXJlYSBjaGFydHMqKjogVGhlc2UgdmlzdWFscyBzaG93IGNoYW5nZSBpbiBvbmUgb3IgbW9yZSBxdWFudGl0aWVzIGJ5IHBsb3R0aW5nIGEgc2VyaWVzIG9mIGRhdGEgcG9pbnRzIG92ZXIgdGltZSBhbmQgYXJlIGZyZXF1ZW50bHkgdXNlZCB3aXRoaW4gcHJlZGljdGl2ZSBhbmFseXRpY3MuIExpbmUgZ3JhcGhzIHV0aWxpemUgbGluZXMgdG8gZGVtb25zdHJhdGUgdGhlc2UgY2hhbmdlcyB3aGlsZSBhcmVhIGNoYXJ0cyBjb25uZWN0IGRhdGEgcG9pbnRzIHdpdGggbGluZSBzZWdtZW50cywgc3RhY2tpbmcgdmFyaWFibGVzIG9uIHRvcCBvZiBvbmUgYW5vdGhlciBhbmQgdXNpbmcgY29sb3IgdG8gZGlzdGluZ3Vpc2ggYmV0d2VlbiB2YXJpYWJsZXMuCgotICAgKipIaXN0b2dyYW1zKio6IFRoaXMgZ3JhcGggcGxvdHMgYSBkaXN0cmlidXRpb24gb2YgbnVtYmVycyB1c2luZyBhIGJhciBjaGFydCAod2l0aCBubyBzcGFjZXMgYmV0d2VlbiB0aGUgYmFycyksIHJlcHJlc2VudGluZyB0aGUgcXVhbnRpdHkgb2YgZGF0YSAob3IgZnJlcXVlbmN5KSB0aGF0IGZhbGxzIHdpdGhpbiBhIHBhcnRpY3VsYXIgcmFuZ2UuIFRoaXMgdmlzdWFsIG1ha2VzIGl0IGVhc3kgZm9yIGFuIGVuZCB1c2VyIHRvIGlkZW50aWZ5IG91dGxpZXJzIHdpdGhpbiBhIGdpdmVuIGRhdGFzZXQuCgoqKkltcG9ydGFudCoqOiBCeSBjb252ZW50aW9uLCB0aGUgeC1heGlzIGlzIHRoZSAqKmluZGVwZW5kZW50IHZhcmlhYmxlKiogYW5kIHRoZSAqKmRlcGVuZGVudCB2YXJpYWJsZSoqIGlzIHBsb3R0ZWQgb24gdGhlIHktYXhpcy4KClNvIGZhciB3ZSBoYXZlIGJlZW4gdXNpbmcgYmFzZSBSIHZpc3VhbGl6YXRpb24gdG9vbHMgKGUuZy4gd2hlbiB5b3UgdXNlZCB0aGUgY29tbWFuZDogKnBsb3QqKS4gSG93ZXZlciwgdGhlcmUgYXJlIHZhcmlvdXMgb3RoZXIgcGFja2FnZXMgdGhhdCB3ZSBjYW4gdXNlIHRvIHByb2R1Y2UgbmljZXIgYW5kIG1vcmUgc29waGlzdGljYXRlZCBncmFwaHMuIE9uZSBvZiB0aGUgbW9zdCBwb3B1bGFyIG9mIHN1Y2ggcGFja2FnZXMgaXMgY2FsbGVkICoqKmdncGxvdDIqKiouCgojIyMgQnV0IHdoYXQgYXJlIFIgcGFja2FnZXM/CgpPbmUgb2YgdGhlIHByaW1hcnkgcmVhc29ucyBmb3IgUuKAmXMgcG9wdWxhcml0eSBpcyBpdHMgZXh0ZW5zaXZlIHBhY2thZ2UgZWNvc3lzdGVtLiBPbiBS4oCZcyBtYWluIHBhY2thZ2UgcmVwb3NpdG9yeTogW0NvbXByZWhlbnNpdmUgUiBBcmNoaXZlIE5ldHdvcmtdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnLykgKENSQU4pIGFsb25lIHlvdSBoYXZlIG92ZXIgMTAsMDAwIHBhY2thZ2VzIGF2YWlsYWJsZSB0byBjaG9vc2UgZnJvbS4gWW91IGNhbiBzZWUgdGhlIGxpc3Qgb2YgYXZhaWxhYmxlIHBhY2thZ2VzIG9uIENSQU4gW2hlcmVdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9hdmFpbGFibGVfcGFja2FnZXNfYnlfbmFtZS5odG1sKS4gWWV0LCB3aGVuIHlvdSBmaXJzdCBpbnN0YWxsIFIgeW91IG9ubHkgZ2V0IGEgdmVyeSBsaW1pdGVkIHNldCBvZiBjb3JlIHBhY2thZ2VzIOKAnG91dCBvZiB0aGUgYm944oCdLiBBbnkgZnVydGhlciBwYWNrYWdlcyB0aGF0IHlvdeKAmWQgbGlrZSB0byB1c2UgeW91IGhhdmUgdG8gaW5zdGFsbCB5b3Vyc2VsZi4KCiMjIyBJbnN0YWxsaW5nIHBhY2thZ2VzCgpUbyBiZSBhYmxlIHRvIHVzZSBhIChub24tYmFzZSkgcGFja2FnZSBmb3IgdGhlIGZpcnN0IHRpbWUsIHdlIHdpbGwgbmVlZCB0byBmaXJzdCBpbnN0YWxsIGl0IG9uIG91ciBzeXN0ZW0uIEluc3RhbGxpbmcgcGFja2FnZXMgZnJvbSBDUkFOIGNvdWxkbuKAmXQgYmUgZWFzaWVyISBTaW1wbHkgdHlwZSBpbnN0YWxsLnBhY2thZ2VzKCkgd2l0aCB0aGUgbmFtZSBvZiB5b3VyIGRlc2lyZWQgcGFja2FnZSBpbiBxdW90ZXMgYXMgZmlyc3QgYXJndW1lbnQuCgpgYGB7cn0KaW5zdGFsbC5wYWNrYWdlcygiZ2dwbG90MiIpCmBgYAoKTm90ZTogQWx0aG91Z2ggSSBoYXZlIGluY2x1ZGVkIGFuZCBleGVjdXRlZCB0aGUgY29kZSB3aXRoaW4gbXkgbm90ZWJvb2sgaGVyZSAodG8gc2hvdyB5b3UgaG93IGl0IGlzIGRvbmUpLCBpdCBpcyB1c3VhbGx5IGFkdmlzYWJsZSB0byBub3QgaW5jbHVkZSB0aGlzIGluIFIgbm90ZWJvb2tzIGJ1dCBkaXJlY3RseSBpbiB5b3VyIGNvbnNvbGUgKHRoZSBib3ggYXQgdGhlIGxvd2VyIGxlZnQgY29ybmVyIHVzdWFsbHkgaW4gUlN0dWRpbykgYXMKCjEpICAqKllvdSB3aWxsIG9ubHkgbmVlZCB0byBpbnN0YWxsIGl0IG9uY2Ugb24gZWFjaCBjb21wdXRlciB5b3UgdXNlLioqCjIpICBJdCB3aWxsIG9mdGVuIHByb2R1Y2UgdmVyeSBsb25nIGNvZGVzIHRoYXQgd2lsbCBtYWtlIHlvdXIgaHRtbCAob3IgcGRmKSBvdXRwdXRzIHZlcnkgbWVzc3kuCgpPbmNlIGEgcGFja2FnZSBpcyBpbnN0YWxsZWQgb24geW91ciBzeXN0ZW0sIHlvdSBjYW4gbG9hZCBpdCB0byBSIGJ5IHVzaW5nIHRoZSBjb21tYW5kOiBsaWJyYXJ5KCpwYWNrYWdlIG5hbWUqKS4gKipZb3Ugd2lsbCBoYXZlIHRvIGRvIHRoaXMgZXZlcnkgdGltZSBhZnRlciB5b3UgcmVzdGFydCBSKiouIFRodXMsIHVubGlrZSB0aGUgKmluc3RhbGwucGFja2FnZXMqIGNvbW1hbmQsIGl0IGlzIHJlY29tbWVuZGVkIHRvIGluY2x1ZGUgdGhpcyBhdCB0aGUgdG9wIG9mIGVhY2ggb2YgeW91ciBub3RlYm9va3MsIHRvIG1ha2Ugc3VyZSB0aGUgcGFja2FnZXMgeW91IG5lZWQgYXJlIGxvYWRlZC4KCmBgYHtyfQpsaWJyYXJ5KGdncGxvdDIpCmBgYAoKIyMjIGdncGxvdDIKCipnZ3Bsb3QyKiBpcyBhIHBvd2VyZnVsIGRhdGEgdmlzdWFsaXphdGlvbiBwYWNrYWdlIGluIHRoZSBSIHByb2dyYW1taW5nIGxhbmd1YWdlLiBJdCBpcyBiYXNlZCBvbiB0aGUgZ3JhbW1hciBvZiBncmFwaGljcywgd2hpY2ggaXMgYSB3YXkgb2YgZGVzY3JpYmluZyBhbmQgYnVpbGRpbmcgZ3JhcGhzIHVzaW5nIGEgc3RydWN0dXJlZCBhcHByb2FjaC4gKmdncGxvdDIqIGFsbG93cyB5b3UgdG8gY3JlYXRlIGEgd2lkZSB2YXJpZXR5IG9mIHBsb3RzIGFuZCBncmFwaGljcywgaW5jbHVkaW5nIHNjYXR0ZXIgcGxvdHMsIGJhciBwbG90cywgbGluZSBwbG90cywgaGlzdG9ncmFtcywgYW5kIG1vcmUsIHdpdGggYSBoaWdoIGRlZ3JlZSBvZiBjdXN0b21pemF0aW9uIGFuZCBmbGV4aWJpbGl0eS4gSXQgaXMgbm93IG92ZXIgMTAgeWVhcnMgb2xkIGFuZCBpcyB3aWRlbHkgdXNlZCBpbiB0aGUgZGF0YSBzY2llbmNlIGFuZCBzdGF0aXN0aWNhbCBjb21tdW5pdGllcyBmb3IgY3JlYXRpbmcgdmlzdWFsbHkgYXBwZWFsaW5nIGFuZCBpbmZvcm1hdGl2ZSBwbG90cyBmcm9tIGRhdGEuCgpXaGlsZSBpdCBpcyBzbGlnaHRseSBtb3JlIGNvbXBsZXggdG8gZXhlY3V0ZSB0aGFuIHRoZSBzaW1wbGUgcGxvdHMgaW4gYmFzZSBSLCBvbmNlIHlvdSB1bmRlcnN0YW5kIGl0cyBzeW50YXggKGJ5IHByYWN0aWNpbmchKSB5b3Ugd2lsbCBnZXQgdGhlIGhhbmcgb2YgaXQgcXVpY2tseS4gSXQgaXMgYmVzdCB0byBpbWFnaW5lIGhvdyAqZ2dwbG90Miogd29ya3MgYXMgbWFraW5nIGdyYXBocyB3aXRoIGRpZmZlcmVudCBsYXllcnMuIEluIG1vc3QgY2FzZXMgeW91IHN0YXJ0IHdpdGggZ2dwbG90KCksIHN1cHBseSBhIGRhdGFzZXQgYW5kIGFlc3RoZXRpYyBtYXBwaW5nICh3aXRoIGFlcygpKSAqVGhpcyB3aWxsIGJlIHRoZSBiYWNrZ3JvdW5kIGFuZCBheGVzIG9mIHlvdXIgZ3JhcGgqLiBZb3UgdGhlbiBhZGQgb24gbGF5ZXJzIChsaWtlIGdlb21fcG9pbnQoKSBvciBnZW9tX2hpc3RvZ3JhbSgpKSAqVGhlc2Ugd2lsbCBiZSB0aGUgcG9pbnRzLCBsaW5lcyBvciBiYXJzIG9uIHRvcCBvZiB5b3VyIGJhY2tncm91bmQqLCBzY2FsZXMgKGxpa2Ugc2NhbGVfY29sb3VyX2JyZXdlcigpKSwgZmFjZXRpbmcgc3BlY2lmaWNhdGlvbnMgKGxpa2UgZmFjZXRfd3JhcCgpKSBhbmQgY29vcmRpbmF0ZSBzeXN0ZW1zIChsaWtlIGNvb3JkX2ZsaXAoKSkuIFdlIHdpbGwgY292ZXIgc29tZSBvZiB0aGVzZSBpbiB0aGlzIGxlY3R1cmUgYW5kIG1vcmUgdGhyb3VnaG91dCBvdXIgY291cnNlLiAKCiMjIyBMZXQncyB0cnkgaXQhCk5vdyB0aGF0IHdlJ3ZlIGxvYWRlZCB0aGUgZ2dwbG90IGxpYnJhcnkgaW50byBSLCBsZXQncyB0ZXN0IGl0IG91dC4KQnV0IGJlZm9yZSB3ZSBjYW4gcHV0IGl0IHRvIHVzZSwgd2UnbGwgbmVlZCB0byBhZGQgb25lIG1vcmUgdml0YWwgY29tcG9uZW50IHdlJ3JlIHN0aWxsIG1pc3NpbmcuIFRoZSBhY3R1YWwgZGF0YSEKCkxldCdzIHN0YXJ0IHdpdGggdGhlIGRhdGFzZXQgd2UgdXNlZCBsYXN0IHdlZWs6IGZpc2hfc2l6ZS5jc3YgYW5kIHJlY3JlYXRlIHRoZSBib3hwbG90IHdlIG1hZGUgYnV0IHdpdGggKmdncGxvdDIqIHRoaXMgdGltZS4KYGBge3J9CnNldHdkKCIvaG9tZS9rYXphbmppYW4vRG9jdW1lbnRzL1IgcHJvamVjdHMvRVNTMTAzLyIpCmZpc2ggPSByZWFkLmNzdiAoIkRhdGEvZmlzaF9zaXplLmNzdiIsIGhlYWRlcj1ULCBzZXA9IiwiKQpoZWFkKGZpc2gpCmBgYAoKSW4gdGhpcyBkYXRhc2V0LCB3ZSBoYXZlIDIgdmFyaWFibGVzOgoKLSAxIGNvbnRpbnVlcyB2YXJpYWJsZTogc2l6ZSAob3IgbGVuZ3RoKSBvZiB0aGUgZmlzaAotIDEgY2F0ZWdvcmljYWwgdmFyaWFibGU6IHRoZSB0eXBlIG9mIHRoZSBmaXNoCgpBcyB0aGUgc2l6ZSBvZiB0aGUgZmlzaCBpcyBvZnRlbiBkZXBlbmRlbnQgb24gaXRzIHR5cGUsIHdlIHdpbGwgYXNzdW1lIHRoYXQgZm9ybWVyIGlzIHRoZSAqKmRlcGVuZGVudCB2YXJpYWJsZSoqIChzbyB5LWF4aXMpIGFuZCB0aGUgbGF0dGVyIGlzIHRoZSAqKmluZGVwZW5kZW50IHZhcmlhYmxlKiogKHNvIHgtYXhpcykKClRoZSBzaW1wbGVzdCBnZ3Bsb3QyIHN5bnRheCBmb2xsb3dzIHRoZSBmb2xsb3dpbmcgbG9naWM6Cj4gZ2dwbG90IChkYXRhc2V0LCBhZXMgKHgtYXhpcywgeS1heGlzKSkgKyBncmFwaF90eXBlKCkgI3lvdSB3aWxsIG9mdGVuIGdldCBhIHNtYWxsIHBvcC11cCBpbiBSIHN0dWRpbyB3aGlsZSB0eXBpbmcgdGhlIGNvbW1hbmQgdG8gaGVscCB5b3UgY2hvb3NlIHRoZSBzeW50YXggZm9yIHRoZSBncmFwaCB0eXBlIHlvdSB3YW50LgoKU28gZm9yIG91ciBzcGVjaWZpYyBleGFtcGxlLCB3ZSBuZWVkIHRvIHJld3JpdGUgdGhlIGFib3ZlIGFzOgoKYGBge3J9CmdncGxvdChmaXNoLCBhZXMoZmlzaF90eXBlcywgc2l6ZSkpICsgZ2VvbV9ib3hwbG90KCkKYGBgCkFsdGVybmF0aXZlbHksIGlmIHdlIGRvIG5vdCB3YW50IHRvIHZpZXcgb3VyIGRhdGEgYXMgYSBib3hwbG90IGJ1dCB2aXN1YWxpemUgYWxsIG1lYXN1cmVtZW50cyBhcyBzZXBhcmF0ZSBwb2ludHMsIHlvdSBjYW4gY2hvb3NlICpnZW9tX3BvaW50KCkqIGFzIGEgZ3JhcGggdHlwZSBpbnN0ZWFkIG9mICpnZW9tX2JveHBsb3QoKQoKYGBge3J9CmdncGxvdChmaXNoLCBhZXMoZmlzaF90eXBlcywgc2l6ZSkpICsgZ2VvbV9wb2ludCgpCmBgYApOb3cgbGV0IHVzIG1ha2Ugc29tZSBtb2RpZmljYXRpb25zIHRvIHRoZSBhYm92ZSBncmFwaC4KQXNzdW1lIG91ciBwb2ludHMgYXJlIHRvbyBzbWFsbCwgc28gd2Ugd2FudCB0byBtYWtlIHRoZW0gYmlnZ2VyLCBhbmQgbWFrZSB0aGVtIHJlZCB0byBwb3Agb3V0IQpXZSBjYW4gYWRkIHRoZXNlIGRldGFpbHMgd2l0aGluIHRoZSBwYXJhbnRoZXNlcyBvZiBnZW9tX3BvaW50KCk6CgpgYGB7cn0KZ2dwbG90KGZpc2gsIGFlcyhmaXNoX3R5cGVzLCBzaXplKSkgKyBnZW9tX3BvaW50KHNpemU9MywgY29sb3I9InJlZCIpCmBgYAoKVGhlIGZsZXhpYmlsaXR5IG9mICpnZ3Bsb3QyKiBjb21lcyB0byB0aGUgZm9yZSB3aXRoIHRoZSBhYmlsaXR5IHRvIGFkZCBtdWx0aXBsZSB2aXN1YWxpemF0aW9uIHR5cGVzIGF0IG9uY2UuIEZvciB0aGUgZnVuIG9mIGl0LCBsZXQncyB0cnkgdG8gY29tYmluZSBib3RoIHByZXZpb3VzIGdyYXBocyAoYm94cGxvdCBhbmQgcG9pbnRzKSBpbiBvbmUgZ3JhcGguIFdlIGNhbiBldmVuIGFkZCBzb21lIHRyYW5zcGFyZW5jeSB0byB0aGUgcG9pbnRzIChhbHBoYSA9IDAgZm9yIGZ1bGwgdHJhbnNwYXJlbmN5IHRvIDEgZm9yIG5vIHRyYW5zcGFyZW5jeSkgdG8gbm90IGZ1bGx5IHNoaWVsZCB0aGUgYm94cGxvdHMgYmVsb3cgdGhlbS4KCmBgYHtyfQpnZ3Bsb3QoZmlzaCwgYWVzKGZpc2hfdHlwZXMsIHNpemUpKSArIAogIGdlb21fYm94cGxvdCgpICsgCiAgZ2VvbV9wb2ludChzaXplPTMsIGNvbG9yPSJyZWQiLCBhbHBoYSA9IDAuMikKYGBgCgpPdXIgZmlndXJlIHRob3VnaCBpcyBzdGlsbCBtaXNzaW5nIGEgdGl0bGUsIGhvd2V2ZXIuIFRoaXMgY2FuIGJlIGFkZGVkIHdpdGggdGhlIGNvbW1hbmQgKmxhYnMqLiBUbyBhbHNvIHNob3cgb3VyIHggYW5kIHktYXhlcyB0aXRsZXMgbW9yZSBwcm9mZXNzaW9uYWxseSwgd2UgY2FuIHVzZSB0aGUgY29tbWFuZHMgKnhsYWIqIGFuZCAqeWxhYiosIHJlc3BlY3RpdmVseS4gTGFzdGx5LCB5b3UgY2FuIGV4cGVyaW1lbnQgd2l0aCBkaWZmZXJlbnQgY29sb3IgdGhlbWVzIGxpa2UgYmxhY2sgYW5kIHdoaXRlIChidyksIGEgZGFyayB0aGVtZSwgYSBtaW5pbWFsIHRoZW1lLCBldGMuIFNlZSBiZWxvdzoKCmBgYHtyfQpnZ3Bsb3QoZmlzaCwgYWVzKGZpc2hfdHlwZXMsIHNpemUpKSArIAogIGdlb21fYm94cGxvdCgpICsgCiAgZ2VvbV9wb2ludChzaXplPTMsIGNvbG9yPSJyZWQiLCBhbHBoYSA9IDAuMikgKyAKICBsYWJzKHRpdGxlPSAiU2l6ZSBvZiBmaXNoZXMgYnkgdHlwZSIsIAogICAgICAgeD0iRmlzaCBUeXBlcyIsCiAgICAgICB5PSJMZW5ndGggaW4gY20iKSArCiAgdGhlbWVfYncoKQpgYGAKTm93IHdlIGhhdmUgYSBwcm9mZXNzaW9uYWwtbG9va2luZyBncmFwaCB0aGF0IHdlIGNhbiBleHBvcnQgYW5kIHVzZSBhbnl3aGVyZS4KCiMjIyBIb3cgdG8gZXhwb3J0IGEgZ3JhcGgKClRvIGV4cG9ydCBhbnkgZ3JhcGggcHJvZHVjZWQgYnkgKmdncGxvdDIqLCB3ZSBjYW4gc2ltcGx5IHVzZSB0aGUgKmdnc2F2ZSogY29tbWFuZCwgYXMgZm9sbG93czoKPiBnZ3NhdmUoZmlsZW5hbWUgb2YgaW1hZ2UgdG8gYmUgc2F2ZWQsZGV2aWNlID0gZmlsZXR5cGUgIyhlLmcuIHBuZywganBlZywgdGlmZiwgcG5nLCBibXAsIHN2Zywgb3IgcGRmKS4gCgpVbmxlc3Mgb3RoZXJ3aXNlIHNwZWNpZmllZCwgaXQgZGVmYXVsdHMgdG8gbGFzdCBwbG90IGRpc3BsYXllZC4KCmBgYHtyfQpnZ3NhdmUoIkZpc2ggc2l6ZXMgYnkgdHlwZSIsIGRldmljZT1qcGVnKQpgYGAKClRoZSBpbWFnZSBzaG91bGQgbm93IGFwcGVhciBpbiB5b3VyIHdvcmtpbmcgZGlyZWN0b3J5LiAKCkFsdGVybmF0aXZlbHksIHlvdSBjYW4gYWxzbyByaWdodC1jbGljayBvbiB0aGUgZ2VuZXJhdGVkIGltYWdlIGFuZCBzZWxlY3QgJypTYXZlIGltYWdlIGFzLi4uKicuIENvZGVzIGV4ZWN1dGVkIGluIHRoZSBjb25zb2xlIGFsc28gYXBwZWFyIGluIHRoZSAnUGxvdHMnIHRhYiBpbiB0aGUgYm90dG9tIHJpZ2h0IHdpbmRvdywgd2hlcmUgeW91IGNhbiBhbHNvIGdyYXBoaWNhbGx5IGV4cG9ydCB0aGVtLgoKIyMjIFRpbWUgc2VyaWVzIGFuZCBsaW5lIGdyYXBocwoKUmVjYWxsIHRoYXQgd2hlbiB3ZSBoYWQgYSBjb250aW51b3VzIG9yIHRpbWUgc2VyaWVzIGRhdGEsIHRoZW4gdGhlIG1vc3QgY29tbW9uIHR5cGUgb2YgZ3JhcGggdG8gdXNlIHdhcyB0aGUgbGluZSBncmFwaC4KCkZvciB0aGlzIGV4YW1wbGUsIHdlIHdpbGwgdXNlIHRoZSAqQk9EKiBkYXRhc2V0IGluIHRoZSBiYXNlIFIgcGFja2FnZS4KCmBgYHtyfQpoZWFkKEJPRCkKYGBgCgpBcyB5b3UgY2FuIHNlZSwgd2UgaGF2ZSAyIGNvbHVtbnM6IDEgaW5kaWNhdGluZyB0aW1lLCB0aGUgb3RoZXIgb3h5Z2VuIGRlbWFuZC4gV2Ugd2FudCB0byBwbG90IHRoZSBPMiBkZW1hbmQgdnMgdGltZS4gQXMgTzIgaXMgdGhlIGRlcGVuZGVudCB2YXJpYWJsZSBhbmQgdGltZSBpcyB0aGUgaW5kZXBlbmRlbnQgdmFyaWFibGUsIHRoZSBmb3JtZXIgZ29lcyBvbnRvIHRoZSB5LWF4aXMuCgpSZXBsYWNlICpnZW9tX3BvaW50KCkqIHdpdGggKmdlb21fbGluZSgpKiB0byBkcmF3IGEgbGluZSBpbnN0ZWFkIG9mIHNjYXR0ZXIgcG9pbnRzLgoKYGBge3J9CmdncGxvdChCT0QsIGFlcyhUaW1lLCBkZW1hbmQpKSsKICBnZW9tX2xpbmUoKSAKYGBgCllvdSBjYW4gc3RpbGwgc2hvdyB0aGUgcG9pbnRzIGlmIHlvdSdkIGxpa2UgdG8gY2xhcmlmeSB3aGVuIHRoZSBtZWFzdXJlbWVudHMgd2VyZSBtYWRlLiBUbyBkbyBzbywgeW91IGNhbiB1c2UgYm90aCAgKmdlb21fcG9pbnQoKSogd2l0aCAqZ2VvbV9saW5lKCkqIGNvbW1hbmRzIGluIHlvdXIgY29kZS4KCmBgYHtyfQpnZ3Bsb3QoQk9ELCBhZXMoVGltZSwgZGVtYW5kKSkrCiAgZ2VvbV9saW5lKCkgKwogIGdlb21fcG9pbnQoYWVzKGNvbG9yPSJyZWQiLCBhbHBoYSA9IDAuNiwgc2l6ZSA9IDIpLCBzaG93LmxlZ2VuZCA9IEYpCmBgYAoKCgojIyMgVmlzdWFsaXphdGlvbiBvZiBtdWx0aXBhcmFtZXRlciBkYXRhCgpTbyBmYXIsIHdlJ3ZlIG9ubHkgbG9va2VkIGludG8gMiBwYXJhbWV0ZXJzIChmaXNoIHR5cGUgdnMgc2l6ZSBvciBvbmUgcGFyYW1ldGVyIHZzIHRpbWUpLiBXaGF0IGlmIHdlIGhhZCBzZXZlcmFsIHBhcmFtZXRlcnMgdGhhdCB3ZSB3YW50ZWQgdG8gdmlzdWFsaXplIHNpbXVsdGFuZW91c2x5PwoKQ29uc2lkZXIgdGhlIGRhdGFzZXQgY2FsbGVkIENPMiwgd2hpY2ggc2hvd3MgY2FyYm9uIGRpb3hpZGUgdXB0YWtlIGluIGdyYXNzIHBsYW50cyBmcm9tIGFuIGV4cGVyaW1lbnQgb24gdGhlIGNvbGQgdG9sZXJhbmNlIG9mIHRoZSBncmFzcyBzcGVjaWVzICpFY2hpbm9jaGxvYSBjcnVzLWdhbGxpKi4gVGhlIGRhdGEgaGFzIDUgY29sdW1ucyBhcyBjYW4gYmUgc2VlbiBiZWxvdzoKCmBgYHtyfQpwcmludChDTzIpCmBgYAoKQXMgeW91IGNhbiBzZWUsIHRoaXMgZGF0YXNldCBoYXMgMSBpbmRlcGVuZGVudCBudW1lcmljIHZhcmlhYmxlIChjb25jKSwgMSBkZXBlbmRlbnQgbnVtZXJpYyB2YXJpYWJsZSAodXB0YWtlKSwgYW5kIDMgY2F0ZWdvcmljYWwgdmFyaWFibGVzIChQbGFudCwgVHlwZSwgYW5kIFRyZWF0bWVudCkKCklmIHdlIHdlcmUgdG8gcGxvdCB0aGlzIGxpa2UgdGhlIGZpcnN0IGV4YW1wbGUsIHdlJ2QgcGxvdCBjb25jZW50cmF0aW9uIHZzIHVwdGFrZS4KQXMgdXB0YWtlIGlzIHRoZSBkZXBlbmRlbnQgdmFyaWFibGUsIGl0IGdvZXMgdG8gdGhlIHktYXhpcy4KU28gd2UnbGwgaGF2ZToKYGBge3J9CmdncGxvdChDTzIsIGFlcyhjb25jLCB1cHRha2UpKSsKICBnZW9tX3BvaW50KCkKYGBgCkJ1dCB3aGF0IGlmIHdlIHdhbnQgdG8gc2VlIGEgM3JkIHBhcmFtZXRlciAoc3VjaCBhcyBUcmVhdG1lbnQpIGFsc28gdG8gaW52ZXN0aWdhdGUgYW55IHJlbGF0aW9ucyB3aXRoIGl0IHRvbz8KV2UgY2FuIGFkZCB0aGUgdHJlYXRtZW50IHBhcmFtZXRlciB0byBiZSByZXByZXNlbnRlZCBieSBkaWZmZXJlbnQgc2hhcGVzIHRvIHRoZSBhYm92ZSBncmFwaC4KCmBgYHtyfQpnZ3Bsb3QoQ08yLCBhZXMoY29uYywgdXB0YWtlLCBzaGFwZT1UcmVhdG1lbnQpKSsKICBnZW9tX3BvaW50KCkKYGBgCkFzIHlvdSBzZWUsIHdlIGhhdmUgdGhlIGV4YWN0IHNhbWUgZ3JhcGggcHJvZHVjZWQgYnV0IGluc3RlYWQgb2YgdGhlIGRvdHMgd2UgaGF2ZSAyIGRpZmZlcmVudCBzaGFwZXMsIGNpcmNsZSBhbmQgdHJpYW5nbGUsIHJlcHJlc2VudGluZyB0aGUgbm9uY2hpbGxlZCBhbmQgY2hpbGxlZCB0cmVhdG1lbnRzLCByZXNwZWN0aXZlbHkuIAoKCkZpbmFsbHksIHdlIHdhbnQgdG8gYWRkIGEgNHRoIHBhcmFtZXRlciBhcyB3ZWxsOiAqUGxhbnQqLgpGb3IgdGhpcyB2YXJpYWJsZSB3ZSB3aWxsIHVzZSBkaWZmZXJlbnQgY29sb3JzIHRvIGRpc3Rpbmd1aXNoIHRoZSBkaWZmZXJlbnQgcGxhbnRzIGluIG91ciBkYXRhc2V0LgoKSW4gdGhlIHByZXZpb3VzIGdyYXBoLCB0aGluZ3Mgd2VyZSBhbHJlYWR5IHNsaWdodGx5IGRpZmZpY3VsdCB0byBkaXN0aW5ndWlzaCBkdWUgdG8gdGhlIHNtYWxsIHNpemVzIG9mIHRoZSBwb2ludHMuIE5vdyB3aXRoIHRoZSBleHRyYSBwYXJhbWV0ZXIsIGl0IG1pZ2h0IGJlIGV2ZW4gaGFyZGVyIHRvIGFuYWx5emUuClNvIHRvIGltcHJvdmUgdGhlIGFib3ZlIGdyYXBoLCBsZXQncyBtYWtlIHRoZSBkb3RzIHNsaWdodGx5IGJpZ2dlciBhbmQgaW5jcmVhc2UgdGhlaXIgdHJhbnNwYXJlbmN5OgoKYGBge3J9CmdncGxvdChDTzIsIGFlcyhjb25jLCB1cHRha2UsIGNvbG9yPVBsYW50LCBzaGFwZT1UcmVhdG1lbnQpKSsKICBnZW9tX3BvaW50KHNpemU9NCwgYWxwaGE9MC42KQpgYGAKIyMjIEZhY2V0cwpTb21ldGltZXMsIHdoZW4geW91IGhhdmUgYSBjb21wbGV4IGRhdGFzZXQgd2l0aCB0b28gbWFueSB2YXJpYWJsZXMsICB5b3UnbGwgcmVhY2ggdGhlIGxpbWl0IHRvIGhvdyBtYW55IG9mIHRoZSB2YXJpYWJsZXMgeW91IGNhbiBhZGQgaW50byBhIHNpbmdsZSBncmFwaCB3aGlsZSBzdGlsbCBrZWVwaW5nIGl0IHNpbXBsZSBlbm91Z2ggdG8gcmVhZCwgdW5kZXJzdGFuZCwgb3IgYW5hbHl6ZS4KCkluIHRob3NlIGNhc2VzLCBzb21ldGltZXMgaXQgaXMgYmV0dGVyIHRvIHNwbGl0IHRoZSBkYXRhIGludG8gc3Vic2V0cyBhbmQgZGlzcGxheSB0aGVtIGFzIG11bHRpIHBhbmVsIHBsb3RzLiBUaGlzIGZ1bmN0aW9uYWxpdHkgaW4gKmdncGxvdDIqIGlzIGNhbGxlZCAqZmFjZXRzKi4KClRha2UgdGhlIGFib3ZlIGV4YW1wbGUuIE9ubHkgbm93LCB3ZSBhbHNvIHdhbnQgdG8gYWRkIHRoZSAqVHlwZSogYXMgd2VsbCBpbnRvIHRoZSBncmFwaC4gV2Ugd2FudCB0byBkbyB0aGF0IGJ5IHNwbGl0dGluZyB0aGUgZGF0YSBpbnRvIDIgcGFuZWxzLCBkaXN0aW5ndWlzaGVkIGJ5IHRoZSAqVHlwZSogcGFyYW1ldGVyLgoKYGBge3J9CmdncGxvdChDTzIsIGFlcyhjb25jLCB1cHRha2UsIGNvbG9yPVBsYW50LCBzaGFwZT1UcmVhdG1lbnQpKSsKICBnZW9tX3BvaW50KHNpemU9NCwgYWxwaGE9MC42KSsKICBmYWNldF93cmFwKH5UeXBlKQpgYGAKTm93IHRvIGFuYWx5emUsIHdlIGNhbiBkZWR1Y2UgdGhhdCB0aGVyZSBpcyBhIGNsZWFyIGRpc3RpbmN0aW9uIGJldHdlZW4gdGhlIFF1ZWJlYyBhbmQgTWlzc2lzc2lwcGkgdHlwZXMsIHdpdGggdXB0YWtlIGJlaW5nIHJlbGF0aXZlbHkgaGlnaGVyIGluIHRoZSBmb3JtZXIuIFRoZXJlIGlzIGFsc28gYSBjbGVhciBUcmVhdG1lbnQgZWZmZWN0IGluIE1pc3Npc3NpcHBpIHBsYW50cywgd2l0aCBjaGlsbGVkIHBsYW50cyBoYXZpbmcgbG93ZXIgdXB0YWtlIHRoYW4gbm9uY2hpbGxlZCBwbGFudHMuIEhvd2V2ZXIsIHRoaXMgZGlzdGluY3Rpb24gaXMgbGVzcyBjbGVhciBpbiB0aGUgUXVlYmVjIHBsYW50cy4gCgpGaW5hbGx5LCB0byBjb21wbGV0ZSBvdXIgZ3JhcGgsIHdlIHdhbnQgdG8gYWRkIGEgdGl0bGUgYW5kIGZpeCB0aGUgYXhpcyBsYWJlbHM6CmBgYHtyfQpnZ3Bsb3QoQ08yLCBhZXMoY29uYywgdXB0YWtlLCBjb2xvcj1QbGFudCwgc2hhcGU9VHJlYXRtZW50KSkrCiAgZ2VvbV9wb2ludChzaXplPTQsIGFscGhhPTAuNikrCiAgZmFjZXRfd3JhcCh+VHlwZSkrCiAgbGFicyAodGl0bGU9IlVwdGFrZSBvZiBDTzIgcGVyIHBsYW50IGFuZCB0cmVhdG1lbnQgdHlwZSIsIAogICAgICAgIHg9ImNvbmNlbnRyYXRpb24iLAogICAgICAgIHk9ICJ1cHRha2UiKSAKYGBgCgojIyMgVHJ5IG9uIHlvdXIgb3duCgpTZWxlY3QgZGF0YShlY29ub21pY3MpClRoaXMgZGF0YXNldCB3YXMgcHJvZHVjZWQgZnJvbSBVUyBlY29ub21pYyB0aW1lIHNlcmllcyBkYXRhIGF2YWlsYWJsZSBmcm9tIGh0dHBzOi8vZnJlZC5zdGxvdWlzZmVkLm9yZy8uIApJdCBpcyBhIGRhdGEgZnJhbWUgd2l0aCA2IHBvcHVsYXRpb24gdmFyaWFibGVzIGFuZCA1NzQgcm93cy4KCkZpcnN0IG9mIGFsbCwgdmlldyB0aGUgZmlyc3QgNiByb3dzIG9mIHRoZSBkYXRhc2V0IHNvIHlvdSBoYXZlIGFuIGlkZWEgd2hhdCBpdCBsb29rcyBsaWtlLgoKTm93IHBsb3QgdGhlIG51bWJlciBvZiB1bmVtcGxveWVkIHZzIGRhdGUuIE1ha2Ugc3VyZSB0aGUgZGVwZW5kZW50IHZhcmlhYmxlIGlzIG9uIHRoZSB5LWF4aXMuIEFkZCBvbnRvIHlvdXIgZmlndXJlIHRoZSBtZWRpYW4gZHVyYXRpb24gb2YgdW5lbXBsb3ltZW50ICgqdWVtcG1lZCopIGFzIHNpemUgb2YgdGhlIGRvdHMgYW5kIHRoZSBwZXJzb25hbCBzYXZpbmdzIHJhdGUgKCpwc2F2ZXJ0KikgYXMgdGhlIGNvbG9yIG9mIHRoZSBkb3RzLiAKCkV4cG9ydCB0aGUgZmlndXJlLiBBbmFseXplIQoKVGlwOiBUaGUgZmlndXJlIHNob3VsZCBsb29rIGxpa2UgdGhpczogIVt0aGlzXShodHRwczovL2kuaW1ndXIuY29tL3U0d1RCMEsucG5nKQoKCiMjIyBUaGlyc3R5IGZvciBtb3JlPyBIZXJlIGFyZSBzb21lIGFkZGl0aW9uYWwgcmVzb3VyY2VzCgpUaGVyZSBhcmUgYSBwbGV0aG9yYSBvZiByZXNvdXJjZXMgdGhhdCB5b3UgY2FuIGZpbmQgZnJlZWx5IG9ubGluZSBmb3IgZGF0YSB2aXN1YWxpemF0aW9uLCBpbiBnZW5lcmFsIGFuZCBnZ3Bsb3QyLCBzcGVjaWZpY2FsbHkuIEJ1dCBoZXJlIGFyZSBhIGZldyBnb29kIHN1Z2dlc3Rpb25zIGlmIHlvdSB3YW50IHRvIGRlbHZlIGRlZXBlciBpbnRvIHRoZSB0b3BpYzoKCi0gSWYgeW91IHdhbnQgdG8gZGl2ZSBpbnRvIG1ha2luZyBjb21tb24gZ3JhcGhpY3MgYXMgcXVpY2tseSBhcyBwb3NzaWJsZSwgdGhlIFtSIEdyYXBoaWNzIENvb2tib29rXShodHRwczovL3ItZ3JhcGhpY3Mub3JnLykgYnkgV2luc3RvbiBDaGFuZy4gSXQgcHJvdmlkZXMgYSBzZXQgb2YgcmVjaXBlcyB0byBzb2x2ZSBjb21tb24gZ3JhcGhpY3MgcHJvYmxlbXMuCi0gVGhlIFtEYXRhIFZpc3VhbGl6YXRpb25dKGh0dHBzOi8vcjRkcy5oYWQuY28ubnovZGF0YS12aXN1YWxpc2F0aW9uLmh0bWwpIGFuZCBbR3JhcGhpY3MgZm9yIGNvbW11bmljYXRpb25dKGh0dHBzOi8vcjRkcy5oYWQuY28ubnovZ3JhcGhpY3MtZm9yLWNvbW11bmljYXRpb24uaHRtbCkgY2hhcHRlcnMgaW4gW1IgZm9yIERhdGEgU2NpZW5jZV0oaHR0cHM6Ly9yNGRzLmhhZC5jby5uei8pLgotIElmIHlvdeKAmWQgbGlrZSB0byBmb2xsb3cgYSB3ZWJpbmFyLCB0cnkgW1Bsb3R0aW5nIEFueXRoaW5nIHdpdGggZ2dwbG90Ml0oaHR0cHM6Ly95b3V0dS5iZS9oMjlnMjF6MGE2OCkgYnkgVGhvbWFzIExpbiBQZWRlcnNlbi4KLSBUaGUgZ2dwbG90MiBjaGVhdHNoZWV0OiAhW2dncGxvdDIgY2hlYXRzaGVldF0oaHR0cHM6Ly93d3cuYnVzaW5lc3Mtc2NpZW5jZS5pby9hc3NldHMvMjAyMS0wNy0yNy1nZ2ZvcmNlLWh1bGwtcGxvdHMvZ2dwbG90Ml9jaGVhdHNoZWV0LmpwZykKCgoKCg==