Load libraries and data.
library(MASS)
library(stringr)
library(dplyr)
library(ggplot2)
library(xtable)
load("tidy_case_study.RData")
# force function namespace for key dplyr functions
select <- function(...) dplyr::select(...)
filter <- function(...) dplyr::filter(...)
arrange <- function(...) dplyr::arrange(...)
summarise <- function(...) dplyr::summarise(...)
summarize <- function(...) dplyr::summarise(...)
mutate <- function(...) dplyr::mutate(...)
group_by <- function(...) dplyr::group_by(...)
Part A. Display overall hourly deaths
We use ggplot() + geom_line()
;
deaths2 <- deaths %>%
filter(!is.na(hod))
deaths2 %>%
group_by(hod) %>%
summarise(nobs = n()) %>%
ggplot(aes(x = hod, y = nobs)) + geom_line()
Add axis labels and comma;
deaths2 %>%
group_by(hod) %>%
summarise(nobs = n()) %>%
ggplot(aes(x = hod, y = nobs)) + geom_line() +
labs(x = "Hour of day", y = "Number of deaths" ) +
scale_y_continuous(labels = scales::comma)
We use ggsave()
to save the figure.
ggsave("overall.png", width = 10, height = 6)
### Note: Strictly speaking, the 2008 data should be used.
# deaths08 <- deaths %>% filter(yod == 2008, mod != 0, dod != 0)
# table(deaths$yod)
# deaths08 %>%
# filter(!is.na(hod)) %>%
# group_by(hod) %>%
# summarise(nobs = n()) %>%
# ggplot(aes(x = hod, y = nobs)) + geom_line()
Part B. Count deaths per hour, per disease
Create panels (a) and (b) of Table 16; we group the data by cause of death (cod
) and hour of day (hod
), summarize the data for the frequency count, and then join a lookup-table for cod
descriptions.
# ---- Count deaths per hour, per disease ----
deaths_cod_hod <- deaths2 %>%
group_by(cod, hod) %>%
summarise( freq = n() ) %>%
left_join(codes, by = "cod")
Warning: Column `cod` joining character vector and factor, coercing into
character vector
head(deaths_cod_hod)
Create panel (c); we group the data by cod
and create a variable for the proportion of hourly deaths within each cod
.
cod_hod_prop <- deaths_cod_hod %>%
group_by(cod) %>%
mutate( prop = freq / sum(freq) )
# # alternatively
# deaths2 %>% group_by(cod) %>%
# mutate(inv_sum_cod = 1/n()) %>%
# group_by(hod, cod) %>%
# summarise(prop=sum(inv_sum_cod))
head(cod_hod_prop)
Create panel (d); we further summarise the data for the overall hourly death rates. In cod_hod_prop
, we have a frequency of each cod-hod
pair (freq
), and here we are adding it up across cod
to obtain the total frequency of deaths for each hour and then converting that into a relative frequency (through dividing it by the grand total of deaths).
# ---- Compare to overall abundance ----
overall_freq <- cod_hod_prop %>%
# Note: grouping by hod to get the overal trend for each hour
group_by(hod) %>%
summarise( freq_all = sum(freq) ) %>%
ungroup() %>%
mutate( prop_all = freq_all/sum(freq_all) )
# # alternatively
# deaths2 %>% group_by(hod) %>%
# summarise(freq_all=n()) %>%
# ungroup() %>%
# mutate(prop_all = freq/sum(freq_all))
master_hod <- left_join(cod_hod_prop, overall_freq, by = "hod")
head(master_hod)
# ---- Pick better subset of rows to show ----
table_C <- master_hod %>%
filter(cod %in% c("I21", "N18", "E84", "B16") & hod >= 8 & hod <= 12)
table_C %>%
# MASS package has its own select() function
# to specify a function from a particular package, use ::
dplyr::select(hod, cod, disease, freq, prop, freq_all, prop_all) %>%
arrange(hod) %>%
filter(hod %in% c(8, 9, 10, 11), !(hod==11 & cod=="N18"))
Part C. Find outliers
For each cause of death, we first create an overall frequency count and an average (squared) distance between prop
and prop_all
across hours. We then filter out for the cause of death with less than 50 deaths.
devi_cod <- master_hod %>%
group_by(cod) %>%
summarise(
n = sum(freq),
dist = mean((prop - prop_all)^2)
) %>%
filter(n > 50)
Plot devi_cod
in the normal scale;
# ---- Find outliers ----
devi_cod %>%
ggplot(aes(x = n, y = dist)) + geom_point()
ggsave("n-dist-raw.png", width = 6, height = 6)
We can see that the distributions of n
and dist
are both highly skewed, for which the logarithmic transformation is often useful.
devi_cod %>%
ggplot(aes(x = n)) +
geom_histogram(color='white')
devi_cod %>%
ggplot(aes(x = n)) +
scale_x_log10() +
geom_histogram(color='white')
devi_cod %>%
ggplot(aes(x = dist)) +
geom_histogram(color='white')
devi_cod %>%
ggplot(aes(x = dist)) +
scale_x_log10() +
geom_histogram(color='white')
There are a handful of extremely common causes of death, and many relatively rare causes of death.
Now plot devi_cod
in the logarithmic scale;
devi_cod %>%
ggplot(aes(x = n, y = dist)) +
scale_x_log10() +
scale_y_log10() +
geom_point()
Add comma to the scale labels and a fitted line by geom_smooth()
;
devi_cod %>%
ggplot(aes(x = n, y = dist)) +
scale_x_log10(labels = scales::comma) +
scale_y_log10(labels = scales::comma) +
geom_point() +
geom_smooth(method = "rlm", se = FALSE)
ggsave("n-dist-log.png", width = 6, height = 6)
In the logarithmic scale, we clearly see a pattern that the more common the cause, the smaller the deviation (dist) tends to be. In below we will fit a linear relationship to account for this tendency via regression and define the vertical differences between the observed points and the fitted line (i.e., regression residuals). Then, we will define “unusual” causes of death in terms of particularly large residuals.
Part D. Fit data by a regression and plot residuals
Formally, we use a regression to estimate the linear model above. We regress log(dist)
on log(n)
(i.e., the variables on the y-axis and the x-axis in the previous figure) and store the residuals.
# While there are no missing values (`NA`) in this case,
# we write a function to deal with a more general case.
my_rlm_resid <- function(y, x1) {
use <- (!is.na(y) & !is.na(x1))
rlt <- rep(NA, length(y))
rlt[use] <- rlm(y ~ x1) %>% residuals()
rlt # returns the residual of same length as y
}
devi_cod <- devi_cod %>%
mutate(resid = my_rlm_resid(log(dist),log(n)))
### Alternatively, we provide instructions inside a function do() with ".$varname" notations
# devi_cod$resid <- devi_cod %>%
# do({
# y <- log(.$dist)
# x1 <- log(.$n)
# use <- (!is.na(y) & !is.na(x1))
# rlt <- rep(NA, length(y))
# rlt[use] <- rlm(y ~ x1) %>% residuals()
# data.frame(rlt) # returns the residual of same length as y
# }) %>% unlist()
Plot the residuals against log(n) with a horizontal line at 1.5.
devi_cod %>%
ggplot(aes(x = n, y = resid)) +
geom_hline(yintercept = 1.5, colour = "grey50") +
scale_x_log10() +
geom_point()
ggsave("n-dist-resid.png", width = 6, height = 6)
Part E. Visualize unusual causes of death
We filter the data to keep the cause of death that has the residual value greater than 1.5. We join these data and master_hod
, while filtering out the data on the “usual” cause of death. Then, we split the data into those with relatively large and small numbers of deaths at the cutoff value of 350.
unusual <- devi_cod %>% filter(resid > 1.5)
head(unusual)
hod_unusual <- right_join(master_hod, unusual, by = "cod") # Note: we use right_join()
hod_unusual_big <- hod_unusual %>% filter(n > 350)
hod_unusual_sml <- hod_unusual %>% filter(n <= 350)
# Note the total number of cod at each stage
unusual$cod %>% unique() %>% length()
[1] 13
master_hod$cod %>% unique() %>% length()
[1] 1194
hod_unusual$cod %>% unique() %>% length()
[1] 13
hod_unusual_big$cod %>% unique() %>% length()
[1] 8
hod_unusual_sml$cod %>% unique() %>% length()
[1] 5
Plot hod_unusual_big
and hod_unusual_sml
using facet_wrap()
, which shows multiple plots in one figure. Add a curve for the overall hourly frequency by combining the data from overall_freq
.
# ---- Visualize unusual causes of death ----
hod_unusual_big %>%
ggplot(aes(x = hod, y = prop)) +
geom_line() +
geom_line(aes(y = prop_all), data = overall_freq, colour = "grey50") +
facet_wrap(~ disease, ncol = 3)
ggsave("unusual-big.png", width = 8, height = 6)
hod_unusual_sml %>%
ggplot(aes(x = hod, y = prop)) +
geom_line() +
geom_line(aes(y = prop_all), data = overall_freq, colour = "grey50") +
facet_wrap(~ disease, ncol = 3)
ggsave("unusual-sml.png", width = 8, height = 4)
Go back
LS0tCnRpdGxlOiAiS2V5OiBkcGx5ciBleGVyY2lzZSIKb3V0cHV0OiBodG1sX25vdGVib29rCiMgcmVuZGVyKCJ0aWR5X2Nhc2Vfc3R1ZHkvMDRfMDFfa2V5LlJtZCIpCi0tLQoKCgpMb2FkIGxpYnJhcmllcyBhbmQgZGF0YS4KCmBgYHtyLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQpsaWJyYXJ5KE1BU1MpCmxpYnJhcnkoc3RyaW5ncikKbGlicmFyeShkcGx5cikKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHh0YWJsZSkKbG9hZCgidGlkeV9jYXNlX3N0dWR5LlJEYXRhIikKCiMgZm9yY2UgZnVuY3Rpb24gbmFtZXNwYWNlIGZvciBrZXkgZHBseXIgZnVuY3Rpb25zICAKc2VsZWN0IDwtIGZ1bmN0aW9uKC4uLikgZHBseXI6OnNlbGVjdCguLi4pCmZpbHRlciA8LSBmdW5jdGlvbiguLi4pIGRwbHlyOjpmaWx0ZXIoLi4uKQphcnJhbmdlIDwtIGZ1bmN0aW9uKC4uLikgZHBseXI6OmFycmFuZ2UoLi4uKQpzdW1tYXJpc2UgPC0gZnVuY3Rpb24oLi4uKSBkcGx5cjo6c3VtbWFyaXNlKC4uLikKc3VtbWFyaXplIDwtIGZ1bmN0aW9uKC4uLikgZHBseXI6OnN1bW1hcmlzZSguLi4pCm11dGF0ZSA8LSBmdW5jdGlvbiguLi4pIGRwbHlyOjptdXRhdGUoLi4uKSAKZ3JvdXBfYnkgPC0gZnVuY3Rpb24oLi4uKSBkcGx5cjo6Z3JvdXBfYnkoLi4uKSAKYGBgCgoKCiMjIyBQYXJ0IEEuIERpc3BsYXkgb3ZlcmFsbCBob3VybHkgZGVhdGhzIHstfQoKV2UgdXNlIGBnZ3Bsb3QoKSArIGdlb21fbGluZSgpYDsgCmBgYHtyfQpkZWF0aHMyIDwtIGRlYXRocyAlPiUKICBmaWx0ZXIoIWlzLm5hKGhvZCkpCgpkZWF0aHMyICU+JQogIGdyb3VwX2J5KGhvZCkgJT4lCiAgc3VtbWFyaXNlKG5vYnMgPSBuKCkpICU+JQogIGdncGxvdChhZXMoeCA9IGhvZCwgeSA9IG5vYnMpKSArIGdlb21fbGluZSgpCmBgYAoKQWRkIGF4aXMgbGFiZWxzIGFuZCBjb21tYTsgIApgYGB7cn0KZGVhdGhzMiAlPiUKICBncm91cF9ieShob2QpICU+JQogIHN1bW1hcmlzZShub2JzID0gbigpKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBob2QsIHkgPSBub2JzKSkgKyBnZW9tX2xpbmUoKSArCiAgbGFicyh4ID0gIkhvdXIgb2YgZGF5IiwgeSA9ICJOdW1iZXIgb2YgZGVhdGhzIiApICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpjb21tYSkKYGBgCgpXZSB1c2UgYGdnc2F2ZSgpYCB0byBzYXZlIHRoZSBmaWd1cmUuIApgYGB7cn0KZ2dzYXZlKCJvdmVyYWxsLnBuZyIsIHdpZHRoID0gMTAsIGhlaWdodCA9IDYpCmBgYAoKCmBgYHtyfQojIyMgTm90ZTogU3RyaWN0bHkgc3BlYWtpbmcsIHRoZSAyMDA4IGRhdGEgc2hvdWxkIGJlIHVzZWQuIAojIGRlYXRoczA4IDwtIGRlYXRocyAlPiUgZmlsdGVyKHlvZCA9PSAyMDA4LCBtb2QgIT0gMCwgZG9kICE9IDApCiMgdGFibGUoZGVhdGhzJHlvZCkKCiMgZGVhdGhzMDggJT4lCiMgICBmaWx0ZXIoIWlzLm5hKGhvZCkpICU+JQojICAgZ3JvdXBfYnkoaG9kKSAlPiUKIyAgIHN1bW1hcmlzZShub2JzID0gbigpKSAlPiUKIyAgIGdncGxvdChhZXMoeCA9IGhvZCwgeSA9IG5vYnMpKSArIGdlb21fbGluZSgpCmBgYAoKCiMjIyBQYXJ0IEIuIENvdW50IGRlYXRocyBwZXIgaG91ciwgcGVyIGRpc2Vhc2Ugey19CgpDcmVhdGUgcGFuZWxzIChhKSBhbmQgKGIpIG9mIFRhYmxlIDE2OyAgd2UgZ3JvdXAgdGhlIGRhdGEgYnkgY2F1c2Ugb2YgZGVhdGggKGBjb2RgKSBhbmQgaG91ciBvZiBkYXkgKGBob2RgKSwgc3VtbWFyaXplIHRoZSBkYXRhIGZvciB0aGUgZnJlcXVlbmN5IGNvdW50LCBhbmQgdGhlbiBqb2luIGEgbG9va3VwLXRhYmxlIGZvciBgY29kYCBkZXNjcmlwdGlvbnMuICAgCmBgYHtyfQojIC0tLS0gQ291bnQgZGVhdGhzIHBlciBob3VyLCBwZXIgZGlzZWFzZSAtLS0tCmRlYXRoc19jb2RfaG9kIDwtIGRlYXRoczIgJT4lCiAgZ3JvdXBfYnkoY29kLCBob2QpICU+JQogIHN1bW1hcmlzZSggZnJlcSA9IG4oKSApICU+JQogIGxlZnRfam9pbihjb2RlcywgYnkgPSAiY29kIikKCmhlYWQoZGVhdGhzX2NvZF9ob2QpCmBgYAoKQ3JlYXRlIHBhbmVsIChjKTsgd2UgZ3JvdXAgdGhlIGRhdGEgYnkgYGNvZGAgYW5kIGNyZWF0ZSBhIHZhcmlhYmxlIGZvciB0aGUgcHJvcG9ydGlvbiBvZiBob3VybHkgZGVhdGhzIHdpdGhpbiBlYWNoIGBjb2RgLiAgICAgICAKYGBge3J9CmNvZF9ob2RfcHJvcCA8LSBkZWF0aHNfY29kX2hvZCAlPiUKICBncm91cF9ieShjb2QpICU+JQogIG11dGF0ZSggcHJvcCA9IGZyZXEgLyBzdW0oZnJlcSkgKQoKIyAjIGFsdGVybmF0aXZlbHkgCiMgZGVhdGhzMiAlPiUgZ3JvdXBfYnkoY29kKSAlPiUgCiMgICBtdXRhdGUoaW52X3N1bV9jb2QgPSAxL24oKSkgJT4lIAojICAgZ3JvdXBfYnkoaG9kLCBjb2QpICU+JSAKIyAgIHN1bW1hcmlzZShwcm9wPXN1bShpbnZfc3VtX2NvZCkpCgpoZWFkKGNvZF9ob2RfcHJvcCkKYGBgCgoKQ3JlYXRlIHBhbmVsIChkKTsgd2UgZnVydGhlciBzdW1tYXJpc2UgdGhlIGRhdGEgZm9yIHRoZSBvdmVyYWxsIGhvdXJseSBkZWF0aCByYXRlcy4gSW4gYGNvZF9ob2RfcHJvcGAsIHdlIGhhdmUgYSBmcmVxdWVuY3kgb2YgZWFjaCBgY29kLWhvZGAgcGFpciAgKGBmcmVxYCksIGFuZCBoZXJlIHdlIGFyZSBhZGRpbmcgaXQgdXAgYWNyb3NzIGBjb2RgIHRvIG9idGFpbiB0aGUgdG90YWwgZnJlcXVlbmN5IG9mIGRlYXRocyBmb3IgZWFjaCBob3VyIGFuZCB0aGVuIGNvbnZlcnRpbmcgdGhhdCBpbnRvIGEgcmVsYXRpdmUgZnJlcXVlbmN5ICh0aHJvdWdoIGRpdmlkaW5nIGl0IGJ5IHRoZSBncmFuZCB0b3RhbCBvZiBkZWF0aHMpLiAgICAKYGBge3J9CiMgLS0tLSAgQ29tcGFyZSB0byBvdmVyYWxsIGFidW5kYW5jZSAtLS0tCm92ZXJhbGxfZnJlcSA8LSBjb2RfaG9kX3Byb3AgJT4lCiAgIyBOb3RlOiBncm91cGluZyBieSBob2QgdG8gZ2V0IHRoZSBvdmVyYWwgdHJlbmQgZm9yIGVhY2ggaG91cgogIGdyb3VwX2J5KGhvZCkgJT4lCiAgc3VtbWFyaXNlKCBmcmVxX2FsbCA9IHN1bShmcmVxKSApICU+JQogIHVuZ3JvdXAoKSAlPiUKICBtdXRhdGUoIHByb3BfYWxsID0gZnJlcV9hbGwvc3VtKGZyZXFfYWxsKSApCgojICMgYWx0ZXJuYXRpdmVseSAKIyBkZWF0aHMyICU+JSBncm91cF9ieShob2QpICU+JQojICAgc3VtbWFyaXNlKGZyZXFfYWxsPW4oKSkgJT4lIAojICAgdW5ncm91cCgpICU+JSAKIyAgIG11dGF0ZShwcm9wX2FsbCA9IGZyZXEvc3VtKGZyZXFfYWxsKSkKCm1hc3Rlcl9ob2QgPC0gbGVmdF9qb2luKGNvZF9ob2RfcHJvcCwgb3ZlcmFsbF9mcmVxLCBieSA9ICJob2QiKQpoZWFkKG1hc3Rlcl9ob2QpCmBgYAoKCmBgYHtyfQojIC0tLS0gUGljayBiZXR0ZXIgc3Vic2V0IG9mIHJvd3MgdG8gc2hvdyAtLS0tCgp0YWJsZV9DIDwtIG1hc3Rlcl9ob2QgJT4lCiAgZmlsdGVyKGNvZCAlaW4lIGMoIkkyMSIsICJOMTgiLCAiRTg0IiwgIkIxNiIpICYgaG9kID49IDggJiBob2QgPD0gMTIpCgp0YWJsZV9DICU+JQogICMgTUFTUyBwYWNrYWdlIGhhcyBpdHMgb3duIHNlbGVjdCgpIGZ1bmN0aW9uCiAgIyB0byBzcGVjaWZ5IGEgZnVuY3Rpb24gZnJvbSBhIHBhcnRpY3VsYXIgcGFja2FnZSwgdXNlIDo6CiAgZHBseXI6OnNlbGVjdChob2QsIGNvZCwgZGlzZWFzZSwgZnJlcSwgcHJvcCwgZnJlcV9hbGwsIHByb3BfYWxsKSAlPiUKICBhcnJhbmdlKGhvZCkgJT4lCiAgZmlsdGVyKGhvZCAlaW4lIGMoOCwgOSwgMTAsIDExKSwgIShob2Q9PTExICYgY29kPT0iTjE4IikpCmBgYAoKCgoKCiMjIyBQYXJ0IEMuIEZpbmQgb3V0bGllcnMgey19CgpGb3IgZWFjaCBjYXVzZSBvZiBkZWF0aCwgd2UgZmlyc3QgY3JlYXRlIGFuIG92ZXJhbGwgZnJlcXVlbmN5IGNvdW50IGFuZCBhbiBhdmVyYWdlIChzcXVhcmVkKSBkaXN0YW5jZSBiZXR3ZWVuIGBwcm9wYCBhbmQgYHByb3BfYWxsYCBhY3Jvc3MgaG91cnMuIFdlIHRoZW4gZmlsdGVyIG91dCBmb3IgdGhlIGNhdXNlIG9mIGRlYXRoIHdpdGggbGVzcyB0aGFuIDUwIGRlYXRocy4gCmBgYHtyfQpkZXZpX2NvZCA8LSBtYXN0ZXJfaG9kICU+JQogIGdyb3VwX2J5KGNvZCkgJT4lCiAgc3VtbWFyaXNlKAogICAgbiA9IHN1bShmcmVxKSwKICAgIGRpc3QgPSBtZWFuKChwcm9wIC0gcHJvcF9hbGwpXjIpCiAgKSAlPiUKICBmaWx0ZXIobiA+IDUwKQpgYGAKClBsb3QgYGRldmlfY29kYCBpbiB0aGUgbm9ybWFsIHNjYWxlOwpgYGB7cn0KIyAtLS0tIEZpbmQgb3V0bGllcnMgLS0tLQpkZXZpX2NvZCAlPiUKICBnZ3Bsb3QoYWVzKHggPSBuLCB5ID0gZGlzdCkpICsgZ2VvbV9wb2ludCgpCmdnc2F2ZSgibi1kaXN0LXJhdy5wbmciLCB3aWR0aCA9IDYsIGhlaWdodCA9IDYpCmBgYAoKV2UgY2FuIHNlZSB0aGF0IHRoZSBkaXN0cmlidXRpb25zIG9mIGBuYCBhbmQgYGRpc3RgIGFyZSBib3RoIGhpZ2hseSBza2V3ZWQsIGZvciB3aGljaCB0aGUgbG9nYXJpdGhtaWMgdHJhbnNmb3JtYXRpb24gaXMgb2Z0ZW4gdXNlZnVsLiAgCmBgYHtyLCBtZXNzYWdlPUZBTFNFfQpkZXZpX2NvZCAlPiUKICBnZ3Bsb3QoYWVzKHggPSBuKSkgKwogIGdlb21faGlzdG9ncmFtKGNvbG9yPSd3aGl0ZScpIAoKZGV2aV9jb2QgJT4lCiAgZ2dwbG90KGFlcyh4ID0gbikpICsKICBzY2FsZV94X2xvZzEwKCkgKwogIGdlb21faGlzdG9ncmFtKGNvbG9yPSd3aGl0ZScpIAoKZGV2aV9jb2QgJT4lCiAgZ2dwbG90KGFlcyh4ID0gZGlzdCkpICsKICBnZW9tX2hpc3RvZ3JhbShjb2xvcj0nd2hpdGUnKSAgCgpkZXZpX2NvZCAlPiUKICBnZ3Bsb3QoYWVzKHggPSBkaXN0KSkgKwogIHNjYWxlX3hfbG9nMTAoKSArCiAgZ2VvbV9oaXN0b2dyYW0oY29sb3I9J3doaXRlJykgCmBgYApUaGVyZSBhcmUgYSBoYW5kZnVsIG9mIGV4dHJlbWVseSBjb21tb24gY2F1c2VzIG9mIGRlYXRoLCBhbmQgbWFueSByZWxhdGl2ZWx5IHJhcmUgY2F1c2VzIG9mIGRlYXRoLgoKCk5vdyBwbG90ICBgZGV2aV9jb2RgIGluIHRoZSBsb2dhcml0aG1pYyBzY2FsZTsgCmBgYHtyLCBtZXNzYWdlPUZBTFNFfQpkZXZpX2NvZCAlPiUKICBnZ3Bsb3QoYWVzKHggPSBuLCB5ID0gZGlzdCkpICsKICBzY2FsZV94X2xvZzEwKCkgKwogIHNjYWxlX3lfbG9nMTAoKSArCiAgZ2VvbV9wb2ludCgpIApgYGAKCkFkZCBjb21tYSB0byB0aGUgc2NhbGUgbGFiZWxzIGFuZCBhIGZpdHRlZCBsaW5lIGJ5IGBnZW9tX3Ntb290aCgpYDsgIApgYGB7cn0KZGV2aV9jb2QgJT4lCiAgZ2dwbG90KGFlcyh4ID0gbiwgeSA9IGRpc3QpKSArCiAgc2NhbGVfeF9sb2cxMChsYWJlbHMgPSBzY2FsZXM6OmNvbW1hKSArCiAgc2NhbGVfeV9sb2cxMChsYWJlbHMgPSBzY2FsZXM6OmNvbW1hKSArCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX3Ntb290aChtZXRob2QgPSAicmxtIiwgc2UgPSBGQUxTRSkKZ2dzYXZlKCJuLWRpc3QtbG9nLnBuZyIsIHdpZHRoID0gNiwgaGVpZ2h0ID0gNikKYGBgCgpJbiB0aGUgbG9nYXJpdGhtaWMgc2NhbGUsIHdlIGNsZWFybHkgc2VlIGEgcGF0dGVybiB0aGF0ICoqdGhlIG1vcmUgY29tbW9uIHRoZSBjYXVzZSwgdGhlIHNtYWxsZXIgdGhlIGRldmlhdGlvbiAoZGlzdCkgdGVuZHMgdG8gYmUuKiogIEluIGJlbG93IHdlIHdpbGwgZml0IGEgbGluZWFyIHJlbGF0aW9uc2hpcCB0byBhY2NvdW50IGZvciB0aGlzIHRlbmRlbmN5IHZpYSByZWdyZXNzaW9uIGFuZCBkZWZpbmUgdGhlIHZlcnRpY2FsIGRpZmZlcmVuY2VzIGJldHdlZW4gdGhlIG9ic2VydmVkIHBvaW50cyBhbmQgdGhlIGZpdHRlZCBsaW5lIChpLmUuLCByZWdyZXNzaW9uIHJlc2lkdWFscykuIFRoZW4sIHdlIHdpbGwgZGVmaW5lICJ1bnVzdWFsIiBjYXVzZXMgb2YgZGVhdGggaW4gdGVybXMgb2YgcGFydGljdWxhcmx5IGxhcmdlIHJlc2lkdWFscy4gCgoKCiMjIyBQYXJ0IEQuIEZpdCBkYXRhIGJ5IGEgcmVncmVzc2lvbiBhbmQgcGxvdCByZXNpZHVhbHMgCgpGb3JtYWxseSwgd2UgdXNlIGEgcmVncmVzc2lvbiB0byBlc3RpbWF0ZSB0aGUgbGluZWFyIG1vZGVsIGFib3ZlLiAgV2UgcmVncmVzcyBgbG9nKGRpc3QpYCBvbiBgbG9nKG4pYCAoaS5lLiwgdGhlIHZhcmlhYmxlcyBvbiB0aGUgeS1heGlzIGFuZCB0aGUgeC1heGlzIGluIHRoZSBwcmV2aW91cyBmaWd1cmUpIGFuZCBzdG9yZSB0aGUgcmVzaWR1YWxzLgpgYGB7cn0KIyAgV2hpbGUgdGhlcmUgYXJlIG5vIG1pc3NpbmcgdmFsdWVzIChgTkFgKSBpbiB0aGlzIGNhc2UsIAojICB3ZSB3cml0ZSBhIGZ1bmN0aW9uIHRvIGRlYWwgd2l0aCBhIG1vcmUgZ2VuZXJhbCBjYXNlLiAgCm15X3JsbV9yZXNpZCA8LSBmdW5jdGlvbih5LCB4MSkgewogIHVzZSA8LSAoIWlzLm5hKHkpICYgIWlzLm5hKHgxKSkKICBybHQgPC0gcmVwKE5BLCBsZW5ndGgoeSkpCiAgcmx0W3VzZV0gPC0gcmxtKHkgfiB4MSkgJT4lIHJlc2lkdWFscygpCiAgcmx0ICAgIyByZXR1cm5zIHRoZSByZXNpZHVhbCBvZiBzYW1lIGxlbmd0aCBhcyB5Cn0KCmRldmlfY29kIDwtIGRldmlfY29kICU+JQogIG11dGF0ZShyZXNpZCA9IG15X3JsbV9yZXNpZChsb2coZGlzdCksbG9nKG4pKSkKCiMjIyBBbHRlcm5hdGl2ZWx5LCB3ZSBwcm92aWRlIGluc3RydWN0aW9ucyBpbnNpZGUgYSBmdW5jdGlvbiBkbygpIHdpdGggIi4kdmFybmFtZSIgbm90YXRpb25zCiMgZGV2aV9jb2QkcmVzaWQgPC0gZGV2aV9jb2QgJT4lCiMgICBkbyh7CiMgICAgIHkgPC0gbG9nKC4kZGlzdCkKIyAgICAgeDEgPC0gbG9nKC4kbikKIyAgICAgdXNlIDwtICghaXMubmEoeSkgJiAhaXMubmEoeDEpKQojICAgICBybHQgPC0gcmVwKE5BLCBsZW5ndGgoeSkpCiMgICAgIHJsdFt1c2VdIDwtIHJsbSh5IH4geDEpICU+JSByZXNpZHVhbHMoKQojICAgICBkYXRhLmZyYW1lKHJsdCkgICAjIHJldHVybnMgdGhlIHJlc2lkdWFsIG9mIHNhbWUgbGVuZ3RoIGFzIHkKIyAgIH0pICU+JSB1bmxpc3QoKQpgYGAKClBsb3QgdGhlIHJlc2lkdWFscyBhZ2FpbnN0ICpsb2cobikqIHdpdGggYSBob3Jpem9udGFsIGxpbmUgYXQgMS41LgpgYGB7cn0KZGV2aV9jb2QgJT4lCiAgZ2dwbG90KGFlcyh4ID0gbiwgeSA9IHJlc2lkKSkgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDEuNSwgY29sb3VyID0gImdyZXk1MCIpICsKICBzY2FsZV94X2xvZzEwKCkgKwogIGdlb21fcG9pbnQoKQpnZ3NhdmUoIm4tZGlzdC1yZXNpZC5wbmciLCB3aWR0aCA9IDYsIGhlaWdodCA9IDYpCmBgYAoKCiMjIyBQYXJ0IEUuIFZpc3VhbGl6ZSB1bnVzdWFsIGNhdXNlcyBvZiBkZWF0aCB7LX0KCldlIGZpbHRlciB0aGUgZGF0YSB0byBrZWVwIHRoZSBjYXVzZSBvZiBkZWF0aCB0aGF0IGhhcyB0aGUgcmVzaWR1YWwgdmFsdWUgZ3JlYXRlciB0aGFuIDEuNS4gV2Ugam9pbiB0aGVzZSBkYXRhIGFuZCBgbWFzdGVyX2hvZGAsIHdoaWxlIGZpbHRlcmluZyBvdXQgdGhlIGRhdGEgb24gdGhlICJ1c3VhbCIgY2F1c2Ugb2YgZGVhdGguIFRoZW4sIHdlIHNwbGl0IHRoZSBkYXRhIGludG8gdGhvc2Ugd2l0aCByZWxhdGl2ZWx5IGxhcmdlIGFuZCBzbWFsbCBudW1iZXJzIG9mIGRlYXRocyBhdCB0aGUgY3V0b2ZmIHZhbHVlIG9mIDM1MC4gICAKYGBge3J9CnVudXN1YWwgPC0gZGV2aV9jb2QgJT4lIGZpbHRlcihyZXNpZCA+IDEuNSkKaGVhZCh1bnVzdWFsKQoKaG9kX3VudXN1YWwgPC0gcmlnaHRfam9pbihtYXN0ZXJfaG9kLCB1bnVzdWFsLCBieSA9ICJjb2QiKSAjIE5vdGU6IHdlIHVzZSByaWdodF9qb2luKCkgCmhvZF91bnVzdWFsX2JpZyA8LSBob2RfdW51c3VhbCAlPiUgZmlsdGVyKG4gPiAzNTApCmhvZF91bnVzdWFsX3NtbCA8LSBob2RfdW51c3VhbCAlPiUgZmlsdGVyKG4gPD0gMzUwKQpgYGAKCmBgYHtyfQojIE5vdGUgdGhlIHRvdGFsIG51bWJlciBvZiBjb2QgYXQgZWFjaCBzdGFnZQp1bnVzdWFsJGNvZCAlPiUgdW5pcXVlKCkgJT4lIGxlbmd0aCgpCm1hc3Rlcl9ob2QkY29kICU+JSB1bmlxdWUoKSAlPiUgbGVuZ3RoKCkKaG9kX3VudXN1YWwkY29kICU+JSB1bmlxdWUoKSAlPiUgbGVuZ3RoKCkKaG9kX3VudXN1YWxfYmlnJGNvZCAlPiUgdW5pcXVlKCkgJT4lIGxlbmd0aCgpCmhvZF91bnVzdWFsX3NtbCRjb2QgJT4lIHVuaXF1ZSgpICU+JSBsZW5ndGgoKQpgYGAKClBsb3QgYGhvZF91bnVzdWFsX2JpZ2AgYW5kIGBob2RfdW51c3VhbF9zbWxgIHVzaW5nIGBmYWNldF93cmFwKClgLCB3aGljaCBzaG93cyBtdWx0aXBsZSBwbG90cyBpbiBvbmUgZmlndXJlLiBBZGQgYSBjdXJ2ZSBmb3IgdGhlIG92ZXJhbGwgaG91cmx5IGZyZXF1ZW5jeSBieSBjb21iaW5pbmcgdGhlIGRhdGEgZnJvbSBgb3ZlcmFsbF9mcmVxYC4gIApgYGB7cn0KIyAtLS0tIFZpc3VhbGl6ZSB1bnVzdWFsIGNhdXNlcyBvZiBkZWF0aCAtLS0tCmhvZF91bnVzdWFsX2JpZyAlPiUKZ2dwbG90KGFlcyh4ID0gaG9kLCB5ID0gcHJvcCkpICsKICBnZW9tX2xpbmUoKSArCiAgZ2VvbV9saW5lKGFlcyh5ID0gcHJvcF9hbGwpLCBkYXRhID0gb3ZlcmFsbF9mcmVxLCBjb2xvdXIgPSAiZ3JleTUwIikgKwogIGZhY2V0X3dyYXAofiBkaXNlYXNlLCBuY29sID0gMykKZ2dzYXZlKCJ1bnVzdWFsLWJpZy5wbmciLCB3aWR0aCA9IDgsIGhlaWdodCA9IDYpCmBgYAoKYGBge3J9CmhvZF91bnVzdWFsX3NtbCAlPiUKICBnZ3Bsb3QoYWVzKHggPSBob2QsIHkgPSBwcm9wKSkgKwogIGdlb21fbGluZSgpICsKICBnZW9tX2xpbmUoYWVzKHkgPSBwcm9wX2FsbCksIGRhdGEgPSBvdmVyYWxsX2ZyZXEsIGNvbG91ciA9ICJncmV5NTAiKSArCiAgZmFjZXRfd3JhcCh+IGRpc2Vhc2UsIG5jb2wgPSAzKQpnZ3NhdmUoInVudXN1YWwtc21sLnBuZyIsIHdpZHRoID0gOCwgaGVpZ2h0ID0gNCkKYGBgCgoKPGEgaHJlZj0iLi4vNC0xLWRwbHlyLmh0bWwiPkdvIGJhY2s8L2E+Cgo=