Purpose

The purpose of today’s lab is to get more familiar with RMarkdown. RMarkdown is a file format that allows us to produce reports. You can use RMarkdown to produce html files (as we have been doing), but also word documents, pdfs, slideshows, websites, and more. In 612, we will be using RMarkdown to create APA manuscripts in R.

Here are two resources about RMarkdown that I recommend bookmarking: this cheatsheet and this book.



YAML

The YAML is the header of your RMarkdown file that starts and ends with ---. When you open a new RMarkdown file, it will automatically create a default YAML with a title, author, date, and output. You can set the output to which file type you want the report to print out in (html_document, pdf_document, word_document, ioslides_presentation, etc.)

---
title: Lab 7: RMarkdown
author: Zach Schroeder
date: November 15, 2024
output: 
  html_document
---

For an html document, you can add a table of contents by specifying toc: true under html_document. If you like how the table of contents is floating to the left like it is on the course website, you can also add toc_float: true. Additionally, you can customize your theme, change the width and height of figures for the whole report, number your sections, and so on. For how to do these, refer here.

---
title: 'Lab 7: RMarkdown'
output:
  html_document:
    toc: true
    toc_float: true
---

Code chunks

You can create a new code chunk with the shortcut Ctrl + Alt + I (or Cmd + Option + I if you have a Mac). This keyboard shortcut will also split a code chunk at the cursor.

Code chunk options

Code chunks have the default setting that all code will be evaluated and all code and results of the code will be printed out in your report when you knit it. But you may want to override the defaults. For example, you may want your final report to show only your figures but not the code that created the figures. You would edit the code chunk, inside the brackets, like this:

```{r, echo = FALSE}

Here are some more useful options.

Option Purpose Useful for…
echo = FALSE The results will print but not the code chunk If you want to hide your code
eval = FALSE The code chunk will print but is not evaluated If you want to showcase sample code
include = FALSE The code chunk is evaluated but nothing is printed You are loading libraries
warning = FALSE Warning messages will not be displayed You want to get rid of a warning message in your report but you still want it to print the rest of your results out (if it is not a warning message try message = FALSE)
error = TRUE The error message will display in your report instead of in the console You can use this to knit even when you have an error message
fig.path = figures/ Predetermines where the figure is saved. If the folder named in the chunk doesn’t exist, it will create one If you are knitting a document with many figures, this will allow you to move the important figures to a unique folder (and keep your source folder neater)

Refer here for more options. To change the settings for all of the code chunks in your report, you can set a global option. For example, if I wanted only the results and no code to print out for my entire report, I would put the code knitr::opts_chunk$set(echo = FALSE) in my first code chunk.

To keep your chunk options clean, you can use #| to add chunk options inside the chunk itself. This example from posit illustrates the option well.

ggplot(data = mtcars, aes(x = wt, y = mpg)) +
  geom_point()
This is a long description that conveys the meaning of the visual.

This is a long caption that fits better inside of a code chunk.

#| echo = FALSE,
#| message = FALSE,
#| fig.width = 6, fig.height = 6,
#| fig.path = "figures/",
#| fig.caption = "This is a long caption that fits better inside of a code chunk"
#| fig.alt = "This is a long description that conveys the meaning of the visual."

ggplot(data = mtcars, aes(x = wt, y = mpg)) +
  geom_point()

#|

Naming code chunks

I highly recommend naming your code chunks. The rationale is outlined in this blog post. In brief, the benefits to naming chunks are:

  1. It makes your document easier to navigate. You can navigate to chunks by selecting the dropdown menu from the bottom of the code pane.

  2. It makes it easier to debug knitting errors. When knitting a document, you may receive an error message that refers to the chunk that caused the knit to abort. It may be easier to locate regression dv emotion than chunk 12.

  3. It makes caching more efficient. If you have a code chunk that takes a long time to load, you can set cache = TRUE in the chunk options. This will only re-run the chunk if the chunk changes. Otherwise, knitting will use a prior, cached version of the chunk output.



Tables and tabbed sections

Tabbed sections are a way to organize your html file a little better. Follow this format exactly to make a tabbed section. Your first line will be the header of the section # header title {.tabset .tabset-fade .tabset-pills} followed by tab names ## tab 1, ## tab 2, and so on. In this section, we will also be exploring how to make a table using the kableExtra package.


Table 1

Here is a summary table without kableExtra.

(table_1 <- ggplot2::diamonds %>% 
  group_by(cut) %>% 
  summarize(n = n(),
          m_carat = mean(carat),
          sd_carat = sd(carat),
          m_depth = mean(depth),
          sd_depth = sd(depth),
          m_price = mean(price),
          sd_price = sd(price)))
## # A tibble: 5 × 8
##   cut           n m_carat sd_carat m_depth sd_depth m_price sd_price
##   <ord>     <int>   <dbl>    <dbl>   <dbl>    <dbl>   <dbl>    <dbl>
## 1 Fair       1610   1.05     0.516    64.0    3.64    4359.    3560.
## 2 Good       4906   0.849    0.454    62.4    2.17    3929.    3682.
## 3 Very Good 12082   0.806    0.459    61.8    1.38    3982.    3936.
## 4 Premium   13791   0.892    0.515    61.3    1.16    4584.    4349.
## 5 Ideal     21551   0.703    0.433    61.7    0.719   3458.    3808.

Table 2

This is a simple table using the kableExtra::kbl function. The kbl function makes very simple tables and is equivalent to knitr::kable that Sara used in class. If you need to make a nice table quickly, kbl is a good function to use.

#Creating a kable table where each digit is rounded to two decimal places
table_1 %>% 
  kbl(digits= 2)
cut n m_carat sd_carat m_depth sd_depth m_price sd_price
Fair 1610 1.05 0.52 64.04 3.64 4358.76 3560.39
Good 4906 0.85 0.45 62.37 2.17 3928.86 3681.59
Very Good 12082 0.81 0.46 61.82 1.38 3981.76 3935.86
Premium 13791 0.89 0.52 61.26 1.16 4584.26 4349.20
Ideal 21551 0.70 0.43 61.71 0.72 3457.54 3808.40


This is technically a little better but we can further customize it.


Table 3

With the kableExtra::kbl function, you can add a table caption, change the column names, and format the table so that it’s a little easier to read.

table_1 %>% 
  kbl(format = "simple",
      digits = 2, #rounds all values to two decimal places
      col.names = c("Cut", "N", "M Carat", "SD Carat",
                    "M Depth", "SD Depth",
                    "M Price", "SD Price"), #column names
      caption = "Table 1. A summary table for Carat, Depth, and Price by Cut of diamond.") #add table caption
Table 1. A summary table for Carat, Depth, and Price by Cut of diamond.
Cut N M Carat SD Carat M Depth SD Depth M Price SD Price
Fair 1610 1.05 0.52 64.04 3.64 4358.76 3560.39
Good 4906 0.85 0.45 62.37 2.17 3928.86 3681.59
Very Good 12082 0.81 0.46 61.82 1.38 3981.76 3935.86
Premium 13791 0.89 0.52 61.26 1.16 4584.26 4349.20
Ideal 21551 0.70 0.43 61.71 0.72 3457.54 3808.40

Table 4

If you want to style your table further, you would need to use other functions from the kableExtra package. For example, I can use the kable_classic function to create a “classic” style table.

table_1 %>% 
  kbl(col.names = c("Cut", "N", "M Carat", "SD Carat",
                    "M Depth", "SD Depth",
                    "M Price", "SD Price"),
      digits = 2,
      caption = "<b>Table 1</b><br /> <i>A summary table for Carat, Depth, and Price by Cut of diamond.</i>") %>% # This is html code that says bold "Table 1", enter, then italicize the rest
  kable_classic(full_width = FALSE) # make a classic table
Table 1
A summary table for Carat, Depth, and Price by Cut of diamond.
Cut N M Carat SD Carat M Depth SD Depth M Price SD Price
Fair 1610 1.05 0.52 64.04 3.64 4358.76 3560.39
Good 4906 0.85 0.45 62.37 2.17 3928.86 3681.59
Very Good 12082 0.81 0.46 61.82 1.38 3981.76 3935.86
Premium 13791 0.89 0.52 61.26 1.16 4584.26 4349.20
Ideal 21551 0.70 0.43 61.71 0.72 3457.54 3808.40

Table 5

Now, I am adding headers with the kableExtra::add_header_above function and a footnote with the kableExtra::footnote function.

(table_2 <- table_1 %>% 
  kbl(col.names = c("Cut", "N", "M", "SD",
                    "M", "SD",
                    "M", "SD"), # I renamed the columns
      digits = 2,
      caption = "<b>Table 1</b><br /> <i>A summary table for Carat, Depth, and Price by Cut of diamond.</i>",
      align =  "c") %>% #align center 
  kable_classic(full_width = FALSE) %>% 
  add_header_above(c(" " = 2, "Carat" = 2, "Depth " = 2, "Price" = 2)) %>% #adds headers called carat, depth, and price. The 2's indicate how many columns are under each header
  footnote(footnote_as_chunk = TRUE, 
           general = "Add footnote here.")) #adds a footnote 
Table 1
A summary table for Carat, Depth, and Price by Cut of diamond.
Carat
Depth
Price
Cut N M SD M SD M SD
Fair 1610 1.05 0.52 64.04 3.64 4358.76 3560.39
Good 4906 0.85 0.45 62.37 2.17 3928.86 3681.59
Very Good 12082 0.81 0.46 61.82 1.38 3981.76 3935.86
Premium 13791 0.89 0.52 61.26 1.16 4584.26 4349.20
Ideal 21551 0.70 0.43 61.71 0.72 3457.54 3808.40
Note: Add footnote here.

Table 6

Here I am using the kableExtra::row_spec function to highlight the 4th row Premium in yellow. There are so many more things that you can do with the kableExtra package. Here is an excellent resource.

table_2 %>% 
  row_spec(4, background = "#EFF184")
Table 1
A summary table for Carat, Depth, and Price by Cut of diamond.
Carat
Depth
Price
Cut N M SD M SD M SD
Fair 1610 1.05 0.52 64.04 3.64 4358.76 3560.39
Good 4906 0.85 0.45 62.37 2.17 3928.86 3681.59
Very Good 12082 0.81 0.46 61.82 1.38 3981.76 3935.86
Premium 13791 0.89 0.52 61.26 1.16 4584.26 4349.20
Ideal 21551 0.70 0.43 61.71 0.72 3457.54 3808.40
Note: Add footnote here.

Table 7

You can create a scroll box for your tables using the scroll_box function. This comes in handy when you have a large output to display. You can adjust the dimensions of the scroll box according to your preferences.

table_2 %>% 
  kable_paper() %>%
  scroll_box(width = "100%", height = "200px")
Table 1
A summary table for Carat, Depth, and Price by Cut of diamond.
Carat
Depth
Price
Cut N M SD M SD M SD
Fair 1610 1.05 0.52 64.04 3.64 4358.76 3560.39
Good 4906 0.85 0.45 62.37 2.17 3928.86 3681.59
Very Good 12082 0.81 0.46 61.82 1.38 3981.76 3935.86
Premium 13791 0.89 0.52 61.26 1.16 4584.26 4349.20
Ideal 21551 0.70 0.43 61.71 0.72 3457.54 3808.40
Note: Add footnote here.

Inline text

Inline text refers to text that is outside of code chunks. I am currently writing in inline text. In order to format the text that you write outside of code chunks, you have to abide by Markdown syntax. For example, you may want to bold, italicize, or strikethrough a word. You also may want to insert a list, table, headers, link, image, blockquote, or equation. Refer to the RMarkdown cheatsheet for how to format in Markdown syntax.

Visual editor

Clicking the settings cog and selecting Use Visual Editor will let you see most of the RMarkdown formatting while you are typing. This may be useful if you are formatting a document but don’t want to knit every time you make a small change. If editing a markdown document in the visual editor, common shortcuts (e.g., cmd + B to bold) can be used to edit text lieu of typing out **bold**. All editing shortcuts can be found here.

Search insert-able elements

Using cmd + / will open a search menu that includes all items that can be inserted into a markdown document. These include code chunks, bullet/numbered lists, and the different levels of headings. It can also insert code chunks for other programming languages (e.g., python or / SQL)




Inline code

Inline code

Sometimes you may want to code outside of a code chunk. The most common reason for this is to report statistics in your inline text. For example, let’s say you are writing a manuscript in R and you need to report the mean and standard deviation for a variable. You can calculate the mean and standard deviation of the variable in the code chunk, then call the answer in the in-line text. This will reduce human transfer errors.

#Descriptive stats for diamond price 

range_price_low <- range(diamonds$price)[1]

range_price_high <- range(diamonds$price)[2]

m_price <- mean(diamonds$price)

sd_price <- sd(diamonds$price)

Now, I can call the variables inline, like this: The price of diamonds ranged from 326 to 18823 (M = 3932.7997219, SD = 3989.4397381).



Advanced code

You can do more than call a variable outside of the code chunks. For example, here is some code that will make the sentence look a little nicer. However, when you code outside of the code chunks, the code becomes really difficult to read, so I recommend keeping complicated code inside of the code chunks.

The price of diamonds ranged from $326.00 to $18,823.00 (M = $3,932.80, SD = $3,989.44).

Instead of this mess, you want to first create your variables:

range_price_low <- range(diamonds$price)[1] %>%
  as.double() %>% #makes range_price_low a double (rather than an integer)
  format(nsmall = 2) %>% #format it to two decimal places
  paste0("$", .) #add a dollar sign before the number

range_price_high <- range(diamonds$price)[2] %>% 
  as.double() %>% 
  format(nsmall = 2, big.mark = ",") %>% #big.mark adds a comma for large numbers
  paste0("$", .)

m_price <- diamonds$price %>%
  mean() %>% 
  format(nsmall = 2, big.mark = ",") %>% 
  paste0("$", .)

sd_price <- diamonds$price %>%
  sd() %>% 
  format(nsmall = 2, big.mark = ",") %>% 
  paste0("$", .)

And then you can print your sentence: The price of diamonds ranged from $326.00 to $18,823.00 (M = $3,932.80, SD = $3,989.44).



Creating a function

#To remove redundancy in your code, you may want to create a function instead
#Here I've created a function with one argument "x" that converts numbers into money formatted numbers
money_format <- function(x){
  x %>%
  as.double() %>% 
  format(nsmall = 2, big.mark = ",") %>% 
  paste0("$", .)
}

#testing the function
money_format(23948234)
## [1] "$23,948,234.00"
money_format(23)
## [1] "$23.00"
diamonds$price %>% 
  mean() %>% 
  money_format() 
## [1] "$3,932.80"

Your new function will work inline too: $32,334.00


Style

After you complete a long day of coding, you may realize that some of your code is difficult to read. Installing the styler package creates an Addin (located in the Addins menu on the menu bar) that will apply the tidy style guide (from the tidyverse) to your a section or all of your code. While the content of your code will not change, it will do things to make it more readable, such as create line breaks after pipes (%>%)

Knitting errors

Knitting errors are particularly frustrating error messages if you thought you were done with your project and the code had worked up to the point of knitting. Plus, the messages can be vague and confusing. Here’s our advice:

  • Knit early and knit often. If you’re working on the homework, it’s a good idea to knit at least once after every problem.

  • When you get an error, you first want to try to locate where the error is. If you think you found it, you can comment out the entire code chunk by highlighting the code and typing Ctrl + Shift + C (or Cmd + Shift + C on a Mac), or you can change the code chunk options to error = TRUE. You should be able to knit now if the error message is coming from the code chunk that you just disabled. Otherwise, disable more code chunks, one at a time until it knits.

  • Once you’ve established where the error is, you may still not understand why the code isn’t working. The most common reasons are…

    • Your data set wasn’t imported properly.
    • You haven’t loaded the proper libraries and you need to add at least one library() command.
    • You are referring to a variable that hasn’t been assigned yet. It probably worked before because it was assigned in your global environment, but it needs to be assigned before the line of code in order for it to knit.
  • The function knit_exit() will exit the knitting process when run inline or in a code chunk. If you are debugging your code, using this will let you examine line-by-line to identify where the problem originates.

Caching code

You may run into code that takes forever to run. It is most common when importing large .csv files but may arise elsewhere. If you set cache = TRUE in the chunk options, it will save the last output of that code chunk and not rerun it until the code is edited. If you want to cache chunks that depend on the cached chunk, include the dependson argument. This lets you reference the cached chunk (hint: this is why you may want to name chunks!), which will rerun that code if the prior cached code is edited.

x <- 600
x
## [1] 600
x + 5
## [1] 505

If you edit the cached-chunk (e.g., by replacing 500 with 600) the dependent-chunk would not update properly. However, if you add the argument dependson = cached-chunk to the dependent-chunk, the cache would update any time the cached-chunk is edited.


Minihacks

Minihack answers can be found here

For today’s minihacks, you will be using RMarkdown to create your own html file.

  1. Open up a new RMarkdown file and erase everything but the YAML. Edit the YAML in the following ways:
    • Change the title to “Lab 7 Minihacks.”
    • Remove the author and date.
    • Under output, add a table of contents, numbered sections, and choose a theme. You should be outputting to an html file. Some html themes you may want to try are cerulean, journal, flatly, lumen, paper, and readable.
    • Knit the file. You should only see the title. The color and font will depend on which theme you chose.
    • Hint if you are having issues knitting, check that the tabs and spaces are correctly formatted
  2. Create a new code chunk and load the following libraries: tidyverse, ggplot2, kableExtra, rio and here.
    • Change the default chunk option so that the code is evaluated, but neither the code nor any resulting messages will show up in your report. You can do this all by changing one default option.
    • In the same code chunk, using the rio and here packages, import the data set us_contagious_diseases.csv and store it in a data frame called data.
    • Finally, in this code chunk, add the code options(scipen = 999), which will turn off scientific notation
  3. The us_contagious_diseases data set has the yearly counts for seven contagious diseases for the years 1928 - 2011. I have created three tables and called them data_1, data_2, and data_3.
    • Create a new level 1 header called “Tables.”
    • Under the Tables header, copy and paste the three chunks of code written below.
data_1 <- data %>% 
  group_by(disease) %>% 
  summarise(sum_count = sum(count)) 

data_1 %>% 
  kbl()
data_2 <- data %>% 
  filter(disease == "Measles") %>% 
  group_by(year) %>% 
  summarise(sum_count = sum(count))

data_2 %>% 
  kbl()
data_3 <- data %>% 
  filter(disease == "Measles" & year == "1938") %>%
  mutate(per_measles = count/population * 100) %>% 
  select(state, count, population, per_measles) 

data_3 %>% 
  kbl()
  • Create three subheaders “Table 1”, “Table 2”, and “Table 3” between the code chunks so that each code chunk is under the respective subheader.
    • Now, edit the code to make better tables. Using the kableExtra package, for each table, add a table title and edit the column names.
    • For each table, change the table format to classic with the kable_classic function.
    • For the second and third tables, try using the kableExtra::scroll_box function to limit the amount of space it takes up.
    • For the third table, highlight the Oregon row (row 38).
    • Change the chunk options on the tables so that you can only see the tables (not the code).
    • Knit to make sure that everything shows up how you want it.
  1. Create a tabbed section called “Figures”. You should have three tabs: “Figure 1”, “Figure 2” and “Figure 3”.
    • Copy and paste the code for these three figures into your RMarkdown file.
data_1 %>% 
  ggplot(aes(x = disease, y = sum_count)) +
  geom_bar(stat = "identity") +
  theme_minimal() +
  labs(x = "Type of disease", y= "Death count") + 
  coord_flip()
data_2 %>% 
  ggplot(aes(x = year, y = sum_count)) +
  geom_point() +
  theme_minimal() +
  labs(x = "Year", y= "Death count") +
  geom_vline(xintercept = 1963, color = "red", linetype = "dashed") + 
  geom_text(x = 1980, y = 600000, label = "Vaccine invented in 1963", 
            color = "red")
#install.packages("maps")
library(maps)
data_3 <- data_3 %>% 
  mutate(region = tolower(state))
states_map <- map_data("state")
disease_map <- left_join(states_map, data_3, by = "region")
ggplot(disease_map, aes(long, lat, group= group)) +
  geom_polygon(aes(fill = per_measles), color = "white") +
  labs(fill = "% Measles") +
  theme_minimal()
  • Next,

    • Change the default chunk options so that you can only see the figures (no code).

    • Use chunk options to change the widths of the figures to 8 inches.

    • Knit and familiarize yourself with what information these graphs are presenting.

  1. Create one last level 1 header called “Questions”. Create three subheadings “Question 1”, “Question 2”, and “Question 3”. Using in-line code, answer the following questions under the respective subheading:
    • Question 1) Measles had the highest number of infections in the US during this time span. What was the number of infections? Answer this question using data_1.
    • Question 2) What was the average number of Measles cases per year in the US from 1928 to 2011? Round this number to two decimal places. Answer this question using data_2.
    • Question 3) In 1938, Wisconsin had the highest number of Measles cases per capita. What percent of Wisconsin’s population contracted Measles in 1938? Answer this question using data_3.

LS0tCnRpdGxlOiAnTGFiIDc6IFJNYXJrZG93bicKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6IAogICAgdGhlbWU6IGNvc21vCiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogIHdvcmRfZG9jdW1lbnQ6CiAgICB0b2M6IHllcwogICAgdG9jX2RlcHRoOiAnMycKZWRpdG9yX29wdGlvbnM6IAogIGNodW5rX291dHB1dF90eXBlOiBjb25zb2xlCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkKCiMgc3VwcHJlc3Mgc2NpZW50aWZpYyBub3RhdGlvbgpvcHRpb25zKHNjaXBlbiA9IDk5OSkKCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoa2FibGVFeHRyYSkKYGBgCgojIFB1cnBvc2UKClRoZSBwdXJwb3NlIG9mIHRvZGF5J3MgbGFiIGlzIHRvIGdldCBtb3JlIGZhbWlsaWFyIHdpdGggUk1hcmtkb3duLiBSTWFya2Rvd24gaXMgYSBmaWxlIGZvcm1hdCB0aGF0IGFsbG93cyB1cyB0byBwcm9kdWNlIHJlcG9ydHMuIFlvdSBjYW4gdXNlIFJNYXJrZG93biB0byBwcm9kdWNlIGh0bWwgZmlsZXMgKGFzIHdlIGhhdmUgYmVlbiBkb2luZyksIGJ1dCBhbHNvIHdvcmQgZG9jdW1lbnRzLCBwZGZzLCBzbGlkZXNob3dzLCB3ZWJzaXRlcywgYW5kIG1vcmUuIEluIDYxMiwgd2Ugd2lsbCBiZSB1c2luZyBSTWFya2Rvd24gdG8gY3JlYXRlIEFQQSBtYW51c2NyaXB0cyBpbiBSLgoKSGVyZSBhcmUgdHdvIHJlc291cmNlcyBhYm91dCBSTWFya2Rvd24gdGhhdCBJIHJlY29tbWVuZCBib29rbWFya2luZzogdGhpcyBbY2hlYXRzaGVldF0oaHR0cHM6Ly9yc3R1ZGlvLmNvbS93cC1jb250ZW50L3VwbG9hZHMvMjAxNS8wMi9ybWFya2Rvd24tY2hlYXRzaGVldC5wZGYpIGFuZCB0aGlzIFtib29rXShodHRwczovL2Jvb2tkb3duLm9yZy95aWh1aS9ybWFya2Rvd24vKS4KCjxiciAvPgoKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIFlBTUwKClRoZSBZQU1MIGlzIHRoZSBoZWFkZXIgb2YgeW91ciBSTWFya2Rvd24gZmlsZSB0aGF0IHN0YXJ0cyBhbmQgZW5kcyB3aXRoIGAtLS1gLiBXaGVuIHlvdSBvcGVuIGEgbmV3IFJNYXJrZG93biBmaWxlLCBpdCB3aWxsIGF1dG9tYXRpY2FsbHkgY3JlYXRlIGEgZGVmYXVsdCBZQU1MIHdpdGggYSB0aXRsZSwgYXV0aG9yLCBkYXRlLCBhbmQgb3V0cHV0LiBZb3UgY2FuIHNldCB0aGUgb3V0cHV0IHRvIHdoaWNoIGZpbGUgdHlwZSB5b3Ugd2FudCB0aGUgcmVwb3J0IHRvIHByaW50IG91dCBpbiAoYGh0bWxfZG9jdW1lbnRgLCBgcGRmX2RvY3VtZW50YCwgYHdvcmRfZG9jdW1lbnRgLCBgaW9zbGlkZXNfcHJlc2VudGF0aW9uYCwgZXRjLikKCmBgYCB5YW1sCi0tLQp0aXRsZTogTGFiIDc6IFJNYXJrZG93bgphdXRob3I6IFphY2ggU2Nocm9lZGVyCmRhdGU6IE5vdmVtYmVyIDE1LCAyMDI0Cm91dHB1dDogCiAgaHRtbF9kb2N1bWVudAotLS0KYGBgCgpGb3IgYW4gaHRtbCBkb2N1bWVudCwgeW91IGNhbiBhZGQgYSB0YWJsZSBvZiBjb250ZW50cyBieSBzcGVjaWZ5aW5nIGB0b2M6IHRydWVgIHVuZGVyIGBodG1sX2RvY3VtZW50YC4gSWYgeW91IGxpa2UgaG93IHRoZSB0YWJsZSBvZiBjb250ZW50cyBpcyBmbG9hdGluZyB0byB0aGUgbGVmdCBsaWtlIGl0IGlzIG9uIHRoZSBjb3Vyc2Ugd2Vic2l0ZSwgeW91IGNhbiBhbHNvIGFkZCBgdG9jX2Zsb2F0OiB0cnVlYC4gQWRkaXRpb25hbGx5LCB5b3UgY2FuIGN1c3RvbWl6ZSB5b3VyIHRoZW1lLCBjaGFuZ2UgdGhlIHdpZHRoIGFuZCBoZWlnaHQgb2YgZmlndXJlcyBmb3IgdGhlIHdob2xlIHJlcG9ydCwgbnVtYmVyIHlvdXIgc2VjdGlvbnMsIGFuZCBzbyBvbi4gRm9yIGhvdyB0byBkbyB0aGVzZSwgcmVmZXIgW2hlcmVdKGh0dHBzOi8vYm9va2Rvd24ub3JnL3lpaHVpL3JtYXJrZG93bi9odG1sLWRvY3VtZW50Lmh0bWwpLgoKYGBgIHlhbWwKLS0tCnRpdGxlOiAnTGFiIDc6IFJNYXJrZG93bicKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQotLS0KYGBgCgotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCiMgQ29kZSBjaHVua3MKCllvdSBjYW4gY3JlYXRlIGEgbmV3IGNvZGUgY2h1bmsgd2l0aCB0aGUgc2hvcnRjdXQgYEN0cmwgKyBBbHQgKyBJYCAob3IgYENtZCArIE9wdGlvbiArIElgIGlmIHlvdSBoYXZlIGEgTWFjKS4gVGhpcyBrZXlib2FyZCBzaG9ydGN1dCB3aWxsIGFsc28gc3BsaXQgYSBjb2RlIGNodW5rIGF0IHRoZSBjdXJzb3IuCgpgYGB7cn0KCgpgYGAKCiMjIENvZGUgY2h1bmsgb3B0aW9ucwoKQ29kZSBjaHVua3MgaGF2ZSB0aGUgZGVmYXVsdCBzZXR0aW5nIHRoYXQgYWxsIGNvZGUgd2lsbCBiZSBldmFsdWF0ZWQgYW5kIGFsbCBjb2RlIGFuZCByZXN1bHRzIG9mIHRoZSBjb2RlIHdpbGwgYmUgcHJpbnRlZCBvdXQgaW4geW91ciByZXBvcnQgd2hlbiB5b3Uga25pdCBpdC4gQnV0IHlvdSBtYXkgd2FudCB0byBvdmVycmlkZSB0aGUgZGVmYXVsdHMuIEZvciBleGFtcGxlLCB5b3UgbWF5IHdhbnQgeW91ciBmaW5hbCByZXBvcnQgdG8gc2hvdyAqKm9ubHkqKiB5b3VyIGZpZ3VyZXMgYnV0IG5vdCB0aGUgY29kZSB0aGF0IGNyZWF0ZWQgdGhlIGZpZ3VyZXMuIFlvdSB3b3VsZCBlZGl0IHRoZSBjb2RlIGNodW5rLCBpbnNpZGUgdGhlIGJyYWNrZXRzLCBsaWtlIHRoaXM6CgpgYGAgbWFya2Rvd24KYHIgJydgYGBge3IsIGVjaG8gPSBGQUxTRX0KYGBgCgpIZXJlIGFyZSBzb21lIG1vcmUgdXNlZnVsIG9wdGlvbnMuCgp8IE9wdGlvbiB8IFB1cnBvc2UgfCBVc2VmdWwgZm9yLi4uIHwKfDotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXw6LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS18Oi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tfAp8IGBlY2hvID0gRkFMU0VgIHwgVGhlIHJlc3VsdHMgd2lsbCBwcmludCBidXQgbm90IHRoZSBjb2RlIGNodW5rIHwgSWYgeW91IHdhbnQgdG8gaGlkZSB5b3VyIGNvZGUgfAp8IGBldmFsID0gRkFMU0VgIHwgVGhlIGNvZGUgY2h1bmsgd2lsbCBwcmludCBidXQgaXMgbm90IGV2YWx1YXRlZCB8IElmIHlvdSB3YW50IHRvIHNob3djYXNlIHNhbXBsZSBjb2RlIHwKfCBgaW5jbHVkZSA9IEZBTFNFYCB8IFRoZSBjb2RlIGNodW5rIGlzIGV2YWx1YXRlZCBidXQgbm90aGluZyBpcyBwcmludGVkIHwgWW91IGFyZSBsb2FkaW5nIGxpYnJhcmllcyB8CnwgYHdhcm5pbmcgPSBGQUxTRWAgfCBXYXJuaW5nIG1lc3NhZ2VzIHdpbGwgbm90IGJlIGRpc3BsYXllZCB8IFlvdSB3YW50IHRvIGdldCByaWQgb2YgYSB3YXJuaW5nIG1lc3NhZ2UgaW4geW91ciByZXBvcnQgYnV0IHlvdSBzdGlsbCB3YW50IGl0IHRvIHByaW50IHRoZSByZXN0IG9mIHlvdXIgcmVzdWx0cyBvdXQgKGlmIGl0IGlzIG5vdCBhIHdhcm5pbmcgbWVzc2FnZSB0cnkgYG1lc3NhZ2UgPSBGQUxTRWApIHwKfCBgZXJyb3IgPSBUUlVFYCB8IFRoZSBlcnJvciBtZXNzYWdlIHdpbGwgZGlzcGxheSBpbiB5b3VyIHJlcG9ydCBpbnN0ZWFkIG9mIGluIHRoZSBjb25zb2xlIHwgWW91IGNhbiB1c2UgdGhpcyB0byBrbml0IGV2ZW4gd2hlbiB5b3UgaGF2ZSBhbiBlcnJvciBtZXNzYWdlIHwKfCBgZmlnLnBhdGggPSBmaWd1cmVzL2AgfCBQcmVkZXRlcm1pbmVzIHdoZXJlIHRoZSBmaWd1cmUgaXMgc2F2ZWQuIElmIHRoZSBmb2xkZXIgbmFtZWQgaW4gdGhlIGNodW5rIGRvZXNuJ3QgZXhpc3QsIGl0IHdpbGwgY3JlYXRlIG9uZSB8IElmIHlvdSBhcmUga25pdHRpbmcgYSBkb2N1bWVudCB3aXRoIG1hbnkgZmlndXJlcywgdGhpcyB3aWxsIGFsbG93IHlvdSB0byBtb3ZlIHRoZSBpbXBvcnRhbnQgZmlndXJlcyB0byBhIHVuaXF1ZSBmb2xkZXIgKGFuZCBrZWVwIHlvdXIgc291cmNlIGZvbGRlciBuZWF0ZXIpIHwKClJlZmVyIFtoZXJlXShodHRwczovL2Jvb2tkb3duLm9yZy95aWh1aS9ybWFya2Rvd24vci1jb2RlLmh0bWwpIGZvciBtb3JlIG9wdGlvbnMuIFRvIGNoYW5nZSB0aGUgc2V0dGluZ3MgZm9yIGFsbCBvZiB0aGUgY29kZSBjaHVua3MgaW4geW91ciByZXBvcnQsIHlvdSBjYW4gc2V0IGEgZ2xvYmFsIG9wdGlvbi4gRm9yIGV4YW1wbGUsIGlmIEkgd2FudGVkIG9ubHkgdGhlIHJlc3VsdHMgYW5kIG5vIGNvZGUgdG8gcHJpbnQgb3V0IGZvciBteSBlbnRpcmUgcmVwb3J0LCBJIHdvdWxkIHB1dCB0aGUgY29kZSBga25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBGQUxTRSlgIGluIG15IGZpcnN0IGNvZGUgY2h1bmsuCgpUbyBrZWVwIHlvdXIgY2h1bmsgb3B0aW9ucyBjbGVhbiwgeW91IGNhbiB1c2UgYCN8YCB0byBhZGQgY2h1bmsgb3B0aW9ucyBpbnNpZGUgdGhlIGNodW5rIGl0c2VsZi4gVGhpcyBleGFtcGxlIGZyb20gW3Bvc2l0XShodHRwczovL3Bvc2l0LmNvL2Jsb2cvci1tYXJrZG93bi10aXBzLXRyaWNrcy0yLWNsZWFuaW5nLXVwLXlvdXItY29kZS8pIGlsbHVzdHJhdGVzIHRoZSBvcHRpb24gd2VsbC4KCmBgYHtyIGNhcnMtcGxvdCwgZWNobyA9IFRSVUUsIG1lc3NhZ2UgPSBGQUxTRSwgZmlnLndpZHRoID0gNiwgZmlnLmhlaWdodCA9IDYsIGZpZy5wYXRoID0gImZpZ3VyZXMvIiwgZmlnLmNhcCA9ICJUaGlzIGlzIGEgbG9uZyBjYXB0aW9uIHRoYXQgZml0cyBiZXR0ZXIgaW5zaWRlIG9mIGEgY29kZSBjaHVuay4iLCBmaWcuYWx0ID0gIlRoaXMgaXMgYSBsb25nIGRlc2NyaXB0aW9uIHRoYXQgY29udmV5cyB0aGUgbWVhbmluZyBvZiB0aGUgdmlzdWFsLiJ9CmdncGxvdChkYXRhID0gbXRjYXJzLCBhZXMoeCA9IHd0LCB5ID0gbXBnKSkgKwogIGdlb21fcG9pbnQoKQoKYGBgCgpgYGB7ciBjYXJzLXBsb3Qtc2hvcnR9CgojfCBlY2hvID0gRkFMU0UsCiN8IG1lc3NhZ2UgPSBGQUxTRSwKI3wgZmlnLndpZHRoID0gNiwgZmlnLmhlaWdodCA9IDYsCiN8IGZpZy5wYXRoID0gImZpZ3VyZXMvIiwKI3wgZmlnLmNhcHRpb24gPSAiVGhpcyBpcyBhIGxvbmcgY2FwdGlvbiB0aGF0IGZpdHMgYmV0dGVyIGluc2lkZSBvZiBhIGNvZGUgY2h1bmsiCiN8IGZpZy5hbHQgPSAiVGhpcyBpcyBhIGxvbmcgZGVzY3JpcHRpb24gdGhhdCBjb252ZXlzIHRoZSBtZWFuaW5nIG9mIHRoZSB2aXN1YWwuIgoKZ2dwbG90KGRhdGEgPSBtdGNhcnMsIGFlcyh4ID0gd3QsIHkgPSBtcGcpKSArCiAgZ2VvbV9wb2ludCgpCmBgYAoKI3wKCiMjIE5hbWluZyBjb2RlIGNodW5rcwoKSSBoaWdobHkgcmVjb21tZW5kIG5hbWluZyB5b3VyIGNvZGUgY2h1bmtzLiBUaGUgcmF0aW9uYWxlIGlzIG91dGxpbmVkIGluIFt0aGlzXShodHRwczovL21hc2FsbW9uLmV1LzIwMTcvMDgvMDgvY2h1bmtwZXRzLykgYmxvZyBwb3N0LiBJbiBicmllZiwgdGhlIGJlbmVmaXRzIHRvIG5hbWluZyBjaHVua3MgYXJlOgoKMS4gIEl0IG1ha2VzIHlvdXIgZG9jdW1lbnQgZWFzaWVyIHRvIG5hdmlnYXRlLiBZb3UgY2FuIG5hdmlnYXRlIHRvIGNodW5rcyBieSBzZWxlY3RpbmcgdGhlIGRyb3Bkb3duIG1lbnUgZnJvbSB0aGUgYm90dG9tIG9mIHRoZSBjb2RlIHBhbmUuCgoyLiAgSXQgbWFrZXMgaXQgZWFzaWVyIHRvIGRlYnVnIGtuaXR0aW5nIGVycm9ycy4gV2hlbiBrbml0dGluZyBhIGRvY3VtZW50LCB5b3UgbWF5IHJlY2VpdmUgYW4gZXJyb3IgbWVzc2FnZSB0aGF0IHJlZmVycyB0byB0aGUgY2h1bmsgdGhhdCBjYXVzZWQgdGhlIGtuaXQgdG8gYWJvcnQuIEl0IG1heSBiZSBlYXNpZXIgdG8gbG9jYXRlIGByZWdyZXNzaW9uIGR2IGVtb3Rpb25gIHRoYW4gYGNodW5rIDEyYC4KCjMuICBJdCBtYWtlcyBjYWNoaW5nIG1vcmUgZWZmaWNpZW50LiBJZiB5b3UgaGF2ZSBhIGNvZGUgY2h1bmsgdGhhdCB0YWtlcyBhIGxvbmcgdGltZSB0byBsb2FkLCB5b3UgY2FuIHNldCBgY2FjaGUgPSBUUlVFYCBpbiB0aGUgY2h1bmsgb3B0aW9ucy4gVGhpcyB3aWxsIG9ubHkgcmUtcnVuIHRoZSBjaHVuayAqaWYqIHRoZSBjaHVuayBjaGFuZ2VzLiBPdGhlcndpc2UsIGtuaXR0aW5nIHdpbGwgdXNlIGEgcHJpb3IsIGNhY2hlZCB2ZXJzaW9uIG9mIHRoZSBjaHVuayBvdXRwdXQuCgo8YnIgLz4KCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyBUYWJsZXMgYW5kIHRhYmJlZCBzZWN0aW9ucyB7LnRhYnNldCAudGFic2V0LWZhZGUgLnRhYnNldC1waWxsc30KClRhYmJlZCBzZWN0aW9ucyBhcmUgYSB3YXkgdG8gb3JnYW5pemUgeW91ciBodG1sIGZpbGUgYSBsaXR0bGUgYmV0dGVyLiBGb2xsb3cgdGhpcyBmb3JtYXQgZXhhY3RseSB0byBtYWtlIGEgdGFiYmVkIHNlY3Rpb24uIFlvdXIgZmlyc3QgbGluZSB3aWxsIGJlIHRoZSBoZWFkZXIgb2YgdGhlIHNlY3Rpb24gYCMgaGVhZGVyIHRpdGxlIHsudGFic2V0IC50YWJzZXQtZmFkZSAudGFic2V0LXBpbGxzfWAgZm9sbG93ZWQgYnkgdGFiIG5hbWVzIGAjIyB0YWIgMWAsIGAjIyB0YWIgMmAsIGFuZCBzbyBvbi4gSW4gdGhpcyBzZWN0aW9uLCB3ZSB3aWxsIGFsc28gYmUgZXhwbG9yaW5nIGhvdyB0byBtYWtlIGEgdGFibGUgdXNpbmcgdGhlIGBrYWJsZUV4dHJhYCBwYWNrYWdlLgoKPGJyIC8+CgojIyBUYWJsZSAxCgpIZXJlIGlzIGEgc3VtbWFyeSB0YWJsZSB3aXRob3V0IGBrYWJsZUV4dHJhYC4KCmBgYHtyLCBtZXNzYWdlID0gRkFMU0V9Cih0YWJsZV8xIDwtIGdncGxvdDI6OmRpYW1vbmRzICU+JSAKICBncm91cF9ieShjdXQpICU+JSAKICBzdW1tYXJpemUobiA9IG4oKSwKICAgICAgICAgIG1fY2FyYXQgPSBtZWFuKGNhcmF0KSwKICAgICAgICAgIHNkX2NhcmF0ID0gc2QoY2FyYXQpLAogICAgICAgICAgbV9kZXB0aCA9IG1lYW4oZGVwdGgpLAogICAgICAgICAgc2RfZGVwdGggPSBzZChkZXB0aCksCiAgICAgICAgICBtX3ByaWNlID0gbWVhbihwcmljZSksCiAgICAgICAgICBzZF9wcmljZSA9IHNkKHByaWNlKSkpCmBgYAoKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIyBUYWJsZSAyCgpUaGlzIGlzIGEgc2ltcGxlIHRhYmxlIHVzaW5nIHRoZSBga2FibGVFeHRyYTo6a2JsYCBmdW5jdGlvbi4gVGhlIGBrYmxgIGZ1bmN0aW9uIG1ha2VzIHZlcnkgc2ltcGxlIHRhYmxlcyBhbmQgaXMgZXF1aXZhbGVudCB0byBga25pdHI6OmthYmxlYCB0aGF0IFNhcmEgdXNlZCBpbiBjbGFzcy4gSWYgeW91IG5lZWQgdG8gbWFrZSBhIG5pY2UgdGFibGUgcXVpY2tseSwgYGtibGAgaXMgYSBnb29kIGZ1bmN0aW9uIHRvIHVzZS4KCmBgYHtyfQojQ3JlYXRpbmcgYSBrYWJsZSB0YWJsZSB3aGVyZSBlYWNoIGRpZ2l0IGlzIHJvdW5kZWQgdG8gdHdvIGRlY2ltYWwgcGxhY2VzCnRhYmxlXzEgJT4lIAogIGtibChkaWdpdHM9IDIpCmBgYAoKPGJyIC8+CgpUaGlzIGlzIHRlY2huaWNhbGx5IGEgbGl0dGxlIGJldHRlciBidXQgd2UgY2FuIGZ1cnRoZXIgY3VzdG9taXplIGl0LgoKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIyBUYWJsZSAzCgpXaXRoIHRoZSBga2FibGVFeHRyYTo6a2JsYCBmdW5jdGlvbiwgeW91IGNhbiBhZGQgYSB0YWJsZSBjYXB0aW9uLCBjaGFuZ2UgdGhlIGNvbHVtbiBuYW1lcywgYW5kIGZvcm1hdCB0aGUgdGFibGUgc28gdGhhdCBpdCdzIGEgbGl0dGxlIGVhc2llciB0byByZWFkLgoKYGBge3J9CnRhYmxlXzEgJT4lIAogIGtibChmb3JtYXQgPSAic2ltcGxlIiwKICAgICAgZGlnaXRzID0gMiwgI3JvdW5kcyBhbGwgdmFsdWVzIHRvIHR3byBkZWNpbWFsIHBsYWNlcwogICAgICBjb2wubmFtZXMgPSBjKCJDdXQiLCAiTiIsICJNIENhcmF0IiwgIlNEIENhcmF0IiwKICAgICAgICAgICAgICAgICAgICAiTSBEZXB0aCIsICJTRCBEZXB0aCIsCiAgICAgICAgICAgICAgICAgICAgIk0gUHJpY2UiLCAiU0QgUHJpY2UiKSwgI2NvbHVtbiBuYW1lcwogICAgICBjYXB0aW9uID0gIlRhYmxlIDEuIEEgc3VtbWFyeSB0YWJsZSBmb3IgQ2FyYXQsIERlcHRoLCBhbmQgUHJpY2UgYnkgQ3V0IG9mIGRpYW1vbmQuIikgI2FkZCB0YWJsZSBjYXB0aW9uCiAgCmBgYAoKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIyBUYWJsZSA0CgpJZiB5b3Ugd2FudCB0byBzdHlsZSB5b3VyIHRhYmxlIGZ1cnRoZXIsIHlvdSB3b3VsZCBuZWVkIHRvIHVzZSBvdGhlciBmdW5jdGlvbnMgZnJvbSB0aGUgYGthYmxlRXh0cmFgIHBhY2thZ2UuIEZvciBleGFtcGxlLCBJIGNhbiB1c2UgdGhlIGBrYWJsZV9jbGFzc2ljYCBmdW5jdGlvbiB0byBjcmVhdGUgYSAiY2xhc3NpYyIgc3R5bGUgdGFibGUuCgpgYGB7cn0KdGFibGVfMSAlPiUgCiAga2JsKGNvbC5uYW1lcyA9IGMoIkN1dCIsICJOIiwgIk0gQ2FyYXQiLCAiU0QgQ2FyYXQiLAogICAgICAgICAgICAgICAgICAgICJNIERlcHRoIiwgIlNEIERlcHRoIiwKICAgICAgICAgICAgICAgICAgICAiTSBQcmljZSIsICJTRCBQcmljZSIpLAogICAgICBkaWdpdHMgPSAyLAogICAgICBjYXB0aW9uID0gIjxiPlRhYmxlIDE8L2I+PGJyIC8+IDxpPkEgc3VtbWFyeSB0YWJsZSBmb3IgQ2FyYXQsIERlcHRoLCBhbmQgUHJpY2UgYnkgQ3V0IG9mIGRpYW1vbmQuPC9pPiIpICU+JSAjIFRoaXMgaXMgaHRtbCBjb2RlIHRoYXQgc2F5cyBib2xkICJUYWJsZSAxIiwgZW50ZXIsIHRoZW4gaXRhbGljaXplIHRoZSByZXN0CiAga2FibGVfY2xhc3NpYyhmdWxsX3dpZHRoID0gRkFMU0UpICMgbWFrZSBhIGNsYXNzaWMgdGFibGUKYGBgCgotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCiMjIFRhYmxlIDUKCk5vdywgSSBhbSBhZGRpbmcgaGVhZGVycyB3aXRoIHRoZSBga2FibGVFeHRyYTo6YWRkX2hlYWRlcl9hYm92ZWAgZnVuY3Rpb24gYW5kIGEgZm9vdG5vdGUgd2l0aCB0aGUgYGthYmxlRXh0cmE6OmZvb3Rub3RlYCBmdW5jdGlvbi4KCmBgYHtyfQoodGFibGVfMiA8LSB0YWJsZV8xICU+JSAKICBrYmwoY29sLm5hbWVzID0gYygiQ3V0IiwgIk4iLCAiTSIsICJTRCIsCiAgICAgICAgICAgICAgICAgICAgIk0iLCAiU0QiLAogICAgICAgICAgICAgICAgICAgICJNIiwgIlNEIiksICMgSSByZW5hbWVkIHRoZSBjb2x1bW5zCiAgICAgIGRpZ2l0cyA9IDIsCiAgICAgIGNhcHRpb24gPSAiPGI+VGFibGUgMTwvYj48YnIgLz4gPGk+QSBzdW1tYXJ5IHRhYmxlIGZvciBDYXJhdCwgRGVwdGgsIGFuZCBQcmljZSBieSBDdXQgb2YgZGlhbW9uZC48L2k+IiwKICAgICAgYWxpZ24gPSAgImMiKSAlPiUgI2FsaWduIGNlbnRlciAKICBrYWJsZV9jbGFzc2ljKGZ1bGxfd2lkdGggPSBGQUxTRSkgJT4lIAogIGFkZF9oZWFkZXJfYWJvdmUoYygiICIgPSAyLCAiQ2FyYXQiID0gMiwgIkRlcHRoICIgPSAyLCAiUHJpY2UiID0gMikpICU+JSAjYWRkcyBoZWFkZXJzIGNhbGxlZCBjYXJhdCwgZGVwdGgsIGFuZCBwcmljZS4gVGhlIDIncyBpbmRpY2F0ZSBob3cgbWFueSBjb2x1bW5zIGFyZSB1bmRlciBlYWNoIGhlYWRlcgogIGZvb3Rub3RlKGZvb3Rub3RlX2FzX2NodW5rID0gVFJVRSwgCiAgICAgICAgICAgZ2VuZXJhbCA9ICJBZGQgZm9vdG5vdGUgaGVyZS4iKSkgI2FkZHMgYSBmb290bm90ZSAKYGBgCgotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCiMjIFRhYmxlIDYKCkhlcmUgSSBhbSB1c2luZyB0aGUgYGthYmxlRXh0cmE6OnJvd19zcGVjYCBmdW5jdGlvbiB0byBoaWdobGlnaHQgdGhlIDR0aCByb3cgYFByZW1pdW1gIGluIHllbGxvdy4gVGhlcmUgYXJlIHNvIG1hbnkgbW9yZSB0aGluZ3MgdGhhdCB5b3UgY2FuIGRvIHdpdGggdGhlIGthYmxlRXh0cmEgcGFja2FnZS4gW0hlcmVdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9rYWJsZUV4dHJhL3ZpZ25ldHRlcy9hd2Vzb21lX3RhYmxlX2luX2h0bWwuaHRtbCkgaXMgYW4gZXhjZWxsZW50IHJlc291cmNlLgoKYGBge3J9Cgp0YWJsZV8yICU+JSAKICByb3dfc3BlYyg0LCBiYWNrZ3JvdW5kID0gIiNFRkYxODQiKQogIApgYGAKCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyMgVGFibGUgNwoKWW91IGNhbiBjcmVhdGUgYSBzY3JvbGwgYm94IGZvciB5b3VyIHRhYmxlcyB1c2luZyB0aGUgYHNjcm9sbF9ib3hgIGZ1bmN0aW9uLiBUaGlzIGNvbWVzIGluIGhhbmR5IHdoZW4geW91IGhhdmUgYSBsYXJnZSBvdXRwdXQgdG8gZGlzcGxheS4gWW91IGNhbiBhZGp1c3QgdGhlIGRpbWVuc2lvbnMgb2YgdGhlIHNjcm9sbCBib3ggYWNjb3JkaW5nIHRvIHlvdXIgcHJlZmVyZW5jZXMuCgpgYGB7cn0KdGFibGVfMiAlPiUgCiAga2FibGVfcGFwZXIoKSAlPiUKICBzY3JvbGxfYm94KHdpZHRoID0gIjEwMCUiLCBoZWlnaHQgPSAiMjAwcHgiKQpgYGAKCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyBJbmxpbmUgdGV4dAoKSW5saW5lIHRleHQgcmVmZXJzIHRvIHRleHQgdGhhdCBpcyBvdXRzaWRlIG9mIGNvZGUgY2h1bmtzLiBJIGFtIGN1cnJlbnRseSB3cml0aW5nIGluIGlubGluZSB0ZXh0LiBJbiBvcmRlciB0byBmb3JtYXQgdGhlIHRleHQgdGhhdCB5b3Ugd3JpdGUgb3V0c2lkZSBvZiBjb2RlIGNodW5rcywgeW91IGhhdmUgdG8gYWJpZGUgYnkgTWFya2Rvd24gc3ludGF4LiBGb3IgZXhhbXBsZSwgeW91IG1heSB3YW50IHRvICoqYm9sZCoqLCAqaXRhbGljaXplKiwgb3Igfn5zdHJpa2V0aHJvdWdofn4gYSB3b3JkLiBZb3UgYWxzbyBtYXkgd2FudCB0byBpbnNlcnQgYSBsaXN0LCB0YWJsZSwgaGVhZGVycywgbGluaywgaW1hZ2UsIGJsb2NrcXVvdGUsIG9yIGVxdWF0aW9uLiBSZWZlciB0byB0aGUgUk1hcmtkb3duIFtjaGVhdHNoZWV0XShodHRwczovL3JzdHVkaW8uY29tL3dwLWNvbnRlbnQvdXBsb2Fkcy8yMDE1LzAyL3JtYXJrZG93bi1jaGVhdHNoZWV0LnBkZikgZm9yIGhvdyB0byBmb3JtYXQgaW4gTWFya2Rvd24gc3ludGF4LgoKIyMgVmlzdWFsIGVkaXRvcgoKQ2xpY2tpbmcgdGhlIHNldHRpbmdzIGNvZyBhbmQgc2VsZWN0aW5nIGBVc2UgVmlzdWFsIEVkaXRvcmAgd2lsbCBsZXQgeW91IHNlZSBtb3N0IG9mIHRoZSBSTWFya2Rvd24gZm9ybWF0dGluZyB3aGlsZSB5b3UgYXJlIHR5cGluZy4gVGhpcyBtYXkgYmUgdXNlZnVsIGlmIHlvdSBhcmUgZm9ybWF0dGluZyBhIGRvY3VtZW50IGJ1dCBkb24ndCB3YW50IHRvIGtuaXQgZXZlcnkgdGltZSB5b3UgbWFrZSBhIHNtYWxsIGNoYW5nZS4gSWYgZWRpdGluZyBhIG1hcmtkb3duIGRvY3VtZW50IGluIHRoZSB2aXN1YWwgZWRpdG9yLCBjb21tb24gc2hvcnRjdXRzIChlLmcuLCBgY21kICsgQmAgdG8gYm9sZCkgY2FuIGJlIHVzZWQgdG8gZWRpdCB0ZXh0IGxpZXUgb2YgdHlwaW5nIG91dCBgKipib2xkKipgLiBBbGwgZWRpdGluZyBzaG9ydGN1dHMgY2FuIGJlIGZvdW5kIFtoZXJlXShodHRwczovL3JzdHVkaW8uZ2l0aHViLmlvL3Zpc3VhbC1tYXJrZG93bi1lZGl0aW5nL3Nob3J0Y3V0cy5odG1sKS4KCiMjIFNlYXJjaCBpbnNlcnQtYWJsZSBlbGVtZW50cwoKVXNpbmcgYGNtZCArIC9gIHdpbGwgb3BlbiBhIHNlYXJjaCBtZW51IHRoYXQgaW5jbHVkZXMgYWxsIGl0ZW1zIHRoYXQgY2FuIGJlIGluc2VydGVkIGludG8gYSBtYXJrZG93biBkb2N1bWVudC4gVGhlc2UgaW5jbHVkZSBjb2RlIGNodW5rcywgYnVsbGV0L251bWJlcmVkIGxpc3RzLCBhbmQgdGhlIGRpZmZlcmVudCBsZXZlbHMgb2YgaGVhZGluZ3MuIEl0IGNhbiBhbHNvIGluc2VydCBjb2RlIGNodW5rcyBmb3Igb3RoZXIgcHJvZ3JhbW1pbmcgbGFuZ3VhZ2VzIChlLmcuLCBgcHl0aG9uYCBvciAvIGBTUUxgKQoKPGJyIC8+Cgo8YnIgLz4KCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyMgSW5saW5lIGNvZGUgey50YWJzZXQgLnRhYnNldC1mYWRlIC50YWJzZXQtcGlsbHN9CgojIyMgSW5saW5lIGNvZGUKClNvbWV0aW1lcyB5b3UgbWF5IHdhbnQgdG8gY29kZSBvdXRzaWRlIG9mIGEgY29kZSBjaHVuay4gVGhlIG1vc3QgY29tbW9uIHJlYXNvbiBmb3IgdGhpcyBpcyB0byByZXBvcnQgc3RhdGlzdGljcyBpbiB5b3VyIGlubGluZSB0ZXh0LiBGb3IgZXhhbXBsZSwgbGV0J3Mgc2F5IHlvdSBhcmUgd3JpdGluZyBhIG1hbnVzY3JpcHQgaW4gUiBhbmQgeW91IG5lZWQgdG8gcmVwb3J0IHRoZSBtZWFuIGFuZCBzdGFuZGFyZCBkZXZpYXRpb24gZm9yIGEgdmFyaWFibGUuIFlvdSBjYW4gY2FsY3VsYXRlIHRoZSBtZWFuIGFuZCBzdGFuZGFyZCBkZXZpYXRpb24gb2YgdGhlIHZhcmlhYmxlIGluIHRoZSBjb2RlIGNodW5rLCB0aGVuIGNhbGwgdGhlIGFuc3dlciBpbiB0aGUgaW4tbGluZSB0ZXh0LiBUaGlzIHdpbGwgcmVkdWNlIGh1bWFuIHRyYW5zZmVyIGVycm9ycy4KCmBgYHtyfQojRGVzY3JpcHRpdmUgc3RhdHMgZm9yIGRpYW1vbmQgcHJpY2UgCgpyYW5nZV9wcmljZV9sb3cgPC0gcmFuZ2UoZGlhbW9uZHMkcHJpY2UpWzFdCgpyYW5nZV9wcmljZV9oaWdoIDwtIHJhbmdlKGRpYW1vbmRzJHByaWNlKVsyXQoKbV9wcmljZSA8LSBtZWFuKGRpYW1vbmRzJHByaWNlKQoKc2RfcHJpY2UgPC0gc2QoZGlhbW9uZHMkcHJpY2UpCgpgYGAKCk5vdywgSSBjYW4gY2FsbCB0aGUgdmFyaWFibGVzIGlubGluZSwgbGlrZSB0aGlzOiBUaGUgcHJpY2Ugb2YgZGlhbW9uZHMgcmFuZ2VkIGZyb20gYHIgcmFuZ2VfcHJpY2VfbG93YCB0byBgciByYW5nZV9wcmljZV9oaWdoYCAoKk0qID0gYHIgbV9wcmljZWAsICpTRCogPSBgciBzZF9wcmljZWApLgoKPGJyIC8+CgotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCiMjIyBBZHZhbmNlZCBjb2RlCgpZb3UgY2FuIGRvIG1vcmUgdGhhbiBjYWxsIGEgdmFyaWFibGUgb3V0c2lkZSBvZiB0aGUgY29kZSBjaHVua3MuIEZvciBleGFtcGxlLCBoZXJlIGlzIHNvbWUgY29kZSB0aGF0IHdpbGwgbWFrZSB0aGUgc2VudGVuY2UgbG9vayBhIGxpdHRsZSBuaWNlci4gSG93ZXZlciwgd2hlbiB5b3UgY29kZSBvdXRzaWRlIG9mIHRoZSBjb2RlIGNodW5rcywgdGhlIGNvZGUgYmVjb21lcyByZWFsbHkgZGlmZmljdWx0IHRvIHJlYWQsIHNvIEkgcmVjb21tZW5kIGtlZXBpbmcgY29tcGxpY2F0ZWQgY29kZSBpbnNpZGUgb2YgdGhlIGNvZGUgY2h1bmtzLgoKVGhlIHByaWNlIG9mIGRpYW1vbmRzIHJhbmdlZCBmcm9tIGByIHBhc3RlMCgiJCIsIGZvcm1hdChhcy5kb3VibGUocmFuZ2VfcHJpY2VfbG93KSwgbnNtYWxsID0gMikpYCB0byBgciBwYXN0ZTAoIiQiLCBmb3JtYXQoYXMuZG91YmxlKHJhbmdlX3ByaWNlX2hpZ2gpLCBuc21hbGwgPSAyLCBiaWcubWFyayA9ICIsIikpYCAoKk0qID0gYHIgcGFzdGUwKCIkIiwgZm9ybWF0KG1fcHJpY2UsIGJpZy5tYXJrID0gIiwiLCBuc21hbGwgPSAyKSlgLCAqU0QqID0gYHIgcGFzdGUwKCIkIixmb3JtYXQoc2RfcHJpY2UsIGJpZy5tYXJrPSAiLCIpKWApLgoKSW5zdGVhZCBvZiB0aGlzIG1lc3MsIHlvdSB3YW50IHRvIGZpcnN0IGNyZWF0ZSB5b3VyIHZhcmlhYmxlczoKCmBgYHtyfQpyYW5nZV9wcmljZV9sb3cgPC0gcmFuZ2UoZGlhbW9uZHMkcHJpY2UpWzFdICU+JQogIGFzLmRvdWJsZSgpICU+JSAjbWFrZXMgcmFuZ2VfcHJpY2VfbG93IGEgZG91YmxlIChyYXRoZXIgdGhhbiBhbiBpbnRlZ2VyKQogIGZvcm1hdChuc21hbGwgPSAyKSAlPiUgI2Zvcm1hdCBpdCB0byB0d28gZGVjaW1hbCBwbGFjZXMKICBwYXN0ZTAoIiQiLCAuKSAjYWRkIGEgZG9sbGFyIHNpZ24gYmVmb3JlIHRoZSBudW1iZXIKCnJhbmdlX3ByaWNlX2hpZ2ggPC0gcmFuZ2UoZGlhbW9uZHMkcHJpY2UpWzJdICU+JSAKICBhcy5kb3VibGUoKSAlPiUgCiAgZm9ybWF0KG5zbWFsbCA9IDIsIGJpZy5tYXJrID0gIiwiKSAlPiUgI2JpZy5tYXJrIGFkZHMgYSBjb21tYSBmb3IgbGFyZ2UgbnVtYmVycwogIHBhc3RlMCgiJCIsIC4pCgptX3ByaWNlIDwtIGRpYW1vbmRzJHByaWNlICU+JQogIG1lYW4oKSAlPiUgCiAgZm9ybWF0KG5zbWFsbCA9IDIsIGJpZy5tYXJrID0gIiwiKSAlPiUgCiAgcGFzdGUwKCIkIiwgLikKCnNkX3ByaWNlIDwtIGRpYW1vbmRzJHByaWNlICU+JQogIHNkKCkgJT4lIAogIGZvcm1hdChuc21hbGwgPSAyLCBiaWcubWFyayA9ICIsIikgJT4lIAogIHBhc3RlMCgiJCIsIC4pCgpgYGAKCkFuZCB0aGVuIHlvdSBjYW4gcHJpbnQgeW91ciBzZW50ZW5jZTogVGhlIHByaWNlIG9mIGRpYW1vbmRzIHJhbmdlZCBmcm9tIGByIHJhbmdlX3ByaWNlX2xvd2AgdG8gYHIgcmFuZ2VfcHJpY2VfaGlnaGAgKCpNKiA9IGByIG1fcHJpY2VgLCAqU0QqID0gYHIgc2RfcHJpY2VgKS4KCjxiciAvPgoKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIyMgQ3JlYXRpbmcgYSBmdW5jdGlvbgoKYGBge3J9CiNUbyByZW1vdmUgcmVkdW5kYW5jeSBpbiB5b3VyIGNvZGUsIHlvdSBtYXkgd2FudCB0byBjcmVhdGUgYSBmdW5jdGlvbiBpbnN0ZWFkCiNIZXJlIEkndmUgY3JlYXRlZCBhIGZ1bmN0aW9uIHdpdGggb25lIGFyZ3VtZW50ICJ4IiB0aGF0IGNvbnZlcnRzIG51bWJlcnMgaW50byBtb25leSBmb3JtYXR0ZWQgbnVtYmVycwptb25leV9mb3JtYXQgPC0gZnVuY3Rpb24oeCl7CiAgeCAlPiUKICBhcy5kb3VibGUoKSAlPiUgCiAgZm9ybWF0KG5zbWFsbCA9IDIsIGJpZy5tYXJrID0gIiwiKSAlPiUgCiAgcGFzdGUwKCIkIiwgLikKfQoKI3Rlc3RpbmcgdGhlIGZ1bmN0aW9uCm1vbmV5X2Zvcm1hdCgyMzk0ODIzNCkKCm1vbmV5X2Zvcm1hdCgyMykKCmRpYW1vbmRzJHByaWNlICU+JSAKICBtZWFuKCkgJT4lIAogIG1vbmV5X2Zvcm1hdCgpIApgYGAKCllvdXIgbmV3IGZ1bmN0aW9uIHdpbGwgd29yayBpbmxpbmUgdG9vOiBgciBtb25leV9mb3JtYXQoMzIzMzQpYAoKLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgojIFN0eWxlCgpBZnRlciB5b3UgY29tcGxldGUgYSBsb25nIGRheSBvZiBjb2RpbmcsIHlvdSBtYXkgcmVhbGl6ZSB0aGF0IHNvbWUgb2YgeW91ciBjb2RlIGlzIGRpZmZpY3VsdCB0byByZWFkLiBJbnN0YWxsaW5nIHRoZSBgc3R5bGVyYCBwYWNrYWdlIGNyZWF0ZXMgYW4gYEFkZGluYCAobG9jYXRlZCBpbiB0aGUgQWRkaW5zIG1lbnUgb24gdGhlIG1lbnUgYmFyKSB0aGF0IHdpbGwgYXBwbHkgdGhlIGB0aWR5YCBzdHlsZSBndWlkZSAoZnJvbSB0aGUgYHRpZHl2ZXJzZWApIHRvIHlvdXIgYSBzZWN0aW9uIG9yIGFsbCBvZiB5b3VyIGNvZGUuIFdoaWxlIHRoZSBjb250ZW50IG9mIHlvdXIgY29kZSB3aWxsIG5vdCBjaGFuZ2UsIGl0IHdpbGwgZG8gdGhpbmdzIHRvIG1ha2UgaXQgbW9yZSByZWFkYWJsZSwgc3VjaCBhcyBjcmVhdGUgbGluZSBicmVha3MgYWZ0ZXIgcGlwZXMgKGAlPiVgKQoKIyBLbml0dGluZyBlcnJvcnMKCktuaXR0aW5nIGVycm9ycyBhcmUgcGFydGljdWxhcmx5IGZydXN0cmF0aW5nIGVycm9yIG1lc3NhZ2VzIGlmIHlvdSB0aG91Z2h0IHlvdSB3ZXJlIGRvbmUgd2l0aCB5b3VyIHByb2plY3QgYW5kIHRoZSBjb2RlIGhhZCB3b3JrZWQgdXAgdG8gdGhlIHBvaW50IG9mIGtuaXR0aW5nLiBQbHVzLCB0aGUgbWVzc2FnZXMgY2FuIGJlIHZhZ3VlIGFuZCBjb25mdXNpbmcuIEhlcmUncyBvdXIgYWR2aWNlOgoKLSAgIEtuaXQgZWFybHkgYW5kIGtuaXQgb2Z0ZW4uIElmIHlvdSdyZSB3b3JraW5nIG9uIHRoZSBob21ld29yaywgaXQncyBhIGdvb2QgaWRlYSB0byBrbml0IGF0IGxlYXN0IG9uY2UgYWZ0ZXIgZXZlcnkgcHJvYmxlbS4KCi0gICBXaGVuIHlvdSBnZXQgYW4gZXJyb3IsIHlvdSBmaXJzdCB3YW50IHRvIHRyeSB0byBsb2NhdGUgd2hlcmUgdGhlIGVycm9yIGlzLiBJZiB5b3UgdGhpbmsgeW91IGZvdW5kIGl0LCB5b3UgY2FuIGNvbW1lbnQgb3V0IHRoZSBlbnRpcmUgY29kZSBjaHVuayBieSBoaWdobGlnaHRpbmcgdGhlIGNvZGUgYW5kIHR5cGluZyBgQ3RybCArIFNoaWZ0ICsgQ2AgKG9yIGBDbWQgKyBTaGlmdCArIENgIG9uIGEgTWFjKSwgb3IgeW91IGNhbiBjaGFuZ2UgdGhlIGNvZGUgY2h1bmsgb3B0aW9ucyB0byBgZXJyb3IgPSBUUlVFYC4gWW91IHNob3VsZCBiZSBhYmxlIHRvIGtuaXQgbm93IGlmIHRoZSBlcnJvciBtZXNzYWdlIGlzIGNvbWluZyBmcm9tIHRoZSBjb2RlIGNodW5rIHRoYXQgeW91IGp1c3QgZGlzYWJsZWQuIE90aGVyd2lzZSwgZGlzYWJsZSBtb3JlIGNvZGUgY2h1bmtzLCBvbmUgYXQgYSB0aW1lIHVudGlsIGl0IGtuaXRzLgoKLSAgIE9uY2UgeW91J3ZlIGVzdGFibGlzaGVkIHdoZXJlIHRoZSBlcnJvciBpcywgeW91IG1heSBzdGlsbCBub3QgdW5kZXJzdGFuZCB3aHkgdGhlIGNvZGUgaXNuJ3Qgd29ya2luZy4gVGhlIG1vc3QgY29tbW9uIHJlYXNvbnMgYXJlLi4uCgogICAgLSAgIFlvdXIgZGF0YSBzZXQgd2Fzbid0IGltcG9ydGVkIHByb3Blcmx5LgogICAgLSAgIFlvdSBoYXZlbid0IGxvYWRlZCB0aGUgcHJvcGVyIGxpYnJhcmllcyBhbmQgeW91IG5lZWQgdG8gYWRkIGF0IGxlYXN0IG9uZSBgbGlicmFyeSgpYCBjb21tYW5kLgogICAgLSAgIFlvdSBhcmUgcmVmZXJyaW5nIHRvIGEgdmFyaWFibGUgdGhhdCBoYXNuJ3QgYmVlbiBhc3NpZ25lZCB5ZXQuIEl0IHByb2JhYmx5IHdvcmtlZCBiZWZvcmUgYmVjYXVzZSBpdCB3YXMgYXNzaWduZWQgaW4geW91ciBnbG9iYWwgZW52aXJvbm1lbnQsIGJ1dCBpdCBuZWVkcyB0byBiZSBhc3NpZ25lZCBiZWZvcmUgdGhlIGxpbmUgb2YgY29kZSBpbiBvcmRlciBmb3IgaXQgdG8ga25pdC4KCi0gICBUaGUgZnVuY3Rpb24gYGtuaXRfZXhpdCgpYCB3aWxsIGV4aXQgdGhlIGtuaXR0aW5nIHByb2Nlc3Mgd2hlbiBydW4gaW5saW5lIG9yIGluIGEgY29kZSBjaHVuay4gSWYgeW91IGFyZSBkZWJ1Z2dpbmcgeW91ciBjb2RlLCB1c2luZyB0aGlzIHdpbGwgbGV0IHlvdSBleGFtaW5lIGxpbmUtYnktbGluZSB0byBpZGVudGlmeSB3aGVyZSB0aGUgcHJvYmxlbSBvcmlnaW5hdGVzLgoKIyMgQ2FjaGluZyBjb2RlCgpZb3UgbWF5IHJ1biBpbnRvIGNvZGUgdGhhdCB0YWtlcyAqZm9yZXZlciogdG8gcnVuLiBJdCBpcyBtb3N0IGNvbW1vbiB3aGVuIGltcG9ydGluZyBsYXJnZSAuY3N2IGZpbGVzIGJ1dCBtYXkgYXJpc2UgZWxzZXdoZXJlLiBJZiB5b3Ugc2V0IGBjYWNoZSA9IFRSVUVgIGluIHRoZSBjaHVuayBvcHRpb25zLCBpdCB3aWxsIHNhdmUgdGhlIGxhc3Qgb3V0cHV0IG9mIHRoYXQgY29kZSBjaHVuayBhbmQgbm90IHJlcnVuIGl0IHVudGlsIHRoZSBjb2RlIGlzIGVkaXRlZC4gSWYgeW91IHdhbnQgdG8gY2FjaGUgY2h1bmtzIHRoYXQgKmRlcGVuZCogb24gdGhlIGNhY2hlZCBjaHVuaywgaW5jbHVkZSB0aGUgYGRlcGVuZHNvbmAgYXJndW1lbnQuIFRoaXMgbGV0cyB5b3UgcmVmZXJlbmNlIHRoZSBjYWNoZWQgY2h1bmsgKCpoaW50KjogdGhpcyBpcyB3aHkgeW91IG1heSB3YW50IHRvIG5hbWUgY2h1bmtzISksIHdoaWNoIHdpbGwgcmVydW4gdGhhdCBjb2RlIGlmIHRoZSBwcmlvciBjYWNoZWQgY29kZSBpcyBlZGl0ZWQuCgpgYGB7ciBjYWNoZWQtY2h1bmt9CiN8IGNhY2hlID0gVFJVRQp4IDwtIDYwMAp4CgpgYGAKCmBgYHtyIGRlcGVuZGVudC1jaHVua30KI3wgY2FjaGUgPSBUUlVFCgp4ICsgNQoKYGBgCgpJZiB5b3UgZWRpdCB0aGUgYGNhY2hlZC1jaHVua2AgKGUuZy4sIGJ5IHJlcGxhY2luZyBgNTAwYCB3aXRoIGA2MDBgKSB0aGUgZGVwZW5kZW50LWNodW5rIHdvdWxkICpub3QqIHVwZGF0ZSBwcm9wZXJseS4gSG93ZXZlciwgaWYgeW91IGFkZCB0aGUgYXJndW1lbnQgYGRlcGVuZHNvbiA9IGNhY2hlZC1jaHVua2AgdG8gdGhlIGBkZXBlbmRlbnQtY2h1bmtgLCB0aGUgY2FjaGUgKndvdWxkKiB1cGRhdGUgYW55IHRpbWUgdGhlIGBjYWNoZWQtY2h1bmtgIGlzIGVkaXRlZC4KCi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKIyBNaW5paGFja3MKCj4gTWluaWhhY2sgYW5zd2VycyBjYW4gYmUgZm91bmQgW2hlcmVdKGh0dHBzOi8vdW9wc3ljaC5naXRodWIuaW8vcHN5NjExL2xhYnMvbGFiLTdfbWluaWhhY2tzLlJtZCkKCkZvciB0b2RheSdzIG1pbmloYWNrcywgeW91IHdpbGwgYmUgdXNpbmcgUk1hcmtkb3duIHRvIGNyZWF0ZSB5b3VyIG93biBodG1sIGZpbGUuCgoxLiAgT3BlbiB1cCBhIG5ldyBSTWFya2Rvd24gZmlsZSBhbmQgZXJhc2UgZXZlcnl0aGluZyBidXQgdGhlIFlBTUwuIEVkaXQgdGhlIFlBTUwgaW4gdGhlIGZvbGxvd2luZyB3YXlzOgogICAgLSAgIENoYW5nZSB0aGUgdGl0bGUgdG8gIkxhYiA3IE1pbmloYWNrcy4iCiAgICAtICAgUmVtb3ZlIHRoZSBhdXRob3IgYW5kIGRhdGUuCiAgICAtICAgVW5kZXIgb3V0cHV0LCBhZGQgYSB0YWJsZSBvZiBjb250ZW50cywgbnVtYmVyZWQgc2VjdGlvbnMsIGFuZCBjaG9vc2UgYSB0aGVtZS4gWW91IHNob3VsZCBiZSBvdXRwdXR0aW5nIHRvIGFuIGh0bWwgZmlsZS4gU29tZSBodG1sIHRoZW1lcyB5b3UgbWF5IHdhbnQgdG8gdHJ5IGFyZSBgY2VydWxlYW5gLCBgam91cm5hbGAsIGBmbGF0bHlgLCBgbHVtZW5gLCBgcGFwZXJgLCBhbmQgYHJlYWRhYmxlYC4KICAgIC0gICBLbml0IHRoZSBmaWxlLiBZb3Ugc2hvdWxkIG9ubHkgc2VlIHRoZSB0aXRsZS4gVGhlIGNvbG9yIGFuZCBmb250IHdpbGwgZGVwZW5kIG9uIHdoaWNoIHRoZW1lIHlvdSBjaG9zZS4KICAgIC0gKkhpbnQqIGlmIHlvdSBhcmUgaGF2aW5nIGlzc3VlcyBrbml0dGluZywgY2hlY2sgdGhhdCB0aGUgdGFicyBhbmQgc3BhY2VzIGFyZSBjb3JyZWN0bHkgZm9ybWF0dGVkCjIuICBDcmVhdGUgYSBuZXcgY29kZSBjaHVuayBhbmQgbG9hZCB0aGUgZm9sbG93aW5nIGxpYnJhcmllczogYHRpZHl2ZXJzZWAsIGBnZ3Bsb3QyYCwgYGthYmxlRXh0cmFgLCBgcmlvYCBhbmQgYGhlcmVgLgogICAgLSAgIENoYW5nZSB0aGUgZGVmYXVsdCBjaHVuayBvcHRpb24gc28gdGhhdCB0aGUgY29kZSBpcyBldmFsdWF0ZWQsIGJ1dCBuZWl0aGVyIHRoZSBjb2RlIG5vciBhbnkgcmVzdWx0aW5nIG1lc3NhZ2VzIHdpbGwgc2hvdyB1cCBpbiB5b3VyIHJlcG9ydC4gWW91IGNhbiBkbyB0aGlzIGFsbCBieSBjaGFuZ2luZyBvbmUgZGVmYXVsdCBvcHRpb24uCiAgICAtICAgSW4gdGhlIHNhbWUgY29kZSBjaHVuaywgdXNpbmcgdGhlIGByaW9gIGFuZCBgaGVyZWAgcGFja2FnZXMsIGltcG9ydCB0aGUgZGF0YSBzZXQgW3VzX2NvbnRhZ2lvdXNfZGlzZWFzZXMuY3N2XShyZXNvdXJjZXMvbGFiNy91c19jb250YWdpb3VzX2Rpc2Vhc2VzLmNzdikgYW5kIHN0b3JlIGl0IGluIGEgZGF0YSBmcmFtZSBjYWxsZWQgZGF0YS4KICAgIC0gICBGaW5hbGx5LCBpbiB0aGlzIGNvZGUgY2h1bmssIGFkZCB0aGUgY29kZSBgb3B0aW9ucyhzY2lwZW4gPSA5OTkpYCwgd2hpY2ggd2lsbCB0dXJuIG9mZiBzY2llbnRpZmljIG5vdGF0aW9uCjMuICBUaGUgYHVzX2NvbnRhZ2lvdXNfZGlzZWFzZXNgIGRhdGEgc2V0IGhhcyB0aGUgeWVhcmx5IGNvdW50cyBmb3Igc2V2ZW4gY29udGFnaW91cyBkaXNlYXNlcyBmb3IgdGhlIHllYXJzIDE5MjggLSAyMDExLiBJIGhhdmUgY3JlYXRlZCB0aHJlZSB0YWJsZXMgYW5kIGNhbGxlZCB0aGVtIGBkYXRhXzFgLCBgZGF0YV8yYCwgYW5kIGBkYXRhXzNgLgogICAgLSAgIENyZWF0ZSBhIG5ldyBsZXZlbCAxIGhlYWRlciBjYWxsZWQgIlRhYmxlcy4iCiAgICAtICAgVW5kZXIgdGhlIFRhYmxlcyBoZWFkZXIsIGNvcHkgYW5kIHBhc3RlIHRoZSB0aHJlZSBjaHVua3Mgb2YgY29kZSB3cml0dGVuIGJlbG93LgoKYGBge3IsIGV2YWwgPSBGQUxTRX0KZGF0YV8xIDwtIGRhdGEgJT4lIAogIGdyb3VwX2J5KGRpc2Vhc2UpICU+JSAKICBzdW1tYXJpc2Uoc3VtX2NvdW50ID0gc3VtKGNvdW50KSkgCgpkYXRhXzEgJT4lIAogIGtibCgpCmBgYAoKYGBge3IsIGV2YWwgPSBGQUxTRX0KZGF0YV8yIDwtIGRhdGEgJT4lIAogIGZpbHRlcihkaXNlYXNlID09ICJNZWFzbGVzIikgJT4lIAogIGdyb3VwX2J5KHllYXIpICU+JSAKICBzdW1tYXJpc2Uoc3VtX2NvdW50ID0gc3VtKGNvdW50KSkKCmRhdGFfMiAlPiUgCiAga2JsKCkKYGBgCgpgYGB7ciwgZXZhbCA9IEZBTFNFfQpkYXRhXzMgPC0gZGF0YSAlPiUgCiAgZmlsdGVyKGRpc2Vhc2UgPT0gIk1lYXNsZXMiICYgeWVhciA9PSAiMTkzOCIpICU+JQogIG11dGF0ZShwZXJfbWVhc2xlcyA9IGNvdW50L3BvcHVsYXRpb24gKiAxMDApICU+JSAKICBzZWxlY3Qoc3RhdGUsIGNvdW50LCBwb3B1bGF0aW9uLCBwZXJfbWVhc2xlcykgCgpkYXRhXzMgJT4lIAogIGtibCgpCmBgYAoKLSAgIENyZWF0ZSB0aHJlZSBzdWJoZWFkZXJzICJUYWJsZSAxIiwgIlRhYmxlIDIiLCBhbmQgIlRhYmxlIDMiIGJldHdlZW4gdGhlIGNvZGUgY2h1bmtzIHNvIHRoYXQgZWFjaCBjb2RlIGNodW5rIGlzIHVuZGVyIHRoZSByZXNwZWN0aXZlIHN1YmhlYWRlci4KICAgIC0gICBOb3csIGVkaXQgdGhlIGNvZGUgdG8gbWFrZSBiZXR0ZXIgdGFibGVzLiBVc2luZyB0aGUgYGthYmxlRXh0cmFgIHBhY2thZ2UsIGZvciBlYWNoIHRhYmxlLCBhZGQgYSB0YWJsZSB0aXRsZSBhbmQgZWRpdCB0aGUgY29sdW1uIG5hbWVzLgogICAgLSAgIEZvciBlYWNoIHRhYmxlLCBjaGFuZ2UgdGhlIHRhYmxlIGZvcm1hdCB0byBjbGFzc2ljIHdpdGggdGhlIGBrYWJsZV9jbGFzc2ljYCBmdW5jdGlvbi4KICAgIC0gICBGb3IgdGhlIHNlY29uZCBhbmQgdGhpcmQgdGFibGVzLCB0cnkgdXNpbmcgdGhlIGBrYWJsZUV4dHJhOjpzY3JvbGxfYm94YCBmdW5jdGlvbiB0byBsaW1pdCB0aGUgYW1vdW50IG9mIHNwYWNlIGl0IHRha2VzIHVwLgogICAgLSAgIEZvciB0aGUgdGhpcmQgdGFibGUsIGhpZ2hsaWdodCB0aGUgT3JlZ29uIHJvdyAocm93IDM4KS4KICAgIC0gICBDaGFuZ2UgdGhlIGNodW5rIG9wdGlvbnMgb24gdGhlIHRhYmxlcyBzbyB0aGF0IHlvdSBjYW4gb25seSBzZWUgdGhlIHRhYmxlcyAobm90IHRoZSBjb2RlKS4KICAgIC0gICBLbml0IHRvIG1ha2Ugc3VyZSB0aGF0IGV2ZXJ5dGhpbmcgc2hvd3MgdXAgaG93IHlvdSB3YW50IGl0LgoKNC4gIENyZWF0ZSBhICoqdGFiYmVkKiogc2VjdGlvbiBjYWxsZWQgIkZpZ3VyZXMiLiBZb3Ugc2hvdWxkIGhhdmUgdGhyZWUgdGFiczogIkZpZ3VyZSAxIiwgIkZpZ3VyZSAyIiBhbmQgIkZpZ3VyZSAzIi4KICAgIC0gICBDb3B5IGFuZCBwYXN0ZSB0aGUgY29kZSBmb3IgdGhlc2UgdGhyZWUgZmlndXJlcyBpbnRvIHlvdXIgUk1hcmtkb3duIGZpbGUuCgpgYGB7ciwgZXZhbCA9IEZBTFNFfQpkYXRhXzEgJT4lIAogIGdncGxvdChhZXMoeCA9IGRpc2Vhc2UsIHkgPSBzdW1fY291bnQpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIGxhYnMoeCA9ICJUeXBlIG9mIGRpc2Vhc2UiLCB5PSAiRGVhdGggY291bnQiKSArIAogIGNvb3JkX2ZsaXAoKQpgYGAKCmBgYHtyLCBldmFsID0gRkFMU0V9CmRhdGFfMiAlPiUgCiAgZ2dwbG90KGFlcyh4ID0geWVhciwgeSA9IHN1bV9jb3VudCkpICsKICBnZW9tX3BvaW50KCkgKwogIHRoZW1lX21pbmltYWwoKSArCiAgbGFicyh4ID0gIlllYXIiLCB5PSAiRGVhdGggY291bnQiKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMTk2MywgY29sb3IgPSAicmVkIiwgbGluZXR5cGUgPSAiZGFzaGVkIikgKyAKICBnZW9tX3RleHQoeCA9IDE5ODAsIHkgPSA2MDAwMDAsIGxhYmVsID0gIlZhY2NpbmUgaW52ZW50ZWQgaW4gMTk2MyIsIAogICAgICAgICAgICBjb2xvciA9ICJyZWQiKQpgYGAKCmBgYHtyLCBldmFsID0gRkFMU0V9CiNpbnN0YWxsLnBhY2thZ2VzKCJtYXBzIikKbGlicmFyeShtYXBzKQpkYXRhXzMgPC0gZGF0YV8zICU+JSAKICBtdXRhdGUocmVnaW9uID0gdG9sb3dlcihzdGF0ZSkpCnN0YXRlc19tYXAgPC0gbWFwX2RhdGEoInN0YXRlIikKZGlzZWFzZV9tYXAgPC0gbGVmdF9qb2luKHN0YXRlc19tYXAsIGRhdGFfMywgYnkgPSAicmVnaW9uIikKZ2dwbG90KGRpc2Vhc2VfbWFwLCBhZXMobG9uZywgbGF0LCBncm91cD0gZ3JvdXApKSArCiAgZ2VvbV9wb2x5Z29uKGFlcyhmaWxsID0gcGVyX21lYXNsZXMpLCBjb2xvciA9ICJ3aGl0ZSIpICsKICBsYWJzKGZpbGwgPSAiJSBNZWFzbGVzIikgKwogIHRoZW1lX21pbmltYWwoKQpgYGAKCi0gICBOZXh0LAoKICAgIC0gICBDaGFuZ2UgdGhlIGRlZmF1bHQgY2h1bmsgb3B0aW9ucyBzbyB0aGF0IHlvdSBjYW4gb25seSBzZWUgdGhlIGZpZ3VyZXMgKG5vIGNvZGUpLgoKICAgIC0gICBVc2UgY2h1bmsgb3B0aW9ucyB0byBjaGFuZ2UgdGhlIHdpZHRocyBvZiB0aGUgZmlndXJlcyB0byA4IGluY2hlcy4KCiAgICAtICAgS25pdCBhbmQgZmFtaWxpYXJpemUgeW91cnNlbGYgd2l0aCB3aGF0IGluZm9ybWF0aW9uIHRoZXNlIGdyYXBocyBhcmUgcHJlc2VudGluZy4KCjUuICBDcmVhdGUgb25lIGxhc3QgbGV2ZWwgMSBoZWFkZXIgY2FsbGVkICJRdWVzdGlvbnMiLiBDcmVhdGUgdGhyZWUgc3ViaGVhZGluZ3MgIlF1ZXN0aW9uIDEiLCAiUXVlc3Rpb24gMiIsIGFuZCAiUXVlc3Rpb24gMyIuICoqVXNpbmcgaW4tbGluZSBjb2RlKiosIGFuc3dlciB0aGUgZm9sbG93aW5nIHF1ZXN0aW9ucyB1bmRlciB0aGUgcmVzcGVjdGl2ZSBzdWJoZWFkaW5nOgogICAgLSAgIFF1ZXN0aW9uIDEpIE1lYXNsZXMgaGFkIHRoZSBoaWdoZXN0IG51bWJlciBvZiBpbmZlY3Rpb25zIGluIHRoZSBVUyBkdXJpbmcgdGhpcyB0aW1lIHNwYW4uIFdoYXQgd2FzIHRoZSBudW1iZXIgb2YgaW5mZWN0aW9ucz8gQW5zd2VyIHRoaXMgcXVlc3Rpb24gdXNpbmcgYGRhdGFfMWAuCiAgICAtICAgUXVlc3Rpb24gMikgV2hhdCB3YXMgdGhlIGF2ZXJhZ2UgbnVtYmVyIG9mIE1lYXNsZXMgY2FzZXMgcGVyIHllYXIgaW4gdGhlIFVTIGZyb20gMTkyOCB0byAyMDExPyBSb3VuZCB0aGlzIG51bWJlciB0byB0d28gZGVjaW1hbCBwbGFjZXMuIEFuc3dlciB0aGlzIHF1ZXN0aW9uIHVzaW5nIGBkYXRhXzJgLgogICAgLSAgIFF1ZXN0aW9uIDMpIEluIDE5MzgsIFdpc2NvbnNpbiBoYWQgdGhlIGhpZ2hlc3QgbnVtYmVyIG9mIE1lYXNsZXMgY2FzZXMgcGVyIGNhcGl0YS4gV2hhdCBwZXJjZW50IG9mIFdpc2NvbnNpbidzIHBvcHVsYXRpb24gY29udHJhY3RlZCBNZWFzbGVzIGluIDE5Mzg/IEFuc3dlciB0aGlzIHF1ZXN0aW9uIHVzaW5nIGBkYXRhXzNgLgoKIyMgCg==