<<BACK

Literate programming is in essence to treat programming as writing human readable literature. Yesterday we learned how to write scripts and I explained that you should always write ample comments with # to explain what you were doing in real words. Literate programming flips that on it’s head. It intersperses snippets of code throughout human readable (and nicely formatted) text.

This type of programming maximizes reproducibility since the focus is on human readability while still maintaining functionality. In my [Remi] opinion, using interactive literate programming in R in the form of R notebooks is by far the most efficient workflow for science. Using R notebooks, you can go from raw data to a fully-formatted publication-ready pdf file using a single document. However, my preference is simply to effectively write an exhaustively detailed methods section more akin to a lab notebook than a polished manuscript. I then submit this as an appendix to my real manuscript.

R notebooks are written in “R Markdown” (.Rmd) which is really just markdown with chunks of R code interspersed in the text. Markdown is a lightweight markup language with plain text formatting syntax. It’s designed so that it can be converted to HTML and many other formats (e.g. .pdf, .docx). You’ve probably already used markdown before and not even realized it since it is so ubiquitous on the web.

Also, this entire workshop website was developped using R Markdown!

But that’s enough talk, let’s do it! The first step is to start a new notebook.

Have a read through of what is on that template, it’s quite informative

That top bit between the two lines with --- is the YAML header (YAML stands for “YAML Ain’t Markup Language”, seriously…), it essentially contains options about the entire document and how that will be output. Don’t worry about it too much for now.

The text in the white sections is markdown, pretty much plain text with some basic formatting. Here’s a few examples of formatting options, even LaTeX equations (they are just highlighted above and formatted below because I had to make them look like code so markdown would not format them, but feel free to past these into your notebook):

# Heading 1
## Heading 2
### Heading 3
#### Heading 4

*italics*

**bold**

~~strikethrough~~

~subscript~

^superscript^

![](pictures/notebook.png)

[link](www.link.com)

$E = mc^2$

$$y = \mu + \sum_{i=1}^p \beta_i x_i + \epsilon$$

Heading 1

Heading 2

Heading 3

Heading 4

italics

bold

strike-through

subscript

superscript

link

\(E = mc^2\)

\[y = \mu + \sum_{i=1}^p \beta_i x_i + \epsilon\]

Again, there is much more on the R Markdown site and cheatsheet

Up to now not super exciting, but the real power is that you can write R code and run it interactively inside a notebook. The part highlighted in blue preceded by three back ticks and the {r} and followed by three more back ticks is called an R chunk. You can write a few lines of R code and run it by hitting the run button in the chunk:

You can also see a lot more options in the run button at the top right:

This gets really useful as you are developing your analysis since you can run your entire analysis by running all the chunks, or if you are working part way through a document, you can run just the chunks up to the point where you are working. The game changer for me is that the output of the chunk is printed to the notebook interactively. So you can make some changes to a chunk and rerun just the chunk or even just some specific lines of the chunk (that works just like in a script, highlight and Ctrl + Enter or Command + Enter) without having to re-run your entire analysis (so long as the current chunk doesn’t overwrite something).

Also, instead of commenting out lines of code, you can ‘turn off’ whole chunks by setting options in the curly brackets {r, eval = FALSE}. This is useful if a certain part of your analysis takes a really long time, you can run that chunk once, save the output to file, then set eval = FALSE, that way you can still have the code there, but you can just load the output and continue with your analysis.

I also really appreciate being able to pop out the file in a new window with the . That way I can work on my notebook interactively, which has my markdown text, my R code, and it’s output, and it’s full screen!

#You can also run inline code like this `r x <- c(2,3,4)` and then say things like the mean is `r mean(x)`

Which becomes: You can also run inline code like this and then say things like the mean is 3

That is quite powerful since doing something like adding a data point upstream will not make your text incorrect.

Rendering

One of the cool things about working on a notebook is that when you hit the button it will render your .rmd ‘as is’ without having to re-run your analysis. Sure there are pros and cons with that, if you fudged something it renders the output that is already in the notebook. To ensure that everything is reproducible, you may want to make sure you run all your chunks before finalizing everything. Alternatively, click on the little down arrow on the button and click on ‘Knit to PDF’ (or HTML or Word) and it will run all the chunks automatically.

You’ve also just discovered one of the strengths of working in R Markdown, you can write one file and have many different possible outputs. Of course, when you output to pdf or word, your output will lose any interactive features (e.g. plotly, leaflet, etc)

Finally, when you render as either html or a notebook, it’s easy to post that on to GitHub as your own website so you can share what you’ve done with colleagues, supervisors, the public, whoever! We’ll cover that in the Data Archiving & Version Control lesson this afternoon

<<BACK

LS0tDQp0aXRsZTogIkludHJvZHVjdGlvbiB0byBsaXRlcmF0ZSBwcm9ncmFtbWluZyBpbiBSIg0Kb3V0cHV0Og0KICBodG1sX25vdGVib29rOg0KICAgIHRvYzogeWVzDQogICAgdG9jX2Zsb2F0OiB5ZXMNCi0tLQ0KWzw8QkFDS10oaHR0cHM6Ly9yZW1pLWRhaWdsZS5naXRodWIuaW8vMjAxNy1DSE9OZS1EYXRhLykNCg0KTGl0ZXJhdGUgcHJvZ3JhbW1pbmcgaXMgaW4gZXNzZW5jZSB0byB0cmVhdCBwcm9ncmFtbWluZyBhcyB3cml0aW5nIGh1bWFuIHJlYWRhYmxlIGxpdGVyYXR1cmUuIFllc3RlcmRheSB3ZSBsZWFybmVkIGhvdyB0byB3cml0ZSBzY3JpcHRzIGFuZCBJIGV4cGxhaW5lZCB0aGF0IHlvdSBzaG91bGQgYWx3YXlzIHdyaXRlIGFtcGxlIGNvbW1lbnRzIHdpdGggYCNgIHRvIGV4cGxhaW4gd2hhdCB5b3Ugd2VyZSBkb2luZyBpbiByZWFsIHdvcmRzLiBMaXRlcmF0ZSBwcm9ncmFtbWluZyBmbGlwcyB0aGF0IG9uIGl0J3MgaGVhZC4gSXQgaW50ZXJzcGVyc2VzIHNuaXBwZXRzIG9mIGNvZGUgdGhyb3VnaG91dCBodW1hbiByZWFkYWJsZSAoYW5kIG5pY2VseSBmb3JtYXR0ZWQpIHRleHQuDQoNClRoaXMgdHlwZSBvZiBwcm9ncmFtbWluZyBtYXhpbWl6ZXMgcmVwcm9kdWNpYmlsaXR5IHNpbmNlIHRoZSBmb2N1cyBpcyBvbiBodW1hbiByZWFkYWJpbGl0eSB3aGlsZSBzdGlsbCBtYWludGFpbmluZyBmdW5jdGlvbmFsaXR5LiBJbiBteSBbUmVtaV0gb3BpbmlvbiwgdXNpbmcgaW50ZXJhY3RpdmUgbGl0ZXJhdGUgcHJvZ3JhbW1pbmcgaW4gUiBpbiB0aGUgZm9ybSBvZiBSIG5vdGVib29rcyBpcyBieSBmYXIgdGhlIG1vc3QgZWZmaWNpZW50IHdvcmtmbG93IGZvciBzY2llbmNlLiBVc2luZyBSIG5vdGVib29rcywgeW91IGNhbiBnbyBmcm9tIHJhdyBkYXRhIHRvIGEgZnVsbHktZm9ybWF0dGVkIHB1YmxpY2F0aW9uLXJlYWR5IHBkZiBmaWxlIHVzaW5nIGEgc2luZ2xlIGRvY3VtZW50LiBIb3dldmVyLCBteSBwcmVmZXJlbmNlIGlzIHNpbXBseSB0byBlZmZlY3RpdmVseSB3cml0ZSBhbiBleGhhdXN0aXZlbHkgZGV0YWlsZWQgbWV0aG9kcyBzZWN0aW9uIG1vcmUgYWtpbiB0byBhIGxhYiBub3RlYm9vayB0aGFuIGEgcG9saXNoZWQgbWFudXNjcmlwdC4gSSB0aGVuIHN1Ym1pdCB0aGlzIGFzIGFuIGFwcGVuZGl4IHRvIG15IHJlYWwgbWFudXNjcmlwdC4NCg0KUiBub3RlYm9va3MgYXJlIHdyaXR0ZW4gaW4gIlIgTWFya2Rvd24iIChgLlJtZGApIHdoaWNoIGlzIHJlYWxseSBqdXN0IG1hcmtkb3duIHdpdGggY2h1bmtzIG9mIFIgY29kZSBpbnRlcnNwZXJzZWQgaW4gdGhlIHRleHQuIE1hcmtkb3duIGlzIGEgbGlnaHR3ZWlnaHQgbWFya3VwIGxhbmd1YWdlIHdpdGggcGxhaW4gdGV4dCBmb3JtYXR0aW5nIHN5bnRheC4gSXQncyBkZXNpZ25lZCBzbyB0aGF0IGl0IGNhbiBiZSBjb252ZXJ0ZWQgdG8gSFRNTCBhbmQgbWFueSBvdGhlciBmb3JtYXRzIChlLmcuIGAucGRmYCwgYC5kb2N4YCkuIFlvdSd2ZSBwcm9iYWJseSBhbHJlYWR5IHVzZWQgbWFya2Rvd24gYmVmb3JlIGFuZCBub3QgZXZlbiByZWFsaXplZCBpdCBzaW5jZSBpdCBpcyBzbyB1YmlxdWl0b3VzIG9uIHRoZSB3ZWIuDQoNCkFsc28sICp0aGlzIGVudGlyZSB3b3Jrc2hvcCB3ZWJzaXRlIHdhcyBkZXZlbG9wcGVkIHVzaW5nIFIgTWFya2Rvd24qIQ0KDQpCdXQgdGhhdCdzIGVub3VnaCB0YWxrLCBsZXQncyBkbyBpdCEgVGhlIGZpcnN0IHN0ZXAgaXMgdG8gc3RhcnQgYSBuZXcgbm90ZWJvb2suDQoNCiFbXShwaWN0dXJlcy9uZXdub3RlYm9vay5wbmcpDQoNCkhhdmUgYSByZWFkIHRocm91Z2ggb2Ygd2hhdCBpcyBvbiB0aGF0IHRlbXBsYXRlLCBpdCdzIHF1aXRlIGluZm9ybWF0aXZlDQoNCiFbXShwaWN0dXJlcy9ub3RlYm9vay5wbmcpDQoNClRoYXQgdG9wIGJpdCBiZXR3ZWVuIHRoZSB0d28gbGluZXMgd2l0aCBgLS0tYCBpcyB0aGUgWUFNTCBoZWFkZXIgKFlBTUwgc3RhbmRzIGZvciAiWUFNTCBBaW4ndCBNYXJrdXAgTGFuZ3VhZ2UiLCBzZXJpb3VzbHkuLi4pLCBpdCBlc3NlbnRpYWxseSBjb250YWlucyBvcHRpb25zIGFib3V0IHRoZSBlbnRpcmUgZG9jdW1lbnQgYW5kIGhvdyB0aGF0IHdpbGwgYmUgb3V0cHV0LiBEb24ndCB3b3JyeSBhYm91dCBpdCB0b28gbXVjaCBmb3Igbm93Lg0KDQpUaGUgdGV4dCBpbiB0aGUgd2hpdGUgc2VjdGlvbnMgaXMgbWFya2Rvd24sIHByZXR0eSBtdWNoIHBsYWluIHRleHQgd2l0aCBzb21lIGJhc2ljIGZvcm1hdHRpbmcuIEhlcmUncyBhIGZldyBleGFtcGxlcyBvZiBmb3JtYXR0aW5nIG9wdGlvbnMsIGV2ZW4gTGFUZVggZXF1YXRpb25zICh0aGV5IGFyZSBqdXN0IGhpZ2hsaWdodGVkIGFib3ZlIGFuZCBmb3JtYXR0ZWQgYmVsb3cgYmVjYXVzZSBJIGhhZCB0byBtYWtlIHRoZW0gbG9vayBsaWtlIGNvZGUgc28gbWFya2Rvd24gd291bGQgbm90IGZvcm1hdCB0aGVtLCBidXQgZmVlbCBmcmVlIHRvIHBhc3QgdGhlc2UgaW50byB5b3VyIG5vdGVib29rKToNCg0KYGBgDQojIEhlYWRpbmcgMQ0KIyMgSGVhZGluZyAyDQojIyMgSGVhZGluZyAzDQojIyMjIEhlYWRpbmcgNA0KDQoqaXRhbGljcyoNCg0KKipib2xkKioNCg0Kfn5zdHJpa2V0aHJvdWdofn4NCg0KfnN1YnNjcmlwdH4NCg0KXnN1cGVyc2NyaXB0Xg0KDQohW10ocGljdHVyZXMvbm90ZWJvb2sucG5nKQ0KDQpbbGlua10od3d3LmxpbmsuY29tKQ0KDQokRSA9IG1jXjIkDQoNCiQkeSA9IFxtdSArIFxzdW1fe2k9MX1ecCBcYmV0YV9pIHhfaSArIFxlcHNpbG9uJCQNCg0KYGBgDQoNCiMgSGVhZGluZyAxDQojIyBIZWFkaW5nIDINCiMjIyBIZWFkaW5nIDMNCiMjIyMgSGVhZGluZyA0DQoNCippdGFsaWNzKg0KDQoqKmJvbGQqKg0KDQp+fnN0cmlrZS10aHJvdWdofn4NCg0KfnN1YnNjcmlwdH4NCg0KXnN1cGVyc2NyaXB0Xg0KDQohW10ocGljdHVyZXMvcHJldmlldy5wbmcpDQoNCltsaW5rXSh3d3cubGluay5jb20pDQoNCiRFID0gbWNeMiQNCg0KJCR5ID0gXG11ICsgXHN1bV97aT0xfV5wIFxiZXRhX2kgeF9pICsgXGVwc2lsb24kJA0KDQpBZ2FpbiwgdGhlcmUgaXMgbXVjaCBtb3JlIG9uIHRoZSBSIE1hcmtkb3duIFtzaXRlXShodHRwOi8vcm1hcmtkb3duLnJzdHVkaW8uY29tL2xlc3Nvbi0xLmh0bWwpIGFuZCBbY2hlYXRzaGVldF0oaHR0cHM6Ly93d3cucnN0dWRpby5jb20vd3AtY29udGVudC91cGxvYWRzLzIwMTUvMDIvcm1hcmtkb3duLWNoZWF0c2hlZXQucGRmKQ0KDQpVcCB0byBub3cgbm90IHN1cGVyIGV4Y2l0aW5nLCBidXQgdGhlIHJlYWwgcG93ZXIgaXMgdGhhdCB5b3UgY2FuIHdyaXRlIFIgY29kZSBhbmQgcnVuIGl0IGludGVyYWN0aXZlbHkgaW5zaWRlIGEgbm90ZWJvb2suIFRoZSBwYXJ0IGhpZ2hsaWdodGVkIGluIGJsdWUgcHJlY2VkZWQgYnkgdGhyZWUgYmFjayB0aWNrcyBhbmQgdGhlIGB7cn1gIGFuZCBmb2xsb3dlZCBieSB0aHJlZSBtb3JlIGJhY2sgdGlja3MgaXMgY2FsbGVkIGFuIFIgY2h1bmsuIFlvdSBjYW4gd3JpdGUgYSBmZXcgbGluZXMgb2YgUiBjb2RlIGFuZCBydW4gaXQgYnkgaGl0dGluZyB0aGUgcnVuIGJ1dHRvbiBpbiB0aGUgY2h1bms6DQoNCiFbXShwaWN0dXJlcy9ydW4ucG5nKQ0KDQpZb3UgY2FuIGFsc28gc2VlIGEgbG90IG1vcmUgb3B0aW9ucyBpbiB0aGUgcnVuIGJ1dHRvbiBhdCB0aGUgdG9wIHJpZ2h0Og0KDQohW10ocGljdHVyZXMvcnVuYnV0dG9uLnBuZykNCg0KVGhpcyBnZXRzIHJlYWxseSB1c2VmdWwgYXMgeW91IGFyZSBkZXZlbG9waW5nIHlvdXIgYW5hbHlzaXMgc2luY2UgeW91IGNhbiBydW4geW91ciBlbnRpcmUgYW5hbHlzaXMgYnkgcnVubmluZyBhbGwgdGhlIGNodW5rcywgb3IgaWYgeW91IGFyZSB3b3JraW5nIHBhcnQgd2F5IHRocm91Z2ggYSBkb2N1bWVudCwgeW91IGNhbiBydW4ganVzdCB0aGUgY2h1bmtzIHVwIHRvIHRoZSBwb2ludCB3aGVyZSB5b3UgYXJlIHdvcmtpbmcuIFRoZSBnYW1lIGNoYW5nZXIgZm9yIG1lIGlzIHRoYXQgdGhlIG91dHB1dCBvZiB0aGUgY2h1bmsgaXMgcHJpbnRlZCB0byB0aGUgbm90ZWJvb2sgaW50ZXJhY3RpdmVseS4gU28geW91IGNhbiBtYWtlIHNvbWUgY2hhbmdlcyB0byBhIGNodW5rIGFuZCByZXJ1biBqdXN0IHRoZSBjaHVuayBvciBldmVuIGp1c3Qgc29tZSBzcGVjaWZpYyBsaW5lcyBvZiB0aGUgY2h1bmsgKHRoYXQgd29ya3MganVzdCBsaWtlIGluIGEgc2NyaXB0LCBoaWdobGlnaHQgYW5kIGBDdHJsYCArIGBFbnRlcmAgb3IgYENvbW1hbmRgICsgYEVudGVyYCkgd2l0aG91dCBoYXZpbmcgdG8gcmUtcnVuIHlvdXIgZW50aXJlIGFuYWx5c2lzIChzbyBsb25nIGFzIHRoZSBjdXJyZW50IGNodW5rIGRvZXNuJ3Qgb3ZlcndyaXRlIHNvbWV0aGluZykuDQoNCkFsc28sIGluc3RlYWQgb2YgY29tbWVudGluZyBvdXQgbGluZXMgb2YgY29kZSwgeW91IGNhbiAndHVybiBvZmYnIHdob2xlIGNodW5rcyBieSBzZXR0aW5nIG9wdGlvbnMgaW4gdGhlIGN1cmx5IGJyYWNrZXRzIGB7ciwgZXZhbCA9IEZBTFNFfWAuIFRoaXMgaXMgdXNlZnVsIGlmIGEgY2VydGFpbiBwYXJ0IG9mIHlvdXIgYW5hbHlzaXMgdGFrZXMgYSByZWFsbHkgbG9uZyB0aW1lLCB5b3UgY2FuIHJ1biB0aGF0IGNodW5rIG9uY2UsIHNhdmUgdGhlIG91dHB1dCB0byBmaWxlLCB0aGVuIHNldCBgZXZhbCA9IEZBTFNFYCwgdGhhdCB3YXkgeW91IGNhbiBzdGlsbCBoYXZlIHRoZSBjb2RlIHRoZXJlLCBidXQgeW91IGNhbiBqdXN0IGxvYWQgdGhlIG91dHB1dCBhbmQgY29udGludWUgd2l0aCB5b3VyIGFuYWx5c2lzLg0KDQpJIGFsc28gcmVhbGx5IGFwcHJlY2lhdGUgYmVpbmcgYWJsZSB0byBwb3Agb3V0IHRoZSBmaWxlIGluIGEgbmV3IHdpbmRvdyB3aXRoIHRoZSAhW10ocGljdHVyZXMvcG9wb3V0LnBuZykuIFRoYXQgd2F5IEkgY2FuIHdvcmsgb24gbXkgbm90ZWJvb2sgaW50ZXJhY3RpdmVseSwgd2hpY2ggaGFzIG15IG1hcmtkb3duIHRleHQsIG15IFIgY29kZSwgYW5kIGl0J3Mgb3V0cHV0LCBhbmQgaXQncyBmdWxsIHNjcmVlbiENCg0KYGBge3J9DQojWW91IGNhbiBhbHNvIHJ1biBpbmxpbmUgY29kZSBsaWtlIHRoaXMgYHIgeCA8LSBjKDIsMyw0KWAgYW5kIHRoZW4gc2F5IHRoaW5ncyBsaWtlIHRoZSBtZWFuIGlzIGByIG1lYW4oeClgDQpgYGANCiBXaGljaCBiZWNvbWVzOg0KWW91IGNhbiBhbHNvIHJ1biBpbmxpbmUgY29kZSBsaWtlIHRoaXMgYHIgeCA8LSBjKDIsMyw0KWAgYW5kIHRoZW4gc2F5IHRoaW5ncyBsaWtlIHRoZSBtZWFuIGlzIGByIG1lYW4oeClgDQoNClRoYXQgaXMgcXVpdGUgcG93ZXJmdWwgc2luY2UgZG9pbmcgc29tZXRoaW5nIGxpa2UgYWRkaW5nIGEgZGF0YSBwb2ludCB1cHN0cmVhbSB3aWxsIG5vdCBtYWtlIHlvdXIgdGV4dCBpbmNvcnJlY3QuIA0KDQojIFJlbmRlcmluZw0KDQpPbmUgb2YgdGhlIGNvb2wgdGhpbmdzIGFib3V0IHdvcmtpbmcgb24gYSBub3RlYm9vayBpcyB0aGF0IHdoZW4geW91IGhpdCB0aGUgIVtdKHBpY3R1cmVzL3ByZXZpZXcucG5nKSBidXR0b24gaXQgd2lsbCByZW5kZXIgeW91ciBgLnJtZGAgJ2FzIGlzJyB3aXRob3V0IGhhdmluZyB0byByZS1ydW4geW91ciBhbmFseXNpcy4gU3VyZSB0aGVyZSBhcmUgcHJvcyBhbmQgY29ucyB3aXRoIHRoYXQsIGlmIHlvdSBmdWRnZWQgc29tZXRoaW5nIGl0IHJlbmRlcnMgdGhlIG91dHB1dCB0aGF0IGlzIGFscmVhZHkgaW4gdGhlIG5vdGVib29rLiBUbyBlbnN1cmUgdGhhdCBldmVyeXRoaW5nIGlzIHJlcHJvZHVjaWJsZSwgeW91IG1heSB3YW50IHRvIG1ha2Ugc3VyZSB5b3UgcnVuIGFsbCB5b3VyIGNodW5rcyBiZWZvcmUgZmluYWxpemluZyBldmVyeXRoaW5nLiBBbHRlcm5hdGl2ZWx5LCBjbGljayBvbiB0aGUgbGl0dGxlIGRvd24gYXJyb3cgb24gdGhlICFbXShwaWN0dXJlcy9wcmV2aWV3LnBuZykgYnV0dG9uIGFuZCBjbGljayBvbiAnS25pdCB0byBQREYnIChvciBIVE1MIG9yIFdvcmQpIGFuZCBpdCB3aWxsIHJ1biBhbGwgdGhlIGNodW5rcyBhdXRvbWF0aWNhbGx5LiANCg0KWW91J3ZlIGFsc28ganVzdCBkaXNjb3ZlcmVkIG9uZSBvZiB0aGUgc3RyZW5ndGhzIG9mIHdvcmtpbmcgaW4gUiBNYXJrZG93biwgeW91IGNhbiB3cml0ZSBvbmUgZmlsZSBhbmQgaGF2ZSBtYW55IGRpZmZlcmVudCBwb3NzaWJsZSBvdXRwdXRzLiBPZiBjb3Vyc2UsIHdoZW4geW91IG91dHB1dCB0byBwZGYgb3Igd29yZCwgeW91ciBvdXRwdXQgd2lsbCBsb3NlIGFueSBpbnRlcmFjdGl2ZSBmZWF0dXJlcyAoZS5nLiBwbG90bHksIGxlYWZsZXQsIGV0YykNCg0KRmluYWxseSwgd2hlbiB5b3UgcmVuZGVyIGFzIGVpdGhlciBodG1sIG9yIGEgbm90ZWJvb2ssIGl0J3MgZWFzeSB0byBwb3N0IHRoYXQgb24gdG8gR2l0SHViIGFzIHlvdXIgb3duIHdlYnNpdGUgc28geW91IGNhbiBzaGFyZSB3aGF0IHlvdSd2ZSBkb25lIHdpdGggY29sbGVhZ3Vlcywgc3VwZXJ2aXNvcnMsIHRoZSBwdWJsaWMsIHdob2V2ZXIhIFdlJ2xsIGNvdmVyIHRoYXQgaW4gdGhlIFtEYXRhIEFyY2hpdmluZyAmIFZlcnNpb24gQ29udHJvbF0oaHR0cHM6Ly9yZW1pLWRhaWdsZS5naXRodWIuaW8vMjAxNy1DSE9OZS1EYXRhL3ZlcnNpb25jb250cm9sLm5iLmh0bWwpIGxlc3NvbiB0aGlzIGFmdGVybm9vbg0KDQpbPDxCQUNLXShodHRwczovL3JlbWktZGFpZ2xlLmdpdGh1Yi5pby8yMDE3LUNIT05lLURhdGEvKQ0K