Today, we’re going to make our first interactive plots! We’re going to cover two of the basics for interactivity in R/RMarkdown:

  1. Plotly
  2. flexdashboard

Plotly provides a super easy-to-use wrapper for ggplots that interface with JavaScript libraries to add basic interactive elements to your existing plots.

flexdashboard is a special version of an rmarkdown file that knits to a dashboard view. By itself, this isn’t exactly “interactive”, but you can easily add plotly graphs or additional interactive elements. Dashboards are becoming more and more popular to show results visually, but still with enough context to explain them.

For today’s lab, we’re going to return to some data we’re familiar with: covid. We’ll begin using the state_avg dataset that we constructed in Lab05, and then you will use the full covid dataset for Part 3.

covid = read_csv("data/covid_data.csv")

covid %>%
  group_by(geo_value, signal) %>%
  summarize(
    avg = mean(value, na.rm = T)
  ) %>%
  pivot_wider(id_cols = geo_value, names_from = signal, values_from = avg) %>%
  ungroup() -> state_avg

Part 1: Plotly

Plotly is special software for creating interactive plots with JavaScript, but you don’t need to know any JavaScript to use it! the ggplotly command translates between ggplot2 and JavaScript for you.

First, install the plotly package. Take a look at what simply wrapping an existing ggplot in ggplotly can do:

p1 = state_avg %>%
    mutate(state = str_to_upper(geo_value)) %>%
    ggplot(aes(x = smoothed_wearing_mask, y = smoothed_cli)) +
    geom_point() + 
    theme_minimal()

ggplotly(p1)

(Move your cursor around over the graph and hover over points – you may have to click on the browser window to activate the plot). Try clicking on the menu options in the upper right of the graph to toggle features on/off.

While this is fun, it’s not especially useful, since we can read the values for each point directly from the x and y axes. What would be useful is to be able to hover over a point and see which state it corresponds to. Lucky for us, plotly can do just that!

By adding a text aesthetic to geom_point, we can tell plotly where to find the state information for each point. Then, we can change what values plotly shows us when we hover a point by changing the tooltip argument to “text”.

p2 = state_avg %>%
    mutate(state = str_to_upper(geo_value)) %>%
    ggplot(aes(x = smoothed_wearing_mask, y = smoothed_cli)) +
    geom_point(aes(text = toupper(geo_value))) + 
    theme_minimal()

ggplotly(p2, tooltip = "text")

(See the plotly documentation for more info on custom tooltips)

Part 2: Plotly on your own

Turn any graph we’ve made so far (in any of the labs, projects, or class) into an interactive plotly graph. You should try to choose a graph where the interactivity adds something to the graph. It may be helpful to look through the plotly documentation if you’re trying to do something specific.

(There is a Part 3 of this lab that will likely be more time consuming, so don’t spend too much time finding the perfect graph for Part 2.)

Submitting your work

Note that in order for the interactivity to work, you will have to knit to html instead of pdf. Knitted html files are standalone files that can be viewed and shared – just like word and PDF documents.

RPubs is a free service that publishes your knitted rmarkdown files to the web and is super easy to use.

Before publishing your file:

  • use echo = FALSE at the beginning of your R chunks to hide specific blocks of code. I’d recommend doing this for any code that contains specific paths on your computer (like read_csv('aluby/Private/Super-Private-Folder-Name/lab09.html'))
  • If you don’t want to include your name on your knitted HTML file, you don’t have to!
  • If you don’t want to publish anything online, you don’t have to, and can submit your files on moodle as usual
    • Moodle often struggles with HTML files because they’re so large. I’ll up the file upload limit for this lab, but if you run into uploading issues, submit your .rmd and email me your HTML.

When you’re ready, knit to HTML. When the knitted file pops up, click “Publish Document” in the upper right corner, then choose “RPubs”.

After publishing your file,

  • Take note of the URL that is generated
  • Submit the URL to your file in the text submission area of moodle. You’ll submit two URLs for this assignment, one that contains your plotly graph and the other that contains your flexdashboard.

Part 3: flexdashboard

First, install the flexdashboard package.

I’ve made a template for you using penguins data. Try knitting it, see how everything shows up, and play around with changing a few things. Then, change the dashboard to use the covid data. You can choose any signal, state, or time period for your dashboard (or a combination!).

To customize the theme, add a theme argument to the top of your rmarkdown file like so:

---
title: "Palmer Penguins"
output: 
  flexdashboard::flex_dashboard:
    orientation: columns
    vertical_layout: fill
    theme: bootstrap
---

Possible themes are:

  • cosmo
  • bootstrap
  • cerulean
  • journal
  • flatly
  • readable
  • spacelab
  • united
  • lumen
  • paper
  • sandstone
  • simplex
  • yeti

If you’re feeling saucy, you could even include plotly graphs in your dashboard.

We are barely skimming the surface of what’s possible with flexdashboard today. If you want to build a dashboard for Project 3 or your final project, I highly recommend checking out the flexdashboard documentation to see some more of the advanced features.

Submitting your work

Same rules as for Part 2. When you’re ready, knit to HTML. When the knitted file pops up, click “Publish Document” in the upper right corner, then choose “RPubs”.

After publishing your file,

  • Take note of the URL that is generated
  • Submit the URL to your file in the text submission area of moodle. You’ll submit two URLs for this assignment, one that contains your plotly graph and the other that contains your flexdashboard.
LS0tCnRpdGxlOiAiTGFiMDk6IEludGVyYWN0aXZpdHkgSSIKb3V0cHV0OiAKICBodG1sX2RvY3VtZW50OiAKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICBjc3M6IHN0YXQ0MS1sYWItdGhlbWUuY3NzCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0UpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHBsb3RseSkKYGBgCgpUb2RheSwgd2UncmUgZ29pbmcgdG8gbWFrZSBvdXIgZmlyc3QgaW50ZXJhY3RpdmUgcGxvdHMhIFdlJ3JlIGdvaW5nIHRvIGNvdmVyIHR3byBvZiB0aGUgYmFzaWNzIGZvciBpbnRlcmFjdGl2aXR5IGluIFIvUk1hcmtkb3duOgoKMS4gUGxvdGx5CjIuIGZsZXhkYXNoYm9hcmQKClBsb3RseSBwcm92aWRlcyBhICoqc3VwZXIqKiBlYXN5LXRvLXVzZSB3cmFwcGVyIGZvciBnZ3Bsb3RzIHRoYXQgaW50ZXJmYWNlIHdpdGggSmF2YVNjcmlwdCBsaWJyYXJpZXMgdG8gYWRkIGJhc2ljIGludGVyYWN0aXZlIGVsZW1lbnRzIHRvIHlvdXIgZXhpc3RpbmcgcGxvdHMuIAoKZmxleGRhc2hib2FyZCBpcyBhIHNwZWNpYWwgdmVyc2lvbiBvZiBhbiBybWFya2Rvd24gZmlsZSB0aGF0IGtuaXRzIHRvIGEgZGFzaGJvYXJkIHZpZXcuIEJ5IGl0c2VsZiwgdGhpcyBpc24ndCBleGFjdGx5ICJpbnRlcmFjdGl2ZSIsIGJ1dCB5b3UgY2FuIGVhc2lseSBhZGQgcGxvdGx5IGdyYXBocyBvciBhZGRpdGlvbmFsIGludGVyYWN0aXZlIGVsZW1lbnRzLiBEYXNoYm9hcmRzIGFyZSBiZWNvbWluZyBtb3JlIGFuZCBtb3JlIHBvcHVsYXIgdG8gc2hvdyByZXN1bHRzIHZpc3VhbGx5LCBidXQgc3RpbGwgd2l0aCBlbm91Z2ggY29udGV4dCB0byBleHBsYWluIHRoZW0uIAoKRm9yIHRvZGF5J3MgbGFiLCB3ZSdyZSBnb2luZyB0byByZXR1cm4gdG8gc29tZSBkYXRhIHdlJ3JlIGZhbWlsaWFyIHdpdGg6IGBjb3ZpZGAuIFdlJ2xsIGJlZ2luIHVzaW5nIHRoZSBgc3RhdGVfYXZnYCBkYXRhc2V0IHRoYXQgd2UgY29uc3RydWN0ZWQgaW4gTGFiMDUsIGFuZCB0aGVuIHlvdSB3aWxsIHVzZSB0aGUgZnVsbCBgY292aWRgIGRhdGFzZXQgZm9yIFBhcnQgMy4gCgpgYGB7cn0KY292aWQgPSByZWFkX2NzdigiZGF0YS9jb3ZpZF9kYXRhLmNzdiIpCgpjb3ZpZCAlPiUKICBncm91cF9ieShnZW9fdmFsdWUsIHNpZ25hbCkgJT4lCiAgc3VtbWFyaXplKAogICAgYXZnID0gbWVhbih2YWx1ZSwgbmEucm0gPSBUKQogICkgJT4lCiAgcGl2b3Rfd2lkZXIoaWRfY29scyA9IGdlb192YWx1ZSwgbmFtZXNfZnJvbSA9IHNpZ25hbCwgdmFsdWVzX2Zyb20gPSBhdmcpICU+JQogIHVuZ3JvdXAoKSAtPiBzdGF0ZV9hdmcKYGBgCgoKIyBQYXJ0IDE6IFBsb3RseQoKUGxvdGx5IGlzIHNwZWNpYWwgc29mdHdhcmUgZm9yIGNyZWF0aW5nIGludGVyYWN0aXZlIHBsb3RzIHdpdGggSmF2YVNjcmlwdCwgYnV0ICp5b3UgZG9uJ3QgbmVlZCB0byBrbm93IGFueSBKYXZhU2NyaXB0IHRvIHVzZSBpdCEqIHRoZSBgZ2dwbG90bHlgIGNvbW1hbmQgdHJhbnNsYXRlcyBiZXR3ZWVuIGBnZ3Bsb3QyYCBhbmQgSmF2YVNjcmlwdCBmb3IgeW91LiAKCkZpcnN0LCBpbnN0YWxsIHRoZSBgcGxvdGx5YCBwYWNrYWdlLiBUYWtlIGEgbG9vayBhdCB3aGF0IHNpbXBseSB3cmFwcGluZyBhbiBleGlzdGluZyBnZ3Bsb3QgaW4gYGdncGxvdGx5YCBjYW4gZG86CgpgYGB7cn0KcDEgPSBzdGF0ZV9hdmcgJT4lCiAgICBtdXRhdGUoc3RhdGUgPSBzdHJfdG9fdXBwZXIoZ2VvX3ZhbHVlKSkgJT4lCiAgICBnZ3Bsb3QoYWVzKHggPSBzbW9vdGhlZF93ZWFyaW5nX21hc2ssIHkgPSBzbW9vdGhlZF9jbGkpKSArCiAgICBnZW9tX3BvaW50KCkgKyAKICAgIHRoZW1lX21pbmltYWwoKQoKZ2dwbG90bHkocDEpCmBgYAoKKE1vdmUgeW91ciBjdXJzb3IgYXJvdW5kIG92ZXIgdGhlIGdyYXBoIGFuZCBob3ZlciBvdmVyIHBvaW50cyAtLSB5b3UgbWF5IGhhdmUgdG8gY2xpY2sgb24gdGhlIGJyb3dzZXIgd2luZG93IHRvIGFjdGl2YXRlIHRoZSBwbG90KS4gVHJ5IGNsaWNraW5nIG9uIHRoZSBtZW51IG9wdGlvbnMgaW4gdGhlIHVwcGVyIHJpZ2h0IG9mIHRoZSBncmFwaCB0byB0b2dnbGUgZmVhdHVyZXMgb24vb2ZmLiAKCldoaWxlIHRoaXMgaXMgZnVuLCBpdCdzIG5vdCBlc3BlY2lhbGx5IHVzZWZ1bCwgc2luY2Ugd2UgY2FuIHJlYWQgdGhlIHZhbHVlcyBmb3IgZWFjaCBwb2ludCBkaXJlY3RseSBmcm9tIHRoZSB4IGFuZCB5IGF4ZXMuIFdoYXQgKndvdWxkKiBiZSB1c2VmdWwgaXMgdG8gYmUgYWJsZSB0byBob3ZlciBvdmVyIGEgcG9pbnQgYW5kIHNlZSB3aGljaCBzdGF0ZSBpdCBjb3JyZXNwb25kcyB0by4gTHVja3kgZm9yIHVzLCBgcGxvdGx5YCBjYW4gZG8ganVzdCB0aGF0ISAKCkJ5IGFkZGluZyBhIGB0ZXh0YCBhZXN0aGV0aWMgdG8gYGdlb21fcG9pbnRgLCB3ZSBjYW4gdGVsbCBwbG90bHkgd2hlcmUgdG8gZmluZCB0aGUgc3RhdGUgaW5mb3JtYXRpb24gZm9yIGVhY2ggcG9pbnQuIFRoZW4sIHdlIGNhbiBjaGFuZ2Ugd2hhdCB2YWx1ZXMgcGxvdGx5IHNob3dzIHVzIHdoZW4gd2UgaG92ZXIgYSBwb2ludCBieSBjaGFuZ2luZyB0aGUgYHRvb2x0aXBgIGFyZ3VtZW50IHRvICJ0ZXh0Ii4gCgpgYGB7cn0KcDIgPSBzdGF0ZV9hdmcgJT4lCiAgICBtdXRhdGUoc3RhdGUgPSBzdHJfdG9fdXBwZXIoZ2VvX3ZhbHVlKSkgJT4lCiAgICBnZ3Bsb3QoYWVzKHggPSBzbW9vdGhlZF93ZWFyaW5nX21hc2ssIHkgPSBzbW9vdGhlZF9jbGkpKSArCiAgICBnZW9tX3BvaW50KGFlcyh0ZXh0ID0gdG91cHBlcihnZW9fdmFsdWUpKSkgKyAKICAgIHRoZW1lX21pbmltYWwoKQoKZ2dwbG90bHkocDIsIHRvb2x0aXAgPSAidGV4dCIpCmBgYAoKKFNlZSB0aGUgW3Bsb3RseSBkb2N1bWVudGF0aW9uXShodHRwczovL3Bsb3RseS5jb20vZ2dwbG90Mi9pbnRlcmFjdGl2ZS10b29sdGlwLykgZm9yIG1vcmUgaW5mbyBvbiBjdXN0b20gdG9vbHRpcHMpCgojIFBhcnQgMjogUGxvdGx5IG9uIHlvdXIgb3duCgpUdXJuIGFueSBncmFwaCB3ZSd2ZSBtYWRlIHNvIGZhciAoaW4gYW55IG9mIHRoZSBsYWJzLCBwcm9qZWN0cywgb3IgY2xhc3MpIGludG8gYW4gaW50ZXJhY3RpdmUgcGxvdGx5IGdyYXBoLiBZb3Ugc2hvdWxkIHRyeSB0byBjaG9vc2UgYSBncmFwaCB3aGVyZSB0aGUgaW50ZXJhY3Rpdml0eSAqKmFkZHMgc29tZXRoaW5nKiogdG8gdGhlIGdyYXBoLiBJdCBtYXkgYmUgaGVscGZ1bCB0byBsb29rIHRocm91Z2ggdGhlIFtwbG90bHkgZG9jdW1lbnRhdGlvbl0oaHR0cHM6Ly9wbG90bHkuY29tL2dncGxvdDIvKSBpZiB5b3UncmUgdHJ5aW5nIHRvIGRvIHNvbWV0aGluZyBzcGVjaWZpYy4gCgooVGhlcmUgaXMgYSBQYXJ0IDMgb2YgdGhpcyBsYWIgdGhhdCB3aWxsIGxpa2VseSBiZSBtb3JlIHRpbWUgY29uc3VtaW5nLCBzbyBkb24ndCBzcGVuZCB0b28gbXVjaCB0aW1lIGZpbmRpbmcgdGhlICpwZXJmZWN0KiBncmFwaCBmb3IgUGFydCAyLikKCiMjIyBTdWJtaXR0aW5nIHlvdXIgd29yawoKTm90ZSB0aGF0IGluIG9yZGVyIGZvciB0aGUgaW50ZXJhY3Rpdml0eSB0byB3b3JrLCB5b3Ugd2lsbCBoYXZlIHRvIGtuaXQgdG8gKmh0bWwqIGluc3RlYWQgb2YgcGRmLiBLbml0dGVkIGh0bWwgZmlsZXMgYXJlIHN0YW5kYWxvbmUgZmlsZXMgdGhhdCBjYW4gYmUgdmlld2VkIGFuZCBzaGFyZWQgLS0ganVzdCBsaWtlIHdvcmQgYW5kIFBERiBkb2N1bWVudHMuIAoKW2BSUHVic2BdKGh0dHBzOi8vcnB1YnMuY29tLykgaXMgYSBmcmVlIHNlcnZpY2UgdGhhdCBwdWJsaXNoZXMgeW91ciBrbml0dGVkIHJtYXJrZG93biBmaWxlcyB0byB0aGUgd2ViIGFuZCBpcyAqKnN1cGVyIGVhc3kqKiB0byB1c2UuIAoKQmVmb3JlIHB1Ymxpc2hpbmcgeW91ciBmaWxlOiAKCisgdXNlIGBlY2hvID0gRkFMU0VgIGF0IHRoZSBiZWdpbm5pbmcgb2YgeW91ciBSIGNodW5rcyB0byBoaWRlIHNwZWNpZmljIGJsb2NrcyBvZiBjb2RlLiBJJ2QgcmVjb21tZW5kIGRvaW5nIHRoaXMgZm9yIGFueSBjb2RlIHRoYXQgY29udGFpbnMgc3BlY2lmaWMgcGF0aHMgb24geW91ciBjb21wdXRlciAobGlrZSBgcmVhZF9jc3YoJ2FsdWJ5L1ByaXZhdGUvU3VwZXItUHJpdmF0ZS1Gb2xkZXItTmFtZS9sYWIwOS5odG1sJylgKQorIElmIHlvdSBkb24ndCB3YW50IHRvIGluY2x1ZGUgeW91ciBuYW1lIG9uIHlvdXIga25pdHRlZCBIVE1MIGZpbGUsIHlvdSBkb24ndCBoYXZlIHRvISAKKyBJZiB5b3UgZG9uJ3Qgd2FudCB0byBwdWJsaXNoIGFueXRoaW5nIG9ubGluZSwgeW91IGRvbid0IGhhdmUgdG8sIGFuZCBjYW4gc3VibWl0IHlvdXIgZmlsZXMgb24gbW9vZGxlIGFzIHVzdWFsCiAgICAtIE1vb2RsZSBvZnRlbiBzdHJ1Z2dsZXMgd2l0aCBIVE1MIGZpbGVzIGJlY2F1c2UgdGhleSdyZSBzbyBsYXJnZS4gSSdsbCB1cCB0aGUgZmlsZSB1cGxvYWQgbGltaXQgZm9yIHRoaXMgbGFiLCBidXQgaWYgeW91IHJ1biBpbnRvIHVwbG9hZGluZyBpc3N1ZXMsIHN1Ym1pdCB5b3VyIC5ybWQgYW5kIGVtYWlsIG1lIHlvdXIgSFRNTC4gCiAgICAKV2hlbiB5b3UncmUgcmVhZHksIGtuaXQgdG8gSFRNTC4gV2hlbiB0aGUga25pdHRlZCBmaWxlIHBvcHMgdXAsIGNsaWNrICJQdWJsaXNoIERvY3VtZW50IiBpbiB0aGUgdXBwZXIgcmlnaHQgY29ybmVyLCB0aGVuIGNob29zZSAiUlB1YnMiLiAKCgpBZnRlciBwdWJsaXNoaW5nIHlvdXIgZmlsZSwKCisgKipUYWtlIG5vdGUgb2YgdGhlIFVSTCB0aGF0IGlzIGdlbmVyYXRlZCoqCisgU3VibWl0IHRoZSBVUkwgdG8geW91ciBmaWxlIGluIHRoZSB0ZXh0IHN1Ym1pc3Npb24gYXJlYSBvZiBtb29kbGUuIFlvdSdsbCBzdWJtaXQgdHdvIFVSTHMgZm9yIHRoaXMgYXNzaWdubWVudCwgb25lIHRoYXQgY29udGFpbnMgeW91ciBgcGxvdGx5YCBncmFwaCBhbmQgdGhlIG90aGVyIHRoYXQgY29udGFpbnMgeW91ciBgZmxleGRhc2hib2FyZGAuIAoKCiMgUGFydCAzOiBgZmxleGRhc2hib2FyZGAKCkZpcnN0LCBpbnN0YWxsIHRoZSBgZmxleGRhc2hib2FyZGAgcGFja2FnZS4gCgpJJ3ZlIG1hZGUgYSB0ZW1wbGF0ZSBmb3IgeW91IHVzaW5nIGBwZW5ndWluc2AgZGF0YS4gVHJ5IGtuaXR0aW5nIGl0LCBzZWUgaG93IGV2ZXJ5dGhpbmcgc2hvd3MgdXAsIGFuZCBwbGF5IGFyb3VuZCB3aXRoIGNoYW5naW5nIGEgZmV3IHRoaW5ncy4gVGhlbiwgY2hhbmdlIHRoZSBkYXNoYm9hcmQgdG8gdXNlIHRoZSBgY292aWRgIGRhdGEuIFlvdSBjYW4gY2hvb3NlIGFueSBzaWduYWwsIHN0YXRlLCBvciB0aW1lIHBlcmlvZCBmb3IgeW91ciBkYXNoYm9hcmQgKG9yIGEgY29tYmluYXRpb24hKS4gCgpUbyBjdXN0b21pemUgdGhlIHRoZW1lLCBhZGQgYSBgdGhlbWVgIGFyZ3VtZW50IHRvIHRoZSB0b3Agb2YgeW91ciBybWFya2Rvd24gZmlsZSBsaWtlIHNvOiAKCmBgYAotLS0KdGl0bGU6ICJQYWxtZXIgUGVuZ3VpbnMiCm91dHB1dDogCiAgZmxleGRhc2hib2FyZDo6ZmxleF9kYXNoYm9hcmQ6CiAgICBvcmllbnRhdGlvbjogY29sdW1ucwogICAgdmVydGljYWxfbGF5b3V0OiBmaWxsCiAgICB0aGVtZTogYm9vdHN0cmFwCi0tLQpgYGAKClBvc3NpYmxlIHRoZW1lcyBhcmU6IAoKLSBjb3NtbwotIGJvb3RzdHJhcAotIGNlcnVsZWFuCi0gam91cm5hbAotIGZsYXRseQotIHJlYWRhYmxlCi0gc3BhY2VsYWIKLSB1bml0ZWQKLSBsdW1lbgotIHBhcGVyCi0gc2FuZHN0b25lCi0gc2ltcGxleAotIHlldGkKCklmIHlvdSdyZSBmZWVsaW5nIHNhdWN5LCB5b3UgY291bGQgZXZlbiBpbmNsdWRlIGBwbG90bHlgIGdyYXBocyBpbiB5b3VyIGRhc2hib2FyZC4KCldlIGFyZSAqYmFyZWx5KiBza2ltbWluZyB0aGUgc3VyZmFjZSBvZiB3aGF0J3MgcG9zc2libGUgd2l0aCBmbGV4ZGFzaGJvYXJkIHRvZGF5LiBJZiB5b3Ugd2FudCB0byBidWlsZCBhIGRhc2hib2FyZCBmb3IgUHJvamVjdCAzIG9yIHlvdXIgZmluYWwgcHJvamVjdCwgSSBoaWdobHkgcmVjb21tZW5kIGNoZWNraW5nIG91dCB0aGUgW2ZsZXhkYXNoYm9hcmQgZG9jdW1lbnRhdGlvbl0oaHR0cHM6Ly9ybWFya2Rvd24ucnN0dWRpby5jb20vZmxleGRhc2hib2FyZC91c2luZy5odG1sKSB0byBzZWUgc29tZSBtb3JlIG9mIHRoZSBhZHZhbmNlZCBmZWF0dXJlcy4gCgojIyMgU3VibWl0dGluZyB5b3VyIHdvcmsKClNhbWUgcnVsZXMgYXMgZm9yIFBhcnQgMi4gV2hlbiB5b3UncmUgcmVhZHksIGtuaXQgdG8gSFRNTC4gV2hlbiB0aGUga25pdHRlZCBmaWxlIHBvcHMgdXAsIGNsaWNrICJQdWJsaXNoIERvY3VtZW50IiBpbiB0aGUgdXBwZXIgcmlnaHQgY29ybmVyLCB0aGVuIGNob29zZSAiUlB1YnMiLiAKCkFmdGVyIHB1Ymxpc2hpbmcgeW91ciBmaWxlLAoKKyAqKlRha2Ugbm90ZSBvZiB0aGUgVVJMIHRoYXQgaXMgZ2VuZXJhdGVkKioKKyBTdWJtaXQgdGhlIFVSTCB0byB5b3VyIGZpbGUgaW4gdGhlIHRleHQgc3VibWlzc2lvbiBhcmVhIG9mIG1vb2RsZS4gWW91J2xsIHN1Ym1pdCB0d28gVVJMcyBmb3IgdGhpcyBhc3NpZ25tZW50LCBvbmUgdGhhdCBjb250YWlucyB5b3VyIGBwbG90bHlgIGdyYXBoIGFuZCB0aGUgb3RoZXIgdGhhdCBjb250YWlucyB5b3VyIGBmbGV4ZGFzaGJvYXJkYC4gCgo=