suppressPackageStartupMessages(library("tidyverse"))

1. What does mean(is.na(x)) tell you about a vector x? What about `sum(!is.finite(x))?

I’ll use the numeric vector x to compare the behaviors of is.na() and is.finite(). It contains numbers (-1, 0, 1) as well as all the special numeric values: infinity (Inf), missing (NA), and not-a-number (NaN).

x <- c(-Inf, -1, 0, 1, Inf, NA, NaN)

The expression mean(is.na(x)) calculates the proportion of missing values (values equal to NA) in a vector.

mean(is.na(x))
[1] 0.2857143

The expression sum(!is.finite(x)) calculates the number of elements in the vector that are equal to missing (NA), not-a-number (NaN), or infinity (Inf).

sum(!is.finite(x))
[1] 4

Review the Numeric section for the differences between is.na() and is.finite().

2. 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
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

3. Compare and contrast setNames() with purrr::set_names().

The function setNames() takes two arguments, a vector to be named and a vector of names to apply to its elements.

setNames(1:4, c("a", "b", "c", "d"))
a b c d 
1 2 3 4 

You can use the values of the vector as its names if the nm argument is used.

setNames(nm = c("a", "b", "c", "d"))
  a   b   c   d 
"a" "b" "c" "d" 

The function set_names() has more ways to set the names than setNames(). The names can be specified in the same manner as setNames().

purrr::set_names(1:4, c("a", "b", "c", "d"))
a b c d 
1 2 3 4 

The names can also be specified as unnamed arguments,

purrr::set_names(1:4, "a", "b", "c", "d")
a b c d 
1 2 3 4 

The function set_names() will name an object with itself if no nm argument is provided (the opposite of setNames() behavior).

purrr::set_names(c("a", "b", "c", "d"))
  a   b   c   d 
"a" "b" "c" "d" 

The biggest difference between set_names() and setNames() is that set_names() allows for using a function or formula to transform the existing names.

purrr::set_names(c(a = 1, b = 2, c = 3), toupper)
A B C 
1 2 3 
purrr::set_names(c(a = 1, b = 2, c = 3), ~ toupper(.))
A B C 
1 2 3 

The set_names() function also checks that the length of the names argument is the same length as the vector that is being named, and will raise an error if it is not.

#purrr::set_names(1:4, c("a", "b"))
#>Error: `nm` must be `NULL` or a character vector the same length as `x`

The setNames() function will allow the names to be shorter than the vector being named, and will set the missing names to NA.

setNames(1:4, c("a", "b"))
   a    b <NA> <NA> 
   1    2    3    4 

4.Create functions that take a vector as input and returns:

1. The last value. Should you use [ or [[? 2. The elements at even numbered positions. 3. Every element except the last value. 4. Only even numbers (and no missing values).

The answers to the parts follow.

1. This function find the last value in a vector.

last_value <- function(x) {
  # check for case with no length
  if (length(x)) {
    x[[length(x)]]
  } else {
    x
  }
}
last_value(numeric())
numeric(0)
last_value(1)
[1] 1
last_value(1:10)
[1] 10

The function uses [[ in order to extract a single element.

2. This function returns the elements at even number positions.

even_indices <- function(x) {
  if (length(x)) {
    x[seq_along(x) %% 2 == 0]
  } else {
    x
  }
}
even_indices(numeric())
numeric(0)
even_indices(1)
numeric(0)
even_indices(1:10)
[1]  2  4  6  8 10
# test using case to ensure that values not indices
# are being returned
even_indices(letters)
 [1] "b" "d" "f" "h" "j" "l" "n" "p" "r" "t" "v" "x" "z"

3. This function returns a vector with every element except the last.

not_last <- function(x) {
  n <- length(x)
  if (n) {
    x[-n]
  } else {
    # n == 0
    x
  }
}
not_last(1:3)
[1] 1 2

We should also confirm that the function works with some edge cases, like a vector with one element, and a vector with zero elements.

not_last(1)
numeric(0)
not_last(numeric())
numeric(0)

In both these cases, not_last() correctly returns an empty vector.

4. This function returns the elements of a vector that are even numbers.

even_numbers <- function(x) {
  x[x %% 2 == 0]
}
even_numbers(-4:4)
[1] -4 -2  0  2  4

We could improve this function by handling the special numeric values: NA, NaN, Inf. However, first we need to decide how to handle them. Neither NaN nor Inf are numbers, and so they are neither even nor odd. In other words, since NaN nor Inf aren’t even numbers, they aren’t even numbers. What about NA? Well, we don’t know. NA is a number, but we don’t know its value. The missing number could be even or odd, but we don’t know. Another reason to return NA is that it is consistent with the behavior of other R functions, which generally return NA values instead of dropping them.

even_numbers2 <- function(x) {
  x[!is.infinite(x) & !is.nan(x) & (x %% 2 == 0)]
}
even_numbers2(c(0:4, NA, NaN, Inf, -Inf))
[1]  0  2  4 NA

5. Why is x[-which(x > 0)] not the same as x[x <= 0]?

These expressions differ in the way that they treat missing values. Let’s test how they work by creating a vector with positive and negative integers, and special values (NA, NaN, and Inf). These values should encompass all relevant types of values that these expressions would encounter.

x <- c(-1:1, Inf, -Inf, NaN, NA)
x[-which(x > 0)]
[1]   -1    0 -Inf  NaN   NA
x[x <= 0]
[1]   -1    0 -Inf   NA   NA

The expressions x[-which(x > 0)] and x[x <= 0] return the same values except for a NaN instead of a NA in the which() based expression.

So what is going on here? Let’s work through each part of these expressions and see where the different occurs. Let’s start with the expression x[x <= 0].

x <= 0
[1]  TRUE  TRUE FALSE FALSE  TRUE    NA    NA

Recall how the logical relational operators (<, <=, ==, !=, >, >=) treat NA values. Any relational operation that includes a NA returns an NA. Is NA <= 0? We don’t know because it depends on the unknown value of NA, so the answer is NA. This same argument applies to NaN. Asking whether NaN <= 0 does not make sense because you can’t compare a number to “Not a Number”.

Now recall how indexing treats NA values. Indexing can take a logical vector as in input, in which case it will include those elements where the logical vector is TRUE, and will not return those elements where the logical vector is FALSE. Logical vectors can also include NA values, and it is not clear how they should be treated. Well, since the value is NA, it could be TRUE or FALSE, we don’t know. Keeping elements with NA would treat the NA as TRUE, and dropping them would treat the NA as FALSE.

The way R decides to handle the NA values so that they are treated differently than TRUE or FALSE values is to include elements where the indexing vector is NA, but set their values to NA.

Now consider the expression x[-which(x > 0)]. As before, to understand this expression we’ll work from the inside out. Consider x > 0.

x > 0
[1] FALSE FALSE  TRUE  TRUE FALSE    NA    NA

As with x <= 0, it returns NA for comparisons involving NA and NaN.

What does which() do?

which(x > 0)
[1] 3 4

The which() function returns the indexes for which the argument is TRUE. This means that it is not including the indexes for which the argument is FALSE or NA.

Now consider the full expression x[-which(x > 0)]? The which() function returned a vector of integers. How does indexing treat negative integers?

x[1:2]
[1] -1  0
x[-(1:2)]
[1]    1  Inf -Inf  NaN   NA

If indexing gets a vector of positive integers, it will select those indexes; if it receives a vector of negative integers, it will drop those indexes. Thus, x[-which(x > 0)] ends up dropping the elements for which x > 0 is true, and keeps all the other elements and their original values, including NA and NaN.

There’s one other special case that we should consider. How do these two expressions work with an empty vector?

x <- numeric()
x[x <= 0]
numeric(0)
x[-which(x > 0)]
numeric(0)

Thankfully, they both handle empty vectors the same.

This exercise is a reminder to always test your code. Even though these two expressions looked equivalent, they are not in practice. And when you do test code, consider both how it works on typical values as well as special values and edge cases, like a vector with NA or NaN or Inf values, or an empty vector. These are where unexpected behavior is most likely to occur.

6. 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?

Let’s consider the named vector,

x <- c(a = 10, b = 20)

If we subset it by an integer larger than its length, it returns a vector of missing values.

x[3]
<NA> 
  NA 

This also applies to ranges.

x[3:5]
<NA> <NA> <NA> 
  NA   NA   NA 

If some indexes are larger than the length of the vector, those elements are NA.

x[1:5]
   a    b <NA> <NA> <NA> 
  10   20   NA   NA   NA 

Likewise, when [ is provided names not in the vector’s names, it will return NA for those elements.

x["c"]
<NA> 
  NA 
x[c("c", "d", "e")]
<NA> <NA> <NA> 
  NA   NA   NA 
x[c("a", "b", "c")]
   a    b <NA> 
  10   20   NA 

Though not yet discussed much in this lecture, the [[ behaves differently. With an atomic vector, if [[ is given an index outside the range of the vector or an invalid name, it raises an error.

LS0tDQp0aXRsZTogIlVzaW5nIGF0b21pYyB2ZWN0b3JzIg0Kb3V0cHV0OiANCiAgaHRtbF9ub3RlYm9vazoNCiAgICB0b2M6IHRydWUNCiAgICB0b2NfZmxvYXQ6IHRydWUNCi0tLQ0KDQpgYGB7cn0NCnN1cHByZXNzUGFja2FnZVN0YXJ0dXBNZXNzYWdlcyhsaWJyYXJ5KCJ0aWR5dmVyc2UiKSkNCmBgYA0KDQojIyMgMS4gV2hhdCBkb2VzIGBtZWFuKGlzLm5hKHgpKWAgdGVsbCB5b3UgYWJvdXQgYSB2ZWN0b3IgYHhgPyBXaGF0IGFib3V0IGBzdW0oIWlzLmZpbml0ZSh4KSk/DQoNCknigJlsbCB1c2UgdGhlIG51bWVyaWMgdmVjdG9yIHggdG8gY29tcGFyZSB0aGUgYmVoYXZpb3JzIG9mIGBpcy5uYSgpYCBhbmQgYGlzLmZpbml0ZSgpYC4gSXQgY29udGFpbnMgbnVtYmVycyAoYC0xYCwgYDBgLCBgMWApIGFzIHdlbGwgYXMgYWxsIHRoZSBzcGVjaWFsIG51bWVyaWMgdmFsdWVzOiBpbmZpbml0eSAoYEluZmApLCBtaXNzaW5nIChgTkFgKSwgYW5kIG5vdC1hLW51bWJlciAoYE5hTmApLg0KDQpgYGB7cn0NCnggPC0gYygtSW5mLCAtMSwgMCwgMSwgSW5mLCBOQSwgTmFOKQ0KYGBgDQoNClRoZSBleHByZXNzaW9uIGBtZWFuKGlzLm5hKHgpKWAgY2FsY3VsYXRlcyB0aGUgcHJvcG9ydGlvbiBvZiBtaXNzaW5nIHZhbHVlcyAodmFsdWVzIGVxdWFsIHRvIGBOQWApIGluIGEgdmVjdG9yLg0KDQpgYGB7cn0NCm1lYW4oaXMubmEoeCkpDQpgYGANCg0KVGhlIGV4cHJlc3Npb24gYHN1bSghaXMuZmluaXRlKHgpKWAgY2FsY3VsYXRlcyB0aGUgbnVtYmVyIG9mIGVsZW1lbnRzIGluIHRoZSB2ZWN0b3IgdGhhdCBhcmUgZXF1YWwgdG8gbWlzc2luZyAoYE5BYCksIG5vdC1hLW51bWJlciAoYE5hTmApLCBvciBpbmZpbml0eSAoYEluZmApLg0KDQpgYGB7cn0NCnN1bSghaXMuZmluaXRlKHgpKQ0KYGBgDQoNClJldmlldyB0aGUgTnVtZXJpYyBzZWN0aW9uIGZvciB0aGUgZGlmZmVyZW5jZXMgYmV0d2VlbiBgaXMubmEoKWAgYW5kIGBpcy5maW5pdGUoKWAuDQoNCiMjIyAyLiBDYXJlZnVsbHkgcmVhZCB0aGUgZG9jdW1lbnRhdGlvbiBvZiBgaXMudmVjdG9yKClgLiBXaGF0IGRvZXMgaXQgYWN0dWFsbHkgdGVzdCBmb3I/IFdoeSBkb2VzIGBpcy5hdG9taWMoKWAgbm90IGFncmVlIHdpdGggdGhlIGRlZmluaXRpb24gb2YgYXRvbWljIHZlY3RvcnMgYWJvdmU/DQoNClRoZSBmdW5jdGlvbiBgaXMudmVjdG9yKClgIG9ubHkgY2hlY2tzIHdoZXRoZXIgdGhlIG9iamVjdCBoYXMgbm8gYXR0cmlidXRlcyBvdGhlciB0aGFuIG5hbWVzLiBUaHVzIGEgbGlzdCBpcyBhIHZlY3RvcjoNCg0KYGBge3J9DQppcy52ZWN0b3IobGlzdChhID0gMSwgYiA9IDIpKQ0KYGBgDQoNCkJ1dCBhbnkgb2JqZWN0IHRoYXQgaGFzIGFuIGF0dHJpYnV0ZSAob3RoZXIgdGhhbiBuYW1lcykgaXMgbm90Og0KDQpgYGB7cn0NCnggPC0gMToxMA0KYXR0cih4LCAic29tZXRoaW5nIikgPC0gVFJVRQ0KaXMudmVjdG9yKHgpDQpgYGANCg0KVGhlIGlkZWEgYmVoaW5kIHRoaXMgaXMgdGhhdCBvYmplY3Qgb3JpZW50ZWQgY2xhc3NlcyB3aWxsIGluY2x1ZGUgYXR0cmlidXRlcywgaW5jbHVkaW5nLCBidXQgbm90IGxpbWl0ZWQgdG8gImNsYXNzIi4NCg0KVGhlIGZ1bmN0aW9uIGBpcy5hdG9taWMoKWAgZXhwbGljaXRseSBjaGVja3Mgd2hldGhlciBhbiBvYmplY3QgaXMgb25lIG9mIHRoZSBhdG9taWMgdHlwZXMgKOKAnGxvZ2ljYWzigJ0sIOKAnGludGVnZXLigJ0sIOKAnG51bWVyaWPigJ0sIOKAnGNvbXBsZXjigJ0sIOKAnGNoYXJhY3RlcuKAnSwgYW5kIOKAnHJhd+KAnSkgb3IgTlVMTC4NCg0KYGBge3J9DQppcy5hdG9taWMoMToxMCkNCmlzLmF0b21pYyhsaXN0KGEgPSAxKSkNCmBgYA0KDQpUaGUgZnVuY3Rpb24gYGlzLmF0b21pYygpYCB3aWxsIGNvbnNpZGVyIG9iamVjdHMgdG8gYmUgYXRvbWljIGV2ZW4gaWYgdGhleSBoYXZlIGV4dHJhIGF0dHJpYnV0ZXMuDQoNCmBgYHtyfQ0KaXMuYXRvbWljKHgpDQpgYGANCg0KIyMjIDMuIENvbXBhcmUgYW5kIGNvbnRyYXN0IGBzZXROYW1lcygpYCB3aXRoIGBwdXJycjo6c2V0X25hbWVzKClgLg0KDQpUaGUgZnVuY3Rpb24gYHNldE5hbWVzKClgIHRha2VzIHR3byBhcmd1bWVudHMsIGEgdmVjdG9yIHRvIGJlIG5hbWVkIGFuZCBhIHZlY3RvciBvZiBuYW1lcyB0byBhcHBseSB0byBpdHMgZWxlbWVudHMuDQoNCmBgYHtyfQ0Kc2V0TmFtZXMoMTo0LCBjKCJhIiwgImIiLCAiYyIsICJkIikpDQpgYGANCg0KWW91IGNhbiB1c2UgdGhlIHZhbHVlcyBvZiB0aGUgdmVjdG9yIGFzIGl0cyBuYW1lcyBpZiB0aGUgYG5tYCBhcmd1bWVudCBpcyB1c2VkLg0KDQpgYGB7cn0NCnNldE5hbWVzKG5tID0gYygiYSIsICJiIiwgImMiLCAiZCIpKQ0KYGBgDQoNClRoZSBmdW5jdGlvbiBgc2V0X25hbWVzKClgIGhhcyBtb3JlIHdheXMgdG8gc2V0IHRoZSBuYW1lcyB0aGFuIGBzZXROYW1lcygpYC4gVGhlIG5hbWVzIGNhbiBiZSBzcGVjaWZpZWQgaW4gdGhlIHNhbWUgbWFubmVyIGFzIGBzZXROYW1lcygpYC4NCg0KYGBge3J9DQpwdXJycjo6c2V0X25hbWVzKDE6NCwgYygiYSIsICJiIiwgImMiLCAiZCIpKQ0KYGBgDQoNClRoZSBuYW1lcyBjYW4gYWxzbyBiZSBzcGVjaWZpZWQgYXMgdW5uYW1lZCBhcmd1bWVudHMsDQoNCmBgYHtyfQ0KcHVycnI6OnNldF9uYW1lcygxOjQsICJhIiwgImIiLCAiYyIsICJkIikNCmBgYA0KDQpUaGUgZnVuY3Rpb24gYHNldF9uYW1lcygpYCB3aWxsIG5hbWUgYW4gb2JqZWN0IHdpdGggaXRzZWxmIGlmIG5vIG5tIGFyZ3VtZW50IGlzIHByb3ZpZGVkICh0aGUgb3Bwb3NpdGUgb2YgYHNldE5hbWVzKClgIGJlaGF2aW9yKS4NCg0KYGBge3J9DQpwdXJycjo6c2V0X25hbWVzKGMoImEiLCAiYiIsICJjIiwgImQiKSkNCmBgYA0KDQpUaGUgYmlnZ2VzdCBkaWZmZXJlbmNlIGJldHdlZW4gYHNldF9uYW1lcygpYCBhbmQgYHNldE5hbWVzKClgIGlzIHRoYXQgYHNldF9uYW1lcygpYCBhbGxvd3MgZm9yIHVzaW5nIGEgZnVuY3Rpb24gb3IgZm9ybXVsYSB0byB0cmFuc2Zvcm0gdGhlIGV4aXN0aW5nIG5hbWVzLg0KDQpgYGB7cn0NCnB1cnJyOjpzZXRfbmFtZXMoYyhhID0gMSwgYiA9IDIsIGMgPSAzKSwgdG91cHBlcikNCnB1cnJyOjpzZXRfbmFtZXMoYyhhID0gMSwgYiA9IDIsIGMgPSAzKSwgfiB0b3VwcGVyKC4pKQ0KYGBgDQoNClRoZSBgc2V0X25hbWVzKClgIGZ1bmN0aW9uIGFsc28gY2hlY2tzIHRoYXQgdGhlIGxlbmd0aCBvZiB0aGUgbmFtZXMgYXJndW1lbnQgaXMgdGhlIHNhbWUgbGVuZ3RoIGFzIHRoZSB2ZWN0b3IgdGhhdCBpcyBiZWluZyBuYW1lZCwgYW5kIHdpbGwgcmFpc2UgYW4gZXJyb3IgaWYgaXQgaXMgbm90Lg0KDQpgYGB7cn0NCiNwdXJycjo6c2V0X25hbWVzKDE6NCwgYygiYSIsICJiIikpDQojPkVycm9yOiBgbm1gIG11c3QgYmUgYE5VTExgIG9yIGEgY2hhcmFjdGVyIHZlY3RvciB0aGUgc2FtZSBsZW5ndGggYXMgYHhgDQpgYGANCg0KVGhlIGBzZXROYW1lcygpYCBmdW5jdGlvbiB3aWxsIGFsbG93IHRoZSBuYW1lcyB0byBiZSBzaG9ydGVyIHRoYW4gdGhlIHZlY3RvciBiZWluZyBuYW1lZCwgYW5kIHdpbGwgc2V0IHRoZSBtaXNzaW5nIG5hbWVzIHRvIE5BLg0KDQpgYGB7cn0NCnNldE5hbWVzKDE6NCwgYygiYSIsICJiIikpDQpgYGANCg0KIyMjIDQuQ3JlYXRlIGZ1bmN0aW9ucyB0aGF0IHRha2UgYSB2ZWN0b3IgYXMgaW5wdXQgYW5kIHJldHVybnM6DQoNCioqMS4gVGhlIGxhc3QgdmFsdWUuIFNob3VsZCB5b3UgdXNlIGBbYCBvciBgW1tgPyoqDQoqKjIuIFRoZSBlbGVtZW50cyBhdCBldmVuIG51bWJlcmVkIHBvc2l0aW9ucy4qKg0KKiozLiBFdmVyeSBlbGVtZW50IGV4Y2VwdCB0aGUgbGFzdCB2YWx1ZS4qKg0KKio0LiBPbmx5IGV2ZW4gbnVtYmVycyAoYW5kIG5vIG1pc3NpbmcgdmFsdWVzKS4qKg0KDQpUaGUgYW5zd2VycyB0byB0aGUgcGFydHMgZm9sbG93Lg0KDQoqKjEuKiogVGhpcyBmdW5jdGlvbiBmaW5kIHRoZSBsYXN0IHZhbHVlIGluIGEgdmVjdG9yLg0KDQpgYGB7cn0NCmxhc3RfdmFsdWUgPC0gZnVuY3Rpb24oeCkgew0KICAjIGNoZWNrIGZvciBjYXNlIHdpdGggbm8gbGVuZ3RoDQogIGlmIChsZW5ndGgoeCkpIHsNCiAgICB4W1tsZW5ndGgoeCldXQ0KICB9IGVsc2Ugew0KICAgIHgNCiAgfQ0KfQ0KbGFzdF92YWx1ZShudW1lcmljKCkpDQpsYXN0X3ZhbHVlKDEpDQpsYXN0X3ZhbHVlKDE6MTApDQpgYGANCg0KVGhlIGZ1bmN0aW9uIHVzZXMgYFtbYCBpbiBvcmRlciB0byBleHRyYWN0IGEgc2luZ2xlIGVsZW1lbnQuDQoNCioqMi4qKiBUaGlzIGZ1bmN0aW9uIHJldHVybnMgdGhlIGVsZW1lbnRzIGF0IGV2ZW4gbnVtYmVyIHBvc2l0aW9ucy4NCg0KYGBge3J9DQpldmVuX2luZGljZXMgPC0gZnVuY3Rpb24oeCkgew0KICBpZiAobGVuZ3RoKHgpKSB7DQogICAgeFtzZXFfYWxvbmcoeCkgJSUgMiA9PSAwXQ0KICB9IGVsc2Ugew0KICAgIHgNCiAgfQ0KfQ0KZXZlbl9pbmRpY2VzKG51bWVyaWMoKSkNCmV2ZW5faW5kaWNlcygxKQ0KZXZlbl9pbmRpY2VzKDE6MTApDQojIHRlc3QgdXNpbmcgY2FzZSB0byBlbnN1cmUgdGhhdCB2YWx1ZXMgbm90IGluZGljZXMNCiMgYXJlIGJlaW5nIHJldHVybmVkDQpldmVuX2luZGljZXMobGV0dGVycykNCmBgYA0KDQoqKjMuKiogVGhpcyBmdW5jdGlvbiByZXR1cm5zIGEgdmVjdG9yIHdpdGggZXZlcnkgZWxlbWVudCBleGNlcHQgdGhlIGxhc3QuDQpgYGB7cn0NCm5vdF9sYXN0IDwtIGZ1bmN0aW9uKHgpIHsNCiAgbiA8LSBsZW5ndGgoeCkNCiAgaWYgKG4pIHsNCiAgICB4Wy1uXQ0KICB9IGVsc2Ugew0KICAgICMgbiA9PSAwDQogICAgeA0KICB9DQp9DQpub3RfbGFzdCgxOjMpDQpgYGANCg0KV2Ugc2hvdWxkIGFsc28gY29uZmlybSB0aGF0IHRoZSBmdW5jdGlvbiB3b3JrcyB3aXRoIHNvbWUgZWRnZSBjYXNlcywgbGlrZSBhIHZlY3RvciB3aXRoIG9uZSBlbGVtZW50LCBhbmQgYSB2ZWN0b3Igd2l0aCB6ZXJvIGVsZW1lbnRzLg0KDQpgYGB7cn0NCm5vdF9sYXN0KDEpDQpub3RfbGFzdChudW1lcmljKCkpDQpgYGANCg0KSW4gYm90aCB0aGVzZSBjYXNlcywgbm90X2xhc3QoKSBjb3JyZWN0bHkgcmV0dXJucyBhbiBlbXB0eSB2ZWN0b3IuDQoNCioqNC4qKiBUaGlzIGZ1bmN0aW9uIHJldHVybnMgdGhlIGVsZW1lbnRzIG9mIGEgdmVjdG9yIHRoYXQgYXJlIGV2ZW4gbnVtYmVycy4NCg0KYGBge3J9DQpldmVuX251bWJlcnMgPC0gZnVuY3Rpb24oeCkgew0KICB4W3ggJSUgMiA9PSAwXQ0KfQ0KZXZlbl9udW1iZXJzKC00OjQpDQpgYGANCg0KV2UgY291bGQgaW1wcm92ZSB0aGlzIGZ1bmN0aW9uIGJ5IGhhbmRsaW5nIHRoZSBzcGVjaWFsIG51bWVyaWMgdmFsdWVzOiBgTkFgLCBgTmFOYCwgYEluZmAuIEhvd2V2ZXIsIGZpcnN0IHdlIG5lZWQgdG8gZGVjaWRlIGhvdyB0byBoYW5kbGUgdGhlbS4gTmVpdGhlciBgTmFOYCBub3IgYEluZmAgYXJlIG51bWJlcnMsIGFuZCBzbyB0aGV5IGFyZSBuZWl0aGVyIGV2ZW4gbm9yIG9kZC4gSW4gb3RoZXIgd29yZHMsIHNpbmNlIGBOYU5gIG5vciBgSW5mYCBhcmVu4oCZdCBldmVuIG51bWJlcnMsIHRoZXkgYXJlbuKAmXQgZXZlbiBudW1iZXJzLiBXaGF0IGFib3V0IGBOQWA/IFdlbGwsIHdlIGRvbuKAmXQga25vdy4gYE5BYCBpcyBhIG51bWJlciwgYnV0IHdlIGRvbuKAmXQga25vdyBpdHMgdmFsdWUuIFRoZSBtaXNzaW5nIG51bWJlciBjb3VsZCBiZSBldmVuIG9yIG9kZCwgYnV0IHdlIGRvbuKAmXQga25vdy4gQW5vdGhlciByZWFzb24gdG8gcmV0dXJuIGBOQWAgaXMgdGhhdCBpdCBpcyBjb25zaXN0ZW50IHdpdGggdGhlIGJlaGF2aW9yIG9mIG90aGVyIFIgZnVuY3Rpb25zLCB3aGljaCBnZW5lcmFsbHkgcmV0dXJuIGBOQWAgdmFsdWVzIGluc3RlYWQgb2YgZHJvcHBpbmcgdGhlbS4NCg0KYGBge3J9DQpldmVuX251bWJlcnMyIDwtIGZ1bmN0aW9uKHgpIHsNCiAgeFshaXMuaW5maW5pdGUoeCkgJiAhaXMubmFuKHgpICYgKHggJSUgMiA9PSAwKV0NCn0NCmV2ZW5fbnVtYmVyczIoYygwOjQsIE5BLCBOYU4sIEluZiwgLUluZikpDQpgYGANCg0KIyMjIDUuIFdoeSBpcyBgeFstd2hpY2goeCA+IDApXWAgbm90IHRoZSBzYW1lIGFzIGB4W3ggPD0gMF1gPw0KDQpUaGVzZSBleHByZXNzaW9ucyBkaWZmZXIgaW4gdGhlIHdheSB0aGF0IHRoZXkgdHJlYXQgbWlzc2luZyB2YWx1ZXMuIExldOKAmXMgdGVzdCBob3cgdGhleSB3b3JrIGJ5IGNyZWF0aW5nIGEgdmVjdG9yIHdpdGggcG9zaXRpdmUgYW5kIG5lZ2F0aXZlIGludGVnZXJzLCBhbmQgc3BlY2lhbCB2YWx1ZXMgKGBOQWAsIGBOYU5gLCBhbmQgYEluZmApLiBUaGVzZSB2YWx1ZXMgc2hvdWxkIGVuY29tcGFzcyBhbGwgcmVsZXZhbnQgdHlwZXMgb2YgdmFsdWVzIHRoYXQgdGhlc2UgZXhwcmVzc2lvbnMgd291bGQgZW5jb3VudGVyLg0KDQpgYGB7cn0NCnggPC0gYygtMToxLCBJbmYsIC1JbmYsIE5hTiwgTkEpDQp4Wy13aGljaCh4ID4gMCldDQp4W3ggPD0gMF0NCmBgYA0KDQpUaGUgZXhwcmVzc2lvbnMgYHhbLXdoaWNoKHggPiAwKV1gIGFuZCBgeFt4IDw9IDBdYCByZXR1cm4gdGhlIHNhbWUgdmFsdWVzIGV4Y2VwdCBmb3IgYSBgTmFOYCBpbnN0ZWFkIG9mIGEgYE5BYCBpbiB0aGUgYHdoaWNoKClgIGJhc2VkIGV4cHJlc3Npb24uDQoNClNvIHdoYXQgaXMgZ29pbmcgb24gaGVyZT8gTGV04oCZcyB3b3JrIHRocm91Z2ggZWFjaCBwYXJ0IG9mIHRoZXNlIGV4cHJlc3Npb25zIGFuZCBzZWUgd2hlcmUgdGhlIGRpZmZlcmVudCBvY2N1cnMuIExldOKAmXMgc3RhcnQgd2l0aCB0aGUgZXhwcmVzc2lvbiBgeFt4IDw9IDBdYC4NCg0KYGBge3J9DQp4IDw9IDANCmBgYA0KDQpSZWNhbGwgaG93IHRoZSBsb2dpY2FsIHJlbGF0aW9uYWwgb3BlcmF0b3JzIChgPGAsIGA8PWAsIGA9PWAsIGAhPWAsIGA+YCwgYD49YCkgdHJlYXQgYE5BYCB2YWx1ZXMuIEFueSByZWxhdGlvbmFsIG9wZXJhdGlvbiB0aGF0IGluY2x1ZGVzIGEgYE5BYCByZXR1cm5zIGFuIGBOQWAuIElzIGBOQSA8PSAwYD8gV2UgZG9u4oCZdCBrbm93IGJlY2F1c2UgaXQgZGVwZW5kcyBvbiB0aGUgdW5rbm93biB2YWx1ZSBvZiBgTkFgLCBzbyB0aGUgYW5zd2VyIGlzIGBOQWAuIFRoaXMgc2FtZSBhcmd1bWVudCBhcHBsaWVzIHRvIGBOYU5gLiBBc2tpbmcgd2hldGhlciBgTmFOIDw9IDBgIGRvZXMgbm90IG1ha2Ugc2Vuc2UgYmVjYXVzZSB5b3UgY2Fu4oCZdCBjb21wYXJlIGEgbnVtYmVyIHRvIOKAnE5vdCBhIE51bWJlcuKAnS4NCg0KTm93IHJlY2FsbCBob3cgaW5kZXhpbmcgdHJlYXRzIGBOQWAgdmFsdWVzLiBJbmRleGluZyBjYW4gdGFrZSBhIGxvZ2ljYWwgdmVjdG9yIGFzIGluIGlucHV0LCBpbiB3aGljaCBjYXNlIGl0IHdpbGwgaW5jbHVkZSB0aG9zZSBlbGVtZW50cyB3aGVyZSB0aGUgbG9naWNhbCB2ZWN0b3IgaXMgYFRSVUVgLCBhbmQgd2lsbCBub3QgcmV0dXJuIHRob3NlIGVsZW1lbnRzIHdoZXJlIHRoZSBsb2dpY2FsIHZlY3RvciBpcyBgRkFMU0VgLiBMb2dpY2FsIHZlY3RvcnMgY2FuIGFsc28gaW5jbHVkZSBgTkFgIHZhbHVlcywgYW5kIGl0IGlzIG5vdCBjbGVhciBob3cgdGhleSBzaG91bGQgYmUgdHJlYXRlZC4gV2VsbCwgc2luY2UgdGhlIHZhbHVlIGlzIGBOQWAsIGl0IGNvdWxkIGJlIGBUUlVFYCBvciBgRkFMU0VgLCB3ZSBkb27igJl0IGtub3cuIEtlZXBpbmcgZWxlbWVudHMgd2l0aCBgTkFgIHdvdWxkIHRyZWF0IHRoZSBgTkFgIGFzIGBUUlVFYCwgYW5kIGRyb3BwaW5nIHRoZW0gd291bGQgdHJlYXQgdGhlIGBOQWAgYXMgYEZBTFNFYC4NCg0KVGhlIHdheSBgUmAgZGVjaWRlcyB0byBoYW5kbGUgdGhlIGBOQWAgdmFsdWVzIHNvIHRoYXQgdGhleSBhcmUgdHJlYXRlZCBkaWZmZXJlbnRseSB0aGFuIGBUUlVFYCBvciBgRkFMU0VgIHZhbHVlcyBpcyB0byBpbmNsdWRlIGVsZW1lbnRzIHdoZXJlIHRoZSBpbmRleGluZyB2ZWN0b3IgaXMgYE5BYCwgYnV0IHNldCB0aGVpciB2YWx1ZXMgdG8gYE5BYC4NCg0KTm93IGNvbnNpZGVyIHRoZSBleHByZXNzaW9uIGB4Wy13aGljaCh4ID4gMCldYC4gQXMgYmVmb3JlLCB0byB1bmRlcnN0YW5kIHRoaXMgZXhwcmVzc2lvbiB3ZeKAmWxsIHdvcmsgZnJvbSB0aGUgaW5zaWRlIG91dC4gQ29uc2lkZXIgYHggPiAwYC4NCg0KYGBge3J9DQp4ID4gMA0KYGBgDQoNCkFzIHdpdGggYHggPD0gMGAsIGl0IHJldHVybnMgYE5BYCBmb3IgY29tcGFyaXNvbnMgaW52b2x2aW5nIGBOQWAgYW5kIGBOYU5gLg0KDQpXaGF0IGRvZXMgYHdoaWNoKClgIGRvPw0KDQpgYGB7cn0NCndoaWNoKHggPiAwKQ0KYGBgDQoNClRoZSBgd2hpY2goKWAgZnVuY3Rpb24gcmV0dXJucyB0aGUgaW5kZXhlcyBmb3Igd2hpY2ggdGhlIGFyZ3VtZW50IGlzIGBUUlVFYC4gVGhpcyBtZWFucyB0aGF0IGl0IGlzIG5vdCBpbmNsdWRpbmcgdGhlIGluZGV4ZXMgZm9yIHdoaWNoIHRoZSBhcmd1bWVudCBpcyBgRkFMU0VgIG9yIGBOQWAuDQoNCk5vdyBjb25zaWRlciB0aGUgZnVsbCBleHByZXNzaW9uIGB4Wy13aGljaCh4ID4gMCldYD8gVGhlIGB3aGljaCgpYCBmdW5jdGlvbiByZXR1cm5lZCBhIHZlY3RvciBvZiBpbnRlZ2Vycy4gSG93IGRvZXMgaW5kZXhpbmcgdHJlYXQgbmVnYXRpdmUgaW50ZWdlcnM/DQoNCmBgYHtyfQ0KeFsxOjJdDQp4Wy0oMToyKV0NCmBgYA0KDQpJZiBpbmRleGluZyBnZXRzIGEgdmVjdG9yIG9mIHBvc2l0aXZlIGludGVnZXJzLCBpdCB3aWxsIHNlbGVjdCB0aG9zZSBpbmRleGVzOyBpZiBpdCByZWNlaXZlcyBhIHZlY3RvciBvZiBuZWdhdGl2ZSBpbnRlZ2VycywgaXQgd2lsbCBkcm9wIHRob3NlIGluZGV4ZXMuIFRodXMsIGB4Wy13aGljaCh4ID4gMCldYCBlbmRzIHVwIGRyb3BwaW5nIHRoZSBlbGVtZW50cyBmb3Igd2hpY2ggYHggPiAwYCBpcyB0cnVlLCBhbmQga2VlcHMgYWxsIHRoZSBvdGhlciBlbGVtZW50cyBhbmQgdGhlaXIgb3JpZ2luYWwgdmFsdWVzLCBpbmNsdWRpbmcgYE5BYCBhbmQgYE5hTmAuDQoNClRoZXJl4oCZcyBvbmUgb3RoZXIgc3BlY2lhbCBjYXNlIHRoYXQgd2Ugc2hvdWxkIGNvbnNpZGVyLiBIb3cgZG8gdGhlc2UgdHdvIGV4cHJlc3Npb25zIHdvcmsgd2l0aCBhbiBlbXB0eSB2ZWN0b3I/DQoNCmBgYHtyfQ0KeCA8LSBudW1lcmljKCkNCnhbeCA8PSAwXQ0KeFstd2hpY2goeCA+IDApXQ0KYGBgDQoNClRoYW5rZnVsbHksIHRoZXkgYm90aCBoYW5kbGUgZW1wdHkgdmVjdG9ycyB0aGUgc2FtZS4NCg0KVGhpcyBleGVyY2lzZSBpcyBhIHJlbWluZGVyIHRvIGFsd2F5cyB0ZXN0IHlvdXIgY29kZS4gRXZlbiB0aG91Z2ggdGhlc2UgdHdvIGV4cHJlc3Npb25zIGxvb2tlZCBlcXVpdmFsZW50LCB0aGV5IGFyZSBub3QgaW4gcHJhY3RpY2UuIEFuZCB3aGVuIHlvdSBkbyB0ZXN0IGNvZGUsIGNvbnNpZGVyIGJvdGggaG93IGl0IHdvcmtzIG9uIHR5cGljYWwgdmFsdWVzIGFzIHdlbGwgYXMgc3BlY2lhbCB2YWx1ZXMgYW5kIGVkZ2UgY2FzZXMsIGxpa2UgYSB2ZWN0b3Igd2l0aCBgTkFgIG9yIGBOYU5gIG9yIGBJbmZgIHZhbHVlcywgb3IgYW4gZW1wdHkgdmVjdG9yLiBUaGVzZSBhcmUgd2hlcmUgdW5leHBlY3RlZCBiZWhhdmlvciBpcyBtb3N0IGxpa2VseSB0byBvY2N1ci4NCg0KIyMjIDYuIFdoYXQgaGFwcGVucyB3aGVuIHlvdSBzdWJzZXQgd2l0aCBhIHBvc2l0aXZlIGludGVnZXIgdGhhdOKAmXMgYmlnZ2VyIHRoYW4gdGhlIGxlbmd0aCBvZiB0aGUgdmVjdG9yPyBXaGF0IGhhcHBlbnMgd2hlbiB5b3Ugc3Vic2V0IHdpdGggYSBuYW1lIHRoYXQgZG9lc27igJl0IGV4aXN0Pw0KDQpMZXTigJlzIGNvbnNpZGVyIHRoZSBuYW1lZCB2ZWN0b3IsDQoNCmBgYHtyfQ0KeCA8LSBjKGEgPSAxMCwgYiA9IDIwKQ0KYGBgDQoNCklmIHdlIHN1YnNldCBpdCBieSBhbiBpbnRlZ2VyIGxhcmdlciB0aGFuIGl0cyBsZW5ndGgsIGl0IHJldHVybnMgYSB2ZWN0b3Igb2YgbWlzc2luZyB2YWx1ZXMuDQoNCmBgYHtyfQ0KeFszXQ0KYGBgDQoNClRoaXMgYWxzbyBhcHBsaWVzIHRvIHJhbmdlcy4NCg0KYGBge3J9DQp4WzM6NV0NCmBgYA0KDQpJZiBzb21lIGluZGV4ZXMgYXJlIGxhcmdlciB0aGFuIHRoZSBsZW5ndGggb2YgdGhlIHZlY3RvciwgdGhvc2UgZWxlbWVudHMgYXJlIGBOQWAuDQoNCmBgYHtyfQ0KeFsxOjVdDQpgYGANCg0KTGlrZXdpc2UsIHdoZW4gYFtgIGlzIHByb3ZpZGVkIG5hbWVzIG5vdCBpbiB0aGUgdmVjdG9y4oCZcyBuYW1lcywgaXQgd2lsbCByZXR1cm4gTkEgZm9yIHRob3NlIGVsZW1lbnRzLg0KDQpgYGB7cn0NCnhbImMiXQ0KeFtjKCJjIiwgImQiLCAiZSIpXQ0KeFtjKCJhIiwgImIiLCAiYyIpXQ0KYGBgDQoNClRob3VnaCBub3QgeWV0IGRpc2N1c3NlZCBtdWNoIGluIHRoaXMgbGVjdHVyZSwgdGhlIGBbW2AgYmVoYXZlcyBkaWZmZXJlbnRseS4gV2l0aCBhbiBhdG9taWMgdmVjdG9yLCBpZiBgW1tgIGlzIGdpdmVuIGFuIGluZGV4IG91dHNpZGUgdGhlIHJhbmdlIG9mIHRoZSB2ZWN0b3Igb3IgYW4gaW52YWxpZCBuYW1lLCBpdCByYWlzZXMgYW4gZXJyb3IuDQoNCmBgYHtyfQ0KeFtbImMiXV0NCnhbWzVdXQ0KYGBgDQo=