12 Tidy Data

12.1 Introduction

“Happy families are all alike; every unhappy family is unhappy in its own way.” - Leo Tolstoy

“Tidy datasets are all alike, but every messy dataset is messy in its own way.” - Hadley Wickham

In this cahpter, you will learn a consisten way to organise your data in R, an organisation called tidy data. Getting your data into this format requires some upfront work, but that work pays off in the long term. One you have tidy data and tidy tools provided by packages in the tidyverse, you will spend much less time munging data from one representation to another, allowing you to spend more time on the analytic questions at hand.

12.1.1 Prerequisites

In this chapter we’ll focus on tidyr, a package that provides a bunch of tools to help tidy up your messy datasets. tidy is a member of the core tidyverse.

library(tidyverse)

12.2 Tidy data

There are many ways to represent the same underlying data, but some datasets are easier to use than others.

There are three interrelated rules which make a dataset tidy:

  1. Each variable must have its own column.
  2. Each observation must have its own row.
  3. Each value must have its own cell.

These three rules are interrelated because it’s impossible to only satisfy two of the three. That interrelationship leads to an even simpler set of practical instructions:

  1. Put each dataset in a tibble.
  2. Put each variable in a column.

In this example, only table1 is tidy. It’s the only representation where each column is a variable.

2 main advantages to tidy data.

1.There’s a general advantage to picking one consistent way of storing data. If you have a consistent data structure, it’s easier to learn the tools that work with it because they have a underlying uniformity.

  1. There’s a specific advantage to placing variables in columns because it allows R’s vectorised nature to shine. As you learned in mutate and summary functions, most built-in R functions work with vectors of values. That makes transforming tidy data feel particularly natural.

dplyr, ggplot2, and all the other packages in the tidyverse are designed to work with tidy data.

12.2.1 Exercises

  1. Using prose, describe how the variables and observations are organised in each of the sample tables.

Table1 is organized with four variables across four columns: country, year, cases and population. It is easy to imagine creating many graphics with this format and faceting easily by country and year.

Table2 is similar to table one - country and year are the same - cases and population have been turned into values; essentially combined to create a new column “type”. Count then represents respective numbers of cases and population.

Tables 3 combines the cases and population into a single new column called “rate” - essentially cases/population. While this new data has its own advantages it limits the options available for analysis. It is better to have the raw data and then create a new “rate” variable from the variables in column 1 than to start with the rate.

Tables 4 and 5 are split across two tables and defined by year. The first tibble contains cases data and the second contains population data - making it thus difficult to compare case and poulation data without performing a SQL join.

  1. Compute the rate for table2, and table4a + table4b. You will need to perform four operations:

  2. Extract the number of TB cases per country per year.
  3. Extract the matching population per country per year.
  4. Divide cases by population, and multiply by 10000.
  5. Store back in the appropriate place.

Which representation is easiest to work with? Which is hardest? Why?

table1 <- tibble(
  country = c(
    rep("Afghanistan", 2),
    rep("Brazil", 2),
    rep("China", 2)
  ),
  year = rep(c(1999, 2000), 3),
  cases = c(745, 2666, 37737, 80488, 212258, 213766),
  population = c(19987071, 20595360, 172006362, 174504898, 1272915272, 1280428583)
)

table2 <- tibble(
  country = c(
    rep("Afghanistan", 4),
    rep("Brazil", 4),
    rep("China", 4)
  ),
  year = rep(c(1999, 1999, 2000, 2000), 3),
  type = rep(c("cases", "population", "cases", "population"), 3),
  count = c(745, 19987071, 2666, 20595360, 37737, 172006362, 80488, 174504898, 212258, 1272915272, 213766, 1280428583)
)

table3 <- tibble(
  country = c(
    rep("Afghanistan", 2),
    rep("Brazil", 2),
    rep("China", 2)
  ),
  year = rep(c(1999, 2000), 3),
  rate = c("745/19987071", "2666/20595360", "37737/172006362", "80488/174504898", "212258/1272915272", "213766/1280428583")
)

table4a <- tibble(
  country = c("Afghanistan", "Brazil", "China"),
  '1999' = c(745, 37737, 212258),
  '2000' = c(2666, 80488, 213766)
)

table4b <- tribble(
~country, ~`1999`, ~`2000`,
#---------|-----------|---------
"Afghanistan", 19987071, 20595360,
"Brazil", 172006362, 174504898,
"China", 1272915272, 1280428583
)
table2_mod <- tibble(
  country = table2$country[table2$type == "cases"],
  year = table2$year[table2$type == "cases"],
  cases = table2$count[table2$type == "cases"],
  population = table2$count[table2$type == "population"],
  rate = (cases/population) * 10000
)

table2_mod
table4c <-
  tibble(
    country = table4a$country,
    `1999` = (table4a$`1999`/table4b$`1999`) * 10000,
    `2000` = (table4a$`2000`/table4b$`2000`) * 10000
  )

table4c

Neither were particularly easy to work with, but it was more confusing thinking about cases and population in terms of years.

  1. Recreate the plot showing change in cases over time using table2 instead of table1. What do you need to do first?
# Example
ggplot(table1, aes(year, cases)) +
  geom_line(aes(group = country), color = "grey50") +
  geom_point(aes(color = country))

# Actual
table2 %>%
  filter(type == "cases") %>%
  ggplot(aes(year, count)) +
  geom_line(aes(group = country), color = "grey50") +
  geom_point(aes(color = country))

Just need to filter out “population” data in type column from table.

12.3 Pivoting

Most data that you will encounter will be untidy. There are two main reasons:

  1. Most people aren’t familiar with the principles of tidy data, and it’s hard to derive them yourself unless you spend a lot of time working with data.

  2. Data is often organised to failitate some use other than analysis. For example, data is often organised to make entry as easy as possible.

This means for most real analyses, you’ll need to do some tidying. The first step is always to figure out what the variables and observations are. Sometimes this is easy; other times you’ll need to consult with the people who originall generated the data. The second step is to resolve one of two common problems:

  1. One variable might be spread across multiple columns.

  2. One observation might be scattered across multiple rows.

Typically a dataset will only suffer from one of these problems; it’ll only suffer from both if you’re really unlucky! To fix these problems, you’ll need the two most important functions in tidyr: pivot_longer() and pivot_wider().

12.3.1 Longer

A common problem is a datset where some of the column names are not names of variables, but values of a variable. Take table4a: the column names 1999 and 2000 represent values of the year variable, the values in the 1999 and 2000 columns represent values of the cases variable, and each row represents two observations, not one.

table4a

To tidy a dataset like this, we need to pivot the offending columns into a new pair of variables. To describe that operation we need three paramaters:

  • The set of columns whose names are values, not variables. In this example, those are the columns 1999 and 2000_.
  • The name of the variable to move the column names to. Here it is year.
  • The name of the variable to move the column values to. Here it’s cases.

Together those paramaters generate the call to pivot_longer():

table4a

table4a %>%
  pivot_longer(cols = c(`1999`, `2000`), names_to = "year", values_to = "cases")

The columns to pivot are specified with dplyr::select() style notation. Here there are only two columns, so we list them individually. Note that “1999” and “2000” are non-syntactic names (because they don’t start with a letter) so we have to surround them in backticks. To refresh your memory of the other ways to select columns see, select.

year and cases do not exist in table41 so we put their names in quotes.

In the final result, the pivoted columns are dropped, and we get new year and cases columns. Otherwise, the relationships between the original variables are preserved. Visually, this is shown in Figure 12.2.

pivot_longer() makes datasets longer by increasing the number of rows and decreasing the number of columns. I don’t believe it makes sense to describe a datset as being in “long form”. Length is a relative term, and you can only say (e.g.) that datset A is longer than dataset B.

We can use pivot_longer() to tidy table4b in a similar fashion. The only difference is the variable stored in the cell values:

table4b %>%
  pivot_longer(cols = c(`1999`, `2000`), names_to = "year", values_to = "population")

To combine the tidied versions of table4a and table4b into a single tibble, we need to use dplyr::left_join(), which you’ll learn about in relational data.

tidy4a <- table4a %>%
  pivot_longer(cols = c(`1999`, `2000`), names_to = "year", values_to = "cases")

tidy4b <- table4b %>%
  pivot_longer(cols = c(`1999`, `2000`), names_to = "year", values_to = "population")
left_join(tidy4a, tidy4b, by = c("country", "year"))

12.3.2 Wider

pivot_wider() is the opposite of pivot_longer(). You use it when an observation is scattered across multiple rows. For example, take table2: an observation is a country in a year, but each observation is spread across two rows.

table2 %>%
  pivot_wider(id_cols = c(country, year), names_from = type, values_from = count)

To tidy this up, we first analyse the representation in similar way to pivot_longer(). This time, however, we only need two paramaters:

Once we’ve figured that out, we can use pivot_wider(), as shown programmatically below, and visually in Figure 12.3.

# Above we provided __id_cols__, but they don't appear necessary in this example.
table2 %>%
  pivot_wider(names_from = type, values_from = count)

As you might have guessed from their names, pivot_wider() and pivot_longer() are complements. pivot_longer() makes wide tables narrower and longer; pivot_wider() makes long tables shorter and wider.

12.3.3 Exercises

  1. Why are pivot_longer() and pivot_wider() not perfectly symmetrical? Carefully consider the following example:
stocks <- tibble(
  year = c(2015, 2015, 2016, 2016),
  half = c( 1, 2, 1, 2),
  return = c(1.88, 0.59, 0.92, 0.17)
)
stocks

stocks %>%
  pivot_wider(names_from = year, values_from = return)

stocks %>%
  pivot_wider(names_from = year, values_from = return) %>%
  pivot_longer(`2015`:`2016`, names_to = "year", values_to = "return")

They are not perfectly symmetrical because when you pivot you change the nature of the data (columns, values and observations). For example, when we pivot_wider from our original dataset, each observation contains the half and return by respective year, but the year is provided by the column (the variable). It is a relatively “smaller” dataset, but it is confusing to think of the yearly returns in terms of variables. Were there no description, this data would be somewhat difficult to understand.

pivot_longer() has a names_ptypes argument, e.g. names_ptypes = list(year = double()). What does it do?

stocks %>%
  pivot_wider(names_from = year, values_from = return) %>%
  pivot_longer(`2015`:`2016`, names_to = "year", values_to = "return", names_ptypes = list(year = double()))
Error: Can't convert <character> to <double>.
Run `rlang::last_error()` to see where the error occurred.

It defines the type, class, and attributes of a vector. It should be used to confirm that the created columns are the types that you expect. It is not to be used to change the column type (hence, the above error message). Instead use names_transform or values_transform.

stocks %>%
  pivot_wider(names_from = year, values_from = return) %>%
  pivot_longer(`2015`:`2016`, names_to = "year", values_to = "return", names_transform = list(year = as.double)
               )
  1. Why does this code fail?
table4a %>%
  pivot_longer(c(1999, 2000), names_to = "year", values_to = "cases")
Error: Can't subset columns that don't exist.
x Locations 1999 and 2000 don't exist.
ℹ There are only 3 columns.
Run `rlang::last_error()` to see where the error occurred.

The code fails because we need to wrap our column variables in backticks -> c(1999, 2000). These names do not follow proper R naming conventions (they do not begin with a letter) so we need to specify what they are - in this case column names.

table4a %>%
  pivot_longer(c(`1999`, `2000`), names_to = "year", values_to = "cases")
  1. What would happen if you widen this table? Why? How could you add a new column to uniquely identify each value?
people <- tribble(
  ~name,             ~names,    ~values,
  #-----------------|----------|--------
  "Phillip Woods",   "age",     45,
  "Phillip Woods",   "height",  186,
  "Phillip Woods",   "age",     50,
  "Jessica Cordero", "age",     37,
  "Jessica Cordero", "height",   156
)

people

Before running a script to widen the only issue we might have is that we have two ages observations for Phillip Woods, but only one height observation - our new dataset won’t be balanced. We may be able to accomplish this adding a new column denoting the observation number.

people %>%
  group_by(name, names) %>%
  mutate(obs = row_number()) %>%
  pivot_wider(names_from = name, values_from = values)

With this particular type of data however it would be better if age and height were the columns and Philip Woods and Jessica Cordero remained in the name column. Ideally, we would just replicate the value of height for Philip Woods because it is unlikely that it is any different for ages 45 and 50.

  1. Tidy the simple tibble below. Do you need to make it wider or longer? What are the variables?
preg <- tribble(
  ~pregnant, ~male, ~female,
  "yes",     NA,    10,
  "no",      20,    12
)
preg

preg %>%
  pivot_longer(cols = c(male, female), names_to = "gender", values_to = "count")

# Can remove NA value for "pregnant males" using values_drop_na
preg %>%
  pivot_longer(cols = c(male, female), names_to = "gender", values_to = "count", values_drop_na = TRUE)

The data seems to make the most sense if we pivot_longer. In this example the dataset appears to resemble counts of pregnant males and females (obviously there are no pregnant males), but the data is represented by NA.

12.4 Separating and uniting

So far you’ve learned how to tidy table2 and table4, but not table3. table3 has a different problem: we have one column (rate) that contains two variables (cases and population). To fix this problem, we’ll need the separate() function. You’ll also learn about the complement of separate(): unite(), which you use if a single variable is spread across multiple columns.

12.4.1 Separate

separate() pulls apart one column into multiple columns, by splitting wherever a separator character appears. Take table3:

table3 %>%
  separate(col = rate, into = c("cases", "population"), sep = "/")

The rate column contains both cases and population variables, and we need to split it into two variables. separate() takes the name of the column to separate, and the names of the columns to separate into, as shown in Figure 12.4 and the code above.

Above we specified what the separator should be. However, by default, separate() will split values wherever it sees a non-alphanumeric character (i.e. a character that isn’t a number or letter). In this case, we didn’t need to specify “/” as the separator, but in more complicated cases it will likely be necessary.

(Formally, sep is a regular expression, which you’ll learn more about in strings).

Look carefully at the column types: you’ll notice that cases and population are character columns. This is the default behavior in separate(): it leaves the type of the column as is. Here, however, it’s not very useful as those really are numbers. We can ask separate() to try and convert to better types using convert = TRUE:

table3 %>%
  separate(col = rate, into = c("cases", "population"), sep = "/", convert = TRUE)

You can also pass a vector of integers to sep. separate() will interpret the integers as positions to split at. Positive values start at 1 on the far-left of the strings; negative values start at -1 on the far-right of the strings. When using integers to separate strings, the length of sep should be one less than the number of names in into.

You can use this arrangement to separate the last two digits of each year. This make this data less tidy, but is useful in other cases, as you’ll see in a little bit.

table3 %>%
  separate(col = year, into = c("century", "year"), sep = 2)

12.4.2 Unite

unite() is the inverse of separate(): it combines multiple columns into a single column. You’ll need it much less frequrently than separate(), but it’s still a useful tool to have in your back pocket.

We can use unite() to rejoin the century and year columns that we created in the last example. That data is saved as tidyr::table5. unite takes a data frame, the name of the new variable to create, and a set of columns to combine, again specified in dplyr::select() style:

table5 %>%
  unite(col = year, c(century, year), sep = "")

12.4.3 Exercises

  1. What do the extra and fill arguments do in separate()? Experiment with the various options for the following two oy datasets.

extra controls what happens when there are too many pieces when sep is a character vector. There are three valid options:

  • “warn” (the default): emit a warning and drop extra values.
  • “drop”: drop any extra values without a warning.
  • “merge”: only splits at most length(into) times

fill If sep is a character vector, this controls what happens when there are not enough pieces. There are three valid options:

  • “warn” (the default): emit a warning and fill from the right
  • “right”: fill with missing values on the right
  • “left”: fill with missing values on the left
tibble(x = c("a,b,c", "d,e,f,g", "h,i,j")) %>%
  separate(x, c("one", "two", "three"), extra = "warn")
Expected 3 pieces. Additional pieces discarded in 1 rows [2].
tibble(x = c("a,b,c", "d,e,f,g", "h,i,j")) %>%
  separate(x, c("one", "two", "three"), extra = "drop")

tibble(x = c("a,b,c", "d,e,f,g", "h,i,j")) %>%
  separate(x, c("one", "two", "three"), extra = "merge")
# In these examples the command expects "more data".

# Emit a warning and fill from the right
tibble(x = c("a,b,c", "d,e", "f,g,i")) %>% 
  separate(x, c("one", "two", "three"), fill = "warn")
Expected 3 pieces. Missing pieces filled with `NA` in 1 rows [2].
# Fill with missing values on the right
tibble(x = c("a,b,c", "d,e", "f,g,i")) %>% 
  separate(x, c("one", "two", "three"), fill = "right")

# Fill with missing values on the left
tibble(x = c("a,b,c", "d,e", "f,g,i")) %>% 
  separate(x, c("one", "two", "three"), fill = "left")
  1. Both unite() and separate() have a remove argument. What does it do? Why would you set it to FALSE?

remove If TRUE, remove input column from output data frame. You would set it to FALSE if you want to create a new variable, but keep the old one. It defaults to TRUE.

  1. Compare and contrast separate() and extract(). Why are there three variations of separation (by position, by separator, and with groups), but only one unite?

Briefly mentioned earlier, separate() is a type of regular expression or regex. Thus, when using separate() you are telling the built-in regex function how to separate the data, i.e. by position or delimiter. However, extract() allows for a little bit more flexibility because it lets you write the regular expression dictating how to split up the data.

For example, in the example below separate() is unable to properly separate the data because there is no delimiter to separate by and the positions vary (in some cases there are two characters and in some cases there is only one).

# Failed parse
tibble(x = c("X1", "X20", "AA11", "AA2")) %>%
  separate(col = x, into = c("variable", "id"), sep = 1)
# Failed parse
tibble(x = c("X1", "X20", "AA11", "AA2")) %>%
  separate(col = x, into = c("variable", "id"), sep = 2)

# Failed parse
tibble(x = c("X1", "X20", "AA11", "AA2")) %>%
  separate(col = x, into = c("variable", "id"), sep = "")
Expected 2 pieces. Additional pieces discarded in 4 rows [1, 2, 3, 4].
# Using extract
tibble(x = c("X1", "X20", "AA11", "AA2")) %>%
  extract(col = x, into = c("variable", "id"), regex = "([A-Z]+)([0-9]+)")

In the regular expression above, the parentheses indicate what each segment to be read should look like. Thus, for variable we are passing on the condition that it must be alphabetical [A-Z] and can be of any length (+). The second term, id, must be numeric [0-9] and can be of any length (+). The entire expression must be surrounded by quotes.

Thus when separating a single variable into multiple columns there can be multiple criteria by which you would like to separate.

However, as we’ll see in the example below when uniting data from multiple columns there is always only one choice as to how to combine their contents.

# Unite
tibble(x = c("A", "B", "C", "D"),
       y = c("1", "2", "3", "4")) %>%
  unite(col = "XY", c(x, y), sep = "_")

# OR
tibble(x = c("A", "B", "C", "D"),
       y = c("1", "2", "3", "4")) %>%
  unite(col = "XY", c(x, y), sep = "")

12.5 Missing values

Changing the representation of a datset brings up an important subtlety of missing values. Surprisingly, a value can be missing in one of two possible ways:

Let’s illustrate this idea with a very simple data set:

stocks <- tibble(
  year   = c(2015, 2015, 2015, 2015, 2016, 2016, 2016),
  qtr    = c(   1,    2,    3,    4,    2,    3,    4),
  return = c(1.88, 0.59, 0.35,   NA, 0.92, 0.17, 2.66)
)

stocks

There are two missing values in this dataset:

One way to think about the difference is with this Zen-like koan: An explicit missing value is the presence of an absence; an implicit missing value is the absence of a presence.

The way that a dataset is represented can make implicit values explicit. For example, we can make the implicit missing value explicit by putting years in the columns:

stocks %>%
  pivot_wider(names_from = year, values_from = return)

Because these explicit missing values may not be important in other representations of the data, you can set values_drop_na = TRUE in pivot_longer() to turn explicit missing values implicit:

stocks %>%
  pivot_wider(names_from = year, values_from = return) %>%
  pivot_longer(
    cols = c(`2015`, `2016`),
    names_to = "year",
    values_to = "return",
    values_drop_na = TRUE
  )

Another important tool for making missing values explicit in tidy data is complete():

stocks %>%
  complete(year, qtr)

complete() takes a set of columns, and finds all unique combinations. It then ensures the original dataset contains all those values, filling in explicit NAs where necessary. There’s one other important tool that you should know for working with missing values. Sometimes when a data source has primarily been used for data entry, missing values indicate that the previous value should be carried forward:

treatment <- tribble(
  ~ person,           ~ treatment, ~response,
  "Derrick Whitmore", 1,           7,
  NA,                 2,           10,
  NA,                 3,           9,
  "Katherine Burke",  1,           4
)

You can fill in these missing values with fill(). It takes a set of columns where you want missing values to be replaced by the most recent non-missing value (sometimes called last observation carried forward).

treatment %>%
  fill(person, .direction = "down")

12.5.1 Exercises

  1. Compare and contrast the fill arguments to pivot_wider() and complete().

Fill does not make changes to the structure of the data. It does not reorganize columns. Pivot_wider takes the values in a column and creates new columns with them. Complete finds all existing combinations using a set of columns and then ensures the original dataset contains all those values, filling in explicit NAs where necessary.

Most likely you would pivot_wider and then complete which would likely create some NAs, but those NAs could possibly be filled in using fill.

  1. What does the direction argument to fill() do?

.direction indicates in what direction the fill should happen c(“down”, “up”, “downup”, “updown”). Down and up are fairly intuitive, but “downup” means first down and then up and “updown” means first up and then down.

12.6 Case Study

Tidying a messy dataset from the World Health Organization on tuberculosis cases.

Here we move all of the columns that seem to provide case data to a new variable called “key” and move the values from the respective columns into the new column “cases”.

who1 <- who %>%
  pivot_longer(cols = new_sp_m014:newrel_f65,
               names_to = "key",
               values_to = "cases",
               values_drop_na = TRUE)
who1

We can get some hint of the structure of the values in the new key column by counting them:

who1 %>%
  count(key)

According to the data dictionary:

  1. The first three letters of each column denote whether the column contains new or old cases of TB. In this dataset, each column contains new cases.

  2. The next two letters descripe the type of TB:

  1. The sixth letter gives the sex of TB patients. The dataset groups cases by males (m) and females (f).

  2. The remaining numbers gives the age group. The dataset groups cases into seven age groups:

We need to make a minor fix to the format of the column names: unfortunately the names are slightly inconsisten because instead of new_rel we have newrel (it’s hard to spot this here but if you don’t fix it we’ll get errors in subsequent steps). You’ll learn about str_replace() in strings, but the basic idea is pretty simple: replace the characters “newrel” with “new_rel”. This makes all variable names consistent.

who2 <- who1 %>%
  mutate(key = str_replace(key, "newrel", "new_rel"))
who2 %>%
  filter(grepl("new_rel", key, ignore.case = TRUE) == TRUE)

We can separate the values in each code with two passes of separate(). The first pass will split the codes at each underscore.

who3 <- who2 %>%
  separate(col = key, into = c("newold", "type", "sexage"), sep = "_") %>%
  separate(col = sexage, into = c("sex", "age"), sep = 1)

who3

who4 <- subset(who3, select = -c(iso2, iso3, newold))
who4

The who dataset is now tidy!!!

In future cases, rather than performing each operation one code at a time, we would build up a complex pipe to perform all of the operations in a single chunk of code.

who %>%
  pivot_longer(
    cols = new_sp_m014:newrel_f65, 
    names_to = "key", 
    values_to = "cases", 
    values_drop_na = TRUE
  ) %>% 
  mutate(
    key = stringr::str_replace(key, "newrel", "new_rel")
  ) %>%
  separate(key, c("new", "var", "sexage")) %>% 
  select(-new, -iso2, -iso3) %>% 
  separate(sexage, c("sex", "age"), sep = 1)

12.6.1 Exercises

  1. In this case study I set values_drop_na = TRUE just to make it easier to check that we had the correct values. Is this reasonable? Think about how missing values are represented in this dataset. Are there implicit missing values? What’s the difference between an NA and zero?

While it might not be advisable considering we started off knowing very little about the data, in hindsight it appears fine. The data is structured to show the number of tuberculosis cases by country, year, type, sex, and age. This means that for 219 countries represented in the dataset, they should each have 34 years of data (1980 - 2013), on 4 distinct types of tubeculosis and 7 age groups.

who1 %>%
  filter(cases == 0) %>%
  nrow()
[1] 11080

There are 11,080 rows in the data where the number of cases equals zero.

An NA means nothing was explicitly filled in for that value. A zero means a zero was entered.

pivot_longer(who, c(new_sp_m014:newrel_f65), names_to = "key", values_to = "cases") %>%
  group_by(country, year) %>%
  mutate(prop_missing = sum(is.na(cases))/n()) %>%
  filter(prop_missing > 0, prop_missing < 1)

Finally, I will check for implicit missing values. Implicit missing values are (year, country) combinations that do not apear in the data.

nrow(who)
[1] 7240
who %>%
  complete(country, year) %>%
  nrow()
[1] 7446
anti_join(complete(who, country, year), who, by = c("country", "year")) %>%
  select(country, year) %>%
  group_by(country) %>%
  summarise(min_year = min(year), max_year = max(year))

To summarize:

  • 0 is used to represent no cases of TB.
  • Explicit missing values (__NA__s) are used to represent missing data for (country, year) combinations in which the country existed in that year.
  • Implicit missing values are used to represent missing data because a country did not exist in that year.
  1. What happens if you neglect the mutate() step? (__mutate(names_from = stringr::str_replace(key, “newrel”, “new_rel”)))?
who %>%
  pivot_longer(
    cols = new_sp_m014:newrel_f65, 
    names_to = "key", 
    values_to = "cases", 
    values_drop_na = TRUE
  ) %>% 
  mutate(
    key = stringr::str_replace(key, "newrel", "new_rel")
  ) %>%
  separate(key, c("new", "var", "sexage")) %>% 
  select(-new, -iso2, -iso3) %>% 
  separate(sexage, c("sex", "age"), sep = 1)
who %>%
  pivot_longer(
    cols = new_sp_m014:newrel_f65, 
    names_to = "key", 
    values_to = "cases", 
    values_drop_na = TRUE
  ) %>%
  separate(key, c("new", "var", "sexage")) %>% 
  select(-new, -iso2, -iso3) %>% 
  separate(sexage, c("sex", "age"), sep = 1)
Expected 3 pieces. Missing pieces filled with `NA` in 2580 rows [243, 244, 679, 680, 681, 682, 683, 684, 685, 686, 687, 688, 689, 690, 691, 692, 903, 904, 905, 906, ...].

If you neglect the mutate step you get an error message when you try to separate the key variable because when it tries to separate by the "_" delimiter it does not find one and so NAs are created.

who %>%
  select(country, iso2, iso3) %>%
  group_by(country, iso2, iso3) %>%
  distinct() %>%
  extract(col = country, into = "abb3", regex = "([a-zA-Z]{3})", remove = FALSE) %>%
  extract(col = country, into = "abb2", regex = "([a-zA-Z]{2})", remove = FALSE) %>%
  mutate(abb2 = tolower(abb2),
         abb3 = tolower(abb3),
         iso2 = tolower(iso2),
         iso3 = tolower(iso3)) %>%
  filter(abb2 != iso2 & abb3 != iso3)

Unfortunately, the acronyms do not line up 100% evenly, but it seems pretty clear that these are just abbreviations using two and 3 letters.

A clearer way to do this is to just check if there are more than one unique combination for each country.

select(who, country, iso2, iso3) %>%
  distinct() %>%
  group_by(country) %>%
  filter(n() > 1)
who4 %>%
  group_by(country, year, sex) %>%
  summarise(tot_cases = sum(cases))  %>%
  unite(country_sex, c(country, sex), sep = "_", remove = FALSE) %>%
  ggplot(aes(year, tot_cases)) +
  geom_line(aes(group = country_sex, color = sex)) +
  coord_cartesian(xlim = c(1995, 2013))
`summarise()` has grouped output by 'country', 'year'. You can override using the `.groups` argument.

It would probably make most sense to split the country data into quantiles and then examine those lines.

12.7 Non-tidy data

Just because a dataset might be “messy” or not “tidy” does not mean that it is useless. Two main reasons for using other data structures are:

  • Alternative representations may have substantial performance or space advantages.
  • Specialised fields have evolved their own conventions for storing data that may be quite different to the conventions of tidy data.

Tidy data is a nice default, but there are good reasons to use other structures.

LS0tCnRpdGxlOiAiQ2hhcHRlciAxMiAtIFRpZHkgRGF0YSIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyMgMTIgVGlkeSBEYXRhCgojIyMgMTIuMSBJbnRyb2R1Y3Rpb24KCiJIYXBweSBmYW1pbGllcyBhcmUgYWxsIGFsaWtlOyBldmVyeSB1bmhhcHB5IGZhbWlseSBpcyB1bmhhcHB5IGluIGl0cyBvd24gd2F5LiIgLSBMZW8gVG9sc3RveQoKIlRpZHkgZGF0YXNldHMgYXJlIGFsbCBhbGlrZSwgYnV0IGV2ZXJ5IG1lc3N5IGRhdGFzZXQgaXMgbWVzc3kgaW4gaXRzIG93biB3YXkuIiAtIEhhZGxleSBXaWNraGFtCgpJbiB0aGlzIGNhaHB0ZXIsIHlvdSB3aWxsIGxlYXJuIGEgY29uc2lzdGVuIHdheSB0byBvcmdhbmlzZSB5b3VyIGRhdGEgaW4gUiwgYW4gb3JnYW5pc2F0aW9uIGNhbGxlZCBfX3RpZHkgZGF0YV9fLiBHZXR0aW5nIHlvdXIgZGF0YSBpbnRvIHRoaXMgZm9ybWF0IHJlcXVpcmVzIHNvbWUgdXBmcm9udCB3b3JrLCBidXQgdGhhdCB3b3JrIHBheXMgb2ZmIGluIHRoZSBsb25nIHRlcm0uIE9uZSB5b3UgaGF2ZSB0aWR5IGRhdGEgYW5kIHRpZHkgdG9vbHMgcHJvdmlkZWQgYnkgcGFja2FnZXMgaW4gdGhlIHRpZHl2ZXJzZSwgeW91IHdpbGwgc3BlbmQgbXVjaCBsZXNzIHRpbWUgbXVuZ2luZyBkYXRhIGZyb20gb25lIHJlcHJlc2VudGF0aW9uIHRvIGFub3RoZXIsIGFsbG93aW5nIHlvdSB0byBzcGVuZCBtb3JlIHRpbWUgb24gdGhlIGFuYWx5dGljIHF1ZXN0aW9ucyBhdCBoYW5kLgoKIyMjIDEyLjEuMSBQcmVyZXF1aXNpdGVzCgpJbiB0aGlzIGNoYXB0ZXIgd2UnbGwgZm9jdXMgb24gdGlkeXIsIGEgcGFja2FnZSB0aGF0IHByb3ZpZGVzIGEgYnVuY2ggb2YgdG9vbHMgdG8gaGVscCB0aWR5IHVwIHlvdXIgbWVzc3kgZGF0YXNldHMuIHRpZHkgaXMgYSBtZW1iZXIgb2YgdGhlIGNvcmUgdGlkeXZlcnNlLgoKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpgYGAKCiMjIyAxMi4yIFRpZHkgZGF0YQoKVGhlcmUgYXJlIG1hbnkgd2F5cyB0byByZXByZXNlbnQgdGhlIHNhbWUgdW5kZXJseWluZyBkYXRhLCBidXQgc29tZSBkYXRhc2V0cyBhcmUgZWFzaWVyIHRvIHVzZSB0aGFuIG90aGVycy4KClRoZXJlIGFyZSB0aHJlZSBpbnRlcnJlbGF0ZWQgcnVsZXMgd2hpY2ggbWFrZSBhIGRhdGFzZXQgdGlkeToKCjEuIEVhY2ggdmFyaWFibGUgbXVzdCBoYXZlIGl0cyBvd24gY29sdW1uLgoyLiBFYWNoIG9ic2VydmF0aW9uIG11c3QgaGF2ZSBpdHMgb3duIHJvdy4KMy4gRWFjaCB2YWx1ZSBtdXN0IGhhdmUgaXRzIG93biBjZWxsLgoKVGhlc2UgdGhyZWUgcnVsZXMgYXJlIGludGVycmVsYXRlZCBiZWNhdXNlIGl0J3MgaW1wb3NzaWJsZSB0byBvbmx5IHNhdGlzZnkgdHdvIG9mIHRoZSB0aHJlZS4gVGhhdCBpbnRlcnJlbGF0aW9uc2hpcCBsZWFkcyB0byBhbiBldmVuIHNpbXBsZXIgc2V0IG9mIHByYWN0aWNhbCBpbnN0cnVjdGlvbnM6CgoxLiBQdXQgZWFjaCBkYXRhc2V0IGluIGEgdGliYmxlLgoyLiBQdXQgZWFjaCB2YXJpYWJsZSBpbiBhIGNvbHVtbi4KCkluIHRoaXMgZXhhbXBsZSwgb25seSBfX3RhYmxlMV9fIGlzIHRpZHkuIEl0J3MgdGhlIG9ubHkgcmVwcmVzZW50YXRpb24gd2hlcmUgZWFjaCBjb2x1bW4gaXMgYSB2YXJpYWJsZS4KCjIgbWFpbiBhZHZhbnRhZ2VzIHRvICp0aWR5KiBkYXRhLgoKMS5UaGVyZSdzIGEgZ2VuZXJhbCBhZHZhbnRhZ2UgdG8gcGlja2luZyBvbmUgY29uc2lzdGVudCB3YXkgb2Ygc3RvcmluZyBkYXRhLiBJZiB5b3UgaGF2ZSBhIGNvbnNpc3RlbnQgZGF0YSBzdHJ1Y3R1cmUsIGl0J3MgZWFzaWVyIHRvIGxlYXJuIHRoZSB0b29scyB0aGF0IHdvcmsgd2l0aCBpdCBiZWNhdXNlIHRoZXkgaGF2ZSBhIHVuZGVybHlpbmcgdW5pZm9ybWl0eS4KCjIuIFRoZXJlJ3MgYSBzcGVjaWZpYyBhZHZhbnRhZ2UgdG8gcGxhY2luZyB2YXJpYWJsZXMgaW4gY29sdW1ucyBiZWNhdXNlIGl0IGFsbG93cyBSJ3MgdmVjdG9yaXNlZCBuYXR1cmUgdG8gc2hpbmUuIEFzIHlvdSBsZWFybmVkIGluIF9fbXV0YXRlX18gYW5kIF9fc3VtbWFyeSBmdW5jdGlvbnNfXywgbW9zdCBidWlsdC1pbiBSIGZ1bmN0aW9ucyB3b3JrIHdpdGggdmVjdG9ycyBvZiB2YWx1ZXMuIFRoYXQgbWFrZXMgdHJhbnNmb3JtaW5nIHRpZHkgZGF0YSBmZWVsIHBhcnRpY3VsYXJseSBuYXR1cmFsLgoKZHBseXIsIGdncGxvdDIsIGFuZCBhbGwgdGhlIG90aGVyIHBhY2thZ2VzIGluIHRoZSB0aWR5dmVyc2UgYXJlIGRlc2lnbmVkIHRvIHdvcmsgd2l0aCAqdGlkeSogZGF0YS4KCiMjIyAxMi4yLjEgRXhlcmNpc2VzCgoxLiBVc2luZyBwcm9zZSwgZGVzY3JpYmUgaG93IHRoZSB2YXJpYWJsZXMgYW5kIG9ic2VydmF0aW9ucyBhcmUgb3JnYW5pc2VkIGluIGVhY2ggb2YgdGhlIHNhbXBsZSB0YWJsZXMuCgpUYWJsZTEgaXMgb3JnYW5pemVkIHdpdGggZm91ciB2YXJpYWJsZXMgYWNyb3NzIGZvdXIgY29sdW1uczogY291bnRyeSwgeWVhciwgY2FzZXMgYW5kIHBvcHVsYXRpb24uIEl0IGlzIGVhc3kgdG8gaW1hZ2luZSBjcmVhdGluZyBtYW55IGdyYXBoaWNzIHdpdGggdGhpcyBmb3JtYXQgYW5kIGZhY2V0aW5nIGVhc2lseSBieSBjb3VudHJ5IGFuZCB5ZWFyLgoKVGFibGUyIGlzIHNpbWlsYXIgdG8gdGFibGUgb25lIC0gY291bnRyeSBhbmQgeWVhciBhcmUgdGhlIHNhbWUgLSBjYXNlcyBhbmQgcG9wdWxhdGlvbiBoYXZlIGJlZW4gdHVybmVkIGludG8gdmFsdWVzOyBlc3NlbnRpYWxseSBjb21iaW5lZCB0byBjcmVhdGUgYSBuZXcgY29sdW1uICJ0eXBlIi4gQ291bnQgdGhlbiByZXByZXNlbnRzIHJlc3BlY3RpdmUgbnVtYmVycyBvZiBjYXNlcyBhbmQgcG9wdWxhdGlvbi4KClRhYmxlcyAzIGNvbWJpbmVzIHRoZSBjYXNlcyBhbmQgcG9wdWxhdGlvbiBpbnRvIGEgc2luZ2xlIG5ldyBjb2x1bW4gY2FsbGVkICJyYXRlIiAtIGVzc2VudGlhbGx5IGNhc2VzL3BvcHVsYXRpb24uIFdoaWxlIHRoaXMgbmV3IGRhdGEgaGFzIGl0cyBvd24gYWR2YW50YWdlcyBpdCBsaW1pdHMgdGhlIG9wdGlvbnMgYXZhaWxhYmxlIGZvciBhbmFseXNpcy4gSXQgaXMgYmV0dGVyIHRvIGhhdmUgdGhlIHJhdyBkYXRhIGFuZCB0aGVuIGNyZWF0ZSBhIG5ldyAicmF0ZSIgdmFyaWFibGUgZnJvbSB0aGUgdmFyaWFibGVzIGluIGNvbHVtbiAxIHRoYW4gdG8gc3RhcnQgd2l0aCB0aGUgcmF0ZS4KClRhYmxlcyA0IGFuZCA1IGFyZSBzcGxpdCBhY3Jvc3MgdHdvIHRhYmxlcyBhbmQgZGVmaW5lZCBieSB5ZWFyLiBUaGUgZmlyc3QgdGliYmxlIGNvbnRhaW5zIGNhc2VzIGRhdGEgYW5kIHRoZSBzZWNvbmQgY29udGFpbnMgcG9wdWxhdGlvbiBkYXRhIC0gbWFraW5nIGl0IHRodXMgZGlmZmljdWx0IHRvIGNvbXBhcmUgY2FzZSBhbmQgcG91bGF0aW9uIGRhdGEgd2l0aG91dCBwZXJmb3JtaW5nIGEgU1FMIGpvaW4uCgoyLiBDb21wdXRlIHRoZSBfX3JhdGVfXyBmb3IgX190YWJsZTJfXywgYW5kIF9fdGFibGU0YV9fICsgX190YWJsZTRiX18uIFlvdSB3aWxsIG5lZWQgdG8gcGVyZm9ybSBmb3VyIG9wZXJhdGlvbnM6CgoxLiBFeHRyYWN0IHRoZSBudW1iZXIgb2YgVEIgY2FzZXMgcGVyIGNvdW50cnkgcGVyIHllYXIuCjIuIEV4dHJhY3QgdGhlIG1hdGNoaW5nIHBvcHVsYXRpb24gcGVyIGNvdW50cnkgcGVyIHllYXIuCjMuIERpdmlkZSBjYXNlcyBieSBwb3B1bGF0aW9uLCBhbmQgbXVsdGlwbHkgYnkgMTAwMDAuCjQuIFN0b3JlIGJhY2sgaW4gdGhlIGFwcHJvcHJpYXRlIHBsYWNlLgoKV2hpY2ggcmVwcmVzZW50YXRpb24gaXMgZWFzaWVzdCB0byB3b3JrIHdpdGg/IFdoaWNoIGlzIGhhcmRlc3Q/IFdoeT8KCmBgYHtyfQp0YWJsZTEgPC0gdGliYmxlKAogIGNvdW50cnkgPSBjKAogICAgcmVwKCJBZmdoYW5pc3RhbiIsIDIpLAogICAgcmVwKCJCcmF6aWwiLCAyKSwKICAgIHJlcCgiQ2hpbmEiLCAyKQogICksCiAgeWVhciA9IHJlcChjKDE5OTksIDIwMDApLCAzKSwKICBjYXNlcyA9IGMoNzQ1LCAyNjY2LCAzNzczNywgODA0ODgsIDIxMjI1OCwgMjEzNzY2KSwKICBwb3B1bGF0aW9uID0gYygxOTk4NzA3MSwgMjA1OTUzNjAsIDE3MjAwNjM2MiwgMTc0NTA0ODk4LCAxMjcyOTE1MjcyLCAxMjgwNDI4NTgzKQopCgp0YWJsZTIgPC0gdGliYmxlKAogIGNvdW50cnkgPSBjKAogICAgcmVwKCJBZmdoYW5pc3RhbiIsIDQpLAogICAgcmVwKCJCcmF6aWwiLCA0KSwKICAgIHJlcCgiQ2hpbmEiLCA0KQogICksCiAgeWVhciA9IHJlcChjKDE5OTksIDE5OTksIDIwMDAsIDIwMDApLCAzKSwKICB0eXBlID0gcmVwKGMoImNhc2VzIiwgInBvcHVsYXRpb24iLCAiY2FzZXMiLCAicG9wdWxhdGlvbiIpLCAzKSwKICBjb3VudCA9IGMoNzQ1LCAxOTk4NzA3MSwgMjY2NiwgMjA1OTUzNjAsIDM3NzM3LCAxNzIwMDYzNjIsIDgwNDg4LCAxNzQ1MDQ4OTgsIDIxMjI1OCwgMTI3MjkxNTI3MiwgMjEzNzY2LCAxMjgwNDI4NTgzKQopCgp0YWJsZTMgPC0gdGliYmxlKAogIGNvdW50cnkgPSBjKAogICAgcmVwKCJBZmdoYW5pc3RhbiIsIDIpLAogICAgcmVwKCJCcmF6aWwiLCAyKSwKICAgIHJlcCgiQ2hpbmEiLCAyKQogICksCiAgeWVhciA9IHJlcChjKDE5OTksIDIwMDApLCAzKSwKICByYXRlID0gYygiNzQ1LzE5OTg3MDcxIiwgIjI2NjYvMjA1OTUzNjAiLCAiMzc3MzcvMTcyMDA2MzYyIiwgIjgwNDg4LzE3NDUwNDg5OCIsICIyMTIyNTgvMTI3MjkxNTI3MiIsICIyMTM3NjYvMTI4MDQyODU4MyIpCikKCnRhYmxlNGEgPC0gdGliYmxlKAogIGNvdW50cnkgPSBjKCJBZmdoYW5pc3RhbiIsICJCcmF6aWwiLCAiQ2hpbmEiKSwKICAnMTk5OScgPSBjKDc0NSwgMzc3MzcsIDIxMjI1OCksCiAgJzIwMDAnID0gYygyNjY2LCA4MDQ4OCwgMjEzNzY2KQopCgp0YWJsZTRiIDwtIHRyaWJibGUoCn5jb3VudHJ5LCB+YDE5OTlgLCB+YDIwMDBgLAojLS0tLS0tLS0tfC0tLS0tLS0tLS0tfC0tLS0tLS0tLQoiQWZnaGFuaXN0YW4iLCAxOTk4NzA3MSwgMjA1OTUzNjAsCiJCcmF6aWwiLCAxNzIwMDYzNjIsIDE3NDUwNDg5OCwKIkNoaW5hIiwgMTI3MjkxNTI3MiwgMTI4MDQyODU4MwopCmBgYAoKYGBge3J9CnRhYmxlMl9tb2QgPC0gdGliYmxlKAogIGNvdW50cnkgPSB0YWJsZTIkY291bnRyeVt0YWJsZTIkdHlwZSA9PSAiY2FzZXMiXSwKICB5ZWFyID0gdGFibGUyJHllYXJbdGFibGUyJHR5cGUgPT0gImNhc2VzIl0sCiAgY2FzZXMgPSB0YWJsZTIkY291bnRbdGFibGUyJHR5cGUgPT0gImNhc2VzIl0sCiAgcG9wdWxhdGlvbiA9IHRhYmxlMiRjb3VudFt0YWJsZTIkdHlwZSA9PSAicG9wdWxhdGlvbiJdLAogIHJhdGUgPSAoY2FzZXMvcG9wdWxhdGlvbikgKiAxMDAwMAopCgp0YWJsZTJfbW9kCmBgYAoKYGBge3J9CnRhYmxlNGMgPC0KICB0aWJibGUoCiAgICBjb3VudHJ5ID0gdGFibGU0YSRjb3VudHJ5LAogICAgYDE5OTlgID0gKHRhYmxlNGEkYDE5OTlgL3RhYmxlNGIkYDE5OTlgKSAqIDEwMDAwLAogICAgYDIwMDBgID0gKHRhYmxlNGEkYDIwMDBgL3RhYmxlNGIkYDIwMDBgKSAqIDEwMDAwCiAgKQoKdGFibGU0YwpgYGAKCk5laXRoZXIgd2VyZSBwYXJ0aWN1bGFybHkgZWFzeSB0byB3b3JrIHdpdGgsIGJ1dCBpdCB3YXMgbW9yZSBjb25mdXNpbmcgdGhpbmtpbmcgYWJvdXQgY2FzZXMgYW5kIHBvcHVsYXRpb24gaW4gdGVybXMgb2YgeWVhcnMuCgozLiBSZWNyZWF0ZSB0aGUgcGxvdCBzaG93aW5nIGNoYW5nZSBpbiBjYXNlcyBvdmVyIHRpbWUgdXNpbmcgX190YWJsZTJfXyBpbnN0ZWFkIG9mIF9fdGFibGUxX18uIFdoYXQgZG8geW91IG5lZWQgdG8gZG8gZmlyc3Q/CgpgYGB7cn0KIyBFeGFtcGxlCmdncGxvdCh0YWJsZTEsIGFlcyh5ZWFyLCBjYXNlcykpICsKICBnZW9tX2xpbmUoYWVzKGdyb3VwID0gY291bnRyeSksIGNvbG9yID0gImdyZXk1MCIpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IGNvdW50cnkpKQoKIyBBY3R1YWwKdGFibGUyICU+JQogIGZpbHRlcih0eXBlID09ICJjYXNlcyIpICU+JQogIGdncGxvdChhZXMoeWVhciwgY291bnQpKSArCiAgZ2VvbV9saW5lKGFlcyhncm91cCA9IGNvdW50cnkpLCBjb2xvciA9ICJncmV5NTAiKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBjb3VudHJ5KSkKYGBgCgpKdXN0IG5lZWQgdG8gZmlsdGVyIG91dCAicG9wdWxhdGlvbiIgZGF0YSBpbiB0eXBlIGNvbHVtbiBmcm9tIHRhYmxlLgoKIyMgMTIuMyBQaXZvdGluZwoKTW9zdCBkYXRhIHRoYXQgeW91IHdpbGwgZW5jb3VudGVyIHdpbGwgYmUgdW50aWR5LiBUaGVyZSBhcmUgdHdvIG1haW4gcmVhc29uczoKCjEuIE1vc3QgcGVvcGxlIGFyZW4ndCBmYW1pbGlhciB3aXRoIHRoZSBwcmluY2lwbGVzIG9mIHRpZHkgZGF0YSwgYW5kIGl0J3MgaGFyZCB0byBkZXJpdmUgdGhlbSB5b3Vyc2VsZiB1bmxlc3MgeW91IHNwZW5kIGEgKmxvdCogb2YgdGltZSB3b3JraW5nIHdpdGggZGF0YS4KCjIuIERhdGEgaXMgb2Z0ZW4gb3JnYW5pc2VkIHRvIGZhaWxpdGF0ZSBzb21lIHVzZSBvdGhlciB0aGFuIGFuYWx5c2lzLiBGb3IgZXhhbXBsZSwgZGF0YSBpcyBvZnRlbiBvcmdhbmlzZWQgdG8gbWFrZSBlbnRyeSBhcyBlYXN5IGFzIHBvc3NpYmxlLgoKVGhpcyBtZWFucyBmb3IgbW9zdCByZWFsIGFuYWx5c2VzLCB5b3UnbGwgbmVlZCB0byBkbyBzb21lIHRpZHlpbmcuIFRoZSBmaXJzdCBzdGVwIGlzIGFsd2F5cyB0byBmaWd1cmUgb3V0IHdoYXQgdGhlIHZhcmlhYmxlcyBhbmQgb2JzZXJ2YXRpb25zIGFyZS4gU29tZXRpbWVzIHRoaXMgaXMgZWFzeTsgb3RoZXIgdGltZXMgeW91J2xsIG5lZWQgdG8gY29uc3VsdCB3aXRoIHRoZSBwZW9wbGUgd2hvIG9yaWdpbmFsbCBnZW5lcmF0ZWQgdGhlIGRhdGEuIFRoZSBzZWNvbmQgc3RlcCBpcyB0byByZXNvbHZlIG9uZSBvZiB0d28gY29tbW9uIHByb2JsZW1zOgoKMS4gT25lIHZhcmlhYmxlIG1pZ2h0IGJlIHNwcmVhZCBhY3Jvc3MgbXVsdGlwbGUgY29sdW1ucy4KCjIuIE9uZSBvYnNlcnZhdGlvbiBtaWdodCBiZSBzY2F0dGVyZWQgYWNyb3NzIG11bHRpcGxlIHJvd3MuCgpUeXBpY2FsbHkgYSBkYXRhc2V0IHdpbGwgb25seSBzdWZmZXIgZnJvbSBvbmUgb2YgdGhlc2UgcHJvYmxlbXM7IGl0J2xsIG9ubHkgc3VmZmVyIGZyb20gYm90aCBpZiB5b3UncmUgcmVhbGx5IHVubHVja3khIFRvIGZpeCB0aGVzZSBwcm9ibGVtcywgeW91J2xsIG5lZWQgdGhlIHR3byBtb3N0IGltcG9ydGFudCBmdW5jdGlvbnMgaW4gdGlkeXI6IF9fcGl2b3RfbG9uZ2VyKClfXyBhbmQgX19waXZvdF93aWRlcigpX18uCgojIyMgMTIuMy4xIExvbmdlcgoKQSBjb21tb24gcHJvYmxlbSBpcyBhIGRhdHNldCB3aGVyZSBzb21lIG9mIHRoZSBjb2x1bW4gbmFtZXMgYXJlIG5vdCBuYW1lcyBvZiB2YXJpYWJsZXMsIGJ1dCAqdmFsdWVzKiBvZiBhIHZhcmlhYmxlLiBUYWtlIF9fdGFibGU0YV9fOiB0aGUgY29sdW1uIG5hbWVzIF9fMTk5OV9fIGFuZCBfXzIwMDBfXyByZXByZXNlbnQgdmFsdWVzIG9mIHRoZSBfX3llYXJfXyB2YXJpYWJsZSwgdGhlIHZhbHVlcyBpbiB0aGUgX18xOTk5X18gYW5kIF9fMjAwMF9fIGNvbHVtbnMgcmVwcmVzZW50IHZhbHVlcyBvZiB0aGUgX19jYXNlc19fIHZhcmlhYmxlLCBhbmQgZWFjaCByb3cgcmVwcmVzZW50cyB0d28gb2JzZXJ2YXRpb25zLCBub3Qgb25lLgoKYGBge3J9CnRhYmxlNGEKYGBgCgpUbyB0aWR5IGEgZGF0YXNldCBsaWtlIHRoaXMsIHdlIG5lZWQgdG8gX19waXZvdF9fIHRoZSBvZmZlbmRpbmcgY29sdW1ucyBpbnRvIGEgbmV3IHBhaXIgb2YgdmFyaWFibGVzLiBUbyBkZXNjcmliZSB0aGF0IG9wZXJhdGlvbiB3ZSBuZWVkIHRocmVlIHBhcmFtYXRlcnM6CgoqIFRoZSBzZXQgb2YgY29sdW1ucyB3aG9zZSBuYW1lcyBhcmUgdmFsdWVzLCBub3QgdmFyaWFibGVzLiBJbiB0aGlzIGV4YW1wbGUsIHRob3NlIGFyZSB0aGUgY29sdW1ucyBfXzE5OTlfXyBhbmQgX18yMDAwX19fLgoqIFRoZSBuYW1lIG9mIHRoZSB2YXJpYWJsZSB0byBtb3ZlIHRoZSBjb2x1bW4gbmFtZXMgdG8uIEhlcmUgaXQgaXMgX195ZWFyX18uCiogVGhlIG5hbWUgb2YgdGhlIHZhcmlhYmxlIHRvIG1vdmUgdGhlIGNvbHVtbiB2YWx1ZXMgdG8uIEhlcmUgaXQncyBfX2Nhc2VzX18uCgpUb2dldGhlciB0aG9zZSBwYXJhbWF0ZXJzIGdlbmVyYXRlIHRoZSBjYWxsIHRvIF9fcGl2b3RfbG9uZ2VyKClfXzoKCmBgYHtyfQp0YWJsZTRhCgp0YWJsZTRhICU+JQogIHBpdm90X2xvbmdlcihjb2xzID0gYyhgMTk5OWAsIGAyMDAwYCksIG5hbWVzX3RvID0gInllYXIiLCB2YWx1ZXNfdG8gPSAiY2FzZXMiKQpgYGAKClRoZSBjb2x1bW5zIHRvIHBpdm90IGFyZSBzcGVjaWZpZWQgd2l0aCBfX2RwbHlyOjpzZWxlY3QoKV9fIHN0eWxlIG5vdGF0aW9uLiBIZXJlIHRoZXJlIGFyZSBvbmx5IHR3byBjb2x1bW5zLCBzbyB3ZSBsaXN0IHRoZW0gaW5kaXZpZHVhbGx5LiBOb3RlIHRoYXQgIjE5OTkiIGFuZCAiMjAwMCIgYXJlIG5vbi1zeW50YWN0aWMgbmFtZXMgKGJlY2F1c2UgdGhleSBkb24ndCBzdGFydCB3aXRoIGEgbGV0dGVyKSBzbyB3ZSBoYXZlIHRvIHN1cnJvdW5kIHRoZW0gaW4gYmFja3RpY2tzLiBUbyByZWZyZXNoIHlvdXIgbWVtb3J5IG9mIHRoZSBvdGhlciB3YXlzIHRvIHNlbGVjdCBjb2x1bW5zIHNlZSwgX19zZWxlY3RfXy4KCl9feWVhcl9fIGFuZCBfX2Nhc2VzX18gZG8gbm90IGV4aXN0IGluIF9fdGFibGU0MV9fIHNvIHdlIHB1dCB0aGVpciBuYW1lcyBpbiBxdW90ZXMuCgpJbiB0aGUgZmluYWwgcmVzdWx0LCB0aGUgcGl2b3RlZCBjb2x1bW5zIGFyZSBkcm9wcGVkLCBhbmQgd2UgZ2V0IG5ldyBfX3llYXJfXyBhbmQgX19jYXNlc19fIGNvbHVtbnMuIE90aGVyd2lzZSwgdGhlIHJlbGF0aW9uc2hpcHMgYmV0d2VlbiB0aGUgb3JpZ2luYWwgdmFyaWFibGVzIGFyZSBwcmVzZXJ2ZWQuIFZpc3VhbGx5LCB0aGlzIGlzIHNob3duIGluIF9fRmlndXJlIDEyLjJfXy4KCl9fcGl2b3RfbG9uZ2VyKClfXyBtYWtlcyBkYXRhc2V0cyBsb25nZXIgYnkgaW5jcmVhc2luZyB0aGUgbnVtYmVyIG9mIHJvd3MgYW5kIGRlY3JlYXNpbmcgdGhlIG51bWJlciBvZiBjb2x1bW5zLiBJIGRvbid0IGJlbGlldmUgaXQgbWFrZXMgc2Vuc2UgdG8gZGVzY3JpYmUgYSBkYXRzZXQgYXMgYmVpbmcgaW4gImxvbmcgZm9ybSIuIExlbmd0aCBpcyBhIHJlbGF0aXZlIHRlcm0sIGFuZCB5b3UgY2FuIG9ubHkgc2F5IChlLmcuKSB0aGF0IGRhdHNldCBBIGlzIGxvbmdlciB0aGFuIGRhdGFzZXQgQi4KCldlIGNhbiB1c2UgX19waXZvdF9sb25nZXIoKV9fIHRvIHRpZHkgX190YWJsZTRiX18gaW4gYSBzaW1pbGFyIGZhc2hpb24uIFRoZSBvbmx5IGRpZmZlcmVuY2UgaXMgdGhlIHZhcmlhYmxlIHN0b3JlZCBpbiB0aGUgY2VsbCB2YWx1ZXM6CgpgYGB7cn0KdGFibGU0YiAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IGMoYDE5OTlgLCBgMjAwMGApLCBuYW1lc190byA9ICJ5ZWFyIiwgdmFsdWVzX3RvID0gInBvcHVsYXRpb24iKQpgYGAKClRvIGNvbWJpbmUgdGhlIHRpZGllZCB2ZXJzaW9ucyBvZiBfX3RhYmxlNGFfXyBhbmQgX190YWJsZTRiX18gaW50byBhIHNpbmdsZSB0aWJibGUsIHdlIG5lZWQgdG8gdXNlIF9fZHBseXI6OmxlZnRfam9pbigpX18sIHdoaWNoIHlvdSdsbCBsZWFybiBhYm91dCBpbiByZWxhdGlvbmFsIGRhdGEuCgpgYGB7cn0KdGlkeTRhIDwtIHRhYmxlNGEgJT4lCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBjKGAxOTk5YCwgYDIwMDBgKSwgbmFtZXNfdG8gPSAieWVhciIsIHZhbHVlc190byA9ICJjYXNlcyIpCgp0aWR5NGIgPC0gdGFibGU0YiAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IGMoYDE5OTlgLCBgMjAwMGApLCBuYW1lc190byA9ICJ5ZWFyIiwgdmFsdWVzX3RvID0gInBvcHVsYXRpb24iKQpsZWZ0X2pvaW4odGlkeTRhLCB0aWR5NGIsIGJ5ID0gYygiY291bnRyeSIsICJ5ZWFyIikpCmBgYAoKIyMgMTIuMy4yIFdpZGVyCgpfX3Bpdm90X3dpZGVyKClfXyBpcyB0aGUgb3Bwb3NpdGUgb2YgX19waXZvdF9sb25nZXIoKV9fLiBZb3UgdXNlIGl0IHdoZW4gYW4gb2JzZXJ2YXRpb24gaXMgc2NhdHRlcmVkIGFjcm9zcyBtdWx0aXBsZSByb3dzLiBGb3IgZXhhbXBsZSwgdGFrZSBfX3RhYmxlMl9fOiBhbiBvYnNlcnZhdGlvbiBpcyBhIGNvdW50cnkgaW4gYSB5ZWFyLCBidXQgZWFjaCBvYnNlcnZhdGlvbiBpcyBzcHJlYWQgYWNyb3NzIHR3byByb3dzLgoKYGBge3J9CnRhYmxlMiAlPiUKICBwaXZvdF93aWRlcihpZF9jb2xzID0gYyhjb3VudHJ5LCB5ZWFyKSwgbmFtZXNfZnJvbSA9IHR5cGUsIHZhbHVlc19mcm9tID0gY291bnQpCmBgYAoKVG8gdGlkeSB0aGlzIHVwLCB3ZSBmaXJzdCBhbmFseXNlIHRoZSByZXByZXNlbnRhdGlvbiBpbiBzaW1pbGFyIHdheSB0byBfX3Bpdm90X2xvbmdlcigpX18uIFRoaXMgdGltZSwgaG93ZXZlciwgd2Ugb25seSBuZWVkIHR3byBwYXJhbWF0ZXJzOgoKKiBUaGUgY29sdW1uIHRvIHRha2UgdmFyaWFibGUgbmFtZXMgZnJvbS4gSGVyZSwgaXQncyBfX3R5cGVfXy4KKiBUaGUgY29sdW1uIHRvIHRha2UgdmFsdWVzIGZyb20uIEhlcmUgaXQncyBfX2NvdW50X18uCgpPbmNlIHdlJ3ZlIGZpZ3VyZWQgdGhhdCBvdXQsIHdlIGNhbiB1c2UgX19waXZvdF93aWRlcigpX18sIGFzIHNob3duIHByb2dyYW1tYXRpY2FsbHkgYmVsb3csIGFuZCB2aXN1YWxseSBpbiBfX0ZpZ3VyZSAxMi4zX18uCgpgYGB7cn0KIyBBYm92ZSB3ZSBwcm92aWRlZCBfX2lkX2NvbHNfXywgYnV0IHRoZXkgZG9uJ3QgYXBwZWFyIG5lY2Vzc2FyeSBpbiB0aGlzIGV4YW1wbGUuCnRhYmxlMiAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gdHlwZSwgdmFsdWVzX2Zyb20gPSBjb3VudCkKYGBgCgpBcyB5b3UgbWlnaHQgaGF2ZSBndWVzc2VkIGZyb20gdGhlaXIgbmFtZXMsIF9fcGl2b3Rfd2lkZXIoKV9fIGFuZCBfX3Bpdm90X2xvbmdlcigpX18gYXJlIGNvbXBsZW1lbnRzLiBfX3Bpdm90X2xvbmdlcigpX18gbWFrZXMgd2lkZSB0YWJsZXMgbmFycm93ZXIgYW5kIGxvbmdlcjsgX19waXZvdF93aWRlcigpX18gbWFrZXMgbG9uZyB0YWJsZXMgc2hvcnRlciBhbmQgd2lkZXIuCgojIyMgMTIuMy4zIEV4ZXJjaXNlcwoKMS4gV2h5IGFyZSBfX3Bpdm90X2xvbmdlcigpX18gYW5kIF9fcGl2b3Rfd2lkZXIoKV9fIG5vdCBwZXJmZWN0bHkgc3ltbWV0cmljYWw/IENhcmVmdWxseSBjb25zaWRlciB0aGUgZm9sbG93aW5nIGV4YW1wbGU6CgpgYGB7cn0Kc3RvY2tzIDwtIHRpYmJsZSgKICB5ZWFyID0gYygyMDE1LCAyMDE1LCAyMDE2LCAyMDE2KSwKICBoYWxmID0gYyggMSwgMiwgMSwgMiksCiAgcmV0dXJuID0gYygxLjg4LCAwLjU5LCAwLjkyLCAwLjE3KQopCnN0b2NrcwoKc3RvY2tzICU+JQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSB5ZWFyLCB2YWx1ZXNfZnJvbSA9IHJldHVybikKCnN0b2NrcyAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0geWVhciwgdmFsdWVzX2Zyb20gPSByZXR1cm4pICU+JQogIHBpdm90X2xvbmdlcihgMjAxNWA6YDIwMTZgLCBuYW1lc190byA9ICJ5ZWFyIiwgdmFsdWVzX3RvID0gInJldHVybiIpCmBgYAoKVGhleSBhcmUgbm90IHBlcmZlY3RseSBzeW1tZXRyaWNhbCBiZWNhdXNlIHdoZW4geW91IHBpdm90IHlvdSBjaGFuZ2UgdGhlIG5hdHVyZSBvZiB0aGUgZGF0YSAoY29sdW1ucywgdmFsdWVzIGFuZCBvYnNlcnZhdGlvbnMpLiBGb3IgZXhhbXBsZSwKd2hlbiB3ZSBwaXZvdF93aWRlciBmcm9tIG91ciBvcmlnaW5hbCBkYXRhc2V0LCBlYWNoIG9ic2VydmF0aW9uIGNvbnRhaW5zIHRoZSBoYWxmIGFuZCByZXR1cm4gYnkgcmVzcGVjdGl2ZSB5ZWFyLCBidXQgdGhlIHllYXIgaXMgcHJvdmlkZWQgYnkgdGhlIGNvbHVtbiAodGhlIHZhcmlhYmxlKS4gSXQgaXMgYSByZWxhdGl2ZWx5ICJzbWFsbGVyIiBkYXRhc2V0LCBidXQgaXQgaXMgY29uZnVzaW5nIHRvIHRoaW5rIG9mIHRoZSB5ZWFybHkgcmV0dXJucyBpbiB0ZXJtcyBvZiB2YXJpYWJsZXMuIFdlcmUgdGhlcmUgbm8gZGVzY3JpcHRpb24sIHRoaXMgZGF0YSB3b3VsZCBiZSBzb21ld2hhdCBkaWZmaWN1bHQgdG8gdW5kZXJzdGFuZC4KCl9fcGl2b3RfbG9uZ2VyKClfXyBoYXMgYSBfX25hbWVzX3B0eXBlc19fIGFyZ3VtZW50LCBlLmcuIF9fbmFtZXNfcHR5cGVzID0gbGlzdCh5ZWFyID0gZG91YmxlKCkpX18uIFdoYXQgZG9lcyBpdCBkbz8KCmBgYHtyfQpzdG9ja3MgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IHllYXIsIHZhbHVlc19mcm9tID0gcmV0dXJuKSAlPiUKICBwaXZvdF9sb25nZXIoYDIwMTVgOmAyMDE2YCwgbmFtZXNfdG8gPSAieWVhciIsIHZhbHVlc190byA9ICJyZXR1cm4iLCBuYW1lc19wdHlwZXMgPSBsaXN0KHllYXIgPSBkb3VibGUoKSkpCmBgYAoKSXQgZGVmaW5lcyB0aGUgdHlwZSwgY2xhc3MsIGFuZCBhdHRyaWJ1dGVzIG9mIGEgdmVjdG9yLiBJdCBzaG91bGQgYmUgdXNlZCB0byBjb25maXJtIHRoYXQgdGhlIGNyZWF0ZWQgY29sdW1ucyBhcmUgdGhlIHR5cGVzIHRoYXQgeW91IGV4cGVjdC4gSXQgaXMgbm90IHRvIGJlIHVzZWQgdG8gY2hhbmdlIHRoZSBjb2x1bW4gdHlwZSAoaGVuY2UsIHRoZSBhYm92ZSBlcnJvciBtZXNzYWdlKS4gSW5zdGVhZCB1c2UgX19uYW1lc190cmFuc2Zvcm1fXyBvciBfX3ZhbHVlc190cmFuc2Zvcm1fXy4KCmBgYHtyfQpzdG9ja3MgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IHllYXIsIHZhbHVlc19mcm9tID0gcmV0dXJuKSAlPiUKICBwaXZvdF9sb25nZXIoYDIwMTVgOmAyMDE2YCwgbmFtZXNfdG8gPSAieWVhciIsIHZhbHVlc190byA9ICJyZXR1cm4iLCBuYW1lc190cmFuc2Zvcm0gPSBsaXN0KHllYXIgPSBhcy5kb3VibGUpCiAgICAgICAgICAgICAgICkKYGBgCgoyLiBXaHkgZG9lcyB0aGlzIGNvZGUgZmFpbD8KCmBgYHtyfQp0YWJsZTRhICU+JQogIHBpdm90X2xvbmdlcihjKDE5OTksIDIwMDApLCBuYW1lc190byA9ICJ5ZWFyIiwgdmFsdWVzX3RvID0gImNhc2VzIikKYGBgCgpUaGUgY29kZSBmYWlscyBiZWNhdXNlIHdlIG5lZWQgdG8gd3JhcCBvdXIgY29sdW1uIHZhcmlhYmxlcyBpbiBiYWNrdGlja3MgLT4gYyhgMTk5OWAsIGAyMDAwYCkuIFRoZXNlIG5hbWVzIGRvIG5vdCBmb2xsb3cgcHJvcGVyIFIgbmFtaW5nIGNvbnZlbnRpb25zICh0aGV5IGRvIG5vdCBiZWdpbiB3aXRoIGEgbGV0dGVyKSBzbyB3ZSBuZWVkIHRvIHNwZWNpZnkgd2hhdCB0aGV5IGFyZSAtIGluIHRoaXMgY2FzZSBjb2x1bW4gbmFtZXMuCgpgYGB7cn0KdGFibGU0YSAlPiUKICBwaXZvdF9sb25nZXIoYyhgMTk5OWAsIGAyMDAwYCksIG5hbWVzX3RvID0gInllYXIiLCB2YWx1ZXNfdG8gPSAiY2FzZXMiKQpgYGAKCjMuIFdoYXQgd291bGQgaGFwcGVuIGlmIHlvdSB3aWRlbiB0aGlzIHRhYmxlPyBXaHk/IEhvdyBjb3VsZCB5b3UgYWRkIGEgbmV3IGNvbHVtbiB0byB1bmlxdWVseSBpZGVudGlmeSBlYWNoIHZhbHVlPwoKYGBge3J9CnBlb3BsZSA8LSB0cmliYmxlKAogIH5uYW1lLCAgICAgICAgICAgICB+bmFtZXMsICAgIH52YWx1ZXMsCiAgIy0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS18LS0tLS0tLS0KICAiUGhpbGxpcCBXb29kcyIsICAgImFnZSIsICAgICA0NSwKICAiUGhpbGxpcCBXb29kcyIsICAgImhlaWdodCIsICAxODYsCiAgIlBoaWxsaXAgV29vZHMiLCAgICJhZ2UiLCAgICAgNTAsCiAgIkplc3NpY2EgQ29yZGVybyIsICJhZ2UiLCAgICAgMzcsCiAgIkplc3NpY2EgQ29yZGVybyIsICJoZWlnaHQiLCAgIDE1NgopCgpwZW9wbGUKYGBgCgpCZWZvcmUgcnVubmluZyBhIHNjcmlwdCB0byB3aWRlbiB0aGUgb25seSBpc3N1ZSB3ZSBtaWdodCBoYXZlIGlzIHRoYXQgd2UgaGF2ZSB0d28gYWdlcyBvYnNlcnZhdGlvbnMgZm9yIFBoaWxsaXAgV29vZHMsIGJ1dCBvbmx5IG9uZSBoZWlnaHQgb2JzZXJ2YXRpb24gLSBvdXIgbmV3IGRhdGFzZXQgd29uJ3QgYmUgYmFsYW5jZWQuIFdlIG1heSBiZSBhYmxlIHRvIGFjY29tcGxpc2ggdGhpcyBhZGRpbmcgYSBuZXcgY29sdW1uIGRlbm90aW5nIHRoZSBvYnNlcnZhdGlvbiBudW1iZXIuCgpgYGB7cn0KcGVvcGxlICU+JQogIGdyb3VwX2J5KG5hbWUsIG5hbWVzKSAlPiUKICBtdXRhdGUob2JzID0gcm93X251bWJlcigpKSAlPiUKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gbmFtZSwgdmFsdWVzX2Zyb20gPSB2YWx1ZXMpCmBgYAoKV2l0aCB0aGlzIHBhcnRpY3VsYXIgdHlwZSBvZiBkYXRhIGhvd2V2ZXIgaXQgd291bGQgYmUgYmV0dGVyIGlmIGFnZSBhbmQgaGVpZ2h0IHdlcmUgdGhlIGNvbHVtbnMgYW5kIFBoaWxpcCBXb29kcyBhbmQgSmVzc2ljYSBDb3JkZXJvIHJlbWFpbmVkIGluIHRoZSBuYW1lIGNvbHVtbi4gSWRlYWxseSwgd2Ugd291bGQganVzdCByZXBsaWNhdGUgdGhlIHZhbHVlIG9mIGhlaWdodCBmb3IgUGhpbGlwIFdvb2RzIGJlY2F1c2UgaXQgaXMgdW5saWtlbHkgdGhhdCBpdCBpcyBhbnkgZGlmZmVyZW50IGZvciBhZ2VzIDQ1IGFuZCA1MC4KCjQuIFRpZHkgdGhlIHNpbXBsZSB0aWJibGUgYmVsb3cuIERvIHlvdSBuZWVkIHRvIG1ha2UgaXQgd2lkZXIgb3IgbG9uZ2VyPyBXaGF0IGFyZSB0aGUgdmFyaWFibGVzPwoKYGBge3J9CnByZWcgPC0gdHJpYmJsZSgKICB+cHJlZ25hbnQsIH5tYWxlLCB+ZmVtYWxlLAogICJ5ZXMiLCAgICAgTkEsICAgIDEwLAogICJubyIsICAgICAgMjAsICAgIDEyCikKcHJlZwoKcHJlZyAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IGMobWFsZSwgZmVtYWxlKSwgbmFtZXNfdG8gPSAiZ2VuZGVyIiwgdmFsdWVzX3RvID0gImNvdW50IikKCiMgQ2FuIHJlbW92ZSBOQSB2YWx1ZSBmb3IgInByZWduYW50IG1hbGVzIiB1c2luZyB2YWx1ZXNfZHJvcF9uYQpwcmVnICU+JQogIHBpdm90X2xvbmdlcihjb2xzID0gYyhtYWxlLCBmZW1hbGUpLCBuYW1lc190byA9ICJnZW5kZXIiLCB2YWx1ZXNfdG8gPSAiY291bnQiLCB2YWx1ZXNfZHJvcF9uYSA9IFRSVUUpCmBgYAoKVGhlIGRhdGEgc2VlbXMgdG8gbWFrZSB0aGUgbW9zdCBzZW5zZSBpZiB3ZSBfX3Bpdm90X2xvbmdlcl9fLiBJbiB0aGlzIGV4YW1wbGUgdGhlIGRhdGFzZXQgYXBwZWFycyB0byByZXNlbWJsZSBjb3VudHMgb2YgcHJlZ25hbnQgbWFsZXMgYW5kIGZlbWFsZXMgKG9idmlvdXNseSB0aGVyZSBhcmUgbm8gcHJlZ25hbnQgbWFsZXMpLCBidXQgdGhlIGRhdGEgaXMgcmVwcmVzZW50ZWQgYnkgTkEuCgojIyAxMi40IFNlcGFyYXRpbmcgYW5kIHVuaXRpbmcKClNvIGZhciB5b3UndmUgbGVhcm5lZCBob3cgdG8gdGlkeSBfX3RhYmxlMl9fIGFuZCBfX3RhYmxlNF9fLCBidXQgbm90IF9fdGFibGUzX18uIF9fdGFibGUzX18gaGFzIGEgZGlmZmVyZW50IHByb2JsZW06IHdlIGhhdmUgb25lIGNvbHVtbiAoX19yYXRlX18pIHRoYXQgY29udGFpbnMgdHdvIHZhcmlhYmxlcyAoX19jYXNlc19fIGFuZCBfX3BvcHVsYXRpb25fXykuIFRvIGZpeCB0aGlzIHByb2JsZW0sIHdlJ2xsIG5lZWQgdGhlIF9fc2VwYXJhdGUoKV9fIGZ1bmN0aW9uLiBZb3UnbGwgYWxzbyBsZWFybiBhYm91dCB0aGUgY29tcGxlbWVudCBvZiBfX3NlcGFyYXRlKClfXzogX191bml0ZSgpX18sIHdoaWNoIHlvdSB1c2UgaWYgYSBzaW5nbGUgdmFyaWFibGUgaXMgc3ByZWFkIGFjcm9zcyBtdWx0aXBsZSBjb2x1bW5zLgoKIyMjIDEyLjQuMSBTZXBhcmF0ZQoKX19zZXBhcmF0ZSgpX18gcHVsbHMgYXBhcnQgb25lIGNvbHVtbiBpbnRvIG11bHRpcGxlIGNvbHVtbnMsIGJ5IHNwbGl0dGluZyB3aGVyZXZlciBhIHNlcGFyYXRvciBjaGFyYWN0ZXIgYXBwZWFycy4gVGFrZSBfX3RhYmxlM19fOgoKYGBge3J9CnRhYmxlMyAlPiUKICBzZXBhcmF0ZShjb2wgPSByYXRlLCBpbnRvID0gYygiY2FzZXMiLCAicG9wdWxhdGlvbiIpLCBzZXAgPSAiLyIpCmBgYAoKVGhlIF9fcmF0ZV9fIGNvbHVtbiBjb250YWlucyBib3RoIF9fY2FzZXNfXyBhbmQgX19wb3B1bGF0aW9uX18gdmFyaWFibGVzLCBhbmQgd2UgbmVlZCB0byBzcGxpdCBpdCBpbnRvIHR3byB2YXJpYWJsZXMuIF9fc2VwYXJhdGUoKV9fIHRha2VzIHRoZSBuYW1lIG9mIHRoZSBjb2x1bW4gdG8gc2VwYXJhdGUsIGFuZCB0aGUgbmFtZXMgb2YgdGhlIGNvbHVtbnMgdG8gc2VwYXJhdGUgaW50bywgYXMgc2hvd24gaW4gX19GaWd1cmUgMTIuNF9fIGFuZCB0aGUgY29kZSBhYm92ZS4KCkFib3ZlIHdlIHNwZWNpZmllZCB3aGF0IHRoZSBzZXBhcmF0b3Igc2hvdWxkIGJlLiBIb3dldmVyLCBieSBkZWZhdWx0LCBfX3NlcGFyYXRlKClfXyB3aWxsIHNwbGl0IHZhbHVlcyB3aGVyZXZlciBpdCBzZWVzIGEgbm9uLWFscGhhbnVtZXJpYyBjaGFyYWN0ZXIgKGkuZS4gYSBjaGFyYWN0ZXIgdGhhdCBpc24ndCBhIG51bWJlciBvciBsZXR0ZXIpLiBJbiB0aGlzIGNhc2UsIHdlIGRpZG4ndCBuZWVkIHRvIHNwZWNpZnkgIi8iIGFzIHRoZSBzZXBhcmF0b3IsIGJ1dCBpbiBtb3JlIGNvbXBsaWNhdGVkIGNhc2VzIGl0IHdpbGwgbGlrZWx5IGJlIG5lY2Vzc2FyeS4KCihGb3JtYWxseSwgX19zZXBfXyBpcyBhIHJlZ3VsYXIgZXhwcmVzc2lvbiwgd2hpY2ggeW91J2xsIGxlYXJuIG1vcmUgYWJvdXQgaW4gX19zdHJpbmdzX18pLgoKTG9vayBjYXJlZnVsbHkgYXQgdGhlIGNvbHVtbiB0eXBlczogeW91J2xsIG5vdGljZSB0aGF0IF9fY2FzZXNfXyBhbmQgX19wb3B1bGF0aW9uX18gYXJlIGNoYXJhY3RlciBjb2x1bW5zLiBUaGlzIGlzIHRoZSBkZWZhdWx0IGJlaGF2aW9yIGluIF9fc2VwYXJhdGUoKV9fOiBpdCBsZWF2ZXMgdGhlIHR5cGUgb2YgdGhlIGNvbHVtbiBhcyBpcy4gSGVyZSwgaG93ZXZlciwgaXQncyBub3QgdmVyeSB1c2VmdWwgYXMgdGhvc2UgcmVhbGx5IGFyZSBudW1iZXJzLiBXZSBjYW4gYXNrIF9fc2VwYXJhdGUoKV9fIHRvIHRyeSBhbmQgY29udmVydCB0byBiZXR0ZXIgdHlwZXMgdXNpbmcgX19jb252ZXJ0ID0gVFJVRV9fOgoKYGBge3J9CnRhYmxlMyAlPiUKICBzZXBhcmF0ZShjb2wgPSByYXRlLCBpbnRvID0gYygiY2FzZXMiLCAicG9wdWxhdGlvbiIpLCBzZXAgPSAiLyIsIGNvbnZlcnQgPSBUUlVFKQpgYGAKCllvdSBjYW4gYWxzbyBwYXNzIGEgdmVjdG9yIG9mIGludGVnZXJzIHRvIF9fc2VwX18uIF9fc2VwYXJhdGUoKV9fIHdpbGwgaW50ZXJwcmV0IHRoZSBpbnRlZ2VycyBhcyBwb3NpdGlvbnMgdG8gc3BsaXQgYXQuIFBvc2l0aXZlIHZhbHVlcyBzdGFydCBhdCAxIG9uIHRoZSBmYXItbGVmdCBvZiB0aGUgc3RyaW5nczsgbmVnYXRpdmUgdmFsdWVzIHN0YXJ0IGF0IC0xIG9uIHRoZSBmYXItcmlnaHQgb2YgdGhlIHN0cmluZ3MuIFdoZW4gdXNpbmcgaW50ZWdlcnMgdG8gc2VwYXJhdGUgc3RyaW5ncywgdGhlIGxlbmd0aCBvZiBfX3NlcF9fIHNob3VsZCBiZSBvbmUgbGVzcyB0aGFuIHRoZSBudW1iZXIgb2YgbmFtZXMgaW4gX19pbnRvX18uIAoKWW91IGNhbiB1c2UgdGhpcyBhcnJhbmdlbWVudCB0byBzZXBhcmF0ZSB0aGUgbGFzdCB0d28gZGlnaXRzIG9mIGVhY2ggeWVhci4gVGhpcyBtYWtlIHRoaXMgZGF0YSBsZXNzIHRpZHksIGJ1dCBpcyB1c2VmdWwgaW4gb3RoZXIgY2FzZXMsIGFzIHlvdSdsbCBzZWUgaW4gYSBsaXR0bGUgYml0LgoKYGBge3J9CnRhYmxlMyAlPiUKICBzZXBhcmF0ZShjb2wgPSB5ZWFyLCBpbnRvID0gYygiY2VudHVyeSIsICJ5ZWFyIiksIHNlcCA9IDIpCmBgYAoKIyMjIDEyLjQuMiBVbml0ZQoKX191bml0ZSgpX18gaXMgdGhlIGludmVyc2Ugb2YgX19zZXBhcmF0ZSgpX186IGl0IGNvbWJpbmVzIG11bHRpcGxlIGNvbHVtbnMgaW50byBhIHNpbmdsZSBjb2x1bW4uIFlvdSdsbCBuZWVkIGl0IG11Y2ggbGVzcyBmcmVxdXJlbnRseSB0aGFuIF9fc2VwYXJhdGUoKV9fLCBidXQgaXQncyBzdGlsbCBhIHVzZWZ1bCB0b29sIHRvIGhhdmUgaW4geW91ciBiYWNrIHBvY2tldC4KCgpXZSBjYW4gdXNlIF9fdW5pdGUoKV9fIHRvIHJlam9pbiB0aGUgKmNlbnR1cnkqIGFuZCAqeWVhciogY29sdW1ucyB0aGF0IHdlIGNyZWF0ZWQgaW4gdGhlIGxhc3QgZXhhbXBsZS4gVGhhdCBkYXRhIGlzIHNhdmVkIGFzIF9fdGlkeXI6OnRhYmxlNV9fLiBfX3VuaXRlX18gdGFrZXMgYSBkYXRhIGZyYW1lLCB0aGUgbmFtZSBvZiB0aGUgbmV3IHZhcmlhYmxlIHRvIGNyZWF0ZSwgYW5kIGEgc2V0IG9mIGNvbHVtbnMgdG8gY29tYmluZSwgYWdhaW4gc3BlY2lmaWVkIGluIF9fZHBseXI6OnNlbGVjdCgpX18gc3R5bGU6CgpgYGB7cn0KdGFibGU1ICU+JQogIHVuaXRlKGNvbCA9IHllYXIsIGMoY2VudHVyeSwgeWVhciksIHNlcCA9ICIiKQpgYGAKCiMjIyAxMi40LjMgRXhlcmNpc2VzCgoxLiBXaGF0IGRvIHRoZSBfX2V4dHJhX18gYW5kIF9fZmlsbF9fIGFyZ3VtZW50cyBkbyBpbiBfX3NlcGFyYXRlKClfXz8gRXhwZXJpbWVudCB3aXRoIHRoZSB2YXJpb3VzIG9wdGlvbnMgZm9yIHRoZSBmb2xsb3dpbmcgdHdvIG95IGRhdGFzZXRzLgoKKmV4dHJhKiBjb250cm9scyB3aGF0IGhhcHBlbnMgd2hlbiB0aGVyZSBhcmUgdG9vIG1hbnkgcGllY2VzIHdoZW4gX19zZXBfXyBpcyBhIGNoYXJhY3RlciB2ZWN0b3IuIFRoZXJlIGFyZSB0aHJlZSB2YWxpZCBvcHRpb25zOgoKKiAid2FybiIgKHRoZSBkZWZhdWx0KTogZW1pdCBhIHdhcm5pbmcgYW5kIGRyb3AgZXh0cmEgdmFsdWVzLgoqICJkcm9wIjogZHJvcCBhbnkgZXh0cmEgdmFsdWVzIHdpdGhvdXQgYSB3YXJuaW5nLgoqICJtZXJnZSI6IG9ubHkgc3BsaXRzIGF0IG1vc3QgbGVuZ3RoKGludG8pIHRpbWVzCgoqZmlsbCogSWYgX19zZXBfXyBpcyBhIGNoYXJhY3RlciB2ZWN0b3IsIHRoaXMgY29udHJvbHMgd2hhdCBoYXBwZW5zIHdoZW4gdGhlcmUgYXJlIG5vdCBlbm91Z2ggcGllY2VzLiBUaGVyZSBhcmUgdGhyZWUgdmFsaWQgb3B0aW9uczoKCiogIndhcm4iICh0aGUgZGVmYXVsdCk6IGVtaXQgYSB3YXJuaW5nIGFuZCBmaWxsIGZyb20gdGhlIHJpZ2h0CiogInJpZ2h0IjogZmlsbCB3aXRoIG1pc3NpbmcgdmFsdWVzIG9uIHRoZSByaWdodAoqICJsZWZ0IjogZmlsbCB3aXRoIG1pc3NpbmcgdmFsdWVzIG9uIHRoZSBsZWZ0CgpgYGB7cn0KIyBJbiB0aGVzZSBleGFtcGxlcyB3ZSBoYXZlICJ0b28gbXVjaCBkYXRhIi4KCiMgRW1pdCBhIHdhcm5pbmcgYW5kIGRyb3AgZXh0cmEgdmFsdWVzLgp0aWJibGUoeCA9IGMoImEsYixjIiwgImQsZSxmLGciLCAiaCxpLGoiKSkgJT4lCiAgc2VwYXJhdGUoeCwgYygib25lIiwgInR3byIsICJ0aHJlZSIpLCBleHRyYSA9ICJ3YXJuIikKCiMgRHJvcCBhbnkgZXh0cmEgdmFsdWVzIHdpdGhvdXQgYSB3YXJuaW5nCnRpYmJsZSh4ID0gYygiYSxiLGMiLCAiZCxlLGYsZyIsICJoLGksaiIpKSAlPiUKICBzZXBhcmF0ZSh4LCBjKCJvbmUiLCAidHdvIiwgInRocmVlIiksIGV4dHJhID0gImRyb3AiKQoKIyBPbmx5IHNwbGl0cyBhdCBtb3N0IGxlbmd0aChpbnRvKSB0aW1lcwp0aWJibGUoeCA9IGMoImEsYixjIiwgImQsZSxmLGciLCAiaCxpLGoiKSkgJT4lCiAgc2VwYXJhdGUoeCwgYygib25lIiwgInR3byIsICJ0aHJlZSIpLCBleHRyYSA9ICJtZXJnZSIpCmBgYAoKYGBge3J9CiMgSW4gdGhlc2UgZXhhbXBsZXMgdGhlIGNvbW1hbmQgZXhwZWN0cyAibW9yZSBkYXRhIi4KCiMgRW1pdCBhIHdhcm5pbmcgYW5kIGZpbGwgZnJvbSB0aGUgcmlnaHQKdGliYmxlKHggPSBjKCJhLGIsYyIsICJkLGUiLCAiZixnLGkiKSkgJT4lIAogIHNlcGFyYXRlKHgsIGMoIm9uZSIsICJ0d28iLCAidGhyZWUiKSwgZmlsbCA9ICJ3YXJuIikKCiMgRmlsbCB3aXRoIG1pc3NpbmcgdmFsdWVzIG9uIHRoZSByaWdodAp0aWJibGUoeCA9IGMoImEsYixjIiwgImQsZSIsICJmLGcsaSIpKSAlPiUgCiAgc2VwYXJhdGUoeCwgYygib25lIiwgInR3byIsICJ0aHJlZSIpLCBmaWxsID0gInJpZ2h0IikKCiMgRmlsbCB3aXRoIG1pc3NpbmcgdmFsdWVzIG9uIHRoZSBsZWZ0CnRpYmJsZSh4ID0gYygiYSxiLGMiLCAiZCxlIiwgImYsZyxpIikpICU+JSAKICBzZXBhcmF0ZSh4LCBjKCJvbmUiLCAidHdvIiwgInRocmVlIiksIGZpbGwgPSAibGVmdCIpCmBgYAoKMi4gQm90aCBfX3VuaXRlKClfXyBhbmQgX19zZXBhcmF0ZSgpX18gaGF2ZSBhIF9fcmVtb3ZlX18gYXJndW1lbnQuIFdoYXQgZG9lcyBpdCBkbz8gV2h5IHdvdWxkIHlvdSBzZXQgaXQgdG8gX19GQUxTRV9fPwoKKnJlbW92ZSogSWYgVFJVRSwgcmVtb3ZlIGlucHV0IGNvbHVtbiBmcm9tIG91dHB1dCBkYXRhIGZyYW1lLiBZb3Ugd291bGQgc2V0IGl0IHRvIF9fRkFMU0VfXyBpZiB5b3Ugd2FudCB0byBjcmVhdGUgYSBuZXcgdmFyaWFibGUsIGJ1dCBrZWVwIHRoZSBvbGQgb25lLiBJdCBkZWZhdWx0cyB0byBUUlVFLgoKMy4gQ29tcGFyZSBhbmQgY29udHJhc3QgX19zZXBhcmF0ZSgpX18gYW5kIF9fZXh0cmFjdCgpX18uIFdoeSBhcmUgdGhlcmUgdGhyZWUgdmFyaWF0aW9ucyBvZiBzZXBhcmF0aW9uIChieSBwb3NpdGlvbiwgYnkgc2VwYXJhdG9yLCBhbmQgd2l0aCBncm91cHMpLCBidXQgb25seSBvbmUgdW5pdGU/CgpCcmllZmx5IG1lbnRpb25lZCBlYXJsaWVyLCBfX3NlcGFyYXRlKClfXyBpcyBhIHR5cGUgb2YgcmVndWxhciBleHByZXNzaW9uIG9yICpyZWdleCouIFRodXMsIHdoZW4gdXNpbmcgX19zZXBhcmF0ZSgpX18geW91IGFyZSB0ZWxsaW5nIHRoZSBidWlsdC1pbiByZWdleCBmdW5jdGlvbiBob3cgdG8gc2VwYXJhdGUgdGhlIGRhdGEsIGkuZS4gYnkgcG9zaXRpb24gb3IgZGVsaW1pdGVyLiBIb3dldmVyLCBfX2V4dHJhY3QoKV9fIGFsbG93cyBmb3IgYSBsaXR0bGUgYml0IG1vcmUgZmxleGliaWxpdHkgYmVjYXVzZSBpdCBsZXRzIHlvdSB3cml0ZSB0aGUgcmVndWxhciBleHByZXNzaW9uIGRpY3RhdGluZyBob3cgdG8gc3BsaXQgdXAgdGhlIGRhdGEuCgpGb3IgZXhhbXBsZSwgaW4gdGhlIGV4YW1wbGUgYmVsb3cgX19zZXBhcmF0ZSgpX18gaXMgdW5hYmxlIHRvIHByb3Blcmx5IHNlcGFyYXRlIHRoZSBkYXRhIGJlY2F1c2UgdGhlcmUgaXMgbm8gZGVsaW1pdGVyIHRvIHNlcGFyYXRlIGJ5IGFuZCB0aGUgcG9zaXRpb25zIHZhcnkgKGluIHNvbWUgY2FzZXMgdGhlcmUgYXJlIHR3byBjaGFyYWN0ZXJzIGFuZCBpbiBzb21lIGNhc2VzIHRoZXJlIGlzIG9ubHkgb25lKS4KCmBgYHtyfQojIEZhaWxlZCBwYXJzZQp0aWJibGUoeCA9IGMoIlgxIiwgIlgyMCIsICJBQTExIiwgIkFBMiIpKSAlPiUKICBzZXBhcmF0ZShjb2wgPSB4LCBpbnRvID0gYygidmFyaWFibGUiLCAiaWQiKSwgc2VwID0gMSkKIyBGYWlsZWQgcGFyc2UKdGliYmxlKHggPSBjKCJYMSIsICJYMjAiLCAiQUExMSIsICJBQTIiKSkgJT4lCiAgc2VwYXJhdGUoY29sID0geCwgaW50byA9IGMoInZhcmlhYmxlIiwgImlkIiksIHNlcCA9IDIpCgojIEZhaWxlZCBwYXJzZQp0aWJibGUoeCA9IGMoIlgxIiwgIlgyMCIsICJBQTExIiwgIkFBMiIpKSAlPiUKICBzZXBhcmF0ZShjb2wgPSB4LCBpbnRvID0gYygidmFyaWFibGUiLCAiaWQiKSwgc2VwID0gIiIpCgojIFVzaW5nIGV4dHJhY3QKdGliYmxlKHggPSBjKCJYMSIsICJYMjAiLCAiQUExMSIsICJBQTIiKSkgJT4lCiAgZXh0cmFjdChjb2wgPSB4LCBpbnRvID0gYygidmFyaWFibGUiLCAiaWQiKSwgcmVnZXggPSAiKFtBLVpdKykoWzAtOV0rKSIpCmBgYAoKSW4gdGhlIHJlZ3VsYXIgZXhwcmVzc2lvbiBhYm92ZSwgdGhlIHBhcmVudGhlc2VzIGluZGljYXRlIHdoYXQgZWFjaCBzZWdtZW50IHRvIGJlIHJlYWQgc2hvdWxkIGxvb2sgbGlrZS4gVGh1cywgZm9yIHZhcmlhYmxlIHdlIGFyZSBwYXNzaW5nIG9uIHRoZSBjb25kaXRpb24gdGhhdCBpdCBtdXN0IGJlIGFscGhhYmV0aWNhbCBbQS1aXSBhbmQgY2FuIGJlIG9mIGFueSBsZW5ndGggKCspLiBUaGUgc2Vjb25kIHRlcm0sIGlkLCBtdXN0IGJlIG51bWVyaWMgWzAtOV0gYW5kIGNhbiBiZSBvZiBhbnkgbGVuZ3RoICgrKS4gVGhlIGVudGlyZSBleHByZXNzaW9uIG11c3QgYmUgc3Vycm91bmRlZCBieSBxdW90ZXMuCgpUaHVzIHdoZW4gc2VwYXJhdGluZyBhIHNpbmdsZSB2YXJpYWJsZSBpbnRvIG11bHRpcGxlIGNvbHVtbnMgdGhlcmUgY2FuIGJlIG11bHRpcGxlIGNyaXRlcmlhIGJ5IHdoaWNoIHlvdSB3b3VsZCBsaWtlIHRvIHNlcGFyYXRlLgoKSG93ZXZlciwgYXMgd2UnbGwgc2VlIGluIHRoZSBleGFtcGxlIGJlbG93IHdoZW4gdW5pdGluZyBkYXRhIGZyb20gbXVsdGlwbGUgY29sdW1ucyB0aGVyZSBpcyBhbHdheXMgb25seSBvbmUgY2hvaWNlIGFzIHRvIGhvdyB0byBjb21iaW5lIHRoZWlyIGNvbnRlbnRzLgoKYGBge3J9CiMgVW5pdGUKdGliYmxlKHggPSBjKCJBIiwgIkIiLCAiQyIsICJEIiksCiAgICAgICB5ID0gYygiMSIsICIyIiwgIjMiLCAiNCIpKSAlPiUKICB1bml0ZShjb2wgPSAiWFkiLCBjKHgsIHkpLCBzZXAgPSAiXyIpCgojIE9SCnRpYmJsZSh4ID0gYygiQSIsICJCIiwgIkMiLCAiRCIpLAogICAgICAgeSA9IGMoIjEiLCAiMiIsICIzIiwgIjQiKSkgJT4lCiAgdW5pdGUoY29sID0gIlhZIiwgYyh4LCB5KSwgc2VwID0gIiIpCmBgYAoKIyMgMTIuNSBNaXNzaW5nIHZhbHVlcwoKQ2hhbmdpbmcgdGhlIHJlcHJlc2VudGF0aW9uIG9mIGEgZGF0c2V0IGJyaW5ncyB1cCBhbiBpbXBvcnRhbnQgc3VidGxldHkgb2YgbWlzc2luZyB2YWx1ZXMuIFN1cnByaXNpbmdseSwgYSB2YWx1ZSBjYW4gYmUgbWlzc2luZyBpbiBvbmUgb2YgdHdvIHBvc3NpYmxlIHdheXM6CgoqIF9fRXhwbGljaWx5X18sIGkuZS4gZmxhZ2dlZCB3aXRoIF9fTkFfXy4KKiBfX0ltcGxpY2l0bHlfXywgaS5lLiBzaW1wbHkgbm90IHByZXNlbnQgaW4gdGhlIGRhdGEuCgpMZXQncyBpbGx1c3RyYXRlIHRoaXMgaWRlYSB3aXRoIGEgdmVyeSBzaW1wbGUgZGF0YSBzZXQ6CgpgYGB7cn0Kc3RvY2tzIDwtIHRpYmJsZSgKICB5ZWFyICAgPSBjKDIwMTUsIDIwMTUsIDIwMTUsIDIwMTUsIDIwMTYsIDIwMTYsIDIwMTYpLAogIHF0ciAgICA9IGMoICAgMSwgICAgMiwgICAgMywgICAgNCwgICAgMiwgICAgMywgICAgNCksCiAgcmV0dXJuID0gYygxLjg4LCAwLjU5LCAwLjM1LCAgIE5BLCAwLjkyLCAwLjE3LCAyLjY2KQopCgpzdG9ja3MKYGBgCgpUaGVyZSBhcmUgdHdvIG1pc3NpbmcgdmFsdWVzIGluIHRoaXMgZGF0YXNldDoKCiogVGhlIHJldHVybiBmb3IgdGhlIGZvdXJ0aCBxdWFydGVyIG9mIDIwMTUgaXMgZXhwbGljaXRseSBtaXNzaW5nLCBiZWNhdXNlIHRoZSBjZWxsIHdoZXJlIGl0cyB2YWx1ZSBzaG91bGQgYmUgaW5zdGVhZCBjb250YWlucyBfX05BX18uCiogVGhlIHJldHVybiBmb3IgdGhlIGZpcnN0IHF1YXJ0ZXIgb2YgMjAxNiBpcyBpbXBsaWNpdGx5IG1pc3NpbmcsIGJlY2F1c2UgaXQgc2ltcGx5bCBkb2VzIG5vdCBhcHBlYXIgaW4gdGhlIGRhdGFzZXQuCgpPbmUgd2F5IHRvIHRoaW5rIGFib3V0IHRoZSBkaWZmZXJlbmNlIGlzIHdpdGggdGhpcyBaZW4tbGlrZSBrb2FuOiBBbiBleHBsaWNpdCBtaXNzaW5nIHZhbHVlIGlzIHRoZSBwcmVzZW5jZSBvZiBhbiBhYnNlbmNlOyBhbiBpbXBsaWNpdCBtaXNzaW5nIHZhbHVlIGlzIHRoZSBhYnNlbmNlIG9mIGEgcHJlc2VuY2UuCgpUaGUgd2F5IHRoYXQgYSBkYXRhc2V0IGlzIHJlcHJlc2VudGVkIGNhbiBtYWtlIGltcGxpY2l0IHZhbHVlcyBleHBsaWNpdC4gRm9yIGV4YW1wbGUsIHdlIGNhbiBtYWtlIHRoZSBpbXBsaWNpdCBtaXNzaW5nIHZhbHVlIGV4cGxpY2l0IGJ5IHB1dHRpbmcgeWVhcnMgaW4gdGhlIGNvbHVtbnM6CgpgYGB7cn0Kc3RvY2tzICU+JQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSB5ZWFyLCB2YWx1ZXNfZnJvbSA9IHJldHVybikKYGBgCgpCZWNhdXNlIHRoZXNlIGV4cGxpY2l0IG1pc3NpbmcgdmFsdWVzIG1heSBub3QgYmUgaW1wb3J0YW50IGluIG90aGVyIHJlcHJlc2VudGF0aW9ucyBvZiB0aGUgZGF0YSwgeW91IGNhbiBzZXQgX192YWx1ZXNfZHJvcF9uYSA9IFRSVUVfXyBpbiBfX3Bpdm90X2xvbmdlcigpX18gdG8gdHVybiBleHBsaWNpdCBtaXNzaW5nIHZhbHVlcyBpbXBsaWNpdDoKCmBgYHtyfQpzdG9ja3MgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IHllYXIsIHZhbHVlc19mcm9tID0gcmV0dXJuKSAlPiUKICBwaXZvdF9sb25nZXIoCiAgICBjb2xzID0gYyhgMjAxNWAsIGAyMDE2YCksCiAgICBuYW1lc190byA9ICJ5ZWFyIiwKICAgIHZhbHVlc190byA9ICJyZXR1cm4iLAogICAgdmFsdWVzX2Ryb3BfbmEgPSBUUlVFCiAgKQpgYGAKCkFub3RoZXIgaW1wb3J0YW50IHRvb2wgZm9yIG1ha2luZyBtaXNzaW5nIHZhbHVlcyBleHBsaWNpdCBpbiB0aWR5IGRhdGEgaXMgX19jb21wbGV0ZSgpX186CgpgYGB7cn0Kc3RvY2tzICU+JQogIGNvbXBsZXRlKHllYXIsIHF0cikKYGBgCgpfX2NvbXBsZXRlKClfXyB0YWtlcyBhIHNldCBvZiBjb2x1bW5zLCBhbmQgZmluZHMgYWxsIHVuaXF1ZSBjb21iaW5hdGlvbnMuIEl0IHRoZW4gZW5zdXJlcyB0aGUgb3JpZ2luYWwgZGF0YXNldCBjb250YWlucyBhbGwgdGhvc2UgdmFsdWVzLCBmaWxsaW5nIGluIGV4cGxpY2l0IE5BcyB3aGVyZSBuZWNlc3NhcnkuIFRoZXJlJ3Mgb25lIG90aGVyIGltcG9ydGFudCB0b29sIHRoYXQgeW91IHNob3VsZCBrbm93IGZvciB3b3JraW5nIHdpdGggbWlzc2luZyB2YWx1ZXMuIFNvbWV0aW1lcyB3aGVuIGEgZGF0YSBzb3VyY2UgaGFzIHByaW1hcmlseSBiZWVuIHVzZWQgZm9yIGRhdGEgZW50cnksIG1pc3NpbmcgdmFsdWVzIGluZGljYXRlIHRoYXQgdGhlIHByZXZpb3VzIHZhbHVlIHNob3VsZCBiZSBjYXJyaWVkIGZvcndhcmQ6CgpgYGB7cn0KdHJlYXRtZW50IDwtIHRyaWJibGUoCiAgfiBwZXJzb24sICAgICAgICAgICB+IHRyZWF0bWVudCwgfnJlc3BvbnNlLAogICJEZXJyaWNrIFdoaXRtb3JlIiwgMSwgICAgICAgICAgIDcsCiAgTkEsICAgICAgICAgICAgICAgICAyLCAgICAgICAgICAgMTAsCiAgTkEsICAgICAgICAgICAgICAgICAzLCAgICAgICAgICAgOSwKICAiS2F0aGVyaW5lIEJ1cmtlIiwgIDEsICAgICAgICAgICA0CikKYGBgCgpZb3UgY2FuIGZpbGwgaW4gdGhlc2UgbWlzc2luZyB2YWx1ZXMgd2l0aCBfX2ZpbGwoKV9fLiBJdCB0YWtlcyBhIHNldCBvZiBjb2x1bW5zIHdoZXJlIHlvdSB3YW50IG1pc3NpbmcgdmFsdWVzIHRvIGJlIHJlcGxhY2VkIGJ5IHRoZSBtb3N0IHJlY2VudCBub24tbWlzc2luZyB2YWx1ZSAoc29tZXRpbWVzIGNhbGxlZCBsYXN0IG9ic2VydmF0aW9uIGNhcnJpZWQgZm9yd2FyZCkuCgpgYGB7cn0KdHJlYXRtZW50ICU+JQogIGZpbGwocGVyc29uLCAuZGlyZWN0aW9uID0gImRvd24iKQpgYGAKCiMjIyAxMi41LjEgRXhlcmNpc2VzCgoxLiBDb21wYXJlIGFuZCBjb250cmFzdCB0aGUgX19maWxsX18gYXJndW1lbnRzIHRvIF9fcGl2b3Rfd2lkZXIoKV9fIGFuZCBfX2NvbXBsZXRlKClfXy4KCl9fRmlsbF9fIGRvZXMgbm90IG1ha2UgY2hhbmdlcyB0byB0aGUgc3RydWN0dXJlIG9mIHRoZSBkYXRhLiBJdCBkb2VzIG5vdCByZW9yZ2FuaXplIGNvbHVtbnMuIFBpdm90X3dpZGVyIHRha2VzIHRoZSB2YWx1ZXMgaW4gYSBjb2x1bW4gYW5kIGNyZWF0ZXMgbmV3IGNvbHVtbnMgd2l0aCB0aGVtLiBDb21wbGV0ZSBmaW5kcyBhbGwgZXhpc3RpbmcgY29tYmluYXRpb25zIHVzaW5nIGEgc2V0IG9mIGNvbHVtbnMgYW5kIHRoZW4gZW5zdXJlcyB0aGUgb3JpZ2luYWwgZGF0YXNldCBjb250YWlucyBhbGwgdGhvc2UgdmFsdWVzLCBmaWxsaW5nIGluIGV4cGxpY2l0IE5BcyB3aGVyZSBuZWNlc3NhcnkuCgpNb3N0IGxpa2VseSB5b3Ugd291bGQgcGl2b3Rfd2lkZXIgYW5kIHRoZW4gY29tcGxldGUgd2hpY2ggd291bGQgbGlrZWx5IGNyZWF0ZSBzb21lIE5BcywgYnV0IHRob3NlIE5BcyBjb3VsZCBwb3NzaWJseSBiZSBmaWxsZWQgaW4gdXNpbmcgZmlsbC4KCjIuIFdoYXQgZG9lcyB0aGUgZGlyZWN0aW9uIGFyZ3VtZW50IHRvIF9fZmlsbCgpX18gZG8/CgoqLmRpcmVjdGlvbiogaW5kaWNhdGVzIGluIHdoYXQgZGlyZWN0aW9uIHRoZSBmaWxsIHNob3VsZCBoYXBwZW4gYygiZG93biIsICJ1cCIsICJkb3dudXAiLCAidXBkb3duIikuIERvd24gYW5kIHVwIGFyZSBmYWlybHkgaW50dWl0aXZlLCBidXQgImRvd251cCIgbWVhbnMgZmlyc3QgZG93biBhbmQgdGhlbiB1cCBhbmQgInVwZG93biIgbWVhbnMgZmlyc3QgdXAgYW5kIHRoZW4gZG93bi4KCiMgMTIuNiBDYXNlIFN0dWR5CgpUaWR5aW5nIGEgbWVzc3kgZGF0YXNldCBmcm9tIHRoZSBXb3JsZCBIZWFsdGggT3JnYW5pemF0aW9uIG9uIHR1YmVyY3Vsb3NpcyBjYXNlcy4KCkhlcmUgd2UgbW92ZSBhbGwgb2YgdGhlIGNvbHVtbnMgdGhhdCBzZWVtIHRvIHByb3ZpZGUgY2FzZSBkYXRhIHRvIGEgbmV3IHZhcmlhYmxlIGNhbGxlZCAia2V5IiBhbmQgbW92ZSB0aGUgdmFsdWVzIGZyb20gdGhlIHJlc3BlY3RpdmUgY29sdW1ucyBpbnRvIHRoZSBuZXcgY29sdW1uICJjYXNlcyIuCgpgYGB7cn0Kd2hvMSA8LSB3aG8gJT4lCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBuZXdfc3BfbTAxNDpuZXdyZWxfZjY1LAogICAgICAgICAgICAgICBuYW1lc190byA9ICJrZXkiLAogICAgICAgICAgICAgICB2YWx1ZXNfdG8gPSAiY2FzZXMiLAogICAgICAgICAgICAgICB2YWx1ZXNfZHJvcF9uYSA9IFRSVUUpCndobzEKYGBgCgpXZSBjYW4gZ2V0IHNvbWUgaGludCBvZiB0aGUgc3RydWN0dXJlIG9mIHRoZSB2YWx1ZXMgaW4gdGhlIG5ldyBfX2tleV9fIGNvbHVtbiBieSBjb3VudGluZyB0aGVtOgoKYGBge3J9CndobzEgJT4lCiAgY291bnQoa2V5KQpgYGAKCkFjY29yZGluZyB0byB0aGUgZGF0YSBkaWN0aW9uYXJ5OgoKMS4gVGhlIGZpcnN0IHRocmVlIGxldHRlcnMgb2YgZWFjaCBjb2x1bW4gZGVub3RlIHdoZXRoZXIgdGhlIGNvbHVtbiBjb250YWlucyBuZXcgb3Igb2xkIGNhc2VzIG9mIFRCLiBJbiB0aGlzIGRhdGFzZXQsIGVhY2ggY29sdW1uIGNvbnRhaW5zIG5ldyBjYXNlcy4KCjIuIFRoZSBuZXh0IHR3byBsZXR0ZXJzIGRlc2NyaXBlIHRoZSB0eXBlIG9mIFRCOgoKKiBfX3JlbF9fIHN0YW5kcyBmb3IgY2FzZXMgb2YgcmVsYXBzZQoqIF9fZXBfXyBzdGFuZHMgZm9yIGNhc2VzIG9mIGV4dHJhcHVsbW9uYXJ5IFRCCiogX19zbl9fIHN0YW5kcyBmb3IgY2FzZXMgb2YgcHVsbW9uYXJ5IFRCIHRoYXQgY291bGQgbm90IGJlIGRpYWdub3NlZCBieSBhIHB1bG1vbmFyeSBzbWVhciAoc21lYXIgbmVnYXRpdmUpCiogX19zcF9fIHN0YW5kcyBmb3IgY2FzZXMgb2YgcHVsbW9uYXJ5IFRCIHRoYXQgY291bGQgYmUgZGlhZ25vc2VkIGJ5IGEgcHVsbW9uYXJ5IHNtZWFyIChzbWVhciBwb3NpdGl2ZSkKCjMuIFRoZSBzaXh0aCBsZXR0ZXIgZ2l2ZXMgdGhlIHNleCBvZiBUQiBwYXRpZW50cy4gVGhlIGRhdGFzZXQgZ3JvdXBzIGNhc2VzIGJ5IG1hbGVzIChfX21fXykgYW5kIGZlbWFsZXMgKF9fZl9fKS4KCjQuIFRoZSByZW1haW5pbmcgbnVtYmVycyBnaXZlcyB0aGUgYWdlIGdyb3VwLiBUaGUgZGF0YXNldCBncm91cHMgY2FzZXMgaW50byBzZXZlbiBhZ2UgZ3JvdXBzOgoKKiBfXzAxNF9fID0gMCAtIDE0IHllYXJzIG9sZAoqIF9fMTUyNF9fID0gMTUgLSAyNCB5ZWFycyBvbGQKKiBfXzI1MzRfXyA9IDI1IC0gMzQgeWVhcnMgb2xkCiogX18gMzU0NF9fID0gMzUgLSA0NCB5ZWFycyBvbGQKKiBfXzQ1NDRfXyA9IDQ1IC0gNTQgeWVhcnMgb2xkCiogX181NTY0X18gPSA1NSAtIDY0IHllYXJzIG9sZAoqIF9fNjVfXyA9IDY1IG9yIG9sZGVyCgpXZSBuZWVkIHRvIG1ha2UgYSBtaW5vciBmaXggdG8gdGhlIGZvcm1hdCBvZiB0aGUgY29sdW1uIG5hbWVzOiB1bmZvcnR1bmF0ZWx5IHRoZSBuYW1lcyBhcmUgc2xpZ2h0bHkgaW5jb25zaXN0ZW4gYmVjYXVzZSBpbnN0ZWFkIG9mIF9fbmV3X3JlbF9fIHdlIGhhdmUgX19uZXdyZWxfXyAoaXQncyBoYXJkIHRvIHNwb3QgdGhpcyBoZXJlIGJ1dCBpZiB5b3UgZG9uJ3QgZml4IGl0IHdlJ2xsIGdldCBlcnJvcnMgaW4gc3Vic2VxdWVudCBzdGVwcykuIFlvdSdsbCBsZWFybiBhYm91dCBfX3N0cl9yZXBsYWNlKClfXyBpbiBfX3N0cmluZ3NfXywgYnV0IHRoZSBiYXNpYyBpZGVhIGlzIHByZXR0eSBzaW1wbGU6IHJlcGxhY2UgdGhlIGNoYXJhY3RlcnMgIm5ld3JlbCIgd2l0aCAibmV3X3JlbCIuIFRoaXMgbWFrZXMgYWxsIHZhcmlhYmxlIG5hbWVzIGNvbnNpc3RlbnQuCgpgYGB7cn0Kd2hvMiA8LSB3aG8xICU+JQogIG11dGF0ZShrZXkgPSBzdHJfcmVwbGFjZShrZXksICJuZXdyZWwiLCAibmV3X3JlbCIpKQp3aG8yICU+JQogIGZpbHRlcihncmVwbCgibmV3X3JlbCIsIGtleSwgaWdub3JlLmNhc2UgPSBUUlVFKSA9PSBUUlVFKQpgYGAKCldlIGNhbiBzZXBhcmF0ZSB0aGUgdmFsdWVzIGluIGVhY2ggY29kZSB3aXRoIHR3byBwYXNzZXMgb2YgX19zZXBhcmF0ZSgpX18uIFRoZSBmaXJzdCBwYXNzIHdpbGwgc3BsaXQgdGhlIGNvZGVzIGF0IGVhY2ggdW5kZXJzY29yZS4KCmBgYHtyfQp3aG8zIDwtIHdobzIgJT4lCiAgc2VwYXJhdGUoY29sID0ga2V5LCBpbnRvID0gYygibmV3b2xkIiwgInR5cGUiLCAic2V4YWdlIiksIHNlcCA9ICJfIikgJT4lCiAgc2VwYXJhdGUoY29sID0gc2V4YWdlLCBpbnRvID0gYygic2V4IiwgImFnZSIpLCBzZXAgPSAxKQoKd2hvMwoKd2hvNCA8LSBzdWJzZXQod2hvMywgc2VsZWN0ID0gLWMoaXNvMiwgaXNvMywgbmV3b2xkKSkKd2hvNApgYGAKClRoZSBfX3dob19fIGRhdGFzZXQgaXMgbm93IHRpZHkhISEKCkluIGZ1dHVyZSBjYXNlcywgcmF0aGVyIHRoYW4gcGVyZm9ybWluZyBlYWNoIG9wZXJhdGlvbiBvbmUgY29kZSBhdCBhIHRpbWUsIHdlIHdvdWxkIGJ1aWxkIHVwIGEgY29tcGxleCBwaXBlIHRvIHBlcmZvcm0gYWxsIG9mIHRoZSBvcGVyYXRpb25zIGluIGEgc2luZ2xlIGNodW5rIG9mIGNvZGUuCgpgYGB7cn0Kd2hvICU+JQogIHBpdm90X2xvbmdlcigKICAgIGNvbHMgPSBuZXdfc3BfbTAxNDpuZXdyZWxfZjY1LCAKICAgIG5hbWVzX3RvID0gImtleSIsIAogICAgdmFsdWVzX3RvID0gImNhc2VzIiwgCiAgICB2YWx1ZXNfZHJvcF9uYSA9IFRSVUUKICApICU+JSAKICBtdXRhdGUoCiAgICBrZXkgPSBzdHJpbmdyOjpzdHJfcmVwbGFjZShrZXksICJuZXdyZWwiLCAibmV3X3JlbCIpCiAgKSAlPiUKICBzZXBhcmF0ZShrZXksIGMoIm5ldyIsICJ2YXIiLCAic2V4YWdlIikpICU+JSAKICBzZWxlY3QoLW5ldywgLWlzbzIsIC1pc28zKSAlPiUgCiAgc2VwYXJhdGUoc2V4YWdlLCBjKCJzZXgiLCAiYWdlIiksIHNlcCA9IDEpCmBgYAoKIyMjIDEyLjYuMSBFeGVyY2lzZXMKCjEuIEluIHRoaXMgY2FzZSBzdHVkeSBJIHNldCBfX3ZhbHVlc19kcm9wX25hID0gVFJVRV9fIGp1c3QgdG8gbWFrZSBpdCBlYXNpZXIgdG8gY2hlY2sgdGhhdCB3ZSBoYWQgdGhlIGNvcnJlY3QgdmFsdWVzLiBJcyB0aGlzIHJlYXNvbmFibGU/IFRoaW5rIGFib3V0IGhvdyBtaXNzaW5nIHZhbHVlcyBhcmUgcmVwcmVzZW50ZWQgaW4gdGhpcyBkYXRhc2V0LiBBcmUgdGhlcmUgaW1wbGljaXQgbWlzc2luZyB2YWx1ZXM/IFdoYXQncyB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIGFuIF9fTkFfXyBhbmQgemVybz8KCldoaWxlIGl0IG1pZ2h0IG5vdCBiZSBhZHZpc2FibGUgY29uc2lkZXJpbmcgd2Ugc3RhcnRlZCBvZmYga25vd2luZyB2ZXJ5IGxpdHRsZSBhYm91dCB0aGUgZGF0YSwgaW4gaGluZHNpZ2h0IGl0IGFwcGVhcnMgZmluZS4gVGhlIGRhdGEgaXMgc3RydWN0dXJlZCB0byBzaG93IHRoZSBudW1iZXIgb2YgdHViZXJjdWxvc2lzIGNhc2VzIGJ5IGNvdW50cnksIHllYXIsIHR5cGUsIHNleCwgYW5kIGFnZS4gVGhpcyBtZWFucyB0aGF0IGZvciAyMTkgY291bnRyaWVzIHJlcHJlc2VudGVkIGluIHRoZSBkYXRhc2V0LCB0aGV5IHNob3VsZCBlYWNoIGhhdmUgMzQgeWVhcnMgb2YgZGF0YSAoMTk4MCAtIDIwMTMpLCBvbiA0IGRpc3RpbmN0IHR5cGVzIG9mIHR1YmVjdWxvc2lzIGFuZCA3IGFnZSBncm91cHMuCgpgYGB7cn0KIyBDaGVjayBpZiB0aGVyZSBhcmUgdHJ1ZSB6ZXJvZXMgaW4gdGhlIGRhdGEgKE5BcyBkb24ndCBtZWFuIHplcm8pCndobzEgJT4lCiAgZmlsdGVyKGNhc2VzID09IDApICU+JQogIG5yb3coKQpgYGAKClRoZXJlIGFyZSAxMSwwODAgcm93cyBpbiB0aGUgZGF0YSB3aGVyZSB0aGUgbnVtYmVyIG9mIGNhc2VzIGVxdWFscyB6ZXJvLgoKQW4gX19OQV9fIG1lYW5zIG5vdGhpbmcgd2FzIGV4cGxpY2l0bHkgZmlsbGVkIGluIGZvciB0aGF0IHZhbHVlLiBBIHplcm8gbWVhbnMgYSB6ZXJvIHdhcyBlbnRlcmVkLgoKYGBge3J9CiMgQ2hlY2sgaWYgY291bnRyeS15ZWFyIGdyb3VwIGNhbiBiZSBtaXNzaW5nIHNvbWUgZGF0YSwgYnV0IG5vdCBhbGwuCnBpdm90X2xvbmdlcih3aG8sIGMobmV3X3NwX20wMTQ6bmV3cmVsX2Y2NSksIG5hbWVzX3RvID0gImtleSIsIHZhbHVlc190byA9ICJjYXNlcyIpICU+JQogIGdyb3VwX2J5KGNvdW50cnksIHllYXIpICU+JQogIG11dGF0ZShwcm9wX21pc3NpbmcgPSBzdW0oaXMubmEoY2FzZXMpKS9uKCkpICU+JQogIGZpbHRlcihwcm9wX21pc3NpbmcgPiAwLCBwcm9wX21pc3NpbmcgPCAxKQpgYGAKCkZpbmFsbHksIEkgd2lsbCBjaGVjayBmb3IgaW1wbGljaXQgbWlzc2luZyB2YWx1ZXMuIEltcGxpY2l0IG1pc3NpbmcgdmFsdWVzIGFyZSAoX195ZWFyX18sIF9fY291bnRyeV9fKSBjb21iaW5hdGlvbnMgdGhhdCBkbyBub3QgYXBlYXIgaW4gdGhlIGRhdGEuCgpgYGB7cn0KIyBDaGVjayBmb3IgaW1wbGljaXQgdmFsdWVzLgpucm93KHdobykKCndobyAlPiUKICBjb21wbGV0ZShjb3VudHJ5LCB5ZWFyKSAlPiUKICBucm93KCkKYGBgCgpgYGB7cn0KYW50aV9qb2luKGNvbXBsZXRlKHdobywgY291bnRyeSwgeWVhciksIHdobywgYnkgPSBjKCJjb3VudHJ5IiwgInllYXIiKSkgJT4lCiAgc2VsZWN0KGNvdW50cnksIHllYXIpICU+JQogIGdyb3VwX2J5KGNvdW50cnkpICU+JQogIHN1bW1hcmlzZShtaW5feWVhciA9IG1pbih5ZWFyKSwgbWF4X3llYXIgPSBtYXgoeWVhcikpCmBgYAoKVG8gc3VtbWFyaXplOgoKKiAwIGlzIHVzZWQgdG8gcmVwcmVzZW50IG5vIGNhc2VzIG9mIFRCLgoqIEV4cGxpY2l0IG1pc3NpbmcgdmFsdWVzIChfX05BX19zKSBhcmUgdXNlZCB0byByZXByZXNlbnQgbWlzc2luZyBkYXRhIGZvciAoX19jb3VudHJ5X18sIF9feWVhcl9fKSBjb21iaW5hdGlvbnMgaW4gd2hpY2ggdGhlIGNvdW50cnkgZXhpc3RlZCBpbiB0aGF0IHllYXIuCiogSW1wbGljaXQgbWlzc2luZyB2YWx1ZXMgYXJlIHVzZWQgdG8gcmVwcmVzZW50IG1pc3NpbmcgZGF0YSBiZWNhdXNlIGEgY291bnRyeSBkaWQgbm90IGV4aXN0IGluIHRoYXQgeWVhci4KCjIuIFdoYXQgaGFwcGVucyBpZiB5b3UgbmVnbGVjdCB0aGUgX19tdXRhdGUoKV9fIHN0ZXA/IChfX211dGF0ZShuYW1lc19mcm9tID0gc3RyaW5ncjo6c3RyX3JlcGxhY2Uoa2V5LCAibmV3cmVsIiwgIm5ld19yZWwiKSkpPwoKYGBge3J9CndobyAlPiUKICBwaXZvdF9sb25nZXIoCiAgICBjb2xzID0gbmV3X3NwX20wMTQ6bmV3cmVsX2Y2NSwgCiAgICBuYW1lc190byA9ICJrZXkiLCAKICAgIHZhbHVlc190byA9ICJjYXNlcyIsIAogICAgdmFsdWVzX2Ryb3BfbmEgPSBUUlVFCiAgKSAlPiUgCiAgbXV0YXRlKAogICAga2V5ID0gc3RyaW5ncjo6c3RyX3JlcGxhY2Uoa2V5LCAibmV3cmVsIiwgIm5ld19yZWwiKQogICkgJT4lCiAgc2VwYXJhdGUoa2V5LCBjKCJuZXciLCAidmFyIiwgInNleGFnZSIpKSAlPiUgCiAgc2VsZWN0KC1uZXcsIC1pc28yLCAtaXNvMykgJT4lIAogIHNlcGFyYXRlKHNleGFnZSwgYygic2V4IiwgImFnZSIpLCBzZXAgPSAxKQpgYGAKCmBgYHtyfQp3aG8gJT4lCiAgcGl2b3RfbG9uZ2VyKAogICAgY29scyA9IG5ld19zcF9tMDE0Om5ld3JlbF9mNjUsIAogICAgbmFtZXNfdG8gPSAia2V5IiwgCiAgICB2YWx1ZXNfdG8gPSAiY2FzZXMiLCAKICAgIHZhbHVlc19kcm9wX25hID0gVFJVRQogICkgJT4lCiAgc2VwYXJhdGUoa2V5LCBjKCJuZXciLCAidmFyIiwgInNleGFnZSIpKSAlPiUgCiAgc2VsZWN0KC1uZXcsIC1pc28yLCAtaXNvMykgJT4lIAogIHNlcGFyYXRlKHNleGFnZSwgYygic2V4IiwgImFnZSIpLCBzZXAgPSAxKQpgYGAKCklmIHlvdSBuZWdsZWN0IHRoZSBtdXRhdGUgc3RlcCB5b3UgZ2V0IGFuIGVycm9yIG1lc3NhZ2Ugd2hlbiB5b3UgdHJ5IHRvIHNlcGFyYXRlIHRoZSBrZXkgdmFyaWFibGUgYmVjYXVzZSB3aGVuIGl0IHRyaWVzIHRvIHNlcGFyYXRlIGJ5IHRoZSAiXyIgZGVsaW1pdGVyIGl0IGRvZXMgbm90IGZpbmQgb25lIGFuZCBzbyBOQXMgYXJlIGNyZWF0ZWQuCgpgYGB7cn0Kd2hvICU+JQogIHNlbGVjdChjb3VudHJ5LCBpc28yLCBpc28zKSAlPiUKICBncm91cF9ieShjb3VudHJ5LCBpc28yLCBpc28zKSAlPiUKICBkaXN0aW5jdCgpICU+JQogIGV4dHJhY3QoY29sID0gY291bnRyeSwgaW50byA9ICJhYmIzIiwgcmVnZXggPSAiKFthLXpBLVpdezN9KSIsIHJlbW92ZSA9IEZBTFNFKSAlPiUKICBleHRyYWN0KGNvbCA9IGNvdW50cnksIGludG8gPSAiYWJiMiIsIHJlZ2V4ID0gIihbYS16QS1aXXsyfSkiLCByZW1vdmUgPSBGQUxTRSkgJT4lCiAgbXV0YXRlKGFiYjIgPSB0b2xvd2VyKGFiYjIpLAogICAgICAgICBhYmIzID0gdG9sb3dlcihhYmIzKSwKICAgICAgICAgaXNvMiA9IHRvbG93ZXIoaXNvMiksCiAgICAgICAgIGlzbzMgPSB0b2xvd2VyKGlzbzMpKSAlPiUKICBmaWx0ZXIoYWJiMiAhPSBpc28yICYgYWJiMyAhPSBpc28zKQpgYGAKClVuZm9ydHVuYXRlbHksIHRoZSBhY3JvbnltcyBkbyBub3QgbGluZSB1cCAxMDAlIGV2ZW5seSwgYnV0IGl0IHNlZW1zIHByZXR0eSBjbGVhciB0aGF0IHRoZXNlIGFyZSBqdXN0IGFiYnJldmlhdGlvbnMgdXNpbmcgdHdvIGFuZCAzIGxldHRlcnMuCgpBIGNsZWFyZXIgd2F5IHRvIGRvIHRoaXMgaXMgdG8ganVzdCBjaGVjayBpZiB0aGVyZSBhcmUgbW9yZSB0aGFuIG9uZSB1bmlxdWUgY29tYmluYXRpb24gZm9yIGVhY2ggY291bnRyeS4KCmBgYHtyfQpzZWxlY3Qod2hvLCBjb3VudHJ5LCBpc28yLCBpc28zKSAlPiUKICBkaXN0aW5jdCgpICU+JQogIGdyb3VwX2J5KGNvdW50cnkpICU+JQogIGZpbHRlcihuKCkgPiAxKQpgYGAKCmBgYHtyfQp3aG80ICU+JQogIGdyb3VwX2J5KGNvdW50cnksIHllYXIsIHNleCkgJT4lCiAgc3VtbWFyaXNlKHRvdF9jYXNlcyA9IHN1bShjYXNlcykpICAlPiUKICB1bml0ZShjb3VudHJ5X3NleCwgYyhjb3VudHJ5LCBzZXgpLCBzZXAgPSAiXyIsIHJlbW92ZSA9IEZBTFNFKSAlPiUKICBnZ3Bsb3QoYWVzKHllYXIsIHRvdF9jYXNlcykpICsKICBnZW9tX2xpbmUoYWVzKGdyb3VwID0gY291bnRyeV9zZXgsIGNvbG9yID0gc2V4KSkgKwogIGNvb3JkX2NhcnRlc2lhbih4bGltID0gYygxOTk1LCAyMDEzKSkKYGBgCgpJdCB3b3VsZCBwcm9iYWJseSBtYWtlIG1vc3Qgc2Vuc2UgdG8gc3BsaXQgdGhlIGNvdW50cnkgZGF0YSBpbnRvIHF1YW50aWxlcyBhbmQgdGhlbiBleGFtaW5lIHRob3NlIGxpbmVzLgoKIyMgMTIuNyBOb24tdGlkeSBkYXRhCgpKdXN0IGJlY2F1c2UgYSBkYXRhc2V0IG1pZ2h0IGJlICJtZXNzeSIgb3Igbm90ICJ0aWR5IiBkb2VzIG5vdCBtZWFuIHRoYXQgaXQgaXMgdXNlbGVzcy4gVHdvIG1haW4gcmVhc29ucyBmb3IgdXNpbmcgb3RoZXIgZGF0YSBzdHJ1Y3R1cmVzIGFyZToKCiogQWx0ZXJuYXRpdmUgcmVwcmVzZW50YXRpb25zIG1heSBoYXZlIHN1YnN0YW50aWFsIHBlcmZvcm1hbmNlIG9yIHNwYWNlIGFkdmFudGFnZXMuCiogU3BlY2lhbGlzZWQgZmllbGRzIGhhdmUgZXZvbHZlZCB0aGVpciBvd24gY29udmVudGlvbnMgZm9yIHN0b3JpbmcgZGF0YSB0aGF0IG1heSBiZSBxdWl0ZSBkaWZmZXJlbnQgdG8gdGhlIGNvbnZlbnRpb25zIG9mIHRpZHkgZGF0YS4KClRpZHkgZGF0YSBpcyBhIG5pY2UgZGVmYXVsdCwgYnV0IHRoZXJlIGFyZSBnb29kIHJlYXNvbnMgdG8gdXNlIG90aGVyIHN0cnVjdHVyZXMuCgoKCgoKCgoKCg==