Palmer Penguins Data Set
To begin, 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.
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")
Open up RStudio, and run the following code to load and summarise the palmerpenguins
package.
Note that the package is called palmerpenguins
, but once this is loaded, the actual data to access in R is stored in the object penguins
.
# This code loads the `palmerpenguins` package into your current R working environment.
library(palmerpenguins)
# This code summarises the data in the `palmerpenguins` package.
summary(penguins)
Don’t worry too much about the values shown in the summary table - 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
.
Plotly Scatter Plots
From our summary table, we can see that the measurement variables for the penguins include body_mass_g
and flipper_length_mm
.
It seems reasonable to think that penguins with larger body masses might also have longer flippers.
To visualise this, and check our assumption, we could use a scatter plot. To create this scatter plot, we will use the plotly
package, which offers several benefits over using the default plotting options in R. For more details on plotly
, you can refer to Section 3 of the Data Visualisation in R supplement.
First, let’s load the plotly
package. Using our process in 1 as a guide, load the plotly
package in R.
(If you do not have the plotly
package downloaded, make sure to do this now too).
Hint: Check the code chunk below if you are not sure how to proceed.
install.packages("plotly")
library(plotly)
We can create a plotly
plot using the function plot_ly()
. Let’s take a look at the typical composition of a plotly
plot:
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 that we simply replace the ...
s with whatever data we are using.
The code below will create a simple scatter plot of flipper_length_mm
versus body_mass_g
. Make sure to inspect this code, and check that you understand each component. Since we have specified our data set is penguins
, 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 that 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.
One key benefit of plotly
graphs compared to base R graphs, is that the plotly
graphs are interactive!
Notice is that if you hover over the data in the scatter plot, you can see the specific coordinates of each point.
If you left-click and drag your cursor over a section to create a box, you can also zoom in on a particular section of the plot. Just double left-click to zoom back out.
As we suspected, it seems quite clear that 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.
Another great aspect of plotly graphs is that it is very easy to include a third variable 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 most of the smaller penguins are female, and most of the larger penguins are 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. 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 in R.
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 Code
box below if you are stuck.
# If you are specifying specific individual colours, you will need to use the layout
colors = c("...", "...").
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 2.5 sequentially to colors = "Set1"
, then to colors = "Set2"
and finally to colors = "Set3"
. Do any particular sets appeal to you?
There are many different display options for plot_ly
graphics, and if you try running the R commands
penguins_scatter2 <- plot_ly(data = penguins, x = ~body_mass_g, y = ~flipper_length_mm,
color = ~sex, colors = "Set1")
penguins_scatter2
you may see some red Warning messages
appear in the R Console. Often, you don’t have to worry about these, but if you would like to minimise them, you can add the following arguments to your plot_ly
function.
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 have included the additional arguments type = ...
and mode = ...
.
- 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 R has selected, since some details haven’t been user-specified).
This is often for the best - try changing the mode = "markers"
section of code to mode ="lines"
and then re-running the plot. What happens?
So far, we have treated all the penguins as one large group, differentiated by sex
. However, we actually have data for three separate species of penguin - Adelie
, Chinstrap
, and Gentoo
.
We have already used different colours to differentiate the male and female penguins, but so far all the data points are the same symbol - a dot. We can use the additional argument symbol = ...
within our plot_ly
function to further improve our graph, and 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. 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 previous version of the scatter plot.
Just as R has many colour options available, so too are there many symbol options available. Since we have not specified which specific symbols to use in 2.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.
There are 26 different base R symbols you can choose from - these can be specified either by number, or by name. Some of the names are quite long, e.g. "filled triangle point-up"
, so it is often easier to use numbers. However, some names are easy to remember - take a look at the table below.
Table 2.1: Symbol Options
Number |
Name |
0 |
square |
1 |
circle |
2 |
triangle point up |
3 |
plus |
4 |
cross |
5 |
diamond |
8 |
star |
using 2.1 and the symbols = ...
argument, change the symbols used in the penguins_scatter3
scatter plot created in 2.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
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.
As a result, 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 2.8.
Try this now, observe the changes, and then try increasing and decreasing the marker size.
Mixed Subplots
Recall from our first Data Science Computer Lab how we created some histograms for our palmerpenguins
data set. Some of the code used for that lab is reproduced below:
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")
penguin_hist
Suppose that we would like to present all our palmerpenguins
data visualisations together. We can do this using the subplot
function.
Take a look at the R code below:
penguin_combined_plots <- subplot(penguins_scatter3, penguin_hist,
nrows = 2, margin = 0.05)
penguin_combined_plots <- penguin_combined_plots %>%
layout(title = "Palmer Penguin Data",
xaxis = list(title = 'body_mass_g'),
yaxis = list(title = "flipper_length_mm"),
xaxis2 = list(title = 'body_mass_g'),
yaxis2 = list(title = "count"))
Note that here:
- We are using the
subplot
command to plot the penguins_scatter3
and penguin_hist
plots together.
- The
nrows = 2
argument tells R to produce these plots in 2 rows.
- The
margin = 0.05
argument tells R to leave a small margin between the two plots.
- The subsequent lines of code are used to add a title to our selection of plots, and add axes labels to the plots - note that we use
xaxis
to define the x-axis label for the first plot, and xaxis2
to define the x-axis label for the second plot (and similarly for the y-axes).
When we now run this object penguin_combined_plots
, we obtain the following:
penguin_combined_plots
Note that the two plots are still wholely interactive. The legends have been combined, and can be used to filter the individual plots.
While we have only combined two plots here, the subplot
function can be used to present several plots together, which can be particularly informative when you would like to display multiple aspects of your data simultaneously.
The only major downside of presenting plots together using subplot
is that their axes labels are removed by default, and must be respecified, as above.
Using the information from 4.1, try to combine the scatter plot you produced in 3 with the histogram shown above at the start of 4.
Hint: You don’t need to write any code for the histogram, you can simply use the R code shown at the start of 4.
Great job, that’s everything for today!
Hopefully you now feel confident creating plotly scatter plots. Don’t worry if some of the code seems difficult at the moment - we are only at the second 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.
LS0tDQp0aXRsZTogIlNUTTEwMDE6IENvbXB1dGVyIExhYiAyQiINCm91dHB1dDoNCiAgYm9va2Rvd246Omh0bWxfZG9jdW1lbnQyOiANCiAgICB0b2M6IHRydWUNCiAgICB0b2NfZmxvYXQ6IHRydWUNCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQogICAgdGhlbWU6IHJlYWRhYmxlDQogICAgY29kZV9mb2xkaW5nOiBzaG93DQpiaWJsaW9ncmFwaHk6IFNUTTEwMDFfRFNfQ0xfcmVmZXJlbmNlcy5iaWIgDQpsaW5rLWNpdGF0aW9uczogeWVzDQotLS0NCg0KPHN0eWxlPg0KI1RPQyB7DQogIGJhY2tncm91bmQ6IHVybCgiaHR0cHM6Ly93d3cubGF0cm9iZS5lZHUuYXUvX21lZGlhL2xhLXRyb2JlLWFwaS92NS9pbWcvbG9nby5zdmciKTsNCiAgYmFja2dyb3VuZC1zaXplOiBjb250YWluOw0KICBwYWRkaW5nLXRvcDogODBweCAhaW1wb3J0YW50Ow0KICBiYWNrZ3JvdW5kLXJlcGVhdDogbm8tcmVwZWF0Ow0KfQ0KPC9zdHlsZT4NCg0KIyMjIERhdGEgU2NpZW5jZSBNb2R1bGUgey19DQoNCiMjIyBUb3BpYyAyQjogRGF0YSBWaXN1YWxpc2F0aW9uIElJIHstfQ0KDQo8YnI+DQoNCkluIHRoaXMgY29tcHV0ZXIgbGFiLCB3ZSB3aWxsIGV4dGVuZCBvdXIgYXBwcmVjaWF0aW9uIG9mIHRoZSBwb3RlbnRpYWwgb2YgdGhlIGBwbG90bHlgIFtAcGxvdGx5XSBSIHBhY2thZ2UsIGFuZCBjcmVhdGUgc29tZSBpbmZvcm1hdGl2ZSwgaW50ZXJhY3RpdmUgZGF0YSB2aXN1YWxpc2F0aW9ucywgdXNpbmcgZGF0YSBmcm9tIHRoZSBgcGVuZ3VpbnNgIGRhdGEgc2V0LiBUaGUgdHlwZXMgb2YgcGxvdHMgd2UgY29uc2lkZXIgaW4gdGhpcyBsYWIgd2VyZSBpbnRyb2R1Y2VkIGluIFtUb3BpYyAyXShodHRwczovL2Jvb2tkb3duLm9yZy9hX3NoYWtlci9TVE0xMDAxX1RvcGljXzIvKS4NCg0KQnkgdGhlIGVuZCBvZiB0aGlzIGxhYiwgeW91IHNob3VsZCBmZWVsIGNvbWZvcnRhYmxlIGNyZWF0aW5nIGEgY3VzdG9taXplZCwgaW50ZXJhY3RpdmUgc2NhdHRlciBwbG90LCBhbmQgYmUgYWJsZSB0byBjb21iaW5lIGRpZmZlcmVudCBwbG90bHkgZ3JhcGhzIHRvZ2V0aGVyIGluIGEgc2luZ2xlLCBjdXN0b21pemVkIGRpc3BsYXkuDQoNCjxicj4NCg0KIyBQYWxtZXIgUGVuZ3VpbnMgRGF0YSBTZXQgeyNwZW5ndWluc30NCg0KVG8gYmVnaW4sIGxldCdzIHF1aWNrbHkgcmVmcmVzaCBvdXIgbWVtb3JpZXMgb2YgdGhlIGBwZW5ndWluc2AgZGF0YSBzZXQgZnJvbSB0aGUgYHBhbG1lcnBlbmd1aW5zYCBSIHBhY2thZ2UgW0BwZW5ndWluc10uIA0KVGhpcyBkYXRhIHNldCBjb250YWlucyBpbmZvcm1hdGlvbiBvbiAzIHNwZWNpZXMgb2YgcGVuZ3Vpbiwgd2hvIGxpdmUgb24gZGlmZmVyZW50IGlzbGFuZHMgaW4gdGhlIFBhbG1lciBhcmNoaXBlbGFnbywgb2ZmIHRoZSBjb2FzdCBvZiBBbnRhcmN0aWNhLiBGb3IgbW9yZSBkZXRhaWxzLCB5b3UgY2FuIHJlZmVyIHRvIFtTZWN0aW9uIDIgb2YgdGhlIERhdGEgVmlzdWFsaXNhdGlvbiBpbiBSIHN1cHBsZW1lbnRdKGh0dHBzOi8vYm9va2Rvd24ub3JnL3JlaGsvc3RtMTAwMV9kc21fdDFfZGF0YV92aXN1YWxpc2F0aW9uX2luX3IvcGVuZ3VpbnMuaHRtbCkuDQoNCipOb3RlOiBJZiB5b3UgZG8gbm90IGhhdmUgdGhlIGBwYWxtZXJwZW5ndWluc2AgcGFja2FnZSBkb3dubG9hZGVkLCBqdXN0IGNsaWNrIG9uIHRoZSBgQ29kZWAgYm94IGJlbG93LCBhbmQgcnVuIHRoZSBjb2RlIHRoYXQgYXBwZWFyczoqDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUiLCBldmFsID0gRiwgZWNobyA9IFR9DQppbnN0YWxsLnBhY2thZ2VzKCJwYWxtZXJwZW5ndWlucyIpDQpgYGANCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gRiwgaW5jbHVkZSA9IEZ9DQpsaWJyYXJ5KHBhbG1lcnBlbmd1aW5zKQ0KYGBgDQoNCk9wZW4gdXAgUlN0dWRpbywgYW5kIHJ1biB0aGUgZm9sbG93aW5nIGNvZGUgdG8gbG9hZCBhbmQgc3VtbWFyaXNlIHRoZSBgcGFsbWVycGVuZ3VpbnNgIHBhY2thZ2UuDQoNCipOb3RlIHRoYXQgdGhlIHBhY2thZ2UgaXMgY2FsbGVkIGBwYWxtZXJwZW5ndWluc2AsIGJ1dCBvbmNlIHRoaXMgaXMgbG9hZGVkLCB0aGUgYWN0dWFsIGRhdGEgdG8gYWNjZXNzIGluIFIgaXMgc3RvcmVkIGluIHRoZSBvYmplY3QgYHBlbmd1aW5zYC4qDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gRiwgZWNobyA9IFR9DQojIFRoaXMgY29kZSBsb2FkcyB0aGUgYHBhbG1lcnBlbmd1aW5zYCBwYWNrYWdlIGludG8geW91ciBjdXJyZW50IFIgd29ya2luZyBlbnZpcm9ubWVudC4NCmxpYnJhcnkocGFsbWVycGVuZ3VpbnMpDQpgYGANCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBGLCBlY2hvID0gVH0NCiMgVGhpcyBjb2RlIHN1bW1hcmlzZXMgdGhlIGRhdGEgaW4gdGhlIGBwYWxtZXJwZW5ndWluc2AgcGFja2FnZS4NCnN1bW1hcnkocGVuZ3VpbnMpDQpgYGANCg0KRG9uJ3Qgd29ycnkgdG9vIG11Y2ggYWJvdXQgdGhlIHZhbHVlcyBzaG93biBpbiB0aGUgc3VtbWFyeSB0YWJsZSAtIHRoZSBtYWluIHRoaW5ncyB0byBub3RlIGF0IHRoaXMgc3RhZ2UgYXJlIHRoZSBkaWZmZXJlbnQgdmFyaWFibGVzLCBuYW1lbHkgYHNwZWNpZXNgLCBgaXNsYW5kYCwgYGJpbGxfbGVuZ3RoX21tYCwgYGJpbGxfZGVwdGhfbW1gLCBgZmxpcHBlcl9sZW5ndGhfbW1gLCBgYm9keV9tYXNzX2dgLCBgc2V4YCBhbmQgYHllYXJgLg0KDQojIFBsb3RseSBTY2F0dGVyIFBsb3RzIHsjc2NhdHRlcn0gDQoNCkZyb20gb3VyIHN1bW1hcnkgdGFibGUsIHdlIGNhbiBzZWUgdGhhdCB0aGUgbWVhc3VyZW1lbnQgdmFyaWFibGVzIGZvciB0aGUgcGVuZ3VpbnMgaW5jbHVkZSBgYm9keV9tYXNzX2dgIGFuZCBgZmxpcHBlcl9sZW5ndGhfbW1gLg0KSXQgc2VlbXMgcmVhc29uYWJsZSB0byB0aGluayB0aGF0IHBlbmd1aW5zIHdpdGggbGFyZ2VyIGJvZHkgbWFzc2VzIG1pZ2h0IGFsc28gaGF2ZSBsb25nZXIgZmxpcHBlcnMuIA0KDQpUbyB2aXN1YWxpc2UgdGhpcywgYW5kIGNoZWNrIG91ciBhc3N1bXB0aW9uLCB3ZSBjb3VsZCB1c2UgYSAqKnNjYXR0ZXIgcGxvdCoqLiBUbyBjcmVhdGUgdGhpcyBzY2F0dGVyIHBsb3QsIHdlIHdpbGwgdXNlIHRoZSBgcGxvdGx5YCBwYWNrYWdlLCB3aGljaCBvZmZlcnMgc2V2ZXJhbCBiZW5lZml0cyBvdmVyIHVzaW5nIHRoZSBkZWZhdWx0IHBsb3R0aW5nIG9wdGlvbnMgaW4gUi4gRm9yIG1vcmUgZGV0YWlscyBvbiBgcGxvdGx5YCwgeW91IGNhbiByZWZlciB0byBbU2VjdGlvbiAzIG9mIHRoZSBEYXRhIFZpc3VhbGlzYXRpb24gaW4gUiBzdXBwbGVtZW50XShodHRwczovL2Jvb2tkb3duLm9yZy9yZWhrL3N0bTEwMDFfZHNtX3QxX2RhdGFfdmlzdWFsaXNhdGlvbl9pbl9yL3Bsb3RseS1jb21wdXRlci1sYWJzLTFiLmh0bWwpLg0KDQojIyANCg0KRmlyc3QsIGxldCdzIGxvYWQgdGhlIGBwbG90bHlgIHBhY2thZ2UuIFVzaW5nIG91ciBwcm9jZXNzIGluIFxAcmVmKHBlbmd1aW5zKSBhcyBhIGd1aWRlLCBsb2FkIHRoZSBgcGxvdGx5YCBwYWNrYWdlIGluIFIuIA0KKElmIHlvdSBkbyBub3QgaGF2ZSB0aGUgYHBsb3RseWAgIHBhY2thZ2UgZG93bmxvYWRlZCwgbWFrZSBzdXJlIHRvIGRvIHRoaXMgbm93IHRvbykuDQoNCipIaW50OiBDaGVjayB0aGUgY29kZSBjaHVuayBiZWxvdyBpZiB5b3UgYXJlIG5vdCBzdXJlIGhvdyB0byBwcm9jZWVkLioNCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gRiwgaW5jbHVkZSA9IEZ9DQpsaWJyYXJ5KHBsb3RseSkNCmBgYA0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1oaWRlIiwgZXZhbCA9IEYsIGVjaG8gPSBUfQ0KaW5zdGFsbC5wYWNrYWdlcygicGxvdGx5IikNCmxpYnJhcnkocGxvdGx5KQ0KYGBgDQoNCiMjIHsjc2ltcGxlc2NhdHRlcn0NCg0KV2UgY2FuIGNyZWF0ZSBhIGBwbG90bHlgIHBsb3QgdXNpbmcgdGhlIGZ1bmN0aW9uIGBwbG90X2x5KClgLiBMZXQncyB0YWtlIGEgbG9vayBhdCB0aGUgdHlwaWNhbCBjb21wb3NpdGlvbiBvZiBhIGBwbG90bHlgIHBsb3Q6DQoNCiBgcGxvdF9uYW1lIDwtIHBsb3RfbHkoZGF0YSA9IC4uLiwgeCA9IH4gLi4uLCB5ID0gfiAuLi4pYA0KIA0KTGV0J3MgYnJlYWsgdGhpcyBkb3duLiANCg0KKiBGaXJzdGx5LCAodXNpbmcgdGhlIGFzc2lnbm1lbnQgb3BlcmF0b3IgYDwtYCkgd2UgYXNzaWduIGEgbmFtZSB0byBvdXIgcGxvdCAtIGhlcmUgd2UgaGF2ZSBjaG9zZW4gdGhlIGdlbmVyaWMgYHBsb3RfbmFtZWAuIA0KKiBOZXh0LCB3aXRoaW4gYHBsb3RseSgpYCwgd2Ugc3BlY2lmeSB0aGUgbWFpbiBhcmd1bWVudHMgb2YgdGhlIGZ1bmN0aW9uLiANCiogVGhlIGBkYXRhID0gLi4uYCBwYXJ0IHRlbGxzIFIgd2hhdCBkYXRhIHdlIGFyZSBhbmFseXNpbmcuIA0KKiBUaGUgYHggPSB+IC4uLmAgcGFydCB0ZWxscyBSIHdoaWNoIHZhcmlhYmxlIGluIG91ciBkYXRhIHNldCB0byBwbG90IG9uIHRoZSB4LWF4aXMgb2Ygb3VyIHBsb3QuDQoqIFRoZSBgeSA9IH4gLi4uYCBwYXJ0IHRlbGxzIFIgd2hpY2ggdmFyaWFibGUgaW4gb3VyIGRhdGEgc2V0IHRvIHBsb3Qgb24gdGhlIHktYXhpcyBvZiBvdXIgcGxvdC4NCiANCk5vdGUgdGhhdCB3ZSBzaW1wbHkgcmVwbGFjZSB0aGUgYC4uLmBzIHdpdGggd2hhdGV2ZXIgZGF0YSB3ZSBhcmUgdXNpbmcuDQoNClRoZSBjb2RlIGJlbG93IHdpbGwgY3JlYXRlIGEgc2ltcGxlIHNjYXR0ZXIgcGxvdCBvZiBgZmxpcHBlcl9sZW5ndGhfbW1gIHZlcnN1cyBgYm9keV9tYXNzX2dgLiBNYWtlIHN1cmUgdG8gaW5zcGVjdCB0aGlzIGNvZGUsIGFuZCBjaGVjayB0aGF0IHlvdSB1bmRlcnN0YW5kIGVhY2ggY29tcG9uZW50LiBTaW5jZSB3ZSBoYXZlIHNwZWNpZmllZCBvdXIgZGF0YSBzZXQgaXMgYHBlbmd1aW5zYCwgd2UgZG9uJ3QgdGhlbiBuZWVkIHRvIGRvIHRoaXMgd2hlbiBzcGVjaWZ5aW5nIG91ciBgeGAgYW5kIGB5YCBpbnB1dHMgLSB3ZSBjYW4gc2ltcGx5IHNwZWNpZnkgYW55IG9mIHRoZSB2YXJpYWJsZXMgY29udGFpbmVkIHdpdGhpbiB0aGlzIGRhdGEgc2V0Lg0KDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gRiwgZWNobyA9IFR9DQpwZW5ndWluc19zY2F0dGVyIDwtIHBsb3RfbHkoZGF0YSA9IHBlbmd1aW5zLCB4ID0gfmJvZHlfbWFzc19nLCB5ID0gfmZsaXBwZXJfbGVuZ3RoX21tKQ0KcGVuZ3VpbnNfc2NhdHRlcg0KYGBgDQoNCipOb3RlIHRoYXQgb25jZSB3ZSBhc3NpZ24gdGhlIHBsb3QgdG8gdGhlIG9iamVjdCBgcGVuZ3VpbnNfc2NhdHRlcmAsIHdlIHRoZW4gaGF2ZSB0byBydW4gdGhpcyBvYmplY3QgaW4gYSBzdWJzZXF1ZW50IGxpbmUsIGluIG9yZGVyIGZvciB0aGUgcGxvdCB0byBiZSByZW5kZXJlZC4qDQoNCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gRiwgd2FybmluZyA9IEZ9DQpwZW5ndWluc19zY2F0dGVyIDwtIHBsb3RfbHkoZGF0YSA9IHBlbmd1aW5zLCB4ID0gfmJvZHlfbWFzc19nLCB5ID0gfmZsaXBwZXJfbGVuZ3RoX21tLCB0eXBlID0gInNjYXR0ZXIiLCBtb2RlID0gIm1hcmtlcnMiKQ0Kc3VwcHJlc3NNZXNzYWdlcyhwZW5ndWluc19zY2F0dGVyKQ0KYGBgDQoNCiMjDQoNCk9uZSBrZXkgYmVuZWZpdCBvZiBgcGxvdGx5YCBncmFwaHMgY29tcGFyZWQgdG8gYmFzZSBSIGdyYXBocywgaXMgdGhhdCB0aGUgYHBsb3RseWAgZ3JhcGhzIGFyZSBpbnRlcmFjdGl2ZSENCg0KTm90aWNlIGlzIHRoYXQgaWYgeW91IGhvdmVyIG92ZXIgdGhlIGRhdGEgaW4gdGhlIHNjYXR0ZXIgcGxvdCwgeW91IGNhbiBzZWUgdGhlIHNwZWNpZmljIGNvb3JkaW5hdGVzIG9mIGVhY2ggcG9pbnQuIA0KSWYgeW91IGxlZnQtY2xpY2sgYW5kIGRyYWcgeW91ciBjdXJzb3Igb3ZlciBhIHNlY3Rpb24gdG8gY3JlYXRlIGEgYm94LCB5b3UgY2FuIGFsc28gem9vbSBpbiBvbiBhIHBhcnRpY3VsYXIgc2VjdGlvbiBvZiB0aGUgcGxvdC4gSnVzdCBkb3VibGUgbGVmdC1jbGljayB0byB6b29tIGJhY2sgb3V0Lg0KDQojIyB7I3NjYXR0ZXJjb2xvdXJ9DQoNCkFzIHdlIHN1c3BlY3RlZCwgaXQgc2VlbXMgcXVpdGUgY2xlYXIgdGhhdCBhcyB0aGUgYm9keSBtYXNzIG9mIHBlbmd1aW5zIGluY3JlYXNlcywgc28gdG9vIGRvZXMgdGhlaXIgZmxpcHBlciBsZW5ndGguDQoNCkJ1dCBvdXIgZ3JhcGggaXMgcXVpdGUgYmFzaWMgYXQgdGhlIG1vbWVudCAtIHdlIGNhbiBkbyBiZXR0ZXIuIA0KDQpBbm90aGVyIGdyZWF0IGFzcGVjdCBvZiBwbG90bHkgZ3JhcGhzIGlzIHRoYXQgaXQgaXMgdmVyeSBlYXN5IHRvIGluY2x1ZGUgYSB0aGlyZCB2YXJpYWJsZSB3aGljaCBjYW4gaGVscCB0byBmdXJ0aGVyIGRpc3Rpbmd1aXNoIHRoZSBkYXRhIHBsb3R0ZWQgb24gdGhlIGB4YCBhbmQgYHlgIGF4ZXMuIFdlIGNhbiBkbyBzbyBieSBhZGRpbmcgdGhlIGFyZ3VtZW50IGBjb2xvciA9IH4uLi5gIHdpdGhpbiBgcGxvdGx5KClgLiANCg0KUGVyaGFwcyB0aGUgYGJvZHlfbWFzc19nYCBhbmQgYGZsaXBwZXJfbGVuZ3RoX21tYCAgb2YgdGhlIHBlbmd1aW5zIGlzIGFsc28gcmVsYXRlZCB0byB0aGVpciBgc2V4YD8NCkxldCdzIHRha2UgYSBsb29rIGF0IGhvdyBvdXIgc2NhdHRlciBwbG90IGNoYW5nZXMsIGlmIHdlIGRpc3Rpbmd1aXNoIGJldHdlZW4gbWFsZSBhbmQgZmVtYWxlIHBlbmd1aW5zLg0KDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gRiwgZWNobyA9IFR9DQpwZW5ndWluc19zY2F0dGVyMiA8LSBwbG90X2x5KGRhdGEgPSBwZW5ndWlucywgeCA9IH5ib2R5X21hc3NfZywgeSA9IH5mbGlwcGVyX2xlbmd0aF9tbSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gfnNleCkNCnBlbmd1aW5zX3NjYXR0ZXIyDQpgYGANCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gRiwgd2FybmluZyA9IEYsIGZpZy5hbGlnbiA9ICJjZW50ZXIifQ0KcGVuZ3VpbnNfc2NhdHRlcjIgPC0gcGxvdF9seShkYXRhID0gcGVuZ3VpbnMsIHggPSB+Ym9keV9tYXNzX2csIHkgPSB+ZmxpcHBlcl9sZW5ndGhfbW0sIGNvbG9yID0gfnNleCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGUgPSAic2NhdHRlciIsIG1vZGUgPSAibWFya2VycyIpDQpzdXBwcmVzc01lc3NhZ2VzKHBlbmd1aW5zX3NjYXR0ZXIyKQ0KYGBgDQoNClRoYXQncyBsb29raW5nIGEgYml0IG5pY2VyISBOb3cgd2UgY2FuIHNlZSB0aGF0IG1vc3Qgb2YgdGhlIHNtYWxsZXIgcGVuZ3VpbnMgYXJlIGZlbWFsZSwgYW5kIG1vc3Qgb2YgdGhlIGxhcmdlciBwZW5ndWlucyBhcmUgbWFsZS4gSWYgeW91IGhvdmVyIG92ZXIgdGhlIGRhdGEsIHlvdSdsbCBub3RpY2UgdGhhdCB0aGUgYHNleGAgaXMgbm93IHNob3duIGFsb25nc2lkZSB0aGUgY29vcmRpbmF0ZXMgb2YgZWFjaCBkYXRhIHBvaW50LiANCg0KV2UgYWxzbyBoYXZlIGEgaGVscGZ1bCBsZWdlbmQgaW4gdGhlIHRvcCByaWdodC4gVGhpcyBpcyBub3Qgb25seSB1c2VmdWwgYXMgYSBndWlkZSAtIHRyeSBjbGlja2luZyBvbiBvbmUgb2YgdGhlIGxhYmVscyBpbiB0aGUgbGVnZW5kLg0KDQojIyB7I3NjYXR0ZXJjb2xvdXJzfQ0KDQpXaGlsZSBvdXIgc2NhdHRlciBwbG90IGlzIGxvb2tpbmcgYmV0dGVyLCB0aGUgZGVmYXVsdCBjb2xvdXJzIGNob3NlbiB0byBkaXN0aW5ndWlzaCBiZXR3ZWVuIG1hbGUgYW5kIGZlbWFsZSBwZW5ndWlucyBhcmUgcXVpdGUgc2ltaWxhci4gUGVyaGFwcyB3ZSB3b3VsZCBsaWtlIG1vcmUgY29udHJhc3Q/DQoNClRvIHNwZWNpZnkgdGhlIHNldCBvZiBjb2xvdXJzIHRvIHVzZSBmb3IgdGhlIHBsb3QsIHdlIGNhbiBhZGQgdGhlIGFkZGl0aW9uYWwgYXJndW1lbnQgYGNvbG9ycyA9IC4uLmAgdG8gb3VyIGBwbG90X2x5YCBmdW5jdGlvbi4gVGhpcyBhcmd1bWVudCBhY2NlcHRzIGFueSB2YWxpZCBSIGNvbG91ciBjb2Rlcy4gVGFrZSBhIGxvb2sgYXQgW3RoaXMgcGRmXShodHRwOi8vd3d3LnN0YXQuY29sdW1iaWEuZWR1L350emhlbmcvZmlsZXMvUmNvbG9yLnBkZikgZm9yIGFuIG92ZXJ2aWV3IG9mIGRpZmZlcmVudCBjb2xvdXJzIHdlIGNhbiB1c2UgaW4gUi4NCg0KQ29tcGxldGUgYW5kIHRoZW4gcnVuIHRoZSBjb2RlIGJlbG93IHRvIGNoYW5nZSB0aGUgY29sb3VycyB5b3UgdXNlIGluIHlvdXIgc2NhdHRlciBwbG90LiANCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBGLCBlY2hvID0gVH0NCnBlbmd1aW5zX3NjYXR0ZXJfY29sb3VycyA8LSBwbG90X2x5KGRhdGEgPSBwZW5ndWlucywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4ID0gfmJvZHlfbWFzc19nLCB5ID0gfmZsaXBwZXJfbGVuZ3RoX21tLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gfnNleCwgY29sb3JzID0gLi4uKQ0KcGVuZ3VpbnNfc2NhdHRlcl9jb2xvdXJzDQpgYGANCg0KKkhpbnQ6IFlvdSB3aWxsIG5lZWQgYSBjb21iaW5hdGlvbiBvZiB0d28gY29sb3Vycy4gQ2hlY2sgdGhlIGBDb2RlYCBib3ggYmVsb3cgaWYgeW91IGFyZSBzdHVjay4qDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUiLCBldmFsID0gRiwgZWNobyA9IFQsIHdhcm5pbmcgPSBGLCBtZXNzYWdlID0gRn0NCiMgSWYgeW91IGFyZSBzcGVjaWZ5aW5nIHNwZWNpZmljIGluZGl2aWR1YWwgY29sb3VycywgeW91IHdpbGwgbmVlZCB0byB1c2UgdGhlIGxheW91dCANCmNvbG9ycyA9IGMoIi4uLiIsICIuLi4iKS4NCmBgYA0KDQojIw0KDQpJZiB5b3UgZG8gbm90IHdhbnQgdG8gc3BlbmQgdG9vIG11Y2ggdGltZSBjdXN0b21pc2luZyB0aGUgY29sb3VycyB1c2VkIGluIHlvdXIgcGxvdHMsIHRoZXJlIGFyZSBwcmUtZXhpc3Rpbmcgc2V0cyBvZiBjb2xvdXJzIHlvdSBjYW4gdXNlLiBUcnkgc2V0dGluZyB5b3VyIGBjb2xvcnMgPS4uLmAgYXJndW1lbnQgaW4gXEByZWYoc2NhdHRlcmNvbG91cnMpIHNlcXVlbnRpYWxseSB0byBgY29sb3JzID0gIlNldDEiYCwgdGhlbiB0byBgY29sb3JzID0gIlNldDIiYCBhbmQgZmluYWxseSB0byBgY29sb3JzID0gIlNldDMiYC4gRG8gYW55IHBhcnRpY3VsYXIgc2V0cyBhcHBlYWwgdG8geW91Pw0KDQojIw0KDQpUaGVyZSBhcmUgbWFueSBkaWZmZXJlbnQgZGlzcGxheSBvcHRpb25zIGZvciBgcGxvdF9seWAgZ3JhcGhpY3MsIGFuZCBpZiB5b3UgdHJ5IHJ1bm5pbmcgdGhlIFIgY29tbWFuZHMNCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBGLCBlY2hvID0gVH0NCnBlbmd1aW5zX3NjYXR0ZXIyIDwtIHBsb3RfbHkoZGF0YSA9IHBlbmd1aW5zLCB4ID0gfmJvZHlfbWFzc19nLCB5ID0gfmZsaXBwZXJfbGVuZ3RoX21tLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSB+c2V4LCBjb2xvcnMgPSAiU2V0MSIpDQpwZW5ndWluc19zY2F0dGVyMg0KYGBgDQoNCnlvdSBtYXkgc2VlIHNvbWUgcmVkIGBXYXJuaW5nIG1lc3NhZ2VzYCBhcHBlYXIgaW4gdGhlIFIgQ29uc29sZS4gT2Z0ZW4sIHlvdSBkb24ndCBoYXZlIHRvIHdvcnJ5IGFib3V0IHRoZXNlLCBidXQgaWYgeW91IHdvdWxkIGxpa2UgdG8gbWluaW1pc2UgdGhlbSwgeW91IGNhbiBhZGQgdGhlIGZvbGxvd2luZyBhcmd1bWVudHMgdG8geW91ciBgcGxvdF9seWAgZnVuY3Rpb24uDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gRiwgZWNobyA9IFR9DQpwZW5ndWluc19zY2F0dGVyMiA8LSBwbG90X2x5KGRhdGEgPSBwZW5ndWlucywgeCA9IH5ib2R5X21hc3NfZywgeSA9IH5mbGlwcGVyX2xlbmd0aF9tbSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gfnNleCwgY29sb3JzID0gIlNldDEiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gInNjYXR0ZXIiLCBtb2RlID0gIm1hcmtlcnMiKQ0KcGVuZ3VpbnNfc2NhdHRlcjINCmBgYA0KDQpIZXJlLCB3ZSBoYXZlIGluY2x1ZGVkIHRoZSBhZGRpdGlvbmFsIGFyZ3VtZW50cyBgdHlwZSA9IC4uLmAgYW5kIGBtb2RlID0gLi4uYC4NCg0KKiBXZSBzZXQgYHR5cGUgPSAic2NhdHRlciJgIHRvIGVuc3VyZSBvdXIgZGF0YSBpcyBwbG90dGVkIGFzIGEgc2NhdHRlciBwbG90Lg0KKiBXZSBzZXQgYG1vZGUgPSAibWFya2VycyJgIHRvIGVuc3VyZSB0aGF0IGVhY2ggb2Ygb3VyIGRhdGEgcG9pbnRzIGlzIHBsb3R0ZWQgaW5kaXZpZHVhbGx5Lg0KDQpUaGVzZSBhZGRpdGlvbmFsIGFyZ3VtZW50cyBhcmUgb2Z0ZW4gaGVscGZ1bCwgYXMgc29tZXRpbWVzIHdlIGxpa2UgdG8gaGF2ZSBhIGxpdHRsZSBtb3JlIGNvbnRyb2wgb3ZlciBob3cgb3VyIGRhdGEgaXMgcHJlc2VudGVkLg0KDQpZb3UnbGwgbm90aWNlIGhvd2V2ZXIgdGhhdCBpZiB0aGVzZSBjb21tYW5kcyBhcmUgb21pdHRlZCBmcm9tIHlvdXIgZnVuY3Rpb24sIFIgd2lsbCBqdXN0IHdvcmsgb3V0IHdoYXQgaXQgdGhpbmtzIGlzIHRoZSBvcHRpbWFsIHByZXNlbnRhdGlvbiBmb3JtYXQgKGhlbmNlIHRoZSB3YXJuaW5nIG1lc3NhZ2VzIGluZm9ybWluZyB1cyB3aGljaCBvcHRpb25zIFIgaGFzIHNlbGVjdGVkLCBzaW5jZSBzb21lIGRldGFpbHMgaGF2ZW4ndCBiZWVuIHVzZXItc3BlY2lmaWVkKS4NCg0KVGhpcyBpcyBvZnRlbiBmb3IgdGhlIGJlc3QgLSB0cnkgY2hhbmdpbmcgdGhlIGBtb2RlID0gIm1hcmtlcnMiYCBzZWN0aW9uIG9mIGNvZGUgdG8gYG1vZGUgPSJsaW5lcyJgIGFuZCB0aGVuIHJlLXJ1bm5pbmcgdGhlIHBsb3QuIFdoYXQgaGFwcGVucz8NCg0KIyMgeyNzY2F0dGVyc3ltYm9sfQ0KDQpTbyBmYXIsIHdlIGhhdmUgdHJlYXRlZCBhbGwgdGhlIHBlbmd1aW5zIGFzIG9uZSBsYXJnZSBncm91cCwgZGlmZmVyZW50aWF0ZWQgYnkgYHNleGAuIEhvd2V2ZXIsIHdlIGFjdHVhbGx5IGhhdmUgZGF0YSBmb3IgdGhyZWUgc2VwYXJhdGUgc3BlY2llcyBvZiBwZW5ndWluIC0gYEFkZWxpZWAsIGBDaGluc3RyYXBgLCBhbmQgYEdlbnRvb2AuDQoNCldlIGhhdmUgYWxyZWFkeSB1c2VkIGRpZmZlcmVudCBjb2xvdXJzIHRvIGRpZmZlcmVudGlhdGUgdGhlIG1hbGUgYW5kIGZlbWFsZSBwZW5ndWlucywgYnV0IHNvIGZhciBhbGwgdGhlIGRhdGEgcG9pbnRzIGFyZSB0aGUgc2FtZSBzeW1ib2wgLSBhIGRvdC4gV2UgY2FuIHVzZSB0aGUgYWRkaXRpb25hbCBhcmd1bWVudCBgc3ltYm9sID0gLi4uYCB3aXRoaW4gb3VyIGBwbG90X2x5YCBmdW5jdGlvbiB0byBmdXJ0aGVyIGltcHJvdmUgb3VyIGdyYXBoLCBhbmQgZGlzdGluZ3Vpc2ggYmV0d2VlbiB0aGUgZGlmZmVyZW50IHNwZWNpZXMgb2YgcGVuZ3Vpbi4gDQoNClRha2UgYSBsb29rIGF0IHRoZSBSIGNvZGUgYW5kIHJlc3VsdGFudCBncmFwaCBiZWxvdzoNCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBGLCBlY2hvID0gVH0NCnBlbmd1aW5zX3NjYXR0ZXIzIDwtIHBsb3RfbHkoZGF0YSA9IHBlbmd1aW5zLCB4ID0gfmJvZHlfbWFzc19nLCB5ID0gfmZsaXBwZXJfbGVuZ3RoX21tLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSB+c2V4LCBjb2xvcnMgPSAiU2V0MSIsIHN5bWJvbCA9IH5zcGVjaWVzLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZSA9ICJzY2F0dGVyIiwgbW9kZSA9ICJtYXJrZXJzIikNCnBlbmd1aW5zX3NjYXR0ZXIzDQpgYGANCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gRiwgd2FybmluZyA9IEYsIG1lc3NhZ2UgPSBGLCBmaWcuYWxpZ24gPSAiY2VudGVyIn0NCnBlbmd1aW5zX3NjYXR0ZXIzIDwtIHBsb3RfbHkoZGF0YSA9IHJlbW92ZV9taXNzaW5nKHBlbmd1aW5zKSwgeCA9IH5ib2R5X21hc3NfZywgeSA9IH5mbGlwcGVyX2xlbmd0aF9tbSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gfnNleCwgY29sb3JzID0gIlNldDEiLCBzeW1ib2wgPSB+c3BlY2llcywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGUgPSAic2NhdHRlciIsIG1vZGUgPSAibWFya2VycyIpDQoNCnBlbmd1aW5zX3NjYXR0ZXIzDQpgYGANCg0KR3JlYXQhIFRoaXMgaXMgbG9va2luZyBtdWNoIG1vcmUgaW5mb3JtYXRpdmUgdGhhbiBvdXIgaW5pdGlhbCBzY2F0dGVyIHBsb3QuIE5vdyBpdCdzIHF1aXRlIGNsZWFyIGZvciBpbnN0YW5jZSB0aGF0IHRoZSBtYWpvcml0eSBvZiBsYXJnZXIgcGVuZ3VpbnMgKGJvdGggbWFsZSBhbmQgZmVtYWxlKSBhcmUgb2YgdGhlIEdlbnRvbyBzcGVjaWVzLCB3aGljaCB3ZSBjb3VsZG4ndCBkaXNjZXJuIGZyb20gb3VyIHByZXZpb3VzIHZlcnNpb24gb2YgdGhlIHNjYXR0ZXIgcGxvdC4NCg0KIyMNCg0KSnVzdCBhcyBSIGhhcyBtYW55IGNvbG91ciBvcHRpb25zIGF2YWlsYWJsZSwgc28gdG9vIGFyZSB0aGVyZSBtYW55IHN5bWJvbCBvcHRpb25zIGF2YWlsYWJsZS4gU2luY2Ugd2UgaGF2ZSBub3Qgc3BlY2lmaWVkIHdoaWNoIHNwZWNpZmljIHN5bWJvbHMgdG8gdXNlIGluIFxAcmVmKHNjYXR0ZXJzeW1ib2wpLCBSIGhhcyB1c2VkIHRoZSBmaXJzdCBkZWZhdWx0IDMuDQoNCldlIHVzZWQgYGNvbG9ycyA9IC4uLmAgdG8gbW9kaWZ5IG91ciBgY29sb3IgPSAuLi5gIHNwZWNpZmljYXRpb24sIGFuZCBzaW1pbGFybHksIHdlIGNhbiB1c2UgYHN5bWJvbHMgPSAuLi5gIHRvIG1vZGlmeSBvdXIgYHN5bWJvbCA9IC4uLmAgc3BlY2lmaWNhdGlvbi4gDQoNClRoZXJlIGFyZSAyNiBkaWZmZXJlbnQgYmFzZSBSIHN5bWJvbHMgeW91IGNhbiBjaG9vc2UgZnJvbSAtIHRoZXNlIGNhbiBiZSBzcGVjaWZpZWQgZWl0aGVyIGJ5IG51bWJlciwgb3IgYnkgbmFtZS4gU29tZSBvZiB0aGUgbmFtZXMgYXJlIHF1aXRlIGxvbmcsIGUuZy4gYCJmaWxsZWQgdHJpYW5nbGUgcG9pbnQtdXAiYCwgc28gaXQgaXMgb2Z0ZW4gZWFzaWVyIHRvIHVzZSBudW1iZXJzLiBIb3dldmVyLCBzb21lIG5hbWVzIGFyZSBlYXN5IHRvIHJlbWVtYmVyIC0gdGFrZSBhIGxvb2sgYXQgdGhlIHRhYmxlIGJlbG93Lg0KDQpgYGB7ciwgZWNobz1GLCBsYWJlbCA9ICJ0YWJsZSJ9DQpyb3cwIDwtIGMoIioqTnVtYmVyKioiLCAiKipOYW1lKioiKQ0Kcm93MSA8LSBjKDAsICJzcXVhcmUiKQ0Kcm93MiA8LSBjKDEsICJjaXJjbGUiKQ0Kcm93MyA8LSBjKDIsICJ0cmlhbmdsZSBwb2ludCB1cCIpDQpyb3c0IDwtIGMoMywgInBsdXMiKQ0Kcm93NSA8LSBjKDQsICJjcm9zcyIpDQpyb3c2IDwtIGMoNSwgImRpYW1vbmQiKQ0Kcm93NyA8LSBjKDgsICJzdGFyIikgDQptYXQgPC0gbWF0cml4KGMocm93MCwgcm93MSwgcm93Miwgcm93Mywgcm93NCwgcm93NSwgcm93Niwgcm93NyksIG5yb3cgPSA4LCBieXJvdyA9IFRSVUUpDQoNCmtuaXRyOjprYWJsZSgNCiAgbWF0LCANCiAgYm9va3RhYnMgPSBGQUxTRSwNCiAgY2FwdGlvbiA9ICdTeW1ib2wgT3B0aW9ucycNCikNCmBgYA0KDQp1c2luZyBcQHJlZih0YWI6dGFibGUpIGFuZCB0aGUgYHN5bWJvbHMgPSAuLi5gIGFyZ3VtZW50LCBjaGFuZ2UgdGhlIHN5bWJvbHMgdXNlZCBpbiB0aGUgYHBlbmd1aW5zX3NjYXR0ZXIzYCBzY2F0dGVyIHBsb3QgY3JlYXRlZCBpbiBcQHJlZihzY2F0dGVyc3ltYm9sKS4NCg0KKkhpbnQ6IElmIHlvdSBhcmUgdXNpbmcgc3ltYm9sIG5hbWVzLCBhbmQgeW91ciBjb2RlIGlzbid0IHdvcmtpbmcsIGNoZWNrIHRoZSBjb2RlIGNodW5rIGJlbG93LioNCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSIsIGV2YWwgPSBGLCBlY2hvID0gVH0NCiMgTm90ZSB0aGF0IGp1c3QgbGlrZSBmb3IgdGhlIGNvbG91cnMgYXJndW1lbnQsIGlmIHlvdSBhcmUgdXNpbmcgd29yZHMsIA0KIyB0aGVzZSBuZWVkIHRvIGJlIHN1cnJvdW5kZWQgd2l0aCBxdW90YXRpb24gbWFya3MsDQojIGUuZy4gInNxdWFyZSIsIG9yICdzcXVhcmUnIHdpbGwgd29yaywgYnV0IHNxdWFyZSB3aWxsIG5vdA0KYGBgDQoNCiMjDQoNCkFzIGEgZmluYWwgdG91Y2gsIHlvdSBtYXkgYWxzbyBsaWtlIHRvIGNoYW5nZSB0aGUgc2l6ZSBvZiB0aGUgc3ltYm9scyBpbiB5b3VyIHNjYXR0ZXIgcGxvdC4gDQpUbyBkbyBzbywgd2UgY2FuIGluY2x1ZGUgdGhlIGBtYXJrZXIgPSAuLi5gIGFyZ3VtZW50IGluIG91ciBgcGxvdF9seWAgZnVuY3Rpb24uDQoNClRoaXMgaXMgYSBsaXR0bGUgbW9yZSBjb21wbGljYXRlZCB0byB1c2UgdGhhbiBvdXIgcHJldmlvdXMgYXJndW1lbnRzLCBhcyBtdWx0aXBsZSBzcGVjaWZpY2F0aW9ucyBjYW4gYmUgbWFkZSB3aXRoaW4gdGhpcyBhcmd1bWVudC4gQXMgYSByZXN1bHQsIHdlIHVzZSB0aGUgZm9ybWF0IGBtYXJrZXIgPSBsaXN0KC4uLilgLiBXaXRoaW4gdGhlIGBsaXN0KClgIGZ1bmN0aW9uLCB3ZSBjYW4gaW5jbHVkZSBtdWx0aXBsZSBzcGVjaWZpY2F0aW9ucyB3aGljaCBhbGwgcGVydGFpbiB0byB0aGUgYG1hcmtlcmAgYXJndW1lbnQuDQoNClRvIGNoYW5nZSB0aGUgc2l6ZSBvZiB0aGUgc3ltYm9scywgd2UgdXNlIHRoZSBhcHByb3ByaWF0ZWx5IG5hbWVkIGBzaXplID0gYCBhcmd1bWVudCwgd2l0aGluIHRoZSBgbGlzdCgpYCBmdW5jdGlvbi4NCkFzIGEgcmVzdWx0LCBpZiB3ZSB3YW50IHRvIGNoYW5nZSB0aGUgZGVmYXVsdCBtYXJrZXIgc2l6ZSAoNikgdG8gYmUgYSBsaXR0bGUgbGFyZ2VyLCB3ZSBjb3VsZCBpbmNsdWRlIHRoZSBhcmd1bWVudA0KYG1hcmtlciA9IGxpc3Qoc2l6ZSA9IDgpYCB3aXRoaW4gb3VyIGBwbG90X2x5YCBmdW5jdGlvbiBmb3Igb3VyIGBwZW5ndWluc19zY2F0dGVyM2Agc2NhdHRlciBwbG90IGNyZWF0ZWQgaW4gXEByZWYoc2NhdHRlcnN5bWJvbCkuIA0KDQpUcnkgdGhpcyBub3csIG9ic2VydmUgdGhlIGNoYW5nZXMsIGFuZCB0aGVuIHRyeSBpbmNyZWFzaW5nIGFuZCBkZWNyZWFzaW5nIHRoZSBtYXJrZXIgc2l6ZS4NCg0KDQojIENyZWF0aW5nIHlvdXIgb3duIFBsb3RseSBTY2F0dGVyIFBsb3QgeyNzY2F0dGVycGVyc29uYWx9DQoNCk5vdyB0aGF0IHdlIGhhdmUgY292ZXJlZCB0aGUgYmFzaWNzIG9mIGNyZWF0aW5nIGBwbG90bHlgIHNjYXR0ZXIgcGxvdHMgaW4gXEByZWYoc2NhdHRlciksIGl0J3MgdGltZSBmb3IgeW91IHRvIGNyZWF0ZSB5b3VyIG93biB1c2luZyB0aGUgYHBlbmd1aW5zYCBkYXRhIHNldC4NCg0KIyMNCg0KVG8gYmVnaW4sIHRyeSBjcmVhdGluZyBhIHNpbXBsZSBgcGxvdGx5YCBzY2F0dGVyIHBsb3Qgb2YgYGJpbGxfbGVuZ3RoX21tYCB2ZXJzdXMgYGJvZHlfbWFzc19nYC4NCg0KKklmIHlvdSdyZSBub3Qgc3VyZSB0aGF0IHlvdSdyZSBvbiB0aGUgcmlnaHQgdHJhY2ssIHJlZmVyIGJhY2sgdG8gXEByZWYoc2ltcGxlc2NhdHRlciksIGFuZC9vciBjaGVjayB0aGUgY29kZSBiZWxvdzoqDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUiLCBldmFsID0gRiwgZWNobyA9IFQsIGZpZy5hbGlnbiA9ICJjZW50ZXIifQ0KcGVuZ3VpbnNfc2NhdHRlcl9uZXcgPC0gcGxvdF9seShkYXRhID0gcGVuZ3VpbnMsIHggPSB+Ym9keV9tYXNzX2csIHkgPSB+Li4uDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGUgPSAic2NhdHRlciIsIG1vZGUgPSAibWFya2VycyIpDQpwZW5ndWluc19zY2F0dGVyX25ldw0KYGBgDQoNCiMjDQoNCk9uY2UgeW91IGFyZSBoYXBweSB3aXRoIHlvdXIgaW5pdGlhbCBzY2F0dGVyIHBsb3QsIHRyeSB1c2luZyB0aGUgYGNvbG9yID0gfmAgYXJndW1lbnQgdG8gZGlmZmVyZW50aWF0ZSB0aGUgZGF0YSBpbiB5b3VyIHBsb3QgYnkgYGlzbGFuZGAuIERvIHlvdSBub3RpY2UgYW55IHBhdHRlcm5zPw0KDQoqWW91IGNhbiByZWZlciBiYWNrIHRvIFxAcmVmKHNjYXR0ZXJjb2xvdXIpIGlmIHlvdSBhcmUgbm90IHN1cmUgaG93IHRvIHByb2NlZWQuKg0KDQojIw0KDQpOZXh0LCB1c2UgdGhlIGBzeW1ib2wgPSB+YCBhcmd1bWVudCB0byBzaG93IGRpZmZlcmVudCBzeW1ib2xzIGZvciBlYWNoIGBzcGVjaWVzYCBpbiB5b3VyIHBsb3QuDQoNCiMjDQoNClRvIGZpbmlzaCBvZmYgeW91ciBwbG90LCBjaGFuZ2UgdGhlIHN5bWJvbHMgaW4geW91ciBwbG90LCBhbmQgaW5jcmVhc2UgdGhlIG1hcmtlciBzaXplIG9mIHlvdXIgc3ltYm9scyBzbGlnaHRseS4NCg0KIyMNCg0KRG9lcyBpdCBzZWVtIGxpa2UgcGVuZ3VpbnMgbGl2aW5nIG9uIGRpZmZlcmVudCBpc2xhbmRzIGhhdmUgbm90aWNlYWJseSBkaWZmZXJlbnQgYGJvZHlfbWFzc19nYCBvciBgYmlsbF9sZW5ndGhfbW1gIG1lYXN1cmVtZW50cz8NCg0KDQojIE1peGVkIFN1YnBsb3RzIHsjc3VicGxvdHN9DQoNClJlY2FsbCBmcm9tIG91ciBbZmlyc3QgRGF0YSBTY2llbmNlIENvbXB1dGVyIExhYl0oaHR0cHM6Ly9ycHVicy5jb20vTFRVX1NUTTEwMDEvRFNNQ0wxX1MpIGhvdyB3ZSBjcmVhdGVkIHNvbWUgaGlzdG9ncmFtcyBmb3Igb3VyIGBwYWxtZXJwZW5ndWluc2AgZGF0YSBzZXQuIFNvbWUgb2YgdGhlIGNvZGUgdXNlZCBmb3IgdGhhdCBsYWIgaXMgcmVwcm9kdWNlZCBiZWxvdzoNCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gVCwgd2FybmluZyA9IEYsIG1lc3NhZ2UgPSBGLCBmaWcuYWxpZ24gPSAiY2VudGVyIn0NCnBlbmd1aW5faGlzdCA8LSBwbG90X2x5KGRhdGEgPSBwZW5ndWlucywgeCA9IH5ib2R5X21hc3NfZywgY29sb3IgPSB+aXNsYW5kLCB0eXBlID0gImhpc3RvZ3JhbSIsIGFscGhhID0gMC42KQ0KDQpwZW5ndWluX2hpc3QgPC0gcGVuZ3Vpbl9oaXN0ICU+JSBsYXlvdXQoeWF4aXMgPSBsaXN0KHRpdGxlID0gJ2NvdW50JyksIGJhcm1vZGUgPSJvdmVybGF5IikNCnBlbmd1aW5faGlzdA0KYGBgDQoNClN1cHBvc2UgdGhhdCB3ZSB3b3VsZCBsaWtlIHRvIHByZXNlbnQgYWxsIG91ciBgcGFsbWVycGVuZ3VpbnNgIGRhdGEgdmlzdWFsaXNhdGlvbnMgdG9nZXRoZXIuIFdlIGNhbiBkbyB0aGlzIHVzaW5nIHRoZSBgc3VicGxvdGAgZnVuY3Rpb24uDQoNCiMjIHsjc3VicGxvdHdhbGt0aHJvdWdofQ0KDQpUYWtlIGEgbG9vayBhdCB0aGUgUiBjb2RlIGJlbG93Og0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IFQsIGVjaG8gPSBULCB3YXJuaW5nID0gRiwgbWVzc2FnZSA9IEZ9DQpwZW5ndWluX2NvbWJpbmVkX3Bsb3RzIDwtIHN1YnBsb3QocGVuZ3VpbnNfc2NhdHRlcjMsIHBlbmd1aW5faGlzdCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbnJvd3MgPSAyLCBtYXJnaW4gPSAwLjA1KSANCnBlbmd1aW5fY29tYmluZWRfcGxvdHMgPC0gcGVuZ3Vpbl9jb21iaW5lZF9wbG90cyAlPiUgDQogICAgICAgICAgICAgICAgICAgICAgICAgIGxheW91dCh0aXRsZSA9ICJQYWxtZXIgUGVuZ3VpbiBEYXRhIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHhheGlzID0gbGlzdCh0aXRsZSA9ICdib2R5X21hc3NfZycpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICJmbGlwcGVyX2xlbmd0aF9tbSIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeGF4aXMyID0gbGlzdCh0aXRsZSA9ICdib2R5X21hc3NfZycpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHlheGlzMiA9IGxpc3QodGl0bGUgPSAiY291bnQiKSkNCmBgYA0KDQpOb3RlIHRoYXQgaGVyZToNCg0KKiBXZSBhcmUgdXNpbmcgdGhlIGBzdWJwbG90YCBjb21tYW5kIHRvIHBsb3QgdGhlIGBwZW5ndWluc19zY2F0dGVyM2AgYW5kIGBwZW5ndWluX2hpc3RgIHBsb3RzIHRvZ2V0aGVyLg0KKiBUaGUgYG5yb3dzID0gMmAgYXJndW1lbnQgdGVsbHMgUiB0byBwcm9kdWNlIHRoZXNlIHBsb3RzIGluIDIgcm93cy4NCiogVGhlIGBtYXJnaW4gPSAwLjA1YCBhcmd1bWVudCB0ZWxscyBSIHRvIGxlYXZlIGEgc21hbGwgbWFyZ2luIGJldHdlZW4gdGhlIHR3byBwbG90cy4NCiogVGhlIHN1YnNlcXVlbnQgbGluZXMgb2YgY29kZSBhcmUgdXNlZCB0byBhZGQgYSB0aXRsZSB0byBvdXIgc2VsZWN0aW9uIG9mIHBsb3RzLCBhbmQgYWRkIGF4ZXMgbGFiZWxzIHRvIHRoZSBwbG90cyAtIG5vdGUgdGhhdCB3ZSB1c2UgYHhheGlzYCB0byBkZWZpbmUgdGhlIHgtYXhpcyBsYWJlbCBmb3IgdGhlIGZpcnN0IHBsb3QsIGFuZCBgeGF4aXMyYCB0byBkZWZpbmUgdGhlIHgtYXhpcyBsYWJlbCBmb3IgdGhlIHNlY29uZCBwbG90IChhbmQgc2ltaWxhcmx5IGZvciB0aGUgeS1heGVzKS4NCg0KV2hlbiB3ZSBub3cgcnVuIHRoaXMgb2JqZWN0IGBwZW5ndWluX2NvbWJpbmVkX3Bsb3RzYCwgd2Ugb2J0YWluIHRoZSBmb2xsb3dpbmc6DQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gVCwgZWNobyA9IFQsIHdhcm5pbmcgPSBGLCBtZXNzYWdlID0gRiwgZmlnLmRpbSA9IGMoMTAsIDgpLCBmaWcuYWxpZ24gPSAiY2VudGVyIn0NCnBlbmd1aW5fY29tYmluZWRfcGxvdHMNCmBgYA0KDQpOb3RlIHRoYXQgdGhlIHR3byBwbG90cyBhcmUgc3RpbGwgd2hvbGVseSBpbnRlcmFjdGl2ZS4gVGhlIGxlZ2VuZHMgaGF2ZSBiZWVuIGNvbWJpbmVkLCBhbmQgY2FuIGJlIHVzZWQgdG8gZmlsdGVyIHRoZSBpbmRpdmlkdWFsIHBsb3RzLg0KDQpXaGlsZSB3ZSBoYXZlIG9ubHkgY29tYmluZWQgdHdvIHBsb3RzIGhlcmUsIHRoZSBgc3VicGxvdGAgZnVuY3Rpb24gY2FuIGJlIHVzZWQgdG8gcHJlc2VudCBzZXZlcmFsIHBsb3RzIHRvZ2V0aGVyLCB3aGljaCBjYW4gYmUgcGFydGljdWxhcmx5IGluZm9ybWF0aXZlIHdoZW4geW91IHdvdWxkIGxpa2UgdG8gZGlzcGxheSBtdWx0aXBsZSBhc3BlY3RzIG9mIHlvdXIgZGF0YSBzaW11bHRhbmVvdXNseS4NClRoZSBvbmx5IG1ham9yIGRvd25zaWRlIG9mIHByZXNlbnRpbmcgcGxvdHMgdG9nZXRoZXIgdXNpbmcgYHN1YnBsb3RgIGlzIHRoYXQgdGhlaXIgYXhlcyBsYWJlbHMgYXJlIHJlbW92ZWQgYnkgZGVmYXVsdCwgYW5kIG11c3QgYmUgcmVzcGVjaWZpZWQsIGFzIGFib3ZlLg0KDQojIyANCg0KVXNpbmcgdGhlIGluZm9ybWF0aW9uIGZyb20gXEByZWYoc3VicGxvdHdhbGt0aHJvdWdoKSwgdHJ5IHRvIGNvbWJpbmUgdGhlIHNjYXR0ZXIgcGxvdCB5b3UgcHJvZHVjZWQgaW4gXEByZWYoc2NhdHRlcnBlcnNvbmFsKSB3aXRoIHRoZSBoaXN0b2dyYW0gc2hvd24gYWJvdmUgYXQgdGhlIHN0YXJ0IG9mIFxAcmVmKHN1YnBsb3RzKS4NCg0KKkhpbnQ6IFlvdSBkb24ndCBuZWVkIHRvIHdyaXRlIGFueSBjb2RlIGZvciB0aGUgaGlzdG9ncmFtLCB5b3UgY2FuIHNpbXBseSB1c2UgdGhlIFIgY29kZSBzaG93biBhdCB0aGUgc3RhcnQgb2YgXEByZWYoc3VicGxvdHMpLioNCg0KPGJyPg0KDQojIyMjIEdyZWF0IGpvYiwgdGhhdCdzIGV2ZXJ5dGhpbmcgZm9yIHRvZGF5ISAjIyMjIHstfQ0KDQpIb3BlZnVsbHkgeW91IG5vdyBmZWVsIGNvbmZpZGVudCBjcmVhdGluZyBwbG90bHkgc2NhdHRlciBwbG90cy4gRG9uJ3Qgd29ycnkgaWYgc29tZSBvZiB0aGUgY29kZSBzZWVtcyBkaWZmaWN1bHQgYXQgdGhlIG1vbWVudCAtIHdlIGFyZSBvbmx5IGF0IHRoZSBzZWNvbmQgbGFiLCBhbmQgd2Ugd2lsbCBoYXZlIHBsZW50eSBvZiB0aW1lIHRvIHByYWN0aWNlIGFuZCBpbXByb3ZlIGFzIHRoZSBzZW1lc3RlciBwcm9ncmVzc2VzLg0KDQpCZWZvcmUgeW91IGZpbmlzaCB1cCwgbWFrZSBzdXJlIHRvIHNhdmUgeW91ciBzY3JpcHQgZmlsZSBzb21ld2hlcmUgc2FmZSAtIGl0IG1pZ2h0IGNvbWUgaW4gaGFuZHkgbGF0ZXIgb24uIA0KDQo8YnI+DQoNCiMgUmVmZXJlbmNlcyB7LSAjUmVmfQ0KPGRpdiBpZD0icmVmcyI+PC9kaXY+DQoNCjxicj4NCg0KPGZvbnQgY29sb3IgPSAiZ3JleSI+DQpUaGVzZSBub3RlcyBoYXZlIGJlZW4gcHJlcGFyZWQgYnkgUnVwZXJ0IEt1dmVrZS4gVGhlIGNvcHlyaWdodCBmb3IgdGhlIG1hdGVyaWFsIGluIHRoZXNlIG5vdGVzIHJlc2lkZXMgd2l0aCB0aGUgYXV0aG9yIG5hbWVkIGFib3ZlLCB3aXRoIHRoZSBEZXBhcnRtZW50IG9mIE1hdGhlbWF0aWNhbCBhbmQgUGh5c2ljYWwgU2NpZW5jZXMgYW5kIHdpdGggTGEgVHJvYmUgVW5pdmVyc2l0eS4gQ29weXJpZ2h0IGluIHRoaXMgd29yayBpcyB2ZXN0ZWQgaW4gTGEgVHJvYmUgVW5pdmVyc2l0eSBpbmNsdWRpbmcgYWxsIExhIFRyb2JlIFVuaXZlcnNpdHkgYnJhbmRpbmcgYW5kIG5hbWluZy4gVW5sZXNzIG90aGVyd2lzZSBzdGF0ZWQsIG1hdGVyaWFsIHdpdGhpbiB0aGlzIHdvcmsgaXMgbGljZW5zZWQgdW5kZXIgYSBDcmVhdGl2ZSBDb21tb25zIEF0dHJpYnV0aW9uLU5vbiBDb21tZXJjaWFsLU5vbiBEZXJpdmF0aXZlcyBMaWNlbnNlIA0KPGEgaHJlZiA9ICJodHRwczovL2NyZWF0aXZlY29tbW9ucy5vcmcvbGljZW5zZXMvYnktbmMtbmQvNC4wL0NDIiB0YXJnZXQ9Il9ibGFuayI+IEJZLU5DLU5ELiA8L2E+DQo8L2ZvbnQ+