Introduction

This document describes all data, methods and code used to generate the results within the above-listed article.

All data are publically available, and you are free to interrogate and use the code in your own analyses.

All data preparation, analyses, figures and tables were generated using the R programming language, with the exception of some initial data preparation done within Microsoft Excel. This data preparation only involved changing the structure of existing data within an Excel sheet, rather than the contents of such data.

Reviewer comment responses

Many of the results presented here are produced in response to specific reviewer comments. Where an analysis addresses a specific comment, a comment/reviewer code (such as C7R1 for the seventh comment, by reviewer 1), is included in the text to make this clearer.

Data

The data used are from this National Records of Scotland (NRS)) webpage. The dataset ‘Latest tables based on 2013 ESP’ (European Standardized Population) was downloaded in Excel format.

All analyses presented in the paper were based on table 7 of this Excel Workbook.

The contents of table 7 of the Workbook were rearranged so as to conform with data structure recommended by (Wickham, (2014) ‘Tidy Data’)[https://www.jstatsoft.org/article/view/v059i10/v59i10.pdf], producing a new datasheet, called flat_data, which was imported directly into R. All further processing and analyses were conducted within R.

Workflow and results

The following code chunks perform the analyses which are presented in the paper.

Where additional information are required as to the methods, they are described adjacent to the code chunks.

Loading the required packages

pacman::p_load(tidyverse, readxl, cowplot, kableExtra)

Note: pacman is an R package for managing R packages. It has to be installed once using install.packages("pacman"), but once installed will either install or load other packages as required.

Load data

dta <- read_excel("data/ASMR_SIMD_2001_2017_indexed trends.xlsx", sheet = "flat_data")

Tidying the data

names(dta) <- c("year", "overall", "q1", "q2", "q3", "q4", "q5", "sex")
dta_tidy <- dta %>% 
  rename(sex = sex) %>% 
  gather(key = "simd", value = "asmr", -year, -sex) %>% 
  mutate(SIMD = factor(simd, 
                       levels = c("q1", "q2", "q3", "q4", "q5","overall"),
                       labels = c("Q.1 (Most deprived)", 
                                  "Q.2", "Q.3", "Q.4", "Q.5 (Least deprived)", "Overall")
                       )
         )

Note: Q in the above refers to quintile, i.e. fifths of areas by Scottish Index of Multiple Deprivation (SIMD) scores, with Q1 referring to the most deprived fifth of areas.

Visualising

This is one part of the first figure. The R package ggplot2 is used to produce this visualisation.

p1 <- dta_tidy %>% 
  ggplot(aes(x = year )) +
  facet_wrap(~sex) + 
  geom_line(aes(y = asmr, group = SIMD, linetype = SIMD, size = SIMD, color = SIMD)) + 
  scale_size_manual(values = c(1, 1.2, 1, 1.2, 1, 1.4)) + 
  scale_linetype_manual(values = c(2,3,4,5, 6, 1)) + 
  scale_color_manual(values = c("black", "grey", "black", "grey", "black", "blue")) + 
  labs(x = "Year", y = "Age Standardised mortality rate per 100 000") + 
  scale_y_continuous(expand = c(0, 0), limits = c(0, 2500), minor_breaks = seq(0, 2500, by = 100)) +
  scale_x_continuous(minor_breaks = 2001:2017) +
  geom_vline(xintercept = 2012, linetype = "dashed") + 
  geom_vline(xintercept = 2006, linetype = "dashed") + 
  annotate("text", y = 100, x = 2006 + (2012 - 2006) / 2, label = "2006 to 2011") + 
  annotate("text", y = 100, x = 2012 + (2018 - 2012) / 2, label = "2012 to 2017") + 
  geom_ribbon(
    aes(x = year, ymin = q5, ymax =q1), 
    alpha = 0.1, fill ="red",
    data = dta_tidy %>% filter(simd %in% c("q1", "q5")) %>% select(-SIMD) %>% spread(simd, asmr)
    
  ) + 
  background_grid(major = "xy", minor = "xy")
p1

NA

C10R2: How was the percentage change calculated?

C6R1: Absolute changes

The following code chunk calculates the percentage change, from the earlier to latter period, in ASMR by sex and SIMD quintile.

Algebraically this can be expressed as follows

\[ C_T = -100 \big[1 - \frac{y_T^{last}}{y_T^{first}}\big] \]

Where \(C_T\) refers to the percentage change over a time period \(T\), \(y_T^{last}\) to the observed age-standardised mortality rate (ASMR) in the last year within the period \(T\), and \(y_T^{first}\) to the ASMR in the first year in the period \(T\). Within the analyses, two distinct periods are considered: 2006 to 2011 inclusive, and 2012 to 2017 inclusive.

This code chunk has been adapted so as to also include calcuations of absolute differences (per 100,000 population) in the death rates.

changes <- dta_tidy %>% 
  mutate(period = case_when(
    between(year, 2012, 2017) ~ "2012-2017", 
    between(year, 2006, 2011) ~ "2006-2011",
    TRUE ~ NA_character_) %>% factor(levels = c("2012-2017", "2006-2011"))) %>% 
  group_by(sex, simd, period) %>% 
  filter(year == min(year) | year == max(year) ) %>% # This finds the first and last year in each period
  filter(!is.na(period)) %>% 
  group_by(sex, SIMD, period) %>% 
  summarise(
    percent_change = - 100 * (1 - asmr[year == max(year)] / asmr[year == min(year)]),
    absolute_change = asmr[year == max(year)] - asmr[year == min(year)]
    ) %>% 
  ungroup()
Factor `period` contains implicit NA, consider using `forcats::fct_explicit_na`

Note: The contents of changes look as follows:

changes

For the alternative method, presented in the appendix, the model predicted ASMR values \(\hat{Y}\) are used in place of the observed ASMR values \(y\) in the above. These predicted values are produced for each SIMD, period, and sex category regressed on year within period. This is shown in the section ‘approach discussed in sensitivity analysis’.

Absolute rates (C6R1)

The following shows the absolute changes in ASMR graphically

changes %>% 
  ggplot(aes(x = SIMD, y = absolute_change)) +
  geom_point() + 
  facet_grid(period~sex) + 
  geom_hline(yintercept = 0) +
  theme(axis.text.x = element_text(angle = 90)) + 
  labs(x = "Deprivation quintile", y = "Absolute change in ASMR", title = "Absolute change in ASMR by sex, period, and SIMD quintile")

We can see from this that the absolute changes slowed in the latter period, and became positive (worse in absolute terms) in the most deprived fifth of the population.

The following shows the above as a table

changes %>% 
  select(-percent_change) %>% 
  spread(SIMD, absolute_change)

Amended figure (C12R2, C20R3)

Two cosmetic amendments to Figure1b have been requested. The first is to avoid overlapping points between periods; the second is to relabel the xaxis so the labels read ‘most deprived’ and ‘least deprived’ rather than ‘most’ and ‘least’.

The following code chunk produces these figures with these amendments made.

p2 <- changes %>%
    select(-absolute_change) %>% 
    mutate(SIMD = factor(SIMD, 
                       levels = c("Q.1 (Most deprived)", 
                                  "Q.2", "Q.3", "Q.4", "Q.5 (Least deprived)", "Overall"),
                       labels = c("Most deprived", "Q2", "Q3", "Q4", "Least deprived", "Overall")
                       )
         ) %>% 
  filter(SIMD != "Overall") %>% 
  ggplot(aes(x = SIMD, y = percent_change, group = period, shape = period, fill = period, colour = period)) + 
  facet_wrap( ~ sex) + 
  geom_point(size = 5) + 
  stat_smooth(method = "lm", se = F, colour = "black") + # This produces the blue line with the regression slopes
  geom_hline(yintercept = 0) + 
  geom_hline( # This adds the overall percent change
    aes(yintercept = percent_change, group = period),
    data = changes %>% filter(SIMD == "Overall"),
    linetype = "dashed"
  ) + 
  theme(axis.text.x = element_text(angle = 90)) + 
  labs(y = "Percent change in ASMR by period", x = "SIMD Quintile") +
  scale_shape_manual("Period", values = c(2, 16)) +    # This has been changed to make one of the points hollow
  scale_fill_manual("Period", values = c("black", "grey")) +
  scale_colour_manual("Period", values = c("black", "grey"))
p2 

It is now clear that the points overlap in the least deprived quitile.

Combined figure

The following produces the combined figure comprising the two parts shown previously. The figure is rendered as a png format image at 300dpi, and placed in the directory ‘figures’.

p_both <- plot_grid(p1, p2, labels = c("A", "B"), ncol = 1, align = "v")
p_both

ggsave("figures/combined_figure_2012.png", dpi = 300, units = "cm", height = 30, width = 30)

Table

The following shows how the contents of the table were produced.

These summarise a series of univariate linear regressions of SIMD quintile against precentage change in ASMR within distinct periods.

The columns intercept and gradient present summary information about point estimates and 95% confidence intervals for the intercept and gradient of the the regressions, which are then presented in the formatted table.

A functional programming approach was adopted in order to produce the same analyses consistently for different sex and period combinations, using functions within the (purrr package)[https://purrr.tidyverse.org/.

get_ci <- function(x){
  tmp <- x %>% summary() %>% coefficients()
  
  return(
    list(
      lower = tmp[,1] - 1.96 * tmp[,2],
      upper = tmp[,1] + 1.96 * tmp[,2]
    )
  )
  
}
# Model parameters 
tbl_1_pct <- changes %>% 
  filter(SIMD != "Overall") %>% 
  mutate(qnt = unclass(SIMD) - 1) %>% # This is so the intercept refers to the 1st quintile (not the 'zeroth' quintile)
  select(sex, period, percent_change, qnt) %>% 
  group_by(sex, period) %>% 
  nest() %>% 
  mutate(mdl = map(data, ~lm(percent_change ~ qnt, data = .x))) %>% 
  mutate(`R. sq.` = map_dbl(mdl, ~summary(.x)["r.squared"][[1]])) %>% 
  mutate(gradient = map_dbl(mdl, ~coef(.x)["qnt"])) %>% 
  mutate(intercept = map_dbl(mdl, ~coef(.x)["(Intercept)"])) %>% 
  mutate(cis = map(mdl, get_ci)) %>% 
  mutate(
    int_lower = map_dbl(cis, ~.[["lower"]][1]),
    int_upper = map_dbl(cis, ~.[["upper"]][1]),
    grd_lower = map_dbl(cis, ~.[["lower"]][2]),
    grd_upper = map_dbl(cis, ~.[["upper"]][2])                
  ) %>% 
  select(sex, period, `R. sq.`, 
         gradient, grd_lower, grd_upper, 
         intercept, int_lower, int_upper
  ) %>% 
  mutate(
    gradient = paste0(
      format(round(gradient, 2), nsmall = 2), 
      " (", 
      format(round(grd_lower, 2), nsmall = 2), 
      ", ", 
      format(round(grd_upper, 2), nsmall = 2), 
      ")"
    )
  ) %>% 
  mutate(
    intercept = paste0(
      format(round(intercept, 2), nsmall = 2), 
      " (", 
      format(round(int_lower, 2), nsmall = 2), 
      ", ", 
      format(round(int_upper, 2), nsmall = 2),
      ")"
    )
  ) %>% 
  select(-grd_lower, -grd_upper, -int_lower, -int_upper)
tbl_1_pct
tbl_2_pct <- changes %>% select(-absolute_change) %>% spread(SIMD, percent_change)
tbl_both_pct <- inner_join(tbl_2_pct, tbl_1_pct) 
Joining, by = c("sex", "period")
tbl_both_pct 

The following converts the above table into a more neatly formatted table using the kable and kableExtra packages.

tbl_both_pct %>% 
  mutate(period = factor(period, levels = c("2006-2011", "2012-2017")))  %>%
  arrange(sex, period) %>% 
  knitr::kable(
    digits = 2, 
    caption = "Percent change in ASMR by sex, SIMD quintile, and period"
  ) %>% 
  kableExtra::kable_styling() %>% 
  kableExtra::add_header_above(c(" "," ", "Percentages" = 6, "Model results" = 3)) %>% 
  kableExtra::footnote("Overall: Whole of Scotland. R.Sq. : R-Squared for model. Gradient: Increase in % change per unit increase in quintile. Intercept: Predicted % change in most deprived quintile. For gradient and intercept, values in parentheses show lower and upper 95% confidence intervals of coefficients respectively.")
Percent change in ASMR by sex, SIMD quintile, and period
Percentages
Model results
sex period Q.1 (Most deprived) Q.2 Q.3 Q.4 Q.5 (Least deprived) Overall R. sq. gradient intercept
Female 2006-2011 -7.21 -7.37 -13.34 -13.21 -7.81 -10.11 0.12 -0.70 (-2.84, 1.44) -8.38 (-13.62, -3.14)
Female 2012-2017 0.69 -2.65 -2.96 -5.53 -7.79 -3.46 0.96 -1.98 (-2.44, -1.53) 0.32 ( -0.80, 1.44)
Male 2006-2011 -9.81 -11.57 -10.94 -12.35 -12.57 -11.82 0.79 -0.63 (-1.00, -0.26) -10.19 (-11.09, -9.29)
Male 2012-2017 2.11 -2.27 -2.78 -3.57 -4.44 -2.00 0.80 -1.44 (-2.25, -0.63) 0.69 ( -1.29, 2.67)
Total 2006-2011 -8.56 -9.18 -12.19 -12.17 -9.04 -10.59 0.12 -0.40 (-1.60, 0.81) -9.44 (-12.39, -6.48)
Total 2012-2017 1.35 -2.32 -2.38 -4.61 -6.05 -2.59 0.93 -1.71 (-2.25, -1.17) 0.62 ( -0.70, 1.93)
Note:
Overall: Whole of Scotland. R.Sq. : R-Squared for model. Gradient: Increase in % change per unit increase in quintile. Intercept: Predicted % change in most deprived quintile. For gradient and intercept, values in parentheses show lower and upper 95% confidence intervals of coefficients respectively.

Absolute change

The following table presents a similarly unformatted, then formatted, table for the absolute change differences.

# Model parameters 
tbl_1_abs <- changes %>% 
  filter(SIMD != "Overall") %>% 
  mutate(qnt = unclass(SIMD) - 1) %>% # This is so the intercept refers to the 1st quintile (not the 'zeroth' quintile)
  select(sex, period, absolute_change, qnt) %>% 
  group_by(sex, period) %>% 
  nest() %>% 
  mutate(mdl = map(data, ~lm(absolute_change ~ qnt, data = .x))) %>% 
  mutate(`R. sq.` = map_dbl(mdl, ~summary(.x)["r.squared"][[1]])) %>% 
  mutate(gradient = map_dbl(mdl, ~coef(.x)["qnt"])) %>% 
  mutate(intercept = map_dbl(mdl, ~coef(.x)["(Intercept)"])) %>% 
  mutate(cis = map(mdl, get_ci)) %>% 
  mutate(
    int_lower = map_dbl(cis, ~.[["lower"]][1]),
    int_upper = map_dbl(cis, ~.[["upper"]][1]),
    grd_lower = map_dbl(cis, ~.[["lower"]][2]),
    grd_upper = map_dbl(cis, ~.[["upper"]][2])                
  ) %>% 
  select(sex, period, `R. sq.`, 
         gradient, grd_lower, grd_upper, 
         intercept, int_lower, int_upper
  ) %>% 
  mutate(
    gradient = paste0(
      format(round(gradient, 2), nsmall = 2), 
      " (", 
      format(round(grd_lower, 2), nsmall = 2), 
      ", ", 
      format(round(grd_upper, 2), nsmall = 2), 
      ")"
    )
  ) %>% 
  mutate(
    intercept = paste0(
      format(round(intercept, 2), nsmall = 2), 
      " (", 
      format(round(int_lower, 2), nsmall = 2), 
      ", ", 
      format(round(int_upper, 2), nsmall = 2),
      ")"
    )
  ) %>% 
  select(-grd_lower, -grd_upper, -int_lower, -int_upper)
tbl_1_abs
tbl_2_abs <- changes %>% select(-percent_change) %>% spread(SIMD, absolute_change)
tbl_both_abs <- inner_join(tbl_2_abs, tbl_1_abs) 
Joining, by = c("sex", "period")
tbl_both_abs 

And the following shows the above table formatted as previously

tbl_both_abs %>% 
  mutate(period = factor(period, levels = c("2006-2011", "2012-2017")))  %>%
  arrange(sex, period) %>% 
  knitr::kable(
    digits = 2, 
    caption = "Absolute change in ASMR by sex, SIMD quintile, and period"
  ) %>% 
  kableExtra::kable_styling() %>% 
  kableExtra::add_header_above(c(" "," ", "Absolute Differences" = 6, "Model results" = 3)) %>% 
  kableExtra::footnote("Overall: Whole of Scotland. R.Sq. : R-Squared for model. Gradient: Increase in absolute change per unit increase in quintile. Intercept: Predicted absolute change in most deprived quintile. For gradient and intercept, values in parentheses show lower and upper 95% confidence intervals of coefficients respectively.")
Absolute change in ASMR by sex, SIMD quintile, and period
Absolute Differences
Model results
sex period Q.1 (Most deprived) Q.2 Q.3 Q.4 Q.5 (Least deprived) Overall R. sq. gradient intercept
Female 2006-2011 -99.6 -88.8 -149.8 -136.2 -67.8 -113.2 0.01 1.62 (-22.57, 25.81) -111.68 (-170.94, -52.42)
Female 2012-2017 9.3 -30.0 -29.8 -50.9 -62.7 -35.8 0.90 -16.49 (-22.60, -10.38) 0.16 ( -14.81, 15.13)
Male 2006-2011 -203.8 -202.2 -169.5 -166.5 -146.0 -184.7 0.92 15.13 ( 10.20, 20.06) -207.86 (-219.94, -195.78)
Male 2012-2017 38.9 -34.6 -38.1 -41.0 -44.9 -27.1 0.61 -17.40 (-33.27, -1.53) 10.86 ( -28.00, 49.72)
Total 2006-2011 -143.1 -131.0 -158.3 -141.3 -88.8 -137.9 0.35 9.83 ( -5.36, 25.02) -152.16 (-189.36, -114.96)
Total 2012-2017 21.1 -30.1 -27.6 -47.2 -54.0 -30.4 0.81 -16.73 (-25.92, -7.54) 5.90 ( -16.62, 28.42)
Note:
Overall: Whole of Scotland. R.Sq. : R-Squared for model. Gradient: Increase in absolute change per unit increase in quintile. Intercept: Predicted absolute change in most deprived quintile. For gradient and intercept, values in parentheses show lower and upper 95% confidence intervals of coefficients respectively.

Table with absolute and relative changes combined

tbl_both_pct %>%
  mutate(type = "pct") %>% 
  bind_rows(
    tbl_both_abs %>% mutate(type = "abs") 
  ) %>% 
  mutate(period = factor(period, levels = c("2006-2011", "2012-2017")))  %>%
  mutate(type = factor(type, levels = c("pct", "abs"))) %>% 
  arrange(type, sex, period) %>% 
  select(-type) %>% 
  knitr::kable(
    digits = 2, 
    caption = "Change in ASMRs per 100,000 population, by sex, SIMD quintile and period"
  ) %>% 
  kableExtra::kable_styling() %>% 
  kableExtra::pack_rows("Percentage", 1,7) %>% 
  kableExtra::pack_rows("Absolute", 7,12) %>% 
  kableExtra::add_header_above(c(" "," ", "Differences" = 6, "Model results" = 3)) %>% 
  kableExtra::footnote("Overall: Whole of Scotland. R.Sq. : R-Squared for model. Gradient: Increase in change per unit increase in quintile. Intercept: Predicted change in most deprived quintile. For gradient and intercept, values in parentheses show lower and upper 95% confidence intervals of coefficients respectively.")
Change in ASMRs per 100,000 population, by sex, SIMD quintile and period
Differences
Model results
sex period Q.1 (Most deprived) Q.2 Q.3 Q.4 Q.5 (Least deprived) Overall R. sq. gradient intercept
Percentage
Female 2006-2011 -7.21 -7.37 -13.34 -13.21 -7.81 -10.11 0.12 -0.70 (-2.84, 1.44) -8.38 (-13.62, -3.14)
Female 2012-2017 0.69 -2.65 -2.96 -5.53 -7.79 -3.46 0.96 -1.98 (-2.44, -1.53) 0.32 ( -0.80, 1.44)
Male 2006-2011 -9.81 -11.57 -10.94 -12.35 -12.57 -11.82 0.79 -0.63 (-1.00, -0.26) -10.19 (-11.09, -9.29)
Male 2012-2017 2.11 -2.27 -2.78 -3.57 -4.44 -2.00 0.80 -1.44 (-2.25, -0.63) 0.69 ( -1.29, 2.67)
Total 2006-2011 -8.56 -9.18 -12.19 -12.17 -9.04 -10.59 0.12 -0.40 (-1.60, 0.81) -9.44 (-12.39, -6.48)
Total 2012-2017 1.35 -2.32 -2.38 -4.61 -6.05 -2.59 0.93 -1.71 (-2.25, -1.17) 0.62 ( -0.70, 1.93)
Absolute
Female 2006-2011 -99.60 -88.80 -149.80 -136.20 -67.80 -113.20 0.01 1.62 (-22.57, 25.81) -111.68 (-170.94, -52.42)
Female 2012-2017 9.30 -30.00 -29.80 -50.90 -62.70 -35.80 0.90 -16.49 (-22.60, -10.38) 0.16 ( -14.81, 15.13)
Male 2006-2011 -203.80 -202.20 -169.50 -166.50 -146.00 -184.70 0.92 15.13 ( 10.20, 20.06) -207.86 (-219.94, -195.78)
Male 2012-2017 38.90 -34.60 -38.10 -41.00 -44.90 -27.10 0.61 -17.40 (-33.27, -1.53) 10.86 ( -28.00, 49.72)
Total 2006-2011 -143.10 -131.00 -158.30 -141.30 -88.80 -137.90 0.35 9.83 ( -5.36, 25.02) -152.16 (-189.36, -114.96)
Total 2012-2017 21.10 -30.10 -27.60 -47.20 -54.00 -30.40 0.81 -16.73 (-25.92, -7.54) 5.90 ( -16.62, 28.42)
Note:
Overall: Whole of Scotland. R.Sq. : R-Squared for model. Gradient: Increase in change per unit increase in quintile. Intercept: Predicted change in most deprived quintile. For gradient and intercept, values in parentheses show lower and upper 95% confidence intervals of coefficients respectively.

Approach discussed in sensitivity analysis (C2R1, C10R2)

The sensitivity analysis to the paper showed the effect of using the fitted values for the first and last year in each of the periods, rather than the values themselves. This approach can address any concern that the first and last year within either period were in any way anomalous or uncharacteristic of change within the period as a whole.

The function broom::augment was used to extract fitted values for each year within each period, sex and SIMD combination. The fitted values, .fitted, were then used in place of the observed values, asmr, as in the main analyses.

percent_changes_pred <- dta_tidy %>% 
    mutate(period = case_when(
        between(year, 2012, 2017) ~ "2012-2017", 
        between(year, 2006, 2011) ~ "2006-2011",
        TRUE ~ NA_character_) %>% factor(levels = c("2012-2017", "2006-2011"))) %>% 
    group_by(sex, SIMD, simd, period) %>% 
  nest() %>% 
  mutate(mdl = map(data, ~lm(asmr ~ year, data = .x))) %>% 
  mutate(aug = map(mdl, broom::augment)) %>% 
  select(-data, -mdl) %>% 
  unnest() %>% 
  filter(!is.na(period)) %>% 
  group_by(sex, SIMD, period) %>% 
  filter(year == min(year) | year == max(year) ) %>% 
  summarise(percent_change = - 100 * (1 - .fitted[year == max(year)] / .fitted[year == min(year)])) %>% 
  ungroup()
Factor `period` contains implicit NA, consider using `forcats::fct_explicit_na`Factor `period` contains implicit NA, consider using `forcats::fct_explicit_na`
percent_changes_pred_overall <- percent_changes_pred %>% 
  group_by(sex, period) %>% 
  summarise(percent_change = mean(percent_change)) %>% 
  ungroup() %>% 
  mutate(SIMD = "Mean of quintiles") %>% 
  select(sex, SIMD, period, percent_change)
  
percent_changes_pred <- percent_changes_pred %>% 
  bind_rows(percent_changes_pred_overall) %>% 
  mutate(SIMD = factor(SIMD, 
                       levels = c("Q.1 (Most deprived)", 
                                  "Q.2", "Q.3", "Q.4", "Q.5 (Least deprived)", "Overall", "Mean of quintiles"),
                       labels = c("Most deprived", "Q2", "Q3", "Q4", "Least deprived", "Overall", "Mean of quintiles")
                       )
  ) 
binding factor and character vector, coercing into character vectorbinding character and factor vector, coercing into character vector

The subfigure using this alternative strategy is therefore produced as follows:

p2a <- percent_changes_pred %>% 
  filter(!(SIMD %in% c("Overall", "Mean of quintiles"))) %>% 
  ggplot(aes(x = SIMD, y = percent_change, group = period, shape = period, fill = period, colour = period)) + 
  facet_wrap( ~ sex) + 
  geom_point(size = 5) + 
  stat_smooth(method = "lm", se = F, colour = "black") + # This produces the blue line with the regression slopes
  geom_hline(yintercept = 0) + 
  geom_hline( # This adds the overall percent change
    aes(yintercept = percent_change, group = period),
    data = changes %>% filter(SIMD == "Overall"),
    linetype = "dashed"
  ) + 
  theme(axis.text.x = element_text(angle = 90)) + 
  labs(y = "Percent change in ASMR by period", x = "SIMD Quintile") +
  scale_shape_manual("Period", values = c(2, 16)) +    # This has been changed to make one of the points hollow
  scale_fill_manual("Period", values = c("black", "grey")) +
  scale_colour_manual("Period", values = c("black", "grey"))
    
p2a

ggsave("figures/fig1a_using_alt_method_2012.png", dpi = 300, units = "cm", height = 16, width = 30)

The table of the above, using this alternative modelling strategy, is produced using the code chunks below

get_ci <- function(x){
  tmp <- x %>% summary() %>% coefficients()
  
  return(
    list(
      lower = tmp[,1] - 1.96 * tmp[,2],
      upper = tmp[,1] + 1.96 * tmp[,2]
    )
  )
  
}
# Model parameters 
tbl_1a <- percent_changes_pred %>% 
  filter(!(SIMD %in% c("Overall", "Mean of quintiles"))) %>% 
  mutate(qnt = unclass(SIMD) - 1) %>% # This is so the intercept refers to the 1st quintile (not the 'zeroth' quintile)
  select(sex, period, percent_change, qnt) %>% 
  group_by(sex, period) %>% 
  nest() %>% 
  mutate(mdl = map(data, ~lm(percent_change ~ qnt, data = .x))) %>% 
  mutate(`R. sq.` = map_dbl(mdl, ~summary(.x)["r.squared"][[1]])) %>% 
  mutate(gradient = map_dbl(mdl, ~coef(.x)["qnt"])) %>% 
  mutate(intercept = map_dbl(mdl, ~coef(.x)["(Intercept)"])) %>% 
  mutate(cis = map(mdl, get_ci)) %>% 
  mutate(
    int_lower = map_dbl(cis, ~.[["lower"]][1]),
    int_upper = map_dbl(cis, ~.[["upper"]][1]),
    grd_lower = map_dbl(cis, ~.[["lower"]][2]),
    grd_upper = map_dbl(cis, ~.[["upper"]][2])                
  ) %>% 
  select(sex, period, `R. sq.`, 
         gradient, grd_lower, grd_upper, 
         intercept, int_lower, int_upper
  ) %>% 
  mutate(
    gradient = paste0(
      format(round(gradient, 2), nsmall = 2), 
      " (", 
      format(round(grd_lower, 2), nsmall = 2), 
      ", ", 
      format(round(grd_upper, 2), nsmall = 2), 
      ")"
    )
  ) %>% 
  mutate(
    intercept = paste0(
      format(round(intercept, 2), nsmall = 2), 
      " (", 
      format(round(int_lower, 2), nsmall = 2), 
      ", ", 
      format(round(int_upper, 2), nsmall = 2),
      ")"
    )
  ) %>% 
  select(-grd_lower, -grd_upper, -int_lower, -int_upper)
tbl_1a
tbl_2a <- percent_changes_pred %>% filter(SIMD != "Mean of quintiles") %>% spread(SIMD, percent_change)
tbl_both_a <- inner_join(tbl_2a, tbl_1a) 
Joining, by = c("sex", "period")
tbl_both_a

And the table using the alternative approach

tbl_both_a %>%
  gather(`Most deprived`:`Overall`, key = "SIMD", value = "value") %>% 
    mutate(SIMD = factor(SIMD, 
                       levels = c("Most deprived", "Q2", "Q3", "Q4", "Least deprived","Overall"),
                       labels = c("Q.1 (Most deprived)", 
                                  "Q.2", "Q.3", "Q.4", "Q.5 (Least deprived)", "Overall")
                       )
         ) %>% 
  mutate(period = factor(period, levels = c("2006-2011", "2012-2017")))  %>%
  spread(key = SIMD, value = value) %>% 
  select(sex, period, `Q.1 (Most deprived)`:`Overall`, everything()) %>% 
  arrange(sex, period) %>% 
  knitr::kable(
    digits = 2, 
    caption = "Percent change in ASMR by sex, SIMD quintile, and period. (Alternative method)"
  ) %>% 
  kableExtra::kable_styling() %>% 
  kableExtra::add_header_above(c(" "," ", "Percentages" = 6, "Model results" = 3)) %>% 
  kableExtra::footnote("Overall: Whole of Scotland. R.Sq. : R-Squared for model. Gradient: Increase in % change per unit increase in quintile. Intercept: Predicted % change in most deprived quintile. For gradient and intercept, values in parentheses show lower and upper 95% confidence intervals of coefficients respectively.")
Percent change in ASMR by sex, SIMD quintile, and period. (Alternative method)
Percentages
Model results
sex period Q.1 (Most deprived) Q.2 Q.3 Q.4 Q.5 (Least deprived) Overall R. sq. gradient intercept
Female 2006-2011 -7.35 -9.09 -13.32 -13.59 -9.76 -10.94 0.29 -0.93 (-2.58, 0.72) -8.76 (-12.80, -4.72)
Female 2012-2017 1.60 -2.38 -0.75 -4.50 -7.60 -2.47 0.85 -2.05 (-3.03, -1.07) 1.38 ( -1.03, 3.78)
Male 2006-2011 -11.90 -13.14 -12.62 -13.06 -12.40 -13.11 0.08 -0.09 (-0.44, 0.26) -12.44 (-13.29, -11.59)
Male 2012-2017 2.69 -1.92 -0.42 -5.06 -3.76 -1.40 0.71 -1.60 (-2.78, -0.43) 1.51 ( -1.36, 4.39)
Total 2006-2011 -9.63 -10.73 -12.82 -12.76 -10.45 -11.67 0.16 -0.37 (-1.31, 0.58) -10.55 (-12.85, -8.24)
Total 2012-2017 2.22 -1.85 -0.19 -4.54 -5.73 -1.72 0.83 -1.86 (-2.80, -0.92) 1.70 ( -0.60, 4.01)
Note:
Overall: Whole of Scotland. R.Sq. : R-Squared for model. Gradient: Increase in % change per unit increase in quintile. Intercept: Predicted % change in most deprived quintile. For gradient and intercept, values in parentheses show lower and upper 95% confidence intervals of coefficients respectively.

Discussion

This document has provided descriptions of the data used, the processing performed on the data, and the code used to perform all analyses, visualisations, and tabulations. Our hope is this addresses any methodological concerns from viewers and reviewers, and will make it much more straightforward for anyone who wants to replicate and advance on our analyses to do so.

Requests from reviewers

This section will include additional analyses performed as a result of reviewer comments.

C7 R1 - Observed vs predicted values

The reviewer comment was:

R-squared is a poor measure in and of itself of model fit - particularly given the small number of observations in the model. One may consider reporting observed vs predicted changes to understand how well the model is fitting. Furthermore, directly including the age structure would significantly improve model fit.

The predicted vs observed values are shown as follows:

changes %>% 
  filter(SIMD != "Overall") %>% 
  mutate(qnt = unclass(SIMD) - 1) %>% # This is so the intercept refers to the 1st quintile (not the 'zeroth' quintile)
  select(sex, period, percent_change, qnt) %>% 
  group_by(sex, period) %>% 
  nest() %>% 
  mutate(mdl = map(data, ~lm(percent_change ~ qnt, data = .x))) %>% 
  mutate(dta_augmented = map2(mdl, data, broom::augment)) %>% 
  select(-data, -mdl) %>% 
  unnest() %>% 
  ggplot(aes(x = percent_change, y = .fitted, label = qnt + 1)) + 
  geom_text() + 
  facet_grid(sex ~ period) + 
  stat_smooth(method = "lm", se = F) + 
  labs(
    x = "Observed percentage",
    y = "Fitted percentage",
    title = "Relationships between observed and fitted percentages by sex and period",
    subtitle = "Values refer to SIMD quintiles (1: most deprived)"
    
  )

This supports the observation that the relationship has become more linear over time, as also illustrated by the changing \(R^{2}\) values between the two periods.

LS0tDQp0aXRsZTogT25saW5lIFRlY2huaWNhbCBBcHBlbmRpeCBmb3IgRmVudG9uLCBXeXBlciwgTWNDYXJ0bmV5LCBNaW50b24sICdTb2Npb2Vjb25vbWljDQogIGluZXF1YWxpdHkgaW4gcmVjZW50IG1vcnRhbGl0eSB0cmVuZHMgaW4gU2NvdGxhbmQNCmF1dGhvcjogIkpvbiBNaW50b24iDQpvdXRwdXQ6DQogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQNCiAgcGRmX2RvY3VtZW50OiBkZWZhdWx0DQogIHdvcmRfZG9jdW1lbnQ6IGRlZmF1bHQNCiAgaHRtbF9kb2N1bWVudDoNCiAgICBkZl9wcmludDogcGFnZWQNCmFsd2F5c19hbGxvd19odG1sOiB5ZXMNCi0tLQ0KDQojIEludHJvZHVjdGlvbg0KDQpUaGlzIGRvY3VtZW50IGRlc2NyaWJlcyBhbGwgZGF0YSwgbWV0aG9kcyBhbmQgY29kZSB1c2VkIHRvIGdlbmVyYXRlIHRoZSByZXN1bHRzIHdpdGhpbiB0aGUgYWJvdmUtbGlzdGVkIGFydGljbGUuIA0KDQpBbGwgZGF0YSBhcmUgcHVibGljYWxseSBhdmFpbGFibGUsIGFuZCB5b3UgYXJlIGZyZWUgdG8gaW50ZXJyb2dhdGUgYW5kIHVzZSB0aGUgY29kZSBpbiB5b3VyIG93biBhbmFseXNlcy4gDQoNCkFsbCBkYXRhIHByZXBhcmF0aW9uLCBhbmFseXNlcywgZmlndXJlcyBhbmQgdGFibGVzIHdlcmUgZ2VuZXJhdGVkIHVzaW5nIHRoZSBSIHByb2dyYW1taW5nIGxhbmd1YWdlLCB3aXRoIHRoZSBleGNlcHRpb24gb2Ygc29tZSBpbml0aWFsIGRhdGEgcHJlcGFyYXRpb24gZG9uZSB3aXRoaW4gTWljcm9zb2Z0IEV4Y2VsLiBUaGlzIGRhdGEgcHJlcGFyYXRpb24gb25seSBpbnZvbHZlZCBjaGFuZ2luZyB0aGUgc3RydWN0dXJlIG9mIGV4aXN0aW5nIGRhdGEgd2l0aGluIGFuIEV4Y2VsIHNoZWV0LCByYXRoZXIgdGhhbiB0aGUgY29udGVudHMgb2Ygc3VjaCBkYXRhLiANCg0KIyMgUmV2aWV3ZXIgY29tbWVudCByZXNwb25zZXMNCg0KTWFueSBvZiB0aGUgcmVzdWx0cyBwcmVzZW50ZWQgaGVyZSBhcmUgcHJvZHVjZWQgaW4gcmVzcG9uc2UgdG8gc3BlY2lmaWMgcmV2aWV3ZXIgY29tbWVudHMuIFdoZXJlIGFuIGFuYWx5c2lzIGFkZHJlc3NlcyBhIHNwZWNpZmljIGNvbW1lbnQsIGEgY29tbWVudC9yZXZpZXdlciBjb2RlIChzdWNoIGFzIEM3UjEgZm9yIHRoZSBzZXZlbnRoIGNvbW1lbnQsIGJ5IHJldmlld2VyIDEpLCBpcyBpbmNsdWRlZCBpbiB0aGUgdGV4dCB0byBtYWtlIHRoaXMgY2xlYXJlci4NCg0KDQoNCiMgRGF0YSANCg0KVGhlIGRhdGEgdXNlZCBhcmUgZnJvbSBbdGhpcyBOYXRpb25hbCBSZWNvcmRzIG9mIFNjb3RsYW5kIChOUlMpKSB3ZWJwYWdlXShodHRwczovL3d3dy5ucnNjb3RsYW5kLmdvdi51ay9zdGF0aXN0aWNzLWFuZC1kYXRhL3N0YXRpc3RpY3Mvc3RhdGlzdGljcy1ieS10aGVtZS92aXRhbC1ldmVudHMvZGVhdGhzL2FnZS1zdGFuZGFyZGlzZWQtZGVhdGgtcmF0ZXMtY2FsY3VsYXRlZC11c2luZy10aGUtZXNwKS4gVGhlIGRhdGFzZXQgWydMYXRlc3QgdGFibGVzIGJhc2VkIG9uIDIwMTMgRVNQJyAoRXVyb3BlYW4gU3RhbmRhcmRpemVkIFBvcHVsYXRpb24pIHdhcyBkb3dubG9hZGVkIGluIEV4Y2VsIGZvcm1hdF0oaHR0cHM6Ly93d3cubnJzY290bGFuZC5nb3YudWsvZmlsZXMvL3N0YXRpc3RpY3MvYWdlLXN0YW5kYXJkaXNlZC1kZWF0aC1yYXRlcy1lc3AvMjAxNy9hZ2Utc3RhbmRhcmQtZGVhdGgtcmF0ZXMtMTctYWxsJTIwdGFicy1yZXZpc2VkLnhsc3gpLg0KDQpBbGwgYW5hbHlzZXMgcHJlc2VudGVkIGluIHRoZSBwYXBlciB3ZXJlIGJhc2VkIG9uIHRhYmxlIDcgb2YgdGhpcyBFeGNlbCBXb3JrYm9vay4NCg0KVGhlIGNvbnRlbnRzIG9mIHRhYmxlIDcgb2YgdGhlIFdvcmtib29rIHdlcmUgcmVhcnJhbmdlZCBzbyBhcyB0byBjb25mb3JtIHdpdGggZGF0YSBzdHJ1Y3R1cmUgcmVjb21tZW5kZWQgYnkgKFdpY2toYW0sICgyMDE0KSAnVGlkeSBEYXRhJylbaHR0cHM6Ly93d3cuanN0YXRzb2Z0Lm9yZy9hcnRpY2xlL3ZpZXcvdjA1OWkxMC92NTlpMTAucGRmXSwgcHJvZHVjaW5nIGEgbmV3IGRhdGFzaGVldCwgY2FsbGVkIGBmbGF0X2RhdGFgLCB3aGljaCB3YXMgaW1wb3J0ZWQgZGlyZWN0bHkgaW50byBSLiBBbGwgZnVydGhlciBwcm9jZXNzaW5nIGFuZCBhbmFseXNlcyB3ZXJlIGNvbmR1Y3RlZCB3aXRoaW4gUi4NCg0KIyBXb3JrZmxvdyBhbmQgcmVzdWx0cw0KDQpUaGUgZm9sbG93aW5nIGNvZGUgY2h1bmtzIHBlcmZvcm0gdGhlIGFuYWx5c2VzIHdoaWNoIGFyZSBwcmVzZW50ZWQgaW4gdGhlIHBhcGVyLiANCg0KV2hlcmUgYWRkaXRpb25hbCBpbmZvcm1hdGlvbiBhcmUgcmVxdWlyZWQgYXMgdG8gdGhlIG1ldGhvZHMsIHRoZXkgYXJlIGRlc2NyaWJlZCBhZGphY2VudCB0byB0aGUgY29kZSBjaHVua3MuIA0KDQojIyBMb2FkaW5nIHRoZSByZXF1aXJlZCBwYWNrYWdlcw0KDQpgYGB7cn0NCnBhY21hbjo6cF9sb2FkKHRpZHl2ZXJzZSwgcmVhZHhsLCBjb3dwbG90LCBrYWJsZUV4dHJhKQ0KYGBgDQoNCipOb3RlKjogYHBhY21hbmAgaXMgYW4gUiBwYWNrYWdlIGZvciBtYW5hZ2luZyBSIHBhY2thZ2VzLiBJdCBoYXMgdG8gYmUgaW5zdGFsbGVkIG9uY2UgdXNpbmcgYGluc3RhbGwucGFja2FnZXMoInBhY21hbiIpYCwgYnV0IG9uY2UgaW5zdGFsbGVkIHdpbGwgZWl0aGVyIGluc3RhbGwgb3IgbG9hZCBvdGhlciBwYWNrYWdlcyBhcyByZXF1aXJlZC4gDQoNCiMjIExvYWQgZGF0YQ0KDQpgYGB7cn0NCmR0YSA8LSByZWFkX2V4Y2VsKCJkYXRhL0FTTVJfU0lNRF8yMDAxXzIwMTdfaW5kZXhlZCB0cmVuZHMueGxzeCIsIHNoZWV0ID0gImZsYXRfZGF0YSIpDQoNCmBgYA0KDQojIyBUaWR5aW5nIHRoZSBkYXRhIA0KDQoNCmBgYHtyfQ0KbmFtZXMoZHRhKSA8LSBjKCJ5ZWFyIiwgIm92ZXJhbGwiLCAicTEiLCAicTIiLCAicTMiLCAicTQiLCAicTUiLCAic2V4IikNCg0KZHRhX3RpZHkgPC0gZHRhICU+JSANCiAgcmVuYW1lKHNleCA9IHNleCkgJT4lIA0KICBnYXRoZXIoa2V5ID0gInNpbWQiLCB2YWx1ZSA9ICJhc21yIiwgLXllYXIsIC1zZXgpICU+JSANCiAgbXV0YXRlKFNJTUQgPSBmYWN0b3Ioc2ltZCwgDQogICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoInExIiwgInEyIiwgInEzIiwgInE0IiwgInE1Iiwib3ZlcmFsbCIpLA0KICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJRLjEgKE1vc3QgZGVwcml2ZWQpIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlEuMiIsICJRLjMiLCAiUS40IiwgIlEuNSAoTGVhc3QgZGVwcml2ZWQpIiwgIk92ZXJhbGwiKQ0KICAgICAgICAgICAgICAgICAgICAgICApDQogICAgICAgICApDQoNCmBgYA0KDQoqKk5vdGU6KiogYFFgIGluIHRoZSBhYm92ZSByZWZlcnMgdG8gcXVpbnRpbGUsIGkuZS4gZmlmdGhzIG9mIGFyZWFzIGJ5IFNjb3R0aXNoIEluZGV4IG9mIE11bHRpcGxlIERlcHJpdmF0aW9uIChTSU1EKSBzY29yZXMsIHdpdGggYFExYCByZWZlcnJpbmcgdG8gdGhlIG1vc3QgZGVwcml2ZWQgZmlmdGggb2YgYXJlYXMuIA0KDQojIyBWaXN1YWxpc2luZw0KDQpUaGlzIGlzIG9uZSBwYXJ0IG9mIHRoZSBmaXJzdCBmaWd1cmUuIFRoZSBSIHBhY2thZ2UgYGdncGxvdDJgIGlzIHVzZWQgdG8gcHJvZHVjZSB0aGlzIHZpc3VhbGlzYXRpb24uDQoNCmBgYHtyLCBmaWcud2lkdGggPSAxMiwgZmlnLmhlaWdodCA9IDl9DQpwMSA8LSBkdGFfdGlkeSAlPiUgDQogIGdncGxvdChhZXMoeCA9IHllYXIgKSkgKw0KDQogIGZhY2V0X3dyYXAofnNleCkgKyANCiAgZ2VvbV9saW5lKGFlcyh5ID0gYXNtciwgZ3JvdXAgPSBTSU1ELCBsaW5ldHlwZSA9IFNJTUQsIHNpemUgPSBTSU1ELCBjb2xvciA9IFNJTUQpKSArIA0KICBzY2FsZV9zaXplX21hbnVhbCh2YWx1ZXMgPSBjKDEsIDEuMiwgMSwgMS4yLCAxLCAxLjQpKSArIA0KICBzY2FsZV9saW5ldHlwZV9tYW51YWwodmFsdWVzID0gYygyLDMsNCw1LCA2LCAxKSkgKyANCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoImJsYWNrIiwgImdyZXkiLCAiYmxhY2siLCAiZ3JleSIsICJibGFjayIsICJibHVlIikpICsgDQogIGxhYnMoeCA9ICJZZWFyIiwgeSA9ICJBZ2UgU3RhbmRhcmRpc2VkIG1vcnRhbGl0eSByYXRlIHBlciAxMDAgMDAwIikgKyANCiAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwgMCksIGxpbWl0cyA9IGMoMCwgMjUwMCksIG1pbm9yX2JyZWFrcyA9IHNlcSgwLCAyNTAwLCBieSA9IDEwMCkpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKG1pbm9yX2JyZWFrcyA9IDIwMDE6MjAxNykgKw0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAyMDEyLCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArIA0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAyMDA2LCBsaW5ldHlwZSA9ICJkYXNoZWQiKSArIA0KICBhbm5vdGF0ZSgidGV4dCIsIHkgPSAxMDAsIHggPSAyMDA2ICsgKDIwMTIgLSAyMDA2KSAvIDIsIGxhYmVsID0gIjIwMDYgdG8gMjAxMSIpICsgDQogIGFubm90YXRlKCJ0ZXh0IiwgeSA9IDEwMCwgeCA9IDIwMTIgKyAoMjAxOCAtIDIwMTIpIC8gMiwgbGFiZWwgPSAiMjAxMiB0byAyMDE3IikgKyANCiAgZ2VvbV9yaWJib24oDQogICAgYWVzKHggPSB5ZWFyLCB5bWluID0gcTUsIHltYXggPXExKSwgDQogICAgYWxwaGEgPSAwLjEsIGZpbGwgPSJyZWQiLA0KICAgIGRhdGEgPSBkdGFfdGlkeSAlPiUgZmlsdGVyKHNpbWQgJWluJSBjKCJxMSIsICJxNSIpKSAlPiUgc2VsZWN0KC1TSU1EKSAlPiUgc3ByZWFkKHNpbWQsIGFzbXIpDQogICAgDQogICkgKyANCiAgYmFja2dyb3VuZF9ncmlkKG1ham9yID0gInh5IiwgbWlub3IgPSAieHkiKQ0KDQoNCg0KcDENCiAgDQoNCg0KYGBgDQoNCiMjIEMxMFIyOiBIb3cgd2FzIHRoZSBwZXJjZW50YWdlIGNoYW5nZSBjYWxjdWxhdGVkPw0KIyMgQzZSMTogQWJzb2x1dGUgY2hhbmdlcyANCg0KVGhlIGZvbGxvd2luZyBjb2RlIGNodW5rIGNhbGN1bGF0ZXMgdGhlIHBlcmNlbnRhZ2UgY2hhbmdlLCBmcm9tIHRoZSBlYXJsaWVyIHRvIGxhdHRlciBwZXJpb2QsIGluIEFTTVIgYnkgc2V4IGFuZCBTSU1EIHF1aW50aWxlLiANCg0KQWxnZWJyYWljYWxseSB0aGlzIGNhbiBiZSBleHByZXNzZWQgYXMgZm9sbG93cw0KDQokJA0KQ19UID0gLTEwMCBcYmlnWzEgLSBcZnJhY3t5X1Ree2xhc3R9fXt5X1Ree2ZpcnN0fX1cYmlnXQ0KJCQNCg0KV2hlcmUgJENfVCQgcmVmZXJzIHRvIHRoZSBwZXJjZW50YWdlIGNoYW5nZSBvdmVyIGEgdGltZSBwZXJpb2QgJFQkLCAkeV9UXntsYXN0fSQgdG8gdGhlIG9ic2VydmVkIGFnZS1zdGFuZGFyZGlzZWQgbW9ydGFsaXR5IHJhdGUgKEFTTVIpIGluIHRoZSBsYXN0IHllYXIgd2l0aGluIHRoZSBwZXJpb2QgJFQkLCBhbmQgJHlfVF57Zmlyc3R9JCB0byB0aGUgQVNNUiBpbiB0aGUgZmlyc3QgeWVhciBpbiB0aGUgcGVyaW9kICRUJC4gV2l0aGluIHRoZSBhbmFseXNlcywgdHdvIGRpc3RpbmN0IHBlcmlvZHMgYXJlIGNvbnNpZGVyZWQ6IDIwMDYgdG8gMjAxMSBpbmNsdXNpdmUsIGFuZCAyMDEyIHRvIDIwMTcgaW5jbHVzaXZlLiANCg0KVGhpcyBjb2RlIGNodW5rIGhhcyBiZWVuIGFkYXB0ZWQgc28gYXMgdG8gYWxzbyBpbmNsdWRlIGNhbGN1YXRpb25zIG9mIGFic29sdXRlIGRpZmZlcmVuY2VzIChwZXIgMTAwLDAwMCBwb3B1bGF0aW9uKSBpbiB0aGUgZGVhdGggcmF0ZXMuDQoNCmBgYHtyfQ0KY2hhbmdlcyA8LSBkdGFfdGlkeSAlPiUgDQogIG11dGF0ZShwZXJpb2QgPSBjYXNlX3doZW4oDQogICAgYmV0d2Vlbih5ZWFyLCAyMDEyLCAyMDE3KSB+ICIyMDEyLTIwMTciLCANCiAgICBiZXR3ZWVuKHllYXIsIDIwMDYsIDIwMTEpIH4gIjIwMDYtMjAxMSIsDQogICAgVFJVRSB+IE5BX2NoYXJhY3Rlcl8pICU+JSBmYWN0b3IobGV2ZWxzID0gYygiMjAxMi0yMDE3IiwgIjIwMDYtMjAxMSIpKSkgJT4lIA0KICBncm91cF9ieShzZXgsIHNpbWQsIHBlcmlvZCkgJT4lIA0KICBmaWx0ZXIoeWVhciA9PSBtaW4oeWVhcikgfCB5ZWFyID09IG1heCh5ZWFyKSApICU+JSAjIFRoaXMgZmluZHMgdGhlIGZpcnN0IGFuZCBsYXN0IHllYXIgaW4gZWFjaCBwZXJpb2QNCiAgZmlsdGVyKCFpcy5uYShwZXJpb2QpKSAlPiUgDQogIGdyb3VwX2J5KHNleCwgU0lNRCwgcGVyaW9kKSAlPiUgDQogIHN1bW1hcmlzZSgNCiAgICBwZXJjZW50X2NoYW5nZSA9IC0gMTAwICogKDEgLSBhc21yW3llYXIgPT0gbWF4KHllYXIpXSAvIGFzbXJbeWVhciA9PSBtaW4oeWVhcildKSwNCiAgICBhYnNvbHV0ZV9jaGFuZ2UgPSBhc21yW3llYXIgPT0gbWF4KHllYXIpXSAtIGFzbXJbeWVhciA9PSBtaW4oeWVhcildDQogICAgKSAlPiUgDQogIHVuZ3JvdXAoKQ0KDQpgYGANCg0KDQoNCg0KTm90ZTogVGhlIGNvbnRlbnRzIG9mIGBjaGFuZ2VzYCBsb29rIGFzIGZvbGxvd3M6DQoNCmBgYHtyfQ0KY2hhbmdlcw0KDQpgYGANCg0KDQpGb3IgdGhlIGFsdGVybmF0aXZlIG1ldGhvZCwgcHJlc2VudGVkIGluIHRoZSBhcHBlbmRpeCwgdGhlIG1vZGVsIHByZWRpY3RlZCBBU01SIHZhbHVlcyAkXGhhdHtZfSQgYXJlIHVzZWQgaW4gcGxhY2Ugb2YgdGhlIG9ic2VydmVkIEFTTVIgdmFsdWVzICR5JCBpbiB0aGUgYWJvdmUuIFRoZXNlIHByZWRpY3RlZCB2YWx1ZXMgYXJlIHByb2R1Y2VkIGZvciBlYWNoIFNJTUQsIHBlcmlvZCwgYW5kIHNleCBjYXRlZ29yeSByZWdyZXNzZWQgb24geWVhciB3aXRoaW4gcGVyaW9kLiBUaGlzIGlzIHNob3duIGluIHRoZSBzZWN0aW9uICdhcHByb2FjaCBkaXNjdXNzZWQgaW4gc2Vuc2l0aXZpdHkgYW5hbHlzaXMnLiAgIA0KDQoNCg0KIyMgQWJzb2x1dGUgcmF0ZXMgKEM2UjEpDQoNClRoZSBmb2xsb3dpbmcgc2hvd3MgdGhlIGFic29sdXRlIGNoYW5nZXMgaW4gQVNNUiBncmFwaGljYWxseSANCg0KYGBge3IsIGZpZy5oZWlnaHQgPSA2LCBmaWcud2lkdGggPSA5fQ0KY2hhbmdlcyAlPiUgDQogIGdncGxvdChhZXMoeCA9IFNJTUQsIHkgPSBhYnNvbHV0ZV9jaGFuZ2UpKSArDQogIGdlb21fcG9pbnQoKSArIA0KICBmYWNldF9ncmlkKHBlcmlvZH5zZXgpICsgDQogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDApICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCkpICsgDQogIGxhYnMoeCA9ICJEZXByaXZhdGlvbiBxdWludGlsZSIsIHkgPSAiQWJzb2x1dGUgY2hhbmdlIGluIEFTTVIiLCB0aXRsZSA9ICJBYnNvbHV0ZSBjaGFuZ2UgaW4gQVNNUiBieSBzZXgsIHBlcmlvZCwgYW5kIFNJTUQgcXVpbnRpbGUiKQ0KDQpgYGANCg0KV2UgY2FuIHNlZSBmcm9tIHRoaXMgdGhhdCB0aGUgYWJzb2x1dGUgY2hhbmdlcyBzbG93ZWQgaW4gdGhlIGxhdHRlciBwZXJpb2QsIGFuZCBiZWNhbWUgcG9zaXRpdmUgKHdvcnNlIGluIGFic29sdXRlIHRlcm1zKSBpbiB0aGUgbW9zdCBkZXByaXZlZCBmaWZ0aCBvZiB0aGUgcG9wdWxhdGlvbi4NCg0KVGhlIGZvbGxvd2luZyBzaG93cyB0aGUgYWJvdmUgYXMgYSB0YWJsZQ0KDQpgYGB7cn0NCmNoYW5nZXMgJT4lIA0KICBzZWxlY3QoLXBlcmNlbnRfY2hhbmdlKSAlPiUgDQogIHNwcmVhZChTSU1ELCBhYnNvbHV0ZV9jaGFuZ2UpDQoNCmBgYA0KDQojIyBBbWVuZGVkIGZpZ3VyZSAoQzEyUjIsIEMyMFIzKQ0KDQpUd28gY29zbWV0aWMgYW1lbmRtZW50cyB0byBGaWd1cmUxYiBoYXZlIGJlZW4gcmVxdWVzdGVkLiBUaGUgZmlyc3QgaXMgdG8gYXZvaWQgb3ZlcmxhcHBpbmcgcG9pbnRzIGJldHdlZW4gcGVyaW9kczsgdGhlIHNlY29uZCBpcyB0byByZWxhYmVsIHRoZSB4YXhpcyBzbyB0aGUgbGFiZWxzIHJlYWQgJ21vc3QgZGVwcml2ZWQnIGFuZCAnbGVhc3QgZGVwcml2ZWQnIHJhdGhlciB0aGFuICdtb3N0JyBhbmQgJ2xlYXN0Jy4gDQoNClRoZSBmb2xsb3dpbmcgY29kZSBjaHVuayBwcm9kdWNlcyB0aGVzZSBmaWd1cmVzIHdpdGggdGhlc2UgYW1lbmRtZW50cyBtYWRlLg0KDQoNCmBgYHtyLCBmaWcud2lkdGggPSA5LCBmaWcuaGVpZ2h0ID0gNn0NCnAyIDwtIGNoYW5nZXMgJT4lDQogICAgc2VsZWN0KC1hYnNvbHV0ZV9jaGFuZ2UpICU+JSANCiAgICBtdXRhdGUoU0lNRCA9IGZhY3RvcihTSU1ELCANCiAgICAgICAgICAgICAgICAgICAgICAgbGV2ZWxzID0gYygiUS4xIChNb3N0IGRlcHJpdmVkKSIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJRLjIiLCAiUS4zIiwgIlEuNCIsICJRLjUgKExlYXN0IGRlcHJpdmVkKSIsICJPdmVyYWxsIiksDQogICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIk1vc3QgZGVwcml2ZWQiLCAiUTIiLCAiUTMiLCAiUTQiLCAiTGVhc3QgZGVwcml2ZWQiLCAiT3ZlcmFsbCIpDQogICAgICAgICAgICAgICAgICAgICAgICkNCiAgICAgICAgICkgJT4lIA0KICBmaWx0ZXIoU0lNRCAhPSAiT3ZlcmFsbCIpICU+JSANCiAgZ2dwbG90KGFlcyh4ID0gU0lNRCwgeSA9IHBlcmNlbnRfY2hhbmdlLCBncm91cCA9IHBlcmlvZCwgc2hhcGUgPSBwZXJpb2QsIGZpbGwgPSBwZXJpb2QsIGNvbG91ciA9IHBlcmlvZCkpICsgDQogIGZhY2V0X3dyYXAoIH4gc2V4KSArIA0KICBnZW9tX3BvaW50KHNpemUgPSA1KSArIA0KICBzdGF0X3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEYsIGNvbG91ciA9ICJibGFjayIpICsgIyBUaGlzIHByb2R1Y2VzIHRoZSBibHVlIGxpbmUgd2l0aCB0aGUgcmVncmVzc2lvbiBzbG9wZXMNCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCkgKyANCiAgZ2VvbV9obGluZSggIyBUaGlzIGFkZHMgdGhlIG92ZXJhbGwgcGVyY2VudCBjaGFuZ2UNCiAgICBhZXMoeWludGVyY2VwdCA9IHBlcmNlbnRfY2hhbmdlLCBncm91cCA9IHBlcmlvZCksDQogICAgZGF0YSA9IGNoYW5nZXMgJT4lIGZpbHRlcihTSU1EID09ICJPdmVyYWxsIiksDQogICAgbGluZXR5cGUgPSAiZGFzaGVkIg0KICApICsgDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTApKSArIA0KICBsYWJzKHkgPSAiUGVyY2VudCBjaGFuZ2UgaW4gQVNNUiBieSBwZXJpb2QiLCB4ID0gIlNJTUQgUXVpbnRpbGUiKSArDQogIHNjYWxlX3NoYXBlX21hbnVhbCgiUGVyaW9kIiwgdmFsdWVzID0gYygyLCAxNikpICsgICAgIyBUaGlzIGhhcyBiZWVuIGNoYW5nZWQgdG8gbWFrZSBvbmUgb2YgdGhlIHBvaW50cyBob2xsb3cNCiAgc2NhbGVfZmlsbF9tYW51YWwoIlBlcmlvZCIsIHZhbHVlcyA9IGMoImJsYWNrIiwgImdyZXkiKSkgKw0KICBzY2FsZV9jb2xvdXJfbWFudWFsKCJQZXJpb2QiLCB2YWx1ZXMgPSBjKCJibGFjayIsICJncmV5IikpDQpwMiANCg0KYGBgDQoNCkl0IGlzIG5vdyBjbGVhciB0aGF0IHRoZSBwb2ludHMgb3ZlcmxhcCBpbiB0aGUgbGVhc3QgZGVwcml2ZWQgcXVpdGlsZS4NCg0KDQoNCg0KIyBDb21iaW5lZCBmaWd1cmUgDQoNClRoZSBmb2xsb3dpbmcgcHJvZHVjZXMgdGhlIGNvbWJpbmVkIGZpZ3VyZSBjb21wcmlzaW5nIHRoZSB0d28gcGFydHMgc2hvd24gcHJldmlvdXNseS4gDQpUaGUgZmlndXJlIGlzIHJlbmRlcmVkIGFzIGEgcG5nIGZvcm1hdCBpbWFnZSBhdCAzMDBkcGksIGFuZCBwbGFjZWQgaW4gdGhlIGRpcmVjdG9yeSAnZmlndXJlcycuDQoNCmBgYHtyLCBmaWcuaGVpZ2h0ID0gMTIsIGZpZy53aWR0aCA9IDEyfQ0KcF9ib3RoIDwtIHBsb3RfZ3JpZChwMSwgcDIsIGxhYmVscyA9IGMoIkEiLCAiQiIpLCBuY29sID0gMSwgYWxpZ24gPSAidiIpDQoNCnBfYm90aA0KZ2dzYXZlKCJmaWd1cmVzL2NvbWJpbmVkX2ZpZ3VyZV8yMDEyLnBuZyIsIGRwaSA9IDMwMCwgdW5pdHMgPSAiY20iLCBoZWlnaHQgPSAzMCwgd2lkdGggPSAzMCkNCg0KYGBgDQoNCiMjIFRhYmxlIA0KDQpUaGUgZm9sbG93aW5nIHNob3dzIGhvdyB0aGUgY29udGVudHMgb2YgdGhlIHRhYmxlIHdlcmUgcHJvZHVjZWQuIA0KDQpUaGVzZSBzdW1tYXJpc2UgYSBzZXJpZXMgb2YgdW5pdmFyaWF0ZSBsaW5lYXIgcmVncmVzc2lvbnMgb2YgU0lNRCBxdWludGlsZSBhZ2FpbnN0IHByZWNlbnRhZ2UgY2hhbmdlIGluIEFTTVIgd2l0aGluIGRpc3RpbmN0IHBlcmlvZHMuIA0KDQpUaGUgY29sdW1ucyBgaW50ZXJjZXB0YCBhbmQgYGdyYWRpZW50YCBwcmVzZW50IHN1bW1hcnkgaW5mb3JtYXRpb24gYWJvdXQgcG9pbnQgZXN0aW1hdGVzIGFuZCA5NSUgY29uZmlkZW5jZSBpbnRlcnZhbHMgZm9yIHRoZSBpbnRlcmNlcHQgYW5kIGdyYWRpZW50IG9mIHRoZSB0aGUgcmVncmVzc2lvbnMsIHdoaWNoIGFyZSB0aGVuIHByZXNlbnRlZCBpbiB0aGUgZm9ybWF0dGVkIHRhYmxlLiANCg0KQSBmdW5jdGlvbmFsIHByb2dyYW1taW5nIGFwcHJvYWNoIHdhcyBhZG9wdGVkIGluIG9yZGVyIHRvIHByb2R1Y2UgdGhlIHNhbWUgYW5hbHlzZXMgY29uc2lzdGVudGx5IGZvciBkaWZmZXJlbnQgc2V4IGFuZCBwZXJpb2QgY29tYmluYXRpb25zLCB1c2luZyBmdW5jdGlvbnMgd2l0aGluIHRoZSAoYHB1cnJyYCBwYWNrYWdlKVtodHRwczovL3B1cnJyLnRpZHl2ZXJzZS5vcmcvLg0KDQoNCmBgYHtyfQ0KDQpnZXRfY2kgPC0gZnVuY3Rpb24oeCl7DQogIHRtcCA8LSB4ICU+JSBzdW1tYXJ5KCkgJT4lIGNvZWZmaWNpZW50cygpDQogIA0KICByZXR1cm4oDQogICAgbGlzdCgNCiAgICAgIGxvd2VyID0gdG1wWywxXSAtIDEuOTYgKiB0bXBbLDJdLA0KICAgICAgdXBwZXIgPSB0bXBbLDFdICsgMS45NiAqIHRtcFssMl0NCiAgICApDQogICkNCiAgDQp9DQoNCiMgTW9kZWwgcGFyYW1ldGVycyANCnRibF8xX3BjdCA8LSBjaGFuZ2VzICU+JSANCiAgZmlsdGVyKFNJTUQgIT0gIk92ZXJhbGwiKSAlPiUgDQogIG11dGF0ZShxbnQgPSB1bmNsYXNzKFNJTUQpIC0gMSkgJT4lICMgVGhpcyBpcyBzbyB0aGUgaW50ZXJjZXB0IHJlZmVycyB0byB0aGUgMXN0IHF1aW50aWxlIChub3QgdGhlICd6ZXJvdGgnIHF1aW50aWxlKQ0KICBzZWxlY3Qoc2V4LCBwZXJpb2QsIHBlcmNlbnRfY2hhbmdlLCBxbnQpICU+JSANCiAgZ3JvdXBfYnkoc2V4LCBwZXJpb2QpICU+JSANCiAgbmVzdCgpICU+JSANCiAgbXV0YXRlKG1kbCA9IG1hcChkYXRhLCB+bG0ocGVyY2VudF9jaGFuZ2UgfiBxbnQsIGRhdGEgPSAueCkpKSAlPiUgDQogIG11dGF0ZShgUi4gc3EuYCA9IG1hcF9kYmwobWRsLCB+c3VtbWFyeSgueClbInIuc3F1YXJlZCJdW1sxXV0pKSAlPiUgDQogIG11dGF0ZShncmFkaWVudCA9IG1hcF9kYmwobWRsLCB+Y29lZigueClbInFudCJdKSkgJT4lIA0KICBtdXRhdGUoaW50ZXJjZXB0ID0gbWFwX2RibChtZGwsIH5jb2VmKC54KVsiKEludGVyY2VwdCkiXSkpICU+JSANCiAgbXV0YXRlKGNpcyA9IG1hcChtZGwsIGdldF9jaSkpICU+JSANCiAgbXV0YXRlKA0KICAgIGludF9sb3dlciA9IG1hcF9kYmwoY2lzLCB+LltbImxvd2VyIl1dWzFdKSwNCiAgICBpbnRfdXBwZXIgPSBtYXBfZGJsKGNpcywgfi5bWyJ1cHBlciJdXVsxXSksDQogICAgZ3JkX2xvd2VyID0gbWFwX2RibChjaXMsIH4uW1sibG93ZXIiXV1bMl0pLA0KICAgIGdyZF91cHBlciA9IG1hcF9kYmwoY2lzLCB+LltbInVwcGVyIl1dWzJdKSAgICAgICAgICAgICAgICANCiAgKSAlPiUgDQogIHNlbGVjdChzZXgsIHBlcmlvZCwgYFIuIHNxLmAsIA0KICAgICAgICAgZ3JhZGllbnQsIGdyZF9sb3dlciwgZ3JkX3VwcGVyLCANCiAgICAgICAgIGludGVyY2VwdCwgaW50X2xvd2VyLCBpbnRfdXBwZXINCiAgKSAlPiUgDQogIG11dGF0ZSgNCiAgICBncmFkaWVudCA9IHBhc3RlMCgNCiAgICAgIGZvcm1hdChyb3VuZChncmFkaWVudCwgMiksIG5zbWFsbCA9IDIpLCANCiAgICAgICIgKCIsIA0KICAgICAgZm9ybWF0KHJvdW5kKGdyZF9sb3dlciwgMiksIG5zbWFsbCA9IDIpLCANCiAgICAgICIsICIsIA0KICAgICAgZm9ybWF0KHJvdW5kKGdyZF91cHBlciwgMiksIG5zbWFsbCA9IDIpLCANCiAgICAgICIpIg0KICAgICkNCiAgKSAlPiUgDQogIG11dGF0ZSgNCiAgICBpbnRlcmNlcHQgPSBwYXN0ZTAoDQogICAgICBmb3JtYXQocm91bmQoaW50ZXJjZXB0LCAyKSwgbnNtYWxsID0gMiksIA0KICAgICAgIiAoIiwgDQogICAgICBmb3JtYXQocm91bmQoaW50X2xvd2VyLCAyKSwgbnNtYWxsID0gMiksIA0KICAgICAgIiwgIiwgDQogICAgICBmb3JtYXQocm91bmQoaW50X3VwcGVyLCAyKSwgbnNtYWxsID0gMiksDQogICAgICAiKSINCiAgICApDQogICkgJT4lIA0KICBzZWxlY3QoLWdyZF9sb3dlciwgLWdyZF91cHBlciwgLWludF9sb3dlciwgLWludF91cHBlcikNCg0KdGJsXzFfcGN0DQoNCnRibF8yX3BjdCA8LSBjaGFuZ2VzICU+JSBzZWxlY3QoLWFic29sdXRlX2NoYW5nZSkgJT4lIHNwcmVhZChTSU1ELCBwZXJjZW50X2NoYW5nZSkNCg0KdGJsX2JvdGhfcGN0IDwtIGlubmVyX2pvaW4odGJsXzJfcGN0LCB0YmxfMV9wY3QpIA0KdGJsX2JvdGhfcGN0IA0KYGBgDQoNClRoZSBmb2xsb3dpbmcgY29udmVydHMgdGhlIGFib3ZlIHRhYmxlIGludG8gYSBtb3JlIG5lYXRseSBmb3JtYXR0ZWQgdGFibGUgdXNpbmcgdGhlIGBrYWJsZWAgYW5kIGBrYWJsZUV4dHJhYCBwYWNrYWdlcy4NCg0KDQpgYGB7ciwgd2FybmluZyA9IEYsIG1hcmt1cCA9ICdhc2lzJ30NCnRibF9ib3RoX3BjdCAlPiUgDQogIG11dGF0ZShwZXJpb2QgPSBmYWN0b3IocGVyaW9kLCBsZXZlbHMgPSBjKCIyMDA2LTIwMTEiLCAiMjAxMi0yMDE3IikpKSAgJT4lDQogIGFycmFuZ2Uoc2V4LCBwZXJpb2QpICU+JSANCiAga25pdHI6OmthYmxlKA0KICAgIGRpZ2l0cyA9IDIsIA0KICAgIGNhcHRpb24gPSAiUGVyY2VudCBjaGFuZ2UgaW4gQVNNUiBieSBzZXgsIFNJTUQgcXVpbnRpbGUsIGFuZCBwZXJpb2QiDQogICkgJT4lIA0KICBrYWJsZUV4dHJhOjprYWJsZV9zdHlsaW5nKCkgJT4lIA0KICBrYWJsZUV4dHJhOjphZGRfaGVhZGVyX2Fib3ZlKGMoIiAiLCIgIiwgIlBlcmNlbnRhZ2VzIiA9IDYsICJNb2RlbCByZXN1bHRzIiA9IDMpKSAlPiUgDQogIGthYmxlRXh0cmE6OmZvb3Rub3RlKCJPdmVyYWxsOiBXaG9sZSBvZiBTY290bGFuZC4gUi5TcS4gOiBSLVNxdWFyZWQgZm9yIG1vZGVsLiBHcmFkaWVudDogSW5jcmVhc2UgaW4gJSBjaGFuZ2UgcGVyIHVuaXQgaW5jcmVhc2UgaW4gcXVpbnRpbGUuIEludGVyY2VwdDogUHJlZGljdGVkICUgY2hhbmdlIGluIG1vc3QgZGVwcml2ZWQgcXVpbnRpbGUuIEZvciBncmFkaWVudCBhbmQgaW50ZXJjZXB0LCB2YWx1ZXMgaW4gcGFyZW50aGVzZXMgc2hvdyBsb3dlciBhbmQgdXBwZXIgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWxzIG9mIGNvZWZmaWNpZW50cyByZXNwZWN0aXZlbHkuIikNCg0KYGBgDQoNCg0KIyMgQWJzb2x1dGUgY2hhbmdlDQoNClRoZSBmb2xsb3dpbmcgdGFibGUgcHJlc2VudHMgYSBzaW1pbGFybHkgdW5mb3JtYXR0ZWQsIHRoZW4gZm9ybWF0dGVkLCB0YWJsZSBmb3IgdGhlIGFic29sdXRlIGNoYW5nZSBkaWZmZXJlbmNlcy4gDQoNCmBgYHtyfQ0KDQojIE1vZGVsIHBhcmFtZXRlcnMgDQp0YmxfMV9hYnMgPC0gY2hhbmdlcyAlPiUgDQogIGZpbHRlcihTSU1EICE9ICJPdmVyYWxsIikgJT4lIA0KICBtdXRhdGUocW50ID0gdW5jbGFzcyhTSU1EKSAtIDEpICU+JSAjIFRoaXMgaXMgc28gdGhlIGludGVyY2VwdCByZWZlcnMgdG8gdGhlIDFzdCBxdWludGlsZSAobm90IHRoZSAnemVyb3RoJyBxdWludGlsZSkNCiAgc2VsZWN0KHNleCwgcGVyaW9kLCBhYnNvbHV0ZV9jaGFuZ2UsIHFudCkgJT4lIA0KICBncm91cF9ieShzZXgsIHBlcmlvZCkgJT4lIA0KICBuZXN0KCkgJT4lIA0KICBtdXRhdGUobWRsID0gbWFwKGRhdGEsIH5sbShhYnNvbHV0ZV9jaGFuZ2UgfiBxbnQsIGRhdGEgPSAueCkpKSAlPiUgDQogIG11dGF0ZShgUi4gc3EuYCA9IG1hcF9kYmwobWRsLCB+c3VtbWFyeSgueClbInIuc3F1YXJlZCJdW1sxXV0pKSAlPiUgDQogIG11dGF0ZShncmFkaWVudCA9IG1hcF9kYmwobWRsLCB+Y29lZigueClbInFudCJdKSkgJT4lIA0KICBtdXRhdGUoaW50ZXJjZXB0ID0gbWFwX2RibChtZGwsIH5jb2VmKC54KVsiKEludGVyY2VwdCkiXSkpICU+JSANCiAgbXV0YXRlKGNpcyA9IG1hcChtZGwsIGdldF9jaSkpICU+JSANCiAgbXV0YXRlKA0KICAgIGludF9sb3dlciA9IG1hcF9kYmwoY2lzLCB+LltbImxvd2VyIl1dWzFdKSwNCiAgICBpbnRfdXBwZXIgPSBtYXBfZGJsKGNpcywgfi5bWyJ1cHBlciJdXVsxXSksDQogICAgZ3JkX2xvd2VyID0gbWFwX2RibChjaXMsIH4uW1sibG93ZXIiXV1bMl0pLA0KICAgIGdyZF91cHBlciA9IG1hcF9kYmwoY2lzLCB+LltbInVwcGVyIl1dWzJdKSAgICAgICAgICAgICAgICANCiAgKSAlPiUgDQogIHNlbGVjdChzZXgsIHBlcmlvZCwgYFIuIHNxLmAsIA0KICAgICAgICAgZ3JhZGllbnQsIGdyZF9sb3dlciwgZ3JkX3VwcGVyLCANCiAgICAgICAgIGludGVyY2VwdCwgaW50X2xvd2VyLCBpbnRfdXBwZXINCiAgKSAlPiUgDQogIG11dGF0ZSgNCiAgICBncmFkaWVudCA9IHBhc3RlMCgNCiAgICAgIGZvcm1hdChyb3VuZChncmFkaWVudCwgMiksIG5zbWFsbCA9IDIpLCANCiAgICAgICIgKCIsIA0KICAgICAgZm9ybWF0KHJvdW5kKGdyZF9sb3dlciwgMiksIG5zbWFsbCA9IDIpLCANCiAgICAgICIsICIsIA0KICAgICAgZm9ybWF0KHJvdW5kKGdyZF91cHBlciwgMiksIG5zbWFsbCA9IDIpLCANCiAgICAgICIpIg0KICAgICkNCiAgKSAlPiUgDQogIG11dGF0ZSgNCiAgICBpbnRlcmNlcHQgPSBwYXN0ZTAoDQogICAgICBmb3JtYXQocm91bmQoaW50ZXJjZXB0LCAyKSwgbnNtYWxsID0gMiksIA0KICAgICAgIiAoIiwgDQogICAgICBmb3JtYXQocm91bmQoaW50X2xvd2VyLCAyKSwgbnNtYWxsID0gMiksIA0KICAgICAgIiwgIiwgDQogICAgICBmb3JtYXQocm91bmQoaW50X3VwcGVyLCAyKSwgbnNtYWxsID0gMiksDQogICAgICAiKSINCiAgICApDQogICkgJT4lIA0KICBzZWxlY3QoLWdyZF9sb3dlciwgLWdyZF91cHBlciwgLWludF9sb3dlciwgLWludF91cHBlcikNCg0KdGJsXzFfYWJzDQoNCnRibF8yX2FicyA8LSBjaGFuZ2VzICU+JSBzZWxlY3QoLXBlcmNlbnRfY2hhbmdlKSAlPiUgc3ByZWFkKFNJTUQsIGFic29sdXRlX2NoYW5nZSkNCg0KdGJsX2JvdGhfYWJzIDwtIGlubmVyX2pvaW4odGJsXzJfYWJzLCB0YmxfMV9hYnMpIA0KdGJsX2JvdGhfYWJzIA0KDQpgYGANCg0KDQpBbmQgdGhlIGZvbGxvd2luZyBzaG93cyB0aGUgYWJvdmUgdGFibGUgZm9ybWF0dGVkIGFzIHByZXZpb3VzbHkNCg0KDQpgYGB7cn0NCnRibF9ib3RoX2FicyAlPiUgDQogIG11dGF0ZShwZXJpb2QgPSBmYWN0b3IocGVyaW9kLCBsZXZlbHMgPSBjKCIyMDA2LTIwMTEiLCAiMjAxMi0yMDE3IikpKSAgJT4lDQogIGFycmFuZ2Uoc2V4LCBwZXJpb2QpICU+JSANCiAga25pdHI6OmthYmxlKA0KICAgIGRpZ2l0cyA9IDIsIA0KICAgIGNhcHRpb24gPSAiQWJzb2x1dGUgY2hhbmdlIGluIEFTTVIgYnkgc2V4LCBTSU1EIHF1aW50aWxlLCBhbmQgcGVyaW9kIg0KICApICU+JSANCiAga2FibGVFeHRyYTo6a2FibGVfc3R5bGluZygpICU+JSANCiAga2FibGVFeHRyYTo6YWRkX2hlYWRlcl9hYm92ZShjKCIgIiwiICIsICJBYnNvbHV0ZSBEaWZmZXJlbmNlcyIgPSA2LCAiTW9kZWwgcmVzdWx0cyIgPSAzKSkgJT4lIA0KICBrYWJsZUV4dHJhOjpmb290bm90ZSgiT3ZlcmFsbDogV2hvbGUgb2YgU2NvdGxhbmQuIFIuU3EuIDogUi1TcXVhcmVkIGZvciBtb2RlbC4gR3JhZGllbnQ6IEluY3JlYXNlIGluIGFic29sdXRlIGNoYW5nZSBwZXIgdW5pdCBpbmNyZWFzZSBpbiBxdWludGlsZS4gSW50ZXJjZXB0OiBQcmVkaWN0ZWQgYWJzb2x1dGUgY2hhbmdlIGluIG1vc3QgZGVwcml2ZWQgcXVpbnRpbGUuIEZvciBncmFkaWVudCBhbmQgaW50ZXJjZXB0LCB2YWx1ZXMgaW4gcGFyZW50aGVzZXMgc2hvdyBsb3dlciBhbmQgdXBwZXIgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWxzIG9mIGNvZWZmaWNpZW50cyByZXNwZWN0aXZlbHkuIikNCg0KYGBgDQoNCiMjIFRhYmxlIHdpdGggYWJzb2x1dGUgYW5kIHJlbGF0aXZlIGNoYW5nZXMgY29tYmluZWQNCg0KDQpgYGB7cn0NCnRibF9ib3RoX3BjdCAlPiUNCiAgbXV0YXRlKHR5cGUgPSAicGN0IikgJT4lIA0KICBiaW5kX3Jvd3MoDQogICAgdGJsX2JvdGhfYWJzICU+JSBtdXRhdGUodHlwZSA9ICJhYnMiKSANCiAgKSAlPiUgDQogIG11dGF0ZShwZXJpb2QgPSBmYWN0b3IocGVyaW9kLCBsZXZlbHMgPSBjKCIyMDA2LTIwMTEiLCAiMjAxMi0yMDE3IikpKSAgJT4lDQogIG11dGF0ZSh0eXBlID0gZmFjdG9yKHR5cGUsIGxldmVscyA9IGMoInBjdCIsICJhYnMiKSkpICU+JSANCiAgYXJyYW5nZSh0eXBlLCBzZXgsIHBlcmlvZCkgJT4lIA0KICBzZWxlY3QoLXR5cGUpICU+JSANCiAga25pdHI6OmthYmxlKA0KICAgIGRpZ2l0cyA9IDIsIA0KICAgIGNhcHRpb24gPSAiQ2hhbmdlIGluIEFTTVJzIHBlciAxMDAsMDAwIHBvcHVsYXRpb24sIGJ5IHNleCwgU0lNRCBxdWludGlsZSBhbmQgcGVyaW9kIg0KICApICU+JSANCiAga2FibGVFeHRyYTo6a2FibGVfc3R5bGluZygpICU+JSANCiAga2FibGVFeHRyYTo6cGFja19yb3dzKCJQZXJjZW50YWdlIiwgMSw3KSAlPiUgDQogIGthYmxlRXh0cmE6OnBhY2tfcm93cygiQWJzb2x1dGUiLCA3LDEyKSAlPiUgDQogIGthYmxlRXh0cmE6OmFkZF9oZWFkZXJfYWJvdmUoYygiICIsIiAiLCAiRGlmZmVyZW5jZXMiID0gNiwgIk1vZGVsIHJlc3VsdHMiID0gMykpICU+JSANCiAga2FibGVFeHRyYTo6Zm9vdG5vdGUoIk92ZXJhbGw6IFdob2xlIG9mIFNjb3RsYW5kLiBSLlNxLiA6IFItU3F1YXJlZCBmb3IgbW9kZWwuIEdyYWRpZW50OiBJbmNyZWFzZSBpbiBjaGFuZ2UgcGVyIHVuaXQgaW5jcmVhc2UgaW4gcXVpbnRpbGUuIEludGVyY2VwdDogUHJlZGljdGVkIGNoYW5nZSBpbiBtb3N0IGRlcHJpdmVkIHF1aW50aWxlLiBGb3IgZ3JhZGllbnQgYW5kIGludGVyY2VwdCwgdmFsdWVzIGluIHBhcmVudGhlc2VzIHNob3cgbG93ZXIgYW5kIHVwcGVyIDk1JSBjb25maWRlbmNlIGludGVydmFscyBvZiBjb2VmZmljaWVudHMgcmVzcGVjdGl2ZWx5LiIpDQoNCg0KYGBgDQojIEFwcHJvYWNoIGRpc2N1c3NlZCBpbiBzZW5zaXRpdml0eSBhbmFseXNpcyAoQzJSMSwgQzEwUjIpDQoNClRoZSBzZW5zaXRpdml0eSBhbmFseXNpcyB0byB0aGUgcGFwZXIgc2hvd2VkIHRoZSBlZmZlY3Qgb2YgdXNpbmcgdGhlIGZpdHRlZCB2YWx1ZXMgZm9yIHRoZSBmaXJzdCBhbmQgbGFzdCB5ZWFyIGluIGVhY2ggb2YgdGhlIHBlcmlvZHMsIHJhdGhlciB0aGFuIHRoZSB2YWx1ZXMgdGhlbXNlbHZlcy4gVGhpcyBhcHByb2FjaCBjYW4gYWRkcmVzcyBhbnkgY29uY2VybiB0aGF0IHRoZSBmaXJzdCBhbmQgbGFzdCB5ZWFyIHdpdGhpbiBlaXRoZXIgcGVyaW9kIHdlcmUgaW4gYW55IHdheSBhbm9tYWxvdXMgb3IgdW5jaGFyYWN0ZXJpc3RpYyBvZiBjaGFuZ2Ugd2l0aGluIHRoZSBwZXJpb2QgYXMgYSB3aG9sZS4gDQoNClRoZSBmdW5jdGlvbiBgYnJvb206OmF1Z21lbnRgIHdhcyB1c2VkIHRvIGV4dHJhY3QgZml0dGVkIHZhbHVlcyBmb3IgZWFjaCB5ZWFyIHdpdGhpbiBlYWNoIHBlcmlvZCwgc2V4IGFuZCBTSU1EIGNvbWJpbmF0aW9uLiBUaGUgZml0dGVkIHZhbHVlcywgYC5maXR0ZWRgLCB3ZXJlIHRoZW4gdXNlZCBpbiBwbGFjZSBvZiB0aGUgb2JzZXJ2ZWQgdmFsdWVzLCBgYXNtcmAsIGFzIGluIHRoZSBtYWluIGFuYWx5c2VzLiAgDQoNCmBgYHtyfQ0KcGVyY2VudF9jaGFuZ2VzX3ByZWQgPC0gZHRhX3RpZHkgJT4lIA0KICAgIG11dGF0ZShwZXJpb2QgPSBjYXNlX3doZW4oDQogICAgICAgIGJldHdlZW4oeWVhciwgMjAxMiwgMjAxNykgfiAiMjAxMi0yMDE3IiwgDQogICAgICAgIGJldHdlZW4oeWVhciwgMjAwNiwgMjAxMSkgfiAiMjAwNi0yMDExIiwNCiAgICAgICAgVFJVRSB+IE5BX2NoYXJhY3Rlcl8pICU+JSBmYWN0b3IobGV2ZWxzID0gYygiMjAxMi0yMDE3IiwgIjIwMDYtMjAxMSIpKSkgJT4lIA0KICAgIGdyb3VwX2J5KHNleCwgU0lNRCwgc2ltZCwgcGVyaW9kKSAlPiUgDQogIG5lc3QoKSAlPiUgDQogIG11dGF0ZShtZGwgPSBtYXAoZGF0YSwgfmxtKGFzbXIgfiB5ZWFyLCBkYXRhID0gLngpKSkgJT4lIA0KICBtdXRhdGUoYXVnID0gbWFwKG1kbCwgYnJvb206OmF1Z21lbnQpKSAlPiUgDQogIHNlbGVjdCgtZGF0YSwgLW1kbCkgJT4lIA0KICB1bm5lc3QoKSAlPiUgDQogIGZpbHRlcighaXMubmEocGVyaW9kKSkgJT4lIA0KICBncm91cF9ieShzZXgsIFNJTUQsIHBlcmlvZCkgJT4lIA0KICBmaWx0ZXIoeWVhciA9PSBtaW4oeWVhcikgfCB5ZWFyID09IG1heCh5ZWFyKSApICU+JSANCiAgc3VtbWFyaXNlKHBlcmNlbnRfY2hhbmdlID0gLSAxMDAgKiAoMSAtIC5maXR0ZWRbeWVhciA9PSBtYXgoeWVhcildIC8gLmZpdHRlZFt5ZWFyID09IG1pbih5ZWFyKV0pKSAlPiUgDQogIHVuZ3JvdXAoKQ0KDQoNCmBgYA0KDQoNCmBgYHtyfQ0KcGVyY2VudF9jaGFuZ2VzX3ByZWRfb3ZlcmFsbCA8LSBwZXJjZW50X2NoYW5nZXNfcHJlZCAlPiUgDQogIGdyb3VwX2J5KHNleCwgcGVyaW9kKSAlPiUgDQogIHN1bW1hcmlzZShwZXJjZW50X2NoYW5nZSA9IG1lYW4ocGVyY2VudF9jaGFuZ2UpKSAlPiUgDQogIHVuZ3JvdXAoKSAlPiUgDQogIG11dGF0ZShTSU1EID0gIk1lYW4gb2YgcXVpbnRpbGVzIikgJT4lIA0KICBzZWxlY3Qoc2V4LCBTSU1ELCBwZXJpb2QsIHBlcmNlbnRfY2hhbmdlKQ0KICANCnBlcmNlbnRfY2hhbmdlc19wcmVkIDwtIHBlcmNlbnRfY2hhbmdlc19wcmVkICU+JSANCiAgYmluZF9yb3dzKHBlcmNlbnRfY2hhbmdlc19wcmVkX292ZXJhbGwpICU+JSANCiAgbXV0YXRlKFNJTUQgPSBmYWN0b3IoU0lNRCwgDQogICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIlEuMSAoTW9zdCBkZXByaXZlZCkiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUS4yIiwgIlEuMyIsICJRLjQiLCAiUS41IChMZWFzdCBkZXByaXZlZCkiLCAiT3ZlcmFsbCIsICJNZWFuIG9mIHF1aW50aWxlcyIpLA0KICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBjKCJNb3N0IGRlcHJpdmVkIiwgIlEyIiwgIlEzIiwgIlE0IiwgIkxlYXN0IGRlcHJpdmVkIiwgIk92ZXJhbGwiLCAiTWVhbiBvZiBxdWludGlsZXMiKQ0KICAgICAgICAgICAgICAgICAgICAgICApDQogICkgDQpgYGANCg0KVGhlIHN1YmZpZ3VyZSB1c2luZyB0aGlzIGFsdGVybmF0aXZlIHN0cmF0ZWd5IGlzIHRoZXJlZm9yZSBwcm9kdWNlZCBhcyBmb2xsb3dzOg0KDQpgYGB7ciwgZmlnLndpZHRoID0gOSwgZmlnLmhlaWdodCA9IDZ9DQpwMmEgPC0gcGVyY2VudF9jaGFuZ2VzX3ByZWQgJT4lIA0KICBmaWx0ZXIoIShTSU1EICVpbiUgYygiT3ZlcmFsbCIsICJNZWFuIG9mIHF1aW50aWxlcyIpKSkgJT4lIA0KICBnZ3Bsb3QoYWVzKHggPSBTSU1ELCB5ID0gcGVyY2VudF9jaGFuZ2UsIGdyb3VwID0gcGVyaW9kLCBzaGFwZSA9IHBlcmlvZCwgZmlsbCA9IHBlcmlvZCwgY29sb3VyID0gcGVyaW9kKSkgKyANCiAgZmFjZXRfd3JhcCggfiBzZXgpICsgDQogIGdlb21fcG9pbnQoc2l6ZSA9IDUpICsgDQogIHN0YXRfc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRiwgY29sb3VyID0gImJsYWNrIikgKyAjIFRoaXMgcHJvZHVjZXMgdGhlIGJsdWUgbGluZSB3aXRoIHRoZSByZWdyZXNzaW9uIHNsb3Blcw0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwKSArIA0KICBnZW9tX2hsaW5lKCAjIFRoaXMgYWRkcyB0aGUgb3ZlcmFsbCBwZXJjZW50IGNoYW5nZQ0KICAgIGFlcyh5aW50ZXJjZXB0ID0gcGVyY2VudF9jaGFuZ2UsIGdyb3VwID0gcGVyaW9kKSwNCiAgICBkYXRhID0gY2hhbmdlcyAlPiUgZmlsdGVyKFNJTUQgPT0gIk92ZXJhbGwiKSwNCiAgICBsaW5ldHlwZSA9ICJkYXNoZWQiDQogICkgKyANCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCkpICsgDQogIGxhYnMoeSA9ICJQZXJjZW50IGNoYW5nZSBpbiBBU01SIGJ5IHBlcmlvZCIsIHggPSAiU0lNRCBRdWludGlsZSIpICsNCiAgc2NhbGVfc2hhcGVfbWFudWFsKCJQZXJpb2QiLCB2YWx1ZXMgPSBjKDIsIDE2KSkgKyAgICAjIFRoaXMgaGFzIGJlZW4gY2hhbmdlZCB0byBtYWtlIG9uZSBvZiB0aGUgcG9pbnRzIGhvbGxvdw0KICBzY2FsZV9maWxsX21hbnVhbCgiUGVyaW9kIiwgdmFsdWVzID0gYygiYmxhY2siLCAiZ3JleSIpKSArDQogIHNjYWxlX2NvbG91cl9tYW51YWwoIlBlcmlvZCIsIHZhbHVlcyA9IGMoImJsYWNrIiwgImdyZXkiKSkNCiAgICANCnAyYQ0KDQpnZ3NhdmUoImZpZ3VyZXMvZmlnMWFfdXNpbmdfYWx0X21ldGhvZF8yMDEyLnBuZyIsIGRwaSA9IDMwMCwgdW5pdHMgPSAiY20iLCBoZWlnaHQgPSAxNiwgd2lkdGggPSAzMCkNCg0KYGBgDQoNClRoZSB0YWJsZSBvZiB0aGUgYWJvdmUsIHVzaW5nIHRoaXMgYWx0ZXJuYXRpdmUgbW9kZWxsaW5nIHN0cmF0ZWd5LCBpcyBwcm9kdWNlZCB1c2luZyB0aGUgY29kZSBjaHVua3MgYmVsb3cNCg0KYGBge3J9DQoNCmdldF9jaSA8LSBmdW5jdGlvbih4KXsNCiAgdG1wIDwtIHggJT4lIHN1bW1hcnkoKSAlPiUgY29lZmZpY2llbnRzKCkNCiAgDQogIHJldHVybigNCiAgICBsaXN0KA0KICAgICAgbG93ZXIgPSB0bXBbLDFdIC0gMS45NiAqIHRtcFssMl0sDQogICAgICB1cHBlciA9IHRtcFssMV0gKyAxLjk2ICogdG1wWywyXQ0KICAgICkNCiAgKQ0KICANCn0NCg0KIyBNb2RlbCBwYXJhbWV0ZXJzIA0KdGJsXzFhIDwtIHBlcmNlbnRfY2hhbmdlc19wcmVkICU+JSANCiAgZmlsdGVyKCEoU0lNRCAlaW4lIGMoIk92ZXJhbGwiLCAiTWVhbiBvZiBxdWludGlsZXMiKSkpICU+JSANCiAgbXV0YXRlKHFudCA9IHVuY2xhc3MoU0lNRCkgLSAxKSAlPiUgIyBUaGlzIGlzIHNvIHRoZSBpbnRlcmNlcHQgcmVmZXJzIHRvIHRoZSAxc3QgcXVpbnRpbGUgKG5vdCB0aGUgJ3plcm90aCcgcXVpbnRpbGUpDQogIHNlbGVjdChzZXgsIHBlcmlvZCwgcGVyY2VudF9jaGFuZ2UsIHFudCkgJT4lIA0KICBncm91cF9ieShzZXgsIHBlcmlvZCkgJT4lIA0KICBuZXN0KCkgJT4lIA0KICBtdXRhdGUobWRsID0gbWFwKGRhdGEsIH5sbShwZXJjZW50X2NoYW5nZSB+IHFudCwgZGF0YSA9IC54KSkpICU+JSANCiAgbXV0YXRlKGBSLiBzcS5gID0gbWFwX2RibChtZGwsIH5zdW1tYXJ5KC54KVsici5zcXVhcmVkIl1bWzFdXSkpICU+JSANCiAgbXV0YXRlKGdyYWRpZW50ID0gbWFwX2RibChtZGwsIH5jb2VmKC54KVsicW50Il0pKSAlPiUgDQogIG11dGF0ZShpbnRlcmNlcHQgPSBtYXBfZGJsKG1kbCwgfmNvZWYoLngpWyIoSW50ZXJjZXB0KSJdKSkgJT4lIA0KICBtdXRhdGUoY2lzID0gbWFwKG1kbCwgZ2V0X2NpKSkgJT4lIA0KICBtdXRhdGUoDQogICAgaW50X2xvd2VyID0gbWFwX2RibChjaXMsIH4uW1sibG93ZXIiXV1bMV0pLA0KICAgIGludF91cHBlciA9IG1hcF9kYmwoY2lzLCB+LltbInVwcGVyIl1dWzFdKSwNCiAgICBncmRfbG93ZXIgPSBtYXBfZGJsKGNpcywgfi5bWyJsb3dlciJdXVsyXSksDQogICAgZ3JkX3VwcGVyID0gbWFwX2RibChjaXMsIH4uW1sidXBwZXIiXV1bMl0pICAgICAgICAgICAgICAgIA0KICApICU+JSANCiAgc2VsZWN0KHNleCwgcGVyaW9kLCBgUi4gc3EuYCwgDQogICAgICAgICBncmFkaWVudCwgZ3JkX2xvd2VyLCBncmRfdXBwZXIsIA0KICAgICAgICAgaW50ZXJjZXB0LCBpbnRfbG93ZXIsIGludF91cHBlcg0KICApICU+JSANCiAgbXV0YXRlKA0KICAgIGdyYWRpZW50ID0gcGFzdGUwKA0KICAgICAgZm9ybWF0KHJvdW5kKGdyYWRpZW50LCAyKSwgbnNtYWxsID0gMiksIA0KICAgICAgIiAoIiwgDQogICAgICBmb3JtYXQocm91bmQoZ3JkX2xvd2VyLCAyKSwgbnNtYWxsID0gMiksIA0KICAgICAgIiwgIiwgDQogICAgICBmb3JtYXQocm91bmQoZ3JkX3VwcGVyLCAyKSwgbnNtYWxsID0gMiksIA0KICAgICAgIikiDQogICAgKQ0KICApICU+JSANCiAgbXV0YXRlKA0KICAgIGludGVyY2VwdCA9IHBhc3RlMCgNCiAgICAgIGZvcm1hdChyb3VuZChpbnRlcmNlcHQsIDIpLCBuc21hbGwgPSAyKSwgDQogICAgICAiICgiLCANCiAgICAgIGZvcm1hdChyb3VuZChpbnRfbG93ZXIsIDIpLCBuc21hbGwgPSAyKSwgDQogICAgICAiLCAiLCANCiAgICAgIGZvcm1hdChyb3VuZChpbnRfdXBwZXIsIDIpLCBuc21hbGwgPSAyKSwNCiAgICAgICIpIg0KICAgICkNCiAgKSAlPiUgDQogIHNlbGVjdCgtZ3JkX2xvd2VyLCAtZ3JkX3VwcGVyLCAtaW50X2xvd2VyLCAtaW50X3VwcGVyKQ0KDQp0YmxfMWENCg0KdGJsXzJhIDwtIHBlcmNlbnRfY2hhbmdlc19wcmVkICU+JSBmaWx0ZXIoU0lNRCAhPSAiTWVhbiBvZiBxdWludGlsZXMiKSAlPiUgc3ByZWFkKFNJTUQsIHBlcmNlbnRfY2hhbmdlKQ0KDQp0YmxfYm90aF9hIDwtIGlubmVyX2pvaW4odGJsXzJhLCB0YmxfMWEpIA0KdGJsX2JvdGhfYQ0KYGBgDQoNCkFuZCB0aGUgdGFibGUgdXNpbmcgdGhlIGFsdGVybmF0aXZlIGFwcHJvYWNoDQoNCmBgYHtyLCB3YXJuaW5nID0gRiwgbWFya3VwID0gJ2FzaXMnfQ0KdGJsX2JvdGhfYSAlPiUNCiAgZ2F0aGVyKGBNb3N0IGRlcHJpdmVkYDpgT3ZlcmFsbGAsIGtleSA9ICJTSU1EIiwgdmFsdWUgPSAidmFsdWUiKSAlPiUgDQogICAgbXV0YXRlKFNJTUQgPSBmYWN0b3IoU0lNRCwgDQogICAgICAgICAgICAgICAgICAgICAgIGxldmVscyA9IGMoIk1vc3QgZGVwcml2ZWQiLCAiUTIiLCAiUTMiLCAiUTQiLCAiTGVhc3QgZGVwcml2ZWQiLCJPdmVyYWxsIiksDQogICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIlEuMSAoTW9zdCBkZXByaXZlZCkiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUS4yIiwgIlEuMyIsICJRLjQiLCAiUS41IChMZWFzdCBkZXByaXZlZCkiLCAiT3ZlcmFsbCIpDQogICAgICAgICAgICAgICAgICAgICAgICkNCiAgICAgICAgICkgJT4lIA0KICBtdXRhdGUocGVyaW9kID0gZmFjdG9yKHBlcmlvZCwgbGV2ZWxzID0gYygiMjAwNi0yMDExIiwgIjIwMTItMjAxNyIpKSkgICU+JQ0KICBzcHJlYWQoa2V5ID0gU0lNRCwgdmFsdWUgPSB2YWx1ZSkgJT4lIA0KICBzZWxlY3Qoc2V4LCBwZXJpb2QsIGBRLjEgKE1vc3QgZGVwcml2ZWQpYDpgT3ZlcmFsbGAsIGV2ZXJ5dGhpbmcoKSkgJT4lIA0KICBhcnJhbmdlKHNleCwgcGVyaW9kKSAlPiUgDQogIGtuaXRyOjprYWJsZSgNCiAgICBkaWdpdHMgPSAyLCANCiAgICBjYXB0aW9uID0gIlBlcmNlbnQgY2hhbmdlIGluIEFTTVIgYnkgc2V4LCBTSU1EIHF1aW50aWxlLCBhbmQgcGVyaW9kLiAoQWx0ZXJuYXRpdmUgbWV0aG9kKSINCiAgKSAlPiUgDQogIGthYmxlRXh0cmE6OmthYmxlX3N0eWxpbmcoKSAlPiUgDQogIGthYmxlRXh0cmE6OmFkZF9oZWFkZXJfYWJvdmUoYygiICIsIiAiLCAiUGVyY2VudGFnZXMiID0gNiwgIk1vZGVsIHJlc3VsdHMiID0gMykpICU+JSANCiAga2FibGVFeHRyYTo6Zm9vdG5vdGUoIk92ZXJhbGw6IFdob2xlIG9mIFNjb3RsYW5kLiBSLlNxLiA6IFItU3F1YXJlZCBmb3IgbW9kZWwuIEdyYWRpZW50OiBJbmNyZWFzZSBpbiAlIGNoYW5nZSBwZXIgdW5pdCBpbmNyZWFzZSBpbiBxdWludGlsZS4gSW50ZXJjZXB0OiBQcmVkaWN0ZWQgJSBjaGFuZ2UgaW4gbW9zdCBkZXByaXZlZCBxdWludGlsZS4gRm9yIGdyYWRpZW50IGFuZCBpbnRlcmNlcHQsIHZhbHVlcyBpbiBwYXJlbnRoZXNlcyBzaG93IGxvd2VyIGFuZCB1cHBlciA5NSUgY29uZmlkZW5jZSBpbnRlcnZhbHMgb2YgY29lZmZpY2llbnRzIHJlc3BlY3RpdmVseS4iKQ0KDQoNCmBgYA0KDQoNCg0KIyBEaXNjdXNzaW9uDQoNClRoaXMgZG9jdW1lbnQgaGFzIHByb3ZpZGVkIGRlc2NyaXB0aW9ucyBvZiB0aGUgZGF0YSB1c2VkLCB0aGUgcHJvY2Vzc2luZyBwZXJmb3JtZWQgb24gdGhlIGRhdGEsIGFuZCB0aGUgY29kZSB1c2VkIHRvIHBlcmZvcm0gYWxsIGFuYWx5c2VzLCB2aXN1YWxpc2F0aW9ucywgYW5kIHRhYnVsYXRpb25zLiBPdXIgaG9wZSBpcyB0aGlzIGFkZHJlc3NlcyBhbnkgbWV0aG9kb2xvZ2ljYWwgY29uY2VybnMgZnJvbSB2aWV3ZXJzIGFuZCByZXZpZXdlcnMsIGFuZCB3aWxsIG1ha2UgaXQgbXVjaCBtb3JlIHN0cmFpZ2h0Zm9yd2FyZCBmb3IgYW55b25lIHdobyB3YW50cyB0byByZXBsaWNhdGUgYW5kIGFkdmFuY2Ugb24gb3VyIGFuYWx5c2VzIHRvIGRvIHNvLiANCg0KDQojIFJlcXVlc3RzIGZyb20gcmV2aWV3ZXJzDQoNClRoaXMgc2VjdGlvbiB3aWxsIGluY2x1ZGUgYWRkaXRpb25hbCBhbmFseXNlcyBwZXJmb3JtZWQgYXMgYSByZXN1bHQgb2YgcmV2aWV3ZXIgY29tbWVudHMuIA0KDQojIyBDNyBSMSAtIE9ic2VydmVkIHZzIHByZWRpY3RlZCB2YWx1ZXMgDQoNClRoZSByZXZpZXdlciBjb21tZW50IHdhczogDQoNCiAgICBSLXNxdWFyZWQgaXMgYSBwb29yIG1lYXN1cmUgaW4gYW5kIG9mIGl0c2VsZiBvZiBtb2RlbCBmaXQgLSBwYXJ0aWN1bGFybHkgZ2l2ZW4gdGhlIHNtYWxsIG51bWJlciBvZiBvYnNlcnZhdGlvbnMgaW4gdGhlIG1vZGVsLiBPbmUgbWF5IGNvbnNpZGVyIHJlcG9ydGluZyBvYnNlcnZlZCB2cyBwcmVkaWN0ZWQgY2hhbmdlcyB0byB1bmRlcnN0YW5kIGhvdyB3ZWxsIHRoZSBtb2RlbCBpcyBmaXR0aW5nLiBGdXJ0aGVybW9yZSwgZGlyZWN0bHkgaW5jbHVkaW5nIHRoZSBhZ2Ugc3RydWN0dXJlIHdvdWxkIHNpZ25pZmljYW50bHkgaW1wcm92ZSBtb2RlbCBmaXQuDQoNClRoZSBwcmVkaWN0ZWQgdnMgb2JzZXJ2ZWQgdmFsdWVzIGFyZSBzaG93biBhcyBmb2xsb3dzOg0KDQpgYGB7ciwgZmlnLndpZHRoID0gOCwgZmlnLmhlaWdodCA9IDh9DQpjaGFuZ2VzICU+JSANCiAgZmlsdGVyKFNJTUQgIT0gIk92ZXJhbGwiKSAlPiUgDQogIG11dGF0ZShxbnQgPSB1bmNsYXNzKFNJTUQpIC0gMSkgJT4lICMgVGhpcyBpcyBzbyB0aGUgaW50ZXJjZXB0IHJlZmVycyB0byB0aGUgMXN0IHF1aW50aWxlIChub3QgdGhlICd6ZXJvdGgnIHF1aW50aWxlKQ0KICBzZWxlY3Qoc2V4LCBwZXJpb2QsIHBlcmNlbnRfY2hhbmdlLCBxbnQpICU+JSANCiAgZ3JvdXBfYnkoc2V4LCBwZXJpb2QpICU+JSANCiAgbmVzdCgpICU+JSANCiAgbXV0YXRlKG1kbCA9IG1hcChkYXRhLCB+bG0ocGVyY2VudF9jaGFuZ2UgfiBxbnQsIGRhdGEgPSAueCkpKSAlPiUgDQogIG11dGF0ZShkdGFfYXVnbWVudGVkID0gbWFwMihtZGwsIGRhdGEsIGJyb29tOjphdWdtZW50KSkgJT4lIA0KICBzZWxlY3QoLWRhdGEsIC1tZGwpICU+JSANCiAgdW5uZXN0KCkgJT4lIA0KICBnZ3Bsb3QoYWVzKHggPSBwZXJjZW50X2NoYW5nZSwgeSA9IC5maXR0ZWQsIGxhYmVsID0gcW50ICsgMSkpICsgDQogIGdlb21fdGV4dCgpICsgDQogIGZhY2V0X2dyaWQoc2V4IH4gcGVyaW9kKSArIA0KICBzdGF0X3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEYpICsgDQogIGxhYnMoDQogICAgeCA9ICJPYnNlcnZlZCBwZXJjZW50YWdlIiwNCiAgICB5ID0gIkZpdHRlZCBwZXJjZW50YWdlIiwNCiAgICB0aXRsZSA9ICJSZWxhdGlvbnNoaXBzIGJldHdlZW4gb2JzZXJ2ZWQgYW5kIGZpdHRlZCBwZXJjZW50YWdlcyBieSBzZXggYW5kIHBlcmlvZCIsDQogICAgc3VidGl0bGUgPSAiVmFsdWVzIHJlZmVyIHRvIFNJTUQgcXVpbnRpbGVzICgxOiBtb3N0IGRlcHJpdmVkKSINCiAgICANCiAgKQ0KDQpgYGANCg0KVGhpcyBzdXBwb3J0cyB0aGUgb2JzZXJ2YXRpb24gdGhhdCB0aGUgcmVsYXRpb25zaGlwIGhhcyBiZWNvbWUgbW9yZSBsaW5lYXIgb3ZlciB0aW1lLCBhcyBhbHNvIGlsbHVzdHJhdGVkIGJ5IHRoZSBjaGFuZ2luZyAkUl57Mn0kIHZhbHVlcyBiZXR3ZWVuIHRoZSB0d28gcGVyaW9kcy4gDQoNCg==