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!
-
-
-
@@ -3116,17 +3081,11 @@
Taking a closer look at penguins
Get a full view of the dataset:
-
-
-
Or catch a glimpse
:
-
-
-
@@ -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
-
-
-
@@ -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=