diff --git a/tutorial/tour-of-the-tidyverse.Rmd b/tutorial/tour-of-the-tidyverse.Rmd index 67ca7d1..9a23f41 100644 --- a/tutorial/tour-of-the-tidyverse.Rmd +++ b/tutorial/tour-of-the-tidyverse.Rmd @@ -176,51 +176,65 @@ penguins %>% ## group_by() and summarize() Summarizing the data using `group_by()` and `summarize()` + +We can use `group_by()` to group our data by **species** and **sex**, and `summarize()` to calculate the average **body_mass_g** for each grouping. ```{r group-by-summarize} +penguins %>% + select(species, sex, body_mass_g) %>% + group_by(species, sex) %>% + summarize(mean = mean(body_mass_g)) +``` + +## count() and add_count() +If we're just interested in _counting_ the observations in each grouping, we can group and summarize with special functions `count()` and `add_count()`. + +Counting can be done with `group_by()` and `summarize()`, but it's a little cumbersome. + +It involves... +1. using `mutate()` to create an intermediate variable **n_species** that adds up all observations per **species**, and +2. an `ungroup()`-ing step + +```{r} penguins %>% - group_by(species, sex) %>% + group_by(species) %>% + mutate(n_species = n()) %>% + ungroup() %>% + group_by(species, sex, n_species) %>% summarize(n = n()) ``` -## count() and add_count() -Because we're just _counting_ observations in this example, we also have the option to use `count()` which simplifies our code a little. +In contrast, `count()` and `add_count()` offer a simplified approach. -> Thank you to Alison Hill for [these suggestions](https://github.com/spcanelon/2020-rladies-chi-tidyverse/issues/2)! +> Thank you to Alison Hill for [this suggestion](https://github.com/spcanelon/2020-rladies-chi-tidyverse/issues/2)! ```{r count} -penguins %>% - count(species, sex) +penguins %>% + count(species, sex) %>% + add_count(species, wt = n, + name = "n_species") ``` ## mutate() +We can add to our counting example by using `mutate()` to create a new variable **prop**, which represents the proportion of penguins of each **sex**, grouped by **species** -### Option 1 -Creating new variables with `mutate()` -```{r group-by-summarize-mutate} -penguins %>% - group_by(species) %>% - mutate(n_species = n()) %>% - ungroup() %>% - group_by(species, sex, n_species) %>% - summarize(n = n()) %>% - mutate(prop = n/n_species*100) -``` +> Thank you to Alison Hill for [this suggestions](https://github.com/spcanelon/2020-rladies-chi-tidyverse/issues/2)! -### Option 2 -We can also use `mutate()` along with `add_count()` to add up the counts per species group to use as a denominator ("n_species") when we calculate the proportion by sex. -```{r count-mutate} +```{r} penguins %>% count(species, sex) %>% - add_count(species, wt = n, name = "n_species") %>% - mutate(prop = n/n_species*100) + add_count(species, wt = n, + name = "n_species") %>% + mutate(prop = n/n_species*100) ``` + ## filter() -Regardless of which approach we take to summarize our data, we can proceed to filtering rows by adding on a filtering step to our pipeline using `filter()` +Finally, we can filter rows to only show us **Chinstrap** penguin summaries by adding `filter()` to our pipeline ```{r filter} penguins %>% count(species, sex) %>% - add_count(species, wt = n, name = "n_species") %>% + add_count(species, wt = n, + name = "n_species") %>% mutate(prop = n/n_species*100) %>% filter(species == "Chinstrap") ``` diff --git a/tutorial/tour-of-the-tidyverse.nb.html b/tutorial/tour-of-the-tidyverse.nb.html index dde20d4..1f87c3b 100644 --- a/tutorial/tour-of-the-tidyverse.nb.html +++ b/tutorial/tour-of-the-tidyverse.nb.html @@ -3011,9 +3011,6 @@

First created on Aug 31, 2020 (updated on Sept 22, 2020)

- -
knitr::opts_chunk$set(message = FALSE, warning = FALSE, collapse = TRUE)
-
@@ -3025,8 +3022,8 @@

About {palmerpenguins}

-
# install.packages("remotes")
-# remotes::install_github("allisonhorst/palmerpenguins")
+
# install.packages("remotes")
+# remotes::install_github("allisonhorst/palmerpenguins")
@@ -3035,14 +3032,6 @@

About {palmerpenguins}

Loading packages

- -
# loading packages
-library(tidyverse)
-library(palmerpenguins)
-
-# viewing data sets in package "palmerpenguins"
-data(package = "palmerpenguins")
-
@@ -3051,13 +3040,6 @@

readr

Let’s get data into R!

- -
# option 1: load using URL ----
-raw_adelie_url <- read_csv("https://portal.edirepository.org/nis/dataviewer?packageid=knb-lter-pal.219.3&entityid=002f3893385f710df69eeebe893144ff")
-
-# option 2: load using filepath ----
-raw_adelie_filepath <- read_csv("raw_adelie.csv")
-

Lucky for us, Allison Horst compiled data from all three species together for us in the {palmerpenguins} package!

@@ -3067,14 +3049,6 @@

readr

- -
# saves package tibble into global environment
-penguins <- palmerpenguins::penguins 
-head(penguins)
-
-penguins_raw <- palmerpenguins::penguins_raw
-head(penguins_raw)
- @@ -3083,12 +3057,6 @@

tibble

A tibble is much like the data frame in base R, but optimized for use in the Tidyverse. Let’s take a look at the differences.

- -
# try each of these commands in the console and see if you can spot the differences!
-
-as_tibble(penguins)
-as.data.frame(penguins)
- @@ -3106,9 +3074,6 @@

What differences do you see?

Try it out here!

- -
vignette("tibble")
-
@@ -3116,17 +3081,11 @@

Taking a closer look at penguins

Get a full view of the dataset:

- -
View(penguins)
-

Or catch a glimpse:

- -
glimpse(penguins)
-
@@ -3139,33 +3098,6 @@

ggplot2

Let’s see if body mass varies by penguin sex

- -
penguins %>%
-  ggplot()
-
-penguins %>%
-  ggplot(aes(x = sex, y = body_mass_g))
-
-penguins %>%
-  ggplot(aes(x = sex, y = body_mass_g)) +
-  geom_point()
-
-# A scatter plot doesn't really tell us much.
-# Let's try a different geometry
-
-penguins %>%
-  ggplot(aes(x = sex, y = body_mass_g)) +
-  geom_boxplot()
-
-# That's more informative!
-# Let's see if there are differences by penguin species
-
-penguins %>%
-  ggplot(aes(x = sex, y = body_mass_g)) +
-  geom_boxplot(aes(fill = species))
-
-# What do you notice?
- @@ -3186,9 +3118,6 @@

What observations can you make from the plot?

dplyr

- -
glimpse(penguins)
-
@@ -3196,10 +3125,6 @@

select()

Selecting dataset columns with select()

- -
penguins %>%
-  select(species, sex, body_mass_g)
-
@@ -3208,88 +3133,66 @@

arrange()

Reordering the data set with arrange()

- -
penguins %>%
-  select(species, sex, body_mass_g) %>%
-  arrange(desc(body_mass_g))
-

group_by() and summarize()

Summarizing the data using group_by() and summarize()

+

We can use group_by() to group our data by species and sex, and summarize() to calculate the average body_mass_g for each grouping.

- -
penguins %>% 
-  group_by(species, sex) %>%
-  summarize(n = n())
+ +
penguins %>%
+  select(species, sex, body_mass_g) %>%
+  group_by(species, sex) %>%         
+  summarize(mean = mean(body_mass_g))

count() and add_count()

-

Because we’re just counting observations in this example, we also have the option to use count() which simplifies our code a little.

-
-

Thank you to Alison Hill for these suggestions!

-
+

If we’re just interested in counting the observations in each grouping, we can group and summarize with special functions count() and add_count().

+

Counting can be done with group_by() and summarize(), but it’s a little cumbersome.

+

It involves… 1. using mutate() to create an intermediate variable n_species that adds up all observations per species, and 2. an ungroup()-ing step

- -
penguins %>%
-  count(species, sex)
+ +
penguins %>% 
+  group_by(species) %>%
+  mutate(n_species = n()) %>%            
+  ungroup() %>%                          
+  group_by(species, sex, n_species) %>%
+  summarize(n = n())
-
-
-

mutate()

-
-

Option 1

-

Creating new variables with mutate()

+

In contrast, count() and add_count() offer a simplified approach.

+
+

Thank you to Alison Hill for this suggestion!

+
- -
penguins %>% 
-  group_by(species) %>%
-  mutate(n_species = n()) %>%
-  ungroup() %>%
-  group_by(species, sex, n_species) %>%
-  summarize(n = n()) %>%
-  mutate(prop = n/n_species*100)
-
-
-

Option 2

-

We can also use mutate() along with add_count() to add up the counts per species group to use as a denominator (“n_species”) when we calculate the proportion by sex.

+
+

mutate()

+

We can add to our counting example by using mutate() to create a new variable prop, which represents the proportion of penguins of each sex, grouped by species

+
+

Thank you to Alison Hill for this suggestions!

+
- -
penguins %>% 
-  count(species, sex) %>%
-  add_count(species, wt = n, name = "n_species") %>%
-  mutate(prop = n/n_species*100)
-
-

filter()

-

Regardless of which approach we take to summarize our data, we can proceed to filtering rows by adding on a filtering step to our pipeline using filter()

+

Finally, we can filter rows to only show us Chinstrap penguin summaries by adding filter() to our pipeline

- -
penguins %>% 
-  count(species, sex) %>%
-  add_count(species, wt = n, name = "n_species") %>%
-  mutate(prop = n/n_species*100) %>%
-  filter(species == "Chinstrap")
-
@@ -3301,30 +3204,16 @@

forcats

The factor() function is perfect for this.

- -
penguins %>%
-  mutate(year_factor = factor(year, levels = unique(year)))
-

The result is a new factor year_factor with levels 2007, 2008 and 2009!

- -
penguins_new <-
-  penguins %>%
-  mutate(year_factor = factor(year, levels = unique(year)))
-penguins_new
-

Double check the variable class and factor levels below:

- -
class(penguins_new$year_factor)
-levels(penguins_new$year_factor)
-
@@ -3334,22 +3223,11 @@

stringr

From what we’ve learned so far, take a guess at what this code chunk will do before running it.

- -
penguins %>%
-  select(species, island) %>%
-  mutate(ISLAND = str_to_upper(island))
-

How about this one? How is it different from the previous code chunk?

- -
penguins %>%
-  select(species, island) %>%
-  mutate(ISLAND = str_to_upper(island)) %>%
-  mutate(species_island = str_c(species, ISLAND, sep = "_"))
- @@ -3359,24 +3237,11 @@

tidyr

We can pretend that it wasn’t and that body_mass_g was recorded separately for male, female, and sex NA penguins. Like untidy_penguins below:

- -
untidy_penguins <-
-  penguins %>%
-    pivot_wider(names_from = sex,
-                values_from = body_mass_g)
-untidy_penguins
-

Now let’s make it tidy again with the help of the pivot_longer() function! pivot_wider()is another very popular tidying function. Have you seen it before? Hint: see the code chunk above!

- -
untidy_penguins %>%
-  pivot_longer(cols = male:`NA`, 
-               names_to = "sex",
-               values_to = "body_mass_g")
- @@ -3388,59 +3253,25 @@

purrr

Let’s turn this plot:

- -
penguins %>%
-  ggplot(aes(x = sex, y = body_mass_g)) +
-  geom_boxplot(aes(fill = species))
-

Into this one!

- -
penguins %>%
-  ggplot(aes(x = sex, y = body_mass_g)) +
-  geom_boxplot(aes(fill = species)) +
-  scale_fill_manual(values = nord::nord_palettes$frost)
-

Let’s try out the frost palette.

- -
# we'll need to load the {nord} package
-library(nord)
-
-# you can choose colors using the color hex codes
-nord::nord_palettes$frost
- - -
# but you might prefer to use `scale_fill_manual()` 
-# or more specialized functions like `scale_fill_nord()` 
-# included in the {nord} package
-penguins %>%
-  ggplot(aes(x = sex, y = body_mass_g)) +
-  geom_boxplot(aes(fill = species)) +
-  scale_fill_manual(values = nord::nord_palettes$frost)
-  #scale_fill_nord(palette = "frost")
-

Ok now for a handy package/function trio!

- -
# we'll have to load the {prismatic} package
-library(prismatic)
-
-prismatic::color(nord::nord_palettes$frost)
-

purrr’s map() function can help us iterate the prismatic::color() function over all palettes in a palette package like nord!

@@ -3450,7 +3281,7 @@

purrr

-
nord::nord_palettes %>% map(prismatic::color)
+
nord::nord_palettes %>% map(prismatic::color)
@@ -3466,71 +3297,14 @@

Recreating a {palmerpenguins} plot

- -
# scatterplot sequence ----
-penguins %>%
-  ggplot() + 
-  geom_point(aes(x = flipper_length_mm, y = bill_length_mm)) # add aesthetics
-
-penguins %>%
-  ggplot() +
-  geom_point(aes(x = flipper_length_mm, y = bill_length_mm, 
-                 color = species)) # add color per species
-
-penguins %>%
-  ggplot() +
-  geom_point(aes(x = flipper_length_mm, y = bill_length_mm, 
-                 color = species, shape = species)) # add shape per species
-
-penguins %>%
-  ggplot() +
-  geom_point(aes(x = flipper_length_mm, y = bill_length_mm, 
-                 color = species, shape = species)) # add shape per species
-
-penguins %>%
-  ggplot() +
-  geom_point(aes(x = flipper_length_mm, y = bill_length_mm, 
-                 color = species, shape = species)) +
-  geom_smooth(aes(x = flipper_length_mm, y = bill_length_mm, 
-                  color = species))
-
-penguins %>%
-  ggplot(aes(x = flipper_length_mm, y = bill_length_mm)) + 
-  geom_point(aes(color = species, shape = species)) +
-  geom_smooth(aes(color = species), se = FALSE, method = "lm")
- - -
penguins %>%
-  ggplot() +
-  geom_point(aes(x = flipper_length_mm, y = body_mass_g, 
-                 color = species, shape = species))
- - -
penguins %>%
-  ggplot() +
-  geom_histogram(aes(x = flipper_length_mm))
-
-penguins %>%
-  ggplot() +
-  geom_histogram(aes(x = flipper_length_mm, color = species))
-
-penguins %>%
-  ggplot() +
-  geom_histogram(aes(x = flipper_length_mm, fill = species))
-
-penguins %>%
-  ggplot() +
-  geom_histogram(aes(x = flipper_length_mm, fill = species, 
-                     position = "identity", alpha = 0.5))
- @@ -3553,19 +3327,19 @@

tidytuesdayR

-
# install.packages("tidytuesdayR")
-# remotes::install_github("thebioengineer/tidytuesdayR")
-
-library(tidytuesdayR)
-
-# load the data
-tt_data <- tt_load("2020-07-27") # error message
-tt_data <- tt_load("2020-07-28")
-tt_data <- tt_load(2020, week=31)
-
-# take a peek
-readme(tt_data)
-print(tt_data)
+
# install.packages("tidytuesdayR")
+# remotes::install_github("thebioengineer/tidytuesdayR")
+
+library(tidytuesdayR)
+
+# load the data
+tt_data <- tt_load("2020-07-27") # error message
+tt_data <- tt_load("2020-07-28")
+tt_data <- tt_load(2020, week=31)
+
+# take a peek
+readme(tt_data)
+print(tt_data)
@@ -3594,7 +3368,7 @@

Examples

-
LS0tCnRpdGxlOiAiQW4gQW50YXJjdGljIFRvdXIgb2YgdGhlIFRpZHl2ZXJzZSIKYXV0aG9yOiAiU2lsdmlhIFAuIENhbmVsw7NuLCBQaEQgKEBzcGNhbmVsb24pIgpkYXRlOiAiRmlyc3QgY3JlYXRlZCBvbiBBdWcgMzEsIDIwMjAgKHVwZGF0ZWQgb24gU2VwdCAyMiwgMjAyMCkiCmluc3RpdHV0ZTogIlVuaXZlcnNpdHkgb2YgUGVubnN5bHZhbmlhIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIGZpZ193aWR0aDogNy4yCiAgICBoaWdobGlnaHQ6IHB5Z21lbnRzCiAgICBudW1iZXJfc2VjdGlvbnM6IG5vCiAgICB0aGVtZTogbHVtZW4KICAgIHRvYzogeWVzCiAgICB0b2NfZmxvYXQ6IHllcwogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IHllcwogICAgZGZfcHJpbnQ6IHBhZ2VkCi0tLQoKYGBge3J9CmtuaXRyOjpvcHRzX2NodW5rJHNldChtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSwgY29sbGFwc2UgPSBUUlVFKQpgYGAKCiMgQWJvdXQge3BhbG1lcnBlbmd1aW5zfQotIFt7cGFsbWVycGVuZ3VpbnN9IERvY3VtZW50YXRpb25dKGh0dHBzOi8vYWxsaXNvbmhvcnN0LmdpdGh1Yi5pby9wYWxtZXJwZW5ndWlucy8pCi0gW0FsbGlzb24gSG9yc3QncyBHaXRIdWIgcmVwbyBmb3IgUGFsbWVyIFBlbmd1aW5zIGRhdGFzZXRdKGh0dHBzOi8vZ2l0aHViLmNvbS9hbGxpc29uaG9yc3QvcGFsbWVycGVuZ3VpbnMpCgpgYGB7ciwgZXZhbCA9IEZBTFNFfQojIGluc3RhbGwucGFja2FnZXMoInJlbW90ZXMiKQojIHJlbW90ZXM6Omluc3RhbGxfZ2l0aHViKCJhbGxpc29uaG9yc3QvcGFsbWVycGVuZ3VpbnMiKQpgYGAKCiMgTG9hZGluZyBwYWNrYWdlcwpgYGB7cn0KIyBsb2FkaW5nIHBhY2thZ2VzCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHBhbG1lcnBlbmd1aW5zKQoKIyB2aWV3aW5nIGRhdGEgc2V0cyBpbiBwYWNrYWdlICJwYWxtZXJwZW5ndWlucyIKZGF0YShwYWNrYWdlID0gInBhbG1lcnBlbmd1aW5zIikKYGBgCgojIHJlYWRyIAoKTGV0J3MgZ2V0IGRhdGEgaW50byBSIQoKYGBge3J9CiMgb3B0aW9uIDE6IGxvYWQgdXNpbmcgVVJMIC0tLS0KcmF3X2FkZWxpZV91cmwgPC0gcmVhZF9jc3YoImh0dHBzOi8vcG9ydGFsLmVkaXJlcG9zaXRvcnkub3JnL25pcy9kYXRhdmlld2VyP3BhY2thZ2VpZD1rbmItbHRlci1wYWwuMjE5LjMmZW50aXR5aWQ9MDAyZjM4OTMzODVmNzEwZGY2OWVlZWJlODkzMTQ0ZmYiKQoKIyBvcHRpb24gMjogbG9hZCB1c2luZyBmaWxlcGF0aCAtLS0tCnJhd19hZGVsaWVfZmlsZXBhdGggPC0gcmVhZF9jc3YoInJhd19hZGVsaWUuY3N2IikKYGBgCgpMdWNreSBmb3IgdXMsIEFsbGlzb24gSG9yc3QgY29tcGlsZWQgZGF0YSBmcm9tIGFsbCB0aHJlZSBzcGVjaWVzIHRvZ2V0aGVyIGZvciB1cyBpbiB0aGUgYHtwYWxtZXJwZW5ndWluc31gIHBhY2thZ2UhCgotIGBwZW5ndWluc2AgY29udGFpbnMgYSBjbGVhbiBkYXRhc2V0LCBhbmQKLSBgcGVuZ3VpbnNfcmF3YCBjb250YWlucyByYXcgZGF0YQoKYGBge3J9CiMgc2F2ZXMgcGFja2FnZSB0aWJibGUgaW50byBnbG9iYWwgZW52aXJvbm1lbnQKcGVuZ3VpbnMgPC0gcGFsbWVycGVuZ3VpbnM6OnBlbmd1aW5zIApoZWFkKHBlbmd1aW5zKQoKcGVuZ3VpbnNfcmF3IDwtIHBhbG1lcnBlbmd1aW5zOjpwZW5ndWluc19yYXcKaGVhZChwZW5ndWluc19yYXcpCmBgYAoKIyB0aWJibGUgCgpBIGB0aWJibGVgIGlzIG11Y2ggbGlrZSB0aGUgYGRhdGEgZnJhbWVgIGluIGJhc2UgUiwgYnV0IG9wdGltaXplZCBmb3IgdXNlIGluIHRoZSBUaWR5dmVyc2UuIExldCdzIHRha2UgYSBsb29rIGF0IHRoZSBkaWZmZXJlbmNlcy4KCmBgYHtyIHRpYmJsZX0KIyB0cnkgZWFjaCBvZiB0aGVzZSBjb21tYW5kcyBpbiB0aGUgY29uc29sZSBhbmQgc2VlIGlmIHlvdSBjYW4gc3BvdCB0aGUgZGlmZmVyZW5jZXMhCgphc190aWJibGUocGVuZ3VpbnMpCmFzLmRhdGEuZnJhbWUocGVuZ3VpbnMpCmBgYAoKIyBXaGF0IGRpZmZlcmVuY2VzIGRvIHlvdSBzZWU/CllvdSBtaWdodCBzZWUgYSB0aWJibGUgcHJpbnRzOgoKLSB2YXJpYWJsZSBjbGFzc2VzCi0gb25seSAxMCByb3dzCi0gb25seSBhcyBtYW55IGNvbHVtbnMgYXMgY2FuIGZpdCBvbiB0aGUgc2NyZWVuCi0gTkFzIGFyZSBoaWdobGlnaHRlZCBpbiBjb25zb2xlIHNvIHRoZXkncmUgZWFzeSB0byBzcG90IChmb250IGhpZ2hsaWdodGluZyBhbmQgc3R5bGluZyBpbiBgdGliYmxlYCkKCk5vdCBzbyBtdWNoIGEgY29uY2VybiBpbiBhbiBSIE1hcmtkb3duIGZpbGUsIGJ1dCBub3RpY2VhYmxlIGluIHRoZSBjb25zb2xlLiBQcmludCBtZXRob2QgbWFrZXMgaXQgZWFzaWVyIHRvIHdvcmsgd2l0aCBsYXJnZSBkYXRhc2V0cy4KClRoZXJlIGFyZSBhIGNvdXBsZSBvZiBvdGhlciBtYWluIGRpZmZlcmVuY2VzLCBuYW1lbHkgaW4gKipzdWJzZXR0aW5nKiogYW5kICoqcmVjeWNsaW5nKiouIENoZWNrIHRoZW0gb3V0IGluIHRoZSBbYHZpZ25ldHRlKCJ0aWJibGUiKV0oaHR0cHM6Ly90aWJibGUudGlkeXZlcnNlLm9yZy9hcnRpY2xlcy90aWJibGUuaHRtbCkKClRyeSBpdCBvdXQgaGVyZSEKYGBge3IgdGliYmxlLXZpZ25ldHRlfQp2aWduZXR0ZSgidGliYmxlIikKYGBgCgoKIyMgVGFraW5nIGEgY2xvc2VyIGxvb2sgYXQgYHBlbmd1aW5zYAoKR2V0IGEgZnVsbCB2aWV3IG9mIHRoZSBkYXRhc2V0OgpgYGB7ciBwZW5ndWlucy12aWV3fQpWaWV3KHBlbmd1aW5zKQpgYGAKCk9yIGNhdGNoIGEgYGdsaW1wc2VgOgpgYGB7ciBwZW5ndWlucy1nbGltcHNlfQpnbGltcHNlKHBlbmd1aW5zKQpgYGAKCiMgZ2dwbG90MiAKCkxldCdzIHN0YXJ0IGJ5IG1ha2luZyBhIHNpbXBsZSBwbG90IG9mIG91ciBkYXRhIQoKYGdncGxvdDJgIHVzZXMgdGhlICJHcmFtbWFyIG9mIEdyYXBoaWNzIiBhbmQgbGF5ZXJzIGdyYXBoaWNhbCBjb21wb25lbnRzIHRvZ2V0aGVyIHRvIGNyZWF0ZSBhIHBsb3QuCgojIyBMZXQncyBzZWUgaWYgYm9keSBtYXNzIHZhcmllcyBieSBwZW5ndWluIHNleAoKYGBge3IgZ2dwbG90Mn0KcGVuZ3VpbnMgJT4lCiAgZ2dwbG90KCkKCnBlbmd1aW5zICU+JQogIGdncGxvdChhZXMoeCA9IHNleCwgeSA9IGJvZHlfbWFzc19nKSkKCnBlbmd1aW5zICU+JQogIGdncGxvdChhZXMoeCA9IHNleCwgeSA9IGJvZHlfbWFzc19nKSkgKwogIGdlb21fcG9pbnQoKQoKIyBBIHNjYXR0ZXIgcGxvdCBkb2Vzbid0IHJlYWxseSB0ZWxsIHVzIG11Y2guCiMgTGV0J3MgdHJ5IGEgZGlmZmVyZW50IGdlb21ldHJ5CgpwZW5ndWlucyAlPiUKICBnZ3Bsb3QoYWVzKHggPSBzZXgsIHkgPSBib2R5X21hc3NfZykpICsKICBnZW9tX2JveHBsb3QoKQoKIyBUaGF0J3MgbW9yZSBpbmZvcm1hdGl2ZSEKIyBMZXQncyBzZWUgaWYgdGhlcmUgYXJlIGRpZmZlcmVuY2VzIGJ5IHBlbmd1aW4gc3BlY2llcwoKcGVuZ3VpbnMgJT4lCiAgZ2dwbG90KGFlcyh4ID0gc2V4LCB5ID0gYm9keV9tYXNzX2cpKSArCiAgZ2VvbV9ib3hwbG90KGFlcyhmaWxsID0gc3BlY2llcykpCgojIFdoYXQgZG8geW91IG5vdGljZT8KYGBgCiMjIFdoYXQgb2JzZXJ2YXRpb25zIGNhbiB5b3UgbWFrZSBmcm9tIHRoZSBwbG90PwpZb3UgbWlnaHQgc2VlOgoKLSBHZW50b28gcGVuZ3VpbnMgaGF2ZSBoaWdoZXIgYm9keSBtYXNzIHRoYW4gQWRlbGllIGFuZCBDaGluc3RyYXAgcGVuZ3VpbnMKLSBIaWdoZXIgYm9keSBtYXNzIGFtb25nIG1hbGUgR2VudG9vIHBlbmd1aW5zIGNvbXBhcmVkIHRvIGZlbWFsZSBwZW5ndWlucwotIFBhdHRlcm4gbm90IGFzIGRpc2Nlcm5hYmxlIHdoZW4gY29tcGFyaW5nIEFkZWxpZSBhbmQgQ2hpbnN0cmFwIHBlbmd1aW5zCi0gTm8gYE5BYHMgYW1vbmcgQ2hpbnN0cmFwIHBlbmd1aW4gZGF0YSBwb2ludHMhIGBzZXhgIHdhcyBhdmFpbGFibGUgZm9yIGVhY2ggb2JzZXJ2YXRpb24KCkkgd29uZGVyIHdoYXQgcGVyY2VudGFnZSBvZiBvYnNlcnZhdGlvbnMgYXJlIGBOQWAgZm9yIGVhY2ggc3BlY2llcz8gTGV0J3MgZ2V0IHRoZSB0aWR5dmVyc2UgdG8gaGVscCB1cyB3aXRoIHRoaXMhCgpOZXh0IHN0b3AsIGBkcGx5cmAhCgojIGRwbHlyIAoKYGBge3J9CmdsaW1wc2UocGVuZ3VpbnMpCmBgYAoKIyMgc2VsZWN0KCkKU2VsZWN0aW5nIGRhdGFzZXQgY29sdW1ucyB3aXRoIGBzZWxlY3QoKWAKYGBge3Igc2VsZWN0fQpwZW5ndWlucyAlPiUKICBzZWxlY3Qoc3BlY2llcywgc2V4LCBib2R5X21hc3NfZykKYGBgCgojIyBhcnJhbmdlKCkKUmVvcmRlcmluZyB0aGUgZGF0YSBzZXQgd2l0aCBgYXJyYW5nZSgpYApgYGB7ciBhcnJhbmdlfQpwZW5ndWlucyAlPiUKICBzZWxlY3Qoc3BlY2llcywgc2V4LCBib2R5X21hc3NfZykgJT4lCiAgYXJyYW5nZShkZXNjKGJvZHlfbWFzc19nKSkKYGBgCgojIyBncm91cF9ieSgpIGFuZCBzdW1tYXJpemUoKQpTdW1tYXJpemluZyB0aGUgZGF0YSB1c2luZyBgZ3JvdXBfYnkoKWAgYW5kIGBzdW1tYXJpemUoKWAKYGBge3IgZ3JvdXAtYnktc3VtbWFyaXplfQpwZW5ndWlucyAlPiUgCiAgZ3JvdXBfYnkoc3BlY2llcywgc2V4KSAlPiUKICBzdW1tYXJpemUobiA9IG4oKSkKYGBgCgojIyBjb3VudCgpIGFuZCBhZGRfY291bnQoKQpCZWNhdXNlIHdlJ3JlIGp1c3QgX2NvdW50aW5nXyBvYnNlcnZhdGlvbnMgaW4gdGhpcyBleGFtcGxlLCB3ZSBhbHNvIGhhdmUgdGhlIG9wdGlvbiB0byB1c2UgYGNvdW50KClgIHdoaWNoIHNpbXBsaWZpZXMgb3VyIGNvZGUgYSBsaXR0bGUuCgo+IFRoYW5rIHlvdSB0byBBbGlzb24gSGlsbCBmb3IgW3RoZXNlIHN1Z2dlc3Rpb25zXShodHRwczovL2dpdGh1Yi5jb20vc3BjYW5lbG9uLzIwMjAtcmxhZGllcy1jaGktdGlkeXZlcnNlL2lzc3Vlcy8yKSEKCmBgYHtyIGNvdW50fQpwZW5ndWlucyAlPiUKICBjb3VudChzcGVjaWVzLCBzZXgpCmBgYAoKIyMgbXV0YXRlKCkKCiMjIyBPcHRpb24gMQpDcmVhdGluZyBuZXcgdmFyaWFibGVzIHdpdGggYG11dGF0ZSgpYApgYGB7ciBncm91cC1ieS1zdW1tYXJpemUtbXV0YXRlfQpwZW5ndWlucyAlPiUgCiAgZ3JvdXBfYnkoc3BlY2llcykgJT4lCiAgbXV0YXRlKG5fc3BlY2llcyA9IG4oKSkgJT4lCiAgdW5ncm91cCgpICU+JQogIGdyb3VwX2J5KHNwZWNpZXMsIHNleCwgbl9zcGVjaWVzKSAlPiUKICBzdW1tYXJpemUobiA9IG4oKSkgJT4lCiAgbXV0YXRlKHByb3AgPSBuL25fc3BlY2llcyoxMDApCmBgYAoKIyMjIE9wdGlvbiAyCldlIGNhbiBhbHNvIHVzZSBgbXV0YXRlKClgIGFsb25nIHdpdGggYGFkZF9jb3VudCgpYCB0byBhZGQgdXAgdGhlIGNvdW50cyBwZXIgc3BlY2llcyBncm91cCB0byB1c2UgYXMgYSBkZW5vbWluYXRvciAoIm5fc3BlY2llcyIpIHdoZW4gd2UgY2FsY3VsYXRlIHRoZSBwcm9wb3J0aW9uIGJ5IHNleC4KYGBge3IgY291bnQtbXV0YXRlfQpwZW5ndWlucyAlPiUgCiAgY291bnQoc3BlY2llcywgc2V4KSAlPiUKICBhZGRfY291bnQoc3BlY2llcywgd3QgPSBuLCBuYW1lID0gIm5fc3BlY2llcyIpICU+JQogIG11dGF0ZShwcm9wID0gbi9uX3NwZWNpZXMqMTAwKQpgYGAKCiMjIGZpbHRlcigpClJlZ2FyZGxlc3Mgb2Ygd2hpY2ggYXBwcm9hY2ggd2UgdGFrZSB0byBzdW1tYXJpemUgb3VyIGRhdGEsIHdlIGNhbiBwcm9jZWVkIHRvIGZpbHRlcmluZyByb3dzIGJ5IGFkZGluZyBvbiBhIGZpbHRlcmluZyBzdGVwIHRvIG91ciBwaXBlbGluZSB1c2luZyBgZmlsdGVyKClgCmBgYHtyIGZpbHRlcn0KcGVuZ3VpbnMgJT4lIAogIGNvdW50KHNwZWNpZXMsIHNleCkgJT4lCiAgYWRkX2NvdW50KHNwZWNpZXMsIHd0ID0gbiwgbmFtZSA9ICJuX3NwZWNpZXMiKSAlPiUKICBtdXRhdGUocHJvcCA9IG4vbl9zcGVjaWVzKjEwMCkgJT4lCiAgZmlsdGVyKHNwZWNpZXMgPT0gIkNoaW5zdHJhcCIpCmBgYAoKIyBmb3JjYXRzIAoKQ3VycmVudGx5IHRoZSBgeWVhcmAgdmFyaWFibGUgaW4gYHBlbmd1aW5zYCBpcyBjb250aW51b3VzIGZyb20gMjAwNyB0byAyMDA5LgoKVGhlcmUgbWF5IGJlIHNpdHVhdGlvbnMgd2hlcmUgdGhpcyBpc24ndCB3aGF0IHdlIHdhbnQgYW5kIHdlIG1pZ2h0IHdhbnQgdG8gdHVybiBpdCBpbnRvIGEgY2F0ZWdvcmljYWwgdmFyaWFibGUgaW5zdGVhZC4KClRoZSBgZmFjdG9yKClgIGZ1bmN0aW9uIGlzIHBlcmZlY3QgZm9yIHRoaXMuCmBgYHtyfQpwZW5ndWlucyAlPiUKICBtdXRhdGUoeWVhcl9mYWN0b3IgPSBmYWN0b3IoeWVhciwgbGV2ZWxzID0gdW5pcXVlKHllYXIpKSkKYGBgCgpUaGUgcmVzdWx0IGlzIGEgbmV3IGZhY3RvciBgeWVhcl9mYWN0b3JgIHdpdGggbGV2ZWxzIGAyMDA3YCwgYDIwMDhgIGFuZCBgMjAwOWAhCgpgYGB7cn0KcGVuZ3VpbnNfbmV3IDwtCiAgcGVuZ3VpbnMgJT4lCiAgbXV0YXRlKHllYXJfZmFjdG9yID0gZmFjdG9yKHllYXIsIGxldmVscyA9IHVuaXF1ZSh5ZWFyKSkpCnBlbmd1aW5zX25ldwpgYGAKCkRvdWJsZSBjaGVjayB0aGUgdmFyaWFibGUgY2xhc3MgYW5kIGZhY3RvciBsZXZlbHMgYmVsb3c6CgpgYGB7cn0KY2xhc3MocGVuZ3VpbnNfbmV3JHllYXJfZmFjdG9yKQpsZXZlbHMocGVuZ3VpbnNfbmV3JHllYXJfZmFjdG9yKQpgYGAKCiMgc3RyaW5nciAKCkxldCdzIHBsYXkgYXJvdW5kIHdpdGggc3RyaW5ncyBhIGxpdHRsZSBiaXQhCgpGcm9tIHdoYXQgd2UndmUgbGVhcm5lZCBzbyBmYXIsIHRha2UgYSBndWVzcyBhdCB3aGF0IHRoaXMgY29kZSBjaHVuayB3aWxsIGRvIGJlZm9yZSBydW5uaW5nIGl0LiAKCmBgYHtyfQpwZW5ndWlucyAlPiUKICBzZWxlY3Qoc3BlY2llcywgaXNsYW5kKSAlPiUKICBtdXRhdGUoSVNMQU5EID0gc3RyX3RvX3VwcGVyKGlzbGFuZCkpCmBgYAoKSG93IGFib3V0IHRoaXMgb25lPyBIb3cgaXMgaXQgZGlmZmVyZW50IGZyb20gdGhlIHByZXZpb3VzIGNvZGUgY2h1bms/CgpgYGB7cn0KcGVuZ3VpbnMgJT4lCiAgc2VsZWN0KHNwZWNpZXMsIGlzbGFuZCkgJT4lCiAgbXV0YXRlKElTTEFORCA9IHN0cl90b191cHBlcihpc2xhbmQpKSAlPiUKICBtdXRhdGUoc3BlY2llc19pc2xhbmQgPSBzdHJfYyhzcGVjaWVzLCBJU0xBTkQsIHNlcCA9ICJfIikpCmBgYAoKIyB0aWR5ciAKCkJvdGggcGVuZ3VpbiBkYXRhc2V0cyBhcmUgYWxyZWFkeSB0aWR5IQoKV2UgY2FuIHByZXRlbmQgdGhhdCBpdCB3YXNuJ3QgYW5kIHRoYXQgYGJvZHlfbWFzc19nYCB3YXMgcmVjb3JkZWQgc2VwYXJhdGVseSBmb3IgYG1hbGVgLCBgZmVtYWxlYCwgYW5kIHNleCBgTkFgIHBlbmd1aW5zLiBMaWtlIGB1bnRpZHlfcGVuZ3VpbnNgIGJlbG93OgpgYGB7cn0KdW50aWR5X3Blbmd1aW5zIDwtCiAgcGVuZ3VpbnMgJT4lCiAgICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gc2V4LAogICAgICAgICAgICAgICAgdmFsdWVzX2Zyb20gPSBib2R5X21hc3NfZykKdW50aWR5X3Blbmd1aW5zCmBgYAoKTm93IGxldCdzIG1ha2UgaXQgdGlkeSBhZ2FpbiB3aXRoIHRoZSBoZWxwIG9mIHRoZSBgcGl2b3RfbG9uZ2VyKClgIGZ1bmN0aW9uIQpgcGl2b3Rfd2lkZXIoKWBpcyBhbm90aGVyIHZlcnkgcG9wdWxhciB0aWR5aW5nIGZ1bmN0aW9uLiBIYXZlIHlvdSBzZWVuIGl0IGJlZm9yZT8gSGludDogc2VlIHRoZSBjb2RlIGNodW5rIGFib3ZlIQoKYGBge3J9CnVudGlkeV9wZW5ndWlucyAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IG1hbGU6YE5BYCwgCiAgICAgICAgICAgICAgIG5hbWVzX3RvID0gInNleCIsCiAgICAgICAgICAgICAgIHZhbHVlc190byA9ICJib2R5X21hc3NfZyIpCmBgYAoKIyBwdXJyciAKCk9rLCB3ZSBsb3ZlIG91ciBlYXJsaWVyIGJveHBsb3Qgc2hvd2luZyB1cyBgYm9keV9tYXNzX2dgIGJ5IGBzZXhgIGFuZCBjb2xvcmVkIGJ5IGBzcGVjaWVzYC4uLiBidXQgbGV0J3MgY2hhbmdlIHVwIHRoZSBjb2xvcnMgdG8ga2VlcCB3aXRoIG91ciBBbnRhcmN0aWNhIHRoZW1lIQoKSSdtIGEgYmlnIGZhbiBvZiB0aGUgY29sb3IgcGFsZXR0ZXMgaW4gdGhlIGBub3JkYCBgciBlbW86OmppKCJwYWNrYWdlIilgCgohW10oaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2prYXVwcC9ub3JkL21hc3Rlci9tYW4vZmlndXJlcy9SRUFETUUtcGFsZXR0ZXMtMS5wbmcpCgpMZXQncyB0dXJuIHRoaXMgcGxvdDoKCmBgYHtyfQpwZW5ndWlucyAlPiUKICBnZ3Bsb3QoYWVzKHggPSBzZXgsIHkgPSBib2R5X21hc3NfZykpICsKICBnZW9tX2JveHBsb3QoYWVzKGZpbGwgPSBzcGVjaWVzKSkKYGBgCgoKSW50byB0aGlzIG9uZSEKCmBgYHtyfQpwZW5ndWlucyAlPiUKICBnZ3Bsb3QoYWVzKHggPSBzZXgsIHkgPSBib2R5X21hc3NfZykpICsKICBnZW9tX2JveHBsb3QoYWVzKGZpbGwgPSBzcGVjaWVzKSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IG5vcmQ6Om5vcmRfcGFsZXR0ZXMkZnJvc3QpCmBgYAoKTGV0J3MgdHJ5IG91dCB0aGUgYGZyb3N0YCBwYWxldHRlLgoKYGBge3J9CiMgd2UnbGwgbmVlZCB0byBsb2FkIHRoZSB7bm9yZH0gcGFja2FnZQpsaWJyYXJ5KG5vcmQpCgojIHlvdSBjYW4gY2hvb3NlIGNvbG9ycyB1c2luZyB0aGUgY29sb3IgaGV4IGNvZGVzCm5vcmQ6Om5vcmRfcGFsZXR0ZXMkZnJvc3QKYGBgCgoKCmBgYHtyfQojIGJ1dCB5b3UgbWlnaHQgcHJlZmVyIHRvIHVzZSBgc2NhbGVfZmlsbF9tYW51YWwoKWAgCiMgb3IgbW9yZSBzcGVjaWFsaXplZCBmdW5jdGlvbnMgbGlrZSBgc2NhbGVfZmlsbF9ub3JkKClgIAojIGluY2x1ZGVkIGluIHRoZSB7bm9yZH0gcGFja2FnZQpwZW5ndWlucyAlPiUKICBnZ3Bsb3QoYWVzKHggPSBzZXgsIHkgPSBib2R5X21hc3NfZykpICsKICBnZW9tX2JveHBsb3QoYWVzKGZpbGwgPSBzcGVjaWVzKSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IG5vcmQ6Om5vcmRfcGFsZXR0ZXMkZnJvc3QpCiAgI3NjYWxlX2ZpbGxfbm9yZChwYWxldHRlID0gImZyb3N0IikKYGBgCgpPayBub3cgZm9yIGEgaGFuZHkgcGFja2FnZS9mdW5jdGlvbiB0cmlvIQoKYGBge3J9CiMgd2UnbGwgaGF2ZSB0byBsb2FkIHRoZSB7cHJpc21hdGljfSBwYWNrYWdlCmxpYnJhcnkocHJpc21hdGljKQoKcHJpc21hdGljOjpjb2xvcihub3JkOjpub3JkX3BhbGV0dGVzJGZyb3N0KQpgYGAKCmBwdXJycmAncyBgbWFwKClgIGZ1bmN0aW9uIGNhbiBoZWxwIHVzIGl0ZXJhdGUgdGhlIGBwcmlzbWF0aWM6OmNvbG9yKClgIGZ1bmN0aW9uIG92ZXIgYWxsIHBhbGV0dGVzIGluIGEgcGFsZXR0ZSBwYWNrYWdlIGxpa2UgYG5vcmRgIQoKPiBOb3RlOiBOb3QgYWxsIGNvbG9ycyB3aWxsIHNob3cgd2VsbCwgbGlrZSBgcG9sYXJuaWdodGAgYmVsb3cuIGBwcmlzbWF0aWM6OmNvbG9yKClgIHJlbGllcyBvbiBhIHBhY2thZ2UgdGhhdCBraW5kYSBoYXMgbGltaXRlZCBmdW5jdGlvbmFsaXR5IGluIHRoaXMgc2Vuc2UgKGBjcmF5b25gKS4gSXQncyBkb2luZyBpdHMgYmVzdCA6KQoKYGBge3IsIGV2YWwgPSBGQUxTRX0Kbm9yZDo6bm9yZF9wYWxldHRlcyAlPiUgbWFwKHByaXNtYXRpYzo6Y29sb3IpCmBgYAoKIyBFeHRyYSBtYXRlcmlhbCBiZWxvdyEKCiMjIFJlY3JlYXRpbmcgYSB7cGFsbWVycGVuZ3VpbnN9IHBsb3QKCkxldCdzIHByYWN0aWNlIGluIHJlYWwgdGltZSEKCiFbaHR0cHM6Ly9naXRodWIuY29tL2FsbGlzb25ob3JzdC9wYWxtZXJwZW5ndWluc10oaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2FsbGlzb25ob3JzdC9wYWxtZXJwZW5ndWlucy9tYXN0ZXIvbWFuL2ZpZ3VyZXMvUkVBRE1FLWZsaXBwZXItYmlsbC0xLnBuZykKCmBgYHtyIHNjYXR0ZXJwbG90LWJpbGwtbGVuZ3RofQojIHNjYXR0ZXJwbG90IHNlcXVlbmNlIC0tLS0KcGVuZ3VpbnMgJT4lCiAgZ2dwbG90KCkgKyAKICBnZW9tX3BvaW50KGFlcyh4ID0gZmxpcHBlcl9sZW5ndGhfbW0sIHkgPSBiaWxsX2xlbmd0aF9tbSkpICMgYWRkIGFlc3RoZXRpY3MKCnBlbmd1aW5zICU+JQogIGdncGxvdCgpICsKICBnZW9tX3BvaW50KGFlcyh4ID0gZmxpcHBlcl9sZW5ndGhfbW0sIHkgPSBiaWxsX2xlbmd0aF9tbSwgCiAgICAgICAgICAgICAgICAgY29sb3IgPSBzcGVjaWVzKSkgIyBhZGQgY29sb3IgcGVyIHNwZWNpZXMKCnBlbmd1aW5zICU+JQogIGdncGxvdCgpICsKICBnZW9tX3BvaW50KGFlcyh4ID0gZmxpcHBlcl9sZW5ndGhfbW0sIHkgPSBiaWxsX2xlbmd0aF9tbSwgCiAgICAgICAgICAgICAgICAgY29sb3IgPSBzcGVjaWVzLCBzaGFwZSA9IHNwZWNpZXMpKSAjIGFkZCBzaGFwZSBwZXIgc3BlY2llcwoKcGVuZ3VpbnMgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fcG9pbnQoYWVzKHggPSBmbGlwcGVyX2xlbmd0aF9tbSwgeSA9IGJpbGxfbGVuZ3RoX21tLCAKICAgICAgICAgICAgICAgICBjb2xvciA9IHNwZWNpZXMsIHNoYXBlID0gc3BlY2llcykpICMgYWRkIHNoYXBlIHBlciBzcGVjaWVzCgpwZW5ndWlucyAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9wb2ludChhZXMoeCA9IGZsaXBwZXJfbGVuZ3RoX21tLCB5ID0gYmlsbF9sZW5ndGhfbW0sIAogICAgICAgICAgICAgICAgIGNvbG9yID0gc3BlY2llcywgc2hhcGUgPSBzcGVjaWVzKSkgKwogIGdlb21fc21vb3RoKGFlcyh4ID0gZmxpcHBlcl9sZW5ndGhfbW0sIHkgPSBiaWxsX2xlbmd0aF9tbSwgCiAgICAgICAgICAgICAgICAgIGNvbG9yID0gc3BlY2llcykpCgpwZW5ndWlucyAlPiUKICBnZ3Bsb3QoYWVzKHggPSBmbGlwcGVyX2xlbmd0aF9tbSwgeSA9IGJpbGxfbGVuZ3RoX21tKSkgKyAKICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IHNwZWNpZXMsIHNoYXBlID0gc3BlY2llcykpICsKICBnZW9tX3Ntb290aChhZXMoY29sb3IgPSBzcGVjaWVzKSwgc2UgPSBGQUxTRSwgbWV0aG9kID0gImxtIikKYGBgCgpgYGB7ciBzY2F0dGVycGxvdC1ib2R5LW1hc3N9CnBlbmd1aW5zICU+JQogIGdncGxvdCgpICsKICBnZW9tX3BvaW50KGFlcyh4ID0gZmxpcHBlcl9sZW5ndGhfbW0sIHkgPSBib2R5X21hc3NfZywgCiAgICAgICAgICAgICAgICAgY29sb3IgPSBzcGVjaWVzLCBzaGFwZSA9IHNwZWNpZXMpKQpgYGAKCmBgYHtyIGhpc3RvZ3JhbX0KcGVuZ3VpbnMgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21faGlzdG9ncmFtKGFlcyh4ID0gZmxpcHBlcl9sZW5ndGhfbW0pKQoKcGVuZ3VpbnMgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21faGlzdG9ncmFtKGFlcyh4ID0gZmxpcHBlcl9sZW5ndGhfbW0sIGNvbG9yID0gc3BlY2llcykpCgpwZW5ndWlucyAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKHggPSBmbGlwcGVyX2xlbmd0aF9tbSwgZmlsbCA9IHNwZWNpZXMpKQoKcGVuZ3VpbnMgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21faGlzdG9ncmFtKGFlcyh4ID0gZmxpcHBlcl9sZW5ndGhfbW0sIGZpbGwgPSBzcGVjaWVzLCAKICAgICAgICAgICAgICAgICAgICAgcG9zaXRpb24gPSAiaWRlbnRpdHkiLCBhbHBoYSA9IDAuNSkpCmBgYAoKCiMgVGlkeVR1ZXNkYXkKCiMjIEdldHRpbmcgc3RhcnRlZAoKLSBbSW50cm8gQmxvZyBhbmQgaGlzdG9yeV0oaHR0cHM6Ly90aGVtb2NrdXAuYmxvZy9wb3N0cy8yMDE4LTEyLTExLXRpZHl0dWVzZGF5LWEtd2Vla2x5LXNvY2lhbC1kYXRhLXByb2plY3QtaW4tci8pCi0gW0ludHJvIFR3ZWV0IGJ5IFRvbSBNb2NrIChSU3R1ZGlvKV0oaHR0cHM6Ly90d2l0dGVyLmNvbS90aG9tYXNfbW9jay9zdGF0dXMvMTI4Nzc3NDU3NTgzMzYxNjM4ND9zPTIwKQotIFtUaWR5VHVlc2RheXMgR2l0SHViXShodHRwczovL2dpdGh1Yi5jb20vcmZvcmRhdGFzY2llbmNlL3RpZHl0dWVzZGF5L2Jsb2IvbWFzdGVyL1JFQURNRS5tZCkKLSBbVGlkeVR1ZXNkYXkgUG9kY2FzdF0oaHR0cHM6Ly90d2l0dGVyLmNvbS90aWR5cG9kKQotIFtUaWR5VHVlc2RheSBTaWdodC1VbnNlZW4gb24gWW91VHViZV0oaHR0cHM6Ly93d3cueW91dHViZS5jb20vd2F0Y2g/dj1JbXBYYXdQTkNmTSkKLSBbe3RpZHl0dWVzZGF5Un0gcGFja2FnZSB0byBoZWxwIHlvdSBlYXNpbHkgZG93bmxvYWQgdGhlIGRhdGEgc2V0XShodHRwczovL2dpdGh1Yi5jb20vdGhlYmlvZW5naW5lZXIvdGlkeXR1ZXNkYXlSKQoKIyMgdGlkeXR1ZXNkYXlSCmBgYHtyIGV2YWw9RkFMU0V9CiMgaW5zdGFsbC5wYWNrYWdlcygidGlkeXR1ZXNkYXlSIikKIyByZW1vdGVzOjppbnN0YWxsX2dpdGh1YigidGhlYmlvZW5naW5lZXIvdGlkeXR1ZXNkYXlSIikKCmxpYnJhcnkodGlkeXR1ZXNkYXlSKQoKIyBsb2FkIHRoZSBkYXRhCnR0X2RhdGEgPC0gdHRfbG9hZCgiMjAyMC0wNy0yNyIpICMgZXJyb3IgbWVzc2FnZQp0dF9kYXRhIDwtIHR0X2xvYWQoIjIwMjAtMDctMjgiKQp0dF9kYXRhIDwtIHR0X2xvYWQoMjAyMCwgd2Vlaz0zMSkKCiMgdGFrZSBhIHBlZWsKcmVhZG1lKHR0X2RhdGEpCnByaW50KHR0X2RhdGEpCmBgYAoKIyMgTGV2ZWwgdXAgd2l0aCBtb2RlbGluZwotIFtKdWxpYSBTaWxnZSAoUlN0dWRpbykgdGVhY2hlcyBUaWR5bW9kZWxzIHdpdGgge3BhbG1lcnBlbmd1aW5zfSBvbiBZb3VUdWJlXShodHRwczovL3d3dy55b3V0dWJlLmNvbS93YXRjaD92PXo1N2kyR1ZjZHd3KQoKIyMgRXhhbXBsZXMKCi0gU3BlY2lmaWMgdG8ge3BhbG1lcnBlbmd1aW5zfToKICAtIEZvY3VzIG9uIGZvbnRzIGFuZCBmb3JtYXR0aW5nOiBodHRwczovL3R3aXR0ZXIuY29tL2VsbGFta2F5ZS9zdGF0dXMvMTI4OTE1NzEzOTQzNzYyMTI1MD9zPTIwCiAgLSBSLUxhZGllcyBBbWVzOiBodHRwczovL3R3aXR0ZXIuY29tL1JMYWRpZXNBbWVzL3N0YXR1cy8xMjk0NDI1MzU5Mzg4MTE0OTQ0P3M9MjAKICAKLSBHZW5lcmFsIHRvICN0aWR5dHVlc2RheToKICAtIFItTGFkaWVzIENoaWNhZ28gVGlkeVR1ZXNkYXkgbGVhZGVyIE9sYSE6IGh0dHBzOi8vdHdpdHRlci5jb20vQW1hemluZ1NwZWNpYWxpCiAgLSBSLUxhZGllcyBDaGljYWdvIFRpZHlUdWVzZGF5IHNldHVwOiBodHRwczovL3R3aXR0ZXIuY29tL1JMYWRpZXNDaGljYWdvL3N0YXR1cy8xMTkyMjQzMTcwNDEyNzYxMDg4P3M9MjA=
+
LS0tCnRpdGxlOiAiQW4gQW50YXJjdGljIFRvdXIgb2YgdGhlIFRpZHl2ZXJzZSIKYXV0aG9yOiAiU2lsdmlhIFAuIENhbmVsw7NuLCBQaEQgKEBzcGNhbmVsb24pIgpkYXRlOiAiRmlyc3QgY3JlYXRlZCBvbiBBdWcgMzEsIDIwMjAgKHVwZGF0ZWQgb24gU2VwdCAyMiwgMjAyMCkiCmluc3RpdHV0ZTogIlVuaXZlcnNpdHkgb2YgUGVubnN5bHZhbmlhIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIGZpZ193aWR0aDogNy4yCiAgICBoaWdobGlnaHQ6IHB5Z21lbnRzCiAgICBudW1iZXJfc2VjdGlvbnM6IG5vCiAgICB0aGVtZTogbHVtZW4KICAgIHRvYzogeWVzCiAgICB0b2NfZmxvYXQ6IHllcwogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IHllcwogICAgZGZfcHJpbnQ6IHBhZ2VkCi0tLQoKYGBge3J9CmtuaXRyOjpvcHRzX2NodW5rJHNldChtZXNzYWdlID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSwgY29sbGFwc2UgPSBUUlVFKQpgYGAKCiMgQWJvdXQge3BhbG1lcnBlbmd1aW5zfQotIFt7cGFsbWVycGVuZ3VpbnN9IERvY3VtZW50YXRpb25dKGh0dHBzOi8vYWxsaXNvbmhvcnN0LmdpdGh1Yi5pby9wYWxtZXJwZW5ndWlucy8pCi0gW0FsbGlzb24gSG9yc3QncyBHaXRIdWIgcmVwbyBmb3IgUGFsbWVyIFBlbmd1aW5zIGRhdGFzZXRdKGh0dHBzOi8vZ2l0aHViLmNvbS9hbGxpc29uaG9yc3QvcGFsbWVycGVuZ3VpbnMpCgpgYGB7ciwgZXZhbCA9IEZBTFNFfQojIGluc3RhbGwucGFja2FnZXMoInJlbW90ZXMiKQojIHJlbW90ZXM6Omluc3RhbGxfZ2l0aHViKCJhbGxpc29uaG9yc3QvcGFsbWVycGVuZ3VpbnMiKQpgYGAKCiMgTG9hZGluZyBwYWNrYWdlcwpgYGB7cn0KIyBsb2FkaW5nIHBhY2thZ2VzCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHBhbG1lcnBlbmd1aW5zKQoKIyB2aWV3aW5nIGRhdGEgc2V0cyBpbiBwYWNrYWdlICJwYWxtZXJwZW5ndWlucyIKZGF0YShwYWNrYWdlID0gInBhbG1lcnBlbmd1aW5zIikKYGBgCgojIHJlYWRyIAoKTGV0J3MgZ2V0IGRhdGEgaW50byBSIQoKYGBge3J9CiMgb3B0aW9uIDE6IGxvYWQgdXNpbmcgVVJMIC0tLS0KcmF3X2FkZWxpZV91cmwgPC0gcmVhZF9jc3YoImh0dHBzOi8vcG9ydGFsLmVkaXJlcG9zaXRvcnkub3JnL25pcy9kYXRhdmlld2VyP3BhY2thZ2VpZD1rbmItbHRlci1wYWwuMjE5LjMmZW50aXR5aWQ9MDAyZjM4OTMzODVmNzEwZGY2OWVlZWJlODkzMTQ0ZmYiKQoKIyBvcHRpb24gMjogbG9hZCB1c2luZyBmaWxlcGF0aCAtLS0tCnJhd19hZGVsaWVfZmlsZXBhdGggPC0gcmVhZF9jc3YoInJhd19hZGVsaWUuY3N2IikKYGBgCgpMdWNreSBmb3IgdXMsIEFsbGlzb24gSG9yc3QgY29tcGlsZWQgZGF0YSBmcm9tIGFsbCB0aHJlZSBzcGVjaWVzIHRvZ2V0aGVyIGZvciB1cyBpbiB0aGUgYHtwYWxtZXJwZW5ndWluc31gIHBhY2thZ2UhCgotIGBwZW5ndWluc2AgY29udGFpbnMgYSBjbGVhbiBkYXRhc2V0LCBhbmQKLSBgcGVuZ3VpbnNfcmF3YCBjb250YWlucyByYXcgZGF0YQoKYGBge3J9CiMgc2F2ZXMgcGFja2FnZSB0aWJibGUgaW50byBnbG9iYWwgZW52aXJvbm1lbnQKcGVuZ3VpbnMgPC0gcGFsbWVycGVuZ3VpbnM6OnBlbmd1aW5zIApoZWFkKHBlbmd1aW5zKQoKcGVuZ3VpbnNfcmF3IDwtIHBhbG1lcnBlbmd1aW5zOjpwZW5ndWluc19yYXcKaGVhZChwZW5ndWluc19yYXcpCmBgYAoKIyB0aWJibGUgCgpBIGB0aWJibGVgIGlzIG11Y2ggbGlrZSB0aGUgYGRhdGEgZnJhbWVgIGluIGJhc2UgUiwgYnV0IG9wdGltaXplZCBmb3IgdXNlIGluIHRoZSBUaWR5dmVyc2UuIExldCdzIHRha2UgYSBsb29rIGF0IHRoZSBkaWZmZXJlbmNlcy4KCmBgYHtyIHRpYmJsZX0KIyB0cnkgZWFjaCBvZiB0aGVzZSBjb21tYW5kcyBpbiB0aGUgY29uc29sZSBhbmQgc2VlIGlmIHlvdSBjYW4gc3BvdCB0aGUgZGlmZmVyZW5jZXMhCgphc190aWJibGUocGVuZ3VpbnMpCmFzLmRhdGEuZnJhbWUocGVuZ3VpbnMpCmBgYAoKIyBXaGF0IGRpZmZlcmVuY2VzIGRvIHlvdSBzZWU/CllvdSBtaWdodCBzZWUgYSB0aWJibGUgcHJpbnRzOgoKLSB2YXJpYWJsZSBjbGFzc2VzCi0gb25seSAxMCByb3dzCi0gb25seSBhcyBtYW55IGNvbHVtbnMgYXMgY2FuIGZpdCBvbiB0aGUgc2NyZWVuCi0gTkFzIGFyZSBoaWdobGlnaHRlZCBpbiBjb25zb2xlIHNvIHRoZXkncmUgZWFzeSB0byBzcG90IChmb250IGhpZ2hsaWdodGluZyBhbmQgc3R5bGluZyBpbiBgdGliYmxlYCkKCk5vdCBzbyBtdWNoIGEgY29uY2VybiBpbiBhbiBSIE1hcmtkb3duIGZpbGUsIGJ1dCBub3RpY2VhYmxlIGluIHRoZSBjb25zb2xlLiBQcmludCBtZXRob2QgbWFrZXMgaXQgZWFzaWVyIHRvIHdvcmsgd2l0aCBsYXJnZSBkYXRhc2V0cy4KClRoZXJlIGFyZSBhIGNvdXBsZSBvZiBvdGhlciBtYWluIGRpZmZlcmVuY2VzLCBuYW1lbHkgaW4gKipzdWJzZXR0aW5nKiogYW5kICoqcmVjeWNsaW5nKiouIENoZWNrIHRoZW0gb3V0IGluIHRoZSBbYHZpZ25ldHRlKCJ0aWJibGUiKV0oaHR0cHM6Ly90aWJibGUudGlkeXZlcnNlLm9yZy9hcnRpY2xlcy90aWJibGUuaHRtbCkKClRyeSBpdCBvdXQgaGVyZSEKYGBge3IgdGliYmxlLXZpZ25ldHRlfQp2aWduZXR0ZSgidGliYmxlIikKYGBgCgoKIyMgVGFraW5nIGEgY2xvc2VyIGxvb2sgYXQgYHBlbmd1aW5zYAoKR2V0IGEgZnVsbCB2aWV3IG9mIHRoZSBkYXRhc2V0OgpgYGB7ciBwZW5ndWlucy12aWV3fQpWaWV3KHBlbmd1aW5zKQpgYGAKCk9yIGNhdGNoIGEgYGdsaW1wc2VgOgpgYGB7ciBwZW5ndWlucy1nbGltcHNlfQpnbGltcHNlKHBlbmd1aW5zKQpgYGAKCiMgZ2dwbG90MiAKCkxldCdzIHN0YXJ0IGJ5IG1ha2luZyBhIHNpbXBsZSBwbG90IG9mIG91ciBkYXRhIQoKYGdncGxvdDJgIHVzZXMgdGhlICJHcmFtbWFyIG9mIEdyYXBoaWNzIiBhbmQgbGF5ZXJzIGdyYXBoaWNhbCBjb21wb25lbnRzIHRvZ2V0aGVyIHRvIGNyZWF0ZSBhIHBsb3QuCgojIyBMZXQncyBzZWUgaWYgYm9keSBtYXNzIHZhcmllcyBieSBwZW5ndWluIHNleAoKYGBge3IgZ2dwbG90Mn0KcGVuZ3VpbnMgJT4lCiAgZ2dwbG90KCkKCnBlbmd1aW5zICU+JQogIGdncGxvdChhZXMoeCA9IHNleCwgeSA9IGJvZHlfbWFzc19nKSkKCnBlbmd1aW5zICU+JQogIGdncGxvdChhZXMoeCA9IHNleCwgeSA9IGJvZHlfbWFzc19nKSkgKwogIGdlb21fcG9pbnQoKQoKIyBBIHNjYXR0ZXIgcGxvdCBkb2Vzbid0IHJlYWxseSB0ZWxsIHVzIG11Y2guCiMgTGV0J3MgdHJ5IGEgZGlmZmVyZW50IGdlb21ldHJ5CgpwZW5ndWlucyAlPiUKICBnZ3Bsb3QoYWVzKHggPSBzZXgsIHkgPSBib2R5X21hc3NfZykpICsKICBnZW9tX2JveHBsb3QoKQoKIyBUaGF0J3MgbW9yZSBpbmZvcm1hdGl2ZSEKIyBMZXQncyBzZWUgaWYgdGhlcmUgYXJlIGRpZmZlcmVuY2VzIGJ5IHBlbmd1aW4gc3BlY2llcwoKcGVuZ3VpbnMgJT4lCiAgZ2dwbG90KGFlcyh4ID0gc2V4LCB5ID0gYm9keV9tYXNzX2cpKSArCiAgZ2VvbV9ib3hwbG90KGFlcyhmaWxsID0gc3BlY2llcykpCgojIFdoYXQgZG8geW91IG5vdGljZT8KYGBgCiMjIFdoYXQgb2JzZXJ2YXRpb25zIGNhbiB5b3UgbWFrZSBmcm9tIHRoZSBwbG90PwpZb3UgbWlnaHQgc2VlOgoKLSBHZW50b28gcGVuZ3VpbnMgaGF2ZSBoaWdoZXIgYm9keSBtYXNzIHRoYW4gQWRlbGllIGFuZCBDaGluc3RyYXAgcGVuZ3VpbnMKLSBIaWdoZXIgYm9keSBtYXNzIGFtb25nIG1hbGUgR2VudG9vIHBlbmd1aW5zIGNvbXBhcmVkIHRvIGZlbWFsZSBwZW5ndWlucwotIFBhdHRlcm4gbm90IGFzIGRpc2Nlcm5hYmxlIHdoZW4gY29tcGFyaW5nIEFkZWxpZSBhbmQgQ2hpbnN0cmFwIHBlbmd1aW5zCi0gTm8gYE5BYHMgYW1vbmcgQ2hpbnN0cmFwIHBlbmd1aW4gZGF0YSBwb2ludHMhIGBzZXhgIHdhcyBhdmFpbGFibGUgZm9yIGVhY2ggb2JzZXJ2YXRpb24KCkkgd29uZGVyIHdoYXQgcGVyY2VudGFnZSBvZiBvYnNlcnZhdGlvbnMgYXJlIGBOQWAgZm9yIGVhY2ggc3BlY2llcz8gTGV0J3MgZ2V0IHRoZSB0aWR5dmVyc2UgdG8gaGVscCB1cyB3aXRoIHRoaXMhCgpOZXh0IHN0b3AsIGBkcGx5cmAhCgojIGRwbHlyIAoKYGBge3J9CmdsaW1wc2UocGVuZ3VpbnMpCmBgYAoKIyMgc2VsZWN0KCkKU2VsZWN0aW5nIGRhdGFzZXQgY29sdW1ucyB3aXRoIGBzZWxlY3QoKWAKYGBge3Igc2VsZWN0fQpwZW5ndWlucyAlPiUKICBzZWxlY3Qoc3BlY2llcywgc2V4LCBib2R5X21hc3NfZykKYGBgCgojIyBhcnJhbmdlKCkKUmVvcmRlcmluZyB0aGUgZGF0YSBzZXQgd2l0aCBgYXJyYW5nZSgpYApgYGB7ciBhcnJhbmdlfQpwZW5ndWlucyAlPiUKICBzZWxlY3Qoc3BlY2llcywgc2V4LCBib2R5X21hc3NfZykgJT4lCiAgYXJyYW5nZShkZXNjKGJvZHlfbWFzc19nKSkKYGBgCgojIyBncm91cF9ieSgpIGFuZCBzdW1tYXJpemUoKQpTdW1tYXJpemluZyB0aGUgZGF0YSB1c2luZyBgZ3JvdXBfYnkoKWAgYW5kIGBzdW1tYXJpemUoKWAKCldlIGNhbiB1c2UgYGdyb3VwX2J5KClgIHRvIGdyb3VwIG91ciBkYXRhIGJ5ICoqc3BlY2llcyoqIGFuZCAqKnNleCoqLCBhbmQgYHN1bW1hcml6ZSgpYCB0byBjYWxjdWxhdGUgdGhlIGF2ZXJhZ2UgKipib2R5X21hc3NfZyoqIGZvciBlYWNoIGdyb3VwaW5nLgpgYGB7ciBncm91cC1ieS1zdW1tYXJpemV9CnBlbmd1aW5zICU+JQogIHNlbGVjdChzcGVjaWVzLCBzZXgsIGJvZHlfbWFzc19nKSAlPiUKICBncm91cF9ieShzcGVjaWVzLCBzZXgpICU+JSAgICAgICAgIAogIHN1bW1hcml6ZShtZWFuID0gbWVhbihib2R5X21hc3NfZykpCmBgYAoKIyMgY291bnQoKSBhbmQgYWRkX2NvdW50KCkKSWYgd2UncmUganVzdCBpbnRlcmVzdGVkIGluIF9jb3VudGluZ18gdGhlIG9ic2VydmF0aW9ucyBpbiBlYWNoIGdyb3VwaW5nLCB3ZSBjYW4gZ3JvdXAgYW5kIHN1bW1hcml6ZSB3aXRoIHNwZWNpYWwgZnVuY3Rpb25zIGBjb3VudCgpYCBhbmQgYGFkZF9jb3VudCgpYC4KCkNvdW50aW5nIGNhbiBiZSBkb25lIHdpdGggYGdyb3VwX2J5KClgIGFuZCBgc3VtbWFyaXplKClgLCBidXQgaXQncyBhIGxpdHRsZSBjdW1iZXJzb21lLiAKCkl0IGludm9sdmVzLi4uCjEuIHVzaW5nIGBtdXRhdGUoKWAgdG8gY3JlYXRlIGFuIGludGVybWVkaWF0ZSB2YXJpYWJsZSAqKm5fc3BlY2llcyoqIHRoYXQgYWRkcyB1cCBhbGwgb2JzZXJ2YXRpb25zIHBlciAqKnNwZWNpZXMqKiwgYW5kCjIuIGFuIGB1bmdyb3VwKClgLWluZyBzdGVwCgpgYGB7cn0KcGVuZ3VpbnMgJT4lIAogIGdyb3VwX2J5KHNwZWNpZXMpICU+JQogIG11dGF0ZShuX3NwZWNpZXMgPSBuKCkpICU+JSAgICAgICAgICAgIAogIHVuZ3JvdXAoKSAlPiUgICAgICAgICAgICAgICAgICAgICAgICAgIAogIGdyb3VwX2J5KHNwZWNpZXMsIHNleCwgbl9zcGVjaWVzKSAlPiUKICBzdW1tYXJpemUobiA9IG4oKSkKYGBgCgpJbiBjb250cmFzdCwgYGNvdW50KClgIGFuZCBgYWRkX2NvdW50KClgIG9mZmVyIGEgc2ltcGxpZmllZCBhcHByb2FjaC4KCj4gVGhhbmsgeW91IHRvIEFsaXNvbiBIaWxsIGZvciBbdGhpcyBzdWdnZXN0aW9uXShodHRwczovL2dpdGh1Yi5jb20vc3BjYW5lbG9uLzIwMjAtcmxhZGllcy1jaGktdGlkeXZlcnNlL2lzc3Vlcy8yKSEKCmBgYHtyIGNvdW50fQpwZW5ndWlucyAlPiUgCiAgY291bnQoc3BlY2llcywgc2V4KSAlPiUKICBhZGRfY291bnQoc3BlY2llcywgd3QgPSBuLCAgICAKICAgICAgICAgICAgbmFtZSA9ICJuX3NwZWNpZXMiKSAKYGBgCgojIyBtdXRhdGUoKQpXZSBjYW4gYWRkIHRvIG91ciBjb3VudGluZyBleGFtcGxlIGJ5IHVzaW5nIGBtdXRhdGUoKWAgdG8gY3JlYXRlIGEgbmV3IHZhcmlhYmxlICoqcHJvcCoqLCB3aGljaCByZXByZXNlbnRzIHRoZSBwcm9wb3J0aW9uIG9mIHBlbmd1aW5zIG9mIGVhY2ggKipzZXgqKiwgZ3JvdXBlZCBieSAqKnNwZWNpZXMqKgoKPiBUaGFuayB5b3UgdG8gQWxpc29uIEhpbGwgZm9yIFt0aGlzIHN1Z2dlc3Rpb25zXShodHRwczovL2dpdGh1Yi5jb20vc3BjYW5lbG9uLzIwMjAtcmxhZGllcy1jaGktdGlkeXZlcnNlL2lzc3Vlcy8yKSEKCmBgYHtyfQpwZW5ndWlucyAlPiUgCiAgY291bnQoc3BlY2llcywgc2V4KSAlPiUKICBhZGRfY291bnQoc3BlY2llcywgd3QgPSBuLCAKICAgICAgICAgICAgbmFtZSA9ICJuX3NwZWNpZXMiKSAlPiUKICBtdXRhdGUocHJvcCA9IG4vbl9zcGVjaWVzKjEwMCkgCmBgYAoKCiMjIGZpbHRlcigpCkZpbmFsbHksIHdlIGNhbiBmaWx0ZXIgcm93cyB0byBvbmx5IHNob3cgdXMgKipDaGluc3RyYXAqKiBwZW5ndWluIHN1bW1hcmllcyBieSBhZGRpbmcgYGZpbHRlcigpYCB0byBvdXIgcGlwZWxpbmUKYGBge3IgZmlsdGVyfQpwZW5ndWlucyAlPiUgCiAgY291bnQoc3BlY2llcywgc2V4KSAlPiUKICBhZGRfY291bnQoc3BlY2llcywgd3QgPSBuLCAKICAgICAgICAgICAgbmFtZSA9ICJuX3NwZWNpZXMiKSAlPiUKICBtdXRhdGUocHJvcCA9IG4vbl9zcGVjaWVzKjEwMCkgJT4lCiAgZmlsdGVyKHNwZWNpZXMgPT0gIkNoaW5zdHJhcCIpCmBgYAoKIyBmb3JjYXRzIAoKQ3VycmVudGx5IHRoZSBgeWVhcmAgdmFyaWFibGUgaW4gYHBlbmd1aW5zYCBpcyBjb250aW51b3VzIGZyb20gMjAwNyB0byAyMDA5LgoKVGhlcmUgbWF5IGJlIHNpdHVhdGlvbnMgd2hlcmUgdGhpcyBpc24ndCB3aGF0IHdlIHdhbnQgYW5kIHdlIG1pZ2h0IHdhbnQgdG8gdHVybiBpdCBpbnRvIGEgY2F0ZWdvcmljYWwgdmFyaWFibGUgaW5zdGVhZC4KClRoZSBgZmFjdG9yKClgIGZ1bmN0aW9uIGlzIHBlcmZlY3QgZm9yIHRoaXMuCmBgYHtyfQpwZW5ndWlucyAlPiUKICBtdXRhdGUoeWVhcl9mYWN0b3IgPSBmYWN0b3IoeWVhciwgbGV2ZWxzID0gdW5pcXVlKHllYXIpKSkKYGBgCgpUaGUgcmVzdWx0IGlzIGEgbmV3IGZhY3RvciBgeWVhcl9mYWN0b3JgIHdpdGggbGV2ZWxzIGAyMDA3YCwgYDIwMDhgIGFuZCBgMjAwOWAhCgpgYGB7cn0KcGVuZ3VpbnNfbmV3IDwtCiAgcGVuZ3VpbnMgJT4lCiAgbXV0YXRlKHllYXJfZmFjdG9yID0gZmFjdG9yKHllYXIsIGxldmVscyA9IHVuaXF1ZSh5ZWFyKSkpCnBlbmd1aW5zX25ldwpgYGAKCkRvdWJsZSBjaGVjayB0aGUgdmFyaWFibGUgY2xhc3MgYW5kIGZhY3RvciBsZXZlbHMgYmVsb3c6CgpgYGB7cn0KY2xhc3MocGVuZ3VpbnNfbmV3JHllYXJfZmFjdG9yKQpsZXZlbHMocGVuZ3VpbnNfbmV3JHllYXJfZmFjdG9yKQpgYGAKCiMgc3RyaW5nciAKCkxldCdzIHBsYXkgYXJvdW5kIHdpdGggc3RyaW5ncyBhIGxpdHRsZSBiaXQhCgpGcm9tIHdoYXQgd2UndmUgbGVhcm5lZCBzbyBmYXIsIHRha2UgYSBndWVzcyBhdCB3aGF0IHRoaXMgY29kZSBjaHVuayB3aWxsIGRvIGJlZm9yZSBydW5uaW5nIGl0LiAKCmBgYHtyfQpwZW5ndWlucyAlPiUKICBzZWxlY3Qoc3BlY2llcywgaXNsYW5kKSAlPiUKICBtdXRhdGUoSVNMQU5EID0gc3RyX3RvX3VwcGVyKGlzbGFuZCkpCmBgYAoKSG93IGFib3V0IHRoaXMgb25lPyBIb3cgaXMgaXQgZGlmZmVyZW50IGZyb20gdGhlIHByZXZpb3VzIGNvZGUgY2h1bms/CgpgYGB7cn0KcGVuZ3VpbnMgJT4lCiAgc2VsZWN0KHNwZWNpZXMsIGlzbGFuZCkgJT4lCiAgbXV0YXRlKElTTEFORCA9IHN0cl90b191cHBlcihpc2xhbmQpKSAlPiUKICBtdXRhdGUoc3BlY2llc19pc2xhbmQgPSBzdHJfYyhzcGVjaWVzLCBJU0xBTkQsIHNlcCA9ICJfIikpCmBgYAoKIyB0aWR5ciAKCkJvdGggcGVuZ3VpbiBkYXRhc2V0cyBhcmUgYWxyZWFkeSB0aWR5IQoKV2UgY2FuIHByZXRlbmQgdGhhdCBpdCB3YXNuJ3QgYW5kIHRoYXQgYGJvZHlfbWFzc19nYCB3YXMgcmVjb3JkZWQgc2VwYXJhdGVseSBmb3IgYG1hbGVgLCBgZmVtYWxlYCwgYW5kIHNleCBgTkFgIHBlbmd1aW5zLiBMaWtlIGB1bnRpZHlfcGVuZ3VpbnNgIGJlbG93OgpgYGB7cn0KdW50aWR5X3Blbmd1aW5zIDwtCiAgcGVuZ3VpbnMgJT4lCiAgICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gc2V4LAogICAgICAgICAgICAgICAgdmFsdWVzX2Zyb20gPSBib2R5X21hc3NfZykKdW50aWR5X3Blbmd1aW5zCmBgYAoKTm93IGxldCdzIG1ha2UgaXQgdGlkeSBhZ2FpbiB3aXRoIHRoZSBoZWxwIG9mIHRoZSBgcGl2b3RfbG9uZ2VyKClgIGZ1bmN0aW9uIQpgcGl2b3Rfd2lkZXIoKWBpcyBhbm90aGVyIHZlcnkgcG9wdWxhciB0aWR5aW5nIGZ1bmN0aW9uLiBIYXZlIHlvdSBzZWVuIGl0IGJlZm9yZT8gSGludDogc2VlIHRoZSBjb2RlIGNodW5rIGFib3ZlIQoKYGBge3J9CnVudGlkeV9wZW5ndWlucyAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IG1hbGU6YE5BYCwgCiAgICAgICAgICAgICAgIG5hbWVzX3RvID0gInNleCIsCiAgICAgICAgICAgICAgIHZhbHVlc190byA9ICJib2R5X21hc3NfZyIpCmBgYAoKIyBwdXJyciAKCk9rLCB3ZSBsb3ZlIG91ciBlYXJsaWVyIGJveHBsb3Qgc2hvd2luZyB1cyBgYm9keV9tYXNzX2dgIGJ5IGBzZXhgIGFuZCBjb2xvcmVkIGJ5IGBzcGVjaWVzYC4uLiBidXQgbGV0J3MgY2hhbmdlIHVwIHRoZSBjb2xvcnMgdG8ga2VlcCB3aXRoIG91ciBBbnRhcmN0aWNhIHRoZW1lIQoKSSdtIGEgYmlnIGZhbiBvZiB0aGUgY29sb3IgcGFsZXR0ZXMgaW4gdGhlIGBub3JkYCBgciBlbW86OmppKCJwYWNrYWdlIilgCgohW10oaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2prYXVwcC9ub3JkL21hc3Rlci9tYW4vZmlndXJlcy9SRUFETUUtcGFsZXR0ZXMtMS5wbmcpCgpMZXQncyB0dXJuIHRoaXMgcGxvdDoKCmBgYHtyfQpwZW5ndWlucyAlPiUKICBnZ3Bsb3QoYWVzKHggPSBzZXgsIHkgPSBib2R5X21hc3NfZykpICsKICBnZW9tX2JveHBsb3QoYWVzKGZpbGwgPSBzcGVjaWVzKSkKYGBgCgoKSW50byB0aGlzIG9uZSEKCmBgYHtyfQpwZW5ndWlucyAlPiUKICBnZ3Bsb3QoYWVzKHggPSBzZXgsIHkgPSBib2R5X21hc3NfZykpICsKICBnZW9tX2JveHBsb3QoYWVzKGZpbGwgPSBzcGVjaWVzKSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IG5vcmQ6Om5vcmRfcGFsZXR0ZXMkZnJvc3QpCmBgYAoKTGV0J3MgdHJ5IG91dCB0aGUgYGZyb3N0YCBwYWxldHRlLgoKYGBge3J9CiMgd2UnbGwgbmVlZCB0byBsb2FkIHRoZSB7bm9yZH0gcGFja2FnZQpsaWJyYXJ5KG5vcmQpCgojIHlvdSBjYW4gY2hvb3NlIGNvbG9ycyB1c2luZyB0aGUgY29sb3IgaGV4IGNvZGVzCm5vcmQ6Om5vcmRfcGFsZXR0ZXMkZnJvc3QKYGBgCgoKCmBgYHtyfQojIGJ1dCB5b3UgbWlnaHQgcHJlZmVyIHRvIHVzZSBgc2NhbGVfZmlsbF9tYW51YWwoKWAgCiMgb3IgbW9yZSBzcGVjaWFsaXplZCBmdW5jdGlvbnMgbGlrZSBgc2NhbGVfZmlsbF9ub3JkKClgIAojIGluY2x1ZGVkIGluIHRoZSB7bm9yZH0gcGFja2FnZQpwZW5ndWlucyAlPiUKICBnZ3Bsb3QoYWVzKHggPSBzZXgsIHkgPSBib2R5X21hc3NfZykpICsKICBnZW9tX2JveHBsb3QoYWVzKGZpbGwgPSBzcGVjaWVzKSkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IG5vcmQ6Om5vcmRfcGFsZXR0ZXMkZnJvc3QpCiAgI3NjYWxlX2ZpbGxfbm9yZChwYWxldHRlID0gImZyb3N0IikKYGBgCgpPayBub3cgZm9yIGEgaGFuZHkgcGFja2FnZS9mdW5jdGlvbiB0cmlvIQoKYGBge3J9CiMgd2UnbGwgaGF2ZSB0byBsb2FkIHRoZSB7cHJpc21hdGljfSBwYWNrYWdlCmxpYnJhcnkocHJpc21hdGljKQoKcHJpc21hdGljOjpjb2xvcihub3JkOjpub3JkX3BhbGV0dGVzJGZyb3N0KQpgYGAKCmBwdXJycmAncyBgbWFwKClgIGZ1bmN0aW9uIGNhbiBoZWxwIHVzIGl0ZXJhdGUgdGhlIGBwcmlzbWF0aWM6OmNvbG9yKClgIGZ1bmN0aW9uIG92ZXIgYWxsIHBhbGV0dGVzIGluIGEgcGFsZXR0ZSBwYWNrYWdlIGxpa2UgYG5vcmRgIQoKPiBOb3RlOiBOb3QgYWxsIGNvbG9ycyB3aWxsIHNob3cgd2VsbCwgbGlrZSBgcG9sYXJuaWdodGAgYmVsb3cuIGBwcmlzbWF0aWM6OmNvbG9yKClgIHJlbGllcyBvbiBhIHBhY2thZ2UgdGhhdCBraW5kYSBoYXMgbGltaXRlZCBmdW5jdGlvbmFsaXR5IGluIHRoaXMgc2Vuc2UgKGBjcmF5b25gKS4gSXQncyBkb2luZyBpdHMgYmVzdCA6KQoKYGBge3IsIGV2YWwgPSBGQUxTRX0Kbm9yZDo6bm9yZF9wYWxldHRlcyAlPiUgbWFwKHByaXNtYXRpYzo6Y29sb3IpCmBgYAoKIyBFeHRyYSBtYXRlcmlhbCBiZWxvdyEKCiMjIFJlY3JlYXRpbmcgYSB7cGFsbWVycGVuZ3VpbnN9IHBsb3QKCkxldCdzIHByYWN0aWNlIGluIHJlYWwgdGltZSEKCiFbaHR0cHM6Ly9naXRodWIuY29tL2FsbGlzb25ob3JzdC9wYWxtZXJwZW5ndWluc10oaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2FsbGlzb25ob3JzdC9wYWxtZXJwZW5ndWlucy9tYXN0ZXIvbWFuL2ZpZ3VyZXMvUkVBRE1FLWZsaXBwZXItYmlsbC0xLnBuZykKCmBgYHtyIHNjYXR0ZXJwbG90LWJpbGwtbGVuZ3RofQojIHNjYXR0ZXJwbG90IHNlcXVlbmNlIC0tLS0KcGVuZ3VpbnMgJT4lCiAgZ2dwbG90KCkgKyAKICBnZW9tX3BvaW50KGFlcyh4ID0gZmxpcHBlcl9sZW5ndGhfbW0sIHkgPSBiaWxsX2xlbmd0aF9tbSkpICMgYWRkIGFlc3RoZXRpY3MKCnBlbmd1aW5zICU+JQogIGdncGxvdCgpICsKICBnZW9tX3BvaW50KGFlcyh4ID0gZmxpcHBlcl9sZW5ndGhfbW0sIHkgPSBiaWxsX2xlbmd0aF9tbSwgCiAgICAgICAgICAgICAgICAgY29sb3IgPSBzcGVjaWVzKSkgIyBhZGQgY29sb3IgcGVyIHNwZWNpZXMKCnBlbmd1aW5zICU+JQogIGdncGxvdCgpICsKICBnZW9tX3BvaW50KGFlcyh4ID0gZmxpcHBlcl9sZW5ndGhfbW0sIHkgPSBiaWxsX2xlbmd0aF9tbSwgCiAgICAgICAgICAgICAgICAgY29sb3IgPSBzcGVjaWVzLCBzaGFwZSA9IHNwZWNpZXMpKSAjIGFkZCBzaGFwZSBwZXIgc3BlY2llcwoKcGVuZ3VpbnMgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fcG9pbnQoYWVzKHggPSBmbGlwcGVyX2xlbmd0aF9tbSwgeSA9IGJpbGxfbGVuZ3RoX21tLCAKICAgICAgICAgICAgICAgICBjb2xvciA9IHNwZWNpZXMsIHNoYXBlID0gc3BlY2llcykpICMgYWRkIHNoYXBlIHBlciBzcGVjaWVzCgpwZW5ndWlucyAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9wb2ludChhZXMoeCA9IGZsaXBwZXJfbGVuZ3RoX21tLCB5ID0gYmlsbF9sZW5ndGhfbW0sIAogICAgICAgICAgICAgICAgIGNvbG9yID0gc3BlY2llcywgc2hhcGUgPSBzcGVjaWVzKSkgKwogIGdlb21fc21vb3RoKGFlcyh4ID0gZmxpcHBlcl9sZW5ndGhfbW0sIHkgPSBiaWxsX2xlbmd0aF9tbSwgCiAgICAgICAgICAgICAgICAgIGNvbG9yID0gc3BlY2llcykpCgpwZW5ndWlucyAlPiUKICBnZ3Bsb3QoYWVzKHggPSBmbGlwcGVyX2xlbmd0aF9tbSwgeSA9IGJpbGxfbGVuZ3RoX21tKSkgKyAKICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IHNwZWNpZXMsIHNoYXBlID0gc3BlY2llcykpICsKICBnZW9tX3Ntb290aChhZXMoY29sb3IgPSBzcGVjaWVzKSwgc2UgPSBGQUxTRSwgbWV0aG9kID0gImxtIikKYGBgCgpgYGB7ciBzY2F0dGVycGxvdC1ib2R5LW1hc3N9CnBlbmd1aW5zICU+JQogIGdncGxvdCgpICsKICBnZW9tX3BvaW50KGFlcyh4ID0gZmxpcHBlcl9sZW5ndGhfbW0sIHkgPSBib2R5X21hc3NfZywgCiAgICAgICAgICAgICAgICAgY29sb3IgPSBzcGVjaWVzLCBzaGFwZSA9IHNwZWNpZXMpKQpgYGAKCmBgYHtyIGhpc3RvZ3JhbX0KcGVuZ3VpbnMgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21faGlzdG9ncmFtKGFlcyh4ID0gZmxpcHBlcl9sZW5ndGhfbW0pKQoKcGVuZ3VpbnMgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21faGlzdG9ncmFtKGFlcyh4ID0gZmxpcHBlcl9sZW5ndGhfbW0sIGNvbG9yID0gc3BlY2llcykpCgpwZW5ndWlucyAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKHggPSBmbGlwcGVyX2xlbmd0aF9tbSwgZmlsbCA9IHNwZWNpZXMpKQoKcGVuZ3VpbnMgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21faGlzdG9ncmFtKGFlcyh4ID0gZmxpcHBlcl9sZW5ndGhfbW0sIGZpbGwgPSBzcGVjaWVzLCAKICAgICAgICAgICAgICAgICAgICAgcG9zaXRpb24gPSAiaWRlbnRpdHkiLCBhbHBoYSA9IDAuNSkpCmBgYAoKCiMgVGlkeVR1ZXNkYXkKCiMjIEdldHRpbmcgc3RhcnRlZAoKLSBbSW50cm8gQmxvZyBhbmQgaGlzdG9yeV0oaHR0cHM6Ly90aGVtb2NrdXAuYmxvZy9wb3N0cy8yMDE4LTEyLTExLXRpZHl0dWVzZGF5LWEtd2Vla2x5LXNvY2lhbC1kYXRhLXByb2plY3QtaW4tci8pCi0gW0ludHJvIFR3ZWV0IGJ5IFRvbSBNb2NrIChSU3R1ZGlvKV0oaHR0cHM6Ly90d2l0dGVyLmNvbS90aG9tYXNfbW9jay9zdGF0dXMvMTI4Nzc3NDU3NTgzMzYxNjM4ND9zPTIwKQotIFtUaWR5VHVlc2RheXMgR2l0SHViXShodHRwczovL2dpdGh1Yi5jb20vcmZvcmRhdGFzY2llbmNlL3RpZHl0dWVzZGF5L2Jsb2IvbWFzdGVyL1JFQURNRS5tZCkKLSBbVGlkeVR1ZXNkYXkgUG9kY2FzdF0oaHR0cHM6Ly90d2l0dGVyLmNvbS90aWR5cG9kKQotIFtUaWR5VHVlc2RheSBTaWdodC1VbnNlZW4gb24gWW91VHViZV0oaHR0cHM6Ly93d3cueW91dHViZS5jb20vd2F0Y2g/dj1JbXBYYXdQTkNmTSkKLSBbe3RpZHl0dWVzZGF5Un0gcGFja2FnZSB0byBoZWxwIHlvdSBlYXNpbHkgZG93bmxvYWQgdGhlIGRhdGEgc2V0XShodHRwczovL2dpdGh1Yi5jb20vdGhlYmlvZW5naW5lZXIvdGlkeXR1ZXNkYXlSKQoKIyMgdGlkeXR1ZXNkYXlSCmBgYHtyIGV2YWw9RkFMU0V9CiMgaW5zdGFsbC5wYWNrYWdlcygidGlkeXR1ZXNkYXlSIikKIyByZW1vdGVzOjppbnN0YWxsX2dpdGh1YigidGhlYmlvZW5naW5lZXIvdGlkeXR1ZXNkYXlSIikKCmxpYnJhcnkodGlkeXR1ZXNkYXlSKQoKIyBsb2FkIHRoZSBkYXRhCnR0X2RhdGEgPC0gdHRfbG9hZCgiMjAyMC0wNy0yNyIpICMgZXJyb3IgbWVzc2FnZQp0dF9kYXRhIDwtIHR0X2xvYWQoIjIwMjAtMDctMjgiKQp0dF9kYXRhIDwtIHR0X2xvYWQoMjAyMCwgd2Vlaz0zMSkKCiMgdGFrZSBhIHBlZWsKcmVhZG1lKHR0X2RhdGEpCnByaW50KHR0X2RhdGEpCmBgYAoKIyMgTGV2ZWwgdXAgd2l0aCBtb2RlbGluZwotIFtKdWxpYSBTaWxnZSAoUlN0dWRpbykgdGVhY2hlcyBUaWR5bW9kZWxzIHdpdGgge3BhbG1lcnBlbmd1aW5zfSBvbiBZb3VUdWJlXShodHRwczovL3d3dy55b3V0dWJlLmNvbS93YXRjaD92PXo1N2kyR1ZjZHd3KQoKIyMgRXhhbXBsZXMKCi0gU3BlY2lmaWMgdG8ge3BhbG1lcnBlbmd1aW5zfToKICAtIEZvY3VzIG9uIGZvbnRzIGFuZCBmb3JtYXR0aW5nOiBodHRwczovL3R3aXR0ZXIuY29tL2VsbGFta2F5ZS9zdGF0dXMvMTI4OTE1NzEzOTQzNzYyMTI1MD9zPTIwCiAgLSBSLUxhZGllcyBBbWVzOiBodHRwczovL3R3aXR0ZXIuY29tL1JMYWRpZXNBbWVzL3N0YXR1cy8xMjk0NDI1MzU5Mzg4MTE0OTQ0P3M9MjAKICAKLSBHZW5lcmFsIHRvICN0aWR5dHVlc2RheToKICAtIFItTGFkaWVzIENoaWNhZ28gVGlkeVR1ZXNkYXkgbGVhZGVyIE9sYSE6IGh0dHBzOi8vdHdpdHRlci5jb20vQW1hemluZ1NwZWNpYWxpCiAgLSBSLUxhZGllcyBDaGljYWdvIFRpZHlUdWVzZGF5IHNldHVwOiBodHRwczovL3R3aXR0ZXIuY29tL1JMYWRpZXNDaGljYWdvL3N0YXR1cy8xMTkyMjQzMTcwNDEyNzYxMDg4P3M9MjA=