Associated Material

Zoom notes: Zoom Notes 05 - Communicate

Readings:

Introducing RMarkdown

So far through this course we’ve been using Rscripts for analysis which lets us save and run our R code, including comments about what we’re doing along the way. We’re now going to introduce RMarkdown documents - which are like Rscripts on steroids!

RMarkdown is a framework that enables the creation of reproducible documents which are a combination of text, R code, and the evaluated output from the code all embedded in a single document. Not only that, but from a single RMarkdown source document, multiple different output formats can be produced such as HTML, PDF, and Word docs.

In fact this entire course has been written using RMarkdown! At the top right of each page is a Code button that will let you download the RMarkdown code that created the page.


Below is an example of an RMarkdown source document

---
title: "Abridged Gapminder Analysis"
date: 2022-04-13
output: html_document
---

```{r setup, include = FALSE}
library(tidyverse)
```

# Introduction

Load in the Gapminder dataset so that it is ready for analysis

```{r read.csv}
# Save an imported data frame into a named variable
gapminder_data <- read_csv("gapminder_data_2007.csv")
```

There are `r nrow(gapminder_data)` rows to the dataset.

## Visualise Life Expectancy

This is a histogram of the life expectancy.

```{r hist}
# Histogram of life expectancy values from gapminder
gapminder_data %>% 
  ggplot(aes(x = lifeExp)) + 
  geom_histogram()
```

There are three main components to this document

  1. The YAML header which is surrounded by ---s and provides information for the compiling process
  2. R code chunks which are surrounded by ```s
  3. Text which can be formatted using the Markdown language.

A reference guide of RMarkdown syntax can be found through Help -> Cheat Sheets -> R Markdown Reference Guide in the RStudio menu.


Example RMarkdown

Before we delve into explaining each part of the RMarkdown file we’re going to create our own from the included template that comes with RStudio.

Lets create our own RMarkdown document now from the template. To do this go File -> New File -> R Markdown. You’ll then be presented with a window that looks like this

Take the opportunity to fill in your name and title then click OK.

You should now have a document that looks like the following:

---
title: "My First Rmd"
author: "Murray"
date: '2022-04-13'
output: html_document
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```

## R Markdown

This is an R Markdown document. Markdown is a simple formatting syntax for authoring HTML, PDF, and MS Word documents. For more details on using R Markdown see <http://rmarkdown.rstudio.com>.

When you click the **Knit** button a document will be generated that includes both content as well as the output of any embedded R code chunks within the document. You can embed an R code chunk like this:

```{r cars}
summary(cars)
```

## Including Plots

You can also embed plots, for example:

```{r pressure, echo=FALSE}
plot(pressure)
```

Note that the `echo = FALSE` parameter was added to the code chunk to prevent printing of the R code that generated the plot.

RStudio Visual Editor

From Rstudio v1.2 there has been the inclusion of a live-preview editor that can be turned on that provides a graphical point-and-click method of editing Markdown.

Source view

Source view


Visual view

Visual view


Documentation for how to use the editor and its functionality can be found at https://rstudio.github.io/visual-markdown-editing/


Knitting

In order to get our output document, we need to do a compiling step or knit the document - behind the scenes the text portions are formatted based on the markdown syntax, the R code is run and the results generated, and then the formatted text, code, and results are “knitted” together as a single output.

One of the key benefits on a reproducibility side is that RMarkdown is evaluated from top to bottom externally from your session and so it needs to be self-reliant and have all the commands from reading your data in, processing it, and making your awesome tables and plots like in the Visualisation Module.

To knit the document look for the knit button in the top left of the “source” panel. The keyboard shortcut is Ctrl + Shift + K on PC or Apple + Shift + K on MacOS.

You will then be prompted to save this script, call it “r_markdown_example.Rmd” as save it in your scripts/ directory within your project directory. Once you have knitted a window should pop-up containing your brand new analysis document!

RMarkdown scripts generally have the file extension .Rmd.

Take a few minutes to read from top to bottom through your script and identifying the same features in your outputted HTML document.


Markdown syntax

Markdown is a simplified language that uses symbols to encode formatting of text in a compiled document. Markdown documents can be converted to HTML or LaTeX (used for PDF) through Pandoc (which comes bundled with RStudio).

Headings

Headers - these use the # for the largest heading (header 1) through to ###### the smallest heading (level 6) and correspond to the h1 to h6 heading tags in HTML.

# Level 1 heading

## level 2 heading

### level 3 heading

#### level 4 heading

##### level 5 heading

###### level 6 heading


We’ll cover some more of the common text formatting now, where you’ll see the rendered paragraph followed by the markdown syntax that was used to generate it:

Bold/Italics

Italics is encoded by surrounding word(s) with with a single asterisk (*) or underscore (_), bold uses double asterisks ** or underscores __. To superscript something, surround it with carets (^), and to subscript surround it with tilde (~). Surrounding with double tildes will strikethrough.

*Italics* is encoded by surrounding word(s) with with a single asterisk (\*) or underscore (_), **bold** uses double asterisks ** or underscores __. To ^super^script something, surround it with carets (^), and to ~sub~script surround it with tilde (~). Surrounding with double tildes will ~~strikethrough~~.


Lists

Unordered lists can be made by starting a line with either a dash (-) or an asterisk (*) and if you want to nest items use a tab or two spaces to indent per layer.

  • item 1
  • item 2
  • item 3
    • subitem 1
    • subitem 2
      • sub sub item 1
  • item 4
- item 1
- item 2
- item 3
  - subitem 1
  - subitem 2
    - sub sub item 1
- item 4

Ordered lists start the line with a number followed by a fullstop. It is possible to nest unordered and ordered lists within the same list

  1. item 1
  2. item 2
  3. item 3
1. item 1
2. item 2
3. item 3


Block quotes

block quotes are a way of including blocks of text from someone else. To use these that the line with a > angle bracket

> block quotes are a way of including blocks of text from someone else. To use these begin the line with a > angle bracket


Verbatim code

If you want to include code in your document, the use of verbatim blocks will stop the symbols being interpreted for markdown and will be reproduced asis in the document.
These blocks are started and ended with three backticks ```

```
If you want to include code in your document as has been done to demonstrate the markdown code that generated each of the example paragraphs, the use of verbatim blocks will stop the symbols being interpreted for markdown and will be reproduced as is in the document.
Theses blocks are started and ended with three backticks ```
```

You can also do inline verbatim by surrounding the text with a single backtick

You can also do `inline verbatim` by surrounding the text with a single backtick

Code Chunks

Markdown provides verbatim code chunks, however where RMarkdown really comes into its own is the ability to have the code that is included evaluated and the results also embedded directly below the code that was created them. While it’s called RMarkdown you’re also not just limited to R but other languages can be included and run (so long as the underlying engines are set up)

A code chunk takes this format, similar to to the verbatim code chunk but following the first three backticks are curly braces, and inside the name of the language in lower case - in this case “r”

```{r}
1 + 2
```

Would produce

1 + 2
#> [1] 3


Working directory

The working directory or location that R is going to start looking for specified files (e.g. a csv to read in) for an RMarkdown will default to the location the RMarkdown file is saved. This can be a common source of errors in compiling an RMarkdown document if your RMarkdown is saved in a subdirectory and you don’t have your file paths correct.

Don’t use setwd() in an RMarkdown. It will cause issues.

If you are using an RStudio project and structure as introduced in Introducing R and Rstudio you can make use of the here package which provides a nice way of dealing with relative file paths as if you were navigating from the top of your project directory.

For instance given the following project setup:

my_project/
  |- data/
      \- my_csv.csv
  |- docs/
  |- outputs/
  |- scripts/
      \- my_rmd.Rmd
  \ - my_project.Rproj
  

If we were working on the file my_rmd.Rmd without the use of here we would need to use relative paths from scripts/ (we want to use relative paths within our project because they aren’t dependant on any particular computer making our project transferable) and the command to read data in would look like this:

my_data <- read_csv("../data/my_csv.csv")

Using here everything is relative from the .Rproj file which can be easier to think of since it follows a relative path the same structure as the project, not relative to where the file you’re currently working on lives - here works all that out for you:

library(here)
my_data <- read_csv(here("data/my_csv.csv"))


Code Chunk Options

The behaviour of the code chunks can be modified with options. These options are provided inside the {}’s of the code chunk and are comma separated.

The defaults for a chunk are:

```{r, eval=TRUE, echo=TRUE, message=TRUE, include=TRUE, warning=TRUE}
1 + 2
```
  • echo=TRUE will “echo” the code that is run above the results
  • eval=TRUE means the code inside the chunk will be evaluated (run)
  • include=TRUE means the code and the results will be included in the document
  • warning=TRUE will include any warnings as output in the document
  • message=TRUE will include messages as output in the document

These can individually be specified and set to FALSE to disable the specific behaviour.

Images, Figures and Tables

Images

Inserting images into RMarkdown documents can be done in two main ways

  1. Through markdown with ![alt text](path/to/image)
  2. Using a code chunk and the include_graphics() function from knitr

The second method give you more control over the display of the image in the output because you can use the code chunk options to such as

  • fig.align to control the alignment on the page of the image
  • fig.cap to provide a figure caption
  • out.width controls the output width
  • out.height controls the output height

Figures

Images generated through code such as plots will automatically be included as the output underneath the code that created them.

The figure placement and size can be controlled through the code chunk options

  • fig.align to control the alignment on the page of the image
  • fig.cap to provide a figure caption
  • fig.width controls the output width
  • fig.height controls the output height
  • fig.asp can be used to scale a figure

Tables

Tables can be created manually through markdown using the following syntax

col 1 | col 2 | col 3
---|---|---
row 1 | a | 1
row 2 | b | 2

which creates the following table:

col 1 col 2 col 3
row 1 a 1
row 2 b 2

But these table can be quite laborious to create and customise. They also will need to be manually updated if your data changes. A better option is to create tables directly from your data using the kable() function from knitr which will take a dataframe and automatically create the markdown for it.

library(palmerpenguins)
library(knitr)

penguins_small <- head(penguins, n = 10)

kable(penguins_small)
species island bill_length_mm bill_depth_mm flipper_length_mm body_mass_g sex year
Adelie Torgersen 39.1 18.7 181 3750 male 2007
Adelie Torgersen 39.5 17.4 186 3800 female 2007
Adelie Torgersen 40.3 18.0 195 3250 female 2007
Adelie Torgersen NA NA NA NA NA 2007
Adelie Torgersen 36.7 19.3 193 3450 female 2007
Adelie Torgersen 39.3 20.6 190 3650 male 2007
Adelie Torgersen 38.9 17.8 181 3625 female 2007
Adelie Torgersen 39.2 19.6 195 4675 male 2007
Adelie Torgersen 34.1 18.1 193 3475 NA 2007
Adelie Torgersen 42.0 20.2 190 4250 NA 2007

These kable tables can be further customised from the function parameters such as col.names to provide a vector of column names for the table, digits to round numbers, and align to control the alignment of the columns.

The additional customisation can be achieved through the use of the kableExtra package which provides numerous extra function for the the customisation of tables in both HTML and LaTeX which differ slightly in what is possible in each format. But they both include features such as row/column/cell colouring, text formatting, groupings, and footnotes.


Here is an example of some extra customisations that could be done to the original table that was demonstrated above with kable. If your customisations on your table rely on the data staying the same they might need to be redone if you update the data in the table.

library(palmerpenguins)
library(knitr)
library(kableExtra)

penguins_small <- head(penguins, n = 10)

# kbl comes from kableExtra and is a version of kable()
kableExtra::kbl(penguins_small, 
    col.names = c("Species", 
                  "Island", 
                  "Bill Length", 
                  "Bill Depth", 
                  "Flipper Length", 
                  "Body Mass (g)", 
                  "Sex", 
                  "Year"), 
    align = "llrrrrcr",
    caption = "A table showing the measurements of the first 10 penguins from the Palmers Penguins dataset.") %>% 
  kableExtra::kable_styling(full_width = TRUE,
                            position = 'center',
                            font_size = 16,
                            bootstrap_options = 'striped') %>% 
  # add in a grouping header for the columns using mm
  kableExtra::add_header_above(header = c("",
                                          "", 
                                          "Measurements (mm)" = 3, 
                                          "", 
                                          "", 
                                          ""))
A table showing the measurements of the first 10 penguins from the Palmers Penguins dataset.
Measurements (mm)
Species Island Bill Length Bill Depth Flipper Length Body Mass (g) Sex Year
Adelie Torgersen 39.1 18.7 181 3750 male 2007
Adelie Torgersen 39.5 17.4 186 3800 female 2007
Adelie Torgersen 40.3 18.0 195 3250 female 2007
Adelie Torgersen NA NA NA NA NA 2007
Adelie Torgersen 36.7 19.3 193 3450 female 2007
Adelie Torgersen 39.3 20.6 190 3650 male 2007
Adelie Torgersen 38.9 17.8 181 3625 female 2007
Adelie Torgersen 39.2 19.6 195 4675 male 2007
Adelie Torgersen 34.1 18.1 193 3475 NA 2007
Adelie Torgersen 42.0 20.2 190 4250 NA 2007


Citations

Citations can be inserted into an RMarkdown document. This document from RStudio goes through how to do it using ether Markdown or with the visual editor which can be linked with a citation manager such as Zotero, or by searching DOIs and more.


Quarto

Pre-requisite: In order to use Quarto you will need to install the Quarto program which RStudio can then use to compile the Quarto. See https://quarto.org/docs/get-started/

RMarkdown is an extremely useful format for creating reproducible reports, however, there are some key features that are missing (without additional packages and tweaking) which you will find you need if you want to use it for making documents like theses or manuscripts, the easiest to point to is cross-referencing to figures and tables in your text (the packages bookdown and thesisdown do add this functionality to RMarkdown).

Quarto is the next iteration of RMarkdown, and has taken much of the functionality that the extra packages created to expand on RMarkdown had, and includes them right from the get-go. Not only that, but Quarto has been designed from the start to have multi-language support, so if you find yourself working in another language such as python, then this same document publishing system is still available to you.

By and large, Quarto and RMarkdown are extremely similar - they both share the three main components:

  1. YAML header
  2. Markdown blocks
  3. Code chunks

Where they differ is there are some slight syntax changes, largely in the YAML header and how options are given to code chunks.

The first difference is that instead of being saved with a .Rmd file extension, a quarto document has the extension .qmd. And instead of the Knit button, it’s called Render.

YAML Header

The YAML header is the first place where there is a main difference. Instead of output: html_document we use format: html. e.g.

---
title: "My Quarto Document"
format: html
author: "Murray Cadzow"
---

Code chunks

The code part of the code chunks are exactly the same with quarto as in RMarkdown. Where they differ is how the chunk options are provided. Instead of them being placed within the curly braces, they can be listed inside the block at the top following a #|, using the key: value syntax like in the YAML header, instead of using =.

```{r}
#| eval: false

1 + 2
```

Conclusion

This module has only scratched the surface of what is possible with the highly versatile format that is RMarkdown. The main benefit that RMarkdown is that it provides a mechanism to create reproducible analysis documents that include prose, code, and generated outputs.

Make sure to check out RMarkdown - the definitive guide for a comprehensive introduction and guide to the possibilities of RMarkdown. There are also packages for creating multi-document RMarkdown outputs such as entire websites (packagedown, distill), blogs (blogdown), and books (bookdown).

LS0tCnRpdGxlOiAiQ29tbXVuaWNhdGUiCmRhdGU6ICJTZW1lc3RlciAyLCAyMDIzIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICB0b2NfZGVwdGg6IDMKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIGNvZGVfZm9sZGluZzogc2hvdwotLS0KCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQpsaWJyYXJ5KGtuaXRyKQoKa25pdHI6Om9wdHNfY2h1bmskc2V0KAogIGNvbW1lbnQgPSAiIz4iLAogIGZpZy5wYXRoID0gImZpZ3VyZXMvMDUvIiwgIyB1c2Ugb25seSBmb3Igc2luZ2xlIFJtZCBmaWxlcwogIGNvbGxhcHNlID0gVFJVRSwKICBlY2hvID0gVFJVRQopCgoKYGBgCgo+ICMjIyMgQXNzb2NpYXRlZCBNYXRlcmlhbAo+Cj4gWm9vbSBub3RlczogW1pvb20gTm90ZXMgMDUgLSBDb21tdW5pY2F0ZV0oem9vbV9ub3Rlc18wNV9jb21tdW5pY2F0ZS5odG1sKQo+Cj4gUmVhZGluZ3M6Cj4KPiAtICAgW1IgZm9yIERhdGEgU2NpZW5jZSAtIENoYXB0ZXIgMjddKGh0dHBzOi8vcjRkcy5oYWQuY28ubnovci1tYXJrZG93bi5odG1sKQo+IC0gICBbUiBmb3IgRGF0YSBTY2llbmNlIC0gQ2hhcHRlciAyOV0oaHR0cHM6Ly9yNGRzLmhhZC5jby5uei9yLW1hcmtkb3duLWZvcm1hdHMuaHRtbCkKPiAtICAgW1JlZmVyZW5jZTogUk1hcmtkb3duIC0gdGhlIGRlZmluaXRpdmUgZ3VpZGVdKGh0dHBzOi8vYm9va2Rvd24ub3JnL3lpaHVpL3JtYXJrZG93bi8pCj4gLSAgIFtSTWFya2Rvd24gUmVmZXJlbmNlIEd1aWRlXShodHRwczovL3d3dy5yc3R1ZGlvLmNvbS93cC1jb250ZW50L3VwbG9hZHMvMjAxNS8wMy9ybWFya2Rvd24tcmVmZXJlbmNlLnBkZikKPiAtICAgW1IgZm9yIERhdGEgU2NpZW5jZSAtIFF1YXJ0b10oaHR0cHM6Ly9yNGRzLmhhZGxleS5uei9xdWFydG8uaHRtbCkKCmBgYHs9aHRtbH0KPCEtLQpUaGlzIG1vZHVsZSBpcyBnb2luZyB0byBjb3ZlcjogCgotIHVzaW5nIHRoZSB7aGVyZX0gcGFja2FnZSB0byBtYW5hZ2UgcGF0aHMgZm9yIHNjcmlwdHMgYW5kIHJtYXJrZG93bgoKLSBVc2luZyB0aGUgZG9jdW1lbnQgb3V0bGluZS9jb2xsYXBzaW5nIGNvZGUgaW4gUnNjcmlwdHMKLSAoYnJpZWZseSkgY29udmVydGluZyBhIFIgc2NyaXB0IGludG8gYSBub3RlYm9vawoKVGhlIG1haW4gZm9jdXMgd2lsbCBiZSBvbiBjb3ZlcmluZyB0aGUgdXNlZnVsbmVzcyBvZiBSbWFya2Rvd24gaW4gY3JlYXRpbmcgZGVzY3JpcHRpdmUgYW5hbHlzaXMgZG9jdW1lbnRzCgpDb3ZlciB0aGUgYmFzaWNzIG9mIHRoZSAzIGNvbXBvbmVudHMgb2YgYW4gUm1hcmtkb3duIGRvY3VtZW50Ci0geWFtbAotIG1hcmtkb3duCi0gY29kZSBjaHVua3MKCkludHJvZHVjZSB0aGUgYmFzaWMgc3ludGF4IG9mIE1hcmtkb3duCi0gaGVhZGVycwotIGJvbGQvaXRhbGljcwotIGxpc3RzCi0gdmVyYmF0aW0gY29kZQoKCk9wdGlvbnMgb2YgYSBjb2RlIGNodW5rCi0gZWNobwotIGV2YWwKLSBpbmNsdWRlCi0gd2FybmluZwotIG1lc3NhZ2UKLSBmaWcKLSByZXN1bHRzCi0gaW5saW5lIGNvZGUKCkVtYmVkZGluZyBpbWFnZXMKLSBpbWFnZXMKICAtIGtuaXRyOjppbmNsdWRlX2dyYXBoaWNzCiAgLSBgIVtdKClgCiAgCkVtYmVkZGluZyBwbG90cwoKCk1ha2luZyB0YWJsZXMKLSBtYXJrZG93bgotIGtuaXRyOjprYWJsZQogIC0gY3VzdG9taXNpbmcgdGFibGVzIHdpdGggdGhlIHtrYWJsZUV4dHJhfSBwYWNrYWdlCgotLS0tLQotLT4KYGBgCiMjIEludHJvZHVjaW5nIFJNYXJrZG93bgoKU28gZmFyIHRocm91Z2ggdGhpcyBjb3Vyc2Ugd2UndmUgYmVlbiB1c2luZyBSc2NyaXB0cyBmb3IgYW5hbHlzaXMgd2hpY2ggbGV0cyB1cyBzYXZlIGFuZCBydW4gb3VyIFIgY29kZSwgaW5jbHVkaW5nIGNvbW1lbnRzIGFib3V0IHdoYXQgd2UncmUgZG9pbmcgYWxvbmcgdGhlIHdheS4gV2UncmUgbm93IGdvaW5nIHRvIGludHJvZHVjZSBSTWFya2Rvd24gZG9jdW1lbnRzIC0gd2hpY2ggYXJlIGxpa2UgUnNjcmlwdHMgb24gc3Rlcm9pZHMhCgpSTWFya2Rvd24gaXMgYSBmcmFtZXdvcmsgdGhhdCBlbmFibGVzIHRoZSBjcmVhdGlvbiBvZiByZXByb2R1Y2libGUgZG9jdW1lbnRzIHdoaWNoIGFyZSBhIGNvbWJpbmF0aW9uIG9mIHRleHQsIFIgY29kZSwgYW5kIHRoZSBldmFsdWF0ZWQgb3V0cHV0IGZyb20gdGhlIGNvZGUgYWxsIGVtYmVkZGVkIGluIGEgc2luZ2xlIGRvY3VtZW50LiBOb3Qgb25seSB0aGF0LCBidXQgZnJvbSBhIHNpbmdsZSBSTWFya2Rvd24gc291cmNlIGRvY3VtZW50LCBtdWx0aXBsZSBkaWZmZXJlbnQgb3V0cHV0IGZvcm1hdHMgY2FuIGJlIHByb2R1Y2VkIHN1Y2ggYXMgSFRNTCwgUERGLCBhbmQgV29yZCBkb2NzLgoKSW4gZmFjdCB0aGlzIGVudGlyZSBjb3Vyc2UgaGFzIGJlZW4gd3JpdHRlbiB1c2luZyBSTWFya2Rvd24hIEF0IHRoZSB0b3AgcmlnaHQgb2YgZWFjaCBwYWdlIGlzIGEgYENvZGVgIGJ1dHRvbiB0aGF0IHdpbGwgbGV0IHlvdSBkb3dubG9hZCB0aGUgUk1hcmtkb3duIGNvZGUgdGhhdCBjcmVhdGVkIHRoZSBwYWdlLgoKXAoKQmVsb3cgaXMgYW4gZXhhbXBsZSBvZiBhbiBSTWFya2Rvd24gc291cmNlIGRvY3VtZW50CgpgYGB7ciBlY2hvID0gRkFMU0UsIGNvbW1lbnQgPSAiIn0KY2F0KGh0bWx0b29sczo6aW5jbHVkZVRleHQoInNjcmlwdHMvZ2FwbWluZGVyX2FuYWx5c2lzLlJtZCIpKQpgYGAKClRoZXJlIGFyZSB0aHJlZSBtYWluIGNvbXBvbmVudHMgdG8gdGhpcyBkb2N1bWVudAoKMS4gIFRoZSAqKllBTUwqKiBoZWFkZXIgd2hpY2ggaXMgc3Vycm91bmRlZCBieSBgLS0tYHMgYW5kIHByb3ZpZGVzIGluZm9ybWF0aW9uIGZvciB0aGUgY29tcGlsaW5nIHByb2Nlc3MKMi4gIFIgY29kZSAqKmNodW5rcyoqIHdoaWNoIGFyZSBzdXJyb3VuZGVkIGJ5IGBgYGAgYGBgIGBgYGBzCjMuICBUZXh0IHdoaWNoIGNhbiBiZSBmb3JtYXR0ZWQgdXNpbmcgdGhlIE1hcmtkb3duIGxhbmd1YWdlLgoKCkEgcmVmZXJlbmNlIGd1aWRlIG9mIFJNYXJrZG93biBzeW50YXggY2FuIGJlIGZvdW5kIHRocm91Z2ggYEhlbHBgIC0+IGBDaGVhdCBTaGVldHNgIC0+IGBSIE1hcmtkb3duIFJlZmVyZW5jZSBHdWlkZWAgaW4gdGhlIFJTdHVkaW8gbWVudS4KClwKCiMjIyBFeGFtcGxlIFJNYXJrZG93bgoKQmVmb3JlIHdlIGRlbHZlIGludG8gZXhwbGFpbmluZyBlYWNoIHBhcnQgb2YgdGhlIFJNYXJrZG93biBmaWxlIHdlJ3JlIGdvaW5nIHRvIGNyZWF0ZSBvdXIgb3duIGZyb20gdGhlIGluY2x1ZGVkIHRlbXBsYXRlIHRoYXQgY29tZXMgd2l0aCBSU3R1ZGlvLgoKTGV0cyBjcmVhdGUgb3VyIG93biBSTWFya2Rvd24gZG9jdW1lbnQgbm93IGZyb20gdGhlIHRlbXBsYXRlLiBUbyBkbyB0aGlzIGdvIGBGaWxlYCAtXD4gYE5ldyBGaWxlYCAtXD4gYFIgTWFya2Rvd25gLiBZb3UnbGwgdGhlbiBiZSBwcmVzZW50ZWQgd2l0aCBhIHdpbmRvdyB0aGF0IGxvb2tzIGxpa2UgdGhpcwoKYGBge3IsIG91dC53aWR0aD0iMTAwJSIsIGVjaG8gPSBGQUxTRX0KaW5jbHVkZV9ncmFwaGljcygiaW1hZ2VzLzA1LW5ld19ybWQucG5nIikKYGBgCgpUYWtlIHRoZSBvcHBvcnR1bml0eSB0byBmaWxsIGluIHlvdXIgbmFtZSBhbmQgdGl0bGUgdGhlbiBjbGljayBgT0tgLgoKWW91IHNob3VsZCBub3cgaGF2ZSBhIGRvY3VtZW50IHRoYXQgbG9va3MgbGlrZSB0aGUgZm9sbG93aW5nOgoKYGBge3IgZWNobyA9IEZBTFNFLCBjb21tZW50ID0gIiJ9CmNhdChodG1sdG9vbHM6OmluY2x1ZGVUZXh0KCJzY3JpcHRzL3JtZF90ZW1wbGF0ZS5SbWQiKSkKYGBgCgojIyMgUlN0dWRpbyBWaXN1YWwgRWRpdG9yCgpGcm9tIFJzdHVkaW8gdjEuMiB0aGVyZSBoYXMgYmVlbiB0aGUgaW5jbHVzaW9uIG9mIGEgbGl2ZS1wcmV2aWV3IGVkaXRvciB0aGF0IGNhbiBiZSB0dXJuZWQgb24gdGhhdCBwcm92aWRlcyBhIGdyYXBoaWNhbCBwb2ludC1hbmQtY2xpY2sgbWV0aG9kIG9mIGVkaXRpbmcgTWFya2Rvd24uCgpgYGB7ciwgZWNobyA9IEZBTFNFLCBvdXQud2lkdGggPSAiNzUlIiwgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcuY2FwPSJTb3VyY2UgdmlldyJ9CmluY2x1ZGVfZ3JhcGhpY3MoImltYWdlcy8wNS1ybWQtZWRpdG9yLnBuZyIpCmBgYAoKXAoKYGBge3IsIGVjaG8gPSBGQUxTRSwgb3V0LndpZHRoID0gIjkwJSIsIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLmNhcD0iVmlzdWFsIHZpZXcifQppbmNsdWRlX2dyYXBoaWNzKCJpbWFnZXMvMDUtcnN0dWRpby1ybWQtdmlzdWFsLnBuZyIpCmBgYAoKClwKCkRvY3VtZW50YXRpb24gZm9yIGhvdyB0byB1c2UgdGhlIGVkaXRvciBhbmQgaXRzIGZ1bmN0aW9uYWxpdHkgY2FuIGJlIGZvdW5kIGF0IFtodHRwczovL3JzdHVkaW8uZ2l0aHViLmlvL3Zpc3VhbC1tYXJrZG93bi1lZGl0aW5nL10oaHR0cHM6Ly9yc3R1ZGlvLmdpdGh1Yi5pby92aXN1YWwtbWFya2Rvd24tZWRpdGluZy8pCgpcCgojIyMgS25pdHRpbmcKCkluIG9yZGVyIHRvIGdldCBvdXIgb3V0cHV0IGRvY3VtZW50LCB3ZSBuZWVkIHRvIGRvIGEgY29tcGlsaW5nIHN0ZXAgb3IgKiprbml0KiogdGhlIGRvY3VtZW50IC0gYmVoaW5kIHRoZSBzY2VuZXMgdGhlIHRleHQgcG9ydGlvbnMgYXJlIGZvcm1hdHRlZCBiYXNlZCBvbiB0aGUgbWFya2Rvd24gc3ludGF4LCB0aGUgUiBjb2RlIGlzIHJ1biBhbmQgdGhlIHJlc3VsdHMgZ2VuZXJhdGVkLCBhbmQgdGhlbiB0aGUgZm9ybWF0dGVkIHRleHQsIGNvZGUsIGFuZCByZXN1bHRzIGFyZSAiKiprbml0dGVkKioiIHRvZ2V0aGVyIGFzIGEgc2luZ2xlIG91dHB1dC4KCk9uZSBvZiB0aGUga2V5IGJlbmVmaXRzIG9uIGEgcmVwcm9kdWNpYmlsaXR5IHNpZGUgaXMgdGhhdCBSTWFya2Rvd24gaXMgZXZhbHVhdGVkIGZyb20gdG9wIHRvIGJvdHRvbSBleHRlcm5hbGx5IGZyb20geW91ciBzZXNzaW9uIGFuZCBzbyBpdCBuZWVkcyB0byBiZSBzZWxmLXJlbGlhbnQgYW5kIGhhdmUgYWxsIHRoZSBjb21tYW5kcyBmcm9tIHJlYWRpbmcgeW91ciBkYXRhIGluLCBwcm9jZXNzaW5nIGl0LCBhbmQgbWFraW5nIHlvdXIgYXdlc29tZSB0YWJsZXMgYW5kIHBsb3RzIGxpa2UgaW4gdGhlIFtWaXN1YWxpc2F0aW9uIE1vZHVsZV0oMDItdmlzdWFsaXNlLmh0bWwpLgoKVG8ga25pdCB0aGUgZG9jdW1lbnQgbG9vayBmb3IgdGhlIGBrbml0YCBidXR0b24gaW4gdGhlIHRvcCBsZWZ0IG9mIHRoZSAic291cmNlIiBwYW5lbC4gVGhlIGtleWJvYXJkIHNob3J0Y3V0IGlzIDxrYmQ+Q3RybDwva2JkPiArIDxrYmQ+U2hpZnQ8L2tiZD4gKyA8a2JkPks8L2tiZD4gb24gUEMgb3IgPGtiZD5BcHBsZTwva2JkPiArIDxrYmQ+U2hpZnQ8L2tiZD4gKyA8a2JkPks8L2tiZD4gb24gTWFjT1MuCgpgYGB7ciwgb3V0LndpZHRoID0gIjEwMCUiLCBlY2hvID0gRkFMU0V9CmluY2x1ZGVfZ3JhcGhpY3MoImltYWdlcy8wMS1tYXJrZG93bl9rbml0X2J1dHRvbi5wbmciKQpgYGAKCllvdSB3aWxsIHRoZW4gYmUgcHJvbXB0ZWQgdG8gc2F2ZSB0aGlzIHNjcmlwdCwgY2FsbCBpdCAicl9tYXJrZG93bl9leGFtcGxlLlJtZCIgYXMgc2F2ZSBpdCBpbiB5b3VyIGBzY3JpcHRzL2AgZGlyZWN0b3J5IHdpdGhpbiB5b3VyIHByb2plY3QgZGlyZWN0b3J5LiBPbmNlIHlvdSBoYXZlIGtuaXR0ZWQgYSB3aW5kb3cgc2hvdWxkIHBvcC11cCBjb250YWluaW5nIHlvdXIgYnJhbmQgbmV3IGFuYWx5c2lzIGRvY3VtZW50IQoKPiBSTWFya2Rvd24gc2NyaXB0cyBnZW5lcmFsbHkgaGF2ZSB0aGUgZmlsZSBleHRlbnNpb24gYC5SbWRgLgoKVGFrZSBhIGZldyBtaW51dGVzIHRvIHJlYWQgZnJvbSB0b3AgdG8gYm90dG9tIHRocm91Z2ggeW91ciBzY3JpcHQgYW5kIGlkZW50aWZ5aW5nIHRoZSBzYW1lIGZlYXR1cmVzIGluIHlvdXIgb3V0cHV0dGVkIEhUTUwgZG9jdW1lbnQuCgpcCgojIyBNYXJrZG93biBzeW50YXgKCk1hcmtkb3duIGlzIGEgc2ltcGxpZmllZCBsYW5ndWFnZSB0aGF0IHVzZXMgc3ltYm9scyB0byBlbmNvZGUgZm9ybWF0dGluZyBvZiB0ZXh0IGluIGEgY29tcGlsZWQgZG9jdW1lbnQuIE1hcmtkb3duIGRvY3VtZW50cyBjYW4gYmUgY29udmVydGVkIHRvIEhUTUwgb3IgTGFUZVggKHVzZWQgZm9yIFBERikgdGhyb3VnaCBQYW5kb2MgKHdoaWNoIGNvbWVzIGJ1bmRsZWQgd2l0aCBSU3R1ZGlvKS4KCiMjIyBIZWFkaW5ncwoKSGVhZGVycyAtIHRoZXNlIHVzZSB0aGUgXCMgZm9yIHRoZSBsYXJnZXN0IGhlYWRpbmcgKGhlYWRlciAxKSB0aHJvdWdoIHRvIFwjIyMjIyMgdGhlIHNtYWxsZXN0IGhlYWRpbmcgKGxldmVsIDYpIGFuZCBjb3JyZXNwb25kIHRvIHRoZSBoMSB0byBoNiBoZWFkaW5nIHRhZ3MgaW4gSFRNTC4KCmBgYAojIExldmVsIDEgaGVhZGluZwoKIyMgbGV2ZWwgMiBoZWFkaW5nCgojIyMgbGV2ZWwgMyBoZWFkaW5nCgojIyMjIGxldmVsIDQgaGVhZGluZwoKIyMjIyMgbGV2ZWwgNSBoZWFkaW5nCgojIyMjIyMgbGV2ZWwgNiBoZWFkaW5nCmBgYAoKXAoKV2UnbGwgY292ZXIgc29tZSBtb3JlIG9mIHRoZSBjb21tb24gdGV4dCBmb3JtYXR0aW5nIG5vdywgd2hlcmUgeW91J2xsIHNlZSB0aGUgcmVuZGVyZWQgcGFyYWdyYXBoIGZvbGxvd2VkIGJ5IHRoZSBtYXJrZG93biBzeW50YXggdGhhdCB3YXMgdXNlZCB0byBnZW5lcmF0ZSBpdDoKCiMjIyBCb2xkL0l0YWxpY3MKCgoqSXRhbGljcyogaXMgZW5jb2RlZCBieSBzdXJyb3VuZGluZyB3b3JkKHMpIHdpdGggd2l0aCBhIHNpbmdsZSBhc3RlcmlzayAoXCopIG9yIHVuZGVyc2NvcmUgKFxfKSwgKipib2xkKiogdXNlcyBkb3VibGUgYXN0ZXJpc2tzIFwqXCogb3IgdW5kZXJzY29yZXMgXF9cXy4gVG8gXnN1cGVyXnNjcmlwdCBzb21ldGhpbmcsIHN1cnJvdW5kIGl0IHdpdGggY2FyZXRzIChcXiksIGFuZCB0byB+c3VifnNjcmlwdCBzdXJyb3VuZCBpdCB3aXRoIHRpbGRlIChcfikuIFN1cnJvdW5kaW5nIHdpdGggZG91YmxlIHRpbGRlcyB3aWxsIH5+c3RyaWtldGhyb3VnaH5+LgoKYGBgCipJdGFsaWNzKiBpcyBlbmNvZGVkIGJ5IHN1cnJvdW5kaW5nIHdvcmQocykgd2l0aCB3aXRoIGEgc2luZ2xlIGFzdGVyaXNrIChcKikgb3IgdW5kZXJzY29yZSAoXyksICoqYm9sZCoqIHVzZXMgZG91YmxlIGFzdGVyaXNrcyAqKiBvciB1bmRlcnNjb3JlcyBfXy4gVG8gXnN1cGVyXnNjcmlwdCBzb21ldGhpbmcsIHN1cnJvdW5kIGl0IHdpdGggY2FyZXRzICheKSwgYW5kIHRvIH5zdWJ+c2NyaXB0IHN1cnJvdW5kIGl0IHdpdGggdGlsZGUgKH4pLiBTdXJyb3VuZGluZyB3aXRoIGRvdWJsZSB0aWxkZXMgd2lsbCB+fnN0cmlrZXRocm91Z2h+fi4KYGBgCgpcCgojIyMgTGlzdHMKClVub3JkZXJlZCBsaXN0cyBjYW4gYmUgbWFkZSBieSBzdGFydGluZyBhIGxpbmUgd2l0aCBlaXRoZXIgYSBkYXNoICgtKSBvciBhbiBhc3RlcmlzayAoXCopIGFuZCBpZiB5b3Ugd2FudCB0byBuZXN0IGl0ZW1zIHVzZSBhIHRhYiBvciB0d28gc3BhY2VzIHRvIGluZGVudCBwZXIgbGF5ZXIuCgotIGl0ZW0gMQotIGl0ZW0gMgotIGl0ZW0gMwogICAgLSBzdWJpdGVtIDEKICAgIC0gc3ViaXRlbSAyCiAgICAgICAgLSBzdWIgc3ViIGl0ZW0gMQotIGl0ZW0gNAoKCmBgYAotIGl0ZW0gMQotIGl0ZW0gMgotIGl0ZW0gMwogIC0gc3ViaXRlbSAxCiAgLSBzdWJpdGVtIDIKICAgIC0gc3ViIHN1YiBpdGVtIDEKLSBpdGVtIDQKYGBgCk9yZGVyZWQgbGlzdHMgc3RhcnQgdGhlIGxpbmUgd2l0aCBhIG51bWJlciBmb2xsb3dlZCBieSBhIGZ1bGxzdG9wLiBJdCBpcyBwb3NzaWJsZSB0byBuZXN0IHVub3JkZXJlZCBhbmQgb3JkZXJlZCBsaXN0cyB3aXRoaW4gdGhlIHNhbWUgbGlzdAoKMS4gIGl0ZW0gMQoyLiAgaXRlbSAyCjMuICBpdGVtIDMKCgpgYGAKMS4gaXRlbSAxCjIuIGl0ZW0gMgozLiBpdGVtIDMKYGBgCgpcCgojIyMgQmxvY2sgcXVvdGVzCgo+IGJsb2NrIHF1b3RlcyBhcmUgYSB3YXkgb2YgaW5jbHVkaW5nIGJsb2NrcyBvZiB0ZXh0IGZyb20gc29tZW9uZSBlbHNlLiBUbyB1c2UgdGhlc2UgdGhhdCB0aGUgbGluZSB3aXRoIGEgXD4gYW5nbGUgYnJhY2tldAoKYGBgCj4gYmxvY2sgcXVvdGVzIGFyZSBhIHdheSBvZiBpbmNsdWRpbmcgYmxvY2tzIG9mIHRleHQgZnJvbSBzb21lb25lIGVsc2UuIFRvIHVzZSB0aGVzZSBiZWdpbiB0aGUgbGluZSB3aXRoIGEgPiBhbmdsZSBicmFja2V0CmBgYAoKXAoKIyMjIExpbmtzCgpMaW5rcyBjYW4gYmUgZG9uZSBhcyBlaXRoZXIgdGhlIGZ1bGwgdXJsIGUuZy4gPGh0dHBzOi8vd3d3Lmdvb2dsZS5jb20+LCBvciB5b3UgY2FuIFtsaW5rIHdvcmRzXShodHRwczovL3d3dy5nb29nbGUuY29tKSBieSBzdXJyb3VuZGluZyB0aGVtIHdpdGggW10gZm9sbG93ZWQgaW1tZWRpYXRlbHkgYnkgdGhlIHVybCBpbiBwYXJlbnRoZXNlcy4KCmBgYApMaW5rcyBjYW4gYmUgZG9uZSBhcyBlaXRoZXIgdGhlIGZ1bGwgdXJsIGUuZy4gaHR0cHM6Ly93d3cuZ29vZ2xlLmNvbSwgb3IgeW91IGNhbiBbbGluayB3b3Jkc10oaHR0cHM6Ly93d3cuZ29vZ2xlLmNvbSkgYnkgc3Vycm91bmRpbmcgdGhlbSB3aXRoIFtdIGZvbGxvd2VkIGltbWVkaWF0ZWx5IGJ5IHRoZSB1cmwgaW4gcGFyZW50aGVzZXMuCmBgYApcCgojIyMgVmVyYmF0aW0gY29kZQoKYGBgYApJZiB5b3Ugd2FudCB0byBpbmNsdWRlIGNvZGUgaW4geW91ciBkb2N1bWVudCwgdGhlIHVzZSBvZiB2ZXJiYXRpbSBibG9ja3Mgd2lsbCBzdG9wIHRoZSBzeW1ib2xzIGJlaW5nIGludGVycHJldGVkIGZvciBtYXJrZG93biBhbmQgd2lsbCBiZSByZXByb2R1Y2VkIGFzaXMgaW4gdGhlIGRvY3VtZW50LgpUaGVzZSBibG9ja3MgYXJlIHN0YXJ0ZWQgYW5kIGVuZGVkIHdpdGggdGhyZWUgYmFja3RpY2tzIGBgYApgYGBgCgpgYGBgCgpgYGAKSWYgeW91IHdhbnQgdG8gaW5jbHVkZSBjb2RlIGluIHlvdXIgZG9jdW1lbnQgYXMgaGFzIGJlZW4gZG9uZSB0byBkZW1vbnN0cmF0ZSB0aGUgbWFya2Rvd24gY29kZSB0aGF0IGdlbmVyYXRlZCBlYWNoIG9mIHRoZSBleGFtcGxlIHBhcmFncmFwaHMsIHRoZSB1c2Ugb2YgdmVyYmF0aW0gYmxvY2tzIHdpbGwgc3RvcCB0aGUgc3ltYm9scyBiZWluZyBpbnRlcnByZXRlZCBmb3IgbWFya2Rvd24gYW5kIHdpbGwgYmUgcmVwcm9kdWNlZCBhcyBpcyBpbiB0aGUgZG9jdW1lbnQuClRoZXNlcyBibG9ja3MgYXJlIHN0YXJ0ZWQgYW5kIGVuZGVkIHdpdGggdGhyZWUgYmFja3RpY2tzIGBgYApgYGAKYGBgYAoKWW91IGNhbiBhbHNvIGRvIGBpbmxpbmUgdmVyYmF0aW1gIGJ5IHN1cnJvdW5kaW5nIHRoZSB0ZXh0IHdpdGggYSBzaW5nbGUgYmFja3RpY2sKCmBgYApZb3UgY2FuIGFsc28gZG8gYGlubGluZSB2ZXJiYXRpbWAgYnkgc3Vycm91bmRpbmcgdGhlIHRleHQgd2l0aCBhIHNpbmdsZSBiYWNrdGljawpgYGAKCiMjIENvZGUgQ2h1bmtzCgpNYXJrZG93biBwcm92aWRlcyB2ZXJiYXRpbSBjb2RlIGNodW5rcywgaG93ZXZlciB3aGVyZSBSTWFya2Rvd24gcmVhbGx5IGNvbWVzIGludG8gaXRzIG93biBpcyB0aGUgYWJpbGl0eSB0byBoYXZlIHRoZSBjb2RlIHRoYXQgaXMgaW5jbHVkZWQgZXZhbHVhdGVkIGFuZCB0aGUgcmVzdWx0cyBhbHNvIGVtYmVkZGVkIGRpcmVjdGx5IGJlbG93IHRoZSBjb2RlIHRoYXQgd2FzIGNyZWF0ZWQgdGhlbS4gV2hpbGUgaXQncyBjYWxsZWQgUk1hcmtkb3duIHlvdSdyZSBhbHNvIG5vdCBqdXN0IGxpbWl0ZWQgdG8gUiBidXQgb3RoZXIgbGFuZ3VhZ2VzIGNhbiBiZSBpbmNsdWRlZCBhbmQgcnVuIChzbyBsb25nIGFzIHRoZSB1bmRlcmx5aW5nIGVuZ2luZXMgYXJlIHNldCB1cCkKCkEgY29kZSBjaHVuayB0YWtlcyB0aGlzIGZvcm1hdCwgc2ltaWxhciB0byB0byB0aGUgdmVyYmF0aW0gY29kZSBjaHVuayBidXQgZm9sbG93aW5nIHRoZSBmaXJzdCB0aHJlZSBiYWNrdGlja3MgYXJlIGN1cmx5IGJyYWNlcywgYW5kIGluc2lkZSB0aGUgbmFtZSBvZiB0aGUgbGFuZ3VhZ2UgaW4gbG93ZXIgY2FzZSAtIGluIHRoaXMgY2FzZSAiciIKCmBgYHtyIGVjaG8gPSBGQUxTRSwgY29tbWVudCA9ICIifQpjYXQoaHRtbHRvb2xzOjppbmNsdWRlVGV4dCgic2NyaXB0cy9jb2RlX2NodW5rLlJtZCIpKQpgYGAKCldvdWxkIHByb2R1Y2UKCmBgYHtyfQoxICsgMgpgYGAKClwKCiMjIyBXb3JraW5nIGRpcmVjdG9yeQoKVGhlIHdvcmtpbmcgZGlyZWN0b3J5IG9yIGxvY2F0aW9uIHRoYXQgUiBpcyBnb2luZyB0byBzdGFydCBsb29raW5nIGZvciBzcGVjaWZpZWQgZmlsZXMgKGUuZy4gYSBjc3YgdG8gcmVhZCBpbikgZm9yIGFuIFJNYXJrZG93biB3aWxsIGRlZmF1bHQgdG8gdGhlIGxvY2F0aW9uIHRoZSBSTWFya2Rvd24gZmlsZSBpcyBzYXZlZC4gVGhpcyBjYW4gYmUgYSBjb21tb24gc291cmNlIG9mIGVycm9ycyBpbiBjb21waWxpbmcgYW4gUk1hcmtkb3duIGRvY3VtZW50IGlmIHlvdXIgUk1hcmtkb3duIGlzIHNhdmVkIGluIGEgc3ViZGlyZWN0b3J5IGFuZCB5b3UgZG9uJ3QgaGF2ZSB5b3VyIGZpbGUgcGF0aHMgY29ycmVjdC4KCj4gRG9uJ3QgdXNlIGBzZXR3ZCgpYCBpbiBhbiBSTWFya2Rvd24uIEl0IHdpbGwgY2F1c2UgaXNzdWVzLgoKSWYgeW91IGFyZSB1c2luZyBhbiBSU3R1ZGlvIHByb2plY3QgYW5kIHN0cnVjdHVyZSBhcyBpbnRyb2R1Y2VkIGluIFtJbnRyb2R1Y2luZyBSIGFuZCBSc3R1ZGlvXSgwMS1pbnRyby5odG1sKSB5b3UgY2FuIG1ha2UgdXNlIG9mIHRoZSBbYGhlcmVgXShodHRwczovL2hlcmUuci1saWIub3JnL2FydGljbGVzL2hlcmUuaHRtbCkgcGFja2FnZSB3aGljaCBwcm92aWRlcyBhIG5pY2Ugd2F5IG9mIGRlYWxpbmcgd2l0aCByZWxhdGl2ZSBmaWxlIHBhdGhzIGFzIGlmIHlvdSB3ZXJlIG5hdmlnYXRpbmcgZnJvbSB0aGUgdG9wIG9mIHlvdXIgcHJvamVjdCBkaXJlY3RvcnkuCgpGb3IgaW5zdGFuY2UgZ2l2ZW4gdGhlIGZvbGxvd2luZyBwcm9qZWN0IHNldHVwOgoKYGBgCm15X3Byb2plY3QvCiAgfC0gZGF0YS8KICAgICAgXC0gbXlfY3N2LmNzdgogIHwtIGRvY3MvCiAgfC0gb3V0cHV0cy8KICB8LSBzY3JpcHRzLwogICAgICBcLSBteV9ybWQuUm1kCiAgXCAtIG15X3Byb2plY3QuUnByb2oKICAKYGBgCgpJZiB3ZSB3ZXJlIHdvcmtpbmcgb24gdGhlIGZpbGUgYG15X3JtZC5SbWRgIHdpdGhvdXQgdGhlIHVzZSBvZiBgaGVyZWAgd2Ugd291bGQgbmVlZCB0byB1c2UgcmVsYXRpdmUgcGF0aHMgZnJvbSBgc2NyaXB0cy9gICh3ZSB3YW50IHRvIHVzZSByZWxhdGl2ZSBwYXRocyB3aXRoaW4gb3VyIHByb2plY3QgYmVjYXVzZSB0aGV5IGFyZW4ndCBkZXBlbmRhbnQgb24gYW55IHBhcnRpY3VsYXIgY29tcHV0ZXIgbWFraW5nIG91ciBwcm9qZWN0IHRyYW5zZmVyYWJsZSkgYW5kIHRoZSBjb21tYW5kIHRvIHJlYWQgZGF0YSBpbiB3b3VsZCBsb29rIGxpa2UgdGhpczoKCmBgYHtyICwgZXZhbCA9IEZBTFNFfQpteV9kYXRhIDwtIHJlYWRfY3N2KCIuLi9kYXRhL215X2Nzdi5jc3YiKQpgYGAKClVzaW5nIGBoZXJlYCBldmVyeXRoaW5nIGlzIHJlbGF0aXZlIGZyb20gdGhlIGAuUnByb2pgIGZpbGUgd2hpY2ggY2FuIGJlIGVhc2llciB0byB0aGluayBvZiBzaW5jZSBpdCBmb2xsb3dzIGEgcmVsYXRpdmUgcGF0aCB0aGUgc2FtZSBzdHJ1Y3R1cmUgYXMgdGhlIHByb2plY3QsIG5vdCByZWxhdGl2ZSB0byB3aGVyZSB0aGUgZmlsZSB5b3UncmUgY3VycmVudGx5IHdvcmtpbmcgb24gbGl2ZXMgLSBgaGVyZWAgd29ya3MgYWxsIHRoYXQgb3V0IGZvciB5b3U6CgpgYGB7ciwgZXZhbD1GQUxTRX0KbGlicmFyeShoZXJlKQpteV9kYXRhIDwtIHJlYWRfY3N2KGhlcmUoImRhdGEvbXlfY3N2LmNzdiIpKQpgYGAKClwKCiMjIyBDb2RlIENodW5rIE9wdGlvbnMKClRoZSBiZWhhdmlvdXIgb2YgdGhlIGNvZGUgY2h1bmtzIGNhbiBiZSBtb2RpZmllZCB3aXRoIG9wdGlvbnMuIFRoZXNlIG9wdGlvbnMgYXJlIHByb3ZpZGVkIGluc2lkZSB0aGUge30ncyBvZiB0aGUgY29kZSBjaHVuayBhbmQgYXJlIGNvbW1hIHNlcGFyYXRlZC4KClRoZSBkZWZhdWx0cyBmb3IgYSBjaHVuayBhcmU6CgpgYGB7ciBlY2hvID0gRkFMU0UsIGNvbW1lbnQgPSAiIn0KY2F0KGh0bWx0b29sczo6aW5jbHVkZVRleHQoInNjcmlwdHMvY29kZV9jaHVua19kZWZhdWx0cy5SbWQiKSkKYGBgCgotICAgYGVjaG89VFJVRWAgd2lsbCAiZWNobyIgdGhlIGNvZGUgdGhhdCBpcyBydW4gYWJvdmUgdGhlIHJlc3VsdHMKLSAgIGBldmFsPVRSVUVgIG1lYW5zIHRoZSBjb2RlIGluc2lkZSB0aGUgY2h1bmsgd2lsbCBiZSBldmFsdWF0ZWQgKHJ1bikKLSAgIGBpbmNsdWRlPVRSVUVgIG1lYW5zIHRoZSBjb2RlIGFuZCB0aGUgcmVzdWx0cyB3aWxsIGJlIGluY2x1ZGVkIGluIHRoZSBkb2N1bWVudAotICAgYHdhcm5pbmc9VFJVRWAgd2lsbCBpbmNsdWRlIGFueSB3YXJuaW5ncyBhcyBvdXRwdXQgaW4gdGhlIGRvY3VtZW50Ci0gICBgbWVzc2FnZT1UUlVFYCB3aWxsIGluY2x1ZGUgbWVzc2FnZXMgYXMgb3V0cHV0IGluIHRoZSBkb2N1bWVudAoKVGhlc2UgY2FuIGluZGl2aWR1YWxseSBiZSBzcGVjaWZpZWQgYW5kIHNldCB0byBgRkFMU0VgIHRvIGRpc2FibGUgdGhlIHNwZWNpZmljIGJlaGF2aW91ci4KCiMjIEltYWdlcywgRmlndXJlcyBhbmQgVGFibGVzCgojIyMgSW1hZ2VzCgpJbnNlcnRpbmcgaW1hZ2VzIGludG8gUk1hcmtkb3duIGRvY3VtZW50cyBjYW4gYmUgZG9uZSBpbiB0d28gbWFpbiB3YXlzCgoxLiAgVGhyb3VnaCBtYXJrZG93biB3aXRoIGAhW2FsdCB0ZXh0XShwYXRoL3RvL2ltYWdlKWAKMi4gIFVzaW5nIGEgY29kZSBjaHVuayBhbmQgdGhlIGBpbmNsdWRlX2dyYXBoaWNzKClgIGZ1bmN0aW9uIGZyb20gYGtuaXRyYAoKVGhlIHNlY29uZCBtZXRob2QgZ2l2ZSB5b3UgbW9yZSBjb250cm9sIG92ZXIgdGhlIGRpc3BsYXkgb2YgdGhlIGltYWdlIGluIHRoZSBvdXRwdXQgYmVjYXVzZSB5b3UgY2FuIHVzZSB0aGUgY29kZSBjaHVuayBvcHRpb25zIHRvIHN1Y2ggYXMKCi0gICBgZmlnLmFsaWduYCB0byBjb250cm9sIHRoZSBhbGlnbm1lbnQgb24gdGhlIHBhZ2Ugb2YgdGhlIGltYWdlCi0gICBgZmlnLmNhcGAgdG8gcHJvdmlkZSBhIGZpZ3VyZSBjYXB0aW9uCi0gICBgb3V0LndpZHRoYCBjb250cm9scyB0aGUgb3V0cHV0IHdpZHRoCi0gICBgb3V0LmhlaWdodGAgY29udHJvbHMgdGhlIG91dHB1dCBoZWlnaHQKCiMjIyBGaWd1cmVzCgpJbWFnZXMgZ2VuZXJhdGVkIHRocm91Z2ggY29kZSBzdWNoIGFzIHBsb3RzIHdpbGwgYXV0b21hdGljYWxseSBiZSBpbmNsdWRlZCBhcyB0aGUgb3V0cHV0IHVuZGVybmVhdGggdGhlIGNvZGUgdGhhdCBjcmVhdGVkIHRoZW0uCgpUaGUgZmlndXJlIHBsYWNlbWVudCBhbmQgc2l6ZSBjYW4gYmUgY29udHJvbGxlZCB0aHJvdWdoIHRoZSBjb2RlIGNodW5rIG9wdGlvbnMKCi0gICBgZmlnLmFsaWduYCB0byBjb250cm9sIHRoZSBhbGlnbm1lbnQgb24gdGhlIHBhZ2Ugb2YgdGhlIGltYWdlCi0gICBgZmlnLmNhcGAgdG8gcHJvdmlkZSBhIGZpZ3VyZSBjYXB0aW9uCi0gICBgZmlnLndpZHRoYCBjb250cm9scyB0aGUgb3V0cHV0IHdpZHRoCi0gICBgZmlnLmhlaWdodGAgY29udHJvbHMgdGhlIG91dHB1dCBoZWlnaHQKLSAgIGBmaWcuYXNwYCBjYW4gYmUgdXNlZCB0byBzY2FsZSBhIGZpZ3VyZQoKIyMjIFRhYmxlcwoKVGFibGVzIGNhbiBiZSBjcmVhdGVkIG1hbnVhbGx5IHRocm91Z2ggbWFya2Rvd24gdXNpbmcgdGhlIGZvbGxvd2luZyBzeW50YXgKCiAgICBjb2wgMSB8IGNvbCAyIHwgY29sIDMKICAgIC0tLXwtLS18LS0tCiAgICByb3cgMSB8IGEgfCAxCiAgICByb3cgMiB8IGIgfCAyCgp3aGljaCBjcmVhdGVzIHRoZSBmb2xsb3dpbmcgdGFibGU6Cgp8IGNvbCAxIHwgY29sIDIgfCBjb2wgMyB8CnwtLS0tLS0tfC0tLS0tLS18LS0tLS0tLXwKfCByb3cgMSB8IGEgICAgIHwgMSAgICAgfAp8IHJvdyAyIHwgYiAgICAgfCAyICAgICB8CgpCdXQgdGhlc2UgdGFibGUgY2FuIGJlIHF1aXRlIGxhYm9yaW91cyB0byBjcmVhdGUgYW5kIGN1c3RvbWlzZS4gVGhleSBhbHNvIHdpbGwgbmVlZCB0byBiZSBtYW51YWxseSB1cGRhdGVkIGlmIHlvdXIgZGF0YSBjaGFuZ2VzLiBBIGJldHRlciBvcHRpb24gaXMgdG8gY3JlYXRlIHRhYmxlcyBkaXJlY3RseSBmcm9tIHlvdXIgZGF0YSB1c2luZyB0aGUgYGthYmxlKClgIGZ1bmN0aW9uIGZyb20gYGtuaXRyYCB3aGljaCB3aWxsIHRha2UgYSBkYXRhZnJhbWUgYW5kIGF1dG9tYXRpY2FsbHkgY3JlYXRlIHRoZSBtYXJrZG93biBmb3IgaXQuCgpgYGB7cn0KbGlicmFyeShwYWxtZXJwZW5ndWlucykKbGlicmFyeShrbml0cikKCnBlbmd1aW5zX3NtYWxsIDwtIGhlYWQocGVuZ3VpbnMsIG4gPSAxMCkKCmthYmxlKHBlbmd1aW5zX3NtYWxsKQpgYGAKClRoZXNlIGthYmxlIHRhYmxlcyBjYW4gYmUgZnVydGhlciBjdXN0b21pc2VkIGZyb20gdGhlIGZ1bmN0aW9uIHBhcmFtZXRlcnMgc3VjaCBhcyBgY29sLm5hbWVzYCB0byBwcm92aWRlIGEgdmVjdG9yIG9mIGNvbHVtbiBuYW1lcyBmb3IgdGhlIHRhYmxlLCBgZGlnaXRzYCB0byByb3VuZCBudW1iZXJzLCBhbmQgYGFsaWduYCB0byBjb250cm9sIHRoZSBhbGlnbm1lbnQgb2YgdGhlIGNvbHVtbnMuCgpUaGUgYWRkaXRpb25hbCBjdXN0b21pc2F0aW9uIGNhbiBiZSBhY2hpZXZlZCB0aHJvdWdoIHRoZSB1c2Ugb2YgdGhlIFtga2FibGVFeHRyYWAgcGFja2FnZV0oaHR0cHM6Ly9naXRodWIuY29tL2hhb3podTIzMy9rYWJsZUV4dHJhKSB3aGljaCBwcm92aWRlcyBudW1lcm91cyBleHRyYSBmdW5jdGlvbiBmb3IgdGhlIHRoZSBjdXN0b21pc2F0aW9uIG9mIHRhYmxlcyBpbiBib3RoIFtIVE1MXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMva2FibGVFeHRyYS92aWduZXR0ZXMvYXdlc29tZV90YWJsZV9pbl9odG1sLmh0bWwpIGFuZCBbTGFUZVhdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9rYWJsZUV4dHJhL3ZpZ25ldHRlcy9hd2Vzb21lX3RhYmxlX2luX3BkZi5wZGYpIHdoaWNoIGRpZmZlciBzbGlnaHRseSBpbiB3aGF0IGlzIHBvc3NpYmxlIGluIGVhY2ggZm9ybWF0LiBCdXQgdGhleSBib3RoIGluY2x1ZGUgZmVhdHVyZXMgc3VjaCBhcyByb3cvY29sdW1uL2NlbGwgY29sb3VyaW5nLCB0ZXh0IGZvcm1hdHRpbmcsIGdyb3VwaW5ncywgYW5kIGZvb3Rub3Rlcy4KClwKCkhlcmUgaXMgYW4gZXhhbXBsZSBvZiBzb21lIGV4dHJhIGN1c3RvbWlzYXRpb25zIHRoYXQgY291bGQgYmUgZG9uZSB0byB0aGUgb3JpZ2luYWwgdGFibGUgdGhhdCB3YXMgZGVtb25zdHJhdGVkIGFib3ZlIHdpdGggYGthYmxlYC4gSWYgeW91ciBjdXN0b21pc2F0aW9ucyBvbiB5b3VyIHRhYmxlIHJlbHkgb24gdGhlIGRhdGEgc3RheWluZyB0aGUgc2FtZSB0aGV5IG1pZ2h0IG5lZWQgdG8gYmUgcmVkb25lIGlmIHlvdSB1cGRhdGUgdGhlIGRhdGEgaW4gdGhlIHRhYmxlLiAKCmBgYHtyfQpsaWJyYXJ5KHBhbG1lcnBlbmd1aW5zKQpsaWJyYXJ5KGtuaXRyKQpsaWJyYXJ5KGthYmxlRXh0cmEpCgpwZW5ndWluc19zbWFsbCA8LSBoZWFkKHBlbmd1aW5zLCBuID0gMTApCgojIGtibCBjb21lcyBmcm9tIGthYmxlRXh0cmEgYW5kIGlzIGEgdmVyc2lvbiBvZiBrYWJsZSgpCmthYmxlRXh0cmE6OmtibChwZW5ndWluc19zbWFsbCwgCiAgICBjb2wubmFtZXMgPSBjKCJTcGVjaWVzIiwgCiAgICAgICAgICAgICAgICAgICJJc2xhbmQiLCAKICAgICAgICAgICAgICAgICAgIkJpbGwgTGVuZ3RoIiwgCiAgICAgICAgICAgICAgICAgICJCaWxsIERlcHRoIiwgCiAgICAgICAgICAgICAgICAgICJGbGlwcGVyIExlbmd0aCIsIAogICAgICAgICAgICAgICAgICAiQm9keSBNYXNzIChnKSIsIAogICAgICAgICAgICAgICAgICAiU2V4IiwgCiAgICAgICAgICAgICAgICAgICJZZWFyIiksIAogICAgYWxpZ24gPSAibGxycnJyY3IiLAogICAgY2FwdGlvbiA9ICJBIHRhYmxlIHNob3dpbmcgdGhlIG1lYXN1cmVtZW50cyBvZiB0aGUgZmlyc3QgMTAgcGVuZ3VpbnMgZnJvbSB0aGUgUGFsbWVycyBQZW5ndWlucyBkYXRhc2V0LiIpICU+JSAKICBrYWJsZUV4dHJhOjprYWJsZV9zdHlsaW5nKGZ1bGxfd2lkdGggPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcG9zaXRpb24gPSAnY2VudGVyJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvbnRfc2l6ZSA9IDE2LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgYm9vdHN0cmFwX29wdGlvbnMgPSAnc3RyaXBlZCcpICU+JSAKICAjIGFkZCBpbiBhIGdyb3VwaW5nIGhlYWRlciBmb3IgdGhlIGNvbHVtbnMgdXNpbmcgbW0KICBrYWJsZUV4dHJhOjphZGRfaGVhZGVyX2Fib3ZlKGhlYWRlciA9IGMoIiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk1lYXN1cmVtZW50cyAobW0pIiA9IDMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIiIpKQogIApgYGAKClwKCgoKIyMgQ2l0YXRpb25zCgpDaXRhdGlvbnMgY2FuIGJlIGluc2VydGVkIGludG8gYW4gUk1hcmtkb3duIGRvY3VtZW50LiBbVGhpcyBkb2N1bWVudCBmcm9tIFJTdHVkaW9dKGh0dHBzOi8vcnN0dWRpby5naXRodWIuaW8vdmlzdWFsLW1hcmtkb3duLWVkaXRpbmcvY2l0YXRpb25zLmh0bWwpIGdvZXMgdGhyb3VnaCBob3cgdG8gZG8gaXQgdXNpbmcgZXRoZXIgTWFya2Rvd24gb3Igd2l0aCB0aGUgdmlzdWFsIGVkaXRvciB3aGljaCBjYW4gYmUgbGlua2VkIHdpdGggYSBjaXRhdGlvbiBtYW5hZ2VyIHN1Y2ggYXMgWm90ZXJvLCBvciBieSBzZWFyY2hpbmcgRE9JcyBhbmQgbW9yZS4KClwKCiMjIFF1YXJ0bwoKPiBQcmUtcmVxdWlzaXRlOiBJbiBvcmRlciB0byB1c2UgUXVhcnRvIHlvdSB3aWxsIG5lZWQgdG8gaW5zdGFsbCB0aGUgUXVhcnRvIHByb2dyYW0gd2hpY2ggUlN0dWRpbyBjYW4gdGhlbiB1c2UgdG8gY29tcGlsZSB0aGUgUXVhcnRvLiBTZWUgaHR0cHM6Ly9xdWFydG8ub3JnL2RvY3MvZ2V0LXN0YXJ0ZWQvCgpSTWFya2Rvd24gaXMgYW4gZXh0cmVtZWx5IHVzZWZ1bCBmb3JtYXQgZm9yIGNyZWF0aW5nIHJlcHJvZHVjaWJsZSByZXBvcnRzLCBfaG93ZXZlcl8sIHRoZXJlIGFyZSBzb21lIGtleSBmZWF0dXJlcyB0aGF0IGFyZSBtaXNzaW5nICh3aXRob3V0IGFkZGl0aW9uYWwgcGFja2FnZXMgYW5kIHR3ZWFraW5nKSB3aGljaCB5b3Ugd2lsbCBmaW5kIHlvdSBuZWVkIGlmIHlvdSB3YW50IHRvIHVzZSBpdCBmb3IgbWFraW5nIGRvY3VtZW50cyBsaWtlIHRoZXNlcyBvciBtYW51c2NyaXB0cywgdGhlIGVhc2llc3QgdG8gcG9pbnQgdG8gaXMgY3Jvc3MtcmVmZXJlbmNpbmcgdG8gZmlndXJlcyBhbmQgdGFibGVzIGluIHlvdXIgdGV4dCAodGhlIHBhY2thZ2VzIF9ib29rZG93bl8gYW5kIF90aGVzaXNkb3duXyBkbyBhZGQgdGhpcyBmdW5jdGlvbmFsaXR5IHRvIFJNYXJrZG93bikuCgpRdWFydG8gaXMgdGhlIG5leHQgaXRlcmF0aW9uIG9mIFJNYXJrZG93biwgYW5kIGhhcyB0YWtlbiBtdWNoIG9mIHRoZSBmdW5jdGlvbmFsaXR5IHRoYXQgdGhlIGV4dHJhIHBhY2thZ2VzIGNyZWF0ZWQgdG8gZXhwYW5kIG9uIFJNYXJrZG93biBoYWQsIGFuZCBpbmNsdWRlcyB0aGVtIHJpZ2h0IGZyb20gdGhlIGdldC1nby4gTm90IG9ubHkgdGhhdCwgYnV0IFF1YXJ0byBoYXMgYmVlbiBkZXNpZ25lZCBmcm9tIHRoZSBzdGFydCB0byBoYXZlIG11bHRpLWxhbmd1YWdlIHN1cHBvcnQsIHNvIGlmIHlvdSBmaW5kIHlvdXJzZWxmIHdvcmtpbmcgaW4gYW5vdGhlciBsYW5ndWFnZSBzdWNoIGFzIHB5dGhvbiwgdGhlbiB0aGlzIHNhbWUgZG9jdW1lbnQgcHVibGlzaGluZyBzeXN0ZW0gaXMgc3RpbGwgYXZhaWxhYmxlIHRvIHlvdS4KCkJ5IGFuZCBsYXJnZSwgUXVhcnRvIGFuZCBSTWFya2Rvd24gYXJlIGV4dHJlbWVseSBzaW1pbGFyIC0gdGhleSBib3RoIHNoYXJlIHRoZSB0aHJlZSBtYWluIGNvbXBvbmVudHM6CgoxLiBZQU1MIGhlYWRlcgoyLiBNYXJrZG93biBibG9ja3MKMy4gQ29kZSBjaHVua3MKCldoZXJlIHRoZXkgZGlmZmVyIGlzIHRoZXJlIGFyZSBzb21lIHNsaWdodCBzeW50YXggY2hhbmdlcywgbGFyZ2VseSBpbiB0aGUgWUFNTCBoZWFkZXIgYW5kIGhvdyBvcHRpb25zIGFyZSBnaXZlbiB0byBjb2RlIGNodW5rcy4KClRoZSBmaXJzdCBkaWZmZXJlbmNlIGlzIHRoYXQgaW5zdGVhZCBvZiBiZWluZyBzYXZlZCB3aXRoIGEgYC5SbWRgIGZpbGUgZXh0ZW5zaW9uLCBhIHF1YXJ0byBkb2N1bWVudCBoYXMgdGhlIGV4dGVuc2lvbiBgLnFtZGAuIEFuZCBpbnN0ZWFkIG9mIHRoZSBgS25pdGAgYnV0dG9uLCBpdCdzIGNhbGxlZCBgUmVuZGVyYC4KCiMjIyBZQU1MIEhlYWRlcgoKVGhlIFlBTUwgaGVhZGVyIGlzIHRoZSBmaXJzdCBwbGFjZSB3aGVyZSB0aGVyZSBpcyBhIG1haW4gZGlmZmVyZW5jZS4gSW5zdGVhZCBvZiBgb3V0cHV0OiBodG1sX2RvY3VtZW50YCB3ZSB1c2UgYGZvcm1hdDogaHRtbGAuIGUuZy4KCn5+fn4KLS0tCnRpdGxlOiAiTXkgUXVhcnRvIERvY3VtZW50Igpmb3JtYXQ6IGh0bWwKYXV0aG9yOiAiTXVycmF5IENhZHpvdyIKLS0tCn5+fn4KCiMjIyBDb2RlIGNodW5rcwoKVGhlIGNvZGUgcGFydCBvZiB0aGUgY29kZSBjaHVua3MgYXJlIGV4YWN0bHkgdGhlIHNhbWUgd2l0aCBxdWFydG8gYXMgaW4gUk1hcmtkb3duLiBXaGVyZSB0aGV5IGRpZmZlciBpcyBob3cgdGhlIGNodW5rIG9wdGlvbnMgYXJlIHByb3ZpZGVkLiBJbnN0ZWFkIG9mIHRoZW0gYmVpbmcgcGxhY2VkIHdpdGhpbiB0aGUgY3VybHkgYnJhY2VzLCB0aGV5IGNhbiBiZSBsaXN0ZWQgaW5zaWRlIHRoZSBibG9jayBhdCB0aGUgdG9wIGZvbGxvd2luZyBhIGAjfGAsIHVzaW5nIHRoZSBga2V5OiB2YWx1ZWAgc3ludGF4IGxpa2UgaW4gdGhlIFlBTUwgaGVhZGVyLCBpbnN0ZWFkIG9mIHVzaW5nIGA9YC4KCgpgYGB7ciBlY2hvID0gRkFMU0UsIGNvbW1lbnQgPSAiIn0KY2F0KGh0bWx0b29sczo6aW5jbHVkZVRleHQoInNjcmlwdHMvY29kZV9jaHVua19xdWFydG8uUm1kIikpCmBgYAoKCiMjIENvbmNsdXNpb24KClRoaXMgbW9kdWxlIGhhcyBvbmx5IHNjcmF0Y2hlZCB0aGUgc3VyZmFjZSBvZiB3aGF0IGlzIHBvc3NpYmxlIHdpdGggdGhlIGhpZ2hseSB2ZXJzYXRpbGUgZm9ybWF0IHRoYXQgaXMgUk1hcmtkb3duLiBUaGUgbWFpbiBiZW5lZml0IHRoYXQgUk1hcmtkb3duIGlzIHRoYXQgaXQgcHJvdmlkZXMgYSBtZWNoYW5pc20gdG8gY3JlYXRlIHJlcHJvZHVjaWJsZSBhbmFseXNpcyBkb2N1bWVudHMgdGhhdCBpbmNsdWRlIHByb3NlLCBjb2RlLCBhbmQgZ2VuZXJhdGVkIG91dHB1dHMuCgpNYWtlIHN1cmUgdG8gY2hlY2sgb3V0IFtSTWFya2Rvd24gLSB0aGUgZGVmaW5pdGl2ZSBndWlkZV0oaHR0cHM6Ly9ib29rZG93bi5vcmcveWlodWkvcm1hcmtkb3duLykgZm9yIGEgY29tcHJlaGVuc2l2ZSBpbnRyb2R1Y3Rpb24gYW5kIGd1aWRlIHRvIHRoZSBwb3NzaWJpbGl0aWVzIG9mIFJNYXJrZG93bi4gVGhlcmUgYXJlIGFsc28gcGFja2FnZXMgZm9yIGNyZWF0aW5nIG11bHRpLWRvY3VtZW50IFJNYXJrZG93biBvdXRwdXRzIHN1Y2ggYXMgZW50aXJlIHdlYnNpdGVzIChgcGFja2FnZWRvd25gLCBgZGlzdGlsbGApLCBibG9ncyAoYGJsb2dkb3duYCksIGFuZCBib29rcyAoYGJvb2tkb3duYCkuCg==