Themes

  1. Is there a reproducibility crisis?
  2. What is reproducible psychological science?
  3. How can R make my science more transparent, open, and reproducible?

Is there a reproducibility crisis?


Not just in psychology



Here are the data from the Nature survey.

(Munafò et al. 2017) manifesto

This recent manifesto from Nature Human Behavior describes the risks to reproducible science at every step of the process. I urge you to read it.

What am I trying to reproduce?

  • My own workflow
    • Data collection
    • Cleaning
    • Visualization
    • Analysis
    • Reporting
    • Manuscript generation?
  • “Hit by a truck” scenario

But today I want us to think more parochially about our own workflows. How can using R make our own data collection, cleaning, visualization, and analysis workflows more reproducible. Ask yourself this: Can you pick up where you left off on a project you were working on yesterday? Last week? Last month? Six months ago? Put it this way: If you were hit by a truck tomorrow, could your adviser and collaborators pick up where you left off?

Reproducible workflows

  • Scripted, automated = minimize human-dependent steps.
  • Well-documented
  • Be kind to your future (forgetful) self
  • Transparent to me & colleagues == transparent to others

Reproducible workflows are scripted. They minimize human contact with your data files. They are well-documented. And it turns out that workflows that are transparent to you and your colleagues are transparent to others. This makes them easy to share.

Using R for reproducible workflows

  • Option 1: All commands in an R script: e.g., project_analysis.R
  • Option 2a: Mix R code, output, comments in an R Markdown document
  • Option 2b: Use R scripts with some special formatting, (more info).

We’ve already shown you in this bootcamp how writing R scripts and functions can let you import, clean, munge, reorganize, plot, and analyze data. We’ve already seen how commenting code fragments makes it easier to read and understand. An extension to R called R Markdown lets us mix R code, analyses, text, tables, and other formatting to make all sorts of products. R Markdown files are just text files. But with this one text file, it’s easy to produce multiple output types: PDF or Word formatted documents; HTML for blogs, web sites, or even slide presentation.

Example 1

# Import data

# Clean data

# Visualize data

# Analyze data

# Report findings

# Import data
my_data <- read.csv("path/2/data_file.csv")

# Clean data
my_data$gender <- tolower(my_data$gender) # make lower case
...

Make script that calls sequence of R commands or functions

# Import data
source("R/Import_data.R") # source() runs scripts, loads functions

# Clean data
source("R/Clean_data.R")

# Visualize data
source("R/Visualize_data.R")
...

Strengths & Weaknesses

  • R commands in files that can be re-run
  • Separate pieces of workflow kept separate
  • “Master.R” script that can be run to regenerate full sequence of results
    • Error in raw data file?
    • No problem; fix and re-run “Master.R”
  • How to save results or share with collaborators?

Example 2 - R Markdown

Just to show you how easy this is, let’s look at the R syntax James used yesterday. I’m going to show you how adding just a tiny bit of text to that file transforms it. Here is the original R script. Here is the transformed file with a .Rmd extension.

Structure of an R Markdown .Rmd file

One R to rule them all and in the console bind them…

Your turn

  1. Open “File/New File/R Notebook”
  2. Change title: "R Notebook" to something else, like title: "Rick's R Notebook"
  3. Save the file (default name is Untitled) with an .Rmd extension.
  4. Look at the *.Rmd code.
  5. Look at the *.nb.html file in a browser.

Things to try if you like

# Big idea

## Smaller idea in service of bigger

- Supporting point
- Another suppporting point

1. an enumerated **bold** point
1. an enumerated *italicized* point

- a [link](http://psu-psychology.github.io/r-bootcamp) to this bootcamp
- an image: ![rawr](https://www.insidehighered.com/sites/default/server_files/media/PennState2.PNG)
- an equation: $e = mc^2$

Big idea

Smaller idea in service of bigger

  • Supporting point
  • Another suppporting point
  • a bold point
  • an italicized point

  • a link to this bootcamp
  • an image: rawr
  • an equation: \(e = mc^2\)

Let’s try it with some data

One file, many output options

  • ‘Default’ for the file: rmarkdown::render("talks/bootcamp-survey.Rmd")
  • PDF document: rmarkdown::render('talks/bootcamp-survey.Rmd', output_format = "pdf_document")
  • Word document: rmarkdown::render('talks/bootcamp-survey.Rmd', output_format = "word_document")

  • HTML slides: rmarkdown::render('talks/bootcamp-survey.Rmd', output_format = "ioslides_presentation")
  • Multiple outputs: rmarkdown::render('talks/bootcamp-survey.Rmd', output_format = c("pdf_document", "word_document", "github_document", "ioslides_presentation")

Key points

  • Use R scripts to capture & reproduce workflows and/or
  • Use R Markdown files for documents, reports, presentations.
    • One or more output formats from the same file.
    • Analysis/lab notebook.

  • Use R scripts or functions to automate different pieces of the pipeline.
  • Make README files to explain how to put pieces together.

Toward a reproducible psychological science…

  • Transparent, reproducible, open workflows pre-publication
  • Openly shared materials + data + code
  • (Munafò et al. 2017): reproducible practices across the workflow
    • Where to share and when? Lots of options. Let’s talk.
  • (Gilmore and Adolph 2017): video and reproducibility

Advanced topics

R Studio Projects

  • Keep files, settings, organized
  • Easy to switch between projects
  • Reduces mental effort (what directory am I in?)
  • Integrates with version control (e.g., GitHub)

Version control

  • Keep track of your past
  • Back to the Future
  • git: a system for software version control
  • GitHub: a website for managing projects that use git

My GitHub workflow

  1. Create a repo on GitHub
  2. Copy repo URL
  3. File/New Project.../
  4. Version Control, Git
  5. Paste repo URL
  6. Select local name for repo and directory where it lives.
  7. Open project within R Studio File/Open Project...
  8. Commit early & often


Scripting the pipeline

# Get_bootcamp_googlesheet.R
# 
# Script to authenticate to Google, extract R bootcamp survey data

library(googlesheets)
library(tidyverse)

survey_url <- "https://docs.google.com/spreadsheets/d/1Ay56u6g4jyEEdlmV2NHxTLBlcjI2gHavta-Ik0kGrpg/edit?usp=sharing"

bootcamp_by_url <- survey_url %>%
  extract_key_from_url() %>%
  gs_key()

bootcamp_sheets <- gs_ws_ls(bootcamp_by_url)

boot_data <- bootcamp_by_url %>%
  gs_read(bootcamp_sheets[1])
          
names(boot_data) <- c("Timestamp",
                      "R_exp",
                      "GoT",
                      "Age_yrs",
                      "Sleep_hrs",
                      "Fav_date",
                      "Tidy_data")

write_csv(boot_data, path = "data/survey.csv")

# Update_survey.R
#
# Updates Googlesheet survey data and generates new R Markdown report
#

source("R/Get_bootcamp_googlesheet.R")
rmarkdown::render("talks/bootcamp-survey.Rmd", 
                  output_format = c("github_document",
                                    "pdf_document",
                                    "word_document",
                                    "ioslides_presentation"))

Web sites

  • _site.yml: site configuration parameters
  • index.Rmd: home page for site
  • other *.Rmd files: other pages
  • other directories for files
  • rmarkdown::render_site()
  • GitHub pages or other web site hosting service

Learn from my mistakes

  • Script everything you possibly can
    • If you have to repeat something, make a function or write a parameterized script
  • Document all the time
    • Comments in code
    • Update README files
  • Don’t be afraid to ask
  • Don’t be afraid to work in the open
  • Learn from others
  • Just do it!

References

Gilmore, Rick O, and Karen E Adolph. 2017. “Video Can Make Behavioural Science More Reproducible.” Nature Human Behavior 1 (12~jun). doi:10.1038/s41562-017-0128.

Munafò, Marcus R, Brian A Nosek, Dorothy V M Bishop, Katherine S Button, Christopher D Chambers, Nathalie Percie du Sert, Uri Simonsohn, Eric-Jan Wagenmakers, Jennifer J Ware, and John P A Ioannidis. 2017. “A Manifesto for Reproducible Science.” Nature Human Behaviour 1 (10~jan): 0021. doi:10.1038/s41562-016-0021.

LS0tCnRpdGxlOiAiUi1lcHJvZHVjaWJsZSBQc3ljaG9sb2dpY2FsIFNjaWVuY2UiCmF1dGhvcjogIlJpY2sgR2lsbW9yZSIKZGF0ZTogImByIFN5cy50aW1lKClgIgpjc3M6IGdpbG1vcmUuY3NzCmJpYmxpb2dyYXBoeTogYm9vdGNhbXAuYmliCmxvZ286IC4uL2ltZy9wc3UtbG9nby5wbmcKb3V0cHV0OiAKICBpb3NsaWRlc19wcmVzZW50YXRpb246CiAgICB3aWRlc2NyZWVuOiB0cnVlCiAgcGRmX2RvY3VtZW50OgogICAgdG9jOiB0cnVlCiAgICB0b2NfZGVwdGg6IDMKICBnaXRodWJfZG9jdW1lbnQ6CiAgICB0b2M6IHRydWUKICAgIHRvY19kZXB0aDogMwotLS0KCi0tLQoKPGlmcmFtZSB3aWR0aD0iNTYwIiBoZWlnaHQ9IjMxNSIgc3JjPSJodHRwczovL3d3dy55b3V0dWJlLmNvbS9lbWJlZC82Nm9Odl9ESnVQYyIgZnJhbWVib3JkZXI9IjAiIGFsbG93ZnVsbHNjcmVlbj48L2lmcmFtZT4KCiMjIFRoZW1lcwoKMS4gSXMgdGhlcmUgYSByZXByb2R1Y2liaWxpdHkgY3Jpc2lzPwoyLiBXaGF0IGlzIHJlcHJvZHVjaWJsZSBwc3ljaG9sb2dpY2FsIHNjaWVuY2U/CjMuIEhvdyBjYW4gUiBtYWtlIG15IHNjaWVuY2UgbW9yZSB0cmFuc3BhcmVudCwgb3BlbiwgYW5kIHJlcHJvZHVjaWJsZT8KCiMjIElzIHRoZXJlIGEgcmVwcm9kdWNpYmlsaXR5IGNyaXNpcz8KCi0gWWVzLCBhIHNpZ25pZmljYW50IGNyaXNpcwotIFllcywgYSBzbGlnaHQgY3Jpc2lzCi0gTm8gY3Jpc2lzCi0gRG9uJ3Qga25vdwoKLS0tCgo8ZGl2IGNsYXNzPSJjZW50ZXJlZCI+CjxhIGhyZWY9Imh0dHA6Ly93d3cubmF0dXJlLmNvbS9wb2xvcG9seV9mcy83LjM2NzE2LjE0Njk2OTU5MjMhL2ltYWdlL3JlcHJvZHVjaWJpbGl0eS1ncmFwaGljLW9ubGluZTEuanBlZ19nZW4vZGVyaXZhdGl2ZXMvbGFuZHNjYXBlXzYzMC9yZXByb2R1Y2liaWxpdHktZ3JhcGhpYy1vbmxpbmUxLmpwZWciIGhlaWdodD00NTBweD4KPGltZyBzcmM9Imh0dHA6Ly93d3cubmF0dXJlLmNvbS9wb2xvcG9seV9mcy83LjM2NzE2LjE0Njk2OTU5MjMhL2ltYWdlL3JlcHJvZHVjaWJpbGl0eS1ncmFwaGljLW9ubGluZTEuanBlZ19nZW4vZGVyaXZhdGl2ZXMvbGFuZHNjYXBlXzYzMC9yZXByb2R1Y2liaWxpdHktZ3JhcGhpYy1vbmxpbmUxLmpwZWciIGhlaWdodD01MDBweD4KPC9hPgoKW0Jha2VyIDIwMTZdKGh0dHA6Ly9kb2kub3JnLzEwLjEwMzgvNTMzNDUyYSkKPC9kaXY+CgojIyBOb3QganVzdCBpbiBwc3ljaG9sb2d5Cgo8ZGl2IGNsYXNzPSJjZW50ZXJlZCI+CjxhIGhyZWY9Imh0dHA6Ly93d3cubmF0dXJlLmNvbS9wb2xvcG9seV9mcy83LjM2NzE4LjE0NjQxNzQ0NzEhL2ltYWdlL3JlcHJvZHVjaWJpbGl0eS1ncmFwaGljLW9ubGluZTMuanBnX2dlbi9kZXJpdmF0aXZlcy9sYW5kc2NhcGVfNjMwL3JlcHJvZHVjaWJpbGl0eS1ncmFwaGljLW9ubGluZTMuanBnIj4KPGltZyBzcmM9Imh0dHA6Ly93d3cubmF0dXJlLmNvbS9wb2xvcG9seV9mcy83LjM2NzE4LjE0NjQxNzQ0NzEhL2ltYWdlL3JlcHJvZHVjaWJpbGl0eS1ncmFwaGljLW9ubGluZTMuanBnX2dlbi9kZXJpdmF0aXZlcy9sYW5kc2NhcGVfNjMwL3JlcHJvZHVjaWJpbGl0eS1ncmFwaGljLW9ubGluZTMuanBnIiIgaGVpZ2h0PTUwMHB4Pgo8L2E+CgotLS0KCjxkaXYgY2xhc3M9ImNlbnRlcmVkIj4KPGltZyBzcmM9Imh0dHBzOi8vY2RuLnNob3BpZnkuY29tL3MvZmlsZXMvMS8wODc3LzU3NjIvcHJvZHVjdHMvUmlnb3JfTW9ydGlzXzEwMjR4MTAyNC5qcGc/dj0xNDkxMjQwMTEwIiBoZWlnaHQ9NTAwcHgvPgo8L2Rpdj4KCi0tLQoKPGRpdiBjbGFzcz0iY2VudGVyZWQiPgo8YSBocmVmPSJodHRwOi8vd3d3Lm5hdHVyZS5jb20vcG9sb3BvbHlfZnMvNy4zNjcxOS4xNDY0MTc0NDg4IS9pbWFnZS9yZXByb2R1Y2liaWxpdHktZ3JhcGhpYy1vbmxpbmU0LmpwZ19nZW4vZGVyaXZhdGl2ZXMvbGFuZHNjYXBlXzYzMC9yZXByb2R1Y2liaWxpdHktZ3JhcGhpYy1vbmxpbmU0LmpwZyI+CjxpbWcgc3JjPSJodHRwOi8vd3d3Lm5hdHVyZS5jb20vcG9sb3BvbHlfZnMvNy4zNjcxOS4xNDY0MTc0NDg4IS9pbWFnZS9yZXByb2R1Y2liaWxpdHktZ3JhcGhpYy1vbmxpbmU0LmpwZ19nZW4vZGVyaXZhdGl2ZXMvbGFuZHNjYXBlXzYzMC9yZXByb2R1Y2liaWxpdHktZ3JhcGhpYy1vbmxpbmU0LmpwZyIgaGVpZ2h0PTUwMHB4Pgo8L2E+CgpbQmFrZXIgMjAxNl0oaHR0cDovL2RvaS5vcmcvMTAuMTAzOC81MzM0NTJhKQo8L2Rpdj4KCjxkaXYgY2xhc3M9Im5vdGVzIj4KSGVyZSBhcmUgdGhlIGRhdGEgZnJvbSB0aGUgTmF0dXJlIHN1cnZleS4KPC9kaXY+CgojIyBbW0BNdW5hZm8yMDE3LWRjXV0oaHR0cDovL2RvaS5vcmcvMTAuMTAzOC9zNDE1NjItMDE2LTAwMjEpIG1hbmlmZXN0bwoKPGRpdiBjbGFzcz0iY2VudGVyZWQiPgo8YSBocmVmPSJodHRwOi8vd3d3Lm5hdHVyZS5jb20vYXJ0aWNsZXMvczQxNTYyLTAxNi0wMDIxL2ZpZ3VyZXMvMSI+CjxpbWcgc3JjPSJodHRwOi8vd3d3Lm5hdHVyZS5jb20vYXJ0aWNsZS1hc3NldHMvbnBnL25hdGh1bWJlaGF2LzIwMTcvczQxNTYyLTAxNi0wMDIxL2ltYWdlc19oaXJlcy93OTI2L3M0MTU2Mi0wMTYtMDAyMS1mMS5qcGciIGhlaWdodD01MDBweD4KPC9hPgo8L2Rpdj4KCjxkaXYgY2xhc3M9Im5vdGVzIj4KVGhpcyByZWNlbnQgbWFuaWZlc3RvIGZyb20gTmF0dXJlIEh1bWFuIEJlaGF2aW9yIGRlc2NyaWJlcyB0aGUgcmlza3MgdG8gcmVwcm9kdWNpYmxlIHNjaWVuY2UgYXQgZXZlcnkgc3RlcCBvZiB0aGUgcHJvY2Vzcy4KSSB1cmdlIHlvdSB0byByZWFkIGl0Lgo8L2Rpdj4KCiMjIFdoYXQgYW0gSSB0cnlpbmcgdG8gcmVwcm9kdWNlPwoKLSBNeSBvd24gd29ya2Zsb3cKICAgIC0gRGF0YSBjb2xsZWN0aW9uCiAgICAtIENsZWFuaW5nCiAgICAtIFZpc3VhbGl6YXRpb24KICAgIC0gQW5hbHlzaXMKICAgIC0gUmVwb3J0aW5nCiAgICAtIE1hbnVzY3JpcHQgZ2VuZXJhdGlvbj8KLSAiSGl0IGJ5IGEgdHJ1Y2siIHNjZW5hcmlvCgo8ZGl2IGNsYXNzPSJub3RlcyI+CkJ1dCB0b2RheSBJIHdhbnQgdXMgdG8gdGhpbmsgbW9yZSBwYXJvY2hpYWxseSBhYm91dCBvdXIgb3duIHdvcmtmbG93cy4KSG93IGNhbiB1c2luZyBSIG1ha2Ugb3VyIG93biBkYXRhIGNvbGxlY3Rpb24sIGNsZWFuaW5nLCB2aXN1YWxpemF0aW9uLCBhbmQgYW5hbHlzaXMgd29ya2Zsb3dzIG1vcmUgcmVwcm9kdWNpYmxlLgpBc2sgeW91cnNlbGYgdGhpczogQ2FuIHlvdSBwaWNrIHVwIHdoZXJlIHlvdSBsZWZ0IG9mZiBvbiBhIHByb2plY3QgeW91IHdlcmUgd29ya2luZyBvbiB5ZXN0ZXJkYXk/IExhc3Qgd2Vlaz8gTGFzdCBtb250aD8gU2l4IG1vbnRocyBhZ28/ClB1dCBpdCB0aGlzIHdheTogSWYgeW91IHdlcmUgaGl0IGJ5IGEgdHJ1Y2sgdG9tb3Jyb3csIGNvdWxkIHlvdXIgYWR2aXNlciBhbmQgY29sbGFib3JhdG9ycyBwaWNrIHVwIHdoZXJlIHlvdSBsZWZ0IG9mZj8KPC9kaXY+CgojIyBSZXByb2R1Y2libGUgd29ya2Zsb3dzCgotIFNjcmlwdGVkLCBhdXRvbWF0ZWQgPSBtaW5pbWl6ZSBodW1hbi1kZXBlbmRlbnQgc3RlcHMuCi0gV2VsbC1kb2N1bWVudGVkCi0gQmUga2luZCB0byB5b3VyIGZ1dHVyZSAoZm9yZ2V0ZnVsKSBzZWxmCi0gVHJhbnNwYXJlbnQgdG8gbWUgJiBjb2xsZWFndWVzID09IHRyYW5zcGFyZW50IHRvIG90aGVycwoKPGRpdiBjbGFzcz0ibm90ZXMiPgpSZXByb2R1Y2libGUgd29ya2Zsb3dzIGFyZSBzY3JpcHRlZC4KVGhleSBtaW5pbWl6ZSBodW1hbiBjb250YWN0IHdpdGggeW91ciBkYXRhIGZpbGVzLgpUaGV5IGFyZSB3ZWxsLWRvY3VtZW50ZWQuCkFuZCBpdCB0dXJucyBvdXQgdGhhdCB3b3JrZmxvd3MgdGhhdCBhcmUgdHJhbnNwYXJlbnQgdG8geW91IGFuZCB5b3VyIGNvbGxlYWd1ZXMgYXJlIHRyYW5zcGFyZW50IHRvIG90aGVycy4KVGhpcyBtYWtlcyB0aGVtIGVhc3kgdG8gc2hhcmUuCjwvZGl2PgoKIyMgVXNpbmcgUiBmb3IgcmVwcm9kdWNpYmxlIHdvcmtmbG93cwoKLSAqKk9wdGlvbiAxKio6IEFsbCBjb21tYW5kcyBpbiBhbiBSIHNjcmlwdDogZS5nLiwgYHByb2plY3RfYW5hbHlzaXMuUmAKLSAqKk9wdGlvbiAyYSoqOiBNaXggUiBjb2RlLCBvdXRwdXQsIGNvbW1lbnRzIGluIGFuIFtSIE1hcmtkb3duXShodHRwOi8vcm1hcmtkb3duLnJzdHVkaW8uY29tLykgZG9jdW1lbnQKLSAqKk9wdGlvbiAyYioqOiBVc2UgUiBzY3JpcHRzIHdpdGggc29tZSBbc3BlY2lhbCBmb3JtYXR0aW5nXShodHRwOi8vcm1hcmtkb3duLnJzdHVkaW8uY29tL2FydGljbGVzX3JlcG9ydF9mcm9tX3Jfc2NyaXB0Lmh0bWwpLCBbKG1vcmUgaW5mbyldKGh0dHBzOi8vZ2l0aHViLmNvbS9qZW5ueWJjL2hhcHB5LWdpdC13aXRoLXIvYmxvYi9tYXN0ZXIvMzFfd29ya2Zsb3ctZmlyc3QtdXNlLXItc2NyaXB0LWFuZC1naXRodWIuUm1kKS4KICAgIAo8ZGl2IGNsYXNzPSJub3RlcyI+CldlJ3ZlIGFscmVhZHkgc2hvd24geW91IGluIHRoaXMgYm9vdGNhbXAgaG93IHdyaXRpbmcgUiBzY3JpcHRzIGFuZCBmdW5jdGlvbnMgY2FuIGxldCB5b3UgaW1wb3J0LCBjbGVhbiwgbXVuZ2UsIHJlb3JnYW5pemUsIHBsb3QsIGFuZCBhbmFseXplIGRhdGEuCldlJ3ZlIGFscmVhZHkgc2VlbiBob3cgY29tbWVudGluZyBjb2RlIGZyYWdtZW50cyBtYWtlcyBpdCBlYXNpZXIgdG8gcmVhZCBhbmQgdW5kZXJzdGFuZC4KQW4gZXh0ZW5zaW9uIHRvIFIgY2FsbGVkIFIgTWFya2Rvd24gbGV0cyB1cyBtaXggUiBjb2RlLCBhbmFseXNlcywgdGV4dCwgdGFibGVzLCBhbmQgb3RoZXIgZm9ybWF0dGluZyB0byBtYWtlIGFsbCBzb3J0cyBvZiBwcm9kdWN0cy4KUiBNYXJrZG93biBmaWxlcyBhcmUganVzdCB0ZXh0IGZpbGVzLgpCdXQgd2l0aCB0aGlzIG9uZSB0ZXh0IGZpbGUsIGl0J3MgZWFzeSB0byBwcm9kdWNlIG11bHRpcGxlIG91dHB1dCB0eXBlczogUERGIG9yIFdvcmQgZm9ybWF0dGVkIGRvY3VtZW50czsgSFRNTCBmb3IgYmxvZ3MsIHdlYiBzaXRlcywgb3IgZXZlbiBzbGlkZSBwcmVzZW50YXRpb24uCjwvZGl2PgoKIyMgRXhhbXBsZSAxCgpgYGAKIyBJbXBvcnQgZGF0YQoKIyBDbGVhbiBkYXRhCgojIFZpc3VhbGl6ZSBkYXRhCgojIEFuYWx5emUgZGF0YQoKIyBSZXBvcnQgZmluZGluZ3MKYGBgCgotLS0KCmBgYAojIEltcG9ydCBkYXRhCm15X2RhdGEgPC0gcmVhZC5jc3YoInBhdGgvMi9kYXRhX2ZpbGUuY3N2IikKCiMgQ2xlYW4gZGF0YQpteV9kYXRhJGdlbmRlciA8LSB0b2xvd2VyKG15X2RhdGEkZ2VuZGVyKSAjIG1ha2UgbG93ZXIgY2FzZQouLi4KYGBgCgojIyBNYWtlIHNjcmlwdCB0aGF0IGNhbGxzIHNlcXVlbmNlIG9mIFIgY29tbWFuZHMgb3IgZnVuY3Rpb25zCgpgYGAKIyBJbXBvcnQgZGF0YQpzb3VyY2UoIlIvSW1wb3J0X2RhdGEuUiIpICMgc291cmNlKCkgcnVucyBzY3JpcHRzLCBsb2FkcyBmdW5jdGlvbnMKCiMgQ2xlYW4gZGF0YQpzb3VyY2UoIlIvQ2xlYW5fZGF0YS5SIikKCiMgVmlzdWFsaXplIGRhdGEKc291cmNlKCJSL1Zpc3VhbGl6ZV9kYXRhLlIiKQouLi4KYGBgCgojIyBTdHJlbmd0aHMgJiBXZWFrbmVzc2VzCgotIFIgY29tbWFuZHMgaW4gZmlsZXMgdGhhdCBjYW4gYmUgcmUtcnVuCi0gU2VwYXJhdGUgcGllY2VzIG9mIHdvcmtmbG93IGtlcHQgc2VwYXJhdGUKLSAiTWFzdGVyLlIiIHNjcmlwdCB0aGF0IGNhbiBiZSBydW4gdG8gcmVnZW5lcmF0ZSBmdWxsIHNlcXVlbmNlIG9mIHJlc3VsdHMKICAgIC0gRXJyb3IgaW4gcmF3IGRhdGEgZmlsZT8KICAgIC0gTm8gcHJvYmxlbTsgZml4IGFuZCByZS1ydW4gIk1hc3Rlci5SIgotIEhvdyB0byBzYXZlIHJlc3VsdHMgb3Igc2hhcmUgd2l0aCBjb2xsYWJvcmF0b3JzPwoKIyMgRXhhbXBsZSAyIC0gUiBNYXJrZG93bgoKLSBKYW1lcycgUiBjb21tYW5kcyBmcm9tIERheSAxOiBbUmF3IFIgc2NyaXB0ICguUildKFItV29ya3Nob3AtSmFtZXMuUikKLSBDb252ZXJ0ZWQgdG8gW1IgTWFya2Rvd25dKFItV29ya3Nob3AtSmFtZXMuUm1kKQotIE91dHB1dCBhcyB8IFtIVE1MIG5vdGVib29rXShSLVdvcmtzaG9wLUphbWVzLm5iLmh0bWwpIHwgW0hUTUwgU2xpZGVzXShSLVdvcmtzaG9wLUphbWVzLmh0bWwpIHwgW1BERl0oUi1Xb3Jrc2hvcC1KYW1lcy5wZGYpIHwgW2RvY3hdKFItV29ya3Nob3AtSmFtZXMuZG9jeCkgfAoKPGRpdiBjbGFzcz0ibm90ZXMiPgpKdXN0IHRvIHNob3cgeW91IGhvdyBlYXN5IHRoaXMgaXMsIGxldCdzIGxvb2sgYXQgdGhlIFIgc3ludGF4IEphbWVzIHVzZWQgeWVzdGVyZGF5LgpJJ20gZ29pbmcgdG8gc2hvdyB5b3UgaG93IGFkZGluZyBqdXN0IGEgdGlueSBiaXQgb2YgdGV4dCB0byB0aGF0IGZpbGUgdHJhbnNmb3JtcyBpdC4KSGVyZSBpcyB0aGUgb3JpZ2luYWwgUiBzY3JpcHQuCkhlcmUgaXMgdGhlIHRyYW5zZm9ybWVkIGZpbGUgd2l0aCBhIC5SbWQgZXh0ZW5zaW9uLgo8L2Rpdj4KCiMjIFN0cnVjdHVyZSBvZiBhbiBbUiBNYXJrZG93biAuUm1kXShSLVdvcmtzaG9wLUphbWVzLlJtZCkgZmlsZQoKLSBoZWFkZXIgaW5mbyBpbiBbWUFNTCBBaW4ndCBNYXJrdXAgTGFuZ3VhZ2UgKFlBTUwpIGZvcm1hdF0oaHR0cDovL3d3dy55YW1sLm9yZy9zdGFydC5odG1sKQotIE1hcmtkb3duIGZvciBmb3JtYXRpbmcgdGV4dCAoaGVhZGVycywgKipib2xkZmFjZSoqLyppdGFsaWNzKiwgYGNvZGVgLCBidWxsZXRlZCBvciBudW1iZXJlZCBsaXN0cywgW3dlYiBsaW5rc10oaHR0cDovL3d3dy5wc3UuZWR1KSwgZXRjLgotIFIgY29kZSAiY2h1bmtzIgoKIyMgT25lIFIgdG8gcnVsZSB0aGVtIGFsbCBhbmQgaW4gdGhlIGNvbnNvbGUgYmluZCB0aGVtLi4uCgotIE9uZSBmaWxlLCBtYW55IHBvc3NpYmxlIG91dHB1dHMKICAgIC0gW3BkZl9kb2N1bWVudF0oaHR0cDovL3JtYXJrZG93bi5yc3R1ZGlvLmNvbS9wZGZfZG9jdW1lbnRfZm9ybWF0Lmh0bWwpLCBbd29yZF9kb2N1bWVudF0oaHR0cDovL3JtYXJrZG93bi5yc3R1ZGlvLmNvbS93b3JkX2RvY3VtZW50X2Zvcm1hdC5odG1sKSwgb3IgW2dpdGh1Yl9kb2N1bWVudF0oaHR0cDovL3JtYXJrZG93bi5yc3R1ZGlvLmNvbS9naXRodWJfZG9jdW1lbnRfZm9ybWF0Lmh0bWwpCiAgICAtIFtpb3NsaWRlc19wcmVzZW50YXRpb25dKGh0dHA6Ly9ybWFya2Rvd24ucnN0dWRpby5jb20vaW9zbGlkZXNfcHJlc2VudGF0aW9uX2Zvcm1hdC5odG1sKSBmb3IgSFRNTCBzbGlkZSBzaG93CiAgICAtIENvb2wgaW50ZXJhY3RpdmUgd2ViLWFwcCBsaWtlIERhbidzIHR1dG9yaWFsCiAgICAtIFdlYiBzaXRlcyBsaWtlIHRoZSBvbmUgZm9yIHRoaXMgW2Jvb3RjYW1wXShodHRwczovL2dpdGh1Yi5jb20vcHN1LXBzeWNob2xvZ3kvci1ib290Y2FtcCksIFtibG9nc10oaHR0cHM6Ly9ib29rZG93bi5vcmcveWlodWkvYmxvZ2Rvd24vKSwgZXZlbiBbYm9va3NdKGh0dHBzOi8vYm9va2Rvd24ub3JnL3lpaHVpL2Jvb2tkb3duLykKCiMjIFlvdXIgdHVybgoKMS4gT3BlbiAiRmlsZS9OZXcgRmlsZS9SIE5vdGVib29rIgoyLiBDaGFuZ2UgYHRpdGxlOiAiUiBOb3RlYm9vayJgIHRvIHNvbWV0aGluZyBlbHNlLCBsaWtlIGB0aXRsZTogIlJpY2sncyBSIE5vdGVib29rImAKMy4gU2F2ZSB0aGUgZmlsZSAoZGVmYXVsdCBuYW1lIGlzIGBVbnRpdGxlZGApIHdpdGggYW4gYC5SbWRgIGV4dGVuc2lvbi4KNC4gTG9vayBhdCB0aGUgYCouUm1kYCBjb2RlLgo1LiBMb29rIGF0IHRoZSBgKi5uYi5odG1sYCBmaWxlIGluIGEgYnJvd3Nlci4KCiMjIFRoaW5ncyB0byB0cnkgaWYgeW91IGxpa2UKCmBgYAojIEJpZyBpZGVhCgojIyBTbWFsbGVyIGlkZWEgaW4gc2VydmljZSBvZiBiaWdnZXIKCi0gU3VwcG9ydGluZyBwb2ludAotIEFub3RoZXIgc3VwcHBvcnRpbmcgcG9pbnQKCjEuIGFuIGVudW1lcmF0ZWQgKipib2xkKiogcG9pbnQKMS4gYW4gZW51bWVyYXRlZCAqaXRhbGljaXplZCogcG9pbnQKCi0gYSBbbGlua10oaHR0cDovL3BzdS1wc3ljaG9sb2d5LmdpdGh1Yi5pby9yLWJvb3RjYW1wKSB0byB0aGlzIGJvb3RjYW1wCi0gYW4gaW1hZ2U6ICFbcmF3cl0oaHR0cHM6Ly93d3cuaW5zaWRlaGlnaGVyZWQuY29tL3NpdGVzL2RlZmF1bHQvc2VydmVyX2ZpbGVzL21lZGlhL1Blbm5TdGF0ZTIuUE5HKQotIGFuIGVxdWF0aW9uOiAkZSA9IG1jXjIkCmBgYAoKIyBCaWcgaWRlYQoKIyMgU21hbGxlciBpZGVhIGluIHNlcnZpY2Ugb2YgYmlnZ2VyCgotIFN1cHBvcnRpbmcgcG9pbnQKLSBBbm90aGVyIHN1cHBwb3J0aW5nIHBvaW50Ci0gYSAqKmJvbGQqKiBwb2ludAotIGFuICppdGFsaWNpemVkKiBwb2ludAoKLS0tCgotIGEgW2xpbmtdKGh0dHA6Ly9wc3UtcHN5Y2hvbG9neS5naXRodWIuaW8vci1ib290Y2FtcCkgdG8gdGhpcyBib290Y2FtcAotIGFuIGltYWdlOiAhW3Jhd3JdKGh0dHBzOi8vd3d3Lmluc2lkZWhpZ2hlcmVkLmNvbS9zaXRlcy9kZWZhdWx0L3NlcnZlcl9maWxlcy9tZWRpYS9QZW5uU3RhdGUyLlBORykKLSBhbiBlcXVhdGlvbjogJGUgPSBtY14yJAoKIyMgTGV0J3MgdHJ5IGl0IHdpdGggc29tZSBkYXRhCgotIFtib290Y2FtcC1zdXJ2ZXkuUm1kXShib290Y2FtcC1zdXJ2ZXkuUm1kKQotIFtib290Y2FtcC1zdXJ2ZXkubWRdKGJvb3RjYW1wLXN1cnZleS5tZCkKCiMjIE9uZSBmaWxlLCBtYW55IG91dHB1dCBvcHRpb25zCgotICdEZWZhdWx0JyBmb3IgdGhlIGZpbGU6IGBybWFya2Rvd246OnJlbmRlcigidGFsa3MvYm9vdGNhbXAtc3VydmV5LlJtZCIpYAotICoqUERGIGRvY3VtZW50Kio6IGBybWFya2Rvd246OnJlbmRlcigndGFsa3MvYm9vdGNhbXAtc3VydmV5LlJtZCcsIG91dHB1dF9mb3JtYXQgPSAicGRmX2RvY3VtZW50IilgCi0gKipXb3JkIGRvY3VtZW50Kio6IGBybWFya2Rvd246OnJlbmRlcigndGFsa3MvYm9vdGNhbXAtc3VydmV5LlJtZCcsIG91dHB1dF9mb3JtYXQgPSAid29yZF9kb2N1bWVudCIpYAoKLS0tCgotICoqSFRNTCBzbGlkZXMqKjogYHJtYXJrZG93bjo6cmVuZGVyKCd0YWxrcy9ib290Y2FtcC1zdXJ2ZXkuUm1kJywgb3V0cHV0X2Zvcm1hdCA9ICJpb3NsaWRlc19wcmVzZW50YXRpb24iKWAKLSAqKk11bHRpcGxlIG91dHB1dHMqKjogYHJtYXJrZG93bjo6cmVuZGVyKCd0YWxrcy9ib290Y2FtcC1zdXJ2ZXkuUm1kJywgb3V0cHV0X2Zvcm1hdCA9IGMoInBkZl9kb2N1bWVudCIsICJ3b3JkX2RvY3VtZW50IiwgImdpdGh1Yl9kb2N1bWVudCIsICJpb3NsaWRlc19wcmVzZW50YXRpb24iKWAKCiMjIEtleSBwb2ludHMKCi0gVXNlIFIgc2NyaXB0cyB0byBjYXB0dXJlICYgcmVwcm9kdWNlIHdvcmtmbG93cyBhbmQvb3IKLSBVc2UgUiBNYXJrZG93biBmaWxlcyBmb3IgZG9jdW1lbnRzLCByZXBvcnRzLCBwcmVzZW50YXRpb25zLgogICAgLSBPbmUgb3IgbW9yZSBvdXRwdXQgZm9ybWF0cyBmcm9tIHRoZSBzYW1lIGZpbGUuCiAgICAtIEFuYWx5c2lzL2xhYiBub3RlYm9vay4KICAgIAotLS0KCi0gVXNlIFIgc2NyaXB0cyBvciBmdW5jdGlvbnMgdG8gYXV0b21hdGUgZGlmZmVyZW50IHBpZWNlcyBvZiB0aGUgcGlwZWxpbmUuCi0gTWFrZSBSRUFETUUgZmlsZXMgdG8gZXhwbGFpbiBob3cgdG8gcHV0IHBpZWNlcyB0b2dldGhlci4KCi0tLQoKPGRpdiBjbGFzcz0iY2VudGVyZWQiPgo8aW1nIHNyYz0iaHR0cHM6Ly9hbTIzLmFrYW1haXplZC5uZXQvdG1zL2NudC91cGxvYWRzLzIwMTcvMDUvMTQ5MTk5MDIwNTU1NS0xLmpwZyIgaGVpZ2h0PTUwMHB4Pgo8L2Rpdj4KCiMjIFRvd2FyZCBhIHJlcHJvZHVjaWJsZSBwc3ljaG9sb2dpY2FsIHNjaWVuY2UuLi4KCi0gVHJhbnNwYXJlbnQsIHJlcHJvZHVjaWJsZSwgb3BlbiB3b3JrZmxvd3MgcHJlLXB1YmxpY2F0aW9uCi0gT3Blbmx5IHNoYXJlZCBtYXRlcmlhbHMgKyBkYXRhICsgY29kZQotIFtbQE11bmFmbzIwMTctZGNdXShodHRwOi8vZG9pLm9yZy8xMC4xMDM4L3M0MTU2Mi0wMTYtMDAyMSk6IHJlcHJvZHVjaWJsZSBwcmFjdGljZXMgYWNyb3NzIHRoZSB3b3JrZmxvdwogICAgLSBXaGVyZSB0byBzaGFyZSBhbmQgd2hlbj8gTG90cyBvZiBvcHRpb25zLiBMZXQncyB0YWxrLgotIFtbQEdpbG1vcmUyMDE3LWVoXV0oaHR0cDovL2R4LmRvaS5vcmcvMTAuMTAzOC9zNDE1NjItMDE3LTAxMjgpOiB2aWRlbyBhbmQgcmVwcm9kdWNpYmlsaXR5CgojIyBBZHZhbmNlZCB0b3BpY3MKCi0gV3JpdGUgcGFwZXJzIGluIFIgTWFya2Rvd24gdXNpbmcgW2BwYXBhamFgXShodHRwczovL2dpdGh1Yi5jb20vY3JzaC9wYXBhamEpCiAgICAtIE1ha2UgW3RoaXNdKC4uL3BhcGFqYV9kZW1vL2dpbG1vcmUtbGVicmV0b24taGFsbHF1aXN0LnBkZikgZnJvbSBbdGhpc10oLi4vcGFwYWphX2RlbW8vZ2lsbW9yZS1sZWJyZXRvbi1oYWxscXVpc3QuUm1kKQotIFVzZSBSIFN0dWRpbyBbcHJvamVjdHNdKGh0dHBzOi8vc3VwcG9ydC5yc3R1ZGlvLmNvbS9oYy9lbi11cy9hcnRpY2xlcy8yMDA1MjYyMDctVXNpbmctUHJvamVjdHMpCi0gVmVyc2lvbiBjb250cm9sIHdpdGggZ2l0IGFuZCBbR2l0SHViXShodHRwOi8vZ2l0aHViLmNvbSkKLSBTY3JpcHRhYmxlIGFuYWx5c2lzIHdvcmtmbG93cwogICAgLSBSZXBvcnRzIGZvciBlYWNoIHBhcnRpY2lwYW50LCBlLmcuIFtQRUVQLUlJIHByb2plY3RdKGh0dHBzOi8vZ2l0aHViLmNvbS9naWxtb3JlLWxhYi9wZWVwLUlJLXJhdGluZ3MtYW5hbHlzaXMpCiAgICAtIFRoaXMgYm9vdGNhbXAncyBbYE1ha2Vfc2l0ZS5SYF0oLi4vUi9NYWtlX3NpdGUuUikKLSBbV2ViIHNpdGVzXShodHRwOi8vcm1hcmtkb3duLnJzdHVkaW8uY29tL3JtYXJrZG93bl93ZWJzaXRlcy5odG1sKSwgW2Jsb2dzXShodHRwczovL2Jvb2tkb3duLm9yZy95aWh1aS9ibG9nZG93bi8pLCAoZXZlbiBbYm9va3NdKGh0dHBzOi8vYm9va2Rvd24ub3JnLykpIHdpdGggUiBNYXJrZG93bgogICAgCiMjIFIgU3R1ZGlvIFByb2plY3RzCgotIEtlZXAgZmlsZXMsIHNldHRpbmdzLCBvcmdhbml6ZWQKLSBFYXN5IHRvIHN3aXRjaCBiZXR3ZWVuIHByb2plY3RzCi0gUmVkdWNlcyBtZW50YWwgZWZmb3J0ICh3aGF0IGRpcmVjdG9yeSBhbSBJIGluPykKLSBJbnRlZ3JhdGVzIHdpdGggdmVyc2lvbiBjb250cm9sIChlLmcuLCBHaXRIdWIpCgotLS0KCjxkaXYgY2xhc3M9ImNlbnRlcmVkIj4KPGltZyBzcmM9Ii4uL2ltZy9yaWNrcy1yZWNlbnQtcHJvamVjdHMuanBnIiBoZWlnaHQ9NTUwLz4KPC9kaXY+CgojIyBWZXJzaW9uIGNvbnRyb2wKCi0gS2VlcCB0cmFjayBvZiB5b3VyIHBhc3QKLSBCYWNrIHRvIHRoZSBGdXR1cmUKLSAqKmdpdCoqOiBhIHN5c3RlbSBmb3Igc29mdHdhcmUgdmVyc2lvbiBjb250cm9sCi0gWyoqR2l0SHViKipdKGh0dHA6Ly9naXRodWIuY29tKTogYSB3ZWJzaXRlIGZvciBtYW5hZ2luZyBwcm9qZWN0cyB0aGF0IHVzZSBnaXQKCiMjIE15IEdpdEh1YiB3b3JrZmxvdwoKMS4gQ3JlYXRlIGEgcmVwbyBvbiBHaXRIdWIKMi4gQ29weSByZXBvIFVSTAozLiBgRmlsZS9OZXcgUHJvamVjdC4uLi9gCjQuIFZlcnNpb24gQ29udHJvbCwgR2l0CjUuIFBhc3RlIHJlcG8gVVJMCjYuIFNlbGVjdCBsb2NhbCBuYW1lIGZvciByZXBvIGFuZCBkaXJlY3Rvcnkgd2hlcmUgaXQgbGl2ZXMuCjcuIE9wZW4gcHJvamVjdCB3aXRoaW4gUiBTdHVkaW8gYEZpbGUvT3BlbiBQcm9qZWN0Li4uYAo4LiBDb21taXQgZWFybHkgJiBvZnRlbgoKLS0tCgo8ZGl2IGNsYXNzPSJjZW50ZXJlZCI+Cjx2aWRlbyBoZWlnaHQ9IjQ0MCIgd2lkdGg9IjcyMCIgY29udHJvbHM+CiAgPHNvdXJjZSBzcmM9Ii4uL21vdi9yc3R1ZGlvLXByb2plY3Qtb24tZ2l0aHViLTEubXA0IiB0eXBlPSJ2aWRlby9tcDQiPgogIFlvdXIgYnJvd3NlciBkb2VzIG5vdCBzdXBwb3J0IHRoZSB2aWRlbyB0YWcuCjwvdmlkZW8+CjwvZGl2PgoKLS0tCgo8ZGl2IGNsYXNzPSJjZW50ZXJlZCI+Cjx2aWRlbyBoZWlnaHQ9IjQ0MCIgd2lkdGg9IjcyMCIgY29udHJvbHM+CiAgPHNvdXJjZSBzcmM9Ii4uL21vdi9lZGl0LXNhdmUtY29tbWl0LXB1c2gtMS5tcDQiIHR5cGU9InZpZGVvL21wNCI+CllvdXIgYnJvd3NlciBkb2VzIG5vdCBzdXBwb3J0IHRoZSB2aWRlbyB0YWcuCjwvdmlkZW8+CjwvZGl2PgoKIyMgU2NyaXB0aW5nIHRoZSBwaXBlbGluZQoKYGBgCiMgR2V0X2Jvb3RjYW1wX2dvb2dsZXNoZWV0LlIKIyAKIyBTY3JpcHQgdG8gYXV0aGVudGljYXRlIHRvIEdvb2dsZSwgZXh0cmFjdCBSIGJvb3RjYW1wIHN1cnZleSBkYXRhCgpsaWJyYXJ5KGdvb2dsZXNoZWV0cykKbGlicmFyeSh0aWR5dmVyc2UpCgpzdXJ2ZXlfdXJsIDwtICJodHRwczovL2RvY3MuZ29vZ2xlLmNvbS9zcHJlYWRzaGVldHMvZC8xQXk1NnU2ZzRqeUVFZGxtVjJOSHhUTEJsY2pJMmdIYXZ0YS1JazBrR3JwZy9lZGl0P3VzcD1zaGFyaW5nIgoKYm9vdGNhbXBfYnlfdXJsIDwtIHN1cnZleV91cmwgJT4lCiAgZXh0cmFjdF9rZXlfZnJvbV91cmwoKSAlPiUKICBnc19rZXkoKQoKYm9vdGNhbXBfc2hlZXRzIDwtIGdzX3dzX2xzKGJvb3RjYW1wX2J5X3VybCkKYGBgCgotLS0KCmBgYApib290X2RhdGEgPC0gYm9vdGNhbXBfYnlfdXJsICU+JQogIGdzX3JlYWQoYm9vdGNhbXBfc2hlZXRzWzFdKQogICAgICAgICAgCm5hbWVzKGJvb3RfZGF0YSkgPC0gYygiVGltZXN0YW1wIiwKICAgICAgICAgICAgICAgICAgICAgICJSX2V4cCIsCiAgICAgICAgICAgICAgICAgICAgICAiR29UIiwKICAgICAgICAgICAgICAgICAgICAgICJBZ2VfeXJzIiwKICAgICAgICAgICAgICAgICAgICAgICJTbGVlcF9ocnMiLAogICAgICAgICAgICAgICAgICAgICAgIkZhdl9kYXRlIiwKICAgICAgICAgICAgICAgICAgICAgICJUaWR5X2RhdGEiKQoKd3JpdGVfY3N2KGJvb3RfZGF0YSwgcGF0aCA9ICJkYXRhL3N1cnZleS5jc3YiKQpgYGAKCi0tLQoKYGBgCiMgVXBkYXRlX3N1cnZleS5SCiMKIyBVcGRhdGVzIEdvb2dsZXNoZWV0IHN1cnZleSBkYXRhIGFuZCBnZW5lcmF0ZXMgbmV3IFIgTWFya2Rvd24gcmVwb3J0CiMKCnNvdXJjZSgiUi9HZXRfYm9vdGNhbXBfZ29vZ2xlc2hlZXQuUiIpCnJtYXJrZG93bjo6cmVuZGVyKCJ0YWxrcy9ib290Y2FtcC1zdXJ2ZXkuUm1kIiwgCiAgICAgICAgICAgICAgICAgIG91dHB1dF9mb3JtYXQgPSBjKCJnaXRodWJfZG9jdW1lbnQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicGRmX2RvY3VtZW50IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIndvcmRfZG9jdW1lbnQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiaW9zbGlkZXNfcHJlc2VudGF0aW9uIikpCmBgYAoKIyMgW1dlYiBzaXRlc10oaHR0cDovL3JtYXJrZG93bi5yc3R1ZGlvLmNvbS9ybWFya2Rvd25fd2Vic2l0ZXMuaHRtbCkKCi0gW2Bfc2l0ZS55bWxgXSguLi9fc2l0ZS55bWwpOiBzaXRlIGNvbmZpZ3VyYXRpb24gcGFyYW1ldGVycwotIFtgaW5kZXguUm1kYF0oLi4vaW5kZXguUm1kKTogaG9tZSBwYWdlIGZvciBzaXRlCi0gb3RoZXIgYCouUm1kYCBmaWxlczogb3RoZXIgcGFnZXMKLSBvdGhlciBkaXJlY3RvcmllcyBmb3IgZmlsZXMKLSBgcm1hcmtkb3duOjpyZW5kZXJfc2l0ZSgpYAotIFtHaXRIdWIgcGFnZXNdKGh0dHBzOi8vcGFnZXMuZ2l0aHViLmNvbS8pIG9yIG90aGVyIHdlYiBzaXRlIGhvc3Rpbmcgc2VydmljZQoKIyMgTGVhcm4gZnJvbSBteSBtaXN0YWtlcwoKLSBTY3JpcHQgKipldmVyeXRoaW5nKiogeW91IHBvc3NpYmx5IGNhbgogICAgLSBJZiB5b3UgaGF2ZSB0byByZXBlYXQgc29tZXRoaW5nLCBtYWtlIGEgZnVuY3Rpb24gb3Igd3JpdGUgYSBwYXJhbWV0ZXJpemVkIHNjcmlwdAotIERvY3VtZW50ICoqYWxsIHRoZSB0aW1lKioKICAgIC0gQ29tbWVudHMgaW4gY29kZQogICAgLSBVcGRhdGUgUkVBRE1FIGZpbGVzCi0gRG9uJ3QgYmUgYWZyYWlkIHRvIGFzawotIERvbid0IGJlIGFmcmFpZCB0byB3b3JrIGluIHRoZSBvcGVuCi0gTGVhcm4gZnJvbSBvdGhlcnMKLSBKdXN0IGRvIGl0IQoKIyMgUmVmZXJlbmNlcwoK