R will always be arcane to those who do not make a serious effort to learn it. It is not meant to be intuitive and easy for casual users to just plunge into. It is far too complex and powerful for that. But the rewards are great for serious data analysts who put in the effort.

Berton Gunter R-help August 2007 (archived at https://perma.cc/KY9N-2FTT)

“Evelyn Hall: I would like to know how (if) I can extract some of the information from the summary of my nlme.

Simon Blomberg: This is R. There is no if. Only how.”

Evelyn Hall and Simon ‘Yoda’ Blomberg, R-help April 2005 (archived at https://perma.cc/KY9N-2FTT)

1 Learning R

1.1 Base R

Here are a slew of resources for learning base R (in addition to the documents in the lab’s Primer Articles folder):

1.2 Statistics (using R)

The following are resources for learning statistics using R.

1.3 tidyverse

The following are resources for learning tidyverse, which is a collection of R packages for data management:

2 Initial Set Up

Note: many of these initial setup steps described below are not necessary for general use; many of these steps are necessary only for using lab-related repositories (e.g., to gain API access to export data from REDCap, to use absolute paths rather than relative paths so repos can communicate with each other, etc.).

  1. Make sure you are logged onto a computer that can access the lab server (either a lab computer, or a computer you can VPN into the lab server), and that you have admin access to install and uninstall software
  2. Install R (https://www.r-project.org/) into a directory that contains no spaces; On PC, change the location from the default C:/Program Files/R/[R-VERSION] (which contains a space) to C:/R/[R-VERSION] (which does not contain any spaces; archived at https://perma.cc/6VMX-3LYX---this is because some packages that require compilation to install cannot read filepaths with spaces; archived at https://perma.cc/XA3V-JTPY); may have to right click and “Run As Administrator”
    • If R was already installed in a directory that contains spaces (e.g., C:/Program Files/R/[R-VERSION]), uninstall R before installing it in a directory that doesn’t contain spaces
  3. Install RStudio Desktop (https://www.rstudio.com/products/rstudio/download/) in the main program files directory; may have to right click and “Run As Administrator”. RStudio is the best available graphical user interface for R.
  4. Set the executables for R and RStudio to always run with administrator permissions.
    • If on Windows, open File Explorer and find the main executable of R (C:/R/[R-VERSION]/bin/R.exe) and RStudio (C:\Program Files\RStudio\bin\RStudio.exe). Right-click it to open the contextual menu. Then, click or tap on “Properties”. In the Properties window, go to the Compatibility tab. At the bottom of the window, check the box next to the “Run this program as an administrator” option, and then click or tap on Apply or OK.
  5. Install tools to allow you to compile R packages so you can install packages from source, if necessary (i.e., if package binaries are not available):
  6. Set up git, GitLab, and the GitHub Desktop App in the main program files directory; may have to right click and “Run As Administrator”; For instructions setting up and using GitLab, see here: https://devpsylab.github.io/DataAnalysis/git.html#toBegin
  7. The Rprofile.site file in the etc folder of the R installation directory is the code that is run for every user at the beginning each time you load R. We will update the default Rprofile.site file with the lab’s Rprofile.site file so R installs packages in the correct location, sets the default package repository, updates packages, and gives you a fortune cookie. To do this, perform the following steps:
    • Rename the Rprofile.site file in the R installation directory (C:/R/R-[InsertVersionNumber]/etc/Rprofile.site) to be Rprofile_BACKUP.site
    • Download the lab’s Rprofile.site file located in this repository at the following location (https://research-git.uiowa.edu/PetersenLab/R-InitialSetup/-/blob/master/R%20Setup%20Files/Rprofile.site), and paste it into the R installation directory (PC: C:/R/R-[InsertVersionNumber]/etc/Rprofile.site; Mac: /Library/Frameworks/R.framework/Versions/[InsertVersionNumber]/Resources/etc/Rprofile.site)
  8. The .Rprofile file in the user’s Documents folder is the code that is run for the particular user at the beginning each time you load R. We will update the default .Rprofile file (if there is one) with the lab’s .Rprofile file so R knows which computer you are using and which path to use (relative to where your R projects are located). To do this, perform the following steps:
    • Download the lab’s .Rprofile template file in this repository at the following location, and make sure to remove anything besides .Rprofile in the filename: https://research-git.uiowa.edu/PetersenLab/R-InitialSetup/-/blob/master/R%20Setup%20Files/.Rprofile
    • Open the lab’s .Rprofile file, and revise it with your HawkID
    • Revise the lab’s .Rprofile file with the local path to the Documents folder for each of the computers you will use to access R (e.g., home computer, work computer, laptop). Make sure to use forward slashes (/), not back slashes (\) in the path.
    • You will save the file in your HOME directory. To find the HOME directory, open R and type the following command: Sys.getenv("HOME")—the output of the command is the location of your HOME directory; If this is a lab computer, it may be located here: //home.iowa.uiowa.edu/[user]/Documents. If this is your personal computer, it may be located here: PC: C:/Users/[user]/Documents; Mac: /Users/[user]. Then close R.
    • If your HOME directory is in a OneDrive folder (or another cloud-based sync folder), you will want to change the directory of your HOME path so that it is not in a OneDrive folder. To do that, open Environment Variables (archived at https://perma.cc/A2E5-B5VA) in Windows. Then, add/edit HOME as the “variable name” with the intended location as the “variable value” (e.g., C:/Users/[user]/Documents, where you replace “user” with your HawkID).
      • You may also solve this issue by placing the following command in the Rprofile.site from the previous step
        • Sys.setenv("HOME" = "C:/Users/[specific user ID])/Documents")
    • Move the revised .Rprofile file to the HOME directory and overwrite the original .Rprofile file (if it exists). You may have to show hidden files in order to see the file (PC: see Windows Explorer settings; Mac: Command+Shift+Dot).
    • Make sure to show filename extensions in your file explorer window, and make sure the file is named .Rprofile (not .Rprofile.Rprofile). Make sure there is a period at the beginning of the filename.
  9. Run RStudio. If the Rprofile.site and .Rprofile files are correctly set up, they should pre-populate your path location when you open R. If the contents of the Global Environment in RStudio are empty, your Rprofile.site and/or .Rprofile files are not set up correctly.
    • If you get this error (Error: could not find function "install.packages"), run the following line manually and then restart RStudio after the package finishes installing: install.packages("fortunes")
  10. For reproducibility purposes, prevent R/RStudio from saving your workspaces automatically using the following steps:
    • With RStudio running, choose Tools → Global Options from the menus.
    • In the Options dialog, change the value for Save workspace to .RData on exit to Never.
    • Click OK.
  11. Install the petersenlab R package using the following steps:
    • Install the remotes package using the following command: install.packages("remotes")
    • Install the petersenlab package using the following command: remotes::install_github("DevPsyLab/petersenlab")
  12. Request an API token for the following REDCap project(s); note: please check with Dr. P before requesting an API token. In general, RAs should not have an API token.
  13. When your API token has been approved for these projects, open the Encrypt REDCap Token.R script: https://research-git.uiowa.edu/petersenlab/R-InitialSetup/blob/master/REDCap%20Credentials/Encrypt%20REDCap%20Token.R
  14. Revise the API tokens to reflect yours, then run the script to save your encrypted credentials on the lab server and your encryption key on your local computer
    • Verify that the Encryption Key (REDCap Encryption Key.RData) was saved where you intended it to be saved on your local computer
    • Verify that a file named with your HawkID was saved here: //lc-rs-store24.hpc.uiowa.edu/lss_itpetersen/Lab/Studies/School Readiness Study/Data Management/REDCap/Tokens/
  15. Copy the Encryption Key (REDCap Encryption Key.RData) to the comparable location of any other computers you own that you plan to access the data from
    • The file has to be in the comparable location (relative to the path variable you set in Rprofile.site) of every computer in order for it to be found by the Export Data.R script. The default location is: file.path(path, "GitHub/R/Data/REDCap Encryption Key.RData"), so if path is set as "C:/User/YourName", the file would be saved in: C:/User/YourName/GitHub/R/Data/REDCap Encryption Key.RData. The recommended location for GitHub repos is to create a folder titled GitHub in your Documents folder, and to put repos in the GitHub folder; it is NOT recommended to put git repos in a OneDrive folder because git files tend not to play nice with syncing services (archived at https://perma.cc/XZ6F-43G3; e.g., OneDrive, Dropbox)
  16. Add the SRS Data Processing repo from the lab drive to your GitHub Desktop App (//lc-rs-store24.hpc.uiowa.edu/lss_itpetersen/Lab/Studies/School Readiness Study/Data Processing)
  17. Open RStudio by using “Run as Administrator” (always open RStudio as an administrator so it has write access to the program files directory);
  18. Open the Export Data.R script in R: https://research-git.uiowa.edu/petersenlab/srs/SRS-DataProcessing/blob/master/1.%20Export%20Data/Export%20Data.R \\lc-rs-store24.hpc.uiowa.edu\lss_itpetersen\Lab\Studies\School Readiness Study\Data Processing\1. Export Data\Export Data.R
  19. Ensure your HawkID and location of your encryption key in the script are correct, and then run the script to verify that you can export data from REDCap
  20. For antialiased plots in RStudio, change the Graphics backend to Cairo: Tools → Global Options → Graphics

3 Lab Package

The petersenlab package is here: https://devpsylab.github.io/petersenlab. To install the petersenlab package, see instructions here.

4 Install Packages

To install and load R packages, see the instructions here.

5 Update Packages

To update packages, use the following code:

update.packages(checkBuilt = TRUE)

One indication that the packages might not be updating to the latest version is seeing the same packages showing as needing an update after having run the update.packages() function. If this does not update the package(s) to the latest version, you may need to install the latest version of the package(s) from source (see the section on “Initial Set Up” of R for the software needed to install R packages from source):

update.packages(checkBuilt = TRUE, type = "source")

6 Update R

Instructions adapted from: https://mirror.las.iastate.edu/CRAN/bin/windows/base/rw-FAQ.html#What_0027s-the-best-way-to-upgrade_003f (archived at https://perma.cc/W5QW-MA6Q)

  1. Uninstall R
  2. Install the new R version into a directory that contains no spaces (see Step 2 in the Initial Set Up section above)
  3. [You only need to do this step if you installed packages in the R-version-specific “Library” folder rather than the common/shared “Packages” folder—that is, you don’t need to do this step if you used the lab’s Rprofile.site file, as described above, which installs packages to the common/shared “Packages” folder]:
    • Copy installed packages in the “Library” folder to the “Library” folder in the new installation
  4. In new R version folder, copy the current Rprofile.site file as a backup (Rprofile_BACKUP.site) and overwrite the original file with the lab’s version of Rprofile.site from here: https://research-git.uiowa.edu/PetersenLab/R-InitialSetup/-/blob/master/R%20Setup%20Files/Rprofile.site
    • R will run the file named Rprofile.site at initial runtime.
  5. Set the executables for R and RStudio to always run with administrator permissions.
    • If on Windows, open File Explorer and find the main executable of R (C:\R\R-VERSION\bin\R.exe) and RStudio (C:\Program Files\RStudio\bin\RStudio.exe). Right-click it to open the contextual menu. Then, click or tap on “Properties”. In the Properties window, go to the Compatibility tab. At the bottom of the window, check the box next to the “Run this program as an administrator” option, and then click or tap on Apply or OK.
  6. Make sure you have the latest version of the tools necessary to compile packages from source (i.e., Rtools for Windows or R Compiler Tools for Rcpp on MacOS; see the instructions in the section on initial set up)
  7. Open the new R version and run update.packages(checkBuilt = TRUE, ask = FALSE), and install any necessary packages
  8. Close R
  9. Delete anything left of the old installation

7 Style Guide and Best Practices

7.1 Create Rstudio Project

For each data analysis project (i.e., each GitLab/GitHub repo), create an RStudio Project. This helps keep your project files organized.

7.2 Use R Notebooks for “Computational Notebooks”

Using R Notebooks for “Computational Notebooks” is helpful for reproducible code that can be shared with others. To create computational notebooks see the Markdown section on computational notebooks in the Data Analysis guides.

7.3 Separate sections in code

  • In R scripts, use sections.
    • To insert a section in RStudio, use CTRL-Shift-R or “Code” - “Insert Section”
  • In R Notebooks/Markdown, use Headers and code chunks.
    • Headers: 1, 2, or 3 pound signs
    • Code Chunks: Ctrl+Alt+I; or click “Insert” button then “R”

7.4 Naming variables

  • Use meaningful variable names; we want to know what a variable represents without having to consult an external codebook for every variable
  • Variable names should include the prefix for the measure followed by an underscore
    • e.g., cbcl_ for the Child Behavior Checklist variables
  • Use lower camel case for variable naming
    • e.g., prefix_thisIsTheVariableName
  • Do not include spaces in variable names

7.5 Comment code frequently and clearly!

It is important to comment code frequently and clearly. You want you (and others) to easily be able to understand your code if you come back to it several years later!

7.6 Don’t save your workspace image

For reproducibility purposes, it is important not to save your workspace image (archived at https://perma.cc/9SCZ-L4DE). It is best practices to begin R each session with a clean workspace. If there is a .Rdata file in the same folder as the Rstudio Project, Rstudio will automatically load the objects into the workspace at the beginning of the session. This is problematic because those objects can interact/interfere with the code and can lead to problems with replicability for others who are running the code without those objects in the workspace. When you exit RStudio, RStudio asks if you want to “Save workspace image to [filepath]/.Rdata?” Make sure to select “Don’t Save”! However, do make sure to save your R scripts before exiting Rstudio.

8 Data Management

9 Saving Plots

png(); dev.off()

11 Shortcuts

  • Run selected line(s) of code: Ctrl + Enter
  • Comment/uncomment code: Ctrl + Shift + C
  • Pipe: Ctrl + Shift + M
  • Insert Code Chunk: Ctrl + Alt + I
  • Assignment operator: Alt + - (alt-dash)
  • Select multiple lines: Ctrl + Alt, up or down; or Alt + drag mouse
  • Search: Ctrl + Shift + F
  • Show all keyboard shortcuts: Alt + Shift + K

13 Running Scripts Automatically with Windows

https://www.spsanderson.com/steveondata/posts/2023-06-29/index.html (archived at https://perma.cc/9EXK-W99Y)

R scripts can be run automatically. For example, it can be helpful to have an R markdown report run automatically before the day begins.

  1. Open the Notepad app and create a file with the following syntax.
    • Location of R executable file\R CMD BATCH "Path location of script that should be automatically run"
    • Example:
    • C:\R\4.1.3\bin\R CMD BATCH "R:\Lab\Studies\School Readiness Study\Data Processing\5. Reports\automatic_reports\Run_Reports_auto.R"
  2. Save the file as a .bat file in the desired location
  3. Once the .bat file has been created, search Windows Task Scheduler in the search bar task scheduler
  4. In the Actions selection bar, select Create basic Task...
  5. Name the task and provide a description
  6. Next, set the trigger for the new task (i.e., how often the task should run)
  7. Set the action for the task by selecting Start a program
  8. Under, Program/script browse to the .bat file that was created in step 1 and select Next
  9. Click Finish and the script is now configured to run automatically
  10. Note: When R is updated, the path to the bin folder within R needs to be updated to reflect an accurate absolute path to R.
    • Example: C:\R\4.1.3\bin\R CMD BATCH changed to C:\R\4.3.0\bin\R CMD BATCH

13.1 Troubleshooting

13.1.1 Pandoc error

This error may appear if you are attempting to render a markdown file

pandoc version 1.12.3 or higher is required and was not found.

The solution to this problem can be found at this link (archived at https://perma.cc/YX57-BPRS)

14 Reading Password Protected Excel Databases

A helpful post can be found here:

https://stackoverflow.com/questions/35852722/how-do-you-read-a-password-protected-excel-file-into-r (archived at https://perma.cc/U32Z-22VE)

install.packages("excel.link")

library("excel.link")

passwordProtectedBook <- xl.read.file(file.path("full path to workbook"), #Full path to workbook
password = "pass", #password
write.res.password="pass") #writing the reset password

15 Sending slacks with R

Occasionally, it can be helpful to send a Slack message using R. For example, if a script does not run, a Slack message can be sent to inform the appropriate team members. These instructions (archived at https://perma.cc/9CWJ-J5ZT) can largely be followed to set up R to send Slack messages. However, there are some differences:

  1. When setting up the configuration file, use the below template. The slack API token should be placed in the token category.
    • Note the token will need to be updated every 30 days. You can generate a new token by navigating to the Slack API and selecting Oauth & Permissions
    • slack picture
      slack picture
token: YOUR_FULL_API_TOKEN
channel: #general
username: slackr
incoming_webhook_url: https://hooks.slack.com/services/XXXXX/XXXXX/XXXXX

Once the configuration is complete, it is possible to send messages. For now, we have found it helpful to embed the slacks in the tryCatch function.

tryCatch(
CODE YOU WANT TO RUN,
error = function(e)
{
  #message to send if the code doesn't run
  my_message <- paste( "example message")
  slackr_msg(my_message, channel = "#recruitment")
})

15.1 Slacking Specific Users

It is also possible to slack specific users with instructions found at this link (archived at https://perma.cc/59U5-V4GQ).

16 Replacing //n with a space

Many notes in projects that are exported from REDCap come with spaces denotes as //n. Use the below code to make these fields more readable in the future.

gsub('\\n', ', ', df$notesField)

17 Working with R on a Network Drive

When working with R on a network drive, it may be helpful to configure the project to store .Rproj.user on the local C:/ drive rather than on the network drive, which results in slow execution times.

For more info:

18 Package Development

18.1 Working with renv for Package Management

renv is used for reproducibility, by helping with package management (tracking package versions, etc.):

https://rstudio.github.io/renv/articles/renv.html

Before updating a package locally, make sure that it is available in the Posit Package Manager (so it can be available to GitHub Actions):

https://packagemanager.posit.co

18.1.1 Updating the Package

To update the package, run the following in R:

# 1. Update packages in package environment
renv::upgrade()
renv::update()
renv::snapshot()

# 2. Add/edit code

# 3. Update documentation
roxygen2::roxygenise()

# 4. Update package version
usethis::use_version()

Then, build the package: Ctrl-Shift-B

Then, install the package:

renv::install("C:/R/Packages/petersenlab") #PC
renv::install("/Library/Frameworks/R.framework/Packages/petersenlab") #Mac

18.1.2 Installing Packages

To install new packages in the package environment, run the following in R:

renv::install("NAME_OF_PACKAGE")

or:

install.packages("NAME_OF_PACKAGE)

18.2 R CMD check

  1. Build the source package
    • click on the “Build” tab in the top-right pane of RStudio, and then click “Build Source Package”
  2. Open terminal in RStudio
    • After the package is built, open a terminal window directly in RStudio by clicking on the “Terminal” tab at the bottom of RStudio
  3. Run R CMD check --as-cran
    • In the terminal window, navigate to the directory where your package source is located. Then, run R CMD check --as-cran followed by the name of your package tarball. For example:

Build .tar.gz file:

devtools::build(pkg = "D:/Documents/GitHub/petersenlab")
R CMD check --as-cran petersenlab_1.0.0.tar.gz

If errors compiling the PDF manual:

R CMD Rd2pdf . --output=man/figures/manual.pdf --force --no-preview --no-clean

18.2.1 Troubleshooting

18.2.1.1 no visible binding for global variable; Undefined global functions or variables

For example:

no visible binding for global variable
    'moderatorVal_centered'
  Undefined global functions or variables:
    moderatorVal_centered predictorVal_centered

Solution: set each variable to NULL in the package function before it is mentioned. For example:

predictorVal_centered <- moderatorVal_centered <- NULL

18.3 R CMD check via GitHub Actions

usethis::use_github_action("check-standard")

18.4 Useful keyboard shortcuts for package authoring:

Install Package: ‘Ctrl + Shift + B’

Check Package: ‘Ctrl + Shift + E’

Test Package: ‘Ctrl + Shift + T’

renv::install("C:/R/Packages/petersenlab")
renv::snapshot()
renv::install()

18.5 pkgdown

Run once to configure your package to use pkgdown:

usethis::use_pkgdown()

Then use pkgdown to build your website:

pkgdown::build_site()

18.6 Steps to Add Functions

  1. Add .R file with the function
  2. Add the function to the _pkgdown.yml file
  3. Update version number
  4. renv::upgrade()
  5. renv::update()
  6. renv::snapshot()
  7. roxygen2::roxygenise()
  8. Install Package: ‘Ctrl + Shift + B’
  9. Check Package: ‘Ctrl + Shift + E’
  10. R CMD check
  11. Commit and push changes
  12. Update release version in GitHub

18.7 Add sub-packages

devtools::build(pkg = "D:/Documents/GitHub/petersenlab/inst/extdata/testpackage1")
devtools::build(pkg = "D:/Documents/GitHub/petersenlab/inst/extdata/testpackage2")

install.packages("D:/Documents/GitHub/petersenlab/inst/extdata/testpackage1_0.1.0.tar.gz", repos = NULL, source = TRUE)
install.packages("D:/Documents/GitHub/petersenlab/inst/extdata/testpackage2_0.1.0.tar.gz", repos = NULL, source = TRUE)

remotes::install_local("D:/Documents/GitHub/petersenlab/inst/extdata/testpackage2_0.1.0.tar.gz")
remotes::install_local("D:/Documents/GitHub/petersenlab/inst/extdata/testpackage2_0.1.0.tar.gz")

18.8 Submit Package to CRAN

https://cran.r-project.org/submit.html

LS0tCnRpdGxlOiAiUiIKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZSA9IEZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoCiAgZWNobyA9IFRSVUUsCiAgZXJyb3IgPSBUUlVFLAogIGNvbW1lbnQgPSAiIiwKICBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IikKYGBgCgogPiAiKmBSYCB3aWxsIGFsd2F5cyBiZSBhcmNhbmUgdG8gdGhvc2Ugd2hvIGRvIG5vdCBtYWtlIGEgc2VyaW91cyBlZmZvcnQgdG8gbGVhcm4gaXQuIEl0IGlzIG5vdCBtZWFudCB0byBiZSBpbnR1aXRpdmUgYW5kIGVhc3kgZm9yIGNhc3VhbCB1c2VycyB0byBqdXN0IHBsdW5nZSBpbnRvLiBJdCBpcyBmYXIgdG9vIGNvbXBsZXggYW5kIHBvd2VyZnVsIGZvciB0aGF0LiBCdXQgdGhlIHJld2FyZHMgYXJlIGdyZWF0IGZvciBzZXJpb3VzIGRhdGEgYW5hbHlzdHMgd2hvIHB1dCBpbiB0aGUgZWZmb3J0LioiCgrigJQgW0JlcnRvbiBHdW50ZXIgUi1oZWxwIEF1Z3VzdCAyMDA3XShodHRwczovL3d3dy5icm9kcmlndWVzLmNvL2Jsb2cvMjAyMi0wNi0wMi1hcmNhbmUvKSAoYXJjaGl2ZWQgYXQgaHR0cHM6Ly9wZXJtYS5jYy9LWTlOLTJGVFQpCgo+ICJFdmVseW4gSGFsbDogSSB3b3VsZCBsaWtlIHRvIGtub3cgaG93IChpZikgSSBjYW4gZXh0cmFjdCBzb21lIG9mIHRoZSBpbmZvcm1hdGlvbiBmcm9tIHRoZSBzdW1tYXJ5IG9mIG15IG5sbWUuCj4gCj4gU2ltb24gQmxvbWJlcmc6IFRoaXMgaXMgYFJgLiBUaGVyZSBpcyBubyBpZi4gT25seSBob3cuIgoK4oCUIFtFdmVseW4gSGFsbCBhbmQgU2ltb24gJ1lvZGEnIEJsb21iZXJnLCBSLWhlbHAgQXByaWwgMjAwNV0oaHR0cHM6Ly93d3cuYnJvZHJpZ3Vlcy5jby9ibG9nLzIwMjItMDYtMDItYXJjYW5lLykgKGFyY2hpdmVkIGF0IGh0dHBzOi8vcGVybWEuY2MvS1k5Ti0yRlRUKQoKIyBMZWFybmluZyBgUmAgeyNsZWFybn0KCiMjIEJhc2UgUgoKSGVyZSBhcmUgYSBzbGV3IG9mIHJlc291cmNlcyBmb3IgbGVhcm5pbmcgYmFzZSBgUmAgKGluIGFkZGl0aW9uIHRvIHRoZSBkb2N1bWVudHMgaW4gdGhlIGxhYidzIFtQcmltZXIgQXJ0aWNsZXMgZm9sZGVyXShodHRwczovL2RyaXZlLmdvb2dsZS5jb20vZHJpdmUvdS8wL2ZvbGRlcnMvMVUwcE5yakYyX3RJUFU2Qml5Q3YwSHFiT1VBNVA1MTZyKSk6CgotIFVzZSB0aGlzIEludHJvIHRvIGBSYDogaHR0cHM6Ly93d3cuc3RhdG1ldGhvZHMubmV0LyAoYXJjaGl2ZWQgYXQgaHR0cHM6Ly9wZXJtYS5jYy9TUFEyLURKS00pCiAgICAtIEkgdXNlZCB0aGlzIHJlc291cmNlIGNvbnNpZGVyYWJseSB3aGVuIEkgd2FzIGxlYXJuaW5nIGBSYAotIExlYXJuIGhvdyB0byBiZWNvbWUgYSBiZXR0ZXIgY29kZXI6IGh0dHBzOi8vd3d3LnItYmxvZ2dlcnMuY29tLzEwLXRvcC10aXBzLWZvci1iZWNvbWluZy1hLWJldHRlci1jb2Rlci8gKGFyY2hpdmVkIGF0IGh0dHBzOi8vcGVybWEuY2MvSDNXNy1RREFNKQotIEhvdyB0byBiZWNvbWUgZmx1ZW50IGluIGBSYDogaHR0cHM6Ly93d3cuc2hhcnBzaWdodGxhYnMuY29tL2Jsb2cvYXJlLXlvdS1mbHVlbnQtci8gKGFyY2hpdmVkIGF0IGh0dHBzOi8vcGVybWEuY2MvUldMNS1HVFdWKQotIFZpZGVvIHRyYWluaW5nIGNvdXJzZXMgaW4gYFJgIHNraWxsczogaHR0cHM6Ly93d3cucGx1cmFsc2lnaHQuY29tL3NlYXJjaD9xPVIgKGFyY2hpdmVkIGF0IGh0dHBzOi8vcGVybWEuY2MvVTRaWi1VRTRYKQotIEJyb3dzZSB0aGUgYENvb2tib29rIGZvciBSYCB0byBmaW5kIHNvbHV0aW9ucyB0byBjb21tb24gdGFza3MgYW5kIHByb2JsZW1zOiBodHRwOi8vd3d3LmNvb2tib29rLXIuY29tLyAoYXJjaGl2ZWQgYXQgaHR0cHM6Ly9wZXJtYS5jYy81RVJKLVZSRlIpCi0gQnJvd3NlIHRoZSBgUiBHcmFwaCBHYWxsZXJ5YCB0byBmaW5kIGV4YW1wbGVzIG9mIHZhcmlvdXMgZ3JhcGhzOiA8aHR0cHM6Ly9yLWdyYXBoLWdhbGxlcnkuY29tPgotIEZyZWUgYENvZGVhY2FkZW15YCBjb3Vyc2Ugb24gYFJgOiBodHRwczovL3d3dy5jb2RlY2FkZW15LmNvbS9sZWFybi9sZWFybi1yIChhcmNoaXZlZCBhdCBodHRwczovL3Blcm1hLmNjL0pIUzItRVlVVSkKLSBGcmVlIGBDb3Vyc2VyYWAgY291cnNlcyBvbiBgUmA6IGh0dHBzOi8vcGFpcmFjaC5jb20vMjAxMi8xMi8yMi9sZWFybi10by11c2Utci1mb3ItZnJlZS13aXRoLWNvdXJzZXJhLyAoYXJjaGl2ZWQgYXQgaHR0cHM6Ly9wZXJtYS5jYy9YSjVVLTVFNFcpCi0gTU9PQ3MgYW5kIGNvdXJzZXMgdG8gbGVhcm4gYFJgOiBodHRwczovL3d3dy5yLWJsb2dnZXJzLmNvbS9tb29jcy1hbmQtY291cnNlcy10by1sZWFybi1yLyAoYXJjaGl2ZWQgYXQgaHR0cHM6Ly9wZXJtYS5jYy9NUTI1LUUzTUUpCi0gV2F0Y2ggdGhlc2UgdmlkZW9zIGZyb20gYENvdXJzZXJhYDogaHR0cHM6Ly9ibG9nLnJldm9sdXRpb25hbmFseXRpY3MuY29tLzIwMTIvMTIvY291cnNlcmEtdmlkZW9zLmh0bWwgKGFyY2hpdmVkIGF0IGh0dHBzOi8vcGVybWEuY2MvNkZVNC1QQVFXKQotIGBSU3R1ZGlvYCBXZWJpbmFyczogaHR0cHM6Ly93d3cucnN0dWRpby5jb20vcmVzb3VyY2VzL3dlYmluYXJzLyAoYXJjaGl2ZWQgYXQgaHR0cHM6Ly9wZXJtYS5jYy82Uk5SLTk4SkIpCi0gVUNMQSBTdGF0cyBXZWJzaXRlOiBodHRwczovL3N0YXRzLmlkcmUudWNsYS5lZHUvci8gKGFyY2hpdmVkIGF0IGh0dHBzOi8vcGVybWEuY2MvTTNONi05NlJZKQotIFRha2UgdGhpcyBJbnRyb2R1Y3Rpb24gdG8gYFJgIGNvdXJzZTogaHR0cHM6Ly93d3cuZGF0YWNhbXAuY29tL2NvdXJzZXMvZnJlZS1pbnRyb2R1Y3Rpb24tdG8tciAoYXJjaGl2ZWQgYXQgaHR0cHM6Ly9wZXJtYS5jYy82Wk05LTM3TDkpCi0gVGVhY2hpbmcgYFJgIGluIGEgS2luZGVyLCBHZW50bGVyLCBNb3JlIEVmZmVjdGl2ZSBNYW5uZXI6IGh0dHBzOi8vZ2l0aHViLmNvbS9tYXRsb2ZmL1RpZHl2ZXJzZVNrZXB0aWMgKGFyY2hpdmVkIGF0IGh0dHBzOi8vcGVybWEuY2MvUVU5Ri1GQlM4KQotIExlYXJuIGBSYCBpbnRlcmFjdGl2ZWx5IHdpdGggYHN3aXJsYDogaHR0cHM6Ly9zd2lybHN0YXRzLmNvbS8gKGFyY2hpdmVkIGF0IGh0dHBzOi8vcGVybWEuY2MvVFQ5Vi1VNjYzKQotIFVzZSB0aGUgYGxlYXJucmAgcGFja2FnZTogaHR0cHM6Ly9ibG9nLnJzdHVkaW8uY29tLzIwMTcvMDcvMTEvaW50cm9kdWNpbmctbGVhcm5yLyAoYXJjaGl2ZWQgYXQgaHR0cHM6Ly9wZXJtYS5jYy9YR0o4LUVYU04pCi0gWW91IHdpbGwgc29tZXRpbWVzIGZpbmQgcmVsZXZhbnQgYXJ0aWNsZXMgb24gYFItYmxvZ2dlcnNgOiBodHRwczovL3d3dy5yLWJsb2dnZXJzLmNvbS8gKGFyY2hpdmVkIGF0IGh0dHBzOi8vcGVybWEuY2MvRUwzWC1aWEJCKQoKIyMgU3RhdGlzdGljcyAodXNpbmcgYFJgKQoKVGhlIGZvbGxvd2luZyBhcmUgcmVzb3VyY2VzIGZvciBsZWFybmluZyBzdGF0aXN0aWNzIHVzaW5nIGBSYC4KCi0gVUNMQSBTdGF0cyBXZWJzaXRlOiBodHRwczovL3N0YXRzLm9hcmMudWNsYS5lZHUvb3RoZXIvZGFlLyAoYXJjaGl2ZWQgYXQgaHR0cHM6Ly9wZXJtYS5jYy9GVkc1LTVYODIpCi0gRnJlZSB0ZXh0Ym9vayBvbiBMZWFybmluZyBTdGF0aXN0aWNzIHdpdGggYFJgOiBodHRwczovL2xlYXJuaW5nc3RhdGlzdGljc3dpdGhyLmNvbSAoYXJjaGl2ZWQgYXQgaHR0cHM6Ly9wZXJtYS5jYy9TWTg3LTVHQ1gpCi0gQW4gZXhjZWxsZW50IGludHJvZHVjdG9yeSB0ZXh0Ym9vayBvbiBEaXNjb3ZlcmluZyBTdGF0aXN0aWNzIHVzaW5nIGBSYDogaHR0cHM6Ly93d3cuYW1hem9uLmNvbS9EaXNjb3ZlcmluZy1TdGF0aXN0aWNzLVVzaW5nLUFuZHktRmllbGQvZHAvMTQ0NjIwMDQ2OSAoYXJjaGl2ZWQgYXQgaHR0cHM6Ly9wZXJtYS5jYy85TEdVLTdaTUUpCgojIyBgdGlkeXZlcnNlYAoKVGhlIGZvbGxvd2luZyBhcmUgcmVzb3VyY2VzIGZvciBsZWFybmluZyBgdGlkeXZlcnNlYCwgd2hpY2ggaXMgYSBjb2xsZWN0aW9uIG9mIGBSYCBwYWNrYWdlcyBmb3IgZGF0YSBtYW5hZ2VtZW50OgoKLSBodHRwczovL3d3dy50aWR5dmVyc2Uub3JnL2xlYXJuLyAoYXJjaGl2ZWQgYXQgaHR0cHM6Ly9wZXJtYS5jYy81WlVNLVhHRVMpCgotIGh0dHBzOi8vd3d3LmxpbmtlZGluLmNvbS9sZWFybmluZy9sZWFybmluZy10aGUtci10aWR5dmVyc2Uvd2VsY29tZT91PTQyNDU5MDIwIChhcmNoaXZlZCBhdCBodHRwczovL3Blcm1hLmNjL1RENTYtRlg4UikKCiMjIFF1ZXN0aW9ucwoKSWYgeW91IGhhdmUgcXVlc3Rpb25zOgoKLSBQb3N0IHRvIHRoZSBgUmAgbWFpbGluZyBsaXN0OiBodHRwczovL3N0YXQuZXRoei5jaC9tYWlsbWFuL2xpc3RpbmZvL3ItaGVscAotIFBvc3QgdG8gZm9ydW1zOiBodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy90YWdnZWQvcgotIE1vcmUgaW5mbzogaHR0cHM6Ly93d3cuci1ibG9nZ2Vycy5jb20vd2hlcmUtdG8tZ2V0LWhlbHAtd2l0aC15b3VyLXItcXVlc3Rpb24vIChhcmNoaXZlZCBhdCBodHRwczovL3Blcm1hLmNjL1A1VFctRTdIUCkKCiMgSW5pdGlhbCBTZXQgVXAgeyNzZXR1cH0KCk5vdGU6IG1hbnkgb2YgdGhlc2UgaW5pdGlhbCBzZXR1cCBzdGVwcyBkZXNjcmliZWQgYmVsb3cgYXJlIG5vdCBuZWNlc3NhcnkgZm9yIGdlbmVyYWwgdXNlOyBtYW55IG9mIHRoZXNlIHN0ZXBzIGFyZSBuZWNlc3Nhcnkgb25seSBmb3IgdXNpbmcgbGFiLXJlbGF0ZWQgcmVwb3NpdG9yaWVzIChlLmcuLCB0byBnYWluIEFQSSBhY2Nlc3MgdG8gZXhwb3J0IGRhdGEgZnJvbSBgUkVEQ2FwYCwgdG8gdXNlIGFic29sdXRlIHBhdGhzIHJhdGhlciB0aGFuIHJlbGF0aXZlIHBhdGhzIHNvIHJlcG9zIGNhbiBjb21tdW5pY2F0ZSB3aXRoIGVhY2ggb3RoZXIsIGV0Yy4pLgoKMS4gTWFrZSBzdXJlIHlvdSBhcmUgbG9nZ2VkIG9udG8gYSBjb21wdXRlciB0aGF0IGNhbiBhY2Nlc3MgdGhlIGxhYiBzZXJ2ZXIgKGVpdGhlciBhIGxhYiBjb21wdXRlciwgb3IgYSBjb21wdXRlciB5b3UgY2FuIFZQTiBpbnRvIHRoZSBsYWIgc2VydmVyKSwgYW5kIHRoYXQgeW91IGhhdmUgYWRtaW4gYWNjZXNzIHRvIGluc3RhbGwgYW5kIHVuaW5zdGFsbCBzb2Z0d2FyZQoxLiBJbnN0YWxsIGBSYCAoaHR0cHM6Ly93d3cuci1wcm9qZWN0Lm9yZy8pIGludG8gYSBkaXJlY3RvcnkgdGhhdCBjb250YWlucyBubyBzcGFjZXM7IE9uIFBDLCBjaGFuZ2UgdGhlIGxvY2F0aW9uIGZyb20gdGhlIGRlZmF1bHQgYEM6L1Byb2dyYW0gRmlsZXMvUi9bUi1WRVJTSU9OXWAgKHdoaWNoIGNvbnRhaW5zIGEgc3BhY2UpIHRvIGBDOi9SL1tSLVZFUlNJT05dYCAoW3doaWNoIGRvZXMgbm90IGNvbnRhaW4gYW55IHNwYWNlc10oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvZG9jL21hbnVhbHMvci1yZWxlYXNlL1ItYWRtaW4uaHRtbCNJbnN0YWxsaW5nLVItdW5kZXItV2luZG93cyk7IGFyY2hpdmVkIGF0IGh0dHBzOi8vcGVybWEuY2MvNlZNWC0zTFlYLS0tdGhpcyBpcyBiZWNhdXNlIFtzb21lIHBhY2thZ2VzIHRoYXQgcmVxdWlyZSBjb21waWxhdGlvbiB0byBpbnN0YWxsIGNhbm5vdCByZWFkIGZpbGVwYXRocyB3aXRoIHNwYWNlc10oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvZG9jL21hbnVhbHMvci1yZWxlYXNlL1ItYWRtaW4uaHRtbCNJbnN0YWxsYXRpb24pOyBhcmNoaXZlZCBhdCBodHRwczovL3Blcm1hLmNjL1hBM1YtSlRQWSk7IG1heSBoYXZlIHRvIHJpZ2h0IGNsaWNrIGFuZCAiUnVuIEFzIEFkbWluaXN0cmF0b3IiCiAgICAtIElmIGBSYCB3YXMgYWxyZWFkeSBpbnN0YWxsZWQgaW4gYSBkaXJlY3RvcnkgdGhhdCBjb250YWlucyBzcGFjZXMgKGUuZy4sIGBDOi9Qcm9ncmFtIEZpbGVzL1IvW1ItVkVSU0lPTl1gKSwgdW5pbnN0YWxsIGBSYCBiZWZvcmUgaW5zdGFsbGluZyBpdCBpbiBhIGRpcmVjdG9yeSB0aGF0IGRvZXNuJ3QgY29udGFpbiBzcGFjZXMKMS4gSW5zdGFsbCBgUlN0dWRpb2AgRGVza3RvcCAoaHR0cHM6Ly93d3cucnN0dWRpby5jb20vcHJvZHVjdHMvcnN0dWRpby9kb3dubG9hZC8pIGluIHRoZSBtYWluIHByb2dyYW0gZmlsZXMgZGlyZWN0b3J5OyBtYXkgaGF2ZSB0byByaWdodCBjbGljayBhbmQgIlJ1biBBcyBBZG1pbmlzdHJhdG9yIi4KYFJTdHVkaW9gIGlzIHRoZSBiZXN0IGF2YWlsYWJsZSBncmFwaGljYWwgdXNlciBpbnRlcmZhY2UgZm9yIFIuCjEuIFNldCB0aGUgZXhlY3V0YWJsZXMgZm9yIGBSYCBhbmQgYFJTdHVkaW9gIHRvIGFsd2F5cyBydW4gd2l0aCBhZG1pbmlzdHJhdG9yIHBlcm1pc3Npb25zLgogICAgLSBJZiBvbiBXaW5kb3dzLCBvcGVuIEZpbGUgRXhwbG9yZXIgYW5kIGZpbmQgdGhlIG1haW4gZXhlY3V0YWJsZSBvZiBgUmAgKGBDOi9SL1tSLVZFUlNJT05dL2Jpbi9SLmV4ZWApIGFuZCBgUlN0dWRpb2AgKGBDOlxQcm9ncmFtIEZpbGVzXFJTdHVkaW9cYmluXFJTdHVkaW8uZXhlYCkuCiAgICBSaWdodC1jbGljayBpdCB0byBvcGVuIHRoZSBjb250ZXh0dWFsIG1lbnUuCiAgICBUaGVuLCBjbGljayBvciB0YXAgb24gIlByb3BlcnRpZXMiLgogICAgSW4gdGhlIFByb3BlcnRpZXMgd2luZG93LCBnbyB0byB0aGUgQ29tcGF0aWJpbGl0eSB0YWIuCiAgICBBdCB0aGUgYm90dG9tIG9mIHRoZSB3aW5kb3csIGNoZWNrIHRoZSBib3ggbmV4dCB0byB0aGUgIlJ1biB0aGlzIHByb2dyYW0gYXMgYW4gYWRtaW5pc3RyYXRvciIgb3B0aW9uLCBhbmQgdGhlbiBjbGljayBvciB0YXAgb24gQXBwbHkgb3IgT0suCjEuIEluc3RhbGwgdG9vbHMgdG8gYWxsb3cgeW91IHRvIGNvbXBpbGUgYFJgIHBhY2thZ2VzIHNvIHlvdSBjYW4gaW5zdGFsbCBwYWNrYWdlcyBmcm9tIHNvdXJjZSwgaWYgbmVjZXNzYXJ5IChpLmUuLCBpZiBwYWNrYWdlIGJpbmFyaWVzIGFyZSBub3QgYXZhaWxhYmxlKToKICAgIC0gSWYgb24gV2luZG93cywgaW5zdGFsbCBbUnRvb2xzXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy9iaW4vd2luZG93cy9SdG9vbHMvKTsgbWF5IGhhdmUgdG8gcmlnaHQgY2xpY2sgYW5kICJSdW4gQXMgQWRtaW5pc3RyYXRvciIKICAgIC0gSWYgb24gTWFjLCBpbnN0YWxsIFtSIENvbXBpbGVyIFRvb2xzIGZvciBSY3BwIG9uIE1hY09TXShodHRwczovL3RoZWNvYXRsZXNzcHJvZmVzc29yLmNvbS9wcm9ncmFtbWluZy9jcHAvci1jb21waWxlci10b29scy1mb3ItcmNwcC1vbi1tYWNvcy8pIChhcmNoaXZlZCBhdCBodHRwczovL3Blcm1hLmNjL0IzNUotUjIyWCkKMS4gU2V0IHVwIGBnaXRgLCBgR2l0TGFiYCwgYW5kIHRoZSBgR2l0SHViIERlc2t0b3BgIEFwcCBpbiB0aGUgbWFpbiBwcm9ncmFtIGZpbGVzIGRpcmVjdG9yeTsgbWF5IGhhdmUgdG8gcmlnaHQgY2xpY2sgYW5kICJSdW4gQXMgQWRtaW5pc3RyYXRvciI7IEZvciBpbnN0cnVjdGlvbnMgc2V0dGluZyB1cCBhbmQgdXNpbmcgYEdpdExhYmAsIHNlZSBoZXJlOiBodHRwczovL2RldnBzeWxhYi5naXRodWIuaW8vRGF0YUFuYWx5c2lzL2dpdC5odG1sI3RvQmVnaW4KMS4gVGhlIGBScHJvZmlsZS5zaXRlYCBmaWxlIGluIHRoZSBgZXRjYCBmb2xkZXIgb2YgdGhlIGBSYCBpbnN0YWxsYXRpb24gZGlyZWN0b3J5IGlzIHRoZSBjb2RlIHRoYXQgaXMgcnVuIGZvciAqKipldmVyeSB1c2VyKioqIGF0IHRoZSBiZWdpbm5pbmcgZWFjaCB0aW1lIHlvdSBsb2FkIFIuICBXZSB3aWxsIHVwZGF0ZSB0aGUgZGVmYXVsdCBgUnByb2ZpbGUuc2l0ZWAgZmlsZSB3aXRoIHRoZSBsYWIncyBgUnByb2ZpbGUuc2l0ZWAgZmlsZSBzbyBgUmAgaW5zdGFsbHMgcGFja2FnZXMgaW4gdGhlIGNvcnJlY3QgbG9jYXRpb24sIHNldHMgdGhlIGRlZmF1bHQgcGFja2FnZSByZXBvc2l0b3J5LCB1cGRhdGVzIHBhY2thZ2VzLCBhbmQgZ2l2ZXMgeW91IGEgZm9ydHVuZSBjb29raWUuClRvIGRvIHRoaXMsIHBlcmZvcm0gdGhlIGZvbGxvd2luZyBzdGVwczoKICAgIC0gUmVuYW1lIHRoZSBgUnByb2ZpbGUuc2l0ZWAgZmlsZSBpbiB0aGUgYFJgIGluc3RhbGxhdGlvbiBkaXJlY3RvcnkgKGBDOi9SL1ItW0luc2VydFZlcnNpb25OdW1iZXJdL2V0Yy9ScHJvZmlsZS5zaXRlYCkgdG8gYmUgYFJwcm9maWxlX0JBQ0tVUC5zaXRlYAogICAgLSBEb3dubG9hZCB0aGUgbGFiJ3MgYFJwcm9maWxlLnNpdGVgIGZpbGUgbG9jYXRlZCBpbiB0aGlzIHJlcG9zaXRvcnkgYXQgdGhlIGZvbGxvd2luZyBsb2NhdGlvbiAoaHR0cHM6Ly9yZXNlYXJjaC1naXQudWlvd2EuZWR1L1BldGVyc2VuTGFiL1ItSW5pdGlhbFNldHVwLy0vYmxvYi9tYXN0ZXIvUiUyMFNldHVwJTIwRmlsZXMvUnByb2ZpbGUuc2l0ZSksIGFuZCBwYXN0ZSBpdCBpbnRvIHRoZSBgUmAgaW5zdGFsbGF0aW9uIGRpcmVjdG9yeSAoUEM6IGBDOi9SL1ItW0luc2VydFZlcnNpb25OdW1iZXJdL2V0Yy9ScHJvZmlsZS5zaXRlYDsgTWFjOiBgL0xpYnJhcnkvRnJhbWV3b3Jrcy9SLmZyYW1ld29yay9WZXJzaW9ucy9bSW5zZXJ0VmVyc2lvbk51bWJlcl0vUmVzb3VyY2VzL2V0Yy9ScHJvZmlsZS5zaXRlYCkKMS4gVGhlIGAuUnByb2ZpbGVgIGZpbGUgaW4gdGhlIHVzZXIncyBgRG9jdW1lbnRzYCBmb2xkZXIgaXMgdGhlIGNvZGUgdGhhdCBpcyBydW4gZm9yICoqKnRoZSBwYXJ0aWN1bGFyIHVzZXIqKiogYXQgdGhlIGJlZ2lubmluZyBlYWNoIHRpbWUgeW91IGxvYWQgUi4KV2Ugd2lsbCB1cGRhdGUgdGhlIGRlZmF1bHQgYC5ScHJvZmlsZWAgZmlsZSAoaWYgdGhlcmUgaXMgb25lKSB3aXRoIHRoZSBsYWIncyBgLlJwcm9maWxlYCBmaWxlIHNvIGBSYCBrbm93cyB3aGljaCBjb21wdXRlciB5b3UgYXJlIHVzaW5nIGFuZCB3aGljaCBwYXRoIHRvIHVzZSAocmVsYXRpdmUgdG8gd2hlcmUgeW91ciBgUmAgcHJvamVjdHMgYXJlIGxvY2F0ZWQpLgpUbyBkbyB0aGlzLCBwZXJmb3JtIHRoZSBmb2xsb3dpbmcgc3RlcHM6CiAgICAtIERvd25sb2FkIHRoZSBsYWIncyBgLlJwcm9maWxlYCB0ZW1wbGF0ZSBmaWxlIGluIHRoaXMgcmVwb3NpdG9yeSBhdCB0aGUgZm9sbG93aW5nIGxvY2F0aW9uLCBhbmQgbWFrZSBzdXJlIHRvIHJlbW92ZSBhbnl0aGluZyBiZXNpZGVzIGAuUnByb2ZpbGVgIGluIHRoZSBmaWxlbmFtZTogaHR0cHM6Ly9yZXNlYXJjaC1naXQudWlvd2EuZWR1L1BldGVyc2VuTGFiL1ItSW5pdGlhbFNldHVwLy0vYmxvYi9tYXN0ZXIvUiUyMFNldHVwJTIwRmlsZXMvLlJwcm9maWxlCiAgICAtIE9wZW4gdGhlIGxhYidzIGAuUnByb2ZpbGVgIGZpbGUsIGFuZCByZXZpc2UgaXQgd2l0aCB5b3VyIEhhd2tJRAogICAgLSBSZXZpc2UgdGhlIGxhYidzIGAuUnByb2ZpbGVgIGZpbGUgd2l0aCB0aGUgbG9jYWwgcGF0aCB0byB0aGUgYERvY3VtZW50c2AgZm9sZGVyIGZvciBlYWNoIG9mIHRoZSBjb21wdXRlcnMgeW91IHdpbGwgdXNlIHRvIGFjY2VzcyBgUmAgKGUuZy4sIGhvbWUgY29tcHV0ZXIsIHdvcmsgY29tcHV0ZXIsIGxhcHRvcCkuCiAgICBNYWtlIHN1cmUgdG8gdXNlIGZvcndhcmQgc2xhc2hlcyAoYC9gKSwgbm90IGJhY2sgc2xhc2hlcyAoYFxgKSBpbiB0aGUgcGF0aC4KICAgIC0gWW91IHdpbGwgc2F2ZSB0aGUgZmlsZSBpbiB5b3VyIGBIT01FYCBkaXJlY3RvcnkuCiAgICBUbyBmaW5kIHRoZSBgSE9NRWAgZGlyZWN0b3J5LCBvcGVuIGBSYCBhbmQgdHlwZSB0aGUgZm9sbG93aW5nIGNvbW1hbmQ6IGBTeXMuZ2V0ZW52KCJIT01FIilg4oCUdGhlIG91dHB1dCBvZiB0aGUgY29tbWFuZCBpcyB0aGUgbG9jYXRpb24gb2YgeW91ciBgSE9NRWAgZGlyZWN0b3J5OyBJZiB0aGlzIGlzIGEgbGFiIGNvbXB1dGVyLCBpdCBtYXkgYmUgbG9jYXRlZCBoZXJlOiBgLy9ob21lLmlvd2EudWlvd2EuZWR1L1t1c2VyXS9Eb2N1bWVudHNgLgogICAgSWYgdGhpcyBpcyB5b3VyIHBlcnNvbmFsIGNvbXB1dGVyLCBpdCBtYXkgYmUgbG9jYXRlZCBoZXJlOiBQQzogYEM6L1VzZXJzL1t1c2VyXS9Eb2N1bWVudHNgOyBNYWM6IGAvVXNlcnMvW3VzZXJdYC4KICAgIFRoZW4gY2xvc2UgUi4KICAgIC0gSWYgeW91ciBgSE9NRWAgZGlyZWN0b3J5IGlzIGluIGEgT25lRHJpdmUgZm9sZGVyIChvciBhbm90aGVyIGNsb3VkLWJhc2VkIHN5bmMgZm9sZGVyKSwgeW91IHdpbGwgd2FudCB0byBjaGFuZ2UgdGhlIGRpcmVjdG9yeSBvZiB5b3VyIGBIT01FYCBwYXRoIHNvIHRoYXQgaXQgaXMgbm90IGluIGEgT25lRHJpdmUgZm9sZGVyLgogICAgVG8gZG8gdGhhdCwgb3BlbiBbYEVudmlyb25tZW50IFZhcmlhYmxlc2BdKGh0dHBzOi8vc3VwZXJ1c2VyLmNvbS9xdWVzdGlvbnMvOTQ5NTYwL2hvdy1kby1pLXNldC1zeXN0ZW0tZW52aXJvbm1lbnQtdmFyaWFibGVzLWluLXdpbmRvd3MtMTApIChhcmNoaXZlZCBhdCBodHRwczovL3Blcm1hLmNjL0EyRTUtQjVWQSkgaW4gV2luZG93cy4KICAgIFRoZW4sIGFkZC9lZGl0IGBIT01FYCBhcyB0aGUgInZhcmlhYmxlIG5hbWUiIHdpdGggdGhlIGludGVuZGVkIGxvY2F0aW9uIGFzIHRoZSAidmFyaWFibGUgdmFsdWUiIChlLmcuLCBgQzovVXNlcnMvW3VzZXJdL0RvY3VtZW50c2AsIHdoZXJlIHlvdSByZXBsYWNlICJ1c2VyIiB3aXRoIHlvdXIgSGF3a0lEKS4KICAgICAgICAtIFlvdSBtYXkgYWxzbyBzb2x2ZSB0aGlzIGlzc3VlIGJ5IHBsYWNpbmcgdGhlIGZvbGxvd2luZyBjb21tYW5kIGluIHRoZSBgUnByb2ZpbGUuc2l0ZWAgZnJvbSB0aGUgcHJldmlvdXMgc3RlcAogICAgICAgICAgICAtIGBTeXMuc2V0ZW52KCJIT01FIiA9ICJDOi9Vc2Vycy9bc3BlY2lmaWMgdXNlciBJRF0pL0RvY3VtZW50cyIpYAogICAgLSBNb3ZlIHRoZSByZXZpc2VkIGAuUnByb2ZpbGVgIGZpbGUgdG8gdGhlIGBIT01FYCBkaXJlY3RvcnkgYW5kIG92ZXJ3cml0ZSB0aGUgb3JpZ2luYWwgYC5ScHJvZmlsZWAgZmlsZSAoaWYgaXQgZXhpc3RzKS4KICAgIFlvdSBtYXkgaGF2ZSB0byBzaG93IGhpZGRlbiBmaWxlcyBpbiBvcmRlciB0byBzZWUgdGhlIGZpbGUgKFBDOiBzZWUgV2luZG93cyBFeHBsb3JlciBzZXR0aW5nczsgTWFjOiBDb21tYW5kK1NoaWZ0K0RvdCkuCiAgICAtIE1ha2Ugc3VyZSB0byBzaG93IGZpbGVuYW1lIGV4dGVuc2lvbnMgaW4geW91ciBmaWxlIGV4cGxvcmVyIHdpbmRvdywgYW5kIG1ha2Ugc3VyZSB0aGUgZmlsZSBpcyBuYW1lZCBgLlJwcm9maWxlYCAobm90IGAuUnByb2ZpbGUuUnByb2ZpbGVgKS4KICAgIE1ha2Ugc3VyZSB0aGVyZSBpcyBhIHBlcmlvZCBhdCB0aGUgYmVnaW5uaW5nIG9mIHRoZSBmaWxlbmFtZS4KMS4gUnVuIGBSU3R1ZGlvYC4KSWYgdGhlIGBScHJvZmlsZS5zaXRlYCBhbmQgYC5ScHJvZmlsZWAgZmlsZXMgYXJlIGNvcnJlY3RseSBzZXQgdXAsIHRoZXkgc2hvdWxkIHByZS1wb3B1bGF0ZSB5b3VyIGBwYXRoYCBsb2NhdGlvbiB3aGVuIHlvdSBvcGVuIFIuCklmIHRoZSBjb250ZW50cyBvZiB0aGUgYEdsb2JhbCBFbnZpcm9ubWVudGAgaW4gYFJTdHVkaW9gIGFyZSBlbXB0eSwgeW91ciBgUnByb2ZpbGUuc2l0ZWAgYW5kL29yIGAuUnByb2ZpbGVgIGZpbGVzIGFyZSBub3Qgc2V0IHVwIGNvcnJlY3RseS4KICAgIC0gSWYgeW91IGdldCB0aGlzIGVycm9yIChgRXJyb3I6IGNvdWxkIG5vdCBmaW5kIGZ1bmN0aW9uICJpbnN0YWxsLnBhY2thZ2VzImApLCBydW4gdGhlIGZvbGxvd2luZyBsaW5lIG1hbnVhbGx5IGFuZCB0aGVuIHJlc3RhcnQgYFJTdHVkaW9gIGFmdGVyIHRoZSBwYWNrYWdlIGZpbmlzaGVzIGluc3RhbGxpbmc6IGBpbnN0YWxsLnBhY2thZ2VzKCJmb3J0dW5lcyIpYAoxLiBGb3IgW3JlcHJvZHVjaWJpbGl0eSBwdXJwb3Nlc10oI2RvbnRTYXZlV29ya3NwYWNlKSwgcHJldmVudCBgUmAvYFJTdHVkaW9gIGZyb20gc2F2aW5nIHlvdXIgd29ya3NwYWNlcyBhdXRvbWF0aWNhbGx5IHVzaW5nIHRoZSBmb2xsb3dpbmcgc3RlcHM6CiAgICAtIFdpdGggUlN0dWRpbyBydW5uaW5nLCBjaG9vc2UgYFRvb2xzIOKGkiBHbG9iYWwgT3B0aW9uc2AgZnJvbSB0aGUgbWVudXMuCiAgICAtIEluIHRoZSBPcHRpb25zIGRpYWxvZywgY2hhbmdlIHRoZSB2YWx1ZSBmb3IgYFNhdmUgd29ya3NwYWNlIHRvIC5SRGF0YSBvbiBleGl0YCB0byBgTmV2ZXJgLgogICAgLSBDbGljayBgT0tgLgoxLiBJbnN0YWxsIHRoZSBgcGV0ZXJzZW5sYWJgIGBSYCBwYWNrYWdlIHVzaW5nIHRoZSBmb2xsb3dpbmcgc3RlcHM6CiAgICAtIEluc3RhbGwgdGhlIGByZW1vdGVzYCBwYWNrYWdlIHVzaW5nIHRoZSBmb2xsb3dpbmcgY29tbWFuZDogYGluc3RhbGwucGFja2FnZXMoInJlbW90ZXMiKWAKICAgIC0gSW5zdGFsbCB0aGUgYHBldGVyc2VubGFiYCBwYWNrYWdlIHVzaW5nIHRoZSBmb2xsb3dpbmcgY29tbWFuZDogYHJlbW90ZXM6Omluc3RhbGxfZ2l0aHViKCJEZXZQc3lMYWIvcGV0ZXJzZW5sYWIiKWAKMS4gUmVxdWVzdCBhbiBbQVBJIHRva2VuXShodHRwczovL3JlZGNhcC5pY3RzLnVpb3dhLmVkdS9yZWRjYXAvYXBpL2hlbHAvP2NvbnRlbnQ9dG9rZW5zKSBmb3IgdGhlIGZvbGxvd2luZyBSRURDYXAgcHJvamVjdChzKTsgbm90ZTogcGxlYXNlIGNoZWNrIHdpdGggRHIuIFAgYmVmb3JlIHJlcXVlc3RpbmcgYW4gQVBJIHRva2VuLgpJbiBnZW5lcmFsLCBSQXMgc2hvdWxkIG5vdCBoYXZlIGFuIEFQSSB0b2tlbi4KICAgIC0gW1NjaG9vbCBSZWFkaW5lc3MgU3R1ZHldKGh0dHBzOi8vcmVkY2FwLmljdHMudWlvd2EuZWR1L3JlZGNhcC9yZWRjYXBfdjEyLjQuMS9pbmRleC5waHA/cGlkPTQ5NDEpCiAgICAtIFtTY2hvb2wgUmVhZGluZXNzIFN0dWR5IFNjcmVlbmluZ10oaHR0cHM6Ly9yZWRjYXAuaWN0cy51aW93YS5lZHUvcmVkY2FwL3JlZGNhcF92MTIuNC4xL2luZGV4LnBocD9waWQ9NDk1OCkKICAgIC0gWzIwMTcwMTgzNyAtIE1lY2hhbmlzbXMgaW4gdGhlIERldmVsb3BtZW50IG9mIFNlbGYtUmVndWxhdGlvbiwgU2Nob29sIFJlYWRpbmVzcywgYW5kIEJlaGF2aW9yIFByb2JsZW1zIFtEYXRhIEV4dHJhY3Rpb25dXShodHRwczovL3JlZGNhcC5pY3RzLnVpb3dhLmVkdS9yZWRjYXAvcmVkY2FwX3YxMi40LjEvaW5kZXgucGhwP3BpZD0xMTIzMykKICAgIC0gW1NjaG9vbCBSZWFkaW5lc3MgU3R1ZHkgLSBQcm9zcGVjdGl2ZSBQYXJ0aWNpcGFudHNdKGh0dHBzOi8vcmVkY2FwLmljdHMudWlvd2EuZWR1L3JlZGNhcC9yZWRjYXBfdjEyLjQuMS9pbmRleC5waHA/cGlkPTEwNDQwKQoxLiBXaGVuIHlvdXIgQVBJIHRva2VuIGhhcyBiZWVuIGFwcHJvdmVkIGZvciB0aGVzZSBwcm9qZWN0cywgb3BlbiB0aGUgYEVuY3J5cHQgUkVEQ2FwIFRva2VuLlJgIHNjcmlwdDoKaHR0cHM6Ly9yZXNlYXJjaC1naXQudWlvd2EuZWR1L3BldGVyc2VubGFiL1ItSW5pdGlhbFNldHVwL2Jsb2IvbWFzdGVyL1JFRENhcCUyMENyZWRlbnRpYWxzL0VuY3J5cHQlMjBSRURDYXAlMjBUb2tlbi5SCjEuIFJldmlzZSB0aGUgQVBJIHRva2VucyB0byByZWZsZWN0IHlvdXJzLCB0aGVuIHJ1biB0aGUgc2NyaXB0IHRvIHNhdmUgeW91ciBlbmNyeXB0ZWQgY3JlZGVudGlhbHMgb24gdGhlIGxhYiBzZXJ2ZXIgYW5kIHlvdXIgZW5jcnlwdGlvbiBrZXkgb24geW91ciBsb2NhbCBjb21wdXRlcgogICAgLSBWZXJpZnkgdGhhdCB0aGUgRW5jcnlwdGlvbiBLZXkgKGBSRURDYXAgRW5jcnlwdGlvbiBLZXkuUkRhdGFgKSB3YXMgc2F2ZWQgd2hlcmUgeW91IGludGVuZGVkIGl0IHRvIGJlIHNhdmVkIG9uIHlvdXIgbG9jYWwgY29tcHV0ZXIKICAgIC0gVmVyaWZ5IHRoYXQgYSBmaWxlIG5hbWVkIHdpdGggeW91ciBIYXdrSUQgd2FzIHNhdmVkIGhlcmU6IGAvL2xjLXJzLXN0b3JlMjQuaHBjLnVpb3dhLmVkdS9sc3NfaXRwZXRlcnNlbi9MYWIvU3R1ZGllcy9TY2hvb2wgUmVhZGluZXNzIFN0dWR5L0RhdGEgTWFuYWdlbWVudC9SRURDYXAvVG9rZW5zL2AKMS4gQ29weSB0aGUgRW5jcnlwdGlvbiBLZXkgKGBSRURDYXAgRW5jcnlwdGlvbiBLZXkuUkRhdGFgKSB0byB0aGUgY29tcGFyYWJsZSBsb2NhdGlvbiBvZiBhbnkgb3RoZXIgY29tcHV0ZXJzIHlvdSBvd24gdGhhdCB5b3UgcGxhbiB0byBhY2Nlc3MgdGhlIGRhdGEgZnJvbQogICAgLSBUaGUgZmlsZSBoYXMgdG8gYmUgaW4gdGhlIGNvbXBhcmFibGUgbG9jYXRpb24gKHJlbGF0aXZlIHRvIHRoZSBgcGF0aGAgdmFyaWFibGUgeW91IHNldCBpbiBgUnByb2ZpbGUuc2l0ZWApIG9mIGV2ZXJ5IGNvbXB1dGVyIGluIG9yZGVyIGZvciBpdCB0byBiZSBmb3VuZCBieSB0aGUgYEV4cG9ydCBEYXRhLlJgIHNjcmlwdC4KICAgIFRoZSBkZWZhdWx0IGxvY2F0aW9uIGlzOiBgZmlsZS5wYXRoKHBhdGgsICJHaXRIdWIvUi9EYXRhL1JFRENhcCBFbmNyeXB0aW9uIEtleS5SRGF0YSIpYCwgc28gaWYgYHBhdGhgIGlzIHNldCBhcyBgIkM6L1VzZXIvWW91ck5hbWUiYCwgdGhlIGZpbGUgd291bGQgYmUgc2F2ZWQgaW46IGBDOi9Vc2VyL1lvdXJOYW1lL0dpdEh1Yi9SL0RhdGEvUkVEQ2FwIEVuY3J5cHRpb24gS2V5LlJEYXRhYC4KICAgIFRoZSByZWNvbW1lbmRlZCBsb2NhdGlvbiBmb3IgYEdpdEh1YmAgcmVwb3MgaXMgdG8gY3JlYXRlIGEgZm9sZGVyIHRpdGxlZCBgR2l0SHViYCBpbiB5b3VyIGBEb2N1bWVudHNgIGZvbGRlciwgYW5kIHRvIHB1dCByZXBvcyBpbiB0aGUgYEdpdEh1YmAgZm9sZGVyOyBpdCBpcyAqTk9UKiByZWNvbW1lbmRlZCB0byBwdXQgYGdpdGAgcmVwb3MgaW4gYSBPbmVEcml2ZSBmb2xkZXIgYmVjYXVzZSBbYGdpdGAgZmlsZXMgdGVuZCBub3QgdG8gcGxheSBuaWNlIHdpdGggc3luY2luZyBzZXJ2aWNlc10oaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvMTkzMDUwMzMvd2h5LWlzLXB1dHRpbmctZ2l0LXJlcG9zaXRvcmllcy1pbnNpZGUtb2YtYS1kcm9wYm94LWZvbGRlci1ub3QtcmVjb21tZW5kZWQpIChhcmNoaXZlZCBhdCBodHRwczovL3Blcm1hLmNjL1haNkYtNDNHMzsgZS5nLiwgT25lRHJpdmUsIERyb3Bib3gpCjEuIEFkZCB0aGUgU1JTIERhdGEgUHJvY2Vzc2luZyByZXBvIGZyb20gdGhlIGxhYiBkcml2ZSB0byB5b3VyIGBHaXRIdWIgRGVza3RvcGAgQXBwIChgLy9sYy1ycy1zdG9yZTI0LmhwYy51aW93YS5lZHUvbHNzX2l0cGV0ZXJzZW4vTGFiL1N0dWRpZXMvU2Nob29sIFJlYWRpbmVzcyBTdHVkeS9EYXRhIFByb2Nlc3NpbmdgKQogICAgLSBGb3IgaW5zdHJ1Y3Rpb25zLCBzZWUgdGhlIHNlY3Rpb24gb24gIltIb3cgdG8gYWRkIGEgcHJlLWV4aXN0aW5nIHJlcG8gZnJvbSB0aGUgbGFiIGRyaXZlIChSRFNTL25ldHdvcmsgc2hhcmUpIHRvIHlvdXIgY29tcHV0ZXJdKGh0dHBzOi8vcmVzZWFyY2gtZ2l0LnVpb3dhLmVkdS9QZXRlcnNlbkxhYi9SLUluaXRpYWxTZXR1cC8tL2Jsb2IvbWFzdGVyL0dpdExhYi9HaXRMYWIlMjBJbnN0cnVjdGlvbnMubWQjaG93LXRvLWFkZC1hLXByZS1leGlzdGluZy1yZXBvLWZyb20tdGhlLWxhYi1kcml2ZS1yZHNzbmV0d29yay1zaGFyZS10by15b3VyLWNvbXB1dGVyKSIgaGVyZTogaHR0cHM6Ly9yZXNlYXJjaC1naXQudWlvd2EuZWR1L3BldGVyc2VubGFiL1ItSW5pdGlhbFNldHVwL2Jsb2IvbWFzdGVyL0dpdExhYi9HaXRMYWIlMjBJbnN0cnVjdGlvbnMubWQKMS4gT3BlbiBgUlN0dWRpb2AgYnkgdXNpbmcgIlJ1biBhcyBBZG1pbmlzdHJhdG9yIiAoYWx3YXlzIG9wZW4gYFJTdHVkaW9gIGFzIGFuIGFkbWluaXN0cmF0b3Igc28gaXQgaGFzIHdyaXRlIGFjY2VzcyB0byB0aGUgcHJvZ3JhbSBmaWxlcyBkaXJlY3RvcnkpOwoxLiBPcGVuIHRoZSBgRXhwb3J0IERhdGEuUmAgc2NyaXB0IGluIFI6Cmh0dHBzOi8vcmVzZWFyY2gtZ2l0LnVpb3dhLmVkdS9wZXRlcnNlbmxhYi9zcnMvU1JTLURhdGFQcm9jZXNzaW5nL2Jsb2IvbWFzdGVyLzEuJTIwRXhwb3J0JTIwRGF0YS9FeHBvcnQlMjBEYXRhLlIKYFxcbGMtcnMtc3RvcmUyNC5ocGMudWlvd2EuZWR1XGxzc19pdHBldGVyc2VuXExhYlxTdHVkaWVzXFNjaG9vbCBSZWFkaW5lc3MgU3R1ZHlcRGF0YSBQcm9jZXNzaW5nXDEuIEV4cG9ydCBEYXRhXEV4cG9ydCBEYXRhLlJgCjEuIEVuc3VyZSB5b3VyIEhhd2tJRCBhbmQgbG9jYXRpb24gb2YgeW91ciBlbmNyeXB0aW9uIGtleSBpbiB0aGUgc2NyaXB0IGFyZSBjb3JyZWN0LCBhbmQgdGhlbiBydW4gdGhlIHNjcmlwdCB0byB2ZXJpZnkgdGhhdCB5b3UgY2FuIGV4cG9ydCBkYXRhIGZyb20gUkVEQ2FwCjEuIEZvciBhbnRpYWxpYXNlZCBwbG90cyBpbiBgUlN0dWRpb2AsIGNoYW5nZSB0aGUgR3JhcGhpY3MgYmFja2VuZCB0byBgQ2Fpcm9gOgpgVG9vbHMg4oaSIEdsb2JhbCBPcHRpb25zIOKGkiBHcmFwaGljc2AKCiMgTGFiIFBhY2thZ2UgeyNwZXRlcnNlbmxhYn0KClRoZSBbYHBldGVyc2VubGFiYCBwYWNrYWdlXShodHRwczovL2RldnBzeWxhYi5naXRodWIuaW8vcGV0ZXJzZW5sYWIpIGlzIGhlcmU6IGh0dHBzOi8vZGV2cHN5bGFiLmdpdGh1Yi5pby9wZXRlcnNlbmxhYi4KVG8gaW5zdGFsbCB0aGUgW2BwZXRlcnNlbmxhYmAgcGFja2FnZV0oaHR0cHM6Ly9kZXZwc3lsYWIuZ2l0aHViLmlvL3BldGVyc2VubGFiKSwgc2VlIGluc3RydWN0aW9ucyBbaGVyZV0oZGF0YU1hbmFnZW1lbnQuaHRtbCNsYWJGdW5jdGlvbnMpLgoKIyBJbnN0YWxsIFBhY2thZ2VzIHsjaW5zdGFsbFBhY2thZ2VzfQoKVG8gaW5zdGFsbCBhbmQgbG9hZCBgUmAgcGFja2FnZXMsIHNlZSB0aGUgaW5zdHJ1Y3Rpb25zIFtoZXJlXShkYXRhTWFuYWdlbWVudC5odG1sI2xvYWRJbnN0YWxsUGFja2FnZXMpLgoKIyBVcGRhdGUgUGFja2FnZXMgeyN1cGRhdGVQYWNrYWdlc30KClRvIHVwZGF0ZSBwYWNrYWdlcywgdXNlIHRoZSBmb2xsb3dpbmcgY29kZToKCmBgYHtyLCBjbGFzcy5zb3VyY2UgPSAiZm9sZC1zaG93IiwgZXZhbCA9IEZBTFNFfQp1cGRhdGUucGFja2FnZXMoY2hlY2tCdWlsdCA9IFRSVUUpCmBgYAoKT25lIGluZGljYXRpb24gdGhhdCB0aGUgcGFja2FnZXMgbWlnaHQgbm90IGJlIHVwZGF0aW5nIHRvIHRoZSBsYXRlc3QgdmVyc2lvbiBpcyBzZWVpbmcgdGhlIHNhbWUgcGFja2FnZXMgc2hvd2luZyBhcyBuZWVkaW5nIGFuIHVwZGF0ZSBhZnRlciBoYXZpbmcgcnVuIHRoZSBgdXBkYXRlLnBhY2thZ2VzKClgIGZ1bmN0aW9uLgpJZiB0aGlzIGRvZXMgbm90IHVwZGF0ZSB0aGUgcGFja2FnZShzKSB0byB0aGUgbGF0ZXN0IHZlcnNpb24sIHlvdSBtYXkgbmVlZCB0byBpbnN0YWxsIHRoZSBsYXRlc3QgdmVyc2lvbiBvZiB0aGUgcGFja2FnZShzKSBmcm9tIHNvdXJjZSAoc2VlIHRoZSBzZWN0aW9uIG9uICJbSW5pdGlhbCBTZXQgVXBdKCNzZXR1cCkiIG9mIGBSYCBmb3IgdGhlIHNvZnR3YXJlIG5lZWRlZCB0byBpbnN0YWxsIFIgcGFja2FnZXMgZnJvbSBzb3VyY2UpOgoKYGBge3IsIGNsYXNzLnNvdXJjZSA9ICJmb2xkLXNob3ciLCBldmFsID0gRkFMU0V9CnVwZGF0ZS5wYWNrYWdlcyhjaGVja0J1aWx0ID0gVFJVRSwgdHlwZSA9ICJzb3VyY2UiKQpgYGAKCiMgVXBkYXRlIGBSYCB7I3VwZGF0ZVJ9CgpJbnN0cnVjdGlvbnMgYWRhcHRlZCBmcm9tOiBodHRwczovL21pcnJvci5sYXMuaWFzdGF0ZS5lZHUvQ1JBTi9iaW4vd2luZG93cy9iYXNlL3J3LUZBUS5odG1sI1doYXRfMDAyN3MtdGhlLWJlc3Qtd2F5LXRvLXVwZ3JhZGVfMDAzZiAoYXJjaGl2ZWQgYXQgaHR0cHM6Ly9wZXJtYS5jYy9XNVFXLU1BNlEpCgoxLiBVbmluc3RhbGwgYFJgCjEuIEluc3RhbGwgdGhlIG5ldyBgUmAgdmVyc2lvbiBpbnRvIGEgZGlyZWN0b3J5IHRoYXQgY29udGFpbnMgbm8gc3BhY2VzIChzZWUgU3RlcCAyIGluIHRoZSBbSW5pdGlhbCBTZXQgVXBdKCNzZXR1cCkgc2VjdGlvbiBhYm92ZSkKMS4gW1lvdSBvbmx5IG5lZWQgdG8gZG8gdGhpcyBzdGVwIGlmIHlvdSBpbnN0YWxsZWQgcGFja2FnZXMgaW4gdGhlIFItdmVyc2lvbi1zcGVjaWZpYyAiTGlicmFyeSIgZm9sZGVyIHJhdGhlciB0aGFuIHRoZSBjb21tb24vc2hhcmVkICJQYWNrYWdlcyIgZm9sZGVy4oCUdGhhdCBpcywgeW91IGRvbid0IG5lZWQgdG8gZG8gdGhpcyBzdGVwIGlmIHlvdSB1c2VkIHRoZSBsYWIncyBgUnByb2ZpbGUuc2l0ZWAgZmlsZSwgYXMgZGVzY3JpYmVkIGFib3ZlLCB3aGljaCBpbnN0YWxscyBwYWNrYWdlcyB0byB0aGUgY29tbW9uL3NoYXJlZCAiUGFja2FnZXMiIGZvbGRlcl06CiAgICAtIENvcHkgaW5zdGFsbGVkIHBhY2thZ2VzIGluIHRoZSAiTGlicmFyeSIgZm9sZGVyIHRvIHRoZSAiTGlicmFyeSIgZm9sZGVyIGluIHRoZSBuZXcgaW5zdGFsbGF0aW9uCjEuIEluIG5ldyBgUmAgdmVyc2lvbiBmb2xkZXIsIGNvcHkgdGhlIGN1cnJlbnQgYFJwcm9maWxlLnNpdGVgIGZpbGUgYXMgYSBiYWNrdXAgKGBScHJvZmlsZV9CQUNLVVAuc2l0ZWApIGFuZCBvdmVyd3JpdGUgdGhlIG9yaWdpbmFsIGZpbGUgd2l0aCB0aGUgbGFiJ3MgdmVyc2lvbiBvZiBgUnByb2ZpbGUuc2l0ZWAgZnJvbSBoZXJlOiBodHRwczovL3Jlc2VhcmNoLWdpdC51aW93YS5lZHUvUGV0ZXJzZW5MYWIvUi1Jbml0aWFsU2V0dXAvLS9ibG9iL21hc3Rlci9SJTIwU2V0dXAlMjBGaWxlcy9ScHJvZmlsZS5zaXRlCiAgICAtIGBSYCB3aWxsIHJ1biB0aGUgZmlsZSBuYW1lZCBgUnByb2ZpbGUuc2l0ZWAgYXQgaW5pdGlhbCBydW50aW1lLgoxLiBTZXQgdGhlIGV4ZWN1dGFibGVzIGZvciBgUmAgYW5kIGBSU3R1ZGlvYCB0byBhbHdheXMgcnVuIHdpdGggYWRtaW5pc3RyYXRvciBwZXJtaXNzaW9ucy4KICAgIC0gSWYgb24gV2luZG93cywgb3BlbiBGaWxlIEV4cGxvcmVyIGFuZCBmaW5kIHRoZSBtYWluIGV4ZWN1dGFibGUgb2YgYFJgIChgQzpcUlxSLVZFUlNJT05cYmluXFIuZXhlYCkgYW5kIGBSU3R1ZGlvYCAoYEM6XFByb2dyYW0gRmlsZXNcUlN0dWRpb1xiaW5cUlN0dWRpby5leGVgKS4KICAgIFJpZ2h0LWNsaWNrIGl0IHRvIG9wZW4gdGhlIGNvbnRleHR1YWwgbWVudS4KICAgIFRoZW4sIGNsaWNrIG9yIHRhcCBvbiAiUHJvcGVydGllcyIuCiAgICBJbiB0aGUgUHJvcGVydGllcyB3aW5kb3csIGdvIHRvIHRoZSBDb21wYXRpYmlsaXR5IHRhYi4KICAgIEF0IHRoZSBib3R0b20gb2YgdGhlIHdpbmRvdywgY2hlY2sgdGhlIGJveCBuZXh0IHRvIHRoZSAiUnVuIHRoaXMgcHJvZ3JhbSBhcyBhbiBhZG1pbmlzdHJhdG9yIiBvcHRpb24sIGFuZCB0aGVuIGNsaWNrIG9yIHRhcCBvbiBBcHBseSBvciBPSy4KMS4gTWFrZSBzdXJlIHlvdSBoYXZlIHRoZSBsYXRlc3QgdmVyc2lvbiBvZiB0aGUgdG9vbHMgbmVjZXNzYXJ5IHRvIGNvbXBpbGUgcGFja2FnZXMgZnJvbSBzb3VyY2UgKGkuZS4sIFJ0b29scyBmb3IgV2luZG93cyBvciBgUmAgQ29tcGlsZXIgVG9vbHMgZm9yIFJjcHAgb24gTWFjT1M7IHNlZSB0aGUgaW5zdHJ1Y3Rpb25zIGluIHRoZSBzZWN0aW9uIG9uIFtpbml0aWFsIHNldCB1cF0oI3NldHVwKSkKMS4gT3BlbiB0aGUgbmV3IGBSYCB2ZXJzaW9uIGFuZCBydW4gYHVwZGF0ZS5wYWNrYWdlcyhjaGVja0J1aWx0ID0gVFJVRSwgYXNrID0gRkFMU0UpYCwgYW5kIGluc3RhbGwgYW55IG5lY2Vzc2FyeSBwYWNrYWdlcwoxLiBDbG9zZSBSCjEuIERlbGV0ZSBhbnl0aGluZyBsZWZ0IG9mIHRoZSBvbGQgaW5zdGFsbGF0aW9uCgojIFN0eWxlIEd1aWRlIGFuZCBCZXN0IFByYWN0aWNlcyB7I2Jlc3RQcmFjdGljZXN9CgojIyBDcmVhdGUgYFJzdHVkaW8gUHJvamVjdGAKCkZvciBlYWNoIGRhdGEgYW5hbHlzaXMgcHJvamVjdCAoaS5lLiwgZWFjaCBbYEdpdExhYmAvYEdpdEh1YmBdKCNnaXQpIHJlcG8pLCBjcmVhdGUgYW4gUlN0dWRpbyBQcm9qZWN0LgpUaGlzIGhlbHBzIGtlZXAgeW91ciBwcm9qZWN0IGZpbGVzIG9yZ2FuaXplZC4KCiMjIFVzZSBgUmAgTm90ZWJvb2tzIGZvciAiQ29tcHV0YXRpb25hbCBOb3RlYm9va3MiCgpVc2luZyBgUmAgTm90ZWJvb2tzIGZvciAiQ29tcHV0YXRpb25hbCBOb3RlYm9va3MiIGlzIGhlbHBmdWwgZm9yIHJlcHJvZHVjaWJsZSBjb2RlIHRoYXQgY2FuIGJlIHNoYXJlZCB3aXRoIG90aGVycy4KVG8gY3JlYXRlIGNvbXB1dGF0aW9uYWwgbm90ZWJvb2tzIHNlZSB0aGUgYE1hcmtkb3duYCBzZWN0aW9uIG9uIFtjb21wdXRhdGlvbmFsIG5vdGVib29rc10obWFya2Rvd24uaHRtbCNjb21wdXRhdGlvbmFsTm90ZWJvb2spIGluIHRoZSBEYXRhIEFuYWx5c2lzIGd1aWRlcy4KCiMjIFNlcGFyYXRlIHNlY3Rpb25zIGluIGNvZGUKCi0gSW4gYFJgIHNjcmlwdHMsIHVzZSBzZWN0aW9ucy4KICAgIC0gVG8gaW5zZXJ0IGEgc2VjdGlvbiBpbiBgUlN0dWRpb2AsIHVzZSBgQ1RSTC1TaGlmdC1SYCBvciAiQ29kZSIgLSAiSW5zZXJ0IFNlY3Rpb24iCi0gSW4gYFJgIE5vdGVib29rcy9NYXJrZG93biwgdXNlIEhlYWRlcnMgYW5kIGNvZGUgY2h1bmtzLgogICAgLSBIZWFkZXJzOiAxLCAyLCBvciAzIHBvdW5kIHNpZ25zCiAgICAtIENvZGUgQ2h1bmtzOiBgQ3RybCtBbHQrSWA7IG9yIGNsaWNrICJJbnNlcnQiIGJ1dHRvbiB0aGVuICJSIgoKIyMgTmFtaW5nIHZhcmlhYmxlcwoKLSBVc2UgbWVhbmluZ2Z1bCB2YXJpYWJsZSBuYW1lczsgd2Ugd2FudCB0byBrbm93IHdoYXQgYSB2YXJpYWJsZSByZXByZXNlbnRzIHdpdGhvdXQgaGF2aW5nIHRvIGNvbnN1bHQgYW4gZXh0ZXJuYWwgY29kZWJvb2sgZm9yIGV2ZXJ5IHZhcmlhYmxlCi0gVmFyaWFibGUgbmFtZXMgc2hvdWxkIGluY2x1ZGUgdGhlIHByZWZpeCBmb3IgdGhlIG1lYXN1cmUgZm9sbG93ZWQgYnkgYW4gdW5kZXJzY29yZQogICAgLSBlLmcuLCBgY2JjbF9gIGZvciB0aGUgQ2hpbGQgQmVoYXZpb3IgQ2hlY2tsaXN0IHZhcmlhYmxlcwotIFVzZSBsb3dlciBjYW1lbCBjYXNlIGZvciB2YXJpYWJsZSBuYW1pbmcKICAgIC0gZS5nLiwgYHByZWZpeF90aGlzSXNUaGVWYXJpYWJsZU5hbWVgCi0gRG8gKipub3QqKiBpbmNsdWRlIHNwYWNlcyBpbiB2YXJpYWJsZSBuYW1lcwoKIyMgQ29tbWVudCBjb2RlIGZyZXF1ZW50bHkgYW5kIGNsZWFybHkhCgpJdCBpcyBpbXBvcnRhbnQgdG8gY29tbWVudCBjb2RlIGZyZXF1ZW50bHkgYW5kIGNsZWFybHkuCllvdSB3YW50IHlvdSAoYW5kIG90aGVycykgdG8gZWFzaWx5IGJlIGFibGUgdG8gdW5kZXJzdGFuZCB5b3VyIGNvZGUgaWYgeW91IGNvbWUgYmFjayB0byBpdCBzZXZlcmFsIHllYXJzIGxhdGVyIQoKIyMgRG9uJ3Qgc2F2ZSB5b3VyIHdvcmtzcGFjZSBpbWFnZSB7I2RvbnRTYXZlV29ya3NwYWNlfQoKRm9yIHJlcHJvZHVjaWJpbGl0eSBwdXJwb3NlcywgaXQgaXMgaW1wb3J0YW50IFsqKm5vdCoqIHRvIHNhdmUgeW91ciB3b3Jrc3BhY2UgaW1hZ2VdKGh0dHBzOi8vd3d3LnItYmxvZ2dlcnMuY29tLzIwMTcvMDQvdXNpbmctci1kb250LXNhdmUteW91ci13b3Jrc3BhY2UvKSAoYXJjaGl2ZWQgYXQgaHR0cHM6Ly9wZXJtYS5jYy85U0NaLUw0REUpLgpJdCBpcyBiZXN0IHByYWN0aWNlcyB0byBiZWdpbiBgUmAgZWFjaCBzZXNzaW9uIHdpdGggYSBjbGVhbiB3b3Jrc3BhY2UuCklmIHRoZXJlIGlzIGEgYC5SZGF0YWAgZmlsZSBpbiB0aGUgc2FtZSBmb2xkZXIgYXMgdGhlIGBSc3R1ZGlvIFByb2plY3RgLCBSc3R1ZGlvIHdpbGwgYXV0b21hdGljYWxseSBsb2FkIHRoZSBvYmplY3RzIGludG8gdGhlIHdvcmtzcGFjZSBhdCB0aGUgYmVnaW5uaW5nIG9mIHRoZSBzZXNzaW9uLgpUaGlzIGlzIHByb2JsZW1hdGljIGJlY2F1c2UgdGhvc2Ugb2JqZWN0cyBjYW4gaW50ZXJhY3QvaW50ZXJmZXJlIHdpdGggdGhlIGNvZGUgYW5kIGNhbiBsZWFkIHRvIHByb2JsZW1zIHdpdGggcmVwbGljYWJpbGl0eSBmb3Igb3RoZXJzIHdobyBhcmUgcnVubmluZyB0aGUgY29kZSB3aXRob3V0IHRob3NlIG9iamVjdHMgaW4gdGhlIHdvcmtzcGFjZS4KV2hlbiB5b3UgZXhpdCBgUlN0dWRpb2AsIGBSU3R1ZGlvYCBhc2tzIGlmIHlvdSB3YW50IHRvICJTYXZlIHdvcmtzcGFjZSBpbWFnZSB0byBgW2ZpbGVwYXRoXS8uUmRhdGFgPyIKTWFrZSBzdXJlIHRvIHNlbGVjdCAiRG9uJ3QgU2F2ZSIhCkhvd2V2ZXIsIGRvIG1ha2Ugc3VyZSB0byBzYXZlIHlvdXIgYFJgIHNjcmlwdHMgYmVmb3JlIGV4aXRpbmcgUnN0dWRpby4KCiMgRGF0YSBNYW5hZ2VtZW50CgotIFRoZSBsYWIncyBbRGF0YSBBbmFseXNpcyBHdWlkZXMgb24gRGF0YSBNYW5hZ2VtZW50XShkYXRhTWFuYWdlbWVudC5odG1sKQotIFRpZHl2ZXJzZTogaHR0cHM6Ly93d3cudGlkeXZlcnNlLm9yZwotIFVuaXZlcnNpdHkgb2YgSW93YSBXb3Jrc2hvcHMKCiMgU2F2aW5nIFBsb3RzCgpgcG5nKCk7IGRldi5vZmYoKWAKCi0gVGhlIGxhYidzIFtEYXRhIEFuYWx5c2lzIEd1aWRlcyBvbiBGaWd1cmVzXShmaWd1cmVzLmh0bWwpCgojIFNhdmluZyBPdXRwdXQKCmBSIE1hcmtkb3duYAoKLSBUaGUgbGFiJ3MgW0RhdGEgQW5hbHlzaXMgR3VpZGVzIG9uIE1hcmtkb3duXShtYXJrZG93bi5odG1sKQotIGh0dHBzOi8vcm1hcmtkb3duLnJzdHVkaW8uY29tL2xlc3Nvbi0xLmh0bWwgKGFyY2hpdmVkIGF0IGh0dHBzOi8vcGVybWEuY2MvOFNRSC1ONjhYKQotIGh0dHBzOi8vd3d3LnJzdHVkaW8uY29tL3dwLWNvbnRlbnQvdXBsb2Fkcy8yMDE1LzAyL3JtYXJrZG93bi1jaGVhdHNoZWV0LnBkZiAoYXJjaGl2ZWQgYXQgaHR0cHM6Ly9wZXJtYS5jYy8zTk1ULTRMMjUpCi0gaHR0cHM6Ly9ib29rZG93bi5vcmcveWlodWkvcm1hcmtkb3duLyAoYXJjaGl2ZWQgYXQgaHR0cHM6Ly9wZXJtYS5jYy9VSkM4LVpaVkMpCgojIFNob3J0Y3V0cwoKLSBSdW4gc2VsZWN0ZWQgbGluZShzKSBvZiBjb2RlOiBDdHJsICsgRW50ZXIKLSBDb21tZW50L3VuY29tbWVudCBjb2RlOiBDdHJsICsgU2hpZnQgKyBDCi0gUGlwZTogQ3RybCArIFNoaWZ0ICsgTQotIEluc2VydCBDb2RlIENodW5rOiBDdHJsICsgQWx0ICsgSQotIEFzc2lnbm1lbnQgb3BlcmF0b3I6IEFsdCArIC0gKGFsdC1kYXNoKQotIFNlbGVjdCBtdWx0aXBsZSBsaW5lczogQ3RybCArIEFsdCwgdXAgb3IgZG93bjsgb3IgQWx0ICsgZHJhZyBtb3VzZQotIFNlYXJjaDogQ3RybCArIFNoaWZ0ICsgRgotIFNob3cgYWxsIGtleWJvYXJkIHNob3J0Y3V0czogQWx0ICsgU2hpZnQgKyBLCgojIFN0YXRpc3RpY3MgRXhhbXBsZXMKCi0gW0JheWVzaWFuIEFuYWx5c2lzXShiYXllc2lhbi5odG1sKQotIFtEYXRhIE1hbmFnZW1lbnRdKGRhdGFNYW5hZ2VtZW50Lmh0bWwpCi0gW0RldmVsb3BtZW50YWwgU2NhbGluZ10oZGV2ZWxvcG1lbnRhbFNjYWxpbmcuaHRtbCkKLSBbRXhwbG9yYXRvcnkgRGF0YSBBbmFseXNpc10oZWRhLmh0bWwpCi0gW0ZhY3RvciBBbmFseXNpc10oZmFjdG9yQW5hbHlzaXMuaHRtbCkKLSBbSGllcmFyY2hpY2FsIExpbmVhciBNb2RlbGluZ10oaGxtLmh0bWwpCi0gW0l0ZW0gUmVzcG9uc2UgVGhlb3J5XShpcnQuaHRtbCkKLSBbTG9uZ2l0dWRpbmFsIERhdGEgQW5hbHlzaXNdKGxkYS5odG1sKQotIFtNZWRpYXRpb25dKHNlbS5odG1sI21lZGlhdGlvbikKLSBbTW9kZXJhdGlvbi9JbnRlcmFjdGlvbl0ocmVncmVzc2lvbi5odG1sI21vZGVyYXRpb24pCi0gW011bHRpcGxlIEltcHV0YXRpb25dKG11bHRpcGxlSW1wdXRhdGlvbi5odG1sKQotIFtQcmluY2lwYWwgQ29tcG9uZW50IEFuYWx5c2lzXShwY2EuaHRtbCkKLSBbUmVncmVzc2lvbl0ocmVncmVzc2lvbi5odG1sKQotIFtTdHJ1Y3R1cmFsIEVxdWF0aW9uIE1vZGVsaW5nXShzZW0uaHRtbCkKCiMgUnVubmluZyBTY3JpcHRzIEF1dG9tYXRpY2FsbHkgd2l0aCBXaW5kb3dzCgpodHRwczovL3d3dy5zcHNhbmRlcnNvbi5jb20vc3RldmVvbmRhdGEvcG9zdHMvMjAyMy0wNi0yOS9pbmRleC5odG1sIChhcmNoaXZlZCBhdCBodHRwczovL3Blcm1hLmNjLzlFWEstVzk5WSkKCmBSYCBzY3JpcHRzIGNhbiBiZSBydW4gYXV0b21hdGljYWxseS4KRm9yIGV4YW1wbGUsIGl0IGNhbiBiZSBoZWxwZnVsIHRvIGhhdmUgYW4gYFJgIG1hcmtkb3duIHJlcG9ydCBydW4gYXV0b21hdGljYWxseSBiZWZvcmUgdGhlIGRheSBiZWdpbnMuCgoxLiBPcGVuIHRoZSBgTm90ZXBhZGAgYXBwIGFuZCBjcmVhdGUgYSBmaWxlIHdpdGggdGhlIGZvbGxvd2luZyBzeW50YXguCiAgIC0gYExvY2F0aW9uIG9mIFIgZXhlY3V0YWJsZSBmaWxlXFIgQ01EIEJBVENIICJQYXRoIGxvY2F0aW9uIG9mIHNjcmlwdCB0aGF0IHNob3VsZCBiZSBhdXRvbWF0aWNhbGx5IHJ1biJgCiAgIC0gKipFeGFtcGxlOioqIAogICAtIGBDOlxSXDQuMS4zXGJpblxSIENNRCBCQVRDSCAiUjpcTGFiXFN0dWRpZXNcU2Nob29sIFJlYWRpbmVzcyBTdHVkeVxEYXRhIFByb2Nlc3NpbmdcNS4gUmVwb3J0c1xhdXRvbWF0aWNfcmVwb3J0c1xSdW5fUmVwb3J0c19hdXRvLlIiYAoxLiBTYXZlIHRoZSBmaWxlIGFzIGEgYC5iYXRgIGZpbGUgaW4gdGhlIGRlc2lyZWQgbG9jYXRpb24KMS4gT25jZSB0aGUgYC5iYXRgIGZpbGUgaGFzIGJlZW4gY3JlYXRlZCwgc2VhcmNoIGBXaW5kb3dzIFRhc2sgU2NoZWR1bGVyYCBpbiB0aGUgc2VhcmNoIGJhcgohW3Rhc2sgc2NoZWR1bGVyXShpbWFnZXMvdGFzay1zY2hlZHVsZXIucG5nKQoxLiBJbiB0aGUgYEFjdGlvbnNgIHNlbGVjdGlvbiBiYXIsIHNlbGVjdCBgQ3JlYXRlIGJhc2ljIFRhc2suLi5gCjEuIE5hbWUgdGhlIHRhc2sgYW5kIHByb3ZpZGUgYSBkZXNjcmlwdGlvbgoxLiBOZXh0LCBzZXQgdGhlIHRyaWdnZXIgZm9yIHRoZSBuZXcgdGFzayAoaS5lLiwgaG93IG9mdGVuIHRoZSB0YXNrIHNob3VsZCBydW4pCjEuIFNldCB0aGUgYWN0aW9uIGZvciB0aGUgdGFzayBieSBzZWxlY3RpbmcgYFN0YXJ0IGEgcHJvZ3JhbWAKMS4gVW5kZXIsIGBQcm9ncmFtL3NjcmlwdGAgYnJvd3NlIHRvIHRoZSBgLmJhdGAgZmlsZSB0aGF0IHdhcyBjcmVhdGVkIGluIHN0ZXAgMSBhbmQgc2VsZWN0IGBOZXh0YAoxLiBDbGljayBgRmluaXNoYCBhbmQgdGhlIHNjcmlwdCBpcyBub3cgY29uZmlndXJlZCB0byBydW4gYXV0b21hdGljYWxseQoxLiAqKk5vdGU6IFdoZW4gYFJgIGlzIHVwZGF0ZWQsIHRoZSBwYXRoIHRvIHRoZSBgYmluYCBmb2xkZXIgd2l0aGluIGBSYCBuZWVkcyB0byBiZSB1cGRhdGVkIHRvIHJlZmxlY3QgYW4gYWNjdXJhdGUgYWJzb2x1dGUgcGF0aCB0byBSLioqCiAgICAtIEV4YW1wbGU6IGBDOlxSXDQuMS4zXGJpblxSIENNRCBCQVRDSGAgY2hhbmdlZCB0byBgQzpcUlw0LjMuMFxiaW5cUiBDTUQgQkFUQ0hgCgojIyBUcm91Ymxlc2hvb3RpbmcKCiMjIyBQYW5kb2MgZXJyb3IKClRoaXMgZXJyb3IgbWF5IGFwcGVhciBpZiB5b3UgYXJlIGF0dGVtcHRpbmcgdG8gcmVuZGVyIGEgbWFya2Rvd24gZmlsZQoKYGBgCnBhbmRvYyB2ZXJzaW9uIDEuMTIuMyBvciBoaWdoZXIgaXMgcmVxdWlyZWQgYW5kIHdhcyBub3QgZm91bmQuCmBgYAoKVGhlIHNvbHV0aW9uIHRvIHRoaXMgcHJvYmxlbSBbY2FuIGJlIGZvdW5kIGF0IHRoaXMgbGlua10oaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvMjg0MzI2MDcvcGFuZG9jLXZlcnNpb24tMS0xMi0zLW9yLWhpZ2hlci1pcy1yZXF1aXJlZC1hbmQtd2FzLW5vdC1mb3VuZC1yLXNoaW55KSAoYXJjaGl2ZWQgYXQgaHR0cHM6Ly9wZXJtYS5jYy9ZWDU3LUJQUlMpCgojIFJlYWRpbmcgUGFzc3dvcmQgUHJvdGVjdGVkIEV4Y2VsIERhdGFiYXNlcwoKQSBoZWxwZnVsIHBvc3QgY2FuIGJlIGZvdW5kIGhlcmU6IDxicj4KCmh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzM1ODUyNzIyL2hvdy1kby15b3UtcmVhZC1hLXBhc3N3b3JkLXByb3RlY3RlZC1leGNlbC1maWxlLWludG8tciAoYXJjaGl2ZWQgYXQgaHR0cHM6Ly9wZXJtYS5jYy9VMzJaLTIyVkUpCgpgYGB7ciwgZXZhbCA9IEZBTFNFfQppbnN0YWxsLnBhY2thZ2VzKCJleGNlbC5saW5rIikKCmxpYnJhcnkoImV4Y2VsLmxpbmsiKQoKcGFzc3dvcmRQcm90ZWN0ZWRCb29rIDwtIHhsLnJlYWQuZmlsZShmaWxlLnBhdGgoImZ1bGwgcGF0aCB0byB3b3JrYm9vayIpLCAjRnVsbCBwYXRoIHRvIHdvcmtib29rCnBhc3N3b3JkID0gInBhc3MiLCAjcGFzc3dvcmQKd3JpdGUucmVzLnBhc3N3b3JkPSJwYXNzIikgI3dyaXRpbmcgdGhlIHJlc2V0IHBhc3N3b3JkCmBgYAoKIyBTZW5kaW5nIHNsYWNrcyB3aXRoIGBSYAoKT2NjYXNpb25hbGx5LCBpdCBjYW4gYmUgaGVscGZ1bCB0byBzZW5kIGEgU2xhY2sgbWVzc2FnZSB1c2luZyBgUmAuCkZvciBleGFtcGxlLCBpZiBhIHNjcmlwdCBkb2VzIG5vdCBydW4sIGEgU2xhY2sgbWVzc2FnZSBjYW4gYmUgc2VudCB0byBpbmZvcm0gdGhlIGFwcHJvcHJpYXRlIHRlYW0gbWVtYmVycy4KW1RoZXNlIGluc3RydWN0aW9uc10oaHR0cHM6Ly93d3cuaW5mb3dvcmxkLmNvbS9hcnRpY2xlLzM0MDI2NTcvaG93LXRvLXNsYWNrLWZyb20tci5odG1sKSAoYXJjaGl2ZWQgYXQgaHR0cHM6Ly9wZXJtYS5jYy85Q1dKLUo1WlQpIGNhbiBsYXJnZWx5IGJlIGZvbGxvd2VkIHRvIHNldCB1cCBgUmAgdG8gc2VuZCBTbGFjayBtZXNzYWdlcy4KSG93ZXZlciwgdGhlcmUgYXJlIHNvbWUgZGlmZmVyZW5jZXM6CgoxLiBXaGVuIHNldHRpbmcgdXAgdGhlIGNvbmZpZ3VyYXRpb24gZmlsZSwgdXNlIHRoZSBiZWxvdyB0ZW1wbGF0ZS4KVGhlIHNsYWNrIEFQSSB0b2tlbiBzaG91bGQgYmUgcGxhY2VkIGluIHRoZSBgdG9rZW5gIGNhdGVnb3J5LgogICAgLSBOb3RlIHRoZSB0b2tlbiB3aWxsIG5lZWQgdG8gYmUgdXBkYXRlZCBldmVyeSAzMCBkYXlzLgogICAgWW91IGNhbiBnZW5lcmF0ZSBhIG5ldyB0b2tlbiBieSBuYXZpZ2F0aW5nIHRvIHRoZSBbU2xhY2sgQVBJXShodHRwczovL2FwaS5zbGFjay5jb20vYXBwcykgYW5kIHNlbGVjdGluZyBgT2F1dGggJiBQZXJtaXNzaW9uc2AKICAgIC0gIVtzbGFjayBwaWN0dXJlXShpbWFnZXMvc2xhY2tBUEkucG5nKQoKYGBgCnRva2VuOiBZT1VSX0ZVTExfQVBJX1RPS0VOCmNoYW5uZWw6ICNnZW5lcmFsCnVzZXJuYW1lOiBzbGFja3IKaW5jb21pbmdfd2ViaG9va191cmw6IGh0dHBzOi8vaG9va3Muc2xhY2suY29tL3NlcnZpY2VzL1hYWFhYL1hYWFhYL1hYWFhYCmBgYAoKT25jZSB0aGUgY29uZmlndXJhdGlvbiBpcyBjb21wbGV0ZSwgaXQgaXMgcG9zc2libGUgdG8gc2VuZCBtZXNzYWdlcy4gCkZvciBub3csIHdlIGhhdmUgZm91bmQgaXQgaGVscGZ1bCB0byBlbWJlZCB0aGUgc2xhY2tzIGluIHRoZSBgdHJ5Q2F0Y2hgIGZ1bmN0aW9uLiAKCmBgYHtyLCBldmFsID0gRkFMU0V9CnRyeUNhdGNoKApDT0RFIFlPVSBXQU5UIFRPIFJVTiwKZXJyb3IgPSBmdW5jdGlvbihlKQp7CiAgI21lc3NhZ2UgdG8gc2VuZCBpZiB0aGUgY29kZSBkb2Vzbid0IHJ1bgogIG15X21lc3NhZ2UgPC0gcGFzdGUoICJleGFtcGxlIG1lc3NhZ2UiKQogIHNsYWNrcl9tc2cobXlfbWVzc2FnZSwgY2hhbm5lbCA9ICIjcmVjcnVpdG1lbnQiKQp9KQpgYGAKCiMjIFNsYWNraW5nIFNwZWNpZmljIFVzZXJzCgpJdCBpcyBhbHNvIHBvc3NpYmxlIHRvIHNsYWNrIHNwZWNpZmljIHVzZXJzIHdpdGggaW5zdHJ1Y3Rpb25zIGZvdW5kIFthdCB0aGlzIGxpbmtdKGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzMyNDE5NzU2L2hvdy1kby15b3UtdGFnLXBlb3BsZS13aXRoLWEtc2xhY2stYm90KSAoYXJjaGl2ZWQgYXQgaHR0cHM6Ly9wZXJtYS5jYy81OVU1LVY0R1EpLgoKIyBSZXBsYWNpbmcgYC8vbmAgd2l0aCBhIHNwYWNlCgpNYW55IG5vdGVzIGluIHByb2plY3RzIHRoYXQgYXJlIGV4cG9ydGVkIGZyb20gUkVEQ2FwIGNvbWUgd2l0aCBzcGFjZXMgZGVub3RlcyBhcyBgLy9uYC4KVXNlIHRoZSBiZWxvdyBjb2RlIHRvIG1ha2UgdGhlc2UgZmllbGRzIG1vcmUgcmVhZGFibGUgaW4gdGhlIGZ1dHVyZS4KCmBgYHtyLCBldmFsID0gRkFMU0V9CmdzdWIoJ1xcbicsICcsICcsIGRmJG5vdGVzRmllbGQpCmBgYAoKIyBXb3JraW5nIHdpdGggYFJgIG9uIGEgTmV0d29yayBEcml2ZQoKV2hlbiB3b3JraW5nIHdpdGggYFJgIG9uIGEgbmV0d29yayBkcml2ZSwgaXQgbWF5IGJlIGhlbHBmdWwgdG8gY29uZmlndXJlIHRoZSBwcm9qZWN0IHRvIHN0b3JlIGAuUnByb2oudXNlcmAgb24gdGhlIGxvY2FsIGBDOi9gIGRyaXZlIHJhdGhlciB0aGFuIG9uIHRoZSBuZXR3b3JrIGRyaXZlLCB3aGljaCByZXN1bHRzIGluIHNsb3cgZXhlY3V0aW9uIHRpbWVzLgoKRm9yIG1vcmUgaW5mbzoKCi0gaHR0cHM6Ly9naXRodWIuY29tL3JzdHVkaW8vcnN0dWRpby9wdWxsLzE0ODc1Ci0gaHR0cHM6Ly9naXRodWIuY29tL3JzdHVkaW8vcnN0dWRpby9pc3N1ZXMvMTQ2MTkjaXNzdWVjb21tZW50LTIxODk4NTU1OTgKLSBodHRwczovL2dpdGh1Yi5jb20vcnN0dWRpby9yc3R1ZGlvL2lzc3Vlcy8xMDQxNyNpc3N1ZWNvbW1lbnQtMjE5OTkzMDM4NQoKIyBQYWNrYWdlIERldmVsb3BtZW50CgojIyBXb3JraW5nIHdpdGggYHJlbnZgIGZvciBQYWNrYWdlIE1hbmFnZW1lbnQKCmByZW52YCBpcyB1c2VkIGZvciByZXByb2R1Y2liaWxpdHksIGJ5IGhlbHBpbmcgd2l0aCBwYWNrYWdlIG1hbmFnZW1lbnQgKHRyYWNraW5nIHBhY2thZ2UgdmVyc2lvbnMsIGV0Yy4pOgoKaHR0cHM6Ly9yc3R1ZGlvLmdpdGh1Yi5pby9yZW52L2FydGljbGVzL3JlbnYuaHRtbAoKQmVmb3JlIHVwZGF0aW5nIGEgcGFja2FnZSBsb2NhbGx5LCBtYWtlIHN1cmUgdGhhdCBpdCBpcyBhdmFpbGFibGUgaW4gdGhlIFBvc2l0IFBhY2thZ2UgTWFuYWdlciAoc28gaXQgY2FuIGJlIGF2YWlsYWJsZSB0byBHaXRIdWIgQWN0aW9ucyk6CgpodHRwczovL3BhY2thZ2VtYW5hZ2VyLnBvc2l0LmNvCgojIyMgVXBkYXRpbmcgdGhlIFBhY2thZ2UKClRvIHVwZGF0ZSB0aGUgcGFja2FnZSwgcnVuIHRoZSBmb2xsb3dpbmcgaW4gYFJgOgoKYGBge3IsIGV2YWwgPSBGQUxTRX0KIyAxLiBVcGRhdGUgcGFja2FnZXMgaW4gcGFja2FnZSBlbnZpcm9ubWVudApyZW52Ojp1cGdyYWRlKCkKcmVudjo6dXBkYXRlKCkKcmVudjo6c25hcHNob3QoKQoKIyAyLiBBZGQvZWRpdCBjb2RlCgojIDMuIFVwZGF0ZSBkb2N1bWVudGF0aW9uCnJveHlnZW4yOjpyb3h5Z2VuaXNlKCkKCiMgNC4gVXBkYXRlIHBhY2thZ2UgdmVyc2lvbgp1c2V0aGlzOjp1c2VfdmVyc2lvbigpCmBgYAoKVGhlbiwgYnVpbGQgdGhlIHBhY2thZ2U6IEN0cmwtU2hpZnQtQgoKVGhlbiwgaW5zdGFsbCB0aGUgcGFja2FnZToKCmBgYHtyLCBldmFsID0gRkFMU0V9CnJlbnY6Omluc3RhbGwoIkM6L1IvUGFja2FnZXMvcGV0ZXJzZW5sYWIiKSAjUEMKcmVudjo6aW5zdGFsbCgiL0xpYnJhcnkvRnJhbWV3b3Jrcy9SLmZyYW1ld29yay9QYWNrYWdlcy9wZXRlcnNlbmxhYiIpICNNYWMKYGBgCgojIyMgSW5zdGFsbGluZyBQYWNrYWdlcwoKVG8gaW5zdGFsbCBuZXcgcGFja2FnZXMgaW4gdGhlIHBhY2thZ2UgZW52aXJvbm1lbnQsIHJ1biB0aGUgZm9sbG93aW5nIGluIGBSYDoKCmBgYHtyLCBldmFsID0gRkFMU0V9CnJlbnY6Omluc3RhbGwoIk5BTUVfT0ZfUEFDS0FHRSIpCmBgYApvcjoKYGBge3IsIGV2YWwgPSBGQUxTRX0KaW5zdGFsbC5wYWNrYWdlcygiTkFNRV9PRl9QQUNLQUdFKQpgYGAKCiMjIGBSIENNRCBjaGVja2AgeyNyQ21kQ2hlY2t9CgoxLiBCdWlsZCB0aGUgc291cmNlIHBhY2thZ2UKICAgIC0gY2xpY2sgb24gdGhlICJCdWlsZCIgdGFiIGluIHRoZSB0b3AtcmlnaHQgcGFuZSBvZiBSU3R1ZGlvLCBhbmQgdGhlbiBjbGljayAiQnVpbGQgU291cmNlIFBhY2thZ2UiCjEuIE9wZW4gdGVybWluYWwgaW4gUlN0dWRpbwogICAgLSBBZnRlciB0aGUgcGFja2FnZSBpcyBidWlsdCwgb3BlbiBhIHRlcm1pbmFsIHdpbmRvdyBkaXJlY3RseSBpbiBSU3R1ZGlvIGJ5IGNsaWNraW5nIG9uIHRoZSAiVGVybWluYWwiIHRhYiBhdCB0aGUgYm90dG9tIG9mIFJTdHVkaW8KMS4gUnVuIGBSIENNRCBjaGVjayAtLWFzLWNyYW5gCiAgICAtIEluIHRoZSB0ZXJtaW5hbCB3aW5kb3csIG5hdmlnYXRlIHRvIHRoZSBkaXJlY3Rvcnkgd2hlcmUgeW91ciBwYWNrYWdlIHNvdXJjZSBpcyBsb2NhdGVkLgogICAgVGhlbiwgcnVuIGBSIENNRCBjaGVjayAtLWFzLWNyYW5gIGZvbGxvd2VkIGJ5IHRoZSBuYW1lIG9mIHlvdXIgcGFja2FnZSB0YXJiYWxsLiBGb3IgZXhhbXBsZToKCkJ1aWxkIGAudGFyLmd6YCBmaWxlOgoKYGBge3IsIGV2YWwgPSBGQUxTRX0KZGV2dG9vbHM6OmJ1aWxkKHBrZyA9ICJEOi9Eb2N1bWVudHMvR2l0SHViL3BldGVyc2VubGFiIikKYGBgCgpgYGB7ciwgZXZhbCA9IEZBTFNFfQpSIENNRCBjaGVjayAtLWFzLWNyYW4gcGV0ZXJzZW5sYWJfMS4wLjAudGFyLmd6CmBgYAoKSWYgZXJyb3JzIGNvbXBpbGluZyB0aGUgUERGIG1hbnVhbDoKCmBgYHtyLCBldmFsID0gRkFMU0V9ClIgQ01EIFJkMnBkZiAuIC0tb3V0cHV0PW1hbi9maWd1cmVzL21hbnVhbC5wZGYgLS1mb3JjZSAtLW5vLXByZXZpZXcgLS1uby1jbGVhbgpgYGAKCiMjIyBUcm91Ymxlc2hvb3RpbmcKCiMjIyMgYG5vIHZpc2libGUgYmluZGluZyBmb3IgZ2xvYmFsIHZhcmlhYmxlYDsgYFVuZGVmaW5lZCBnbG9iYWwgZnVuY3Rpb25zIG9yIHZhcmlhYmxlc2AKCkZvciBleGFtcGxlOgpgYGByCm5vIHZpc2libGUgYmluZGluZyBmb3IgZ2xvYmFsIHZhcmlhYmxlCiAgICAnbW9kZXJhdG9yVmFsX2NlbnRlcmVkJwogIFVuZGVmaW5lZCBnbG9iYWwgZnVuY3Rpb25zIG9yIHZhcmlhYmxlczoKICAgIG1vZGVyYXRvclZhbF9jZW50ZXJlZCBwcmVkaWN0b3JWYWxfY2VudGVyZWQKYGBgCgpTb2x1dGlvbjogc2V0IGVhY2ggdmFyaWFibGUgdG8gYE5VTExgIGluIHRoZSBwYWNrYWdlIGZ1bmN0aW9uIGJlZm9yZSBpdCBpcyBtZW50aW9uZWQuCkZvciBleGFtcGxlOgoKYGBgcgpwcmVkaWN0b3JWYWxfY2VudGVyZWQgPC0gbW9kZXJhdG9yVmFsX2NlbnRlcmVkIDwtIE5VTEwKYGBgCgojIyBgUiBDTUQgY2hlY2tgIHZpYSBHaXRIdWIgQWN0aW9ucwoKYGBge3IsIGV2YWwgPSBGQUxTRX0KdXNldGhpczo6dXNlX2dpdGh1Yl9hY3Rpb24oImNoZWNrLXN0YW5kYXJkIikKYGBgCgojIyBVc2VmdWwga2V5Ym9hcmQgc2hvcnRjdXRzIGZvciBwYWNrYWdlIGF1dGhvcmluZzoKCiBJbnN0YWxsIFBhY2thZ2U6ICAgICAgICAgICAnQ3RybCArIFNoaWZ0ICsgQicKIAogQ2hlY2sgUGFja2FnZTogICAgICAgICAgICAgJ0N0cmwgKyBTaGlmdCArIEUnCiAKIFRlc3QgUGFja2FnZTogICAgICAgICAgICAgICdDdHJsICsgU2hpZnQgKyBUJwoKYGBge3IsIGV2YWwgPSBGQUxTRX0KcmVudjo6aW5zdGFsbCgiQzovUi9QYWNrYWdlcy9wZXRlcnNlbmxhYiIpCnJlbnY6OnNuYXBzaG90KCkKcmVudjo6aW5zdGFsbCgpCmBgYAoKIyMgYHBrZ2Rvd25gCgpSdW4gb25jZSB0byBjb25maWd1cmUgeW91ciBwYWNrYWdlIHRvIHVzZSBwa2dkb3duOgoKYGBge3IsIGV2YWwgPSBGQUxTRX0KdXNldGhpczo6dXNlX3BrZ2Rvd24oKQpgYGAKClRoZW4gdXNlIGBwa2dkb3duYCB0byBidWlsZCB5b3VyIHdlYnNpdGU6CgpgYGB7ciwgZXZhbCA9IEZBTFNFfQpwa2dkb3duOjpidWlsZF9zaXRlKCkKYGBgCgojIyBTdGVwcyB0byBBZGQgRnVuY3Rpb25zCgoxLiBBZGQgYC5SYCBmaWxlIHdpdGggdGhlIGZ1bmN0aW9uCjEuIEFkZCB0aGUgZnVuY3Rpb24gdG8gdGhlIGBfcGtnZG93bi55bWxgIGZpbGUKMS4gVXBkYXRlIHZlcnNpb24gbnVtYmVyCjEuIGByZW52Ojp1cGdyYWRlKClgCjEuIGByZW52Ojp1cGRhdGUoKWAKMS4gYHJlbnY6OnNuYXBzaG90KClgCjEuIGByb3h5Z2VuMjo6cm94eWdlbmlzZSgpYAoxLiBJbnN0YWxsIFBhY2thZ2U6ICdDdHJsICsgU2hpZnQgKyBCJwoxLiBDaGVjayBQYWNrYWdlOiAnQ3RybCArIFNoaWZ0ICsgRScKMS4gYFIgQ01EIGNoZWNrYAoxLiBDb21taXQgYW5kIHB1c2ggY2hhbmdlcwoxLiBVcGRhdGUgcmVsZWFzZSB2ZXJzaW9uIGluIEdpdEh1YgoKIyMgQWRkIHN1Yi1wYWNrYWdlcwoKYGBge3IsIGV2YWwgPSBGQUxTRX0KZGV2dG9vbHM6OmJ1aWxkKHBrZyA9ICJEOi9Eb2N1bWVudHMvR2l0SHViL3BldGVyc2VubGFiL2luc3QvZXh0ZGF0YS90ZXN0cGFja2FnZTEiKQpkZXZ0b29sczo6YnVpbGQocGtnID0gIkQ6L0RvY3VtZW50cy9HaXRIdWIvcGV0ZXJzZW5sYWIvaW5zdC9leHRkYXRhL3Rlc3RwYWNrYWdlMiIpCgppbnN0YWxsLnBhY2thZ2VzKCJEOi9Eb2N1bWVudHMvR2l0SHViL3BldGVyc2VubGFiL2luc3QvZXh0ZGF0YS90ZXN0cGFja2FnZTFfMC4xLjAudGFyLmd6IiwgcmVwb3MgPSBOVUxMLCBzb3VyY2UgPSBUUlVFKQppbnN0YWxsLnBhY2thZ2VzKCJEOi9Eb2N1bWVudHMvR2l0SHViL3BldGVyc2VubGFiL2luc3QvZXh0ZGF0YS90ZXN0cGFja2FnZTJfMC4xLjAudGFyLmd6IiwgcmVwb3MgPSBOVUxMLCBzb3VyY2UgPSBUUlVFKQoKcmVtb3Rlczo6aW5zdGFsbF9sb2NhbCgiRDovRG9jdW1lbnRzL0dpdEh1Yi9wZXRlcnNlbmxhYi9pbnN0L2V4dGRhdGEvdGVzdHBhY2thZ2UyXzAuMS4wLnRhci5neiIpCnJlbW90ZXM6Omluc3RhbGxfbG9jYWwoIkQ6L0RvY3VtZW50cy9HaXRIdWIvcGV0ZXJzZW5sYWIvaW5zdC9leHRkYXRhL3Rlc3RwYWNrYWdlMl8wLjEuMC50YXIuZ3oiKQpgYGAKCiMjIFN1Ym1pdCBQYWNrYWdlIHRvIENSQU4KCmh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3N1Ym1pdC5odG1sCgojIyBSZXNvdXJjZXMKCk9mZmljaWFsIGRvY3VtZW50YXRpb24gZm9yIENSQU46CgotIGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL2RvYy9tYW51YWxzL1ItZXh0cy5odG1sCgpVbm9mZmljaWFsIGRvY3VtZW50YXRpb246CgotIGh0dHBzOi8vcnB1YnMuY29tL1lhUnJyL3JwYWNrYWdlaW50cm8KLSBodHRwczovL3ItcGtncy5vcmcKLSBodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy9kb2MvY29udHJpYi9MZWlzY2gtQ3JlYXRpbmdQYWNrYWdlcy5wZGYKLSBodHRwczovL3BvcnRhbC5zdGF0cy5veC5hYy51ay91c2VyZGF0YS9ydXRoL0FQVFMyMDEyL1Jjb3Vyc2UxMC5wZGYKLSBodHRwczovL3dlYi5taXQuZWR1L2luc29uZy93d3cvcGRmL3JwYWNrYWdlX2luc3RydWN0aW9ucy5wZGYKLSBodHRwczovL2hpbGFyeXBhcmtlci5jb20vMjAxNC8wNC8yOS93cml0aW5nLWFuLXItcGFja2FnZS1mcm9tLXNjcmF0Y2gvCgojIyMgRm9yIFBhY2thZ2UgRGV2ZWxvcG1lbnQgVGFza3MKCi0gaHR0cHM6Ly91c2V0aGlzLnItbGliLm9yZy9pbmRleC5odG1sCgojIyMgRm9yIERvY3VtZW50YXRpb24KCi0gaHR0cHM6Ly9naXRodWIuY29tL3ItbGliL3JveHlnZW4yI3JveHlnZW4yCi0gaHR0cHM6Ly9oaWxhcnlwYXJrZXIuY29tLzIwMTQvMDQvMjkvd3JpdGluZy1hbi1yLXBhY2thZ2UtZnJvbS1zY3JhdGNoLwoKIyMjIENyZWF0aW5nIFZpZ25ldHRlcwoKLSBodHRwczovL2Jvb2tkb3duLm9yZy95aWh1aS9ybWFya2Rvd24tY29va2Jvb2svcGFja2FnZS12aWduZXR0ZS5odG1sCgojIyMgRm9yIExpY2Vuc2luZwoKLSBodHRwczovL3VzZXRoaXMuci1saWIub3JnL3JlZmVyZW5jZS9saWNlbnNlcy5odG1sCg==



Developmental Psychopathology Lab