Skip to contents

1 Import Data

# load wealingNES package
library(weanlingNES)

# load dataset
data("data_nes")
data("data_ses")

# merge into one dataset
data_comp <- rbind(
  rbindlist(data_nes$year_2018),
  rbindlist(data_ses$year_2014),
  use.names = T,
  fill = T
)

# remove outlier (i.e. dive duration > 5000 s)
data_comp <- data_comp[dduration < 5000, ]
data_comp[, diff_days := c(0, diff(day_departure)), by = .id]

# keep the first trip
data_comp_split <- split(data_comp, by = c(".id"))
data_comp_split_list <- lapply(data_comp_split, function(x) {
  # find the rows after 100 day_departure where diff_days > 1
  second_trip <- x[day_departure > 100 & diff_days > 1, ]
  # if there is a second trip
  if (nrow(second_trip) != 0) {
    # get the first date of this second trip
    date_cut <- second_trip[, min(date)]
    # return only the first trip
    return(x[date < date_cut, ])
    # if no second trip
  } else {
    # return the full dataset
    return(x)
  }
})

# rebuilt the dataset
data_comp <- rbindlist(data_comp_split_list)

# rename sp for viz purposes
data_comp %>% .[, sp_rename := fifelse(
  sp == "nes",
  "Northern elephant seal",
  "Southern elephant seal"
)]
# rename divetype for viz purposes
data_comp[, divetype_rename := divetype %>%
            word(2) %>%
            str_to_title()]

# set up colours
# https://davidmathlogic.com/colorblind/#%23D81B60-%231E88E5-%23FFC107-%23004D40
# https://thenode.biologists.com/data-visualization-with-flying-colors/research/
# https://color.adobe.com/create/color-accessibility
# colours <- c("#e08214", "#8073ac")
colours <- c("#E1BE6A", "#009E73")

2 Figures

Figure 1

# datasets
data_fig_sum <- data_comp[!is.na(lat) & .id %in% c(
  "ind_2018070",
  "ind_140072"
), ] %>%
  .[.id == "ind_2018070", .id := "Northern elephant seal: ID 2018070"] %>%
  .[.id == "ind_140072", .id := "Southern elephant seal: ID 140072"] %>%
  .[, .id := ordered(.id, levels = c(
    "Northern elephant seal: ID 2018070",
    "Southern elephant seal: ID 140072"
  ))]

# maxdepth
data_fig_sum_maxdepth <- melt(
  data_fig_sum[, .(
    date,
    maxdepth,
    day_departure,
    .id
  )],
  id.vars = c("date", "day_departure", ".id"),
  measure.vars = c("maxdepth")
)

# duration
data_fig_sum_dduration <- melt(
  data_fig_sum[, .(
    date,
    dduration,
    day_departure,
    .id
  )],
  id.vars = c("date", "day_departure", ".id"),
  measure.vars = c("dduration")
)

# driftrate
data_fig_sum_driftrate <- melt(
  data_fig_sum[divetype == "2: drift", .(
    driftrate = median(driftrate, na.rm = T),
    day_departure = first(day_departure)
  ),
  by = .(date = as.Date(date), .id)
  ],
  id.vars = c("date", "day_departure", ".id"),
  measure.vars = c("driftrate")
)

# bADL
data_fig_sum_adl <- melt(
  data_fig_sum[divetype == "1: foraging",
               .(
                 adl = round(quantile(dduration, 0.95) /
                               60),
                 day_departure = first(day_departure)
               ),
               by = .(date = as.Date(date), .id)
  ],
  id.vars = c("date", "day_departure", ".id"),
  measure.vars = c("adl")
)

# configure theme (to get gradient https://encycolorpedia.com/)
nes_theme <- ttheme(
  colnames.style = colnames_style(
    color = "black",
    fill = colours[1],
    face = "bold"
  ),
  tbody.style = tbody_style(color = "black", fill = c("#e8c883", "#f3deb4"))
)
ses_theme <- ttheme(
  colnames.style = colnames_style(
    color = "black",
    fill = colours[2],
    face = "bold"
  ),
  tbody.style = tbody_style(color = "black", fill = c("#74bfa0", "#bbdfce"))
)
# read image
nes_image <- image_read("../man/figures/nes_crop.png")
ses_image <- image_read("../man/figures/ses_crop.png")

# map
trip <- basemap(
  shapefiles = "DecimalDegree",
  bathymetry = TRUE
) +
  geom_path(
    data = data_fig_sum,
    aes(x = lon, y = lat, group = .id),
    size = 2,
    colour = "white",
    show.legend = F
  ) +
  scale_fill_manual(
    name = "Bathymetry (m)",
    values = colorRampPalette(c(
      "#F7FBFF", "#DEEBF7", "#9ECAE1", "#4292C6", "#08306B"
    ))(10),
    labels =
      c(
        "0-50",
        "50-300",
        "300-500",
        "500-1000",
        "1000-1500",
        "1500-2000",
        "2000-4000",
        "4000-6000",
        "6000-10000",
        ">10000"
      )
  ) +
  geom_path(
    data = data_fig_sum,
    aes(x = lon, y = lat, col = .id),
    size = 1.5,
    show.legend = F
  ) +
  scale_color_manual(values = colours, guide = "none") +
  annotation_raster(nes_image, -175, -145, 20, 50) +
  annotation_raster(ses_image, 75, 105, -50, -20) +
  theme_void() +
  theme(legend.position = "top")

# maxdepth
fig_sum_maxdepth <-
  ggplot(data_fig_sum_maxdepth, aes(x = day_departure, y = value, col = .id)) +
  geom_point(
    show.legend = F,
    shape = 16,
    size = 1,
    alpha = 0.5
  ) +
  labs(y = "Maximum depth (m)") +
  scale_y_reverse() +
  scale_colour_manual(values = colours) +
  facet_grid2(. ~ .id,
              strip = strip_themed(background_x = elem_list_rect(fill = colours))
  ) +
  theme_jjo() +
  theme(
    axis.title.x = element_blank(),
    axis.text.x = element_blank(),
    axis.ticks.x = element_blank(),
    strip.background = element_blank(),
    strip.text.x = element_blank()
  )

# driftrate
fig_sum_dduration <-
  ggplot(
    data_fig_sum_dduration,
    aes(x = day_departure, y = value / 60, col = .id)
  ) +
  geom_point(
    show.legend = F,
    shape = 16,
    size = 1,
    alpha = 0.5
  ) +
  labs(y = "Dive duration (min)") +
  scale_colour_manual(values = colours) +
  facet_grid2(. ~ .id,
              strip = strip_themed(background_x = elem_list_rect(fill = colours))
  ) +
  theme_jjo() +
  theme(
    axis.title.x = element_blank(),
    axis.text.x = element_blank(),
    axis.ticks.x = element_blank(),
    strip.background = element_blank(),
    strip.text.x = element_blank()
  )

# driftrate
fig_sum_driftrate <-
  ggplot(
    data_fig_sum_driftrate,
    aes(x = day_departure, y = value, col = .id)
  ) +
  geom_point(show.legend = F) +
  geom_hline(
    yintercept = 0,
    linetype = "dashed",
    size = 1
  ) +
  labs(
    y = expression(paste("Daily median drift rate (m.", s^-1, ")")),
    x = "Number of days since departure"
  ) +
  scale_colour_manual(values = colours) +
  facet_grid2(. ~ .id,
              strip = strip_themed(background_x = elem_list_rect(fill = colours))
  ) +
  theme_jjo() +
  theme(
    strip.background = element_blank(),
    strip.text.x = element_blank()
  )
# summary table for nes
table_sum_nes <- data.table::transpose(data_fig_sum[sp == "nes", .(
  "# of days recorded" = prettyNum(
    uniqueN(as.Date(date)),
    big.mark = ",",
    scientific = FALSE
  ),
  "Recorder settings" = "All dives",
  "# of dives recorded" = prettyNum(.N, big.mark = ",", scientific = FALSE),
  "Median max depth" = paste(prettyNum(
    round(quantile(maxdepth, 0.5), 1),
    big.mark = ",",
    scientific = FALSE
  ), "m"),
  "Median dive duration" = paste(prettyNum(
    round(quantile(dduration, 0.5) / 60, 1),
    big.mark = ",",
    scientific = FALSE
  ), "min"),
  "Median bottom duration" = paste(prettyNum(
    round(quantile(botttime, 0.5) / 60, 1),
    big.mark = ",",
    scientific = FALSE
  ), "min")
), by = .("Seal ID" = .id)], keep.names = " ", make.names = 1)

# summary table for ses
table_sum_ses <- data.table::transpose(data_fig_sum[sp == "ses", .(
  "# of days recorded" = prettyNum(
    uniqueN(as.Date(date)),
    big.mark = ",",
    scientific = FALSE
  ),
  "Recorder settings" = "1 dive every ~2.25 hr",
  "# of dives recorded" = prettyNum(.N, big.mark = ",", scientific = FALSE),
  "Median max depth" = paste(prettyNum(
    round(quantile(maxdepth, 0.5), 1),
    big.mark = ",",
    scientific = FALSE
  ), "m"),
  "Median dive duration" = paste(prettyNum(
    round(quantile(dduration, 0.5) / 60, 1),
    big.mark = ",",
    scientific = FALSE
  ), "min"),
  "Median bottom duration" = paste(prettyNum(
    round(quantile(botttime, 0.5) / 60, 1),
    big.mark = ",",
    scientific = FALSE
  ), "min")
), by = .("Seal ID" = .id)], keep.names = " ", make.names = 1)

# format tables
table_sum_nes <- tableGrob(table_sum_nes,
                           rows = NULL,
                           cols = NULL,
                           theme = nes_theme
)
header_sum_nes <- tableGrob(mtcars[1, 1],
                            rows = NULL,
                            cols = c(data_fig_sum[sp == "nes", unique(.id)]),
                            theme = nes_theme
)
table_sum_nes <- gtable_combine(header_sum_nes[1, ], table_sum_nes, along = 2)
table_sum_nes$layout[1:2, c("r")] <- 2
table_sum_nes$widths <- unit(c(0.6, 0.4), "npc")

table_sum_ses <- tableGrob(table_sum_ses,
                           rows = NULL,
                           cols = NULL,
                           theme = ses_theme
)
header_sum_ses <- tableGrob(mtcars[1, 1],
                            rows = NULL,
                            cols = c(data_fig_sum[sp == "ses", unique(.id)]),
                            theme = ses_theme
)
table_sum_ses <- gtable_combine(header_sum_ses[1, ], table_sum_ses, along = 2)
table_sum_ses$layout[1:2, c("r")] <- 2
table_sum_ses$widths <- unit(c(0.6, 0.4), "npc")
# # final plot
# trip / (as_ggplot(table_sum_nes) + as_ggplot(table_sum_ses)) / fig_sum_maxdepth / fig_sum_dduration / fig_sum_driftrate +
#   # annotation A, B, C, ...
#   plot_annotation(tag_levels = list(c("(A)", "(B)", "", "(C)", "(D)", "(E)"))) +
#   # layout
#   plot_layout(heights = c(2, 1, 1, 1, 1)) &
#   # annotation in bold
#   theme(plot.tag = element_text(face = "bold"))
# # export (height 1375; width 875)
layout = "
AAAADDD
AAAADDD
AAAADDD
AAAAEEE
AAAAEEE
BBBBEEE
CCCCFFF
CCCCFFF
CCCCFFF
"

trip + guide_area() + (as_ggplot(table_sum_nes) + as_ggplot(table_sum_ses)) + fig_sum_maxdepth + fig_sum_dduration + fig_sum_driftrate +
  plot_annotation(tag_levels = list(c("(A)", "(B)", "", "(C)", "(D)", "(E)"))) +
  # layout
  plot_layout(design = layout, guides = 'collect') &
  # annotation in bold
  theme(plot.tag = element_text(face = "bold"))
Illustrative data from one representative weanling northern elephant seal (2018070; gold) and one southern elephant seal (130072; green) for comparison. The panels show for each seal: (A) the migration routes during their first trip to sea from Año Nuevo, California, United States of America, and Kerguelen Island, France, respectively; (B) a summary of tag setup and dive characteristics; the development of (C) maximum diving depth, (D) dive duration, and (E) daily median drift rate. Data show clear improvement of diving physiology for both species, with northern elephant seals exhibiting accelerated development in both diving duration and depth.

Figure 2.1: Illustrative data from one representative weanling northern elephant seal (2018070; gold) and one southern elephant seal (130072; green) for comparison. The panels show for each seal: (A) the migration routes during their first trip to sea from Año Nuevo, California, United States of America, and Kerguelen Island, France, respectively; (B) a summary of tag setup and dive characteristics; the development of (C) maximum diving depth, (D) dive duration, and (E) daily median drift rate. Data show clear improvement of diving physiology for both species, with northern elephant seals exhibiting accelerated development in both diving duration and depth.

# export (height 700; width 1450)

Figure 2

# initial plots
fig_maxdepth_ini <- plot_comp(
  data_comp,
  "maxdepth",
  group_to_compare = "sp_rename",
  nb_days = 200,
  cols = "divetype_rename",
  ribbon = T,
  point = F,
  colours = colours,
  linetype_ribbon = 0,
  individual = FALSE,
  # method = "GCV.Cp",
  scales = "free_y"
)
fig_dduration_ini <- plot_comp(
  copy(data_comp)[, dduration_min := dduration / 60],
  "dduration_min",
  group_to_compare = "sp_rename",
  nb_days = 200,
  cols = "divetype_rename",
  ribbon = T,
  point = F,
  colours = colours,
  linetype_ribbon = 0,
  individual = FALSE,
  # method = "GCV.Cp",
  scales = "free_y"
)
# get limits
maxdepth_limits <- ggplot_build(fig_maxdepth_ini)$layout$panel_params[[1]]$y.range
dduration_limits <- ggplot_build(fig_dduration_ini)$layout$panel_params[[1]]$y.range

# update initial plots
fig_maxdepth <- fig_maxdepth_ini +
  labs(
    y = "Maximum depth (m)",
    colour = "Elephant seals",
    fill = "Elephant seals"
  ) +
  coord_cartesian(ylim = rev(maxdepth_limits)) +
  scale_colour_manual(
    values = colours,
    labels = data_comp[, sort(unique(sp_rename))] %>%
      word(1) %>%
      str_to_title()
  ) +
  scale_fill_manual(
    values = colours,
    labels = data_comp[, sort(unique(sp_rename))] %>%
      word(1) %>%
      str_to_title()
  ) +
  theme_jjo() +
  theme(
    legend.position = "top",
    axis.title.x = element_blank(),
    axis.text.x = element_blank(),
    axis.line.x = element_blank(),
    axis.ticks.x = element_blank(),
    strip.text = element_text(colour = 'grey20')
  )
fig_dduration <- fig_dduration_ini +
  labs(
    x = "Number of days since departure",
    y = "Dive duration (min)"
  ) +
  coord_cartesian(ylim = dduration_limits) +
  theme_jjo() +
  theme(
    legend.position = "none",
    strip.text.x = element_blank()
  )

# density plots
fig_dens_maxdepth <-
  ggplot(data_comp[day_departure <= 200, ], aes(y = maxdepth, fill = sp)) +
  geom_density(show.legend = F, col = "black", alpha = 0.4, size = 0.3) +
  coord_cartesian(ylim = rev(maxdepth_limits)) +
  scale_fill_manual(values = colours) +
  theme_void()
fig_dens_dduration <-
  ggplot(data_comp[day_departure <= 200, ], aes(y = dduration / 60, fill = sp)) +
  geom_density(show.legend = F, col = "black", alpha = 0.4, size = 0.3) +
  coord_cartesian(ylim = dduration_limits) +
  scale_fill_manual(values = colours) +
  theme_void()
((fig_maxdepth | fig_dens_maxdepth) + plot_layout(ncol = 2, widths = c(5, 1))) /
  ((fig_dduration | fig_dens_dduration) + plot_layout(ncol = 2, widths = c(5, 1)))
Development of depth and duration across dive types throughout the first trip to sea in northern (n=4) and southern elephant seals (n=9) estimated from generalized additive models. The solid lines represent the means, and the shaded areas represent the 95% confidence intervals. Marginal density plots represent the spread of data across all dive types for each species.

Figure 2.2: Development of depth and duration across dive types throughout the first trip to sea in northern (n=4) and southern elephant seals (n=9) estimated from generalized additive models. The solid lines represent the means, and the shaded areas represent the 95% confidence intervals. Marginal density plots represent the spread of data across all dive types for each species.

# Mann Whitney / Wilcoxon rank sum test on dive depth
tidy(wilcox.test(
  data_comp[day_departure <= 200 & sp == "nes", maxdepth],
  data_comp[day_departure <= 200 & sp == "ses", maxdepth]
)) %>%
  gt() %>%
  tab_header(title = "Mann Whitney / Wilcoxon rank sum test on dive depth")
Mann Whitney / Wilcoxon rank sum test on dive depth
statistic p.value method alternative
902643075 0 Wilcoxon rank sum test with continuity correction two.sided
# Mann Whitney / Wilcoxon rank sum test on dive duration
tidy(wilcox.test(
  data_comp[day_departure <= 200 & sp == "nes", dduration],
  data_comp[day_departure <= 200 & sp == "ses", dduration]
)) %>%
  gt() %>%
  tab_header(title = "Mann Whitney / Wilcoxon rank sum test on dive duration")
Mann Whitney / Wilcoxon rank sum test on dive duration
statistic p.value method alternative
897660292 0 Wilcoxon rank sum test with continuity correction two.sided

Figure 3

# (only for .id with location data, and so phase information)
prop_dive_id_phase_divetype_sp <- data_comp[
  !is.na(lat),
  table(divetype, sp, sp_rename, phase, .id)
] %>%
  # the calculate the proportion of dive in each divetype, per sp and phases
  prop.table(., c(".id")) %>%
  # convert into a data.table
  as.data.table(.)

# merge this table to add the number of dives, per divetype, phase, sp, .id
prop_dive_id_phase_divetype_sp <-
  merge(
    prop_dive_id_phase_divetype_sp,
    data_comp[!is.na(lat),
              .(nb_dives_divetype = uniqueN(divenumber)),
              by = .(sp, sp_rename, .id, divetype, phase)
    ] %>%
      .[, nb_dives := sum(nb_dives_divetype),
        by = .(.id)
      ] %>%
      .[],
    by = c("sp_rename", "sp", ".id", "divetype", "phase"),
    all.y = T
  )

# calculate the right proportions
dataPlot <- prop_dive_id_phase_divetype_sp %>%
  .[, .(
    N = wtd.mean(N, nb_dives),
    # its equivalent of using only the number of dives and not the percentage
    # N == N_v2
    N_v2 = sum(nb_dives_divetype) / sum(nb_dives),
    N_sd = sqrt(wtd.var(N, nb_dives))
  ),
  by = .(sp_rename, sp, divetype, phase)
  ]
# p_value calculation for nes
df_p_val_nes <- data_comp[sp == "nes" & !is.na(lat),
                          .(nb_divetype = .N),
                          by = .(divetype, phase)
] %>%
  .[, nb_dive := sum(nb_divetype)] %>%
  # perform by divetype
  rstatix::group_by(divetype) %>%
  # a prop.test test
  summarise(rstatix::prop_test(x = nb_divetype, n = nb_dive, correct = F)) %>%
  # then adjust the p_value for multiple test
  rstatix::adjust_pvalue(p.col = "p", method = "bonferroni") %>%
  # update p.adj
  rstatix::add_significance(p.col = "p.adj") %>%
  # sort
  arrange(divetype)

# dataset for nes
dataPlot_nes <- copy(dataPlot)[sp == "nes", N := -(1 * N)] %>%
  .[sp == "nes"]

# plot
fig_nes_prop <-
  ggplot(
    dataPlot_nes,
    aes(x = divetype, y = N, fill = phase)
  ) +
  geom_bar(
    stat = "identity",
    position = "dodge",
    color = "grey30"
  ) +
  scale_y_continuous(
    labels = function(x) {
      percent(abs(x), 1)
    }
  ) +
  geom_errorbar(aes(ymin = N - N_sd, ymax = N),
                width = .2,
                position = position_dodge(.9)
  ) +
  coord_flip(ylim = c(-c(round((dataPlot[, max(N + N_sd)] + 0.03) * 100) / 100, 0))) +
  facet_grid(. ~ sp_rename, scales = "free_x") +
  theme_jjo() +
  # day first, and night
  scale_fill_manual(
    values = c("white", "grey"),
    labels = c("Day-time", "Night-time")
  ) +
  # add stat
  geom_signif(
    y_position = dataPlot_nes[, .(position = min(N - N_sd)), divetype]$position +
      dataPlot_nes[, max(N + N_sd)] * 0.5,
    xmin = seq(0, dataPlot_nes[, uniqueN(divetype)] - 1) + 0.8,
    xmax = seq(1, dataPlot_nes[, uniqueN(divetype)]) + 0.2,
    # replace **** by *** (more standard)
    annotation = fifelse(
      df_p_val_nes$p.adj.signif == "****",
      "***",
      df_p_val_nes$p.adj.signif
    ),
    tip_length = 0,
    vjust = -0.6,
    angle = 90
  ) +
  labs(fill = "Time of day") +
  theme(
    legend.position = "top",
    axis.line.y = element_blank(),
    axis.title.y = element_blank(),
    axis.title.x = element_blank(),
    axis.text.y = element_blank(),
    axis.ticks.y = element_blank(),
    axis.line = element_line(arrow = arrow(
      length = unit(0.2, "lines"),
      type = "closed",
      ends = "first"
    )),
    strip.background = element_rect(fill = colours[1]),
    strip.text = element_text(colour = 'grey20')
  )

# p_value calculation for ses
df_p_val_ses <- data_comp[sp == "ses" & !is.na(lat),
                          .(nb_divetype = .N),
                          by = .(divetype, phase)
] %>%
  .[, nb_dive := sum(nb_divetype)] %>%
  # perform by divetype
  rstatix::group_by(divetype) %>%
  # a prop.test test
  summarise(rstatix::prop_test(x = nb_divetype, n = nb_dive, correct = F)) %>%
  # then adjust the p_value for multiple test
  rstatix::adjust_pvalue(p.col = "p", method = "bonferroni") %>%
  # update p.adj
  rstatix::add_significance(p.col = "p.adj") %>%
  # sort
  arrange(divetype)

# dataset for ses
dataPlot_ses <- copy(dataPlot)[sp == "ses", ] %>%
  .[sp == "ses"]

# plot
fig_ses_prop <-
  ggplot(dataPlot_ses, aes(x = divetype, y = N, fill = phase)) +
  geom_bar(
    stat = "identity",
    position = "dodge",
    color = "grey30"
  ) +
  scale_y_continuous(
    labels = function(x) {
      percent(abs(x), 1)
    }
  ) +
  geom_errorbar(aes(ymin = N, ymax = N + N_sd),
                width = .2,
                position = position_dodge(.9)
  ) +
  coord_flip(ylim = c(0, round((dataPlot[, max(N + N_sd)] + 0.03) * 100) / 100)) +
  facet_grid(. ~ sp_rename, scales = "free_x") +
  theme_jjo() +
  # day first, and night
  scale_fill_manual(
    values = c("white", "grey"),
    labels = c("Day-time", "Night-time")
  ) +
  # add stat
  geom_signif(
    y_position = dataPlot_ses[, .(position = max(N + N_sd)), divetype]$position +
      dataPlot_ses[, min(N + N_sd)] * 0.5,
    xmin = seq(0, dataPlot_ses[, uniqueN(divetype)] - 1) + 0.8,
    xmax = seq(1, dataPlot_ses[, uniqueN(divetype)]) + 0.2,
    # replace **** by *** (more standard)
    annotation = fifelse(
      df_p_val_ses$p.adj.signif == "****",
      "***",
      df_p_val_ses$p.adj.signif
    ),
    tip_length = 0
  ) +
  labs(fill = "Time of day") +
  theme(
    legend.position = "none",
    axis.line.y = element_blank(),
    axis.title.y = element_blank(),
    axis.title.x = element_blank(),
    axis.text.y = element_blank(),
    axis.ticks.y = element_blank(),
    axis.line.x = element_line(arrow = arrow(
      length = unit(0.2, "lines"), type = "closed"
    )),
    strip.background = element_rect(fill = colours[2]),
    strip.text = element_text(colour = 'grey20')
  )

df_text <- data.table(
  x = rep(0, data_comp[, uniqueN(divetype)]),
  label_to_order = data_comp[, sort(unique(divetype))],
  divetype = data_comp[, sort(unique(divetype))] %>%
    word(2) %>%
    str_to_title(),
  percentage = round(as.vector(prop.table(data_comp[
    !is.na(lat),
    table(divetype)
  ])) * 100, 1)
) %>%
  .[, label_to_display := paste0(divetype, "\n(", percentage, " %)")]
fig_text <-
  ggplot(df_text, aes(x = x, y = label_to_order, label = label_to_display)) +
  geom_text() +
  theme_void()

fig_label_1 <-
  ggplot(data.frame(l = "Percentage of dives", x = 1, y = 1)) +
  geom_text(aes(x, y, label = l)) +
  theme_void() +
  coord_cartesian(clip = "off")
((fig_nes_prop | fig_text | fig_ses_prop) +
   plot_layout(
     widths = c(4, 1, 4),
     guides = "collect"
   ) &
   theme(legend.position = "top")) / fig_label_1 +
  plot_layout(heights = c(6, 1))
Frequency of dive types across time of day and species. Species-wide statistical test were based on averages of each individual’s dive type proportion weighted by the total number of dives. Percentages in the middle panel represent the frequency of each dive type across species and time of day. Asterisks indicate a significant difference (P-value<0.0001) between day-time and night-time dive frequencies within each species (two-sample z-test).

Figure 2.3: Frequency of dive types across time of day and species. Species-wide statistical test were based on averages of each individual’s dive type proportion weighted by the total number of dives. Percentages in the middle panel represent the frequency of each dive type across species and time of day. Asterisks indicate a significant difference (P-value<0.0001) between day-time and night-time dive frequencies within each species (two-sample z-test).

Figure 4

# calculate the median of driftrate for each day
median_driftrate <- data_comp[divetype == "2: drift",
                              .(driftrate = quantile(driftrate, 0.5)),
                              by = .(day_departure, .id, sp)
] %>%
  .[, sp := fifelse(sp == "nes", "Northern", "Southern")]

# initial plots
fig_driftrate_ini <- plot_comp(
  median_driftrate,
  "driftrate",
  group_to_compare = "sp",
  nb_days = 200,
  ribbon = T,
  linetype_ribbon = 0,
  point = F,
  colours = colours
)
# get limits
driftrate_limits <- ggplot_build(fig_driftrate_ini)$layout$panel_params[[1]]$y.range

# update initial plots
fig_driftrate <- fig_driftrate_ini +
  labs(
    y = expression(paste("Daily median drift rate (m.", s^-1, ")")),
    x = "Number of days since departure",
    colour = "Elephant seal",
    fill = "Elephant seal"
  ) +
  geom_hline(
    yintercept = 0,
    linetype = 2,
    size = 1,
    col = "black"
  ) +
  coord_cartesian(ylim = driftrate_limits) +
  theme_jjo() +
  theme(
    legend.position = "top"
  )

# density plots
fig_dens_driftrate <-
  ggplot(
    data_comp[divetype == "2: drift" & day_departure <= 200, ],
    aes(y = driftrate, fill = sp)
  ) +
  geom_density(show.legend = F, col = "black", alpha = 0.4, size = 0.3) +
  coord_cartesian(ylim = driftrate_limits) +
  scale_fill_manual(values = colours) +
  theme_void()
(fig_driftrate | fig_dens_driftrate) + plot_layout(widths = c(5, 1))
Changes in median drift rate across the first trip to sea in northern (n=4) and southern (n=9) elephant seals estimated from a generalized additive model. The bold solid lines represent the mean species-level responses while the thin lines represent individual-level responses. The shaded areas represent the 95% confidence interval, and the black dashed line indicates neutral buoyancy. Marginal density plots indicate the spread of data across the entire migration for each species.

Figure 2.4: Changes in median drift rate across the first trip to sea in northern (n=4) and southern (n=9) elephant seals estimated from a generalized additive model. The bold solid lines represent the mean species-level responses while the thin lines represent individual-level responses. The shaded areas represent the 95% confidence interval, and the black dashed line indicates neutral buoyancy. Marginal density plots indicate the spread of data across the entire migration for each species.

Extra

data_comp[divetype == "2: drift",
          .(driftrate = median(driftrate, na.rm = T)),
          by = .(.id, day_departure, sp_rename)
] %>%
  merge(., data_comp[,
                     .(maxdepth = median(maxdepth, na.rm = T)),
                     by = .(.id, day_departure, sp_rename)
  ],
  by = c(".id", "day_departure", "sp_rename")
  ) %>%
  ggplot(aes(y = driftrate, x = maxdepth, col = word(sp_rename, 1))) +
  geom_point() +
  scale_color_manual(
    values = colours,
    name = "Elephant seals"
  ) +
  labs(
    x = "Daily median dive depth (m)",
    y = "Daily median drift rate (m/s)"
  ) +
  theme_jjo() +
  theme(legend.position = "top")
Daily median drift rate vs. daily median of maximum dive depth

Figure 2.5: Daily median drift rate vs. daily median of maximum dive depth

data_comp[divetype == "2: drift",
          .(driftrate = median(driftrate, na.rm = T)),
          by = .(.id, day_departure, sp_rename)
] %>%
  merge(., data_comp[,
                     .(maxdepth = max(maxdepth, na.rm = T)),
                     by = .(.id, day_departure, sp_rename)
  ],
  by = c(".id", "day_departure", "sp_rename")
  ) %>%
  ggplot(aes(y = driftrate, x = maxdepth, col = word(sp_rename, 1))) +
  geom_point() +
  scale_color_manual(
    values = colours,
    name = "Elephant seals"
  ) +
  labs(
    x = "Daily maximum dive depth (m)",
    y = "Daily median drift rate (m/s)"
  ) +
  theme_jjo() +
  theme(legend.position = "top")
Daily median drift rate vs. daily maximum of maximum dive depth

Figure 2.6: Daily median drift rate vs. daily maximum of maximum dive depth

From these two graphs, I don’t think it can be said that somehow body condition constrains dive depth, since deep dives occur at positive and negative buoyancies.

3 Tables

Table 1

I thought about doing a table that provides summary information and gives a rapid overview of the dataset.

# based on
# https://themockup.blog/posts/2020-10-31-embedding-custom-features-in-gt-tables/
gt_ggplot_driftrate <- function(table_data, plot_col, data_col, plot_fun, ...) {
  # save the data extract ahead of time
  # to be used in our anonymous function below
  data_in <- purrr::pluck(table_data, "_data", data_col)

  # retrieve min max
  range_x <- rbindlist(data_in)[, range(day_departure)]
  range_y <- c(-0.35, 0.15)

  # draw plot
  text_transform(
    table_data,
    # note the use of {{}} here - this is tidy eval
    # that allows you to indicate specific columns
    locations = cells_body(columns = c({{ plot_col }})),
    fn = function(x) {
      # build the plot
      plot <- lapply(data_in, function(x) {
        # build the plot
        ggplot(x) +
          # for color https://davidmathlogic.com/colorblind/#%23D81B60-%231E88E5-%23FFC107-%23004D40
          geom_area(aes(x = day_departure, y = ifelse(driftrate < 0,
                                                      driftrate, 0)),
                    fill = "#5D3A9B", alpha = 0.5
          ) +
          # for color https://davidmathlogic.com/colorblind/#%23D81B60-%231E88E5-%23FFC107-%23004D40
          geom_area(aes(x = day_departure, y = ifelse(driftrate > 0,
                                                      driftrate, 0)),
                    fill = "#E66100", alpha = 0.5
          ) +
          geom_segment(aes(x = 0,
                           y = 0,
                           xend = max(day_departure) + 10 ,
                           yend = 0),
                       size = 7,
                       colour = "grey30",
                       arrow = arrow(type = "closed",
                                     length = unit(0.2, units = "npc"))) +
          coord_cartesian(xlim = range_x, ylim = range_y) +
          theme_void() +
          theme(
            panel.grid = element_blank(),
            panel.border = element_blank(),
          )
      })

      # draw for every row
      lapply(plot, ggplot_image, aspect_ratio = 5, height = 25)
    }
  )
}
gt_ggplot_sparkline <- function(table_data, plot_col, data_col, plot_fun, ...) {
  # save the data extract ahead of time
  # to be used in our anonymous function below
  data_in <- purrr::pluck(table_data, "_data", data_col)

  # colnames
  col_names <- colnames(rbindlist(data_in))

  # interest variable
  var_interest <- setdiff(col_names, "day_departure")

  # retrieve min max
  range_x <- rbindlist(data_in)[, range(day_departure)]
  range_y <- rbindlist(data_in)[, range(get(var_interest))]

  # draw plot
  text_transform(
    table_data,
    # note the use of {{}} here - this is tidy eval
    # that allows you to indicate specific columns
    locations = cells_body(columns = c({{ plot_col }})),
    fn = function(x) {
      # build the plot
      plot <- lapply(data_in, function(x) {
        # build the plot
        ggplot(x, aes(x = day_departure, y = get(var_interest))) +
          geom_path(size = 6, color = "grey60") +
          geom_smooth(size = 10,
                      linetype = "dashed",
                      colour = "black",
                      method = "lm",
                      se = FALSE,
                      na.rm = TRUE) +
          coord_cartesian(xlim = range_x, ylim = range_y) +
          theme_void() +
          theme(
            panel.grid = element_blank(),
            panel.border = element_blank()
          )
      })

      # draw for every row
      lapply(plot, ggplot_image, aspect_ratio = 4, height = 26)
    }
  )
}
# summary_table_es <-
data_comp[, travel_distance := distGeo(
  matrix(c(lon, lat), ncol = 2),
  matrix(c(shift(lon), shift(lat)), ncol = 2)
),
by = .id
] %>%
  as_tibble() %>%
  mutate(id_rename = word(.id, 2, sep = "_")) %>%
  group_by(sp_rename, id_rename) %>%
  summarise(
    N = prettyNum(n(),
                  big.mark = ",",
                  scientific = FALSE
    ),
    nb_days = round(as.numeric(difftime(
      last(date), first(date),
      units = "days"
    )), 1),
    travel_distance = prettyNum(
      sum(travel_distance, na.rm = T) / 1000,
      digits = 1,
      big.mark = ",",
      scientific = FALSE
    ),
    Maxdepth_mean = round(mean(maxdepth),1),
    Maxdepth_plus_minus = "±",
    Maxdepth_sd = round(sd(maxdepth),1),
    Dduration_mean = round(mean(dduration)/60,1),
    Dduration_plus_minus = "±",
    Dduration_sd = round(sd(maxdepth)/60,1),
    .groups = "drop"
  ) %>%
  # replace travel_distance = 0 by NA
  mutate(travel_distance = na_if(travel_distance, 0)) %>%
  # add driftrate from drift dives
  left_join(
    .,
    data_comp %>%
      as_tibble() %>%
      mutate(id_rename = word(.id, 2, sep = "_")) %>%
      group_by(sp_rename, id_rename, day_departure) %>%
      filter(divetype == "2: drift") %>%
      summarise(
        driftrate = as.numeric(quantile(
          driftrate, 0.5,
          na.rm = T
        )),
        .groups = "drop"
      ) %>%
      group_by(sp_rename, id_rename) %>%
      summarise(
        sparkline_driftrate = list(
          data.frame(
            driftrate = driftrate,
            day_departure = day_departure
          )
        ),
        .groups = "drop"
      ),
    by = c("sp_rename", "id_rename")
  ) %>%
  # add quantile 95 of dduration and max_depth
  left_join(
    .,
    data_comp %>%
      as_tibble() %>%
      mutate(id_rename = word(.id, 2, sep = "_")) %>%
      group_by(sp_rename, id_rename, day_departure) %>%
      summarise(
        maxdepth = as.numeric(quantile(maxdepth, 0.95, na.rm = T)),
        dduration = as.numeric(quantile(dduration, 0.95, na.rm = T)),
        .groups = "drop"
      ) %>%
      group_by(sp_rename, id_rename) %>%
      summarise(
        sparkline_qt_dduration = list(
          data.frame(
            dduration = dduration,
            day_departure = day_departure
          )),
        sparkline_qt_maxdepth = list(
          data.frame(
            maxdepth = -maxdepth,
            day_departure = day_departure
          )),
        .groups = "drop"
      ),
    by = c("sp_rename", "id_rename")
  ) %>%
  # add percentage
  left_join(
    .,
    data_comp %>%
      as_tibble() %>%
      mutate(id_rename = word(.id, 2, sep = "_")) %>%
      group_by(sp_rename, id_rename, divetype) %>%
      summarise(
        n = n(),
        .groups = "drop"
      ) %>%
      group_by(sp_rename, id_rename) %>%
      summarise(
        divetype_perc = round(n * 100 / sum(n)),
        divetype,
        .groups = "drop"
      ) %>%
      arrange(divetype) %>%
      group_by(sp_rename, id_rename) %>%
      summarise(divetype_perc = list(divetype_perc), .groups = "drop"),
    by = c("sp_rename", "id_rename")
  ) %>%
  # add wean mass based on Weanling Dive Metada.xlsx
  left_join(
    .,
    data.table(
      id_rename = c(
        "2018070",
        "2018072",
        "2018074",
        "2018080",
        "140059",
        "140060",
        "140062",
        "140063",
        "140068",
        "140069",
        "140072",
        "140073",
        "140075"
      ),
      sp_rename = c(
        rep("Northern elephant seal", 4),
        rep("Southern elephant seal", 9)
      ),
      weanmass = c(132, 138, 119, 142, 118, 112, 85, NA, 125, NA, NA, 102, NA)
    ),
    by = c("sp_rename", "id_rename")
  ) %>%
  # reorder column
  relocate(nb_days, N, travel_distance, weanmass, divetype_perc,
           .after = id_rename) %>%
  # setup group row
  gt(groupname_col = "sp_rename") %>%
  # spanner (several columns into one column)
  tab_spanner(
    label = "Maximum depth (m)",
    columns = c(
      Maxdepth_mean,
      Maxdepth_plus_minus,
      Maxdepth_sd,
      sparkline_qt_maxdepth
    )
  ) %>%
  tab_spanner(
    label = "Dive duration (min)",
    columns = c(
      Dduration_mean,
      Dduration_plus_minus,
      Dduration_sd,
      sparkline_qt_dduration
    )
  ) %>%
  tab_spanner(
    label = md("Daily median drift rate"),
    columns = c(sparkline_driftrate)
  ) %>%
  tab_spanner(
    label = md("Travel distance"),
    columns = c(travel_distance)
  ) %>%
  tab_spanner(
    label = md("Weaning mass"),
    columns = c(weanmass)
  ) %>%
  tab_spanner(
    label = md("Dive type proportions"),
    columns = c(divetype_perc)
  ) %>%
  # plot
  gt_ggplot_sparkline(sparkline_qt_maxdepth, "sparkline_qt_maxdepth") %>%
  gt_ggplot_sparkline(sparkline_qt_dduration, "sparkline_qt_dduration") %>%
  gt_ggplot_driftrate(sparkline_driftrate, "sparkline_driftrate") %>%
  gt_plt_bar_stack_extra(
    divetype_perc,
    width = 65,
    labels = c("Transit", "Foraging", "Drift", "Benthic"),
    palette = c("#000000", "#444444", "#888888", "#CCCCCC")
  ) %>%
  # alignement
  cols_align(
    columns = c(N, Maxdepth_sd, Dduration_sd),
    align = "left"
  ) %>%
  cols_align(
    columns = c(N, Maxdepth_mean, Dduration_mean),
    align = "right"
  ) %>%
  cols_align(
    columns = c(travel_distance, weanmass, Maxdepth_plus_minus, Dduration_plus_minus),
    align = "center"
  ) %>%
  # format
  fmt_number(
    columns = Maxdepth_mean,
    decimal = 1
  ) %>%
    fmt_number(
    columns = ends_with("_sd"),
    decimal = 1
  ) %>%
  # rename columns
  cols_label(
    N = "# dives",
    id_rename = md("ID"),
    nb_days = "# days",
    travel_distance = "(km)",
    weanmass = "(kg)",
    Maxdepth_mean = md("Mean"),
    Maxdepth_plus_minus = md("±"),
    Maxdepth_sd = md("SD"),
    sparkline_qt_maxdepth = md("Trend"),
    Dduration_mean = md("Mean"),
    Dduration_plus_minus = md("±"),
    Dduration_sd = md("SD"),
    sparkline_driftrate = md("(m.s<sup>-1</sup>)"),
    sparkline_qt_dduration = md("Trend")
  ) %>%
  # add color square
  text_transform(
    locations = cells_row_groups(),
    fn = function(x) {
      # identify sp
      sp <- unique(x)
      # set colour
      colour <-
        if_else(grepl("Northern", sp), colours[1], colours[2])
      # html to add the color box
      purrr::map(x, ~ html(
        glue(
          "<div><span style='height: 15px;width: 15px;background-color: {colour};display: inline-block;border-radius:5px;float:left;top:13%;left:5%;'</span> <span style='display: inline-block;float:left;line-height:20px;padding: 0px 25px;white-space:nowrap;'>{sp}</span></div>"
        )
      ))
    }
  ) %>%
  # color cols
  gt_highlight_cols(
    columns = c(
      Maxdepth_mean,
      Maxdepth_plus_minus,
      Maxdepth_sd,
      sparkline_qt_maxdepth,
      sparkline_driftrate,
      weanmass,
      N
    ),
    fill = "lightgrey",
    alpha = 0.5
  ) %>%
  # footnote
  tab_footnote(
    footnote = "Recorded",
    locations = cells_column_labels(columns = c(N, nb_days))
  ) %>%
  # color rows
  opt_row_striping() %>%
  # set horizontal padding for plus minus
  tab_style(style = "padding-left:0px;padding-right:0px;",
            locations = cells_column_labels(columns = ends_with("plus_minus"))) %>%
      tab_style(style = "padding-left:0px;padding-right:0px;",
            locations = cells_body(columns = ends_with("plus_minus"))) %>%
  # set horizontal padding for plus minus
  tab_style(style = "padding-top:0px;padding-bottom:0px",
            locations = cells_body(columns = starts_with("sparkline"))) %>%
  # settings
  tab_options(
    # # width table
    table.width = pct(175),
    # padding = vertical space between rows
    data_row.padding = px(3),
    # horizontal scroll
    container.overflow.x = T)
ID # days1 # dives1 Travel distance Weaning mass Dive type proportions Maximum depth (m) Dive duration (min) Daily median drift rate
(km) (kg) Transit||Foraging||Drift||Benthic Mean ± SD Trend Mean ± SD Trend (m.s-1)
Northern elephant seal
2018070 229.5 22,390 5,948 132 5818159 305.5 ± 180.0 12.9 ± 3.0
2018072 251.3 22,799 10,430 138 5622157 331.6 ± 187.2 14.1 ± 3.1
2018074 222.8 25,679 NA 119 47211616 231.7 ± 150.9 11.1 ± 2.5
2018080 213.9 19,028 8,334 142 4533158 296.5 ± 146.7 14.5 ± 2.4
Southern elephant seal
140059 185.3 1,823 7,356 118 6572214 179.5 ± 112.5 11.4 ± 1.9
140060 192.4 1,866 8,897 112 7592113 188.9 ± 102.6 9.7 ± 1.7
140062 152.3 1,574 5,864 85 9472420 135.7 ± 60.4 7.0 ± 1.0
140063 157.5 1,570 7,804 NA 6472620 175.1 ± 113.0 10.2 ± 1.9
140068 196.9 1,904 8,328 125 6572215 165.8 ± 113.3 11.1 ± 1.9
140069 216.3 2,123 8,865 NA 1257229 174.0 ± 125.1 9.2 ± 2.1
140072 154.9 1,555 8,857 NA 13472714 148.6 ± 79.9 8.3 ± 1.3
140073 174.3 1,692 7,094 102 8572114 190.5 ± 117.2 10.3 ± 2.0
140075 142.3 1,451 6,608 NA 10492912 132.5 ± 90.3 7.8 ± 1.5
1 Recorded
# # for export
# summary_table_es %>% gtsave_extra(
#   "test_table_2.png",
#   vwidth = 1300,
#   vheight = 580,
#   cliprect = "viewport"
# )

Title: Descriptive statistics and visual representations of the first offshore foraging trip for each northern and southern elephant seal in the dataset. For maximum depth (m) and dive duration (min), the trend represents the changes in the daily 95th percentile through time in a solid gray line associated with a linear regression in black dashes. For drift rate (m.s-1), the daily median was calculated to represent the evolution over time, with positive values in orange and negative in purple.

Extra

# by species
data_comp %>%
  .[!is.na(lat), `:=`(
    sunrise_today = maptools::sunriset(matrix(c(lon, lat), ncol = 2),
                                       date,
                                       direction = "sunrise",
                                       POSIXct.out = TRUE
    )$time,
    sunset_today = maptools::sunriset(matrix(c(lon, lat), ncol = 2),
                                      date,
                                      direction = "sunset",
                                      POSIXct.out = TRUE
    )$time
  ), ] %>%
  # calculation day-time length
  .[, day_time := as.numeric(difftime(sunset_today,
                                      sunrise_today,
                                      units = "hours"))] %>%
  # calculation night-time length
  .[, night_time := 24 - day_time] %>%
  # calculate maxdepth and dduration
  .[, .(
    result_depth = paste(round(mean(maxdepth), 1),
                         "±",
                         round(sd(maxdepth), 1)),
    result_duration = paste(round(mean(dduration / 60), 1),
                            "±",
                            round(sd(dduration / 60), 1)),
    result_day_time = paste(round(mean(day_time, na.rm = T), 1),
                            "±",
                            round(sd(day_time, na.rm = T), 1)),
    result_night_time = paste(round(mean(night_time, na.rm = T), 1),
                              "±",
                              round(sd(night_time, na.rm = T), 1))
  ), by = .(sp_rename)] %>%
  # add wean mass based on Weanling Dive Metada.xlsx
  merge(., data.table(
    id_rename = c(
      "2018070",
      "2018072",
      "2018074",
      "2018080",
      "140059",
      "140060",
      "140062",
      "140063",
      "140068",
      "140069",
      "140072",
      "140073",
      "140075"
    ),
    sp_rename = c(
      rep("Northern elephant seal", 4),
      rep("Southern elephant seal", 9)
    ),
    weanmass = c(132, 138, 119, 142, 118, 112, 85, NA, 125, NA, NA, 102, NA)
  ) %>%
    .[, .(result_mass = paste(
      round(mean(weanmass, na.rm = T), 1),
      "±",
      round(sd(weanmass, na.rm = T), 1)
    )),
    by = sp_rename
    ],
  by = c("sp_rename")
  ) %>%
  merge(., data_comp[, .(travel_distance = sum(travel_distance, na.rm = T) / 1000),
                     by = .(.id, sp_rename)] %>%
          .[, travel_distance := na_if(travel_distance, 0)] %>%
          .[, .(result_distance = paste(round(mean(
            travel_distance,
            na.rm = T
          ), 1), "±", round(sd(
            travel_distance,
            na.rm = T
          ), 1))), by = .(sp_rename)], by = "sp_rename") %>%
  gt()
sp_rename result_depth result_duration result_day_time result_night_time result_mass result_distance
Northern elephant seal 289.1 ± 171.8 13 ± 4.7 13.3 ± 2.4 10.7 ± 2.4 132.8 ± 10 8237 ± 2242.6
Southern elephant seal 167 ± 106.7 9.5 ± 4.7 13 ± 3.1 11 ± 3.1 108.4 ± 15.6 7741.6 ± 1093.4
data_comp[, .(
  nb_days = as.numeric(difftime(max(date), min(date), units = "day")),
  dist_km = sum(travel_distance, na.rm = T) / 1000
), by = .(.id)] %>%
  .[, dist_km := na_if(dist_km, 0)] %>%
  .[, lapply(.SD, function(x) {
    c(
      round(mean(x, na.rm = T), 2),
      round(sd(x, na.rm = T), 2)
    )
  }),
  .SDcols = c("nb_days", "dist_km")
  ] %>%
  data.table::transpose(., keep.names = "Parameter") %>%
  setnames(., c("Parameters", "mean", "sd")) %>%
  .[] %>%
  gt()
Parameters mean sd
nb_days 191.52 34.07
dist_km 7865.40 1354.29
LS0tCnRpdGxlOiAiRmlndXJlcyIKYXV0aG9yOiAiSm9mZnJleSBKT1VNQUEiCmRhdGU6ICJgciBpbnZpc2libGUoU3lzLnNldGxvY2FsZShsb2NhbGUgPSAnQycpKTsgZm9ybWF0KFN5cy5EYXRlKCksIGZvcm1hdCA9ICclQiAlZCwgJVknKWAiCnJlc291cmNlX2ZpbGVzOgogIC0gLi4vbWFuL2ZpZ3VyZXMvbmVzX2Nyb3AucG5nCiAgLSAuLi9tYW4vZmlndXJlcy9zZXNfY3JvcC5wbmcKb3V0cHV0OgogIGJvb2tkb3duOjpodG1sX2RvY3VtZW50MjoKICAgIGNzczogY29zbW9fY3VzdG9tLmNzcwogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMKICAgIGNvZGVfZm9sZGluZzogc2hvdwogICAgZGZfcHJpbnQ6IGRlZmF1bHQKICAgIGZpZ19jYXB0aW9uOiB5ZXMKICAgIGNvZGVfZG93bmxvYWQ6IHllcwogICAgdG9jOiB5ZXMKICAgIHRvY19mbG9hdDoKICAgICAgY29sbGFwc2VkOiB5ZXMKICAgICAgc21vb3RoX3Njcm9sbDogbm8KbGluay1jaXRhdGlvbnM6IHllcwpwa2dkb3duOgogIGFzX2lzOiB0cnVlCnZpZ25ldHRlOiA+CiAgJVxWaWduZXR0ZUluZGV4RW50cnl7RmlndXJlc30KICAlXFZpZ25ldHRlRW5naW5le2tuaXRyOjpybWFya2Rvd259CiAgJVxWaWduZXR0ZUVuY29kaW5ne1VURi04fQotLS0KCmBgYHtyLCBpbmNsdWRlID0gRkFMU0V9CiMgIyByZWR1Y2UgcG5nIHNpemUKa25pdHI6OmtuaXRfaG9va3Mkc2V0KG9wdGlwbmcgPSBrbml0cjo6aG9va19vcHRpcG5nKQprbml0cjo6a25pdF9ob29rcyRzZXQocG5ncXVhbnQgPSBrbml0cjo6aG9va19wbmdxdWFudCkKCiMgZ2xvYmFsIG9wdGlvbiByZWxhdGl2ZSB0byBybWFya2Rvd24Ka25pdHI6Om9wdHNfY2h1bmskc2V0KAogIGNhY2hlID0gRkFMU0UsCiAgZWNobyA9IFRSVUUsCiAgZmlnLmFsaWduID0gImNlbnRlciIsCiAgb3V0LndpZHRoID0gIjEwMCUiLAogIG1lc3NhZ2UgPSBGQUxTRSwKICB3YXJuaW5nID0gRkFMU0UsCiAgY2FjaGUubGF6eSA9IEZBTFNFLAogIG9wdGlwbmcgPSAiLW83IC1xdWlldCIsCiAgcG5ncXVhbnQgPSAiLS1zcGVlZD0xIgopCgojIGxpYnJhcnkKbGlicmFyeShIbWlzYykKbGlicmFyeShkYXRhLnRhYmxlKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoZ2dwdWJyKQpsaWJyYXJ5KGthYmxlRXh0cmEpCmxpYnJhcnkobWFncml0dHIpCmxpYnJhcnkocGF0Y2h3b3JrKQpsaWJyYXJ5KHNjYWxlcykKbGlicmFyeShnZ3Bsb3RpZnkpCmxpYnJhcnkoc3RyaW5ncikKbGlicmFyeShnZ09jZWFuTWFwcykKbGlicmFyeShnZ09jZWFuTWFwc0RhdGEpCmxpYnJhcnkoZ2doNHgpCmxpYnJhcnkoZ3JpZEV4dHJhKQpsaWJyYXJ5KGdsdWUpCmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZ3QpCmxpYnJhcnkoZ3RFeHRyYXMpCmxpYnJhcnkobWFnaWNrKQpsaWJyYXJ5KGdnc2lnbmlmKQpsaWJyYXJ5KGdlb3NwaGVyZSkKbGlicmFyeShicm9vbSkKCiMgcmVtb3ZlIHNvbWUgd2FybmluZ3MKc3VwcHJlc3NXYXJuaW5ncyhsaWJyYXJ5KGdncGxvdDIpKQoKIyBkZWZpbmUgbXkgb3duIHRhYmxlIGZvcm1hdDogaHR0cHM6Ly9naXRodWIuY29tL2hhb3podTIzMy9rYWJsZUV4dHJhL2lzc3Vlcy8zNzQKc2FibGUgPC0gZnVuY3Rpb24oeCwgZXNjYXBlID0gVCwgLi4uKSB7CiAga25pdHI6OmthYmxlKHgsIGVzY2FwZSA9IGVzY2FwZSwgLi4uKSAlPiUKICAgIGthYmxlX3N0eWxpbmcoCiAgICAgIGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJob3ZlciIsICJyZXNwb25zaXZlIiksCiAgICAgIGZ1bGxfd2lkdGggPSBGCiAgICApCn0KCiMgbWFrZSBzdXJlIHdlIGFyZSBpbiBVVEY4LCB0byBjb3JyZWN0bHkgZGlzcGxheSDCsQpTeXMuc2V0bG9jYWxlKCJMQ19BTEwiLCAiZW5fVVMuVVRGLTgiKQpgYGAKCiMgSW1wb3J0IERhdGEKCmBgYHtyfQojIGxvYWQgd2VhbGluZ05FUyBwYWNrYWdlCmxpYnJhcnkod2VhbmxpbmdORVMpCgojIGxvYWQgZGF0YXNldApkYXRhKCJkYXRhX25lcyIpCmRhdGEoImRhdGFfc2VzIikKCiMgbWVyZ2UgaW50byBvbmUgZGF0YXNldApkYXRhX2NvbXAgPC0gcmJpbmQoCiAgcmJpbmRsaXN0KGRhdGFfbmVzJHllYXJfMjAxOCksCiAgcmJpbmRsaXN0KGRhdGFfc2VzJHllYXJfMjAxNCksCiAgdXNlLm5hbWVzID0gVCwKICBmaWxsID0gVAopCgojIHJlbW92ZSBvdXRsaWVyIChpLmUuIGRpdmUgZHVyYXRpb24gPiA1MDAwIHMpCmRhdGFfY29tcCA8LSBkYXRhX2NvbXBbZGR1cmF0aW9uIDwgNTAwMCwgXQpkYXRhX2NvbXBbLCBkaWZmX2RheXMgOj0gYygwLCBkaWZmKGRheV9kZXBhcnR1cmUpKSwgYnkgPSAuaWRdCgojIGtlZXAgdGhlIGZpcnN0IHRyaXAKZGF0YV9jb21wX3NwbGl0IDwtIHNwbGl0KGRhdGFfY29tcCwgYnkgPSBjKCIuaWQiKSkKZGF0YV9jb21wX3NwbGl0X2xpc3QgPC0gbGFwcGx5KGRhdGFfY29tcF9zcGxpdCwgZnVuY3Rpb24oeCkgewogICMgZmluZCB0aGUgcm93cyBhZnRlciAxMDAgZGF5X2RlcGFydHVyZSB3aGVyZSBkaWZmX2RheXMgPiAxCiAgc2Vjb25kX3RyaXAgPC0geFtkYXlfZGVwYXJ0dXJlID4gMTAwICYgZGlmZl9kYXlzID4gMSwgXQogICMgaWYgdGhlcmUgaXMgYSBzZWNvbmQgdHJpcAogIGlmIChucm93KHNlY29uZF90cmlwKSAhPSAwKSB7CiAgICAjIGdldCB0aGUgZmlyc3QgZGF0ZSBvZiB0aGlzIHNlY29uZCB0cmlwCiAgICBkYXRlX2N1dCA8LSBzZWNvbmRfdHJpcFssIG1pbihkYXRlKV0KICAgICMgcmV0dXJuIG9ubHkgdGhlIGZpcnN0IHRyaXAKICAgIHJldHVybih4W2RhdGUgPCBkYXRlX2N1dCwgXSkKICAgICMgaWYgbm8gc2Vjb25kIHRyaXAKICB9IGVsc2UgewogICAgIyByZXR1cm4gdGhlIGZ1bGwgZGF0YXNldAogICAgcmV0dXJuKHgpCiAgfQp9KQoKIyByZWJ1aWx0IHRoZSBkYXRhc2V0CmRhdGFfY29tcCA8LSByYmluZGxpc3QoZGF0YV9jb21wX3NwbGl0X2xpc3QpCgojIHJlbmFtZSBzcCBmb3Igdml6IHB1cnBvc2VzCmRhdGFfY29tcCAlPiUgLlssIHNwX3JlbmFtZSA6PSBmaWZlbHNlKAogIHNwID09ICJuZXMiLAogICJOb3J0aGVybiBlbGVwaGFudCBzZWFsIiwKICAiU291dGhlcm4gZWxlcGhhbnQgc2VhbCIKKV0KIyByZW5hbWUgZGl2ZXR5cGUgZm9yIHZpeiBwdXJwb3NlcwpkYXRhX2NvbXBbLCBkaXZldHlwZV9yZW5hbWUgOj0gZGl2ZXR5cGUgJT4lCiAgICAgICAgICAgIHdvcmQoMikgJT4lCiAgICAgICAgICAgIHN0cl90b190aXRsZSgpXQoKIyBzZXQgdXAgY29sb3VycwojIGh0dHBzOi8vZGF2aWRtYXRobG9naWMuY29tL2NvbG9yYmxpbmQvIyUyM0Q4MUI2MC0lMjMxRTg4RTUtJTIzRkZDMTA3LSUyMzAwNEQ0MAojIGh0dHBzOi8vdGhlbm9kZS5iaW9sb2dpc3RzLmNvbS9kYXRhLXZpc3VhbGl6YXRpb24td2l0aC1mbHlpbmctY29sb3JzL3Jlc2VhcmNoLwojIGh0dHBzOi8vY29sb3IuYWRvYmUuY29tL2NyZWF0ZS9jb2xvci1hY2Nlc3NpYmlsaXR5CiMgY29sb3VycyA8LSBjKCIjZTA4MjE0IiwgIiM4MDczYWMiKQpjb2xvdXJzIDwtIGMoIiNFMUJFNkEiLCAiIzAwOUU3MyIpCmBgYAoKIyBGaWd1cmVzCgojIyBGaWd1cmUgMSB7LX0KCmBgYHtyfQojIGRhdGFzZXRzCmRhdGFfZmlnX3N1bSA8LSBkYXRhX2NvbXBbIWlzLm5hKGxhdCkgJiAuaWQgJWluJSBjKAogICJpbmRfMjAxODA3MCIsCiAgImluZF8xNDAwNzIiCiksIF0gJT4lCiAgLlsuaWQgPT0gImluZF8yMDE4MDcwIiwgLmlkIDo9ICJOb3J0aGVybiBlbGVwaGFudCBzZWFsOiBJRCAyMDE4MDcwIl0gJT4lCiAgLlsuaWQgPT0gImluZF8xNDAwNzIiLCAuaWQgOj0gIlNvdXRoZXJuIGVsZXBoYW50IHNlYWw6IElEIDE0MDA3MiJdICU+JQogIC5bLCAuaWQgOj0gb3JkZXJlZCguaWQsIGxldmVscyA9IGMoCiAgICAiTm9ydGhlcm4gZWxlcGhhbnQgc2VhbDogSUQgMjAxODA3MCIsCiAgICAiU291dGhlcm4gZWxlcGhhbnQgc2VhbDogSUQgMTQwMDcyIgogICkpXQoKIyBtYXhkZXB0aApkYXRhX2ZpZ19zdW1fbWF4ZGVwdGggPC0gbWVsdCgKICBkYXRhX2ZpZ19zdW1bLCAuKAogICAgZGF0ZSwKICAgIG1heGRlcHRoLAogICAgZGF5X2RlcGFydHVyZSwKICAgIC5pZAogICldLAogIGlkLnZhcnMgPSBjKCJkYXRlIiwgImRheV9kZXBhcnR1cmUiLCAiLmlkIiksCiAgbWVhc3VyZS52YXJzID0gYygibWF4ZGVwdGgiKQopCgojIGR1cmF0aW9uCmRhdGFfZmlnX3N1bV9kZHVyYXRpb24gPC0gbWVsdCgKICBkYXRhX2ZpZ19zdW1bLCAuKAogICAgZGF0ZSwKICAgIGRkdXJhdGlvbiwKICAgIGRheV9kZXBhcnR1cmUsCiAgICAuaWQKICApXSwKICBpZC52YXJzID0gYygiZGF0ZSIsICJkYXlfZGVwYXJ0dXJlIiwgIi5pZCIpLAogIG1lYXN1cmUudmFycyA9IGMoImRkdXJhdGlvbiIpCikKCiMgZHJpZnRyYXRlCmRhdGFfZmlnX3N1bV9kcmlmdHJhdGUgPC0gbWVsdCgKICBkYXRhX2ZpZ19zdW1bZGl2ZXR5cGUgPT0gIjI6IGRyaWZ0IiwgLigKICAgIGRyaWZ0cmF0ZSA9IG1lZGlhbihkcmlmdHJhdGUsIG5hLnJtID0gVCksCiAgICBkYXlfZGVwYXJ0dXJlID0gZmlyc3QoZGF5X2RlcGFydHVyZSkKICApLAogIGJ5ID0gLihkYXRlID0gYXMuRGF0ZShkYXRlKSwgLmlkKQogIF0sCiAgaWQudmFycyA9IGMoImRhdGUiLCAiZGF5X2RlcGFydHVyZSIsICIuaWQiKSwKICBtZWFzdXJlLnZhcnMgPSBjKCJkcmlmdHJhdGUiKQopCgojIGJBREwKZGF0YV9maWdfc3VtX2FkbCA8LSBtZWx0KAogIGRhdGFfZmlnX3N1bVtkaXZldHlwZSA9PSAiMTogZm9yYWdpbmciLAogICAgICAgICAgICAgICAuKAogICAgICAgICAgICAgICAgIGFkbCA9IHJvdW5kKHF1YW50aWxlKGRkdXJhdGlvbiwgMC45NSkgLwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgNjApLAogICAgICAgICAgICAgICAgIGRheV9kZXBhcnR1cmUgPSBmaXJzdChkYXlfZGVwYXJ0dXJlKQogICAgICAgICAgICAgICApLAogICAgICAgICAgICAgICBieSA9IC4oZGF0ZSA9IGFzLkRhdGUoZGF0ZSksIC5pZCkKICBdLAogIGlkLnZhcnMgPSBjKCJkYXRlIiwgImRheV9kZXBhcnR1cmUiLCAiLmlkIiksCiAgbWVhc3VyZS52YXJzID0gYygiYWRsIikKKQoKIyBjb25maWd1cmUgdGhlbWUgKHRvIGdldCBncmFkaWVudCBodHRwczovL2VuY3ljb2xvcnBlZGlhLmNvbS8pCm5lc190aGVtZSA8LSB0dGhlbWUoCiAgY29sbmFtZXMuc3R5bGUgPSBjb2xuYW1lc19zdHlsZSgKICAgIGNvbG9yID0gImJsYWNrIiwKICAgIGZpbGwgPSBjb2xvdXJzWzFdLAogICAgZmFjZSA9ICJib2xkIgogICksCiAgdGJvZHkuc3R5bGUgPSB0Ym9keV9zdHlsZShjb2xvciA9ICJibGFjayIsIGZpbGwgPSBjKCIjZThjODgzIiwgIiNmM2RlYjQiKSkKKQpzZXNfdGhlbWUgPC0gdHRoZW1lKAogIGNvbG5hbWVzLnN0eWxlID0gY29sbmFtZXNfc3R5bGUoCiAgICBjb2xvciA9ICJibGFjayIsCiAgICBmaWxsID0gY29sb3Vyc1syXSwKICAgIGZhY2UgPSAiYm9sZCIKICApLAogIHRib2R5LnN0eWxlID0gdGJvZHlfc3R5bGUoY29sb3IgPSAiYmxhY2siLCBmaWxsID0gYygiIzc0YmZhMCIsICIjYmJkZmNlIikpCikKYGBgCgpgYGB7cn0KIyByZWFkIGltYWdlCm5lc19pbWFnZSA8LSBpbWFnZV9yZWFkKCIuLi9tYW4vZmlndXJlcy9uZXNfY3JvcC5wbmciKQpzZXNfaW1hZ2UgPC0gaW1hZ2VfcmVhZCgiLi4vbWFuL2ZpZ3VyZXMvc2VzX2Nyb3AucG5nIikKCiMgbWFwCnRyaXAgPC0gYmFzZW1hcCgKICBzaGFwZWZpbGVzID0gIkRlY2ltYWxEZWdyZWUiLAogIGJhdGh5bWV0cnkgPSBUUlVFCikgKwogIGdlb21fcGF0aCgKICAgIGRhdGEgPSBkYXRhX2ZpZ19zdW0sCiAgICBhZXMoeCA9IGxvbiwgeSA9IGxhdCwgZ3JvdXAgPSAuaWQpLAogICAgc2l6ZSA9IDIsCiAgICBjb2xvdXIgPSAid2hpdGUiLAogICAgc2hvdy5sZWdlbmQgPSBGCiAgKSArCiAgc2NhbGVfZmlsbF9tYW51YWwoCiAgICBuYW1lID0gIkJhdGh5bWV0cnkgKG0pIiwKICAgIHZhbHVlcyA9IGNvbG9yUmFtcFBhbGV0dGUoYygKICAgICAgIiNGN0ZCRkYiLCAiI0RFRUJGNyIsICIjOUVDQUUxIiwgIiM0MjkyQzYiLCAiIzA4MzA2QiIKICAgICkpKDEwKSwKICAgIGxhYmVscyA9CiAgICAgIGMoCiAgICAgICAgIjAtNTAiLAogICAgICAgICI1MC0zMDAiLAogICAgICAgICIzMDAtNTAwIiwKICAgICAgICAiNTAwLTEwMDAiLAogICAgICAgICIxMDAwLTE1MDAiLAogICAgICAgICIxNTAwLTIwMDAiLAogICAgICAgICIyMDAwLTQwMDAiLAogICAgICAgICI0MDAwLTYwMDAiLAogICAgICAgICI2MDAwLTEwMDAwIiwKICAgICAgICAiPjEwMDAwIgogICAgICApCiAgKSArCiAgZ2VvbV9wYXRoKAogICAgZGF0YSA9IGRhdGFfZmlnX3N1bSwKICAgIGFlcyh4ID0gbG9uLCB5ID0gbGF0LCBjb2wgPSAuaWQpLAogICAgc2l6ZSA9IDEuNSwKICAgIHNob3cubGVnZW5kID0gRgogICkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjb2xvdXJzLCBndWlkZSA9ICJub25lIikgKwogIGFubm90YXRpb25fcmFzdGVyKG5lc19pbWFnZSwgLTE3NSwgLTE0NSwgMjAsIDUwKSArCiAgYW5ub3RhdGlvbl9yYXN0ZXIoc2VzX2ltYWdlLCA3NSwgMTA1LCAtNTAsIC0yMCkgKwogIHRoZW1lX3ZvaWQoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpCgojIG1heGRlcHRoCmZpZ19zdW1fbWF4ZGVwdGggPC0KICBnZ3Bsb3QoZGF0YV9maWdfc3VtX21heGRlcHRoLCBhZXMoeCA9IGRheV9kZXBhcnR1cmUsIHkgPSB2YWx1ZSwgY29sID0gLmlkKSkgKwogIGdlb21fcG9pbnQoCiAgICBzaG93LmxlZ2VuZCA9IEYsCiAgICBzaGFwZSA9IDE2LAogICAgc2l6ZSA9IDEsCiAgICBhbHBoYSA9IDAuNQogICkgKwogIGxhYnMoeSA9ICJNYXhpbXVtIGRlcHRoIChtKSIpICsKICBzY2FsZV95X3JldmVyc2UoKSArCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjb2xvdXJzKSArCiAgZmFjZXRfZ3JpZDIoLiB+IC5pZCwKICAgICAgICAgICAgICBzdHJpcCA9IHN0cmlwX3RoZW1lZChiYWNrZ3JvdW5kX3ggPSBlbGVtX2xpc3RfcmVjdChmaWxsID0gY29sb3VycykpCiAgKSArCiAgdGhlbWVfampvKCkgKwogIHRoZW1lKAogICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksCiAgICBheGlzLnRpY2tzLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICBzdHJpcC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLAogICAgc3RyaXAudGV4dC54ID0gZWxlbWVudF9ibGFuaygpCiAgKQoKIyBkcmlmdHJhdGUKZmlnX3N1bV9kZHVyYXRpb24gPC0KICBnZ3Bsb3QoCiAgICBkYXRhX2ZpZ19zdW1fZGR1cmF0aW9uLAogICAgYWVzKHggPSBkYXlfZGVwYXJ0dXJlLCB5ID0gdmFsdWUgLyA2MCwgY29sID0gLmlkKQogICkgKwogIGdlb21fcG9pbnQoCiAgICBzaG93LmxlZ2VuZCA9IEYsCiAgICBzaGFwZSA9IDE2LAogICAgc2l6ZSA9IDEsCiAgICBhbHBoYSA9IDAuNQogICkgKwogIGxhYnMoeSA9ICJEaXZlIGR1cmF0aW9uIChtaW4pIikgKwogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gY29sb3VycykgKwogIGZhY2V0X2dyaWQyKC4gfiAuaWQsCiAgICAgICAgICAgICAgc3RyaXAgPSBzdHJpcF90aGVtZWQoYmFja2dyb3VuZF94ID0gZWxlbV9saXN0X3JlY3QoZmlsbCA9IGNvbG91cnMpKQogICkgKwogIHRoZW1lX2pqbygpICsKICB0aGVtZSgKICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy50aWNrcy54ID0gZWxlbWVudF9ibGFuaygpLAogICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKQogICkKCiMgZHJpZnRyYXRlCmZpZ19zdW1fZHJpZnRyYXRlIDwtCiAgZ2dwbG90KAogICAgZGF0YV9maWdfc3VtX2RyaWZ0cmF0ZSwKICAgIGFlcyh4ID0gZGF5X2RlcGFydHVyZSwgeSA9IHZhbHVlLCBjb2wgPSAuaWQpCiAgKSArCiAgZ2VvbV9wb2ludChzaG93LmxlZ2VuZCA9IEYpICsKICBnZW9tX2hsaW5lKAogICAgeWludGVyY2VwdCA9IDAsCiAgICBsaW5ldHlwZSA9ICJkYXNoZWQiLAogICAgc2l6ZSA9IDEKICApICsKICBsYWJzKAogICAgeSA9IGV4cHJlc3Npb24ocGFzdGUoIkRhaWx5IG1lZGlhbiBkcmlmdCByYXRlIChtLiIsIHNeLTEsICIpIikpLAogICAgeCA9ICJOdW1iZXIgb2YgZGF5cyBzaW5jZSBkZXBhcnR1cmUiCiAgKSArCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjb2xvdXJzKSArCiAgZmFjZXRfZ3JpZDIoLiB+IC5pZCwKICAgICAgICAgICAgICBzdHJpcCA9IHN0cmlwX3RoZW1lZChiYWNrZ3JvdW5kX3ggPSBlbGVtX2xpc3RfcmVjdChmaWxsID0gY29sb3VycykpCiAgKSArCiAgdGhlbWVfampvKCkgKwogIHRoZW1lKAogICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKQogICkKYGBgCgpgYGB7cn0KIyBzdW1tYXJ5IHRhYmxlIGZvciBuZXMKdGFibGVfc3VtX25lcyA8LSBkYXRhLnRhYmxlOjp0cmFuc3Bvc2UoZGF0YV9maWdfc3VtW3NwID09ICJuZXMiLCAuKAogICIjIG9mIGRheXMgcmVjb3JkZWQiID0gcHJldHR5TnVtKAogICAgdW5pcXVlTihhcy5EYXRlKGRhdGUpKSwKICAgIGJpZy5tYXJrID0gIiwiLAogICAgc2NpZW50aWZpYyA9IEZBTFNFCiAgKSwKICAiUmVjb3JkZXIgc2V0dGluZ3MiID0gIkFsbCBkaXZlcyIsCiAgIiMgb2YgZGl2ZXMgcmVjb3JkZWQiID0gcHJldHR5TnVtKC5OLCBiaWcubWFyayA9ICIsIiwgc2NpZW50aWZpYyA9IEZBTFNFKSwKICAiTWVkaWFuIG1heCBkZXB0aCIgPSBwYXN0ZShwcmV0dHlOdW0oCiAgICByb3VuZChxdWFudGlsZShtYXhkZXB0aCwgMC41KSwgMSksCiAgICBiaWcubWFyayA9ICIsIiwKICAgIHNjaWVudGlmaWMgPSBGQUxTRQogICksICJtIiksCiAgIk1lZGlhbiBkaXZlIGR1cmF0aW9uIiA9IHBhc3RlKHByZXR0eU51bSgKICAgIHJvdW5kKHF1YW50aWxlKGRkdXJhdGlvbiwgMC41KSAvIDYwLCAxKSwKICAgIGJpZy5tYXJrID0gIiwiLAogICAgc2NpZW50aWZpYyA9IEZBTFNFCiAgKSwgIm1pbiIpLAogICJNZWRpYW4gYm90dG9tIGR1cmF0aW9uIiA9IHBhc3RlKHByZXR0eU51bSgKICAgIHJvdW5kKHF1YW50aWxlKGJvdHR0aW1lLCAwLjUpIC8gNjAsIDEpLAogICAgYmlnLm1hcmsgPSAiLCIsCiAgICBzY2llbnRpZmljID0gRkFMU0UKICApLCAibWluIikKKSwgYnkgPSAuKCJTZWFsIElEIiA9IC5pZCldLCBrZWVwLm5hbWVzID0gIiAiLCBtYWtlLm5hbWVzID0gMSkKCiMgc3VtbWFyeSB0YWJsZSBmb3Igc2VzCnRhYmxlX3N1bV9zZXMgPC0gZGF0YS50YWJsZTo6dHJhbnNwb3NlKGRhdGFfZmlnX3N1bVtzcCA9PSAic2VzIiwgLigKICAiIyBvZiBkYXlzIHJlY29yZGVkIiA9IHByZXR0eU51bSgKICAgIHVuaXF1ZU4oYXMuRGF0ZShkYXRlKSksCiAgICBiaWcubWFyayA9ICIsIiwKICAgIHNjaWVudGlmaWMgPSBGQUxTRQogICksCiAgIlJlY29yZGVyIHNldHRpbmdzIiA9ICIxIGRpdmUgZXZlcnkgfjIuMjUgaHIiLAogICIjIG9mIGRpdmVzIHJlY29yZGVkIiA9IHByZXR0eU51bSguTiwgYmlnLm1hcmsgPSAiLCIsIHNjaWVudGlmaWMgPSBGQUxTRSksCiAgIk1lZGlhbiBtYXggZGVwdGgiID0gcGFzdGUocHJldHR5TnVtKAogICAgcm91bmQocXVhbnRpbGUobWF4ZGVwdGgsIDAuNSksIDEpLAogICAgYmlnLm1hcmsgPSAiLCIsCiAgICBzY2llbnRpZmljID0gRkFMU0UKICApLCAibSIpLAogICJNZWRpYW4gZGl2ZSBkdXJhdGlvbiIgPSBwYXN0ZShwcmV0dHlOdW0oCiAgICByb3VuZChxdWFudGlsZShkZHVyYXRpb24sIDAuNSkgLyA2MCwgMSksCiAgICBiaWcubWFyayA9ICIsIiwKICAgIHNjaWVudGlmaWMgPSBGQUxTRQogICksICJtaW4iKSwKICAiTWVkaWFuIGJvdHRvbSBkdXJhdGlvbiIgPSBwYXN0ZShwcmV0dHlOdW0oCiAgICByb3VuZChxdWFudGlsZShib3R0dGltZSwgMC41KSAvIDYwLCAxKSwKICAgIGJpZy5tYXJrID0gIiwiLAogICAgc2NpZW50aWZpYyA9IEZBTFNFCiAgKSwgIm1pbiIpCiksIGJ5ID0gLigiU2VhbCBJRCIgPSAuaWQpXSwga2VlcC5uYW1lcyA9ICIgIiwgbWFrZS5uYW1lcyA9IDEpCgojIGZvcm1hdCB0YWJsZXMKdGFibGVfc3VtX25lcyA8LSB0YWJsZUdyb2IodGFibGVfc3VtX25lcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgcm93cyA9IE5VTEwsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbHMgPSBOVUxMLAogICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZSA9IG5lc190aGVtZQopCmhlYWRlcl9zdW1fbmVzIDwtIHRhYmxlR3JvYihtdGNhcnNbMSwgMV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICByb3dzID0gTlVMTCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbHMgPSBjKGRhdGFfZmlnX3N1bVtzcCA9PSAibmVzIiwgdW5pcXVlKC5pZCldKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lID0gbmVzX3RoZW1lCikKdGFibGVfc3VtX25lcyA8LSBndGFibGVfY29tYmluZShoZWFkZXJfc3VtX25lc1sxLCBdLCB0YWJsZV9zdW1fbmVzLCBhbG9uZyA9IDIpCnRhYmxlX3N1bV9uZXMkbGF5b3V0WzE6MiwgYygiciIpXSA8LSAyCnRhYmxlX3N1bV9uZXMkd2lkdGhzIDwtIHVuaXQoYygwLjYsIDAuNCksICJucGMiKQoKdGFibGVfc3VtX3NlcyA8LSB0YWJsZUdyb2IodGFibGVfc3VtX3NlcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgcm93cyA9IE5VTEwsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbHMgPSBOVUxMLAogICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZSA9IHNlc190aGVtZQopCmhlYWRlcl9zdW1fc2VzIDwtIHRhYmxlR3JvYihtdGNhcnNbMSwgMV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICByb3dzID0gTlVMTCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbHMgPSBjKGRhdGFfZmlnX3N1bVtzcCA9PSAic2VzIiwgdW5pcXVlKC5pZCldKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lID0gc2VzX3RoZW1lCikKdGFibGVfc3VtX3NlcyA8LSBndGFibGVfY29tYmluZShoZWFkZXJfc3VtX3Nlc1sxLCBdLCB0YWJsZV9zdW1fc2VzLCBhbG9uZyA9IDIpCnRhYmxlX3N1bV9zZXMkbGF5b3V0WzE6MiwgYygiciIpXSA8LSAyCnRhYmxlX3N1bV9zZXMkd2lkdGhzIDwtIHVuaXQoYygwLjYsIDAuNCksICJucGMiKQpgYGAKCmBgYHtyIGZpZy53aWR0aD0xMC41LCBmaWcuYXNwPTEuNCwgZmlnLmNhcD0iSWxsdXN0cmF0aXZlIGRhdGEgZnJvbSBvbmUgcmVwcmVzZW50YXRpdmUgd2Vhbmxpbmcgbm9ydGhlcm4gZWxlcGhhbnQgc2VhbCAoMjAxODA3MDsgZ29sZCkgYW5kIG9uZSBzb3V0aGVybiBlbGVwaGFudCBzZWFsICgxMzAwNzI7IGdyZWVuKSBmb3IgY29tcGFyaXNvbi4gVGhlIHBhbmVscyBzaG93IGZvciBlYWNoIHNlYWw6IChBKSB0aGUgbWlncmF0aW9uIHJvdXRlcyBkdXJpbmcgdGhlaXIgZmlyc3QgdHJpcCB0byBzZWEgZnJvbSBBw7FvIE51ZXZvLCBDYWxpZm9ybmlhLCBVbml0ZWQgU3RhdGVzIG9mIEFtZXJpY2EsIGFuZCBLZXJndWVsZW4gSXNsYW5kLCBGcmFuY2UsIHJlc3BlY3RpdmVseTsgKEIpIGEgc3VtbWFyeSBvZiB0YWcgc2V0dXAgYW5kIGRpdmUgY2hhcmFjdGVyaXN0aWNzOyB0aGUgZGV2ZWxvcG1lbnQgb2YgKEMpIG1heGltdW0gZGl2aW5nIGRlcHRoLCAoRCkgZGl2ZSBkdXJhdGlvbiwgYW5kIChFKSBkYWlseSBtZWRpYW4gZHJpZnQgcmF0ZS4gRGF0YSBzaG93IGNsZWFyIGltcHJvdmVtZW50IG9mIGRpdmluZyBwaHlzaW9sb2d5IGZvciBib3RoIHNwZWNpZXMsIHdpdGggbm9ydGhlcm4gZWxlcGhhbnQgc2VhbHMgZXhoaWJpdGluZyBhY2NlbGVyYXRlZCBkZXZlbG9wbWVudCBpbiBib3RoIGRpdmluZyBkdXJhdGlvbiBhbmQgZGVwdGguIn0KIyAjIGZpbmFsIHBsb3QKIyB0cmlwIC8gKGFzX2dncGxvdCh0YWJsZV9zdW1fbmVzKSArIGFzX2dncGxvdCh0YWJsZV9zdW1fc2VzKSkgLyBmaWdfc3VtX21heGRlcHRoIC8gZmlnX3N1bV9kZHVyYXRpb24gLyBmaWdfc3VtX2RyaWZ0cmF0ZSArCiMgICAjIGFubm90YXRpb24gQSwgQiwgQywgLi4uCiMgICBwbG90X2Fubm90YXRpb24odGFnX2xldmVscyA9IGxpc3QoYygiKEEpIiwgIihCKSIsICIiLCAiKEMpIiwgIihEKSIsICIoRSkiKSkpICsKIyAgICMgbGF5b3V0CiMgICBwbG90X2xheW91dChoZWlnaHRzID0gYygyLCAxLCAxLCAxLCAxKSkgJgojICAgIyBhbm5vdGF0aW9uIGluIGJvbGQKIyAgIHRoZW1lKHBsb3QudGFnID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIpKQojICMgZXhwb3J0IChoZWlnaHQgMTM3NTsgd2lkdGggODc1KQpgYGAKCmBgYHtyIGZpZy53aWR0aD0xNS41LCBmaWcuYXNwPTAuNTUsIGZpZy5jYXA9IklsbHVzdHJhdGl2ZSBkYXRhIGZyb20gb25lIHJlcHJlc2VudGF0aXZlIHdlYW5saW5nIG5vcnRoZXJuIGVsZXBoYW50IHNlYWwgKDIwMTgwNzA7IGdvbGQpIGFuZCBvbmUgc291dGhlcm4gZWxlcGhhbnQgc2VhbCAoMTMwMDcyOyBncmVlbikgZm9yIGNvbXBhcmlzb24uIFRoZSBwYW5lbHMgc2hvdyBmb3IgZWFjaCBzZWFsOiAoQSkgdGhlIG1pZ3JhdGlvbiByb3V0ZXMgZHVyaW5nIHRoZWlyIGZpcnN0IHRyaXAgdG8gc2VhIGZyb20gQcOxbyBOdWV2bywgQ2FsaWZvcm5pYSwgVW5pdGVkIFN0YXRlcyBvZiBBbWVyaWNhLCBhbmQgS2VyZ3VlbGVuIElzbGFuZCwgRnJhbmNlLCByZXNwZWN0aXZlbHk7IChCKSBhIHN1bW1hcnkgb2YgdGFnIHNldHVwIGFuZCBkaXZlIGNoYXJhY3RlcmlzdGljczsgdGhlIGRldmVsb3BtZW50IG9mIChDKSBtYXhpbXVtIGRpdmluZyBkZXB0aCwgKEQpIGRpdmUgZHVyYXRpb24sIGFuZCAoRSkgZGFpbHkgbWVkaWFuIGRyaWZ0IHJhdGUuIERhdGEgc2hvdyBjbGVhciBpbXByb3ZlbWVudCBvZiBkaXZpbmcgcGh5c2lvbG9neSBmb3IgYm90aCBzcGVjaWVzLCB3aXRoIG5vcnRoZXJuIGVsZXBoYW50IHNlYWxzIGV4aGliaXRpbmcgYWNjZWxlcmF0ZWQgZGV2ZWxvcG1lbnQgaW4gYm90aCBkaXZpbmcgZHVyYXRpb24gYW5kIGRlcHRoLiJ9CmxheW91dCA9ICIKQUFBQURERApBQUFBRERECkFBQUFEREQKQUFBQUVFRQpBQUFBRUVFCkJCQkJFRUUKQ0NDQ0ZGRgpDQ0NDRkZGCkNDQ0NGRkYKIgoKdHJpcCArIGd1aWRlX2FyZWEoKSArIChhc19nZ3Bsb3QodGFibGVfc3VtX25lcykgKyBhc19nZ3Bsb3QodGFibGVfc3VtX3NlcykpICsgZmlnX3N1bV9tYXhkZXB0aCArIGZpZ19zdW1fZGR1cmF0aW9uICsgZmlnX3N1bV9kcmlmdHJhdGUgKwogIHBsb3RfYW5ub3RhdGlvbih0YWdfbGV2ZWxzID0gbGlzdChjKCIoQSkiLCAiKEIpIiwgIiIsICIoQykiLCAiKEQpIiwgIihFKSIpKSkgKwogICMgbGF5b3V0CiAgcGxvdF9sYXlvdXQoZGVzaWduID0gbGF5b3V0LCBndWlkZXMgPSAnY29sbGVjdCcpICYKICAjIGFubm90YXRpb24gaW4gYm9sZAogIHRoZW1lKHBsb3QudGFnID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIpKQoKIyBleHBvcnQgKGhlaWdodCA3MDA7IHdpZHRoIDE0NTApCmBgYAoKIyMgRmlndXJlIDIgey19CgpgYGB7ciBjYWNoZT1GfQojIGluaXRpYWwgcGxvdHMKZmlnX21heGRlcHRoX2luaSA8LSBwbG90X2NvbXAoCiAgZGF0YV9jb21wLAogICJtYXhkZXB0aCIsCiAgZ3JvdXBfdG9fY29tcGFyZSA9ICJzcF9yZW5hbWUiLAogIG5iX2RheXMgPSAyMDAsCiAgY29scyA9ICJkaXZldHlwZV9yZW5hbWUiLAogIHJpYmJvbiA9IFQsCiAgcG9pbnQgPSBGLAogIGNvbG91cnMgPSBjb2xvdXJzLAogIGxpbmV0eXBlX3JpYmJvbiA9IDAsCiAgaW5kaXZpZHVhbCA9IEZBTFNFLAogICMgbWV0aG9kID0gIkdDVi5DcCIsCiAgc2NhbGVzID0gImZyZWVfeSIKKQpmaWdfZGR1cmF0aW9uX2luaSA8LSBwbG90X2NvbXAoCiAgY29weShkYXRhX2NvbXApWywgZGR1cmF0aW9uX21pbiA6PSBkZHVyYXRpb24gLyA2MF0sCiAgImRkdXJhdGlvbl9taW4iLAogIGdyb3VwX3RvX2NvbXBhcmUgPSAic3BfcmVuYW1lIiwKICBuYl9kYXlzID0gMjAwLAogIGNvbHMgPSAiZGl2ZXR5cGVfcmVuYW1lIiwKICByaWJib24gPSBULAogIHBvaW50ID0gRiwKICBjb2xvdXJzID0gY29sb3VycywKICBsaW5ldHlwZV9yaWJib24gPSAwLAogIGluZGl2aWR1YWwgPSBGQUxTRSwKICAjIG1ldGhvZCA9ICJHQ1YuQ3AiLAogIHNjYWxlcyA9ICJmcmVlX3kiCikKYGBgCgoKYGBge3J9CiMgZ2V0IGxpbWl0cwptYXhkZXB0aF9saW1pdHMgPC0gZ2dwbG90X2J1aWxkKGZpZ19tYXhkZXB0aF9pbmkpJGxheW91dCRwYW5lbF9wYXJhbXNbWzFdXSR5LnJhbmdlCmRkdXJhdGlvbl9saW1pdHMgPC0gZ2dwbG90X2J1aWxkKGZpZ19kZHVyYXRpb25faW5pKSRsYXlvdXQkcGFuZWxfcGFyYW1zW1sxXV0keS5yYW5nZQoKIyB1cGRhdGUgaW5pdGlhbCBwbG90cwpmaWdfbWF4ZGVwdGggPC0gZmlnX21heGRlcHRoX2luaSArCiAgbGFicygKICAgIHkgPSAiTWF4aW11bSBkZXB0aCAobSkiLAogICAgY29sb3VyID0gIkVsZXBoYW50IHNlYWxzIiwKICAgIGZpbGwgPSAiRWxlcGhhbnQgc2VhbHMiCiAgKSArCiAgY29vcmRfY2FydGVzaWFuKHlsaW0gPSByZXYobWF4ZGVwdGhfbGltaXRzKSkgKwogIHNjYWxlX2NvbG91cl9tYW51YWwoCiAgICB2YWx1ZXMgPSBjb2xvdXJzLAogICAgbGFiZWxzID0gZGF0YV9jb21wWywgc29ydCh1bmlxdWUoc3BfcmVuYW1lKSldICU+JQogICAgICB3b3JkKDEpICU+JQogICAgICBzdHJfdG9fdGl0bGUoKQogICkgKwogIHNjYWxlX2ZpbGxfbWFudWFsKAogICAgdmFsdWVzID0gY29sb3VycywKICAgIGxhYmVscyA9IGRhdGFfY29tcFssIHNvcnQodW5pcXVlKHNwX3JlbmFtZSkpXSAlPiUKICAgICAgd29yZCgxKSAlPiUKICAgICAgc3RyX3RvX3RpdGxlKCkKICApICsKICB0aGVtZV9qam8oKSArCiAgdGhlbWUoCiAgICBsZWdlbmQucG9zaXRpb24gPSAidG9wIiwKICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF9ibGFuaygpLAogICAgYXhpcy5saW5lLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICBheGlzLnRpY2tzLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KGNvbG91ciA9ICdncmV5MjAnKQogICkKZmlnX2RkdXJhdGlvbiA8LSBmaWdfZGR1cmF0aW9uX2luaSArCiAgbGFicygKICAgIHggPSAiTnVtYmVyIG9mIGRheXMgc2luY2UgZGVwYXJ0dXJlIiwKICAgIHkgPSAiRGl2ZSBkdXJhdGlvbiAobWluKSIKICApICsKICBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGRkdXJhdGlvbl9saW1pdHMpICsKICB0aGVtZV9qam8oKSArCiAgdGhlbWUoCiAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICBzdHJpcC50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCkKICApCgojIGRlbnNpdHkgcGxvdHMKZmlnX2RlbnNfbWF4ZGVwdGggPC0KICBnZ3Bsb3QoZGF0YV9jb21wW2RheV9kZXBhcnR1cmUgPD0gMjAwLCBdLCBhZXMoeSA9IG1heGRlcHRoLCBmaWxsID0gc3ApKSArCiAgZ2VvbV9kZW5zaXR5KHNob3cubGVnZW5kID0gRiwgY29sID0gImJsYWNrIiwgYWxwaGEgPSAwLjQsIHNpemUgPSAwLjMpICsKICBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IHJldihtYXhkZXB0aF9saW1pdHMpKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY29sb3VycykgKwogIHRoZW1lX3ZvaWQoKQpmaWdfZGVuc19kZHVyYXRpb24gPC0KICBnZ3Bsb3QoZGF0YV9jb21wW2RheV9kZXBhcnR1cmUgPD0gMjAwLCBdLCBhZXMoeSA9IGRkdXJhdGlvbiAvIDYwLCBmaWxsID0gc3ApKSArCiAgZ2VvbV9kZW5zaXR5KHNob3cubGVnZW5kID0gRiwgY29sID0gImJsYWNrIiwgYWxwaGEgPSAwLjQsIHNpemUgPSAwLjMpICsKICBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGRkdXJhdGlvbl9saW1pdHMpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjb2xvdXJzKSArCiAgdGhlbWVfdm9pZCgpCmBgYAoKYGBge3IgZmlnLmhlaWdodD01LCBmaWcuY2FwID0gIkRldmVsb3BtZW50IG9mIGRlcHRoIGFuZCBkdXJhdGlvbiBhY3Jvc3MgZGl2ZSB0eXBlcyB0aHJvdWdob3V0IHRoZSBmaXJzdCB0cmlwIHRvIHNlYSBpbiBub3J0aGVybiAobj00KSBhbmQgc291dGhlcm4gZWxlcGhhbnQgc2VhbHMgKG49OSkgZXN0aW1hdGVkIGZyb20gZ2VuZXJhbGl6ZWQgYWRkaXRpdmUgbW9kZWxzLiBUaGUgc29saWQgbGluZXMgcmVwcmVzZW50IHRoZSBtZWFucywgYW5kIHRoZSBzaGFkZWQgYXJlYXMgcmVwcmVzZW50IHRoZSA5NSUgY29uZmlkZW5jZSBpbnRlcnZhbHMuIE1hcmdpbmFsIGRlbnNpdHkgcGxvdHMgcmVwcmVzZW50IHRoZSBzcHJlYWQgb2YgZGF0YSBhY3Jvc3MgYWxsIGRpdmUgdHlwZXMgZm9yIGVhY2ggc3BlY2llcy4ifQooKGZpZ19tYXhkZXB0aCB8IGZpZ19kZW5zX21heGRlcHRoKSArIHBsb3RfbGF5b3V0KG5jb2wgPSAyLCB3aWR0aHMgPSBjKDUsIDEpKSkgLwogICgoZmlnX2RkdXJhdGlvbiB8IGZpZ19kZW5zX2RkdXJhdGlvbikgKyBwbG90X2xheW91dChuY29sID0gMiwgd2lkdGhzID0gYyg1LCAxKSkpCmBgYAoKYGBge3J9CiMgTWFubiBXaGl0bmV5IC8gV2lsY294b24gcmFuayBzdW0gdGVzdCBvbiBkaXZlIGRlcHRoCnRpZHkod2lsY294LnRlc3QoCiAgZGF0YV9jb21wW2RheV9kZXBhcnR1cmUgPD0gMjAwICYgc3AgPT0gIm5lcyIsIG1heGRlcHRoXSwKICBkYXRhX2NvbXBbZGF5X2RlcGFydHVyZSA8PSAyMDAgJiBzcCA9PSAic2VzIiwgbWF4ZGVwdGhdCikpICU+JQogIGd0KCkgJT4lCiAgdGFiX2hlYWRlcih0aXRsZSA9ICJNYW5uIFdoaXRuZXkgLyBXaWxjb3hvbiByYW5rIHN1bSB0ZXN0IG9uIGRpdmUgZGVwdGgiKQpgYGAKCmBgYHtyfQojIE1hbm4gV2hpdG5leSAvIFdpbGNveG9uIHJhbmsgc3VtIHRlc3Qgb24gZGl2ZSBkdXJhdGlvbgp0aWR5KHdpbGNveC50ZXN0KAogIGRhdGFfY29tcFtkYXlfZGVwYXJ0dXJlIDw9IDIwMCAmIHNwID09ICJuZXMiLCBkZHVyYXRpb25dLAogIGRhdGFfY29tcFtkYXlfZGVwYXJ0dXJlIDw9IDIwMCAmIHNwID09ICJzZXMiLCBkZHVyYXRpb25dCikpICU+JQogIGd0KCkgJT4lCiAgdGFiX2hlYWRlcih0aXRsZSA9ICJNYW5uIFdoaXRuZXkgLyBXaWxjb3hvbiByYW5rIHN1bSB0ZXN0IG9uIGRpdmUgZHVyYXRpb24iKQpgYGAKCiMjIEZpZ3VyZSAzIHstfQoKYGBge3J9CiMgKG9ubHkgZm9yIC5pZCB3aXRoIGxvY2F0aW9uIGRhdGEsIGFuZCBzbyBwaGFzZSBpbmZvcm1hdGlvbikKcHJvcF9kaXZlX2lkX3BoYXNlX2RpdmV0eXBlX3NwIDwtIGRhdGFfY29tcFsKICAhaXMubmEobGF0KSwKICB0YWJsZShkaXZldHlwZSwgc3AsIHNwX3JlbmFtZSwgcGhhc2UsIC5pZCkKXSAlPiUKICAjIHRoZSBjYWxjdWxhdGUgdGhlIHByb3BvcnRpb24gb2YgZGl2ZSBpbiBlYWNoIGRpdmV0eXBlLCBwZXIgc3AgYW5kIHBoYXNlcwogIHByb3AudGFibGUoLiwgYygiLmlkIikpICU+JQogICMgY29udmVydCBpbnRvIGEgZGF0YS50YWJsZQogIGFzLmRhdGEudGFibGUoLikKCiMgbWVyZ2UgdGhpcyB0YWJsZSB0byBhZGQgdGhlIG51bWJlciBvZiBkaXZlcywgcGVyIGRpdmV0eXBlLCBwaGFzZSwgc3AsIC5pZApwcm9wX2RpdmVfaWRfcGhhc2VfZGl2ZXR5cGVfc3AgPC0KICBtZXJnZSgKICAgIHByb3BfZGl2ZV9pZF9waGFzZV9kaXZldHlwZV9zcCwKICAgIGRhdGFfY29tcFshaXMubmEobGF0KSwKICAgICAgICAgICAgICAuKG5iX2RpdmVzX2RpdmV0eXBlID0gdW5pcXVlTihkaXZlbnVtYmVyKSksCiAgICAgICAgICAgICAgYnkgPSAuKHNwLCBzcF9yZW5hbWUsIC5pZCwgZGl2ZXR5cGUsIHBoYXNlKQogICAgXSAlPiUKICAgICAgLlssIG5iX2RpdmVzIDo9IHN1bShuYl9kaXZlc19kaXZldHlwZSksCiAgICAgICAgYnkgPSAuKC5pZCkKICAgICAgXSAlPiUKICAgICAgLltdLAogICAgYnkgPSBjKCJzcF9yZW5hbWUiLCAic3AiLCAiLmlkIiwgImRpdmV0eXBlIiwgInBoYXNlIiksCiAgICBhbGwueSA9IFQKICApCgojIGNhbGN1bGF0ZSB0aGUgcmlnaHQgcHJvcG9ydGlvbnMKZGF0YVBsb3QgPC0gcHJvcF9kaXZlX2lkX3BoYXNlX2RpdmV0eXBlX3NwICU+JQogIC5bLCAuKAogICAgTiA9IHd0ZC5tZWFuKE4sIG5iX2RpdmVzKSwKICAgICMgaXRzIGVxdWl2YWxlbnQgb2YgdXNpbmcgb25seSB0aGUgbnVtYmVyIG9mIGRpdmVzIGFuZCBub3QgdGhlIHBlcmNlbnRhZ2UKICAgICMgTiA9PSBOX3YyCiAgICBOX3YyID0gc3VtKG5iX2RpdmVzX2RpdmV0eXBlKSAvIHN1bShuYl9kaXZlcyksCiAgICBOX3NkID0gc3FydCh3dGQudmFyKE4sIG5iX2RpdmVzKSkKICApLAogIGJ5ID0gLihzcF9yZW5hbWUsIHNwLCBkaXZldHlwZSwgcGhhc2UpCiAgXQpgYGAKCmBgYHtyfQojIHBfdmFsdWUgY2FsY3VsYXRpb24gZm9yIG5lcwpkZl9wX3ZhbF9uZXMgPC0gZGF0YV9jb21wW3NwID09ICJuZXMiICYgIWlzLm5hKGxhdCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgLihuYl9kaXZldHlwZSA9IC5OKSwKICAgICAgICAgICAgICAgICAgICAgICAgICBieSA9IC4oZGl2ZXR5cGUsIHBoYXNlKQpdICU+JQogIC5bLCBuYl9kaXZlIDo9IHN1bShuYl9kaXZldHlwZSldICU+JQogICMgcGVyZm9ybSBieSBkaXZldHlwZQogIHJzdGF0aXg6Omdyb3VwX2J5KGRpdmV0eXBlKSAlPiUKICAjIGEgcHJvcC50ZXN0IHRlc3QKICBzdW1tYXJpc2UocnN0YXRpeDo6cHJvcF90ZXN0KHggPSBuYl9kaXZldHlwZSwgbiA9IG5iX2RpdmUsIGNvcnJlY3QgPSBGKSkgJT4lCiAgIyB0aGVuIGFkanVzdCB0aGUgcF92YWx1ZSBmb3IgbXVsdGlwbGUgdGVzdAogIHJzdGF0aXg6OmFkanVzdF9wdmFsdWUocC5jb2wgPSAicCIsIG1ldGhvZCA9ICJib25mZXJyb25pIikgJT4lCiAgIyB1cGRhdGUgcC5hZGoKICByc3RhdGl4OjphZGRfc2lnbmlmaWNhbmNlKHAuY29sID0gInAuYWRqIikgJT4lCiAgIyBzb3J0CiAgYXJyYW5nZShkaXZldHlwZSkKCiMgZGF0YXNldCBmb3IgbmVzCmRhdGFQbG90X25lcyA8LSBjb3B5KGRhdGFQbG90KVtzcCA9PSAibmVzIiwgTiA6PSAtKDEgKiBOKV0gJT4lCiAgLltzcCA9PSAibmVzIl0KCiMgcGxvdApmaWdfbmVzX3Byb3AgPC0KICBnZ3Bsb3QoCiAgICBkYXRhUGxvdF9uZXMsCiAgICBhZXMoeCA9IGRpdmV0eXBlLCB5ID0gTiwgZmlsbCA9IHBoYXNlKQogICkgKwogIGdlb21fYmFyKAogICAgc3RhdCA9ICJpZGVudGl0eSIsCiAgICBwb3NpdGlvbiA9ICJkb2RnZSIsCiAgICBjb2xvciA9ICJncmV5MzAiCiAgKSArCiAgc2NhbGVfeV9jb250aW51b3VzKAogICAgbGFiZWxzID0gZnVuY3Rpb24oeCkgewogICAgICBwZXJjZW50KGFicyh4KSwgMSkKICAgIH0KICApICsKICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluID0gTiAtIE5fc2QsIHltYXggPSBOKSwKICAgICAgICAgICAgICAgIHdpZHRoID0gLjIsCiAgICAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKC45KQogICkgKwogIGNvb3JkX2ZsaXAoeWxpbSA9IGMoLWMocm91bmQoKGRhdGFQbG90WywgbWF4KE4gKyBOX3NkKV0gKyAwLjAzKSAqIDEwMCkgLyAxMDAsIDApKSkgKwogIGZhY2V0X2dyaWQoLiB+IHNwX3JlbmFtZSwgc2NhbGVzID0gImZyZWVfeCIpICsKICB0aGVtZV9qam8oKSArCiAgIyBkYXkgZmlyc3QsIGFuZCBuaWdodAogIHNjYWxlX2ZpbGxfbWFudWFsKAogICAgdmFsdWVzID0gYygid2hpdGUiLCAiZ3JleSIpLAogICAgbGFiZWxzID0gYygiRGF5LXRpbWUiLCAiTmlnaHQtdGltZSIpCiAgKSArCiAgIyBhZGQgc3RhdAogIGdlb21fc2lnbmlmKAogICAgeV9wb3NpdGlvbiA9IGRhdGFQbG90X25lc1ssIC4ocG9zaXRpb24gPSBtaW4oTiAtIE5fc2QpKSwgZGl2ZXR5cGVdJHBvc2l0aW9uICsKICAgICAgZGF0YVBsb3RfbmVzWywgbWF4KE4gKyBOX3NkKV0gKiAwLjUsCiAgICB4bWluID0gc2VxKDAsIGRhdGFQbG90X25lc1ssIHVuaXF1ZU4oZGl2ZXR5cGUpXSAtIDEpICsgMC44LAogICAgeG1heCA9IHNlcSgxLCBkYXRhUGxvdF9uZXNbLCB1bmlxdWVOKGRpdmV0eXBlKV0pICsgMC4yLAogICAgIyByZXBsYWNlICoqKiogYnkgKioqIChtb3JlIHN0YW5kYXJkKQogICAgYW5ub3RhdGlvbiA9IGZpZmVsc2UoCiAgICAgIGRmX3BfdmFsX25lcyRwLmFkai5zaWduaWYgPT0gIioqKioiLAogICAgICAiKioqIiwKICAgICAgZGZfcF92YWxfbmVzJHAuYWRqLnNpZ25pZgogICAgKSwKICAgIHRpcF9sZW5ndGggPSAwLAogICAgdmp1c3QgPSAtMC42LAogICAgYW5nbGUgPSA5MAogICkgKwogIGxhYnMoZmlsbCA9ICJUaW1lIG9mIGRheSIpICsKICB0aGVtZSgKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiLAogICAgYXhpcy5saW5lLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMubGluZSA9IGVsZW1lbnRfbGluZShhcnJvdyA9IGFycm93KAogICAgICBsZW5ndGggPSB1bml0KDAuMiwgImxpbmVzIiksCiAgICAgIHR5cGUgPSAiY2xvc2VkIiwKICAgICAgZW5kcyA9ICJmaXJzdCIKICAgICkpLAogICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gY29sb3Vyc1sxXSksCiAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KGNvbG91ciA9ICdncmV5MjAnKQogICkKCiMgcF92YWx1ZSBjYWxjdWxhdGlvbiBmb3Igc2VzCmRmX3BfdmFsX3NlcyA8LSBkYXRhX2NvbXBbc3AgPT0gInNlcyIgJiAhaXMubmEobGF0KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAuKG5iX2RpdmV0eXBlID0gLk4pLAogICAgICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gLihkaXZldHlwZSwgcGhhc2UpCl0gJT4lCiAgLlssIG5iX2RpdmUgOj0gc3VtKG5iX2RpdmV0eXBlKV0gJT4lCiAgIyBwZXJmb3JtIGJ5IGRpdmV0eXBlCiAgcnN0YXRpeDo6Z3JvdXBfYnkoZGl2ZXR5cGUpICU+JQogICMgYSBwcm9wLnRlc3QgdGVzdAogIHN1bW1hcmlzZShyc3RhdGl4Ojpwcm9wX3Rlc3QoeCA9IG5iX2RpdmV0eXBlLCBuID0gbmJfZGl2ZSwgY29ycmVjdCA9IEYpKSAlPiUKICAjIHRoZW4gYWRqdXN0IHRoZSBwX3ZhbHVlIGZvciBtdWx0aXBsZSB0ZXN0CiAgcnN0YXRpeDo6YWRqdXN0X3B2YWx1ZShwLmNvbCA9ICJwIiwgbWV0aG9kID0gImJvbmZlcnJvbmkiKSAlPiUKICAjIHVwZGF0ZSBwLmFkagogIHJzdGF0aXg6OmFkZF9zaWduaWZpY2FuY2UocC5jb2wgPSAicC5hZGoiKSAlPiUKICAjIHNvcnQKICBhcnJhbmdlKGRpdmV0eXBlKQoKIyBkYXRhc2V0IGZvciBzZXMKZGF0YVBsb3Rfc2VzIDwtIGNvcHkoZGF0YVBsb3QpW3NwID09ICJzZXMiLCBdICU+JQogIC5bc3AgPT0gInNlcyJdCgojIHBsb3QKZmlnX3Nlc19wcm9wIDwtCiAgZ2dwbG90KGRhdGFQbG90X3NlcywgYWVzKHggPSBkaXZldHlwZSwgeSA9IE4sIGZpbGwgPSBwaGFzZSkpICsKICBnZW9tX2JhcigKICAgIHN0YXQgPSAiaWRlbnRpdHkiLAogICAgcG9zaXRpb24gPSAiZG9kZ2UiLAogICAgY29sb3IgPSAiZ3JleTMwIgogICkgKwogIHNjYWxlX3lfY29udGludW91cygKICAgIGxhYmVscyA9IGZ1bmN0aW9uKHgpIHsKICAgICAgcGVyY2VudChhYnMoeCksIDEpCiAgICB9CiAgKSArCiAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbiA9IE4sIHltYXggPSBOICsgTl9zZCksCiAgICAgICAgICAgICAgICB3aWR0aCA9IC4yLAogICAgICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSguOSkKICApICsKICBjb29yZF9mbGlwKHlsaW0gPSBjKDAsIHJvdW5kKChkYXRhUGxvdFssIG1heChOICsgTl9zZCldICsgMC4wMykgKiAxMDApIC8gMTAwKSkgKwogIGZhY2V0X2dyaWQoLiB+IHNwX3JlbmFtZSwgc2NhbGVzID0gImZyZWVfeCIpICsKICB0aGVtZV9qam8oKSArCiAgIyBkYXkgZmlyc3QsIGFuZCBuaWdodAogIHNjYWxlX2ZpbGxfbWFudWFsKAogICAgdmFsdWVzID0gYygid2hpdGUiLCAiZ3JleSIpLAogICAgbGFiZWxzID0gYygiRGF5LXRpbWUiLCAiTmlnaHQtdGltZSIpCiAgKSArCiAgIyBhZGQgc3RhdAogIGdlb21fc2lnbmlmKAogICAgeV9wb3NpdGlvbiA9IGRhdGFQbG90X3Nlc1ssIC4ocG9zaXRpb24gPSBtYXgoTiArIE5fc2QpKSwgZGl2ZXR5cGVdJHBvc2l0aW9uICsKICAgICAgZGF0YVBsb3Rfc2VzWywgbWluKE4gKyBOX3NkKV0gKiAwLjUsCiAgICB4bWluID0gc2VxKDAsIGRhdGFQbG90X3Nlc1ssIHVuaXF1ZU4oZGl2ZXR5cGUpXSAtIDEpICsgMC44LAogICAgeG1heCA9IHNlcSgxLCBkYXRhUGxvdF9zZXNbLCB1bmlxdWVOKGRpdmV0eXBlKV0pICsgMC4yLAogICAgIyByZXBsYWNlICoqKiogYnkgKioqIChtb3JlIHN0YW5kYXJkKQogICAgYW5ub3RhdGlvbiA9IGZpZmVsc2UoCiAgICAgIGRmX3BfdmFsX3NlcyRwLmFkai5zaWduaWYgPT0gIioqKioiLAogICAgICAiKioqIiwKICAgICAgZGZfcF92YWxfc2VzJHAuYWRqLnNpZ25pZgogICAgKSwKICAgIHRpcF9sZW5ndGggPSAwCiAgKSArCiAgbGFicyhmaWxsID0gIlRpbWUgb2YgZGF5IikgKwogIHRoZW1lKAogICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgYXhpcy5saW5lLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X2JsYW5rKCksCiAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMudGlja3MueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGF4aXMubGluZS54ID0gZWxlbWVudF9saW5lKGFycm93ID0gYXJyb3coCiAgICAgIGxlbmd0aCA9IHVuaXQoMC4yLCAibGluZXMiKSwgdHlwZSA9ICJjbG9zZWQiCiAgICApKSwKICAgIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9IGNvbG91cnNbMl0pLAogICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChjb2xvdXIgPSAnZ3JleTIwJykKICApCgpkZl90ZXh0IDwtIGRhdGEudGFibGUoCiAgeCA9IHJlcCgwLCBkYXRhX2NvbXBbLCB1bmlxdWVOKGRpdmV0eXBlKV0pLAogIGxhYmVsX3RvX29yZGVyID0gZGF0YV9jb21wWywgc29ydCh1bmlxdWUoZGl2ZXR5cGUpKV0sCiAgZGl2ZXR5cGUgPSBkYXRhX2NvbXBbLCBzb3J0KHVuaXF1ZShkaXZldHlwZSkpXSAlPiUKICAgIHdvcmQoMikgJT4lCiAgICBzdHJfdG9fdGl0bGUoKSwKICBwZXJjZW50YWdlID0gcm91bmQoYXMudmVjdG9yKHByb3AudGFibGUoZGF0YV9jb21wWwogICAgIWlzLm5hKGxhdCksCiAgICB0YWJsZShkaXZldHlwZSkKICBdKSkgKiAxMDAsIDEpCikgJT4lCiAgLlssIGxhYmVsX3RvX2Rpc3BsYXkgOj0gcGFzdGUwKGRpdmV0eXBlLCAiXG4oIiwgcGVyY2VudGFnZSwgIiAlKSIpXQpmaWdfdGV4dCA8LQogIGdncGxvdChkZl90ZXh0LCBhZXMoeCA9IHgsIHkgPSBsYWJlbF90b19vcmRlciwgbGFiZWwgPSBsYWJlbF90b19kaXNwbGF5KSkgKwogIGdlb21fdGV4dCgpICsKICB0aGVtZV92b2lkKCkKCmZpZ19sYWJlbF8xIDwtCiAgZ2dwbG90KGRhdGEuZnJhbWUobCA9ICJQZXJjZW50YWdlIG9mIGRpdmVzIiwgeCA9IDEsIHkgPSAxKSkgKwogIGdlb21fdGV4dChhZXMoeCwgeSwgbGFiZWwgPSBsKSkgKwogIHRoZW1lX3ZvaWQoKSArCiAgY29vcmRfY2FydGVzaWFuKGNsaXAgPSAib2ZmIikKYGBgCgpgYGB7ciBmaWcuY2FwID0gIkZyZXF1ZW5jeSBvZiBkaXZlIHR5cGVzIGFjcm9zcyB0aW1lIG9mIGRheSBhbmQgc3BlY2llcy4gU3BlY2llcy13aWRlIHN0YXRpc3RpY2FsIHRlc3Qgd2VyZSBiYXNlZCBvbiBhdmVyYWdlcyBvZiBlYWNoIGluZGl2aWR1YWzigJlzIGRpdmUgdHlwZSBwcm9wb3J0aW9uIHdlaWdodGVkIGJ5IHRoZSB0b3RhbCBudW1iZXIgb2YgZGl2ZXMuIFBlcmNlbnRhZ2VzIGluIHRoZSBtaWRkbGUgcGFuZWwgcmVwcmVzZW50IHRoZSBmcmVxdWVuY3kgb2YgZWFjaCBkaXZlIHR5cGUgYWNyb3NzIHNwZWNpZXMgYW5kIHRpbWUgb2YgZGF5LiBBc3Rlcmlza3MgaW5kaWNhdGUgYSBzaWduaWZpY2FudCBkaWZmZXJlbmNlIChQLXZhbHVlPDAuMDAwMSkgYmV0d2VlbiBkYXktdGltZSBhbmQgbmlnaHQtdGltZSBkaXZlIGZyZXF1ZW5jaWVzIHdpdGhpbiBlYWNoIHNwZWNpZXMgKHR3by1zYW1wbGUgei10ZXN0KS4ifQooKGZpZ19uZXNfcHJvcCB8IGZpZ190ZXh0IHwgZmlnX3Nlc19wcm9wKSArCiAgIHBsb3RfbGF5b3V0KAogICAgIHdpZHRocyA9IGMoNCwgMSwgNCksCiAgICAgZ3VpZGVzID0gImNvbGxlY3QiCiAgICkgJgogICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikpIC8gZmlnX2xhYmVsXzEgKwogIHBsb3RfbGF5b3V0KGhlaWdodHMgPSBjKDYsIDEpKQpgYGAKCiMjIEZpZ3VyZSA0IHstfQoKYGBge3IgY2FjaGU9Rn0KIyBjYWxjdWxhdGUgdGhlIG1lZGlhbiBvZiBkcmlmdHJhdGUgZm9yIGVhY2ggZGF5Cm1lZGlhbl9kcmlmdHJhdGUgPC0gZGF0YV9jb21wW2RpdmV0eXBlID09ICIyOiBkcmlmdCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC4oZHJpZnRyYXRlID0gcXVhbnRpbGUoZHJpZnRyYXRlLCAwLjUpKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnkgPSAuKGRheV9kZXBhcnR1cmUsIC5pZCwgc3ApCl0gJT4lCiAgLlssIHNwIDo9IGZpZmVsc2Uoc3AgPT0gIm5lcyIsICJOb3J0aGVybiIsICJTb3V0aGVybiIpXQoKIyBpbml0aWFsIHBsb3RzCmZpZ19kcmlmdHJhdGVfaW5pIDwtIHBsb3RfY29tcCgKICBtZWRpYW5fZHJpZnRyYXRlLAogICJkcmlmdHJhdGUiLAogIGdyb3VwX3RvX2NvbXBhcmUgPSAic3AiLAogIG5iX2RheXMgPSAyMDAsCiAgcmliYm9uID0gVCwKICBsaW5ldHlwZV9yaWJib24gPSAwLAogIHBvaW50ID0gRiwKICBjb2xvdXJzID0gY29sb3VycwopCmBgYAoKYGBge3J9CiMgZ2V0IGxpbWl0cwpkcmlmdHJhdGVfbGltaXRzIDwtIGdncGxvdF9idWlsZChmaWdfZHJpZnRyYXRlX2luaSkkbGF5b3V0JHBhbmVsX3BhcmFtc1tbMV1dJHkucmFuZ2UKCiMgdXBkYXRlIGluaXRpYWwgcGxvdHMKZmlnX2RyaWZ0cmF0ZSA8LSBmaWdfZHJpZnRyYXRlX2luaSArCiAgbGFicygKICAgIHkgPSBleHByZXNzaW9uKHBhc3RlKCJEYWlseSBtZWRpYW4gZHJpZnQgcmF0ZSAobS4iLCBzXi0xLCAiKSIpKSwKICAgIHggPSAiTnVtYmVyIG9mIGRheXMgc2luY2UgZGVwYXJ0dXJlIiwKICAgIGNvbG91ciA9ICJFbGVwaGFudCBzZWFsIiwKICAgIGZpbGwgPSAiRWxlcGhhbnQgc2VhbCIKICApICsKICBnZW9tX2hsaW5lKAogICAgeWludGVyY2VwdCA9IDAsCiAgICBsaW5ldHlwZSA9IDIsCiAgICBzaXplID0gMSwKICAgIGNvbCA9ICJibGFjayIKICApICsKICBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGRyaWZ0cmF0ZV9saW1pdHMpICsKICB0aGVtZV9qam8oKSArCiAgdGhlbWUoCiAgICBsZWdlbmQucG9zaXRpb24gPSAidG9wIgogICkKCiMgZGVuc2l0eSBwbG90cwpmaWdfZGVuc19kcmlmdHJhdGUgPC0KICBnZ3Bsb3QoCiAgICBkYXRhX2NvbXBbZGl2ZXR5cGUgPT0gIjI6IGRyaWZ0IiAmIGRheV9kZXBhcnR1cmUgPD0gMjAwLCBdLAogICAgYWVzKHkgPSBkcmlmdHJhdGUsIGZpbGwgPSBzcCkKICApICsKICBnZW9tX2RlbnNpdHkoc2hvdy5sZWdlbmQgPSBGLCBjb2wgPSAiYmxhY2siLCBhbHBoYSA9IDAuNCwgc2l6ZSA9IDAuMykgKwogIGNvb3JkX2NhcnRlc2lhbih5bGltID0gZHJpZnRyYXRlX2xpbWl0cykgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNvbG91cnMpICsKICB0aGVtZV92b2lkKCkKYGBgCgpgYGB7ciBmaWcuY2FwID0gIkNoYW5nZXMgaW4gbWVkaWFuIGRyaWZ0IHJhdGUgYWNyb3NzIHRoZSBmaXJzdCB0cmlwIHRvIHNlYSBpbiBub3J0aGVybiAobj00KSBhbmQgc291dGhlcm4gKG49OSkgZWxlcGhhbnQgc2VhbHMgZXN0aW1hdGVkIGZyb20gYSBnZW5lcmFsaXplZCBhZGRpdGl2ZSBtb2RlbC4gVGhlIGJvbGQgc29saWQgbGluZXMgcmVwcmVzZW50IHRoZSBtZWFuIHNwZWNpZXMtbGV2ZWwgcmVzcG9uc2VzIHdoaWxlIHRoZSB0aGluIGxpbmVzIHJlcHJlc2VudCBpbmRpdmlkdWFsLWxldmVsIHJlc3BvbnNlcy4gVGhlIHNoYWRlZCBhcmVhcyByZXByZXNlbnQgdGhlIDk1JSBjb25maWRlbmNlIGludGVydmFsLCBhbmQgdGhlIGJsYWNrIGRhc2hlZCBsaW5lIGluZGljYXRlcyBuZXV0cmFsIGJ1b3lhbmN5LiBNYXJnaW5hbCBkZW5zaXR5IHBsb3RzIGluZGljYXRlIHRoZSBzcHJlYWQgb2YgZGF0YSBhY3Jvc3MgdGhlIGVudGlyZSBtaWdyYXRpb24gZm9yIGVhY2ggc3BlY2llcy4ifQooZmlnX2RyaWZ0cmF0ZSB8IGZpZ19kZW5zX2RyaWZ0cmF0ZSkgKyBwbG90X2xheW91dCh3aWR0aHMgPSBjKDUsIDEpKQpgYGAKCiMjIEV4dHJhIHstfQoKYGBge3IgZmlnLmNhcD0iRGFpbHkgbWVkaWFuIGRyaWZ0IHJhdGUgdnMuIGRhaWx5IG1lZGlhbiBvZiBtYXhpbXVtIGRpdmUgZGVwdGgifQpkYXRhX2NvbXBbZGl2ZXR5cGUgPT0gIjI6IGRyaWZ0IiwKICAgICAgICAgIC4oZHJpZnRyYXRlID0gbWVkaWFuKGRyaWZ0cmF0ZSwgbmEucm0gPSBUKSksCiAgICAgICAgICBieSA9IC4oLmlkLCBkYXlfZGVwYXJ0dXJlLCBzcF9yZW5hbWUpCl0gJT4lCiAgbWVyZ2UoLiwgZGF0YV9jb21wWywKICAgICAgICAgICAgICAgICAgICAgLihtYXhkZXB0aCA9IG1lZGlhbihtYXhkZXB0aCwgbmEucm0gPSBUKSksCiAgICAgICAgICAgICAgICAgICAgIGJ5ID0gLiguaWQsIGRheV9kZXBhcnR1cmUsIHNwX3JlbmFtZSkKICBdLAogIGJ5ID0gYygiLmlkIiwgImRheV9kZXBhcnR1cmUiLCAic3BfcmVuYW1lIikKICApICU+JQogIGdncGxvdChhZXMoeSA9IGRyaWZ0cmF0ZSwgeCA9IG1heGRlcHRoLCBjb2wgPSB3b3JkKHNwX3JlbmFtZSwgMSkpKSArCiAgZ2VvbV9wb2ludCgpICsKICBzY2FsZV9jb2xvcl9tYW51YWwoCiAgICB2YWx1ZXMgPSBjb2xvdXJzLAogICAgbmFtZSA9ICJFbGVwaGFudCBzZWFscyIKICApICsKICBsYWJzKAogICAgeCA9ICJEYWlseSBtZWRpYW4gZGl2ZSBkZXB0aCAobSkiLAogICAgeSA9ICJEYWlseSBtZWRpYW4gZHJpZnQgcmF0ZSAobS9zKSIKICApICsKICB0aGVtZV9qam8oKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpCmBgYAoKYGBge3IgZmlnLmNhcD0iRGFpbHkgbWVkaWFuIGRyaWZ0IHJhdGUgdnMuIGRhaWx5IG1heGltdW0gb2YgbWF4aW11bSBkaXZlIGRlcHRoIn0KZGF0YV9jb21wW2RpdmV0eXBlID09ICIyOiBkcmlmdCIsCiAgICAgICAgICAuKGRyaWZ0cmF0ZSA9IG1lZGlhbihkcmlmdHJhdGUsIG5hLnJtID0gVCkpLAogICAgICAgICAgYnkgPSAuKC5pZCwgZGF5X2RlcGFydHVyZSwgc3BfcmVuYW1lKQpdICU+JQogIG1lcmdlKC4sIGRhdGFfY29tcFssCiAgICAgICAgICAgICAgICAgICAgIC4obWF4ZGVwdGggPSBtYXgobWF4ZGVwdGgsIG5hLnJtID0gVCkpLAogICAgICAgICAgICAgICAgICAgICBieSA9IC4oLmlkLCBkYXlfZGVwYXJ0dXJlLCBzcF9yZW5hbWUpCiAgXSwKICBieSA9IGMoIi5pZCIsICJkYXlfZGVwYXJ0dXJlIiwgInNwX3JlbmFtZSIpCiAgKSAlPiUKICBnZ3Bsb3QoYWVzKHkgPSBkcmlmdHJhdGUsIHggPSBtYXhkZXB0aCwgY29sID0gd29yZChzcF9yZW5hbWUsIDEpKSkgKwogIGdlb21fcG9pbnQoKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKAogICAgdmFsdWVzID0gY29sb3VycywKICAgIG5hbWUgPSAiRWxlcGhhbnQgc2VhbHMiCiAgKSArCiAgbGFicygKICAgIHggPSAiRGFpbHkgbWF4aW11bSBkaXZlIGRlcHRoIChtKSIsCiAgICB5ID0gIkRhaWx5IG1lZGlhbiBkcmlmdCByYXRlIChtL3MpIgogICkgKwogIHRoZW1lX2pqbygpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAidG9wIikKYGBgCgo+IEZyb20gdGhlc2UgdHdvIGdyYXBocywgSSBkb24ndCB0aGluayBpdCBjYW4gYmUgc2FpZCB0aGF0IHNvbWVob3cgYm9keSBjb25kaXRpb24gY29uc3RyYWlucyBkaXZlIGRlcHRoLCBzaW5jZSBkZWVwIGRpdmVzIG9jY3VyIGF0IHBvc2l0aXZlIGFuZCBuZWdhdGl2ZSBidW95YW5jaWVzLgoKIyBUYWJsZXMKCiMjIFRhYmxlIDEgey19CgpJIHRob3VnaHQgYWJvdXQgZG9pbmcgYSB0YWJsZSB0aGF0IHByb3ZpZGVzIHN1bW1hcnkgaW5mb3JtYXRpb24gYW5kIGdpdmVzIGEgcmFwaWQgb3ZlcnZpZXcgb2YgdGhlIGRhdGFzZXQuCgpgYGB7cn0KIyBiYXNlZCBvbgojIGh0dHBzOi8vdGhlbW9ja3VwLmJsb2cvcG9zdHMvMjAyMC0xMC0zMS1lbWJlZGRpbmctY3VzdG9tLWZlYXR1cmVzLWluLWd0LXRhYmxlcy8KZ3RfZ2dwbG90X2RyaWZ0cmF0ZSA8LSBmdW5jdGlvbih0YWJsZV9kYXRhLCBwbG90X2NvbCwgZGF0YV9jb2wsIHBsb3RfZnVuLCAuLi4pIHsKICAjIHNhdmUgdGhlIGRhdGEgZXh0cmFjdCBhaGVhZCBvZiB0aW1lCiAgIyB0byBiZSB1c2VkIGluIG91ciBhbm9ueW1vdXMgZnVuY3Rpb24gYmVsb3cKICBkYXRhX2luIDwtIHB1cnJyOjpwbHVjayh0YWJsZV9kYXRhLCAiX2RhdGEiLCBkYXRhX2NvbCkKCiAgIyByZXRyaWV2ZSBtaW4gbWF4CiAgcmFuZ2VfeCA8LSByYmluZGxpc3QoZGF0YV9pbilbLCByYW5nZShkYXlfZGVwYXJ0dXJlKV0KICByYW5nZV95IDwtIGMoLTAuMzUsIDAuMTUpCgogICMgZHJhdyBwbG90CiAgdGV4dF90cmFuc2Zvcm0oCiAgICB0YWJsZV9kYXRhLAogICAgIyBub3RlIHRoZSB1c2Ugb2Yge3t9fSBoZXJlIC0gdGhpcyBpcyB0aWR5IGV2YWwKICAgICMgdGhhdCBhbGxvd3MgeW91IHRvIGluZGljYXRlIHNwZWNpZmljIGNvbHVtbnMKICAgIGxvY2F0aW9ucyA9IGNlbGxzX2JvZHkoY29sdW1ucyA9IGMoe3sgcGxvdF9jb2wgfX0pKSwKICAgIGZuID0gZnVuY3Rpb24oeCkgewogICAgICAjIGJ1aWxkIHRoZSBwbG90CiAgICAgIHBsb3QgPC0gbGFwcGx5KGRhdGFfaW4sIGZ1bmN0aW9uKHgpIHsKICAgICAgICAjIGJ1aWxkIHRoZSBwbG90CiAgICAgICAgZ2dwbG90KHgpICsKICAgICAgICAgICMgZm9yIGNvbG9yIGh0dHBzOi8vZGF2aWRtYXRobG9naWMuY29tL2NvbG9yYmxpbmQvIyUyM0Q4MUI2MC0lMjMxRTg4RTUtJTIzRkZDMTA3LSUyMzAwNEQ0MAogICAgICAgICAgZ2VvbV9hcmVhKGFlcyh4ID0gZGF5X2RlcGFydHVyZSwgeSA9IGlmZWxzZShkcmlmdHJhdGUgPCAwLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkcmlmdHJhdGUsIDApKSwKICAgICAgICAgICAgICAgICAgICBmaWxsID0gIiM1RDNBOUIiLCBhbHBoYSA9IDAuNQogICAgICAgICAgKSArCiAgICAgICAgICAjIGZvciBjb2xvciBodHRwczovL2RhdmlkbWF0aGxvZ2ljLmNvbS9jb2xvcmJsaW5kLyMlMjNEODFCNjAtJTIzMUU4OEU1LSUyM0ZGQzEwNy0lMjMwMDRENDAKICAgICAgICAgIGdlb21fYXJlYShhZXMoeCA9IGRheV9kZXBhcnR1cmUsIHkgPSBpZmVsc2UoZHJpZnRyYXRlID4gMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZHJpZnRyYXRlLCAwKSksCiAgICAgICAgICAgICAgICAgICAgZmlsbCA9ICIjRTY2MTAwIiwgYWxwaGEgPSAwLjUKICAgICAgICAgICkgKwogICAgICAgICAgZ2VvbV9zZWdtZW50KGFlcyh4ID0gMCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IDAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHhlbmQgPSBtYXgoZGF5X2RlcGFydHVyZSkgKyAxMCAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHllbmQgPSAwKSwKICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gNywKICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSAiZ3JleTMwIiwKICAgICAgICAgICAgICAgICAgICAgICBhcnJvdyA9IGFycm93KHR5cGUgPSAiY2xvc2VkIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlbmd0aCA9IHVuaXQoMC4yLCB1bml0cyA9ICJucGMiKSkpICsKICAgICAgICAgIGNvb3JkX2NhcnRlc2lhbih4bGltID0gcmFuZ2VfeCwgeWxpbSA9IHJhbmdlX3kpICsKICAgICAgICAgIHRoZW1lX3ZvaWQoKSArCiAgICAgICAgICB0aGVtZSgKICAgICAgICAgICAgcGFuZWwuZ3JpZCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgKQogICAgICB9KQoKICAgICAgIyBkcmF3IGZvciBldmVyeSByb3cKICAgICAgbGFwcGx5KHBsb3QsIGdncGxvdF9pbWFnZSwgYXNwZWN0X3JhdGlvID0gNSwgaGVpZ2h0ID0gMjUpCiAgICB9CiAgKQp9Cmd0X2dncGxvdF9zcGFya2xpbmUgPC0gZnVuY3Rpb24odGFibGVfZGF0YSwgcGxvdF9jb2wsIGRhdGFfY29sLCBwbG90X2Z1biwgLi4uKSB7CiAgIyBzYXZlIHRoZSBkYXRhIGV4dHJhY3QgYWhlYWQgb2YgdGltZQogICMgdG8gYmUgdXNlZCBpbiBvdXIgYW5vbnltb3VzIGZ1bmN0aW9uIGJlbG93CiAgZGF0YV9pbiA8LSBwdXJycjo6cGx1Y2sodGFibGVfZGF0YSwgIl9kYXRhIiwgZGF0YV9jb2wpCgogICMgY29sbmFtZXMKICBjb2xfbmFtZXMgPC0gY29sbmFtZXMocmJpbmRsaXN0KGRhdGFfaW4pKQoKICAjIGludGVyZXN0IHZhcmlhYmxlCiAgdmFyX2ludGVyZXN0IDwtIHNldGRpZmYoY29sX25hbWVzLCAiZGF5X2RlcGFydHVyZSIpCgogICMgcmV0cmlldmUgbWluIG1heAogIHJhbmdlX3ggPC0gcmJpbmRsaXN0KGRhdGFfaW4pWywgcmFuZ2UoZGF5X2RlcGFydHVyZSldCiAgcmFuZ2VfeSA8LSByYmluZGxpc3QoZGF0YV9pbilbLCByYW5nZShnZXQodmFyX2ludGVyZXN0KSldCgogICMgZHJhdyBwbG90CiAgdGV4dF90cmFuc2Zvcm0oCiAgICB0YWJsZV9kYXRhLAogICAgIyBub3RlIHRoZSB1c2Ugb2Yge3t9fSBoZXJlIC0gdGhpcyBpcyB0aWR5IGV2YWwKICAgICMgdGhhdCBhbGxvd3MgeW91IHRvIGluZGljYXRlIHNwZWNpZmljIGNvbHVtbnMKICAgIGxvY2F0aW9ucyA9IGNlbGxzX2JvZHkoY29sdW1ucyA9IGMoe3sgcGxvdF9jb2wgfX0pKSwKICAgIGZuID0gZnVuY3Rpb24oeCkgewogICAgICAjIGJ1aWxkIHRoZSBwbG90CiAgICAgIHBsb3QgPC0gbGFwcGx5KGRhdGFfaW4sIGZ1bmN0aW9uKHgpIHsKICAgICAgICAjIGJ1aWxkIHRoZSBwbG90CiAgICAgICAgZ2dwbG90KHgsIGFlcyh4ID0gZGF5X2RlcGFydHVyZSwgeSA9IGdldCh2YXJfaW50ZXJlc3QpKSkgKwogICAgICAgICAgZ2VvbV9wYXRoKHNpemUgPSA2LCBjb2xvciA9ICJncmV5NjAiKSArCiAgICAgICAgICBnZW9tX3Ntb290aChzaXplID0gMTAsCiAgICAgICAgICAgICAgICAgICAgICBsaW5ldHlwZSA9ICJkYXNoZWQiLAogICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gImJsYWNrIiwKICAgICAgICAgICAgICAgICAgICAgIG1ldGhvZCA9ICJsbSIsCiAgICAgICAgICAgICAgICAgICAgICBzZSA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgbmEucm0gPSBUUlVFKSArCiAgICAgICAgICBjb29yZF9jYXJ0ZXNpYW4oeGxpbSA9IHJhbmdlX3gsIHlsaW0gPSByYW5nZV95KSArCiAgICAgICAgICB0aGVtZV92b2lkKCkgKwogICAgICAgICAgdGhlbWUoCiAgICAgICAgICAgIHBhbmVsLmdyaWQgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfYmxhbmsoKQogICAgICAgICAgKQogICAgICB9KQoKICAgICAgIyBkcmF3IGZvciBldmVyeSByb3cKICAgICAgbGFwcGx5KHBsb3QsIGdncGxvdF9pbWFnZSwgYXNwZWN0X3JhdGlvID0gNCwgaGVpZ2h0ID0gMjYpCiAgICB9CiAgKQp9CmBgYAoKYGBge3J9CiMgc3VtbWFyeV90YWJsZV9lcyA8LQpkYXRhX2NvbXBbLCB0cmF2ZWxfZGlzdGFuY2UgOj0gZGlzdEdlbygKICBtYXRyaXgoYyhsb24sIGxhdCksIG5jb2wgPSAyKSwKICBtYXRyaXgoYyhzaGlmdChsb24pLCBzaGlmdChsYXQpKSwgbmNvbCA9IDIpCiksCmJ5ID0gLmlkCl0gJT4lCiAgYXNfdGliYmxlKCkgJT4lCiAgbXV0YXRlKGlkX3JlbmFtZSA9IHdvcmQoLmlkLCAyLCBzZXAgPSAiXyIpKSAlPiUKICBncm91cF9ieShzcF9yZW5hbWUsIGlkX3JlbmFtZSkgJT4lCiAgc3VtbWFyaXNlKAogICAgTiA9IHByZXR0eU51bShuKCksCiAgICAgICAgICAgICAgICAgIGJpZy5tYXJrID0gIiwiLAogICAgICAgICAgICAgICAgICBzY2llbnRpZmljID0gRkFMU0UKICAgICksCiAgICBuYl9kYXlzID0gcm91bmQoYXMubnVtZXJpYyhkaWZmdGltZSgKICAgICAgbGFzdChkYXRlKSwgZmlyc3QoZGF0ZSksCiAgICAgIHVuaXRzID0gImRheXMiCiAgICApKSwgMSksCiAgICB0cmF2ZWxfZGlzdGFuY2UgPSBwcmV0dHlOdW0oCiAgICAgIHN1bSh0cmF2ZWxfZGlzdGFuY2UsIG5hLnJtID0gVCkgLyAxMDAwLAogICAgICBkaWdpdHMgPSAxLAogICAgICBiaWcubWFyayA9ICIsIiwKICAgICAgc2NpZW50aWZpYyA9IEZBTFNFCiAgICApLAogICAgTWF4ZGVwdGhfbWVhbiA9IHJvdW5kKG1lYW4obWF4ZGVwdGgpLDEpLAogICAgTWF4ZGVwdGhfcGx1c19taW51cyA9ICLCsSIsCiAgICBNYXhkZXB0aF9zZCA9IHJvdW5kKHNkKG1heGRlcHRoKSwxKSwKICAgIERkdXJhdGlvbl9tZWFuID0gcm91bmQobWVhbihkZHVyYXRpb24pLzYwLDEpLAogICAgRGR1cmF0aW9uX3BsdXNfbWludXMgPSAiwrEiLAogICAgRGR1cmF0aW9uX3NkID0gcm91bmQoc2QobWF4ZGVwdGgpLzYwLDEpLAogICAgLmdyb3VwcyA9ICJkcm9wIgogICkgJT4lCiAgIyByZXBsYWNlIHRyYXZlbF9kaXN0YW5jZSA9IDAgYnkgTkEKICBtdXRhdGUodHJhdmVsX2Rpc3RhbmNlID0gbmFfaWYodHJhdmVsX2Rpc3RhbmNlLCAwKSkgJT4lCiAgIyBhZGQgZHJpZnRyYXRlIGZyb20gZHJpZnQgZGl2ZXMKICBsZWZ0X2pvaW4oCiAgICAuLAogICAgZGF0YV9jb21wICU+JQogICAgICBhc190aWJibGUoKSAlPiUKICAgICAgbXV0YXRlKGlkX3JlbmFtZSA9IHdvcmQoLmlkLCAyLCBzZXAgPSAiXyIpKSAlPiUKICAgICAgZ3JvdXBfYnkoc3BfcmVuYW1lLCBpZF9yZW5hbWUsIGRheV9kZXBhcnR1cmUpICU+JQogICAgICBmaWx0ZXIoZGl2ZXR5cGUgPT0gIjI6IGRyaWZ0IikgJT4lCiAgICAgIHN1bW1hcmlzZSgKICAgICAgICBkcmlmdHJhdGUgPSBhcy5udW1lcmljKHF1YW50aWxlKAogICAgICAgICAgZHJpZnRyYXRlLCAwLjUsCiAgICAgICAgICBuYS5ybSA9IFQKICAgICAgICApKSwKICAgICAgICAuZ3JvdXBzID0gImRyb3AiCiAgICAgICkgJT4lCiAgICAgIGdyb3VwX2J5KHNwX3JlbmFtZSwgaWRfcmVuYW1lKSAlPiUKICAgICAgc3VtbWFyaXNlKAogICAgICAgIHNwYXJrbGluZV9kcmlmdHJhdGUgPSBsaXN0KAogICAgICAgICAgZGF0YS5mcmFtZSgKICAgICAgICAgICAgZHJpZnRyYXRlID0gZHJpZnRyYXRlLAogICAgICAgICAgICBkYXlfZGVwYXJ0dXJlID0gZGF5X2RlcGFydHVyZQogICAgICAgICAgKQogICAgICAgICksCiAgICAgICAgLmdyb3VwcyA9ICJkcm9wIgogICAgICApLAogICAgYnkgPSBjKCJzcF9yZW5hbWUiLCAiaWRfcmVuYW1lIikKICApICU+JQogICMgYWRkIHF1YW50aWxlIDk1IG9mIGRkdXJhdGlvbiBhbmQgbWF4X2RlcHRoCiAgbGVmdF9qb2luKAogICAgLiwKICAgIGRhdGFfY29tcCAlPiUKICAgICAgYXNfdGliYmxlKCkgJT4lCiAgICAgIG11dGF0ZShpZF9yZW5hbWUgPSB3b3JkKC5pZCwgMiwgc2VwID0gIl8iKSkgJT4lCiAgICAgIGdyb3VwX2J5KHNwX3JlbmFtZSwgaWRfcmVuYW1lLCBkYXlfZGVwYXJ0dXJlKSAlPiUKICAgICAgc3VtbWFyaXNlKAogICAgICAgIG1heGRlcHRoID0gYXMubnVtZXJpYyhxdWFudGlsZShtYXhkZXB0aCwgMC45NSwgbmEucm0gPSBUKSksCiAgICAgICAgZGR1cmF0aW9uID0gYXMubnVtZXJpYyhxdWFudGlsZShkZHVyYXRpb24sIDAuOTUsIG5hLnJtID0gVCkpLAogICAgICAgIC5ncm91cHMgPSAiZHJvcCIKICAgICAgKSAlPiUKICAgICAgZ3JvdXBfYnkoc3BfcmVuYW1lLCBpZF9yZW5hbWUpICU+JQogICAgICBzdW1tYXJpc2UoCiAgICAgICAgc3BhcmtsaW5lX3F0X2RkdXJhdGlvbiA9IGxpc3QoCiAgICAgICAgICBkYXRhLmZyYW1lKAogICAgICAgICAgICBkZHVyYXRpb24gPSBkZHVyYXRpb24sCiAgICAgICAgICAgIGRheV9kZXBhcnR1cmUgPSBkYXlfZGVwYXJ0dXJlCiAgICAgICAgICApKSwKICAgICAgICBzcGFya2xpbmVfcXRfbWF4ZGVwdGggPSBsaXN0KAogICAgICAgICAgZGF0YS5mcmFtZSgKICAgICAgICAgICAgbWF4ZGVwdGggPSAtbWF4ZGVwdGgsCiAgICAgICAgICAgIGRheV9kZXBhcnR1cmUgPSBkYXlfZGVwYXJ0dXJlCiAgICAgICAgICApKSwKICAgICAgICAuZ3JvdXBzID0gImRyb3AiCiAgICAgICksCiAgICBieSA9IGMoInNwX3JlbmFtZSIsICJpZF9yZW5hbWUiKQogICkgJT4lCiAgIyBhZGQgcGVyY2VudGFnZQogIGxlZnRfam9pbigKICAgIC4sCiAgICBkYXRhX2NvbXAgJT4lCiAgICAgIGFzX3RpYmJsZSgpICU+JQogICAgICBtdXRhdGUoaWRfcmVuYW1lID0gd29yZCguaWQsIDIsIHNlcCA9ICJfIikpICU+JQogICAgICBncm91cF9ieShzcF9yZW5hbWUsIGlkX3JlbmFtZSwgZGl2ZXR5cGUpICU+JQogICAgICBzdW1tYXJpc2UoCiAgICAgICAgbiA9IG4oKSwKICAgICAgICAuZ3JvdXBzID0gImRyb3AiCiAgICAgICkgJT4lCiAgICAgIGdyb3VwX2J5KHNwX3JlbmFtZSwgaWRfcmVuYW1lKSAlPiUKICAgICAgc3VtbWFyaXNlKAogICAgICAgIGRpdmV0eXBlX3BlcmMgPSByb3VuZChuICogMTAwIC8gc3VtKG4pKSwKICAgICAgICBkaXZldHlwZSwKICAgICAgICAuZ3JvdXBzID0gImRyb3AiCiAgICAgICkgJT4lCiAgICAgIGFycmFuZ2UoZGl2ZXR5cGUpICU+JQogICAgICBncm91cF9ieShzcF9yZW5hbWUsIGlkX3JlbmFtZSkgJT4lCiAgICAgIHN1bW1hcmlzZShkaXZldHlwZV9wZXJjID0gbGlzdChkaXZldHlwZV9wZXJjKSwgLmdyb3VwcyA9ICJkcm9wIiksCiAgICBieSA9IGMoInNwX3JlbmFtZSIsICJpZF9yZW5hbWUiKQogICkgJT4lCiAgIyBhZGQgd2VhbiBtYXNzIGJhc2VkIG9uIFdlYW5saW5nIERpdmUgTWV0YWRhLnhsc3gKICBsZWZ0X2pvaW4oCiAgICAuLAogICAgZGF0YS50YWJsZSgKICAgICAgaWRfcmVuYW1lID0gYygKICAgICAgICAiMjAxODA3MCIsCiAgICAgICAgIjIwMTgwNzIiLAogICAgICAgICIyMDE4MDc0IiwKICAgICAgICAiMjAxODA4MCIsCiAgICAgICAgIjE0MDA1OSIsCiAgICAgICAgIjE0MDA2MCIsCiAgICAgICAgIjE0MDA2MiIsCiAgICAgICAgIjE0MDA2MyIsCiAgICAgICAgIjE0MDA2OCIsCiAgICAgICAgIjE0MDA2OSIsCiAgICAgICAgIjE0MDA3MiIsCiAgICAgICAgIjE0MDA3MyIsCiAgICAgICAgIjE0MDA3NSIKICAgICAgKSwKICAgICAgc3BfcmVuYW1lID0gYygKICAgICAgICByZXAoIk5vcnRoZXJuIGVsZXBoYW50IHNlYWwiLCA0KSwKICAgICAgICByZXAoIlNvdXRoZXJuIGVsZXBoYW50IHNlYWwiLCA5KQogICAgICApLAogICAgICB3ZWFubWFzcyA9IGMoMTMyLCAxMzgsIDExOSwgMTQyLCAxMTgsIDExMiwgODUsIE5BLCAxMjUsIE5BLCBOQSwgMTAyLCBOQSkKICAgICksCiAgICBieSA9IGMoInNwX3JlbmFtZSIsICJpZF9yZW5hbWUiKQogICkgJT4lCiAgIyByZW9yZGVyIGNvbHVtbgogIHJlbG9jYXRlKG5iX2RheXMsIE4sIHRyYXZlbF9kaXN0YW5jZSwgd2Vhbm1hc3MsIGRpdmV0eXBlX3BlcmMsCiAgICAgICAgICAgLmFmdGVyID0gaWRfcmVuYW1lKSAlPiUKICAjIHNldHVwIGdyb3VwIHJvdwogIGd0KGdyb3VwbmFtZV9jb2wgPSAic3BfcmVuYW1lIikgJT4lCiAgIyBzcGFubmVyIChzZXZlcmFsIGNvbHVtbnMgaW50byBvbmUgY29sdW1uKQogIHRhYl9zcGFubmVyKAogICAgbGFiZWwgPSAiTWF4aW11bSBkZXB0aCAobSkiLAogICAgY29sdW1ucyA9IGMoCiAgICAgIE1heGRlcHRoX21lYW4sCiAgICAgIE1heGRlcHRoX3BsdXNfbWludXMsCiAgICAgIE1heGRlcHRoX3NkLAogICAgICBzcGFya2xpbmVfcXRfbWF4ZGVwdGgKICAgICkKICApICU+JQogIHRhYl9zcGFubmVyKAogICAgbGFiZWwgPSAiRGl2ZSBkdXJhdGlvbiAobWluKSIsCiAgICBjb2x1bW5zID0gYygKICAgICAgRGR1cmF0aW9uX21lYW4sCiAgICAgIERkdXJhdGlvbl9wbHVzX21pbnVzLAogICAgICBEZHVyYXRpb25fc2QsCiAgICAgIHNwYXJrbGluZV9xdF9kZHVyYXRpb24KICAgICkKICApICU+JQogIHRhYl9zcGFubmVyKAogICAgbGFiZWwgPSBtZCgiRGFpbHkgbWVkaWFuIGRyaWZ0IHJhdGUiKSwKICAgIGNvbHVtbnMgPSBjKHNwYXJrbGluZV9kcmlmdHJhdGUpCiAgKSAlPiUKICB0YWJfc3Bhbm5lcigKICAgIGxhYmVsID0gbWQoIlRyYXZlbCBkaXN0YW5jZSIpLAogICAgY29sdW1ucyA9IGModHJhdmVsX2Rpc3RhbmNlKQogICkgJT4lCiAgdGFiX3NwYW5uZXIoCiAgICBsYWJlbCA9IG1kKCJXZWFuaW5nIG1hc3MiKSwKICAgIGNvbHVtbnMgPSBjKHdlYW5tYXNzKQogICkgJT4lCiAgdGFiX3NwYW5uZXIoCiAgICBsYWJlbCA9IG1kKCJEaXZlIHR5cGUgcHJvcG9ydGlvbnMiKSwKICAgIGNvbHVtbnMgPSBjKGRpdmV0eXBlX3BlcmMpCiAgKSAlPiUKICAjIHBsb3QKICBndF9nZ3Bsb3Rfc3BhcmtsaW5lKHNwYXJrbGluZV9xdF9tYXhkZXB0aCwgInNwYXJrbGluZV9xdF9tYXhkZXB0aCIpICU+JQogIGd0X2dncGxvdF9zcGFya2xpbmUoc3BhcmtsaW5lX3F0X2RkdXJhdGlvbiwgInNwYXJrbGluZV9xdF9kZHVyYXRpb24iKSAlPiUKICBndF9nZ3Bsb3RfZHJpZnRyYXRlKHNwYXJrbGluZV9kcmlmdHJhdGUsICJzcGFya2xpbmVfZHJpZnRyYXRlIikgJT4lCiAgZ3RfcGx0X2Jhcl9zdGFja19leHRyYSgKICAgIGRpdmV0eXBlX3BlcmMsCiAgICB3aWR0aCA9IDY1LAogICAgbGFiZWxzID0gYygiVHJhbnNpdCIsICJGb3JhZ2luZyIsICJEcmlmdCIsICJCZW50aGljIiksCiAgICBwYWxldHRlID0gYygiIzAwMDAwMCIsICIjNDQ0NDQ0IiwgIiM4ODg4ODgiLCAiI0NDQ0NDQyIpCiAgKSAlPiUKICAjIGFsaWduZW1lbnQKICBjb2xzX2FsaWduKAogICAgY29sdW1ucyA9IGMoTiwgTWF4ZGVwdGhfc2QsIERkdXJhdGlvbl9zZCksCiAgICBhbGlnbiA9ICJsZWZ0IgogICkgJT4lCiAgY29sc19hbGlnbigKICAgIGNvbHVtbnMgPSBjKE4sIE1heGRlcHRoX21lYW4sIERkdXJhdGlvbl9tZWFuKSwKICAgIGFsaWduID0gInJpZ2h0IgogICkgJT4lCiAgY29sc19hbGlnbigKICAgIGNvbHVtbnMgPSBjKHRyYXZlbF9kaXN0YW5jZSwgd2Vhbm1hc3MsIE1heGRlcHRoX3BsdXNfbWludXMsIERkdXJhdGlvbl9wbHVzX21pbnVzKSwKICAgIGFsaWduID0gImNlbnRlciIKICApICU+JQogICMgZm9ybWF0CiAgZm10X251bWJlcigKICAgIGNvbHVtbnMgPSBNYXhkZXB0aF9tZWFuLAogICAgZGVjaW1hbCA9IDEKICApICU+JQogICAgZm10X251bWJlcigKICAgIGNvbHVtbnMgPSBlbmRzX3dpdGgoIl9zZCIpLAogICAgZGVjaW1hbCA9IDEKICApICU+JQogICMgcmVuYW1lIGNvbHVtbnMKICBjb2xzX2xhYmVsKAogICAgTiA9ICIjIGRpdmVzIiwKICAgIGlkX3JlbmFtZSA9IG1kKCJJRCIpLAogICAgbmJfZGF5cyA9ICIjIGRheXMiLAogICAgdHJhdmVsX2Rpc3RhbmNlID0gIihrbSkiLAogICAgd2Vhbm1hc3MgPSAiKGtnKSIsCiAgICBNYXhkZXB0aF9tZWFuID0gbWQoIk1lYW4iKSwKICAgIE1heGRlcHRoX3BsdXNfbWludXMgPSBtZCgiwrEiKSwKICAgIE1heGRlcHRoX3NkID0gbWQoIlNEIiksCiAgICBzcGFya2xpbmVfcXRfbWF4ZGVwdGggPSBtZCgiVHJlbmQiKSwKICAgIERkdXJhdGlvbl9tZWFuID0gbWQoIk1lYW4iKSwKICAgIERkdXJhdGlvbl9wbHVzX21pbnVzID0gbWQoIsKxIiksCiAgICBEZHVyYXRpb25fc2QgPSBtZCgiU0QiKSwKICAgIHNwYXJrbGluZV9kcmlmdHJhdGUgPSBtZCgiKG0uczxzdXA+LTE8L3N1cD4pIiksCiAgICBzcGFya2xpbmVfcXRfZGR1cmF0aW9uID0gbWQoIlRyZW5kIikKICApICU+JQogICMgYWRkIGNvbG9yIHNxdWFyZQogIHRleHRfdHJhbnNmb3JtKAogICAgbG9jYXRpb25zID0gY2VsbHNfcm93X2dyb3VwcygpLAogICAgZm4gPSBmdW5jdGlvbih4KSB7CiAgICAgICMgaWRlbnRpZnkgc3AKICAgICAgc3AgPC0gdW5pcXVlKHgpCiAgICAgICMgc2V0IGNvbG91cgogICAgICBjb2xvdXIgPC0KICAgICAgICBpZl9lbHNlKGdyZXBsKCJOb3J0aGVybiIsIHNwKSwgY29sb3Vyc1sxXSwgY29sb3Vyc1syXSkKICAgICAgIyBodG1sIHRvIGFkZCB0aGUgY29sb3IgYm94CiAgICAgIHB1cnJyOjptYXAoeCwgfiBodG1sKAogICAgICAgIGdsdWUoCiAgICAgICAgICAiPGRpdj48c3BhbiBzdHlsZT0naGVpZ2h0OiAxNXB4O3dpZHRoOiAxNXB4O2JhY2tncm91bmQtY29sb3I6IHtjb2xvdXJ9O2Rpc3BsYXk6IGlubGluZS1ibG9jaztib3JkZXItcmFkaXVzOjVweDtmbG9hdDpsZWZ0O3RvcDoxMyU7bGVmdDo1JTsnPC9zcGFuPiA8c3BhbiBzdHlsZT0nZGlzcGxheTogaW5saW5lLWJsb2NrO2Zsb2F0OmxlZnQ7bGluZS1oZWlnaHQ6MjBweDtwYWRkaW5nOiAwcHggMjVweDt3aGl0ZS1zcGFjZTpub3dyYXA7Jz57c3B9PC9zcGFuPjwvZGl2PiIKICAgICAgICApCiAgICAgICkpCiAgICB9CiAgKSAlPiUKICAjIGNvbG9yIGNvbHMKICBndF9oaWdobGlnaHRfY29scygKICAgIGNvbHVtbnMgPSBjKAogICAgICBNYXhkZXB0aF9tZWFuLAogICAgICBNYXhkZXB0aF9wbHVzX21pbnVzLAogICAgICBNYXhkZXB0aF9zZCwKICAgICAgc3BhcmtsaW5lX3F0X21heGRlcHRoLAogICAgICBzcGFya2xpbmVfZHJpZnRyYXRlLAogICAgICB3ZWFubWFzcywKICAgICAgTgogICAgKSwKICAgIGZpbGwgPSAibGlnaHRncmV5IiwKICAgIGFscGhhID0gMC41CiAgKSAlPiUKICAjIGZvb3Rub3RlCiAgdGFiX2Zvb3Rub3RlKAogICAgZm9vdG5vdGUgPSAiUmVjb3JkZWQiLAogICAgbG9jYXRpb25zID0gY2VsbHNfY29sdW1uX2xhYmVscyhjb2x1bW5zID0gYyhOLCBuYl9kYXlzKSkKICApICU+JQogICMgY29sb3Igcm93cwogIG9wdF9yb3dfc3RyaXBpbmcoKSAlPiUKICAjIHNldCBob3Jpem9udGFsIHBhZGRpbmcgZm9yIHBsdXMgbWludXMKICB0YWJfc3R5bGUoc3R5bGUgPSAicGFkZGluZy1sZWZ0OjBweDtwYWRkaW5nLXJpZ2h0OjBweDsiLAogICAgICAgICAgICBsb2NhdGlvbnMgPSBjZWxsc19jb2x1bW5fbGFiZWxzKGNvbHVtbnMgPSBlbmRzX3dpdGgoInBsdXNfbWludXMiKSkpICU+JQogICAgICB0YWJfc3R5bGUoc3R5bGUgPSAicGFkZGluZy1sZWZ0OjBweDtwYWRkaW5nLXJpZ2h0OjBweDsiLAogICAgICAgICAgICBsb2NhdGlvbnMgPSBjZWxsc19ib2R5KGNvbHVtbnMgPSBlbmRzX3dpdGgoInBsdXNfbWludXMiKSkpICU+JQogICMgc2V0IGhvcml6b250YWwgcGFkZGluZyBmb3IgcGx1cyBtaW51cwogIHRhYl9zdHlsZShzdHlsZSA9ICJwYWRkaW5nLXRvcDowcHg7cGFkZGluZy1ib3R0b206MHB4IiwKICAgICAgICAgICAgbG9jYXRpb25zID0gY2VsbHNfYm9keShjb2x1bW5zID0gc3RhcnRzX3dpdGgoInNwYXJrbGluZSIpKSkgJT4lCiAgIyBzZXR0aW5ncwogIHRhYl9vcHRpb25zKAogICAgIyAjIHdpZHRoIHRhYmxlCiAgICB0YWJsZS53aWR0aCA9IHBjdCgxNzUpLAogICAgIyBwYWRkaW5nID0gdmVydGljYWwgc3BhY2UgYmV0d2VlbiByb3dzCiAgICBkYXRhX3Jvdy5wYWRkaW5nID0gcHgoMyksCiAgICAjIGhvcml6b250YWwgc2Nyb2xsCiAgICBjb250YWluZXIub3ZlcmZsb3cueCA9IFQpCgojICMgZm9yIGV4cG9ydAojIHN1bW1hcnlfdGFibGVfZXMgJT4lIGd0c2F2ZV9leHRyYSgKIyAgICJ0ZXN0X3RhYmxlXzIucG5nIiwKIyAgIHZ3aWR0aCA9IDEzMDAsCiMgICB2aGVpZ2h0ID0gNTgwLAojICAgY2xpcHJlY3QgPSAidmlld3BvcnQiCiMgKQpgYGAKClRpdGxlOiBEZXNjcmlwdGl2ZSBzdGF0aXN0aWNzIGFuZCB2aXN1YWwgcmVwcmVzZW50YXRpb25zIG9mIHRoZSBmaXJzdCBvZmZzaG9yZSBmb3JhZ2luZyB0cmlwIGZvciBlYWNoIG5vcnRoZXJuIGFuZCBzb3V0aGVybiBlbGVwaGFudCBzZWFsIGluIHRoZSBkYXRhc2V0LiBGb3IgbWF4aW11bSBkZXB0aCAobSkgYW5kIGRpdmUgZHVyYXRpb24gKG1pbiksIHRoZSB0cmVuZCByZXByZXNlbnRzIHRoZSBjaGFuZ2VzIGluIHRoZSBkYWlseSA5NXRoIHBlcmNlbnRpbGUgdGhyb3VnaCB0aW1lIGluIGEgc29saWQgZ3JheSBsaW5lIGFzc29jaWF0ZWQgd2l0aCBhIGxpbmVhciByZWdyZXNzaW9uIGluIGJsYWNrIGRhc2hlcy4gRm9yIGRyaWZ0IHJhdGUgKG0ucy0xKSwgdGhlIGRhaWx5IG1lZGlhbiB3YXMgY2FsY3VsYXRlZCB0byByZXByZXNlbnQgdGhlIGV2b2x1dGlvbiBvdmVyIHRpbWUsIHdpdGggcG9zaXRpdmUgdmFsdWVzIGluIG9yYW5nZSBhbmQgbmVnYXRpdmUgaW4gcHVycGxlLgoKIyMgRXh0cmEgey19CgpgYGB7cn0KIyBieSBzcGVjaWVzCmRhdGFfY29tcCAlPiUKICAuWyFpcy5uYShsYXQpLCBgOj1gKAogICAgc3VucmlzZV90b2RheSA9IG1hcHRvb2xzOjpzdW5yaXNldChtYXRyaXgoYyhsb24sIGxhdCksIG5jb2wgPSAyKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0ZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlyZWN0aW9uID0gInN1bnJpc2UiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBQT1NJWGN0Lm91dCA9IFRSVUUKICAgICkkdGltZSwKICAgIHN1bnNldF90b2RheSA9IG1hcHRvb2xzOjpzdW5yaXNldChtYXRyaXgoYyhsb24sIGxhdCksIG5jb2wgPSAyKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpcmVjdGlvbiA9ICJzdW5zZXQiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFBPU0lYY3Qub3V0ID0gVFJVRQogICAgKSR0aW1lCiAgKSwgXSAlPiUKICAjIGNhbGN1bGF0aW9uIGRheS10aW1lIGxlbmd0aAogIC5bLCBkYXlfdGltZSA6PSBhcy5udW1lcmljKGRpZmZ0aW1lKHN1bnNldF90b2RheSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdW5yaXNlX3RvZGF5LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVuaXRzID0gImhvdXJzIikpXSAlPiUKICAjIGNhbGN1bGF0aW9uIG5pZ2h0LXRpbWUgbGVuZ3RoCiAgLlssIG5pZ2h0X3RpbWUgOj0gMjQgLSBkYXlfdGltZV0gJT4lCiAgIyBjYWxjdWxhdGUgbWF4ZGVwdGggYW5kIGRkdXJhdGlvbgogIC5bLCAuKAogICAgcmVzdWx0X2RlcHRoID0gcGFzdGUocm91bmQobWVhbihtYXhkZXB0aCksIDEpLAogICAgICAgICAgICAgICAgICAgICAgICAgIsKxIiwKICAgICAgICAgICAgICAgICAgICAgICAgIHJvdW5kKHNkKG1heGRlcHRoKSwgMSkpLAogICAgcmVzdWx0X2R1cmF0aW9uID0gcGFzdGUocm91bmQobWVhbihkZHVyYXRpb24gLyA2MCksIDEpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIsKxIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJvdW5kKHNkKGRkdXJhdGlvbiAvIDYwKSwgMSkpLAogICAgcmVzdWx0X2RheV90aW1lID0gcGFzdGUocm91bmQobWVhbihkYXlfdGltZSwgbmEucm0gPSBUKSwgMSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiwrEiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgcm91bmQoc2QoZGF5X3RpbWUsIG5hLnJtID0gVCksIDEpKSwKICAgIHJlc3VsdF9uaWdodF90aW1lID0gcGFzdGUocm91bmQobWVhbihuaWdodF90aW1lLCBuYS5ybSA9IFQpLCAxKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIsKxIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcm91bmQoc2QobmlnaHRfdGltZSwgbmEucm0gPSBUKSwgMSkpCiAgKSwgYnkgPSAuKHNwX3JlbmFtZSldICU+JQogICMgYWRkIHdlYW4gbWFzcyBiYXNlZCBvbiBXZWFubGluZyBEaXZlIE1ldGFkYS54bHN4CiAgbWVyZ2UoLiwgZGF0YS50YWJsZSgKICAgIGlkX3JlbmFtZSA9IGMoCiAgICAgICIyMDE4MDcwIiwKICAgICAgIjIwMTgwNzIiLAogICAgICAiMjAxODA3NCIsCiAgICAgICIyMDE4MDgwIiwKICAgICAgIjE0MDA1OSIsCiAgICAgICIxNDAwNjAiLAogICAgICAiMTQwMDYyIiwKICAgICAgIjE0MDA2MyIsCiAgICAgICIxNDAwNjgiLAogICAgICAiMTQwMDY5IiwKICAgICAgIjE0MDA3MiIsCiAgICAgICIxNDAwNzMiLAogICAgICAiMTQwMDc1IgogICAgKSwKICAgIHNwX3JlbmFtZSA9IGMoCiAgICAgIHJlcCgiTm9ydGhlcm4gZWxlcGhhbnQgc2VhbCIsIDQpLAogICAgICByZXAoIlNvdXRoZXJuIGVsZXBoYW50IHNlYWwiLCA5KQogICAgKSwKICAgIHdlYW5tYXNzID0gYygxMzIsIDEzOCwgMTE5LCAxNDIsIDExOCwgMTEyLCA4NSwgTkEsIDEyNSwgTkEsIE5BLCAxMDIsIE5BKQogICkgJT4lCiAgICAuWywgLihyZXN1bHRfbWFzcyA9IHBhc3RlKAogICAgICByb3VuZChtZWFuKHdlYW5tYXNzLCBuYS5ybSA9IFQpLCAxKSwKICAgICAgIsKxIiwKICAgICAgcm91bmQoc2Qod2Vhbm1hc3MsIG5hLnJtID0gVCksIDEpCiAgICApKSwKICAgIGJ5ID0gc3BfcmVuYW1lCiAgICBdLAogIGJ5ID0gYygic3BfcmVuYW1lIikKICApICU+JQogIG1lcmdlKC4sIGRhdGFfY29tcFssIC4odHJhdmVsX2Rpc3RhbmNlID0gc3VtKHRyYXZlbF9kaXN0YW5jZSwgbmEucm0gPSBUKSAvIDEwMDApLAogICAgICAgICAgICAgICAgICAgICBieSA9IC4oLmlkLCBzcF9yZW5hbWUpXSAlPiUKICAgICAgICAgIC5bLCB0cmF2ZWxfZGlzdGFuY2UgOj0gbmFfaWYodHJhdmVsX2Rpc3RhbmNlLCAwKV0gJT4lCiAgICAgICAgICAuWywgLihyZXN1bHRfZGlzdGFuY2UgPSBwYXN0ZShyb3VuZChtZWFuKAogICAgICAgICAgICB0cmF2ZWxfZGlzdGFuY2UsCiAgICAgICAgICAgIG5hLnJtID0gVAogICAgICAgICAgKSwgMSksICLCsSIsIHJvdW5kKHNkKAogICAgICAgICAgICB0cmF2ZWxfZGlzdGFuY2UsCiAgICAgICAgICAgIG5hLnJtID0gVAogICAgICAgICAgKSwgMSkpKSwgYnkgPSAuKHNwX3JlbmFtZSldLCBieSA9ICJzcF9yZW5hbWUiKSAlPiUKICBndCgpCmBgYApgYGB7cn0KZGF0YV9jb21wWywgLigKICBuYl9kYXlzID0gYXMubnVtZXJpYyhkaWZmdGltZShtYXgoZGF0ZSksIG1pbihkYXRlKSwgdW5pdHMgPSAiZGF5IikpLAogIGRpc3Rfa20gPSBzdW0odHJhdmVsX2Rpc3RhbmNlLCBuYS5ybSA9IFQpIC8gMTAwMAopLCBieSA9IC4oLmlkKV0gJT4lCiAgLlssIGRpc3Rfa20gOj0gbmFfaWYoZGlzdF9rbSwgMCldICU+JQogIC5bLCBsYXBwbHkoLlNELCBmdW5jdGlvbih4KSB7CiAgICBjKAogICAgICByb3VuZChtZWFuKHgsIG5hLnJtID0gVCksIDIpLAogICAgICByb3VuZChzZCh4LCBuYS5ybSA9IFQpLCAyKQogICAgKQogIH0pLAogIC5TRGNvbHMgPSBjKCJuYl9kYXlzIiwgImRpc3Rfa20iKQogIF0gJT4lCiAgZGF0YS50YWJsZTo6dHJhbnNwb3NlKC4sIGtlZXAubmFtZXMgPSAiUGFyYW1ldGVyIikgJT4lCiAgc2V0bmFtZXMoLiwgYygiUGFyYW1ldGVycyIsICJtZWFuIiwgInNkIikpICU+JQogIC5bXSAlPiUKICBndCgpCmBgYAo=