Introduction

This is an R Markdown document that documents data analyses for the manuscript Zander et al (Seasonal climate signals preserved in biochemical varves: insights from novel high-resolution sediment scanning techniques). For full interpretation of the data and plots contained here, please see the associated manuscript. Any use of data and plots should refer to Zander et al.

Load packages and data

setwd(dirname(rstudioapi::getActiveDocumentContext()$path))
Sys.setenv(LANGUAGE = "en")
# Check and install pacman if neccesary
if (!require("pacman")) {
  install.packages("pacman")
  library(pacman)
}

# Load libraries
pacman::p_load(
  data.table, dtw, ggplot2, tidyverse, grid, lineup, vegan, corrplot, psych, distantia,
  viridis, pracma, reshape2, mgcv, gridExtra, gamclass, cowplot, mvnormtest
)
# Load data
XRF <- read.csv("ZAB_HiRes_XRF.csv")
CNS <- read.csv("ZAB_CNS_2020.csv")
HSI <- read.csv("ZAB_HiRes_HSI.csv")
Chrono <- read.csv("Chrono_Tornado.csv")
meteo <- read.csv("meteo_1966_2020.csv")

Preparing scanning data: Corrections, assigning ages, and aligning datasets

# Correction to TOC and TN to account for degration/remineralization using formula from galman et al 2008 (Limnology and Oceanography)
CNS$year <- as.numeric(CNS$year)
CNS$toc_p <- as.numeric(CNS$toc_p)
CNS$toc_corr <- (CNS$toc_p + (23.41 * (2020.3 - CNS$year + 0.5) / (2020.3 - CNS$year + 0.5 + 1) / 100) * CNS$toc_p) # 2020.3 represents approximate date of coring
CNS$tn_corr <- (CNS$tn_p + (36.17 * (2020.3 - CNS$year + 0.5) / (2020.3 - CNS$year + 0.5 + 1) / 100) * CNS$tn_p)
CNS$tc_corr <- CNS$tic_p + CNS$toc_corr

plot(CNS$tc_corr, CNS$year, type = "l", ylim = c(2000, 2020), main = "Total carbon with and without toc decay correction")
lines(CNS$tc_p, CNS$year, col = "blue")

CNS$toc.n_corr <- CNS$toc_corr / CNS$tn_corr
# Mass accumulation rate caclulation
CNS$MAR <- CNS$calib.thickness.mm * CNS$dry_bulk_density_gcm3


# removing cracks
XRF_scaled <- cbind(XRF[, -c(4:16)], scale(XRF[, c(4:16)]))
crack_finder <- XRF_scaled$Ca.KA + XRF_scaled$Fe.KA + XRF_scaled$Si.KA # counts of abundant elements
XRF <- cbind(XRF, crack_finder)
XRF <- subset.data.frame(XRF, crack_finder > -2.9) # remove cracks (defined as areas with low abundances of common elements)

# assign ages based on depths
for (i in 1:nrow(Chrono)) {
  setDT(XRF)[comp_depth_mm <= Chrono$Comp.Depth[i] & comp_depth_mm >= Chrono$Comp.Depth[i + 1], year := Chrono$Year[i]]
}

XRF <- subset(XRF, year != 0) # subset only depths with assigned ages
XRF$cum_year_scale <- 0

# setting each year to be 1 unit long
for (i in 1:nrow(Chrono)) {
  setDT(XRF)[year == Chrono$Year[i], year_scale := seq(1, 0.001, length.out = nrow(subset(XRF, year == Chrono$Year[i])))]
}
XRF$cum_year_scale <- XRF$year_scale + XRF$year + 0.3

##### HSI data
HSI$year_scale <- 0
HSI$year_scale <- as.numeric(HSI$year_scale)
HSI$year <- 0
HSI$year <- as.numeric(HSI$year)
for (i in 1:nrow(Chrono)) {
  setDT(HSI)[HSI_depth <= Chrono$HSI_depth[i] & HSI_depth >= Chrono$HSI_depth[i + 1], year := Chrono$Year[i]]
}
### calibrating rabd indices according to calibration published in Zander et al., 2021 (Science of Total Environment)
HSI$TChl <- 1560.48 * HSI$`RABD655.685max` - 1578.9
HSI$Bphe <- HSI$RABD845 * 861.18 - 851.65
HSI[HSI < 0] <- 0

# setting each year to be 1 unit long (HSI version)
HSI <- subset(HSI, year != 0) # only including years with ages
HSI$cum_year_scale <- 0
for (i in 1:nrow(Chrono)) {
  setDT(HSI)[year == Chrono$Year[i], year_scale := seq(1, 0.001, length.out = nrow(subset(HSI, year == Chrono$Year[i])))]
}
HSI$cum_year_scale <- HSI$year_scale + HSI$year + 0.3

#### aligning and regularlizing XRF and HSI data
Source <- as.data.frame(HSI[, c(11, 3, 4, 9, 10)])
Destin <- as.data.frame(XRF[, 21])
Names <- colnames(Source)

# interpolate data for all columns
Data <- Destin
for (i in 2:ncol(Source)) {
  temp <- approx(Source[, 1], Source[, i], xout = Destin[, 1])
  Data[, i] <- temp$y
}
# Replace destination depth with interpolated depth (just to be sure it worked)
Data[, 1] <- temp$x
# Replace column names with actual names
colnames(Data) <- c("Depth_cm", Names[2:length(Names)])

## Full Dataset !
HiRes_full <- cbind(XRF[, c(21, 20, 18, 4:8, 10:12)], Data[, c(3, 4, 5)])
colnames(HiRes_full) <- c("Age", "Varve Year", "Comp Depth", "Ca", "Fe", "Mn", "Si", "P", "S", "K", "Ti", "Rmean", "TChl", "Bphe")


###### Aligning HSI to XRF using dynamical time warp alignment of Rmean and Ca
HiRes_full_scaled <- cbind(HiRes_full[, 1:3], scale(HiRes_full[, 4:14]))
test_dtw_P2 <- dtw(x = HiRes_full_scaled$Rmean, y = HiRes_full_scaled$Ca, window.type = "sakoechiba", 
                   window.size = 50, step.pattern = symmetricP2, keep = TRUE) 
# Sakoe Chiba band is simple symmetrical window (window width here is equal to the thinnest varve width, i.e. <= 1 year)
# Testing showed symmetric P2 is most reasonable step pattern, but this could vary
plot(test_dtw_P2, type = "threeway")


HSI_regular <- na.omit(Data[, 2:5])
warp <- warp(test_dtw_P2, index.reference = FALSE)
HSI_DTW <- HSI_regular[warp, ]

# example plot of DTW alignment
plot(HiRes_full_scaled$Age-0.3, HiRes_full_scaled$Ca, type = "l", xlim = c(2015, 2020), ylim= c(-2.5,4.5), main = "example plot of DTW alignment", xlab= "C (%)", ylab = "Z-score")
lines(HiRes_full_scaled$Age-0.3, HiRes_full_scaled$Rmean, col = "red")
lines(HiRes_full_scaled$Age-0.3, scale(HSI_DTW$Rmean), col = "blue")
abline(v=c(2015,2016,2017,2018,2019), lty=3)
legend(x = "bottomright",          # Position
       legend = c("Ca", "Rmean", "Rmean (after DTW)"),  # Legend texts
       lty = 1,           # Line types
       col = c("black", "red", "blue"),           # Line colors
       lwd = 2)                 # Line width

Plotting full datasets

rm(test_dtw_P2)
# Putting together full, aligned dataset
HiRes_full[, 12:14] <- HSI_DTW[, c(2:4)]
colnames(HiRes_full)[c(2, 3)] <- c("varve_year", "comp_depth_mm")
HiRes_full_scaled <- cbind(HiRes_full[, 1:3], scale(HiRes_full[, 4:14]))
HiRes_full_sub1 <- HiRes_full[HiRes_full$`varve_year` >= 1966] # subset for study period 1966-2019

Plotting XRF and HSI data

color1 <- c("#c01d11", "2068c9", "#33799b", "#7c9b21", "#a54a0a", "#b3a22e", "#1798a1", "#a62b84", "#0f692d", "#500f8f") # color vector
XRF_piv <- tidyr::pivot_longer(HiRes_full, cols = c("Ca", "K", "Ti", "Si", "Fe", "S", "Mn", "P"), names_to = "proxy") # make sideways
xrf_data_plot_depth <- ggplot(XRF_piv, aes(value, comp_depth_mm, color = forcats::as_factor(proxy))) +
  geom_path() +
  scale_color_manual(values = color1) +
  scale_y_reverse(limits = c(345.06, 0.6)) +
  labs(y = "Depth (mm)", x = "cps", title = element_blank()) +
  facet_wrap(~proxy, ncol = 8, scales = "free") +
  theme_bw() +
  theme(
    strip.background = element_blank(),
    legend.box.background = element_blank(), legend.position = "none"
  )

HSI_piv <- tidyr::pivot_longer(HSI, cols = c("TChl", "Bphe"), names_to = "proxy") # make sideways
HSI_data_plot_depth <- ggplot(HSI_piv, aes(value, HSI_depth, color = forcats::as_factor(proxy))) +
  geom_path() +
  scale_color_manual(values = c("#0f692d", "#500f8f")) +
  scale_y_reverse(limits = c(320.04, 0.54)) +
  labs(y = element_blank(), x = "ug/g", title = element_blank()) +
  facet_wrap(~proxy, ncol = 8, scales = "free") +
  theme_bw() +
  theme(
    strip.background = element_blank(),
    legend.box.background = element_blank(), legend.position = "none"
  )

plot_grid(xrf_data_plot_depth, HSI_data_plot_depth, rel_widths = c(4 / 5, 1 / 5))

Plotting CNS, MAR, Cs-137

CNS <- CNS[CNS$year >= 1966 & CNS$year <= 2019, ]
par(mfrow = c(1, 6), mar = c(5.1, 2, 2, 1))
plot(CNS$tc_corr, CNS$year, ylim = c(1966, 2020), type = "o", pch = 16, xlim = c(0, 20), ylab = "Year (CE)", xlab = "C (% weight)")
lines(CNS$toc_corr, CNS$year, lty = 5, type = "o", pch = 16)
lines(CNS$tic_p, CNS$year, lty = 3, type = "o", pch = 16)
plot(CNS$toc.n_corr, CNS$year, ylim = c(1966, 2020), type = "o", pch = 16, xlim = c(0, 12), xlab = "TOC:N Ratio", yaxt = "n", lty = 3, ylab = "")
plot(CNS$tn_corr, CNS$year, ylim = c(1966, 2020), type = "o", pch = 16, xlim = c(0, 2), xlab = "N (% weight)", yaxt = "n", ylab = "")
plot(CNS$ts_p, CNS$year, ylim = c(1966, 2020), type = "o", pch = 16, xlim = c(0, 3), xlab = "S (% weight)", yaxt = "n", ylab = "")
plot(CNS$MAR, CNS$year, ylim = c(1966, 2020), type = "o", pch = 16, xlim = c(0, 2), xlab = "MAR (g cm-2 yr-1)", yaxt = "n", ylab = "")
plot(CNS[is.na(CNS$ZAB_12_1_Cs) == FALSE, ]$ZAB_12_1_Cs, CNS[is.na(CNS$ZAB_12_1_Cs) == FALSE, ]$year,
  ylim = c(1966, 2020), type = "o", pch = 16,
  xlab = "137Cs (Bq kg-1)", xlim = c(0, 350), yaxt = "n", ylab = ""
)
lines(CNS$Cs, CNS$year, type = "o", lty = 2, pch = 1)

Varve type classification based on multivariate clustering of sub-annual timeseries

Annual cyle

# First, aligning all data to a fractional varve year scale from 0 to 1
A <- rep("A", nrow(HiRes_full_sub1))
HiRes_full_sub1 <- as.data.frame(cbind(A, HiRes_full_sub1))

gap <- 0.02 # target resolution in fractional year units (each year will contain 50 data points)

int <- cut(HiRes_full_sub1$Age, seq(min(HiRes_full_sub1$Age), max(HiRes_full_sub1$Age + gap), by = gap), right = FALSE)
ag <- aggregate(HiRes_full_sub1[c(2, 4:15)], list(HiRes_full_sub1$A, int), mean)
ag$age_new <- seq(1966.3, 2020.28, length.out = nrow(ag))

ag$year_scale <- ag$age_new - floor(ag$age_new)
ag$year_scale <- round(ag$year_scale, 2)
for (i in 1:length(ag$year_scale)) {
  if (ag$year_scale[i] <= 0.3) {
    ag$year_scale[i] <- ag$year_scale[i] + 0.7
  } else {
    ag$year_scale[i] <- ag$year_scale[i] - 0.3
  }
}

ag <- as.data.frame(cbind(ag[16:17], ag[5:15]))
ag[, 3:13] <- scale(ag[, 3:13])
year_ag <- aggregate(ag[3:13], list(ag$year_scale), FUN = mean)

year_ag_piv1 <- tidyr::pivot_longer(year_ag, cols = c("Ca", "Ti", "Si", "Fe", "S", "Mn", "P", "TChl", "Bphe"), names_to = "proxy")
color2 <- c("#c01d11", "#33799b", "#7c9b21", "#a54a0a", "#b3a22e", "#1798a1", "#a62b84", "#0f692d", "#500f8f") # color vector
colnames(year_ag_piv1)[1] <- "year_scale"
#### annual cyle plot mean values
ann_cycle1 <- ggplot(year_ag_piv1, aes(year_scale, value, color = forcats::as_factor(proxy))) +
  geom_path(alpha = 0.6, lwd = 1.5) +
  scale_color_manual(values = color2) +
  labs(
    x = "",
    y = "Z-score",
    title = "Average Annual Cycle 1966-2019",
    color = "proxy"
  ) +
  theme_bw() +
  guides(colour = guide_legend(nrow = 1)) +
  theme(legend.position = "bottom")
ann_cycle1

Varve type classification based on multivariate time series clustering of within-varve time series

# preparing data for dissimilarity calculation: transform, detrend and scale data
sequence1 <- HiRes_full[, c(4:11, 13, 14)]
sequence1 <- sequence1 + 1
sequence1 <- log(sequence1)
sequence1 <- detrend(as.matrix(sequence1))
sequence1 <- as.data.frame(sequence1)
sequence1$`Bphe`[sequence1$`Bphe` <= sequence1$`Bphe`[6413]] <- sequence1$`Bphe`[6413] # resetting 0 baseline for Bphe after detrending
sequence1 <- cbind(HiRes_full$varve_year, XRF$year_scale[1:6413], scale(sequence1))
sequence1 <- as.data.frame(sequence1)
colnames(sequence1)[c(1, 2)] <- c("Varve_Year", "Year_scale")
sequence1 <- subset(sequence1, Varve_Year <= 2019 & Varve_Year >= 1966) # study period

psi1 <- workflowPsi(
  sequences = sequence1,
  grouping.column = "Varve_Year",
  time.column = "Year_scale",
  method = "euclidean",
  diagonal = TRUE,
  ignore.blocks = TRUE,
  format = "matrix"
)

hclust_1 <- hclust(as.dist(psi1), method = "ward.D2")
plot(hclust_1)

Heatmap of dissimilarity scores

psi1_nozero <- psi1
psi1_nozero[psi1_nozero == 0] <- NA
heatmap(psi1_nozero, Rowv = as.dendrogram(hclust_1), Colv = as.dendrogram(hclust_1), symm = TRUE, col = viridis(256))

mycl <- cutree(hclust_1, h = 5.3)
mycl <- as.data.frame(mycl)
colnames(mycl) <- c("group")
mycl$year <- rownames(mycl)

Bar plot - importance of each element in driving year-to-year dissimilarity

psi.importance <- workflowImportance(
  sequences = sequence1,
  grouping.column = "Varve_Year",
  time.column = "Year_scale",
  method = "euclidean",
  diagonal = TRUE,
  ignore.blocks = TRUE
)

psi.df <- psi.importance$psi
psi.drop.df <- psi.importance$psi.drop
barplot(colMeans(psi.drop.df[, 3:12]))

Varve Type plots

ag$varve_year <- ag$age_new - 0.3
ag$varve_year <- floor(ag$varve_year)
ag$clust_group <- 0
varve_years <- seq(2019, 1966, -1)
for (i in 1:length(ag$varve_year)) {
  for (j in 1:length(varve_years)) {
    if (ag$varve_year[i] == varve_years[j]) {
      ag$clust_group[i] <- mycl[j, 1]
    }
  }
}

# proxy clusters mean and 80% CIs
group1_ag <- aggregate(subset(ag, clust_group == 1), list(subset(ag, clust_group == 1)$year_scale), FUN = mean)
group1_90 <- aggregate(subset(ag, clust_group == 1), list(subset(ag, clust_group == 1)$year_scale), function(x) quantile(x, 0.90))
group1_10 <- aggregate(subset(ag, clust_group == 1), list(subset(ag, clust_group == 1)$year_scale), function(x) quantile(x, 0.10))
group2_ag <- aggregate(subset(ag, clust_group == 2), list(subset(ag, clust_group == 2)$year_scale), FUN = mean)
group2_90 <- aggregate(subset(ag, clust_group == 2), list(subset(ag, clust_group == 2)$year_scale), function(x) quantile(x, 0.9))
group2_10 <- aggregate(subset(ag, clust_group == 2), list(subset(ag, clust_group == 2)$year_scale), function(x) quantile(x, 0.1))
group3_ag <- aggregate(subset(ag, clust_group == 3), list(subset(ag, clust_group == 3)$year_scale), FUN = mean)
group3_90 <- aggregate(subset(ag, clust_group == 3), list(subset(ag, clust_group == 3)$year_scale), function(x) quantile(x, 0.9))
group3_10 <- aggregate(subset(ag, clust_group == 3), list(subset(ag, clust_group == 3)$year_scale), function(x) quantile(x, 0.1))
group4_ag <- aggregate(subset(ag, clust_group == 4), list(subset(ag, clust_group == 4)$year_scale), FUN = mean)
group4_90 <- aggregate(subset(ag, clust_group == 4), list(subset(ag, clust_group == 4)$year_scale), function(x) quantile(x, 0.9))
group4_10 <- aggregate(subset(ag, clust_group == 4), list(subset(ag, clust_group == 4)$year_scale), function(x) quantile(x, 0.1))

group1_ag_piv1 <- tidyr::pivot_longer(group1_ag, cols = c("Ca", "Ti", "Si", "Fe", "S", "Mn", "P", "TChl", "Bphe"), names_to = "proxy")
group1_ag_piv1 <- cbind(group1_ag_piv1[, c(3, 8, 9)], tidyr::pivot_longer(group1_90, cols = c("Ca", "Ti", "Si", "Fe", "S", "Mn", "P", "TChl", "Bphe"), names_to = "proxy", values_to = "p90th")[9], tidyr::pivot_longer(group1_10, cols = c("Ca", "Ti", "Si", "Fe", "S", "Mn", "P", "TChl", "Bphe"), names_to = "proxy", values_to = "p10th")[9])
group1_ag_piv1$group <- "Varve Type 1"

group2_ag_piv1 <- tidyr::pivot_longer(group2_ag, cols = c("Ca", "Ti", "Si", "Fe", "S", "Mn", "P", "TChl", "Bphe"), names_to = "proxy")
group2_ag_piv1 <- cbind(group2_ag_piv1[, c(3, 8, 9)], tidyr::pivot_longer(group2_90, cols = c("Ca", "Ti", "Si", "Fe", "S", "Mn", "P", "TChl", "Bphe"), names_to = "proxy", values_to = "p90th")[9], tidyr::pivot_longer(group2_10, cols = c("Ca", "Ti", "Si", "Fe", "S", "Mn", "P", "TChl", "Bphe"), names_to = "proxy", values_to = "p10th")[9])
group2_ag_piv1$group <- "Varve Type 2"

group3_ag_piv1 <- tidyr::pivot_longer(group3_ag, cols = c("Ca", "Ti", "Si", "Fe", "S", "Mn", "P", "TChl", "Bphe"), names_to = "proxy")
group3_ag_piv1 <- cbind(group3_ag_piv1[, c(3, 8, 9)], tidyr::pivot_longer(group3_90, cols = c("Ca", "Ti", "Si", "Fe", "S", "Mn", "P", "TChl", "Bphe"), names_to = "proxy", values_to = "p90th")[9], tidyr::pivot_longer(group3_10, cols = c("Ca", "Ti", "Si", "Fe", "S", "Mn", "P", "TChl", "Bphe"), names_to = "proxy", values_to = "p10th")[9])
group3_ag_piv1$group <- "Varve Type 3"

group4_ag_piv1 <- tidyr::pivot_longer(group4_ag, cols = c("Ca", "Ti", "Si", "Fe", "S", "Mn", "P", "TChl", "Bphe"), names_to = "proxy")
group4_ag_piv1 <- cbind(group4_ag_piv1[, c(3, 8, 9)], tidyr::pivot_longer(group4_90, cols = c("Ca", "Ti", "Si", "Fe", "S", "Mn", "P", "TChl", "Bphe"), names_to = "proxy", values_to = "p90th")[9], tidyr::pivot_longer(group4_10, cols = c("Ca", "Ti", "Si", "Fe", "S", "Mn", "P", "TChl", "Bphe"), names_to = "proxy", values_to = "p10th")[9])
group4_ag_piv1$group <- "Varve Type 4"

groups_all <- rbind(group1_ag_piv1, group2_ag_piv1, group3_ag_piv1, group4_ag_piv1)
groups_all$proxy_group <- "A"
groups_all[groups_all$proxy %in% c("Ca", "P", "TChl"), ]$proxy_group <- "A"
groups_all[groups_all$proxy %in% c("Fe", "S", "Mn"), ]$proxy_group <- "B"
groups_all[groups_all$proxy %in% c("Ti", "Si", "Bphe"), ]$proxy_group <- "C"

# plot
all_groups_plot2 <- ggplot(groups_all, aes(year_scale)) +
  geom_path(aes(x = year_scale, y = value, color = forcats::as_factor(proxy)), size = 1) +
  geom_ribbon(aes(ymin = p10th, ymax = p90th, fill = forcats::as_factor(proxy)), alpha = 0.3) +
  scale_color_manual(values = c(color2)) +
  scale_fill_manual(values = c(color2)) +
  labs(
    x = "",
    y = "Z-score",
    color = "proxy"
  ) +
  theme_bw() +
  guides(colour = guide_legend(nrow = 1)) +
  theme(legend.position = "bottom") +
  facet_grid(rows = vars(group), cols = vars(proxy_group))
all_groups_plot2

Comparing meteorological conditions in years defined by varve types

Boxplot of seasonal weather by varve type

### aggregate meteo data into annual seasonal values
Ket_meteo <- subset.data.frame(meteo, station == "K?TRZYN")
# substitute missing wind data with mean values
Ket_meteo$ws_mean_daily[(29309 - 19173):(29683 - 19173)] <- NA
Ket_meteo <- Ket_meteo %>%
  group_by(day_of_year) %>%
  mutate(ws_mean_daily = replace(ws_mean_daily, is.na(ws_mean_daily), mean(ws_mean_daily, na.rm = TRUE))) %>%
  ungroup()
Ket_meteo <- as.data.frame(Ket_meteo)
# define varve year as March to March
Ket_meteo$varve_year <- Ket_meteo$yy
Ket_meteo$varve_year[Ket_meteo$mm == 1 | Ket_meteo$mm == 2] <- Ket_meteo$yy[Ket_meteo$mm == 1 | Ket_meteo$mm == 2] - 1

meteo_ann_mean <- aggregate(Ket_meteo[, c(9, 11, 39)], list(Ket_meteo$varve_year), mean)
colnames(meteo_ann_mean) <- c("varve_year", "Temp_ANN", "Precip_ANN", "Wind_ANN")
meteo_ann_mean <- subset(meteo_ann_mean, varve_year >= 1966)

# creating empty columns
meteo_ann_mean$Temp_MAM <- 0
meteo_ann_mean$Temp_JJA <- 0
meteo_ann_mean$Temp_SON <- 0
meteo_ann_mean$Temp_DJF <- 0
meteo_ann_mean$Temp_MAM_lag1 <- 0
meteo_ann_mean$Temp_MAMJJA <- 0

meteo_ann_mean$p90_Precip_MAM <- 0
meteo_ann_mean$p90_Precip_JJA <- 0
meteo_ann_mean$p90_Precip_SON <- 0
meteo_ann_mean$p90_Precip_DJF <- 0
meteo_ann_mean$p90_Precip_MAM_lag1 <- 0

meteo_ann_mean$p90_Wind_MAM <- 0
meteo_ann_mean$p90_Wind_JJA <- 0
meteo_ann_mean$p90_Wind_SON <- 0
meteo_ann_mean$p90_Wind_DJF <- 0
meteo_ann_mean$p90_Wind_MAM_lag1 <- 0
meteo_ann_mean$MAR_DEC_Wind_Days <- 0

meteo_ann_mean$Temp_MAR <- 0
meteo_ann_mean$Temp_APR <- 0
meteo_ann_mean$Temp_MAY <- 0
meteo_ann_mean$Temp_JUN <- 0
meteo_ann_mean$Temp_JUL <- 0
meteo_ann_mean$Temp_AUG <- 0
meteo_ann_mean$Temp_SEP <- 0
meteo_ann_mean$Temp_OCT <- 0
meteo_ann_mean$Temp_NOV <- 0
meteo_ann_mean$Temp_DEC <- 0
meteo_ann_mean$Temp_JAN_LAG1 <- 0
meteo_ann_mean$Temp_FEB_LAG1 <- 0
meteo_ann_mean$Temp_MAR_LAG1 <- 0
meteo_ann_mean$Temp_APR_LAG1 <- 0
meteo_ann_mean$Temp_MAY_LAG1 <- 0

meteo_ann_mean$p90_Precip_MAR <- 0
meteo_ann_mean$p90_Precip_APR <- 0
meteo_ann_mean$p90_Precip_MAY <- 0
meteo_ann_mean$p90_Precip_JUN <- 0
meteo_ann_mean$p90_Precip_JUL <- 0
meteo_ann_mean$p90_Precip_AUG <- 0
meteo_ann_mean$p90_Precip_SEP <- 0
meteo_ann_mean$p90_Precip_OCT <- 0
meteo_ann_mean$p90_Precip_NOV <- 0
meteo_ann_mean$p90_Precip_DEC <- 0
meteo_ann_mean$p90_Precip_JAN_LAG1 <- 0
meteo_ann_mean$p90_Precip_FEB_LAG1 <- 0
meteo_ann_mean$p90_Precip_MAR_LAG1 <- 0
meteo_ann_mean$p90_Precip_APR_LAG1 <- 0
meteo_ann_mean$p90_Precip_MAY_LAG1 <- 0

meteo_ann_mean$p90_Wind_MAR <- 0
meteo_ann_mean$p90_Wind_APR <- 0
meteo_ann_mean$p90_Wind_MAY <- 0
meteo_ann_mean$p90_Wind_JUN <- 0
meteo_ann_mean$p90_Wind_JUL <- 0
meteo_ann_mean$p90_Wind_AUG <- 0
meteo_ann_mean$p90_Wind_SEP <- 0
meteo_ann_mean$p90_Wind_OCT <- 0
meteo_ann_mean$p90_Wind_NOV <- 0
meteo_ann_mean$p90_Wind_DEC <- 0
meteo_ann_mean$p90_Wind_JAN_LAG1 <- 0
meteo_ann_mean$p90_Wind_FEB_LAG1 <- 0
meteo_ann_mean$p90_Wind_MAR_LAG1 <- 0
meteo_ann_mean$p90_Wind_APR_LAG1 <- 0
meteo_ann_mean$p90_Wind_MAY_LAG1 <- 0

# filling in with annualized data
wt <- 7 # threshold for wind days (m/s)

for (i in 1:nrow(meteo_ann_mean)) {
  meteo_ann_mean$Temp_MAM[i] <- mean(subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i] & mm <= 5 & mm >= 3)[, 9])
  meteo_ann_mean$Temp_JJA[i] <- mean(subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i] & mm <= 8 & mm >= 6)[, 9])
  meteo_ann_mean$Temp_SON[i] <- mean(subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i] & mm <= 11 & mm >= 9)[, 9])
  meteo_ann_mean$Temp_MAMJJA[i] <- mean(subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i] & mm <= 8 & mm >= 3)[, 9])
  D <- as.data.frame(subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i] & mm == 12)[, 9])
  JF <- as.data.frame(subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i + 1] & mm <= 2)[, 9])
  colnames(D) <- "a"
  colnames(JF) <- "a"
  DJF <- rbind(D, JF)
  meteo_ann_mean$Temp_DJF[i] <- mean(DJF$a)

  meteo_ann_mean$Temp_MAR[i] <- mean(subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i] & mm == 3)[, 9])
  meteo_ann_mean$Temp_APR[i] <- mean(subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i] & mm == 4)[, 9])
  meteo_ann_mean$Temp_MAY[i] <- mean(subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i] & mm == 5)[, 9])
  meteo_ann_mean$Temp_JUN[i] <- mean(subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i] & mm == 6)[, 9])
  meteo_ann_mean$Temp_JUL[i] <- mean(subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i] & mm == 7)[, 9])
  meteo_ann_mean$Temp_AUG[i] <- mean(subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i] & mm == 8)[, 9])
  meteo_ann_mean$Temp_SEP[i] <- mean(subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i] & mm == 9)[, 9])
  meteo_ann_mean$Temp_OCT[i] <- mean(subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i] & mm == 10)[, 9])
  meteo_ann_mean$Temp_NOV[i] <- mean(subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i] & mm == 11)[, 9])
  meteo_ann_mean$Temp_DEC[i] <- mean(subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i] & mm == 12)[, 9])
  meteo_ann_mean$Temp_JAN_LAG1[i] <- mean(subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i] + 1 & mm == 1)[, 9])
  meteo_ann_mean$Temp_FEB_LAG1[i] <- mean(subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i] + 1 & mm == 2)[, 9])
  meteo_ann_mean$Temp_MAR_LAG1[i] <- mean(subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i] + 1 & mm == 3)[, 9])
  meteo_ann_mean$Temp_APR_LAG1[i] <- mean(subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i] + 1 & mm == 4)[, 9])
  meteo_ann_mean$Temp_MAY_LAG1[i] <- mean(subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i] + 1 & mm == 5)[, 9])


  meteo_ann_mean$p90_Precip_MAM[i] <- stats::quantile((subset(Ket_meteo, yy == meteo_ann_mean$varve_year[i] & mm <= 5 & mm >= 3)[, 11]), probs = 0.9)
  meteo_ann_mean$p90_Precip_JJA[i] <- quantile((subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i] & mm <= 8 & mm >= 6)[, 11]), 0.9)
  meteo_ann_mean$p90_Precip_SON[i] <- quantile((subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i] & mm <= 11 & mm >= 9)[, 11]), 0.9)
  D <- as.data.frame(subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i] & mm == 12)[, 11])
  JF <- as.data.frame(subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i + 1] & mm <= 2)[, 11])
  colnames(D) <- "a"
  colnames(JF) <- "a"
  DJF <- rbind(D, JF)
  meteo_ann_mean$p90_Precip_DJF[i] <- quantile(DJF$a, 0.9)

  meteo_ann_mean$p90_Precip_MAR[i] <- stats::quantile(subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i] & mm == 3)[, 11], probs = 0.9)
  meteo_ann_mean$p90_Precip_APR[i] <- stats::quantile(subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i] & mm == 4)[, 11], probs = 0.9)
  meteo_ann_mean$p90_Precip_MAY[i] <- stats::quantile(subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i] & mm == 5)[, 11], probs = 0.9)
  meteo_ann_mean$p90_Precip_JUN[i] <- stats::quantile(subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i] & mm == 6)[, 11], probs = 0.9)
  meteo_ann_mean$p90_Precip_JUL[i] <- stats::quantile(subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i] & mm == 7)[, 11], probs = 0.9)
  meteo_ann_mean$p90_Precip_AUG[i] <- stats::quantile(subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i] & mm == 8)[, 11], probs = 0.9)
  meteo_ann_mean$p90_Precip_SEP[i] <- stats::quantile(subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i] & mm == 9)[, 11], probs = 0.9)
  meteo_ann_mean$p90_Precip_OCT[i] <- stats::quantile(subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i] & mm == 10)[, 11], probs = 0.9)
  meteo_ann_mean$p90_Precip_NOV[i] <- stats::quantile(subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i] & mm == 11)[, 11], probs = 0.9)
  meteo_ann_mean$p90_Precip_DEC[i] <- stats::quantile(subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i] & mm == 12)[, 11], probs = 0.9)
  meteo_ann_mean$p90_Precip_JAN_LAG1[i] <- stats::quantile(subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i] + 1 & mm == 1)[, 11], probs = 0.9)
  meteo_ann_mean$p90_Precip_FEB_LAG1[i] <- stats::quantile(subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i] + 1 & mm == 2)[, 11], probs = 0.9)
  meteo_ann_mean$p90_Precip_MAR_LAG1[i] <- stats::quantile(subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i] + 1 & mm == 3)[, 11], probs = 0.9)
  meteo_ann_mean$p90_Precip_APR_LAG1[i] <- stats::quantile(subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i] + 1 & mm == 4)[, 11], probs = 0.9)
  meteo_ann_mean$p90_Precip_MAY_LAG1[i] <- stats::quantile(subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i] + 1 & mm == 5)[, 11], probs = 0.9)


  meteo_ann_mean$p90_Wind_MAM[i] <- quantile((subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i] & mm <= 5 & mm >= 3)$ws_mean_daily), 0.9)
  meteo_ann_mean$p90_Wind_JJA[i] <- quantile((subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i] & mm <= 8 & mm >= 6)$ws_mean_daily), 0.9)
  meteo_ann_mean$p90_Wind_SON[i] <- quantile((subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i] & mm <= 11 & mm >= 9)$ws_mean_daily), 0.9)
  D <- as.data.frame(subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i] & mm == 12)$ws_mean_daily)
  JF <- as.data.frame(subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i + 1] & mm <= 2)$ws_mean_daily)
  colnames(D) <- "a"
  colnames(JF) <- "a"
  DJF <- rbind(D, JF)
  meteo_ann_mean$p90_Wind_DJF[i] <- quantile(DJF$a, 0.9)
  meteo_ann_mean$MAR_DEC_Wind_Days[i] <- nrow(subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i] & ws_mean_daily >= wt & mm >= 3))

  meteo_ann_mean$p90_Wind_MAR[i] <- stats::quantile(subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i] & mm == 3)[, 39], probs = 0.9)
  meteo_ann_mean$p90_Wind_APR[i] <- stats::quantile(subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i] & mm == 4)[, 39], probs = 0.9)
  meteo_ann_mean$p90_Wind_MAY[i] <- stats::quantile(subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i] & mm == 5)[, 39], probs = 0.9)
  meteo_ann_mean$p90_Wind_JUN[i] <- stats::quantile(subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i] & mm == 6)[, 39], probs = 0.9)
  meteo_ann_mean$p90_Wind_JUL[i] <- stats::quantile(subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i] & mm == 7)[, 39], probs = 0.9)
  meteo_ann_mean$p90_Wind_AUG[i] <- stats::quantile(subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i] & mm == 8)[, 39], probs = 0.9)
  meteo_ann_mean$p90_Wind_SEP[i] <- stats::quantile(subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i] & mm == 9)[, 39], probs = 0.9)
  meteo_ann_mean$p90_Wind_OCT[i] <- stats::quantile(subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i] & mm == 10)[, 39], probs = 0.9)
  meteo_ann_mean$p90_Wind_NOV[i] <- stats::quantile(subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i] & mm == 11)[, 39], probs = 0.9)
  meteo_ann_mean$p90_Wind_DEC[i] <- stats::quantile(subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i] & mm == 12)[, 39], probs = 0.9)
  meteo_ann_mean$p90_Wind_JAN_LAG1[i] <- stats::quantile(subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i] + 1 & mm == 1)[, 39], probs = 0.9)
  meteo_ann_mean$p90_Wind_FEB_LAG1[i] <- stats::quantile(subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i] + 1 & mm == 2)[, 39], probs = 0.9)
  meteo_ann_mean$p90_Wind_MAR_LAG1[i] <- stats::quantile(subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i] + 1 & mm == 3)[, 39], probs = 0.9)
  meteo_ann_mean$p90_Wind_APR_LAG1[i] <- stats::quantile(subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i] + 1 & mm == 4)[, 39], probs = 0.9)
  meteo_ann_mean$p90_Wind_MAY_LAG1[i] <- stats::quantile(subset.data.frame(Ket_meteo, yy == meteo_ann_mean$varve_year[i] + 1 & mm == 5)[, 39], probs = 0.9)
}

# calculating MAM_lag1 (spring of year after varve year, this may be included in some varves)
meteo_ann_mean$Temp_MAM_lag1 <- c(meteo_ann_mean$Temp_MAM[2:54], NA)
meteo_ann_mean$p90_Wind_MAM_lag1 <- c(meteo_ann_mean$p90_Wind_MAM[2:54], NA)
meteo_ann_mean$p90_Precip_MAM_lag1 <- c(meteo_ann_mean$p90_Precip_MAM[2:54], NA)

# substituting mean values in years with missing wind data
meteo_ann_mean[28, c(18:21, 58:66)] <- colMeans(na.omit(meteo_ann_mean[c(-28, -29), ]))[c(18:21, 58:66)]
meteo_ann_mean[29, c(16:18, 21, 52:60)] <- colMeans(na.omit(meteo_ann_mean[c(-28, -29), ]))[c(16:18, 21, 52:60)]

# Boxplot of seasonal weather by varve type
meteo_clust <- as.data.frame(cbind(mycl[54:1, 1], meteo_ann_mean[, 1], scale(meteo_ann_mean[c(5:9, 11:20)])))
colnames(meteo_clust)[c(1, 2)] <- c("Group", "Year")
meteo_clust_piv <- tidyr::pivot_longer(meteo_clust, cols = colnames(meteo_clust)[c(3:17)], names_to = "variable")
meteo_clust_piv$variable <- rep(c("MAM", "JJA", "SON", "DJF", "MAM_lag1"), 54 * 3)
meteo_clust_piv$variable <- factor(meteo_clust_piv$variable, levels = c("MAM", "JJA", "SON", "DJF", "MAM_lag1"))
meteo_clust_piv$met_var <- rep(c("temp", "temp", "temp", "temp", "temp", "p90_precip", "p90_precip", "p90_precip", "p90_precip", "p90_precip", "p90_wind", "p90_wind", "p90_wind", "p90_wind", "p90_wind"), 54)
cbPalette <- c("#D55E00", "#56B4E9", "#009E73", "#F0E442")
groups_plot2 <- ggplot() +
  geom_boxplot(data = meteo_clust_piv, aes(x = variable, y = value, fill = factor(Group)), lwd = 0.3, outlier.size = 0.2) +
  xlab("Season") +
  scale_fill_manual(values = cbPalette) +
  ylab("Z-score") +
  theme(legend.title = element_blank(), panel.grid = element_blank()) +
  facet_grid(rows = vars(met_var))
groups_plot2 + geom_hline(yintercept = 0, linetype = "dashed")

Assessing normality - some variables show positive skew, however ANOVA is not strongly sensitive to normality assumption, so we proceed

## assessing normality
ggplot(data = meteo_clust_piv, aes(x = value)) +
  stat_density() +
  facet_grid(rows = vars(met_var), cols = vars(variable), scales = "free_y")


y <- as.data.frame(meteo_clust[, c(3:17)])

"Shapiro-Wilks test"
[1] "Shapiro-Wilks test"
shapiro_test_df <- function(df, bonf = TRUE, alpha = 0.05) {
  l <- lapply(df, shapiro.test)
  s <- do.call("c", lapply(l, "[[", 1))
  p <- do.call("c", lapply(l, "[[", 2))
  if (bonf == TRUE) {
    sig <- ifelse(p > alpha / length(l), "H0", "Ha")
  } else {
    sig <- ifelse(p > alpha, "H0", "Ha")
  }
  return(list(
    statistic = s,
    p.value = p,
    significance = sig,
    method = ifelse(bonf == TRUE, "Shapiro-Wilks test with Bonferroni Correction",
      "Shapiro-Wilks test without Bonferroni Correction"
    )
  ))
}

shapiro_test_df(y, bonf = TRUE)
$statistic
           Temp_MAM.W            Temp_JJA.W            Temp_SON.W            Temp_DJF.W       Temp_MAM_lag1.W      p90_Precip_MAM.W 
            0.9702331             0.9735592             0.9792417             0.9707698             0.9708621             0.8881146 
     p90_Precip_JJA.W      p90_Precip_SON.W      p90_Precip_DJF.W p90_Precip_MAM_lag1.W        p90_Wind_MAM.W        p90_Wind_JJA.W 
            0.9793625             0.9506285             0.9773174             0.8866153             0.9768590             0.9764569 
       p90_Wind_SON.W        p90_Wind_DJF.W   p90_Wind_MAM_lag1.W 
            0.9810630             0.9862046             0.9773622 

$p.value
           Temp_MAM            Temp_JJA            Temp_SON            Temp_DJF       Temp_MAM_lag1      p90_Precip_MAM 
       0.1973847411        0.2751992104        0.4685928590        0.2083880995        0.2198589151        0.0001132049 
     p90_Precip_JJA      p90_Precip_SON      p90_Precip_DJF p90_Precip_MAM_lag1        p90_Wind_MAM        p90_Wind_JJA 
       0.4735658925        0.0264979994        0.3940685521        0.0001164720        0.3776767268        0.3637323773 
       p90_Wind_SON        p90_Wind_DJF   p90_Wind_MAM_lag1 
       0.5469326229        0.7871439074        0.4080749462 

$significance
           Temp_MAM            Temp_JJA            Temp_SON            Temp_DJF       Temp_MAM_lag1      p90_Precip_MAM 
               "H0"                "H0"                "H0"                "H0"                "H0"                "Ha" 
     p90_Precip_JJA      p90_Precip_SON      p90_Precip_DJF p90_Precip_MAM_lag1        p90_Wind_MAM        p90_Wind_JJA 
               "H0"                "H0"                "H0"                "Ha"                "H0"                "H0" 
       p90_Wind_SON        p90_Wind_DJF   p90_Wind_MAM_lag1 
               "H0"                "H0"                "H0" 

$method
[1] "Shapiro-Wilks test with Bonferroni Correction"

Analysis of variance. Null Hypothesis: years associated with the four varve types experienced the same meteorological conditions Note: significance code symbols are different here than in the manuscript

# Analysis of variance
y <- as.matrix(meteo_clust[, c(3:17)])
manova1 <- manova(y ~ as.factor(meteo_clust$Group))
"multivariate analysis of variance"
[1] "multivariate analysis of variance"
summary(manova1)
                             Df Pillai approx F num Df den Df  Pr(>F)   
as.factor(meteo_clust$Group)  3 1.3648   2.0587     45    111 0.00119 **
Residuals                    49                                         
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
"analysis of variance for each meteo variable"
[1] "analysis of variance for each meteo variable"
summary.aov(manova1)
 Response Temp_MAM :
                             Df Sum Sq Mean Sq F value  Pr(>F)  
as.factor(meteo_clust$Group)  3  9.634  3.2113  3.7265 0.01717 *
Residuals                    49 42.226  0.8618                  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

 Response Temp_JJA :
                             Df Sum Sq Mean Sq F value  Pr(>F)   
as.factor(meteo_clust$Group)  3 10.328  3.4427  4.2776 0.00926 **
Residuals                    49 39.437  0.8048                   
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

 Response Temp_SON :
                             Df Sum Sq Mean Sq F value  Pr(>F)  
as.factor(meteo_clust$Group)  3  9.516  3.1720  3.8796 0.01445 *
Residuals                    49 40.063  0.8176                  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

 Response Temp_DJF :
                             Df Sum Sq Mean Sq F value Pr(>F)
as.factor(meteo_clust$Group)  3  4.044 1.34791  1.4606 0.2368
Residuals                    49 45.221 0.92287               

 Response Temp_MAM_lag1 :
                             Df Sum Sq Mean Sq F value   Pr(>F)   
as.factor(meteo_clust$Group)  3 11.214  3.7378  4.4906 0.007316 **
Residuals                    49 40.786  0.8324                    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

 Response p90_Precip_MAM :
                             Df Sum Sq Mean Sq F value Pr(>F)
as.factor(meteo_clust$Group)  3  4.379 1.45983  1.4974 0.2269
Residuals                    49 47.772 0.97494               

 Response p90_Precip_JJA :
                             Df Sum Sq Mean Sq F value  Pr(>F)  
as.factor(meteo_clust$Group)  3  6.608 2.20273  2.3277 0.08605 .
Residuals                    49 46.370 0.94633                  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

 Response p90_Precip_SON :
                             Df Sum Sq Mean Sq F value Pr(>F)
as.factor(meteo_clust$Group)  3  2.901 0.96688  0.9485 0.4245
Residuals                    49 49.952 1.01943               

 Response p90_Precip_DJF :
                             Df Sum Sq Mean Sq F value Pr(>F)
as.factor(meteo_clust$Group)  3  4.451 1.48374  1.5861 0.2047
Residuals                    49 45.839 0.93549               

 Response p90_Precip_MAM_lag1 :
                             Df Sum Sq Mean Sq F value Pr(>F)
as.factor(meteo_clust$Group)  3  3.456  1.1519  1.1627 0.3335
Residuals                    49 48.544  0.9907               

 Response p90_Wind_MAM :
                             Df Sum Sq Mean Sq F value   Pr(>F)   
as.factor(meteo_clust$Group)  3 14.809  4.9363  6.3359 0.001022 **
Residuals                    49 38.176  0.7791                    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

 Response p90_Wind_JJA :
                             Df Sum Sq Mean Sq F value Pr(>F)
as.factor(meteo_clust$Group)  3  5.054 1.68458  1.7229 0.1745
Residuals                    49 47.911 0.97777               

 Response p90_Wind_SON :
                             Df Sum Sq Mean Sq F value  Pr(>F)  
as.factor(meteo_clust$Group)  3 10.760  3.5867  4.1827 0.01029 *
Residuals                    49 42.017  0.8575                  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

 Response p90_Wind_DJF :
                             Df Sum Sq Mean Sq F value Pr(>F)
as.factor(meteo_clust$Group)  3  1.919 0.63973  0.6153 0.6084
Residuals                    49 50.943 1.03966               

 Response p90_Wind_MAM_lag1 :
                             Df Sum Sq Mean Sq F value    Pr(>F)    
as.factor(meteo_clust$Group)  3 19.538  6.5127  9.8306 3.477e-05 ***
Residuals                    49 32.462  0.6625                      
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

1 observation deleted due to missingness

Correlations between meteorological data and sedimentary data

Assessing normality - some variables are non-normal, but we proceed with correlation analysis. Emphasis is on understanding relationships, not significance tests. Variables with highest correlations are normally distributed.

# calculated annual means for geochemical data
proxy_ann_mean <- aggregate(HiRes_full[, c(4:11, 13, 14)], list(HiRes_full$varve_year), mean)
colnames(proxy_ann_mean)[1] <- "varve_year"
proxy_ann_mean <- proxy_ann_mean[proxy_ann_mean$varve_year >= 1966, ]
proxy_ann_all <- cbind(proxy_ann_mean[2:11], CNS[54:1, c(11, 37, 39, 38, 41)])
colnames(proxy_ann_all)[11:14] <- c("TIC", "TOC", "TC", "TN")

proxy_ann_all_piv <- tidyr::pivot_longer(proxy_ann_all, cols = colnames(proxy_ann_all), names_to = "proxy")
ggplot(data = proxy_ann_all_piv, aes(x = value)) +
  stat_density() +
  facet_wrap(facets = "proxy", nrow = 3, scales = "free")

"Shapiro-Wilks test"
[1] "Shapiro-Wilks test"
shapiro_test_df(proxy_ann_all, bonf = TRUE)
$statistic
     Ca.W      Fe.W      Mn.W      Si.W       P.W       S.W       K.W      Ti.W    TChl.W    Bphe.W     TIC.W     TOC.W      TC.W 
0.9696440 0.9131046 0.9241429 0.9814126 0.9476018 0.9637299 0.9572583 0.9853412 0.9112746 0.9838330 0.9713009 0.9797486 0.9418974 
     TN.W     MAR.W 
0.9751930 0.9360141 

$p.value
          Ca           Fe           Mn           Si            P            S            K           Ti         TChl         Bphe 
0.1859328483 0.0008274316 0.0021517032 0.5627068717 0.0195840976 0.1012762802 0.0519709111 0.7474558174 0.0007096279 0.6760597969 
         TIC          TOC           TC           TN          MAR 
0.2198375108 0.4896885978 0.0111917053 0.3225689073 0.0063794821 

$significance
  Ca   Fe   Mn   Si    P    S    K   Ti TChl Bphe  TIC  TOC   TC   TN  MAR 
"H0" "Ha" "Ha" "H0" "H0" "H0" "H0" "H0" "Ha" "H0" "H0" "H0" "H0" "H0" "H0" 

$method
[1] "Shapiro-Wilks test with Bonferroni Correction"

Seasonal correlations. Selected correlations from this analysis are displayed in Table 1 of associated manuscript.

meteo_sub1 <- meteo_ann_mean[, c(5:21)] # seasonal meteo data
meteo_sub1[54, c(5, 11, 16)] <- colMeans(meteo_sub1[-54, ])[c(5, 11, 16)] # replacing missing data with means

# Seasonal correlations
cor_matrix_seasonal <- corbetw2mat(meteo_sub1, proxy_ann_all, what = "all")

AR_proxies <- acf(proxy_ann_all, lag = 1, plot = FALSE)
AR_proxies <- AR_proxies$acf

AR_meteo <- acf(meteo_sub1, lag = 1, plot = FALSE)
AR_meteo <- AR_meteo$acf

adj_n <- matrix(, nrow = ncol(meteo_sub1), ncol = ncol(proxy_ann_all))
# calculate adjusted n using method of Bretherton et al. (1999)

for (i in 1:ncol(meteo_sub1)) {
  for (j in 1:ncol(proxy_ann_all)) {
    adj_n[i, j] <- nrow(proxy_ann_all) * (1 - AR_meteo[2, i, i] * AR_proxies[2, j, j]) / (1 + AR_meteo[2, i, i] * AR_proxies[2, j, j])
  }
}
adj_n[adj_n > 54] <- 54
colnames(adj_n) <- colnames(proxy_ann_all)
rownames(adj_n) <- colnames(meteo_sub1)

pval <- corr.p(cor_matrix_seasonal, n = adj_n, adjust = "fdr")$p
cor_matrix_seasonal <- t(cor_matrix_seasonal)
pval <- t(pval)
corrplot(cor_matrix_seasonal, method = "color", p.mat = pval, sig.level = c(0.01, 0.05, 0.1), pch = c("."), insig = "label_sig")

Correlations with monthly meteo data and full correlation plot

meteo_sub2 <- meteo_ann_mean[, 22:66] # monthly meteo data
meteo_sub2[54, c(13:15, 28:30, 43:45)] <- colMeans(meteo_sub2[-54, ])[c(13:15, 28:30, 43:45)] # replacing missing data with means

cor_matrix_months <- corbetw2mat(proxy_ann_all, meteo_sub2, what = "all")
colnames(cor_matrix_months) <- c("Temp MAR", "Temp APR", "Temp MAY", "Temp JUN", "Temp JUL", "Temp AUG", "Temp SEP", "Temp OCT", "Temp NOV", "Temp DEC", "Temp JAN", "Temp FEB", "Temp-MAR", "Temp-APR", "Temp-MAY", "Precip MAR", "Precip APR", "Precip MAY", "Precip JUN", "Precip JUL", "Precip AUG", "Precip SEP", "Precip OCT", "Precip NOV", "Precip DEC", "Precip JAN", "Precip FEB", "Precip-MAR", "Precip-APR", "Precip-MAY", "Wind MAR", "Wind APR", "Wind MAY", "Wind JUN", "Wind JUL", "Wind AUG", "Wind SEP", "Wind OCT", "Wind NOV", "Wind DEC", "Wind JAN", "Wind FEB", "Wind-MAR", "Wind-APR", "Wind-MAY")
AR_meteo_sub2 <- acf(meteo_sub2, lag = 1, plot = FALSE)
AR_meteo_sub2 <- AR_meteo_sub2$acf

adj_n_2 <- matrix(, nrow = ncol(proxy_ann_all), ncol = ncol(meteo_sub2))
# calculate adjusted n using method of Bretherton et al. (1999)

for (i in 1:ncol(proxy_ann_all)) {
  for (j in 1:ncol(meteo_sub2)) {
    adj_n_2[i, j] <- nrow(meteo_sub2) * (1 - AR_proxies[2, i, i] * AR_meteo_sub2[2, j, j]) / (1 + AR_proxies[2, i, i] * AR_meteo_sub2[2, j, j])
  }
}
adj_n_2[adj_n_2 > 54] <- 54
colnames(adj_n_2) <- colnames(meteo_sub2)
rownames(adj_n_2) <- colnames(proxy_ann_all)

pval_2 <- corr.p(cor_matrix_months, n = adj_n_2, adjust = "fdr")$p
par(mfrow = c(2, 2))
corrplot(cor_matrix_months[, 1:15], method = "color", p.mat = pval_2[, 1:15], sig.level = c(0.01, 0.05, 0.1), pch = c("."), insig = "label_sig")
corrplot(cor_matrix_months[, 16:30], method = "color", p.mat = pval_2[, 16:30], sig.level = c(0.01, 0.05, 0.1), pch = c("."), insig = "label_sig")
corrplot(cor_matrix_months[, 31:45], method = "color", p.mat = pval_2[, 31:45], sig.level = c(0.01, 0.05, 0.1), pch = c("."), insig = "label_sig")
corrplot(cor_matrix_seasonal[,c(-5,-11,-16)], method = "color", p.mat = pval[,c(-5,-11,-16)], sig.level = c(0.01, 0.05, 0.1), pch = c("."), insig = "label_sig")

Redundancy analysis (RDA)

rda_1 <- rda(proxy_ann_all, meteo_clust[, c(3:6, 8:11, 13:16)], scale = TRUE)
RsquareAdj(rda_1)
$r.squared
[1] 0.468402

$adj.r.squared
[1] 0.3128123
summary(rda_1)$cont
$importance
Importance of components:
                       RDA1    RDA2    RDA3    RDA4    RDA5    RDA6     RDA7     RDA8     RDA9    RDA10     RDA11     RDA12    PC1
Eigenvalue            4.245 0.92460 0.58711 0.52234 0.26917 0.18465 0.142550 0.087522 0.032040 0.022689 0.0062269 0.0020600 2.2679
Proportion Explained  0.283 0.06164 0.03914 0.03482 0.01794 0.01231 0.009503 0.005835 0.002136 0.001513 0.0004151 0.0001373 0.1512
Cumulative Proportion 0.283 0.34465 0.38379 0.41861 0.43655 0.44886 0.458366 0.464201 0.466337 0.467850 0.4682646 0.4684020 0.6196
                          PC2    PC3     PC4     PC5     PC6     PC7     PC8    PC9     PC10     PC11     PC12     PC13     PC14
Eigenvalue            1.43923 1.0964 0.78670 0.63538 0.54924 0.37014 0.27920 0.2085 0.142169 0.094810 0.052231 0.037459 0.014580
Proportion Explained  0.09595 0.0731 0.05245 0.04236 0.03662 0.02468 0.01861 0.0139 0.009478 0.006321 0.003482 0.002497 0.000972
Cumulative Proportion 0.71554 0.7886 0.84109 0.88344 0.92006 0.94474 0.96335 0.9773 0.986728 0.993049 0.996531 0.999028 1.000000
plot(rda_1, scaling = 3, display = c("cn", "sp"))
spe.sc <- scores(rda_1, choices = 1:2, scaling = 3, display = "sp")
arrows(0, 0, spe.sc[, 1], spe.sc[, 2], length = 0.1, lty = 1, col = "red", lwd = 1)
points.rda <- scores(rda_1, choices = 1:2, scaling = 3, display = "sites")

points(points.rda[meteo_clust$Group == 1, ], col = "#d55e00", pch = 16) # VT-1
points(points.rda[meteo_clust$Group == 2, ], col = "#56b4e9", pch = 16) # VT-2
points(points.rda[meteo_clust$Group == 3, ], col = "#009e73", pch = 16) # VT-3
points(points.rda[meteo_clust$Group == 4, ], col = "#f0e442", pch = 16) # VT-4

Generalized Additive Models (GAMs)

Spring and Summer Temperature (MAMJJA) model

VT <- as.data.frame(rev(mycl$group))
Annual_data_comb <- cbind(proxy_ann_all, meteo_ann_mean)
Annual_data_comb$VT <- VT[1:54,1]
# MAMJJA Temp GAM
gam_MAMJJA_temp <- gam(Temp_MAMJJA ~ s(TC) + s(Ti), data = Annual_data_comb, method = "REML", select = TRUE)
summary(gam_MAMJJA_temp)

Family: gaussian 
Link function: identity 

Formula:
Temp_MAMJJA ~ s(TC) + s(Ti)

Parametric coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept) 12.08264    0.09249   130.6   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Approximate significance of smooth terms:
         edf Ref.df     F  p-value    
s(TC) 0.9616      9 2.781 4.47e-06 ***
s(Ti) 0.9065      9 1.077  0.00184 ** 
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

R-sq.(adj) =  0.548   Deviance explained = 56.4%
-REML = 59.676  Scale est. = 0.46196   n = 54
pred_MAMJJA_temp <- as_tibble(as.data.frame(predict(gam_MAMJJA_temp, se.fit = TRUE, unconditional = TRUE)))
pred_MAMJJA_temp <- bind_cols(Annual_data_comb, pred_MAMJJA_temp) %>%
  mutate(upr = fit + 2 * se.fit, lwr = fit - 2 * se.fit)
theme_set(theme_bw())
MAMJJA_temp_plot <- ggplot(Annual_data_comb, aes(x = varve_year, y = Temp_MAMJJA)) +
  geom_point() +
  scale_x_continuous(breaks = seq(1965, 2020, 5), limits = c(1965, 2020)) +
  geom_ribbon(
    data = pred_MAMJJA_temp,
    mapping = aes(ymin = lwr, ymax = upr, x = varve_year), alpha = 0.4, inherit.aes = FALSE,
    fill = "lightblue"
  ) +
  geom_line(
    data = pred_MAMJJA_temp,
    mapping = aes(y = fit, x = varve_year), inherit.aes = FALSE, size = 1, colour = "black"
  ) +
  labs(x = "varve_year", y = "MAMJJA Temp (°C)") +
  theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank())
MAMJJA_temp_plot

plot(gam_MAMJJA_temp, pages = 1, all.terms = TRUE, shade = TRUE, residuals = TRUE, pch = 1, cex = 1, seWithMean = TRUE, shade.col = "lightblue")

Diagnostic plots

par(mfrow = c(3, 2))
gam.check(gam_MAMJJA_temp)

Method: REML   Optimizer: outer newton
full convergence after 12 iterations.
Gradient range [-2.820061e-05,1.069222e-05]
(score 59.67644 & scale 0.4619602).
Hessian positive definite, eigenvalue range [1.536549e-06,26.51675].
Model rank =  19 / 19 

Basis dimension (k) checking results. Low p-value (k-index<1) may
indicate that k is too low, especially if edf is close to k'.

         k'   edf k-index p-value
s(TC) 9.000 0.962    1.14    0.85
s(Ti) 9.000 0.906    0.98    0.44
acf(gam_MAMJJA_temp$residuals, lag.max = 36, main = "ACF")
pacf(gam_MAMJJA_temp$residuals, lag.max = 36, main = "pACF")

10-fold cross-validated RMSE

CV_temp <- CVgam(formula = Temp_MAMJJA ~ s(TC) + s(Ti), data = Annual_data_comb, method = "REML")
   GAMscale CV-mse-GAM  
     0.4577      0.4797 
paste("CV-RMSE (°C) = ", round(sqrt(CV_temp$cvscale), digits = 2))
[1] "CV-RMSE (°C) =  0.69"
paste("CV-RMSE (%) = ", round(100 * sqrt(CV_temp$cvscale) / (max(Annual_data_comb$Temp_MAMJJA) - min(Annual_data_comb$Temp_MAMJJA)), digits = 2))
[1] "CV-RMSE (%) =  14.42"

Split-period calibration and validation (MAMJJA Temperature)

# preparing summary table
Annual_data_comb_cal <- Annual_data_comb[Annual_data_comb$varve_year <= 1992, ]
Annual_data_comb_ver <- Annual_data_comb[Annual_data_comb$varve_year > 1992, ]

split_period_temp <- data.frame(cal_period = c("1966-1992", "1993-2019"), val_period = c("1993-2019", "1966-1992"), Rsqr_adj = NA, RE = NA, CE = NA, RMSE = NA)
# calibration model
gam_MAMJJA_temp_cal <- gam(Temp_MAMJJA ~ s(TC) + s(Ti), data = Annual_data_comb_cal, method = "REML", select = TRUE)
split_period_temp$Rsqr_adj[1] <- summary(gam_MAMJJA_temp_cal)$r.sq

# Calculate RE, CE, RMSE
pred_MAMJJA_temp_cal <- as_tibble(as.data.frame(predict(gam_MAMJJA_temp_cal, newdata = Annual_data_comb, se.fit = TRUE, unconditional = TRUE)))
pred_MAMJJA_temp_ver <- as_tibble(as.data.frame(predict(gam_MAMJJA_temp_cal, newdata = Annual_data_comb_ver, se.fit = TRUE, unconditional = TRUE)))

RE_MAMJJA_temp <- 1 - sum((Annual_data_comb_ver$Temp_MAMJJA - pred_MAMJJA_temp_ver$fit)^2) / sum((Annual_data_comb_ver$Temp_MAMJJA - mean(Annual_data_comb_cal$Temp_MAMJJA))^2)
split_period_temp$RE[1] <- RE_MAMJJA_temp

CE_MAMJJA_temp <- 1 - sum((Annual_data_comb_ver$Temp_MAMJJA - pred_MAMJJA_temp_ver$fit)^2) / sum((Annual_data_comb_ver$Temp_MAMJJA - mean(Annual_data_comb_ver$Temp_MAMJJA))^2)
split_period_temp$CE[1] <- CE_MAMJJA_temp

RMSEP_MAMJJA_temp <- sqrt(mean((Annual_data_comb_ver$Temp_MAMJJA - pred_MAMJJA_temp_ver$fit)^2))
split_period_temp$RMSE[1] <- paste(round(RMSEP_MAMJJA_temp, digits = 3), " (", round(100 * RMSEP_MAMJJA_temp / (max(Annual_data_comb$Temp_MAMJJA) - min(Annual_data_comb$Temp_MAMJJA)), digits = 3), "%)")

# now switching calibration and verification periods
gam_MAMJJA_temp_ver <- gam(Temp_MAMJJA ~ s(TC) + s(Ti), data = Annual_data_comb_ver, method = "REML", select = TRUE)
split_period_temp$Rsqr_adj[2] <- summary(gam_MAMJJA_temp_ver)$r.sq
pred_MAMJJA_temp_ver_2 <- as_tibble(as.data.frame(predict(gam_MAMJJA_temp_ver, newdata = Annual_data_comb_cal, se.fit = TRUE, unconditional = TRUE)))
RE_MAMJJA_temp_2 <- 1 - sum((Annual_data_comb_cal$Temp_MAMJJA - pred_MAMJJA_temp_ver_2$fit)^2) / sum((Annual_data_comb_cal$Temp_MAMJJA - mean(Annual_data_comb_ver$Temp_MAMJJA))^2)
split_period_temp$RE[2] <- RE_MAMJJA_temp_2

CE_MAMJJA_temp_2 <- 1 - sum((Annual_data_comb_cal$Temp_MAMJJA - pred_MAMJJA_temp_ver_2$fit)^2) / sum((Annual_data_comb_cal$Temp_MAMJJA - mean(Annual_data_comb_cal$Temp_MAMJJA))^2)
split_period_temp$CE[2] <- CE_MAMJJA_temp_2

RMSEP_MAMJJA_temp_2 <- sqrt(mean((Annual_data_comb_cal$Temp_MAMJJA - pred_MAMJJA_temp_ver_2$fit)^2))
split_period_temp$RMSE[2] <- paste(round(RMSEP_MAMJJA_temp_2, digits = 3), " (", round(100 * RMSEP_MAMJJA_temp_2 / (max(Annual_data_comb$Temp_MAMJJA) - min(Annual_data_comb$Temp_MAMJJA)), digits = 3), "%)")

split_period_temp

# split period plot
pred_MAMJJA_temp_ver_3 <- as_tibble(as.data.frame(predict(gam_MAMJJA_temp_ver, newdata = Annual_data_comb, se.fit = TRUE, unconditional = TRUE)))
pred_MAMJJA_temp_ver_3 <- bind_cols(Annual_data_comb, pred_MAMJJA_temp_ver_3)
pred_MAMJJA_temp_cal_3 <- as_tibble(as.data.frame(predict(gam_MAMJJA_temp_cal, newdata = Annual_data_comb, se.fit = TRUE, unconditional = TRUE)))
pred_MAMJJA_temp_cal_3 <- bind_cols(Annual_data_comb, pred_MAMJJA_temp_cal_3)
theme_set(theme_bw())
gam_MAMJJA_temp_split <- ggplot(Annual_data_comb, aes(x = varve_year, y = Temp_MAMJJA)) +
  geom_point() +
  scale_x_continuous(breaks = seq(1965, 2020, 5), limits = c(1965, 2020)) +
  geom_line(
    data = pred_MAMJJA_temp,
    mapping = aes(y = fit, x = varve_year), inherit.aes = FALSE, size = 1, colour = "black"
  ) +
    geom_line(
    data = pred_MAMJJA_temp_ver_3,
    mapping = aes(y = fit, x = varve_year), inherit.aes = FALSE, size = 1, colour = "red"
  ) +
    geom_line(
    data = pred_MAMJJA_temp_cal_3,
    mapping = aes(y = fit, x = varve_year), inherit.aes = FALSE, size = 1, colour = "blue"
  ) +
  labs(x = "Year", y = "MAMJJA Temp (°C)") +
  theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank())
gam_MAMJJA_temp_split

March-December wind days (> 7 m/s) model

# removing missing years
wind_data_comb <- Annual_data_comb[Annual_data_comb$varve_year != 1994 & Annual_data_comb$varve_year != 1993, ]

gam_wind_days_MAR_DEC <- gam(MAR_DEC_Wind_Days ~ s(MAR) + s(Si), data = wind_data_comb, method = "REML", select = TRUE)

summary(gam_wind_days_MAR_DEC)

Family: gaussian 
Link function: identity 

Formula:
MAR_DEC_Wind_Days ~ s(MAR) + s(Si)

Parametric coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)  13.3462     0.8181   16.31   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Approximate significance of smooth terms:
          edf Ref.df     F  p-value    
s(MAR) 0.9192      9 1.260 0.000817 ***
s(Si)  0.9065      9 1.074 0.001750 ** 
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

R-sq.(adj) =  0.478   Deviance explained = 49.6%
-REML = 167.48  Scale est. = 34.804    n = 52
pred_wind_days_MAR_DEC <- as_tibble(as.data.frame(predict(gam_wind_days_MAR_DEC, se.fit = TRUE, unconditional = TRUE)))
pred_wind_days_MAR_DEC <- bind_cols(wind_data_comb, pred_wind_days_MAR_DEC) %>%
  mutate(upr = fit + 2 * se.fit, lwr = fit - 2 * se.fit)
theme_set(theme_bw())
wind_days_MAR_DEC_plot <- ggplot(wind_data_comb, aes(x = varve_year, y = MAR_DEC_Wind_Days)) +
  geom_point() +
  scale_x_continuous(breaks = seq(1965, 2020, 5), limits = c(1965, 2020)) +
  geom_ribbon(
    data = pred_wind_days_MAR_DEC,
    mapping = aes(ymin = lwr, ymax = upr, x = varve_year), alpha = 0.4, inherit.aes = FALSE,
    fill = "lightblue"
  ) +
  geom_line(
    data = pred_wind_days_MAR_DEC,
    mapping = aes(y = fit, x = varve_year), inherit.aes = FALSE, size = 1, colour = "black"
  ) +
  labs(x = "Year", y = "# of days with mean wind speed > 7 m/s")
wind_days_MAR_DEC_plot


plot(gam_wind_days_MAR_DEC, pages = 1, shade = TRUE, residuals = TRUE, pch = 1, cex = 1, seWithMean = TRUE, shade.col = "lightblue")

Diagnostic plots

par(mfrow = c(3, 2))
gam.check(gam_wind_days_MAR_DEC)

Method: REML   Optimizer: outer newton
full convergence after 13 iterations.
Gradient range [-6.492196e-05,0.0001896789]
(score 167.4796 & scale 34.80371).
Hessian positive definite, eigenvalue range [2.334065e-05,25.51643].
Model rank =  19 / 19 

Basis dimension (k) checking results. Low p-value (k-index<1) may
indicate that k is too low, especially if edf is close to k'.

          k'   edf k-index p-value
s(MAR) 9.000 0.919    1.34    0.99
s(Si)  9.000 0.906    0.99    0.43
acf(gam_wind_days_MAR_DEC$residuals, lag.max = 36, main = "ACF")
pacf(gam_wind_days_MAR_DEC$residuals, lag.max = 36, main = "pACF")

10-fold cross-validated RMSE

CV_wind <- CVgam(formula = MAR_DEC_Wind_Days ~ s(MAR) + s(Si), data = wind_data_comb, method = "REML")
   GAMscale CV-mse-GAM  
    34.8747     36.8989 
paste("CV-RMSE (days) = ", round(sqrt(CV_wind$cvscale), digits = 2))
[1] "CV-RMSE (days) =  6.07"
paste("CV-RMSE (%) = ", round(100 * sqrt(CV_wind$cvscale) / (max(wind_data_comb$MAR_DEC_Wind_Days) - min(wind_data_comb$MAR_DEC_Wind_Days)), digits = 2))
[1] "CV-RMSE (%) =  18.98"

Split-period calibration and validation

wind_data_comb_cal <- wind_data_comb[wind_data_comb$varve_year <= 1991, ]
wind_data_comb_ver <- wind_data_comb[wind_data_comb$varve_year > 1991, ]

# preparing summary table
split_period_wind <- data.frame(cal_period = c("1966-1991", "1992, 1995-2019"), val_period = c("1992, 1995-2019", "1966-1991"), Rsqr_adj = NA, RE = NA, CE = NA, RMSE = NA)
# calibration model
gam_wind_days_MAR_DEC_cal <- gam(MAR_DEC_Wind_Days ~ s(MAR) + s(Si), data = wind_data_comb_cal, method = "REML", select = TRUE)
split_period_wind$Rsqr_adj[1] <- summary(gam_wind_days_MAR_DEC_cal)$r.sq

# Calculate RE, CE, RMSE
pred_wind_days_ver <- as_tibble(as.data.frame(predict(gam_wind_days_MAR_DEC_cal, newdata = wind_data_comb_ver, se.fit = TRUE, unconditional = TRUE)))
RE_wind_days <- 1 - sum((wind_data_comb_ver$MAR_DEC_Wind_Days - pred_wind_days_ver$fit)^2) / sum((wind_data_comb_ver$MAR_DEC_Wind_Days - mean(wind_data_comb_cal$MAR_DEC_Wind_Days))^2)
split_period_wind$RE[1] <- RE_wind_days

CE_wind_days <- 1 - sum((wind_data_comb_ver$MAR_DEC_Wind_Days - pred_wind_days_ver$fit)^2) / sum((wind_data_comb_ver$MAR_DEC_Wind_Days - mean(wind_data_comb_ver$MAR_DEC_Wind_Days))^2)
split_period_wind$CE[1] <- CE_wind_days

RMSEP_wind_days <- sqrt(mean((wind_data_comb_ver$MAR_DEC_Wind_Days - pred_wind_days_ver$fit)^2))
split_period_wind$RMSE[1] <- paste(round(RMSEP_wind_days, digits = 3), " (", round(100 * RMSEP_wind_days / (max(wind_data_comb$MAR_DEC_Wind_Days) - min(wind_data_comb$MAR_DEC_Wind_Days)), digits = 3), "%)")

# now using ver as cal
gam_wind_days_MAR_DEC_ver <- gam(MAR_DEC_Wind_Days ~ s(MAR) + s(Si), data = wind_data_comb_ver, method = "REML", select = TRUE)
split_period_wind$Rsqr_adj[2] <- summary(gam_wind_days_MAR_DEC_ver)$r.sq

pred_wind_days_ver_2 <- as_tibble(as.data.frame(predict(gam_wind_days_MAR_DEC_ver, newdata = wind_data_comb_cal, se.fit = TRUE, unconditional = TRUE)))
RE_wind_days_2 <- 1 - sum((wind_data_comb_cal$MAR_DEC_Wind_Days - pred_wind_days_ver_2$fit)^2) / sum((wind_data_comb_cal$MAR_DEC_Wind_Days - mean(wind_data_comb_ver$MAR_DEC_Wind_Days))^2)
split_period_wind$RE[2] <- RE_wind_days_2

CE_wind_days_2 <- 1 - sum((wind_data_comb_cal$MAR_DEC_Wind_Days - pred_wind_days_ver_2$fit)^2) / sum((wind_data_comb_cal$MAR_DEC_Wind_Days - mean(wind_data_comb_cal$MAR_DEC_Wind_Days))^2)
split_period_wind$CE[2] <- CE_wind_days_2

RMSEP_wind_days_2 <- sqrt(mean((wind_data_comb_cal$MAR_DEC_Wind_Days - pred_wind_days_ver_2$fit)^2))
split_period_wind$RMSE[2] <- paste(round(RMSEP_wind_days_2, digits = 3), " (", round(100 * RMSEP_wind_days_2 / (max(wind_data_comb$MAR_DEC_Wind_Days) - min(wind_data_comb$MAR_DEC_Wind_Days)), digits = 3), "%)")

split_period_wind

# split period plot
pred_wind_days_ver_3 <- as_tibble(as.data.frame(predict(gam_wind_days_MAR_DEC_ver, newdata = wind_data_comb, se.fit = TRUE, unconditional = TRUE)))
pred_wind_days_ver_3 <- bind_cols(wind_data_comb, pred_wind_days_ver_3)
pred_wind_days_cal_3 <- as_tibble(as.data.frame(predict(gam_wind_days_MAR_DEC_cal, newdata = wind_data_comb, se.fit = TRUE, unconditional = TRUE)))
pred_wind_days_cal_3 <- bind_cols(wind_data_comb, pred_wind_days_cal_3)
theme_set(theme_bw())
gam_wind_days_MAR_DEC_split <- ggplot(wind_data_comb, aes(x = varve_year, y = MAR_DEC_Wind_Days)) +
  geom_point() +
  scale_x_continuous(breaks = seq(1965, 2020, 5), limits = c(1965, 2020)) +
  geom_line(
    data = pred_wind_days_MAR_DEC,
    mapping = aes(y = fit, x = varve_year), inherit.aes = FALSE, size = 1, colour = "black"
  ) +
    geom_line(
    data = pred_wind_days_ver_3,
    mapping = aes(y = fit, x = varve_year), inherit.aes = FALSE, size = 1, colour = "red"
  ) +
    geom_line(
    data = pred_wind_days_cal_3,
    mapping = aes(y = fit, x = varve_year), inherit.aes = FALSE, size = 1, colour = "blue"
  ) +
  labs(x = "Year", y = "# of days with mean wind speed > 7 m/s") +
  theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank())
gam_wind_days_MAR_DEC_split

Supplementary correlation plots

"Annual resolution proxy data"
[1] "Annual resolution proxy data"
corrplot(cor(proxy_ann_all), addCoef.col = "black", number.cex = 10 / ncol(proxy_ann_all))

"Full resolution (60 um) scanning proxy data"
[1] "Full resolution (60 um) scanning proxy data"
corrplot(cor(HiRes_full[HiRes_full$varve_year >= 1966, 4:14]), addCoef.col = "black", number.cex = 10 / ncol(HiRes_full[, 4:14]))

"Seasonal meteo data"
[1] "Seasonal meteo data"
corrplot(cor(meteo_sub1), addCoef.col = "black", number.cex = 10 / ncol(meteo_sub1))

Session info

Sys.Date()
[1] "2021-08-17"
sessionInfo()
R version 4.1.0 (2021-05-18)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 10 x64 (build 17134)

Matrix products: default

locale:
[1] LC_COLLATE=German_Switzerland.1252  LC_CTYPE=German_Switzerland.1252    LC_MONETARY=German_Switzerland.1252
[4] LC_NUMERIC=C                        LC_TIME=German_Switzerland.1252    

attached base packages:
[1] grid      stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] mvnormtest_0.1-9  cowplot_1.1.1     gamclass_0.62.3   gridExtra_2.3     mgcv_1.8-36       nlme_3.1-152      reshape2_1.4.4   
 [8] pracma_2.3.3      viridis_0.6.1     viridisLite_0.4.0 distantia_1.0.2   psych_2.1.6       corrplot_0.89     vegan_2.5-7      
[15] lattice_0.20-44   permute_0.9-5     lineup_0.38-3     forcats_0.5.1     stringr_1.4.0     dplyr_1.0.7       purrr_0.3.4      
[22] readr_1.4.0       tidyr_1.1.3       tibble_3.1.2      tidyverse_1.3.1   ggplot2_3.3.4     dtw_1.22-3        proxy_0.4-26     
[29] data.table_1.14.0 pacman_0.5.1     

loaded via a namespace (and not attached):
 [1] fs_1.5.0            lubridate_1.7.10    RColorBrewer_1.1-2  doParallel_1.0.16   httr_1.4.2          tools_4.1.0        
 [7] backports_1.2.1     utf8_1.2.1          R6_2.5.0            rpart_4.1-15        DBI_1.1.1           colorspace_2.0-1   
[13] withr_2.4.2         tidyselect_1.1.1    mnormt_2.0.2        arrangements_1.1.9  compiler_4.1.0      cli_2.5.0          
[19] rvest_1.0.0         xml2_1.3.2          labeling_0.4.2      scales_1.1.1        randomForest_4.6-14 digest_0.6.27      
[25] rmarkdown_2.9       jpeg_0.1-8.1        pkgconfig_2.0.3     htmltools_0.5.1.1   dbplyr_2.1.1        maps_3.3.0         
[31] rlang_0.4.11        readxl_1.3.1        rstudioapi_0.13     farver_2.1.0        generics_0.1.0      jsonlite_1.7.2     
[37] magrittr_2.0.1      dotCall64_1.0-1     Matrix_1.3-4        Rcpp_1.0.6          munsell_0.5.0       fansi_0.5.0        
[43] lifecycle_1.0.0     stringi_1.6.1       yaml_2.2.1          MASS_7.3-54         plyr_1.8.6          parallel_4.1.0     
[49] crayon_1.4.1        haven_2.4.1         splines_4.1.0       hms_1.1.0           tmvnsim_1.0-2       knitr_1.33         
[55] pillar_1.6.1        codetools_0.2-18    reprex_2.0.0        glue_1.4.2          evaluate_0.14       latticeExtra_0.6-29
[61] modelr_0.1.8        png_0.1-7           vctrs_0.3.8         spam_2.6-0          foreach_1.5.1       cellranger_1.1.0   
[67] gtable_0.3.0        assertthat_0.2.1    xfun_0.24           broom_0.7.7         iterators_1.0.13    tinytex_0.32       
[73] fields_12.3         cluster_2.1.2       gmp_0.6-2           ellipsis_0.3.2     
LS0tDQp0aXRsZTogIlpBQkhpUmVzIFdvcmtmbG93Ig0Kc3VidGl0bGU6ICJDb2RlIGZvciBhbmFseXNlcyBpbiAnU2Vhc29uYWwgY2xpbWF0ZSBzaWduYWxzIHByZXNlcnZlZCBpbiBiaW9jaGVtaWNhbCB2YXJ2ZXM6IGluc2lnaHRzIGZyb20gbm92ZWwgaGlnaC1yZXNvbHV0aW9uIHNlZGltZW50IHNjYW5uaW5nIHRlY2huaXF1ZXMnIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIGhpZ2hsaWdodDogdGFuZ28NCiAgICB0aGVtZTogZmxhdGx5DQogICAgZGZfcHJpbnQ6IHBhZ2VkDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZmxvYXQ6IG5vDQogICAgY29kZV9mb2xkaW5nOiAiaGlkZSINCiAgaHRtbF9ub3RlYm9vazoNCiAgICBoaWdobGlnaHQ6IHRhbmdvDQogICAgdGhlbWU6IGZsYXRseQ0KICAgIHRvYzogeWVzDQogICAgdG9jX2Zsb2F0OiBubw0KICAgIGNvZGVfZm9sZGluZzogImhpZGUiDQotLS0NCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpDQpgYGANCg0KIyMgSW50cm9kdWN0aW9uDQoNClRoaXMgaXMgYW4gUiBNYXJrZG93biBkb2N1bWVudCB0aGF0IGRvY3VtZW50cyBkYXRhIGFuYWx5c2VzIGZvciB0aGUgbWFudXNjcmlwdCBaYW5kZXIgZXQgYWwgKFNlYXNvbmFsIGNsaW1hdGUgc2lnbmFscyBwcmVzZXJ2ZWQgaW4gYmlvY2hlbWljYWwgdmFydmVzOiBpbnNpZ2h0cyBmcm9tIG5vdmVsIGhpZ2gtcmVzb2x1dGlvbiBzZWRpbWVudCBzY2FubmluZyB0ZWNobmlxdWVzKS4gRm9yIGZ1bGwgaW50ZXJwcmV0YXRpb24gb2YgdGhlIGRhdGEgYW5kIHBsb3RzIGNvbnRhaW5lZCBoZXJlLCBwbGVhc2Ugc2VlIHRoZSBhc3NvY2lhdGVkIG1hbnVzY3JpcHQuIEFueSB1c2Ugb2YgZGF0YSBhbmQgcGxvdHMgc2hvdWxkIHJlZmVyIHRvIFphbmRlciBldCBhbC4NCg0KIyMgTG9hZCBwYWNrYWdlcyBhbmQgZGF0YQ0KDQpgYGB7ciBsb2FkIHBhY2thZ2VzLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0Kc2V0d2QoZGlybmFtZShyc3R1ZGlvYXBpOjpnZXRBY3RpdmVEb2N1bWVudENvbnRleHQoKSRwYXRoKSkNClN5cy5zZXRlbnYoTEFOR1VBR0UgPSAiZW4iKQ0KIyBDaGVjayBhbmQgaW5zdGFsbCBwYWNtYW4gaWYgbmVjY2VzYXJ5DQppZiAoIXJlcXVpcmUoInBhY21hbiIpKSB7DQogIGluc3RhbGwucGFja2FnZXMoInBhY21hbiIpDQogIGxpYnJhcnkocGFjbWFuKQ0KfQ0KDQojIExvYWQgbGlicmFyaWVzDQpwYWNtYW46OnBfbG9hZCgNCiAgZGF0YS50YWJsZSwgZHR3LCBnZ3Bsb3QyLCB0aWR5dmVyc2UsIGdyaWQsIGxpbmV1cCwgdmVnYW4sIGNvcnJwbG90LCBwc3ljaCwgZGlzdGFudGlhLA0KICB2aXJpZGlzLCBwcmFjbWEsIHJlc2hhcGUyLCBtZ2N2LCBncmlkRXh0cmEsIGdhbWNsYXNzLCBjb3dwbG90LCBtdm5vcm10ZXN0DQopDQpgYGANCg0KYGBge3IgbG9hZCBkYXRhLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyBMb2FkIGRhdGENClhSRiA8LSByZWFkLmNzdigiWkFCX0hpUmVzX1hSRi5jc3YiKQ0KQ05TIDwtIHJlYWQuY3N2KCJaQUJfQ05TXzIwMjAuY3N2IikNCkhTSSA8LSByZWFkLmNzdigiWkFCX0hpUmVzX0hTSS5jc3YiKQ0KQ2hyb25vIDwtIHJlYWQuY3N2KCJDaHJvbm9fVG9ybmFkby5jc3YiKQ0KbWV0ZW8gPC0gcmVhZC5jc3YoIm1ldGVvXzE5NjZfMjAyMC5jc3YiKQ0KYGBgDQoNCiMjIFByZXBhcmluZyBzY2FubmluZyBkYXRhOiBDb3JyZWN0aW9ucywgYXNzaWduaW5nIGFnZXMsIGFuZCBhbGlnbmluZyBkYXRhc2V0cw0KDQpgYGB7ciBkYXRhX3NldHVwLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD02LCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyBDb3JyZWN0aW9uIHRvIFRPQyBhbmQgVE4gdG8gYWNjb3VudCBmb3IgZGVncmF0aW9uL3JlbWluZXJhbGl6YXRpb24gdXNpbmcgZm9ybXVsYSBmcm9tIGdhbG1hbiBldCBhbCAyMDA4IChMaW1ub2xvZ3kgYW5kIE9jZWFub2dyYXBoeSkNCkNOUyR5ZWFyIDwtIGFzLm51bWVyaWMoQ05TJHllYXIpDQpDTlMkdG9jX3AgPC0gYXMubnVtZXJpYyhDTlMkdG9jX3ApDQpDTlMkdG9jX2NvcnIgPC0gKENOUyR0b2NfcCArICgyMy40MSAqICgyMDIwLjMgLSBDTlMkeWVhciArIDAuNSkgLyAoMjAyMC4zIC0gQ05TJHllYXIgKyAwLjUgKyAxKSAvIDEwMCkgKiBDTlMkdG9jX3ApICMgMjAyMC4zIHJlcHJlc2VudHMgYXBwcm94aW1hdGUgZGF0ZSBvZiBjb3JpbmcNCkNOUyR0bl9jb3JyIDwtIChDTlMkdG5fcCArICgzNi4xNyAqICgyMDIwLjMgLSBDTlMkeWVhciArIDAuNSkgLyAoMjAyMC4zIC0gQ05TJHllYXIgKyAwLjUgKyAxKSAvIDEwMCkgKiBDTlMkdG5fcCkNCkNOUyR0Y19jb3JyIDwtIENOUyR0aWNfcCArIENOUyR0b2NfY29ycg0KDQpwbG90KENOUyR0Y19jb3JyLCBDTlMkeWVhciwgdHlwZSA9ICJsIiwgeWxpbSA9IGMoMjAwMCwgMjAyMCksIG1haW4gPSAiVG90YWwgY2FyYm9uIHdpdGggYW5kIHdpdGhvdXQgdG9jIGRlY2F5IGNvcnJlY3Rpb24iKQ0KbGluZXMoQ05TJHRjX3AsIENOUyR5ZWFyLCBjb2wgPSAiYmx1ZSIpDQpDTlMkdG9jLm5fY29yciA8LSBDTlMkdG9jX2NvcnIgLyBDTlMkdG5fY29ycg0KIyBNYXNzIGFjY3VtdWxhdGlvbiByYXRlIGNhY2x1bGF0aW9uDQpDTlMkTUFSIDwtIENOUyRjYWxpYi50aGlja25lc3MubW0gKiBDTlMkZHJ5X2J1bGtfZGVuc2l0eV9nY20zDQoNCg0KIyByZW1vdmluZyBjcmFja3MNClhSRl9zY2FsZWQgPC0gY2JpbmQoWFJGWywgLWMoNDoxNildLCBzY2FsZShYUkZbLCBjKDQ6MTYpXSkpDQpjcmFja19maW5kZXIgPC0gWFJGX3NjYWxlZCRDYS5LQSArIFhSRl9zY2FsZWQkRmUuS0EgKyBYUkZfc2NhbGVkJFNpLktBICMgY291bnRzIG9mIGFidW5kYW50IGVsZW1lbnRzDQpYUkYgPC0gY2JpbmQoWFJGLCBjcmFja19maW5kZXIpDQpYUkYgPC0gc3Vic2V0LmRhdGEuZnJhbWUoWFJGLCBjcmFja19maW5kZXIgPiAtMi45KSAjIHJlbW92ZSBjcmFja3MgKGRlZmluZWQgYXMgYXJlYXMgd2l0aCBsb3cgYWJ1bmRhbmNlcyBvZiBjb21tb24gZWxlbWVudHMpDQoNCiMgYXNzaWduIGFnZXMgYmFzZWQgb24gZGVwdGhzDQpmb3IgKGkgaW4gMTpucm93KENocm9ubykpIHsNCiAgc2V0RFQoWFJGKVtjb21wX2RlcHRoX21tIDw9IENocm9ubyRDb21wLkRlcHRoW2ldICYgY29tcF9kZXB0aF9tbSA+PSBDaHJvbm8kQ29tcC5EZXB0aFtpICsgMV0sIHllYXIgOj0gQ2hyb25vJFllYXJbaV1dDQp9DQoNClhSRiA8LSBzdWJzZXQoWFJGLCB5ZWFyICE9IDApICMgc3Vic2V0IG9ubHkgZGVwdGhzIHdpdGggYXNzaWduZWQgYWdlcw0KWFJGJGN1bV95ZWFyX3NjYWxlIDwtIDANCg0KIyBzZXR0aW5nIGVhY2ggeWVhciB0byBiZSAxIHVuaXQgbG9uZw0KZm9yIChpIGluIDE6bnJvdyhDaHJvbm8pKSB7DQogIHNldERUKFhSRilbeWVhciA9PSBDaHJvbm8kWWVhcltpXSwgeWVhcl9zY2FsZSA6PSBzZXEoMSwgMC4wMDEsIGxlbmd0aC5vdXQgPSBucm93KHN1YnNldChYUkYsIHllYXIgPT0gQ2hyb25vJFllYXJbaV0pKSldDQp9DQpYUkYkY3VtX3llYXJfc2NhbGUgPC0gWFJGJHllYXJfc2NhbGUgKyBYUkYkeWVhciArIDAuMw0KDQojIyMjIyBIU0kgZGF0YQ0KSFNJJHllYXJfc2NhbGUgPC0gMA0KSFNJJHllYXJfc2NhbGUgPC0gYXMubnVtZXJpYyhIU0kkeWVhcl9zY2FsZSkNCkhTSSR5ZWFyIDwtIDANCkhTSSR5ZWFyIDwtIGFzLm51bWVyaWMoSFNJJHllYXIpDQpmb3IgKGkgaW4gMTpucm93KENocm9ubykpIHsNCiAgc2V0RFQoSFNJKVtIU0lfZGVwdGggPD0gQ2hyb25vJEhTSV9kZXB0aFtpXSAmIEhTSV9kZXB0aCA+PSBDaHJvbm8kSFNJX2RlcHRoW2kgKyAxXSwgeWVhciA6PSBDaHJvbm8kWWVhcltpXV0NCn0NCiMjIyBjYWxpYnJhdGluZyByYWJkIGluZGljZXMgYWNjb3JkaW5nIHRvIGNhbGlicmF0aW9uIHB1Ymxpc2hlZCBpbiBaYW5kZXIgZXQgYWwuLCAyMDIxIChTY2llbmNlIG9mIFRvdGFsIEVudmlyb25tZW50KQ0KSFNJJFRDaGwgPC0gMTU2MC40OCAqIEhTSSRgUkFCRDY1NS42ODVtYXhgIC0gMTU3OC45DQpIU0kkQnBoZSA8LSBIU0kkUkFCRDg0NSAqIDg2MS4xOCAtIDg1MS42NQ0KSFNJW0hTSSA8IDBdIDwtIDANCg0KIyBzZXR0aW5nIGVhY2ggeWVhciB0byBiZSAxIHVuaXQgbG9uZyAoSFNJIHZlcnNpb24pDQpIU0kgPC0gc3Vic2V0KEhTSSwgeWVhciAhPSAwKSAjIG9ubHkgaW5jbHVkaW5nIHllYXJzIHdpdGggYWdlcw0KSFNJJGN1bV95ZWFyX3NjYWxlIDwtIDANCmZvciAoaSBpbiAxOm5yb3coQ2hyb25vKSkgew0KICBzZXREVChIU0kpW3llYXIgPT0gQ2hyb25vJFllYXJbaV0sIHllYXJfc2NhbGUgOj0gc2VxKDEsIDAuMDAxLCBsZW5ndGgub3V0ID0gbnJvdyhzdWJzZXQoSFNJLCB5ZWFyID09IENocm9ubyRZZWFyW2ldKSkpXQ0KfQ0KSFNJJGN1bV95ZWFyX3NjYWxlIDwtIEhTSSR5ZWFyX3NjYWxlICsgSFNJJHllYXIgKyAwLjMNCg0KIyMjIyBhbGlnbmluZyBhbmQgcmVndWxhcmxpemluZyBYUkYgYW5kIEhTSSBkYXRhDQpTb3VyY2UgPC0gYXMuZGF0YS5mcmFtZShIU0lbLCBjKDExLCAzLCA0LCA5LCAxMCldKQ0KRGVzdGluIDwtIGFzLmRhdGEuZnJhbWUoWFJGWywgMjFdKQ0KTmFtZXMgPC0gY29sbmFtZXMoU291cmNlKQ0KDQojIGludGVycG9sYXRlIGRhdGEgZm9yIGFsbCBjb2x1bW5zDQpEYXRhIDwtIERlc3Rpbg0KZm9yIChpIGluIDI6bmNvbChTb3VyY2UpKSB7DQogIHRlbXAgPC0gYXBwcm94KFNvdXJjZVssIDFdLCBTb3VyY2VbLCBpXSwgeG91dCA9IERlc3RpblssIDFdKQ0KICBEYXRhWywgaV0gPC0gdGVtcCR5DQp9DQojIFJlcGxhY2UgZGVzdGluYXRpb24gZGVwdGggd2l0aCBpbnRlcnBvbGF0ZWQgZGVwdGggKGp1c3QgdG8gYmUgc3VyZSBpdCB3b3JrZWQpDQpEYXRhWywgMV0gPC0gdGVtcCR4DQojIFJlcGxhY2UgY29sdW1uIG5hbWVzIHdpdGggYWN0dWFsIG5hbWVzDQpjb2xuYW1lcyhEYXRhKSA8LSBjKCJEZXB0aF9jbSIsIE5hbWVzWzI6bGVuZ3RoKE5hbWVzKV0pDQoNCiMjIEZ1bGwgRGF0YXNldCAhDQpIaVJlc19mdWxsIDwtIGNiaW5kKFhSRlssIGMoMjEsIDIwLCAxOCwgNDo4LCAxMDoxMildLCBEYXRhWywgYygzLCA0LCA1KV0pDQpjb2xuYW1lcyhIaVJlc19mdWxsKSA8LSBjKCJBZ2UiLCAiVmFydmUgWWVhciIsICJDb21wIERlcHRoIiwgIkNhIiwgIkZlIiwgIk1uIiwgIlNpIiwgIlAiLCAiUyIsICJLIiwgIlRpIiwgIlJtZWFuIiwgIlRDaGwiLCAiQnBoZSIpDQoNCg0KIyMjIyMjIEFsaWduaW5nIEhTSSB0byBYUkYgdXNpbmcgZHluYW1pY2FsIHRpbWUgd2FycCBhbGlnbm1lbnQgb2YgUm1lYW4gYW5kIENhDQpIaVJlc19mdWxsX3NjYWxlZCA8LSBjYmluZChIaVJlc19mdWxsWywgMTozXSwgc2NhbGUoSGlSZXNfZnVsbFssIDQ6MTRdKSkNCnRlc3RfZHR3X1AyIDwtIGR0dyh4ID0gSGlSZXNfZnVsbF9zY2FsZWQkUm1lYW4sIHkgPSBIaVJlc19mdWxsX3NjYWxlZCRDYSwgd2luZG93LnR5cGUgPSAic2Frb2VjaGliYSIsIA0KICAgICAgICAgICAgICAgICAgIHdpbmRvdy5zaXplID0gNTAsIHN0ZXAucGF0dGVybiA9IHN5bW1ldHJpY1AyLCBrZWVwID0gVFJVRSkgDQojIFNha29lIENoaWJhIGJhbmQgaXMgc2ltcGxlIHN5bW1ldHJpY2FsIHdpbmRvdyAod2luZG93IHdpZHRoIGhlcmUgaXMgZXF1YWwgdG8gdGhlIHRoaW5uZXN0IHZhcnZlIHdpZHRoLCBpLmUuIDw9IDEgeWVhcikNCiMgVGVzdGluZyBzaG93ZWQgc3ltbWV0cmljIFAyIGlzIG1vc3QgcmVhc29uYWJsZSBzdGVwIHBhdHRlcm4sIGJ1dCB0aGlzIGNvdWxkIHZhcnkNCnBsb3QodGVzdF9kdHdfUDIsIHR5cGUgPSAidGhyZWV3YXkiKQ0KDQpIU0lfcmVndWxhciA8LSBuYS5vbWl0KERhdGFbLCAyOjVdKQ0Kd2FycCA8LSB3YXJwKHRlc3RfZHR3X1AyLCBpbmRleC5yZWZlcmVuY2UgPSBGQUxTRSkNCkhTSV9EVFcgPC0gSFNJX3JlZ3VsYXJbd2FycCwgXQ0KDQojIGV4YW1wbGUgcGxvdCBvZiBEVFcgYWxpZ25tZW50DQpwbG90KEhpUmVzX2Z1bGxfc2NhbGVkJEFnZS0wLjMsIEhpUmVzX2Z1bGxfc2NhbGVkJENhLCB0eXBlID0gImwiLCB4bGltID0gYygyMDE1LCAyMDIwKSwgeWxpbT0gYygtMi41LDQuNSksIG1haW4gPSAiZXhhbXBsZSBwbG90IG9mIERUVyBhbGlnbm1lbnQiLCB4bGFiPSAiQyAoJSkiLCB5bGFiID0gIlotc2NvcmUiKQ0KbGluZXMoSGlSZXNfZnVsbF9zY2FsZWQkQWdlLTAuMywgSGlSZXNfZnVsbF9zY2FsZWQkUm1lYW4sIGNvbCA9ICJyZWQiKQ0KbGluZXMoSGlSZXNfZnVsbF9zY2FsZWQkQWdlLTAuMywgc2NhbGUoSFNJX0RUVyRSbWVhbiksIGNvbCA9ICJibHVlIikNCmFibGluZSh2PWMoMjAxNSwyMDE2LDIwMTcsMjAxOCwyMDE5KSwgbHR5PTMpDQpsZWdlbmQoeCA9ICJib3R0b21yaWdodCIsICAgICAgICAgICMgUG9zaXRpb24NCiAgICAgICBsZWdlbmQgPSBjKCJDYSIsICJSbWVhbiIsICJSbWVhbiAoYWZ0ZXIgRFRXKSIpLCAgIyBMZWdlbmQgdGV4dHMNCiAgICAgICBsdHkgPSAxLCAgICAgICAgICAgIyBMaW5lIHR5cGVzDQogICAgICAgY29sID0gYygiYmxhY2siLCAicmVkIiwgImJsdWUiKSwgICAgICAgICAgICMgTGluZSBjb2xvcnMNCiAgICAgICBsd2QgPSAyKSAgICAgICAgICAgICAgICAgIyBMaW5lIHdpZHRoDQoNCmBgYA0KDQojIyBQbG90dGluZyBmdWxsIGRhdGFzZXRzDQoNCmBgYHtyIGZ1bGxfZGF0YSwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTAsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpybSh0ZXN0X2R0d19QMikNCiMgUHV0dGluZyB0b2dldGhlciBmdWxsLCBhbGlnbmVkIGRhdGFzZXQNCkhpUmVzX2Z1bGxbLCAxMjoxNF0gPC0gSFNJX0RUV1ssIGMoMjo0KV0NCmNvbG5hbWVzKEhpUmVzX2Z1bGwpW2MoMiwgMyldIDwtIGMoInZhcnZlX3llYXIiLCAiY29tcF9kZXB0aF9tbSIpDQpIaVJlc19mdWxsX3NjYWxlZCA8LSBjYmluZChIaVJlc19mdWxsWywgMTozXSwgc2NhbGUoSGlSZXNfZnVsbFssIDQ6MTRdKSkNCkhpUmVzX2Z1bGxfc3ViMSA8LSBIaVJlc19mdWxsW0hpUmVzX2Z1bGwkYHZhcnZlX3llYXJgID49IDE5NjZdICMgc3Vic2V0IGZvciBzdHVkeSBwZXJpb2QgMTk2Ni0yMDE5DQpgYGANCg0KUGxvdHRpbmcgWFJGIGFuZCBIU0kgZGF0YQ0KYGBge3IgSGlyZXNfcGxvdCwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTAsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpjb2xvcjEgPC0gYygiI2MwMWQxMSIsICIyMDY4YzkiLCAiIzMzNzk5YiIsICIjN2M5YjIxIiwgIiNhNTRhMGEiLCAiI2IzYTIyZSIsICIjMTc5OGExIiwgIiNhNjJiODQiLCAiIzBmNjkyZCIsICIjNTAwZjhmIikgIyBjb2xvciB2ZWN0b3INClhSRl9waXYgPC0gdGlkeXI6OnBpdm90X2xvbmdlcihIaVJlc19mdWxsLCBjb2xzID0gYygiQ2EiLCAiSyIsICJUaSIsICJTaSIsICJGZSIsICJTIiwgIk1uIiwgIlAiKSwgbmFtZXNfdG8gPSAicHJveHkiKSAjIG1ha2Ugc2lkZXdheXMNCnhyZl9kYXRhX3Bsb3RfZGVwdGggPC0gZ2dwbG90KFhSRl9waXYsIGFlcyh2YWx1ZSwgY29tcF9kZXB0aF9tbSwgY29sb3IgPSBmb3JjYXRzOjphc19mYWN0b3IocHJveHkpKSkgKw0KICBnZW9tX3BhdGgoKSArDQogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjb2xvcjEpICsNCiAgc2NhbGVfeV9yZXZlcnNlKGxpbWl0cyA9IGMoMzQ1LjA2LCAwLjYpKSArDQogIGxhYnMoeSA9ICJEZXB0aCAobW0pIiwgeCA9ICJjcHMiLCB0aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkgKw0KICBmYWNldF93cmFwKH5wcm94eSwgbmNvbCA9IDgsIHNjYWxlcyA9ICJmcmVlIikgKw0KICB0aGVtZV9idygpICsNCiAgdGhlbWUoDQogICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBsZWdlbmQuYm94LmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIg0KICApDQoNCkhTSV9waXYgPC0gdGlkeXI6OnBpdm90X2xvbmdlcihIU0ksIGNvbHMgPSBjKCJUQ2hsIiwgIkJwaGUiKSwgbmFtZXNfdG8gPSAicHJveHkiKSAjIG1ha2Ugc2lkZXdheXMNCkhTSV9kYXRhX3Bsb3RfZGVwdGggPC0gZ2dwbG90KEhTSV9waXYsIGFlcyh2YWx1ZSwgSFNJX2RlcHRoLCBjb2xvciA9IGZvcmNhdHM6OmFzX2ZhY3Rvcihwcm94eSkpKSArDQogIGdlb21fcGF0aCgpICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoIiMwZjY5MmQiLCAiIzUwMGY4ZiIpKSArDQogIHNjYWxlX3lfcmV2ZXJzZShsaW1pdHMgPSBjKDMyMC4wNCwgMC41NCkpICsNCiAgbGFicyh5ID0gZWxlbWVudF9ibGFuaygpLCB4ID0gInVnL2ciLCB0aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkgKw0KICBmYWNldF93cmFwKH5wcm94eSwgbmNvbCA9IDgsIHNjYWxlcyA9ICJmcmVlIikgKw0KICB0aGVtZV9idygpICsNCiAgdGhlbWUoDQogICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBsZWdlbmQuYm94LmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCksIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIg0KICApDQoNCnBsb3RfZ3JpZCh4cmZfZGF0YV9wbG90X2RlcHRoLCBIU0lfZGF0YV9wbG90X2RlcHRoLCByZWxfd2lkdGhzID0gYyg0IC8gNSwgMSAvIDUpKQ0KYGBgDQoNClBsb3R0aW5nIENOUywgTUFSLCBDcy0xMzcNCmBgYHtyIGNuc19wbG90LCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD0xMCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCkNOUyA8LSBDTlNbQ05TJHllYXIgPj0gMTk2NiAmIENOUyR5ZWFyIDw9IDIwMTksIF0NCnBhcihtZnJvdyA9IGMoMSwgNiksIG1hciA9IGMoNS4xLCAyLCAyLCAxKSkNCnBsb3QoQ05TJHRjX2NvcnIsIENOUyR5ZWFyLCB5bGltID0gYygxOTY2LCAyMDIwKSwgdHlwZSA9ICJvIiwgcGNoID0gMTYsIHhsaW0gPSBjKDAsIDIwKSwgeWxhYiA9ICJZZWFyIChDRSkiLCB4bGFiID0gIkMgKCUgd2VpZ2h0KSIpDQpsaW5lcyhDTlMkdG9jX2NvcnIsIENOUyR5ZWFyLCBsdHkgPSA1LCB0eXBlID0gIm8iLCBwY2ggPSAxNikNCmxpbmVzKENOUyR0aWNfcCwgQ05TJHllYXIsIGx0eSA9IDMsIHR5cGUgPSAibyIsIHBjaCA9IDE2KQ0KcGxvdChDTlMkdG9jLm5fY29yciwgQ05TJHllYXIsIHlsaW0gPSBjKDE5NjYsIDIwMjApLCB0eXBlID0gIm8iLCBwY2ggPSAxNiwgeGxpbSA9IGMoMCwgMTIpLCB4bGFiID0gIlRPQzpOIFJhdGlvIiwgeWF4dCA9ICJuIiwgbHR5ID0gMywgeWxhYiA9ICIiKQ0KcGxvdChDTlMkdG5fY29yciwgQ05TJHllYXIsIHlsaW0gPSBjKDE5NjYsIDIwMjApLCB0eXBlID0gIm8iLCBwY2ggPSAxNiwgeGxpbSA9IGMoMCwgMiksIHhsYWIgPSAiTiAoJSB3ZWlnaHQpIiwgeWF4dCA9ICJuIiwgeWxhYiA9ICIiKQ0KcGxvdChDTlMkdHNfcCwgQ05TJHllYXIsIHlsaW0gPSBjKDE5NjYsIDIwMjApLCB0eXBlID0gIm8iLCBwY2ggPSAxNiwgeGxpbSA9IGMoMCwgMyksIHhsYWIgPSAiUyAoJSB3ZWlnaHQpIiwgeWF4dCA9ICJuIiwgeWxhYiA9ICIiKQ0KcGxvdChDTlMkTUFSLCBDTlMkeWVhciwgeWxpbSA9IGMoMTk2NiwgMjAyMCksIHR5cGUgPSAibyIsIHBjaCA9IDE2LCB4bGltID0gYygwLCAyKSwgeGxhYiA9ICJNQVIgKGcgY20tMiB5ci0xKSIsIHlheHQgPSAibiIsIHlsYWIgPSAiIikNCnBsb3QoQ05TW2lzLm5hKENOUyRaQUJfMTJfMV9DcykgPT0gRkFMU0UsIF0kWkFCXzEyXzFfQ3MsIENOU1tpcy5uYShDTlMkWkFCXzEyXzFfQ3MpID09IEZBTFNFLCBdJHllYXIsDQogIHlsaW0gPSBjKDE5NjYsIDIwMjApLCB0eXBlID0gIm8iLCBwY2ggPSAxNiwNCiAgeGxhYiA9ICIxMzdDcyAoQnEga2ctMSkiLCB4bGltID0gYygwLCAzNTApLCB5YXh0ID0gIm4iLCB5bGFiID0gIiINCikNCmxpbmVzKENOUyRDcywgQ05TJHllYXIsIHR5cGUgPSAibyIsIGx0eSA9IDIsIHBjaCA9IDEpDQpgYGANCg0KIyMgVmFydmUgdHlwZSBjbGFzc2lmaWNhdGlvbiBiYXNlZCBvbiBtdWx0aXZhcmlhdGUgY2x1c3RlcmluZyBvZiBzdWItYW5udWFsIHRpbWVzZXJpZXMNCkFubnVhbCBjeWxlDQpgYGB7ciBhbm51YWwgY3ljbGUsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyBGaXJzdCwgYWxpZ25pbmcgYWxsIGRhdGEgdG8gYSBmcmFjdGlvbmFsIHZhcnZlIHllYXIgc2NhbGUgZnJvbSAwIHRvIDENCkEgPC0gcmVwKCJBIiwgbnJvdyhIaVJlc19mdWxsX3N1YjEpKQ0KSGlSZXNfZnVsbF9zdWIxIDwtIGFzLmRhdGEuZnJhbWUoY2JpbmQoQSwgSGlSZXNfZnVsbF9zdWIxKSkNCg0KZ2FwIDwtIDAuMDIgIyB0YXJnZXQgcmVzb2x1dGlvbiBpbiBmcmFjdGlvbmFsIHllYXIgdW5pdHMgKGVhY2ggeWVhciB3aWxsIGNvbnRhaW4gNTAgZGF0YSBwb2ludHMpDQoNCmludCA8LSBjdXQoSGlSZXNfZnVsbF9zdWIxJEFnZSwgc2VxKG1pbihIaVJlc19mdWxsX3N1YjEkQWdlKSwgbWF4KEhpUmVzX2Z1bGxfc3ViMSRBZ2UgKyBnYXApLCBieSA9IGdhcCksIHJpZ2h0ID0gRkFMU0UpDQphZyA8LSBhZ2dyZWdhdGUoSGlSZXNfZnVsbF9zdWIxW2MoMiwgNDoxNSldLCBsaXN0KEhpUmVzX2Z1bGxfc3ViMSRBLCBpbnQpLCBtZWFuKQ0KYWckYWdlX25ldyA8LSBzZXEoMTk2Ni4zLCAyMDIwLjI4LCBsZW5ndGgub3V0ID0gbnJvdyhhZykpDQoNCmFnJHllYXJfc2NhbGUgPC0gYWckYWdlX25ldyAtIGZsb29yKGFnJGFnZV9uZXcpDQphZyR5ZWFyX3NjYWxlIDwtIHJvdW5kKGFnJHllYXJfc2NhbGUsIDIpDQpmb3IgKGkgaW4gMTpsZW5ndGgoYWckeWVhcl9zY2FsZSkpIHsNCiAgaWYgKGFnJHllYXJfc2NhbGVbaV0gPD0gMC4zKSB7DQogICAgYWckeWVhcl9zY2FsZVtpXSA8LSBhZyR5ZWFyX3NjYWxlW2ldICsgMC43DQogIH0gZWxzZSB7DQogICAgYWckeWVhcl9zY2FsZVtpXSA8LSBhZyR5ZWFyX3NjYWxlW2ldIC0gMC4zDQogIH0NCn0NCg0KYWcgPC0gYXMuZGF0YS5mcmFtZShjYmluZChhZ1sxNjoxN10sIGFnWzU6MTVdKSkNCmFnWywgMzoxM10gPC0gc2NhbGUoYWdbLCAzOjEzXSkNCnllYXJfYWcgPC0gYWdncmVnYXRlKGFnWzM6MTNdLCBsaXN0KGFnJHllYXJfc2NhbGUpLCBGVU4gPSBtZWFuKQ0KDQp5ZWFyX2FnX3BpdjEgPC0gdGlkeXI6OnBpdm90X2xvbmdlcih5ZWFyX2FnLCBjb2xzID0gYygiQ2EiLCAiVGkiLCAiU2kiLCAiRmUiLCAiUyIsICJNbiIsICJQIiwgIlRDaGwiLCAiQnBoZSIpLCBuYW1lc190byA9ICJwcm94eSIpDQpjb2xvcjIgPC0gYygiI2MwMWQxMSIsICIjMzM3OTliIiwgIiM3YzliMjEiLCAiI2E1NGEwYSIsICIjYjNhMjJlIiwgIiMxNzk4YTEiLCAiI2E2MmI4NCIsICIjMGY2OTJkIiwgIiM1MDBmOGYiKSAjIGNvbG9yIHZlY3Rvcg0KY29sbmFtZXMoeWVhcl9hZ19waXYxKVsxXSA8LSAieWVhcl9zY2FsZSINCiMjIyMgYW5udWFsIGN5bGUgcGxvdCBtZWFuIHZhbHVlcw0KYW5uX2N5Y2xlMSA8LSBnZ3Bsb3QoeWVhcl9hZ19waXYxLCBhZXMoeWVhcl9zY2FsZSwgdmFsdWUsIGNvbG9yID0gZm9yY2F0czo6YXNfZmFjdG9yKHByb3h5KSkpICsNCiAgZ2VvbV9wYXRoKGFscGhhID0gMC42LCBsd2QgPSAxLjUpICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNvbG9yMikgKw0KICBsYWJzKA0KICAgIHggPSAiIiwNCiAgICB5ID0gIlotc2NvcmUiLA0KICAgIHRpdGxlID0gIkF2ZXJhZ2UgQW5udWFsIEN5Y2xlIDE5NjYtMjAxOSIsDQogICAgY29sb3IgPSAicHJveHkiDQogICkgKw0KICB0aGVtZV9idygpICsNCiAgZ3VpZGVzKGNvbG91ciA9IGd1aWRlX2xlZ2VuZChucm93ID0gMSkpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpDQphbm5fY3ljbGUxDQpgYGANCg0KVmFydmUgdHlwZSBjbGFzc2lmaWNhdGlvbiBiYXNlZCBvbiBtdWx0aXZhcmlhdGUgdGltZSBzZXJpZXMgY2x1c3RlcmluZyBvZiB3aXRoaW4tdmFydmUgdGltZSBzZXJpZXMNCg0KYGBge3IgdmFydmUgdHlwZSwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTAsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIHByZXBhcmluZyBkYXRhIGZvciBkaXNzaW1pbGFyaXR5IGNhbGN1bGF0aW9uOiB0cmFuc2Zvcm0sIGRldHJlbmQgYW5kIHNjYWxlIGRhdGENCnNlcXVlbmNlMSA8LSBIaVJlc19mdWxsWywgYyg0OjExLCAxMywgMTQpXQ0Kc2VxdWVuY2UxIDwtIHNlcXVlbmNlMSArIDENCnNlcXVlbmNlMSA8LSBsb2coc2VxdWVuY2UxKQ0Kc2VxdWVuY2UxIDwtIGRldHJlbmQoYXMubWF0cml4KHNlcXVlbmNlMSkpDQpzZXF1ZW5jZTEgPC0gYXMuZGF0YS5mcmFtZShzZXF1ZW5jZTEpDQpzZXF1ZW5jZTEkYEJwaGVgW3NlcXVlbmNlMSRgQnBoZWAgPD0gc2VxdWVuY2UxJGBCcGhlYFs2NDEzXV0gPC0gc2VxdWVuY2UxJGBCcGhlYFs2NDEzXSAjIHJlc2V0dGluZyAwIGJhc2VsaW5lIGZvciBCcGhlIGFmdGVyIGRldHJlbmRpbmcNCnNlcXVlbmNlMSA8LSBjYmluZChIaVJlc19mdWxsJHZhcnZlX3llYXIsIFhSRiR5ZWFyX3NjYWxlWzE6NjQxM10sIHNjYWxlKHNlcXVlbmNlMSkpDQpzZXF1ZW5jZTEgPC0gYXMuZGF0YS5mcmFtZShzZXF1ZW5jZTEpDQpjb2xuYW1lcyhzZXF1ZW5jZTEpW2MoMSwgMildIDwtIGMoIlZhcnZlX1llYXIiLCAiWWVhcl9zY2FsZSIpDQpzZXF1ZW5jZTEgPC0gc3Vic2V0KHNlcXVlbmNlMSwgVmFydmVfWWVhciA8PSAyMDE5ICYgVmFydmVfWWVhciA+PSAxOTY2KSAjIHN0dWR5IHBlcmlvZA0KDQpwc2kxIDwtIHdvcmtmbG93UHNpKA0KICBzZXF1ZW5jZXMgPSBzZXF1ZW5jZTEsDQogIGdyb3VwaW5nLmNvbHVtbiA9ICJWYXJ2ZV9ZZWFyIiwNCiAgdGltZS5jb2x1bW4gPSAiWWVhcl9zY2FsZSIsDQogIG1ldGhvZCA9ICJldWNsaWRlYW4iLA0KICBkaWFnb25hbCA9IFRSVUUsDQogIGlnbm9yZS5ibG9ja3MgPSBUUlVFLA0KICBmb3JtYXQgPSAibWF0cml4Ig0KKQ0KDQpoY2x1c3RfMSA8LSBoY2x1c3QoYXMuZGlzdChwc2kxKSwgbWV0aG9kID0gIndhcmQuRDIiKQ0KcGxvdChoY2x1c3RfMSkNCmBgYA0KDQpIZWF0bWFwIG9mIGRpc3NpbWlsYXJpdHkgc2NvcmVzDQoNCmBgYHtyIGhlYXRtYXAsIGZpZy5oZWlnaHQ9MTAsIGZpZy53aWR0aD0xMCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCnBzaTFfbm96ZXJvIDwtIHBzaTENCnBzaTFfbm96ZXJvW3BzaTFfbm96ZXJvID09IDBdIDwtIE5BDQpoZWF0bWFwKHBzaTFfbm96ZXJvLCBSb3d2ID0gYXMuZGVuZHJvZ3JhbShoY2x1c3RfMSksIENvbHYgPSBhcy5kZW5kcm9ncmFtKGhjbHVzdF8xKSwgc3ltbSA9IFRSVUUsIGNvbCA9IHZpcmlkaXMoMjU2KSkNCm15Y2wgPC0gY3V0cmVlKGhjbHVzdF8xLCBoID0gNS4zKQ0KbXljbCA8LSBhcy5kYXRhLmZyYW1lKG15Y2wpDQpjb2xuYW1lcyhteWNsKSA8LSBjKCJncm91cCIpDQpteWNsJHllYXIgPC0gcm93bmFtZXMobXljbCkNCmBgYA0KDQpCYXIgcGxvdCAtIGltcG9ydGFuY2Ugb2YgZWFjaCBlbGVtZW50IGluIGRyaXZpbmcgeWVhci10by15ZWFyIGRpc3NpbWlsYXJpdHkNCg0KYGBge3IgZGlzc2ltaWxhcml0eSwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9NiwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCnBzaS5pbXBvcnRhbmNlIDwtIHdvcmtmbG93SW1wb3J0YW5jZSgNCiAgc2VxdWVuY2VzID0gc2VxdWVuY2UxLA0KICBncm91cGluZy5jb2x1bW4gPSAiVmFydmVfWWVhciIsDQogIHRpbWUuY29sdW1uID0gIlllYXJfc2NhbGUiLA0KICBtZXRob2QgPSAiZXVjbGlkZWFuIiwNCiAgZGlhZ29uYWwgPSBUUlVFLA0KICBpZ25vcmUuYmxvY2tzID0gVFJVRQ0KKQ0KDQpwc2kuZGYgPC0gcHNpLmltcG9ydGFuY2UkcHNpDQpwc2kuZHJvcC5kZiA8LSBwc2kuaW1wb3J0YW5jZSRwc2kuZHJvcA0KYmFycGxvdChjb2xNZWFucyhwc2kuZHJvcC5kZlssIDM6MTJdKSkNCmBgYA0KDQpWYXJ2ZSBUeXBlIHBsb3RzDQoNCmBgYHtyIHZhcnZlIHR5cGUgcGxvdHMsIGZpZy5oZWlnaHQ9MTAsIGZpZy53aWR0aD0xMCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmFnJHZhcnZlX3llYXIgPC0gYWckYWdlX25ldyAtIDAuMw0KYWckdmFydmVfeWVhciA8LSBmbG9vcihhZyR2YXJ2ZV95ZWFyKQ0KYWckY2x1c3RfZ3JvdXAgPC0gMA0KdmFydmVfeWVhcnMgPC0gc2VxKDIwMTksIDE5NjYsIC0xKQ0KZm9yIChpIGluIDE6bGVuZ3RoKGFnJHZhcnZlX3llYXIpKSB7DQogIGZvciAoaiBpbiAxOmxlbmd0aCh2YXJ2ZV95ZWFycykpIHsNCiAgICBpZiAoYWckdmFydmVfeWVhcltpXSA9PSB2YXJ2ZV95ZWFyc1tqXSkgew0KICAgICAgYWckY2x1c3RfZ3JvdXBbaV0gPC0gbXljbFtqLCAxXQ0KICAgIH0NCiAgfQ0KfQ0KDQojIHByb3h5IGNsdXN0ZXJzIG1lYW4gYW5kIDgwJSBDSXMNCmdyb3VwMV9hZyA8LSBhZ2dyZWdhdGUoc3Vic2V0KGFnLCBjbHVzdF9ncm91cCA9PSAxKSwgbGlzdChzdWJzZXQoYWcsIGNsdXN0X2dyb3VwID09IDEpJHllYXJfc2NhbGUpLCBGVU4gPSBtZWFuKQ0KZ3JvdXAxXzkwIDwtIGFnZ3JlZ2F0ZShzdWJzZXQoYWcsIGNsdXN0X2dyb3VwID09IDEpLCBsaXN0KHN1YnNldChhZywgY2x1c3RfZ3JvdXAgPT0gMSkkeWVhcl9zY2FsZSksIGZ1bmN0aW9uKHgpIHF1YW50aWxlKHgsIDAuOTApKQ0KZ3JvdXAxXzEwIDwtIGFnZ3JlZ2F0ZShzdWJzZXQoYWcsIGNsdXN0X2dyb3VwID09IDEpLCBsaXN0KHN1YnNldChhZywgY2x1c3RfZ3JvdXAgPT0gMSkkeWVhcl9zY2FsZSksIGZ1bmN0aW9uKHgpIHF1YW50aWxlKHgsIDAuMTApKQ0KZ3JvdXAyX2FnIDwtIGFnZ3JlZ2F0ZShzdWJzZXQoYWcsIGNsdXN0X2dyb3VwID09IDIpLCBsaXN0KHN1YnNldChhZywgY2x1c3RfZ3JvdXAgPT0gMikkeWVhcl9zY2FsZSksIEZVTiA9IG1lYW4pDQpncm91cDJfOTAgPC0gYWdncmVnYXRlKHN1YnNldChhZywgY2x1c3RfZ3JvdXAgPT0gMiksIGxpc3Qoc3Vic2V0KGFnLCBjbHVzdF9ncm91cCA9PSAyKSR5ZWFyX3NjYWxlKSwgZnVuY3Rpb24oeCkgcXVhbnRpbGUoeCwgMC45KSkNCmdyb3VwMl8xMCA8LSBhZ2dyZWdhdGUoc3Vic2V0KGFnLCBjbHVzdF9ncm91cCA9PSAyKSwgbGlzdChzdWJzZXQoYWcsIGNsdXN0X2dyb3VwID09IDIpJHllYXJfc2NhbGUpLCBmdW5jdGlvbih4KSBxdWFudGlsZSh4LCAwLjEpKQ0KZ3JvdXAzX2FnIDwtIGFnZ3JlZ2F0ZShzdWJzZXQoYWcsIGNsdXN0X2dyb3VwID09IDMpLCBsaXN0KHN1YnNldChhZywgY2x1c3RfZ3JvdXAgPT0gMykkeWVhcl9zY2FsZSksIEZVTiA9IG1lYW4pDQpncm91cDNfOTAgPC0gYWdncmVnYXRlKHN1YnNldChhZywgY2x1c3RfZ3JvdXAgPT0gMyksIGxpc3Qoc3Vic2V0KGFnLCBjbHVzdF9ncm91cCA9PSAzKSR5ZWFyX3NjYWxlKSwgZnVuY3Rpb24oeCkgcXVhbnRpbGUoeCwgMC45KSkNCmdyb3VwM18xMCA8LSBhZ2dyZWdhdGUoc3Vic2V0KGFnLCBjbHVzdF9ncm91cCA9PSAzKSwgbGlzdChzdWJzZXQoYWcsIGNsdXN0X2dyb3VwID09IDMpJHllYXJfc2NhbGUpLCBmdW5jdGlvbih4KSBxdWFudGlsZSh4LCAwLjEpKQ0KZ3JvdXA0X2FnIDwtIGFnZ3JlZ2F0ZShzdWJzZXQoYWcsIGNsdXN0X2dyb3VwID09IDQpLCBsaXN0KHN1YnNldChhZywgY2x1c3RfZ3JvdXAgPT0gNCkkeWVhcl9zY2FsZSksIEZVTiA9IG1lYW4pDQpncm91cDRfOTAgPC0gYWdncmVnYXRlKHN1YnNldChhZywgY2x1c3RfZ3JvdXAgPT0gNCksIGxpc3Qoc3Vic2V0KGFnLCBjbHVzdF9ncm91cCA9PSA0KSR5ZWFyX3NjYWxlKSwgZnVuY3Rpb24oeCkgcXVhbnRpbGUoeCwgMC45KSkNCmdyb3VwNF8xMCA8LSBhZ2dyZWdhdGUoc3Vic2V0KGFnLCBjbHVzdF9ncm91cCA9PSA0KSwgbGlzdChzdWJzZXQoYWcsIGNsdXN0X2dyb3VwID09IDQpJHllYXJfc2NhbGUpLCBmdW5jdGlvbih4KSBxdWFudGlsZSh4LCAwLjEpKQ0KDQpncm91cDFfYWdfcGl2MSA8LSB0aWR5cjo6cGl2b3RfbG9uZ2VyKGdyb3VwMV9hZywgY29scyA9IGMoIkNhIiwgIlRpIiwgIlNpIiwgIkZlIiwgIlMiLCAiTW4iLCAiUCIsICJUQ2hsIiwgIkJwaGUiKSwgbmFtZXNfdG8gPSAicHJveHkiKQ0KZ3JvdXAxX2FnX3BpdjEgPC0gY2JpbmQoZ3JvdXAxX2FnX3BpdjFbLCBjKDMsIDgsIDkpXSwgdGlkeXI6OnBpdm90X2xvbmdlcihncm91cDFfOTAsIGNvbHMgPSBjKCJDYSIsICJUaSIsICJTaSIsICJGZSIsICJTIiwgIk1uIiwgIlAiLCAiVENobCIsICJCcGhlIiksIG5hbWVzX3RvID0gInByb3h5IiwgdmFsdWVzX3RvID0gInA5MHRoIilbOV0sIHRpZHlyOjpwaXZvdF9sb25nZXIoZ3JvdXAxXzEwLCBjb2xzID0gYygiQ2EiLCAiVGkiLCAiU2kiLCAiRmUiLCAiUyIsICJNbiIsICJQIiwgIlRDaGwiLCAiQnBoZSIpLCBuYW1lc190byA9ICJwcm94eSIsIHZhbHVlc190byA9ICJwMTB0aCIpWzldKQ0KZ3JvdXAxX2FnX3BpdjEkZ3JvdXAgPC0gIlZhcnZlIFR5cGUgMSINCg0KZ3JvdXAyX2FnX3BpdjEgPC0gdGlkeXI6OnBpdm90X2xvbmdlcihncm91cDJfYWcsIGNvbHMgPSBjKCJDYSIsICJUaSIsICJTaSIsICJGZSIsICJTIiwgIk1uIiwgIlAiLCAiVENobCIsICJCcGhlIiksIG5hbWVzX3RvID0gInByb3h5IikNCmdyb3VwMl9hZ19waXYxIDwtIGNiaW5kKGdyb3VwMl9hZ19waXYxWywgYygzLCA4LCA5KV0sIHRpZHlyOjpwaXZvdF9sb25nZXIoZ3JvdXAyXzkwLCBjb2xzID0gYygiQ2EiLCAiVGkiLCAiU2kiLCAiRmUiLCAiUyIsICJNbiIsICJQIiwgIlRDaGwiLCAiQnBoZSIpLCBuYW1lc190byA9ICJwcm94eSIsIHZhbHVlc190byA9ICJwOTB0aCIpWzldLCB0aWR5cjo6cGl2b3RfbG9uZ2VyKGdyb3VwMl8xMCwgY29scyA9IGMoIkNhIiwgIlRpIiwgIlNpIiwgIkZlIiwgIlMiLCAiTW4iLCAiUCIsICJUQ2hsIiwgIkJwaGUiKSwgbmFtZXNfdG8gPSAicHJveHkiLCB2YWx1ZXNfdG8gPSAicDEwdGgiKVs5XSkNCmdyb3VwMl9hZ19waXYxJGdyb3VwIDwtICJWYXJ2ZSBUeXBlIDIiDQoNCmdyb3VwM19hZ19waXYxIDwtIHRpZHlyOjpwaXZvdF9sb25nZXIoZ3JvdXAzX2FnLCBjb2xzID0gYygiQ2EiLCAiVGkiLCAiU2kiLCAiRmUiLCAiUyIsICJNbiIsICJQIiwgIlRDaGwiLCAiQnBoZSIpLCBuYW1lc190byA9ICJwcm94eSIpDQpncm91cDNfYWdfcGl2MSA8LSBjYmluZChncm91cDNfYWdfcGl2MVssIGMoMywgOCwgOSldLCB0aWR5cjo6cGl2b3RfbG9uZ2VyKGdyb3VwM185MCwgY29scyA9IGMoIkNhIiwgIlRpIiwgIlNpIiwgIkZlIiwgIlMiLCAiTW4iLCAiUCIsICJUQ2hsIiwgIkJwaGUiKSwgbmFtZXNfdG8gPSAicHJveHkiLCB2YWx1ZXNfdG8gPSAicDkwdGgiKVs5XSwgdGlkeXI6OnBpdm90X2xvbmdlcihncm91cDNfMTAsIGNvbHMgPSBjKCJDYSIsICJUaSIsICJTaSIsICJGZSIsICJTIiwgIk1uIiwgIlAiLCAiVENobCIsICJCcGhlIiksIG5hbWVzX3RvID0gInByb3h5IiwgdmFsdWVzX3RvID0gInAxMHRoIilbOV0pDQpncm91cDNfYWdfcGl2MSRncm91cCA8LSAiVmFydmUgVHlwZSAzIg0KDQpncm91cDRfYWdfcGl2MSA8LSB0aWR5cjo6cGl2b3RfbG9uZ2VyKGdyb3VwNF9hZywgY29scyA9IGMoIkNhIiwgIlRpIiwgIlNpIiwgIkZlIiwgIlMiLCAiTW4iLCAiUCIsICJUQ2hsIiwgIkJwaGUiKSwgbmFtZXNfdG8gPSAicHJveHkiKQ0KZ3JvdXA0X2FnX3BpdjEgPC0gY2JpbmQoZ3JvdXA0X2FnX3BpdjFbLCBjKDMsIDgsIDkpXSwgdGlkeXI6OnBpdm90X2xvbmdlcihncm91cDRfOTAsIGNvbHMgPSBjKCJDYSIsICJUaSIsICJTaSIsICJGZSIsICJTIiwgIk1uIiwgIlAiLCAiVENobCIsICJCcGhlIiksIG5hbWVzX3RvID0gInByb3h5IiwgdmFsdWVzX3RvID0gInA5MHRoIilbOV0sIHRpZHlyOjpwaXZvdF9sb25nZXIoZ3JvdXA0XzEwLCBjb2xzID0gYygiQ2EiLCAiVGkiLCAiU2kiLCAiRmUiLCAiUyIsICJNbiIsICJQIiwgIlRDaGwiLCAiQnBoZSIpLCBuYW1lc190byA9ICJwcm94eSIsIHZhbHVlc190byA9ICJwMTB0aCIpWzldKQ0KZ3JvdXA0X2FnX3BpdjEkZ3JvdXAgPC0gIlZhcnZlIFR5cGUgNCINCg0KZ3JvdXBzX2FsbCA8LSByYmluZChncm91cDFfYWdfcGl2MSwgZ3JvdXAyX2FnX3BpdjEsIGdyb3VwM19hZ19waXYxLCBncm91cDRfYWdfcGl2MSkNCmdyb3Vwc19hbGwkcHJveHlfZ3JvdXAgPC0gIkEiDQpncm91cHNfYWxsW2dyb3Vwc19hbGwkcHJveHkgJWluJSBjKCJDYSIsICJQIiwgIlRDaGwiKSwgXSRwcm94eV9ncm91cCA8LSAiQSINCmdyb3Vwc19hbGxbZ3JvdXBzX2FsbCRwcm94eSAlaW4lIGMoIkZlIiwgIlMiLCAiTW4iKSwgXSRwcm94eV9ncm91cCA8LSAiQiINCmdyb3Vwc19hbGxbZ3JvdXBzX2FsbCRwcm94eSAlaW4lIGMoIlRpIiwgIlNpIiwgIkJwaGUiKSwgXSRwcm94eV9ncm91cCA8LSAiQyINCg0KIyBwbG90DQphbGxfZ3JvdXBzX3Bsb3QyIDwtIGdncGxvdChncm91cHNfYWxsLCBhZXMoeWVhcl9zY2FsZSkpICsNCiAgZ2VvbV9wYXRoKGFlcyh4ID0geWVhcl9zY2FsZSwgeSA9IHZhbHVlLCBjb2xvciA9IGZvcmNhdHM6OmFzX2ZhY3Rvcihwcm94eSkpLCBzaXplID0gMSkgKw0KICBnZW9tX3JpYmJvbihhZXMoeW1pbiA9IHAxMHRoLCB5bWF4ID0gcDkwdGgsIGZpbGwgPSBmb3JjYXRzOjphc19mYWN0b3IocHJveHkpKSwgYWxwaGEgPSAwLjMpICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGMoY29sb3IyKSkgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKGNvbG9yMikpICsNCiAgbGFicygNCiAgICB4ID0gIiIsDQogICAgeSA9ICJaLXNjb3JlIiwNCiAgICBjb2xvciA9ICJwcm94eSINCiAgKSArDQogIHRoZW1lX2J3KCkgKw0KICBndWlkZXMoY29sb3VyID0gZ3VpZGVfbGVnZW5kKG5yb3cgPSAxKSkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikgKw0KICBmYWNldF9ncmlkKHJvd3MgPSB2YXJzKGdyb3VwKSwgY29scyA9IHZhcnMocHJveHlfZ3JvdXApKQ0KYWxsX2dyb3Vwc19wbG90Mg0KYGBgDQoNCiMjIENvbXBhcmluZyBtZXRlb3JvbG9naWNhbCBjb25kaXRpb25zIGluIHllYXJzIGRlZmluZWQgYnkgdmFydmUgdHlwZXMNCg0KQm94cGxvdCBvZiBzZWFzb25hbCB3ZWF0aGVyIGJ5IHZhcnZlIHR5cGUNCg0KYGBge3IgbWV0ZW8gYnkgdmFydmUgdHlwZSwgZmlnLmhlaWdodD0xMCwgZmlnLndpZHRoPTYsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIyMgYWdncmVnYXRlIG1ldGVvIGRhdGEgaW50byBhbm51YWwgc2Vhc29uYWwgdmFsdWVzDQpLZXRfbWV0ZW8gPC0gc3Vic2V0LmRhdGEuZnJhbWUobWV0ZW8sIHN0YXRpb24gPT0gIks/VFJaWU4iKQ0KIyBzdWJzdGl0dXRlIG1pc3Npbmcgd2luZCBkYXRhIHdpdGggbWVhbiB2YWx1ZXMNCktldF9tZXRlbyR3c19tZWFuX2RhaWx5WygyOTMwOSAtIDE5MTczKTooMjk2ODMgLSAxOTE3MyldIDwtIE5BDQpLZXRfbWV0ZW8gPC0gS2V0X21ldGVvICU+JQ0KICBncm91cF9ieShkYXlfb2ZfeWVhcikgJT4lDQogIG11dGF0ZSh3c19tZWFuX2RhaWx5ID0gcmVwbGFjZSh3c19tZWFuX2RhaWx5LCBpcy5uYSh3c19tZWFuX2RhaWx5KSwgbWVhbih3c19tZWFuX2RhaWx5LCBuYS5ybSA9IFRSVUUpKSkgJT4lDQogIHVuZ3JvdXAoKQ0KS2V0X21ldGVvIDwtIGFzLmRhdGEuZnJhbWUoS2V0X21ldGVvKQ0KIyBkZWZpbmUgdmFydmUgeWVhciBhcyBNYXJjaCB0byBNYXJjaA0KS2V0X21ldGVvJHZhcnZlX3llYXIgPC0gS2V0X21ldGVvJHl5DQpLZXRfbWV0ZW8kdmFydmVfeWVhcltLZXRfbWV0ZW8kbW0gPT0gMSB8IEtldF9tZXRlbyRtbSA9PSAyXSA8LSBLZXRfbWV0ZW8keXlbS2V0X21ldGVvJG1tID09IDEgfCBLZXRfbWV0ZW8kbW0gPT0gMl0gLSAxDQoNCm1ldGVvX2Fubl9tZWFuIDwtIGFnZ3JlZ2F0ZShLZXRfbWV0ZW9bLCBjKDksIDExLCAzOSldLCBsaXN0KEtldF9tZXRlbyR2YXJ2ZV95ZWFyKSwgbWVhbikNCmNvbG5hbWVzKG1ldGVvX2Fubl9tZWFuKSA8LSBjKCJ2YXJ2ZV95ZWFyIiwgIlRlbXBfQU5OIiwgIlByZWNpcF9BTk4iLCAiV2luZF9BTk4iKQ0KbWV0ZW9fYW5uX21lYW4gPC0gc3Vic2V0KG1ldGVvX2Fubl9tZWFuLCB2YXJ2ZV95ZWFyID49IDE5NjYpDQoNCiMgY3JlYXRpbmcgZW1wdHkgY29sdW1ucw0KbWV0ZW9fYW5uX21lYW4kVGVtcF9NQU0gPC0gMA0KbWV0ZW9fYW5uX21lYW4kVGVtcF9KSkEgPC0gMA0KbWV0ZW9fYW5uX21lYW4kVGVtcF9TT04gPC0gMA0KbWV0ZW9fYW5uX21lYW4kVGVtcF9ESkYgPC0gMA0KbWV0ZW9fYW5uX21lYW4kVGVtcF9NQU1fbGFnMSA8LSAwDQptZXRlb19hbm5fbWVhbiRUZW1wX01BTUpKQSA8LSAwDQoNCm1ldGVvX2Fubl9tZWFuJHA5MF9QcmVjaXBfTUFNIDwtIDANCm1ldGVvX2Fubl9tZWFuJHA5MF9QcmVjaXBfSkpBIDwtIDANCm1ldGVvX2Fubl9tZWFuJHA5MF9QcmVjaXBfU09OIDwtIDANCm1ldGVvX2Fubl9tZWFuJHA5MF9QcmVjaXBfREpGIDwtIDANCm1ldGVvX2Fubl9tZWFuJHA5MF9QcmVjaXBfTUFNX2xhZzEgPC0gMA0KDQptZXRlb19hbm5fbWVhbiRwOTBfV2luZF9NQU0gPC0gMA0KbWV0ZW9fYW5uX21lYW4kcDkwX1dpbmRfSkpBIDwtIDANCm1ldGVvX2Fubl9tZWFuJHA5MF9XaW5kX1NPTiA8LSAwDQptZXRlb19hbm5fbWVhbiRwOTBfV2luZF9ESkYgPC0gMA0KbWV0ZW9fYW5uX21lYW4kcDkwX1dpbmRfTUFNX2xhZzEgPC0gMA0KbWV0ZW9fYW5uX21lYW4kTUFSX0RFQ19XaW5kX0RheXMgPC0gMA0KDQptZXRlb19hbm5fbWVhbiRUZW1wX01BUiA8LSAwDQptZXRlb19hbm5fbWVhbiRUZW1wX0FQUiA8LSAwDQptZXRlb19hbm5fbWVhbiRUZW1wX01BWSA8LSAwDQptZXRlb19hbm5fbWVhbiRUZW1wX0pVTiA8LSAwDQptZXRlb19hbm5fbWVhbiRUZW1wX0pVTCA8LSAwDQptZXRlb19hbm5fbWVhbiRUZW1wX0FVRyA8LSAwDQptZXRlb19hbm5fbWVhbiRUZW1wX1NFUCA8LSAwDQptZXRlb19hbm5fbWVhbiRUZW1wX09DVCA8LSAwDQptZXRlb19hbm5fbWVhbiRUZW1wX05PViA8LSAwDQptZXRlb19hbm5fbWVhbiRUZW1wX0RFQyA8LSAwDQptZXRlb19hbm5fbWVhbiRUZW1wX0pBTl9MQUcxIDwtIDANCm1ldGVvX2Fubl9tZWFuJFRlbXBfRkVCX0xBRzEgPC0gMA0KbWV0ZW9fYW5uX21lYW4kVGVtcF9NQVJfTEFHMSA8LSAwDQptZXRlb19hbm5fbWVhbiRUZW1wX0FQUl9MQUcxIDwtIDANCm1ldGVvX2Fubl9tZWFuJFRlbXBfTUFZX0xBRzEgPC0gMA0KDQptZXRlb19hbm5fbWVhbiRwOTBfUHJlY2lwX01BUiA8LSAwDQptZXRlb19hbm5fbWVhbiRwOTBfUHJlY2lwX0FQUiA8LSAwDQptZXRlb19hbm5fbWVhbiRwOTBfUHJlY2lwX01BWSA8LSAwDQptZXRlb19hbm5fbWVhbiRwOTBfUHJlY2lwX0pVTiA8LSAwDQptZXRlb19hbm5fbWVhbiRwOTBfUHJlY2lwX0pVTCA8LSAwDQptZXRlb19hbm5fbWVhbiRwOTBfUHJlY2lwX0FVRyA8LSAwDQptZXRlb19hbm5fbWVhbiRwOTBfUHJlY2lwX1NFUCA8LSAwDQptZXRlb19hbm5fbWVhbiRwOTBfUHJlY2lwX09DVCA8LSAwDQptZXRlb19hbm5fbWVhbiRwOTBfUHJlY2lwX05PViA8LSAwDQptZXRlb19hbm5fbWVhbiRwOTBfUHJlY2lwX0RFQyA8LSAwDQptZXRlb19hbm5fbWVhbiRwOTBfUHJlY2lwX0pBTl9MQUcxIDwtIDANCm1ldGVvX2Fubl9tZWFuJHA5MF9QcmVjaXBfRkVCX0xBRzEgPC0gMA0KbWV0ZW9fYW5uX21lYW4kcDkwX1ByZWNpcF9NQVJfTEFHMSA8LSAwDQptZXRlb19hbm5fbWVhbiRwOTBfUHJlY2lwX0FQUl9MQUcxIDwtIDANCm1ldGVvX2Fubl9tZWFuJHA5MF9QcmVjaXBfTUFZX0xBRzEgPC0gMA0KDQptZXRlb19hbm5fbWVhbiRwOTBfV2luZF9NQVIgPC0gMA0KbWV0ZW9fYW5uX21lYW4kcDkwX1dpbmRfQVBSIDwtIDANCm1ldGVvX2Fubl9tZWFuJHA5MF9XaW5kX01BWSA8LSAwDQptZXRlb19hbm5fbWVhbiRwOTBfV2luZF9KVU4gPC0gMA0KbWV0ZW9fYW5uX21lYW4kcDkwX1dpbmRfSlVMIDwtIDANCm1ldGVvX2Fubl9tZWFuJHA5MF9XaW5kX0FVRyA8LSAwDQptZXRlb19hbm5fbWVhbiRwOTBfV2luZF9TRVAgPC0gMA0KbWV0ZW9fYW5uX21lYW4kcDkwX1dpbmRfT0NUIDwtIDANCm1ldGVvX2Fubl9tZWFuJHA5MF9XaW5kX05PViA8LSAwDQptZXRlb19hbm5fbWVhbiRwOTBfV2luZF9ERUMgPC0gMA0KbWV0ZW9fYW5uX21lYW4kcDkwX1dpbmRfSkFOX0xBRzEgPC0gMA0KbWV0ZW9fYW5uX21lYW4kcDkwX1dpbmRfRkVCX0xBRzEgPC0gMA0KbWV0ZW9fYW5uX21lYW4kcDkwX1dpbmRfTUFSX0xBRzEgPC0gMA0KbWV0ZW9fYW5uX21lYW4kcDkwX1dpbmRfQVBSX0xBRzEgPC0gMA0KbWV0ZW9fYW5uX21lYW4kcDkwX1dpbmRfTUFZX0xBRzEgPC0gMA0KDQojIGZpbGxpbmcgaW4gd2l0aCBhbm51YWxpemVkIGRhdGENCnd0IDwtIDcgIyB0aHJlc2hvbGQgZm9yIHdpbmQgZGF5cyAobS9zKQ0KDQpmb3IgKGkgaW4gMTpucm93KG1ldGVvX2Fubl9tZWFuKSkgew0KICBtZXRlb19hbm5fbWVhbiRUZW1wX01BTVtpXSA8LSBtZWFuKHN1YnNldC5kYXRhLmZyYW1lKEtldF9tZXRlbywgeXkgPT0gbWV0ZW9fYW5uX21lYW4kdmFydmVfeWVhcltpXSAmIG1tIDw9IDUgJiBtbSA+PSAzKVssIDldKQ0KICBtZXRlb19hbm5fbWVhbiRUZW1wX0pKQVtpXSA8LSBtZWFuKHN1YnNldC5kYXRhLmZyYW1lKEtldF9tZXRlbywgeXkgPT0gbWV0ZW9fYW5uX21lYW4kdmFydmVfeWVhcltpXSAmIG1tIDw9IDggJiBtbSA+PSA2KVssIDldKQ0KICBtZXRlb19hbm5fbWVhbiRUZW1wX1NPTltpXSA8LSBtZWFuKHN1YnNldC5kYXRhLmZyYW1lKEtldF9tZXRlbywgeXkgPT0gbWV0ZW9fYW5uX21lYW4kdmFydmVfeWVhcltpXSAmIG1tIDw9IDExICYgbW0gPj0gOSlbLCA5XSkNCiAgbWV0ZW9fYW5uX21lYW4kVGVtcF9NQU1KSkFbaV0gPC0gbWVhbihzdWJzZXQuZGF0YS5mcmFtZShLZXRfbWV0ZW8sIHl5ID09IG1ldGVvX2Fubl9tZWFuJHZhcnZlX3llYXJbaV0gJiBtbSA8PSA4ICYgbW0gPj0gMylbLCA5XSkNCiAgRCA8LSBhcy5kYXRhLmZyYW1lKHN1YnNldC5kYXRhLmZyYW1lKEtldF9tZXRlbywgeXkgPT0gbWV0ZW9fYW5uX21lYW4kdmFydmVfeWVhcltpXSAmIG1tID09IDEyKVssIDldKQ0KICBKRiA8LSBhcy5kYXRhLmZyYW1lKHN1YnNldC5kYXRhLmZyYW1lKEtldF9tZXRlbywgeXkgPT0gbWV0ZW9fYW5uX21lYW4kdmFydmVfeWVhcltpICsgMV0gJiBtbSA8PSAyKVssIDldKQ0KICBjb2xuYW1lcyhEKSA8LSAiYSINCiAgY29sbmFtZXMoSkYpIDwtICJhIg0KICBESkYgPC0gcmJpbmQoRCwgSkYpDQogIG1ldGVvX2Fubl9tZWFuJFRlbXBfREpGW2ldIDwtIG1lYW4oREpGJGEpDQoNCiAgbWV0ZW9fYW5uX21lYW4kVGVtcF9NQVJbaV0gPC0gbWVhbihzdWJzZXQuZGF0YS5mcmFtZShLZXRfbWV0ZW8sIHl5ID09IG1ldGVvX2Fubl9tZWFuJHZhcnZlX3llYXJbaV0gJiBtbSA9PSAzKVssIDldKQ0KICBtZXRlb19hbm5fbWVhbiRUZW1wX0FQUltpXSA8LSBtZWFuKHN1YnNldC5kYXRhLmZyYW1lKEtldF9tZXRlbywgeXkgPT0gbWV0ZW9fYW5uX21lYW4kdmFydmVfeWVhcltpXSAmIG1tID09IDQpWywgOV0pDQogIG1ldGVvX2Fubl9tZWFuJFRlbXBfTUFZW2ldIDwtIG1lYW4oc3Vic2V0LmRhdGEuZnJhbWUoS2V0X21ldGVvLCB5eSA9PSBtZXRlb19hbm5fbWVhbiR2YXJ2ZV95ZWFyW2ldICYgbW0gPT0gNSlbLCA5XSkNCiAgbWV0ZW9fYW5uX21lYW4kVGVtcF9KVU5baV0gPC0gbWVhbihzdWJzZXQuZGF0YS5mcmFtZShLZXRfbWV0ZW8sIHl5ID09IG1ldGVvX2Fubl9tZWFuJHZhcnZlX3llYXJbaV0gJiBtbSA9PSA2KVssIDldKQ0KICBtZXRlb19hbm5fbWVhbiRUZW1wX0pVTFtpXSA8LSBtZWFuKHN1YnNldC5kYXRhLmZyYW1lKEtldF9tZXRlbywgeXkgPT0gbWV0ZW9fYW5uX21lYW4kdmFydmVfeWVhcltpXSAmIG1tID09IDcpWywgOV0pDQogIG1ldGVvX2Fubl9tZWFuJFRlbXBfQVVHW2ldIDwtIG1lYW4oc3Vic2V0LmRhdGEuZnJhbWUoS2V0X21ldGVvLCB5eSA9PSBtZXRlb19hbm5fbWVhbiR2YXJ2ZV95ZWFyW2ldICYgbW0gPT0gOClbLCA5XSkNCiAgbWV0ZW9fYW5uX21lYW4kVGVtcF9TRVBbaV0gPC0gbWVhbihzdWJzZXQuZGF0YS5mcmFtZShLZXRfbWV0ZW8sIHl5ID09IG1ldGVvX2Fubl9tZWFuJHZhcnZlX3llYXJbaV0gJiBtbSA9PSA5KVssIDldKQ0KICBtZXRlb19hbm5fbWVhbiRUZW1wX09DVFtpXSA8LSBtZWFuKHN1YnNldC5kYXRhLmZyYW1lKEtldF9tZXRlbywgeXkgPT0gbWV0ZW9fYW5uX21lYW4kdmFydmVfeWVhcltpXSAmIG1tID09IDEwKVssIDldKQ0KICBtZXRlb19hbm5fbWVhbiRUZW1wX05PVltpXSA8LSBtZWFuKHN1YnNldC5kYXRhLmZyYW1lKEtldF9tZXRlbywgeXkgPT0gbWV0ZW9fYW5uX21lYW4kdmFydmVfeWVhcltpXSAmIG1tID09IDExKVssIDldKQ0KICBtZXRlb19hbm5fbWVhbiRUZW1wX0RFQ1tpXSA8LSBtZWFuKHN1YnNldC5kYXRhLmZyYW1lKEtldF9tZXRlbywgeXkgPT0gbWV0ZW9fYW5uX21lYW4kdmFydmVfeWVhcltpXSAmIG1tID09IDEyKVssIDldKQ0KICBtZXRlb19hbm5fbWVhbiRUZW1wX0pBTl9MQUcxW2ldIDwtIG1lYW4oc3Vic2V0LmRhdGEuZnJhbWUoS2V0X21ldGVvLCB5eSA9PSBtZXRlb19hbm5fbWVhbiR2YXJ2ZV95ZWFyW2ldICsgMSAmIG1tID09IDEpWywgOV0pDQogIG1ldGVvX2Fubl9tZWFuJFRlbXBfRkVCX0xBRzFbaV0gPC0gbWVhbihzdWJzZXQuZGF0YS5mcmFtZShLZXRfbWV0ZW8sIHl5ID09IG1ldGVvX2Fubl9tZWFuJHZhcnZlX3llYXJbaV0gKyAxICYgbW0gPT0gMilbLCA5XSkNCiAgbWV0ZW9fYW5uX21lYW4kVGVtcF9NQVJfTEFHMVtpXSA8LSBtZWFuKHN1YnNldC5kYXRhLmZyYW1lKEtldF9tZXRlbywgeXkgPT0gbWV0ZW9fYW5uX21lYW4kdmFydmVfeWVhcltpXSArIDEgJiBtbSA9PSAzKVssIDldKQ0KICBtZXRlb19hbm5fbWVhbiRUZW1wX0FQUl9MQUcxW2ldIDwtIG1lYW4oc3Vic2V0LmRhdGEuZnJhbWUoS2V0X21ldGVvLCB5eSA9PSBtZXRlb19hbm5fbWVhbiR2YXJ2ZV95ZWFyW2ldICsgMSAmIG1tID09IDQpWywgOV0pDQogIG1ldGVvX2Fubl9tZWFuJFRlbXBfTUFZX0xBRzFbaV0gPC0gbWVhbihzdWJzZXQuZGF0YS5mcmFtZShLZXRfbWV0ZW8sIHl5ID09IG1ldGVvX2Fubl9tZWFuJHZhcnZlX3llYXJbaV0gKyAxICYgbW0gPT0gNSlbLCA5XSkNCg0KDQogIG1ldGVvX2Fubl9tZWFuJHA5MF9QcmVjaXBfTUFNW2ldIDwtIHN0YXRzOjpxdWFudGlsZSgoc3Vic2V0KEtldF9tZXRlbywgeXkgPT0gbWV0ZW9fYW5uX21lYW4kdmFydmVfeWVhcltpXSAmIG1tIDw9IDUgJiBtbSA+PSAzKVssIDExXSksIHByb2JzID0gMC45KQ0KICBtZXRlb19hbm5fbWVhbiRwOTBfUHJlY2lwX0pKQVtpXSA8LSBxdWFudGlsZSgoc3Vic2V0LmRhdGEuZnJhbWUoS2V0X21ldGVvLCB5eSA9PSBtZXRlb19hbm5fbWVhbiR2YXJ2ZV95ZWFyW2ldICYgbW0gPD0gOCAmIG1tID49IDYpWywgMTFdKSwgMC45KQ0KICBtZXRlb19hbm5fbWVhbiRwOTBfUHJlY2lwX1NPTltpXSA8LSBxdWFudGlsZSgoc3Vic2V0LmRhdGEuZnJhbWUoS2V0X21ldGVvLCB5eSA9PSBtZXRlb19hbm5fbWVhbiR2YXJ2ZV95ZWFyW2ldICYgbW0gPD0gMTEgJiBtbSA+PSA5KVssIDExXSksIDAuOSkNCiAgRCA8LSBhcy5kYXRhLmZyYW1lKHN1YnNldC5kYXRhLmZyYW1lKEtldF9tZXRlbywgeXkgPT0gbWV0ZW9fYW5uX21lYW4kdmFydmVfeWVhcltpXSAmIG1tID09IDEyKVssIDExXSkNCiAgSkYgPC0gYXMuZGF0YS5mcmFtZShzdWJzZXQuZGF0YS5mcmFtZShLZXRfbWV0ZW8sIHl5ID09IG1ldGVvX2Fubl9tZWFuJHZhcnZlX3llYXJbaSArIDFdICYgbW0gPD0gMilbLCAxMV0pDQogIGNvbG5hbWVzKEQpIDwtICJhIg0KICBjb2xuYW1lcyhKRikgPC0gImEiDQogIERKRiA8LSByYmluZChELCBKRikNCiAgbWV0ZW9fYW5uX21lYW4kcDkwX1ByZWNpcF9ESkZbaV0gPC0gcXVhbnRpbGUoREpGJGEsIDAuOSkNCg0KICBtZXRlb19hbm5fbWVhbiRwOTBfUHJlY2lwX01BUltpXSA8LSBzdGF0czo6cXVhbnRpbGUoc3Vic2V0LmRhdGEuZnJhbWUoS2V0X21ldGVvLCB5eSA9PSBtZXRlb19hbm5fbWVhbiR2YXJ2ZV95ZWFyW2ldICYgbW0gPT0gMylbLCAxMV0sIHByb2JzID0gMC45KQ0KICBtZXRlb19hbm5fbWVhbiRwOTBfUHJlY2lwX0FQUltpXSA8LSBzdGF0czo6cXVhbnRpbGUoc3Vic2V0LmRhdGEuZnJhbWUoS2V0X21ldGVvLCB5eSA9PSBtZXRlb19hbm5fbWVhbiR2YXJ2ZV95ZWFyW2ldICYgbW0gPT0gNClbLCAxMV0sIHByb2JzID0gMC45KQ0KICBtZXRlb19hbm5fbWVhbiRwOTBfUHJlY2lwX01BWVtpXSA8LSBzdGF0czo6cXVhbnRpbGUoc3Vic2V0LmRhdGEuZnJhbWUoS2V0X21ldGVvLCB5eSA9PSBtZXRlb19hbm5fbWVhbiR2YXJ2ZV95ZWFyW2ldICYgbW0gPT0gNSlbLCAxMV0sIHByb2JzID0gMC45KQ0KICBtZXRlb19hbm5fbWVhbiRwOTBfUHJlY2lwX0pVTltpXSA8LSBzdGF0czo6cXVhbnRpbGUoc3Vic2V0LmRhdGEuZnJhbWUoS2V0X21ldGVvLCB5eSA9PSBtZXRlb19hbm5fbWVhbiR2YXJ2ZV95ZWFyW2ldICYgbW0gPT0gNilbLCAxMV0sIHByb2JzID0gMC45KQ0KICBtZXRlb19hbm5fbWVhbiRwOTBfUHJlY2lwX0pVTFtpXSA8LSBzdGF0czo6cXVhbnRpbGUoc3Vic2V0LmRhdGEuZnJhbWUoS2V0X21ldGVvLCB5eSA9PSBtZXRlb19hbm5fbWVhbiR2YXJ2ZV95ZWFyW2ldICYgbW0gPT0gNylbLCAxMV0sIHByb2JzID0gMC45KQ0KICBtZXRlb19hbm5fbWVhbiRwOTBfUHJlY2lwX0FVR1tpXSA8LSBzdGF0czo6cXVhbnRpbGUoc3Vic2V0LmRhdGEuZnJhbWUoS2V0X21ldGVvLCB5eSA9PSBtZXRlb19hbm5fbWVhbiR2YXJ2ZV95ZWFyW2ldICYgbW0gPT0gOClbLCAxMV0sIHByb2JzID0gMC45KQ0KICBtZXRlb19hbm5fbWVhbiRwOTBfUHJlY2lwX1NFUFtpXSA8LSBzdGF0czo6cXVhbnRpbGUoc3Vic2V0LmRhdGEuZnJhbWUoS2V0X21ldGVvLCB5eSA9PSBtZXRlb19hbm5fbWVhbiR2YXJ2ZV95ZWFyW2ldICYgbW0gPT0gOSlbLCAxMV0sIHByb2JzID0gMC45KQ0KICBtZXRlb19hbm5fbWVhbiRwOTBfUHJlY2lwX09DVFtpXSA8LSBzdGF0czo6cXVhbnRpbGUoc3Vic2V0LmRhdGEuZnJhbWUoS2V0X21ldGVvLCB5eSA9PSBtZXRlb19hbm5fbWVhbiR2YXJ2ZV95ZWFyW2ldICYgbW0gPT0gMTApWywgMTFdLCBwcm9icyA9IDAuOSkNCiAgbWV0ZW9fYW5uX21lYW4kcDkwX1ByZWNpcF9OT1ZbaV0gPC0gc3RhdHM6OnF1YW50aWxlKHN1YnNldC5kYXRhLmZyYW1lKEtldF9tZXRlbywgeXkgPT0gbWV0ZW9fYW5uX21lYW4kdmFydmVfeWVhcltpXSAmIG1tID09IDExKVssIDExXSwgcHJvYnMgPSAwLjkpDQogIG1ldGVvX2Fubl9tZWFuJHA5MF9QcmVjaXBfREVDW2ldIDwtIHN0YXRzOjpxdWFudGlsZShzdWJzZXQuZGF0YS5mcmFtZShLZXRfbWV0ZW8sIHl5ID09IG1ldGVvX2Fubl9tZWFuJHZhcnZlX3llYXJbaV0gJiBtbSA9PSAxMilbLCAxMV0sIHByb2JzID0gMC45KQ0KICBtZXRlb19hbm5fbWVhbiRwOTBfUHJlY2lwX0pBTl9MQUcxW2ldIDwtIHN0YXRzOjpxdWFudGlsZShzdWJzZXQuZGF0YS5mcmFtZShLZXRfbWV0ZW8sIHl5ID09IG1ldGVvX2Fubl9tZWFuJHZhcnZlX3llYXJbaV0gKyAxICYgbW0gPT0gMSlbLCAxMV0sIHByb2JzID0gMC45KQ0KICBtZXRlb19hbm5fbWVhbiRwOTBfUHJlY2lwX0ZFQl9MQUcxW2ldIDwtIHN0YXRzOjpxdWFudGlsZShzdWJzZXQuZGF0YS5mcmFtZShLZXRfbWV0ZW8sIHl5ID09IG1ldGVvX2Fubl9tZWFuJHZhcnZlX3llYXJbaV0gKyAxICYgbW0gPT0gMilbLCAxMV0sIHByb2JzID0gMC45KQ0KICBtZXRlb19hbm5fbWVhbiRwOTBfUHJlY2lwX01BUl9MQUcxW2ldIDwtIHN0YXRzOjpxdWFudGlsZShzdWJzZXQuZGF0YS5mcmFtZShLZXRfbWV0ZW8sIHl5ID09IG1ldGVvX2Fubl9tZWFuJHZhcnZlX3llYXJbaV0gKyAxICYgbW0gPT0gMylbLCAxMV0sIHByb2JzID0gMC45KQ0KICBtZXRlb19hbm5fbWVhbiRwOTBfUHJlY2lwX0FQUl9MQUcxW2ldIDwtIHN0YXRzOjpxdWFudGlsZShzdWJzZXQuZGF0YS5mcmFtZShLZXRfbWV0ZW8sIHl5ID09IG1ldGVvX2Fubl9tZWFuJHZhcnZlX3llYXJbaV0gKyAxICYgbW0gPT0gNClbLCAxMV0sIHByb2JzID0gMC45KQ0KICBtZXRlb19hbm5fbWVhbiRwOTBfUHJlY2lwX01BWV9MQUcxW2ldIDwtIHN0YXRzOjpxdWFudGlsZShzdWJzZXQuZGF0YS5mcmFtZShLZXRfbWV0ZW8sIHl5ID09IG1ldGVvX2Fubl9tZWFuJHZhcnZlX3llYXJbaV0gKyAxICYgbW0gPT0gNSlbLCAxMV0sIHByb2JzID0gMC45KQ0KDQoNCiAgbWV0ZW9fYW5uX21lYW4kcDkwX1dpbmRfTUFNW2ldIDwtIHF1YW50aWxlKChzdWJzZXQuZGF0YS5mcmFtZShLZXRfbWV0ZW8sIHl5ID09IG1ldGVvX2Fubl9tZWFuJHZhcnZlX3llYXJbaV0gJiBtbSA8PSA1ICYgbW0gPj0gMykkd3NfbWVhbl9kYWlseSksIDAuOSkNCiAgbWV0ZW9fYW5uX21lYW4kcDkwX1dpbmRfSkpBW2ldIDwtIHF1YW50aWxlKChzdWJzZXQuZGF0YS5mcmFtZShLZXRfbWV0ZW8sIHl5ID09IG1ldGVvX2Fubl9tZWFuJHZhcnZlX3llYXJbaV0gJiBtbSA8PSA4ICYgbW0gPj0gNikkd3NfbWVhbl9kYWlseSksIDAuOSkNCiAgbWV0ZW9fYW5uX21lYW4kcDkwX1dpbmRfU09OW2ldIDwtIHF1YW50aWxlKChzdWJzZXQuZGF0YS5mcmFtZShLZXRfbWV0ZW8sIHl5ID09IG1ldGVvX2Fubl9tZWFuJHZhcnZlX3llYXJbaV0gJiBtbSA8PSAxMSAmIG1tID49IDkpJHdzX21lYW5fZGFpbHkpLCAwLjkpDQogIEQgPC0gYXMuZGF0YS5mcmFtZShzdWJzZXQuZGF0YS5mcmFtZShLZXRfbWV0ZW8sIHl5ID09IG1ldGVvX2Fubl9tZWFuJHZhcnZlX3llYXJbaV0gJiBtbSA9PSAxMikkd3NfbWVhbl9kYWlseSkNCiAgSkYgPC0gYXMuZGF0YS5mcmFtZShzdWJzZXQuZGF0YS5mcmFtZShLZXRfbWV0ZW8sIHl5ID09IG1ldGVvX2Fubl9tZWFuJHZhcnZlX3llYXJbaSArIDFdICYgbW0gPD0gMikkd3NfbWVhbl9kYWlseSkNCiAgY29sbmFtZXMoRCkgPC0gImEiDQogIGNvbG5hbWVzKEpGKSA8LSAiYSINCiAgREpGIDwtIHJiaW5kKEQsIEpGKQ0KICBtZXRlb19hbm5fbWVhbiRwOTBfV2luZF9ESkZbaV0gPC0gcXVhbnRpbGUoREpGJGEsIDAuOSkNCiAgbWV0ZW9fYW5uX21lYW4kTUFSX0RFQ19XaW5kX0RheXNbaV0gPC0gbnJvdyhzdWJzZXQuZGF0YS5mcmFtZShLZXRfbWV0ZW8sIHl5ID09IG1ldGVvX2Fubl9tZWFuJHZhcnZlX3llYXJbaV0gJiB3c19tZWFuX2RhaWx5ID49IHd0ICYgbW0gPj0gMykpDQoNCiAgbWV0ZW9fYW5uX21lYW4kcDkwX1dpbmRfTUFSW2ldIDwtIHN0YXRzOjpxdWFudGlsZShzdWJzZXQuZGF0YS5mcmFtZShLZXRfbWV0ZW8sIHl5ID09IG1ldGVvX2Fubl9tZWFuJHZhcnZlX3llYXJbaV0gJiBtbSA9PSAzKVssIDM5XSwgcHJvYnMgPSAwLjkpDQogIG1ldGVvX2Fubl9tZWFuJHA5MF9XaW5kX0FQUltpXSA8LSBzdGF0czo6cXVhbnRpbGUoc3Vic2V0LmRhdGEuZnJhbWUoS2V0X21ldGVvLCB5eSA9PSBtZXRlb19hbm5fbWVhbiR2YXJ2ZV95ZWFyW2ldICYgbW0gPT0gNClbLCAzOV0sIHByb2JzID0gMC45KQ0KICBtZXRlb19hbm5fbWVhbiRwOTBfV2luZF9NQVlbaV0gPC0gc3RhdHM6OnF1YW50aWxlKHN1YnNldC5kYXRhLmZyYW1lKEtldF9tZXRlbywgeXkgPT0gbWV0ZW9fYW5uX21lYW4kdmFydmVfeWVhcltpXSAmIG1tID09IDUpWywgMzldLCBwcm9icyA9IDAuOSkNCiAgbWV0ZW9fYW5uX21lYW4kcDkwX1dpbmRfSlVOW2ldIDwtIHN0YXRzOjpxdWFudGlsZShzdWJzZXQuZGF0YS5mcmFtZShLZXRfbWV0ZW8sIHl5ID09IG1ldGVvX2Fubl9tZWFuJHZhcnZlX3llYXJbaV0gJiBtbSA9PSA2KVssIDM5XSwgcHJvYnMgPSAwLjkpDQogIG1ldGVvX2Fubl9tZWFuJHA5MF9XaW5kX0pVTFtpXSA8LSBzdGF0czo6cXVhbnRpbGUoc3Vic2V0LmRhdGEuZnJhbWUoS2V0X21ldGVvLCB5eSA9PSBtZXRlb19hbm5fbWVhbiR2YXJ2ZV95ZWFyW2ldICYgbW0gPT0gNylbLCAzOV0sIHByb2JzID0gMC45KQ0KICBtZXRlb19hbm5fbWVhbiRwOTBfV2luZF9BVUdbaV0gPC0gc3RhdHM6OnF1YW50aWxlKHN1YnNldC5kYXRhLmZyYW1lKEtldF9tZXRlbywgeXkgPT0gbWV0ZW9fYW5uX21lYW4kdmFydmVfeWVhcltpXSAmIG1tID09IDgpWywgMzldLCBwcm9icyA9IDAuOSkNCiAgbWV0ZW9fYW5uX21lYW4kcDkwX1dpbmRfU0VQW2ldIDwtIHN0YXRzOjpxdWFudGlsZShzdWJzZXQuZGF0YS5mcmFtZShLZXRfbWV0ZW8sIHl5ID09IG1ldGVvX2Fubl9tZWFuJHZhcnZlX3llYXJbaV0gJiBtbSA9PSA5KVssIDM5XSwgcHJvYnMgPSAwLjkpDQogIG1ldGVvX2Fubl9tZWFuJHA5MF9XaW5kX09DVFtpXSA8LSBzdGF0czo6cXVhbnRpbGUoc3Vic2V0LmRhdGEuZnJhbWUoS2V0X21ldGVvLCB5eSA9PSBtZXRlb19hbm5fbWVhbiR2YXJ2ZV95ZWFyW2ldICYgbW0gPT0gMTApWywgMzldLCBwcm9icyA9IDAuOSkNCiAgbWV0ZW9fYW5uX21lYW4kcDkwX1dpbmRfTk9WW2ldIDwtIHN0YXRzOjpxdWFudGlsZShzdWJzZXQuZGF0YS5mcmFtZShLZXRfbWV0ZW8sIHl5ID09IG1ldGVvX2Fubl9tZWFuJHZhcnZlX3llYXJbaV0gJiBtbSA9PSAxMSlbLCAzOV0sIHByb2JzID0gMC45KQ0KICBtZXRlb19hbm5fbWVhbiRwOTBfV2luZF9ERUNbaV0gPC0gc3RhdHM6OnF1YW50aWxlKHN1YnNldC5kYXRhLmZyYW1lKEtldF9tZXRlbywgeXkgPT0gbWV0ZW9fYW5uX21lYW4kdmFydmVfeWVhcltpXSAmIG1tID09IDEyKVssIDM5XSwgcHJvYnMgPSAwLjkpDQogIG1ldGVvX2Fubl9tZWFuJHA5MF9XaW5kX0pBTl9MQUcxW2ldIDwtIHN0YXRzOjpxdWFudGlsZShzdWJzZXQuZGF0YS5mcmFtZShLZXRfbWV0ZW8sIHl5ID09IG1ldGVvX2Fubl9tZWFuJHZhcnZlX3llYXJbaV0gKyAxICYgbW0gPT0gMSlbLCAzOV0sIHByb2JzID0gMC45KQ0KICBtZXRlb19hbm5fbWVhbiRwOTBfV2luZF9GRUJfTEFHMVtpXSA8LSBzdGF0czo6cXVhbnRpbGUoc3Vic2V0LmRhdGEuZnJhbWUoS2V0X21ldGVvLCB5eSA9PSBtZXRlb19hbm5fbWVhbiR2YXJ2ZV95ZWFyW2ldICsgMSAmIG1tID09IDIpWywgMzldLCBwcm9icyA9IDAuOSkNCiAgbWV0ZW9fYW5uX21lYW4kcDkwX1dpbmRfTUFSX0xBRzFbaV0gPC0gc3RhdHM6OnF1YW50aWxlKHN1YnNldC5kYXRhLmZyYW1lKEtldF9tZXRlbywgeXkgPT0gbWV0ZW9fYW5uX21lYW4kdmFydmVfeWVhcltpXSArIDEgJiBtbSA9PSAzKVssIDM5XSwgcHJvYnMgPSAwLjkpDQogIG1ldGVvX2Fubl9tZWFuJHA5MF9XaW5kX0FQUl9MQUcxW2ldIDwtIHN0YXRzOjpxdWFudGlsZShzdWJzZXQuZGF0YS5mcmFtZShLZXRfbWV0ZW8sIHl5ID09IG1ldGVvX2Fubl9tZWFuJHZhcnZlX3llYXJbaV0gKyAxICYgbW0gPT0gNClbLCAzOV0sIHByb2JzID0gMC45KQ0KICBtZXRlb19hbm5fbWVhbiRwOTBfV2luZF9NQVlfTEFHMVtpXSA8LSBzdGF0czo6cXVhbnRpbGUoc3Vic2V0LmRhdGEuZnJhbWUoS2V0X21ldGVvLCB5eSA9PSBtZXRlb19hbm5fbWVhbiR2YXJ2ZV95ZWFyW2ldICsgMSAmIG1tID09IDUpWywgMzldLCBwcm9icyA9IDAuOSkNCn0NCg0KIyBjYWxjdWxhdGluZyBNQU1fbGFnMSAoc3ByaW5nIG9mIHllYXIgYWZ0ZXIgdmFydmUgeWVhciwgdGhpcyBtYXkgYmUgaW5jbHVkZWQgaW4gc29tZSB2YXJ2ZXMpDQptZXRlb19hbm5fbWVhbiRUZW1wX01BTV9sYWcxIDwtIGMobWV0ZW9fYW5uX21lYW4kVGVtcF9NQU1bMjo1NF0sIE5BKQ0KbWV0ZW9fYW5uX21lYW4kcDkwX1dpbmRfTUFNX2xhZzEgPC0gYyhtZXRlb19hbm5fbWVhbiRwOTBfV2luZF9NQU1bMjo1NF0sIE5BKQ0KbWV0ZW9fYW5uX21lYW4kcDkwX1ByZWNpcF9NQU1fbGFnMSA8LSBjKG1ldGVvX2Fubl9tZWFuJHA5MF9QcmVjaXBfTUFNWzI6NTRdLCBOQSkNCg0KIyBzdWJzdGl0dXRpbmcgbWVhbiB2YWx1ZXMgaW4geWVhcnMgd2l0aCBtaXNzaW5nIHdpbmQgZGF0YQ0KbWV0ZW9fYW5uX21lYW5bMjgsIGMoMTg6MjEsIDU4OjY2KV0gPC0gY29sTWVhbnMobmEub21pdChtZXRlb19hbm5fbWVhbltjKC0yOCwgLTI5KSwgXSkpW2MoMTg6MjEsIDU4OjY2KV0NCm1ldGVvX2Fubl9tZWFuWzI5LCBjKDE2OjE4LCAyMSwgNTI6NjApXSA8LSBjb2xNZWFucyhuYS5vbWl0KG1ldGVvX2Fubl9tZWFuW2MoLTI4LCAtMjkpLCBdKSlbYygxNjoxOCwgMjEsIDUyOjYwKV0NCg0KIyBCb3hwbG90IG9mIHNlYXNvbmFsIHdlYXRoZXIgYnkgdmFydmUgdHlwZQ0KbWV0ZW9fY2x1c3QgPC0gYXMuZGF0YS5mcmFtZShjYmluZChteWNsWzU0OjEsIDFdLCBtZXRlb19hbm5fbWVhblssIDFdLCBzY2FsZShtZXRlb19hbm5fbWVhbltjKDU6OSwgMTE6MjApXSkpKQ0KY29sbmFtZXMobWV0ZW9fY2x1c3QpW2MoMSwgMildIDwtIGMoIkdyb3VwIiwgIlllYXIiKQ0KbWV0ZW9fY2x1c3RfcGl2IDwtIHRpZHlyOjpwaXZvdF9sb25nZXIobWV0ZW9fY2x1c3QsIGNvbHMgPSBjb2xuYW1lcyhtZXRlb19jbHVzdClbYygzOjE3KV0sIG5hbWVzX3RvID0gInZhcmlhYmxlIikNCm1ldGVvX2NsdXN0X3BpdiR2YXJpYWJsZSA8LSByZXAoYygiTUFNIiwgIkpKQSIsICJTT04iLCAiREpGIiwgIk1BTV9sYWcxIiksIDU0ICogMykNCm1ldGVvX2NsdXN0X3BpdiR2YXJpYWJsZSA8LSBmYWN0b3IobWV0ZW9fY2x1c3RfcGl2JHZhcmlhYmxlLCBsZXZlbHMgPSBjKCJNQU0iLCAiSkpBIiwgIlNPTiIsICJESkYiLCAiTUFNX2xhZzEiKSkNCm1ldGVvX2NsdXN0X3BpdiRtZXRfdmFyIDwtIHJlcChjKCJ0ZW1wIiwgInRlbXAiLCAidGVtcCIsICJ0ZW1wIiwgInRlbXAiLCAicDkwX3ByZWNpcCIsICJwOTBfcHJlY2lwIiwgInA5MF9wcmVjaXAiLCAicDkwX3ByZWNpcCIsICJwOTBfcHJlY2lwIiwgInA5MF93aW5kIiwgInA5MF93aW5kIiwgInA5MF93aW5kIiwgInA5MF93aW5kIiwgInA5MF93aW5kIiksIDU0KQ0KY2JQYWxldHRlIDwtIGMoIiNENTVFMDAiLCAiIzU2QjRFOSIsICIjMDA5RTczIiwgIiNGMEU0NDIiKQ0KZ3JvdXBzX3Bsb3QyIDwtIGdncGxvdCgpICsNCiAgZ2VvbV9ib3hwbG90KGRhdGEgPSBtZXRlb19jbHVzdF9waXYsIGFlcyh4ID0gdmFyaWFibGUsIHkgPSB2YWx1ZSwgZmlsbCA9IGZhY3RvcihHcm91cCkpLCBsd2QgPSAwLjMsIG91dGxpZXIuc2l6ZSA9IDAuMikgKw0KICB4bGFiKCJTZWFzb24iKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNiUGFsZXR0ZSkgKw0KICB5bGFiKCJaLXNjb3JlIikgKw0KICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksIHBhbmVsLmdyaWQgPSBlbGVtZW50X2JsYW5rKCkpICsNCiAgZmFjZXRfZ3JpZChyb3dzID0gdmFycyhtZXRfdmFyKSkNCmdyb3Vwc19wbG90MiArIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gImRhc2hlZCIpDQpgYGANCg0KQXNzZXNzaW5nIG5vcm1hbGl0eSAtIHNvbWUgdmFyaWFibGVzIHNob3cgcG9zaXRpdmUgc2tldywgaG93ZXZlciBBTk9WQSBpcyBub3Qgc3Ryb25nbHkgc2Vuc2l0aXZlIHRvIG5vcm1hbGl0eSBhc3N1bXB0aW9uLCBzbyB3ZSBwcm9jZWVkDQoNCmBgYHtyIG5vcm1hbCwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTAsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIyBhc3Nlc3Npbmcgbm9ybWFsaXR5DQpnZ3Bsb3QoZGF0YSA9IG1ldGVvX2NsdXN0X3BpdiwgYWVzKHggPSB2YWx1ZSkpICsNCiAgc3RhdF9kZW5zaXR5KCkgKw0KICBmYWNldF9ncmlkKHJvd3MgPSB2YXJzKG1ldF92YXIpLCBjb2xzID0gdmFycyh2YXJpYWJsZSksIHNjYWxlcyA9ICJmcmVlX3kiKQ0KDQp5IDwtIGFzLmRhdGEuZnJhbWUobWV0ZW9fY2x1c3RbLCBjKDM6MTcpXSkNCg0KIlNoYXBpcm8tV2lsa3MgdGVzdCINCnNoYXBpcm9fdGVzdF9kZiA8LSBmdW5jdGlvbihkZiwgYm9uZiA9IFRSVUUsIGFscGhhID0gMC4wNSkgew0KICBsIDwtIGxhcHBseShkZiwgc2hhcGlyby50ZXN0KQ0KICBzIDwtIGRvLmNhbGwoImMiLCBsYXBwbHkobCwgIltbIiwgMSkpDQogIHAgPC0gZG8uY2FsbCgiYyIsIGxhcHBseShsLCAiW1siLCAyKSkNCiAgaWYgKGJvbmYgPT0gVFJVRSkgew0KICAgIHNpZyA8LSBpZmVsc2UocCA+IGFscGhhIC8gbGVuZ3RoKGwpLCAiSDAiLCAiSGEiKQ0KICB9IGVsc2Ugew0KICAgIHNpZyA8LSBpZmVsc2UocCA+IGFscGhhLCAiSDAiLCAiSGEiKQ0KICB9DQogIHJldHVybihsaXN0KA0KICAgIHN0YXRpc3RpYyA9IHMsDQogICAgcC52YWx1ZSA9IHAsDQogICAgc2lnbmlmaWNhbmNlID0gc2lnLA0KICAgIG1ldGhvZCA9IGlmZWxzZShib25mID09IFRSVUUsICJTaGFwaXJvLVdpbGtzIHRlc3Qgd2l0aCBCb25mZXJyb25pIENvcnJlY3Rpb24iLA0KICAgICAgIlNoYXBpcm8tV2lsa3MgdGVzdCB3aXRob3V0IEJvbmZlcnJvbmkgQ29ycmVjdGlvbiINCiAgICApDQogICkpDQp9DQoNCnNoYXBpcm9fdGVzdF9kZih5LCBib25mID0gVFJVRSkNCmBgYA0KDQpBbmFseXNpcyBvZiB2YXJpYW5jZS4gTnVsbCBIeXBvdGhlc2lzOiB5ZWFycyBhc3NvY2lhdGVkIHdpdGggdGhlIGZvdXIgdmFydmUgdHlwZXMgZXhwZXJpZW5jZWQgdGhlIHNhbWUgbWV0ZW9yb2xvZ2ljYWwgY29uZGl0aW9ucw0KTm90ZTogc2lnbmlmaWNhbmNlIGNvZGUgc3ltYm9scyBhcmUgZGlmZmVyZW50IGhlcmUgdGhhbiBpbiB0aGUgbWFudXNjcmlwdA0KDQpgYGB7ciBBTk9WQSwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9NiwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMgQW5hbHlzaXMgb2YgdmFyaWFuY2UNCnkgPC0gYXMubWF0cml4KG1ldGVvX2NsdXN0WywgYygzOjE3KV0pDQptYW5vdmExIDwtIG1hbm92YSh5IH4gYXMuZmFjdG9yKG1ldGVvX2NsdXN0JEdyb3VwKSkNCiJtdWx0aXZhcmlhdGUgYW5hbHlzaXMgb2YgdmFyaWFuY2UiDQpzdW1tYXJ5KG1hbm92YTEpDQoiYW5hbHlzaXMgb2YgdmFyaWFuY2UgZm9yIGVhY2ggbWV0ZW8gdmFyaWFibGUiDQpzdW1tYXJ5LmFvdihtYW5vdmExKQ0KYGBgDQoNCiMjIENvcnJlbGF0aW9ucyBiZXR3ZWVuIG1ldGVvcm9sb2dpY2FsIGRhdGEgYW5kIHNlZGltZW50YXJ5IGRhdGENCg0KQXNzZXNzaW5nIG5vcm1hbGl0eSAtIHNvbWUgdmFyaWFibGVzIGFyZSBub24tbm9ybWFsLCBidXQgd2UgcHJvY2VlZCB3aXRoIGNvcnJlbGF0aW9uIGFuYWx5c2lzLiBFbXBoYXNpcyBpcyBvbiB1bmRlcnN0YW5kaW5nIHJlbGF0aW9uc2hpcHMsIG5vdCBzaWduaWZpY2FuY2UgdGVzdHMuIFZhcmlhYmxlcyB3aXRoIGhpZ2hlc3QgY29ycmVsYXRpb25zIGFyZSBub3JtYWxseSBkaXN0cmlidXRlZC4NCg0KYGBge3IgcHJveHkgZGlzdHJpYnV0aW9uLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xMCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMgY2FsY3VsYXRlZCBhbm51YWwgbWVhbnMgZm9yIGdlb2NoZW1pY2FsIGRhdGENCnByb3h5X2Fubl9tZWFuIDwtIGFnZ3JlZ2F0ZShIaVJlc19mdWxsWywgYyg0OjExLCAxMywgMTQpXSwgbGlzdChIaVJlc19mdWxsJHZhcnZlX3llYXIpLCBtZWFuKQ0KY29sbmFtZXMocHJveHlfYW5uX21lYW4pWzFdIDwtICJ2YXJ2ZV95ZWFyIg0KcHJveHlfYW5uX21lYW4gPC0gcHJveHlfYW5uX21lYW5bcHJveHlfYW5uX21lYW4kdmFydmVfeWVhciA+PSAxOTY2LCBdDQpwcm94eV9hbm5fYWxsIDwtIGNiaW5kKHByb3h5X2Fubl9tZWFuWzI6MTFdLCBDTlNbNTQ6MSwgYygxMSwgMzcsIDM5LCAzOCwgNDEpXSkNCmNvbG5hbWVzKHByb3h5X2Fubl9hbGwpWzExOjE0XSA8LSBjKCJUSUMiLCAiVE9DIiwgIlRDIiwgIlROIikNCg0KcHJveHlfYW5uX2FsbF9waXYgPC0gdGlkeXI6OnBpdm90X2xvbmdlcihwcm94eV9hbm5fYWxsLCBjb2xzID0gY29sbmFtZXMocHJveHlfYW5uX2FsbCksIG5hbWVzX3RvID0gInByb3h5IikNCmdncGxvdChkYXRhID0gcHJveHlfYW5uX2FsbF9waXYsIGFlcyh4ID0gdmFsdWUpKSArDQogIHN0YXRfZGVuc2l0eSgpICsNCiAgZmFjZXRfd3JhcChmYWNldHMgPSAicHJveHkiLCBucm93ID0gMywgc2NhbGVzID0gImZyZWUiKQ0KIlNoYXBpcm8tV2lsa3MgdGVzdCINCnNoYXBpcm9fdGVzdF9kZihwcm94eV9hbm5fYWxsLCBib25mID0gVFJVRSkNCmBgYA0KDQpTZWFzb25hbCBjb3JyZWxhdGlvbnMuIFNlbGVjdGVkIGNvcnJlbGF0aW9ucyBmcm9tIHRoaXMgYW5hbHlzaXMgYXJlIGRpc3BsYXllZCBpbiBUYWJsZSAxIG9mIGFzc29jaWF0ZWQgbWFudXNjcmlwdC4NCg0KYGBge3Igc2Vhc29uYWwgY29ycmVsYXRpb25zLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD02LCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KbWV0ZW9fc3ViMSA8LSBtZXRlb19hbm5fbWVhblssIGMoNToyMSldICMgc2Vhc29uYWwgbWV0ZW8gZGF0YQ0KbWV0ZW9fc3ViMVs1NCwgYyg1LCAxMSwgMTYpXSA8LSBjb2xNZWFucyhtZXRlb19zdWIxWy01NCwgXSlbYyg1LCAxMSwgMTYpXSAjIHJlcGxhY2luZyBtaXNzaW5nIGRhdGEgd2l0aCBtZWFucw0KDQojIFNlYXNvbmFsIGNvcnJlbGF0aW9ucw0KY29yX21hdHJpeF9zZWFzb25hbCA8LSBjb3JiZXR3Mm1hdChtZXRlb19zdWIxLCBwcm94eV9hbm5fYWxsLCB3aGF0ID0gImFsbCIpDQoNCkFSX3Byb3hpZXMgPC0gYWNmKHByb3h5X2Fubl9hbGwsIGxhZyA9IDEsIHBsb3QgPSBGQUxTRSkNCkFSX3Byb3hpZXMgPC0gQVJfcHJveGllcyRhY2YNCg0KQVJfbWV0ZW8gPC0gYWNmKG1ldGVvX3N1YjEsIGxhZyA9IDEsIHBsb3QgPSBGQUxTRSkNCkFSX21ldGVvIDwtIEFSX21ldGVvJGFjZg0KDQphZGpfbiA8LSBtYXRyaXgoLCBucm93ID0gbmNvbChtZXRlb19zdWIxKSwgbmNvbCA9IG5jb2wocHJveHlfYW5uX2FsbCkpDQojIGNhbGN1bGF0ZSBhZGp1c3RlZCBuIHVzaW5nIG1ldGhvZCBvZiBCcmV0aGVydG9uIGV0IGFsLiAoMTk5OSkNCg0KZm9yIChpIGluIDE6bmNvbChtZXRlb19zdWIxKSkgew0KICBmb3IgKGogaW4gMTpuY29sKHByb3h5X2Fubl9hbGwpKSB7DQogICAgYWRqX25baSwgal0gPC0gbnJvdyhwcm94eV9hbm5fYWxsKSAqICgxIC0gQVJfbWV0ZW9bMiwgaSwgaV0gKiBBUl9wcm94aWVzWzIsIGosIGpdKSAvICgxICsgQVJfbWV0ZW9bMiwgaSwgaV0gKiBBUl9wcm94aWVzWzIsIGosIGpdKQ0KICB9DQp9DQphZGpfblthZGpfbiA+IDU0XSA8LSA1NA0KY29sbmFtZXMoYWRqX24pIDwtIGNvbG5hbWVzKHByb3h5X2Fubl9hbGwpDQpyb3duYW1lcyhhZGpfbikgPC0gY29sbmFtZXMobWV0ZW9fc3ViMSkNCg0KcHZhbCA8LSBjb3JyLnAoY29yX21hdHJpeF9zZWFzb25hbCwgbiA9IGFkal9uLCBhZGp1c3QgPSAiZmRyIikkcA0KY29yX21hdHJpeF9zZWFzb25hbCA8LSB0KGNvcl9tYXRyaXhfc2Vhc29uYWwpDQpwdmFsIDwtIHQocHZhbCkNCmNvcnJwbG90KGNvcl9tYXRyaXhfc2Vhc29uYWwsIG1ldGhvZCA9ICJjb2xvciIsIHAubWF0ID0gcHZhbCwgc2lnLmxldmVsID0gYygwLjAxLCAwLjA1LCAwLjEpLCBwY2ggPSBjKCIuIiksIGluc2lnID0gImxhYmVsX3NpZyIpDQpgYGANCg0KQ29ycmVsYXRpb25zIHdpdGggbW9udGhseSBtZXRlbyBkYXRhIGFuZCBmdWxsIGNvcnJlbGF0aW9uIHBsb3QNCg0KYGBge3IgbW9udGhseSBjb3JyZWxhdGlvbnMsIGZpZy5oZWlnaHQ9MTAsIGZpZy53aWR0aD0xMCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCm1ldGVvX3N1YjIgPC0gbWV0ZW9fYW5uX21lYW5bLCAyMjo2Nl0gIyBtb250aGx5IG1ldGVvIGRhdGENCm1ldGVvX3N1YjJbNTQsIGMoMTM6MTUsIDI4OjMwLCA0Mzo0NSldIDwtIGNvbE1lYW5zKG1ldGVvX3N1YjJbLTU0LCBdKVtjKDEzOjE1LCAyODozMCwgNDM6NDUpXSAjIHJlcGxhY2luZyBtaXNzaW5nIGRhdGEgd2l0aCBtZWFucw0KDQpjb3JfbWF0cml4X21vbnRocyA8LSBjb3JiZXR3Mm1hdChwcm94eV9hbm5fYWxsLCBtZXRlb19zdWIyLCB3aGF0ID0gImFsbCIpDQpjb2xuYW1lcyhjb3JfbWF0cml4X21vbnRocykgPC0gYygiVGVtcCBNQVIiLCAiVGVtcCBBUFIiLCAiVGVtcCBNQVkiLCAiVGVtcCBKVU4iLCAiVGVtcCBKVUwiLCAiVGVtcCBBVUciLCAiVGVtcCBTRVAiLCAiVGVtcCBPQ1QiLCAiVGVtcCBOT1YiLCAiVGVtcCBERUMiLCAiVGVtcCBKQU4iLCAiVGVtcCBGRUIiLCAiVGVtcC1NQVIiLCAiVGVtcC1BUFIiLCAiVGVtcC1NQVkiLCAiUHJlY2lwIE1BUiIsICJQcmVjaXAgQVBSIiwgIlByZWNpcCBNQVkiLCAiUHJlY2lwIEpVTiIsICJQcmVjaXAgSlVMIiwgIlByZWNpcCBBVUciLCAiUHJlY2lwIFNFUCIsICJQcmVjaXAgT0NUIiwgIlByZWNpcCBOT1YiLCAiUHJlY2lwIERFQyIsICJQcmVjaXAgSkFOIiwgIlByZWNpcCBGRUIiLCAiUHJlY2lwLU1BUiIsICJQcmVjaXAtQVBSIiwgIlByZWNpcC1NQVkiLCAiV2luZCBNQVIiLCAiV2luZCBBUFIiLCAiV2luZCBNQVkiLCAiV2luZCBKVU4iLCAiV2luZCBKVUwiLCAiV2luZCBBVUciLCAiV2luZCBTRVAiLCAiV2luZCBPQ1QiLCAiV2luZCBOT1YiLCAiV2luZCBERUMiLCAiV2luZCBKQU4iLCAiV2luZCBGRUIiLCAiV2luZC1NQVIiLCAiV2luZC1BUFIiLCAiV2luZC1NQVkiKQ0KQVJfbWV0ZW9fc3ViMiA8LSBhY2YobWV0ZW9fc3ViMiwgbGFnID0gMSwgcGxvdCA9IEZBTFNFKQ0KQVJfbWV0ZW9fc3ViMiA8LSBBUl9tZXRlb19zdWIyJGFjZg0KDQphZGpfbl8yIDwtIG1hdHJpeCgsIG5yb3cgPSBuY29sKHByb3h5X2Fubl9hbGwpLCBuY29sID0gbmNvbChtZXRlb19zdWIyKSkNCiMgY2FsY3VsYXRlIGFkanVzdGVkIG4gdXNpbmcgbWV0aG9kIG9mIEJyZXRoZXJ0b24gZXQgYWwuICgxOTk5KQ0KDQpmb3IgKGkgaW4gMTpuY29sKHByb3h5X2Fubl9hbGwpKSB7DQogIGZvciAoaiBpbiAxOm5jb2wobWV0ZW9fc3ViMikpIHsNCiAgICBhZGpfbl8yW2ksIGpdIDwtIG5yb3cobWV0ZW9fc3ViMikgKiAoMSAtIEFSX3Byb3hpZXNbMiwgaSwgaV0gKiBBUl9tZXRlb19zdWIyWzIsIGosIGpdKSAvICgxICsgQVJfcHJveGllc1syLCBpLCBpXSAqIEFSX21ldGVvX3N1YjJbMiwgaiwgal0pDQogIH0NCn0NCmFkal9uXzJbYWRqX25fMiA+IDU0XSA8LSA1NA0KY29sbmFtZXMoYWRqX25fMikgPC0gY29sbmFtZXMobWV0ZW9fc3ViMikNCnJvd25hbWVzKGFkal9uXzIpIDwtIGNvbG5hbWVzKHByb3h5X2Fubl9hbGwpDQoNCnB2YWxfMiA8LSBjb3JyLnAoY29yX21hdHJpeF9tb250aHMsIG4gPSBhZGpfbl8yLCBhZGp1c3QgPSAiZmRyIikkcA0KcGFyKG1mcm93ID0gYygyLCAyKSkNCmNvcnJwbG90KGNvcl9tYXRyaXhfbW9udGhzWywgMToxNV0sIG1ldGhvZCA9ICJjb2xvciIsIHAubWF0ID0gcHZhbF8yWywgMToxNV0sIHNpZy5sZXZlbCA9IGMoMC4wMSwgMC4wNSwgMC4xKSwgcGNoID0gYygiLiIpLCBpbnNpZyA9ICJsYWJlbF9zaWciKQ0KY29ycnBsb3QoY29yX21hdHJpeF9tb250aHNbLCAxNjozMF0sIG1ldGhvZCA9ICJjb2xvciIsIHAubWF0ID0gcHZhbF8yWywgMTY6MzBdLCBzaWcubGV2ZWwgPSBjKDAuMDEsIDAuMDUsIDAuMSksIHBjaCA9IGMoIi4iKSwgaW5zaWcgPSAibGFiZWxfc2lnIikNCmNvcnJwbG90KGNvcl9tYXRyaXhfbW9udGhzWywgMzE6NDVdLCBtZXRob2QgPSAiY29sb3IiLCBwLm1hdCA9IHB2YWxfMlssIDMxOjQ1XSwgc2lnLmxldmVsID0gYygwLjAxLCAwLjA1LCAwLjEpLCBwY2ggPSBjKCIuIiksIGluc2lnID0gImxhYmVsX3NpZyIpDQpjb3JycGxvdChjb3JfbWF0cml4X3NlYXNvbmFsWyxjKC01LC0xMSwtMTYpXSwgbWV0aG9kID0gImNvbG9yIiwgcC5tYXQgPSBwdmFsWyxjKC01LC0xMSwtMTYpXSwgc2lnLmxldmVsID0gYygwLjAxLCAwLjA1LCAwLjEpLCBwY2ggPSBjKCIuIiksIGluc2lnID0gImxhYmVsX3NpZyIpDQpgYGANCg0KIyMjIFJlZHVuZGFuY3kgYW5hbHlzaXMgKFJEQSkNCg0KYGBge3IgUkRBLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD04LCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KcmRhXzEgPC0gcmRhKHByb3h5X2Fubl9hbGwsIG1ldGVvX2NsdXN0WywgYygzOjYsIDg6MTEsIDEzOjE2KV0sIHNjYWxlID0gVFJVRSkNClJzcXVhcmVBZGoocmRhXzEpDQpzdW1tYXJ5KHJkYV8xKSRjb250DQpwbG90KHJkYV8xLCBzY2FsaW5nID0gMywgZGlzcGxheSA9IGMoImNuIiwgInNwIikpDQpzcGUuc2MgPC0gc2NvcmVzKHJkYV8xLCBjaG9pY2VzID0gMToyLCBzY2FsaW5nID0gMywgZGlzcGxheSA9ICJzcCIpDQphcnJvd3MoMCwgMCwgc3BlLnNjWywgMV0sIHNwZS5zY1ssIDJdLCBsZW5ndGggPSAwLjEsIGx0eSA9IDEsIGNvbCA9ICJyZWQiLCBsd2QgPSAxKQ0KcG9pbnRzLnJkYSA8LSBzY29yZXMocmRhXzEsIGNob2ljZXMgPSAxOjIsIHNjYWxpbmcgPSAzLCBkaXNwbGF5ID0gInNpdGVzIikNCg0KcG9pbnRzKHBvaW50cy5yZGFbbWV0ZW9fY2x1c3QkR3JvdXAgPT0gMSwgXSwgY29sID0gIiNkNTVlMDAiLCBwY2ggPSAxNikgIyBWVC0xDQpwb2ludHMocG9pbnRzLnJkYVttZXRlb19jbHVzdCRHcm91cCA9PSAyLCBdLCBjb2wgPSAiIzU2YjRlOSIsIHBjaCA9IDE2KSAjIFZULTINCnBvaW50cyhwb2ludHMucmRhW21ldGVvX2NsdXN0JEdyb3VwID09IDMsIF0sIGNvbCA9ICIjMDA5ZTczIiwgcGNoID0gMTYpICMgVlQtMw0KcG9pbnRzKHBvaW50cy5yZGFbbWV0ZW9fY2x1c3QkR3JvdXAgPT0gNCwgXSwgY29sID0gIiNmMGU0NDIiLCBwY2ggPSAxNikgIyBWVC00DQpgYGANCg0KIyMgR2VuZXJhbGl6ZWQgQWRkaXRpdmUgTW9kZWxzIChHQU1zKQ0KDQojIyMgU3ByaW5nIGFuZCBTdW1tZXIgVGVtcGVyYXR1cmUgKE1BTUpKQSkgbW9kZWwNCg0KYGBge3IgVGVtcF9HQU0xLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD04LCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KVlQgPC0gYXMuZGF0YS5mcmFtZShyZXYobXljbCRncm91cCkpDQpBbm51YWxfZGF0YV9jb21iIDwtIGNiaW5kKHByb3h5X2Fubl9hbGwsIG1ldGVvX2Fubl9tZWFuKQ0KQW5udWFsX2RhdGFfY29tYiRWVCA8LSBWVFsxOjU0LDFdDQojIE1BTUpKQSBUZW1wIEdBTQ0KZ2FtX01BTUpKQV90ZW1wIDwtIGdhbShUZW1wX01BTUpKQSB+IHMoVEMpICsgcyhUaSksIGRhdGEgPSBBbm51YWxfZGF0YV9jb21iLCBtZXRob2QgPSAiUkVNTCIsIHNlbGVjdCA9IFRSVUUpDQpzdW1tYXJ5KGdhbV9NQU1KSkFfdGVtcCkNCg0KcHJlZF9NQU1KSkFfdGVtcCA8LSBhc190aWJibGUoYXMuZGF0YS5mcmFtZShwcmVkaWN0KGdhbV9NQU1KSkFfdGVtcCwgc2UuZml0ID0gVFJVRSwgdW5jb25kaXRpb25hbCA9IFRSVUUpKSkNCnByZWRfTUFNSkpBX3RlbXAgPC0gYmluZF9jb2xzKEFubnVhbF9kYXRhX2NvbWIsIHByZWRfTUFNSkpBX3RlbXApICU+JQ0KICBtdXRhdGUodXByID0gZml0ICsgMiAqIHNlLmZpdCwgbHdyID0gZml0IC0gMiAqIHNlLmZpdCkNCnRoZW1lX3NldCh0aGVtZV9idygpKQ0KTUFNSkpBX3RlbXBfcGxvdCA8LSBnZ3Bsb3QoQW5udWFsX2RhdGFfY29tYiwgYWVzKHggPSB2YXJ2ZV95ZWFyLCB5ID0gVGVtcF9NQU1KSkEpKSArDQogIGdlb21fcG9pbnQoKSArDQogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoMTk2NSwgMjAyMCwgNSksIGxpbWl0cyA9IGMoMTk2NSwgMjAyMCkpICsNCiAgZ2VvbV9yaWJib24oDQogICAgZGF0YSA9IHByZWRfTUFNSkpBX3RlbXAsDQogICAgbWFwcGluZyA9IGFlcyh5bWluID0gbHdyLCB5bWF4ID0gdXByLCB4ID0gdmFydmVfeWVhciksIGFscGhhID0gMC40LCBpbmhlcml0LmFlcyA9IEZBTFNFLA0KICAgIGZpbGwgPSAibGlnaHRibHVlIg0KICApICsNCiAgZ2VvbV9saW5lKA0KICAgIGRhdGEgPSBwcmVkX01BTUpKQV90ZW1wLA0KICAgIG1hcHBpbmcgPSBhZXMoeSA9IGZpdCwgeCA9IHZhcnZlX3llYXIpLCBpbmhlcml0LmFlcyA9IEZBTFNFLCBzaXplID0gMSwgY29sb3VyID0gImJsYWNrIg0KICApICsNCiAgbGFicyh4ID0gInZhcnZlX3llYXIiLCB5ID0gIk1BTUpKQSBUZW1wICjCsEMpIikgKw0KICB0aGVtZShwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLCBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpKQ0KTUFNSkpBX3RlbXBfcGxvdA0KcGxvdChnYW1fTUFNSkpBX3RlbXAsIHBhZ2VzID0gMSwgYWxsLnRlcm1zID0gVFJVRSwgc2hhZGUgPSBUUlVFLCByZXNpZHVhbHMgPSBUUlVFLCBwY2ggPSAxLCBjZXggPSAxLCBzZVdpdGhNZWFuID0gVFJVRSwgc2hhZGUuY29sID0gImxpZ2h0Ymx1ZSIpDQpgYGANCg0KRGlhZ25vc3RpYyBwbG90cw0KDQpgYGB7ciBUZW1wX0dBTTIsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTgsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpwYXIobWZyb3cgPSBjKDMsIDIpKQ0KZ2FtLmNoZWNrKGdhbV9NQU1KSkFfdGVtcCkNCmFjZihnYW1fTUFNSkpBX3RlbXAkcmVzaWR1YWxzLCBsYWcubWF4ID0gMzYsIG1haW4gPSAiQUNGIikNCnBhY2YoZ2FtX01BTUpKQV90ZW1wJHJlc2lkdWFscywgbGFnLm1heCA9IDM2LCBtYWluID0gInBBQ0YiKQ0KYGBgDQoNCjEwLWZvbGQgY3Jvc3MtdmFsaWRhdGVkIFJNU0UNCg0KYGBge3IgVGVtcF9HQU1fQ1ZfUk1TRSwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9OCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCkNWX3RlbXAgPC0gQ1ZnYW0oZm9ybXVsYSA9IFRlbXBfTUFNSkpBIH4gcyhUQykgKyBzKFRpKSwgZGF0YSA9IEFubnVhbF9kYXRhX2NvbWIsIG1ldGhvZCA9ICJSRU1MIikNCnBhc3RlKCJDVi1STVNFICjCsEMpID0gIiwgcm91bmQoc3FydChDVl90ZW1wJGN2c2NhbGUpLCBkaWdpdHMgPSAyKSkNCnBhc3RlKCJDVi1STVNFICglKSA9ICIsIHJvdW5kKDEwMCAqIHNxcnQoQ1ZfdGVtcCRjdnNjYWxlKSAvIChtYXgoQW5udWFsX2RhdGFfY29tYiRUZW1wX01BTUpKQSkgLSBtaW4oQW5udWFsX2RhdGFfY29tYiRUZW1wX01BTUpKQSkpLCBkaWdpdHMgPSAyKSkNCmBgYA0KU3BsaXQtcGVyaW9kIGNhbGlicmF0aW9uIGFuZCB2YWxpZGF0aW9uIChNQU1KSkEgVGVtcGVyYXR1cmUpDQoNCmBgYHtyIFRlbXBfR0FNX3NwbGl0LCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD04LCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyBwcmVwYXJpbmcgc3VtbWFyeSB0YWJsZQ0KQW5udWFsX2RhdGFfY29tYl9jYWwgPC0gQW5udWFsX2RhdGFfY29tYltBbm51YWxfZGF0YV9jb21iJHZhcnZlX3llYXIgPD0gMTk5MiwgXQ0KQW5udWFsX2RhdGFfY29tYl92ZXIgPC0gQW5udWFsX2RhdGFfY29tYltBbm51YWxfZGF0YV9jb21iJHZhcnZlX3llYXIgPiAxOTkyLCBdDQoNCnNwbGl0X3BlcmlvZF90ZW1wIDwtIGRhdGEuZnJhbWUoY2FsX3BlcmlvZCA9IGMoIjE5NjYtMTk5MiIsICIxOTkzLTIwMTkiKSwgdmFsX3BlcmlvZCA9IGMoIjE5OTMtMjAxOSIsICIxOTY2LTE5OTIiKSwgUnNxcl9hZGogPSBOQSwgUkUgPSBOQSwgQ0UgPSBOQSwgUk1TRSA9IE5BKQ0KIyBjYWxpYnJhdGlvbiBtb2RlbA0KZ2FtX01BTUpKQV90ZW1wX2NhbCA8LSBnYW0oVGVtcF9NQU1KSkEgfiBzKFRDKSArIHMoVGkpLCBkYXRhID0gQW5udWFsX2RhdGFfY29tYl9jYWwsIG1ldGhvZCA9ICJSRU1MIiwgc2VsZWN0ID0gVFJVRSkNCnNwbGl0X3BlcmlvZF90ZW1wJFJzcXJfYWRqWzFdIDwtIHN1bW1hcnkoZ2FtX01BTUpKQV90ZW1wX2NhbCkkci5zcQ0KDQojIENhbGN1bGF0ZSBSRSwgQ0UsIFJNU0UNCnByZWRfTUFNSkpBX3RlbXBfY2FsIDwtIGFzX3RpYmJsZShhcy5kYXRhLmZyYW1lKHByZWRpY3QoZ2FtX01BTUpKQV90ZW1wX2NhbCwgbmV3ZGF0YSA9IEFubnVhbF9kYXRhX2NvbWIsIHNlLmZpdCA9IFRSVUUsIHVuY29uZGl0aW9uYWwgPSBUUlVFKSkpDQpwcmVkX01BTUpKQV90ZW1wX3ZlciA8LSBhc190aWJibGUoYXMuZGF0YS5mcmFtZShwcmVkaWN0KGdhbV9NQU1KSkFfdGVtcF9jYWwsIG5ld2RhdGEgPSBBbm51YWxfZGF0YV9jb21iX3Zlciwgc2UuZml0ID0gVFJVRSwgdW5jb25kaXRpb25hbCA9IFRSVUUpKSkNCg0KUkVfTUFNSkpBX3RlbXAgPC0gMSAtIHN1bSgoQW5udWFsX2RhdGFfY29tYl92ZXIkVGVtcF9NQU1KSkEgLSBwcmVkX01BTUpKQV90ZW1wX3ZlciRmaXQpXjIpIC8gc3VtKChBbm51YWxfZGF0YV9jb21iX3ZlciRUZW1wX01BTUpKQSAtIG1lYW4oQW5udWFsX2RhdGFfY29tYl9jYWwkVGVtcF9NQU1KSkEpKV4yKQ0Kc3BsaXRfcGVyaW9kX3RlbXAkUkVbMV0gPC0gUkVfTUFNSkpBX3RlbXANCg0KQ0VfTUFNSkpBX3RlbXAgPC0gMSAtIHN1bSgoQW5udWFsX2RhdGFfY29tYl92ZXIkVGVtcF9NQU1KSkEgLSBwcmVkX01BTUpKQV90ZW1wX3ZlciRmaXQpXjIpIC8gc3VtKChBbm51YWxfZGF0YV9jb21iX3ZlciRUZW1wX01BTUpKQSAtIG1lYW4oQW5udWFsX2RhdGFfY29tYl92ZXIkVGVtcF9NQU1KSkEpKV4yKQ0Kc3BsaXRfcGVyaW9kX3RlbXAkQ0VbMV0gPC0gQ0VfTUFNSkpBX3RlbXANCg0KUk1TRVBfTUFNSkpBX3RlbXAgPC0gc3FydChtZWFuKChBbm51YWxfZGF0YV9jb21iX3ZlciRUZW1wX01BTUpKQSAtIHByZWRfTUFNSkpBX3RlbXBfdmVyJGZpdCleMikpDQpzcGxpdF9wZXJpb2RfdGVtcCRSTVNFWzFdIDwtIHBhc3RlKHJvdW5kKFJNU0VQX01BTUpKQV90ZW1wLCBkaWdpdHMgPSAzKSwgIiAoIiwgcm91bmQoMTAwICogUk1TRVBfTUFNSkpBX3RlbXAgLyAobWF4KEFubnVhbF9kYXRhX2NvbWIkVGVtcF9NQU1KSkEpIC0gbWluKEFubnVhbF9kYXRhX2NvbWIkVGVtcF9NQU1KSkEpKSwgZGlnaXRzID0gMyksICIlKSIpDQoNCiMgbm93IHN3aXRjaGluZyBjYWxpYnJhdGlvbiBhbmQgdmVyaWZpY2F0aW9uIHBlcmlvZHMNCmdhbV9NQU1KSkFfdGVtcF92ZXIgPC0gZ2FtKFRlbXBfTUFNSkpBIH4gcyhUQykgKyBzKFRpKSwgZGF0YSA9IEFubnVhbF9kYXRhX2NvbWJfdmVyLCBtZXRob2QgPSAiUkVNTCIsIHNlbGVjdCA9IFRSVUUpDQpzcGxpdF9wZXJpb2RfdGVtcCRSc3FyX2FkalsyXSA8LSBzdW1tYXJ5KGdhbV9NQU1KSkFfdGVtcF92ZXIpJHIuc3ENCnByZWRfTUFNSkpBX3RlbXBfdmVyXzIgPC0gYXNfdGliYmxlKGFzLmRhdGEuZnJhbWUocHJlZGljdChnYW1fTUFNSkpBX3RlbXBfdmVyLCBuZXdkYXRhID0gQW5udWFsX2RhdGFfY29tYl9jYWwsIHNlLmZpdCA9IFRSVUUsIHVuY29uZGl0aW9uYWwgPSBUUlVFKSkpDQpSRV9NQU1KSkFfdGVtcF8yIDwtIDEgLSBzdW0oKEFubnVhbF9kYXRhX2NvbWJfY2FsJFRlbXBfTUFNSkpBIC0gcHJlZF9NQU1KSkFfdGVtcF92ZXJfMiRmaXQpXjIpIC8gc3VtKChBbm51YWxfZGF0YV9jb21iX2NhbCRUZW1wX01BTUpKQSAtIG1lYW4oQW5udWFsX2RhdGFfY29tYl92ZXIkVGVtcF9NQU1KSkEpKV4yKQ0Kc3BsaXRfcGVyaW9kX3RlbXAkUkVbMl0gPC0gUkVfTUFNSkpBX3RlbXBfMg0KDQpDRV9NQU1KSkFfdGVtcF8yIDwtIDEgLSBzdW0oKEFubnVhbF9kYXRhX2NvbWJfY2FsJFRlbXBfTUFNSkpBIC0gcHJlZF9NQU1KSkFfdGVtcF92ZXJfMiRmaXQpXjIpIC8gc3VtKChBbm51YWxfZGF0YV9jb21iX2NhbCRUZW1wX01BTUpKQSAtIG1lYW4oQW5udWFsX2RhdGFfY29tYl9jYWwkVGVtcF9NQU1KSkEpKV4yKQ0Kc3BsaXRfcGVyaW9kX3RlbXAkQ0VbMl0gPC0gQ0VfTUFNSkpBX3RlbXBfMg0KDQpSTVNFUF9NQU1KSkFfdGVtcF8yIDwtIHNxcnQobWVhbigoQW5udWFsX2RhdGFfY29tYl9jYWwkVGVtcF9NQU1KSkEgLSBwcmVkX01BTUpKQV90ZW1wX3Zlcl8yJGZpdCleMikpDQpzcGxpdF9wZXJpb2RfdGVtcCRSTVNFWzJdIDwtIHBhc3RlKHJvdW5kKFJNU0VQX01BTUpKQV90ZW1wXzIsIGRpZ2l0cyA9IDMpLCAiICgiLCByb3VuZCgxMDAgKiBSTVNFUF9NQU1KSkFfdGVtcF8yIC8gKG1heChBbm51YWxfZGF0YV9jb21iJFRlbXBfTUFNSkpBKSAtIG1pbihBbm51YWxfZGF0YV9jb21iJFRlbXBfTUFNSkpBKSksIGRpZ2l0cyA9IDMpLCAiJSkiKQ0KDQpzcGxpdF9wZXJpb2RfdGVtcA0KDQojIHNwbGl0IHBlcmlvZCBwbG90DQpwcmVkX01BTUpKQV90ZW1wX3Zlcl8zIDwtIGFzX3RpYmJsZShhcy5kYXRhLmZyYW1lKHByZWRpY3QoZ2FtX01BTUpKQV90ZW1wX3ZlciwgbmV3ZGF0YSA9IEFubnVhbF9kYXRhX2NvbWIsIHNlLmZpdCA9IFRSVUUsIHVuY29uZGl0aW9uYWwgPSBUUlVFKSkpDQpwcmVkX01BTUpKQV90ZW1wX3Zlcl8zIDwtIGJpbmRfY29scyhBbm51YWxfZGF0YV9jb21iLCBwcmVkX01BTUpKQV90ZW1wX3Zlcl8zKQ0KcHJlZF9NQU1KSkFfdGVtcF9jYWxfMyA8LSBhc190aWJibGUoYXMuZGF0YS5mcmFtZShwcmVkaWN0KGdhbV9NQU1KSkFfdGVtcF9jYWwsIG5ld2RhdGEgPSBBbm51YWxfZGF0YV9jb21iLCBzZS5maXQgPSBUUlVFLCB1bmNvbmRpdGlvbmFsID0gVFJVRSkpKQ0KcHJlZF9NQU1KSkFfdGVtcF9jYWxfMyA8LSBiaW5kX2NvbHMoQW5udWFsX2RhdGFfY29tYiwgcHJlZF9NQU1KSkFfdGVtcF9jYWxfMykNCnRoZW1lX3NldCh0aGVtZV9idygpKQ0KZ2FtX01BTUpKQV90ZW1wX3NwbGl0IDwtIGdncGxvdChBbm51YWxfZGF0YV9jb21iLCBhZXMoeCA9IHZhcnZlX3llYXIsIHkgPSBUZW1wX01BTUpKQSkpICsNCiAgZ2VvbV9wb2ludCgpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IHNlcSgxOTY1LCAyMDIwLCA1KSwgbGltaXRzID0gYygxOTY1LCAyMDIwKSkgKw0KICBnZW9tX2xpbmUoDQogICAgZGF0YSA9IHByZWRfTUFNSkpBX3RlbXAsDQogICAgbWFwcGluZyA9IGFlcyh5ID0gZml0LCB4ID0gdmFydmVfeWVhciksIGluaGVyaXQuYWVzID0gRkFMU0UsIHNpemUgPSAxLCBjb2xvdXIgPSAiYmxhY2siDQogICkgKw0KICAgIGdlb21fbGluZSgNCiAgICBkYXRhID0gcHJlZF9NQU1KSkFfdGVtcF92ZXJfMywNCiAgICBtYXBwaW5nID0gYWVzKHkgPSBmaXQsIHggPSB2YXJ2ZV95ZWFyKSwgaW5oZXJpdC5hZXMgPSBGQUxTRSwgc2l6ZSA9IDEsIGNvbG91ciA9ICJyZWQiDQogICkgKw0KICAgIGdlb21fbGluZSgNCiAgICBkYXRhID0gcHJlZF9NQU1KSkFfdGVtcF9jYWxfMywNCiAgICBtYXBwaW5nID0gYWVzKHkgPSBmaXQsIHggPSB2YXJ2ZV95ZWFyKSwgaW5oZXJpdC5hZXMgPSBGQUxTRSwgc2l6ZSA9IDEsIGNvbG91ciA9ICJibHVlIg0KICApICsNCiAgbGFicyh4ID0gIlllYXIiLCB5ID0gIk1BTUpKQSBUZW1wICjCsEMpIikgKw0KICB0aGVtZShwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLCBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpKQ0KZ2FtX01BTUpKQV90ZW1wX3NwbGl0DQpgYGANCg0KIyMjIE1hcmNoLURlY2VtYmVyIHdpbmQgZGF5cyAoPiA3IG0vcykgbW9kZWwNCg0KYGBge3IgV2luZF9HQU0xLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD04LCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyByZW1vdmluZyBtaXNzaW5nIHllYXJzDQp3aW5kX2RhdGFfY29tYiA8LSBBbm51YWxfZGF0YV9jb21iW0FubnVhbF9kYXRhX2NvbWIkdmFydmVfeWVhciAhPSAxOTk0ICYgQW5udWFsX2RhdGFfY29tYiR2YXJ2ZV95ZWFyICE9IDE5OTMsIF0NCg0KZ2FtX3dpbmRfZGF5c19NQVJfREVDIDwtIGdhbShNQVJfREVDX1dpbmRfRGF5cyB+IHMoTUFSKSArIHMoU2kpLCBkYXRhID0gd2luZF9kYXRhX2NvbWIsIG1ldGhvZCA9ICJSRU1MIiwgc2VsZWN0ID0gVFJVRSkNCg0Kc3VtbWFyeShnYW1fd2luZF9kYXlzX01BUl9ERUMpDQoNCnByZWRfd2luZF9kYXlzX01BUl9ERUMgPC0gYXNfdGliYmxlKGFzLmRhdGEuZnJhbWUocHJlZGljdChnYW1fd2luZF9kYXlzX01BUl9ERUMsIHNlLmZpdCA9IFRSVUUsIHVuY29uZGl0aW9uYWwgPSBUUlVFKSkpDQpwcmVkX3dpbmRfZGF5c19NQVJfREVDIDwtIGJpbmRfY29scyh3aW5kX2RhdGFfY29tYiwgcHJlZF93aW5kX2RheXNfTUFSX0RFQykgJT4lDQogIG11dGF0ZSh1cHIgPSBmaXQgKyAyICogc2UuZml0LCBsd3IgPSBmaXQgLSAyICogc2UuZml0KQ0KdGhlbWVfc2V0KHRoZW1lX2J3KCkpDQp3aW5kX2RheXNfTUFSX0RFQ19wbG90IDwtIGdncGxvdCh3aW5kX2RhdGFfY29tYiwgYWVzKHggPSB2YXJ2ZV95ZWFyLCB5ID0gTUFSX0RFQ19XaW5kX0RheXMpKSArDQogIGdlb21fcG9pbnQoKSArDQogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoMTk2NSwgMjAyMCwgNSksIGxpbWl0cyA9IGMoMTk2NSwgMjAyMCkpICsNCiAgZ2VvbV9yaWJib24oDQogICAgZGF0YSA9IHByZWRfd2luZF9kYXlzX01BUl9ERUMsDQogICAgbWFwcGluZyA9IGFlcyh5bWluID0gbHdyLCB5bWF4ID0gdXByLCB4ID0gdmFydmVfeWVhciksIGFscGhhID0gMC40LCBpbmhlcml0LmFlcyA9IEZBTFNFLA0KICAgIGZpbGwgPSAibGlnaHRibHVlIg0KICApICsNCiAgZ2VvbV9saW5lKA0KICAgIGRhdGEgPSBwcmVkX3dpbmRfZGF5c19NQVJfREVDLA0KICAgIG1hcHBpbmcgPSBhZXMoeSA9IGZpdCwgeCA9IHZhcnZlX3llYXIpLCBpbmhlcml0LmFlcyA9IEZBTFNFLCBzaXplID0gMSwgY29sb3VyID0gImJsYWNrIg0KICApICsNCiAgbGFicyh4ID0gIlllYXIiLCB5ID0gIiMgb2YgZGF5cyB3aXRoIG1lYW4gd2luZCBzcGVlZCA+IDcgbS9zIikNCndpbmRfZGF5c19NQVJfREVDX3Bsb3QNCg0KcGxvdChnYW1fd2luZF9kYXlzX01BUl9ERUMsIHBhZ2VzID0gMSwgc2hhZGUgPSBUUlVFLCByZXNpZHVhbHMgPSBUUlVFLCBwY2ggPSAxLCBjZXggPSAxLCBzZVdpdGhNZWFuID0gVFJVRSwgc2hhZGUuY29sID0gImxpZ2h0Ymx1ZSIpDQpgYGANCg0KRGlhZ25vc3RpYyBwbG90cw0KDQpgYGB7ciBXaW5kX0dBTTIsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTgsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpwYXIobWZyb3cgPSBjKDMsIDIpKQ0KZ2FtLmNoZWNrKGdhbV93aW5kX2RheXNfTUFSX0RFQykNCmFjZihnYW1fd2luZF9kYXlzX01BUl9ERUMkcmVzaWR1YWxzLCBsYWcubWF4ID0gMzYsIG1haW4gPSAiQUNGIikNCnBhY2YoZ2FtX3dpbmRfZGF5c19NQVJfREVDJHJlc2lkdWFscywgbGFnLm1heCA9IDM2LCBtYWluID0gInBBQ0YiKQ0KYGBgDQoNCjEwLWZvbGQgY3Jvc3MtdmFsaWRhdGVkIFJNU0UNCg0KYGBge3IgV2luZF9HQU1fQ1ZfUk1TRSwgZmlnLmhlaWdodD04LCBmaWcud2lkdGg9OCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCkNWX3dpbmQgPC0gQ1ZnYW0oZm9ybXVsYSA9IE1BUl9ERUNfV2luZF9EYXlzIH4gcyhNQVIpICsgcyhTaSksIGRhdGEgPSB3aW5kX2RhdGFfY29tYiwgbWV0aG9kID0gIlJFTUwiKQ0KcGFzdGUoIkNWLVJNU0UgKGRheXMpID0gIiwgcm91bmQoc3FydChDVl93aW5kJGN2c2NhbGUpLCBkaWdpdHMgPSAyKSkNCnBhc3RlKCJDVi1STVNFICglKSA9ICIsIHJvdW5kKDEwMCAqIHNxcnQoQ1Zfd2luZCRjdnNjYWxlKSAvIChtYXgod2luZF9kYXRhX2NvbWIkTUFSX0RFQ19XaW5kX0RheXMpIC0gbWluKHdpbmRfZGF0YV9jb21iJE1BUl9ERUNfV2luZF9EYXlzKSksIGRpZ2l0cyA9IDIpKQ0KYGBgDQpTcGxpdC1wZXJpb2QgY2FsaWJyYXRpb24gYW5kIHZhbGlkYXRpb24NCg0KYGBge3IgV2luZF9HQU1fc3BsaXQsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTgsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQp3aW5kX2RhdGFfY29tYl9jYWwgPC0gd2luZF9kYXRhX2NvbWJbd2luZF9kYXRhX2NvbWIkdmFydmVfeWVhciA8PSAxOTkxLCBdDQp3aW5kX2RhdGFfY29tYl92ZXIgPC0gd2luZF9kYXRhX2NvbWJbd2luZF9kYXRhX2NvbWIkdmFydmVfeWVhciA+IDE5OTEsIF0NCg0KIyBwcmVwYXJpbmcgc3VtbWFyeSB0YWJsZQ0Kc3BsaXRfcGVyaW9kX3dpbmQgPC0gZGF0YS5mcmFtZShjYWxfcGVyaW9kID0gYygiMTk2Ni0xOTkxIiwgIjE5OTIsIDE5OTUtMjAxOSIpLCB2YWxfcGVyaW9kID0gYygiMTk5MiwgMTk5NS0yMDE5IiwgIjE5NjYtMTk5MSIpLCBSc3FyX2FkaiA9IE5BLCBSRSA9IE5BLCBDRSA9IE5BLCBSTVNFID0gTkEpDQojIGNhbGlicmF0aW9uIG1vZGVsDQpnYW1fd2luZF9kYXlzX01BUl9ERUNfY2FsIDwtIGdhbShNQVJfREVDX1dpbmRfRGF5cyB+IHMoTUFSKSArIHMoU2kpLCBkYXRhID0gd2luZF9kYXRhX2NvbWJfY2FsLCBtZXRob2QgPSAiUkVNTCIsIHNlbGVjdCA9IFRSVUUpDQpzcGxpdF9wZXJpb2Rfd2luZCRSc3FyX2FkalsxXSA8LSBzdW1tYXJ5KGdhbV93aW5kX2RheXNfTUFSX0RFQ19jYWwpJHIuc3ENCg0KIyBDYWxjdWxhdGUgUkUsIENFLCBSTVNFDQpwcmVkX3dpbmRfZGF5c192ZXIgPC0gYXNfdGliYmxlKGFzLmRhdGEuZnJhbWUocHJlZGljdChnYW1fd2luZF9kYXlzX01BUl9ERUNfY2FsLCBuZXdkYXRhID0gd2luZF9kYXRhX2NvbWJfdmVyLCBzZS5maXQgPSBUUlVFLCB1bmNvbmRpdGlvbmFsID0gVFJVRSkpKQ0KUkVfd2luZF9kYXlzIDwtIDEgLSBzdW0oKHdpbmRfZGF0YV9jb21iX3ZlciRNQVJfREVDX1dpbmRfRGF5cyAtIHByZWRfd2luZF9kYXlzX3ZlciRmaXQpXjIpIC8gc3VtKCh3aW5kX2RhdGFfY29tYl92ZXIkTUFSX0RFQ19XaW5kX0RheXMgLSBtZWFuKHdpbmRfZGF0YV9jb21iX2NhbCRNQVJfREVDX1dpbmRfRGF5cykpXjIpDQpzcGxpdF9wZXJpb2Rfd2luZCRSRVsxXSA8LSBSRV93aW5kX2RheXMNCg0KQ0Vfd2luZF9kYXlzIDwtIDEgLSBzdW0oKHdpbmRfZGF0YV9jb21iX3ZlciRNQVJfREVDX1dpbmRfRGF5cyAtIHByZWRfd2luZF9kYXlzX3ZlciRmaXQpXjIpIC8gc3VtKCh3aW5kX2RhdGFfY29tYl92ZXIkTUFSX0RFQ19XaW5kX0RheXMgLSBtZWFuKHdpbmRfZGF0YV9jb21iX3ZlciRNQVJfREVDX1dpbmRfRGF5cykpXjIpDQpzcGxpdF9wZXJpb2Rfd2luZCRDRVsxXSA8LSBDRV93aW5kX2RheXMNCg0KUk1TRVBfd2luZF9kYXlzIDwtIHNxcnQobWVhbigod2luZF9kYXRhX2NvbWJfdmVyJE1BUl9ERUNfV2luZF9EYXlzIC0gcHJlZF93aW5kX2RheXNfdmVyJGZpdCleMikpDQpzcGxpdF9wZXJpb2Rfd2luZCRSTVNFWzFdIDwtIHBhc3RlKHJvdW5kKFJNU0VQX3dpbmRfZGF5cywgZGlnaXRzID0gMyksICIgKCIsIHJvdW5kKDEwMCAqIFJNU0VQX3dpbmRfZGF5cyAvIChtYXgod2luZF9kYXRhX2NvbWIkTUFSX0RFQ19XaW5kX0RheXMpIC0gbWluKHdpbmRfZGF0YV9jb21iJE1BUl9ERUNfV2luZF9EYXlzKSksIGRpZ2l0cyA9IDMpLCAiJSkiKQ0KDQojIG5vdyB1c2luZyB2ZXIgYXMgY2FsDQpnYW1fd2luZF9kYXlzX01BUl9ERUNfdmVyIDwtIGdhbShNQVJfREVDX1dpbmRfRGF5cyB+IHMoTUFSKSArIHMoU2kpLCBkYXRhID0gd2luZF9kYXRhX2NvbWJfdmVyLCBtZXRob2QgPSAiUkVNTCIsIHNlbGVjdCA9IFRSVUUpDQpzcGxpdF9wZXJpb2Rfd2luZCRSc3FyX2FkalsyXSA8LSBzdW1tYXJ5KGdhbV93aW5kX2RheXNfTUFSX0RFQ192ZXIpJHIuc3ENCg0KcHJlZF93aW5kX2RheXNfdmVyXzIgPC0gYXNfdGliYmxlKGFzLmRhdGEuZnJhbWUocHJlZGljdChnYW1fd2luZF9kYXlzX01BUl9ERUNfdmVyLCBuZXdkYXRhID0gd2luZF9kYXRhX2NvbWJfY2FsLCBzZS5maXQgPSBUUlVFLCB1bmNvbmRpdGlvbmFsID0gVFJVRSkpKQ0KUkVfd2luZF9kYXlzXzIgPC0gMSAtIHN1bSgod2luZF9kYXRhX2NvbWJfY2FsJE1BUl9ERUNfV2luZF9EYXlzIC0gcHJlZF93aW5kX2RheXNfdmVyXzIkZml0KV4yKSAvIHN1bSgod2luZF9kYXRhX2NvbWJfY2FsJE1BUl9ERUNfV2luZF9EYXlzIC0gbWVhbih3aW5kX2RhdGFfY29tYl92ZXIkTUFSX0RFQ19XaW5kX0RheXMpKV4yKQ0Kc3BsaXRfcGVyaW9kX3dpbmQkUkVbMl0gPC0gUkVfd2luZF9kYXlzXzINCg0KQ0Vfd2luZF9kYXlzXzIgPC0gMSAtIHN1bSgod2luZF9kYXRhX2NvbWJfY2FsJE1BUl9ERUNfV2luZF9EYXlzIC0gcHJlZF93aW5kX2RheXNfdmVyXzIkZml0KV4yKSAvIHN1bSgod2luZF9kYXRhX2NvbWJfY2FsJE1BUl9ERUNfV2luZF9EYXlzIC0gbWVhbih3aW5kX2RhdGFfY29tYl9jYWwkTUFSX0RFQ19XaW5kX0RheXMpKV4yKQ0Kc3BsaXRfcGVyaW9kX3dpbmQkQ0VbMl0gPC0gQ0Vfd2luZF9kYXlzXzINCg0KUk1TRVBfd2luZF9kYXlzXzIgPC0gc3FydChtZWFuKCh3aW5kX2RhdGFfY29tYl9jYWwkTUFSX0RFQ19XaW5kX0RheXMgLSBwcmVkX3dpbmRfZGF5c192ZXJfMiRmaXQpXjIpKQ0Kc3BsaXRfcGVyaW9kX3dpbmQkUk1TRVsyXSA8LSBwYXN0ZShyb3VuZChSTVNFUF93aW5kX2RheXNfMiwgZGlnaXRzID0gMyksICIgKCIsIHJvdW5kKDEwMCAqIFJNU0VQX3dpbmRfZGF5c18yIC8gKG1heCh3aW5kX2RhdGFfY29tYiRNQVJfREVDX1dpbmRfRGF5cykgLSBtaW4od2luZF9kYXRhX2NvbWIkTUFSX0RFQ19XaW5kX0RheXMpKSwgZGlnaXRzID0gMyksICIlKSIpDQoNCnNwbGl0X3BlcmlvZF93aW5kDQoNCiMgc3BsaXQgcGVyaW9kIHBsb3QNCnByZWRfd2luZF9kYXlzX3Zlcl8zIDwtIGFzX3RpYmJsZShhcy5kYXRhLmZyYW1lKHByZWRpY3QoZ2FtX3dpbmRfZGF5c19NQVJfREVDX3ZlciwgbmV3ZGF0YSA9IHdpbmRfZGF0YV9jb21iLCBzZS5maXQgPSBUUlVFLCB1bmNvbmRpdGlvbmFsID0gVFJVRSkpKQ0KcHJlZF93aW5kX2RheXNfdmVyXzMgPC0gYmluZF9jb2xzKHdpbmRfZGF0YV9jb21iLCBwcmVkX3dpbmRfZGF5c192ZXJfMykNCnByZWRfd2luZF9kYXlzX2NhbF8zIDwtIGFzX3RpYmJsZShhcy5kYXRhLmZyYW1lKHByZWRpY3QoZ2FtX3dpbmRfZGF5c19NQVJfREVDX2NhbCwgbmV3ZGF0YSA9IHdpbmRfZGF0YV9jb21iLCBzZS5maXQgPSBUUlVFLCB1bmNvbmRpdGlvbmFsID0gVFJVRSkpKQ0KcHJlZF93aW5kX2RheXNfY2FsXzMgPC0gYmluZF9jb2xzKHdpbmRfZGF0YV9jb21iLCBwcmVkX3dpbmRfZGF5c19jYWxfMykNCnRoZW1lX3NldCh0aGVtZV9idygpKQ0KZ2FtX3dpbmRfZGF5c19NQVJfREVDX3NwbGl0IDwtIGdncGxvdCh3aW5kX2RhdGFfY29tYiwgYWVzKHggPSB2YXJ2ZV95ZWFyLCB5ID0gTUFSX0RFQ19XaW5kX0RheXMpKSArDQogIGdlb21fcG9pbnQoKSArDQogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoMTk2NSwgMjAyMCwgNSksIGxpbWl0cyA9IGMoMTk2NSwgMjAyMCkpICsNCiAgZ2VvbV9saW5lKA0KICAgIGRhdGEgPSBwcmVkX3dpbmRfZGF5c19NQVJfREVDLA0KICAgIG1hcHBpbmcgPSBhZXMoeSA9IGZpdCwgeCA9IHZhcnZlX3llYXIpLCBpbmhlcml0LmFlcyA9IEZBTFNFLCBzaXplID0gMSwgY29sb3VyID0gImJsYWNrIg0KICApICsNCiAgICBnZW9tX2xpbmUoDQogICAgZGF0YSA9IHByZWRfd2luZF9kYXlzX3Zlcl8zLA0KICAgIG1hcHBpbmcgPSBhZXMoeSA9IGZpdCwgeCA9IHZhcnZlX3llYXIpLCBpbmhlcml0LmFlcyA9IEZBTFNFLCBzaXplID0gMSwgY29sb3VyID0gInJlZCINCiAgKSArDQogICAgZ2VvbV9saW5lKA0KICAgIGRhdGEgPSBwcmVkX3dpbmRfZGF5c19jYWxfMywNCiAgICBtYXBwaW5nID0gYWVzKHkgPSBmaXQsIHggPSB2YXJ2ZV95ZWFyKSwgaW5oZXJpdC5hZXMgPSBGQUxTRSwgc2l6ZSA9IDEsIGNvbG91ciA9ICJibHVlIg0KICApICsNCiAgbGFicyh4ID0gIlllYXIiLCB5ID0gIiMgb2YgZGF5cyB3aXRoIG1lYW4gd2luZCBzcGVlZCA+IDcgbS9zIikgKw0KICB0aGVtZShwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLCBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpKQ0KZ2FtX3dpbmRfZGF5c19NQVJfREVDX3NwbGl0DQpgYGANCg0KIyMgU3VwcGxlbWVudGFyeSBjb3JyZWxhdGlvbiBwbG90cw0KDQpgYGB7ciBjb3JyX3Bsb3RzLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD04LCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIkFubnVhbCByZXNvbHV0aW9uIHByb3h5IGRhdGEiDQpjb3JycGxvdChjb3IocHJveHlfYW5uX2FsbCksIGFkZENvZWYuY29sID0gImJsYWNrIiwgbnVtYmVyLmNleCA9IDEwIC8gbmNvbChwcm94eV9hbm5fYWxsKSkNCiJGdWxsIHJlc29sdXRpb24gKDYwIHVtKSBzY2FubmluZyBwcm94eSBkYXRhIg0KY29ycnBsb3QoY29yKEhpUmVzX2Z1bGxbSGlSZXNfZnVsbCR2YXJ2ZV95ZWFyID49IDE5NjYsIDQ6MTRdKSwgYWRkQ29lZi5jb2wgPSAiYmxhY2siLCBudW1iZXIuY2V4ID0gMTAgLyBuY29sKEhpUmVzX2Z1bGxbLCA0OjE0XSkpDQoiU2Vhc29uYWwgbWV0ZW8gZGF0YSINCmNvcnJwbG90KGNvcihtZXRlb19zdWIxKSwgYWRkQ29lZi5jb2wgPSAiYmxhY2siLCBudW1iZXIuY2V4ID0gMTAgLyBuY29sKG1ldGVvX3N1YjEpKQ0KYGBgDQoNCiMgU2Vzc2lvbiBpbmZvDQpgYGB7cn0NClN5cy5EYXRlKCkNCnNlc3Npb25JbmZvKCkNCmBgYA==