Data Science Stream

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.


1 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.

1.1

🏡 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")

1.2

🏡 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.

2 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.

2.1

💻 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)

2.2

💻 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'))


2.3

💻 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

2.4

💻 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.

2.5

💻 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")


2.6

💻 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.

2.7

💻 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


3 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.

3.1

💻 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.

3.2

💻 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.

3.3

💻 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.

3.4

💻 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


3.5

💻 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.


3.6

💻 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?

3.7

💻 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.

3.8

💻 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.

3.9

💻 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.


3.10

💻 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


4 Extension: Creating your own plotly Scatter Plot

💻 To finish up, let’s try creating your own plotly scatter plot.

4.1

💻 To begin, create a simple plotly scatter plot of bill_length_mm versus body_mass_g, using the penguins data set.


Hint

If you are not sure that you are on the right track, refer back to 3.1, and/or check the code below:

# This partially complete code should help
penguins_scatter_new <- plot_ly(data = penguins, 
                                x = ~body_mass_g, y = ~...
                                type = "scatter", mode = "markers")
penguins_scatter_new

4.2

💻 Once you are happy with your initial scatter plot, try using the color = ~ argument to differentiate the data in your plot by island. Do you notice any patterns?

Hint: You can refer back to 3.3 if you are not sure how to proceed.

4.3

💻 Next, use the symbol = ~ argument to show different symbols for each species in your plot.

4.4

💻 To finish off your plot, change the symbols used in your plot, and increase the marker size of your symbols slightly.


🎧 Online students 💬 If you have been able to reach this point before the end of the lab, take a snippet/screenshot of your plot and copy-paste it into the chat.


4.5

💻 By inspecting your plot, does it seem like penguins living on different islands have noticeably different body_mass_g or bill_length_mm measurements?


Great job, that’s everything for today!

Hopefully you now feel confident creating interactive histograms and scatter plots using plotly. Don’t worry if some of the code seems difficult at the moment - we are only at the second data science computer lab, and we will have plenty of time to practice and improve as the semester progresses.

Before you finish up, make sure to save your script file somewhere safe - it might come in handy later on.


References

Horst, Allison Marie, Alison Presmanes Hill, and Kristen B Gorman. 2020. Palmerpenguins: Palmer Archipelago (Antarctica) Penguin Data. https://doi.org/10.5281/zenodo.3960218.
Sievert, Carson. 2020. Interactive Web-Based Data Visualization with r, Plotly, and Shiny. Chapman; Hall/CRC. https://plotly-r.com.


These notes have been prepared by Rupert Kuveke. The copyright for the material in these notes resides with the author named above, with the Department of Mathematical and Physical Sciences and with La Trobe University. Copyright in this work is vested in La Trobe University including all La Trobe University branding and naming. Unless otherwise stated, material within this work is licensed under a Creative Commons Attribution-Non Commercial-Non Derivatives License BY-NC-ND.

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==