1 Introduction

When data in is wide format, a subjects responses will be in a single row, and each response is in separate columns. However R prefers long format. We could melt and cast with reshape2 to reshape from wide to long format, but is there a way to reshape using even less code? Luckily for us, Hadley Wickham has created the easy to use tidyr!

tidyr allow us to quickly and easily tidy and reorganize our data for all sorts of analyses. This is particularly helpful with a disorganized dataset. tidyr is built for this function. Specifically, tidyr can only be used with exisiting dataframes, and cannot aggregate.

In this chapter, we will go over the hallmark functions of tidyr: gather(), separate(), unite(), and spread().

First let’s install and call up the tidyr package. We will also need to use the dplyr package.

#install.packages("tidyr") # I have used "#" to "comment out" this line for this tutorial. Just take away the first "#" and you are good to go!
#install.packages("dplyr")

library(tidyr)
library(dplyr)

1.1 %>%

Why do we need dplyr? dplyr is a grammar of data manipulation. We need dplyr to use the pipe operator, %>%, in our code. %>% is not required to use tidyr, but it does make things easier!

%>% allows you to pipe a value forward into an expression or to function call; such that x %>% f, instead of f(x). This short hand was created by Stefan Milton Bache with the magrittr package. To read more about this function, click here

1.2 The Dataframe

Here I have created a messy wide dataset. Feel free to use it to follow along!

In this example study, participants were asked to categorize three faces by clicking various buttons that represent three different categories. The time it took to click a button is in milliseconds.

n=10
wide <- data.frame(
  ID = c(1:n),
  Face.1 = c(411,723,325,456,579,612,709,513,527,379),
  Face.2 = c(123,300,400,500,600,654,789,906,413,567),
  Face.3 = c(1457,1000,569,896,956,2345,780,599,1023,678)
)

This dataset I created is messy; As you can see below, only ID is in a column, Response time split between three columns, such that responses are in both rows and columns (by ID and Face.1, Face.2, and Face.3).

What we want instead is one column for the condition (Face.1, Face.2, or Face.3) responses and a column for response time, with each row being a singular observation for each participant. Participant IDs should repeat as this is a within subject design (each participant saw each face).

##    ID Face.1 Face.2 Face.3
## 1   1    411    123   1457
## 2   2    723    300   1000
## 3   3    325    400    569
## 4   4    456    500    896
## 5   5    579    600    956
## 6   6    612    654   2345
## 7   7    709    789    780
## 8   8    513    906    599
## 9   9    527    413   1023
## 10 10    379    567    678

2 Gather()

By using the gather() function, we can transform the data from wide to long Here is the generic code for gather():

#gather(data, key, value, ..., na.rm = FALSE, convert = FALSE, factor_key = FALSE)

2.1 Gather() Arguments

Whoa! What does this all mean? Let’s find out more about the arguments of gather():

  • data: Your data frame.

  • key, value: The unquoted new names of key and value columns to create in the output. The key will become the name of the condition/IV column, and value will become the name of the response/DV column.

  • ...: The columns to gather. Use the exisiting variable names. Select a range of variables with : (e.g. if you have variables a, b, c, and d, and want to select all of these varibeles you will indicate this with a:d). If you want to exclude a variable, use - (e.g. exclude y with -y).

  • na.rm: If you indicate that na.rm=TRUE, this will remove rows from the output where the value is missing.

  • convert: If TRUE this will automatically convert the key column to a logical, integer, numeric, complex, or factor as appropriate. This is useful if the column names are actually numeric, integer, or logical.

  • factor_key: If FALSE, the default, the key values will be stored as a character vector. If TRUE, will be stored as a factor, which preserves the original ordering of the columns.

2.2 Using Gather()

Now that we have a better understanding of the arguements, lets make our data set long using gather()!

long <- wide %>% gather(Face, ResponseTime, Face.1:Face.3)
##    ID   Face ResponseTime
## 1   1 Face.1          411
## 2   2 Face.1          723
## 3   3 Face.1          325
## 4   4 Face.1          456
## 5   5 Face.1          579
## 6   6 Face.1          612
## 7   7 Face.1          709
## 8   8 Face.1          513
## 9   9 Face.1          527
## 10 10 Face.1          379
## 11  1 Face.2          123
## 12  2 Face.2          300
## 13  3 Face.2          400
## 14  4 Face.2          500
## 15  5 Face.2          600
## 16  6 Face.2          654
## 17  7 Face.2          789
## 18  8 Face.2          906
## 19  9 Face.2          413
## 20 10 Face.2          567
## 21  1 Face.3         1457
## 22  2 Face.3         1000
## 23  3 Face.3          569
## 24  4 Face.3          896
## 25  5 Face.3          956
## 26  6 Face.3         2345
## 27  7 Face.3          780
## 28  8 Face.3          599
## 29  9 Face.3         1023
## 30 10 Face.3          678

As you can see, now we have two columns: One for the the Faces, and one for response time. Each participant saw each face, so ID repeats three times.

3 Separate()

Although the long dataset we created using gather() is acceptable for use, we can break down the face variable even further using separate().

Here is the generic code for separate():

#separate(data, col, into, sep = "[^[:alnum:]]+", remove = TRUE, convert = FALSE, extra = "warn", fill = "warn")

3.1 Separate() Arguments

What are the arugments unique to separate()?

  • col: Unquoted name of the column to be separated.

  • into: Names for the new variables that you are separating out from the column.

  • sep: Separator between columns. If the seprator is a character, it is interpreted as a regular expression. The default value is a regular expression that matches any sequence of non-alphanumeric values. In the example, each face is indicated by a number that follows a period (.). I do not need speifcy this because this exists in each level of Face. If numeric, it is interpreted as the position to split at. Positive values start at 1 at the far-left of the string; negative value start at -1 at the far-right of the string. The length of sep should be one less than into.

  • remove: If this is TRUE, it removes the input column from output data frame.

  • extra: If sep is a character vector (like .), this controls what happens when there are too many pieces (e.g. Face.1.A, rather than Face.1). 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 (like .), this controls what happens when there are not enough pieces (e.g. Face1, rather than Face.1). 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

3.2 Using Separate()

Each face is indicated by number after a period. This variable annotation allows us to separate the face variable into two. By using the separate function of tidyr we can tease apart single variables which sometimes capture multiple variables (or sometimes redundant information).

In this case, I want to split the Face from the number attached to it, which in this example represents the race of the face.

long_separate <- long %>% separate(Face, c("Target", "Number"))
##    ID Target Number ResponseTime
## 1   1   Face      1          411
## 2   2   Face      1          723
## 3   3   Face      1          325
## 4   4   Face      1          456
## 5   5   Face      1          579
## 6   6   Face      1          612
## 7   7   Face      1          709
## 8   8   Face      1          513
## 9   9   Face      1          527
## 10 10   Face      1          379
## 11  1   Face      2          123
## 12  2   Face      2          300
## 13  3   Face      2          400
## 14  4   Face      2          500
## 15  5   Face      2          600
## 16  6   Face      2          654
## 17  7   Face      2          789
## 18  8   Face      2          906
## 19  9   Face      2          413
## 20 10   Face      2          567
## 21  1   Face      3         1457
## 22  2   Face      3         1000
## 23  3   Face      3          569
## 24  4   Face      3          896
## 25  5   Face      3          956
## 26  6   Face      3         2345
## 27  7   Face      3          780
## 28  8   Face      3          599
## 29  9   Face      3         1023
## 30 10   Face      3          678

Now, We have two columns, one for Target, the values of which are all “Face”, and one for Number, which indicates which of the three faces it is.

4 Unite

To undo separate(), we can use unite(), which merges two variables into one.

Here is the generic code for unite():

#unite(data, col, ..., sep = ".", remove = TRUE)

4.1 Unite() Arguments

Here are the arugments unique to unite():

  • sep: In the code for unite() the sep indicated the separator we choose to to use to bind values. In this case, we are using .

4.2 Using Unite()

long_unite <- long_separate %>% unite(Face, Target, Number, sep = ".")
##    ID   Face ResponseTime
## 1   1 Face.1          411
## 2   2 Face.1          723
## 3   3 Face.1          325
## 4   4 Face.1          456
## 5   5 Face.1          579
## 6   6 Face.1          612
## 7   7 Face.1          709
## 8   8 Face.1          513
## 9   9 Face.1          527
## 10 10 Face.1          379
## 11  1 Face.2          123
## 12  2 Face.2          300
## 13  3 Face.2          400
## 14  4 Face.2          500
## 15  5 Face.2          600
## 16  6 Face.2          654
## 17  7 Face.2          789
## 18  8 Face.2          906
## 19  9 Face.2          413
## 20 10 Face.2          567
## 21  1 Face.3         1457
## 22  2 Face.3         1000
## 23  3 Face.3          569
## 24  4 Face.3          896
## 25  5 Face.3          956
## 26  6 Face.3         2345
## 27  7 Face.3          780
## 28  8 Face.3          599
## 29  9 Face.3         1023
## 30 10 Face.3          678

As you can see the data now looks like it did when we first transfromed from wide to long using gather()!

5 Spread

Finally, we will transform the data from long back to wide with the spread() function.

Here is the generic code for spread()

#spread(data, key, value, fill = NA, convert = FALSE, drop = TRUE, sep = NULL)

5.1 Spread() Arguments

The arugments unique to spread():

  • key: The unquoted name of the column whose values will be used as column headings.

  • value: The unquoted name of the column whose values will populate the cells.

  • fill: If used, missing values will be replaced with this value. There are two types of missing in the input: explicit missing values (i.e. NA), and implicit missings, rows that simply aren’t present. Both types of missing value will be replaced by fill.

  • convert: If TRUE, this will automatically convert the new columns to a logical, integer, numeric, complex, or factor as appropriate.

  • drop: If FALSE, will keep factor levels that don’t appear in the data, filling in missing combinations with fill.

  • sep: If NULL, the column names will be taken from the values of key variable. If non-NULL, the column names will be created by stringing together the name, separator, and value.

back_to_wide <- long_unite %>% spread(Face, ResponseTime)
##    ID Face.1 Face.2 Face.3
## 1   1    411    123   1457
## 2   2    723    300   1000
## 3   3    325    400    569
## 4   4    456    500    896
## 5   5    579    600    956
## 6   6    612    654   2345
## 7   7    709    789    780
## 8   8    513    906    599
## 9   9    527    413   1023
## 10 10    379    567    678

And there we have it! We have come full circle back into wide.

6 Challenge

Now it’s your turn.

## wide format
gap_wide <- readr::read_csv('https://raw.githubusercontent.com/kflisikowski/ds/master/gapminder_wide.csv')

## long format
gapminder <- readr::read_csv('https://raw.githubusercontent.com/kflisikowski/ds/master/gapminder.csv')

Let’s have a look:

head(gap_wide)
## # A tibble: 6 × 38
##   continent country      gdpPe…¹ gdpPe…² gdpPe…³ gdpPe…⁴ gdpPe…⁵ gdpPe…⁶ gdpPe…⁷
##   <chr>     <chr>          <dbl>   <dbl>   <dbl>   <dbl>   <dbl>   <dbl>   <dbl>
## 1 Africa    Algeria        2449.   3014.   2551.   3247.   4183.   4910.   5745.
## 2 Africa    Angola         3521.   3828.   4269.   5523.   5473.   3009.   2757.
## 3 Africa    Benin          1063.    960.    949.   1036.   1086.   1029.   1278.
## 4 Africa    Botswana        851.    918.    984.   1215.   2264.   3215.   4551.
## 5 Africa    Burkina Faso    543.    617.    723.    795.    855.    743.    807.
## 6 Africa    Burundi         339.    380.    355.    413.    464.    556.    560.
## # … with 29 more variables: gdpPercap_1987 <dbl>, gdpPercap_1992 <dbl>,
## #   gdpPercap_1997 <dbl>, gdpPercap_2002 <dbl>, gdpPercap_2007 <dbl>,
## #   lifeExp_1952 <dbl>, lifeExp_1957 <dbl>, lifeExp_1962 <dbl>,
## #   lifeExp_1967 <dbl>, lifeExp_1972 <dbl>, lifeExp_1977 <dbl>,
## #   lifeExp_1982 <dbl>, lifeExp_1987 <dbl>, lifeExp_1992 <dbl>,
## #   lifeExp_1997 <dbl>, lifeExp_2002 <dbl>, lifeExp_2007 <dbl>, pop_1952 <dbl>,
## #   pop_1957 <dbl>, pop_1962 <dbl>, pop_1967 <dbl>, pop_1972 <dbl>, …
str(gap_wide)
## spc_tbl_ [142 × 38] (S3: spec_tbl_df/tbl_df/tbl/data.frame)
##  $ continent     : chr [1:142] "Africa" "Africa" "Africa" "Africa" ...
##  $ country       : chr [1:142] "Algeria" "Angola" "Benin" "Botswana" ...
##  $ gdpPercap_1952: num [1:142] 2449 3521 1063 851 543 ...
##  $ gdpPercap_1957: num [1:142] 3014 3828 960 918 617 ...
##  $ gdpPercap_1962: num [1:142] 2551 4269 949 984 723 ...
##  $ gdpPercap_1967: num [1:142] 3247 5523 1036 1215 795 ...
##  $ gdpPercap_1972: num [1:142] 4183 5473 1086 2264 855 ...
##  $ gdpPercap_1977: num [1:142] 4910 3009 1029 3215 743 ...
##  $ gdpPercap_1982: num [1:142] 5745 2757 1278 4551 807 ...
##  $ gdpPercap_1987: num [1:142] 5681 2430 1226 6206 912 ...
##  $ gdpPercap_1992: num [1:142] 5023 2628 1191 7954 932 ...
##  $ gdpPercap_1997: num [1:142] 4797 2277 1233 8647 946 ...
##  $ gdpPercap_2002: num [1:142] 5288 2773 1373 11004 1038 ...
##  $ gdpPercap_2007: num [1:142] 6223 4797 1441 12570 1217 ...
##  $ lifeExp_1952  : num [1:142] 43.1 30 38.2 47.6 32 ...
##  $ lifeExp_1957  : num [1:142] 45.7 32 40.4 49.6 34.9 ...
##  $ lifeExp_1962  : num [1:142] 48.3 34 42.6 51.5 37.8 ...
##  $ lifeExp_1967  : num [1:142] 51.4 36 44.9 53.3 40.7 ...
##  $ lifeExp_1972  : num [1:142] 54.5 37.9 47 56 43.6 ...
##  $ lifeExp_1977  : num [1:142] 58 39.5 49.2 59.3 46.1 ...
##  $ lifeExp_1982  : num [1:142] 61.4 39.9 50.9 61.5 48.1 ...
##  $ lifeExp_1987  : num [1:142] 65.8 39.9 52.3 63.6 49.6 ...
##  $ lifeExp_1992  : num [1:142] 67.7 40.6 53.9 62.7 50.3 ...
##  $ lifeExp_1997  : num [1:142] 69.2 41 54.8 52.6 50.3 ...
##  $ lifeExp_2002  : num [1:142] 71 41 54.4 46.6 50.6 ...
##  $ lifeExp_2007  : num [1:142] 72.3 42.7 56.7 50.7 52.3 ...
##  $ pop_1952      : num [1:142] 9279525 4232095 1738315 442308 4469979 ...
##  $ pop_1957      : num [1:142] 10270856 4561361 1925173 474639 4713416 ...
##  $ pop_1962      : num [1:142] 11000948 4826015 2151895 512764 4919632 ...
##  $ pop_1967      : num [1:142] 12760499 5247469 2427334 553541 5127935 ...
##  $ pop_1972      : num [1:142] 14760787 5894858 2761407 619351 5433886 ...
##  $ pop_1977      : num [1:142] 17152804 6162675 3168267 781472 5889574 ...
##  $ pop_1982      : num [1:142] 20033753 7016384 3641603 970347 6634596 ...
##  $ pop_1987      : num [1:142] 23254956 7874230 4243788 1151184 7586551 ...
##  $ pop_1992      : num [1:142] 26298373 8735988 4981671 1342614 8878303 ...
##  $ pop_1997      : num [1:142] 29072015 9875024 6066080 1536536 10352843 ...
##  $ pop_2002      : num [1:142] 31287142 10866106 7026113 1630347 12251209 ...
##  $ pop_2007      : num [1:142] 33333216 12420476 8078314 1639131 14326203 ...
##  - attr(*, "spec")=
##   .. cols(
##   ..   continent = col_character(),
##   ..   country = col_character(),
##   ..   gdpPercap_1952 = col_double(),
##   ..   gdpPercap_1957 = col_double(),
##   ..   gdpPercap_1962 = col_double(),
##   ..   gdpPercap_1967 = col_double(),
##   ..   gdpPercap_1972 = col_double(),
##   ..   gdpPercap_1977 = col_double(),
##   ..   gdpPercap_1982 = col_double(),
##   ..   gdpPercap_1987 = col_double(),
##   ..   gdpPercap_1992 = col_double(),
##   ..   gdpPercap_1997 = col_double(),
##   ..   gdpPercap_2002 = col_double(),
##   ..   gdpPercap_2007 = col_double(),
##   ..   lifeExp_1952 = col_double(),
##   ..   lifeExp_1957 = col_double(),
##   ..   lifeExp_1962 = col_double(),
##   ..   lifeExp_1967 = col_double(),
##   ..   lifeExp_1972 = col_double(),
##   ..   lifeExp_1977 = col_double(),
##   ..   lifeExp_1982 = col_double(),
##   ..   lifeExp_1987 = col_double(),
##   ..   lifeExp_1992 = col_double(),
##   ..   lifeExp_1997 = col_double(),
##   ..   lifeExp_2002 = col_double(),
##   ..   lifeExp_2007 = col_double(),
##   ..   pop_1952 = col_double(),
##   ..   pop_1957 = col_double(),
##   ..   pop_1962 = col_double(),
##   ..   pop_1967 = col_double(),
##   ..   pop_1972 = col_double(),
##   ..   pop_1977 = col_double(),
##   ..   pop_1982 = col_double(),
##   ..   pop_1987 = col_double(),
##   ..   pop_1992 = col_double(),
##   ..   pop_1997 = col_double(),
##   ..   pop_2002 = col_double(),
##   ..   pop_2007 = col_double()
##   .. )
##  - attr(*, "problems")=<externalptr>

While wide format is nice for data entry, it’s not nice for calculations. Some of the columns are a mix of variable (e.g. “gdpPercap”) and data (“1952”). What if you were asked for the mean population after 1990 in Algeria? Possible, but ugly. But we know it doesn’t need to be so ugly. Let’s tidy it back to the format we’ve been using.

Your job is to get it to long format. You will have to do this in 2 steps. The first step is to take all of those column names (e.g. lifeExp_1970) and make them a variable in a new column, and transfer the values into another column.

We need to name two new variables in the key-value pair, one for the key, one for the value. It can be hard to wrap your mind around this, so let’s give it a try. Let’s name them obstype_year and obs_values.

gap_long <- gap_wide %>% 
  gather(key   = obstype_year,
         value = obs_values)

Although we were already planning to inspect our work, let’s definitely do it now:

str(gap_long)
## tibble [5,396 × 2] (S3: tbl_df/tbl/data.frame)
##  $ obstype_year: chr [1:5396] "continent" "continent" "continent" "continent" ...
##  $ obs_values  : chr [1:5396] "Africa" "Africa" "Africa" "Africa" ...

Although we were already planning to inspect our work, let’s definitely do it now:

str(gap_long)
## tibble [5,396 × 2] (S3: tbl_df/tbl/data.frame)
##  $ obstype_year: chr [1:5396] "continent" "continent" "continent" "continent" ...
##  $ obs_values  : chr [1:5396] "Africa" "Africa" "Africa" "Africa" ...

We have reshaped our dataframe but this new format isn’t really what we wanted.

What went wrong? Notice that it didn’t know that we wanted to keep continent and country untouched; we need to give it more information about which columns we want reshaped. We can do this in several ways.

One way is to identify the columns is by name. Listing them explicitly can be a good approach if there are just a few. But in our case we have 30 columns. I’m not going to list them out here since there is way too much potential for error if I tried to list gdpPercap_1952, gdpPercap_1957, gdpPercap_1962 and so on. But we could use some of dplyr’s awesome helper functions — because we expect that there is a better way to do this!

gap_long <- gap_wide %>% 
  gather(key   = obstype_year,
         value = obs_values,
         dplyr::starts_with('pop'),
         dplyr::starts_with('lifeExp'),
         dplyr::starts_with('gdpPercap'))  #here i'm listing all the columns to use in gather

str(gap_long)
## tibble [5,112 × 4] (S3: tbl_df/tbl/data.frame)
##  $ continent   : chr [1:5112] "Africa" "Africa" "Africa" "Africa" ...
##  $ country     : chr [1:5112] "Algeria" "Angola" "Benin" "Botswana" ...
##  $ obstype_year: chr [1:5112] "pop_1952" "pop_1952" "pop_1952" "pop_1952" ...
##  $ obs_values  : num [1:5112] 9279525 4232095 1738315 442308 4469979 ...
head(gap_long)
## # A tibble: 6 × 4
##   continent country      obstype_year obs_values
##   <chr>     <chr>        <chr>             <dbl>
## 1 Africa    Algeria      pop_1952        9279525
## 2 Africa    Angola       pop_1952        4232095
## 3 Africa    Benin        pop_1952        1738315
## 4 Africa    Botswana     pop_1952         442308
## 5 Africa    Burkina Faso pop_1952        4469979
## 6 Africa    Burundi      pop_1952        2445618
tail(gap_long)
## # A tibble: 6 × 4
##   continent country        obstype_year   obs_values
##   <chr>     <chr>          <chr>               <dbl>
## 1 Europe    Sweden         gdpPercap_2007     33860.
## 2 Europe    Switzerland    gdpPercap_2007     37506.
## 3 Europe    Turkey         gdpPercap_2007      8458.
## 4 Europe    United Kingdom gdpPercap_2007     33203.
## 5 Oceania   Australia      gdpPercap_2007     34435.
## 6 Oceania   New Zealand    gdpPercap_2007     25185.

Success! And there is another way that is nice to use if your columns don’t follow such a structured pattern: you can exclude the columns you don’t want.

gap_long <- gap_wide %>% 
  gather(key   = obstype_year,
         value = obs_values,
         -continent, -country)

str(gap_long)
## tibble [5,112 × 4] (S3: tbl_df/tbl/data.frame)
##  $ continent   : chr [1:5112] "Africa" "Africa" "Africa" "Africa" ...
##  $ country     : chr [1:5112] "Algeria" "Angola" "Benin" "Botswana" ...
##  $ obstype_year: chr [1:5112] "gdpPercap_1952" "gdpPercap_1952" "gdpPercap_1952" "gdpPercap_1952" ...
##  $ obs_values  : num [1:5112] 2449 3521 1063 851 543 ...
head(gap_long)
## # A tibble: 6 × 4
##   continent country      obstype_year   obs_values
##   <chr>     <chr>        <chr>               <dbl>
## 1 Africa    Algeria      gdpPercap_1952      2449.
## 2 Africa    Angola       gdpPercap_1952      3521.
## 3 Africa    Benin        gdpPercap_1952      1063.
## 4 Africa    Botswana     gdpPercap_1952       851.
## 5 Africa    Burkina Faso gdpPercap_1952       543.
## 6 Africa    Burundi      gdpPercap_1952       339.
tail(gap_long)
## # A tibble: 6 × 4
##   continent country        obstype_year obs_values
##   <chr>     <chr>          <chr>             <dbl>
## 1 Europe    Sweden         pop_2007        9031088
## 2 Europe    Switzerland    pop_2007        7554661
## 3 Europe    Turkey         pop_2007       71158647
## 4 Europe    United Kingdom pop_2007       60776238
## 5 Oceania   Australia      pop_2007       20434176
## 6 Oceania   New Zealand    pop_2007        4115771

6.1 Exercise 1.

Using gap_long, calculate the mean life expectancy for each continent over time from 1982 to 2007.

6.2 Exercise 2.

Convert gap_long all the way back to gap_wide. Hint: Do this in 2 steps. First, create appropriate labels for all our new variables (variable_year combinations) with the opposite of separate: tidyr::unite(). Second, spread() that variable_year column into wider format.

head(gap_long) # remember the columns
## # A tibble: 6 × 4
##   continent country      obstype_year   obs_values
##   <chr>     <chr>        <chr>               <dbl>
## 1 Africa    Algeria      gdpPercap_1952      2449.
## 2 Africa    Angola       gdpPercap_1952      3521.
## 3 Africa    Benin        gdpPercap_1952      1063.
## 4 Africa    Botswana     gdpPercap_1952       851.
## 5 Africa    Burkina Faso gdpPercap_1952       543.
## 6 Africa    Burundi      gdpPercap_1952       339.

7 Complete

One of the coolest functions in tidyr is the function complete(). We’ll start with an example dataframe:

df <- data.frame(
  Year = c(1999, 2000, 2004, 1999, 2004),
  Var1 = c("La", "La", "La", "Mi", "Mi"),
  Var2 = c(4,5,2,1,8)
)

df
##   Year Var1 Var2
## 1 1999   La    4
## 2 2000   La    5
## 3 2004   La    2
## 4 1999   Mi    1
## 5 2004   Mi    8

“Mi” is not listed for the year 2000.

Does this mean it wasn’t observed (Var2 = 0) or that it wasn’t recorded (Var2 = NA)? Only the person who recorded the data knows, but let’s assume that this means the Var2 was 0 for that year.

We can use the complete() function to make our dataset more complete.

df %>% 
  complete(Year, Var1)
## # A tibble: 6 × 3
##    Year Var1   Var2
##   <dbl> <chr> <dbl>
## 1  1999 La        4
## 2  1999 Mi        1
## 3  2000 La        5
## 4  2000 Mi       NA
## 5  2004 La        2
## 6  2004 Mi        8

This gives us an NA for “Mi” in 2000, but we want it to be a 0 instead. We can use the fill argument to assign the fill value.

df %>% complete(Year, Var1, fill = list(Var2 = 0))
## # A tibble: 6 × 3
##    Year Var1   Var2
##   <dbl> <chr> <dbl>
## 1  1999 La        4
## 2  1999 Mi        1
## 3  2000 La        5
## 4  2000 Mi        0
## 5  2004 La        2
## 6  2004 Mi        8

Now we have what we want. Let’s assume that all years between 1999 and 2004 that aren’t listed should actually be assigned a value of 0. We can use the full_seq() function from tidyr to fill out our dataset with all years 1999-2004 and assign Var2 values of 0 to those years & Var1 for which there was no observation.

df %>% complete(Year = full_seq(Year, period = 1),
                   Var1,
                   fill = list(Var2 = 0))
## # A tibble: 12 × 3
##     Year Var1   Var2
##    <dbl> <chr> <dbl>
##  1  1999 La        4
##  2  1999 Mi        1
##  3  2000 La        5
##  4  2000 Mi        0
##  5  2001 La        0
##  6  2001 Mi        0
##  7  2002 La        0
##  8  2002 Mi        0
##  9  2003 La        0
## 10  2003 Mi        0
## 11  2004 La        2
## 12  2004 Mi        8

8 References

LS0tDQp0aXRsZTogIlRpZHkgV2VlazogUmVzaGFwaW5nIERhdGEgVXNpbmcgVGlkeXIiDQphdXRob3I6ICJZb3VyIE5hbWUiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgdGhlbWU6IGNlcnVsZWFuDQogICAgaGlnaGxpZ2h0OiB0ZXh0bWF0ZQ0KICAgIGZvbnRzaXplOiA4cHQNCiAgICB0b2M6IHRydWUNCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUNCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQogICAgdG9jX2Zsb2F0Og0KICAgICAgY29sbGFwc2VkOiBmYWxzZQ0KZWRpdG9yX29wdGlvbnM6IA0KICBtYXJrZG93bjogDQogICAgd3JhcDogNzINCi0tLQ0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkNCmBgYA0KDQojIEludHJvZHVjdGlvbg0KDQpXaGVuIGRhdGEgaW4gaXMgd2lkZSBmb3JtYXQsIGEgc3ViamVjdHMgcmVzcG9uc2VzIHdpbGwgYmUgaW4gYSBzaW5nbGUNCnJvdywgYW5kIGVhY2ggcmVzcG9uc2UgaXMgaW4gc2VwYXJhdGUgY29sdW1ucy4gSG93ZXZlciBSIHByZWZlcnMgbG9uZw0KZm9ybWF0LiBXZSBjb3VsZCBgbWVsdGAgYW5kIGBjYXN0YCB3aXRoIGByZXNoYXBlMmAgdG8gcmVzaGFwZSBmcm9tIHdpZGUNCnRvIGxvbmcgZm9ybWF0LCBidXQgaXMgdGhlcmUgYSB3YXkgdG8gcmVzaGFwZSB1c2luZyBldmVuIGxlc3MgY29kZT8NCkx1Y2tpbHkgZm9yIHVzLCBbSGFkbGV5DQpXaWNraGFtXShodHRwczovL3ByaWNlb25vbWljcy5jb20vaGFkbGV5LXdpY2toYW0tdGhlLW1hbi13aG8tcmV2b2x1dGlvbml6ZWQtci8pDQpoYXMgY3JlYXRlZCB0aGUgZWFzeSB0byB1c2UgYHRpZHlyYCENCg0KYHRpZHlyYCBhbGxvdyB1cyB0byBxdWlja2x5IGFuZCBlYXNpbHkgdGlkeSBhbmQgcmVvcmdhbml6ZSBvdXIgZGF0YSBmb3INCmFsbCBzb3J0cyBvZiBhbmFseXNlcy4gVGhpcyBpcyBwYXJ0aWN1bGFybHkgaGVscGZ1bCB3aXRoIGEgZGlzb3JnYW5pemVkDQpkYXRhc2V0LiBgdGlkeXJgIGlzIGJ1aWx0IGZvciB0aGlzIGZ1bmN0aW9uLiBTcGVjaWZpY2FsbHksIGB0aWR5cmAgY2FuDQpvbmx5IGJlIHVzZWQgd2l0aCBleGlzaXRpbmcgZGF0YWZyYW1lcywgYW5kIGNhbm5vdCBhZ2dyZWdhdGUuDQoNCkluIHRoaXMgY2hhcHRlciwgd2Ugd2lsbCBnbyBvdmVyIHRoZSBoYWxsbWFyayBmdW5jdGlvbnMgb2YgYHRpZHlyYDoNCmBnYXRoZXIoKWAsIGBzZXBhcmF0ZSgpYCwgYHVuaXRlKClgLCBhbmQgYHNwcmVhZCgpYC4NCg0KRmlyc3QgbGV0J3MgaW5zdGFsbCBhbmQgY2FsbCB1cCB0aGUgYHRpZHlyYCBwYWNrYWdlLiBXZSB3aWxsIGFsc28gbmVlZA0KdG8gdXNlIHRoZSBgZHBseXJgIHBhY2thZ2UuDQoNCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCBlY2hvPVRSVUV9DQojaW5zdGFsbC5wYWNrYWdlcygidGlkeXIiKSAjIEkgaGF2ZSB1c2VkICIjIiB0byAiY29tbWVudCBvdXQiIHRoaXMgbGluZSBmb3IgdGhpcyB0dXRvcmlhbC4gSnVzdCB0YWtlIGF3YXkgdGhlIGZpcnN0ICIjIiBhbmQgeW91IGFyZSBnb29kIHRvIGdvIQ0KI2luc3RhbGwucGFja2FnZXMoImRwbHlyIikNCg0KbGlicmFyeSh0aWR5cikNCmxpYnJhcnkoZHBseXIpDQpgYGANCg0KIyMgJVw+JQ0KDQpXaHkgZG8gd2UgbmVlZCBgZHBseXJgPyBgZHBseXJgIGlzIGEgZ3JhbW1hciBvZiBkYXRhIG1hbmlwdWxhdGlvbi4gV2UNCm5lZWQgYGRwbHlyYCB0byB1c2UgdGhlIHBpcGUgb3BlcmF0b3IsIGAlPiVgLCBpbiBvdXIgY29kZS4gYCU+JWAgaXMgbm90DQpyZXF1aXJlZCB0byB1c2UgdGlkeXIsIGJ1dCBpdCBkb2VzIG1ha2UgdGhpbmdzIGVhc2llciENCg0KYCU+JWAgYWxsb3dzIHlvdSB0byBwaXBlIGEgdmFsdWUgZm9yd2FyZCBpbnRvIGFuIGV4cHJlc3Npb24gb3IgdG8NCmZ1bmN0aW9uIGNhbGw7IHN1Y2ggdGhhdCBgeCAlPiUgZmAsIGluc3RlYWQgb2YgYGYoeClgLiBUaGlzIHNob3J0IGhhbmQNCndhcyBjcmVhdGVkIGJ5IFN0ZWZhbiBNaWx0b24gQmFjaGUgd2l0aCB0aGUgYG1hZ3JpdHRyYCBwYWNrYWdlLiBUbyByZWFkDQptb3JlIGFib3V0IHRoaXMgZnVuY3Rpb24sIGNsaWNrDQpbaGVyZV0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL21hZ3JpdHRyL3ZpZ25ldHRlcy9tYWdyaXR0ci5odG1sKQ0KDQojIyBUaGUgRGF0YWZyYW1lDQoNCkhlcmUgSSBoYXZlIGNyZWF0ZWQgYSBtZXNzeSB3aWRlIGRhdGFzZXQuIEZlZWwgZnJlZSB0byB1c2UgaXQgdG8gZm9sbG93DQphbG9uZyENCg0KSW4gdGhpcyBleGFtcGxlIHN0dWR5LCBwYXJ0aWNpcGFudHMgd2VyZSBhc2tlZCB0byBjYXRlZ29yaXplIHRocmVlIGZhY2VzDQpieSBjbGlja2luZyB2YXJpb3VzIGJ1dHRvbnMgdGhhdCByZXByZXNlbnQgdGhyZWUgZGlmZmVyZW50IGNhdGVnb3JpZXMuDQpUaGUgdGltZSBpdCB0b29rIHRvIGNsaWNrIGEgYnV0dG9uIGlzIGluIG1pbGxpc2Vjb25kcy4NCg0KYGBge3IsIG1lc3NhZ2U9RkFMU0UsIGVjaG89VFJVRX0NCm49MTANCndpZGUgPC0gZGF0YS5mcmFtZSgNCiAgSUQgPSBjKDE6biksDQogIEZhY2UuMSA9IGMoNDExLDcyMywzMjUsNDU2LDU3OSw2MTIsNzA5LDUxMyw1MjcsMzc5KSwNCiAgRmFjZS4yID0gYygxMjMsMzAwLDQwMCw1MDAsNjAwLDY1NCw3ODksOTA2LDQxMyw1NjcpLA0KICBGYWNlLjMgPSBjKDE0NTcsMTAwMCw1NjksODk2LDk1NiwyMzQ1LDc4MCw1OTksMTAyMyw2NzgpDQopDQpgYGANCg0KVGhpcyBkYXRhc2V0IEkgY3JlYXRlZCBpcyBtZXNzeTsgQXMgeW91IGNhbiBzZWUgYmVsb3csIG9ubHkgSUQgaXMgaW4gYQ0KY29sdW1uLCBSZXNwb25zZSB0aW1lIHNwbGl0IGJldHdlZW4gdGhyZWUgY29sdW1ucywgc3VjaCB0aGF0IHJlc3BvbnNlcw0KYXJlIGluIGJvdGggcm93cyBhbmQgY29sdW1ucyAoYnkgSUQgYW5kIEZhY2UuMSwgRmFjZS4yLCBhbmQgRmFjZS4zKS4NCg0KV2hhdCB3ZSB3YW50IGluc3RlYWQgaXMgb25lIGNvbHVtbiBmb3IgdGhlIGNvbmRpdGlvbiAoRmFjZS4xLCBGYWNlLjIsIG9yDQpGYWNlLjMpIHJlc3BvbnNlcyBhbmQgYSBjb2x1bW4gZm9yIHJlc3BvbnNlIHRpbWUsIHdpdGggZWFjaCByb3cgYmVpbmcgYQ0Kc2luZ3VsYXIgb2JzZXJ2YXRpb24gZm9yIGVhY2ggcGFydGljaXBhbnQuIFBhcnRpY2lwYW50IElEcyBzaG91bGQgcmVwZWF0DQphcyB0aGlzIGlzIGEgd2l0aGluIHN1YmplY3QgZGVzaWduIChlYWNoIHBhcnRpY2lwYW50IHNhdyBlYWNoIGZhY2UpLg0KDQpgYGB7ciwgbWVzc2FnZT1UUlVFLCBlY2hvPUZBTFNFfQ0Kd2lkZQ0KYGBgDQoNCiMgR2F0aGVyKCkNCg0KQnkgdXNpbmcgdGhlIGBnYXRoZXIoKWAgZnVuY3Rpb24sIHdlIGNhbiB0cmFuc2Zvcm0gdGhlIGRhdGEgZnJvbSB3aWRlIHRvDQpsb25nIEhlcmUgaXMgdGhlIGdlbmVyaWMgY29kZSBmb3IgYGdhdGhlcigpYDoNCg0KYGBge3IsIG1lc3NhZ2U9RkFMU0UsIGVjaG89VFJVRX0NCiNnYXRoZXIoZGF0YSwga2V5LCB2YWx1ZSwgLi4uLCBuYS5ybSA9IEZBTFNFLCBjb252ZXJ0ID0gRkFMU0UsIGZhY3Rvcl9rZXkgPSBGQUxTRSkNCmBgYA0KDQojIyBHYXRoZXIoKSBBcmd1bWVudHMNCg0KV2hvYSEgV2hhdCBkb2VzIHRoaXMgYWxsIG1lYW4/IExldCdzIGZpbmQgb3V0IG1vcmUgYWJvdXQgdGhlIGFyZ3VtZW50cw0Kb2YgYGdhdGhlcigpYDoNCg0KLSAgIGBkYXRhYDogWW91ciBkYXRhIGZyYW1lLg0KDQotICAgYGtleSwgdmFsdWVgOiBUaGUgdW5xdW90ZWQgbmV3IG5hbWVzIG9mIGtleSBhbmQgdmFsdWUgY29sdW1ucyB0bw0KICAgIGNyZWF0ZSBpbiB0aGUgb3V0cHV0LiBUaGUga2V5IHdpbGwgYmVjb21lIHRoZSBuYW1lIG9mIHRoZQ0KICAgIGNvbmRpdGlvbi9JViBjb2x1bW4sIGFuZCB2YWx1ZSB3aWxsIGJlY29tZSB0aGUgbmFtZSBvZiB0aGUNCiAgICByZXNwb25zZS9EViBjb2x1bW4uDQoNCi0gICBgLi4uYDogVGhlIGNvbHVtbnMgdG8gZ2F0aGVyLiBVc2UgdGhlIGV4aXNpdGluZyB2YXJpYWJsZSBuYW1lcy4NCiAgICBTZWxlY3QgYSByYW5nZSBvZiB2YXJpYWJsZXMgd2l0aCBgOmAgKGUuZy4gaWYgeW91IGhhdmUgdmFyaWFibGVzIGEsDQogICAgYiwgYywgYW5kIGQsIGFuZCB3YW50IHRvIHNlbGVjdCBhbGwgb2YgdGhlc2UgdmFyaWJlbGVzIHlvdSB3aWxsDQogICAgaW5kaWNhdGUgdGhpcyB3aXRoIGE6ZCkuIElmIHlvdSB3YW50IHRvIGV4Y2x1ZGUgYSB2YXJpYWJsZSwgdXNlIGAtYA0KICAgIChlLmcuIGV4Y2x1ZGUgeSB3aXRoIC15KS4NCg0KLSAgIGBuYS5ybWA6IElmIHlvdSBpbmRpY2F0ZSB0aGF0IG5hLnJtPVRSVUUsIHRoaXMgd2lsbCByZW1vdmUgcm93cyBmcm9tDQogICAgdGhlIG91dHB1dCB3aGVyZSB0aGUgdmFsdWUgaXMgbWlzc2luZy4NCg0KLSAgIGBjb252ZXJ0YDogSWYgVFJVRSB0aGlzIHdpbGwgYXV0b21hdGljYWxseSBjb252ZXJ0IHRoZSBrZXkgY29sdW1uIHRvDQogICAgYSBsb2dpY2FsLCBpbnRlZ2VyLCBudW1lcmljLCBjb21wbGV4LCBvciBmYWN0b3IgYXMgYXBwcm9wcmlhdGUuIFRoaXMNCiAgICBpcyB1c2VmdWwgaWYgdGhlIGNvbHVtbiBuYW1lcyBhcmUgYWN0dWFsbHkgbnVtZXJpYywgaW50ZWdlciwgb3INCiAgICBsb2dpY2FsLg0KDQotICAgYGZhY3Rvcl9rZXlgOiBJZiBGQUxTRSwgdGhlIGRlZmF1bHQsIHRoZSBrZXkgdmFsdWVzIHdpbGwgYmUgc3RvcmVkDQogICAgYXMgYSBjaGFyYWN0ZXIgdmVjdG9yLiBJZiBUUlVFLCB3aWxsIGJlIHN0b3JlZCBhcyBhIGZhY3Rvciwgd2hpY2gNCiAgICBwcmVzZXJ2ZXMgdGhlIG9yaWdpbmFsIG9yZGVyaW5nIG9mIHRoZSBjb2x1bW5zLg0KDQojIyBVc2luZyBHYXRoZXIoKSANCg0KTm93IHRoYXQgd2UgaGF2ZSBhIGJldHRlciB1bmRlcnN0YW5kaW5nIG9mIHRoZSBhcmd1ZW1lbnRzLCBsZXRzIG1ha2Ugb3VyDQpkYXRhIHNldCBsb25nIHVzaW5nIGBnYXRoZXIoKWAhDQoNCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCBlY2hvPVRSVUV9DQpsb25nIDwtIHdpZGUgJT4lIGdhdGhlcihGYWNlLCBSZXNwb25zZVRpbWUsIEZhY2UuMTpGYWNlLjMpDQpgYGANCg0KYGBge3IsIG1lc3NhZ2U9VFJVRSwgZWNobz1GQUxTRX0NCmxvbmcNCmBgYA0KDQpBcyB5b3UgY2FuIHNlZSwgbm93IHdlIGhhdmUgdHdvIGNvbHVtbnM6IE9uZSBmb3IgdGhlIHRoZSBGYWNlcywgYW5kIG9uZQ0KZm9yIHJlc3BvbnNlIHRpbWUuIEVhY2ggcGFydGljaXBhbnQgc2F3IGVhY2ggZmFjZSwgc28gSUQgcmVwZWF0cyB0aHJlZQ0KdGltZXMuDQoNCiMgU2VwYXJhdGUoKQ0KDQpBbHRob3VnaCB0aGUgbG9uZyBkYXRhc2V0IHdlIGNyZWF0ZWQgdXNpbmcgYGdhdGhlcigpYCBpcyBhY2NlcHRhYmxlIGZvcg0KdXNlLCB3ZSBjYW4gYnJlYWsgZG93biB0aGUgZmFjZSB2YXJpYWJsZSBldmVuIGZ1cnRoZXIgdXNpbmcNCmBzZXBhcmF0ZSgpYC4NCg0KSGVyZSBpcyB0aGUgZ2VuZXJpYyBjb2RlIGZvciBgc2VwYXJhdGUoKWA6DQoNCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCBlY2hvPVRSVUV9DQojc2VwYXJhdGUoZGF0YSwgY29sLCBpbnRvLCBzZXAgPSAiW15bOmFsbnVtOl1dKyIsIHJlbW92ZSA9IFRSVUUsIGNvbnZlcnQgPSBGQUxTRSwgZXh0cmEgPSAid2FybiIsIGZpbGwgPSAid2FybiIpDQpgYGANCg0KIyMgU2VwYXJhdGUoKSBBcmd1bWVudHMNCg0KV2hhdCBhcmUgdGhlIGFydWdtZW50cyB1bmlxdWUgdG8gYHNlcGFyYXRlKClgPw0KDQotICAgYGNvbGA6IFVucXVvdGVkIG5hbWUgb2YgdGhlIGNvbHVtbiB0byBiZSBzZXBhcmF0ZWQuDQoNCi0gICBgaW50b2A6IE5hbWVzIGZvciB0aGUgbmV3IHZhcmlhYmxlcyB0aGF0IHlvdSBhcmUgc2VwYXJhdGluZyBvdXQgZnJvbQ0KICAgIHRoZSBjb2x1bW4uDQoNCi0gICBgc2VwYDogU2VwYXJhdG9yIGJldHdlZW4gY29sdW1ucy4gSWYgdGhlIHNlcHJhdG9yIGlzIGEgY2hhcmFjdGVyLCBpdA0KICAgIGlzIGludGVycHJldGVkIGFzIGEgcmVndWxhciBleHByZXNzaW9uLiBUaGUgZGVmYXVsdCB2YWx1ZSBpcyBhDQogICAgcmVndWxhciBleHByZXNzaW9uIHRoYXQgbWF0Y2hlcyBhbnkgc2VxdWVuY2Ugb2Ygbm9uLWFscGhhbnVtZXJpYw0KICAgIHZhbHVlcy4gSW4gdGhlIGV4YW1wbGUsIGVhY2ggZmFjZSBpcyBpbmRpY2F0ZWQgYnkgYSBudW1iZXIgdGhhdA0KICAgIGZvbGxvd3MgYSBwZXJpb2QgKGAuYCkuIEkgZG8gbm90IG5lZWQgc3BlaWZjeSB0aGlzIGJlY2F1c2UgdGhpcw0KICAgIGV4aXN0cyBpbiBlYWNoIGxldmVsIG9mIEZhY2UuIElmIG51bWVyaWMsIGl0IGlzIGludGVycHJldGVkIGFzIHRoZQ0KICAgIHBvc2l0aW9uIHRvIHNwbGl0IGF0LiBQb3NpdGl2ZSB2YWx1ZXMgc3RhcnQgYXQgMSBhdCB0aGUgZmFyLWxlZnQgb2YNCiAgICB0aGUgc3RyaW5nOyBuZWdhdGl2ZSB2YWx1ZSBzdGFydCBhdCAtMSBhdCB0aGUgZmFyLXJpZ2h0IG9mIHRoZQ0KICAgIHN0cmluZy4gVGhlIGxlbmd0aCBvZiBgc2VwYCBzaG91bGQgYmUgb25lIGxlc3MgdGhhbiBgaW50b2AuDQoNCi0gICBgcmVtb3ZlYDogSWYgdGhpcyBpcyBUUlVFLCBpdCByZW1vdmVzIHRoZSBpbnB1dCBjb2x1bW4gZnJvbSBvdXRwdXQNCiAgICBkYXRhIGZyYW1lLg0KDQotICAgYGV4dHJhYDogSWYgYHNlcGAgaXMgYSBjaGFyYWN0ZXIgdmVjdG9yIChsaWtlIGAuYCksIHRoaXMgY29udHJvbHMNCiAgICB3aGF0IGhhcHBlbnMgd2hlbiB0aGVyZSBhcmUgdG9vIG1hbnkgcGllY2VzIChlLmcuIEZhY2UuMS5BLCByYXRoZXINCiAgICB0aGFuIEZhY2UuMSkuIFRoZXJlIGFyZSB0aHJlZSB2YWxpZCBvcHRpb25zOiAid2FybiIgKHRoZSBkZWZhdWx0KToNCiAgICBlbWl0IGEgd2FybmluZyBhbmQgZHJvcCBleHRyYSB2YWx1ZXMuICJkcm9wIjogZHJvcCBhbnkgZXh0cmEgdmFsdWVzDQogICAgd2l0aG91dCBhIHdhcm5pbmcuICJtZXJnZSI6IG9ubHkgc3BsaXRzIGF0IG1vc3QgbGVuZ3RoKGludG8pIHRpbWVzDQoNCi0gICBgZmlsbGA6IElmIGBzZXBgIGlzIGEgY2hhcmFjdGVyIHZlY3RvciAobGlrZSBgLmApLCB0aGlzIGNvbnRyb2xzDQogICAgd2hhdCBoYXBwZW5zIHdoZW4gdGhlcmUgYXJlIG5vdCBlbm91Z2ggcGllY2VzIChlLmcuIEZhY2UxLCByYXRoZXINCiAgICB0aGFuIEZhY2UuMSkuIFRoZXJlIGFyZSB0aHJlZSB2YWxpZCBvcHRpb25zOiAid2FybiIgKHRoZSBkZWZhdWx0KToNCiAgICBlbWl0IGEgd2FybmluZyBhbmQgZmlsbCBmcm9tIHRoZSByaWdodCAicmlnaHQiOiBmaWxsIHdpdGggbWlzc2luZw0KICAgIHZhbHVlcyBvbiB0aGUgcmlnaHQgImxlZnQiOiBmaWxsIHdpdGggbWlzc2luZyB2YWx1ZXMgb24gdGhlIGxlZnQNCg0KIyMgVXNpbmcgU2VwYXJhdGUoKQ0KDQpFYWNoIGZhY2UgaXMgaW5kaWNhdGVkIGJ5IG51bWJlciBhZnRlciBhIHBlcmlvZC4gVGhpcyB2YXJpYWJsZQ0KYW5ub3RhdGlvbiBhbGxvd3MgdXMgdG8gc2VwYXJhdGUgdGhlIGZhY2UgdmFyaWFibGUgaW50byB0d28uIEJ5IHVzaW5nDQp0aGUgYHNlcGFyYXRlYCBmdW5jdGlvbiBvZiBgdGlkeXJgIHdlIGNhbiB0ZWFzZSBhcGFydCBzaW5nbGUgdmFyaWFibGVzDQp3aGljaCBzb21ldGltZXMgY2FwdHVyZSBtdWx0aXBsZSB2YXJpYWJsZXMgKG9yIHNvbWV0aW1lcyByZWR1bmRhbnQNCmluZm9ybWF0aW9uKS4NCg0KSW4gdGhpcyBjYXNlLCBJIHdhbnQgdG8gc3BsaXQgdGhlIEZhY2UgZnJvbSB0aGUgbnVtYmVyIGF0dGFjaGVkIHRvIGl0LA0Kd2hpY2ggaW4gdGhpcyBleGFtcGxlIHJlcHJlc2VudHMgdGhlIHJhY2Ugb2YgdGhlIGZhY2UuDQoNCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCBlY2hvPVRSVUV9DQpsb25nX3NlcGFyYXRlIDwtIGxvbmcgJT4lIHNlcGFyYXRlKEZhY2UsIGMoIlRhcmdldCIsICJOdW1iZXIiKSkNCmBgYA0KDQpgYGB7ciwgbWVzc2FnZT1UUlVFLCBlY2hvPUZBTFNFfQ0KbG9uZ19zZXBhcmF0ZQ0KYGBgDQoNCk5vdywgV2UgaGF2ZSB0d28gY29sdW1ucywgb25lIGZvciBUYXJnZXQsIHRoZSB2YWx1ZXMgb2Ygd2hpY2ggYXJlIGFsbA0KIkZhY2UiLCBhbmQgb25lIGZvciBOdW1iZXIsIHdoaWNoIGluZGljYXRlcyB3aGljaCBvZiB0aGUgdGhyZWUgZmFjZXMgaXQNCmlzLg0KDQojIFVuaXRlDQoNClRvIHVuZG8gYHNlcGFyYXRlKClgLCB3ZSBjYW4gdXNlIGB1bml0ZSgpYCwgd2hpY2ggbWVyZ2VzIHR3byB2YXJpYWJsZXMNCmludG8gb25lLg0KDQpIZXJlIGlzIHRoZSBnZW5lcmljIGNvZGUgZm9yIGB1bml0ZSgpYDoNCg0KYGBge3IsIG1lc3NhZ2U9RkFMU0UsIGVjaG89VFJVRX0NCiN1bml0ZShkYXRhLCBjb2wsIC4uLiwgc2VwID0gIi4iLCByZW1vdmUgPSBUUlVFKQ0KYGBgDQoNCiMjIFVuaXRlKCkgQXJndW1lbnRzDQoNCkhlcmUgYXJlIHRoZSBhcnVnbWVudHMgdW5pcXVlIHRvIGB1bml0ZSgpYDoNCg0KLSAgIGBzZXBgOiBJbiB0aGUgY29kZSBmb3IgYHVuaXRlKClgIHRoZSBgc2VwYCBpbmRpY2F0ZWQgdGhlIHNlcGFyYXRvcg0KICAgIHdlIGNob29zZSB0byB0byB1c2UgdG8gYmluZCB2YWx1ZXMuIEluIHRoaXMgY2FzZSwgd2UgYXJlIHVzaW5nIGAuYA0KDQojIyBVc2luZyBVbml0ZSgpDQoNCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCBlY2hvPVRSVUV9DQpsb25nX3VuaXRlIDwtIGxvbmdfc2VwYXJhdGUgJT4lIHVuaXRlKEZhY2UsIFRhcmdldCwgTnVtYmVyLCBzZXAgPSAiLiIpDQpgYGANCg0KYGBge3IsIG1lc3NhZ2U9VFJVRSwgZWNobz1GQUxTRX0NCmxvbmdfdW5pdGUNCmBgYA0KDQpBcyB5b3UgY2FuIHNlZSB0aGUgZGF0YSBub3cgbG9va3MgbGlrZSBpdCBkaWQgd2hlbiB3ZSBmaXJzdCB0cmFuc2Zyb21lZA0KZnJvbSB3aWRlIHRvIGxvbmcgdXNpbmcgYGdhdGhlcigpYCENCg0KIyBTcHJlYWQNCg0KRmluYWxseSwgd2Ugd2lsbCB0cmFuc2Zvcm0gdGhlIGRhdGEgZnJvbSBsb25nIGJhY2sgdG8gd2lkZSB3aXRoIHRoZQ0KYHNwcmVhZCgpYCBmdW5jdGlvbi4NCg0KSGVyZSBpcyB0aGUgZ2VuZXJpYyBjb2RlIGZvciBgc3ByZWFkKClgDQoNCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCBlY2hvPVRSVUV9DQojc3ByZWFkKGRhdGEsIGtleSwgdmFsdWUsIGZpbGwgPSBOQSwgY29udmVydCA9IEZBTFNFLCBkcm9wID0gVFJVRSwgc2VwID0gTlVMTCkNCmBgYA0KDQojIyBTcHJlYWQoKSBBcmd1bWVudHMNCg0KVGhlIGFydWdtZW50cyB1bmlxdWUgdG8gYHNwcmVhZCgpYDoNCg0KLSAgIGBrZXlgOiBUaGUgdW5xdW90ZWQgbmFtZSBvZiB0aGUgY29sdW1uIHdob3NlIHZhbHVlcyB3aWxsIGJlIHVzZWQgYXMNCiAgICBjb2x1bW4gaGVhZGluZ3MuDQoNCi0gICBgdmFsdWVgOiBUaGUgdW5xdW90ZWQgbmFtZSBvZiB0aGUgY29sdW1uIHdob3NlIHZhbHVlcyB3aWxsIHBvcHVsYXRlDQogICAgdGhlIGNlbGxzLg0KDQotICAgYGZpbGxgOiBJZiB1c2VkLCBtaXNzaW5nIHZhbHVlcyB3aWxsIGJlIHJlcGxhY2VkIHdpdGggdGhpcyB2YWx1ZS4NCiAgICBUaGVyZSBhcmUgdHdvIHR5cGVzIG9mIG1pc3NpbmcgaW4gdGhlIGlucHV0OiBleHBsaWNpdCBtaXNzaW5nIHZhbHVlcw0KICAgIChpLmUuIGBOQWApLCBhbmQgaW1wbGljaXQgbWlzc2luZ3MsIHJvd3MgdGhhdCBzaW1wbHkgYXJlbid0IHByZXNlbnQuDQogICAgQm90aCB0eXBlcyBvZiBtaXNzaW5nIHZhbHVlIHdpbGwgYmUgcmVwbGFjZWQgYnkgYGZpbGxgLg0KDQotICAgYGNvbnZlcnRgOiBJZiBgVFJVRWAsIHRoaXMgd2lsbCBhdXRvbWF0aWNhbGx5IGNvbnZlcnQgdGhlIG5ldw0KICAgIGNvbHVtbnMgdG8gYSBsb2dpY2FsLCBpbnRlZ2VyLCBudW1lcmljLCBjb21wbGV4LCBvciBmYWN0b3IgYXMNCiAgICBhcHByb3ByaWF0ZS4NCg0KLSAgIGBkcm9wYDogSWYgYEZBTFNFYCwgd2lsbCBrZWVwIGZhY3RvciBsZXZlbHMgdGhhdCBkb24ndCBhcHBlYXIgaW4gdGhlDQogICAgZGF0YSwgZmlsbGluZyBpbiBtaXNzaW5nIGNvbWJpbmF0aW9ucyB3aXRoIGBmaWxsYC4NCg0KLSAgIGBzZXBgOiBJZiBgTlVMTGAsIHRoZSBjb2x1bW4gbmFtZXMgd2lsbCBiZSB0YWtlbiBmcm9tIHRoZSB2YWx1ZXMgb2YNCiAgICBrZXkgdmFyaWFibGUuIElmIG5vbi1gTlVMTGAsIHRoZSBjb2x1bW4gbmFtZXMgd2lsbCBiZSBjcmVhdGVkIGJ5DQogICAgc3RyaW5naW5nIHRvZ2V0aGVyIHRoZSBuYW1lLCBzZXBhcmF0b3IsIGFuZCB2YWx1ZS4NCg0KYGBge3IsIG1lc3NhZ2U9RkFMU0UsIGVjaG89VFJVRX0NCmJhY2tfdG9fd2lkZSA8LSBsb25nX3VuaXRlICU+JSBzcHJlYWQoRmFjZSwgUmVzcG9uc2VUaW1lKQ0KYGBgDQoNCmBgYHtyLCBtZXNzYWdlPVRSVUUsIGVjaG89RkFMU0V9DQpiYWNrX3RvX3dpZGUNCmBgYA0KDQpBbmQgdGhlcmUgd2UgaGF2ZSBpdCEgV2UgaGF2ZSBjb21lIGZ1bGwgY2lyY2xlIGJhY2sgaW50byB3aWRlLg0KDQojIENoYWxsZW5nZQ0KDQpOb3cgaXQncyB5b3VyIHR1cm4uIA0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyMgd2lkZSBmb3JtYXQNCmdhcF93aWRlIDwtIHJlYWRyOjpyZWFkX2NzdignaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2tmbGlzaWtvd3NraS9kcy9tYXN0ZXIvZ2FwbWluZGVyX3dpZGUuY3N2JykNCg0KIyMgbG9uZyBmb3JtYXQNCmdhcG1pbmRlciA8LSByZWFkcjo6cmVhZF9jc3YoJ2h0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9rZmxpc2lrb3dza2kvZHMvbWFzdGVyL2dhcG1pbmRlci5jc3YnKQ0KYGBgDQoNCkxldOKAmXMgaGF2ZSBhIGxvb2s6DQoNCmBgYHtyfQ0KaGVhZChnYXBfd2lkZSkNCnN0cihnYXBfd2lkZSkNCmBgYA0KDQpXaGlsZSB3aWRlIGZvcm1hdCBpcyBuaWNlIGZvciBkYXRhIGVudHJ5LCBpdCdzIG5vdCBuaWNlIGZvciBjYWxjdWxhdGlvbnMuIFNvbWUgb2YgdGhlIGNvbHVtbnMgYXJlIGEgbWl4IG9mIHZhcmlhYmxlIChlLmcuICJnZHBQZXJjYXAiKSBhbmQgZGF0YSAoIjE5NTIiKS4gV2hhdCBpZiB5b3Ugd2VyZSBhc2tlZCBmb3IgdGhlIG1lYW4gcG9wdWxhdGlvbiBhZnRlciAxOTkwIGluIEFsZ2VyaWE/IFBvc3NpYmxlLCBidXQgdWdseS4gQnV0IHdlIGtub3cgaXQgZG9lc24ndCBuZWVkIHRvIGJlIHNvIHVnbHkuIExldCdzIHRpZHkgaXQgYmFjayB0byB0aGUgZm9ybWF0IHdlJ3ZlIGJlZW4gdXNpbmcuDQoNCllvdXIgam9iIGlzIHRvIGdldCBpdCB0byBsb25nIGZvcm1hdC4gWW91IHdpbGwgaGF2ZSB0byBkbyB0aGlzIGluIDIgc3RlcHMuIFRoZSBmaXJzdCBzdGVwIGlzIHRvIHRha2UgYWxsIG9mIHRob3NlIGNvbHVtbiBuYW1lcyAoZS5nLiBsaWZlRXhwXzE5NzApIGFuZCBtYWtlIHRoZW0gYSB2YXJpYWJsZSBpbiBhIG5ldyBjb2x1bW4sIGFuZCB0cmFuc2ZlciB0aGUgdmFsdWVzIGludG8gYW5vdGhlciBjb2x1bW4uDQoNCldlIG5lZWQgdG8gbmFtZSB0d28gbmV3IHZhcmlhYmxlcyBpbiB0aGUga2V5LXZhbHVlIHBhaXIsIG9uZSBmb3IgdGhlIGtleSwgb25lIGZvciB0aGUgdmFsdWUuIEl0IGNhbiBiZSBoYXJkIHRvIHdyYXAgeW91ciBtaW5kIGFyb3VuZCB0aGlzLCBzbyBsZXQncyBnaXZlIGl0IGEgdHJ5LiBMZXQncyBuYW1lIHRoZW0gb2JzdHlwZV95ZWFyIGFuZCBvYnNfdmFsdWVzLg0KDQpgYGB7cn0NCmdhcF9sb25nIDwtIGdhcF93aWRlICU+JSANCiAgZ2F0aGVyKGtleSAgID0gb2JzdHlwZV95ZWFyLA0KICAgICAgICAgdmFsdWUgPSBvYnNfdmFsdWVzKQ0KYGBgDQoNCkFsdGhvdWdoIHdlIHdlcmUgYWxyZWFkeSBwbGFubmluZyB0byBpbnNwZWN0IG91ciB3b3JrLCBsZXQncyBkZWZpbml0ZWx5IGRvIGl0IG5vdzoNCg0KYGBge3J9DQpzdHIoZ2FwX2xvbmcpDQpgYGANCg0KQWx0aG91Z2ggd2Ugd2VyZSBhbHJlYWR5IHBsYW5uaW5nIHRvIGluc3BlY3Qgb3VyIHdvcmssIGxldCdzIGRlZmluaXRlbHkgZG8gaXQgbm93Og0KDQpgYGB7cn0NCnN0cihnYXBfbG9uZykNCmBgYA0KDQpXZSBoYXZlIHJlc2hhcGVkIG91ciBkYXRhZnJhbWUgYnV0IHRoaXMgbmV3IGZvcm1hdCBpc24ndCByZWFsbHkgd2hhdCB3ZSB3YW50ZWQuDQoNCldoYXQgd2VudCB3cm9uZz8gTm90aWNlIHRoYXQgaXQgZGlkbid0IGtub3cgdGhhdCB3ZSB3YW50ZWQgdG8ga2VlcCBjb250aW5lbnQgYW5kIGNvdW50cnkgdW50b3VjaGVkOyB3ZSBuZWVkIHRvIGdpdmUgaXQgbW9yZSBpbmZvcm1hdGlvbiBhYm91dCB3aGljaCBjb2x1bW5zIHdlIHdhbnQgcmVzaGFwZWQuIFdlIGNhbiBkbyB0aGlzIGluIHNldmVyYWwgd2F5cy4NCg0KT25lIHdheSBpcyB0byBpZGVudGlmeSB0aGUgY29sdW1ucyBpcyBieSBuYW1lLiBMaXN0aW5nIHRoZW0gZXhwbGljaXRseSBjYW4gYmUgYSBnb29kIGFwcHJvYWNoIGlmIHRoZXJlIGFyZSBqdXN0IGEgZmV3LiBCdXQgaW4gb3VyIGNhc2Ugd2UgaGF2ZSAzMCBjb2x1bW5zLiBJJ20gbm90IGdvaW5nIHRvIGxpc3QgdGhlbSBvdXQgaGVyZSBzaW5jZSB0aGVyZSBpcyB3YXkgdG9vIG11Y2ggcG90ZW50aWFsIGZvciBlcnJvciBpZiBJIHRyaWVkIHRvIGxpc3QgZ2RwUGVyY2FwXzE5NTIsIGdkcFBlcmNhcF8xOTU3LCBnZHBQZXJjYXBfMTk2MiBhbmQgc28gb24uIEJ1dCB3ZSBjb3VsZCB1c2Ugc29tZSBvZiBkcGx5cuKAmXMgYXdlc29tZSBoZWxwZXIgZnVuY3Rpb25zIOKAlCBiZWNhdXNlIHdlIGV4cGVjdCB0aGF0IHRoZXJlIGlzIGEgYmV0dGVyIHdheSB0byBkbyB0aGlzIQ0KDQpgYGB7cn0NCmdhcF9sb25nIDwtIGdhcF93aWRlICU+JSANCiAgZ2F0aGVyKGtleSAgID0gb2JzdHlwZV95ZWFyLA0KICAgICAgICAgdmFsdWUgPSBvYnNfdmFsdWVzLA0KICAgICAgICAgZHBseXI6OnN0YXJ0c193aXRoKCdwb3AnKSwNCiAgICAgICAgIGRwbHlyOjpzdGFydHNfd2l0aCgnbGlmZUV4cCcpLA0KICAgICAgICAgZHBseXI6OnN0YXJ0c193aXRoKCdnZHBQZXJjYXAnKSkgICNoZXJlIGknbSBsaXN0aW5nIGFsbCB0aGUgY29sdW1ucyB0byB1c2UgaW4gZ2F0aGVyDQoNCnN0cihnYXBfbG9uZykNCmhlYWQoZ2FwX2xvbmcpDQp0YWlsKGdhcF9sb25nKQ0KYGBgDQoNClN1Y2Nlc3MhIEFuZCB0aGVyZSBpcyBhbm90aGVyIHdheSB0aGF0IGlzIG5pY2UgdG8gdXNlIGlmIHlvdXIgY29sdW1ucyBkb24ndCBmb2xsb3cgc3VjaCBhIHN0cnVjdHVyZWQgcGF0dGVybjogeW91IGNhbiBleGNsdWRlIHRoZSBjb2x1bW5zIHlvdSBkb24ndCB3YW50Lg0KDQpgYGB7cn0NCmdhcF9sb25nIDwtIGdhcF93aWRlICU+JSANCiAgZ2F0aGVyKGtleSAgID0gb2JzdHlwZV95ZWFyLA0KICAgICAgICAgdmFsdWUgPSBvYnNfdmFsdWVzLA0KICAgICAgICAgLWNvbnRpbmVudCwgLWNvdW50cnkpDQoNCnN0cihnYXBfbG9uZykNCmhlYWQoZ2FwX2xvbmcpDQp0YWlsKGdhcF9sb25nKQ0KYGBgDQoNCiMjIEV4ZXJjaXNlIDEuDQoNClVzaW5nIGdhcF9sb25nLCBjYWxjdWxhdGUgdGhlIG1lYW4gbGlmZSBleHBlY3RhbmN5IGZvciBlYWNoIGNvbnRpbmVudCBvdmVyIHRpbWUgZnJvbSAxOTgyIHRvIDIwMDcuIA0KDQpgYGB7ciBleGVyY2lzZTF9DQoNCmBgYA0KDQojIyBFeGVyY2lzZSAyLg0KDQpDb252ZXJ0IGdhcF9sb25nIGFsbCB0aGUgd2F5IGJhY2sgdG8gZ2FwX3dpZGUuIEhpbnQ6IERvIHRoaXMgaW4gMiBzdGVwcy4gRmlyc3QsIGNyZWF0ZSBhcHByb3ByaWF0ZSBsYWJlbHMgZm9yIGFsbCBvdXIgbmV3IHZhcmlhYmxlcyAodmFyaWFibGVfeWVhciBjb21iaW5hdGlvbnMpIHdpdGggdGhlIG9wcG9zaXRlIG9mIHNlcGFyYXRlOiB0aWR5cjo6dW5pdGUoKS4gU2Vjb25kLCBzcHJlYWQoKSB0aGF0IHZhcmlhYmxlX3llYXIgY29sdW1uIGludG8gd2lkZXIgZm9ybWF0Lg0KDQpgYGB7ciBleGVyY2lzZTJ9DQpoZWFkKGdhcF9sb25nKSAjIHJlbWVtYmVyIHRoZSBjb2x1bW5zDQoNCmBgYA0KDQojIENvbXBsZXRlDQoNCk9uZSBvZiB0aGUgY29vbGVzdCBmdW5jdGlvbnMgaW4gdGlkeXIgaXMgdGhlIGZ1bmN0aW9uIGNvbXBsZXRlKCkuIFdl4oCZbGwgc3RhcnQgd2l0aCBhbiBleGFtcGxlIGRhdGFmcmFtZToNCg0KYGBge3J9DQpkZiA8LSBkYXRhLmZyYW1lKA0KICBZZWFyID0gYygxOTk5LCAyMDAwLCAyMDA0LCAxOTk5LCAyMDA0KSwNCiAgVmFyMSA9IGMoIkxhIiwgIkxhIiwgIkxhIiwgIk1pIiwgIk1pIiksDQogIFZhcjIgPSBjKDQsNSwyLDEsOCkNCikNCg0KZGYNCmBgYA0KDQoiTWkiIGlzIG5vdCBsaXN0ZWQgZm9yIHRoZSB5ZWFyIDIwMDAuDQoNCkRvZXMgdGhpcyBtZWFuIGl0IHdhc24ndCBvYnNlcnZlZCAoVmFyMiA9IDApIG9yIHRoYXQgaXQgd2Fzbid0IHJlY29yZGVkIChWYXIyID0gTkEpPyBPbmx5IHRoZSBwZXJzb24gd2hvIHJlY29yZGVkIHRoZSBkYXRhIGtub3dzLCBidXQgbGV0J3MgYXNzdW1lIHRoYXQgdGhpcyBtZWFucyB0aGUgVmFyMiB3YXMgMCBmb3IgdGhhdCB5ZWFyLg0KDQpXZSBjYW4gdXNlIHRoZSBjb21wbGV0ZSgpIGZ1bmN0aW9uIHRvIG1ha2Ugb3VyIGRhdGFzZXQgbW9yZSBjb21wbGV0ZS4NCg0KYGBge3J9DQpkZiAlPiUgDQogIGNvbXBsZXRlKFllYXIsIFZhcjEpDQpgYGANCg0KVGhpcyBnaXZlcyB1cyBhbiBOQSBmb3IgIk1pIiBpbiAyMDAwLCBidXQgd2Ugd2FudCBpdCB0byBiZSBhIDAgaW5zdGVhZC4gV2UgY2FuIHVzZSB0aGUgZmlsbCBhcmd1bWVudCB0byBhc3NpZ24gdGhlIGZpbGwgdmFsdWUuDQoNCmBgYHtyfQ0KZGYgJT4lIGNvbXBsZXRlKFllYXIsIFZhcjEsIGZpbGwgPSBsaXN0KFZhcjIgPSAwKSkNCmBgYA0KDQpOb3cgd2UgaGF2ZSB3aGF0IHdlIHdhbnQuIExldCdzIGFzc3VtZSB0aGF0IGFsbCB5ZWFycyBiZXR3ZWVuIDE5OTkgYW5kIDIwMDQgdGhhdCBhcmVuJ3QgbGlzdGVkIHNob3VsZCBhY3R1YWxseSBiZSBhc3NpZ25lZCBhIHZhbHVlIG9mIDAuIFdlIGNhbiB1c2UgdGhlIGZ1bGxfc2VxKCkgZnVuY3Rpb24gZnJvbSB0aWR5ciB0byBmaWxsIG91dCBvdXIgZGF0YXNldCB3aXRoIGFsbCB5ZWFycyAxOTk5LTIwMDQgYW5kIGFzc2lnbiBWYXIyIHZhbHVlcyBvZiAwIHRvIHRob3NlIHllYXJzICYgVmFyMSBmb3Igd2hpY2ggdGhlcmUgd2FzIG5vIG9ic2VydmF0aW9uLg0KDQpgYGB7cn0NCmRmICU+JSBjb21wbGV0ZShZZWFyID0gZnVsbF9zZXEoWWVhciwgcGVyaW9kID0gMSksDQogICAgICAgICAgICAgICAgICAgVmFyMSwNCiAgICAgICAgICAgICAgICAgICBmaWxsID0gbGlzdChWYXIyID0gMCkpDQpgYGANCg0KIyBSZWZlcmVuY2VzDQoNCi0gICA8aHR0cHM6Ly9wcmljZW9ub21pY3MuY29tL2hhZGxleS13aWNraGFtLXRoZS1tYW4td2hvLXJldm9sdXRpb25pemVkLXIvPg0KICAgIFwjIFdobyBpcyB0aGlzIEhhZGxleSBXaWNraGFtIGd1eT8NCg0KLSAgIDxodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvbWFncml0dHIvdmlnbmV0dGVzL21hZ3JpdHRyLmh0bWw+DQogICAgXCMgRnVydGhlciByZWFkaW5nIGFib3V0IGAlPiVgDQoNCi0gICA8aHR0cHM6Ly9ibG9nLnJzdHVkaW8ub3JnLzIwMTQvMDcvMjIvaW50cm9kdWNpbmctdGlkeXIvPiBcIyBIZWxwZnVsDQogICAgb3ZlcnZpZXcgb2YgdGlkeXINCg0KLSAgIDxodHRwOi8vYWRlbW9zLnBlb3BsZS51aWMuZWR1L0NoYXB0ZXI4Lmh0bWw+IFwjIFRpbSBDYXJzZWwncyBjaGFwdGVyDQogICAgb24gcmVzaGFwZTINCg0KLSAgIDxodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvdGlkeXIvdGlkeXIucGRmPiBcIyBBIGZ1bGwNCiAgICBndWlkZSBvZiB0aWR5IHIgYW5kIGFsbCB0aGUgYXJndW1lbnRzIGZvciBlYWNoIGZ1bmN0aW9uIG9mIHRoZQ0KICAgIHBhY2thZ2UNCg0KLSAgIDxodHRwOi8vZ2FycmV0dGdtYW4uZ2l0aHViLmlvL3RpZHlpbmcvPiBcIyBEaWZmZXJlbnQgdHlwZXMgb2YgbWVzc3kNCiAgICBkYXRhIGFuZCBob3cgdG8gZml4IHdpdGggdGlkeXINCg==