Associated Material

Zoom Notes: Zoom Notes 10 - Workflows

Introduction

In this module we’re going to cover some ways to improve your workflow as you use R. As you develop your understanding of R and proceed to do fancier things, you’ll want to start bringing in extra features to make your life easier. When we think of a workflow there are three main phases we undertake. At the very beginning we’re setting ourselves up, establishing how things will be organised, and how we intend to work. Second, we do the work - which involves testing and adjusting the established systems, and lastly, we wrap things up.


Getting organised

In the first module we discussed creating a structure for your work inside an RStudio project. For both analysis and programming projects it is useful to have a pre-established ‘go-to’ template structure to keep things organised.

An overarching principle is “keep similar things together”. For an analysis project, this can mean the structure we first covered when setting up an RStudio Project:

My_Project/
  |- data/
  |- docs/
  |- output/
  \- scripts/

Beyond the structure of where we put things, we also want to establish the the principles of how the project will operate. Two important files in this regard are the README and the LICENSE. The README will tell yourself and others important details about the project such as where the source data came from, or how to run the code in the project (e.g. order of scripts). Secondly a LICENSE - this will become important later on when code you have written may be released for others to see (e.g. as part of a research paper) as it will set out the rules under which people may use your code.


Licensing

When we’re dealing with research, by and large we’re operating in an “open source” manner - i.e. the code that is used to perform the research is shared alongside the results so that people can view it. Just because the code is available doesn’t mean that people get to do what they like with your code though.

It’s always a good practice to add a license to go along with your code. A license is a document that lets people who come across the code what they’re allowed to do with it, and what they’re not. There are many open source licenses available and they vary in what behaviours they permit or restrict. When choosing an open source licence there are 3 main questions you need to answer:

  1. Do you care about how any modifications that people make to the code are distributed?
  2. Do you or your institution own any related software patents?
  3. Do you care about the way your name is or isn’t mentioned when someone makes use of your code?

An extremely common license in research code/software is the MIT license which is the simplest and most permissive, and essentially says the code is “as is” without any warranties, and lets people use, copy, modify, and distribute your code so long as the copyright notice goes along with it (i.e. for attribution purposes). For help selecting an appropriate license have a look at https://choosealicense.com.


The usethis Package

The usethis package is designed to assist in the creation of new packages and setting up of new projects. It is is an extremely useful package for several “workflow” tasks. It provides functions for many common workflow tasks such as creating new projects, adding README files, or opening R files.

# Create and open a new package
usethis::create_project(path = "path/to/new/project")

# Create a markdown README
usethis::use_readme_md()

# Create an RMarkdown README
usethis::use_readme_rmd()

# Create a new R script in your project in directory R/
usethis::use_r(name = "myfile.R")

On top of these, there are many other helper functions, such as for creating various licenses, editing configurations, interacting with version control software, or setting up automatic testing. All of which we’ll touch on in this module.

Once you have chosen an appropriate license, usethis likely has a template ready to go. e.g. usethis::use_mit_license().


Configuration

As part of the set up stage, we’re also wanting to make things easier on ourselves to that we can be more productive during the “do stuff” stage.

There is a hidden file called .Rprofile which is loaded as R launches and is a place where you can place customisations of options to make your R life easier. For instance I have mine set to automatically load workflow helper packages such as usethis testthat and devtools. And set a few options to make R produce more warnings so that it helps me know when something might cause an issue. It’s also a good place to set some defaults such as your favourite CRAN mirror so that R doesn’t need to ask you when you go to install packages.

usethis::edit_r_profile()
 # load workflow helper packages if in interactive session
if (interactive()) {
  suppressMessages(require(devtools))
  suppressMessages(require(usethis))
  suppressMessages(require(testthat))
}


# set CRAN
options(repos = c(CRAN = "https://cloud.r-project.org/"))


# warn on partial matches
options(
  warnPartialMatchArgs = TRUE,
  warnPartialMatchDollar = TRUE,
  warnPartialMatchAttr = TRUE
)

# fancy quotes are annoying and lead to
# 'copy + paste' bugs / frustrations
options(useFancyQuotes = FALSE)

Don’t put analysis modifying options into your .Rprofile e.g. automatic loading of tidyverse. It will make the code you write less reproducible because it will start depending on these hidden settings, and it can make debugging harder.


Keyboard shortcuts

The keyboard shortcut to rule them all: Alt + Shift + K

Other useful shortcuts

Keys produces
Ctrl + Shift + M %>%
Alt + - <-
Ctrl + Shift + K knits Rmd
Ctrl + Shift + F10 Restart R
Ctrl + Alt + I Insert code chunk
Ctrl + Shift + S Source active file
Ctrl + . Go to file/function

Make your own…

Tools -> Modify Keyboard Shortcuts


Scripts

Establish the structure of how you want to capture your code. Are you going to do everything in Rscripts? RMarkdown? A combination? Create the appropriate script files. It can be useful to have a separate Rscript where you store functions that you create which can be ‘sourced’ into your other scripts through source("scriptname.R).


Initialise Version Control

This section is a very brief overview of version control, specifically to say that you should start to build it into your workflow and we’ll touch on it again in the Automating Version Control section but ultimately the details are outside of the scope of this course.

You are likely familiar with versioning, usually people try to achieve this through file names. This is ok to a point but can cumbersome and doesn’t scale well across multiple files nor does it give you an easy way to see exactly what the differences were between those files. This is where using version control software such as git can make your life easier.

It’s always a good idea to get this set up before you get under way doing actual work so that you can track you changes from the the very start. In the case of git, following Happy Git with R for installing and configuring git and subsequently telling RStudio about your installation is a good place to start.

Once you have RStudio set up with git, when you add (initialise) version control onto your project you’ll get an new tab appear and a hidden directory called .git will be created inside your project directory. A directory under version control is called a ‘repository’ or ‘repo’.

Version control is used for keeping track of the changes made to your scripts, we don’t usually use it to manage our data - since our initial raw data isn’t going to be changing. For managing data, we use an appropriate backup or archiving system.


Testing and Adjusting

Once things are set up, we’re ready to actually start doing the work we want to do. As we develop our code however, we constantly cycle through testing and adjusting. Each piece of code we write needs to be checked that is is working correctly. Often this type of testing is performed manually as you go: ‘does the line of code run?’ - checking for syntax errors, and then ‘does the output look right?’. When the answer to these either question is no, we then enter a debugging mode where we try and find out why the code isn’t doing what we think it should be.


Debugging

Errors messages are common when coding and are a way the computer communicates it doesn’t understand what the instructions it has been given are. Common types of errors we encounter are:

  • syntactical
  • logical
  • runtime

Syntactical errors are usually the most straight forward, the computer says that no straight away due to improper syntax. These are usually the easiest to find and correct. Logical errors come about through incorrect implementation of logic. The computer will run the code without complaint but the result isn’t correct - these can be tricky to find and fix because they often involve checking each logical statement and subsequent code pathway in order to track down what is going wrong. Runtime errors are errors where you are trying to make the computer do something it can’t in certain situations, such as storing a result in a certain location. The code will run sometimes but not others and again can be tricky to track down.

Remember, each time we find and fix an error, we must retest. This can get quite laborious to do manually so we can find better systems to help such as automatic testing but first we’ll cover some general principles on how to go about debugging.


Where do I start?

Knowing where to start debugging takes practice. some general good advice can be found in https://adv-r.hadley.nz/debugging.html with some specific tips and tricks for R. The general premise is that we want to test and confirm all of our assumptions.

Finding your bug is a process of confirming the many things that you believe are true — until you find one which is not true.

— Norm Matloff

Some techniques for solving errors and confirming our assumptions can include:

  • using print statements to confirm values at key stages
  • googling the error message
  • restart R and rerun the code
  • reading the documentation
  • talk through the problem

‘Rubber duck debugging’ is a technique which involves talking your way through what you are trying to achieve with your code and explaining what your code is actually doing at each step to a rubber duck (or other toy). Often by being systematic and saying out loud what is happening this will trigger an “a-ha” moment as to what is causing the issue. You can also use this technique with another person e.g. co-worker instead of a toy if you prefer.


General process

My general process focuses on the initial source of the error and then starts to work backwards in command history.

  1. Do I recognise the message?
  2. Re-look at the command I ran looking for
    • typos
    • missing syntax (e.g. brackets, semicolons, etc.)
    • correct naming of things
  3. Is the input for my command what I expect it is?
  4. Did the previous command run properly?
    • if not jump to 1. for the previous command


Getting to know some errors

R is notorious for having messages that are not user friendly. Lets look at a few common R errors and warnings so that we can become more familiar with a) what they look like, b) how to find the useful bits

Anatomy of a message

  1. Usually the first word is “Error”, but sometimes it can be “Warning”. Code that produces errors won’t run. Code that produces warnings will run but is signifying that you should be extra careful about the output because it might not be doing what you think it is.
  2. Immediately following is the exact code that is producing the error/warning. This tells you where to start looking.
  3. after the : gives the details about what the error/warning actually is.
my_var
#> Error in eval(expr, envir, enclos): object 'my_var' not found

Caused by trying to access a variable that hasn’t been defined yet.

mean[2]
#> Error in mean[2]: object of type 'closure' is not subsettable

Caused by using the subsetting brackets [] instead of () which are used for a function.

a <- c(one = 1,two = 2, three = 3)
a$one
#> Error in a$one: $ operator is invalid for atomic vectors

You can’t use $ on an atomic vector, it’s used on structures such as data.frames or lists.

a[[20]]
#> Error in a[[20]]: subscript out of bounds

Caused by trying to access an element at an index that doesn’t exist.

read.csv("myfile.csv")
#> Warning in file(file, "rt"): cannot open file 'myfile.csv': No such file or
#> directory
#> Error in file(file, "rt"): cannot open the connection

Caused by providing a file name that R cannot find in the working directory.

ggplot()
#> Error in ggplot(): could not find function "ggplot"

Caused by not having a ggplot function either user defined in the environment or not loaded a library that contains it (ggplot2 or tidyverse).

notapackage::notafunction()
#> Error in loadNamespace(x): there is no package called 'notapackage'

Caused by trying to call a function from a package that doesn’t exist is not be installed on the library path.

if(NA){
  print("was NA")
}
#> Error in if (NA) {: missing value where TRUE/FALSE needed

if requires the result to be TRUE or FALSE, NA isn’t a TRUE or FALSE.

if(c(3 > c(1,2,3))){
  print("less than three")
}
#> Error in if (c(3 > c(1, 2, 3))) {: the condition has length > 1

if(c(1,2,3) > 3){
  print("less than one")
}
#> Error in if (c(1, 2, 3) > 3) {: the condition has length > 1

if requires a single TRUE or FALSE result, these statements create multiple. In older versions of R this produced a warning and not an error.

mean(c("1", "2"))
#> Warning in mean.default(c("1", "2")): argument is not numeric or logical:
#> returning NA

Caused by the a data type that doesn’t coerce into a numeric automatically.


Adjusting

In the process of developing, it’s also important to take opportunities to adjust how things are being done. Working code is better than no code, but you create more code it’s also a good idea to every so often look for opportunities to make things better - efficiency or maintenance wise.

Code replication is a good place to start - if you’ve found yourself copy and pasting the same code over in the same project, consider making it into a function. This then gives you a single place that needs to be changed. If you find yourself copy and pasting your functions across projects, consider creating your own package.


RMarkdown driven dev

Emily Riederer has a great blog post about RMarkdown driven development which describes a process of development using RMarkdown documents, where first you get things to a working situation, then go through rounds of tidying your document bringing like-to-like with your code so that code blocks contain similar processes. As the tidying is performed, it provides an opportunity to also reduce duplication of code and increase the maintainability by converting processes into functions.


Packages

If you find yourself copy and pasting function between documents, it might be time to start creating your own package, that way you reduce the number of individual places your function is defined and this makes it easier in the future to maintain. Packages also bring in an extra level of utility in that you can improve documentation and implement automated testing so that you know when changes break functionality.

If you want to look further into how to create packages, check out the R Packages online book and you can use usethis::create_package() to create a new package from a template.


Automating

As you go about developing, there are two main things you will find yourself doing over and over again - trying to remember what you have changed, and making sure that any changes haven’t broken anything. These processes can be quite time intensive so it’s quite useful to try and automate the pieces that you can.


Automated testing

As you code and manually test, it can be beneficial to formalise the manual tests into an automated solution so that you can be more efficient and also ensure that you know when you ‘break things’ with future changes. This is particularly useful when you fix bugs in your code, create a test that replicates the condition that caused the bug.

In R, one system uses the package testthat which provides a framework to create these formal tests which will evaluate a piece of code against the known expected output and tell you if they don’t match.


# expect a mean of 2
testthat::expect_equal(mean(c(1,2,3)), 2)

testthat operates by setting up expectations and testing if they hold true. If they are true the expectation function is silent, if thy aren’t it will tell you when run. This lets you formalise tests that you would be running manually and as you make adjustments to your code you can rerun these tests to check things are still working.


Automating differences

Version control software is slightly different from what you might have experienced with something like ‘track changes’ in Microsoft Word which tracks all changes live.

In the case of git, once you have everything set up and configured there is a (simplified) mini-workflow which can be done after clicking the ‘commit’ button in the git tab:

  1. Tell git you want it to track the changes on a file
  2. Make some changes
  3. Tell git you want to include these changes in its tracking
    • click the ‘staged’ checkbox on the file in the git-commit window
  4. Tell git to ‘snapshot’ your changes and include a message about them
    • write a message and click commit in the git - commit window
  5. go back to step 2.

Why would you do this workflow? For your future self. Every snapshot you take with git gives you a point in time that you can roll back to if you wish - from a reproducibility point of view this lets you run any version of your code at a snapshot. git can also let you see exactly what changes there were between snapshots which can be extremely helpful for debugging

git is a fairly complex piece of software and provides more functionality than this, but for starting out this workflow covers the main need and use case.


Finalise

Congratulations! You’ve made it to the end-stage of your project where you’re ready to wrap things up and share your project with others. What you do at this stage entirely depends on what output your project was for. Perhaps it’s sending your entire project directory to your lecturer or supervisor. Or this could involve uploading your version controlled code to an online code repository such as https://github.com and publishing the url in your paper or other output.

Regardless, embrace the completion. Then continue on to your next project, bringing with you the skills you learnt on this one.


What’s Next

Please fill in the feedback form https://tinyurl.com/r4ssp-module-fb-s2-23. Your input helps us make R4SSP better.


Appendix

An example workflow set up

# Create and open a new project
usethis::create_project(path = "~/myproject")

# Initialise version control
usethis::use_git()

# Create the project structure
dir.create("data")
dir.create("scripts")
dir.create("output")
dir.create("docs")

# Tell git to ignore the data directory by adding line:
# data/
usethis::edit_git_ignore()


# Add a README
usethis::use_readme_md()

# Add MIT License
usethis::use_mit_license(copyright_holder = "Firstname Lastname")
LS0tCnRpdGxlOiAiV29ya2Zsb3dzIgpkYXRlOiAiU2VtZXN0ZXIgMiwgMjAyMyIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgdG9jX2RlcHRoOiAzCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6IHNob3cKLS0tCiAgCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQpsaWJyYXJ5KGtuaXRyKQoKa25pdHI6Om9wdHNfY2h1bmskc2V0KAogIGNvbW1lbnQgPSAiIz4iLAogIGZpZy5wYXRoID0gImZpZ3VyZXMvMTAvIiwgIyB1c2Ugb25seSBmb3Igc2luZ2xlIFJtZCBmaWxlcwogIGNvbGxhcHNlID0gVFJVRSwKICBlY2hvID0gVFJVRQopCmBgYAoKPiAjIyMjIEFzc29jaWF0ZWQgTWF0ZXJpYWwKPgo+IFpvb20gTm90ZXM6IFtab29tIE5vdGVzIDEwIC0gV29ya2Zsb3dzXSh6b29tX25vdGVzXzEwX3dvcmtmbG93cy5odG1sKQoKCgoKCiMjIEludHJvZHVjdGlvbgoKSW4gdGhpcyBtb2R1bGUgd2UncmUgZ29pbmcgdG8gY292ZXIgc29tZSB3YXlzIHRvIGltcHJvdmUgeW91ciB3b3JrZmxvdyBhcyB5b3UgdXNlIFIuIEFzIHlvdSBkZXZlbG9wIHlvdXIgdW5kZXJzdGFuZGluZyBvZiBSIGFuZCBwcm9jZWVkIHRvIGRvIGZhbmNpZXIgdGhpbmdzLCB5b3UnbGwgd2FudCB0byBzdGFydCBicmluZ2luZyBpbiBleHRyYSBmZWF0dXJlcyB0byBtYWtlIHlvdXIgbGlmZSBlYXNpZXIuIFdoZW4gd2UgdGhpbmsgb2YgYSB3b3JrZmxvdyB0aGVyZSBhcmUgdGhyZWUgbWFpbiBwaGFzZXMgd2UgdW5kZXJ0YWtlLiBBdCB0aGUgdmVyeSBiZWdpbm5pbmcgd2UncmUgc2V0dGluZyBvdXJzZWx2ZXMgdXAsIGVzdGFibGlzaGluZyBob3cgdGhpbmdzIHdpbGwgYmUgb3JnYW5pc2VkLCBhbmQgaG93IHdlIGludGVuZCB0byB3b3JrLiBTZWNvbmQsIHdlIGRvIHRoZSB3b3JrIC0gd2hpY2ggaW52b2x2ZXMgdGVzdGluZyBhbmQgYWRqdXN0aW5nIHRoZSBlc3RhYmxpc2hlZCBzeXN0ZW1zLCBhbmQgbGFzdGx5LCB3ZSB3cmFwIHRoaW5ncyB1cC4KClwKCiMjIEdldHRpbmcgb3JnYW5pc2VkCgpJbiB0aGUgZmlyc3QgbW9kdWxlIHdlIGRpc2N1c3NlZCBjcmVhdGluZyBhIHN0cnVjdHVyZSBmb3IgeW91ciB3b3JrIGluc2lkZSBhbiBSU3R1ZGlvIHByb2plY3QuIEZvciBib3RoIGFuYWx5c2lzIGFuZCBwcm9ncmFtbWluZyBwcm9qZWN0cyBpdCBpcyB1c2VmdWwgdG8gaGF2ZSBhIHByZS1lc3RhYmxpc2hlZCAnZ28tdG8nIHRlbXBsYXRlIHN0cnVjdHVyZSB0byBrZWVwIHRoaW5ncyBvcmdhbmlzZWQuCgpBbiBvdmVyYXJjaGluZyBwcmluY2lwbGUgaXMgImtlZXAgc2ltaWxhciB0aGluZ3MgdG9nZXRoZXIiLiBGb3IgYW4gYW5hbHlzaXMgcHJvamVjdCwgdGhpcyBjYW4gbWVhbiB0aGUgc3RydWN0dXJlIHdlIGZpcnN0IGNvdmVyZWQgd2hlbiBzZXR0aW5nIHVwIGFuIFJTdHVkaW8gUHJvamVjdDoKCmBgYApNeV9Qcm9qZWN0LwogIHwtIGRhdGEvCiAgfC0gZG9jcy8KICB8LSBvdXRwdXQvCiAgXC0gc2NyaXB0cy8KYGBgCgpCZXlvbmQgdGhlIHN0cnVjdHVyZSBvZiB3aGVyZSB3ZSBwdXQgdGhpbmdzLCB3ZSBhbHNvIHdhbnQgdG8gZXN0YWJsaXNoIHRoZSB0aGUgcHJpbmNpcGxlcyBvZiBob3cgdGhlIHByb2plY3Qgd2lsbCBvcGVyYXRlLiBUd28gaW1wb3J0YW50IGZpbGVzIGluIHRoaXMgcmVnYXJkIGFyZSB0aGUgUkVBRE1FIGFuZCB0aGUgTElDRU5TRS4gVGhlIFJFQURNRSB3aWxsIHRlbGwgeW91cnNlbGYgYW5kIG90aGVycyBpbXBvcnRhbnQgZGV0YWlscyBhYm91dCB0aGUgcHJvamVjdCBzdWNoIGFzIHdoZXJlIHRoZSBzb3VyY2UgZGF0YSBjYW1lIGZyb20sIG9yIGhvdyB0byBydW4gdGhlIGNvZGUgaW4gdGhlIHByb2plY3QgKGUuZy4gb3JkZXIgb2Ygc2NyaXB0cykuIFNlY29uZGx5IGEgTElDRU5TRSAtIHRoaXMgd2lsbCBiZWNvbWUgaW1wb3J0YW50IGxhdGVyIG9uIHdoZW4gY29kZSB5b3UgaGF2ZSB3cml0dGVuIG1heSBiZSByZWxlYXNlZCBmb3Igb3RoZXJzIHRvIHNlZSAoZS5nLiBhcyBwYXJ0IG9mIGEgcmVzZWFyY2ggcGFwZXIpIGFzIGl0IHdpbGwgc2V0IG91dCB0aGUgcnVsZXMgdW5kZXIgd2hpY2ggcGVvcGxlIG1heSB1c2UgeW91ciBjb2RlLgoKXAoKIyMjIExpY2Vuc2luZwoKV2hlbiB3ZSdyZSBkZWFsaW5nIHdpdGggcmVzZWFyY2gsIGJ5IGFuZCBsYXJnZSB3ZSdyZSBvcGVyYXRpbmcgaW4gYW4gIm9wZW4gc291cmNlIiBtYW5uZXIgLSBpLmUuIHRoZSBjb2RlIHRoYXQgaXMgdXNlZCB0byBwZXJmb3JtIHRoZSByZXNlYXJjaCBpcyBzaGFyZWQgYWxvbmdzaWRlIHRoZSByZXN1bHRzIHNvIHRoYXQgcGVvcGxlIGNhbiB2aWV3IGl0LiBKdXN0IGJlY2F1c2UgdGhlIGNvZGUgaXMgYXZhaWxhYmxlIGRvZXNuJ3QgbWVhbiB0aGF0IHBlb3BsZSBnZXQgdG8gZG8gd2hhdCB0aGV5IGxpa2Ugd2l0aCB5b3VyIGNvZGUgdGhvdWdoLiAKCkl0J3MgYWx3YXlzIGEgZ29vZCBwcmFjdGljZSB0byBhZGQgYSBsaWNlbnNlIHRvIGdvIGFsb25nIHdpdGggeW91ciBjb2RlLiBBIGxpY2Vuc2UgaXMgYSBkb2N1bWVudCB0aGF0IGxldHMgcGVvcGxlIHdobyBjb21lIGFjcm9zcyB0aGUgY29kZSB3aGF0IHRoZXkncmUgYWxsb3dlZCB0byBkbyB3aXRoIGl0LCBhbmQgd2hhdCB0aGV5J3JlIG5vdC4gVGhlcmUgYXJlIG1hbnkgb3BlbiBzb3VyY2UgbGljZW5zZXMgYXZhaWxhYmxlIGFuZCB0aGV5IHZhcnkgaW4gd2hhdCBiZWhhdmlvdXJzIHRoZXkgcGVybWl0IG9yIHJlc3RyaWN0LiBXaGVuIGNob29zaW5nIGFuIG9wZW4gc291cmNlIGxpY2VuY2UgdGhlcmUgYXJlIDMgbWFpbiBxdWVzdGlvbnMgeW91IG5lZWQgdG8gYW5zd2VyOgoKMS4gRG8geW91IGNhcmUgYWJvdXQgaG93IGFueSBtb2RpZmljYXRpb25zIHRoYXQgcGVvcGxlIG1ha2UgdG8gdGhlIGNvZGUgYXJlIGRpc3RyaWJ1dGVkPwoyLiBEbyB5b3Ugb3IgeW91ciBpbnN0aXR1dGlvbiBvd24gYW55IHJlbGF0ZWQgc29mdHdhcmUgcGF0ZW50cz8KMy4gRG8geW91IGNhcmUgYWJvdXQgdGhlIHdheSB5b3VyIG5hbWUgaXMgb3IgaXNuJ3QgbWVudGlvbmVkIHdoZW4gc29tZW9uZSBtYWtlcyB1c2Ugb2YgeW91ciBjb2RlPwoKQW4gZXh0cmVtZWx5IGNvbW1vbiBsaWNlbnNlIGluIHJlc2VhcmNoIGNvZGUvc29mdHdhcmUgaXMgdGhlIE1JVCBsaWNlbnNlIHdoaWNoIGlzIHRoZSBzaW1wbGVzdCBhbmQgbW9zdCBwZXJtaXNzaXZlLCBhbmQgZXNzZW50aWFsbHkgc2F5cyB0aGUgY29kZSBpcyAiYXMgaXMiIHdpdGhvdXQgYW55IHdhcnJhbnRpZXMsIGFuZCBsZXRzIHBlb3BsZSB1c2UsIGNvcHksIG1vZGlmeSwgYW5kIGRpc3RyaWJ1dGUgeW91ciBjb2RlIHNvIGxvbmcgYXMgdGhlIGNvcHlyaWdodCBub3RpY2UgZ29lcyBhbG9uZyB3aXRoIGl0IChpLmUuIGZvciBhdHRyaWJ1dGlvbiBwdXJwb3NlcykuIEZvciBoZWxwIHNlbGVjdGluZyBhbiBhcHByb3ByaWF0ZSBsaWNlbnNlIGhhdmUgYSBsb29rIGF0IFtodHRwczovL2Nob29zZWFsaWNlbnNlLmNvbV0oaHR0cHM6Ly9jaG9vc2VhbGljZW5zZS5jb20pLgoKXAoKIyMjIFRoZSBgdXNldGhpc2AgUGFja2FnZQoKVGhlIFtgdXNldGhpc2BdKGh0dHBzOi8vdXNldGhpcy5yLWxpYi5vcmcpIHBhY2thZ2UgaXMgZGVzaWduZWQgdG8gYXNzaXN0IGluIHRoZSBjcmVhdGlvbiBvZiBuZXcgcGFja2FnZXMgYW5kIHNldHRpbmcgdXAgb2YgbmV3IHByb2plY3RzLiBJdCBpcyBpcyBhbiBleHRyZW1lbHkgdXNlZnVsIHBhY2thZ2UgZm9yIHNldmVyYWwgIndvcmtmbG93IiB0YXNrcy4gSXQgcHJvdmlkZXMgZnVuY3Rpb25zIGZvciBtYW55IGNvbW1vbiB3b3JrZmxvdyB0YXNrcyBzdWNoIGFzIGNyZWF0aW5nIG5ldyBwcm9qZWN0cywgYWRkaW5nIFJFQURNRSBmaWxlcywgb3Igb3BlbmluZyBSIGZpbGVzLiAKCmBgYHtyLCBldmFsID0gRkFMU0V9CiMgQ3JlYXRlIGFuZCBvcGVuIGEgbmV3IHBhY2thZ2UKdXNldGhpczo6Y3JlYXRlX3Byb2plY3QocGF0aCA9ICJwYXRoL3RvL25ldy9wcm9qZWN0IikKCiMgQ3JlYXRlIGEgbWFya2Rvd24gUkVBRE1FCnVzZXRoaXM6OnVzZV9yZWFkbWVfbWQoKQoKIyBDcmVhdGUgYW4gUk1hcmtkb3duIFJFQURNRQp1c2V0aGlzOjp1c2VfcmVhZG1lX3JtZCgpCgojIENyZWF0ZSBhIG5ldyBSIHNjcmlwdCBpbiB5b3VyIHByb2plY3QgaW4gZGlyZWN0b3J5IFIvCnVzZXRoaXM6OnVzZV9yKG5hbWUgPSAibXlmaWxlLlIiKQoKYGBgCgpPbiB0b3Agb2YgdGhlc2UsIHRoZXJlIGFyZSBtYW55IG90aGVyIGhlbHBlciBmdW5jdGlvbnMsIHN1Y2ggYXMgZm9yIGNyZWF0aW5nIHZhcmlvdXMgbGljZW5zZXMsIGVkaXRpbmcgY29uZmlndXJhdGlvbnMsIGludGVyYWN0aW5nIHdpdGggdmVyc2lvbiBjb250cm9sIHNvZnR3YXJlLCBvciBzZXR0aW5nIHVwIGF1dG9tYXRpYyB0ZXN0aW5nLiBBbGwgb2Ygd2hpY2ggd2UnbGwgdG91Y2ggb24gaW4gdGhpcyBtb2R1bGUuCgpPbmNlIHlvdSBoYXZlIGNob3NlbiBhbiBhcHByb3ByaWF0ZSBsaWNlbnNlLCBgdXNldGhpc2AgbGlrZWx5IGhhcyBhIHRlbXBsYXRlIHJlYWR5IHRvIGdvLiBlLmcuIGB1c2V0aGlzOjp1c2VfbWl0X2xpY2Vuc2UoKWAuCgpcCgojIyMgQ29uZmlndXJhdGlvbgoKQXMgcGFydCBvZiB0aGUgc2V0IHVwIHN0YWdlLCB3ZSdyZSBhbHNvIHdhbnRpbmcgdG8gbWFrZSB0aGluZ3MgZWFzaWVyIG9uIG91cnNlbHZlcyB0byB0aGF0IHdlIGNhbiBiZSBtb3JlIHByb2R1Y3RpdmUgZHVyaW5nIHRoZSAiZG8gc3R1ZmYiIHN0YWdlLgoKVGhlcmUgaXMgYSBoaWRkZW4gZmlsZSBjYWxsZWQgLlJwcm9maWxlIHdoaWNoIGlzIGxvYWRlZCBhcyBSIGxhdW5jaGVzIGFuZCBpcyBhIHBsYWNlIHdoZXJlIHlvdSBjYW4gcGxhY2UgY3VzdG9taXNhdGlvbnMgb2Ygb3B0aW9ucyB0byBtYWtlIHlvdXIgUiBsaWZlIGVhc2llci4gRm9yIGluc3RhbmNlIEkgaGF2ZSBtaW5lIHNldCB0byBhdXRvbWF0aWNhbGx5IGxvYWQgd29ya2Zsb3cgaGVscGVyIHBhY2thZ2VzIHN1Y2ggYXMgYHVzZXRoaXNgIGB0ZXN0dGhhdGAgYW5kIGBkZXZ0b29sc2AuIEFuZCBzZXQgYSBmZXcgb3B0aW9ucyB0byBtYWtlIFIgcHJvZHVjZSBtb3JlIHdhcm5pbmdzIHNvIHRoYXQgaXQgaGVscHMgbWUga25vdyB3aGVuIHNvbWV0aGluZyBtaWdodCBjYXVzZSBhbiBpc3N1ZS4gSXQncyBhbHNvIGEgZ29vZCBwbGFjZSB0byBzZXQgc29tZSBkZWZhdWx0cyBzdWNoIGFzIHlvdXIgZmF2b3VyaXRlIENSQU4gbWlycm9yIHNvIHRoYXQgUiBkb2Vzbid0IG5lZWQgdG8gYXNrIHlvdSB3aGVuIHlvdSBnbyB0byBpbnN0YWxsIHBhY2thZ2VzLgoKYGBge3IsIGV2YWw9RkFMU0V9CnVzZXRoaXM6OmVkaXRfcl9wcm9maWxlKCkKYGBgCgoKYGBge3IsIGV2YWw9RkFMU0V9CiAjIGxvYWQgd29ya2Zsb3cgaGVscGVyIHBhY2thZ2VzIGlmIGluIGludGVyYWN0aXZlIHNlc3Npb24KaWYgKGludGVyYWN0aXZlKCkpIHsKICBzdXBwcmVzc01lc3NhZ2VzKHJlcXVpcmUoZGV2dG9vbHMpKQogIHN1cHByZXNzTWVzc2FnZXMocmVxdWlyZSh1c2V0aGlzKSkKICBzdXBwcmVzc01lc3NhZ2VzKHJlcXVpcmUodGVzdHRoYXQpKQp9CgoKIyBzZXQgQ1JBTgpvcHRpb25zKHJlcG9zID0gYyhDUkFOID0gImh0dHBzOi8vY2xvdWQuci1wcm9qZWN0Lm9yZy8iKSkKCgojIHdhcm4gb24gcGFydGlhbCBtYXRjaGVzCm9wdGlvbnMoCiAgd2FyblBhcnRpYWxNYXRjaEFyZ3MgPSBUUlVFLAogIHdhcm5QYXJ0aWFsTWF0Y2hEb2xsYXIgPSBUUlVFLAogIHdhcm5QYXJ0aWFsTWF0Y2hBdHRyID0gVFJVRQopCgojIGZhbmN5IHF1b3RlcyBhcmUgYW5ub3lpbmcgYW5kIGxlYWQgdG8KIyAnY29weSArIHBhc3RlJyBidWdzIC8gZnJ1c3RyYXRpb25zCm9wdGlvbnModXNlRmFuY3lRdW90ZXMgPSBGQUxTRSkKYGBgCgpEb24ndCBwdXQgYW5hbHlzaXMgbW9kaWZ5aW5nIG9wdGlvbnMgaW50byB5b3VyIC5ScHJvZmlsZSBlLmcuIGF1dG9tYXRpYyBsb2FkaW5nIG9mIGB0aWR5dmVyc2VgLiBJdCB3aWxsIG1ha2UgdGhlIGNvZGUgeW91IHdyaXRlIGxlc3MgcmVwcm9kdWNpYmxlIGJlY2F1c2UgaXQgd2lsbCBzdGFydCBkZXBlbmRpbmcgb24gdGhlc2UgaGlkZGVuIHNldHRpbmdzLCBhbmQgaXQgY2FuIG1ha2UgZGVidWdnaW5nIGhhcmRlci4KClwKCiMjIyMgS2V5Ym9hcmQgc2hvcnRjdXRzCgpUaGUga2V5Ym9hcmQgc2hvcnRjdXQgdG8gcnVsZSB0aGVtIGFsbDogPGtiZD5BbHQ8L2tiZD4gKyA8a2JkPlNoaWZ0PC9rYmQ+ICsgPGtiZD5LPC9rYmQ+CgpPdGhlciB1c2VmdWwgc2hvcnRjdXRzCgpLZXlzIHwgcHJvZHVjZXMKLS0tfC0tLQo8a2JkPkN0cmw8L2tiZD4gKyA8a2JkPlNoaWZ0PC9rYmQ+ICsgPGtiZD5NPC9rYmQ+IHwgJT4lCjxrYmQ+QWx0PC9rYmQ+ICsgPGtiZD4tPC9rYmQ+IHwgPC0KPGtiZD5DdHJsPC9rYmQ+ICsgPGtiZD5TaGlmdDwva2JkPiArIDxrYmQ+Szwva2JkPiB8IGtuaXRzIFJtZAo8a2JkPkN0cmw8L2tiZD4gKyA8a2JkPlNoaWZ0PC9rYmQ+ICsgPGtiZD5GMTA8L2tiZD4gfCBSZXN0YXJ0IFIKPGtiZD5DdHJsPC9rYmQ+ICsgPGtiZD5BbHQ8L2tiZD4gKyA8a2JkPkk8L2tiZD4gfCBJbnNlcnQgY29kZSBjaHVuawo8a2JkPkN0cmw8L2tiZD4gKyA8a2JkPlNoaWZ0PC9rYmQ+ICsgPGtiZD5TPC9rYmQ+IHwgU291cmNlIGFjdGl2ZSBmaWxlCjxrYmQ+Q3RybDwva2JkPiArIDxrYmQ+Ljwva2JkPiB8IEdvIHRvIGZpbGUvZnVuY3Rpb24KCk1ha2UgeW91ciBvd24uLi4KClRvb2xzIC0+IE1vZGlmeSBLZXlib2FyZCBTaG9ydGN1dHMKClwKCiMjIyBTY3JpcHRzCgpFc3RhYmxpc2ggdGhlIHN0cnVjdHVyZSBvZiBob3cgeW91IHdhbnQgdG8gY2FwdHVyZSB5b3VyIGNvZGUuIEFyZSB5b3UgZ29pbmcgdG8gZG8gZXZlcnl0aGluZyBpbiBSc2NyaXB0cz8gUk1hcmtkb3duPyBBIGNvbWJpbmF0aW9uPyBDcmVhdGUgdGhlIGFwcHJvcHJpYXRlIHNjcmlwdCBmaWxlcy4gSXQgY2FuIGJlIHVzZWZ1bCB0byBoYXZlIGEgc2VwYXJhdGUgUnNjcmlwdCB3aGVyZSB5b3Ugc3RvcmUgZnVuY3Rpb25zIHRoYXQgeW91IGNyZWF0ZSB3aGljaCBjYW4gYmUgJ3NvdXJjZWQnIGludG8geW91ciBvdGhlciBzY3JpcHRzIHRocm91Z2ggYHNvdXJjZSgic2NyaXB0bmFtZS5SKWAuCgpcCgojIyMgSW5pdGlhbGlzZSBWZXJzaW9uIENvbnRyb2wKClRoaXMgc2VjdGlvbiBpcyBhIHZlcnkgYnJpZWYgb3ZlcnZpZXcgb2YgdmVyc2lvbiBjb250cm9sLCBzcGVjaWZpY2FsbHkgdG8gc2F5IHRoYXQgeW91IHNob3VsZCBzdGFydCB0byBidWlsZCBpdCBpbnRvIHlvdXIgd29ya2Zsb3cgYW5kIHdlJ2xsIHRvdWNoIG9uIGl0IGFnYWluIGluIHRoZSBbQXV0b21hdGluZyBWZXJzaW9uIENvbnRyb2xdKCNhdXRvLXZjKSBzZWN0aW9uIGJ1dCB1bHRpbWF0ZWx5IHRoZSBkZXRhaWxzIGFyZSBvdXRzaWRlIG9mIHRoZSBzY29wZSBvZiB0aGlzIGNvdXJzZS4KCllvdSBhcmUgbGlrZWx5IGZhbWlsaWFyIHdpdGggdmVyc2lvbmluZywgdXN1YWxseSBwZW9wbGUgdHJ5IHRvIGFjaGlldmUgdGhpcyB0aHJvdWdoIGZpbGUgbmFtZXMuIFRoaXMgaXMgb2sgdG8gYSBwb2ludCBidXQgY2FuIGN1bWJlcnNvbWUgYW5kIGRvZXNuJ3Qgc2NhbGUgd2VsbCBhY3Jvc3MgbXVsdGlwbGUgZmlsZXMgbm9yIGRvZXMgaXQgZ2l2ZSB5b3UgYW4gZWFzeSB3YXkgdG8gc2VlIGV4YWN0bHkgd2hhdCB0aGUgZGlmZmVyZW5jZXMgd2VyZSBiZXR3ZWVuIHRob3NlIGZpbGVzLiBUaGlzIGlzIHdoZXJlIHVzaW5nIHZlcnNpb24gY29udHJvbCBzb2Z0d2FyZSBzdWNoIGFzIGBnaXRgIGNhbiBtYWtlIHlvdXIgbGlmZSBlYXNpZXIuCgpJdCdzIGFsd2F5cyBhIGdvb2QgaWRlYSB0byBnZXQgdGhpcyBzZXQgdXAgYmVmb3JlIHlvdSBnZXQgdW5kZXIgd2F5IGRvaW5nIGFjdHVhbCB3b3JrIHNvIHRoYXQgeW91IGNhbiB0cmFjayB5b3UgY2hhbmdlcyBmcm9tIHRoZSB0aGUgdmVyeSBzdGFydC4gSW4gdGhlIGNhc2Ugb2YgYGdpdGAsIGZvbGxvd2luZyBbSGFwcHkgR2l0IHdpdGggUl0oaHR0cHM6Ly9oYXBweWdpdHdpdGhyLmNvbSkgZm9yIGluc3RhbGxpbmcgYW5kIGNvbmZpZ3VyaW5nIGBnaXRgIGFuZCBzdWJzZXF1ZW50bHkgdGVsbGluZyBSU3R1ZGlvIGFib3V0IHlvdXIgaW5zdGFsbGF0aW9uIGlzIGEgZ29vZCBwbGFjZSB0byBzdGFydC4KCk9uY2UgeW91IGhhdmUgUlN0dWRpbyBzZXQgdXAgd2l0aCBgZ2l0YCwgd2hlbiB5b3UgYWRkIChpbml0aWFsaXNlKSB2ZXJzaW9uIGNvbnRyb2wgb250byB5b3VyIHByb2plY3QgeW91J2xsIGdldCBhbiBuZXcgdGFiIGFwcGVhciBhbmQgYSBoaWRkZW4gZGlyZWN0b3J5IGNhbGxlZCBgLmdpdGAgd2lsbCBiZSBjcmVhdGVkIGluc2lkZSB5b3VyIHByb2plY3QgZGlyZWN0b3J5LiBBIGRpcmVjdG9yeSB1bmRlciB2ZXJzaW9uIGNvbnRyb2wgaXMgY2FsbGVkIGEgJ3JlcG9zaXRvcnknIG9yICdyZXBvJy4KCmBgYHtyLCBlY2hvPUZBTFNFLCBmaWcuYWxpZ249J2NlbnRlcid9CmluY2x1ZGVfZ3JhcGhpY3MoImltYWdlcy8xMC1naXRfcGFuZWwucG5nIikKYGBgCgoKClZlcnNpb24gY29udHJvbCBpcyB1c2VkIGZvciBrZWVwaW5nIHRyYWNrIG9mIHRoZSBjaGFuZ2VzIG1hZGUgdG8geW91ciBzY3JpcHRzLCB3ZSBkb24ndCB1c3VhbGx5IHVzZSBpdCB0byBtYW5hZ2Ugb3VyIGRhdGEgLSBzaW5jZSBvdXIgaW5pdGlhbCByYXcgZGF0YSBpc24ndCBnb2luZyB0byBiZSBjaGFuZ2luZy4gRm9yIG1hbmFnaW5nIGRhdGEsIHdlIHVzZSBhbiBhcHByb3ByaWF0ZSBiYWNrdXAgb3IgYXJjaGl2aW5nIHN5c3RlbS4KClwKCiMjIFRlc3RpbmcgYW5kIEFkanVzdGluZwoKT25jZSB0aGluZ3MgYXJlIHNldCB1cCwgd2UncmUgcmVhZHkgdG8gYWN0dWFsbHkgc3RhcnQgZG9pbmcgdGhlIHdvcmsgd2Ugd2FudCB0byBkby4gQXMgd2UgZGV2ZWxvcCBvdXIgY29kZSBob3dldmVyLCB3ZSBjb25zdGFudGx5IGN5Y2xlIHRocm91Z2ggdGVzdGluZyBhbmQgYWRqdXN0aW5nLiBFYWNoIHBpZWNlIG9mIGNvZGUgd2Ugd3JpdGUgbmVlZHMgdG8gYmUgY2hlY2tlZCB0aGF0IGlzIGlzIHdvcmtpbmcgY29ycmVjdGx5LiBPZnRlbiB0aGlzIHR5cGUgb2YgdGVzdGluZyBpcyBwZXJmb3JtZWQgbWFudWFsbHkgYXMgeW91IGdvOiAnZG9lcyB0aGUgbGluZSBvZiBjb2RlIHJ1bj8nIC0gY2hlY2tpbmcgZm9yIHN5bnRheCBlcnJvcnMsIGFuZCB0aGVuICdkb2VzIHRoZSBvdXRwdXQgbG9vayByaWdodD8nLiBXaGVuIHRoZSBhbnN3ZXIgdG8gdGhlc2UgZWl0aGVyIHF1ZXN0aW9uIGlzIG5vLCB3ZSB0aGVuIGVudGVyIGEgZGVidWdnaW5nIG1vZGUgd2hlcmUgd2UgdHJ5IGFuZCBmaW5kIG91dCB3aHkgdGhlIGNvZGUgaXNuJ3QgZG9pbmcgd2hhdCB3ZSB0aGluayBpdCBzaG91bGQgYmUuICAgCgpcCgojIyMgRGVidWdnaW5nCgoKRXJyb3JzIG1lc3NhZ2VzIGFyZSBjb21tb24gd2hlbiBjb2RpbmcgYW5kIGFyZSBhIHdheSB0aGUgY29tcHV0ZXIgY29tbXVuaWNhdGVzIGl0IGRvZXNuJ3QgdW5kZXJzdGFuZCB3aGF0IHRoZSBpbnN0cnVjdGlvbnMgaXQgaGFzIGJlZW4gZ2l2ZW4gYXJlLgpDb21tb24gdHlwZXMgb2YgZXJyb3JzIHdlIGVuY291bnRlciBhcmU6CgotIHN5bnRhY3RpY2FsCi0gbG9naWNhbAotIHJ1bnRpbWUKClN5bnRhY3RpY2FsIGVycm9ycyBhcmUgdXN1YWxseSB0aGUgbW9zdCBzdHJhaWdodCBmb3J3YXJkLCB0aGUgY29tcHV0ZXIgc2F5cyB0aGF0IG5vIHN0cmFpZ2h0IGF3YXkgZHVlIHRvIGltcHJvcGVyIHN5bnRheC4gVGhlc2UgYXJlIHVzdWFsbHkgdGhlIGVhc2llc3QgdG8gZmluZCBhbmQgY29ycmVjdC4gTG9naWNhbCBlcnJvcnMgY29tZSBhYm91dCB0aHJvdWdoIGluY29ycmVjdCBpbXBsZW1lbnRhdGlvbiBvZiBsb2dpYy4gVGhlIGNvbXB1dGVyIHdpbGwgcnVuIHRoZSBjb2RlIHdpdGhvdXQgY29tcGxhaW50IGJ1dCB0aGUgcmVzdWx0IGlzbid0IGNvcnJlY3QgLSB0aGVzZSBjYW4gYmUgdHJpY2t5IHRvIGZpbmQgYW5kIGZpeCBiZWNhdXNlIHRoZXkgb2Z0ZW4gaW52b2x2ZSBjaGVja2luZyBlYWNoIGxvZ2ljYWwgc3RhdGVtZW50IGFuZCBzdWJzZXF1ZW50IGNvZGUgcGF0aHdheSBpbiBvcmRlciB0byB0cmFjayBkb3duIHdoYXQgaXMgZ29pbmcgd3JvbmcuIFJ1bnRpbWUgZXJyb3JzIGFyZSBlcnJvcnMgd2hlcmUgeW91IGFyZSB0cnlpbmcgdG8gbWFrZSB0aGUgY29tcHV0ZXIgZG8gc29tZXRoaW5nIGl0IGNhbid0IGluIGNlcnRhaW4gc2l0dWF0aW9ucywgc3VjaCBhcyBzdG9yaW5nIGEgcmVzdWx0IGluIGEgY2VydGFpbiBsb2NhdGlvbi4gVGhlIGNvZGUgd2lsbCBydW4gc29tZXRpbWVzIGJ1dCBub3Qgb3RoZXJzIGFuZCBhZ2FpbiBjYW4gYmUgdHJpY2t5IHRvIHRyYWNrIGRvd24uIAoKUmVtZW1iZXIsIGVhY2ggdGltZSB3ZSBmaW5kIGFuZCBmaXggYW4gZXJyb3IsIHdlIG11c3QgcmV0ZXN0LiBUaGlzIGNhbiBnZXQgcXVpdGUgbGFib3Jpb3VzIHRvIGRvIG1hbnVhbGx5IHNvIHdlIGNhbiBmaW5kIGJldHRlciBzeXN0ZW1zIHRvIGhlbHAgc3VjaCBhcyBbYXV0b21hdGljIHRlc3RpbmddKCNhdXRvbWF0aWMtdGVzdHMpIGJ1dCBmaXJzdCB3ZSdsbCBjb3ZlciBzb21lIGdlbmVyYWwgcHJpbmNpcGxlcyBvbiBob3cgdG8gZ28gYWJvdXQgZGVidWdnaW5nLgoKCgpgYGB7ciwgZWNobyA9IEZBTFNFLCBvdXQuaGVpZ2h0ID0gJzUwJScsIG91dC53aWR0aD0nNTAlJywgZmlnLmNhcCA9ICJodHRwczovL3hrY2QuY29tLzE3MzkvIiwgZmlnLmFsaWduPSdjZW50ZXInfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiaW1hZ2VzLzEwLWZpeGluZ19wcm9ibGVtcy5wbmciKQpgYGAKClwKCiMjIyMgV2hlcmUgZG8gSSBzdGFydD8KCktub3dpbmcgd2hlcmUgdG8gc3RhcnQgZGVidWdnaW5nIHRha2VzIHByYWN0aWNlLiBzb21lIGdlbmVyYWwgZ29vZCBhZHZpY2UgY2FuIGJlIGZvdW5kIGluIGh0dHBzOi8vYWR2LXIuaGFkbGV5Lm56L2RlYnVnZ2luZy5odG1sIHdpdGggc29tZSBzcGVjaWZpYyB0aXBzIGFuZCB0cmlja3MgZm9yIFIuIFRoZSBnZW5lcmFsIHByZW1pc2UgaXMgdGhhdCB3ZSB3YW50IHRvIHRlc3QgYW5kIGNvbmZpcm0gYWxsIG9mIG91ciBhc3N1bXB0aW9ucy4KCj4gRmluZGluZyB5b3VyIGJ1ZyBpcyBhIHByb2Nlc3Mgb2YgY29uZmlybWluZyB0aGUgbWFueSB0aGluZ3MgdGhhdCB5b3UgYmVsaWV2ZSBhcmUgdHJ1ZSDigJQgdW50aWwgeW91IGZpbmQgb25lIHdoaWNoIGlzIG5vdCB0cnVlLgo+Cj4g4oCUIE5vcm0gTWF0bG9mZgoKU29tZSB0ZWNobmlxdWVzIGZvciBzb2x2aW5nIGVycm9ycyBhbmQgY29uZmlybWluZyBvdXIgYXNzdW1wdGlvbnMgY2FuIGluY2x1ZGU6CgoKLSB1c2luZyBwcmludCBzdGF0ZW1lbnRzIHRvIGNvbmZpcm0gdmFsdWVzIGF0IGtleSBzdGFnZXMKLSBnb29nbGluZyB0aGUgZXJyb3IgbWVzc2FnZQotIHJlc3RhcnQgUiBhbmQgcmVydW4gdGhlIGNvZGUKLSByZWFkaW5nIHRoZSBkb2N1bWVudGF0aW9uCi0gdGFsayB0aHJvdWdoIHRoZSBwcm9ibGVtCgoKYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0LndpZHRoID0gJzUwJScsIG91dC5oZWlnaHQgPSAnNTAlJywgZmlnLmFsaWduPSdjZW50ZXInfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiaW1hZ2VzLzEwLXJ1YmJlcmR1Y2suanBnIikKYGBgCgonUnViYmVyIGR1Y2sgZGVidWdnaW5nJyBpcyBhIHRlY2huaXF1ZSB3aGljaCBpbnZvbHZlcyB0YWxraW5nIHlvdXIgd2F5IHRocm91Z2ggd2hhdCB5b3UgYXJlIHRyeWluZyB0byBhY2hpZXZlIHdpdGggeW91ciBjb2RlIGFuZCBleHBsYWluaW5nIHdoYXQgeW91ciBjb2RlIGlzIGFjdHVhbGx5IGRvaW5nIGF0IGVhY2ggc3RlcCB0byBhIHJ1YmJlciBkdWNrIChvciBvdGhlciB0b3kpLiBPZnRlbiBieSBiZWluZyBzeXN0ZW1hdGljIGFuZCBzYXlpbmcgb3V0IGxvdWQgd2hhdCBpcyBoYXBwZW5pbmcgdGhpcyB3aWxsIHRyaWdnZXIgYW4gImEtaGEiIG1vbWVudCBhcyB0byB3aGF0IGlzIGNhdXNpbmcgdGhlIGlzc3VlLiBZb3UgY2FuIGFsc28gdXNlIHRoaXMgdGVjaG5pcXVlIHdpdGggYW5vdGhlciBwZXJzb24gZS5nLiBjby13b3JrZXIgaW5zdGVhZCBvZiBhIHRveSBpZiB5b3UgcHJlZmVyLgoKXAoKIyMjIyBHZW5lcmFsIHByb2Nlc3MKCk15IGdlbmVyYWwgcHJvY2VzcyBmb2N1c2VzIG9uIHRoZSBpbml0aWFsIHNvdXJjZSBvZiB0aGUgZXJyb3IgYW5kIHRoZW4gc3RhcnRzIHRvIHdvcmsgYmFja3dhcmRzIGluIGNvbW1hbmQgaGlzdG9yeS4KCjEuIERvIEkgcmVjb2duaXNlIHRoZSBtZXNzYWdlPwoyLiBSZS1sb29rIGF0IHRoZSBjb21tYW5kIEkgcmFuIGxvb2tpbmcgZm9yCiAgICAtIHR5cG9zCiAgICAtIG1pc3Npbmcgc3ludGF4IChlLmcuIGJyYWNrZXRzLCBzZW1pY29sb25zLCBldGMuKQogICAgLSBjb3JyZWN0IG5hbWluZyBvZiB0aGluZ3MKMy4gSXMgdGhlIGlucHV0IGZvciBteSBjb21tYW5kIHdoYXQgSSBleHBlY3QgaXQgaXM/CjQuIERpZCB0aGUgcHJldmlvdXMgY29tbWFuZCBydW4gcHJvcGVybHk/CiAgICAtIGlmIG5vdCBqdW1wIHRvIDEuIGZvciB0aGUgcHJldmlvdXMgY29tbWFuZAoKXAoKIyMjIyBHZXR0aW5nIHRvIGtub3cgc29tZSBlcnJvcnMKClIgaXMgbm90b3Jpb3VzIGZvciBoYXZpbmcgbWVzc2FnZXMgdGhhdCBhcmUgbm90IHVzZXIgZnJpZW5kbHkuIExldHMgbG9vayBhdCBhIGZldyBjb21tb24gUiBlcnJvcnMgYW5kIHdhcm5pbmdzIHNvIHRoYXQgd2UgY2FuIGJlY29tZSBtb3JlIGZhbWlsaWFyIHdpdGggYSkgd2hhdCB0aGV5IGxvb2sgbGlrZSwgYikgaG93IHRvIGZpbmQgdGhlIHVzZWZ1bCBiaXRzCgoqKkFuYXRvbXkgb2YgYSBtZXNzYWdlKioKCjEuIFVzdWFsbHkgdGhlIGZpcnN0IHdvcmQgaXMgIkVycm9yIiwgYnV0IHNvbWV0aW1lcyBpdCBjYW4gYmUgIldhcm5pbmciLiBDb2RlIHRoYXQgcHJvZHVjZXMgZXJyb3JzIHdvbid0IHJ1bi4gQ29kZSB0aGF0IHByb2R1Y2VzIHdhcm5pbmdzIHdpbGwgcnVuIGJ1dCBpcyBzaWduaWZ5aW5nIHRoYXQgeW91IHNob3VsZCBiZSBleHRyYSBjYXJlZnVsIGFib3V0IHRoZSBvdXRwdXQgYmVjYXVzZSBpdCBtaWdodCBub3QgYmUgZG9pbmcgd2hhdCB5b3UgdGhpbmsgaXQgaXMuIAoyLiBJbW1lZGlhdGVseSBmb2xsb3dpbmcgaXMgdGhlIGV4YWN0IGNvZGUgdGhhdCBpcyBwcm9kdWNpbmcgdGhlIGVycm9yL3dhcm5pbmcuIFRoaXMgdGVsbHMgeW91IHdoZXJlIHRvIHN0YXJ0IGxvb2tpbmcuCjMuIGFmdGVyIHRoZSBgOmAgZ2l2ZXMgdGhlIGRldGFpbHMgYWJvdXQgd2hhdCB0aGUgZXJyb3Ivd2FybmluZyBhY3R1YWxseSBpcy4gCgpgYGB7ciwgZXZhbCA9IFRSVUUsIGVycm9yID0gVFJVRSwgd2FybmluZyA9IFRSVUUsIHJlc3VsdHM9J2hpZGUnfQpteV92YXIKYGBgCgpDYXVzZWQgYnkgdHJ5aW5nIHRvIGFjY2VzcyBhIHZhcmlhYmxlIHRoYXQgaGFzbid0IGJlZW4gZGVmaW5lZCB5ZXQuCgpgYGB7ciwgZXZhbCA9IFRSVUUsIGVycm9yID0gVFJVRSwgd2FybmluZyA9IFRSVUUsIHJlc3VsdHM9J2hpZGUnfQptZWFuWzJdCmBgYAoKQ2F1c2VkIGJ5IHVzaW5nIHRoZSBzdWJzZXR0aW5nIGJyYWNrZXRzIGBbXWAgaW5zdGVhZCBvZiBgKClgIHdoaWNoIGFyZSB1c2VkIGZvciBhIGZ1bmN0aW9uLgoKYGBge3IsIGV2YWwgPSBUUlVFLCBlcnJvciA9IFRSVUUsIHdhcm5pbmcgPSBUUlVFLCByZXN1bHRzPSdoaWRlJ30KYSA8LSBjKG9uZSA9IDEsdHdvID0gMiwgdGhyZWUgPSAzKQphJG9uZQpgYGAKCllvdSBjYW4ndCB1c2UgYCRgIG9uIGFuIGF0b21pYyB2ZWN0b3IsIGl0J3MgdXNlZCBvbiBzdHJ1Y3R1cmVzIHN1Y2ggYXMgZGF0YS5mcmFtZXMgb3IgbGlzdHMuCgpgYGB7ciwgZXZhbCA9IFRSVUUsIGVycm9yID0gVFJVRSwgd2FybmluZyA9IFRSVUUsIHJlc3VsdHM9J2hpZGUnfQphW1syMF1dCmBgYAoKQ2F1c2VkIGJ5IHRyeWluZyB0byBhY2Nlc3MgYW4gZWxlbWVudCBhdCBhbiBpbmRleCB0aGF0IGRvZXNuJ3QgZXhpc3QuCgpgYGB7ciwgZXZhbCA9IFRSVUUsIGVycm9yID0gVFJVRSwgd2FybmluZyA9IFRSVUUsIHJlc3VsdHM9J2hpZGUnfQpyZWFkLmNzdigibXlmaWxlLmNzdiIpCmBgYAoKQ2F1c2VkIGJ5IHByb3ZpZGluZyBhIGZpbGUgbmFtZSB0aGF0IFIgY2Fubm90IGZpbmQgaW4gdGhlIHdvcmtpbmcgZGlyZWN0b3J5LgoKYGBge3IsIGV2YWwgPSBUUlVFLCBlcnJvciA9IFRSVUUsIHdhcm5pbmcgPSBUUlVFLCByZXN1bHRzPSdoaWRlJ30KZ2dwbG90KCkKYGBgCgpDYXVzZWQgYnkgbm90IGhhdmluZyBhIGBnZ3Bsb3RgIGZ1bmN0aW9uIGVpdGhlciB1c2VyIGRlZmluZWQgaW4gdGhlIGVudmlyb25tZW50IG9yIG5vdCBsb2FkZWQgYSBsaWJyYXJ5IHRoYXQgY29udGFpbnMgaXQgKGBnZ3Bsb3QyYCBvciBgdGlkeXZlcnNlYCkuCgpgYGB7ciwgZXZhbCA9IFRSVUUsIGVycm9yID0gVFJVRSwgd2FybmluZyA9IFRSVUUsIHJlc3VsdHM9J2hpZGUnfQpub3RhcGFja2FnZTo6bm90YWZ1bmN0aW9uKCkKYGBgCgpDYXVzZWQgYnkgdHJ5aW5nIHRvIGNhbGwgYSBmdW5jdGlvbiBmcm9tIGEgcGFja2FnZSB0aGF0IGRvZXNuJ3QgZXhpc3QgaXMgbm90IGJlIGluc3RhbGxlZCBvbiB0aGUgbGlicmFyeSBwYXRoLgoKYGBge3IsIGV2YWwgPSBUUlVFLCBlcnJvciA9IFRSVUUsIHdhcm5pbmcgPSBUUlVFLCByZXN1bHRzPSdoaWRlJ30KaWYoTkEpewogIHByaW50KCJ3YXMgTkEiKQp9CmBgYAoKYGlmYCByZXF1aXJlcyB0aGUgcmVzdWx0IHRvIGJlIFRSVUUgb3IgRkFMU0UsIGBOQWAgaXNuJ3QgYSBUUlVFIG9yIEZBTFNFLgoKCmBgYHtyLCBldmFsID0gVFJVRSwgZXJyb3IgPSBUUlVFLCB3YXJuaW5nID0gVFJVRSwgcmVzdWx0cz0naGlkZSd9CmlmKGMoMyA+IGMoMSwyLDMpKSl7CiAgcHJpbnQoImxlc3MgdGhhbiB0aHJlZSIpCn0KCmlmKGMoMSwyLDMpID4gMyl7CiAgcHJpbnQoImxlc3MgdGhhbiBvbmUiKQp9CmBgYAoKYGlmYCByZXF1aXJlcyBhIHNpbmdsZSBUUlVFIG9yIEZBTFNFIHJlc3VsdCwgdGhlc2Ugc3RhdGVtZW50cyBjcmVhdGUgbXVsdGlwbGUuIEluIG9sZGVyIHZlcnNpb25zIG9mIFIgdGhpcyBwcm9kdWNlZCBhIHdhcm5pbmcgYW5kIG5vdCBhbiBlcnJvci4KCmBgYHtyLCBldmFsID0gVFJVRSwgZXJyb3IgPSBUUlVFLCB3YXJuaW5nID0gVFJVRSwgcmVzdWx0cz0naGlkZSd9Cm1lYW4oYygiMSIsICIyIikpCmBgYAoKQ2F1c2VkIGJ5IHRoZSBhIGRhdGEgdHlwZSB0aGF0IGRvZXNuJ3QgY29lcmNlIGludG8gYSBudW1lcmljIGF1dG9tYXRpY2FsbHkuCgpcCgojIyMgQWRqdXN0aW5nCgpJbiB0aGUgcHJvY2VzcyBvZiBkZXZlbG9waW5nLCBpdCdzIGFsc28gaW1wb3J0YW50IHRvIHRha2Ugb3Bwb3J0dW5pdGllcyB0byBhZGp1c3QgaG93IHRoaW5ncyBhcmUgYmVpbmcgZG9uZS4gV29ya2luZyBjb2RlIGlzIGJldHRlciB0aGFuIG5vIGNvZGUsIGJ1dCB5b3UgY3JlYXRlIG1vcmUgY29kZSBpdCdzIGFsc28gYSBnb29kIGlkZWEgdG8gZXZlcnkgc28gb2Z0ZW4gbG9vayBmb3Igb3Bwb3J0dW5pdGllcyB0byBtYWtlIHRoaW5ncyBiZXR0ZXIgLSBlZmZpY2llbmN5IG9yIG1haW50ZW5hbmNlIHdpc2UuCgpDb2RlIHJlcGxpY2F0aW9uIGlzIGEgZ29vZCBwbGFjZSB0byBzdGFydCAtIGlmIHlvdSd2ZSBmb3VuZCB5b3Vyc2VsZiBjb3B5IGFuZCBwYXN0aW5nIHRoZSBzYW1lIGNvZGUgb3ZlciBpbiB0aGUgc2FtZSBwcm9qZWN0LCBjb25zaWRlciBtYWtpbmcgaXQgaW50byBhIGZ1bmN0aW9uLiBUaGlzIHRoZW4gZ2l2ZXMgeW91IGEgc2luZ2xlIHBsYWNlIHRoYXQgbmVlZHMgdG8gYmUgY2hhbmdlZC4gSWYgeW91IGZpbmQgeW91cnNlbGYgY29weSBhbmQgcGFzdGluZyB5b3VyIGZ1bmN0aW9ucyBhY3Jvc3MgcHJvamVjdHMsIGNvbnNpZGVyIGNyZWF0aW5nIHlvdXIgb3duIHBhY2thZ2UuCgpcCgojIyMjIFJNYXJrZG93biBkcml2ZW4gZGV2CgpFbWlseSBSaWVkZXJlciBoYXMgYSBncmVhdCBibG9nIHBvc3QgYWJvdXQgW1JNYXJrZG93biBkcml2ZW4gZGV2ZWxvcG1lbnRdKGh0dHBzOi8vZW1pbHlyaWVkZXJlci5uZXRsaWZ5LmFwcC9wb3N0L3JtYXJrZG93bi1kcml2ZW4tZGV2ZWxvcG1lbnQvKSB3aGljaCBkZXNjcmliZXMgYSBwcm9jZXNzIG9mIGRldmVsb3BtZW50IHVzaW5nIFJNYXJrZG93biBkb2N1bWVudHMsIHdoZXJlIGZpcnN0IHlvdSBnZXQgdGhpbmdzIHRvIGEgd29ya2luZyBzaXR1YXRpb24sIHRoZW4gZ28gdGhyb3VnaCByb3VuZHMgb2YgdGlkeWluZyB5b3VyIGRvY3VtZW50IGJyaW5naW5nIGxpa2UtdG8tbGlrZSB3aXRoIHlvdXIgY29kZSBzbyB0aGF0IGNvZGUgYmxvY2tzIGNvbnRhaW4gc2ltaWxhciBwcm9jZXNzZXMuIEFzIHRoZSB0aWR5aW5nIGlzIHBlcmZvcm1lZCwgaXQgcHJvdmlkZXMgYW4gb3Bwb3J0dW5pdHkgdG8gYWxzbyByZWR1Y2UgZHVwbGljYXRpb24gb2YgY29kZSBhbmQgaW5jcmVhc2UgdGhlIG1haW50YWluYWJpbGl0eSBieSBjb252ZXJ0aW5nIHByb2Nlc3NlcyBpbnRvIGZ1bmN0aW9ucy4gCgpcCgojIyMjIFBhY2thZ2VzCgpJZiB5b3UgZmluZCB5b3Vyc2VsZiBjb3B5IGFuZCBwYXN0aW5nIGZ1bmN0aW9uIGJldHdlZW4gZG9jdW1lbnRzLCBpdCBtaWdodCBiZSB0aW1lIHRvIHN0YXJ0IGNyZWF0aW5nIHlvdXIgb3duIHBhY2thZ2UsIHRoYXQgd2F5IHlvdSByZWR1Y2UgdGhlIG51bWJlciBvZiBpbmRpdmlkdWFsIHBsYWNlcyB5b3VyIGZ1bmN0aW9uIGlzIGRlZmluZWQgYW5kIHRoaXMgbWFrZXMgaXQgZWFzaWVyIGluIHRoZSBmdXR1cmUgdG8gbWFpbnRhaW4uIFBhY2thZ2VzIGFsc28gYnJpbmcgaW4gYW4gZXh0cmEgbGV2ZWwgb2YgdXRpbGl0eSBpbiB0aGF0IHlvdSBjYW4gaW1wcm92ZSBkb2N1bWVudGF0aW9uIGFuZCBpbXBsZW1lbnQgYXV0b21hdGVkIHRlc3Rpbmcgc28gdGhhdCB5b3Uga25vdyB3aGVuIGNoYW5nZXMgYnJlYWsgZnVuY3Rpb25hbGl0eS4KCklmIHlvdSB3YW50IHRvIGxvb2sgZnVydGhlciBpbnRvIGhvdyB0byBjcmVhdGUgcGFja2FnZXMsIGNoZWNrIG91dCB0aGUgW1IgUGFja2FnZXMgb25saW5lIGJvb2tdKGh0dHBzOi8vci1wa2dzLm9yZy9pbmRleC5odG1sKSBhbmQgeW91IGNhbiB1c2UgYHVzZXRoaXM6OmNyZWF0ZV9wYWNrYWdlKClgIHRvIGNyZWF0ZSBhIG5ldyBwYWNrYWdlIGZyb20gYSB0ZW1wbGF0ZS4KClwKCiMjIEF1dG9tYXRpbmcKCkFzIHlvdSBnbyBhYm91dCBkZXZlbG9waW5nLCB0aGVyZSBhcmUgdHdvIG1haW4gdGhpbmdzIHlvdSB3aWxsIGZpbmQgeW91cnNlbGYgZG9pbmcgb3ZlciBhbmQgb3ZlciBhZ2FpbiAtIHRyeWluZyB0byByZW1lbWJlciB3aGF0IHlvdSBoYXZlIGNoYW5nZWQsIGFuZCBtYWtpbmcgc3VyZSB0aGF0IGFueSBjaGFuZ2VzIGhhdmVuJ3QgYnJva2VuIGFueXRoaW5nLiBUaGVzZSBwcm9jZXNzZXMgY2FuIGJlIHF1aXRlIHRpbWUgaW50ZW5zaXZlIHNvIGl0J3MgcXVpdGUgdXNlZnVsIHRvIHRyeSBhbmQgYXV0b21hdGUgdGhlIHBpZWNlcyB0aGF0IHlvdSBjYW4uCgpcCgojIyMgQXV0b21hdGVkIHRlc3RpbmcgeyNhdXRvbWF0aWMtdGVzdHN9CgpBcyB5b3UgY29kZSBhbmQgbWFudWFsbHkgdGVzdCwgaXQgY2FuIGJlIGJlbmVmaWNpYWwgdG8gZm9ybWFsaXNlIHRoZSBtYW51YWwgdGVzdHMgaW50byBhbiBhdXRvbWF0ZWQgc29sdXRpb24gc28gdGhhdCB5b3UgY2FuIGJlIG1vcmUgZWZmaWNpZW50IGFuZCBhbHNvIGVuc3VyZSB0aGF0IHlvdSBrbm93IHdoZW4geW91ICdicmVhayB0aGluZ3MnIHdpdGggZnV0dXJlIGNoYW5nZXMuIFRoaXMgaXMgcGFydGljdWxhcmx5IHVzZWZ1bCB3aGVuIHlvdSBmaXggYnVncyBpbiB5b3VyIGNvZGUsIGNyZWF0ZSBhIHRlc3QgdGhhdCByZXBsaWNhdGVzIHRoZSBjb25kaXRpb24gdGhhdCBjYXVzZWQgdGhlIGJ1Zy4KCkluIFIsIG9uZSBzeXN0ZW0gdXNlcyB0aGUgcGFja2FnZSBgdGVzdHRoYXRgIHdoaWNoIHByb3ZpZGVzIGEgZnJhbWV3b3JrIHRvIGNyZWF0ZSB0aGVzZSBmb3JtYWwgdGVzdHMgd2hpY2ggd2lsbCBldmFsdWF0ZSBhIHBpZWNlIG9mIGNvZGUgYWdhaW5zdCB0aGUga25vd24gZXhwZWN0ZWQgb3V0cHV0IGFuZCB0ZWxsIHlvdSBpZiB0aGV5IGRvbid0IG1hdGNoLgoKYGBge3IsIGV2YWwgPSBGQUxTRX0KCiMgZXhwZWN0IGEgbWVhbiBvZiAyCnRlc3R0aGF0OjpleHBlY3RfZXF1YWwobWVhbihjKDEsMiwzKSksIDIpCmBgYAoKYHRlc3R0aGF0YCBvcGVyYXRlcyBieSBzZXR0aW5nIHVwIGV4cGVjdGF0aW9ucyBhbmQgdGVzdGluZyBpZiB0aGV5IGhvbGQgdHJ1ZS4gSWYgdGhleSBhcmUgdHJ1ZSB0aGUgZXhwZWN0YXRpb24gZnVuY3Rpb24gaXMgc2lsZW50LCBpZiB0aHkgYXJlbid0IGl0IHdpbGwgdGVsbCB5b3Ugd2hlbiBydW4uIFRoaXMgbGV0cyB5b3UgZm9ybWFsaXNlIHRlc3RzIHRoYXQgeW91IHdvdWxkIGJlIHJ1bm5pbmcgbWFudWFsbHkgYW5kIGFzIHlvdSBtYWtlIGFkanVzdG1lbnRzIHRvIHlvdXIgY29kZSB5b3UgY2FuIHJlcnVuIHRoZXNlIHRlc3RzIHRvIGNoZWNrIHRoaW5ncyBhcmUgc3RpbGwgd29ya2luZy4KClwKCiMjIyBBdXRvbWF0aW5nIGRpZmZlcmVuY2VzIHsjYXV0by12Y30KClZlcnNpb24gY29udHJvbCBzb2Z0d2FyZSBpcyBzbGlnaHRseSBkaWZmZXJlbnQgZnJvbSB3aGF0IHlvdSBtaWdodCBoYXZlIGV4cGVyaWVuY2VkIHdpdGggc29tZXRoaW5nIGxpa2UgJ3RyYWNrIGNoYW5nZXMnIGluIE1pY3Jvc29mdCBXb3JkIHdoaWNoIHRyYWNrcyBhbGwgY2hhbmdlcyBsaXZlLiAKCkluIHRoZSBjYXNlIG9mIGBnaXRgLCBvbmNlIHlvdSBoYXZlIGV2ZXJ5dGhpbmcgc2V0IHVwIGFuZCBjb25maWd1cmVkIHRoZXJlIGlzIGEgKHNpbXBsaWZpZWQpIG1pbmktd29ya2Zsb3cgd2hpY2ggY2FuIGJlIGRvbmUgYWZ0ZXIgY2xpY2tpbmcgdGhlICdjb21taXQnIGJ1dHRvbiBpbiB0aGUgZ2l0IHRhYjoKCmBgYHtyLCBlY2hvID0gRkFMU0UsIGZpZy5hbGlnbj0nY2VudGVyJ30KaW5jbHVkZV9ncmFwaGljcygiaW1hZ2VzLzEwLWNvbW1pdC5wbmciKQpgYGAKCgoKMS4gVGVsbCBgZ2l0YCB5b3Ugd2FudCBpdCB0byB0cmFjayB0aGUgY2hhbmdlcyBvbiBhIGZpbGUKMi4gTWFrZSBzb21lIGNoYW5nZXMKMy4gVGVsbCBgZ2l0YCB5b3Ugd2FudCB0byBpbmNsdWRlIHRoZXNlIGNoYW5nZXMgaW4gaXRzIHRyYWNraW5nCiAgICAtIGNsaWNrIHRoZSAnc3RhZ2VkJyBjaGVja2JveCBvbiB0aGUgZmlsZSBpbiB0aGUgZ2l0LWNvbW1pdCB3aW5kb3cKNC4gVGVsbCBgZ2l0YCB0byAnc25hcHNob3QnIHlvdXIgY2hhbmdlcyBhbmQgaW5jbHVkZSBhIG1lc3NhZ2UgYWJvdXQgdGhlbQogICAgLSB3cml0ZSBhIG1lc3NhZ2UgYW5kIGNsaWNrIGNvbW1pdCBpbiB0aGUgZ2l0IC0gY29tbWl0IHdpbmRvdwo1LiBnbyBiYWNrIHRvIHN0ZXAgMi4KCgoKCldoeSB3b3VsZCB5b3UgZG8gdGhpcyB3b3JrZmxvdz8gRm9yIHlvdXIgZnV0dXJlIHNlbGYuIEV2ZXJ5IHNuYXBzaG90IHlvdSB0YWtlIHdpdGggYGdpdGAgZ2l2ZXMgeW91IGEgcG9pbnQgaW4gdGltZSB0aGF0IHlvdSBjYW4gcm9sbCBiYWNrIHRvIGlmIHlvdSB3aXNoIC0gZnJvbSBhIHJlcHJvZHVjaWJpbGl0eSBwb2ludCBvZiB2aWV3IHRoaXMgbGV0cyB5b3UgcnVuIF9hbnlfIHZlcnNpb24gb2YgeW91ciBjb2RlIGF0IGEgc25hcHNob3QuIGBnaXRgIGNhbiBhbHNvIGxldCB5b3Ugc2VlIGV4YWN0bHkgd2hhdCBjaGFuZ2VzIHRoZXJlIHdlcmUgYmV0d2VlbiBzbmFwc2hvdHMgd2hpY2ggY2FuIGJlIGV4dHJlbWVseSBoZWxwZnVsIGZvciBkZWJ1Z2dpbmcKCmBnaXRgIGlzIGEgZmFpcmx5IGNvbXBsZXggcGllY2Ugb2Ygc29mdHdhcmUgYW5kIHByb3ZpZGVzIG1vcmUgZnVuY3Rpb25hbGl0eSB0aGFuIHRoaXMsIGJ1dCBmb3Igc3RhcnRpbmcgb3V0IHRoaXMgd29ya2Zsb3cgY292ZXJzIHRoZSBtYWluIG5lZWQgYW5kIHVzZSBjYXNlLgoKXAoKIyMgRmluYWxpc2UKCkNvbmdyYXR1bGF0aW9ucyEgWW91J3ZlIG1hZGUgaXQgdG8gdGhlIGVuZC1zdGFnZSBvZiB5b3VyIHByb2plY3Qgd2hlcmUgeW91J3JlIHJlYWR5IHRvIHdyYXAgdGhpbmdzIHVwIGFuZCBzaGFyZSB5b3VyIHByb2plY3Qgd2l0aCBvdGhlcnMuIFdoYXQgeW91IGRvIGF0IHRoaXMgc3RhZ2UgZW50aXJlbHkgZGVwZW5kcyBvbiB3aGF0IG91dHB1dCB5b3VyIHByb2plY3Qgd2FzIGZvci4gUGVyaGFwcyBpdCdzIHNlbmRpbmcgeW91ciBlbnRpcmUgcHJvamVjdCBkaXJlY3RvcnkgdG8geW91ciBsZWN0dXJlciBvciBzdXBlcnZpc29yLiBPciB0aGlzIGNvdWxkIGludm9sdmUgdXBsb2FkaW5nIHlvdXIgdmVyc2lvbiBjb250cm9sbGVkIGNvZGUgdG8gYW4gb25saW5lIGNvZGUgcmVwb3NpdG9yeSBzdWNoIGFzIFtodHRwczovL2dpdGh1Yi5jb21dKGh0dHBzOi8vZ2l0aHViLmNvbSkgYW5kIHB1Ymxpc2hpbmcgdGhlIHVybCBpbiB5b3VyIHBhcGVyIG9yIG90aGVyIG91dHB1dC4KClJlZ2FyZGxlc3MsIGVtYnJhY2UgdGhlIGNvbXBsZXRpb24uIFRoZW4gY29udGludWUgb24gdG8geW91ciBuZXh0IHByb2plY3QsIGJyaW5naW5nIHdpdGggeW91IHRoZSBza2lsbHMgeW91IGxlYXJudCBvbiB0aGlzIG9uZS4KClwKCiMjIFdoYXQncyBOZXh0CgpQbGVhc2UgZmlsbCBpbiB0aGUgZmVlZGJhY2sgZm9ybSBbaHR0cHM6Ly90aW55dXJsLmNvbS9yNHNzcC1tb2R1bGUtZmItczItMjNdKGh0dHBzOi8vdGlueXVybC5jb20vcjRzc3AtbW9kdWxlLWZiLXMyLTIzKS4gWW91ciBpbnB1dCBoZWxwcyB1cyBtYWtlIFI0U1NQIGJldHRlci4KClwKCiMjIEFwcGVuZGl4CgpBbiBleGFtcGxlIHdvcmtmbG93IHNldCB1cAoKYGBge3IsIGV2YWw9RkFMU0V9CiMgQ3JlYXRlIGFuZCBvcGVuIGEgbmV3IHByb2plY3QKdXNldGhpczo6Y3JlYXRlX3Byb2plY3QocGF0aCA9ICJ+L215cHJvamVjdCIpCgojIEluaXRpYWxpc2UgdmVyc2lvbiBjb250cm9sCnVzZXRoaXM6OnVzZV9naXQoKQoKIyBDcmVhdGUgdGhlIHByb2plY3Qgc3RydWN0dXJlCmRpci5jcmVhdGUoImRhdGEiKQpkaXIuY3JlYXRlKCJzY3JpcHRzIikKZGlyLmNyZWF0ZSgib3V0cHV0IikKZGlyLmNyZWF0ZSgiZG9jcyIpCgojIFRlbGwgZ2l0IHRvIGlnbm9yZSB0aGUgZGF0YSBkaXJlY3RvcnkgYnkgYWRkaW5nIGxpbmU6CiMgZGF0YS8KdXNldGhpczo6ZWRpdF9naXRfaWdub3JlKCkKCgojIEFkZCBhIFJFQURNRQp1c2V0aGlzOjp1c2VfcmVhZG1lX21kKCkKCiMgQWRkIE1JVCBMaWNlbnNlCnVzZXRoaXM6OnVzZV9taXRfbGljZW5zZShjb3B5cmlnaHRfaG9sZGVyID0gIkZpcnN0bmFtZSBMYXN0bmFtZSIpCmBgYAoKCgo=