Reproducible Analysis
Researcher degrees of freedom are an issue in disciplines that rely heavily on fairly complicated statistical analysis. There are many different ways a dataset can be analysed, which can produce qualitatively different results (see Many analysts, one dataset). A way to combat this is to create reproducible workflows, so that given the files and analytical techniques used a result can be replicated and thus critiqued.
Hadley Wickam’s amazing book R for Data Science has the following image of the workflow:
Read the book for a much more developed workflow practice.
Data Import
The information contain here is a quick and dirty way to get set up data import, the first stage of the workflow, a stage that is confusing and daunting given the many different applications that exist to assist in streamlining and data sharing.
I will walk through three topics:
R Projects
Packrat
Github
Projects
R Projects are amazing. Use them. They will save you time and allow you to organise all your work so that you, or anyone else, can pick up where you left off without any key files missing. There is great synergy between R projects, Packrat and GitHub, such that you should be able to import, analyse and share data and code that clearly illustrates what you are trying to do; great for collaboration and great for reporducibility.
Projects allow one to use relative file addresses, such as Temporal_data.csv, which allows for ease of reproducibilty. Projects automatically set the working directing to project folder. This allows us to use relative file addresses so we don’t have to specify what folder to look in on the computer for the dataset. If we have all the files of interest in the project folder, we can just call the name of the datafile and not have to specify where to look.
Why is this useful? Well consider if you sent your datafiles and scipts to someone else. They are going to have a different storage system to you, they’re unlikely to have folders laid out like /PhD/Data/Dimensions of Natural Capital/Transect Data/Nat_Cap_Dim_Transect_Data.csv". So instead we organise our files into one project folder, use relative addresses and send the whole project folder over to our friend. They will then be able to open up a script and get straight to work, no messing around with looking for files.
#relative address
temporal <- read.csv("Temporal_data.csv")
#absolute address, wont be transferable and so hinders ease of reproducibility
Transect <- read.csv("~/PhD/Data/Dimensions of Natural Capital/Transect Data/Nat_Cap_Dim_Transect_Data.csv")
Packrat
Packages make life so much easier, sharing functions and code allows analyses to proceed incredibly fast, once you know what to do. An issue for reproducibility though is that packages change over time, perhaps a function is changed to do something slightly different and years later when you go to reproduce some work, this could produce a different result. Packrat gets around this issue.
Packrat is a dependency management tool that allows each project to have it’s own package folder, or private package library. It notes what version of the package has been used, so that if an analysis is reproduced years later, it will install the version of the package that was used when the analysis took place.
Isolated: Installing a new or updated package for one project won’t break your other projects, and vice versa. That’s because packrat gives each project its own private package library.
Portable: Easily transport your projects from one computer to another, even across different platforms. Packrat makes it easy to install the packages your project depends on.
Reproducible: Packrat records the exact package versions you depend on, and ensures those exact versions are the ones that get installed wherever you go.
To set up Packrat: got to Packages tab and look for Packrat sub tab. You may need to update R studio for this to appear. Click on the packrat tab and check the box to use Packrat with this project.
Now all the packages for this project are stored in a folder for this project. Great.
GitHub
GitHub is a repository for code. It is useful as just that, a repository for all your code, which you can access from anywhere. It’s main advantage over other cloud storage services is that it is built to assist in collaboratively working on projects together. Very useful in the computer programming worlds, but also useful when working on data analysis.
Github works off repositories, basically the same as projects in R. All the filed related to one project are stored in a repositroy.
Introduction to Git
If you are new to Github it can be quite confusing. I was, and still am, a beginner, but I can now see why it can be useful and am eager to keep using it for all of my projects. For an introduction check out this tutorial. By following this tutorial you will be set up with a GitHub account and introduced to repositories.
Further tutorials
For our purposes it will mostly be a reposisitory for code and allow ease of collaboration on analysis, but it can be used for alot more besides.
Setting up Git with an R project:
It should be possible to set up git with an already existing project, yet when I do this I can’t connect to my online github account. I haven’t figured out why yet. So what I do is create a new project that uses Git from the start and then copy over any folders I want into the new Git initiated R project.
You will need a GitHub account to follow these instructions.
- Create a
new project (top right tab in the R studio user interface)
- Choose
Version Control option (the third option)
- Choose the local library on your computer where you would like to create the folder, I use the same address as the R project I created above and just make a new folder within that.
- On your git hub account, create a new repository (green button on the right hand side of the repository sreen).
- Name the repository (repo if Git jargon) whatever you would like, good to keep the names of the R project and Git repo the same.
- Copy and paste the URL of the newly created repo into the URL section of the New Project window in R Studio.
- Copy and paste all the files from the R project folder into the newly created Git enabled R project folder.
- To check that Git is now enabled for use with your R project, open up R project and look for the Git Tab in the top right window in R Studio, as shown:

Now that the project is set up and connected to your online github profile you can commit all the files in the R project and then push them to the master branch online (read this as uploading the project).
- In the top right window of R Studio go to the
Git tab.
- As this is the first time we are commiting (getting files ready to upload) files, click on the
commit sub tab
- Check the files that you would like to
commit, write some commit comment, it is mandatory, and then click the commit button.
- Close the box that pops up and then click the
push button. This will upload or push the committed files to the online repo.
- Check the online repo, have the files been uploaded?
Sharing Projects
Your project can now be shared with other people, all they have to do is copy and paste the URL of the repository when they are creating a new project.
Choose GIT as the version control manager
Alternatively, you can add collaborators to the online repository. Go to the settings tab of your repository on GitHub, then manage access and add collaborators.

Doing this will mean that you don’t have to clone the repository and create a new project every time someone else conducts some new analysis, uploads a new file etc. This is the benefit of GIT, you can pull any new updates that someone else has pushed, you can see what has changed, then do some of your own work, commit the work and then push back to the online repository so your collaborators can access it.
When sharing files collaboratively, the process to follow is:
Pull any new files from the online repo, this will update all the files you hold locally on your device.
Commit the changes in the files you have worked on.
Push the files to upload them to the online repo.
The Pull, Commit and Push workflow ensures that you stay up to date with how the project is developing while contributing your work.
Tidy Data

Tidy Data
Tidy data (go and check out the link for Hadley Wickham’s explanation) is way of formatting data that follows three rules:
- Each variable has its own column
- Each observation must have its own row
- Each value must have its own cell.
Visually it looks like this:
The benefit of using tidy datasets is that it provides a standardised way to format a dataset. This allows you to get familiar with a data structure and become fluent in handling data transformation and analysis, whatever dataset you are presented with. But it is not just an arbirary standard that benefits the user. The tidyverse family of packages is built around tidy datasets and so using tidy data will assist in using that very powerful package family.
The data set below is not tidy. I have multiple observations in one row, the size of a network in May, June, July and August. I am really missing a variable called month and a variable called size. This dataset needs to be tidied.
If you would like to run this code on your computer make sure to remove the comments, the #, in front of the lines of code for installing packages.
#install.packages("kableExtra")
#install.packages("dplyr")
library(dplyr)
library(kableExtra) #this is a package for making nice tables, to compare try just running head(temporal)
kable(head(temporal)) %>%
kable_styling(bootstrap_options = c("striped", "hover"))
| X |
May |
June |
July |
August |
type |
level |
| 1 |
6 |
95 |
41 |
54 |
Urban |
High Urban |
| 2 |
37 |
40 |
113 |
23 |
Urban |
High Urban |
| 3 |
3 |
3 |
19 |
56 |
Urban |
High Urban |
| 4 |
6 |
67 |
99 |
63 |
Urban |
Medium Urban |
| 5 |
7 |
67 |
69 |
52 |
Urban |
Medium Urban |
| 6 |
12 |
114 |
51 |
55 |
Urban |
Medium Urban |
Fortunately, some very smart people have written packages that take all the pain out of doing this. The tidyr package contains functions such as pivot_longer which take an untidy dataset and transform it into a tidy dataset.
#install.packages("tidyr")
library("tidyr")
#taking the four columns May, June, July and Augst and creating a column called month for the names and a column called size for the values.
kable(temporal[1:2,] %>%
pivot_longer(c("May", "June", "July", "August"), names_to = "month", values_to ="size", names_ptypes = list(month = factor()))) %>%
kable_styling(bootstrap_options = c("striped", "hover"))
| X |
type |
level |
month |
size |
| 1 |
Urban |
High Urban |
May |
6 |
| 1 |
Urban |
High Urban |
June |
95 |
| 1 |
Urban |
High Urban |
July |
41 |
| 1 |
Urban |
High Urban |
August |
54 |
| 2 |
Urban |
High Urban |
May |
37 |
| 2 |
Urban |
High Urban |
June |
40 |
| 2 |
Urban |
High Urban |
July |
113 |
| 2 |
Urban |
High Urban |
August |
23 |
Ta da! Now we have tidy data.
Visualisation
I’m a convert to ggplot, after having used base R functions to create plots for years. To help assist in your conversion check out this webpage of plots built using ggplot, aren’t they beautiful?
An example of using ggplot
temporal %>%
pivot_longer(c("May", "June", "July", "August"), names_to = "month", values_to ="size", names_ptypes = list(month = factor())) %>%
ggplot( aes(x=month, y=size)) +
geom_jitter(aes(col=level), size = 3, width = 0.1) +
scale_colour_manual(values= urbanpalette) +
coord_cartesian(ylim=c(0,150)) +
labs(title = "", y="Size", x="", caption = "") +
theme_bw()

In this document I am experimenting with ggplot trying to create beautiful looking PCA plots. Check out the many different ways of creatin PCA plots and compare the base plots to the more customised ggplot based plots. The code to recreate all the plots in the document can be downloaded from this github repo.
Communication
R is far from just a statistical analysis programme. It’s an integrated development environment (IDE) meaning that it can be used to create, develop and publish documents, widgets, webpages, books, theses, presentations, blogs and the list keeps growing. It’s like Powerpoint, Word, LateX, Stata, Wordpress and Wix all bundled into one. Best of all it’s open source, free and has a community that loves to share code and best practices, meaning that if you see some really cool figure, analysis or widget, you will most likely find a tutorial, or code, that will help you to reproduce it. Then you can modify it however you want and hopefully inspire someone to use your code.
R Markdown
R Markdown is a very verstaile document formatting language. It can be translated into HTML (the language of webpages), PDFs through LateX, Word Documents and numerious presentation style formats. People have created websites using R Markdown (link, link and link) and have written books in R Markdown, in fact there is a book about R Markdown written in R Markdown.
This guide has been written using R Markdown!
Markdown resources:
R Pubs
R Pubs is a free publishing service provided by RStudio the company so it is easy to share documents created in RStudio the application.
You are able to read this document because RPubs is hosting it on their servers.
ShinyR
ShinyR allows you to build interactive web applications directly from R. You can publish any apps you create for free at https://www.shinyapps.io/.
#install.packages("shiny")
library(shiny)
Define UI for application that draws a histogram
ui <- fluidPage(
# Application title
titlePanel("Old Faithful Geyser Data"),
# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
sliderInput("bins",
"Number of bins:",
min = 1,
max = 50,
value = 30)
),
# Show a plot of the generated distribution
mainPanel(
plotOutput("distPlot")
)
)
)
Define server logic required to draw a histogram
server <- function(input, output) {
output$distPlot <- renderPlot({
# generate bins based on input$bins from ui.R
x <- faithful[, 2]
bins <- seq(min(x), max(x), length.out = input$bins + 1)
# draw the histogram with the specified number of bins
hist(x, breaks = bins, col = 'darkgray', border = 'white')
})
}
The render function is for the plots or text that you would like to change when in the app
Run the application
#shinyApp(ui = ui, server = server)
Making your own Website
Making websites with Git
Making websites with R
Writing a book or thesis with R
See this good blog on how to write a thesis in R
See this book chapter on how to write books
LS0tDQp0aXRsZTogIlJlcHJvZHVjaWJsZSBBbmFseXNpcyINCmF1dGhvcjogIkNpYW4gV2hpdGUiDQpkYXRlOiAnMjAyMC0wMy0xOCcNCm91dHB1dDoNCiAgaHRtbF9ub3RlYm9vazogZGVmYXVsdA0KICBwZGZfZG9jdW1lbnQ6IGRlZmF1bHQNCi0tLQ0KDQoqKioNCg0KIyBSZXByb2R1Y2libGUgQW5hbHlzaXMNCg0KUmVzZWFyY2hlciBkZWdyZWVzIG9mIGZyZWVkb20gYXJlIGFuIGlzc3VlIGluIGRpc2NpcGxpbmVzIHRoYXQgcmVseSBoZWF2aWx5IG9uIGZhaXJseSBjb21wbGljYXRlZCBzdGF0aXN0aWNhbCBhbmFseXNpcy4gVGhlcmUgYXJlIG1hbnkgZGlmZmVyZW50IHdheXMgYSBkYXRhc2V0IGNhbiBiZSBhbmFseXNlZCwgd2hpY2ggY2FuIHByb2R1Y2UgcXVhbGl0YXRpdmVseSBkaWZmZXJlbnQgcmVzdWx0cyAoc2VlIFtNYW55IGFuYWx5c3RzLCBvbmUgZGF0YXNldF0oaHR0cHM6Ly9qb3VybmFscy5zYWdlcHViLmNvbS9kb2kvMTAuMTE3Ny8yNTE1MjQ1OTE3NzQ3NjQ2KSkuIEEgd2F5IHRvIGNvbWJhdCB0aGlzIGlzIHRvIGNyZWF0ZSByZXByb2R1Y2libGUgd29ya2Zsb3dzLCBzbyB0aGF0IGdpdmVuIHRoZSBmaWxlcyBhbmQgYW5hbHl0aWNhbCB0ZWNobmlxdWVzIHVzZWQgYSByZXN1bHQgY2FuIGJlIHJlcGxpY2F0ZWQgYW5kIHRodXMgY3JpdGlxdWVkLg0KDQpbSGFkbGV5IFdpY2thbSdzXShodHRwOi8vaGFkbGV5Lm56LykgYW1hemluZyBib29rIFtSIGZvciBEYXRhIFNjaWVuY2VdKGh0dHBzOi8vcjRkcy5oYWQuY28ubnovKSBoYXMgdGhlIGZvbGxvd2luZyBpbWFnZSBvZiB0aGUgd29ya2Zsb3c6DQoNCiFbRGF0YSBBbmFseXNpcyBXb3JrZmxvd10oV29ya2Zsb3cuUE5HKQ0KDQpSZWFkIHRoZSBib29rIGZvciBhIG11Y2ggbW9yZSBkZXZlbG9wZWQgd29ya2Zsb3cgcHJhY3RpY2UuDQoNCioqKg0KDQojIyBEYXRhIEltcG9ydA0KDQpUaGUgaW5mb3JtYXRpb24gY29udGFpbiBoZXJlIGlzIGEgcXVpY2sgYW5kIGRpcnR5IHdheSB0byBnZXQgc2V0IHVwIGRhdGEgaW1wb3J0LCB0aGUgZmlyc3Qgc3RhZ2Ugb2YgdGhlIHdvcmtmbG93LCBhIHN0YWdlIHRoYXQgaXMgY29uZnVzaW5nIGFuZCBkYXVudGluZyBnaXZlbiB0aGUgbWFueSBkaWZmZXJlbnQgYXBwbGljYXRpb25zIHRoYXQgZXhpc3QgdG8gYXNzaXN0IGluIHN0cmVhbWxpbmluZyBhbmQgZGF0YSBzaGFyaW5nLg0KDQpJIHdpbGwgd2FsayB0aHJvdWdoIHRocmVlIHRvcGljczoNCg0KMS4gUiBQcm9qZWN0cw0KDQoyLiBQYWNrcmF0DQoNCjMuIEdpdGh1YiAgDQoNCg0KIyMjIFByb2plY3RzDQoNClIgUHJvamVjdHMgYXJlIGFtYXppbmcuIFVzZSB0aGVtLiBUaGV5IHdpbGwgc2F2ZSB5b3UgdGltZSBhbmQgYWxsb3cgeW91IHRvIG9yZ2FuaXNlIGFsbCB5b3VyIHdvcmsgc28gdGhhdCB5b3UsIG9yIGFueW9uZSBlbHNlLCBjYW4gcGljayB1cCB3aGVyZSB5b3UgbGVmdCBvZmYgd2l0aG91dCBhbnkga2V5IGZpbGVzIG1pc3NpbmcuIFRoZXJlIGlzIGdyZWF0IHN5bmVyZ3kgYmV0d2VlbiBSIHByb2plY3RzLCBQYWNrcmF0IGFuZCBHaXRIdWIsIHN1Y2ggdGhhdCB5b3Ugc2hvdWxkIGJlIGFibGUgdG8gaW1wb3J0LCBhbmFseXNlIGFuZCBzaGFyZSBkYXRhIGFuZCBjb2RlIHRoYXQgY2xlYXJseSBpbGx1c3RyYXRlcyB3aGF0IHlvdSBhcmUgdHJ5aW5nIHRvIGRvOyBncmVhdCBmb3IgY29sbGFib3JhdGlvbiBhbmQgZ3JlYXQgZm9yIHJlcG9yZHVjaWJpbGl0eS4NCg0KW1Byb2plY3RzXShodHRwczovL3I0ZHMuaGFkLmNvLm56L3dvcmtmbG93LXByb2plY3RzLmh0bWwpIGFsbG93IG9uZSB0byB1c2UgcmVsYXRpdmUgZmlsZSBhZGRyZXNzZXMsIHN1Y2ggYXMgYFRlbXBvcmFsX2RhdGEuY3N2YCwgd2hpY2ggYWxsb3dzIGZvciBlYXNlIG9mIHJlcHJvZHVjaWJpbHR5LiBQcm9qZWN0cyBhdXRvbWF0aWNhbGx5IHNldCB0aGUgd29ya2luZyBkaXJlY3RpbmcgdG8gcHJvamVjdCBmb2xkZXIuIFRoaXMgYWxsb3dzIHVzIHRvIHVzZSByZWxhdGl2ZSBmaWxlIGFkZHJlc3NlcyBzbyB3ZSBkb24ndCBoYXZlIHRvIHNwZWNpZnkgd2hhdCBmb2xkZXIgdG8gbG9vayBpbiBvbiB0aGUgY29tcHV0ZXIgZm9yIHRoZSBkYXRhc2V0LiBJZiB3ZSBoYXZlIGFsbCB0aGUgZmlsZXMgb2YgaW50ZXJlc3QgaW4gdGhlIHByb2plY3QgZm9sZGVyLCB3ZSBjYW4ganVzdCBjYWxsIHRoZSBuYW1lIG9mIHRoZSBkYXRhZmlsZSBhbmQgbm90IGhhdmUgdG8gc3BlY2lmeSB3aGVyZSB0byBsb29rLiANCg0KV2h5IGlzIHRoaXMgdXNlZnVsPyBXZWxsIGNvbnNpZGVyIGlmIHlvdSBzZW50IHlvdXIgZGF0YWZpbGVzIGFuZCBzY2lwdHMgdG8gc29tZW9uZSBlbHNlLiBUaGV5IGFyZSBnb2luZyB0byBoYXZlIGEgZGlmZmVyZW50IHN0b3JhZ2Ugc3lzdGVtIHRvIHlvdSwgdGhleSdyZSB1bmxpa2VseSB0byBoYXZlIGZvbGRlcnMgbGFpZCBvdXQgbGlrZSBgL1BoRC9EYXRhL0RpbWVuc2lvbnMgb2YgTmF0dXJhbCBDYXBpdGFsL1RyYW5zZWN0IERhdGEvTmF0X0NhcF9EaW1fVHJhbnNlY3RfRGF0YS5jc3YiYC4gU28gaW5zdGVhZCB3ZSBvcmdhbmlzZSBvdXIgZmlsZXMgaW50byBvbmUgcHJvamVjdCBmb2xkZXIsIHVzZSByZWxhdGl2ZSBhZGRyZXNzZXMgYW5kIHNlbmQgdGhlIHdob2xlIHByb2plY3QgZm9sZGVyIG92ZXIgdG8gb3VyIGZyaWVuZC4gVGhleSB3aWxsIHRoZW4gYmUgYWJsZSB0byBvcGVuIHVwIGEgc2NyaXB0IGFuZCBnZXQgc3RyYWlnaHQgdG8gd29yaywgbm8gbWVzc2luZyBhcm91bmQgd2l0aCBsb29raW5nIGZvciBmaWxlcy4NCg0KYGBge3J9DQojcmVsYXRpdmUgYWRkcmVzcw0KdGVtcG9yYWwgPC0gcmVhZC5jc3YoIlRlbXBvcmFsX2RhdGEuY3N2IikNCg0KI2Fic29sdXRlIGFkZHJlc3MsIHdvbnQgYmUgdHJhbnNmZXJhYmxlIGFuZCBzbyBoaW5kZXJzIGVhc2Ugb2YgcmVwcm9kdWNpYmlsaXR5DQpUcmFuc2VjdCA8LSByZWFkLmNzdigifi9QaEQvRGF0YS9EaW1lbnNpb25zIG9mIE5hdHVyYWwgQ2FwaXRhbC9UcmFuc2VjdCBEYXRhL05hdF9DYXBfRGltX1RyYW5zZWN0X0RhdGEuY3N2IikNCmBgYA0KDQoNCg0KIyMjIFBhY2tyYXQNCg0KUGFja2FnZXMgbWFrZSBsaWZlIHNvIG11Y2ggZWFzaWVyLCBzaGFyaW5nIGZ1bmN0aW9ucyBhbmQgY29kZSBhbGxvd3MgYW5hbHlzZXMgdG8gcHJvY2VlZCBpbmNyZWRpYmx5IGZhc3QsIG9uY2UgeW91IGtub3cgd2hhdCB0byBkby4gQW4gaXNzdWUgZm9yIHJlcHJvZHVjaWJpbGl0eSB0aG91Z2ggaXMgdGhhdCBwYWNrYWdlcyBjaGFuZ2Ugb3ZlciB0aW1lLCBwZXJoYXBzIGEgZnVuY3Rpb24gaXMgY2hhbmdlZCB0byBkbyBzb21ldGhpbmcgc2xpZ2h0bHkgZGlmZmVyZW50IGFuZCB5ZWFycyBsYXRlciB3aGVuIHlvdSBnbyB0byByZXByb2R1Y2Ugc29tZSB3b3JrLCB0aGlzIGNvdWxkIHByb2R1Y2UgYSBkaWZmZXJlbnQgcmVzdWx0LiBQYWNrcmF0IGdldHMgYXJvdW5kIHRoaXMgaXNzdWUuDQoNCltQYWNrcmF0XShodHRwOi8vcnN0dWRpby5naXRodWIuaW8vcGFja3JhdC8pIGlzIGEgZGVwZW5kZW5jeSBtYW5hZ2VtZW50IHRvb2wgdGhhdCBhbGxvd3MgZWFjaCBwcm9qZWN0IHRvIGhhdmUgaXQncyBvd24gcGFja2FnZSBmb2xkZXIsIG9yICoqcHJpdmF0ZSBwYWNrYWdlIGxpYnJhcnkqKi4gSXQgbm90ZXMgd2hhdCB2ZXJzaW9uIG9mIHRoZSBwYWNrYWdlIGhhcyBiZWVuIHVzZWQsIHNvIHRoYXQgaWYgYW4gYW5hbHlzaXMgaXMgcmVwcm9kdWNlZCB5ZWFycyBsYXRlciwgaXQgd2lsbCBpbnN0YWxsIHRoZSB2ZXJzaW9uIG9mIHRoZSBwYWNrYWdlIHRoYXQgd2FzIHVzZWQgd2hlbiB0aGUgYW5hbHlzaXMgdG9vayBwbGFjZS4NCg0KDQo+IElzb2xhdGVkOiBJbnN0YWxsaW5nIGEgbmV3IG9yIHVwZGF0ZWQgcGFja2FnZSBmb3Igb25lIHByb2plY3Qgd29u4oCZdCBicmVhayB5b3VyIG90aGVyIHByb2plY3RzLCBhbmQgdmljZSB2ZXJzYS4gVGhhdOKAmXMgYmVjYXVzZSBwYWNrcmF0IGdpdmVzIGVhY2ggcHJvamVjdCBpdHMgb3duIHByaXZhdGUgcGFja2FnZSBsaWJyYXJ5Lg0KDQo+UG9ydGFibGU6IEVhc2lseSB0cmFuc3BvcnQgeW91ciBwcm9qZWN0cyBmcm9tIG9uZSBjb21wdXRlciB0byBhbm90aGVyLCBldmVuIGFjcm9zcyBkaWZmZXJlbnQgcGxhdGZvcm1zLiBQYWNrcmF0IG1ha2VzIGl0IGVhc3kgdG8gaW5zdGFsbCB0aGUgcGFja2FnZXMgeW91ciBwcm9qZWN0IGRlcGVuZHMgb24uDQoNCj5SZXByb2R1Y2libGU6IFBhY2tyYXQgcmVjb3JkcyB0aGUgZXhhY3QgcGFja2FnZSB2ZXJzaW9ucyB5b3UgZGVwZW5kIG9uLCBhbmQgZW5zdXJlcyB0aG9zZSBleGFjdCB2ZXJzaW9ucyBhcmUgdGhlIG9uZXMgdGhhdCBnZXQgaW5zdGFsbGVkIHdoZXJldmVyIHlvdSBnby4NCg0KVG8gc2V0IHVwIFBhY2tyYXQ6IGdvdCB0byBgUGFja2FnZXNgIHRhYiBhbmQgbG9vayBmb3IgYFBhY2tyYXRgIHN1YiB0YWIuIFlvdSBtYXkgbmVlZCB0byB1cGRhdGUgUiBzdHVkaW8gZm9yIHRoaXMgdG8gYXBwZWFyLiBDbGljayBvbiB0aGUgcGFja3JhdCB0YWIgYW5kIGNoZWNrIHRoZSBib3ggdG8gdXNlIFBhY2tyYXQgd2l0aCB0aGlzIHByb2plY3QuDQoNCk5vdyBhbGwgdGhlIHBhY2thZ2VzIGZvciB0aGlzIHByb2plY3QgYXJlIHN0b3JlZCBpbiBhIGZvbGRlciBmb3IgdGhpcyBwcm9qZWN0LiBHcmVhdC4NCg0KIyMjIEdpdEh1Yg0KDQpHaXRIdWIgaXMgYSByZXBvc2l0b3J5IGZvciBjb2RlLiBJdCBpcyB1c2VmdWwgYXMganVzdCB0aGF0LCBhIHJlcG9zaXRvcnkgZm9yIGFsbCB5b3VyIGNvZGUsIHdoaWNoIHlvdSBjYW4gYWNjZXNzIGZyb20gYW55d2hlcmUuIEl0J3MgbWFpbiBhZHZhbnRhZ2Ugb3ZlciBvdGhlciBjbG91ZCBzdG9yYWdlIHNlcnZpY2VzIGlzIHRoYXQgaXQgaXMgYnVpbHQgdG8gYXNzaXN0IGluIGNvbGxhYm9yYXRpdmVseSB3b3JraW5nIG9uIHByb2plY3RzIHRvZ2V0aGVyLiBWZXJ5IHVzZWZ1bCBpbiB0aGUgY29tcHV0ZXIgcHJvZ3JhbW1pbmcgd29ybGRzLCBidXQgYWxzbyB1c2VmdWwgd2hlbiB3b3JraW5nIG9uIGRhdGEgYW5hbHlzaXMuDQoNCkdpdGh1YiB3b3JrcyBvZmYgcmVwb3NpdG9yaWVzLCBiYXNpY2FsbHkgdGhlIHNhbWUgYXMgcHJvamVjdHMgaW4gUi4gQWxsIHRoZSBmaWxlZCByZWxhdGVkIHRvIG9uZSBwcm9qZWN0IGFyZSBzdG9yZWQgaW4gYSByZXBvc2l0cm95Lg0KDQojIyMjIEludHJvZHVjdGlvbiB0byBHaXQNCg0KSWYgeW91IGFyZSBuZXcgdG8gR2l0aHViIGl0IGNhbiBiZSBxdWl0ZSBjb25mdXNpbmcuIEkgd2FzLCBhbmQgc3RpbGwgYW0sIGEgYmVnaW5uZXIsIGJ1dCBJIGNhbiBub3cgc2VlIHdoeSBpdCBjYW4gYmUgdXNlZnVsIGFuZCBhbSBlYWdlciB0byBrZWVwIHVzaW5nIGl0IGZvciBhbGwgb2YgbXkgcHJvamVjdHMuIEZvciBhbiBpbnRyb2R1Y3Rpb24gY2hlY2sgb3V0IHRoaXMgIFt0dXRvcmlhbF0oaHR0cHM6Ly9ndWlkZXMuZ2l0aHViLmNvbS9hY3Rpdml0aWVzL2hlbGxvLXdvcmxkLykuIEJ5IGZvbGxvd2luZyB0aGlzIHR1dG9yaWFsIHlvdSB3aWxsIGJlIHNldCB1cCB3aXRoIGEgR2l0SHViIGFjY291bnQgYW5kIGludHJvZHVjZWQgdG8gcmVwb3NpdG9yaWVzLiANCg0KRnVydGhlciB0dXRvcmlhbHMNCg0KKiBbbGVhcm4gR2l0XShodHRwczovL3RyeS5naXRodWIuaW8vKSAgDQoNCiAgIE1vcmUgYWR2YW5jZWQ6ICANCiogW0dpdCBjaGVhdHNoZWV0XShodHRwczovL2dpdGh1Yi5jb20vdGlpbWdyZWVuL2dpdGh1Yi1jaGVhdC1zaGVldCkgIA0KKiBbR2l0IGFuZCB3ZWJzaXRlc10oaHR0cDovL2ptY2dsb25lLmNvbS9ndWlkZXMvZ2l0aHViLXBhZ2VzLykgIA0KKiBbSHVic3BvdF0oaHR0cHM6Ly9wcm9kdWN0Lmh1YnNwb3QuY29tL2Jsb2cvZ2l0LWFuZC1naXRodWItdHV0b3JpYWwtZm9yLWJlZ2lubmVycykgIA0KDQpGb3Igb3VyIHB1cnBvc2VzIGl0IHdpbGwgbW9zdGx5IGJlIGEgcmVwb3Npc2l0b3J5IGZvciBjb2RlIGFuZCBhbGxvdyBlYXNlIG9mIGNvbGxhYm9yYXRpb24gb24gYW5hbHlzaXMsIGJ1dCBpdCBjYW4gYmUgdXNlZCBmb3IgYWxvdCBtb3JlIGJlc2lkZXMuDQoNCiMjIyMgU2V0dGluZyB1cCBHaXQgd2l0aCBhbiBSIHByb2plY3Q6DQoNCkl0IHNob3VsZCBiZSBwb3NzaWJsZSB0byBzZXQgdXAgZ2l0IHdpdGggYW4gYWxyZWFkeSBleGlzdGluZyBwcm9qZWN0LCB5ZXQgd2hlbiBJIGRvIHRoaXMgSSBjYW4ndCBjb25uZWN0IHRvIG15IG9ubGluZSBnaXRodWIgYWNjb3VudC4gSSBoYXZlbid0IGZpZ3VyZWQgb3V0IHdoeSB5ZXQuIFNvIHdoYXQgSSBkbyBpcyBjcmVhdGUgYSBuZXcgcHJvamVjdCB0aGF0IHVzZXMgR2l0IGZyb20gdGhlIHN0YXJ0IGFuZCB0aGVuIGNvcHkgb3ZlciBhbnkgZm9sZGVycyBJIHdhbnQgaW50byB0aGUgbmV3IEdpdCBpbml0aWF0ZWQgUiBwcm9qZWN0Lg0KDQpZb3Ugd2lsbCBuZWVkIGEgR2l0SHViIGFjY291bnQgdG8gZm9sbG93IHRoZXNlIGluc3RydWN0aW9ucy4NCg0KMS4gQ3JlYXRlIGEgYG5ldyBwcm9qZWN0YCAodG9wIHJpZ2h0IHRhYiBpbiB0aGUgUiBzdHVkaW8gdXNlciBpbnRlcmZhY2UpICANCjIuIENob29zZSBgVmVyc2lvbiBDb250cm9sYCBvcHRpb24gKHRoZSB0aGlyZCBvcHRpb24pICANCjMuIENob29zZSB0aGUgbG9jYWwgbGlicmFyeSBvbiB5b3VyIGNvbXB1dGVyIHdoZXJlIHlvdSB3b3VsZCBsaWtlIHRvIGNyZWF0ZSB0aGUgZm9sZGVyLCBJIHVzZSB0aGUgc2FtZSBhZGRyZXNzIGFzIHRoZSBSIHByb2plY3QgSSBjcmVhdGVkIGFib3ZlIGFuZCBqdXN0IG1ha2UgYSBuZXcgZm9sZGVyIHdpdGhpbiB0aGF0LiAgDQo0LiBPbiB5b3VyIGdpdCBodWIgYWNjb3VudCwgY3JlYXRlIGEgbmV3IHJlcG9zaXRvcnkgKGdyZWVuIGJ1dHRvbiBvbiB0aGUgcmlnaHQgaGFuZCBzaWRlIG9mIHRoZSByZXBvc2l0b3J5IHNyZWVuKS4gIA0KNS4gTmFtZSB0aGUgcmVwb3NpdG9yeSAocmVwbyBpZiBHaXQgamFyZ29uKSB3aGF0ZXZlciB5b3Ugd291bGQgbGlrZSwgZ29vZCB0byBrZWVwIHRoZSBuYW1lcyBvZiB0aGUgUiBwcm9qZWN0IGFuZCBHaXQgcmVwbyB0aGUgc2FtZS4gIA0KNi4gQ29weSBhbmQgcGFzdGUgdGhlIFVSTCBvZiB0aGUgbmV3bHkgY3JlYXRlZCByZXBvIGludG8gdGhlIFVSTCBzZWN0aW9uIG9mIHRoZSBOZXcgUHJvamVjdCB3aW5kb3cgaW4gUiBTdHVkaW8uICANCjcuIENvcHkgYW5kIHBhc3RlIGFsbCB0aGUgZmlsZXMgZnJvbSB0aGUgUiBwcm9qZWN0IGZvbGRlciBpbnRvIHRoZSBuZXdseSBjcmVhdGVkIEdpdCBlbmFibGVkIFIgcHJvamVjdCBmb2xkZXIuICANCjguIFRvIGNoZWNrIHRoYXQgR2l0IGlzIG5vdyBlbmFibGVkIGZvciB1c2Ugd2l0aCB5b3VyIFIgcHJvamVjdCwgb3BlbiB1cCBSIHByb2plY3QgYW5kIGxvb2sgZm9yIHRoZSBHaXQgVGFiIGluIHRoZSB0b3AgcmlnaHQgd2luZG93IGluIFIgU3R1ZGlvLCBhcyBzaG93bjoNCg0KIVtdKEdpdF9lbmFibGVkLlBORykNCg0KTm93IHRoYXQgdGhlIHByb2plY3QgaXMgc2V0IHVwIGFuZCBjb25uZWN0ZWQgdG8geW91ciBvbmxpbmUgZ2l0aHViIHByb2ZpbGUgeW91IGNhbiBjb21taXQgYWxsIHRoZSBmaWxlcyBpbiB0aGUgUiBwcm9qZWN0IGFuZCB0aGVuIHB1c2ggdGhlbSB0byB0aGUgbWFzdGVyIGJyYW5jaCBvbmxpbmUgKHJlYWQgdGhpcyBhcyB1cGxvYWRpbmcgdGhlIHByb2plY3QpLg0KDQoxLiBJbiB0aGUgdG9wIHJpZ2h0IHdpbmRvdyBvZiBSIFN0dWRpbyBnbyB0byB0aGUgYEdpdGAgdGFiLiAgDQoyLiBBcyB0aGlzIGlzIHRoZSBmaXJzdCB0aW1lIHdlIGFyZSBjb21taXRpbmcgKGdldHRpbmcgZmlsZXMgcmVhZHkgdG8gdXBsb2FkKSBmaWxlcywgY2xpY2sgb24gdGhlIGBjb21taXRgIHN1YiB0YWIgIA0KMy4gQ2hlY2sgdGhlIGZpbGVzIHRoYXQgeW91IHdvdWxkIGxpa2UgdG8gYGNvbW1pdGAsIHdyaXRlIHNvbWUgY29tbWl0IGNvbW1lbnQsIGl0IGlzIG1hbmRhdG9yeSwgYW5kIHRoZW4gY2xpY2sgdGhlIGNvbW1pdCBidXR0b24uDQogICsgIVtDb21taXRdKENvbW1pdC5wbmcpDQo0LiBDbG9zZSB0aGUgYm94IHRoYXQgcG9wcyB1cCBhbmQgdGhlbiBjbGljayB0aGUgYHB1c2hgIGJ1dHRvbi4gVGhpcyB3aWxsIHVwbG9hZCBvciBgcHVzaGAgdGhlIGNvbW1pdHRlZCBmaWxlcyB0byB0aGUgb25saW5lIHJlcG8uDQogICsgIVtQdXNoXShQdXNoLlBORykNCjUuIENoZWNrIHRoZSBvbmxpbmUgcmVwbywgaGF2ZSB0aGUgZmlsZXMgYmVlbiB1cGxvYWRlZD8NCg0KIyMjIyBTaGFyaW5nIFByb2plY3RzDQoNCllvdXIgcHJvamVjdCBjYW4gbm93IGJlIHNoYXJlZCB3aXRoIG90aGVyIHBlb3BsZSwgYWxsIHRoZXkgaGF2ZSB0byBkbyBpcyBjb3B5IGFuZCBwYXN0ZSB0aGUgVVJMIG9mIHRoZSByZXBvc2l0b3J5IHdoZW4gdGhleSBhcmUgY3JlYXRpbmcgYSBuZXcgcHJvamVjdC4NCg0KIVtDcmVhdGUgYSBuZXcgdmVyc2lvbiBjb250cm9sIHByb2plY3RdKFZlcnNpb25fY29udHJvbC5QTkcpDQoNCkNob29zZSBHSVQgYXMgdGhlIHZlcnNpb24gY29udHJvbCBtYW5hZ2VyDQoNCiFbQ29weSBhbmQgcGFzdGUgdGhlIHJlcG9zaXRvcnkgVVJMIGludG8gdGhlIFVSTCBib3hdKE5ld19wcm9qZWN0LlBORykNCg0KDQoNCkFsdGVybmF0aXZlbHksIHlvdSBjYW4gYWRkIGNvbGxhYm9yYXRvcnMgdG8gdGhlIG9ubGluZSByZXBvc2l0b3J5LiBHbyB0byB0aGUgc2V0dGluZ3MgdGFiIG9mIHlvdXIgcmVwb3NpdG9yeSBvbiBHaXRIdWIsIHRoZW4gbWFuYWdlIGFjY2VzcyBhbmQgYWRkIGNvbGxhYm9yYXRvcnMuIA0KDQohW10oQ29sbGFib3JhdG9ycy5QTkcpDQoNCkRvaW5nIHRoaXMgd2lsbCBtZWFuIHRoYXQgeW91IGRvbid0IGhhdmUgdG8gY2xvbmUgdGhlIHJlcG9zaXRvcnkgYW5kIGNyZWF0ZSBhIG5ldyBwcm9qZWN0IGV2ZXJ5IHRpbWUgc29tZW9uZSBlbHNlIGNvbmR1Y3RzIHNvbWUgbmV3IGFuYWx5c2lzLCB1cGxvYWRzIGEgbmV3IGZpbGUgZXRjLiBUaGlzIGlzIHRoZSBiZW5lZml0IG9mIEdJVCwgeW91IGNhbiBgcHVsbGAgYW55IG5ldyB1cGRhdGVzIHRoYXQgc29tZW9uZSBlbHNlIGhhcyBgcHVzaGVkYCwgeW91IGNhbiBzZWUgd2hhdCBoYXMgY2hhbmdlZCwgdGhlbiBkbyBzb21lIG9mIHlvdXIgb3duIHdvcmssIGBjb21taXRgIHRoZSB3b3JrIGFuZCB0aGVuIGBwdXNoYCBiYWNrIHRvIHRoZSBvbmxpbmUgcmVwb3NpdG9yeSBzbyB5b3VyIGNvbGxhYm9yYXRvcnMgY2FuIGFjY2VzcyBpdC4NCg0KV2hlbiBzaGFyaW5nIGZpbGVzIGNvbGxhYm9yYXRpdmVseSwgdGhlIHByb2Nlc3MgdG8gZm9sbG93IGlzOg0KDQoxLiBgUHVsbGAgYW55IG5ldyBmaWxlcyBmcm9tIHRoZSBvbmxpbmUgcmVwbywgdGhpcyB3aWxsIHVwZGF0ZSBhbGwgdGhlIGZpbGVzIHlvdSBob2xkIGxvY2FsbHkgb24geW91ciBkZXZpY2UuDQoyLiBgQ29tbWl0YCB0aGUgY2hhbmdlcyBpbiB0aGUgZmlsZXMgeW91IGhhdmUgd29ya2VkIG9uLg0KMy4gYFB1c2hgIHRoZSBmaWxlcyB0byB1cGxvYWQgdGhlbSB0byB0aGUgb25saW5lIHJlcG8uDQoNClRoZSBgUHVsbGAsIGBDb21taXRgIGFuZCBgUHVzaGAgd29ya2Zsb3cgZW5zdXJlcyB0aGF0IHlvdSBzdGF5IHVwIHRvIGRhdGUgd2l0aCBob3cgdGhlIHByb2plY3QgaXMgZGV2ZWxvcGluZyB3aGlsZSBjb250cmlidXRpbmcgeW91ciB3b3JrLg0KDQoqKioNCg0KIyMgVGlkeSBEYXRhDQoNCiFbXShXb3JrZmxvdy5QTkcpDQoNCg0KVGlkeSBEYXRhDQoNCltUaWR5IGRhdGFdKGh0dHBzOi8vcjRkcy5oYWQuY28ubnovdGlkeS1kYXRhLmh0bWwjdGlkeS1kYXRhLTEpIChnbyBhbmQgY2hlY2sgb3V0IHRoZSBsaW5rIGZvciBIYWRsZXkgV2lja2hhbSdzIGV4cGxhbmF0aW9uKSBpcyB3YXkgb2YgZm9ybWF0dGluZyBkYXRhIHRoYXQgZm9sbG93cyB0aHJlZSBydWxlczoNCg0KMS4gRWFjaCB2YXJpYWJsZSBoYXMgaXRzIG93biBjb2x1bW4NCjIuIEVhY2ggb2JzZXJ2YXRpb24gbXVzdCBoYXZlIGl0cyBvd24gcm93DQozLiBFYWNoIHZhbHVlIG11c3QgaGF2ZSBpdHMgb3duIGNlbGwuDQoNClZpc3VhbGx5IGl0IGxvb2tzIGxpa2UgdGhpczoNCg0KIVtUaWR5IGRhdGEgZm9ybWF0XShUaWR5X2RhdGEuUE5HKQ0KDQpUaGUgYmVuZWZpdCBvZiB1c2luZyB0aWR5IGRhdGFzZXRzIGlzIHRoYXQgaXQgcHJvdmlkZXMgYSBzdGFuZGFyZGlzZWQgd2F5IHRvIGZvcm1hdCBhIGRhdGFzZXQuIFRoaXMgYWxsb3dzIHlvdSB0byBnZXQgZmFtaWxpYXIgd2l0aCBhIGRhdGEgc3RydWN0dXJlIGFuZCBiZWNvbWUgZmx1ZW50IGluIGhhbmRsaW5nIGRhdGEgdHJhbnNmb3JtYXRpb24gYW5kIGFuYWx5c2lzLCB3aGF0ZXZlciBkYXRhc2V0IHlvdSBhcmUgcHJlc2VudGVkIHdpdGguIEJ1dCBpdCBpcyBub3QganVzdCBhbiBhcmJpcmFyeSBzdGFuZGFyZCB0aGF0IGJlbmVmaXRzIHRoZSB1c2VyLiBUaGUgYHRpZHl2ZXJzZWAgZmFtaWx5IG9mIHBhY2thZ2VzIGlzIGJ1aWx0IGFyb3VuZCB0aWR5IGRhdGFzZXRzIGFuZCBzbyB1c2luZyB0aWR5IGRhdGEgd2lsbCBhc3Npc3QgaW4gdXNpbmcgdGhhdCB2ZXJ5IHBvd2VyZnVsIHBhY2thZ2UgZmFtaWx5Lg0KDQpUaGUgZGF0YSBzZXQgYmVsb3cgaXMgbm90IHRpZHkuIEkgaGF2ZSBtdWx0aXBsZSBvYnNlcnZhdGlvbnMgaW4gb25lIHJvdywgdGhlIHNpemUgb2YgYSBuZXR3b3JrIGluIE1heSwgSnVuZSwgSnVseSBhbmQgQXVndXN0LiBJIGFtIHJlYWxseSBtaXNzaW5nIGEgdmFyaWFibGUgY2FsbGVkIGBtb250aGAgYW5kIGEgdmFyaWFibGUgY2FsbGVkIGBzaXplYC4gVGhpcyBkYXRhc2V0IG5lZWRzIHRvIGJlIHRpZGllZC4NCg0KSWYgeW91IHdvdWxkIGxpa2UgdG8gcnVuIHRoaXMgY29kZSBvbiB5b3VyIGNvbXB1dGVyIG1ha2Ugc3VyZSB0byByZW1vdmUgdGhlIGNvbW1lbnRzLCB0aGUgIywgaW4gZnJvbnQgb2YgdGhlIGxpbmVzIG9mIGNvZGUgZm9yIGluc3RhbGxpbmcgcGFja2FnZXMuDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0V9DQojaW5zdGFsbC5wYWNrYWdlcygia2FibGVFeHRyYSIpDQojaW5zdGFsbC5wYWNrYWdlcygiZHBseXIiKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkoa2FibGVFeHRyYSkgI3RoaXMgaXMgYSBwYWNrYWdlIGZvciBtYWtpbmcgbmljZSB0YWJsZXMsIHRvIGNvbXBhcmUgdHJ5IGp1c3QgcnVubmluZyBoZWFkKHRlbXBvcmFsKQ0Ka2FibGUoaGVhZCh0ZW1wb3JhbCkpICU+JQ0KICBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJob3ZlciIpKQ0KYGBgDQoNCkZvcnR1bmF0ZWx5LCBzb21lIHZlcnkgc21hcnQgcGVvcGxlIGhhdmUgd3JpdHRlbiBwYWNrYWdlcyB0aGF0IHRha2UgYWxsIHRoZSBwYWluIG91dCBvZiBkb2luZyB0aGlzLiBUaGUgYHRpZHlyYCBwYWNrYWdlIGNvbnRhaW5zIGZ1bmN0aW9ucyBzdWNoIGFzIGBwaXZvdF9sb25nZXJgIHdoaWNoIHRha2UgYW4gdW50aWR5IGRhdGFzZXQgYW5kIHRyYW5zZm9ybSBpdCBpbnRvIGEgdGlkeSBkYXRhc2V0Lg0KYGBge3J9DQojaW5zdGFsbC5wYWNrYWdlcygidGlkeXIiKQ0KbGlicmFyeSgidGlkeXIiKQ0KDQojdGFraW5nIHRoZSBmb3VyIGNvbHVtbnMgTWF5LCBKdW5lLCBKdWx5IGFuZCBBdWdzdCBhbmQgY3JlYXRpbmcgYSBjb2x1bW4gY2FsbGVkIG1vbnRoIGZvciB0aGUgbmFtZXMgYW5kIGEgY29sdW1uIGNhbGxlZCBzaXplIGZvciB0aGUgdmFsdWVzLg0Ka2FibGUodGVtcG9yYWxbMToyLF0gJT4lDQogIHBpdm90X2xvbmdlcihjKCJNYXkiLCAiSnVuZSIsICJKdWx5IiwgIkF1Z3VzdCIpLCBuYW1lc190byA9ICJtb250aCIsIHZhbHVlc190byA9InNpemUiLCBuYW1lc19wdHlwZXMgPSBsaXN0KG1vbnRoID0gZmFjdG9yKCkpKSkgJT4lDQogIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImhvdmVyIikpDQpgYGANCg0KVGEgZGEhIE5vdyB3ZSBoYXZlIHRpZHkgZGF0YS4gDQoNCioqKg0KDQojIyBUcmFuc2Zvcm0NCg0KIVtEYXRhIEFuYWx5c2lzIFdvcmtmbG93XShXb3JrZmxvdy5QTkcpDQoNCkNoZWNrIG91dCBIYWRsZXkgV2lja2hhbSdzIGJvb2sgZm9yIGluZm9ybWF0aW9uIG9uIFtwaXBpbmddKGh0dHBzOi8vcjRkcy5oYWQuY28ubnovcGlwZXMuaHRtbCksIFt2ZWN0b3JzXShodHRwczovL3I0ZHMuaGFkLmNvLm56L3ZlY3RvcnMuaHRtbCksIFtmdW5jdGlvbnNdKGh0dHBzOi8vcjRkcy5oYWQuY28ubnovZnVuY3Rpb25zLmh0bWwpIGFuZCBbaXRlcmF0aW9uLl0oaHR0cHM6Ly9yNGRzLmhhZC5jby5uei9pdGVyYXRpb24uaHRtbCkgVGhlc2UgYXJlIHRoZSBudXRzIGFuZCBib2x0cyBvZiBtYW5pcHVsYXRpbmcgYW5kIHRyYW5zZm9ybWluZyBkYXRhIGFuZCBJIHdvdWxkIHJlY29tbWVuZCBzcGVuZGluZyBzb21lIHRpbWUgb24gZWFjaCBzdWJqZWN0IHRvIGdldCBmbHVlbnQgaW4gZGF0YSBtYW5pcHVsYXRpb24uIEl0IHdpbGwgc2F2ZSB5b3UgbG9hZHMgb2YgdGltZSBhbmQgZXZlbiBiZSBlbmpveWFibGUgb25jZSB5b3UgaGl0IGEgY2VydGFpbiBlc2NhcGUgdmVsb2NpdHkuDQoNCg0KPiBUbDtkciBTdG9yaW5nIG9iamVjdHMgaW4gdGhlIGVudmlyb25tZW50IGlzIG5lY2Vzc2FyeSBidXQgY2FuIGJlIGEgYml0IGNsdXR0ZXJlZCwgcGlwaW5nIGhlbHBzIHRvIHJlZHVjZSB0aGUgY2x1dHRlci4gUGlwaW5nIHdvdWxkIGJyaW5nIGpveSB0byBNYXJpZSBLb25kby4NCg0KT25lIG5vdGUgb24gcGlwaW5nIGlzIHRoYXQgaXQgY2hhbmdlcyBob3cgeW91IHRoaW5rIGFib3V0IHVzaW5nIFIuIFdoZW5ldmVyIEkgd2FzIGNvbmR1Y3RpbmcgbXVsdGlwbGUgb3BlcmF0aW9ucyBvbiBhIGRhdGFzZXQgSSB3b3VsZCBzdG9yZSBlYWNoIHN0ZXAgb2YgdGhlIG9wZXJhdGlvbiBhcyBhbiBvYmplY3QsIGBhID0gN2AsICBgYS4xID0gNmAsIGBhLjIgPSA4YCwgaW4gdGhlIGVudmlyb25tZW50LiBJbiB0aGUgcHJvY2VzcyBvZiBjb25kdWN0aW5nIGFuIGFuYWx5c2lzIEkgY291bGQgZW5kIHVwIHdpdGggaHVuZHJlZHMgb2Ygb2JqZWN0cyBpbiB0aGUgZW52aXJvbm1lbnQgbW9zdCB3aXRoIGFyYnJpdGFyeSBuYW1lcywgc3VjaCBhcyBgYS4yYCBiZWluZyBgOGAsIHRoYXQgZG9uJ3QgbWFrZSBzZW5zZSB0byBhbnlvbmUgZWxzZSwgb3IgZXZlbiBteXNlbGYgYSB3ZWVrIGxhdGVyLiBJIHRoZW4gaGF2ZSB0byB0cnkgYW5kIGZpZ3VyZSBvdXQgd2hhdCBvYmplY3Qgc3RvcmVkIHdoYXQgdmFsdWUgYW5kIGRpc3Rpbmd1aXNoIGl0IGZyb20gdGhlIG15cmlhZCBvZiBvdGhlciB2ZXJ5IHNpbWlsYXIgb2JqZWN0cyBJIGNyZWF0ZWQsIHdhcyBJIGludGVyZXN0ZWQgaW4gYGFgIG9yIGBhLjFgPz8uIEl0IGlzIHZlcnkgZWFzeSB0byBjb25mdXNlIGBhYCBhbmQgYGEuMWAgaW4gYSBwaWVjZSBvZiBjb2RlIGFuZCBpZiBJIGRvbid0IGNhdGNoIGl0LCB0aGlzIGNvdWxkIGVmZmVjdCB0aGUgYW5hbHlzaXMuDQoNClBpcGluZyBoZWxwcyB0byBnZXQgYXJvdW5kIHRoaXMgaXNzdWUsIGFzIGVhY2ggcGllY2Ugb2YgY29kZSBjYW4gc3RhbmQgYWxvbmUgYW5kIGJlIHNlbGYgcmVmZXJlbnRpYWwgdG8gc29tZSBkZWdyZWUuIEl0IGJ1bmRsZXMgdXAgbXVsdGlwbGUgb3BlcmF0aW9ucywgcGlwaW5nIHRoZSByZXN1bHQgb2YgdGhlIHByZXZpb3VzIG9wZXJhdGlvbiB0byB0aGUgZm9sbG93aW5nIG9wZXJhdGlvbi4gVGhhdCB3YXkgd2UgZG9uJ3QgbmVlZCB0byBzdG9yZSBsb3RzIGFuZCBsb3RzIG9mIG9iamVjdHMgaW4gdGhlIGVudmlyb25tZW50LCB3ZSBjYW4gdXNlIHBpcGVzLCBkZWNsdXR0ZXJpbmcgdGhlIGVudmlyb25tZW50LCBtYWtpbmcgY29kZSBsZXNzIGNvbmZ1c2luZyBhbmQgaW5jcmVhc2luZyBlYXNlIG9mIHJlcHJvZHVjaWJpbHR5Lg0KDQpBIHNlY29uZCBwb2ludCBpcyB0aGF0IGNvZGUgaW4gYSBzY3JpcHQgaXMgbW9yZSAncmVhbCcgdGhhbiBhbnkgb2JqZWN0IHN0b3JlZCBpbiB0aGUgZW52aXJvbm1lbnQuIEZvciBhIG1vcmUgY29uc2lzZSBleHBsYW5hdGlvbiBvZiB0aGUgcmVhbG5lc3Mgb2Ygb2JqZWN0cyBhbmQgY29kZSBjaGVjayBvdXQgdGhpcyBbd2hhdCBpcyByZWFsXShodHRwczovL3I0ZHMuaGFkLmNvLm56L3dvcmtmbG93LXByb2plY3RzLmh0bWwjd2hhdC1pcy1yZWFsKSBzZWN0aW9uIG9mIHRoZSBSIGZvciBEYXRhIFNjaWVuY2UgYm9vay4NCg0KKioqDQoNCiMjIFZpc3VhbGlzYXRpb24NCg0KIVtEYXRhIEFuYWx5c2lzIFdvcmtmbG93XShXb3JrZmxvdy5QTkcpDQoNCkknbSBhIGNvbnZlcnQgdG8gZ2dwbG90LCBhZnRlciBoYXZpbmcgdXNlZCBiYXNlIFIgZnVuY3Rpb25zIHRvIGNyZWF0ZSBwbG90cyBmb3IgeWVhcnMuIFRvIGhlbHAgYXNzaXN0IGluIHlvdXIgY29udmVyc2lvbiBjaGVjayBvdXQgdGhpcyBbd2VicGFnZV0oaHR0cDovL3Itc3RhdGlzdGljcy5jby9Ub3A1MC1HZ3Bsb3QyLVZpc3VhbGl6YXRpb25zLU1hc3Rlckxpc3QtUi1Db2RlLmh0bWwpIG9mIHBsb3RzIGJ1aWx0IHVzaW5nIGdncGxvdCwgYXJlbid0IHRoZXkgYmVhdXRpZnVsPw0KDQoNCkFuIGV4YW1wbGUgb2YgdXNpbmcgZ2dwbG90DQpgYGB7ciBpbmNsdWRlPUZ9DQojc2V0dGluZyBteSBwYWxldHRlDQp1cmJhbnBhbGV0dGUgPC0gYygiIzQ1NzVCNCIsIiM3NEFERDEiLCIjQUJEOUU5IiwgImdyZXkiLA0KICAgICAgICAgICAgICAgICAiZ3JleSIsImdyZXkiLCJncmV5IikNCg0KI3NldHRpbmcgZmFjdG9yIGxldmVscyBzbyB0aGV5IHdpbGwgYmUgZGlzcGxheWVkIGFzIHN1Y2ggaW4gbGVnZW5kDQpmYWN0b3IodGVtcG9yYWwkbGV2ZWwsIGxldmVscyA9IGMoIkhpZ2ggVXJiYW4iLCJNZWRpdW0gVXJiYW4iLCJMb3cgVXJiYW4iLCJTZW1pIE5hdCIsIkxvdyBBZ3JpY3VsdHVyYWwiLCJNZWRpdW0gQWdyaWN1bHR1cmFsIiwiSGlnaCBBZ3JpY3VsdHVyYWwiKSkNCg0KDQojaW5zdGFsbGluZyBnZ3Bsb3QgYW5kIGxvYWRpbmcgbGlicmFyeQ0KI2luc3RhbGwucGFja2FnZXMoImdncGxvdDIiKQ0KbGlicmFyeSgiZ2dwbG90MiIpDQpgYGANCg0KYGBge3J9DQp0ZW1wb3JhbCAlPiUNCiAgcGl2b3RfbG9uZ2VyKGMoIk1heSIsICJKdW5lIiwgIkp1bHkiLCAiQXVndXN0IiksIG5hbWVzX3RvID0gIm1vbnRoIiwgdmFsdWVzX3RvID0ic2l6ZSIsIG5hbWVzX3B0eXBlcyA9IGxpc3QobW9udGggPSBmYWN0b3IoKSkpICU+JQ0KICBnZ3Bsb3QoIGFlcyh4PW1vbnRoLCB5PXNpemUpKSArDQogICAgZ2VvbV9qaXR0ZXIoYWVzKGNvbD1sZXZlbCksIHNpemUgPSAzLCB3aWR0aCA9IDAuMSkgKw0KICAgICAgIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzPSB1cmJhbnBhbGV0dGUpICsNCiAgICAgICBjb29yZF9jYXJ0ZXNpYW4oeWxpbT1jKDAsMTUwKSkgKw0KICAgICAgIGxhYnModGl0bGUgPSAiIiwgeT0iU2l6ZSIsIHg9IiIsIGNhcHRpb24gPSAiIikgKw0KICAgICAgICB0aGVtZV9idygpDQpgYGANCg0KSW4gdGhpcyBbZG9jdW1lbnRdKGh0dHBzOi8vcnB1YnMuY29tL2Npd2hpdGUvNTg1OTQ4KSBJIGFtIGV4cGVyaW1lbnRpbmcgd2l0aCBnZ3Bsb3QgdHJ5aW5nIHRvIGNyZWF0ZSBiZWF1dGlmdWwgbG9va2luZyBQQ0EgcGxvdHMuIENoZWNrIG91dCB0aGUgbWFueSBkaWZmZXJlbnQgd2F5cyBvZiBjcmVhdGluIFBDQSBwbG90cyBhbmQgY29tcGFyZSB0aGUgYmFzZSBwbG90cyB0byB0aGUgbW9yZSBjdXN0b21pc2VkIGdncGxvdCBiYXNlZCBwbG90cy4gVGhlIGNvZGUgdG8gcmVjcmVhdGUgYWxsIHRoZSBwbG90cyBpbiB0aGUgZG9jdW1lbnQgY2FuIGJlIGRvd25sb2FkZWQgZnJvbSB0aGlzIFtnaXRodWIgcmVwb10oaHR0cHM6Ly9naXRodWIuY29tL2Npd2hpdGUvUENBL3RyZWUvbWFzdGVyKS4NCg0KDQoqKioNCg0KIyMgQ29tbXVuaWNhdGlvbg0KDQpSIGlzIGZhciBmcm9tIGp1c3QgYSBzdGF0aXN0aWNhbCBhbmFseXNpcyBwcm9ncmFtbWUuIEl0J3MgYW4gaW50ZWdyYXRlZCBkZXZlbG9wbWVudCBlbnZpcm9ubWVudCAoSURFKSBtZWFuaW5nIHRoYXQgaXQgY2FuIGJlIHVzZWQgdG8gY3JlYXRlLCBkZXZlbG9wIGFuZCBwdWJsaXNoIGRvY3VtZW50cywgd2lkZ2V0cywgd2VicGFnZXMsIGJvb2tzLCB0aGVzZXMsIHByZXNlbnRhdGlvbnMsIGJsb2dzIGFuZCB0aGUgbGlzdCBrZWVwcyBncm93aW5nLiBJdCdzIGxpa2UgUG93ZXJwb2ludCwgV29yZCwgTGF0ZVgsIFN0YXRhLCBXb3JkcHJlc3MgYW5kIFdpeCBhbGwgYnVuZGxlZCBpbnRvIG9uZS4gQmVzdCBvZiBhbGwgaXQncyBvcGVuIHNvdXJjZSwgZnJlZSBhbmQgaGFzIGEgY29tbXVuaXR5IHRoYXQgbG92ZXMgdG8gc2hhcmUgY29kZSBhbmQgYmVzdCBwcmFjdGljZXMsIG1lYW5pbmcgdGhhdCBpZiB5b3Ugc2VlIHNvbWUgcmVhbGx5IGNvb2wgZmlndXJlLCBhbmFseXNpcyBvciB3aWRnZXQsIHlvdSB3aWxsIG1vc3QgbGlrZWx5IGZpbmQgYSB0dXRvcmlhbCwgb3IgY29kZSwgdGhhdCB3aWxsIGhlbHAgeW91IHRvIHJlcHJvZHVjZSBpdC4gVGhlbiB5b3UgY2FuIG1vZGlmeSBpdCBob3dldmVyIHlvdSB3YW50IGFuZCBob3BlZnVsbHkgaW5zcGlyZSBzb21lb25lIHRvIHVzZSB5b3VyIGNvZGUuDQoNCiMjIyMgUiBNYXJrZG93bg0KDQpSIE1hcmtkb3duIGlzIGEgdmVyeSB2ZXJzdGFpbGUgZG9jdW1lbnQgZm9ybWF0dGluZyBsYW5ndWFnZS4gSXQgY2FuIGJlIHRyYW5zbGF0ZWQgaW50byBIVE1MICh0aGUgbGFuZ3VhZ2Ugb2Ygd2VicGFnZXMpLCBQREZzIHRocm91Z2ggTGF0ZVgsIFdvcmQgRG9jdW1lbnRzIGFuZCBudW1lcmlvdXMgcHJlc2VudGF0aW9uIHN0eWxlIGZvcm1hdHMuIFBlb3BsZSBoYXZlIGNyZWF0ZWQgd2Vic2l0ZXMgdXNpbmcgUiBNYXJrZG93biAoW2xpbmtdKGh0dHBzOi8vYW1iZXIucmJpbmQuaW8vKSwgW2xpbmtdKGh0dHBzOi8vcm9iamh5bmRtYW4uY29tKSBhbmQgW2xpbmtdKGh0dHA6Ly9saXZlZnJlZW9yZGljaG90b21pemUuY29tKSkgYW5kIGhhdmUgd3JpdHRlbiBib29rcyBpbiBSIE1hcmtkb3duLCBpbiBmYWN0IHRoZXJlIGlzIGEgYm9vayBhYm91dCBbUiBNYXJrZG93bl0oaHR0cHM6Ly9ib29rZG93bi5vcmcveWlodWkvcm1hcmtkb3duLykgd3JpdHRlbiBpbiBSIE1hcmtkb3duLg0KDQpUaGlzIGd1aWRlIGhhcyBiZWVuIHdyaXR0ZW4gdXNpbmcgUiBNYXJrZG93biEgIA0KDQpNYXJrZG93biByZXNvdXJjZXM6DQoNCiogW1F1aWNrIGd1aWRlXShodHRwczovL2dpdGh1Yi5jb20vYWRhbS1wL21hcmtkb3duLWhlcmUvd2lraS9NYXJrZG93bi1DaGVhdHNoZWV0KSBvbiBmb3JtYXRpbmcgb2YgZG9jdW1lbnRzICANCiogW0NoZWF0c2hlZXRdKGh0dHBzOi8vcnN0dWRpby5jb20vd3AtY29udGVudC91cGxvYWRzLzIwMTYvMDMvcm1hcmtkb3duLWNoZWF0c2hlZXQtMi4wLnBkZikNCg0KIyMjIyBSIFB1YnMNCg0KW1IgUHVic10oaHR0cHM6Ly9ycHVicy5jb20vKSBpcyBhIGZyZWUgcHVibGlzaGluZyBzZXJ2aWNlIHByb3ZpZGVkIGJ5IFJTdHVkaW8gdGhlIGNvbXBhbnkgc28gaXQgaXMgZWFzeSB0byBzaGFyZSBkb2N1bWVudHMgY3JlYXRlZCBpbiBSU3R1ZGlvIHRoZSBhcHBsaWNhdGlvbi4NCg0KWW91IGFyZSBhYmxlIHRvIHJlYWQgdGhpcyBkb2N1bWVudCBiZWNhdXNlIFJQdWJzIGlzIGhvc3RpbmcgaXQgb24gdGhlaXIgc2VydmVycy4NCg0KIyMjIyBTaGlueVINCg0KW1NoaW55Ul0oaHR0cHM6Ly9zaGlueS5yc3R1ZGlvLmNvbS8pIGFsbG93cyB5b3UgdG8gYnVpbGQgaW50ZXJhY3RpdmUgd2ViIGFwcGxpY2F0aW9ucyBkaXJlY3RseSBmcm9tIFIuIFlvdSBjYW4gcHVibGlzaCBhbnkgYXBwcyB5b3UgY3JlYXRlIGZvciBmcmVlIGF0IGh0dHBzOi8vd3d3LnNoaW55YXBwcy5pby8uIA0KDQoNCmBgYHtyfQ0KI2luc3RhbGwucGFja2FnZXMoInNoaW55IikNCmxpYnJhcnkoc2hpbnkpDQpgYGANCg0KRGVmaW5lIFVJIGZvciBhcHBsaWNhdGlvbiB0aGF0IGRyYXdzIGEgaGlzdG9ncmFtDQoNCmBgYHtyfQ0KdWkgPC0gZmx1aWRQYWdlKA0KICAgDQogICAjIEFwcGxpY2F0aW9uIHRpdGxlDQogICB0aXRsZVBhbmVsKCJPbGQgRmFpdGhmdWwgR2V5c2VyIERhdGEiKSwNCiAgIA0KICAgIyBTaWRlYmFyIHdpdGggYSBzbGlkZXIgaW5wdXQgZm9yIG51bWJlciBvZiBiaW5zIA0KICAgc2lkZWJhckxheW91dCgNCiAgICAgIHNpZGViYXJQYW5lbCgNCiAgICAgICAgIHNsaWRlcklucHV0KCJiaW5zIiwNCiAgICAgICAgICAgICAgICAgICAgICJOdW1iZXIgb2YgYmluczoiLA0KICAgICAgICAgICAgICAgICAgICAgbWluID0gMSwNCiAgICAgICAgICAgICAgICAgICAgIG1heCA9IDUwLA0KICAgICAgICAgICAgICAgICAgICAgdmFsdWUgPSAzMCkNCiAgICAgICksDQogICAgICANCiAgICAgICMgU2hvdyBhIHBsb3Qgb2YgdGhlIGdlbmVyYXRlZCBkaXN0cmlidXRpb24NCiAgICAgIG1haW5QYW5lbCgNCiAgICAgICAgIHBsb3RPdXRwdXQoImRpc3RQbG90IikNCiAgICAgICkNCiAgICkNCikNCmBgYGANCg0KRGVmaW5lIHNlcnZlciBsb2dpYyByZXF1aXJlZCB0byBkcmF3IGEgaGlzdG9ncmFtDQpgYGB7cn0NCnNlcnZlciA8LSBmdW5jdGlvbihpbnB1dCwgb3V0cHV0KSB7DQogICANCiAgIG91dHB1dCRkaXN0UGxvdCA8LSByZW5kZXJQbG90KHsNCiAgICAgICMgZ2VuZXJhdGUgYmlucyBiYXNlZCBvbiBpbnB1dCRiaW5zIGZyb20gdWkuUg0KICAgICAgeCAgICA8LSBmYWl0aGZ1bFssIDJdIA0KICAgICAgYmlucyA8LSBzZXEobWluKHgpLCBtYXgoeCksIGxlbmd0aC5vdXQgPSBpbnB1dCRiaW5zICsgMSkNCiAgICAgIA0KICAgICAgIyBkcmF3IHRoZSBoaXN0b2dyYW0gd2l0aCB0aGUgc3BlY2lmaWVkIG51bWJlciBvZiBiaW5zDQogICAgICBoaXN0KHgsIGJyZWFrcyA9IGJpbnMsIGNvbCA9ICdkYXJrZ3JheScsIGJvcmRlciA9ICd3aGl0ZScpDQogICB9KQ0KfQ0KYGBgDQoNClRoZSByZW5kZXIgZnVuY3Rpb24gaXMgZm9yIHRoZSBwbG90cyBvciB0ZXh0IHRoYXQgeW91IHdvdWxkIGxpa2UgdG8gY2hhbmdlIHdoZW4gaW4gdGhlIGFwcA0KDQpSdW4gdGhlIGFwcGxpY2F0aW9uIA0KYGBge3J9DQojc2hpbnlBcHAodWkgPSB1aSwgc2VydmVyID0gc2VydmVyKQ0KYGBgDQoNCiMjIyMgTWFraW5nIHlvdXIgb3duIFdlYnNpdGUNCg0KTWFraW5nIHdlYnNpdGVzIHdpdGggR2l0ICANCg0KKiBNYWtlIHlvdXIgb3duIHdlYnNpdGUgd2l0aCBbR2l0IFBhZ2VzXShodHRwczovL3BhZ2VzLmdpdGh1Yi5jb20vKQ0KDQoqIFNlZSBteSBmaXJzdCBhdHRlbXB0OiBodHRwczovL2Npd2hpdGUuZ2l0aHViLmlvLw0KDQoqIFNlZSB0aGlzIGdvb2QgW3R1dG9yaWFsXShodHRwOi8vam1jZ2xvbmUuY29tL2d1aWRlcy9naXRodWItcGFnZXMvKQ0KDQoNCk1ha2luZyB3ZWJzaXRlcyB3aXRoIFINCg0KKiBTZWUgdGhpcyBbdHV0b3JpYWxdKGh0dHBzOi8vYm9va2Rvd24ub3JnL3lpaHVpL3JtYXJrZG93bi93ZWJzaXRlcy5odG1sKQ0KDQojIyMjIFdyaXRpbmcgYSBib29rIG9yIHRoZXNpcyB3aXRoIFINCg0KU2VlIHRoaXMgZ29vZCBbYmxvZ10oaHR0cHM6Ly9saXZlZnJlZW9yZGljaG90b21pemUuY29tLzIwMTgvMDkvMTQvb25lLXllYXItdG8tZGlzc2VydGF0ZS8pIG9uIGhvdyB0byB3cml0ZSBhIHRoZXNpcyBpbiBSDQoNClNlZSB0aGlzIFtib29rIGNoYXB0ZXJdKGh0dHBzOi8vYm9va2Rvd24ub3JnL3lpaHVpL3JtYXJrZG93bi9ib29rcy5odG1sKSBvbiBob3cgdG8gd3JpdGUgYm9va3M=