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=