Welcome to the 2nd R workshop of LIFE4138!
Last time, we learned a bit about the basics and structure of the R
language, using base R. This time, it’s a little bit different. We’ll
think about the different coding philosophies of R coding (there are
many many many ways to approach R), and today I’ll guide you through a
little bit of what is known as the tidyr philosophy. This is an arguably
more advanced way to handle and explore your data, and then we’ll get
some hands on experience of a different method of visualising data than
last time, by using the ggplot2 package.
Right. Our main aim for today is to give you a little bit more
insight into how R works, and how we can approach it. Don’t worry if you
still don’t feel like you’ve got the basics absolutely nailed down, this
is something that will come in time, with continued practice. Remember
you can always look back at last session if you’re struggling, but now
you’ve got a grounding of the basics, we can begin to build on it.
Keep in mind the language analogy. If you were learning Spanish,
you’d appreciate that you have to keep practicing. You’d also realise
pretty rapidly that there are often multiple ways to achieve the same
result - the same is true for R. For any outcome, there are multiple
ways to get there, and the only way to establish yourself as a
proficient R (or Python, or unix, or C++, or any other language) user is
to get stuck in and try things out!
R philosophies
There are many many ways that we can approach our coding in R. The
original way, baseR, is what we covered in the last session. It was
originally built on vector-based data, way back when R was first
developed in the early 90s.
Another common approach to using R is a method known as tidyR, which
utilises a selection of packages called the tidyverse.
Each of the packages within the tidyverse are built with the same
underlying ethos, which is the ability to make R code more readable and
reproducible. The focus of data handling in the tidyverse is the
data.frame object as an entire entity, rather than the
vectors within.
There are several other popular R philosophies (for e.g. the
data.table philosophy), but we wont delve into those here,
we’ll stick to baseR and the tidyverse.
It’s worth knowing that you may well come across some rather strong
opinions about these two coding methods, particularly on twitter. With
some quick searching of the term “tidyverse”, you can quite quickly find
some very heated debates! In the interest of balance, I’ll suggest that
there are advantages and disadvantages to both approaches, and their
applicability or suitability varies massively with the context of what
it is that you’re trying to achieve.
In my opinion, it’s better to be bilingual. Use what works for you,
when it works for you. I tend to use a bit of a mishmash of both
approaches, but then I’m not overly opinionated on the subject. Do what
works. Tidyverse can help to make things a little clearer, but in some
cases it’s overkill, and baseR is actually simpler to use.
What is the tidyverse?
The tidyverse is a diverse set of packages and tools, which include
popular packages such as dplyr, ggplot2,
readr, and purrr. Several of these packages
you might use without ever explicitly calling them, because of the
nature of the way that the tidyverse is installed. The main ones that
we’ll focus on here are dplyr and ggplot2.
ggplot2, as the name might suggest, is a package explicitly designed to
rethink the way that R handles plotting and data visualisation. We’ll
talk more about that later though.
dplyr
dplyr is a really useful package for data wrangling and manipulation.
It is invaluable when you are trying to get your data into a useable
format, or get a quick summary to help you understand your data a little
better. It is particularly useful for filtering your dataset. dplyr
allows you to extract information to get your data into shape for
downstream analysis.
The principle of data wrangling sounds tedious, but it is a crucially
important part of bioinformatics and data science. dplyr is explicitly
designed to handle data wrangling in R, and uses a variety of tools and
functions to make this easy and accessible. As an analogy, if like me,
your desk is messy and chaotic, I often find that tidying it up is a
great way to help me to focus my mind on what it is I’m meant to be
getting on with, rather than just staring at the mess and playing with
the random bit of bluetac I’ve found. The same principle can be applied
to your data. If you have a messy dataset with loads of variabes and
nonsense in, it can become difficult to focus. Filtering out the stuff
you don’t need and tidying it up is a vital first step in any
analysis.
To get to grips with this, we’re going to use a really popular
dataset that’s integrated into dplyr - the starwars
dataset. The likelihood of you being a starwars superfan with an
encyclopaedic knowledge of the heights and weights of characters from
within the starwars universe is low, so it provides an excellent example
of how, by using dplyr, you can get to know and understand a
dataset.
Let’s get cracking then.
First things first, we need to install and load the packages we need.
There are several ways of doing this, you can either install and load
the entire collection of tidyverse packages, or we can just install the
ones that we’ll need here:
install.packages("tidyverse")
library(tidyverse)
# or
install.packages("dplyr")
install.packages("ggplot2")
library(dplyr)
library(ggplot2)
Now, we can load the starwars dataset into our R session:
data(starwars)
You might notice that the starwars data displays as a
tibble rather than the typical data.frame. A
tibble is very similar to a data.frame, but
with some bonus features. These are not generally immediately apparent
(or particularly important in this context). A tibble is
essentially an updated data.frame, and is a very neat
tidyverse add-on. At first glance, it’s perhaps obvious that the display
is a little nicer than we’re used to. Three main differences that you
may notice:
- Shows only the first 10 lines -
data.frame prints the
entire contents - this essentially calls head() on the
data.
- Also only displays the first few columns - the rest of the
information such as the columns not shown is listed below the tibble
output.
- There is information on how things are coded. Here we can see that
the name is coded as a character input (which we might expect). Height
is an integer, which is just a whole number with no decimal places (or,
a discrete numeric). Mass is what is known in R as a double, or
dbl - this essentially means it’s a floating point number
with any potential value from -Inf to Inf.
We can use tibbles in the same way that we might use a
data.frame - for e.g.:
starwars$name
displays the names of all of the characters in the
tibble, just as it would in a data.frame
format.
The pipe operator %>%
Before we go any further, it’s important to introduce the pipe
operator to you. The pipe operator is a really useful bit of kit for
coding in R, and it comes from the package magrittr
(although the magrittr library is automatically loaded
alongside dplyr so don’t worry about installing it!). The
reason the pipe-containing package is called magrittr is
because of a famous Belgian surrealist artist, who painted the famous
“The Treachery of Images”, seen below:

The text, Ceci n’est pas une pipe is French for “this is not
a pipe”.
The pipe function, coded as %>% allows you to “pipe”
data from one command or function, directly to another. It works in a
very similar way to unix pipes, and allows you to chain together
functions in a single code block, allowing for more readable code. You
rarely, if ever, have to use pipe operators in your
code, but we’ll use them lots here to demonstrate their usefulness. I
find pipes make for easier coding, as you can break down complex
commands into their consituent parts, rather than wrestling with nested
functions with a million brackets. Piping helps you to take a simple
command, and build up the complexity of it slowly and logically,
iteratively adding bits and sense-checking as you go, before you end up
with a complex but readable and easily reproducible bit of code.
Let’s demonstrate the usefulness of a pipe alone, before we combine
it with dplyr. Say we wanted to work out the length of the
name column in the starwars dataset.
We’ll first demonstrate without the pipe operator, and then with
it.
length(starwars$name)
[1] 87
starwars$name %>%
length()
[1] 87
These two bits of code give us the same result (87!) - here, where
the code is relatively straightforward and focussing around only a
single function, it is perhaps easier to use the baseR version. When we
get to more complicated stuff, the usefulness of pipes will be much more
apparent. Essentially what the second bit of code is saying is take the
name column from within the starwars dataset, and pop it
inside the length function.
Piping and dplyr
The select() function
Piping is great for data manipulation, particularly when combined
with the tools in dplyr. Say you want to select a column
from a dataset. We can of course do this using our previous method of
the $ operator, or, we can use the select()
function from `dplyr.
starwars$name
starwars %>%
select(name)
Here, the select() function perhaps makes it more
obvious what the code means, particularly for those of you not used to
reading R. You also end up with slightly different outputs, in that the
tidyverse solution gives you a tibble output.
But, what if we want to select multiple columns in one go? In baseR,
we would have to use our vector-based indexing strategies (the square
brackets!), with the c() function. It’s much simplier in
the tidyR solution:
# The baseR solution:
starwars[ ,c("name","homeworld")]
# Tidyverse:
starwars %>%
select(name, homeworld)
Note that we do not use the “” in the select()
function, because we’ve already told R that we are looking inside the
starwars dataset, by piping it to the function. In the baseR solution,
we have to use them otherwise R will look for objects first.
The select() function is a really quick and super
powerful way of subsetting data. There are also several helper arguments
that you can use inside of select() in order to customise
how you want to filter. We will have a look at two of them below, but
you can have a look at the rest by using the help function on the select
command ?select.
First, we can use the helper function contains() to
select only the columns that contain a certain character. Let’s try and
use the tidyverse to select only columns which have an underscore (“_“)
in:
Notice that this time, we used quotation marks as we are asking R to
pattern match a bit of a string. We end up with the above tibble - the
columns all contain an underscore in their names!
We can also use the starts_with() helper function. This
time, we’ll select all the columns whos name start with a lower-case
s:
Here, we end up with columns “skin_colour”, “sex”, “species”, and
“starships” - all of which start with a lowercase s - so our code
works!
The select() function is versatile - we can also use it
to select all columns except name and homeworld, by editing the
code we used earlier - recall we used
starwars %>% select(name, homeworld) - we can just add -
symbols in front of the column names we want to remove…
We can scroll through the resulting tibble and see that all columns
except name and homeworld are present!
The filter() function
Okay, now we’ve learned how to select columns - how do we filter out
rows? The language differs slightly (and so do the functions! when we’re
discussing handling rows and columns:
We always select columns, and filter rows
In baseR, we use indexes to remove things. dplyr
functions in a similar way, but is optimised for readability. It still
inherently functions on the logical `TRUE/FALSE operators,
but in a slightly different way. Let’s have a look at an example to
better explain what I’m talking about. If we wanted to select all of the
humans in our dataset, in baseR, we’d first have to return a series of
logical operators, and then work out where to put them in our indexing
system. In tidyR, we simply pipe to the filter()
function:
# BaseR solution:
starwars$species == "Human" # This is the logical statement producing bit of code, that needs to go in the [] index system somewhere...
starwars[starwars$species == "Human", ] # Don't forget the comma to tell R we are only looking in rows!
# Tidyverse solution:
starwars %>%
filter(species == "Human")
The particularly discerning will have noticed that these solutions
provide us with two slightly different outcomes - the first gives us a
tibble with dimensions 39x14, and the tidyverse solution gives us a
tibble which is only 35x14. This difference is to do with the way the
select() function handles NA values - it
automatically removes them, whereas the baseR solution retains them in
the output. In order to get rid of them, we need to add another function
to our base solution - the which() function. By wrapping
our filtering process in which(), we are telling R to
remove any characters for which the species is a NA
value:
starwars[which(starwars$species == "Human"), ]
This is where the difference between base and tidyR really becomes
apparent - as an R novice, the base solution is difficult to interpret -
it’s certainly not immediately obvious what is going on!
Right then - we’ve learned how to filter a dataset to show us only
the results which contain a string value in a single column - what if we
want to filter for more than one thing?! What if we want all humans
which were born on Tatooine? We can just add another argument to our
filter() function using a comma:
We can establish fairly quickly using the tidyverse approach that
there are 8 humans in the starwars universe who were born on
Tatooine.
Combining functions
So, we’ve estblished that you can select columns and filter rows - we
can also combine these to create an even more powerful data wrangling
tool! We can pull out the variables that we’re interested in, which is a
key part of the tidyverse. It’s important here to note however that we
are doing this process to better understand our data, not to just remove
bits of it that we don’t want!
Now, let’s combine the select() and
filter() commands using our pipe operator to give us a
dataset that contains only the name, height, and birth year of our human
characters:
starwars %>%
filter(species == "Human") %>%
select(name, height, birth_year)
Remember the differences in when you need to use quotations!
That was a really straightforward and easy to read way of filtering
our dataset to contain only the information that we want. We can perform
the same function in BaseR by filling in both sides of our square
brackets to give a set of information about exactly what rows and
columns we want to keep, but it is much clunkier and less
user-friendly:
Using dplyr to get summaries of data
We can use the filter() and select()
functions to summarise our data and give us some information about it.
Summarising data is an important and useful tool - we might want to
count the number of observations in a group, or get a mean value of
subsets for example. There are a set of summary functions that are very
useful for this - we’ll hav a look at tally(),
group_by() and summmarise() below - they allow
you to create a new tibble for plotting out output as a summary
dataset.
Counting by groups
First, let’s learn to count within groups - perhaps we want to count
how many of each species there are in our starwars data. We can do this
by using the group_by() and tally() functions
- lets see how they work:
starwars %>%
group_by(species)
When you run the above, you end up with this tibble output. You can
see at the top next to the dimensions that we have 38 different species
in our dataset, but this isn’t obvious from looking at just the data.
Let’s use the tally() function to count them up:
starwars %>%
group_by(species) %>%
tally()
Tally literally counts the number of occurrences within a single
group, and produces a new tibble with a new count column, “n”. We can
see the species names, and see that we’ve got 6 Droids and 3 Gungans,
and 1 of everything else in the display. If we want more than 10 rows,
we can pipe the code to the print() function, and provide
how many rows we want in the argument n = within the
function. If you want R to print all the data without having to check
how many rows there are, you can ask it to print infinite rows with
n = Inf:
starwars %>%
group_by(species) %>%
tally() %>%
print(n = Inf)
Okay - but what if we want R to give us some more complex
information? What if we want to know the counts of the genders within
the species too? We can iteratively make our code more complicated to
achieve these things - in this case, we just need to add another
argument to the group_by() function:
starwars %>%
group_by(species, gender) %>%
tally() %>%
print(n = Inf)
This technique is useful for counting bits of information, as well as
plotting. Maybe you could envision a situation where you would want to
plot the results of genders separately.
We can get more detailed still - we take take height and mass for
example, and summarise it. This is similar to what we’ve just done, but
slightly more complex - let’s work out the average height for each
species. Here, we will introduce the summarise() function
into our code pipeline.
starwars %>%
group_by(species) %>%
summarise(mean_height = mean(height, na.rm = TRUE))
The summarise command is made up of a series of
components here:
- First,
mean_height is creating a new column, called
“mean_height”
- We are then using an
= to tell R what to populate that
column with
- After the
=, we use the mean() function,
with two arguments. The first is telling R what we want to work out the
mean of (in this case, height), and the second is the
na.rm = TRUE argument - recall from last session that lots
of functions can’t cope with missing data, which overrides the rest of
the data to give an NA output.
We are essentially asking R to look within each species, and return
the mean values for height, removing any NA values as it
goes.
Now, lets run the same code but add an extra column for mass -
remember our coding style of starting small and adding bits on:
starwars %>%
group_by(species) %>%
summarise(mean_height = mean(height, na.rm = TRUE),
mean_mass = mean(mass, na.rm = TRUE))
You can see here that even though we’ve got an na.rm
argument, we still have a NaN in our dataset - this is
because for whatever reason, it’s apparently impossible to gain data on
the mass of a Chagrian!
As with all things in R, there is more than one tidyverse solution to
the above problem, we can also use the vars() argument
within the summarise_at() function, this is subtly
different to the summarise() function, where we ask R to
summarise multiple things at once using the same function:
starwars %>%
group_by(species) %>%
summarise_at(vars(height, mass), mean, na.rm = TRUE)
Hopefully, here we’ve demonstrated the use of the pipe mechanism in
dplyr to build more complex commands which are readable and
easy to follow the logic of. Remember to start simple, and build
yourself up to the more complicated stuff, using the new “grammar” that
you’ve learned to create complex code structures one step at a time. As
a general rule, you shouldn’t use more than ten pipes in a single
stretch - if you’re doing this, it’s probably best to resassign your
object a new name part-way through the process and start from scratch
with the new object.
ggplot2
Time for a bit of a tone change, to shift to a different way of
exploring data within the tidyverse. Whist dplyr is great
for exploring your data and getting to know it, data visualisation is a
different approach.
The “gg” in ggplot2 stands for “the grammar of
graphics”. The idea behind this package is that it is built to make you
think about data vis in a slightly different way. The way that you use
ggplot2 is different to plotting in baseR, and if you’re very familiar
with base plots, it can seem difficult to get your head around, although
it’s certainly worth persevering. However, if you are new to R, it’s a
great way of learning how create graphics.
ggplot is extremely flexible, with lots of additional packages which
you can install that integrate into it - the possibilities for graphical
customisation are almost infinite. It’s a great way to create
publication ready high quality plots quickly and easily - I know that
I’ve used ggplot every single time I’ve written and published any
science!
There are three key components to any graphics created in ggplot:
- A data.frame or tibble (where ggplot is getting the data to plot
from)
- A co-ordinate based system of mappable variables - i.e. an x and y
axis, allowing ggplot2 can map variables to it
- Layers of geometry, or
geom, which plot your data.
This sounds quite complicated and abstract, but in reality it’s a
simple concept - think of ggplot like a raster or vector based image
processing/design software like photoshop or GIMP, where you iteratively
add layers, building up to your final plot. Sound familiar? ggplot (and
all the tidyverse packages) work on the same code-building philosophy as
dplyr!
Before we begin, if you haven’t done so already, remember to load
ggplot2 into your R environment:
install.packages("ggplot2")
library(ggplot2)
Scatter plots
The best way to learn is, as always, to have a go yourself. First,
we’ll create a scatter plot! This is similar to the baseR
plot(x, y) output, but infinitely more customisable. Let’s
plot the relationship between height and mass of characters within the
starwars universe.
# If you don't already have the starwars data loaded:
data(starwars)
We’ll build up those layers, starting with telling R what dataset we
are using, with the ggplot() function, and slowly build up
to a complete plot. Note that whilst the package is called
ggplot2, the plotting function is just
ggplot()
ggplot(starwars)

This generates us a nice blank grey square. It might not seem like a
fabulous start, but we’ve managed to fulfull our first of the three
necessary inputs - a dataframe.
Let’s build on this by adding the next part - employing a co-ordinate
system for us to map our variables on to. We do this by using the
aes() argument within the ggplot() function.
Here, aes stands for aesthetics - which doesn’t mean what
the plot looks like, but tells ggplot exactly what we want to map onto
our graph:
ggplot(starwars, aes(x = height, y = mass))

Yay - we have our co-ordinate system and our axes in place ready to
map the data onto. Note that in the aes() argument I have
specified which is x and which is y, you do not need to do this. R
automatically plots x and then y, so typing
ggplot(starwars, aes(height, mass)) would yeild the same
result.
Now, let’s add the points to the graph. We do this by adding a new
layer to the plot, with one of the set of geom functions in
ggplot - geom_point(). To add a new layer, we end the
previous line of code with a +, which tells R that we
weren’t finished with the last line:
ggplot(starwars, aes(x = height, y = mass))+
geom_point()

You may see a warning that says R has removed 28 rows with missing
values - these are just our NA values from the dataset, so
you can ignore that for now.
Now, plotting our scatter plot of height and mass has shown us why we
might want to plot our data - it seems that we have a single individual
with a mass of around 1400 units, whereas everyone else is below about
200! If you know anything about the starwars universe you might be able
to guess who this is… For everyone else - let’s see if we can work it
out by going back to our dplyr skills that we’ve just
learned, and add in a way to only display information about individuals
with a mass of greater than 1000!
starwars %>%
filter(mass > 1000) %>%
select(name, species, mass)
If you know anything about starwars, perhaps unsurprisingly, our
answer is Jabba the Hutt!
Anyway, back to ggplot.
Histograms
Sometimes, you might want to plot the distribution of your data. This
is useful for both identifying outliers, and also for seeing what our
data look like. In lots of statistical tests, we make assumptions
regarding the distribution of our data - often this assumption is that
our data follow a normal distribution. We can create a histogram really
quickly using ggplot and see if this is true!
We’ll start by building up our data as we did before, but we’ll go
straight to adding the co-ordinate system:
ggplot(starwars, aes(mass))

You might have noticed that we only have one axis here - this is
because we have only supplied R with a single aesthetic (the x
aesthetic). The reason that we have done this, is because histograms
plot a single variable against it’s count - we don’t know what that
count is yet, ggplot will figure that out for us. Notice also that we
can get an idea of the scale just by looking at the x axis, we can see
here that our mass ranges from 0 to way above 1000 (which we now know is
a direct result of Jabba the Hut!).
Let’s add the histogram geom.
ggplot(starwars, aes(mass))+
geom_histogram()

We can see that, as in our scatterplot, most individuals are below
about 250 units of mass, with a single individual way over 1000!
There are loads of different geoms available, and lots of online
resources to check out - the ggplot manual is particularly useful! For
now, let’s just have a look at one more, the boxplot. Boxplots are an
incredibly useful way of looking at distributions of data within groups,
and working out whether particular groups from a single dataset differ
from one another in a certain measurement. Let’s plot a boxplot that
tells us about the mass of species from within the starwars
universe:
ggplot(starwars, aes(x = species, y = mass))+
geom_boxplot()

Ah. This isn’t a very nice plot. There’s far too much data, and it’s
all very messy. We can’t see any of our species names, or really work
out what’s going on at all - lets learn how to fix it…
Combining ggplot2 and dplyr
It’s time to combine our new plotting and data-wrangling skillsets!
ggplot is a great way of showing data, but really the power of the
tidyverse comes when you integrate the packages with one another. The
combined philosophies of dplyr and ggplot2 can create us a much nicer
plot. Because dplyr and ggplot2 were built together under the tidyverse
umbrella, they integrate really smoothly with one another, and combining
them is as simple as piping from a dplyr filter into a ggplot function.
You can take a dataset you don’t know, and really get a handle on it by
combining these tools. Let’s try here.
We’ll go back to our boxpot and use what we’ve learned with dplyr to
create a much nicer boxplot that describes the mass of three different
species (rather than all of them at once!). So, which species shall we
use? In a dataset that contains lots of observations of a single
individual of a species, I think it makes sense to select the three most
abundant species. Remember how earlier we used the
group_by() and the tally() functions to get R
to count the number of individuals in each species?
starwars %>%
group_by(species) %>%
tally()
This is great, but it would be better if we could order it and see at
a glance which species had the most individuals - we can do this with
the arrange() function and the desc
argument:
starwars %>%
group_by(species) %>%
tally() %>%
arrange(desc(n))
desc(n) tells the arrange() function that
we want to display our data in descending order of the number of
individuals in each species.
We can see from the resulting tibble that we have 35 humans, 6
droids, our next highest is NA where species wasn’t
recorded, so we’ll ignore that, and then 3 gungans. We’ll plot the mass
of each of these three species! To do this, we will need to filter our
data using dplyr. We can filter for mulitple matches using
the OR operator | thus:
starwars %>%
filter(species == "Human" | species == "Droid" | species == "Gungan")
When we run the code to sense check ourselves, it’s tricky to see if
it’s worked in the way we wanted. We can get round this by piping to
select so we can only see the relevant columns:
starwars %>%
filter(species == "Human" | species == "Droid" | species == "Gungan") %>%
select(name, species, mass)
Right, we still can’t see if we’ve got any Gungans in here. Let’s get
around that by adding a tally to display a count of how many species are
in our new selection - don’t forget the group_by() to tell
tally what it needs to count!
starwars %>%
filter(species == "Human" | species == "Droid" | species == "Gungan") %>%
select(name, species, mass) %>%
group_by(species) %>%
tally()
Fabulous. It seems that we’ve got all of our data in check, and our
code seems to be doing what we want it to! We can delete those final
group_by() and tally() sense checks, and pipe
straight to ggplot. We’ll just plot the aesthetics first to check if
we’ve got the correct mapping and that only three species appear on the
x axis. We don’t need to include the name of the data in our
ggplot() command this time - R already knows what data
we’re using from our piping
starwars %>%
filter(species == "Human" | species == "Droid" | species == "Gungan") %>%
select(name, species, mass) %>%
ggplot(aes(x = species, y = mass))

Excellent. Now, let’s add the boxplot geom.
starwars %>%
filter(species == "Human" | species == "Droid" | species == "Gungan") %>%
select(name, species, mass) %>%
ggplot(aes(x = species, y = mass))+
geom_boxplot()

This is a much nicer and more successful boxplot than before! We can
see that the mean mass of Droids tends to be much lower than Gungans and
Humans, but their mass is more variable.
We have successfully combined ggplot and dplyr in a really useful and
powerful way, that will make exploring data much quicker and easier.
Reshaping data
The starwars dataset is already in a nice format for plotting, and we
haven’t needed to do anything with it to get it there. This won’t always
be the case with real world data. Sorting this out is complicated, and
it’s okay if you don’t fully grasp the following the first time round -
you’ll get used to it by practicing and having a go with data in your
own time.
Now, there are two main types of data:
- long data - many rows, but few columns. An individual has many rows,
each with a different observation on it
- wide data - many columns, fewer rows. Each individual is a single
row, with many columns of observations
Sometimes, it’s necessary to swap between these types of data so we
can produce the plot that we want. The pivot_data functions
allow us to do this. pivot_longer will convert a wide
dataset into a long one, by reducing the number of columns and
increasing the number of rows, converting columns into new rows, and
pivot_wider does the opposite.
We’ll use the iris dataset to demonstrate. As a
reminder, the iris dataset contains different measurements (petal
length, petal width, sepal length, and sepal width) from multiple
individuals of three different species of iris. If we view the data with
head we can see that the data is in a wide format, where a
row represents a single individual with columns of observations:
head(iris)
We want this dataset to be long, with multiple rows per individual,
and only a single column of measurements. Let’s have a go at using
pivot_longer() to achieve this. The first thing we have to
consider, though, is that iris is a data.frame rather than a tibble. We
can fix that by piping to as_tibble() before we reshape.
We’ll also assign all of this to a new object, that we’ll call
iris2.
iris2 <- iris %>%
as_tibble() %>%
pivot_longer(col = 1:4, names_to = "measure")
Let’s dissect that pivot_longer() function:
- the
col = 1:4 argument tells the function that we want
to convert these 4 columns into individual rows. We don’t include the
fifth column, species, as this is an identifier rather than a
measurement.
- the
names_to = "measure" is simply creating a new
column where we can store the original column headings.
Note that when we assign things, we don’t automatically get them as
an output too - let’s call iris2 and see what it looks
like:
Great. The data is now in a long format, rather than wide. We can
plot it as a boxplot that tells us information about each species and
measurement seperately. Let’s try it with what we currently know of
ggplot:
ggplot(iris2, aes(x = Species, y = value))+
geom_boxplot()

This plot has given us three different boxes on our plot - one per
species. We’ve conflated all of the measurements together - this is
simply because we haven’t told R that we want them separated! We can do
this using a tool known as facet grids, which is essentially a fancy way
of saying “splitting plots to pull out different measurements”. Let’s
try adding a facet_grid() layer to our plot, and including
the argument ~measure within it. Remember that a ~ denotes
a relationship between things, so by calling
facet_grid(~measure) we are asking R to plot the above, but
separating the plots between measurement types. Lets have a go:
ggplot(iris2, aes(x = Species, y = value))+
geom_boxplot()+
facet_grid(~measure)

Great, so now we’ve managed to separate our measurements out into
individual plots, and by doing this we can learn more about the data! We
can see that the setosa species tends to be smaller than the other two
generally, with the exception of it’s sepal width. Hopefully now you can
see how reshaping your data in this way allows you to explore it
differently, and get to know it a little better!
Saving plots
So now we’ve got our data plotted and ready to go, we might want to
save it. Helpfully, there is an “export graph” button on the plot window
that makes this nice and easy. Although there might be a situation where
you’ve used R to automate the production of multiple plots, and you’d
like to include a save function within the code itself. You can do this
fairly simply with the ggsave() function, which basically
does what it says on the tin.
You give the function a name and a file extension in the form of
“my_plot.png” for example, and R will save it into your working
directory. Try the following
ggsave(my_plot.png)
and you should see that R has saved your plot into your project
folder. You can test this by navigating to your file tree in Rstudio and
clicking on the newly saved plot to open it. Helpfully, R will interpret
the .suffix as a file format, so you can change this at will - perhaps
you want a .tiff or a .pdf file - just change the suffix and R will do
this for you.
A note on dimensions - R will automatically export a plot with the
dimensions of the plot window - you can either change that by manually
adjusting these, or by hard-coding some dimensions into the
ggsave() function - have a look at the ?ggsave
help files to find out more!
Customisation
There are loads of ways to customise your R plots, that we don’t have
time to discuss now, but a quick google will show you that there are
endless possibilities - go away and have fun!
And finally…
So, we’ve learned a bit about the philosophies and approaches to
using R, and looked at more advanced ways of handling data with
dplyr. We’ve gained some hands-on experience with using
ggplot2 to produce plots.
LS0tCnRpdGxlOiAiTElGRSA0MTM4OiBSIFdvcmtzaG9wIDIiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCldlbGNvbWUgdG8gdGhlIDJuZCBSIHdvcmtzaG9wIG9mIExJRkU0MTM4IQoKTGFzdCB0aW1lLCB3ZSBsZWFybmVkIGEgYml0IGFib3V0IHRoZSBiYXNpY3MgYW5kIHN0cnVjdHVyZSBvZiB0aGUgUiBsYW5ndWFnZSwgdXNpbmcgYmFzZSBSLiBUaGlzIHRpbWUsIGl0J3MgYSBsaXR0bGUgYml0IGRpZmZlcmVudC4gV2UnbGwgdGhpbmsgYWJvdXQgdGhlIGRpZmZlcmVudCBjb2RpbmcgcGhpbG9zb3BoaWVzIG9mIFIgY29kaW5nICh0aGVyZSBhcmUgbWFueSBtYW55IG1hbnkgd2F5cyB0byBhcHByb2FjaCBSKSwgYW5kIHRvZGF5IEknbGwgZ3VpZGUgeW91IHRocm91Z2ggYSBsaXR0bGUgYml0IG9mIHdoYXQgaXMga25vd24gYXMgdGhlIHRpZHlyIHBoaWxvc29waHkuIFRoaXMgaXMgYW4gYXJndWFibHkgbW9yZSBhZHZhbmNlZCB3YXkgdG8gaGFuZGxlIGFuZCBleHBsb3JlIHlvdXIgZGF0YSwgYW5kIHRoZW4gd2UnbGwgZ2V0IHNvbWUgaGFuZHMgb24gZXhwZXJpZW5jZSBvZiBhIGRpZmZlcmVudCBtZXRob2Qgb2YgdmlzdWFsaXNpbmcgZGF0YSB0aGFuIGxhc3QgdGltZSwgYnkgdXNpbmcgdGhlIGBgYGdncGxvdDJgYGAgcGFja2FnZS4gCgpSaWdodC4gT3VyIG1haW4gYWltIGZvciB0b2RheSBpcyB0byBnaXZlIHlvdSBhIGxpdHRsZSBiaXQgbW9yZSBpbnNpZ2h0IGludG8gaG93IFIgd29ya3MsIGFuZCBob3cgd2UgY2FuIGFwcHJvYWNoIGl0LiBEb24ndCB3b3JyeSBpZiB5b3Ugc3RpbGwgZG9uJ3QgZmVlbCBsaWtlIHlvdSd2ZSBnb3QgdGhlIGJhc2ljcyBhYnNvbHV0ZWx5IG5haWxlZCBkb3duLCB0aGlzIGlzIHNvbWV0aGluZyB0aGF0IHdpbGwgY29tZSBpbiB0aW1lLCB3aXRoIGNvbnRpbnVlZCBwcmFjdGljZS4gUmVtZW1iZXIgeW91IGNhbiBhbHdheXMgbG9vayBiYWNrIGF0IGxhc3Qgc2Vzc2lvbiBpZiB5b3UncmUgc3RydWdnbGluZywgYnV0IG5vdyB5b3UndmUgZ290IGEgZ3JvdW5kaW5nIG9mIHRoZSBiYXNpY3MsIHdlIGNhbiBiZWdpbiB0byBidWlsZCBvbiBpdC4gCgpLZWVwIGluIG1pbmQgdGhlIGxhbmd1YWdlIGFuYWxvZ3kuIElmIHlvdSB3ZXJlIGxlYXJuaW5nIFNwYW5pc2gsIHlvdSdkIGFwcHJlY2lhdGUgdGhhdCB5b3UgaGF2ZSB0byBrZWVwIHByYWN0aWNpbmcuIFlvdSdkIGFsc28gcmVhbGlzZSBwcmV0dHkgcmFwaWRseSB0aGF0IHRoZXJlIGFyZSBvZnRlbiBtdWx0aXBsZSB3YXlzIHRvIGFjaGlldmUgdGhlIHNhbWUgcmVzdWx0IC0gdGhlIHNhbWUgaXMgdHJ1ZSBmb3IgUi4gRm9yIGFueSBvdXRjb21lLCB0aGVyZSBhcmUgbXVsdGlwbGUgd2F5cyB0byBnZXQgdGhlcmUsIGFuZCB0aGUgb25seSB3YXkgdG8gZXN0YWJsaXNoIHlvdXJzZWxmIGFzIGEgcHJvZmljaWVudCBSIChvciBQeXRob24sIG9yIHVuaXgsIG9yIEMrKywgb3IgYW55IG90aGVyIGxhbmd1YWdlKSB1c2VyIGlzIHRvIGdldCBzdHVjayBpbiBhbmQgdHJ5IHRoaW5ncyBvdXQhIAoKIyBSIHBoaWxvc29waGllcwoKVGhlcmUgYXJlIG1hbnkgbWFueSB3YXlzIHRoYXQgd2UgY2FuIGFwcHJvYWNoIG91ciBjb2RpbmcgaW4gUi4gVGhlIG9yaWdpbmFsIHdheSwgYmFzZVIsIGlzIHdoYXQgd2UgY292ZXJlZCBpbiB0aGUgbGFzdCBzZXNzaW9uLiBJdCB3YXMgb3JpZ2luYWxseSBidWlsdCBvbiB2ZWN0b3ItYmFzZWQgZGF0YSwgd2F5IGJhY2sgd2hlbiBSIHdhcyBmaXJzdCBkZXZlbG9wZWQgaW4gdGhlIGVhcmx5IDkwcy4KCkFub3RoZXIgY29tbW9uIGFwcHJvYWNoIHRvIHVzaW5nIFIgaXMgYSBtZXRob2Qga25vd24gYXMgdGlkeVIsIHdoaWNoIHV0aWxpc2VzIGEgc2VsZWN0aW9uIG9mIHBhY2thZ2VzIGNhbGxlZCAqKnRoZSB0aWR5dmVyc2UqKi4gRWFjaCBvZiB0aGUgcGFja2FnZXMgd2l0aGluIHRoZSB0aWR5dmVyc2UgYXJlIGJ1aWx0IHdpdGggdGhlIHNhbWUgdW5kZXJseWluZyBldGhvcywgd2hpY2ggaXMgdGhlIGFiaWxpdHkgdG8gbWFrZSBSIGNvZGUgbW9yZSByZWFkYWJsZSBhbmQgcmVwcm9kdWNpYmxlLiBUaGUgZm9jdXMgb2YgZGF0YSBoYW5kbGluZyBpbiB0aGUgdGlkeXZlcnNlIGlzIHRoZSBgYGBkYXRhLmZyYW1lYGBgIG9iamVjdCBhcyBhbiBlbnRpcmUgZW50aXR5LCByYXRoZXIgdGhhbiB0aGUgdmVjdG9ycyB3aXRoaW4uCgpUaGVyZSBhcmUgc2V2ZXJhbCBvdGhlciBwb3B1bGFyIFIgcGhpbG9zb3BoaWVzIChmb3IgZS5nLiB0aGUgYGBgZGF0YS50YWJsZWBgYCBwaGlsb3NvcGh5KSwgYnV0IHdlIHdvbnQgZGVsdmUgaW50byB0aG9zZSBoZXJlLCB3ZSdsbCBzdGljayB0byBiYXNlUiBhbmQgdGhlIHRpZHl2ZXJzZS4KCkl0J3Mgd29ydGgga25vd2luZyB0aGF0IHlvdSBtYXkgd2VsbCBjb21lIGFjcm9zcyBzb21lIHJhdGhlciBzdHJvbmcgb3BpbmlvbnMgYWJvdXQgdGhlc2UgdHdvIGNvZGluZyBtZXRob2RzLCBwYXJ0aWN1bGFybHkgb24gdHdpdHRlci4gV2l0aCBzb21lIHF1aWNrIHNlYXJjaGluZyBvZiB0aGUgdGVybSAidGlkeXZlcnNlIiwgeW91IGNhbiBxdWl0ZSBxdWlja2x5IGZpbmQgc29tZSB2ZXJ5IGhlYXRlZCBkZWJhdGVzISBJbiB0aGUgaW50ZXJlc3Qgb2YgYmFsYW5jZSwgSSdsbCBzdWdnZXN0IHRoYXQgdGhlcmUgYXJlIGFkdmFudGFnZXMgYW5kIGRpc2FkdmFudGFnZXMgdG8gYm90aCBhcHByb2FjaGVzLCBhbmQgdGhlaXIgYXBwbGljYWJpbGl0eSBvciBzdWl0YWJpbGl0eSB2YXJpZXMgbWFzc2l2ZWx5IHdpdGggdGhlIGNvbnRleHQgb2Ygd2hhdCBpdCBpcyB0aGF0IHlvdSdyZSB0cnlpbmcgdG8gYWNoaWV2ZS4gCgpJbiBteSBvcGluaW9uLCBpdCdzIGJldHRlciB0byBiZSBiaWxpbmd1YWwuIFVzZSB3aGF0IHdvcmtzIGZvciB5b3UsIHdoZW4gaXQgd29ya3MgZm9yIHlvdS4gSSB0ZW5kIHRvIHVzZSBhIGJpdCBvZiBhIG1pc2htYXNoIG9mIGJvdGggYXBwcm9hY2hlcywgYnV0IHRoZW4gSSdtIG5vdCBvdmVybHkgb3BpbmlvbmF0ZWQgb24gdGhlIHN1YmplY3QuIERvIHdoYXQgd29ya3MuIFRpZHl2ZXJzZSBjYW4gaGVscCB0byBtYWtlIHRoaW5ncyBhIGxpdHRsZSBjbGVhcmVyLCBidXQgaW4gc29tZSBjYXNlcyBpdCdzIG92ZXJraWxsLCBhbmQgYmFzZVIgaXMgYWN0dWFsbHkgc2ltcGxlciB0byB1c2UuCgojIyBXaGF0IGlzIHRoZSB0aWR5dmVyc2U/CgpUaGUgdGlkeXZlcnNlIGlzIGEgZGl2ZXJzZSBzZXQgb2YgcGFja2FnZXMgYW5kIHRvb2xzLCB3aGljaCBpbmNsdWRlIHBvcHVsYXIgcGFja2FnZXMgc3VjaCBhcyBgYGBkcGx5cmBgYCwgYGBgZ2dwbG90MmBgYCwgYGBgcmVhZHJgYGAsIGFuZCBgYGBwdXJycmBgYC4gU2V2ZXJhbCBvZiB0aGVzZSBwYWNrYWdlcyB5b3UgbWlnaHQgdXNlIHdpdGhvdXQgZXZlciBleHBsaWNpdGx5IGNhbGxpbmcgdGhlbSwgYmVjYXVzZSBvZiB0aGUgbmF0dXJlIG9mIHRoZSB3YXkgdGhhdCB0aGUgdGlkeXZlcnNlIGlzIGluc3RhbGxlZC4gVGhlIG1haW4gb25lcyB0aGF0IHdlJ2xsIGZvY3VzIG9uIGhlcmUgYXJlIGBgYGRwbHlyYGBgIGFuZCBgYGBnZ3Bsb3QyYGBgLiBnZ3Bsb3QyLCBhcyB0aGUgbmFtZSBtaWdodCBzdWdnZXN0LCBpcyBhIHBhY2thZ2UgZXhwbGljaXRseSBkZXNpZ25lZCB0byByZXRoaW5rIHRoZSB3YXkgdGhhdCBSIGhhbmRsZXMgcGxvdHRpbmcgYW5kIGRhdGEgdmlzdWFsaXNhdGlvbi4gV2UnbGwgdGFsayBtb3JlIGFib3V0IHRoYXQgbGF0ZXIgdGhvdWdoLgoKCiMgZHBseXIKCmRwbHlyIGlzIGEgcmVhbGx5IHVzZWZ1bCBwYWNrYWdlIGZvciBkYXRhIHdyYW5nbGluZyBhbmQgbWFuaXB1bGF0aW9uLiBJdCBpcyBpbnZhbHVhYmxlIHdoZW4geW91IGFyZSB0cnlpbmcgdG8gZ2V0IHlvdXIgZGF0YSBpbnRvIGEgdXNlYWJsZSBmb3JtYXQsIG9yIGdldCBhIHF1aWNrIHN1bW1hcnkgdG8gaGVscCB5b3UgdW5kZXJzdGFuZCB5b3VyIGRhdGEgYSBsaXR0bGUgYmV0dGVyLiBJdCBpcyBwYXJ0aWN1bGFybHkgdXNlZnVsIGZvciBmaWx0ZXJpbmcgeW91ciBkYXRhc2V0LiBkcGx5ciBhbGxvd3MgeW91IHRvIGV4dHJhY3QgaW5mb3JtYXRpb24gdG8gZ2V0IHlvdXIgZGF0YSBpbnRvIHNoYXBlIGZvciBkb3duc3RyZWFtIGFuYWx5c2lzLgoKVGhlIHByaW5jaXBsZSBvZiBkYXRhIHdyYW5nbGluZyBzb3VuZHMgdGVkaW91cywgYnV0IGl0IGlzIGEgY3J1Y2lhbGx5IGltcG9ydGFudCBwYXJ0IG9mIGJpb2luZm9ybWF0aWNzIGFuZCBkYXRhIHNjaWVuY2UuIGRwbHlyIGlzIGV4cGxpY2l0bHkgZGVzaWduZWQgdG8gaGFuZGxlIGRhdGEgd3JhbmdsaW5nIGluIFIsIGFuZCB1c2VzIGEgdmFyaWV0eSBvZiB0b29scyBhbmQgZnVuY3Rpb25zIHRvIG1ha2UgdGhpcyBlYXN5IGFuZCBhY2Nlc3NpYmxlLiBBcyBhbiBhbmFsb2d5LCBpZiBsaWtlIG1lLCB5b3VyIGRlc2sgaXMgbWVzc3kgYW5kIGNoYW90aWMsIEkgb2Z0ZW4gZmluZCB0aGF0IHRpZHlpbmcgaXQgdXAgaXMgYSBncmVhdCB3YXkgdG8gaGVscCBtZSB0byBmb2N1cyBteSBtaW5kIG9uIHdoYXQgaXQgaXMgSSdtIG1lYW50IHRvIGJlIGdldHRpbmcgb24gd2l0aCwgcmF0aGVyIHRoYW4ganVzdCBzdGFyaW5nIGF0IHRoZSBtZXNzIGFuZCBwbGF5aW5nIHdpdGggdGhlIHJhbmRvbSBiaXQgb2YgYmx1ZXRhYyBJJ3ZlIGZvdW5kLiBUaGUgc2FtZSBwcmluY2lwbGUgY2FuIGJlIGFwcGxpZWQgdG8geW91ciBkYXRhLiBJZiB5b3UgaGF2ZSBhIG1lc3N5IGRhdGFzZXQgd2l0aCBsb2FkcyBvZiB2YXJpYWJlcyBhbmQgbm9uc2Vuc2UgaW4sIGl0IGNhbiBiZWNvbWUgZGlmZmljdWx0IHRvIGZvY3VzLiBGaWx0ZXJpbmcgb3V0IHRoZSBzdHVmZiB5b3UgZG9uJ3QgbmVlZCBhbmQgdGlkeWluZyBpdCB1cCBpcyBhIHZpdGFsIGZpcnN0IHN0ZXAgaW4gYW55IGFuYWx5c2lzLgoKVG8gZ2V0IHRvIGdyaXBzIHdpdGggdGhpcywgd2UncmUgZ29pbmcgdG8gdXNlIGEgcmVhbGx5IHBvcHVsYXIgZGF0YXNldCB0aGF0J3MgaW50ZWdyYXRlZCBpbnRvIGRwbHlyIC0gdGhlIGBgYHN0YXJ3YXJzYGBgIGRhdGFzZXQuIFRoZSBsaWtlbGlob29kIG9mIHlvdSBiZWluZyBhIHN0YXJ3YXJzIHN1cGVyZmFuIHdpdGggYW4gZW5jeWNsb3BhZWRpYyBrbm93bGVkZ2Ugb2YgdGhlIGhlaWdodHMgYW5kIHdlaWdodHMgb2YgY2hhcmFjdGVycyBmcm9tIHdpdGhpbiB0aGUgc3RhcndhcnMgdW5pdmVyc2UgaXMgbG93LCBzbyBpdCBwcm92aWRlcyBhbiBleGNlbGxlbnQgZXhhbXBsZSBvZiBob3csIGJ5IHVzaW5nIGRwbHlyLCB5b3UgY2FuIGdldCB0byBrbm93IGFuZCB1bmRlcnN0YW5kIGEgZGF0YXNldC4KCgpMZXQncyBnZXQgY3JhY2tpbmcgdGhlbi4KCkZpcnN0IHRoaW5ncyBmaXJzdCwgd2UgbmVlZCB0byBpbnN0YWxsIGFuZCBsb2FkIHRoZSBwYWNrYWdlcyB3ZSBuZWVkLiBUaGVyZSBhcmUgc2V2ZXJhbCB3YXlzIG9mIGRvaW5nIHRoaXMsIHlvdSBjYW4gZWl0aGVyIGluc3RhbGwgYW5kIGxvYWQgdGhlIGVudGlyZSBjb2xsZWN0aW9uIG9mIHRpZHl2ZXJzZSBwYWNrYWdlcywgb3Igd2UgY2FuIGp1c3QgaW5zdGFsbCB0aGUgb25lcyB0aGF0IHdlJ2xsIG5lZWQgaGVyZToKCmBgYHtyfQppbnN0YWxsLnBhY2thZ2VzKCJ0aWR5dmVyc2UiKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKCiMgb3IKCmluc3RhbGwucGFja2FnZXMoImRwbHlyIikKaW5zdGFsbC5wYWNrYWdlcygiZ2dwbG90MiIpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZ2dwbG90MikKYGBgCk5vdywgd2UgY2FuIGxvYWQgdGhlIHN0YXJ3YXJzIGRhdGFzZXQgaW50byBvdXIgUiBzZXNzaW9uOgoKYGBge3J9CmRhdGEoc3RhcndhcnMpCmBgYAoKWW91IG1pZ2h0IG5vdGljZSB0aGF0IHRoZSBzdGFyd2FycyBkYXRhIGRpc3BsYXlzIGFzIGEgYGBgdGliYmxlYGBgIHJhdGhlciB0aGFuIHRoZSB0eXBpY2FsIGBgYGRhdGEuZnJhbWVgYGAuIEEgYGBgdGliYmxlYGBgIGlzIHZlcnkgc2ltaWxhciB0byBhIGBgYGRhdGEuZnJhbWVgYGAsIGJ1dCB3aXRoIHNvbWUgYm9udXMgZmVhdHVyZXMuIFRoZXNlIGFyZSBub3QgZ2VuZXJhbGx5IGltbWVkaWF0ZWx5IGFwcGFyZW50IChvciBwYXJ0aWN1bGFybHkgaW1wb3J0YW50IGluIHRoaXMgY29udGV4dCkuIEEgYGBgdGliYmxlYGBgIGlzIGVzc2VudGlhbGx5IGFuIHVwZGF0ZWQgYGBgZGF0YS5mcmFtZWBgYCwgYW5kIGlzIGEgdmVyeSBuZWF0IHRpZHl2ZXJzZSBhZGQtb24uIEF0IGZpcnN0IGdsYW5jZSwgaXQncyBwZXJoYXBzIG9idmlvdXMgdGhhdCB0aGUgZGlzcGxheSBpcyBhIGxpdHRsZSBuaWNlciB0aGFuIHdlJ3JlIHVzZWQgdG8uIFRocmVlIG1haW4gZGlmZmVyZW5jZXMgdGhhdCB5b3UgbWF5IG5vdGljZToKCiogU2hvd3Mgb25seSB0aGUgZmlyc3QgMTAgbGluZXMgLSBgYGBkYXRhLmZyYW1lYGBgIHByaW50cyB0aGUgZW50aXJlIGNvbnRlbnRzIC0gdGhpcyBlc3NlbnRpYWxseSBjYWxscyBgYGBoZWFkKClgYGAgb24gdGhlIGRhdGEuCiogQWxzbyBvbmx5IGRpc3BsYXlzIHRoZSBmaXJzdCBmZXcgY29sdW1ucyAtIHRoZSByZXN0IG9mIHRoZSBpbmZvcm1hdGlvbiBzdWNoIGFzIHRoZSBjb2x1bW5zIG5vdCBzaG93biBpcyBsaXN0ZWQgYmVsb3cgdGhlIHRpYmJsZSBvdXRwdXQuCiogVGhlcmUgaXMgaW5mb3JtYXRpb24gb24gaG93IHRoaW5ncyBhcmUgY29kZWQuIEhlcmUgd2UgY2FuIHNlZSB0aGF0IHRoZSBuYW1lIGlzIGNvZGVkIGFzIGEgY2hhcmFjdGVyIGlucHV0ICh3aGljaCB3ZSBtaWdodCBleHBlY3QpLiBIZWlnaHQgaXMgYW4gaW50ZWdlciwgd2hpY2ggaXMganVzdCBhIHdob2xlIG51bWJlciB3aXRoIG5vIGRlY2ltYWwgcGxhY2VzIChvciwgYSBkaXNjcmV0ZSBudW1lcmljKS4gTWFzcyBpcyB3aGF0IGlzIGtub3duIGluIFIgYXMgYSBkb3VibGUsIG9yIGBgYGRibGBgYCAtIHRoaXMgZXNzZW50aWFsbHkgbWVhbnMgaXQncyBhIGZsb2F0aW5nIHBvaW50IG51bWJlciB3aXRoIGFueSBwb3RlbnRpYWwgdmFsdWUgZnJvbSAtSW5mIHRvIEluZi4gCgpXZSBjYW4gdXNlIHRpYmJsZXMgaW4gdGhlIHNhbWUgd2F5IHRoYXQgd2UgbWlnaHQgdXNlIGEgYGBgZGF0YS5mcmFtZWBgYCAtIGZvciBlLmcuOgpgYGB7cn0Kc3RhcndhcnMkbmFtZQpgYGAKZGlzcGxheXMgdGhlIG5hbWVzIG9mIGFsbCBvZiB0aGUgY2hhcmFjdGVycyBpbiB0aGUgYGBgdGliYmxlYGBgLCBqdXN0IGFzIGl0IHdvdWxkIGluIGEgYGBgZGF0YS5mcmFtZWBgYCBmb3JtYXQuIAoKIyBUaGUgcGlwZSBvcGVyYXRvciBgYGAlPiVgYGAKCkJlZm9yZSB3ZSBnbyBhbnkgZnVydGhlciwgaXQncyBpbXBvcnRhbnQgdG8gaW50cm9kdWNlIHRoZSBwaXBlIG9wZXJhdG9yIHRvIHlvdS4gVGhlIHBpcGUgb3BlcmF0b3IgaXMgYSByZWFsbHkgdXNlZnVsIGJpdCBvZiBraXQgZm9yIGNvZGluZyBpbiBSLCBhbmQgaXQgY29tZXMgZnJvbSB0aGUgcGFja2FnZSBgYGBtYWdyaXR0cmBgYCAoYWx0aG91Z2ggdGhlIGBgYG1hZ3JpdHRyYGBgIGxpYnJhcnkgaXMgYXV0b21hdGljYWxseSBsb2FkZWQgYWxvbmdzaWRlIGBgYGRwbHlyYGBgIHNvIGRvbid0IHdvcnJ5IGFib3V0IGluc3RhbGxpbmcgaXQhKS4gVGhlIHJlYXNvbiB0aGUgcGlwZS1jb250YWluaW5nIHBhY2thZ2UgaXMgY2FsbGVkIGBgYG1hZ3JpdHRyYGBgIGlzIGJlY2F1c2Ugb2YgYSBmYW1vdXMgQmVsZ2lhbiBzdXJyZWFsaXN0IGFydGlzdCwgd2hvIHBhaW50ZWQgdGhlIGZhbW91cyAiVGhlIFRyZWFjaGVyeSBvZiBJbWFnZXMiLCBzZWVuIGJlbG93OgoKIVtdKHBpcGUuanBlZykKClRoZSB0ZXh0LCAqQ2VjaSBuJ2VzdCBwYXMgdW5lIHBpcGUqIGlzIEZyZW5jaCBmb3IgInRoaXMgaXMgbm90IGEgcGlwZSIuCgpUaGUgcGlwZSBmdW5jdGlvbiwgY29kZWQgYXMgYGBgJT4lYGBgIGFsbG93cyB5b3UgdG8gInBpcGUiIGRhdGEgZnJvbSBvbmUgY29tbWFuZCBvciBmdW5jdGlvbiwgZGlyZWN0bHkgdG8gYW5vdGhlci4gSXQgd29ya3MgaW4gYSB2ZXJ5IHNpbWlsYXIgd2F5IHRvIHVuaXggcGlwZXMsIGFuZCBhbGxvd3MgeW91IHRvIGNoYWluIHRvZ2V0aGVyIGZ1bmN0aW9ucyBpbiBhIHNpbmdsZSBjb2RlIGJsb2NrLCBhbGxvd2luZyBmb3IgbW9yZSByZWFkYWJsZSBjb2RlLiBZb3UgcmFyZWx5LCBpZiBldmVyLCAqKmhhdmUqKiB0byB1c2UgcGlwZSBvcGVyYXRvcnMgaW4geW91ciBjb2RlLCBidXQgd2UnbGwgdXNlIHRoZW0gbG90cyBoZXJlIHRvIGRlbW9uc3RyYXRlIHRoZWlyIHVzZWZ1bG5lc3MuIEkgZmluZCBwaXBlcyBtYWtlIGZvciBlYXNpZXIgY29kaW5nLCBhcyB5b3UgY2FuIGJyZWFrIGRvd24gY29tcGxleCBjb21tYW5kcyBpbnRvIHRoZWlyIGNvbnNpdHVlbnQgcGFydHMsIHJhdGhlciB0aGFuIHdyZXN0bGluZyB3aXRoIG5lc3RlZCBmdW5jdGlvbnMgd2l0aCBhIG1pbGxpb24gYnJhY2tldHMuIFBpcGluZyBoZWxwcyB5b3UgdG8gdGFrZSBhIHNpbXBsZSBjb21tYW5kLCBhbmQgYnVpbGQgdXAgdGhlIGNvbXBsZXhpdHkgb2YgaXQgc2xvd2x5IGFuZCBsb2dpY2FsbHksIGl0ZXJhdGl2ZWx5IGFkZGluZyBiaXRzIGFuZCBzZW5zZS1jaGVja2luZyBhcyB5b3UgZ28sIGJlZm9yZSB5b3UgZW5kIHVwIHdpdGggYSBjb21wbGV4IGJ1dCByZWFkYWJsZSBhbmQgZWFzaWx5IHJlcHJvZHVjaWJsZSBiaXQgb2YgY29kZS4KCkxldCdzIGRlbW9uc3RyYXRlIHRoZSB1c2VmdWxuZXNzIG9mIGEgcGlwZSBhbG9uZSwgYmVmb3JlIHdlIGNvbWJpbmUgaXQgd2l0aCBgYGBkcGx5cmBgYC4gU2F5IHdlIHdhbnRlZCB0byB3b3JrIG91dCB0aGUgbGVuZ3RoIG9mIHRoZSBgYGBuYW1lYGBgIGNvbHVtbiBpbiB0aGUgYGBgc3RhcndhcnNgYGAgZGF0YXNldC4KCldlJ2xsIGZpcnN0IGRlbW9uc3RyYXRlIHdpdGhvdXQgdGhlIHBpcGUgb3BlcmF0b3IsIGFuZCB0aGVuIHdpdGggaXQuCgpgYGB7cn0KbGVuZ3RoKHN0YXJ3YXJzJG5hbWUpCgpzdGFyd2FycyRuYW1lICU+JQogIGxlbmd0aCgpCmBgYAoKVGhlc2UgdHdvIGJpdHMgb2YgY29kZSBnaXZlIHVzIHRoZSBzYW1lIHJlc3VsdCAoODchKSAtIGhlcmUsIHdoZXJlIHRoZSBjb2RlIGlzIHJlbGF0aXZlbHkgc3RyYWlnaHRmb3J3YXJkIGFuZCBmb2N1c3NpbmcgYXJvdW5kIG9ubHkgYSBzaW5nbGUgZnVuY3Rpb24sIGl0IGlzIHBlcmhhcHMgZWFzaWVyIHRvIHVzZSB0aGUgYmFzZVIgdmVyc2lvbi4gV2hlbiB3ZSBnZXQgdG8gbW9yZSBjb21wbGljYXRlZCBzdHVmZiwgdGhlIHVzZWZ1bG5lc3Mgb2YgcGlwZXMgd2lsbCBiZSBtdWNoIG1vcmUgYXBwYXJlbnQuIEVzc2VudGlhbGx5IHdoYXQgdGhlIHNlY29uZCBiaXQgb2YgY29kZSBpcyBzYXlpbmcgaXMgdGFrZSB0aGUgbmFtZSBjb2x1bW4gZnJvbSB3aXRoaW4gdGhlIGBgYHN0YXJ3YXJzYGBgIGRhdGFzZXQsIGFuZCBwb3AgaXQgaW5zaWRlIHRoZSBsZW5ndGggZnVuY3Rpb24uCgojIFBpcGluZyBhbmQgZHBseXIKCiMjIFRoZSBgYGBzZWxlY3QoKWBgYCBmdW5jdGlvbgoKUGlwaW5nIGlzIGdyZWF0IGZvciBkYXRhIG1hbmlwdWxhdGlvbiwgcGFydGljdWxhcmx5IHdoZW4gY29tYmluZWQgd2l0aCB0aGUgdG9vbHMgaW4gYGBgZHBseXJgYGAuIFNheSB5b3Ugd2FudCB0byBzZWxlY3QgYSBjb2x1bW4gZnJvbSBhIGRhdGFzZXQuIFdlIGNhbiBvZiBjb3Vyc2UgZG8gdGhpcyB1c2luZyBvdXIgcHJldmlvdXMgbWV0aG9kIG9mIHRoZSBgYGAkYGBgIG9wZXJhdG9yLCBvciwgd2UgY2FuIHVzZSB0aGUgYGBgc2VsZWN0KClgYGAgZnVuY3Rpb24gZnJvbSBgYGBgZHBseXJgYGAuCgpgYGB7cn0Kc3RhcndhcnMkbmFtZQoKc3RhcndhcnMgJT4lCiAgc2VsZWN0KG5hbWUpCmBgYApIZXJlLCB0aGUgYGBgc2VsZWN0KClgYGAgZnVuY3Rpb24gcGVyaGFwcyBtYWtlcyBpdCBtb3JlIG9idmlvdXMgd2hhdCB0aGUgY29kZSBtZWFucywgcGFydGljdWxhcmx5IGZvciB0aG9zZSBvZiB5b3Ugbm90IHVzZWQgdG8gcmVhZGluZyBSLiBZb3UgYWxzbyBlbmQgdXAgd2l0aCBzbGlnaHRseSBkaWZmZXJlbnQgb3V0cHV0cywgaW4gdGhhdCB0aGUgdGlkeXZlcnNlIHNvbHV0aW9uIGdpdmVzIHlvdSBhIHRpYmJsZSBvdXRwdXQuIAoKQnV0LCB3aGF0IGlmIHdlIHdhbnQgdG8gc2VsZWN0IG11bHRpcGxlIGNvbHVtbnMgaW4gb25lIGdvPyBJbiBiYXNlUiwgd2Ugd291bGQgaGF2ZSB0byB1c2Ugb3VyIHZlY3Rvci1iYXNlZCBpbmRleGluZyBzdHJhdGVnaWVzICh0aGUgc3F1YXJlIGJyYWNrZXRzISksIHdpdGggdGhlIGBgYGMoKWBgYCBmdW5jdGlvbi4gSXQncyBtdWNoIHNpbXBsaWVyIGluIHRoZSB0aWR5UiBzb2x1dGlvbjoKCmBgYHtyfQojIFRoZSBiYXNlUiBzb2x1dGlvbjoKc3RhcndhcnNbICxjKCJuYW1lIiwiaG9tZXdvcmxkIildCgojIFRpZHl2ZXJzZToKc3RhcndhcnMgJT4lCiAgc2VsZWN0KG5hbWUsIGhvbWV3b3JsZCkKYGBgCipOb3RlIHRoYXQgd2UgZG8gbm90IHVzZSB0aGUgIiIgaW4gdGhlIGBgYHNlbGVjdCgpYGBgIGZ1bmN0aW9uLCBiZWNhdXNlIHdlJ3ZlIGFscmVhZHkgdG9sZCBSIHRoYXQgd2UgYXJlIGxvb2tpbmcgaW5zaWRlIHRoZSBzdGFyd2FycyBkYXRhc2V0LCBieSBwaXBpbmcgaXQgdG8gdGhlIGZ1bmN0aW9uLiBJbiB0aGUgYmFzZVIgc29sdXRpb24sIHdlIGhhdmUgdG8gdXNlIHRoZW0gb3RoZXJ3aXNlIFIgd2lsbCBsb29rIGZvciBvYmplY3RzIGZpcnN0LioKClRoZSBgYGBzZWxlY3QoKWBgYCBmdW5jdGlvbiBpcyBhIHJlYWxseSBxdWljayBhbmQgc3VwZXIgcG93ZXJmdWwgd2F5IG9mIHN1YnNldHRpbmcgZGF0YS4gVGhlcmUgYXJlIGFsc28gc2V2ZXJhbCBoZWxwZXIgYXJndW1lbnRzIHRoYXQgeW91IGNhbiB1c2UgaW5zaWRlIG9mIGBgYHNlbGVjdCgpYGBgIGluIG9yZGVyIHRvIGN1c3RvbWlzZSBob3cgeW91IHdhbnQgdG8gZmlsdGVyLiBXZSB3aWxsIGhhdmUgYSBsb29rIGF0IHR3byBvZiB0aGVtIGJlbG93LCBidXQgeW91IGNhbiBoYXZlIGEgbG9vayBhdCB0aGUgcmVzdCBieSB1c2luZyB0aGUgaGVscCBmdW5jdGlvbiBvbiB0aGUgc2VsZWN0IGNvbW1hbmQgYGBgP3NlbGVjdGBgYC4KCkZpcnN0LCB3ZSBjYW4gdXNlIHRoZSBoZWxwZXIgZnVuY3Rpb24gYGBgY29udGFpbnMoKWBgYCB0byBzZWxlY3Qgb25seSB0aGUgY29sdW1ucyB0aGF0IGNvbnRhaW4gYSBjZXJ0YWluIGNoYXJhY3Rlci4gTGV0J3MgdHJ5IGFuZCB1c2UgdGhlIHRpZHl2ZXJzZSB0byBzZWxlY3Qgb25seSBjb2x1bW5zIHdoaWNoIGhhdmUgYW4gdW5kZXJzY29yZSAoIl8iKSBpbjoKCmBgYHtyfQpzdGFyd2FycyAlPiUKICBzZWxlY3QoY29udGFpbnMoIl8iKSkKYGBgCk5vdGljZSB0aGF0IHRoaXMgdGltZSwgd2UgdXNlZCBxdW90YXRpb24gbWFya3MgYXMgd2UgYXJlIGFza2luZyBSIHRvIHBhdHRlcm4gbWF0Y2ggYSBiaXQgb2YgYSBzdHJpbmcuIFdlIGVuZCB1cCB3aXRoIHRoZSBhYm92ZSB0aWJibGUgLSB0aGUgY29sdW1ucyBhbGwgY29udGFpbiBhbiB1bmRlcnNjb3JlIGluIHRoZWlyIG5hbWVzIQoKV2UgY2FuIGFsc28gdXNlIHRoZSBgYGBzdGFydHNfd2l0aCgpYGBgIGhlbHBlciBmdW5jdGlvbi4gVGhpcyB0aW1lLCB3ZSdsbCBzZWxlY3QgYWxsIHRoZSBjb2x1bW5zIHdob3MgbmFtZSBzdGFydCB3aXRoIGEgbG93ZXItY2FzZSBzOgoKYGBge3J9CnN0YXJ3YXJzICU+JQogIHNlbGVjdChzdGFydHNfd2l0aCgicyIpKQpgYGAKCkhlcmUsIHdlIGVuZCB1cCB3aXRoIGNvbHVtbnMgInNraW5fY29sb3VyIiwgInNleCIsICJzcGVjaWVzIiwgYW5kICJzdGFyc2hpcHMiIC0gYWxsIG9mIHdoaWNoIHN0YXJ0IHdpdGggYSBsb3dlcmNhc2UgcyAtIHNvIG91ciBjb2RlIHdvcmtzIQoKVGhlIGBgYHNlbGVjdCgpYGBgIGZ1bmN0aW9uIGlzIHZlcnNhdGlsZSAtIHdlIGNhbiBhbHNvIHVzZSBpdCB0byBzZWxlY3QgYWxsIGNvbHVtbnMgKmV4Y2VwdCogbmFtZSBhbmQgaG9tZXdvcmxkLCBieSBlZGl0aW5nIHRoZSBjb2RlIHdlIHVzZWQgZWFybGllciAtIHJlY2FsbCB3ZSB1c2VkIGBgYHN0YXJ3YXJzICU+JSBzZWxlY3QobmFtZSwgaG9tZXdvcmxkKWBgYCAtIHdlIGNhbiBqdXN0IGFkZCAtIHN5bWJvbHMgaW4gZnJvbnQgb2YgdGhlIGNvbHVtbiBuYW1lcyB3ZSB3YW50IHRvIHJlbW92ZS4uLgoKYGBge3J9CnN0YXJ3YXJzICU+JQogIHNlbGVjdCgtbmFtZSwtaG9tZXdvcmxkKQpgYGAKV2UgY2FuIHNjcm9sbCB0aHJvdWdoIHRoZSByZXN1bHRpbmcgdGliYmxlIGFuZCBzZWUgdGhhdCBhbGwgY29sdW1ucyBleGNlcHQgbmFtZSBhbmQgaG9tZXdvcmxkIGFyZSBwcmVzZW50IQoKCiMjIFRoZSBgYGBmaWx0ZXIoKWBgYCBmdW5jdGlvbgoKT2theSwgbm93IHdlJ3ZlIGxlYXJuZWQgaG93IHRvIHNlbGVjdCBjb2x1bW5zIC0gaG93IGRvIHdlIGZpbHRlciBvdXQgcm93cz8gVGhlIGxhbmd1YWdlIGRpZmZlcnMgc2xpZ2h0bHkgKGFuZCBzbyBkbyB0aGUgZnVuY3Rpb25zISB3aGVuIHdlJ3JlIGRpc2N1c3NpbmcgaGFuZGxpbmcgcm93cyBhbmQgY29sdW1uczoKCioqV2UgYWx3YXlzIHNlbGVjdCBjb2x1bW5zLCBhbmQgZmlsdGVyIHJvd3MqKgoKSW4gYmFzZVIsIHdlIHVzZSBpbmRleGVzIHRvIHJlbW92ZSB0aGluZ3MuIGBgYGRwbHlyYGBgIGZ1bmN0aW9ucyBpbiBhIHNpbWlsYXIgd2F5LCBidXQgaXMgb3B0aW1pc2VkIGZvciByZWFkYWJpbGl0eS4gSXQgc3RpbGwgaW5oZXJlbnRseSBmdW5jdGlvbnMgb24gdGhlIGxvZ2ljYWwgYGBgYFRSVUUvRkFMU0VgYGAgb3BlcmF0b3JzLCBidXQgaW4gYSBzbGlnaHRseSBkaWZmZXJlbnQgd2F5LiBMZXQncyBoYXZlIGEgbG9vayBhdCBhbiBleGFtcGxlIHRvIGJldHRlciBleHBsYWluIHdoYXQgSSdtIHRhbGtpbmcgYWJvdXQuIElmIHdlIHdhbnRlZCB0byBzZWxlY3QgYWxsIG9mIHRoZSBodW1hbnMgaW4gb3VyIGRhdGFzZXQsIGluIGJhc2VSLCB3ZSdkIGZpcnN0IGhhdmUgdG8gcmV0dXJuIGEgc2VyaWVzIG9mIGxvZ2ljYWwgb3BlcmF0b3JzLCBhbmQgdGhlbiB3b3JrIG91dCB3aGVyZSB0byBwdXQgdGhlbSBpbiBvdXIgaW5kZXhpbmcgc3lzdGVtLiBJbiB0aWR5Uiwgd2Ugc2ltcGx5IHBpcGUgdG8gdGhlIGBgYGZpbHRlcigpYGBgIGZ1bmN0aW9uOgpgYGB7cn0KIyBCYXNlUiBzb2x1dGlvbjoKc3RhcndhcnMkc3BlY2llcyA9PSAiSHVtYW4iICMgVGhpcyBpcyB0aGUgbG9naWNhbCBzdGF0ZW1lbnQgcHJvZHVjaW5nIGJpdCBvZiBjb2RlLCB0aGF0IG5lZWRzIHRvIGdvIGluIHRoZSBbXSBpbmRleCBzeXN0ZW0gc29tZXdoZXJlLi4uCnN0YXJ3YXJzW3N0YXJ3YXJzJHNwZWNpZXMgPT0gIkh1bWFuIiwgXSAjIERvbid0IGZvcmdldCB0aGUgY29tbWEgdG8gdGVsbCBSIHdlIGFyZSBvbmx5IGxvb2tpbmcgaW4gcm93cyEKCiMgVGlkeXZlcnNlIHNvbHV0aW9uOgpzdGFyd2FycyAlPiUKICBmaWx0ZXIoc3BlY2llcyA9PSAiSHVtYW4iKQpgYGAKVGhlIHBhcnRpY3VsYXJseSBkaXNjZXJuaW5nIHdpbGwgaGF2ZSBub3RpY2VkIHRoYXQgdGhlc2Ugc29sdXRpb25zIHByb3ZpZGUgdXMgd2l0aCB0d28gc2xpZ2h0bHkgZGlmZmVyZW50IG91dGNvbWVzIC0gdGhlIGZpcnN0IGdpdmVzIHVzIGEgdGliYmxlIHdpdGggZGltZW5zaW9ucyAzOXgxNCwgYW5kIHRoZSB0aWR5dmVyc2Ugc29sdXRpb24gZ2l2ZXMgdXMgYSB0aWJibGUgd2hpY2ggaXMgb25seSAzNXgxNC4gVGhpcyBkaWZmZXJlbmNlIGlzIHRvIGRvIHdpdGggdGhlIHdheSB0aGUgYGBgc2VsZWN0KClgYGAgZnVuY3Rpb24gaGFuZGxlcyBgYGBOQWBgYCB2YWx1ZXMgLSBpdCBhdXRvbWF0aWNhbGx5IHJlbW92ZXMgdGhlbSwgd2hlcmVhcyB0aGUgYmFzZVIgc29sdXRpb24gcmV0YWlucyB0aGVtIGluIHRoZSBvdXRwdXQuIEluIG9yZGVyIHRvIGdldCByaWQgb2YgdGhlbSwgd2UgbmVlZCB0byBhZGQgYW5vdGhlciBmdW5jdGlvbiB0byBvdXIgYmFzZSBzb2x1dGlvbiAtIHRoZSBgYGB3aGljaCgpYGBgIGZ1bmN0aW9uLiBCeSB3cmFwcGluZyBvdXIgZmlsdGVyaW5nIHByb2Nlc3MgaW4gYGBgd2hpY2goKWBgYCwgd2UgYXJlIHRlbGxpbmcgUiB0byByZW1vdmUgYW55IGNoYXJhY3RlcnMgZm9yIHdoaWNoIHRoZSBzcGVjaWVzIGlzIGEgYGBgTkFgYGAgdmFsdWU6CgpgYGB7cn0Kc3RhcndhcnNbd2hpY2goc3RhcndhcnMkc3BlY2llcyA9PSAiSHVtYW4iKSwgXQpgYGAKVGhpcyBpcyB3aGVyZSB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIGJhc2UgYW5kIHRpZHlSIHJlYWxseSBiZWNvbWVzIGFwcGFyZW50IC0gYXMgYW4gUiBub3ZpY2UsIHRoZSBiYXNlIHNvbHV0aW9uIGlzIGRpZmZpY3VsdCB0byBpbnRlcnByZXQgLSBpdCdzIGNlcnRhaW5seSBub3QgaW1tZWRpYXRlbHkgb2J2aW91cyB3aGF0IGlzIGdvaW5nIG9uIQoKUmlnaHQgdGhlbiAtIHdlJ3ZlIGxlYXJuZWQgaG93IHRvIGZpbHRlciBhIGRhdGFzZXQgdG8gc2hvdyB1cyBvbmx5IHRoZSByZXN1bHRzIHdoaWNoIGNvbnRhaW4gYSBzdHJpbmcgdmFsdWUgaW4gYSBzaW5nbGUgY29sdW1uIC0gd2hhdCBpZiB3ZSB3YW50IHRvIGZpbHRlciBmb3IgbW9yZSB0aGFuIG9uZSB0aGluZz8hIFdoYXQgaWYgd2Ugd2FudCBhbGwgaHVtYW5zIHdoaWNoIHdlcmUgYm9ybiBvbiBUYXRvb2luZT8gV2UgY2FuIGp1c3QgYWRkIGFub3RoZXIgYXJndW1lbnQgdG8gb3VyIGBgYGZpbHRlcigpYGBgIGZ1bmN0aW9uIHVzaW5nIGEgY29tbWE6CgpgYGB7cn0Kc3RhcndhcnMgJT4lCiAgZmlsdGVyKHNwZWNpZXMgPT0gIkh1bWFuIiwKICAgICAgICAgaG9tZXdvcmxkID09ICJUYXRvb2luZSIpCmBgYAoKV2UgY2FuIGVzdGFibGlzaCBmYWlybHkgcXVpY2tseSB1c2luZyB0aGUgdGlkeXZlcnNlIGFwcHJvYWNoIHRoYXQgdGhlcmUgYXJlIDggaHVtYW5zIGluIHRoZSBzdGFyd2FycyB1bml2ZXJzZSB3aG8gd2VyZSBib3JuIG9uIFRhdG9vaW5lLgoKIyMgQ29tYmluaW5nIGZ1bmN0aW9ucwoKU28sIHdlJ3ZlIGVzdGJsaXNoZWQgdGhhdCB5b3UgY2FuIHNlbGVjdCBjb2x1bW5zIGFuZCBmaWx0ZXIgcm93cyAtIHdlIGNhbiBhbHNvIGNvbWJpbmUgdGhlc2UgdG8gY3JlYXRlIGFuIGV2ZW4gbW9yZSBwb3dlcmZ1bCBkYXRhIHdyYW5nbGluZyB0b29sISBXZSBjYW4gcHVsbCBvdXQgdGhlIHZhcmlhYmxlcyB0aGF0IHdlJ3JlIGludGVyZXN0ZWQgaW4sIHdoaWNoIGlzIGEga2V5IHBhcnQgb2YgdGhlIHRpZHl2ZXJzZS4gSXQncyBpbXBvcnRhbnQgaGVyZSB0byBub3RlIGhvd2V2ZXIgdGhhdCB3ZSBhcmUgZG9pbmcgdGhpcyBwcm9jZXNzIHRvIGJldHRlciB1bmRlcnN0YW5kIG91ciBkYXRhLCBub3QgdG8ganVzdCByZW1vdmUgYml0cyBvZiBpdCB0aGF0IHdlIGRvbid0IHdhbnQhCgpOb3csIGxldCdzIGNvbWJpbmUgdGhlIGBgYHNlbGVjdCgpYGBgIGFuZCBgYGBmaWx0ZXIoKWBgYCBjb21tYW5kcyB1c2luZyBvdXIgcGlwZSBvcGVyYXRvciB0byBnaXZlIHVzIGEgZGF0YXNldCB0aGF0IGNvbnRhaW5zIG9ubHkgdGhlIG5hbWUsIGhlaWdodCwgYW5kIGJpcnRoIHllYXIgb2Ygb3VyIGh1bWFuIGNoYXJhY3RlcnM6CgpgYGB7cn0Kc3RhcndhcnMgJT4lCiAgZmlsdGVyKHNwZWNpZXMgPT0gIkh1bWFuIikgJT4lCiAgc2VsZWN0KG5hbWUsIGhlaWdodCwgYmlydGhfeWVhcikKYGBgCgpSZW1lbWJlciB0aGUgZGlmZmVyZW5jZXMgaW4gd2hlbiB5b3UgbmVlZCB0byB1c2UgcXVvdGF0aW9ucyEKClRoYXQgd2FzIGEgcmVhbGx5IHN0cmFpZ2h0Zm9yd2FyZCBhbmQgZWFzeSB0byByZWFkIHdheSBvZiBmaWx0ZXJpbmcgb3VyIGRhdGFzZXQgdG8gY29udGFpbiBvbmx5IHRoZSBpbmZvcm1hdGlvbiB0aGF0IHdlIHdhbnQuIFdlIGNhbiBwZXJmb3JtIHRoZSBzYW1lIGZ1bmN0aW9uIGluIEJhc2VSIGJ5IGZpbGxpbmcgaW4gYm90aCBzaWRlcyBvZiBvdXIgc3F1YXJlIGJyYWNrZXRzIHRvIGdpdmUgYSBzZXQgb2YgaW5mb3JtYXRpb24gYWJvdXQgZXhhY3RseSB3aGF0IHJvd3MgYW5kIGNvbHVtbnMgd2Ugd2FudCB0byBrZWVwLCBidXQgaXQgaXMgbXVjaCBjbHVua2llciBhbmQgbGVzcyB1c2VyLWZyaWVuZGx5OgpgYGB7cn0KIyBEb24ndCBmb3JnZXQgdG8gaW5jbHVkZSB0aGUgd2hpY2ggZnVuY3Rpb24gdG8gcmVtb3ZlIE5BcyEKc3RhcndhcnNbd2hpY2goc3RhcndhcnMkc3BlY2llcyA9PSAiSHVtYW4iKSwKICAgICAgICAgYygibmFtZSIsICJoZWlnaHQiLCAiYmlydGhfeWVhciIpXQpgYGAKCiMgVXNpbmcgYGBgZHBseXJgYGAgdG8gZ2V0IHN1bW1hcmllcyBvZiBkYXRhCgpXZSBjYW4gdXNlIHRoZSBgYGBmaWx0ZXIoKWBgYCBhbmQgYGBgc2VsZWN0KClgYGAgZnVuY3Rpb25zIHRvIHN1bW1hcmlzZSBvdXIgZGF0YSBhbmQgZ2l2ZSB1cyBzb21lIGluZm9ybWF0aW9uIGFib3V0IGl0LiBTdW1tYXJpc2luZyBkYXRhIGlzIGFuIGltcG9ydGFudCBhbmQgdXNlZnVsIHRvb2wgLSB3ZSBtaWdodCB3YW50IHRvIGNvdW50IHRoZSBudW1iZXIgb2Ygb2JzZXJ2YXRpb25zIGluIGEgZ3JvdXAsIG9yIGdldCBhIG1lYW4gdmFsdWUgb2Ygc3Vic2V0cyBmb3IgZXhhbXBsZS4gVGhlcmUgYXJlIGEgc2V0IG9mIHN1bW1hcnkgZnVuY3Rpb25zIHRoYXQgYXJlIHZlcnkgdXNlZnVsIGZvciB0aGlzIC0gd2UnbGwgaGF2IGEgbG9vayBhdCBgYGB0YWxseSgpYGBgLCBgYGBncm91cF9ieSgpYGBgIGFuZCBgYGBzdW1tbWFyaXNlKClgYGAgYmVsb3cgLSB0aGV5IGFsbG93IHlvdSB0byBjcmVhdGUgYSBuZXcgdGliYmxlIGZvciBwbG90dGluZyBvdXQgb3V0cHV0IGFzIGEgc3VtbWFyeSBkYXRhc2V0LiAKCiMjIENvdW50aW5nIGJ5IGdyb3VwcwoKRmlyc3QsIGxldCdzIGxlYXJuIHRvIGNvdW50IHdpdGhpbiBncm91cHMgLSBwZXJoYXBzIHdlIHdhbnQgdG8gY291bnQgaG93IG1hbnkgb2YgZWFjaCBzcGVjaWVzIHRoZXJlIGFyZSBpbiBvdXIgc3RhcndhcnMgZGF0YS4gV2UgY2FuIGRvIHRoaXMgYnkgdXNpbmcgdGhlIGBgYGdyb3VwX2J5KClgYGAgYW5kIGBgYHRhbGx5KClgYGAgZnVuY3Rpb25zIC0gbGV0cyBzZWUgaG93IHRoZXkgd29yazoKCmBgYHtyfQpzdGFyd2FycyAlPiUKICBncm91cF9ieShzcGVjaWVzKQpgYGAKV2hlbiB5b3UgcnVuIHRoZSBhYm92ZSwgeW91IGVuZCB1cCB3aXRoIHRoaXMgdGliYmxlIG91dHB1dC4gWW91IGNhbiBzZWUgYXQgdGhlIHRvcCBuZXh0IHRvIHRoZSBkaW1lbnNpb25zIHRoYXQgd2UgaGF2ZSAzOCBkaWZmZXJlbnQgc3BlY2llcyBpbiBvdXIgZGF0YXNldCwgYnV0IHRoaXMgaXNuJ3Qgb2J2aW91cyBmcm9tIGxvb2tpbmcgYXQganVzdCB0aGUgZGF0YS4gTGV0J3MgdXNlIHRoZSBgYGB0YWxseSgpYGBgIGZ1bmN0aW9uIHRvIGNvdW50IHRoZW0gdXA6CgpgYGB7cn0Kc3RhcndhcnMgJT4lCiAgZ3JvdXBfYnkoc3BlY2llcykgJT4lCiAgdGFsbHkoKQpgYGAKClRhbGx5IGxpdGVyYWxseSBjb3VudHMgdGhlIG51bWJlciBvZiBvY2N1cnJlbmNlcyB3aXRoaW4gYSBzaW5nbGUgZ3JvdXAsIGFuZCBwcm9kdWNlcyBhIG5ldyB0aWJibGUgd2l0aCBhIG5ldyBjb3VudCBjb2x1bW4sICJuIi4gV2UgY2FuIHNlZSB0aGUgc3BlY2llcyBuYW1lcywgYW5kIHNlZSB0aGF0IHdlJ3ZlIGdvdCA2IERyb2lkcyBhbmQgMyBHdW5nYW5zLCBhbmQgMSBvZiBldmVyeXRoaW5nIGVsc2UgaW4gdGhlIGRpc3BsYXkuIElmIHdlIHdhbnQgbW9yZSB0aGFuIDEwIHJvd3MsIHdlIGNhbiBwaXBlIHRoZSBjb2RlIHRvIHRoZSBgYGBwcmludCgpYGBgIGZ1bmN0aW9uLCBhbmQgcHJvdmlkZSBob3cgbWFueSByb3dzIHdlIHdhbnQgaW4gdGhlIGFyZ3VtZW50IGBgYG4gPSBgYGAgd2l0aGluIHRoZSBmdW5jdGlvbi4gSWYgeW91IHdhbnQgUiB0byBwcmludCBhbGwgdGhlIGRhdGEgd2l0aG91dCBoYXZpbmcgdG8gY2hlY2sgaG93IG1hbnkgcm93cyB0aGVyZSBhcmUsIHlvdSBjYW4gYXNrIGl0IHRvIHByaW50IGluZmluaXRlIHJvd3Mgd2l0aCBgYGBuID0gSW5mYGBgOgpgYGB7cn0Kc3RhcndhcnMgJT4lCiAgZ3JvdXBfYnkoc3BlY2llcykgJT4lCiAgdGFsbHkoKSAlPiUKICBwcmludChuID0gSW5mKQpgYGAKCk9rYXkgLSBidXQgd2hhdCBpZiB3ZSB3YW50IFIgdG8gZ2l2ZSB1cyBzb21lIG1vcmUgY29tcGxleCBpbmZvcm1hdGlvbj8gV2hhdCBpZiB3ZSB3YW50IHRvIGtub3cgdGhlIGNvdW50cyBvZiB0aGUgZ2VuZGVycyB3aXRoaW4gdGhlIHNwZWNpZXMgdG9vPyBXZSBjYW4gaXRlcmF0aXZlbHkgbWFrZSBvdXIgY29kZSBtb3JlIGNvbXBsaWNhdGVkIHRvIGFjaGlldmUgdGhlc2UgdGhpbmdzIC0gaW4gdGhpcyBjYXNlLCB3ZSBqdXN0IG5lZWQgdG8gYWRkIGFub3RoZXIgYXJndW1lbnQgdG8gdGhlIGBgYGdyb3VwX2J5KClgYGAgZnVuY3Rpb246CgpgYGB7cn0Kc3RhcndhcnMgJT4lCiAgZ3JvdXBfYnkoc3BlY2llcywgZ2VuZGVyKSAlPiUKICB0YWxseSgpICU+JQogIHByaW50KG4gPSBJbmYpCmBgYApUaGlzIHRlY2huaXF1ZSBpcyB1c2VmdWwgZm9yIGNvdW50aW5nIGJpdHMgb2YgaW5mb3JtYXRpb24sIGFzIHdlbGwgYXMgcGxvdHRpbmcuIE1heWJlIHlvdSBjb3VsZCBlbnZpc2lvbiBhIHNpdHVhdGlvbiB3aGVyZSB5b3Ugd291bGQgd2FudCB0byBwbG90IHRoZSByZXN1bHRzIG9mIGdlbmRlcnMgc2VwYXJhdGVseS4KCldlIGNhbiBnZXQgbW9yZSBkZXRhaWxlZCBzdGlsbCAtIHdlIHRha2UgdGFrZSBoZWlnaHQgYW5kIG1hc3MgZm9yIGV4YW1wbGUsIGFuZCBzdW1tYXJpc2UgaXQuIFRoaXMgaXMgc2ltaWxhciB0byB3aGF0IHdlJ3ZlIGp1c3QgZG9uZSwgYnV0IHNsaWdodGx5IG1vcmUgY29tcGxleCAtIGxldCdzIHdvcmsgb3V0IHRoZSBhdmVyYWdlIGhlaWdodCBmb3IgZWFjaCBzcGVjaWVzLiBIZXJlLCB3ZSB3aWxsIGludHJvZHVjZSB0aGUgYGBgc3VtbWFyaXNlKClgYGAgZnVuY3Rpb24gaW50byBvdXIgY29kZSBwaXBlbGluZS4KCmBgYHtyfQpzdGFyd2FycyAlPiUKICBncm91cF9ieShzcGVjaWVzKSAlPiUKICBzdW1tYXJpc2UobWVhbl9oZWlnaHQgPSBtZWFuKGhlaWdodCwgbmEucm0gPSBUUlVFKSkKYGBgClRoZSBgYGBzdW1tYXJpc2VgYGAgY29tbWFuZCBpcyBtYWRlIHVwIG9mIGEgc2VyaWVzIG9mIGNvbXBvbmVudHMgaGVyZToKCiogRmlyc3QsIGBgYG1lYW5faGVpZ2h0YGBgIGlzIGNyZWF0aW5nIGEgbmV3IGNvbHVtbiwgY2FsbGVkICJtZWFuX2hlaWdodCIKKiBXZSBhcmUgdGhlbiB1c2luZyBhbiBgYGA9YGBgIHRvIHRlbGwgUiB3aGF0IHRvIHBvcHVsYXRlIHRoYXQgY29sdW1uIHdpdGgKKiBBZnRlciB0aGUgYGBgPWBgYCwgd2UgdXNlIHRoZSBgYGBtZWFuKClgYGAgZnVuY3Rpb24sIHdpdGggdHdvIGFyZ3VtZW50cy4gVGhlIGZpcnN0IGlzIHRlbGxpbmcgUiB3aGF0IHdlIHdhbnQgdG8gd29yayBvdXQgdGhlIG1lYW4gb2YgKGluIHRoaXMgY2FzZSwgaGVpZ2h0KSwgYW5kIHRoZSBzZWNvbmQgaXMgdGhlIGBgYG5hLnJtID0gVFJVRWBgYCBhcmd1bWVudCAtIHJlY2FsbCBmcm9tIGxhc3Qgc2Vzc2lvbiB0aGF0IGxvdHMgb2YgZnVuY3Rpb25zIGNhbid0IGNvcGUgd2l0aCBtaXNzaW5nIGRhdGEsIHdoaWNoIG92ZXJyaWRlcyB0aGUgcmVzdCBvZiB0aGUgZGF0YSB0byBnaXZlIGFuIGBgYE5BYGBgIG91dHB1dC4KCldlIGFyZSBlc3NlbnRpYWxseSBhc2tpbmcgUiB0byBsb29rIHdpdGhpbiBlYWNoIHNwZWNpZXMsIGFuZCByZXR1cm4gdGhlIG1lYW4gdmFsdWVzIGZvciBoZWlnaHQsIHJlbW92aW5nIGFueSBgYGBOQWBgYCB2YWx1ZXMgYXMgaXQgZ29lcy4gCgpOb3csIGxldHMgcnVuIHRoZSBzYW1lIGNvZGUgYnV0IGFkZCBhbiBleHRyYSBjb2x1bW4gZm9yIG1hc3MgLSByZW1lbWJlciBvdXIgY29kaW5nIHN0eWxlIG9mIHN0YXJ0aW5nIHNtYWxsIGFuZCBhZGRpbmcgYml0cyBvbjoKCmBgYHtyfQpzdGFyd2FycyAlPiUKICBncm91cF9ieShzcGVjaWVzKSAlPiUKICBzdW1tYXJpc2UobWVhbl9oZWlnaHQgPSBtZWFuKGhlaWdodCwgbmEucm0gPSBUUlVFKSwKICAgICAgICAgICAgbWVhbl9tYXNzID0gbWVhbihtYXNzLCBuYS5ybSA9IFRSVUUpKQpgYGAKWW91IGNhbiBzZWUgaGVyZSB0aGF0IGV2ZW4gdGhvdWdoIHdlJ3ZlIGdvdCBhbiBgYGBuYS5ybWBgYCBhcmd1bWVudCwgd2Ugc3RpbGwgaGF2ZSBhIGBgYE5hTmBgYCBpbiBvdXIgZGF0YXNldCAtIHRoaXMgaXMgYmVjYXVzZSBmb3Igd2hhdGV2ZXIgcmVhc29uLCBpdCdzIGFwcGFyZW50bHkgaW1wb3NzaWJsZSB0byBnYWluIGRhdGEgb24gdGhlIG1hc3Mgb2YgYSBDaGFncmlhbiEKCkFzIHdpdGggYWxsIHRoaW5ncyBpbiBSLCB0aGVyZSBpcyBtb3JlIHRoYW4gb25lIHRpZHl2ZXJzZSBzb2x1dGlvbiB0byB0aGUgYWJvdmUgcHJvYmxlbSwgd2UgY2FuIGFsc28gdXNlIHRoZSBgYGB2YXJzKClgYGAgYXJndW1lbnQgd2l0aGluIHRoZSBgYGBzdW1tYXJpc2VfYXQoKWBgYCBmdW5jdGlvbiwgdGhpcyBpcyBzdWJ0bHkgZGlmZmVyZW50IHRvIHRoZSBgYGBzdW1tYXJpc2UoKWBgYCBmdW5jdGlvbiwgd2hlcmUgd2UgYXNrIFIgdG8gc3VtbWFyaXNlIG11bHRpcGxlIHRoaW5ncyBhdCBvbmNlIHVzaW5nIHRoZSBzYW1lIGZ1bmN0aW9uOgoKYGBge3J9CnN0YXJ3YXJzICU+JQogIGdyb3VwX2J5KHNwZWNpZXMpICU+JQogIHN1bW1hcmlzZV9hdCh2YXJzKGhlaWdodCwgbWFzcyksIG1lYW4sIG5hLnJtID0gVFJVRSkKYGBgCgpIb3BlZnVsbHksIGhlcmUgd2UndmUgZGVtb25zdHJhdGVkIHRoZSB1c2Ugb2YgdGhlIHBpcGUgbWVjaGFuaXNtIGluIGBgYGRwbHlyYGBgIHRvIGJ1aWxkIG1vcmUgY29tcGxleCBjb21tYW5kcyB3aGljaCBhcmUgcmVhZGFibGUgYW5kIGVhc3kgdG8gZm9sbG93IHRoZSBsb2dpYyBvZi4gUmVtZW1iZXIgdG8gc3RhcnQgc2ltcGxlLCBhbmQgYnVpbGQgeW91cnNlbGYgdXAgdG8gdGhlIG1vcmUgY29tcGxpY2F0ZWQgc3R1ZmYsIHVzaW5nIHRoZSBuZXcgImdyYW1tYXIiIHRoYXQgeW91J3ZlIGxlYXJuZWQgdG8gY3JlYXRlIGNvbXBsZXggY29kZSBzdHJ1Y3R1cmVzIG9uZSBzdGVwIGF0IGEgdGltZS4gQXMgYSBnZW5lcmFsIHJ1bGUsIHlvdSBzaG91bGRuJ3QgdXNlIG1vcmUgdGhhbiB0ZW4gcGlwZXMgaW4gYSBzaW5nbGUgc3RyZXRjaCAtIGlmIHlvdSdyZSBkb2luZyB0aGlzLCBpdCdzIHByb2JhYmx5IGJlc3QgdG8gcmVzYXNzaWduIHlvdXIgb2JqZWN0IGEgbmV3IG5hbWUgcGFydC13YXkgdGhyb3VnaCB0aGUgcHJvY2VzcyBhbmQgc3RhcnQgZnJvbSBzY3JhdGNoIHdpdGggdGhlIG5ldyBvYmplY3QuIAoKCiMgZ2dwbG90MgoKVGltZSBmb3IgYSBiaXQgb2YgYSB0b25lIGNoYW5nZSwgdG8gc2hpZnQgdG8gYSBkaWZmZXJlbnQgd2F5IG9mIGV4cGxvcmluZyBkYXRhIHdpdGhpbiB0aGUgdGlkeXZlcnNlLiBXaGlzdCBgYGBkcGx5cmBgYCBpcyBncmVhdCBmb3IgZXhwbG9yaW5nIHlvdXIgZGF0YSBhbmQgZ2V0dGluZyB0byBrbm93IGl0LCBkYXRhIHZpc3VhbGlzYXRpb24gaXMgYSBkaWZmZXJlbnQgYXBwcm9hY2guCgpUaGUgImdnIiBpbiBgYGBnZ3Bsb3QyYGBgIHN0YW5kcyBmb3IgInRoZSBncmFtbWFyIG9mIGdyYXBoaWNzIi4gVGhlIGlkZWEgYmVoaW5kIHRoaXMgcGFja2FnZSBpcyB0aGF0IGl0IGlzIGJ1aWx0IHRvIG1ha2UgeW91IHRoaW5rIGFib3V0IGRhdGEgdmlzIGluIGEgc2xpZ2h0bHkgZGlmZmVyZW50IHdheS4gVGhlIHdheSB0aGF0IHlvdSB1c2UgZ2dwbG90MiBpcyBkaWZmZXJlbnQgdG8gcGxvdHRpbmcgaW4gYmFzZVIsIGFuZCBpZiB5b3UncmUgdmVyeSBmYW1pbGlhciB3aXRoIGJhc2UgcGxvdHMsIGl0IGNhbiBzZWVtIGRpZmZpY3VsdCB0byBnZXQgeW91ciBoZWFkIGFyb3VuZCwgYWx0aG91Z2ggaXQncyBjZXJ0YWlubHkgd29ydGggcGVyc2V2ZXJpbmcuIEhvd2V2ZXIsIGlmIHlvdSBhcmUgbmV3IHRvIFIsIGl0J3MgYSBncmVhdCB3YXkgb2YgbGVhcm5pbmcgaG93IGNyZWF0ZSBncmFwaGljcy4KCmdncGxvdCBpcyBleHRyZW1lbHkgZmxleGlibGUsIHdpdGggbG90cyBvZiBhZGRpdGlvbmFsIHBhY2thZ2VzIHdoaWNoIHlvdSBjYW4gaW5zdGFsbCB0aGF0IGludGVncmF0ZSBpbnRvIGl0IC0gdGhlIHBvc3NpYmlsaXRpZXMgZm9yIGdyYXBoaWNhbCBjdXN0b21pc2F0aW9uIGFyZSBhbG1vc3QgaW5maW5pdGUuIEl0J3MgYSBncmVhdCB3YXkgdG8gY3JlYXRlIHB1YmxpY2F0aW9uIHJlYWR5IGhpZ2ggcXVhbGl0eSBwbG90cyBxdWlja2x5IGFuZCBlYXNpbHkgLSBJIGtub3cgdGhhdCBJJ3ZlIHVzZWQgZ2dwbG90IGV2ZXJ5IHNpbmdsZSB0aW1lIEkndmUgd3JpdHRlbiBhbmQgcHVibGlzaGVkIGFueSBzY2llbmNlIQoKVGhlcmUgYXJlIHRocmVlIGtleSBjb21wb25lbnRzIHRvIGFueSBncmFwaGljcyBjcmVhdGVkIGluIGdncGxvdDoKCiogQSBkYXRhLmZyYW1lIG9yIHRpYmJsZSAod2hlcmUgZ2dwbG90IGlzIGdldHRpbmcgdGhlIGRhdGEgdG8gcGxvdCBmcm9tKQoqIEEgY28tb3JkaW5hdGUgYmFzZWQgc3lzdGVtIG9mIG1hcHBhYmxlIHZhcmlhYmxlcyAtIGkuZS4gYW4geCBhbmQgeSBheGlzLCBhbGxvd2luZyBnZ3Bsb3QyIGNhbiBtYXAgdmFyaWFibGVzIHRvIGl0CiogTGF5ZXJzIG9mIGdlb21ldHJ5LCBvciBgYGBnZW9tYGBgLCB3aGljaCBwbG90IHlvdXIgZGF0YS4KClRoaXMgc291bmRzIHF1aXRlIGNvbXBsaWNhdGVkIGFuZCBhYnN0cmFjdCwgYnV0IGluIHJlYWxpdHkgaXQncyBhIHNpbXBsZSBjb25jZXB0IC0gdGhpbmsgb2YgZ2dwbG90IGxpa2UgYSByYXN0ZXIgb3IgdmVjdG9yIGJhc2VkIGltYWdlIHByb2Nlc3NpbmcvZGVzaWduIHNvZnR3YXJlIGxpa2UgcGhvdG9zaG9wIG9yIEdJTVAsIHdoZXJlIHlvdSBpdGVyYXRpdmVseSBhZGQgbGF5ZXJzLCBidWlsZGluZyB1cCB0byB5b3VyIGZpbmFsIHBsb3QuIFNvdW5kIGZhbWlsaWFyPyBnZ3Bsb3QgKGFuZCBhbGwgdGhlIHRpZHl2ZXJzZSBwYWNrYWdlcykgd29yayBvbiB0aGUgc2FtZSBjb2RlLWJ1aWxkaW5nIHBoaWxvc29waHkgYXMgYGBgZHBseXJgYGAhCgpCZWZvcmUgd2UgYmVnaW4sIGlmIHlvdSBoYXZlbid0IGRvbmUgc28gYWxyZWFkeSwgcmVtZW1iZXIgdG8gbG9hZCBgYGBnZ3Bsb3QyYGBgIGludG8geW91ciBSIGVudmlyb25tZW50OgpgYGB7cn0KaW5zdGFsbC5wYWNrYWdlcygiZ2dwbG90MiIpCmxpYnJhcnkoZ2dwbG90MikKYGBgCgoKIyMgU2NhdHRlciBwbG90cwoKVGhlIGJlc3Qgd2F5IHRvIGxlYXJuIGlzLCBhcyBhbHdheXMsIHRvIGhhdmUgYSBnbyB5b3Vyc2VsZi4gRmlyc3QsIHdlJ2xsIGNyZWF0ZSBhIHNjYXR0ZXIgcGxvdCEgVGhpcyBpcyBzaW1pbGFyIHRvIHRoZSBiYXNlUiBgYGBwbG90KHgsIHkpYGBgIG91dHB1dCwgYnV0IGluZmluaXRlbHkgbW9yZSBjdXN0b21pc2FibGUuIExldCdzIHBsb3QgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGhlaWdodCBhbmQgbWFzcyBvZiBjaGFyYWN0ZXJzIHdpdGhpbiB0aGUgc3RhcndhcnMgdW5pdmVyc2UuCgpgYGB7cn0KIyBJZiB5b3UgZG9uJ3QgYWxyZWFkeSBoYXZlIHRoZSBzdGFyd2FycyBkYXRhIGxvYWRlZDoKZGF0YShzdGFyd2FycykKYGBgCgpXZSdsbCBidWlsZCB1cCB0aG9zZSBsYXllcnMsIHN0YXJ0aW5nIHdpdGggdGVsbGluZyBSIHdoYXQgZGF0YXNldCB3ZSBhcmUgdXNpbmcsIHdpdGggdGhlIGBgYGdncGxvdCgpYGBgIGZ1bmN0aW9uLCBhbmQgc2xvd2x5IGJ1aWxkIHVwIHRvIGEgY29tcGxldGUgcGxvdC4gKipOb3RlIHRoYXQgd2hpbHN0IHRoZSBwYWNrYWdlIGlzIGNhbGxlZCBgYGBnZ3Bsb3QyYGBgLCB0aGUgcGxvdHRpbmcgZnVuY3Rpb24gaXMganVzdCBgYGBnZ3Bsb3QoKWBgYCoqCgpgYGB7cn0KZ2dwbG90KHN0YXJ3YXJzKQpgYGAKCgpUaGlzIGdlbmVyYXRlcyB1cyBhIG5pY2UgYmxhbmsgZ3JleSBzcXVhcmUuIEl0IG1pZ2h0IG5vdCBzZWVtIGxpa2UgYSBmYWJ1bG91cyBzdGFydCwgYnV0IHdlJ3ZlIG1hbmFnZWQgdG8gZnVsZnVsbCBvdXIgZmlyc3Qgb2YgdGhlIHRocmVlIG5lY2Vzc2FyeSBpbnB1dHMgLSBhIGRhdGFmcmFtZS4KCkxldCdzIGJ1aWxkIG9uIHRoaXMgYnkgYWRkaW5nIHRoZSBuZXh0IHBhcnQgLSBlbXBsb3lpbmcgYSBjby1vcmRpbmF0ZSBzeXN0ZW0gZm9yIHVzIHRvIG1hcCBvdXIgdmFyaWFibGVzIG9uIHRvLiBXZSBkbyB0aGlzIGJ5IHVzaW5nIHRoZSBgYGBhZXMoKWBgYCBhcmd1bWVudCB3aXRoaW4gdGhlIGBgYGdncGxvdCgpYGBgIGZ1bmN0aW9uLiBIZXJlLCBgYGBhZXNgYGAgc3RhbmRzIGZvciBhZXN0aGV0aWNzIC0gd2hpY2ggZG9lc24ndCBtZWFuIHdoYXQgdGhlIHBsb3QgbG9va3MgbGlrZSwgYnV0IHRlbGxzIGdncGxvdCBleGFjdGx5IHdoYXQgd2Ugd2FudCB0byBtYXAgb250byBvdXIgZ3JhcGg6CgpgYGB7cn0KZ2dwbG90KHN0YXJ3YXJzLCBhZXMoeCA9IGhlaWdodCwgeSA9IG1hc3MpKQpgYGAKCllheSAtIHdlIGhhdmUgb3VyIGNvLW9yZGluYXRlIHN5c3RlbSBhbmQgb3VyIGF4ZXMgaW4gcGxhY2UgcmVhZHkgdG8gbWFwIHRoZSBkYXRhIG9udG8uIE5vdGUgdGhhdCBpbiB0aGUgYGBgYWVzKClgYGAgYXJndW1lbnQgSSBoYXZlIHNwZWNpZmllZCB3aGljaCBpcyB4IGFuZCB3aGljaCBpcyB5LCB5b3UgZG8gbm90IG5lZWQgdG8gZG8gdGhpcy4gUiBhdXRvbWF0aWNhbGx5IHBsb3RzIHggYW5kIHRoZW4geSwgc28gdHlwaW5nIGBgYGdncGxvdChzdGFyd2FycywgYWVzKGhlaWdodCwgbWFzcykpYGBgIHdvdWxkIHllaWxkIHRoZSBzYW1lIHJlc3VsdC4gCgpOb3csIGxldCdzIGFkZCB0aGUgcG9pbnRzIHRvIHRoZSBncmFwaC4gV2UgZG8gdGhpcyBieSBhZGRpbmcgYSBuZXcgbGF5ZXIgdG8gdGhlIHBsb3QsIHdpdGggb25lIG9mIHRoZSBzZXQgb2YgYGBgZ2VvbWBgYCBmdW5jdGlvbnMgaW4gZ2dwbG90IC0gYGBgZ2VvbV9wb2ludCgpYGBgLiBUbyBhZGQgYSBuZXcgbGF5ZXIsIHdlIGVuZCB0aGUgcHJldmlvdXMgbGluZSBvZiBjb2RlIHdpdGggYSBgYGArYGBgLCB3aGljaCB0ZWxscyBSIHRoYXQgd2Ugd2VyZW4ndCBmaW5pc2hlZCB3aXRoIHRoZSBsYXN0IGxpbmU6CgpgYGB7cn0KZ2dwbG90KHN0YXJ3YXJzLCBhZXMoeCA9IGhlaWdodCwgeSA9IG1hc3MpKSsKICBnZW9tX3BvaW50KCkKYGBgCllvdSBtYXkgc2VlIGEgd2FybmluZyB0aGF0IHNheXMgUiBoYXMgcmVtb3ZlZCAyOCByb3dzIHdpdGggbWlzc2luZyB2YWx1ZXMgLSB0aGVzZSBhcmUganVzdCBvdXIgYGBgTkFgYGAgdmFsdWVzIGZyb20gdGhlIGRhdGFzZXQsIHNvIHlvdSBjYW4gaWdub3JlIHRoYXQgZm9yIG5vdy4gCgpOb3csIHBsb3R0aW5nIG91ciBzY2F0dGVyIHBsb3Qgb2YgaGVpZ2h0IGFuZCBtYXNzIGhhcyBzaG93biB1cyB3aHkgd2UgbWlnaHQgd2FudCB0byBwbG90IG91ciBkYXRhIC0gaXQgc2VlbXMgdGhhdCB3ZSBoYXZlIGEgc2luZ2xlIGluZGl2aWR1YWwgd2l0aCBhIG1hc3Mgb2YgYXJvdW5kIDE0MDAgdW5pdHMsIHdoZXJlYXMgZXZlcnlvbmUgZWxzZSBpcyBiZWxvdyBhYm91dCAyMDAhIElmIHlvdSBrbm93IGFueXRoaW5nIGFib3V0IHRoZSBzdGFyd2FycyB1bml2ZXJzZSB5b3UgbWlnaHQgYmUgYWJsZSB0byBndWVzcyB3aG8gdGhpcyBpcy4uLiBGb3IgZXZlcnlvbmUgZWxzZSAtIGxldCdzIHNlZSBpZiB3ZSBjYW4gd29yayBpdCBvdXQgYnkgZ29pbmcgYmFjayB0byBvdXIgYGBgZHBseXJgYGAgc2tpbGxzIHRoYXQgd2UndmUganVzdCBsZWFybmVkLCBhbmQgYWRkIGluIGEgd2F5IHRvIG9ubHkgZGlzcGxheSBpbmZvcm1hdGlvbiBhYm91dCBpbmRpdmlkdWFscyB3aXRoIGEgbWFzcyBvZiBncmVhdGVyIHRoYW4gMTAwMCEKCmBgYHtyfQpzdGFyd2FycyAlPiUKICBmaWx0ZXIobWFzcyA+IDEwMDApICU+JQogIHNlbGVjdChuYW1lLCBzcGVjaWVzLCBtYXNzKQpgYGAKSWYgeW91IGtub3cgYW55dGhpbmcgYWJvdXQgc3RhcndhcnMsIHBlcmhhcHMgdW5zdXJwcmlzaW5nbHksIG91ciBhbnN3ZXIgaXMgSmFiYmEgdGhlIEh1dHQhCgpBbnl3YXksIGJhY2sgdG8gZ2dwbG90LgoKIyMgSGlzdG9ncmFtcwoKU29tZXRpbWVzLCB5b3UgbWlnaHQgd2FudCB0byBwbG90IHRoZSBkaXN0cmlidXRpb24gb2YgeW91ciBkYXRhLiBUaGlzIGlzIHVzZWZ1bCBmb3IgYm90aCBpZGVudGlmeWluZyBvdXRsaWVycywgYW5kIGFsc28gZm9yIHNlZWluZyB3aGF0IG91ciBkYXRhIGxvb2sgbGlrZS4gSW4gbG90cyBvZiBzdGF0aXN0aWNhbCB0ZXN0cywgd2UgbWFrZSBhc3N1bXB0aW9ucyByZWdhcmRpbmcgdGhlIGRpc3RyaWJ1dGlvbiBvZiBvdXIgZGF0YSAtIG9mdGVuIHRoaXMgYXNzdW1wdGlvbiBpcyB0aGF0IG91ciBkYXRhIGZvbGxvdyBhIG5vcm1hbCBkaXN0cmlidXRpb24uIFdlIGNhbiBjcmVhdGUgYSBoaXN0b2dyYW0gcmVhbGx5IHF1aWNrbHkgdXNpbmcgZ2dwbG90IGFuZCBzZWUgaWYgdGhpcyBpcyB0cnVlIQoKV2UnbGwgc3RhcnQgYnkgYnVpbGRpbmcgdXAgb3VyIGRhdGEgYXMgd2UgZGlkIGJlZm9yZSwgYnV0IHdlJ2xsIGdvIHN0cmFpZ2h0IHRvIGFkZGluZyB0aGUgY28tb3JkaW5hdGUgc3lzdGVtOgpgYGB7cn0KZ2dwbG90KHN0YXJ3YXJzLCBhZXMoeCA9IG1hc3MpKQpgYGAKCllvdSBtaWdodCBoYXZlIG5vdGljZWQgdGhhdCB3ZSBvbmx5IGhhdmUgb25lIGF4aXMgaGVyZSAtIHRoaXMgaXMgYmVjYXVzZSB3ZSBoYXZlIG9ubHkgc3VwcGxpZWQgUiB3aXRoIGEgc2luZ2xlIGFlc3RoZXRpYyAodGhlIHggYWVzdGhldGljKS4gVGhlIHJlYXNvbiB0aGF0IHdlIGhhdmUgZG9uZSB0aGlzLCBpcyBiZWNhdXNlIGhpc3RvZ3JhbXMgcGxvdCBhIHNpbmdsZSB2YXJpYWJsZSBhZ2FpbnN0IGl0J3MgY291bnQgLSB3ZSBkb24ndCBrbm93IHdoYXQgdGhhdCBjb3VudCBpcyB5ZXQsIGdncGxvdCB3aWxsIGZpZ3VyZSB0aGF0IG91dCBmb3IgdXMuIE5vdGljZSBhbHNvIHRoYXQgd2UgY2FuIGdldCBhbiBpZGVhIG9mIHRoZSBzY2FsZSBqdXN0IGJ5IGxvb2tpbmcgYXQgdGhlIHggYXhpcywgd2UgY2FuIHNlZSBoZXJlIHRoYXQgb3VyIG1hc3MgcmFuZ2VzIGZyb20gMCB0byB3YXkgYWJvdmUgMTAwMCAod2hpY2ggd2Ugbm93IGtub3cgaXMgYSBkaXJlY3QgcmVzdWx0IG9mIEphYmJhIHRoZSBIdXQhKS4KCkxldCdzIGFkZCB0aGUgaGlzdG9ncmFtIGdlb20uCgpgYGB7cn0KZ2dwbG90KHN0YXJ3YXJzLCBhZXMobWFzcykpKwogIGdlb21faGlzdG9ncmFtKCkKYGBgCgpXZSBjYW4gc2VlIHRoYXQsIGFzIGluIG91ciBzY2F0dGVycGxvdCwgbW9zdCBpbmRpdmlkdWFscyBhcmUgYmVsb3cgYWJvdXQgMjUwIHVuaXRzIG9mIG1hc3MsIHdpdGggYSBzaW5nbGUgaW5kaXZpZHVhbCB3YXkgb3ZlciAxMDAwIQoKVGhlcmUgYXJlIGxvYWRzIG9mIGRpZmZlcmVudCBnZW9tcyBhdmFpbGFibGUsIGFuZCBsb3RzIG9mIG9ubGluZSByZXNvdXJjZXMgdG8gY2hlY2sgb3V0IC0gdGhlIGdncGxvdCBtYW51YWwgaXMgcGFydGljdWxhcmx5IHVzZWZ1bCEgRm9yIG5vdywgbGV0J3MganVzdCBoYXZlIGEgbG9vayBhdCBvbmUgbW9yZSwgdGhlIGJveHBsb3QuIEJveHBsb3RzIGFyZSBhbiBpbmNyZWRpYmx5IHVzZWZ1bCB3YXkgb2YgbG9va2luZyBhdCBkaXN0cmlidXRpb25zIG9mIGRhdGEgd2l0aGluIGdyb3VwcywgYW5kIHdvcmtpbmcgb3V0IHdoZXRoZXIgcGFydGljdWxhciBncm91cHMgZnJvbSBhIHNpbmdsZSBkYXRhc2V0IGRpZmZlciBmcm9tIG9uZSBhbm90aGVyIGluIGEgY2VydGFpbiBtZWFzdXJlbWVudC4gTGV0J3MgcGxvdCBhIGJveHBsb3QgdGhhdCB0ZWxscyB1cyBhYm91dCB0aGUgbWFzcyBvZiBzcGVjaWVzIGZyb20gd2l0aGluIHRoZSBzdGFyd2FycyB1bml2ZXJzZToKCmBgYHtyfQpnZ3Bsb3Qoc3RhcndhcnMsIGFlcyh4ID0gc3BlY2llcywgeSA9IG1hc3MpKSsKICBnZW9tX2JveHBsb3QoKQpgYGAKCkFoLiBUaGlzIGlzbid0IGEgdmVyeSBuaWNlIHBsb3QuIFRoZXJlJ3MgZmFyIHRvbyBtdWNoIGRhdGEsIGFuZCBpdCdzIGFsbCB2ZXJ5IG1lc3N5LiBXZSBjYW4ndCBzZWUgYW55IG9mIG91ciBzcGVjaWVzIG5hbWVzLCBvciByZWFsbHkgd29yayBvdXQgd2hhdCdzIGdvaW5nIG9uIGF0IGFsbCAtIGxldHMgbGVhcm4gaG93IHRvIGZpeCBpdC4uLgoKIyBDb21iaW5pbmcgZ2dwbG90MiBhbmQgZHBseXIKCkl0J3MgdGltZSB0byBjb21iaW5lIG91ciBuZXcgcGxvdHRpbmcgYW5kIGRhdGEtd3JhbmdsaW5nIHNraWxsc2V0cyEgZ2dwbG90IGlzIGEgZ3JlYXQgd2F5IG9mIHNob3dpbmcgZGF0YSwgYnV0IHJlYWxseSB0aGUgcG93ZXIgb2YgdGhlIHRpZHl2ZXJzZSBjb21lcyB3aGVuIHlvdSBpbnRlZ3JhdGUgdGhlIHBhY2thZ2VzIHdpdGggb25lIGFub3RoZXIuIFRoZSBjb21iaW5lZCBwaGlsb3NvcGhpZXMgb2YgZHBseXIgYW5kIGdncGxvdDIgY2FuIGNyZWF0ZSB1cyBhIG11Y2ggbmljZXIgcGxvdC4gQmVjYXVzZSBkcGx5ciBhbmQgZ2dwbG90MiB3ZXJlIGJ1aWx0IHRvZ2V0aGVyIHVuZGVyIHRoZSB0aWR5dmVyc2UgdW1icmVsbGEsIHRoZXkgaW50ZWdyYXRlIHJlYWxseSBzbW9vdGhseSB3aXRoIG9uZSBhbm90aGVyLCBhbmQgY29tYmluaW5nIHRoZW0gaXMgYXMgc2ltcGxlIGFzIHBpcGluZyBmcm9tIGEgZHBseXIgZmlsdGVyIGludG8gYSBnZ3Bsb3QgZnVuY3Rpb24uIFlvdSBjYW4gdGFrZSBhIGRhdGFzZXQgeW91IGRvbid0IGtub3csIGFuZCByZWFsbHkgZ2V0IGEgaGFuZGxlIG9uIGl0IGJ5IGNvbWJpbmluZyB0aGVzZSB0b29scy4gTGV0J3MgdHJ5IGhlcmUuCgpXZSdsbCBnbyBiYWNrIHRvIG91ciBib3hwb3QgYW5kIHVzZSB3aGF0IHdlJ3ZlIGxlYXJuZWQgd2l0aCBkcGx5ciB0byBjcmVhdGUgYSBtdWNoIG5pY2VyIGJveHBsb3QgdGhhdCBkZXNjcmliZXMgdGhlIG1hc3Mgb2YgdGhyZWUgZGlmZmVyZW50IHNwZWNpZXMgKHJhdGhlciB0aGFuIGFsbCBvZiB0aGVtIGF0IG9uY2UhKS4gU28sIHdoaWNoIHNwZWNpZXMgc2hhbGwgd2UgdXNlPyBJbiBhIGRhdGFzZXQgdGhhdCBjb250YWlucyBsb3RzIG9mIG9ic2VydmF0aW9ucyBvZiBhIHNpbmdsZSBpbmRpdmlkdWFsIG9mIGEgc3BlY2llcywgSSB0aGluayBpdCBtYWtlcyBzZW5zZSB0byBzZWxlY3QgdGhlIHRocmVlIG1vc3QgYWJ1bmRhbnQgc3BlY2llcy4gUmVtZW1iZXIgaG93IGVhcmxpZXIgd2UgdXNlZCB0aGUgYGBgZ3JvdXBfYnkoKWBgYCBhbmQgdGhlIGBgYHRhbGx5KClgYGAgZnVuY3Rpb25zIHRvIGdldCBSIHRvIGNvdW50IHRoZSBudW1iZXIgb2YgaW5kaXZpZHVhbHMgaW4gZWFjaCBzcGVjaWVzPwoKYGBge3J9CnN0YXJ3YXJzICU+JQogIGdyb3VwX2J5KHNwZWNpZXMpICU+JQogIHRhbGx5KCkKYGBgCgpUaGlzIGlzIGdyZWF0LCBidXQgaXQgd291bGQgYmUgYmV0dGVyIGlmIHdlIGNvdWxkIG9yZGVyIGl0IGFuZCBzZWUgYXQgYSBnbGFuY2Ugd2hpY2ggc3BlY2llcyBoYWQgdGhlIG1vc3QgaW5kaXZpZHVhbHMgLSB3ZSBjYW4gZG8gdGhpcyB3aXRoIHRoZSBgYGBhcnJhbmdlKClgYGAgZnVuY3Rpb24gYW5kIHRoZSBgYGBkZXNjYGBgIGFyZ3VtZW50OgoKYGBge3J9CnN0YXJ3YXJzICU+JQogIGdyb3VwX2J5KHNwZWNpZXMpICU+JQogIHRhbGx5KCkgJT4lCiAgYXJyYW5nZShkZXNjKG4pKQpgYGAKCmBgYGRlc2MobilgYGAgdGVsbHMgdGhlIGBgYGFycmFuZ2UoKWBgYCBmdW5jdGlvbiB0aGF0IHdlIHdhbnQgdG8gZGlzcGxheSBvdXIgZGF0YSBpbiBkZXNjZW5kaW5nIG9yZGVyIG9mIHRoZSBudW1iZXIgb2YgaW5kaXZpZHVhbHMgaW4gZWFjaCBzcGVjaWVzLgoKV2UgY2FuIHNlZSBmcm9tIHRoZSByZXN1bHRpbmcgdGliYmxlIHRoYXQgd2UgaGF2ZSAzNSBodW1hbnMsIDYgZHJvaWRzLCBvdXIgbmV4dCBoaWdoZXN0IGlzIGBgYE5BYGBgIHdoZXJlIHNwZWNpZXMgd2Fzbid0IHJlY29yZGVkLCBzbyB3ZSdsbCBpZ25vcmUgdGhhdCwgYW5kIHRoZW4gMyBndW5nYW5zLiBXZSdsbCBwbG90IHRoZSBtYXNzIG9mIGVhY2ggb2YgdGhlc2UgdGhyZWUgc3BlY2llcyEgVG8gZG8gdGhpcywgd2Ugd2lsbCBuZWVkIHRvIGZpbHRlciBvdXIgZGF0YSB1c2luZyBgYGBkcGx5cmBgYC4gV2UgY2FuIGZpbHRlciBmb3IgbXVsaXRwbGUgbWF0Y2hlcyB1c2luZyB0aGUgT1Igb3BlcmF0b3IgYGBgfGBgYCB0aHVzOgoKYGBge3J9CnN0YXJ3YXJzICU+JQogIGZpbHRlcihzcGVjaWVzID09ICJIdW1hbiIgfCBzcGVjaWVzID09ICJEcm9pZCIgfCBzcGVjaWVzID09ICJHdW5nYW4iKQpgYGAKCldoZW4gd2UgcnVuIHRoZSBjb2RlIHRvIHNlbnNlIGNoZWNrIG91cnNlbHZlcywgaXQncyB0cmlja3kgdG8gc2VlIGlmIGl0J3Mgd29ya2VkIGluIHRoZSB3YXkgd2Ugd2FudGVkLiBXZSBjYW4gZ2V0IHJvdW5kIHRoaXMgYnkgcGlwaW5nIHRvIHNlbGVjdCBzbyB3ZSBjYW4gb25seSBzZWUgdGhlIHJlbGV2YW50IGNvbHVtbnM6CgpgYGB7cn0Kc3RhcndhcnMgJT4lCiAgZmlsdGVyKHNwZWNpZXMgPT0gIkh1bWFuIiB8IHNwZWNpZXMgPT0gIkRyb2lkIiB8IHNwZWNpZXMgPT0gIkd1bmdhbiIpICU+JQogIHNlbGVjdChuYW1lLCBzcGVjaWVzLCBtYXNzKQpgYGAKClJpZ2h0LCB3ZSBzdGlsbCBjYW4ndCBzZWUgaWYgd2UndmUgZ290IGFueSBHdW5nYW5zIGluIGhlcmUuIExldCdzIGdldCBhcm91bmQgdGhhdCBieSBhZGRpbmcgYSB0YWxseSB0byBkaXNwbGF5IGEgY291bnQgb2YgaG93IG1hbnkgc3BlY2llcyBhcmUgaW4gb3VyIG5ldyBzZWxlY3Rpb24gLSBkb24ndCBmb3JnZXQgdGhlIGBgYGdyb3VwX2J5KClgYGAgdG8gdGVsbCB0YWxseSB3aGF0IGl0IG5lZWRzIHRvIGNvdW50IQoKYGBge3J9CnN0YXJ3YXJzICU+JQogIGZpbHRlcihzcGVjaWVzID09ICJIdW1hbiIgfCBzcGVjaWVzID09ICJEcm9pZCIgfCBzcGVjaWVzID09ICJHdW5nYW4iKSAlPiUKICBzZWxlY3QobmFtZSwgc3BlY2llcywgbWFzcykgJT4lCiAgZ3JvdXBfYnkoc3BlY2llcykgJT4lCiAgdGFsbHkoKQpgYGAKRmFidWxvdXMuIEl0IHNlZW1zIHRoYXQgd2UndmUgZ290IGFsbCBvZiBvdXIgZGF0YSBpbiBjaGVjaywgYW5kIG91ciBjb2RlIHNlZW1zIHRvIGJlIGRvaW5nIHdoYXQgd2Ugd2FudCBpdCB0byEgV2UgY2FuIGRlbGV0ZSB0aG9zZSBmaW5hbCBgYGBncm91cF9ieSgpYGBgIGFuZCBgYGB0YWxseSgpYGBgIHNlbnNlIGNoZWNrcywgYW5kIHBpcGUgc3RyYWlnaHQgdG8gZ2dwbG90LiBXZSdsbCBqdXN0IHBsb3QgdGhlIGFlc3RoZXRpY3MgZmlyc3QgdG8gY2hlY2sgaWYgd2UndmUgZ290IHRoZSBjb3JyZWN0IG1hcHBpbmcgYW5kIHRoYXQgb25seSB0aHJlZSBzcGVjaWVzIGFwcGVhciBvbiB0aGUgeCBheGlzLiBXZSBkb24ndCBuZWVkIHRvIGluY2x1ZGUgdGhlIG5hbWUgb2YgdGhlIGRhdGEgaW4gb3VyIGBgYGdncGxvdCgpYGBgIGNvbW1hbmQgdGhpcyB0aW1lIC0gUiBhbHJlYWR5IGtub3dzIHdoYXQgZGF0YSB3ZSdyZSB1c2luZyBmcm9tIG91ciBwaXBpbmcKCmBgYHtyfQpzdGFyd2FycyAlPiUKICBmaWx0ZXIoc3BlY2llcyA9PSAiSHVtYW4iIHwgc3BlY2llcyA9PSAiRHJvaWQiIHwgc3BlY2llcyA9PSAiR3VuZ2FuIikgJT4lCiAgc2VsZWN0KG5hbWUsIHNwZWNpZXMsIG1hc3MpICU+JQogIGdncGxvdChhZXMoeCA9IHNwZWNpZXMsIHkgPSBtYXNzKSkKYGBgCgpFeGNlbGxlbnQuIE5vdywgbGV0J3MgYWRkIHRoZSBib3hwbG90IGdlb20uCgpgYGB7cn0Kc3RhcndhcnMgJT4lCiAgZmlsdGVyKHNwZWNpZXMgPT0gIkh1bWFuIiB8IHNwZWNpZXMgPT0gIkRyb2lkIiB8IHNwZWNpZXMgPT0gIkd1bmdhbiIpICU+JQogIHNlbGVjdChuYW1lLCBzcGVjaWVzLCBtYXNzKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBzcGVjaWVzLCB5ID0gbWFzcykpKwogIGdlb21fYm94cGxvdCgpCmBgYAoKVGhpcyBpcyBhIG11Y2ggbmljZXIgYW5kIG1vcmUgc3VjY2Vzc2Z1bCBib3hwbG90IHRoYW4gYmVmb3JlISBXZSBjYW4gc2VlIHRoYXQgdGhlIG1lYW4gbWFzcyBvZiBEcm9pZHMgdGVuZHMgdG8gYmUgbXVjaCBsb3dlciB0aGFuIEd1bmdhbnMgYW5kIEh1bWFucywgYnV0IHRoZWlyIG1hc3MgaXMgbW9yZSB2YXJpYWJsZS4gCgpXZSBoYXZlIHN1Y2Nlc3NmdWxseSBjb21iaW5lZCBnZ3Bsb3QgYW5kIGRwbHlyIGluIGEgcmVhbGx5IHVzZWZ1bCBhbmQgcG93ZXJmdWwgd2F5LCB0aGF0IHdpbGwgbWFrZSBleHBsb3JpbmcgZGF0YSBtdWNoIHF1aWNrZXIgYW5kIGVhc2llci4KCiMgUmVzaGFwaW5nIGRhdGEKClRoZSBzdGFyd2FycyBkYXRhc2V0IGlzIGFscmVhZHkgaW4gYSBuaWNlIGZvcm1hdCBmb3IgcGxvdHRpbmcsIGFuZCB3ZSBoYXZlbid0IG5lZWRlZCB0byBkbyBhbnl0aGluZyB3aXRoIGl0IHRvIGdldCBpdCB0aGVyZS4gVGhpcyB3b24ndCBhbHdheXMgYmUgdGhlIGNhc2Ugd2l0aCByZWFsIHdvcmxkIGRhdGEuIFNvcnRpbmcgdGhpcyBvdXQgaXMgY29tcGxpY2F0ZWQsIGFuZCBpdCdzIG9rYXkgaWYgeW91IGRvbid0IGZ1bGx5IGdyYXNwIHRoZSBmb2xsb3dpbmcgdGhlIGZpcnN0IHRpbWUgcm91bmQgLSB5b3UnbGwgZ2V0IHVzZWQgdG8gaXQgYnkgcHJhY3RpY2luZyBhbmQgaGF2aW5nIGEgZ28gd2l0aCBkYXRhIGluIHlvdXIgb3duIHRpbWUuCgpOb3csIHRoZXJlIGFyZSB0d28gbWFpbiB0eXBlcyBvZiBkYXRhOgoKKiBsb25nIGRhdGEgLSBtYW55IHJvd3MsIGJ1dCBmZXcgY29sdW1ucy4gQW4gaW5kaXZpZHVhbCBoYXMgbWFueSByb3dzLCBlYWNoIHdpdGggYSBkaWZmZXJlbnQgb2JzZXJ2YXRpb24gb24gaXQKKiB3aWRlIGRhdGEgLSBtYW55IGNvbHVtbnMsIGZld2VyIHJvd3MuIEVhY2ggaW5kaXZpZHVhbCBpcyBhIHNpbmdsZSByb3csIHdpdGggbWFueSBjb2x1bW5zIG9mIG9ic2VydmF0aW9ucwoKU29tZXRpbWVzLCBpdCdzIG5lY2Vzc2FyeSB0byBzd2FwIGJldHdlZW4gdGhlc2UgdHlwZXMgb2YgZGF0YSBzbyB3ZSBjYW4gcHJvZHVjZSB0aGUgcGxvdCB0aGF0IHdlIHdhbnQuIFRoZSBgYGBwaXZvdF9kYXRhYGBgIGZ1bmN0aW9ucyBhbGxvdyB1cyB0byBkbyB0aGlzLiBgYGBwaXZvdF9sb25nZXJgYGAgd2lsbCBjb252ZXJ0IGEgd2lkZSBkYXRhc2V0IGludG8gYSBsb25nIG9uZSwgYnkgcmVkdWNpbmcgdGhlIG51bWJlciBvZiBjb2x1bW5zIGFuZCBpbmNyZWFzaW5nIHRoZSBudW1iZXIgb2Ygcm93cywgY29udmVydGluZyBjb2x1bW5zIGludG8gbmV3IHJvd3MsIGFuZCBgYGBwaXZvdF93aWRlcmBgYCBkb2VzIHRoZSBvcHBvc2l0ZS4gCgpXZSdsbCB1c2UgdGhlIGBgYGlyaXNgYGAgZGF0YXNldCB0byBkZW1vbnN0cmF0ZS4gQXMgYSByZW1pbmRlciwgdGhlIGlyaXMgZGF0YXNldCBjb250YWlucyBkaWZmZXJlbnQgbWVhc3VyZW1lbnRzIChwZXRhbCBsZW5ndGgsIHBldGFsIHdpZHRoLCBzZXBhbCBsZW5ndGgsIGFuZCBzZXBhbCB3aWR0aCkgZnJvbSBtdWx0aXBsZSBpbmRpdmlkdWFscyBvZiB0aHJlZSBkaWZmZXJlbnQgc3BlY2llcyBvZiBpcmlzLiBJZiB3ZSB2aWV3IHRoZSBkYXRhIHdpdGggYGBgaGVhZGBgYCB3ZSBjYW4gc2VlIHRoYXQgdGhlIGRhdGEgaXMgaW4gYSB3aWRlIGZvcm1hdCwgd2hlcmUgYSByb3cgcmVwcmVzZW50cyBhIHNpbmdsZSBpbmRpdmlkdWFsIHdpdGggY29sdW1ucyBvZiBvYnNlcnZhdGlvbnM6CgpgYGB7cn0KaGVhZChpcmlzKQpgYGAKCldlIHdhbnQgdGhpcyBkYXRhc2V0IHRvIGJlIGxvbmcsIHdpdGggbXVsdGlwbGUgcm93cyBwZXIgaW5kaXZpZHVhbCwgYW5kIG9ubHkgYSBzaW5nbGUgY29sdW1uIG9mIG1lYXN1cmVtZW50cy4gTGV0J3MgaGF2ZSBhIGdvIGF0IHVzaW5nIGBgYHBpdm90X2xvbmdlcigpYGBgIHRvIGFjaGlldmUgdGhpcy4gVGhlIGZpcnN0IHRoaW5nIHdlIGhhdmUgdG8gY29uc2lkZXIsIHRob3VnaCwgaXMgdGhhdCBpcmlzIGlzIGEgZGF0YS5mcmFtZSByYXRoZXIgdGhhbiBhIHRpYmJsZS4gV2UgY2FuIGZpeCB0aGF0IGJ5IHBpcGluZyB0byBgYXNfdGliYmxlKClgIGJlZm9yZSB3ZSByZXNoYXBlLiBXZSdsbCBhbHNvIGFzc2lnbiBhbGwgb2YgdGhpcyB0byBhIG5ldyBvYmplY3QsIHRoYXQgd2UnbGwgY2FsbCBgaXJpczJgLgoKYGBge3J9CmlyaXMyIDwtIGlyaXMgJT4lCiAgYXNfdGliYmxlKCkgJT4lCiAgcGl2b3RfbG9uZ2VyKGNvbCA9IDE6NCwgbmFtZXNfdG8gPSAibWVhc3VyZSIpCmBgYApMZXQncyBkaXNzZWN0IHRoYXQgYHBpdm90X2xvbmdlcigpYCBmdW5jdGlvbjoKCiogdGhlIGBjb2wgPSAxOjRgIGFyZ3VtZW50IHRlbGxzIHRoZSBmdW5jdGlvbiB0aGF0IHdlIHdhbnQgdG8gY29udmVydCB0aGVzZSA0IGNvbHVtbnMgaW50byBpbmRpdmlkdWFsIHJvd3MuIFdlIGRvbid0IGluY2x1ZGUgdGhlIGZpZnRoIGNvbHVtbiwgc3BlY2llcywgYXMgdGhpcyBpcyBhbiBpZGVudGlmaWVyIHJhdGhlciB0aGFuIGEgbWVhc3VyZW1lbnQuCiogdGhlIGBuYW1lc190byA9ICJtZWFzdXJlImAgaXMgc2ltcGx5IGNyZWF0aW5nIGEgbmV3IGNvbHVtbiB3aGVyZSB3ZSBjYW4gc3RvcmUgdGhlIG9yaWdpbmFsIGNvbHVtbiBoZWFkaW5ncy4KCk5vdGUgdGhhdCB3aGVuIHdlIGFzc2lnbiB0aGluZ3MsIHdlIGRvbid0IGF1dG9tYXRpY2FsbHkgZ2V0IHRoZW0gYXMgYW4gb3V0cHV0IHRvbyAtIGxldCdzIGNhbGwgYGlyaXMyYCBhbmQgc2VlIHdoYXQgaXQgbG9va3MgbGlrZToKCmBgYHtyfQppcmlzMgpgYGAKCkdyZWF0LiBUaGUgZGF0YSBpcyBub3cgaW4gYSBsb25nIGZvcm1hdCwgcmF0aGVyIHRoYW4gd2lkZS4gV2UgY2FuIHBsb3QgaXQgYXMgYSBib3hwbG90IHRoYXQgdGVsbHMgdXMgaW5mb3JtYXRpb24gYWJvdXQgZWFjaCBzcGVjaWVzIGFuZCBtZWFzdXJlbWVudCBzZXBlcmF0ZWx5LiBMZXQncyB0cnkgaXQgd2l0aCB3aGF0IHdlIGN1cnJlbnRseSBrbm93IG9mIGdncGxvdDoKCmBgYHtyfQpnZ3Bsb3QoaXJpczIsIGFlcyh4ID0gU3BlY2llcywgeSA9IHZhbHVlKSkrCiAgZ2VvbV9ib3hwbG90KCkKYGBgCgpUaGlzIHBsb3QgaGFzIGdpdmVuIHVzIHRocmVlIGRpZmZlcmVudCBib3hlcyBvbiBvdXIgcGxvdCAtIG9uZSBwZXIgc3BlY2llcy4gV2UndmUgY29uZmxhdGVkIGFsbCBvZiB0aGUgbWVhc3VyZW1lbnRzIHRvZ2V0aGVyIC0gdGhpcyBpcyBzaW1wbHkgYmVjYXVzZSB3ZSBoYXZlbid0IHRvbGQgUiB0aGF0IHdlIHdhbnQgdGhlbSBzZXBhcmF0ZWQhIFdlIGNhbiBkbyB0aGlzIHVzaW5nIGEgdG9vbCBrbm93biBhcyBmYWNldCBncmlkcywgd2hpY2ggaXMgZXNzZW50aWFsbHkgYSBmYW5jeSB3YXkgb2Ygc2F5aW5nICJzcGxpdHRpbmcgcGxvdHMgdG8gcHVsbCBvdXQgZGlmZmVyZW50IG1lYXN1cmVtZW50cyIuIExldCdzIHRyeSBhZGRpbmcgYSBgYGBmYWNldF9ncmlkKClgYGAgbGF5ZXIgdG8gb3VyIHBsb3QsIGFuZCBpbmNsdWRpbmcgdGhlIGFyZ3VtZW50IGBgYH5tZWFzdXJlYGBgIHdpdGhpbiBpdC4gUmVtZW1iZXIgdGhhdCBhIH4gZGVub3RlcyBhIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHRoaW5ncywgc28gYnkgY2FsbGluZyBgYGBmYWNldF9ncmlkKH5tZWFzdXJlKWBgYCB3ZSBhcmUgYXNraW5nIFIgdG8gcGxvdCB0aGUgYWJvdmUsIGJ1dCBzZXBhcmF0aW5nIHRoZSBwbG90cyBiZXR3ZWVuIG1lYXN1cmVtZW50IHR5cGVzLiBMZXRzIGhhdmUgYSBnbzoKCmBgYHtyfQpnZ3Bsb3QoaXJpczIsIGFlcyh4ID0gU3BlY2llcywgeSA9IHZhbHVlKSkrCiAgZ2VvbV9ib3hwbG90KCkrCiAgZmFjZXRfZ3JpZCh+bWVhc3VyZSkKYGBgCgpHcmVhdCwgc28gbm93IHdlJ3ZlIG1hbmFnZWQgdG8gc2VwYXJhdGUgb3VyIG1lYXN1cmVtZW50cyBvdXQgaW50byBpbmRpdmlkdWFsIHBsb3RzLCBhbmQgYnkgZG9pbmcgdGhpcyB3ZSBjYW4gbGVhcm4gbW9yZSBhYm91dCB0aGUgZGF0YSEgV2UgY2FuIHNlZSB0aGF0IHRoZSBzZXRvc2Egc3BlY2llcyB0ZW5kcyB0byBiZSBzbWFsbGVyIHRoYW4gdGhlIG90aGVyIHR3byBnZW5lcmFsbHksIHdpdGggdGhlIGV4Y2VwdGlvbiBvZiBpdCdzIHNlcGFsIHdpZHRoLiBIb3BlZnVsbHkgbm93IHlvdSBjYW4gc2VlIGhvdyByZXNoYXBpbmcgeW91ciBkYXRhIGluIHRoaXMgd2F5IGFsbG93cyB5b3UgdG8gZXhwbG9yZSBpdCBkaWZmZXJlbnRseSwgYW5kIGdldCB0byBrbm93IGl0IGEgbGl0dGxlIGJldHRlciEKCiMgU2F2aW5nIHBsb3RzCgpTbyBub3cgd2UndmUgZ290IG91ciBkYXRhIHBsb3R0ZWQgYW5kIHJlYWR5IHRvIGdvLCB3ZSBtaWdodCB3YW50IHRvIHNhdmUgaXQuIEhlbHBmdWxseSwgdGhlcmUgaXMgYW4gImV4cG9ydCBncmFwaCIgYnV0dG9uIG9uIHRoZSBwbG90IHdpbmRvdyB0aGF0IG1ha2VzIHRoaXMgbmljZSBhbmQgZWFzeS4gQWx0aG91Z2ggdGhlcmUgbWlnaHQgYmUgYSBzaXR1YXRpb24gd2hlcmUgeW91J3ZlIHVzZWQgUiB0byBhdXRvbWF0ZSB0aGUgcHJvZHVjdGlvbiBvZiBtdWx0aXBsZSBwbG90cywgYW5kIHlvdSdkIGxpa2UgdG8gaW5jbHVkZSBhIHNhdmUgZnVuY3Rpb24gd2l0aGluIHRoZSBjb2RlIGl0c2VsZi4gWW91IGNhbiBkbyB0aGlzIGZhaXJseSBzaW1wbHkgd2l0aCB0aGUgYGdnc2F2ZSgpYCBmdW5jdGlvbiwgd2hpY2ggYmFzaWNhbGx5IGRvZXMgd2hhdCBpdCBzYXlzIG9uIHRoZSB0aW4uCgpZb3UgZ2l2ZSB0aGUgZnVuY3Rpb24gYSBuYW1lIGFuZCBhIGZpbGUgZXh0ZW5zaW9uIGluIHRoZSBmb3JtIG9mICJteV9wbG90LnBuZyIgZm9yIGV4YW1wbGUsIGFuZCBSIHdpbGwgc2F2ZSBpdCBpbnRvIHlvdXIgd29ya2luZyBkaXJlY3RvcnkuIFRyeSB0aGUgZm9sbG93aW5nCgpgYGB7cn0KZ2dzYXZlKG15X3Bsb3QucG5nKQpgYGAKYW5kIHlvdSBzaG91bGQgc2VlIHRoYXQgUiBoYXMgc2F2ZWQgeW91ciBwbG90IGludG8geW91ciBwcm9qZWN0IGZvbGRlci4gWW91IGNhbiB0ZXN0IHRoaXMgYnkgbmF2aWdhdGluZyB0byB5b3VyIGZpbGUgdHJlZSBpbiBSc3R1ZGlvIGFuZCBjbGlja2luZyBvbiB0aGUgbmV3bHkgc2F2ZWQgcGxvdCB0byBvcGVuIGl0LiBIZWxwZnVsbHksIFIgd2lsbCBpbnRlcnByZXQgdGhlIC5zdWZmaXggYXMgYSBmaWxlIGZvcm1hdCwgc28geW91IGNhbiBjaGFuZ2UgdGhpcyBhdCB3aWxsIC0gcGVyaGFwcyB5b3Ugd2FudCBhIC50aWZmIG9yIGEgLnBkZiBmaWxlIC0ganVzdCBjaGFuZ2UgdGhlIHN1ZmZpeCBhbmQgUiB3aWxsIGRvIHRoaXMgZm9yIHlvdS4gCgpBIG5vdGUgb24gZGltZW5zaW9ucyAtIFIgd2lsbCBhdXRvbWF0aWNhbGx5IGV4cG9ydCBhIHBsb3Qgd2l0aCB0aGUgZGltZW5zaW9ucyBvZiB0aGUgcGxvdCB3aW5kb3cgLSB5b3UgY2FuIGVpdGhlciBjaGFuZ2UgdGhhdCBieSBtYW51YWxseSBhZGp1c3RpbmcgdGhlc2UsIG9yIGJ5IGhhcmQtY29kaW5nIHNvbWUgZGltZW5zaW9ucyBpbnRvIHRoZSBgZ2dzYXZlKClgIGZ1bmN0aW9uIC0gaGF2ZSBhIGxvb2sgYXQgdGhlIGA/Z2dzYXZlYCBoZWxwIGZpbGVzIHRvIGZpbmQgb3V0IG1vcmUhCgojIyBDdXN0b21pc2F0aW9uCgpUaGVyZSBhcmUgbG9hZHMgb2Ygd2F5cyB0byBjdXN0b21pc2UgeW91ciBSIHBsb3RzLCB0aGF0IHdlIGRvbid0IGhhdmUgdGltZSB0byBkaXNjdXNzIG5vdywgYnV0IGEgcXVpY2sgZ29vZ2xlIHdpbGwgc2hvdyB5b3UgdGhhdCB0aGVyZSBhcmUgZW5kbGVzcyBwb3NzaWJpbGl0aWVzIC0gZ28gYXdheSBhbmQgaGF2ZSBmdW4hCgojIEFuZCBmaW5hbGx5Li4uCgpTbywgd2UndmUgbGVhcm5lZCBhIGJpdCBhYm91dCB0aGUgcGhpbG9zb3BoaWVzIGFuZCBhcHByb2FjaGVzIHRvIHVzaW5nIFIsIGFuZCBsb29rZWQgYXQgbW9yZSBhZHZhbmNlZCB3YXlzIG9mIGhhbmRsaW5nIGRhdGEgd2l0aCBgZHBseXJgLiBXZSd2ZSBnYWluZWQgc29tZSBoYW5kcy1vbiBleHBlcmllbmNlIHdpdGggdXNpbmcgYGdncGxvdDJgIHRvIHByb2R1Y2UgcGxvdHMuCg==