Chapter 16 Vectors
Pre requisites: purrr package. Installed when you call the tidyverse package.
Vector Basics
There are two types of vectors: Atomic vectors, of which there are six types: logical, integer, double, character, complex and raw. Ineger and double vectors are collectively known as numeric vectors
Lists, which are sometimes called rcursive vectors becasue lists can contain other lists!
The main difference between atomic and lists is that atomic vectorsa re homogenerous, while list can be heterogeneous. There’s one other related object: NULL. NULL is often used to represent the absence of a vector. As opposed to NA, which is used to represent the absence of a value in a vector. NULL typically behaves like a vector of length 0.

Every vector has two key properties:
Its type, which you can determine with typeof().
typeof(letters)
[1] "character"
typeof(1:10)
[1] "integer"
Its length, which you can determine with length().
x <- list("a", "b", 1:10)
length(x)
[1] 3
Vectors can also contain arbitrary additional metadata in the form of attributes. These attributes are used to create augmented vectors which build on additional behaviour.
There are four important types of augmented vector:
Factors are built on top of integer vectors. Dates and date-times are built on top of numeric vectors. Data frames and tibbles are built on top of lists.
This chapter will introduce you to these important vectors from simplest to most complicated. You’ll start with atomic vectors, then build up to lists, and finish off with augmented vectors.
Important Types of atomic vector
Logical
Logical vectors are the simplest type of atomic vector because they can take only three possible values: FALSE, TRUE, and NA. Logical vectors are usually constructed with comparison operators, as described in comparisons. You can also create them by hand with c():
1:10 %% 3 == 0
[1] FALSE FALSE TRUE FALSE FALSE TRUE FALSE FALSE TRUE FALSE
c(TRUE, TRUE, FALSE, NA)
[1] TRUE TRUE FALSE NA
Numeric
Integer and double vectors are known collectively as numeric vectors. In R, numbers are doubles by default. To make an integer, place an L after the number:
typeof(1)
[1] "double"
typeof(1L)
[1] "integer"
The distinction between integers and doubles is not usually important, but there are two important differences that you should be aware of:
Doubles are approximations. Doubles represent floating point numbers that can not always be precisely represented with a fixed amount of memory. This means that you should consider all doubles to be approximations. For example, what is square of the square root of two?
x <- sqrt(2) ^ 2
x
[1] 2
x -2
[1] 4.440892e-16
This behaviour is common when working with floating point numbers: most calculations include some approximation error. Instead of comparing floating point numbers using ==, you should use dplyr::near() which allows for some numerical tolerance.
library(tidyverse)
package <U+393C><U+3E31>tidyverse<U+393C><U+3E32> was built under R version 3.3.3Loading tidyverse: ggplot2
Loading tidyverse: tibble
Loading tidyverse: tidyr
Loading tidyverse: readr
Loading tidyverse: purrr
Loading tidyverse: dplyr
Conflicts with tidy packages -----------------------------------------------------
filter(): dplyr, stats
lag(): dplyr, stats
sqrt(2) ^ 2 == 2
[1] FALSE
near(sqrt(2) ^ 2, 2)
[1] TRUE
Integers have one special value: NA, while doubles have four: NA, NaN, Inf and -Inf. All three special values NaN, Inf and -Inf can arise during division:
c(-1, 0, 1) / 0
[1] -Inf NaN Inf
Avoid using == to check for these other special values. Instead use the helper functions is.finite(), is.infinite(), and is.nan():
Character
Character vectors are the most complex type of atomic vector, because each element of a character vector is a string, and a string can contain an arbitrary amount of data.
You’ve already learned a lot about working with strings in strings. Here I wanted to mention one important feature of the underlying string implementation: R uses a global string pool. This means that each unique string is only stored in memory once, and every use of the string points to that representation. This reduces the amount of memory needed by duplicated strings. You can see this behaviour in practice with pryr::object_size():
x <- "This is a reasonably long string."
pryr::object_size(x)
136 B
y <- rep(x, 1000)
pryr::object_size(y)
8.13 kB
y doesn’t take up 1,000x as much memory as x, because each element of y is just a pointer to that same string. A pointer is 8 bytes, so 1000 pointers to a 136 B string is 8 * 1000 + 136 = 8.13 kB.
Missing Values
Note that each type of atomic vector has its own missing value:
NA # logical
[1] NA
#> [1] NA
NA_integer_ # integer
[1] NA
#> [1] NA
NA_real_ # double
[1] NA
#> [1] NA
NA_character_ # character
[1] NA
#> [1] NA
Normally you don’t need to know about these different types because you can always use NA and it will be converted to the correct type using the implicit coercion rules described next. However, there are some functions that are strict about their inputs, so it’s useful to have this knowledge sitting in your back pocket so you can be specific when needed.
Exercise
Describe the difference between is.finite(x) and !is.infinite(x). To find out, try the functions on a numeric vector that includes a number and the five special values (NA, NaN, Inf, -Inf).
x <- c(0, NA, NaN, Inf, -Inf)
is.finite(x)
[1] TRUE FALSE FALSE FALSE FALSE
!is.infinite(x)
[1] TRUE TRUE TRUE FALSE FALSE
is.finite considers only a number to be finite, and considers missing (NA), not a number (NaN), and positive and negative infinity to be not finite. However, since is.infinite only considers Inf and -Inf to be inifinite, !is.infinite considers 0 as well as missing and not-a-number to be not infinite.
Read the source code for dplyr::near() (Hint: to see the source code, drop the ()). How does it work? The source for dplyr::near is:
dplyr::near #> function (x, y, tol = .Machine$double.eps^0.5) #> { #> abs(x - y) < tol #> } #> <environment: namespace:dplyr>
Instead of checking for exact equality, it checks that two numbers are within a certain tolerance, tol. By default the tolerance is set to the square root of .Machine$double.eps, which is the smallest floating point number that the computer can represent.
A logical vector can take 3 possible values. How many possible values can an integer vector take? How many possible values can a double take? Use google to do some research.
Brainstorm at least four functions that allow you to convert a double to an integer. How do they differ? Be precise.
What functions from the readr package allow you to turn a string into logical, integer, and double vector?
The functions parse_logical, parse_integer, and parse_number.
parse_logical(c("TRUE", "FALSE", "1", "0", "true", "t", "NA"))
[1] TRUE FALSE TRUE FALSE TRUE TRUE NA
parse_integer(c("1235", "0134", "NA"))
[1] 1235 134 NA
parse_number(c("1.0", "3.5", "1,000", "NA"))
[1] 1.0 3.5 1000.0 NA
Using atomic vectors
Now that you understand the different types of atomic vector, it’s useful to review some of the important tools for working with them. These include:
How to convert from one type to another, and when that happens automatically. How to tell if an object is a specific type of vector. What happens when you work with vectors of different lengths. How to name the elements of a vector. How to pull out elements of interest.
Coercion
There are two ways to convert, or coerce, one type of vector to another:
Explicit coercion happens when you call a function like as.logical(), as.integer(), as.double(), or as.character(). Whenever you find yourself using explicit coercion, you should always check whether you can make the fix upstream, so that the vector never had the wrong type in the first place. For example, you may need to tweak your readr col_types specification.
Implicit coercion happens when you use a vector in a specific context that expects a certain type of vector. For example, when you use a logical vector with a numeric summary function, or when you use a double vector where an integer vector is expected.
Because explicit coercion is used relatively rarely, and is largely easy to understand, I’ll focus on implicit coercion here.
You’ve already seen the most important type of implicit coercion: using a logical vector in a numeric context. In this case TRUE is converted to 1 and FALSE converted to 0. That means the sum of a logical vector is the number of trues, and the mean of a logical vector is the proportion of trues:
x <- sample(20, 100, replace = TRUE)
y <- x > 10
sum(y) # how many are greater than 10?
[1] 55
#> [1] 44
mean(y) # what proportion are greater than 10?
[1] 0.55
#> [1] 0.44
You may see some code (typically older) that relies on implicit coercion in the opposite direction, from integer to logical:
if (length(x)) {
# do something
}
In this case, 0 is converted to FALSE and everything else is converted to TRUE. I think this makes it harder to understand your code, and I don’t recommend it. Instead be explicit: length(x) > 0.
It’s also important to understand what happens when you try and create a vector containing multiple types with c(): the most complex type always wins.
typeof(c(TRUE, 1L))
[1] "integer"
#> [1] "integer"
typeof(c(1L, 1.5))
[1] "double"
#> [1] "double"
typeof(c(1.5, "a"))
[1] "character"
#> [1] "character"
An atomic vector can not have a mix of different types because the type is a property of the complete vector, not the individual elements. If you need to mix multiple types in the same vector, you should use a list, which you’ll learn about shortly.
Test functions
Sometimes you want to do different things based on the type of vector. One option is to use typeof(). Another is to use a test function which returns a TRUE or FALSE. Base R provides many functions like is.vector() and is.atomic(), but they often returns surprising results. Instead, it’s safer to use the is_* functions provided by purrr, which are summarised in the table below.
lgl int dbl chr list
is_logical() x
is_integer() x
is_double() x
is_numeric() x x
is_character() x
is_atomic() x x x x
is_list() x is_vector() x x x x x
Each predicate also comes with a “scalar” version, like is_scalar_atomic(), which checks that the length is 1. This is useful, for example, if you want to check that an argument to your function is a single logical value.
Scalars and recycling rules
As well as implicitly coercing the types of vectors to be compatible, R will also implicitly coerce the length of vectors. This is called vector recycling, because the shorter vector is repeated, or recycled, to the same length as the longer vector.
This is generally most useful when you are mixing vectors and “scalars”. I put scalars in quotes because R doesn’t actually have scalars: instead, a single number is a vector of length 1. Because there are no scalars, most built-in functions are vectorised, meaning that they will operate on a vector of numbers. That’s why, for example, this code works:
sample(10) + 100
[1] 109 105 106 101 103 104 102 107 110 108
#> [1] 109 108 104 102 103 110 106 107 105 101
runif(10) > 0.5
[1] FALSE FALSE FALSE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
#> [1] TRUE TRUE FALSE TRUE TRUE TRUE FALSE TRUE TRUE TRUE
In R, basic mathematical operations work with vectors. That means that you should never need to perform explicit iteration when performing simple mathematical computations.
It’s intuitive what should happen if you add two vectors of the same length, or a vector and a “scalar”, but what happens if you add two vectors of different lengths?
1:10 + 1:2
[1] 2 4 4 6 6 8 8 10 10 12
Here, R will expand the shortest vector to the same length as the longest, so called recycling. This is silent except when the length of the longer is not an integer multiple of the length of the shorter:
1:10 + 1:3
longer object length is not a multiple of shorter object length
[1] 2 4 6 5 7 9 8 10 12 11
While vector recycling can be used to create very succinct, clever code, it can also silently conceal problems. For this reason, the vectorised functions in tidyverse will throw errors when you recycle anything other than a scalar. If you do want to recycle, you’ll need to do it yourself with rep():
tibble(x = 1:4, y = 1:2)
Error: Variables must be length 1 or 4.
Problem variables: 'y'
tibble(x = 1:4, y = rep(1:2, 2))
#> # A tibble: 4 × 2
#> x y
#> <int> <int>
#> 1 1 1
#> 2 2 2
#> 3 3 1
#> 4 4 2
tibble(x = 1:4, y = rep(1:2, each = 2))
#> # A tibble: 4 × 2
#> x y
#> <int> <int>
#> 1 1 1
#> 2 2 1
#> 3 3 2
#> 4 4 2
Naming Vectors
All types of vectors can be named. You can name them during creation with c():
c(x = 1, y = 2, z = 4)
x y z
1 2 4
Or after the fact with purrr::set_names():
set_names(1:3, c("a", "b", "c"))
a b c
1 2 3
Subsetting
So far we’ve used dplyr::filter() to filter the rows in a tibble. filter() only works with tibble, so we’ll need new tool for vectors: [. [ is the subsetting function, and is called like x[a]. There are four types of things that you can subset a vector with:
A numeric vector containing only integers. The integers must either be all positive, all negative, or zero. Subsetting with positive integers keeps the elements at those positions:
x <- c("one", "two", "three", "four", "five")
x[c(3, 2, 5)]
[1] "three" "two" "five"
By repeating a position, you can actually make a longer output than input:
x[c(1, 1, 5, 5, 5, 2)]
[1] "one" "one" "five" "five" "five" "two"
Negative values drop the elements at the specified positions:
x[c(-1, -3, -5)]
[1] "two" "four"
It’s an error to mix positive and negative values:
x[c(1, -1)]
Error in x[c(1, -1)] : only 0's may be mixed with negative subscripts
The error message mentions subsetting with zero, which returns no values:
x[0]
character(0)
This is not useful very often, but it can be helpful if you want to create unusual data structures to test your functions with.
Subsetting with a logical vector keeps all values corresponding to a TRUE value. This is most often useful in conjunction with the comparison functions.
x <- c(10, 3, NA, 5, 8, 1, NA)
x[!is.na(x)]
[1] 10 3 5 8 1
# All even (or mikssing!) values of x
x[x %% 2 == 0]
[1] 10 NA 8 NA
If you have a named vector, you can subset it with a character vector:
x <- c(abc = 1, def = 2, xyz = 5)
x[c("xyz", "def")]
xyz def
5 2
Like with positive integers, you can also use a character vector to duplicate individual entries.
The simplest type of subsetting is nothing, x[], which returns the complete x. This is not useful for subsetting vectors, but it is useful when subsetting matrices (and other high dimensional structures) because it lets you select all the rows or all the columns, by leaving that index blank. For example, if x is 2d, x[1, ] selects the first row and all the columns, and x[, -1] selects all rows and all columns except the first.
x[]
abc def xyz
1 2 5
Exercises
What does mean(is.na(x)) tell you about a vector x? What about sum(!is.finite(x))? The expression mean(is.na(x)) calculates the proportion of missing values in a vector
x <- c(1:10, NA, NaN, Inf, -Inf)
mean(is.na(x))
[1] 0.1428571
The expression mean(!is.finite(x)) calcualtes the proportion of values that are NA, NaN, or infinite.
mean(!is.finite(x))
[1] 0.2857143
Carefully read the documentation of is.vector(). What does it actually test for? Why does is.atomic() not agree with the definition of atomic vectors above? The function is.vector only checks whether the object has no attributes other than names. Thus a list is a vector:
is.vector(list(a = 1, b = 2))
[1] TRUE
But any object that has an attribute (other than names) is not:
x <- 1:10
attr(x, "something") <- TRUE
is.vector(x)
[1] FALSE
The idea behind this is that object oriented classes will include attributes, including, but not limited to “class”. The function is.atomic explicitly checks whether an object is one of the atomic types (“logical”, “integer”, “numeric”, “complex”, “character”, and “raw”) or NULL.
is.atomic(1:10)
[1] TRUE
#> [1] TRUE
is.atomic(list(a = 1))
[1] FALSE
The function is.atomic will consider objects to be atomic even if they have extra attributes.
is.atomic(x)
[1] TRUE
Compare and contrast setNames() with purrr::set_names(). These are simple functions, so we can simply print out their source code:
setNames
#> function (object = nm, nm)
#> {
#> names(object) <- nm
#> object
#> }
#> <bytecode: 0x7fca28a92038>
#> <environment: namespace:stats>
purrr::set_names
#> function (x, nm = x)
#> {
#> if (!is_vector(x)) {
#> stop("`x` must be a vector", call. = FALSE)
#> }
#> if (length(x) != length(nm)) {
#> stop("`x` and `nm` must be the same length", call. = FALSE)
#> }
#> names(x) <- nm
#> x
#> }
#> <environment: namespace:purrr>
From the code we can see that set_names adds a few sanity checks: x has to be a vector, and the lengths of the object and the names have to be the same.
The last value. Should you use [ or [[?
The elements at even numbered positions.
Every element except the last value.
Only even numbers (and no missing values).
Why is x[-which(x > 0)] not the same as x[x <= 0]?
What happens when you subset with a positive integer that’s bigger than the length of the vector? What happens when you subset with a name that doesn’t exist? When you subset with positive integers that are larger than the length of the vector, NA values are returned for those integers larger than the length of the vector.
(1:10)[11:12]
[1] NA NA
When a vector is subset with a name that doesn’t exist, an error is generated.
c(a = 1, 2)[["b"]]
Error in c(a = 1, 2)[["b"]] : subscript out of bounds
Recursive Vectors –Lists
Lists are a step up in complexity from atomic vectors, because lists can contain other lists. This makes them suitable for representing hierarchical or tree-like structures. You create a list with list():
x <- list(1, 2, 3)
x
[[1]]
[1] 1
[[2]]
[1] 2
[[3]]
[1] 3
A very useful tool for working with lists is str() because it focusses on the structure, not the contents.
str(x)
List of 3
$ : num 1
$ : num 2
$ : num 3
x_named <- list(a = 1, b = 2, c = 3)
str(x_named)
List of 3
$ a: num 1
$ b: num 2
$ c: num 3
Unlike atomic vectors, list() can contain a mix of objects:
y <- list("a", 1L, 1.5, TRUE)
str(y)
List of 4
$ : chr "a"
$ : int 1
$ : num 1.5
$ : logi TRUE
Lists can even contain other lists!
z <- list(list(1, 2), list(3, 4))
str(z)
List of 2
$ :List of 2
..$ : num 1
..$ : num 2
$ :List of 2
..$ : num 3
..$ : num 4
Visualizing Lists
To explain more complicated list manipulation functions, it’s helpful to have a visual representation of lists. For example, take these three lists:
x1 <- list(c(1, 2), c(3, 4))
x2 <- list(list(1, 2), list(3, 4))
x3 <- list(1, list(2, list(3)))

There are three principles:
Lists have rounded corners. Atomic vectors have square corners.
Children are drawn inside their parent, and have a slightly darker background to make it easier to see the hierarchy.
The orientation of the children (i.e. rows or columns) isn’t important, so I’ll pick a row or column orientation to either save space or illustrate an important property in the example.
Subsetting
There are three ways to subset a list, which I’ll illustrate with a list named a:
a <- list(a = 1:3, b = "a string", c = pi, d = list(-1, -5))
[ extracts a sub-list. The result will always be a list.
str(a[1:2])
List of 2
$ a: int [1:3] 1 2 3
$ b: chr "a string"
str(a[4])
List of 1
$ d:List of 2
..$ : num -1
..$ : num -5
Like with vectors, you can subset with a logical, integer, or character vector. [[ extracts a single component from a list. It removes a level of hierarchy from the list.
str(a[[1]])
int [1:3] 1 2 3
str(a[[4]])
List of 2
$ : num -1
$ : num -5
$ is a shorthand for extracting named elements of a list. It works similarly to [[ except that you don’t need to use quotes.
a$a
[1] 1 2 3
The distinction between [ and [[ is really important for lists, because [[ drills down into the list while [ returns a new, smaller list. Compare the code and output above with the visual representation in the figure below 
Attributes
Any vector can contain arbitrary additional metadata through its attributes. You can think of attributes as named list of vectors that can be attached to any object. You can get and set individual attribute values with attr() or see them all at once with attributes().
x <- 1:10
attr(x, "greeting")
NULL
attr(x, "greeting") <- "Hi!"
attr(x, "farewell") <- "Bye!"
attributes(x)
$greeting
[1] "Hi!"
$farewell
[1] "Bye!"
There are three very important attributes that are used to implement fundamental parts of R:
- Names are used to name the elements of a vector.
- Dimensions (dims, for short) make a vector behave like a matrix or array.
- Class is used to implement the S3 object oriented system.
You’ve seen names above, and we won’t cover dimensions because we don’t use matrices in this book. It remains to describe the class, which controls how generic functions work. Generic functions are key to object oriented programming in R, because they make functions behave differently for different classes of input. A detailed discussion of object oriented programming is beyond the scope of this book, but you can read more about it in Advanced R at
http://adv-r.had.co.nz/OO-essentials.html#s3.
Here’s what a typical generic function looks like:
as.Date
function (x, ...)
UseMethod("as.Date")
<bytecode: 0x000000001700c780>
<environment: namespace:base>
#> function (x, ...)
#> UseMethod("as.Date")
#> <bytecode: 0x6b42288>
#> <environment: namespace:base>
The call to “UseMethod” means that this is a generic function, and it will call a specific method, a function, based on the class of the first argument. (All methods are functions; not all functions are methods). You can list all the methods for a generic with methods():
methods("as.Date")
[1] as.Date.character as.Date.date as.Date.dates as.Date.default
[5] as.Date.factor as.Date.numeric as.Date.POSIXct as.Date.POSIXlt
see '?methods' for accessing help and source code
#> [1] as.Date.character as.Date.date as.Date.dates as.Date.default
#> [5] as.Date.factor as.Date.numeric as.Date.POSIXct as.Date.POSIXlt
#> see '?methods' for accessing help and source code
For example, if x is a character vector, as.Date() will call as.Date.character(); if it’s a factor, it’ll call as.Date.factor().
You can see the specific implementation of a method with getS3method():
getS3method("as.Date", "default")
#> function (x, ...)
#> {
#> if (inherits(x, "Date"))
#> return(x)
#> if (is.logical(x) && all(is.na(x)))
#> return(structure(as.numeric(x), class = "Date"))
#> stop(gettextf("do not know how to convert '%s' to class %s",
#> deparse(substitute(x)), dQuote("Date")), domain = NA)
#> }
#> <bytecode: 0x573a678>
#> <environment: namespace:base>
getS3method("as.Date", "numeric")
#> function (x, origin, ...)
#> {
#> if (missing(origin))
#> stop("'origin' must be supplied")
#> as.Date(origin, ...) + x
#> }
#> <bytecode: 0x573d6b8>
#> <environment: namespace:base>
The most important S3 generic is print(): it controls how the object is printed when you type its name at the console. Other important generics are the subsetting functions [, [[, and $.
Augmented Vectors
Atomic vectors and lists are the building blocks for other important vector types like factors and dates. I call these augmented vectors, because they are vectors with additional attributes, including class. Because augmented vectors have a class, they behave differently to the atomic vector on which they are built. In this book, we make use of four important augmented vectors:
Factors Dates Date-times Tibbles
Factors
Factors are designed to represent categorical data that can take a fixed set of possible values. Factors are built on top of integers, and have a levels attribute:
x <- factor(c("ab", "cd", "ab"), levels = c("ab", "cd", "ef"))
typeof(x)
[1] "integer"
attributes(x)
$levels
[1] "ab" "cd" "ef"
$class
[1] "factor"
Dates and Date-Times
Dates in R are numeric vectors that represent the number of days since 1 January 1970.
x <- as.Date("1971-01-01")
unclass(x)
[1] 365
#> [1] 365
typeof(x)
[1] "double"
#> [1] "double"
attributes(x)
$class
[1] "Date"
#> $class
#> [1] "Date"
Date-times are numeric vectors with class POSIXct that represent the number of seconds since 1 January 1970. (In case you were wondering, “POSIXct” stands for “Portable Operating System Interface”, calendar time.)
x <- lubridate::ymd_hm("1970-01-01 01:00")
unclass(x)
[1] 3600
attr(,"tzone")
[1] "UTC"
typeof(x)
[1] "double"
attributes(x)
$tzone
[1] "UTC"
$class
[1] "POSIXct" "POSIXt"
The tzone attribute is optional. It controls how the time is printed, not what absolute time it refers to.
attr(x, "tzone") <- "US/Pacific"
x
[1] "1969-12-31 17:00:00 PST"
attr(x, "tzone") <- "US/Eastern"
x
[1] "1969-12-31 20:00:00 EST"
There is another type of date-times called POSIXlt. These are built on top of named lists:
y <- as.POSIXlt(x)
typeof(y)
[1] "list"
attributes(y)
$names
[1] "sec" "min" "hour" "mday" "mon" "year" "wday" "yday"
[9] "isdst" "zone" "gmtoff"
$class
[1] "POSIXlt" "POSIXt"
$tzone
[1] "US/Eastern" "EST" "EDT"
POSIXlts are rare inside the tidyverse. They do crop up in base R, because they are needed to extract specific components of a date, like the year or month. Since lubridate provides helpers for you to do this instead, you don’t need them. POSIXct’s are always easier to work with, so if you find you have a POSIXlt, you should always convert it to a regular data time lubridate::as_date_time().
Tibbles
Tibbles are augmented lists: they have class “tbl_df” + “tbl” + “data.frame”, and names (column) and row.names attributes:
tb <- tibble::tibble(x = 1:5, y = 5:1)
typeof(tb)
[1] "list"
attributes(tb)
$names
[1] "x" "y"
$class
[1] "tbl_df" "tbl" "data.frame"
$row.names
[1] 1 2 3 4 5
The difference between a tibble and a list is that all the elements of a data frame must be vectors with the same length. All functions that work with tibbles enforce this constraint.
Traditional data.frames have a very similar structure:
df <- data.frame(x = 1:5, y = 5:1)
typeof(df)
[1] "list"
attributes(df)
$names
[1] "x" "y"
$row.names
[1] 1 2 3 4 5
$class
[1] "data.frame"
The main difference is the class. The class of tibble includes “data.frame” which means tibbles inherit the regular data frame behaviour by default.
Exercise
What does hms::hms(3600) return? How does it print? What primitive type is the augmented vector built on top of? What attributes does it use?
x <- hms::hms(3600)
class(x)
[1] "hms" "difftime"
x
01:00:00
typeof(x)
[1] "double"
attributes(x)
$units
[1] "secs"
$class
[1] "hms" "difftime"
hms::hms returns an object of class, and prints the time in “%H:%M:%S” format. The primitive type is a double. The atttributes is uses are “units” and “class”.
Try and make a tibble that has columns with different lengths. What happens? If I try to create at tibble with a scalar and column of a different length there are no issues, and the scalar is repeated to the length of the longer vector.
tibble(x = 1, y = 1:5)
However, if I try to create a tibble with two vectors of different lengths (other than one), the tibble function throws an error.
tibble(x = 1:3, y = 1:4)
Error: Variables must be length 1 or 4.
Problem variables: 'x'
Based on the definition above, is it ok to have a list as a column of a tibble? But there is nothing that prevents a tibble from having vectors of different types: doubles, character, integers, logical, factor, date. The later are still atomic, but they have additional attributes. So, maybe there won’t be an issue with a list vector as long as it is the same length.
tibble(x = 1:3, y = list("a", 1, list(1:3)))
It works! I even used a list with heterogenous types and there wasn’t an issue. In following chapters we’ll see that list vectors can be very useful: for example, when processing many different models.
LS0tDQp0aXRsZTogIlIgZm9yIERhdGEgU2NpZW5jZSBDaGFwdGVyIDE2IFZlY3RvcnMiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQo8aDE+IENoYXB0ZXIgMTYgVmVjdG9ycyA8L2gxPg0KDQpQcmUgcmVxdWlzaXRlczogcHVycnIgcGFja2FnZS4gSW5zdGFsbGVkIHdoZW4geW91IGNhbGwgdGhlIHRpZHl2ZXJzZSBwYWNrYWdlLiANCjxoMj4gVmVjdG9yIEJhc2ljcyA8L2gyPg0KVGhlcmUgYXJlIHR3byB0eXBlcyBvZiB2ZWN0b3JzOiA8L2JyPg0KQXRvbWljIHZlY3RvcnMsIG9mIHdoaWNoIHRoZXJlIGFyZSBzaXggdHlwZXM6IGxvZ2ljYWwsIGludGVnZXIsIGRvdWJsZSwgY2hhcmFjdGVyLCBjb21wbGV4IGFuZCByYXcuIEluZWdlciBhbmQgZG91YmxlIHZlY3RvcnMgYXJlIGNvbGxlY3RpdmVseSBrbm93biBhcyBudW1lcmljIHZlY3RvcnM8L2JyPg0KDQpMaXN0cywgd2hpY2ggYXJlIHNvbWV0aW1lcyBjYWxsZWQgcmN1cnNpdmUgdmVjdG9ycyBiZWNhc3VlIGxpc3RzIGNhbiBjb250YWluIG90aGVyIGxpc3RzISA8L2JyPg0KDQpUaGUgbWFpbiBkaWZmZXJlbmNlIGJldHdlZW4gYXRvbWljIGFuZCBsaXN0cyBpcyB0aGF0IGF0b21pYyB2ZWN0b3JzYSByZSBob21vZ2VuZXJvdXMsIHdoaWxlIGxpc3QgY2FuIGJlIGhldGVyb2dlbmVvdXMuIFRoZXJlJ3Mgb25lIG90aGVyIHJlbGF0ZWQgb2JqZWN0OiBOVUxMLiBOVUxMIGlzIG9mdGVuIHVzZWQgdG8gcmVwcmVzZW50IHRoZSBhYnNlbmNlIG9mIGEgdmVjdG9yLiBBcyBvcHBvc2VkIHRvIE5BLCB3aGljaCBpcyB1c2VkIHRvIHJlcHJlc2VudCB0aGUgYWJzZW5jZSBvZiBhIHZhbHVlIGluIGEgdmVjdG9yLiAgTlVMTCB0eXBpY2FsbHkgYmVoYXZlcyBsaWtlIGEgdmVjdG9yIG9mIGxlbmd0aCAwLiANCg0KPGltZyBzcmM9Imh0dHA6Ly9yNGRzLmhhZC5jby5uei9kaWFncmFtcy9kYXRhLXN0cnVjdHVyZXMtb3ZlcnZpZXcucG5nIiAvPg0KDQpFdmVyeSB2ZWN0b3IgaGFzIHR3byBrZXkgcHJvcGVydGllczoNCg0KSXRzIHR5cGUsIHdoaWNoIHlvdSBjYW4gZGV0ZXJtaW5lIHdpdGggdHlwZW9mKCkuDQpgYGB7cn0NCnR5cGVvZihsZXR0ZXJzKQ0KdHlwZW9mKDE6MTApDQpgYGANCkl0cyBsZW5ndGgsIHdoaWNoIHlvdSBjYW4gZGV0ZXJtaW5lIHdpdGggbGVuZ3RoKCkuDQoNCmBgYHtyfQ0KeCA8LSBsaXN0KCJhIiwgImIiLCAxOjEwKQ0KbGVuZ3RoKHgpDQoNCg0KYGBgDQpWZWN0b3JzIGNhbiBhbHNvIGNvbnRhaW4gYXJiaXRyYXJ5IGFkZGl0aW9uYWwgbWV0YWRhdGEgaW4gdGhlIGZvcm0gb2YgYXR0cmlidXRlcy4gVGhlc2UgYXR0cmlidXRlcyBhcmUgdXNlZCB0byBjcmVhdGUgYXVnbWVudGVkIHZlY3RvcnMgd2hpY2ggYnVpbGQgb24gYWRkaXRpb25hbCBiZWhhdmlvdXIuIDwvcD4NCg0KVGhlcmUgYXJlIGZvdXIgaW1wb3J0YW50IHR5cGVzIG9mIGF1Z21lbnRlZCB2ZWN0b3I6IDwvYnI+DQoNCkZhY3RvcnMgYXJlIGJ1aWx0IG9uIHRvcCBvZiBpbnRlZ2VyIHZlY3RvcnMuIDwvYnI+DQpEYXRlcyBhbmQgZGF0ZS10aW1lcyBhcmUgYnVpbHQgb24gdG9wIG9mIG51bWVyaWMgdmVjdG9ycy48L2JyPg0KRGF0YSBmcmFtZXMgYW5kIHRpYmJsZXMgYXJlIGJ1aWx0IG9uIHRvcCBvZiBsaXN0cy48L3A+DQoNClRoaXMgY2hhcHRlciB3aWxsIGludHJvZHVjZSB5b3UgdG8gdGhlc2UgaW1wb3J0YW50IHZlY3RvcnMgZnJvbSBzaW1wbGVzdCB0byBtb3N0IGNvbXBsaWNhdGVkLiBZb3UnbGwgc3RhcnQgd2l0aCBhdG9taWMgdmVjdG9ycywgdGhlbiBidWlsZCB1cCB0byBsaXN0cywgYW5kIGZpbmlzaCBvZmYgd2l0aCBhdWdtZW50ZWQgdmVjdG9ycy4NCg0KPGgyPiBJbXBvcnRhbnQgVHlwZXMgb2YgYXRvbWljIHZlY3RvciA8L2gyPg0KPGgzPkxvZ2ljYWwgPC9oMz4NCg0KTG9naWNhbCB2ZWN0b3JzIGFyZSB0aGUgc2ltcGxlc3QgdHlwZSBvZiBhdG9taWMgdmVjdG9yIGJlY2F1c2UgdGhleSBjYW4gdGFrZSBvbmx5IHRocmVlIHBvc3NpYmxlIHZhbHVlczogRkFMU0UsIFRSVUUsIGFuZCBOQS4gTG9naWNhbCB2ZWN0b3JzIGFyZSB1c3VhbGx5IGNvbnN0cnVjdGVkIHdpdGggY29tcGFyaXNvbiBvcGVyYXRvcnMsIGFzIGRlc2NyaWJlZCBpbiBjb21wYXJpc29ucy4gWW91IGNhbiBhbHNvIGNyZWF0ZSB0aGVtIGJ5IGhhbmQgd2l0aCBjKCk6DQoNCmBgYHtyfQ0KMToxMCAlJSAzID09IDANCg0KYGBgDQoNCg0KYGBge3J9DQpjKFRSVUUsIFRSVUUsIEZBTFNFLCBOQSkNCmBgYA0KDQo8aDM+TnVtZXJpYyA8L2gzPg0KDQpJbnRlZ2VyIGFuZCBkb3VibGUgdmVjdG9ycyBhcmUga25vd24gY29sbGVjdGl2ZWx5IGFzIG51bWVyaWMgdmVjdG9ycy4gSW4gUiwgbnVtYmVycyBhcmUgZG91YmxlcyBieSBkZWZhdWx0LiBUbyBtYWtlIGFuIGludGVnZXIsIHBsYWNlIGFuIEwgYWZ0ZXIgdGhlIG51bWJlcjoNCg0KYGBge3J9DQp0eXBlb2YoMSkNCnR5cGVvZigxTCkNCmBgYA0KDQpUaGUgZGlzdGluY3Rpb24gYmV0d2VlbiBpbnRlZ2VycyBhbmQgZG91YmxlcyBpcyBub3QgdXN1YWxseSBpbXBvcnRhbnQsIGJ1dCB0aGVyZSBhcmUgdHdvIGltcG9ydGFudCBkaWZmZXJlbmNlcyB0aGF0IHlvdSBzaG91bGQgYmUgYXdhcmUgb2Y6IDwvYnI+DQoNCkRvdWJsZXMgYXJlIGFwcHJveGltYXRpb25zLiBEb3VibGVzIHJlcHJlc2VudCBmbG9hdGluZyBwb2ludCBudW1iZXJzIHRoYXQgY2FuIG5vdCBhbHdheXMgYmUgcHJlY2lzZWx5IHJlcHJlc2VudGVkIHdpdGggYSBmaXhlZCBhbW91bnQgb2YgbWVtb3J5LiBUaGlzIG1lYW5zIHRoYXQgeW91IHNob3VsZCBjb25zaWRlciBhbGwgZG91YmxlcyB0byBiZSBhcHByb3hpbWF0aW9ucy4gRm9yIGV4YW1wbGUsIHdoYXQgaXMgc3F1YXJlIG9mIHRoZSBzcXVhcmUgcm9vdCBvZiB0d28/DQoNCmBgYHtyfQ0KeCA8LSBzcXJ0KDIpICBeIDINCngNCnggLSAyIA0KDQpgYGANCg0KVGhpcyBiZWhhdmlvdXIgaXMgY29tbW9uIHdoZW4gd29ya2luZyB3aXRoIGZsb2F0aW5nIHBvaW50IG51bWJlcnM6IG1vc3QgY2FsY3VsYXRpb25zIGluY2x1ZGUgc29tZSBhcHByb3hpbWF0aW9uIGVycm9yLiBJbnN0ZWFkIG9mIGNvbXBhcmluZyBmbG9hdGluZyBwb2ludCBudW1iZXJzIHVzaW5nID09LCB5b3Ugc2hvdWxkIHVzZSBkcGx5cjo6bmVhcigpIHdoaWNoIGFsbG93cyBmb3Igc29tZSBudW1lcmljYWwgdG9sZXJhbmNlLiA8L3A+DQpgYGB7cn0NCmxpYnJhcnkodGlkeXZlcnNlKQ0Kc3FydCgyKSBeIDIgPT0gMg0KbmVhcihzcXJ0KDIpIF4gMiwgMikNCmBgYA0KDQpJbnRlZ2VycyBoYXZlIG9uZSBzcGVjaWFsIHZhbHVlOiBOQSwgd2hpbGUgZG91YmxlcyBoYXZlIGZvdXI6IE5BLCBOYU4sIEluZiBhbmQgLUluZi4gQWxsIHRocmVlIHNwZWNpYWwgdmFsdWVzIE5hTiwgSW5mIGFuZCAtSW5mIGNhbiBhcmlzZSBkdXJpbmcgZGl2aXNpb246DQoNCmBgYHtyfQ0KYygtMSwgMCwgMSkgLyAwDQpgYGANCg0KQXZvaWQgdXNpbmcgPT0gdG8gY2hlY2sgZm9yIHRoZXNlIG90aGVyIHNwZWNpYWwgdmFsdWVzLiBJbnN0ZWFkIHVzZSB0aGUgaGVscGVyIGZ1bmN0aW9ucyBpcy5maW5pdGUoKSwgaXMuaW5maW5pdGUoKSwgYW5kIGlzLm5hbigpOiANCg0KPGgyPiBDaGFyYWN0ZXIgPC9oMj4NCkNoYXJhY3RlciB2ZWN0b3JzIGFyZSB0aGUgbW9zdCBjb21wbGV4IHR5cGUgb2YgYXRvbWljIHZlY3RvciwgYmVjYXVzZSBlYWNoIGVsZW1lbnQgb2YgYSBjaGFyYWN0ZXIgdmVjdG9yIGlzIGEgc3RyaW5nLCBhbmQgYSBzdHJpbmcgY2FuIGNvbnRhaW4gYW4gYXJiaXRyYXJ5IGFtb3VudCBvZiBkYXRhLiA8L3A+DQoNCg0KWW91J3ZlIGFscmVhZHkgbGVhcm5lZCBhIGxvdCBhYm91dCB3b3JraW5nIHdpdGggc3RyaW5ncyBpbiBzdHJpbmdzLiBIZXJlIEkgd2FudGVkIHRvIG1lbnRpb24gb25lIGltcG9ydGFudCBmZWF0dXJlIG9mIHRoZSB1bmRlcmx5aW5nIHN0cmluZyBpbXBsZW1lbnRhdGlvbjogUiB1c2VzIGEgZ2xvYmFsIHN0cmluZyBwb29sLiBUaGlzIG1lYW5zIHRoYXQgZWFjaCB1bmlxdWUgc3RyaW5nIGlzIG9ubHkgc3RvcmVkIGluIG1lbW9yeSBvbmNlLCBhbmQgZXZlcnkgdXNlIG9mIHRoZSBzdHJpbmcgcG9pbnRzIHRvIHRoYXQgcmVwcmVzZW50YXRpb24uIFRoaXMgcmVkdWNlcyB0aGUgYW1vdW50IG9mIG1lbW9yeSBuZWVkZWQgYnkgZHVwbGljYXRlZCBzdHJpbmdzLiBZb3UgY2FuIHNlZSB0aGlzIGJlaGF2aW91ciBpbiBwcmFjdGljZSB3aXRoIHByeXI6Om9iamVjdF9zaXplKCk6IA0KDQpgYGB7cn0NCnggPC0gIlRoaXMgaXMgYSByZWFzb25hYmx5IGxvbmcgc3RyaW5nLiINCnByeXI6Om9iamVjdF9zaXplKHgpDQoNCmBgYA0KDQoNCmBgYHtyfQ0KeSA8LSByZXAoeCwgMTAwMCkNCnByeXI6Om9iamVjdF9zaXplKHkpDQpgYGANCnkgZG9lc24ndCB0YWtlIHVwIDEsMDAweCBhcyBtdWNoIG1lbW9yeSBhcyB4LCBiZWNhdXNlIGVhY2ggZWxlbWVudCBvZiB5IGlzIGp1c3QgYSBwb2ludGVyIHRvIHRoYXQgc2FtZSBzdHJpbmcuIEEgcG9pbnRlciBpcyA4IGJ5dGVzLCBzbyAxMDAwIHBvaW50ZXJzIHRvIGEgMTM2IEIgc3RyaW5nIGlzIDggKiAxMDAwICsgMTM2ID0gOC4xMyBrQi4NCg0KPGgzPiBNaXNzaW5nIFZhbHVlcyA8L2gzPg0KTm90ZSB0aGF0IGVhY2ggdHlwZSBvZiBhdG9taWMgdmVjdG9yIGhhcyBpdHMgb3duIG1pc3NpbmcgdmFsdWU6IA0KDQpgYGB7cn0NCk5BICAgICAgICAgICAgIyBsb2dpY2FsDQojPiBbMV0gTkENCk5BX2ludGVnZXJfICAgIyBpbnRlZ2VyDQojPiBbMV0gTkENCk5BX3JlYWxfICAgICAgIyBkb3VibGUNCiM+IFsxXSBOQQ0KTkFfY2hhcmFjdGVyXyAjIGNoYXJhY3Rlcg0KIz4gWzFdIE5BDQoNCmBgYA0KDQpOb3JtYWxseSB5b3UgZG9uJ3QgbmVlZCB0byBrbm93IGFib3V0IHRoZXNlIGRpZmZlcmVudCB0eXBlcyBiZWNhdXNlIHlvdSBjYW4gYWx3YXlzIHVzZSBOQSBhbmQgaXQgd2lsbCBiZSBjb252ZXJ0ZWQgdG8gdGhlIGNvcnJlY3QgdHlwZSB1c2luZyB0aGUgaW1wbGljaXQgY29lcmNpb24gcnVsZXMgZGVzY3JpYmVkIG5leHQuIEhvd2V2ZXIsIHRoZXJlIGFyZSBzb21lIGZ1bmN0aW9ucyB0aGF0IGFyZSBzdHJpY3QgYWJvdXQgdGhlaXIgaW5wdXRzLCBzbyBpdCdzIHVzZWZ1bCB0byBoYXZlIHRoaXMga25vd2xlZGdlIHNpdHRpbmcgaW4geW91ciBiYWNrIHBvY2tldCBzbyB5b3UgY2FuIGJlIHNwZWNpZmljIHdoZW4gbmVlZGVkLg0KDQo8aDM+IEV4ZXJjaXNlIDwvaDM+DQpEZXNjcmliZSB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIGlzLmZpbml0ZSh4KSBhbmQgIWlzLmluZmluaXRlKHgpLjwvYnI+DQpUbyBmaW5kIG91dCwgdHJ5IHRoZSBmdW5jdGlvbnMgb24gYSBudW1lcmljIHZlY3RvciB0aGF0IGluY2x1ZGVzIGEgbnVtYmVyIGFuZCB0aGUgZml2ZSBzcGVjaWFsIHZhbHVlcyAoTkEsIE5hTiwgSW5mLCAtSW5mKS4gPC9QPg0KDQpgYGB7cn0NCnggPC0gYygwLCBOQSwgTmFOLCBJbmYsIC1JbmYpDQppcy5maW5pdGUoeCkNCiFpcy5pbmZpbml0ZSh4KQ0KYGBgDQppcy5maW5pdGUgY29uc2lkZXJzIG9ubHkgYSBudW1iZXIgdG8gYmUgZmluaXRlLCBhbmQgY29uc2lkZXJzIG1pc3NpbmcgKE5BKSwgbm90IGEgbnVtYmVyIChOYU4pLCBhbmQgcG9zaXRpdmUgYW5kIG5lZ2F0aXZlIGluZmluaXR5IHRvIGJlIG5vdCBmaW5pdGUuIEhvd2V2ZXIsIHNpbmNlIGlzLmluZmluaXRlIG9ubHkgY29uc2lkZXJzIEluZiBhbmQgLUluZiB0byBiZSBpbmlmaW5pdGUsICFpcy5pbmZpbml0ZSBjb25zaWRlcnMgMCBhcyB3ZWxsIGFzIG1pc3NpbmcgYW5kIG5vdC1hLW51bWJlciB0byBiZSBub3QgaW5maW5pdGUuIDwvUD4NCg0KUmVhZCB0aGUgc291cmNlIGNvZGUgZm9yIGRwbHlyOjpuZWFyKCkgKEhpbnQ6IHRvIHNlZSB0aGUgc291cmNlIGNvZGUsIGRyb3AgdGhlICgpKS4gSG93IGRvZXMgaXQgd29yaz8gPC9icj4NClRoZSBzb3VyY2UgZm9yIGRwbHlyOjpuZWFyIGlzOiA8L2JyPg0KDQpkcGx5cjo6bmVhcjwvYnI+DQojPiBmdW5jdGlvbiAoeCwgeSwgdG9sID0gLk1hY2hpbmUkZG91YmxlLmVwc14wLjUpIDwvYnI+DQojPiB7PC9icj4NCiM+ICAgICBhYnMoeCAtIHkpIDwgdG9sPC9icj4NCiM+IH08L2JyPg0KIz4gPGVudmlyb25tZW50OiBuYW1lc3BhY2U6ZHBseXI+PC9icj4NCg0KDQpJbnN0ZWFkIG9mIGNoZWNraW5nIGZvciBleGFjdCBlcXVhbGl0eSwgaXQgY2hlY2tzIHRoYXQgdHdvIG51bWJlcnMgYXJlIHdpdGhpbiBhIGNlcnRhaW4gdG9sZXJhbmNlLCB0b2wuIEJ5IGRlZmF1bHQgdGhlIHRvbGVyYW5jZSBpcyBzZXQgdG8gdGhlIHNxdWFyZSByb290IG9mIC5NYWNoaW5lJGRvdWJsZS5lcHMsIHdoaWNoIGlzIHRoZSBzbWFsbGVzdCBmbG9hdGluZyBwb2ludCBudW1iZXIgdGhhdCB0aGUgY29tcHV0ZXIgY2FuIHJlcHJlc2VudC4gPC9wPg0KDQpBIGxvZ2ljYWwgdmVjdG9yIGNhbiB0YWtlIDMgcG9zc2libGUgdmFsdWVzLiBIb3cgbWFueSBwb3NzaWJsZSB2YWx1ZXMgY2FuIGFuIGludGVnZXIgdmVjdG9yIHRha2U/IEhvdyBtYW55IHBvc3NpYmxlIHZhbHVlcyBjYW4gYSBkb3VibGUgdGFrZT8gVXNlIGdvb2dsZSB0byBkbyBzb21lIHJlc2VhcmNoLiA8L3A+DQoNCkJyYWluc3Rvcm0gYXQgbGVhc3QgZm91ciBmdW5jdGlvbnMgdGhhdCBhbGxvdyB5b3UgdG8gY29udmVydCBhIGRvdWJsZSB0byBhbiBpbnRlZ2VyLiBIb3cgZG8gdGhleSBkaWZmZXI/IEJlIHByZWNpc2UuIDwvcD4NCg0KV2hhdCBmdW5jdGlvbnMgZnJvbSB0aGUgcmVhZHIgcGFja2FnZSBhbGxvdyB5b3UgdG8gdHVybiBhIHN0cmluZyBpbnRvIGxvZ2ljYWwsIGludGVnZXIsIGFuZCBkb3VibGUgdmVjdG9yPyA8L3A+DQoNClRoZSBmdW5jdGlvbnMgcGFyc2VfbG9naWNhbCwgcGFyc2VfaW50ZWdlciwgYW5kIHBhcnNlX251bWJlci4NCg0KYGBge3J9DQpwYXJzZV9sb2dpY2FsKGMoIlRSVUUiLCAiRkFMU0UiLCAiMSIsICIwIiwgInRydWUiLCAidCIsICJOQSIpKQ0KcGFyc2VfaW50ZWdlcihjKCIxMjM1IiwgIjAxMzQiLCAiTkEiKSkNCnBhcnNlX251bWJlcihjKCIxLjAiLCAiMy41IiwgIjEsMDAwIiwgIk5BIikpDQpgYGANCg0KPGgyPiBVc2luZyBhdG9taWMgdmVjdG9ycyA8L2gyPg0KTm93IHRoYXQgeW91IHVuZGVyc3RhbmQgdGhlIGRpZmZlcmVudCB0eXBlcyBvZiBhdG9taWMgdmVjdG9yLCBpdCdzIHVzZWZ1bCB0byByZXZpZXcgc29tZSBvZiB0aGUgaW1wb3J0YW50IHRvb2xzIGZvciB3b3JraW5nIHdpdGggdGhlbS4gVGhlc2UgaW5jbHVkZTogPC9icj4NCg0KSG93IHRvIGNvbnZlcnQgZnJvbSBvbmUgdHlwZSB0byBhbm90aGVyLCBhbmQgd2hlbiB0aGF0IGhhcHBlbnMgYXV0b21hdGljYWxseS48L2JyPg0KSG93IHRvIHRlbGwgaWYgYW4gb2JqZWN0IGlzIGEgc3BlY2lmaWMgdHlwZSBvZiB2ZWN0b3IuPC9icj4NCldoYXQgaGFwcGVucyB3aGVuIHlvdSB3b3JrIHdpdGggdmVjdG9ycyBvZiBkaWZmZXJlbnQgbGVuZ3Rocy48L2JyPg0KSG93IHRvIG5hbWUgdGhlIGVsZW1lbnRzIG9mIGEgdmVjdG9yLjwvYnI+DQpIb3cgdG8gcHVsbCBvdXQgZWxlbWVudHMgb2YgaW50ZXJlc3QuPC9icj4NCg0KPGgzPiBDb2VyY2lvbiA8L2gzPg0KVGhlcmUgYXJlIHR3byB3YXlzIHRvIGNvbnZlcnQsIG9yIGNvZXJjZSwgb25lIHR5cGUgb2YgdmVjdG9yIHRvIGFub3RoZXI6PC9icj4NCg0KRXhwbGljaXQgY29lcmNpb24gaGFwcGVucyB3aGVuIHlvdSBjYWxsIGEgZnVuY3Rpb24gbGlrZSBhcy5sb2dpY2FsKCksIGFzLmludGVnZXIoKSwgYXMuZG91YmxlKCksIG9yIGFzLmNoYXJhY3RlcigpLiBXaGVuZXZlciB5b3UgZmluZCB5b3Vyc2VsZiB1c2luZyBleHBsaWNpdCBjb2VyY2lvbiwgeW91IHNob3VsZCBhbHdheXMgY2hlY2sgd2hldGhlciB5b3UgY2FuIG1ha2UgdGhlIGZpeCB1cHN0cmVhbSwgc28gdGhhdCB0aGUgdmVjdG9yIG5ldmVyIGhhZCB0aGUgd3JvbmcgdHlwZSBpbiB0aGUgZmlyc3QgcGxhY2UuIEZvciBleGFtcGxlLCB5b3UgbWF5IG5lZWQgdG8gdHdlYWsgeW91ciByZWFkciBjb2xfdHlwZXMgc3BlY2lmaWNhdGlvbi48L3A+DQoNCkltcGxpY2l0IGNvZXJjaW9uIGhhcHBlbnMgd2hlbiB5b3UgdXNlIGEgdmVjdG9yIGluIGEgc3BlY2lmaWMgY29udGV4dCB0aGF0IGV4cGVjdHMgYSBjZXJ0YWluIHR5cGUgb2YgdmVjdG9yLiBGb3IgZXhhbXBsZSwgd2hlbiB5b3UgdXNlIGEgbG9naWNhbCB2ZWN0b3Igd2l0aCBhIG51bWVyaWMgc3VtbWFyeSBmdW5jdGlvbiwgb3Igd2hlbiB5b3UgdXNlIGEgZG91YmxlIHZlY3RvciB3aGVyZSBhbiBpbnRlZ2VyIHZlY3RvciBpcyBleHBlY3RlZC48L3A+DQoNCkJlY2F1c2UgZXhwbGljaXQgY29lcmNpb24gaXMgdXNlZCByZWxhdGl2ZWx5IHJhcmVseSwgYW5kIGlzIGxhcmdlbHkgZWFzeSB0byB1bmRlcnN0YW5kLCBJJ2xsIGZvY3VzIG9uIGltcGxpY2l0IGNvZXJjaW9uIGhlcmUuPC9wPg0KDQoNCllvdSd2ZSBhbHJlYWR5IHNlZW4gdGhlIG1vc3QgaW1wb3J0YW50IHR5cGUgb2YgaW1wbGljaXQgY29lcmNpb246IHVzaW5nIGEgbG9naWNhbCB2ZWN0b3IgaW4gYSBudW1lcmljIGNvbnRleHQuIEluIHRoaXMgY2FzZSBUUlVFIGlzIGNvbnZlcnRlZCB0byAxIGFuZCBGQUxTRSBjb252ZXJ0ZWQgdG8gMC4gVGhhdCBtZWFucyB0aGUgc3VtIG9mIGEgbG9naWNhbCB2ZWN0b3IgaXMgdGhlIG51bWJlciBvZiB0cnVlcywgYW5kIHRoZSBtZWFuIG9mIGEgbG9naWNhbCB2ZWN0b3IgaXMgdGhlIHByb3BvcnRpb24gb2YgdHJ1ZXM6PC9icj4NCg0KDQpgYGB7cn0NCnggPC0gc2FtcGxlKDIwLCAxMDAsIHJlcGxhY2UgPSBUUlVFKQ0KeSA8LSB4ID4gMTANCnN1bSh5KSAgIyBob3cgbWFueSBhcmUgZ3JlYXRlciB0aGFuIDEwPw0KIz4gWzFdIDQ0DQptZWFuKHkpICMgd2hhdCBwcm9wb3J0aW9uIGFyZSBncmVhdGVyIHRoYW4gMTA/DQojPiBbMV0gMC40NA0KDQpgYGANCllvdSBtYXkgc2VlIHNvbWUgY29kZSAodHlwaWNhbGx5IG9sZGVyKSB0aGF0IHJlbGllcyBvbiBpbXBsaWNpdCBjb2VyY2lvbiBpbiB0aGUgb3Bwb3NpdGUgZGlyZWN0aW9uLCBmcm9tIGludGVnZXIgdG8gbG9naWNhbDoNCg0KYGBge3J9DQppZiAobGVuZ3RoKHgpKSB7DQogICMgZG8gc29tZXRoaW5nDQp9DQoNCmBgYA0KSW4gdGhpcyBjYXNlLCAwIGlzIGNvbnZlcnRlZCB0byBGQUxTRSBhbmQgZXZlcnl0aGluZyBlbHNlIGlzIGNvbnZlcnRlZCB0byBUUlVFLiBJIHRoaW5rIHRoaXMgbWFrZXMgaXQgaGFyZGVyIHRvIHVuZGVyc3RhbmQgeW91ciBjb2RlLCBhbmQgSSBkb24ndCByZWNvbW1lbmQgaXQuIEluc3RlYWQgYmUgZXhwbGljaXQ6IGxlbmd0aCh4KSA+IDAuIDwvcD4NCg0KSXQncyBhbHNvIGltcG9ydGFudCB0byB1bmRlcnN0YW5kIHdoYXQgaGFwcGVucyB3aGVuIHlvdSB0cnkgYW5kIGNyZWF0ZSBhIHZlY3RvciBjb250YWluaW5nIG11bHRpcGxlIHR5cGVzIHdpdGggYygpOiB0aGUgbW9zdCBjb21wbGV4IHR5cGUgYWx3YXlzIHdpbnMuDQpgYGB7cn0NCnR5cGVvZihjKFRSVUUsIDFMKSkNCiM+IFsxXSAiaW50ZWdlciINCnR5cGVvZihjKDFMLCAxLjUpKQ0KIz4gWzFdICJkb3VibGUiDQp0eXBlb2YoYygxLjUsICJhIikpDQojPiBbMV0gImNoYXJhY3RlciINCmBgYA0KQW4gYXRvbWljIHZlY3RvciBjYW4gbm90IGhhdmUgYSBtaXggb2YgZGlmZmVyZW50IHR5cGVzIGJlY2F1c2UgdGhlIHR5cGUgaXMgYSBwcm9wZXJ0eSBvZiB0aGUgY29tcGxldGUgdmVjdG9yLCBub3QgdGhlIGluZGl2aWR1YWwgZWxlbWVudHMuIElmIHlvdSBuZWVkIHRvIG1peCBtdWx0aXBsZSB0eXBlcyBpbiB0aGUgc2FtZSB2ZWN0b3IsIHlvdSBzaG91bGQgdXNlIGEgbGlzdCwgd2hpY2ggeW91J2xsIGxlYXJuIGFib3V0IHNob3J0bHkuDQoNCjxoMj4gVGVzdCBmdW5jdGlvbnMgPC9oMj4NCg0KU29tZXRpbWVzIHlvdSB3YW50IHRvIGRvIGRpZmZlcmVudCB0aGluZ3MgYmFzZWQgb24gdGhlIHR5cGUgb2YgdmVjdG9yLiBPbmUgb3B0aW9uIGlzIHRvIHVzZSB0eXBlb2YoKS4gQW5vdGhlciBpcyB0byB1c2UgYSB0ZXN0IGZ1bmN0aW9uIHdoaWNoIHJldHVybnMgYSBUUlVFIG9yIEZBTFNFLiBCYXNlIFIgcHJvdmlkZXMgbWFueSBmdW5jdGlvbnMgbGlrZSBpcy52ZWN0b3IoKSBhbmQgaXMuYXRvbWljKCksIGJ1dCB0aGV5IG9mdGVuIHJldHVybnMgc3VycHJpc2luZyByZXN1bHRzLiBJbnN0ZWFkLCBpdCdzIHNhZmVyIHRvIHVzZSB0aGUgaXNfKiBmdW5jdGlvbnMgcHJvdmlkZWQgYnkgcHVycnIsIHdoaWNoIGFyZSBzdW1tYXJpc2VkIGluIHRoZSB0YWJsZSBiZWxvdy4NCjwvcD4NCg0KDQogICAgICAgICAgICAgICAgbGdsCSAgaW50CSAgZGJsCSAgY2hyCSAgbGlzdA0KaXNfbG9naWNhbCgpCSAgeAkJCQkNCmlzX2ludGVnZXIoKQkJICAgICAgeAkJCQ0KaXNfZG91YmxlKCkJCQkgICAgICAgICAgICB4CQkNCmlzX251bWVyaWMoKQkJICAgICAgeAkgICAgeAkJDQppc19jaGFyYWN0ZXIoKQkJCQkgICAgICAgICAgICB4CQ0KaXNfYXRvbWljKCkJICAgIHgJICAgIHgJICAgIHgJICAgIHgJDQppc19saXN0KCkJCQkJCSAgICAgICAgICAgICAgICAgICAgICB4DQppc192ZWN0b3IoKQkgICAgeAkgICAgeAkgICAgeAkgICAgeAkgICAgeCA8L2JyPg0KDQpFYWNoIHByZWRpY2F0ZSBhbHNvIGNvbWVzIHdpdGggYSAic2NhbGFyIiB2ZXJzaW9uLCBsaWtlIGlzX3NjYWxhcl9hdG9taWMoKSwgd2hpY2ggY2hlY2tzIHRoYXQgdGhlIGxlbmd0aCBpcyAxLiBUaGlzIGlzIHVzZWZ1bCwgZm9yIGV4YW1wbGUsIGlmIHlvdSB3YW50IHRvIGNoZWNrIHRoYXQgYW4gYXJndW1lbnQgdG8geW91ciBmdW5jdGlvbiBpcyBhIHNpbmdsZSBsb2dpY2FsIHZhbHVlLiA8L3A+DQoNCjxoMj4gU2NhbGFycyBhbmQgcmVjeWNsaW5nIHJ1bGVzIDwvaDI+DQpBcyB3ZWxsIGFzIGltcGxpY2l0bHkgY29lcmNpbmcgdGhlIHR5cGVzIG9mIHZlY3RvcnMgdG8gYmUgY29tcGF0aWJsZSwgUiB3aWxsIGFsc28gaW1wbGljaXRseSBjb2VyY2UgdGhlIGxlbmd0aCBvZiB2ZWN0b3JzLiBUaGlzIGlzIGNhbGxlZCB2ZWN0b3IgcmVjeWNsaW5nLCBiZWNhdXNlIHRoZSBzaG9ydGVyIHZlY3RvciBpcyByZXBlYXRlZCwgb3IgcmVjeWNsZWQsIHRvIHRoZSBzYW1lIGxlbmd0aCBhcyB0aGUgbG9uZ2VyIHZlY3Rvci4gPC9wPg0KDQpUaGlzIGlzIGdlbmVyYWxseSBtb3N0IHVzZWZ1bCB3aGVuIHlvdSBhcmUgbWl4aW5nIHZlY3RvcnMgYW5kICJzY2FsYXJzIi4gSSBwdXQgc2NhbGFycyBpbiBxdW90ZXMgYmVjYXVzZSBSIGRvZXNuJ3QgYWN0dWFsbHkgaGF2ZSBzY2FsYXJzOiBpbnN0ZWFkLCBhIHNpbmdsZSBudW1iZXIgaXMgYSB2ZWN0b3Igb2YgbGVuZ3RoIDEuIEJlY2F1c2UgdGhlcmUgYXJlIG5vIHNjYWxhcnMsIG1vc3QgYnVpbHQtaW4gZnVuY3Rpb25zIGFyZSB2ZWN0b3Jpc2VkLCBtZWFuaW5nIHRoYXQgdGhleSB3aWxsIG9wZXJhdGUgb24gYSB2ZWN0b3Igb2YgbnVtYmVycy4gVGhhdCdzIHdoeSwgZm9yIGV4YW1wbGUsIHRoaXMgY29kZSB3b3JrczogPC9wPg0KDQpgYGB7cn0NCnNhbXBsZSgxMCkgKyAxMDANCiM+ICBbMV0gMTA5IDEwOCAxMDQgMTAyIDEwMyAxMTAgMTA2IDEwNyAxMDUgMTAxDQpydW5pZigxMCkgPiAwLjUNCiM+ICBbMV0gIFRSVUUgIFRSVUUgRkFMU0UgIFRSVUUgIFRSVUUgIFRSVUUgRkFMU0UgIFRSVUUgIFRSVUUgIFRSVUUNCmBgYA0KSW4gUiwgYmFzaWMgbWF0aGVtYXRpY2FsIG9wZXJhdGlvbnMgd29yayB3aXRoIHZlY3RvcnMuIFRoYXQgbWVhbnMgdGhhdCB5b3Ugc2hvdWxkIG5ldmVyIG5lZWQgdG8gcGVyZm9ybSBleHBsaWNpdCBpdGVyYXRpb24gd2hlbiBwZXJmb3JtaW5nIHNpbXBsZSBtYXRoZW1hdGljYWwgY29tcHV0YXRpb25zLiA8L3A+DQoNCkl0J3MgaW50dWl0aXZlIHdoYXQgc2hvdWxkIGhhcHBlbiBpZiB5b3UgYWRkIHR3byB2ZWN0b3JzIG9mIHRoZSBzYW1lIGxlbmd0aCwgb3IgYSB2ZWN0b3IgYW5kIGEgInNjYWxhciIsIGJ1dCB3aGF0IGhhcHBlbnMgaWYgeW91IGFkZCB0d28gdmVjdG9ycyBvZiBkaWZmZXJlbnQgbGVuZ3Rocz8gPC9wPg0KDQpgYGB7cn0NCjE6MTAgKyAxOjINCmBgYA0KDQpIZXJlLCBSIHdpbGwgZXhwYW5kIHRoZSBzaG9ydGVzdCB2ZWN0b3IgdG8gdGhlIHNhbWUgbGVuZ3RoIGFzIHRoZSBsb25nZXN0LCBzbyBjYWxsZWQgcmVjeWNsaW5nLiBUaGlzIGlzIHNpbGVudCBleGNlcHQgd2hlbiB0aGUgbGVuZ3RoIG9mIHRoZSBsb25nZXIgaXMgbm90IGFuIGludGVnZXIgbXVsdGlwbGUgb2YgdGhlIGxlbmd0aCBvZiB0aGUgc2hvcnRlcjogDQoNCmBgYHtyfQ0KMToxMCArIDE6Mw0KYGBgDQoNCldoaWxlIHZlY3RvciByZWN5Y2xpbmcgY2FuIGJlIHVzZWQgdG8gY3JlYXRlIHZlcnkgc3VjY2luY3QsIGNsZXZlciBjb2RlLCBpdCBjYW4gYWxzbyBzaWxlbnRseSBjb25jZWFsIHByb2JsZW1zLiBGb3IgdGhpcyByZWFzb24sIHRoZSB2ZWN0b3Jpc2VkIGZ1bmN0aW9ucyBpbiB0aWR5dmVyc2Ugd2lsbCB0aHJvdyBlcnJvcnMgd2hlbiB5b3UgcmVjeWNsZSBhbnl0aGluZyBvdGhlciB0aGFuIGEgc2NhbGFyLiBJZiB5b3UgZG8gd2FudCB0byByZWN5Y2xlLCB5b3UnbGwgbmVlZCB0byBkbyBpdCB5b3Vyc2VsZiB3aXRoIHJlcCgpOg0KDQpgYGB7cn0NCnRpYmJsZSh4ID0gMTo0LCB5ID0gMToyKQ0KIz4gRXJyb3I6IFZhcmlhYmxlcyBtdXN0IGJlIGxlbmd0aCAxIG9yIDQuDQojPiBQcm9ibGVtIHZhcmlhYmxlczogJ3knDQoNCmBgYA0KYGBge3J9DQoNCnRpYmJsZSh4ID0gMTo0LCB5ID0gcmVwKDE6MiwgMikpDQojPiAjIEEgdGliYmxlOiA0INcgMg0KIz4gICAgICAgeCAgICAgeQ0KIz4gICA8aW50PiA8aW50Pg0KIz4gMSAgICAgMSAgICAgMQ0KIz4gMiAgICAgMiAgICAgMg0KIz4gMyAgICAgMyAgICAgMQ0KIz4gNCAgICAgNCAgICAgMg0KDQp0aWJibGUoeCA9IDE6NCwgeSA9IHJlcCgxOjIsIGVhY2ggPSAyKSkNCiM+ICMgQSB0aWJibGU6IDQg1yAyDQojPiAgICAgICB4ICAgICB5DQojPiAgIDxpbnQ+IDxpbnQ+DQojPiAxICAgICAxICAgICAxDQojPiAyICAgICAyICAgICAxDQojPiAzICAgICAzICAgICAyDQojPiA0ICAgICA0ICAgICAyDQpgYGANCg0KPGgyPiBOYW1pbmcgVmVjdG9ycyA8L2gyPg0KQWxsIHR5cGVzIG9mIHZlY3RvcnMgY2FuIGJlIG5hbWVkLiBZb3UgY2FuIG5hbWUgdGhlbSBkdXJpbmcgY3JlYXRpb24gd2l0aCBjKCk6DQoNCmBgYHtyfQ0KYyh4ID0gMSwgeSA9IDIsIHogPSA0KQ0KDQpgYGANCg0KT3IgYWZ0ZXIgdGhlIGZhY3Qgd2l0aCBwdXJycjo6c2V0X25hbWVzKCk6DQoNCmBgYHtyfQ0Kc2V0X25hbWVzKDE6MywgYygiYSIsICJiIiwgImMiKSkNCmBgYA0KPGgyPiBTdWJzZXR0aW5nIDwvaDI+DQoNClNvIGZhciB3ZSd2ZSB1c2VkIGRwbHlyOjpmaWx0ZXIoKSB0byBmaWx0ZXIgdGhlIHJvd3MgaW4gYSB0aWJibGUuIGZpbHRlcigpIG9ubHkgd29ya3Mgd2l0aCB0aWJibGUsIHNvIHdlJ2xsIG5lZWQgbmV3IHRvb2wgZm9yIHZlY3RvcnM6IFsuIFsgaXMgdGhlIHN1YnNldHRpbmcgZnVuY3Rpb24sIGFuZCBpcyBjYWxsZWQgbGlrZSB4W2FdLiBUaGVyZSBhcmUgZm91ciB0eXBlcyBvZiB0aGluZ3MgdGhhdCB5b3UgY2FuIHN1YnNldCBhIHZlY3RvciB3aXRoOiA8L2JyPg0KDQpBIG51bWVyaWMgdmVjdG9yIGNvbnRhaW5pbmcgb25seSBpbnRlZ2Vycy4gVGhlIGludGVnZXJzIG11c3QgZWl0aGVyIGJlIGFsbCBwb3NpdGl2ZSwgYWxsIG5lZ2F0aXZlLCBvciB6ZXJvLiBTdWJzZXR0aW5nIHdpdGggcG9zaXRpdmUgaW50ZWdlcnMga2VlcHMgdGhlIGVsZW1lbnRzIGF0IHRob3NlIHBvc2l0aW9uczoNCg0KYGBge3J9DQp4IDwtIGMoIm9uZSIsICJ0d28iLCAidGhyZWUiLCAiZm91ciIsICJmaXZlIikNCnhbYygzLCAyLCA1KV0NCmBgYA0KQnkgcmVwZWF0aW5nIGEgcG9zaXRpb24sIHlvdSBjYW4gYWN0dWFsbHkgbWFrZSBhIGxvbmdlciBvdXRwdXQgdGhhbiBpbnB1dDoNCg0KYGBge3J9DQp4W2MoMSwgMSwgNSwgNSwgNSwgMildDQoNCmBgYA0KDQpOZWdhdGl2ZSB2YWx1ZXMgZHJvcCB0aGUgZWxlbWVudHMgYXQgdGhlIHNwZWNpZmllZCBwb3NpdGlvbnM6DQoNCmBgYHtyfQ0KeFtjKC0xLCAtMywgLTUpXQ0KDQpgYGANCkl0J3MgYW4gZXJyb3IgdG8gbWl4IHBvc2l0aXZlIGFuZCBuZWdhdGl2ZSB2YWx1ZXM6DQoNCmBgYHtyfQ0KeFtjKDEsIC0xKV0NCmBgYA0KDQpUaGUgZXJyb3IgbWVzc2FnZSBtZW50aW9ucyBzdWJzZXR0aW5nIHdpdGggemVybywgd2hpY2ggcmV0dXJucyBubyB2YWx1ZXM6DQpgYGB7cn0NCnhbMF0NCmBgYA0KVGhpcyBpcyBub3QgdXNlZnVsIHZlcnkgb2Z0ZW4sIGJ1dCBpdCBjYW4gYmUgaGVscGZ1bCBpZiB5b3Ugd2FudCB0byBjcmVhdGUgdW51c3VhbCBkYXRhIHN0cnVjdHVyZXMgdG8gdGVzdCB5b3VyIGZ1bmN0aW9ucyB3aXRoLiA8L3A+DQoNClN1YnNldHRpbmcgd2l0aCBhIGxvZ2ljYWwgdmVjdG9yIGtlZXBzIGFsbCB2YWx1ZXMgY29ycmVzcG9uZGluZyB0byBhIFRSVUUgdmFsdWUuIFRoaXMgaXMgbW9zdCBvZnRlbiB1c2VmdWwgaW4gY29uanVuY3Rpb24gd2l0aCB0aGUgY29tcGFyaXNvbiBmdW5jdGlvbnMuPC9wPg0KYGBge3J9DQp4IDwtIGMoMTAsIDMsIE5BLCA1LCA4LCAxLCBOQSkNCnhbIWlzLm5hKHgpXQ0KYGBgDQoNCmBgYHtyfQ0KIyBBbGwgZXZlbiAob3IgbWlzc2luZyEpIHZhbHVlcyBvZiB4DQp4W3ggJSUgMiA9PSAwXQ0KYGBgDQoNCklmIHlvdSBoYXZlIGEgbmFtZWQgdmVjdG9yLCB5b3UgY2FuIHN1YnNldCBpdCB3aXRoIGEgY2hhcmFjdGVyIHZlY3RvcjoNCg0KYGBge3J9DQp4IDwtIGMoYWJjID0gMSwgZGVmID0gMiwgeHl6ID0gNSkNCnhbYygieHl6IiwgImRlZiIpXQ0KDQpgYGANCg0KTGlrZSB3aXRoIHBvc2l0aXZlIGludGVnZXJzLCB5b3UgY2FuIGFsc28gdXNlIGEgY2hhcmFjdGVyIHZlY3RvciB0byBkdXBsaWNhdGUgaW5kaXZpZHVhbCBlbnRyaWVzLiA8L3A+DQoNClRoZSBzaW1wbGVzdCB0eXBlIG9mIHN1YnNldHRpbmcgaXMgbm90aGluZywgeFtdLCB3aGljaCByZXR1cm5zIHRoZSBjb21wbGV0ZSB4LiBUaGlzIGlzIG5vdCB1c2VmdWwgZm9yIHN1YnNldHRpbmcgdmVjdG9ycywgYnV0IGl0IGlzIHVzZWZ1bCB3aGVuIHN1YnNldHRpbmcgbWF0cmljZXMgKGFuZCBvdGhlciBoaWdoIGRpbWVuc2lvbmFsIHN0cnVjdHVyZXMpIGJlY2F1c2UgaXQgbGV0cyB5b3Ugc2VsZWN0IGFsbCB0aGUgcm93cyBvciBhbGwgdGhlIGNvbHVtbnMsIGJ5IGxlYXZpbmcgdGhhdCBpbmRleCBibGFuay4gRm9yIGV4YW1wbGUsIGlmIHggaXMgMmQsIHhbMSwgXSBzZWxlY3RzIHRoZSBmaXJzdCByb3cgYW5kIGFsbCB0aGUgY29sdW1ucywgYW5kIHhbLCAtMV0gc2VsZWN0cyBhbGwgcm93cyBhbmQgYWxsIGNvbHVtbnMgZXhjZXB0IHRoZSBmaXJzdC4NCmBgYHtyfQ0KeFtdDQpgYGANCg0KPGgzPiBFeGVyY2lzZXMgPC9oMz4NCg0KV2hhdCBkb2VzIG1lYW4oaXMubmEoeCkpIHRlbGwgeW91IGFib3V0IGEgdmVjdG9yIHg/IFdoYXQgYWJvdXQgc3VtKCFpcy5maW5pdGUoeCkpPzwvYnI+DQpUaGUgZXhwcmVzc2lvbiBtZWFuKGlzLm5hKHgpKSBjYWxjdWxhdGVzIHRoZSBwcm9wb3J0aW9uIG9mIG1pc3NpbmcgdmFsdWVzIGluIGEgdmVjdG9yDQpgYGB7cn0NCnggPC0gYygxOjEwLCBOQSwgTmFOLCBJbmYsIC1JbmYpDQptZWFuKGlzLm5hKHgpKQ0KDQpgYGANClRoZSBleHByZXNzaW9uIG1lYW4oIWlzLmZpbml0ZSh4KSkgY2FsY3VhbHRlcyB0aGUgcHJvcG9ydGlvbiBvZiB2YWx1ZXMgdGhhdCBhcmUgTkEsIE5hTiwgb3IgaW5maW5pdGUuDQpgYGB7cn0NCm1lYW4oIWlzLmZpbml0ZSh4KSkNCg0KYGBgDQoNCg0KQ2FyZWZ1bGx5IHJlYWQgdGhlIGRvY3VtZW50YXRpb24gb2YgaXMudmVjdG9yKCkuIFdoYXQgZG9lcyBpdCBhY3R1YWxseSB0ZXN0IGZvcj8gV2h5IGRvZXMgaXMuYXRvbWljKCkgbm90IGFncmVlIHdpdGggdGhlIGRlZmluaXRpb24gb2YgYXRvbWljIHZlY3RvcnMgYWJvdmU/PC9icj4NClRoZSBmdW5jdGlvbiBpcy52ZWN0b3Igb25seSBjaGVja3Mgd2hldGhlciB0aGUgb2JqZWN0IGhhcyBubyBhdHRyaWJ1dGVzIG90aGVyIHRoYW4gbmFtZXMuIFRodXMgYSBsaXN0IGlzIGEgdmVjdG9yOg0KDQpgYGB7cn0NCmlzLnZlY3RvcihsaXN0KGEgPSAxLCBiID0gMikpDQpgYGANCkJ1dCBhbnkgb2JqZWN0IHRoYXQgaGFzIGFuIGF0dHJpYnV0ZSAob3RoZXIgdGhhbiBuYW1lcykgaXMgbm90Og0KYGBge3J9DQp4IDwtIDE6MTANCmF0dHIoeCwgInNvbWV0aGluZyIpIDwtIFRSVUUNCmlzLnZlY3Rvcih4KQ0KYGBgDQpUaGUgaWRlYSBiZWhpbmQgdGhpcyBpcyB0aGF0IG9iamVjdCBvcmllbnRlZCBjbGFzc2VzIHdpbGwgaW5jbHVkZSBhdHRyaWJ1dGVzLCBpbmNsdWRpbmcsIGJ1dCBub3QgbGltaXRlZCB0byAiY2xhc3MiLiBUaGUgZnVuY3Rpb24gaXMuYXRvbWljIGV4cGxpY2l0bHkgY2hlY2tzIHdoZXRoZXIgYW4gb2JqZWN0IGlzIG9uZSBvZiB0aGUgYXRvbWljIHR5cGVzICgibG9naWNhbCIsICJpbnRlZ2VyIiwgIm51bWVyaWMiLCAiY29tcGxleCIsICJjaGFyYWN0ZXIiLCBhbmQgInJhdyIpIG9yIE5VTEwuDQoNCmBgYHtyfQ0KaXMuYXRvbWljKDE6MTApDQojPiBbMV0gVFJVRQ0KaXMuYXRvbWljKGxpc3QoYSA9IDEpKQ0KDQpgYGANCg0KVGhlIGZ1bmN0aW9uIGlzLmF0b21pYyB3aWxsIGNvbnNpZGVyIG9iamVjdHMgdG8gYmUgYXRvbWljIGV2ZW4gaWYgdGhleSBoYXZlIGV4dHJhIGF0dHJpYnV0ZXMuDQoNCmBgYHtyfQ0KDQppcy5hdG9taWMoeCkNCmBgYA0KDQpDb21wYXJlIGFuZCBjb250cmFzdCBzZXROYW1lcygpIHdpdGggcHVycnI6OnNldF9uYW1lcygpLiA8L2JyPg0KVGhlc2UgYXJlIHNpbXBsZSBmdW5jdGlvbnMsIHNvIHdlIGNhbiBzaW1wbHkgcHJpbnQgb3V0IHRoZWlyIHNvdXJjZSBjb2RlOg0KYGBge3J9DQpzZXROYW1lcw0KIz4gZnVuY3Rpb24gKG9iamVjdCA9IG5tLCBubSkgDQojPiB7DQojPiAgICAgbmFtZXMob2JqZWN0KSA8LSBubQ0KIz4gICAgIG9iamVjdA0KIz4gfQ0KIz4gPGJ5dGVjb2RlOiAweDdmY2EyOGE5MjAzOD4NCiM+IDxlbnZpcm9ubWVudDogbmFtZXNwYWNlOnN0YXRzPg0KYGBgDQoNCnB1cnJyOjpzZXRfbmFtZXMNCmBgYHtyfQ0KIz4gZnVuY3Rpb24gKHgsIG5tID0geCkgDQojPiB7DQojPiAgICAgaWYgKCFpc192ZWN0b3IoeCkpIHsNCiM+ICAgICAgICAgc3RvcCgiYHhgIG11c3QgYmUgYSB2ZWN0b3IiLCBjYWxsLiA9IEZBTFNFKQ0KIz4gICAgIH0NCiM+ICAgICBpZiAobGVuZ3RoKHgpICE9IGxlbmd0aChubSkpIHsNCiM+ICAgICAgICAgc3RvcCgiYHhgIGFuZCBgbm1gIG11c3QgYmUgdGhlIHNhbWUgbGVuZ3RoIiwgY2FsbC4gPSBGQUxTRSkNCiM+ICAgICB9DQojPiAgICAgbmFtZXMoeCkgPC0gbm0NCiM+ICAgICB4DQojPiB9DQojPiA8ZW52aXJvbm1lbnQ6IG5hbWVzcGFjZTpwdXJycj4NCmBgYA0KRnJvbSB0aGUgY29kZSB3ZSBjYW4gc2VlIHRoYXQgc2V0X25hbWVzIGFkZHMgYSBmZXcgc2FuaXR5IGNoZWNrczogeCBoYXMgdG8gYmUgYSB2ZWN0b3IsIGFuZCB0aGUgbGVuZ3RocyBvZiB0aGUgb2JqZWN0IGFuZCB0aGUgbmFtZXMgaGF2ZSB0byBiZSB0aGUgc2FtZS4gPC9wPg0KDQoNCg0KVGhlIGxhc3QgdmFsdWUuIFNob3VsZCB5b3UgdXNlIFsgb3IgW1s/IDwvYnI+DQoNClRoZSBlbGVtZW50cyBhdCBldmVuIG51bWJlcmVkIHBvc2l0aW9ucy4NCg0KRXZlcnkgZWxlbWVudCBleGNlcHQgdGhlIGxhc3QgdmFsdWUuDQoNCk9ubHkgZXZlbiBudW1iZXJzIChhbmQgbm8gbWlzc2luZyB2YWx1ZXMpLg0KDQpXaHkgaXMgeFstd2hpY2goeCA+IDApXSBub3QgdGhlIHNhbWUgYXMgeFt4IDw9IDBdPw0KDQpXaGF0IGhhcHBlbnMgd2hlbiB5b3Ugc3Vic2V0IHdpdGggYSBwb3NpdGl2ZSBpbnRlZ2VyIHRoYXQncyBiaWdnZXIgdGhhbiB0aGUgbGVuZ3RoIG9mIHRoZSB2ZWN0b3I/IFdoYXQgaGFwcGVucyB3aGVuIHlvdSBzdWJzZXQgd2l0aCBhIG5hbWUgdGhhdCBkb2Vzbid0IGV4aXN0PyA8L2JyPg0KV2hlbiB5b3Ugc3Vic2V0IHdpdGggcG9zaXRpdmUgaW50ZWdlcnMgdGhhdCBhcmUgbGFyZ2VyIHRoYW4gdGhlIGxlbmd0aCBvZiB0aGUgdmVjdG9yLCBOQSB2YWx1ZXMgYXJlIHJldHVybmVkIGZvciB0aG9zZSBpbnRlZ2VycyBsYXJnZXIgdGhhbiB0aGUgbGVuZ3RoIG9mIHRoZSB2ZWN0b3IuDQpgYGB7cn0NCigxOjEwKVsxMToxMl0NCg0KYGBgDQoNCldoZW4gYSB2ZWN0b3IgaXMgc3Vic2V0IHdpdGggYSBuYW1lIHRoYXQgZG9lc24ndCBleGlzdCwgYW4gZXJyb3IgaXMgZ2VuZXJhdGVkLg0KYGBge3J9DQpjKGEgPSAxLCAyKVtbImIiXV0NCmBgYA0KDQo8aDI+IFJlY3Vyc2l2ZSBWZWN0b3JzIC0tTGlzdHMgPC9oMj4NCg0KTGlzdHMgYXJlIGEgc3RlcCB1cCBpbiBjb21wbGV4aXR5IGZyb20gYXRvbWljIHZlY3RvcnMsIGJlY2F1c2UgbGlzdHMgY2FuIGNvbnRhaW4gb3RoZXIgbGlzdHMuIFRoaXMgbWFrZXMgdGhlbSBzdWl0YWJsZSBmb3IgcmVwcmVzZW50aW5nIGhpZXJhcmNoaWNhbCBvciB0cmVlLWxpa2Ugc3RydWN0dXJlcy4gWW91IGNyZWF0ZSBhIGxpc3Qgd2l0aCBsaXN0KCk6DQpgYGB7cn0NCnggPC0gbGlzdCgxLCAyLCAzKQ0KeA0KYGBgDQpBIHZlcnkgdXNlZnVsIHRvb2wgZm9yIHdvcmtpbmcgd2l0aCBsaXN0cyBpcyBzdHIoKSBiZWNhdXNlIGl0IGZvY3Vzc2VzIG9uIHRoZSBzdHJ1Y3R1cmUsIG5vdCB0aGUgY29udGVudHMuDQoNCmBgYHtyfQ0Kc3RyKHgpDQpgYGANCg0KYGBge3J9DQp4X25hbWVkIDwtIGxpc3QoYSA9IDEsIGIgPSAyLCBjID0gMykNCnN0cih4X25hbWVkKQ0KYGBgDQpVbmxpa2UgYXRvbWljIHZlY3RvcnMsIGxpc3QoKSBjYW4gY29udGFpbiBhIG1peCBvZiBvYmplY3RzOg0KDQpgYGB7cn0NCnkgPC0gbGlzdCgiYSIsIDFMLCAxLjUsIFRSVUUpDQpzdHIoeSkNCmBgYA0KDQpMaXN0cyBjYW4gZXZlbiBjb250YWluIG90aGVyIGxpc3RzIQ0KYGBge3J9DQp6IDwtIGxpc3QobGlzdCgxLCAyKSwgbGlzdCgzLCA0KSkNCnN0cih6KQ0KYGBgDQoNCjxoMz4gVmlzdWFsaXppbmcgTGlzdHMgPC9oMz4NClRvIGV4cGxhaW4gbW9yZSBjb21wbGljYXRlZCBsaXN0IG1hbmlwdWxhdGlvbiBmdW5jdGlvbnMsIGl0J3MgaGVscGZ1bCB0byBoYXZlIGEgdmlzdWFsIHJlcHJlc2VudGF0aW9uIG9mIGxpc3RzLiBGb3IgZXhhbXBsZSwgdGFrZSB0aGVzZSB0aHJlZSBsaXN0czoNCg0KYGBge3J9DQp4MSA8LSBsaXN0KGMoMSwgMiksIGMoMywgNCkpDQp4MiA8LSBsaXN0KGxpc3QoMSwgMiksIGxpc3QoMywgNCkpDQp4MyA8LSBsaXN0KDEsIGxpc3QoMiwgbGlzdCgzKSkpDQoNCmBgYA0KDQo8aW1nIHNyYz0iaHR0cDovL3I0ZHMuaGFkLmNvLm56L2RpYWdyYW1zL2xpc3RzLXN0cnVjdHVyZS5wbmciIC8+DQoNClRoZXJlIGFyZSB0aHJlZSBwcmluY2lwbGVzOiA8L2JyPg0KDQpMaXN0cyBoYXZlIHJvdW5kZWQgY29ybmVycy4gQXRvbWljIHZlY3RvcnMgaGF2ZSBzcXVhcmUgY29ybmVycy48L2JyPg0KDQpDaGlsZHJlbiBhcmUgZHJhd24gaW5zaWRlIHRoZWlyIHBhcmVudCwgYW5kIGhhdmUgYSBzbGlnaHRseSBkYXJrZXIgYmFja2dyb3VuZCB0byBtYWtlIGl0IGVhc2llciB0byBzZWUgdGhlIGhpZXJhcmNoeS48L2JyPg0KDQpUaGUgb3JpZW50YXRpb24gb2YgdGhlIGNoaWxkcmVuIChpLmUuIHJvd3Mgb3IgY29sdW1ucykgaXNuJ3QgaW1wb3J0YW50LCBzbyBJJ2xsIHBpY2sgYSByb3cgb3IgY29sdW1uIG9yaWVudGF0aW9uIHRvIGVpdGhlciBzYXZlIHNwYWNlIG9yIGlsbHVzdHJhdGUgYW4gaW1wb3J0YW50IHByb3BlcnR5IGluIHRoZSBleGFtcGxlLjwvYnI+DQoNCjxoMz4gU3Vic2V0dGluZyA8L2gzPg0KVGhlcmUgYXJlIHRocmVlIHdheXMgdG8gc3Vic2V0IGEgbGlzdCwgd2hpY2ggSSdsbCBpbGx1c3RyYXRlIHdpdGggYSBsaXN0IG5hbWVkIGE6DQoNCmBgYHtyfQ0KYSA8LSBsaXN0KGEgPSAxOjMsIGIgPSAiYSBzdHJpbmciLCBjID0gcGksIGQgPSBsaXN0KC0xLCAtNSkpDQpgYGANCg0KWyBleHRyYWN0cyBhIHN1Yi1saXN0LiBUaGUgcmVzdWx0IHdpbGwgYWx3YXlzIGJlIGEgbGlzdC4NCg0KYGBge3J9DQpzdHIoYVsxOjJdKQ0KDQpzdHIoYVs0XSkNCmBgYA0KTGlrZSB3aXRoIHZlY3RvcnMsIHlvdSBjYW4gc3Vic2V0IHdpdGggYSBsb2dpY2FsLCBpbnRlZ2VyLCBvciBjaGFyYWN0ZXIgdmVjdG9yLg0KW1sgZXh0cmFjdHMgYSBzaW5nbGUgY29tcG9uZW50IGZyb20gYSBsaXN0LiBJdCByZW1vdmVzIGEgbGV2ZWwgb2YgaGllcmFyY2h5IGZyb20gdGhlIGxpc3QuDQoNCmBgYHtyfQ0Kc3RyKGFbWzFdXSkNCnN0cihhW1s0XV0pDQpgYGANCg0KJCBpcyBhIHNob3J0aGFuZCBmb3IgZXh0cmFjdGluZyBuYW1lZCBlbGVtZW50cyBvZiBhIGxpc3QuIEl0IHdvcmtzIHNpbWlsYXJseSB0byBbWyBleGNlcHQgdGhhdCB5b3UgZG9uJ3QgbmVlZCB0byB1c2UgcXVvdGVzLg0KDQpgYGB7cn0NCmEkYQ0KYGBgDQoNClRoZSBkaXN0aW5jdGlvbiBiZXR3ZWVuIFsgYW5kIFtbIGlzIHJlYWxseSBpbXBvcnRhbnQgZm9yIGxpc3RzLCBiZWNhdXNlIFtbIGRyaWxscyBkb3duIGludG8gdGhlIGxpc3Qgd2hpbGUgWyByZXR1cm5zIGEgbmV3LCBzbWFsbGVyIGxpc3QuIENvbXBhcmUgdGhlIGNvZGUgYW5kIG91dHB1dCBhYm92ZSB3aXRoIHRoZSB2aXN1YWwgcmVwcmVzZW50YXRpb24gaW4gIHRoZSBmaWd1cmUgYmVsb3cNCjxpbWcgc3JjPSJodHRwOi8vcjRkcy5oYWQuY28ubnovZGlhZ3JhbXMvbGlzdHMtc3Vic2V0dGluZy5wbmciIC8+DQoNCg0KPGgyPiBBdHRyaWJ1dGVzIDwvaDI+DQoNCkFueSB2ZWN0b3IgY2FuIGNvbnRhaW4gYXJiaXRyYXJ5IGFkZGl0aW9uYWwgbWV0YWRhdGEgdGhyb3VnaCBpdHMgYXR0cmlidXRlcy4gWW91IGNhbiB0aGluayBvZiBhdHRyaWJ1dGVzIGFzIG5hbWVkIGxpc3Qgb2YgdmVjdG9ycyB0aGF0IGNhbiBiZSBhdHRhY2hlZCB0byBhbnkgb2JqZWN0LiBZb3UgY2FuIGdldCBhbmQgc2V0IGluZGl2aWR1YWwgYXR0cmlidXRlIHZhbHVlcyB3aXRoIGF0dHIoKSBvciBzZWUgdGhlbSBhbGwgYXQgb25jZSB3aXRoIGF0dHJpYnV0ZXMoKS4gDQoNCmBgYHtyfQ0KeCA8LSAxOjEwDQphdHRyKHgsICJncmVldGluZyIpDQpgYGANCg0KYGBge3J9DQphdHRyKHgsICJncmVldGluZyIpIDwtICJIaSEiDQphdHRyKHgsICJmYXJld2VsbCIpIDwtICJCeWUhIg0KYXR0cmlidXRlcyh4KQ0KYGBgDQpUaGVyZSBhcmUgdGhyZWUgdmVyeSBpbXBvcnRhbnQgYXR0cmlidXRlcyB0aGF0IGFyZSB1c2VkIHRvIGltcGxlbWVudCBmdW5kYW1lbnRhbCBwYXJ0cyBvZiBSOiA8L2JyPg0KDQoxLiBOYW1lcyBhcmUgdXNlZCB0byBuYW1lIHRoZSBlbGVtZW50cyBvZiBhIHZlY3Rvci4gPC9icj4NCjIuIERpbWVuc2lvbnMgKGRpbXMsIGZvciBzaG9ydCkgbWFrZSBhIHZlY3RvciBiZWhhdmUgbGlrZSBhIG1hdHJpeCBvciBhcnJheS48L2JyPg0KMy4gQ2xhc3MgaXMgdXNlZCB0byBpbXBsZW1lbnQgdGhlIFMzIG9iamVjdCBvcmllbnRlZCBzeXN0ZW0uPC9wPg0KDQpZb3UndmUgc2VlbiBuYW1lcyBhYm92ZSwgYW5kIHdlIHdvbid0IGNvdmVyIGRpbWVuc2lvbnMgYmVjYXVzZSB3ZSBkb24ndCB1c2UgbWF0cmljZXMgaW4gdGhpcyBib29rLiBJdCByZW1haW5zIHRvIGRlc2NyaWJlIHRoZSBjbGFzcywgd2hpY2ggY29udHJvbHMgaG93IGdlbmVyaWMgZnVuY3Rpb25zIHdvcmsuIEdlbmVyaWMgZnVuY3Rpb25zIGFyZSBrZXkgdG8gb2JqZWN0IG9yaWVudGVkIHByb2dyYW1taW5nIGluIFIsIGJlY2F1c2UgdGhleSBtYWtlIGZ1bmN0aW9ucyBiZWhhdmUgZGlmZmVyZW50bHkgZm9yIGRpZmZlcmVudCBjbGFzc2VzIG9mIGlucHV0LiBBIGRldGFpbGVkIGRpc2N1c3Npb24gb2Ygb2JqZWN0IG9yaWVudGVkIHByb2dyYW1taW5nIGlzIGJleW9uZCB0aGUgc2NvcGUgb2YgdGhpcyBib29rLCBidXQgeW91IGNhbiByZWFkIG1vcmUgYWJvdXQgaXQgaW4gQWR2YW5jZWQgUiBhdCBodHRwOi8vYWR2LXIuaGFkLmNvLm56L09PLWVzc2VudGlhbHMuaHRtbCNzMy4NCjwvcD4NCkhlcmUncyB3aGF0IGEgdHlwaWNhbCBnZW5lcmljIGZ1bmN0aW9uIGxvb2tzIGxpa2U6DQpgYGB7cn0NCmFzLkRhdGUNCiM+IGZ1bmN0aW9uICh4LCAuLi4pIA0KIz4gVXNlTWV0aG9kKCJhcy5EYXRlIikNCiM+IDxieXRlY29kZTogMHg2YjQyMjg4Pg0KIz4gPGVudmlyb25tZW50OiBuYW1lc3BhY2U6YmFzZT4NCg0KYGBgDQoNClRoZSBjYWxsIHRvICJVc2VNZXRob2QiIG1lYW5zIHRoYXQgdGhpcyBpcyBhIGdlbmVyaWMgZnVuY3Rpb24sIGFuZCBpdCB3aWxsIGNhbGwgYSBzcGVjaWZpYyBtZXRob2QsIGEgZnVuY3Rpb24sIGJhc2VkIG9uIHRoZSBjbGFzcyBvZiB0aGUgZmlyc3QgYXJndW1lbnQuIChBbGwgbWV0aG9kcyBhcmUgZnVuY3Rpb25zOyBub3QgYWxsIGZ1bmN0aW9ucyBhcmUgbWV0aG9kcykuIFlvdSBjYW4gbGlzdCBhbGwgdGhlIG1ldGhvZHMgZm9yIGEgZ2VuZXJpYyB3aXRoIG1ldGhvZHMoKToNCmBgYHtyfQ0KbWV0aG9kcygiYXMuRGF0ZSIpDQojPiBbMV0gYXMuRGF0ZS5jaGFyYWN0ZXIgYXMuRGF0ZS5kYXRlICAgICAgYXMuRGF0ZS5kYXRlcyAgICAgYXMuRGF0ZS5kZWZhdWx0ICANCiM+IFs1XSBhcy5EYXRlLmZhY3RvciAgICBhcy5EYXRlLm51bWVyaWMgICBhcy5EYXRlLlBPU0lYY3QgICBhcy5EYXRlLlBPU0lYbHQgIA0KIz4gc2VlICc/bWV0aG9kcycgZm9yIGFjY2Vzc2luZyBoZWxwIGFuZCBzb3VyY2UgY29kZQ0KDQpgYGANCg0KRm9yIGV4YW1wbGUsIGlmIHggaXMgYSBjaGFyYWN0ZXIgdmVjdG9yLCBhcy5EYXRlKCkgd2lsbCBjYWxsIGFzLkRhdGUuY2hhcmFjdGVyKCk7IGlmIGl0J3MgYSBmYWN0b3IsIGl0J2xsIGNhbGwgYXMuRGF0ZS5mYWN0b3IoKS4NCg0KWW91IGNhbiBzZWUgdGhlIHNwZWNpZmljIGltcGxlbWVudGF0aW9uIG9mIGEgbWV0aG9kIHdpdGggZ2V0UzNtZXRob2QoKToNCg0KYGBge3J9DQpnZXRTM21ldGhvZCgiYXMuRGF0ZSIsICJkZWZhdWx0IikNCiM+IGZ1bmN0aW9uICh4LCAuLi4pIA0KIz4gew0KIz4gICAgIGlmIChpbmhlcml0cyh4LCAiRGF0ZSIpKSANCiM+ICAgICAgICAgcmV0dXJuKHgpDQojPiAgICAgaWYgKGlzLmxvZ2ljYWwoeCkgJiYgYWxsKGlzLm5hKHgpKSkgDQojPiAgICAgICAgIHJldHVybihzdHJ1Y3R1cmUoYXMubnVtZXJpYyh4KSwgY2xhc3MgPSAiRGF0ZSIpKQ0KIz4gICAgIHN0b3AoZ2V0dGV4dGYoImRvIG5vdCBrbm93IGhvdyB0byBjb252ZXJ0ICclcycgdG8gY2xhc3MgJXMiLCANCiM+ICAgICAgICAgZGVwYXJzZShzdWJzdGl0dXRlKHgpKSwgZFF1b3RlKCJEYXRlIikpLCBkb21haW4gPSBOQSkNCiM+IH0NCiM+IDxieXRlY29kZTogMHg1NzNhNjc4Pg0KIz4gPGVudmlyb25tZW50OiBuYW1lc3BhY2U6YmFzZT4NCmdldFMzbWV0aG9kKCJhcy5EYXRlIiwgIm51bWVyaWMiKQ0KIz4gZnVuY3Rpb24gKHgsIG9yaWdpbiwgLi4uKSANCiM+IHsNCiM+ICAgICBpZiAobWlzc2luZyhvcmlnaW4pKSANCiM+ICAgICAgICAgc3RvcCgiJ29yaWdpbicgbXVzdCBiZSBzdXBwbGllZCIpDQojPiAgICAgYXMuRGF0ZShvcmlnaW4sIC4uLikgKyB4DQojPiB9DQojPiA8Ynl0ZWNvZGU6IDB4NTczZDZiOD4NCiM+IDxlbnZpcm9ubWVudDogbmFtZXNwYWNlOmJhc2U+DQpgYGANCg0KVGhlIG1vc3QgaW1wb3J0YW50IFMzIGdlbmVyaWMgaXMgcHJpbnQoKTogaXQgY29udHJvbHMgaG93IHRoZSBvYmplY3QgaXMgcHJpbnRlZCB3aGVuIHlvdSB0eXBlIGl0cyBuYW1lIGF0IHRoZSBjb25zb2xlLiBPdGhlciBpbXBvcnRhbnQgZ2VuZXJpY3MgYXJlIHRoZSBzdWJzZXR0aW5nIGZ1bmN0aW9ucyBbLCBbWywgYW5kICQuDQoNCjxoMj4gQXVnbWVudGVkIFZlY3RvcnMgPC9oMj4NCg0KQXRvbWljIHZlY3RvcnMgYW5kIGxpc3RzIGFyZSB0aGUgYnVpbGRpbmcgYmxvY2tzIGZvciBvdGhlciBpbXBvcnRhbnQgdmVjdG9yIHR5cGVzIGxpa2UgZmFjdG9ycyBhbmQgZGF0ZXMuIEkgY2FsbCB0aGVzZSBhdWdtZW50ZWQgdmVjdG9ycywgYmVjYXVzZSB0aGV5IGFyZSB2ZWN0b3JzIHdpdGggYWRkaXRpb25hbCBhdHRyaWJ1dGVzLCBpbmNsdWRpbmcgY2xhc3MuIEJlY2F1c2UgYXVnbWVudGVkIHZlY3RvcnMgaGF2ZSBhIGNsYXNzLCB0aGV5IGJlaGF2ZSBkaWZmZXJlbnRseSB0byB0aGUgYXRvbWljIHZlY3RvciBvbiB3aGljaCB0aGV5IGFyZSBidWlsdC4gSW4gdGhpcyBib29rLCB3ZSBtYWtlIHVzZSBvZiBmb3VyIGltcG9ydGFudCBhdWdtZW50ZWQgdmVjdG9yczogPC9wPg0KDQpGYWN0b3JzIDwvYnI+DQpEYXRlcyA8L2JyPg0KRGF0ZS10aW1lcyA8L2JyPg0KVGliYmxlcyA8L2JyPg0KDQo8aDM+IEZhY3RvcnMgPC9oMz4NCkZhY3RvcnMgYXJlIGRlc2lnbmVkIHRvIHJlcHJlc2VudCBjYXRlZ29yaWNhbCBkYXRhIHRoYXQgY2FuIHRha2UgYSBmaXhlZCBzZXQgb2YgcG9zc2libGUgdmFsdWVzLiBGYWN0b3JzIGFyZSBidWlsdCBvbiB0b3Agb2YgaW50ZWdlcnMsIGFuZCBoYXZlIGEgbGV2ZWxzIGF0dHJpYnV0ZToNCg0KYGBge3J9DQp4IDwtIGZhY3RvcihjKCJhYiIsICJjZCIsICJhYiIpLCBsZXZlbHMgPSBjKCJhYiIsICJjZCIsICJlZiIpKQ0KdHlwZW9mKHgpDQphdHRyaWJ1dGVzKHgpDQpgYGANCiANCiA8aDM+IERhdGVzIGFuZCBEYXRlLVRpbWVzIDwvaDM+DQogDQogRGF0ZXMgaW4gUiBhcmUgbnVtZXJpYyB2ZWN0b3JzIHRoYXQgcmVwcmVzZW50IHRoZSBudW1iZXIgb2YgZGF5cyBzaW5jZSAxIEphbnVhcnkgMTk3MC4NCiANCiANCmBgYHtyfQ0KeCA8LSBhcy5EYXRlKCIxOTcxLTAxLTAxIikNCnVuY2xhc3MoeCkNCiM+IFsxXSAzNjUNCg0KdHlwZW9mKHgpDQojPiBbMV0gImRvdWJsZSINCmF0dHJpYnV0ZXMoeCkNCiM+ICRjbGFzcw0KIz4gWzFdICJEYXRlIg0KYGBgDQpEYXRlLXRpbWVzIGFyZSBudW1lcmljIHZlY3RvcnMgd2l0aCBjbGFzcyBQT1NJWGN0IHRoYXQgcmVwcmVzZW50IHRoZSBudW1iZXIgb2Ygc2Vjb25kcyBzaW5jZSAxIEphbnVhcnkgMTk3MC4gKEluIGNhc2UgeW91IHdlcmUgd29uZGVyaW5nLCAiUE9TSVhjdCIgc3RhbmRzIGZvciAiUG9ydGFibGUgT3BlcmF0aW5nIFN5c3RlbSBJbnRlcmZhY2UiLCBjYWxlbmRhciB0aW1lLikNCg0KYGBge3J9DQp4IDwtIGx1YnJpZGF0ZTo6eW1kX2htKCIxOTcwLTAxLTAxIDAxOjAwIikNCnVuY2xhc3MoeCkNCmBgYA0KDQpgYGB7cn0NCnR5cGVvZih4KQ0KYXR0cmlidXRlcyh4KQ0KYGBgDQpUaGUgdHpvbmUgYXR0cmlidXRlIGlzIG9wdGlvbmFsLiBJdCBjb250cm9scyBob3cgdGhlIHRpbWUgaXMgcHJpbnRlZCwgbm90IHdoYXQgYWJzb2x1dGUgdGltZSBpdCByZWZlcnMgdG8uDQoNCmBgYHtyfQ0KYXR0cih4LCAidHpvbmUiKSA8LSAiVVMvUGFjaWZpYyINCngNCg0KYGBgDQoNCmBgYHtyfQ0KYXR0cih4LCAidHpvbmUiKSA8LSAiVVMvRWFzdGVybiINCngNCmBgYA0KVGhlcmUgaXMgYW5vdGhlciB0eXBlIG9mIGRhdGUtdGltZXMgY2FsbGVkIFBPU0lYbHQuIFRoZXNlIGFyZSBidWlsdCBvbiB0b3Agb2YgbmFtZWQgbGlzdHM6DQoNCmBgYHtyfQ0KeSA8LSBhcy5QT1NJWGx0KHgpDQp0eXBlb2YoeSkNCmF0dHJpYnV0ZXMoeSkNCmBgYA0KDQpQT1NJWGx0cyBhcmUgcmFyZSBpbnNpZGUgdGhlIHRpZHl2ZXJzZS4gVGhleSBkbyBjcm9wIHVwIGluIGJhc2UgUiwgYmVjYXVzZSB0aGV5IGFyZSBuZWVkZWQgdG8gZXh0cmFjdCBzcGVjaWZpYyBjb21wb25lbnRzIG9mIGEgZGF0ZSwgbGlrZSB0aGUgeWVhciBvciBtb250aC4gU2luY2UgbHVicmlkYXRlIHByb3ZpZGVzIGhlbHBlcnMgZm9yIHlvdSB0byBkbyB0aGlzIGluc3RlYWQsIHlvdSBkb24ndCBuZWVkIHRoZW0uIFBPU0lYY3QncyBhcmUgYWx3YXlzIGVhc2llciB0byB3b3JrIHdpdGgsIHNvIGlmIHlvdSBmaW5kIHlvdSBoYXZlIGEgUE9TSVhsdCwgeW91IHNob3VsZCBhbHdheXMgY29udmVydCBpdCB0byBhIHJlZ3VsYXIgZGF0YSB0aW1lIGx1YnJpZGF0ZTo6YXNfZGF0ZV90aW1lKCkuDQo8L3A+DQoNCjxoMz4gVGliYmxlcyA8L2gzPg0KVGliYmxlcyBhcmUgYXVnbWVudGVkIGxpc3RzOiB0aGV5IGhhdmUgY2xhc3MgInRibF9kZiIgKyAidGJsIiArICJkYXRhLmZyYW1lIiwgYW5kIG5hbWVzIChjb2x1bW4pIGFuZCByb3cubmFtZXMgYXR0cmlidXRlczogDQoNCmBgYHtyfQ0KdGIgPC0gdGliYmxlOjp0aWJibGUoeCA9IDE6NSwgeSA9IDU6MSkNCnR5cGVvZih0YikNCmF0dHJpYnV0ZXModGIpDQpgYGANClRoZSBkaWZmZXJlbmNlIGJldHdlZW4gYSB0aWJibGUgYW5kIGEgbGlzdCBpcyB0aGF0IGFsbCB0aGUgZWxlbWVudHMgb2YgYSBkYXRhIGZyYW1lIG11c3QgYmUgdmVjdG9ycyB3aXRoIHRoZSBzYW1lIGxlbmd0aC4gQWxsIGZ1bmN0aW9ucyB0aGF0IHdvcmsgd2l0aCB0aWJibGVzIGVuZm9yY2UgdGhpcyBjb25zdHJhaW50Lg0KDQpUcmFkaXRpb25hbCBkYXRhLmZyYW1lcyBoYXZlIGEgdmVyeSBzaW1pbGFyIHN0cnVjdHVyZToNCg0KYGBge3J9DQpkZiA8LSBkYXRhLmZyYW1lKHggPSAxOjUsIHkgPSA1OjEpDQp0eXBlb2YoZGYpDQoNCmF0dHJpYnV0ZXMoZGYpDQpgYGANCg0KVGhlIG1haW4gZGlmZmVyZW5jZSBpcyB0aGUgY2xhc3MuIFRoZSBjbGFzcyBvZiB0aWJibGUgaW5jbHVkZXMgImRhdGEuZnJhbWUiIHdoaWNoIG1lYW5zIHRpYmJsZXMgaW5oZXJpdCB0aGUgcmVndWxhciBkYXRhIGZyYW1lIGJlaGF2aW91ciBieSBkZWZhdWx0Lg0KDQo8aDM+IEV4ZXJjaXNlIDwvaDM+DQoNCldoYXQgZG9lcyBobXM6OmhtcygzNjAwKSByZXR1cm4/IEhvdyBkb2VzIGl0IHByaW50PyBXaGF0IHByaW1pdGl2ZSB0eXBlIGlzIHRoZSBhdWdtZW50ZWQgdmVjdG9yIGJ1aWx0IG9uIHRvcCBvZj8gV2hhdCBhdHRyaWJ1dGVzIGRvZXMgaXQgdXNlPw0KDQpgYGB7cn0NCnggPC0gaG1zOjpobXMoMzYwMCkNCmNsYXNzKHgpDQp4DQp0eXBlb2YoeCkNCmF0dHJpYnV0ZXMoeCkNCg0KYGBgDQpobXM6OmhtcyByZXR1cm5zIGFuIG9iamVjdCBvZiBjbGFzcywgYW5kIHByaW50cyB0aGUgdGltZSBpbiAiJUg6JU06JVMiIGZvcm1hdC4gVGhlIHByaW1pdGl2ZSB0eXBlIGlzIGEgZG91YmxlLiBUaGUgYXR0dHJpYnV0ZXMgaXMgdXNlcyBhcmUgInVuaXRzIiBhbmQgImNsYXNzIi4NCg0KVHJ5IGFuZCBtYWtlIGEgdGliYmxlIHRoYXQgaGFzIGNvbHVtbnMgd2l0aCBkaWZmZXJlbnQgbGVuZ3Rocy4gV2hhdCBoYXBwZW5zPw0KSWYgSSB0cnkgdG8gY3JlYXRlIGF0IHRpYmJsZSB3aXRoIGEgc2NhbGFyIGFuZCBjb2x1bW4gb2YgYSBkaWZmZXJlbnQgbGVuZ3RoIHRoZXJlIGFyZSBubyBpc3N1ZXMsIGFuZCB0aGUgc2NhbGFyIGlzIHJlcGVhdGVkIHRvIHRoZSBsZW5ndGggb2YgdGhlIGxvbmdlciB2ZWN0b3IuDQoNCmBgYHtyfQ0KdGliYmxlKHggPSAxLCB5ID0gMTo1KQ0KYGBgDQoNCkhvd2V2ZXIsIGlmIEkgdHJ5IHRvIGNyZWF0ZSBhIHRpYmJsZSB3aXRoIHR3byB2ZWN0b3JzIG9mIGRpZmZlcmVudCBsZW5ndGhzIChvdGhlciB0aGFuIG9uZSksIHRoZSB0aWJibGUgZnVuY3Rpb24gdGhyb3dzIGFuIGVycm9yLg0KDQpgYGB7cn0NCnRpYmJsZSh4ID0gMTozLCB5ID0gMTo0KQ0KYGBgDQpCYXNlZCBvbiB0aGUgZGVmaW5pdGlvbiBhYm92ZSwgaXMgaXQgb2sgdG8gaGF2ZSBhIGxpc3QgYXMgYSBjb2x1bW4gb2YgYSB0aWJibGU/PC9icj4NCkJ1dCB0aGVyZSBpcyBub3RoaW5nIHRoYXQgcHJldmVudHMgYSB0aWJibGUgZnJvbSBoYXZpbmcgdmVjdG9ycyBvZiBkaWZmZXJlbnQgdHlwZXM6IGRvdWJsZXMsIGNoYXJhY3RlciwgaW50ZWdlcnMsIGxvZ2ljYWwsIGZhY3RvciwgZGF0ZS4gVGhlIGxhdGVyIGFyZSBzdGlsbCBhdG9taWMsIGJ1dCB0aGV5IGhhdmUgYWRkaXRpb25hbCBhdHRyaWJ1dGVzLiBTbywgbWF5YmUgdGhlcmUgd29uJ3QgYmUgYW4gaXNzdWUgd2l0aCBhIGxpc3QgdmVjdG9yIGFzIGxvbmcgYXMgaXQgaXMgdGhlIHNhbWUgbGVuZ3RoLg0KDQpgYGB7cn0NCnRpYmJsZSh4ID0gMTozLCB5ID0gbGlzdCgiYSIsIDEsIGxpc3QoMTozKSkpDQpgYGANCkl0IHdvcmtzISBJIGV2ZW4gdXNlZCBhIGxpc3Qgd2l0aCBoZXRlcm9nZW5vdXMgdHlwZXMgYW5kIHRoZXJlIHdhc24ndCBhbiBpc3N1ZS4gSW4gZm9sbG93aW5nIGNoYXB0ZXJzIHdlJ2xsIHNlZSB0aGF0IGxpc3QgdmVjdG9ycyBjYW4gYmUgdmVyeSB1c2VmdWw6IGZvciBleGFtcGxlLCB3aGVuIHByb2Nlc3NpbmcgbWFueSBkaWZmZXJlbnQgbW9kZWxzLg0K