Overview

Welcome to the hands-on, practical learning portion of Lesson 2 where you will create a single page R Markdown document. I made this page to help guide you in the process. The material below contains a series of assignments and challenges designed to get you comfortable utilizing YAML metadata, Markdown syntax, and R code chunks.

The page itself is written almost entirely in R Markdown, meaning there is no extensive use of anything fancy like complicated CSS or HTML. I will introduce some simple HTML code you can use to jazz up your document a little. You should be able to solve any problem I present by digging around in the raw code on GitHub, consulting the Resources page, using one of the targeted search strategies described in the Problem Solving post, and/or posting a question to the Slack channel.

Some Keys to Success

Knit often. Whenever you make a change to the YAML header, add a new code chunk, etc., re-knit (or render) your document. This is very important. Regular knitting allows you to a) see the effects of a change and b) track down (troubleshoot) issues more easily.

Simply hit the knit button or use the shortcut keys—on MacOS Cmd+Shift+K and Windows Ctrl+Shift+K. Learn to love these shortcut keys. They will save you time.

You can choose how your document is previewed using the drop down menu in the document settings. Preview in Window opens the document in a separate RStudio window and Preview in Viewer Pane lets you see the document in the main RStudio IDE. These are good for quick looks. You should always double-check the actual HTML file because sometimes things look different in RStudio.

Something to consider while you create your page is readability. This not only applies to the final document but also the raw R Markdown code itself. Think about someone digging through your code to figure out how you did something. Or think about yourself coming back to the code after a few years. The better your document is formatted, the easier it will be to understand. In future lessons we will return to some best practices but for now remember, part of what we are doing here is making your science more transparent and reproducible. If your document is confusing to follow then it serves neither of these purposes.

Assignment 1: The Basics

In the first assignment, you will employ some basic techniques to control the look of your document and how R code chunks are rendered. We will cover YAML metadata modifications, setting global chunk options, and writing Markdown content. You will also learn about testing R code first before rendering the final document.

1.1 Make a Document

If you have not already done so, your first task is to create an R Markdown document. Open R Studio and go to File > New File > R Markdown. A window should pop up where you can fill in the details. It is not important what you put here since you can change it at any time. What is important is that Document and HTML are both selected. We will cover other document types in the future. Hit Ok and follow the steps in this graphic. Remember, you do not need to add a file extension when you save the document.


Building your initial R Markdown document.

Building your initial R Markdown document.


Once you have a document built and saved, there should be a .html file in your working directory. Double-click that file—it should open in your default browser. Each time you re-knit the .Rmd file, you can just refresh the browser page or double-click the file again.

1.2 Add Markdown Text

Your first task is to add some content and format the content with Markdown. This doesn’t need to be anything fancy to start. You can either add text as you go or paste a large amount of text in at once. Dealers choice. You can use the Markdown section of Lesson 0 or the Markdown section from the Resources page for reference.

  1. Add headers to give the document structure. Use different header levels.
  2. Add hyperlinks. We will learn about internal links later. For now, just link to outside websites.
  3. Add emphasis formatting like bold, italics, and block text.
  4. Mix and match formatting, like make a hyperlink bold or add italics to block text.
  5. Make a list of items.

1.3 Modify & Test R Code Chunks

Now it is time to get some practice modifying code chunk options so you can gain more control over the behavior of code and result display. If you have your own R code you are more than welcome to use it here. I will use the default code chunks that were added to the .Rmd file. Please see the section on Chunk structure & options from Lesson 2 for more details.

Here are the two default code chunks. As you can see, both have names and the second chunk has a single option.

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

There are many code chunk options you can control. Which options you use and how you set them will be determined by your needs. Test the behavior of the following options by setting each equal to either TRUE or FALSE. Render the document and see if you can figure out what changed. Each of these has a default value so you may not see a change until you set the alternative value.

  1. echo
  2. collapse
  3. eval
  4. prompt
  5. highlight
  6. include

Next, it is a really good habit to check code chunks as you add them. This will ensure that each chunk works, making it easier to track down problems. If you refer to the first image on this page, you can you have options for Chunk OutputInline and Console. This controls where the output is displayed. Let’s take a quick look at a code chunk in RStudio and see how you test chunks before rendering.

Take a look at the tool bar on the far right. Option 1 is a drop down menu that gives you an alternative way to set code chunk options. Option 2 will Run all Code Chunks Above meaning that RStudio will run all code chunks above the current chunk but not the current chunk itself. And Option 3 will Run the Current Chunk. Incidentally, if you do not see these options it means something is wrong with the chunk.

Go ahead and run the chunk.

1.4 Modify YAML Metadata

You last task is to modify the YAML header to suit your needs and tastes. I would like you to experiment with different options and settings to see what happens in the final document.

  1. Run ?rmarkdown::html_document or ?html_document in the Console to see the header options for an HTML document.
  2. Add a table of contents and include options that modify the behavior of the table of contents.
  3. Add the option to keep the Markdown document. This will save a .md copy of your file.
  4. Open the .md file in a text editor. This is the output from knitr—after all R code has been processed—and what PanDoc uses to generate an HTML file. Keep this file open as you build your document. Pay attention to how your R code is converted to Markdown syntax.
  5. Change the theme. Options are listed on the Convert to an HTML document help page you opened in RStudio. Try a few options and see what happens.
  6. Change the code highlight option. These too are listed on the help page. Try a few options and see what happens.

Assignment 2: Tables

In this assignment, you will explore different methods of incorporating tables in your document. The choice of method depends on a) the type of data, b) the amount of data, and c) the desired output. I will cover a few tools for creating tables but please note there are many options out there, so look around and let us know if you find a tool you like.

For each example, I will use the mtcars data set from the datasets package. The mtcars data set has 32 rows and 11 columns. Feel free to load your own data table or use the mtcars data set.

Tools

You will use four different tools in this assignment for making tables. Here is a summary table of of each tool.

Table types and recommended uses.
Table type Table size Formatting Options Skill Level
markdown small minimal beginner
rmarkdown::paged_table large minimal beginner
knitr::kable + kableExtra small extensive intermediate
DT + DataTables large extensive advanced


2.1 Markdown

The simplest method of building a table is with Markdown syntax. This is a nice option because you can hard code the table right into the document—no need to install and load libraries or write code chunks—and it is easy to implement. The downside is there is minimal functionality available in a Markdown table.

Markdown does not work well for large tables. So I will first grab a subset of mtcars, specifically the first 4 rows and 3 columns. In my code chunk I add the chunk option comment="". This prevents knit from appending a string (default is ##) to the start of each line of results in the final document.

                mpg cyl disp
Mazda RX4      21.0   6  160
Mazda RX4 Wag  21.0   6  160
Datsun 710     22.8   4  108
Hornet 4 Drive 21.4   6  258


Incidentally, the results box above is technically the simplest table you can make, either by calling the data frame mtcars_sub directly or running print.data.frame(mtcars_sub).

Anyway, run this code chunk, copy the results, and make a Markdown table. You can either run the chunk in RStudio without rendering the document (described above) or render the document and copy the results from HTML page. I added a header to the first column. And here is the Markdown table.


Demonstration of the output from pipe_tables Markdown syntax.
model mpg cyl disp
Mazda RX4 21.0 6 160
Mazda RX4 Wag 21.0 6 160
Datsun 710 22.8 4 108
Hornet 4 Drive 21.4 6 258


Since this is a Markdown table, you can add additional Markdown syntax for formatting. See if you can figure out what syntax I added to my table and add some to your table. Also check out the Tables section of PanDoc User’s Guide for other Markdown table options, including how to add a caption. In addition to pipe_tables, you can create multiline_tables grid_tables, and simple_tables.

Something to notice is that the Markdown table spans the entire width of the page—even though it does not need all of that space. As far as I know, there is no way to control this behavior without adding additional HTML formatting.

Recommendation Use Markdown for small, simple tables where styling is not a concern.

2.2 R Markdown Paged Tables

With larger tables, it may not be practical to display the full table inline. So we need a way to shrink a large table so it looks good while still allowing access to the full table.

The next type of table I want you to try are Paged Tables. R Markdown comes with its own built in table function called paged_table. The paged_table function allows pagination of rows and columns making it possible to render a large table in a small space.

It is easy to code paged_table but that ease comes with a small price—limited functionality. Here are the options you do have with paged_table function.

A Markdown table listing the Options for the paged_table function.
Option Description
rows.print Maximum rows to print per page.
max.print Maximum rows in the table (defaults to 1000).
cols.print Maximum columns in the table (defaults to 10).
rownames.print Print row names as part of the table.

A quick side note. You actually need to load the rmarkdown package for paged_table to work. Anyway, this is a good time to return to the first code chunk in your .Rmd file—the chunk called setup that R Markdown added by default.

I like to use this chunk to load all of the packages I need for my document. Using a single chunk for all of my packages helps me keep my document organized. Notice the setup chunk has the option include=FALSE. This prevents the content of the chunk from appearing in the final document, which for me is more stylistically appealing. I can add a sessionInfo() chunk at the end of my document to report all of the packages so this information is available to the reader. We will cover sessionInfo() when we get into more depth on the subject of reproducible. If you do not want to load the library you can run the command like this: rmarkdown::paged_table().

OK, back to the table. Now I can create a table of mtcars with the paged_table function and use an option to limit the number of printed rows to 5 for each page. I used echo=FALSE in my code chunk to hide the code :). By now you should know where to look for a solution.


Notice that for each column, the column class is printed below the name (text enclosed in < >). This is irritating and related to printing a table from a built-in data frame. I have no idea how to fix this (within the confines of R Markdown) but I will work on a solution.

Recommendation Use paged_table for large tables where extensive styling is not a concern.

2.3 Kable Tables

Knitr comes with its own tool for rendering simple tables called kable. The documentation for kable can be found here or by running ?knitr::kable() in the Console. By itself, kable comes with almost no options. We can extend its functionality with the kableExtra package and piping syntax from magrittr. The features of kableExtra are extensive and I will only touch on a few here. The documentation for kableExtra can be found here or by running ?kableExtra in the Console after the package has been installed and loaded.

I highly recommend you learn how to use these packages for making tables.

Again, you will need to load kableExtra and either load the knitr package or run the command like this: knitr::kable().

First, let’s look at the default kable table output. We will use the head of the mtcars data set.


Wow, this table looks terrible.
mpg cyl disp hp drat wt qsec vs am gear carb
Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1
Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2
Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1


If we tried to render the entire table by omitting head, we would just get a long, crappy table in our document. Not cool. Lets see if we can jazz this up a bit with kableExtra.

This table looks better
mpg cyl disp hp drat wt qsec vs am gear carb
Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1
Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2
Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1

Here I used the pipe operator (%>%) to pass the results of kable to the function kable_styling—a part of the kableExtra package. By running kable_styling as is, I am using defaults for all of the options.

The pipe operator is a powerful tool worth learning.

Back to the table. It certainly looks better than the default kable version but we are missing the ability to page the table. I would like you to run these two commands and look at the output.

This command will include the whole table.

kable(mtcars) %>%
  kable_styling()

And this command will transpose the table (swap rows and columns) using the transpose (t) function. Remember, mtcars has 32 rows and 11 columns but when you transpose the table, it has 11 rows and 32 columns. So it is really wide in the transposed state.

kable(head(t(mtcars))) %>%
  kable_styling()

I hope you agree that neither of these tables are acceptable, especially the second one. Unfortunately, the kableExtra package does not come with an option to add pagination. You can however put the table in a fixed-height, fixed-width (or both) box, and make it scrollable. We can do this by using a pipe operator and the scroll_box function. While we are at it, lets also add tweak some options in kable_styling to make a more handsome table.

Scrollable kable table.
Mazda RX4 Mazda RX4 Wag Datsun 710 Hornet 4 Drive Hornet Sportabout Valiant Duster 360 Merc 240D Merc 230 Merc 280 Merc 280C Merc 450SE Merc 450SL Merc 450SLC Cadillac Fleetwood Lincoln Continental Chrysler Imperial Fiat 128 Honda Civic Toyota Corolla Toyota Corona Dodge Challenger AMC Javelin Camaro Z28 Pontiac Firebird Fiat X1-9 Porsche 914-2 Lotus Europa Ford Pantera L Ferrari Dino Maserati Bora Volvo 142E
mpg 21.00 21.000 22.80 21.400 18.70 18.10 14.30 24.40 22.80 19.20 17.80 16.40 17.30 15.20 10.40 10.400 14.700 32.40 30.400 33.900 21.500 15.50 15.200 13.30 19.200 27.300 26.00 30.400 15.80 19.70 15.00 21.40
cyl 6.00 6.000 4.00 6.000 8.00 6.00 8.00 4.00 4.00 6.00 6.00 8.00 8.00 8.00 8.00 8.000 8.000 4.00 4.000 4.000 4.000 8.00 8.000 8.00 8.000 4.000 4.00 4.000 8.00 6.00 8.00 4.00
disp 160.00 160.000 108.00 258.000 360.00 225.00 360.00 146.70 140.80 167.60 167.60 275.80 275.80 275.80 472.00 460.000 440.000 78.70 75.700 71.100 120.100 318.00 304.000 350.00 400.000 79.000 120.30 95.100 351.00 145.00 301.00 121.00
hp 110.00 110.000 93.00 110.000 175.00 105.00 245.00 62.00 95.00 123.00 123.00 180.00 180.00 180.00 205.00 215.000 230.000 66.00 52.000 65.000 97.000 150.00 150.000 245.00 175.000 66.000 91.00 113.000 264.00 175.00 335.00 109.00
drat 3.90 3.900 3.85 3.080 3.15 2.76 3.21 3.69 3.92 3.92 3.92 3.07 3.07 3.07 2.93 3.000 3.230 4.08 4.930 4.220 3.700 2.76 3.150 3.73 3.080 4.080 4.43 3.770 4.22 3.62 3.54 4.11
wt 2.62 2.875 2.32 3.215 3.44 3.46 3.57 3.19 3.15 3.44 3.44 4.07 3.73 3.78 5.25 5.424 5.345 2.20 1.615 1.835 2.465 3.52 3.435 3.84 3.845 1.935 2.14 1.513 3.17 2.77 3.57 2.78
qsec 16.46 17.020 18.61 19.440 17.02 20.22 15.84 20.00 22.90 18.30 18.90 17.40 17.60 18.00 17.98 17.820 17.420 19.47 18.520 19.900 20.010 16.87 17.300 15.41 17.050 18.900 16.70 16.900 14.50 15.50 14.60 18.60
vs 0.00 0.000 1.00 1.000 0.00 1.00 0.00 1.00 1.00 1.00 1.00 0.00 0.00 0.00 0.00 0.000 0.000 1.00 1.000 1.000 1.000 0.00 0.000 0.00 0.000 1.000 0.00 1.000 0.00 0.00 0.00 1.00
am 1.00 1.000 1.00 0.000 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.000 0.000 1.00 1.000 1.000 0.000 0.00 0.000 0.00 0.000 1.000 1.00 1.000 1.00 1.00 1.00 1.00
gear 4.00 4.000 4.00 3.000 3.00 3.00 3.00 4.00 4.00 4.00 4.00 3.00 3.00 3.00 3.00 3.000 3.000 4.00 4.000 4.000 3.000 3.00 3.000 3.00 3.000 4.000 5.00 5.000 5.00 5.00 5.00 4.00
carb 4.00 4.000 1.00 1.000 2.00 1.00 4.00 2.00 2.00 4.00 4.00 3.00 3.00 3.00 4.00 4.000 4.000 1.00 2.000 1.000 1.000 2.00 2.000 4.00 2.000 1.000 2.00 2.000 4.00 6.00 8.00 2.00


For the scroll_box function I set the width = "100%" rather than specifying a dimension. This ensures the box will always be the width of the page no matter how small the window is.

Even though you cannot make a paged table with kable, there are many styling options available in the kableExtra package that makes this method extremely useful and worth learning. Plus, the code is relatively simple to write.

I want to show you one more feature that is not available the other table methods we cover in this Assignment—floating. Let’s first subset the mtcars data set so we can make a small table. Next we use the full_width and position options to control the size and position of the table.

Here is our code chunk.

mpg cyl disp hp drat wt
Mazda RX4 21.0 6 160 110 3.90 2.620
Mazda RX4 Wag 21.0 6 160 110 3.90 2.875
Datsun 710 22.8 4 108 93 3.85 2.320
Hornet 4 Drive 21.4 6 258 110 3.08 3.215
Hornet Sportabout 18.7 8 360 175 3.15 3.440
Valiant 18.1 6 225 105 2.76 3.460
Duster 360 14.3 8 360 245 3.21 3.570


Let’s say we have a bunch of text that we want to put side-by-side with this small table. Our subsetted mtcars data set now has 7 rows and 6 columns. We can make our table smaller by setting full_width = FALSE in kable_styling and float the table by setting position = "float_right"

Please study the extensive options available in kable and kableExtra and create tables that implement some of the options.



Recommendation Use kable + kableExtra for small tables where extensive styling is desired.

2.4 DT Tables

The last option I want to cover for building tables is implemented using the datatable function from the DT package, an interface to the JavaScript library DataTables. To demonstrate the functionality, I will use a larger data set called USJudgeRatings from the datasets package. USJudgeRatings has 43 rows and 12 columns. This table is too big—horizontally and vertically—to fit on a standard page.

The syntax for the DT::datatable is more complicated than the other methods but that comes with more extensive functionality.

Working with DT::datatable is an advanced level skill. I highly recommend you learn how to use the package, but it will take practice.

Please make sure you are comfortable with the other methods first before trying to use DT::datatable. I promise, if you do not know what you are doing, this package will cause a lot of frustration. That said, I use it all the time because it is awesome.

Moving on. If we run DT on the USJudgeRatings data set without any options the table will spill off the side of the page. Again, not cool. Try to run this command and see what happens.

datatable(USJudgeRatings)

DT::datatable does not page tables horizontally like the paged_table command does (described above). We can set the width of the table and add an option that allows horizontal scrolling. For this we use the options argument. The syntax is to add width = "100%" followed by options = list(), where we put a comma separated list of options. For now, we just include scrollX in our list of options.


Play around with the table a little. As you can see

  • the table now fits in the window,
  • horizontal scrolling in enabled,
  • the page is vertically paged,
  • there is a Show entries drop down, and
  • there is a Search box.

The Show entries and Search box are added by default. We can decide whether to show these options or not. I will save that for later. For now, I want to leave you with a more stylized DT data table to give you a sense of the possibilities. Don’t worry so much about the code—pay attention to the functionality.



I added buttons to download the table to different formats, changed the page length to 5, and changed the values in the Show entries drop down. Play around with the table. There is a lot more to do with this package and we will come back to it often.

Recommendation Use DT::datatable for large tables where extensive styling is desired.

That’s all for this assignment.

Assignment 3: Code

If you are interested in making your science more transparent and reproducible, you need to provide at least two things—the raw data you generated and the code you used to analyze it. Hopefully it is obvious by now that you need to provide access to both components; neither is particularly useful without the other. We will cover data availability in a future lesson. For this assignment, you will practice several different methods for making your code accessible. The method or methods you choose for your own work will depend on the type of analyses and the type of code.

Your assignment is to implement these methods in your document and play around with the different options.

Purl

Knitr comes with a built-in function called purl, which allows you to extract all the R code from an R Markdown document and convert it to an R script. In order to run purl, you must either load the knitr library first (i.e., library(knitr)) and then run purl or call the function directly by running knitr::purl(). We will start by discussing some simple options for running purl and then talk about how you run the command. The basic structure of the command is:

knitr::purl(input="filename.Rmd", documentation = L)

By default, purl uses the base name of the input file as the base name of the output file. If you want to control this behavior, add the option output="filename.R" where filename is whatever you choose.

The option documentation is an integer that specifies the level (L) of documentation to add to the script. You have three choices

  • 0 means output pure code to the script, discard all Markdown text and code chunk details.
  • 1 (the default) means discard all Markdown text but add the chunk headers to the script as commented lines.
  • 2 means to add all Markdown text and code chunks to the script as commented lines.

As far as I know, you cannot run purl from inside an actual code chunk. I have no idea why nor was I able to find an answer. If have an answer or know a solution, please let us know. There easiest way to generate an R script from an R Markdown document with purl to is to run the command in the Console like so:

knitr::purl(input="filename.Rmd", documentation = 1)

Run the purl command using the three options described above for documentation option and look at the output files.

Inline R expressions are ignored by default. For example, if you had an inline R expression like this `r sqrt(2)` the expression would not be included in the R script generated by purl. If you want to include inline expressions in the R script, you need to set the global R option knitr.purl.inline = TRUE before calling knitr::purl().

Remember way back when you generated your initial R Markdown document a default code chunk was added just below the YAML header?

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

If you add knitr.purl.inline = TRUE to that code chunk, all inline expressions will be added to the R script.

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

The last thing I want to mention is that you can prevent certain code chunks from appearing in the R Script by adding the option purl = FALSE to the chunk. For example, if you add this option to the setup chunk we just discussed that chunk will not appear in the final document.

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

Test the behavior of the different options for purl on your document. You can also use this funtion on any R Markdown document to quickly retrieve the code. For example, if you download the Rmd file for this page from GitHub you can run purl to quickly extract the R code.

Recommendation Use purl to generate a simple R script version of your R Markdown document after the document is finished and saved. You can then link to the file somewhere in your document.

Download Rmd

I hope by now you have seen that any document I present in this course has a link to a GitHub repo where you can download or copy the .Rmd file. That’s great and all, but wouldn’t it be nice if you could do it right from the HTML page? Well, you can by adding one simple line of code as a property of html_document in your YAML header —code_download: true.

output:
  html_document:
    theme: journal
    toc: true
    toc_float: true
    toc_depth: 3
    highlight: tango
    code_download: true

You could of course set the property to false except this is the default value and nothing will change. Look back at the top of this page and you should now see a Code button in the upper right corner. Click on the drop down and select Download Rmd and this entire page should be saved to your Downloads directory.

Go ahead and add this option to your YAML header.

Code Folding

I have mentioned a time or two that the benefits of using R Markdown is the ability to execute and display code in your final document. If you go back to the default setup chunk at the top of your .Rmd you should see this:

knitr::opts_chunk$set(echo = TRUE)

I discussed this chunk previously in #5 of the Chunk structure & options section in Lesson 2. Briefly, this is a global command that ensures all R code chunks are visible in the final document, unless you escape this behavior by using echo = FALSE in a particular chunk. Of course, you could also set the global option to FALSE as is knitr::opts_chunk$set(echo = FALSE) and then none of the R code would be visible at all. This is a perfectly fine option in some situations but not in others.

Let’s face it—code takes up a lot of space in a document and large code chunks are not particularly pleasing to look at. You may encounter situations where you both want the code available on a page but you also want to hide the code. For this we use a technique called code folding. Near the bottom of Lesson 0, I used some simple HTML to make a section that folds the R code for the Clifford Attractor. There is a little Show/hide button that allows you to look at the code if you want to; otherwise it is hidden by default. But this approach is a little clunky because you must a) know some HTML and b) include this for every chunk.

R Markdown has a similar functionality for showing and hiding code but it only takes a single line of code added to the YAML header. Again, return to your YAML header and add the argument code_folding: as a nested property of html_document:. Your two options for code_folding: are show and hide.

output:
  html_document:
    theme: journal
    toc: true
    toc_float: true
    toc_depth: 3
    highlight: tango
    code_download: true
    code_folding: hide

Once you add this to the YAML header, the drop down Code button in the upper right corner of the page should now include Show All Code and Hide All Code. This allows the user to specify how they want to view the code in the document. Either property you set for code_folding will be the default state for the entire document.

You should also notice that a new Code button appears next to every code chunk in your document. Again, if you want to exclude the code from individual chunks, just set echo = FALSE for that chunk and the code will not be included at all.

Add code_folding: argument to your YAML header and set a property value.


As far as I know there is no way of folding the results of a code chunk or folding individual chunks unless you use HTML.

That’s all for this assignment.

Assignment 4: Graphics

The last major piece of the puzzle is to add graphics to your R Markdown document. Think of this Assignment more as a mini guidebook and less as a to-do list of activities. The reason being, is that the topic of graphics is much too broad to cover in-depth during this course.

For the sake of convenience, I will use figure to refer to any visual representation of data (chart, plot, graph, etc.) made with (R) code and generated when the document is rendered. An image on the other hand, is any external visual product inserted into the document, like a png or jpg.

The distinction is that figures are created when the R Markdown document is rendered, and the R code is processed. In contrast, images are added to the rendered document by referencing a file.

Let’s look at an example that demonstrates the difference between a figure and an image. We can use the built-in pressure data set from the datasets package and the plot command to display a temperature-by-pressure plot. Here is the simple line of code followed by the figure that is created when the document is rendered.

Figure generated with R code and rendered in the final document.

Figure generated with R code and rendered in the final document.

Basically, when I knit the R Markdown file (.Rmd) three things happen. First, knitr reads the code chunk, creates the plot, and saves the plot as a .png file. Next, knitr adds a line of code to the subsequent Markdown file (.md), which links to the .png file. Finally, PanDoc embeds the .png file into the HTML document. And just like that, I have a plot in my HTML document from a single line of R code.

Now instead let’s say I need to do some post-processing on the plot. I want the points to be larger and red, but I am too lazy to figure out how to code this in R (you should not be so lazy). I can use the same code to generate the plot in R but this time I will manually save the plot as a png file. I then make the modifications in a vector graphics program like Inkscape, save the modified file, and then use Markdown code in my .Rmd file to include the image in the final document. In this case, the plot is added directly to the HTML document by PanDoc rather than first being generated by knitr.

# Markdown code in the Rmd file to add an image.
![](files/pressure_modified.png)

Image added to the rendered document by referencing a file using Mardown.

Of course, you can add any image you want. The image does not need to be generated by R code or be a png. For example, here is a Girih tile mosaic I made using the online tool Girih Designer.

![](files/girih.jpg)


Girih tiles are a set of regular polygons (with overlaid strapwork) used in medieval Islamic architecture. Check out this cool Science paper from 2007 that explores the geometry behind Girih tiles.


It is important to understand the distinction between code-generated figures vs. imported images. You need different tools to display and control each type of graphic.

Your goal for this Assignment is to add figures and images to your R Markdown page.

Check out this blog post from ZevRoss on Tips and tricks for working with images and figures in R Markdown documents. I reference this resource a lot.

Figures

I think a lot about data visualization and in my opinion, it is one of the most important skills you can develop as you move forward with your own work.

The simple graph has brought more information to the data analyst’s mind than any other device. — John Tukey

Almost any kind of data can be visualized and there are literally dozens and dozens of figure types you can create with R code. This includes maps, networks, flow charts, dendrograms, and so on. In an HTML document, it is possible to create both static and interactive figures. However, data visualization in R is a broad topic and can often get quite complicated. In addition to the numerous chart types, there are many R packages you can use for visualizations. Some, like ggplot2, have extensive functionality while others (e.g., leaflet) are more appropriate for specific types of data and/or visualizations. Ultimately, the approach you choose will depend on your data and the type of message you want to convey.

My point in saying this is that a comprehensive tutorial on data visualization in R is simply beyond the scope of this Assignment. If there is sufficient interest in particular packages and/or chart types I am happy to write a lesson plan. For now, I would like to focus on a few best practices and strategies that I think are important for creating visualization products using code in your R Markdown document.

  1. Select an appropriate chart type to suite your needs.
  2. Whenever possible, always generate figures in your R Markdown document using (R) code.
  3. If you use color in your figures, pay special attention to your color palette.
  4. How to control the output.


This list is far from comprehensive. There is a paper in PLoS Computational Biology from 2014 on Ten Simple Rules for Better Figures, which provides a nice primer on the subject of figure design.

If you want to get deeper into visualization methods and techniques, beyond what we discuss here, I strongly encourage you to learn more about the work of Edward Tufte, widely recognized as a pioneer in the field of data visualization.

For some inspiration, I also recommend visiting Martin Krzywinski data visualization site. The site itself is dense, but Martin’s visualizations are incredible, and the site is updated often.


1. Select a chart type

One of the first things to think about is what kind of chart you want to create. As I mentioned, this will depend on the type of data you have and the message you are trying to convey. There are different factors to consider when selecting a chart type and many online tools available to help narrow down your selection.

W3Schools.com
The original Chart Chooser designed and published by Andrew Abela. The Chart Chooser is a flowchart guide that helps you identify the type of chart that is appropriate to your data. Click on the image to download a PDF copy.


The Chart Chooser was originally published in 2009 so it is a bit old now. But it can give you a good place to start when choosing a chart type. Cool Infographics by Randy Krum has a nice DataViz page that provides a more up-to-date collection of data visualization chart choosers, reference guides, and cheat sheets.

Yan Holtz has developed several websites dedicated to data visualization. These resources are AMAZING not to mention that his websites are beautiful. Please look at Yan’s From Data to Viz page. This page is interactive and designed to help you choose the most appropriate chart for your data. It has links to the code, explanations, and common mistakes to avoid.

Assignment: Spend time familiarizing yourself with different data visualization techniques and chart types. Think about your own data and data visualization needs.


2. Create your figure

The next step is to write the code for your figure. Where possible, I highly recommend that you code all of your figures directly in the R Markdown document. Coding your figures directly is beneficial for several reasons. By creating figures directly in an R Markdown document and including the code you can:

  • Provide more reproducible & transparent workflows. If you present a figure with the code and the underlying data, your readers can easily validate your findings.
  • Help others. Have you ever seen a graphic and wondered how it was created? By making the code available in your document, you help others create badass figures.
  • Always remember. How many times have you created a figure and then forgotten how you made it? Well, no more. Now your figures are directly tied to the code
  • Reuse code blocks. You may find yourself using the same chart type over and over in your work. Rather than rewriting the same code each time, you can reuse the code chunk.
  • Easily make changes. My goal is to code figures that are as close to production ready as possible. By that I mean creating figures that need little or no post-processing before going into a publication. If I need to change some part of a figure, I simply modify the code and re-render the document. This keep post-processing to a minimum.

Here is an example of what I mean. On the left is the published version of an NMDS plot from a recent paper. On the right is the raw version of the plot generated with R code only—before any post-processing.

PDF post-processed in Inkscape R code only saved to PDF

I hope you agree that the differences between the two are minor. In the final version, I changed the location of the legend, moved some labels around for clarity, modified the font, and tweaked the vector overlays. Again, the goal is to code as much of the figure as possible, relying of vector graphics programs like Inkscape and Illustrator for beautification only.

As I mentioned above, teaching and learning R code to generate figures is currently beyond the scope of this course. That said, I want you to explore the resources listed below. Doing so will give you a better sense of different chart types and the R code used to generate them. If you do not know much R, start by copying code and then playing around with different parameters. And make sure you understand the default setting.

Your Assignment is to select 2-3 different chart types and add the R code to your document. Ideally, you would use your own data but feel free to use the dummy data provided with the examples.

If you have not used R to generate figures before, I highly recommend you first look at the Tutorial on Graphs from the Introduction to R course by Ernesto Bonadies, Lee Dietterich, Tauana Cunha, and Bruno de Medeiros. The tutorial covers some built-in R graphing functions as well as ggplot2. It’s a great tutorial.

Remember, your visualization needs are particular to you and your needs. Find some charts that look interesting or useful and add them to your document. Of course, I am more than happy to help you implement any type of graph in your document :)

  • Yan Holtz’s From Data to Viz page.
  • The R Graph Gallery, a collection of charts made with R. Charts are divided into several sections and each comes with chart with reproducible code. Click here to see every chart on the site.
  • If you want to use other languages, similar pages are available for D3.js (a JavaScript library) and Python.

  • r-statistics.co by Selva Prabhakaran has Top 50 ggplot2 Visualizations (with full R Code).

  • Leaflet is one of the most popular open-source JavaScript libraries for interactive maps. Code + Tutorials.


3. Color

I want to turn now to the topic of color. A question to ask yourself is do I need to use color in this figure? If you are unsure, the answer is probably ‘no’. High-contrast black and white graphics can be more readable than color and also better for copying and printing. So, if you don’t need color then don’t use it.

Edward Tufte is fond of saying that color can be your best ally or your worst enemy. Color is an important visual dimension that can help tell a compelling story. However, when it is not used correctly, color can be counterproductive and lead to confusion about the message a figure is trying to convey.

In my field—microbial ecology—we often rely on color to display information about diversity. Microbial diversity is pretty vast, and it can be difficult to display all of this diversity in a single, static figure. All too often, people misuse color and the literature is full of figures that are very difficult to interpret. I thought about showing you some actual examples but felt that it would be a little mean-spirited. Instead, I made a figure using my own data to demonstrate this point.

Here, each bar represents a different sample and each color a different microbial Class.

<small>*Example of **color as an enemy**. This figure has way too many colors to convey a clear message. Unfortunately, figures like this are common in the literature*. </small>

Example of color as an enemy. This figure has way too many colors to convey a clear message. Unfortunately, figures like this are common in the literature.

When you use too many colors you force your reader to continually go back and forth from the chart to the legend. This is annoying, confusing, and ultimately detracts from the meaning of the figure.

Another problem is that many of us have different abilities to perceive color and/or differences in color. Color blindness, also known as color vision deficiency, is a decreased ability to see color or differences in color. When designing figures, it is important to use a) a relatively small color palette and b) a palette that is friendly to a variety of people.

For more information on the topic, I recommend reading Bang Wong’s Nature Methods paper, Points of view: Color blindness. Wong proposes a color-blind friendly color palette that uses contrasting colors that can be distinguished by a range of people. Consider that roughly 8% of people (mostly males) are color blind. So, what do you think? Do you want Keanu Reeves to understand your figures or not? If so, consider a color scheme that is friendly to all vision types

Wong’s scheme is conservative—there are only 8 colors. Others have developed 12,13, and 15 color palette schemes that offer more options than Wong’s palette. Just be careful—–figures with too many colors can inhibit our ability to discern patterns.

Limited color palettes like these force us to be more careful when deciding what information to target or how many groups to display. For your consideration, I have included a few color-blind friendly color palettes. You can download these colors as plain text by clicking on the palette title.

CONSERVATIVE 8-COLOR PALETTE
Color Name HEX RGB
_______ black #000000 0, 0, 0
_______ blue #0072B2 0, 114, 178
_______ sky blue #56B4E9 86, 180, 233
_______ reddish purple #CC79A7 204, 121, 167
_______ bluish green #009E73 0, 158, 115
_______ vermillion #D55E00 213, 94, 0
_______ orange #E69F00 230, 159, 0
_______ yellow #F0E442 240, 228, 66
12-COLOR PALETTE
Color Name HEX RGB
_______ dark grey #323232 50, 50, 50
_______ jazzberry jam #BF3465 191, 52, 101
_______ kepel #50B29E 80, 178, 158
_______ light grey #D9D9D9 217, 217, 217
_______ seance #731683 115, 22, 131
_______ mariner #1C6CCC 28, 108, 204
_______ capri #21BCFF 33, 188, 255
_______ pale plum #DFA5E5 223, 165, 229
_______ saddle brown #874310 135, 67, 16
_______ mars yellow #DB6D1B 219, 109, 27
_______ fuego #B8CE17 184, 206, 23
_______ paris daisy #F4E345 244, 227, 69
13-COLOR PALETTE
Color Name HEX RGB
_______ black #000000 0, 0, 0
_______ blue lagoon #006E82 0, 110, 130
_______ seance #8214A0 130, 20, 160
_______ science blue #005AC8 0, 90, 200
_______ azure radiance #00A0FA 0, 160, 250
_______ blush pink #FA78FA 250, 120, 250
_______ bright turquoise #14D2DC 20, 210, 220
_______ shiraz #AA0A3C 170, 10, 60
_______ salem #0A9B4B 10, 155, 75
_______ salmon #FF825F 255, 130, 95
_______ ronchi #EAD644 234, 214, 68
_______ mint green #A0FA82 160, 250, 130
_______ dairy cream #FAE6BE 250, 230, 190
15-COLOR PALETTE
Color Name HEX RGB
_______ black #000000 0, 0, 0
_______ sherpa blue #004949 0 73 73
_______ persian green #009292 0 146 146
_______ hot pink #ff6db6 255, 109, 182
_______ cotton candy #ffb6db 255, 182, 219
_______ pigment indigo #490092 73 0 146
_______ science blue #006ddb 0, 109, 219
_______ heliotrope #b66dff 182 109 255
_______ malibu #6db6ff 109, 182, 255
_______ french pass #b6dbff 182 216 255
_______ red berry #920000 146, 0, 0
_______ brown #924900 146 73 0
_______ mango tango #db6d00 219, 109, 0
_______ harlequin #24ff24 36, 255, 36
_______ laser lemon #ffff6d 255, 255, 109

If you want to create your own color palette (say based on Wong’s colors) you would write the code like this. Then you could pass the character string wong_pal to any place you need a color palette.

Here is another great article on Coloring for Colorblindness by David Nichols that has an interactive color picker and recommendations for accessible palettes.

Remember, these are only suggestions. Ultimately, it is your choice how to use color and what palettes work best for you needs, I am merely offering some food for thought. Again, color and figure design are very broad—I encourage you to spend some time exploring these topics in more depth with the reference I provided. See where it takes you.


4. Controlling the output

The last thing we need to discuss is how to control the way your plot is rendered in the final document. Individual R packages have different options for controlling various aspects of a plot or chart including color, point size, line thickness, axis labels, etc. Again, this topic is beyond the scope of this lesson but let’s look at an example anyway. We return to our simple example from above using the plot function with the cars data set. We can use different built-in options to modify the chart (color added for demonstration purposes only).

This code controls the plot style but not how the plot is rendered in the final document. By that I mean the size and alignment of the plot in the HTML document. To control these aspects, you will need to use various code chunk options. Knowing how to code each chunk option and knowing what each does takes some practice. Let’s look at a few of the most common options.

  • fig.align: (‘character’) Alignment of figures in the output document (possible values are left, right and center. Note, character values must be enclosed in single quotation marks like so: 'center'.
  • fig.width and fig.height: (default are 7 and 5, respectively; numeric) Width and height of the plot (in inches). Note Only works with R-generated figures.
  • fig.asp: (default NULL; numeric) The aspect ratio of the plot, i.e. the ratio of height/width; when fig.asp is specified, the height of a plot (the chunk option fig.height) is calculated from fig.width X fig.asp
  • fig.dim: (default NULL; numeric) Numeric vector of length 2, it gives fig.width and fig.height, e.g., fig.dim = c(5, 7) is a shorthand of fig.width = 5, fig.height = 7; if both fig.asp and fig.dim are provided, fig.asp will be ignored (with a warning)
  • out.width, out.height: (NULL; character OR numeric) Width and height of the plot in the final output file (can be different with its real fig.width and fig.height, i.e. plots can be scaled in the output document). For example, as a percent out.width = '80% or in pixels out.width = 600px.
  • fig.cap: (NULL; character) Figure caption to be used. Note, character values must be enclosed in single quotation marks like so: 'This is a figure caption'.

OK, let’s use chunk options to change the size and alignment and add a caption. I will hide the R code since it is the same as above. If you want to see the chunk options you need to look at the raw .Rmd file on the GitHub repo.

This is a figure caption.

This is a figure caption.

If you want to display multiple figures side-by-side, you need to set fig.show='hold'. This chunk option holds all plots and outputs them at the very end of a code chunk, as opposed to printing them one by one. You also need to set out.width equal to a percent value divided by the number of plots. For example, suppose we want to display three plots side-by-side, we need to set out.width='33%'.

```{r grid, fig.show='hold', out.width='33%'}
p1 <- plot(pressure)
p2 <- plot(cars)
p3 <- plot(pressure)
```

There are more sophisticated ways to display multiple figures using something like grid.arrange (from the gridExtra package) or plot_grid (from the cowplot package). I encourage you to look at these packages.

Play around with these options to see how it affects the final output. Chunk options for figures can be confusing at times but you will get the hang of it with a bit of practice.

That is all I have to say about figures. Again, this is a broad topic and I suggest you look around to see what is possible. If there is something specific you want to do please post it to the Slack channel.

Images

The other type of graphic you may want to use is an image—any externally generated visual product inserted into the document, like a png or jpg. When plots are not generated with R code, there is no way for knitr to capture plots automatically. In this case, you may generate the images manually and then pass their file paths to some other function to include these images in the output. Don’t worry, this section is not long. First I want to cover a few best practices and then go over different ways of displaying and controlling images.

Best practices

In R Markdown, you can use GIF (Graphic Interchange Format) for simple animations or SVG (Scalable Vector Graphics) for things like logos and maps. These file types are used in special situations and will not be covered here. By far the easiest file types to work with in R Markdown for static images are PNG (Portable Network Graphics) and JPG/JPEG (Joint Photographic Experts Group). There are really no strict rules for when you should use PNG vs. JPG. Generally speaking though:

  • PNG is usually better for graphics like charts & graphs, images with text, anything with high contrast colors, or for images that contain less color data. The other advantage is that unlike JPG, PNG format supports a transparent background. PNGs are also better for screenshots.
  • JPG is usually better for high color and photographs. Another advantage is the it is easier to reduce file sizes without compromising quality. However, JPG does not support transparent background.

Another thing to consider is image compression. Nothing slows down a website more than a bulky image. So always compress your images before adding them to your website. There are a ton of online and standalone compression tools available for compression. I use the tools from WebsitePlanet and Optimizilla. Honestly, I haven’t spent a ton of time comparing tools, but I want you to find a couple that work for you.

If you plan on working a lot with images, I strongly encourage you to get familiar with the different file types and compression options.

Adding images in R Markdown

I would like to cover three basic methods to add images to an R Markdown document.

  1. Markdown
  2. knitr::include_graphics
  3. The magick package


1. Markdown code

Markdown syntax is the easiest way to add an image, however you sacrifice control because there are very few options. I demonstrated the Markdown syntax way back at the beginning of this assignment but at this point it’s probably a distant memory. So, let’s review. The syntax is simple. Start a new line with an !, followed by open and closed brackets ([]), and then the relative file path, like so:

![](files/julia.png)

Image of a Julia set, an iterated function system generated using the equation \(f_{c}(z)=z^{2}+c\) where \(c\) is a complex number, in this case \(c=-0.7269 + 0.1889i\). Downloaded from Wikimedia Commons, created by IkamusumeFan, and licensed under CC-BY-SA-4.0.


You can also display multiple images side-by-side using Markdown. In this case, you must specify the width of an image (where \(width \leq 100/n\) & \(n = no. of images\)) and put the Markdown code for each image on the same line (no space between the two tags).


![](files/julia.png){width=50%}![](files/julia2.png){width=50%}

Two different Julia sets. The image on the right (\(c = −0.835 − 0.2321i\)) was downloaded from Wikimedia Commons, created by Simpsons_contributor, and released under the public domain.

We can also use Markdown code to include an image directly from a URL.

![](https://upload.wikimedia.org/wikipedia/commons/0/0a/Subsection_Bifurcation_Diagram_Logistic_Map.png)

A chaotic region from the bifurcation diagram of the logistic map, derived by iterating the equation \(x_{n+1} = rx(1-x_n)\) over all values for \(r[0,4]\). The map was popularized in a paper by the biologist Robert May entitled Simple mathematical models with very complicated dynamics. Image by InXnI and licensed under CC0. Original.


The issue with using Markdown code for images is that there are few options. It is difficult to make modifications without using HTML and CSS.


2. knitr::include_graphics

If you want a bit more control over the output you can use a built-in knitr function called include_graphics. The major advantage of this function is that it is portable, meaning that it works for all document formats that knitr supports. That way you do not need to use different syntax for different document types to embed an external image. Since we use include_graphics within a chunk, several chunk options are available for controlling the output. Go to your console window in RStudio and type ?knitr::include_graphics to see the help menu. As you can see, there are very few options. Most of the control will come from using chunk options.

Note, the double colon (::) in this command specifies the exact function from that specific package. This prevents any problems from arising if another package also has the same function name. I am not aware of any other packages that have the function include_graphics but the convention I have seen is the knitr::include_graphics so I will use that here. It is up to you whether or not you want to use the double colon.

It is important to note that some of the chunk options we used for figures will not work for images.

Specifically, fig.width, fig.height, and fig.dim do not work with images. To control the size, we need to use out.width and out.height. Remember, out.width and out.height need either a character (e.g., '50%') OR a numeric (600px) value. We also have access to fig.align for placement and fig.cap to add a caption. Here is a code chunk using knitr::include_graphics.

```{r cave1, fig.cap="INSERT CAPTION.", out.width = '100%', fig.align='left'}
knitr::include_graphics("files/cave.jpg")
```
*The Great Hall of Polychromes, [Cave of Altamira](https://en.wikipedia.org/wiki/Cave_of_Altamira), published by M. Sanz de Sautuola in 1880 ([original](https://commons.wikimedia.org/wiki/File:Altamira-1880.jpg)) licensed under the [public domain](https://en.wikipedia.org/wiki/Public_domain)*.

The Great Hall of Polychromes, Cave of Altamira, published by M. Sanz de Sautuola in 1880 (original) licensed under the public domain.

As we did above when we displayed figures side-by-side, we can do the same with images and the include_graphics function. Here again we fig.show='hold' and specify the out.width. We use the c function to combine values—in this case image file names—into a list. This is analogous to the Markdown syntax we used above fir displaying images side-by-side.

```{r cave_rock, out.width='50%', fig.cap="INSERT CAPTION", fig.show='hold', fig.align='left'}
knitr::include_graphics(c("files/cave.jpg","files/rock.jpg"))
```
<small><em>The Great Hall of Polychromes (right) & rock painting of [Mimi spirits](https://en.wikipedia.org/wiki/Mimi_(folklore)) from [Kakadu National Park](https://commons.wikimedia.org/wiki/Kakadu_National_Park). [Original](https://en.wikipedia.org/wiki/Nourlangie_Rock#/media/File:Anbangbang_gallery_Mimi_rock_art_cropped.jpg) licensed under [CC BY-SA 2.5](https://creativecommons.org/licenses/by-sa/2.5) by Dustin M. Ramsey ([Kralizec!](https://en.wikipedia.org/wiki/User:Kralizec!)).</em></small><small><em>The Great Hall of Polychromes (right) & rock painting of [Mimi spirits](https://en.wikipedia.org/wiki/Mimi_(folklore)) from [Kakadu National Park](https://commons.wikimedia.org/wiki/Kakadu_National_Park). [Original](https://en.wikipedia.org/wiki/Nourlangie_Rock#/media/File:Anbangbang_gallery_Mimi_rock_art_cropped.jpg) licensed under [CC BY-SA 2.5](https://creativecommons.org/licenses/by-sa/2.5) by Dustin M. Ramsey ([Kralizec!](https://en.wikipedia.org/wiki/User:Kralizec!)).</em></small>

The Great Hall of Polychromes (right) & rock painting of Mimi spirits from Kakadu National Park. Original licensed under CC BY-SA 2.5 by Dustin M. Ramsey (Kralizec!).

As we did with Markdown, we can also use knitr::include_graphics to add an image directly from the web.

<small><em>The Hummingbird (part of the [Nazca Lines](https://en.wikipedia.org/wiki/Nazca_Lines)) by [Diego Delso](https://commons.wikimedia.org/wiki/User:Poco_a_poco) licensed under [CC BY-SA](https://creativecommons.org/licenses/by-sa/4.0/).</em></small>

The Hummingbird (part of the Nazca Lines) by Diego Delso licensed under CC BY-SA.


3. The magick package: Advanced image-processing in R

The magick package is designed to modernize and simplify high-quality image processing in R by wrapping the ImageMagick STL. First, install magick in R using this command:

install.packages("magick")

Then add this to your setup code chunk:

library(magick)

I will highlight just a few of the options available in the magick package, but please know this package has a lot of functionality. Much of what we controlled above with chunk options (e.g., out.width) can instead be controlled directly with magick. In addition, you can edit images, add text annotation, include filters and effects, animate, overlay images, etc. This package is definitely worth learning, especially if you plan to work with images.

I will not use any code chunk options to control the behavior of the image so I can demonstrate some of the magick functionality. For this demonstration I will use an image of the wings of a female Blue-Spotted Hawker, Adversaeschna brevistyla by Jogn Tann licensed under CC BY 2.0. For this demonstration the jpg was converted to png using JPG to PNG then imported to Gimp where I cropped the imaged and made the background transparent. OK. Displaying an image is easy using the image_read command. I will set the variable wings so I can manipulate the image later on without needing to call the path. We can use the print command to get some details about the image. If you do not plan to make any changes you can simply run the command without the variable name.

## # A tibble: 1 x 7
##   format width height colorspace matte filesize density
##   <chr>  <int>  <int> <chr>      <lgl>    <int> <chr>  
## 1 PNG     9759   4455 sRGB       TRUE   1063380 72x72

This image is much larger than the page so knitr resized it to fit in the page container.

How about changing the background color and adding a border? This is an example of stringing together multiple commands. Cool.

We can also flip the image and resize proportionally to height of 200px.

Every time we call an image_-like command, magick will print the image. So, unless we want a bunch of images we need to assign a variable each time we use an image_ command. Then we can simply call the variable to print the image.

How about we make a set of wings? To do this, I will:

  1. Read in the wings.png file. These are the right-side wings.
  2. Scale the image (remember the file is really big).
  3. Crop the image because there is a lot of white space.
  4. Copy the modified image and reflect it around the vertical axis to make left-side wings. 5) Combine the images to make a wing set.

First I read in the file and assign it to the variable right. Next, I scale the image using the image_scale command. Notice I set the dimensions to x400. This means resize proportionally to height of 200px. If I wanted to resize proportionally to width I would write it like this, 400.

Now I will crop the image with image_crop. This was a bit of a pain, but basically I left the height the same by specifying x400 and then set cropped 150px off the left of the image. You really just need to play around with this to get it right.

Finally, I use the c command to combine the variables into a list and then use image_append to print them side-by-side. Now we have a set of wings.


Your Assignment is to work through the magick tutorial and use magick in your document.

If you have a pretty big document already, I recommend starting a new dummy document for this tutorial. That way you can make changes and render the document more quickly. Work with JPG files, PNG files with a transparent background, and SVGs. You can also use the magick package with R code generated figures so play with that too. Learn the magick package by working through the tutorial.


That’s all for this Assignment and for Lesson 2. You should now have all the big pieces you need to make an awesome, single-page, R Markdown document.

Session Info

## R version 4.0.0 (2020-04-24)
## Platform: x86_64-apple-darwin17.0 (64-bit)
## Running under: macOS Catalina 10.15.4
## 
## Matrix products: default
## BLAS:   /Library/Frameworks/R.framework/Versions/4.0/Resources/lib/libRblas.dylib
## LAPACK: /Library/Frameworks/R.framework/Versions/4.0/Resources/lib/libRlapack.dylib
## 
## locale:
## [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
##  [1] magick_2.3       cowplot_1.0.0    ggplot2_3.3.0    gridExtra_2.3   
##  [5] scales_1.1.0     DT_0.13          rmarkdown_2.1    kableExtra_1.1.0
##  [9] epuRate_0.1      knitr_1.28      
## 
## loaded via a namespace (and not attached):
##  [1] Rcpp_1.0.4.6      highr_0.8         pillar_1.4.4      compiler_4.0.0   
##  [5] base64enc_0.1-3   tools_4.0.0       digest_0.6.25     jsonlite_1.6.1   
##  [9] gtable_0.3.0      evaluate_0.14     lifecycle_0.2.0   tibble_3.0.1     
## [13] viridisLite_0.3.0 png_0.1-7         pkgconfig_2.0.3   rlang_0.4.6      
## [17] cli_2.0.2         rstudioapi_0.11   crosstalk_1.1.0.1 yaml_2.2.1       
## [21] xfun_0.13         withr_2.2.0       dplyr_0.8.5       stringr_1.4.0    
## [25] httr_1.4.1        xml2_1.3.2        vctrs_0.2.4       htmlwidgets_1.5.1
## [29] hms_0.5.3         tidyselect_1.0.0  webshot_0.5.2     grid_4.0.0       
## [33] glue_1.4.0        R6_2.4.1          fansi_0.4.1       purrr_0.3.4      
## [37] readr_1.3.1       magrittr_1.5      ellipsis_0.3.0    htmltools_0.4.0  
## [41] assertthat_0.2.1  rvest_0.3.5       colorspace_1.4-1  utf8_1.1.4       
## [45] stringi_1.4.6     munsell_0.5.0     crayon_1.3.4
LS0tCnRpdGxlOiAiW0xlc3NvbiAyOiBQcmFjdGljYWwgUGFnZV0oaHR0cHM6Ly9naXRodWIuY29tL3N0cmktY29uL2RjLXNpbmdsZS9ibG9iL21hc3Rlci9pbmRleC5SbWQpIgphdXRob3I6ICJieSBKYXJyb2QiCmRhdGU6ICJgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVkICVCLCAlWScpYCIKc21hcnQ6IHRydWUKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICB0aGVtZTogY2VydWxlYW4KICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICB0b2NfZGVwdGg6IDMKICAgIGhpZ2hsaWdodDogdGFuZ28KICAgIGtlZXBfbWQ6IHRydWUKICAgIHNlbGZfY29udGFpbmVkOiB0cnVlCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCiAgICBjb2RlX2ZvbGRpbmc6IHNob3cKICAgIGNzczogc3R5bGVzLmNzcwojb3V0cHV0OgojICBlcHVSYXRlOjplcHVyYXRlOgojICAgIHRvYzogVFJVRQojICAgIG51bWJlcl9zZWN0aW9uczogRkFMU0UKIyAgICBjb2RlX2ZvbGRpbmc6ICJzaG93IgplZGl0b3Jfb3B0aW9uczoKICBjaHVua19vdXRwdXRfdHlwZTogaW5saW5lCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwga25pdHIucHVybC5pbmxpbmUgPSBUUlVFKQpzZXQuc2VlZCg5MTEpCmBgYAoKYGBge3IgbG9hZF9saWJzLCBpbmNsdWRlPUZBTFNFfQpsaWJyYXJ5KGtuaXRyKQpsaWJyYXJ5KGVwdVJhdGUpCmxpYnJhcnkoa2FibGVFeHRyYSkKbGlicmFyeShybWFya2Rvd24pCmxpYnJhcnkoRFQpCmxpYnJhcnkoc2NhbGVzKQpsaWJyYXJ5KGdyaWRFeHRyYSkKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGNvd3Bsb3QpCmxpYnJhcnkobWFnaWNrKQpgYGAKCiMjIE92ZXJ2aWV3CgpXZWxjb21lIHRvIHRoZSBoYW5kcy1vbiwgcHJhY3RpY2FsIGxlYXJuaW5nIHBvcnRpb24gb2YgW0xlc3NvbiAyXShodHRwczovL3N0cmktY29uLmdpdGh1Yi5pby9kYXRhLWN1cmF0aW9uLzIwMjAvMDQvMDkvbGVzc29uLTIvKSB3aGVyZSB5b3Ugd2lsbCBjcmVhdGUgYSBzaW5nbGUgcGFnZSBSIE1hcmtkb3duIGRvY3VtZW50LiBJIG1hZGUgdGhpcyBwYWdlIHRvIGhlbHAgZ3VpZGUgeW91IGluIHRoZSBwcm9jZXNzLiBUaGUgbWF0ZXJpYWwgYmVsb3cgY29udGFpbnMgYSBzZXJpZXMgb2YgYXNzaWdubWVudHMgYW5kIGNoYWxsZW5nZXMgZGVzaWduZWQgdG8gZ2V0IHlvdSBjb21mb3J0YWJsZSB1dGlsaXppbmcgW1lBTUwgbWV0YWRhdGFdKGh0dHBzOi8vc3RyaS1jb24uZ2l0aHViLmlvL2RhdGEtY3VyYXRpb24vMjAyMC8wNC8wOS9sZXNzb24tMi8jdGhlLXlhbWwtaGVhZGVyLTEpLCBbTWFya2Rvd24gc3ludGF4XShodHRwczovL3N0cmktY29uLmdpdGh1Yi5pby9kYXRhLWN1cmF0aW9uLzIwMjAvMDQvMDkvbGVzc29uLTIvI21hcmtkb3duLWZvcm1hdHRlZC10ZXh0LTEpLCBhbmQgW1IgY29kZSBjaHVua3NdKGh0dHBzOi8vc3RyaS1jb24uZ2l0aHViLmlvL2RhdGEtY3VyYXRpb24vMjAyMC8wNC8wOS9sZXNzb24tMi8jci1jb2RlLWNodW5rcy0xKS4KClRoZSBwYWdlIGl0c2VsZiBpcyB3cml0dGVuIGFsbW9zdCBlbnRpcmVseSBpbiBSIE1hcmtkb3duLCBtZWFuaW5nIHRoZXJlIGlzIG5vIGV4dGVuc2l2ZSB1c2Ugb2YgYW55dGhpbmcgZmFuY3kgbGlrZSBjb21wbGljYXRlZCAgQ1NTIG9yIEhUTUwuIEkgd2lsbCBpbnRyb2R1Y2Ugc29tZSBzaW1wbGUgSFRNTCBjb2RlIHlvdSBjYW4gdXNlIHRvIGphenogdXAgeW91ciBkb2N1bWVudCBhIGxpdHRsZS4gWW91IHNob3VsZCBiZSBhYmxlIHRvIHNvbHZlIGFueSBwcm9ibGVtIEkgcHJlc2VudCBieSBkaWdnaW5nIGFyb3VuZCBpbiB0aGUgcmF3IGNvZGUgb24gR2l0SHViLCBjb25zdWx0aW5nIHRoZSBbUmVzb3VyY2VzIHBhZ2VdKGh0dHBzOi8vc3RyaS1jb24uZ2l0aHViLmlvL2RhdGEtY3VyYXRpb24vcGFnZS9yZXNvdXJjZXMvKSwgdXNpbmcgb25lIG9mIHRoZSB0YXJnZXRlZCBzZWFyY2ggc3RyYXRlZ2llcyBkZXNjcmliZWQgaW4gdGhlIFtQcm9ibGVtIFNvbHZpbmcgcG9zdF0oaHR0cHM6Ly9zdHJpLWNvbi5naXRodWIuaW8vZGF0YS1jdXJhdGlvbi8yMDIwLzA0LzAzL2hlbHAvKSwgYW5kL29yIHBvc3RpbmcgYSBxdWVzdGlvbiB0byB0aGUgU2xhY2sgY2hhbm5lbC4KCiMjIFNvbWUgS2V5cyB0byBTdWNjZXNzCgo+ICoqS25pdCBvZnRlbioqLiBXaGVuZXZlciB5b3UgbWFrZSBhIGNoYW5nZSB0byB0aGUgWUFNTCBoZWFkZXIsIGFkZCBhIG5ldyBjb2RlIGNodW5rLCBldGMuLCByZS1rbml0IChvciByZW5kZXIpIHlvdXIgZG9jdW1lbnQuIFRoaXMgaXMgdmVyeSBpbXBvcnRhbnQuIFJlZ3VsYXIga25pdHRpbmcgYWxsb3dzIHlvdSB0byAqKmEqKikgc2VlIHRoZSBlZmZlY3RzIG9mIGEgY2hhbmdlIGFuZCAqKmIqKikgdHJhY2sgZG93biAodHJvdWJsZXNob290KSBpc3N1ZXMgbW9yZSBlYXNpbHkuCj4KPiBTaW1wbHkgaGl0IHRoZSBrbml0IGJ1dHRvbiBvciB1c2UgdGhlIHNob3J0Y3V0IGtleXMtLS1vbiBNYWNPUyBgQ21kYCtgU2hpZnRgK2BLYCBhbmQgV2luZG93cyBgQ3RybGArYFNoaWZ0YCtgS2AuIExlYXJuIHRvIGxvdmUgdGhlc2Ugc2hvcnRjdXQga2V5cy4gVGhleSB3aWxsIHNhdmUgeW91IHRpbWUuCgpZb3UgY2FuIGNob29zZSBob3cgeW91ciBkb2N1bWVudCBpcyBwcmV2aWV3ZWQgdXNpbmcgdGhlIGRyb3AgZG93biBtZW51IGluIHRoZSBkb2N1bWVudCBzZXR0aW5ncy4gYFByZXZpZXcgaW4gV2luZG93YCBvcGVucyB0aGUgZG9jdW1lbnQgaW4gYSBzZXBhcmF0ZSBSU3R1ZGlvIHdpbmRvdyBhbmQgYFByZXZpZXcgaW4gVmlld2VyIFBhbmVgIGxldHMgeW91IHNlZSB0aGUgZG9jdW1lbnQgaW4gdGhlIG1haW4gUlN0dWRpbyBJREUuIFRoZXNlIGFyZSBnb29kIGZvciAqcXVpY2sqIGxvb2tzLiBZb3Ugc2hvdWxkICoqYWx3YXlzKiogZG91YmxlLWNoZWNrIHRoZSBhY3R1YWwgSFRNTCBmaWxlIGJlY2F1c2Ugc29tZXRpbWVzIHRoaW5ncyBsb29rIGRpZmZlcmVudCBpbiBSU3R1ZGlvLgo8YnIvPgoKIVtdKGZpbGVzL3ByZXZpZXcucG5nKQoKU29tZXRoaW5nIHRvIGNvbnNpZGVyIHdoaWxlIHlvdSBjcmVhdGUgeW91ciBwYWdlIGlzICpyZWFkYWJpbGl0eSouIFRoaXMgbm90IG9ubHkgYXBwbGllcyB0byB0aGUgZmluYWwgZG9jdW1lbnQgYnV0IGFsc28gdGhlIHJhdyBSIE1hcmtkb3duIGNvZGUgaXRzZWxmLiBUaGluayBhYm91dCBzb21lb25lIGRpZ2dpbmcgdGhyb3VnaCB5b3VyIGNvZGUgdG8gZmlndXJlIG91dCBob3cgeW91IGRpZCBzb21ldGhpbmcuIE9yIHRoaW5rIGFib3V0IHlvdXJzZWxmIGNvbWluZyBiYWNrIHRvIHRoZSBjb2RlIGFmdGVyIGEgZmV3IHllYXJzLiBUaGUgYmV0dGVyIHlvdXIgZG9jdW1lbnQgaXMgZm9ybWF0dGVkLCB0aGUgZWFzaWVyIGl0IHdpbGwgYmUgdG8gdW5kZXJzdGFuZC4gSW4gZnV0dXJlIGxlc3NvbnMgd2Ugd2lsbCByZXR1cm4gdG8gc29tZSBiZXN0IHByYWN0aWNlcyBidXQgZm9yIG5vdyByZW1lbWJlciwgcGFydCBvZiB3aGF0IHdlIGFyZSBkb2luZyBoZXJlIGlzIG1ha2luZyB5b3VyIHNjaWVuY2UgbW9yZSAqdHJhbnNwYXJlbnQqIGFuZCAqcmVwcm9kdWNpYmxlKi4gSWYgeW91ciBkb2N1bWVudCBpcyBjb25mdXNpbmcgdG8gZm9sbG93IHRoZW4gaXQgc2VydmVzIG5laXRoZXIgb2YgdGhlc2UgcHVycG9zZXMuCgojIyBBc3NpZ25tZW50IDE6IFRoZSBCYXNpY3MKCkluIHRoZSBmaXJzdCBhc3NpZ25tZW50LCB5b3Ugd2lsbCBlbXBsb3kgc29tZSBiYXNpYyB0ZWNobmlxdWVzIHRvIGNvbnRyb2wgdGhlIGxvb2sgb2YgeW91ciBkb2N1bWVudCBhbmQgaG93IFIgY29kZSBjaHVua3MgYXJlIHJlbmRlcmVkLiBXZSB3aWxsIGNvdmVyIFlBTUwgbWV0YWRhdGEgbW9kaWZpY2F0aW9ucywgc2V0dGluZyBnbG9iYWwgY2h1bmsgb3B0aW9ucywgYW5kIHdyaXRpbmcgTWFya2Rvd24gY29udGVudC4gWW91IHdpbGwgYWxzbyBsZWFybiBhYm91dCB0ZXN0aW5nIFIgY29kZSBmaXJzdCBiZWZvcmUgcmVuZGVyaW5nIHRoZSBmaW5hbCBkb2N1bWVudC4KCiMjIyAxLjEgTWFrZSBhIERvY3VtZW50CgpJZiB5b3UgaGF2ZSBub3QgYWxyZWFkeSBkb25lIHNvLCB5b3VyIGZpcnN0IHRhc2sgaXMgdG8gY3JlYXRlIGFuIFIgTWFya2Rvd24gZG9jdW1lbnQuIE9wZW4gUiBTdHVkaW8gYW5kIGdvIHRvIGBGaWxlID4gTmV3IEZpbGUgPiBSIE1hcmtkb3duYC4gQSB3aW5kb3cgc2hvdWxkIHBvcCB1cCB3aGVyZSB5b3UgY2FuIGZpbGwgaW4gdGhlIGRldGFpbHMuIEl0IGlzIG5vdCBpbXBvcnRhbnQgd2hhdCB5b3UgcHV0IGhlcmUgc2luY2UgeW91IGNhbiBjaGFuZ2UgaXQgYXQgYW55IHRpbWUuIFdoYXQgaXMgaW1wb3J0YW50IGlzIHRoYXQgKipEb2N1bWVudCoqIGFuZCAqKkhUTUwqKiBhcmUgYm90aCBzZWxlY3RlZC4gV2Ugd2lsbCBjb3ZlciBvdGhlciBkb2N1bWVudCB0eXBlcyBpbiB0aGUgZnV0dXJlLiBIaXQgYE9rYCBhbmQgZm9sbG93IHRoZSBzdGVwcyBpbiB0aGlzIGdyYXBoaWMuIFJlbWVtYmVyLCB5b3UgZG8gbm90IG5lZWQgdG8gYWRkIGEgZmlsZSBleHRlbnNpb24gd2hlbiB5b3Ugc2F2ZSB0aGUgZG9jdW1lbnQuCgo8YnIvPgoKYGBge3IgbWFrZV9ybWQsIGVjaG89RkFMU0UsIGNhY2hlPVRSVUUsIGZpZy5jYXA9IkJ1aWxkaW5nIHlvdXIgaW5pdGlhbCBSIE1hcmtkb3duIGRvY3VtZW50LiIgfQppbmNsdWRlX2dyYXBoaWNzKCJmaWxlcy9tYWtlLXJtZC5naWYiKQpgYGAKCjxici8+CgpPbmNlIHlvdSBoYXZlIGEgZG9jdW1lbnQgYnVpbHQgYW5kIHNhdmVkLCB0aGVyZSBzaG91bGQgYmUgYSBgLmh0bWxgIGZpbGUgaW4geW91ciB3b3JraW5nIGRpcmVjdG9yeS4gRG91YmxlLWNsaWNrIHRoYXQgZmlsZS0tLWl0IHNob3VsZCBvcGVuIGluIHlvdXIgZGVmYXVsdCBicm93c2VyLiBFYWNoIHRpbWUgeW91IHJlLWtuaXQgdGhlIGAuUm1kYCBmaWxlLCB5b3UgY2FuIGp1c3QgcmVmcmVzaCB0aGUgYnJvd3NlciBwYWdlIG9yIGRvdWJsZS1jbGljayB0aGUgZmlsZSBhZ2Fpbi4KCiMjIyAxLjIgQWRkIE1hcmtkb3duIFRleHQKCllvdXIgZmlyc3QgdGFzayBpcyB0byBhZGQgc29tZSBjb250ZW50IGFuZCBmb3JtYXQgdGhlIGNvbnRlbnQgd2l0aCBNYXJrZG93bi4gVGhpcyBkb2Vzbid0IG5lZWQgdG8gYmUgYW55dGhpbmcgZmFuY3kgdG8gc3RhcnQuIFlvdSBjYW4gZWl0aGVyIGFkZCB0ZXh0IGFzIHlvdSBnbyBvciBwYXN0ZSBhIGxhcmdlIGFtb3VudCBvZiB0ZXh0IGluIGF0IG9uY2UuIERlYWxlcnMgY2hvaWNlLiBZb3UgY2FuIHVzZSB0aGUgW01hcmtkb3duXShodHRwczovL3N0cmktY29uLmdpdGh1Yi5pby9kYXRhLWN1cmF0aW9uLzIwMjAvMDMvMjgvbGVzc29uLTAvI21hcmtkb3duLTMpIHNlY3Rpb24gb2YgTGVzc29uIDAgb3IgdGhlIFtNYXJrZG93bl0oaHR0cHM6Ly9zdHJpLWNvbi5naXRodWIuaW8vZGF0YS1jdXJhdGlvbi9wYWdlL3Jlc291cmNlcy8jbWFya2Rvd24pIHNlY3Rpb24gZnJvbSB0aGUgUmVzb3VyY2VzIHBhZ2UgZm9yIHJlZmVyZW5jZS4KCjEpIEFkZCBoZWFkZXJzIHRvIGdpdmUgdGhlIGRvY3VtZW50IHN0cnVjdHVyZS4gVXNlIGRpZmZlcmVudCBoZWFkZXIgbGV2ZWxzLgoyKSBBZGQgaHlwZXJsaW5rcy4gV2Ugd2lsbCBsZWFybiBhYm91dCAqaW50ZXJuYWwqIGxpbmtzIGxhdGVyLiBGb3Igbm93LCBqdXN0IGxpbmsgdG8gb3V0c2lkZSB3ZWJzaXRlcy4KMykgQWRkIGVtcGhhc2lzIGZvcm1hdHRpbmcgbGlrZSBib2xkLCBpdGFsaWNzLCBhbmQgYmxvY2sgdGV4dC4KNCkgTWl4IGFuZCBtYXRjaCBmb3JtYXR0aW5nLCBsaWtlIG1ha2UgYSBoeXBlcmxpbmsgYm9sZCBvciBhZGQgaXRhbGljcyB0byBibG9jayB0ZXh0Lgo1KSBNYWtlIGEgbGlzdCBvZiBpdGVtcy4KCiMjIyAxLjMgTW9kaWZ5ICYgVGVzdCBSIENvZGUgQ2h1bmtzCgpOb3cgaXQgaXMgdGltZSB0byBnZXQgc29tZSBwcmFjdGljZSBtb2RpZnlpbmcgY29kZSBjaHVuayBvcHRpb25zIHNvIHlvdSBjYW4gZ2FpbiBtb3JlIGNvbnRyb2wgb3ZlciB0aGUgYmVoYXZpb3Igb2YgY29kZSBhbmQgcmVzdWx0IGRpc3BsYXkuIElmIHlvdSBoYXZlIHlvdXIgb3duIFIgY29kZSB5b3UgYXJlIG1vcmUgdGhhbiB3ZWxjb21lIHRvIHVzZSBpdCBoZXJlLiBJIHdpbGwgdXNlIHRoZSBkZWZhdWx0IGNvZGUgY2h1bmtzIHRoYXQgd2VyZSBhZGRlZCB0byB0aGUgYC5SbWRgIGZpbGUuIFBsZWFzZSBzZWUgdGhlIHNlY3Rpb24gb24gW0NodW5rIHN0cnVjdHVyZSAmIG9wdGlvbnNdKGh0dHBzOi8vc3RyaS1jb24uZ2l0aHViLmlvL2RhdGEtY3VyYXRpb24vMjAyMC8wNC8wOS9sZXNzb24tMi8jY2h1bmstc3RydWN0dXJlLW9wdGlvbnMtMSkgZnJvbSBMZXNzb24gMiBmb3IgbW9yZSBkZXRhaWxzLgoKSGVyZSBhcmUgdGhlIHR3byBkZWZhdWx0IGNvZGUgY2h1bmtzLiBBcyB5b3UgY2FuIHNlZSwgYm90aCBoYXZlIG5hbWVzIGFuZCB0aGUgc2Vjb25kIGNodW5rIGhhcyBhIHNpbmdsZSBvcHRpb24uCgpgYGBgCmBgYHtyIGNhcnN9YHIgJydgCnN1bW1hcnkoY2FycykKYGBgCmBgYGAKCmBgYGAKYGBge3IgcHJlc3N1cmUsIGVjaG89RkFMU0V9YHIgJydgCnBsb3QocHJlc3N1cmUpCmBgYApgYGBgCgpUaGVyZSBhcmUgbWFueSBjb2RlIGNodW5rIG9wdGlvbnMgeW91IGNhbiBjb250cm9sLiBXaGljaCBvcHRpb25zIHlvdSB1c2UgYW5kIGhvdyB5b3Ugc2V0IHRoZW0gd2lsbCBiZSBkZXRlcm1pbmVkIGJ5IHlvdXIgbmVlZHMuIFRlc3QgdGhlIGJlaGF2aW9yIG9mIHRoZSBmb2xsb3dpbmcgb3B0aW9ucyBieSBzZXR0aW5nIGVhY2ggZXF1YWwgdG8gZWl0aGVyIGBUUlVFYCBvciBgRkFMU0VgLiBSZW5kZXIgdGhlIGRvY3VtZW50IGFuZCBzZWUgaWYgeW91IGNhbiBmaWd1cmUgb3V0IHdoYXQgY2hhbmdlZC4gRWFjaCBvZiB0aGVzZSBoYXMgYSBkZWZhdWx0IHZhbHVlIHNvIHlvdSBtYXkgbm90IHNlZSBhIGNoYW5nZSB1bnRpbCB5b3Ugc2V0IHRoZSBhbHRlcm5hdGl2ZSB2YWx1ZS4KCjEpIGBlY2hvYAoyKSBgY29sbGFwc2VgCjMpIGBldmFsYAo0KSBgcHJvbXB0YAo1KSBgaGlnaGxpZ2h0YAo2KSBgaW5jbHVkZWAKCk5leHQsIGl0IGlzIGEgcmVhbGx5IGdvb2QgaGFiaXQgdG8gY2hlY2sgY29kZSBjaHVua3MgYXMgeW91IGFkZCB0aGVtLiBUaGlzIHdpbGwgZW5zdXJlIHRoYXQgZWFjaCBjaHVuayB3b3JrcywgbWFraW5nIGl0IGVhc2llciB0byB0cmFjayBkb3duIHByb2JsZW1zLiBJZiB5b3UgcmVmZXIgdG8gdGhlIGZpcnN0IGltYWdlIG9uIHRoaXMgcGFnZSwgeW91IGNhbiB5b3UgaGF2ZSBvcHRpb25zIGZvciAqKkNodW5rIE91dHB1dCoqLS0tKklubGluZSogYW5kICpDb25zb2xlKi4gVGhpcyBjb250cm9scyB3aGVyZSB0aGUgb3V0cHV0IGlzIGRpc3BsYXllZC4gTGV0J3MgdGFrZSBhIHF1aWNrIGxvb2sgYXQgYSBjb2RlIGNodW5rIGluIFJTdHVkaW8gYW5kIHNlZSBob3cgeW91IHRlc3QgY2h1bmtzIGJlZm9yZSByZW5kZXJpbmcuCgohW10oZmlsZXMvcnVuLWNodW5rLnBuZykKClRha2UgYSBsb29rIGF0IHRoZSB0b29sIGJhciBvbiB0aGUgZmFyIHJpZ2h0LiAqKk9wdGlvbiAxKiogaXMgYSBkcm9wIGRvd24gbWVudSB0aGF0IGdpdmVzIHlvdSBhbiBhbHRlcm5hdGl2ZSB3YXkgdG8gc2V0IGNvZGUgY2h1bmsgb3B0aW9ucy4gKipPcHRpb24gMioqIHdpbGwgKlJ1biBhbGwgQ29kZSBDaHVua3MgQWJvdmUqIG1lYW5pbmcgdGhhdCBSU3R1ZGlvIHdpbGwgcnVuIGFsbCBjb2RlIGNodW5rcyBhYm92ZSB0aGUgY3VycmVudCBjaHVuayBidXQgbm90IHRoZSBjdXJyZW50IGNodW5rIGl0c2VsZi4gQW5kICoqT3B0aW9uIDMqKiB3aWxsICpSdW4gdGhlIEN1cnJlbnQgQ2h1bmsqLiBJbmNpZGVudGFsbHksIGlmIHlvdSBkbyBub3Qgc2VlIHRoZXNlIG9wdGlvbnMgaXQgbWVhbnMgc29tZXRoaW5nIGlzIHdyb25nIHdpdGggdGhlIGNodW5rLgoKR28gYWhlYWQgYW5kIHJ1biB0aGUgY2h1bmsuCgojIyMgMS40IE1vZGlmeSBZQU1MIE1ldGFkYXRhCgpZb3UgbGFzdCB0YXNrIGlzIHRvIG1vZGlmeSB0aGUgWUFNTCBoZWFkZXIgdG8gc3VpdCB5b3VyIG5lZWRzIGFuZCB0YXN0ZXMuIEkgd291bGQgbGlrZSB5b3UgdG8gZXhwZXJpbWVudCB3aXRoIGRpZmZlcmVudCBvcHRpb25zIGFuZCBzZXR0aW5ncyB0byBzZWUgd2hhdCBoYXBwZW5zIGluIHRoZSBmaW5hbCBkb2N1bWVudC4KCjEpIFJ1biBgP3JtYXJrZG93bjo6aHRtbF9kb2N1bWVudGAgb3IgYD9odG1sX2RvY3VtZW50YCBpbiB0aGUgQ29uc29sZSB0byBzZWUgdGhlIGhlYWRlciBvcHRpb25zIGZvciBhbiBIVE1MIGRvY3VtZW50LgoyKSBBZGQgYSB0YWJsZSBvZiBjb250ZW50cyBhbmQgaW5jbHVkZSBvcHRpb25zIHRoYXQgbW9kaWZ5IHRoZSBiZWhhdmlvciBvZiB0aGUgdGFibGUgb2YgY29udGVudHMuCjMpIEFkZCB0aGUgb3B0aW9uIHRvIGtlZXAgdGhlIE1hcmtkb3duIGRvY3VtZW50LiBUaGlzIHdpbGwgc2F2ZSBhIGAubWRgIGNvcHkgb2YgeW91ciBmaWxlLgo0KSBPcGVuIHRoZSBgLm1kYCBmaWxlIGluIGEgdGV4dCBlZGl0b3IuIFRoaXMgaXMgdGhlIG91dHB1dCBmcm9tIGBrbml0cmAtLS1hZnRlciBhbGwgUiBjb2RlIGhhcyBiZWVuIHByb2Nlc3NlZC0tLWFuZCB3aGF0IFBhbkRvYyB1c2VzIHRvIGdlbmVyYXRlIGFuIEhUTUwgZmlsZS4gS2VlcCB0aGlzIGZpbGUgb3BlbiBhcyB5b3UgYnVpbGQgeW91ciBkb2N1bWVudC4gUGF5IGF0dGVudGlvbiB0byBob3cgeW91ciBSIGNvZGUgaXMgY29udmVydGVkIHRvIE1hcmtkb3duIHN5bnRheC4KNSkgQ2hhbmdlIHRoZSB0aGVtZS4gT3B0aW9ucyBhcmUgbGlzdGVkIG9uIHRoZSAqQ29udmVydCB0byBhbiBIVE1MIGRvY3VtZW50KiBoZWxwIHBhZ2UgeW91IG9wZW5lZCBpbiBSU3R1ZGlvLiBUcnkgYSBmZXcgb3B0aW9ucyBhbmQgc2VlIHdoYXQgaGFwcGVucy4KNikgQ2hhbmdlIHRoZSBjb2RlIGhpZ2hsaWdodCBvcHRpb24uIFRoZXNlIHRvbyBhcmUgbGlzdGVkIG9uIHRoZSBoZWxwIHBhZ2UuIFRyeSBhIGZldyBvcHRpb25zIGFuZCBzZWUgd2hhdCBoYXBwZW5zLgoKIyMgQXNzaWdubWVudCAyOiBUYWJsZXMKCkluIHRoaXMgYXNzaWdubWVudCwgeW91IHdpbGwgZXhwbG9yZSBkaWZmZXJlbnQgbWV0aG9kcyBvZiBpbmNvcnBvcmF0aW5nIHRhYmxlcyBpbiB5b3VyIGRvY3VtZW50LiBUaGUgY2hvaWNlIG9mIG1ldGhvZCBkZXBlbmRzIG9uICoqYSoqKSB0aGUgdHlwZSBvZiBkYXRhLCAqKmIqKikgdGhlIGFtb3VudCBvZiBkYXRhLCBhbmQgKipjKiopIHRoZSBkZXNpcmVkIG91dHB1dC4gSSB3aWxsIGNvdmVyIGEgZmV3IHRvb2xzIGZvciBjcmVhdGluZyB0YWJsZXMgYnV0IHBsZWFzZSBub3RlIHRoZXJlIGFyZSBbbWFueSBvcHRpb25zXShodHRwczovL3Jmb3J0aGVyZXN0b2Z1cy5jb20vMjAxOS8xMS9ob3ctdG8tbWFrZS1iZWF1dGlmdWwtdGFibGVzLWluLXIvKSBvdXQgdGhlcmUsIHNvIGxvb2sgYXJvdW5kIGFuZCBsZXQgdXMga25vdyBpZiB5b3UgZmluZCBhIHRvb2wgeW91IGxpa2UuCgpGb3IgZWFjaCBleGFtcGxlLCBJIHdpbGwgdXNlIHRoZSBgbXRjYXJzYCBkYXRhIHNldCBmcm9tIHRoZSBgZGF0YXNldHNgIHBhY2thZ2UuIFRoZSBgbXRjYXJzYCBkYXRhIHNldCBoYXMgYHIgbnJvdyhtdGNhcnMpYCByb3dzIGFuZCBgciBuY29sKG10Y2FycylgIGNvbHVtbnMuIEZlZWwgZnJlZSB0byBsb2FkIHlvdXIgb3duIGRhdGEgdGFibGUgb3IgdXNlIHRoZSBgbXRjYXJzYCBkYXRhIHNldC4KCiMjIyBUb29scwoKWW91IHdpbGwgdXNlIGZvdXIgZGlmZmVyZW50IHRvb2xzIGluIHRoaXMgYXNzaWdubWVudCBmb3IgbWFraW5nIHRhYmxlcy4gSGVyZSBpcyBhIHN1bW1hcnkgdGFibGUgb2Ygb2YgZWFjaCB0b29sLgoKfCBUYWJsZSB0eXBlICAgICAgICAgICAgICAgICAgICB8IFRhYmxlIHNpemUgICAgICAgfCAgRm9ybWF0dGluZyBPcHRpb25zICB8IFNraWxsIExldmVsICAgICAgfAp8LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXw6LS0tLS0tLS0tLS0tLS0tLTp8Oi0tLS0tLS0tLS0tLS0tLS0tLS0tOnw6LS0tLS0tLS0tLS0tLS0tLTp8CnwgYG1hcmtkb3duYCAgICAgICAgICAgICAgICAgICAgfCBzbWFsbCAgICAgICAgICAgIHwgbWluaW1hbCAgICAgICAgICAgICAgfCBiZWdpbm5lciAgICAgICAgIHwKfCBgcm1hcmtkb3duOjpwYWdlZF90YWJsZWAgICAgICB8IGxhcmdlICAgICAgICAgICAgfCBtaW5pbWFsICAgICAgICAgICAgICB8IGJlZ2lubmVyICAgICAgICAgfAp8IGBrbml0cjo6a2FibGVgICsgYGthYmxlRXh0cmFgIHwgc21hbGwgICAgICAgICAgICB8IGV4dGVuc2l2ZSAgICAgICAgICAgIHwgaW50ZXJtZWRpYXRlICAgICB8CnwgYERUYCArIGBEYXRhVGFibGVzYCAgICAgICAgICAgfCBsYXJnZSAgICAgICAgICAgIHwgZXh0ZW5zaXZlICAgICAgICAgICAgfCBhZHZhbmNlZCAgICAgICAgIHwKVGFibGU6ICpUYWJsZSB0eXBlcyBhbmQgcmVjb21tZW5kZWQgdXNlcy4qCgo8YnIvPgoKIyMjIDIuMSBNYXJrZG93bgoKVGhlIHNpbXBsZXN0IG1ldGhvZCBvZiBidWlsZGluZyBhIHRhYmxlIGlzIHdpdGggTWFya2Rvd24gc3ludGF4LiBUaGlzIGlzIGEgbmljZSBvcHRpb24gYmVjYXVzZSB5b3UgY2FuIGhhcmQgY29kZSB0aGUgdGFibGUgcmlnaHQgaW50byB0aGUgZG9jdW1lbnQtLS1ubyBuZWVkIHRvIGluc3RhbGwgYW5kIGxvYWQgbGlicmFyaWVzIG9yIHdyaXRlIGNvZGUgY2h1bmtzLS0tYW5kIGl0IGlzIGVhc3kgdG8gaW1wbGVtZW50LiBUaGUgZG93bnNpZGUgaXMgdGhlcmUgaXMgbWluaW1hbCBmdW5jdGlvbmFsaXR5IGF2YWlsYWJsZSBpbiBhIE1hcmtkb3duIHRhYmxlLgoKTWFya2Rvd24gZG9lcyBub3Qgd29yayB3ZWxsIGZvciBsYXJnZSB0YWJsZXMuIFNvIEkgd2lsbCBmaXJzdCBncmFiIGEgc3Vic2V0IG9mIGBtdGNhcnNgLCBzcGVjaWZpY2FsbHkgdGhlIGZpcnN0IDQgcm93cyBhbmQgMyBjb2x1bW5zLiBJbiBteSBjb2RlIGNodW5rIEkgYWRkIHRoZSBjaHVuayBvcHRpb24gYGNvbW1lbnQ9IiJgLiBUaGlzIHByZXZlbnRzIGtuaXQgZnJvbSBhcHBlbmRpbmcgYSBzdHJpbmcgKGRlZmF1bHQgaXMgYCMjYCkgdG8gdGhlIHN0YXJ0IG9mIGVhY2ggbGluZSBvZiByZXN1bHRzIGluIHRoZSBmaW5hbCBkb2N1bWVudC4KCmBgYHtyIG10Y2Fyc19zdWIsIGNvbW1lbnQ9IiJ9Cm10Y2Fyc19zdWIgPC0gbXRjYXJzWzE6NCwxOjNdCm10Y2Fyc19zdWIKYGBgCgo8YnIvPgoKKkluY2lkZW50YWxseSwgdGhlIHJlc3VsdHMgYm94IGFib3ZlIGlzIHRlY2huaWNhbGx5IHRoZSBzaW1wbGVzdCB0YWJsZSB5b3UgY2FuIG1ha2UsIGVpdGhlciBieSBjYWxsaW5nIHRoZSBkYXRhIGZyYW1lIGBtdGNhcnNfc3ViYCBkaXJlY3RseSBvciBydW5uaW5nIGBwcmludC5kYXRhLmZyYW1lKG10Y2Fyc19zdWIpYC4qCgpBbnl3YXksIHJ1biB0aGlzIGNvZGUgY2h1bmssIGNvcHkgdGhlIHJlc3VsdHMsIGFuZCBtYWtlIGEgTWFya2Rvd24gdGFibGUuIFlvdSBjYW4gZWl0aGVyIHJ1biB0aGUgY2h1bmsgaW4gUlN0dWRpbyB3aXRob3V0IHJlbmRlcmluZyB0aGUgZG9jdW1lbnQgKGRlc2NyaWJlZCBhYm92ZSkgb3IgcmVuZGVyIHRoZSBkb2N1bWVudCBhbmQgY29weSB0aGUgcmVzdWx0cyBmcm9tIEhUTUwgcGFnZS4gSSBhZGRlZCBhIGhlYWRlciB0byB0aGUgZmlyc3QgY29sdW1uLiBBbmQgaGVyZSBpcyB0aGUgTWFya2Rvd24gdGFibGUuCgo8YnIvPgoKfCBtb2RlbCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8ICBtcGcgICB8ICBjeWwgfCAgZGlzcCAgICAgfAp8Oi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXw6LS0tLS0tOnw6LS0tLTp8LS0tLS0tLS0tLTp8CnwgW01hemRhIFJYNF0oaHR0cHM6Ly9zY28ud2lraXBlZGlhLm9yZy93aWtpL01hemRhX1JYLTQpICAgICAgICAgICAgfCAqMjEuMCogfCAqKjYqKnwgICAgMTYwICAgIHwKfCBgTWF6ZGEgUlg0IFdhZ2AgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8ICoyMS4wKiB8ICAgNiAgfCAgICAxNjAgICAgfAp8IFtEYXRzdW4gNzEwXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9OaXNzYW5fVmlvbGV0IzcxMCkgICAgIHwgKjIyLjgqIHwgICA0ICB8ICAgIDEwOCAgICB8CnwgW0hvcm5ldCA0IERyaXZlXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9BTUNfSG9ybmV0KSAgICAgICAgfCAyMS40ICAgfCAgIDYgIHwgICoqMjU4KiogIHwKVGFibGU6ICAqRGVtb25zdHJhdGlvbiBvZiB0aGUgb3V0cHV0IGZyb20gYHBpcGVfdGFibGVzYCBNYXJrZG93biBzeW50YXguKgoKPGJyLz4KClNpbmNlIHRoaXMgaXMgYSBNYXJrZG93biB0YWJsZSwgeW91IGNhbiBhZGQgYWRkaXRpb25hbCBNYXJrZG93biBzeW50YXggZm9yIGZvcm1hdHRpbmcuIFNlZSBpZiB5b3UgY2FuIGZpZ3VyZSBvdXQgd2hhdCBzeW50YXggSSBhZGRlZCB0byBteSB0YWJsZSBhbmQgYWRkIHNvbWUgdG8geW91ciB0YWJsZS4gQWxzbyBjaGVjayBvdXQgdGhlICpUYWJsZXMqIHNlY3Rpb24gb2YgW1BhbkRvYyBVc2VyJ3MgR3VpZGVdKGh0dHBzOi8vcGFuZG9jLm9yZy9NQU5VQUwuaHRtbCN0YWJsZXMpIGZvciBvdGhlciBNYXJrZG93biB0YWJsZSBvcHRpb25zLCBpbmNsdWRpbmcgaG93IHRvIGFkZCBhIGNhcHRpb24uIEluIGFkZGl0aW9uIHRvIGBwaXBlX3RhYmxlc2AsIHlvdSBjYW4gY3JlYXRlIGBtdWx0aWxpbmVfdGFibGVzYCBgZ3JpZF90YWJsZXNgLCBhbmQgYHNpbXBsZV90YWJsZXNgLgoKU29tZXRoaW5nIHRvIG5vdGljZSBpcyB0aGF0IHRoZSBNYXJrZG93biB0YWJsZSBzcGFucyB0aGUgZW50aXJlIHdpZHRoIG9mIHRoZSBwYWdlLS0tZXZlbiB0aG91Z2ggaXQgZG9lcyBub3QgbmVlZCBhbGwgb2YgdGhhdCBzcGFjZS4gQXMgZmFyIGFzIEkga25vdywgdGhlcmUgaXMgbm8gd2F5IHRvIGNvbnRyb2wgdGhpcyBiZWhhdmlvciB3aXRob3V0IGFkZGluZyBhZGRpdGlvbmFsIEhUTUwgZm9ybWF0dGluZy4KCj4gKipSZWNvbW1lbmRhdGlvbioqIFVzZSBgTWFya2Rvd25gIGZvciBzbWFsbCwgc2ltcGxlIHRhYmxlcyB3aGVyZSBzdHlsaW5nIGlzIG5vdCBhIGNvbmNlcm4uCgojIyMgMi4yIFIgTWFya2Rvd24gUGFnZWQgVGFibGVzCgpXaXRoIGxhcmdlciB0YWJsZXMsIGl0IG1heSBub3QgYmUgcHJhY3RpY2FsIHRvIGRpc3BsYXkgdGhlIGZ1bGwgdGFibGUgaW5saW5lLiBTbyB3ZSBuZWVkIGEgd2F5IHRvIHNocmluayBhIGxhcmdlIHRhYmxlIHNvIGl0IGxvb2tzIGdvb2Qgd2hpbGUgc3RpbGwgYWxsb3dpbmcgYWNjZXNzIHRvIHRoZSBmdWxsIHRhYmxlLgoKVGhlIG5leHQgdHlwZSBvZiB0YWJsZSBJIHdhbnQgeW91IHRvIHRyeSBhcmUgUGFnZWQgVGFibGVzLiBSIE1hcmtkb3duIGNvbWVzIHdpdGggaXRzIG93biBidWlsdCBpbiB0YWJsZSBmdW5jdGlvbiBjYWxsZWQgYHBhZ2VkX3RhYmxlYC4gVGhlIGBwYWdlZF90YWJsZWAgZnVuY3Rpb24gYWxsb3dzIHBhZ2luYXRpb24gb2Ygcm93cyBhbmQgY29sdW1ucyBtYWtpbmcgaXQgcG9zc2libGUgdG8gcmVuZGVyIGEgbGFyZ2UgdGFibGUgaW4gYSBzbWFsbCBzcGFjZS4KCkl0IGlzIGVhc3kgdG8gY29kZSBgcGFnZWRfdGFibGVgIGJ1dCB0aGF0IGVhc2UgY29tZXMgd2l0aCBhIHNtYWxsIHByaWNlLS0tbGltaXRlZCBmdW5jdGlvbmFsaXR5LiBIZXJlIGFyZSB0aGUgb3B0aW9ucyB5b3UgZG8gaGF2ZSB3aXRoIGBwYWdlZF90YWJsZWAgZnVuY3Rpb24uCgp8IE9wdGlvbiAgICAgICAgICAgfCBEZXNjcmlwdGlvbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwKfC0tLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS18CnwgYHJvd3MucHJpbnRgICAgICB8IE1heGltdW0gcm93cyB0byBwcmludCBwZXIgcGFnZS4gICAgICAgICAgICAgICAgfAp8IGBtYXgucHJpbnRgICAgICAgfCBNYXhpbXVtIHJvd3MgaW4gdGhlIHRhYmxlIChkZWZhdWx0cyB0byAxMDAwKS4gIHwKfCBgY29scy5wcmludGAgICAgIHwgTWF4aW11bSBjb2x1bW5zIGluIHRoZSB0YWJsZSAoZGVmYXVsdHMgdG8gMTApLiB8CnwgYHJvd25hbWVzLnByaW50YCB8IFByaW50IHJvdyBuYW1lcyBhcyBwYXJ0IG9mIHRoZSB0YWJsZS4gICAgICAgICAgfApUYWJsZTogKkEgTWFya2Rvd24gdGFibGUgbGlzdGluZyB0aGUgT3B0aW9ucyBmb3IgdGhlIGBwYWdlZF90YWJsZWAgZnVuY3Rpb24uICoKCioqKkEgcXVpY2sgc2lkZSBub3RlKioqLiBZb3UgYWN0dWFsbHkgbmVlZCB0byBsb2FkIHRoZSBgcm1hcmtkb3duYCBwYWNrYWdlIGZvciBgcGFnZWRfdGFibGVgIHRvIHdvcmsuIEFueXdheSwgdGhpcyBpcyBhIGdvb2QgdGltZSB0byByZXR1cm4gdG8gdGhlIGZpcnN0IGNvZGUgY2h1bmsgaW4geW91ciBgLlJtZGAgZmlsZS0tLXRoZSBjaHVuayBjYWxsZWQgYHNldHVwYCB0aGF0IFIgTWFya2Rvd24gYWRkZWQgYnkgZGVmYXVsdC4KCkkgbGlrZSB0byB1c2UgdGhpcyBjaHVuayB0byBsb2FkIGFsbCBvZiB0aGUgcGFja2FnZXMgSSBuZWVkIGZvciBteSBkb2N1bWVudC4gVXNpbmcgYSBzaW5nbGUgY2h1bmsgZm9yIGFsbCBvZiBteSBwYWNrYWdlcyBoZWxwcyBtZSBrZWVwIG15IGRvY3VtZW50IG9yZ2FuaXplZC4gTm90aWNlIHRoZSBgc2V0dXBgIGNodW5rIGhhcyB0aGUgb3B0aW9uIGBpbmNsdWRlPUZBTFNFYC4gVGhpcyBwcmV2ZW50cyB0aGUgY29udGVudCBvZiB0aGUgY2h1bmsgZnJvbSBhcHBlYXJpbmcgaW4gdGhlIGZpbmFsIGRvY3VtZW50LCB3aGljaCBmb3IgbWUgaXMgbW9yZSBzdHlsaXN0aWNhbGx5IGFwcGVhbGluZy4gIEkgY2FuIGFkZCBhIGBzZXNzaW9uSW5mbygpYCBjaHVuayBhdCB0aGUgZW5kIG9mIG15IGRvY3VtZW50IHRvIHJlcG9ydCBhbGwgb2YgdGhlIHBhY2thZ2VzIHNvIHRoaXMgaW5mb3JtYXRpb24gaXMgYXZhaWxhYmxlIHRvIHRoZSByZWFkZXIuIFdlIHdpbGwgY292ZXIgYHNlc3Npb25JbmZvKClgIHdoZW4gd2UgZ2V0IGludG8gbW9yZSBkZXB0aCBvbiB0aGUgc3ViamVjdCBvZiAqcmVwcm9kdWNpYmxlKi4gSWYgeW91IGRvIG5vdCB3YW50IHRvIGxvYWQgdGhlIGxpYnJhcnkgeW91IGNhbiBydW4gdGhlIGNvbW1hbmQgbGlrZSB0aGlzOiBgcm1hcmtkb3duOjpwYWdlZF90YWJsZSgpYC4KCioqKk9LLCBiYWNrIHRvIHRoZSB0YWJsZSoqKi4gTm93IEkgY2FuIGNyZWF0ZSBhIHRhYmxlIG9mIGBtdGNhcnNgIHdpdGggdGhlIGBwYWdlZF90YWJsZWAgZnVuY3Rpb24gYW5kIHVzZSBhbiBvcHRpb24gdG8gbGltaXQgdGhlIG51bWJlciBvZiBwcmludGVkIHJvd3MgdG8gYDVgIGZvciBlYWNoIHBhZ2UuIEkgdXNlZCBgZWNobz1GQUxTRWAgaW4gbXkgY29kZSBjaHVuayB0byBoaWRlIHRoZSBjb2RlIDopLiBCeSBub3cgeW91IHNob3VsZCBrbm93IHdoZXJlIHRvIGxvb2sgZm9yIGEgc29sdXRpb24uCgo8YnIvPgoKYGBge3IgbXRjYXJzX3BhZ2VkLCBlY2hvPUZBTFNFLCBmaWcuY2FwPSJzdHVmZiJ9CnBhZ2VkX3RhYmxlKG10Y2Fycywgb3B0aW9ucyA9IGxpc3Qocm93cy5wcmludCA9IDUpKQpgYGAKCk5vdGljZSB0aGF0IGZvciBlYWNoIGNvbHVtbiwgdGhlIGNvbHVtbiAqY2xhc3MqIGlzIHByaW50ZWQgYmVsb3cgdGhlIG5hbWUgKHRleHQgZW5jbG9zZWQgaW4gPCA+KS4gVGhpcyBpcyBpcnJpdGF0aW5nIGFuZCByZWxhdGVkIHRvIHByaW50aW5nIGEgdGFibGUgZnJvbSBhIGJ1aWx0LWluIGRhdGEgZnJhbWUuIEkgaGF2ZSBubyBpZGVhIGhvdyB0byBmaXggdGhpcyAod2l0aGluIHRoZSBjb25maW5lcyBvZiBSIE1hcmtkb3duKSBidXQgSSB3aWxsIHdvcmsgb24gYSBzb2x1dGlvbi4KCj4gKipSZWNvbW1lbmRhdGlvbioqIFVzZSBgcGFnZWRfdGFibGVgIGZvciBsYXJnZSB0YWJsZXMgd2hlcmUgZXh0ZW5zaXZlIHN0eWxpbmcgaXMgbm90IGEgY29uY2Vybi4KCiMjIyAyLjMgS2FibGUgVGFibGVzCgpLbml0ciBjb21lcyB3aXRoIGl0cyBvd24gdG9vbCBmb3IgcmVuZGVyaW5nIHNpbXBsZSB0YWJsZXMgY2FsbGVkIGBrYWJsZWAuIFRoZSBkb2N1bWVudGF0aW9uIGZvciBga2FibGVgIGNhbiBiZSBmb3VuZCBbaGVyZV0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL2thYmxlRXh0cmEvaW5kZXguaHRtbCkgb3IgYnkgcnVubmluZyBgP2tuaXRyOjprYWJsZSgpYCBpbiB0aGUgQ29uc29sZS4gQnkgaXRzZWxmLCBrYWJsZSAgY29tZXMgd2l0aCAqYWxtb3N0IG5vIG9wdGlvbnMqLiBXZSBjYW4gZXh0ZW5kIGl0cyBmdW5jdGlvbmFsaXR5IHdpdGggdGhlIGBrYWJsZUV4dHJhYCBwYWNrYWdlIGFuZCBwaXBpbmcgc3ludGF4IGZyb20gYG1hZ3JpdHRyYC4gVGhlIGZlYXR1cmVzIG9mIGBrYWJsZUV4dHJhYCAgYXJlIGV4dGVuc2l2ZSBhbmQgSSB3aWxsIG9ubHkgdG91Y2ggb24gYSBmZXcgaGVyZS4gVGhlIGRvY3VtZW50YXRpb24gZm9yIGBrYWJsZUV4dHJhYCBjYW4gYmUgZm91bmQgW2hlcmVdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9rYWJsZUV4dHJhL2luZGV4Lmh0bWwpIG9yIGJ5IHJ1bm5pbmcgYD9rYWJsZUV4dHJhYCBpbiB0aGUgQ29uc29sZSBhZnRlciB0aGUgcGFja2FnZSBoYXMgYmVlbiBpbnN0YWxsZWQgYW5kIGxvYWRlZC4KCj4gSSBoaWdobHkgcmVjb21tZW5kIHlvdSBbbGVhcm4gaG93IHRvIHVzZSB0aGVzZSBwYWNrYWdlc10oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL2thYmxlRXh0cmEvdmlnbmV0dGVzL2F3ZXNvbWVfdGFibGVfaW5faHRtbC5odG1sKSBmb3IgbWFraW5nIHRhYmxlcy4KCkFnYWluLCB5b3Ugd2lsbCBuZWVkIHRvIGxvYWQgYGthYmxlRXh0cmFgIGFuZCBlaXRoZXIgbG9hZCB0aGUgYGtuaXRyYCBwYWNrYWdlIG9yIHJ1biB0aGUgY29tbWFuZCBsaWtlIHRoaXM6IGBrbml0cjo6a2FibGUoKWAuCgpGaXJzdCwgbGV04oCZcyBsb29rIGF0IHRoZSBkZWZhdWx0IGBrYWJsZWAgdGFibGUgb3V0cHV0LiBXZSB3aWxsIHVzZSB0aGUgaGVhZCBvZiB0aGUgYG10Y2Fyc2AgZGF0YSBzZXQuCgo8YnIvPgoKYGBge3Iga2FibGVfZGVmYXVsdH0Ka2FibGUoaGVhZChtdGNhcnMpLCBjYXB0aW9uID0gIipXb3csIHRoaXMgdGFibGUgbG9va3MgdGVycmlibGUuKiIpCmBgYAoKPGJyLz4KCklmIHdlIHRyaWVkIHRvIHJlbmRlciB0aGUgZW50aXJlIHRhYmxlIGJ5IG9taXR0aW5nIGBoZWFkYCwgd2Ugd291bGQganVzdCBnZXQgYSBsb25nLCBjcmFwcHkgdGFibGUgaW4gb3VyIGRvY3VtZW50LiBOb3QgY29vbC4gTGV0cyBzZWUgaWYgd2UgY2FuIGphenogdGhpcyB1cCBhIGJpdCB3aXRoIGBrYWJsZUV4dHJhYC4KCmBgYHtyIGthYmxlX2phenp9CmthYmxlKGhlYWQobXRjYXJzKSwgY2FwdGlvbiA9ICIqVGhpcyB0YWJsZSBsb29rcyBiZXR0ZXIqIikgJT4lCiAga2FibGVfc3R5bGluZygpCgpgYGAKCkhlcmUgSSB1c2VkIHRoZSBbcGlwZSBvcGVyYXRvcl0oaHR0cHM6Ly9yaXB0dXRvcmlhbC5jb20vci90b3BpYy82NTIvcGlwZS1vcGVyYXRvcnMtLS0tLS1hbmQtb3RoZXJzLSkgKGAlPiVgKSB0byBwYXNzIHRoZSByZXN1bHRzIG9mIGBrYWJsZWAgdG8gdGhlIGZ1bmN0aW9uIGBrYWJsZV9zdHlsaW5nYC0tLWEgcGFydCBvZiB0aGUgYGthYmxlRXh0cmFgIHBhY2thZ2UuIEJ5IHJ1bm5pbmcgIGBrYWJsZV9zdHlsaW5nYCAqYXMgaXMqLCBJIGFtIHVzaW5nIGRlZmF1bHRzIGZvciBhbGwgb2YgdGhlIG9wdGlvbnMuCgo+IFRoZSBwaXBlIG9wZXJhdG9yIGlzIGEgcG93ZXJmdWwgdG9vbCB3b3J0aCBsZWFybmluZy4KCkJhY2sgdG8gdGhlIHRhYmxlLiBJdCBjZXJ0YWlubHkgbG9va3MgYmV0dGVyIHRoYW4gdGhlIGRlZmF1bHQgYGthYmxlYCB2ZXJzaW9uIGJ1dCB3ZSBhcmUgbWlzc2luZyB0aGUgYWJpbGl0eSB0byAqcGFnZSogdGhlIHRhYmxlLiBJIHdvdWxkIGxpa2UgeW91IHRvIHJ1biB0aGVzZSB0d28gY29tbWFuZHMgYW5kIGxvb2sgYXQgdGhlIG91dHB1dC4KClRoaXMgY29tbWFuZCB3aWxsIGluY2x1ZGUgdGhlIHdob2xlIHRhYmxlLgoKYGBgCmthYmxlKG10Y2FycykgJT4lCiAga2FibGVfc3R5bGluZygpCmBgYAoKQW5kIHRoaXMgY29tbWFuZCB3aWxsIHRyYW5zcG9zZSB0aGUgdGFibGUgKHN3YXAgcm93cyBhbmQgY29sdW1ucykgdXNpbmcgdGhlIHRyYW5zcG9zZSAoYHRgKSBmdW5jdGlvbi4gUmVtZW1iZXIsIGBtdGNhcnNgIGhhcyBgciBucm93KG10Y2FycylgIHJvd3MgYW5kIGByIG5jb2wobXRjYXJzKWAgY29sdW1ucyBidXQgd2hlbiB5b3UgdHJhbnNwb3NlIHRoZSB0YWJsZSwgaXQgaGFzIGByIG5yb3codChtdGNhcnMpKWAgcm93cyBhbmQgYHIgbmNvbCh0KG10Y2FycykpYCBjb2x1bW5zLiBTbyBpdCBpcyByZWFsbHkgd2lkZSBpbiB0aGUgdHJhbnNwb3NlZCBzdGF0ZS4KCmBgYAprYWJsZShoZWFkKHQobXRjYXJzKSkpICU+JQogIGthYmxlX3N0eWxpbmcoKQpgYGAKCkkgaG9wZSB5b3UgYWdyZWUgdGhhdCBuZWl0aGVyIG9mIHRoZXNlIHRhYmxlcyBhcmUgYWNjZXB0YWJsZSwgZXNwZWNpYWxseSB0aGUgc2Vjb25kIG9uZS4gVW5mb3J0dW5hdGVseSwgdGhlIGBrYWJsZUV4dHJhYCBwYWNrYWdlIGRvZXMgbm90IGNvbWUgd2l0aCBhbiBvcHRpb24gdG8gYWRkIHBhZ2luYXRpb24uIFlvdSBjYW4gaG93ZXZlciBwdXQgdGhlIHRhYmxlIGluIGEgZml4ZWQtaGVpZ2h0LCBmaXhlZC13aWR0aCAob3IgYm90aCkgYm94LCBhbmQgbWFrZSBpdCBzY3JvbGxhYmxlLiBXZSBjYW4gZG8gdGhpcyBieSB1c2luZyBhIHBpcGUgb3BlcmF0b3IgYW5kIHRoZSBgc2Nyb2xsX2JveGAgZnVuY3Rpb24uIFdoaWxlIHdlIGFyZSBhdCBpdCwgbGV0cyBhbHNvIGFkZCB0d2VhayBzb21lIG9wdGlvbnMgaW4gYGthYmxlX3N0eWxpbmdgIHRvIG1ha2UgYSBtb3JlIGhhbmRzb21lIHRhYmxlLgoKYGBge3Iga2FibGVfc2Nyb2xsfQprYWJsZSh0KG10Y2FycyksIGNhcHRpb24gPSAiKlNjcm9sbGFibGUga2FibGUgdGFibGUuKiIpICU+JQogIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImhvdmVyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY29uZGVuc2VkIiwgInJlc3BvbnNpdmUiKSkgJT4lCiAgc2Nyb2xsX2JveCh3aWR0aCA9ICIxMDAlIiwgaGVpZ2h0ID0gIjMwMHB4IikKYGBgCgo8YnIvPgoKRm9yIHRoZSBgc2Nyb2xsX2JveGAgZnVuY3Rpb24gSSBzZXQgdGhlIGB3aWR0aCA9ICIxMDAlImAgcmF0aGVyIHRoYW4gc3BlY2lmeWluZyBhIGRpbWVuc2lvbi4gVGhpcyBlbnN1cmVzIHRoZSBib3ggd2lsbCBhbHdheXMgYmUgdGhlIHdpZHRoIG9mIHRoZSBwYWdlIG5vIG1hdHRlciBob3cgc21hbGwgdGhlIHdpbmRvdyBpcy4KCkV2ZW4gdGhvdWdoIHlvdSBjYW5ub3QgbWFrZSBhIHBhZ2VkIHRhYmxlIHdpdGggYGthYmxlYCwgdGhlcmUgYXJlICBtYW55IHN0eWxpbmcgb3B0aW9ucyBhdmFpbGFibGUgaW4gdGhlIGBrYWJsZUV4dHJhYCBwYWNrYWdlIHRoYXQgbWFrZXMgdGhpcyBtZXRob2QgIGV4dHJlbWVseSB1c2VmdWwgYW5kIHdvcnRoIGxlYXJuaW5nLiBQbHVzLCB0aGUgY29kZSBpcyByZWxhdGl2ZWx5IHNpbXBsZSB0byB3cml0ZS4KCkkgd2FudCB0byBzaG93IHlvdSBvbmUgbW9yZSBmZWF0dXJlIHRoYXQgaXMgbm90IGF2YWlsYWJsZSB0aGUgb3RoZXIgdGFibGUgbWV0aG9kcyB3ZSBjb3ZlciBpbiB0aGlzIEFzc2lnbm1lbnQtLS0qZmxvYXRpbmcqLiBMZXQncyBmaXJzdCBzdWJzZXQgdGhlIGBtdGNhcnNgIGRhdGEgc2V0IHNvIHdlIGNhbiBtYWtlIGEgc21hbGwgdGFibGUuIE5leHQgd2UgdXNlIHRoZSBgZnVsbF93aWR0aGAgYW5kIGBwb3NpdGlvbmAgb3B0aW9ucyB0byBjb250cm9sIHRoZSBzaXplIGFuZCBwb3NpdGlvbiBvZiB0aGUgdGFibGUuCgpIZXJlIGlzIG91ciBjb2RlIGNodW5rLgoKYGBge3Iga2FibGVfZmxvYXR9Cm10Y2Fyc19zdWIgPC0gbXRjYXJzWzE6NywxOjZdCmthYmxlKG10Y2Fyc19zdWIpICU+JQogIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSAic3RyaXBlZCIsCiAgICAgICAgICAgICAgICBmdWxsX3dpZHRoID0gRkFMU0UsCiAgICAgICAgICAgICAgICBwb3NpdGlvbiA9ICJmbG9hdF9yaWdodCIpCmBgYAoKPGJyLz4KCkxldOKAmXMgc2F5IHdlIGhhdmUgYSBidW5jaCBvZiB0ZXh0IHRoYXQgd2Ugd2FudCB0byBwdXQgc2lkZS1ieS1zaWRlIHdpdGggdGhpcyBzbWFsbCB0YWJsZS4gT3VyIHN1YnNldHRlZCBgbXRjYXJzYCBkYXRhIHNldCBub3cgaGFzIGByIG5yb3cobXRjYXJzX3N1YilgIHJvd3MgYW5kIGByIG5jb2wobXRjYXJzX3N1YilgIGNvbHVtbnMuIFdlIGNhbiBtYWtlIG91ciB0YWJsZSBzbWFsbGVyIGJ5IHNldHRpbmcgYGZ1bGxfd2lkdGggPSBGQUxTRWAgaW4gYGthYmxlX3N0eWxpbmdgIGFuZCBmbG9hdCB0aGUgdGFibGUgYnkgc2V0dGluZyBgcG9zaXRpb24gPSAiZmxvYXRfcmlnaHQiYAoKUGxlYXNlIHN0dWR5IHRoZSBbZXh0ZW5zaXZlIG9wdGlvbnMgYXZhaWxhYmxlIGluIGBrYWJsZWAgYW5kIGBrYWJsZUV4dHJhYF0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL2thYmxlRXh0cmEvdmlnbmV0dGVzL2F3ZXNvbWVfdGFibGVfaW5faHRtbC5odG1sKSBhbmQgY3JlYXRlIHRhYmxlcyB0aGF0IGltcGxlbWVudCBzb21lIG9mIHRoZSBvcHRpb25zLgoKPGJyLz48YnIvPgoKPiAqKlJlY29tbWVuZGF0aW9uKiogVXNlIGBrYWJsZWAgKyBga2FibGVFeHRyYWAgZm9yIHNtYWxsIHRhYmxlcyB3aGVyZSBleHRlbnNpdmUgc3R5bGluZyBpcyBkZXNpcmVkLgoKIyMjIDIuNCBEVCBUYWJsZXMKClRoZSBsYXN0IG9wdGlvbiBJIHdhbnQgdG8gY292ZXIgZm9yIGJ1aWxkaW5nIHRhYmxlcyBpcyBpbXBsZW1lbnRlZCB1c2luZyB0aGUgYGRhdGF0YWJsZWAgZnVuY3Rpb24gZnJvbSB0aGUgW0RUXShodHRwczovL3JzdHVkaW8uZ2l0aHViLmlvL0RULykgcGFja2FnZSwgYW4gaW50ZXJmYWNlIHRvIHRoZSBKYXZhU2NyaXB0IGxpYnJhcnkgKltEYXRhVGFibGVzXShodHRwczovL2RhdGF0YWJsZXMubmV0LykqLiBUbyBkZW1vbnN0cmF0ZSB0aGUgZnVuY3Rpb25hbGl0eSwgSSB3aWxsIHVzZSBhIGxhcmdlciBkYXRhIHNldCBjYWxsZWQgYFVTSnVkZ2VSYXRpbmdzYCBmcm9tIHRoZSBgZGF0YXNldHNgIHBhY2thZ2UuIGBVU0p1ZGdlUmF0aW5nc2AgaGFzIGByIG5yb3coVVNKdWRnZVJhdGluZ3MpYCByb3dzIGFuZCBgciBuY29sKFVTSnVkZ2VSYXRpbmdzKWAgY29sdW1ucy4gVGhpcyB0YWJsZSBpcyB0b28gYmlnLS0taG9yaXpvbnRhbGx5IGFuZCB2ZXJ0aWNhbGx5LS0tdG8gZml0IG9uIGEgc3RhbmRhcmQgcGFnZS4KClRoZSBzeW50YXggZm9yIHRoZSBgRFQ6OmRhdGF0YWJsZWAgaXMgbW9yZSBjb21wbGljYXRlZCB0aGFuIHRoZSBvdGhlciBtZXRob2RzIGJ1dCB0aGF0IGNvbWVzIHdpdGggIG1vcmUgZXh0ZW5zaXZlIGZ1bmN0aW9uYWxpdHkuCgo+IFdvcmtpbmcgd2l0aCBgRFQ6OmRhdGF0YWJsZWAgaXMgYW4gYWR2YW5jZWQgbGV2ZWwgc2tpbGwuIEkgaGlnaGx5IHJlY29tbWVuZCB5b3UgbGVhcm4gaG93IHRvIHVzZSB0aGUgcGFja2FnZSwgYnV0IGl0IHdpbGwgdGFrZSAgcHJhY3RpY2UuCgpQbGVhc2UgbWFrZSBzdXJlIHlvdSBhcmUgY29tZm9ydGFibGUgd2l0aCB0aGUgb3RoZXIgbWV0aG9kcyBmaXJzdCBiZWZvcmUgdHJ5aW5nIHRvIHVzZSBgRFQ6OmRhdGF0YWJsZWAuIEkgcHJvbWlzZSwgaWYgeW91IGRvIG5vdCBrbm93IHdoYXQgeW91IGFyZSBkb2luZywgdGhpcyBwYWNrYWdlIHdpbGwgY2F1c2UgYSBsb3Qgb2YgZnJ1c3RyYXRpb24uIFRoYXQgc2FpZCwgSSB1c2UgaXQgYWxsIHRoZSB0aW1lIGJlY2F1c2UgaXQgaXMgYXdlc29tZS4KCk1vdmluZyBvbi4gSWYgd2UgcnVuIGBEVGAgb24gdGhlIGBVU0p1ZGdlUmF0aW5nc2AgZGF0YSBzZXQgd2l0aG91dCBhbnkgb3B0aW9ucyB0aGUgdGFibGUgd2lsbCBzcGlsbCBvZmYgdGhlIHNpZGUgb2YgdGhlIHBhZ2UuIEFnYWluLCBub3QgY29vbC4gVHJ5IHRvIHJ1biB0aGlzIGNvbW1hbmQgYW5kIHNlZSB3aGF0IGhhcHBlbnMuCgpgYGAKZGF0YXRhYmxlKFVTSnVkZ2VSYXRpbmdzKQpgYGAKCmBEVDo6ZGF0YXRhYmxlYCAqZG9lcyBub3QgcGFnZSB0YWJsZXMgaG9yaXpvbnRhbGx5KiBsaWtlIHRoZSBgcGFnZWRfdGFibGVgIGNvbW1hbmQgZG9lcyAoZGVzY3JpYmVkIGFib3ZlKS4gV2UgY2FuIHNldCB0aGUgd2lkdGggb2YgdGhlIHRhYmxlIGFuZCBhZGQgYW4gb3B0aW9uIHRoYXQgYWxsb3dzIGhvcml6b250YWwgc2Nyb2xsaW5nLiBGb3IgdGhpcyB3ZSB1c2UgdGhlIGBvcHRpb25zYCBhcmd1bWVudC4gVGhlIHN5bnRheCBpcyB0byBhZGQgYHdpZHRoID0gIjEwMCUiYCBmb2xsb3dlZCBieSBgb3B0aW9ucyA9IGxpc3QoKWAsIHdoZXJlIHdlIHB1dCBhIGNvbW1hIHNlcGFyYXRlZCBsaXN0IG9mIG9wdGlvbnMuIEZvciBub3csIHdlIGp1c3QgaW5jbHVkZSBgc2Nyb2xsWGAgaW4gb3VyIGxpc3Qgb2Ygb3B0aW9ucy4KCmBgYHtyIGR0fQpkYXRhdGFibGUoVVNKdWRnZVJhdGluZ3MsIHdpZHRoID0gIjEwMCUiLAogICAgICAgICAgb3B0aW9ucyA9IGxpc3Qoc2Nyb2xsWCA9IFRSVUUpKQpgYGAKCjxici8+CgpQbGF5IGFyb3VuZCB3aXRoIHRoZSB0YWJsZSBhIGxpdHRsZS4gQXMgeW91IGNhbiBzZWUKCiogdGhlIHRhYmxlIG5vdyBmaXRzIGluIHRoZSB3aW5kb3csCiogaG9yaXpvbnRhbCBzY3JvbGxpbmcgaW4gZW5hYmxlZCwKKiB0aGUgcGFnZSBpcyB2ZXJ0aWNhbGx5IHBhZ2VkLAoqIHRoZXJlIGlzIGEgKlNob3cgZW50cmllcyogZHJvcCBkb3duLCBhbmQKKiB0aGVyZSBpcyBhICpTZWFyY2gqIGJveC4KClRoZSAqU2hvdyBlbnRyaWVzKiBhbmQgKlNlYXJjaCogYm94IGFyZSBhZGRlZCBieSBkZWZhdWx0LiBXZSBjYW4gZGVjaWRlIHdoZXRoZXIgdG8gc2hvdyB0aGVzZSBvcHRpb25zIG9yIG5vdC4gSSB3aWxsIHNhdmUgdGhhdCBmb3IgbGF0ZXIuIEZvciBub3csIEkgd2FudCB0byBsZWF2ZSB5b3Ugd2l0aCBhIG1vcmUgc3R5bGl6ZWQgRFQgZGF0YSB0YWJsZSB0byBnaXZlIHlvdSBhIHNlbnNlIG9mIHRoZSBwb3NzaWJpbGl0aWVzLiBEb24ndCB3b3JyeSBzbyBtdWNoIGFib3V0IHRoZSBjb2RlLS0tcGF5IGF0dGVudGlvbiB0byB0aGUgZnVuY3Rpb25hbGl0eS4KCmBgYHtyIGR0X2phenp9CmRhdGF0YWJsZShVU0p1ZGdlUmF0aW5ncywgd2lkdGggPSAiMTAwJSIsCiAgICAgICAgICBleHRlbnNpb25zID0gJ0J1dHRvbnMnLCBvcHRpb25zID0gbGlzdCgKICAgICAgICAgICAgc2Nyb2xsWCA9IFRSVUUsCiAgICAgICAgICAgIGRvbSA9ICdsZnJ0aXBCJywKICAgICAgICAgICAgYnV0dG9ucyA9IGMoJ2NvcHknLCAnY3N2JywgJ2V4Y2VsJywgJ3BkZicsICdwcmludCcpLAogICAgICAgICAgICBwYWdlTGVuZ3RoID0gNSwKICAgICAgICAgICAgbGVuZ3RoTWVudSA9IGMoNSwgMTAsIDIwLCA0NSkKICAgICAgICAgICAgKQogICAgICAgICAgKQpgYGAKPGJyLz48YnIvPgoKSSBhZGRlZCBidXR0b25zIHRvIGRvd25sb2FkIHRoZSB0YWJsZSB0byBkaWZmZXJlbnQgZm9ybWF0cywgY2hhbmdlZCB0aGUgcGFnZSBsZW5ndGggdG8gNSwgYW5kIGNoYW5nZWQgdGhlIHZhbHVlcyBpbiB0aGUgKlNob3cgZW50cmllcyogZHJvcCBkb3duLiBQbGF5IGFyb3VuZCB3aXRoIHRoZSB0YWJsZS4gVGhlcmUgaXMgYSBsb3QgbW9yZSB0byBkbyB3aXRoIHRoaXMgcGFja2FnZSBhbmQgd2Ugd2lsbCBjb21lIGJhY2sgdG8gaXQgb2Z0ZW4uCgo+ICoqUmVjb21tZW5kYXRpb24qKiBVc2UgYERUOjpkYXRhdGFibGVgIGZvciBsYXJnZSB0YWJsZXMgd2hlcmUgZXh0ZW5zaXZlIHN0eWxpbmcgaXMgZGVzaXJlZC4KClRoYXTigJlzIGFsbCBmb3IgdGhpcyBhc3NpZ25tZW50LgoKIyMgQXNzaWdubWVudCAzOiBDb2RlCgpJZiB5b3UgYXJlIGludGVyZXN0ZWQgaW4gbWFraW5nIHlvdXIgc2NpZW5jZSBtb3JlIHRyYW5zcGFyZW50IGFuZCByZXByb2R1Y2libGUsIHlvdSBuZWVkIHRvIHByb3ZpZGUgYXQgbGVhc3QgdHdvIHRoaW5ncy0tLXRoZSByYXcgZGF0YSB5b3UgZ2VuZXJhdGVkIGFuZCB0aGUgY29kZSB5b3UgdXNlZCB0byBhbmFseXplIGl0LiBIb3BlZnVsbHkgaXQgaXMgb2J2aW91cyBieSBub3cgdGhhdCB5b3UgbmVlZCB0byBwcm92aWRlIGFjY2VzcyB0byAqKipib3RoKioqIGNvbXBvbmVudHM7IG5laXRoZXIgaXMgcGFydGljdWxhcmx5IHVzZWZ1bCB3aXRob3V0IHRoZSBvdGhlci4gV2Ugd2lsbCBjb3ZlciBkYXRhIGF2YWlsYWJpbGl0eSBpbiBhIGZ1dHVyZSBsZXNzb24uIEZvciB0aGlzIGFzc2lnbm1lbnQsIHlvdSB3aWxsIHByYWN0aWNlIHNldmVyYWwgZGlmZmVyZW50IG1ldGhvZHMgZm9yIG1ha2luZyB5b3VyIGNvZGUgYWNjZXNzaWJsZS4gVGhlIG1ldGhvZCBvciBtZXRob2RzIHlvdSBjaG9vc2UgZm9yIHlvdXIgb3duIHdvcmsgd2lsbCBkZXBlbmQgb24gdGhlIHR5cGUgb2YgYW5hbHlzZXMgKmFuZCogdGhlIHR5cGUgb2YgY29kZS4KCj4gIyMjIyMgWW91ciBhc3NpZ25tZW50IGlzIHRvIGltcGxlbWVudCB0aGVzZSBtZXRob2RzIGluIHlvdXIgZG9jdW1lbnQgYW5kIHBsYXkgYXJvdW5kIHdpdGggdGhlIGRpZmZlcmVudCBvcHRpb25zLgoKIyMjIFB1cmwKCktuaXRyIGNvbWVzIHdpdGggYSBidWlsdC1pbiBmdW5jdGlvbiBjYWxsZWQgYHB1cmxgLCB3aGljaCBhbGxvd3MgeW91IHRvIGV4dHJhY3QgYWxsIHRoZSBSIGNvZGUgZnJvbSBhbiBSIE1hcmtkb3duIGRvY3VtZW50IGFuZCBjb252ZXJ0IGl0IHRvIGFuIFIgc2NyaXB0LiBJbiBvcmRlciB0byBydW4gYHB1cmxgLCB5b3UgbXVzdCBlaXRoZXIgbG9hZCB0aGUga25pdHIgbGlicmFyeSBmaXJzdCAoaS5lLiwgYGxpYnJhcnkoa25pdHIpYCkgYW5kIHRoZW4gcnVuIGBwdXJsYCBvciBjYWxsIHRoZSBmdW5jdGlvbiBkaXJlY3RseSBieSBydW5uaW5nIGBrbml0cjo6cHVybCgpYC4gV2Ugd2lsbCBzdGFydCBieSBkaXNjdXNzaW5nIHNvbWUgc2ltcGxlICpvcHRpb25zKiBmb3IgcnVubmluZyBgcHVybGAgYW5kIHRoZW4gdGFsayBhYm91dCAqaG93KiB5b3UgcnVuIHRoZSBjb21tYW5kLiBUaGUgYmFzaWMgc3RydWN0dXJlIG9mIHRoZSBjb21tYW5kIGlzOgoKPiBga25pdHI6OnB1cmwoaW5wdXQ9ImZpbGVuYW1lLlJtZCIsIGRvY3VtZW50YXRpb24gPSBMKWAKCkJ5IGRlZmF1bHQsIGBwdXJsYCB1c2VzIHRoZSBiYXNlIG5hbWUgb2YgdGhlIGlucHV0IGZpbGUgYXMgdGhlIGJhc2UgbmFtZSBvZiB0aGUgb3V0cHV0IGZpbGUuIElmIHlvdSB3YW50IHRvIGNvbnRyb2wgdGhpcyBiZWhhdmlvciwgYWRkIHRoZSBvcHRpb24gYG91dHB1dD0iZmlsZW5hbWUuUiJgIHdoZXJlIGBmaWxlbmFtZWAgaXMgd2hhdGV2ZXIgeW91IGNob29zZS4KClRoZSBvcHRpb24gYGRvY3VtZW50YXRpb25gIGlzIGFuIGludGVnZXIgdGhhdCBzcGVjaWZpZXMgdGhlIGxldmVsIChgTGApIG9mIGRvY3VtZW50YXRpb24gdG8gYWRkIHRvIHRoZSBzY3JpcHQuIFlvdSBoYXZlIHRocmVlIGNob2ljZXMKCiogKiowKiogbWVhbnMgb3V0cHV0IHB1cmUgY29kZSB0byB0aGUgc2NyaXB0LCBkaXNjYXJkIGFsbCBNYXJrZG93biB0ZXh0IGFuZCBjb2RlIGNodW5rIGRldGFpbHMuCiogKioxKiogKHRoZSBkZWZhdWx0KSBtZWFucyBkaXNjYXJkIGFsbCBNYXJrZG93biB0ZXh0IGJ1dCBhZGQgdGhlIGNodW5rIGhlYWRlcnMgdG8gdGhlIHNjcmlwdCBhcyBjb21tZW50ZWQgbGluZXMuCiogKioyKiogbWVhbnMgdG8gYWRkIGFsbCBNYXJrZG93biB0ZXh0IGFuZCBjb2RlIGNodW5rcyB0byB0aGUgc2NyaXB0IGFzIGNvbW1lbnRlZCBsaW5lcy4KCkFzIGZhciBhcyBJIGtub3csIHlvdSAqKmNhbm5vdCoqIHJ1biBgcHVybGAgZnJvbSBpbnNpZGUgYW4gYWN0dWFsIGNvZGUgY2h1bmsuIEkgaGF2ZSBubyBpZGVhIHdoeSBub3Igd2FzIEkgYWJsZSB0byBmaW5kIGFuIGFuc3dlci4gSWYgaGF2ZSBhbiBhbnN3ZXIgb3Iga25vdyBhIHNvbHV0aW9uLCBwbGVhc2UgbGV0IHVzIGtub3cuIFRoZXJlICplYXNpZXN0KiB3YXkgdG8gZ2VuZXJhdGUgYW4gUiBzY3JpcHQgZnJvbSBhbiBSIE1hcmtkb3duIGRvY3VtZW50IHdpdGggYHB1cmxgIHRvICBpcyB0byBydW4gdGhlIGNvbW1hbmQgaW4gdGhlIENvbnNvbGUgbGlrZSBzbzoKCmBrbml0cjo6cHVybChpbnB1dD0iZmlsZW5hbWUuUm1kIiwgZG9jdW1lbnRhdGlvbiA9IDEpYAoKPiBSdW4gdGhlIGBwdXJsYCBjb21tYW5kIHVzaW5nIHRoZSB0aHJlZSBvcHRpb25zIGRlc2NyaWJlZCBhYm92ZSBmb3IgYGRvY3VtZW50YXRpb25gIG9wdGlvbiBhbmQgbG9vayBhdCB0aGUgb3V0cHV0IGZpbGVzLgoKSW5saW5lIFIgZXhwcmVzc2lvbnMgYXJlIGlnbm9yZWQgYnkgZGVmYXVsdC4gRm9yIGV4YW1wbGUsIGlmIHlvdSBoYWQgYW4gaW5saW5lIFIgZXhwcmVzc2lvbiBsaWtlIHRoaXMgYGAgYHIKc3FydCgyKWAgYGAKdGhlIGV4cHJlc3Npb24gd291bGQgbm90IGJlIGluY2x1ZGVkIGluIHRoZSBSIHNjcmlwdCBnZW5lcmF0ZWQgYnkgYHB1cmxgLiBJZiB5b3Ugd2FudCB0byBpbmNsdWRlIGlubGluZSBleHByZXNzaW9ucyBpbiB0aGUgUiBzY3JpcHQsIHlvdSBuZWVkIHRvIHNldCB0aGUgZ2xvYmFsIFIgb3B0aW9uIGBrbml0ci5wdXJsLmlubGluZSA9IFRSVUVgIGJlZm9yZSBjYWxsaW5nIGBrbml0cjo6cHVybCgpYC4KClJlbWVtYmVyIHdheSBiYWNrIHdoZW4geW91IGdlbmVyYXRlZCB5b3VyIGluaXRpYWwgUiBNYXJrZG93biBkb2N1bWVudCBhIGRlZmF1bHQgY29kZSBjaHVuayB3YXMgYWRkZWQganVzdCBiZWxvdyB0aGUgWUFNTCBoZWFkZXI/CgoKYGBgYApgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX1gciAnJ2AKa25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQpgYGAKYGBgYAoKSWYgeW91IGFkZCBga25pdHIucHVybC5pbmxpbmUgPSBUUlVFYCB0byB0aGF0IGNvZGUgY2h1bmssIGFsbCBpbmxpbmUgZXhwcmVzc2lvbnMgd2lsbCBiZSBhZGRlZCB0byB0aGUgUiBzY3JpcHQuCgpgYGBgCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfWByICcnYAprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsIGtuaXRyLnB1cmwuaW5saW5lID0gVFJVRSkKYGBgCmBgYGAKClRoZSBsYXN0IHRoaW5nIEkgd2FudCB0byBtZW50aW9uIGlzIHRoYXQgeW91IGNhbiAqcHJldmVudCogY2VydGFpbiBjb2RlIGNodW5rcyBmcm9tIGFwcGVhcmluZyBpbiB0aGUgUiBTY3JpcHQgYnkgYWRkaW5nIHRoZSBvcHRpb24gYHB1cmwgPSBGQUxTRWAgdG8gdGhlIGNodW5rLiBGb3IgZXhhbXBsZSwgaWYgeW91IGFkZCB0aGlzIG9wdGlvbiB0byB0aGUgYHNldHVwYCBjaHVuayB3ZSBqdXN0IGRpc2N1c3NlZCB0aGF0IGNodW5rIHdpbGwgbm90IGFwcGVhciBpbiB0aGUgZmluYWwgZG9jdW1lbnQuCgpgYGBgCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFLCBwdXJsID0gRkFMU0V9YHIgJydgCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwga25pdHIucHVybC5pbmxpbmUgPSBUUlVFKQpgYGAKYGBgYAoKVGVzdCB0aGUgYmVoYXZpb3Igb2YgdGhlIGRpZmZlcmVudCBvcHRpb25zIGZvciBgcHVybGAgb24geW91ciBkb2N1bWVudC4gWW91IGNhbiBhbHNvIHVzZSB0aGlzIGZ1bnRpb24gb24gKmFueSogUiBNYXJrZG93biBkb2N1bWVudCB0byBxdWlja2x5IHJldHJpZXZlIHRoZSBjb2RlLiBGb3IgZXhhbXBsZSwgaWYgeW91IGRvd25sb2FkIHRoZSBSbWQgZmlsZSBmb3IgdGhpcyBwYWdlIGZyb20gR2l0SHViIHlvdSBjYW4gcnVuIGBwdXJsYCB0byBxdWlja2x5IGV4dHJhY3QgdGhlIFIgY29kZS4KCj4gKipSZWNvbW1lbmRhdGlvbioqIFVzZSBgcHVybGAgdG8gZ2VuZXJhdGUgYSBzaW1wbGUgUiBzY3JpcHQgdmVyc2lvbiBvZiB5b3VyIFIgTWFya2Rvd24gZG9jdW1lbnQgKmFmdGVyKiB0aGUgZG9jdW1lbnQgaXMgZmluaXNoZWQgYW5kIHNhdmVkLiBZb3UgY2FuIHRoZW4gbGluayB0byB0aGUgZmlsZSBzb21ld2hlcmUgaW4geW91ciBkb2N1bWVudC4KCiMjIyBEb3dubG9hZCBSbWQKCkkgaG9wZSBieSBub3cgeW91IGhhdmUgc2VlbiB0aGF0IGFueSBkb2N1bWVudCBJIHByZXNlbnQgaW4gdGhpcyBjb3Vyc2UgaGFzIGEgbGluayB0byBhIEdpdEh1YiByZXBvIHdoZXJlIHlvdSBjYW4gZG93bmxvYWQgb3IgY29weSB0aGUgYC5SbWRgIGZpbGUuIFRoYXQncyBncmVhdCBhbmQgYWxsLCBidXQgd291bGRuJ3QgaXQgYmUgbmljZSBpZiB5b3UgY291bGQgZG8gaXQgcmlnaHQgZnJvbSB0aGUgSFRNTCBwYWdlPyBXZWxsLCB5b3UgY2FuIGJ5IGFkZGluZyBvbmUgc2ltcGxlIGxpbmUgb2YgY29kZSBhcyBhIHByb3BlcnR5IG9mIGBodG1sX2RvY3VtZW50YCBpbiB5b3VyIFlBTUwgaGVhZGVyIC0tLWBjb2RlX2Rvd25sb2FkOiB0cnVlYC4KCmBgYApvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIHRoZW1lOiBqb3VybmFsCiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgdG9jX2RlcHRoOiAzCiAgICBoaWdobGlnaHQ6IHRhbmdvCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCmBgYAoKWW91IGNvdWxkIG9mIGNvdXJzZSBzZXQgdGhlIHByb3BlcnR5IHRvIGBmYWxzZWAgZXhjZXB0IHRoaXMgaXMgdGhlIGRlZmF1bHQgdmFsdWUgYW5kIG5vdGhpbmcgd2lsbCBjaGFuZ2UuIExvb2sgYmFjayBhdCB0aGUgdG9wIG9mIHRoaXMgcGFnZSBhbmQgeW91IHNob3VsZCBub3cgc2VlIGEgYENvZGVgIGJ1dHRvbiBpbiB0aGUgdXBwZXIgcmlnaHQgY29ybmVyLiBDbGljayBvbiB0aGUgZHJvcCBkb3duIGFuZCBzZWxlY3QgYERvd25sb2FkIFJtZGAgYW5kIHRoaXMgZW50aXJlIHBhZ2Ugc2hvdWxkIGJlIHNhdmVkIHRvIHlvdXIgRG93bmxvYWRzIGRpcmVjdG9yeS4KCj4gR28gYWhlYWQgYW5kIGFkZCB0aGlzIG9wdGlvbiB0byB5b3VyIFlBTUwgaGVhZGVyLgoKIyMjIENvZGUgRm9sZGluZwoKSSBoYXZlIG1lbnRpb25lZCBhIHRpbWUgb3IgdHdvIHRoYXQgdGhlIGJlbmVmaXRzIG9mIHVzaW5nIFIgTWFya2Rvd24gaXMgdGhlIGFiaWxpdHkgdG8gKioqZXhlY3V0ZSoqKiBhbmQgKioqZGlzcGxheSoqKiBjb2RlIGluIHlvdXIgZmluYWwgZG9jdW1lbnQuIElmIHlvdSBnbyBiYWNrIHRvIHRoZSBkZWZhdWx0IGBzZXR1cGAgY2h1bmsgYXQgdGhlIHRvcCBvZiB5b3VyIGAuUm1kYCB5b3Ugc2hvdWxkIHNlZSB0aGlzOgoKYGBgCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkKYGBgCgpJIGRpc2N1c3NlZCB0aGlzIGNodW5rIHByZXZpb3VzbHkgaW4gIzUgb2YgdGhlIFtDaHVuayBzdHJ1Y3R1cmUgJiBvcHRpb25zXShodHRwczovL3N0cmktY29uLmdpdGh1Yi5pby9kYXRhLWN1cmF0aW9uLzIwMjAvMDQvMDkvbGVzc29uLTIvI2NodW5rLXN0cnVjdHVyZS1vcHRpb25zLTEpIHNlY3Rpb24gaW4gTGVzc29uIDIuIEJyaWVmbHksIHRoaXMgaXMgYSAqZ2xvYmFsIGNvbW1hbmQqIHRoYXQgZW5zdXJlcyBhbGwgUiBjb2RlIGNodW5rcyBhcmUgdmlzaWJsZSBpbiB0aGUgZmluYWwgZG9jdW1lbnQsIHVubGVzcyB5b3UgZXNjYXBlIHRoaXMgYmVoYXZpb3IgYnkgdXNpbmcgYGVjaG8gPSBGQUxTRWAgaW4gYSBwYXJ0aWN1bGFyIGNodW5rLiBPZiBjb3Vyc2UsIHlvdSBjb3VsZCBhbHNvIHNldCB0aGUgZ2xvYmFsIG9wdGlvbiB0byBgRkFMU0VgIGFzIGlzIGBrbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IEZBTFNFKWAgYW5kIHRoZW4gbm9uZSBvZiB0aGUgUiBjb2RlIHdvdWxkIGJlIHZpc2libGUgYXQgYWxsLiBUaGlzIGlzIGEgcGVyZmVjdGx5IGZpbmUgb3B0aW9uIGluIHNvbWUgc2l0dWF0aW9ucyBidXQgbm90IGluIG90aGVycy4KCkxldCdzIGZhY2UgaXQtLS1jb2RlIHRha2VzIHVwIGEgbG90IG9mIHNwYWNlIGluIGEgZG9jdW1lbnQgYW5kIGxhcmdlIGNvZGUgY2h1bmtzIGFyZSBub3QgcGFydGljdWxhcmx5IHBsZWFzaW5nIHRvIGxvb2sgYXQuIFlvdSBtYXkgZW5jb3VudGVyIHNpdHVhdGlvbnMgd2hlcmUgeW91IGJvdGggd2FudCB0aGUgY29kZSBhdmFpbGFibGUgb24gYSBwYWdlICpidXQqIHlvdSBhbHNvIHdhbnQgdG8gaGlkZSB0aGUgY29kZS4gRm9yIHRoaXMgd2UgdXNlIGEgdGVjaG5pcXVlIGNhbGxlZCAqKipjb2RlIGZvbGRpbmcqKiouIE5lYXIgdGhlIGJvdHRvbSBvZiBbTGVzc29uIDBdKGh0dHBzOi8vc3RyaS1jb24uZ2l0aHViLmlvL2RhdGEtY3VyYXRpb24vMjAyMC8wMy8yOC9sZXNzb24tMC8pLCBJIHVzZWQgc29tZSBzaW1wbGUgSFRNTCB0byBtYWtlIGEgc2VjdGlvbiB0aGF0IGZvbGRzIHRoZSBSIGNvZGUgZm9yIHRoZSBDbGlmZm9yZCBBdHRyYWN0b3IuIFRoZXJlIGlzIGEgbGl0dGxlIGBTaG93L2hpZGVgIGJ1dHRvbiB0aGF0IGFsbG93cyB5b3UgdG8gbG9vayBhdCB0aGUgY29kZSBpZiB5b3Ugd2FudCB0bzsgb3RoZXJ3aXNlIGl0IGlzIGhpZGRlbiBieSBkZWZhdWx0LiBCdXQgdGhpcyBhcHByb2FjaCBpcyBhIGxpdHRsZSBjbHVua3kgYmVjYXVzZSB5b3UgbXVzdCAqKmEqKikga25vdyBzb21lIEhUTUwgYW5kICoqYioqKSBpbmNsdWRlIHRoaXMgZm9yIGV2ZXJ5IGNodW5rLgoKUiBNYXJrZG93biBoYXMgYSBzaW1pbGFyIGZ1bmN0aW9uYWxpdHkgZm9yIHNob3dpbmcgYW5kIGhpZGluZyBjb2RlIGJ1dCBpdCBvbmx5IHRha2VzIGEgc2luZ2xlIGxpbmUgb2YgY29kZSBhZGRlZCB0byB0aGUgWUFNTCBoZWFkZXIuIEFnYWluLCByZXR1cm4gdG8geW91ciBZQU1MIGhlYWRlciBhbmQgYWRkIHRoZSBhcmd1bWVudCAgYGNvZGVfZm9sZGluZzpgIGFzIGEgbmVzdGVkIHByb3BlcnR5IG9mIGBodG1sX2RvY3VtZW50OmAuIFlvdXIgdHdvIG9wdGlvbnMgZm9yIGBjb2RlX2ZvbGRpbmc6YCBhcmUgYHNob3dgIGFuZCBgaGlkZWAuCgpgYGAKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICB0aGVtZTogam91cm5hbAogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKICAgIHRvY19kZXB0aDogMwogICAgaGlnaGxpZ2h0OiB0YW5nbwogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgY29kZV9mb2xkaW5nOiBoaWRlCmBgYAoKT25jZSB5b3UgYWRkIHRoaXMgdG8gdGhlIFlBTUwgaGVhZGVyLCB0aGUgZHJvcCBkb3duIGBDb2RlYCBidXR0b24gaW4gdGhlIHVwcGVyIHJpZ2h0IGNvcm5lciBvZiB0aGUgcGFnZSBzaG91bGQgbm93IGluY2x1ZGUgYFNob3cgQWxsIENvZGVgIGFuZCBgSGlkZSBBbGwgQ29kZWAuIFRoaXMgYWxsb3dzIHRoZSB1c2VyIHRvIHNwZWNpZnkgaG93IHRoZXkgd2FudCB0byB2aWV3IHRoZSBjb2RlIGluIHRoZSBkb2N1bWVudC4gRWl0aGVyIHByb3BlcnR5IHlvdSBzZXQgZm9yIGBjb2RlX2ZvbGRpbmdgIHdpbGwgYmUgdGhlIGRlZmF1bHQgc3RhdGUgZm9yIHRoZSBlbnRpcmUgZG9jdW1lbnQuCgpZb3Ugc2hvdWxkIGFsc28gbm90aWNlIHRoYXQgYSBuZXcgYENvZGVgIGJ1dHRvbiBhcHBlYXJzIG5leHQgdG8gZXZlcnkgY29kZSBjaHVuayBpbiB5b3VyIGRvY3VtZW50LiBBZ2FpbiwgaWYgeW91IHdhbnQgdG8gZXhjbHVkZSB0aGUgY29kZSBmcm9tIGluZGl2aWR1YWwgY2h1bmtzLCBqdXN0IHNldCBgZWNobyA9IEZBTFNFYCBmb3IgdGhhdCBjaHVuayBhbmQgdGhlIGNvZGUgd2lsbCBub3QgYmUgaW5jbHVkZWQgYXQgYWxsLgoKPiBBZGQgYGNvZGVfZm9sZGluZzpgIGFyZ3VtZW50IHRvIHlvdXIgWUFNTCBoZWFkZXIgYW5kIHNldCBhIHByb3BlcnR5IHZhbHVlLgoKPGJyLz4KCkFzIGZhciBhcyBJIGtub3cgdGhlcmUgaXMgbm8gd2F5IG9mIGZvbGRpbmcgdGhlICpyZXN1bHRzKiBvZiBhIGNvZGUgY2h1bmsgb3IgZm9sZGluZyBpbmRpdmlkdWFsIGNodW5rcyB1bmxlc3MgeW91IHVzZSBIVE1MLgoKVGhhdCdzIGFsbCBmb3IgdGhpcyBhc3NpZ25tZW50LgoKIyMgQXNzaWdubWVudCA0OiBHcmFwaGljcwoKVGhlIGxhc3QgbWFqb3IgcGllY2Ugb2YgdGhlIHB1enpsZSBpcyB0byBhZGQgZ3JhcGhpY3MgdG8geW91ciBSIE1hcmtkb3duIGRvY3VtZW50LiBUaGluayBvZiB0aGlzIEFzc2lnbm1lbnQgbW9yZSBhcyBhIG1pbmkgZ3VpZGVib29rIGFuZCBsZXNzIGFzIGEgdG8tZG8gbGlzdCBvZiBhY3Rpdml0aWVzLiBUaGUgcmVhc29uIGJlaW5nLCBpcyB0aGF0IHRoZSB0b3BpYyBvZiAqZ3JhcGhpY3MqIGlzIG11Y2ggdG9vIGJyb2FkIHRvIGNvdmVyIGluLWRlcHRoIGR1cmluZyB0aGlzIGNvdXJzZS4KCkZvciB0aGUgc2FrZSBvZiBjb252ZW5pZW5jZSwgSSB3aWxsIHVzZSAqKipmaWd1cmUqKiogdG8gcmVmZXIgdG8gYW55IHZpc3VhbCByZXByZXNlbnRhdGlvbiBvZiBkYXRhIChjaGFydCwgcGxvdCwgZ3JhcGgsIGV0Yy4pIG1hZGUgd2l0aCAoUikgY29kZSBhbmQgKmdlbmVyYXRlZCogd2hlbiB0aGUgZG9jdW1lbnQgaXMgcmVuZGVyZWQuIEFuICoqKmltYWdlKioqIG9uIHRoZSBvdGhlciBoYW5kLCBpcyBhbnkgZXh0ZXJuYWwgdmlzdWFsIHByb2R1Y3QgKmluc2VydGVkKiBpbnRvIHRoZSBkb2N1bWVudCwgbGlrZSBhIGBwbmdgIG9yIGBqcGdgLgoKVGhlIGRpc3RpbmN0aW9uIGlzIHRoYXQgKipmaWd1cmVzKiogYXJlICpjcmVhdGVkKiB3aGVuIHRoZSBSIE1hcmtkb3duIGRvY3VtZW50IGlzIHJlbmRlcmVkLCBhbmQgdGhlIFIgY29kZSBpcyBwcm9jZXNzZWQuIEluIGNvbnRyYXN0LCAqKmltYWdlcyoqIGFyZSAqYWRkZWQqIHRvIHRoZSByZW5kZXJlZCBkb2N1bWVudCBieSByZWZlcmVuY2luZyBhIGZpbGUuCgpMZXQncyBsb29rIGF0IGFuIGV4YW1wbGUgdGhhdCBkZW1vbnN0cmF0ZXMgdGhlIGRpZmZlcmVuY2UgYmV0d2VlbiBhICpmaWd1cmUqIGFuZCBhbiAqaW1hZ2UqLiBXZSBjYW4gdXNlIHRoZSBidWlsdC1pbiBgcHJlc3N1cmVgIGRhdGEgc2V0IGZyb20gdGhlIGBkYXRhc2V0c2AgcGFja2FnZSBhbmQgdGhlIGBwbG90YCBjb21tYW5kIHRvIGRpc3BsYXkgYSB0ZW1wZXJhdHVyZS1ieS1wcmVzc3VyZSBwbG90LiBIZXJlIGlzIHRoZSBzaW1wbGUgbGluZSBvZiBjb2RlIGZvbGxvd2VkIGJ5IHRoZSBmaWd1cmUgdGhhdCBpcyBjcmVhdGVkIHdoZW4gdGhlIGRvY3VtZW50IGlzIHJlbmRlcmVkLgoKYGBge3IgcGxvdF9wcmVzc3VyZSwgZmlnLmNhcD0iPHNtYWxsPioqKkZpZ3VyZSoqIGdlbmVyYXRlZCB3aXRoIFIgY29kZSBhbmQgcmVuZGVyZWQgaW4gdGhlIGZpbmFsIGRvY3VtZW50LiogPC9zbWFsbD4ifQpwbG90KHByZXNzdXJlKQpgYGAKCkJhc2ljYWxseSwgd2hlbiBJIGtuaXQgdGhlIFIgTWFya2Rvd24gZmlsZSAoYC5SbWRgKSB0aHJlZSB0aGluZ3MgaGFwcGVuLiBGaXJzdCwgYGtuaXRyYCByZWFkcyB0aGUgY29kZSBjaHVuaywgY3JlYXRlcyB0aGUgcGxvdCwgYW5kIHNhdmVzIHRoZSBwbG90IGFzIGEgYC5wbmdgIGZpbGUuIE5leHQsIGtuaXRyIGFkZHMgYSBsaW5lIG9mIGNvZGUgdG8gdGhlIHN1YnNlcXVlbnQgTWFya2Rvd24gZmlsZSAoYC5tZGApLCB3aGljaCBsaW5rcyB0byB0aGUgYC5wbmdgIGZpbGUuIEZpbmFsbHksIFBhbkRvYyBlbWJlZHMgdGhlIGAucG5nYCBmaWxlIGludG8gdGhlIEhUTUwgZG9jdW1lbnQuIEFuZCBqdXN0IGxpa2UgdGhhdCwgSSBoYXZlIGEgcGxvdCBpbiBteSBIVE1MIGRvY3VtZW50IGZyb20gYSBzaW5nbGUgbGluZSBvZiBSIGNvZGUuCgpOb3cgaW5zdGVhZCBsZXQncyBzYXkgSSBuZWVkIHRvIGRvIHNvbWUgcG9zdC1wcm9jZXNzaW5nIG9uIHRoZSBwbG90LiBJIHdhbnQgdGhlIHBvaW50cyB0byBiZSBsYXJnZXIgYW5kIHJlZCwgYnV0IEkgYW0gdG9vIGxhenkgdG8gZmlndXJlIG91dCBob3cgdG8gY29kZSB0aGlzIGluIFIgKHlvdSBzaG91bGQgbm90IGJlIHNvIGxhenkpLiBJIGNhbiB1c2UgdGhlIHNhbWUgY29kZSB0byBnZW5lcmF0ZSB0aGUgcGxvdCBpbiBSIGJ1dCB0aGlzIHRpbWUgSSB3aWxsIG1hbnVhbGx5IHNhdmUgdGhlIHBsb3QgYXMgYSBgcG5nYCBmaWxlLiBJIHRoZW4gbWFrZSB0aGUgbW9kaWZpY2F0aW9ucyBpbiBhIHZlY3RvciBncmFwaGljcyBwcm9ncmFtIGxpa2UgW0lua3NjYXBlXShodHRwczovL2lua3NjYXBlLm9yZy8pLCBzYXZlIHRoZSBtb2RpZmllZCBmaWxlLCBhbmQgdGhlbiB1c2UgIE1hcmtkb3duIGNvZGUgaW4gbXkgYC5SbWRgIGZpbGUgdG8gaW5jbHVkZSB0aGUgaW1hZ2UgaW4gdGhlIGZpbmFsIGRvY3VtZW50LiBJbiB0aGlzIGNhc2UsIHRoZSBwbG90IGlzIGFkZGVkIGRpcmVjdGx5IHRvIHRoZSBIVE1MIGRvY3VtZW50IGJ5IFBhbkRvYyByYXRoZXIgdGhhbiBmaXJzdCBiZWluZyBnZW5lcmF0ZWQgYnkga25pdHIuCgpgYGB7ciBzYXZlX3Bsb3RfcHJlc3N1cmUsIHJlc3VsdHM9J2hpZGUnfQojIFIgY29kZSB0byBjcmVhdGUgYW5kIHNhdmUgaW1hZ2UKcG5nKCJmaWxlcy9wcmVzc3VyZS5wbmciLCB3aWR0aCA9IDY4MCwgaGVpZ2h0ID0gNTAwLAogICAgdW5pdHMgPSAicHgiLCBwb2ludHNpemUgPSAxNikKcGxvdChwcmVzc3VyZSkKZGV2Lm9mZigpCmBgYAoKYGBgCiMgTWFya2Rvd24gY29kZSBpbiB0aGUgUm1kIGZpbGUgdG8gYWRkIGFuIGltYWdlLgohW10oZmlsZXMvcHJlc3N1cmVfbW9kaWZpZWQucG5nKQpgYGAKCiFbXShmaWxlcy9wcmVzc3VyZV9tb2RpZmllZC5wbmcpCgo8c21hbGw+KioqSW1hZ2UqKiBhZGRlZCB0byB0aGUgcmVuZGVyZWQgZG9jdW1lbnQgYnkgcmVmZXJlbmNpbmcgYSBmaWxlIHVzaW5nIE1hcmRvd24uKiA8L3NtYWxsPgoKT2YgY291cnNlLCB5b3UgY2FuIGFkZCBhbnkgaW1hZ2UgeW91IHdhbnQuIFRoZSBpbWFnZSAqZG9lcyBub3QqIG5lZWQgdG8gYmUgZ2VuZXJhdGVkIGJ5IFIgY29kZSBvciBiZSBhIGBwbmdgLiBGb3IgZXhhbXBsZSwgaGVyZSBpcyBhIFtHaXJpaCB0aWxlXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9HaXJpaF90aWxlcykgbW9zYWljIEkgbWFkZSB1c2luZyB0aGUgb25saW5lIHRvb2wgW0dpcmloIERlc2lnbmVyXShodHRwczovL2dpcmloZGVzaWduZXIuY29tLykuCgpgYGAKIVtdKGZpbGVzL2dpcmloLmpwZykKYGBgCgo8YnIvPgoKIVtdKGZpbGVzL2dpcmloLmpwZykKCipHaXJpaCB0aWxlcyBhcmUgYSBzZXQgb2YgcmVndWxhciBwb2x5Z29ucyAod2l0aCBvdmVybGFpZCBzdHJhcHdvcmspIHVzZWQgaW4gbWVkaWV2YWwgSXNsYW1pYyBhcmNoaXRlY3R1cmUuIENoZWNrIG91dCB0aGlzIGNvb2wgW1NjaWVuY2UgcGFwZXJdKGh0dHA6Ly93d3cucGh5c2ljcy5ydXRnZXJzLmVkdS9+cGNoYW5kcmEvcGh5c2ljczYwMS9MdV9TdGVpbmhhcmR0LnBkZikgZnJvbSAyMDA3IHRoYXQgZXhwbG9yZXMgdGhlIGdlb21ldHJ5IGJlaGluZCBHaXJpaCB0aWxlcy4qCgo8YnIvPgoKPiBJdCBpcyBpbXBvcnRhbnQgdG8gdW5kZXJzdGFuZCB0aGUgZGlzdGluY3Rpb24gYmV0d2VlbiBjb2RlLWdlbmVyYXRlZCAqZmlndXJlcyogIHZzLiBpbXBvcnRlZCAqaW1hZ2VzKi4gWW91IG5lZWQgZGlmZmVyZW50IHRvb2xzIHRvIGRpc3BsYXkgYW5kIGNvbnRyb2wgZWFjaCB0eXBlIG9mIGdyYXBoaWMuCgo+ICMjIyMjIFlvdXIgZ29hbCBmb3IgdGhpcyBBc3NpZ25tZW50IGlzIHRvIGFkZCAqZmlndXJlcyogYW5kICppbWFnZXMqIHRvIHlvdXIgUiBNYXJrZG93biBwYWdlLgoKQ2hlY2sgb3V0IHRoaXMgYmxvZyBwb3N0IGZyb20gWmV2Um9zcyBvbiBbVGlwcyBhbmQgdHJpY2tzIGZvciB3b3JraW5nIHdpdGggaW1hZ2VzIGFuZCBmaWd1cmVzIGluIFIgTWFya2Rvd24gZG9jdW1lbnRzXShodHRwczovL3d3dy56ZXZyb3NzLmNvbS9ibG9nLzIwMTcvMDYvMTkvdGlwcy1hbmQtdHJpY2tzLWZvci13b3JraW5nLXdpdGgtaW1hZ2VzLWFuZC1maWd1cmVzLWluLXItbWFya2Rvd24tZG9jdW1lbnRzLyNhcmd1bWVudHMtb3V0LndpZHRoLWFuZC1vdXQuaGVpZ2h0LWFwcGx5LXRvLWJvdGgtZXhpc3RpbmctaW1hZ2VzLWFuZC1yLWdlbmVyYXRlZC1maWd1cmVzKS4gSSByZWZlcmVuY2UgdGhpcyByZXNvdXJjZSBhIGxvdC4KCiMjIyBGaWd1cmVzCgpJIHRoaW5rIGEgbG90IGFib3V0IGRhdGEgdmlzdWFsaXphdGlvbiBhbmQgaW4gbXkgb3BpbmlvbiwgaXQgaXMgb25lIG9mIHRoZSBtb3N0IGltcG9ydGFudCBza2lsbHMgeW91IGNhbiBkZXZlbG9wIGFzIHlvdSBtb3ZlIGZvcndhcmQgd2l0aCB5b3VyIG93biB3b3JrLgoKPiAqVGhlIHNpbXBsZSBncmFwaCBoYXMgYnJvdWdodCBtb3JlIGluZm9ybWF0aW9uIHRvIHRoZSBkYXRhIGFuYWx5c3TigJlzIG1pbmQgdGhhbiBhbnkgb3RoZXIgZGV2aWNlLiog4oCUIEpvaG4gVHVrZXkKCkFsbW9zdCBhbnkga2luZCBvZiBkYXRhIGNhbiBiZSB2aXN1YWxpemVkIGFuZCB0aGVyZSBhcmUgbGl0ZXJhbGx5IGRvemVucyBhbmQgZG96ZW5zIG9mIFtmaWd1cmUgdHlwZXNdKGh0dHBzOi8vd3d3LnItZ3JhcGgtZ2FsbGVyeS5jb20vYWxsLWdyYXBocy5odG1sKSB5b3UgY2FuIGNyZWF0ZSB3aXRoIFIgY29kZS4gVGhpcyBpbmNsdWRlcyBtYXBzLCBuZXR3b3JrcywgZmxvdyBjaGFydHMsIGRlbmRyb2dyYW1zLCBhbmQgc28gb24uIEluIGFuIEhUTUwgZG9jdW1lbnQsIGl0IGlzIHBvc3NpYmxlIHRvIGNyZWF0ZSBib3RoIHN0YXRpYyAqYW5kKiBpbnRlcmFjdGl2ZSBmaWd1cmVzLiBIb3dldmVyLCBkYXRhIHZpc3VhbGl6YXRpb24gaW4gUiBpcyBhIGJyb2FkIHRvcGljIGFuZCBjYW4gb2Z0ZW4gZ2V0IHF1aXRlIGNvbXBsaWNhdGVkLiBJbiBhZGRpdGlvbiB0byB0aGUgbnVtZXJvdXMgY2hhcnQgdHlwZXMsIHRoZXJlIGFyZSBtYW55IFIgcGFja2FnZXMgeW91IGNhbiB1c2UgZm9yIHZpc3VhbGl6YXRpb25zLiBTb21lLCBsaWtlIGBnZ3Bsb3QyYCwgaGF2ZSBbZXh0ZW5zaXZlIGZ1bmN0aW9uYWxpdHldKGh0dHA6Ly9yLXN0YXRpc3RpY3MuY28vVG9wNTAtR2dwbG90Mi1WaXN1YWxpemF0aW9ucy1NYXN0ZXJMaXN0LVItQ29kZS5odG1sKSB3aGlsZSBvdGhlcnMgKGUuZy4sIFtsZWFmbGV0XShodHRwczovL3JzdHVkaW8uZ2l0aHViLmlvL2xlYWZsZXQvKSkgYXJlIG1vcmUgYXBwcm9wcmlhdGUgZm9yIHNwZWNpZmljIHR5cGVzIG9mIGRhdGEgYW5kL29yIHZpc3VhbGl6YXRpb25zLiBVbHRpbWF0ZWx5LCB0aGUgYXBwcm9hY2ggeW91IGNob29zZSB3aWxsIGRlcGVuZCBvbiB5b3VyIGRhdGEgYW5kIHRoZSB0eXBlIG9mIG1lc3NhZ2UgeW91IHdhbnQgdG8gY29udmV5LgoKTXkgcG9pbnQgaW4gc2F5aW5nIHRoaXMgaXMgdGhhdCBhIGNvbXByZWhlbnNpdmUgdHV0b3JpYWwgb24gZGF0YSB2aXN1YWxpemF0aW9uIGluIFIgaXMgc2ltcGx5IGJleW9uZCB0aGUgc2NvcGUgb2YgdGhpcyBBc3NpZ25tZW50LiBJZiB0aGVyZSBpcyBzdWZmaWNpZW50IGludGVyZXN0IGluIHBhcnRpY3VsYXIgcGFja2FnZXMgYW5kL29yIGNoYXJ0IHR5cGVzIEkgYW0gaGFwcHkgdG8gd3JpdGUgYSBsZXNzb24gcGxhbi4gRm9yIG5vdywgSSB3b3VsZCBsaWtlIHRvIGZvY3VzIG9uIGEgZmV3ICpiZXN0IHByYWN0aWNlcyogYW5kICpzdHJhdGVnaWVzKiB0aGF0IEkgdGhpbmsgYXJlIGltcG9ydGFudCBmb3IgY3JlYXRpbmcgdmlzdWFsaXphdGlvbiBwcm9kdWN0cyB1c2luZyBjb2RlIGluIHlvdXIgUiBNYXJrZG93biBkb2N1bWVudC4gCgoxKSBTZWxlY3QgYW4gYXBwcm9wcmlhdGUgY2hhcnQgdHlwZSB0byBzdWl0ZSB5b3VyIG5lZWRzLgoyKSBXaGVuZXZlciBwb3NzaWJsZSwgYWx3YXlzIGdlbmVyYXRlIGZpZ3VyZXMgaW4geW91ciBSIE1hcmtkb3duIGRvY3VtZW50IHVzaW5nIChSKSBjb2RlLgozKSBJZiB5b3UgdXNlIGNvbG9yIGluIHlvdXIgZmlndXJlcywgcGF5IHNwZWNpYWwgYXR0ZW50aW9uIHRvIHlvdXIgY29sb3IgcGFsZXR0ZS4KNCkgSG93IHRvIGNvbnRyb2wgdGhlIG91dHB1dC4KCjxici8+CgpUaGlzIGxpc3QgaXMgZmFyIGZyb20gY29tcHJlaGVuc2l2ZS4gVGhlcmUgaXMgYSBwYXBlciBpbiBQTG9TIENvbXB1dGF0aW9uYWwgQmlvbG9neSBmcm9tIDIwMTQgb24gW1RlbiBTaW1wbGUgUnVsZXMgZm9yIEJldHRlciBGaWd1cmVzXShodHRwczovL2RvaS5vcmcvMTAuMTM3MS9qb3VybmFsLnBjYmkuMTAwMzgzMyksIHdoaWNoIHByb3ZpZGVzIGEgbmljZSBwcmltZXIgb24gdGhlIHN1YmplY3Qgb2YgZmlndXJlIGRlc2lnbi4gCgpJZiB5b3Ugd2FudCB0byBnZXQgZGVlcGVyIGludG8gdmlzdWFsaXphdGlvbiBtZXRob2RzIGFuZCB0ZWNobmlxdWVzLCBiZXlvbmQgd2hhdCB3ZSBkaXNjdXNzIGhlcmUsIEkgc3Ryb25nbHkgZW5jb3VyYWdlIHlvdSB0byBsZWFybiBtb3JlIGFib3V0IHRoZSB3b3JrIG9mIFtFZHdhcmQgVHVmdGVdKGh0dHBzOi8vd3d3LmVkd2FyZHR1ZnRlLmNvbS90dWZ0ZS8pLCB3aWRlbHkgcmVjb2duaXplZCBhcyBhIHBpb25lZXIgaW4gdGhlIGZpZWxkIG9mIGRhdGEgdmlzdWFsaXphdGlvbi4KCkZvciBzb21lIGluc3BpcmF0aW9uLCBJIGFsc28gcmVjb21tZW5kIHZpc2l0aW5nIFtNYXJ0aW4gS3J6eXdpbnNraV0oaHR0cDovL21rd2ViLmJjZ3NjLmNhLykgZGF0YSB2aXN1YWxpemF0aW9uIHNpdGUuIFRoZSBzaXRlIGl0c2VsZiBpcyBkZW5zZSwgYnV0IE1hcnRpbidzIHZpc3VhbGl6YXRpb25zIGFyZSBpbmNyZWRpYmxlLCBhbmQgdGhlIHNpdGUgaXMgdXBkYXRlZCBvZnRlbi4KCjxici8+CgojIyMjIDEuIFNlbGVjdCBhIGNoYXJ0IHR5cGUKCk9uZSBvZiB0aGUgZmlyc3QgdGhpbmdzIHRvIHRoaW5rIGFib3V0IGlzIHdoYXQga2luZCBvZiBjaGFydCB5b3Ugd2FudCB0byBjcmVhdGUuIEFzIEkgbWVudGlvbmVkLCB0aGlzIHdpbGwgZGVwZW5kIG9uIHRoZSB0eXBlIG9mIGRhdGEgeW91IGhhdmUgYW5kIHRoZSBtZXNzYWdlIHlvdSBhcmUgdHJ5aW5nIHRvIGNvbnZleS4gVGhlcmUgYXJlIGRpZmZlcmVudCBmYWN0b3JzIHRvIGNvbnNpZGVyIHdoZW4gc2VsZWN0aW5nIGEgY2hhcnQgdHlwZSBhbmQgbWFueSBvbmxpbmUgdG9vbHMgYXZhaWxhYmxlIHRvIGhlbHAgbmFycm93IGRvd24geW91ciBzZWxlY3Rpb24uCgo8ZmlndXJlPgogIDxhIGhyZWY9Imh0dHBzOi8vZXh0cmVtZXByZXNlbnRhdGlvbi50eXBlcGFkLmNvbS9maWxlcy9jaG9vc2luZy1hLWdvb2QtY2hhcnQtMDkucGRmIj4KICAgIDxpbWcgc3JjPSJmaWxlcy9jaG9vc2luZy1hLWdvb2QtY2hhcnQtMDkucG5nIiBhbHQ9IlczU2Nob29scy5jb20iPgogIDwvYT4KICA8ZmlnY2FwdGlvbj48c21hbGw+PGVtPlRoZSBvcmlnaW5hbCBDaGFydCBDaG9vc2VyIGRlc2lnbmVkIGFuZCBwdWJsaXNoZWQgYnkgQW5kcmV3IEFiZWxhLiBUaGUgQ2hhcnQgQ2hvb3NlciBpcyBhIGZsb3djaGFydCBndWlkZSB0aGF0IGhlbHBzIHlvdSBpZGVudGlmeSB0aGUgdHlwZSBvZiBjaGFydCB0aGF0IGlzIGFwcHJvcHJpYXRlIHRvIHlvdXIgZGF0YS4gQ2xpY2sgb24gdGhlIGltYWdlIHRvIGRvd25sb2FkIGEgUERGIGNvcHkuPC9zbWFsbD48L2VtPjwvZmlnY2FwdGlvbj4KPC9maWd1cmU+Cgo8YnIvPgoKVGhlICpDaGFydCBDaG9vc2VyKiB3YXMgb3JpZ2luYWxseSBwdWJsaXNoZWQgaW4gMjAwOSBzbyBpdCBpcyBhIGJpdCBvbGQgbm93LiBCdXQgaXQgY2FuIGdpdmUgeW91IGEgZ29vZCBwbGFjZSB0byBzdGFydCB3aGVuIGNob29zaW5nIGEgY2hhcnQgdHlwZS4gQ29vbCBJbmZvZ3JhcGhpY3MgYnkgW1JhbmR5IEtydW1dKGh0dHBzOi8vcmFuZHlrcnVtLmNvbS8pIGhhcyBhIG5pY2UgW0RhdGFWaXogcGFnZV0oaHR0cHM6Ly9jb29saW5mb2dyYXBoaWNzLmNvbS9kYXRhdml6LWd1aWRlcykgdGhhdCBwcm92aWRlcyBhIG1vcmUgdXAtdG8tZGF0ZSBjb2xsZWN0aW9uIG9mIGRhdGEgdmlzdWFsaXphdGlvbiBjaGFydCBjaG9vc2VycywgcmVmZXJlbmNlIGd1aWRlcywgYW5kIGNoZWF0IHNoZWV0cy4KCltZYW4gSG9sdHpdKGh0dHBzOi8vd3d3Lnlhbi1ob2x0ei5jb20vKSBoYXMgZGV2ZWxvcGVkIHNldmVyYWwgd2Vic2l0ZXMgZGVkaWNhdGVkIHRvIGRhdGEgdmlzdWFsaXphdGlvbi4gVGhlc2UgcmVzb3VyY2VzIGFyZSAqKkFNQVpJTkcqKiBub3QgdG8gbWVudGlvbiB0aGF0IGhpcyB3ZWJzaXRlcyBhcmUgYmVhdXRpZnVsLiBQbGVhc2UgbG9vayBhdCBZYW4ncyBbRnJvbSBEYXRhIHRvIFZpel0oaHR0cHM6Ly93d3cuZGF0YS10by12aXouY29tLykgcGFnZS4gVGhpcyBwYWdlIGlzIGludGVyYWN0aXZlIGFuZCBkZXNpZ25lZCB0byBoZWxwIHlvdSBjaG9vc2UgdGhlIG1vc3QgYXBwcm9wcmlhdGUgY2hhcnQgZm9yIHlvdXIgZGF0YS4gSXQgaGFzIGxpbmtzIHRvIHRoZSBjb2RlLCBleHBsYW5hdGlvbnMsIGFuZCBjb21tb24gbWlzdGFrZXMgdG8gYXZvaWQuCgo+ICMjIyMjIEFzc2lnbm1lbnQ6IFNwZW5kIHRpbWUgZmFtaWxpYXJpemluZyB5b3Vyc2VsZiB3aXRoIGRpZmZlcmVudCBkYXRhIHZpc3VhbGl6YXRpb24gdGVjaG5pcXVlcyBhbmQgY2hhcnQgdHlwZXMuIFRoaW5rIGFib3V0IHlvdXIgb3duIGRhdGEgYW5kIGRhdGEgdmlzdWFsaXphdGlvbiBuZWVkcy4KCjxici8+CgojIyMjIDIuIENyZWF0ZSB5b3VyIGZpZ3VyZQoKVGhlIG5leHQgc3RlcCBpcyB0byB3cml0ZSB0aGUgY29kZSBmb3IgeW91ciBmaWd1cmUuIFdoZXJlIHBvc3NpYmxlLCAqKipJIGhpZ2hseSByZWNvbW1lbmQgdGhhdCB5b3UgY29kZSBhbGwgb2YgeW91ciBmaWd1cmVzIGRpcmVjdGx5IGluIHRoZSBSIE1hcmtkb3duIGRvY3VtZW50KioqLiBDb2RpbmcgeW91ciBmaWd1cmVzIGRpcmVjdGx5IGlzIGJlbmVmaWNpYWwgZm9yIHNldmVyYWwgcmVhc29ucy4gQnkgY3JlYXRpbmcgZmlndXJlcyBkaXJlY3RseSBpbiBhbiBSIE1hcmtkb3duIGRvY3VtZW50IGFuZCBpbmNsdWRpbmcgdGhlIGNvZGUgeW91IGNhbjoKCiogKipQcm92aWRlIG1vcmUgcmVwcm9kdWNpYmxlICYgdHJhbnNwYXJlbnQgd29ya2Zsb3dzKiouIElmIHlvdSBwcmVzZW50IGEgZmlndXJlIHdpdGggdGhlIGNvZGUgKmFuZCogdGhlIHVuZGVybHlpbmcgZGF0YSwgeW91ciByZWFkZXJzIGNhbiBlYXNpbHkgdmFsaWRhdGUgeW91ciBmaW5kaW5ncy4KKiAqKkhlbHAgb3RoZXJzKiouIEhhdmUgeW91IGV2ZXIgc2VlbiBhIGdyYXBoaWMgYW5kIHdvbmRlcmVkIGhvdyBpdCB3YXMgY3JlYXRlZD8gQnkgbWFraW5nIHRoZSBjb2RlIGF2YWlsYWJsZSBpbiB5b3VyIGRvY3VtZW50LCB5b3UgaGVscCBvdGhlcnMgY3JlYXRlIGJhZGFzcyBmaWd1cmVzLgoqICoqQWx3YXlzIHJlbWVtYmVyKiouIEhvdyBtYW55IHRpbWVzIGhhdmUgeW91IGNyZWF0ZWQgYSBmaWd1cmUgYW5kIHRoZW4gZm9yZ290dGVuIGhvdyB5b3UgbWFkZSBpdD8gV2VsbCwgbm8gbW9yZS4gTm93IHlvdXIgZmlndXJlcyBhcmUgZGlyZWN0bHkgdGllZCB0byB0aGUgY29kZQoqICoqUmV1c2UgY29kZSBibG9ja3MqKi4gWW91IG1heSBmaW5kIHlvdXJzZWxmIHVzaW5nIHRoZSBzYW1lIGNoYXJ0IHR5cGUgb3ZlciBhbmQgb3ZlciBpbiB5b3VyIHdvcmsuIFJhdGhlciB0aGFuIHJld3JpdGluZyB0aGUgc2FtZSBjb2RlIGVhY2ggdGltZSwgeW91IGNhbiByZXVzZSB0aGUgY29kZSBjaHVuay4KKiAqKkVhc2lseSBtYWtlIGNoYW5nZXMqKi4gTXkgZ29hbCBpcyB0byBjb2RlIGZpZ3VyZXMgdGhhdCBhcmUgYXMgY2xvc2UgdG8gcHJvZHVjdGlvbiByZWFkeSBhcyBwb3NzaWJsZS4gQnkgdGhhdCBJIG1lYW4gY3JlYXRpbmcgZmlndXJlcyB0aGF0IG5lZWQgbGl0dGxlIG9yIG5vIHBvc3QtcHJvY2Vzc2luZyBiZWZvcmUgZ29pbmcgaW50byBhIHB1YmxpY2F0aW9uLiBJZiBJIG5lZWQgdG8gY2hhbmdlIHNvbWUgcGFydCBvZiBhIGZpZ3VyZSwgSSBzaW1wbHkgbW9kaWZ5IHRoZSBjb2RlIGFuZCByZS1yZW5kZXIgdGhlIGRvY3VtZW50LiBUaGlzIGtlZXAgcG9zdC1wcm9jZXNzaW5nIHRvIGEgbWluaW11bS4KCkhlcmUgaXMgYW4gZXhhbXBsZSBvZiB3aGF0IEkgbWVhbi4gT24gdGhlIGxlZnQgaXMgdGhlIHB1Ymxpc2hlZCB2ZXJzaW9uIG9mIGFuIFtOTURTIHBsb3RdKGh0dHBzOi8vcm95YWxzb2NpZXR5cHVibGlzaGluZy5vcmcvZG9pLzEwLjEwOTgvcnNwYi4yMDE5LjIzNjcjUlNQQjIwMTkyMzY3RjEpIGZyb20gYSByZWNlbnQgcGFwZXIuIE9uIHRoZSByaWdodCBpcyB0aGUgKnJhdyogdmVyc2lvbiBvZiB0aGUgcGxvdCBnZW5lcmF0ZWQgd2l0aCBbUiBjb2RlIG9ubHldKGh0dHBzOi8vZ2l0aHViLmNvbS9wcm9qZWN0ZGlnZXN0L3dlYi9ibG9iL21hc3Rlci9idWlsZC8xX2ZpZWxkX29ic2VydmF0aW9ucy5SbWQjTDEyNiktLS1iZWZvcmUgYW55IHBvc3QtcHJvY2Vzc2luZy4KCnwgIVtdKGZpbGVzL2ZpZy1tb2QucG5nKSB8ICFbXShmaWxlcy9maWctcmNvZGUucG5nKSAgfAp8Oi0tLTp8Oi0tLTp8CnwgKlBERiBwb3N0LXByb2Nlc3NlZCBpbiBbSW5rc2NhcGVdKGh0dHBzOi8vaW5rc2NhcGUub3JnLykqIHwgKlIgY29kZSBvbmx5IHNhdmVkIHRvIFBERiogIHwKCkkgaG9wZSB5b3UgYWdyZWUgdGhhdCB0aGUgZGlmZmVyZW5jZXMgYmV0d2VlbiB0aGUgdHdvIGFyZSBtaW5vci4gSW4gdGhlIGZpbmFsIHZlcnNpb24sIEkgY2hhbmdlZCB0aGUgbG9jYXRpb24gb2YgdGhlIGxlZ2VuZCwgbW92ZWQgc29tZSBsYWJlbHMgYXJvdW5kIGZvciBjbGFyaXR5LCBtb2RpZmllZCB0aGUgZm9udCwgYW5kIHR3ZWFrZWQgdGhlIHZlY3RvciBvdmVybGF5cy4gQWdhaW4sIHRoZSBnb2FsIGlzIHRvIGNvZGUgYXMgbXVjaCBvZiB0aGUgZmlndXJlIGFzIHBvc3NpYmxlLCByZWx5aW5nIG9mIHZlY3RvciBncmFwaGljcyBwcm9ncmFtcyBsaWtlIElua3NjYXBlIGFuZCBJbGx1c3RyYXRvciBmb3IgKmJlYXV0aWZpY2F0aW9uIG9ubHkqLgoKQXMgSSBtZW50aW9uZWQgYWJvdmUsIHRlYWNoaW5nIGFuZCBsZWFybmluZyBSIGNvZGUgdG8gZ2VuZXJhdGUgZmlndXJlcyBpcyBjdXJyZW50bHkgYmV5b25kIHRoZSBzY29wZSBvZiB0aGlzIGNvdXJzZS4gVGhhdCBzYWlkLCBJIHdhbnQgeW91IHRvIGV4cGxvcmUgdGhlIHJlc291cmNlcyBsaXN0ZWQgYmVsb3cuIERvaW5nIHNvIHdpbGwgZ2l2ZSB5b3UgYSBiZXR0ZXIgc2Vuc2Ugb2YgZGlmZmVyZW50IGNoYXJ0IHR5cGVzIGFuZCB0aGUgUiBjb2RlIHVzZWQgdG8gZ2VuZXJhdGUgdGhlbS4gSWYgeW91IGRvIG5vdCBrbm93IG11Y2ggUiwgc3RhcnQgYnkgY29weWluZyBjb2RlIGFuZCB0aGVuIHBsYXlpbmcgYXJvdW5kIHdpdGggZGlmZmVyZW50IHBhcmFtZXRlcnMuIEFuZCAqKm1ha2Ugc3VyZSB5b3UgdW5kZXJzdGFuZCB0aGUgZGVmYXVsdCBzZXR0aW5nKiouIAoKPiAjIyMjIyBZb3VyIEFzc2lnbm1lbnQgaXMgdG8gc2VsZWN0IDItMyBkaWZmZXJlbnQgY2hhcnQgdHlwZXMgYW5kIGFkZCB0aGUgUiBjb2RlIHRvIHlvdXIgZG9jdW1lbnQuIElkZWFsbHksIHlvdSB3b3VsZCB1c2UgeW91ciBvd24gZGF0YSBidXQgZmVlbCBmcmVlIHRvIHVzZSB0aGUgZHVtbXkgZGF0YSBwcm92aWRlZCB3aXRoIHRoZSBleGFtcGxlcy4KCklmIHlvdSBoYXZlIG5vdCB1c2VkIFIgdG8gZ2VuZXJhdGUgZmlndXJlcyBiZWZvcmUsIEkgaGlnaGx5IHJlY29tbWVuZCB5b3UgZmlyc3QgbG9vayBhdCB0aGUgW1R1dG9yaWFsIG9uIEdyYXBoc10oaHR0cHM6Ly90YXVhbmFjdW5oYS5jb20vY291cnNlcy8yMDIwX3N0cmlfaW50cm9SL3R1dG9yaWFscy9sM19ncmFwaHMvKSBmcm9tIHRoZSAqSW50cm9kdWN0aW9uIHRvIFIqIGNvdXJzZSBieSBFcm5lc3RvIEJvbmFkaWVzLCBMZWUgRGlldHRlcmljaCwgVGF1YW5hIEN1bmhhLCBhbmQgQnJ1bm8gZGUgTWVkZWlyb3MuIFRoZSB0dXRvcmlhbCBjb3ZlcnMgc29tZSBidWlsdC1pbiBSIGdyYXBoaW5nIGZ1bmN0aW9ucyBhcyB3ZWxsIGFzIGBnZ3Bsb3QyYC4gSXQncyBhIGdyZWF0IHR1dG9yaWFsLiAKClJlbWVtYmVyLCB5b3VyIHZpc3VhbGl6YXRpb24gbmVlZHMgYXJlIHBhcnRpY3VsYXIgdG8geW91IGFuZCB5b3VyIG5lZWRzLiBGaW5kIHNvbWUgY2hhcnRzIHRoYXQgbG9vayBpbnRlcmVzdGluZyBvciB1c2VmdWwgYW5kICBhZGQgdGhlbSB0byB5b3VyIGRvY3VtZW50LiBPZiBjb3Vyc2UsIEkgYW0gbW9yZSB0aGFuIGhhcHB5IHRvIGhlbHAgeW91IGltcGxlbWVudCBhbnkgdHlwZSBvZiBncmFwaCBpbiB5b3VyIGRvY3VtZW50IDopCgoqIFlhbiBIb2x0eidzIFtGcm9tIERhdGEgdG8gVml6XShodHRwczovL3d3dy5kYXRhLXRvLXZpei5jb20vKSBwYWdlLgoqIFtUaGUgUiBHcmFwaCBHYWxsZXJ5XShodHRwczovL3d3dy5yLWdyYXBoLWdhbGxlcnkuY29tL2luZGV4Lmh0bWwpLCBhIGNvbGxlY3Rpb24gb2YgY2hhcnRzIG1hZGUgd2l0aCAgUi4gQ2hhcnRzIGFyZSBkaXZpZGVkIGludG8gc2V2ZXJhbCBzZWN0aW9ucyBhbmQgZWFjaCBjb21lcyB3aXRoIGNoYXJ0IHdpdGggcmVwcm9kdWNpYmxlIGNvZGUuIFtDbGljayBoZXJlXShodHRwczovL3d3dy5yLWdyYXBoLWdhbGxlcnkuY29tL2FsbC1ncmFwaHMuaHRtbCkgdG8gc2VlIGV2ZXJ5IGNoYXJ0IG9uIHRoZSBzaXRlLgoqIElmIHlvdSB3YW50IHRvIHVzZSBvdGhlciBsYW5ndWFnZXMsIHNpbWlsYXIgcGFnZXMgYXJlIGF2YWlsYWJsZSBmb3IgW0QzLmpzXShodHRwczovL3d3dy5kMy1ncmFwaC1nYWxsZXJ5LmNvbS8pIChhIEphdmFTY3JpcHQgbGlicmFyeSkgYW5kIFtQeXRob25dKGh0dHBzOi8vcHl0aG9uLWdyYXBoLWdhbGxlcnkuY29tLykuCgoqIFtyLXN0YXRpc3RpY3MuY29dKGh0dHA6Ly9yLXN0YXRpc3RpY3MuY28vKSBieSBTZWx2YSBQcmFiaGFrYXJhbiBoYXMgW1RvcCA1MCBnZ3Bsb3QyIFZpc3VhbGl6YXRpb25zXShodHRwOi8vci1zdGF0aXN0aWNzLmNvL1RvcDUwLUdncGxvdDItVmlzdWFsaXphdGlvbnMtTWFzdGVyTGlzdC1SLUNvZGUuaHRtbCkgKHdpdGggZnVsbCBSIENvZGUpLgoKKiBbTGVhZmxldF0oaHR0cHM6Ly9yc3R1ZGlvLmdpdGh1Yi5pby9sZWFmbGV0LykgaXMgb25lIG9mIHRoZSBtb3N0IHBvcHVsYXIgb3Blbi1zb3VyY2UgSmF2YVNjcmlwdCBsaWJyYXJpZXMgZm9yICoqaW50ZXJhY3RpdmUgbWFwcyoqLiBDb2RlICsgVHV0b3JpYWxzLgoKPGJyLz4KCiMjIyMgMy4gQ29sb3IKCkkgd2FudCB0byB0dXJuIG5vdyB0byB0aGUgdG9waWMgb2YgKmNvbG9yKi4gQSBxdWVzdGlvbiB0byBhc2sgeW91cnNlbGYgaXMgKmRvIEkgbmVlZCB0byB1c2UgY29sb3IgaW4gdGhpcyBmaWd1cmU/KiBJZiB5b3UgYXJlIHVuc3VyZSwgdGhlIGFuc3dlciBpcyBwcm9iYWJseSAnbm8nLiBIaWdoLWNvbnRyYXN0IGJsYWNrIGFuZCB3aGl0ZSBncmFwaGljcyBjYW4gYmUgbW9yZSByZWFkYWJsZSB0aGFuIGNvbG9yIGFuZCBhbHNvIGJldHRlciBmb3IgY29weWluZyBhbmQgcHJpbnRpbmcuIFNvLCBpZiB5b3UgZG9uJ3QgKm5lZWQqIGNvbG9yIHRoZW4gZG9uJ3QgdXNlIGl0LgoKW0Vkd2FyZCBUdWZ0ZV0oaHR0cHM6Ly93d3cuZWR3YXJkdHVmdGUuY29tL3R1ZnRlLykgaXMgZm9uZCBvZiBzYXlpbmcgdGhhdCBjb2xvciBjYW4gYmUgeW91ciBiZXN0IGFsbHkgb3IgeW91ciB3b3JzdCBlbmVteS4gQ29sb3IgaXMgYW4gaW1wb3J0YW50IHZpc3VhbCBkaW1lbnNpb24gdGhhdCBjYW4gaGVscCB0ZWxsIGEgIGNvbXBlbGxpbmcgc3RvcnkuIEhvd2V2ZXIsIHdoZW4gaXQgaXMgbm90IHVzZWQgY29ycmVjdGx5LCBjb2xvciBjYW4gYmUgY291bnRlcnByb2R1Y3RpdmUgYW5kIGxlYWQgdG8gY29uZnVzaW9uIGFib3V0IHRoZSBtZXNzYWdlIGEgZmlndXJlIGlzIHRyeWluZyB0byBjb252ZXkuCgpJbiBteSBmaWVsZC0tLW1pY3JvYmlhbCBlY29sb2d5LS0td2Ugb2Z0ZW4gcmVseSBvbiBjb2xvciB0byBkaXNwbGF5IGluZm9ybWF0aW9uIGFib3V0IGRpdmVyc2l0eS4gTWljcm9iaWFsIGRpdmVyc2l0eSBpcyBwcmV0dHkgdmFzdCwgYW5kIGl0IGNhbiBiZSBkaWZmaWN1bHQgdG8gZGlzcGxheSBhbGwgb2YgdGhpcyBkaXZlcnNpdHkgaW4gYSBzaW5nbGUsIHN0YXRpYyBmaWd1cmUuIEFsbCB0b28gb2Z0ZW4sIHBlb3BsZSBtaXN1c2UgY29sb3IgYW5kIHRoZSBsaXRlcmF0dXJlIGlzIGZ1bGwgb2YgZmlndXJlcyB0aGF0IGFyZSB2ZXJ5IGRpZmZpY3VsdCB0byBpbnRlcnByZXQuIEkgdGhvdWdodCBhYm91dCBzaG93aW5nIHlvdSBzb21lIGFjdHVhbCBleGFtcGxlcyBidXQgZmVsdCB0aGF0IGl0IHdvdWxkIGJlIGEgbGl0dGxlIG1lYW4tc3Bpcml0ZWQuIEluc3RlYWQsIEkgbWFkZSBhIGZpZ3VyZSB1c2luZyBteSBvd24gZGF0YSB0byBkZW1vbnN0cmF0ZSB0aGlzIHBvaW50LiAKCkhlcmUsIGVhY2ggYmFyIHJlcHJlc2VudHMgYSBkaWZmZXJlbnQgc2FtcGxlIGFuZCBlYWNoIGNvbG9yIGEgZGlmZmVyZW50IG1pY3JvYmlhbCBDbGFzcy4KCmBgYHtyIGJhZF9jb2xvciwgb3V0LndpZHRoPSI3MCUiLCBlY2hvPUZBTFNFLCBmaWcuY2FwPSI8c21hbGw+KkV4YW1wbGUgb2YgKipjb2xvciBhcyBhbiBlbmVteSoqLiBUaGlzIGZpZ3VyZSBoYXMgd2F5IHRvbyBtYW55IGNvbG9ycyB0byBjb252ZXkgYSBjbGVhciBtZXNzYWdlLiBVbmZvcnR1bmF0ZWx5LCBmaWd1cmVzIGxpa2UgdGhpcyBhcmUgY29tbW9uIGluIHRoZSBsaXRlcmF0dXJlKi4gPC9zbWFsbD4ifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiZmlsZXMvYmFkLWNvbG9yLnBuZyIpCmBgYAoKV2hlbiB5b3UgdXNlIHRvbyBtYW55IGNvbG9ycyB5b3UgZm9yY2UgeW91ciByZWFkZXIgdG8gY29udGludWFsbHkgZ28gYmFjayBhbmQgZm9ydGggZnJvbSB0aGUgY2hhcnQgdG8gdGhlIGxlZ2VuZC4gVGhpcyBpcyBhbm5veWluZywgY29uZnVzaW5nLCBhbmQgdWx0aW1hdGVseSBkZXRyYWN0cyBmcm9tIHRoZSBtZWFuaW5nIG9mIHRoZSBmaWd1cmUuIAoKQW5vdGhlciBwcm9ibGVtIGlzIHRoYXQgbWFueSBvZiB1cyBoYXZlIGRpZmZlcmVudCBhYmlsaXRpZXMgdG8gcGVyY2VpdmUgY29sb3IgYW5kL29yIGRpZmZlcmVuY2VzIGluIGNvbG9yLiBbQ29sb3IgYmxpbmRuZXNzXShodHRwOi8vbWt3ZWIuYmNnc2MuY2EvY29sb3JibGluZC9pbmRleC5taHRtbCNwYWdlLWNvbnRhaW5lciksIGFsc28ga25vd24gYXMgY29sb3IgdmlzaW9uIGRlZmljaWVuY3ksIGlzIGEgZGVjcmVhc2VkIGFiaWxpdHkgdG8gc2VlIGNvbG9yIG9yIGRpZmZlcmVuY2VzIGluIGNvbG9yLiBXaGVuIGRlc2lnbmluZyBmaWd1cmVzLCBpdCBpcyBpbXBvcnRhbnQgdG8gdXNlICoqYSoqKSBhIHJlbGF0aXZlbHkgc21hbGwgY29sb3IgcGFsZXR0ZSBhbmQgKipiKiopIGEgcGFsZXR0ZSB0aGF0IGlzIGZyaWVuZGx5IHRvIGEgdmFyaWV0eSBvZiBwZW9wbGUuIAoKRm9yIG1vcmUgaW5mb3JtYXRpb24gb24gdGhlIHRvcGljLCBJIHJlY29tbWVuZCByZWFkaW5nIEJhbmcgV29uZ+KAmXMgTmF0dXJlIE1ldGhvZHMgcGFwZXIsIFtQb2ludHMgb2YgdmlldzogQ29sb3IgYmxpbmRuZXNzXShodHRwOi8vZHguZG9pLm9yZy8xMC4xMDM4L25tZXRoLjE2MTgpLiBXb25nIHByb3Bvc2VzIGEgY29sb3ItYmxpbmQgZnJpZW5kbHkgY29sb3IgcGFsZXR0ZSB0aGF0IHVzZXMgY29udHJhc3RpbmcgY29sb3JzIHRoYXQgY2FuIGJlIGRpc3Rpbmd1aXNoZWQgYnkgYSByYW5nZSBvZiBwZW9wbGUuIENvbnNpZGVyIHRoYXQgcm91Z2hseSA4JSBvZiBwZW9wbGUgKG1vc3RseSBtYWxlcykgYXJlIGNvbG9yIGJsaW5kLiBTbywgd2hhdCBkbyB5b3UgdGhpbms/IERvIHlvdSB3YW50IEtlYW51IFJlZXZlcyB0byB1bmRlcnN0YW5kIHlvdXIgZmlndXJlcyBvciBub3Q/IElmIHNvLCBjb25zaWRlciBhIGNvbG9yIHNjaGVtZSB0aGF0IGlzIGZyaWVuZGx5IHRvIGFsbCB2aXNpb24gdHlwZXMKCldvbmfigJlzIHNjaGVtZSBpcyBjb25zZXJ2YXRpdmUtLS10aGVyZSBhcmUgb25seSA4IGNvbG9ycy4gT3RoZXJzIGhhdmUgZGV2ZWxvcGVkIFsxMiwxMywgYW5kIDE1IGNvbG9yIHBhbGV0dGUgc2NoZW1lc10oaHR0cDovL21rd2ViLmJjZ3NjLmNhL2NvbG9yYmxpbmQvcGFsZXR0ZXMubWh0bWwjcGFnZS1jb250YWluZXIpIHRoYXQgb2ZmZXIgbW9yZSBvcHRpb25zIHRoYW4gV29uZydzIHBhbGV0dGUuIEp1c3QgYmUgY2FyZWZ1bOKAlC0tZmlndXJlcyB3aXRoIHRvbyBtYW55IGNvbG9ycyBjYW4gaW5oaWJpdCBvdXIgYWJpbGl0eSB0byBkaXNjZXJuIHBhdHRlcm5zLiAKCkxpbWl0ZWQgY29sb3IgcGFsZXR0ZXMgbGlrZSB0aGVzZSBmb3JjZSB1cyB0byBiZSBtb3JlIGNhcmVmdWwgd2hlbiBkZWNpZGluZyB3aGF0IGluZm9ybWF0aW9uIHRvIHRhcmdldCBvciBob3cgbWFueSBncm91cHMgdG8gZGlzcGxheS4gRm9yIHlvdXIgY29uc2lkZXJhdGlvbiwgSSBoYXZlIGluY2x1ZGVkIGEgZmV3IGNvbG9yLWJsaW5kIGZyaWVuZGx5IGNvbG9yIHBhbGV0dGVzLiBZb3UgY2FuIGRvd25sb2FkIHRoZXNlIGNvbG9ycyBhcyBwbGFpbiB0ZXh0IGJ5IGNsaWNraW5nIG9uIHRoZSBwYWxldHRlIHRpdGxlLiAKCmBgYHtyIGNvbG9yXzhfdGFiLCBlY2hvPUZBTFNFfQp0ZXh0X3RibCA8LSBkYXRhLmZyYW1lKAogIENvbG9yID0gYygiX19fX19fXyIsICJfX19fX19fIiwgIl9fX19fX18iLCAKICAgICAgICAgICAgIl9fX19fX18iLCAiX19fX19fXyIsICJfX19fX19fIiwgCiAgICAgICAgICAgICJfX19fX19fIiwgIl9fX19fX18iKSwKICBOYW1lID0gYygiYmxhY2siLCAiYmx1ZSIsICJza3kgYmx1ZSIsICJyZWRkaXNoIHB1cnBsZSIsIAogICAgICAgICAgICJibHVpc2ggZ3JlZW4iLCAidmVybWlsbGlvbiIsICJvcmFuZ2UiLCAieWVsbG93IiksCiAgSEVYID0gYygiIzAwMDAwMCIsICIjMDA3MkIyIiwgIiM1NkI0RTkiLCAiI0NDNzlBNyIsIAogICAgICAgICAgICAgICIjMDA5RTczIiwgIiNENTVFMDAiLCAiI0U2OUYwMCIsICIjRjBFNDQyIiksCiAgUkdCID0gYygiMCwgMCwgMCIsICIwLCAxMTQsIDE3OCIsICI4NiwgMTgwLCAyMzMiLCAKICAgICAgICAgICAgICAgIjIwNCwgMTIxLCAxNjciLCAiMCwgMTU4LCAxMTUiLCAiMjEzLCA5NCwgMCIsIAogICAgICAgICAgICAgICAiMjMwLCAxNTksIDAiLCAiMjQwLCAyMjgsIDY2IikKKQoKdGV4dF90YmwkQ29sb3IgPC0gY2VsbF9zcGVjKHRleHRfdGJsJENvbG9yLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvcm1hdCA9ICJodG1sIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kID0gYygiIzAwMDAwMCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIiMwMDcyQjIiLCAiIzU2QjRFOSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIiNDQzc5QTciLCAiIzAwOUU3MyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIiNENTVFMDAiLCAiI0U2OUYwMCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIiNGMEU0NDIiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kX2FzX3RpbGUgPSBUUlVFLCBmb250X3NpemUgPSAyMCkKCmthYmxlKHRleHRfdGJsLCBlc2NhcGUgPSBGQUxTRSwgY2FwdGlvbiA9ICJbQ09OU0VSVkFUSVZFIDgtQ09MT1IgUEFMRVRURV0oY29sb3IvOC1jb2xvci1wYWwudHh0KSIpICU+JQogIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJib3JkZXJlZCIsICJjb25kZW5zZWQiKSwgCiAgICAgICAgICAgICAgICBmdWxsX3dpZHRoID0gRiwgcG9zaXRpb24gPSAiZmxvYXRfbGVmdCIsIGZvbnRfc2l6ZSA9IDE0KSAlPiUKICBjb2x1bW5fc3BlYygxLCB3aWR0aCA9ICI2ZW0iLCBib3JkZXJfcmlnaHQgPSBUKSAlPiUKICBjb2x1bW5fc3BlYygyLCBib2xkID0gVCwgYm9yZGVyX3JpZ2h0ID0gVCwgYm9yZGVyX2xlZnQgPSBUKSAlPiUKICBjb2x1bW5fc3BlYygzLCBib2xkID0gVCwgYm9yZGVyX3JpZ2h0ID0gVCkgJT4lCiAgY29sdW1uX3NwZWMoNCwgYm9sZCA9IFQsIGJvcmRlcl9yaWdodCA9IFQpCmBgYAoKCmBgYHtyIGNvbG9yXzEyX3RhYiwgZWNobz1GQUxTRX0KdGV4dF90YmwgPC0gZGF0YS5mcmFtZSgKICBDb2xvciA9IGMoIl9fX19fX18iLCAiX19fX19fXyIsICJfX19fX19fIiwgCiAgICAgICAgICAgICJfX19fX19fIiwgIl9fX19fX18iLCAiX19fX19fXyIsIAogICAgICAgICAgICAiX19fX19fXyIsICJfX19fX19fIiwgIl9fX19fX18iLCAKICAgICAgICAgICAgIl9fX19fX18iLCAiX19fX19fXyIsICJfX19fX19fIiksCiAgTmFtZSA9IGMoImRhcmsgZ3JleSIsICJqYXp6YmVycnkgamFtIiwgImtlcGVsIiwgCiAgICAgICAgICAgImxpZ2h0IGdyZXkiLCAic2VhbmNlIiwgIm1hcmluZXIiLCAiY2FwcmkiLCAKICAgICAgICAgICAicGFsZSBwbHVtIiwgInNhZGRsZSBicm93biIsICJtYXJzIHllbGxvdyIsIAogICAgICAgICAgICJmdWVnbyIsICJwYXJpcyBkYWlzeSIpLAogIEhFWCA9IGMoIiMzMjMyMzIiLCAiI0JGMzQ2NSIsICIjNTBCMjlFIiwgCiAgICAgICAgICAgICAgIiNEOUQ5RDkiLCAiIzczMTY4MyIsICIjMUM2Q0NDIiwgCiAgICAgICAgICAgICAgIiMyMUJDRkYiLCAiI0RGQTVFNSIsICIjODc0MzEwIiwgCiAgICAgICAgICAgICAgIiNEQjZEMUIiLCAiI0I4Q0UxNyIsICIjRjRFMzQ1IiksCiAgUkdCID0gYygiNTAsIDUwLCA1MCIsICIxOTEsIDUyLCAxMDEiLCAiODAsIDE3OCwgMTU4IiwgCiAgICAgICAgICAgICAgICIyMTcsIDIxNywgMjE3IiwgIjExNSwgMjIsIDEzMSIsICIyOCwgMTA4LCAyMDQiLCAKICAgICAgICAgICAgICAgIjMzLCAxODgsIDI1NSIsICIyMjMsIDE2NSwgMjI5IiwgIjEzNSwgNjcsIDE2IiwgCiAgICAgICAgICAgICAgICIyMTksIDEwOSwgMjciLCAiMTg0LCAyMDYsIDIzIiwgIjI0NCwgMjI3LCA2OSIpCikKCnRleHRfdGJsJENvbG9yIDwtIGNlbGxfc3BlYyh0ZXh0X3RibCRDb2xvciwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb3JtYXQgPSAiaHRtbCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFja2dyb3VuZCA9IGMoIiMzMjMyMzIiLCAiI0JGMzQ2NSIsICIjNTBCMjlFIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIjRDlEOUQ5IiwgIiM3MzE2ODMiLCAiIzFDNkNDQyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiIzIxQkNGRiIsICIjREZBNUU1IiwgIiM4NzQzMTAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIiNEQjZEMUIiLCAiI0I4Q0UxNyIsICIjRjRFMzQ1IiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kX2FzX3RpbGUgPSBUUlVFLCBmb250X3NpemUgPSAyMCkKCmthYmxlKHRleHRfdGJsLCBlc2NhcGUgPSBGQUxTRSwgY2FwdGlvbiA9ICJbMTItQ09MT1IgUEFMRVRURV0oY29sb3IvMTItY29sb3ItcGFsLnR4dCkiKSAlPiUKICBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gYygiYm9yZGVyZWQiLCAiY29uZGVuc2VkIiksIAogICAgICAgICAgICAgICAgZnVsbF93aWR0aCA9IEYsIHBvc2l0aW9uID0gInJpZ2h0IiwgZm9udF9zaXplID0gMTMpICU+JQogIGNvbHVtbl9zcGVjKDEsIHdpZHRoID0gIjZlbSIsIGJvcmRlcl9yaWdodCA9IFQpICU+JQogIGNvbHVtbl9zcGVjKDIsIGJvbGQgPSBULCBib3JkZXJfcmlnaHQgPSBULCBib3JkZXJfbGVmdCA9IFQpICU+JQogIGNvbHVtbl9zcGVjKDMsIGJvbGQgPSBULCBib3JkZXJfcmlnaHQgPSBUKSAlPiUKICBjb2x1bW5fc3BlYyg0LCBib2xkID0gVCwgYm9yZGVyX3JpZ2h0ID0gVCkKYGBgCgoKYGBge3IgY29sb3JfMTNfdGFiLCBlY2hvPUZBTFNFfQp0ZXh0X3RibCA8LSBkYXRhLmZyYW1lKAogIENvbG9yID0gYygiX19fX19fXyIsICJfX19fX19fIiwgIl9fX19fX18iLCAKICAgICAgICAgICAgIl9fX19fX18iLCAiX19fX19fXyIsICJfX19fX19fIiwgCiAgICAgICAgICAgICJfX19fX19fIiwgIl9fX19fX18iLCAiX19fX19fXyIsIAogICAgICAgICAgICAiX19fX19fXyIsICJfX19fX19fIiwgIl9fX19fX18iLCAKICAgICAgICAgICAgIl9fX19fX18iKSwKICBOYW1lID0gYygiYmxhY2siLCAiYmx1ZSBsYWdvb24iLCAic2VhbmNlIiwgCiAgICAgICAgICAgInNjaWVuY2UgYmx1ZSIsICJhenVyZSByYWRpYW5jZSIsICJibHVzaCBwaW5rIiwgCiAgICAgICAgICAgImJyaWdodCB0dXJxdW9pc2UiLCAic2hpcmF6IiwgInNhbGVtIiwgCiAgICAgICAgICAgInNhbG1vbiIsICJyb25jaGkiLCAibWludCBncmVlbiIsIAogICAgICAgICAgICJkYWlyeSBjcmVhbSIpLAogIEhFWCA9IGMoIiMwMDAwMDAiLCAiIzAwNkU4MiIsICIjODIxNEEwIiwgCiAgICAgICAgICAgICAgIiMwMDVBQzgiLCAiIzAwQTBGQSIsICIjRkE3OEZBIiwgCiAgICAgICAgICAgICAgIiMxNEQyREMiLCAiI0FBMEEzQyIsICIjMEE5QjRCIiwgCiAgICAgICAgICAgICAgIiNGRjgyNUYiLCAiI0VBRDY0NCIsICIjQTBGQTgyIiwgCiAgICAgICAgICAgICAgIiNGQUU2QkUiKSwKICBSR0IgPSBjKCIwLCAwLCAwIiwgIjAsIDExMCwgMTMwIiwgIjEzMCwgMjAsIDE2MCIsIAogICAgICAgICAgICAgICAiMCwgOTAsIDIwMCIsICIwLCAxNjAsIDI1MCIsICIyNTAsIDEyMCwgMjUwIiwgCiAgICAgICAgICAgICAgICIyMCwgMjEwLCAyMjAiLCAiMTcwLCAxMCwgNjAiLCAiMTAsIDE1NSwgNzUiLCAKICAgICAgICAgICAgICAgIjI1NSwgMTMwLCA5NSIsICIyMzQsIDIxNCwgNjgiLCAiMTYwLCAyNTAsIDEzMCIsIAogICAgICAgICAgICAgICAiMjUwLCAyMzAsIDE5MCIpCikKdGV4dF90YmwkQ29sb3IgPC0gY2VsbF9zcGVjKHRleHRfdGJsJENvbG9yLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvcm1hdCA9ICJodG1sIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kID0gYygiIzAwMDAwMCIsICIjMDA2RTgyIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiIzgyMTRBMCIsICIjMDA1QUM4IiwgIiMwMEEwRkEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIiNGQTc4RkEiLCAiIzE0RDJEQyIsICIjQUEwQTNDIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIjMEE5QjRCIiwgIiNGRjgyNUYiLCAiI0VBRDY0NCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiI0EwRkE4MiIsICIjRkFFNkJFIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYWNrZ3JvdW5kX2FzX3RpbGUgPSBUUlVFLCBmb250X3NpemUgPSAyMCkKCmthYmxlKHRleHRfdGJsLCBlc2NhcGUgPSBGQUxTRSwgY2FwdGlvbiA9ICJbMTMtQ09MT1IgUEFMRVRURV0oY29sb3IvMTMtY29sb3ItcGFsLnR4dCkiKSAlPiUKICBrYWJsZV9zdHlsaW5nKGJvb3RzdHJhcF9vcHRpb25zID0gYygiYm9yZGVyZWQiLCAiY29uZGVuc2VkIiksIAogICAgICAgICAgICAgICAgZnVsbF93aWR0aCA9IEYsIHBvc2l0aW9uID0gImZsb2F0X2xlZnQiLCBmb250X3NpemUgPSAxMykgJT4lCiAgY29sdW1uX3NwZWMoMSwgd2lkdGggPSAiNmVtIiwgYm9yZGVyX3JpZ2h0ID0gVCkgJT4lCiAgY29sdW1uX3NwZWMoMiwgYm9sZCA9IFQsIGJvcmRlcl9yaWdodCA9IFQsIGJvcmRlcl9sZWZ0ID0gVCkgJT4lCiAgY29sdW1uX3NwZWMoMywgYm9sZCA9IFQsIGJvcmRlcl9yaWdodCA9IFQpICU+JQogIGNvbHVtbl9zcGVjKDQsIGJvbGQgPSBULCBib3JkZXJfcmlnaHQgPSBUKQpgYGAKCmBgYHtyIGNvbG9yXzE1X3RhYiwgZWNobz1GQUxTRX0KdGV4dF90YmwgPC0gZGF0YS5mcmFtZSgKICBDb2xvciA9IGMoIl9fX19fX18iLCAiX19fX19fXyIsICJfX19fX19fIiwgCiAgICAgICAgICAgICJfX19fX19fIiwgIl9fX19fX18iLCAiX19fX19fXyIsIAogICAgICAgICAgICAiX19fX19fXyIsICJfX19fX19fIiwgIl9fX19fX18iLCAKICAgICAgICAgICAgIl9fX19fX18iLCAiX19fX19fXyIsICJfX19fX19fIiwKICAgICAgICAgICAgIl9fX19fX18iLCAiX19fX19fXyIsICJfX19fX19fIiksCiAgTmFtZSA9IGMoImJsYWNrIiwgInNoZXJwYSBibHVlIiwgInBlcnNpYW4gZ3JlZW4iLCAKICAgICAgICAgICAiaG90IHBpbmsiLCAiY290dG9uIGNhbmR5IiwgInBpZ21lbnQgaW5kaWdvIiwgCiAgICAgICAgICAgInNjaWVuY2UgYmx1ZSIsICJoZWxpb3Ryb3BlIiwgIm1hbGlidSIsIAogICAgICAgICAgICJmcmVuY2ggcGFzcyIsICJyZWQgYmVycnkiLCAiYnJvd24iLCAKICAgICAgICAgICAibWFuZ28gdGFuZ28iLCAiaGFybGVxdWluIiwgImxhc2VyIGxlbW9uIiksCiAgSEVYID0gYygiIzAwMDAwMCIsICIjMDA0OTQ5IiwgIiMwMDkyOTIiLCAKICAgICAgICAgICAgICAiI2ZmNmRiNiIsICIjZmZiNmRiIiwgIiM0OTAwOTIiLCAKICAgICAgICAgICAgICAiIzAwNmRkYiIsICIjYjY2ZGZmIiwgIiM2ZGI2ZmYiLCAKICAgICAgICAgICAgICAiI2I2ZGJmZiIsICIjOTIwMDAwIiwgIiM5MjQ5MDAiLCAKICAgICAgICAgICAgICAiI2RiNmQwMCIsICIjMjRmZjI0IiwgIiNmZmZmNmQiKSwKICBSR0IgPSBjKCIwLCAwLCAwIiwgIjAgNzMgNzMiLCAiMCAxNDYgMTQ2IiwgCiAgICAgICAgICAgICAgICIyNTUsIDEwOSwgMTgyIiwgIjI1NSwgMTgyLCAyMTkiLCAiNzMgMCAxNDYiLCAKICAgICAgICAgICAgICAgIjAsIDEwOSwgMjE5IiwgIjE4MiAxMDkgMjU1IiwgIjEwOSwgMTgyLCAyNTUiLCAKICAgICAgICAgICAgICAgIjE4MiAyMTYgMjU1IiwgIjE0NiwgMCwgMCIsICIxNDYgNzMgMCIsIAogICAgICAgICAgICAgICAiMjE5LCAxMDksIDAiLCAiMzYsIDI1NSwgMzYiLCAiMjU1LCAyNTUsIDEwOSIpCikKCnRleHRfdGJsJENvbG9yIDwtIGNlbGxfc3BlYyh0ZXh0X3RibCRDb2xvciwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb3JtYXQgPSAiaHRtbCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgYmFja2dyb3VuZCA9IGMoIiMwMDAwMDAiLCAiIzAwNDk0OSIsICIjMDA5MjkyIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiI2ZmNmRiNiIsICIjZmZiNmRiIiwgIiM0OTAwOTIiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIjMDA2ZGRiIiwgIiNiNjZkZmYiLCAiIzZkYjZmZiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIiNiNmRiZmYiLCAiIzkyMDAwMCIsICIjOTI0OTAwIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiI2RiNmQwMCIsICIjMjRmZjI0IiwgIiNmZmZmNmQiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJhY2tncm91bmRfYXNfdGlsZSA9IFRSVUUsIGZvbnRfc2l6ZSA9IDIwKQoKa2FibGUodGV4dF90YmwsIGVzY2FwZSA9IEZBTFNFLCBjYXB0aW9uID0gIlsxNS1DT0xPUiBQQUxFVFRFXShjb2xvci8xNS1jb2xvci1wYWwudHh0KSIpICU+JQogIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJib3JkZXJlZCIsICJjb25kZW5zZWQiKSwgCiAgICAgICAgICAgICAgICBmdWxsX3dpZHRoID0gRiwgcG9zaXRpb24gPSAicmlnaHQiLCBmb250X3NpemUgPSAxMikgJT4lCiAgY29sdW1uX3NwZWMoMSwgd2lkdGggPSAiNmVtIiwgYm9yZGVyX3JpZ2h0ID0gVCkgJT4lCiAgY29sdW1uX3NwZWMoMiwgYm9sZCA9IFQsIGJvcmRlcl9yaWdodCA9IFQsIGJvcmRlcl9sZWZ0ID0gVCkgJT4lCiAgY29sdW1uX3NwZWMoMywgYm9sZCA9IFQsIGJvcmRlcl9yaWdodCA9IFQpICU+JQogIGNvbHVtbl9zcGVjKDQsIGJvbGQgPSBULCBib3JkZXJfcmlnaHQgPSBUKQpgYGAKCklmIHlvdSB3YW50IHRvIGNyZWF0ZSB5b3VyIG93biBjb2xvciBwYWxldHRlIChzYXkgYmFzZWQgb24gV29uZydzIGNvbG9ycykgeW91IHdvdWxkIHdyaXRlIHRoZSBjb2RlIGxpa2UgdGhpcy4gVGhlbiB5b3UgY291bGQgcGFzcyB0aGUgY2hhcmFjdGVyIHN0cmluZyBgd29uZ19wYWxgIHRvIGFueSBwbGFjZSB5b3UgbmVlZCBhIGNvbG9yIHBhbGV0dGUuCgpgYGB7ciBtYWtlX2NvbG9yX3BhbH0Kd29uZ19wYWwgPC0gYygiIzAwOUU3MyIsICIjRDU1RTAwIiwgIiNGMEU0NDIiLAogICAgICAgICAgICAgICAgIiNDQzc5QTciLCAiIzU2QjRFOSIsICIjRTY5RjAwIiwKICAgICAgICAgICAgICAgICIjMDA3MkIyIiwgIiM3RjdGN0YiLCAiIzAwMDAwMCIpCgpgYGAKCkhlcmUgaXMgYW5vdGhlciBncmVhdCBhcnRpY2xlIG9uIFtDb2xvcmluZyBmb3IgQ29sb3JibGluZG5lc3NdKGh0dHBzOi8vZGF2aWRtYXRobG9naWMuY29tL2NvbG9yYmxpbmQvIyUyMzAwMDAwMC0lMjNFNjlGMDAtJTIzNTZCNEU5LSUyMzAwOUU3My0lMjNGMEU0NDItJTIzMDA3MkIyLSUyM0Q1NUUwMC0lMjNDQzc5QTcpIGJ5IERhdmlkIE5pY2hvbHMgdGhhdCBoYXMgYW4gaW50ZXJhY3RpdmUgY29sb3IgcGlja2VyIGFuZCByZWNvbW1lbmRhdGlvbnMgZm9yIGFjY2Vzc2libGUgcGFsZXR0ZXMuIAoKUmVtZW1iZXIsIHRoZXNlIGFyZSAqb25seSBzdWdnZXN0aW9ucyouIFVsdGltYXRlbHksIGl0IGlzIHlvdXIgY2hvaWNlIGhvdyB0byB1c2UgY29sb3IgYW5kIHdoYXQgcGFsZXR0ZXMgd29yayBiZXN0IGZvciB5b3UgbmVlZHMsIEkgYW0gbWVyZWx5IG9mZmVyaW5nIHNvbWUgZm9vZCBmb3IgdGhvdWdodC4gQWdhaW4sIGNvbG9yIGFuZCBmaWd1cmUgZGVzaWduIGFyZSB2ZXJ5IGJyb2FkLS0tSSBlbmNvdXJhZ2UgeW91IHRvIHNwZW5kIHNvbWUgdGltZSBleHBsb3JpbmcgdGhlc2UgdG9waWNzIGluIG1vcmUgZGVwdGggd2l0aCB0aGUgcmVmZXJlbmNlIEkgcHJvdmlkZWQuIFNlZSB3aGVyZSBpdCB0YWtlcyB5b3UuICAKCmBgYHtyIGNvbG9yXzEyMSwgZmlnLmhlaWdodD02LCBvdXQud2lkdGggPSAnNjAlJywgZmlnLmFsaWduPSdjZW50ZXInLCBjb21tZW50PScnLCBmaWcuc2hvdz0naG9sZCcsIGV2YWw9RkFMU0UsIGVjaG89RkFMU0V9CiMgV29uZyBwYWxldHRlCndvbmdfcGFsIDwtIGMoIiMwMDlFNzMiLCAiI0Q1NUUwMCIsICIjRjBFNDQyIiwKICAgICAgICAgICAgICAgICIjQ0M3OUE3IiwgIiM1NkI0RTkiLCAiI0U2OUYwMCIsCiAgICAgICAgICAgICAgICAiIzAwNzJCMiIsICIjN0Y3RjdGIiwgIiMwMDAwMDAiKQojc2hvd19jb2wod29uZ19wYWwpCgp0d2VsdmVfcGFsIDwtIGMoIiMzMjMyMzIiLCAiI0JGMzQ2NSIsICIjNTBCMjlFIiwgCiAgICAgICAgICAgICAgICAiI0Q5RDlEOSIsICIjNzMxNjgzIiwgIiMxQzZDQ0MiLCAKICAgICAgICAgICAgICAgICIjMjFCQ0ZGIiwgIiNERkE1RTUiLCAiIzg3NDMxMCIsIAogICAgICAgICAgICAgICAgIiNEQjZEMUIiLCAiI0I4Q0UxNyIsICIjRjRFMzQ1IikKI3Nob3dfY29sKHR3ZWx2ZV9wYWwpCgp0aGlydGVlbl9wYWwgPC0gYygiIzAwMDAwMCIsICIjMDA2RTgyIiwgIiM4MjE0QTAiLCAKICAgICAgICAgICAgICAgICAgIiMwMDVBQzgiLCAiIzAwQTBGQSIsICIjRkE3OEZBIiwgCiAgICAgICAgICAgICAgICAgICIjMTREMkRDIiwgIiNBQTBBM0MiLCAiIzBBOUI0QiIsIAogICAgICAgICAgICAgICAgICAiI0ZGODI1RiIsICIjRUFENjQ0IiwgIiNBMEZBODIiLCAKICAgICAgICAgICAgICAgICAgIiNGQUU2QkUiKQojc2hvd19jb2wodGhpcnRlZW5fcGFsKQoKZmlmdGVlbl9wYWwgPC0gYygiIzAwMDAwMCIsICIjMDA0OTQ5IiwgIiMwMDkyOTIiLCAKICAgICAgICAgICAgICAiI2ZmNmRiNiIsICIjZmZiNmRiIiwgIiM0OTAwOTIiLCAKICAgICAgICAgICAgICAiIzAwNmRkYiIsICIjYjY2ZGZmIiwgIiM2ZGI2ZmYiLCAKICAgICAgICAgICAgICAiI2I2ZGJmZiIsICIjOTIwMDAwIiwgIiM5MjQ5MDAiLCAKICAgICAgICAgICAgICAiI2RiNmQwMCIsICIjMjRmZjI0IiwgIiNmZmZmNmQiKQpzaG93X2NvbChmaWZ0ZWVuX3BhbCkKYGBgCgo8YnIvPgoKIyMjIyA0LiBDb250cm9sbGluZyB0aGUgb3V0cHV0CgpUaGUgbGFzdCB0aGluZyB3ZSBuZWVkIHRvIGRpc2N1c3MgaXMgaG93IHRvIGNvbnRyb2wgdGhlIHdheSB5b3VyIHBsb3QgaXMgcmVuZGVyZWQgaW4gdGhlIGZpbmFsIGRvY3VtZW50LiBJbmRpdmlkdWFsIFIgcGFja2FnZXMgaGF2ZSBkaWZmZXJlbnQgb3B0aW9ucyBmb3IgY29udHJvbGxpbmcgdmFyaW91cyBhc3BlY3RzIG9mIGEgcGxvdCBvciBjaGFydCBpbmNsdWRpbmcgY29sb3IsIHBvaW50IHNpemUsIGxpbmUgdGhpY2tuZXNzLCBheGlzIGxhYmVscywgZXRjLiBBZ2FpbiwgdGhpcyB0b3BpYyBpcyBiZXlvbmQgdGhlIHNjb3BlIG9mIHRoaXMgbGVzc29uIGJ1dCBsZXQncyBsb29rIGF0IGFuIGV4YW1wbGUgYW55d2F5LiBXZSByZXR1cm4gdG8gb3VyIHNpbXBsZSBleGFtcGxlIGZyb20gYWJvdmUgdXNpbmcgdGhlIGBwbG90YCBmdW5jdGlvbiB3aXRoIHRoZSBgY2Fyc2AgZGF0YSBzZXQuIFdlIGNhbiB1c2UgZGlmZmVyZW50IGJ1aWx0LWluIG9wdGlvbnMgdG8gbW9kaWZ5IHRoZSBjaGFydCAoKmNvbG9yIGFkZGVkIGZvciBkZW1vbnN0cmF0aW9uIHB1cnBvc2VzIG9ubHkqKS4gCgpgYGB7ciBvdXRfMX0KcGxvdChjYXJzLCBtYWluID0gIlBsb3QgVGl0bGUiLCAKICAgICBzdWIgPSAiVGhpcyBpcyB0aGUgcGxvdCBzdWJ0aXRsZSIsIAogICAgIHhsYWIgPSAidGVtcGVyYXR1cmUgKEMpIiwgCiAgICAgeWxhYiA9ICJwcmVzc3VyZSAoUGEpIiwgCiAgICAgcGNoID0gMjQsIGNleD0xLjUsIGNvbD0icmVkIiwgYmc9ImJsdWUiLCBsd2Q9MikKYGBgCgpUaGlzIGNvZGUgY29udHJvbHMgdGhlIHBsb3QgKnN0eWxlKiBidXQgbm90IGhvdyB0aGUgcGxvdCBpcyByZW5kZXJlZCBpbiB0aGUgZmluYWwgZG9jdW1lbnQuIEJ5IHRoYXQgSSBtZWFuIHRoZSAqc2l6ZSogYW5kICphbGlnbm1lbnQqIG9mIHRoZSBwbG90IGluIHRoZSBIVE1MIGRvY3VtZW50LiBUbyBjb250cm9sIHRoZXNlIGFzcGVjdHMsIHlvdSB3aWxsIG5lZWQgdG8gdXNlIHZhcmlvdXMgKioqW2NvZGUgY2h1bmsgb3B0aW9uc10oaHR0cHM6Ly95aWh1aS5vcmcva25pdHIvb3B0aW9ucy8jcGxvdHMpKioqLiBLbm93aW5nIGhvdyB0byBjb2RlIGVhY2ggY2h1bmsgb3B0aW9uIGFuZCBrbm93aW5nIHdoYXQgZWFjaCBkb2VzIHRha2VzIHNvbWUgcHJhY3RpY2UuIExldCdzIGxvb2sgYXQgYSBmZXcgb2YgdGhlIG1vc3QgY29tbW9uIG9wdGlvbnMuCgoqIGBmaWcuYWxpZ25gOiAoJ2NoYXJhY3RlcicpIEFsaWdubWVudCBvZiBmaWd1cmVzIGluIHRoZSBvdXRwdXQgZG9jdW1lbnQgKHBvc3NpYmxlIHZhbHVlcyBhcmUgYGxlZnRgLCBgcmlnaHRgIGFuZCBgY2VudGVyYC4gKk5vdGUqLCBjaGFyYWN0ZXIgdmFsdWVzIG11c3QgYmUgZW5jbG9zZWQgaW4gKipzaW5nbGUgcXVvdGF0aW9uKiogbWFya3MgbGlrZSBzbzogYCdjZW50ZXInYC4KKiBgZmlnLndpZHRoYCBhbmQgYGZpZy5oZWlnaHRgOiAoZGVmYXVsdCBhcmUgNyBhbmQgNSwgcmVzcGVjdGl2ZWx5OyBudW1lcmljKSBXaWR0aCBhbmQgaGVpZ2h0IG9mIHRoZSBwbG90IChpbiBpbmNoZXMpLiAqTm90ZSogT25seSB3b3JrcyB3aXRoIFItZ2VuZXJhdGVkIGZpZ3VyZXMuCiogYGZpZy5hc3BgOiAoZGVmYXVsdCBOVUxMOyBudW1lcmljKSBUaGUgYXNwZWN0IHJhdGlvIG9mIHRoZSBwbG90LCBpLmUuIHRoZSByYXRpbyBvZiBoZWlnaHQvd2lkdGg7IHdoZW4gYGZpZy5hc3BgIGlzIHNwZWNpZmllZCwgdGhlIGhlaWdodCBvZiBhIHBsb3QgKHRoZSBjaHVuayBvcHRpb24gYGZpZy5oZWlnaHRgKSBpcyBjYWxjdWxhdGVkIGZyb20gYGZpZy53aWR0aGAgWCBgZmlnLmFzcGAKKiBgZmlnLmRpbWA6IChkZWZhdWx0IE5VTEw7IG51bWVyaWMpIE51bWVyaWMgdmVjdG9yIG9mIGxlbmd0aCAyLCBpdCBnaXZlcyBgZmlnLndpZHRoYCBhbmQgYGZpZy5oZWlnaHRgLCBlLmcuLCBgZmlnLmRpbWAgPSBjKDUsIDcpIGlzIGEgc2hvcnRoYW5kIG9mIGBmaWcud2lkdGhgID0gNSwgYGZpZy5oZWlnaHRgID0gNzsgaWYgYm90aCBgZmlnLmFzcGAgYW5kIGBmaWcuZGltYCBhcmUgcHJvdmlkZWQsIGBmaWcuYXNwYCB3aWxsIGJlIGlnbm9yZWQgKHdpdGggYSB3YXJuaW5nKQoqIGBvdXQud2lkdGhgLCBgb3V0LmhlaWdodGA6IChOVUxMOyBjaGFyYWN0ZXIgT1IgbnVtZXJpYykgV2lkdGggYW5kIGhlaWdodCBvZiB0aGUgcGxvdCBpbiB0aGUgZmluYWwgb3V0cHV0IGZpbGUgKGNhbiBiZSBkaWZmZXJlbnQgd2l0aCBpdHMgcmVhbCBgZmlnLndpZHRoYCBhbmQgYGZpZy5oZWlnaHRgLCBpLmUuIHBsb3RzIGNhbiBiZSBzY2FsZWQgaW4gdGhlIG91dHB1dCBkb2N1bWVudCkuIEZvciBleGFtcGxlLCBhcyBhIHBlcmNlbnQgYG91dC53aWR0aCA9ICc4MCVgIG9yIGluIHBpeGVscyBgb3V0LndpZHRoID0gNjAwcHhgLiAKKiBgZmlnLmNhcGA6IChOVUxMOyBjaGFyYWN0ZXIpIEZpZ3VyZSBjYXB0aW9uIHRvIGJlIHVzZWQuICpOb3RlKiwgY2hhcmFjdGVyIHZhbHVlcyBtdXN0IGJlIGVuY2xvc2VkIGluICoqc2luZ2xlIHF1b3RhdGlvbioqIG1hcmtzIGxpa2Ugc286IGAnVGhpcyBpcyBhIGZpZ3VyZSBjYXB0aW9uJ2AuCgpPSywgbGV0J3MgdXNlICBjaHVuayBvcHRpb25zIHRvIGNoYW5nZSB0aGUgc2l6ZSBhbmQgYWxpZ25tZW50IGFuZCBhZGQgYSBjYXB0aW9uLiBJIHdpbGwgaGlkZSB0aGUgUiBjb2RlIHNpbmNlIGl0IGlzIHRoZSBzYW1lIGFzIGFib3ZlLiBJZiB5b3Ugd2FudCB0byBzZWUgdGhlIGNodW5rIG9wdGlvbnMgeW91IG5lZWQgdG8gbG9vayBhdCB0aGUgcmF3IGAuUm1kYCBmaWxlIG9uIHRoZSBbR2l0SHViIHJlcG9dKGh0dHBzOi8vZ2l0aHViLmNvbS9zdHJpLWNvbi9kYy1zaW5nbGUvYmxvYi9tYXN0ZXIvaW5kZXguUm1kKS4gCgpgYGB7ciBvdXRfMiwgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD00LCBmaWcuY2FwPSdUaGlzIGlzIGEgZmlndXJlIGNhcHRpb24uJywgZWNobz1GQUxTRX0KcGxvdChjYXJzLCBtYWluID0gIlBsb3QgVGl0bGUiLCAKICAgICB4bGFiID0gInRlbXBlcmF0dXJlIChDKSIsIAogICAgIHlsYWIgPSAicHJlc3N1cmUgKFBhKSIsIAogICAgIHBjaCA9IDI0LCBjZXg9MS41LCBjb2w9InJlZCIsIGJnPSJibHVlIiwgbHdkPTIpCmBgYAoKSWYgeW91IHdhbnQgdG8gZGlzcGxheSBtdWx0aXBsZSBmaWd1cmVzIHNpZGUtYnktc2lkZSwgeW91IG5lZWQgdG8gc2V0IGBmaWcuc2hvdz0naG9sZCdgLiBUaGlzIGNodW5rIG9wdGlvbiAgaG9sZHMgYWxsIHBsb3RzIGFuZCBvdXRwdXRzIHRoZW0gYXQgdGhlIHZlcnkgZW5kIG9mIGEgY29kZSBjaHVuaywgYXMgb3Bwb3NlZCB0byBwcmludGluZyB0aGVtIG9uZSBieSBvbmUuIFlvdSBhbHNvIG5lZWQgdG8gc2V0IGBvdXQud2lkdGhgIGVxdWFsIHRvIGEgcGVyY2VudCB2YWx1ZSBkaXZpZGVkIGJ5IHRoZSBudW1iZXIgb2YgcGxvdHMuIEZvciBleGFtcGxlLCBzdXBwb3NlIHdlIHdhbnQgdG8gZGlzcGxheSB0aHJlZSBwbG90cyBzaWRlLWJ5LXNpZGUsIHdlIG5lZWQgdG8gc2V0IGBvdXQud2lkdGg9JzMzJSdgLgoKYGBgYApgYGB7ciBncmlkLCBmaWcuc2hvdz0naG9sZCcsIG91dC53aWR0aD0nMzMlJ31gciAnJ2AKcDEgPC0gcGxvdChwcmVzc3VyZSkKcDIgPC0gcGxvdChjYXJzKQpwMyA8LSBwbG90KHByZXNzdXJlKQpgYGAKYGBgYAoKYGBge3IgZ3JpZCwgZWNobz1GQUxTRSwgZmlnLnNob3c9J2hvbGQnLCBvdXQud2lkdGg9JzMzJSd9CnAxIDwtIHBsb3QocHJlc3N1cmUpCnAyIDwtIHBsb3QoY2FycykKcDMgPC0gcGxvdChwcmVzc3VyZSkKYGBgCgpUaGVyZSBhcmUgbW9yZSBzb3BoaXN0aWNhdGVkIHdheXMgdG8gZGlzcGxheSBtdWx0aXBsZSBmaWd1cmVzIHVzaW5nIHNvbWV0aGluZyBsaWtlIGBncmlkLmFycmFuZ2VgIChmcm9tIHRoZSBgZ3JpZEV4dHJhYCBwYWNrYWdlKSBvciBgcGxvdF9ncmlkYCAoZnJvbSB0aGUgYGNvd3Bsb3RgIHBhY2thZ2UpLiBJIGVuY291cmFnZSB5b3UgdG8gbG9vayBhdCB0aGVzZSBwYWNrYWdlcy4gCgpQbGF5IGFyb3VuZCB3aXRoIHRoZXNlIG9wdGlvbnMgdG8gc2VlIGhvdyBpdCBhZmZlY3RzIHRoZSBmaW5hbCBvdXRwdXQuIENodW5rIG9wdGlvbnMgZm9yIGZpZ3VyZXMgY2FuIGJlIGNvbmZ1c2luZyBhdCB0aW1lcyBidXQgeW91IHdpbGwgZ2V0IHRoZSBoYW5nIG9mIGl0IHdpdGggYSBiaXQgb2YgcHJhY3RpY2UuIAoKVGhhdCBpcyBhbGwgSSBoYXZlIHRvIHNheSBhYm91dCBmaWd1cmVzLiBBZ2FpbiwgdGhpcyBpcyBhIGJyb2FkIHRvcGljIGFuZCBJIHN1Z2dlc3QgeW91IGxvb2sgYXJvdW5kIHRvIHNlZSB3aGF0IGlzIHBvc3NpYmxlLiBJZiB0aGVyZSBpcyBzb21ldGhpbmcgc3BlY2lmaWMgeW91IHdhbnQgdG8gZG8gcGxlYXNlIHBvc3QgaXQgdG8gdGhlIFNsYWNrIGNoYW5uZWwuIAoKIyMjIEltYWdlcwoKVGhlIG90aGVyIHR5cGUgb2YgZ3JhcGhpYyB5b3UgbWF5IHdhbnQgdG8gdXNlIGlzIGFuIGltYWdlLS0tYW55IGV4dGVybmFsbHkgZ2VuZXJhdGVkIHZpc3VhbCBwcm9kdWN0ICppbnNlcnRlZCogaW50byB0aGUgZG9jdW1lbnQsIGxpa2UgYSBgcG5nYCBvciBganBnYC4gIFdoZW4gcGxvdHMgYXJlIG5vdCBnZW5lcmF0ZWQgd2l0aCBSIGNvZGUsIHRoZXJlIGlzIG5vIHdheSBmb3IgYGtuaXRyYCB0byBjYXB0dXJlIHBsb3RzIGF1dG9tYXRpY2FsbHkuIEluIHRoaXMgY2FzZSwgeW91IG1heSBnZW5lcmF0ZSB0aGUgaW1hZ2VzIG1hbnVhbGx5IGFuZCB0aGVuIHBhc3MgdGhlaXIgZmlsZSBwYXRocyB0byBzb21lIG90aGVyIGZ1bmN0aW9uIHRvIGluY2x1ZGUgdGhlc2UgaW1hZ2VzIGluIHRoZSBvdXRwdXQuIERvbid0IHdvcnJ5LCB0aGlzIHNlY3Rpb24gaXMgbm90IGxvbmcuIEZpcnN0IEkgd2FudCB0byBjb3ZlciBhIGZldyBiZXN0IHByYWN0aWNlcyBhbmQgdGhlbiBnbyBvdmVyIGRpZmZlcmVudCB3YXlzIG9mIGRpc3BsYXlpbmcgYW5kIGNvbnRyb2xsaW5nIGltYWdlcy4gCgojIyMjIEJlc3QgcHJhY3RpY2VzCgpJbiBSIE1hcmtkb3duLCB5b3UgY2FuIHVzZSBHSUYgKEdyYXBoaWMgSW50ZXJjaGFuZ2UgRm9ybWF0KSBmb3Igc2ltcGxlIGFuaW1hdGlvbnMgb3IgU1ZHIChTY2FsYWJsZSBWZWN0b3IgR3JhcGhpY3MpIGZvciB0aGluZ3MgbGlrZSBsb2dvcyBhbmQgbWFwcy4gVGhlc2UgZmlsZSB0eXBlcyBhcmUgdXNlZCBpbiBzcGVjaWFsIHNpdHVhdGlvbnMgYW5kIHdpbGwgbm90IGJlIGNvdmVyZWQgaGVyZS4gQnkgZmFyIHRoZSBlYXNpZXN0IGZpbGUgdHlwZXMgdG8gd29yayB3aXRoIGluIFIgTWFya2Rvd24gZm9yIHN0YXRpYyBpbWFnZXMgYXJlIFBORyAoUG9ydGFibGUgTmV0d29yayBHcmFwaGljcykgYW5kIEpQRy9KUEVHIChKb2ludCBQaG90b2dyYXBoaWMgRXhwZXJ0cyBHcm91cCkuIFRoZXJlIGFyZSByZWFsbHkgbm8gc3RyaWN0IHJ1bGVzIGZvciB3aGVuIHlvdSBzaG91bGQgdXNlIFBORyB2cy4gSlBHLiAqKipHZW5lcmFsbHkqKiogc3BlYWtpbmcgdGhvdWdoOgoKKiAqKlBORyoqIGlzIHVzdWFsbHkgYmV0dGVyIGZvciBncmFwaGljcyBsaWtlIGNoYXJ0cyAmIGdyYXBocywgaW1hZ2VzIHdpdGggdGV4dCwgYW55dGhpbmcgd2l0aCBoaWdoIGNvbnRyYXN0IGNvbG9ycywgb3IgZm9yIGltYWdlcyB0aGF0IGNvbnRhaW4gbGVzcyBjb2xvciBkYXRhLiBUaGUgb3RoZXIgYWR2YW50YWdlIGlzIHRoYXQgdW5saWtlIEpQRywgUE5HIGZvcm1hdCBzdXBwb3J0cyBhIHRyYW5zcGFyZW50IGJhY2tncm91bmQuIFBOR3MgYXJlIGFsc28gYmV0dGVyIGZvciBzY3JlZW5zaG90cy4gCiogKipKUEcqKiBpcyB1c3VhbGx5IGJldHRlciBmb3IgaGlnaCBjb2xvciBhbmQgcGhvdG9ncmFwaHMuIEFub3RoZXIgYWR2YW50YWdlIGlzIHRoZSBpdCBpcyBlYXNpZXIgdG8gcmVkdWNlIGZpbGUgc2l6ZXMgd2l0aG91dCBjb21wcm9taXNpbmcgcXVhbGl0eS4gSG93ZXZlciwgSlBHIGRvZXMgbm90IHN1cHBvcnQgdHJhbnNwYXJlbnQgYmFja2dyb3VuZC4KCkFub3RoZXIgdGhpbmcgdG8gY29uc2lkZXIgaXMgKmltYWdlIGNvbXByZXNzaW9uKi4gTm90aGluZyBzbG93cyBkb3duIGEgd2Vic2l0ZSBtb3JlIHRoYW4gYSBidWxreSBpbWFnZS4gU28gYWx3YXlzIGNvbXByZXNzIHlvdXIgaW1hZ2VzIGJlZm9yZSBhZGRpbmcgdGhlbSB0byB5b3VyIHdlYnNpdGUuIFRoZXJlIGFyZSBhIFt0b24gb2Ygb25saW5lIGFuZCBzdGFuZGFsb25lIGNvbXByZXNzaW9uIHRvb2xzXShodHRwczovL2Jsb2cudGVtcGxhdGV0b2FzdGVyLmNvbS9iZXN0LWltYWdlLWNvbXByZXNzaW9uLXRvb2xzLykgYXZhaWxhYmxlIGZvciBjb21wcmVzc2lvbi4gSSB1c2UgdGhlIHRvb2xzIGZyb20gW1dlYnNpdGVQbGFuZXRdKGh0dHBzOi8vd3d3LndlYnNpdGVwbGFuZXQuY29tL3dlYnRvb2xzL2ltYWdlY29tcHJlc3Nvci8pIGFuZCBbT3B0aW1pemlsbGFdKGh0dHBzOi8vaW1hZ2Vjb21wcmVzc29yLmNvbS8pLiBIb25lc3RseSwgSSBoYXZlbid0IHNwZW50IGEgdG9uIG9mIHRpbWUgY29tcGFyaW5nIHRvb2xzLCBidXQgSSB3YW50IHlvdSB0byBmaW5kIGEgY291cGxlIHRoYXQgd29yayBmb3IgeW91LiAKCj4gSWYgeW91IHBsYW4gb24gd29ya2luZyBhIGxvdCB3aXRoIGltYWdlcywgSSBzdHJvbmdseSBlbmNvdXJhZ2UgeW91IHRvIGdldCBmYW1pbGlhciB3aXRoIHRoZSBkaWZmZXJlbnQgZmlsZSB0eXBlcyBhbmQgY29tcHJlc3Npb24gb3B0aW9ucy4KCiMjIyMgQWRkaW5nIGltYWdlcyBpbiBSIE1hcmtkb3duCgpJIHdvdWxkIGxpa2UgdG8gY292ZXIgdGhyZWUgYmFzaWMgbWV0aG9kcyB0byBhZGQgaW1hZ2VzIHRvIGFuIFIgTWFya2Rvd24gZG9jdW1lbnQuIAoKMSkgTWFya2Rvd24KMikgYGtuaXRyOjppbmNsdWRlX2dyYXBoaWNzYAozKSBUaGUgYG1hZ2lja2AgcGFja2FnZQoKPGJyLz4KCiMjIyMgMS4gTWFya2Rvd24gY29kZQoKTWFya2Rvd24gc3ludGF4IGlzIHRoZSBlYXNpZXN0IHdheSB0byBhZGQgYW4gaW1hZ2UsIGhvd2V2ZXIgeW91IHNhY3JpZmljZSBjb250cm9sIGJlY2F1c2UgdGhlcmUgYXJlIHZlcnkgZmV3IG9wdGlvbnMuIEkgZGVtb25zdHJhdGVkIHRoZSBNYXJrZG93biBzeW50YXggd2F5IGJhY2sgYXQgdGhlIGJlZ2lubmluZyBvZiB0aGlzIGFzc2lnbm1lbnQgYnV0IGF0IHRoaXMgcG9pbnQgaXQncyBwcm9iYWJseSBhIGRpc3RhbnQgbWVtb3J5LiBTbywgbGV0J3MgcmV2aWV3LiBUaGUgc3ludGF4IGlzIHNpbXBsZS4gU3RhcnQgYSBuZXcgbGluZSB3aXRoIGFuIGAhYCwgZm9sbG93ZWQgYnkgb3BlbiBhbmQgY2xvc2VkIGJyYWNrZXRzIChgW11gKSwgYW5kIHRoZW4gdGhlICpyZWxhdGl2ZSogZmlsZSBwYXRoLCBsaWtlIHNvOgoKYGBgCiFbXShmaWxlcy9qdWxpYS5wbmcpCmBgYAoKIVtdKGZpbGVzL2p1bGlhLnBuZykKPHNtYWxsPjxlbT5JbWFnZSBvZiBhIFtKdWxpYSAgc2V0XShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9KdWxpYV9zZXQpLCBhbiBbaXRlcmF0ZWQgZnVuY3Rpb24gc3lzdGVtXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9JdGVyYXRlZF9mdW5jdGlvbl9zeXN0ZW0pIGdlbmVyYXRlZCB1c2luZyB0aGUgZXF1YXRpb24gJGZfe2N9KHopPXpeezJ9K2MkIHdoZXJlICRjJCBpcyBhIGNvbXBsZXggbnVtYmVyLCBpbiB0aGlzIGNhc2UgJGM9LTAuNzI2OSArIDAuMTg4OWkkLiBbRG93bmxvYWRlZF0oaHR0cHM6Ly9jb21tb25zLndpa2ltZWRpYS5vcmcvd2lraS9GaWxlOkp1bGlhXy0wLjcyNjlfMC4xODg5LnBuZykgZnJvbSBXaWtpbWVkaWEgQ29tbW9ucywgY3JlYXRlZCBieSBbSWthbXVzdW1lRmFuXShodHRwczovL2NvbW1vbnMud2lraW1lZGlhLm9yZy93aWtpL1VzZXI6SWthbXVzdW1lRmFuKSwgYW5kIGxpY2Vuc2VkIHVuZGVyIFtDQy1CWS1TQS00LjBdKGh0dHBzOi8vY29tbW9ucy53aWtpbWVkaWEub3JnL3dpa2kvQ2F0ZWdvcnk6Q0MtQlktU0EtNC4wKS48L2VtPjwvc21hbGw+Cgo8YnIvPgoKWW91IGNhbiBhbHNvIGRpc3BsYXkgIG11bHRpcGxlIGltYWdlcyBzaWRlLWJ5LXNpZGUgdXNpbmcgTWFya2Rvd24uIEluIHRoaXMgY2FzZSwgeW91IG11c3Qgc3BlY2lmeSB0aGUgIHdpZHRoIG9mIGFuIGltYWdlICh3aGVyZSAkd2lkdGggXGxlcSAxMDAvbiQgJiAkbiA9IG5vLiBvZiBpbWFnZXMkKSBhbmQgcHV0IHRoZSBNYXJrZG93biBjb2RlIGZvciBlYWNoIGltYWdlIG9uIHRoZSBzYW1lIGxpbmUgKG5vIHNwYWNlIGJldHdlZW4gdGhlIHR3byB0YWdzKS4KCjxici8+CgpgYGAKIVtdKGZpbGVzL2p1bGlhLnBuZyl7d2lkdGg9NTAlfSFbXShmaWxlcy9qdWxpYTIucG5nKXt3aWR0aD01MCV9CmBgYAoKIVtdKGZpbGVzL2p1bGlhLnBuZyl7d2lkdGg9NTAlfSFbXShmaWxlcy9qdWxpYTIucG5nKXt3aWR0aD01MCV9CjxzbWFsbD48ZW0+VHdvIGRpZmZlcmVudCBKdWxpYSBzZXRzLiBUaGUgaW1hZ2Ugb24gdGhlIHJpZ2h0ICgkYyA9IOKIkjAuODM1IOKIkiAwLjIzMjFpJCkgd2FzIFtkb3dubG9hZGVkXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9GaWxlOkp1bGlhXy0wLjgzNV8tMC4yMzIxLnBuZykgZnJvbSBXaWtpbWVkaWEgQ29tbW9ucywgY3JlYXRlZCBieSBbU2ltcHNvbnNfY29udHJpYnV0b3JdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL1VzZXI6U2ltcHNvbnNfY29udHJpYnV0b3IpLCBhbmQgcmVsZWFzZWQgdW5kZXIgdGhlIFtwdWJsaWMgZG9tYWluXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9lbjpwdWJsaWNfZG9tYWluKS48L2VtPjwvc21hbGw+CgpXZSBjYW4gYWxzbyB1c2UgTWFya2Rvd24gY29kZSB0byBpbmNsdWRlIGFuIGltYWdlIGRpcmVjdGx5IGZyb20gYSBVUkwuIAoKYGBgCiFbXShodHRwczovL3VwbG9hZC53aWtpbWVkaWEub3JnL3dpa2lwZWRpYS9jb21tb25zLzAvMGEvU3Vic2VjdGlvbl9CaWZ1cmNhdGlvbl9EaWFncmFtX0xvZ2lzdGljX01hcC5wbmcpCmBgYAoKIVtdKGh0dHBzOi8vdXBsb2FkLndpa2ltZWRpYS5vcmcvd2lraXBlZGlhL2NvbW1vbnMvMC8wYS9TdWJzZWN0aW9uX0JpZnVyY2F0aW9uX0RpYWdyYW1fTG9naXN0aWNfTWFwLnBuZyl7d2lkdGg9ODUlfQoKPHNtYWxsPjxlbT4gQSBjaGFvdGljIHJlZ2lvbiBmcm9tIHRoZSBbYmlmdXJjYXRpb24gZGlhZ3JhbV0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvQmlmdXJjYXRpb25fZGlhZ3JhbSkgb2YgdGhlIFtsb2dpc3RpYyBtYXBdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0xvZ2lzdGljX21hcCksIGRlcml2ZWQgYnkgaXRlcmF0aW5nIHRoZSBlcXVhdGlvbiAkeF97bisxfSA9IHJ4KDEteF9uKSQgb3ZlciBhbGwgdmFsdWVzIGZvciAkclswLDRdJC4gVGhlIG1hcCB3YXMgcG9wdWxhcml6ZWQgaW4gYSBwYXBlciBieSB0aGUgYmlvbG9naXN0IFtSb2JlcnQgTWF5XShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9Sb2JlcnRfTWF5LF9CYXJvbl9NYXlfb2ZfT3hmb3JkKSBlbnRpdGxlZCBbU2ltcGxlIG1hdGhlbWF0aWNhbCBtb2RlbHMgd2l0aCB2ZXJ5IGNvbXBsaWNhdGVkIGR5bmFtaWNzXShodHRwOi8vd3d3Lm1zLnVreS5lZHUvfm1hMTM3L1NwcmluZzE2L01heV9Mb2dpc3RpYy5wZGYpLiBJbWFnZSBieSBJblhuSSBhbmQgbGljZW5zZWQgdW5kZXIgW0NDMF0oaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvcHVibGljZG9tYWluL3plcm8vMS4wL2RlZWQuZW4pLiBbT3JpZ2luYWxdKGh0dHBzOi8vY29tbW9ucy53aWtpbWVkaWEub3JnL3dpa2kvRmlsZTpTdWJzZWN0aW9uX0JpZnVyY2F0aW9uX0RpYWdyYW1fTG9naXN0aWNfTWFwLnBuZykuPC9lbT48L3NtYWxsPgoKPGJyLz4KClRoZSBpc3N1ZSB3aXRoIHVzaW5nIE1hcmtkb3duIGNvZGUgZm9yIGltYWdlcyBpcyB0aGF0IHRoZXJlIGFyZSBmZXcgb3B0aW9ucy4gSXQgaXMgZGlmZmljdWx0IHRvIG1ha2UgbW9kaWZpY2F0aW9ucyB3aXRob3V0IHVzaW5nIEhUTUwgYW5kIENTUy4gCgo8YnIvPgoKIyMjIyAyLiBga25pdHI6OmluY2x1ZGVfZ3JhcGhpY3NgCgpJZiB5b3Ugd2FudCBhIGJpdCBtb3JlIGNvbnRyb2wgb3ZlciB0aGUgb3V0cHV0IHlvdSBjYW4gdXNlIGEgYnVpbHQtaW4gYGtuaXRyYCBmdW5jdGlvbiBjYWxsZWQgYGluY2x1ZGVfZ3JhcGhpY3NgLiBUaGUgbWFqb3IgYWR2YW50YWdlIG9mIHRoaXMgZnVuY3Rpb24gaXMgdGhhdCBpdCBpcyBwb3J0YWJsZSwgbWVhbmluZyB0aGF0IGl0IHdvcmtzIGZvciBhbGwgZG9jdW1lbnQgZm9ybWF0cyB0aGF0IGBrbml0cmAgc3VwcG9ydHMuIFRoYXQgd2F5IHlvdSBkbyBub3QgbmVlZCB0byB1c2UgZGlmZmVyZW50IHN5bnRheCBmb3IgZGlmZmVyZW50IGRvY3VtZW50IHR5cGVzIHRvIGVtYmVkIGFuIGV4dGVybmFsIGltYWdlLiBTaW5jZSB3ZSB1c2UgYGluY2x1ZGVfZ3JhcGhpY3NgIHdpdGhpbiBhIGNodW5rLCBzZXZlcmFsIGNodW5rIG9wdGlvbnMgYXJlIGF2YWlsYWJsZSBmb3IgY29udHJvbGxpbmcgdGhlIG91dHB1dC4gR28gdG8geW91ciBjb25zb2xlIHdpbmRvdyBpbiBSU3R1ZGlvIGFuZCB0eXBlIGA/a25pdHI6OmluY2x1ZGVfZ3JhcGhpY3NgIHRvIHNlZSB0aGUgaGVscCBtZW51LiBBcyB5b3UgY2FuIHNlZSwgdGhlcmUgYXJlIHZlcnkgZmV3IG9wdGlvbnMuIE1vc3Qgb2YgdGhlIGNvbnRyb2wgd2lsbCBjb21lIGZyb20gdXNpbmcgY2h1bmsgb3B0aW9ucy4gCgoqTm90ZSosIHRoZSBkb3VibGUgY29sb24gKGA6OmApIGluIHRoaXMgY29tbWFuZCBzcGVjaWZpZXMgdGhlIGV4YWN0IGZ1bmN0aW9uIGZyb20gdGhhdCBzcGVjaWZpYyBwYWNrYWdlLiBUaGlzIHByZXZlbnRzIGFueSBwcm9ibGVtcyBmcm9tIGFyaXNpbmcgaWYgYW5vdGhlciBwYWNrYWdlIGFsc28gaGFzIHRoZSBzYW1lIGZ1bmN0aW9uIG5hbWUuIEkgYW0gbm90IGF3YXJlIG9mIGFueSBvdGhlciBwYWNrYWdlcyB0aGF0IGhhdmUgdGhlIGZ1bmN0aW9uIGBpbmNsdWRlX2dyYXBoaWNzYCBidXQgdGhlIGNvbnZlbnRpb24gSSBoYXZlIHNlZW4gaXMgdGhlIGBrbml0cjo6aW5jbHVkZV9ncmFwaGljc2Agc28gSSB3aWxsIHVzZSB0aGF0IGhlcmUuIEl0IGlzIHVwIHRvIHlvdSB3aGV0aGVyIG9yIG5vdCB5b3Ugd2FudCB0byB1c2UgdGhlIGRvdWJsZSBjb2xvbi4gCgo+IEl0IGlzIGltcG9ydGFudCB0byBub3RlIHRoYXQgc29tZSBvZiB0aGUgY2h1bmsgb3B0aW9ucyB3ZSB1c2VkIGZvciBmaWd1cmVzICoqKndpbGwgbm90IHdvcmsqKiogZm9yIGltYWdlcy4gCgpTcGVjaWZpY2FsbHksIGBmaWcud2lkdGhgLCBgZmlnLmhlaWdodGAsIGFuZCBgZmlnLmRpbWAgZG8gbm90IHdvcmsgd2l0aCBpbWFnZXMuIFRvIGNvbnRyb2wgdGhlIHNpemUsIHdlIG5lZWQgdG8gdXNlIGBvdXQud2lkdGhgIGFuZCBgb3V0LmhlaWdodGAuIFJlbWVtYmVyLCBgb3V0LndpZHRoYCBhbmQgYG91dC5oZWlnaHRgIG5lZWQgZWl0aGVyIGEgKmNoYXJhY3RlciogKGUuZy4sIGAnNTAlJ2ApIE9SIGEgKm51bWVyaWMqIChgNjAwcHhgKSB2YWx1ZS4gV2UgYWxzbyBoYXZlIGFjY2VzcyB0byBgZmlnLmFsaWduYCBmb3IgcGxhY2VtZW50IGFuZCBgZmlnLmNhcGAgdG8gYWRkIGEgY2FwdGlvbi4gSGVyZSBpcyBhIGNvZGUgY2h1bmsgdXNpbmcgYGtuaXRyOjppbmNsdWRlX2dyYXBoaWNzYC4KCmBgYGAKYGBge3IgY2F2ZTEsIGZpZy5jYXA9IklOU0VSVCBDQVBUSU9OLiIsIG91dC53aWR0aCA9ICcxMDAlJywgZmlnLmFsaWduPSdsZWZ0J31gciAnJ2AKa25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoImZpbGVzL2NhdmUuanBnIikKYGBgCmBgYGAKCmBgYHtyIGNhdmUsIGZpZy5jYXA9IipUaGUgR3JlYXQgSGFsbCBvZiBQb2x5Y2hyb21lcywgW0NhdmUgb2YgQWx0YW1pcmFdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0NhdmVfb2ZfQWx0YW1pcmEpLCBwdWJsaXNoZWQgYnkgTS4gU2FueiBkZSBTYXV0dW9sYSBpbiAxODgwIChbb3JpZ2luYWxdKGh0dHBzOi8vY29tbW9ucy53aWtpbWVkaWEub3JnL3dpa2kvRmlsZTpBbHRhbWlyYS0xODgwLmpwZykpIGxpY2Vuc2VkIHVuZGVyIHRoZSBbcHVibGljIGRvbWFpbl0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvUHVibGljX2RvbWFpbikqLiIsIG91dC53aWR0aCA9ICcxMDAlJywgZmlnLmFsaWduPSdsZWZ0JywgZWNobz1GQUxTRX0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoImZpbGVzL2NhdmUuanBnIikKYGBgCgpBcyB3ZSBkaWQgYWJvdmUgd2hlbiB3ZSBkaXNwbGF5ZWQgZmlndXJlcyBzaWRlLWJ5LXNpZGUsIHdlIGNhbiBkbyB0aGUgc2FtZSB3aXRoIGltYWdlcyBhbmQgdGhlIGBpbmNsdWRlX2dyYXBoaWNzYCBmdW5jdGlvbi4gSGVyZSBhZ2FpbiB3ZSBgZmlnLnNob3c9J2hvbGQnYCBhbmQgc3BlY2lmeSB0aGUgYG91dC53aWR0aGAuIFdlIHVzZSB0aGUgYGNgIGZ1bmN0aW9uIHRvIGNvbWJpbmUgdmFsdWVzLS0taW4gdGhpcyBjYXNlIGltYWdlIGZpbGUgbmFtZXMtLS1pbnRvIGEgbGlzdC4gVGhpcyBpcyBhbmFsb2dvdXMgdG8gdGhlIE1hcmtkb3duIHN5bnRheCB3ZSB1c2VkIGFib3ZlIGZpciBkaXNwbGF5aW5nIGltYWdlcyBzaWRlLWJ5LXNpZGUuCgpgYGBgCmBgYHtyIGNhdmVfcm9jaywgb3V0LndpZHRoPSc1MCUnLCBmaWcuY2FwPSJJTlNFUlQgQ0FQVElPTiIsIGZpZy5zaG93PSdob2xkJywgZmlnLmFsaWduPSdsZWZ0J31gciAnJ2AKa25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoYygiZmlsZXMvY2F2ZS5qcGciLCJmaWxlcy9yb2NrLmpwZyIpKQpgYGAKYGBgYAoKYGBge3IsIGVjaG89RkFMU0UsIG91dC53aWR0aD0nNTAlJywgb3V0LmhlaWdodD0iNDAlIiwgZmlnLnNob3c9J2hvbGQnLCBmaWcuYWxpZ249J2xlZnQnLCBmaWcuY2FwPSI8c21hbGw+PGVtPlRoZSBHcmVhdCBIYWxsIG9mIFBvbHljaHJvbWVzIChyaWdodCkgJiByb2NrIHBhaW50aW5nIG9mIFtNaW1pIHNwaXJpdHNdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL01pbWlfKGZvbGtsb3JlKSkgZnJvbSBbS2FrYWR1IE5hdGlvbmFsIFBhcmtdKGh0dHBzOi8vY29tbW9ucy53aWtpbWVkaWEub3JnL3dpa2kvS2FrYWR1X05hdGlvbmFsX1BhcmspLiBbT3JpZ2luYWxdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL05vdXJsYW5naWVfUm9jayMvbWVkaWEvRmlsZTpBbmJhbmdiYW5nX2dhbGxlcnlfTWltaV9yb2NrX2FydF9jcm9wcGVkLmpwZykgbGljZW5zZWQgdW5kZXIgW0NDIEJZLVNBIDIuNV0oaHR0cHM6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL2xpY2Vuc2VzL2J5LXNhLzIuNSkgYnkgRHVzdGluIE0uIFJhbXNleSAoW0tyYWxpemVjIV0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvVXNlcjpLcmFsaXplYyEpKS48L2VtPjwvc21hbGw+In0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoYygiZmlsZXMvY2F2ZS5qcGciLCJmaWxlcy9yb2NrLmpwZyIpKQpgYGAKCkFzIHdlIGRpZCB3aXRoIE1hcmtkb3duLCB3ZSBjYW4gYWxzbyB1c2UgYGtuaXRyOjppbmNsdWRlX2dyYXBoaWNzYCB0byBhZGQgYW4gaW1hZ2UgZGlyZWN0bHkgZnJvbSB0aGUgd2ViLiAKCmBgYHtyIGFkZF93ZWJfaW1hZ2UsZmlnLmFsaWduPSdjZW50ZXInLCAgb3V0LmhlaWdodD00MDAsIGZpZy5jYXA9IjxzbWFsbD48ZW0+VGhlIEh1bW1pbmdiaXJkIChwYXJ0IG9mIHRoZSBbTmF6Y2EgTGluZXNdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL05hemNhX0xpbmVzKSkgYnkgW0RpZWdvIERlbHNvXShodHRwczovL2NvbW1vbnMud2lraW1lZGlhLm9yZy93aWtpL1VzZXI6UG9jb19hX3BvY28pIGxpY2Vuc2VkIHVuZGVyIFtDQyBCWS1TQV0oaHR0cHM6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL2xpY2Vuc2VzL2J5LXNhLzQuMC8pLjwvZW0+PC9zbWFsbD4ifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiaHR0cHM6Ly91cGxvYWQud2lraW1lZGlhLm9yZy93aWtpcGVkaWEvY29tbW9ucy90aHVtYi9hL2E1L0wlQzMlQURuZWFzX2RlX05hemNhJTJDX05hemNhJTJDX1BlciVDMyVCQSUyQ18yMDE1LTA3LTI5JTJDX0REXzUyLkpQRy8xMDI0cHgtTCVDMyVBRG5lYXNfZGVfTmF6Y2ElMkNfTmF6Y2ElMkNfUGVyJUMzJUJBJTJDXzIwMTUtMDctMjklMkNfRERfNTIuSlBHIikKYGBgCgo8YnIvPgoKIyMjIyAzLiBUaGUgYG1hZ2lja2AgcGFja2FnZTogQWR2YW5jZWQgaW1hZ2UtcHJvY2Vzc2luZyBpbiBSCgpUaGUgYG1hZ2lja2AgcGFja2FnZSBpcyBkZXNpZ25lZCB0byBtb2Rlcm5pemUgYW5kIHNpbXBsaWZ5IGhpZ2gtcXVhbGl0eSBpbWFnZSBwcm9jZXNzaW5nIGluIFIgYnkgd3JhcHBpbmcgdGhlIFtJbWFnZU1hZ2ljayBTVExdKGh0dHBzOi8vd3d3LmltYWdlbWFnaWNrLm9yZy9NYWdpY2srKy9TVEwuaHRtbCkuIEZpcnN0LCBpbnN0YWxsIGBtYWdpY2tgIGluIFIgdXNpbmcgdGhpcyBjb21tYW5kOgoKYGBgCmluc3RhbGwucGFja2FnZXMoIm1hZ2ljayIpCmBgYAoKVGhlbiBhZGQgdGhpcyB0byB5b3VyIHNldHVwIGNvZGUgY2h1bms6CgpgYGAKbGlicmFyeShtYWdpY2spCmBgYAoKSSB3aWxsIGhpZ2hsaWdodCBqdXN0IGEgZmV3IG9mIHRoZSBvcHRpb25zIGF2YWlsYWJsZSBpbiB0aGUgYG1hZ2lja2AgcGFja2FnZSwgYnV0IHBsZWFzZSBrbm93IHRoaXMgcGFja2FnZSBoYXMgYSBsb3Qgb2YgZnVuY3Rpb25hbGl0eS4gTXVjaCBvZiB3aGF0IHdlIGNvbnRyb2xsZWQgYWJvdmUgd2l0aCBjaHVuayBvcHRpb25zIChlLmcuLCBgb3V0LndpZHRoYCkgY2FuIGluc3RlYWQgYmUgY29udHJvbGxlZCBkaXJlY3RseSB3aXRoIGBtYWdpY2tgLiBJbiBhZGRpdGlvbiwgeW91IGNhbiBlZGl0IGltYWdlcywgYWRkIHRleHQgYW5ub3RhdGlvbiwgaW5jbHVkZSBmaWx0ZXJzIGFuZCBlZmZlY3RzLCBhbmltYXRlLCBvdmVybGF5IGltYWdlcywgZXRjLiBUaGlzIHBhY2thZ2UgaXMgZGVmaW5pdGVseSB3b3J0aCBsZWFybmluZywgZXNwZWNpYWxseSBpZiB5b3UgcGxhbiB0byB3b3JrIHdpdGggaW1hZ2VzLiAKCkkgd2lsbCAgKm5vdCB1c2UgYW55IGNvZGUgY2h1bmsgb3B0aW9ucyogdG8gY29udHJvbCB0aGUgYmVoYXZpb3Igb2YgdGhlIGltYWdlIHNvIEkgY2FuIGRlbW9uc3RyYXRlIHNvbWUgb2YgdGhlIGBtYWdpY2tgIGZ1bmN0aW9uYWxpdHkuIEZvciB0aGlzIGRlbW9uc3RyYXRpb24gSSB3aWxsIHVzZSBhbiBpbWFnZSBvZiB0aGUgW3dpbmdzIG9mIGEgZmVtYWxlIEJsdWUtU3BvdHRlZCBIYXdrZXIsICpBZHZlcnNhZXNjaG5hIGJyZXZpc3R5bGEqXShodHRwczovL2NvbW1vbnMud2lraW1lZGlhLm9yZy93aWtpL0ZpbGU6QWR2ZXJzYWVzY2huYV9icmV2aXN0eWxhX2ZlbWFsZV93aW5nc18oMTI1NjExMDYwMDMpLmpwZykgYnkgW0pvZ24gVGFubl0oaHR0cHM6Ly93d3cuZmxpY2tyLmNvbS9wZW9wbGUvMzEwMzE4MzVATjA4KSBsaWNlbnNlZCB1bmRlciBbQ0MgQlkgMi4wXShodHRwczovL2NyZWF0aXZlY29tbW9ucy5vcmcvbGljZW5zZXMvYnkvMi4wL2RlZWQuZW4pLiBGb3IgdGhpcyBkZW1vbnN0cmF0aW9uIHRoZSBganBnYCB3YXMgY29udmVydGVkIHRvIGBwbmdgIHVzaW5nIFtKUEcgdG8gUE5HXShodHRwczovL2pwZzJwbmcuY29tLykgdGhlbiBpbXBvcnRlZCB0byBbR2ltcF0oaHR0cHM6Ly93d3cuZ2ltcC5vcmcvKSB3aGVyZSBJIGNyb3BwZWQgdGhlIGltYWdlZCBhbmQgbWFkZSB0aGUgYmFja2dyb3VuZCB0cmFuc3BhcmVudC4gCk9LLiBEaXNwbGF5aW5nIGFuIGltYWdlIGlzIGVhc3kgdXNpbmcgdGhlIGBpbWFnZV9yZWFkYCBjb21tYW5kLiBJIHdpbGwgIHNldCB0aGUgdmFyaWFibGUgYHdpbmdzYCBzbyBJIGNhbiBtYW5pcHVsYXRlIHRoZSBpbWFnZSBsYXRlciBvbiB3aXRob3V0IG5lZWRpbmcgdG8gY2FsbCB0aGUgcGF0aC4gV2UgY2FuIHVzZSB0aGUgYHByaW50YCBjb21tYW5kIHRvIGdldCBzb21lIGRldGFpbHMgYWJvdXQgdGhlIGltYWdlLiBJZiB5b3UgZG8gbm90IHBsYW4gdG8gbWFrZSBhbnkgY2hhbmdlcyB5b3UgY2FuIHNpbXBseSBydW4gdGhlIGNvbW1hbmQgd2l0aG91dCB0aGUgdmFyaWFibGUgbmFtZS4KCmBgYHtyIHdpbmdzfQojIGltYWdlX3JlYWQoImZpbGVzL3dpbmdzLnBuZyIpIFVuY29tbWVudCB0byByZW5kZXIgdGhlIGltYWdlIGRpcmVjdGx5Lgp3aW5ncyA8LSBpbWFnZV9yZWFkKCJmaWxlcy93aW5ncy5wbmciKQpwcmludCh3aW5ncykKYGBgCgpUaGlzIGltYWdlIGlzIG11Y2ggbGFyZ2VyIHRoYW4gdGhlIHBhZ2Ugc28ga25pdHIgcmVzaXplZCBpdCB0byBmaXQgaW4gdGhlIHBhZ2UgY29udGFpbmVyLiAKCkhvdyBhYm91dCBjaGFuZ2luZyB0aGUgYmFja2dyb3VuZCBjb2xvciBhbmQgYWRkaW5nIGEgYm9yZGVyPyBUaGlzIGlzIGFuIGV4YW1wbGUgb2Ygc3RyaW5naW5nIHRvZ2V0aGVyIG11bHRpcGxlIGNvbW1hbmRzLiBDb29sLiAKCmBgYHtyIHdpbmdzX2NvbG9yfQppbWFnZV9ib3JkZXIoaW1hZ2VfYmFja2dyb3VuZCh3aW5ncywgIiM1NkI0RTkiKSwgIiMxNDE0MTQiLCAiNTB4MzAiKQpgYGAKCldlIGNhbiBhbHNvIGZsaXAgdGhlIGltYWdlIGFuZCByZXNpemUgcHJvcG9ydGlvbmFsbHkgdG8gaGVpZ2h0IG9mIDIwMHB4LiAKCmBgYHtyIHdpbmdzX2ZsaXAsIGZpZy5hbGlnbj0nY2VudGVyJ30KaW1hZ2Vfc2NhbGUoaW1hZ2VfZmxpcCh3aW5ncyksICJ4MjAwIikKYGBgCgpFdmVyeSB0aW1lIHdlIGNhbGwgYW4gYGltYWdlX2AtbGlrZSBjb21tYW5kLCBgbWFnaWNrYCB3aWxsIHByaW50IHRoZSBpbWFnZS4gU28sIHVubGVzcyB3ZSB3YW50IGEgYnVuY2ggb2YgaW1hZ2VzIHdlIG5lZWQgdG8gYXNzaWduIGEgdmFyaWFibGUgZWFjaCB0aW1lIHdlIHVzZSBhbiBgaW1hZ2VfYCBjb21tYW5kLiBUaGVuIHdlIGNhbiBzaW1wbHkgY2FsbCB0aGUgdmFyaWFibGUgdG8gcHJpbnQgdGhlIGltYWdlLgoKSG93IGFib3V0IHdlIG1ha2UgYSAqc2V0IG9mIHdpbmdzKj8gVG8gZG8gdGhpcywgSSB3aWxsOgoKMSkgUmVhZCBpbiB0aGUgYHdpbmdzLnBuZ2AgZmlsZS4gVGhlc2UgYXJlIHRoZSByaWdodC1zaWRlIHdpbmdzLiAKMikgU2NhbGUgdGhlIGltYWdlIChyZW1lbWJlciB0aGUgZmlsZSBpcyByZWFsbHkgYmlnKS4KMykgQ3JvcCB0aGUgaW1hZ2UgYmVjYXVzZSB0aGVyZSBpcyBhIGxvdCBvZiB3aGl0ZSBzcGFjZS4gCjQpIENvcHkgdGhlIG1vZGlmaWVkIGltYWdlIGFuZCByZWZsZWN0IGl0IGFyb3VuZCB0aGUgdmVydGljYWwgYXhpcyB0byBtYWtlIGxlZnQtc2lkZSB3aW5ncy4gNSkgQ29tYmluZSB0aGUgaW1hZ2VzIHRvIG1ha2UgYSB3aW5nIHNldC4gCgpGaXJzdCBJIHJlYWQgaW4gdGhlIGZpbGUgYW5kIGFzc2lnbiBpdCB0byB0aGUgdmFyaWFibGUgYHJpZ2h0YC4gTmV4dCwgSSBzY2FsZSB0aGUgaW1hZ2UgdXNpbmcgdGhlIGBpbWFnZV9zY2FsZWAgY29tbWFuZC4gTm90aWNlIEkgc2V0IHRoZSBkaW1lbnNpb25zIHRvIGB4NDAwYC4gVGhpcyBtZWFucyByZXNpemUgcHJvcG9ydGlvbmFsbHkgdG8gaGVpZ2h0IG9mIDIwMHB4LiBJZiBJIHdhbnRlZCB0byByZXNpemUgcHJvcG9ydGlvbmFsbHkgdG8gd2lkdGggSSB3b3VsZCB3cml0ZSBpdCBsaWtlIHRoaXMsIGA0MDBgLiAKCmBgYHtyIHdpbmdzX3JlYWR9CnJpZ2h0IDwtIGltYWdlX3JlYWQoImZpbGVzL3dpbmdzLnBuZyIpCnJpZ2h0IDwtIGltYWdlX3NjYWxlKHJpZ2h0LCAieDQwMCIpCmBgYAoKTm93IEkgd2lsbCBjcm9wIHRoZSBpbWFnZSB3aXRoIGBpbWFnZV9jcm9wYC4gVGhpcyB3YXMgYSBiaXQgb2YgYSBwYWluLCBidXQgYmFzaWNhbGx5IEkgbGVmdCB0aGUgaGVpZ2h0IHRoZSBzYW1lIGJ5IHNwZWNpZnlpbmcgYHg0MDBgIGFuZCB0aGVuIHNldCBjcm9wcGVkIDE1MHB4IG9mZiB0aGUgbGVmdCBvZiB0aGUgaW1hZ2UuIFlvdSByZWFsbHkganVzdCBuZWVkIHRvIHBsYXkgYXJvdW5kIHdpdGggdGhpcyB0byBnZXQgaXQgcmlnaHQuCgpgYGB7ciB3aW5nc19jcm9wfQpyaWdodCA8LSBpbWFnZV9jcm9wKHJpZ2h0LCAieDQwMCsxNTAiKQpsZWZ0IDwtIGltYWdlX2Zsb3AocmlnaHQpCmBgYAoKRmluYWxseSwgSSB1c2UgdGhlIGBjYCBjb21tYW5kIHRvIGNvbWJpbmUgdGhlIHZhcmlhYmxlcyBpbnRvIGEgbGlzdCBhbmQgdGhlbiB1c2UgYGltYWdlX2FwcGVuZGAgdG8gcHJpbnQgdGhlbSBzaWRlLWJ5LXNpZGUuIE5vdyB3ZSBoYXZlIGEgc2V0IG9mIHdpbmdzLiAgCgpgYGB7ciB3aW5nc19wYWlyfQppbWcgPC0gYyhsZWZ0LCByaWdodCkKaW1hZ2VfYXBwZW5kKGltZykKYGBgCgo8YnIvPgoKPiAjIyMjIyBZb3VyIEFzc2lnbm1lbnQgaXMgdG8gd29yayB0aHJvdWdoIHRoZSBbbWFnaWNrIHR1dG9yaWFsXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvbWFnaWNrL3ZpZ25ldHRlcy9pbnRyby5odG1sKSBhbmQgdXNlIGBtYWdpY2tgIGluIHlvdXIgZG9jdW1lbnQuCgpJZiB5b3UgaGF2ZSBhIHByZXR0eSBiaWcgZG9jdW1lbnQgYWxyZWFkeSwgSSByZWNvbW1lbmQgc3RhcnRpbmcgYSBuZXcgZHVtbXkgZG9jdW1lbnQgZm9yIHRoaXMgdHV0b3JpYWwuIFRoYXQgd2F5IHlvdSBjYW4gbWFrZSBjaGFuZ2VzIGFuZCByZW5kZXIgdGhlIGRvY3VtZW50IG1vcmUgcXVpY2tseS4gV29yayB3aXRoIEpQRyBmaWxlcywgUE5HIGZpbGVzIHdpdGggYSB0cmFuc3BhcmVudCBiYWNrZ3JvdW5kLCBhbmQgU1ZHcy4gWW91IGNhbiBhbHNvIHVzZSB0aGUgYG1hZ2lja2AgcGFja2FnZSB3aXRoIFIgY29kZSBnZW5lcmF0ZWQgZmlndXJlcyBzbyBwbGF5IHdpdGggdGhhdCB0b28uICoqTGVhcm4gdGhlIG1hZ2ljayBwYWNrYWdlKiogYnkgd29ya2luZyB0aHJvdWdoIHRoZSBbdHV0b3JpYWxdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9tYWdpY2svdmlnbmV0dGVzL2ludHJvLmh0bWwpLiAKCioqKgoKVGhhdCdzIGFsbCBmb3IgdGhpcyBBc3NpZ25tZW50IGFuZCBmb3IgTGVzc29uIDIuIFlvdSBzaG91bGQgbm93IGhhdmUgYWxsIHRoZSBiaWcgcGllY2VzIHlvdSBuZWVkIHRvIG1ha2UgYW4gYXdlc29tZSwgc2luZ2xlLXBhZ2UsIFIgTWFya2Rvd24gZG9jdW1lbnQuCgojIyBTZXNzaW9uIEluZm8KCmBgYHtyIHNlc3Npb259CnNlc3Npb25JbmZvKCkKYGBgCg==