Introduction

R code can be written in two general ways: (1) as Literate Programs using R Markdown Notebooks and (2) as scripts. Scripts are programs that can run within an IDE such as R Studio or be directly executed from the command line through R. Scripts have the benefit that they can be debugged using a debugger, while R Notebook code chunks are more difficult to debug. Another benefit of scripts is that they can be run from the command line and as part of cron jobs, i.e., they can be scheduled to run automatically at a point in time. Finally, R scripts can be included in shell scripts (on Unix and MacOS) and .bat batch programs (on Windows).

R Notebooks are markdown documents that contain embedded code in R and other languages. They are most useful when producing reports, memos, and analytics journals where we need to intersperse narratives and text with code. An R Notebook produces a document (HTML or PDF, most commonly) when it is “run”. An R Script is a program that runs like in any other language.

R Scripts are preferable when you need stand-alone R programs that can be run directly from the command line or within a shell script. One main benefit of using R Scripts is that we can use the debugger within R Studio.

Writing R Scripts in R Studio

An R script is a text file containing R statements. In R, every statement must be on a separate line. A script file can be created in any text editor, but not a word processor. One of the easiest ways to create an R script is to use R Studio because R Studio provides mechanisms for debugging, syntax aware editing, an object navigator, among other features.

While not actually required, R scripts should have the extension .R.

File and Path References

Unlike an R Notebook, R does not consider the folder (directory) where it is located to be the current working directory. You must explicitly specify all paths or use setwd() to set the working directory for the duration of the script. This is a particular issue when running within an R Project.

Running R Scripts from the Command Line

Running R from the command line provides much more flexibility than running R only within an IDE such as R Studio. For example, we can process multiple files at once through loops in a shell script. We can write several smaller R programs and chain them together so that each program carries out one step in the analysis. The programs become more modular and can be used independently.

To run (or execute) an R script requires that “Base R” is installed; it does not require R Studio to be installed. To run an R script from the command line, start or open a command line shell (also known as a terminal or simply a shell). On Windows, run the program cmd or powershell, on MacOS launch Terminal. While they look similar, cmd is a traditional DOS shell, while PowerShell is more similar to a Unix shell. Terminal is a standard Unix bash (Bourne Again Shell). MacOS comes with bash as the default user shell and also includes the TENEX C shell (tcsh), the Korn shell (ksh), and the Z shell (zsh). This generally does not matter for simple command line interactions but matters if you wish to write shell scripts.

Assume that the file ScriptA.R is an R program. We can run it directly from the command line using the Rscript program that is installed when you install R:

Rscript ScriptA.R

To launch R for interactive work from the command line, you can launch it as follows:

R

To run Rscript or R from the command line presumes that they are in your “path”. If you get the error that they cannot be found, then you need to add the installation folder for R to your path or specify the full path to RScript/R.

The example below shows how to embed an R program within a shell script on Unix (and MacOS/Linux).

#!/bin/sh

Rscript ScriptA.R

After creating a new shell script, don’t forget to set execute permissions on the file with:

chmod +x analyze

The video tutorial demonstrates how to run an R program from the command line and within shell scripts.

Nesting R Scripts

You can “call” or run another R Script from within an R Script using either source() or sys.source() as shown below:

source("another-script.R")

Program Structure

R Scripts are scripts in the sense that they are R statements that are executed line-by-line starting with the first line. There is no “entry point” like in C where execution starts at the function main(). However, we can adopt that structure by making the first line a call to the function main() as shown below and then placing all code with a main() function.

Conclusion

R is a powerful data manipulation and statistical programming language that can be used to create standalone programs.


Files & Resources

All Files for Lesson 6.109

References

None.

Errata

None collected yet. Let us know.

LS0tDQp0aXRsZTogIlIgU2NyaXB0cyBhbmQgUHJvZ3JhbXMiDQpwYXJhbXM6DQogIGNhdGVnb3J5OiA2DQogIG51bWJlcjogMTA5DQogIHRpbWU6IDQ1DQogIGxldmVsOiBiZWdpbm5lcg0KICB0YWdzOiAicixyIHNjcmlwdCINCiAgZGVzY3JpcHRpb246ICJTaG93cyBob3cgdG8gY3JlYXRlIFIgc2NyaXB0cyBhbmQgZXhlY3V0ZSB0aGVtIGZyb20gdGhlIGNvbW1hbmQNCiAgICAgICAgICAgICAgICBsaW5lIGFzIHN0YW5kLWFsb25lIHByb2dyYW1zLiINCmRhdGU6ICI8c21hbGw+YHIgU3lzLkRhdGUoKWA8L3NtYWxsPiINCmF1dGhvcjogIjxzbWFsbD5NYXJ0aW4gU2NoZWRsYmF1ZXI8L3NtYWxsPiINCmVtYWlsOiAibS5zY2hlZGxiYXVlckBuZXUuZWR1Ig0KYWZmaWxpdGF0aW9uOiAiTm9ydGhlYXN0ZXJuIFVuaXZlcnNpdHkiDQpvdXRwdXQ6IA0KICBib29rZG93bjo6aHRtbF9kb2N1bWVudDI6DQogICAgdG9jOiB0cnVlDQogICAgdG9jX2Zsb2F0OiB0cnVlDQogICAgY29sbGFwc2VkOiBmYWxzZQ0KICAgIG51bWJlcl9zZWN0aW9uczogZmFsc2UNCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQogICAgdGhlbWU6IHNwYWNlbGFiDQogICAgaGlnaGxpZ2h0OiB0YW5nbw0KLS0tDQoNCi0tLQ0KdGl0bGU6ICI8c21hbGw+YHIgcGFyYW1zJGNhdGVnb3J5YC5gciBwYXJhbXMkbnVtYmVyYDwvc21hbGw+PGJyLz48c3BhbiBzdHlsZT0nY29sb3I6ICMyRTQwNTM7IGZvbnQtc2l6ZTogMC45ZW0nPmByIHJtYXJrZG93bjo6bWV0YWRhdGEkdGl0bGVgPC9zcGFuPiINCi0tLQ0KDQpgYGB7ciBjb2RlPXhmdW46OnJlYWRfdXRmOChwYXN0ZTAoaGVyZTo6aGVyZSgpLCcvUi9faW5zZXJ0MkRCLlInKSksIGluY2x1ZGUgPSBGQUxTRX0NCmBgYA0KDQojIyBJbnRyb2R1Y3Rpb24NCg0KUiBjb2RlIGNhbiBiZSB3cml0dGVuIGluIHR3byBnZW5lcmFsIHdheXM6ICgxKSBhcyBMaXRlcmF0ZSBQcm9ncmFtcyB1c2luZyBSIE1hcmtkb3duIE5vdGVib29rcyBhbmQgKDIpIGFzIHNjcmlwdHMuIFNjcmlwdHMgYXJlIHByb2dyYW1zIHRoYXQgY2FuIHJ1biB3aXRoaW4gYW4gSURFIHN1Y2ggYXMgUiBTdHVkaW8gb3IgYmUgZGlyZWN0bHkgZXhlY3V0ZWQgZnJvbSB0aGUgY29tbWFuZCBsaW5lIHRocm91Z2ggUi4gU2NyaXB0cyBoYXZlIHRoZSBiZW5lZml0IHRoYXQgdGhleSBjYW4gYmUgZGVidWdnZWQgdXNpbmcgYSBkZWJ1Z2dlciwgd2hpbGUgUiBOb3RlYm9vayBjb2RlIGNodW5rcyBhcmUgbW9yZSBkaWZmaWN1bHQgdG8gZGVidWcuIEFub3RoZXIgYmVuZWZpdCBvZiBzY3JpcHRzIGlzIHRoYXQgdGhleSBjYW4gYmUgcnVuIGZyb20gdGhlIGNvbW1hbmQgbGluZSBhbmQgYXMgcGFydCBvZiAqY3Jvbiogam9icywgKmkuZS4qLCB0aGV5IGNhbiBiZSBzY2hlZHVsZWQgdG8gcnVuIGF1dG9tYXRpY2FsbHkgYXQgYSBwb2ludCBpbiB0aW1lLiBGaW5hbGx5LCBSIHNjcmlwdHMgY2FuIGJlIGluY2x1ZGVkIGluIHNoZWxsIHNjcmlwdHMgKG9uIFVuaXggYW5kIE1hY09TKSBhbmQgKi5iYXQqIGJhdGNoIHByb2dyYW1zIChvbiBXaW5kb3dzKS4NCg0KUiBOb3RlYm9va3MgYXJlIG1hcmtkb3duIGRvY3VtZW50cyB0aGF0IGNvbnRhaW4gZW1iZWRkZWQgY29kZSBpbiBSIGFuZCBvdGhlciBsYW5ndWFnZXMuIFRoZXkgYXJlIG1vc3QgdXNlZnVsIHdoZW4gcHJvZHVjaW5nIHJlcG9ydHMsIG1lbW9zLCBhbmQgYW5hbHl0aWNzIGpvdXJuYWxzIHdoZXJlIHdlIG5lZWQgdG8gaW50ZXJzcGVyc2UgbmFycmF0aXZlcyBhbmQgdGV4dCB3aXRoIGNvZGUuIEFuIFIgTm90ZWJvb2sgcHJvZHVjZXMgYSBkb2N1bWVudCAoSFRNTCBvciBQREYsIG1vc3QgY29tbW9ubHkpIHdoZW4gaXQgaXMgInJ1biIuIEFuIFIgU2NyaXB0IGlzIGEgcHJvZ3JhbSB0aGF0IHJ1bnMgbGlrZSBpbiBhbnkgb3RoZXIgbGFuZ3VhZ2UuDQoNClIgU2NyaXB0cyBhcmUgcHJlZmVyYWJsZSB3aGVuIHlvdSBuZWVkIHN0YW5kLWFsb25lIFIgcHJvZ3JhbXMgdGhhdCBjYW4gYmUgcnVuIGRpcmVjdGx5IGZyb20gdGhlIGNvbW1hbmQgbGluZSBvciB3aXRoaW4gYSBzaGVsbCBzY3JpcHQuIE9uZSBtYWluIGJlbmVmaXQgb2YgdXNpbmcgUiBTY3JpcHRzIGlzIHRoYXQgd2UgY2FuIHVzZSB0aGUgZGVidWdnZXIgd2l0aGluIFIgU3R1ZGlvLg0KDQojIyBXcml0aW5nIFIgU2NyaXB0cyBpbiBSIFN0dWRpbw0KDQpBbiBSIHNjcmlwdCBpcyBhIHRleHQgZmlsZSBjb250YWluaW5nIFIgc3RhdGVtZW50cy4gSW4gUiwgZXZlcnkgc3RhdGVtZW50IG11c3QgYmUgb24gYSBzZXBhcmF0ZSBsaW5lLiBBIHNjcmlwdCBmaWxlIGNhbiBiZSBjcmVhdGVkIGluIGFueSB0ZXh0IGVkaXRvciwgYnV0IG5vdCBhIHdvcmQgcHJvY2Vzc29yLiBPbmUgb2YgdGhlIGVhc2llc3Qgd2F5cyB0byBjcmVhdGUgYW4gUiBzY3JpcHQgaXMgdG8gdXNlIFIgU3R1ZGlvIGJlY2F1c2UgUiBTdHVkaW8gcHJvdmlkZXMgbWVjaGFuaXNtcyBmb3IgZGVidWdnaW5nLCBzeW50YXggYXdhcmUgZWRpdGluZywgYW4gb2JqZWN0IG5hdmlnYXRvciwgYW1vbmcgb3RoZXIgZmVhdHVyZXMuDQoNCldoaWxlIG5vdCBhY3R1YWxseSByZXF1aXJlZCwgUiBzY3JpcHRzIHNob3VsZCBoYXZlIHRoZSBleHRlbnNpb24gKi5SKi4NCg0KIyMgRmlsZSBhbmQgUGF0aCBSZWZlcmVuY2VzDQoNClVubGlrZSBhbiBSIE5vdGVib29rLCBSIGRvZXMgbm90IGNvbnNpZGVyIHRoZSBmb2xkZXIgKGRpcmVjdG9yeSkgd2hlcmUgaXQgaXMgbG9jYXRlZCB0byBiZSB0aGUgY3VycmVudCB3b3JraW5nIGRpcmVjdG9yeS4gWW91IG11c3QgZXhwbGljaXRseSBzcGVjaWZ5IGFsbCBwYXRocyBvciB1c2UgPGNvZGU+c2V0d2QoKTwvY29kZT4gdG8gc2V0IHRoZSB3b3JraW5nIGRpcmVjdG9yeSBmb3IgdGhlIGR1cmF0aW9uIG9mIHRoZSBzY3JpcHQuIFRoaXMgaXMgYSBwYXJ0aWN1bGFyIGlzc3VlIHdoZW4gcnVubmluZyB3aXRoaW4gYW4gUiBQcm9qZWN0Lg0KDQojIyBSdW5uaW5nIFIgU2NyaXB0cyBmcm9tIHRoZSBDb21tYW5kIExpbmUNCg0KUnVubmluZyBSIGZyb20gdGhlIGNvbW1hbmQgbGluZSBwcm92aWRlcyBtdWNoIG1vcmUgZmxleGliaWxpdHkgdGhhbiBydW5uaW5nIFIgb25seSB3aXRoaW4gYW4gSURFIHN1Y2ggYXMgUiBTdHVkaW8uIEZvciBleGFtcGxlLCB3ZSBjYW4gcHJvY2VzcyBtdWx0aXBsZSBmaWxlcyBhdCBvbmNlIHRocm91Z2ggbG9vcHMgaW4gYSBzaGVsbCBzY3JpcHQuIFdlIGNhbiB3cml0ZSBzZXZlcmFsIHNtYWxsZXIgUiBwcm9ncmFtcyBhbmQgY2hhaW4gdGhlbSB0b2dldGhlciBzbyB0aGF0IGVhY2ggcHJvZ3JhbSBjYXJyaWVzIG91dCBvbmUgc3RlcCBpbiB0aGUgYW5hbHlzaXMuIFRoZSBwcm9ncmFtcyBiZWNvbWUgbW9yZSBtb2R1bGFyIGFuZCBjYW4gYmUgdXNlZCBpbmRlcGVuZGVudGx5Lg0KDQpUbyBydW4gKG9yIGV4ZWN1dGUpIGFuIFIgc2NyaXB0IHJlcXVpcmVzIHRoYXQgIltCYXNlIFJdKGh0dHA6Ly9yLXByb2plY3Qub3JnKSIgaXMgaW5zdGFsbGVkOyBpdCBkb2VzIG5vdCByZXF1aXJlIFIgU3R1ZGlvIHRvIGJlIGluc3RhbGxlZC4gVG8gcnVuIGFuIFIgc2NyaXB0IGZyb20gdGhlIGNvbW1hbmQgbGluZSwgc3RhcnQgb3Igb3BlbiBhIGNvbW1hbmQgbGluZSBzaGVsbCAoYWxzbyBrbm93biBhcyBhIHRlcm1pbmFsIG9yIHNpbXBseSBhIHNoZWxsKS4gT24gV2luZG93cywgcnVuIHRoZSBwcm9ncmFtICpjbWQqIG9yICpwb3dlcnNoZWxsKiwgb24gTWFjT1MgbGF1bmNoICpUZXJtaW5hbCouIFdoaWxlIHRoZXkgbG9vayBzaW1pbGFyLCAqY21kKiBpcyBhIHRyYWRpdGlvbmFsIERPUyBzaGVsbCwgd2hpbGUgKlBvd2VyU2hlbGwqIGlzIG1vcmUgc2ltaWxhciB0byBhIFVuaXggc2hlbGwuICpUZXJtaW5hbCogaXMgYSBzdGFuZGFyZCBVbml4ICoqYmFzaCoqIChCb3VybmUgQWdhaW4gU2hlbGwpLiBNYWNPUyBjb21lcyB3aXRoICoqYmFzaCoqIGFzIHRoZSBkZWZhdWx0IHVzZXIgc2hlbGwgYW5kIGFsc28gaW5jbHVkZXMgdGhlIFRFTkVYIEMgc2hlbGwgKCoqdGNzaCoqKSwgdGhlIEtvcm4gc2hlbGwgKCoqa3NoKiopLCBhbmQgdGhlIFogc2hlbGwgKCoqenNoKiopLiBUaGlzIGdlbmVyYWxseSBkb2VzIG5vdCBtYXR0ZXIgZm9yIHNpbXBsZSBjb21tYW5kIGxpbmUgaW50ZXJhY3Rpb25zIGJ1dCBtYXR0ZXJzIGlmIHlvdSB3aXNoIHRvIHdyaXRlIHNoZWxsIHNjcmlwdHMuDQoNCkFzc3VtZSB0aGF0IHRoZSBmaWxlIFtTY3JpcHRBLlJdKFNjcmlwdEEuUikgaXMgYW4gUiBwcm9ncmFtLiBXZSBjYW4gcnVuIGl0IGRpcmVjdGx5IGZyb20gdGhlIGNvbW1hbmQgbGluZSB1c2luZyB0aGUgKipSc2NyaXB0KiogcHJvZ3JhbSB0aGF0IGlzIGluc3RhbGxlZCB3aGVuIHlvdSBpbnN0YWxsIFI6DQoNCmBgYHtiYXNoIGV2YWw9Rn0NClJzY3JpcHQgU2NyaXB0QS5SDQpgYGANCg0KVG8gbGF1bmNoIFIgZm9yIGludGVyYWN0aXZlIHdvcmsgZnJvbSB0aGUgY29tbWFuZCBsaW5lLCB5b3UgY2FuIGxhdW5jaCBpdCBhcyBmb2xsb3dzOg0KDQpgYGB7YmFzaCwgZXZhbD1GfQ0KUg0KYGBgDQoNClRvIHJ1biAqKlJzY3JpcHQqKiBvciAqKlIqKiBmcm9tIHRoZSBjb21tYW5kIGxpbmUgcHJlc3VtZXMgdGhhdCB0aGV5IGFyZSBpbiB5b3VyICJwYXRoIi4gSWYgeW91IGdldCB0aGUgZXJyb3IgdGhhdCB0aGV5IGNhbm5vdCBiZSBmb3VuZCwgdGhlbiB5b3UgbmVlZCB0byBhZGQgdGhlIGluc3RhbGxhdGlvbiBmb2xkZXIgZm9yIFIgdG8geW91ciBwYXRoIG9yIHNwZWNpZnkgdGhlIGZ1bGwgcGF0aCB0byAqKlJTY3JpcHQvUioqLg0KDQpUaGUgZXhhbXBsZSBiZWxvdyBzaG93cyBob3cgdG8gZW1iZWQgYW4gUiBwcm9ncmFtIHdpdGhpbiBhIHNoZWxsIHNjcmlwdCBvbiBVbml4IChhbmQgTWFjT1MvTGludXgpLg0KDQpgYGB7YmFzaCBldmFsPUZ9DQojIS9iaW4vc2gNCg0KUnNjcmlwdCBTY3JpcHRBLlINCg0KYGBgDQoNCkFmdGVyIGNyZWF0aW5nIGEgbmV3IHNoZWxsIHNjcmlwdCwgZG9uJ3QgZm9yZ2V0IHRvIHNldCBleGVjdXRlIHBlcm1pc3Npb25zIG9uIHRoZSBmaWxlIHdpdGg6DQoNCmBgYHtiYXNoIGV2YWw9Rn0NCmNobW9kICt4IGFuYWx5emUNCmBgYA0KDQpUaGUgdmlkZW8gdHV0b3JpYWwgZGVtb25zdHJhdGVzIGhvdyB0byBydW4gYW4gUiBwcm9ncmFtIGZyb20gdGhlIGNvbW1hbmQgbGluZSBhbmQgd2l0aGluIHNoZWxsIHNjcmlwdHMuDQoNCmBgYHs9aHRtbH0NCjxpZnJhbWUgc3JjPSJodHRwczovL3BsYXllci52aW1lby5jb20vdmlkZW8vNzc4ODMzMTc0P2g9NmI0ZjkxMzE2OSZhbXA7YmFkZ2U9MCZhbXA7YXV0b3BhdXNlPTAmYW1wO3BsYXllcl9pZD0wJmFtcDthcHBfaWQ9NTg0NzkiIHdpZHRoPSIzNjAiIGhlaWdodD0iMjM3IiBmcmFtZWJvcmRlcj0iMSIgYWxsb3c9ImF1dG9wbGF5OyBmdWxsc2NyZWVuOyBwaWN0dXJlLWluLXBpY3R1cmUiIGFsbG93ZnVsbHNjcmVlbiB0aXRsZT0iUiBTY3JpcHRzIGZyb20gdGhlIENvbW1hbmQgTGluZSIgZGF0YS1leHRlcm5hbD0iMSI+PC9pZnJhbWU+DQpgYGANCiMjIE5lc3RpbmcgUiBTY3JpcHRzDQoNCllvdSBjYW4gImNhbGwiIG9yIHJ1biBhbm90aGVyIFIgU2NyaXB0IGZyb20gd2l0aGluIGFuIFIgU2NyaXB0IHVzaW5nIGVpdGhlciBgc291cmNlKClgIG9yIGBzeXMuc291cmNlKClgIGFzIHNob3duIGJlbG93Og0KDQpgYGB7ciBldmFsPUZ9DQpzb3VyY2UoImFub3RoZXItc2NyaXB0LlIiKQ0KYGBgDQoNCiMjIFByb2dyYW0gU3RydWN0dXJlDQoNClIgU2NyaXB0cyBhcmUgc2NyaXB0cyBpbiB0aGUgc2Vuc2UgdGhhdCB0aGV5IGFyZSBSIHN0YXRlbWVudHMgdGhhdCBhcmUgZXhlY3V0ZWQgbGluZS1ieS1saW5lIHN0YXJ0aW5nIHdpdGggdGhlIGZpcnN0IGxpbmUuIFRoZXJlIGlzIG5vICJlbnRyeSBwb2ludCIgbGlrZSBpbiBDIHdoZXJlIGV4ZWN1dGlvbiBzdGFydHMgYXQgdGhlIGZ1bmN0aW9uIGBtYWluKClgLiBIb3dldmVyLCB3ZSBjYW4gYWRvcHQgdGhhdCBzdHJ1Y3R1cmUgYnkgbWFraW5nIHRoZSBmaXJzdCBsaW5lIGEgY2FsbCB0byB0aGUgZnVuY3Rpb24gYG1haW4oKWAgYXMgc2hvd24gYmVsb3cgYW5kIHRoZW4gcGxhY2luZyBhbGwgY29kZSB3aXRoIGEgYG1haW4oKWAgZnVuY3Rpb24uDQoNCiMjIENvbmNsdXNpb24NCg0KUiBpcyBhIHBvd2VyZnVsIGRhdGEgbWFuaXB1bGF0aW9uIGFuZCBzdGF0aXN0aWNhbCBwcm9ncmFtbWluZyBsYW5ndWFnZSB0aGF0IGNhbiBiZSB1c2VkIHRvIGNyZWF0ZSBzdGFuZGFsb25lIHByb2dyYW1zLg0KDQotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KIyMgRmlsZXMgJiBSZXNvdXJjZXMNCg0KYGBge3IgemlwRmlsZXMsIGVjaG89RkFMU0V9DQp6aXBOYW1lID0gc3ByaW50ZigiTGVzc29uRmlsZXMtJXMtJXMuemlwIiwgDQogICAgICAgICAgICAgICAgIHBhcmFtcyRjYXRlZ29yeSwNCiAgICAgICAgICAgICAgICAgcGFyYW1zJG51bWJlcikNCg0KdGV4dEFMaW5rID0gcGFzdGUwKCJBbGwgRmlsZXMgZm9yIExlc3NvbiAiLCANCiAgICAgICAgICAgICAgIHBhcmFtcyRjYXRlZ29yeSwiLiIscGFyYW1zJG51bWJlcikNCg0KIyBkb3dubG9hZEZpbGVzTGluaygpIGlzIGluY2x1ZGVkIGZyb20gX2luc2VydDJEQi5SDQprbml0cjo6cmF3X2h0bWwoZG93bmxvYWRGaWxlc0xpbmsoIi4iLCB6aXBOYW1lLCB0ZXh0QUxpbmspKQ0KYGBgDQoNCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQojIyBSZWZlcmVuY2VzDQoNCk5vbmUuDQoNCiMjIEVycmF0YQ0KDQpOb25lIGNvbGxlY3RlZCB5ZXQuIExldCB1cyBrbm93Lg0KDQpgYGB7PWh0bWx9DQo8c2NyaXB0IHNyYz0iaHR0cHM6Ly9mb3JtLmpvdGZvcm0uY29tL3N0YXRpYy9mZWVkYmFjazIuanMiIHR5cGU9InRleHQvamF2YXNjcmlwdCI+DQogIG5ldyBKb3Rmb3JtRmVlZGJhY2soew0KICAgIGZvcm1JZDogIjIxMjE4NzA3Mjc4NDE1NyIsDQogICAgYnV0dG9uVGV4dDogIkZlZWRiYWNrIiwNCiAgICBiYXNlOiAiaHR0cHM6Ly9mb3JtLmpvdGZvcm0uY29tLyIsDQogICAgYmFja2dyb3VuZDogIiNGNTkyMDIiLA0KICAgIGZvbnRDb2xvcjogIiNGRkZGRkYiLA0KICAgIGJ1dHRvblNpZGU6ICJsZWZ0IiwNCiAgICBidXR0b25BbGlnbjogImNlbnRlciIsDQogICAgdHlwZTogZmFsc2UsDQogICAgd2lkdGg6IDcwMCwNCiAgICBoZWlnaHQ6IDUwMCwNCiAgICBpc0NhcmRGb3JtOiBmYWxzZQ0KICB9KTsNCjwvc2NyaXB0Pg0KYGBgDQpgYGB7ciBjb2RlPXhmdW46OnJlYWRfdXRmOChwYXN0ZTAoaGVyZTo6aGVyZSgpLCcvUi9fZGVwbG95S25pdC5SJykpLCBpbmNsdWRlID0gRkFMU0V9DQpgYGANCg==