Data Science Stream

Topic 3B: Data Visualisation II


Welcome to the third computer lab for the Data Science stream of STM1001.

Previously, in the second Data Science computer lab, we familiarised ourselves with the plotly function, and made some informative and interactive histograms and scatter plots of data from the palmerpenguins package (Horst, Hill, and Gorman 2020).

In this computer lab we will focus on further developing our plotly (Sievert 2020) and R coding skills, and cover how to create interactive box plots and violin plots. These plots were introduced in Topic 2.

By the end of this lab, you should feel comfortable using plotly to create a range of interactive data visualisations in RStudio.

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


🏫 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 Preparations

🏡 Before we begin, we will need to carry out some initial preparations.

1.1

🏡 First, we will need to load all the requisite packages in RStudio.

By now, you should have the palmerpenguins and plotly packages installed. Open up RStudio and load these packages now.

Note: If for whatever reason you do not have one or both of these packages installed on your current device, just click the Code button below to see the relevant code you will need to run in RStudio.

install.packages("palmerpenguins")
install.packages("plotly")

Note: If you need a quick refresher on how to load packages in RStudio, just click the Code button below.

library(palmerpenguins)
library(plotly)

2 Creating Interactive Box Plots in RStudio

💻 Recall that we can obtain some key summary information on the penguins data from the palmerpenguins package using the function summary, as shown below:

summary(penguins)
##       species          island    bill_length_mm  bill_depth_mm  
##  Adelie   :152   Biscoe   :168   Min.   :32.10   Min.   :13.10  
##  Chinstrap: 68   Dream    :124   1st Qu.:39.23   1st Qu.:15.60  
##  Gentoo   :124   Torgersen: 52   Median :44.45   Median :17.30  
##                                  Mean   :43.92   Mean   :17.15  
##                                  3rd Qu.:48.50   3rd Qu.:18.70  
##                                  Max.   :59.60   Max.   :21.50  
##                                  NA's   :2       NA's   :2      
##  flipper_length_mm  body_mass_g       sex           year     
##  Min.   :172.0     Min.   :2700   female:165   Min.   :2007  
##  1st Qu.:190.0     1st Qu.:3550   male  :168   1st Qu.:2007  
##  Median :197.0     Median :4050   NA's  : 11   Median :2008  
##  Mean   :200.9     Mean   :4202                Mean   :2008  
##  3rd Qu.:213.0     3rd Qu.:4750                3rd Qu.:2009  
##  Max.   :231.0     Max.   :6300                Max.   :2009  
##  NA's   :2         NA's   :2

Rather than showing this information as numbers, we can use box plots to visually present the key information for the numeric variables in this data set.

Note: Refer to Section 5.2 of Topic 2 for details on box plots.

2.1

💻 Recall that we can create a simple box plot in RStudio using the built-in R function boxplot, as shown below:

boxplot(penguins$body_mass_g)

This box plot leaves much to be desired, and is a little underwhelming. Let’s see what we can do using the plotly package instead.

Note: As we create box plots using plotly, several red Warning messages may appear in the RStudio Console. It is safe to ignore these.

2.2

💻 Recall from the second Data Science computer lab that the typical composition of a simple plotly plot looks like this:

plot_name <- plot_ly(data = ..., x = ~ ..., y = ~ ..., type = ...)

Using this as a base, we can create a simple plotly box plot (as shown below) using the following code:

penguins_box <- plot_ly(data = penguins, y = ~body_mass_g, type = "box")
penguins_box

Note: Here type = "box" tells plotly to create a box plot, similar to how we used type = "scatter" to plot data as a scatter plot in the second Data Science computer lab.

2.3

💻 The plotly box plot in 2.2 looks better than the one created using the built-in boxplot function, and if we hover over it we can observe different informative details like the minimum, median, maximum, and first and third quartiles.

However, notice how the term trace 0 appears when you hover over the plotly box plot? We can replace this with a more informative term, by adding the argument x0 = ... in our code. For example, run the R code below to change trace 0 to body mass (g), and assess the result:

penguins_box <- plot_ly(data = penguins, 
                        y = ~body_mass_g, 
                        type = "box", 
                        x0 = "body mass (g)")
penguins_box

2.4

💻 While this is a good start, currently our box plot does not tell us about the distribution of body mass values across the male and female penguins, or across the different species.

Let’s see how we can add this information to our box plot.

Run the R code below to split the box plot of body_mass_g into separate box plots for male and female penguins:

penguins_box <- plot_ly(data = penguins, 
                        y = ~body_mass_g,
                        color = ~sex, 
                        type = "box")
penguins_box

Note: We no longer need to use the x0 argument here, as plotly now uses the values within the sex variable.

2.5

💻 What do you observe about the distribution of body_mass_g values across the male and female penguins? Would you say that the distributions are symmetric or skewed?


🎧 Online students 💬 Leave a comment about your results in the chat.


2.6

💻 Our box plot is looking better, but we can improve it further by segmenting the data by species.

We can add the species information into our box plot (as shown below), using the following code:

penguins_box <- plot_ly(data = penguins, 
                        x = ~species, y = ~body_mass_g, 
                        color = ~sex, type = "box")
penguins_box

2.7

💻 But wait, the box plots for the males and females of each species are overlapping, which doesn’t look great!

Fortunately, we can fix this easily by changing the layout specifications for the box plot. Run the code below, and observe what happens:

penguins_box %>% layout(boxmode = "group")

Note: Don’t worry about the warning messages that appear when running this code.

2.8

💻 Write a short summary statement discussing the notable features of the 2.7 box plots.


🎧 Online students 💬 Post a short summary of the box plots’ notable features in the chat.


🏡 Reconvene in main room to discuss results


3 Piping

💻 You may have noticed that we used the pipe operator in 2.71. Recall from Section 4.1 of the Data Visualisation in R supplement that the pipe operator can be used to chain together a sequence of operations, in an intuitive manner which is typically easier to read than alternative methods.

In 2.7 we used piping to add additional details to an existing object, without needing to define a new object.

Note: Before you continue with this lab, make sure you have read over Section 4.1 of the Data Visualisation in R supplement.

3.1

💻 Suppose that we would like to add a title to our grouped box plots from 2.7.

Instead of rewriting our penguins_box object and assigning the output to a new object (e.g. penguins_box2), we could use the pipe operator to add this information directly to penguins_box.

The code below does just this:

penguins_box %>% layout(title = "Box Plots of Penguin body mass Data", 
                        boxmode = "group")

3.2

💻 We can also add a title to our legend. This can often help to make our graphs more informative. Try running the code below, and check the result:

penguins_box %>% layout(title = "Box Plots of Penguin body mass Data", 
                        boxmode = "group",
                        legend=list(title=list(text='Sex')))

3.3

💻 Notice that in the 3.2 code, we were able to use the layout function to add details to multiple components of our plot. Generally, when we make changes to plotly plots via piping, we are making changes to the layout, rather than the core data being visualised.

Within the layout function, we have used the argument title (the function of which is to, rather appropriately, change the title). This is one of many possible arguments - some you will learn as we develop our understanding of plotly, and some you may never use, as they are quite context specific. Typically though, the names of the arguments are clear and easy to remember - for instance, legend allows us to change details in the legend.

3.4

💻 To conclude this example, suppose that we would like to rename the x-axis and y-axis of penguins_box. The default names are ok, but perhaps we would like something a little different. Run the code below and assess the results.

penguins_box %>% layout(xaxis = list(title = "Penguin Species"),
                        yaxis = list(title = "Penguin Body Mass (grams)"),
                        boxmode = "group",
                        legend=list(title=list(text='Sex')))

3.5

💻 Notice that we have included the list function within our layout function coding in 3.4. The xaxis and yaxis arguments can both take several settings - for example, we could change the x-axis title, and font size. A list function structure is a typical requirement for layout arguments (the title in 3.1 was an exception).

Therefore, please keep in mind that generally speaking, in the context of our plotly graphs, when dealing with the layout function we need to use the list function before specifying our desired changes to layout arguments.

3.6

💻 As a final note, it’s worth pointing out that our main title from 3.1 has disappeared in our new plot in 3.4. This is because we did not assign our enhanced plot to a new object.

When we use piping, we are not modifying the original object, but rather are carrying out operations on/with it. Therefore any changes we implement via piping are not saved to the original object.

4 Creating Interactive Violin Plots in RStudio

💻 Let us now use our plotly and piping skills to create another type of plot, the violin plot.

We can think of violin plots as being an extension of box plots, which also show the density of the observations (a bit like a smoothed version of a histogram).

Note: Refer to Section 5.3 of Topic 2 for details on violin plots.

4.1

💻 We can use the code from 2.3 as a good starting point for our first violin plot, although we will need to replace the type = 'box' specification with…you guessed it - type = 'violin'.

Run the R code below to produce our first violin plot:

penguins_violin <- plot_ly(data = penguins, 
                           y = ~body_mass_g, 
                           type = "violin", 
                           x0 = "body mass (g)",
                           box = list(visible = T ))
penguins_violin

Note: We include the argument box = list(visible = T ) to ensure the box plot of the data also appears in the violin plot.

4.2

💻 Let us now start making our violin plot more informative. Using the code in 2.6 as a guide, break the violin plot in 4.1 into separate violin plots for each species of penguin.

Hint: If you are stuck on this and not sure how to proceed, check the Code chunk below:

penguins_violin <- plot_ly(data = penguins, 
                           x = ~species, # this is the line we add
                           y = ~body_mass_g, 
                           type = 'violin',
                           box = list(visible = T )) 
penguins_violin

4.3

💻 Next, let’s split these violin plots into separate ones for male and female penguins. To do this, we can add either the argument color =~ sex, or the argument split = ~sex. Choose one, and modify your penguins_violin object accordingly.

4.4

💻 Unfortunately, using either option in 4.3 results in our violin plots overlapping like in 2.6.

Fortunately, we can address this using our new piping skills.

Using the code in 2.7 and 3.1 as a guide, pipe additional details to your penguins_violin object so that the violin plots for the male and female penguins of each species are next to each in separate lanes, rather than overlapping.

Hint: You will have to change the boxmode= "group" code used in the layout parts of 2.7 and 3.1 - think about what type of plot you are considering now.

4.5

💻 To finish up, use piping to add an appropriate title to your grouped violin plots graph.


🏡 Reconvene in main room to discuss results


5 Extension: Creating your own plotly plots

💡 Now that you have had a chance to practice creating interactive box plots and violin plots using plotly, it is time to make your own.

Using all the skills you have gained from this lab, create a set of either box plots or violin plots (or both if you would like) with the following characteristics:

  • The plots should show information on the bill_length of the penguins
  • The plots should be grouped by the sex of the penguin
  • The plots should be coloured according to the island the penguin inhabits
  • The plots should be split according to the species of the penguin
  • The hover text should show the island the penguin inhabits
  • The plots should have informative axes and legend labels, and an informative title

See how you go, and if you get stuck, remember to ask your lab demonstrator for help. Good luck!


🎧 Online students 💬 If your breakout room group had time to create your own Plotly penguin plot in Question 5, take a snippet/screenshot of it and copy-paste it into the chat.


🏡 Discuss results in main room and conclude lab


Well done! There was a lot of content today.

Don’t worry if you weren’t able to finish everything in the one session - there is quite of lot of material to work through in this lab, and it’s not easy.

Hopefully though, you are beginning to feel quite skilled with using plotly. The techniques and coding skills you are learning should hold you in good stead for the following weeks. Remember, you can always refer back to this material at a later date if you need a quick refresher.

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.


  1. We used it a couple of times in the second Data Science computer lab too↩︎

LS0tDQp0aXRsZTogIlNUTTEwMDE6IENvbXB1dGVyIExhYiAzQiINCm91dHB1dDoNCiAgYm9va2Rvd246Omh0bWxfZG9jdW1lbnQyOiANCiAgICB0b2M6IHRydWUNCiAgICB0b2NfZmxvYXQ6IHRydWUNCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQogICAgdGhlbWU6IHJlYWRhYmxlDQogICAgY29kZV9mb2xkaW5nOiBzaG93DQpiaWJsaW9ncmFwaHk6IFNUTTEwMDFfRFNfQ0xfcmVmZXJlbmNlcy5iaWIgDQpsaW5rLWNpdGF0aW9uczogeWVzDQotLS0NCg0KPHN0eWxlPg0KI1RPQyB7DQogIGJhY2tncm91bmQ6IHVybCgiaHR0cHM6Ly93d3cubGF0cm9iZS5lZHUuYXUvX21lZGlhL2xhLXRyb2JlLWFwaS92NS9pbWcvbG9nby5zdmciKTsNCiAgYmFja2dyb3VuZC1zaXplOiBjb250YWluOw0KICBwYWRkaW5nLXRvcDogODBweCAhaW1wb3J0YW50Ow0KICBiYWNrZ3JvdW5kLXJlcGVhdDogbm8tcmVwZWF0Ow0KfQ0KPC9zdHlsZT4NCg0KIyMjIERhdGEgU2NpZW5jZSBTdHJlYW0gey19DQoNCiMjIyBUb3BpYyAzQjogRGF0YSBWaXN1YWxpc2F0aW9uIElJIHstfQ0KDQo8YnI+DQoNCldlbGNvbWUgdG8gdGhlIHRoaXJkIGNvbXB1dGVyIGxhYiBmb3IgdGhlIERhdGEgU2NpZW5jZSBzdHJlYW0gb2YgU1RNMTAwMS4NCg0KUHJldmlvdXNseSwgaW4gdGhlIFtzZWNvbmQgRGF0YSBTY2llbmNlIGNvbXB1dGVyIGxhYl0oaHR0cHM6Ly9ycHVicy5jb20vTFRVX1NUTTEwMDEvRFNNQ0wyKSwgd2UgZmFtaWxpYXJpc2VkIG91cnNlbHZlcyB3aXRoIHRoZSBgcGxvdGx5YCBmdW5jdGlvbiwgYW5kIG1hZGUgc29tZSBpbmZvcm1hdGl2ZSBhbmQgaW50ZXJhY3RpdmUgaGlzdG9ncmFtcyBhbmQgc2NhdHRlciBwbG90cyBvZiBkYXRhIGZyb20gdGhlIGBwYWxtZXJwZW5ndWluc2AgcGFja2FnZSBbQHBlbmd1aW5zXS4NCg0KSW4gdGhpcyBjb21wdXRlciBsYWIgd2Ugd2lsbCBmb2N1cyBvbiBmdXJ0aGVyIGRldmVsb3Bpbmcgb3VyIGBwbG90bHlgIFtAcGxvdGx5XSBhbmQgUiBjb2Rpbmcgc2tpbGxzLCBhbmQgY292ZXIgaG93IHRvIGNyZWF0ZSBpbnRlcmFjdGl2ZSBib3ggcGxvdHMgYW5kIHZpb2xpbiBwbG90cy4gVGhlc2UgcGxvdHMgd2VyZSBpbnRyb2R1Y2VkIGluIFtUb3BpYyAyXShodHRwczovL2Jvb2tkb3duLm9yZy9hX3NoYWtlci9TVE0xMDAxX1RvcGljXzIvKS4NCg0KQnkgdGhlIGVuZCBvZiB0aGlzIGxhYiwgeW91IHNob3VsZCBmZWVsIGNvbWZvcnRhYmxlIHVzaW5nIGBwbG90bHlgIHRvIGNyZWF0ZSBhIHJhbmdlIG9mIGludGVyYWN0aXZlIGRhdGEgdmlzdWFsaXNhdGlvbnMgaW4gUlN0dWRpby4NCg0KPGRldGFpbHM+DQogIDxzdW1tYXJ5PmByIGVtbzo6amkoImhlYWRwaG9uZXMiKWAgKipPbmxpbmUgc3R1ZGVudHMqKjwvc3VtbWFyeT4NClRocm91Z2hvdXQgdGhlIGNvbXB1dGVyIGxhYiBxdWVzdGlvbiBzaGVldHMsIHlvdSB3aWxsIHNlZSBlbW9qaXMgYW5kL29yIGNvbGxhcHNpYmxlIHNlY3Rpb25zIGxpa2UgdGhpcyBvbmUuIEVhY2ggZW1vamkgaGFzIGEgcGFydGljdWxhciBtZWFuaW5nIGFuZCB3aWxsIHNvbWV0aW1lcyBiZSBhc3NvY2lhdGVkIHdpdGggYWRkaXRpb25hbCBpbnN0cnVjdGlvbnM6DQoNCioqUHJvbXB0cyBmb3IgeW91KioNCg0KYHIgZW1vOjpqaSgic3BlZWNoX2JhbGxvb24iKWAgV3JpdGUgeW91ciBhbnN3ZXIgaW4gdGhlIGNoYXQuDQoNCioqTW9kZXMgYXQgZGlmZmVyZW50IHRpbWVzIGR1cmluZyB0aGUgbGFiKioNCg0KYHIgZW1vOjpqaSgiaG91c2Vfd2l0aF9nYXJkZW4iKWAgKipNYWluIHJvb20qKi4gQWxsIHRvZ2V0aGVyIGluIHRoZSBtYWluIHJvb20g4oCTIHlvdXIgY29tcHV0ZXIgbGFiIGRlbW9uc3RyYXRvciB3aWxsIGJlIHByZXNlbnRpbmcgaW5mb3JtYXRpb24gb3IgZmFjaWxpdGF0aW5nIGNsYXNzIGRpc2N1c3Npb24NCg0KYHIgZW1vOjpqaSgiYnVsYiIpYCAqKkJyZWFrb3V0IHJvb21zKiouIFBlcnNvbiB3aXRoIGJpcnRoZGF5IGNsb3Nlc3QgdG8gKHlvdXIgY29tcHV0ZXIgbGFiIGRlbW9uc3RyYXRvciB3aWxsIHBpY2sgYSByYW5kb20gZGF0ZSkgc2hhcmVzIHRoZWlyIHNjcmVlbiBvciB3aGl0ZWJvYXJkLiBIZXJlIHlvdSB3aWxsIGRpc2N1c3MgYSBxdWVzdGlvbiB0b2dldGhlciBhbmQgYnJpbmcgeW91ciBncm91cCdzIGFuc3dlciBiYWNrIHRvIHRoZSBtYWluIHJvb20uDQoNCmByIGVtbzo6amkoImNvbXB1dGVyIilgICoqRm9jdXMgbW9kZSoqLiBZb3Ugd2lsbCBzdGlsbCBiZSBpbiB0aGUgbWFpbiByb29tLCBidXQgd29ya2luZyBpbmRlcGVuZGVudGx5LiBBbGwgc3R1ZGVudHMgd2lsbCBiZSBzaGFyaW5nIHNjcmVlbiBkdXJpbmcgdGhpcyB0aW1lIHNvIHRoYXQgeW91ciBjb21wdXRlciBsYWIgZGVtb25zdHJhdG9yIChidXQgbm90IG90aGVyIHN0dWRlbnRzKSBjYW4gc2VlIHlvdXIgc2NyZWVuLiANCg0KPC9kZXRhaWxzPiANCg0KPGJyPg0KDQo8ZGV0YWlscz4NCiAgPHN1bW1hcnk+YHIgZW1vOjpqaSgic2Nob29sIilgICoqRmFjZS10by1mYWNlIChibGVuZGVkKSBzdHVkZW50cyoqPC9zdW1tYXJ5Pg0KVGhyb3VnaG91dCB0aGUgY29tcHV0ZXIgbGFiIHF1ZXN0aW9uIHNoZWV0cywgeW91IHdpbGwgc2VlIGVtb2ppcyBhbmQvb3IgY29sbGFwc2libGUgc2VjdGlvbnMgbGlrZSB0aGlzIG9uZS4gWW91IGNhbiBpZ25vcmUgdGhlIGVtb2ppcyBhbmQgY29sbGFwc2libGUgc2VjdGlvbnMsIGFzIHRoZXkgY29udGFpbiBpbmZvcm1hdGlvbiByZWxldmFudCB0byBzdHVkZW50cyB3aG8gYXJlIHN0dWR5aW5nIG9ubGluZS4NCg0KPC9kZXRhaWxzPiANCg0KPGJyPg0KDQojIFByZXBhcmF0aW9ucyB7I2xvYWRpbmd9DQoNCmByIGVtbzo6amkoImhvdXNlX3dpdGhfZ2FyZGVuIilgIEJlZm9yZSB3ZSBiZWdpbiwgd2Ugd2lsbCBuZWVkIHRvIGNhcnJ5IG91dCBzb21lIGluaXRpYWwgcHJlcGFyYXRpb25zLg0KDQojIw0KDQpgciBlbW86OmppKCJob3VzZV93aXRoX2dhcmRlbiIpYCBGaXJzdCwgd2Ugd2lsbCBuZWVkIHRvIGxvYWQgYWxsIHRoZSByZXF1aXNpdGUgcGFja2FnZXMgaW4gUlN0dWRpby4NCg0KQnkgbm93LCB5b3Ugc2hvdWxkIGhhdmUgdGhlIGBwYWxtZXJwZW5ndWluc2AgYW5kIGBwbG90bHlgIHBhY2thZ2VzIGluc3RhbGxlZC4NCk9wZW4gdXAgUlN0dWRpbyBhbmQgbG9hZCB0aGVzZSBwYWNrYWdlcyBub3cuDQoNCipOb3RlOiBJZiBmb3Igd2hhdGV2ZXIgcmVhc29uIHlvdSBkbyBub3QgaGF2ZSBvbmUgb3IgYm90aCBvZiB0aGVzZSBwYWNrYWdlcyBpbnN0YWxsZWQgb24geW91ciBjdXJyZW50IGRldmljZSwganVzdCBjbGljayB0aGUgYENvZGVgIGJ1dHRvbiBiZWxvdyB0byBzZWUgdGhlIHJlbGV2YW50IGNvZGUgeW91IHdpbGwgbmVlZCB0byBydW4gaW4gUlN0dWRpby4qDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLWhpZGUiLCBldmFsID0gRiwgZWNobyA9IFR9DQppbnN0YWxsLnBhY2thZ2VzKCJwYWxtZXJwZW5ndWlucyIpDQppbnN0YWxsLnBhY2thZ2VzKCJwbG90bHkiKQ0KYGBgDQoNCipOb3RlOiBJZiB5b3UgbmVlZCBhIHF1aWNrIHJlZnJlc2hlciBvbiBob3cgdG8gbG9hZCBwYWNrYWdlcyBpbiBSU3R1ZGlvLCBqdXN0IGNsaWNrIHRoZSBgQ29kZWAgYnV0dG9uIGJlbG93LioNCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSIsIGV2YWwgPSBGLCBlY2hvID0gVH0NCmxpYnJhcnkocGFsbWVycGVuZ3VpbnMpDQpsaWJyYXJ5KHBsb3RseSkNCmBgYA0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IFQsIGluY2x1ZGUgPSBGfQ0KbGlicmFyeShwYWxtZXJwZW5ndWlucykNCmxpYnJhcnkocGxvdGx5KQ0KYGBgDQoNCiMgQ3JlYXRpbmcgSW50ZXJhY3RpdmUgQm94IFBsb3RzIGluIFJTdHVkaW8NCg0KYHIgZW1vOjpqaSgiY29tcHV0ZXIiKWAgUmVjYWxsIHRoYXQgd2UgY2FuIG9idGFpbiBzb21lIGtleSBzdW1tYXJ5IGluZm9ybWF0aW9uIG9uIHRoZSBgcGVuZ3VpbnNgIGRhdGEgZnJvbSB0aGUgYHBhbG1lcnBlbmd1aW5zYCBwYWNrYWdlIHVzaW5nIHRoZSBmdW5jdGlvbiBgc3VtbWFyeWAsIGFzIHNob3duIGJlbG93Og0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IFQsIGVjaG8gPSBUfQ0Kc3VtbWFyeShwZW5ndWlucykNCmBgYA0KDQpSYXRoZXIgdGhhbiBzaG93aW5nIHRoaXMgaW5mb3JtYXRpb24gYXMgbnVtYmVycywgd2UgY2FuIHVzZSAqKmJveCBwbG90cyoqIHRvIHZpc3VhbGx5IHByZXNlbnQgdGhlIGtleSBpbmZvcm1hdGlvbiBmb3IgdGhlIG51bWVyaWMgdmFyaWFibGVzIGluIHRoaXMgZGF0YSBzZXQuDQoNCipOb3RlOiBSZWZlciB0byBbU2VjdGlvbiA1LjIgb2YgVG9waWMgMl0oaHR0cHM6Ly9ib29rZG93bi5vcmcvYV9zaGFrZXIvU1RNMTAwMV9Ub3BpY18yLzUuMi1ib3hwbG90cy5odG1sKSBmb3IgZGV0YWlscyBvbiBib3ggcGxvdHMuKg0KDQoNCiMjDQoNCmByIGVtbzo6amkoImNvbXB1dGVyIilgIFJlY2FsbCB0aGF0IHdlIGNhbiBjcmVhdGUgYSBzaW1wbGUgYm94IHBsb3QgaW4gUlN0dWRpbyB1c2luZyB0aGUgYnVpbHQtaW4gUiBmdW5jdGlvbiBgYm94cGxvdGAsIGFzIHNob3duIGJlbG93Og0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IFQsIGVjaG8gPSBULCBmaWcuZGltID0gYyg1LDQpLCBmaWcuYWxpZ249J2NlbnRlcid9DQpib3hwbG90KHBlbmd1aW5zJGJvZHlfbWFzc19nKQ0KYGBgDQoNClRoaXMgYm94IHBsb3QgbGVhdmVzIG11Y2ggdG8gYmUgZGVzaXJlZCwgYW5kIGlzIGEgbGl0dGxlIHVuZGVyd2hlbG1pbmcuIExldCdzIHNlZSB3aGF0IHdlIGNhbiBkbyB1c2luZyB0aGUgYHBsb3RseWAgcGFja2FnZSBpbnN0ZWFkLg0KDQoqTm90ZTogQXMgd2UgY3JlYXRlIGJveCBwbG90cyB1c2luZyBgcGxvdGx5YCwgc2V2ZXJhbCByZWQgPHNwYW4gc3R5bGU9ImNvbG9yOnJlZCI+V2FybmluZyBtZXNzYWdlczwvc3Bhbj4gbWF5IGFwcGVhciBpbiB0aGUgUlN0dWRpbyBgQ29uc29sZWAuIEl0IGlzIHNhZmUgdG8gaWdub3JlIHRoZXNlLioNCg0KIyMgeyNib3hwbG90YmFzZX0NCg0KYHIgZW1vOjpqaSgiY29tcHV0ZXIiKWAgUmVjYWxsIGZyb20gdGhlIFtzZWNvbmQgRGF0YSBTY2llbmNlIGNvbXB1dGVyIGxhYl0oaHR0cHM6Ly9ycHVicy5jb20vTFRVX1NUTTEwMDEvRFNNQ0wyKSB0aGF0IHRoZSB0eXBpY2FsIGNvbXBvc2l0aW9uIG9mIGEgc2ltcGxlIGBwbG90bHlgIHBsb3QgbG9va3MgbGlrZSB0aGlzOg0KDQpgcGxvdF9uYW1lIDwtIHBsb3RfbHkoZGF0YSA9IC4uLiwgeCA9IH4gLi4uLCB5ID0gfiAuLi4sIHR5cGUgPSAuLi4pYA0KDQpVc2luZyB0aGlzIGFzIGEgYmFzZSwgd2UgY2FuIGNyZWF0ZSBhIHNpbXBsZSBgcGxvdGx5YCBib3ggcGxvdCAoYXMgc2hvd24gYmVsb3cpIHVzaW5nIHRoZSBmb2xsb3dpbmcgY29kZToNCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gVCwgZmlnLmFsaWduPSdjZW50ZXInLCB3YXJuaW5nID0gRn0NCnBlbmd1aW5zX2JveCA8LSBwbG90X2x5KGRhdGEgPSBwZW5ndWlucywgeSA9IH5ib2R5X21hc3NfZywgdHlwZSA9ICJib3giKQ0KcGVuZ3VpbnNfYm94DQpgYGANCg0KKk5vdGU6IEhlcmUgYHR5cGUgPSAiYm94ImAgdGVsbHMgYHBsb3RseWAgdG8gY3JlYXRlIGEgYm94IHBsb3QsIHNpbWlsYXIgdG8gaG93IHdlIHVzZWQgYHR5cGUgPSAic2NhdHRlciJgIHRvIHBsb3QgZGF0YSBhcyBhIHNjYXR0ZXIgcGxvdCBpbiAgdGhlIFtzZWNvbmQgRGF0YSBTY2llbmNlIGNvbXB1dGVyIGxhYl0oaHR0cHM6Ly9ycHVicy5jb20vTFRVX1NUTTEwMDEvRFNNQ0wyKS4qDQoNCiMjIHsjdHJhY2V9DQoNCmByIGVtbzo6amkoImNvbXB1dGVyIilgIFRoZSBgcGxvdGx5YCBib3ggcGxvdCBpbiBcQHJlZihib3hwbG90YmFzZSkgbG9va3MgYmV0dGVyIHRoYW4gdGhlIG9uZSBjcmVhdGVkIHVzaW5nIHRoZSBidWlsdC1pbiBgYm94cGxvdGAgZnVuY3Rpb24sIGFuZCBpZiB3ZSBob3ZlciBvdmVyIGl0IHdlIGNhbiBvYnNlcnZlIGRpZmZlcmVudCBpbmZvcm1hdGl2ZSBkZXRhaWxzIGxpa2UgdGhlIG1pbmltdW0sIG1lZGlhbiwgbWF4aW11bSwgYW5kIGZpcnN0IGFuZCB0aGlyZCBxdWFydGlsZXMuDQoNCkhvd2V2ZXIsIG5vdGljZSBob3cgdGhlIHRlcm0gYHRyYWNlIDBgIGFwcGVhcnMgd2hlbiB5b3UgaG92ZXIgb3ZlciB0aGUgYHBsb3RseWAgYm94IHBsb3Q/IA0KV2UgY2FuIHJlcGxhY2UgdGhpcyB3aXRoIGEgbW9yZSBpbmZvcm1hdGl2ZSB0ZXJtLCBieSBhZGRpbmcgdGhlIGFyZ3VtZW50IGB4MCA9IC4uLmAgaW4gb3VyIGNvZGUuDQpGb3IgZXhhbXBsZSwgcnVuIHRoZSBSIGNvZGUgYmVsb3cgdG8gY2hhbmdlIGB0cmFjZSAwYCB0byBgYm9keSBtYXNzIChnKWAsIGFuZCBhc3Nlc3MgdGhlIHJlc3VsdDoNCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBGLCBlY2hvID0gVCwgZmlnLmFsaWduPSdjZW50ZXInLCB3YXJuaW5nID0gRn0NCnBlbmd1aW5zX2JveCA8LSBwbG90X2x5KGRhdGEgPSBwZW5ndWlucywgDQogICAgICAgICAgICAgICAgICAgICAgICB5ID0gfmJvZHlfbWFzc19nLCANCiAgICAgICAgICAgICAgICAgICAgICAgIHR5cGUgPSAiYm94IiwgDQogICAgICAgICAgICAgICAgICAgICAgICB4MCA9ICJib2R5IG1hc3MgKGcpIikNCnBlbmd1aW5zX2JveA0KYGBgDQoNCiMjIHsjYm94cGxvdHNleH0NCg0KYHIgZW1vOjpqaSgiY29tcHV0ZXIiKWAgV2hpbGUgdGhpcyBpcyBhIGdvb2Qgc3RhcnQsIGN1cnJlbnRseSBvdXIgYm94IHBsb3QgZG9lcyBub3QgdGVsbCB1cyBhYm91dCB0aGUgZGlzdHJpYnV0aW9uIG9mIGJvZHkgbWFzcyB2YWx1ZXMgIGFjcm9zcyB0aGUgbWFsZSBhbmQgZmVtYWxlIHBlbmd1aW5zLCBvciBhY3Jvc3MgdGhlIGRpZmZlcmVudCBzcGVjaWVzLiANCg0KTGV0J3Mgc2VlIGhvdyB3ZSBjYW4gYWRkIHRoaXMgaW5mb3JtYXRpb24gdG8gb3VyIGJveCBwbG90Lg0KDQpSdW4gdGhlIFIgY29kZSBiZWxvdyB0byBzcGxpdCB0aGUgYm94IHBsb3Qgb2YgYGJvZHlfbWFzc19nYCBpbnRvIHNlcGFyYXRlIGJveCBwbG90cyBmb3IgbWFsZSBhbmQgZmVtYWxlIHBlbmd1aW5zOg0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IEYsIGVjaG8gPSBULCBmaWcuYWxpZ249J2NlbnRlcicsIHdhcm5pbmcgPSBGfQ0KcGVuZ3VpbnNfYm94IDwtIHBsb3RfbHkoZGF0YSA9IHBlbmd1aW5zLCANCiAgICAgICAgICAgICAgICAgICAgICAgIHkgPSB+Ym9keV9tYXNzX2csDQogICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IH5zZXgsIA0KICAgICAgICAgICAgICAgICAgICAgICAgdHlwZSA9ICJib3giKQ0KcGVuZ3VpbnNfYm94DQpgYGANCg0KKk5vdGU6IFdlIG5vIGxvbmdlciBuZWVkIHRvIHVzZSB0aGUgYHgwYCBhcmd1bWVudCBoZXJlLCBhcyBgcGxvdGx5YCBub3cgdXNlcyB0aGUgdmFsdWVzIHdpdGhpbiB0aGUgYHNleGAgdmFyaWFibGUuKg0KDQojIw0KDQpgciBlbW86OmppKCJjb21wdXRlciIpYCBXaGF0IGRvIHlvdSBvYnNlcnZlIGFib3V0IHRoZSBkaXN0cmlidXRpb24gb2YgYGJvZHlfbWFzc19nYCB2YWx1ZXMgYWNyb3NzIHRoZSBtYWxlIGFuZCBmZW1hbGUgcGVuZ3VpbnM/IFdvdWxkIHlvdSBzYXkgdGhhdCB0aGUgZGlzdHJpYnV0aW9ucyBhcmUgc3ltbWV0cmljIG9yIHNrZXdlZD8NCg0KPGJyPg0KDQo8ZGV0YWlscz4NCiAgPHN1bW1hcnk+YHIgZW1vOjpqaSgiaGVhZHBob25lcyIpYCAqKk9ubGluZSBzdHVkZW50cyoqPC9zdW1tYXJ5Pg0KYHIgZW1vOjpqaSgic3BlZWNoX2JhbGxvb24iKWAgIExlYXZlIGEgY29tbWVudCBhYm91dCB5b3VyIHJlc3VsdHMgaW4gdGhlIGNoYXQuDQo8L2RldGFpbHM+IA0KDQo8YnI+DQoNCiMjIHsjYm94cGxvdHNlZ21lbnR9DQoNCmByIGVtbzo6amkoImNvbXB1dGVyIilgIE91ciBib3ggcGxvdCBpcyBsb29raW5nIGJldHRlciwgYnV0IHdlIGNhbiBpbXByb3ZlIGl0IGZ1cnRoZXIgYnkgc2VnbWVudGluZyB0aGUgZGF0YSBieSBgc3BlY2llc2AuDQoNCldlIGNhbiBhZGQgdGhlIGBzcGVjaWVzYCBpbmZvcm1hdGlvbiBpbnRvIG91ciBib3ggcGxvdCAoYXMgc2hvd24gYmVsb3cpLCB1c2luZyB0aGUgZm9sbG93aW5nIGNvZGU6DQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gVCwgZWNobyA9IFQsIGZpZy5hbGlnbj0nY2VudGVyJywgd2FybmluZyA9IEZ9DQpwZW5ndWluc19ib3ggPC0gcGxvdF9seShkYXRhID0gcGVuZ3VpbnMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgeCA9IH5zcGVjaWVzLCB5ID0gfmJvZHlfbWFzc19nLCANCiAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gfnNleCwgdHlwZSA9ICJib3giKQ0KcGVuZ3VpbnNfYm94DQpgYGANCg0KIyMgeyNmaW5hbGJveHBsb3R9DQoNCmByIGVtbzo6amkoImNvbXB1dGVyIilgIEJ1dCB3YWl0LCB0aGUgYm94IHBsb3RzIGZvciB0aGUgbWFsZXMgYW5kIGZlbWFsZXMgb2YgZWFjaCBzcGVjaWVzIGFyZSBvdmVybGFwcGluZywgd2hpY2ggZG9lc24ndCBsb29rIGdyZWF0IQ0KDQpGb3J0dW5hdGVseSwgd2UgY2FuIGZpeCB0aGlzIGVhc2lseSBieSBjaGFuZ2luZyB0aGUgbGF5b3V0IHNwZWNpZmljYXRpb25zIGZvciB0aGUgYm94IHBsb3QuDQpSdW4gdGhlIGNvZGUgYmVsb3csIGFuZCBvYnNlcnZlIHdoYXQgaGFwcGVuczoNCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBGLCBlY2hvID0gVCwgZmlnLmFsaWduPSdjZW50ZXInLCB3YXJuaW5nID0gRn0NCnBlbmd1aW5zX2JveCAlPiUgbGF5b3V0KGJveG1vZGUgPSAiZ3JvdXAiKQ0KYGBgDQoNCipOb3RlOiBEb24ndCB3b3JyeSBhYm91dCB0aGUgd2FybmluZyBtZXNzYWdlcyB0aGF0IGFwcGVhciB3aGVuIHJ1bm5pbmcgdGhpcyBjb2RlLioNCg0KIyMNCg0KYHIgZW1vOjpqaSgiY29tcHV0ZXIiKWAgV3JpdGUgYSBzaG9ydCBzdW1tYXJ5IHN0YXRlbWVudCBkaXNjdXNzaW5nIHRoZSBub3RhYmxlIGZlYXR1cmVzIG9mIHRoZSBcQHJlZihmaW5hbGJveHBsb3QpIGJveCBwbG90cy4NCg0KPGJyPg0KDQo8ZGV0YWlscz4NCiAgPHN1bW1hcnk+YHIgZW1vOjpqaSgiaGVhZHBob25lcyIpYCAqKk9ubGluZSBzdHVkZW50cyoqPC9zdW1tYXJ5Pg0KYHIgZW1vOjpqaSgic3BlZWNoX2JhbGxvb24iKWAgIFBvc3QgYSBzaG9ydCBzdW1tYXJ5IG9mIHRoZSBib3ggcGxvdHMnIG5vdGFibGUgZmVhdHVyZXMgaW4gdGhlIGNoYXQuDQo8L2RldGFpbHM+IA0KDQo8YnI+DQoNCiMjIyMgYHIgZW1vOjpqaSgiaG91c2Vfd2l0aF9nYXJkZW4iKWAgUmVjb252ZW5lIGluIG1haW4gcm9vbSB0byBkaXNjdXNzIHJlc3VsdHMgey19DQoNCjxicj4NCg0KIyBQaXBpbmcNCg0KYHIgZW1vOjpqaSgiY29tcHV0ZXIiKWAgWW91IG1heSBoYXZlIG5vdGljZWQgdGhhdCB3ZSB1c2VkIHRoZSAqKnBpcGUgb3BlcmF0b3IqKiBpbiAgXEByZWYoZmluYWxib3hwbG90KV5bV2UgdXNlZCBpdCBhIGNvdXBsZSBvZiB0aW1lcyBpbiAgdGhlIFtzZWNvbmQgRGF0YSBTY2llbmNlIGNvbXB1dGVyIGxhYl0oaHR0cHM6Ly9ycHVicy5jb20vTFRVX1NUTTEwMDEvRFNNQ0wyKSB0b29dLg0KUmVjYWxsIGZyb20gW1NlY3Rpb24gNC4xIG9mIHRoZSBEYXRhIFZpc3VhbGlzYXRpb24gaW4gUiBzdXBwbGVtZW50XShodHRwczovL2Jvb2tkb3duLm9yZy9yZWhrL3N0bTEwMDFfZHNtX2RhdGFfdmlzdWFsaXNhdGlvbl9pbl9yL3ItY29kaW5nLXRlY2huaXF1ZXMtY29tcHV0ZXItbGFicy0zYi5odG1sI3BpcGluZykgIHRoYXQgdGhlIHBpcGUgb3BlcmF0b3IgY2FuIGJlIHVzZWQgdG8gY2hhaW4gdG9nZXRoZXIgYSBzZXF1ZW5jZSBvZiBvcGVyYXRpb25zLCBpbiBhbiBpbnR1aXRpdmUgbWFubmVyIHdoaWNoIGlzIHR5cGljYWxseSBlYXNpZXIgdG8gcmVhZCB0aGFuIGFsdGVybmF0aXZlIG1ldGhvZHMuIA0KDQpJbiBcQHJlZihmaW5hbGJveHBsb3QpIHdlIHVzZWQgcGlwaW5nIHRvIGFkZCBhZGRpdGlvbmFsIGRldGFpbHMgdG8gYW4gZXhpc3Rpbmcgb2JqZWN0LCB3aXRob3V0IG5lZWRpbmcgdG8gZGVmaW5lIGEgbmV3IG9iamVjdC4NCg0KKk5vdGU6IEJlZm9yZSB5b3UgY29udGludWUgd2l0aCB0aGlzIGxhYiwgbWFrZSBzdXJlIHlvdSBoYXZlIHJlYWQgb3ZlciBbU2VjdGlvbiA0LjEgb2YgdGhlIERhdGEgVmlzdWFsaXNhdGlvbiBpbiBSIHN1cHBsZW1lbnRdKGh0dHBzOi8vYm9va2Rvd24ub3JnL3JlaGsvc3RtMTAwMV9kc21fZGF0YV92aXN1YWxpc2F0aW9uX2luX3Ivci1jb2RpbmctdGVjaG5pcXVlcy1jb21wdXRlci1sYWJzLTNiLmh0bWwjcGlwaW5nKS4qDQoNCiMjIHsjdGl0bGV9DQoNCmByIGVtbzo6amkoImNvbXB1dGVyIilgIFN1cHBvc2UgdGhhdCB3ZSB3b3VsZCBsaWtlIHRvIGFkZCBhIHRpdGxlIHRvIG91ciBncm91cGVkIGJveCBwbG90cyBmcm9tIFxAcmVmKGZpbmFsYm94cGxvdCkuDQoNCkluc3RlYWQgb2YgcmV3cml0aW5nIG91ciBgcGVuZ3VpbnNfYm94YCBvYmplY3QgYW5kIGFzc2lnbmluZyB0aGUgb3V0cHV0IHRvIGEgbmV3IG9iamVjdCAoZS5nLiBgcGVuZ3VpbnNfYm94MmApLCB3ZSBjb3VsZCB1c2UgdGhlIHBpcGUgb3BlcmF0b3IgdG8gYWRkIHRoaXMgaW5mb3JtYXRpb24gZGlyZWN0bHkgdG8gYHBlbmd1aW5zX2JveGAuDQoNClRoZSBjb2RlIGJlbG93IGRvZXMganVzdCB0aGlzOg0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IFQsIGVjaG8gPSBULCB3YXJuaW5nID0gRn0NCnBlbmd1aW5zX2JveCAlPiUgbGF5b3V0KHRpdGxlID0gIkJveCBQbG90cyBvZiBQZW5ndWluIGJvZHkgbWFzcyBEYXRhIiwgDQogICAgICAgICAgICAgICAgICAgICAgICBib3htb2RlID0gImdyb3VwIikNCmBgYA0KDQojIyB7I2xlZ2VuZHRpdGxlfQ0KDQpgciBlbW86OmppKCJjb21wdXRlciIpYCBXZSBjYW4gYWxzbyBhZGQgYSB0aXRsZSB0byBvdXIgbGVnZW5kLiBUaGlzIGNhbiBvZnRlbiBoZWxwIHRvIG1ha2Ugb3VyIGdyYXBocyBtb3JlIGluZm9ybWF0aXZlLg0KVHJ5IHJ1bm5pbmcgdGhlIGNvZGUgYmVsb3csIGFuZCBjaGVjayB0aGUgcmVzdWx0Og0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IEYsIGVjaG8gPSBULCB3YXJuaW5nID0gRn0NCnBlbmd1aW5zX2JveCAlPiUgbGF5b3V0KHRpdGxlID0gIkJveCBQbG90cyBvZiBQZW5ndWluIGJvZHkgbWFzcyBEYXRhIiwgDQogICAgICAgICAgICAgICAgICAgICAgICBib3htb2RlID0gImdyb3VwIiwNCiAgICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZD1saXN0KHRpdGxlPWxpc3QodGV4dD0nU2V4JykpKQ0KYGBgDQoNCiMjDQoNCmByIGVtbzo6amkoImNvbXB1dGVyIilgIE5vdGljZSB0aGF0IGluIHRoZSBcQHJlZihsZWdlbmR0aXRsZSkgY29kZSwgd2Ugd2VyZSBhYmxlIHRvIHVzZSB0aGUgYGxheW91dGAgZnVuY3Rpb24gdG8gYWRkIGRldGFpbHMgdG8gKm11bHRpcGxlIGNvbXBvbmVudHMqIG9mIG91ciBwbG90LiBHZW5lcmFsbHksIHdoZW4gd2UgbWFrZSBjaGFuZ2VzIHRvIGBwbG90bHlgIHBsb3RzIHZpYSBwaXBpbmcsIHdlIGFyZSBtYWtpbmcgY2hhbmdlcyB0byB0aGUgbGF5b3V0LCByYXRoZXIgdGhhbiB0aGUgY29yZSBkYXRhIGJlaW5nIHZpc3VhbGlzZWQuDQoNCldpdGhpbiB0aGUgYGxheW91dGAgZnVuY3Rpb24sIHdlIGhhdmUgdXNlZCB0aGUgYXJndW1lbnQgYHRpdGxlYCAodGhlIGZ1bmN0aW9uIG9mIHdoaWNoIGlzIHRvLCByYXRoZXIgYXBwcm9wcmlhdGVseSwgY2hhbmdlIHRoZSB0aXRsZSkuIFRoaXMgaXMgb25lIG9mIG1hbnkgcG9zc2libGUgYXJndW1lbnRzIC0gc29tZSB5b3Ugd2lsbCBsZWFybiBhcyB3ZSBkZXZlbG9wIG91ciB1bmRlcnN0YW5kaW5nIG9mIGBwbG90bHlgLCBhbmQgc29tZSB5b3UgbWF5IG5ldmVyIHVzZSwgYXMgdGhleSBhcmUgcXVpdGUgY29udGV4dCBzcGVjaWZpYy4gVHlwaWNhbGx5IHRob3VnaCwgdGhlIG5hbWVzIG9mIHRoZSBhcmd1bWVudHMgYXJlIGNsZWFyIGFuZCBlYXN5IHRvIHJlbWVtYmVyIC0gZm9yIGluc3RhbmNlLCBgbGVnZW5kYCBhbGxvd3MgdXMgdG8gY2hhbmdlIGRldGFpbHMgaW4gdGhlIGxlZ2VuZC4NCg0KIyMgeyNwaXBpbmdheGVzfQ0KDQpgciBlbW86OmppKCJjb21wdXRlciIpYCBUbyBjb25jbHVkZSB0aGlzIGV4YW1wbGUsIHN1cHBvc2UgdGhhdCB3ZSB3b3VsZCBsaWtlIHRvIHJlbmFtZSB0aGUgeC1heGlzIGFuZCB5LWF4aXMgb2YgYHBlbmd1aW5zX2JveGAuIFRoZSBkZWZhdWx0IG5hbWVzIGFyZSBvaywgYnV0IHBlcmhhcHMgd2Ugd291bGQgbGlrZSBzb21ldGhpbmcgYSBsaXR0bGUgZGlmZmVyZW50LiBSdW4gdGhlIGNvZGUgYmVsb3cgYW5kIGFzc2VzcyB0aGUgcmVzdWx0cy4NCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBGLCBlY2hvID0gVCwgd2FybmluZyA9IEZ9DQpwZW5ndWluc19ib3ggJT4lIGxheW91dCh4YXhpcyA9IGxpc3QodGl0bGUgPSAiUGVuZ3VpbiBTcGVjaWVzIiksDQogICAgICAgICAgICAgICAgICAgICAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAiUGVuZ3VpbiBCb2R5IE1hc3MgKGdyYW1zKSIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgYm94bW9kZSA9ICJncm91cCIsDQogICAgICAgICAgICAgICAgICAgICAgICBsZWdlbmQ9bGlzdCh0aXRsZT1saXN0KHRleHQ9J1NleCcpKSkNCg0KYGBgDQoNCiMjDQoNCmByIGVtbzo6amkoImNvbXB1dGVyIilgIE5vdGljZSB0aGF0IHdlIGhhdmUgaW5jbHVkZWQgdGhlIGBsaXN0YCBmdW5jdGlvbiB3aXRoaW4gb3VyIGBsYXlvdXRgIGZ1bmN0aW9uIGNvZGluZyBpbiBcQHJlZihwaXBpbmdheGVzKS4NClRoZSBgeGF4aXNgIGFuZCBgeWF4aXNgIGFyZ3VtZW50cyBjYW4gYm90aCB0YWtlIHNldmVyYWwgc2V0dGluZ3MgLSBmb3IgZXhhbXBsZSwgd2UgY291bGQgY2hhbmdlIHRoZSB4LWF4aXMgdGl0bGUsIGFuZCBmb250IHNpemUuIEEgYGxpc3RgIGZ1bmN0aW9uICBzdHJ1Y3R1cmUgaXMgYSB0eXBpY2FsIHJlcXVpcmVtZW50IGZvciBgbGF5b3V0YCBhcmd1bWVudHMgKHRoZSB0aXRsZSBpbiBcQHJlZih0aXRsZSkgd2FzIGFuIGV4Y2VwdGlvbikuIA0KDQpUaGVyZWZvcmUsIHBsZWFzZSBrZWVwIGluIG1pbmQgdGhhdCBnZW5lcmFsbHkgc3BlYWtpbmcsIGluIHRoZSBjb250ZXh0IG9mIG91ciBgcGxvdGx5YCBncmFwaHMsIHdoZW4gZGVhbGluZyB3aXRoIHRoZSBgbGF5b3V0YCBmdW5jdGlvbiB3ZSBuZWVkIHRvIHVzZSB0aGUgYGxpc3RgIGZ1bmN0aW9uIGJlZm9yZSBzcGVjaWZ5aW5nIG91ciBkZXNpcmVkIGNoYW5nZXMgdG8gYGxheW91dGAgYXJndW1lbnRzLg0KDQojIw0KDQpgciBlbW86OmppKCJjb21wdXRlciIpYCBBcyBhIGZpbmFsIG5vdGUsIGl0J3Mgd29ydGggcG9pbnRpbmcgb3V0IHRoYXQgb3VyIG1haW4gdGl0bGUgZnJvbSBcQHJlZih0aXRsZSkgaGFzIGRpc2FwcGVhcmVkIGluIG91ciBuZXcgcGxvdCBpbiBcQHJlZihwaXBpbmdheGVzKS4gVGhpcyBpcyBiZWNhdXNlIHdlIGRpZCBub3QgYXNzaWduIG91ciBlbmhhbmNlZCBwbG90IHRvIGEgbmV3IG9iamVjdC4gDQoNCldoZW4gd2UgdXNlIHBpcGluZywgd2UgYXJlIG5vdCBtb2RpZnlpbmcgdGhlIG9yaWdpbmFsIG9iamVjdCwgYnV0IHJhdGhlciBhcmUgY2Fycnlpbmcgb3V0IG9wZXJhdGlvbnMgb24vd2l0aCBpdC4gVGhlcmVmb3JlICoqYW55IGNoYW5nZXMgd2UgaW1wbGVtZW50IHZpYSBwaXBpbmcgYXJlIG5vdCBzYXZlZCB0byB0aGUgb3JpZ2luYWwgb2JqZWN0KiouDQoNCiMgQ3JlYXRpbmcgSW50ZXJhY3RpdmUgVmlvbGluIFBsb3RzIGluIFJTdHVkaW8geyN2aW9saW59DQoNCmByIGVtbzo6amkoImNvbXB1dGVyIilgIExldCB1cyBub3cgdXNlIG91ciBgcGxvdGx5YCBhbmQgcGlwaW5nIHNraWxscyB0byBjcmVhdGUgYW5vdGhlciB0eXBlIG9mIHBsb3QsIHRoZSAqKnZpb2xpbiBwbG90KiouDQoNCldlIGNhbiB0aGluayBvZiB2aW9saW4gcGxvdHMgYXMgYmVpbmcgYW4gZXh0ZW5zaW9uIG9mIGJveCBwbG90cywgd2hpY2ggYWxzbyBzaG93IHRoZSBkZW5zaXR5IG9mIHRoZSBvYnNlcnZhdGlvbnMgKGEgYml0IGxpa2UgYSBzbW9vdGhlZCB2ZXJzaW9uIG9mIGEgaGlzdG9ncmFtKS4NCg0KKk5vdGU6IFJlZmVyIHRvIFtTZWN0aW9uIDUuMyBvZiBUb3BpYyAyXShodHRwczovL2Jvb2tkb3duLm9yZy9hX3NoYWtlci9TVE0xMDAxX1RvcGljXzIvNS4zLXZpb2xpbi1wbG90cy5odG1sKSBmb3IgZGV0YWlscyBvbiB2aW9saW4gcGxvdHMuKg0KDQojIyB7I2luaXRpYWx2aW9saW59DQoNCmByIGVtbzo6amkoImNvbXB1dGVyIilgIFdlIGNhbiB1c2UgdGhlIGNvZGUgZnJvbSBcQHJlZih0cmFjZSkgYXMgYSBnb29kIHN0YXJ0aW5nIHBvaW50IGZvciBvdXIgZmlyc3QgdmlvbGluIHBsb3QsDQphbHRob3VnaCB3ZSB3aWxsIG5lZWQgdG8gcmVwbGFjZSB0aGUgYHR5cGUgPSAnYm94J2Agc3BlY2lmaWNhdGlvbiB3aXRoLi4ueW91IGd1ZXNzZWQgaXQgLSBgdHlwZSA9ICd2aW9saW4nYC4NCg0KUnVuIHRoZSBSIGNvZGUgYmVsb3cgdG8gcHJvZHVjZSBvdXIgZmlyc3QgdmlvbGluIHBsb3Q6DQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gRiwgZWNobyA9IFQsIGZpZy5hbGlnbj0nY2VudGVyJywgd2FybmluZyA9IEZ9DQpwZW5ndWluc192aW9saW4gPC0gcGxvdF9seShkYXRhID0gcGVuZ3VpbnMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IH5ib2R5X21hc3NfZywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gInZpb2xpbiIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgeDAgPSAiYm9keSBtYXNzIChnKSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICBib3ggPSBsaXN0KHZpc2libGUgPSBUICkpDQpwZW5ndWluc192aW9saW4NCmBgYA0KDQoqTm90ZTogV2UgaW5jbHVkZSB0aGUgYXJndW1lbnQgYGJveCA9IGxpc3QodmlzaWJsZSA9IFQgKWAgdG8gZW5zdXJlIHRoZSBib3ggcGxvdCBvZiB0aGUgZGF0YSBhbHNvIGFwcGVhcnMgaW4gdGhlIHZpb2xpbiBwbG90LioNCg0KIyMNCg0KYHIgZW1vOjpqaSgiY29tcHV0ZXIiKWAgTGV0IHVzIG5vdyBzdGFydCBtYWtpbmcgb3VyIHZpb2xpbiBwbG90IG1vcmUgaW5mb3JtYXRpdmUuIFVzaW5nIHRoZSBjb2RlIGluIFxAcmVmKGJveHBsb3RzZWdtZW50KSBhcyBhIGd1aWRlLCBicmVhayB0aGUgdmlvbGluIHBsb3QgaW4gXEByZWYoaW5pdGlhbHZpb2xpbikgaW50byBzZXBhcmF0ZSB2aW9saW4gcGxvdHMgZm9yIGVhY2ggYHNwZWNpZXNgIG9mIHBlbmd1aW4uDQoNCipIaW50OiBJZiB5b3UgYXJlIHN0dWNrIG9uIHRoaXMgYW5kIG5vdCBzdXJlIGhvdyB0byBwcm9jZWVkLCBjaGVjayB0aGUgYENvZGVgIGNodW5rIGJlbG93OioNCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSIsIGV2YWwgPSBGLCBlY2hvID0gVCwgZmlnLmFsaWduPSdjZW50ZXInLCB3YXJuaW5nID0gRn0NCnBlbmd1aW5zX3Zpb2xpbiA8LSBwbG90X2x5KGRhdGEgPSBwZW5ndWlucywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICB4ID0gfnNwZWNpZXMsICMgdGhpcyBpcyB0aGUgbGluZSB3ZSBhZGQNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSB+Ym9keV9tYXNzX2csIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZSA9ICd2aW9saW4nLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgYm94ID0gbGlzdCh2aXNpYmxlID0gVCApKSANCnBlbmd1aW5zX3Zpb2xpbg0KYGBgDQoNCiMjIHsjb3B0aW9uc30NCg0KYHIgZW1vOjpqaSgiY29tcHV0ZXIiKWAgTmV4dCwgbGV0J3Mgc3BsaXQgdGhlc2UgdmlvbGluIHBsb3RzIGludG8gc2VwYXJhdGUgb25lcyBmb3IgbWFsZSBhbmQgZmVtYWxlIHBlbmd1aW5zLiBUbyBkbyB0aGlzLCB3ZSBjYW4gYWRkIGVpdGhlciB0aGUgYXJndW1lbnQgYGNvbG9yID1+IHNleGAsIG9yIHRoZSBhcmd1bWVudCBgc3BsaXQgPSB+c2V4YC4gQ2hvb3NlIG9uZSwgYW5kIG1vZGlmeSB5b3VyIGBwZW5ndWluc192aW9saW5gIG9iamVjdCBhY2NvcmRpbmdseS4NCg0KIyMgeyNmaW5hbHZpb2xpbnBsb3RzfQ0KDQpgciBlbW86OmppKCJjb21wdXRlciIpYCBVbmZvcnR1bmF0ZWx5LCB1c2luZyBlaXRoZXIgb3B0aW9uIGluIFxAcmVmKG9wdGlvbnMpIHJlc3VsdHMgaW4gb3VyIHZpb2xpbiBwbG90cyBvdmVybGFwcGluZyBsaWtlIGluIFxAcmVmKGJveHBsb3RzZWdtZW50KS4NCg0KRm9ydHVuYXRlbHksIHdlIGNhbiBhZGRyZXNzIHRoaXMgdXNpbmcgb3VyIG5ldyBwaXBpbmcgc2tpbGxzLg0KDQpVc2luZyB0aGUgY29kZSBpbiBcQHJlZihmaW5hbGJveHBsb3QpIGFuZCBcQHJlZih0aXRsZSkgYXMgYSBndWlkZSwgcGlwZSBhZGRpdGlvbmFsIGRldGFpbHMgdG8geW91ciBgcGVuZ3VpbnNfdmlvbGluYCBvYmplY3Qgc28gdGhhdCB0aGUgdmlvbGluIHBsb3RzIGZvciB0aGUgbWFsZSBhbmQgZmVtYWxlIHBlbmd1aW5zIG9mIGVhY2ggc3BlY2llcyBhcmUgbmV4dCB0byBlYWNoIGluIHNlcGFyYXRlIGxhbmVzLCByYXRoZXIgdGhhbiBvdmVybGFwcGluZy4NCg0KKkhpbnQ6IFlvdSB3aWxsIGhhdmUgdG8gY2hhbmdlIHRoZSBgYm94bW9kZT0gImdyb3VwImAgY29kZSB1c2VkIGluIHRoZSBgbGF5b3V0YCBwYXJ0cyBvZiBcQHJlZihmaW5hbGJveHBsb3QpIGFuZCBcQHJlZih0aXRsZSkgLSB0aGluayBhYm91dCB3aGF0IHR5cGUgb2YgcGxvdCB5b3UgYXJlIGNvbnNpZGVyaW5nIG5vdy4qIA0KDQojIw0KDQpgciBlbW86OmppKCJjb21wdXRlciIpYCBUbyBmaW5pc2ggdXAsIHVzZSBwaXBpbmcgdG8gYWRkIGFuIGFwcHJvcHJpYXRlIHRpdGxlIHRvIHlvdXIgZ3JvdXBlZCB2aW9saW4gcGxvdHMgZ3JhcGguDQoNCjxicj4NCg0KIyMjIyBgciBlbW86OmppKCJob3VzZV93aXRoX2dhcmRlbiIpYCBSZWNvbnZlbmUgaW4gbWFpbiByb29tIHRvIGRpc2N1c3MgcmVzdWx0cyB7LX0NCg0KPGJyPg0KDQojIEV4dGVuc2lvbjogQ3JlYXRpbmcgeW91ciBvd24gYHBsb3RseWAgcGxvdHMgeyNleHRlbnNpb25xdWVzdGlvbn0NCg0KYHIgZW1vOjpqaSgiYnVsYiIpYCBOb3cgdGhhdCB5b3UgaGF2ZSBoYWQgYSBjaGFuY2UgdG8gcHJhY3RpY2UgY3JlYXRpbmcgaW50ZXJhY3RpdmUgYm94IHBsb3RzIGFuZCB2aW9saW4gcGxvdHMgdXNpbmcgYHBsb3RseWAsIGl0IGlzIHRpbWUgdG8gbWFrZSB5b3VyIG93bi4NCg0KVXNpbmcgYWxsIHRoZSBza2lsbHMgeW91IGhhdmUgZ2FpbmVkIGZyb20gdGhpcyBsYWIsIGNyZWF0ZSBhIHNldCBvZiBlaXRoZXIgYm94IHBsb3RzIG9yIHZpb2xpbiBwbG90cyAob3IgYm90aCBpZiB5b3Ugd291bGQgbGlrZSkgd2l0aCB0aGUgZm9sbG93aW5nIGNoYXJhY3RlcmlzdGljczoNCg0KKiBUaGUgcGxvdHMgc2hvdWxkIHNob3cgaW5mb3JtYXRpb24gb24gdGhlIGBiaWxsX2xlbmd0aGAgb2YgdGhlIHBlbmd1aW5zDQoqIFRoZSBwbG90cyBzaG91bGQgYmUgZ3JvdXBlZCBieSB0aGUgYHNleGAgb2YgdGhlIHBlbmd1aW4NCiogVGhlIHBsb3RzIHNob3VsZCBiZSBjb2xvdXJlZCBhY2NvcmRpbmcgdG8gdGhlIGBpc2xhbmRgIHRoZSBwZW5ndWluIGluaGFiaXRzDQoqIFRoZSBwbG90cyBzaG91bGQgYmUgc3BsaXQgYWNjb3JkaW5nIHRvIHRoZSBgc3BlY2llc2Agb2YgdGhlIHBlbmd1aW4NCiogVGhlIGhvdmVyIHRleHQgc2hvdWxkIHNob3cgdGhlIGBpc2xhbmRgIHRoZSBwZW5ndWluIGluaGFiaXRzDQoqIFRoZSBwbG90cyBzaG91bGQgaGF2ZSBpbmZvcm1hdGl2ZSBheGVzIGFuZCBsZWdlbmQgbGFiZWxzLCBhbmQgYW4gaW5mb3JtYXRpdmUgdGl0bGUNCg0KU2VlIGhvdyB5b3UgZ28sIGFuZCBpZiB5b3UgZ2V0IHN0dWNrLCByZW1lbWJlciB0byBhc2sgeW91ciBsYWIgZGVtb25zdHJhdG9yIGZvciBoZWxwLiBHb29kIGx1Y2shIA0KDQo8YnI+DQoNCjxkZXRhaWxzPg0KICA8c3VtbWFyeT5gciBlbW86OmppKCJoZWFkcGhvbmVzIilgICoqT25saW5lIHN0dWRlbnRzKio8L3N1bW1hcnk+DQpgciBlbW86OmppKCJzcGVlY2hfYmFsbG9vbiIpYCAgSWYgeW91ciBicmVha291dCByb29tIGdyb3VwIGhhZCB0aW1lIHRvIGNyZWF0ZSB5b3VyIG93biBQbG90bHkgcGVuZ3VpbiBwbG90IGluIFF1ZXN0aW9uIFxAcmVmKGV4dGVuc2lvbnF1ZXN0aW9uKSwgdGFrZSBhIHNuaXBwZXQvc2NyZWVuc2hvdCBvZiBpdCBhbmQgY29weS1wYXN0ZSBpdCBpbnRvIHRoZSBjaGF0Lg0KPC9kZXRhaWxzPiANCg0KPGJyPg0KDQojIyMjIGByIGVtbzo6amkoImhvdXNlX3dpdGhfZ2FyZGVuIilgIERpc2N1c3MgcmVzdWx0cyBpbiBtYWluIHJvb20gYW5kIGNvbmNsdWRlIGxhYiB7LX0NCg0KPGJyPg0KDQojIyMjIFdlbGwgZG9uZSEgVGhlcmUgd2FzIGEgbG90IG9mIGNvbnRlbnQgdG9kYXkuICMjIyMgey19DQoNCkRvbid0IHdvcnJ5IGlmIHlvdSB3ZXJlbid0IGFibGUgdG8gZmluaXNoIGV2ZXJ5dGhpbmcgaW4gdGhlIG9uZSBzZXNzaW9uIC0gdGhlcmUgaXMgcXVpdGUgb2YgbG90IG9mIG1hdGVyaWFsIHRvIHdvcmsgdGhyb3VnaCBpbiB0aGlzIGxhYiwgYW5kIGl0J3Mgbm90IGVhc3kuDQoNCkhvcGVmdWxseSB0aG91Z2gsIHlvdSBhcmUgYmVnaW5uaW5nIHRvIGZlZWwgcXVpdGUgc2tpbGxlZCB3aXRoIHVzaW5nIGBwbG90bHlgLiBUaGUgdGVjaG5pcXVlcyBhbmQgY29kaW5nIHNraWxscyB5b3UgYXJlIGxlYXJuaW5nIHNob3VsZCBob2xkIHlvdSBpbiBnb29kIHN0ZWFkIGZvciB0aGUgZm9sbG93aW5nIHdlZWtzLiBSZW1lbWJlciwgeW91IGNhbiBhbHdheXMgcmVmZXIgYmFjayB0byB0aGlzIG1hdGVyaWFsIGF0IGEgbGF0ZXIgZGF0ZSBpZiB5b3UgbmVlZCBhIHF1aWNrIHJlZnJlc2hlci4NCg0KQmVmb3JlIHlvdSBmaW5pc2ggdXAsIG1ha2Ugc3VyZSB0byBzYXZlIHlvdXIgc2NyaXB0IGZpbGUgc29tZXdoZXJlIHNhZmUgLSBpdCBtaWdodCBjb21lIGluIGhhbmR5IGxhdGVyIG9uLiANCjxicj4NCg0KIyBSZWZlcmVuY2VzIHstICNSZWZ9DQo8ZGl2IGlkPSJyZWZzIj48L2Rpdj4NCg0KPGJyPg0KDQo8Zm9udCBjb2xvciA9ICJncmV5Ij4NClRoZXNlIG5vdGVzIGhhdmUgYmVlbiBwcmVwYXJlZCBieSBSdXBlcnQgS3V2ZWtlLiBUaGUgY29weXJpZ2h0IGZvciB0aGUgbWF0ZXJpYWwgaW4gdGhlc2Ugbm90ZXMgcmVzaWRlcyB3aXRoIHRoZSBhdXRob3IgbmFtZWQgYWJvdmUsIHdpdGggdGhlIERlcGFydG1lbnQgb2YgTWF0aGVtYXRpY2FsIGFuZCBQaHlzaWNhbCBTY2llbmNlcyBhbmQgd2l0aCBMYSBUcm9iZSBVbml2ZXJzaXR5LiBDb3B5cmlnaHQgaW4gdGhpcyB3b3JrIGlzIHZlc3RlZCBpbiBMYSBUcm9iZSBVbml2ZXJzaXR5IGluY2x1ZGluZyBhbGwgTGEgVHJvYmUgVW5pdmVyc2l0eSBicmFuZGluZyBhbmQgbmFtaW5nLiBVbmxlc3Mgb3RoZXJ3aXNlIHN0YXRlZCwgbWF0ZXJpYWwgd2l0aGluIHRoaXMgd29yayBpcyBsaWNlbnNlZCB1bmRlciBhIENyZWF0aXZlIENvbW1vbnMgQXR0cmlidXRpb24tTm9uIENvbW1lcmNpYWwtTm9uIERlcml2YXRpdmVzIExpY2Vuc2UgDQo8YSBocmVmID0gImh0dHBzOi8vY3JlYXRpdmVjb21tb25zLm9yZy9saWNlbnNlcy9ieS1uYy1uZC80LjAvQ0MiIHRhcmdldD0iX2JsYW5rIj4gQlktTkMtTkQuIDwvYT4NCjwvZm9udD4=