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): Example of a Human-Readable Data Dictionary

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

Aspect Human-Readable Data Dictionary Machine-Readable Data Dictionary
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.

Aspect PDF Output HTML Output
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

Topic Recommendation
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