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