suppressPackageStartupMessages(library("tidyverse"))

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 %>% 
  pivot_wider(names_from = year, values_from = return) %>% 
  pivot_longer(`2015`:`2016`, names_to = "year", values_to = "return")

(Hint: look at the variable types and think about column names.) pivot_longer() has a names_ptype argument, e.g. names_ptype = list(year = double()). What does it do?

The functions pivot_longer() and pivot_wider() are not perfectly symmetrical because column type information is lost. When we use pivot_wider() on a data frame, it discards the original column types. It has to coerce all the variables into a single vector with a single type. Later, if we pivot_longer() that data frame, the pivot_longer() function does not know the original data types of the variables.

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

The following use of pivot_longer() will create a column, year, from the column names. However, since column names are used to create the names_from column, the resulting vector is a character vector. Even though we “know” that the all the column names refer to years, which are numbers, the pivot_longer() function does not know that.

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

names_ptype in pivot_longer() is a list of of column name-prototype pairs. A prototype (or ptype for short) is a zero-length vector (like integer() or numeric()) that defines the type, class, and attributes of a vector. If not specified, the type of the columns generated from names_to will be character, and the type of the variables generated from values_to will be the common type of the input columns used to generate them.

The functions pivot_wider() and pivot_longer() are almost symmetrical if we use the names_ptype argument. When names_ptype = list(year = double()), the pivot_longer() function will attempt to convert year to the double.

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

Now, year is a double vector. However, this conversion is merely guessing the type of the variables and so will not always return the original variable types. That information is lost.

2. Why does this code fail?

#table4a %>% 
  #pivot_longer(c(1999, 2000), names_to = "year", values_to = "cases")
#> Error in inds_combine(.vars, ind_list): Position must be between 0 and n

The code fails because the column names 1999 and 2000 are not non-syntactic variable names. A syntactic name must consist of letters2, digits, . and _ but can’t begin with _ or a digit. Additionally, you can’t use any of the reserved words like TRUE, NULL, if, and function (see the complete list in ?Reserved). A name that doesn’t follow these rules is a non-syntactic name; if you try to use them, you’ll get an error.

When selecting variables from a data frame, tidyverse functions will interpret numbers, like 1999 and 2000, as column numbers. In this case, pivot_longer() tries to select 1999th and 2000th column of the data frame. To select the columns 1999 and 2000, you can either surround their names in backticks ( `) or provide them as strings.

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

3.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
)

glimpse(people)
Observations: 5
Variables: 3
$ name   <chr> "Phillip Woods", "Phillip Woods", "Phillip Woods", "Jessica Cordero", "Jessica Co...
$ names  <chr> "age", "height", "age", "age", "height"
$ values <dbl> 45, 186, 50, 37, 156
pivot_wider(people, names_from = names, values_from = values)
Values in `values` are not uniquely identified; output will contain list-cols.
* Use `values_fn = list(values = list)` to suppress this warning.
* Use `values_fn = list(values = length)` to identify where the duplicates arise
* Use `values_fn = list(values = summary_fun)` to summarise duplicates

pivot_wider() this data frame fails because the name and key columns do not uniquely identify rows. In particular, there are two rows with values for the age of “Phillip Woods”.

We could solve the problem by adding a row with a distinct observation count for each combination of name and key.

people2 <- people %>%
  group_by(name, names) %>%
  mutate(obs = row_number())
people2

We can pivot_wider() people2 because the combination of name and obs will uniquely identify the spread rows.

pivot_wider(people2, names_from = names, values_from = values)

Another way to solve this problem is by keeping only distinct rows of the name and key values, and dropping duplicate rows.

people %>%
  distinct(name, names, .keep_all = TRUE) %>%
  pivot_wider(names_from = names, values_from = values)

However, before doing this you would want to understand why there are duplicates in the data to begin with. This is usually not merely a nuisance, but indicates deeper problems with the data.

4. 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
)

To tidy the preg tibble, we need to use pivot_longer(). The variables in this data are:

  • sex (“female”, “male”)
  • pregnant (“yes”, “no”)
  • count, which is a non-negative integer representing the number of observations.

The observations in this data are unique combinations of sex and pregnancy status.

preg_tidy <- preg %>%
  #gather(male, female, key = "sex", value = "count")
  pivot_longer(c(male, female), names_to = "sex", values_to = "count")
preg_tidy

We can simplify the tidied data frame by removing the (male, pregnant) row with the missing value of NA.

preg_tidy2 <- preg %>%
  pivot_longer(c(male, female), names_to = "sex", values_to = "count", values_drop_na=TRUE)
preg_tidy2

This an example of turning an explicit missing value into an implicit missing value, which is discussed in the upcoming Missing Values section. The missing (male, pregnant) row represents an implicit missing value because the value of count can be inferred from its absence. In the tidy data, we can represent rows with missing values of count either explicitly with an NA (as in preg_tidy) or implicitly by the absence of a row (as in preg_tidy2). But in the wide data, the missing values can only be represented explicitly.

Though we have already done enough to make the data tidy, there’s some other changes that can be made to clean this data. If a variable takes two values, like pregnant and sex, it is often preferable to store them as logical vectors.

preg_tidy3 <- preg_tidy2 %>%
  mutate(
    female = sex == "female",
    pregnant = pregnant == "yes"
  ) %>%
  select(female, pregnant, count)
preg_tidy3

In the previous data frame, I named the logical variable representing the sex female, not sex. This makes the meaning of the variable self-documenting. If the variable were named sex with values TRUE and FALSE, without reading the documentation, we wouldn’t know whether TRUE means male or female.

Apart from some minor memory savings, representing these variables as logical vectors results in more clear and concise code. Compare the filter() calls to select non-pregnant females from preg_tidy2 and preg_tidy.

filter(preg_tidy2, sex == "female", pregnant == "no")
filter(preg_tidy3, female, !pregnant)
LS0tDQp0aXRsZTogIlBpdm90aW5nIg0Kb3V0cHV0OiANCiAgaHRtbF9ub3RlYm9vazoNCiAgICB0b2M6IHRydWUNCiAgICB0b2NfZmxvYXQ6IHRydWUNCi0tLQ0KDQpgYGB7cn0NCnN1cHByZXNzUGFja2FnZVN0YXJ0dXBNZXNzYWdlcyhsaWJyYXJ5KCJ0aWR5dmVyc2UiKSkNCmBgYA0KDQojIyMgMS4gV2h5IGFyZSBgcGl2b3RfbG9uZ2VyKClgIGFuZCBgcGl2b3Rfd2lkZXIoKWAgbm90IHBlcmZlY3RseSBzeW1tZXRyaWNhbD8gQ2FyZWZ1bGx5IGNvbnNpZGVyIHRoZSBmb2xsb3dpbmcgZXhhbXBsZToNCg0KYGBge3J9DQpzdG9ja3MgPC0gdGliYmxlKA0KICB5ZWFyICAgPSBjKDIwMTUsIDIwMTUsIDIwMTYsIDIwMTYpLA0KICBoYWxmICA9IGMoICAgMSwgICAgMiwgICAgIDEsICAgIDIpLA0KICByZXR1cm4gPSBjKDEuODgsIDAuNTksIDAuOTIsIDAuMTcpDQopDQpzdG9ja3MgJT4lIA0KICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0geWVhciwgdmFsdWVzX2Zyb20gPSByZXR1cm4pICU+JSANCiAgcGl2b3RfbG9uZ2VyKGAyMDE1YDpgMjAxNmAsIG5hbWVzX3RvID0gInllYXIiLCB2YWx1ZXNfdG8gPSAicmV0dXJuIikNCmBgYA0KDQooSGludDogbG9vayBhdCB0aGUgdmFyaWFibGUgdHlwZXMgYW5kIHRoaW5rIGFib3V0IGNvbHVtbiBuYW1lcy4pIGBwaXZvdF9sb25nZXIoKWAgaGFzIGEgYG5hbWVzX3B0eXBlYCBhcmd1bWVudCwgZS5nLiBgbmFtZXNfcHR5cGUgPSBsaXN0KHllYXIgPSBkb3VibGUoKSlgLiBXaGF0IGRvZXMgaXQgZG8/DQoNClRoZSBmdW5jdGlvbnMgYHBpdm90X2xvbmdlcigpYCBhbmQgYHBpdm90X3dpZGVyKClgIGFyZSBub3QgcGVyZmVjdGx5IHN5bW1ldHJpY2FsIGJlY2F1c2UgY29sdW1uIHR5cGUgaW5mb3JtYXRpb24gaXMgbG9zdC4gV2hlbiB3ZSB1c2UgYHBpdm90X3dpZGVyKClgIG9uIGEgZGF0YSBmcmFtZSwgaXQgZGlzY2FyZHMgdGhlIG9yaWdpbmFsIGNvbHVtbiB0eXBlcy4gSXQgaGFzIHRvIGNvZXJjZSBhbGwgdGhlIHZhcmlhYmxlcyBpbnRvIGEgc2luZ2xlIHZlY3RvciB3aXRoIGEgc2luZ2xlIHR5cGUuIExhdGVyLCBpZiB3ZSBgcGl2b3RfbG9uZ2VyKClgIHRoYXQgZGF0YSBmcmFtZSwgdGhlIGBwaXZvdF9sb25nZXIoKWAgZnVuY3Rpb24gZG9lcyBub3Qga25vdyB0aGUgb3JpZ2luYWwgZGF0YSB0eXBlcyBvZiB0aGUgdmFyaWFibGVzLg0KDQpgYGB7cn0NCnN0b2NrcyAlPiUgDQogIHBpdm90X3dpZGVyKG5hbWVzX2Zyb20gPSB5ZWFyLCB2YWx1ZXNfZnJvbSA9IHJldHVybikNCmBgYA0KDQpUaGUgZm9sbG93aW5nIHVzZSBvZiBgcGl2b3RfbG9uZ2VyKClgIHdpbGwgY3JlYXRlIGEgY29sdW1uLCB5ZWFyLCBmcm9tIHRoZSBjb2x1bW4gbmFtZXMuIEhvd2V2ZXIsIHNpbmNlIGNvbHVtbiBuYW1lcyBhcmUgdXNlZCB0byBjcmVhdGUgdGhlIGBuYW1lc19mcm9tYCBjb2x1bW4sIHRoZSByZXN1bHRpbmcgdmVjdG9yIGlzIGEgY2hhcmFjdGVyIHZlY3Rvci4gRXZlbiB0aG91Z2ggd2Ug4oCca25vd+KAnSB0aGF0IHRoZSBhbGwgdGhlIGNvbHVtbiBuYW1lcyByZWZlciB0byB5ZWFycywgd2hpY2ggYXJlIG51bWJlcnMsIHRoZSBgcGl2b3RfbG9uZ2VyKClgIGZ1bmN0aW9uIGRvZXMgbm90IGtub3cgdGhhdC4NCg0KYGBge3J9DQpzdG9ja3MgJT4lIA0KICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0geWVhciwgdmFsdWVzX2Zyb20gPSByZXR1cm4pICU+JSANCiAgcGl2b3RfbG9uZ2VyKGAyMDE1YDpgMjAxNmAsIG5hbWVzX3RvID0gInllYXIiLCB2YWx1ZXNfdG8gPSAicmV0dXJuIikNCmBgYA0KDQpgbmFtZXNfcHR5cGVgIGluIGBwaXZvdF9sb25nZXIoKWAgaXMgYSBsaXN0IG9mIG9mIGNvbHVtbiBuYW1lLXByb3RvdHlwZSBwYWlycy4gQSBwcm90b3R5cGUgKG9yIHB0eXBlIGZvciBzaG9ydCkgaXMgYSB6ZXJvLWxlbmd0aCB2ZWN0b3IgKGxpa2UgYGludGVnZXIoKWAgb3IgYG51bWVyaWMoKWApIHRoYXQgZGVmaW5lcyB0aGUgdHlwZSwgY2xhc3MsIGFuZCBhdHRyaWJ1dGVzIG9mIGEgdmVjdG9yLiBJZiBub3Qgc3BlY2lmaWVkLCB0aGUgdHlwZSBvZiB0aGUgY29sdW1ucyBnZW5lcmF0ZWQgZnJvbSBuYW1lc190byB3aWxsIGJlIGNoYXJhY3RlciwgYW5kIHRoZSB0eXBlIG9mIHRoZSB2YXJpYWJsZXMgZ2VuZXJhdGVkIGZyb20gdmFsdWVzX3RvIHdpbGwgYmUgdGhlIGNvbW1vbiB0eXBlIG9mIHRoZSBpbnB1dCBjb2x1bW5zIHVzZWQgdG8gZ2VuZXJhdGUgdGhlbS4NCg0KVGhlIGZ1bmN0aW9ucyBgcGl2b3Rfd2lkZXIoKWAgYW5kIGBwaXZvdF9sb25nZXIoKWAgYXJlIGFsbW9zdCBzeW1tZXRyaWNhbCBpZiB3ZSB1c2UgdGhlIGBuYW1lc19wdHlwZWAgYXJndW1lbnQuIFdoZW4gYG5hbWVzX3B0eXBlID0gbGlzdCh5ZWFyID0gZG91YmxlKCkpYCwgdGhlIGBwaXZvdF9sb25nZXIoKWAgZnVuY3Rpb24gd2lsbCBhdHRlbXB0IHRvIGNvbnZlcnQgYHllYXJgIHRvIHRoZSBkb3VibGUuDQoNCmBgYHtyfQ0Kc3RvY2tzICU+JSANCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IHllYXIsIHZhbHVlc19mcm9tID0gcmV0dXJuKSAlPiUgDQogIHBpdm90X2xvbmdlcihgMjAxNWA6YDIwMTZgLCBuYW1lc190byA9ICJ5ZWFyIiwgdmFsdWVzX3RvID0gInJldHVybiIsIG5hbWVzX3B0eXBlID0gbGlzdCh5ZWFyID0gZG91YmxlKCkpKQ0KYGBgDQoNCk5vdywgYHllYXJgIGlzIGEgZG91YmxlIHZlY3Rvci4gSG93ZXZlciwgdGhpcyBjb252ZXJzaW9uIGlzIG1lcmVseSBndWVzc2luZyB0aGUgdHlwZSBvZiB0aGUgdmFyaWFibGVzIGFuZCBzbyB3aWxsIG5vdCBhbHdheXMgcmV0dXJuIHRoZSBvcmlnaW5hbCB2YXJpYWJsZSB0eXBlcy4gVGhhdCBpbmZvcm1hdGlvbiBpcyBsb3N0Lg0KDQoNCiMjIyAyLiBXaHkgZG9lcyB0aGlzIGNvZGUgZmFpbD8NCg0KYGBge3J9DQojdGFibGU0YSAlPiUgDQogICNwaXZvdF9sb25nZXIoYygxOTk5LCAyMDAwKSwgbmFtZXNfdG8gPSAieWVhciIsIHZhbHVlc190byA9ICJjYXNlcyIpDQojPiBFcnJvciBpbiBpbmRzX2NvbWJpbmUoLnZhcnMsIGluZF9saXN0KTogUG9zaXRpb24gbXVzdCBiZSBiZXR3ZWVuIDAgYW5kIG4NCmBgYA0KDQpUaGUgY29kZSBmYWlscyBiZWNhdXNlIHRoZSBjb2x1bW4gbmFtZXMgMTk5OSBhbmQgMjAwMCBhcmUgbm90IG5vbi1zeW50YWN0aWMgdmFyaWFibGUgbmFtZXMuIEEgc3ludGFjdGljIG5hbWUgbXVzdCBjb25zaXN0IG9mIGxldHRlcnMyLCBkaWdpdHMsIGAuYCBhbmQgYF9gIGJ1dCBjYW7igJl0IGJlZ2luIHdpdGggYF9gIG9yIGEgZGlnaXQuIEFkZGl0aW9uYWxseSwgeW91IGNhbuKAmXQgdXNlIGFueSBvZiB0aGUgcmVzZXJ2ZWQgd29yZHMgbGlrZSBgVFJVRWAsIGBOVUxMYCwgaWYsIGFuZCBmdW5jdGlvbiAoc2VlIHRoZSBjb21wbGV0ZSBsaXN0IGluIGA/UmVzZXJ2ZWRgKS4gQSBuYW1lIHRoYXQgZG9lc27igJl0IGZvbGxvdyB0aGVzZSBydWxlcyBpcyBhICoqbm9uLXN5bnRhY3RpYyoqIG5hbWU7IGlmIHlvdSB0cnkgdG8gdXNlIHRoZW0sIHlvdeKAmWxsIGdldCBhbiBlcnJvci4gDQoNCldoZW4gc2VsZWN0aW5nIHZhcmlhYmxlcyBmcm9tIGEgZGF0YSBmcmFtZSwgdGlkeXZlcnNlIGZ1bmN0aW9ucyB3aWxsIGludGVycHJldCBudW1iZXJzLCBsaWtlIGAxOTk5YCBhbmQgYDIwMDBgLCBhcyBjb2x1bW4gbnVtYmVycy4gSW4gdGhpcyBjYXNlLCBgcGl2b3RfbG9uZ2VyKClgIHRyaWVzIHRvIHNlbGVjdCAxOTk5dGggYW5kIDIwMDB0aCBjb2x1bW4gb2YgdGhlIGRhdGEgZnJhbWUuIFRvIHNlbGVjdCB0aGUgY29sdW1ucyBgMTk5OWAgYW5kIGAyMDAwYCwgeW91IGNhbiBlaXRoZXIgc3Vycm91bmQgdGhlaXIgbmFtZXMgaW4gYmFja3RpY2tzICggIGApIG9yIHByb3ZpZGUgdGhlbSBhcyBzdHJpbmdzLg0KDQpgYGB7cn0NCnRhYmxlNGEgJT4lIA0KICBwaXZvdF9sb25nZXIoYyhgMTk5OWAsIGAyMDAwYCksIG5hbWVzX3RvID0gInllYXIiLCB2YWx1ZXNfdG8gPSAiY2FzZXMiKQ0KdGFibGU0YSAlPiUgDQogIHBpdm90X2xvbmdlcihjKCIxOTk5IiwgIjIwMDAiKSwgbmFtZXNfdG8gPSAieWVhciIsIHZhbHVlc190byA9ICJjYXNlcyIpDQpgYGANCg0KDQojIyMgMy5XaGF0IHdvdWxkIGhhcHBlbiBpZiB5b3Ugd2lkZW4gdGhpcyB0YWJsZT8gV2h5PyBIb3cgY291bGQgeW91IGFkZCBhIG5ldyBjb2x1bW4gdG8gdW5pcXVlbHkgaWRlbnRpZnkgZWFjaCB2YWx1ZT8NCg0KYGBge3J9DQpwZW9wbGUgPC0gdHJpYmJsZSgNCiAgfm5hbWUsICAgICAgICAgICAgIH5uYW1lcywgIH52YWx1ZXMsDQogICMtLS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLXwtLS0tLS0NCiAgIlBoaWxsaXAgV29vZHMiLCAgICJhZ2UiLCAgICAgICA0NSwNCiAgIlBoaWxsaXAgV29vZHMiLCAgICJoZWlnaHQiLCAgIDE4NiwNCiAgIlBoaWxsaXAgV29vZHMiLCAgICJhZ2UiLCAgICAgICA1MCwNCiAgIkplc3NpY2EgQ29yZGVybyIsICJhZ2UiLCAgICAgICAzNywNCiAgIkplc3NpY2EgQ29yZGVybyIsICJoZWlnaHQiLCAgIDE1Ng0KKQ0KDQpnbGltcHNlKHBlb3BsZSkNCg0KcGl2b3Rfd2lkZXIocGVvcGxlLCBuYW1lc19mcm9tID0gbmFtZXMsIHZhbHVlc19mcm9tID0gdmFsdWVzKQ0KYGBgDQoNCmBwaXZvdF93aWRlcigpYCB0aGlzIGRhdGEgZnJhbWUgZmFpbHMgYmVjYXVzZSB0aGUgbmFtZSBhbmQga2V5IGNvbHVtbnMgZG8gbm90IHVuaXF1ZWx5IGlkZW50aWZ5IHJvd3MuIEluIHBhcnRpY3VsYXIsIHRoZXJlIGFyZSB0d28gcm93cyB3aXRoIHZhbHVlcyBmb3IgdGhlIGFnZSBvZiDigJxQaGlsbGlwIFdvb2Rz4oCdLg0KDQpXZSBjb3VsZCBzb2x2ZSB0aGUgcHJvYmxlbSBieSBhZGRpbmcgYSByb3cgd2l0aCBhIGRpc3RpbmN0IG9ic2VydmF0aW9uIGNvdW50IGZvciBlYWNoIGNvbWJpbmF0aW9uIG9mIG5hbWUgYW5kIGtleS4NCg0KYGBge3J9DQpwZW9wbGUyIDwtIHBlb3BsZSAlPiUNCiAgZ3JvdXBfYnkobmFtZSwgbmFtZXMpICU+JQ0KICBtdXRhdGUob2JzID0gcm93X251bWJlcigpKQ0KcGVvcGxlMg0KYGBgDQoNCldlIGNhbiBgcGl2b3Rfd2lkZXIoKWAgYHBlb3BsZTJgIGJlY2F1c2UgdGhlIGNvbWJpbmF0aW9uIG9mIG5hbWUgYW5kIG9icyB3aWxsIHVuaXF1ZWx5IGlkZW50aWZ5IHRoZSBzcHJlYWQgcm93cy4NCg0KYGBge3J9DQpwaXZvdF93aWRlcihwZW9wbGUyLCBuYW1lc19mcm9tID0gbmFtZXMsIHZhbHVlc19mcm9tID0gdmFsdWVzKQ0KYGBgDQoNCkFub3RoZXIgd2F5IHRvIHNvbHZlIHRoaXMgcHJvYmxlbSBpcyBieSBrZWVwaW5nIG9ubHkgZGlzdGluY3Qgcm93cyBvZiB0aGUgbmFtZSBhbmQga2V5IHZhbHVlcywgYW5kIGRyb3BwaW5nIGR1cGxpY2F0ZSByb3dzLg0KDQpgYGB7cn0NCnBlb3BsZSAlPiUNCiAgZGlzdGluY3QobmFtZSwgbmFtZXMsIC5rZWVwX2FsbCA9IFRSVUUpICU+JQ0KICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gbmFtZXMsIHZhbHVlc19mcm9tID0gdmFsdWVzKQ0KYGBgDQoNCkhvd2V2ZXIsIGJlZm9yZSBkb2luZyB0aGlzIHlvdSB3b3VsZCB3YW50IHRvIHVuZGVyc3RhbmQgd2h5IHRoZXJlIGFyZSBkdXBsaWNhdGVzIGluIHRoZSBkYXRhIHRvIGJlZ2luIHdpdGguIFRoaXMgaXMgdXN1YWxseSBub3QgbWVyZWx5IGEgbnVpc2FuY2UsIGJ1dCBpbmRpY2F0ZXMgZGVlcGVyIHByb2JsZW1zIHdpdGggdGhlIGRhdGEuDQoNCiMjIyA0LiBUaWR5IHRoZSBzaW1wbGUgdGliYmxlIGJlbG93LiBEbyB5b3UgbmVlZCB0byBtYWtlIGl0IHdpZGVyIG9yIGxvbmdlcj8gV2hhdCBhcmUgdGhlIHZhcmlhYmxlcz8NCg0KYGBge3J9DQpwcmVnIDwtIHRyaWJibGUoDQogIH5wcmVnbmFudCwgfm1hbGUsIH5mZW1hbGUsDQogICJ5ZXMiLCAgICAgTkEsICAgIDEwLA0KICAibm8iLCAgICAgIDIwLCAgICAxMg0KKQ0KYGBgDQoNClRvIHRpZHkgdGhlIGBwcmVnYCB0aWJibGUsIHdlIG5lZWQgdG8gdXNlIGBwaXZvdF9sb25nZXIoKWAuIFRoZSB2YXJpYWJsZXMgaW4gdGhpcyBkYXRhIGFyZToNCg0KIC0gYHNleGAgKOKAnGZlbWFsZeKAnSwg4oCcbWFsZeKAnSkNCiAtIGBwcmVnbmFudGAgKOKAnHllc+KAnSwg4oCcbm/igJ0pDQogLSBgY291bnRgLCB3aGljaCBpcyBhIG5vbi1uZWdhdGl2ZSBpbnRlZ2VyIHJlcHJlc2VudGluZyB0aGUgbnVtYmVyIG9mIG9ic2VydmF0aW9ucy4NCg0KVGhlIG9ic2VydmF0aW9ucyBpbiB0aGlzIGRhdGEgYXJlIHVuaXF1ZSBjb21iaW5hdGlvbnMgb2Ygc2V4IGFuZCBwcmVnbmFuY3kgc3RhdHVzLg0KDQpgYGB7cn0NCnByZWdfdGlkeSA8LSBwcmVnICU+JQ0KICAjZ2F0aGVyKG1hbGUsIGZlbWFsZSwga2V5ID0gInNleCIsIHZhbHVlID0gImNvdW50IikNCiAgcGl2b3RfbG9uZ2VyKGMobWFsZSwgZmVtYWxlKSwgbmFtZXNfdG8gPSAic2V4IiwgdmFsdWVzX3RvID0gImNvdW50IikNCnByZWdfdGlkeQ0KYGBgDQoNCldlIGNhbiBzaW1wbGlmeSB0aGUgdGlkaWVkIGRhdGEgZnJhbWUgYnkgcmVtb3ZpbmcgdGhlIChtYWxlLCBwcmVnbmFudCkgcm93IHdpdGggdGhlIG1pc3NpbmcgdmFsdWUgb2YgYE5BYC4NCg0KYGBge3J9DQpwcmVnX3RpZHkyIDwtIHByZWcgJT4lDQogIHBpdm90X2xvbmdlcihjKG1hbGUsIGZlbWFsZSksIG5hbWVzX3RvID0gInNleCIsIHZhbHVlc190byA9ICJjb3VudCIsIHZhbHVlc19kcm9wX25hPVRSVUUpDQpwcmVnX3RpZHkyDQpgYGANCg0KVGhpcyBhbiBleGFtcGxlIG9mIHR1cm5pbmcgYW4gZXhwbGljaXQgbWlzc2luZyB2YWx1ZSBpbnRvIGFuIGltcGxpY2l0IG1pc3NpbmcgdmFsdWUsIHdoaWNoIGlzIGRpc2N1c3NlZCBpbiB0aGUgdXBjb21pbmcgTWlzc2luZyBWYWx1ZXMgc2VjdGlvbi4gVGhlIG1pc3NpbmcgKG1hbGUsIHByZWduYW50KSByb3cgcmVwcmVzZW50cyBhbiBpbXBsaWNpdCBtaXNzaW5nIHZhbHVlIGJlY2F1c2UgdGhlIHZhbHVlIG9mIGBjb3VudGAgY2FuIGJlIGluZmVycmVkIGZyb20gaXRzIGFic2VuY2UuIEluIHRoZSB0aWR5IGRhdGEsIHdlIGNhbiByZXByZXNlbnQgcm93cyB3aXRoIG1pc3NpbmcgdmFsdWVzIG9mIGBjb3VudGAgZWl0aGVyIGV4cGxpY2l0bHkgd2l0aCBhbiBgTkFgIChhcyBpbiBgcHJlZ190aWR5YCkgb3IgaW1wbGljaXRseSBieSB0aGUgYWJzZW5jZSBvZiBhIHJvdyAoYXMgaW4gYHByZWdfdGlkeTJgKS4gQnV0IGluIHRoZSB3aWRlIGRhdGEsIHRoZSBtaXNzaW5nIHZhbHVlcyBjYW4gb25seSBiZSByZXByZXNlbnRlZCBleHBsaWNpdGx5Lg0KDQpUaG91Z2ggd2UgaGF2ZSBhbHJlYWR5IGRvbmUgZW5vdWdoIHRvIG1ha2UgdGhlIGRhdGEgdGlkeSwgdGhlcmXigJlzIHNvbWUgb3RoZXIgY2hhbmdlcyB0aGF0IGNhbiBiZSBtYWRlIHRvIGNsZWFuIHRoaXMgZGF0YS4gSWYgYSB2YXJpYWJsZSB0YWtlcyB0d28gdmFsdWVzLCBsaWtlIGBwcmVnbmFudGAgYW5kIGBzZXhgLCBpdCBpcyBvZnRlbiBwcmVmZXJhYmxlIHRvIHN0b3JlIHRoZW0gYXMgbG9naWNhbCB2ZWN0b3JzLg0KDQpgYGB7cn0NCnByZWdfdGlkeTMgPC0gcHJlZ190aWR5MiAlPiUNCiAgbXV0YXRlKA0KICAgIGZlbWFsZSA9IHNleCA9PSAiZmVtYWxlIiwNCiAgICBwcmVnbmFudCA9IHByZWduYW50ID09ICJ5ZXMiDQogICkgJT4lDQogIHNlbGVjdChmZW1hbGUsIHByZWduYW50LCBjb3VudCkNCnByZWdfdGlkeTMNCmBgYA0KDQpJbiB0aGUgcHJldmlvdXMgZGF0YSBmcmFtZSwgSSBuYW1lZCB0aGUgbG9naWNhbCB2YXJpYWJsZSByZXByZXNlbnRpbmcgdGhlIHNleCBgZmVtYWxlYCwgbm90IGBzZXhgLiBUaGlzIG1ha2VzIHRoZSBtZWFuaW5nIG9mIHRoZSB2YXJpYWJsZSBzZWxmLWRvY3VtZW50aW5nLiBJZiB0aGUgdmFyaWFibGUgd2VyZSBuYW1lZCBgc2V4YCB3aXRoIHZhbHVlcyBgVFJVRWAgYW5kIGBGQUxTRWAsIHdpdGhvdXQgcmVhZGluZyB0aGUgZG9jdW1lbnRhdGlvbiwgd2Ugd291bGRu4oCZdCBrbm93IHdoZXRoZXIgYFRSVUVgIG1lYW5zIG1hbGUgb3IgZmVtYWxlLg0KDQpBcGFydCBmcm9tIHNvbWUgbWlub3IgbWVtb3J5IHNhdmluZ3MsIHJlcHJlc2VudGluZyB0aGVzZSB2YXJpYWJsZXMgYXMgbG9naWNhbCB2ZWN0b3JzIHJlc3VsdHMgaW4gbW9yZSBjbGVhciBhbmQgY29uY2lzZSBjb2RlLiBDb21wYXJlIHRoZSBgZmlsdGVyKClgIGNhbGxzIHRvIHNlbGVjdCBub24tcHJlZ25hbnQgZmVtYWxlcyBmcm9tIGBwcmVnX3RpZHkyYCBhbmQgYHByZWdfdGlkeWAuDQoNCmBgYHtyfQ0KZmlsdGVyKHByZWdfdGlkeTIsIHNleCA9PSAiZmVtYWxlIiwgcHJlZ25hbnQgPT0gIm5vIikNCmZpbHRlcihwcmVnX3RpZHkzLCBmZW1hbGUsICFwcmVnbmFudCkNCmBgYA0K