10.1 Introduction

Throughout this book we work with “tibbles” instead of R’s tranditional data.frame. Tibbles are data frames, but they weak some older behaviors to make life a little easier. R is an old language, and some things that were useful 10 or 20 years ago now get in your way. It’s difficult to change base R without breaking existing code, so most innovation occurs in packages. Here we will describe the tibble package, which provides opinionated data frames that make working in the tidyverse a little easier. In most places, I’ll use the term tibble and data frame interchangeably; when I want to draw particular attention to R’s built-in data frame, I’ll call them data.frame S.

If this chapter leaves you wanting to learn more about tilles, you might enjoy vignette(“tibble”).

10.1.1 Prerequisites

In this chapter we’ll explore the tibble package, part of the core tidyverse.

library(tidyverse)

10.2 Creating tibbles

Almost all of the functions that you’ll use in this book produce tibbles, as tibbles are one of the unifying features of the tidyverse. Most other R packages use regular data frames, so you might want to coerce a data frame to a tibble. You can do that with as_tibble():

as_tibble(iris)

You can create a new tibble from individual vectors with tibble(). tibble() will automatically recycle inputs of length 1, and allows you to refer to variables that you just created, as shown below.

tibble(
  x = 1:5,
  y = 1,
  z = x^2 + y
)

If you’re already familiar with data.frame(), note that tibble() does much less: it never changes the type of the inputs (e.g. it never converts strings to factors!), it never changes the names of variables, and it never creates row names.

It’s possible for a tibble to have column names that are not valid R variable names, aka non-syntatic names. For example, they might not start with a letter, or they might contain unusual characters like a space. To refer to these variables, you need to surround them with backticks, `:

tb <- tibble(
  `:)` = "smile",
  ` ` = "space",
  `2000` = "number"
)
tb

You’ll also need the backticks when working with these variables in other packages, like ggplot2, dplyr, and tidyr.

Another way to create a tibble is with tibble(), short for __tr__ansposed tibble. tribble() is customised for data entry in code: column headings are defined by formulas (i.e. they start with ~), and entries are separated by commas. This makes it possible to lay out small amouts of data in easy to read form.

tribble(
  ~x, ~y, ~z,
  #--|--|----
  "a", 2, 3.6,
  "b", 1, 8.5
)

10.3 Tibbles vs. data.frame

There are two main differences in the usage of a tibble vs. a classic data.frame: printing and subsetting.

10.3.1 Printing

Tibbles have a refined print method that shows only the first 10 rows, and all the columns that fit on screen. This makes it much easier to work with large data. In addition to its name, each column reports its type, a nice feature borrowed from str():

tibble(
  a = lubridate::now() + runif(1e3) * 86400,
  b = lubridate::today() + runif(1e3) * 30,
  c = 1:1e3,
  d = runif(1e3),
  e = sample(letters, 1e3, replace = TRUE)
)

Tibbles are designed so that you don’t accidentally overwhelm your console when you print large data frames. But sometimes you need more output than the default display. There are a few options that can help.

First, you can explicitly print() the data frame and control the number of rows (n) and the width of the display. width = Inf will display all columns.

nycflights13::flights %>%
  print(n = 10, width = Inf)

You can also control the default print behavior by setting options:

You can see a complete list of options by looking at the package help with package?tibble.

A final option is to use RStudio’s built-in data viewer to get a scrollable view of the complete dataset. This is also often useful at the end of a long chain of manipulations.

nycflights13::flights %>%
  View()

10.3.2 Subsetting

So far all the tools you’ve learned have worked with complete data frames. If you want to pull out a single variable, you need some new tools, \(__ and __[[__. __[[__ can extract by name or position, __\) only extracts by name but is a little less typing.

df <- tibble(
  x = runif(5),
  y = rnorm(5)
)

# Extract by name
df$x
[1] 0.1801147 0.9679416 0.4738654 0.8527135 0.2442153
df[["x"]]
[1] 0.1801147 0.9679416 0.4738654 0.8527135 0.2442153
# Extract by position
df[[1]]
[1] 0.1801147 0.9679416 0.4738654 0.8527135 0.2442153

To use these in a pipe, you’ll need to use the special placeholder .:

df %>% .$x
[1] 0.1801147 0.9679416 0.4738654 0.8527135 0.2442153
df %>%
  .[["x"]]
[1] 0.1801147 0.9679416 0.4738654 0.8527135 0.2442153

Compared to a data.frame, tibbles are more strict: they never do partial matching, and they will generate a warning if the column you are trying to access does not exist.

10.4 Interacting with older code

Some older functions don’t work with tibbles. If you encounter one of these functions, use as.data.frame() to turn a tibble back to a data.frame:

class(as.data.frame(tb))
[1] "data.frame"

The main reason that some older functions don’t work with tibble is the [ function. We don’t use [ much in this book because dplyr::filter() and dplyr::select() allow you to solve the same problems with clearer code (but you will learn a little about it in vector subsetting). With base R data frames, [ sometimes returns a data frame, and sometimes returns a vector. With tibbles, [ always returns another tibble.

10.5 Exercises

  1. How can you tell if an object is a tibble? (Hint: try printing mtcars, which is a regular data frame).
mtcars
as_tibble(mtcars)

I think because of my screen, there is not much of a noticeable difference. We know however that data frames will print all columns and not cap how many rows. Tibbles however are more compact and generally (assuming no prefernce overrides) will print the first ten rows and only as many columns as fit on the screen.

Interestingly, both tables produced show the type of data in each column - I thought data frames did not do this? Perhaps this is a unique feature of R notebook.

You can also use the is_tibble function to check.

is_tibble(mtcars)
[1] FALSE

More generally, you can use the class() function to find out the class of an object. Tibbles has classes c(“tbl_df”, “tbl”, “data.frame”), while old data frames will only have the class “data.frame”.

If you are interested in reading more on R’s classes, read the chapters on object oriented programming in Advanaced R.

  1. Compare and contrast the following operations on a data.frame and equivalent tibble What is different? Why might the default data frame behaviors cause you frustration?
df <- data.frame(abc = 1, xyz = "a")
df$x
[1] a
Levels: a
df[, "xyz"]
[1] a
Levels: a
df[, c("abc", "xyz")]
df2 <- tibble(abc = 1, xyz = "a")
df2$x
Unknown or uninitialised column: `x`.
NULL
df2[, "xyz"]
df2[, c("abc", "xyz")]

When using the $ operator, data frames will select any column that begins with the first letter. So in the first example, there is no column “x”, but because there is a column “xyz” - the data frame pulls the corresponding rows for that column. This may be helpful for lowering keystrokes, but it increases the risk of accidentally selecting a column you did not intend to.

  1. If you have the name of a variable stored in an object, e.g. var <- “mpg”, how can you extract the reference variable from a tibble?
df[[var]]
Error in .subset2(x, i, exact = exact) : invalid subscript type 'closure'
  1. Practice referring to non-syntactic names in the following data frame by:

  2. Extracting the variable called 1.
  3. Plotting a scatterplot of 1 vs 2.
  4. Creating a new column called 3 which is 2 divided by 1.
  5. Renaming the columns to one, two, and three.

annoying <- tibble(
  `1` = 1:10,
  `2` = `1` * 2 + rnorm(length(`1`))
)
annoying[[1]]
 [1]  1  2  3  4  5  6  7  8  9 10
annoying$`1`
 [1]  1  2  3  4  5  6  7  8  9 10
annoying[["1"]]
 [1]  1  2  3  4  5  6  7  8  9 10
ggplot(annoying, aes(`1`, `2`)) +
  geom_point()

annoying <- tibble(annoying, `3` = annoying$`2`/annoying$`1`)
annoying
annoying <- rename(annoying, one = `1`, two = `2`, three = `3`)
annoying
  1. What does tibble::enframe() do? When might you use it?
?tibble::enframe

enframe() converts vectors to data frames, and vice versa.

enframe() converts named atomic vectors or lists to one- or two-column data frames. For a list, the result will be a nested tibble with a column of type list. For unnamed vectors, the natural sequence is used as name column.

deframe() converts two-column data frames to a named vector or list, using the first column as name and the second column as value. If the input has only one column, and unnamed vector is returned.

enframe(c(a = 1, b = 2, c = 3))

This would be useful if you had a series of vectors that you needed to use to construct a data frame. For example, in the df above, if you had a bunch of vectors containg car data, you could create a useful dataset with all the vectors.

  1. What option controls how many additional column names are printed at the footer of a tibble?
LS0tCnRpdGxlOiAiQ2ggMTAgLSBUaWJibGVzIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgojIyMjIDEwLjEgSW50cm9kdWN0aW9uCgpUaHJvdWdob3V0IHRoaXMgYm9vayB3ZSB3b3JrIHdpdGggInRpYmJsZXMiIGluc3RlYWQgb2YgUidzIHRyYW5kaXRpb25hbCBfX2RhdGEuZnJhbWVfXy4KVGliYmxlcyAqYXJlKiBkYXRhIGZyYW1lcywgYnV0IHRoZXkgd2VhayBzb21lIG9sZGVyIGJlaGF2aW9ycyB0byBtYWtlIGxpZmUgYSBsaXR0bGUgZWFzaWVyLiBSIGlzIGFuIG9sZCBsYW5ndWFnZSwgYW5kIHNvbWUgdGhpbmdzIHRoYXQgd2VyZSB1c2VmdWwgMTAgb3IgMjAgeWVhcnMgYWdvIG5vdyBnZXQgaW4geW91ciB3YXkuIEl0J3MgZGlmZmljdWx0IHRvIGNoYW5nZSBiYXNlIFIgd2l0aG91dCBicmVha2luZyBleGlzdGluZyBjb2RlLCBzbyBtb3N0IGlubm92YXRpb24gb2NjdXJzIGluIHBhY2thZ2VzLiBIZXJlIHdlIHdpbGwgZGVzY3JpYmUgdGhlIF9fdGliYmxlX18gcGFja2FnZSwgd2hpY2ggcHJvdmlkZXMgb3BpbmlvbmF0ZWQgZGF0YSBmcmFtZXMgdGhhdCBtYWtlIHdvcmtpbmcgaW4gdGhlIHRpZHl2ZXJzZSBhIGxpdHRsZSBlYXNpZXIuIEluIG1vc3QgcGxhY2VzLCBJJ2xsIHVzZSB0aGUgdGVybSB0aWJibGUgYW5kIGRhdGEgZnJhbWUgaW50ZXJjaGFuZ2VhYmx5OyB3aGVuIEkgd2FudCB0byBkcmF3IHBhcnRpY3VsYXIgYXR0ZW50aW9uIHRvIFIncyBidWlsdC1pbiBkYXRhIGZyYW1lLCBJJ2xsIGNhbGwgdGhlbSBfX2RhdGEuZnJhbWUgU19fLgoKSWYgdGhpcyBjaGFwdGVyIGxlYXZlcyB5b3Ugd2FudGluZyB0byBsZWFybiBtb3JlIGFib3V0IHRpbGxlcywgeW91IG1pZ2h0IGVuam95IF9fdmlnbmV0dGUoInRpYmJsZSIpX18uCgojIyMjIDEwLjEuMSBQcmVyZXF1aXNpdGVzCgpJbiB0aGlzIGNoYXB0ZXIgd2UnbGwgZXhwbG9yZSB0aGUgX190aWJibGVfXyBwYWNrYWdlLCBwYXJ0IG9mIHRoZSBjb3JlIHRpZHl2ZXJzZS4KCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKYGBgCgojIyMjIDEwLjIgQ3JlYXRpbmcgdGliYmxlcwoKQWxtb3N0IGFsbCBvZiB0aGUgZnVuY3Rpb25zIHRoYXQgeW91J2xsIHVzZSBpbiB0aGlzIGJvb2sgcHJvZHVjZSB0aWJibGVzLCBhcyB0aWJibGVzIGFyZSBvbmUgb2YgdGhlIHVuaWZ5aW5nIGZlYXR1cmVzIG9mIHRoZSB0aWR5dmVyc2UuIE1vc3Qgb3RoZXIgUiBwYWNrYWdlcyB1c2UgcmVndWxhciBkYXRhIGZyYW1lcywgc28geW91IG1pZ2h0IHdhbnQgdG8gY29lcmNlIGEgZGF0YSBmcmFtZSB0byBhIHRpYmJsZS4gWW91IGNhbiBkbyB0aGF0IHdpdGggX19hc190aWJibGUoKV9fOgoKYGBge3J9CmFzX3RpYmJsZShpcmlzKQpgYGAKCllvdSBjYW4gY3JlYXRlIGEgbmV3IHRpYmJsZSBmcm9tIGluZGl2aWR1YWwgdmVjdG9ycyB3aXRoIF9fdGliYmxlKClfXy4gX190aWJibGUoKV9fIHdpbGwgYXV0b21hdGljYWxseSByZWN5Y2xlIGlucHV0cyBvZiBsZW5ndGggMSwgYW5kIGFsbG93cyB5b3UgdG8gcmVmZXIgdG8gdmFyaWFibGVzIHRoYXQgeW91IGp1c3QgY3JlYXRlZCwgYXMgc2hvd24gYmVsb3cuCgpgYGB7cn0KdGliYmxlKAogIHggPSAxOjUsCiAgeSA9IDEsCiAgeiA9IHheMiArIHkKKQpgYGAKCklmIHlvdSdyZSBhbHJlYWR5IGZhbWlsaWFyIHdpdGggX19kYXRhLmZyYW1lKClfXywgbm90ZSB0aGF0IF9fdGliYmxlKClfXyBkb2VzIG11Y2ggbGVzczogaXQgbmV2ZXIgY2hhbmdlcyB0aGUgdHlwZSBvZiB0aGUgaW5wdXRzIChlLmcuIGl0IG5ldmVyIGNvbnZlcnRzIHN0cmluZ3MgdG8gZmFjdG9ycyEpLCBpdCBuZXZlciBjaGFuZ2VzIHRoZSBuYW1lcyBvZiB2YXJpYWJsZXMsIGFuZCBpdCBuZXZlciBjcmVhdGVzIHJvdyBuYW1lcy4KCkl0J3MgcG9zc2libGUgZm9yIGEgdGliYmxlIHRvIGhhdmUgY29sdW1uIG5hbWVzIHRoYXQgYXJlIG5vdCB2YWxpZCBSIHZhcmlhYmxlIG5hbWVzLCBha2EgX19ub24tc3ludGF0aWNfXyBuYW1lcy4gRm9yIGV4YW1wbGUsIHRoZXkgbWlnaHQgbm90IHN0YXJ0IHdpdGggYSBsZXR0ZXIsIG9yIHRoZXkgbWlnaHQgY29udGFpbiB1bnVzdWFsIGNoYXJhY3RlcnMgbGlrZSBhIHNwYWNlLiBUbyByZWZlciB0byB0aGVzZSB2YXJpYWJsZXMsIHlvdSBuZWVkIHRvIHN1cnJvdW5kIHRoZW0gd2l0aCBiYWNrdGlja3MsIF9fYF9fOgoKYGBge3J9CnRiIDwtIHRpYmJsZSgKICBgOilgID0gInNtaWxlIiwKICBgIGAgPSAic3BhY2UiLAogIGAyMDAwYCA9ICJudW1iZXIiCikKdGIKYGBgCgpZb3UnbGwgYWxzbyBuZWVkIHRoZSBiYWNrdGlja3Mgd2hlbiB3b3JraW5nIHdpdGggdGhlc2UgdmFyaWFibGVzIGluIG90aGVyIHBhY2thZ2VzLCBsaWtlIGdncGxvdDIsIGRwbHlyLCBhbmQgdGlkeXIuCgpBbm90aGVyIHdheSB0byBjcmVhdGUgYSB0aWJibGUgaXMgd2l0aCBfX3RpYmJsZSgpX18sIHNob3J0IGZvciBfX3RyX19hbnNwb3NlZCB0aWJibGUuIF9fdHJpYmJsZSgpX18gaXMgY3VzdG9taXNlZCBmb3IgZGF0YSBlbnRyeSBpbiBjb2RlOiBjb2x1bW4gaGVhZGluZ3MgYXJlIGRlZmluZWQgYnkgZm9ybXVsYXMgKGkuZS4gdGhleSBzdGFydCB3aXRoIF9ffl9fKSwgYW5kIGVudHJpZXMgYXJlIHNlcGFyYXRlZCBieSBjb21tYXMuIFRoaXMgbWFrZXMgaXQgcG9zc2libGUgdG8gbGF5IG91dCBzbWFsbCBhbW91dHMgb2YgZGF0YSBpbiBlYXN5IHRvIHJlYWQgZm9ybS4KCmBgYHtyfQp0cmliYmxlKAogIH54LCB+eSwgfnosCiAgIy0tfC0tfC0tLS0KICAiYSIsIDIsIDMuNiwKICAiYiIsIDEsIDguNQopCmBgYAoKIyMjIyAxMC4zIFRpYmJsZXMgdnMuIGRhdGEuZnJhbWUKClRoZXJlIGFyZSB0d28gbWFpbiBkaWZmZXJlbmNlcyBpbiB0aGUgdXNhZ2Ugb2YgYSB0aWJibGUgdnMuIGEgY2xhc3NpYyBfX2RhdGEuZnJhbWVfXzogcHJpbnRpbmcgYW5kIHN1YnNldHRpbmcuCgojIyMjIDEwLjMuMSBQcmludGluZwoKVGliYmxlcyBoYXZlIGEgcmVmaW5lZCBwcmludCBtZXRob2QgdGhhdCBzaG93cyBvbmx5IHRoZSBmaXJzdCAxMCByb3dzLCBhbmQgYWxsIHRoZSBjb2x1bW5zIHRoYXQgZml0IG9uIHNjcmVlbi4gVGhpcyBtYWtlcyBpdCBtdWNoIGVhc2llciB0byB3b3JrIHdpdGggbGFyZ2UgZGF0YS4gSW4gYWRkaXRpb24gdG8gaXRzIG5hbWUsIGVhY2ggY29sdW1uIHJlcG9ydHMgaXRzIHR5cGUsIGEgbmljZSBmZWF0dXJlIGJvcnJvd2VkIGZyb20gX19zdHIoKV9fOgoKYGBge3J9CnRpYmJsZSgKICBhID0gbHVicmlkYXRlOjpub3coKSArIHJ1bmlmKDFlMykgKiA4NjQwMCwKICBiID0gbHVicmlkYXRlOjp0b2RheSgpICsgcnVuaWYoMWUzKSAqIDMwLAogIGMgPSAxOjFlMywKICBkID0gcnVuaWYoMWUzKSwKICBlID0gc2FtcGxlKGxldHRlcnMsIDFlMywgcmVwbGFjZSA9IFRSVUUpCikKYGBgCgpUaWJibGVzIGFyZSBkZXNpZ25lZCBzbyB0aGF0IHlvdSBkb24ndCBhY2NpZGVudGFsbHkgb3ZlcndoZWxtIHlvdXIgY29uc29sZSB3aGVuIHlvdSBwcmludCBsYXJnZSBkYXRhIGZyYW1lcy4gQnV0IHNvbWV0aW1lcyB5b3UgIG5lZWQgbW9yZSBvdXRwdXQgdGhhbiB0aGUgZGVmYXVsdCBkaXNwbGF5LiBUaGVyZSBhcmUgYSBmZXcgb3B0aW9ucyB0aGF0IGNhbiBoZWxwLgoKRmlyc3QsIHlvdSBjYW4gZXhwbGljaXRseSBfX3ByaW50KClfXyB0aGUgZGF0YSBmcmFtZSBhbmQgY29udHJvbCB0aGUgbnVtYmVyIG9mIHJvd3MgKF9fbl9fKSBhbmQgdGhlIF9fd2lkdGhfXyBvZiB0aGUgZGlzcGxheS4gX193aWR0aCA9IEluZl9fIHdpbGwgZGlzcGxheSBhbGwgY29sdW1ucy4gCgpgYGB7cn0KbnljZmxpZ2h0czEzOjpmbGlnaHRzICU+JQogIHByaW50KG4gPSAxMCwgd2lkdGggPSBJbmYpCmBgYAoKWW91IGNhbiBhbHNvIGNvbnRyb2wgdGhlIGRlZmF1bHQgcHJpbnQgYmVoYXZpb3IgYnkgc2V0dGluZyBvcHRpb25zOgoKKiBfX29wdGlvbnModGliYmxlLnByaW50X21heCA9IG4sIHRpYmJsZS5wcmludF9taW4gPSBtKV9fOiBpZiBtb3JlIHRoYW4gX19uX18gcm93cywgcHJpbnQgb25seSBfX21fXyByb3dzLiBVc2UgX19vcHRpb25zKHRpYmJsZS5wcmludF9taW4gPSBJbmYpX18gdG8gYWx3YXlzIHNob3cgYWxsIHJvd3MuCgoqIFVzZSBfX29wdGlvbnModGliYmxlLndpZHRoID0gSW5mKV9fIHRvIGFsd2F5cyBwcmludCBhbGwgY29sdW1ucywgcmVnYXJkbGVzcyBvZiB0aGUgd2lkdGggb2YgdGhlIHNjcmVlbi4KCllvdSBjYW4gc2VlIGEgY29tcGxldGUgbGlzdCBvZiBvcHRpb25zIGJ5IGxvb2tpbmcgYXQgdGhlIHBhY2thZ2UgaGVscCB3aXRoIF9fcGFja2FnZT90aWJibGVfXy4KCkEgZmluYWwgb3B0aW9uIGlzIHRvIHVzZSBSU3R1ZGlvJ3MgYnVpbHQtaW4gZGF0YSB2aWV3ZXIgdG8gZ2V0IGEgc2Nyb2xsYWJsZSB2aWV3IG9mIHRoZSBjb21wbGV0ZSBkYXRhc2V0LiBUaGlzIGlzIGFsc28gb2Z0ZW4gdXNlZnVsIGF0IHRoZSBlbmQgb2YgYSBsb25nIGNoYWluIG9mIG1hbmlwdWxhdGlvbnMuCgpgYGB7cn0KbnljZmxpZ2h0czEzOjpmbGlnaHRzICU+JQogIFZpZXcoKQpgYGAKCiMjIyMgMTAuMy4yIFN1YnNldHRpbmcKClNvIGZhciBhbGwgdGhlIHRvb2xzIHlvdSd2ZSBsZWFybmVkIGhhdmUgd29ya2VkIHdpdGggY29tcGxldGUgZGF0YSBmcmFtZXMuIElmIHlvdSB3YW50IHRvIHB1bGwgb3V0IGEgc2luZ2xlIHZhcmlhYmxlLCB5b3UgbmVlZCBzb21lIG5ldyB0b29scywgX18kX18gYW5kIF9fW1tfXy4gX19bW19fIGNhbiBleHRyYWN0IGJ5IG5hbWUgb3IgcG9zaXRpb24sIF9fJF9fIG9ubHkgZXh0cmFjdHMgYnkgbmFtZSBidXQgaXMgYSBsaXR0bGUgbGVzcyB0eXBpbmcuCgpgYGB7cn0KZGYgPC0gdGliYmxlKAogIHggPSBydW5pZig1KSwKICB5ID0gcm5vcm0oNSkKKQoKIyBFeHRyYWN0IGJ5IG5hbWUKZGYkeAoKZGZbWyJ4Il1dCgojIEV4dHJhY3QgYnkgcG9zaXRpb24KZGZbWzFdXQpgYGAKClRvIHVzZSB0aGVzZSBpbiBhIHBpcGUsIHlvdSdsbCBuZWVkIHRvIHVzZSB0aGUgc3BlY2lhbCBwbGFjZWhvbGRlciBfXy5fXzoKCmBgYHtyfQpkZiAlPiUgLiR4CmRmICU+JQogIC5bWyJ4Il1dCmBgYAoKQ29tcGFyZWQgdG8gYSBfX2RhdGEuZnJhbWVfXywgdGliYmxlcyBhcmUgbW9yZSBzdHJpY3Q6IHRoZXkgbmV2ZXIgZG8gcGFydGlhbCBtYXRjaGluZywgYW5kIHRoZXkgd2lsbCBnZW5lcmF0ZSBhIHdhcm5pbmcgaWYgdGhlIGNvbHVtbiB5b3UgYXJlIHRyeWluZyB0byBhY2Nlc3MgZG9lcyBub3QgZXhpc3QuCgojIyMjIDEwLjQgSW50ZXJhY3Rpbmcgd2l0aCBvbGRlciBjb2RlCgpTb21lIG9sZGVyIGZ1bmN0aW9ucyBkb24ndCB3b3JrIHdpdGggdGliYmxlcy4gSWYgeW91IGVuY291bnRlciBvbmUgb2YgdGhlc2UgZnVuY3Rpb25zLCB1c2UgX19hcy5kYXRhLmZyYW1lKClfXyB0byB0dXJuIGEgdGliYmxlIGJhY2sgdG8gYSBfX2RhdGEuZnJhbWVfXzoKCmBgYHtyfQpjbGFzcyhhcy5kYXRhLmZyYW1lKHRiKSkKYGBgCgpUaGUgbWFpbiByZWFzb24gdGhhdCBzb21lIG9sZGVyIGZ1bmN0aW9ucyBkb24ndCB3b3JrIHdpdGggdGliYmxlIGlzIHRoZSBfX1tfXyBmdW5jdGlvbi4gV2UgZG9uJ3QgdXNlIF9fW19fIG11Y2ggaW4gdGhpcyBib29rIGJlY2F1c2UgX19kcGx5cjo6ZmlsdGVyKClfXyBhbmQgX19kcGx5cjo6c2VsZWN0KClfXyBhbGxvdyB5b3UgdG8gc29sdmUgdGhlIHNhbWUgcHJvYmxlbXMgd2l0aCBjbGVhcmVyIGNvZGUgKGJ1dCB5b3Ugd2lsbCBsZWFybiBhIGxpdHRsZSBhYm91dCBpdCBpbiBfX3ZlY3RvciBzdWJzZXR0aW5nX18pLiBXaXRoIGJhc2UgUiBkYXRhIGZyYW1lcywgX19bX18gc29tZXRpbWVzIHJldHVybnMgYSBkYXRhIGZyYW1lLCBhbmQgc29tZXRpbWVzIHJldHVybnMgYSB2ZWN0b3IuIFdpdGggdGliYmxlcywgX19bX18gYWx3YXlzIHJldHVybnMgYW5vdGhlciB0aWJibGUuCgojIyMjIDEwLjUgRXhlcmNpc2VzCgoxLiBIb3cgY2FuIHlvdSB0ZWxsIGlmIGFuIG9iamVjdCBpcyBhIHRpYmJsZT8gKEhpbnQ6IHRyeSBwcmludGluZyBfX210Y2Fyc19fLCB3aGljaCBpcyBhIHJlZ3VsYXIgZGF0YSBmcmFtZSkuCgpgYGB7cn0KbXRjYXJzCmFzX3RpYmJsZShtdGNhcnMpCmBgYAoKSSB0aGluayBiZWNhdXNlIG9mIG15IHNjcmVlbiwgdGhlcmUgaXMgbm90IG11Y2ggb2YgYSBub3RpY2VhYmxlIGRpZmZlcmVuY2UuIFdlIGtub3cgaG93ZXZlciB0aGF0IGRhdGEgZnJhbWVzIHdpbGwgcHJpbnQgYWxsIGNvbHVtbnMgYW5kIG5vdCBjYXAgaG93IG1hbnkgcm93cy4gVGliYmxlcyBob3dldmVyIGFyZSBtb3JlIGNvbXBhY3QgYW5kIGdlbmVyYWxseSAoYXNzdW1pbmcgbm8gcHJlZmVybmNlIG92ZXJyaWRlcykgd2lsbCBwcmludCB0aGUgZmlyc3QgdGVuIHJvd3MgYW5kIG9ubHkgYXMgbWFueSBjb2x1bW5zIGFzIGZpdCBvbiB0aGUgc2NyZWVuLgoKSW50ZXJlc3RpbmdseSwgYm90aCB0YWJsZXMgcHJvZHVjZWQgc2hvdyB0aGUgdHlwZSBvZiBkYXRhIGluIGVhY2ggY29sdW1uIC0gSSB0aG91Z2h0IGRhdGEgZnJhbWVzIGRpZCBub3QgZG8gdGhpcz8gUGVyaGFwcyB0aGlzIGlzIGEgdW5pcXVlIGZlYXR1cmUgb2YgUiBub3RlYm9vay4KCllvdSBjYW4gYWxzbyB1c2UgdGhlIF9faXNfdGliYmxlX18gZnVuY3Rpb24gdG8gY2hlY2suCgpgYGB7cn0KaXNfdGliYmxlKG10Y2FycykKYGBgCgpNb3JlIGdlbmVyYWxseSwgeW91IGNhbiB1c2UgdGhlIF9fY2xhc3MoKV9fIGZ1bmN0aW9uIHRvIGZpbmQgb3V0IHRoZSBjbGFzcyBvZiBhbiBvYmplY3QuIFRpYmJsZXMgaGFzIGNsYXNzZXMgX19jKCJ0YmxfZGYiLCAidGJsIiwgImRhdGEuZnJhbWUiKV9fLCB3aGlsZSBvbGQgZGF0YSBmcmFtZXMgd2lsbCBvbmx5IGhhdmUgdGhlIGNsYXNzIF9fImRhdGEuZnJhbWUiX18uCgpJZiB5b3UgYXJlIGludGVyZXN0ZWQgaW4gcmVhZGluZyBtb3JlIG9uIFIncyBjbGFzc2VzLCByZWFkIHRoZSBjaGFwdGVycyBvbiBvYmplY3Qgb3JpZW50ZWQgcHJvZ3JhbW1pbmcgaW4gX19BZHZhbmFjZWQgUl9fLiAKCjIuIENvbXBhcmUgYW5kIGNvbnRyYXN0IHRoZSBmb2xsb3dpbmcgb3BlcmF0aW9ucyBvbiBhIF9fZGF0YS5mcmFtZV9fIGFuZCBlcXVpdmFsZW50IHRpYmJsZSBXaGF0IGlzIGRpZmZlcmVudD8gV2h5IG1pZ2h0IHRoZSBkZWZhdWx0IGRhdGEgZnJhbWUgYmVoYXZpb3JzIGNhdXNlIHlvdSBmcnVzdHJhdGlvbj8KCmBgYHtyfQpkZiA8LSBkYXRhLmZyYW1lKGFiYyA9IDEsIHh5eiA9ICJhIikKZGYkeApkZlssICJ4eXoiXQpkZlssIGMoImFiYyIsICJ4eXoiKV0KYGBgCgpgYGB7cn0KZGYyIDwtIHRpYmJsZShhYmMgPSAxLCB4eXogPSAiYSIpCmRmMiR4CmRmMlssICJ4eXoiXQpkZjJbLCBjKCJhYmMiLCAieHl6IildCmBgYAoKV2hlbiB1c2luZyB0aGUgX18kX18gb3BlcmF0b3IsIGRhdGEgZnJhbWVzIHdpbGwgc2VsZWN0IGFueSBjb2x1bW4gdGhhdCBiZWdpbnMgd2l0aCB0aGUgZmlyc3QgbGV0dGVyLiBTbyBpbiB0aGUgZmlyc3QgZXhhbXBsZSwgdGhlcmUgaXMgbm8gY29sdW1uICJ4IiwgYnV0IGJlY2F1c2UgdGhlcmUgaXMgYSBjb2x1bW4gInh5eiIgLSB0aGUgZGF0YSBmcmFtZSBwdWxscyB0aGUgY29ycmVzcG9uZGluZyByb3dzIGZvciB0aGF0IGNvbHVtbi4gVGhpcyBtYXkgYmUgaGVscGZ1bCBmb3IgbG93ZXJpbmcga2V5c3Ryb2tlcywgYnV0IGl0IGluY3JlYXNlcyB0aGUgcmlzayBvZiBhY2NpZGVudGFsbHkgc2VsZWN0aW5nIGEgY29sdW1uIHlvdSBkaWQgbm90IGludGVuZCB0by4KCjMuIElmIHlvdSBoYXZlIHRoZSBuYW1lIG9mIGEgdmFyaWFibGUgc3RvcmVkIGluIGFuIG9iamVjdCwgZS5nLiBfX3ZhciA8LSAibXBnIl9fLCBob3cgY2FuIHlvdSBleHRyYWN0IHRoZSByZWZlcmVuY2UgdmFyaWFibGUgZnJvbSBhIHRpYmJsZT8KCmBgYHtyfQpkZltbdmFyXV0KYGBgCgo0LiBQcmFjdGljZSByZWZlcnJpbmcgdG8gbm9uLXN5bnRhY3RpYyBuYW1lcyBpbiB0aGUgZm9sbG93aW5nIGRhdGEgZnJhbWUgYnk6CgoxLiBFeHRyYWN0aW5nIHRoZSB2YXJpYWJsZSBjYWxsZWQgMS4KMi4gUGxvdHRpbmcgYSBzY2F0dGVycGxvdCBvZiBfXzFfXyB2cyBfXzJfXy4KMy4gQ3JlYXRpbmcgYSBuZXcgY29sdW1uIGNhbGxlZCBfXzNfXyB3aGljaCBpcyBfXzJfXyBkaXZpZGVkIGJ5IF9fMV9fLgo0LiBSZW5hbWluZyB0aGUgY29sdW1ucyB0byBfX29uZV9fLCBfX3R3b19fLCBhbmQgX190aHJlZV9fLgoKYGBge3J9CmFubm95aW5nIDwtIHRpYmJsZSgKICBgMWAgPSAxOjEwLAogIGAyYCA9IGAxYCAqIDIgKyBybm9ybShsZW5ndGgoYDFgKSkKKQpgYGAKCmBgYHtyfQphbm5veWluZ1tbMV1dCmFubm95aW5nJGAxYAphbm5veWluZ1tbIjEiXV0KYGBgCgpgYGB7cn0KZ2dwbG90KGFubm95aW5nLCBhZXMoYDFgLCBgMmApKSArCiAgZ2VvbV9wb2ludCgpCmBgYAoKYGBge3J9CmFubm95aW5nIDwtIHRpYmJsZShhbm5veWluZywgYDNgID0gYW5ub3lpbmckYDJgL2Fubm95aW5nJGAxYCkKYGBgCgpgYGB7cn0KYW5ub3lpbmcKYGBgCgpgYGB7cn0KYW5ub3lpbmcgPC0gcmVuYW1lKGFubm95aW5nLCBvbmUgPSBgMWAsIHR3byA9IGAyYCwgdGhyZWUgPSBgM2ApCmBgYAoKYGBge3J9CmFubm95aW5nCmBgYAoKNS4gV2hhdCBkb2VzIF9fdGliYmxlOjplbmZyYW1lKClfXyBkbz8gV2hlbiBtaWdodCB5b3UgdXNlIGl0PwoKYGBge3J9Cj90aWJibGU6OmVuZnJhbWUKYGBgCgplbmZyYW1lKCkgY29udmVydHMgdmVjdG9ycyB0byBkYXRhIGZyYW1lcywgYW5kIHZpY2UgdmVyc2EuCgplbmZyYW1lKCkgY29udmVydHMgbmFtZWQgYXRvbWljIHZlY3RvcnMgb3IgbGlzdHMgdG8gb25lLSBvciB0d28tY29sdW1uIGRhdGEgZnJhbWVzLiBGb3IgYSBsaXN0LCB0aGUgcmVzdWx0IHdpbGwgYmUgYSBuZXN0ZWQgdGliYmxlIHdpdGggYSBjb2x1bW4gb2YgdHlwZSBsaXN0LiBGb3IgdW5uYW1lZCB2ZWN0b3JzLCB0aGUgbmF0dXJhbCBzZXF1ZW5jZSBpcyB1c2VkIGFzIG5hbWUgY29sdW1uLgoKZGVmcmFtZSgpIGNvbnZlcnRzIHR3by1jb2x1bW4gZGF0YSBmcmFtZXMgdG8gYSBuYW1lZCB2ZWN0b3Igb3IgbGlzdCwgdXNpbmcgdGhlIGZpcnN0IGNvbHVtbiBhcyBuYW1lIGFuZCB0aGUgc2Vjb25kIGNvbHVtbiBhcyB2YWx1ZS4gSWYgdGhlIGlucHV0IGhhcyBvbmx5IG9uZSBjb2x1bW4sIGFuZCB1bm5hbWVkIHZlY3RvciBpcyByZXR1cm5lZC4KCmBgYHtyfQplbmZyYW1lKGMoYSA9IDEsIGIgPSAyLCBjID0gMykpCmBgYAoKVGhpcyB3b3VsZCBiZSB1c2VmdWwgaWYgeW91IGhhZCBhIHNlcmllcyBvZiB2ZWN0b3JzIHRoYXQgeW91IG5lZWRlZCB0byB1c2UgdG8gY29uc3RydWN0IGEgZGF0YSBmcmFtZS4gRm9yIGV4YW1wbGUsIGluIHRoZSBkZiBhYm92ZSwgaWYgeW91IGhhZCBhIGJ1bmNoIG9mIHZlY3RvcnMgY29udGFpbmcgY2FyIGRhdGEsIHlvdSBjb3VsZCBjcmVhdGUgYSB1c2VmdWwgZGF0YXNldCB3aXRoIGFsbCB0aGUgdmVjdG9ycy4KCjYuIFdoYXQgb3B0aW9uIGNvbnRyb2xzIGhvdyBtYW55IGFkZGl0aW9uYWwgY29sdW1uIG5hbWVzIGFyZSBwcmludGVkIGF0IHRoZSBmb290ZXIgb2YgYSB0aWJibGU/CgoKCg==