Data Science Stream

Topic 2B: Data Visualisation I


Example R code solutions for the Data Science Computer Lab 2, which uses data from Horst, Hill, and Gorman (2020), and the plotly (Sievert 2020) R package, are presented below.


1 Palmer Penguins Data Set

1.1

# Install package
install.packages("palmerpenguins")

1.2

# Load the `palmerpenguins` package into your current R working environment
library(palmerpenguins)
# Summarise the data in the `palmerpenguins` package
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

2 Creating Interactive Histograms in RStudio

hist(penguins$body_mass_g, breaks = 19)

2.1

install.packages("plotly")
library(plotly)

2.2

penguin_hist_base <- plot_ly(data = penguins, 
                             x = ~body_mass_g, 
                             type = "histogram")

penguin_hist_base <- penguin_hist_base %>% layout(yaxis = list(title = 'count'))

A brief explanation of the code is provided in the Code chunk below.

# 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

penguin_hist_base

2.4

No answer required.

2.5

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

A brief explanation of the code is provided in the Code chunk below.

# 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

penguin_hist

2.7

No answer required.

3 Creating Interactive Scatter Plots in RStudio

3.1

No answer required.

3.2

penguins_scatter <- plot_ly(data = penguins, 
                            x = ~body_mass_g, y = ~flipper_length_mm)
penguins_scatter

3.3

penguins_scatter2 <- plot_ly(data = penguins, x = ~body_mass_g, y = ~flipper_length_mm, 
                             color = ~sex)
penguins_scatter2

3.4

An example result for an arbitrary selection of colours is shown below.

penguins_scatter_colours <- plot_ly(data = penguins, 
                                    x = ~body_mass_g, y = ~flipper_length_mm, 
                                    color = ~sex, colors = c("cyan", "orange"))
penguins_scatter_colours

3.5

For brevity only the result for the Set2 colors specification is shown below.

penguins_scatter_colours <- plot_ly(data = penguins, 
                                    x = ~body_mass_g, y = ~flipper_length_mm, 
                                    color = ~sex, colors = "Set2")
penguins_scatter_colours

3.6

penguins_scatter2 <- plot_ly(data = penguins, 
                             x = ~body_mass_g, y = ~flipper_length_mm, 
                             color = ~sex, colors = "Set1",
                             type = "scatter", mode = "markers")
penguins_scatter2
penguins_scatter2 <- plot_ly(data = penguins, x = ~body_mass_g, y = ~flipper_length_mm, 
                             color = ~sex, colors = "Set1",
                             type = "scatter", mode = "lines")
penguins_scatter2

Note that here, R is drawing a line between the individual data points - clearly we don’t want this!

3.7

penguins_scatter2 <- plot_ly(data = penguins, x = ~body_mass_g, y = ~flipper_length_mm, 
                             color = ~sex, colors = "Set1", text = ~species,
                             type = "scatter", mode = "markers")
penguins_scatter2

3.8

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

3.9

Here we have used the symbols cross, diamond and star.

penguins_scatter3 <- plot_ly(data = penguins, x = ~body_mass_g, y = ~flipper_length_mm, 
                             color = ~sex, colors = "Set1", symbol = ~species,
                             symbols = c("cross", "diamond", "star"),
                             type = "scatter", mode = "markers")
penguins_scatter3

3.10

penguins_scatter3 <- plot_ly(data = penguins, x = ~body_mass_g, y = ~flipper_length_mm, 
                             color = ~sex, colors = "Set1", symbol = ~species,
                             symbols = c("cross", "diamond", "star"),
                             type = "scatter", mode = "markers",
                             marker = list(size = 8))
penguins_scatter3

4 Creating your own plotly Scatter Plot

4.1

penguins_scatter_new <- plot_ly(data = penguins, 
                                x = ~body_mass_g, y = ~bill_length_mm,
                                type = "scatter", mode = "markers")
penguins_scatter_new

4.2

penguins_scatter_new2 <- plot_ly(data = penguins, 
                                 x = ~body_mass_g, y = ~bill_length_mm,
                                 color = ~island,
                                 type = "scatter", mode = "markers")
penguins_scatter_new2

4.3

penguins_scatter_new3 <- plot_ly(data = penguins, 
                                 x = ~body_mass_g, y = ~bill_length_mm,
                                 color = ~island, symbol = ~species,
                                 type = "scatter", mode = "markers")
penguins_scatter_new3

4.4

penguins_scatter_new4 <- plot_ly(data = penguins, 
                                 x = ~body_mass_g, y = ~bill_length_mm,
                                 color = ~island, symbol = ~species, 
                                 symbols = c("cross", "diamond", "star"),
                                 type = "scatter", mode = "markers",
                                 marker = list(size=8))
penguins_scatter_new4

4.5

It does seem that penguins living on different islands have noticeably different body_mass_g and bill_length_mm measurements, but this is also due to the fact that some species of penguin only live on one of the three islands - e.g. Gentoo and Chinstrap penguins only live on Biscoe island and Dream island respectively, whereas the Adelie penguins live on all three islands.

However, we also note that the Adelie penguins living on Torgersen island are much smaller overall than Adelie penguins living on other islands.


That’s everything covered.


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.

LS0tDQp0aXRsZTogIlNUTTEwMDE6IENvbXB1dGVyIExhYiAyQiBTb2x1dGlvbnMiDQpvdXRwdXQ6DQogIGJvb2tkb3duOjpodG1sX2RvY3VtZW50MjogDQogICAgdG9jOiB0cnVlDQogICAgdG9jX2Zsb2F0OiB0cnVlDQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KICAgIHRoZW1lOiByZWFkYWJsZQ0KICAgIGNvZGVfZm9sZGluZzogc2hvdw0KYmlibGlvZ3JhcGh5OiBTVE0xMDAxX0RTX0NMX3JlZmVyZW5jZXMuYmliIA0KbGluay1jaXRhdGlvbnM6IHllcw0KLS0tDQoNCjxzdHlsZT4NCiNUT0Mgew0KICBiYWNrZ3JvdW5kOiB1cmwoImh0dHBzOi8vd3d3LmxhdHJvYmUuZWR1LmF1L19tZWRpYS9sYS10cm9iZS1hcGkvdjUvaW1nL2xvZ28uc3ZnIik7DQogIGJhY2tncm91bmQtc2l6ZTogY29udGFpbjsNCiAgcGFkZGluZy10b3A6IDgwcHggIWltcG9ydGFudDsNCiAgYmFja2dyb3VuZC1yZXBlYXQ6IG5vLXJlcGVhdDsNCn0NCjwvc3R5bGU+DQoNCiMjIyBEYXRhIFNjaWVuY2UgU3RyZWFtIHstfQ0KDQojIyMgVG9waWMgMkI6IERhdGEgVmlzdWFsaXNhdGlvbiBJIHstfQ0KDQo8YnI+DQoNCkV4YW1wbGUgUiBjb2RlIHNvbHV0aW9ucyBmb3IgdGhlIFtEYXRhIFNjaWVuY2UgQ29tcHV0ZXIgTGFiIDJdKGh0dHBzOi8vcnB1YnMuY29tL0xUVV9TVE0xMDAxL0RTTUNMMiksIHdoaWNoIHVzZXMgZGF0YSBmcm9tIEBwZW5ndWlucywgYW5kIHRoZSBgcGxvdGx5YCBbQHBsb3RseV0gUiBwYWNrYWdlLCBhcmUgcHJlc2VudGVkIGJlbG93Lg0KDQo8YnI+DQoNCiMgUGFsbWVyIFBlbmd1aW5zIERhdGEgU2V0IHsjcGVuZ3VpbnN9DQoNCiMjDQoNCmBgYHtyLCBpbmNsdWRlID0gRn0NCiMgSW5zdGFsbCBwYWNrYWdlcyBpZiBtaXNzaW5nDQppbnN0YWxsLnBhY2thZ2VzKHNldGRpZmYoInBhbG1lcnBlbmd1aW5zIiwgcm93bmFtZXMoaW5zdGFsbGVkLnBhY2thZ2VzKCkpKSwgcmVwb3MgPSAiaHR0cDovL2NyYW4udXMuci1wcm9qZWN0Lm9yZyIpDQppbnN0YWxsLnBhY2thZ2VzKHNldGRpZmYoInBsb3RseSIsIHJvd25hbWVzKGluc3RhbGxlZC5wYWNrYWdlcygpKSksIHJlcG9zID0gImh0dHA6Ly9jcmFuLnVzLnItcHJvamVjdC5vcmciKQ0KYGBgDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gRiwgZWNobyA9IFR9DQojIEluc3RhbGwgcGFja2FnZQ0KaW5zdGFsbC5wYWNrYWdlcygicGFsbWVycGVuZ3VpbnMiKQ0KYGBgDQoNCiMjDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gVCwgZWNobyA9IFR9DQojIExvYWQgdGhlIGBwYWxtZXJwZW5ndWluc2AgcGFja2FnZSBpbnRvIHlvdXIgY3VycmVudCBSIHdvcmtpbmcgZW52aXJvbm1lbnQNCmxpYnJhcnkocGFsbWVycGVuZ3VpbnMpDQojIFN1bW1hcmlzZSB0aGUgZGF0YSBpbiB0aGUgYHBhbG1lcnBlbmd1aW5zYCBwYWNrYWdlDQpzdW1tYXJ5KHBlbmd1aW5zKQ0KYGBgDQoNCiMgQ3JlYXRpbmcgSW50ZXJhY3RpdmUgSGlzdG9ncmFtcyBpbiBSU3R1ZGlvDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gVCwgZWNobyA9IFR9DQpoaXN0KHBlbmd1aW5zJGJvZHlfbWFzc19nLCBicmVha3MgPSAxOSkNCmBgYA0KDQojIw0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IEYsIGVjaG8gPSBGLCBpbmNsdWRlID0gRn0NCmluc3RhbGwucGFja2FnZXMoInBsb3RseSIsIHJlcG9zID0gImh0dHA6Ly9jcmFuLnVzLnItcHJvamVjdC5vcmciKQ0KYGBgDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gRiwgZWNobyA9IFR9DQppbnN0YWxsLnBhY2thZ2VzKCJwbG90bHkiKQ0KYGBgDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gVCwgZWNobyA9IFQsIG1lc3NhZ2UgPSBGLCB3YXJuaW5nID0gRn0NCmxpYnJhcnkocGxvdGx5KQ0KYGBgDQoNCiMjIA0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IFQsIGVjaG8gPSBULCB3YXJuaW5nID0gRiwgbWVzc2FnZSA9IEZ9DQpwZW5ndWluX2hpc3RfYmFzZSA8LSBwbG90X2x5KGRhdGEgPSBwZW5ndWlucywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHggPSB+Ym9keV9tYXNzX2csIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gImhpc3RvZ3JhbSIpDQoNCnBlbmd1aW5faGlzdF9iYXNlIDwtIHBlbmd1aW5faGlzdF9iYXNlICU+JSBsYXlvdXQoeWF4aXMgPSBsaXN0KHRpdGxlID0gJ2NvdW50JykpDQpgYGANCg0KQSBicmllZiBleHBsYW5hdGlvbiBvZiB0aGUgY29kZSBpcyBwcm92aWRlZCBpbiB0aGUgYENvZGVgIGNodW5rIGJlbG93Lg0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1oaWRlIiwgZXZhbCA9IEYsIGVjaG8gPSBUfQ0KIyBIZXJlLCB3ZSBhcmUgY3JlYXRpbmcgYSBwbG90bHkgb2JqZWN0IGNhbGxlZCAicGVuZ3Vpbl9oaXN0X2Jhc2UiDQpwZW5ndWluX2hpc3RfYmFzZSA8LSBwbG90X2x5KGRhdGEgPSBwZW5ndWlucywgIyBXZSBhcmUgdXNpbmcgdGhlIHBlbmd1aW5zIGRhdGENCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeCA9IH5ib2R5X21hc3NfZywgIyBhbmQgbW9kZWxsaW5nIHRoZSBib2R5X21hc3NfZyBkYXRhDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGUgPSAiaGlzdG9ncmFtIikgIyBpbiBhIGhpc3RvZ3JhbSBmb3JtYXQNCg0KIyBUaGUgY29kZSBiZWxvdyBpcyB1c2VkIHRvIG1vZGlmeSB0aGUgbGF5b3V0IG9mIHRoZSBoaXN0b2dyYW0NCiMgdG8gaW5jbHVkZSBhIGxhYmVsIGZvciB0aGUgeS1heGlzDQpwZW5ndWluX2hpc3RfYmFzZSA8LSBwZW5ndWluX2hpc3RfYmFzZSAlPiUgbGF5b3V0KHlheGlzID0gbGlzdCh0aXRsZSA9ICdjb3VudCcpKQ0KYGBgDQoNCiMjIHsjYmFzZWhpc3R9DQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gVCwgZWNobyA9IFQsIHdhcm5pbmcgPSBGLCBtZXNzYWdlID0gRiwgZmlnLmFsaWduID0gImNlbnRlciJ9DQpwZW5ndWluX2hpc3RfYmFzZQ0KYGBgDQoNCiMjDQoNCk5vIGFuc3dlciByZXF1aXJlZC4NCg0KIyMNCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gVCwgd2FybmluZyA9IEYsIG1lc3NhZ2UgPSBGfQ0KcGVuZ3Vpbl9oaXN0IDwtIHBsb3RfbHkoZGF0YSA9IHBlbmd1aW5zLCANCiAgICAgICAgICAgICAgICAgICAgICAgIHggPSB+Ym9keV9tYXNzX2csIA0KICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSB+aXNsYW5kLCANCiAgICAgICAgICAgICAgICAgICAgICAgIHR5cGUgPSAiaGlzdG9ncmFtIiwgYWxwaGEgPSAwLjYpDQoNCnBlbmd1aW5faGlzdCA8LSBwZW5ndWluX2hpc3QgJT4lIGxheW91dCh5YXhpcyA9IGxpc3QodGl0bGUgPSAnY291bnQnKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFybW9kZSA9Im92ZXJsYXkiKQ0KYGBgDQoNCkEgYnJpZWYgZXhwbGFuYXRpb24gb2YgdGhlIGNvZGUgaXMgcHJvdmlkZWQgaW4gdGhlIGBDb2RlYCBjaHVuayBiZWxvdy4NCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSIsIGV2YWwgPSBGLCBlY2hvID0gVH0NCiMgSGVyZSwgd2UgYXJlIGNyZWF0aW5nIGEgcGxvdGx5IG9iamVjdCBjYWxsZWQgInBlbmd1aW5faGlzdCINCnBlbmd1aW5faGlzdCA8LSBwbG90X2x5KGRhdGEgPSBwZW5ndWlucywgIyBXZSBhcmUgdXNpbmcgdGhlIHBlbmd1aW5zIGRhdGENCiAgICAgICAgICAgICAgICAgICAgICAgIHggPSB+Ym9keV9tYXNzX2csICMgYW5kIG1vZGVsbGluZyB0aGUgYm9keV9tYXNzX2cgZGF0YQ0KICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSB+aXNsYW5kLCB0eXBlID0gImhpc3RvZ3JhbSIsIGFscGhhID0gMC42KQ0KIyBXZSBhcmUgcHJvZHVjaW5nIGEgaGlzdG9ncmFtIGZvciB0aGlzIGRhdGEsIHdpdGggcG9pbnRzIGNvbG91cmVkIGRpZmZlcmVudGx5LCANCiMgZGVwZW5kaW5nIG9uIHRoZSBpc2xhbmQgb24gd2hpY2ggdGhlIHBlbmd1aW4gaXMgbG9jYXRlZA0KDQojIFRoZSBjb2RlIGJlbG93IGlzIHVzZWQgdG8gbW9kaWZ5IHRoZSBsYXlvdXQgb2YgdGhlIGhpc3RvZ3JhbQ0KIyBUaGlzIGluY2x1ZGVzIGFkZGluZyBhIGxhYmVsIHRvIHRoZSB5LWF4aXMNCiMgYW5kIHNldHRpbmcgdGhlIGhpc3RvZ3JhbXMgdG8gYmUgbGF5ZXJlZCBvdmVyIGVhY2ggb3RoZXINCiMgKGhlbmNlIHRoZSBhbHBoYSA9IDAuNiBhYm92ZSB0byBjaGFuZ2UgdGhlIG9wYWNpdHkpDQpwZW5ndWluX2hpc3QgPC0gcGVuZ3Vpbl9oaXN0ICU+JSBsYXlvdXQoeWF4aXMgPSBsaXN0KHRpdGxlID0gJ2NvdW50JyksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhcm1vZGUgPSJvdmVybGF5IikNCmBgYA0KDQojIyB7I2lzbGFuZHNoaXN0fQ0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IFQsIGVjaG8gPSBULCB3YXJuaW5nID0gRiwgbWVzc2FnZSA9IEYsIGZpZy5hbGlnbiA9ICJjZW50ZXIifQ0KcGVuZ3Vpbl9oaXN0DQpgYGANCg0KIyMNCg0KTm8gYW5zd2VyIHJlcXVpcmVkLg0KDQojIENyZWF0aW5nIEludGVyYWN0aXZlIFNjYXR0ZXIgUGxvdHMgaW4gUlN0dWRpbyB7I3NjYXR0ZXJ9IA0KDQojIyB7I3NpbXBsZXNjYXR0ZXJ9DQoNCk5vIGFuc3dlciByZXF1aXJlZC4NCg0KIyMgeyNzY2F0dGVyYmFzZX0NCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBGLCBlY2hvID0gVH0NCnBlbmd1aW5zX3NjYXR0ZXIgPC0gcGxvdF9seShkYXRhID0gcGVuZ3VpbnMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHggPSB+Ym9keV9tYXNzX2csIHkgPSB+ZmxpcHBlcl9sZW5ndGhfbW0pDQpwZW5ndWluc19zY2F0dGVyDQpgYGANCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gRiwgd2FybmluZyA9IEZ9DQpwZW5ndWluc19zY2F0dGVyIDwtIHBsb3RfbHkoZGF0YSA9IHBlbmd1aW5zLCB4ID0gfmJvZHlfbWFzc19nLCB5ID0gfmZsaXBwZXJfbGVuZ3RoX21tLCB0eXBlID0gInNjYXR0ZXIiLCBtb2RlID0gIm1hcmtlcnMiKQ0Kc3VwcHJlc3NNZXNzYWdlcyhwZW5ndWluc19zY2F0dGVyKQ0KYGBgDQoNCiMjIHsjc2NhdHRlcmNvbG91cn0NCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBGLCBlY2hvID0gVH0NCnBlbmd1aW5zX3NjYXR0ZXIyIDwtIHBsb3RfbHkoZGF0YSA9IHBlbmd1aW5zLCB4ID0gfmJvZHlfbWFzc19nLCB5ID0gfmZsaXBwZXJfbGVuZ3RoX21tLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSB+c2V4KQ0KcGVuZ3VpbnNfc2NhdHRlcjINCmBgYA0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IFQsIGVjaG8gPSBGLCB3YXJuaW5nID0gRiwgZmlnLmFsaWduID0gImNlbnRlciJ9DQpwZW5ndWluc19zY2F0dGVyMiA8LSBwbG90X2x5KGRhdGEgPSBwZW5ndWlucywgeCA9IH5ib2R5X21hc3NfZywgeSA9IH5mbGlwcGVyX2xlbmd0aF9tbSwgY29sb3IgPSB+c2V4LCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZSA9ICJzY2F0dGVyIiwgbW9kZSA9ICJtYXJrZXJzIikNCnN1cHByZXNzTWVzc2FnZXMocGVuZ3VpbnNfc2NhdHRlcjIpDQpgYGANCg0KIyMgeyNzY2F0dGVyY29sb3Vyc30NCg0KQW4gZXhhbXBsZSByZXN1bHQgZm9yIGFuIGFyYml0cmFyeSBzZWxlY3Rpb24gb2YgY29sb3VycyBpcyBzaG93biBiZWxvdy4NCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBGLCBlY2hvID0gVH0NCnBlbmd1aW5zX3NjYXR0ZXJfY29sb3VycyA8LSBwbG90X2x5KGRhdGEgPSBwZW5ndWlucywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4ID0gfmJvZHlfbWFzc19nLCB5ID0gfmZsaXBwZXJfbGVuZ3RoX21tLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gfnNleCwgY29sb3JzID0gYygiY3lhbiIsICJvcmFuZ2UiKSkNCnBlbmd1aW5zX3NjYXR0ZXJfY29sb3Vycw0KYGBgDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gVCwgZWNobyA9IEYsIHdhcm5pbmcgPSBGLCBmaWcuYWxpZ24gPSAiY2VudGVyIn0NCnBlbmd1aW5zX3NjYXR0ZXJfY29sb3VycyA8LSBwbG90X2x5KGRhdGEgPSBwZW5ndWlucywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4ID0gfmJvZHlfbWFzc19nLCB5ID0gfmZsaXBwZXJfbGVuZ3RoX21tLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gfnNleCwgY29sb3JzID0gYygiY3lhbiIsICJvcmFuZ2UiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGUgPSAic2NhdHRlciIsIG1vZGUgPSAibWFya2VycyIpDQpwZW5ndWluc19zY2F0dGVyX2NvbG91cnMNCmBgYA0KDQojIw0KDQpGb3IgYnJldml0eSBvbmx5IHRoZSByZXN1bHQgZm9yIHRoZSBgU2V0MmAgYGNvbG9yc2Agc3BlY2lmaWNhdGlvbiBpcyBzaG93biBiZWxvdy4NCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBGLCBlY2hvID0gVH0NCnBlbmd1aW5zX3NjYXR0ZXJfY29sb3VycyA8LSBwbG90X2x5KGRhdGEgPSBwZW5ndWlucywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4ID0gfmJvZHlfbWFzc19nLCB5ID0gfmZsaXBwZXJfbGVuZ3RoX21tLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gfnNleCwgY29sb3JzID0gIlNldDIiKQ0KcGVuZ3VpbnNfc2NhdHRlcl9jb2xvdXJzDQpgYGANCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gRiwgd2FybmluZyA9IEYsIGZpZy5hbGlnbiA9ICJjZW50ZXIifQ0KcGVuZ3VpbnNfc2NhdHRlcl9jb2xvdXJzIDwtIHBsb3RfbHkoZGF0YSA9IHBlbmd1aW5zLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHggPSB+Ym9keV9tYXNzX2csIHkgPSB+ZmxpcHBlcl9sZW5ndGhfbW0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSB+c2V4LCBjb2xvcnMgPSAiU2V0MyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gInNjYXR0ZXIiLCBtb2RlID0gIm1hcmtlcnMiKQ0KcGVuZ3VpbnNfc2NhdHRlcl9jb2xvdXJzDQpgYGANCg0KIyMNCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBGLCBlY2hvID0gVH0NCnBlbmd1aW5zX3NjYXR0ZXIyIDwtIHBsb3RfbHkoZGF0YSA9IHBlbmd1aW5zLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeCA9IH5ib2R5X21hc3NfZywgeSA9IH5mbGlwcGVyX2xlbmd0aF9tbSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gfnNleCwgY29sb3JzID0gIlNldDEiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gInNjYXR0ZXIiLCBtb2RlID0gIm1hcmtlcnMiKQ0KcGVuZ3VpbnNfc2NhdHRlcjINCmBgYA0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IFQsIGVjaG8gPSBUfQ0KcGVuZ3VpbnNfc2NhdHRlcjIgPC0gcGxvdF9seShkYXRhID0gcGVuZ3VpbnMsIHggPSB+Ym9keV9tYXNzX2csIHkgPSB+ZmxpcHBlcl9sZW5ndGhfbW0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IH5zZXgsIGNvbG9ycyA9ICJTZXQxIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZSA9ICJzY2F0dGVyIiwgbW9kZSA9ICJsaW5lcyIpDQpwZW5ndWluc19zY2F0dGVyMg0KYGBgDQoNCk5vdGUgdGhhdCBoZXJlLCBSIGlzIGRyYXdpbmcgYSBsaW5lIGJldHdlZW4gdGhlIGluZGl2aWR1YWwgZGF0YSBwb2ludHMgLSBjbGVhcmx5IHdlIGRvbid0IHdhbnQgdGhpcyENCg0KIyMNCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gVCwgd2FybmluZyA9IEZ9DQpwZW5ndWluc19zY2F0dGVyMiA8LSBwbG90X2x5KGRhdGEgPSBwZW5ndWlucywgeCA9IH5ib2R5X21hc3NfZywgeSA9IH5mbGlwcGVyX2xlbmd0aF9tbSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gfnNleCwgY29sb3JzID0gIlNldDEiLCB0ZXh0ID0gfnNwZWNpZXMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGUgPSAic2NhdHRlciIsIG1vZGUgPSAibWFya2VycyIpDQpwZW5ndWluc19zY2F0dGVyMg0KYGBgDQoNCg0KIyMgeyNzY2F0dGVyc3ltYm9sfQ0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IEYsIGVjaG8gPSBUfQ0KcGVuZ3VpbnNfc2NhdHRlcjMgPC0gcGxvdF9seShkYXRhID0gcGVuZ3VpbnMsIHggPSB+Ym9keV9tYXNzX2csIHkgPSB+ZmxpcHBlcl9sZW5ndGhfbW0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IH5zZXgsIGNvbG9ycyA9ICJTZXQxIiwgc3ltYm9sID0gfnNwZWNpZXMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gInNjYXR0ZXIiLCBtb2RlID0gIm1hcmtlcnMiKQ0KcGVuZ3VpbnNfc2NhdHRlcjMNCmBgYA0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IFQsIGVjaG8gPSBGLCB3YXJuaW5nID0gRiwgbWVzc2FnZSA9IEYsIGZpZy5hbGlnbiA9ICJjZW50ZXIifQ0KcGVuZ3VpbnNfc2NhdHRlcjMgPC0gcGxvdF9seShkYXRhID0gcmVtb3ZlX21pc3NpbmcocGVuZ3VpbnMpLCB4ID0gfmJvZHlfbWFzc19nLCB5ID0gfmZsaXBwZXJfbGVuZ3RoX21tLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSB+c2V4LCBjb2xvcnMgPSAiU2V0MSIsIHN5bWJvbCA9IH5zcGVjaWVzLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZSA9ICJzY2F0dGVyIiwgbW9kZSA9ICJtYXJrZXJzIikNCg0KcGVuZ3VpbnNfc2NhdHRlcjMNCmBgYA0KDQojIw0KDQpIZXJlIHdlIGhhdmUgdXNlZCB0aGUgc3ltYm9scyBgY3Jvc3NgLCBgZGlhbW9uZGAgYW5kIGBzdGFyYC4NCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBGLCBlY2hvID0gVH0NCnBlbmd1aW5zX3NjYXR0ZXIzIDwtIHBsb3RfbHkoZGF0YSA9IHBlbmd1aW5zLCB4ID0gfmJvZHlfbWFzc19nLCB5ID0gfmZsaXBwZXJfbGVuZ3RoX21tLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSB+c2V4LCBjb2xvcnMgPSAiU2V0MSIsIHN5bWJvbCA9IH5zcGVjaWVzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzeW1ib2xzID0gYygiY3Jvc3MiLCAiZGlhbW9uZCIsICJzdGFyIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGUgPSAic2NhdHRlciIsIG1vZGUgPSAibWFya2VycyIpDQpwZW5ndWluc19zY2F0dGVyMw0KYGBgDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gVCwgZWNobyA9IEYsIHdhcm5pbmcgPSBGLCBtZXNzYWdlID0gRiwgZmlnLmFsaWduID0gImNlbnRlciJ9DQpwZW5ndWluc19zY2F0dGVyMyA8LSBwbG90X2x5KGRhdGEgPSByZW1vdmVfbWlzc2luZyhwZW5ndWlucyksIHggPSB+Ym9keV9tYXNzX2csIHkgPSB+ZmxpcHBlcl9sZW5ndGhfbW0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IH5zZXgsIGNvbG9ycyA9ICJTZXQxIiwgc3ltYm9sID0gfnNwZWNpZXMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzeW1ib2xzID0gYygiY3Jvc3MiLCAiZGlhbW9uZCIsICJzdGFyIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGUgPSAic2NhdHRlciIsIG1vZGUgPSAibWFya2VycyIpDQoNCnBlbmd1aW5zX3NjYXR0ZXIzDQpgYGANCg0KIyMNCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBGLCBlY2hvID0gVH0NCnBlbmd1aW5zX3NjYXR0ZXIzIDwtIHBsb3RfbHkoZGF0YSA9IHBlbmd1aW5zLCB4ID0gfmJvZHlfbWFzc19nLCB5ID0gfmZsaXBwZXJfbGVuZ3RoX21tLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSB+c2V4LCBjb2xvcnMgPSAiU2V0MSIsIHN5bWJvbCA9IH5zcGVjaWVzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzeW1ib2xzID0gYygiY3Jvc3MiLCAiZGlhbW9uZCIsICJzdGFyIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGUgPSAic2NhdHRlciIsIG1vZGUgPSAibWFya2VycyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcmtlciA9IGxpc3Qoc2l6ZSA9IDgpKQ0KcGVuZ3VpbnNfc2NhdHRlcjMNCmBgYA0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IFQsIGVjaG8gPSBGLCB3YXJuaW5nID0gRiwgbWVzc2FnZSA9IEYsIGZpZy5hbGlnbiA9ICJjZW50ZXIifQ0KcGVuZ3VpbnNfc2NhdHRlcjMgPC0gcGxvdF9seShkYXRhID0gcmVtb3ZlX21pc3NpbmcocGVuZ3VpbnMpLCB4ID0gfmJvZHlfbWFzc19nLCB5ID0gfmZsaXBwZXJfbGVuZ3RoX21tLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSB+c2V4LCBjb2xvcnMgPSAiU2V0MSIsIHN5bWJvbCA9IH5zcGVjaWVzLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3ltYm9scyA9IGMoImNyb3NzIiwgImRpYW1vbmQiLCAic3RhciIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gInNjYXR0ZXIiLCBtb2RlID0gIm1hcmtlcnMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXJrZXIgPSBsaXN0KHNpemUgPSA4KSkNCg0KcGVuZ3VpbnNfc2NhdHRlcjMNCmBgYA0KDQojIENyZWF0aW5nIHlvdXIgb3duIGBwbG90bHlgIFNjYXR0ZXIgUGxvdCB7I3NjYXR0ZXJwZXJzb25hbH0NCg0KIyMNCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gVCwgbWVzc2FnZSA9IEYsIHdhcm5pbmcgPSBGLCBmaWcuYWxpZ24gPSAiY2VudGVyIn0NCnBlbmd1aW5zX3NjYXR0ZXJfbmV3IDwtIHBsb3RfbHkoZGF0YSA9IHBlbmd1aW5zLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeCA9IH5ib2R5X21hc3NfZywgeSA9IH5iaWxsX2xlbmd0aF9tbSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZSA9ICJzY2F0dGVyIiwgbW9kZSA9ICJtYXJrZXJzIikNCnBlbmd1aW5zX3NjYXR0ZXJfbmV3DQpgYGANCg0KIyMNCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gVCwgbWVzc2FnZSA9IEYsIHdhcm5pbmcgPSBGLCBmaWcuYWxpZ24gPSAiY2VudGVyIn0NCnBlbmd1aW5zX3NjYXR0ZXJfbmV3MiA8LSBwbG90X2x5KGRhdGEgPSBwZW5ndWlucywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4ID0gfmJvZHlfbWFzc19nLCB5ID0gfmJpbGxfbGVuZ3RoX21tLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSB+aXNsYW5kLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZSA9ICJzY2F0dGVyIiwgbW9kZSA9ICJtYXJrZXJzIikNCnBlbmd1aW5zX3NjYXR0ZXJfbmV3Mg0KYGBgDQoNCiMjDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gVCwgZWNobyA9IFQsIG1lc3NhZ2UgPSBGLCB3YXJuaW5nID0gRiwgZmlnLmFsaWduID0gImNlbnRlciJ9DQpwZW5ndWluc19zY2F0dGVyX25ldzMgPC0gcGxvdF9seShkYXRhID0gcGVuZ3VpbnMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeCA9IH5ib2R5X21hc3NfZywgeSA9IH5iaWxsX2xlbmd0aF9tbSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gfmlzbGFuZCwgc3ltYm9sID0gfnNwZWNpZXMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gInNjYXR0ZXIiLCBtb2RlID0gIm1hcmtlcnMiKQ0KcGVuZ3VpbnNfc2NhdHRlcl9uZXczDQpgYGANCg0KIyMNCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gVCwgbWVzc2FnZSA9IEYsIHdhcm5pbmcgPSBGLCBmaWcuYWxpZ24gPSAiY2VudGVyIn0NCnBlbmd1aW5zX3NjYXR0ZXJfbmV3NCA8LSBwbG90X2x5KGRhdGEgPSBwZW5ndWlucywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4ID0gfmJvZHlfbWFzc19nLCB5ID0gfmJpbGxfbGVuZ3RoX21tLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSB+aXNsYW5kLCBzeW1ib2wgPSB+c3BlY2llcywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzeW1ib2xzID0gYygiY3Jvc3MiLCAiZGlhbW9uZCIsICJzdGFyIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gInNjYXR0ZXIiLCBtb2RlID0gIm1hcmtlcnMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFya2VyID0gbGlzdChzaXplPTgpKQ0KcGVuZ3VpbnNfc2NhdHRlcl9uZXc0DQpgYGANCg0KIyMNCg0KSXQgZG9lcyBzZWVtIHRoYXQgcGVuZ3VpbnMgbGl2aW5nIG9uIGRpZmZlcmVudCBpc2xhbmRzIGhhdmUgbm90aWNlYWJseSBkaWZmZXJlbnQgYGJvZHlfbWFzc19nYCBhbmQgYGJpbGxfbGVuZ3RoX21tYCBtZWFzdXJlbWVudHMsIGJ1dCB0aGlzIGlzIGFsc28gZHVlIHRvIHRoZSBmYWN0IHRoYXQgc29tZSBzcGVjaWVzIG9mIHBlbmd1aW4gb25seSBsaXZlIG9uIG9uZSBvZiB0aGUgdGhyZWUgaXNsYW5kcyAtIGUuZy4gR2VudG9vIGFuZCBDaGluc3RyYXAgcGVuZ3VpbnMgb25seSBsaXZlIG9uIEJpc2NvZSBpc2xhbmQgYW5kIERyZWFtIGlzbGFuZCByZXNwZWN0aXZlbHksIHdoZXJlYXMgdGhlIEFkZWxpZSBwZW5ndWlucyBsaXZlIG9uIGFsbCB0aHJlZSBpc2xhbmRzLg0KDQpIb3dldmVyLCB3ZSBhbHNvIG5vdGUgdGhhdCB0aGUgQWRlbGllIHBlbmd1aW5zIGxpdmluZyBvbiBUb3JnZXJzZW4gaXNsYW5kIGFyZSBtdWNoIHNtYWxsZXIgb3ZlcmFsbCB0aGFuIEFkZWxpZSBwZW5ndWlucyBsaXZpbmcgb24gb3RoZXIgaXNsYW5kcy4NCg0KPGJyPg0KDQojIyMjIFRoYXQncyBldmVyeXRoaW5nIGNvdmVyZWQuICMjIyMgey19DQoNCjxicj4NCg0KIyBSZWZlcmVuY2VzIHstICNSZWZ9DQo8ZGl2IGlkPSJyZWZzIj48L2Rpdj4NCg0KPGJyPg0KDQo8Zm9udCBjb2xvciA9ICJncmV5Ij4NClRoZXNlIG5vdGVzIGhhdmUgYmVlbiBwcmVwYXJlZCBieSBSdXBlcnQgS3V2ZWtlLiBUaGUgY29weXJpZ2h0IGZvciB0aGUgbWF0ZXJpYWwgaW4gdGhlc2Ugbm90ZXMgcmVzaWRlcyB3aXRoIHRoZSBhdXRob3IgbmFtZWQgYWJvdmUsIHdpdGggdGhlIERlcGFydG1lbnQgb2YgTWF0aGVtYXRpY2FsIGFuZCBQaHlzaWNhbCBTY2llbmNlcyBhbmQgd2l0aCBMYSBUcm9iZSBVbml2ZXJzaXR5LiBDb3B5cmlnaHQgaW4gdGhpcyB3b3JrIGlzIHZlc3RlZCBpbiBMYSBUcm9iZSBVbml2ZXJzaXR5IGluY2x1ZGluZyBhbGwgTGEgVHJvYmUgVW5pdmVyc2l0eSBicmFuZGluZyBhbmQgbmFtaW5nLiBVbmxlc3Mgb3RoZXJ3aXNlIHN0YXRlZCwgbWF0ZXJpYWwgd2l0aGluIHRoaXMgd29yayBpcyBsaWNlbnNlZCB1bmRlciBhIENyZWF0aXZlIENvbW1vbnMgQXR0cmlidXRpb24tTm9uIENvbW1lcmNpYWwtTm9uIERlcml2YXRpdmVzIExpY2Vuc2UgDQo8YSBocmVmID0gImh0dHBzOi8vY3JlYXRpdmVjb21tb25zLm9yZy9saWNlbnNlcy9ieS1uYy1uZC80LjAvQ0MiIHRhcmdldD0iX2JsYW5rIj4gQlktTkMtTkQuIDwvYT4NCjwvZm9udD4=