1 Objective

Run ED using different climate to create an ensemble of runs

  • How does that impact ED results?
  • What impact does it make on dimensions of stability?
  • Is there a relationship between the inputs & metrics?
  • How do we want to calculate recovery?
    • When it reaches the control? When it reaches a steady state?

2 Compare Inputs

# Import the meterolical inputs. 
RESULTS_DIR <- file.path(BASE_DIR, "ED-outputs", "met_results")
# Create a data frame of all the meterolgical data used. 
list.files(RESULTS_DIR, pattern = 'yr', full.names = TRUE) %>%  
  lapply(function(x){
    
    name <- gsub(x = basename(x), pattern = '_yr.csv', replacement = '')
    data <- read.csv(x, stringsAsFactors = FALSE)
    data$scn <- name
    return(data)
    
  }) %>%  
  dplyr::bind_rows() %>%  
  as.data.table -> 
  data
# A mapping file of variable names, description, and units. 
# This will be used to add more information to the met data data frame. 
var_info <- data.table(variable = c('dlwrf', 'nbdsf', 'nddsf', 'vbdsf',
                                    'vddsf', 'prate', 'pres', 'hgt', 
                                    'ugrd', 'vgrd', 'sh', 'tmp'), 
                       description = c('downward long wave radiation', 
                                       'near infrared beam downward solar radiation', 
                                       'near IR diffuse downward solar radiation', 
                                       'visible beam downward solar radiation',
                                       'visible diffuse downward solar radiation', 
                                       'precipitation rate', 
                                       'atmospheric pressure', 
                                       'geopotential height', 
                                       'zonal wind',
                                       'meridional wind', 
                                       'specific humidity',
                                       'air temperature'),  
                       units = c('W m-2', 'W m-2', 'W m-2', 'W m-2',
                                 'W m-2', 'kgH2O m-2 s-1', 'Pa', 'm',
                                 'm s-1', 'm s-', 'kgH2O kgAir-1', 'K'), stringsAsFactors=FALSE)
data <- data[var_info, on = 'variable']
data <- na.omit(data)
data$label <- paste0(data$description, ' (', data$units, ')')
# Define function that generates the standard met input plot 
# Args 
#   data: data table of the met data to plot
#   yr1: the first year of met data to plot, default set to 1950
#   yr2: the final year of met data to plot, default set to 2030 
# Return: a faceted line plot of the met data, ggplot2 object
met_plot <- function(d, yr1 = 1950, yr2 = 2040){
  
  # Color the background 
  ALPHA <- 0.05
  BCK_GRND1 <- '#dcffcc'
  BCK_GRND2 <- '#9fdfcd'
  BCK_GRND3 <- '#baabda'
  
  d[year >= yr1 & year <= yr2] %>%  
    ggplot() + 
    geom_rect(aes(xmin=yr1, xmax = 1979,
                  ymin = -Inf, ymax = Inf), fill = BCK_GRND1, alpha = ALPHA) +
    geom_rect(aes(xmin=1979, xmax = 2010,
                  ymin = -Inf, ymax = Inf), fill = BCK_GRND2, alpha = ALPHA) +
    geom_rect(aes(xmin=2010, xmax = yr2,
                  ymin = -Inf, ymax = Inf), fill = BCK_GRND3, alpha = ALPHA) + 
    labs(caption = 'colored background: looped over obs., obs., 5 year obs. mean ') + 
    geom_line(aes(year, value, linetype = scn)) + 
    facet_wrap('label', scales = 'free', strip.position = "top",
             labeller = label_wrap_gen(width = 20, multi_line = TRUE)) + 
    THEME + 
    labs(y = NULL, x = 'Year', title = 'Annual Mean Meteorological Inputs') + 
    theme(legend.position = 'none') -> 
    plot 
  
  return(plot)
}
# Split the met data up into two different plots, this will make the plots easier to  look at. 
var_list <- unique(data$variable)
pannels_n1 <- ceiling(length(var_list)/2)

Up until 2010 the runs use the same meteorology inputs, starting in 2010, about a decade before the disturbance we start to use different meteorology inputs based on 5 year means sampled from the observational data set.

2.1 Plot Climate Input

# Plot the first half of the met input values 
met_plot(data[variable %in% var_list[1:pannels_n1]])

# Plot the second half of the met input values 
met_plot(data[variable %in% var_list[pannels_n1+1:length(var_list)]])

The inputs for the two different met records starting in 2010, so that that ED has a steady climate for the ~10 yrs before the disturbance, the met ensemble captures a wide range of different climates.

3 ED Results

annual_data <- as.data.table(read.csv(file.path(BASE_DIR, "ED-outputs", "results",
                                                "exp-1-yr.csv"), stringsAsFactors = FALSE))

3.1 Plot Baseline/Control

annual_data$label <- paste0(annual_data$description, " (", annual_data$unit, ")")
annual_data[scn == 'harvest_0_1day_above', ] %>%  
  .[ , severity := '0'] %>% 
  ggplot() + 
      geom_rect(aes(xmin=1900, xmax = 1979,
                  ymin = -Inf, ymax = Inf), fill = BCK_GRND1, alpha = ALPHA) +
    geom_rect(aes(xmin=1979, xmax = 2010,
                  ymin = -Inf, ymax = Inf), fill = BCK_GRND2, alpha = ALPHA) +
    geom_rect(aes(xmin=2010, xmax = 2048,
                  ymin = -Inf, ymax = Inf), fill = BCK_GRND3, alpha = ALPHA) + 
    geom_vline(xintercept = 2019, color = 'black') + 
  geom_line(aes(year, value, linetype = met)) + 
 facet_wrap('label', scales = 'free',  
            labeller = label_wrap_gen(width = 50, multi_line = TRUE)) + 
  THEME + 
  theme(legend.position = 'none')+
  labs(title = 'Disturbance Severity 0%', 
       y = NULL, 
       x = "Year", 
       caption = 'vertical line at 2019, when the FoRTE treatment is applied\ncolored background: looped over obs., obs., 5 year obs. mean ') 

Yes changing the meteorology input files does make a difference in the baseline scenarios, as we can tell based on the vertical line by the time the FoRTE treatment is applied the ED forest stands diverged from one another.

4 Disturbance

What is the difference between the different treatments and the control (0%) runs?

baseline <- annual_data[scn == 'harvest_0_1day_above', ][ , .(year, variable, description, unit, met, baseline = value)]
disturbance <- annual_data[scn != 'harvest_0_1day_above', ]
setnames(x = disturbance, old = "value", new = "disturbance", skip_absent = TRUE)
dt <- baseline[disturbance, on = c( "year", "variable", "description", "unit", "met")]
dt[ , value := disturbance - baseline]
dt[ , severity := gsub(pattern = "harvest_|_1day_above", replacement = "", x = scn)]

4.1 Plot Disturbance

dt$`Disturbance Severity` <- paste0(dt$severity, ' %')
dt[year >= 2015, ] %>% 
  ggplot(aes(year, value, color = `Disturbance Severity`, linetype = met)) + 
  geom_vline(xintercept = 2019, color = 'black') + 
  geom_line() + 
   facet_wrap('label', scales = 'free',  
            labeller = label_wrap_gen(width = 30, multi_line = TRUE)) + 
  THEME + 
  labs(y = 'Disturbance - Baseline', 
       x = 'Year', 
       caption = 'vertical line 2019 disturbance event')  + 
  scale_color_manual(values = FORTE_SEVERITY_COLORS) + 
  guides(linetype = FALSE)

The over shoot in the met2 track for the carbon fluxes is really interesting! Do we think that would happen if the met1 run continued longer?

5 Dimensions of Stability

# Find the recovery at specific time places. 
# Args 
#   d: a data frame of the annual ED outputs
#   x: a vectory of the years to calculate the recovery at. 
# Return: a data frame of the recovery values
recovery_at_X <- function(d, x){
  
# Check inputs 
req_names <- c('scn', 'year', 'variable', 'description', 'unit', 'value', 'met')
assert_that(has_name(d, req_names))
baseline_scn <- "harvest_0_1day_above" 
assert_that(baseline_scn %in% d$scn)
assert_that(all(x %in% d$year))
# Separate the control or baseline scneario values from the output from the other 
# treatment groups. 
baseline_values <- d[scn == baseline_scn][ , c("year", "variable", "value", "met")]
names(baseline_values) <- c("year", "variable", "baseline", "met")
treatment_values <- d[scn != baseline_scn][ , c("scn", "year", "variable", "description", 
                                                "unit", "treatment" = "value", "met", "label")]
names(treatment_values) <- c("scn", "year", "variable", "description", 
                                                "unit", "treatment", "met", "label")
# Combine the control and the treatment values as a wide df, then take the # ln(treatment/control) per year / variable / met realization. 
disturbance_d <- treatment_values[baseline_values, on = c("year", "variable", "met")][year %in% 2019:2050]
disturbance_d[ , value := log(treatment/baseline)]
# Now that the ln(treatment/control) has been calculated we can use these values to calculate
# the various dimensions of ecosystem stability. 
recovery_d <- disturbance_d[year %in% x]
recovery_d <- recovery_d[ , c("scn", "year", "variable", "description", 
                              "unit", "met",  "value")]
names(recovery_d) <- c("scn", "year", "variable", "description", 
                       "unit", "met",  "recovery")
dt <- recovery_d
# Add the disturbance severity column. 
dt$`Disturbance Severity` <- paste0(gsub(x = dt$scn,
                                         pattern = "harvest_|_1day_above", 
                                         replacement = ""), " %")
# Format and apply factor information to the variable name so the dimensions of stability plot 
# step through the carbon cycle in order GPP -> NPP -> NEP. 
dt$variable <- gsub(pattern = "_patch", replacement = "", x = dt$variable)
dt$variable <- factor(x = dt$variable, levels = c("GPP", "NPP", "NEP"), ordered = TRUE)
dt <- na.omit(dt)
return(dt)
}
recovery_at_X_data <- recovery_at_X(annual_data, c(2025, 2030, 2035, 2040, 2045))
# Calculate the various dimensiosn of stability 
# Args
#   d: data table of the annual ED results 
# Return: data table of the dimensions of stability. 
calculate_dimensions_stability <- function(d){
  
# Check inputs 
req_names <- c('scn', 'year', 'variable', 'description', 'unit', 'value', 'met')
assert_that(has_name(d, req_names))
baseline_scn <- "harvest_0_1day_above" 
assert_that(baseline_scn %in% d$scn)
# Separate the control or baseline scneario values from the output from the other 
# treatment groups. 
baseline_values <- d[scn == baseline_scn][ , c("year", "variable", "value", "met")]
names(baseline_values) <- c("year", "variable", "baseline", "met")
treatment_values <- d[scn != baseline_scn][ , c("scn", "year", "variable", "description", 
                                                "unit", "treatment" = "value", "met", "label")]
names(treatment_values) <- c("scn", "year", "variable", "description", 
                                                "unit", "treatment", "met", "label")
# Combine the control and the treatment values as a wide df, then take the # ln(treatment/control) per year / variable / met realization. 
disturbance_d <- treatment_values[baseline_values, on = c("year", "variable", "met")][year %in% 2019:2050]
disturbance_d[ , value := log(treatment/baseline)]
# Now that the ln(treatment/control) has been calculated we can use these values to calculate
# the various dimensions of ecosystem stability. 
treatment_yr <- 2019 # The year of the girdel 
# Resistance: ${r}_{t} = ln(\frac{{F}_{disturbance}}{{F}_{control}})$ at the year year 
# of disturabnce (2019). 
resitance_d <- disturbance_d[year == treatment_yr][ , c("scn", "variable",
                                                        "description", "unit", "met",  "value")]
names(resitance_d) <- c("scn", "variable", "description", "unit", "met",  "resitance")
# Resilience : ${r}_{i} = ln(\frac{{F}_{disturbance}}{{F}_{control}}) = i + {r}_{i} * t$
# Calculate the resilience (the slope of the recovery starting at the treatment_yr)
d_to_use <- disturbance_d[year >= 2019 & year <= 2030] # Do not include data from pre treatment years. 
# Get the result from the linear regression per variable / scn / met ensemble member. 
d_list <- split(d_to_use, interaction(d_to_use$variable, d_to_use$scn, d_to_use$met), 
                drop = TRUE) 
fits <- lapply(d_list, function(input){lm(value ~ year, data = input)})
# Get the slope from the fits, this is the resilience value. 
resilience_values <- sapply(fits, function(x){x$coefficients[2]})
resilience_d <- data.table(info = names(resilience_values), resilience = resilience_values)
resilience_d <- resilience_d[, c("variable", "scn", "met", "x") := tstrsplit(info, ".",
                                                                             fixed=TRUE)]
resilience_d <- resilience_d[, c("resilience", "variable", "scn", "met")]
# Now using the fits calculate the temporal stability. 
# ${s}_{t} = \frac{1}{ SE of resid}$
se_resid <- sapply(fits, function(model){sqrt(deviance(model)/df.residual(model))})
temp_stability_d <- data.table(info = names(se_resid), temp_stability = 1/se_resid)
temp_stability_d <- temp_stability_d[, c("variable", "scn", "met") := tstrsplit(info, ".",
                                                                             fixed=TRUE)]
temp_stability_d <- temp_stability_d[, c("temp_stability", "variable", "scn", "met")]
# Finally calculate the recovery, for now we will define recovery at year 2039
# two decades after the year of the girdel. 
recovery_d <- disturbance_d[year == 2030]
recovery_d <- recovery_d[ , c("scn", "variable", "description", "unit", "met",  "value")]
names(recovery_d) <- c("scn", "variable", "description", "unit", "met",  "recovery")
recovery_d$recovery <- recovery_d$recovery
# Combine all dimensions of stability into a single data table. 
resitance_d[resilience_d, on = c("variable", "scn", "met")] %>% 
  .[temp_stability_d, on = c("variable", "scn", "met")] %>% 
  .[recovery_d, on = c("variable", "scn", "met")] %>% 
  .[, c( "scn", "variable", "description", "unit", "met", "resitance", 
         "resilience", "temp_stability", "recovery")] -> 
  dt 
# Add the disturbance severity column. 
dt$`Disturbance Severity` <- paste0(gsub(x = dt$scn,
                                         pattern = "harvest_|_1day_above", 
                                         replacement = ""), " %")
# Format and apply factor information to the variable name so the dimensions of stability plot 
# step through the carbon cycle in order GPP -> NPP -> NEP. 
dt$variable <- gsub(pattern = "_patch", replacement = "", x = dt$variable)
dt$variable <- factor(x = dt$variable, levels = c("GPP", "NPP", "NEP"), ordered = TRUE)
dt <- na.omit(dt)
return(dt)
}
stability_metrics <- calculate_dimensions_stability(annual_data)

5.1 Plot Resistance

\({r}_{t} = ln(\frac{{F}_{disturbance}}{{F}_{control}})\)

When \[{t}\] is the year of the disturbance, in this case 2019.

stability_metrics %>% 
  ggplot(aes(`Disturbance Severity`, resitance, color = `Disturbance Severity`)) + 
  geom_point(size = 2, alpha = 0.4) + 
  facet_wrap('variable') + 
  THEME  + 
  labs(title = 'Resistance', y = '2019 ln(F disturabnce / F baseline)') + 
  scale_color_manual(values = FORTE_SEVERITY_COLORS) 

5.2 Plot Resilience

\({r}_{i} = ln(\frac{{F}_{disturbance}}{{F}_{control}}) = i + {r}_{i} * t\)

stability_metrics %>%  
ggplot() + 
  geom_point(aes(`Disturbance Severity`, resilience, color = `Disturbance Severity`),
             size = 2, alpha = 0.4) + 
  facet_wrap('variable') + 
  THEME  + 
  labs(title = 'Resilience', y = 'Slope ln(dist/control)') + 
  scale_color_manual(values = FORTE_SEVERITY_COLORS)

5.3 Plot Temporal Stability

\({s}_{t} = \frac{1}{ SE of resid}\)

stability_metrics %>%  
ggplot() + 
  geom_point(aes(`Disturbance Severity`, temp_stability, color = `Disturbance Severity`),
             size = 2, alpha = 0.4) + 
  facet_wrap('variable') + 
  THEME  + 
  labs(title = 'Temporal Stability', 
       y = ' 1 / (SE of resid)') + 
  scale_color_manual(values = FORTE_SEVERITY_COLORS)

5.4 Plot Recovery

Take a look at the recovery at separate time steps.

ggplot(data = recovery_at_X_data[ , year := as.character(year)], 
       aes(x = year, y = recovery, fill = `Disturbance Severity`)) + 
  geom_boxplot() + 
  THEME + 
  labs(x = 'Year', y = "ln(disturbance/baseline)", title = "Recovery at Year") + 
  facet_wrap("variable", ncol = 1, scales = "free")

Recovery 2 decades after the treatment.

stability_metrics %>%  
ggplot() + 
  geom_point(aes(`Disturbance Severity`, recovery, color = `Disturbance Severity`),
             size = 2, alpha = 0.4) + 
  facet_wrap('variable') + 
  THEME  + 
  labs(title = 'Recovery', 
       y = 'Recovery at 2030') + 
  scale_color_manual(values = FORTE_SEVERITY_COLORS)

6 Input & Metric Interactions

# Create a data frame of the disturbance period annual met inputs, note that it should be 
# a wide data frame in preperation for the pair wise plots. 
data[year == 2019][ , c("variable", "value", "scn")] %>%
  unique() %>% 
  setnames(old = c("scn", "value", "variable"), 
           new = c("met", "met_vavlue", "met_variable")) -> 
  dist_met_data
# Combine the met and the dimensions of stability data into a single data frame. 
stability_metrics[ , c("scn", "variable", "met", "resitance", 
                       "resilience", "temp_stability", "recovery", "Disturbance Severity")] %>%
  melt(id.vars = c("scn", "variable", "met", "Disturbance Severity"),
       measure.vars = c("resitance", "resilience", "temp_stability", "recovery"), 
       variable.name = "metric_name", value.name = "metric_value") %>% 
  unique() -> 
  metric_long
full_df <- dist_met_data[metric_long, on = "met", allow.cartesian=TRUE]
var_list <- unique(full_df$variable)
metric   <- unique(full_df$metric_name)
full_df  <- full_df[var_info, on = .(met_variable = variable)] 
lapply(metric, function(m){
  #  & met_variable %in% c("prate", "tmp", "sh")
  full_df[metric_name == m] %>% 
  ggplot(aes(met_vavlue, metric_value, color = `Disturbance Severity`)) + 
  geom_point() + 
  facet_grid(variable ~ description, scales = "free",  labeller = label_wrap_gen(width = 20, multi_line = TRUE)) + 
  THEME + 
  labs(y = NULL, x = NULL, title = m) + 
  theme(legend.position = "bottom") + 
  scale_color_manual(values = FORTE_SEVERITY_COLORS)
}) -> 
  plots
names(plots) <- metric

6.1 Plot Input x Resitance

plots$resitance + 
  theme(axis.text.x = element_text(angle = 45, vjust = 0.5, hjust=0.5))

6.2 Plot Input x Resilience

plots$resilience + 
  theme(axis.text.x = element_text(angle = 45, vjust = 0.5, hjust=0.5))

6.3 Plot Input x Temporal Stability

plots$temp_stability + 
  labs(title = "Temporal Stability") + 
  theme(axis.text.x = element_text(angle = 45, vjust = 0.5, hjust=0.5))

6.4 Plot Input x Recovery

plots$recovery + 
  theme(axis.text.x = element_text(angle = 45, vjust = 0.5, hjust=0.5))

7 Dynamic Recovery

# Calculate the ln(disturbance/control)
# Args 
#   d: a data frame of the anual data 
# Return: a data frame of the ln(disturbance/control) per year/variable/met/disturbance severity 
calc_ln_disturbance <- function(d){
  
  # Check inputs 
  req_names <- c('scn', 'year', 'variable', 'description', 'unit', 'value', 'met')
  assert_that(has_name(d, req_names))
  
  baseline_scn <- "harvest_0_1day_above" 
  assert_that(baseline_scn %in% d$scn)
  
  # Separate the control or baseline scneario values from the output from the other 
  # treatment groups. 
  baseline_values <- d[scn == baseline_scn][ , c("year", "variable", "value", "met")]
  names(baseline_values) <- c("year", "variable", "baseline", "met")
  treatment_values <- d[scn != baseline_scn][ , c("scn", "year", "variable", "description", 
                                                "unit", "treatment" = "value", "met")]
  names(treatment_values) <- c("scn", "year", "variable", "description", "unit", "treatment", "met")
  
  # Combine the control and the treatment values as a wide df, then take the # ln(treatment/control) per year / variable / met
  # realization. 
  disturbance_d <- treatment_values[baseline_values, on = c("year", "variable", "met")][year %in% 2019:2050]
  disturbance_d <- disturbance_d[ , value := log(treatment/baseline)]
  disturbance_d <- disturbance_d[ , disturbance_severity := paste0(gsub(x = scn, pattern = "harvest_|_1day_above", replacement = ""), " %")]
  disturbance_d <- disturbance_d[ , variable :=  gsub(pattern = "_patch", replacement = "", x = variable)]
  disturbance_d$variable <- factor(x = disturbance_d$variable, levels = c("GPP", "NPP", "NEP"), ordered = TRUE)
  disturbance_d <- disturbance_d[ , .(year, variable, met, value, disturbance_severity)]
  disturbance_d <- na.omit(disturbance_d)
  disturbance_d <- disturbance_d[year %in% 2019:2050]
  
  return(disturbance_d)
}
disturbance <- calc_ln_disturbance(annual_data)
# Define the functions to be used by frollapply to get the fits from the rolling slopes 
slope_func <- function(value){
  
  assert_that(is.vector(value))
  sq <- seq(1:length(value))
  fit <- lm(value~sq)
  
  slope <- coef(fit)[2]
  names(slope) <- "slope"
  return(slope)
  
}
intercept_func <- function(value){
  
  assert_that(is.vector(value))
  sq <- seq(1:length(value))
  fit <- lm(value~sq)
  
  inter <- coef(fit)[1]
  names(inter) <- "y-intercept"
  return(inter)
  
}
# Apply the slope and intercept functions to each variable / met / severity disturbance values. 
split(disturbance,
      interaction(disturbance$variable, disturbance$met, disturbance$disturbance_severity)) %>% 
  lapply(function(x){
    
    window <- 5
    slope <- frollapply(x = x[["value"]], n = window, FUN = slope_func, align = "left")
    slope2 <- frollapply(x = slope, n = window, FUN = slope_func, align = "left")
    
    out <- cbind(x, slope = slope, slope2 = slope2)
    return(out)
    
  }) %>% 
  rbindlist %>%  
  na.omit -> 
  dist_slope_y

7.1 Plot of Disturbance Rate of Change

This is the first derivative, the rate of change of disturabnce, we were intrested in when this is 0, if that would be the recovery point becacuse that would refelect when the ecosystem has reached a new steady state…

ggplot(data = dist_slope_y[year %in% 2019:2050]) +
 geom_hline(aes(yintercept = 0)) +
 geom_line(aes(year, slope, group = interaction(disturbance_severity, met)), color = "grey", alpha = 0.3) +
 geom_point(aes(year, slope, color = disturbance_severity, group = interaction(disturbance_severity, met))) +
 facet_wrap("variable", scales = "free", ncol = 1) +
 theme_bw() +
 labs(title = "5 year running slope")

# Selet the recovery years as the years where the mangnitude of the rate of change is less than 1e-3 or set a 
# hard limit of 2030, which is unideal but for now it is not not to avoid some sort of arbitriaty cut off. 
recovery_yr <- dist_slope_y[abs(slope) <= 1e-3][ , .(recovery_yr = min(year)), by = .(variable, met, disturbance_severity)] 
recovery_yr <- recovery_yr[recovery_yr <= 2030]
# Now join with the disurbance values. 
recovery_yr[disturbance, on = c("variable", "met", "disturbance_severity"), nomatch = NA] %>% 
  .[ , recovery_yr:= ifelse(test = is.na(recovery_yr), yes = 2030, no = recovery_yr)] %>% 
  .[year <= recovery_yr] -> 
  disturbance_recovery_subset
# Find recovery value aka the disturbance value at the time of recovery. 
recovery_values <- disturbance_recovery_subset[ year == recovery_yr]

Using when the rate of change or running slope is less than or equal to 0 or with a cut off there are only a handful of runs that recovery or reach a new stead state.

recovery_yr[disturbance, on = c("variable", "met", "disturbance_severity"), nomatch = NA] %>% 
 # .[ , recovery_yr:= ifelse(test = is.na(recovery_yr), yes = 2030, no = recovery_yr)] %>% 
  .[year <= recovery_yr] %>% 
  ggplot(aes(year, value, color = disturbance_severity, group = interaction(met, disturbance_severity))) + 
  geom_line() + 
  facet_grid(variable~disturbance_severity, scales = "free") + 
  labs(title = "Dynamic Recovery", y = "ln(treatment/control)") + 
  theme_bw() + 
  theme(legend.position = "none")

What if the cut off value is when the rate off change is less than or equal to 0 or at most 2030? If that is the case then our results look something like.

recovery_yr[disturbance, on = c("variable", "met", "disturbance_severity"), nomatch = NA] %>%
  .[ , recovery_yr:= ifelse(test = is.na(recovery_yr), yes = 2030, no = recovery_yr)] %>% 
  .[year <= recovery_yr] %>% 
  ggplot(aes(year, value, color = disturbance_severity, group = interaction(met, disturbance_severity))) + 
  geom_line() + 
  facet_grid(variable~disturbance_severity, scales = "free") + 
  labs(title = "Dynamic Recovery", y = "ln(treatment/control)") + 
  theme_bw() + 
  theme(legend.position = "none")

Is a linear fit the right fit here? How do we deal with these different recovery dates?

LS0tCnRpdGxlOiAnRXhwLTEgTWV0IFJlc3VsdHMnCmRhdGU6ICJgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVkICVCLCAlWScpYCIKb3V0cHV0OiAKICBodG1sX25vdGVib29rOiAKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OgogICAgICB0b2NfY29sbGFwc2VkOiB0cnVlCiAgICB0b2NfZGVwdGg6IDQKICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogICAgdGhlbWU6IGx1bWVuCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgd2FybmluZyA9IEZBTFNFKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoZGF0YS50YWJsZSkKbGlicmFyeShmb3J0ZWRhdGEpCmxpYnJhcnkobWFncml0dHIpCmxpYnJhcnkoZm9ydGVkYXRhKQpsaWJyYXJ5KGdncG1pc2MpCmxpYnJhcnkoYXNzZXJ0dGhhdCkKbGlicmFyeShHR2FsbHkpCmxpYnJhcnkoa25pdHIpCgojIERlZmluZSB0aGUgYmFzZSBkaXJlY3RvcnkuIApCQVNFX0RJUiA8LSAiL1VzZXJzL2RvcmgwMTIvRG9jdW1lbnRzLzIwMjAvRm9SVEUvZm9ydGUtZGlzdHVyYmFuY2UiCgojIERlZmluZSB0aGUgY29sb3IgdGhlbWVzIGFuZCB0aGUgZ3JhcGhpbmcgYWVzdGhldGljcy4gClRIRU1FIDwtIHRoZW1lX2J3KCkKQUxQSEEgPC0gMC4wNQpCQ0tfR1JORDEgPC0gJyNkY2ZmY2MnCkJDS19HUk5EMiA8LSAnIzlmZGZjZCcKQkNLX0dSTkQzIDwtICcjYmFhYmRhJwpGT1JURV9TRVZFUklUWV9DT0xPUlMgPC0gYygiIzAwMDAwMCIsICIjMDA5RTczIiwgIiMwMDcyQjIiLCAiI0Q1NUUwMCIpCm5hbWVzKEZPUlRFX1NFVkVSSVRZX0NPTE9SUykgPC0gYygnMCAlJywgJzQ1ICUnLCAnNjUgJScsICc4NSAlJykKYGBgCgoKIyBPYmplY3RpdmUgCgpSdW4gRUQgdXNpbmcgZGlmZmVyZW50IGNsaW1hdGUgdG8gY3JlYXRlIGFuIGVuc2VtYmxlIG9mIHJ1bnMgCgoqIEhvdyBkb2VzIHRoYXQgaW1wYWN0IEVEIHJlc3VsdHM/IAoqIFdoYXQgaW1wYWN0IGRvZXMgaXQgbWFrZSBvbiBkaW1lbnNpb25zIG9mIHN0YWJpbGl0eT8gCiogSXMgdGhlcmUgYSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgaW5wdXRzICYgbWV0cmljcz8gCiogSG93IGRvIHdlIHdhbnQgdG8gY2FsY3VsYXRlIHJlY292ZXJ5PyAKICAqIFdoZW4gaXQgcmVhY2hlcyB0aGUgY29udHJvbD8gV2hlbiBpdCByZWFjaGVzIGEgc3RlYWR5IHN0YXRlPyAKCgoKIyBDb21wYXJlIElucHV0cyAKCmBgYHtyfQojIEltcG9ydCB0aGUgbWV0ZXJvbGljYWwgaW5wdXRzLiAKUkVTVUxUU19ESVIgPC0gZmlsZS5wYXRoKEJBU0VfRElSLCAiRUQtb3V0cHV0cyIsICJtZXRfcmVzdWx0cyIpCgojIENyZWF0ZSBhIGRhdGEgZnJhbWUgb2YgYWxsIHRoZSBtZXRlcm9sZ2ljYWwgZGF0YSB1c2VkLiAKbGlzdC5maWxlcyhSRVNVTFRTX0RJUiwgcGF0dGVybiA9ICd5cicsIGZ1bGwubmFtZXMgPSBUUlVFKSAlPiUgIAogIGxhcHBseShmdW5jdGlvbih4KXsKICAgIAogICAgbmFtZSA8LSBnc3ViKHggPSBiYXNlbmFtZSh4KSwgcGF0dGVybiA9ICdfeXIuY3N2JywgcmVwbGFjZW1lbnQgPSAnJykKICAgIGRhdGEgPC0gcmVhZC5jc3YoeCwgc3RyaW5nc0FzRmFjdG9ycyA9IEZBTFNFKQogICAgZGF0YSRzY24gPC0gbmFtZQogICAgcmV0dXJuKGRhdGEpCiAgICAKICB9KSAlPiUgIAogIGRwbHlyOjpiaW5kX3Jvd3MoKSAlPiUgIAogIGFzLmRhdGEudGFibGUgLT4gCiAgZGF0YQoKIyBBIG1hcHBpbmcgZmlsZSBvZiB2YXJpYWJsZSBuYW1lcywgZGVzY3JpcHRpb24sIGFuZCB1bml0cy4gCiMgVGhpcyB3aWxsIGJlIHVzZWQgdG8gYWRkIG1vcmUgaW5mb3JtYXRpb24gdG8gdGhlIG1ldCBkYXRhIGRhdGEgZnJhbWUuIAp2YXJfaW5mbyA8LSBkYXRhLnRhYmxlKHZhcmlhYmxlID0gYygnZGx3cmYnLCAnbmJkc2YnLCAnbmRkc2YnLCAndmJkc2YnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAndmRkc2YnLCAncHJhdGUnLCAncHJlcycsICdoZ3QnLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ3VncmQnLCAndmdyZCcsICdzaCcsICd0bXAnKSwgCiAgICAgICAgICAgICAgICAgICAgICAgZGVzY3JpcHRpb24gPSBjKCdkb3dud2FyZCBsb25nIHdhdmUgcmFkaWF0aW9uJywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICduZWFyIGluZnJhcmVkIGJlYW0gZG93bndhcmQgc29sYXIgcmFkaWF0aW9uJywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICduZWFyIElSIGRpZmZ1c2UgZG93bndhcmQgc29sYXIgcmFkaWF0aW9uJywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICd2aXNpYmxlIGJlYW0gZG93bndhcmQgc29sYXIgcmFkaWF0aW9uJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ3Zpc2libGUgZGlmZnVzZSBkb3dud2FyZCBzb2xhciByYWRpYXRpb24nLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ3ByZWNpcGl0YXRpb24gcmF0ZScsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnYXRtb3NwaGVyaWMgcHJlc3N1cmUnLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ2dlb3BvdGVudGlhbCBoZWlnaHQnLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ3pvbmFsIHdpbmQnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnbWVyaWRpb25hbCB3aW5kJywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdzcGVjaWZpYyBodW1pZGl0eScsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdhaXIgdGVtcGVyYXR1cmUnKSwgIAogICAgICAgICAgICAgICAgICAgICAgIHVuaXRzID0gYygnVyBtLTInLCAnVyBtLTInLCAnVyBtLTInLCAnVyBtLTInLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnVyBtLTInLCAna2dIMk8gbS0yIHMtMScsICdQYScsICdtJywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ20gcy0xJywgJ20gcy0nLCAna2dIMk8ga2dBaXItMScsICdLJyksIHN0cmluZ3NBc0ZhY3RvcnM9RkFMU0UpCgpkYXRhIDwtIGRhdGFbdmFyX2luZm8sIG9uID0gJ3ZhcmlhYmxlJ10KZGF0YSA8LSBuYS5vbWl0KGRhdGEpCgpkYXRhJGxhYmVsIDwtIHBhc3RlMChkYXRhJGRlc2NyaXB0aW9uLCAnICgnLCBkYXRhJHVuaXRzLCAnKScpCgpgYGAKCgpgYGB7cn0KIyBEZWZpbmUgZnVuY3Rpb24gdGhhdCBnZW5lcmF0ZXMgdGhlIHN0YW5kYXJkIG1ldCBpbnB1dCBwbG90IAojIEFyZ3MgCiMgICBkYXRhOiBkYXRhIHRhYmxlIG9mIHRoZSBtZXQgZGF0YSB0byBwbG90CiMgICB5cjE6IHRoZSBmaXJzdCB5ZWFyIG9mIG1ldCBkYXRhIHRvIHBsb3QsIGRlZmF1bHQgc2V0IHRvIDE5NTAKIyAgIHlyMjogdGhlIGZpbmFsIHllYXIgb2YgbWV0IGRhdGEgdG8gcGxvdCwgZGVmYXVsdCBzZXQgdG8gMjAzMCAKIyBSZXR1cm46IGEgZmFjZXRlZCBsaW5lIHBsb3Qgb2YgdGhlIG1ldCBkYXRhLCBnZ3Bsb3QyIG9iamVjdAptZXRfcGxvdCA8LSBmdW5jdGlvbihkLCB5cjEgPSAxOTUwLCB5cjIgPSAyMDQwKXsKICAKICAjIENvbG9yIHRoZSBiYWNrZ3JvdW5kIAogIEFMUEhBIDwtIDAuMDUKICBCQ0tfR1JORDEgPC0gJyNkY2ZmY2MnCiAgQkNLX0dSTkQyIDwtICcjOWZkZmNkJwogIEJDS19HUk5EMyA8LSAnI2JhYWJkYScKICAKICBkW3llYXIgPj0geXIxICYgeWVhciA8PSB5cjJdICU+JSAgCiAgICBnZ3Bsb3QoKSArIAogICAgZ2VvbV9yZWN0KGFlcyh4bWluPXlyMSwgeG1heCA9IDE5NzksCiAgICAgICAgICAgICAgICAgIHltaW4gPSAtSW5mLCB5bWF4ID0gSW5mKSwgZmlsbCA9IEJDS19HUk5EMSwgYWxwaGEgPSBBTFBIQSkgKwogICAgZ2VvbV9yZWN0KGFlcyh4bWluPTE5NzksIHhtYXggPSAyMDEwLAogICAgICAgICAgICAgICAgICB5bWluID0gLUluZiwgeW1heCA9IEluZiksIGZpbGwgPSBCQ0tfR1JORDIsIGFscGhhID0gQUxQSEEpICsKICAgIGdlb21fcmVjdChhZXMoeG1pbj0yMDEwLCB4bWF4ID0geXIyLAogICAgICAgICAgICAgICAgICB5bWluID0gLUluZiwgeW1heCA9IEluZiksIGZpbGwgPSBCQ0tfR1JORDMsIGFscGhhID0gQUxQSEEpICsgCiAgICBsYWJzKGNhcHRpb24gPSAnY29sb3JlZCBiYWNrZ3JvdW5kOiBsb29wZWQgb3ZlciBvYnMuLCBvYnMuLCA1IHllYXIgb2JzLiBtZWFuICcpICsgCiAgICBnZW9tX2xpbmUoYWVzKHllYXIsIHZhbHVlLCBsaW5ldHlwZSA9IHNjbikpICsgCiAgICBmYWNldF93cmFwKCdsYWJlbCcsIHNjYWxlcyA9ICdmcmVlJywgc3RyaXAucG9zaXRpb24gPSAidG9wIiwKICAgICAgICAgICAgIGxhYmVsbGVyID0gbGFiZWxfd3JhcF9nZW4od2lkdGggPSAyMCwgbXVsdGlfbGluZSA9IFRSVUUpKSArIAogICAgVEhFTUUgKyAKICAgIGxhYnMoeSA9IE5VTEwsIHggPSAnWWVhcicsIHRpdGxlID0gJ0FubnVhbCBNZWFuIE1ldGVvcm9sb2dpY2FsIElucHV0cycpICsgCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAnbm9uZScpIC0+IAogICAgcGxvdCAKICAKICByZXR1cm4ocGxvdCkKCn0KCgojIFNwbGl0IHRoZSBtZXQgZGF0YSB1cCBpbnRvIHR3byBkaWZmZXJlbnQgcGxvdHMsIHRoaXMgd2lsbCBtYWtlIHRoZSBwbG90cyBlYXNpZXIgdG8gIGxvb2sgYXQuIAp2YXJfbGlzdCA8LSB1bmlxdWUoZGF0YSR2YXJpYWJsZSkKcGFubmVsc19uMSA8LSBjZWlsaW5nKGxlbmd0aCh2YXJfbGlzdCkvMikKYGBgCgoKVXAgdW50aWwgMjAxMCB0aGUgcnVucyB1c2UgdGhlIHNhbWUgbWV0ZW9yb2xvZ3kgaW5wdXRzLCBzdGFydGluZyBpbiAyMDEwLCBhYm91dCBhIGRlY2FkZSBiZWZvcmUgdGhlIGRpc3R1cmJhbmNlIHdlIHN0YXJ0IHRvIHVzZSBkaWZmZXJlbnQgbWV0ZW9yb2xvZ3kgaW5wdXRzIGJhc2VkIG9uIDUgeWVhciBtZWFucyBzYW1wbGVkIGZyb20gdGhlIG9ic2VydmF0aW9uYWwgZGF0YSBzZXQuICAKCiMjIFBsb3QgQ2xpbWF0ZSBJbnB1dCAKCmBgYHtyfQojIFBsb3QgdGhlIGZpcnN0IGhhbGYgb2YgdGhlIG1ldCBpbnB1dCB2YWx1ZXMgCm1ldF9wbG90KGRhdGFbdmFyaWFibGUgJWluJSB2YXJfbGlzdFsxOnBhbm5lbHNfbjFdXSkKYGBgCgoKYGBge3J9CiMgUGxvdCB0aGUgc2Vjb25kIGhhbGYgb2YgdGhlIG1ldCBpbnB1dCB2YWx1ZXMgCm1ldF9wbG90KGRhdGFbdmFyaWFibGUgJWluJSB2YXJfbGlzdFtwYW5uZWxzX24xKzE6bGVuZ3RoKHZhcl9saXN0KV1dKQpgYGAKCgpUaGUgaW5wdXRzIGZvciB0aGUgdHdvIGRpZmZlcmVudCBtZXQgcmVjb3JkcyBzdGFydGluZyBpbiAyMDEwLCBzbyB0aGF0IHRoYXQgRUQgaGFzIGEgc3RlYWR5IGNsaW1hdGUgZm9yIHRoZSB+MTAgeXJzIGJlZm9yZSB0aGUgZGlzdHVyYmFuY2UsIHRoZSBtZXQgZW5zZW1ibGUgY2FwdHVyZXMgYSB3aWRlIHJhbmdlIG9mIGRpZmZlcmVudCBjbGltYXRlcy4gCgojIEVEIFJlc3VsdHMgIAoKYGBge3J9CmFubnVhbF9kYXRhIDwtIGFzLmRhdGEudGFibGUocmVhZC5jc3YoZmlsZS5wYXRoKEJBU0VfRElSLCAiRUQtb3V0cHV0cyIsICJyZXN1bHRzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImV4cC0xLXlyLmNzdiIpLCBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpKQpgYGAKCiMjIFBsb3QgQmFzZWxpbmUvQ29udHJvbCAKCmBgYHtyfQphbm51YWxfZGF0YSRsYWJlbCA8LSBwYXN0ZTAoYW5udWFsX2RhdGEkZGVzY3JpcHRpb24sICIgKCIsIGFubnVhbF9kYXRhJHVuaXQsICIpIikKCmFubnVhbF9kYXRhW3NjbiA9PSAnaGFydmVzdF8wXzFkYXlfYWJvdmUnLCBdICU+JSAgCiAgLlsgLCBzZXZlcml0eSA6PSAnMCddICU+JSAKICBnZ3Bsb3QoKSArIAogICAgICBnZW9tX3JlY3QoYWVzKHhtaW49MTkwMCwgeG1heCA9IDE5NzksCiAgICAgICAgICAgICAgICAgIHltaW4gPSAtSW5mLCB5bWF4ID0gSW5mKSwgZmlsbCA9IEJDS19HUk5EMSwgYWxwaGEgPSBBTFBIQSkgKwogICAgZ2VvbV9yZWN0KGFlcyh4bWluPTE5NzksIHhtYXggPSAyMDEwLAogICAgICAgICAgICAgICAgICB5bWluID0gLUluZiwgeW1heCA9IEluZiksIGZpbGwgPSBCQ0tfR1JORDIsIGFscGhhID0gQUxQSEEpICsKICAgIGdlb21fcmVjdChhZXMoeG1pbj0yMDEwLCB4bWF4ID0gMjA0OCwKICAgICAgICAgICAgICAgICAgeW1pbiA9IC1JbmYsIHltYXggPSBJbmYpLCBmaWxsID0gQkNLX0dSTkQzLCBhbHBoYSA9IEFMUEhBKSArIAogICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMjAxOSwgY29sb3IgPSAnYmxhY2snKSArIAogIGdlb21fbGluZShhZXMoeWVhciwgdmFsdWUsIGxpbmV0eXBlID0gbWV0KSkgKyAKIGZhY2V0X3dyYXAoJ2xhYmVsJywgc2NhbGVzID0gJ2ZyZWUnLCAgCiAgICAgICAgICAgIGxhYmVsbGVyID0gbGFiZWxfd3JhcF9nZW4od2lkdGggPSA1MCwgbXVsdGlfbGluZSA9IFRSVUUpKSArIAogIFRIRU1FICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gJ25vbmUnKSsKICBsYWJzKHRpdGxlID0gJ0Rpc3R1cmJhbmNlIFNldmVyaXR5IDAlJywgCiAgICAgICB5ID0gTlVMTCwgCiAgICAgICB4ID0gIlllYXIiLCAKICAgICAgIGNhcHRpb24gPSAndmVydGljYWwgbGluZSBhdCAyMDE5LCB3aGVuIHRoZSBGb1JURSB0cmVhdG1lbnQgaXMgYXBwbGllZFxuY29sb3JlZCBiYWNrZ3JvdW5kOiBsb29wZWQgb3ZlciBvYnMuLCBvYnMuLCA1IHllYXIgb2JzLiBtZWFuICcpIApgYGAKCgpZZXMgY2hhbmdpbmcgdGhlIG1ldGVvcm9sb2d5IGlucHV0IGZpbGVzIGRvZXMgbWFrZSBhIGRpZmZlcmVuY2UgaW4gdGhlIGJhc2VsaW5lIHNjZW5hcmlvcywgYXMgd2UgY2FuIHRlbGwgYmFzZWQgb24gdGhlIHZlcnRpY2FsIGxpbmUgYnkgdGhlIHRpbWUgdGhlIEZvUlRFIHRyZWF0bWVudCBpcyBhcHBsaWVkIHRoZSBFRCBmb3Jlc3Qgc3RhbmRzIGRpdmVyZ2VkIGZyb20gb25lIGFub3RoZXIuIAoKCiMgRGlzdHVyYmFuY2UgCgpXaGF0IGlzIHRoZSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIGRpZmZlcmVudCB0cmVhdG1lbnRzIGFuZCB0aGUgY29udHJvbCAoMCUpIHJ1bnM/IAoKYGBge3J9CmJhc2VsaW5lIDwtIGFubnVhbF9kYXRhW3NjbiA9PSAnaGFydmVzdF8wXzFkYXlfYWJvdmUnLCBdWyAsIC4oeWVhciwgdmFyaWFibGUsIGRlc2NyaXB0aW9uLCB1bml0LCBtZXQsIGJhc2VsaW5lID0gdmFsdWUpXQpkaXN0dXJiYW5jZSA8LSBhbm51YWxfZGF0YVtzY24gIT0gJ2hhcnZlc3RfMF8xZGF5X2Fib3ZlJywgXQpzZXRuYW1lcyh4ID0gZGlzdHVyYmFuY2UsIG9sZCA9ICJ2YWx1ZSIsIG5ldyA9ICJkaXN0dXJiYW5jZSIsIHNraXBfYWJzZW50ID0gVFJVRSkKZHQgPC0gYmFzZWxpbmVbZGlzdHVyYmFuY2UsIG9uID0gYyggInllYXIiLCAidmFyaWFibGUiLCAiZGVzY3JpcHRpb24iLCAidW5pdCIsICJtZXQiKV0KZHRbICwgdmFsdWUgOj0gZGlzdHVyYmFuY2UgLSBiYXNlbGluZV0KZHRbICwgc2V2ZXJpdHkgOj0gZ3N1YihwYXR0ZXJuID0gImhhcnZlc3RffF8xZGF5X2Fib3ZlIiwgcmVwbGFjZW1lbnQgPSAiIiwgeCA9IHNjbildCmBgYAoKIyMgUGxvdCBEaXN0dXJiYW5jZQoKYGBge3J9CmR0JGBEaXN0dXJiYW5jZSBTZXZlcml0eWAgPC0gcGFzdGUwKGR0JHNldmVyaXR5LCAnICUnKQoKZHRbeWVhciA+PSAyMDE1LCBdICU+JSAKICBnZ3Bsb3QoYWVzKHllYXIsIHZhbHVlLCBjb2xvciA9IGBEaXN0dXJiYW5jZSBTZXZlcml0eWAsIGxpbmV0eXBlID0gbWV0KSkgKyAKICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAyMDE5LCBjb2xvciA9ICdibGFjaycpICsgCiAgZ2VvbV9saW5lKCkgKyAKICAgZmFjZXRfd3JhcCgnbGFiZWwnLCBzY2FsZXMgPSAnZnJlZScsICAKICAgICAgICAgICAgbGFiZWxsZXIgPSBsYWJlbF93cmFwX2dlbih3aWR0aCA9IDMwLCBtdWx0aV9saW5lID0gVFJVRSkpICsgCiAgVEhFTUUgKyAKICBsYWJzKHkgPSAnRGlzdHVyYmFuY2UgLSBCYXNlbGluZScsIAogICAgICAgeCA9ICdZZWFyJywgCiAgICAgICBjYXB0aW9uID0gJ3ZlcnRpY2FsIGxpbmUgMjAxOSBkaXN0dXJiYW5jZSBldmVudCcpICArIAogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBGT1JURV9TRVZFUklUWV9DT0xPUlMpICsgCiAgZ3VpZGVzKGxpbmV0eXBlID0gRkFMU0UpCmBgYAoKClRoZSBvdmVyIHNob290IGluIHRoZSBtZXQyIHRyYWNrIGZvciB0aGUgY2FyYm9uIGZsdXhlcyBpcyByZWFsbHkgaW50ZXJlc3RpbmchIERvIHdlIHRoaW5rIHRoYXQgd291bGQgaGFwcGVuIGlmIHRoZSBtZXQxIHJ1biBjb250aW51ZWQgbG9uZ2VyPyAKCgojIERpbWVuc2lvbnMgb2YgU3RhYmlsaXR5IAoKYGBge3J9CiMgRmluZCB0aGUgcmVjb3ZlcnkgYXQgc3BlY2lmaWMgdGltZSBwbGFjZXMuIAojIEFyZ3MgCiMgICBkOiBhIGRhdGEgZnJhbWUgb2YgdGhlIGFubnVhbCBFRCBvdXRwdXRzCiMgICB4OiBhIHZlY3Rvcnkgb2YgdGhlIHllYXJzIHRvIGNhbGN1bGF0ZSB0aGUgcmVjb3ZlcnkgYXQuIAojIFJldHVybjogYSBkYXRhIGZyYW1lIG9mIHRoZSByZWNvdmVyeSB2YWx1ZXMKcmVjb3ZlcnlfYXRfWCA8LSBmdW5jdGlvbihkLCB4KXsKICAKIyBDaGVjayBpbnB1dHMgCnJlcV9uYW1lcyA8LSBjKCdzY24nLCAneWVhcicsICd2YXJpYWJsZScsICdkZXNjcmlwdGlvbicsICd1bml0JywgJ3ZhbHVlJywgJ21ldCcpCmFzc2VydF90aGF0KGhhc19uYW1lKGQsIHJlcV9uYW1lcykpCgpiYXNlbGluZV9zY24gPC0gImhhcnZlc3RfMF8xZGF5X2Fib3ZlIiAKYXNzZXJ0X3RoYXQoYmFzZWxpbmVfc2NuICVpbiUgZCRzY24pCgphc3NlcnRfdGhhdChhbGwoeCAlaW4lIGQkeWVhcikpCgojIFNlcGFyYXRlIHRoZSBjb250cm9sIG9yIGJhc2VsaW5lIHNjbmVhcmlvIHZhbHVlcyBmcm9tIHRoZSBvdXRwdXQgZnJvbSB0aGUgb3RoZXIgCiMgdHJlYXRtZW50IGdyb3Vwcy4gCmJhc2VsaW5lX3ZhbHVlcyA8LSBkW3NjbiA9PSBiYXNlbGluZV9zY25dWyAsIGMoInllYXIiLCAidmFyaWFibGUiLCAidmFsdWUiLCAibWV0IildCm5hbWVzKGJhc2VsaW5lX3ZhbHVlcykgPC0gYygieWVhciIsICJ2YXJpYWJsZSIsICJiYXNlbGluZSIsICJtZXQiKQp0cmVhdG1lbnRfdmFsdWVzIDwtIGRbc2NuICE9IGJhc2VsaW5lX3Njbl1bICwgYygic2NuIiwgInllYXIiLCAidmFyaWFibGUiLCAiZGVzY3JpcHRpb24iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInVuaXQiLCAidHJlYXRtZW50IiA9ICJ2YWx1ZSIsICJtZXQiLCAibGFiZWwiKV0KbmFtZXModHJlYXRtZW50X3ZhbHVlcykgPC0gYygic2NuIiwgInllYXIiLCAidmFyaWFibGUiLCAiZGVzY3JpcHRpb24iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInVuaXQiLCAidHJlYXRtZW50IiwgIm1ldCIsICJsYWJlbCIpCiMgQ29tYmluZSB0aGUgY29udHJvbCBhbmQgdGhlIHRyZWF0bWVudCB2YWx1ZXMgYXMgYSB3aWRlIGRmLCB0aGVuIHRha2UgdGhlICMgbG4odHJlYXRtZW50L2NvbnRyb2wpIHBlciB5ZWFyIC8gdmFyaWFibGUgLyBtZXQgcmVhbGl6YXRpb24uIApkaXN0dXJiYW5jZV9kIDwtIHRyZWF0bWVudF92YWx1ZXNbYmFzZWxpbmVfdmFsdWVzLCBvbiA9IGMoInllYXIiLCAidmFyaWFibGUiLCAibWV0IildW3llYXIgJWluJSAyMDE5OjIwNTBdCmRpc3R1cmJhbmNlX2RbICwgdmFsdWUgOj0gbG9nKHRyZWF0bWVudC9iYXNlbGluZSldCgojIE5vdyB0aGF0IHRoZSBsbih0cmVhdG1lbnQvY29udHJvbCkgaGFzIGJlZW4gY2FsY3VsYXRlZCB3ZSBjYW4gdXNlIHRoZXNlIHZhbHVlcyB0byBjYWxjdWxhdGUKIyB0aGUgdmFyaW91cyBkaW1lbnNpb25zIG9mIGVjb3N5c3RlbSBzdGFiaWxpdHkuIApyZWNvdmVyeV9kIDwtIGRpc3R1cmJhbmNlX2RbeWVhciAlaW4lIHhdCnJlY292ZXJ5X2QgPC0gcmVjb3ZlcnlfZFsgLCBjKCJzY24iLCAieWVhciIsICJ2YXJpYWJsZSIsICJkZXNjcmlwdGlvbiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAidW5pdCIsICJtZXQiLCAgInZhbHVlIildCm5hbWVzKHJlY292ZXJ5X2QpIDwtIGMoInNjbiIsICJ5ZWFyIiwgInZhcmlhYmxlIiwgImRlc2NyaXB0aW9uIiwgCiAgICAgICAgICAgICAgICAgICAgICAgInVuaXQiLCAibWV0IiwgICJyZWNvdmVyeSIpCmR0IDwtIHJlY292ZXJ5X2QKCiMgQWRkIHRoZSBkaXN0dXJiYW5jZSBzZXZlcml0eSBjb2x1bW4uIApkdCRgRGlzdHVyYmFuY2UgU2V2ZXJpdHlgIDwtIHBhc3RlMChnc3ViKHggPSBkdCRzY24sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGF0dGVybiA9ICJoYXJ2ZXN0X3xfMWRheV9hYm92ZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcGxhY2VtZW50ID0gIiIpLCAiICUiKQoKIyBGb3JtYXQgYW5kIGFwcGx5IGZhY3RvciBpbmZvcm1hdGlvbiB0byB0aGUgdmFyaWFibGUgbmFtZSBzbyB0aGUgZGltZW5zaW9ucyBvZiBzdGFiaWxpdHkgcGxvdCAKIyBzdGVwIHRocm91Z2ggdGhlIGNhcmJvbiBjeWNsZSBpbiBvcmRlciBHUFAgLT4gTlBQIC0+IE5FUC4gCmR0JHZhcmlhYmxlIDwtIGdzdWIocGF0dGVybiA9ICJfcGF0Y2giLCByZXBsYWNlbWVudCA9ICIiLCB4ID0gZHQkdmFyaWFibGUpCmR0JHZhcmlhYmxlIDwtIGZhY3Rvcih4ID0gZHQkdmFyaWFibGUsIGxldmVscyA9IGMoIkdQUCIsICJOUFAiLCAiTkVQIiksIG9yZGVyZWQgPSBUUlVFKQpkdCA8LSBuYS5vbWl0KGR0KQpyZXR1cm4oZHQpCgp9CgpyZWNvdmVyeV9hdF9YX2RhdGEgPC0gcmVjb3ZlcnlfYXRfWChhbm51YWxfZGF0YSwgYygyMDI1LCAyMDMwLCAyMDM1LCAyMDQwLCAyMDQ1KSkKYGBgCgoKYGBge3J9CiMgQ2FsY3VsYXRlIHRoZSB2YXJpb3VzIGRpbWVuc2lvc24gb2Ygc3RhYmlsaXR5IAojIEFyZ3MKIyAgIGQ6IGRhdGEgdGFibGUgb2YgdGhlIGFubnVhbCBFRCByZXN1bHRzIAojIFJldHVybjogZGF0YSB0YWJsZSBvZiB0aGUgZGltZW5zaW9ucyBvZiBzdGFiaWxpdHkuIApjYWxjdWxhdGVfZGltZW5zaW9uc19zdGFiaWxpdHkgPC0gZnVuY3Rpb24oZCl7CiAgCiMgQ2hlY2sgaW5wdXRzIApyZXFfbmFtZXMgPC0gYygnc2NuJywgJ3llYXInLCAndmFyaWFibGUnLCAnZGVzY3JpcHRpb24nLCAndW5pdCcsICd2YWx1ZScsICdtZXQnKQphc3NlcnRfdGhhdChoYXNfbmFtZShkLCByZXFfbmFtZXMpKQoKYmFzZWxpbmVfc2NuIDwtICJoYXJ2ZXN0XzBfMWRheV9hYm92ZSIgCmFzc2VydF90aGF0KGJhc2VsaW5lX3NjbiAlaW4lIGQkc2NuKQoKIyBTZXBhcmF0ZSB0aGUgY29udHJvbCBvciBiYXNlbGluZSBzY25lYXJpbyB2YWx1ZXMgZnJvbSB0aGUgb3V0cHV0IGZyb20gdGhlIG90aGVyIAojIHRyZWF0bWVudCBncm91cHMuIApiYXNlbGluZV92YWx1ZXMgPC0gZFtzY24gPT0gYmFzZWxpbmVfc2NuXVsgLCBjKCJ5ZWFyIiwgInZhcmlhYmxlIiwgInZhbHVlIiwgIm1ldCIpXQpuYW1lcyhiYXNlbGluZV92YWx1ZXMpIDwtIGMoInllYXIiLCAidmFyaWFibGUiLCAiYmFzZWxpbmUiLCAibWV0IikKdHJlYXRtZW50X3ZhbHVlcyA8LSBkW3NjbiAhPSBiYXNlbGluZV9zY25dWyAsIGMoInNjbiIsICJ5ZWFyIiwgInZhcmlhYmxlIiwgImRlc2NyaXB0aW9uIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ1bml0IiwgInRyZWF0bWVudCIgPSAidmFsdWUiLCAibWV0IiwgImxhYmVsIildCm5hbWVzKHRyZWF0bWVudF92YWx1ZXMpIDwtIGMoInNjbiIsICJ5ZWFyIiwgInZhcmlhYmxlIiwgImRlc2NyaXB0aW9uIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ1bml0IiwgInRyZWF0bWVudCIsICJtZXQiLCAibGFiZWwiKQojIENvbWJpbmUgdGhlIGNvbnRyb2wgYW5kIHRoZSB0cmVhdG1lbnQgdmFsdWVzIGFzIGEgd2lkZSBkZiwgdGhlbiB0YWtlIHRoZSAjIGxuKHRyZWF0bWVudC9jb250cm9sKSBwZXIgeWVhciAvIHZhcmlhYmxlIC8gbWV0IHJlYWxpemF0aW9uLiAKZGlzdHVyYmFuY2VfZCA8LSB0cmVhdG1lbnRfdmFsdWVzW2Jhc2VsaW5lX3ZhbHVlcywgb24gPSBjKCJ5ZWFyIiwgInZhcmlhYmxlIiwgIm1ldCIpXVt5ZWFyICVpbiUgMjAxOToyMDUwXQpkaXN0dXJiYW5jZV9kWyAsIHZhbHVlIDo9IGxvZyh0cmVhdG1lbnQvYmFzZWxpbmUpXQoKIyBOb3cgdGhhdCB0aGUgbG4odHJlYXRtZW50L2NvbnRyb2wpIGhhcyBiZWVuIGNhbGN1bGF0ZWQgd2UgY2FuIHVzZSB0aGVzZSB2YWx1ZXMgdG8gY2FsY3VsYXRlCiMgdGhlIHZhcmlvdXMgZGltZW5zaW9ucyBvZiBlY29zeXN0ZW0gc3RhYmlsaXR5LiAKdHJlYXRtZW50X3lyIDwtIDIwMTkgIyBUaGUgeWVhciBvZiB0aGUgZ2lyZGVsIAoKIyBSZXNpc3RhbmNlOiAke3J9X3t0fSA9IGxuKFxmcmFje3tGfV97ZGlzdHVyYmFuY2V9fXt7Rn1fe2NvbnRyb2x9fSkkIGF0IHRoZSB5ZWFyIHllYXIgCiMgb2YgZGlzdHVyYWJuY2UgKDIwMTkpLiAKcmVzaXRhbmNlX2QgPC0gZGlzdHVyYmFuY2VfZFt5ZWFyID09IHRyZWF0bWVudF95cl1bICwgYygic2NuIiwgInZhcmlhYmxlIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiZGVzY3JpcHRpb24iLCAidW5pdCIsICJtZXQiLCAgInZhbHVlIildCm5hbWVzKHJlc2l0YW5jZV9kKSA8LSBjKCJzY24iLCAidmFyaWFibGUiLCAiZGVzY3JpcHRpb24iLCAidW5pdCIsICJtZXQiLCAgInJlc2l0YW5jZSIpCgojIFJlc2lsaWVuY2UgOiAke3J9X3tpfSA9IGxuKFxmcmFje3tGfV97ZGlzdHVyYmFuY2V9fXt7Rn1fe2NvbnRyb2x9fSkgPSBpICsge3J9X3tpfSAqIHQkCiMgQ2FsY3VsYXRlIHRoZSByZXNpbGllbmNlICh0aGUgc2xvcGUgb2YgdGhlIHJlY292ZXJ5IHN0YXJ0aW5nIGF0IHRoZSB0cmVhdG1lbnRfeXIpCmRfdG9fdXNlIDwtIGRpc3R1cmJhbmNlX2RbeWVhciA+PSAyMDE5ICYgeWVhciA8PSAyMDMwXSAjIERvIG5vdCBpbmNsdWRlIGRhdGEgZnJvbSBwcmUgdHJlYXRtZW50IHllYXJzLiAKCiMgR2V0IHRoZSByZXN1bHQgZnJvbSB0aGUgbGluZWFyIHJlZ3Jlc3Npb24gcGVyIHZhcmlhYmxlIC8gc2NuIC8gbWV0IGVuc2VtYmxlIG1lbWJlci4gCmRfbGlzdCA8LSBzcGxpdChkX3RvX3VzZSwgaW50ZXJhY3Rpb24oZF90b191c2UkdmFyaWFibGUsIGRfdG9fdXNlJHNjbiwgZF90b191c2UkbWV0KSwgCiAgICAgICAgICAgICAgICBkcm9wID0gVFJVRSkgCmZpdHMgPC0gbGFwcGx5KGRfbGlzdCwgZnVuY3Rpb24oaW5wdXQpe2xtKHZhbHVlIH4geWVhciwgZGF0YSA9IGlucHV0KX0pCgojIEdldCB0aGUgc2xvcGUgZnJvbSB0aGUgZml0cywgdGhpcyBpcyB0aGUgcmVzaWxpZW5jZSB2YWx1ZS4gCnJlc2lsaWVuY2VfdmFsdWVzIDwtIHNhcHBseShmaXRzLCBmdW5jdGlvbih4KXt4JGNvZWZmaWNpZW50c1syXX0pCnJlc2lsaWVuY2VfZCA8LSBkYXRhLnRhYmxlKGluZm8gPSBuYW1lcyhyZXNpbGllbmNlX3ZhbHVlcyksIHJlc2lsaWVuY2UgPSByZXNpbGllbmNlX3ZhbHVlcykKcmVzaWxpZW5jZV9kIDwtIHJlc2lsaWVuY2VfZFssIGMoInZhcmlhYmxlIiwgInNjbiIsICJtZXQiLCAieCIpIDo9IHRzdHJzcGxpdChpbmZvLCAiLiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZml4ZWQ9VFJVRSldCnJlc2lsaWVuY2VfZCA8LSByZXNpbGllbmNlX2RbLCBjKCJyZXNpbGllbmNlIiwgInZhcmlhYmxlIiwgInNjbiIsICJtZXQiKV0KCiMgTm93IHVzaW5nIHRoZSBmaXRzIGNhbGN1bGF0ZSB0aGUgdGVtcG9yYWwgc3RhYmlsaXR5LiAKIyAke3N9X3t0fSA9IFxmcmFjezF9eyBTRSBvZiByZXNpZH0kCnNlX3Jlc2lkIDwtIHNhcHBseShmaXRzLCBmdW5jdGlvbihtb2RlbCl7c3FydChkZXZpYW5jZShtb2RlbCkvZGYucmVzaWR1YWwobW9kZWwpKX0pCnRlbXBfc3RhYmlsaXR5X2QgPC0gZGF0YS50YWJsZShpbmZvID0gbmFtZXMoc2VfcmVzaWQpLCB0ZW1wX3N0YWJpbGl0eSA9IDEvc2VfcmVzaWQpCnRlbXBfc3RhYmlsaXR5X2QgPC0gdGVtcF9zdGFiaWxpdHlfZFssIGMoInZhcmlhYmxlIiwgInNjbiIsICJtZXQiKSA6PSB0c3Ryc3BsaXQoaW5mbywgIi4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpeGVkPVRSVUUpXQp0ZW1wX3N0YWJpbGl0eV9kIDwtIHRlbXBfc3RhYmlsaXR5X2RbLCBjKCJ0ZW1wX3N0YWJpbGl0eSIsICJ2YXJpYWJsZSIsICJzY24iLCAibWV0IildCgojIEZpbmFsbHkgY2FsY3VsYXRlIHRoZSByZWNvdmVyeSwgZm9yIG5vdyB3ZSB3aWxsIGRlZmluZSByZWNvdmVyeSBhdCB5ZWFyIDIwMzkKIyB0d28gZGVjYWRlcyBhZnRlciB0aGUgeWVhciBvZiB0aGUgZ2lyZGVsLiAKcmVjb3ZlcnlfZCA8LSBkaXN0dXJiYW5jZV9kW3llYXIgPT0gMjAzMF0KcmVjb3ZlcnlfZCA8LSByZWNvdmVyeV9kWyAsIGMoInNjbiIsICJ2YXJpYWJsZSIsICJkZXNjcmlwdGlvbiIsICJ1bml0IiwgIm1ldCIsICAidmFsdWUiKV0KbmFtZXMocmVjb3ZlcnlfZCkgPC0gYygic2NuIiwgInZhcmlhYmxlIiwgImRlc2NyaXB0aW9uIiwgInVuaXQiLCAibWV0IiwgICJyZWNvdmVyeSIpCnJlY292ZXJ5X2QkcmVjb3ZlcnkgPC0gcmVjb3ZlcnlfZCRyZWNvdmVyeQoKIyBDb21iaW5lIGFsbCBkaW1lbnNpb25zIG9mIHN0YWJpbGl0eSBpbnRvIGEgc2luZ2xlIGRhdGEgdGFibGUuIApyZXNpdGFuY2VfZFtyZXNpbGllbmNlX2QsIG9uID0gYygidmFyaWFibGUiLCAic2NuIiwgIm1ldCIpXSAlPiUgCiAgLlt0ZW1wX3N0YWJpbGl0eV9kLCBvbiA9IGMoInZhcmlhYmxlIiwgInNjbiIsICJtZXQiKV0gJT4lIAogIC5bcmVjb3ZlcnlfZCwgb24gPSBjKCJ2YXJpYWJsZSIsICJzY24iLCAibWV0IildICU+JSAKICAuWywgYyggInNjbiIsICJ2YXJpYWJsZSIsICJkZXNjcmlwdGlvbiIsICJ1bml0IiwgIm1ldCIsICJyZXNpdGFuY2UiLCAKICAgICAgICAgInJlc2lsaWVuY2UiLCAidGVtcF9zdGFiaWxpdHkiLCAicmVjb3ZlcnkiKV0gLT4gCiAgZHQgCgojIEFkZCB0aGUgZGlzdHVyYmFuY2Ugc2V2ZXJpdHkgY29sdW1uLiAKZHQkYERpc3R1cmJhbmNlIFNldmVyaXR5YCA8LSBwYXN0ZTAoZ3N1Yih4ID0gZHQkc2NuLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiaGFydmVzdF98XzFkYXlfYWJvdmUiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXBsYWNlbWVudCA9ICIiKSwgIiAlIikKCiMgRm9ybWF0IGFuZCBhcHBseSBmYWN0b3IgaW5mb3JtYXRpb24gdG8gdGhlIHZhcmlhYmxlIG5hbWUgc28gdGhlIGRpbWVuc2lvbnMgb2Ygc3RhYmlsaXR5IHBsb3QgCiMgc3RlcCB0aHJvdWdoIHRoZSBjYXJib24gY3ljbGUgaW4gb3JkZXIgR1BQIC0+IE5QUCAtPiBORVAuIApkdCR2YXJpYWJsZSA8LSBnc3ViKHBhdHRlcm4gPSAiX3BhdGNoIiwgcmVwbGFjZW1lbnQgPSAiIiwgeCA9IGR0JHZhcmlhYmxlKQpkdCR2YXJpYWJsZSA8LSBmYWN0b3IoeCA9IGR0JHZhcmlhYmxlLCBsZXZlbHMgPSBjKCJHUFAiLCAiTlBQIiwgIk5FUCIpLCBvcmRlcmVkID0gVFJVRSkKZHQgPC0gbmEub21pdChkdCkKcmV0dXJuKGR0KQoKfQoKc3RhYmlsaXR5X21ldHJpY3MgPC0gY2FsY3VsYXRlX2RpbWVuc2lvbnNfc3RhYmlsaXR5KGFubnVhbF9kYXRhKQpgYGAKCgoKIyMgUGxvdCBSZXNpc3RhbmNlIAoKJHtyfV97dH0gPSBsbihcZnJhY3t7Rn1fe2Rpc3R1cmJhbmNlfX17e0Z9X3tjb250cm9sfX0pJAoKV2hlbiAkJHt0fSQkIGlzIHRoZSB5ZWFyIG9mIHRoZSBkaXN0dXJiYW5jZSwgaW4gdGhpcyBjYXNlIDIwMTkuIAoKYGBge3J9CnN0YWJpbGl0eV9tZXRyaWNzICU+JSAKICBnZ3Bsb3QoYWVzKGBEaXN0dXJiYW5jZSBTZXZlcml0eWAsIHJlc2l0YW5jZSwgY29sb3IgPSBgRGlzdHVyYmFuY2UgU2V2ZXJpdHlgKSkgKyAKICBnZW9tX3BvaW50KHNpemUgPSAyLCBhbHBoYSA9IDAuNCkgKyAKICBmYWNldF93cmFwKCd2YXJpYWJsZScpICsgCiAgVEhFTUUgICsgCiAgbGFicyh0aXRsZSA9ICdSZXNpc3RhbmNlJywgeSA9ICcyMDE5IGxuKEYgZGlzdHVyYWJuY2UgLyBGIGJhc2VsaW5lKScpICsgCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IEZPUlRFX1NFVkVSSVRZX0NPTE9SUykgCmBgYAoKIyMgUGxvdCBSZXNpbGllbmNlIAoKJHtyfV97aX0gPSBsbihcZnJhY3t7Rn1fe2Rpc3R1cmJhbmNlfX17e0Z9X3tjb250cm9sfX0pID0gaSArIHtyfV97aX0gKiB0JAoKCgpgYGB7cn0Kc3RhYmlsaXR5X21ldHJpY3MgJT4lICAKZ2dwbG90KCkgKyAKICBnZW9tX3BvaW50KGFlcyhgRGlzdHVyYmFuY2UgU2V2ZXJpdHlgLCByZXNpbGllbmNlLCBjb2xvciA9IGBEaXN0dXJiYW5jZSBTZXZlcml0eWApLAogICAgICAgICAgICAgc2l6ZSA9IDIsIGFscGhhID0gMC40KSArIAogIGZhY2V0X3dyYXAoJ3ZhcmlhYmxlJykgKyAKICBUSEVNRSAgKyAKICBsYWJzKHRpdGxlID0gJ1Jlc2lsaWVuY2UnLCB5ID0gJ1Nsb3BlIGxuKGRpc3QvY29udHJvbCknKSArIAogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBGT1JURV9TRVZFUklUWV9DT0xPUlMpCgpgYGAKCgojIyBQbG90IFRlbXBvcmFsIFN0YWJpbGl0eSAKCiR7c31fe3R9ID0gXGZyYWN7MX17IFNFIG9mIHJlc2lkfSQKCmBgYHtyfQpzdGFiaWxpdHlfbWV0cmljcyAlPiUgIApnZ3Bsb3QoKSArIAogIGdlb21fcG9pbnQoYWVzKGBEaXN0dXJiYW5jZSBTZXZlcml0eWAsIHRlbXBfc3RhYmlsaXR5LCBjb2xvciA9IGBEaXN0dXJiYW5jZSBTZXZlcml0eWApLAogICAgICAgICAgICAgc2l6ZSA9IDIsIGFscGhhID0gMC40KSArIAogIGZhY2V0X3dyYXAoJ3ZhcmlhYmxlJykgKyAKICBUSEVNRSAgKyAKICBsYWJzKHRpdGxlID0gJ1RlbXBvcmFsIFN0YWJpbGl0eScsIAogICAgICAgeSA9ICcgMSAvIChTRSBvZiByZXNpZCknKSArIAogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBGT1JURV9TRVZFUklUWV9DT0xPUlMpCmBgYAoKCgojIyBQbG90IFJlY292ZXJ5IAoKClRha2UgYSBsb29rIGF0IHRoZSByZWNvdmVyeSBhdCBzZXBhcmF0ZSB0aW1lIHN0ZXBzLiAKCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IHJlY292ZXJ5X2F0X1hfZGF0YVsgLCB5ZWFyIDo9IGFzLmNoYXJhY3Rlcih5ZWFyKV0sIAogICAgICAgYWVzKHggPSB5ZWFyLCB5ID0gcmVjb3ZlcnksIGZpbGwgPSBgRGlzdHVyYmFuY2UgU2V2ZXJpdHlgKSkgKyAKICBnZW9tX2JveHBsb3QoKSArIAogIFRIRU1FICsgCiAgbGFicyh4ID0gJ1llYXInLCB5ID0gImxuKGRpc3R1cmJhbmNlL2Jhc2VsaW5lKSIsIHRpdGxlID0gIlJlY292ZXJ5IGF0IFllYXIiKSArIAogIGZhY2V0X3dyYXAoInZhcmlhYmxlIiwgbmNvbCA9IDEsIHNjYWxlcyA9ICJmcmVlIikKYGBgCgoKUmVjb3ZlcnkgMiBkZWNhZGVzIGFmdGVyIHRoZSB0cmVhdG1lbnQuIAoKCmBgYHtyfQpzdGFiaWxpdHlfbWV0cmljcyAlPiUgIApnZ3Bsb3QoKSArIAogIGdlb21fcG9pbnQoYWVzKGBEaXN0dXJiYW5jZSBTZXZlcml0eWAsIHJlY292ZXJ5LCBjb2xvciA9IGBEaXN0dXJiYW5jZSBTZXZlcml0eWApLAogICAgICAgICAgICAgc2l6ZSA9IDIsIGFscGhhID0gMC40KSArIAogIGZhY2V0X3dyYXAoJ3ZhcmlhYmxlJykgKyAKICBUSEVNRSAgKyAKICBsYWJzKHRpdGxlID0gJ1JlY292ZXJ5JywgCiAgICAgICB5ID0gJ1JlY292ZXJ5IGF0IDIwMzAnKSArIAogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBGT1JURV9TRVZFUklUWV9DT0xPUlMpCmBgYAoKIyBJbnB1dCAmIE1ldHJpYyBJbnRlcmFjdGlvbnMKCgpgYGB7ciwgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nPUZBTFNFfQojIENyZWF0ZSBhIGRhdGEgZnJhbWUgb2YgdGhlIGRpc3R1cmJhbmNlIHBlcmlvZCBhbm51YWwgbWV0IGlucHV0cywgbm90ZSB0aGF0IGl0IHNob3VsZCBiZSAKIyBhIHdpZGUgZGF0YSBmcmFtZSBpbiBwcmVwZXJhdGlvbiBmb3IgdGhlIHBhaXIgd2lzZSBwbG90cy4gCmRhdGFbeWVhciA9PSAyMDE5XVsgLCBjKCJ2YXJpYWJsZSIsICJ2YWx1ZSIsICJzY24iKV0gJT4lCiAgdW5pcXVlKCkgJT4lIAogIHNldG5hbWVzKG9sZCA9IGMoInNjbiIsICJ2YWx1ZSIsICJ2YXJpYWJsZSIpLCAKICAgICAgICAgICBuZXcgPSBjKCJtZXQiLCAibWV0X3Zhdmx1ZSIsICJtZXRfdmFyaWFibGUiKSkgLT4gCiAgZGlzdF9tZXRfZGF0YQoKIyBDb21iaW5lIHRoZSBtZXQgYW5kIHRoZSBkaW1lbnNpb25zIG9mIHN0YWJpbGl0eSBkYXRhIGludG8gYSBzaW5nbGUgZGF0YSBmcmFtZS4gCnN0YWJpbGl0eV9tZXRyaWNzWyAsIGMoInNjbiIsICJ2YXJpYWJsZSIsICJtZXQiLCAicmVzaXRhbmNlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgInJlc2lsaWVuY2UiLCAidGVtcF9zdGFiaWxpdHkiLCAicmVjb3ZlcnkiLCAiRGlzdHVyYmFuY2UgU2V2ZXJpdHkiKV0gJT4lCiAgbWVsdChpZC52YXJzID0gYygic2NuIiwgInZhcmlhYmxlIiwgIm1ldCIsICJEaXN0dXJiYW5jZSBTZXZlcml0eSIpLAogICAgICAgbWVhc3VyZS52YXJzID0gYygicmVzaXRhbmNlIiwgInJlc2lsaWVuY2UiLCAidGVtcF9zdGFiaWxpdHkiLCAicmVjb3ZlcnkiKSwgCiAgICAgICB2YXJpYWJsZS5uYW1lID0gIm1ldHJpY19uYW1lIiwgdmFsdWUubmFtZSA9ICJtZXRyaWNfdmFsdWUiKSAlPiUgCiAgdW5pcXVlKCkgLT4gCiAgbWV0cmljX2xvbmcKCmZ1bGxfZGYgPC0gZGlzdF9tZXRfZGF0YVttZXRyaWNfbG9uZywgb24gPSAibWV0IiwgYWxsb3cuY2FydGVzaWFuPVRSVUVdCmBgYAoKCmBgYHtyfQp2YXJfbGlzdCA8LSB1bmlxdWUoZnVsbF9kZiR2YXJpYWJsZSkKbWV0cmljICAgPC0gdW5pcXVlKGZ1bGxfZGYkbWV0cmljX25hbWUpCmZ1bGxfZGYgIDwtIGZ1bGxfZGZbdmFyX2luZm8sIG9uID0gLihtZXRfdmFyaWFibGUgPSB2YXJpYWJsZSldIAoKbGFwcGx5KG1ldHJpYywgZnVuY3Rpb24obSl7CiAgIyAgJiBtZXRfdmFyaWFibGUgJWluJSBjKCJwcmF0ZSIsICJ0bXAiLCAic2giKQogIGZ1bGxfZGZbbWV0cmljX25hbWUgPT0gbV0gJT4lIAogIGdncGxvdChhZXMobWV0X3Zhdmx1ZSwgbWV0cmljX3ZhbHVlLCBjb2xvciA9IGBEaXN0dXJiYW5jZSBTZXZlcml0eWApKSArIAogIGdlb21fcG9pbnQoKSArIAogIGZhY2V0X2dyaWQodmFyaWFibGUgfiBkZXNjcmlwdGlvbiwgc2NhbGVzID0gImZyZWUiLCAgbGFiZWxsZXIgPSBsYWJlbF93cmFwX2dlbih3aWR0aCA9IDIwLCBtdWx0aV9saW5lID0gVFJVRSkpICsgCiAgVEhFTUUgKyAKICBsYWJzKHkgPSBOVUxMLCB4ID0gTlVMTCwgdGl0bGUgPSBtKSArIAogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKSArIAogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBGT1JURV9TRVZFUklUWV9DT0xPUlMpCn0pIC0+IAogIHBsb3RzCm5hbWVzKHBsb3RzKSA8LSBtZXRyaWMKYGBgCgojIyBQbG90IElucHV0IHggUmVzaXRhbmNlCgpgYGB7ciwgZmlnLndpZHRoPTZ9CnBsb3RzJHJlc2l0YW5jZSArIAogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIHZqdXN0ID0gMC41LCBoanVzdD0wLjUpKQpgYGAKCiMjIFBsb3QgSW5wdXQgeCBSZXNpbGllbmNlCgpgYGB7ciwgZmlnLndpZHRoPTZ9CnBsb3RzJHJlc2lsaWVuY2UgKyAKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCB2anVzdCA9IDAuNSwgaGp1c3Q9MC41KSkKYGBgCgojIyBQbG90IElucHV0IHggVGVtcG9yYWwgU3RhYmlsaXR5CgpgYGB7ciwgZmlnLndpZHRoPTZ9CnBsb3RzJHRlbXBfc3RhYmlsaXR5ICsgCiAgbGFicyh0aXRsZSA9ICJUZW1wb3JhbCBTdGFiaWxpdHkiKSArIAogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIHZqdXN0ID0gMC41LCBoanVzdD0wLjUpKQpgYGAKCiMjIFBsb3QgSW5wdXQgeCBSZWNvdmVyeQoKYGBge3IsIGZpZy53aWR0aD02fQpwbG90cyRyZWNvdmVyeSArIAogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIHZqdXN0ID0gMC41LCBoanVzdD0wLjUpKQpgYGAKCiMgRHluYW1pYyBSZWNvdmVyeSAKCgpgYGB7cn0KCiMgQ2FsY3VsYXRlIHRoZSBsbihkaXN0dXJiYW5jZS9jb250cm9sKQojIEFyZ3MgCiMgICBkOiBhIGRhdGEgZnJhbWUgb2YgdGhlIGFudWFsIGRhdGEgCiMgUmV0dXJuOiBhIGRhdGEgZnJhbWUgb2YgdGhlIGxuKGRpc3R1cmJhbmNlL2NvbnRyb2wpIHBlciB5ZWFyL3ZhcmlhYmxlL21ldC9kaXN0dXJiYW5jZSBzZXZlcml0eSAKY2FsY19sbl9kaXN0dXJiYW5jZSA8LSBmdW5jdGlvbihkKXsKICAKICAjIENoZWNrIGlucHV0cyAKICByZXFfbmFtZXMgPC0gYygnc2NuJywgJ3llYXInLCAndmFyaWFibGUnLCAnZGVzY3JpcHRpb24nLCAndW5pdCcsICd2YWx1ZScsICdtZXQnKQogIGFzc2VydF90aGF0KGhhc19uYW1lKGQsIHJlcV9uYW1lcykpCiAgCiAgYmFzZWxpbmVfc2NuIDwtICJoYXJ2ZXN0XzBfMWRheV9hYm92ZSIgCiAgYXNzZXJ0X3RoYXQoYmFzZWxpbmVfc2NuICVpbiUgZCRzY24pCiAgCiAgIyBTZXBhcmF0ZSB0aGUgY29udHJvbCBvciBiYXNlbGluZSBzY25lYXJpbyB2YWx1ZXMgZnJvbSB0aGUgb3V0cHV0IGZyb20gdGhlIG90aGVyIAogICMgdHJlYXRtZW50IGdyb3Vwcy4gCiAgYmFzZWxpbmVfdmFsdWVzIDwtIGRbc2NuID09IGJhc2VsaW5lX3Njbl1bICwgYygieWVhciIsICJ2YXJpYWJsZSIsICJ2YWx1ZSIsICJtZXQiKV0KICBuYW1lcyhiYXNlbGluZV92YWx1ZXMpIDwtIGMoInllYXIiLCAidmFyaWFibGUiLCAiYmFzZWxpbmUiLCAibWV0IikKICB0cmVhdG1lbnRfdmFsdWVzIDwtIGRbc2NuICE9IGJhc2VsaW5lX3Njbl1bICwgYygic2NuIiwgInllYXIiLCAidmFyaWFibGUiLCAiZGVzY3JpcHRpb24iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInVuaXQiLCAidHJlYXRtZW50IiA9ICJ2YWx1ZSIsICJtZXQiKV0KICBuYW1lcyh0cmVhdG1lbnRfdmFsdWVzKSA8LSBjKCJzY24iLCAieWVhciIsICJ2YXJpYWJsZSIsICJkZXNjcmlwdGlvbiIsICJ1bml0IiwgInRyZWF0bWVudCIsICJtZXQiKQogIAogICMgQ29tYmluZSB0aGUgY29udHJvbCBhbmQgdGhlIHRyZWF0bWVudCB2YWx1ZXMgYXMgYSB3aWRlIGRmLCB0aGVuIHRha2UgdGhlICMgbG4odHJlYXRtZW50L2NvbnRyb2wpIHBlciB5ZWFyIC8gdmFyaWFibGUgLyBtZXQKICAjIHJlYWxpemF0aW9uLiAKICBkaXN0dXJiYW5jZV9kIDwtIHRyZWF0bWVudF92YWx1ZXNbYmFzZWxpbmVfdmFsdWVzLCBvbiA9IGMoInllYXIiLCAidmFyaWFibGUiLCAibWV0IildW3llYXIgJWluJSAyMDE5OjIwNTBdCiAgZGlzdHVyYmFuY2VfZCA8LSBkaXN0dXJiYW5jZV9kWyAsIHZhbHVlIDo9IGxvZyh0cmVhdG1lbnQvYmFzZWxpbmUpXQogIGRpc3R1cmJhbmNlX2QgPC0gZGlzdHVyYmFuY2VfZFsgLCBkaXN0dXJiYW5jZV9zZXZlcml0eSA6PSBwYXN0ZTAoZ3N1Yih4ID0gc2NuLCBwYXR0ZXJuID0gImhhcnZlc3RffF8xZGF5X2Fib3ZlIiwgcmVwbGFjZW1lbnQgPSAiIiksICIgJSIpXQogIGRpc3R1cmJhbmNlX2QgPC0gZGlzdHVyYmFuY2VfZFsgLCB2YXJpYWJsZSA6PSAgZ3N1YihwYXR0ZXJuID0gIl9wYXRjaCIsIHJlcGxhY2VtZW50ID0gIiIsIHggPSB2YXJpYWJsZSldCiAgZGlzdHVyYmFuY2VfZCR2YXJpYWJsZSA8LSBmYWN0b3IoeCA9IGRpc3R1cmJhbmNlX2QkdmFyaWFibGUsIGxldmVscyA9IGMoIkdQUCIsICJOUFAiLCAiTkVQIiksIG9yZGVyZWQgPSBUUlVFKQogIGRpc3R1cmJhbmNlX2QgPC0gZGlzdHVyYmFuY2VfZFsgLCAuKHllYXIsIHZhcmlhYmxlLCBtZXQsIHZhbHVlLCBkaXN0dXJiYW5jZV9zZXZlcml0eSldCiAgZGlzdHVyYmFuY2VfZCA8LSBuYS5vbWl0KGRpc3R1cmJhbmNlX2QpCiAgZGlzdHVyYmFuY2VfZCA8LSBkaXN0dXJiYW5jZV9kW3llYXIgJWluJSAyMDE5OjIwNTBdCiAgCiAgcmV0dXJuKGRpc3R1cmJhbmNlX2QpCn0KCmRpc3R1cmJhbmNlIDwtIGNhbGNfbG5fZGlzdHVyYmFuY2UoYW5udWFsX2RhdGEpCgojIERlZmluZSB0aGUgZnVuY3Rpb25zIHRvIGJlIHVzZWQgYnkgZnJvbGxhcHBseSB0byBnZXQgdGhlIGZpdHMgZnJvbSB0aGUgcm9sbGluZyBzbG9wZXMgCnNsb3BlX2Z1bmMgPC0gZnVuY3Rpb24odmFsdWUpewogIAogIGFzc2VydF90aGF0KGlzLnZlY3Rvcih2YWx1ZSkpCiAgc3EgPC0gc2VxKDE6bGVuZ3RoKHZhbHVlKSkKICBmaXQgPC0gbG0odmFsdWV+c3EpCiAgCiAgc2xvcGUgPC0gY29lZihmaXQpWzJdCiAgbmFtZXMoc2xvcGUpIDwtICJzbG9wZSIKICByZXR1cm4oc2xvcGUpCiAgCn0KaW50ZXJjZXB0X2Z1bmMgPC0gZnVuY3Rpb24odmFsdWUpewogIAogIGFzc2VydF90aGF0KGlzLnZlY3Rvcih2YWx1ZSkpCiAgc3EgPC0gc2VxKDE6bGVuZ3RoKHZhbHVlKSkKICBmaXQgPC0gbG0odmFsdWV+c3EpCiAgCiAgaW50ZXIgPC0gY29lZihmaXQpWzFdCiAgbmFtZXMoaW50ZXIpIDwtICJ5LWludGVyY2VwdCIKICByZXR1cm4oaW50ZXIpCiAgCn0KCiMgQXBwbHkgdGhlIHNsb3BlIGFuZCBpbnRlcmNlcHQgZnVuY3Rpb25zIHRvIGVhY2ggdmFyaWFibGUgLyBtZXQgLyBzZXZlcml0eSBkaXN0dXJiYW5jZSB2YWx1ZXMuIApzcGxpdChkaXN0dXJiYW5jZSwKICAgICAgaW50ZXJhY3Rpb24oZGlzdHVyYmFuY2UkdmFyaWFibGUsIGRpc3R1cmJhbmNlJG1ldCwgZGlzdHVyYmFuY2UkZGlzdHVyYmFuY2Vfc2V2ZXJpdHkpKSAlPiUgCiAgbGFwcGx5KGZ1bmN0aW9uKHgpewogICAgCiAgICB3aW5kb3cgPC0gNQogICAgc2xvcGUgPC0gZnJvbGxhcHBseSh4ID0geFtbInZhbHVlIl1dLCBuID0gd2luZG93LCBGVU4gPSBzbG9wZV9mdW5jLCBhbGlnbiA9ICJsZWZ0IikKICAgIHNsb3BlMiA8LSBmcm9sbGFwcGx5KHggPSBzbG9wZSwgbiA9IHdpbmRvdywgRlVOID0gc2xvcGVfZnVuYywgYWxpZ24gPSAibGVmdCIpCiAgICAKICAgIG91dCA8LSBjYmluZCh4LCBzbG9wZSA9IHNsb3BlLCBzbG9wZTIgPSBzbG9wZTIpCiAgICByZXR1cm4ob3V0KQogICAgCiAgfSkgJT4lIAogIHJiaW5kbGlzdCAlPiUgIAogIG5hLm9taXQgLT4gCiAgZGlzdF9zbG9wZV95CmBgYAoKIyMgUGxvdCBvZiBEaXN0dXJiYW5jZSBSYXRlIG9mIENoYW5nZSAKClRoaXMgaXMgdGhlIGZpcnN0IGRlcml2YXRpdmUsIHRoZSByYXRlIG9mIGNoYW5nZSBvZiBkaXN0dXJhYm5jZSwgd2Ugd2VyZSBpbnRyZXN0ZWQgaW4gd2hlbiB0aGlzIGlzIDAsIGlmIHRoYXQgd291bGQgYmUgdGhlIHJlY292ZXJ5IHBvaW50IGJlY2FjdXNlIHRoYXQgd291bGQgcmVmZWxlY3Qgd2hlbiB0aGUgZWNvc3lzdGVtIGhhcyByZWFjaGVkIGEgbmV3IHN0ZWFkeSBzdGF0ZS4uLiAKCgpgYGB7cn0KZ2dwbG90KGRhdGEgPSBkaXN0X3Nsb3BlX3lbeWVhciAlaW4lIDIwMTk6MjA1MF0pICsKIGdlb21faGxpbmUoYWVzKHlpbnRlcmNlcHQgPSAwKSkgKwogZ2VvbV9saW5lKGFlcyh5ZWFyLCBzbG9wZSwgZ3JvdXAgPSBpbnRlcmFjdGlvbihkaXN0dXJiYW5jZV9zZXZlcml0eSwgbWV0KSksIGNvbG9yID0gImdyZXkiLCBhbHBoYSA9IDAuMykgKwogZ2VvbV9wb2ludChhZXMoeWVhciwgc2xvcGUsIGNvbG9yID0gZGlzdHVyYmFuY2Vfc2V2ZXJpdHksIGdyb3VwID0gaW50ZXJhY3Rpb24oZGlzdHVyYmFuY2Vfc2V2ZXJpdHksIG1ldCkpKSArCiBmYWNldF93cmFwKCJ2YXJpYWJsZSIsIHNjYWxlcyA9ICJmcmVlIiwgbmNvbCA9IDEpICsKIHRoZW1lX2J3KCkgKwogbGFicyh0aXRsZSA9ICI1IHllYXIgcnVubmluZyBzbG9wZSIpCmBgYAoKCmBgYHtyfQojIFNlbGV0IHRoZSByZWNvdmVyeSB5ZWFycyBhcyB0aGUgeWVhcnMgd2hlcmUgdGhlIG1hbmduaXR1ZGUgb2YgdGhlIHJhdGUgb2YgY2hhbmdlIGlzIGxlc3MgdGhhbiAxZS0zIG9yIHNldCBhIAojIGhhcmQgbGltaXQgb2YgMjAzMCwgd2hpY2ggaXMgdW5pZGVhbCBidXQgZm9yIG5vdyBpdCBpcyBub3Qgbm90IHRvIGF2b2lkIHNvbWUgc29ydCBvZiBhcmJpdHJpYXR5IGN1dCBvZmYuIApyZWNvdmVyeV95ciA8LSBkaXN0X3Nsb3BlX3lbYWJzKHNsb3BlKSA8PSAxZS0zXVsgLCAuKHJlY292ZXJ5X3lyID0gbWluKHllYXIpKSwgYnkgPSAuKHZhcmlhYmxlLCBtZXQsIGRpc3R1cmJhbmNlX3NldmVyaXR5KV0gCnJlY292ZXJ5X3lyIDwtIHJlY292ZXJ5X3lyW3JlY292ZXJ5X3lyIDw9IDIwMzBdCgojIE5vdyBqb2luIHdpdGggdGhlIGRpc3VyYmFuY2UgdmFsdWVzLiAKcmVjb3ZlcnlfeXJbZGlzdHVyYmFuY2UsIG9uID0gYygidmFyaWFibGUiLCAibWV0IiwgImRpc3R1cmJhbmNlX3NldmVyaXR5IiksIG5vbWF0Y2ggPSBOQV0gJT4lIAogIC5bICwgcmVjb3ZlcnlfeXI6PSBpZmVsc2UodGVzdCA9IGlzLm5hKHJlY292ZXJ5X3lyKSwgeWVzID0gMjAzMCwgbm8gPSByZWNvdmVyeV95cildICU+JSAKICAuW3llYXIgPD0gcmVjb3ZlcnlfeXJdIC0+IAogIGRpc3R1cmJhbmNlX3JlY292ZXJ5X3N1YnNldAoKIyBGaW5kIHJlY292ZXJ5IHZhbHVlIGFrYSB0aGUgZGlzdHVyYmFuY2UgdmFsdWUgYXQgdGhlIHRpbWUgb2YgcmVjb3ZlcnkuIApyZWNvdmVyeV92YWx1ZXMgPC0gZGlzdHVyYmFuY2VfcmVjb3Zlcnlfc3Vic2V0WyB5ZWFyID09IHJlY292ZXJ5X3lyXQpgYGAKClVzaW5nIHdoZW4gdGhlIHJhdGUgb2YgY2hhbmdlIG9yIHJ1bm5pbmcgc2xvcGUgaXMgbGVzcyB0aGFuIG9yIGVxdWFsIHRvIDAgb3Igd2l0aCBhIGN1dCBvZmYgdGhlcmUgYXJlIG9ubHkgYSBoYW5kZnVsIG9mIHJ1bnMgdGhhdCByZWNvdmVyeSBvciByZWFjaCBhIG5ldyBzdGVhZCBzdGF0ZS4gIAoKYGBge3J9CnJlY292ZXJ5X3lyW2Rpc3R1cmJhbmNlLCBvbiA9IGMoInZhcmlhYmxlIiwgIm1ldCIsICJkaXN0dXJiYW5jZV9zZXZlcml0eSIpLCBub21hdGNoID0gTkFdICU+JSAKICMgLlsgLCByZWNvdmVyeV95cjo9IGlmZWxzZSh0ZXN0ID0gaXMubmEocmVjb3ZlcnlfeXIpLCB5ZXMgPSAyMDMwLCBubyA9IHJlY292ZXJ5X3lyKV0gJT4lIAogIC5beWVhciA8PSByZWNvdmVyeV95cl0gJT4lIAogIGdncGxvdChhZXMoeWVhciwgdmFsdWUsIGNvbG9yID0gZGlzdHVyYmFuY2Vfc2V2ZXJpdHksIGdyb3VwID0gaW50ZXJhY3Rpb24obWV0LCBkaXN0dXJiYW5jZV9zZXZlcml0eSkpKSArIAogIGdlb21fbGluZSgpICsgCiAgZmFjZXRfZ3JpZCh2YXJpYWJsZX5kaXN0dXJiYW5jZV9zZXZlcml0eSwgc2NhbGVzID0gImZyZWUiKSArIAogIGxhYnModGl0bGUgPSAiRHluYW1pYyBSZWNvdmVyeSIsIHkgPSAibG4odHJlYXRtZW50L2NvbnRyb2wpIikgKyAKICB0aGVtZV9idygpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQpgYGAKCgpXaGF0IGlmIHRoZSBjdXQgb2ZmIHZhbHVlIGlzIHdoZW4gdGhlIHJhdGUgb2ZmIGNoYW5nZSBpcyBsZXNzIHRoYW4gb3IgZXF1YWwgdG8gMCBvciBhdCBtb3N0IDIwMzA/IElmIHRoYXQgaXMgdGhlIGNhc2UgdGhlbiBvdXIgcmVzdWx0cyBsb29rIHNvbWV0aGluZyBsaWtlLiAKCgpgYGB7cn0KcmVjb3ZlcnlfeXJbZGlzdHVyYmFuY2UsIG9uID0gYygidmFyaWFibGUiLCAibWV0IiwgImRpc3R1cmJhbmNlX3NldmVyaXR5IiksIG5vbWF0Y2ggPSBOQV0gJT4lCiAgLlsgLCByZWNvdmVyeV95cjo9IGlmZWxzZSh0ZXN0ID0gaXMubmEocmVjb3ZlcnlfeXIpLCB5ZXMgPSAyMDMwLCBubyA9IHJlY292ZXJ5X3lyKV0gJT4lIAogIC5beWVhciA8PSByZWNvdmVyeV95cl0gJT4lIAogIGdncGxvdChhZXMoeWVhciwgdmFsdWUsIGNvbG9yID0gZGlzdHVyYmFuY2Vfc2V2ZXJpdHksIGdyb3VwID0gaW50ZXJhY3Rpb24obWV0LCBkaXN0dXJiYW5jZV9zZXZlcml0eSkpKSArIAogIGdlb21fbGluZSgpICsgCiAgZmFjZXRfZ3JpZCh2YXJpYWJsZX5kaXN0dXJiYW5jZV9zZXZlcml0eSwgc2NhbGVzID0gImZyZWUiKSArIAogIGxhYnModGl0bGUgPSAiRHluYW1pYyBSZWNvdmVyeSIsIHkgPSAibG4odHJlYXRtZW50L2NvbnRyb2wpIikgKyAKICB0aGVtZV9idygpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQpgYGAKCgpJcyBhIGxpbmVhciBmaXQgdGhlIHJpZ2h0IGZpdCBoZXJlPyBIb3cgZG8gd2UgZGVhbCB3aXRoIHRoZXNlIGRpZmZlcmVudCByZWNvdmVyeSBkYXRlcz8gCg==