In this notebook we will try out using a jupyter notebook and try out some code related to chapters 12 through 16. The topics are

library(tidyverse)

Chapter 12 Tidy Data

The datasets have four variables: Country, Year, Population, and Cases.

Tidy data looks like this!

In this chapter 5 datasets are discussed. The first one is a tidy dataset.

table1
table2
table3
table4a
table4b
table5

Add a new column to table1.

# Compute rate per 10,000
table1 %>% 
  mutate(rate = cases / population * 10000)
# Compute cases per year
table1 %>% 
  count(year, wt = cases)
library(ggplot2)
ggplot(table1, aes(year, cases)) + 
  geom_line(aes(group = country), colour = "grey50") + 
  geom_point(aes(colour = country))

Gathering

table4a
table4a %>% 
  gather(`1999`, `2000`, key = "year", value = "cases")
table4b
table4b %>% 
  gather(`1999`, `2000`, key = "year", value = "population")

Left Join

tidy4a <- table4a %>% 
  gather(`1999`, `2000`, key = "year", value = "cases")
tidy4b <- table4b %>% 
  gather(`1999`, `2000`, key = "year", value = "population")
left_join(tidy4a, tidy4b)
Joining, by = c("country", "year")

Spreading

table2
spread(table2, key = type, value = count)

Separate

table3
table3 %>% 
  separate(rate, into = c("cases", "population"))
table3 %>% 
  separate(rate, into = c("cases", "population"), convert = TRUE)
table3 %>% 
  separate(year, into = c("century", "year"), sep = 2)

Unite

table5
table5 %>% 
  unite(new, century, year)
table5 %>% 
  unite(new, century, year, sep = "")

Missing Data

stocks <- tibble(
  year   = c(2015, 2015, 2015, 2015, 2016, 2016, 2016),
  qtr    = c(   1,    2,    3,    4,    2,    3,    4),
  return = c(1.88, 0.59, 0.35,   NA, 0.92, 0.17, 2.66)
)
stocks
stocks %>% 
  spread(year, return)
stocks %>% 
  spread(year, return) %>% 
  gather(year, return, `2015`:`2016`, na.rm = TRUE)
stocks %>% 
  complete(year, qtr)

Case Study

who
who1 <- who %>% 
  gather(new_sp_m014:newrel_f65, key = "key", value = "cases", na.rm = TRUE)
who1 %>% 
  count(key)
who2 <- who1 %>% 
  mutate(key = stringr::str_replace(key, "newrel", "new_rel"))
who2
who3 <- who2 %>% 
  separate(key, c("new", "type", "sexage"), sep = "_")
who3
who3 %>% 
  count(new)
who4 <- who3 %>% 
  select(-new, -iso2, -iso3)
who5 <- who4 %>% 
  separate(sexage, c("sex", "age"), sep = 1)
who5
who %>%
  gather(code, value, new_sp_m014:newrel_f65, na.rm = TRUE) %>% 
  mutate(code = stringr::str_replace(code, "newrel", "new_rel")) %>%
  separate(code, c("new", "var", "sexage")) %>% 
  select(-new, -iso2, -iso3) %>% 
  separate(sexage, c("sex", "age"), sep = 1)

Chapter 13 Relational data

library(tidyverse)
library(nycflights13)

Four datasets

airlines
airports
planes
weather

Keys

The variabled that are used to connect pairs of tables are called keys.

  • primary key
  • foreign key

Check that the key is unique. None greater than 1.

planes %>% 
  count(tailnum) %>% 
  filter(n > 0)
weather %>% 
  count(year, month, day, hour, origin) %>% 
  filter(n > 1)

Sometimes no primary key. Some greater than 1.

flights %>% 
  count(year, month, day, flight) %>% 
  filter(n > 1)
flights %>% 
  count(year, month, day, tailnum) %>% 
  filter(n > 1)

Mutating joins

flights2 <- flights %>% 
  select(year:day, hour, origin, dest, tailnum, carrier)
flights2
flights2 %>%
  select(-origin, -dest) %>% 
  left_join(airlines, by = "carrier")
flights2 %>%
  select(-origin, -dest) %>% 
  mutate(name = airlines$name[match(carrier, airlines$carrier)])

Understanding joins

Be sure to read this section in the book to understand joins!!! Great images to think about.

Defining the key column

flights2 %>% 
  left_join(weather)
Joining, by = c("year", "month", "day", "hour", "origin")
flights2 %>% 
  left_join(planes, by = "tailnum")
flights2 %>% 
  left_join(airports, c("dest" = "faa"))
flights2 %>% 
  left_join(airports, c("origin" = "faa"))

Other implementations

Try to run the code that uses the merge() function and try sqldf() to do the same.

Chapter 14 Strings

library(tidyverse)
library(stringr)
string1 <- "This is a string"
string2 <- 'If I want to include a "quote" inside a string, I use single quotes'
string1
[1] "This is a string"
string2
[1] "If I want to include a \"quote\" inside a string, I use single quotes"
x <- c("\"", "\\")
writeLines(x)
"
\
x <- "\u00b5"
x
[1] "µ"

String length

str_length(c("a", "R for data science", NA))
[1]  1 18 NA

Combind string

str_c("x", "y")
[1] "xy"
str_c("x", "y", "z")
[1] "xyz"
str_c("x", "y", sep = ", ")
[1] "x, y"
name <- "Hadley"
time_of_day <- "morning"
birthday <- FALSE
str_c(
  "Good ", time_of_day, " ", name,
  if (birthday) " and HAPPY BIRTHDAY",
  "."
)
[1] "Good morning Hadley."
str_c(c("x", "y", "z"), collapse = ", ")
[1] "x, y, z"

Subsetting strings

x <- c("Apple", "Banana", "Pear")
str_sub(x, 1, 3)
[1] "App" "Ban" "Pea"
str_sub(x, 1, 1) <- str_to_lower(str_sub(x, 1, 1))
x
[1] "apple"  "banana" "pear"  
x <- c("apple", "eggplant", "banana")
str_sort(x, locale = "en")  # English
[1] "apple"    "banana"   "eggplant"

Matching patterns with regular expressions

x <- c("apple", "banana", "pear")
str_view(x, "an")

str_view(x, ".a.")

Anchors

  • ^ to match the start of the string.
  • $ to match the end of the string.
x <- c("apple", "banana", "pear")
str_view(x, "^a")

str_view(x, "a$")

x <- c("apple pie", "apple", "apple cake")
str_view(x, "apple")

str_view(x, "^apple$")

str_view(c("grey", "gray"), "gr(e|a)y")
x <- "1888 is the longest year in Roman numerals: MDCCCLXXXVIII"
str_view(x, "CC?")

str_view(x, "CC+")

str_view(x, 'C[LX]+')

str_view(x, "C{2}")

str_view(x, "C{2,}")

str_view(x, "C{2,3}")

str_view(x, 'C{2,3}?')

str_view(x, 'C[LX]+?')
str_view(fruit, "(..)\\1", match = TRUE)
x <- c("apple", "banana", "pear")
str_detect(x, "e")
[1]  TRUE FALSE  TRUE
sum(str_detect(words, "^t"))
[1] 65
mean(str_detect(words, "[aeiou]$"))
[1] 0.2765306
no_vowels_1 <- !str_detect(words, "[aeiou]")
no_vowels_2 <- str_detect(words, "^[^aeiou]+$")
identical(no_vowels_1, no_vowels_2)
[1] TRUE
words[str_detect(words, "x$")]
[1] "box" "sex" "six" "tax"
str_subset(words, "x$")
[1] "box" "sex" "six" "tax"
df <- tibble(
  word = words, 
  i = seq_along(word)
)
df %>% 
  filter(str_detect(words, "x$"))
#> # A tibble: 4 × 2
#>    word     i
#>   <chr> <int>
#> 1   box   108
#> 2   sex   747
#> 3   six   772
#> 4   tax   841
df %>% 
  mutate(
    vowels = str_count(word, "[aeiou]"),
    consonants = str_count(word, "[^aeiou]")
  )

Exact matches

length(sentences)
[1] 720
head(sentences)
[1] "The birch canoe slid on the smooth planks." 
[2] "Glue the sheet to the dark blue background."
[3] "It's easy to tell the depth of a well."     
[4] "These days a chicken leg is a rare dish."   
[5] "Rice is often served in round bowls."       
[6] "The juice of lemons makes fine punch."      
colours <- c("red", "orange", "yellow", "green", "blue", "purple")
colour_match <- str_c(colours, collapse = "|")
colour_match
[1] "red|orange|yellow|green|blue|purple"
has_colour <- str_subset(sentences, colour_match)
matches <- str_extract(has_colour, colour_match)
head(matches)
[1] "blue" "blue" "red"  "red"  "red"  "blue"
has_colour <- str_subset(sentences, colour_match)
matches <- str_extract(has_colour, colour_match)
head(matches)
[1] "blue" "blue" "red"  "red"  "red"  "blue"
more <- sentences[str_count(sentences, colour_match) > 1]
str_view_all(more, colour_match)

str_extract(more, colour_match)
[1] "blue"   "green"  "orange"
str_extract_all(more, colour_match)
[[1]]
[1] "blue" "red" 

[[2]]
[1] "green" "red"  

[[3]]
[1] "orange" "red"   
str_extract_all(more, colour_match, simplify = TRUE)
     [,1]     [,2] 
[1,] "blue"   "red"
[2,] "green"  "red"
[3,] "orange" "red"

Chapter 15 Factors

library(tidyverse)
library(forcats)
x1 <- c("Dec", "Apr", "Jan", "Mar")
x2 <- c("Dec", "Apr", "Jam", "Mar")
sort(x1)
[1] "Apr" "Dec" "Jan" "Mar"
month_levels <- c(
  "Jan", "Feb", "Mar", "Apr", "May", "Jun", 
  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
)
y1 <- factor(x1, levels = month_levels)
y1
[1] Dec Apr Jan Mar
Levels: Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
sort(y1)
[1] Jan Mar Apr Dec
Levels: Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
y2 <- factor(x2, levels = month_levels)
y2
[1] Dec  Apr  <NA> Mar 
Levels: Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
y2 <- parse_factor(x2, levels = month_levels)
1 parsing failure.
row # A tibble: 1 x 4 col     row   col           expected actual expected   <int> <int>              <chr>  <chr> actual 1     3    NA value in level set    Jam
factor(x1)
[1] Dec Apr Jan Mar
Levels: Apr Dec Jan Mar
f1 <- factor(x1, levels = unique(x1))
f1
[1] Dec Apr Jan Mar
Levels: Dec Apr Jan Mar
f2 <- x1 %>% factor() %>% fct_inorder()
f2
[1] Dec Apr Jan Mar
Levels: Dec Apr Jan Mar
levels(f2)
[1] "Dec" "Apr" "Jan" "Mar"

Chapter 16 Dates and times

library(tidyverse)
library(lubridate)
library(nycflights13)
today()
[1] "2017-11-03"
now()
[1] "2017-11-03 09:44:08 PDT"
ymd("2017-01-31")
[1] "2017-01-31"
mdy("January 31st, 2017")
[1] "2017-01-31"
dmy("31-Jan-2017")
[1] "2017-01-31"
ymd(20170131)
[1] "2017-01-31"
ymd_hms("2017-01-31 20:11:59")
[1] "2017-01-31 20:11:59 UTC"
mdy_hm("01/31/2017 08:01")
[1] "2017-01-31 08:01:00 UTC"
ymd(20170131, tz = "UTC")
[1] "2017-01-31 UTC"
flights %>% 
  select(year, month, day, hour, minute)
flights %>% 
  select(year, month, day, hour, minute) %>% 
  mutate(departure = make_datetime(year, month, day, hour, minute))
make_datetime_100 <- function(year, month, day, time) {
  make_datetime(year, month, day, time %/% 100, time %% 100)
}
flights_dt <- flights %>% 
  filter(!is.na(dep_time), !is.na(arr_time)) %>% 
  mutate(
    dep_time = make_datetime_100(year, month, day, dep_time),
    arr_time = make_datetime_100(year, month, day, arr_time),
    sched_dep_time = make_datetime_100(year, month, day, sched_dep_time),
    sched_arr_time = make_datetime_100(year, month, day, sched_arr_time)
  ) %>% 
  select(origin, dest, ends_with("delay"), ends_with("time"))
flights_dt
flights_dt %>% 
  ggplot(aes(dep_time)) + 
  geom_freqpoly(binwidth = 86400) # 86400 seconds = 1 day

flights_dt %>% 
  filter(dep_time < ymd(20130102)) %>% 
  ggplot(aes(dep_time)) + 
  geom_freqpoly(binwidth = 600) # 600 s = 10 minutes

as_datetime(today())
[1] "2017-11-03 UTC"
as_date(now())
[1] "2017-11-03"
datetime <- ymd_hms("2016-07-08 12:34:56")
year(datetime)
[1] 2016
#> [1] 2016
month(datetime)
[1] 7
#> [1] 7
mday(datetime)
[1] 8
#> [1] 8
yday(datetime)
[1] 190
#> [1] 190
wday(datetime)
[1] 6
#> [1] 6
month(datetime, label = TRUE)
[1] Jul
Levels: Jan < Feb < Mar < Apr < May < Jun < Jul < Aug < Sep < Oct < Nov < Dec
#> [1] Jul
#> 12 Levels: Jan < Feb < Mar < Apr < May < Jun < Jul < Aug < Sep < ... < Dec
wday(datetime, label = TRUE, abbr = FALSE)
[1] Friday
Levels: Sunday < Monday < Tuesday < Wednesday < Thursday < Friday < Saturday
#> [1] Friday
#> 7 Levels: Sunday < Monday < Tuesday < Wednesday < Thursday < ... < Saturday
flights_dt %>% 
  mutate(wday = wday(dep_time, label = TRUE)) %>% 
  ggplot(aes(x = wday)) +
    geom_bar()

flights_dt %>% 
  mutate(minute = minute(dep_time)) %>% 
  group_by(minute) %>% 
  summarise(
    avg_delay = mean(arr_delay, na.rm = TRUE),
    n = n()) %>% 
  ggplot(aes(minute, avg_delay)) +
    geom_line()

sched_dep <- flights_dt %>% 
  mutate(minute = minute(sched_dep_time)) %>% 
  group_by(minute) %>% 
  summarise(
    avg_delay = mean(arr_delay, na.rm = TRUE),
    n = n())
ggplot(sched_dep, aes(minute, avg_delay)) +
  geom_line()

ggplot(sched_dep, aes(minute, n)) +
  geom_line()

Setting components

(datetime <- ymd_hms("2016-07-08 12:34:56"))
[1] "2016-07-08 12:34:56 UTC"
year(datetime) <- 2020
datetime
[1] "2020-07-08 12:34:56 UTC"
month(datetime) <- 01
datetime
[1] "2020-01-08 12:34:56 UTC"
hour(datetime) <- hour(datetime) + 1
datetime
[1] "2020-01-08 13:34:56 UTC"
update(datetime, year = 2020, month = 2, mday = 2, hour = 2)
[1] "2020-02-02 02:34:56 UTC"
ymd("2015-02-01") %>% 
  update(mday = 30)
[1] "2015-03-02"
ymd("2015-02-01") %>% 
  update(hour = 400)
[1] "2015-02-17 16:00:00 UTC"
flights_dt %>% 
  mutate(dep_hour = update(dep_time, yday = 1)) %>% 
  ggplot(aes(dep_hour)) +
    geom_freqpoly(binwidth = 300)

Time spans

h_age <- today() - ymd(19791014)
h_age
Time difference of 13900 days
as.duration(h_age)
[1] "1200960000s (~38.06 years)"
flights_dt
flights_dt %>% 
  filter(arr_time < dep_time) 

These are overnight flights. We used the same date information for both the departure and the arrival times, but these flights arrived on the following day. We can fix this by adding days(1) to the arrival time of each overnight flight.

flights_dt <- flights_dt %>% 
  mutate(
    overnight = arr_time < dep_time,
    arr_time = arr_time + days(overnight * 1),
    sched_arr_time = sched_arr_time + days(overnight * 1)
  )
flights_dt %>% 
  filter(overnight, arr_time < dep_time) 
LS0tCnRpdGxlOiAiVGlkeSBEYXRhIGFuZCB0aGUgbmV4dCA0IGNoYXB0ZXJzIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpJbiB0aGlzIG5vdGVib29rIHdlIHdpbGwgdHJ5IG91dCB1c2luZyBhIGp1cHl0ZXIgbm90ZWJvb2sgYW5kIHRyeSBvdXQgc29tZSBjb2RlIHJlbGF0ZWQgdG8gY2hhcHRlcnMgMTIgdGhyb3VnaCAxNi4gIFRoZSB0b3BpY3MgYXJlCgotIFRpZHkgRGF0YQotIFJlbGF0aW9uYWwgRGF0YQotIFN0cmluZ3MKLSBGYWN0b3JzCi0gRGF0ZXMgYW5kIFRpbWUKCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKYGBgCgohW10oaHR0cDovL3I0ZHMuaGFkLmNvLm56L2RpYWdyYW1zL2RhdGEtc2NpZW5jZS5wbmcpCgojIENoYXB0ZXIgMTIgVGlkeSBEYXRhCgpUaGUgZGF0YXNldHMgaGF2ZSBmb3VyIHZhcmlhYmxlczogQ291bnRyeSwgWWVhciwgUG9wdWxhdGlvbiwgYW5kIENhc2VzLgoKVGlkeSBkYXRhIGxvb2tzIGxpa2UgdGhpcyEKCiFbXShodHRwOi8vcjRkcy5oYWQuY28ubnovaW1hZ2VzL3RpZHktMS5wbmcpCgpJbiB0aGlzIGNoYXB0ZXIgNSBkYXRhc2V0cyBhcmUgZGlzY3Vzc2VkLiAgVGhlIGZpcnN0IG9uZSBpcyBhIHRpZHkgZGF0YXNldC4KCgpgYGB7cn0KdGFibGUxCnRhYmxlMgp0YWJsZTMKdGFibGU0YQp0YWJsZTRiCnRhYmxlNQpgYGAKCkFkZCBhIG5ldyBjb2x1bW4gdG8gdGFibGUxLgoKYGBge3J9CiMgQ29tcHV0ZSByYXRlIHBlciAxMCwwMDAKdGFibGUxICU+JSAKICBtdXRhdGUocmF0ZSA9IGNhc2VzIC8gcG9wdWxhdGlvbiAqIDEwMDAwKQpgYGAKCmBgYHtyfQojIENvbXB1dGUgY2FzZXMgcGVyIHllYXIKdGFibGUxICU+JSAKICBjb3VudCh5ZWFyLCB3dCA9IGNhc2VzKQpgYGAKCmBgYHtyfQpsaWJyYXJ5KGdncGxvdDIpCmdncGxvdCh0YWJsZTEsIGFlcyh5ZWFyLCBjYXNlcykpICsgCiAgZ2VvbV9saW5lKGFlcyhncm91cCA9IGNvdW50cnkpLCBjb2xvdXIgPSAiZ3JleTUwIikgKyAKICBnZW9tX3BvaW50KGFlcyhjb2xvdXIgPSBjb3VudHJ5KSkKYGBgCgojIyMgR2F0aGVyaW5nCgohW10oaHR0cDovL3I0ZHMuaGFkLmNvLm56L2ltYWdlcy90aWR5LTkucG5nKQoKYGBge3J9CnRhYmxlNGEKdGFibGU0YSAlPiUgCiAgZ2F0aGVyKGAxOTk5YCwgYDIwMDBgLCBrZXkgPSAieWVhciIsIHZhbHVlID0gImNhc2VzIikKYGBgCgpgYGB7cn0KdGFibGU0Ygp0YWJsZTRiICU+JSAKICBnYXRoZXIoYDE5OTlgLCBgMjAwMGAsIGtleSA9ICJ5ZWFyIiwgdmFsdWUgPSAicG9wdWxhdGlvbiIpCmBgYAoKIyMjIExlZnQgSm9pbgoKYGBge3J9CnRpZHk0YSA8LSB0YWJsZTRhICU+JSAKICBnYXRoZXIoYDE5OTlgLCBgMjAwMGAsIGtleSA9ICJ5ZWFyIiwgdmFsdWUgPSAiY2FzZXMiKQp0aWR5NGIgPC0gdGFibGU0YiAlPiUgCiAgZ2F0aGVyKGAxOTk5YCwgYDIwMDBgLCBrZXkgPSAieWVhciIsIHZhbHVlID0gInBvcHVsYXRpb24iKQpsZWZ0X2pvaW4odGlkeTRhLCB0aWR5NGIpCmBgYAoKIyMjIFNwcmVhZGluZwoKIVtdKGh0dHA6Ly9yNGRzLmhhZC5jby5uei9pbWFnZXMvdGlkeS04LnBuZykKCmBgYHtyfQp0YWJsZTIKc3ByZWFkKHRhYmxlMiwga2V5ID0gdHlwZSwgdmFsdWUgPSBjb3VudCkKYGBgCgojIyMgU2VwYXJhdGUKCiFbXShodHRwOi8vcjRkcy5oYWQuY28ubnovaW1hZ2VzL3RpZHktMTcucG5nKQoKCmBgYHtyfQp0YWJsZTMKdGFibGUzICU+JSAKICBzZXBhcmF0ZShyYXRlLCBpbnRvID0gYygiY2FzZXMiLCAicG9wdWxhdGlvbiIpKQp0YWJsZTMgJT4lIAogIHNlcGFyYXRlKHJhdGUsIGludG8gPSBjKCJjYXNlcyIsICJwb3B1bGF0aW9uIiksIGNvbnZlcnQgPSBUUlVFKQp0YWJsZTMgJT4lIAogIHNlcGFyYXRlKHllYXIsIGludG8gPSBjKCJjZW50dXJ5IiwgInllYXIiKSwgc2VwID0gMikKYGBgCgojIyMgVW5pdGUKCiFbXShodHRwOi8vcjRkcy5oYWQuY28ubnovaW1hZ2VzL3RpZHktMTgucG5nKQoKYGBge3J9CnRhYmxlNQp0YWJsZTUgJT4lIAogIHVuaXRlKG5ldywgY2VudHVyeSwgeWVhcikKdGFibGU1ICU+JSAKICB1bml0ZShuZXcsIGNlbnR1cnksIHllYXIsIHNlcCA9ICIiKQpgYGAKCiMjIyBNaXNzaW5nIERhdGEKCmBgYHtyfQpzdG9ja3MgPC0gdGliYmxlKAogIHllYXIgICA9IGMoMjAxNSwgMjAxNSwgMjAxNSwgMjAxNSwgMjAxNiwgMjAxNiwgMjAxNiksCiAgcXRyICAgID0gYyggICAxLCAgICAyLCAgICAzLCAgICA0LCAgICAyLCAgICAzLCAgICA0KSwKICByZXR1cm4gPSBjKDEuODgsIDAuNTksIDAuMzUsICAgTkEsIDAuOTIsIDAuMTcsIDIuNjYpCikKc3RvY2tzCnN0b2NrcyAlPiUgCiAgc3ByZWFkKHllYXIsIHJldHVybikKc3RvY2tzICU+JSAKICBzcHJlYWQoeWVhciwgcmV0dXJuKSAlPiUgCiAgZ2F0aGVyKHllYXIsIHJldHVybiwgYDIwMTVgOmAyMDE2YCwgbmEucm0gPSBUUlVFKQpzdG9ja3MgJT4lIAogIGNvbXBsZXRlKHllYXIsIHF0cikKYGBgCgojIyMgQ2FzZSBTdHVkeQoKYGBge3J9CndobwpgYGAKCmBgYHtyfQp3aG8xIDwtIHdobyAlPiUgCiAgZ2F0aGVyKG5ld19zcF9tMDE0Om5ld3JlbF9mNjUsIGtleSA9ICJrZXkiLCB2YWx1ZSA9ICJjYXNlcyIsIG5hLnJtID0gVFJVRSkKd2hvMSAlPiUgCiAgY291bnQoa2V5KQpgYGAKCmBgYHtyfQp3aG8yIDwtIHdobzEgJT4lIAogIG11dGF0ZShrZXkgPSBzdHJpbmdyOjpzdHJfcmVwbGFjZShrZXksICJuZXdyZWwiLCAibmV3X3JlbCIpKQp3aG8yCmBgYAoKCmBgYHtyfQp3aG8zIDwtIHdobzIgJT4lIAogIHNlcGFyYXRlKGtleSwgYygibmV3IiwgInR5cGUiLCAic2V4YWdlIiksIHNlcCA9ICJfIikKd2hvMwp3aG8zICU+JSAKICBjb3VudChuZXcpCndobzQgPC0gd2hvMyAlPiUgCiAgc2VsZWN0KC1uZXcsIC1pc28yLCAtaXNvMykKd2hvNSA8LSB3aG80ICU+JSAKICBzZXBhcmF0ZShzZXhhZ2UsIGMoInNleCIsICJhZ2UiKSwgc2VwID0gMSkKd2hvNQpgYGAKCmBgYHtyfQp3aG8gJT4lCiAgZ2F0aGVyKGNvZGUsIHZhbHVlLCBuZXdfc3BfbTAxNDpuZXdyZWxfZjY1LCBuYS5ybSA9IFRSVUUpICU+JSAKICBtdXRhdGUoY29kZSA9IHN0cmluZ3I6OnN0cl9yZXBsYWNlKGNvZGUsICJuZXdyZWwiLCAibmV3X3JlbCIpKSAlPiUKICBzZXBhcmF0ZShjb2RlLCBjKCJuZXciLCAidmFyIiwgInNleGFnZSIpKSAlPiUgCiAgc2VsZWN0KC1uZXcsIC1pc28yLCAtaXNvMykgJT4lIAogIHNlcGFyYXRlKHNleGFnZSwgYygic2V4IiwgImFnZSIpLCBzZXAgPSAxKQpgYGAKCiMgQ2hhcHRlciAxMyBSZWxhdGlvbmFsIGRhdGEKCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShueWNmbGlnaHRzMTMpCmBgYAoKRm91ciBkYXRhc2V0cwoKIVtdKGh0dHA6Ly9yNGRzLmhhZC5jby5uei9kaWFncmFtcy9yZWxhdGlvbmFsLW55Y2ZsaWdodHMucG5nKQoKYGBge3J9CmFpcmxpbmVzCmFpcnBvcnRzCnBsYW5lcwp3ZWF0aGVyCmBgYAoKIyMjIEtleXMKClRoZSB2YXJpYWJsZWQgdGhhdCBhcmUgdXNlZCB0byBjb25uZWN0IHBhaXJzIG9mIHRhYmxlcyBhcmUgY2FsbGVkICprZXlzKi4KCi0gcHJpbWFyeSBrZXkKLSBmb3JlaWduIGtleQoKQ2hlY2sgdGhhdCB0aGUga2V5IGlzIHVuaXF1ZS4gIE5vbmUgZ3JlYXRlciB0aGFuIDEuCgpgYGB7cn0KcGxhbmVzICU+JSAKICBjb3VudCh0YWlsbnVtKSAlPiUgCiAgZmlsdGVyKG4gPiAwKQp3ZWF0aGVyICU+JSAKICBjb3VudCh5ZWFyLCBtb250aCwgZGF5LCBob3VyLCBvcmlnaW4pICU+JSAKICBmaWx0ZXIobiA+IDEpCgpgYGAKClNvbWV0aW1lcyBubyBwcmltYXJ5IGtleS4gIFNvbWUgZ3JlYXRlciB0aGFuIDEuCgpgYGB7cn0KZmxpZ2h0cyAlPiUgCiAgY291bnQoeWVhciwgbW9udGgsIGRheSwgZmxpZ2h0KSAlPiUgCiAgZmlsdGVyKG4gPiAxKQpmbGlnaHRzICU+JSAKICBjb3VudCh5ZWFyLCBtb250aCwgZGF5LCB0YWlsbnVtKSAlPiUgCiAgZmlsdGVyKG4gPiAxKQpgYGAKCiMjIyBNdXRhdGluZyBqb2lucwoKYGBge3J9CmZsaWdodHMyIDwtIGZsaWdodHMgJT4lIAogIHNlbGVjdCh5ZWFyOmRheSwgaG91ciwgb3JpZ2luLCBkZXN0LCB0YWlsbnVtLCBjYXJyaWVyKQpmbGlnaHRzMgoKZmxpZ2h0czIgJT4lCiAgc2VsZWN0KC1vcmlnaW4sIC1kZXN0KSAlPiUgCiAgbGVmdF9qb2luKGFpcmxpbmVzLCBieSA9ICJjYXJyaWVyIikKCmZsaWdodHMyICU+JQogIHNlbGVjdCgtb3JpZ2luLCAtZGVzdCkgJT4lIAogIG11dGF0ZShuYW1lID0gYWlybGluZXMkbmFtZVttYXRjaChjYXJyaWVyLCBhaXJsaW5lcyRjYXJyaWVyKV0pCmBgYAoKIyMjIFVuZGVyc3RhbmRpbmcgam9pbnMKCkJlIHN1cmUgdG8gcmVhZCB0aGlzIHNlY3Rpb24gaW4gdGhlIGJvb2sgdG8gdW5kZXJzdGFuZCBqb2lucyEhISAgR3JlYXQgaW1hZ2VzIHRvIHRoaW5rIGFib3V0LgoKIyMjIERlZmluaW5nIHRoZSBrZXkgY29sdW1uCgpgYGB7cn0KZmxpZ2h0czIgJT4lIAogIGxlZnRfam9pbih3ZWF0aGVyKQoKZmxpZ2h0czIgJT4lIAogIGxlZnRfam9pbihwbGFuZXMsIGJ5ID0gInRhaWxudW0iKQoKZmxpZ2h0czIgJT4lIAogIGxlZnRfam9pbihhaXJwb3J0cywgYygiZGVzdCIgPSAiZmFhIikpCgpmbGlnaHRzMiAlPiUgCiAgbGVmdF9qb2luKGFpcnBvcnRzLCBjKCJvcmlnaW4iID0gImZhYSIpKQoKYGBgCgojIyMgT3RoZXIgaW1wbGVtZW50YXRpb25zCgpUcnkgdG8gcnVuIHRoZSBjb2RlIHRoYXQgdXNlcyB0aGUgbWVyZ2UoKSBmdW5jdGlvbiBhbmQgdHJ5IHNxbGRmKCkgdG8gZG8gdGhlIHNhbWUuCgojIENoYXB0ZXIgMTQgU3RyaW5ncwoKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHN0cmluZ3IpCmBgYAoKYGBge3J9CnN0cmluZzEgPC0gIlRoaXMgaXMgYSBzdHJpbmciCnN0cmluZzIgPC0gJ0lmIEkgd2FudCB0byBpbmNsdWRlIGEgInF1b3RlIiBpbnNpZGUgYSBzdHJpbmcsIEkgdXNlIHNpbmdsZSBxdW90ZXMnCgpzdHJpbmcxCnN0cmluZzIKYGBgCgoKYGBge3J9CnggPC0gYygiXCIiLCAiXFwiKQp3cml0ZUxpbmVzKHgpCmBgYAoKYGBge3J9CnggPC0gIlx1MDBiNSIKeApgYGAKCiMjIyBTdHJpbmcgbGVuZ3RoCgpgYGB7cn0Kc3RyX2xlbmd0aChjKCJhIiwgIlIgZm9yIGRhdGEgc2NpZW5jZSIsIE5BKSkKYGBgCgojIyMgQ29tYmluZCBzdHJpbmcgCgpgYGB7cn0Kc3RyX2MoIngiLCAieSIpCnN0cl9jKCJ4IiwgInkiLCAieiIpCnN0cl9jKCJ4IiwgInkiLCBzZXAgPSAiLCAiKQpgYGAKCmBgYHtyfQpuYW1lIDwtICJIYWRsZXkiCnRpbWVfb2ZfZGF5IDwtICJtb3JuaW5nIgpiaXJ0aGRheSA8LSBGQUxTRQoKc3RyX2MoCiAgIkdvb2QgIiwgdGltZV9vZl9kYXksICIgIiwgbmFtZSwKICBpZiAoYmlydGhkYXkpICIgYW5kIEhBUFBZIEJJUlRIREFZIiwKICAiLiIKKQpgYGAKCmBgYHtyfQpzdHJfYyhjKCJ4IiwgInkiLCAieiIpLCBjb2xsYXBzZSA9ICIsICIpCmBgYAoKIyMjIFN1YnNldHRpbmcgc3RyaW5ncwoKYGBge3J9CnggPC0gYygiQXBwbGUiLCAiQmFuYW5hIiwgIlBlYXIiKQpzdHJfc3ViKHgsIDEsIDMpCnN0cl9zdWIoeCwgMSwgMSkgPC0gc3RyX3RvX2xvd2VyKHN0cl9zdWIoeCwgMSwgMSkpCngKYGBgCgpgYGB7cn0KeCA8LSBjKCJhcHBsZSIsICJlZ2dwbGFudCIsICJiYW5hbmEiKQoKc3RyX3NvcnQoeCwgbG9jYWxlID0gImVuIikgICMgRW5nbGlzaApgYGAKCiMjIyBNYXRjaGluZyBwYXR0ZXJucyB3aXRoIHJlZ3VsYXIgZXhwcmVzc2lvbnMKCmBgYHtyfQp4IDwtIGMoImFwcGxlIiwgImJhbmFuYSIsICJwZWFyIikKc3RyX3ZpZXcoeCwgImFuIikKc3RyX3ZpZXcoeCwgIi5hLiIpCmBgYAoKIyMjIEFuY2hvcnMKCi0gXiB0byBtYXRjaCB0aGUgc3RhcnQgb2YgdGhlIHN0cmluZy4KLSAkIHRvIG1hdGNoIHRoZSBlbmQgb2YgdGhlIHN0cmluZy4KCmBgYHtyfQp4IDwtIGMoImFwcGxlIiwgImJhbmFuYSIsICJwZWFyIikKc3RyX3ZpZXcoeCwgIl5hIikKc3RyX3ZpZXcoeCwgImEkIikKCnggPC0gYygiYXBwbGUgcGllIiwgImFwcGxlIiwgImFwcGxlIGNha2UiKQpzdHJfdmlldyh4LCAiYXBwbGUiKQpzdHJfdmlldyh4LCAiXmFwcGxlJCIpCgpzdHJfdmlldyhjKCJncmV5IiwgImdyYXkiKSwgImdyKGV8YSl5IikKYGBgCgpgYGB7cn0KeCA8LSAiMTg4OCBpcyB0aGUgbG9uZ2VzdCB5ZWFyIGluIFJvbWFuIG51bWVyYWxzOiBNRENDQ0xYWFhWSUlJIgpzdHJfdmlldyh4LCAiQ0M/IikKc3RyX3ZpZXcoeCwgIkNDKyIpCnN0cl92aWV3KHgsICdDW0xYXSsnKQpzdHJfdmlldyh4LCAiQ3syfSIpCnN0cl92aWV3KHgsICJDezIsfSIpCnN0cl92aWV3KHgsICJDezIsM30iKQpzdHJfdmlldyh4LCAnQ3syLDN9PycpCnN0cl92aWV3KHgsICdDW0xYXSs/JykKYGBgCgpgYGB7cn0Kc3RyX3ZpZXcoZnJ1aXQsICIoLi4pXFwxIiwgbWF0Y2ggPSBUUlVFKQpgYGAKCmBgYHtyfQp4IDwtIGMoImFwcGxlIiwgImJhbmFuYSIsICJwZWFyIikKc3RyX2RldGVjdCh4LCAiZSIpCmBgYAoKYGBge3J9CnN1bShzdHJfZGV0ZWN0KHdvcmRzLCAiXnQiKSkKbWVhbihzdHJfZGV0ZWN0KHdvcmRzLCAiW2FlaW91XSQiKSkKbm9fdm93ZWxzXzEgPC0gIXN0cl9kZXRlY3Qod29yZHMsICJbYWVpb3VdIikKbm9fdm93ZWxzXzIgPC0gc3RyX2RldGVjdCh3b3JkcywgIl5bXmFlaW91XSskIikKaWRlbnRpY2FsKG5vX3Zvd2Vsc18xLCBub192b3dlbHNfMikKd29yZHNbc3RyX2RldGVjdCh3b3JkcywgIngkIildCnN0cl9zdWJzZXQod29yZHMsICJ4JCIpCgpgYGAKCmBgYHtyfQpkZiA8LSB0aWJibGUoCiAgd29yZCA9IHdvcmRzLCAKICBpID0gc2VxX2Fsb25nKHdvcmQpCikKZGYgJT4lIAogIGZpbHRlcihzdHJfZGV0ZWN0KHdvcmRzLCAieCQiKSkKIz4gIyBBIHRpYmJsZTogNCDDlyAyCiM+ICAgIHdvcmQgICAgIGkKIz4gICA8Y2hyPiA8aW50PgojPiAxICAgYm94ICAgMTA4CiM+IDIgICBzZXggICA3NDcKIz4gMyAgIHNpeCAgIDc3MgojPiA0ICAgdGF4ICAgODQxCmBgYAoKYGBge3J9CmRmICU+JSAKICBtdXRhdGUoCiAgICB2b3dlbHMgPSBzdHJfY291bnQod29yZCwgIlthZWlvdV0iKSwKICAgIGNvbnNvbmFudHMgPSBzdHJfY291bnQod29yZCwgIlteYWVpb3VdIikKICApCmBgYAoKIyMjIEV4YWN0IG1hdGNoZXMKCmBgYHtyfQpsZW5ndGgoc2VudGVuY2VzKQpoZWFkKHNlbnRlbmNlcykKCmNvbG91cnMgPC0gYygicmVkIiwgIm9yYW5nZSIsICJ5ZWxsb3ciLCAiZ3JlZW4iLCAiYmx1ZSIsICJwdXJwbGUiKQpjb2xvdXJfbWF0Y2ggPC0gc3RyX2MoY29sb3VycywgY29sbGFwc2UgPSAifCIpCmNvbG91cl9tYXRjaAoKaGFzX2NvbG91ciA8LSBzdHJfc3Vic2V0KHNlbnRlbmNlcywgY29sb3VyX21hdGNoKQptYXRjaGVzIDwtIHN0cl9leHRyYWN0KGhhc19jb2xvdXIsIGNvbG91cl9tYXRjaCkKaGVhZChtYXRjaGVzKQoKaGFzX2NvbG91ciA8LSBzdHJfc3Vic2V0KHNlbnRlbmNlcywgY29sb3VyX21hdGNoKQptYXRjaGVzIDwtIHN0cl9leHRyYWN0KGhhc19jb2xvdXIsIGNvbG91cl9tYXRjaCkKaGVhZChtYXRjaGVzKQptb3JlIDwtIHNlbnRlbmNlc1tzdHJfY291bnQoc2VudGVuY2VzLCBjb2xvdXJfbWF0Y2gpID4gMV0Kc3RyX3ZpZXdfYWxsKG1vcmUsIGNvbG91cl9tYXRjaCkKCnN0cl9leHRyYWN0KG1vcmUsIGNvbG91cl9tYXRjaCkKc3RyX2V4dHJhY3RfYWxsKG1vcmUsIGNvbG91cl9tYXRjaCkKCnN0cl9leHRyYWN0X2FsbChtb3JlLCBjb2xvdXJfbWF0Y2gsIHNpbXBsaWZ5ID0gVFJVRSkKCmBgYAoKCiMgQ2hhcHRlciAxNSBGYWN0b3JzCgpgYGB7cn0KbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoZm9yY2F0cykKYGBgCgpgYGB7cn0KeDEgPC0gYygiRGVjIiwgIkFwciIsICJKYW4iLCAiTWFyIikKeDIgPC0gYygiRGVjIiwgIkFwciIsICJKYW0iLCAiTWFyIikKc29ydCh4MSkKCm1vbnRoX2xldmVscyA8LSBjKAogICJKYW4iLCAiRmViIiwgIk1hciIsICJBcHIiLCAiTWF5IiwgIkp1biIsIAogICJKdWwiLCAiQXVnIiwgIlNlcCIsICJPY3QiLCAiTm92IiwgIkRlYyIKKQoKeTEgPC0gZmFjdG9yKHgxLCBsZXZlbHMgPSBtb250aF9sZXZlbHMpCnkxCnNvcnQoeTEpCgp5MiA8LSBmYWN0b3IoeDIsIGxldmVscyA9IG1vbnRoX2xldmVscykKeTIKeTIgPC0gcGFyc2VfZmFjdG9yKHgyLCBsZXZlbHMgPSBtb250aF9sZXZlbHMpCgpmYWN0b3IoeDEpCgpmMSA8LSBmYWN0b3IoeDEsIGxldmVscyA9IHVuaXF1ZSh4MSkpCmYxCgpmMiA8LSB4MSAlPiUgZmFjdG9yKCkgJT4lIGZjdF9pbm9yZGVyKCkKZjIKCmxldmVscyhmMikKYGBgCgojIENoYXB0ZXIgMTYgRGF0ZXMgYW5kIHRpbWVzCgpgYGB7cn0KbGlicmFyeSh0aWR5dmVyc2UpCgpsaWJyYXJ5KGx1YnJpZGF0ZSkKbGlicmFyeShueWNmbGlnaHRzMTMpCmBgYAoKCmBgYHtyfQp0b2RheSgpCm5vdygpCmBgYAoKCmBgYHtyfQp5bWQoIjIwMTctMDEtMzEiKQptZHkoIkphbnVhcnkgMzFzdCwgMjAxNyIpCmRteSgiMzEtSmFuLTIwMTciKQoKeW1kKDIwMTcwMTMxKQp5bWRfaG1zKCIyMDE3LTAxLTMxIDIwOjExOjU5IikKbWR5X2htKCIwMS8zMS8yMDE3IDA4OjAxIikKeW1kKDIwMTcwMTMxLCB0eiA9ICJVVEMiKQpgYGAKCmBgYHtyfQpmbGlnaHRzICU+JSAKICBzZWxlY3QoeWVhciwgbW9udGgsIGRheSwgaG91ciwgbWludXRlKQpgYGAKCmBgYHtyfQpmbGlnaHRzICU+JSAKICBzZWxlY3QoeWVhciwgbW9udGgsIGRheSwgaG91ciwgbWludXRlKSAlPiUgCiAgbXV0YXRlKGRlcGFydHVyZSA9IG1ha2VfZGF0ZXRpbWUoeWVhciwgbW9udGgsIGRheSwgaG91ciwgbWludXRlKSkKYGBgCgpgYGB7cn0KbWFrZV9kYXRldGltZV8xMDAgPC0gZnVuY3Rpb24oeWVhciwgbW9udGgsIGRheSwgdGltZSkgewogIG1ha2VfZGF0ZXRpbWUoeWVhciwgbW9udGgsIGRheSwgdGltZSAlLyUgMTAwLCB0aW1lICUlIDEwMCkKfQoKZmxpZ2h0c19kdCA8LSBmbGlnaHRzICU+JSAKICBmaWx0ZXIoIWlzLm5hKGRlcF90aW1lKSwgIWlzLm5hKGFycl90aW1lKSkgJT4lIAogIG11dGF0ZSgKICAgIGRlcF90aW1lID0gbWFrZV9kYXRldGltZV8xMDAoeWVhciwgbW9udGgsIGRheSwgZGVwX3RpbWUpLAogICAgYXJyX3RpbWUgPSBtYWtlX2RhdGV0aW1lXzEwMCh5ZWFyLCBtb250aCwgZGF5LCBhcnJfdGltZSksCiAgICBzY2hlZF9kZXBfdGltZSA9IG1ha2VfZGF0ZXRpbWVfMTAwKHllYXIsIG1vbnRoLCBkYXksIHNjaGVkX2RlcF90aW1lKSwKICAgIHNjaGVkX2Fycl90aW1lID0gbWFrZV9kYXRldGltZV8xMDAoeWVhciwgbW9udGgsIGRheSwgc2NoZWRfYXJyX3RpbWUpCiAgKSAlPiUgCiAgc2VsZWN0KG9yaWdpbiwgZGVzdCwgZW5kc193aXRoKCJkZWxheSIpLCBlbmRzX3dpdGgoInRpbWUiKSkKCmZsaWdodHNfZHQKYGBgCgpgYGB7cn0KZmxpZ2h0c19kdCAlPiUgCiAgZ2dwbG90KGFlcyhkZXBfdGltZSkpICsgCiAgZ2VvbV9mcmVxcG9seShiaW53aWR0aCA9IDg2NDAwKSAjIDg2NDAwIHNlY29uZHMgPSAxIGRheQpgYGAKCmBgYHtyfQpmbGlnaHRzX2R0ICU+JSAKICBmaWx0ZXIoZGVwX3RpbWUgPCB5bWQoMjAxMzAxMDIpKSAlPiUgCiAgZ2dwbG90KGFlcyhkZXBfdGltZSkpICsgCiAgZ2VvbV9mcmVxcG9seShiaW53aWR0aCA9IDYwMCkgIyA2MDAgcyA9IDEwIG1pbnV0ZXMKYGBgCgpgYGB7cn0KYXNfZGF0ZXRpbWUodG9kYXkoKSkKYXNfZGF0ZShub3coKSkKYGBgCgpgYGB7cn0KZGF0ZXRpbWUgPC0geW1kX2htcygiMjAxNi0wNy0wOCAxMjozNDo1NiIpCgp5ZWFyKGRhdGV0aW1lKQojPiBbMV0gMjAxNgptb250aChkYXRldGltZSkKIz4gWzFdIDcKbWRheShkYXRldGltZSkKIz4gWzFdIDgKCnlkYXkoZGF0ZXRpbWUpCiM+IFsxXSAxOTAKd2RheShkYXRldGltZSkKIz4gWzFdIDYKYGBgCgpgYGB7cn0KbW9udGgoZGF0ZXRpbWUsIGxhYmVsID0gVFJVRSkKIz4gWzFdIEp1bAojPiAxMiBMZXZlbHM6IEphbiA8IEZlYiA8IE1hciA8IEFwciA8IE1heSA8IEp1biA8IEp1bCA8IEF1ZyA8IFNlcCA8IC4uLiA8IERlYwp3ZGF5KGRhdGV0aW1lLCBsYWJlbCA9IFRSVUUsIGFiYnIgPSBGQUxTRSkKIz4gWzFdIEZyaWRheQojPiA3IExldmVsczogU3VuZGF5IDwgTW9uZGF5IDwgVHVlc2RheSA8IFdlZG5lc2RheSA8IFRodXJzZGF5IDwgLi4uIDwgU2F0dXJkYXkKYGBgCgpgYGB7cn0KZmxpZ2h0c19kdCAlPiUgCiAgbXV0YXRlKHdkYXkgPSB3ZGF5KGRlcF90aW1lLCBsYWJlbCA9IFRSVUUpKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gd2RheSkpICsKICAgIGdlb21fYmFyKCkKYGBgCgpgYGB7cn0KZmxpZ2h0c19kdCAlPiUgCiAgbXV0YXRlKG1pbnV0ZSA9IG1pbnV0ZShkZXBfdGltZSkpICU+JSAKICBncm91cF9ieShtaW51dGUpICU+JSAKICBzdW1tYXJpc2UoCiAgICBhdmdfZGVsYXkgPSBtZWFuKGFycl9kZWxheSwgbmEucm0gPSBUUlVFKSwKICAgIG4gPSBuKCkpICU+JSAKICBnZ3Bsb3QoYWVzKG1pbnV0ZSwgYXZnX2RlbGF5KSkgKwogICAgZ2VvbV9saW5lKCkKYGBgCgpgYGB7cn0Kc2NoZWRfZGVwIDwtIGZsaWdodHNfZHQgJT4lIAogIG11dGF0ZShtaW51dGUgPSBtaW51dGUoc2NoZWRfZGVwX3RpbWUpKSAlPiUgCiAgZ3JvdXBfYnkobWludXRlKSAlPiUgCiAgc3VtbWFyaXNlKAogICAgYXZnX2RlbGF5ID0gbWVhbihhcnJfZGVsYXksIG5hLnJtID0gVFJVRSksCiAgICBuID0gbigpKQoKZ2dwbG90KHNjaGVkX2RlcCwgYWVzKG1pbnV0ZSwgYXZnX2RlbGF5KSkgKwogIGdlb21fbGluZSgpCmBgYAoKYGBge3J9CmdncGxvdChzY2hlZF9kZXAsIGFlcyhtaW51dGUsIG4pKSArCiAgZ2VvbV9saW5lKCkKYGBgCgojIyMgU2V0dGluZyBjb21wb25lbnRzCgpgYGB7cn0KKGRhdGV0aW1lIDwtIHltZF9obXMoIjIwMTYtMDctMDggMTI6MzQ6NTYiKSkKeWVhcihkYXRldGltZSkgPC0gMjAyMApkYXRldGltZQptb250aChkYXRldGltZSkgPC0gMDEKZGF0ZXRpbWUKaG91cihkYXRldGltZSkgPC0gaG91cihkYXRldGltZSkgKyAxCmRhdGV0aW1lCnVwZGF0ZShkYXRldGltZSwgeWVhciA9IDIwMjAsIG1vbnRoID0gMiwgbWRheSA9IDIsIGhvdXIgPSAyKQoKeW1kKCIyMDE1LTAyLTAxIikgJT4lIAogIHVwZGF0ZShtZGF5ID0gMzApCgp5bWQoIjIwMTUtMDItMDEiKSAlPiUgCiAgdXBkYXRlKGhvdXIgPSA0MDApCgpgYGAKCmBgYHtyfQpmbGlnaHRzX2R0ICU+JSAKICBtdXRhdGUoZGVwX2hvdXIgPSB1cGRhdGUoZGVwX3RpbWUsIHlkYXkgPSAxKSkgJT4lIAogIGdncGxvdChhZXMoZGVwX2hvdXIpKSArCiAgICBnZW9tX2ZyZXFwb2x5KGJpbndpZHRoID0gMzAwKQpgYGAKCiMjIyBUaW1lIHNwYW5zCgpgYGB7cn0KaF9hZ2UgPC0gdG9kYXkoKSAtIHltZCgxOTc5MTAxNCkKaF9hZ2UKYGBgCgpgYGB7cn0KYXMuZHVyYXRpb24oaF9hZ2UpCmBgYAoKYGBge3J9CmZsaWdodHNfZHQKYGBgCgpgYGB7cn0KZmxpZ2h0c19kdCAlPiUgCiAgZmlsdGVyKGFycl90aW1lIDwgZGVwX3RpbWUpIApgYGAKClRoZXNlIGFyZSBvdmVybmlnaHQgZmxpZ2h0cy4gV2UgdXNlZCB0aGUgc2FtZSBkYXRlIGluZm9ybWF0aW9uIGZvciBib3RoIHRoZSBkZXBhcnR1cmUgYW5kIHRoZSBhcnJpdmFsIHRpbWVzLCBidXQgdGhlc2UgZmxpZ2h0cyBhcnJpdmVkIG9uIHRoZSBmb2xsb3dpbmcgZGF5LiBXZSBjYW4gZml4IHRoaXMgYnkgYWRkaW5nIGRheXMoMSkgdG8gdGhlIGFycml2YWwgdGltZSBvZiBlYWNoIG92ZXJuaWdodCBmbGlnaHQuCgpgYGB7cn0KZmxpZ2h0c19kdCA8LSBmbGlnaHRzX2R0ICU+JSAKICBtdXRhdGUoCiAgICBvdmVybmlnaHQgPSBhcnJfdGltZSA8IGRlcF90aW1lLAogICAgYXJyX3RpbWUgPSBhcnJfdGltZSArIGRheXMob3Zlcm5pZ2h0ICogMSksCiAgICBzY2hlZF9hcnJfdGltZSA9IHNjaGVkX2Fycl90aW1lICsgZGF5cyhvdmVybmlnaHQgKiAxKQogICkKYGBgCgoKYGBge3J9CmZsaWdodHNfZHQgJT4lIAogIGZpbHRlcihvdmVybmlnaHQsIGFycl90aW1lIDwgZGVwX3RpbWUpIApgYGAKCgoK