Data Science Stream

Topic 4B: Data Visualisation III


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

This computer lab was designed to run alongside the content in Section 5 of the Data Visualisation in R supplement. It might be helpful to have this content open while you look through these solutions.

1 Preparation

1.1

library(palmerpenguins)
library(plotly)

1.2

R code is provided in the code chunk below.

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

penguins_scatter <- penguins_scatter %>% 
                        layout(title = "Scatter Plot of Penguin Data", 
                               legend=list(title=list(text='Sex')),
                               xaxis = list(title = "Penguin Body Mass (grams)"),
                               yaxis = list(title = "Penguin Flipper Length (mm)"))

2 Adding Range Sliders to plotly Plots

2.1

penguins_scatter %>% rangeslider()

2.2

No answer required.

2.3

No answer required.

3 Creating animated plotly Plots in RStudio

3.1

Example code and output is shown below:

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

penguins_scatter_anim <- penguins_scatter_anim %>% 
                        layout(title = "Animated Scatter Plot of Penguin Data", 
                               legend=list(title=list(text='Sex')),
                               xaxis = list(title = "Penguin Body Mass (grams)"),
                               yaxis = list(title = "Penguin Flipper Length (mm)"))

penguins_scatter_anim

3.2

No answer required.

3.3

Example code and output is shown below:

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

penguins_scatter_anim2 <- penguins_scatter_anim2 %>% 
                        layout(title = "Animated Scatter Plot of Penguin Data", 
                               legend=list(title=list(text='Sex')),
                               xaxis = list(title = "Penguin Body Mass (grams)"),
                               yaxis = list(title = "Penguin Flipper Length (mm)"))

penguins_scatter_anim2

We notice that the Adelie and Chinstrap penguins have a similar range of body_mass_g values, while the Gentoo penguins are typically much heavier.

4 Creating Combined plotly Plots in RStudio

4.1

R code is provided in the code chunk 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")

4.2

penguin_combined_plots <- subplot(penguins_scatter, 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

4.3

Example code and output is shown below:

penguin_combined_plots %>% layout(legend = list(title = list(
                                    text ="Sex and Island Information")))

4.4

Example code and output is shown below:

penguin_box <- plot_ly(data = penguins, 
                        x = ~species,
                       y = ~body_mass_g,
                        color = ~sex, colors = "Set1",
                        type = "box") %>% layout(boxmode = "group")

penguin_combined_plots2 <- subplot(penguins_scatter, 
                                   penguin_hist, 
                                   penguin_box,
                                  nrows = 3, margin = 0.05) 
penguin_combined_plots2 <- penguin_combined_plots2 %>% 
                            layout(title = "Palmer Penguin Data",
                                   legend = list(title = list(
                                    text ="Sex and Island Information")),
                                   xaxis = list(title = 'body_mass_g'), 
                                   yaxis = list(title = "flipper_length_mm"),
                                   xaxis2 = list(title = 'body_mass_g'), 
                                   yaxis2 = list(title = "count"), 
                                   
                                   xaxis3 = list(title = 'species'), 
                                   yaxis3 = list(title = "body_mass_g"))

penguin_combined_plots2 

Note that the colours have been specified to match those in the scatter plot, for consistency.

5 Extension: Adding Buttons to plotly Plots

5.1

No answer required.

5.2

penguins_plots <- plot_ly(data = penguins, 
                          x = ~body_mass_g, 
                          color = ~sex, 
                          colors = "Set1", 
                          opacity = 0.6) %>% 
  layout(
    title = "Penguin's Body Mass Data",
    updatemenus = list(
      list(x = 1.2, y = 0.7, type = "buttons", 
         
           # We really just have to focus on the code below   
         buttons = list(
           
          list(method = "restyle",
               label = "Histogram", # The button label
               args = list(
                list(type = list("histogram")))) # The plot type
    ))))

penguins_plots

5.3

Example code and output is shown below:

penguins_plots <- plot_ly(data = penguins, 
                          x = ~body_mass_g, 
                          color = ~sex, 
                          colors = "Set1", 
                          opacity = 0.6) %>% 
  layout(
    title = "Penguin's Body Mass Data",
    updatemenus = list(
      list(x = 1.2, y = 0.7, type = "buttons", 
           
         # We really just have to focus on the code below   
         buttons = list(
           
          list(method = "restyle",
               label = "Histogram", # The button label
               args = list(
                list(type = list("histogram")))), # The plot type
          
          list(method = "restyle",
               label = "Box Plots",
               args = list(
                list(type = list("box"))))
    ))))

penguins_plots 

5.4

No answer required.

5.5

Example code and output is shown below:

penguins_plots <- plot_ly(data = penguins, 
                          x = ~body_mass_g, 
                          color = ~sex, 
                          colors = "Set1", 
                          opacity = 0.6) %>% 
  layout(
    title = "Penguin's Body Mass Data",
    updatemenus = list(
      list(x = 1.2, y = 0.7, type = "dropdown", 
           
         # We really just have to focus on the code below   
         buttons = list(
           
          list(method = "restyle",
               label = "Histogram", # The button label
               args = list(
                list(type = list("histogram")))), # The plot type
          
          list(method = "restyle",
               label = "Box Plots",
               args = list(
                list(type = list("box"))))
    ))))

penguins_plots 

5.6

penguins_plots %>% layout(barmode ="overlay")

5.7

Example code and output is shown below:

penguins_plots <- plot_ly(data = penguins, 
                          x = ~body_mass_g, 
                          color = ~sex, 
                          colors = "Set1", 
                          opacity = 0.6) %>% 
  layout(
    title = "Penguin's Body Mass Data",
    updatemenus = list(
      list(x = 1.2, y = 0.7, type = "dropdown", 
           
         # We really just have to focus on the code below   
         buttons = list(
           
          list(method = "restyle",
               label = "Histogram", # The button label
               args = list(
                list(type = list("histogram")))), # The plot type
          
          list(method = "restyle",
               label = "Box Plots",
               args = list(
                list(type = list("box")))),
          
          list(method = "restyle",
               label = "Violin Plots",
               args = list(
                list(type = list("violin"),
                     box = list(visible = T ))))
    ))))

penguins_plots %>% layout(barmode ="overlay")

5.8

Example code and output is shown below:

penguins_plots2 <- plot_ly(data = penguins, 
                           x = ~bill_length_mm, 
                           color = ~species, 
                           colors = "Set1", 
                           opacity = 0.6) %>% 
  layout(
    title = "Penguin's Bill Length Data",
    updatemenus = list(
      list(x = 1.2, y = 0.7, type = "dropdown", 
           
         # We really just have to focus on the code below   
         buttons = list(
           
          list(method = "restyle",
               label = "Violin Plots",
               args = list(
                list(type = list("violin"),
                     box = list(visible = T )))),
          
          list(method = "restyle",
               label = "Box Plots",
               args = list(
                list(type = list("box")))),
          
          list(method = "restyle",
               label = "Histogram", 
               args = list(
                list(type = list("histogram"))))
    ))))

penguins_plots2 %>% layout(barmode ="overlay") %>% rangeslider()

5.9

No answer required.


That’s everything covered, well done!


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.

LS0tDQp0aXRsZTogIlNUTTEwMDE6IENvbXB1dGVyIExhYiA0QiBTb2x1dGlvbnMiDQpvdXRwdXQ6DQogIGJvb2tkb3duOjpodG1sX2RvY3VtZW50MjogDQogICAgdG9jOiB0cnVlDQogICAgdG9jX2Zsb2F0OiB0cnVlDQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KICAgIHRoZW1lOiByZWFkYWJsZQ0KICAgIGNvZGVfZm9sZGluZzogc2hvdw0KYmlibGlvZ3JhcGh5OiBTVE0xMDAxX0RTX0NMX3JlZmVyZW5jZXMuYmliIA0KbGluay1jaXRhdGlvbnM6IHllcw0KLS0tDQoNCjxzdHlsZT4NCiNUT0Mgew0KICBiYWNrZ3JvdW5kOiB1cmwoImh0dHBzOi8vd3d3LmxhdHJvYmUuZWR1LmF1L19tZWRpYS9sYS10cm9iZS1hcGkvdjUvaW1nL2xvZ28uc3ZnIik7DQogIGJhY2tncm91bmQtc2l6ZTogY29udGFpbjsNCiAgcGFkZGluZy10b3A6IDgwcHggIWltcG9ydGFudDsNCiAgYmFja2dyb3VuZC1yZXBlYXQ6IG5vLXJlcGVhdDsNCn0NCjwvc3R5bGU+DQoNCiMjIyBEYXRhIFNjaWVuY2UgU3RyZWFtIHstfQ0KDQojIyMgVG9waWMgNEI6IERhdGEgVmlzdWFsaXNhdGlvbiBJSUkgey19DQoNCjxicj4NCg0KRXhhbXBsZSBSIGNvZGUgc29sdXRpb25zIGZvciB0aGUgW0RhdGEgU2NpZW5jZSBDb21wdXRlciBMYWIgNF0oaHR0cHM6Ly9ycHVicy5jb20vTFRVX1NUTTEwMDEvRFNNQ0w0KSwgd2hpY2ggdXNlcyBkYXRhIGZyb20gdGhlIGBwYWxtZXJwZW5ndWluc2AgcGFja2FnZSBbQHBlbmd1aW5zXSwgYW5kIHRoZSBgcGxvdGx5YCBbQHBsb3RseV0sIGFyZSBwcmVzZW50ZWQgYmVsb3cuDQoNClRoaXMgY29tcHV0ZXIgbGFiIHdhcyBkZXNpZ25lZCB0byBydW4gYWxvbmdzaWRlIHRoZSBjb250ZW50IGluIFtTZWN0aW9uIDUgb2YgdGhlIERhdGEgVmlzdWFsaXNhdGlvbiBpbiBSIHN1cHBsZW1lbnRdKGh0dHBzOi8vYm9va2Rvd24ub3JnL3JlaGsvc3RtMTAwMV9kc21fZGF0YV92aXN1YWxpc2F0aW9uX2luX3IvYWR2YW5jZWQtcGxvdGx5LWNvbXB1dGVyLWxhYi00Yi5odG1sKS4gSXQgbWlnaHQgYmUgaGVscGZ1bCB0byBoYXZlIHRoaXMgY29udGVudCBvcGVuIHdoaWxlIHlvdSBsb29rIHRocm91Z2ggdGhlc2Ugc29sdXRpb25zLg0KDQojIFByZXBhcmF0aW9uDQoNCiMjDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gRiwgZWNobyA9IFR9DQpsaWJyYXJ5KHBhbG1lcnBlbmd1aW5zKQ0KbGlicmFyeShwbG90bHkpDQpgYGANCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBpbmNsdWRlID0gRn0NCmxpYnJhcnkocGFsbWVycGVuZ3VpbnMpDQpsaWJyYXJ5KHBsb3RseSkNCmBgYA0KDQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gVCwgaW5jbHVkZSA9IEZ9DQpwZW5ndWlucyA8LSBuYS5vbWl0KHBlbmd1aW5zKQ0KYGBgDQoNCiMjDQoNClIgY29kZSBpcyBwcm92aWRlZCBpbiB0aGUgY29kZSBjaHVuayBiZWxvdy4NCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtaGlkZSIsIGV2YWwgPSBULCBlY2hvID0gVH0NCnBlbmd1aW5zX3NjYXR0ZXIgPC0gcGxvdF9seShkYXRhID0gcGVuZ3VpbnMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHggPSB+Ym9keV9tYXNzX2csIHkgPSB+ZmxpcHBlcl9sZW5ndGhfbW0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gfnNleCwgY29sb3JzID0gIlNldDEiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGUgPSAic2NhdHRlciIsIG1vZGUgPSAibWFya2VycyIpDQoNCnBlbmd1aW5zX3NjYXR0ZXIgPC0gcGVuZ3VpbnNfc2NhdHRlciAlPiUgDQogICAgICAgICAgICAgICAgICAgICAgICBsYXlvdXQodGl0bGUgPSAiU2NhdHRlciBQbG90IG9mIFBlbmd1aW4gRGF0YSIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZD1saXN0KHRpdGxlPWxpc3QodGV4dD0nU2V4JykpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHhheGlzID0gbGlzdCh0aXRsZSA9ICJQZW5ndWluIEJvZHkgTWFzcyAoZ3JhbXMpIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gIlBlbmd1aW4gRmxpcHBlciBMZW5ndGggKG1tKSIpKQ0KYGBgDQoNCiMgQWRkaW5nIFJhbmdlIFNsaWRlcnMgdG8gYHBsb3RseWAgUGxvdHMgeyNzbGlkZXJ9IA0KDQojIyB7I3NsaWRlcnN0YXJ0fQ0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IFQsIGVjaG8gPSBUfQ0KcGVuZ3VpbnNfc2NhdHRlciAlPiUgcmFuZ2VzbGlkZXIoKQ0KYGBgDQoNCiMjDQoNCk5vIGFuc3dlciByZXF1aXJlZC4NCg0KIyMNCg0KTm8gYW5zd2VyIHJlcXVpcmVkLg0KDQojIENyZWF0aW5nIGFuaW1hdGVkIGBwbG90bHlgIFBsb3RzIGluIFJTdHVkaW8geyNhbmltYXRpb25zfQ0KDQojIw0KDQpFeGFtcGxlIGNvZGUgYW5kIG91dHB1dCBpcyBzaG93biBiZWxvdzoNCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gVH0NCnBlbmd1aW5zX3NjYXR0ZXJfYW5pbSA8LSBwbG90X2x5KGRhdGEgPSBwZW5ndWlucywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgeCA9IH5ib2R5X21hc3NfZywgeSA9IH5mbGlwcGVyX2xlbmd0aF9tbSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgZnJhbWUgPSB+eWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9IH5zZXgsIGNvbG9ycyA9ICJTZXQxIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gInNjYXR0ZXIiLCBtb2RlID0gIm1hcmtlcnMiKQ0KDQpwZW5ndWluc19zY2F0dGVyX2FuaW0gPC0gcGVuZ3VpbnNfc2NhdHRlcl9hbmltICU+JSANCiAgICAgICAgICAgICAgICAgICAgICAgIGxheW91dCh0aXRsZSA9ICJBbmltYXRlZCBTY2F0dGVyIFBsb3Qgb2YgUGVuZ3VpbiBEYXRhIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVnZW5kPWxpc3QodGl0bGU9bGlzdCh0ZXh0PSdTZXgnKSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeGF4aXMgPSBsaXN0KHRpdGxlID0gIlBlbmd1aW4gQm9keSBNYXNzIChncmFtcykiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAiUGVuZ3VpbiBGbGlwcGVyIExlbmd0aCAobW0pIikpDQoNCnBlbmd1aW5zX3NjYXR0ZXJfYW5pbQ0KYGBgDQoNCiMjDQoNCk5vIGFuc3dlciByZXF1aXJlZC4NCg0KIyMNCg0KRXhhbXBsZSBjb2RlIGFuZCBvdXRwdXQgaXMgc2hvd24gYmVsb3c6DQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gVCwgZWNobyA9IFR9DQpwZW5ndWluc19zY2F0dGVyX2FuaW0yIDwtIHBsb3RfbHkoZGF0YSA9IHBlbmd1aW5zLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB4ID0gfmJvZHlfbWFzc19nLCB5ID0gfmZsaXBwZXJfbGVuZ3RoX21tLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmcmFtZSA9IH5zcGVjaWVzLCB0ZXh0ID0gfnllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSB+c2V4LCBjb2xvcnMgPSAiU2V0MSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZSA9ICJzY2F0dGVyIiwgbW9kZSA9ICJtYXJrZXJzIikNCg0KcGVuZ3VpbnNfc2NhdHRlcl9hbmltMiA8LSBwZW5ndWluc19zY2F0dGVyX2FuaW0yICU+JSANCiAgICAgICAgICAgICAgICAgICAgICAgIGxheW91dCh0aXRsZSA9ICJBbmltYXRlZCBTY2F0dGVyIFBsb3Qgb2YgUGVuZ3VpbiBEYXRhIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVnZW5kPWxpc3QodGl0bGU9bGlzdCh0ZXh0PSdTZXgnKSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeGF4aXMgPSBsaXN0KHRpdGxlID0gIlBlbmd1aW4gQm9keSBNYXNzIChncmFtcykiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAiUGVuZ3VpbiBGbGlwcGVyIExlbmd0aCAobW0pIikpDQoNCnBlbmd1aW5zX3NjYXR0ZXJfYW5pbTINCmBgYA0KDQpXZSBub3RpY2UgdGhhdCB0aGUgQWRlbGllIGFuZCBDaGluc3RyYXAgcGVuZ3VpbnMgaGF2ZSBhIHNpbWlsYXIgcmFuZ2Ugb2YgYGJvZHlfbWFzc19nYCB2YWx1ZXMsIHdoaWxlIHRoZSBHZW50b28gcGVuZ3VpbnMgYXJlIHR5cGljYWxseSBtdWNoIGhlYXZpZXIuDQoNCiMgQ3JlYXRpbmcgQ29tYmluZWQgYHBsb3RseWAgUGxvdHMgaW4gUlN0dWRpbyB7I3N1YnBsb3RzfQ0KDQojIyB7I3N1YnBsb3R3YWxrdGhyb3VnaH0NCg0KUiBjb2RlIGlzIHByb3ZpZGVkIGluIHRoZSBjb2RlIGNodW5rIGJlbG93Lg0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1oaWRlIiwgZXZhbCA9IFQsIGVjaG8gPSBULCB3YXJuaW5nID0gRiwgbWVzc2FnZSA9IEYsIGZpZy5hbGlnbiA9ICJjZW50ZXIifQ0KcGVuZ3Vpbl9oaXN0IDwtIHBsb3RfbHkoZGF0YSA9IHBlbmd1aW5zLCANCiAgICAgICAgICAgICAgICAgICAgICAgIHggPSB+Ym9keV9tYXNzX2csIA0KICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSB+aXNsYW5kLCANCiAgICAgICAgICAgICAgICAgICAgICAgIHR5cGUgPSAiaGlzdG9ncmFtIiwgYWxwaGEgPSAwLjYpDQoNCnBlbmd1aW5faGlzdCA8LSBwZW5ndWluX2hpc3QgJT4lIGxheW91dCh5YXhpcyA9IGxpc3QodGl0bGUgPSAnY291bnQnKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFybW9kZSA9Im92ZXJsYXkiKQ0KYGBgDQoNCiMjIHsjY29tYmluZWR9DQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gVCwgZWNobyA9IFQsIHdhcm5pbmcgPSBGLCBtZXNzYWdlID0gRiwgZmlnLmFsaWduID0gImNlbnRlciIsIGZpZy5kaW0gPSBjKDgsIDgpfQ0KcGVuZ3Vpbl9jb21iaW5lZF9wbG90cyA8LSBzdWJwbG90KHBlbmd1aW5zX3NjYXR0ZXIsIHBlbmd1aW5faGlzdCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbnJvd3MgPSAyLCBtYXJnaW4gPSAwLjA1KSANCnBlbmd1aW5fY29tYmluZWRfcGxvdHMgPC0gcGVuZ3Vpbl9jb21iaW5lZF9wbG90cyAlPiUgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgbGF5b3V0KHRpdGxlID0gIlBhbG1lciBQZW5ndWluIERhdGEiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4YXhpcyA9IGxpc3QodGl0bGUgPSAnYm9keV9tYXNzX2cnKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICJmbGlwcGVyX2xlbmd0aF9tbSIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4YXhpczIgPSBsaXN0KHRpdGxlID0gJ2JvZHlfbWFzc19nJyksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5YXhpczIgPSBsaXN0KHRpdGxlID0gImNvdW50IikpDQpwZW5ndWluX2NvbWJpbmVkX3Bsb3RzDQpgYGANCg0KIyMNCg0KRXhhbXBsZSBjb2RlIGFuZCBvdXRwdXQgaXMgc2hvd24gYmVsb3c6DQoNCmBgYHtyIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gVCwgZWNobyA9IFQsIHdhcm5pbmcgPSBGLCBtZXNzYWdlID0gRiwgZmlnLmFsaWduID0gImNlbnRlciIsIGZpZy5kaW0gPSBjKDgsIDgpfQ0KcGVuZ3Vpbl9jb21iaW5lZF9wbG90cyAlPiUgbGF5b3V0KGxlZ2VuZCA9IGxpc3QodGl0bGUgPSBsaXN0KA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGV4dCA9IlNleCBhbmQgSXNsYW5kIEluZm9ybWF0aW9uIikpKQ0KYGBgDQoNCiMjIHsjYm94cGxvdHN1YnBsb3R9DQoNCkV4YW1wbGUgY29kZSBhbmQgb3V0cHV0IGlzIHNob3duIGJlbG93Og0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IFQsIGVjaG8gPSBULCB3YXJuaW5nID0gRiwgbWVzc2FnZSA9IEYsIGZpZy5hbGlnbiA9ICJjZW50ZXIiLCBmaWcuZGltID0gYyg4LCAxMil9DQoNCnBlbmd1aW5fYm94IDwtIHBsb3RfbHkoZGF0YSA9IHBlbmd1aW5zLCANCiAgICAgICAgICAgICAgICAgICAgICAgIHggPSB+c3BlY2llcywNCiAgICAgICAgICAgICAgICAgICAgICAgeSA9IH5ib2R5X21hc3NfZywNCiAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gfnNleCwgY29sb3JzID0gIlNldDEiLA0KICAgICAgICAgICAgICAgICAgICAgICAgdHlwZSA9ICJib3giKSAlPiUgbGF5b3V0KGJveG1vZGUgPSAiZ3JvdXAiKQ0KDQpwZW5ndWluX2NvbWJpbmVkX3Bsb3RzMiA8LSBzdWJwbG90KHBlbmd1aW5zX3NjYXR0ZXIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwZW5ndWluX2hpc3QsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwZW5ndWluX2JveCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBucm93cyA9IDMsIG1hcmdpbiA9IDAuMDUpIA0KcGVuZ3Vpbl9jb21iaW5lZF9wbG90czIgPC0gcGVuZ3Vpbl9jb21iaW5lZF9wbG90czIgJT4lIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxheW91dCh0aXRsZSA9ICJQYWxtZXIgUGVuZ3VpbiBEYXRhIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGVnZW5kID0gbGlzdCh0aXRsZSA9IGxpc3QoDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0ZXh0ID0iU2V4IGFuZCBJc2xhbmQgSW5mb3JtYXRpb24iKSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHhheGlzID0gbGlzdCh0aXRsZSA9ICdib2R5X21hc3NfZycpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gImZsaXBwZXJfbGVuZ3RoX21tIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHhheGlzMiA9IGxpc3QodGl0bGUgPSAnYm9keV9tYXNzX2cnKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHlheGlzMiA9IGxpc3QodGl0bGUgPSAiY291bnQiKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4YXhpczMgPSBsaXN0KHRpdGxlID0gJ3NwZWNpZXMnKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHlheGlzMyA9IGxpc3QodGl0bGUgPSAiYm9keV9tYXNzX2ciKSkNCg0KcGVuZ3Vpbl9jb21iaW5lZF9wbG90czIgDQpgYGANCg0KTm90ZSB0aGF0IHRoZSBjb2xvdXJzIGhhdmUgYmVlbiBzcGVjaWZpZWQgdG8gbWF0Y2ggdGhvc2UgaW4gdGhlIHNjYXR0ZXIgcGxvdCwgZm9yIGNvbnNpc3RlbmN5Lg0KDQojIEV4dGVuc2lvbjogQWRkaW5nIEJ1dHRvbnMgdG8gYHBsb3RseWAgUGxvdHMgeyNidXR0b259DQoNCiMjDQoNCk5vIGFuc3dlciByZXF1aXJlZC4NCg0KIyMgeyNidXR0b25zcGxvdH0NCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gVCwgd2FybmluZyA9IEYsIG1lc3NhZ2UgPSBGfQ0KcGVuZ3VpbnNfcGxvdHMgPC0gcGxvdF9seShkYXRhID0gcGVuZ3VpbnMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICB4ID0gfmJvZHlfbWFzc19nLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSB+c2V4LCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3JzID0gIlNldDEiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgb3BhY2l0eSA9IDAuNikgJT4lIA0KICBsYXlvdXQoDQogICAgdGl0bGUgPSAiUGVuZ3VpbidzIEJvZHkgTWFzcyBEYXRhIiwNCiAgICB1cGRhdGVtZW51cyA9IGxpc3QoDQogICAgICBsaXN0KHggPSAxLjIsIHkgPSAwLjcsIHR5cGUgPSAiYnV0dG9ucyIsIA0KICAgICAgICAgDQogICAgICAgICAgICMgV2UgcmVhbGx5IGp1c3QgaGF2ZSB0byBmb2N1cyBvbiB0aGUgY29kZSBiZWxvdyAgIA0KICAgICAgICAgYnV0dG9ucyA9IGxpc3QoDQogICAgICAgICAgIA0KICAgICAgICAgIGxpc3QobWV0aG9kID0gInJlc3R5bGUiLA0KICAgICAgICAgICAgICAgbGFiZWwgPSAiSGlzdG9ncmFtIiwgIyBUaGUgYnV0dG9uIGxhYmVsDQogICAgICAgICAgICAgICBhcmdzID0gbGlzdCgNCiAgICAgICAgICAgICAgICBsaXN0KHR5cGUgPSBsaXN0KCJoaXN0b2dyYW0iKSkpKSAjIFRoZSBwbG90IHR5cGUNCiAgICApKSkpDQoNCnBlbmd1aW5zX3Bsb3RzDQpgYGANCiANCiMjIHsjYWRkYnV0dG9ufQ0KDQpFeGFtcGxlIGNvZGUgYW5kIG91dHB1dCBpcyBzaG93biBiZWxvdzoNCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gVCwgd2FybmluZyA9IEYsIG1lc3NhZ2UgPSBGfQ0KcGVuZ3VpbnNfcGxvdHMgPC0gcGxvdF9seShkYXRhID0gcGVuZ3VpbnMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICB4ID0gfmJvZHlfbWFzc19nLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSB+c2V4LCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3JzID0gIlNldDEiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgb3BhY2l0eSA9IDAuNikgJT4lIA0KICBsYXlvdXQoDQogICAgdGl0bGUgPSAiUGVuZ3VpbidzIEJvZHkgTWFzcyBEYXRhIiwNCiAgICB1cGRhdGVtZW51cyA9IGxpc3QoDQogICAgICBsaXN0KHggPSAxLjIsIHkgPSAwLjcsIHR5cGUgPSAiYnV0dG9ucyIsIA0KICAgICAgICAgICANCiAgICAgICAgICMgV2UgcmVhbGx5IGp1c3QgaGF2ZSB0byBmb2N1cyBvbiB0aGUgY29kZSBiZWxvdyAgIA0KICAgICAgICAgYnV0dG9ucyA9IGxpc3QoDQogICAgICAgICAgIA0KICAgICAgICAgIGxpc3QobWV0aG9kID0gInJlc3R5bGUiLA0KICAgICAgICAgICAgICAgbGFiZWwgPSAiSGlzdG9ncmFtIiwgIyBUaGUgYnV0dG9uIGxhYmVsDQogICAgICAgICAgICAgICBhcmdzID0gbGlzdCgNCiAgICAgICAgICAgICAgICBsaXN0KHR5cGUgPSBsaXN0KCJoaXN0b2dyYW0iKSkpKSwgIyBUaGUgcGxvdCB0eXBlDQogICAgICAgICAgDQogICAgICAgICAgbGlzdChtZXRob2QgPSAicmVzdHlsZSIsDQogICAgICAgICAgICAgICBsYWJlbCA9ICJCb3ggUGxvdHMiLA0KICAgICAgICAgICAgICAgYXJncyA9IGxpc3QoDQogICAgICAgICAgICAgICAgbGlzdCh0eXBlID0gbGlzdCgiYm94IikpKSkNCiAgICApKSkpDQoNCnBlbmd1aW5zX3Bsb3RzIA0KYGBgDQoNCiMjIHsjdHdvYnV0dG9uc30NCg0KTm8gYW5zd2VyIHJlcXVpcmVkLg0KDQojIw0KDQpFeGFtcGxlIGNvZGUgYW5kIG91dHB1dCBpcyBzaG93biBiZWxvdzoNCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gVCwgd2FybmluZyA9IEYsIG1lc3NhZ2UgPSBGfQ0KcGVuZ3VpbnNfcGxvdHMgPC0gcGxvdF9seShkYXRhID0gcGVuZ3VpbnMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICB4ID0gfmJvZHlfbWFzc19nLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSB+c2V4LCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3JzID0gIlNldDEiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgb3BhY2l0eSA9IDAuNikgJT4lIA0KICBsYXlvdXQoDQogICAgdGl0bGUgPSAiUGVuZ3VpbidzIEJvZHkgTWFzcyBEYXRhIiwNCiAgICB1cGRhdGVtZW51cyA9IGxpc3QoDQogICAgICBsaXN0KHggPSAxLjIsIHkgPSAwLjcsIHR5cGUgPSAiZHJvcGRvd24iLCANCiAgICAgICAgICAgDQogICAgICAgICAjIFdlIHJlYWxseSBqdXN0IGhhdmUgdG8gZm9jdXMgb24gdGhlIGNvZGUgYmVsb3cgICANCiAgICAgICAgIGJ1dHRvbnMgPSBsaXN0KA0KICAgICAgICAgICANCiAgICAgICAgICBsaXN0KG1ldGhvZCA9ICJyZXN0eWxlIiwNCiAgICAgICAgICAgICAgIGxhYmVsID0gIkhpc3RvZ3JhbSIsICMgVGhlIGJ1dHRvbiBsYWJlbA0KICAgICAgICAgICAgICAgYXJncyA9IGxpc3QoDQogICAgICAgICAgICAgICAgbGlzdCh0eXBlID0gbGlzdCgiaGlzdG9ncmFtIikpKSksICMgVGhlIHBsb3QgdHlwZQ0KICAgICAgICAgIA0KICAgICAgICAgIGxpc3QobWV0aG9kID0gInJlc3R5bGUiLA0KICAgICAgICAgICAgICAgbGFiZWwgPSAiQm94IFBsb3RzIiwNCiAgICAgICAgICAgICAgIGFyZ3MgPSBsaXN0KA0KICAgICAgICAgICAgICAgIGxpc3QodHlwZSA9IGxpc3QoImJveCIpKSkpDQogICAgKSkpKQ0KDQpwZW5ndWluc19wbG90cyANCmBgYA0KDQojIw0KDQpgYGB7ciBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IFQsIGVjaG8gPSBULCB3YXJuaW5nID0gRiwgbWVzc2FnZSA9IEZ9DQpwZW5ndWluc19wbG90cyAlPiUgbGF5b3V0KGJhcm1vZGUgPSJvdmVybGF5IikNCmBgYA0KDQojIw0KDQpFeGFtcGxlIGNvZGUgYW5kIG91dHB1dCBpcyBzaG93biBiZWxvdzoNCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gVCwgd2FybmluZyA9IEYsIG1lc3NhZ2UgPSBGfQ0KcGVuZ3VpbnNfcGxvdHMgPC0gcGxvdF9seShkYXRhID0gcGVuZ3VpbnMsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICB4ID0gfmJvZHlfbWFzc19nLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSB+c2V4LCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3JzID0gIlNldDEiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgb3BhY2l0eSA9IDAuNikgJT4lIA0KICBsYXlvdXQoDQogICAgdGl0bGUgPSAiUGVuZ3VpbidzIEJvZHkgTWFzcyBEYXRhIiwNCiAgICB1cGRhdGVtZW51cyA9IGxpc3QoDQogICAgICBsaXN0KHggPSAxLjIsIHkgPSAwLjcsIHR5cGUgPSAiZHJvcGRvd24iLCANCiAgICAgICAgICAgDQogICAgICAgICAjIFdlIHJlYWxseSBqdXN0IGhhdmUgdG8gZm9jdXMgb24gdGhlIGNvZGUgYmVsb3cgICANCiAgICAgICAgIGJ1dHRvbnMgPSBsaXN0KA0KICAgICAgICAgICANCiAgICAgICAgICBsaXN0KG1ldGhvZCA9ICJyZXN0eWxlIiwNCiAgICAgICAgICAgICAgIGxhYmVsID0gIkhpc3RvZ3JhbSIsICMgVGhlIGJ1dHRvbiBsYWJlbA0KICAgICAgICAgICAgICAgYXJncyA9IGxpc3QoDQogICAgICAgICAgICAgICAgbGlzdCh0eXBlID0gbGlzdCgiaGlzdG9ncmFtIikpKSksICMgVGhlIHBsb3QgdHlwZQ0KICAgICAgICAgIA0KICAgICAgICAgIGxpc3QobWV0aG9kID0gInJlc3R5bGUiLA0KICAgICAgICAgICAgICAgbGFiZWwgPSAiQm94IFBsb3RzIiwNCiAgICAgICAgICAgICAgIGFyZ3MgPSBsaXN0KA0KICAgICAgICAgICAgICAgIGxpc3QodHlwZSA9IGxpc3QoImJveCIpKSkpLA0KICAgICAgICAgIA0KICAgICAgICAgIGxpc3QobWV0aG9kID0gInJlc3R5bGUiLA0KICAgICAgICAgICAgICAgbGFiZWwgPSAiVmlvbGluIFBsb3RzIiwNCiAgICAgICAgICAgICAgIGFyZ3MgPSBsaXN0KA0KICAgICAgICAgICAgICAgIGxpc3QodHlwZSA9IGxpc3QoInZpb2xpbiIpLA0KICAgICAgICAgICAgICAgICAgICAgYm94ID0gbGlzdCh2aXNpYmxlID0gVCApKSkpDQogICAgKSkpKQ0KDQpwZW5ndWluc19wbG90cyAlPiUgbGF5b3V0KGJhcm1vZGUgPSJvdmVybGF5IikNCmBgYA0KDQojIw0KDQpFeGFtcGxlIGNvZGUgYW5kIG91dHB1dCBpcyBzaG93biBiZWxvdzoNCg0KYGBge3IgY2xhc3Muc291cmNlID0gImZvbGQtc2hvdyIsIGV2YWwgPSBULCBlY2hvID0gVCwgd2FybmluZyA9IEYsIG1lc3NhZ2UgPSBGfQ0KcGVuZ3VpbnNfcGxvdHMyIDwtIHBsb3RfbHkoZGF0YSA9IHBlbmd1aW5zLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHggPSB+YmlsbF9sZW5ndGhfbW0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSB+c3BlY2llcywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvcnMgPSAiU2V0MSIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgb3BhY2l0eSA9IDAuNikgJT4lIA0KICBsYXlvdXQoDQogICAgdGl0bGUgPSAiUGVuZ3VpbidzIEJpbGwgTGVuZ3RoIERhdGEiLA0KICAgIHVwZGF0ZW1lbnVzID0gbGlzdCgNCiAgICAgIGxpc3QoeCA9IDEuMiwgeSA9IDAuNywgdHlwZSA9ICJkcm9wZG93biIsIA0KICAgICAgICAgICANCiAgICAgICAgICMgV2UgcmVhbGx5IGp1c3QgaGF2ZSB0byBmb2N1cyBvbiB0aGUgY29kZSBiZWxvdyAgIA0KICAgICAgICAgYnV0dG9ucyA9IGxpc3QoDQogICAgICAgICAgIA0KICAgICAgICAgIGxpc3QobWV0aG9kID0gInJlc3R5bGUiLA0KICAgICAgICAgICAgICAgbGFiZWwgPSAiVmlvbGluIFBsb3RzIiwNCiAgICAgICAgICAgICAgIGFyZ3MgPSBsaXN0KA0KICAgICAgICAgICAgICAgIGxpc3QodHlwZSA9IGxpc3QoInZpb2xpbiIpLA0KICAgICAgICAgICAgICAgICAgICAgYm94ID0gbGlzdCh2aXNpYmxlID0gVCApKSkpLA0KICAgICAgICAgIA0KICAgICAgICAgIGxpc3QobWV0aG9kID0gInJlc3R5bGUiLA0KICAgICAgICAgICAgICAgbGFiZWwgPSAiQm94IFBsb3RzIiwNCiAgICAgICAgICAgICAgIGFyZ3MgPSBsaXN0KA0KICAgICAgICAgICAgICAgIGxpc3QodHlwZSA9IGxpc3QoImJveCIpKSkpLA0KICAgICAgICAgIA0KICAgICAgICAgIGxpc3QobWV0aG9kID0gInJlc3R5bGUiLA0KICAgICAgICAgICAgICAgbGFiZWwgPSAiSGlzdG9ncmFtIiwgDQogICAgICAgICAgICAgICBhcmdzID0gbGlzdCgNCiAgICAgICAgICAgICAgICBsaXN0KHR5cGUgPSBsaXN0KCJoaXN0b2dyYW0iKSkpKQ0KICAgICkpKSkNCg0KcGVuZ3VpbnNfcGxvdHMyICU+JSBsYXlvdXQoYmFybW9kZSA9Im92ZXJsYXkiKSAlPiUgcmFuZ2VzbGlkZXIoKQ0KYGBgDQoNCiMjDQoNCk5vIGFuc3dlciByZXF1aXJlZC4NCg0KPGJyPg0KDQoNCiMjIyMgVGhhdCdzIGV2ZXJ5dGhpbmcgY292ZXJlZCwgd2VsbCBkb25lISAjIyMjIHstfQ0KDQo8YnI+DQoNCiMgUmVmZXJlbmNlcyB7LSAjUmVmfQ0KPGRpdiBpZD0icmVmcyI+PC9kaXY+DQoNCjxicj4NCg0KPGZvbnQgY29sb3IgPSAiZ3JleSI+DQpUaGVzZSBub3RlcyBoYXZlIGJlZW4gcHJlcGFyZWQgYnkgUnVwZXJ0IEt1dmVrZS4gVGhlIGNvcHlyaWdodCBmb3IgdGhlIG1hdGVyaWFsIGluIHRoZXNlIG5vdGVzIHJlc2lkZXMgd2l0aCB0aGUgYXV0aG9yIG5hbWVkIGFib3ZlLCB3aXRoIHRoZSBEZXBhcnRtZW50IG9mIE1hdGhlbWF0aWNhbCBhbmQgUGh5c2ljYWwgU2NpZW5jZXMgYW5kIHdpdGggTGEgVHJvYmUgVW5pdmVyc2l0eS4gQ29weXJpZ2h0IGluIHRoaXMgd29yayBpcyB2ZXN0ZWQgaW4gTGEgVHJvYmUgVW5pdmVyc2l0eSBpbmNsdWRpbmcgYWxsIExhIFRyb2JlIFVuaXZlcnNpdHkgYnJhbmRpbmcgYW5kIG5hbWluZy4gVW5sZXNzIG90aGVyd2lzZSBzdGF0ZWQsIG1hdGVyaWFsIHdpdGhpbiB0aGlzIHdvcmsgaXMgbGljZW5zZWQgdW5kZXIgYSBDcmVhdGl2ZSBDb21tb25zIEF0dHJpYnV0aW9uLU5vbiBDb21tZXJjaWFsLU5vbiBEZXJpdmF0aXZlcyBMaWNlbnNlIA0KPGEgaHJlZiA9ICJodHRwczovL2NyZWF0aXZlY29tbW9ucy5vcmcvbGljZW5zZXMvYnktbmMtbmQvNC4wL0NDIiB0YXJnZXQ9Il9ibGFuayI+IEJZLU5DLU5ELiA8L2E+DQo8L2ZvbnQ+