Below I list a few commandments of R scripting that will guide us through this lesson. Future you and all those around you will sing your praises if you follow these.

We’ll go through all of these in some detail with an example script!

1. Conform to a predictable script structure

1.1. Provide your metadata about the document (not required, but helpful)

It is always a good idea to write at the top of a script who wrote it (give yourself some credit!), when, and why it was written. In the case of an R script (as opposed to an R Markdown document), we might write something like the below at the top of our document.

#' ---
#' title: The best title
#' purpose: blarg
#' author: You
#' date: YYYY-MM-DD
#' ---

Since the above is commented out, it is completely inert. The R does not run or use this information in anyway.

Similarly, R Mardown documents have an element built into the top of their documents called a YAML, which is used in a slightly different way by R, but accomplishes a similar feat. The words you use in a YAML (like ‘title,’ ‘author,’ etc.) are specific to the YAML, so don’t add anything in there that YAMLs don’t use.

---
title: "The best title"
author: "You"
date: "YYYY-MM-DD"
output: html_document
---

1.2. Add your subsections

Next, so you can see exactly what you are building, we are going to open the document outline in R Studio. To open the document outline, either:

  • Press Control + Shift+ O

  • Click the ‘outline’ button in the most upper right corner of your text editor window.

Here is the outline of an example anaysis.

Outline of an example analysis.

Outline of an example analysis.

(And here is an example of what the outline for this R Markdown HTML report looks like, which is completely different.)

Outline for this R Markdown HTML Notebook.

Outline for this R Markdown HTML Notebook.

Outlines are available for a document types, including R Markdown and R Scripts. You’ll notice in this R Markdown document that different sections headers are listed in the outline for this document. You can click on those to navigate this document.

You can view subsections in your document outline. This structure is up to the user, but, personally, I use the following.


# Directories ---------

# Libraries -------

# Import Data -----

# Functions -------

# Analysis

# *** Correlation ---------

# *** Visualizations ------

# *** Save Outputs -----

In the above example, I use # *** [text] ---- in an attempt to make a level down subsection. Here I consider “Correlation”, “Visualizations”, and “Save Outputs” are all part of doing an analysis. You can use anything to take the space of the asterisk (*) but I think asterisks look best.

These headers work the same as if I wrote them as # Libraries ####.

Below is a short example of a reasonably organized R script that we will build on more. This script is going to correlate some columns and make some plots using one of R’s built in datasets called mpg from the ggplot2 package. To learn more about mpg, type ??mpg in your console, but essentially this dataset describes fuel economy data from 1999 to 2008 for 38 popular models of cars where:

  • displ: engine displacement, in litres

  • cty: city miles per gallon

  • hwy: highway miles per gallon

#' ---
#' title: Engine displacement in cities and on highways. 
#' purpose: This script is going to correlate the displ, cty, and hwy columns of R's built in dataset called mpg from the ggplot2 package and make some plots of those correlations. 
#' author: You
#' date: YYYY-MM-DD
#' ---

# Directories ---------

# Libraries -------

library(ggplot2)
library(ggpubr)

# Import Data -----

data(mpg)

# Functions -------

# Analysis -----

# *** Correlation ---------

cor_hwy<-cor(mpg$displ, mpg$hwy)

cor_cty<-cor(mpg$displ, mpg$cty)

# *** Visualizations ------

g1<-ggplot(mpg, aes(displ, hwy)) +
  geom_point() + 
  geom_smooth(method = "lm") + 
  ggtitle(paste0("Pearson correlation coefficient = ", round(cor_hwy, digits = 2))) +
  ylim(5, 45)

g2<-ggplot(mpg, aes(displ, cty)) +
  geom_point() + 
  geom_smooth(method = "lm") + 
  ggtitle(paste0("Pearson correlation coefficient = ", round(cor_cty, digits = 2))) +
  ylim(5, 45)

g<-ggarrange(plotlist = list(g1, g2),
               nrow=1, ncol = 2)

# *** Save Outputs -----

ggsave(filename = "graph.png", plot = g)
g
Output from script

Output from script

This is a great start! Here we are using a predictable structure for our code, we know where to look for each section, and it looks great! But get ready, there are a few more things to do!

2. Annotate

So, what is actually happening in this script? I just wrote it, so I know, in this moment, exactly what is going on. But will “future me” remember? Future me is pretty forgetful and likes quick answers. As to not upset this irratable future me, it might be best to write a few notes in the document right now. We can easily do that with a single (or more, if you like) hash mark (#) before comment text. See below how I integrate it into the script we just wrote.

Admittedly, I don’t usually write this many comments, but for the purposes of this example I want to be extra explicit.

#' ---
#' title: Engine displacement in cities and on highways. 
#' purpose: This script is going to correlate the displ, cty, and hwy columns of R's built in dataset called mpg from the ggplot2 package and make some plots of those correlations. 
#' author: You
#' date: YYYY-MM-DD
#' ---

# Directories ---------

dir<-getwd() #This is the current directory. This is not currently needed, thought. 

# Libraries ---------

library(ggplot2) # Makes pretty plots
library(ggpubr) # Arranges multiple ggplots on the same page

# Import Data -----

# Download data describing Fuel economy data from 1999 to 2008 for 38 popular models of cars. 
# This data is built into the ggplot2 library. Use "?mpg" to learn more about this dataset. 
data(mpg)
#Columns of interest include: 
## "displ" = engine displacement, in litres
## "cty" = city miles per gallon
## "hwy" = highway miles per gallon

# Functions -------

# There are currently no functions for this script. 

# Analysis -----

# *** Correlation ---------

#Find the Pearson correlation coefficient for:
## engine displacement (litres) ~ highway mpg
cor_hwy<-cor(mpg$displ, mpg$hwy) 

## engine displacement (litres) ~ city mpg
cor_cty<-cor(mpg$displ, mpg$cty)

# *** Visualizations ------

#Create plots displaying data points, a smooth linear model trend line (note 'method = lm'), and a useful title. 

## engine displacement (litres) ~ highway mpg
g1<-ggplot(mpg, aes(displ, hwy)) +
  geom_point() + 
  geom_smooth(method = "lm") + 
  ggtitle(paste0("Pearson correlation coefficient = ", round(cor_hwy, digits = 2))) +
    ylim(5, 45)

## engine displacement (litres) ~ city mpg
g2<-ggplot(mpg, aes(displ, cty)) +
  geom_point() + 
  geom_smooth(method = "lm") + 
  ggtitle(paste0("Pearson correlation coefficient = ", round(cor_cty, digits = 2))) +
    ylim(5, 45)

## arrange these two plots side by side so we can compare differences between the plots. 
g<-ggarrange(plotlist = list(g1, g2),
               nrow=1, ncol = 2)

# *** Save Outputs -----

#Save your plot so you can use and find it later. 
ggsave(filename = "graph.png", plot = g)
g
Output from script

Output from script

Wow! I will never be in the dark again about past me’s true genius. I would feel comfortable sending this off to any colleague - maybe even colleagues who doesn’t code?! - because I know they will understand what I was trying to do.

3. Never repeat code

I see a lot of redundancy in this code. What if I told you I could remove a third of the content in this script with one simple function? Repeating code to do the same thing over and over again will inevitably lead to mistakes, conflicts, and typos. Further, what if we suddenly decided we wanted all graphs to have a new title or change the colors? In the old script, we would have to change the code going into each plot individually. Now, with a function, we can change that once in just one place and it will be changed everywhere.

Though this is a small example and this version of the code would really be sufficient, I am sure you can see how these issues could become a massive problem in a long script you have been working tirelessly on.

analysis.R

(I’ll save the below file as the above name so you can view it later, too).

#' ---
#' title: Engine displacement in cities and on highways. 
#' purpose: This script is going to correlate the displ, cty, and hwy columns of R's built in dataset called mpg from the ggplot2 package and make some plots of those correlations. 
#' author: You
#' date: YYYY-MM-DD
#' ---

# Directories ---------

dir<-getwd() #This is the current directory. This is not currently needed, thought. 

# Libraries ---------

library(ggplot2) # Makes pretty plots
library(ggpubr) # Arranges multiple ggplots on the same page

# Import Data -----

# Download data describing Fuel economy data from 1999 to 2008 for 38 popular models of cars. 
# This data is built into the ggplot2 library. Use "?mpg" to learn more about this dataset. 
data(mpg)
#Columns of interest include: 
## "displ" = engine displacement, in litres
## "cty" = city miles per gallon
## "hwy" = highway miles per gallon

# Functions -------

createplot<-function(x, y) {
  #Createplot is a function for calculating the Pearson correlation coefficient and plotting two variables (x and y) against each other 
  
  #Find the Pearson correlation coefficient
  cor_<-cor(x, y)
  
  #Create plots displaying data points, a smooth linear model trend line (note 'method = lm'), and a useful title. 
  g<-ggplot(mpg, aes(x, y)) +
    geom_point() + # plots points
    geom_smooth(method = "lm") + #plots trend line using a linear model
    ggtitle(paste0("Pearson correlation coefficient = ", round(cor_, digits = 2))) + # displays title with Pearson correlation coefficient
    ylim(5, 45) # standardizes the hieght of the y-axis
  
  #return outputs our graph from the function. 
  return(g)
}

# Analysis -----

# *** Visualizations ------

#Use createplot to output our two finished plots. 
g1<-createplot(x = mpg$displ, y = mpg$hwy)

g2<-createplot(x = mpg$displ, y = mpg$cty)

## arrange these two plots side by side so we can compare differences between the plots. 
g<-ggarrange(plotlist = list(g1, g2),
               nrow=1, ncol = 2)

# *** Save Outputs -----

#Save your plot so you can use and find it later. 
ggsave(filename = "graph.png", plot = g)
g
Output from script

Output from script

4. Name files with predictable and helpful names

“graph.png” is not a terribly helpful name for any file. Good in a pinch, not in the long run. There are a few questions immediately come to mind:

  • What analysis does this plot belong to?
  • At what part of the analysis was this output created? e.g., order?
  • Why do I care about this analysis? e.g., a more descriptive name?
  • What run is this analysis from? e.g., date? (something to think about but skipping this for now. We’ll get to it next.)

I usually try to keep all of my files to similar naming structure like this one.

[Order]-[AnalysisName]-[Description].[filetype]

A few rules:

  • No spaces. You can use ThisLetterCasing or thisLetterCasing to separate words.
  • Use underscores () or dashes (-) to separate ideas so it can be easy to read. Python has issues with underscores (), so you may want to use dashes (-).
  • Names should be kept as short as possible. Some applications (including R, though it varies by action and file type) have a letter count limit on file names.

With this in mind, I might change the file name graph.png in ggsave(filename = "graph.png", plot = g) to 1_TestAnalysis_Graph.png by using the below code:

counter<-0
counter<-counter + 1
filename = paste0(counter, "_TestAnalysis_Graph.png")
ggsave(filename = filename, plot = g)

The counter is not really necessary, but is useful if I want to keep the order of these files in my file folder. If you have to make many of these (or any other) plots but don’t want to have to search for them in a sea of files, numbering can help make their location in the folder predictable.

5. Predictable folder structure

Let’s say that you are working on this analysis over the course of several months and you don’t want to overwrite your outputs each time you run your script or get lost in a sea of files. It’s a little complicated to set up, but I suggest the following:

5.1. Set up three new folders

In a given project, I keep all of my files (generally) in three folders. Note that "./" is R shorthand for “current directory,” which would be the directory of your R Project.

  • rscripts: where you will save all of your rscripts, including this script we have been working on.
  • data: where you will store all of your local data that goes into a script (though not really relevant here since we are using some of R’s in-house data).
  • output: where results from your analysis will go.
dir.create(path = "./rscripts")
dir.create(path = "./data")
dir.create(path = "./output")
The root folder’s stucture.

The root folder’s stucture.

5.2. Create a folder for that analysis run within the output folder

For each day’s run of your analysis, you might like to set up a new file to save everything in. Within that folder, you might also like to keep a copy of what you used to create this file. I recommend automatically creating folders within this new output folder for your rscripts, rawdata, figures, etc. This might seem predicable, but with the:

  • figures folder, we save all of our output figures from the analysis.
  • rscripts folder, we save all of the rscripts we used to create this analysis with. I know many of you must be thinking that this is redundant in a world with GitHub, but it gives me some peace of mind to have all of these things together. Here I use a simple loop to find all of the files in my ./rscripts/ file in the root directory and copy them to the output’s ./output/[folder for that day's code run]/rscripts/ folder.
  • rawdata folder, we store all of the raw data we used to create this analysis.
The output folder’s stucture.

The output folder’s stucture.

There is nothing stopping you from having other folders here with different outputs, like tables or worddocuments. Just keep the names helpful and predictable.


# Directories -------

outputfolder<-paste0("./output/TestAnalysis_", Sys.Date(), "/") # Define the name of the new output folder. Sys.Date() will add today's name to the file folder's name. 
dir.create(path = outputfolder) # Create folder for today's analysis run

dir.create(path = paste0(outputfolder, "rawdata"))
dir.create(path = paste0(outputfolder, "figures"))
dir.create(path = paste0(outputfolder, "rscripts"))

listfiles<-list.files(path = "./rscripts/") #Find all files in "./rscripts"
for (i in 1:length(listfiles)){ # Save all of those files to the rscripts folder in the output folder
  file.copy(from = paste0("./rscripts/", listfiles[i]), 
            to = paste0("./",outputfolder,"/rscripts/", listfiles[i]), 
            overwrite = T)
}

6. Scripts with specific tasks

In a world where your analyses are a bit more complicated, I find that it is good to split your code into the following files:

  • functions.R, this file will be where all of the funcitons used to run your analysis.
  • data.R, this file will load all of your data and edit it for your analysis. Never hand edit data from a source. If you can, always manipulate it so you never destroy your original data copy.
  • run.R, this file will source the other files you created and run the analysis. We want this to have the bare-bones of what we need for our analysis.
The output rscripts’s stucture.

The output rscripts’s stucture.

Such that your new files would look like this and would all be saved in the “rscripts” folder:

functions.R

#' title: Engine displacement in cities and on highways. 
#' purpose: This script is going to correlate the displ, cty, and hwy columns of R's built in dataset called mpg from the ggplot2 package and make some plots of those correlations. 
#' author: You
#' date: YYYY-MM-DD
#' ---

rm(list=ls())

# Libraries -------
PKG <- c("ggplot2", "ggpubr")
for (p in PKG) {
  if(!require(p,character.only = TRUE)) {  
    install.packages(p)
    require(p,character.only = TRUE)}
}


# Directories -------

outputfolder<-paste0("./output/TestAnalysis_", Sys.Date(), "/") # Define the name of the new output folder. Sys.Date() will add today's name to the file folder's name. 
dir.create(path = outputfolder) # Create folder for today's analysis run

dir.create(path = paste0(outputfolder, "rawdata"))
dir.create(path = paste0(outputfolder, "figures"))
dir.create(path = paste0(outputfolder, "rscripts"))
listfiles<-list.files(path = "./rscripts/") #Find all files in "./rscripts"
for (i in 1:length(listfiles)){ # Save all of those files to the rscripts folder in the output folder
  file.copy(from = paste0("./rscripts/", listfiles[i]), 
            to = paste0("./",outputfolder,"/rscripts/", listfiles[i]), 
            overwrite = T)
}

# Functions -------

createplot<-function(x, y) {
  #Createplot is a function for calculating the Pearson correlation coefficient and plotting two variables (x and y) against each other 
  
  #Find the Pearson correlation coefficient
  cor_<-cor(x, y)
  
  #Create plots displaying data points, a smooth linear model trend line (note 'method = lm'), and a useful title. 
  g<-ggplot(mpg, aes(x, y)) +
    geom_point() + # plots points
    geom_smooth(method = "lm") + #plots trend line using a linear model
    ggtitle(paste0("Pearson correlation coefficient = ", round(cor_, digits = 2))) + # displays title with Pearson correlation coefficient
    ylim(5, 45) # standardizes the hieght of the y-axis
  
  #return outputs our graph from the function. 
  return(g)
}

data.R

#' title: Engine displacement in cities and on highways. 
#' purpose: This script is going to correlate the displ, cty, and hwy columns of R's built in dataset called mpg from the ggplot2 package and make some plots of those correlations. 
#' author: You
#' date: YYYY-MM-DD
#' ---

# Libraries ---------

library(ggplot2) # Makes pretty plots

# Import Data -----

# Download data describing Fuel economy data from 1999 to 2008 for 38 popular models of cars. 
# This data is built into the ggplot2 library. Use "?mpg" to learn more about this dataset. 

data(mpg)

#Save the rawdata you used for an analysis (if you want to)

write.csv(x = data.frame(mpg), file = paste0(outputfolder, "rawdata/mpg.csv"))

#Columns of interest include: 
## "displ" = engine displacement, in litres
## "cty" = city miles per gallon
## "hwy" = highway miles per gallon

run.R

#' title: Engine displacement in cities and on highways. 
#' purpose: This script is going to correlate the displ, cty, and hwy columns of R's built in dataset called mpg from the ggplot2 package and make some plots of those correlations. 
#' author: You
#' date: YYYY-MM-DD
#' ---

gc() # garbage collection; remove unused variables

# Source Scripts -------

source("./rscripts/functions.R")
source("./rscripts/data.R")

# Analysis -----

#Use createplot to output our two finished plots. 
g1<-createplot(x = mpg$displ, y = mpg$hwy)

g2<-createplot(x = mpg$displ, y = mpg$cty)

## arrange these two plots side by side so we can compare differences between the plots. 
g<-ggarrange(plotlist = list(g1, g2),
               nrow=1, ncol = 2)

# *** Save Outputs -----

#Save your plot so you can use and find it later. 
counter<-0
counter<-counter + 1
filename = paste0(counter, "_TestAnalysis_Graph.png")
ggsave(filename = paste0(outputfolder, "figures/", filename), plot = g)
g
Output from script

Output from script

See how both the functions and data folders are ‘sourced’ into the run script? It makes the script look so much cleaner and easier to read.

7. Save scripts in an “R Project”

You can find more information about projects here: https://support.rstudio.com/hc/en-us/articles/200526207-Using-Projects

R projects are important for:

  • organizing your analysis from the nuts and bolts (functions and packages) to analysis output (r scripts).
  • sharing your projects to Git Hub
  • so you can establish a ‘relative’ directory (as opposed to a local directory that requires a specific address in your computer)
  • creating R Shiny apps, packages, etc. (beyond the scope of this example)

To create a project for this work, click File>New Project>Existing Directory

File>New Project>Existing Directory

File>New Project>Existing Directory

File>New Project>Existing Directory

File>New Project>Existing Directory

We selected “Existing Directory” since we already have one. It is known as our parent directory and what I have been referring to as ./ in the directory name.

Projects manifest themselves, more or less, as fancy folders where R has automatically deposited the following files:

  • Creates a project file (with an .Rproj extension) within the project directory. This file contains various project options (discussed below) and can also be used as a shortcut for opening the project directly from the filesystem.
  • Creates a hidden directory (named .Rproj.user) where project-specific temporary files (e.g. auto-saved source documents, window-state, etc.) are stored. This directory is also automatically added to .Rbuildignore, .gitignore, etc. if required.

Now, the project is loaded into RStudio and the name is displayed in the Projects toolbar (which is located on the far right side of the main toolbar). Additionally, the project (and all progress on the files) will be easily loadable from File>Recent Projects or File>Open Project.

If you want access to this R Project from my GitHub, for example, you can access it by going to the GitHub link below and downloading it, or with the below code.

install.packages("usethis")
library(usethis) # Automate package and project setup tasks that are otherwise performed manually.
usethis::use_course(url = 'https://github.com/emilyhmarkowitz/BestScriptingPractices/archive/master.zip', 
                    destdir = "your/local/directory/")

8. Other packages to consider using!

Below are some other packages that are worth a closer look as you play around with making beautifully written and organized code!

here

A Simpler Way to Find Your Files

Constructs paths to your project’s files. The ‘here()’ function uses a reasonable heuristics to find your project’s files, based on the current working directory at the time when the package is loaded. Use it as a drop-in replacement for ‘file.path()’, it will always locate the files relative to your project root.

https://github.com/krlmlr/here, http://krlmlr.github.io/here

packrat

A Dependency Management System for Projects and their R Package Dependencies

Manage the R packages your project depends on in an isolated, portable, and reproducible way.

https://github.com/rstudio/packrat/

foreach

Provides Foreach Looping Construct

Support for the foreach looping construct. Foreach is an idiom that allows for iterating over elements in a collection, without the use of an explicit loop counter. This package in particular is intended to be used for its return value, rather than for its side effects. In that sense, it is similar to the standard lapply function, but doesn’t require the evaluation of a function. Using foreach without side effects also facilitates executing the loop in parallel.

https://github.com/RevolutionAnalytics/foreach

LS0tDQp0aXRsZTogIkJlc3QgU2NyaXB0aW5nIFByYWN0aWNlcyINCmF1dGhvcjogIkVtaWx5IE1hcmtvd2l0eiAoRW1pbHkuTWFya293aXR6QE5PQUEuZ292KSINCm91dHB1dDoNCiAgaHRtbF9ub3RlYm9vazoNCiAgICB0b2M6IHRydWUNCiAgICB0b2NfZmxvYXQ6IHRydWUNCiAgICB0b2NfZGVwdGg6IDQNCiAgICB0aGVtZTogZmxhdGx5DQotLS0NCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpDQpgYGANCg0KQmVsb3cgSSBsaXN0IGEgZmV3IGNvbW1hbmRtZW50cyBvZiBSIHNjcmlwdGluZyB0aGF0IHdpbGwgZ3VpZGUgdXMgdGhyb3VnaCB0aGlzIGxlc3Nvbi4gRnV0dXJlIHlvdSBhbmQgYWxsIHRob3NlIGFyb3VuZCB5b3Ugd2lsbCBzaW5nIHlvdXIgcHJhaXNlcyBpZiB5b3UgZm9sbG93IHRoZXNlLg0KDQpXZSdsbCBnbyB0aHJvdWdoIGFsbCBvZiB0aGVzZSBpbiBzb21lIGRldGFpbCB3aXRoIGFuIGV4YW1wbGUgc2NyaXB0IQ0KDQojIyAxLiBDb25mb3JtIHRvIGEgcHJlZGljdGFibGUgc2NyaXB0IHN0cnVjdHVyZQ0KDQojIyMgKioxLjEuIFByb3ZpZGUgeW91ciBtZXRhZGF0YSBhYm91dCB0aGUgZG9jdW1lbnQgKG5vdCByZXF1aXJlZCwgYnV0IGhlbHBmdWwpKioNCg0KSXQgaXMgYWx3YXlzIGEgZ29vZCBpZGVhIHRvIHdyaXRlIGF0IHRoZSB0b3Agb2YgYSBzY3JpcHQgd2hvIHdyb3RlIGl0IChnaXZlIHlvdXJzZWxmIHNvbWUgY3JlZGl0ISksIHdoZW4sIGFuZCB3aHkgaXQgd2FzIHdyaXR0ZW4uIEluIHRoZSBjYXNlIG9mIGFuIFIgc2NyaXB0IChhcyBvcHBvc2VkIHRvIGFuIFIgTWFya2Rvd24gZG9jdW1lbnQpLCB3ZSBtaWdodCB3cml0ZSBzb21ldGhpbmcgbGlrZSB0aGUgYmVsb3cgYXQgdGhlIHRvcCBvZiBvdXIgZG9jdW1lbnQuIA0KDQpgYGB7cn0NCiMnIC0tLQ0KIycgdGl0bGU6IFRoZSBiZXN0IHRpdGxlDQojJyBwdXJwb3NlOiBibGFyZw0KIycgYXV0aG9yOiBZb3UNCiMnIGRhdGU6IFlZWVktTU0tREQNCiMnIC0tLQ0KYGBgDQoNClNpbmNlIHRoZSBhYm92ZSBpcyBjb21tZW50ZWQgb3V0LCBpdCBpcyBjb21wbGV0ZWx5IGluZXJ0LiBUaGUgUiBkb2VzIG5vdCBydW4gb3IgdXNlIHRoaXMgaW5mb3JtYXRpb24gaW4gYW55d2F5LiANCg0KU2ltaWxhcmx5LCBSIE1hcmRvd24gZG9jdW1lbnRzIGhhdmUgYW4gZWxlbWVudCBidWlsdCBpbnRvIHRoZSB0b3Agb2YgdGhlaXIgZG9jdW1lbnRzIGNhbGxlZCBhIFlBTUwsIHdoaWNoIGlzIHVzZWQgaW4gYSBzbGlnaHRseSBkaWZmZXJlbnQgd2F5IGJ5IFIsIGJ1dCBhY2NvbXBsaXNoZXMgYSBzaW1pbGFyIGZlYXQuIFRoZSB3b3JkcyB5b3UgdXNlIGluIGEgWUFNTCAobGlrZSAndGl0bGUsJyAnYXV0aG9yLCcgZXRjLikgYXJlIHNwZWNpZmljIHRvIHRoZSBZQU1MLCBzbyBkb24ndCBhZGQgYW55dGhpbmcgaW4gdGhlcmUgdGhhdCBZQU1McyBkb24ndCB1c2UuIA0KDQpgYGB7ciwgaW5jbHVkZSwgZXZhbD1GQUxTRX0NCi0tLQ0KdGl0bGU6ICJUaGUgYmVzdCB0aXRsZSINCmF1dGhvcjogIllvdSINCmRhdGU6ICJZWVlZLU1NLUREIg0Kb3V0cHV0OiBodG1sX2RvY3VtZW50DQotLS0NCmBgYA0KDQojIyMgKioxLjIuIEFkZCB5b3VyIHN1YnNlY3Rpb25zKioNCg0KTmV4dCwgc28geW91IGNhbiBzZWUgZXhhY3RseSB3aGF0IHlvdSBhcmUgYnVpbGRpbmcsIHdlIGFyZSBnb2luZyB0byBvcGVuIHRoZSBkb2N1bWVudCBvdXRsaW5lIGluIFIgU3R1ZGlvLiBUbyBvcGVuIHRoZSBkb2N1bWVudCBvdXRsaW5lLCBlaXRoZXI6IA0KDQogLSBQcmVzcyBgQ29udHJvbGAgKyBgU2hpZnRgKyBgT2ANCiANCiAtIENsaWNrIHRoZSAnb3V0bGluZScgYnV0dG9uIGluIHRoZSBtb3N0IHVwcGVyIHJpZ2h0IGNvcm5lciBvZiB5b3VyIHRleHQgZWRpdG9yIHdpbmRvdy4gDQogDQpIZXJlIGlzIHRoZSBvdXRsaW5lIG9mIGFuIGV4YW1wbGUgYW5heXNpcy4gDQoNCiFbT3V0bGluZSBvZiBhbiBleGFtcGxlIGFuYWx5c2lzLl0oLi9FeGFtcGxlT3V0bGluZS5KUEcpDQoNCiANCihBbmQgaGVyZSBpcyBhbiBleGFtcGxlIG9mIHdoYXQgdGhlIG91dGxpbmUgZm9yIHRoaXMgUiBNYXJrZG93biBIVE1MIHJlcG9ydCBsb29rcyBsaWtlLCB3aGljaCBpcyBjb21wbGV0ZWx5ICBkaWZmZXJlbnQuKQ0KDQohW091dGxpbmUgZm9yIHRoaXMgUiBNYXJrZG93biBIVE1MIE5vdGVib29rLl0oLi9UaGlzUmVwb3J0T3V0bGluZS5KUEcpDQoNCiANCk91dGxpbmVzIGFyZSBhdmFpbGFibGUgZm9yIGEgZG9jdW1lbnQgdHlwZXMsIGluY2x1ZGluZyBSIE1hcmtkb3duIGFuZCBSIFNjcmlwdHMuIFlvdSdsbCBub3RpY2UgaW4gdGhpcyBSIE1hcmtkb3duIGRvY3VtZW50IHRoYXQgZGlmZmVyZW50IHNlY3Rpb25zIGhlYWRlcnMgYXJlIGxpc3RlZCBpbiB0aGUgb3V0bGluZSBmb3IgdGhpcyBkb2N1bWVudC4gWW91IGNhbiBjbGljayBvbiB0aG9zZSB0byBuYXZpZ2F0ZSB0aGlzIGRvY3VtZW50LiAgDQoNCllvdSBjYW4gdmlldyBzdWJzZWN0aW9ucyBpbiB5b3VyIGRvY3VtZW50IG91dGxpbmUuIFRoaXMgc3RydWN0dXJlIGlzIHVwIHRvIHRoZSB1c2VyLCBidXQsIHBlcnNvbmFsbHksIEkgdXNlIHRoZSBmb2xsb3dpbmcuIA0KDQpgYGB7cn0NCg0KIyBEaXJlY3RvcmllcyAtLS0tLS0tLS0NCg0KIyBMaWJyYXJpZXMgLS0tLS0tLQ0KDQojIEltcG9ydCBEYXRhIC0tLS0tDQoNCiMgRnVuY3Rpb25zIC0tLS0tLS0NCg0KIyBBbmFseXNpcw0KDQojICoqKiBDb3JyZWxhdGlvbiAtLS0tLS0tLS0NCg0KIyAqKiogVmlzdWFsaXphdGlvbnMgLS0tLS0tDQoNCiMgKioqIFNhdmUgT3V0cHV0cyAtLS0tLQ0KDQpgYGANCg0KSW4gdGhlIGFib3ZlIGV4YW1wbGUsIEkgdXNlIGAjICoqKiBbdGV4dF0gLS0tLWAgaW4gYW4gYXR0ZW1wdCB0byBtYWtlIGEgbGV2ZWwgZG93biBzdWJzZWN0aW9uLiBIZXJlIEkgY29uc2lkZXIgIkNvcnJlbGF0aW9uIiwgIlZpc3VhbGl6YXRpb25zIiwgYW5kICJTYXZlIE91dHB1dHMiIGFyZSBhbGwgcGFydCBvZiBkb2luZyBhbiBhbmFseXNpcy4gWW91IGNhbiB1c2UgYW55dGhpbmcgdG8gdGFrZSB0aGUgc3BhY2Ugb2YgdGhlIGFzdGVyaXNrIChgKmApIGJ1dCBJIHRoaW5rIGFzdGVyaXNrcyBsb29rIGJlc3QuIA0KDQpUaGVzZSBoZWFkZXJzIHdvcmsgdGhlIHNhbWUgYXMgaWYgSSB3cm90ZSB0aGVtIGFzIGAjIExpYnJhcmllcyAjIyMjYC4gDQoNCkJlbG93IGlzIGEgc2hvcnQgZXhhbXBsZSBvZiBhIHJlYXNvbmFibHkgb3JnYW5pemVkIFIgc2NyaXB0IHRoYXQgd2Ugd2lsbCBidWlsZCBvbiBtb3JlLiBUaGlzIHNjcmlwdCBpcyBnb2luZyB0byBjb3JyZWxhdGUgc29tZSBjb2x1bW5zIGFuZCBtYWtlIHNvbWUgcGxvdHMgdXNpbmcgb25lIG9mIFIncyBidWlsdCBpbiBkYXRhc2V0cyBjYWxsZWQgYG1wZ2AgZnJvbSB0aGUgYGdncGxvdDJgIHBhY2thZ2UuIFRvIGxlYXJuIG1vcmUgYWJvdXQgYG1wZ2AsIHR5cGUgYD8/bXBnYCBpbiB5b3VyIGNvbnNvbGUsIGJ1dCBlc3NlbnRpYWxseSB0aGlzIGRhdGFzZXQgZGVzY3JpYmVzIGZ1ZWwgZWNvbm9teSBkYXRhIGZyb20gMTk5OSB0byAyMDA4IGZvciAzOCBwb3B1bGFyIG1vZGVscyBvZiBjYXJzIHdoZXJlOiANCg0KIC0gKipkaXNwbCoqOiBlbmdpbmUgZGlzcGxhY2VtZW50LCBpbiBsaXRyZXMNCg0KIC0gKipjdHkqKjogY2l0eSBtaWxlcyBwZXIgZ2FsbG9uDQogDQogLSAqKmh3eSoqOiBoaWdod2F5IG1pbGVzIHBlciBnYWxsb24NCiANCiANCmBgYHtyLCB3YXJuaW5nPUZBTFNFLCBpbmNsdWRlPVRSVUUsIGV2YWw9VFJVRX0NCiMnIC0tLQ0KIycgdGl0bGU6IEVuZ2luZSBkaXNwbGFjZW1lbnQgaW4gY2l0aWVzIGFuZCBvbiBoaWdod2F5cy4gDQojJyBwdXJwb3NlOiBUaGlzIHNjcmlwdCBpcyBnb2luZyB0byBjb3JyZWxhdGUgdGhlIGRpc3BsLCBjdHksIGFuZCBod3kgY29sdW1ucyBvZiBSJ3MgYnVpbHQgaW4gZGF0YXNldCBjYWxsZWQgbXBnIGZyb20gdGhlIGdncGxvdDIgcGFja2FnZSBhbmQgbWFrZSBzb21lIHBsb3RzIG9mIHRob3NlIGNvcnJlbGF0aW9ucy4gDQojJyBhdXRob3I6IFlvdQ0KIycgZGF0ZTogWVlZWS1NTS1ERA0KIycgLS0tDQoNCiMgRGlyZWN0b3JpZXMgLS0tLS0tLS0tDQoNCiMgTGlicmFyaWVzIC0tLS0tLS0NCg0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShnZ3B1YnIpDQoNCiMgSW1wb3J0IERhdGEgLS0tLS0NCg0KZGF0YShtcGcpDQoNCiMgRnVuY3Rpb25zIC0tLS0tLS0NCg0KIyBBbmFseXNpcyAtLS0tLQ0KDQojICoqKiBDb3JyZWxhdGlvbiAtLS0tLS0tLS0NCg0KY29yX2h3eTwtY29yKG1wZyRkaXNwbCwgbXBnJGh3eSkNCg0KY29yX2N0eTwtY29yKG1wZyRkaXNwbCwgbXBnJGN0eSkNCg0KIyAqKiogVmlzdWFsaXphdGlvbnMgLS0tLS0tDQoNCmcxPC1nZ3Bsb3QobXBnLCBhZXMoZGlzcGwsIGh3eSkpICsNCiAgZ2VvbV9wb2ludCgpICsgDQogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIpICsgDQogIGdndGl0bGUocGFzdGUwKCJQZWFyc29uIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50ID0gIiwgcm91bmQoY29yX2h3eSwgZGlnaXRzID0gMikpKSArDQogIHlsaW0oNSwgNDUpDQoNCmcyPC1nZ3Bsb3QobXBnLCBhZXMoZGlzcGwsIGN0eSkpICsNCiAgZ2VvbV9wb2ludCgpICsgDQogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIpICsgDQogIGdndGl0bGUocGFzdGUwKCJQZWFyc29uIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50ID0gIiwgcm91bmQoY29yX2N0eSwgZGlnaXRzID0gMikpKSArDQogIHlsaW0oNSwgNDUpDQoNCmc8LWdnYXJyYW5nZShwbG90bGlzdCA9IGxpc3QoZzEsIGcyKSwNCiAgICAgICAgICAgICAgIG5yb3c9MSwgbmNvbCA9IDIpDQoNCiMgKioqIFNhdmUgT3V0cHV0cyAtLS0tLQ0KDQpnZ3NhdmUoZmlsZW5hbWUgPSAiZ3JhcGgucG5nIiwgcGxvdCA9IGcpDQpnDQoNCmBgYA0KDQohWypPdXRwdXQgZnJvbSBzY3JpcHQqXSguL2dyYXBoLnBuZykNCg0KVGhpcyBpcyBhIGdyZWF0IHN0YXJ0ISBIZXJlIHdlIGFyZSB1c2luZyBhIHByZWRpY3RhYmxlIHN0cnVjdHVyZSBmb3Igb3VyIGNvZGUsIHdlIGtub3cgd2hlcmUgdG8gbG9vayBmb3IgZWFjaCBzZWN0aW9uLCBhbmQgaXQgbG9va3MgZ3JlYXQhIEJ1dCBnZXQgcmVhZHksIHRoZXJlIGFyZSBhIGZldyBtb3JlIHRoaW5ncyB0byBkbyENCg0KIyMgMi4gQW5ub3RhdGUNCg0KU28sIHdoYXQgaXMgYWN0dWFsbHkgaGFwcGVuaW5nIGluIHRoaXMgc2NyaXB0PyBJIGp1c3Qgd3JvdGUgaXQsIHNvICpJIGtub3cqLCAqKippbiB0aGlzIG1vbWVudCoqKiwgZXhhY3RseSB3aGF0IGlzIGdvaW5nIG9uLiBCdXQgd2lsbCAqImZ1dHVyZSBtZSIqIHJlbWVtYmVyPyBGdXR1cmUgbWUgaXMgcHJldHR5IGZvcmdldGZ1bCBhbmQgbGlrZXMgcXVpY2sgYW5zd2Vycy4gQXMgdG8gbm90IHVwc2V0IHRoaXMgaXJyYXRhYmxlIGZ1dHVyZSBtZSwgaXQgbWlnaHQgYmUgYmVzdCB0byB3cml0ZSBhIGZldyBub3RlcyBpbiB0aGUgZG9jdW1lbnQgcmlnaHQgbm93LiBXZSBjYW4gZWFzaWx5IGRvIHRoYXQgd2l0aCBhIHNpbmdsZSAob3IgbW9yZSwgaWYgeW91IGxpa2UpIGhhc2ggbWFyayAoIykgYmVmb3JlIGNvbW1lbnQgdGV4dC4gU2VlIGJlbG93IGhvdyBJIGludGVncmF0ZSBpdCBpbnRvIHRoZSBzY3JpcHQgd2UganVzdCB3cm90ZS4NCg0KQWRtaXR0ZWRseSwgSSBkb24ndCB1c3VhbGx5IHdyaXRlIHRoaXMgbWFueSBjb21tZW50cywgYnV0IGZvciB0aGUgcHVycG9zZXMgb2YgdGhpcyBleGFtcGxlIEkgd2FudCB0byBiZSBleHRyYSBleHBsaWNpdC4gDQoNCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQ0KIycgLS0tDQojJyB0aXRsZTogRW5naW5lIGRpc3BsYWNlbWVudCBpbiBjaXRpZXMgYW5kIG9uIGhpZ2h3YXlzLiANCiMnIHB1cnBvc2U6IFRoaXMgc2NyaXB0IGlzIGdvaW5nIHRvIGNvcnJlbGF0ZSB0aGUgZGlzcGwsIGN0eSwgYW5kIGh3eSBjb2x1bW5zIG9mIFIncyBidWlsdCBpbiBkYXRhc2V0IGNhbGxlZCBtcGcgZnJvbSB0aGUgZ2dwbG90MiBwYWNrYWdlIGFuZCBtYWtlIHNvbWUgcGxvdHMgb2YgdGhvc2UgY29ycmVsYXRpb25zLiANCiMnIGF1dGhvcjogWW91DQojJyBkYXRlOiBZWVlZLU1NLUREDQojJyAtLS0NCg0KIyBEaXJlY3RvcmllcyAtLS0tLS0tLS0NCg0KZGlyPC1nZXR3ZCgpICNUaGlzIGlzIHRoZSBjdXJyZW50IGRpcmVjdG9yeS4gVGhpcyBpcyBub3QgY3VycmVudGx5IG5lZWRlZCwgdGhvdWdodC4gDQoNCiMgTGlicmFyaWVzIC0tLS0tLS0tLQ0KDQpsaWJyYXJ5KGdncGxvdDIpICMgTWFrZXMgcHJldHR5IHBsb3RzDQpsaWJyYXJ5KGdncHVicikgIyBBcnJhbmdlcyBtdWx0aXBsZSBnZ3Bsb3RzIG9uIHRoZSBzYW1lIHBhZ2UNCg0KIyBJbXBvcnQgRGF0YSAtLS0tLQ0KDQojIERvd25sb2FkIGRhdGEgZGVzY3JpYmluZyBGdWVsIGVjb25vbXkgZGF0YSBmcm9tIDE5OTkgdG8gMjAwOCBmb3IgMzggcG9wdWxhciBtb2RlbHMgb2YgY2Fycy4gDQojIFRoaXMgZGF0YSBpcyBidWlsdCBpbnRvIHRoZSBnZ3Bsb3QyIGxpYnJhcnkuIFVzZSAiP21wZyIgdG8gbGVhcm4gbW9yZSBhYm91dCB0aGlzIGRhdGFzZXQuIA0KZGF0YShtcGcpDQojQ29sdW1ucyBvZiBpbnRlcmVzdCBpbmNsdWRlOiANCiMjICJkaXNwbCIgPSBlbmdpbmUgZGlzcGxhY2VtZW50LCBpbiBsaXRyZXMNCiMjICJjdHkiID0gY2l0eSBtaWxlcyBwZXIgZ2FsbG9uDQojIyAiaHd5IiA9IGhpZ2h3YXkgbWlsZXMgcGVyIGdhbGxvbg0KDQojIEZ1bmN0aW9ucyAtLS0tLS0tDQoNCiMgVGhlcmUgYXJlIGN1cnJlbnRseSBubyBmdW5jdGlvbnMgZm9yIHRoaXMgc2NyaXB0LiANCg0KIyBBbmFseXNpcyAtLS0tLQ0KDQojICoqKiBDb3JyZWxhdGlvbiAtLS0tLS0tLS0NCg0KI0ZpbmQgdGhlIFBlYXJzb24gY29ycmVsYXRpb24gY29lZmZpY2llbnQgZm9yOg0KIyMgZW5naW5lIGRpc3BsYWNlbWVudCAobGl0cmVzKSB+IGhpZ2h3YXkgbXBnDQpjb3JfaHd5PC1jb3IobXBnJGRpc3BsLCBtcGckaHd5KSANCg0KIyMgZW5naW5lIGRpc3BsYWNlbWVudCAobGl0cmVzKSB+IGNpdHkgbXBnDQpjb3JfY3R5PC1jb3IobXBnJGRpc3BsLCBtcGckY3R5KQ0KDQojICoqKiBWaXN1YWxpemF0aW9ucyAtLS0tLS0NCg0KI0NyZWF0ZSBwbG90cyBkaXNwbGF5aW5nIGRhdGEgcG9pbnRzLCBhIHNtb290aCBsaW5lYXIgbW9kZWwgdHJlbmQgbGluZSAobm90ZSAnbWV0aG9kID0gbG0nKSwgYW5kIGEgdXNlZnVsIHRpdGxlLiANCg0KIyMgZW5naW5lIGRpc3BsYWNlbWVudCAobGl0cmVzKSB+IGhpZ2h3YXkgbXBnDQpnMTwtZ2dwbG90KG1wZywgYWVzKGRpc3BsLCBod3kpKSArDQogIGdlb21fcG9pbnQoKSArIA0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iKSArIA0KICBnZ3RpdGxlKHBhc3RlMCgiUGVhcnNvbiBjb3JyZWxhdGlvbiBjb2VmZmljaWVudCA9ICIsIHJvdW5kKGNvcl9od3ksIGRpZ2l0cyA9IDIpKSkgKw0KICAgIHlsaW0oNSwgNDUpDQoNCiMjIGVuZ2luZSBkaXNwbGFjZW1lbnQgKGxpdHJlcykgfiBjaXR5IG1wZw0KZzI8LWdncGxvdChtcGcsIGFlcyhkaXNwbCwgY3R5KSkgKw0KICBnZW9tX3BvaW50KCkgKyANCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIikgKyANCiAgZ2d0aXRsZShwYXN0ZTAoIlBlYXJzb24gY29ycmVsYXRpb24gY29lZmZpY2llbnQgPSAiLCByb3VuZChjb3JfY3R5LCBkaWdpdHMgPSAyKSkpICsNCiAgICB5bGltKDUsIDQ1KQ0KDQojIyBhcnJhbmdlIHRoZXNlIHR3byBwbG90cyBzaWRlIGJ5IHNpZGUgc28gd2UgY2FuIGNvbXBhcmUgZGlmZmVyZW5jZXMgYmV0d2VlbiB0aGUgcGxvdHMuIA0KZzwtZ2dhcnJhbmdlKHBsb3RsaXN0ID0gbGlzdChnMSwgZzIpLA0KICAgICAgICAgICAgICAgbnJvdz0xLCBuY29sID0gMikNCg0KIyAqKiogU2F2ZSBPdXRwdXRzIC0tLS0tDQoNCiNTYXZlIHlvdXIgcGxvdCBzbyB5b3UgY2FuIHVzZSBhbmQgZmluZCBpdCBsYXRlci4gDQpnZ3NhdmUoZmlsZW5hbWUgPSAiZ3JhcGgucG5nIiwgcGxvdCA9IGcpDQpnDQoNCmBgYA0KDQoNCiFbKk91dHB1dCBmcm9tIHNjcmlwdCpdKC4vZ3JhcGgucG5nKQ0KDQpXb3chIEkgd2lsbCBuZXZlciBiZSBpbiB0aGUgZGFyayBhZ2FpbiBhYm91dCBwYXN0IG1lJ3MgdHJ1ZSBnZW5pdXMuIEkgd291bGQgZmVlbCBjb21mb3J0YWJsZSBzZW5kaW5nIHRoaXMgb2ZmIHRvIGFueSBjb2xsZWFndWUgLSBtYXliZSBldmVuIGNvbGxlYWd1ZXMgd2hvIGRvZXNuJ3QgY29kZT8hIC0gYmVjYXVzZSBJIGtub3cgdGhleSB3aWxsIHVuZGVyc3RhbmQgd2hhdCBJIHdhcyB0cnlpbmcgdG8gZG8uIA0KDQojIyAzLiAgTmV2ZXIgcmVwZWF0IGNvZGUNCg0KSSBzZWUgYSBsb3Qgb2YgcmVkdW5kYW5jeSBpbiB0aGlzIGNvZGUuIFdoYXQgaWYgSSB0b2xkIHlvdSBJIGNvdWxkIHJlbW92ZSBhIHRoaXJkIG9mIHRoZSBjb250ZW50IGluIHRoaXMgc2NyaXB0IHdpdGggb25lIHNpbXBsZSBmdW5jdGlvbj8gUmVwZWF0aW5nIGNvZGUgdG8gZG8gdGhlIHNhbWUgdGhpbmcgb3ZlciBhbmQgb3ZlciBhZ2FpbiB3aWxsIGluZXZpdGFibHkgbGVhZCB0byBtaXN0YWtlcywgY29uZmxpY3RzLCBhbmQgdHlwb3MuIEZ1cnRoZXIsIHdoYXQgaWYgd2Ugc3VkZGVubHkgZGVjaWRlZCB3ZSB3YW50ZWQgYWxsIGdyYXBocyB0byBoYXZlIGEgbmV3IHRpdGxlIG9yIGNoYW5nZSB0aGUgY29sb3JzPyBJbiB0aGUgb2xkIHNjcmlwdCwgd2Ugd291bGQgaGF2ZSB0byBjaGFuZ2UgdGhlIGNvZGUgZ29pbmcgaW50byBlYWNoIHBsb3QgaW5kaXZpZHVhbGx5LiBOb3csIHdpdGggYSBmdW5jdGlvbiwgd2UgY2FuIGNoYW5nZSB0aGF0IG9uY2UgaW4ganVzdCBvbmUgcGxhY2UgYW5kIGl0IHdpbGwgYmUgY2hhbmdlZCBldmVyeXdoZXJlLiANCg0KVGhvdWdoIHRoaXMgaXMgYSBzbWFsbCBleGFtcGxlIGFuZCB0aGlzIHZlcnNpb24gb2YgdGhlIGNvZGUgd291bGQgcmVhbGx5IGJlIHN1ZmZpY2llbnQsIEkgYW0gc3VyZSB5b3UgY2FuIHNlZSBob3cgdGhlc2UgaXNzdWVzIGNvdWxkIGJlY29tZSBhIG1hc3NpdmUgcHJvYmxlbSBpbiBhIGxvbmcgc2NyaXB0IHlvdSBoYXZlIGJlZW4gd29ya2luZyB0aXJlbGVzc2x5IG9uLiANCg0KIyMjIyBgYW5hbHlzaXMuUmANCg0KKEknbGwgc2F2ZSB0aGUgYmVsb3cgZmlsZSBhcyB0aGUgYWJvdmUgbmFtZSBzbyB5b3UgY2FuIHZpZXcgaXQgbGF0ZXIsIHRvbykuDQoNCmBgYHtyLCB3YXJuaW5nPUZBTFNFfQ0KIycgLS0tDQojJyB0aXRsZTogRW5naW5lIGRpc3BsYWNlbWVudCBpbiBjaXRpZXMgYW5kIG9uIGhpZ2h3YXlzLiANCiMnIHB1cnBvc2U6IFRoaXMgc2NyaXB0IGlzIGdvaW5nIHRvIGNvcnJlbGF0ZSB0aGUgZGlzcGwsIGN0eSwgYW5kIGh3eSBjb2x1bW5zIG9mIFIncyBidWlsdCBpbiBkYXRhc2V0IGNhbGxlZCBtcGcgZnJvbSB0aGUgZ2dwbG90MiBwYWNrYWdlIGFuZCBtYWtlIHNvbWUgcGxvdHMgb2YgdGhvc2UgY29ycmVsYXRpb25zLiANCiMnIGF1dGhvcjogWW91DQojJyBkYXRlOiBZWVlZLU1NLUREDQojJyAtLS0NCg0KIyBEaXJlY3RvcmllcyAtLS0tLS0tLS0NCg0KZGlyPC1nZXR3ZCgpICNUaGlzIGlzIHRoZSBjdXJyZW50IGRpcmVjdG9yeS4gVGhpcyBpcyBub3QgY3VycmVudGx5IG5lZWRlZCwgdGhvdWdodC4gDQoNCiMgTGlicmFyaWVzIC0tLS0tLS0tLQ0KDQpsaWJyYXJ5KGdncGxvdDIpICMgTWFrZXMgcHJldHR5IHBsb3RzDQpsaWJyYXJ5KGdncHVicikgIyBBcnJhbmdlcyBtdWx0aXBsZSBnZ3Bsb3RzIG9uIHRoZSBzYW1lIHBhZ2UNCg0KIyBJbXBvcnQgRGF0YSAtLS0tLQ0KDQojIERvd25sb2FkIGRhdGEgZGVzY3JpYmluZyBGdWVsIGVjb25vbXkgZGF0YSBmcm9tIDE5OTkgdG8gMjAwOCBmb3IgMzggcG9wdWxhciBtb2RlbHMgb2YgY2Fycy4gDQojIFRoaXMgZGF0YSBpcyBidWlsdCBpbnRvIHRoZSBnZ3Bsb3QyIGxpYnJhcnkuIFVzZSAiP21wZyIgdG8gbGVhcm4gbW9yZSBhYm91dCB0aGlzIGRhdGFzZXQuIA0KZGF0YShtcGcpDQojQ29sdW1ucyBvZiBpbnRlcmVzdCBpbmNsdWRlOiANCiMjICJkaXNwbCIgPSBlbmdpbmUgZGlzcGxhY2VtZW50LCBpbiBsaXRyZXMNCiMjICJjdHkiID0gY2l0eSBtaWxlcyBwZXIgZ2FsbG9uDQojIyAiaHd5IiA9IGhpZ2h3YXkgbWlsZXMgcGVyIGdhbGxvbg0KDQojIEZ1bmN0aW9ucyAtLS0tLS0tDQoNCmNyZWF0ZXBsb3Q8LWZ1bmN0aW9uKHgsIHkpIHsNCiAgI0NyZWF0ZXBsb3QgaXMgYSBmdW5jdGlvbiBmb3IgY2FsY3VsYXRpbmcgdGhlIFBlYXJzb24gY29ycmVsYXRpb24gY29lZmZpY2llbnQgYW5kIHBsb3R0aW5nIHR3byB2YXJpYWJsZXMgKHggYW5kIHkpIGFnYWluc3QgZWFjaCBvdGhlciANCiAgDQogICNGaW5kIHRoZSBQZWFyc29uIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50DQogIGNvcl88LWNvcih4LCB5KQ0KICANCiAgI0NyZWF0ZSBwbG90cyBkaXNwbGF5aW5nIGRhdGEgcG9pbnRzLCBhIHNtb290aCBsaW5lYXIgbW9kZWwgdHJlbmQgbGluZSAobm90ZSAnbWV0aG9kID0gbG0nKSwgYW5kIGEgdXNlZnVsIHRpdGxlLiANCiAgZzwtZ2dwbG90KG1wZywgYWVzKHgsIHkpKSArDQogICAgZ2VvbV9wb2ludCgpICsgIyBwbG90cyBwb2ludHMNCiAgICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iKSArICNwbG90cyB0cmVuZCBsaW5lIHVzaW5nIGEgbGluZWFyIG1vZGVsDQogICAgZ2d0aXRsZShwYXN0ZTAoIlBlYXJzb24gY29ycmVsYXRpb24gY29lZmZpY2llbnQgPSAiLCByb3VuZChjb3JfLCBkaWdpdHMgPSAyKSkpICsgIyBkaXNwbGF5cyB0aXRsZSB3aXRoIFBlYXJzb24gY29ycmVsYXRpb24gY29lZmZpY2llbnQNCiAgICB5bGltKDUsIDQ1KSAjIHN0YW5kYXJkaXplcyB0aGUgaGllZ2h0IG9mIHRoZSB5LWF4aXMNCiAgDQogICNyZXR1cm4gb3V0cHV0cyBvdXIgZ3JhcGggZnJvbSB0aGUgZnVuY3Rpb24uIA0KICByZXR1cm4oZykNCn0NCg0KIyBBbmFseXNpcyAtLS0tLQ0KDQojICoqKiBWaXN1YWxpemF0aW9ucyAtLS0tLS0NCg0KI1VzZSBjcmVhdGVwbG90IHRvIG91dHB1dCBvdXIgdHdvIGZpbmlzaGVkIHBsb3RzLiANCmcxPC1jcmVhdGVwbG90KHggPSBtcGckZGlzcGwsIHkgPSBtcGckaHd5KQ0KDQpnMjwtY3JlYXRlcGxvdCh4ID0gbXBnJGRpc3BsLCB5ID0gbXBnJGN0eSkNCg0KIyMgYXJyYW5nZSB0aGVzZSB0d28gcGxvdHMgc2lkZSBieSBzaWRlIHNvIHdlIGNhbiBjb21wYXJlIGRpZmZlcmVuY2VzIGJldHdlZW4gdGhlIHBsb3RzLiANCmc8LWdnYXJyYW5nZShwbG90bGlzdCA9IGxpc3QoZzEsIGcyKSwNCiAgICAgICAgICAgICAgIG5yb3c9MSwgbmNvbCA9IDIpDQoNCiMgKioqIFNhdmUgT3V0cHV0cyAtLS0tLQ0KDQojU2F2ZSB5b3VyIHBsb3Qgc28geW91IGNhbiB1c2UgYW5kIGZpbmQgaXQgbGF0ZXIuIA0KZ2dzYXZlKGZpbGVuYW1lID0gImdyYXBoLnBuZyIsIHBsb3QgPSBnKQ0KZw0KDQpgYGANCg0KIVsqT3V0cHV0IGZyb20gc2NyaXB0Kl0oLi9ncmFwaC5wbmcpDQoNCg0KIyMgNC4gTmFtZSBmaWxlcyB3aXRoIHByZWRpY3RhYmxlIGFuZCBoZWxwZnVsIG5hbWVzDQoNCiJncmFwaC5wbmciIGlzIG5vdCBhIHRlcnJpYmx5IGhlbHBmdWwgbmFtZSBmb3IgYW55IGZpbGUuIEdvb2QgaW4gYSBwaW5jaCwgbm90IGluIHRoZSBsb25nIHJ1bi4gVGhlcmUgYXJlIGEgZmV3IHF1ZXN0aW9ucyBpbW1lZGlhdGVseSBjb21lIHRvIG1pbmQ6IA0KDQogLSBXaGF0IGFuYWx5c2lzIGRvZXMgdGhpcyBwbG90IGJlbG9uZyB0bz8NCiAtIEF0IHdoYXQgcGFydCBvZiB0aGUgYW5hbHlzaXMgd2FzIHRoaXMgb3V0cHV0IGNyZWF0ZWQ/IGUuZy4sIG9yZGVyPw0KIC0gV2h5IGRvIEkgY2FyZSBhYm91dCB0aGlzIGFuYWx5c2lzPyBlLmcuLCBhIG1vcmUgZGVzY3JpcHRpdmUgbmFtZT8NCiAtIFdoYXQgcnVuIGlzIHRoaXMgYW5hbHlzaXMgZnJvbT8gZS5nLiwgZGF0ZT8gKHNvbWV0aGluZyB0byB0aGluayBhYm91dCBidXQgc2tpcHBpbmcgdGhpcyBmb3Igbm93LiBXZSdsbCBnZXQgdG8gaXQgbmV4dC4pDQogDQpJIHVzdWFsbHkgdHJ5IHRvIGtlZXAgYWxsIG9mIG15IGZpbGVzIHRvIHNpbWlsYXIgbmFtaW5nIHN0cnVjdHVyZSBsaWtlIHRoaXMgb25lLiANCg0KYFtPcmRlcl0tW0FuYWx5c2lzTmFtZV0tW0Rlc2NyaXB0aW9uXS5bZmlsZXR5cGVdYA0KDQpBIGZldyBydWxlczogDQoNCiAtIE5vIHNwYWNlcy4gWW91IGNhbiB1c2UgVGhpc0xldHRlckNhc2luZyBvciB0aGlzTGV0dGVyQ2FzaW5nIHRvIHNlcGFyYXRlIHdvcmRzLg0KIC0gVXNlIHVuZGVyc2NvcmVzIChfKSBvciBkYXNoZXMgKC0pIHRvIHNlcGFyYXRlIGlkZWFzIHNvIGl0IGNhbiBiZSBlYXN5IHRvIHJlYWQuIFB5dGhvbiBoYXMgaXNzdWVzIHdpdGggdW5kZXJzY29yZXMgKF8pLCBzbyB5b3UgbWF5IHdhbnQgdG8gdXNlIGRhc2hlcyAoLSkuIA0KIC0gTmFtZXMgc2hvdWxkIGJlIGtlcHQgYXMgc2hvcnQgYXMgcG9zc2libGUuIFNvbWUgYXBwbGljYXRpb25zIChpbmNsdWRpbmcgUiwgdGhvdWdoIGl0IHZhcmllcyBieSBhY3Rpb24gYW5kIGZpbGUgdHlwZSkgaGF2ZSBhIGxldHRlciBjb3VudCBsaW1pdCBvbiBmaWxlIG5hbWVzLg0KDQpXaXRoIHRoaXMgaW4gbWluZCwgSSBtaWdodCBjaGFuZ2UgdGhlIGZpbGUgbmFtZSBgZ3JhcGgucG5nYCBpbiBgZ2dzYXZlKGZpbGVuYW1lID0gImdyYXBoLnBuZyIsIHBsb3QgPSBnKWAgdG8gYDFfVGVzdEFuYWx5c2lzX0dyYXBoLnBuZ2AgYnkgdXNpbmcgdGhlIGJlbG93IGNvZGU6DQoNCmBgYHtyfQ0KY291bnRlcjwtMA0KY291bnRlcjwtY291bnRlciArIDENCmZpbGVuYW1lID0gcGFzdGUwKGNvdW50ZXIsICJfVGVzdEFuYWx5c2lzX0dyYXBoLnBuZyIpDQpnZ3NhdmUoZmlsZW5hbWUgPSBmaWxlbmFtZSwgcGxvdCA9IGcpDQpgYGANCg0KVGhlIGNvdW50ZXIgaXMgbm90IHJlYWxseSBuZWNlc3NhcnksIGJ1dCBpcyB1c2VmdWwgaWYgSSB3YW50IHRvIGtlZXAgdGhlIG9yZGVyIG9mIHRoZXNlIGZpbGVzIGluIG15IGZpbGUgZm9sZGVyLiBJZiB5b3UgaGF2ZSB0byBtYWtlIG1hbnkgb2YgdGhlc2UgKG9yIGFueSBvdGhlcikgcGxvdHMgYnV0IGRvbid0IHdhbnQgdG8gaGF2ZSB0byBzZWFyY2ggZm9yIHRoZW0gaW4gYSBzZWEgb2YgZmlsZXMsIG51bWJlcmluZyBjYW4gaGVscCBtYWtlIHRoZWlyIGxvY2F0aW9uIGluIHRoZSBmb2xkZXIgcHJlZGljdGFibGUuIA0KDQojIyA1LiBQcmVkaWN0YWJsZSBmb2xkZXIgc3RydWN0dXJlDQoNCkxldCdzIHNheSB0aGF0IHlvdSBhcmUgd29ya2luZyBvbiB0aGlzIGFuYWx5c2lzIG92ZXIgdGhlIGNvdXJzZSBvZiBzZXZlcmFsIG1vbnRocyBhbmQgeW91IGRvbid0IHdhbnQgdG8gb3ZlcndyaXRlIHlvdXIgb3V0cHV0cyBlYWNoIHRpbWUgeW91IHJ1biB5b3VyIHNjcmlwdCBvciBnZXQgbG9zdCBpbiBhIHNlYSBvZiBmaWxlcy4gSXQncyBhIGxpdHRsZSBjb21wbGljYXRlZCB0byBzZXQgdXAsIGJ1dCBJIHN1Z2dlc3QgdGhlIGZvbGxvd2luZzogDQoNCiMjIyAqKjUuMS4gU2V0IHVwIHRocmVlIG5ldyBmb2xkZXJzKioNCg0KSW4gYSBnaXZlbiBwcm9qZWN0LCBJIGtlZXAgYWxsIG9mIG15IGZpbGVzIChnZW5lcmFsbHkpIGluIHRocmVlIGZvbGRlcnMuIE5vdGUgdGhhdCBgIi4vImAgaXMgUiBzaG9ydGhhbmQgZm9yICJjdXJyZW50IGRpcmVjdG9yeSwiIHdoaWNoIHdvdWxkIGJlIHRoZSBkaXJlY3Rvcnkgb2YgeW91ciBSIFByb2plY3QuDQoNCiAtICoqYHJzY3JpcHRzYCoqOiB3aGVyZSB5b3Ugd2lsbCBzYXZlIGFsbCBvZiB5b3VyIHJzY3JpcHRzLCBpbmNsdWRpbmcgdGhpcyBzY3JpcHQgd2UgaGF2ZSBiZWVuIHdvcmtpbmcgb24uIA0KIC0gKipgZGF0YWAqKjogd2hlcmUgeW91IHdpbGwgc3RvcmUgYWxsIG9mIHlvdXIgbG9jYWwgZGF0YSB0aGF0IGdvZXMgaW50byBhIHNjcmlwdCAodGhvdWdoIG5vdCByZWFsbHkgcmVsZXZhbnQgaGVyZSBzaW5jZSB3ZSBhcmUgdXNpbmcgc29tZSBvZiBSJ3MgaW4taG91c2UgZGF0YSkuDQogLSAqKmBvdXRwdXRgKio6IHdoZXJlIHJlc3VsdHMgZnJvbSB5b3VyIGFuYWx5c2lzIHdpbGwgZ28uIA0KDQpgYGB7ciwgd2FybmluZz1GQUxTRX0NCmRpci5jcmVhdGUocGF0aCA9ICIuL3JzY3JpcHRzIikNCmRpci5jcmVhdGUocGF0aCA9ICIuL2RhdGEiKQ0KZGlyLmNyZWF0ZShwYXRoID0gIi4vb3V0cHV0IikNCmBgYA0KDQohWypUaGUgcm9vdCBmb2xkZXIncyBzdHVjdHVyZS4qXSguL0ZpbGVTdHJ1Y3R1cmUxLkpQRykNCg0KDQojIyMgKio1LjIuIENyZWF0ZSBhIGZvbGRlciBmb3IgdGhhdCBhbmFseXNpcyBydW4gd2l0aGluIHRoZSBvdXRwdXQgZm9sZGVyKioNCg0KRm9yIGVhY2ggZGF5J3MgcnVuIG9mIHlvdXIgYW5hbHlzaXMsIHlvdSBtaWdodCBsaWtlIHRvIHNldCB1cCBhIG5ldyBmaWxlIHRvIHNhdmUgZXZlcnl0aGluZyBpbi4gV2l0aGluIHRoYXQgZm9sZGVyLCB5b3UgbWlnaHQgYWxzbyBsaWtlIHRvIGtlZXAgYSBjb3B5IG9mIHdoYXQgeW91IHVzZWQgdG8gY3JlYXRlIHRoaXMgZmlsZS4gSSByZWNvbW1lbmQgYXV0b21hdGljYWxseSBjcmVhdGluZyBmb2xkZXJzIHdpdGhpbiB0aGlzIG5ldyBvdXRwdXQgZm9sZGVyIGZvciB5b3VyIHJzY3JpcHRzLCByYXdkYXRhLCBmaWd1cmVzLCBldGMuIFRoaXMgbWlnaHQgc2VlbSBwcmVkaWNhYmxlLCBidXQgd2l0aCB0aGU6IA0KDQogLSAqKmBmaWd1cmVzYCoqIGZvbGRlciwgd2Ugc2F2ZSBhbGwgb2Ygb3VyIG91dHB1dCBmaWd1cmVzIGZyb20gdGhlIGFuYWx5c2lzLiANCiAtICoqYHJzY3JpcHRzYCoqIGZvbGRlciwgd2Ugc2F2ZSBhbGwgb2YgdGhlIHJzY3JpcHRzIHdlIHVzZWQgdG8gY3JlYXRlIHRoaXMgYW5hbHlzaXMgd2l0aC4gSSBrbm93IG1hbnkgb2YgeW91IG11c3QgYmUgdGhpbmtpbmcgdGhhdCB0aGlzIGlzIHJlZHVuZGFudCBpbiBhIHdvcmxkIHdpdGggR2l0SHViLCBidXQgaXQgZ2l2ZXMgbWUgc29tZSBwZWFjZSBvZiBtaW5kIHRvIGhhdmUgYWxsIG9mIHRoZXNlIHRoaW5ncyB0b2dldGhlci4gSGVyZSBJIHVzZSBhIHNpbXBsZSBsb29wIHRvIGZpbmQgYWxsIG9mIHRoZSBmaWxlcyBpbiBteSBgLi9yc2NyaXB0cy9gIGZpbGUgaW4gdGhlIHJvb3QgZGlyZWN0b3J5IGFuZCBjb3B5IHRoZW0gdG8gdGhlIG91dHB1dCdzIGAuL291dHB1dC9bZm9sZGVyIGZvciB0aGF0IGRheSdzIGNvZGUgcnVuXS9yc2NyaXB0cy9gIGZvbGRlci4gDQogLSAqKmByYXdkYXRhYCoqIGZvbGRlciwgd2Ugc3RvcmUgYWxsIG9mIHRoZSByYXcgZGF0YSB3ZSB1c2VkIHRvIGNyZWF0ZSB0aGlzIGFuYWx5c2lzLiANCg0KIVsqVGhlIG91dHB1dCBmb2xkZXIncyBzdHVjdHVyZS4qXSguL0ZpbGVTdHJ1Y3R1cmUzLkpQRykNCg0KVGhlcmUgaXMgbm90aGluZyBzdG9wcGluZyB5b3UgZnJvbSBoYXZpbmcgb3RoZXIgZm9sZGVycyBoZXJlIHdpdGggZGlmZmVyZW50IG91dHB1dHMsIGxpa2UgYHRhYmxlc2Agb3IgYHdvcmRkb2N1bWVudHNgLiBKdXN0IGtlZXAgdGhlIG5hbWVzIGhlbHBmdWwgYW5kIHByZWRpY3RhYmxlLiANCg0KYGBge3IsIHdhcm5pbmc9RkFMU0V9DQoNCiMgRGlyZWN0b3JpZXMgLS0tLS0tLQ0KDQpvdXRwdXRmb2xkZXI8LXBhc3RlMCgiLi9vdXRwdXQvVGVzdEFuYWx5c2lzXyIsIFN5cy5EYXRlKCksICIvIikgIyBEZWZpbmUgdGhlIG5hbWUgb2YgdGhlIG5ldyBvdXRwdXQgZm9sZGVyLiBTeXMuRGF0ZSgpIHdpbGwgYWRkIHRvZGF5J3MgbmFtZSB0byB0aGUgZmlsZSBmb2xkZXIncyBuYW1lLiANCmRpci5jcmVhdGUocGF0aCA9IG91dHB1dGZvbGRlcikgIyBDcmVhdGUgZm9sZGVyIGZvciB0b2RheSdzIGFuYWx5c2lzIHJ1bg0KDQpkaXIuY3JlYXRlKHBhdGggPSBwYXN0ZTAob3V0cHV0Zm9sZGVyLCAicmF3ZGF0YSIpKQ0KZGlyLmNyZWF0ZShwYXRoID0gcGFzdGUwKG91dHB1dGZvbGRlciwgImZpZ3VyZXMiKSkNCmRpci5jcmVhdGUocGF0aCA9IHBhc3RlMChvdXRwdXRmb2xkZXIsICJyc2NyaXB0cyIpKQ0KDQpsaXN0ZmlsZXM8LWxpc3QuZmlsZXMocGF0aCA9ICIuL3JzY3JpcHRzLyIpICNGaW5kIGFsbCBmaWxlcyBpbiAiLi9yc2NyaXB0cyINCmZvciAoaSBpbiAxOmxlbmd0aChsaXN0ZmlsZXMpKXsgIyBTYXZlIGFsbCBvZiB0aG9zZSBmaWxlcyB0byB0aGUgcnNjcmlwdHMgZm9sZGVyIGluIHRoZSBvdXRwdXQgZm9sZGVyDQogIGZpbGUuY29weShmcm9tID0gcGFzdGUwKCIuL3JzY3JpcHRzLyIsIGxpc3RmaWxlc1tpXSksIA0KICAgICAgICAgICAgdG8gPSBwYXN0ZTAoIi4vIixvdXRwdXRmb2xkZXIsIi9yc2NyaXB0cy8iLCBsaXN0ZmlsZXNbaV0pLCANCiAgICAgICAgICAgIG92ZXJ3cml0ZSA9IFQpDQp9DQoNCmBgYA0KDQojIyA2LiBTY3JpcHRzIHdpdGggc3BlY2lmaWMgdGFza3MNCg0KSW4gYSB3b3JsZCB3aGVyZSB5b3VyIGFuYWx5c2VzIGFyZSBhIGJpdCBtb3JlIGNvbXBsaWNhdGVkLCBJIGZpbmQgdGhhdCBpdCBpcyBnb29kIHRvIHNwbGl0IHlvdXIgY29kZSBpbnRvIHRoZSBmb2xsb3dpbmcgZmlsZXM6IA0KDQogLSAqKmBmdW5jdGlvbnMuUmAqKiwgdGhpcyBmaWxlIHdpbGwgYmUgd2hlcmUgYWxsIG9mIHRoZSBmdW5jaXRvbnMgdXNlZCB0byBydW4geW91ciBhbmFseXNpcy4gDQogLSAqKmBkYXRhLlJgKiosIHRoaXMgZmlsZSB3aWxsIGxvYWQgYWxsIG9mIHlvdXIgZGF0YSBhbmQgZWRpdCBpdCBmb3IgeW91ciBhbmFseXNpcy4gTmV2ZXIgaGFuZCBlZGl0IGRhdGEgZnJvbSBhIHNvdXJjZS4gSWYgeW91IGNhbiwgYWx3YXlzIG1hbmlwdWxhdGUgaXQgc28geW91IG5ldmVyIGRlc3Ryb3kgeW91ciBvcmlnaW5hbCBkYXRhIGNvcHkuIA0KIC0gKipgcnVuLlJgKiosIHRoaXMgZmlsZSB3aWxsIHNvdXJjZSB0aGUgb3RoZXIgZmlsZXMgeW91IGNyZWF0ZWQgYW5kIHJ1biB0aGUgYW5hbHlzaXMuIFdlIHdhbnQgdGhpcyB0byBoYXZlIHRoZSBiYXJlLWJvbmVzIG9mIHdoYXQgd2UgbmVlZCBmb3Igb3VyIGFuYWx5c2lzLiANCg0KIVsqVGhlIG91dHB1dCByc2NyaXB0cydzIHN0dWN0dXJlLipdKC4vRmlsZVN0cnVjdHVyZTIuSlBHKQ0KDQpTdWNoIHRoYXQgeW91ciBuZXcgZmlsZXMgd291bGQgbG9vayBsaWtlIHRoaXMgYW5kIHdvdWxkIGFsbCBiZSBzYXZlZCBpbiB0aGUgInJzY3JpcHRzIiBmb2xkZXI6IA0KDQojIyMjIGBmdW5jdGlvbnMuUmANCg0KYGBge3IsIHdhcm5pbmc9RkFMU0V9DQojJyB0aXRsZTogRW5naW5lIGRpc3BsYWNlbWVudCBpbiBjaXRpZXMgYW5kIG9uIGhpZ2h3YXlzLiANCiMnIHB1cnBvc2U6IFRoaXMgc2NyaXB0IGlzIGdvaW5nIHRvIGNvcnJlbGF0ZSB0aGUgZGlzcGwsIGN0eSwgYW5kIGh3eSBjb2x1bW5zIG9mIFIncyBidWlsdCBpbiBkYXRhc2V0IGNhbGxlZCBtcGcgZnJvbSB0aGUgZ2dwbG90MiBwYWNrYWdlIGFuZCBtYWtlIHNvbWUgcGxvdHMgb2YgdGhvc2UgY29ycmVsYXRpb25zLiANCiMnIGF1dGhvcjogWW91DQojJyBkYXRlOiBZWVlZLU1NLUREDQojJyAtLS0NCg0Kcm0obGlzdD1scygpKQ0KDQojIExpYnJhcmllcyAtLS0tLS0tDQpQS0cgPC0gYygiZ2dwbG90MiIsICJnZ3B1YnIiKQ0KZm9yIChwIGluIFBLRykgew0KICBpZighcmVxdWlyZShwLGNoYXJhY3Rlci5vbmx5ID0gVFJVRSkpIHsgIA0KICAgIGluc3RhbGwucGFja2FnZXMocCkNCiAgICByZXF1aXJlKHAsY2hhcmFjdGVyLm9ubHkgPSBUUlVFKX0NCn0NCg0KDQojIERpcmVjdG9yaWVzIC0tLS0tLS0NCg0Kb3V0cHV0Zm9sZGVyPC1wYXN0ZTAoIi4vb3V0cHV0L1Rlc3RBbmFseXNpc18iLCBTeXMuRGF0ZSgpLCAiLyIpICMgRGVmaW5lIHRoZSBuYW1lIG9mIHRoZSBuZXcgb3V0cHV0IGZvbGRlci4gU3lzLkRhdGUoKSB3aWxsIGFkZCB0b2RheSdzIG5hbWUgdG8gdGhlIGZpbGUgZm9sZGVyJ3MgbmFtZS4gDQpkaXIuY3JlYXRlKHBhdGggPSBvdXRwdXRmb2xkZXIpICMgQ3JlYXRlIGZvbGRlciBmb3IgdG9kYXkncyBhbmFseXNpcyBydW4NCg0KZGlyLmNyZWF0ZShwYXRoID0gcGFzdGUwKG91dHB1dGZvbGRlciwgInJhd2RhdGEiKSkNCmRpci5jcmVhdGUocGF0aCA9IHBhc3RlMChvdXRwdXRmb2xkZXIsICJmaWd1cmVzIikpDQpkaXIuY3JlYXRlKHBhdGggPSBwYXN0ZTAob3V0cHV0Zm9sZGVyLCAicnNjcmlwdHMiKSkNCmxpc3RmaWxlczwtbGlzdC5maWxlcyhwYXRoID0gIi4vcnNjcmlwdHMvIikgI0ZpbmQgYWxsIGZpbGVzIGluICIuL3JzY3JpcHRzIg0KZm9yIChpIGluIDE6bGVuZ3RoKGxpc3RmaWxlcykpeyAjIFNhdmUgYWxsIG9mIHRob3NlIGZpbGVzIHRvIHRoZSByc2NyaXB0cyBmb2xkZXIgaW4gdGhlIG91dHB1dCBmb2xkZXINCiAgZmlsZS5jb3B5KGZyb20gPSBwYXN0ZTAoIi4vcnNjcmlwdHMvIiwgbGlzdGZpbGVzW2ldKSwgDQogICAgICAgICAgICB0byA9IHBhc3RlMCgiLi8iLG91dHB1dGZvbGRlciwiL3JzY3JpcHRzLyIsIGxpc3RmaWxlc1tpXSksIA0KICAgICAgICAgICAgb3ZlcndyaXRlID0gVCkNCn0NCg0KIyBGdW5jdGlvbnMgLS0tLS0tLQ0KDQpjcmVhdGVwbG90PC1mdW5jdGlvbih4LCB5KSB7DQogICNDcmVhdGVwbG90IGlzIGEgZnVuY3Rpb24gZm9yIGNhbGN1bGF0aW5nIHRoZSBQZWFyc29uIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50IGFuZCBwbG90dGluZyB0d28gdmFyaWFibGVzICh4IGFuZCB5KSBhZ2FpbnN0IGVhY2ggb3RoZXIgDQogIA0KICAjRmluZCB0aGUgUGVhcnNvbiBjb3JyZWxhdGlvbiBjb2VmZmljaWVudA0KICBjb3JfPC1jb3IoeCwgeSkNCiAgDQogICNDcmVhdGUgcGxvdHMgZGlzcGxheWluZyBkYXRhIHBvaW50cywgYSBzbW9vdGggbGluZWFyIG1vZGVsIHRyZW5kIGxpbmUgKG5vdGUgJ21ldGhvZCA9IGxtJyksIGFuZCBhIHVzZWZ1bCB0aXRsZS4gDQogIGc8LWdncGxvdChtcGcsIGFlcyh4LCB5KSkgKw0KICAgIGdlb21fcG9pbnQoKSArICMgcGxvdHMgcG9pbnRzDQogICAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIikgKyAjcGxvdHMgdHJlbmQgbGluZSB1c2luZyBhIGxpbmVhciBtb2RlbA0KICAgIGdndGl0bGUocGFzdGUwKCJQZWFyc29uIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50ID0gIiwgcm91bmQoY29yXywgZGlnaXRzID0gMikpKSArICMgZGlzcGxheXMgdGl0bGUgd2l0aCBQZWFyc29uIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50DQogICAgeWxpbSg1LCA0NSkgIyBzdGFuZGFyZGl6ZXMgdGhlIGhpZWdodCBvZiB0aGUgeS1heGlzDQogIA0KICAjcmV0dXJuIG91dHB1dHMgb3VyIGdyYXBoIGZyb20gdGhlIGZ1bmN0aW9uLiANCiAgcmV0dXJuKGcpDQp9DQoNCg0KYGBgDQoNCiMjIyMgYGRhdGEuUmANCg0KYGBge3J9DQojJyB0aXRsZTogRW5naW5lIGRpc3BsYWNlbWVudCBpbiBjaXRpZXMgYW5kIG9uIGhpZ2h3YXlzLiANCiMnIHB1cnBvc2U6IFRoaXMgc2NyaXB0IGlzIGdvaW5nIHRvIGNvcnJlbGF0ZSB0aGUgZGlzcGwsIGN0eSwgYW5kIGh3eSBjb2x1bW5zIG9mIFIncyBidWlsdCBpbiBkYXRhc2V0IGNhbGxlZCBtcGcgZnJvbSB0aGUgZ2dwbG90MiBwYWNrYWdlIGFuZCBtYWtlIHNvbWUgcGxvdHMgb2YgdGhvc2UgY29ycmVsYXRpb25zLiANCiMnIGF1dGhvcjogWW91DQojJyBkYXRlOiBZWVlZLU1NLUREDQojJyAtLS0NCg0KIyBMaWJyYXJpZXMgLS0tLS0tLS0tDQoNCmxpYnJhcnkoZ2dwbG90MikgIyBNYWtlcyBwcmV0dHkgcGxvdHMNCg0KIyBJbXBvcnQgRGF0YSAtLS0tLQ0KDQojIERvd25sb2FkIGRhdGEgZGVzY3JpYmluZyBGdWVsIGVjb25vbXkgZGF0YSBmcm9tIDE5OTkgdG8gMjAwOCBmb3IgMzggcG9wdWxhciBtb2RlbHMgb2YgY2Fycy4gDQojIFRoaXMgZGF0YSBpcyBidWlsdCBpbnRvIHRoZSBnZ3Bsb3QyIGxpYnJhcnkuIFVzZSAiP21wZyIgdG8gbGVhcm4gbW9yZSBhYm91dCB0aGlzIGRhdGFzZXQuIA0KDQpkYXRhKG1wZykNCg0KI1NhdmUgdGhlIHJhd2RhdGEgeW91IHVzZWQgZm9yIGFuIGFuYWx5c2lzIChpZiB5b3Ugd2FudCB0bykNCg0Kd3JpdGUuY3N2KHggPSBkYXRhLmZyYW1lKG1wZyksIGZpbGUgPSBwYXN0ZTAob3V0cHV0Zm9sZGVyLCAicmF3ZGF0YS9tcGcuY3N2IikpDQoNCiNDb2x1bW5zIG9mIGludGVyZXN0IGluY2x1ZGU6IA0KIyMgImRpc3BsIiA9IGVuZ2luZSBkaXNwbGFjZW1lbnQsIGluIGxpdHJlcw0KIyMgImN0eSIgPSBjaXR5IG1pbGVzIHBlciBnYWxsb24NCiMjICJod3kiID0gaGlnaHdheSBtaWxlcyBwZXIgZ2FsbG9uDQoNCmBgYA0KDQojIyMjIGBydW4uUmANCg0KYGBge3IsIHdhcm5pbmc9RkFMU0V9DQojJyB0aXRsZTogRW5naW5lIGRpc3BsYWNlbWVudCBpbiBjaXRpZXMgYW5kIG9uIGhpZ2h3YXlzLiANCiMnIHB1cnBvc2U6IFRoaXMgc2NyaXB0IGlzIGdvaW5nIHRvIGNvcnJlbGF0ZSB0aGUgZGlzcGwsIGN0eSwgYW5kIGh3eSBjb2x1bW5zIG9mIFIncyBidWlsdCBpbiBkYXRhc2V0IGNhbGxlZCBtcGcgZnJvbSB0aGUgZ2dwbG90MiBwYWNrYWdlIGFuZCBtYWtlIHNvbWUgcGxvdHMgb2YgdGhvc2UgY29ycmVsYXRpb25zLiANCiMnIGF1dGhvcjogWW91DQojJyBkYXRlOiBZWVlZLU1NLUREDQojJyAtLS0NCg0KZ2MoKSAjIGdhcmJhZ2UgY29sbGVjdGlvbjsgcmVtb3ZlIHVudXNlZCB2YXJpYWJsZXMNCg0KIyBTb3VyY2UgU2NyaXB0cyAtLS0tLS0tDQoNCnNvdXJjZSgiLi9yc2NyaXB0cy9mdW5jdGlvbnMuUiIpDQpzb3VyY2UoIi4vcnNjcmlwdHMvZGF0YS5SIikNCg0KIyBBbmFseXNpcyAtLS0tLQ0KDQojVXNlIGNyZWF0ZXBsb3QgdG8gb3V0cHV0IG91ciB0d28gZmluaXNoZWQgcGxvdHMuIA0KZzE8LWNyZWF0ZXBsb3QoeCA9IG1wZyRkaXNwbCwgeSA9IG1wZyRod3kpDQoNCmcyPC1jcmVhdGVwbG90KHggPSBtcGckZGlzcGwsIHkgPSBtcGckY3R5KQ0KDQojIyBhcnJhbmdlIHRoZXNlIHR3byBwbG90cyBzaWRlIGJ5IHNpZGUgc28gd2UgY2FuIGNvbXBhcmUgZGlmZmVyZW5jZXMgYmV0d2VlbiB0aGUgcGxvdHMuIA0KZzwtZ2dhcnJhbmdlKHBsb3RsaXN0ID0gbGlzdChnMSwgZzIpLA0KICAgICAgICAgICAgICAgbnJvdz0xLCBuY29sID0gMikNCg0KIyAqKiogU2F2ZSBPdXRwdXRzIC0tLS0tDQoNCiNTYXZlIHlvdXIgcGxvdCBzbyB5b3UgY2FuIHVzZSBhbmQgZmluZCBpdCBsYXRlci4gDQpjb3VudGVyPC0wDQpjb3VudGVyPC1jb3VudGVyICsgMQ0KZmlsZW5hbWUgPSBwYXN0ZTAoY291bnRlciwgIl9UZXN0QW5hbHlzaXNfR3JhcGgucG5nIikNCmdnc2F2ZShmaWxlbmFtZSA9IHBhc3RlMChvdXRwdXRmb2xkZXIsICJmaWd1cmVzLyIsIGZpbGVuYW1lKSwgcGxvdCA9IGcpDQpnDQoNCmBgYA0KDQohWypPdXRwdXQgZnJvbSBzY3JpcHQqXSguLi8xX1Rlc3RBbmFseXNpc19HcmFwaC5wbmcpDQoNClNlZSBob3cgYm90aCB0aGUgYGZ1bmN0aW9uc2AgYW5kIGBkYXRhYCBmb2xkZXJzIGFyZSAnc291cmNlZCcgaW50byB0aGUgYHJ1bmAgc2NyaXB0PyBJdCBtYWtlcyB0aGUgc2NyaXB0IGxvb2sgc28gbXVjaCBjbGVhbmVyIGFuZCBlYXNpZXIgdG8gcmVhZC4gDQoNCg0KIyMgNy4gU2F2ZSBzY3JpcHRzIGluIGFuICJSIFByb2plY3QiDQoNCllvdSBjYW4gZmluZCBtb3JlIGluZm9ybWF0aW9uIGFib3V0IHByb2plY3RzIGhlcmU6IGh0dHBzOi8vc3VwcG9ydC5yc3R1ZGlvLmNvbS9oYy9lbi11cy9hcnRpY2xlcy8yMDA1MjYyMDctVXNpbmctUHJvamVjdHMNCg0KUiBwcm9qZWN0cyBhcmUgaW1wb3J0YW50IGZvcjogDQoNCiAtIG9yZ2FuaXppbmcgeW91ciBhbmFseXNpcyBmcm9tIHRoZSBudXRzIGFuZCBib2x0cyAoZnVuY3Rpb25zIGFuZCBwYWNrYWdlcykgdG8gYW5hbHlzaXMgb3V0cHV0IChyIHNjcmlwdHMpLiANCiAtIHNoYXJpbmcgeW91ciBwcm9qZWN0cyB0byBHaXQgSHViDQogLSBzbyB5b3UgY2FuIGVzdGFibGlzaCBhICdyZWxhdGl2ZScgZGlyZWN0b3J5IChhcyBvcHBvc2VkIHRvIGEgbG9jYWwgZGlyZWN0b3J5IHRoYXQgcmVxdWlyZXMgYSBzcGVjaWZpYyBhZGRyZXNzIGluIHlvdXIgY29tcHV0ZXIpDQogLSBjcmVhdGluZyBSIFNoaW55IGFwcHMsIHBhY2thZ2VzLCBldGMuIChiZXlvbmQgdGhlIHNjb3BlIG9mIHRoaXMgZXhhbXBsZSkNCiANClRvIGNyZWF0ZSBhIHByb2plY3QgZm9yIHRoaXMgd29yaywgY2xpY2sgYEZpbGVgPmBOZXcgUHJvamVjdGA+YEV4aXN0aW5nIERpcmVjdG9yeWANCg0KIVsqRmlsZT5OZXcgUHJvamVjdD5FeGlzdGluZyBEaXJlY3RvcnkqXSguL05ld1Byb2plY3QuanBnKQ0KDQohWypGaWxlPk5ldyBQcm9qZWN0PkV4aXN0aW5nIERpcmVjdG9yeSpdKC4vTmV3UHJvamVjdDIuSlBHKQ0KDQpXZSBzZWxlY3RlZCAiRXhpc3RpbmcgRGlyZWN0b3J5IiBzaW5jZSB3ZSBhbHJlYWR5IGhhdmUgb25lLiBJdCBpcyBrbm93biBhcyBvdXIgcGFyZW50IGRpcmVjdG9yeSBhbmQgd2hhdCBJIGhhdmUgYmVlbiByZWZlcnJpbmcgdG8gYXMgYC4vYCBpbiB0aGUgZGlyZWN0b3J5IG5hbWUuIA0KDQpQcm9qZWN0cyBtYW5pZmVzdCB0aGVtc2VsdmVzLCBtb3JlIG9yIGxlc3MsIGFzIGZhbmN5IGZvbGRlcnMgd2hlcmUgUiBoYXMgYXV0b21hdGljYWxseSBkZXBvc2l0ZWQgdGhlIGZvbGxvd2luZyBmaWxlczogDQoNCiAtIENyZWF0ZXMgYSBwcm9qZWN0IGZpbGUgKHdpdGggYW4gLlJwcm9qIGV4dGVuc2lvbikgd2l0aGluIHRoZSBwcm9qZWN0IGRpcmVjdG9yeS4gVGhpcyBmaWxlIGNvbnRhaW5zIHZhcmlvdXMgcHJvamVjdCBvcHRpb25zIChkaXNjdXNzZWQgYmVsb3cpIGFuZCBjYW4gYWxzbyBiZSB1c2VkIGFzIGEgc2hvcnRjdXQgZm9yIG9wZW5pbmcgdGhlIHByb2plY3QgZGlyZWN0bHkgZnJvbSB0aGUgZmlsZXN5c3RlbS4NCiAtIENyZWF0ZXMgYSBoaWRkZW4gZGlyZWN0b3J5IChuYW1lZCAuUnByb2oudXNlcikgd2hlcmUgcHJvamVjdC1zcGVjaWZpYyB0ZW1wb3JhcnkgZmlsZXMgKGUuZy4gYXV0by1zYXZlZCBzb3VyY2UgZG9jdW1lbnRzLCB3aW5kb3ctc3RhdGUsIGV0Yy4pIGFyZSBzdG9yZWQuIFRoaXMgZGlyZWN0b3J5IGlzIGFsc28gYXV0b21hdGljYWxseSBhZGRlZCB0byAuUmJ1aWxkaWdub3JlLCAuZ2l0aWdub3JlLCBldGMuIGlmIHJlcXVpcmVkLg0KDQpOb3csIHRoZSBwcm9qZWN0IGlzIGxvYWRlZCBpbnRvIFJTdHVkaW8gYW5kIHRoZSBuYW1lIGlzIGRpc3BsYXllZCBpbiB0aGUgUHJvamVjdHMgdG9vbGJhciAod2hpY2ggaXMgbG9jYXRlZCBvbiB0aGUgZmFyIHJpZ2h0IHNpZGUgb2YgdGhlIG1haW4gdG9vbGJhcikuIEFkZGl0aW9uYWxseSwgdGhlIHByb2plY3QgKGFuZCBhbGwgcHJvZ3Jlc3Mgb24gdGhlIGZpbGVzKSB3aWxsIGJlIGVhc2lseSBsb2FkYWJsZSBmcm9tIGBGaWxlYD5gUmVjZW50IFByb2plY3RzYCBvciBgRmlsZWA+YE9wZW4gUHJvamVjdGAuIA0KDQpJZiB5b3Ugd2FudCBhY2Nlc3MgdG8gdGhpcyBSIFByb2plY3QgZnJvbSBteSBHaXRIdWIsIGZvciBleGFtcGxlLCB5b3UgY2FuIGFjY2VzcyBpdCBieSBnb2luZyB0byB0aGUgR2l0SHViIGxpbmsgYmVsb3cgYW5kIGRvd25sb2FkaW5nIGl0LCBvciB3aXRoIHRoZSBiZWxvdyBjb2RlLiANCg0KYGBge3IsIGV2YWw9RkFMU0V9DQppbnN0YWxsLnBhY2thZ2VzKCJ1c2V0aGlzIikNCmxpYnJhcnkodXNldGhpcykgIyBBdXRvbWF0ZSBwYWNrYWdlIGFuZCBwcm9qZWN0IHNldHVwIHRhc2tzIHRoYXQgYXJlIG90aGVyd2lzZSBwZXJmb3JtZWQgbWFudWFsbHkuDQp1c2V0aGlzOjp1c2VfY291cnNlKHVybCA9ICdodHRwczovL2dpdGh1Yi5jb20vZW1pbHlobWFya293aXR6L0Jlc3RTY3JpcHRpbmdQcmFjdGljZXMvYXJjaGl2ZS9tYXN0ZXIuemlwJywgDQogICAgICAgICAgICAgICAgICAgIGRlc3RkaXIgPSAieW91ci9sb2NhbC9kaXJlY3RvcnkvIikNCmBgYA0KDQoNCiMjIDguIE90aGVyIHBhY2thZ2VzIHRvIGNvbnNpZGVyIHVzaW5nIQ0KDQpCZWxvdyBhcmUgc29tZSBvdGhlciBwYWNrYWdlcyB0aGF0IGFyZSB3b3J0aCBhIGNsb3NlciBsb29rIGFzIHlvdSBwbGF5IGFyb3VuZCB3aXRoIG1ha2luZyBiZWF1dGlmdWxseSB3cml0dGVuIGFuZCBvcmdhbml6ZWQgY29kZSEgDQoNCmBgYHtyLCBlY2hvPUZBTFNFLCBldmFsPVRSVUUsIGluY2x1ZGU9VFJVRX0NCmxpYnJhcnkoaGVyZSkNCmxpYnJhcnkocGFja3JhdCkNCmxpYnJhcnkoZm9yZWFjaCkNCmBgYA0KDQojIyMgYHIgcGFja2FnZURlc2NyaXB0aW9uKCJoZXJlIikkUGFja2FnZWANCg0KYHIgcGFja2FnZURlc2NyaXB0aW9uKCJoZXJlIikkVGl0bGVgDQoNCmByIHBhY2thZ2VEZXNjcmlwdGlvbigiaGVyZSIpJERlc2NyaXB0aW9uYA0KDQpgciBwYWNrYWdlRGVzY3JpcHRpb24oImhlcmUiKSRVUkxgDQoNCiMjIyBgciBwYWNrYWdlRGVzY3JpcHRpb24oInBhY2tyYXQiKSRQYWNrYWdlYA0KDQpgciBwYWNrYWdlRGVzY3JpcHRpb24oInBhY2tyYXQiKSRUaXRsZWANCg0KYHIgcGFja2FnZURlc2NyaXB0aW9uKCJwYWNrcmF0IikkRGVzY3JpcHRpb25gDQoNCmByIHBhY2thZ2VEZXNjcmlwdGlvbigicGFja3JhdCIpJFVSTGANCg0KDQojIyMgYHIgcGFja2FnZURlc2NyaXB0aW9uKCJmb3JlYWNoIikkUGFja2FnZWANCg0KYHIgcGFja2FnZURlc2NyaXB0aW9uKCJmb3JlYWNoIikkVGl0bGVgDQoNCmByIHBhY2thZ2VEZXNjcmlwdGlvbigiZm9yZWFjaCIpJERlc2NyaXB0aW9uYA0KDQpgciBwYWNrYWdlRGVzY3JpcHRpb24oImZvcmVhY2giKSRVUkxgDQoNCg==