Data Science Module
Palmer Penguins Data Set
# Install package
install.packages("palmerpenguins")
# This code loads the `palmerpenguins` package into your current R working environment.
library(palmerpenguins)
## Warning: package 'palmerpenguins' was built under R version 4.2.2
# This code summarises 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
Plotly Scatter Plots
# Install package
install.packages("plotly")
# Load package
library(plotly)
penguins_scatter <- plot_ly(data = penguins, x = ~body_mass_g, y = ~flipper_length_mm)
penguins_scatter
penguins_scatter2 <- plot_ly(data = penguins, x = ~body_mass_g, y = ~flipper_length_mm,
color = ~sex)
penguins_scatter2
penguins_scatter_colours <- plot_ly(data = penguins,
x = ~body_mass_g, y = ~flipper_length_mm,
color = ~sex, colors = c("cyan", "orange"))
penguins_scatter_colours
penguins_scatter_colours <- plot_ly(data = penguins,
x = ~body_mass_g, y = ~flipper_length_mm,
color = ~sex, colors = "Set2")
penguins_scatter_colours
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!
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
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
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
Creating your own Plotly Scatter Plot
penguins_scatter_new <- plot_ly(data = penguins, x = ~body_mass_g, y = ~bill_length_mm,
type = "scatter", mode = "markers")
penguins_scatter_new
penguins_scatter_new2 <- plot_ly(data = penguins, x = ~body_mass_g, y = ~bill_length_mm,
color = ~island,
type = "scatter", mode = "markers")
penguins_scatter_new2
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
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
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.
Mixed Subplots
Recall from our [Week 1 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"))
penguin_combined_plots
penguin_combined_plots_new <- subplot(penguins_scatter_new4, penguin_hist,
nrows = 2, margin = 0.05)
penguin_combined_plots_new <- penguin_combined_plots_new %>%
layout(title = "Palmer Penguin Species Data",
xaxis = list(title = 'body_mass_g'),
yaxis = list(title = "bill_length_mm"),
xaxis2 = list(title = 'body_mass_g'),
yaxis2 = list(title = "count"))
penguin_combined_plots_new
Note that this set of graphs is actually more informative than the previous subplots, since the colours for both graphs here align with the data being represented. It is always important to take such presentation possibilities into account when developing your subplots.
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+DQoNCiMjIyBEYXRhIFNjaWVuY2UgTW9kdWxlIHstfQ0KDQojIyMgVG9waWMgMkI6IERhdGEgVmlzdWFsaXNhdGlvbiBJSSB7LX0NCg0KPGJyPg0KDQpFeGFtcGxlIFIgY29kZSBzb2x1dGlvbnMgZm9yIHRoZSBbRGF0YSBTY2llbmNlIENvbXB1dGVyIExhYiAyXShodHRwczovL3JwdWJzLmNvbS9MVFVfU1RNMTAwMS9EU01DTDJfUyksIHdoaWNoIHVzZXMgZGF0YSBmcm9tIEBwZW5ndWlucywgYW5kIHRoZSBgcGxvdGx5YCBbQHBsb3RseV0gUiBwYWNrYWdlLCBhcmUgcHJlc2VudGVkIGJlbG93Lg0KDQo8YnI+DQoNCiMgUGFsbWVyIFBlbmd1aW5zIERhdGEgU2V0IHsjcGVuZ3VpbnN9DQoNCmBgYHtyLCBpbmNsdWRlID0gRn0NCmluc3RhbGwucGFja2FnZXMoInBhbG1lcnBlbmd1aW5zIiwgcmVwb3MgPSAiaHR0cDovL2NyYW4udXMuci1wcm9qZWN0Lm9yZyIpICMgSW5zdGFsbCBwYWNrYWdlDQppbnN0YWxsLnBhY2thZ2VzKCJwbG90bHkiLCByZXBvcyA9ICJodHRwOi8vY3Jhbi51cy5yLXByb2plY3Qub3JnIikgIyBJbnN0YWxsIHBhY2thZ2UNCmBgYA0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IEYsIGVjaG8gPSBUfQ0KIyBJbnN0YWxsIHBhY2thZ2UNCmluc3RhbGwucGFja2FnZXMoInBhbG1lcnBlbmd1aW5zIikNCmBgYA0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IFQsIGVjaG8gPSBUfQ0KIyBUaGlzIGNvZGUgbG9hZHMgdGhlIGBwYWxtZXJwZW5ndWluc2AgcGFja2FnZSBpbnRvIHlvdXIgY3VycmVudCBSIHdvcmtpbmcgZW52aXJvbm1lbnQuDQpsaWJyYXJ5KHBhbG1lcnBlbmd1aW5zKQ0KIyBUaGlzIGNvZGUgc3VtbWFyaXNlcyB0aGUgZGF0YSBpbiB0aGUgYHBhbG1lcnBlbmd1aW5zYCBwYWNrYWdlLg0Kc3VtbWFyeShwZW5ndWlucykNCmBgYA0KDQojIFBsb3RseSBTY2F0dGVyIFBsb3RzIHsjc2NhdHRlcn0gDQoNCiMjIA0KDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gRiwgZWNobyA9IFR9DQojIEluc3RhbGwgcGFja2FnZQ0KaW5zdGFsbC5wYWNrYWdlcygicGxvdGx5IikNCmBgYA0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IFQsIGluY2x1ZGUgPSBGfQ0KIyBMb2FkIHBhY2thZ2UNCmxpYnJhcnkocGxvdGx5KQ0KYGBgDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gRiwgZWNobyA9IFR9DQojIExvYWQgcGFja2FnZQ0KbGlicmFyeShwbG90bHkpDQpgYGANCg0KIyMgeyNzaW1wbGVzY2F0dGVyfQ0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IEYsIGVjaG8gPSBUfQ0KcGVuZ3VpbnNfc2NhdHRlciA8LSBwbG90X2x5KGRhdGEgPSBwZW5ndWlucywgeCA9IH5ib2R5X21hc3NfZywgeSA9IH5mbGlwcGVyX2xlbmd0aF9tbSkNCnBlbmd1aW5zX3NjYXR0ZXINCmBgYA0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IFQsIGVjaG8gPSBGLCB3YXJuaW5nID0gRn0NCnBlbmd1aW5zX3NjYXR0ZXIgPC0gcGxvdF9seShkYXRhID0gcGVuZ3VpbnMsIHggPSB+Ym9keV9tYXNzX2csIHkgPSB+ZmxpcHBlcl9sZW5ndGhfbW0sIHR5cGUgPSAic2NhdHRlciIsIG1vZGUgPSAibWFya2VycyIpDQpzdXBwcmVzc01lc3NhZ2VzKHBlbmd1aW5zX3NjYXR0ZXIpDQpgYGANCg0KIyMNCg0KTm8gYW5zd2VyIHJlcXVpcmVkLg0KDQojIyB7I3NjYXR0ZXJjb2xvdXJ9DQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gRiwgZWNobyA9IFR9DQpwZW5ndWluc19zY2F0dGVyMiA8LSBwbG90X2x5KGRhdGEgPSBwZW5ndWlucywgeCA9IH5ib2R5X21hc3NfZywgeSA9IH5mbGlwcGVyX2xlbmd0aF9tbSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gfnNleCkNCnBlbmd1aW5zX3NjYXR0ZXIyDQpgYGANCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gRiwgd2FybmluZyA9IEYsIGZpZy5hbGlnbiA9ICJjZW50ZXIifQ0KcGVuZ3VpbnNfc2NhdHRlcjIgPC0gcGxvdF9seShkYXRhID0gcGVuZ3VpbnMsIHggPSB+Ym9keV9tYXNzX2csIHkgPSB+ZmxpcHBlcl9sZW5ndGhfbW0sIGNvbG9yID0gfnNleCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGUgPSAic2NhdHRlciIsIG1vZGUgPSAibWFya2VycyIpDQpzdXBwcmVzc01lc3NhZ2VzKHBlbmd1aW5zX3NjYXR0ZXIyKQ0KYGBgDQoNCiMjIHsjc2NhdHRlcmNvbG91cnN9DQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gRiwgZWNobyA9IFR9DQpwZW5ndWluc19zY2F0dGVyX2NvbG91cnMgPC0gcGxvdF9seShkYXRhID0gcGVuZ3VpbnMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeCA9IH5ib2R5X21hc3NfZywgeSA9IH5mbGlwcGVyX2xlbmd0aF9tbSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IH5zZXgsIGNvbG9ycyA9IGMoImN5YW4iLCAib3JhbmdlIikpDQpwZW5ndWluc19zY2F0dGVyX2NvbG91cnMNCmBgYA0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IFQsIGVjaG8gPSBGLCB3YXJuaW5nID0gRiwgZmlnLmFsaWduID0gImNlbnRlciJ9DQpwZW5ndWluc19zY2F0dGVyX2NvbG91cnMgPC0gcGxvdF9seShkYXRhID0gcGVuZ3VpbnMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeCA9IH5ib2R5X21hc3NfZywgeSA9IH5mbGlwcGVyX2xlbmd0aF9tbSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IH5zZXgsIGNvbG9ycyA9IGMoImN5YW4iLCAib3JhbmdlIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gInNjYXR0ZXIiLCBtb2RlID0gIm1hcmtlcnMiKQ0KcGVuZ3VpbnNfc2NhdHRlcl9jb2xvdXJzDQpgYGANCg0KIyMNCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBGLCBlY2hvID0gVH0NCnBlbmd1aW5zX3NjYXR0ZXJfY29sb3VycyA8LSBwbG90X2x5KGRhdGEgPSBwZW5ndWlucywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4ID0gfmJvZHlfbWFzc19nLCB5ID0gfmZsaXBwZXJfbGVuZ3RoX21tLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gfnNleCwgY29sb3JzID0gIlNldDIiKQ0KcGVuZ3VpbnNfc2NhdHRlcl9jb2xvdXJzDQpgYGANCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gRiwgd2FybmluZyA9IEYsIGZpZy5hbGlnbiA9ICJjZW50ZXIifQ0KcGVuZ3VpbnNfc2NhdHRlcl9jb2xvdXJzIDwtIHBsb3RfbHkoZGF0YSA9IHBlbmd1aW5zLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHggPSB+Ym9keV9tYXNzX2csIHkgPSB+ZmxpcHBlcl9sZW5ndGhfbW0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSB+c2V4LCBjb2xvcnMgPSAiU2V0MyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gInNjYXR0ZXIiLCBtb2RlID0gIm1hcmtlcnMiKQ0KcGVuZ3VpbnNfc2NhdHRlcl9jb2xvdXJzDQpgYGANCg0KIyMNCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBGLCBlY2hvID0gVH0NCnBlbmd1aW5zX3NjYXR0ZXIyIDwtIHBsb3RfbHkoZGF0YSA9IHBlbmd1aW5zLCB4ID0gfmJvZHlfbWFzc19nLCB5ID0gfmZsaXBwZXJfbGVuZ3RoX21tLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSB+c2V4LCBjb2xvcnMgPSAiU2V0MSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGUgPSAic2NhdHRlciIsIG1vZGUgPSAibWFya2VycyIpDQpwZW5ndWluc19zY2F0dGVyMg0KYGBgDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gVCwgZWNobyA9IFR9DQpwZW5ndWluc19zY2F0dGVyMiA8LSBwbG90X2x5KGRhdGEgPSBwZW5ndWlucywgeCA9IH5ib2R5X21hc3NfZywgeSA9IH5mbGlwcGVyX2xlbmd0aF9tbSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gfnNleCwgY29sb3JzID0gIlNldDEiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gInNjYXR0ZXIiLCBtb2RlID0gImxpbmVzIikNCnBlbmd1aW5zX3NjYXR0ZXIyDQpgYGANCg0KTm90ZSB0aGF0IGhlcmUsIFIgaXMgZHJhd2luZyBhIGxpbmUgYmV0d2VlbiB0aGUgaW5kaXZpZHVhbCBkYXRhIHBvaW50cyAtIGNsZWFybHkgd2UgZG9uJ3Qgd2FudCB0aGlzIQ0KDQojIyB7I3NjYXR0ZXJzeW1ib2x9DQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gRiwgZWNobyA9IFR9DQpwZW5ndWluc19zY2F0dGVyMyA8LSBwbG90X2x5KGRhdGEgPSBwZW5ndWlucywgeCA9IH5ib2R5X21hc3NfZywgeSA9IH5mbGlwcGVyX2xlbmd0aF9tbSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gfnNleCwgY29sb3JzID0gIlNldDEiLCBzeW1ib2wgPSB+c3BlY2llcywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGUgPSAic2NhdHRlciIsIG1vZGUgPSAibWFya2VycyIpDQpwZW5ndWluc19zY2F0dGVyMw0KYGBgDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gVCwgZWNobyA9IEYsIHdhcm5pbmcgPSBGLCBtZXNzYWdlID0gRiwgZmlnLmFsaWduID0gImNlbnRlciJ9DQpwZW5ndWluc19zY2F0dGVyMyA8LSBwbG90X2x5KGRhdGEgPSByZW1vdmVfbWlzc2luZyhwZW5ndWlucyksIHggPSB+Ym9keV9tYXNzX2csIHkgPSB+ZmxpcHBlcl9sZW5ndGhfbW0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IH5zZXgsIGNvbG9ycyA9ICJTZXQxIiwgc3ltYm9sID0gfnNwZWNpZXMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gInNjYXR0ZXIiLCBtb2RlID0gIm1hcmtlcnMiKQ0KDQpwZW5ndWluc19zY2F0dGVyMw0KYGBgDQoNCiMjDQoNCkhlcmUgd2UgaGF2ZSB1c2VkIHRoZSBzeW1ib2xzIGBjcm9zc2AsIGBkaWFtb25kYCBhbmQgYHN0YXJgLg0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IEYsIGVjaG8gPSBUfQ0KcGVuZ3VpbnNfc2NhdHRlcjMgPC0gcGxvdF9seShkYXRhID0gcGVuZ3VpbnMsIHggPSB+Ym9keV9tYXNzX2csIHkgPSB+ZmxpcHBlcl9sZW5ndGhfbW0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IH5zZXgsIGNvbG9ycyA9ICJTZXQxIiwgc3ltYm9sID0gfnNwZWNpZXMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN5bWJvbHMgPSBjKCJjcm9zcyIsICJkaWFtb25kIiwgInN0YXIiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZSA9ICJzY2F0dGVyIiwgbW9kZSA9ICJtYXJrZXJzIikNCnBlbmd1aW5zX3NjYXR0ZXIzDQpgYGANCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gRiwgd2FybmluZyA9IEYsIG1lc3NhZ2UgPSBGLCBmaWcuYWxpZ24gPSAiY2VudGVyIn0NCnBlbmd1aW5zX3NjYXR0ZXIzIDwtIHBsb3RfbHkoZGF0YSA9IHJlbW92ZV9taXNzaW5nKHBlbmd1aW5zKSwgeCA9IH5ib2R5X21hc3NfZywgeSA9IH5mbGlwcGVyX2xlbmd0aF9tbSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gfnNleCwgY29sb3JzID0gIlNldDEiLCBzeW1ib2wgPSB+c3BlY2llcywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN5bWJvbHMgPSBjKCJjcm9zcyIsICJkaWFtb25kIiwgInN0YXIiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZSA9ICJzY2F0dGVyIiwgbW9kZSA9ICJtYXJrZXJzIikNCg0KcGVuZ3VpbnNfc2NhdHRlcjMNCmBgYA0KDQojIw0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IEYsIGVjaG8gPSBUfQ0KcGVuZ3VpbnNfc2NhdHRlcjMgPC0gcGxvdF9seShkYXRhID0gcGVuZ3VpbnMsIHggPSB+Ym9keV9tYXNzX2csIHkgPSB+ZmxpcHBlcl9sZW5ndGhfbW0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IH5zZXgsIGNvbG9ycyA9ICJTZXQxIiwgc3ltYm9sID0gfnNwZWNpZXMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN5bWJvbHMgPSBjKCJjcm9zcyIsICJkaWFtb25kIiwgInN0YXIiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZSA9ICJzY2F0dGVyIiwgbW9kZSA9ICJtYXJrZXJzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFya2VyID0gbGlzdChzaXplID0gOCkpDQpwZW5ndWluc19zY2F0dGVyMw0KYGBgDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gVCwgZWNobyA9IEYsIHdhcm5pbmcgPSBGLCBtZXNzYWdlID0gRiwgZmlnLmFsaWduID0gImNlbnRlciJ9DQpwZW5ndWluc19zY2F0dGVyMyA8LSBwbG90X2x5KGRhdGEgPSByZW1vdmVfbWlzc2luZyhwZW5ndWlucyksIHggPSB+Ym9keV9tYXNzX2csIHkgPSB+ZmxpcHBlcl9sZW5ndGhfbW0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IH5zZXgsIGNvbG9ycyA9ICJTZXQxIiwgc3ltYm9sID0gfnNwZWNpZXMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzeW1ib2xzID0gYygiY3Jvc3MiLCAiZGlhbW9uZCIsICJzdGFyIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGUgPSAic2NhdHRlciIsIG1vZGUgPSAibWFya2VycyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcmtlciA9IGxpc3Qoc2l6ZSA9IDgpKQ0KDQpwZW5ndWluc19zY2F0dGVyMw0KYGBgDQoNCiMgQ3JlYXRpbmcgeW91ciBvd24gUGxvdGx5IFNjYXR0ZXIgUGxvdCB7I3NjYXR0ZXJwZXJzb25hbH0NCg0KIyMNCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gVCwgbWVzc2FnZSA9IEYsIHdhcm5pbmcgPSBGLCBmaWcuYWxpZ24gPSAiY2VudGVyIn0NCnBlbmd1aW5zX3NjYXR0ZXJfbmV3IDwtIHBsb3RfbHkoZGF0YSA9IHBlbmd1aW5zLCB4ID0gfmJvZHlfbWFzc19nLCB5ID0gfmJpbGxfbGVuZ3RoX21tLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gInNjYXR0ZXIiLCBtb2RlID0gIm1hcmtlcnMiKQ0KcGVuZ3VpbnNfc2NhdHRlcl9uZXcNCmBgYA0KDQojIw0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IFQsIGVjaG8gPSBULCBtZXNzYWdlID0gRiwgd2FybmluZyA9IEYsIGZpZy5hbGlnbiA9ICJjZW50ZXIifQ0KcGVuZ3VpbnNfc2NhdHRlcl9uZXcyIDwtIHBsb3RfbHkoZGF0YSA9IHBlbmd1aW5zLCB4ID0gfmJvZHlfbWFzc19nLCB5ID0gfmJpbGxfbGVuZ3RoX21tLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IH5pc2xhbmQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGUgPSAic2NhdHRlciIsIG1vZGUgPSAibWFya2VycyIpDQpwZW5ndWluc19zY2F0dGVyX25ldzINCmBgYA0KDQojIw0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IFQsIGVjaG8gPSBULCBtZXNzYWdlID0gRiwgd2FybmluZyA9IEYsIGZpZy5hbGlnbiA9ICJjZW50ZXIifQ0KcGVuZ3VpbnNfc2NhdHRlcl9uZXczIDwtIHBsb3RfbHkoZGF0YSA9IHBlbmd1aW5zLCB4ID0gfmJvZHlfbWFzc19nLCB5ID0gfmJpbGxfbGVuZ3RoX21tLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IH5pc2xhbmQsIHN5bWJvbCA9IH5zcGVjaWVzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gInNjYXR0ZXIiLCBtb2RlID0gIm1hcmtlcnMiKQ0KcGVuZ3VpbnNfc2NhdHRlcl9uZXczDQpgYGANCg0KIyMNCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gVCwgbWVzc2FnZSA9IEYsIHdhcm5pbmcgPSBGLCBmaWcuYWxpZ24gPSAiY2VudGVyIn0NCnBlbmd1aW5zX3NjYXR0ZXJfbmV3NCA8LSBwbG90X2x5KGRhdGEgPSBwZW5ndWlucywgeCA9IH5ib2R5X21hc3NfZywgeSA9IH5iaWxsX2xlbmd0aF9tbSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSB+aXNsYW5kLCBzeW1ib2wgPSB+c3BlY2llcywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN5bWJvbHMgPSBjKCJjcm9zcyIsICJkaWFtb25kIiwgInN0YXIiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZSA9ICJzY2F0dGVyIiwgbW9kZSA9ICJtYXJrZXJzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFya2VyID0gbGlzdChzaXplPTgpKQ0KcGVuZ3VpbnNfc2NhdHRlcl9uZXc0DQpgYGANCg0KIyMNCg0KSXQgZG9lcyBzZWVtIHRoYXQgcGVuZ3VpbnMgbGl2aW5nIG9uIGRpZmZlcmVudCBpc2xhbmRzIGhhdmUgbm90aWNlYWJseSBkaWZmZXJlbnQgYGJvZHlfbWFzc19nYCBhbmQgYGJpbGxfbGVuZ3RoX21tYCBtZWFzdXJlbWVudHMsIGJ1dCB0aGlzIGlzIGFsc28gZHVlIHRvIHRoZSBmYWN0IHRoYXQgc29tZSBzcGVjaWVzIG9mIHBlbmd1aW4gb25seSBsaXZlIG9uIG9uZSBvZiB0aGUgdGhyZWUgaXNsYW5kcyAtIGUuZy4gR2VudG9vIGFuZCBDaGluc3RyYXAgcGVuZ3VpbnMgb25seSBsaXZlIG9uIEJpc2NvZSBpc2xhbmQgYW5kIERyZWFtIGlzbGFuZCByZXNwZWN0aXZlbHksIHdoZXJlYXMgdGhlIEFkZWxpZSBwZW5ndWlucyBsaXZlIG9uIGFsbCB0aHJlZSBpc2xhbmRzLg0KDQpIb3dldmVyLCB3ZSBhbHNvIG5vdGUgdGhhdCB0aGUgQWRlbGllIHBlbmd1aW5zIGxpdmluZyBvbiBUb3JnZXJzZW4gaXNsYW5kIGFyZSBtdWNoIHNtYWxsZXIgb3ZlcmFsbCB0aGFuIEFkZWxpZSBwZW5ndWlucyBsaXZpbmcgb24gb3RoZXIgaXNsYW5kcy4NCg0KIyBNaXhlZCBTdWJwbG90cyB7I3N1YnBsb3RzfQ0KDQpSZWNhbGwgZnJvbSBvdXIgW1dlZWsgMSBEYXRhIFNjaWVuY2UgQ29tcHV0ZXIgTGFiXSBob3cgd2UgY3JlYXRlZCBzb21lIGhpc3RvZ3JhbXMgZm9yIG91ciBgcGFsbWVycGVuZ3VpbnNgIGRhdGEgc2V0Lg0KU29tZSBvZiB0aGUgY29kZSB1c2VkIGZvciB0aGF0IGxhYiBpcyByZXByb2R1Y2VkIGJlbG93Og0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IFQsIGVjaG8gPSBULCB3YXJuaW5nID0gRiwgbWVzc2FnZSA9IEYsIGZpZy5hbGlnbiA9ICJjZW50ZXIifQ0KcGVuZ3Vpbl9oaXN0IDwtIHBsb3RfbHkoZGF0YSA9IHBlbmd1aW5zLCB4ID0gfmJvZHlfbWFzc19nLCANCiAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gfmlzbGFuZCwgdHlwZSA9ICJoaXN0b2dyYW0iLCBhbHBoYSA9IDAuNikNCg0KcGVuZ3Vpbl9oaXN0IDwtIHBlbmd1aW5faGlzdCAlPiUgbGF5b3V0KHlheGlzID0gbGlzdCh0aXRsZSA9ICdjb3VudCcpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYXJtb2RlID0ib3ZlcmxheSIpDQpwZW5ndWluX2hpc3QNCmBgYA0KDQpTdXBwb3NlIHRoYXQgd2Ugd291bGQgbGlrZSB0byBwcmVzZW50IGFsbCBvdXIgYHBhbG1lcnBlbmd1aW5zYCBkYXRhIHZpc3VhbGlzYXRpb25zIHRvZ2V0aGVyLiBXZSBjYW4gZG8gdGhpcyB1c2luZyB0aGUgYHN1YnBsb3RgIGZ1bmN0aW9uLg0KDQojIyB7I3N1YnBsb3R3YWxrdGhyb3VnaH0NCg0KVGFrZSBhIGxvb2sgYXQgdGhlIFIgY29kZSBiZWxvdzoNCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gVCwgd2FybmluZyA9IEYsIG1lc3NhZ2UgPSBGfQ0KcGVuZ3Vpbl9jb21iaW5lZF9wbG90cyA8LSBzdWJwbG90KHBlbmd1aW5zX3NjYXR0ZXIzLCBwZW5ndWluX2hpc3QsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5yb3dzID0gMiwgbWFyZ2luID0gMC4wNSkgDQpwZW5ndWluX2NvbWJpbmVkX3Bsb3RzIDwtIHBlbmd1aW5fY29tYmluZWRfcGxvdHMgJT4lIA0KICAgICAgICAgICAgICAgICAgICAgICAgICBsYXlvdXQodGl0bGUgPSAiUGFsbWVyIFBlbmd1aW4gRGF0YSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4YXhpcyA9IGxpc3QodGl0bGUgPSAnYm9keV9tYXNzX2cnKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAiZmxpcHBlcl9sZW5ndGhfbW0iKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHhheGlzMiA9IGxpc3QodGl0bGUgPSAnYm9keV9tYXNzX2cnKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5YXhpczIgPSBsaXN0KHRpdGxlID0gImNvdW50IikpDQpgYGANCg0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IFQsIGVjaG8gPSBULCB3YXJuaW5nID0gRiwgbWVzc2FnZSA9IEYsIGZpZy5kaW0gPSBjKDEwLCA4KSwgZmlnLmFsaWduID0gImNlbnRlciJ9DQpwZW5ndWluX2NvbWJpbmVkX3Bsb3RzDQpgYGANCg0KDQojIyANCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gVCwgd2FybmluZyA9IEYsIG1lc3NhZ2UgPSBGfQ0KcGVuZ3Vpbl9jb21iaW5lZF9wbG90c19uZXcgPC0gc3VicGxvdChwZW5ndWluc19zY2F0dGVyX25ldzQsIHBlbmd1aW5faGlzdCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbnJvd3MgPSAyLCBtYXJnaW4gPSAwLjA1KSANCnBlbmd1aW5fY29tYmluZWRfcGxvdHNfbmV3IDwtIHBlbmd1aW5fY29tYmluZWRfcGxvdHNfbmV3ICU+JSANCiAgICAgICAgICAgICAgICAgICAgICAgICAgbGF5b3V0KHRpdGxlID0gIlBhbG1lciBQZW5ndWluIFNwZWNpZXMgRGF0YSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4YXhpcyA9IGxpc3QodGl0bGUgPSAnYm9keV9tYXNzX2cnKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAiYmlsbF9sZW5ndGhfbW0iKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHhheGlzMiA9IGxpc3QodGl0bGUgPSAnYm9keV9tYXNzX2cnKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5YXhpczIgPSBsaXN0KHRpdGxlID0gImNvdW50IikpDQpgYGANCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gVCwgd2FybmluZyA9IEYsIG1lc3NhZ2UgPSBGLCBmaWcuZGltID0gYygxMCwgOCksIGZpZy5hbGlnbiA9ICJjZW50ZXIifQ0KcGVuZ3Vpbl9jb21iaW5lZF9wbG90c19uZXcNCmBgYA0KDQpOb3RlIHRoYXQgdGhpcyBzZXQgb2YgZ3JhcGhzIGlzIGFjdHVhbGx5IG1vcmUgaW5mb3JtYXRpdmUgdGhhbiB0aGUgcHJldmlvdXMgc3VicGxvdHMsIHNpbmNlIHRoZSBjb2xvdXJzIGZvciBib3RoIGdyYXBocyBoZXJlIGFsaWduIHdpdGggdGhlIGRhdGEgYmVpbmcgcmVwcmVzZW50ZWQuIEl0IGlzIGFsd2F5cyBpbXBvcnRhbnQgdG8gdGFrZSBzdWNoIHByZXNlbnRhdGlvbiBwb3NzaWJpbGl0aWVzIGludG8gYWNjb3VudCB3aGVuIGRldmVsb3BpbmcgeW91ciBzdWJwbG90cy4NCg0KPGJyPg0KDQojIyMjIFRoYXQncyBldmVyeXRoaW5nIGNvdmVyZWQuICMjIyMgey19DQoNCjxicj4NCg0KIyBSZWZlcmVuY2VzIHstICNSZWZ9DQo8ZGl2IGlkPSJyZWZzIj48L2Rpdj4NCg0KPGJyPg0KDQo8Zm9udCBjb2xvciA9ICJncmV5Ij4NClRoZXNlIG5vdGVzIGhhdmUgYmVlbiBwcmVwYXJlZCBieSBSdXBlcnQgS3V2ZWtlLiBUaGUgY29weXJpZ2h0IGZvciB0aGUgbWF0ZXJpYWwgaW4gdGhlc2Ugbm90ZXMgcmVzaWRlcyB3aXRoIHRoZSBhdXRob3IgbmFtZWQgYWJvdmUsIHdpdGggdGhlIERlcGFydG1lbnQgb2YgTWF0aGVtYXRpY2FsIGFuZCBQaHlzaWNhbCBTY2llbmNlcyBhbmQgd2l0aCBMYSBUcm9iZSBVbml2ZXJzaXR5LiBDb3B5cmlnaHQgaW4gdGhpcyB3b3JrIGlzIHZlc3RlZCBpbiBMYSBUcm9iZSBVbml2ZXJzaXR5IGluY2x1ZGluZyBhbGwgTGEgVHJvYmUgVW5pdmVyc2l0eSBicmFuZGluZyBhbmQgbmFtaW5nLiBVbmxlc3Mgb3RoZXJ3aXNlIHN0YXRlZCwgbWF0ZXJpYWwgd2l0aGluIHRoaXMgd29yayBpcyBsaWNlbnNlZCB1bmRlciBhIENyZWF0aXZlIENvbW1vbnMgQXR0cmlidXRpb24tTm9uIENvbW1lcmNpYWwtTm9uIERlcml2YXRpdmVzIExpY2Vuc2UgDQo8YSBocmVmID0gImh0dHBzOi8vY3JlYXRpdmVjb21tb25zLm9yZy9saWNlbnNlcy9ieS1uYy1uZC80LjAvQ0MiIHRhcmdldD0iX2JsYW5rIj4gQlktTkMtTkQuIDwvYT4NCjwvZm9udD4=