Introduction

Build Website Website Website Website

This is a template for a data analysis folder that can be easily exported as a webpage or as Supplementary Materials (e.g., as a Word document or a PDF).

How does it look like? Just like this! The README page of this repository, alongside the webpage and the word and PDF documents, were all created from the index.Rmd file.

This means you can easily share your data analysis, either by attaching the PDF or Word file to the publication (as Supplementary Materials), or by directly providing the URL of your GitHub repository: the readers can then enjoy your awesome open-access work in a convenient and transparent way.

Features

Installation

  • What is this?

This repository is a template to set up a reproducible, convenient and shareable workflow for your data analysis. It consists of several Rmarkdown files (.Rmd), that allow you to have R code and text (markdown) in the same document. Importantly, these files can be transformed into other documents formats.

  • How to use this template?

Download it (click here to download), unzip it and edit. Alternatively, you click on the Use this template button at the top of this screen to create a GitHub repository with all the content copied (then you just need to clone the repo to your local machine).

The main files you need to edit are the .Rmd files, that you can open with some editor (e.g., Rstudio), and edit the text and the R chunks of code.

  • How to upload it to a website?

If your repo is not already connected to GitHub, then create a new repository and upload all the content (so that it looks like this repo). Then, go to settings of the repo and enable GitHub pages (i.e., that gives you a webpage from an html stored on GitHub), and select the docs/ folder as the location of the webpage. Indeed, rendering (knitting) the files will generate an “index.html” file in the /docs/ folder, which is used as the website. You can see an example at https://realitybending.github.io/TemplateResults/.

  • To knit or not to knit

In this repo, with have set up a GitHub action that generates all the output files everytime someone commit to the repository. This means that the final documents here are always “up-to-date” with the Rmds (as shown by the green badge). That said, you can remove this GitHub action (just remove the .github/workflows/website.yml file) if you prefer to generate the documents manually only.

  • But I don’t want do upload all my data

In that case, you’ll need to 1) deactivate (i.e., remove the action file) the automatic rendering by GitHub (as no data will be stored on GitHub) and 2) mark the data folder as “to be ignored” (so that it won’t be uploaded). This can be done by adding /data/ to the .gitignore file (that you can open with a notepad). This means that you can still store the data here locally, and generate the documents accordingly, but the data folder will be ignored by git and never uploaded to GitHub. This way, you can still have a cool website, an open-access script, but the data is safe with you. The only down side is that you have to build it manually (cannot use GitHub actions).

  • How to add references?

References have to be added in bib format in the utils/bibliography.bib file, and further referenced in the text like this [@ludecke2019insight] (Lüdecke, Waggoner, & Makowski, 2019).

  • I don’t like the Word (.docx) theme

The theme for the word document is defined in the **Template_Word.docx file, in the /utils/ folder. You need to edit the “styles” (not just the content, but the style itself) to your preference.

  • I have Python code

Thanks to R’s possibilities when it comes to integration with Python, it’s super easy to enable it in your pipeline. Just uncomment the Python installation line in the utils/config.R file and you’re ready to go!

  • It doesn’t work / I have questions / I have ideas

Just open an issue and we’ll be happy to assist ☺

Structure

Most files that you’ll need to create / edit will be written in rmarkdown, which consists of a mix of markdown text and R chunks of code.

The main file is named index.Rmd. However, to avoid having overly long files, the different (and independent) analyses parts are actually split in other documents. For instance, in this template example, the descriptive statistics section is in the 1_descriptive.Rmd file. As you can see in the index file, this file is then integrated as a child document (i.e., it is merged). This makes it very convenient to have a clear structure with well-organized files, that are put together only when merged.

Render and Publish

Importantly, in order to render all the files, do not Knit this document by pressing the ‘Knit’ button. If you do, it will create an output file (for instance index.html) in the root folder, alongside index.Rmd. This is not what we want, as we want to keep the output files tidy in separate folders (for instance, the html version should be in the /docs/ folder, as this is where the website will look for).

There an R script, utils/render.R, that contains the lines to render everything in its correct location. So, when you have the “index.Rmd” file opened (and your working directory is at its root), simply run source("utils/render.R") in the console (or the relevant lines in that file). This will run the rendering file and create all the files.

Contribution

Do not hesitate to improve this template by updating, documenting, or expanding it!

Packages & Data

Packages

This document was prepared on 2021-08-02.

library(bayestestR)
library(parameters)
library(performance)
library(report)
library(see)
library(ggplot2)

summary(report::report(sessionInfo()))

The analysis was done using the R Statistical language (v4.1.0; R Core Team, 2021) on macOS Catalina 10.15.7, using the packages ggplot2 (v3.3.5), stringr (v1.4.0), forcats (v0.5.1), tidyr (v1.1.3), readr (v2.0.0), dplyr (v1.0.7), rmarkdown (v2.9), tibble (v3.1.3), purrr (v0.3.4), parameters (v0.14.0.1), performance (v0.7.3.1), see (v0.6.4), bayestestR (v0.10.5), report (v0.3.5) and tidyverse (v1.3.1).

Data

df <- read.csv("data/data.csv")

cat(paste("The data consists of",
          report::report_participants(df,
                                      participants = "Participant",
                                      age = "Age")))

The data consists of 10 participants (Mean age = 29.9, SD = 0.5, range: [29.0, 30.91])

Note that the chunks generating figures in the code below have some arguments specified in their header, such as fig.width and fig.height, which controls the figure size. These were filled with an eponym argument defined in utils/config.R. We also set the resolution, i.e., dpi, to a low value so that the resulting file is lighter. But don’t forget to crank this value up (to 300-600) to get nice-looking results.

Descriptive Stats

Notice the {.tabset} tag after the section name. This will show the subsections as different tabs (in the html version only, because the other formats are static).

Part 1

Here’s a cool plot:

ggplot(df, aes(x=V1, y=V2, color=Participant)) + 
  geom_point() +
  see::theme_modern()

Part 2

That’s another great plot:

plot(bayestestR::estimate_density(df[c("V1", "V2")])) +
  see::theme_blackboard()

Part 3

Did you ever hear the tragedy of Darth Plagueis The Wise? I thought not. It’s not a story the Jedi would tell you. It’s a Sith legend. Darth Plagueis was a Dark Lord of the Sith, so powerful and so wise he could use the Force to influence the midichlorians to create life… He had such a knowledge of the dark side that he could even keep the ones he cared about from dying. The dark side of the Force is a pathway to many abilities some consider to be unnatural. He became so powerful… the only thing he was afraid of was losing his power, which eventually, of course, he did. Unfortunately, he taught his apprentice everything he knew, then his apprentice killed him in his sleep. Ironic. He could save others from death, but not himself.

Inferential Stats

Here is another analysis that is contained in a separate file. Let’s check-out this linear regression model (note that, in the code chunk parameters, I multiplied figheight by 2 to have a taller plot):

model <- lm(Petal.Length ~ Sepal.Length, data=iris)
performance::check_model(model)

Full Code

The full script of executive code contained in this document is reproduced here.

# Set up the environment (or use local alternative `source("utils/config.R")`)
source("https://raw.githubusercontent.com/RealityBending/TemplateResults/main/utils/config.R")  

fast <- FALSE  # Make this false to skip the chunks
# This chunk is a bit complex so don't worry about it: it's made to add badges to the HTML versions
# NOTE: You have to replace the links accordingly to have working "buttons" on the HTML versions
if (!knitr::is_latex_output() && knitr::is_html_output()) {
  cat("![Build](https://github.com/RealityBending/TemplateResults/workflows/Build/badge.svg)
      [![Website](https://img.shields.io/badge/repo-Readme-2196F3)](https://github.com/RealityBending/TemplateResults)
      [![Website](https://img.shields.io/badge/visit-website-E91E63)](https://realitybending.github.io/TemplateResults/)
      [![Website](https://img.shields.io/badge/download-.docx-FF5722)](https://github.com/RealityBending/TemplateResults/raw/main/word_and_pdf/SupplementaryMaterials.docx)
      [![Website](https://img.shields.io/badge/see-.pdf-FF9800)](https://github.com/RealityBending/TemplateResults/blob/main/word_and_pdf/SupplementaryMaterials.pdf)")
}
# Let's include a demo GIF (this doesn't work in PDF documents)
if (!knitr::is_latex_output()) {
  knitr::include_graphics("figures/demo.gif")
}
library(bayestestR)
library(parameters)
library(performance)
library(report)
library(see)
library(ggplot2)

summary(report::report(sessionInfo()))
df <- read.csv("data/data.csv")

cat(paste("The data consists of",
          report::report_participants(df,
                                      participants = "Participant",
                                      age = "Age")))
report::cite_packages(sessionInfo())
ggplot(df, aes(x=V1, y=V2, color=Participant)) + 
  geom_point() +
  see::theme_modern()
plot(bayestestR::estimate_density(df[c("V1", "V2")])) +
  see::theme_blackboard()
model <- lm(Petal.Length ~ Sepal.Length, data=iris)
performance::check_model(model)

Package References

report::cite_packages(sessionInfo())
  • H. Wickham. ggplot2: Elegant Graphics for Data Analysis. Springer-Verlag New York, 2016.
  • Hadley Wickham (2019). stringr: Simple, Consistent Wrappers for Common String Operations. R package version 1.4.0. https://CRAN.R-project.org/package=stringr
  • Hadley Wickham (2021). forcats: Tools for Working with Categorical Variables (Factors). R package version 0.5.1. https://CRAN.R-project.org/package=forcats
  • Hadley Wickham (2021). tidyr: Tidy Messy Data. R package version 1.1.3. https://CRAN.R-project.org/package=tidyr
  • Hadley Wickham and Jim Hester (2021). readr: Read Rectangular Text Data. R package version 2.0.0. https://CRAN.R-project.org/package=readr
  • Hadley Wickham, Romain François, Lionel Henry and Kirill Müller (2021). dplyr: A Grammar of Data Manipulation. R package version 1.0.7. https://CRAN.R-project.org/package=dplyr
  • JJ Allaire and Yihui Xie and Jonathan McPherson and Javier Luraschi and Kevin Ushey and Aron Atkins and Hadley Wickham and Joe Cheng and Winston Chang and Richard Iannone (2021). rmarkdown: Dynamic Documents for R. R package version 2.9. URL https://rmarkdown.rstudio.com.
  • Kirill Müller and Hadley Wickham (2021). tibble: Simple Data Frames. R package version 3.1.3. https://CRAN.R-project.org/package=tibble
  • Lionel Henry and Hadley Wickham (2020). purrr: Functional Programming Tools. R package version 0.3.4. https://CRAN.R-project.org/package=purrr
  • Lüdecke D, Ben-Shachar M, Patil I, Makowski D (2020). “Extracting,Computing and Exploring the Parameters of Statistical Models using R.”Journal of Open Source Software, 5(53), 2445. doi:10.21105/joss.02445 (URL: https://doi.org/10.21105/joss.02445).
  • Lüdecke et al., (2021). performance: An R Package for Assessment, Comparison and Testing of Statistical Models. Journal of Open Source Software, 6(60), 3139. https://doi.org/10.21105/joss.03139
  • Lüdecke, Patil, Ben-Shachar, Wiernik, Waggoner & Makowski (2020). Visualisation Toolbox for ‘easystats’ and Extra Geoms, Themes and Color Palettes for ‘ggplot2’. CRAN. Available from https://easystats.github.io/see/
  • Makowski, D., Ben-Shachar, M., & Lüdecke, D. (2019). bayestestR: Describing Effects and their Uncertainty, Existence and Significance within the Bayesian Framework. Journal of Open Source Software, 4(40), 1541. doi:10.21105/joss.01541
  • Makowski, D., Ben-Shachar, M.S., Patil, I. & Lüdecke, D. (2020). Automated Results Reporting as a Practical Tool to Improve Reproducibility and Methodological Best Practices Adoption. CRAN. Available from https://github.com/easystats/report. doi: .
  • R Core Team (2021). R: A language and environment for statistical computing. R Foundation for Statistical Computing, Vienna, Austria. URL https://www.R-project.org/.
  • Wickham et al., (2019). Welcome to the tidyverse. Journal of Open Source Software, 4(43), 1686, https://doi.org/10.21105/joss.01686

References

Lüdecke, D., Waggoner, P. D., & Makowski, D. (2019). Insight: A unified interface to access information from model objects in r. Journal of Open Source Software, 4(38), 1412.

LS0tCnRpdGxlOiAnKipSZXN1bHRzIFRlbXBsYXRlKionCnN1YnRpdGxlOiBBIFN1YnRpdGxlCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgdGhlbWU6IGNlcnVsZWFuCiAgICBoaWdobGlnaHQ6IHB5Z21lbnRzCiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiAzCiAgICB0b2NfZmxvYXQ6IHllcwogICAgbnVtYmVyX3NlY3Rpb25zOiBubwogICAgZGZfcHJpbnQ6IGthYmxlCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgIGNvZGVfZG93bmxvYWQ6IHllcwogIHdvcmRfZG9jdW1lbnQ6CiAgICByZWZlcmVuY2VfZG9jeDogdXRpbHMvVGVtcGxhdGVfV29yZC5kb2N4CiAgICBoaWdobGlnaHQ6IHB5Z21lbnRzCiAgICB0b2M6IG5vCiAgICB0b2NfZGVwdGg6IDMKICAgIGRmX3ByaW50OiBrYWJsZQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMKICBybWFya2Rvd246Omh0bWxfdmlnbmV0dGU6CiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiAzCiAgcGRmX2RvY3VtZW50OgogICAgdG9jOiB5ZXMKICAgIHRvY19kZXB0aDogJzInCiAgICBsYXRleF9lbmdpbmU6IHhlbGF0ZXgKZWRpdG9yX29wdGlvbnM6CiAgY2h1bmtfb3V0cHV0X3R5cGU6IGNvbnNvbGUKYmlibGlvZ3JhcGh5OiB1dGlscy9iaWJsaW9ncmFwaHkuYmliCmNzbDogdXRpbHMvYXBhLmNzbAotLS0KCgo8IS0tIAohISEhIElNUE9SVEFOVDogcnVuIGBzb3VyY2UoInV0aWxzL3JlbmRlci5SIilgIHRvIHB1Ymxpc2ggaW5zdGVhZCBvZiBjbGlja2luZyBvbiAnS25pdCcKLS0+CgpgYGB7ciBzZXR1cCwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1UUlVFLCBpbmNsdWRlPUZBTFNFfQojIFNldCB1cCB0aGUgZW52aXJvbm1lbnQgKG9yIHVzZSBsb2NhbCBhbHRlcm5hdGl2ZSBgc291cmNlKCJ1dGlscy9jb25maWcuUiIpYCkKc291cmNlKCJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vUmVhbGl0eUJlbmRpbmcvVGVtcGxhdGVSZXN1bHRzL21haW4vdXRpbHMvY29uZmlnLlIiKSAgCgpmYXN0IDwtIEZBTFNFICAjIE1ha2UgdGhpcyBmYWxzZSB0byBza2lwIHRoZSBjaHVua3MKYGBgCgojIEludHJvZHVjdGlvbgoKYGBge3IgYmFkZ2VzLCBlY2hvPUZBTFNFLCBtZXNzYWdlPVRSVUUsIHdhcm5pbmc9RkFMU0UsIHJlc3VsdHM9J2FzaXMnfQojIFRoaXMgY2h1bmsgaXMgYSBiaXQgY29tcGxleCBzbyBkb24ndCB3b3JyeSBhYm91dCBpdDogaXQncyBtYWRlIHRvIGFkZCBiYWRnZXMgdG8gdGhlIEhUTUwgdmVyc2lvbnMKIyBOT1RFOiBZb3UgaGF2ZSB0byByZXBsYWNlIHRoZSBsaW5rcyBhY2NvcmRpbmdseSB0byBoYXZlIHdvcmtpbmcgImJ1dHRvbnMiIG9uIHRoZSBIVE1MIHZlcnNpb25zCmlmICgha25pdHI6OmlzX2xhdGV4X291dHB1dCgpICYmIGtuaXRyOjppc19odG1sX291dHB1dCgpKSB7CiAgY2F0KCIhW0J1aWxkXShodHRwczovL2dpdGh1Yi5jb20vUmVhbGl0eUJlbmRpbmcvVGVtcGxhdGVSZXN1bHRzL3dvcmtmbG93cy9CdWlsZC9iYWRnZS5zdmcpCiAgICAgIFshW1dlYnNpdGVdKGh0dHBzOi8vaW1nLnNoaWVsZHMuaW8vYmFkZ2UvcmVwby1SZWFkbWUtMjE5NkYzKV0oaHR0cHM6Ly9naXRodWIuY29tL1JlYWxpdHlCZW5kaW5nL1RlbXBsYXRlUmVzdWx0cykKICAgICAgWyFbV2Vic2l0ZV0oaHR0cHM6Ly9pbWcuc2hpZWxkcy5pby9iYWRnZS92aXNpdC13ZWJzaXRlLUU5MUU2MyldKGh0dHBzOi8vcmVhbGl0eWJlbmRpbmcuZ2l0aHViLmlvL1RlbXBsYXRlUmVzdWx0cy8pCiAgICAgIFshW1dlYnNpdGVdKGh0dHBzOi8vaW1nLnNoaWVsZHMuaW8vYmFkZ2UvZG93bmxvYWQtLmRvY3gtRkY1NzIyKV0oaHR0cHM6Ly9naXRodWIuY29tL1JlYWxpdHlCZW5kaW5nL1RlbXBsYXRlUmVzdWx0cy9yYXcvbWFpbi93b3JkX2FuZF9wZGYvU3VwcGxlbWVudGFyeU1hdGVyaWFscy5kb2N4KQogICAgICBbIVtXZWJzaXRlXShodHRwczovL2ltZy5zaGllbGRzLmlvL2JhZGdlL3NlZS0ucGRmLUZGOTgwMCldKGh0dHBzOi8vZ2l0aHViLmNvbS9SZWFsaXR5QmVuZGluZy9UZW1wbGF0ZVJlc3VsdHMvYmxvYi9tYWluL3dvcmRfYW5kX3BkZi9TdXBwbGVtZW50YXJ5TWF0ZXJpYWxzLnBkZikiKQp9CmBgYAoKVGhpcyBpcyBhIHRlbXBsYXRlIGZvciBhIGRhdGEgYW5hbHlzaXMgZm9sZGVyIHRoYXQgY2FuIGJlIGVhc2lseSBleHBvcnRlZCBhcyBhIFsqKndlYnBhZ2UqKl0oaHR0cHM6Ly9yZWFsaXR5YmVuZGluZy5naXRodWIuaW8vVGVtcGxhdGVSZXN1bHRzLykgb3IgYXMgKipTdXBwbGVtZW50YXJ5IE1hdGVyaWFscyoqIChlLmcuLCBhcyBhIFsqKldvcmQgZG9jdW1lbnQqKl0oaHR0cHM6Ly9naXRodWIuY29tL1JlYWxpdHlCZW5kaW5nL1RlbXBsYXRlUmVzdWx0cy9yYXcvbWFpbi93b3JkX2FuZF9wZGYvU3VwcGxlbWVudGFyeU1hdGVyaWFscy5kb2N4KSBvciBhIFsqKlBERioqXShodHRwczovL2dpdGh1Yi5jb20vUmVhbGl0eUJlbmRpbmcvVGVtcGxhdGVSZXN1bHRzL2Jsb2IvbWFpbi93b3JkX2FuZF9wZGYvU3VwcGxlbWVudGFyeU1hdGVyaWFscy5wZGYpKS4KCkhvdyBkb2VzIGl0IGxvb2sgbGlrZT8gSnVzdCBsaWtlIHRoaXMhIFRoZSBSRUFETUUgcGFnZSBvZiB0aGlzIHJlcG9zaXRvcnksIGFsb25nc2lkZSB0aGUgW3dlYnBhZ2VdKGh0dHBzOi8vcmVhbGl0eWJlbmRpbmcuZ2l0aHViLmlvL1RlbXBsYXRlUmVzdWx0cy8pIGFuZCB0aGUgd29yZCBhbmQgUERGIGRvY3VtZW50cywgd2VyZSBhbGwgY3JlYXRlZCBmcm9tIHRoZSBbaW5kZXguUm1kXShodHRwczovL2dpdGh1Yi5jb20vUmVhbGl0eUJlbmRpbmcvVGVtcGxhdGVSZXN1bHRzL2Jsb2IvbWFpbi9pbmRleC5SbWQpIGZpbGUuCgpUaGlzIG1lYW5zIHlvdSBjYW4gZWFzaWx5ICoqc2hhcmUgeW91ciBkYXRhIGFuYWx5c2lzKiosIGVpdGhlciBieSBhdHRhY2hpbmcgdGhlICpQREYqIG9yICpXb3JkKiBmaWxlIHRvIHRoZSBwdWJsaWNhdGlvbiAoYXMgKipTdXBwbGVtZW50YXJ5IE1hdGVyaWFscyoqKSwgb3IgYnkgZGlyZWN0bHkgcHJvdmlkaW5nIHRoZSBVUkwgb2YgeW91ciBHaXRIdWIgcmVwb3NpdG9yeTogdGhlIHJlYWRlcnMgY2FuIHRoZW4gZW5qb3kgeW91ciBhd2Vzb21lIG9wZW4tYWNjZXNzIHdvcmsgaW4gYSBjb252ZW5pZW50IGFuZCB0cmFuc3BhcmVudCB3YXkuCgojIyBGZWF0dXJlcwoKLSBbeF0gQXV0b21hdGljYWxseSBnZW5lcmF0ZXMgZGlmZmVyZW50IHR5cGVzIG9mIGRvY3VtZW50OgogIC0gWyoqUkVBRE1FIHBhZ2UqKl0oaHR0cHM6Ly9naXRodWIuY29tL1JlYWxpdHlCZW5kaW5nL1RlbXBsYXRlUmVzdWx0cy9ibG9iL21haW4vUkVBRE1FLm1kKQogIC0gWyoqUHVibGlzaGVkIHdlYnNpdGUqKl0oaHR0cHM6Ly9yZWFsaXR5YmVuZGluZy5naXRodWIuaW8vVGVtcGxhdGVSZXN1bHRzLykKICAtIFsqKldvcmQgZG9jdW1lbnQqKl0oaHR0cHM6Ly9naXRodWIuY29tL1JlYWxpdHlCZW5kaW5nL1RlbXBsYXRlUmVzdWx0cy9yYXcvbWFpbi93b3JkX2FuZF9wZGYvU3VwcGxlbWVudGFyeU1hdGVyaWFscy5kb2N4KQogIC0gWyoqUERGIGRvY3VtZW50KipdKGh0dHBzOi8vZ2l0aHViLmNvbS9SZWFsaXR5QmVuZGluZy9UZW1wbGF0ZVJlc3VsdHMvYmxvYi9tYWluL3dvcmRfYW5kX3BkZi9TdXBwbGVtZW50YXJ5TWF0ZXJpYWxzLnBkZikKLSBbeF0gQVBBIGNpdGF0aW9ucwotIFt4XSBBdXRvbWF0aWMgY2l0YXRpb25zIGFuZCBbcmVmZXJlbmNlIGxpc3RdKGh0dHBzOi8vZ2l0aHViLmNvbS9SZWFsaXR5QmVuZGluZy9UZW1wbGF0ZVJlc3VsdHMjcGFja2FnZS1yZWZlcmVuY2VzKSBmb3IgYWxsIHBhY2thZ2VzCi0gW3hdIFRpZHkgb3JnYW5pc2F0aW9uIChzZXBhcmF0ZSBmaWxlcyBmb3IgaW5kZXBlbmRlbnQgYW5hbHlzZXMpCi0gW3hdIEdyZWF0IGRlZmF1bHQgY29uZmlndXJhdGlvbgotIFt4XSBBbmQgbW9yZSEKCmBgYHtyIGRlbW9fZ2lmLCBlY2hvPUZBTFNFLCBtZXNzYWdlPVRSVUUsIHdhcm5pbmc9RkFMU0V9CiMgTGV0J3MgaW5jbHVkZSBhIGRlbW8gR0lGICh0aGlzIGRvZXNuJ3Qgd29yayBpbiBQREYgZG9jdW1lbnRzKQppZiAoIWtuaXRyOjppc19sYXRleF9vdXRwdXQoKSkgewogIGtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJmaWd1cmVzL2RlbW8uZ2lmIikKfQpgYGAKCgojIyBJbnN0YWxsYXRpb24KCi0gKipXaGF0IGlzIHRoaXM/KioKClRoaXMgcmVwb3NpdG9yeSBpcyBhIHRlbXBsYXRlIHRvIHNldCB1cCBhIHJlcHJvZHVjaWJsZSwgY29udmVuaWVudCBhbmQgc2hhcmVhYmxlIHdvcmtmbG93IGZvciB5b3VyIGRhdGEgYW5hbHlzaXMuIEl0IGNvbnNpc3RzIG9mIHNldmVyYWwgWypSbWFya2Rvd24qXShodHRwczovL3JtYXJrZG93bi5yc3R1ZGlvLmNvbS9sZXNzb24tMS5odG1sKSBmaWxlcyAoYC5SbWRgKSwgdGhhdCBhbGxvdyB5b3UgdG8gaGF2ZSBSIGNvZGUgYW5kIHRleHQgKG1hcmtkb3duKSBpbiB0aGUgc2FtZSBkb2N1bWVudC4gSW1wb3J0YW50bHksIHRoZXNlIGZpbGVzIGNhbiBiZSB0cmFuc2Zvcm1lZCBpbnRvIG90aGVyIGRvY3VtZW50cyBmb3JtYXRzLgoKLSAqKkhvdyB0byB1c2UgdGhpcyB0ZW1wbGF0ZT8qKgoKRG93bmxvYWQgaXQgKFsqKmNsaWNrIGhlcmUgdG8gZG93bmxvYWQqKl0oaHR0cHM6Ly9naXRodWIuY29tL1JlYWxpdHlCZW5kaW5nL1RlbXBsYXRlUmVzdWx0cy9hcmNoaXZlL21haW4uemlwKSksIHVuemlwIGl0IGFuZCBlZGl0LgpBbHRlcm5hdGl2ZWx5LCB5b3UgY2xpY2sgb24gdGhlIFsqKlVzZSB0aGlzIHRlbXBsYXRlKipdKGh0dHBzOi8vZ2l0aHViLmNvbS9SZWFsaXR5QmVuZGluZy9UZW1wbGF0ZVJlc3VsdHMvZ2VuZXJhdGUpIGJ1dHRvbiBhdCB0aGUgdG9wIG9mIHRoaXMgc2NyZWVuIHRvIGNyZWF0ZSBhIEdpdEh1YiByZXBvc2l0b3J5IHdpdGggYWxsIHRoZSBjb250ZW50IGNvcGllZCAodGhlbiB5b3UganVzdCBuZWVkIHRvIGNsb25lIHRoZSByZXBvIHRvIHlvdXIgbG9jYWwgbWFjaGluZSkuCgpUaGUgbWFpbiBmaWxlcyB5b3UgbmVlZCB0byBlZGl0IGFyZSB0aGUgYC5SbWRgIGZpbGVzLCB0aGF0IHlvdSBjYW4gb3BlbiB3aXRoIHNvbWUgZWRpdG9yIChlLmcuLCBbUnN0dWRpb10oaHR0cHM6Ly9yc3R1ZGlvLmNvbS8pKSwgYW5kIGVkaXQgdGhlIHRleHQgYW5kIHRoZSBSIGNodW5rcyBvZiBjb2RlLgoKCi0gKipIb3cgdG8gdXBsb2FkIGl0IHRvIGEgd2Vic2l0ZT8qKgoKSWYgeW91ciByZXBvIGlzIG5vdCBhbHJlYWR5IGNvbm5lY3RlZCB0byBHaXRIdWIsIHRoZW4gY3JlYXRlIGEgbmV3IHJlcG9zaXRvcnkgYW5kIHVwbG9hZCBhbGwgdGhlIGNvbnRlbnQgKHNvIHRoYXQgaXQgbG9va3MgbGlrZSB0aGlzIHJlcG8pLiBUaGVuLCBnbyB0byBzZXR0aW5ncyBvZiB0aGUgcmVwbyBhbmQgZW5hYmxlICoqR2l0SHViIHBhZ2VzKiogKGkuZS4sIHRoYXQgZ2l2ZXMgeW91IGEgd2VicGFnZSBmcm9tIGFuIGh0bWwgc3RvcmVkIG9uIEdpdEh1YiksIGFuZCBzZWxlY3QgdGhlIGBkb2NzL2AgZm9sZGVyIGFzIHRoZSBsb2NhdGlvbiBvZiB0aGUgd2VicGFnZS4gSW5kZWVkLCByZW5kZXJpbmcgKGtuaXR0aW5nKSB0aGUgZmlsZXMgd2lsbCBnZW5lcmF0ZSBhbiAiaW5kZXguaHRtbCIgZmlsZSBpbiB0aGUgYC9kb2NzL2AgZm9sZGVyLCB3aGljaCBpcyB1c2VkIGFzIHRoZSB3ZWJzaXRlLiBZb3UgY2FuIHNlZSBhbiBleGFtcGxlIGF0IFtodHRwczovL3JlYWxpdHliZW5kaW5nLmdpdGh1Yi5pby9UZW1wbGF0ZVJlc3VsdHMvXShodHRwczovL3JlYWxpdHliZW5kaW5nLmdpdGh1Yi5pby9UZW1wbGF0ZVJlc3VsdHMvKS4KCi0gKipUbyBrbml0IG9yIG5vdCB0byBrbml0KioKCkluIHRoaXMgcmVwbywgd2l0aCBoYXZlIHNldCB1cCBhIFtHaXRIdWIgYWN0aW9uXShodHRwczovL2dpdGh1Yi5jb20vUmVhbGl0eUJlbmRpbmcvVGVtcGxhdGVSZXN1bHRzL2Jsb2IvbWFpbi8uZ2l0aHViL3dvcmtmbG93cy93ZWJzaXRlLnltbCkgdGhhdCBnZW5lcmF0ZXMgYWxsIHRoZSBvdXRwdXQgZmlsZXMgZXZlcnl0aW1lIHNvbWVvbmUgY29tbWl0IHRvIHRoZSByZXBvc2l0b3J5LiBUaGlzIG1lYW5zIHRoYXQgdGhlIGZpbmFsIGRvY3VtZW50cyBoZXJlIGFyZSBhbHdheXMgInVwLXRvLWRhdGUiIHdpdGggdGhlICpSbWRzKiAoYXMgc2hvd24gYnkgdGhlIGdyZWVuIGJhZGdlKS4gVGhhdCBzYWlkLCB5b3UgY2FuIHJlbW92ZSB0aGlzIEdpdEh1YiBhY3Rpb24gKGp1c3QgcmVtb3ZlIHRoZSBgLmdpdGh1Yi93b3JrZmxvd3Mvd2Vic2l0ZS55bWxgIGZpbGUpIGlmIHlvdSBwcmVmZXIgdG8gZ2VuZXJhdGUgdGhlIGRvY3VtZW50cyBtYW51YWxseSBvbmx5LgoKLSAqKkJ1dCBJIGRvbid0IHdhbnQgZG8gdXBsb2FkIGFsbCBteSBkYXRhKioKCkluIHRoYXQgY2FzZSwgeW91J2xsIG5lZWQgdG8gMSkgZGVhY3RpdmF0ZSAoaS5lLiwgcmVtb3ZlIHRoZSBhY3Rpb24gZmlsZSkgdGhlIGF1dG9tYXRpYyByZW5kZXJpbmcgYnkgR2l0SHViIChhcyBubyBkYXRhIHdpbGwgYmUgc3RvcmVkIG9uIEdpdEh1YikgYW5kIDIpIG1hcmsgdGhlICoqZGF0YSoqIGZvbGRlciBhcyAidG8gYmUgaWdub3JlZCIgKHNvIHRoYXQgaXQgd29uJ3QgYmUgdXBsb2FkZWQpLiBUaGlzIGNhbiBiZSBkb25lIGJ5IGFkZGluZyBgL2RhdGEvYCB0byB0aGUgWyoqLmdpdGlnbm9yZSoqXShodHRwczovL2dpdGh1Yi5jb20vUmVhbGl0eUJlbmRpbmcvVGVtcGxhdGVSZXN1bHRzL2Jsb2IvbWFpbi8uZ2l0aWdub3JlKSBmaWxlICh0aGF0IHlvdSBjYW4gb3BlbiB3aXRoIGEgbm90ZXBhZCkuIFRoaXMgbWVhbnMgdGhhdCB5b3UgY2FuIHN0aWxsIHN0b3JlIHRoZSBkYXRhIGhlcmUgbG9jYWxseSwgYW5kIGdlbmVyYXRlIHRoZSBkb2N1bWVudHMgYWNjb3JkaW5nbHksIGJ1dCB0aGUgZGF0YSBmb2xkZXIgd2lsbCBiZSBpZ25vcmVkIGJ5IGdpdCBhbmQgbmV2ZXIgdXBsb2FkZWQgdG8gR2l0SHViLiBUaGlzIHdheSwgeW91IGNhbiBzdGlsbCBoYXZlIGEgY29vbCB3ZWJzaXRlLCBhbiBvcGVuLWFjY2VzcyBzY3JpcHQsIGJ1dCB0aGUgZGF0YSBpcyBzYWZlIHdpdGggeW91LiBUaGUgb25seSBkb3duIHNpZGUgaXMgdGhhdCB5b3UgaGF2ZSB0byBidWlsZCBpdCBtYW51YWxseSAoY2Fubm90IHVzZSBHaXRIdWIgYWN0aW9ucykuCgotICoqSG93IHRvIGFkZCByZWZlcmVuY2VzPyoqCgpSZWZlcmVuY2VzIGhhdmUgdG8gYmUgYWRkZWQgaW4gYGJpYmAgZm9ybWF0IGluIHRoZSBbKnV0aWxzL2JpYmxpb2dyYXBoeS5iaWIqXShodHRwczovL2dpdGh1Yi5jb20vUmVhbGl0eUJlbmRpbmcvVGVtcGxhdGVSZXN1bHRzL2Jsb2IvbWFpbi91dGlscy9iaWJsaW9ncmFwaHkuYmliKSBmaWxlLCBhbmQgZnVydGhlciByZWZlcmVuY2VkIGluIHRoZSB0ZXh0IGxpa2UgdGhpcyBgW0BsdWRlY2tlMjAxOWluc2lnaHRdYCBbQGx1ZGVja2UyMDE5aW5zaWdodF0uCgotICoqSSBkb24ndCBsaWtlIHRoZSBXb3JkICguZG9jeCkgdGhlbWUqKgoKVGhlIHRoZW1lIGZvciB0aGUgd29yZCBkb2N1bWVudCBpcyBkZWZpbmVkIGluIHRoZSBbKipUZW1wbGF0ZV9Xb3JkLmRvY3hdKGh0dHBzOi8vZ2l0aHViLmNvbS9SZWFsaXR5QmVuZGluZy9UZW1wbGF0ZVJlc3VsdHMvdHJlZS9tYWluL3V0aWxzKSBmaWxlLCBpbiB0aGUgYC91dGlscy9gIGZvbGRlci4gWW91IG5lZWQgdG8gZWRpdCB0aGUgInN0eWxlcyIgKG5vdCBqdXN0IHRoZSBjb250ZW50LCBidXQgdGhlIHN0eWxlIGl0c2VsZikgdG8geW91ciBwcmVmZXJlbmNlLgoKLSAqKkkgaGF2ZSBQeXRob24gY29kZSoqCgpUaGFua3MgdG8gUidzIHBvc3NpYmlsaXRpZXMgd2hlbiBpdCBjb21lcyB0byBpbnRlZ3JhdGlvbiB3aXRoIFB5dGhvbiwgaXQncyBzdXBlciBlYXN5IHRvIGVuYWJsZSBpdCBpbiB5b3VyIHBpcGVsaW5lLiBKdXN0IHVuY29tbWVudCB0aGUgW1B5dGhvbiBpbnN0YWxsYXRpb24gbGluZV0oaHR0cHM6Ly9naXRodWIuY29tL1JlYWxpdHlCZW5kaW5nL1RlbXBsYXRlUmVzdWx0cy9ibG9iL21haW4vdXRpbHMvY29uZmlnLlIjTDI0KSBpbiB0aGUgYHV0aWxzL2NvbmZpZy5SYCBmaWxlIGFuZCB5b3UncmUgcmVhZHkgdG8gZ28hCgotICoqSXQgZG9lc24ndCB3b3JrIC8gSSBoYXZlIHF1ZXN0aW9ucyAvIEkgaGF2ZSBpZGVhcyoqCgpKdXN0IFsqKm9wZW4gYW4gaXNzdWUqKl0oaHR0cHM6Ly9naXRodWIuY29tL1JlYWxpdHlCZW5kaW5nL1RlbXBsYXRlUmVzdWx0cy9pc3N1ZXMpIGFuZCB3ZSdsbCBiZSBoYXBweSB0byBhc3Npc3Qg4pi6CgojIyBTdHJ1Y3R1cmUKCk1vc3QgZmlsZXMgdGhhdCB5b3UnbGwgbmVlZCB0byBjcmVhdGUgLyBlZGl0IHdpbGwgYmUgd3JpdHRlbiBpbiBbKipybWFya2Rvd24qKl0oaHR0cHM6Ly9ybWFya2Rvd24ucnN0dWRpby5jb20vbGVzc29uLTEuaHRtbCksIHdoaWNoIGNvbnNpc3RzIG9mIGEgbWl4IG9mIG1hcmtkb3duIHRleHQgYW5kIFIgY2h1bmtzIG9mIGNvZGUuCgpUaGUgbWFpbiBmaWxlIGlzIG5hbWVkIFsqKmluZGV4LlJtZCoqXShodHRwczovL2dpdGh1Yi5jb20vUmVhbGl0eUJlbmRpbmcvVGVtcGxhdGVSZXN1bHRzL2Jsb2IvbWFpbi9pbmRleC5SbWQpLiBIb3dldmVyLCB0byBhdm9pZCBoYXZpbmcgb3Zlcmx5IGxvbmcgZmlsZXMsIHRoZSBkaWZmZXJlbnQgKGFuZCBpbmRlcGVuZGVudCkgYW5hbHlzZXMgcGFydHMgYXJlIGFjdHVhbGx5IHNwbGl0IGluIG90aGVyIGRvY3VtZW50cy4gRm9yIGluc3RhbmNlLCBpbiB0aGlzIHRlbXBsYXRlIGV4YW1wbGUsIHRoZSBkZXNjcmlwdGl2ZSBzdGF0aXN0aWNzIHNlY3Rpb24gaXMgaW4gdGhlIFsqKjFfZGVzY3JpcHRpdmUuUm1kKipdKGh0dHBzOi8vZ2l0aHViLmNvbS9SZWFsaXR5QmVuZGluZy9UZW1wbGF0ZVJlc3VsdHMvYmxvYi9tYWluLzFfZGVzY3JpcHRpdmUuUm1kKSBmaWxlLiBBcyB5b3UgY2FuIFtzZWUgaW4gdGhlIGluZGV4IGZpbGVdKGh0dHBzOi8vZ2l0aHViLmNvbS9SZWFsaXR5QmVuZGluZy9UZW1wbGF0ZVJlc3VsdHMvYmxvYi82OTBmNzk0N2RhMGZjOGFjODVlYWY2ZmI4N2ZhZmVhYTQ2ZmIzYzUwL2luZGV4LlJtZCNMODktTDkwKSwgdGhpcyBmaWxlIGlzIHRoZW4gaW50ZWdyYXRlZCBhcyBhIGNoaWxkIGRvY3VtZW50IChpLmUuLCBpdCBpcyBtZXJnZWQpLiBUaGlzIG1ha2VzIGl0IHZlcnkgY29udmVuaWVudCB0byBoYXZlIGEgY2xlYXIgc3RydWN0dXJlIHdpdGggd2VsbC1vcmdhbml6ZWQgZmlsZXMsIHRoYXQgYXJlIHB1dCB0b2dldGhlciBvbmx5IHdoZW4gbWVyZ2VkLgoKIyMgUmVuZGVyIGFuZCBQdWJsaXNoCgpJbXBvcnRhbnRseSwgaW4gb3JkZXIgdG8gcmVuZGVyIGFsbCB0aGUgZmlsZXMsIGRvIG5vdCBLbml0IHRoaXMgZG9jdW1lbnQgYnkgcHJlc3NpbmcgdGhlICdLbml0JyBidXR0b24uIElmIHlvdSBkbywgaXQgd2lsbCBjcmVhdGUgYW4gb3V0cHV0IGZpbGUgKGZvciBpbnN0YW5jZSBgaW5kZXguaHRtbGApIGluIHRoZSByb290IGZvbGRlciwgYWxvbmdzaWRlIGBpbmRleC5SbWRgLiBUaGlzIGlzICoqbm90IHdoYXQgd2Ugd2FudCoqLCBhcyB3ZSB3YW50IHRvIGtlZXAgdGhlIG91dHB1dCBmaWxlcyB0aWR5IGluIHNlcGFyYXRlIGZvbGRlcnMgKGZvciBpbnN0YW5jZSwgdGhlIGh0bWwgdmVyc2lvbiBzaG91bGQgYmUgaW4gdGhlIGAvZG9jcy9gIGZvbGRlciwgYXMgdGhpcyBpcyB3aGVyZSB0aGUgd2Vic2l0ZSB3aWxsIGxvb2sgZm9yKS4KClRoZXJlIGFuIFIgc2NyaXB0LCBbdXRpbHMvcmVuZGVyLlJdKGh0dHBzOi8vZ2l0aHViLmNvbS9SZWFsaXR5QmVuZGluZy9UZW1wbGF0ZVJlc3VsdHMvYmxvYi9tYWluL3V0aWxzL3JlbmRlci5SKSwgdGhhdCBjb250YWlucyB0aGUgbGluZXMgdG8gcmVuZGVyIGV2ZXJ5dGhpbmcgaW4gaXRzIGNvcnJlY3QgbG9jYXRpb24uIFNvLCB3aGVuIHlvdSBoYXZlIHRoZSAiaW5kZXguUm1kIiBmaWxlIG9wZW5lZCAoYW5kIHlvdXIgd29ya2luZyBkaXJlY3RvcnkgaXMgYXQgaXRzIHJvb3QpLCBzaW1wbHkgcnVuICoqYHNvdXJjZSgidXRpbHMvcmVuZGVyLlIiKWAqKiBpbiB0aGUgY29uc29sZSAob3IgdGhlIHJlbGV2YW50IGxpbmVzIGluIHRoYXQgZmlsZSkuIFRoaXMgd2lsbCBydW4gdGhlIHJlbmRlcmluZyBmaWxlIGFuZCBjcmVhdGUgYWxsIHRoZSBmaWxlcy4KCiMjIENvbnRyaWJ1dGlvbgoKRG8gbm90IGhlc2l0YXRlIHRvIGltcHJvdmUgdGhpcyB0ZW1wbGF0ZSBieSB1cGRhdGluZywgZG9jdW1lbnRpbmcsIG9yIGV4cGFuZGluZyBpdCEKCgojIFBhY2thZ2VzICYgRGF0YQoKIyMgUGFja2FnZXMKClRoaXMgZG9jdW1lbnQgd2FzIHByZXBhcmVkIG9uIGByIGZvcm1hdChTeXMuRGF0ZSgpKWAuIAoKYGBge3Igd2FybmluZz1GQUxTRSwgbWVzc2FnZT1UUlVFLCByZXN1bHRzPSdhc2lzJ30KbGlicmFyeShiYXllc3Rlc3RSKQpsaWJyYXJ5KHBhcmFtZXRlcnMpCmxpYnJhcnkocGVyZm9ybWFuY2UpCmxpYnJhcnkocmVwb3J0KQpsaWJyYXJ5KHNlZSkKbGlicmFyeShnZ3Bsb3QyKQoKc3VtbWFyeShyZXBvcnQ6OnJlcG9ydChzZXNzaW9uSW5mbygpKSkKYGBgCgoKIyMgRGF0YQoKYGBge3Igd2FybmluZz1GQUxTRSwgbWVzc2FnZT1UUlVFLCByZXN1bHRzPSdhc2lzJ30KZGYgPC0gcmVhZC5jc3YoImRhdGEvZGF0YS5jc3YiKQoKY2F0KHBhc3RlKCJUaGUgZGF0YSBjb25zaXN0cyBvZiIsCiAgICAgICAgICByZXBvcnQ6OnJlcG9ydF9wYXJ0aWNpcGFudHMoZGYsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFydGljaXBhbnRzID0gIlBhcnRpY2lwYW50IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZ2UgPSAiQWdlIikpKQpgYGAKCgoKTm90ZSB0aGF0IHRoZSBjaHVua3MgZ2VuZXJhdGluZyBmaWd1cmVzIGluIHRoZSBjb2RlIGJlbG93IGhhdmUgc29tZSBhcmd1bWVudHMgc3BlY2lmaWVkIGluIHRoZWlyIGhlYWRlciwgc3VjaCBhcyBgZmlnLndpZHRoYCBhbmQgYGZpZy5oZWlnaHRgLCB3aGljaCBjb250cm9scyB0aGUgZmlndXJlIHNpemUuIFRoZXNlIHdlcmUgZmlsbGVkIHdpdGggYW4gZXBvbnltIGFyZ3VtZW50IGRlZmluZWQgaW4gW2B1dGlscy9jb25maWcuUmBdKGh0dHBzOi8vZ2l0aHViLmNvbS9SZWFsaXR5QmVuZGluZy9UZW1wbGF0ZVJlc3VsdHMvYmxvYi9tYWluL3V0aWxzL2NvbmZpZy5SI0wyNi1MMjcpLiBXZSBhbHNvIHNldCB0aGUgcmVzb2x1dGlvbiwgaS5lLiwgYGRwaWAsIHRvIGEgbG93IHZhbHVlIHNvIHRoYXQgdGhlIHJlc3VsdGluZyBmaWxlIGlzIGxpZ2h0ZXIuIEJ1dCAqKmRvbid0IGZvcmdldCB0byBjcmFuayB0aGlzIHZhbHVlIHVwKiogKHRvIDMwMC02MDApIHRvIGdldCBuaWNlLWxvb2tpbmcgcmVzdWx0cy4KCgojIERlc2NyaXB0aXZlIFN0YXRzIHsudGFic2V0fQoKTm90aWNlIHRoZSBgey50YWJzZXR9YCB0YWcgYWZ0ZXIgdGhlIHNlY3Rpb24gbmFtZS4gVGhpcyB3aWxsIHNob3cgdGhlIHN1YnNlY3Rpb25zIGFzIGRpZmZlcmVudCB0YWJzIChpbiB0aGUgW2h0bWwgdmVyc2lvbl0oaHR0cHM6Ly9yZWFsaXR5YmVuZGluZy5naXRodWIuaW8vVGVtcGxhdGVSZXN1bHRzLyNEZXNjcmlwdGl2ZV9TdGF0cykgb25seSwgYmVjYXVzZSB0aGUgb3RoZXIgZm9ybWF0cyBhcmUgc3RhdGljKS4KCgpgYGB7ciBjaGlsZD1pZiAoZmFzdCA9PSBGQUxTRSkgJzFfZGVzY3JpcHRpdmUuUm1kJ30KYGBgCgojIEluZmVyZW50aWFsIFN0YXRzCgpgYGB7ciBjaGlsZD1pZiAoZmFzdCA9PSBGQUxTRSkgJzJfaW5mZXJlbnRpYWwuUm1kJ30KYGBgCgoKIyBGdWxsIENvZGUKClRoZSBmdWxsIHNjcmlwdCBvZiBleGVjdXRpdmUgY29kZSBjb250YWluZWQgaW4gdGhpcyBkb2N1bWVudCBpcyByZXByb2R1Y2VkIGhlcmUuCgpgYGB7ciBmdWxsX2NvZGUsIHJlZi5sYWJlbD1rbml0cjo6YWxsX2xhYmVscygpLCBldmFsPUZBTFNFfQpgYGAKCiMgUGFja2FnZSBSZWZlcmVuY2VzCgpgYGB7ciB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCByZXN1bHRzPSdhc2lzJ30KcmVwb3J0OjpjaXRlX3BhY2thZ2VzKHNlc3Npb25JbmZvKCkpCmBgYAoKCiMgUmVmZXJlbmNlcwo=