Background
If you think about your typical R script within a project, you
probably have a series of calls to various functions (and subsequent
assignments of their output to object names) that follow a purposeful
path to an endpoint. Similar to how an article conveys scientific ideas
to others, a package allows us to distribute a specific workflow to
others.
For many of us, our first encounter with R packages is via those that
come bundled with the base installation of R and allow us access to
functions like mean()
and plot()
. In essence,
packages allow us to expand the functionality of base R while still
enforcing some standards (e.g., many of you will have experience with
the various functions in the {tidyverse}
collection).
Here is some common terminology with respect to R packages:
Package: An extension of the base R system with code,
data [optional], and documentation combined together in a standard
format (e.g., {MARSS}
).
Library: A directory/folder containing installed
packages (e.g., the location you would pass to the argument
lib
in the install.packages()
function).
Repository: A website providing packages for
installation (e.g., CRAN).
Source: The original version of a package with
human-readable text and code.
Binary: A compiled version of a package with
computer-readable text and code.
Base packages: Part of the R source tree, maintained by
R Core.
Recommended packages: Part of every R installation, but
not necessarily maintained by R Core.
Contributed packages: All of the remaining packages
contributed by the user community.
Functions
Functions form the basis for R packages. In general, an R function
has the following structure
function_name <- function(arguments) {
error checks
commands to execute
return(something)
}
So, for example, here is a simple function that adds 2 numbers
together and returns the result:
add <- function(x, y) {
## verify x & y are numbers
if(!is.numeric(x) | !is.numeric(y)) {
stop("`x` and `y` must be numbers")
}
## add the 2 numbers
z <- x + y
## return the result
return(z)
}
When building packages, we will also include some additional
information that describes what the function does and how it works. This
information will become part of the help documentation that is returned
when someone types ?function_name
.
Getting started
GitHub repository
Fortunately for us, there are variety of tools available to assist us
in developing and producing packages.
(You can skip the license for now.)
Create a new project in RStudio based upon this
repo.
Create package framework
Once upon a time you had to work through all of the steps to building
a package unassisted. Fortunately for us, the {devtools}
package will automate many of the steps.
You will need both the {devtools}
and
{usethis}
packages for this exercise.
At the R command prompt, load the {devtools}
package,
which will respond with a message about also loading the
{usethis}
package.
> library(devtools)
Loading required package: usethis
We’re now ready to create a framework for building our package.
Before doing so, however, we need to locate the folder/directory where
you created the pets
project.
At the R command prompt, find the location of the working
directory.
> getwd()
## [1] "/Users/mark/Documents/GitHub/FISH549/pets"
Copy the result (including the quotation marks), which you will need
for the next step.
Now execute the following command at at the R command prompt, where
pasted/folder/from/previous/step
is the result from the
getwd()
call above.
> create_package("pasted/folder/from/previous/step")
You should see R responding with a bunch of information about your
new package framework, followed by a prompt asking if you’d like to
overwrite the pre-existing file pets.Rproj
.
✓ Setting active project to '/Users/mark/Documents/GitHub/FISH549/pets'
✓ Creating 'R/'
✓ Writing 'DESCRIPTION'
Package: pets
Title: What the Package Does (One Line, Title Case)
Version: 0.0.0.9000
Authors@R (parsed):
* First Last <first.last@example.com> [aut, cre] (YOUR-ORCID-ID)
Description: What the package does (one paragraph).
License: `use_mit_license()`, `use_gpl3_license()` or friends to
pick a license
Encoding: UTF-8
LazyData: true
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.1.1
✓ Writing 'NAMESPACE'
Overwrite pre-existing file 'pets.Rproj'?
1: Definitely
2: Negative
3: Nope
Selection: 3
✓ Leaving 'pets.Rproj' unchanged
✓ Adding '^pets\\.Rproj$' to '.Rbuildignore'
✓ Adding '.Rproj.user' to '.gitignore'
✓ Adding '^\\.Rproj\\.user$' to '.Rbuildignore'
✓ Opening '/Users/mark/Documents/GitHub/FISH549/pets/' in new RStudio session
✓ Setting active project to '<no active project>'
Go ahead and select any of the options that look like
Nope
, No way
, Not now
, etc. (Note
that these options will vary each time you do this, so don’t worry if
yours don’t mirror the options below.)
After making your selection, RStudio will open a new
instance of your pets
project.
Directory structure
Wow, that’s a lot of information. What just happened here?
First, you should notice that several new files and a folder have
been added to your directory. These include:
.Rbuildignore
: a list of files that we’ll need to
have around, but that should be excluded when building the package from
source; at present this contains ^pets\.Rproj$
and
^\.Rproj\.user$
DESCRIPTION
: provides metadata about your package,
the contents of which were shown above when you ran
create_package()
NAMESPACE
: declares the functions your package
exports for external use and the external functions your package imports
from other packages
/R
: an empty folder where we’ll put our
.R
files that contain our function definitions
Files beginning with a .
are generally hidden from view.
If you cannot see any listed in the Files pane, click
on the drop-down menu with the gear icon (it might say “More” next to it
if your window is large enough). Select Show Hidden Files
at the bottom of the menu to display them.
Restart RStudio
At this point, go ahead and quit both instances of the
RStudio pets
project. Navigate to the
pets.Rproj
file in the folder/directory where you set up
the project initially, and double-click it to restart your project (or
just select your project from the drop-down menu in the upper
right).
After restarting RStudio, you will need to reload
{devtools}
.
> library(devtools)
Loading required package: usethis
Write a function
As mentioned above, the basis of R packages is functions. Let’s go
ahead and create a new function called cats()
.
Type use_r("cats)
to create a script within the
/R
directory called cats.R
where we can define
our new function.
> use_r("cats")
✔ Setting active project to '/Users/mark/Documents/GitHub/FISH549/pets'
• Modify 'R/cats.R'
• Call `use_test()` to create a matching test file
Later we’ll come back the advice to create a matching test file with
use_test()
.
Now we can write our function definition.
cats <- function(love = TRUE) {
if(love == TRUE) {
msg <- "I love cats!"
}
else {
msg <- "I am not a cat person."
}
return(print(msg))
}
Try our function
Now that we’ve defined a new function, it’s a good idea to try it
out. Although we could just highlight the code and execute it in the
normal R environment, there is a function load_all()
that
will help us better simulate the building, installing, and attaching our
new cats
package. As a package accumulates more functions,
load_all()
gives you a much more accurate sense of how the
package is developing than simply testing functions defined in the
global workspace. load_all()
also allows much faster
iteration than actually going through the process of building,
installing, and attaching the package.
Call load_all()
at the command prompt and the function
will respond that it’s loading the {pets}
package.
> load_all()
ℹ Loading pets
Go ahead and try out our new function.
> cats() # default argument is `love = TRUE`
[1] "I love cats!"
> cats(TRUE)
[1] "I love cats!"
> cats(FALSE)
[1] "I am not a cat person."
Commit our changes
This is a good time to go ahead and commit the files we created as
part of create_package()
and our definition of the
cats()
function. Make sure to give your commit(s) a short
but descriptive name(s).
Checking a function
At this point, we have reason to believe that cats()
works as expected, but we should really verify that all of the elements
of the entire pets
package indeed work. This may seem a bit
silly to check after such a small addition or change, but it’s good to
establish the habit of checking our work often.
The standard method for checking a package’s functionality is to run
the command R CMD check
in the Terminal.
However, we can make us of the check()
function in
{devtools}
to do so without leaving
RStudio.
check()
produces a lot of
output under the categories of Documenting
,
Building
, and Checking
.
Run check()
at the command prompt.
> check()
══ Documenting ═════════════════════════════════════════════════════════════
ℹ Updating pets documentation
ℹ Loading pets
══ Building ════════════════════════════════════════════════════════════════
Setting env vars:
• CFLAGS : -Wall -pedantic -fdiagnostics-color=always
• CXXFLAGS : -Wall -pedantic -fdiagnostics-color=always
• CXX11FLAGS: -Wall -pedantic -fdiagnostics-color=always
• CXX14FLAGS: -Wall -pedantic -fdiagnostics-color=always
• CXX17FLAGS: -Wall -pedantic -fdiagnostics-color=always
• CXX20FLAGS: -Wall -pedantic -fdiagnostics-color=always
✔ checking for file ‘/Users/mark/Documents/GitHub/FISH549/pets/DESCRIPTION’ ...
─ preparing ‘pets’:
✔ checking DESCRIPTION meta-information ...
─ checking for LF line-endings in source and make files and shell scripts
─ checking for empty or unneeded directories
Removed empty directory ‘pets/man’
─ building ‘pets_0.0.0.9000.tar.gz’
══ Checking ════════════════════════════════════════════════════════════════
Setting env vars:
• _R_CHECK_CRAN_INCOMING_REMOTE_: FALSE
• _R_CHECK_CRAN_INCOMING_ : FALSE
• _R_CHECK_FORCE_SUGGESTS_ : FALSE
• NOT_CRAN : true
── R CMD check ─────────────────────────────────────────────────────────────
─ using log directory ‘/private/var/folders/w6/bgxxqxln6nxf9z0wr7fypyfw0000gn/T/Rtmp3HNU44/pets.Rcheck’
─ using R version 4.2.2 (2022-10-31)
─ using platform: x86_64-apple-darwin17.0 (64-bit)
─ using session charset: UTF-8
─ using options ‘--no-manual --as-cran’
✔ checking for file ‘pets/DESCRIPTION’
─ this is package ‘pets’ version ‘0.0.0.9000’
─ package encoding: UTF-8
✔ checking package namespace information
✔ checking package dependencies (1.4s)
✔ checking if this is a source package ...
✔ checking if there is a namespace
✔ checking for executable files ...
✔ checking for hidden files and directories
✔ checking for portable file names
✔ checking for sufficient/correct file permissions
✔ checking serialization versions
✔ checking whether package ‘pets’ can be installed (1s)
✔ checking installed package size
✔ checking package directory
✔ checking for future file timestamps ...
W checking DESCRIPTION meta-information ...
Non-standard license specification:
`use_mit_license()`, `use_gpl3_license()` or friends to pick a
license
Standardizable: FALSE
✔ checking top-level files
✔ checking for left-over files
✔ checking index information ...
✔ checking package subdirectories ...
✔ checking R files for non-ASCII characters ...
✔ checking R files for syntax errors ...
✔ checking whether the package can be loaded ...
✔ checking whether the package can be loaded with stated dependencies ...
✔ checking whether the package can be unloaded cleanly ...
✔ checking whether the namespace can be loaded with stated dependencies ...
✔ checking whether the namespace can be unloaded cleanly ...
✔ checking loading without being on the library search path ...
✔ checking dependencies in R code ...
✔ checking S3 generic/method consistency (366ms)
✔ checking replacement functions ...
✔ checking foreign function calls ...
✔ checking R code for possible problems (1.9s)
✔ checking for missing documentation entries ...
─ checking examples ... NONE
✔ checking for non-standard things in the check directory
✔ checking for detritus in the temp directory
See
‘/private/var/folders/w6/bgxxqxln6nxf9z0wr7fypyfw0000gn/T/Rtmp3HNU44/pets.Rcheck/00check.log’
for details.
── R CMD check results ────────────────────────────────────────────────── pets 0.0.0.9000 ────
Duration: 7.2s
❯ checking DESCRIPTION meta-information ... WARNING
Non-standard license specification:
`use_mit_license()`, `use_gpl3_license()` or friends to pick a
license
Standardizable: FALSE
0 errors ✔ | 1 warning ✖ | 0 notes ✔
It is very important to read over all of this
information, as it will report the things that passed the check as well
as any warnings or errors encountered in the process.
Here we see that we have 0 errors, 1 warning, and 0 notes. The
warning says,
Non-standard license specification
which is OK for now, as we’ll address that later.
You can also run a package check via the Build pane
in RStudio.

Edit DESCRIPTION
file
The DESCRIPTION
file provides some metadata about a
package, including the package name, its title, author, etc. Your
DESCRIPTION
file should look something like this:
Package: pets
Title: What the Package Does (One Line, Title Case)
Version: 0.0.0.9000
Authors@R:
person("First", "Last", , "first.last@example.com", role = c("aut", "cre"),
comment = c(ORCID = "YOUR-ORCID-ID"))
Description: What the package does (one paragraph).
License: `use_mit_license()`, `use_gpl3_license()` or friends to pick a
license
Encoding: UTF-8
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.2.1
Let’s go ahead and make the following changes:
Change the package title to
Evaluates Your Feelings About Pets
.
The convention is to use Title Case for package titles.
Add your first and last names, and your email address. You can leave
the role
as is and delete the comment
field
asking about your ORCID
.
Write some descriptive text about the package in the
Description
field. For example,
Pets are awesome companions. Some people are fans of cats, others not so much.
When finished, your DESCRIPTION
file should look
something like this:
Package: pets
Title: Evaluates Your Feelings About Pets
Version: 0.0.0.9000
Authors@R:
person(given = "Mark",
family = "Scheuerell",
role = c("aut", "cre"),
email = "mark@uw.edu")
Description: Pets are awesome companions. Some people are fans of cats, others not so much.
License: `use_mit_license()`, `use_gpl3_license()` or friends to pick a
license
Encoding: UTF-8
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.2.1
Add a license
It’s best practice to add a license to our package so let’s go ahead
and do that (we’ll use the MIT license).
Use the helper function use_mit_license()
to create a
license and make sure to use your own name in the argument.
> use_mit_license("Mark Scheuerell")
✔ Setting License field in DESCRIPTION to 'MIT + file LICENSE'
✔ Writing 'LICENSE'
✔ Writing 'LICENSE.md'
✔ Adding '^LICENSE\\.md$' to '.Rbuildignore'
Open up the newly created LICENSE
file and confirm it
has the current year and your name.
YEAR: 2025
COPYRIGHT HOLDER: Mark Scheuerell
use_mit_license()
will also put a copy of the full
license in LICENSE.md
and add this file to
.Rbuildignore
.
Writing documentation
If you’re like Mark, you often rely on a function’s documentation to
help you understand the arguments to a function and the value(s) that
the function returns. This is typically done via a question mark
preceding the function name (e.g., ?print
). Writing this
documentation used to be a bit onerous, but now it’s easy to add
documentation to a package using the {roxygen2}
package. To
do so, we’ll add a special form of comment above our function definition
in cats.R
, which we’ll denote with a #'
.
Open the cats.R
script and make sure your cursor is at
the very top . From your RStudio menu, select
Code > Insert Roxygen Skeleton.
Your cats.R
file should now look like following.
#' Title
#'
#' @param love
#'
#' @return
#' @export
#'
#' @examples
cats <- function(love = TRUE) {
if(love == TRUE) {
msg <- "I love cats!"
}
else {
msg <- "I am not a cat person."
}
return(print(msg))
}
Let’s go over the different elements of the function’s documentation
skeleton that we just inserted.
Title
: A short descriptive phrase of what the
function does.
@param
: One or more arguments to the function (here
there is only one: love
) and its/their
description(s).
@return
: A description of what the function
returns.
@export
: Tells roxygen2
to add this
function to the NAMESPACE
file so it’s accessible to
users.
@examples
: One or more coded examples of how the
function is used.
Title
Replace Title
with something more descriptive like
Expresses your opinion about cats
.
#' Expresses your opinion about cats
#'
#' @param love
#'
#' @return
#' @export
#'
#' @examples
cats <- function(love = TRUE) {
if(love == TRUE) {
msg <- "I love cats!"
}
else {
msg <- "I am not a cat person."
}
return(print(msg))
}
Parameters
Our {roxygen}
skeleton already contains the one
parameter in our function love
, but we can go ahead and add
an explicit description of this argument. It’s often a good idea to also
include what, if any, the default argument is.
In the #' @param
field after love
, add
A logical argument indicating whether or not you love cats (default = `TRUE`)
.
#' Expresses your opinion about cats
#'
#' @param love A logical argument indicating whether or not you love cats (default = `TRUE`)
#'
#' @return
#' @export
#'
#' @examples
cats <- function(love = TRUE) {
if(love == TRUE) {
msg <- "I love cats!"
}
else {
msg <- "I am not a cat person."
}
return(print(msg))
}
Return
It’s good practice to tell the user what they should expect from a
function. This is admittedly a rather simple function, which is easy to
decipher, but other functions will not be nearly as transparent.
In the #' @return
field , add
One of two possible character strings (`"I love cats!"` or `"I am not a cat person."`)
.
#' Expresses your opinion about cats
#'
#' @param love A logical argument indicating whether or not you love cats (default = `TRUE`)
#'
#' @return One of two possible character strings (`"I love cats!"` or `"I am not a cat person."`).
#' @export
#'
#' @examples
cats <- function(love = TRUE) {
if(love == TRUE) {
msg <- "I love cats!"
}
else {
msg <- "I am not a cat person."
}
return(print(msg))
}
Export
You can leave this blank, as the default behavior is all we need
here.
Examples
This is an optional element of the documentation. If you include
@examples
without any actual code, you will get a warning
about @examples requires a value
. In this case, we can add
a really simple example:
Add cats(TRUE)
to the #' @examples
field.
#' Expresses your opinion about cats
#'
#' @param love A logical argument indicating whether or not you love cats (default = `TRUE`)
#'
#' @return One of two possible character strings (`"I love cats!"` or `"I am not a cat person."`).
#' @export
#'
#' @examples cats(TRUE)
cats <- function(love = TRUE) {
if(love == TRUE) {
msg <- "I love cats!"
}
else {
msg <- "I am not a cat person."
}
return(print(msg))
}
Make sure to save cats.R
after modifying the
{roxygen}
skeleton.
Assemble the documentation
Now that we’ve written the function’s documentation, we need to pass
it along to the cats.Rd
file in the help manual. To do so,
we can use the document()
function.
Run document()
at the command prompt to create the
function documentation.
> document()
Updating pets documentation
ℹ Loading pets
Writing NAMESPACE
Writing cats.Rd
There should be a new folder in your project directory called
/man
, which stands for “manual”. This is where the help
files live.
Open up the /man
folder and inspect the contents of
cats.Rd
. It should look like the following.
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/cats.R
\name{cats}
\alias{cats}
\title{Expresses your opinion about cats}
\usage{
cats(love = TRUE)
}
\arguments{
\item{`love`}{A logical argument indicating whether or not you love cats (default = \code{TRUE})}
}
\value{
One of two possible character strings (\code{"I love cats!"} or \code{"I am not a cat person."}).
}
\description{
Expresses your opinion about cats
}
\examples{
cats(TRUE)
}
Check that everything worked as planned by previewing our help file
with ?cats
.
> ?cats
ℹ Rendering development documentation for "cats"
Your help tab should look like this.

Examine NAMESPACE
file
When we called document()
above to convert the special
Roxygen comments in cats.R
into
man/cats.Rd
, it also updated the NAMESPACE
file based on the @export
line found in the
roxygen
comments.
Open up your NAMESPACE
file and verify that its contents
look like this.
# Generated by roxygen2: do not edit by hand
export(cats)
Check & install
Now is a good time to re-run our diagnostic checks.
Call check()
again, which should return no errors or
warnings.
> check()
══ Documenting ═════════════════════════════════════════════════════════════
ℹ Updating pets documentation
ℹ Loading pets
══ Building ════════════════════════════════════════════════════════════════
Setting env vars:
• CFLAGS : -Wall -pedantic -fdiagnostics-color=always
• CXXFLAGS : -Wall -pedantic -fdiagnostics-color=always
• CXX11FLAGS: -Wall -pedantic -fdiagnostics-color=always
• CXX14FLAGS: -Wall -pedantic -fdiagnostics-color=always
• CXX17FLAGS: -Wall -pedantic -fdiagnostics-color=always
• CXX20FLAGS: -Wall -pedantic -fdiagnostics-color=always
✔ checking for file ‘/Users/mark/Documents/GitHub/FISH549/pets/DESCRIPTION’ ...
─ preparing ‘pets’:
✔ checking DESCRIPTION meta-information ...
─ checking for LF line-endings in source and make files and shell scripts
─ checking for empty or unneeded directories
─ building ‘pets_0.0.0.9000.tar.gz’
══ Checking ════════════════════════════════════════════════════════════════
Setting env vars:
• _R_CHECK_CRAN_INCOMING_REMOTE_: FALSE
• _R_CHECK_CRAN_INCOMING_ : FALSE
• _R_CHECK_FORCE_SUGGESTS_ : FALSE
• NOT_CRAN : true
── R CMD check ─────────────────────────────────────────────────────────────
─ using log directory ‘/private/var/folders/w6/bgxxqxln6nxf9z0wr7fypyfw0000gn/T/Rtmp3HNU44/pets.Rcheck’
─ using R version 4.2.2 (2022-10-31)
─ using platform: x86_64-apple-darwin17.0 (64-bit)
─ using session charset: UTF-8
─ using options ‘--no-manual --as-cran’
✔ checking for file ‘pets/DESCRIPTION’
─ this is package ‘pets’ version ‘0.0.0.9000’
─ package encoding: UTF-8
✔ checking package namespace information
✔ checking package dependencies (3.3s)
✔ checking if this is a source package
✔ checking if there is a namespace
✔ checking for executable files ...
✔ checking for hidden files and directories
✔ checking for portable file names
✔ checking for sufficient/correct file permissions
✔ checking serialization versions
✔ checking whether package ‘pets’ can be installed (1s)
✔ checking installed package size
✔ checking package directory
✔ checking for future file timestamps ...
✔ checking DESCRIPTION meta-information ...
✔ checking top-level files ...
✔ checking for left-over files
✔ checking index information
✔ checking package subdirectories ...
✔ checking R files for non-ASCII characters ...
✔ checking R files for syntax errors ...
✔ checking whether the package can be loaded ...
✔ checking whether the package can be loaded with stated dependencies ...
✔ checking whether the package can be unloaded cleanly ...
✔ checking whether the namespace can be loaded with stated dependencies ...
✔ checking whether the namespace can be unloaded cleanly ...
✔ checking loading without being on the library search path ...
✔ checking dependencies in R code ...
✔ checking S3 generic/method consistency (371ms)
✔ checking replacement functions ...
✔ checking foreign function calls ...
✔ checking R code for possible problems (1.9s)
✔ checking Rd files ...
✔ checking Rd metadata ...
✔ checking Rd line widths ...
✔ checking Rd cross-references ...
✔ checking for missing documentation entries ...
✔ checking for code/documentation mismatches (403ms)
✔ checking Rd \usage sections (522ms)
✔ checking Rd contents ...
✔ checking for unstated dependencies in examples ...
✔ checking examples (547ms)
✔ checking for non-standard things in the check directory
✔ checking for detritus in the temp directory
── R CMD check results ─────────────────────────────────────────── pets 0.0.0.9000 ────
Duration: 11.3s
0 errors ✔ | 0 warnings ✔ | 0 notes ✔
Everything checks out now!
Install
Now that we’ve verified that our package builds correctly, let’s
install and try it out with the install()
function.
> install()
✔ checking for file ‘/Users/mark/Documents/GitHub/FISH549/pets/DESCRIPTION’ ...
─ preparing ‘pets’:
✔ checking DESCRIPTION meta-information ...
─ checking for LF line-endings in source and make files and shell scripts
─ checking for empty or unneeded directories
─ building ‘pets_0.0.0.9000.tar.gz’
Running /Library/Frameworks/R.framework/Resources/bin/R CMD INSTALL \
/var/folders/w6/bgxxqxln6nxf9z0wr7fypyfw0000gn/T//Rtmp3HNU44/pets_0.0.0.9000.tar.gz \
--install-tests
* installing to library ‘/Users/mark/R_libs’
* installing *source* package ‘pets’ ...
** using staged installation
** R
** byte-compile and prepare package for lazy loading
** help
*** installing help indices
** building package indices
** testing if installed package can be loaded from temporary location
** testing if installed package can be loaded from final location
** testing if installed package keeps a record of temporary installation path
* DONE (pets)
At this point you can run library(pets)
to load the
package and use the cats()
function.
> library(pets)
You can also install your package via the Build pane
in RStudio.

LS0tCnRpdGxlOiAiQ3JlYXRpbmcgUiBwYWNrYWdlcyIKc3VidGl0bGU6ICJQYXJ0IDEiCmRhdGU6ICI8YnI+MTkgRmVicnVhcnkgMjAyNSIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICB0aGVtZTogc3BhY2VsYWIKICAgIGhpZ2hsaWdodDogdGV4dG1hdGUKICAgIGNzczogLi4vbGVjdHVyZV9pbnN0LmNzcwogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIHRvY19kZXB0aDogMwotLS0KCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpCmBgYAoKKioqCgojIEJhY2tncm91bmQKCklmIHlvdSB0aGluayBhYm91dCB5b3VyIHR5cGljYWwgUiBzY3JpcHQgd2l0aGluIGEgcHJvamVjdCwgeW91IHByb2JhYmx5IGhhdmUgYSBzZXJpZXMgb2YgY2FsbHMgdG8gdmFyaW91cyBmdW5jdGlvbnMgKGFuZCBzdWJzZXF1ZW50IGFzc2lnbm1lbnRzIG9mIHRoZWlyIG91dHB1dCB0byBvYmplY3QgbmFtZXMpIHRoYXQgZm9sbG93IGEgcHVycG9zZWZ1bCBwYXRoIHRvIGFuIGVuZHBvaW50LiBTaW1pbGFyIHRvIGhvdyBhbiBhcnRpY2xlIGNvbnZleXMgc2NpZW50aWZpYyBpZGVhcyB0byBvdGhlcnMsIGEgcGFja2FnZSBhbGxvd3MgdXMgdG8gZGlzdHJpYnV0ZSBhIHNwZWNpZmljIHdvcmtmbG93IHRvIG90aGVycy4gCgpGb3IgbWFueSBvZiB1cywgb3VyIGZpcnN0IGVuY291bnRlciB3aXRoIFIgcGFja2FnZXMgaXMgdmlhIHRob3NlIHRoYXQgY29tZSBidW5kbGVkIHdpdGggdGhlIGJhc2UgaW5zdGFsbGF0aW9uIG9mIFIgYW5kIGFsbG93IHVzIGFjY2VzcyB0byBmdW5jdGlvbnMgbGlrZSBgbWVhbigpYCBhbmQgYHBsb3QoKWAuIEluIGVzc2VuY2UsIHBhY2thZ2VzIGFsbG93IHVzIHRvIGV4cGFuZCB0aGUgZnVuY3Rpb25hbGl0eSBvZiBiYXNlIFIgd2hpbGUgc3RpbGwgZW5mb3JjaW5nIHNvbWUgc3RhbmRhcmRzIChlLmcuLCBtYW55IG9mIHlvdSB3aWxsIGhhdmUgZXhwZXJpZW5jZSB3aXRoIHRoZSB2YXJpb3VzIGZ1bmN0aW9ucyBpbiB0aGUgYHt0aWR5dmVyc2V9YCBjb2xsZWN0aW9uKS4KCkhlcmUgaXMgc29tZSBjb21tb24gdGVybWlub2xvZ3kgd2l0aCByZXNwZWN0IHRvIFIgcGFja2FnZXM6CgoqICpQYWNrYWdlKjogQW4gZXh0ZW5zaW9uIG9mIHRoZSBiYXNlIFIgc3lzdGVtIHdpdGggY29kZSwgZGF0YSBbb3B0aW9uYWxdLCBhbmQgZG9jdW1lbnRhdGlvbiBjb21iaW5lZCB0b2dldGhlciBpbiBhIHN0YW5kYXJkIGZvcm1hdCAoZS5nLiwgW2B7TUFSU1N9YF0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL01BUlNTL2luZGV4Lmh0bWwpKS4KCiogKkxpYnJhcnkqOiBBIGRpcmVjdG9yeS9mb2xkZXIgY29udGFpbmluZyBpbnN0YWxsZWQgcGFja2FnZXMgKGUuZy4sIHRoZSBsb2NhdGlvbiB5b3Ugd291bGQgcGFzcyB0byB0aGUgYXJndW1lbnQgYGxpYmAgaW4gdGhlIGBpbnN0YWxsLnBhY2thZ2VzKClgIGZ1bmN0aW9uKS4KCiogKlJlcG9zaXRvcnkqOiBBIHdlYnNpdGUgcHJvdmlkaW5nIHBhY2thZ2VzIGZvciBpbnN0YWxsYXRpb24gKGUuZy4sIFtDUkFOXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvYXZhaWxhYmxlX3BhY2thZ2VzX2J5X25hbWUuaHRtbCkpLgoKKiAqU291cmNlKjogVGhlIG9yaWdpbmFsIHZlcnNpb24gb2YgYSBwYWNrYWdlIHdpdGggaHVtYW4tcmVhZGFibGUgdGV4dCBhbmQgY29kZS4KCiogKkJpbmFyeSo6IEEgY29tcGlsZWQgdmVyc2lvbiBvZiBhIHBhY2thZ2Ugd2l0aCBjb21wdXRlci1yZWFkYWJsZSB0ZXh0IGFuZCBjb2RlLgoKKiAqQmFzZSBwYWNrYWdlcyo6IFBhcnQgb2YgdGhlIFIgc291cmNlIHRyZWUsIG1haW50YWluZWQgYnkgKipSIENvcmUqKi4KCiogKlJlY29tbWVuZGVkIHBhY2thZ2VzKjogUGFydCBvZiBldmVyeSBSIGluc3RhbGxhdGlvbiwgYnV0IG5vdCBuZWNlc3NhcmlseSBtYWludGFpbmVkIGJ5ICoqUiBDb3JlKiouCgoqICpDb250cmlidXRlZCBwYWNrYWdlcyo6IEFsbCBvZiB0aGUgcmVtYWluaW5nIHBhY2thZ2VzIGNvbnRyaWJ1dGVkIGJ5IHRoZSB1c2VyIGNvbW11bml0eS4KCioqKgoKIyBGdW5jdGlvbnMKCkZ1bmN0aW9ucyBmb3JtIHRoZSBiYXNpcyBmb3IgUiBwYWNrYWdlcy4gSW4gZ2VuZXJhbCwgYW4gUiBmdW5jdGlvbiBoYXMgdGhlIGZvbGxvd2luZyBzdHJ1Y3R1cmUKCmBgYHtyIHBhY2thZ2VfbGF5b3V0LCBldmFsID0gRkFMU0V9CmZ1bmN0aW9uX25hbWUgPC0gZnVuY3Rpb24oYXJndW1lbnRzKSB7CiAgZXJyb3IgY2hlY2tzCiAgY29tbWFuZHMgdG8gZXhlY3V0ZQogIHJldHVybihzb21ldGhpbmcpCn0KYGBgCgpTbywgZm9yIGV4YW1wbGUsIGhlcmUgaXMgYSBzaW1wbGUgZnVuY3Rpb24gdGhhdCBhZGRzIDIgbnVtYmVycyB0b2dldGhlciBhbmQgcmV0dXJucyB0aGUgcmVzdWx0OgoKYGBge3IgZnVuY19hZGR9CmFkZCA8LSBmdW5jdGlvbih4LCB5KSB7CiAgIyMgdmVyaWZ5IHggJiB5IGFyZSBudW1iZXJzCiAgaWYoIWlzLm51bWVyaWMoeCkgfCAhaXMubnVtZXJpYyh5KSkgewogICAgc3RvcCgiYHhgIGFuZCBgeWAgbXVzdCBiZSBudW1iZXJzIikKICB9CiAgIyMgYWRkIHRoZSAyIG51bWJlcnMKICB6IDwtIHggKyB5CiAgIyMgcmV0dXJuIHRoZSByZXN1bHQKICByZXR1cm4oeikKfQpgYGAKCldoZW4gYnVpbGRpbmcgcGFja2FnZXMsIHdlIHdpbGwgYWxzbyBpbmNsdWRlIHNvbWUgYWRkaXRpb25hbCBpbmZvcm1hdGlvbiB0aGF0IGRlc2NyaWJlcyB3aGF0IHRoZSBmdW5jdGlvbiBkb2VzIGFuZCBob3cgaXQgd29ya3MuIFRoaXMgaW5mb3JtYXRpb24gd2lsbCBiZWNvbWUgcGFydCBvZiB0aGUgaGVscCBkb2N1bWVudGF0aW9uIHRoYXQgaXMgcmV0dXJuZWQgd2hlbiBzb21lb25lIHR5cGVzIGA/ZnVuY3Rpb25fbmFtZWAuCgoqKioKCiMgR2V0dGluZyBzdGFydGVkCgojIyBHaXRIdWIgcmVwb3NpdG9yeQoKRm9ydHVuYXRlbHkgZm9yIHVzLCB0aGVyZSBhcmUgdmFyaWV0eSBvZiB0b29scyBhdmFpbGFibGUgdG8gYXNzaXN0IHVzIGluIGRldmVsb3BpbmcgYW5kIHByb2R1Y2luZyBwYWNrYWdlcy4KCgo6OjogdGFzawoKKiBDcmVhdGUgYSBuZXcsIHB1YmxpYyByZXBvc2l0b3J5IG9uICoqR2l0SHViKiogY2FsbGVkIGBwZXRzYC4KCiogUG9wdWxhdGUgdGhlIHJlcG8gd2l0aAoKICAtIGEgYnJpZWYgYFJFQURNRS5tZGA7CgogIC0gYSBgLmdpdGlnbm9yZWAgZmlsZS4KCihZb3UgY2FuIHNraXAgdGhlIGxpY2Vuc2UgZm9yIG5vdy4pCgo6OjoKCjo6OiB0YXNrCgpDcmVhdGUgYSBuZXcgcHJvamVjdCBpbiAqKlJTdHVkaW8qKiBiYXNlZCB1cG9uIHRoaXMgcmVwby4KCjo6OgoKCioqKgoKIyBDcmVhdGUgcGFja2FnZSBmcmFtZXdvcmsKCk9uY2UgdXBvbiBhIHRpbWUgeW91IGhhZCB0byB3b3JrIHRocm91Z2ggYWxsIG9mIHRoZSBzdGVwcyB0byBidWlsZGluZyBhIHBhY2thZ2UgdW5hc3Npc3RlZC4gRm9ydHVuYXRlbHkgZm9yIHVzLCB0aGUgYHtkZXZ0b29sc31gIHBhY2thZ2Ugd2lsbCBhdXRvbWF0ZSBtYW55IG9mIHRoZSBzdGVwcy4KCjo6OiBub3RlCgpZb3Ugd2lsbCBuZWVkIGJvdGggdGhlIGB7ZGV2dG9vbHN9YCBhbmQgYHt1c2V0aGlzfWAgcGFja2FnZXMgZm9yIHRoaXMgZXhlcmNpc2UuCgo6OjoKCjo6OiB0YXNrCgpBdCB0aGUgUiBjb21tYW5kIHByb21wdCwgbG9hZCB0aGUgYHtkZXZ0b29sc31gIHBhY2thZ2UsIHdoaWNoIHdpbGwgcmVzcG9uZCB3aXRoIGEgbWVzc2FnZSBhYm91dCBhbHNvIGxvYWRpbmcgdGhlIGB7dXNldGhpc31gIHBhY2thZ2UuCgo6OjoKCmBgYHtyLCBldmFsID0gRkFMU0V9Cj4gbGlicmFyeShkZXZ0b29scykKTG9hZGluZyByZXF1aXJlZCBwYWNrYWdlOiB1c2V0aGlzCmBgYAoKV2UncmUgbm93IHJlYWR5IHRvIGNyZWF0ZSBhIGZyYW1ld29yayBmb3IgYnVpbGRpbmcgb3VyIHBhY2thZ2UuIEJlZm9yZSBkb2luZyBzbywgaG93ZXZlciwgd2UgbmVlZCB0byBsb2NhdGUgdGhlIGZvbGRlci9kaXJlY3Rvcnkgd2hlcmUgeW91IGNyZWF0ZWQgdGhlIGBwZXRzYCBwcm9qZWN0LgoKOjo6IHRhc2sKCkF0IHRoZSBSIGNvbW1hbmQgcHJvbXB0LCBmaW5kIHRoZSBsb2NhdGlvbiBvZiB0aGUgd29ya2luZyBkaXJlY3RvcnkuCgo6OjoKCmBgYHtyIGdldHdkLCBldmFsID0gRkFMU0V9Cj4gZ2V0d2QoKQpgYGAKCmBgYAojIyBbMV0gIi9Vc2Vycy9tYXJrL0RvY3VtZW50cy9HaXRIdWIvRklTSDU0OS9wZXRzIgpgYGAKCjo6OiB0YXNrCgpDb3B5IHRoZSByZXN1bHQgKGluY2x1ZGluZyB0aGUgcXVvdGF0aW9uIG1hcmtzKSwgd2hpY2ggeW91IHdpbGwgbmVlZCBmb3IgdGhlIG5leHQgc3RlcC4KCjo6OgoKOjo6IHRhc2sKCk5vdyBleGVjdXRlIHRoZSBmb2xsb3dpbmcgY29tbWFuZCBhdCBhdCB0aGUgUiBjb21tYW5kIHByb21wdCwgd2hlcmUgYHBhc3RlZC9mb2xkZXIvZnJvbS9wcmV2aW91cy9zdGVwYCBpcyB0aGUgcmVzdWx0IGZyb20gdGhlIGBnZXR3ZCgpYCBjYWxsIGFib3ZlLgoKOjo6CgpgYGB7ciBjcmVhdGVfcGtnLCBldmFsID0gRkFMU0V9Cj4gY3JlYXRlX3BhY2thZ2UoInBhc3RlZC9mb2xkZXIvZnJvbS9wcmV2aW91cy9zdGVwIikKYGBgCgpZb3Ugc2hvdWxkIHNlZSBSIHJlc3BvbmRpbmcgd2l0aCBhIGJ1bmNoIG9mIGluZm9ybWF0aW9uIGFib3V0IHlvdXIgbmV3IHBhY2thZ2UgZnJhbWV3b3JrLCBmb2xsb3dlZCBieSBhIHByb21wdCBhc2tpbmcgaWYgeW91J2QgbGlrZSB0byBvdmVyd3JpdGUgdGhlIHByZS1leGlzdGluZyBmaWxlIGBwZXRzLlJwcm9qYC4KCmBgYHtyIGNyZWF0ZV9wa2dfcmVzdWx0cywgZXZhbCA9IEZBTFNFfQrinJMgU2V0dGluZyBhY3RpdmUgcHJvamVjdCB0byAnL1VzZXJzL21hcmsvRG9jdW1lbnRzL0dpdEh1Yi9GSVNINTQ5L3BldHMnCuKckyBDcmVhdGluZyAnUi8nCuKckyBXcml0aW5nICdERVNDUklQVElPTicKUGFja2FnZTogcGV0cwpUaXRsZTogV2hhdCB0aGUgUGFja2FnZSBEb2VzIChPbmUgTGluZSwgVGl0bGUgQ2FzZSkKVmVyc2lvbjogMC4wLjAuOTAwMApBdXRob3JzQFIgKHBhcnNlZCk6CiAgICAqIEZpcnN0IExhc3QgPGZpcnN0Lmxhc3RAZXhhbXBsZS5jb20+IFthdXQsIGNyZV0gKFlPVVItT1JDSUQtSUQpCkRlc2NyaXB0aW9uOiBXaGF0IHRoZSBwYWNrYWdlIGRvZXMgKG9uZSBwYXJhZ3JhcGgpLgpMaWNlbnNlOiBgdXNlX21pdF9saWNlbnNlKClgLCBgdXNlX2dwbDNfbGljZW5zZSgpYCBvciBmcmllbmRzIHRvCiAgICBwaWNrIGEgbGljZW5zZQpFbmNvZGluZzogVVRGLTgKTGF6eURhdGE6IHRydWUKUm94eWdlbjogbGlzdChtYXJrZG93biA9IFRSVUUpClJveHlnZW5Ob3RlOiA3LjEuMQrinJMgV3JpdGluZyAnTkFNRVNQQUNFJwpPdmVyd3JpdGUgcHJlLWV4aXN0aW5nIGZpbGUgJ3BldHMuUnByb2onPwoKMTogRGVmaW5pdGVseQoyOiBOZWdhdGl2ZQozOiBOb3BlCgpTZWxlY3Rpb246IDMK4pyTIExlYXZpbmcgJ3BldHMuUnByb2onIHVuY2hhbmdlZArinJMgQWRkaW5nICdecGV0c1xcLlJwcm9qJCcgdG8gJy5SYnVpbGRpZ25vcmUnCuKckyBBZGRpbmcgJy5ScHJvai51c2VyJyB0byAnLmdpdGlnbm9yZScK4pyTIEFkZGluZyAnXlxcLlJwcm9qXFwudXNlciQnIHRvICcuUmJ1aWxkaWdub3JlJwrinJMgT3BlbmluZyAnL1VzZXJzL21hcmsvRG9jdW1lbnRzL0dpdEh1Yi9GSVNINTQ5L3BldHMvJyBpbiBuZXcgUlN0dWRpbyBzZXNzaW9uCuKckyBTZXR0aW5nIGFjdGl2ZSBwcm9qZWN0IHRvICc8bm8gYWN0aXZlIHByb2plY3Q+JwpgYGAKCjo6OiB0YXNrCgpHbyBhaGVhZCBhbmQgc2VsZWN0IGFueSBvZiB0aGUgb3B0aW9ucyB0aGF0IGxvb2sgbGlrZSBgTm9wZWAsIGBObyB3YXlgLCBgTm90IG5vd2AsIGV0Yy4gKE5vdGUgdGhhdCB0aGVzZSBvcHRpb25zIHdpbGwgdmFyeSBlYWNoIHRpbWUgeW91IGRvIHRoaXMsIHNvIGRvbid0IHdvcnJ5IGlmIHlvdXJzIGRvbid0IG1pcnJvciB0aGUgb3B0aW9ucyBiZWxvdy4pCgo6OjoKCjo6OiBub3RlCgpBZnRlciBtYWtpbmcgeW91ciBzZWxlY3Rpb24sICoqUlN0dWRpbyoqIHdpbGwgb3BlbiBhIG5ldyBpbnN0YW5jZSBvZiB5b3VyIGBwZXRzYCBwcm9qZWN0LgoKOjo6CgojIyBEaXJlY3Rvcnkgc3RydWN0dXJlCgpXb3csIHRoYXQncyBhIGxvdCBvZiBpbmZvcm1hdGlvbi4gV2hhdCBqdXN0IGhhcHBlbmVkIGhlcmU/CgpGaXJzdCwgeW91IHNob3VsZCBub3RpY2UgdGhhdCBzZXZlcmFsIG5ldyBmaWxlcyBhbmQgYSBmb2xkZXIgaGF2ZSBiZWVuIGFkZGVkIHRvIHlvdXIgZGlyZWN0b3J5LiBUaGVzZSBpbmNsdWRlOgoKKiBgLlJidWlsZGlnbm9yZWA6IGEgbGlzdCBvZiBmaWxlcyB0aGF0IHdlJ2xsIG5lZWQgdG8gaGF2ZSBhcm91bmQsIGJ1dCB0aGF0IHNob3VsZCBiZSBleGNsdWRlZCB3aGVuIGJ1aWxkaW5nIHRoZSBwYWNrYWdlIGZyb20gc291cmNlOyBhdCBwcmVzZW50IHRoaXMgY29udGFpbnMgYF5wZXRzXC5ScHJvaiRgIGFuZCBgXlwuUnByb2pcLnVzZXIkYAoKKiBgREVTQ1JJUFRJT05gOiBwcm92aWRlcyBtZXRhZGF0YSBhYm91dCB5b3VyIHBhY2thZ2UsIHRoZSBjb250ZW50cyBvZiB3aGljaCB3ZXJlIHNob3duIGFib3ZlIHdoZW4geW91IHJhbiBgY3JlYXRlX3BhY2thZ2UoKWAKCiogYE5BTUVTUEFDRWA6IGRlY2xhcmVzIHRoZSBmdW5jdGlvbnMgeW91ciBwYWNrYWdlIGV4cG9ydHMgZm9yIGV4dGVybmFsIHVzZSBhbmQgdGhlIGV4dGVybmFsIGZ1bmN0aW9ucyB5b3VyIHBhY2thZ2UgaW1wb3J0cyBmcm9tIG90aGVyIHBhY2thZ2VzCgoqIGAvUmA6IGFuIGVtcHR5IGZvbGRlciB3aGVyZSB3ZSdsbCBwdXQgb3VyIGAuUmAgZmlsZXMgdGhhdCBjb250YWluIG91ciBmdW5jdGlvbiBkZWZpbml0aW9ucwoKOjo6IHRpcAoKRmlsZXMgYmVnaW5uaW5nIHdpdGggYSBgLmAgYXJlIGdlbmVyYWxseSBoaWRkZW4gZnJvbSB2aWV3LiBJZiB5b3UgY2Fubm90IHNlZSBhbnkgbGlzdGVkIGluIHRoZSAqKkZpbGVzKiogcGFuZSwgY2xpY2sgb24gdGhlIGRyb3AtZG93biBtZW51IHdpdGggdGhlIGdlYXIgaWNvbiAoaXQgbWlnaHQgc2F5ICJNb3JlIiBuZXh0IHRvIGl0IGlmIHlvdXIgd2luZG93IGlzIGxhcmdlIGVub3VnaCkuIFNlbGVjdCBgU2hvdyBIaWRkZW4gRmlsZXNgIGF0IHRoZSBib3R0b20gb2YgdGhlIG1lbnUgdG8gZGlzcGxheSB0aGVtLgoKOjo6CgojIyBSZXN0YXJ0IFJTdHVkaW8KCkF0IHRoaXMgcG9pbnQsIGdvIGFoZWFkIGFuZCBxdWl0IGJvdGggaW5zdGFuY2VzIG9mIHRoZSAqKlJTdHVkaW8qKiBgcGV0c2AgcHJvamVjdC4gTmF2aWdhdGUgdG8gdGhlIGBwZXRzLlJwcm9qYCBmaWxlIGluIHRoZSBmb2xkZXIvZGlyZWN0b3J5IHdoZXJlIHlvdSBzZXQgdXAgdGhlIHByb2plY3QgaW5pdGlhbGx5LCBhbmQgZG91YmxlLWNsaWNrIGl0IHRvIHJlc3RhcnQgeW91ciBwcm9qZWN0IChvciBqdXN0IHNlbGVjdCB5b3VyIHByb2plY3QgZnJvbSB0aGUgZHJvcC1kb3duIG1lbnUgaW4gdGhlIHVwcGVyIHJpZ2h0KS4KCjo6OiB0YXNrCgpBZnRlciByZXN0YXJ0aW5nICoqUlN0dWRpbyoqLCB5b3Ugd2lsbCBuZWVkIHRvIHJlbG9hZCBge2RldnRvb2xzfWAuCgo6OjoKCmBgYHtyIHJlbG9hZF9kZXZ0b29scywgZXZhbCA9IEZBTFNFfQo+IGxpYnJhcnkoZGV2dG9vbHMpCkxvYWRpbmcgcmVxdWlyZWQgcGFja2FnZTogdXNldGhpcwpgYGAKCioqKgoKIyBXcml0ZSBhIGZ1bmN0aW9uCgpBcyBtZW50aW9uZWQgYWJvdmUsIHRoZSBiYXNpcyBvZiBSIHBhY2thZ2VzIGlzIGZ1bmN0aW9ucy4gTGV0J3MgZ28gYWhlYWQgYW5kIGNyZWF0ZSBhIG5ldyBmdW5jdGlvbiBjYWxsZWQgYGNhdHMoKWAuCgo6OjogdGFzawoKVHlwZSBgdXNlX3IoImNhdHMpYCB0byBjcmVhdGUgYSBzY3JpcHQgd2l0aGluIHRoZSBgL1JgIGRpcmVjdG9yeSBjYWxsZWQgYGNhdHMuUmAgd2hlcmUgd2UgY2FuIGRlZmluZSBvdXIgbmV3IGZ1bmN0aW9uLgoKOjo6CgpgYGB7ciB1c2VfciwgZXZhbCA9IEZBTFNFfQo+IHVzZV9yKCJjYXRzIikK4pyUIFNldHRpbmcgYWN0aXZlIHByb2plY3QgdG8gJy9Vc2Vycy9tYXJrL0RvY3VtZW50cy9HaXRIdWIvRklTSDU0OS9wZXRzJwrigKIgTW9kaWZ5ICdSL2NhdHMuUicK4oCiIENhbGwgYHVzZV90ZXN0KClgIHRvIGNyZWF0ZSBhIG1hdGNoaW5nIHRlc3QgZmlsZQpgYGAKCjo6OiBub3RlCgpMYXRlciB3ZSdsbCBjb21lIGJhY2sgdGhlIGFkdmljZSB0byBjcmVhdGUgYSBtYXRjaGluZyB0ZXN0IGZpbGUgd2l0aCBgdXNlX3Rlc3QoKWAuCgo6OjoKCk5vdyB3ZSBjYW4gd3JpdGUgb3VyIGZ1bmN0aW9uIGRlZmluaXRpb24uIAoKOjo6IHRhc2sKCiogQ29weS9wYXN0ZSB0aGUgZm9sbG93aW5nIGNvZGUgaW50byB0aGUgYGNhdHMuUmAgZmlsZS4KCiogV2hlbiB5b3UgYXJlIGZpbmlzaGVkLCBzYXZlIHRoZSBmaWxlLgoKOjo6CgpgYGB7ciBkZWZpbmVfY2F0cywgZXZhbCA9IEZBTFNFfQpjYXRzIDwtIGZ1bmN0aW9uKGxvdmUgPSBUUlVFKSB7CiAgaWYobG92ZSA9PSBUUlVFKSB7CiAgICBtc2cgPC0gIkkgbG92ZSBjYXRzISIKICB9CiAgZWxzZSB7CiAgICBtc2cgPC0gIkkgYW0gbm90IGEgY2F0IHBlcnNvbi4iCiAgfQogIHJldHVybihwcmludChtc2cpKQp9CmBgYAoKIyMgVHJ5IG91ciBmdW5jdGlvbgoKTm93IHRoYXQgd2UndmUgZGVmaW5lZCBhIG5ldyBmdW5jdGlvbiwgaXQncyBhIGdvb2QgaWRlYSB0byB0cnkgaXQgb3V0LiBBbHRob3VnaCB3ZSBjb3VsZCBqdXN0IGhpZ2hsaWdodCB0aGUgY29kZSBhbmQgZXhlY3V0ZSBpdCBpbiB0aGUgbm9ybWFsIFIgZW52aXJvbm1lbnQsIHRoZXJlIGlzIGEgZnVuY3Rpb24gYGxvYWRfYWxsKClgIHRoYXQgd2lsbCBoZWxwIHVzIGJldHRlciBzaW11bGF0ZSB0aGUgYnVpbGRpbmcsIGluc3RhbGxpbmcsIGFuZCBhdHRhY2hpbmcgb3VyIG5ldyBgY2F0c2AgcGFja2FnZS4gQXMgYSBwYWNrYWdlIGFjY3VtdWxhdGVzIG1vcmUgZnVuY3Rpb25zLCBgbG9hZF9hbGwoKWAgZ2l2ZXMgeW91IGEgbXVjaCBtb3JlIGFjY3VyYXRlIHNlbnNlIG9mIGhvdyB0aGUgcGFja2FnZSBpcyBkZXZlbG9waW5nIHRoYW4gc2ltcGx5IHRlc3RpbmcgZnVuY3Rpb25zIGRlZmluZWQgaW4gdGhlIGdsb2JhbCB3b3Jrc3BhY2UuIGBsb2FkX2FsbCgpYCBhbHNvIGFsbG93cyBtdWNoIGZhc3RlciBpdGVyYXRpb24gdGhhbiBhY3R1YWxseSBnb2luZyB0aHJvdWdoIHRoZSBwcm9jZXNzIG9mIGJ1aWxkaW5nLCBpbnN0YWxsaW5nLCBhbmQgYXR0YWNoaW5nIHRoZSBwYWNrYWdlLgoKOjo6IHRhc2sKCkNhbGwgYGxvYWRfYWxsKClgIGF0IHRoZSBjb21tYW5kIHByb21wdCBhbmQgdGhlIGZ1bmN0aW9uIHdpbGwgcmVzcG9uZCB0aGF0IGl0J3MgbG9hZGluZyB0aGUgYHtwZXRzfWAgcGFja2FnZS4KCjo6OgoKYGBge3IgbG9hZF9hbGwsIGV2YWwgPSBGQUxTRX0KPiBsb2FkX2FsbCgpCuKEuSBMb2FkaW5nIHBldHMKYGBgCgo6OjogdGFzawoKR28gYWhlYWQgYW5kIHRyeSBvdXQgb3VyIG5ldyBmdW5jdGlvbi4KCjo6OgoKYGBge3IgZGVmaW5lX2NhdHNfMiwgZWNobyA9IEZBTFNFLCBldmFsID0gRkFMU0V9CmNhdHMgPC0gZnVuY3Rpb24obG92ZSA9IFRSVUUpIHsKICBpZihsb3ZlID09IFRSVUUpIHsKICAgIG1zZyA8LSAiSSBsb3ZlIGNhdHMhIgogIH0KICBlbHNlIHsKICAgIG1zZyA8LSAiSSBhbSBub3QgYSBjYXQgcGVyc29uLiIKICB9CiAgcmV0dXJuKHByaW50KG1zZykpCn0KYGBgCgpgYGB7ciB0cnlfY2F0cywgZWNobyA9IEZBTFNFLCBldmFsID0gRkFMU0V9CmNhdHMoVFJVRSkKY2F0cyhGQUxTRSkKY2F0cygxKQpjYXRzKCJhIikKYGBgCgpgYGB7ciBjYXRzX3Rlc3RfMSwgZXZhbCA9IEZBTFNFfQo+IGNhdHMoKSAgIyBkZWZhdWx0IGFyZ3VtZW50IGlzIGBsb3ZlID0gVFJVRWAKWzFdICJJIGxvdmUgY2F0cyEiCj4gY2F0cyhUUlVFKQpbMV0gIkkgbG92ZSBjYXRzISIKPiBjYXRzKEZBTFNFKQpbMV0gIkkgYW0gbm90IGEgY2F0IHBlcnNvbi4iCmBgYAoKOjo6IHN1Y2Nlc3MKCk91ciBmdW5jdGlvbiB3b3JrcyEKCjo6OgoKIyMgSW5mb3JtYWwgdGVzdGluZwoKV2Ugd2lsbCBzZXQgdXAgc29tZSBtb3JlIGZvcm1hbCBmdW5jdGlvbiB0ZXN0aW5nIGxhdGVyLCBidXQgbGV0J3Mgc2VlIHdoYXQgaGFwcGVucyB3aGVuIHdlIGRvbid0IHVzZSB0aGUgZnVuY3Rpb24gYXMgaXQgd2FzIGludGVuZGVkLgoKYGBge3IgY2F0c190ZXN0XzIsIGV2YWwgPSBGQUxTRX0KPiBjYXRzKDEpClsxXSAiSSBsb3ZlIGNhdHMhIgo+IGNhdHMoMikKWzFdICJJIGFtIG5vdCBhIGNhdCBwZXJzb24uIgo+IGNhdHMoIm1laCIpClsxXSAiSSBhbSBub3QgYSBjYXQgcGVyc29uLiIKYGBgCgpXaGF0IGhhcHBlbmVkIGhlcmU/IFdoeSBkaWRuJ3QgUiB0aHJvdyBhbiBlcnJvciBvciB3YXJuaW5nIHdoZW4gd2UgZGlkbid0IGluY2x1ZGUgYSBsb2dpY2FsIGFyZ3VtZW50IG9mIGBUUlVFYCBvciBgRkFMU0VgPwoKKiBJbiB0aGUgZmlyc3QgY2FzZSwgYDFgIGlzIGVxdWl2YWxlbnQgdG8gYFRSVUVgIGluIFIsIHNvIGl0IHJldHVybnMgdGhlIHJlc3VsdCBhcyBpZiBgY2F0cyhUUlVFKWAuCgoqIEluIHRoZSBzZWNvbmQgYW5kIHRoaXJkIGNhc2VzLCBvdXIgZnVuY3Rpb24gZGVmaW5pdGlvbiBvbmx5IGludm9sdmVzIGEgY2hlY2sgd2hldGhlciB0aGUgYXJndW1lbnQgaXMgYFRSVUVgLiBJZiBub3QsIHRoZSBkZWZhdWx0IGJlaGF2aW9yIGlzIHRvIHJldHVybiB0aGUgcmVzdWx0IGAiSSBhbSBub3QgYSBjYXQgcGVyc29uLiJgCgpUaGVzZSB0ZXN0cyBzdWdnZXN0IHRoYXQgYWx0aG91Z2ggb3VyIGZ1bmN0aW9uIHdvcmtzIGFzIGV4cGVjdGVkLCB3ZSBtaWdodCB3YW50IHRvIGFkZCBzb21lIGFkZGl0aW9uYWwgY2hlY2tzIG9uIHRoZSBpbnB1dCBhcmd1bWVudC4KCiMjIENvbW1pdCBvdXIgY2hhbmdlcwoKVGhpcyBpcyBhIGdvb2QgdGltZSB0byBnbyBhaGVhZCBhbmQgY29tbWl0IHRoZSBmaWxlcyB3ZSBjcmVhdGVkIGFzIHBhcnQgb2YgYGNyZWF0ZV9wYWNrYWdlKClgIGFuZCBvdXIgZGVmaW5pdGlvbiBvZiB0aGUgYGNhdHMoKWAgZnVuY3Rpb24uIE1ha2Ugc3VyZSB0byBnaXZlIHlvdXIgY29tbWl0KHMpIGEgc2hvcnQgYnV0IGRlc2NyaXB0aXZlIG5hbWUocykuCgoqKioKCiMgQ2hlY2tpbmcgYSBmdW5jdGlvbgoKQXQgdGhpcyBwb2ludCwgd2UgaGF2ZSByZWFzb24gdG8gYmVsaWV2ZSB0aGF0IGBjYXRzKClgIHdvcmtzIGFzIGV4cGVjdGVkLCBidXQgd2Ugc2hvdWxkIHJlYWxseSB2ZXJpZnkgdGhhdCBhbGwgb2YgdGhlIGVsZW1lbnRzIG9mIHRoZSBlbnRpcmUgYHBldHNgIHBhY2thZ2UgaW5kZWVkIHdvcmsuIFRoaXMgbWF5IHNlZW0gYSBiaXQgc2lsbHkgdG8gY2hlY2sgYWZ0ZXIgc3VjaCBhIHNtYWxsIGFkZGl0aW9uIG9yIGNoYW5nZSwgYnV0IGl0J3MgZ29vZCB0byBlc3RhYmxpc2ggdGhlIGhhYml0IG9mIGNoZWNraW5nIG91ciB3b3JrIG9mdGVuLgoKVGhlIHN0YW5kYXJkIG1ldGhvZCBmb3IgY2hlY2tpbmcgYSBwYWNrYWdlJ3MgZnVuY3Rpb25hbGl0eSBpcyB0byBydW4gdGhlIGNvbW1hbmQgYFIgQ01EIGNoZWNrYCBpbiB0aGUgKipUZXJtaW5hbCoqLiBIb3dldmVyLCB3ZSBjYW4gbWFrZSB1cyBvZiB0aGUgYGNoZWNrKClgIGZ1bmN0aW9uIGluIGB7ZGV2dG9vbHN9YCB0byBkbyBzbyB3aXRob3V0IGxlYXZpbmcgKipSU3R1ZGlvKiouIAoKOjo6IG5vdGUKCmBjaGVjaygpYCBwcm9kdWNlcyAqKiphIGxvdCoqKiBvZiBvdXRwdXQgdW5kZXIgdGhlIGNhdGVnb3JpZXMgb2YgYERvY3VtZW50aW5nYCwgYEJ1aWxkaW5nYCwgYW5kIGBDaGVja2luZ2AuCgo6OjoKCjo6OiB0YXNrCgpSdW4gYGNoZWNrKClgIGF0IHRoZSBjb21tYW5kIHByb21wdC4KCjo6OgoKYGBge3IgcnVuX2NoZWNrLCBldmFsID0gRkFMU0V9Cj4gY2hlY2soKQrilZDilZAgRG9jdW1lbnRpbmcg4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQCuKEuSBVcGRhdGluZyBwZXRzIGRvY3VtZW50YXRpb24K4oS5IExvYWRpbmcgcGV0cwoK4pWQ4pWQIEJ1aWxkaW5nIOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkOKVkApTZXR0aW5nIGVudiB2YXJzOgrigKIgQ0ZMQUdTICAgIDogLVdhbGwgLXBlZGFudGljIC1mZGlhZ25vc3RpY3MtY29sb3I9YWx3YXlzCuKAoiBDWFhGTEFHUyAgOiAtV2FsbCAtcGVkYW50aWMgLWZkaWFnbm9zdGljcy1jb2xvcj1hbHdheXMK4oCiIENYWDExRkxBR1M6IC1XYWxsIC1wZWRhbnRpYyAtZmRpYWdub3N0aWNzLWNvbG9yPWFsd2F5cwrigKIgQ1hYMTRGTEFHUzogLVdhbGwgLXBlZGFudGljIC1mZGlhZ25vc3RpY3MtY29sb3I9YWx3YXlzCuKAoiBDWFgxN0ZMQUdTOiAtV2FsbCAtcGVkYW50aWMgLWZkaWFnbm9zdGljcy1jb2xvcj1hbHdheXMK4oCiIENYWDIwRkxBR1M6IC1XYWxsIC1wZWRhbnRpYyAtZmRpYWdub3N0aWNzLWNvbG9yPWFsd2F5cwrinJQgIGNoZWNraW5nIGZvciBmaWxlIOKAmC9Vc2Vycy9tYXJrL0RvY3VtZW50cy9HaXRIdWIvRklTSDU0OS9wZXRzL0RFU0NSSVBUSU9O4oCZIC4uLgrilIAgIHByZXBhcmluZyDigJhwZXRz4oCZOgrinJQgIGNoZWNraW5nIERFU0NSSVBUSU9OIG1ldGEtaW5mb3JtYXRpb24gLi4uCuKUgCAgY2hlY2tpbmcgZm9yIExGIGxpbmUtZW5kaW5ncyBpbiBzb3VyY2UgYW5kIG1ha2UgZmlsZXMgYW5kIHNoZWxsIHNjcmlwdHMK4pSAICBjaGVja2luZyBmb3IgZW1wdHkgb3IgdW5uZWVkZWQgZGlyZWN0b3JpZXMKICAgUmVtb3ZlZCBlbXB0eSBkaXJlY3Rvcnkg4oCYcGV0cy9tYW7igJkK4pSAICBidWlsZGluZyDigJhwZXRzXzAuMC4wLjkwMDAudGFyLmd64oCZCiAgIArilZDilZAgQ2hlY2tpbmcg4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQClNldHRpbmcgZW52IHZhcnM6CuKAoiBfUl9DSEVDS19DUkFOX0lOQ09NSU5HX1JFTU9URV86IEZBTFNFCuKAoiBfUl9DSEVDS19DUkFOX0lOQ09NSU5HXyAgICAgICA6IEZBTFNFCuKAoiBfUl9DSEVDS19GT1JDRV9TVUdHRVNUU18gICAgICA6IEZBTFNFCuKAoiBOT1RfQ1JBTiAgICAgICAgICAgICAgICAgICAgICA6IHRydWUK4pSA4pSAIFIgQ01EIGNoZWNrIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgArilIAgIHVzaW5nIGxvZyBkaXJlY3Rvcnkg4oCYL3ByaXZhdGUvdmFyL2ZvbGRlcnMvdzYvYmd4eHF4bG42bnhmOXowd3I3ZnlweWZ3MDAwMGduL1QvUnRtcDNITlU0NC9wZXRzLlJjaGVja+KAmQrilIAgIHVzaW5nIFIgdmVyc2lvbiA0LjIuMiAoMjAyMi0xMC0zMSkK4pSAICB1c2luZyBwbGF0Zm9ybTogeDg2XzY0LWFwcGxlLWRhcndpbjE3LjAgKDY0LWJpdCkK4pSAICB1c2luZyBzZXNzaW9uIGNoYXJzZXQ6IFVURi04CuKUgCAgdXNpbmcgb3B0aW9ucyDigJgtLW5vLW1hbnVhbCAtLWFzLWNyYW7igJkK4pyUICBjaGVja2luZyBmb3IgZmlsZSDigJhwZXRzL0RFU0NSSVBUSU9O4oCZCuKUgCAgdGhpcyBpcyBwYWNrYWdlIOKAmHBldHPigJkgdmVyc2lvbiDigJgwLjAuMC45MDAw4oCZCuKUgCAgcGFja2FnZSBlbmNvZGluZzogVVRGLTgK4pyUICBjaGVja2luZyBwYWNrYWdlIG5hbWVzcGFjZSBpbmZvcm1hdGlvbgrinJQgIGNoZWNraW5nIHBhY2thZ2UgZGVwZW5kZW5jaWVzICgxLjRzKQrinJQgIGNoZWNraW5nIGlmIHRoaXMgaXMgYSBzb3VyY2UgcGFja2FnZSAuLi4K4pyUICBjaGVja2luZyBpZiB0aGVyZSBpcyBhIG5hbWVzcGFjZQrinJQgIGNoZWNraW5nIGZvciBleGVjdXRhYmxlIGZpbGVzIC4uLgrinJQgIGNoZWNraW5nIGZvciBoaWRkZW4gZmlsZXMgYW5kIGRpcmVjdG9yaWVzCuKclCAgY2hlY2tpbmcgZm9yIHBvcnRhYmxlIGZpbGUgbmFtZXMK4pyUICBjaGVja2luZyBmb3Igc3VmZmljaWVudC9jb3JyZWN0IGZpbGUgcGVybWlzc2lvbnMK4pyUICBjaGVja2luZyBzZXJpYWxpemF0aW9uIHZlcnNpb25zCuKclCAgY2hlY2tpbmcgd2hldGhlciBwYWNrYWdlIOKAmHBldHPigJkgY2FuIGJlIGluc3RhbGxlZCAoMXMpCuKclCAgY2hlY2tpbmcgaW5zdGFsbGVkIHBhY2thZ2Ugc2l6ZQrinJQgIGNoZWNraW5nIHBhY2thZ2UgZGlyZWN0b3J5CuKclCAgY2hlY2tpbmcgZm9yIGZ1dHVyZSBmaWxlIHRpbWVzdGFtcHMgLi4uClcgIGNoZWNraW5nIERFU0NSSVBUSU9OIG1ldGEtaW5mb3JtYXRpb24gLi4uCiAgIE5vbi1zdGFuZGFyZCBsaWNlbnNlIHNwZWNpZmljYXRpb246CiAgICAgYHVzZV9taXRfbGljZW5zZSgpYCwgYHVzZV9ncGwzX2xpY2Vuc2UoKWAgb3IgZnJpZW5kcyB0byBwaWNrIGEKICAgICBsaWNlbnNlCiAgIFN0YW5kYXJkaXphYmxlOiBGQUxTRQrinJQgIGNoZWNraW5nIHRvcC1sZXZlbCBmaWxlcwrinJQgIGNoZWNraW5nIGZvciBsZWZ0LW92ZXIgZmlsZXMK4pyUICBjaGVja2luZyBpbmRleCBpbmZvcm1hdGlvbiAuLi4K4pyUICBjaGVja2luZyBwYWNrYWdlIHN1YmRpcmVjdG9yaWVzIC4uLgrinJQgIGNoZWNraW5nIFIgZmlsZXMgZm9yIG5vbi1BU0NJSSBjaGFyYWN0ZXJzIC4uLgrinJQgIGNoZWNraW5nIFIgZmlsZXMgZm9yIHN5bnRheCBlcnJvcnMgLi4uCuKclCAgY2hlY2tpbmcgd2hldGhlciB0aGUgcGFja2FnZSBjYW4gYmUgbG9hZGVkIC4uLgrinJQgIGNoZWNraW5nIHdoZXRoZXIgdGhlIHBhY2thZ2UgY2FuIGJlIGxvYWRlZCB3aXRoIHN0YXRlZCBkZXBlbmRlbmNpZXMgLi4uCuKclCAgY2hlY2tpbmcgd2hldGhlciB0aGUgcGFja2FnZSBjYW4gYmUgdW5sb2FkZWQgY2xlYW5seSAuLi4K4pyUICBjaGVja2luZyB3aGV0aGVyIHRoZSBuYW1lc3BhY2UgY2FuIGJlIGxvYWRlZCB3aXRoIHN0YXRlZCBkZXBlbmRlbmNpZXMgLi4uCuKclCAgY2hlY2tpbmcgd2hldGhlciB0aGUgbmFtZXNwYWNlIGNhbiBiZSB1bmxvYWRlZCBjbGVhbmx5IC4uLgrinJQgIGNoZWNraW5nIGxvYWRpbmcgd2l0aG91dCBiZWluZyBvbiB0aGUgbGlicmFyeSBzZWFyY2ggcGF0aCAuLi4K4pyUICBjaGVja2luZyBkZXBlbmRlbmNpZXMgaW4gUiBjb2RlIC4uLgrinJQgIGNoZWNraW5nIFMzIGdlbmVyaWMvbWV0aG9kIGNvbnNpc3RlbmN5ICgzNjZtcykK4pyUICBjaGVja2luZyByZXBsYWNlbWVudCBmdW5jdGlvbnMgLi4uCuKclCAgY2hlY2tpbmcgZm9yZWlnbiBmdW5jdGlvbiBjYWxscyAuLi4K4pyUICBjaGVja2luZyBSIGNvZGUgZm9yIHBvc3NpYmxlIHByb2JsZW1zICgxLjlzKQrinJQgIGNoZWNraW5nIGZvciBtaXNzaW5nIGRvY3VtZW50YXRpb24gZW50cmllcyAuLi4K4pSAICBjaGVja2luZyBleGFtcGxlcyAuLi4gTk9ORQrinJQgIGNoZWNraW5nIGZvciBub24tc3RhbmRhcmQgdGhpbmdzIGluIHRoZSBjaGVjayBkaXJlY3RvcnkK4pyUICBjaGVja2luZyBmb3IgZGV0cml0dXMgaW4gdGhlIHRlbXAgZGlyZWN0b3J5CiAgIAogICBTZWUKICAgICDigJgvcHJpdmF0ZS92YXIvZm9sZGVycy93Ni9iZ3h4cXhsbjZueGY5ejB3cjdmeXB5ZncwMDAwZ24vVC9SdG1wM0hOVTQ0L3BldHMuUmNoZWNrLzAwY2hlY2subG9n4oCZCiAgIGZvciBkZXRhaWxzLgogICAKICAgCuKUgOKUgCBSIENNRCBjaGVjayByZXN1bHRzIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgCBwZXRzIDAuMC4wLjkwMDAg4pSA4pSA4pSA4pSACkR1cmF0aW9uOiA3LjJzCgrina8gY2hlY2tpbmcgREVTQ1JJUFRJT04gbWV0YS1pbmZvcm1hdGlvbiAuLi4gV0FSTklORwogIE5vbi1zdGFuZGFyZCBsaWNlbnNlIHNwZWNpZmljYXRpb246CiAgICBgdXNlX21pdF9saWNlbnNlKClgLCBgdXNlX2dwbDNfbGljZW5zZSgpYCBvciBmcmllbmRzIHRvIHBpY2sgYQogICAgbGljZW5zZQogIFN0YW5kYXJkaXphYmxlOiBGQUxTRQoKMCBlcnJvcnMg4pyUIHwgMSB3YXJuaW5nIOKcliB8IDAgbm90ZXMg4pyUCmBgYAoKOjo6IHRpcAoKSXQgaXMgKip2ZXJ5IGltcG9ydGFudCoqIHRvIHJlYWQgb3ZlciBhbGwgb2YgdGhpcyBpbmZvcm1hdGlvbiwgYXMgaXQgd2lsbCByZXBvcnQgdGhlIHRoaW5ncyB0aGF0IHBhc3NlZCB0aGUgY2hlY2sgYXMgd2VsbCBhcyBhbnkgd2FybmluZ3Mgb3IgZXJyb3JzIGVuY291bnRlcmVkIGluIHRoZSBwcm9jZXNzLiAKCjo6OgoKSGVyZSB3ZSBzZWUgdGhhdCB3ZSBoYXZlIDAgZXJyb3JzLCAxIHdhcm5pbmcsIGFuZCAwIG5vdGVzLiBUaGUgd2FybmluZyBzYXlzLAoKYE5vbi1zdGFuZGFyZCBsaWNlbnNlIHNwZWNpZmljYXRpb25gCgp3aGljaCBpcyBPSyBmb3Igbm93LCBhcyB3ZSdsbCBhZGRyZXNzIHRoYXQgbGF0ZXIuCgo6OjogdGlwCgpZb3UgY2FuIGFsc28gcnVuIGEgcGFja2FnZSBjaGVjayB2aWEgdGhlICoqQnVpbGQqKiBwYW5lIGluICoqUlN0dWRpbyoqLgoKOjo6CgohW10oaW1nL3JzX2J1aWxkX2NoZWNrLnBuZyl7IHdpZHRoPTcwJSB9CgoKKioqCgojIEVkaXQgYERFU0NSSVBUSU9OYCBmaWxlCgpUaGUgYERFU0NSSVBUSU9OYCBmaWxlIHByb3ZpZGVzIHNvbWUgbWV0YWRhdGEgYWJvdXQgYSBwYWNrYWdlLCBpbmNsdWRpbmcgdGhlIHBhY2thZ2UgbmFtZSwgaXRzIHRpdGxlLCBhdXRob3IsIGV0Yy4gWW91ciBgREVTQ1JJUFRJT05gIGZpbGUgc2hvdWxkIGxvb2sgc29tZXRoaW5nIGxpa2UgdGhpczoKCmBgYApQYWNrYWdlOiBwZXRzClRpdGxlOiBXaGF0IHRoZSBQYWNrYWdlIERvZXMgKE9uZSBMaW5lLCBUaXRsZSBDYXNlKQpWZXJzaW9uOiAwLjAuMC45MDAwCkF1dGhvcnNAUjogCiAgICBwZXJzb24oIkZpcnN0IiwgIkxhc3QiLCAsICJmaXJzdC5sYXN0QGV4YW1wbGUuY29tIiwgcm9sZSA9IGMoImF1dCIsICJjcmUiKSwKICAgICAgICAgICBjb21tZW50ID0gYyhPUkNJRCA9ICJZT1VSLU9SQ0lELUlEIikpCkRlc2NyaXB0aW9uOiBXaGF0IHRoZSBwYWNrYWdlIGRvZXMgKG9uZSBwYXJhZ3JhcGgpLgpMaWNlbnNlOiBgdXNlX21pdF9saWNlbnNlKClgLCBgdXNlX2dwbDNfbGljZW5zZSgpYCBvciBmcmllbmRzIHRvIHBpY2sgYQogICAgbGljZW5zZQpFbmNvZGluZzogVVRGLTgKUm94eWdlbjogbGlzdChtYXJrZG93biA9IFRSVUUpClJveHlnZW5Ob3RlOiA3LjIuMQpgYGAKCkxldCdzIGdvIGFoZWFkIGFuZCBtYWtlIHRoZSBmb2xsb3dpbmcgY2hhbmdlczoKCjo6OiB0YXNrCgpDaGFuZ2UgdGhlIHBhY2thZ2UgdGl0bGUgdG8gYEV2YWx1YXRlcyBZb3VyIEZlZWxpbmdzIEFib3V0IFBldHNgLgoKOjo6Cgo6OjogdGlwCgpUaGUgY29udmVudGlvbiBpcyB0byB1c2UgVGl0bGUgQ2FzZSBmb3IgcGFja2FnZSB0aXRsZXMuCgo6OjoKCjo6OiB0YXNrCgpBZGQgeW91ciBmaXJzdCBhbmQgbGFzdCBuYW1lcywgYW5kIHlvdXIgZW1haWwgYWRkcmVzcy4gWW91IGNhbiBsZWF2ZSB0aGUgYHJvbGVgIGFzIGlzIGFuZCBkZWxldGUgdGhlIGBjb21tZW50YCBmaWVsZCBhc2tpbmcgYWJvdXQgeW91ciBgT1JDSURgLgoKOjo6Cgo6OjogdGlwCgpXcml0ZSBzb21lIGRlc2NyaXB0aXZlIHRleHQgYWJvdXQgdGhlIHBhY2thZ2UgaW4gdGhlIGBEZXNjcmlwdGlvbmAgZmllbGQuIEZvciBleGFtcGxlLCBgUGV0cyBhcmUgYXdlc29tZSBjb21wYW5pb25zLiBTb21lIHBlb3BsZSBhcmUgZmFucyBvZiBjYXRzLCBvdGhlcnMgbm90IHNvIG11Y2guYAoKOjo6CgpXaGVuIGZpbmlzaGVkLCB5b3VyIGBERVNDUklQVElPTmAgZmlsZSBzaG91bGQgbG9vayBzb21ldGhpbmcgbGlrZSB0aGlzOgoKYGBgClBhY2thZ2U6IHBldHMKVGl0bGU6IEV2YWx1YXRlcyBZb3VyIEZlZWxpbmdzIEFib3V0IFBldHMKVmVyc2lvbjogMC4wLjAuOTAwMApBdXRob3JzQFI6IAogICAgcGVyc29uKGdpdmVuID0gIk1hcmsiLAogICAgICAgICAgIGZhbWlseSA9ICJTY2hldWVyZWxsIiwKICAgICAgICAgICByb2xlID0gYygiYXV0IiwgImNyZSIpLAogICAgICAgICAgIGVtYWlsID0gIm1hcmtAdXcuZWR1IikKRGVzY3JpcHRpb246IFBldHMgYXJlIGF3ZXNvbWUgY29tcGFuaW9ucy4gU29tZSBwZW9wbGUgYXJlIGZhbnMgb2YgY2F0cywgb3RoZXJzIG5vdCBzbyBtdWNoLgpMaWNlbnNlOiBgdXNlX21pdF9saWNlbnNlKClgLCBgdXNlX2dwbDNfbGljZW5zZSgpYCBvciBmcmllbmRzIHRvIHBpY2sgYQogICAgbGljZW5zZQpFbmNvZGluZzogVVRGLTgKUm94eWdlbjogbGlzdChtYXJrZG93biA9IFRSVUUpClJveHlnZW5Ob3RlOiA3LjIuMQpgYGAKCioqKgoKIyBBZGQgYSBsaWNlbnNlCgpJdCdzIGJlc3QgcHJhY3RpY2UgdG8gYWRkIGEgbGljZW5zZSB0byBvdXIgcGFja2FnZSBzbyBsZXQncyBnbyBhaGVhZCBhbmQgZG8gdGhhdCAod2UnbGwgdXNlIHRoZSBNSVQgbGljZW5zZSkuCgo6OjogdGFzawoKVXNlIHRoZSBoZWxwZXIgZnVuY3Rpb24gYHVzZV9taXRfbGljZW5zZSgpYCB0byBjcmVhdGUgYSBsaWNlbnNlIGFuZCBtYWtlIHN1cmUgdG8gdXNlIHlvdXIgb3duIG5hbWUgaW4gdGhlIGFyZ3VtZW50LgoKOjo6CgpgYGB7ciBhZGRfbGljZW5zZSwgZXZhbCA9IEZBTFNFfQo+IHVzZV9taXRfbGljZW5zZSgiTWFyayBTY2hldWVyZWxsIikK4pyUIFNldHRpbmcgTGljZW5zZSBmaWVsZCBpbiBERVNDUklQVElPTiB0byAnTUlUICsgZmlsZSBMSUNFTlNFJwrinJQgV3JpdGluZyAnTElDRU5TRScK4pyUIFdyaXRpbmcgJ0xJQ0VOU0UubWQnCuKclCBBZGRpbmcgJ15MSUNFTlNFXFwubWQkJyB0byAnLlJidWlsZGlnbm9yZScKYGBgCgo6OjogdGFzawoKT3BlbiB1cCB0aGUgbmV3bHkgY3JlYXRlZCBgTElDRU5TRWAgZmlsZSBhbmQgY29uZmlybSBpdCBoYXMgdGhlIGN1cnJlbnQgeWVhciBhbmQgeW91ciBuYW1lLgoKOjo6CgpgYGAKWUVBUjogMjAyNQpDT1BZUklHSFQgSE9MREVSOiBNYXJrIFNjaGV1ZXJlbGwKYGBgCgo6OjogdGlwCgpgdXNlX21pdF9saWNlbnNlKClgIHdpbGwgYWxzbyBwdXQgYSBjb3B5IG9mIHRoZSBmdWxsIGxpY2Vuc2UgaW4gYExJQ0VOU0UubWRgIGFuZCBhZGQgdGhpcyBmaWxlIHRvIGAuUmJ1aWxkaWdub3JlYC4KCjo6OgoKCioqKgoKIyBXcml0aW5nIGRvY3VtZW50YXRpb24KCklmIHlvdSdyZSBsaWtlIE1hcmssIHlvdSBvZnRlbiByZWx5IG9uIGEgZnVuY3Rpb24ncyBkb2N1bWVudGF0aW9uIHRvIGhlbHAgeW91IHVuZGVyc3RhbmQgdGhlIGFyZ3VtZW50cyB0byBhIGZ1bmN0aW9uIGFuZCB0aGUgdmFsdWUocykgdGhhdCB0aGUgZnVuY3Rpb24gcmV0dXJucy4gVGhpcyBpcyB0eXBpY2FsbHkgZG9uZSB2aWEgYSBxdWVzdGlvbiBtYXJrIHByZWNlZGluZyB0aGUgZnVuY3Rpb24gbmFtZSAoZS5nLiwgYD9wcmludGApLiBXcml0aW5nIHRoaXMgZG9jdW1lbnRhdGlvbiB1c2VkIHRvIGJlIGEgYml0IG9uZXJvdXMsIGJ1dCBub3cgaXQncyBlYXN5IHRvIGFkZCBkb2N1bWVudGF0aW9uIHRvIGEgcGFja2FnZSB1c2luZyB0aGUgYHtyb3h5Z2VuMn1gIHBhY2thZ2UuIFRvIGRvIHNvLCB3ZSdsbCBhZGQgYSBzcGVjaWFsIGZvcm0gb2YgY29tbWVudCBhYm92ZSBvdXIgZnVuY3Rpb24gZGVmaW5pdGlvbiBpbiBgY2F0cy5SYCwgd2hpY2ggd2UnbGwgZGVub3RlIHdpdGggYSBgIydgLiAKCjo6OiB0YXNrCgpPcGVuIHRoZSBgY2F0cy5SYCBzY3JpcHQgYW5kIG1ha2Ugc3VyZSB5b3VyIGN1cnNvciBpcyBhdCB0aGUgdmVyeSB0b3AgLiBGcm9tIHlvdXIgKipSU3R1ZGlvKiogbWVudSwgc2VsZWN0ICoqQ29kZSA+IEluc2VydCBSb3h5Z2VuIFNrZWxldG9uKiouCgo6OjoKCjo6OiB0aXAKCllvdXIgYGNhdHMuUmAgZmlsZSBzaG91bGQgbm93IGxvb2sgbGlrZSBmb2xsb3dpbmcuCgo6OjoKCmBgYAojJyBUaXRsZQojJwojJyBAcGFyYW0gbG92ZSAKIycKIycgQHJldHVybgojJyBAZXhwb3J0CiMnCiMnIEBleGFtcGxlcwpjYXRzIDwtIGZ1bmN0aW9uKGxvdmUgPSBUUlVFKSB7CiAgaWYobG92ZSA9PSBUUlVFKSB7CiAgICBtc2cgPC0gIkkgbG92ZSBjYXRzISIKICB9CiAgZWxzZSB7CiAgICBtc2cgPC0gIkkgYW0gbm90IGEgY2F0IHBlcnNvbi4iCiAgfQogIHJldHVybihwcmludChtc2cpKQp9CmBgYAoKTGV0J3MgZ28gb3ZlciB0aGUgZGlmZmVyZW50IGVsZW1lbnRzIG9mIHRoZSBmdW5jdGlvbidzIGRvY3VtZW50YXRpb24gc2tlbGV0b24gdGhhdCB3ZSBqdXN0IGluc2VydGVkLgoKKiBgVGl0bGVgOiBBIHNob3J0IGRlc2NyaXB0aXZlIHBocmFzZSBvZiB3aGF0IHRoZSBmdW5jdGlvbiBkb2VzLgoKKiBgQHBhcmFtYDogT25lIG9yIG1vcmUgYXJndW1lbnRzIHRvIHRoZSBmdW5jdGlvbiAoaGVyZSB0aGVyZSBpcyBvbmx5IG9uZTogYGxvdmVgKSBhbmQgaXRzL3RoZWlyIGRlc2NyaXB0aW9uKHMpLgoKKiBgQHJldHVybmA6IEEgZGVzY3JpcHRpb24gb2Ygd2hhdCB0aGUgZnVuY3Rpb24gcmV0dXJucy4KCiogYEBleHBvcnRgOiBUZWxscyBgcm94eWdlbjJgIHRvIGFkZCB0aGlzIGZ1bmN0aW9uIHRvIHRoZSBgTkFNRVNQQUNFYCBmaWxlIHNvIGl0J3MgYWNjZXNzaWJsZSB0byB1c2Vycy4KCiogYEBleGFtcGxlc2A6IE9uZSBvciBtb3JlIGNvZGVkIGV4YW1wbGVzIG9mIGhvdyB0aGUgZnVuY3Rpb24gaXMgdXNlZC4KCiMjIyBUaXRsZQoKOjo6IHRhc2sKClJlcGxhY2UgYFRpdGxlYCB3aXRoIHNvbWV0aGluZyBtb3JlIGRlc2NyaXB0aXZlIGxpa2UgYEV4cHJlc3NlcyB5b3VyIG9waW5pb24gYWJvdXQgY2F0c2AuCgo6OjoKCmBgYAojJyBFeHByZXNzZXMgeW91ciBvcGluaW9uIGFib3V0IGNhdHMKIycKIycgQHBhcmFtIGxvdmUgCiMnCiMnIEByZXR1cm4KIycgQGV4cG9ydAojJwojJyBAZXhhbXBsZXMKY2F0cyA8LSBmdW5jdGlvbihsb3ZlID0gVFJVRSkgewogIGlmKGxvdmUgPT0gVFJVRSkgewogICAgbXNnIDwtICJJIGxvdmUgY2F0cyEiCiAgfQogIGVsc2UgewogICAgbXNnIDwtICJJIGFtIG5vdCBhIGNhdCBwZXJzb24uIgogIH0KICByZXR1cm4ocHJpbnQobXNnKSkKfQpgYGAKCiMjIyBQYXJhbWV0ZXJzCgpPdXIgYHtyb3h5Z2VufWAgc2tlbGV0b24gYWxyZWFkeSBjb250YWlucyB0aGUgb25lIHBhcmFtZXRlciBpbiBvdXIgZnVuY3Rpb24gYGxvdmVgLCBidXQgd2UgY2FuIGdvIGFoZWFkIGFuZCBhZGQgYW4gZXhwbGljaXQgZGVzY3JpcHRpb24gb2YgdGhpcyBhcmd1bWVudC4gSXQncyBvZnRlbiBhIGdvb2QgaWRlYSB0byBhbHNvIGluY2x1ZGUgd2hhdCwgaWYgYW55LCB0aGUgZGVmYXVsdCBhcmd1bWVudCBpcy4KCjo6OiB0YXNrCgpJbiB0aGUgYCMnIEBwYXJhbWAgZmllbGQgYWZ0ZXIgYGxvdmVgLCBhZGQgYGBgQSBsb2dpY2FsIGFyZ3VtZW50IGluZGljYXRpbmcgd2hldGhlciBvciBub3QgeW91IGxvdmUgY2F0cyAoZGVmYXVsdCA9IGBUUlVFYClgYGAuCgo6OjoKCmBgYAojJyBFeHByZXNzZXMgeW91ciBvcGluaW9uIGFib3V0IGNhdHMKIycKIycgQHBhcmFtIGxvdmUgQSBsb2dpY2FsIGFyZ3VtZW50IGluZGljYXRpbmcgd2hldGhlciBvciBub3QgeW91IGxvdmUgY2F0cyAoZGVmYXVsdCA9IGBUUlVFYCkKIycKIycgQHJldHVybgojJyBAZXhwb3J0CiMnCiMnIEBleGFtcGxlcwpjYXRzIDwtIGZ1bmN0aW9uKGxvdmUgPSBUUlVFKSB7CiAgaWYobG92ZSA9PSBUUlVFKSB7CiAgICBtc2cgPC0gIkkgbG92ZSBjYXRzISIKICB9CiAgZWxzZSB7CiAgICBtc2cgPC0gIkkgYW0gbm90IGEgY2F0IHBlcnNvbi4iCiAgfQogIHJldHVybihwcmludChtc2cpKQp9CmBgYAoKIyMjIFJldHVybgoKSXQncyBnb29kIHByYWN0aWNlIHRvIHRlbGwgdGhlIHVzZXIgd2hhdCB0aGV5IHNob3VsZCBleHBlY3QgZnJvbSBhIGZ1bmN0aW9uLiBUaGlzIGlzIGFkbWl0dGVkbHkgYSByYXRoZXIgc2ltcGxlIGZ1bmN0aW9uLCB3aGljaCBpcyBlYXN5IHRvIGRlY2lwaGVyLCBidXQgb3RoZXIgZnVuY3Rpb25zIHdpbGwgbm90IGJlIG5lYXJseSBhcyB0cmFuc3BhcmVudC4KCjo6OiB0YXNrCgpJbiB0aGUgYCMnIEByZXR1cm5gIGZpZWxkICwgYWRkIGBgYE9uZSBvZiB0d28gcG9zc2libGUgY2hhcmFjdGVyIHN0cmluZ3MgKGAiSSBsb3ZlIGNhdHMhImAgb3IgYCJJIGFtIG5vdCBhIGNhdCBwZXJzb24uImApYGBgLgoKOjo6CgpgYGAKIycgRXhwcmVzc2VzIHlvdXIgb3BpbmlvbiBhYm91dCBjYXRzCiMnCiMnIEBwYXJhbSBsb3ZlIEEgbG9naWNhbCBhcmd1bWVudCBpbmRpY2F0aW5nIHdoZXRoZXIgb3Igbm90IHlvdSBsb3ZlIGNhdHMgKGRlZmF1bHQgPSBgVFJVRWApCiMnCiMnIEByZXR1cm4gT25lIG9mIHR3byBwb3NzaWJsZSBjaGFyYWN0ZXIgc3RyaW5ncyAoYCJJIGxvdmUgY2F0cyEiYCBvciBgIkkgYW0gbm90IGEgY2F0IHBlcnNvbi4iYCkuCiMnIEBleHBvcnQKIycKIycgQGV4YW1wbGVzCmNhdHMgPC0gZnVuY3Rpb24obG92ZSA9IFRSVUUpIHsKICBpZihsb3ZlID09IFRSVUUpIHsKICAgIG1zZyA8LSAiSSBsb3ZlIGNhdHMhIgogIH0KICBlbHNlIHsKICAgIG1zZyA8LSAiSSBhbSBub3QgYSBjYXQgcGVyc29uLiIKICB9CiAgcmV0dXJuKHByaW50KG1zZykpCn0KYGBgCgojIyMgRXhwb3J0CgpZb3UgY2FuIGxlYXZlIHRoaXMgYmxhbmssIGFzIHRoZSBkZWZhdWx0IGJlaGF2aW9yIGlzIGFsbCB3ZSBuZWVkIGhlcmUuCgojIyMgRXhhbXBsZXMKClRoaXMgaXMgYW4gb3B0aW9uYWwgZWxlbWVudCBvZiB0aGUgZG9jdW1lbnRhdGlvbi4gSWYgeW91IGluY2x1ZGUgYEBleGFtcGxlc2Agd2l0aG91dCBhbnkgYWN0dWFsIGNvZGUsIHlvdSB3aWxsIGdldCBhIHdhcm5pbmcgYWJvdXQgYEBleGFtcGxlcyByZXF1aXJlcyBhIHZhbHVlYC4gSW4gdGhpcyBjYXNlLCB3ZSBjYW4gYWRkIGEgcmVhbGx5IHNpbXBsZSBleGFtcGxlOgoKOjo6IHRhc2sKCkFkZCBgY2F0cyhUUlVFKWAgdG8gdGhlIGAjJyBAZXhhbXBsZXMgYCBmaWVsZC4KCjo6OgoKYGBgCiMnIEV4cHJlc3NlcyB5b3VyIG9waW5pb24gYWJvdXQgY2F0cwojJwojJyBAcGFyYW0gbG92ZSBBIGxvZ2ljYWwgYXJndW1lbnQgaW5kaWNhdGluZyB3aGV0aGVyIG9yIG5vdCB5b3UgbG92ZSBjYXRzIChkZWZhdWx0ID0gYFRSVUVgKQojJwojJyBAcmV0dXJuIE9uZSBvZiB0d28gcG9zc2libGUgY2hhcmFjdGVyIHN0cmluZ3MgKGAiSSBsb3ZlIGNhdHMhImAgb3IgYCJJIGFtIG5vdCBhIGNhdCBwZXJzb24uImApLgojJyBAZXhwb3J0CiMnCiMnIEBleGFtcGxlcyBjYXRzKFRSVUUpCmNhdHMgPC0gZnVuY3Rpb24obG92ZSA9IFRSVUUpIHsKICBpZihsb3ZlID09IFRSVUUpIHsKICAgIG1zZyA8LSAiSSBsb3ZlIGNhdHMhIgogIH0KICBlbHNlIHsKICAgIG1zZyA8LSAiSSBhbSBub3QgYSBjYXQgcGVyc29uLiIKICB9CiAgcmV0dXJuKHByaW50KG1zZykpCn0KYGBgCgo6OjogdGlwCgpNYWtlIHN1cmUgdG8gc2F2ZSBgY2F0cy5SYCBhZnRlciBtb2RpZnlpbmcgdGhlIGB7cm94eWdlbn1gIHNrZWxldG9uLgoKOjo6CgoKIyMgQXNzZW1ibGUgdGhlIGRvY3VtZW50YXRpb24KCk5vdyB0aGF0IHdlJ3ZlIHdyaXR0ZW4gdGhlIGZ1bmN0aW9uJ3MgZG9jdW1lbnRhdGlvbiwgd2UgbmVlZCB0byBwYXNzIGl0IGFsb25nIHRvIHRoZSBgY2F0cy5SZGAgZmlsZSBpbiB0aGUgaGVscCBtYW51YWwuIFRvIGRvIHNvLCB3ZSBjYW4gdXNlIHRoZSBgZG9jdW1lbnQoKWAgZnVuY3Rpb24uCgo6OjogdGFzawoKUnVuIGBkb2N1bWVudCgpYCBhdCB0aGUgY29tbWFuZCBwcm9tcHQgdG8gY3JlYXRlIHRoZSBmdW5jdGlvbiBkb2N1bWVudGF0aW9uLgoKOjo6CgpgYGB7ciBkb2N1bWVudF9oZWxwLCBldmFsID0gRkFMU0V9Cj4gZG9jdW1lbnQoKQpVcGRhdGluZyBwZXRzIGRvY3VtZW50YXRpb24K4oS5IExvYWRpbmcgcGV0cwpXcml0aW5nIE5BTUVTUEFDRQpXcml0aW5nIGNhdHMuUmQKYGBgCgo6OjogdGlwCgpUaGVyZSBzaG91bGQgYmUgYSBuZXcgZm9sZGVyIGluIHlvdXIgcHJvamVjdCBkaXJlY3RvcnkgY2FsbGVkIGAvbWFuYCwgd2hpY2ggc3RhbmRzIGZvciAibWFudWFsIi4gVGhpcyBpcyB3aGVyZSB0aGUgaGVscCBmaWxlcyBsaXZlLgoKOjo6Cgo6OjogdGFzawoKT3BlbiB1cCB0aGUgYC9tYW5gIGZvbGRlciBhbmQgaW5zcGVjdCB0aGUgY29udGVudHMgb2YgYGNhdHMuUmRgLiBJdCBzaG91bGQgbG9vayBsaWtlIHRoZSBmb2xsb3dpbmcuCgo6OjoKCmBgYAolIEdlbmVyYXRlZCBieSByb3h5Z2VuMjogZG8gbm90IGVkaXQgYnkgaGFuZAolIFBsZWFzZSBlZGl0IGRvY3VtZW50YXRpb24gaW4gUi9jYXRzLlIKXG5hbWV7Y2F0c30KXGFsaWFze2NhdHN9Clx0aXRsZXtFeHByZXNzZXMgeW91ciBvcGluaW9uIGFib3V0IGNhdHN9Clx1c2FnZXsKY2F0cyhsb3ZlID0gVFJVRSkKfQpcYXJndW1lbnRzewpcaXRlbXtgbG92ZWB9e0EgbG9naWNhbCBhcmd1bWVudCBpbmRpY2F0aW5nIHdoZXRoZXIgb3Igbm90IHlvdSBsb3ZlIGNhdHMgKGRlZmF1bHQgPSBcY29kZXtUUlVFfSl9Cn0KXHZhbHVlewpPbmUgb2YgdHdvIHBvc3NpYmxlIGNoYXJhY3RlciBzdHJpbmdzIChcY29kZXsiSSBsb3ZlIGNhdHMhIn0gb3IgXGNvZGV7IkkgYW0gbm90IGEgY2F0IHBlcnNvbi4ifSkuCn0KXGRlc2NyaXB0aW9uewpFeHByZXNzZXMgeW91ciBvcGluaW9uIGFib3V0IGNhdHMKfQpcZXhhbXBsZXN7CmNhdHMoVFJVRSkKfQpgYGAKCjo6OiB0YXNrCgpDaGVjayB0aGF0IGV2ZXJ5dGhpbmcgd29ya2VkIGFzIHBsYW5uZWQgYnkgcHJldmlld2luZyBvdXIgaGVscCBmaWxlIHdpdGggYD9jYXRzYC4KCjo6OgoKYGBge3IgdGVzdF9oZWxwLCBldmFsID0gRkFMU0V9Cj4gP2NhdHMK4oS5IFJlbmRlcmluZyBkZXZlbG9wbWVudCBkb2N1bWVudGF0aW9uIGZvciAiY2F0cyIKYGBgCgo6OjogdGlwCgpZb3VyIGhlbHAgdGFiIHNob3VsZCBsb29rIGxpa2UgdGhpcy4KCjo6OgoKIVtdKGltZy9oZWxwX2NhdHMucG5nKXsgd2lkdGg9NzAlIH0KCgojIyMgRXhhbWluZSBgTkFNRVNQQUNFYCBmaWxlCgpXaGVuIHdlIGNhbGxlZCBgZG9jdW1lbnQoKWAgYWJvdmUgdG8gY29udmVydCB0aGUgc3BlY2lhbCAqKlJveHlnZW4qKiBjb21tZW50cyBpbiBgY2F0cy5SYCBpbnRvIGBtYW4vY2F0cy5SZGAsIGl0IGFsc28gdXBkYXRlZCB0aGUgYE5BTUVTUEFDRWAgZmlsZSBiYXNlZCBvbiB0aGUgYEBleHBvcnRgIGxpbmUgZm91bmQgaW4gdGhlIGByb3h5Z2VuYCBjb21tZW50cy4KCjo6OiB0YXNrCgpPcGVuIHVwIHlvdXIgYE5BTUVTUEFDRWAgZmlsZSBhbmQgdmVyaWZ5IHRoYXQgaXRzIGNvbnRlbnRzIGxvb2sgbGlrZSB0aGlzLgoKOjo6CgpgYGAKIyBHZW5lcmF0ZWQgYnkgcm94eWdlbjI6IGRvIG5vdCBlZGl0IGJ5IGhhbmQKCmV4cG9ydChjYXRzKQpgYGAKCioqKgoKIyBDaGVjayAmIGluc3RhbGwKCk5vdyBpcyBhIGdvb2QgdGltZSB0byByZS1ydW4gb3VyIGRpYWdub3N0aWMgY2hlY2tzLgoKOjo6IHRhc2sKCkNhbGwgYGNoZWNrKClgIGFnYWluLCB3aGljaCBzaG91bGQgcmV0dXJuIG5vIGVycm9ycyBvciB3YXJuaW5ncy4KCjo6OgoKYGBge3IgcmUtY2hlY2ssIGV2YWwgPSBGQUxTRX0KPiBjaGVjaygpCuKVkOKVkCBEb2N1bWVudGluZyDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZAK4oS5IFVwZGF0aW5nIHBldHMgZG9jdW1lbnRhdGlvbgrihLkgTG9hZGluZyBwZXRzCgrilZDilZAgQnVpbGRpbmcg4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQ4pWQClNldHRpbmcgZW52IHZhcnM6CuKAoiBDRkxBR1MgICAgOiAtV2FsbCAtcGVkYW50aWMgLWZkaWFnbm9zdGljcy1jb2xvcj1hbHdheXMK4oCiIENYWEZMQUdTICA6IC1XYWxsIC1wZWRhbnRpYyAtZmRpYWdub3N0aWNzLWNvbG9yPWFsd2F5cwrigKIgQ1hYMTFGTEFHUzogLVdhbGwgLXBlZGFudGljIC1mZGlhZ25vc3RpY3MtY29sb3I9YWx3YXlzCuKAoiBDWFgxNEZMQUdTOiAtV2FsbCAtcGVkYW50aWMgLWZkaWFnbm9zdGljcy1jb2xvcj1hbHdheXMK4oCiIENYWDE3RkxBR1M6IC1XYWxsIC1wZWRhbnRpYyAtZmRpYWdub3N0aWNzLWNvbG9yPWFsd2F5cwrigKIgQ1hYMjBGTEFHUzogLVdhbGwgLXBlZGFudGljIC1mZGlhZ25vc3RpY3MtY29sb3I9YWx3YXlzCuKclCAgY2hlY2tpbmcgZm9yIGZpbGUg4oCYL1VzZXJzL21hcmsvRG9jdW1lbnRzL0dpdEh1Yi9GSVNINTQ5L3BldHMvREVTQ1JJUFRJT07igJkgLi4uCuKUgCAgcHJlcGFyaW5nIOKAmHBldHPigJk6CuKclCAgY2hlY2tpbmcgREVTQ1JJUFRJT04gbWV0YS1pbmZvcm1hdGlvbiAuLi4K4pSAICBjaGVja2luZyBmb3IgTEYgbGluZS1lbmRpbmdzIGluIHNvdXJjZSBhbmQgbWFrZSBmaWxlcyBhbmQgc2hlbGwgc2NyaXB0cwrilIAgIGNoZWNraW5nIGZvciBlbXB0eSBvciB1bm5lZWRlZCBkaXJlY3RvcmllcwrilIAgIGJ1aWxkaW5nIOKAmHBldHNfMC4wLjAuOTAwMC50YXIuZ3rigJkKICAgCuKVkOKVkCBDaGVja2luZyDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZAKU2V0dGluZyBlbnYgdmFyczoK4oCiIF9SX0NIRUNLX0NSQU5fSU5DT01JTkdfUkVNT1RFXzogRkFMU0UK4oCiIF9SX0NIRUNLX0NSQU5fSU5DT01JTkdfICAgICAgIDogRkFMU0UK4oCiIF9SX0NIRUNLX0ZPUkNFX1NVR0dFU1RTXyAgICAgIDogRkFMU0UK4oCiIE5PVF9DUkFOICAgICAgICAgICAgICAgICAgICAgIDogdHJ1ZQrilIDilIAgUiBDTUQgY2hlY2sg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSACuKUgCAgdXNpbmcgbG9nIGRpcmVjdG9yeSDigJgvcHJpdmF0ZS92YXIvZm9sZGVycy93Ni9iZ3h4cXhsbjZueGY5ejB3cjdmeXB5ZncwMDAwZ24vVC9SdG1wM0hOVTQ0L3BldHMuUmNoZWNr4oCZCuKUgCAgdXNpbmcgUiB2ZXJzaW9uIDQuMi4yICgyMDIyLTEwLTMxKQrilIAgIHVzaW5nIHBsYXRmb3JtOiB4ODZfNjQtYXBwbGUtZGFyd2luMTcuMCAoNjQtYml0KQrilIAgIHVzaW5nIHNlc3Npb24gY2hhcnNldDogVVRGLTgK4pSAICB1c2luZyBvcHRpb25zIOKAmC0tbm8tbWFudWFsIC0tYXMtY3JhbuKAmQrinJQgIGNoZWNraW5nIGZvciBmaWxlIOKAmHBldHMvREVTQ1JJUFRJT07igJkK4pSAICB0aGlzIGlzIHBhY2thZ2Ug4oCYcGV0c+KAmSB2ZXJzaW9uIOKAmDAuMC4wLjkwMDDigJkK4pSAICBwYWNrYWdlIGVuY29kaW5nOiBVVEYtOArinJQgIGNoZWNraW5nIHBhY2thZ2UgbmFtZXNwYWNlIGluZm9ybWF0aW9uCuKclCAgY2hlY2tpbmcgcGFja2FnZSBkZXBlbmRlbmNpZXMgKDMuM3MpCuKclCAgY2hlY2tpbmcgaWYgdGhpcyBpcyBhIHNvdXJjZSBwYWNrYWdlCuKclCAgY2hlY2tpbmcgaWYgdGhlcmUgaXMgYSBuYW1lc3BhY2UK4pyUICBjaGVja2luZyBmb3IgZXhlY3V0YWJsZSBmaWxlcyAuLi4K4pyUICBjaGVja2luZyBmb3IgaGlkZGVuIGZpbGVzIGFuZCBkaXJlY3RvcmllcwrinJQgIGNoZWNraW5nIGZvciBwb3J0YWJsZSBmaWxlIG5hbWVzCuKclCAgY2hlY2tpbmcgZm9yIHN1ZmZpY2llbnQvY29ycmVjdCBmaWxlIHBlcm1pc3Npb25zCuKclCAgY2hlY2tpbmcgc2VyaWFsaXphdGlvbiB2ZXJzaW9ucwrinJQgIGNoZWNraW5nIHdoZXRoZXIgcGFja2FnZSDigJhwZXRz4oCZIGNhbiBiZSBpbnN0YWxsZWQgKDFzKQrinJQgIGNoZWNraW5nIGluc3RhbGxlZCBwYWNrYWdlIHNpemUK4pyUICBjaGVja2luZyBwYWNrYWdlIGRpcmVjdG9yeQrinJQgIGNoZWNraW5nIGZvciBmdXR1cmUgZmlsZSB0aW1lc3RhbXBzIC4uLgrinJQgIGNoZWNraW5nIERFU0NSSVBUSU9OIG1ldGEtaW5mb3JtYXRpb24gLi4uCuKclCAgY2hlY2tpbmcgdG9wLWxldmVsIGZpbGVzIC4uLgrinJQgIGNoZWNraW5nIGZvciBsZWZ0LW92ZXIgZmlsZXMK4pyUICBjaGVja2luZyBpbmRleCBpbmZvcm1hdGlvbgrinJQgIGNoZWNraW5nIHBhY2thZ2Ugc3ViZGlyZWN0b3JpZXMgLi4uCuKclCAgY2hlY2tpbmcgUiBmaWxlcyBmb3Igbm9uLUFTQ0lJIGNoYXJhY3RlcnMgLi4uCuKclCAgY2hlY2tpbmcgUiBmaWxlcyBmb3Igc3ludGF4IGVycm9ycyAuLi4K4pyUICBjaGVja2luZyB3aGV0aGVyIHRoZSBwYWNrYWdlIGNhbiBiZSBsb2FkZWQgLi4uCuKclCAgY2hlY2tpbmcgd2hldGhlciB0aGUgcGFja2FnZSBjYW4gYmUgbG9hZGVkIHdpdGggc3RhdGVkIGRlcGVuZGVuY2llcyAuLi4K4pyUICBjaGVja2luZyB3aGV0aGVyIHRoZSBwYWNrYWdlIGNhbiBiZSB1bmxvYWRlZCBjbGVhbmx5IC4uLgrinJQgIGNoZWNraW5nIHdoZXRoZXIgdGhlIG5hbWVzcGFjZSBjYW4gYmUgbG9hZGVkIHdpdGggc3RhdGVkIGRlcGVuZGVuY2llcyAuLi4K4pyUICBjaGVja2luZyB3aGV0aGVyIHRoZSBuYW1lc3BhY2UgY2FuIGJlIHVubG9hZGVkIGNsZWFubHkgLi4uCuKclCAgY2hlY2tpbmcgbG9hZGluZyB3aXRob3V0IGJlaW5nIG9uIHRoZSBsaWJyYXJ5IHNlYXJjaCBwYXRoIC4uLgrinJQgIGNoZWNraW5nIGRlcGVuZGVuY2llcyBpbiBSIGNvZGUgLi4uCuKclCAgY2hlY2tpbmcgUzMgZ2VuZXJpYy9tZXRob2QgY29uc2lzdGVuY3kgKDM3MW1zKQrinJQgIGNoZWNraW5nIHJlcGxhY2VtZW50IGZ1bmN0aW9ucyAuLi4K4pyUICBjaGVja2luZyBmb3JlaWduIGZ1bmN0aW9uIGNhbGxzIC4uLgrinJQgIGNoZWNraW5nIFIgY29kZSBmb3IgcG9zc2libGUgcHJvYmxlbXMgKDEuOXMpCuKclCAgY2hlY2tpbmcgUmQgZmlsZXMgLi4uCuKclCAgY2hlY2tpbmcgUmQgbWV0YWRhdGEgLi4uCuKclCAgY2hlY2tpbmcgUmQgbGluZSB3aWR0aHMgLi4uCuKclCAgY2hlY2tpbmcgUmQgY3Jvc3MtcmVmZXJlbmNlcyAuLi4K4pyUICBjaGVja2luZyBmb3IgbWlzc2luZyBkb2N1bWVudGF0aW9uIGVudHJpZXMgLi4uCuKclCAgY2hlY2tpbmcgZm9yIGNvZGUvZG9jdW1lbnRhdGlvbiBtaXNtYXRjaGVzICg0MDNtcykK4pyUICBjaGVja2luZyBSZCBcdXNhZ2Ugc2VjdGlvbnMgKDUyMm1zKQrinJQgIGNoZWNraW5nIFJkIGNvbnRlbnRzIC4uLgrinJQgIGNoZWNraW5nIGZvciB1bnN0YXRlZCBkZXBlbmRlbmNpZXMgaW4gZXhhbXBsZXMgLi4uCuKclCAgY2hlY2tpbmcgZXhhbXBsZXMgKDU0N21zKQrinJQgIGNoZWNraW5nIGZvciBub24tc3RhbmRhcmQgdGhpbmdzIGluIHRoZSBjaGVjayBkaXJlY3RvcnkK4pyUICBjaGVja2luZyBmb3IgZGV0cml0dXMgaW4gdGhlIHRlbXAgZGlyZWN0b3J5CiAgIAogICAK4pSA4pSAIFIgQ01EIGNoZWNrIHJlc3VsdHMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAIHBldHMgMC4wLjAuOTAwMCDilIDilIDilIDilIAKRHVyYXRpb246IDExLjNzCgowIGVycm9ycyDinJQgfCAwIHdhcm5pbmdzIOKclCB8IDAgbm90ZXMg4pyUCmBgYAoKOjo6IHN1Y2Nlc3MKCkV2ZXJ5dGhpbmcgY2hlY2tzIG91dCBub3chCgo6OjoKCiMjIyBJbnN0YWxsCgo6OjogdGFzawoKTm93IHRoYXQgd2UndmUgdmVyaWZpZWQgdGhhdCBvdXIgcGFja2FnZSBidWlsZHMgY29ycmVjdGx5LCBsZXQncyBpbnN0YWxsIGFuZCB0cnkgaXQgb3V0IHdpdGggdGhlIGBpbnN0YWxsKClgIGZ1bmN0aW9uLgoKOjo6CgpgYGB7ciBpbnN0YWxsX3BrZywgZXZhbCA9IEZBTFNFfQo+IGluc3RhbGwoKQrinJQgIGNoZWNraW5nIGZvciBmaWxlIOKAmC9Vc2Vycy9tYXJrL0RvY3VtZW50cy9HaXRIdWIvRklTSDU0OS9wZXRzL0RFU0NSSVBUSU9O4oCZIC4uLgrilIAgIHByZXBhcmluZyDigJhwZXRz4oCZOgrinJQgIGNoZWNraW5nIERFU0NSSVBUSU9OIG1ldGEtaW5mb3JtYXRpb24gLi4uCuKUgCAgY2hlY2tpbmcgZm9yIExGIGxpbmUtZW5kaW5ncyBpbiBzb3VyY2UgYW5kIG1ha2UgZmlsZXMgYW5kIHNoZWxsIHNjcmlwdHMK4pSAICBjaGVja2luZyBmb3IgZW1wdHkgb3IgdW5uZWVkZWQgZGlyZWN0b3JpZXMK4pSAICBidWlsZGluZyDigJhwZXRzXzAuMC4wLjkwMDAudGFyLmd64oCZCiAgIApSdW5uaW5nIC9MaWJyYXJ5L0ZyYW1ld29ya3MvUi5mcmFtZXdvcmsvUmVzb3VyY2VzL2Jpbi9SIENNRCBJTlNUQUxMIFwKICAvdmFyL2ZvbGRlcnMvdzYvYmd4eHF4bG42bnhmOXowd3I3ZnlweWZ3MDAwMGduL1QvL1J0bXAzSE5VNDQvcGV0c18wLjAuMC45MDAwLnRhci5neiBcCiAgLS1pbnN0YWxsLXRlc3RzIAoqIGluc3RhbGxpbmcgdG8gbGlicmFyeSDigJgvVXNlcnMvbWFyay9SX2xpYnPigJkKKiBpbnN0YWxsaW5nICpzb3VyY2UqIHBhY2thZ2Ug4oCYcGV0c+KAmSAuLi4KKiogdXNpbmcgc3RhZ2VkIGluc3RhbGxhdGlvbgoqKiBSCioqIGJ5dGUtY29tcGlsZSBhbmQgcHJlcGFyZSBwYWNrYWdlIGZvciBsYXp5IGxvYWRpbmcKKiogaGVscAoqKiogaW5zdGFsbGluZyBoZWxwIGluZGljZXMKKiogYnVpbGRpbmcgcGFja2FnZSBpbmRpY2VzCioqIHRlc3RpbmcgaWYgaW5zdGFsbGVkIHBhY2thZ2UgY2FuIGJlIGxvYWRlZCBmcm9tIHRlbXBvcmFyeSBsb2NhdGlvbgoqKiB0ZXN0aW5nIGlmIGluc3RhbGxlZCBwYWNrYWdlIGNhbiBiZSBsb2FkZWQgZnJvbSBmaW5hbCBsb2NhdGlvbgoqKiB0ZXN0aW5nIGlmIGluc3RhbGxlZCBwYWNrYWdlIGtlZXBzIGEgcmVjb3JkIG9mIHRlbXBvcmFyeSBpbnN0YWxsYXRpb24gcGF0aAoqIERPTkUgKHBldHMpCmBgYAoKOjo6IHRpcAoKQXQgdGhpcyBwb2ludCB5b3UgY2FuIHJ1biBgbGlicmFyeShwZXRzKWAgdG8gbG9hZCB0aGUgcGFja2FnZSBhbmQgdXNlIHRoZSBgY2F0cygpYCBmdW5jdGlvbi4KCjo6OgoKYGBge3IgbG9hZF9wa2csIGV2YWwgPSBGQUxTRX0KPiBsaWJyYXJ5KHBldHMpCmBgYAoKOjo6IHRpcAoKWW91IGNhbiBhbHNvIGluc3RhbGwgeW91ciBwYWNrYWdlIHZpYSB0aGUgKipCdWlsZCoqIHBhbmUgaW4gKipSU3R1ZGlvKiouCgo6OjoKCiFbXShpbWcvcnNfYnVpbGRfaW5zdGFsbC5wbmcpeyB3aWR0aD03MCUgfQoK