Saving outputs is a crucial part of responsible research data
management and directly supports the FAIR principles: making data
Findable, Accessible, Interoperable, and Reusable
FAIR
Saving outputs for reproducible research is all part of supporting
the FAIR principles, making sure your data is findable, accessible,
interoperable, and re-usable.
In this section, we will learn how to save cleaned datasets, export
plots, update metadata, and document our data processing in a
transparent and accessible way. These practices all support
reproducibility and align with the FAIR principles.
library(dplyr) # for data manipulation
library(readr) # for reading and writing data
Saving Datasets
For this section, you can continue from the previous section or load
a backup of the dataset from the resources
folder:
Rdata_path <- "data/timeuse_day3_2.Rdata"
load(Rdata_path)
The js_data
object contains the dataset we used,
transformed, and modified up to now. In this session, we will assume
this is our final dataset to deposit into a repository such as Borealis.
Saving in .csv
or .tsv
makes sure our files
are open and usable across platforms, easily imported into other
programming languages, databases, or spreadsheet software.
Computational Reproducibility
Using save()
to create an .Rdata
file is
great for putting together a ‘reproducible package’ because it stores
information related to data types and data structures. For example, it
retains which variables have been converted to factors or dates.
However, it is a file type unique to R; considering that the data may
need to be accessed by non-R users, the data should also be stored in a
more interoperable and accessible format.
In our dataset (js_data
), variables like
isFeelRushed
(a binary factor: 1 = Yes, 0 = No) or other
categorical variables (e.g., popCenter
or
feelRushed
) might appear integer-like to read_csv(), which
could misinterpret them as numeric integers instead of factors. Saving
as .RData
preserves these R-specific data types (e.g.,
factors, dates, or custom attributes), ensuring consistency when the
data is reloaded in R across different sections of our analysis.
As we have seen, we can save the js_data
in
.Rdata
format by using the save()
function:
save(js_data, file = "data/timeuse_day4_3_20250515.RData")
Interoperability and Reusability
Now, let’s save this dataset into a csv
(comma-separated
values) or tsv
(tab-separated values) file for sharing or
reuse. Both are plain text files that are
non-proprietary formats promoting
interoperability and
accessibility.
While csv
is commonly used (and what we’ve been using),
in many respects tsv
is more versatile and enhances
reusability due to the following factors:
- csv: Uses commas to separate values; it’s widely
supported but may face issues if data contains commas.
- tsv: Uses tabs as delimiters, avoiding
comma-related problems and improving readability in text editors or
spreadsheet software.
write_csv(js_data, "data/timeuse_day4_3_20250515.csv")
write_tsv(js_data, "data/timeuse_day4_3_20250515.tsv")
write_csv()
and write_tsv()
(from the
tidyverse) are fast, UTF-8 CSV writers that by default skip row names.
They also match read_csv()
and read_tsv()
(also from the tidyverse) conventions. In contrast, base R’s
write.csv()
is slower and by default writes a row-names
column.
While csv
and tsv
are accessible and
interoperable due to being plain text file formats with simple
delimiters, neither is a standard (this is why there is no single way to
handle the presence of commas in a csv
file). There are
other plain text options for storing data that are supported by
standards, such as xml
and json
, but for
rectangular data, csv
and tsv
are very simple
options that enhance accessibility to a human reader.
File Compression
One of the disadvantages of plain text file formats such as
csv
and tsv
is that they are larger than their
software-specific, or ‘binary’, counterparts. In fact, if you look at
the data files we’ve saved throughout the week, you’ll notice that the
csv
versions are significantly larger. However, depending
on the kind of data one is working with, even software-specific formats
can be quite large.
Compression is especially helpful when sharing data through email or
uploading to repositories, enhancing accessibility by
minimizing bandwidth requirements. Even though in this example we’re
working with a relatively small dataset, in real-world scenarios it’s
common to encounter csv
files containing millions of rows –
potentially several gigabytes in size. In such cases, compression
becomes not just helpful but essential to efficiently store, transfer,
and share data files, especially when uploading to platforms like OSF or
institutional repositories, such as Borealis.
Here, we’ll use the .gz
compression format, which
compresses a single file at a time.
con <- gzfile("data/timeuse_day4_3_20250515.gz", "wb")
write_csv(js_data, con)
gzfile("…", "wb")
creates an R connection that writes
directly into a gzip-compressed file, and
write_csv(js_data, con)
writes your data frame directly
into that compressed CSV file.
Why use .gz
specifically? The .gz
format is
widely supported, simple, and natively handled by R through the
gzfile()
function. It’s also compatible with most data
repositories and file-sharing platforms.
To bundle multiple files or folders (e.g., datasets, plots, and
dictionaries), you can use ZIP
compression. A
.zip
file combines several items into a single compressed
archive, which help simplify storage and make sharing easier among
collaborators or repositories.
Saving Plots
Exporting plots in multiple formats ensures your visualizations are
reusable and accessible for different
purposes: publication, presentation, or web display.
Let’s first again generate the scatterplot to show the association
between sleep and work duration from previous section.
library(ggplot2)
p <- ggplot(js_data, aes(durWork, durSleep)) +
geom_point(color = "#2D5E7F", alpha = .2) +
geom_smooth(method = lm, color = "black") +
xlab("Minutes Spent Working") +
ylab ("Minutes Spent Sleeping") +
scale_x_continuous(breaks = seq(0, 1500, 250)) +
labs(title = "Association Between Working and Sleeping") +
theme(text = element_text(size = 18))
p

PNG
PNG format is suitable for web use or slide
presentations. PNG is a raster format that offers high
quality and is widely supported across platforms.
ggsave(
filename = "outputs/association_sleep_working_day4.png",
plot = p,
width = 8,
height = 6,
dpi = 300
)
ggsave()
is a ggplot2
function that saves
your last (or specified) plot to a file, automatically picking the
correct format from the filename extension and letting you set size and
resolution.
PDF
If you want your plots to be resizable without losing quality, you
can use PDF files, as they preserve vector graphics.
This is especially useful for embedding in academic papers or generating
print-friendly outputs.
ggsave(
filename = "outputs/association_sleep_working_day4.pdf",
plot = p,
width = 8,
height = 6)
TIFF
You can save images as TIFF format, as some academic
journals request or prefer TIFF for its high resolution. This format
ensures sharp, detailed visuals suitable for professional publication
requirements.
ggsave(
filename = "outputs/association_sleep_working_day4.tiff",
plot = p,
width = 8,
height = 6,
dpi = 600,
device = "tiff"
)
Saving Documentation
Data Dictionaries
To enhance Findability and
Reusability, metadata must be kept up to date. Metadata
provides context about the data – what each variable means, what values
are allowed and how they are determined, and how data were collected.
This makes it easier for others (including your future self!) to
interpret and reuse your data.
One practical way to create and maintain metadata is to use a
data dictionary. A data dictionary is, ideally, a
structured summary that describes each variable in a dataset, including
its name, type, and label or definition.
Human-Readable vs. Machine-Readable
Data dictionaries can be designed to be
human-readable or machine-readable,
each serving distinct purposes with specific advantages and limitations.
Choosing the appropriate type depends on your audience, whether it’s
researchers reading documentation or systems processing metadata
automatically.
Human-Readable Data Dictionary
- Description: A human-readable data dictionary is
formatted for easy comprehension by people, and is typically presented
as a table in a spreadsheet (e.g., Excel) or document (e.g., PDF, Word).
It includes plain-language descriptions in natural language (e.g.,
English) and is designed to be intuitive for researchers, students, or
non-technical collaborators. For example, a PDF document containing a
table of variable descriptions is human-readable but often not
machine-readable, as it lacks structured data that represents the
relationships present in the dataset
- Example (PDF format):

Machine-Readable Data Dictionary
Description: A machine-readable data dictionary
uses structured formats like JSON, XML, YAML, or RDF, designed for
software to parse and process automatically without human involvement.
These formats align with metadata standards and are ideal for
integration with data repositories or automated systems, enabling
automatic data feeds and processing.
Example (JSON format):
[
{
"variable": "feelRushed",
"type": "integer",
"description": "Duration - Sleeping, resting, relaxing, sick in bed",
"unique_responses": 274,
"missing": 0,
"count": 17390.0,
"mean": 522.3948246118459,
"std": 133.06481348435142,
"min": 0.0,
"percentile_25": 450.0,
"median": 510.0,
"percentile_75": 585.0,
"max": 1440.0
},
{
"variable": "durSleep",
"type": "factor",
"description": "General time use - Feel rushed",
"unique_responses": 6,
"missing": 62,
"levels": [
{"value": 1.0, "label": "Every day"},
{"value": 2.0, "label": "A few times a week"},
{"value": 3.0, "label": "About once a week"},
{"value": 4.0, "label": "About once a month"},
{"value": 5.0, "label": "Less than once a month"}
{"value": 6.0, "label": "Never"}
]
}
]
Summary Table
Pros |
Accessibility: Easy to read, supports
reusability for non-technical users. Ease
of Creation: Manual or CSV export, minimal tools
needed. Broad Usability: Suits workshops/reports,
enhances accessibility. |
Interoperability: JSON/XML enable
automation, repository integration. Efficiency:
Programmatic updates reduce errors for large datasets.
Standardization: Metadata standards enhance
findability. |
Cons |
Limited Automation: Unstructured, hard
to parse, hinders interoperability. Manual
Maintenance: Manual updates risk errors in large datasets.
Scalability Issues: Inefficient for many variables.
Non-FAIR Compliance: Lacks algorithmic processing,
incompatible with FAIR. |
Technical Barrier: Needs scripting,
challenging for users. Reduced Accessibility:
Complex without tools. Format Dependency: JSON/XML
may lack universal support. Learning Curve:
Structured formats hard for new users. |
The human-readable PDF dictionary provided in the workshop is ideal
for learning and quick reference. For long-term storage or submission to
repositories like OSF or Borealis, you might want to convert it to a
machine-readable format to maximize Interoperability and
Findability
Documenting Changes
One of the most important pieces of RDM is documentation and a key
element of documentation is the process of decision making in how one
works through their data, whether that be in the cleaning or analysis
stage of the process. To this end, you should use your RMarkdown file as
a living logbook. Write clear descriptions of how your data has been
transformed, and which variables have been changed, removed, or created.
This documentation improves transparency and promotes
reusability.
Example explanation:
“We filtered the dataset to include only respondents who feel rushed
at least once a week (feelRushed
<= 3), and retained
only time-use columns for analysis.”
Remember that we can create the rushed
and
not_rushed
data frames by filtering
isFeelRushed == 1
for rushed participants and
isFeelRushed == 0
for those who are not rushed.
rushed <- js_data |>
filter(isFeelRushed == 1)
not_rushed <- js_data |>
filter(isFeelRushed == 0)
You can also track changes quantitatively:
summary_changes <- data.frame(
Step = c("Original rows", "Filtered for isFeelRushed == 1", "Final rows"),
Count = c(nrow(js_data), sum(js_data$isFeelRushed == 1, na.rm = TRUE), nrow(rushed))
)
summary_changes
## Step Count
## 1 Original rows 17390
## 2 Filtered for isFeelRushed == 1 12689
## 3 Final rows 12689
Such logs help other researchers understand your workflow and
replicate or build upon your analysis.
Saving Documents to PDF
Once you’ve saved individual datasets and plots, you’ll often want to
bundle your entire analysis – code, text, figures, and tables –
into a single file. You can export your RMarkdown document as a
PDF for a polished, human-readable output or as
HTML for a dynamic, web-friendly format. Each format
has distinct advantages and limitations, depending on your needs.
Pros |
- Human-readable. - Universally accessible. -
Consistent formatting. - Ideal for formal distribution (e.g.,
publications, reports). |
- Machine-readable. - Supports interactivity (e.g.,
collapsible code). - Web-friendly. - Smaller file sizes. |
Cons |
- Not machine-readable. - Lacks interactivity.
- Large file sizes. - Limited for web-based sharing. |
- Requires web browser or specific software. - Less
consistent formatting across devices. - May need technical setup for
sharing. |
In this section, we can practice exporting our RMarkdown document as
either PDF or HTML.
Update your YAML
At the very top of your .Rmd
file, ensure you have a
YAML header supporting both PDF and HTML outputs:
---
title: "RDM Jumpstart Workshop"
author: "Your Name"
date: "2025-05-16"
output:
pdf_document:
toc: true # optional: include table of contents
number_sections: true # optional: number your sections
html_document:
toc: true # optional: include table of contents
code_folding: show # optional: toggle code visibility
code_download: true # optional: allow downloading .Rmd
---
This tells RMarkdown to produce either a PDF via LaTeX or an HTML
file, depending on your knitting choice.
Install TinyTex
R Markdown relies on LaTeX under the hood. We recommend TinyTeX as a
simple solution. TinyTeX is lightweight and will automatically pull in
any missing LaTeX packages as you knit.
install.packages("tinytex")
tinytex::install_tinytex()
Knit
In RStudio:
- PDF: Click the arrow next to Knit and choose Knit to PDF
(or simply hit Knit if PDF is your default).
- HTML: Choose Knit to HTML for a web-friendly output with
interactive features.
Summary
Compression |
Use .csv.gz or .tsv.gz for
large files to reduce size and improve access speed. |
Interoperability |
Prefer .csv or .tsv ; avoid
locked-in formats to maximize cross-platform use. |
Naming Conventions |
Use descriptive names with dates/versions:
timeuse_day4_3_20250515.csv . |
Transparency |
Log all changes in RMarkdown; describe decisions in
plain language. |
Metadata |
Maintain and save an updated data dictionary in
human-readable (e.g., PDF) or machine-readable (e.g., JSON) formats with
rich, structured metadata, enhancing findability and
interoperability. |
Plot Formats |
Use appropriate formats (.png ,
.pdf , .tiff ) based on audience and/or
platform. |
Your Turn
Scenario 1: You’re preparing to share your fully
cleaned dataset so that collaborators using Python, SPSS, or Excel can
easily load it. Would you choose .csv
or
.Rdata
to maximize interoperability and
why?
Scenario 2: You’ve created a human-readable data
dictionary in PDF format, describing newly created variables like
isFeelRushed
. A collaborator needs a machine-readable
version, such as JSON, to share it with a data repository. Why would you
choose JSON over PDF for this purpose, and how does this support
findability and interoperability?
Scenario 3: You’ve just created a
publication-quality ggplot showing the relationship between work time
and sleep. For web sharing and for submission to an academic journal,
which file formats would you export (PNG, PDF, TIFF) and why?
Scenario 4: You need to share your RMarkdown
analysis with both a journal (requiring a formal report) and an online
community (preferring interactive content). Which output formats (PDF or
HTML) would you choose for each, and how do these choices support
accessibility and reusability?
Challenge 1: Select one plot you created in the
visualization section and save it using ggsave()
. Choose an
appropriate file format (e.g., PNG for web, PDF for papers, TIFF for
high-res), create a descriptive filename that includes the date and plot
type, and write the exact ggsave()
command you would use.
Experiment with parameters like resolution (dpi
) or
dimensions (width
, height
) to optimize the
output.
Challenge 2: Revisit your RMarkdown now and improve
the documentation of one of your data-cleaning, or data-transformation
steps. Imagine you (or a colleague who are not familiar with the
project) come back to this 6 months from now: will they understand
exactly what you did and why?
Wrap-Up
Following these practices ensures your research outputs are
understandable, reusable, and verifiable. Saving data, metadata, and
visuals properly helps you, your collaborators, and future researchers
reproduce and extend your work. More importantly, it aligns your
workflow with the FAIR principles,making your research more open,
ethical, and impactful.
Remember: every saved dataset, every labeled plot, and every comment
in your RMarkdown is a contribution toward a more FAIR research
ecosystem.
LS0tCnRpdGxlOiAiU2F2aW5nIE91dHB1dHMgZm9yIFJlcHJvZHVjaWJsZSBSZXNlYXJjaCIKcGFnZXRpdGxlOiAiU2F2aW5nIE91dHB1dHMgZm9yIFJlcHJvZHVjaWJsZSBSZXNlYXJjaCIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICBjb2RlX2ZvbGRpbmc6IHNob3cgIyBhbGxvd3MgdG9nZ2xpbmcgb2Ygc2hvd2luZyBhbmQgaGlkaW5nIGNvZGUuIFJlbW92ZSBpZiBub3QgdXNpbmcgY29kZS4KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUgIyBhbGxvd3MgdGhlIHVzZXIgdG8gZG93bmxvYWQgdGhlIHNvdXJjZSAuUm1kIGZpbGUuIFJlbW92ZSBpZiBub3QgdXNpbmcgY29kZS4KICAgIGluY2x1ZGVzOgogICAgICBhZnRlcl9ib2R5OiBmb290ZXIuaHRtbCAjIGluY2x1ZGUgYSBjdXN0b20gZm9vdGVyLgogICAgdG9jOiB0cnVlCiAgICB0b2NfZGVwdGg6IDMKICAgIHRvY19mbG9hdDoKICAgICAgY29sbGFwc2VkOiBmYWxzZQogICAgICBzbW9vdGhfc2Nyb2xsOiBmYWxzZQogICMgcGRmX2RvY3VtZW50OgogICMgICB0b2M6IHRydWUgICAgICAgICAgICAgICMgb3B0aW9uYWw6IGluY2x1ZGUgdGFibGUgb2YgY29udGVudHMKICAjICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlICAjIG9wdGlvbmFsOiBudW1iZXIgeW91ciBzZWN0aW9ucwotLS0KCjxoNCBzdHlsZT0idGV4dC1hbGlnbjpjZW50ZXI7Ij48c3Ryb25nPlNhdmluZyBvdXRwdXRzIGlzIGEgY3J1Y2lhbCBwYXJ0IG9mIHJlc3BvbnNpYmxlIHJlc2VhcmNoIGRhdGEgbWFuYWdlbWVudCBhbmQgZGlyZWN0bHkgc3VwcG9ydHMgdGhlIEZBSVIgcHJpbmNpcGxlczogbWFraW5nIGRhdGEgPGVtPkZpbmRhYmxlLCBBY2Nlc3NpYmxlLCBJbnRlcm9wZXJhYmxlLCBhbmQgUmV1c2FibGU8L2VtPjwvc3Ryb25nPjwvaDQ+CgojIyBGQUlSCgpTYXZpbmcgb3V0cHV0cyBmb3IgcmVwcm9kdWNpYmxlIHJlc2VhcmNoIGlzIGFsbCBwYXJ0IG9mIHN1cHBvcnRpbmcgdGhlIEZBSVIgcHJpbmNpcGxlcywgbWFraW5nIHN1cmUgeW91ciBkYXRhIGlzIGZpbmRhYmxlLCBhY2Nlc3NpYmxlLCBpbnRlcm9wZXJhYmxlLCBhbmQgcmUtdXNhYmxlLgoKSW4gdGhpcyBzZWN0aW9uLCB3ZSB3aWxsIGxlYXJuIGhvdyB0byBzYXZlIGNsZWFuZWQgZGF0YXNldHMsIGV4cG9ydCBwbG90cywgdXBkYXRlIG1ldGFkYXRhLCBhbmQgZG9jdW1lbnQgb3VyIGRhdGEgcHJvY2Vzc2luZyBpbiBhIHRyYW5zcGFyZW50IGFuZCBhY2Nlc3NpYmxlIHdheS4gVGhlc2UgcHJhY3RpY2VzIGFsbCBzdXBwb3J0IHJlcHJvZHVjaWJpbGl0eSBhbmQgYWxpZ24gd2l0aCB0aGUgRkFJUiBwcmluY2lwbGVzLgoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0UpCmtuaXRyOjprbml0X2VuZ2luZXMkc2V0KGpzb24gPSBmdW5jdGlvbihvcHRpb25zKSB7CiAga25pdHI6OmVuZ2luZV9vdXRwdXQob3B0aW9ucywgb3B0aW9ucyRjb2RlLCBvcHRpb25zJGNvZGUpCn0pCmBgYAoKYGBge3IsIGRhdGEtaXNvbGF0aW9uLTEsIHJlc3VsdHMgPSAnaGlkZScsIGVjaG89RkFMU0V9CmxpYnJhcnkoa2FibGVFeHRyYSkKYGBgCgpgYGB7ciwgZGF0YS1pc29sYXRpb24tMiwgcmVzdWx0cyA9ICdoaWRlJ30KbGlicmFyeShkcGx5cikgIyBmb3IgZGF0YSBtYW5pcHVsYXRpb24KbGlicmFyeShyZWFkcikgIyBmb3IgcmVhZGluZyBhbmQgd3JpdGluZyBkYXRhCmBgYAoKIyMgU2F2aW5nIERhdGFzZXRzCgpGb3IgdGhpcyBzZWN0aW9uLCB5b3UgY2FuIGNvbnRpbnVlIGZyb20gdGhlIHByZXZpb3VzIHNlY3Rpb24gb3IgbG9hZCBhIGJhY2t1cCBvZiB0aGUgZGF0YXNldCBmcm9tIHRoZSBgcmVzb3VyY2VzYCBmb2xkZXI6CgpgYGB7cn0KUmRhdGFfcGF0aCA8LSAiZGF0YS90aW1ldXNlX2RheTNfMi5SZGF0YSIKbG9hZChSZGF0YV9wYXRoKQpgYGAKClRoZSBganNfZGF0YWAgb2JqZWN0IGNvbnRhaW5zIHRoZSBkYXRhc2V0IHdlIHVzZWQsIHRyYW5zZm9ybWVkLCBhbmQgbW9kaWZpZWQgdXAgdG8gbm93LiBJbiB0aGlzIHNlc3Npb24sIHdlIHdpbGwgYXNzdW1lIHRoaXMgaXMgb3VyIGZpbmFsIGRhdGFzZXQgdG8gZGVwb3NpdCBpbnRvIGEgcmVwb3NpdG9yeSBzdWNoIGFzIEJvcmVhbGlzLiBTYXZpbmcgaW4gYC5jc3ZgIG9yIGAudHN2YCBtYWtlcyBzdXJlIG91ciBmaWxlcyBhcmUgb3BlbiBhbmQgdXNhYmxlIGFjcm9zcyBwbGF0Zm9ybXMsIGVhc2lseSBpbXBvcnRlZCBpbnRvIG90aGVyIHByb2dyYW1taW5nIGxhbmd1YWdlcywgZGF0YWJhc2VzLCBvciBzcHJlYWRzaGVldCBzb2Z0d2FyZS4KCiMjIyBDb21wdXRhdGlvbmFsIFJlcHJvZHVjaWJpbGl0eQoKVXNpbmcgYHNhdmUoKWAgdG8gY3JlYXRlIGFuIGAuUmRhdGFgIGZpbGUgaXMgZ3JlYXQgZm9yIHB1dHRpbmcgdG9nZXRoZXIgYSAncmVwcm9kdWNpYmxlIHBhY2thZ2UnIGJlY2F1c2UgaXQgc3RvcmVzIGluZm9ybWF0aW9uIHJlbGF0ZWQgdG8gZGF0YSB0eXBlcyBhbmQgZGF0YSBzdHJ1Y3R1cmVzLiBGb3IgZXhhbXBsZSwgaXQgcmV0YWlucyB3aGljaCB2YXJpYWJsZXMgaGF2ZSBiZWVuIGNvbnZlcnRlZCB0byBmYWN0b3JzIG9yIGRhdGVzLiBIb3dldmVyLCBpdCBpcyBhIGZpbGUgdHlwZSB1bmlxdWUgdG8gUjsgY29uc2lkZXJpbmcgdGhhdCB0aGUgZGF0YSBtYXkgbmVlZCB0byBiZSBhY2Nlc3NlZCBieSBub24tUiB1c2VycywgdGhlIGRhdGEgc2hvdWxkIGFsc28gYmUgc3RvcmVkIGluIGEgbW9yZSBpbnRlcm9wZXJhYmxlIGFuZCBhY2Nlc3NpYmxlIGZvcm1hdC4KCjo6Om5vdGUKSW4gb3VyIGRhdGFzZXQgKGBqc19kYXRhYCksIHZhcmlhYmxlcyBsaWtlIGBpc0ZlZWxSdXNoZWRgIChhIGJpbmFyeSBmYWN0b3I6IDEgPSBZZXMsIDAgPSBObykgb3Igb3RoZXIgY2F0ZWdvcmljYWwgdmFyaWFibGVzIChlLmcuLCBgcG9wQ2VudGVyYCBvciBgZmVlbFJ1c2hlZGApIG1pZ2h0IGFwcGVhciBpbnRlZ2VyLWxpa2UgdG8gcmVhZF9jc3YoKSwgd2hpY2ggY291bGQgbWlzaW50ZXJwcmV0IHRoZW0gYXMgbnVtZXJpYyBpbnRlZ2VycyBpbnN0ZWFkIG9mIGZhY3RvcnMuIFNhdmluZyBhcyBgLlJEYXRhYCBwcmVzZXJ2ZXMgdGhlc2UgUi1zcGVjaWZpYyBkYXRhIHR5cGVzIChlLmcuLCBmYWN0b3JzLCBkYXRlcywgb3IgY3VzdG9tIGF0dHJpYnV0ZXMpLCBlbnN1cmluZyBjb25zaXN0ZW5jeSB3aGVuIHRoZSBkYXRhIGlzIHJlbG9hZGVkIGluIFIgYWNyb3NzIGRpZmZlcmVudCBzZWN0aW9ucyBvZiBvdXIgYW5hbHlzaXMuCjo6OgoKQXMgd2UgaGF2ZSBzZWVuLCB3ZSBjYW4gc2F2ZSB0aGUgYGpzX2RhdGFgIGluIGAuUmRhdGFgIGZvcm1hdCBieSB1c2luZyB0aGUgYHNhdmUoKWAgZnVuY3Rpb246CgpgYGB7cn0Kc2F2ZShqc19kYXRhLCBmaWxlID0gImRhdGEvdGltZXVzZV9kYXk0XzNfMjAyNTA1MTUuUkRhdGEiKQpgYGAKCiMjIyBJbnRlcm9wZXJhYmlsaXR5IGFuZCBSZXVzYWJpbGl0eQoKTm93LCBsZXQncyBzYXZlIHRoaXMgZGF0YXNldCBpbnRvIGEgYGNzdmAgKGNvbW1hLXNlcGFyYXRlZCB2YWx1ZXMpIG9yIGB0c3ZgICh0YWItc2VwYXJhdGVkIHZhbHVlcykgZmlsZSBmb3Igc2hhcmluZyBvciByZXVzZS4gQm90aCBhcmUgcGxhaW4gdGV4dCBmaWxlcyB0aGF0IGFyZSBfX25vbi1wcm9wcmlldGFyeV9fIGZvcm1hdHMgcHJvbW90aW5nICoqaW50ZXJvcGVyYWJpbGl0eSoqIGFuZCAqKmFjY2Vzc2liaWxpdHkqKi4KCldoaWxlIGBjc3ZgIGlzIGNvbW1vbmx5IHVzZWQgKGFuZCB3aGF0IHdlJ3ZlIGJlZW4gdXNpbmcpLCBpbiBtYW55IHJlc3BlY3RzIGB0c3ZgIGlzIG1vcmUgdmVyc2F0aWxlIGFuZCBlbmhhbmNlcyAqKnJldXNhYmlsaXR5KiogZHVlIHRvIHRoZSBmb2xsb3dpbmcgZmFjdG9yczoKCi0gKipjc3YqKjogVXNlcyBjb21tYXMgdG8gc2VwYXJhdGUgdmFsdWVzOyBpdCdzIHdpZGVseSBzdXBwb3J0ZWQgYnV0IG1heSBmYWNlIGlzc3VlcyBpZiBkYXRhIGNvbnRhaW5zIGNvbW1hcy4KLSAqKnRzdioqOiBVc2VzIHRhYnMgYXMgZGVsaW1pdGVycywgYXZvaWRpbmcgY29tbWEtcmVsYXRlZCBwcm9ibGVtcyBhbmQgaW1wcm92aW5nIHJlYWRhYmlsaXR5IGluIHRleHQgZWRpdG9ycyBvciBzcHJlYWRzaGVldCBzb2Z0d2FyZS4KCmBgYHtyfQp3cml0ZV9jc3YoanNfZGF0YSwgImRhdGEvdGltZXVzZV9kYXk0XzNfMjAyNTA1MTUuY3N2IikKd3JpdGVfdHN2KGpzX2RhdGEsICJkYXRhL3RpbWV1c2VfZGF5NF8zXzIwMjUwNTE1LnRzdiIpCmBgYAoKOjo6bm90ZQpgd3JpdGVfY3N2KClgICBhbmQgYHdyaXRlX3RzdigpYCAoZnJvbSB0aGUgdGlkeXZlcnNlKSBhcmUgZmFzdCwgVVRGLTggQ1NWIHdyaXRlcnMgdGhhdCBieSBkZWZhdWx0IHNraXAgcm93IG5hbWVzLiBUaGV5IGFsc28gbWF0Y2ggYHJlYWRfY3N2KClgIGFuZCBgcmVhZF90c3YoKWAgKGFsc28gZnJvbSB0aGUgdGlkeXZlcnNlKSBjb252ZW50aW9ucy4gSW4gY29udHJhc3QsIGJhc2UgUuKAmXMgYHdyaXRlLmNzdigpYCBpcyBzbG93ZXIgYW5kIGJ5IGRlZmF1bHQgd3JpdGVzIGEgcm93LW5hbWVzIGNvbHVtbi4KOjo6Cgo6Ojpub3RlCldoaWxlIGBjc3ZgIGFuZCBgdHN2YCBhcmUgYWNjZXNzaWJsZSBhbmQgaW50ZXJvcGVyYWJsZSBkdWUgdG8gYmVpbmcgcGxhaW4gdGV4dCBmaWxlIGZvcm1hdHMgd2l0aCBzaW1wbGUgZGVsaW1pdGVycywgbmVpdGhlciBpcyBhIHN0YW5kYXJkICh0aGlzIGlzIHdoeSB0aGVyZSBpcyBubyBzaW5nbGUgd2F5IHRvIGhhbmRsZSB0aGUgcHJlc2VuY2Ugb2YgY29tbWFzIGluIGEgYGNzdmAgZmlsZSkuIFRoZXJlIGFyZSBvdGhlciBwbGFpbiB0ZXh0IG9wdGlvbnMgZm9yIHN0b3JpbmcgZGF0YSB0aGF0IGFyZSBzdXBwb3J0ZWQgYnkgc3RhbmRhcmRzLCBzdWNoIGFzIGB4bWxgIGFuZCBganNvbmAsIGJ1dCBmb3IgcmVjdGFuZ3VsYXIgZGF0YSwgYGNzdmAgYW5kIGB0c3ZgIGFyZSB2ZXJ5IHNpbXBsZSBvcHRpb25zIHRoYXQgZW5oYW5jZSBhY2Nlc3NpYmlsaXR5IHRvIGEgaHVtYW4gcmVhZGVyLiAKOjo6CgojIyMgRmlsZSBDb21wcmVzc2lvbgoKT25lIG9mIHRoZSBkaXNhZHZhbnRhZ2VzIG9mIHBsYWluIHRleHQgZmlsZSBmb3JtYXRzIHN1Y2ggYXMgYGNzdmAgYW5kIGB0c3ZgIGlzIHRoYXQgdGhleSBhcmUgbGFyZ2VyIHRoYW4gdGhlaXIgc29mdHdhcmUtc3BlY2lmaWMsIG9yICdiaW5hcnknLCBjb3VudGVycGFydHMuIEluIGZhY3QsIGlmIHlvdSBsb29rIGF0IHRoZSBkYXRhIGZpbGVzIHdlJ3ZlIHNhdmVkIHRocm91Z2hvdXQgdGhlIHdlZWssIHlvdSdsbCBub3RpY2UgdGhhdCB0aGUgYGNzdmAgdmVyc2lvbnMgYXJlIHNpZ25pZmljYW50bHkgbGFyZ2VyLiBIb3dldmVyLCBkZXBlbmRpbmcgb24gdGhlIGtpbmQgb2YgZGF0YSBvbmUgaXMgd29ya2luZyB3aXRoLCBldmVuIHNvZnR3YXJlLXNwZWNpZmljIGZvcm1hdHMgY2FuIGJlIHF1aXRlIGxhcmdlLgoKQ29tcHJlc3Npb24gaXMgZXNwZWNpYWxseSBoZWxwZnVsIHdoZW4gc2hhcmluZyBkYXRhIHRocm91Z2ggZW1haWwgb3IgdXBsb2FkaW5nIHRvIHJlcG9zaXRvcmllcywgZW5oYW5jaW5nICoqYWNjZXNzaWJpbGl0eSoqIGJ5IG1pbmltaXppbmcgYmFuZHdpZHRoIHJlcXVpcmVtZW50cy4gRXZlbiB0aG91Z2ggaW4gdGhpcyBleGFtcGxlIHdlJ3JlIHdvcmtpbmcgd2l0aCBhIHJlbGF0aXZlbHkgc21hbGwgZGF0YXNldCwgaW4gcmVhbC13b3JsZCBzY2VuYXJpb3MgaXQncyBjb21tb24gdG8gZW5jb3VudGVyIGBjc3ZgIGZpbGVzIGNvbnRhaW5pbmcgbWlsbGlvbnMgb2Ygcm93cyAtLSBwb3RlbnRpYWxseSBzZXZlcmFsIGdpZ2FieXRlcyBpbiBzaXplLiBJbiBzdWNoIGNhc2VzLCBjb21wcmVzc2lvbiBiZWNvbWVzIG5vdCBqdXN0IGhlbHBmdWwgYnV0IGVzc2VudGlhbCB0byBlZmZpY2llbnRseSBzdG9yZSwgdHJhbnNmZXIsIGFuZCBzaGFyZSBkYXRhIGZpbGVzLCBlc3BlY2lhbGx5IHdoZW4gdXBsb2FkaW5nIHRvIHBsYXRmb3JtcyBsaWtlIE9TRiBvciBpbnN0aXR1dGlvbmFsIHJlcG9zaXRvcmllcywgc3VjaCBhcyBCb3JlYWxpcy4KCkhlcmUsIHdlJ2xsIHVzZSB0aGUgYC5nemAgY29tcHJlc3Npb24gZm9ybWF0LCB3aGljaCBjb21wcmVzc2VzIGEgc2luZ2xlIGZpbGUgYXQgYSB0aW1lLgoKYGBge3J9CmNvbiA8LSBnemZpbGUoImRhdGEvdGltZXVzZV9kYXk0XzNfMjAyNTA1MTUuZ3oiLCAid2IiKQp3cml0ZV9jc3YoanNfZGF0YSwgY29uKQpgYGAKCjo6OndhbGt0aHJvdWdoCmBnemZpbGUoIuKApiIsICJ3YiIpYCBjcmVhdGVzIGFuIFIgY29ubmVjdGlvbiB0aGF0IHdyaXRlcyBkaXJlY3RseSBpbnRvIGEgZ3ppcC1jb21wcmVzc2VkIGZpbGUsIGFuZCBgd3JpdGVfY3N2KGpzX2RhdGEsIGNvbilgIHdyaXRlcyB5b3VyIGRhdGEgZnJhbWUgZGlyZWN0bHkgaW50byB0aGF0IGNvbXByZXNzZWQgQ1NWIGZpbGUuCjo6OgoKOjo6bm90ZQpXaHkgdXNlIGAuZ3pgIHNwZWNpZmljYWxseT8gVGhlIGAuZ3pgIGZvcm1hdCBpcyB3aWRlbHkgc3VwcG9ydGVkLCBzaW1wbGUsIGFuZCBuYXRpdmVseSBoYW5kbGVkIGJ5IFIgdGhyb3VnaCB0aGUgYGd6ZmlsZSgpYCBmdW5jdGlvbi4gSXQncyBhbHNvIGNvbXBhdGlibGUgd2l0aCBtb3N0IGRhdGEgcmVwb3NpdG9yaWVzIGFuZCBmaWxlLXNoYXJpbmcgcGxhdGZvcm1zLiAKOjo6CgpUbyBidW5kbGUgbXVsdGlwbGUgZmlsZXMgb3IgZm9sZGVycyAoZS5nLiwgZGF0YXNldHMsIHBsb3RzLCBhbmQgZGljdGlvbmFyaWVzKSwgeW91IGNhbiB1c2UgYFpJUGAgY29tcHJlc3Npb24uIEEgYC56aXBgIGZpbGUgY29tYmluZXMgc2V2ZXJhbCBpdGVtcyBpbnRvIGEgc2luZ2xlIGNvbXByZXNzZWQgYXJjaGl2ZSwgd2hpY2ggaGVscCBzaW1wbGlmeSBzdG9yYWdlIGFuZCBtYWtlIHNoYXJpbmcgZWFzaWVyIGFtb25nIGNvbGxhYm9yYXRvcnMgb3IgcmVwb3NpdG9yaWVzLiAKCiMjIFNhdmluZyBQbG90cwoKRXhwb3J0aW5nIHBsb3RzIGluIG11bHRpcGxlIGZvcm1hdHMgZW5zdXJlcyB5b3VyIHZpc3VhbGl6YXRpb25zIGFyZSAqKnJldXNhYmxlKiogYW5kICoqYWNjZXNzaWJsZSoqIGZvciBkaWZmZXJlbnQgcHVycG9zZXM6IHB1YmxpY2F0aW9uLCBwcmVzZW50YXRpb24sIG9yIHdlYiBkaXNwbGF5LgoKTGV0J3MgZmlyc3QgYWdhaW4gZ2VuZXJhdGUgdGhlIHNjYXR0ZXJwbG90IHRvIHNob3cgdGhlIGFzc29jaWF0aW9uIGJldHdlZW4gc2xlZXAgYW5kIHdvcmsgZHVyYXRpb24gZnJvbSBwcmV2aW91cyBzZWN0aW9uLgoKYGBge3IsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTZ9CmxpYnJhcnkoZ2dwbG90MikKCnAgPC0gZ2dwbG90KGpzX2RhdGEsIGFlcyhkdXJXb3JrLCBkdXJTbGVlcCkpICsKICBnZW9tX3BvaW50KGNvbG9yID0gIiMyRDVFN0YiLCBhbHBoYSA9IC4yKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gbG0sIGNvbG9yID0gImJsYWNrIikgKwogIHhsYWIoIk1pbnV0ZXMgU3BlbnQgV29ya2luZyIpICsKICB5bGFiICgiTWludXRlcyBTcGVudCBTbGVlcGluZyIpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDE1MDAsIDI1MCkpICsKICBsYWJzKHRpdGxlID0gIkFzc29jaWF0aW9uIEJldHdlZW4gV29ya2luZyBhbmQgU2xlZXBpbmciKSArCiAgdGhlbWUodGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTgpKQoKcApgYGAKCgojIyMgUE5HCgoqKlBORyoqIGZvcm1hdCBpcyBzdWl0YWJsZSBmb3Igd2ViIHVzZSBvciBzbGlkZSBwcmVzZW50YXRpb25zLiAqKlBORyoqIGlzIGEgcmFzdGVyIGZvcm1hdCB0aGF0IG9mZmVycyBoaWdoIHF1YWxpdHkgYW5kIGlzIHdpZGVseSBzdXBwb3J0ZWQgYWNyb3NzIHBsYXRmb3Jtcy4KCgpgYGB7cn0KZ2dzYXZlKAogIGZpbGVuYW1lID0gIm91dHB1dHMvYXNzb2NpYXRpb25fc2xlZXBfd29ya2luZ19kYXk0LnBuZyIsIAogIHBsb3QgPSBwLCAKICB3aWR0aCA9IDgsIAogIGhlaWdodCA9IDYsIAogIGRwaSA9IDMwMAogICkKYGBgCgo6Ojp3YWxrdGhyb3VnaApgZ2dzYXZlKClgIGlzIGEgYGdncGxvdDJgIGZ1bmN0aW9uIHRoYXQgc2F2ZXMgeW91ciBsYXN0IChvciBzcGVjaWZpZWQpIHBsb3QgdG8gYSBmaWxlLCBhdXRvbWF0aWNhbGx5IHBpY2tpbmcgdGhlIGNvcnJlY3QgZm9ybWF0IGZyb20gdGhlIGZpbGVuYW1lIGV4dGVuc2lvbiBhbmQgbGV0dGluZyB5b3Ugc2V0IHNpemUgYW5kIHJlc29sdXRpb24uCjo6OgoKIyMjIFBERgoKSWYgeW91IHdhbnQgeW91ciBwbG90cyB0byBiZSByZXNpemFibGUgd2l0aG91dCBsb3NpbmcgcXVhbGl0eSwgeW91IGNhbiB1c2UgKipQREYqKiBmaWxlcywgYXMgdGhleSBwcmVzZXJ2ZSB2ZWN0b3IgZ3JhcGhpY3MuIFRoaXMgaXMgZXNwZWNpYWxseSB1c2VmdWwgZm9yIGVtYmVkZGluZyBpbiBhY2FkZW1pYyBwYXBlcnMgb3IgZ2VuZXJhdGluZyBwcmludC1mcmllbmRseSBvdXRwdXRzLgoKYGBge3J9Cmdnc2F2ZSgKICBmaWxlbmFtZSA9ICJvdXRwdXRzL2Fzc29jaWF0aW9uX3NsZWVwX3dvcmtpbmdfZGF5NC5wZGYiLCAKICBwbG90ID0gcCwgCiAgd2lkdGggPSA4LCAKICBoZWlnaHQgPSA2KQpgYGAKCgojIyMgVElGRgoKWW91IGNhbiBzYXZlIGltYWdlcyBhcyAqKlRJRkYqKiBmb3JtYXQsIGFzIHNvbWUgYWNhZGVtaWMgam91cm5hbHMgcmVxdWVzdCBvciBwcmVmZXIgVElGRiBmb3IgaXRzIGhpZ2ggcmVzb2x1dGlvbi4gVGhpcyBmb3JtYXQgZW5zdXJlcyBzaGFycCwgZGV0YWlsZWQgdmlzdWFscyBzdWl0YWJsZSBmb3IgcHJvZmVzc2lvbmFsIHB1YmxpY2F0aW9uIHJlcXVpcmVtZW50cy4KCmBgYHtyfQpnZ3NhdmUoCiAgZmlsZW5hbWUgPSAib3V0cHV0cy9hc3NvY2lhdGlvbl9zbGVlcF93b3JraW5nX2RheTQudGlmZiIsCiAgcGxvdCAgICAgPSBwLAogIHdpZHRoICAgID0gOCwKICBoZWlnaHQgICA9IDYsCiAgZHBpICAgICAgPSA2MDAsCiAgZGV2aWNlICAgPSAidGlmZiIKKQpgYGAKCgojIyBTYXZpbmcgRG9jdW1lbnRhdGlvbgoKIyMjIERhdGEgRGljdGlvbmFyaWVzCgpUbyBlbmhhbmNlICoqRmluZGFiaWxpdHkqKiBhbmQgKipSZXVzYWJpbGl0eSoqLCBtZXRhZGF0YSBtdXN0IGJlIGtlcHQgdXAgdG8gZGF0ZS4gTWV0YWRhdGEgcHJvdmlkZXMgY29udGV4dCBhYm91dCB0aGUgZGF0YSAtLSB3aGF0IGVhY2ggdmFyaWFibGUgbWVhbnMsIHdoYXQgdmFsdWVzIGFyZSBhbGxvd2VkIGFuZCBob3cgdGhleSBhcmUgZGV0ZXJtaW5lZCwgYW5kIGhvdyBkYXRhIHdlcmUgY29sbGVjdGVkLiBUaGlzIG1ha2VzIGl0IGVhc2llciBmb3Igb3RoZXJzIChpbmNsdWRpbmcgeW91ciBmdXR1cmUgc2VsZiEpIHRvIGludGVycHJldCBhbmQgcmV1c2UgeW91ciBkYXRhLgoKT25lIHByYWN0aWNhbCB3YXkgdG8gY3JlYXRlIGFuZCBtYWludGFpbiBtZXRhZGF0YSBpcyB0byB1c2UgYSAqKmRhdGEgZGljdGlvbmFyeSoqLiBBIGRhdGEgZGljdGlvbmFyeSBpcywgaWRlYWxseSwgYSBzdHJ1Y3R1cmVkIHN1bW1hcnkgdGhhdCBkZXNjcmliZXMgZWFjaCB2YXJpYWJsZSBpbiBhIGRhdGFzZXQsIGluY2x1ZGluZyBpdHMgbmFtZSwgdHlwZSwgYW5kIGxhYmVsIG9yIGRlZmluaXRpb24uCgojIyMjIEh1bWFuLVJlYWRhYmxlIHZzLiBNYWNoaW5lLVJlYWRhYmxlCgpEYXRhIGRpY3Rpb25hcmllcyBjYW4gYmUgZGVzaWduZWQgdG8gYmUgKipodW1hbi1yZWFkYWJsZSoqIG9yICoqbWFjaGluZS1yZWFkYWJsZSoqLCBlYWNoIHNlcnZpbmcgZGlzdGluY3QgcHVycG9zZXMgd2l0aCBzcGVjaWZpYyBhZHZhbnRhZ2VzIGFuZCBsaW1pdGF0aW9ucy4gQ2hvb3NpbmcgdGhlIGFwcHJvcHJpYXRlIHR5cGUgZGVwZW5kcyBvbiB5b3VyIGF1ZGllbmNlLCB3aGV0aGVyIGl04oCZcyByZXNlYXJjaGVycyByZWFkaW5nIGRvY3VtZW50YXRpb24gb3Igc3lzdGVtcyBwcm9jZXNzaW5nIG1ldGFkYXRhIGF1dG9tYXRpY2FsbHkuCgoqKkh1bWFuLVJlYWRhYmxlIERhdGEgRGljdGlvbmFyeSoqCgoqICoqRGVzY3JpcHRpb24qKjogQSBodW1hbi1yZWFkYWJsZSBkYXRhIGRpY3Rpb25hcnkgaXMgZm9ybWF0dGVkIGZvciBlYXN5IGNvbXByZWhlbnNpb24gYnkgcGVvcGxlLCBhbmQgaXMgdHlwaWNhbGx5IHByZXNlbnRlZCBhcyBhIHRhYmxlIGluIGEgc3ByZWFkc2hlZXQgKGUuZy4sIEV4Y2VsKSBvciBkb2N1bWVudCAoZS5nLiwgUERGLCBXb3JkKS4gSXQgaW5jbHVkZXMgcGxhaW4tbGFuZ3VhZ2UgZGVzY3JpcHRpb25zIGluIG5hdHVyYWwgbGFuZ3VhZ2UgKGUuZy4sIEVuZ2xpc2gpIGFuZCBpcyBkZXNpZ25lZCB0byBiZSBpbnR1aXRpdmUgZm9yIHJlc2VhcmNoZXJzLCBzdHVkZW50cywgb3Igbm9uLXRlY2huaWNhbCBjb2xsYWJvcmF0b3JzLiBGb3IgZXhhbXBsZSwgYSBQREYgZG9jdW1lbnQgY29udGFpbmluZyBhIHRhYmxlIG9mIHZhcmlhYmxlIGRlc2NyaXB0aW9ucyBpcyBodW1hbi1yZWFkYWJsZSBidXQgb2Z0ZW4gbm90IG1hY2hpbmUtcmVhZGFibGUsIGFzIGl0IGxhY2tzIHN0cnVjdHVyZWQgZGF0YSB0aGF0IHJlcHJlc2VudHMgdGhlIHJlbGF0aW9uc2hpcHMgcHJlc2VudCBpbiB0aGUgZGF0YXNldCAKKiAqKkV4YW1wbGUqKiAoUERGIGZvcm1hdCk6CiAgIVtFeGFtcGxlIG9mIGEgSHVtYW4tUmVhZGFibGUgRGF0YSBEaWN0aW9uYXJ5XShpbWFnZXMvNC1BQ1QtMy1kYXRhZGljdGlvbmFyeVBERi5wbmcpCgoqKk1hY2hpbmUtUmVhZGFibGUgRGF0YSBEaWN0aW9uYXJ5KioKCiogKipEZXNjcmlwdGlvbioqOiBBIG1hY2hpbmUtcmVhZGFibGUgZGF0YSBkaWN0aW9uYXJ5IHVzZXMgc3RydWN0dXJlZCBmb3JtYXRzIGxpa2UgSlNPTiwgWE1MLCBZQU1MLCBvciBSREYsIGRlc2lnbmVkIGZvciBzb2Z0d2FyZSB0byBwYXJzZSBhbmQgcHJvY2VzcyBhdXRvbWF0aWNhbGx5IHdpdGhvdXQgaHVtYW4gaW52b2x2ZW1lbnQuIFRoZXNlIGZvcm1hdHMgYWxpZ24gd2l0aCBtZXRhZGF0YSBzdGFuZGFyZHMgYW5kIGFyZSBpZGVhbCBmb3IgaW50ZWdyYXRpb24gd2l0aCBkYXRhIHJlcG9zaXRvcmllcyBvciBhdXRvbWF0ZWQgc3lzdGVtcywgZW5hYmxpbmcgYXV0b21hdGljIGRhdGEgZmVlZHMgYW5kIHByb2Nlc3NpbmcuCiogKipFeGFtcGxlKiogKEpTT04gZm9ybWF0KToKICBgYGB7anNvbiwgcmVzdWx0cyA9ICdoaWRlJ30KICAgIFsKICAgIHsKICAgICAgInZhcmlhYmxlIjogImZlZWxSdXNoZWQiLAogICAgICAidHlwZSI6ICJpbnRlZ2VyIiwKICAgICAgImRlc2NyaXB0aW9uIjogIkR1cmF0aW9uIC0gU2xlZXBpbmcsIHJlc3RpbmcsIHJlbGF4aW5nLCBzaWNrIGluIGJlZCIsCiAgICAgICJ1bmlxdWVfcmVzcG9uc2VzIjogMjc0LAogICAgICAibWlzc2luZyI6IDAsCiAgICAgICJjb3VudCI6IDE3MzkwLjAsCiAgICAgICJtZWFuIjogNTIyLjM5NDgyNDYxMTg0NTksCiAgICAgICJzdGQiOiAxMzMuMDY0ODEzNDg0MzUxNDIsCiAgICAgICJtaW4iOiAwLjAsCiAgICAgICJwZXJjZW50aWxlXzI1IjogNDUwLjAsCiAgICAgICJtZWRpYW4iOiA1MTAuMCwKICAgICAgInBlcmNlbnRpbGVfNzUiOiA1ODUuMCwKICAgICAgIm1heCI6IDE0NDAuMAogICAgfSwKICAgIHsKICAgICAgInZhcmlhYmxlIjogImR1clNsZWVwIiwKICAgICAgInR5cGUiOiAiZmFjdG9yIiwKICAgICAgImRlc2NyaXB0aW9uIjogIkdlbmVyYWwgdGltZSB1c2UgLSBGZWVsIHJ1c2hlZCIsCiAgICAgICJ1bmlxdWVfcmVzcG9uc2VzIjogNiwKICAgICAgIm1pc3NpbmciOiA2MiwKICAgICAgImxldmVscyI6IFsKICAgICAgICB7InZhbHVlIjogMS4wLCAibGFiZWwiOiAiRXZlcnkgZGF5In0sCiAgICAgICAgeyJ2YWx1ZSI6IDIuMCwgImxhYmVsIjogIkEgZmV3IHRpbWVzIGEgd2VlayJ9LAogICAgICAgIHsidmFsdWUiOiAzLjAsICJsYWJlbCI6ICJBYm91dCBvbmNlIGEgd2VlayJ9LAogICAgICAgIHsidmFsdWUiOiA0LjAsICJsYWJlbCI6ICJBYm91dCBvbmNlIGEgbW9udGgifSwKICAgICAgICB7InZhbHVlIjogNS4wLCAibGFiZWwiOiAiTGVzcyB0aGFuIG9uY2UgYSBtb250aCJ9CiAgICAgICAgeyJ2YWx1ZSI6IDYuMCwgImxhYmVsIjogIk5ldmVyIn0gICAgICAKICAgICAgXQogICAgfQogIF0KICBgYGAKICAKKipTdW1tYXJ5IFRhYmxlKioKCjo6Om1kLXRhYmxlCnwgQXNwZWN0IHwgSHVtYW4tUmVhZGFibGUgRGF0YSBEaWN0aW9uYXJ5IHwgTWFjaGluZS1SZWFkYWJsZSBEYXRhIERpY3Rpb25hcnkgfAp8IDotLS0gfCA6LS0tIHwgOi0tLSB8CnwgKipQcm9zKiogfCAqKkFjY2Vzc2liaWxpdHkqKjogRWFzeSB0byByZWFkLCBzdXBwb3J0cyAqKnJldXNhYmlsaXR5KiogZm9yIG5vbi10ZWNobmljYWwgdXNlcnMuIDxicj4qKkVhc2Ugb2YgQ3JlYXRpb24qKjogTWFudWFsIG9yIENTViBleHBvcnQsIG1pbmltYWwgdG9vbHMgbmVlZGVkLjxicj4qKkJyb2FkIFVzYWJpbGl0eSoqOiBTdWl0cyB3b3Jrc2hvcHMvcmVwb3J0cywgZW5oYW5jZXMgKiphY2Nlc3NpYmlsaXR5KiouIHwgKipJbnRlcm9wZXJhYmlsaXR5Kio6IEpTT04vWE1MIGVuYWJsZSBhdXRvbWF0aW9uLCByZXBvc2l0b3J5IGludGVncmF0aW9uLjxicj4gKipFZmZpY2llbmN5Kio6IFByb2dyYW1tYXRpYyB1cGRhdGVzIHJlZHVjZSBlcnJvcnMgZm9yIGxhcmdlIGRhdGFzZXRzLjxicj4gKipTdGFuZGFyZGl6YXRpb24qKjogTWV0YWRhdGEgc3RhbmRhcmRzIGVuaGFuY2UgKipmaW5kYWJpbGl0eSoqLiB8CnwgKipDb25zKiogfCAgKipMaW1pdGVkIEF1dG9tYXRpb24qKjogVW5zdHJ1Y3R1cmVkLCBoYXJkIHRvIHBhcnNlLCBoaW5kZXJzICoqaW50ZXJvcGVyYWJpbGl0eSoqLjxicj4gKipNYW51YWwgTWFpbnRlbmFuY2UqKjogTWFudWFsIHVwZGF0ZXMgcmlzayBlcnJvcnMgaW4gbGFyZ2UgZGF0YXNldHMuPGJyPiAqKlNjYWxhYmlsaXR5IElzc3VlcyoqOiBJbmVmZmljaWVudCBmb3IgbWFueSB2YXJpYWJsZXMuPGJyPiAqKk5vbi1GQUlSIENvbXBsaWFuY2UqKjogTGFja3MgYWxnb3JpdGhtaWMgcHJvY2Vzc2luZywgaW5jb21wYXRpYmxlIHdpdGggRkFJUi4gfCAqKlRlY2huaWNhbCBCYXJyaWVyKio6IE5lZWRzIHNjcmlwdGluZywgY2hhbGxlbmdpbmcgZm9yIHVzZXJzLjxicj4gKipSZWR1Y2VkIEFjY2Vzc2liaWxpdHkqKjogQ29tcGxleCB3aXRob3V0IHRvb2xzLjxicj4gKipGb3JtYXQgRGVwZW5kZW5jeSoqOiBKU09OL1hNTCBtYXkgbGFjayB1bml2ZXJzYWwgc3VwcG9ydC48YnI+ICoqTGVhcm5pbmcgQ3VydmUqKjogU3RydWN0dXJlZCBmb3JtYXRzIGhhcmQgZm9yIG5ldyB1c2Vycy4gfAo6OjoKCjo6Om5vdGUKVGhlIGh1bWFuLXJlYWRhYmxlIFBERiBkaWN0aW9uYXJ5IHByb3ZpZGVkIGluIHRoZSB3b3Jrc2hvcCBpcyBpZGVhbCBmb3IgbGVhcm5pbmcgYW5kIHF1aWNrIHJlZmVyZW5jZS4gRm9yIGxvbmctdGVybSBzdG9yYWdlIG9yIHN1Ym1pc3Npb24gdG8gcmVwb3NpdG9yaWVzIGxpa2UgT1NGIG9yIEJvcmVhbGlzLCB5b3UgbWlnaHQgd2FudCB0byBjb252ZXJ0IGl0IHRvIGEgbWFjaGluZS1yZWFkYWJsZSBmb3JtYXQgdG8gbWF4aW1pemUgKkludGVyb3BlcmFiaWxpdHkqIGFuZCAqRmluZGFiaWxpdHkqCjo6OgoKIyMjIERvY3VtZW50aW5nIENoYW5nZXMKCk9uZSBvZiB0aGUgbW9zdCBpbXBvcnRhbnQgcGllY2VzIG9mIFJETSBpcyBkb2N1bWVudGF0aW9uIGFuZCBhIGtleSBlbGVtZW50IG9mIGRvY3VtZW50YXRpb24gaXMgdGhlIHByb2Nlc3Mgb2YgZGVjaXNpb24gbWFraW5nIGluIGhvdyBvbmUgd29ya3MgdGhyb3VnaCB0aGVpciBkYXRhLCB3aGV0aGVyIHRoYXQgYmUgaW4gdGhlIGNsZWFuaW5nIG9yIGFuYWx5c2lzIHN0YWdlIG9mIHRoZSBwcm9jZXNzLiBUbyB0aGlzIGVuZCwgeW91IHNob3VsZCB1c2UgeW91ciBSTWFya2Rvd24gZmlsZSBhcyBhIGxpdmluZyBsb2dib29rLiBXcml0ZSBjbGVhciBkZXNjcmlwdGlvbnMgb2YgaG93IHlvdXIgZGF0YSBoYXMgYmVlbiB0cmFuc2Zvcm1lZCwgYW5kIHdoaWNoIHZhcmlhYmxlcyBoYXZlIGJlZW4gY2hhbmdlZCwgcmVtb3ZlZCwgb3IgY3JlYXRlZC4gVGhpcyBkb2N1bWVudGF0aW9uIGltcHJvdmVzICoqdHJhbnNwYXJlbmN5KiogYW5kIHByb21vdGVzICoqcmV1c2FiaWxpdHkqKi4KCkV4YW1wbGUgZXhwbGFuYXRpb246Cgo+ICJXZSBmaWx0ZXJlZCB0aGUgZGF0YXNldCB0byBpbmNsdWRlIG9ubHkgcmVzcG9uZGVudHMgd2hvIGZlZWwgcnVzaGVkIGF0IGxlYXN0IG9uY2UgYSB3ZWVrIChgZmVlbFJ1c2hlZGAgPD0gMyksIGFuZCByZXRhaW5lZCBvbmx5IHRpbWUtdXNlIGNvbHVtbnMgZm9yIGFuYWx5c2lzLiIKCgpSZW1lbWJlciB0aGF0IHdlIGNhbiBjcmVhdGUgdGhlIGBydXNoZWRgIGFuZCBgbm90X3J1c2hlZGAgZGF0YSBmcmFtZXMgYnkgZmlsdGVyaW5nIGBpc0ZlZWxSdXNoZWQgPT0gMWAgZm9yIHJ1c2hlZCBwYXJ0aWNpcGFudHMgYW5kIGBpc0ZlZWxSdXNoZWQgPT0gMGAgZm9yIHRob3NlIHdobyBhcmUgbm90IHJ1c2hlZC4KCgpgYGB7cn0KcnVzaGVkIDwtIGpzX2RhdGEgfD4gCiAgZmlsdGVyKGlzRmVlbFJ1c2hlZCA9PSAxKQoKbm90X3J1c2hlZCA8LSBqc19kYXRhIHw+IAogIGZpbHRlcihpc0ZlZWxSdXNoZWQgPT0gMCkKYGBgCgpZb3UgY2FuIGFsc28gdHJhY2sgY2hhbmdlcyBxdWFudGl0YXRpdmVseToKCmBgYHtyfQpzdW1tYXJ5X2NoYW5nZXMgPC0gZGF0YS5mcmFtZSgKICBTdGVwID0gYygiT3JpZ2luYWwgcm93cyIsICJGaWx0ZXJlZCBmb3IgaXNGZWVsUnVzaGVkID09IDEiLCAiRmluYWwgcm93cyIpLAogIENvdW50ID0gYyhucm93KGpzX2RhdGEpLCBzdW0oanNfZGF0YSRpc0ZlZWxSdXNoZWQgPT0gMSwgbmEucm0gPSBUUlVFKSwgbnJvdyhydXNoZWQpKQopCnN1bW1hcnlfY2hhbmdlcwpgYGAKClN1Y2ggbG9ncyBoZWxwIG90aGVyIHJlc2VhcmNoZXJzIHVuZGVyc3RhbmQgeW91ciB3b3JrZmxvdyBhbmQgcmVwbGljYXRlIG9yIGJ1aWxkIHVwb24geW91ciBhbmFseXNpcy4KCiMjIyBTYXZpbmcgRG9jdW1lbnRzIHRvIFBERgoKT25jZSB5b3UndmUgc2F2ZWQgaW5kaXZpZHVhbCBkYXRhc2V0cyBhbmQgcGxvdHMsIHlvdSdsbCBvZnRlbiB3YW50IHRvIGJ1bmRsZSB5b3VyICplbnRpcmUqIGFuYWx5c2lzIC0tIGNvZGUsIHRleHQsIGZpZ3VyZXMsIGFuZCB0YWJsZXMgLS0gaW50byBhIHNpbmdsZSBmaWxlLiBZb3UgY2FuIGV4cG9ydCB5b3VyIFJNYXJrZG93biBkb2N1bWVudCBhcyBhICoqUERGKiogZm9yIGEgcG9saXNoZWQsIGh1bWFuLXJlYWRhYmxlIG91dHB1dCBvciBhcyAqKkhUTUwqKiBmb3IgYSBkeW5hbWljLCB3ZWItZnJpZW5kbHkgZm9ybWF0LiBFYWNoIGZvcm1hdCBoYXMgZGlzdGluY3QgYWR2YW50YWdlcyBhbmQgbGltaXRhdGlvbnMsIGRlcGVuZGluZyBvbiB5b3VyIG5lZWRzLgoKOjo6bWQtdGFibGUKfCBBc3BlY3QgfCBQREYgT3V0cHV0IHwgSFRNTCBPdXRwdXQgfAp8IDotLS0gfCA6LS0tIHwgOi0tLSB8CnwgKipQcm9zKiogfCAtIEh1bWFuLXJlYWRhYmxlLjxicj4tIFVuaXZlcnNhbGx5IGFjY2Vzc2libGUuPGJyPi0gQ29uc2lzdGVudCBmb3JtYXR0aW5nLjxicj4tIElkZWFsIGZvciBmb3JtYWwgZGlzdHJpYnV0aW9uIChlLmcuLCBwdWJsaWNhdGlvbnMsIHJlcG9ydHMpLiB8IC0gTWFjaGluZS1yZWFkYWJsZS48YnI+LSBTdXBwb3J0cyBpbnRlcmFjdGl2aXR5IChlLmcuLCBjb2xsYXBzaWJsZSBjb2RlKS48YnI+LSBXZWItZnJpZW5kbHkuPGJyPi0gU21hbGxlciBmaWxlIHNpemVzLiB8CnwgKipDb25zKiogfCAtIE5vdCBtYWNoaW5lLXJlYWRhYmxlLiA8YnI+LSBMYWNrcyBpbnRlcmFjdGl2aXR5LiA8YnI+LSBMYXJnZSBmaWxlIHNpemVzLjxicj4tIExpbWl0ZWQgZm9yIHdlYi1iYXNlZCBzaGFyaW5nLiB8IC0gUmVxdWlyZXMgd2ViIGJyb3dzZXIgb3Igc3BlY2lmaWMgc29mdHdhcmUuPGJyPi0gTGVzcyBjb25zaXN0ZW50IGZvcm1hdHRpbmcgYWNyb3NzIGRldmljZXMuPGJyPi0gTWF5IG5lZWQgdGVjaG5pY2FsIHNldHVwIGZvciBzaGFyaW5nLiB8Cjo6OgoKSW4gdGhpcyBzZWN0aW9uLCB3ZSBjYW4gcHJhY3RpY2UgZXhwb3J0aW5nIG91ciBSTWFya2Rvd24gZG9jdW1lbnQgYXMgZWl0aGVyIFBERiBvciBIVE1MLgoKIyMjIyBVcGRhdGUgeW91ciBZQU1MCgpBdCB0aGUgdmVyeSB0b3Agb2YgeW91ciBgLlJtZGAgZmlsZSwgZW5zdXJlIHlvdSBoYXZlIGEgWUFNTCBoZWFkZXIgc3VwcG9ydGluZyBib3RoIFBERiBhbmQgSFRNTCBvdXRwdXRzOgoKYGBgeWFtbAotLS0KdGl0bGU6ICJSRE0gSnVtcHN0YXJ0IFdvcmtzaG9wIgphdXRob3I6ICJZb3VyIE5hbWUiCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OgogIHBkZl9kb2N1bWVudDoKICAgIHRvYzogdHJ1ZSAgICAgICAgICAgICAgIyBvcHRpb25hbDogaW5jbHVkZSB0YWJsZSBvZiBjb250ZW50cwogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlICAjIG9wdGlvbmFsOiBudW1iZXIgeW91ciBzZWN0aW9ucwogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IHRydWUgICAgICAgICAgICAgICMgb3B0aW9uYWw6IGluY2x1ZGUgdGFibGUgb2YgY29udGVudHMKICAgIGNvZGVfZm9sZGluZzogc2hvdyAgICAgIyBvcHRpb25hbDogdG9nZ2xlIGNvZGUgdmlzaWJpbGl0eQogICAgY29kZV9kb3dubG9hZDogdHJ1ZSAgICAjIG9wdGlvbmFsOiBhbGxvdyBkb3dubG9hZGluZyAuUm1kCi0tLQpgYGAKClRoaXMgdGVsbHMgUk1hcmtkb3duIHRvIHByb2R1Y2UgZWl0aGVyIGEgUERGIHZpYSBMYVRlWCBvciBhbiBIVE1MIGZpbGUsIGRlcGVuZGluZyBvbiB5b3VyIGtuaXR0aW5nIGNob2ljZS4KCiMjIyMgSW5zdGFsbCBUaW55VGV4CgpSIE1hcmtkb3duIHJlbGllcyBvbiBMYVRlWCB1bmRlciB0aGUgaG9vZC4gV2UgcmVjb21tZW5kIFRpbnlUZVggYXMgYSBzaW1wbGUgc29sdXRpb24uIFRpbnlUZVggaXMgbGlnaHR3ZWlnaHQgYW5kIHdpbGwgYXV0b21hdGljYWxseSBwdWxsIGluIGFueSBtaXNzaW5nIExhVGVYIHBhY2thZ2VzIGFzIHlvdSBrbml0LgoKYGBge3IsIGV2YWw9RkFMU0V9Cmluc3RhbGwucGFja2FnZXMoInRpbnl0ZXgiKQoKdGlueXRleDo6aW5zdGFsbF90aW55dGV4KCkKYGBgCgojIyMjIEtuaXQKCkluIFJTdHVkaW86IAoKLSAqUERGKjogQ2xpY2sgdGhlIGFycm93IG5leHQgdG8gS25pdCBhbmQgY2hvb3NlIEtuaXQgdG8gUERGIChvciBzaW1wbHkgaGl0IEtuaXQgaWYgUERGIGlzIHlvdXIgZGVmYXVsdCkuCi0gKkhUTUwqOiBDaG9vc2UgS25pdCB0byBIVE1MIGZvciBhIHdlYi1mcmllbmRseSBvdXRwdXQgd2l0aCBpbnRlcmFjdGl2ZSBmZWF0dXJlcy4KCgojIyBTdW1tYXJ5Cgp8IFRvcGljICAgICAgICAgICAgICAgICAgfCBSZWNvbW1lbmRhdGlvbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAp8IDotLS0tLS0tLS0tLS0tLS0tLS0tLS0gfCA6LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIHwKfCAqKkNvbXByZXNzaW9uKiogICAgICAgIHwgVXNlIGAuY3N2Lmd6YCBvciBgLnRzdi5nemAgZm9yIGxhcmdlIGZpbGVzIHRvIHJlZHVjZSBzaXplIGFuZCBpbXByb3ZlIGFjY2VzcyBzcGVlZC4gfAp8ICoqSW50ZXJvcGVyYWJpbGl0eSoqICAgfCBQcmVmZXIgYC5jc3ZgIG9yIGAudHN2YDsgYXZvaWQgbG9ja2VkLWluIGZvcm1hdHMgdG8gbWF4aW1pemUgY3Jvc3MtcGxhdGZvcm0gdXNlLiB8CnwgKipOYW1pbmcgQ29udmVudGlvbnMqKiB8IFVzZSBkZXNjcmlwdGl2ZSBuYW1lcyB3aXRoIGRhdGVzL3ZlcnNpb25zOiBgdGltZXVzZV9kYXk0XzNfMjAyNTA1MTUuY3N2YC4gICAgfAp8ICoqVHJhbnNwYXJlbmN5KiogICAgICAgfCBMb2cgYWxsIGNoYW5nZXMgaW4gUk1hcmtkb3duOyBkZXNjcmliZSBkZWNpc2lvbnMgaW4gcGxhaW4gbGFuZ3VhZ2UuICAgICAgICAgICAgfAp8ICoqTWV0YWRhdGEqKiAgICAgICAgICAgfCBNYWludGFpbiBhbmQgc2F2ZSBhbiB1cGRhdGVkIGRhdGEgZGljdGlvbmFyeSBpbiBodW1hbi1yZWFkYWJsZSAoZS5nLiwgUERGKSBvciBtYWNoaW5lLXJlYWRhYmxlIChlLmcuLCBKU09OKSBmb3JtYXRzIHdpdGggcmljaCwgc3RydWN0dXJlZCBtZXRhZGF0YSwgZW5oYW5jaW5nICoqZmluZGFiaWxpdHkqKiBhbmQgKippbnRlcm9wZXJhYmlsaXR5KiouIHwKfCAqKlBsb3QgRm9ybWF0cyoqICAgICAgIHwgVXNlIGFwcHJvcHJpYXRlIGZvcm1hdHMgKGAucG5nYCwgYC5wZGZgLCBgLnRpZmZgKSBiYXNlZCBvbiBhdWRpZW5jZSBhbmQvb3IgcGxhdGZvcm0uICB8CgojIyBZb3VyIFR1cm4KCjo6OnF1ZXN0aW9uCioqU2NlbmFyaW8gMSoqOiBZb3XigJlyZSBwcmVwYXJpbmcgdG8gc2hhcmUgeW91ciBmdWxseSBjbGVhbmVkIGRhdGFzZXQgc28gdGhhdCBjb2xsYWJvcmF0b3JzIHVzaW5nIFB5dGhvbiwgU1BTUywgb3IgRXhjZWwgY2FuIGVhc2lseSBsb2FkIGl0LiBXb3VsZCB5b3UgY2hvb3NlIGAuY3N2YCBvciBgLlJkYXRhYCB0byBtYXhpbWl6ZSAqKmludGVyb3BlcmFiaWxpdHkqKiBhbmQgd2h5Pwo6OjoKCjo6OnF1ZXN0aW9uCioqU2NlbmFyaW8gMioqOiBZb3XigJl2ZSBjcmVhdGVkIGEgaHVtYW4tcmVhZGFibGUgZGF0YSBkaWN0aW9uYXJ5IGluIFBERiBmb3JtYXQsIGRlc2NyaWJpbmcgbmV3bHkgY3JlYXRlZCB2YXJpYWJsZXMgbGlrZSBgaXNGZWVsUnVzaGVkYC4gQSBjb2xsYWJvcmF0b3IgbmVlZHMgYSBtYWNoaW5lLXJlYWRhYmxlIHZlcnNpb24sIHN1Y2ggYXMgSlNPTiwgdG8gc2hhcmUgaXQgd2l0aCBhIGRhdGEgcmVwb3NpdG9yeS4gV2h5IHdvdWxkIHlvdSBjaG9vc2UgSlNPTiBvdmVyIFBERiBmb3IgdGhpcyBwdXJwb3NlLCBhbmQgaG93IGRvZXMgdGhpcyBzdXBwb3J0ICoqZmluZGFiaWxpdHkqKiBhbmQgKippbnRlcm9wZXJhYmlsaXR5Kio/Cjo6OgoKOjo6cXVlc3Rpb24KKipTY2VuYXJpbyAzKio6IFlvdeKAmXZlIGp1c3QgY3JlYXRlZCBhIHB1YmxpY2F0aW9uLXF1YWxpdHkgZ2dwbG90IHNob3dpbmcgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHdvcmsgdGltZSBhbmQgc2xlZXAuIEZvciB3ZWIgc2hhcmluZyBhbmQgZm9yIHN1Ym1pc3Npb24gdG8gYW4gYWNhZGVtaWMgam91cm5hbCwgd2hpY2ggZmlsZSBmb3JtYXRzIHdvdWxkIHlvdSBleHBvcnQgKFBORywgUERGLCBUSUZGKSBhbmQgd2h5PyAKOjo6Cgo6OjpxdWVzdGlvbgoqKlNjZW5hcmlvIDQqKjogWW91IG5lZWQgdG8gc2hhcmUgeW91ciBSTWFya2Rvd24gYW5hbHlzaXMgd2l0aCBib3RoIGEgam91cm5hbCAocmVxdWlyaW5nIGEgZm9ybWFsIHJlcG9ydCkgYW5kIGFuIG9ubGluZSBjb21tdW5pdHkgKHByZWZlcnJpbmcgaW50ZXJhY3RpdmUgY29udGVudCkuIFdoaWNoIG91dHB1dCBmb3JtYXRzIChQREYgb3IgSFRNTCkgd291bGQgeW91IGNob29zZSBmb3IgZWFjaCwgYW5kIGhvdyBkbyB0aGVzZSBjaG9pY2VzIHN1cHBvcnQgKiphY2Nlc3NpYmlsaXR5KiogYW5kICoqcmV1c2FiaWxpdHkqKj8KOjo6Cgo6OjogcXVlc3Rpb24KKipDaGFsbGVuZ2UgMSoqOiBTZWxlY3Qgb25lIHBsb3QgeW91IGNyZWF0ZWQgaW4gdGhlIHZpc3VhbGl6YXRpb24gc2VjdGlvbiBhbmQgc2F2ZSBpdCB1c2luZyBgZ2dzYXZlKClgLiBDaG9vc2UgYW4gYXBwcm9wcmlhdGUgZmlsZSBmb3JtYXQgKGUuZy4sIFBORyBmb3Igd2ViLCBQREYgZm9yIHBhcGVycywgVElGRiBmb3IgaGlnaC1yZXMpLCBjcmVhdGUgYSBkZXNjcmlwdGl2ZSBmaWxlbmFtZSB0aGF0IGluY2x1ZGVzIHRoZSBkYXRlIGFuZCBwbG90IHR5cGUsIGFuZCB3cml0ZSB0aGUgZXhhY3QgYGdnc2F2ZSgpYCBjb21tYW5kIHlvdSB3b3VsZCB1c2UuIEV4cGVyaW1lbnQgd2l0aCBwYXJhbWV0ZXJzIGxpa2UgcmVzb2x1dGlvbiAoYGRwaWApIG9yIGRpbWVuc2lvbnMgKGB3aWR0aGAsIGBoZWlnaHRgKSB0byBvcHRpbWl6ZSB0aGUgb3V0cHV0Lgo6OjoKICAKOjo6IHF1ZXN0aW9uCioqQ2hhbGxlbmdlIDI6KiogUmV2aXNpdCB5b3VyIFJNYXJrZG93biBub3cgYW5kIGltcHJvdmUgdGhlIGRvY3VtZW50YXRpb24gb2Ygb25lIG9mIHlvdXIgZGF0YS1jbGVhbmluZywgb3IgZGF0YS10cmFuc2Zvcm1hdGlvbiBzdGVwcy4gSW1hZ2luZSB5b3UgKG9yIGEgY29sbGVhZ3VlIHdobyBhcmUgbm90IGZhbWlsaWFyIHdpdGggdGhlIHByb2plY3QpIGNvbWUgYmFjayB0byB0aGlzIDYgbW9udGhzIGZyb20gbm93OiB3aWxsIHRoZXkgdW5kZXJzdGFuZCBleGFjdGx5IHdoYXQgeW91IGRpZCBhbmQgd2h5PyAgCjo6OgoKIyMgV3JhcC1VcAoKRm9sbG93aW5nIHRoZXNlIHByYWN0aWNlcyBlbnN1cmVzIHlvdXIgcmVzZWFyY2ggb3V0cHV0cyBhcmUgdW5kZXJzdGFuZGFibGUsIHJldXNhYmxlLCBhbmQgdmVyaWZpYWJsZS4gU2F2aW5nIGRhdGEsIG1ldGFkYXRhLCBhbmQgdmlzdWFscyBwcm9wZXJseSBoZWxwcyB5b3UsIHlvdXIgY29sbGFib3JhdG9ycywgYW5kIGZ1dHVyZSByZXNlYXJjaGVycyByZXByb2R1Y2UgYW5kIGV4dGVuZCB5b3VyIHdvcmsuIE1vcmUgaW1wb3J0YW50bHksIGl0IGFsaWducyB5b3VyIHdvcmtmbG93IHdpdGggdGhlIEZBSVIgcHJpbmNpcGxlcyxtYWtpbmcgeW91ciByZXNlYXJjaCBtb3JlIG9wZW4sIGV0aGljYWwsIGFuZCBpbXBhY3RmdWwuCgo6Ojpub3RlIApSZW1lbWJlcjogZXZlcnkgc2F2ZWQgZGF0YXNldCwgZXZlcnkgbGFiZWxlZCBwbG90LCBhbmQgZXZlcnkgY29tbWVudCBpbiB5b3VyIFJNYXJrZG93biBpcyBhIGNvbnRyaWJ1dGlvbiB0b3dhcmQgYSBtb3JlIEZBSVIgcmVzZWFyY2ggZWNvc3lzdGVtLgo6OjoK