suppressPackageStartupMessages(library("tidyverse"))
package 㤼㸱tidyverse㤼㸲 was built under R version 3.6.3
suppressPackageStartupMessages(library("lubridate"))

1. What’s the difference between if and ifelse()? Carefully read the help and construct three examples that illustrate the key differences.

The keyword if tests a single condition, while ifelse() tests each element.

2. Write a greeting function that says “good morning”, “good afternoon”, or “good evening”, depending on the time of day. (Hint: use a time argument that defaults to lubridate::now(). That will make it easier to test your function.)

greet <- function(time = lubridate::now()) {
  hr <- lubridate::hour(time)
  # I don't know what to do about times after midnight,
  # are they evening or morning?
  if (hr < 12) {
    print("good morning")
  } else if (hr < 17) {
    print("good afternoon")
  } else {
    print("good evening")
  }
}
greet()
[1] "good afternoon"
greet(ymd_h("2017-01-08:05"))
[1] "good morning"
greet(ymd_h("2018-01-08:13"))
[1] "good afternoon"
greet(ymd_h("2019-01-08:20"))
[1] "good evening"

3. Implement a fizzbuzz() function. It takes a single number as input. If the number is divisible by three, it returns “fizz”. If it’s divisible by five it returns “buzz”. If it’s divisible by three and five, it returns “fizzbuzz”. Otherwise, it returns the number. Make sure you first write working code before you create the function.

We can use modulo operator, %%, to check divisibility. The expression x %% y returns 0 if y divides x.

1:10 %% 3 == 0
 [1] FALSE FALSE  TRUE FALSE FALSE  TRUE FALSE FALSE  TRUE FALSE

A more concise way of checking for divisibility is to note that the not operator will return TRUE for 0, and FALSE for all non-zero numbers. Thus, !(x %% y), will check whether y divides x.

!(1:10 %% 3)
 [1] FALSE FALSE  TRUE FALSE FALSE  TRUE FALSE FALSE  TRUE FALSE

There are four cases to consider:

  1. If x is divisible by 3 and 5, then return “fizzbuzz”.
  2. If x is divisible by 3 and not 5, then return “fizz”.
  3. If x is divisible by 5 and not 3, then return “buzz”.
  4. Otherwise, which is the case in which x is not divisible by either 3 or 5, return x.

The key to answering this question correctly, is to first check whether x is divisible by both 3 and 5. If the function checks whether x is divisible by 3 or 5 before considering the case that the number is divisible by both, then the function will never return “fizzbuzz”.

fizzbuzz <- function(x) {
  # these two lines check that x is a valid input
  stopifnot(length(x) == 1)
  stopifnot(is.numeric(x))
  if (!(x %% 3) && !(x %% 5)) {
    "fizzbuzz"
  } else if (!(x %% 3)) {
    "fizz"
  } else if (!(x %% 5)) {
    "buzz"
  } else {
    # ensure that the function returns a character vector
    as.character(x)
  }
}
fizzbuzz(6)
[1] "fizz"
fizzbuzz(10)
[1] "buzz"
fizzbuzz(15)
[1] "fizzbuzz"
fizzbuzz(2)
[1] "2"

This function can be slightly improved by combining the first two lines conditions so we only check whether x is divisible by 3 once.

fizzbuzz2 <- function(x) {
  # these two lines check that x is a valid input
  stopifnot(length(x) == 1)
  stopifnot(is.numeric(x))
  if (!(x %% 3)) {
    if (!(x %% 5)) {
      "fizzbuzz"
    } else {
      "fizz"
    }
  } else if (!(x %% 5)) {
    "buzz"
  } else {
    # ensure that the function returns a character vector
    as.character(x)
  }
}
fizzbuzz2(6)
[1] "fizz"
fizzbuzz2(10)
[1] "buzz"
fizzbuzz2(15)
[1] "fizzbuzz"
fizzbuzz2(2)
[1] "2"

Instead of only accepting one number as an input, we could a FizzBuzz function that works on a vector. The case_when() function vectorizes multiple if-else conditions, so is perfect for this task. In fact, fizz-buzz is used in the examples in the documentation of case_when().

fizzbuzz_vec <- function(x) {
  case_when(
    !(x %% 3) & !(x %% 5) ~ "fizzbuzz",
    !(x %% 3) ~ "fizz",
    !(x %% 5) ~ "buzz",
    TRUE ~ as.character(x)
  )
}
fizzbuzz_vec(c(0, 1, 2, 3, 5, 9, 10, 12, 15))
[1] "fizzbuzz" "1"        "2"        "fizz"     "buzz"     "fizz"     "buzz"     "fizz"    
[9] "fizzbuzz"

The following function is an example of a vectorized FizzBuzz function that only uses bracket assignment.

fizzbuzz_vec2 <- function(x) {
  y <- as.character(x)
  # put the individual cases first - any elements divisible by both 3 and 5
  # will be overwritten with fizzbuzz later
  y[!(x %% 3)] <- "fizz"
  y[!(x %% 3)] <- "buzz"
  y[!(x %% 3) & !(x %% 5)] <- "fizzbuzz"
  y
}
fizzbuzz_vec2(c(0, 1, 2, 3, 5, 9, 10, 12, 15))
[1] "fizzbuzz" "1"        "2"        "buzz"     "5"        "buzz"     "10"       "buzz"    
[9] "fizzbuzz"

This question, called the “Fizz Buzz” question, is a common programming interview question used for screening out programmers who can’t program.

4. How could you use cut() to simplify this set of nested if-else statements?

if (temp <= 0) {
  "freezing"
} else if (temp <= 10) {
  "cold"
} else if (temp <= 20) {
  "cool"
} else if (temp <= 30) {
  "warm"
} else {
  "hot"
}

How would you change the call to cut() if I’d used < instead of <=? What is the other chief advantage of cut() for this problem? (Hint: what happens if you have many values in temp?)

temp <- seq(-10, 50, by = 5)
cut(temp, c(-Inf, 0, 10, 20, 30, Inf),
  right = TRUE,
  labels = c("freezing", "cold", "cool", "warm", "hot")
)
 [1] freezing freezing freezing cold     cold     cool     cool     warm     warm     hot     
[11] hot      hot      hot     
Levels: freezing cold cool warm hot

To have intervals open on the left (using <), I change the argument to right = FALSE,

temp <- seq(-10, 50, by = 5)
cut(temp, c(-Inf, 0, 10, 20, 30, Inf),
  right = FALSE,
  labels = c("freezing", "cold", "cool", "warm", "hot")
)
 [1] freezing freezing cold     cold     cool     cool     warm     warm     hot      hot     
[11] hot      hot      hot     
Levels: freezing cold cool warm hot

Two advantages of using cut is that it works on vectors, whereas if only works on a single value, and that to change comparisons I only needed to change the argument to right, but I would have had to change four operators in the if expression.

5. What happens if you use switch() with numeric values?

In switch(n, ...), if n is numeric, it will return the nth argument from .... This means that if n = 1, switch() will return the first argument in ..., if n = 2, the second, and so on. For example,

switch(1, "apple", "banana", "cantaloupe")
[1] "apple"
switch(2, "apple", "banana", "cantaloupe")
[1] "banana"

If you use a non-integer number for the first argument of switch(), it will ignore the non-integer part.

switch(1.2, "apple", "banana", "cantaloupe")
[1] "apple"
switch(2.8, "apple", "banana", "cantaloupe")
[1] "banana"

Note that switch() truncates the numeric value, it does not round to the nearest integer. While it is possible to use non-integer numbers with switch(), you should avoid it

6. What does this switch() call do? What happens if x is "e"?

x <- "e"
switch(x,
  a = ,
  b = "ab",
  c = ,
  d = "cd"
)

Experiment, then carefully read the documentation.

First, let’s write a function switcheroo(), and see what it returns for different values of x.

switcheroo <- function(x) {
  switch(x,
    a = ,
    b = "ab",
    c = ,
    d = "cd"
  )
}
switcheroo("a")
[1] "ab"
switcheroo("b")
[1] "ab"
switcheroo("c")
[1] "cd"
switcheroo("d")
[1] "cd"
switcheroo("e")
switcheroo("f")

The switcheroo() function returns "ab" for x = "a" or x = "b", "cd" for x = "c" or x = "d", and NULL for x = "e" or any other value of x not in c("a", "b", "c", "d").

How does this work? The switch() function returns the first non-missing argument value for the first name it matches. Thus, when switch() encounters an argument with a missing value, like a = ,, it will return the value of the next argument with a non missing value, which in this case is b = "ab". If object in switch(object=) is not equal to the names of any of its arguments, switch() will return either the last (unnamed) argument if one is present or NULL. Since "e" is not one of the named arguments in switch() (a, b, c, d), and no other unnamed default value is present, this code will return NULL.

The code in the question is shorter way of writing the following.

switch(x,
  a = "ab",
  b = "ab",
  c = "cd",
  d = "cd",
  NULL # value to return if x not matched
)
NULL
LS0tDQp0aXRsZTogIkNvbmRpdGlvbmFsIGV4ZWN1dGlvbiINCm91dHB1dDogDQogIGh0bWxfbm90ZWJvb2s6DQogICAgdG9jOiB0cnVlDQogICAgdG9jX2Zsb2F0OiB0cnVlDQotLS0NCg0KYGBge3J9DQpzdXBwcmVzc1BhY2thZ2VTdGFydHVwTWVzc2FnZXMobGlicmFyeSgidGlkeXZlcnNlIikpDQpzdXBwcmVzc1BhY2thZ2VTdGFydHVwTWVzc2FnZXMobGlicmFyeSgibHVicmlkYXRlIikpDQpgYGANCg0KIyMjIDEuIFdoYXTigJlzIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gYGlmYCBhbmQgYGlmZWxzZSgpYD8gQ2FyZWZ1bGx5IHJlYWQgdGhlIGhlbHAgYW5kIGNvbnN0cnVjdCB0aHJlZSBleGFtcGxlcyB0aGF0IGlsbHVzdHJhdGUgdGhlIGtleSBkaWZmZXJlbmNlcy4NCg0KVGhlIGtleXdvcmQgYGlmYCB0ZXN0cyBhIHNpbmdsZSBjb25kaXRpb24sIHdoaWxlIGBpZmVsc2UoKWAgdGVzdHMgZWFjaCBlbGVtZW50Lg0KDQojIyMgMi4gV3JpdGUgYSBncmVldGluZyBmdW5jdGlvbiB0aGF0IHNheXMg4oCcZ29vZCBtb3JuaW5n4oCdLCDigJxnb29kIGFmdGVybm9vbuKAnSwgb3Ig4oCcZ29vZCBldmVuaW5n4oCdLCBkZXBlbmRpbmcgb24gdGhlIHRpbWUgb2YgZGF5LiAoSGludDogdXNlIGEgdGltZSBhcmd1bWVudCB0aGF0IGRlZmF1bHRzIHRvIGBsdWJyaWRhdGU6Om5vdygpYC4gVGhhdCB3aWxsIG1ha2UgaXQgZWFzaWVyIHRvIHRlc3QgeW91ciBmdW5jdGlvbi4pDQoNCmBgYHtyfQ0KZ3JlZXQgPC0gZnVuY3Rpb24odGltZSA9IGx1YnJpZGF0ZTo6bm93KCkpIHsNCiAgaHIgPC0gbHVicmlkYXRlOjpob3VyKHRpbWUpDQogICMgSSBkb24ndCBrbm93IHdoYXQgdG8gZG8gYWJvdXQgdGltZXMgYWZ0ZXIgbWlkbmlnaHQsDQogICMgYXJlIHRoZXkgZXZlbmluZyBvciBtb3JuaW5nPw0KICBpZiAoaHIgPCAxMikgew0KICAgIHByaW50KCJnb29kIG1vcm5pbmciKQ0KICB9IGVsc2UgaWYgKGhyIDwgMTcpIHsNCiAgICBwcmludCgiZ29vZCBhZnRlcm5vb24iKQ0KICB9IGVsc2Ugew0KICAgIHByaW50KCJnb29kIGV2ZW5pbmciKQ0KICB9DQp9DQpncmVldCgpDQpncmVldCh5bWRfaCgiMjAxNy0wMS0wODowNSIpKQ0KZ3JlZXQoeW1kX2goIjIwMTgtMDEtMDg6MTMiKSkNCmdyZWV0KHltZF9oKCIyMDE5LTAxLTA4OjIwIikpDQpgYGANCg0KIyMjIDMuIEltcGxlbWVudCBhIGBmaXp6YnV6eigpYCBmdW5jdGlvbi4gSXQgdGFrZXMgYSBzaW5nbGUgbnVtYmVyIGFzIGlucHV0LiBJZiB0aGUgbnVtYmVyIGlzIGRpdmlzaWJsZSBieSB0aHJlZSwgaXQgcmV0dXJucyDigJxmaXp64oCdLiBJZiBpdOKAmXMgZGl2aXNpYmxlIGJ5IGZpdmUgaXQgcmV0dXJucyDigJxidXp64oCdLiBJZiBpdOKAmXMgZGl2aXNpYmxlIGJ5IHRocmVlIGFuZCBmaXZlLCBpdCByZXR1cm5zIOKAnGZpenpidXp64oCdLiBPdGhlcndpc2UsIGl0IHJldHVybnMgdGhlIG51bWJlci4gTWFrZSBzdXJlIHlvdSBmaXJzdCB3cml0ZSB3b3JraW5nIGNvZGUgYmVmb3JlIHlvdSBjcmVhdGUgdGhlIGZ1bmN0aW9uLg0KDQpXZSBjYW4gdXNlIG1vZHVsbyBvcGVyYXRvciwgYCUlYCwgdG8gY2hlY2sgZGl2aXNpYmlsaXR5LiBUaGUgZXhwcmVzc2lvbiBgeCAlJSB5YCByZXR1cm5zIDAgaWYgYHlgIGRpdmlkZXMgYHhgLg0KDQpgYGB7cn0NCjE6MTAgJSUgMyA9PSAwDQpgYGANCg0KQSBtb3JlIGNvbmNpc2Ugd2F5IG9mIGNoZWNraW5nIGZvciBkaXZpc2liaWxpdHkgaXMgdG8gbm90ZSB0aGF0IHRoZSBub3Qgb3BlcmF0b3Igd2lsbCByZXR1cm4gYFRSVUVgIGZvciBgMGAsIGFuZCBgRkFMU0VgIGZvciBhbGwgbm9uLXplcm8gbnVtYmVycy4gVGh1cywgYCEoeCAlJSB5KWAsIHdpbGwgY2hlY2sgd2hldGhlciBgeWAgZGl2aWRlcyBgeGAuDQoNCmBgYHtyfQ0KISgxOjEwICUlIDMpDQpgYGANCg0KVGhlcmUgYXJlIGZvdXIgY2FzZXMgdG8gY29uc2lkZXI6DQoNCjEuIElmIGB4YCBpcyBkaXZpc2libGUgYnkgMyBhbmQgNSwgdGhlbiByZXR1cm4g4oCcZml6emJ1enrigJ0uDQoyLiBJZiBgeGAgaXMgZGl2aXNpYmxlIGJ5IDMgYW5kIG5vdCA1LCB0aGVuIHJldHVybiDigJxmaXp64oCdLg0KMy4gSWYgYHhgIGlzIGRpdmlzaWJsZSBieSA1IGFuZCBub3QgMywgdGhlbiByZXR1cm4g4oCcYnV6euKAnS4NCjQuIE90aGVyd2lzZSwgd2hpY2ggaXMgdGhlIGNhc2UgaW4gd2hpY2ggeCBpcyBub3QgZGl2aXNpYmxlIGJ5IGVpdGhlciAzIG9yIDUsIHJldHVybiB4Lg0KDQpUaGUga2V5IHRvIGFuc3dlcmluZyB0aGlzIHF1ZXN0aW9uIGNvcnJlY3RseSwgaXMgdG8gZmlyc3QgY2hlY2sgd2hldGhlciBgeGAgaXMgZGl2aXNpYmxlIGJ5IGJvdGggMyBhbmQgNS4gSWYgdGhlIGZ1bmN0aW9uIGNoZWNrcyB3aGV0aGVyIGB4YCBpcyBkaXZpc2libGUgYnkgMyBvciA1IGJlZm9yZSBjb25zaWRlcmluZyB0aGUgY2FzZSB0aGF0IHRoZSBudW1iZXIgaXMgZGl2aXNpYmxlIGJ5IGJvdGgsIHRoZW4gdGhlIGZ1bmN0aW9uIHdpbGwgbmV2ZXIgcmV0dXJuICJmaXp6YnV6eiIuDQoNCmBgYHtyfQ0KZml6emJ1enogPC0gZnVuY3Rpb24oeCkgew0KICAjIHRoZXNlIHR3byBsaW5lcyBjaGVjayB0aGF0IHggaXMgYSB2YWxpZCBpbnB1dA0KICBzdG9waWZub3QobGVuZ3RoKHgpID09IDEpDQogIHN0b3BpZm5vdChpcy5udW1lcmljKHgpKQ0KICBpZiAoISh4ICUlIDMpICYmICEoeCAlJSA1KSkgew0KICAgICJmaXp6YnV6eiINCiAgfSBlbHNlIGlmICghKHggJSUgMykpIHsNCiAgICAiZml6eiINCiAgfSBlbHNlIGlmICghKHggJSUgNSkpIHsNCiAgICAiYnV6eiINCiAgfSBlbHNlIHsNCiAgICAjIGVuc3VyZSB0aGF0IHRoZSBmdW5jdGlvbiByZXR1cm5zIGEgY2hhcmFjdGVyIHZlY3Rvcg0KICAgIGFzLmNoYXJhY3Rlcih4KQ0KICB9DQp9DQpmaXp6YnV6eig2KQ0KZml6emJ1enooMTApDQpmaXp6YnV6eigxNSkNCmZpenpidXp6KDIpDQpgYGANCg0KVGhpcyBmdW5jdGlvbiBjYW4gYmUgc2xpZ2h0bHkgaW1wcm92ZWQgYnkgY29tYmluaW5nIHRoZSBmaXJzdCB0d28gbGluZXMgY29uZGl0aW9ucyBzbyB3ZSBvbmx5IGNoZWNrIHdoZXRoZXIgYHhgIGlzIGRpdmlzaWJsZSBieSAzIG9uY2UuDQoNCmBgYHtyfQ0KZml6emJ1enoyIDwtIGZ1bmN0aW9uKHgpIHsNCiAgIyB0aGVzZSB0d28gbGluZXMgY2hlY2sgdGhhdCB4IGlzIGEgdmFsaWQgaW5wdXQNCiAgc3RvcGlmbm90KGxlbmd0aCh4KSA9PSAxKQ0KICBzdG9waWZub3QoaXMubnVtZXJpYyh4KSkNCiAgaWYgKCEoeCAlJSAzKSkgew0KICAgIGlmICghKHggJSUgNSkpIHsNCiAgICAgICJmaXp6YnV6eiINCiAgICB9IGVsc2Ugew0KICAgICAgImZpenoiDQogICAgfQ0KICB9IGVsc2UgaWYgKCEoeCAlJSA1KSkgew0KICAgICJidXp6Ig0KICB9IGVsc2Ugew0KICAgICMgZW5zdXJlIHRoYXQgdGhlIGZ1bmN0aW9uIHJldHVybnMgYSBjaGFyYWN0ZXIgdmVjdG9yDQogICAgYXMuY2hhcmFjdGVyKHgpDQogIH0NCn0NCmZpenpidXp6Mig2KQ0KZml6emJ1enoyKDEwKQ0KZml6emJ1enoyKDE1KQ0KZml6emJ1enoyKDIpDQpgYGANCg0KSW5zdGVhZCBvZiBvbmx5IGFjY2VwdGluZyBvbmUgbnVtYmVyIGFzIGFuIGlucHV0LCB3ZSBjb3VsZCBhIEZpenpCdXp6IGZ1bmN0aW9uIHRoYXQgd29ya3Mgb24gYSB2ZWN0b3IuIFRoZSBgY2FzZV93aGVuKClgIGZ1bmN0aW9uIHZlY3Rvcml6ZXMgbXVsdGlwbGUgaWYtZWxzZSBjb25kaXRpb25zLCBzbyBpcyBwZXJmZWN0IGZvciB0aGlzIHRhc2suIEluIGZhY3QsIGZpenotYnV6eiBpcyB1c2VkIGluIHRoZSBleGFtcGxlcyBpbiB0aGUgZG9jdW1lbnRhdGlvbiBvZiBgY2FzZV93aGVuKClgLg0KDQpgYGB7cn0NCmZpenpidXp6X3ZlYyA8LSBmdW5jdGlvbih4KSB7DQogIGNhc2Vfd2hlbigNCiAgICAhKHggJSUgMykgJiAhKHggJSUgNSkgfiAiZml6emJ1enoiLA0KICAgICEoeCAlJSAzKSB+ICJmaXp6IiwNCiAgICAhKHggJSUgNSkgfiAiYnV6eiIsDQogICAgVFJVRSB+IGFzLmNoYXJhY3Rlcih4KQ0KICApDQp9DQpmaXp6YnV6el92ZWMoYygwLCAxLCAyLCAzLCA1LCA5LCAxMCwgMTIsIDE1KSkNCmBgYA0KDQpUaGUgZm9sbG93aW5nIGZ1bmN0aW9uIGlzIGFuIGV4YW1wbGUgb2YgYSB2ZWN0b3JpemVkIEZpenpCdXp6IGZ1bmN0aW9uIHRoYXQgb25seSB1c2VzIGJyYWNrZXQgYXNzaWdubWVudC4NCg0KYGBge3J9DQpmaXp6YnV6el92ZWMyIDwtIGZ1bmN0aW9uKHgpIHsNCiAgeSA8LSBhcy5jaGFyYWN0ZXIoeCkNCiAgIyBwdXQgdGhlIGluZGl2aWR1YWwgY2FzZXMgZmlyc3QgLSBhbnkgZWxlbWVudHMgZGl2aXNpYmxlIGJ5IGJvdGggMyBhbmQgNQ0KICAjIHdpbGwgYmUgb3ZlcndyaXR0ZW4gd2l0aCBmaXp6YnV6eiBsYXRlcg0KICB5WyEoeCAlJSAzKV0gPC0gImZpenoiDQogIHlbISh4ICUlIDMpXSA8LSAiYnV6eiINCiAgeVshKHggJSUgMykgJiAhKHggJSUgNSldIDwtICJmaXp6YnV6eiINCiAgeQ0KfQ0KZml6emJ1enpfdmVjMihjKDAsIDEsIDIsIDMsIDUsIDksIDEwLCAxMiwgMTUpKQ0KYGBgDQoNClRoaXMgcXVlc3Rpb24sIGNhbGxlZCB0aGUgW+KAnEZpenogQnV6euKAnV0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvRml6el9idXp6KSBxdWVzdGlvbiwgaXMgYSBjb21tb24gcHJvZ3JhbW1pbmcgaW50ZXJ2aWV3IHF1ZXN0aW9uIHVzZWQgZm9yIHNjcmVlbmluZyBvdXQgcHJvZ3JhbW1lcnMgd2hvIGNhbuKAmXQgcHJvZ3JhbS4NCg0KIyMjIDQuIEhvdyBjb3VsZCB5b3UgdXNlIGBjdXQoKWAgdG8gc2ltcGxpZnkgdGhpcyBzZXQgb2YgbmVzdGVkIGlmLWVsc2Ugc3RhdGVtZW50cz8NCg0KYGBge30NCmlmICh0ZW1wIDw9IDApIHsNCiAgImZyZWV6aW5nIg0KfSBlbHNlIGlmICh0ZW1wIDw9IDEwKSB7DQogICJjb2xkIg0KfSBlbHNlIGlmICh0ZW1wIDw9IDIwKSB7DQogICJjb29sIg0KfSBlbHNlIGlmICh0ZW1wIDw9IDMwKSB7DQogICJ3YXJtIg0KfSBlbHNlIHsNCiAgImhvdCINCn0NCmBgYA0KDQpIb3cgd291bGQgeW91IGNoYW5nZSB0aGUgY2FsbCB0byBjdXQoKSBpZiBJ4oCZZCB1c2VkIDwgaW5zdGVhZCBvZiA8PT8gV2hhdCBpcyB0aGUgb3RoZXIgY2hpZWYgYWR2YW50YWdlIG9mIGN1dCgpIGZvciB0aGlzIHByb2JsZW0/IChIaW50OiB3aGF0IGhhcHBlbnMgaWYgeW91IGhhdmUgbWFueSB2YWx1ZXMgaW4gdGVtcD8pDQoNCmBgYHtyfQ0KdGVtcCA8LSBzZXEoLTEwLCA1MCwgYnkgPSA1KQ0KY3V0KHRlbXAsIGMoLUluZiwgMCwgMTAsIDIwLCAzMCwgSW5mKSwNCiAgcmlnaHQgPSBUUlVFLA0KICBsYWJlbHMgPSBjKCJmcmVlemluZyIsICJjb2xkIiwgImNvb2wiLCAid2FybSIsICJob3QiKQ0KKQ0KYGBgDQoNClRvIGhhdmUgaW50ZXJ2YWxzIG9wZW4gb24gdGhlIGxlZnQgKHVzaW5nIGA8YCksIEkgY2hhbmdlIHRoZSBhcmd1bWVudCB0byBgcmlnaHQgPSBGQUxTRWAsDQoNCmBgYHtyfQ0KdGVtcCA8LSBzZXEoLTEwLCA1MCwgYnkgPSA1KQ0KY3V0KHRlbXAsIGMoLUluZiwgMCwgMTAsIDIwLCAzMCwgSW5mKSwNCiAgcmlnaHQgPSBGQUxTRSwNCiAgbGFiZWxzID0gYygiZnJlZXppbmciLCAiY29sZCIsICJjb29sIiwgIndhcm0iLCAiaG90IikNCikNCmBgYA0KDQpUd28gYWR2YW50YWdlcyBvZiB1c2luZyBgY3V0YCBpcyB0aGF0IGl0IHdvcmtzIG9uIHZlY3RvcnMsIHdoZXJlYXMgYGlmYCBvbmx5IHdvcmtzIG9uIGEgc2luZ2xlIHZhbHVlLCBhbmQgdGhhdCB0byBjaGFuZ2UgY29tcGFyaXNvbnMgSSBvbmx5IG5lZWRlZCB0byBjaGFuZ2UgdGhlIGFyZ3VtZW50IHRvIGByaWdodGAsIGJ1dCBJIHdvdWxkIGhhdmUgaGFkIHRvIGNoYW5nZSBmb3VyIG9wZXJhdG9ycyBpbiB0aGUgaWYgZXhwcmVzc2lvbi4NCg0KIyMjIDUuIFdoYXQgaGFwcGVucyBpZiB5b3UgdXNlIGBzd2l0Y2goKWAgd2l0aCBudW1lcmljIHZhbHVlcz8NCg0KSW4gYHN3aXRjaChuLCAuLi4pYCwgaWYgYG5gIGlzIG51bWVyaWMsIGl0IHdpbGwgcmV0dXJuIHRoZSBgbmB0aCBhcmd1bWVudCBmcm9tIGAuLi5gLiBUaGlzIG1lYW5zIHRoYXQgaWYgYG4gPSAxYCwgYHN3aXRjaCgpYCB3aWxsIHJldHVybiB0aGUgZmlyc3QgYXJndW1lbnQgaW4gYC4uLmAsIGlmIGBuID0gMmAsIHRoZSBzZWNvbmQsIGFuZCBzbyBvbi4gRm9yIGV4YW1wbGUsDQoNCmBgYHtyfQ0Kc3dpdGNoKDEsICJhcHBsZSIsICJiYW5hbmEiLCAiY2FudGFsb3VwZSIpDQpzd2l0Y2goMiwgImFwcGxlIiwgImJhbmFuYSIsICJjYW50YWxvdXBlIikNCmBgYA0KDQpJZiB5b3UgdXNlIGEgbm9uLWludGVnZXIgbnVtYmVyIGZvciB0aGUgZmlyc3QgYXJndW1lbnQgb2YgYHN3aXRjaCgpYCwgaXQgd2lsbCBpZ25vcmUgdGhlIG5vbi1pbnRlZ2VyIHBhcnQuDQoNCmBgYHtyfQ0Kc3dpdGNoKDEuMiwgImFwcGxlIiwgImJhbmFuYSIsICJjYW50YWxvdXBlIikNCnN3aXRjaCgyLjgsICJhcHBsZSIsICJiYW5hbmEiLCAiY2FudGFsb3VwZSIpDQpgYGANCg0KTm90ZSB0aGF0IGBzd2l0Y2goKWAgdHJ1bmNhdGVzIHRoZSBudW1lcmljIHZhbHVlLCBpdCBkb2VzIG5vdCByb3VuZCB0byB0aGUgbmVhcmVzdCBpbnRlZ2VyLiBXaGlsZSBpdCBpcyBwb3NzaWJsZSB0byB1c2Ugbm9uLWludGVnZXIgbnVtYmVycyB3aXRoIGBzd2l0Y2goKWAsIHlvdSBzaG91bGQgYXZvaWQgaXQNCg0KIyMjIDYuIFdoYXQgZG9lcyB0aGlzIGBzd2l0Y2goKWAgY2FsbCBkbz8gV2hhdCBoYXBwZW5zIGlmIGB4YCBpcyBgImUiYD8NCg0KYGBge3J9DQp4IDwtICJlIg0Kc3dpdGNoKHgsDQogIGEgPSAsDQogIGIgPSAiYWIiLA0KICBjID0gLA0KICBkID0gImNkIg0KKQ0KYGBgDQoNCkV4cGVyaW1lbnQsIHRoZW4gY2FyZWZ1bGx5IHJlYWQgdGhlIGRvY3VtZW50YXRpb24uDQoNCkZpcnN0LCBsZXTigJlzIHdyaXRlIGEgZnVuY3Rpb24gYHN3aXRjaGVyb28oKWAsIGFuZCBzZWUgd2hhdCBpdCByZXR1cm5zIGZvciBkaWZmZXJlbnQgdmFsdWVzIG9mIGB4YC4NCg0KYGBge3J9DQpzd2l0Y2hlcm9vIDwtIGZ1bmN0aW9uKHgpIHsNCiAgc3dpdGNoKHgsDQogICAgYSA9ICwNCiAgICBiID0gImFiIiwNCiAgICBjID0gLA0KICAgIGQgPSAiY2QiDQogICkNCn0NCnN3aXRjaGVyb28oImEiKQ0Kc3dpdGNoZXJvbygiYiIpDQpzd2l0Y2hlcm9vKCJjIikNCnN3aXRjaGVyb28oImQiKQ0Kc3dpdGNoZXJvbygiZSIpDQpzd2l0Y2hlcm9vKCJmIikNCmBgYA0KDQpUaGUgYHN3aXRjaGVyb28oKWAgZnVuY3Rpb24gcmV0dXJucyBgImFiImAgZm9yIGB4ID0gImEiYCBvciBgeCA9ICJiImAsIGAiY2QiYCBmb3IgYHggPSAiYyJgIG9yIGB4ID0gImQiYCwgYW5kIGBOVUxMYCBmb3IgYHggPSAiZSJgIG9yIGFueSBvdGhlciB2YWx1ZSBvZiBgeGAgbm90IGluIGBjKCJhIiwgImIiLCAiYyIsICJkIilgLg0KDQpIb3cgZG9lcyB0aGlzIHdvcms/IFRoZSBgc3dpdGNoKClgIGZ1bmN0aW9uIHJldHVybnMgdGhlIGZpcnN0IG5vbi1taXNzaW5nIGFyZ3VtZW50IHZhbHVlIGZvciB0aGUgZmlyc3QgbmFtZSBpdCBtYXRjaGVzLiBUaHVzLCB3aGVuIGBzd2l0Y2goKWAgZW5jb3VudGVycyBhbiBhcmd1bWVudCB3aXRoIGEgbWlzc2luZyB2YWx1ZSwgbGlrZSBgYSA9ICxgLCBpdCB3aWxsIHJldHVybiB0aGUgdmFsdWUgb2YgdGhlIG5leHQgYXJndW1lbnQgd2l0aCBhIG5vbiBtaXNzaW5nIHZhbHVlLCB3aGljaCBpbiB0aGlzIGNhc2UgaXMgYGIgPSAiYWIiYC4gSWYgb2JqZWN0IGluIGBzd2l0Y2gob2JqZWN0PSlgIGlzIG5vdCBlcXVhbCB0byB0aGUgbmFtZXMgb2YgYW55IG9mIGl0cyBhcmd1bWVudHMsIGBzd2l0Y2goKWAgd2lsbCByZXR1cm4gZWl0aGVyIHRoZSBsYXN0ICh1bm5hbWVkKSBhcmd1bWVudCBpZiBvbmUgaXMgcHJlc2VudCBvciBgTlVMTGAuIFNpbmNlIGAiZSJgIGlzIG5vdCBvbmUgb2YgdGhlIG5hbWVkIGFyZ3VtZW50cyBpbiBgc3dpdGNoKClgIChgYWAsIGBiYCwgYGNgLCBgZGApLCBhbmQgbm8gb3RoZXIgdW5uYW1lZCBkZWZhdWx0IHZhbHVlIGlzIHByZXNlbnQsIHRoaXMgY29kZSB3aWxsIHJldHVybiBgTlVMTGAuDQoNClRoZSBjb2RlIGluIHRoZSBxdWVzdGlvbiBpcyBzaG9ydGVyIHdheSBvZiB3cml0aW5nIHRoZSBmb2xsb3dpbmcuDQoNCmBgYHtyfQ0Kc3dpdGNoKHgsDQogIGEgPSAiYWIiLA0KICBiID0gImFiIiwNCiAgYyA9ICJjZCIsDQogIGQgPSAiY2QiLA0KICBOVUxMICMgdmFsdWUgdG8gcmV0dXJuIGlmIHggbm90IG1hdGNoZWQNCikNCmBgYA==