Topic 2B: Data Visualisation I
Welcome to the second computer lab for the Data Science stream of STM1001.
In this computer lab we will create some informative, interactive data visualisations, using the penguins
data set from the palmerpenguins
package (Horst, Hill, and Gorman 2020) , and a new package,plotly
(Sievert 2020).
The types of plots we consider in this lab were introduced in
Topic 1 and Topic 2.
By the end of this lab, you should feel comfortable creating interactive histograms and scatter plots in RStudio.
🎧 Reminder: Online students
Throughout the computer lab question sheets, you will see emojis and/or collapsible sections like this one. Each emoji has a particular meaning and will sometimes be associated with additional instructions:
Prompts for you
💬 Write your answer in the chat.
Modes at different times during the lab
🏡 Main room. All together in the main room – your computer lab demonstrator will be presenting information or facilitating class discussion
💡 Breakout rooms. Person with birthday closest to (your computer lab demonstrator will pick a random date) shares their screen or whiteboard. Here you will discuss a question together and bring your group’s answer back to the main room.
💻 Focus mode. You will still be in the main room, but working independently. All students will be sharing screen during this time so that your computer lab demonstrator (but not other students) can see your screen.
🏫 Reminder: Face-to-face (blended) students
Throughout the computer lab question sheets, you will see emojis and/or collapsible sections like this one. You can ignore the emojis and collapsible sections, as they contain information relevant to students who are studying online.
Palmer Penguins Data Set
🏡 Let’s quickly refresh our memories of the penguins
data set from the palmerpenguins
R package (Horst, Hill, and Gorman 2020).
This data set contains information on 3 species of penguin, who live on different islands in the Palmer archipelago, off the coast of Antarctica. For more details, you can refer to Section 2 of the Data Visualisation in R supplement.
🏡 To begin, make sure you have the palmerpenguins
R package installed in RStudio.
Note: If you do not have the palmerpenguins
package downloaded, just click on the Code
box below, and run the code that appears:
install.packages("palmerpenguins")
🏡 Run the following code to load the palmerpenguins
R package, and to summarise the penguins
data set.
Note: The package is called palmerpenguins
, but once this is loaded, the actual data to access in R is stored in the object penguins
.
# Load the `palmerpenguins` package into your current R working environment.
library(palmerpenguins)
# Summarise the `penguins` data in the `palmerpenguins` package.
summary(penguins)
We don’t need to spend much time assessing this summary - the main things to note at this stage are the different variables, namely species
, island
, bill_length_mm
, bill_depth_mm
, flipper_length_mm
, body_mass_g
, sex
and year
.
Creating Interactive Histograms in RStudio
💻 Suppose that we are interested in the distribution of recorded body masses (in grams) of the penguins living in the Palmer Archipelago. To visualise this distribution using the penguins
data, we can produce a histogram.
Note: Refer to Section 3.2 of Topic 1 for details on histograms.
Recall that we can create a simple histogram using the built-in R function hist
:
hist(penguins$body_mass_g, breaks = 19)

This histogram is static, meaning that we cannot interact with the image, and we cannot manipulate it in real time to display different details - perhaps, for example, we would like to see the distribution of the penguins’ body_mass_g
values, but only for the penguins on a specific island.
To achieve these objectives using just the hist
function would take some extensive coding.
💻 As an alternative to the built-in hist
function, we could use the plot_ly
function from the plotly
package to create an interactive, responsive histogram. Let’s take a look at how to do this now.
To begin, just as for the previous packages, we will need to download and load the plotly
package in RStudio, before we can use any plotly
functions.
Run the code below to install and load the plotly
package.
install.packages("plotly")
library(plotly)
💻 To create plotly
plots, we use the function plot_ly()
.
Run the code below to create and store an interactive histogram of the the penguins’ body_mass_g
values in the object penguin_hist_base
.
At this point, don’t worry about the composition of this function - we’ll cover this in more detail shortly.
- For the moment, take a look at the code below, and see if you can get a general idea of what’s going on.
penguin_hist_base <- plot_ly(data = penguins,
x = ~body_mass_g,
type = "histogram")
penguin_hist_base <- penguin_hist_base %>% layout(yaxis = list(title = 'count'))
❓Note
Once you have taken some time to consider the code above, if you would like more details or would like to check the accuracy of your interpretation, click the Show
button below for a brief explanation.
# Here, we are creating a plotly object called "penguin_hist_base"
penguin_hist_base <- plot_ly(data = penguins, # We are using the penguins data
x = ~body_mass_g, # and modelling the body_mass_g data
type = "histogram") # in a histogram format
# The code below is used to modify the layout of the histogram
# to include a label for the y-axis
penguin_hist_base <- penguin_hist_base %>% layout(yaxis = list(title = 'count'))
💻 The plotly
histogram has now been created, but won’t appear until we call the object in which it was stored. If you run the code below, your plotly
histogram (as shown below) should appear in the Viewer
section of RStudio.
penguin_hist_base
💻 Unlike graphs created using base R functions, plotly
graphs are interactive - even when embedded in web pages like this one!
Try the following:
- If you hover over the histogram in 2.3, you can see the specific details of the data.
- If you left-click and drag your cursor over a section of the histogram to create a box, you can also zoom in on a particular section of the plot. Just double left-click to zoom back out.
💻 Perhaps you are not impressed with plotly
yet. After all, our histogram in 2.3 doesn’t look that different to the hist
function version we created at the start of 2, so what is all the fuss about?
Well, it is very easy to modify our plot_ly
histogram to show extra detail. For example, we can easily produce separate histograms for the penguins on each island. Take a look at the R code below, which builds upon what we used in penguin_hist_base
.
penguin_hist <- plot_ly(data = penguins,
x = ~body_mass_g,
color = ~island,
type = "histogram", alpha = 0.6)
penguin_hist <- penguin_hist %>% layout(yaxis = list(title = 'count'),
barmode ="overlay")
Before you move on to the next question, run this code in RStudio.
❓Note
Once you have taken some time to consider the code above, if you would like more details or would like to check the accuracy of your interpretation, click the Show
button below for a brief explanation.
# Here, we are creating a plotly object called "penguin_hist"
penguin_hist <- plot_ly(data = penguins, # We are using the penguins data
x = ~body_mass_g, # and modelling the body_mass_g data
color = ~island, type = "histogram", alpha = 0.6)
# We are producing a histogram for this data, with points coloured differently,
# depending on the island on which the penguin is located
# The code below is used to modify the layout of the histogram
# This includes adding a label to the y-axis
# and setting the histograms to be layered over each other
# (hence the alpha = 0.6 above to change the opacity)
penguin_hist <- penguin_hist %>% layout(yaxis = list(title = 'count'),
barmode ="overlay")
💻 To produce this updated plotly
histogram, run the R code below. Your new histogram (as shown below) should appear in the Viewer
section of RStudio.
penguin_hist
This is looking better than our previous histogram! Because we have told our plot_ly
function to assign different colours to the different islands, we now have three histograms, rather than one with all the data clumped together.
Even better, these are all presented within the one graph, which also includes a handy legend. Hopefully you are now beginning to appreciate the additional functionality offered by plotly
over built-in R functions.
Note: For more details on plotly
, you can refer to Section 3 of the Data Visualisation in R supplement.
💻 Finally, and perhaps most importantly for this specific example, it is important to note that we can dynamically filter results in plotly
graphs. For this example, we can filter observations to focus on data from a specific island. Simply click on one of the lines in the legend in the top right of our histogram in 2.6, to temporarily remove that data from assessment (note that the axes dynamically adjust too).
Try focusing just on the Dream island penguins.
Hint: To bring the removed data back, simply click once more on the relevant line in the legend.
🎧 Online students
💬 Leave a comment in the chat about your favourite aspect of the interactive plotly graphs so far.
🏡 Reconvene in main room to discuss results
Creating Interactive Scatter Plots in RStudio
💻 From our summary table in 1.2, we can see that the measurement variables in the penguins
data set include body_mass_g
and flipper_length_mm
.
It seems reasonable to assume that penguins with larger body masses might also have longer flippers.
To visualise the observations for these variables, and check our assumption, we could use a scatter plot. To create this scatter plot, we will again use the plotly
package, as it offers several benefits over using the default plotting options in R.
Note: Refer to Section 5.1 of Topic 2 for details on scatter plots.
💻 To create an interactive plotly
plot we need to use the function plot_ly()
. In 2.2, we brushed over the details of the plot_ly()
function, so let’s remedy that now.
The typical composition of a simple plotly
plot looks like this:
plot_name <- plot_ly(data = ..., x = ~ ..., y = ~ ...)
Let’s break this down:
- Firstly, (using the assignment operator
<-
) we assign a name to our plot - here we have chosen the generic plot_name
.
- Next, within
plotly()
, we specify the main arguments of the function.
- The
data = ...
part tells R what data we are analysing.
- The
x = ~ ...
part tells R which variable in our data set to plot on the x-axis of our plot.
- The
y = ~ ...
part tells R which variable in our data set to plot on the y-axis of our plot.
Note: We simply replace the ...
s with whatever data we are using.
💻 Run the code below to create a simple scatter plot of the recorded flipper_length_mm
versus body_mass_g
values in the penguins
data set (as shown below). Make sure to inspect this code, and check that you understand each component.
Note that since we have specified our data set is penguins
in the code, we don’t then need to do this when specifying our x
and y
inputs - we can simply specify any of the variables contained within this data set.
penguins_scatter <- plot_ly(data = penguins,
x = ~body_mass_g, y = ~flipper_length_mm)
penguins_scatter
Note: Once we assign the plot to the object penguins_scatter
, we then have to run this object in a subsequent line, in order for the plot to be rendered.
💻 As we suspected, it seems quite clear from the scatter plot above in 3.2 that, in general, as the body mass of penguins increases so too does their flipper length.
But our graph is quite basic at the moment - we can do better.
It is very easy to include a third variable in a plotly
graph, which can help to further distinguish the data plotted on the x
and y
axes. We can do so by adding the argument color = ~...
within plotly()
.
Perhaps the body_mass_g
and flipper_length_mm
of the penguins is also related to their sex
?
Let’s take a look at how our scatter plot changes, if we distinguish between male and female penguins.
penguins_scatter2 <- plot_ly(data = penguins,
x = ~body_mass_g, y = ~flipper_length_mm,
color = ~sex)
penguins_scatter2
That’s looking a bit nicer! Now we can see that the smallest penguins tend to be female, and the largest penguins tend to be male. If you hover over the data, you’ll notice that the sex
is now shown alongside the coordinates of each data point.
We also have a helpful legend in the top right. Remember, this is not only useful as a guide - try clicking on one of the labels in the legend.
💻 While our scatter plot is looking better, the default colours chosen to distinguish between male and female penguins are quite similar. Perhaps we would like more contrast?
To specify the set of colours to use for the plot, we can add the additional argument colors = ...
to our plot_ly
function. This argument accepts any valid R colour codes. Take a look at this pdf for an overview of different colours we can use, or simply try a few basic colours like red, green etc.
Complete and then run the code below to change the colours you use in your scatter plot.
penguins_scatter_colours <- plot_ly(data = penguins,
x = ~body_mass_g, y = ~flipper_length_mm,
color = ~sex, colors = ...)
penguins_scatter_colours
❓Hint
You will need a combination of two colours. Check the Show
box below if you are stuck.
# If you are specifying specific individual colours, you will need to use the layout
colors = c("...", "...")
# within the plot_ly() function
💻 If you do not want to spend too much time customising the colours used in your plots, there are pre-existing sets of colours you can use. Try setting your colors =...
argument in 3.4 sequentially to colors = "Set1"
, then to colors = "Set2"
and finally to colors = "Set3"
. Do any particular sets appeal to you?
🎧 Online students
💬 Post your colour choice(s) in the chat.
💻 There are many different display options for plot_ly
graphics. If you try running the R commands below, you may see some red Warning messages appear in the RStudio Console
section. As discussed in Computer Lab 1B, while it is important to read them, often you don’t have to worry about these.
penguins_scatter2 <- plot_ly(data = penguins, x = ~body_mass_g, y = ~flipper_length_mm,
color = ~sex, colors = "Set1")
penguins_scatter2
In this instance, if you would like to minimise warning messages, you can add the arguments type = "scatter", mode = "markers"
to your plot_ly
function, so that your code now looks like this:
penguins_scatter2 <- plot_ly(data = penguins, x = ~body_mass_g, y = ~flipper_length_mm,
color = ~sex, colors = "Set1",
type = "scatter", mode = "markers")
penguins_scatter2
Here:
- We set
type = "scatter"
to ensure our data is plotted as a scatter plot.
- We set
mode = "markers"
to ensure that each of our data points is plotted individually.
These additional arguments are often helpful, as sometimes we like to have a little more control over how our data is presented.
You’ll notice however that if these commands are omitted from your function, R will just work out what it thinks is the optimal presentation format (hence the warning messages informing us which options have been selected, since some details haven’t been user-specified).
This automatic selection is often for the best - try changing the mode = "markers"
section of code above to mode ="lines"
and then re-running the code chunk. What happens?
💻 So far, we have treated all the penguins as one large group, differentiated by sex
.
When we hover over a point in our scatter plot (representing a penguin), we see the flipper length, body mass, and sex details for that penguin. This is great, but we are missing one important piece of information - the species of penguin! Remember, we actually have data for three separate species
of penguin - Adelie
, Chinstrap
, and Gentoo
.
Fortunately, it is straightforward to add this information to the hover text of our plot. We can do this by including the argument text = ~species
in our code, in a similar way to how we have used color = ~sex
to colour the points.
Update your penguins_scatter2
plot with this text = ~species
addition now, and hover over some points to check that your code has worked as intended.
💻 We have already used different colours to differentiate the male and female penguins, but all the data points are the same symbol - a dot.
Instead of including the argument text = ~species
, we can use the additional argument symbol = ...
within our plot_ly
function to distinguish between the different species
of penguin.
Take a look at the R code and resultant graph below:
penguins_scatter3 <- plot_ly(data = penguins, x = ~body_mass_g, y = ~flipper_length_mm,
color = ~sex, colors = "Set1", symbol = ~species,
type = "scatter", mode = "markers")
penguins_scatter3
Great! This is looking much more informative than our initial scatter plot in 3.2.
Now it’s quite clear, for instance, that the majority of larger penguins (both male and female) are of the Gentoo
species, which we couldn’t discern from our initial versions of this scatter plot.
💻 There are 26 different base R symbols you can choose from - these can be specified either by number, or by name. Since we have not specified which specific symbols to use in 3.8, R has used the first default 3.
We used colors = ...
to modify our color = ...
specification, and similarly, we can use symbols = ...
to modify our symbol = ...
specification.
Some of the symbol names are quite long, e.g. "filled triangle point-up"
, so it is often easier to use numbers. The table below lists some of the available options:
Table 3.1: Symbol Options
Number |
Name |
0 |
square |
1 |
circle |
2 |
triangle point up |
3 |
plus |
4 |
cross |
5 |
diamond |
8 |
star |
Using 3.1 and the symbols = ...
argument, change the symbols used in the penguins_scatter3
scatter plot created in 3.8.
❓Hint
If you are using symbol names, and your code isn’t working, check the code chunk below.
# Note that just like for the colours argument, if you are using words,
# these need to be surrounded with quotation marks,
# e.g. "square", or 'square' will work, but square will not
🎧 Online students
💬 Post your symbol choice(s) in the chat.
💻 As a final touch, you may also like to change the size of the symbols in your scatter plot.
To do so, we can include the marker = ...
argument in our plot_ly
function.
This is a little more complicated to use than our previous arguments, as multiple specifications can be made within this argument. As a result, we use the format marker = list(...)
. Within the list()
function, we can include multiple specifications which all pertain to the marker
argument. To change the size of the symbols, we use the appropriately named size =
argument, within the list()
function.
For example, if we want to change the default marker size (6) to be a little larger, we could include the argument
marker = list(size = 8)
within our plot_ly
function for our penguins_scatter3
scatter plot created in 3.8.
Try this now, observe the changes, and then try increasing and decreasing the marker size.
We have now covered the basics of creating plotly
histograms and scatter plots, well done!
🏡 Reconvene in main room to discuss results
LS0tDQp0aXRsZTogIlNUTTEwMDE6IENvbXB1dGVyIExhYiAyQiINCm91dHB1dDoNCiAgYm9va2Rvd246Omh0bWxfZG9jdW1lbnQyOiANCiAgICB0b2M6IHRydWUNCiAgICB0b2NfZmxvYXQ6IHRydWUNCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQogICAgdGhlbWU6IHJlYWRhYmxlDQogICAgY29kZV9mb2xkaW5nOiBzaG93DQpiaWJsaW9ncmFwaHk6IFNUTTEwMDFfRFNfQ0xfcmVmZXJlbmNlcy5iaWIgDQpsaW5rLWNpdGF0aW9uczogeWVzDQotLS0NCg0KPHN0eWxlPg0KI1RPQyB7DQogIGJhY2tncm91bmQ6IHVybCgiaHR0cHM6Ly93d3cubGF0cm9iZS5lZHUuYXUvX21lZGlhL2xhLXRyb2JlLWFwaS92NS9pbWcvbG9nby5zdmciKTsNCiAgYmFja2dyb3VuZC1zaXplOiBjb250YWluOw0KICBwYWRkaW5nLXRvcDogODBweCAhaW1wb3J0YW50Ow0KICBiYWNrZ3JvdW5kLXJlcGVhdDogbm8tcmVwZWF0Ow0KfQ0KPC9zdHlsZT4NCg0KIyMjIERhdGEgU2NpZW5jZSBTdHJlYW0gey19DQoNCiMjIyBUb3BpYyAyQjogRGF0YSBWaXN1YWxpc2F0aW9uIEkgey19DQoNCjxicj4NCg0KV2VsY29tZSB0byB0aGUgc2Vjb25kIGNvbXB1dGVyIGxhYiBmb3IgdGhlIERhdGEgU2NpZW5jZSBzdHJlYW0gb2YgU1RNMTAwMS4NCg0KSW4gdGhpcyBjb21wdXRlciBsYWIgd2Ugd2lsbCBjcmVhdGUgc29tZSBpbmZvcm1hdGl2ZSwgaW50ZXJhY3RpdmUgZGF0YSB2aXN1YWxpc2F0aW9ucywgdXNpbmcgdGhlIGBwZW5ndWluc2AgZGF0YSBzZXQgZnJvbSB0aGUgYHBhbG1lcnBlbmd1aW5zYCBwYWNrYWdlIFtAcGVuZ3VpbnNdICwgYW5kIGEgbmV3IHBhY2thZ2UsYHBsb3RseWAgW0BwbG90bHldLg0KDQpUaGUgdHlwZXMgb2YgcGxvdHMgd2UgY29uc2lkZXIgaW4gdGhpcyBsYWIgd2VyZSBpbnRyb2R1Y2VkIGluIA0KW1RvcGljIDFdKGh0dHBzOi8vYm9va2Rvd24ub3JnL2Ffc2hha2VyL1NUTTEwMDFfVG9waWNfMS8pIGFuZCBbVG9waWMgMl0oaHR0cHM6Ly9ib29rZG93bi5vcmcvYV9zaGFrZXIvU1RNMTAwMV9Ub3BpY18yLykuDQoNCkJ5IHRoZSBlbmQgb2YgdGhpcyBsYWIsIHlvdSBzaG91bGQgZmVlbCBjb21mb3J0YWJsZSBjcmVhdGluZyBpbnRlcmFjdGl2ZSBoaXN0b2dyYW1zIGFuZCBzY2F0dGVyIHBsb3RzIGluIFJTdHVkaW8uDQoNCjxicj4NCg0KPGRldGFpbHM+DQogIDxzdW1tYXJ5PmByIGVtbzo6amkoImhlYWRwaG9uZXMiKWAgKipSZW1pbmRlcjogT25saW5lIHN0dWRlbnRzKio8L3N1bW1hcnk+DQpUaHJvdWdob3V0IHRoZSBjb21wdXRlciBsYWIgcXVlc3Rpb24gc2hlZXRzLCB5b3Ugd2lsbCBzZWUgZW1vamlzIGFuZC9vciBjb2xsYXBzaWJsZSBzZWN0aW9ucyBsaWtlIHRoaXMgb25lLiBFYWNoIGVtb2ppIGhhcyBhIHBhcnRpY3VsYXIgbWVhbmluZyBhbmQgd2lsbCBzb21ldGltZXMgYmUgYXNzb2NpYXRlZCB3aXRoIGFkZGl0aW9uYWwgaW5zdHJ1Y3Rpb25zOg0KDQoqKlByb21wdHMgZm9yIHlvdSoqDQoNCmByIGVtbzo6amkoInNwZWVjaF9iYWxsb29uIilgIFdyaXRlIHlvdXIgYW5zd2VyIGluIHRoZSBjaGF0Lg0KDQoqKk1vZGVzIGF0IGRpZmZlcmVudCB0aW1lcyBkdXJpbmcgdGhlIGxhYioqDQoNCmByIGVtbzo6amkoImhvdXNlX3dpdGhfZ2FyZGVuIilgICoqTWFpbiByb29tKiouIEFsbCB0b2dldGhlciBpbiB0aGUgbWFpbiByb29tIOKAkyB5b3VyIGNvbXB1dGVyIGxhYiBkZW1vbnN0cmF0b3Igd2lsbCBiZSBwcmVzZW50aW5nIGluZm9ybWF0aW9uIG9yIGZhY2lsaXRhdGluZyBjbGFzcyBkaXNjdXNzaW9uDQoNCmByIGVtbzo6amkoImJ1bGIiKWAgKipCcmVha291dCByb29tcyoqLiBQZXJzb24gd2l0aCBiaXJ0aGRheSBjbG9zZXN0IHRvICh5b3VyIGNvbXB1dGVyIGxhYiBkZW1vbnN0cmF0b3Igd2lsbCBwaWNrIGEgcmFuZG9tIGRhdGUpIHNoYXJlcyB0aGVpciBzY3JlZW4gb3Igd2hpdGVib2FyZC4gSGVyZSB5b3Ugd2lsbCBkaXNjdXNzIGEgcXVlc3Rpb24gdG9nZXRoZXIgYW5kIGJyaW5nIHlvdXIgZ3JvdXAncyBhbnN3ZXIgYmFjayB0byB0aGUgbWFpbiByb29tLg0KDQpgciBlbW86OmppKCJjb21wdXRlciIpYCAqKkZvY3VzIG1vZGUqKi4gWW91IHdpbGwgc3RpbGwgYmUgaW4gdGhlIG1haW4gcm9vbSwgYnV0IHdvcmtpbmcgaW5kZXBlbmRlbnRseS4gQWxsIHN0dWRlbnRzIHdpbGwgYmUgc2hhcmluZyBzY3JlZW4gZHVyaW5nIHRoaXMgdGltZSBzbyB0aGF0IHlvdXIgY29tcHV0ZXIgbGFiIGRlbW9uc3RyYXRvciAoYnV0IG5vdCBvdGhlciBzdHVkZW50cykgY2FuIHNlZSB5b3VyIHNjcmVlbi4gDQoNCjwvZGV0YWlscz4gDQoNCjxicj4NCg0KPGRldGFpbHM+DQogIDxzdW1tYXJ5PmByIGVtbzo6amkoInNjaG9vbCIpYCAqKlJlbWluZGVyOiBGYWNlLXRvLWZhY2UgKGJsZW5kZWQpIHN0dWRlbnRzKio8L3N1bW1hcnk+DQpUaHJvdWdob3V0IHRoZSBjb21wdXRlciBsYWIgcXVlc3Rpb24gc2hlZXRzLCB5b3Ugd2lsbCBzZWUgZW1vamlzIGFuZC9vciBjb2xsYXBzaWJsZSBzZWN0aW9ucyBsaWtlIHRoaXMgb25lLiBZb3UgY2FuIGlnbm9yZSB0aGUgZW1vamlzIGFuZCBjb2xsYXBzaWJsZSBzZWN0aW9ucywgYXMgdGhleSBjb250YWluIGluZm9ybWF0aW9uIHJlbGV2YW50IHRvIHN0dWRlbnRzIHdobyBhcmUgc3R1ZHlpbmcgb25saW5lLg0KDQo8L2RldGFpbHM+IA0KDQo8YnI+DQoNCiMgUGFsbWVyIFBlbmd1aW5zIERhdGEgU2V0IHsjcGVuZ3VpbnN9DQoNCmByIGVtbzo6amkoImhvdXNlX3dpdGhfZ2FyZGVuIilgIExldCdzIHF1aWNrbHkgcmVmcmVzaCBvdXIgbWVtb3JpZXMgb2YgdGhlIGBwZW5ndWluc2AgZGF0YSBzZXQgZnJvbSB0aGUgYHBhbG1lcnBlbmd1aW5zYCBSIHBhY2thZ2UgW0BwZW5ndWluc10uIA0KVGhpcyBkYXRhIHNldCBjb250YWlucyBpbmZvcm1hdGlvbiBvbiAzIHNwZWNpZXMgb2YgcGVuZ3Vpbiwgd2hvIGxpdmUgb24gZGlmZmVyZW50IGlzbGFuZHMgaW4gdGhlIFBhbG1lciBhcmNoaXBlbGFnbywgb2ZmIHRoZSBjb2FzdCBvZiBBbnRhcmN0aWNhLiBGb3IgbW9yZSBkZXRhaWxzLCB5b3UgY2FuIHJlZmVyIHRvIFtTZWN0aW9uIDIgb2YgdGhlIERhdGEgVmlzdWFsaXNhdGlvbiBpbiBSIHN1cHBsZW1lbnRdKGh0dHBzOi8vYm9va2Rvd24ub3JnL3JlaGsvc3RtMTAwMV9kc21fZGF0YV92aXN1YWxpc2F0aW9uX2luX3IvcGVuZ3VpbnMuaHRtbCkuDQoNCiMjDQoNCmByIGVtbzo6amkoImhvdXNlX3dpdGhfZ2FyZGVuIilgIFRvIGJlZ2luLCBtYWtlIHN1cmUgeW91IGhhdmUgdGhlIGBwYWxtZXJwZW5ndWluc2AgUiBwYWNrYWdlIGluc3RhbGxlZCBpbiBSU3R1ZGlvLg0KDQoqTm90ZTogSWYgeW91IGRvIG5vdCBoYXZlIHRoZSBgcGFsbWVycGVuZ3VpbnNgIHBhY2thZ2UgZG93bmxvYWRlZCwganVzdCBjbGljayBvbiB0aGUgYENvZGVgIGJveCBiZWxvdywgYW5kIHJ1biB0aGUgY29kZSB0aGF0IGFwcGVhcnM6Kg0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1oaWRlIiwgZXZhbCA9IEYsIGVjaG8gPSBUfQ0KaW5zdGFsbC5wYWNrYWdlcygicGFsbWVycGVuZ3VpbnMiKQ0KYGBgDQoNCiMjIHsjc3VtbWFyeWluZm99DQoNCmByIGVtbzo6amkoImhvdXNlX3dpdGhfZ2FyZGVuIilgIFJ1biB0aGUgZm9sbG93aW5nIGNvZGUgdG8gbG9hZCB0aGUgYHBhbG1lcnBlbmd1aW5zYCBSIHBhY2thZ2UsIGFuZCB0byBzdW1tYXJpc2UgdGhlIGBwZW5ndWluc2AgZGF0YSBzZXQuDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gVCwgZWNobyA9IEYsIGluY2x1ZGUgPSBGfQ0KbGlicmFyeShwYWxtZXJwZW5ndWlucykNCmBgYA0KDQoqTm90ZTogVGhlIHBhY2thZ2UgaXMgY2FsbGVkIGBwYWxtZXJwZW5ndWluc2AsIGJ1dCBvbmNlIHRoaXMgaXMgbG9hZGVkLCB0aGUgYWN0dWFsIGRhdGEgdG8gYWNjZXNzIGluIFIgaXMgc3RvcmVkIGluIHRoZSBvYmplY3QgYHBlbmd1aW5zYC4qDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gRiwgZWNobyA9IFR9DQojIExvYWQgdGhlIGBwYWxtZXJwZW5ndWluc2AgcGFja2FnZSBpbnRvIHlvdXIgY3VycmVudCBSIHdvcmtpbmcgZW52aXJvbm1lbnQuDQpsaWJyYXJ5KHBhbG1lcnBlbmd1aW5zKQ0KIyBTdW1tYXJpc2UgdGhlIGBwZW5ndWluc2AgZGF0YSBpbiB0aGUgYHBhbG1lcnBlbmd1aW5zYCBwYWNrYWdlLg0Kc3VtbWFyeShwZW5ndWlucykNCmBgYA0KDQpXZSBkb24ndCBuZWVkIHRvIHNwZW5kIG11Y2ggdGltZSBhc3Nlc3NpbmcgdGhpcyBzdW1tYXJ5IC0gdGhlIG1haW4gdGhpbmdzIHRvIG5vdGUgYXQgdGhpcyBzdGFnZSBhcmUgdGhlIGRpZmZlcmVudCB2YXJpYWJsZXMsIG5hbWVseSBgc3BlY2llc2AsIGBpc2xhbmRgLCBgYmlsbF9sZW5ndGhfbW1gLCBgYmlsbF9kZXB0aF9tbWAsIGBmbGlwcGVyX2xlbmd0aF9tbWAsIGBib2R5X21hc3NfZ2AsIGBzZXhgIGFuZCBgeWVhcmAuDQoNCiMgQ3JlYXRpbmcgSW50ZXJhY3RpdmUgSGlzdG9ncmFtcyBpbiBSU3R1ZGlvIHsjaGlzdHN0YXJ0fQ0KDQpgciBlbW86OmppKCJjb21wdXRlciIpYCBTdXBwb3NlIHRoYXQgd2UgYXJlIGludGVyZXN0ZWQgaW4gdGhlIGRpc3RyaWJ1dGlvbiBvZiByZWNvcmRlZCBib2R5IG1hc3NlcyAoaW4gZ3JhbXMpIG9mIHRoZSBwZW5ndWlucyBsaXZpbmcgaW4gdGhlIFBhbG1lciBBcmNoaXBlbGFnby4gVG8gdmlzdWFsaXNlIHRoaXMgZGlzdHJpYnV0aW9uIHVzaW5nIHRoZSBgcGVuZ3VpbnNgIGRhdGEsIHdlIGNhbiBwcm9kdWNlIGEgKipoaXN0b2dyYW0qKi4NCg0KKk5vdGU6IFJlZmVyIHRvIFtTZWN0aW9uIDMuMiBvZiBUb3BpYyAxXShodHRwczovL2Jvb2tkb3duLm9yZy9hX3NoYWtlci9TVE0xMDAxX1RvcGljXzEvMy4yLWhpc3RvZ3JhbXMuaHRtbCkgZm9yIGRldGFpbHMgb24gaGlzdG9ncmFtcy4qDQoNClJlY2FsbCB0aGF0IHdlIGNhbiBjcmVhdGUgYSBzaW1wbGUgaGlzdG9ncmFtIHVzaW5nIHRoZSBidWlsdC1pbiBSIGZ1bmN0aW9uIGBoaXN0YDoNCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gVH0NCmhpc3QocGVuZ3VpbnMkYm9keV9tYXNzX2csIGJyZWFrcyA9IDE5KQ0KYGBgDQoNClRoaXMgaGlzdG9ncmFtIGlzIHN0YXRpYywgbWVhbmluZyB0aGF0IHdlIGNhbm5vdCBpbnRlcmFjdCB3aXRoIHRoZSBpbWFnZSwgYW5kIHdlIGNhbm5vdCBtYW5pcHVsYXRlIGl0IGluIHJlYWwgdGltZSB0byBkaXNwbGF5IGRpZmZlcmVudCBkZXRhaWxzIC0gcGVyaGFwcywgZm9yIGV4YW1wbGUsICB3ZSB3b3VsZCBsaWtlIHRvIHNlZSB0aGUgZGlzdHJpYnV0aW9uIG9mIHRoZSBwZW5ndWlucycgYGJvZHlfbWFzc19nYCB2YWx1ZXMsIGJ1dCBvbmx5IGZvciB0aGUgcGVuZ3VpbnMgb24gYSBzcGVjaWZpYyBpc2xhbmQuIA0KDQpUbyBhY2hpZXZlIHRoZXNlIG9iamVjdGl2ZXMgdXNpbmcganVzdCB0aGUgYGhpc3RgIGZ1bmN0aW9uIHdvdWxkIHRha2Ugc29tZSBleHRlbnNpdmUgY29kaW5nLg0KDQo8IS0tIFdpdGhvdXQgdXNpbmcgYWRkaXRpb25hbCBwYWNrYWdlcywgd2Ugd291bGQgbmVlZCB0byBkbyBzb21lIGV4dGVuc2l2ZSBjb2RpbmcgdG8gcHJvZHVjZSBzdWNoIGEgaGlzdG9ncmFtLiBFdmVuIHRoZW4sIGlmIHdlIHdvdWxkIGxpa2UgdG8gaGF2ZSBzaW1pbGFyIGhpc3RvZ3JhbXMgZm9yIHRoZSBvdGhlciB0d28gaXNsYW5kcywgdGhpcyB3b3VsZCBtZWFuIGZ1cnRoZXIgY29kaW5nLiAtLT4NCg0KIyMgDQoNCmByIGVtbzo6amkoImNvbXB1dGVyIilgIEFzIGFuIGFsdGVybmF0aXZlIHRvIHRoZSBidWlsdC1pbiBgaGlzdGAgZnVuY3Rpb24sIHdlIGNvdWxkIHVzZSB0aGUgYHBsb3RfbHlgIGZ1bmN0aW9uIGZyb20gdGhlIGBwbG90bHlgIHBhY2thZ2UgIHRvIGNyZWF0ZSBhbiBpbnRlcmFjdGl2ZSwgcmVzcG9uc2l2ZSBoaXN0b2dyYW0uIExldCdzIHRha2UgYSBsb29rIGF0IGhvdyB0byBkbyB0aGlzIG5vdy4gDQoNClRvIGJlZ2luLCBqdXN0IGFzIGZvciB0aGUgcHJldmlvdXMgcGFja2FnZXMsIHdlIHdpbGwgbmVlZCB0byBkb3dubG9hZCBhbmQgbG9hZCB0aGUgYHBsb3RseWAgcGFja2FnZSBpbiBSU3R1ZGlvLCBiZWZvcmUgd2UgY2FuIHVzZSBhbnkgYHBsb3RseWAgZnVuY3Rpb25zLg0KDQpSdW4gdGhlIGNvZGUgYmVsb3cgdG8gaW5zdGFsbCBhbmQgbG9hZCB0aGUgYHBsb3RseWAgcGFja2FnZS4NCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBGLCBlY2hvID0gRiwgaW5jbHVkZSA9IEZ9DQppbnN0YWxsLnBhY2thZ2VzKHNldGRpZmYoInBsb3RseSIsIHJvd25hbWVzKGluc3RhbGxlZC5wYWNrYWdlcygpKSksIHJlcG9zID0gImh0dHA6Ly9jcmFuLnVzLnItcHJvamVjdC5vcmciKQ0KYGBgDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gRiwgZWNobyA9IFR9DQppbnN0YWxsLnBhY2thZ2VzKCJwbG90bHkiKQ0KYGBgDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gVCwgZWNobyA9IFQsIG1lc3NhZ2UgPSBGLCB3YXJuaW5nID0gRn0NCmxpYnJhcnkocGxvdGx5KQ0KYGBgDQoNCiMjICB7I3Bsb3RseWhpc3RvZ3JhbX0NCg0KYHIgZW1vOjpqaSgiY29tcHV0ZXIiKWAgVG8gY3JlYXRlIGBwbG90bHlgIHBsb3RzLCB3ZSB1c2UgdGhlIGZ1bmN0aW9uIGBwbG90X2x5KClgLg0KDQpSdW4gdGhlIGNvZGUgYmVsb3cgdG8gY3JlYXRlIGFuZCBzdG9yZSBhbiBpbnRlcmFjdGl2ZSBoaXN0b2dyYW0gb2YgdGhlIHRoZSBwZW5ndWlucycgYGJvZHlfbWFzc19nYCB2YWx1ZXMgaW4gdGhlIG9iamVjdCBgcGVuZ3Vpbl9oaXN0X2Jhc2VgLg0KDQpBdCB0aGlzIHBvaW50LCBkb24ndCB3b3JyeSBhYm91dCB0aGUgY29tcG9zaXRpb24gb2YgdGhpcyBmdW5jdGlvbiAtIHdlJ2xsIGNvdmVyIHRoaXMgaW4gbW9yZSBkZXRhaWwgc2hvcnRseS4gDQoNCiAgKiBGb3IgdGhlIG1vbWVudCwgdGFrZSBhIGxvb2sgYXQgdGhlIGNvZGUgYmVsb3csIGFuZCBzZWUgaWYgeW91IGNhbiBnZXQgYSBnZW5lcmFsIGlkZWEgb2Ygd2hhdCdzIGdvaW5nIG9uLg0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IFQsIGVjaG8gPSBULCB3YXJuaW5nID0gRiwgbWVzc2FnZSA9IEZ9DQpwZW5ndWluX2hpc3RfYmFzZSA8LSBwbG90X2x5KGRhdGEgPSBwZW5ndWlucywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHggPSB+Ym9keV9tYXNzX2csIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gImhpc3RvZ3JhbSIpDQoNCnBlbmd1aW5faGlzdF9iYXNlIDwtIHBlbmd1aW5faGlzdF9iYXNlICU+JSBsYXlvdXQoeWF4aXMgPSBsaXN0KHRpdGxlID0gJ2NvdW50JykpDQpgYGANCg0KPGJyPg0KDQo8ZGV0YWlscz4NCiAgPHN1bW1hcnk+YHIgZW1vOjpqaSgicXVlc3Rpb24iKWAqTm90ZSogIDwvc3VtbWFyeT4NCipPbmNlIHlvdSBoYXZlIHRha2VuIHNvbWUgdGltZSB0byBjb25zaWRlciB0aGUgY29kZSBhYm92ZSwgaWYgeW91IHdvdWxkIGxpa2UgbW9yZSBkZXRhaWxzIG9yIHdvdWxkIGxpa2UgdG8gY2hlY2sgdGhlIGFjY3VyYWN5IG9mIHlvdXIgaW50ZXJwcmV0YXRpb24sIGNsaWNrIHRoZSBgU2hvd2AgYnV0dG9uIGJlbG93IGZvciBhIGJyaWVmIGV4cGxhbmF0aW9uLioNCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSIsIGV2YWwgPSBGLCBlY2hvID0gVH0NCiMgSGVyZSwgd2UgYXJlIGNyZWF0aW5nIGEgcGxvdGx5IG9iamVjdCBjYWxsZWQgInBlbmd1aW5faGlzdF9iYXNlIg0KcGVuZ3Vpbl9oaXN0X2Jhc2UgPC0gcGxvdF9seShkYXRhID0gcGVuZ3VpbnMsICMgV2UgYXJlIHVzaW5nIHRoZSBwZW5ndWlucyBkYXRhDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHggPSB+Ym9keV9tYXNzX2csICMgYW5kIG1vZGVsbGluZyB0aGUgYm9keV9tYXNzX2cgZGF0YQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gImhpc3RvZ3JhbSIpICMgaW4gYSBoaXN0b2dyYW0gZm9ybWF0DQoNCiMgVGhlIGNvZGUgYmVsb3cgaXMgdXNlZCB0byBtb2RpZnkgdGhlIGxheW91dCBvZiB0aGUgaGlzdG9ncmFtDQojIHRvIGluY2x1ZGUgYSBsYWJlbCBmb3IgdGhlIHktYXhpcw0KcGVuZ3Vpbl9oaXN0X2Jhc2UgPC0gcGVuZ3Vpbl9oaXN0X2Jhc2UgJT4lIGxheW91dCh5YXhpcyA9IGxpc3QodGl0bGUgPSAnY291bnQnKSkNCmBgYA0KPC9kZXRhaWxzPg0KDQo8YnI+DQoNCiMjIHsjYmFzZWhpc3R9DQoNCmByIGVtbzo6amkoImNvbXB1dGVyIilgIFRoZSBgcGxvdGx5YCBoaXN0b2dyYW0gaGFzIG5vdyBiZWVuIGNyZWF0ZWQsIGJ1dCB3b24ndCBhcHBlYXIgdW50aWwgd2UgY2FsbCB0aGUgb2JqZWN0IGluIHdoaWNoIGl0IHdhcyBzdG9yZWQuIElmIHlvdSBydW4gdGhlIGNvZGUgYmVsb3csIHlvdXIgYHBsb3RseWAgaGlzdG9ncmFtIChhcyBzaG93biBiZWxvdykgc2hvdWxkIGFwcGVhciBpbiB0aGUgYFZpZXdlcmAgc2VjdGlvbiBvZiBSU3R1ZGlvLg0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IFQsIGVjaG8gPSBULCB3YXJuaW5nID0gRiwgbWVzc2FnZSA9IEYsIGZpZy5hbGlnbiA9ICJjZW50ZXIifQ0KcGVuZ3Vpbl9oaXN0X2Jhc2UNCmBgYA0KDQojIw0KDQpgciBlbW86OmppKCJjb21wdXRlciIpYCBVbmxpa2UgZ3JhcGhzIGNyZWF0ZWQgdXNpbmcgYmFzZSBSIGZ1bmN0aW9ucywgYHBsb3RseWAgZ3JhcGhzIGFyZSBpbnRlcmFjdGl2ZSAtIGV2ZW4gd2hlbiBlbWJlZGRlZCBpbiB3ZWIgcGFnZXMgbGlrZSB0aGlzIG9uZSENCg0KVHJ5IHRoZSBmb2xsb3dpbmc6DQoNCiogSWYgeW91IGhvdmVyIG92ZXIgdGhlIGhpc3RvZ3JhbSBpbiBcQHJlZihiYXNlaGlzdCksIHlvdSBjYW4gc2VlIHRoZSBzcGVjaWZpYyBkZXRhaWxzIG9mIHRoZSBkYXRhLg0KKiBJZiB5b3UgbGVmdC1jbGljayBhbmQgZHJhZyB5b3VyIGN1cnNvciBvdmVyIGEgc2VjdGlvbiBvZiB0aGUgaGlzdG9ncmFtIHRvIGNyZWF0ZSBhIGJveCwgeW91IGNhbiBhbHNvIHpvb20gaW4gb24gYSBwYXJ0aWN1bGFyIHNlY3Rpb24gb2YgdGhlIHBsb3QuIEp1c3QgZG91YmxlIGxlZnQtY2xpY2sgdG8gem9vbSBiYWNrIG91dC4NCg0KIyMNCg0KYHIgZW1vOjpqaSgiY29tcHV0ZXIiKWAgUGVyaGFwcyB5b3UgYXJlIG5vdCBpbXByZXNzZWQgd2l0aCBgcGxvdGx5YCB5ZXQuIEFmdGVyIGFsbCwgb3VyIGhpc3RvZ3JhbSBpbiBcQHJlZihiYXNlaGlzdCkgZG9lc24ndCBsb29rICp0aGF0IGRpZmZlcmVudCogdG8gdGhlIGBoaXN0YCBmdW5jdGlvbiB2ZXJzaW9uIHdlIGNyZWF0ZWQgYXQgdGhlIHN0YXJ0IG9mIFxAcmVmKGhpc3RzdGFydCksIHNvIHdoYXQgaXMgYWxsIHRoZSBmdXNzIGFib3V0Pw0KDQpXZWxsLCBpdCBpcyB2ZXJ5IGVhc3kgdG8gbW9kaWZ5IG91ciBgcGxvdF9seWAgaGlzdG9ncmFtIHRvIHNob3cgZXh0cmEgZGV0YWlsLiBGb3IgZXhhbXBsZSwgd2UgY2FuIGVhc2lseSBwcm9kdWNlIHNlcGFyYXRlIGhpc3RvZ3JhbXMgZm9yIHRoZSBwZW5ndWlucyBvbiBlYWNoIGlzbGFuZC4gVGFrZSBhIGxvb2sgYXQgdGhlIFIgY29kZSBiZWxvdywgd2hpY2ggYnVpbGRzIHVwb24gd2hhdCB3ZSB1c2VkIGluIGBwZW5ndWluX2hpc3RfYmFzZWAuDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gVCwgZWNobyA9IFQsIHdhcm5pbmcgPSBGLCBtZXNzYWdlID0gRn0NCnBlbmd1aW5faGlzdCA8LSBwbG90X2x5KGRhdGEgPSBwZW5ndWlucywgDQogICAgICAgICAgICAgICAgICAgICAgICB4ID0gfmJvZHlfbWFzc19nLCANCiAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gfmlzbGFuZCwgDQogICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gImhpc3RvZ3JhbSIsIGFscGhhID0gMC42KQ0KDQpwZW5ndWluX2hpc3QgPC0gcGVuZ3Vpbl9oaXN0ICU+JSBsYXlvdXQoeWF4aXMgPSBsaXN0KHRpdGxlID0gJ2NvdW50JyksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhcm1vZGUgPSJvdmVybGF5IikNCmBgYA0KDQpCZWZvcmUgeW91IG1vdmUgb24gdG8gdGhlIG5leHQgcXVlc3Rpb24sIHJ1biB0aGlzIGNvZGUgaW4gUlN0dWRpby4NCg0KPGJyPg0KDQo8ZGV0YWlscz4NCiAgPHN1bW1hcnk+YHIgZW1vOjpqaSgicXVlc3Rpb24iKWAqTm90ZSogIDwvc3VtbWFyeT4NCipPbmNlIHlvdSBoYXZlIHRha2VuIHNvbWUgdGltZSB0byBjb25zaWRlciB0aGUgY29kZSBhYm92ZSwgaWYgeW91IHdvdWxkIGxpa2UgbW9yZSBkZXRhaWxzIG9yIHdvdWxkIGxpa2UgdG8gY2hlY2sgdGhlIGFjY3VyYWN5IG9mIHlvdXIgaW50ZXJwcmV0YXRpb24sIGNsaWNrIHRoZSBgU2hvd2AgYnV0dG9uIGJlbG93IGZvciBhIGJyaWVmIGV4cGxhbmF0aW9uLioNCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSIsIGV2YWwgPSBGLCBlY2hvID0gVH0NCiMgSGVyZSwgd2UgYXJlIGNyZWF0aW5nIGEgcGxvdGx5IG9iamVjdCBjYWxsZWQgInBlbmd1aW5faGlzdCINCnBlbmd1aW5faGlzdCA8LSBwbG90X2x5KGRhdGEgPSBwZW5ndWlucywgIyBXZSBhcmUgdXNpbmcgdGhlIHBlbmd1aW5zIGRhdGENCiAgICAgICAgICAgICAgICAgICAgICAgIHggPSB+Ym9keV9tYXNzX2csICMgYW5kIG1vZGVsbGluZyB0aGUgYm9keV9tYXNzX2cgZGF0YQ0KICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSB+aXNsYW5kLCB0eXBlID0gImhpc3RvZ3JhbSIsIGFscGhhID0gMC42KQ0KIyBXZSBhcmUgcHJvZHVjaW5nIGEgaGlzdG9ncmFtIGZvciB0aGlzIGRhdGEsIHdpdGggcG9pbnRzIGNvbG91cmVkIGRpZmZlcmVudGx5LCANCiMgZGVwZW5kaW5nIG9uIHRoZSBpc2xhbmQgb24gd2hpY2ggdGhlIHBlbmd1aW4gaXMgbG9jYXRlZA0KDQojIFRoZSBjb2RlIGJlbG93IGlzIHVzZWQgdG8gbW9kaWZ5IHRoZSBsYXlvdXQgb2YgdGhlIGhpc3RvZ3JhbQ0KIyBUaGlzIGluY2x1ZGVzIGFkZGluZyBhIGxhYmVsIHRvIHRoZSB5LWF4aXMNCiMgYW5kIHNldHRpbmcgdGhlIGhpc3RvZ3JhbXMgdG8gYmUgbGF5ZXJlZCBvdmVyIGVhY2ggb3RoZXINCiMgKGhlbmNlIHRoZSBhbHBoYSA9IDAuNiBhYm92ZSB0byBjaGFuZ2UgdGhlIG9wYWNpdHkpDQpwZW5ndWluX2hpc3QgPC0gcGVuZ3Vpbl9oaXN0ICU+JSBsYXlvdXQoeWF4aXMgPSBsaXN0KHRpdGxlID0gJ2NvdW50JyksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhcm1vZGUgPSJvdmVybGF5IikNCmBgYA0KPC9kZXRhaWxzPg0KDQo8YnI+DQoNCiMjIHsjaXNsYW5kc2hpc3R9DQoNCmByIGVtbzo6amkoImNvbXB1dGVyIilgIFRvIHByb2R1Y2UgdGhpcyB1cGRhdGVkIGBwbG90bHlgIGhpc3RvZ3JhbSwgcnVuIHRoZSBSIGNvZGUgYmVsb3cuIFlvdXIgbmV3IGhpc3RvZ3JhbSAoYXMgc2hvd24gYmVsb3cpIHNob3VsZCBhcHBlYXIgaW4gdGhlIGBWaWV3ZXJgIHNlY3Rpb24gb2YgUlN0dWRpby4NCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gVCwgd2FybmluZyA9IEYsIG1lc3NhZ2UgPSBGLCBmaWcuYWxpZ24gPSAiY2VudGVyIn0NCnBlbmd1aW5faGlzdA0KYGBgDQoNClRoaXMgaXMgbG9va2luZyBiZXR0ZXIgdGhhbiBvdXIgcHJldmlvdXMgaGlzdG9ncmFtISBCZWNhdXNlIHdlIGhhdmUgdG9sZCBvdXIgYHBsb3RfbHlgIGZ1bmN0aW9uIHRvIGFzc2lnbiBkaWZmZXJlbnQgY29sb3VycyB0byB0aGUgZGlmZmVyZW50IGlzbGFuZHMsIHdlIG5vdyBoYXZlIHRocmVlIGhpc3RvZ3JhbXMsIHJhdGhlciB0aGFuIG9uZSB3aXRoIGFsbCB0aGUgZGF0YSBjbHVtcGVkIHRvZ2V0aGVyLg0KDQpFdmVuIGJldHRlciwgdGhlc2UgYXJlIGFsbCBwcmVzZW50ZWQgd2l0aGluIHRoZSBvbmUgZ3JhcGgsIHdoaWNoIGFsc28gaW5jbHVkZXMgYSBoYW5keSBsZWdlbmQuIEhvcGVmdWxseSB5b3UgYXJlIG5vdyBiZWdpbm5pbmcgdG8gYXBwcmVjaWF0ZSB0aGUgYWRkaXRpb25hbCBmdW5jdGlvbmFsaXR5IG9mZmVyZWQgYnkgYHBsb3RseWAgb3ZlciBidWlsdC1pbiBSIGZ1bmN0aW9ucy4NCg0KKk5vdGU6IEZvciBtb3JlIGRldGFpbHMgb24gYHBsb3RseWAsIHlvdSBjYW4gcmVmZXIgdG8gW1NlY3Rpb24gMyBvZiB0aGUgRGF0YSBWaXN1YWxpc2F0aW9uIGluIFIgc3VwcGxlbWVudF0oaHR0cHM6Ly9ib29rZG93bi5vcmcvcmVoay9zdG0xMDAxX2RzbV9kYXRhX3Zpc3VhbGlzYXRpb25faW5fci9wbG90bHktY29tcHV0ZXItbGFicy0yYi5odG1sKS4qDQoNCiMjDQoNCmByIGVtbzo6amkoImNvbXB1dGVyIilgIEZpbmFsbHksIGFuZCBwZXJoYXBzIG1vc3QgaW1wb3J0YW50bHkgZm9yIHRoaXMgc3BlY2lmaWMgZXhhbXBsZSwgaXQgaXMgaW1wb3J0YW50IHRvIG5vdGUgdGhhdCB3ZSBjYW4gKipkeW5hbWljYWxseSBmaWx0ZXIqKiByZXN1bHRzIGluIGBwbG90bHlgIGdyYXBocy4gRm9yIHRoaXMgZXhhbXBsZSwgd2UgY2FuIGZpbHRlciBvYnNlcnZhdGlvbnMgdG8gZm9jdXMgb24gZGF0YSBmcm9tIGEgc3BlY2lmaWMgaXNsYW5kLiBTaW1wbHkgY2xpY2sgb24gb25lIG9mIHRoZSBsaW5lcyBpbiB0aGUgbGVnZW5kIGluIHRoZSB0b3AgcmlnaHQgb2Ygb3VyIGhpc3RvZ3JhbSBpbiBcQHJlZihpc2xhbmRzaGlzdCksIHRvIHRlbXBvcmFyaWx5IHJlbW92ZSB0aGF0IGRhdGEgZnJvbSBhc3Nlc3NtZW50IChub3RlIHRoYXQgdGhlIGF4ZXMgZHluYW1pY2FsbHkgYWRqdXN0IHRvbykuIA0KDQpUcnkgZm9jdXNpbmcganVzdCBvbiB0aGUgRHJlYW0gaXNsYW5kIHBlbmd1aW5zLg0KDQoqSGludDogVG8gYnJpbmcgdGhlIHJlbW92ZWQgZGF0YSBiYWNrLCBzaW1wbHkgY2xpY2sgb25jZSBtb3JlIG9uIHRoZSByZWxldmFudCBsaW5lIGluIHRoZSBsZWdlbmQuKg0KDQo8YnI+DQoNCjxkZXRhaWxzPg0KICA8c3VtbWFyeT5gciBlbW86OmppKCJoZWFkcGhvbmVzIilgICoqT25saW5lIHN0dWRlbnRzKio8L3N1bW1hcnk+DQpgciBlbW86OmppKCJzcGVlY2hfYmFsbG9vbiIpYCBMZWF2ZSBhIGNvbW1lbnQgaW4gdGhlIGNoYXQgYWJvdXQgeW91ciBmYXZvdXJpdGUgYXNwZWN0IG9mIHRoZSBpbnRlcmFjdGl2ZSBwbG90bHkgZ3JhcGhzIHNvIGZhci4gDQo8L2RldGFpbHM+IA0KDQo8YnI+DQoNCiMjIyMgYHIgZW1vOjpqaSgiaG91c2Vfd2l0aF9nYXJkZW4iKWAgUmVjb252ZW5lIGluIG1haW4gcm9vbSB0byBkaXNjdXNzIHJlc3VsdHMgey19DQoNCjxicj4NCg0KIyBDcmVhdGluZyBJbnRlcmFjdGl2ZSBTY2F0dGVyIFBsb3RzIGluIFJTdHVkaW8geyNzY2F0dGVyfSANCg0KYHIgZW1vOjpqaSgiY29tcHV0ZXIiKWAgRnJvbSBvdXIgc3VtbWFyeSB0YWJsZSBpbiBcQHJlZihzdW1tYXJ5aW5mbyksIHdlIGNhbiBzZWUgdGhhdCB0aGUgbWVhc3VyZW1lbnQgdmFyaWFibGVzIGluIHRoZSBgcGVuZ3VpbnNgIGRhdGEgc2V0IGluY2x1ZGUgYGJvZHlfbWFzc19nYCBhbmQgYGZsaXBwZXJfbGVuZ3RoX21tYC4NCg0KSXQgc2VlbXMgcmVhc29uYWJsZSB0byBhc3N1bWUgdGhhdCBwZW5ndWlucyB3aXRoIGxhcmdlciBib2R5IG1hc3NlcyBtaWdodCBhbHNvIGhhdmUgbG9uZ2VyIGZsaXBwZXJzLiANCg0KVG8gdmlzdWFsaXNlIHRoZSBvYnNlcnZhdGlvbnMgZm9yIHRoZXNlIHZhcmlhYmxlcywgYW5kIGNoZWNrIG91ciBhc3N1bXB0aW9uLCB3ZSBjb3VsZCB1c2UgYSAqKnNjYXR0ZXIgcGxvdCoqLiBUbyBjcmVhdGUgdGhpcyBzY2F0dGVyIHBsb3QsIHdlIHdpbGwgYWdhaW4gdXNlIHRoZSBgcGxvdGx5YCBwYWNrYWdlLCBhcyBpdCBvZmZlcnMgc2V2ZXJhbCBiZW5lZml0cyBvdmVyIHVzaW5nIHRoZSBkZWZhdWx0IHBsb3R0aW5nIG9wdGlvbnMgaW4gUi4gDQoNCipOb3RlOiBSZWZlciB0byBbU2VjdGlvbiA1LjEgb2YgVG9waWMgMl0oaHR0cHM6Ly9ib29rZG93bi5vcmcvYV9zaGFrZXIvU1RNMTAwMV9Ub3BpY18yLzUuMS1zY2F0dGVyLXBsb3RzLmh0bWwpIGZvciBkZXRhaWxzIG9uIHNjYXR0ZXIgcGxvdHMuKg0KDQojIyB7I3NpbXBsZXNjYXR0ZXJ9DQoNCmByIGVtbzo6amkoImNvbXB1dGVyIilgIFRvIGNyZWF0ZSBhbiBpbnRlcmFjdGl2ZSBgcGxvdGx5YCBwbG90IHdlIG5lZWQgdG8gdXNlIHRoZSBmdW5jdGlvbiBgcGxvdF9seSgpYC4gSW4gXEByZWYocGxvdGx5aGlzdG9ncmFtKSwgd2UgYnJ1c2hlZCBvdmVyIHRoZSBkZXRhaWxzIG9mIHRoZSBgcGxvdF9seSgpYCBmdW5jdGlvbiwgc28gbGV0J3MgcmVtZWR5IHRoYXQgbm93Lg0KDQpUaGUgdHlwaWNhbCBjb21wb3NpdGlvbiBvZiBhIHNpbXBsZSBgcGxvdGx5YCBwbG90IGxvb2tzIGxpa2UgdGhpczoNCg0KIGBwbG90X25hbWUgPC0gcGxvdF9seShkYXRhID0gLi4uLCB4ID0gfiAuLi4sIHkgPSB+IC4uLilgDQogDQpMZXQncyBicmVhayB0aGlzIGRvd246DQoNCiogRmlyc3RseSwgKHVzaW5nIHRoZSBhc3NpZ25tZW50IG9wZXJhdG9yIGA8LWApIHdlIGFzc2lnbiBhIG5hbWUgdG8gb3VyIHBsb3QgLSBoZXJlIHdlIGhhdmUgY2hvc2VuIHRoZSBnZW5lcmljIGBwbG90X25hbWVgLiANCiogTmV4dCwgd2l0aGluIGBwbG90bHkoKWAsIHdlIHNwZWNpZnkgdGhlIG1haW4gYXJndW1lbnRzIG9mIHRoZSBmdW5jdGlvbi4gDQoqIFRoZSBgZGF0YSA9IC4uLmAgcGFydCB0ZWxscyBSIHdoYXQgZGF0YSB3ZSBhcmUgYW5hbHlzaW5nLiANCiogVGhlIGB4ID0gfiAuLi5gIHBhcnQgdGVsbHMgUiB3aGljaCB2YXJpYWJsZSBpbiBvdXIgZGF0YSBzZXQgdG8gcGxvdCBvbiB0aGUgeC1heGlzIG9mIG91ciBwbG90Lg0KKiBUaGUgYHkgPSB+IC4uLmAgcGFydCB0ZWxscyBSIHdoaWNoIHZhcmlhYmxlIGluIG91ciBkYXRhIHNldCB0byBwbG90IG9uIHRoZSB5LWF4aXMgb2Ygb3VyIHBsb3QuDQogDQoqTm90ZTogV2Ugc2ltcGx5IHJlcGxhY2UgdGhlIGAuLi5gcyB3aXRoIHdoYXRldmVyIGRhdGEgd2UgYXJlIHVzaW5nLioNCg0KIyMgeyNzY2F0dGVyYmFzZX0NCg0KYHIgZW1vOjpqaSgiY29tcHV0ZXIiKWAgUnVuIHRoZSBjb2RlIGJlbG93IHRvIGNyZWF0ZSBhIHNpbXBsZSBzY2F0dGVyIHBsb3Qgb2YgdGhlIHJlY29yZGVkIGBmbGlwcGVyX2xlbmd0aF9tbWAgdmVyc3VzIGBib2R5X21hc3NfZ2AgdmFsdWVzIGluIHRoZSBgcGVuZ3VpbnNgIGRhdGEgc2V0IChhcyBzaG93biBiZWxvdykuIE1ha2Ugc3VyZSB0byBpbnNwZWN0IHRoaXMgY29kZSwgYW5kIGNoZWNrIHRoYXQgeW91IHVuZGVyc3RhbmQgZWFjaCBjb21wb25lbnQuIA0KDQpOb3RlIHRoYXQgc2luY2Ugd2UgaGF2ZSBzcGVjaWZpZWQgb3VyIGRhdGEgc2V0IGlzIGBwZW5ndWluc2AgaW4gdGhlIGNvZGUsIHdlIGRvbid0IHRoZW4gbmVlZCB0byBkbyB0aGlzIHdoZW4gc3BlY2lmeWluZyBvdXIgYHhgIGFuZCBgeWAgaW5wdXRzIC0gd2UgY2FuIHNpbXBseSBzcGVjaWZ5IGFueSBvZiB0aGUgdmFyaWFibGVzIGNvbnRhaW5lZCB3aXRoaW4gdGhpcyBkYXRhIHNldC4NCg0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IEYsIGVjaG8gPSBUfQ0KcGVuZ3VpbnNfc2NhdHRlciA8LSBwbG90X2x5KGRhdGEgPSBwZW5ndWlucywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgeCA9IH5ib2R5X21hc3NfZywgeSA9IH5mbGlwcGVyX2xlbmd0aF9tbSkNCnBlbmd1aW5zX3NjYXR0ZXINCmBgYA0KDQoqTm90ZTogT25jZSB3ZSBhc3NpZ24gdGhlIHBsb3QgdG8gdGhlIG9iamVjdCBgcGVuZ3VpbnNfc2NhdHRlcmAsIHdlIHRoZW4gaGF2ZSB0byBydW4gdGhpcyBvYmplY3QgaW4gYSBzdWJzZXF1ZW50IGxpbmUsIGluIG9yZGVyIGZvciB0aGUgcGxvdCB0byBiZSByZW5kZXJlZC4qDQoNCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gRiwgd2FybmluZyA9IEZ9DQpwZW5ndWluc19zY2F0dGVyIDwtIHBsb3RfbHkoZGF0YSA9IHBlbmd1aW5zLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB4ID0gfmJvZHlfbWFzc19nLCB5ID0gfmZsaXBwZXJfbGVuZ3RoX21tLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gInNjYXR0ZXIiLCBtb2RlID0gIm1hcmtlcnMiKQ0Kc3VwcHJlc3NNZXNzYWdlcyhwZW5ndWluc19zY2F0dGVyKQ0KYGBgDQoNCiMjIHsjc2NhdHRlcmNvbG91cn0NCg0KYHIgZW1vOjpqaSgiY29tcHV0ZXIiKWAgQXMgd2Ugc3VzcGVjdGVkLCBpdCBzZWVtcyBxdWl0ZSBjbGVhciBmcm9tIHRoZSBzY2F0dGVyIHBsb3QgYWJvdmUgaW4gXEByZWYoc2NhdHRlcmJhc2UpIHRoYXQsIGluIGdlbmVyYWwsIGFzIHRoZSBib2R5IG1hc3Mgb2YgcGVuZ3VpbnMgaW5jcmVhc2VzIHNvIHRvbyBkb2VzIHRoZWlyIGZsaXBwZXIgbGVuZ3RoLg0KDQpCdXQgb3VyIGdyYXBoIGlzIHF1aXRlIGJhc2ljIGF0IHRoZSBtb21lbnQgLSB3ZSBjYW4gZG8gYmV0dGVyLiANCg0KSXQgaXMgdmVyeSBlYXN5IHRvIGluY2x1ZGUgYSB0aGlyZCB2YXJpYWJsZSBpbiBhIGBwbG90bHlgIGdyYXBoLCB3aGljaCBjYW4gaGVscCB0byBmdXJ0aGVyIGRpc3Rpbmd1aXNoIHRoZSBkYXRhIHBsb3R0ZWQgb24gdGhlIGB4YCBhbmQgYHlgIGF4ZXMuIFdlIGNhbiBkbyBzbyBieSBhZGRpbmcgdGhlIGFyZ3VtZW50IGBjb2xvciA9IH4uLi5gIHdpdGhpbiBgcGxvdGx5KClgLiANCg0KUGVyaGFwcyB0aGUgYGJvZHlfbWFzc19nYCBhbmQgYGZsaXBwZXJfbGVuZ3RoX21tYCAgb2YgdGhlIHBlbmd1aW5zIGlzIGFsc28gcmVsYXRlZCB0byB0aGVpciBgc2V4YD8NCkxldCdzIHRha2UgYSBsb29rIGF0IGhvdyBvdXIgc2NhdHRlciBwbG90IGNoYW5nZXMsIGlmIHdlIGRpc3Rpbmd1aXNoIGJldHdlZW4gbWFsZSBhbmQgZmVtYWxlIHBlbmd1aW5zLg0KDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gRiwgZWNobyA9IFR9DQpwZW5ndWluc19zY2F0dGVyMiA8LSBwbG90X2x5KGRhdGEgPSBwZW5ndWlucywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHggPSB+Ym9keV9tYXNzX2csIHkgPSB+ZmxpcHBlcl9sZW5ndGhfbW0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IH5zZXgpDQpwZW5ndWluc19zY2F0dGVyMg0KYGBgDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gVCwgZWNobyA9IEYsIHdhcm5pbmcgPSBGLCBmaWcuYWxpZ24gPSAiY2VudGVyIn0NCnBlbmd1aW5zX3NjYXR0ZXIyIDwtIHBsb3RfbHkoZGF0YSA9IHBlbmd1aW5zLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeCA9IH5ib2R5X21hc3NfZywgeSA9IH5mbGlwcGVyX2xlbmd0aF9tbSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gfnNleCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGUgPSAic2NhdHRlciIsIG1vZGUgPSAibWFya2VycyIpDQpzdXBwcmVzc01lc3NhZ2VzKHBlbmd1aW5zX3NjYXR0ZXIyKQ0KYGBgDQoNClRoYXQncyBsb29raW5nIGEgYml0IG5pY2VyISBOb3cgd2UgY2FuIHNlZSB0aGF0IHRoZSBzbWFsbGVzdCBwZW5ndWlucyB0ZW5kIHRvIGJlIGZlbWFsZSwgYW5kIHRoZSBsYXJnZXN0IHBlbmd1aW5zIHRlbmQgdG8gYmUgbWFsZS4gSWYgeW91IGhvdmVyIG92ZXIgdGhlIGRhdGEsIHlvdSdsbCBub3RpY2UgdGhhdCB0aGUgYHNleGAgaXMgbm93IHNob3duIGFsb25nc2lkZSB0aGUgY29vcmRpbmF0ZXMgb2YgZWFjaCBkYXRhIHBvaW50LiANCg0KV2UgYWxzbyBoYXZlIGEgaGVscGZ1bCBsZWdlbmQgaW4gdGhlIHRvcCByaWdodC4gUmVtZW1iZXIsIHRoaXMgaXMgbm90IG9ubHkgdXNlZnVsIGFzIGEgZ3VpZGUgLSB0cnkgY2xpY2tpbmcgb24gb25lIG9mIHRoZSBsYWJlbHMgaW4gdGhlIGxlZ2VuZC4NCg0KIyMgeyNzY2F0dGVyY29sb3Vyc30NCg0KYHIgZW1vOjpqaSgiY29tcHV0ZXIiKWAgV2hpbGUgb3VyIHNjYXR0ZXIgcGxvdCBpcyBsb29raW5nIGJldHRlciwgdGhlIGRlZmF1bHQgY29sb3VycyBjaG9zZW4gdG8gZGlzdGluZ3Vpc2ggYmV0d2VlbiBtYWxlIGFuZCBmZW1hbGUgcGVuZ3VpbnMgYXJlIHF1aXRlIHNpbWlsYXIuIFBlcmhhcHMgd2Ugd291bGQgbGlrZSBtb3JlIGNvbnRyYXN0Pw0KDQpUbyBzcGVjaWZ5IHRoZSBzZXQgb2YgY29sb3VycyB0byB1c2UgZm9yIHRoZSBwbG90LCB3ZSBjYW4gYWRkIHRoZSBhZGRpdGlvbmFsIGFyZ3VtZW50IGBjb2xvcnMgPSAuLi5gIHRvIG91ciBgcGxvdF9seWAgZnVuY3Rpb24uIFRoaXMgYXJndW1lbnQgYWNjZXB0cyBhbnkgdmFsaWQgUiBjb2xvdXIgY29kZXMuIFRha2UgYSBsb29rIGF0IFt0aGlzIHBkZl0oaHR0cDovL3d3dy5zdGF0LmNvbHVtYmlhLmVkdS9+dHpoZW5nL2ZpbGVzL1Jjb2xvci5wZGYpIGZvciBhbiBvdmVydmlldyBvZiBkaWZmZXJlbnQgY29sb3VycyB3ZSBjYW4gdXNlLCBvciBzaW1wbHkgdHJ5IGEgZmV3IGJhc2ljIGNvbG91cnMgbGlrZSByZWQsIGdyZWVuIGV0Yy4NCg0KQ29tcGxldGUgYW5kIHRoZW4gcnVuIHRoZSBjb2RlIGJlbG93IHRvIGNoYW5nZSB0aGUgY29sb3VycyB5b3UgdXNlIGluIHlvdXIgc2NhdHRlciBwbG90LiANCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBGLCBlY2hvID0gVH0NCnBlbmd1aW5zX3NjYXR0ZXJfY29sb3VycyA8LSBwbG90X2x5KGRhdGEgPSBwZW5ndWlucywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4ID0gfmJvZHlfbWFzc19nLCB5ID0gfmZsaXBwZXJfbGVuZ3RoX21tLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gfnNleCwgY29sb3JzID0gLi4uKQ0KcGVuZ3VpbnNfc2NhdHRlcl9jb2xvdXJzDQpgYGANCg0KPGJyPg0KDQo8ZGV0YWlscz4NCiAgPHN1bW1hcnk+YHIgZW1vOjpqaSgicXVlc3Rpb24iKWAqSGludCogIDwvc3VtbWFyeT4NCiAgKllvdSB3aWxsIG5lZWQgYSBjb21iaW5hdGlvbiBvZiB0d28gY29sb3Vycy4gQ2hlY2sgdGhlIGBTaG93YCBib3ggYmVsb3cgaWYgeW91IGFyZSBzdHVjay4qDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUiLCBldmFsID0gRiwgZWNobyA9IFQsIHdhcm5pbmcgPSBGLCBtZXNzYWdlID0gRn0NCiMgSWYgeW91IGFyZSBzcGVjaWZ5aW5nIHNwZWNpZmljIGluZGl2aWR1YWwgY29sb3VycywgeW91IHdpbGwgbmVlZCB0byB1c2UgdGhlIGxheW91dCANCmNvbG9ycyA9IGMoIi4uLiIsICIuLi4iKQ0KIyB3aXRoaW4gdGhlIHBsb3RfbHkoKSBmdW5jdGlvbg0KYGBgDQo8L2RldGFpbHM+IA0KDQo8YnI+DQoNCiMjDQoNCmByIGVtbzo6amkoImNvbXB1dGVyIilgIElmIHlvdSBkbyBub3Qgd2FudCB0byBzcGVuZCB0b28gbXVjaCB0aW1lIGN1c3RvbWlzaW5nIHRoZSBjb2xvdXJzIHVzZWQgaW4geW91ciBwbG90cywgdGhlcmUgYXJlIHByZS1leGlzdGluZyBzZXRzIG9mIGNvbG91cnMgeW91IGNhbiB1c2UuIFRyeSBzZXR0aW5nIHlvdXIgYGNvbG9ycyA9Li4uYCBhcmd1bWVudCBpbiBcQHJlZihzY2F0dGVyY29sb3Vycykgc2VxdWVudGlhbGx5IHRvIGBjb2xvcnMgPSAiU2V0MSJgLCB0aGVuIHRvIGBjb2xvcnMgPSAiU2V0MiJgIGFuZCBmaW5hbGx5IHRvIGBjb2xvcnMgPSAiU2V0MyJgLiBEbyBhbnkgcGFydGljdWxhciBzZXRzIGFwcGVhbCB0byB5b3U/DQoNCjxicj4NCg0KPGRldGFpbHM+DQogIDxzdW1tYXJ5PmByIGVtbzo6amkoImhlYWRwaG9uZXMiKWAgKipPbmxpbmUgc3R1ZGVudHMqKjwvc3VtbWFyeT4NCmByIGVtbzo6amkoInNwZWVjaF9iYWxsb29uIilgIFBvc3QgeW91ciBjb2xvdXIgY2hvaWNlKHMpIGluIHRoZSBjaGF0LiANCjwvZGV0YWlscz4gDQoNCjxicj4NCg0KIyMNCg0KYHIgZW1vOjpqaSgiY29tcHV0ZXIiKWAgVGhlcmUgYXJlIG1hbnkgZGlmZmVyZW50IGRpc3BsYXkgb3B0aW9ucyBmb3IgYHBsb3RfbHlgIGdyYXBoaWNzLiBJZiB5b3UgdHJ5IHJ1bm5pbmcgdGhlIFIgY29tbWFuZHMgYmVsb3csIHlvdSBtYXkgc2VlIHNvbWUgcmVkIDxzcGFuIHN0eWxlPSJjb2xvcjpyZWQiPldhcm5pbmcgbWVzc2FnZXM8L3NwYW4+ICBhcHBlYXIgaW4gdGhlIFJTdHVkaW8gYENvbnNvbGVgIHNlY3Rpb24uIEFzIGRpc2N1c3NlZCBpbiBDb21wdXRlciBMYWIgMUIsIHdoaWxlIGl0IGlzIGltcG9ydGFudCB0byByZWFkIHRoZW0sIG9mdGVuIHlvdSBkb24ndCBoYXZlIHRvIHdvcnJ5IGFib3V0IHRoZXNlLg0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IEYsIGVjaG8gPSBUfQ0KcGVuZ3VpbnNfc2NhdHRlcjIgPC0gcGxvdF9seShkYXRhID0gcGVuZ3VpbnMsIHggPSB+Ym9keV9tYXNzX2csIHkgPSB+ZmxpcHBlcl9sZW5ndGhfbW0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IH5zZXgsIGNvbG9ycyA9ICJTZXQxIikNCnBlbmd1aW5zX3NjYXR0ZXIyDQpgYGANCg0KSW4gdGhpcyBpbnN0YW5jZSwgaWYgeW91IHdvdWxkIGxpa2UgdG8gbWluaW1pc2Ugd2FybmluZyBtZXNzYWdlcywgeW91IGNhbiBhZGQgdGhlIGFyZ3VtZW50cyBgdHlwZSA9ICJzY2F0dGVyIiwgbW9kZSA9ICJtYXJrZXJzImAgdG8geW91ciBgcGxvdF9seWAgZnVuY3Rpb24sIHNvIHRoYXQgeW91ciBjb2RlIG5vdyBsb29rcyBsaWtlIHRoaXM6DQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gRiwgZWNobyA9IFR9DQpwZW5ndWluc19zY2F0dGVyMiA8LSBwbG90X2x5KGRhdGEgPSBwZW5ndWlucywgeCA9IH5ib2R5X21hc3NfZywgeSA9IH5mbGlwcGVyX2xlbmd0aF9tbSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gfnNleCwgY29sb3JzID0gIlNldDEiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gInNjYXR0ZXIiLCBtb2RlID0gIm1hcmtlcnMiKQ0KcGVuZ3VpbnNfc2NhdHRlcjINCmBgYA0KDQpIZXJlOg0KDQoqIFdlIHNldCBgdHlwZSA9ICJzY2F0dGVyImAgdG8gZW5zdXJlIG91ciBkYXRhIGlzIHBsb3R0ZWQgYXMgYSBzY2F0dGVyIHBsb3QuDQoqIFdlIHNldCBgbW9kZSA9ICJtYXJrZXJzImAgdG8gZW5zdXJlIHRoYXQgZWFjaCBvZiBvdXIgZGF0YSBwb2ludHMgaXMgcGxvdHRlZCBpbmRpdmlkdWFsbHkuDQoNClRoZXNlIGFkZGl0aW9uYWwgYXJndW1lbnRzIGFyZSBvZnRlbiBoZWxwZnVsLCBhcyBzb21ldGltZXMgd2UgbGlrZSB0byBoYXZlIGEgbGl0dGxlIG1vcmUgY29udHJvbCBvdmVyIGhvdyBvdXIgZGF0YSBpcyBwcmVzZW50ZWQuDQoNCllvdSdsbCBub3RpY2UgaG93ZXZlciB0aGF0IGlmIHRoZXNlIGNvbW1hbmRzIGFyZSBvbWl0dGVkIGZyb20geW91ciBmdW5jdGlvbiwgUiB3aWxsIGp1c3Qgd29yayBvdXQgd2hhdCBpdCB0aGlua3MgaXMgdGhlIG9wdGltYWwgcHJlc2VudGF0aW9uIGZvcm1hdCAoaGVuY2UgdGhlIHdhcm5pbmcgbWVzc2FnZXMgaW5mb3JtaW5nIHVzIHdoaWNoIG9wdGlvbnMgaGF2ZSBiZWVuIHNlbGVjdGVkLCBzaW5jZSBzb21lIGRldGFpbHMgaGF2ZW4ndCBiZWVuIHVzZXItc3BlY2lmaWVkKS4NCg0KVGhpcyBhdXRvbWF0aWMgc2VsZWN0aW9uIGlzIG9mdGVuIGZvciB0aGUgYmVzdCAtIHRyeSBjaGFuZ2luZyB0aGUgYG1vZGUgPSAibWFya2VycyJgIHNlY3Rpb24gb2YgY29kZSBhYm92ZSB0byBgbW9kZSA9ImxpbmVzImAgYW5kIHRoZW4gcmUtcnVubmluZyB0aGUgY29kZSBjaHVuay4gV2hhdCBoYXBwZW5zPw0KDQoNCiMjDQoNCmByIGVtbzo6amkoImNvbXB1dGVyIilgIFNvIGZhciwgd2UgaGF2ZSB0cmVhdGVkIGFsbCB0aGUgcGVuZ3VpbnMgYXMgb25lIGxhcmdlIGdyb3VwLCBkaWZmZXJlbnRpYXRlZCBieSBgc2V4YC4gDQoNCldoZW4gd2UgaG92ZXIgb3ZlciBhIHBvaW50IGluIG91ciBzY2F0dGVyIHBsb3QgKHJlcHJlc2VudGluZyBhIHBlbmd1aW4pLCB3ZSBzZWUgdGhlIGZsaXBwZXIgbGVuZ3RoLCBib2R5IG1hc3MsIGFuZCBzZXggZGV0YWlscyBmb3IgdGhhdCBwZW5ndWluLiBUaGlzIGlzIGdyZWF0LCBidXQgd2UgYXJlIG1pc3Npbmcgb25lIGltcG9ydGFudCBwaWVjZSBvZiBpbmZvcm1hdGlvbiAtIHRoZSBzcGVjaWVzIG9mIHBlbmd1aW4hIFJlbWVtYmVyLCB3ZSBhY3R1YWxseSBoYXZlIGRhdGEgZm9yIHRocmVlIHNlcGFyYXRlIGBzcGVjaWVzYCBvZiBwZW5ndWluIC0gYEFkZWxpZWAsIGBDaGluc3RyYXBgLCBhbmQgYEdlbnRvb2AuDQoNCkZvcnR1bmF0ZWx5LCBpdCBpcyBzdHJhaWdodGZvcndhcmQgdG8gYWRkIHRoaXMgaW5mb3JtYXRpb24gdG8gdGhlIGhvdmVyIHRleHQgb2Ygb3VyIHBsb3QuIFdlIGNhbiBkbyB0aGlzIGJ5IGluY2x1ZGluZyB0aGUgYXJndW1lbnQgIGB0ZXh0ID0gfnNwZWNpZXNgIGluIG91ciBjb2RlLCBpbiBhIHNpbWlsYXIgd2F5IHRvIGhvdyB3ZSBoYXZlIHVzZWQgYGNvbG9yID0gfnNleGAgdG8gY29sb3VyIHRoZSBwb2ludHMuDQoNClVwZGF0ZSB5b3VyIGBwZW5ndWluc19zY2F0dGVyMmAgcGxvdCB3aXRoIHRoaXMgYHRleHQgPSB+c3BlY2llc2AgYWRkaXRpb24gbm93LCBhbmQgaG92ZXIgb3ZlciBzb21lIHBvaW50cyB0byBjaGVjayB0aGF0IHlvdXIgY29kZSBoYXMgd29ya2VkIGFzIGludGVuZGVkLg0KDQojIyB7I3NjYXR0ZXJzeW1ib2x9DQoNCmByIGVtbzo6amkoImNvbXB1dGVyIilgIFdlIGhhdmUgYWxyZWFkeSB1c2VkIGRpZmZlcmVudCBjb2xvdXJzIHRvIGRpZmZlcmVudGlhdGUgdGhlIG1hbGUgYW5kIGZlbWFsZSBwZW5ndWlucywgYnV0ICBhbGwgdGhlIGRhdGEgcG9pbnRzIGFyZSB0aGUgc2FtZSBzeW1ib2wgLSBhIGRvdC4gDQoNCkluc3RlYWQgb2YgaW5jbHVkaW5nIHRoZSBhcmd1bWVudCAgYHRleHQgPSB+c3BlY2llc2AsIHdlIGNhbiB1c2UgdGhlIGFkZGl0aW9uYWwgYXJndW1lbnQgYHN5bWJvbCA9IC4uLmAgd2l0aGluIG91ciBgcGxvdF9seWAgZnVuY3Rpb24gdG8gZGlzdGluZ3Vpc2ggYmV0d2VlbiB0aGUgZGlmZmVyZW50IGBzcGVjaWVzYCBvZiBwZW5ndWluLiANCg0KVGFrZSBhIGxvb2sgYXQgdGhlIFIgY29kZSBhbmQgcmVzdWx0YW50IGdyYXBoIGJlbG93Og0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IEYsIGVjaG8gPSBUfQ0KcGVuZ3VpbnNfc2NhdHRlcjMgPC0gcGxvdF9seShkYXRhID0gcGVuZ3VpbnMsIHggPSB+Ym9keV9tYXNzX2csIHkgPSB+ZmxpcHBlcl9sZW5ndGhfbW0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IH5zZXgsIGNvbG9ycyA9ICJTZXQxIiwgc3ltYm9sID0gfnNwZWNpZXMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gInNjYXR0ZXIiLCBtb2RlID0gIm1hcmtlcnMiKQ0KcGVuZ3VpbnNfc2NhdHRlcjMNCmBgYA0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IFQsIGVjaG8gPSBGLCB3YXJuaW5nID0gRiwgbWVzc2FnZSA9IEYsIGZpZy5hbGlnbiA9ICJjZW50ZXIifQ0KcGVuZ3VpbnNfc2NhdHRlcjMgPC0gcGxvdF9seShkYXRhID0gcmVtb3ZlX21pc3NpbmcocGVuZ3VpbnMpLCB4ID0gfmJvZHlfbWFzc19nLCB5ID0gfmZsaXBwZXJfbGVuZ3RoX21tLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSB+c2V4LCBjb2xvcnMgPSAiU2V0MSIsIHN5bWJvbCA9IH5zcGVjaWVzLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZSA9ICJzY2F0dGVyIiwgbW9kZSA9ICJtYXJrZXJzIikNCg0KcGVuZ3VpbnNfc2NhdHRlcjMNCmBgYA0KDQpHcmVhdCEgVGhpcyBpcyBsb29raW5nIG11Y2ggbW9yZSBpbmZvcm1hdGl2ZSB0aGFuIG91ciBpbml0aWFsIHNjYXR0ZXIgcGxvdCBpbiBcQHJlZihzY2F0dGVyYmFzZSkuIA0KDQpOb3cgaXQncyBxdWl0ZSBjbGVhciwgZm9yIGluc3RhbmNlLCB0aGF0IHRoZSBtYWpvcml0eSBvZiBsYXJnZXIgcGVuZ3VpbnMgKGJvdGggbWFsZSBhbmQgZmVtYWxlKSBhcmUgb2YgdGhlIGBHZW50b29gIHNwZWNpZXMsIHdoaWNoIHdlIGNvdWxkbid0IGRpc2Nlcm4gZnJvbSBvdXIgaW5pdGlhbCB2ZXJzaW9ucyBvZiB0aGlzIHNjYXR0ZXIgcGxvdC4NCg0KIyMNCg0KYHIgZW1vOjpqaSgiY29tcHV0ZXIiKWAgVGhlcmUgYXJlIDI2IGRpZmZlcmVudCBiYXNlIFIgc3ltYm9scyB5b3UgY2FuIGNob29zZSBmcm9tIC0gdGhlc2UgY2FuIGJlIHNwZWNpZmllZCBlaXRoZXIgYnkgbnVtYmVyLCBvciBieSBuYW1lLiBTaW5jZSB3ZSBoYXZlIG5vdCBzcGVjaWZpZWQgd2hpY2ggc3BlY2lmaWMgc3ltYm9scyB0byB1c2UgaW4gXEByZWYoc2NhdHRlcnN5bWJvbCksIFIgaGFzIHVzZWQgdGhlIGZpcnN0IGRlZmF1bHQgMy4NCg0KV2UgdXNlZCBgY29sb3JzID0gLi4uYCB0byBtb2RpZnkgb3VyIGBjb2xvciA9IC4uLmAgc3BlY2lmaWNhdGlvbiwgYW5kIHNpbWlsYXJseSwgd2UgY2FuIHVzZSBgc3ltYm9scyA9IC4uLmAgdG8gbW9kaWZ5IG91ciBgc3ltYm9sID0gLi4uYCBzcGVjaWZpY2F0aW9uLiANCg0KU29tZSBvZiB0aGUgc3ltYm9sIG5hbWVzIGFyZSBxdWl0ZSBsb25nLCBlLmcuIGAiZmlsbGVkIHRyaWFuZ2xlIHBvaW50LXVwImAsIHNvIGl0IGlzIG9mdGVuIGVhc2llciB0byB1c2UgbnVtYmVycy4gVGhlIHRhYmxlIGJlbG93IGxpc3RzIHNvbWUgb2YgdGhlIGF2YWlsYWJsZSBvcHRpb25zOg0KDQpgYGB7ciwgZWNobz1GLCBsYWJlbCA9ICJ0YWJsZSJ9DQpyb3cwIDwtIGMoIioqTnVtYmVyKioiLCAiKipOYW1lKioiKQ0Kcm93MSA8LSBjKDAsICJzcXVhcmUiKQ0Kcm93MiA8LSBjKDEsICJjaXJjbGUiKQ0Kcm93MyA8LSBjKDIsICJ0cmlhbmdsZSBwb2ludCB1cCIpDQpyb3c0IDwtIGMoMywgInBsdXMiKQ0Kcm93NSA8LSBjKDQsICJjcm9zcyIpDQpyb3c2IDwtIGMoNSwgImRpYW1vbmQiKQ0Kcm93NyA8LSBjKDgsICJzdGFyIikgDQptYXQgPC0gbWF0cml4KGMocm93MCwgcm93MSwgcm93Miwgcm93Mywgcm93NCwgcm93NSwgcm93Niwgcm93NyksIG5yb3cgPSA4LCBieXJvdyA9IFRSVUUpDQoNCmtuaXRyOjprYWJsZSgNCiAgbWF0LCANCiAgYm9va3RhYnMgPSBGQUxTRSwNCiAgY2FwdGlvbiA9ICdTeW1ib2wgT3B0aW9ucycNCikNCmBgYA0KDQpVc2luZyBcQHJlZih0YWI6dGFibGUpIGFuZCB0aGUgYHN5bWJvbHMgPSAuLi5gIGFyZ3VtZW50LCBjaGFuZ2UgdGhlIHN5bWJvbHMgdXNlZCBpbiB0aGUgYHBlbmd1aW5zX3NjYXR0ZXIzYCBzY2F0dGVyIHBsb3QgY3JlYXRlZCBpbiBcQHJlZihzY2F0dGVyc3ltYm9sKS4NCg0KPGJyPg0KDQo8ZGV0YWlscz4NCiAgPHN1bW1hcnk+YHIgZW1vOjpqaSgicXVlc3Rpb24iKWAqSGludCogIDwvc3VtbWFyeT4NCipJZiB5b3UgYXJlIHVzaW5nIHN5bWJvbCBuYW1lcywgYW5kIHlvdXIgY29kZSBpc24ndCB3b3JraW5nLCBjaGVjayB0aGUgY29kZSBjaHVuayBiZWxvdy4qDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUiLCBldmFsID0gRiwgZWNobyA9IFR9DQojIE5vdGUgdGhhdCBqdXN0IGxpa2UgZm9yIHRoZSBjb2xvdXJzIGFyZ3VtZW50LCBpZiB5b3UgYXJlIHVzaW5nIHdvcmRzLCANCiMgdGhlc2UgbmVlZCB0byBiZSBzdXJyb3VuZGVkIHdpdGggcXVvdGF0aW9uIG1hcmtzLA0KIyBlLmcuICJzcXVhcmUiLCBvciAnc3F1YXJlJyB3aWxsIHdvcmssIGJ1dCBzcXVhcmUgd2lsbCBub3QNCmBgYA0KPC9kZXRhaWxzPiANCg0KPGJyPg0KDQo8ZGV0YWlscz4NCiAgPHN1bW1hcnk+YHIgZW1vOjpqaSgiaGVhZHBob25lcyIpYCAqKk9ubGluZSBzdHVkZW50cyoqPC9zdW1tYXJ5Pg0KYHIgZW1vOjpqaSgic3BlZWNoX2JhbGxvb24iKWAgUG9zdCB5b3VyIHN5bWJvbCBjaG9pY2UocykgaW4gdGhlIGNoYXQuIA0KPC9kZXRhaWxzPiANCg0KPGJyPg0KDQojIw0KDQpgciBlbW86OmppKCJjb21wdXRlciIpYCBBcyBhIGZpbmFsIHRvdWNoLCB5b3UgbWF5IGFsc28gbGlrZSB0byBjaGFuZ2UgdGhlIHNpemUgb2YgdGhlIHN5bWJvbHMgaW4geW91ciBzY2F0dGVyIHBsb3QuIA0KVG8gZG8gc28sIHdlIGNhbiBpbmNsdWRlIHRoZSBgbWFya2VyID0gLi4uYCBhcmd1bWVudCBpbiBvdXIgYHBsb3RfbHlgIGZ1bmN0aW9uLg0KDQpUaGlzIGlzIGEgbGl0dGxlIG1vcmUgY29tcGxpY2F0ZWQgdG8gdXNlIHRoYW4gb3VyIHByZXZpb3VzIGFyZ3VtZW50cywgYXMgbXVsdGlwbGUgc3BlY2lmaWNhdGlvbnMgY2FuIGJlIG1hZGUgd2l0aGluIHRoaXMgYXJndW1lbnQuIEFzIGEgcmVzdWx0LCB3ZSB1c2UgdGhlIGZvcm1hdCBgbWFya2VyID0gbGlzdCguLi4pYC4gV2l0aGluIHRoZSBgbGlzdCgpYCBmdW5jdGlvbiwgd2UgY2FuIGluY2x1ZGUgbXVsdGlwbGUgc3BlY2lmaWNhdGlvbnMgd2hpY2ggYWxsIHBlcnRhaW4gdG8gdGhlIGBtYXJrZXJgIGFyZ3VtZW50LiBUbyBjaGFuZ2UgdGhlIHNpemUgb2YgdGhlIHN5bWJvbHMsIHdlIHVzZSB0aGUgYXBwcm9wcmlhdGVseSBuYW1lZCBgc2l6ZSA9IGAgYXJndW1lbnQsIHdpdGhpbiB0aGUgYGxpc3QoKWAgZnVuY3Rpb24uDQoNCkZvciBleGFtcGxlLCBpZiB3ZSB3YW50IHRvIGNoYW5nZSB0aGUgZGVmYXVsdCBtYXJrZXIgc2l6ZSAoNikgdG8gYmUgYSBsaXR0bGUgbGFyZ2VyLCB3ZSBjb3VsZCBpbmNsdWRlIHRoZSBhcmd1bWVudA0KYG1hcmtlciA9IGxpc3Qoc2l6ZSA9IDgpYCB3aXRoaW4gb3VyIGBwbG90X2x5YCBmdW5jdGlvbiBmb3Igb3VyIGBwZW5ndWluc19zY2F0dGVyM2Agc2NhdHRlciBwbG90IGNyZWF0ZWQgaW4gXEByZWYoc2NhdHRlcnN5bWJvbCkuIA0KDQpUcnkgdGhpcyBub3csIG9ic2VydmUgdGhlIGNoYW5nZXMsIGFuZCB0aGVuIHRyeSBpbmNyZWFzaW5nIGFuZCBkZWNyZWFzaW5nIHRoZSBtYXJrZXIgc2l6ZS4NCg0KPGJyPg0KDQojIyMjIFdlIGhhdmUgbm93IGNvdmVyZWQgdGhlIGJhc2ljcyBvZiBjcmVhdGluZyBgcGxvdGx5YCBoaXN0b2dyYW1zIGFuZCBzY2F0dGVyIHBsb3RzLCB3ZWxsIGRvbmUhICMjIyMgey19DQoNCjxicj4NCg0KIyMjIyBgciBlbW86OmppKCJob3VzZV93aXRoX2dhcmRlbiIpYCBSZWNvbnZlbmUgaW4gbWFpbiByb29tIHRvIGRpc2N1c3MgcmVzdWx0cyB7LX0NCg0KPGJyPg0KDQojIEV4dGVuc2lvbjogQ3JlYXRpbmcgeW91ciBvd24gYHBsb3RseWAgU2NhdHRlciBQbG90IHsjc2NhdHRlcnBlcnNvbmFsfQ0KDQpgciBlbW86OmppKCJjb21wdXRlciIpYCBUbyBmaW5pc2ggdXAsIGxldCdzIHRyeSBjcmVhdGluZyB5b3VyIG93biBgcGxvdGx5YCBzY2F0dGVyIHBsb3QuDQoNCiMjDQoNCmByIGVtbzo6amkoImNvbXB1dGVyIilgIFRvIGJlZ2luLCBjcmVhdGUgYSBzaW1wbGUgYHBsb3RseWAgc2NhdHRlciBwbG90IG9mIGBiaWxsX2xlbmd0aF9tbWAgdmVyc3VzIGBib2R5X21hc3NfZ2AsIHVzaW5nIHRoZSBgcGVuZ3VpbnNgIGRhdGEgc2V0Lg0KDQo8YnI+DQoNCjxkZXRhaWxzPg0KICA8c3VtbWFyeT5gciBlbW86OmppKCJxdWVzdGlvbiIpYCpIaW50KiAgPC9zdW1tYXJ5Pg0KKklmIHlvdSBhcmUgbm90IHN1cmUgdGhhdCB5b3UgYXJlIG9uIHRoZSByaWdodCB0cmFjaywgcmVmZXIgYmFjayB0byBcQHJlZihzaW1wbGVzY2F0dGVyKSwgYW5kL29yIGNoZWNrIHRoZSBjb2RlIGJlbG93OioNCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSIsIGV2YWwgPSBGLCBlY2hvID0gVCwgZmlnLmFsaWduID0gImNlbnRlciJ9DQojIFRoaXMgcGFydGlhbGx5IGNvbXBsZXRlIGNvZGUgc2hvdWxkIGhlbHANCnBlbmd1aW5zX3NjYXR0ZXJfbmV3IDwtIHBsb3RfbHkoZGF0YSA9IHBlbmd1aW5zLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeCA9IH5ib2R5X21hc3NfZywgeSA9IH4uLi4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZSA9ICJzY2F0dGVyIiwgbW9kZSA9ICJtYXJrZXJzIikNCnBlbmd1aW5zX3NjYXR0ZXJfbmV3DQpgYGANCjwvZGV0YWlscz4gDQoNCiMjDQoNCmByIGVtbzo6amkoImNvbXB1dGVyIilgIE9uY2UgeW91IGFyZSBoYXBweSB3aXRoIHlvdXIgaW5pdGlhbCBzY2F0dGVyIHBsb3QsIHRyeSB1c2luZyB0aGUgYGNvbG9yID0gfmAgYXJndW1lbnQgdG8gZGlmZmVyZW50aWF0ZSB0aGUgZGF0YSBpbiB5b3VyIHBsb3QgYnkgYGlzbGFuZGAuIERvIHlvdSBub3RpY2UgYW55IHBhdHRlcm5zPw0KDQoqSGludDogWW91IGNhbiByZWZlciBiYWNrIHRvIFxAcmVmKHNjYXR0ZXJjb2xvdXIpIGlmIHlvdSBhcmUgbm90IHN1cmUgaG93IHRvIHByb2NlZWQuKg0KDQojIw0KDQpgciBlbW86OmppKCJjb21wdXRlciIpYCBOZXh0LCB1c2UgdGhlIGBzeW1ib2wgPSB+YCBhcmd1bWVudCB0byBzaG93IGRpZmZlcmVudCBzeW1ib2xzIGZvciBlYWNoIGBzcGVjaWVzYCBpbiB5b3VyIHBsb3QuDQoNCiMjDQoNCmByIGVtbzo6amkoImNvbXB1dGVyIilgIFRvIGZpbmlzaCBvZmYgeW91ciBwbG90LCBjaGFuZ2UgdGhlIHN5bWJvbHMgdXNlZCBpbiB5b3VyIHBsb3QsIGFuZCBpbmNyZWFzZSB0aGUgbWFya2VyIHNpemUgb2YgeW91ciBzeW1ib2xzIHNsaWdodGx5Lg0KDQo8YnI+DQoNCjxkZXRhaWxzPg0KICA8c3VtbWFyeT5gciBlbW86OmppKCJoZWFkcGhvbmVzIilgICoqT25saW5lIHN0dWRlbnRzKio8L3N1bW1hcnk+DQpgciBlbW86OmppKCJzcGVlY2hfYmFsbG9vbiIpYCBJZiB5b3UgaGF2ZSBiZWVuIGFibGUgdG8gcmVhY2ggdGhpcyBwb2ludCBiZWZvcmUgdGhlIGVuZCBvZiB0aGUgbGFiLCB0YWtlIGEgc25pcHBldC9zY3JlZW5zaG90IG9mIHlvdXIgcGxvdCBhbmQgY29weS1wYXN0ZSBpdCBpbnRvIHRoZSBjaGF0LiANCjwvZGV0YWlscz4gDQoNCjxicj4NCg0KIyMNCg0KYHIgZW1vOjpqaSgiY29tcHV0ZXIiKWAgQnkgaW5zcGVjdGluZyB5b3VyIHBsb3QsIGRvZXMgaXQgc2VlbSBsaWtlIHBlbmd1aW5zIGxpdmluZyBvbiBkaWZmZXJlbnQgaXNsYW5kcyBoYXZlIG5vdGljZWFibHkgZGlmZmVyZW50IGBib2R5X21hc3NfZ2Agb3IgYGJpbGxfbGVuZ3RoX21tYCBtZWFzdXJlbWVudHM/DQoNCjxicj4NCg0KIyMjIyBHcmVhdCBqb2IsIHRoYXQncyBldmVyeXRoaW5nIGZvciB0b2RheSEgIyMjIyB7LX0NCg0KSG9wZWZ1bGx5IHlvdSBub3cgZmVlbCBjb25maWRlbnQgY3JlYXRpbmcgaW50ZXJhY3RpdmUgaGlzdG9ncmFtcyBhbmQgc2NhdHRlciBwbG90cyB1c2luZyBgcGxvdGx5YC4gRG9uJ3Qgd29ycnkgaWYgc29tZSBvZiB0aGUgY29kZSBzZWVtcyBkaWZmaWN1bHQgYXQgdGhlIG1vbWVudCAtIHdlIGFyZSBvbmx5IGF0IHRoZSBzZWNvbmQgZGF0YSBzY2llbmNlIGNvbXB1dGVyIGxhYiwgYW5kIHdlIHdpbGwgaGF2ZSBwbGVudHkgb2YgdGltZSB0byBwcmFjdGljZSBhbmQgaW1wcm92ZSBhcyB0aGUgc2VtZXN0ZXIgcHJvZ3Jlc3Nlcy4NCg0KQmVmb3JlIHlvdSBmaW5pc2ggdXAsIG1ha2Ugc3VyZSB0byBzYXZlIHlvdXIgc2NyaXB0IGZpbGUgc29tZXdoZXJlIHNhZmUgLSBpdCBtaWdodCBjb21lIGluIGhhbmR5IGxhdGVyIG9uLiANCg0KPGJyPg0KDQojIFJlZmVyZW5jZXMgey0gI1JlZn0NCjxkaXYgaWQ9InJlZnMiPjwvZGl2Pg0KDQo8YnI+DQoNCjxmb250IGNvbG9yID0gImdyZXkiPg0KVGhlc2Ugbm90ZXMgaGF2ZSBiZWVuIHByZXBhcmVkIGJ5IFJ1cGVydCBLdXZla2UuIFRoZSBjb3B5cmlnaHQgZm9yIHRoZSBtYXRlcmlhbCBpbiB0aGVzZSBub3RlcyByZXNpZGVzIHdpdGggdGhlIGF1dGhvciBuYW1lZCBhYm92ZSwgd2l0aCB0aGUgRGVwYXJ0bWVudCBvZiBNYXRoZW1hdGljYWwgYW5kIFBoeXNpY2FsIFNjaWVuY2VzIGFuZCB3aXRoIExhIFRyb2JlIFVuaXZlcnNpdHkuIENvcHlyaWdodCBpbiB0aGlzIHdvcmsgaXMgdmVzdGVkIGluIExhIFRyb2JlIFVuaXZlcnNpdHkgaW5jbHVkaW5nIGFsbCBMYSBUcm9iZSBVbml2ZXJzaXR5IGJyYW5kaW5nIGFuZCBuYW1pbmcuIFVubGVzcyBvdGhlcndpc2Ugc3RhdGVkLCBtYXRlcmlhbCB3aXRoaW4gdGhpcyB3b3JrIGlzIGxpY2Vuc2VkIHVuZGVyIGEgQ3JlYXRpdmUgQ29tbW9ucyBBdHRyaWJ1dGlvbi1Ob24gQ29tbWVyY2lhbC1Ob24gRGVyaXZhdGl2ZXMgTGljZW5zZSANCjxhIGhyZWYgPSAiaHR0cHM6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL2xpY2Vuc2VzL2J5LW5jLW5kLzQuMC9DQyIgdGFyZ2V0PSJfYmxhbmsiPiBCWS1OQy1ORC4gPC9hPg0KPC9mb250Pg==