Tidy Data with tidyr
There are three interrelated rules which make a dataset tidy:
- Each variable must have its own column
- Each observation must have its own row
- Each value must have its own cell
This means you put each dataset in a tibble and puch each variable in a column
# only table is an example where each column is a variable
library(tidyverse)
table1
table2
table3
table4a
table4b
dplyr, ggplot2 and all the other package in the tidyverse are designed to work with tidy data. Here are some examples:
table1 %>%
mutate(rate=cases/population *10000)
# compute cased per year
table1 %>%
count(year, wt = cases)
# visualize changes over time
library(ggplot2)
ggplot(table1, aes(year, cases)) +
geom_line(aes(group=country), color = "grey50")+
geom_point(aes(color = country))

library(tidyverse)
View(table1)
View(table2)
View(table4a)
View(table4b)
Exercise: Compute the rate for table2
# table 2 extract the rate per country per year
tb2_cases <- filter(table2, type == "cases")[["count"]]
tb2_country <- filter(table2, type == "cases")[["country"]]
tb2_year <- filter(table2, type == "cases")[["year"]]
tb2_population <- filter(table2, type == "population")[["count"]]
table2_clean <- tibble(country = tb2_country,
year = tb2_year,
rate = tb2_cases / tb2_population)
table2_clean
Then compute the rate using the data from two tables table4a and table4b
tibble(country = table4a[["country"]],
'1999' = table4a[["1999"]] / table4b[["1999"]],
'2000' = table4a[["2000"]] / table4b[["2000"]]
)
Now plot using table2
library(ggplot2)
table2 %>%
filter(type == "cases") %>%
ggplot(aes(year, count)) +
geom_line(aes(group = country), color = "grey50") +
geom_point(aes(color = country))

Spreading and Gathering
There are two common issues with database. When one variable is spread across multiple columns. Or when one observation is scattered across multiple rows.
When some of the column names are not names of variables, but values of a variable. Take the table4a; the column names 1999 and 2000 represet values of the YEAR valirable and each row represents two observations, not one.
To fix this, we need to ‘gather’ those columns into a new pair of variables. (transpose? )
You will need three paramaters: The set of columns that represent values, not variables, in table4a, tose are the columns 1999 and 2000 the name of the variable whose values form the column names. ( in this case “Year”) The name of the variable whose values are spread over the cells. Call this ‘value’ and here it’s the number of cases.
# example of gather function
table4a %>%
gather(`1999`,`2000`, key = "Year", value = "cases")
We can use gather to tidy4b as well
table4b %>%
gather(`1999`,`2000`, key = "year", value = "population")
To join the two tables (table4a and table4b)
tidy4a <- table4a %>%
gather(`1999`,`2000`, key = "Year", value = "cases")
tidy4b <- table4b %>%
gather(`1999`,`2000`, key = "Year", value = "population")
left_join(tidy4a, tidy4b)
Joining, by = c("country", "Year")
Spreading
Spreading is the opposite of gathering. YOu use it when an observation is scattered across multiple rows. for example, take table2. The observation for each year is spread into two rows. one for cases, and one for population. This time we will need only two parameters. One is the key column and in table2 its the TYPE column, the next column is the column that contains the values…the value column, here it’s [count]
spread(table2, key=type, value=count)
So gather() makes wide tables narrorwer and longer, while spread() makes long tables shorter and wider.
Separating and Pull
For table3, the rate column contains two values (case and population). We use separate() to pull these two values apart.
table3 %>%
separate(rate, into = c("cases", "population"), sep ="/")
In the above, you will notice that cases and population are “char” fields. Use convert=TRUE to have separate() convert it to better types
table3 %>%
separate(rate, into = c("cases", "population"), sep = "/", convert = TRUE)
Now its correctly separated as integer type.
You can also separate using positions by sep argument
table3 %>%
separate(year, into = c("century","year"), sep =2)
Unite
Check out unite() function that does the opposite thing. You use this if a single variable is spread across multiple columns. Sep -1 starts from the far right, Positive values start at 1 on the far left of the strings.
We can use unite() to rejoin century and year in the above example. That data is saved as tidyr:table5
table5 %>%
unite(new, century, year)
Notice the underscore? Let’s take it out with the sep=“” argument
table5 %>%
unite(new, century, year, sep="")
Exercise:
What do the extra and fill agruments do in separate()
tibble(x=c("a,b,c","d,e,f,g","h,i,j")) %>%
separate(x, c("one","two","three"))
Too many values at 1 locations: 2
tibble(x = c("a,b,c","d,e","f,g,i")) %>%
separate(x, c("one","two","three"))
Too few values at 1 locations: 2
Extra = drop
tibble(x=c("a,b,c","d,e,f,g","h,i,j")) %>%
separate(x, c("one","two","three"), extra ="drop")
Extra= merge
tibble(x = c("a,b,c","d,e,f,g","h,i,j")) %>%
separate(x, c("one","two","three"), extra = "merge")
Using fill =“right”
tibble(x = c("a,b,c","d,e","f,g,i")) %>%
separate(x, c("one","two","three"), fill = "right")
Using fill =“left”
tibble(x = c("a,b,c","d,e","f,g,i")) %>%
separate(x, c("one","two","three"), fill = "left")
Both unite() and separate() have a remove option. Why would we set it to FALSE?
tibble(x = c("a,b,c","d,e","f,g,i")) %>%
separate(x, c("one","two","three"), remove = FALSE)
Too few values at 1 locations: 2
Missing Values
A value can be missing in one of two ways: Explicitly, ie. flagged with NA, or Implicity,ie. simply not present in data.
stocks <- tibble(
year = c( 2005,2015,2015,2015,2016,2016,2016),
qtr = c(1,2,3,4,2,3,4),
return = c(1.88,0.59,.35, NA, 0.92, 0.17, 2.66)
)
stocks
One way that a dataset can make implicit values explicit.
stocks %>%
spread(year, return)
To turn explicit missing values implicit, use na.rm=TRUE
stocks %>%
spread(year, return) %>%
gather(year, return, `2015`:`2016`, na.rm=TRUE)
Complete() takes a set of coumns and fins all unique combinations. It then ensures the original dataset contains all those values, filing in explicit NAs where necessary.
stocks %>%
complete(year,qtr)
When a dataset has 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
)
treatment
You can use the fill() It takes a set of columns where you want missing values to be replaced by the most recent nonmissing values (sometimes called last observation carried forward)
treatment %>%
fill(person)
Case study: tidyr::who
who
who1 <- who %>%
gather(
new_sp_m014:newrel_f65, key = "key",
value="cases",
na.rm=TRUE
)
who1
We can get some hint of the structure of the values in the new key column by counting them:
who1 %>%
count(key)
To make the data consistent, we use str_replace()
who2 <- who1 %>%
mutate(key = stringr::str_replace(key, "newrel", "new_rel"))
who2
We can separate the values in each code with two passes of separet() The first pass will split the codes at ech underscore:
who3 <- who2 %>%
separate(key, c("new","type", "sexage"), sep="_")
who3
Then we might as well drop the new column because it’s constant in this dataset. While we’re dropping columns, let’s also drop iso2 and iso3 since they’r redundant:
who3 %>%
count(new)
who4 <- who3 %>%
select(-new, -iso2,-iso3)
who4
Next we separate sexage into sex and age by splitting after the first character
who5 <- who4 %>%
separate(sexage, c("Sex","Age"), sep = 1)
who5
Exercise: Confirm that country, iso2 and iso3 are redundant? My answer: i use count of country, iso2, iso3. If they are non unique, you should see other aggregations
who %>%
count(country, iso2, iso3)
Nontidy Data
There are two main reasons to use other data structures: alternative representations may have substantial perfromance or space advantages Specialized fields have evolved their own conventions for storing data that may be quite different to the conventions
LS0tDQp0aXRsZTogIlIgZm9yIERhdGEgU2NpZW5jZSBDaGFwdGVyIDkgVGlkeURhdGEiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQo8aDE+IFRpZHkgRGF0YSB3aXRoIHRpZHlyIDwvaDE+DQoNClRoZXJlIGFyZSB0aHJlZSBpbnRlcnJlbGF0ZWQgcnVsZXMgd2hpY2ggbWFrZSBhIGRhdGFzZXQgdGlkeTogPC9icj4NCg0KMS4gRWFjaCB2YXJpYWJsZSBtdXN0IGhhdmUgaXRzIG93biBjb2x1bW4gPC9icj4NCjIuIEVhY2ggb2JzZXJ2YXRpb24gbXVzdCBoYXZlIGl0cyBvd24gcm93IDwvYnI+DQozLiBFYWNoIHZhbHVlIG11c3QgaGF2ZSBpdHMgb3duIGNlbGwgPC9icj4NCg0KPGltZyBzcmM9Imh0dHA6Ly9yNGRzLmhhZC5jby5uei9pbWFnZXMvdGlkeS02LnBuZyIgPiA8L2ltZz4NCg0KVGhpcyBtZWFucyB5b3UgcHV0IGVhY2ggZGF0YXNldCBpbiBhIHRpYmJsZSBhbmQgcHVjaCBlYWNoIHZhcmlhYmxlIGluIGEgY29sdW1uIDwvcD4NCg0KYGBge3J9DQojIG9ubHkgdGFibGUgaXMgYW4gZXhhbXBsZSB3aGVyZSBlYWNoIGNvbHVtbiBpcyBhIHZhcmlhYmxlDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCnRhYmxlMQ0KdGFibGUyDQp0YWJsZTMNCnRhYmxlNGENCnRhYmxlNGINCg0KYGBgDQoNCmRwbHlyLCBnZ3Bsb3QyIGFuZCBhbGwgdGhlIG90aGVyIHBhY2thZ2UgaW4gdGhlIHRpZHl2ZXJzZSBhcmUgZGVzaWduZWQgdG8gd29yayB3aXRoIHRpZHkgZGF0YS4gSGVyZSBhcmUgc29tZSBleGFtcGxlczoNCg0KYGBge3J9DQojIGNvbXB1dGUgcmF0ZSBwZXIgMTAsMDAwDQp0YWJsZTEgJT4lIA0KICBtdXRhdGUocmF0ZSA9IGNhc2VzL3BvcHVsYXRpb24gKjEwMDAwKQ0KYGBgDQoNCmBgYHtyfQ0KIyBjb21wdXRlIGNhc2VkIHBlciB5ZWFyDQp0YWJsZTEgJT4lIA0KICBjb3VudCh5ZWFyLCB3dCA9IGNhc2VzKQ0KYGBgDQoNCg0KYGBge3J9DQojIHZpc3VhbGl6ZSBjaGFuZ2VzIG92ZXIgdGltZSANCmxpYnJhcnkoZ2dwbG90MikNCmdncGxvdCh0YWJsZTEsIGFlcyh5ZWFyLCBjYXNlcykpICsNCiAgZ2VvbV9saW5lKGFlcyhncm91cD1jb3VudHJ5KSwgY29sb3IgPSAiZ3JleTUwIikrDQogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gY291bnRyeSkpDQpgYGANCg0KDQoNCmBgYHtyfQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpWaWV3KHRhYmxlMSkNClZpZXcodGFibGUyKQ0KVmlldyh0YWJsZTRhKQ0KVmlldyh0YWJsZTRiKQ0KYGBgDQoNCkV4ZXJjaXNlOiBDb21wdXRlIHRoZSByYXRlIGZvciB0YWJsZTINCg0KYGBge3J9DQojIHRhYmxlIDIgZXh0cmFjdCB0aGUgcmF0ZSBwZXIgY291bnRyeSBwZXIgeWVhcg0KdGIyX2Nhc2VzIDwtIGZpbHRlcih0YWJsZTIsIHR5cGUgPT0gImNhc2VzIilbWyJjb3VudCJdXQ0KdGIyX2NvdW50cnkgPC0gZmlsdGVyKHRhYmxlMiwgdHlwZSA9PSAiY2FzZXMiKVtbImNvdW50cnkiXV0NCnRiMl95ZWFyIDwtIGZpbHRlcih0YWJsZTIsIHR5cGUgPT0gImNhc2VzIilbWyJ5ZWFyIl1dDQp0YjJfcG9wdWxhdGlvbiA8LSBmaWx0ZXIodGFibGUyLCB0eXBlID09ICJwb3B1bGF0aW9uIilbWyJjb3VudCJdXQ0KdGFibGUyX2NsZWFuIDwtIHRpYmJsZShjb3VudHJ5ID0gdGIyX2NvdW50cnksDQogICAgICAgeWVhciA9IHRiMl95ZWFyLA0KICAgICAgIHJhdGUgPSB0YjJfY2FzZXMgLyB0YjJfcG9wdWxhdGlvbikNCnRhYmxlMl9jbGVhbg0KDQpgYGANCg0KDQpUaGVuIGNvbXB1dGUgdGhlIHJhdGUgdXNpbmcgdGhlIGRhdGEgZnJvbSAgdHdvIHRhYmxlcyB0YWJsZTRhIGFuZCB0YWJsZTRiDQoNCmBgYHtyfQ0KdGliYmxlKGNvdW50cnkgPSB0YWJsZTRhW1siY291bnRyeSJdXSwNCiAgICAgICAnMTk5OScgPSB0YWJsZTRhW1siMTk5OSJdXSAvIHRhYmxlNGJbWyIxOTk5Il1dLA0KICAgICAgICcyMDAwJyA9IHRhYmxlNGFbWyIyMDAwIl1dIC8gdGFibGU0YltbIjIwMDAiXV0NCikNCmBgYA0KDQpOb3cgcGxvdCB1c2luZyB0YWJsZTIgDQoNCmBgYHtyfQ0KbGlicmFyeShnZ3Bsb3QyKQ0KdGFibGUyICU+JQ0KICBmaWx0ZXIodHlwZSA9PSAiY2FzZXMiKSAlPiUNCiAgDQpnZ3Bsb3QoYWVzKHllYXIsIGNvdW50KSkgKw0KICBnZW9tX2xpbmUoYWVzKGdyb3VwID0gY291bnRyeSksIGNvbG9yID0gImdyZXk1MCIpICsNCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBjb3VudHJ5KSkNCg0KYGBgDQoNCg0KDQoNCjxoMj4gU3ByZWFkaW5nIGFuZCBHYXRoZXJpbmcgPC9oMj4NCg0KVGhlcmUgYXJlIHR3byBjb21tb24gaXNzdWVzIHdpdGggZGF0YWJhc2UuIFdoZW4gb25lIHZhcmlhYmxlIGlzIHNwcmVhZCBhY3Jvc3MgbXVsdGlwbGUgY29sdW1ucy4gT3Igd2hlbiBvbmUgb2JzZXJ2YXRpb24gaXMgc2NhdHRlcmVkIGFjcm9zcyBtdWx0aXBsZSByb3dzLiAgPC9wPg0KDQpXaGVuIHNvbWUgb2YgdGhlIGNvbHVtbiBuYW1lcyBhcmUgbm90IG5hbWVzIG9mIHZhcmlhYmxlcywgYnV0IHZhbHVlcyBvZiBhIHZhcmlhYmxlLiBUYWtlIHRoZSB0YWJsZTRhOyB0aGUgY29sdW1uIG5hbWVzIDE5OTkgYW5kIDIwMDAgcmVwcmVzZXQgdmFsdWVzIG9mIHRoZSBZRUFSIHZhbGlyYWJsZSBhbmQgZWFjaCByb3cgcmVwcmVzZW50cyB0d28gb2JzZXJ2YXRpb25zLCBub3Qgb25lLiA8L2JyPg0KDQoNClRvIGZpeCB0aGlzLCB3ZSBuZWVkIHRvICdnYXRoZXInIHRob3NlIGNvbHVtbnMgaW50byBhIG5ldyBwYWlyIG9mIHZhcmlhYmxlcy4gKHRyYW5zcG9zZT8gKSA8L2JyPg0KPGltZyBzcmMgPSJodHRwOi8vZ2FycmV0dGdtYW4uZ2l0aHViLmlvL2ltYWdlcy90aWR5LTkucG5nIiA+IDwvaW1nPg0KDQpZb3Ugd2lsbCBuZWVkIHRocmVlIHBhcmFtYXRlcnM6IDwvYnI+DQpUaGUgc2V0IG9mIGNvbHVtbnMgdGhhdCByZXByZXNlbnQgdmFsdWVzLCBub3QgdmFyaWFibGVzLCBpbiB0YWJsZTRhLCB0b3NlIGFyZSB0aGUgY29sdW1ucyAxOTk5IGFuZCAyMDAwIDwvYnI+DQp0aGUgbmFtZSBvZiB0aGUgdmFyaWFibGUgd2hvc2UgdmFsdWVzIGZvcm0gdGhlIGNvbHVtbiBuYW1lcy4gKCBpbiB0aGlzIGNhc2UgIlllYXIiKTwvYnI+DQpUaGUgbmFtZSBvZiB0aGUgdmFyaWFibGUgd2hvc2UgdmFsdWVzIGFyZSBzcHJlYWQgb3ZlciB0aGUgY2VsbHMuIENhbGwgdGhpcyAndmFsdWUnIGFuZCBoZXJlIGl0J3MgdGhlIG51bWJlciBvZiBjYXNlcy4gPC9wPg0KDQpgYGB7cn0NCiMgZXhhbXBsZSBvZiBnYXRoZXIgZnVuY3Rpb24NCiMgbm90ZSB0aGUgdXNlIGAgYmFja3RpY2tzIGFuZCBub3QgJw0KdGFibGU0YSAlPiUNCiAgZ2F0aGVyKGAxOTk5YCxgMjAwMGAsIGtleSA9ICJZZWFyIiwgdmFsdWUgPSAiY2FzZXMiKQ0KYGBgDQoNCldlIGNhbiB1c2UgZ2F0aGVyIHRvIHRpZHk0YiBhcyB3ZWxsIA0KDQpgYGB7cn0NCnRhYmxlNGIgJT4lDQogIGdhdGhlcihgMTk5OWAsYDIwMDBgLCBrZXkgPSAieWVhciIsIHZhbHVlID0gInBvcHVsYXRpb24iKQ0KYGBgDQoNClRvIGpvaW4gdGhlIHR3byB0YWJsZXMgKHRhYmxlNGEgYW5kIHRhYmxlNGIpDQoNCmBgYHtyfQ0KdGlkeTRhIDwtICB0YWJsZTRhICU+JQ0KICBnYXRoZXIoYDE5OTlgLGAyMDAwYCwga2V5ID0gIlllYXIiLCB2YWx1ZSA9ICJjYXNlcyIpDQp0aWR5NGIgPC0gdGFibGU0YiAlPiUNCiAgZ2F0aGVyKGAxOTk5YCxgMjAwMGAsIGtleSA9ICJZZWFyIiwgdmFsdWUgPSAicG9wdWxhdGlvbiIpDQpsZWZ0X2pvaW4odGlkeTRhLCB0aWR5NGIpDQoNCmBgYA0KDQoNCg0KPGgyPiBTcHJlYWRpbmcgPC9oMj4NClNwcmVhZGluZyBpcyB0aGUgb3Bwb3NpdGUgb2YgZ2F0aGVyaW5nLiBZT3UgdXNlIGl0IHdoZW4gYW4gb2JzZXJ2YXRpb24gaXMgc2NhdHRlcmVkIGFjcm9zcyBtdWx0aXBsZSByb3dzLiBmb3IgZXhhbXBsZSwgdGFrZSB0YWJsZTIuIFRoZSBvYnNlcnZhdGlvbiBmb3IgZWFjaCB5ZWFyIGlzIHNwcmVhZCBpbnRvIHR3byByb3dzLiBvbmUgZm9yIGNhc2VzLCBhbmQgb25lIGZvciBwb3B1bGF0aW9uLiANClRoaXMgdGltZSB3ZSB3aWxsIG5lZWQgb25seSB0d28gcGFyYW1ldGVycy4gT25lIGlzIHRoZSBrZXkgY29sdW1uIGFuZCBpbiB0YWJsZTIgaXRzIHRoZSBUWVBFIGNvbHVtbiwgdGhlIG5leHQgY29sdW1uIGlzIHRoZSBjb2x1bW4gdGhhdCBjb250YWlucyB0aGUgdmFsdWVzLi4udGhlIHZhbHVlIGNvbHVtbiwgaGVyZSBpdCdzIFtjb3VudF0NCg0KPGltZyBzcmM9Imh0dHA6Ly9yNGRzLmhhZC5jby5uei9pbWFnZXMvdGlkeS04LnBuZyIgPiA8L2ltZz4NCg0KDQpgYGB7cn0NCnNwcmVhZCh0YWJsZTIsIGtleSA9IHR5cGUsIHZhbHVlID0gY291bnQpDQpgYGANCg0KDQpTbyBnYXRoZXIoKSBtYWtlcyB3aWRlIHRhYmxlcyBuYXJyb3J3ZXIgYW5kIGxvbmdlciwgd2hpbGUgc3ByZWFkKCkgbWFrZXMgbG9uZyB0YWJsZXMgc2hvcnRlciBhbmQgd2lkZXIuDQo8L3A+DQoNCjxoMj4gU2VwYXJhdGluZyBhbmQgUHVsbCA8L2gyPg0KDQpGb3IgdGFibGUzLCB0aGUgcmF0ZSBjb2x1bW4gY29udGFpbnMgdHdvIHZhbHVlcyAoY2FzZSBhbmQgcG9wdWxhdGlvbikuIFdlIHVzZSBzZXBhcmF0ZSgpIHRvIHB1bGwgdGhlc2UgdHdvIHZhbHVlcyBhcGFydC4gDQoNCjxpbWcgc3JjPSJodHRwOi8vcjRkcy5oYWQuY28ubnovaW1hZ2VzL3RpZHktMTcucG5nIiA+IDwvaW1nPg0KDQpgYGB7cn0NCnRhYmxlMyAlPiUNCiAgc2VwYXJhdGUocmF0ZSwgaW50byA9IGMoImNhc2VzIiwgInBvcHVsYXRpb24iKSwgc2VwID0iLyIpDQpgYGANCkluIHRoZSBhYm92ZSwgeW91IHdpbGwgbm90aWNlIHRoYXQgY2FzZXMgYW5kIHBvcHVsYXRpb24gYXJlICJjaGFyIiBmaWVsZHMuIFVzZSBjb252ZXJ0PVRSVUUgdG8gaGF2ZSBzZXBhcmF0ZSgpIGNvbnZlcnQgaXQgdG8gYmV0dGVyIHR5cGVzIA0KDQpgYGB7cn0NCnRhYmxlMyAlPiUNCiAgc2VwYXJhdGUocmF0ZSwgaW50byA9IGMoImNhc2VzIiwgInBvcHVsYXRpb24iKSwgc2VwID0gIi8iLCBjb252ZXJ0ID0gVFJVRSkNCmBgYA0KDQpOb3cgaXRzIGNvcnJlY3RseSBzZXBhcmF0ZWQgYXMgaW50ZWdlciB0eXBlLiA8L3A+DQoNCllvdSBjYW4gYWxzbyBzZXBhcmF0ZSB1c2luZyBwb3NpdGlvbnMgYnkgc2VwIGFyZ3VtZW50DQoNCmBgYHtyfQ0KdGFibGUzICU+JQ0KICBzZXBhcmF0ZSh5ZWFyLCBpbnRvID0gYygiY2VudHVyeSIsInllYXIiKSwgc2VwID0yKQ0KYGBgDQoNCg0KPGgyPiBVbml0ZSA8L2gyPg0KDQpDaGVjayBvdXQgdW5pdGUoKSBmdW5jdGlvbiB0aGF0IGRvZXMgdGhlIG9wcG9zaXRlIHRoaW5nLiBZb3UgdXNlIHRoaXMgaWYgYSBzaW5nbGUgdmFyaWFibGUgaXMgc3ByZWFkIGFjcm9zcyBtdWx0aXBsZSBjb2x1bW5zLiBTZXAgLTEgc3RhcnRzIGZyb20gdGhlIGZhciByaWdodCwgUG9zaXRpdmUgdmFsdWVzIHN0YXJ0IGF0IDEgb24gdGhlIGZhciBsZWZ0IG9mIHRoZSBzdHJpbmdzLg0KDQpXZSBjYW4gdXNlIHVuaXRlKCkgdG8gcmVqb2luIGNlbnR1cnkgYW5kIHllYXIgaW4gdGhlIGFib3ZlIGV4YW1wbGUuICBUaGF0IGRhdGEgaXMgc2F2ZWQgYXMgdGlkeXI6dGFibGU1DQo8aW1nIHNyYz0iaHR0cDovL3I0ZHMuaGFkLmNvLm56L2ltYWdlcy90aWR5LTE4LnBuZyI+IDwvaW1nPg0KDQoNCmBgYHtyfQ0KdGFibGU1ICU+JQ0KICB1bml0ZShuZXcsIGNlbnR1cnksIHllYXIpDQpgYGANCg0KDQpOb3RpY2UgdGhlIHVuZGVyc2NvcmU/IExldCdzIHRha2UgaXQgb3V0IHdpdGggdGhlIHNlcD0iIiBhcmd1bWVudA0KDQpgYGB7cn0NCnRhYmxlNSAlPiUNCiAgdW5pdGUobmV3LCBjZW50dXJ5LCB5ZWFyLCBzZXA9IiIpDQpgYGANCg0KDQpFeGVyY2lzZTogPC9wPg0KDQoNCldoYXQgZG8gdGhlIGV4dHJhIGFuZCBmaWxsIGFncnVtZW50cyBkbyBpbiBzZXBhcmF0ZSgpDQpgYGB7cn0NCnRpYmJsZSh4PWMoImEsYixjIiwiZCxlLGYsZyIsImgsaSxqIikpICU+JQ0KICBzZXBhcmF0ZSh4LCBjKCJvbmUiLCJ0d28iLCJ0aHJlZSIpKQ0KYGBgDQoNCmBgYHtyfQ0KdGliYmxlKHggPSBjKCJhLGIsYyIsImQsZSIsImYsZyxpIikpICU+JQ0KICBzZXBhcmF0ZSh4LCBjKCJvbmUiLCJ0d28iLCJ0aHJlZSIpKQ0KYGBgDQoNCg0KDQpFeHRyYSA9IGRyb3ANCmBgYHtyfQ0KdGliYmxlKHggPSBjKCJhLGIsYyIsImQsZSxmLGciLCJoLGksaiIpKSAlPiUNCiAgc2VwYXJhdGUoeCwgYygib25lIiwidHdvIiwidGhyZWUiKSwgZXh0cmEgPSAiZHJvcCIpDQpgYGANCkV4dHJhPSBtZXJnZQ0KDQpgYGB7cn0NCnRpYmJsZSh4ID0gYygiYSxiLGMiLCJkLGUsZixnIiwiaCxpLGoiKSkgJT4lDQogIHNlcGFyYXRlKHgsIGMoIm9uZSIsInR3byIsInRocmVlIiksIGV4dHJhID0gIm1lcmdlIikNCmBgYA0KDQoNClVzaW5nIGZpbGwgPSJyaWdodCINCg0KYGBge3J9DQp0aWJibGUoeCA9IGMoImEsYixjIiwiZCxlIiwiZixnLGkiKSkgJT4lDQogIHNlcGFyYXRlKHgsIGMoIm9uZSIsInR3byIsInRocmVlIiksIGZpbGwgPSAicmlnaHQiKQ0KYGBgDQoNClVzaW5nIGZpbGwgPSJsZWZ0Ig0KDQpgYGB7cn0NCnRpYmJsZSh4ID0gYygiYSxiLGMiLCJkLGUiLCJmLGcsaSIpKSAlPiUNCiAgc2VwYXJhdGUoeCwgYygib25lIiwidHdvIiwidGhyZWUiKSwgZmlsbCA9ICJsZWZ0IikNCmBgYA0KDQoNCkJvdGggdW5pdGUoKSBhbmQgc2VwYXJhdGUoKSBoYXZlIGEgcmVtb3ZlIG9wdGlvbi4gV2h5IHdvdWxkIHdlIHNldCBpdCB0byBGQUxTRT8NCg0KDQpgYGB7cn0NCnRpYmJsZSh4ID0gYygiYSxiLGMiLCJkLGUiLCJmLGcsaSIpKSAlPiUNCiAgc2VwYXJhdGUoeCwgYygib25lIiwidHdvIiwidGhyZWUiKSwgcmVtb3ZlID0gRkFMU0UpDQpgYGANCg0KDQo8aDI+IE1pc3NpbmcgVmFsdWVzIDwvaDI+DQoNCkEgdmFsdWUgY2FuIGJlIG1pc3NpbmcgaW4gb25lIG9mIHR3byB3YXlzOiBFeHBsaWNpdGx5LCBpZS4gZmxhZ2dlZCB3aXRoIE5BLCBvciBJbXBsaWNpdHksaWUuIHNpbXBseSBub3QgcHJlc2VudCBpbiBkYXRhLiA8L3A+DQoNCmBgYHtyfQ0Kc3RvY2tzIDwtICB0aWJibGUoDQogIHllYXIgPSBjKCAyMDA1LDIwMTUsMjAxNSwyMDE1LDIwMTYsMjAxNiwyMDE2KSwNCiAgcXRyID0gYygxLDIsMyw0LDIsMyw0KSwNCiAgcmV0dXJuID0gYygxLjg4LDAuNTksLjM1LCBOQSwgMC45MiwgMC4xNywgMi42NikNCiAgDQopDQoNCnN0b2Nrcw0KYGBgDQoNCk9uZSB3YXkgdGhhdCBhIGRhdGFzZXQgY2FuIG1ha2UgaW1wbGljaXQgdmFsdWVzIGV4cGxpY2l0LiANCg0KYGBge3J9DQpzdG9ja3MgJT4lDQogIHNwcmVhZCh5ZWFyLCByZXR1cm4pDQoNCmBgYA0KDQoNClRvIHR1cm4gZXhwbGljaXQgbWlzc2luZyB2YWx1ZXMgaW1wbGljaXQsIHVzZSBuYS5ybT1UUlVFDQoNCmBgYHtyfQ0Kc3RvY2tzICU+JQ0KICBzcHJlYWQoeWVhciwgcmV0dXJuKSAlPiUNCiAgZ2F0aGVyKHllYXIsIHJldHVybiwgYDIwMTVgOmAyMDE2YCwgbmEucm09VFJVRSkNCg0KYGBgDQoNCg0KDQpDb21wbGV0ZSgpIHRha2VzIGEgc2V0IG9mIGNvdW1ucyBhbmQgZmlucyBhbGwgdW5pcXVlIGNvbWJpbmF0aW9ucy4gSXQgdGhlbiBlbnN1cmVzIHRoZSBvcmlnaW5hbCBkYXRhc2V0IGNvbnRhaW5zIGFsbCB0aG9zZSB2YWx1ZXMsIGZpbGluZyBpbiBleHBsaWNpdCBOQXMgd2hlcmUgbmVjZXNzYXJ5Lg0KDQpgYGB7cn0NCnN0b2NrcyAlPiUgDQogIGNvbXBsZXRlKHllYXIscXRyKQ0KYGBgDQoNCg0KDQpXaGVuIGEgZGF0YXNldCBoYXMgYmVlbiB1c2VkIGZvciBkYXRhIGVudHJ5LCBtaXNzaW5nIHZhbHVlcyBpbmRpY2F0ZSB0aGF0IHRoZSBwcmV2aW91cyB2YWx1ZSBzaG91bGQgYmUgY2FycmllZCBmb3J3YXJkOg0KDQoNCmBgYHtyfQ0KdHJlYXRtZW50IDwtIHRyaWJibGUoDQogIH4gcGVyc29uLCB+dHJlYXRtZW50LCB+cmVzcG9uc2UsIA0KICAiRGVycmljayBXaGl0bW9yZSIsMSw3LA0KICBOQSwyLDEwLA0KICBOQSwzLDksDQogICJLYXRoZXJpbmUgQnVya2UiLDEsNA0KKQ0KDQp0cmVhdG1lbnQNCg0KYGBgDQoNCllvdSBjYW4gdXNlIHRoZSBmaWxsKCkgSXQgdGFrZXMgYSBzZXQgb2YgY29sdW1ucyB3aGVyZSB5b3Ugd2FudCBtaXNzaW5nIHZhbHVlcyB0byBiZSByZXBsYWNlZCBieSB0aGUgbW9zdCByZWNlbnQgbm9ubWlzc2luZyB2YWx1ZXMgKHNvbWV0aW1lcyBjYWxsZWQgbGFzdCBvYnNlcnZhdGlvbiBjYXJyaWVkIGZvcndhcmQpDQoNCmBgYHtyfQ0KdHJlYXRtZW50ICU+JQ0KICBmaWxsKHBlcnNvbikNCmBgYA0KDQoNCkNhc2Ugc3R1ZHk6IHRpZHlyOjp3aG8NCg0KYGBge3J9DQp3aG8NCg0KYGBgDQoNCg0KYGBge3J9DQp3aG8xIDwtICB3aG8gJT4lDQogIGdhdGhlcigNCiAgICBuZXdfc3BfbTAxNDpuZXdyZWxfZjY1LCBrZXkgPSAia2V5IiwNCiAgICB2YWx1ZSA9ICJjYXNlcyIsDQogICAgbmEucm0gPSBUUlVFDQogICkNCg0Kd2hvMQ0KYGBgDQoNCldlIGNhbiBnZXQgc29tZSBoaW50IG9mIHRoZSBzdHJ1Y3R1cmUgb2YgdGhlIHZhbHVlcyBpbiB0aGUgbmV3IGtleSBjb2x1bW4gYnkgY291bnRpbmcgdGhlbToNCg0KDQpgYGB7cn0NCndobzEgJT4lDQogIGNvdW50KGtleSkNCmBgYA0KDQoNCg0KVG8gbWFrZSB0aGUgZGF0YSBjb25zaXN0ZW50LCB3ZSB1c2Ugc3RyX3JlcGxhY2UoKSANCg0KYGBge3J9DQp3aG8yIDwtICB3aG8xICU+JQ0KICBtdXRhdGUoa2V5ID0gc3RyaW5ncjo6c3RyX3JlcGxhY2Uoa2V5LCAibmV3cmVsIiwgIm5ld19yZWwiKSkNCndobzINCmBgYA0KDQoNCldlIGNhbiBzZXBhcmF0ZSB0aGUgdmFsdWVzIGluIGVhY2ggY29kZSB3aXRoIHR3byBwYXNzZXMgb2Ygc2VwYXJldCgpIFRoZSBmaXJzdCBwYXNzIHdpbGwgc3BsaXQgdGhlIGNvZGVzIGF0IGVjaCB1bmRlcnNjb3JlOg0KDQpgYGB7cn0NCndobzMgPC0gIHdobzIgJT4lDQogIHNlcGFyYXRlKGtleSwgYygibmV3IiwidHlwZSIsICJzZXhhZ2UiKSwgc2VwPSJfIikNCndobzMNCg0KYGBgDQoNClRoZW4gd2UgbWlnaHQgYXMgd2VsbCBkcm9wIHRoZSBuZXcgY29sdW1uIGJlY2F1c2UgaXQncyBjb25zdGFudCBpbiB0aGlzIGRhdGFzZXQuIFdoaWxlIHdlJ3JlIGRyb3BwaW5nIGNvbHVtbnMsIGxldCdzIGFsc28gZHJvcCBpc28yIGFuZCBpc28zIHNpbmNlIHRoZXknciByZWR1bmRhbnQ6DQoNCmBgYHtyfQ0KIHdobzMgJT4lDQogIGNvdW50KG5ldykNCndobzQgPC0gd2hvMyAlPiUNCiAgc2VsZWN0KC1uZXcsIC1pc28yLC1pc28zKQ0Kd2hvNA0KDQpgYGANCg0KDQoNCk5leHQgd2Ugc2VwYXJhdGUgc2V4YWdlIGludG8gc2V4IGFuZCBhZ2UgYnkgc3BsaXR0aW5nIGFmdGVyIHRoZSBmaXJzdCBjaGFyYWN0ZXINCg0KYGBge3J9DQp3aG81IDwtIHdobzQgICU+JQ0KICBzZXBhcmF0ZShzZXhhZ2UsIGMoIlNleCIsIkFnZSIpLCBzZXAgPSAxKQ0Kd2hvNQ0KYGBgDQpFeGVyY2lzZTogQ29uZmlybSB0aGF0IGNvdW50cnksIGlzbzIgYW5kIGlzbzMgYXJlIHJlZHVuZGFudD8gPC9icj4NCk15IGFuc3dlcjogaSB1c2UgY291bnQgb2YgY291bnRyeSwgaXNvMiwgaXNvMy4gSWYgdGhleSBhcmUgbm9uIHVuaXF1ZSwgeW91IHNob3VsZCBzZWUgb3RoZXIgYWdncmVnYXRpb25zIA0KDQoNCmBgYHtyfQ0Kd2hvICU+JSANCiAgY291bnQoY291bnRyeSwgaXNvMiwgaXNvMykNCg0KYGBgDQoNCg0KDQo8aDI+IE5vbnRpZHkgRGF0YSA8L2gyPg0KVGhlcmUgYXJlIHR3byBtYWluIHJlYXNvbnMgdG8gdXNlIG90aGVyIGRhdGEgc3RydWN0dXJlczo8L2JyPg0KYWx0ZXJuYXRpdmUgcmVwcmVzZW50YXRpb25zIG1heSBoYXZlIHN1YnN0YW50aWFsIHBlcmZyb21hbmNlIG9yIHNwYWNlIGFkdmFudGFnZXMgPC9icj4NClNwZWNpYWxpemVkIGZpZWxkcyBoYXZlIGV2b2x2ZWQgdGhlaXIgb3duIGNvbnZlbnRpb25zIGZvciBzdG9yaW5nIGRhdGEgdGhhdCBtYXkgYmUgcXVpdGUgZGlmZmVyZW50IHRvIHRoZSBjb252ZW50aW9ucyANCg==