Heating tolerance data
ARR <- readxl::read_excel("../data/Morley2018.xlsx", skip = 8) %>%
# Add unique id
rowid_to_column("row_ID") %>%
# remove blank rows
filter(!is.na(Taxon)) %>%
# rename columns
rename("ta_high" = 11, #"High acclimation Temperature /°C" ,
"ta_low" = 12, #"Low Acclimation Temperature/ °C" ,
"ARR" = 17, #"CTMax ARR" ,
"tc_high" = 16, #"CTMax/ °C", # CT max of the high acclimation temperature
"acclim_window" = 13, #"Acclimation Window /°C",
"heating_rate" = 22, #"°C change hr-1",
"collection_latitude" = 19) %>% #"Latitude of Collection/ °") %>%
# fix typo in taxon
mutate(Taxon = str_replace_all(Taxon, "amphibains", "amphibians")) %>%
# Fix incorrect heating rate in DOI 10.1007/s10695-013-9793-7
mutate(heating_rate = ifelse(row_ID == 367, (0.3 * 60), heating_rate)) %>%
# Calculate low temperature CT max
mutate(tc_low = tc_high - (ARR * acclim_window))
We used the acclimation dataset available from the Polar Data Centre under an Open Government Licence v3.0 (Morley et al. 2018). The data was published in Morley et al. (2019). The dataset contains Acclimation Response Ratios (ARR), acclimation temperatures (\(T_a\)) and upper thermal tolerance limits (\(T_c\)) of ectotherms compiled from the literature between 1960 - 2015. Ectotherms were acclimated for between 1 and 300 days to a lower temperature (ta_low
) or a higher temperature (ta_high
) to give paired observations for each species. Animals were heated under a constant ramping temperature from \(T_a\) until the point of organismal collapse (\(T_c\)), called CTmax in Morley et al. (2019). Upper thermal tolerance limits were assayed for both acclimation temperatures in paired observations for a species (tc_low
or tc_high
). Within paired observations, each species was measured at the same constant heating rate, but heating rates varied among paired observations representing independent species or experimental assays. Data were only included if each species had \(T_c\) measured for two different starting \(T_a\), allowing us to compare heating tolerances both within and among species.
The dataset contained 369 observations of 316 species from 15 Classes representing marine, terrestrial and freshwater habitats (7 Phyla: Chordata, Arthropoda, Mollusca, Platyhelminthes, Echinodermata, Brachiopoda and Cnidaria).
The \(T_c\) of the lower acclimation temperature was not reported in Morley et al. (2019). We derived the \(T_c\) of the lower acclimation temperature from rearranging the formula for ARR. We first calculate the difference in \(T_c\) between the two acclimation temperatures from ARR multiplied by the difference in acclimation temperatures; called acclimation window (acclim_window
) following Morley et al. (2019). We then calculate \(T_c\) of the lower acclimation temperature (tc_low
) by subtracting the difference in \(T_c\) from the \(T_c\) of the higher acclimation temperature (tc_high
).
\[
T_{c \space lower} = T_{c \space higher} - (ARR \times acclimation \space window)
\]
Rescaling heating tolerance via heating duration
Physiological processes underlying heating responses scale non-linearly with temperature
# Define constants for rescaling
# Boltzmann's constant, k, in units of eV K-1
k <- 8.61733 * 10 ^ -5
# Kelvin to Celsius conversion for normalisation T_K
Tk <- 273.15
# define \beta for a given activation energy, E = 0.6 (Equation 5)
beta_K <- 0.6 / (k * Tk)
If the endpoint of upper thermal tolerance limits is the product of biological processes and rates, then we may expect these rates to scale with temperature, independent of heating rate. Thus, acclimation temperature influences upper thermal tolerance limits via a non-linear thermal dependence. We use the Universal Temperature Dependence of biological rates (i.e., Boltzmann-Arrhenius equation, Equation (2)) to represent the non-linear effect of temperature on biological rates. We assume that the Boltzmann-Arrhenius equation adequately encompasses all physiological processes underlying heating tolerance and upper thermal tolerance limits, at least phenomenologically.
Mass-specific biological rates (\(r\)) increase with temperature following:
\[\begin{equation}
r = R_0 e^{\frac{-E}{kT}}
\tag{2}
\end{equation}\]
Where \(R_0\) is a normalisation factor, \(E\) is activation energy, \(k\) is Boltzmann’s constant (\(8.617 {\times} 10^{-5}\) eV K-1) and \(T\) is temperature in Kelvin. We use a value of 0.6 eV for \(E\) representing mean activation energy of biological rates across taxa (Dell, Pawar, and Savage 2011).
Although \(E\) varies greatly among taxa and biological rates of interest, varying the value of \(E\) does not meaningfully change our results (see Sensitivity of activation energy). \(R_0\) is not used in the calculation of rescaled heating duration and does not affect our results.
Time is implicit in heating tolerances through heating rates
Heating tolerances have a dimension of time (\(t\)) implicit in their definition. Under a constant heating rate, an organism must withstand heating over time between their acclimation temperature (\(T_a\)) and upper thermal tolerance limits (\(T_c\)).
In other words, heating tolerances also represent a duration of time (heating duration, \(\Delta t\)) between two time points (\(t_a\), the start of the heating assay, and \(t_c\), the end of the heating assay) that have a corresponding temperature (\(T_a\) and \(T_c\), respectively).
Therefore, as we can expect biological processes occurring during heating to scale with temperature we can also expect the durations of theses biological processes at one temperature, \(\Delta t(T)\), to scale with temperature. We can describe the relationship between heating durations starting from two temperatures (\(T_{a1}\) and \(T_{a2}\)) as:
\[\begin{equation}
\frac{\Delta t(T_{a1})}{\Delta t(T_{a2})} \approx e^{\frac{E}{kT_{a1}}-\frac{E}{kT_{a2}}}
\tag{3}
\end{equation}\]
Rescaling the effect of acclimation temperature on heating durations
Following Equation (3), we can use a reference temperature to normalise heating durations for convenience and derive an expression that is independent of temperature but retains dimensions of time. We use 0°C as the reference temperature and define a normalisation constant (\(T_K\)) with a value of 273.15 (i.e. 0°C in Kelvin) for centring temperatures (\(T\)) in °C.
\[
\tau = \frac{T}{T_K}
\]
Here, \(T\) are temperatures in degrees Celsius and \(\tau\) are normalised temperatures that are centred around the normalisation constant \(T_K\). \(\tau\) is unitless and can be converted back into degrees Celsius by \(T = \tau \times T_K\).
Substituting the normalisation constant \(T_K\) as \(T_{a1}\) and temperature \(T\) (in °C) as \(T_{a2}\) in Equation (3), we can derive an initial expression that rescales heating durations by accounting for acclimation temperature:
\[\Delta t_r = e^{\frac{E}{kT_K}}e^{-\frac{E}{kT}} \Delta t(T)\]
Subscript \(r\) denotes variables rescaled by the non-linear temperature dependence of physiological rates (Table 1). \(\Delta t_r\) are rescaled heating durations that correspond to non-rescaled heating duration (\(\Delta t\)).
Rescaled heating duration can be written as an integral between the start (\(t_a\)) and end times (\(t_c\)) of the heating assay, assuming a constant temperature ramp:
\[\begin{equation}
\Delta t_r = e^{\frac{E}{kT_K}} \int_{t_a}^{t_c} e^{-\frac{E}{kT(t)}} dt \tag{4}
\end{equation}\]
We can simplify Equation (4) by using the normalised temperature scale (\(\tau\)) and removing the dimension of temperature.
On a normalised temperature scale (\(\tau\)), \(\frac{E}{kT}\) in Equation (4) becomes:
\[\begin{align}
\frac{E}{kT} &= {\frac{E}{kT_K}} {\frac{1}{1 + \frac{T}{T_K}}} \\
& = {\frac{E}{kT_K}} {\frac{1}{1 + \tau}} \\
& \approx \beta (1-\tau)
\end{align}\]
where
\[\begin{equation}
\beta = \frac{E}{k T_K} \tag{5}
\end{equation}\]
\(\beta\) is a constant with an approximate value of 25.5 using \(E =\) 0.6 (beta_K
).
Thus Equation (4) simplifies to
\[\begin{equation}
\Delta t_r = \int_{t_a}^{t_c} e^{\beta \tau (t)} dt \tag{6}
\end{equation}\]
describing rescaled heating duration as a function of time. Rescaled heating duration (\(\Delta t_r\)) can be considered as the effective elapsed duration of the heating assay once the non-linear effect of acclimation temperature has been accounted for.
Equation (6) can equivalently be expressed as an integration over normalised temperature scales (\(\tau\)).
\[\begin{equation}
\Delta t_r = \frac{1}{\lambda} \int_{\tau_{a}}^{\tau_{c}} e^{\beta \tau} d \tau \tag{7}
\end{equation}\]
Here, \(\tau_a\) is acclimation temperature and \(\tau_c\) is upper thermal tolerance limit on normalised temperature scales and correspond with \(T_a\) and \(T_c\) on degree Celsius scales, respectively. \(\lambda\) is heating rate (°C) on a normalised temperature scale, where \(\lambda = Heating \space rate / T_K\) with units of time-1.
Calculating rescaled heating duration from heating tolerance
Integration of Equation (7) gives an expression for rescaled heating duration \(\Delta t_r\) that describes the effect of the non-linear change in physiological rates as temperatures increased during the heating assay, on normalised temperature scales (Equation (8)).
\[\begin{equation}
\Delta t_r = g_\beta (\Delta \tau) \frac{e^{\beta \tau_a}}{\lambda} \tag{8}
\end{equation}\]
\(\Delta \tau\) is heating tolerance on the normalised temperature scale, where \(\Delta \tau = \tau_c - \tau_a\). \(\Delta \tau\) is not corrected for the non-linear temperature dependence of physiological rates. The function \(g_\beta\) accounts for the change in rescaled temperature in the heating assay via integration:
\[\begin{align}
g_\beta (x) &= \int_{\tau_{a}}^{\tau_{c}} e^{\beta x} dx \\
&= \frac{e^{\beta x} - 1}{\beta}
\tag{9}
\end{align}\]
Thus, Equation (8) is used to calculate rescaled heating duration \(\Delta t_r\) from a known heating tolerance (as \(H\) or \(\Delta \tau\)). Normalised heating tolerances \(\Delta \tau\) can readily be converted into degrees Celsius to calculate \(H\) or vice versa. Rescaled heating durations \(\Delta t_r\) measured at two acclimation temperatures are comparable within a species.
Calculating heating tolerance from rescaled heating duration
Conversely, normalised heating tolerance \(\Delta \tau\) can be calculated from rescaled heating duration \(\Delta t_r\) using the inverse of Equation (9).
\[\begin{equation}
\Delta \tau = f_\beta (e^{-\beta \tau_{a}} \lambda \Delta t_r) \tag{10}
\end{equation}\]
Where \(f_\beta\) is the inverse of \(g_\beta\) (Equation (9)) that also accounts for the change in rescaled temperature in the heating assay.
\[\begin{align}
f_\beta(x) &= \frac{\log (1 + \beta x)}{\beta} = : g^{-1}_\beta(x)
\tag{11}
\end{align}\]
Equations (9) and (11) approach the identity for \(\beta x \ll 1\).
Thus, Equation (10) can be used to calculate normalised heating tolerances \(\Delta \tau\) from a known rescaled heating duration \(\Delta t_r\), and thus can be used to calculate heating tolerance in degrees Celsius, \(H\).
Equations (8) and (10) involves two steps: first the heating rate is rescaled by the term \(e^{\beta \tau_{a}}\) that depends on the starting temperature of the assay (to correct for acclimation temperature), second Equations (9) and (11) account for the change in temperature as the heating assay progresses via integration of the Universal Temperature Dependence.
Rescaling heating durations and heating tolerance is dependent on three assumptions: 1) Heating tolerance is arbitrarily defined with respect to 0°C, 2) heating rate is constant, and 3) the Arrhenius relationship is not affected by the physiological state of the organism or the experimental conditions (i.e., \(E\) does not change).
# function for delta t_r that uses g_beta_fun (Equation 8)
delta_tr_fun <- function(tau_a, tau_c, lambda){
exp(beta_K * tau_a) / lambda * g_beta_fun(tau_c - tau_a)
}
# function g of x and the constant beta (Equation 9)
g_beta_fun <- function(x){(exp(beta_K * x) - 1) / beta_K}
# function f of x and the constant beta (Equation 11)
f_beta_fun <- function(x){log(1 + beta_K * x) / beta_K}
We calculated heating tolerances at the two acclimation temperatures on the normalised temperature scale. We then apply Equation (8) to calculate rescaled heating duration \(\Delta t_r\).
# normalise Ta, Tc and heating rate by Tk, calculate normalised heating tolerance
ARR <- ARR %>%
mutate(tau_a_low = ta_low / Tk,
tau_a_high = ta_high / Tk,
tau_c_low = tc_low / Tk,
tau_c_high = tc_high / Tk,
lambda = heating_rate / Tk,
delta_tau_low = tau_c_low - tau_a_low,
delta_tau_high = tau_c_high - tau_a_high)
# Calculate rescaled heating duration for lower acclimation temperatures (Equation 8)
ARR <- ARR %>%
mutate(delta_tr_low = pmap_dbl(list(tau_a = tau_a_low,
tau_c = tau_c_low,
lambda = lambda),
delta_tr_fun))
# Calculate rescaled heating duration for higher acclimation temperatures (Equation 8)
ARR <- ARR %>%
mutate(delta_tr_high = pmap_dbl(list(tau_a = tau_a_high,
tau_c = tau_c_high,
lambda = lambda),
delta_tr_fun))
Rescaled heating durations \(\Delta t_r\) are influenced by heating rate with larger rescaled heating durations associated with slower heating rates (Figure 2). This dependency with heating rate is explored below.
Dimensionless rescaled heating duration
A simple way of visualising rescaled heating duration without its dependency on heating rate is to multiply rescaled heating duration by heating rate to give a dimensionless quantity (\(H_r\)). This dimensionless quantity demonstrates the strong relationship between rescaled heating durations at either acclimation temperature, regardless of heating rate (Figure 3). However, this dimensionless analysis has limited utility in understanding temperature-rate-time dynamics compared with \(\Delta t_r\). \(\Delta t_r\) includes the integration of the non-linear temperature dependency of biological rates and is our main aim of our analysis.
Sensitivity of activation energy
Intraspecific activation energy of various thermally-dependent traits ranges between 0.2 and 1.2 with a median of 0.55 eV (Dell, Pawar, and Savage 2011). Changing activation energy and thus \(\beta\) does not meaningfully change the reported patterns (Figure 4).
delta_tr_gen
is a generalised function to rescale heating tolerance with \(E\) as a variable. \(\beta\) values are calculated for each value of \(E\).
# Generalised function
delta_tr_gen <- function(x, ev, k = 8.61733*10^-5, Tk = 273.15) { # ev is activation energy
# calculate beta K constant
beta_K_sensi <- ev / (k * Tk)
# function for delta tr that uses g_beta_fun (Equation 8)
delta_tr_gen <- function(tau_a, tau_c, lambda){
exp(beta_K_sensi * tau_a) / lambda * g_beta_fun_gen(tau_c - tau_a)
}
# function f of x and the constant beta
f_beta_fun_gen <- function(x){log(1 + beta_K_sensi * x) / beta_K_sensi}
# function g of x and the constant beta
g_beta_fun_gen <- function(x){(exp(beta_K_sensi * x) - 1) / beta_K_sensi}
# normalise Ta, Tc and heating rate by Tk
x <- x %>% # Calculate heating rate as lambda
mutate(tau_a_low = ta_low / Tk,
tau_a_high = ta_high / Tk,
tau_c_low = tc_low / Tk,
tau_c_high = tc_high / Tk,
lambda = heating_rate / Tk,
delta_tau_low = tau_c_low - tau_a_low, # calculate delta taus
delta_tau_high = tau_c_high - tau_a_high)
# map over low temperature experiments
x <- x %>%
mutate(delta_tr_low = pmap_dbl(list(tau_a = tau_a_low,
tau_c = tau_c_low,
lambda = lambda),
delta_tr_gen))
# do the same with the high temp acclimated data
x <- x %>%
mutate(delta_tr_high = pmap_dbl(list(tau_a = tau_a_high,
tau_c = tau_c_high,
lambda = lambda),
delta_tr_gen))
# Add predictions of high from low and conversely low from high
x <- x %>%
mutate(activation = ev,
delta_tau_high_hat = f_beta_fun_gen(exp(beta_K_sensi * (tau_a_low - tau_a_high)) * g_beta_fun_gen(delta_tau_low)), # predict high from low
delta_tau_low_hat = f_beta_fun_gen(exp(beta_K_sensi * (tau_a_high - tau_a_low)) * g_beta_fun_gen(delta_tau_high))) # predict low from high
return(x) # as list
}
The dataset is replicated for a vector of activation energies, then the delta_tr_gen
function is applied to each element of the list using mapply
.
# define activation energies
activation <- seq(0.2, 1.2, 0.2)
# repeat ARR dataset over length of activation energies
ARR_list <- replicate(length(activation), ARR, simplify = FALSE)
# integrate under curve, merge to single data frame
ARR_list <- do.call(rbind, mapply(ARR_list, FUN = delta_tr_gen, ev = activation, SIMPLIFY = FALSE))
# plot
sensi_plot <- ggplot(data = ARR_list,
mapping = aes(x = delta_tr_low,
y = delta_tr_high)) +
geom_point(col = "grey") +
geom_smooth(method = "lm", se = FALSE, col = "black") +
geom_abline(slope = 1, intercept = 0, lty = 2, alpha = 0.6) +
scale_x_continuous(expand = c(0.01,0), trans = "log10", labels = function(x) format(x, scientific = FALSE)) +
scale_y_continuous(expand = c(0.01,0), trans = "log10", labels = function(x) format(x, scientific = FALSE)) +
# scale_colour_viridis_c(name = "Activation energy") +
facet_wrap(.~activation, ncol=3, scales = "free") +
labs(x = expression("Lower temperature rescaled heating duration"), y = expression("Higher temperature rescaled heating duration")) +
theme_classic(base_size = 12)
sensi_plot
Predicting heating tolerance for a new acclimation temperature
We can use rescaled heating durations to predict heating tolerances measured at a different acclimation temperature (\(a2\)) from a known acclimation temperature (\(a1\)) and heating tolerance.
# Add predictions of high from low and conversely low from high
ARR <- ARR %>%
mutate(delta_tau_high_hat = f_beta_fun(exp(beta_K * (tau_a_low - tau_a_high)) * g_beta_fun(delta_tau_low)), # predict high from low (Equation 12)
delta_tau_low_hat = f_beta_fun(exp(beta_K * (tau_a_high - tau_a_low)) * g_beta_fun(delta_tau_high))) # predict low from high (Equation 13)
Assuming heating tolerances are the same
The simplest model to predict a new heating tolerance from a new acclimation temperature is to assume that heating tolerances at the higher and lower acclimation temperature experiments are the same. For example, we can predict the heating tolerance at the higher acclimation temperature \(\Delta \tau (\tau_{a2})\), from the lower acclimation temperature, \(\Delta \tau (\tau_{a1})\).
\[\begin{equation}
\Delta \tau (\tau_{a2}) \approx \Delta \tau (\tau_{a1}) \tag{12}
\end{equation}\]
pred1 <- ggplot(data = ARR,
mapping = aes(x = delta_tau_low * Tk,
y = delta_tau_high * Tk)) +
geom_point() +
geom_abline(intercept = 0, slope = 1, lty = 2, alpha = 0.6) +
geom_smooth(method = "lm", se = FALSE, col = "darkgrey") +
labs(x = expression("Predicted heating tolerance (\u00B0C)"),
y = expression("Observed heating tolerance (\u00B0C)")) +
scale_x_continuous(expand = c(0,0), limits = c(0, 40)) +
scale_y_continuous(expand = c(0,0), limits = c(0, 40))
pred1
Assuming heating tolerance is the same at both acclimation temperatures overestimates the heating tolerance at the higher temperature (Figure 5).
Correct for acclimation temperature difference
Next, we can correct for the difference in acclimation temperatures by rescaling by the acclimation temperature via \(e^{\beta (\tau_{a1} - \tau_{a2})}\):
\[\begin{equation}
\Delta \tau (\tau_{a2}) \approx \Delta \tau (\tau_{a1}) e^{\beta (\tau_{a1} - \tau_{a2})}
\tag{13}
\end{equation}\]
pred2 <- pred1 + aes(x = (delta_tau_low * exp(beta_K * (tau_a_low - tau_a_high))) * Tk) +
labs(x = expression("Predicted heating tolerance (\u00B0C)"))
pred2
Using Equation (13) underestimates the heating tolerance at the higher acclimation temperature (Figure 6).
Account for difference in acclimation temperature and change in temperature
Finally, we can derive a more precise prediction that fully accounts for the change to heating tolerance that occurs during the experiment as the temperature is increased using Equation (14).
\[\begin{equation}
\Delta \tau (\tau_{a2}) \approx f_\beta \big(e^{\beta (\tau_{a1} - \tau_{a2})} g_\beta(\Delta \tau(\tau_{a1})) \big)
\tag{14}
\end{equation}\]
pred3 <- pred1 + aes(x = delta_tau_high_hat * Tk) +
labs(x = expression("Predicted heating tolerance (\u00B0C)"))
pred3
The \(R^2\) is 93.45%. And as we can predict heating tolerance at the higher acclimation temperature from the lower acclimation temperature in Figure 7, so we can also predict heating tolerance at the lower acclimation temperature from heating tolerance at the higher temperature using Equation (15) (Figure 8).
\[\begin{equation}
\Delta \tau (\tau_{a1}) \approx f_\beta \big(e^{\beta (\tau_{a2} - \tau_{a1})} g_\beta(\Delta \tau(\tau_{a2})) \big)
\tag{15}
\end{equation}\]
pred4 <- pred1 + aes(x = delta_tau_low_hat * Tk,
y = delta_tau_low * Tk) +
# ggtitle("Predict low from high") +
labs(x = expression("Predicted heating tolerance (\u00B0C)"),
y = expression("Observed heating tolerance (\u00B0C)"))
pred4
The \(R^2\) is 91.24%. Equations (14) and (15) converts normalised heating tolerance at one acclimation temperature into rescaled heating tolerance (via \(g_\beta\)), corrects for the difference in acclimation temperature along the non-linear Universal Temperature Dependence (via \(e^{\beta\tau}\)), and converts rescaled and biological rate-corrected heating tolerance into normalised heating tolerance at the other acclimation temperature (via \(f_\beta\)).
The effect of heating rate on rescaled heating duration
varying_rates <- read.csv("Morley_et_al_2016.csv") %>%
rename(heating_rate = 8,
ta = 9,
tc = 10) %>%
mutate(Genus = ifelse(Species == "borchgrevinki", "Pagothenia", genus)) %>% # Synonym Trematomus Pagothenia Pagothenia in ARR dataset
mutate(Name = paste(Genus, Species),
experiment = "variable",
lambda = heating_rate / Tk) %>%
mutate(Phyla = case_when(phyla == "mollusc" ~ "Mollusca",
phyla == "Fish" ~ "Chordata",
phyla == "Ascidians" ~ "Chordata",
phyla == "Crustacean" ~ "Arthropoda",
TRUE ~ phyla)) %>%
group_by(Name) %>%
distinct() %>% # remove duplicated rows
filter(n()>1) %>% # remove species with 1 observation
ungroup()
To examine the relationship between heating rate and rescaled heating duration further, we used a second dataset containing \(T_c\) measured from the same \(T_a\) under different heating rates (\(\lambda\)) (Morley et al. 2016). Species with only one observation are removed (n = 3). The dataset has 107 observations from 7 phyla. Trematomus borchgrevinki is renamed to Pagothenia borchgrevinki because Pagothenia is the accepted genus and is also used in the ARR dataset. We combined this dataset with data from the constant heating rate experiments for species that also had variable heating rate data with them (129 observations from 37 species).
The original ARR dataset was converted to a long format to join with the varying heating rate dataset (species_data
). The datasets are identified by experiment
(variable
or constant
) and occurrence
(identifying species that occur in both datasets).
species_data <- ARR %>%
# Transform the ARR dataset to long format
pivot_longer(cols = starts_with(c("ta_", "tc_")),
names_to = c(".value", "assay"),
names_sep = "_") %>%
mutate(experiment = "constant") %>%
# Join datasets and get occurences of species in each dataset
full_join(.,
varying_rates,
by = c("Genus", "Species", "Name", "experiment", "ta", "tc", "lambda"),
suffix = c("_constant", "_variable")) %>%
# Normalise temperature
mutate(tau_a = ta / Tk,
tau_c = tc / Tk,
delta_tau = tau_c - tau_a) %>%
group_by(Name) %>%
mutate(occurrence = length(unique(experiment))) %>%
ungroup() %>%
# Keep species with more than 1 heating rate from either dataset
filter(experiment == "variable" | occurrence == 2) %>%
# Calculate rescaled heating duration (Equation 8)
mutate(delta_tr = pmap_dbl(list(tau_a = tau_a,
tau_c = tau_c,
lambda = lambda),
delta_tr_fun))
rate_ratios <- species_data %>%
# Group by name
group_by(Name) %>%
# For each species create all combinations of heating rate with covariates
group_modify(~expand_grid(.x,
select(.x, lambda, delta_tr, delta_tau, tau_a),
# Add numbered suffix to all columns; unique for duplications
.name_repair = function (x) ave(x, x, FUN = function(i) str_c(i, seq_along(i))))) %>%
# Calculate ratio of rescaled duration and heating rate (Equation 19)
mutate(lambda_ratio = lambda2/lambda1,
t_ratio = delta_tr2/delta_tr1) %>%
# Calculate scaling coefficient gamma for each species (Equation 19)
group_modify(function(x, y){
x$gg <- abs(as.numeric(coef(lm(log(t_ratio) ~ log(lambda_ratio), x))[2]))
return(x)}) %>%
distinct() %>% # Remove duplications created by expand grid
ungroup() %>%
# Calculate predicted normalised heating tolerance at the second acclimation temperature, corrected for heating rate (Equation 20)
mutate(delta_tau2_hat = f_beta_fun(exp(beta_K * (tau_a1-tau_a2)) * (lambda_ratio ^ (1 - gg)) * g_beta_fun(delta_tau1)),
delta_tau2_hat_inter = f_beta_fun(exp(beta_K * (tau_a1-tau_a2)) * (lambda_ratio ^ (1 - 0.7656548)) * g_beta_fun(delta_tau1)))
# interspecific gamma
gamma <- abs(coef(glm(log(t_ratio) ~ log(lambda_ratio), data = rate_ratios))[2])
Testing a null effect of heating rates on rescaled heating duration
We first considered a null hypothesis that rescaled heating duration does not depend on heating rate. Equation (10) suggests that for any heating rate:
\[\begin{equation}
\Delta \tau (\lambda)= f_\beta (e^{-\beta \tau_{a}} \lambda \Delta t_r(\lambda))
\tag{16}
\end{equation}\]
If the null hypothesis is supported, then \(\Delta t_r (\lambda) = \Delta t_r (0)\) and thus Equation (16) becomes
\[\begin{equation}
\Delta \tau (\lambda) = f_\beta (e^{-\beta \tau_{a}} \lambda \Delta t_r (0))
\tag{17}
\end{equation}\]
which is a logarithmic, temperature-dependent relationship between observed heating tolerance and heating rate. Equation (17) can be tested by conducting ramping assays starting at the same acclimation temperature but using different heating rates. From these data we can infer \(\Delta t_r (0)\) from the experiment with the slowest heating rate \(\lambda_{min}\). We should then have that
\[\begin{equation}
\Delta \tau (\lambda) = f_\beta (\hat{\lambda}), \ \text{where} \ \hat{\lambda} = \frac{\lambda}{\lambda_{min}} g_\beta (\Delta \tau (\lambda_{min}))
\tag{18}
\end{equation}\]
In a plot of normalised heating tolerance (\(\Delta \tau\)) against the transformed variable \(f_\beta (\hat{\lambda})\), the null hypothesis is supported if the points fall along the identity (1:1) line. If points systematically fall below the 1:1 line, then the null hypothesis is not supported.
g_departure <- species_data %>%
filter(experiment == "variable") %>%
group_by(Name) %>%
mutate(lambda_min = min(lambda),
delta_tau_min = delta_tau[which.min(lambda)]) %>%
ungroup() %>%
ggplot(mapping = aes(x = f_beta_fun(lambda / lambda_min * g_beta_fun(delta_tau_min)) * Tk,
y = delta_tau * Tk,
col = Name)) +
geom_point() +
geom_line(alpha = 0.5) +
geom_abline(slope = 1, intercept = 0, lty = 2, alpha = 0.6) +
labs(x = expression("Predicted heating tolerance (\u00B0C)"),
y = expression("Observed heating tolerance (\u00B0C)")) +
scale_colour_viridis_d(option = "C") +
scale_x_continuous(expand = c(0,0), limits = c(0, 100)) +
scale_y_continuous(expand = c(0,0), limits = c(0, 25)) +
theme(legend.position="none", plot.margin = margin(5.5, 7, 5.5, 5.5, unit = "pt"))
g_departure
We used the slowest heating rate of each species to test whether heating rate had no effect on rescaled heating duration and thus predicted heating tolerance. The null hypothesis was not supported because points systematically fall below the 1:1 line (Figure 9).
To visualize the effect of heating rate on rescaled heating tolerance, we plot the ratio of rescaled heating duration for a paired observation within a species with the corresponding ratio for paired heating rate. The relationship between the ratio of rescaled heating duration and the ratio of heating rate is described by an allometric scaling equation in the form \(\Delta t_r (\lambda) \sim c \lambda^{- \gamma}\) where \(c\) depends only on the experimental protocol and the species-specific scaling exponent, \(\gamma\). Points should fall along the identity line if heating rate does not affect rescaled heating tolerance (i.e., a scaling exponent of -1).
Change in rescaled heating duration, and thus heating tolerance, scales with change in heating rate according to an allometric scaling equation. There is some species-specific variation in the slope of the regression \(\gamma\) (colours). Overall, there is an interspecific scaling exponent of approximately \(\gamma =\) 0.766 calculated from a linear regression of ratios of heating rate and ratios of rescaled heating duration on Log10 scales (Figure 10).
g_scaling <- ggplot(data = rate_ratios,
mapping = aes(x = lambda_ratio,
y = t_ratio,
group = Name,
col = Name)) +
geom_line(stat ="smooth", method = "lm", alpha = 0.5) +
geom_point() +
geom_abline(slope = -1, intercept = 0, lty = 2, alpha = 0.6) +
geom_smooth(aes(group = 1), method = "lm", se = FALSE, col = 1) +
scale_x_log10(
breaks = scales::trans_breaks("log10", function(x) 10^x),
labels = scales::trans_format("log10", scales::math_format(10^.x))
) +
scale_y_log10(
breaks = scales::trans_breaks("log10", function(x) 10^x),
labels = scales::trans_format("log10", scales::math_format(10^.x))
) +
ggtitle(paste0("slope = ",
round(gamma, 3))) +
labs(x = "Heating rate ratio", y = "Rescaled heating duration ratio") +
scale_colour_viridis_d(option = "C") +
theme(legend.position="none")
g_scaling
Quantifying the effect of heating rates on rescaled heating tolerance
Since higher heating rates reduces rescaled heating tolerance following a phenomenological power law, then the relationship between two experiments done at two heating rates, \(\lambda_1\) and \(\lambda_2\), regardless of the starting temperature, can be described by:
\[\begin{equation}
\frac{\lambda_2 \Delta t_r (\lambda_2)}{\lambda_1 \Delta t_r (\lambda_1)} \approx \bigg(\frac{\lambda_2}{\lambda_1}\bigg)^{1-\gamma}
\tag{19}
\end{equation}\]
and therefore that from one heating tolerance \(\Delta \tau_1\) we should be able to predict any other \(\Delta \tau_2\). Using Equation (19) we can deduce \(\Delta t_r (\lambda_2)\) and from Equations (8) and (10) leads to:
\[\begin{equation}
\Delta\tau_2 = f_{\beta}\Bigg(e^{\beta(\tau_{a1}-\tau_{a2})}\bigg(\frac{\lambda_2}{\lambda_1}\bigg)^{1-\gamma}g_{\beta}\big(\Delta\tau_1\big)\Bigg)
\tag{20}
\end{equation}\]
That is, we can predict one heating tolerance \(\Delta\tau_2\) from another \(\Delta\tau_1\) using Equation (20) which incorporates the correction for the effect of heating rate on rescaled heating duration using a species specific scaling exponent (\(\gamma\)). We use species-specific scaling exponents in subsequent calculations for precision. Doing so, we see strong concordance of the observed heating tolerance (delta_tau2
) and the estimated value using Equation (20) (delta_tau2_hat
).
g_predict_tau <- rate_ratios %>%
filter(t_ratio != 1 & lambda_ratio != 1) %>% # remove trivial pairs where it is the lowest heating rate
ggplot(mapping = aes(x = delta_tau2_hat * Tk,
y = delta_tau2 * Tk,
col = Name)) +
geom_abline(slope = 1, intercept = 0, lty = 2, alpha = 0.6) +
geom_point() +
geom_smooth(method = "lm", se = FALSE, col = 1) +
labs(x = expression("Predicted heating tolerance (\u00B0C)"),
y = expression("Observed heating tolerance (\u00B0C)")) +
scale_colour_viridis_d(option = "C") +
scale_x_continuous(expand = c(0,0), limits = c(0, 30)) +
scale_y_continuous(expand = c(0,0), limits = c(0, 30)) +
theme(legend.position="none")
g_predict_tau
We can plot the same as Figure 11 but using the interspecific value of 0.766 for \(\gamma\) (Figure 12). Doing so increases our prediction error for a species.
Generalised graphs of rescaled heating tolerances
We can visualise the general relationship described by Equation (20), using median values of heating rate, \(T_c\) and \(T_a\) across all species and \(\gamma =\) 0.766.
sp_heat_rate = median(ARR$heating_rate)
sp_ta = median(ARR$ta_low)
sp_tc = median(ARR$tc_low)
heating_rate <- round(sort(c(10^(seq(log10(0.004), log10(60), length.out = 14)), 0.015, 1, 0.042, 18)), 3) # on log10 scale for equidistant points
heating_rate <- heating_rate[!heating_rate %in% c(0.018, 0.037, 13.667)] # neaten lines
ta <- seq(5, 40, 1) # range of acclimation temperatures
pal_cols <- viridisLite::viridis(n = length(heating_rate), end = 1) # colour palette for points
gen_ecto <- expand_grid(heating_rate, ta) %>%
mutate(sp_lambda = sp_heat_rate / Tk,
sp_tau_a = sp_ta / Tk,
sp_tau_c = sp_tc / Tk,
sp_delta_tau = sp_tau_c - sp_tau_a,
tau_a = ta / Tk,
delta_tau_a = sp_tau_a - tau_a,
lambda = heating_rate / Tk,
lambda_ratio = lambda/sp_lambda) %>%
mutate(delta_tau_hat = f_beta_fun(exp(beta_K * delta_tau_a) * (lambda_ratio ^ (1 - gamma)) * g_beta_fun(sp_delta_tau))) %>%
ggplot() +
geom_line(aes(ta, delta_tau_hat * Tk, group = heating_rate, col = heating_rate)) +
labs(x = expression("Acclimation temperature (\u00B0C)"),
y = expression("Expected heating tolerance (\u00B0C)")) +
scale_colour_viridis_c(name = expression("Heating rate (\u00B0C h" ^-1 * ")"), trans = "log10", labels = function(x) signif(x))
gen_ecto
Figure 13 can also be visualised as predicted upper thermal tolerance limit \(T_c\) for any acclimation temperature \(T_a\).
expand_grid(heating_rate, ta) %>%
mutate(sp_lambda = sp_heat_rate / Tk,
sp_tau_a = sp_ta / Tk,
sp_tau_c = sp_tc / Tk,
sp_delta_tau = sp_tau_c - sp_tau_a,
tau_a = ta / Tk,
delta_tau_a = sp_tau_a - tau_a,
lambda = heating_rate / Tk,
lambda_ratio = lambda/sp_lambda) %>%
mutate(delta_tau_hat = f_beta_fun(exp(beta_K * delta_tau_a) * (lambda_ratio ^ (1 - gamma)) * g_beta_fun(sp_delta_tau))) %>%
ggplot() +
geom_line(aes(ta, delta_tau_hat * Tk + ta, group = heating_rate, col = heating_rate)) +
labs(x = expression("Acclimation temperature (\u00B0C)"),
y = expression("Upper thermal tolerance limit (\u00B0C)")) +
scale_colour_viridis_c(name = expression("Heating rate (\u00B0C h" ^-1 * ")"), trans = "log10", labels = function(x) signif(x))
LS0tDQp0aXRsZTogIlN1cHBsZW1lbnRhcnkgTWF0ZXJpYWwiDQpzdWJ0aXRsZTogIkhlYXRpbmcgdG9sZXJhbmNlIG9mIGVjdG90aGVybXMgaXMgZXhwbGFpbmVkIGJ5IHRlbXBlcmF0dXJl4oCZcyBub24tbGluZWFyIGluZmx1ZW5jZSBvbiBiaW9sb2dpY2FsIHJhdGVzIg0KZGF0ZTogImByIGZvcm1hdChTeXMuRGF0ZSgpLCAnJWQvJW0vJVknKWAiDQphdXRob3I6DQogIC0gSmFjaW50YSBLb25nXltUcmluaXR5IENvbGxlZ2UgRHVibGluLCBJcmVsYW5kLCBrb25nakB0Y2QuaWVdDQogIC0gQW5kcmV3IEphY2tzb25eW1RyaW5pdHkgQ29sbGVnZSBEdWJsaW4sIElyZWxhbmQsIGphY2tzb2FuQHRjZC5pZV0NCiAgLSBOaWNob2xhcyBQYXluZV5bVHJpbml0eSBDb2xsZWdlIER1YmxpbiwgSXJlbGFuZCwgcGF5bmVuQHRjZC5pZV0NCiAgLSBKZWFuIEZyYW4mY2NlZGlsO29pcyBBcm5vbGRpXltDTlJTLCBGcmFuY2UsIGFybm9sZGkuamVmZkBnbWFpbC5jb21dDQpvdXRwdXQ6DQogIGJvb2tkb3duOjpodG1sX2RvY3VtZW50MjoNCiAgICBudW1iZXJfc2VjdGlvbnM6IEZBTFNFDQogICAgY29kZV9kb3dubG9hZDogeWVzDQogICAgY29kZV9mb2xkaW5nOiBoaWRlDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZmxvYXQ6IHllcw0KICAgIGhpZ2hsaWdodDogdGFuZ28NCiAgYm9va2Rvd246OndvcmRfZG9jdW1lbnQyOg0KICAgIG51bWJlcl9zZWN0aW9uczogRkFMU0UNCiAgYm9va2Rvd246OnBkZl9kb2N1bWVudDI6IGRlZmF1bHQNCmVkaXRvcl9vcHRpb25zOg0KICBjaHVua19vdXRwdXRfdHlwZTogY29uc29sZQ0KYmlibGlvZ3JhcGh5OiByYXRlcy5iaWINCi0tLQ0KDQpgYGB7ciBzZXR1cCwgbWVzc2FnZT1GQUxTRSwgZWNobyA9IEZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KA0KICBtZXNzYWdlID0gRkFMU0UsDQogIHdhcm5pbmcgPSBGQUxTRSwNCiAgY29tbWVudCA9IE5BLA0KICBlY2hvID0gVFJVRSwNCiAgZmlnLmFsaWduID0gJ2NlbnRlcicsDQogIGZpZy53aWR0aCA9IDYsDQogIGZpZy5oZWlnaHQgPSA1DQopDQoNCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShjb3dwbG90KQ0KdGhlbWVfc2V0KHRoZW1lX2NsYXNzaWMoYmFzZV9zaXplID0gMTApKSAjIHNldCBkZWZhdWx0IGZvbnQgc2l6ZQ0Kb3B0aW9ucyh0aWJibGUud2lkdGggPSBJbmYpDQpgYGANCg0KKipSRUFETUUqKiAgDQpUaGlzIGRvY3VtZW50IHByZXNlbnRzIHRoZSBmdWxsIHdvcmtmbG93IG9mICpIZWF0aW5nIHRvbGVyYW5jZSBvZiBhbiBlY3RvdGhlcm0gZG9lcyBub3QgdmFyeSB3aGVuIHRlbXBlcmF0dXJl4oCZcyBpbmZsdWVuY2Ugb24gYmlvbG9naWNhbCByYXRlcyBpcyBhY2NvdW50ZWQgZm9yKiwgaW5jbHVkaW5nIHRoZSBmdWxsIGRlcml2YXRpb24gb2YgdGhlIGVxdWF0aW9ucywgZGF0YSBwcm9jZXNzaW5nIGFuZCBnZW5lcmF0aW5nIGZpZ3VyZXMgZm9yIHRoZSBzdHVkeS4gRmlndXJlIGFuZCBlcXVhdGlvbiBudW1iZXJpbmcgaGVyZSBpcyBpbmRlcGVuZGVudCBvZiB0aGUgbWFpbiBhbmQgc3VwcGxlbWVudGFsIHRleHQuIA0KDQpUaGUgYW5hbHlzaXMgd2FzIGNvbmR1Y3RlZCBpbiBgciBSLnZlcnNpb24uc3RyaW5nYCBbQFItYmFzZV0gcnVubmluZyBgVGlkeXZlcnNlYCBbQFItdGlkeXZlcnNlXSAmIGBjb3dwbG90YCBbQFItY293cGxvdF0uIFRoaXMgZG9jdW1lbnQgd2FzIGNyZWF0ZWQgdXNpbmcgYGJvb2tkb3duYCBbQFItYm9va2Rvd25dIChbU2Vzc2lvbiBpbmZvXSkuIFRvcCByaWdodCBkcm9wIGRvd24gbWVudSBjYW4gc2hvdyBjb2RlIGFuZCBkb3dubG9hZCB0aGUgUm1hcmtkb3duIGZpbGUuIA0KDQoqKioNCg0KIyBIZWF0aW5nIHRvbGVyYW5jZSBkYXRhDQoNCmBgYHtyIGltcG9ydH0NCkFSUiA8LSByZWFkeGw6OnJlYWRfZXhjZWwoIi4uL2RhdGEvTW9ybGV5MjAxOC54bHN4IiwgIHNraXAgPSA4KSAlPiUgDQogICMgQWRkIHVuaXF1ZSBpZA0KICByb3dpZF90b19jb2x1bW4oInJvd19JRCIpICU+JSAgDQogICMgcmVtb3ZlIGJsYW5rIHJvd3MNCiAgZmlsdGVyKCFpcy5uYShUYXhvbikpICU+JQ0KICAjIHJlbmFtZSBjb2x1bW5zDQogIHJlbmFtZSgidGFfaGlnaCIgPSAxMSwgIyJIaWdoIGFjY2xpbWF0aW9uIFRlbXBlcmF0dXJlIC/CsEMiICwNCiAgICAgICAgICJ0YV9sb3ciID0gMTIsICMiTG93IEFjY2xpbWF0aW9uIFRlbXBlcmF0dXJlLyDCsEMiICwNCiAgICAgICAgICJBUlIiID0gMTcsICMiQ1RNYXggQVJSIiAsDQogICAgICAgICAidGNfaGlnaCIgPSAxNiwgIyJDVE1heC8gwrBDIiwgIyBDVCBtYXggb2YgdGhlIGhpZ2ggYWNjbGltYXRpb24gdGVtcGVyYXR1cmUNCiAgICAgICAgICJhY2NsaW1fd2luZG93IiA9IDEzLCAjIkFjY2xpbWF0aW9uIFdpbmRvdyAvwrBDIiwNCiAgICAgICAgICJoZWF0aW5nX3JhdGUiID0gMjIsICMiwrBDIGNoYW5nZSBoci0xIiwNCiAgICAgICAgICJjb2xsZWN0aW9uX2xhdGl0dWRlIiA9IDE5KSAlPiUgICMiTGF0aXR1ZGUgb2YgQ29sbGVjdGlvbi8gwrAiKSAlPiUNCiAgIyBmaXggdHlwbyBpbiB0YXhvbg0KICBtdXRhdGUoVGF4b24gPSBzdHJfcmVwbGFjZV9hbGwoVGF4b24sICJhbXBoaWJhaW5zIiwgImFtcGhpYmlhbnMiKSkgJT4lDQogICMgRml4IGluY29ycmVjdCBoZWF0aW5nIHJhdGUgaW4gRE9JIDEwLjEwMDcvczEwNjk1LTAxMy05NzkzLTcNCiAgbXV0YXRlKGhlYXRpbmdfcmF0ZSA9IGlmZWxzZShyb3dfSUQgID09IDM2NywgKDAuMyAqIDYwKSwgaGVhdGluZ19yYXRlKSkgJT4lDQogICMgQ2FsY3VsYXRlIGxvdyB0ZW1wZXJhdHVyZSBDVCBtYXgNCiAgbXV0YXRlKHRjX2xvdyA9IHRjX2hpZ2ggLSAoQVJSICogYWNjbGltX3dpbmRvdykpIA0KYGBgDQoNCldlIHVzZWQgdGhlIGFjY2xpbWF0aW9uIGRhdGFzZXQgYXZhaWxhYmxlIGZyb20gdGhlIFtQb2xhciBEYXRhIENlbnRyZV0oaHR0cHM6Ly9kb2kub3JnLzEwLjUyODUvMjAwMTBiZmItYzZkMy00MzBmLWIxZjctZDE2NzkwYWI4MzU5KSB1bmRlciBhbiBPcGVuIEdvdmVybm1lbnQgTGljZW5jZSB2My4wIFtATW9ybGV5MjAxOF0uIFRoZSBkYXRhIHdhcyBwdWJsaXNoZWQgaW4gQE1vcmxleTIwMTkuIFRoZSBkYXRhc2V0IGNvbnRhaW5zIEFjY2xpbWF0aW9uIFJlc3BvbnNlIFJhdGlvcyAoQVJSKSwgYWNjbGltYXRpb24gdGVtcGVyYXR1cmVzICgkVF9hJCkgYW5kIHVwcGVyIHRoZXJtYWwgdG9sZXJhbmNlIGxpbWl0cyAoJFRfYyQpIG9mIGVjdG90aGVybXMgY29tcGlsZWQgZnJvbSB0aGUgbGl0ZXJhdHVyZSBiZXR3ZWVuIDE5NjAgLSAyMDE1LiBFY3RvdGhlcm1zIHdlcmUgYWNjbGltYXRlZCBmb3IgYmV0d2VlbiBgciBtaW4oQVJSJCdBY2NsaW1hdGlvbiBkdXJhdGlvbi8gZGF5cycpYCBhbmQgYHIgbWF4KEFSUiQnQWNjbGltYXRpb24gZHVyYXRpb24vIGRheXMnKWAgZGF5cyB0byBhIGxvd2VyIHRlbXBlcmF0dXJlIChgdGFfbG93YCkgb3IgYSBoaWdoZXIgdGVtcGVyYXR1cmUgKGB0YV9oaWdoYCkgdG8gZ2l2ZSBwYWlyZWQgb2JzZXJ2YXRpb25zIGZvciBlYWNoIHNwZWNpZXMuIEFuaW1hbHMgd2VyZSBoZWF0ZWQgdW5kZXIgYSBjb25zdGFudCByYW1waW5nIHRlbXBlcmF0dXJlIGZyb20gJFRfYSQgdW50aWwgdGhlIHBvaW50IG9mIG9yZ2FuaXNtYWwgY29sbGFwc2UgKCRUX2MkKSwgY2FsbGVkIENUfm1heH4gaW4gQE1vcmxleTIwMTkuIFVwcGVyIHRoZXJtYWwgdG9sZXJhbmNlIGxpbWl0cyB3ZXJlIGFzc2F5ZWQgZm9yIGJvdGggYWNjbGltYXRpb24gdGVtcGVyYXR1cmVzIGluIHBhaXJlZCBvYnNlcnZhdGlvbnMgZm9yIGEgc3BlY2llcyAoYHRjX2xvd2Agb3IgYHRjX2hpZ2hgKS4gV2l0aGluIHBhaXJlZCBvYnNlcnZhdGlvbnMsIGVhY2ggc3BlY2llcyB3YXMgbWVhc3VyZWQgYXQgdGhlIHNhbWUgY29uc3RhbnQgaGVhdGluZyByYXRlLCBidXQgaGVhdGluZyByYXRlcyB2YXJpZWQgYW1vbmcgcGFpcmVkIG9ic2VydmF0aW9ucyByZXByZXNlbnRpbmcgaW5kZXBlbmRlbnQgc3BlY2llcyBvciBleHBlcmltZW50YWwgYXNzYXlzLiBEYXRhIHdlcmUgb25seSBpbmNsdWRlZCBpZiBlYWNoIHNwZWNpZXMgaGFkICRUX2MkIG1lYXN1cmVkIGZvciB0d28gZGlmZmVyZW50IHN0YXJ0aW5nICRUX2EkLCBhbGxvd2luZyB1cyB0byBjb21wYXJlIGhlYXRpbmcgdG9sZXJhbmNlcyBib3RoIHdpdGhpbiBhbmQgYW1vbmcgc3BlY2llcy4NCg0KVGhlIGRhdGFzZXQgY29udGFpbmVkIGByIG5yb3coQVJSKWAgb2JzZXJ2YXRpb25zIG9mIGByIGxlbmd0aCh1bmlxdWUoQVJSJE5hbWUpKWAgc3BlY2llcyBmcm9tIGByIGxlbmd0aCh1bmlxdWUoQVJSJENsYXNzKSlgIENsYXNzZXMgcmVwcmVzZW50aW5nIG1hcmluZSwgdGVycmVzdHJpYWwgYW5kIGZyZXNod2F0ZXIgaGFiaXRhdHMgKDcgUGh5bGE6IENob3JkYXRhLCBBcnRocm9wb2RhLCBNb2xsdXNjYSwgUGxhdHloZWxtaW50aGVzLCBFY2hpbm9kZXJtYXRhLCBCcmFjaGlvcG9kYSBhbmQgQ25pZGFyaWEpLg0KDQpUaGUgJFRfYyQgb2YgdGhlIGxvd2VyIGFjY2xpbWF0aW9uIHRlbXBlcmF0dXJlIHdhcyBub3QgcmVwb3J0ZWQgaW4gQE1vcmxleTIwMTkuIFdlIGRlcml2ZWQgdGhlICRUX2MkIG9mIHRoZSBsb3dlciBhY2NsaW1hdGlvbiB0ZW1wZXJhdHVyZSBmcm9tIHJlYXJyYW5naW5nIHRoZSBmb3JtdWxhIGZvciBBUlIuIFdlIGZpcnN0IGNhbGN1bGF0ZSB0aGUgZGlmZmVyZW5jZSBpbiAkVF9jJCBiZXR3ZWVuIHRoZSB0d28gYWNjbGltYXRpb24gdGVtcGVyYXR1cmVzIGZyb20gQVJSIG11bHRpcGxpZWQgYnkgdGhlIGRpZmZlcmVuY2UgaW4gYWNjbGltYXRpb24gdGVtcGVyYXR1cmVzOyBjYWxsZWQgYWNjbGltYXRpb24gd2luZG93IChgYWNjbGltX3dpbmRvd2ApIGZvbGxvd2luZyBATW9ybGV5MjAxOS4gV2UgdGhlbiBjYWxjdWxhdGUgJFRfYyQgb2YgdGhlIGxvd2VyIGFjY2xpbWF0aW9uIHRlbXBlcmF0dXJlIChgdGNfbG93YCkgYnkgc3VidHJhY3RpbmcgdGhlIGRpZmZlcmVuY2UgaW4gJFRfYyQgZnJvbSB0aGUgJFRfYyQgb2YgdGhlIGhpZ2hlciBhY2NsaW1hdGlvbiB0ZW1wZXJhdHVyZSAoYHRjX2hpZ2hgKS4NCg0KJCQNClRfe2MgXHNwYWNlIGxvd2VyfSA9IFRfe2MgXHNwYWNlIGhpZ2hlcn0gLSAoQVJSIFx0aW1lcyBhY2NsaW1hdGlvbiBcc3BhY2Ugd2luZG93KQ0KJCQNCg0KKioqDQoNCiMgSGVhdGluZyB0b2xlcmFuY2UNCg0KV2UgZGVmaW5lZCBoZWF0aW5nIHRvbGVyYW5jZSAoJEgkKSBhcw0KDQpcYmVnaW57ZXF1YXRpb259DQpIID0gVF9jIC0gVF9hIA0KKFwjZXE6SCkNClxlbmR7ZXF1YXRpb259DQoNCndoZXJlICRUX2EkIGlzIGFjY2xpbWF0aW9uIHRlbXBlcmF0dXJlICgmZGVnO0MsIGFsc28gc3RhcnRpbmcgdGVtcGVyYXR1cmUgb2YgdGhlIGhlYXRpbmcgYXNzYXkpIGFuZCAkVF9jJCBpcyB1cHBlciB0aGVybWFsIHRvbGVyYW5jZSBsaW1pdCAoJmRlZztDKS4gV2UgY2FsY3VsYXRlZCBoZWF0aW5nIHRvbGVyYW5jZXMgKCRIJCkgYXQgdGhlIGxvd2VyIChgaHRfbG93YCkgYW5kIGhpZ2hlciBhY2NsaW1hdGlvbiAoYGh0X2hpZ2hgKSB0ZW1wZXJhdHVyZS4NCg0KYGBge3IgSH0NCiMgQ2FsY3VsYXRlIGhlYXRpbmcgdG9sZXJhbmNlcywgSCAoRXF1YXRpb24gMSkNCkFSUiA8LSBBUlIgJT4lIA0KICBtdXRhdGUoaHRfbG93ID0gdGNfbG93IC0gdGFfbG93LA0KICAgICAgICAgaHRfaGlnaCA9IHRjX2hpZ2ggLSB0YV9oaWdoKQ0KYGBgDQoNCmBgYHtyIEgtZ3JhcGgsIGVjaG8gPSBGQUxTRSwgZmlnLmNhcCA9ICJIZWF0aW5nIHRvbGVyYW5jZXMgYXQgdGhlIGxvd2VyIGFuZCBoaWdoZXIgYWNjbGltYXRpb24gdGVtcGVyYXR1cmVzIGZvciBwYWlyZWQgb2JzZXJ2YXRpb25zIG9uIExvZzEwIHRyYW5zZm9ybWVkIGF4ZXMuIn0NCmhlYXRpbmdfZ3JhcGggPC0gQVJSICU+JSANCiAgZ2dwbG90KGFlcyhodF9sb3csIGh0X2hpZ2gsIGNvbCA9IGhlYXRpbmdfcmF0ZSkpICsNCiAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwLCBsdHkgPSAyLCBhbHBoYSA9IDAuNikgKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFLCBjb2wgPSAxKSArIA0KICBnZW9tX3BvaW50KCkgKw0KICBsYWJzKHggPSBleHByZXNzaW9uKCJMb3dlciBhY2NsaW1hdGlvbiB0ZW1wZXJhdHVyZSBIIChcdTAwQjBDKSIpLA0KICAgICAgIHkgPSBleHByZXNzaW9uKCJIaWdoZXIgYWNjbGltYXRpb24gdGVtcGVyYXR1cmUgSCAoXHUwMEIwQykiKSwNCiAgICAgICB0aXRsZSA9IGV4cHJlc3Npb24oIkhlYXRpbmcgdG9sZXJhbmNlLCBIIikpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMoMyw0MCksIGV4cGFuZCA9IGMoMCwwKSwgdHJhbnMgPSAibG9nMTAiKSArDQogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDMsNDApLCBleHBhbmQgPSBjKDAsMCksIHRyYW5zID0gImxvZzEwIikgKw0KICBjb29yZF9lcXVhbCgpICsgIA0KICBzY2FsZV9jb2xvdXJfdmlyaWRpc19jKG5hbWUgPSBleHByZXNzaW9uKCJIZWF0aW5nIHJhdGUgKFx1MDBCMEMgaCIgXi0xICogIikiKSwgdHJhbnMgPSAibG9nMTAiLCBsYWJlbHMgPSBmdW5jdGlvbih4KSBzaWduaWYoeCkpDQoNCmhlYXRpbmdfZ3JhcGgNCmBgYA0KDQoqKioNCg0KIyBSZXNjYWxpbmcgaGVhdGluZyB0b2xlcmFuY2UgdmlhIGhlYXRpbmcgZHVyYXRpb24NCiMjIFBoeXNpb2xvZ2ljYWwgcHJvY2Vzc2VzIHVuZGVybHlpbmcgaGVhdGluZyByZXNwb25zZXMgc2NhbGUgbm9uLWxpbmVhcmx5IHdpdGggdGVtcGVyYXR1cmUNCg0KYGBge3IgY29uc3RhbnRzfQ0KIyBEZWZpbmUgY29uc3RhbnRzIGZvciByZXNjYWxpbmcNCiMgQm9sdHptYW5uJ3MgY29uc3RhbnQsIGssICBpbiB1bml0cyBvZiBlViBLLTENCmsgPC0gOC42MTczMyAqIDEwIF4gLTUNCiMgS2VsdmluIHRvIENlbHNpdXMgY29udmVyc2lvbiBmb3Igbm9ybWFsaXNhdGlvbiBUX0sNClRrIDwtIDI3My4xNQ0KIyBkZWZpbmUgXGJldGEgZm9yIGEgZ2l2ZW4gYWN0aXZhdGlvbiBlbmVyZ3ksIEUgPSAwLjYgKEVxdWF0aW9uIDUpDQpiZXRhX0sgPC0gMC42IC8gKGsgKiBUaykNCmBgYA0KDQpJZiB0aGUgZW5kcG9pbnQgb2YgdXBwZXIgdGhlcm1hbCB0b2xlcmFuY2UgbGltaXRzIGlzIHRoZSBwcm9kdWN0IG9mIGJpb2xvZ2ljYWwgcHJvY2Vzc2VzIGFuZCByYXRlcywgdGhlbiB3ZSBtYXkgZXhwZWN0IHRoZXNlIHJhdGVzIHRvIHNjYWxlIHdpdGggdGVtcGVyYXR1cmUsIGluZGVwZW5kZW50IG9mIGhlYXRpbmcgcmF0ZS4gVGh1cywgYWNjbGltYXRpb24gdGVtcGVyYXR1cmUgaW5mbHVlbmNlcyB1cHBlciB0aGVybWFsIHRvbGVyYW5jZSBsaW1pdHMgdmlhIGEgbm9uLWxpbmVhciB0aGVybWFsIGRlcGVuZGVuY2UuIFdlIHVzZSB0aGUgVW5pdmVyc2FsIFRlbXBlcmF0dXJlIERlcGVuZGVuY2Ugb2YgYmlvbG9naWNhbCByYXRlcyAoaS5lLiwgQm9sdHptYW5uLUFycmhlbml1cyBlcXVhdGlvbiwgRXF1YXRpb24gXEByZWYoZXE6QkEpKSB0byByZXByZXNlbnQgdGhlIG5vbi1saW5lYXIgZWZmZWN0IG9mIHRlbXBlcmF0dXJlIG9uIGJpb2xvZ2ljYWwgcmF0ZXMuIFdlIGFzc3VtZSB0aGF0IHRoZSBCb2x0em1hbm4tQXJyaGVuaXVzIGVxdWF0aW9uIGFkZXF1YXRlbHkgZW5jb21wYXNzZXMgYWxsIHBoeXNpb2xvZ2ljYWwgcHJvY2Vzc2VzIHVuZGVybHlpbmcgaGVhdGluZyB0b2xlcmFuY2UgYW5kIHVwcGVyIHRoZXJtYWwgdG9sZXJhbmNlIGxpbWl0cywgYXQgbGVhc3QgcGhlbm9tZW5vbG9naWNhbGx5Lg0KDQpNYXNzLXNwZWNpZmljIGJpb2xvZ2ljYWwgcmF0ZXMgKCRyJCkgaW5jcmVhc2Ugd2l0aCB0ZW1wZXJhdHVyZSBmb2xsb3dpbmc6DQoNClxiZWdpbntlcXVhdGlvbn0NCiAgICByID0gUl8wIGVee1xmcmFjey1FfXtrVH19DQogICAgKFwjZXE6QkEpDQpcZW5ke2VxdWF0aW9ufQ0KDQpXaGVyZSAkUl8wJCBpcyBhIG5vcm1hbGlzYXRpb24gZmFjdG9yLCAkRSQgaXMgYWN0aXZhdGlvbiBlbmVyZ3ksICRrJCBpcyBCb2x0em1hbm4ncyBjb25zdGFudCAoJDguNjE3IHtcdGltZXN9IDEwXnstNX0kIGVWIEteLTFeKSBhbmQgJFQkIGlzIHRlbXBlcmF0dXJlIGluIEtlbHZpbi4gV2UgdXNlIGEgdmFsdWUgb2YgMC42IGVWIGZvciAkRSQgcmVwcmVzZW50aW5nIG1lYW4gYWN0aXZhdGlvbiBlbmVyZ3kgb2YgYmlvbG9naWNhbCByYXRlcyBhY3Jvc3MgdGF4YSBbQERlbGwyMDExXS4NCg0KQWx0aG91Z2ggJEUkIHZhcmllcyBncmVhdGx5IGFtb25nIHRheGEgYW5kIGJpb2xvZ2ljYWwgcmF0ZXMgb2YgaW50ZXJlc3QsIHZhcnlpbmcgdGhlIHZhbHVlIG9mICRFJCBkb2VzIG5vdCBtZWFuaW5nZnVsbHkgY2hhbmdlIG91ciByZXN1bHRzIChzZWUgW1NlbnNpdGl2aXR5IG9mIGFjdGl2YXRpb24gZW5lcmd5XSkuICRSXzAkIGlzIG5vdCB1c2VkIGluIHRoZSBjYWxjdWxhdGlvbiBvZiByZXNjYWxlZCBoZWF0aW5nIGR1cmF0aW9uIGFuZCBkb2VzIG5vdCBhZmZlY3Qgb3VyIHJlc3VsdHMuIA0KDQoqKioNCg0KIyMgVGltZSBpcyBpbXBsaWNpdCBpbiBoZWF0aW5nIHRvbGVyYW5jZXMgdGhyb3VnaCBoZWF0aW5nIHJhdGVzDQoNCkhlYXRpbmcgdG9sZXJhbmNlcyBoYXZlIGEgZGltZW5zaW9uIG9mIHRpbWUgKCR0JCkgaW1wbGljaXQgaW4gdGhlaXIgZGVmaW5pdGlvbi4gVW5kZXIgYSBjb25zdGFudCBoZWF0aW5nIHJhdGUsIGFuIG9yZ2FuaXNtIG11c3Qgd2l0aHN0YW5kIGhlYXRpbmcgb3ZlciB0aW1lIGJldHdlZW4gdGhlaXIgYWNjbGltYXRpb24gdGVtcGVyYXR1cmUgKCRUX2EkKSBhbmQgdXBwZXIgdGhlcm1hbCB0b2xlcmFuY2UgbGltaXRzICgkVF9jJCkuIA0KDQpJbiBvdGhlciB3b3JkcywgaGVhdGluZyB0b2xlcmFuY2VzIGFsc28gcmVwcmVzZW50IGEgZHVyYXRpb24gb2YgdGltZSAoaGVhdGluZyBkdXJhdGlvbiwgJFxEZWx0YSB0JCkgYmV0d2VlbiB0d28gdGltZSBwb2ludHMgKCR0X2EkLCB0aGUgc3RhcnQgb2YgdGhlIGhlYXRpbmcgYXNzYXksIGFuZCAkdF9jJCwgdGhlIGVuZCBvZiB0aGUgaGVhdGluZyBhc3NheSkgdGhhdCBoYXZlIGEgY29ycmVzcG9uZGluZyB0ZW1wZXJhdHVyZSAoJFRfYSQgYW5kICRUX2MkLCByZXNwZWN0aXZlbHkpLiANCg0KVGhlcmVmb3JlLCBhcyB3ZSBjYW4gZXhwZWN0IGJpb2xvZ2ljYWwgcHJvY2Vzc2VzIG9jY3VycmluZyBkdXJpbmcgaGVhdGluZyB0byBzY2FsZSB3aXRoIHRlbXBlcmF0dXJlIHdlIGNhbiBhbHNvIGV4cGVjdCB0aGUgZHVyYXRpb25zIG9mIHRoZXNlcyBiaW9sb2dpY2FsIHByb2Nlc3NlcyBhdCBvbmUgdGVtcGVyYXR1cmUsICRcRGVsdGEgdChUKSQsIHRvIHNjYWxlIHdpdGggdGVtcGVyYXR1cmUuIFdlIGNhbiBkZXNjcmliZSB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gaGVhdGluZyBkdXJhdGlvbnMgc3RhcnRpbmcgZnJvbSB0d28gdGVtcGVyYXR1cmVzICgkVF97YTF9JCBhbmQgJFRfe2EyfSQpIGFzOg0KDQpcYmVnaW57ZXF1YXRpb259DQpcZnJhY3tcRGVsdGEgdChUX3thMX0pfXtcRGVsdGEgdChUX3thMn0pfSBcYXBwcm94IGVee1xmcmFje0V9e2tUX3thMX19LVxmcmFje0V9e2tUX3thMn19fQ0KICAgIChcI2VxOmVxMSkNClxlbmR7ZXF1YXRpb259DQoNCioqKg0KDQojIyBSZXNjYWxpbmcgdGhlIGVmZmVjdCBvZiBhY2NsaW1hdGlvbiB0ZW1wZXJhdHVyZSBvbiBoZWF0aW5nIGR1cmF0aW9ucw0KDQpGb2xsb3dpbmcgRXF1YXRpb24gXEByZWYoZXE6ZXExKSwgd2UgY2FuIHVzZSBhIHJlZmVyZW5jZSB0ZW1wZXJhdHVyZSB0byBub3JtYWxpc2UgaGVhdGluZyBkdXJhdGlvbnMgZm9yIGNvbnZlbmllbmNlIGFuZCBkZXJpdmUgYW4gZXhwcmVzc2lvbiB0aGF0IGlzIGluZGVwZW5kZW50IG9mIHRlbXBlcmF0dXJlIGJ1dCByZXRhaW5zIGRpbWVuc2lvbnMgb2YgdGltZS4gV2UgdXNlIDAmZGVnO0MgYXMgdGhlIHJlZmVyZW5jZSB0ZW1wZXJhdHVyZSBhbmQgZGVmaW5lIGEgbm9ybWFsaXNhdGlvbiBjb25zdGFudCAoJFRfSyQpIHdpdGggYSB2YWx1ZSBvZiBgciBUa2AgKGkuZS4gMCZkZWc7QyBpbiBLZWx2aW4pIGZvciBjZW50cmluZyB0ZW1wZXJhdHVyZXMgKCRUJCkgaW4gJmRlZztDLg0KDQokJA0KXHRhdSA9IFxmcmFje1R9e1RfS30NCiQkDQoNCkhlcmUsICRUJCBhcmUgdGVtcGVyYXR1cmVzIGluIGRlZ3JlZXMgQ2Vsc2l1cyBhbmQgJFx0YXUkIGFyZSBub3JtYWxpc2VkIHRlbXBlcmF0dXJlcyB0aGF0IGFyZSBjZW50cmVkIGFyb3VuZCB0aGUgbm9ybWFsaXNhdGlvbiBjb25zdGFudCAkVF9LJC4gJFx0YXUkIGlzIHVuaXRsZXNzIGFuZCBjYW4gYmUgY29udmVydGVkIGJhY2sgaW50byBkZWdyZWVzIENlbHNpdXMgYnkgJFQgPSBcdGF1IFx0aW1lcyBUX0skLiANCg0KDQpTdWJzdGl0dXRpbmcgdGhlIG5vcm1hbGlzYXRpb24gY29uc3RhbnQgJFRfSyQgYXMgJFRfe2ExfSQgYW5kIHRlbXBlcmF0dXJlICRUJCAoaW4gJmRlZztDKSBhcyAkVF97YTJ9JCBpbiBFcXVhdGlvbiBcQHJlZihlcTplcTEpLCB3ZSBjYW4gZGVyaXZlIGFuIGluaXRpYWwgZXhwcmVzc2lvbiB0aGF0IHJlc2NhbGVzIGhlYXRpbmcgZHVyYXRpb25zIGJ5IGFjY291bnRpbmcgZm9yIGFjY2xpbWF0aW9uIHRlbXBlcmF0dXJlOiANCg0KJCRcRGVsdGEgdF9yID0gZV57XGZyYWN7RX17a1RfS319ZV57LVxmcmFje0V9e2tUfX0gXERlbHRhIHQoVCkkJA0KU3Vic2NyaXB0ICRyJCBkZW5vdGVzIHZhcmlhYmxlcyByZXNjYWxlZCBieSB0aGUgbm9uLWxpbmVhciB0ZW1wZXJhdHVyZSBkZXBlbmRlbmNlIG9mIHBoeXNpb2xvZ2ljYWwgcmF0ZXMgKFRhYmxlIFxAcmVmKHRhYjptYXRocykpLiAkXERlbHRhIHRfciQgYXJlIHJlc2NhbGVkIGhlYXRpbmcgZHVyYXRpb25zIHRoYXQgY29ycmVzcG9uZCB0byBub24tcmVzY2FsZWQgaGVhdGluZyBkdXJhdGlvbiAoJFxEZWx0YSB0JCkuDQoNClJlc2NhbGVkIGhlYXRpbmcgZHVyYXRpb24gY2FuIGJlIHdyaXR0ZW4gYXMgYW4gaW50ZWdyYWwgYmV0d2VlbiB0aGUgc3RhcnQgKCR0X2EkKSBhbmQgZW5kIHRpbWVzICgkdF9jJCkgb2YgdGhlIGhlYXRpbmcgYXNzYXksIGFzc3VtaW5nIGEgY29uc3RhbnQgdGVtcGVyYXR1cmUgcmFtcDoNCg0KXGJlZ2lue2VxdWF0aW9ufQ0KXERlbHRhIHRfciA9IGVee1xmcmFje0V9e2tUX0t9fSBcaW50X3t0X2F9Xnt0X2N9IGVeey1cZnJhY3tFfXtrVCh0KX19IGR0IChcI2VxOmVxMikNClxlbmR7ZXF1YXRpb259DQoNCldlIGNhbiBzaW1wbGlmeSBFcXVhdGlvbiBcQHJlZihlcTplcTIpIGJ5IHVzaW5nIHRoZSBub3JtYWxpc2VkIHRlbXBlcmF0dXJlIHNjYWxlICgkXHRhdSQpIGFuZCByZW1vdmluZyB0aGUgZGltZW5zaW9uIG9mIHRlbXBlcmF0dXJlLg0KDQpPbiBhIG5vcm1hbGlzZWQgdGVtcGVyYXR1cmUgc2NhbGUgKCRcdGF1JCksICRcZnJhY3tFfXtrVH0kIGluIEVxdWF0aW9uIFxAcmVmKGVxOmVxMikgYmVjb21lczoNCg0KXGJlZ2lue2FsaWdufQ0KXGZyYWN7RX17a1R9ICY9IHtcZnJhY3tFfXtrVF9LfX0ge1xmcmFjezF9ezEgKyBcZnJhY3tUfXtUX0t9fX0gXFwNCiYgPSB7XGZyYWN7RX17a1RfS319IHtcZnJhY3sxfXsxICsgXHRhdX19IFxcDQomIFxhcHByb3ggXGJldGEgKDEtXHRhdSkNClxlbmR7YWxpZ259DQoNCndoZXJlIA0KXGJlZ2lue2VxdWF0aW9ufQ0KXGJldGEgPSBcZnJhY3tFfXtrIFRfS30gKFwjZXE6ZXEzKQ0KXGVuZHtlcXVhdGlvbn0NCg0KJFxiZXRhJCBpcyBhIGNvbnN0YW50IHdpdGggYW4gYXBwcm94aW1hdGUgdmFsdWUgb2YgMjUuNSB1c2luZyAkRSA9JCAwLjYgKGBiZXRhX0tgKS4NCg0KVGh1cyBFcXVhdGlvbiBcQHJlZihlcTplcTIpIHNpbXBsaWZpZXMgdG8NCg0KXGJlZ2lue2VxdWF0aW9ufQ0KXERlbHRhIHRfciA9IFxpbnRfe3RfYX1ee3RfY30gZV57XGJldGEgXHRhdSAodCl9IGR0IChcI2VxOmVxNCkNClxlbmR7ZXF1YXRpb259DQoNCmRlc2NyaWJpbmcgcmVzY2FsZWQgaGVhdGluZyBkdXJhdGlvbiBhcyBhIGZ1bmN0aW9uIG9mIHRpbWUuIFJlc2NhbGVkIGhlYXRpbmcgZHVyYXRpb24gKCRcRGVsdGEgdF9yJCkgY2FuIGJlIGNvbnNpZGVyZWQgYXMgdGhlIGVmZmVjdGl2ZSBlbGFwc2VkIGR1cmF0aW9uIG9mIHRoZSBoZWF0aW5nIGFzc2F5IG9uY2UgdGhlIG5vbi1saW5lYXIgZWZmZWN0IG9mIGFjY2xpbWF0aW9uIHRlbXBlcmF0dXJlIGhhcyBiZWVuIGFjY291bnRlZCBmb3IuDQoNCkVxdWF0aW9uIFxAcmVmKGVxOmVxNCkgY2FuIGVxdWl2YWxlbnRseSBiZSBleHByZXNzZWQgYXMgYW4gaW50ZWdyYXRpb24gb3ZlciBub3JtYWxpc2VkIHRlbXBlcmF0dXJlIHNjYWxlcyAoJFx0YXUkKS4gIA0KDQpcYmVnaW57ZXF1YXRpb259DQpcRGVsdGEgdF9yID0gXGZyYWN7MX17XGxhbWJkYX0gXGludF97XHRhdV97YX19XntcdGF1X3tjfX0gZV57XGJldGEgXHRhdX0gZCBcdGF1IChcI2VxOmVxNSkNClxlbmR7ZXF1YXRpb259DQoNCkhlcmUsICRcdGF1X2EkIGlzIGFjY2xpbWF0aW9uIHRlbXBlcmF0dXJlIGFuZCAkXHRhdV9jJCBpcyB1cHBlciB0aGVybWFsIHRvbGVyYW5jZSBsaW1pdCBvbiBub3JtYWxpc2VkIHRlbXBlcmF0dXJlIHNjYWxlcyBhbmQgY29ycmVzcG9uZCB3aXRoICRUX2EkIGFuZCAkVF9jJCBvbiBkZWdyZWUgQ2Vsc2l1cyBzY2FsZXMsIHJlc3BlY3RpdmVseS4gJFxsYW1iZGEkIGlzIGhlYXRpbmcgcmF0ZSAoJmRlZztDKSBvbiBhIG5vcm1hbGlzZWQgdGVtcGVyYXR1cmUgc2NhbGUsIHdoZXJlICRcbGFtYmRhID0gSGVhdGluZyBcc3BhY2UgcmF0ZSAvIFRfSyQgd2l0aCB1bml0cyBvZiB0aW1lXi0xXi4NCg0KKioqDQoNCiMjIENhbGN1bGF0aW5nIHJlc2NhbGVkIGhlYXRpbmcgZHVyYXRpb24gZnJvbSBoZWF0aW5nIHRvbGVyYW5jZQ0KDQpJbnRlZ3JhdGlvbiBvZiBFcXVhdGlvbiBcQHJlZihlcTplcTUpIGdpdmVzIGFuIGV4cHJlc3Npb24gZm9yIHJlc2NhbGVkIGhlYXRpbmcgZHVyYXRpb24gJFxEZWx0YSB0X3IkIHRoYXQgZGVzY3JpYmVzIHRoZSBlZmZlY3Qgb2YgdGhlIG5vbi1saW5lYXIgY2hhbmdlIGluIHBoeXNpb2xvZ2ljYWwgcmF0ZXMgYXMgdGVtcGVyYXR1cmVzIGluY3JlYXNlZCBkdXJpbmcgdGhlIGhlYXRpbmcgYXNzYXksIG9uIG5vcm1hbGlzZWQgdGVtcGVyYXR1cmUgc2NhbGVzIChFcXVhdGlvbiBcQHJlZihlcTplcTdhKSkuDQoNCg0KXGJlZ2lue2VxdWF0aW9ufQ0KXERlbHRhIHRfciA9IGdfXGJldGEgKFxEZWx0YSBcdGF1KSBcZnJhY3tlXntcYmV0YSBcdGF1X2F9fXtcbGFtYmRhfSAoXCNlcTplcTdhKQ0KXGVuZHtlcXVhdGlvbn0NCg0KJFxEZWx0YSBcdGF1JCBpcyBoZWF0aW5nIHRvbGVyYW5jZSBvbiB0aGUgbm9ybWFsaXNlZCB0ZW1wZXJhdHVyZSBzY2FsZSwgd2hlcmUgJFxEZWx0YSBcdGF1ID0gXHRhdV9jIC0gXHRhdV9hJC4gJFxEZWx0YSBcdGF1JCBpcyBub3QgY29ycmVjdGVkIGZvciB0aGUgbm9uLWxpbmVhciB0ZW1wZXJhdHVyZSBkZXBlbmRlbmNlIG9mIHBoeXNpb2xvZ2ljYWwgcmF0ZXMuIFRoZSBmdW5jdGlvbiAkZ19cYmV0YSQgYWNjb3VudHMgZm9yIHRoZSBjaGFuZ2UgaW4gcmVzY2FsZWQgdGVtcGVyYXR1cmUgaW4gdGhlIGhlYXRpbmcgYXNzYXkgdmlhIGludGVncmF0aW9uOg0KDQpcYmVnaW57YWxpZ259DQpnX1xiZXRhICh4KSAmPSBcaW50X3tcdGF1X3thfX1ee1x0YXVfe2N9fSBlXntcYmV0YSB4fSBkeCBcXA0KJj0gXGZyYWN7ZV57XGJldGEgeH0gLSAxfXtcYmV0YX0NCihcI2VxOmVxNmEpDQpcZW5ke2FsaWdufQ0KDQpUaHVzLCBFcXVhdGlvbiBcQHJlZihlcTplcTdhKSBpcyB1c2VkIHRvIGNhbGN1bGF0ZSByZXNjYWxlZCBoZWF0aW5nIGR1cmF0aW9uICRcRGVsdGEgdF9yJCBmcm9tIGEga25vd24gaGVhdGluZyB0b2xlcmFuY2UgKGFzICRIJCBvciAkXERlbHRhIFx0YXUkKS4gTm9ybWFsaXNlZCBoZWF0aW5nIHRvbGVyYW5jZXMgJFxEZWx0YSBcdGF1JCBjYW4gcmVhZGlseSBiZSBjb252ZXJ0ZWQgaW50byBkZWdyZWVzIENlbHNpdXMgdG8gY2FsY3VsYXRlICRIJCBvciB2aWNlIHZlcnNhLiBSZXNjYWxlZCBoZWF0aW5nIGR1cmF0aW9ucyAkXERlbHRhIHRfciQgbWVhc3VyZWQgYXQgdHdvIGFjY2xpbWF0aW9uIHRlbXBlcmF0dXJlcyBhcmUgY29tcGFyYWJsZSB3aXRoaW4gYSBzcGVjaWVzLg0KDQoqKioNCg0KIyMgQ2FsY3VsYXRpbmcgaGVhdGluZyB0b2xlcmFuY2UgZnJvbSByZXNjYWxlZCBoZWF0aW5nIGR1cmF0aW9uDQoNCkNvbnZlcnNlbHksIG5vcm1hbGlzZWQgaGVhdGluZyB0b2xlcmFuY2UgJFxEZWx0YSBcdGF1JCBjYW4gYmUgY2FsY3VsYXRlZCBmcm9tIHJlc2NhbGVkIGhlYXRpbmcgZHVyYXRpb24gJFxEZWx0YSB0X3IkIHVzaW5nIHRoZSBpbnZlcnNlIG9mIEVxdWF0aW9uIFxAcmVmKGVxOmVxNmEpLg0KDQpcYmVnaW57ZXF1YXRpb259DQpcRGVsdGEgXHRhdSA9IGZfXGJldGEgKGVeey1cYmV0YSBcdGF1X3thfX0gXGxhbWJkYSBcRGVsdGEgdF9yKSAoXCNlcTplcTdiKQ0KXGVuZHtlcXVhdGlvbn0NCg0KV2hlcmUgJGZfXGJldGEkIGlzIHRoZSBpbnZlcnNlIG9mICRnX1xiZXRhJCAoRXF1YXRpb24gXEByZWYoZXE6ZXE2YSkpIHRoYXQgYWxzbyBhY2NvdW50cyBmb3IgdGhlIGNoYW5nZSBpbiByZXNjYWxlZCB0ZW1wZXJhdHVyZSBpbiB0aGUgaGVhdGluZyBhc3NheS4NCg0KXGJlZ2lue2FsaWdufQ0KZl9cYmV0YSh4KSAmPSBcZnJhY3tcbG9nICgxICsgXGJldGEgeCl9e1xiZXRhfSA9IDogZ157LTF9X1xiZXRhKHgpDQooXCNlcTplcTZiKQ0KXGVuZHthbGlnbn0NCg0KRXF1YXRpb25zIFxAcmVmKGVxOmVxNmEpIGFuZCBcQHJlZihlcTplcTZiKSBhcHByb2FjaCB0aGUgaWRlbnRpdHkgZm9yICRcYmV0YSB4IFxsbCAxJC4gDQoNClRodXMsIEVxdWF0aW9uIFxAcmVmKGVxOmVxN2IpIGNhbiBiZSB1c2VkIHRvIGNhbGN1bGF0ZSBub3JtYWxpc2VkIGhlYXRpbmcgdG9sZXJhbmNlcyAkXERlbHRhIFx0YXUkIGZyb20gYSBrbm93biByZXNjYWxlZCBoZWF0aW5nIGR1cmF0aW9uICRcRGVsdGEgdF9yJCwgYW5kIHRodXMgY2FuIGJlIHVzZWQgdG8gY2FsY3VsYXRlIGhlYXRpbmcgdG9sZXJhbmNlIGluIGRlZ3JlZXMgQ2Vsc2l1cywgJEgkLg0KDQpFcXVhdGlvbnMgXEByZWYoZXE6ZXE3YSkgYW5kIFxAcmVmKGVxOmVxN2IpIGludm9sdmVzIHR3byBzdGVwczogZmlyc3QgdGhlIGhlYXRpbmcgcmF0ZSBpcyByZXNjYWxlZCBieSB0aGUgdGVybSAkZV57XGJldGEgXHRhdV97YX19JCB0aGF0IGRlcGVuZHMgb24gdGhlIHN0YXJ0aW5nIHRlbXBlcmF0dXJlIG9mIHRoZSBhc3NheSAodG8gY29ycmVjdCBmb3IgYWNjbGltYXRpb24gdGVtcGVyYXR1cmUpLCBzZWNvbmQgRXF1YXRpb25zIFxAcmVmKGVxOmVxNmEpIGFuZCBcQHJlZihlcTplcTZiKSBhY2NvdW50IGZvciB0aGUgY2hhbmdlIGluIHRlbXBlcmF0dXJlIGFzIHRoZSBoZWF0aW5nIGFzc2F5IHByb2dyZXNzZXMgdmlhIGludGVncmF0aW9uIG9mIHRoZSBVbml2ZXJzYWwgVGVtcGVyYXR1cmUgRGVwZW5kZW5jZS4NCg0KUmVzY2FsaW5nIGhlYXRpbmcgZHVyYXRpb25zIGFuZCBoZWF0aW5nIHRvbGVyYW5jZSBpcyBkZXBlbmRlbnQgb24gdGhyZWUgYXNzdW1wdGlvbnM6IDEpIEhlYXRpbmcgdG9sZXJhbmNlIGlzIGFyYml0cmFyaWx5IGRlZmluZWQgd2l0aCByZXNwZWN0IHRvIDAmZGVnO0MsIDIpIGhlYXRpbmcgcmF0ZSBpcyBjb25zdGFudCwgYW5kIDMpIHRoZSBBcnJoZW5pdXMgcmVsYXRpb25zaGlwIGlzIG5vdCBhZmZlY3RlZCBieSB0aGUgcGh5c2lvbG9naWNhbCBzdGF0ZSBvZiB0aGUgb3JnYW5pc20gb3IgdGhlIGV4cGVyaW1lbnRhbCBjb25kaXRpb25zIChpLmUuLCAkRSQgZG9lcyBub3QgY2hhbmdlKS4NCg0KYGBge3IgcmVzY2FsaW5nfSANCiMgZnVuY3Rpb24gZm9yIGRlbHRhIHRfciB0aGF0IHVzZXMgZ19iZXRhX2Z1biAoRXF1YXRpb24gOCkNCmRlbHRhX3RyX2Z1biA8LSBmdW5jdGlvbih0YXVfYSwgdGF1X2MsIGxhbWJkYSl7DQogIGV4cChiZXRhX0sgKiB0YXVfYSkgLyBsYW1iZGEgKiBnX2JldGFfZnVuKHRhdV9jIC0gdGF1X2EpDQp9DQoNCiMgZnVuY3Rpb24gZyBvZiB4IGFuZCB0aGUgY29uc3RhbnQgYmV0YSAoRXF1YXRpb24gOSkNCmdfYmV0YV9mdW4gPC0gZnVuY3Rpb24oeCl7KGV4cChiZXRhX0sgKiB4KSAtIDEpIC8gYmV0YV9LfQ0KDQojIGZ1bmN0aW9uIGYgb2YgeCBhbmQgdGhlIGNvbnN0YW50IGJldGEgKEVxdWF0aW9uIDExKQ0KZl9iZXRhX2Z1biA8LSBmdW5jdGlvbih4KXtsb2coMSArIGJldGFfSyAqIHgpIC8gYmV0YV9LfQ0KYGBgDQoNCldlIGNhbGN1bGF0ZWQgaGVhdGluZyB0b2xlcmFuY2VzIGF0IHRoZSB0d28gYWNjbGltYXRpb24gdGVtcGVyYXR1cmVzIG9uIHRoZSBub3JtYWxpc2VkIHRlbXBlcmF0dXJlIHNjYWxlLiBXZSB0aGVuIGFwcGx5IEVxdWF0aW9uIFxAcmVmKGVxOmVxN2EpIHRvIGNhbGN1bGF0ZSByZXNjYWxlZCBoZWF0aW5nIGR1cmF0aW9uICRcRGVsdGEgdF9yJC4NCg0KYGBge3IgcmVzY2FsZX0NCiMgbm9ybWFsaXNlIFRhLCBUYyBhbmQgaGVhdGluZyByYXRlIGJ5IFRrLCBjYWxjdWxhdGUgbm9ybWFsaXNlZCBoZWF0aW5nIHRvbGVyYW5jZQ0KQVJSIDwtIEFSUiAlPiUgDQogIG11dGF0ZSh0YXVfYV9sb3cgPSB0YV9sb3cgLyBUaywNCiAgICAgICAgIHRhdV9hX2hpZ2ggPSB0YV9oaWdoIC8gVGssDQogICAgICAgICB0YXVfY19sb3cgPSB0Y19sb3cgLyBUaywNCiAgICAgICAgIHRhdV9jX2hpZ2ggPSB0Y19oaWdoIC8gVGssDQogICAgICAgICBsYW1iZGEgPSBoZWF0aW5nX3JhdGUgLyBUaywNCiAgICAgICAgIGRlbHRhX3RhdV9sb3cgPSB0YXVfY19sb3cgLSB0YXVfYV9sb3csDQogICAgICAgICBkZWx0YV90YXVfaGlnaCA9IHRhdV9jX2hpZ2ggLSB0YXVfYV9oaWdoKQ0KDQojIENhbGN1bGF0ZSByZXNjYWxlZCBoZWF0aW5nIGR1cmF0aW9uIGZvciBsb3dlciBhY2NsaW1hdGlvbiB0ZW1wZXJhdHVyZXMgKEVxdWF0aW9uIDgpDQpBUlIgPC0gQVJSICU+JSANCiAgbXV0YXRlKGRlbHRhX3RyX2xvdyA9IHBtYXBfZGJsKGxpc3QodGF1X2EgPSB0YXVfYV9sb3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGF1X2MgPSB0YXVfY19sb3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFtYmRhID0gbGFtYmRhKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVsdGFfdHJfZnVuKSkNCg0KIyBDYWxjdWxhdGUgcmVzY2FsZWQgaGVhdGluZyBkdXJhdGlvbiBmb3IgaGlnaGVyIGFjY2xpbWF0aW9uIHRlbXBlcmF0dXJlcyAoRXF1YXRpb24gOCkNCkFSUiA8LSBBUlIgJT4lIA0KICBtdXRhdGUoZGVsdGFfdHJfaGlnaCA9IHBtYXBfZGJsKGxpc3QodGF1X2EgPSB0YXVfYV9oaWdoLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0YXVfYyA9IHRhdV9jX2hpZ2gsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhbWJkYSA9IGxhbWJkYSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZWx0YV90cl9mdW4pKQ0KYGBgDQoNClJlc2NhbGVkIGhlYXRpbmcgZHVyYXRpb25zICRcRGVsdGEgdF9yJCBhcmUgaW5mbHVlbmNlZCBieSBoZWF0aW5nIHJhdGUgd2l0aCBsYXJnZXIgcmVzY2FsZWQgaGVhdGluZyBkdXJhdGlvbnMgYXNzb2NpYXRlZCB3aXRoIHNsb3dlciBoZWF0aW5nIHJhdGVzIChGaWd1cmUgXEByZWYoZmlnOmhlYXQtZHVyKSkuIFRoaXMgZGVwZW5kZW5jeSB3aXRoIGhlYXRpbmcgcmF0ZSBpcyBleHBsb3JlZCBbYmVsb3ddKCNoZWF0aW5nLXJhdGUpLg0KDQpgYGB7ciBoZWF0LWR1ciwgZWNobyA9IEZBTFNFLCBmaWcuY2FwID0gIlJlc2NhbGVkIGhlYXRpbmcgZHVyYXRpb24gYXQgdGhlIGxvd2VyIGFuZCBoaWdoZXIgYWNjbGltYXRpb24gdGVtcGVyYXR1cmUgb24gTG9nMTAgYXhlcyBoYXZlIGEgc3Ryb25nIGRlcGVuZGVuY3kgd2l0aCBoZWF0aW5nIHJhdGUgKGNvbG91cnMpLiJ9DQpyZXNjYWxlZF9kdXJhdGlvbiA8LSBnZ3Bsb3QoZGF0YSA9IEFSUiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSBkZWx0YV90cl9sb3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gZGVsdGFfdHJfaGlnaCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbCA9IGhlYXRpbmdfcmF0ZSkpICsNCiAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwLCBsdHkgPSAyLCBhbHBoYSA9IDAuNikgKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFLCBjb2wgPSAxKSArDQogIGdlb21fcG9pbnQoKSArDQogIHNjYWxlX3hfY29udGludW91cyh0cmFucyA9ICJsb2cxMCIsIGxhYmVscyA9IGZ1bmN0aW9uKHgpIHJvdW5kKHgpLCBleHBhbmQgPSBjKDAsMCksIGxpbWl0cyA9IGMoMC4xLCAxMDAwMCkpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKHRyYW5zID0gImxvZzEwIiwgbGFiZWxzID0gZnVuY3Rpb24oeCkgcm91bmQoeCksIGV4cGFuZCA9IGMoMCwwKSwgbGltaXRzID0gYygwLjEsIDEwMDAwKSkgKw0KICBjb29yZF9lcXVhbCgpICsNCiAgbGFicyh4ID0gZXhwcmVzc2lvbigiTG93ZXIgYWNjbGltYXRpb24gdGVtcGVyYXR1cmUgIiAqIERlbHRhICogdFtyXSksDQogICAgICAgeSA9IGV4cHJlc3Npb24oIkhpZ2hlciBhY2NsaW1hdGlvbiB0ZW1wZXJhdHVyZSAiICogRGVsdGEgKiB0W3JdKSkgKw0KICBnZ3RpdGxlKGV4cHJlc3Npb24ocGFzdGUoIlJlc2NhbGVkIGhlYXRpbmcgZHVyYXRpb24sICIpICogRGVsdGEgKiB0W3JdKSkgKw0KICBzY2FsZV9jb2xvdXJfdmlyaWRpc19jKG5hbWUgPSBleHByZXNzaW9uKCJIZWF0aW5nIHJhdGUgKFx1MDBCMEMgaCIgXi0xICogIikiKSwgdHJhbnMgPSAibG9nMTAiLCBsYWJlbHMgPSBmdW5jdGlvbih4KSBzaWduaWYoeCkpDQoNCnJlc2NhbGVkX2R1cmF0aW9uDQpgYGANCg0KKioqDQoNCiMjIERpbWVuc2lvbmxlc3MgcmVzY2FsZWQgaGVhdGluZyBkdXJhdGlvbg0KDQpBIHNpbXBsZSB3YXkgb2YgdmlzdWFsaXNpbmcgcmVzY2FsZWQgaGVhdGluZyBkdXJhdGlvbiB3aXRob3V0IGl0cyBkZXBlbmRlbmN5IG9uIGhlYXRpbmcgcmF0ZSBpcyB0byBtdWx0aXBseSByZXNjYWxlZCBoZWF0aW5nIGR1cmF0aW9uIGJ5IGhlYXRpbmcgcmF0ZSB0byBnaXZlIGEgZGltZW5zaW9ubGVzcyBxdWFudGl0eSAoJEhfciQpLiBUaGlzIGRpbWVuc2lvbmxlc3MgcXVhbnRpdHkgZGVtb25zdHJhdGVzIHRoZSBzdHJvbmcgcmVsYXRpb25zaGlwIGJldHdlZW4gcmVzY2FsZWQgaGVhdGluZyBkdXJhdGlvbnMgYXQgZWl0aGVyIGFjY2xpbWF0aW9uIHRlbXBlcmF0dXJlLCByZWdhcmRsZXNzIG9mIGhlYXRpbmcgcmF0ZSAoRmlndXJlIFxAcmVmKGZpZzpoZWF0LXRvbCkpLiBIb3dldmVyLCB0aGlzIGRpbWVuc2lvbmxlc3MgYW5hbHlzaXMgaGFzIGxpbWl0ZWQgdXRpbGl0eSBpbiB1bmRlcnN0YW5kaW5nIHRlbXBlcmF0dXJlLXJhdGUtdGltZSBkeW5hbWljcyBjb21wYXJlZCB3aXRoICRcRGVsdGEgdF9yJC4gJFxEZWx0YSB0X3IkIGluY2x1ZGVzIHRoZSBpbnRlZ3JhdGlvbiBvZiB0aGUgbm9uLWxpbmVhciB0ZW1wZXJhdHVyZSBkZXBlbmRlbmN5IG9mIGJpb2xvZ2ljYWwgcmF0ZXMgYW5kIGlzIG91ciBtYWluIGFpbSBvZiBvdXIgYW5hbHlzaXMuDQoNCmBgYHtyIGhlYXQtdG9sLCBlY2hvID0gRkFMU0UsIGZpZy5jYXAgPSAiRGltZW5zaW9ubGVzcyByZXNjYWxlZCBoZWF0aW5nIGR1cmF0aW9ucyBhdCB0aGUgbG93ZXIgYW5kIGhpZ2hlciBhY2NsaW1hdGlvbiB0ZW1wZXJhdHVyZXMgb24gTG9nMTAgYXhlcy4ifQ0KcmVzY2FsZWRfdG9sZXJhbmNlcyA8LSBnZ3Bsb3QoZGF0YSA9IEFSUiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSBleHAoYmV0YV9LICogdGF1X2FfbG93KSAqIGdfYmV0YV9mdW4odGF1X2NfbG93IC0gdGF1X2FfbG93KSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBleHAoYmV0YV9LICogdGF1X2FfaGlnaCkgKiBnX2JldGFfZnVuKHRhdV9jX2hpZ2ggLSB0YXVfYV9oaWdoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sID0gaGVhdGluZ19yYXRlKSkgKyANCiAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwLCBsdHkgPSAyLCBhbHBoYSA9IDAuNikgKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFLCBjb2wgPSAxKSArIA0KICBnZW9tX3BvaW50KCkgKyANCiAgc2NhbGVfeF9jb250aW51b3VzKHRyYW5zID0gImxvZzEwIiwgZXhwYW5kID0gYygwLDApKSArDQogIHNjYWxlX3lfY29udGludW91cyh0cmFucyA9ICJsb2cxMCIsIGV4cGFuZCA9IGMoMCwwKSkgKw0KICBjb29yZF9lcXVhbCgpICsgIA0KICBzY2FsZV9jb2xvdXJfdmlyaWRpc19jKG5hbWUgPSBleHByZXNzaW9uKCJIZWF0aW5nIHJhdGUgKFx1MDBCMEMgaCIgXi0xICogIikiKSwgdHJhbnMgPSAibG9nMTAiLCBsYWJlbHMgPSBmdW5jdGlvbih4KSBzaWduaWYoeCkpICsNCiAgbGFicyh4ID0gZXhwcmVzc2lvbigiTG93ZXIgYWNjbGltYXRpb24gdGVtcGVyYXR1cmUgIiAqIEhbcl0pLA0KICAgICAgIHkgPSBleHByZXNzaW9uKCJIaWdoZXIgYWNjbGltYXRpb24gdGVtcGVyYXR1cmUgIiAqIEhbcl0pKSArDQogIGdndGl0bGUoZXhwcmVzc2lvbihwYXN0ZSgiRGltZW5zaW9ubGVzcyByZXNjYWxlZCBoZWF0aW5nIGR1cmF0aW9uLCAiICogSFtyXSkpKSANCg0KcmVzY2FsZWRfdG9sZXJhbmNlcw0KYGBgDQoNCioqKg0KDQojIFNlbnNpdGl2aXR5IG9mIGFjdGl2YXRpb24gZW5lcmd5DQoNCkludHJhc3BlY2lmaWMgYWN0aXZhdGlvbiBlbmVyZ3kgb2YgdmFyaW91cyB0aGVybWFsbHktZGVwZW5kZW50IHRyYWl0cyByYW5nZXMgYmV0d2VlbiAwLjIgYW5kIDEuMiB3aXRoIGEgbWVkaWFuIG9mIDAuNTUgZVYgW0BEZWxsMjAxMV0uIENoYW5naW5nIGFjdGl2YXRpb24gZW5lcmd5IGFuZCB0aHVzICRcYmV0YSQgZG9lcyBub3QgbWVhbmluZ2Z1bGx5IGNoYW5nZSB0aGUgcmVwb3J0ZWQgcGF0dGVybnMgKEZpZ3VyZSBcQHJlZihmaWc6c2Vuc2l0aXZpdHkpKS4NCg0KYGRlbHRhX3RyX2dlbmAgaXMgYSBnZW5lcmFsaXNlZCBmdW5jdGlvbiB0byByZXNjYWxlIGhlYXRpbmcgdG9sZXJhbmNlIHdpdGggJEUkIGFzIGEgdmFyaWFibGUuICRcYmV0YSQgdmFsdWVzIGFyZSBjYWxjdWxhdGVkIGZvciBlYWNoIHZhbHVlIG9mICRFJC4NCg0KYGBge3IgYmlvdGltZV9nZW59DQojIEdlbmVyYWxpc2VkIGZ1bmN0aW9uDQpkZWx0YV90cl9nZW4gPC0gZnVuY3Rpb24oeCwgZXYsIGsgPSA4LjYxNzMzKjEwXi01LCBUayA9IDI3My4xNSkgeyAjIGV2IGlzIGFjdGl2YXRpb24gZW5lcmd5DQogIA0KICAjIGNhbGN1bGF0ZSBiZXRhIEsgY29uc3RhbnQNCiAgYmV0YV9LX3NlbnNpIDwtIGV2IC8gKGsgKiBUaykNCiAgDQogICMgZnVuY3Rpb24gZm9yIGRlbHRhIHRyIHRoYXQgdXNlcyBnX2JldGFfZnVuIChFcXVhdGlvbiA4KQ0KICBkZWx0YV90cl9nZW4gPC0gZnVuY3Rpb24odGF1X2EsIHRhdV9jLCBsYW1iZGEpew0KICAgIGV4cChiZXRhX0tfc2Vuc2kgKiB0YXVfYSkgLyBsYW1iZGEgKiBnX2JldGFfZnVuX2dlbih0YXVfYyAtIHRhdV9hKQ0KICB9DQoNCiAgIyBmdW5jdGlvbiBmIG9mIHggYW5kIHRoZSBjb25zdGFudCBiZXRhDQogIGZfYmV0YV9mdW5fZ2VuIDwtIGZ1bmN0aW9uKHgpe2xvZygxICsgYmV0YV9LX3NlbnNpICogeCkgLyBiZXRhX0tfc2Vuc2l9DQogIA0KICAjIGZ1bmN0aW9uIGcgb2YgeCBhbmQgdGhlIGNvbnN0YW50IGJldGENCiAgZ19iZXRhX2Z1bl9nZW4gPC0gZnVuY3Rpb24oeCl7KGV4cChiZXRhX0tfc2Vuc2kgKiB4KSAtIDEpIC8gYmV0YV9LX3NlbnNpfQ0KICANCiAgIyBub3JtYWxpc2UgVGEsIFRjIGFuZCBoZWF0aW5nIHJhdGUgYnkgVGsNCiAgeCA8LSB4ICU+JSAjIENhbGN1bGF0ZSBoZWF0aW5nIHJhdGUgYXMgbGFtYmRhDQogICAgbXV0YXRlKHRhdV9hX2xvdyA9IHRhX2xvdyAvIFRrLA0KICAgICAgICAgICB0YXVfYV9oaWdoID0gdGFfaGlnaCAvIFRrLA0KICAgICAgICAgICB0YXVfY19sb3cgPSB0Y19sb3cgLyBUaywNCiAgICAgICAgICAgdGF1X2NfaGlnaCA9IHRjX2hpZ2ggLyBUaywNCiAgICAgICAgICAgbGFtYmRhID0gaGVhdGluZ19yYXRlIC8gVGssDQogICAgICAgICAgIGRlbHRhX3RhdV9sb3cgPSB0YXVfY19sb3cgLSB0YXVfYV9sb3csICMgY2FsY3VsYXRlIGRlbHRhIHRhdXMNCiAgICAgICAgICAgZGVsdGFfdGF1X2hpZ2ggPSB0YXVfY19oaWdoIC0gdGF1X2FfaGlnaCkNCg0KICAjIG1hcCBvdmVyIGxvdyB0ZW1wZXJhdHVyZSBleHBlcmltZW50cw0KICB4IDwtIHggJT4lIA0KICAgIG11dGF0ZShkZWx0YV90cl9sb3cgPSBwbWFwX2RibChsaXN0KHRhdV9hID0gdGF1X2FfbG93LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGF1X2MgPSB0YXVfY19sb3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYW1iZGEgPSBsYW1iZGEpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlbHRhX3RyX2dlbikpDQogIA0KICAjIGRvIHRoZSBzYW1lIHdpdGggdGhlIGhpZ2ggdGVtcCBhY2NsaW1hdGVkIGRhdGENCiAgeCA8LSB4ICU+JSANCiAgICBtdXRhdGUoZGVsdGFfdHJfaGlnaCA9IHBtYXBfZGJsKGxpc3QodGF1X2EgPSB0YXVfYV9oaWdoLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRhdV9jID0gdGF1X2NfaGlnaCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYW1iZGEgPSBsYW1iZGEpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZWx0YV90cl9nZW4pKQ0KICANCiAgIyBBZGQgcHJlZGljdGlvbnMgb2YgaGlnaCBmcm9tIGxvdyBhbmQgY29udmVyc2VseSBsb3cgZnJvbSBoaWdoDQogIHggPC0geCAlPiUgDQogICAgbXV0YXRlKGFjdGl2YXRpb24gPSBldiwNCiAgICAgICAgICAgZGVsdGFfdGF1X2hpZ2hfaGF0ID0gZl9iZXRhX2Z1bl9nZW4oZXhwKGJldGFfS19zZW5zaSAqICh0YXVfYV9sb3cgLSB0YXVfYV9oaWdoKSkgKiBnX2JldGFfZnVuX2dlbihkZWx0YV90YXVfbG93KSksICMgcHJlZGljdCBoaWdoIGZyb20gbG93DQogICAgICAgICAgIGRlbHRhX3RhdV9sb3dfaGF0ID0gZl9iZXRhX2Z1bl9nZW4oZXhwKGJldGFfS19zZW5zaSAqICh0YXVfYV9oaWdoIC0gdGF1X2FfbG93KSkgKiBnX2JldGFfZnVuX2dlbihkZWx0YV90YXVfaGlnaCkpKSAjIHByZWRpY3QgbG93IGZyb20gaGlnaA0KDQogIHJldHVybih4KSAjIGFzIGxpc3QNCn0NCmBgYA0KDQpUaGUgZGF0YXNldCBpcyByZXBsaWNhdGVkIGZvciBhIHZlY3RvciBvZiBhY3RpdmF0aW9uIGVuZXJnaWVzLCB0aGVuIHRoZSBgZGVsdGFfdHJfZ2VuYCBmdW5jdGlvbiBpcyBhcHBsaWVkIHRvIGVhY2ggZWxlbWVudCBvZiB0aGUgbGlzdCB1c2luZyBgbWFwcGx5YC4NCg0KYGBge3Igc2Vuc2l0aXZpdHksIGZpZy5jYXA9ICJWYXJpYXRpb24gaW4gYWN0aXZhdGlvbiBlbmVyZ3kgKGVWKS4gT2JzZXJ2YXRpb25zIChwb2ludHMpIHdpdGggYSBmaXR0ZWQgbGluZWFyIG1vZGVsIChzb2xpZCBsaW5lKSBmYWxsIGFsb25nIHRoZSBpZGVudGl0eSBsaW5lIChkYXNoZWQgbGluZSkuIiwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTd9DQojIGRlZmluZSBhY3RpdmF0aW9uIGVuZXJnaWVzDQphY3RpdmF0aW9uIDwtIHNlcSgwLjIsIDEuMiwgMC4yKQ0KIyByZXBlYXQgQVJSIGRhdGFzZXQgb3ZlciBsZW5ndGggb2YgYWN0aXZhdGlvbiBlbmVyZ2llcw0KQVJSX2xpc3QgPC0gcmVwbGljYXRlKGxlbmd0aChhY3RpdmF0aW9uKSwgQVJSLCBzaW1wbGlmeSA9IEZBTFNFKQ0KIyBpbnRlZ3JhdGUgdW5kZXIgY3VydmUsIG1lcmdlIHRvIHNpbmdsZSBkYXRhIGZyYW1lDQpBUlJfbGlzdCA8LSBkby5jYWxsKHJiaW5kLCBtYXBwbHkoQVJSX2xpc3QsIEZVTiA9IGRlbHRhX3RyX2dlbiwgZXYgPSBhY3RpdmF0aW9uLCBTSU1QTElGWSA9IEZBTFNFKSkNCg0KIyBwbG90DQpzZW5zaV9wbG90IDwtIGdncGxvdChkYXRhID0gQVJSX2xpc3QsIA0KICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSBkZWx0YV90cl9sb3csIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBkZWx0YV90cl9oaWdoKSkgKyANCiAgZ2VvbV9wb2ludChjb2wgPSAiZ3JleSIpICsgDQogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UsIGNvbCA9ICJibGFjayIpICsgDQogIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gMCwgbHR5ID0gMiwgYWxwaGEgPSAwLjYpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKGV4cGFuZCA9IGMoMC4wMSwwKSwgdHJhbnMgPSAibG9nMTAiLCBsYWJlbHMgPSBmdW5jdGlvbih4KSBmb3JtYXQoeCwgc2NpZW50aWZpYyA9IEZBTFNFKSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLjAxLDApLCB0cmFucyA9ICJsb2cxMCIsIGxhYmVscyA9IGZ1bmN0aW9uKHgpIGZvcm1hdCh4LCBzY2llbnRpZmljID0gRkFMU0UpKSArDQogICMgc2NhbGVfY29sb3VyX3ZpcmlkaXNfYyhuYW1lID0gIkFjdGl2YXRpb24gZW5lcmd5IikgKw0KICBmYWNldF93cmFwKC5+YWN0aXZhdGlvbiwgbmNvbD0zLCBzY2FsZXMgPSAiZnJlZSIpICsNCiAgbGFicyh4ID0gZXhwcmVzc2lvbigiTG93ZXIgdGVtcGVyYXR1cmUgcmVzY2FsZWQgaGVhdGluZyBkdXJhdGlvbiIpLCB5ID0gZXhwcmVzc2lvbigiSGlnaGVyIHRlbXBlcmF0dXJlIHJlc2NhbGVkIGhlYXRpbmcgZHVyYXRpb24iKSkgKw0KICB0aGVtZV9jbGFzc2ljKGJhc2Vfc2l6ZSA9IDEyKQ0KDQpzZW5zaV9wbG90DQpgYGANCg0KKioqDQoNCiMgUHJlZGljdGluZyBoZWF0aW5nIHRvbGVyYW5jZSBmb3IgYSBuZXcgYWNjbGltYXRpb24gdGVtcGVyYXR1cmUNCg0KV2UgY2FuIHVzZSByZXNjYWxlZCBoZWF0aW5nIGR1cmF0aW9ucyB0byBwcmVkaWN0IGhlYXRpbmcgdG9sZXJhbmNlcyBtZWFzdXJlZCBhdCBhIGRpZmZlcmVudCBhY2NsaW1hdGlvbiB0ZW1wZXJhdHVyZSAoJGEyJCkgZnJvbSBhIGtub3duIGFjY2xpbWF0aW9uIHRlbXBlcmF0dXJlICgkYTEkKSBhbmQgaGVhdGluZyB0b2xlcmFuY2UuIA0KDQpgYGB7ciBwcmVkLWZ1bn0NCiMgQWRkIHByZWRpY3Rpb25zIG9mIGhpZ2ggZnJvbSBsb3cgYW5kIGNvbnZlcnNlbHkgbG93IGZyb20gaGlnaA0KQVJSIDwtIEFSUiAlPiUgDQogIG11dGF0ZShkZWx0YV90YXVfaGlnaF9oYXQgPSBmX2JldGFfZnVuKGV4cChiZXRhX0sgKiAodGF1X2FfbG93IC0gdGF1X2FfaGlnaCkpICogZ19iZXRhX2Z1bihkZWx0YV90YXVfbG93KSksICMgcHJlZGljdCBoaWdoIGZyb20gbG93IChFcXVhdGlvbiAxMikNCiAgICAgICAgIGRlbHRhX3RhdV9sb3dfaGF0ID0gZl9iZXRhX2Z1bihleHAoYmV0YV9LICogKHRhdV9hX2hpZ2ggLSB0YXVfYV9sb3cpKSAqIGdfYmV0YV9mdW4oZGVsdGFfdGF1X2hpZ2gpKSkgIyBwcmVkaWN0IGxvdyBmcm9tIGhpZ2ggKEVxdWF0aW9uIDEzKQ0KYGBgDQoNCiMjIEFzc3VtaW5nIGhlYXRpbmcgdG9sZXJhbmNlcyBhcmUgdGhlIHNhbWUNCg0KVGhlIHNpbXBsZXN0IG1vZGVsIHRvIHByZWRpY3QgYSBuZXcgaGVhdGluZyB0b2xlcmFuY2UgZnJvbSBhIG5ldyBhY2NsaW1hdGlvbiB0ZW1wZXJhdHVyZSBpcyB0byBhc3N1bWUgdGhhdCBoZWF0aW5nIHRvbGVyYW5jZXMgYXQgdGhlIGhpZ2hlciBhbmQgbG93ZXIgYWNjbGltYXRpb24gdGVtcGVyYXR1cmUgZXhwZXJpbWVudHMgYXJlIHRoZSBzYW1lLiBGb3IgZXhhbXBsZSwgd2UgY2FuIHByZWRpY3QgdGhlIGhlYXRpbmcgdG9sZXJhbmNlIGF0IHRoZSBoaWdoZXIgYWNjbGltYXRpb24gdGVtcGVyYXR1cmUgJFxEZWx0YSBcdGF1IChcdGF1X3thMn0pJCwgZnJvbSB0aGUgbG93ZXIgYWNjbGltYXRpb24gdGVtcGVyYXR1cmUsICRcRGVsdGEgXHRhdSAoXHRhdV97YTF9KSQuDQoNClxiZWdpbntlcXVhdGlvbn0NClxEZWx0YSBcdGF1IChcdGF1X3thMn0pIFxhcHByb3ggXERlbHRhIFx0YXUgKFx0YXVfe2ExfSkgKFwjZXE6ZXE4KQ0KXGVuZHtlcXVhdGlvbn0NCg0KYGBge3IgcHJlZDEsIGZpZy5jYXAgPSAiUHJlZGljdGluZyBoaWdoZXIgYWNjbGltYXRpb24gdGVtcGVyYXR1cmUgaGVhdGluZyB0b2xlcmFuY2UgZnJvbSBsb3dlciBhY2NsaW1hdGlvbiB0ZW1wZXJhdHVyZSBoZWF0aW5nIHRvbGVyYW5jZSBhc3N1bWluZyBoZWF0aW5nIHRvbGVyYW5jZSBpcyB0aGUgc2FtZS4ifQ0KcHJlZDEgPC0gZ2dwbG90KGRhdGEgPSBBUlIsDQogICAgICAgbWFwcGluZyA9IGFlcyh4ID0gZGVsdGFfdGF1X2xvdyAqIFRrLA0KICAgICAgICAgICAgICAgICAgICAgeSA9IGRlbHRhX3RhdV9oaWdoICogVGspKSArIA0KICBnZW9tX3BvaW50KCkgKyANCiAgZ2VvbV9hYmxpbmUoaW50ZXJjZXB0ID0gMCwgc2xvcGUgPSAxLCBsdHkgPSAyLCBhbHBoYSA9IDAuNikgKyANCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSwgY29sID0gImRhcmtncmV5IikgKyANCiAgbGFicyh4ID0gZXhwcmVzc2lvbigiUHJlZGljdGVkIGhlYXRpbmcgdG9sZXJhbmNlIChcdTAwQjBDKSIpLA0KICAgICAgIHkgPSBleHByZXNzaW9uKCJPYnNlcnZlZCBoZWF0aW5nIHRvbGVyYW5jZSAoXHUwMEIwQykiKSkgKyANCiAgc2NhbGVfeF9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwwKSwgbGltaXRzID0gYygwLCA0MCkpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwwKSwgbGltaXRzID0gYygwLCA0MCkpDQoNCnByZWQxDQpgYGANCg0KQXNzdW1pbmcgaGVhdGluZyB0b2xlcmFuY2UgaXMgdGhlIHNhbWUgYXQgYm90aCBhY2NsaW1hdGlvbiB0ZW1wZXJhdHVyZXMgb3ZlcmVzdGltYXRlcyB0aGUgaGVhdGluZyB0b2xlcmFuY2UgYXQgdGhlIGhpZ2hlciB0ZW1wZXJhdHVyZSAoRmlndXJlIFxAcmVmKGZpZzpwcmVkMSkpLg0KDQojIyBDb3JyZWN0IGZvciBhY2NsaW1hdGlvbiB0ZW1wZXJhdHVyZSBkaWZmZXJlbmNlDQoNCk5leHQsIHdlIGNhbiBjb3JyZWN0IGZvciB0aGUgZGlmZmVyZW5jZSBpbiBhY2NsaW1hdGlvbiB0ZW1wZXJhdHVyZXMgYnkgcmVzY2FsaW5nIGJ5IHRoZSBhY2NsaW1hdGlvbiB0ZW1wZXJhdHVyZSB2aWEgJGVee1xiZXRhIChcdGF1X3thMX0gLSBcdGF1X3thMn0pfSQ6DQoNClxiZWdpbntlcXVhdGlvbn0NClxEZWx0YSBcdGF1IChcdGF1X3thMn0pIFxhcHByb3ggXERlbHRhIFx0YXUgKFx0YXVfe2ExfSkgZV57XGJldGEgKFx0YXVfe2ExfSAtIFx0YXVfe2EyfSl9DQooXCNlcTplcTkpDQpcZW5ke2VxdWF0aW9ufQ0KDQpgYGB7ciBwcmVkMiwgZmlnLmNhcCA9ICJQcmVkaWN0aW5nIGhpZ2hlciBhY2NsaW1hdGlvbiB0ZW1wZXJhdHVyZSBoZWF0aW5nIHRvbGVyYW5jZSBjb3JyZWN0aW5nIGZvciBhY2NsaW1hdGlvbiB0ZW1wZXJhdHVyZSJ9DQpwcmVkMiA8LSBwcmVkMSArIGFlcyh4ID0gKGRlbHRhX3RhdV9sb3cgKiBleHAoYmV0YV9LICogKHRhdV9hX2xvdyAtIHRhdV9hX2hpZ2gpKSkgKiBUaykgKw0KICBsYWJzKHggPSBleHByZXNzaW9uKCJQcmVkaWN0ZWQgaGVhdGluZyB0b2xlcmFuY2UgKFx1MDBCMEMpIikpIA0KcHJlZDINCmBgYA0KDQpVc2luZyBFcXVhdGlvbiBcQHJlZihlcTplcTkpIHVuZGVyZXN0aW1hdGVzIHRoZSBoZWF0aW5nIHRvbGVyYW5jZSBhdCB0aGUgaGlnaGVyIGFjY2xpbWF0aW9uIHRlbXBlcmF0dXJlIChGaWd1cmUgXEByZWYoZmlnOnByZWQyKSkuIA0KDQojIyBBY2NvdW50IGZvciBkaWZmZXJlbmNlIGluIGFjY2xpbWF0aW9uIHRlbXBlcmF0dXJlIGFuZCBjaGFuZ2UgaW4gdGVtcGVyYXR1cmUNCg0KRmluYWxseSwgd2UgY2FuIGRlcml2ZSBhIG1vcmUgcHJlY2lzZSBwcmVkaWN0aW9uIHRoYXQgZnVsbHkgYWNjb3VudHMgZm9yIHRoZSBjaGFuZ2UgdG8gaGVhdGluZyB0b2xlcmFuY2UgdGhhdCBvY2N1cnMgZHVyaW5nIHRoZSBleHBlcmltZW50IGFzIHRoZSB0ZW1wZXJhdHVyZSBpcyBpbmNyZWFzZWQgdXNpbmcgRXF1YXRpb24gXEByZWYoZXE6ZXExMCkuDQoNClxiZWdpbntlcXVhdGlvbn0NClxEZWx0YSBcdGF1IChcdGF1X3thMn0pIFxhcHByb3ggZl9cYmV0YSBcYmlnKGVee1xiZXRhIChcdGF1X3thMX0gLSBcdGF1X3thMn0pfSBnX1xiZXRhKFxEZWx0YSBcdGF1KFx0YXVfe2ExfSkpIFxiaWcpDQooXCNlcTplcTEwKQ0KXGVuZHtlcXVhdGlvbn0NCg0KYGBge3IgcHJlZDMsIGZpZy5jYXAgPSAiQ29ycmVjdGlvbiBmb3IgYWNjbGltYXRpb24gdGVtcGVyYXR1cmUgYW5kIGNoYW5nZSBpbiB0ZW1wZXJhdHVyZSBvdmVyIHRpbWUgdG8gcHJlZGljdCBoZWF0aW5nIHRvbGVyYW5jZSBhdCB0aGUgaGlnaGVyIGFjY2xpbWF0aW9uIHRlbXBlcmF0dXJlIGZyb20gdGhlIGxvd2VyIGFjY2xpbWF0aW9uIHRlbXBlcmF0dXJlLiJ9DQpwcmVkMyA8LSBwcmVkMSArIGFlcyh4ID0gZGVsdGFfdGF1X2hpZ2hfaGF0ICogVGspICsgDQogIGxhYnMoeCA9IGV4cHJlc3Npb24oIlByZWRpY3RlZCBoZWF0aW5nIHRvbGVyYW5jZSAoXHUwMEIwQykiKSkNCnByZWQzDQpgYGANCg0KYGBge3IgcHJlZDMtbG0sIGluY2x1ZGU9RkFMU0V9DQojIGhpZ2ggZnJvbSBsb3cNCnByZWRfaGlnaF9sb3cgPC0gbG0oZGVsdGFfdGF1X2hpZ2ggfiBkZWx0YV90YXVfaGlnaF9oYXQsIA0KICAgICAgICAgICAgICAgICAgIG9mZnNldCA9IGRlbHRhX3RhdV9oaWdoX2hhdCwgDQogICAgICAgICAgICAgICAgICAgZGF0YSA9IEFSUikNCmBgYA0KDQpUaGUgJFJeMiQgaXMgYHIgcm91bmQoc3VtbWFyeShwcmVkX2hpZ2hfbG93KSRyLnNxdWFyZWQsIDQpKjEwMGAlLiBBbmQgYXMgd2UgY2FuIHByZWRpY3QgaGVhdGluZyB0b2xlcmFuY2UgYXQgdGhlIGhpZ2hlciBhY2NsaW1hdGlvbiB0ZW1wZXJhdHVyZSBmcm9tIHRoZSBsb3dlciBhY2NsaW1hdGlvbiB0ZW1wZXJhdHVyZSBpbiBGaWd1cmUgXEByZWYoZmlnOnByZWQzKSwgc28gd2UgY2FuIGFsc28gcHJlZGljdCBoZWF0aW5nIHRvbGVyYW5jZSBhdCB0aGUgbG93ZXIgYWNjbGltYXRpb24gdGVtcGVyYXR1cmUgZnJvbSBoZWF0aW5nIHRvbGVyYW5jZSBhdCB0aGUgaGlnaGVyIHRlbXBlcmF0dXJlIHVzaW5nIEVxdWF0aW9uIFxAcmVmKGVxOmVxMTBiKSAoRmlndXJlIFxAcmVmKGZpZzpwcmVkNCkpLg0KDQpcYmVnaW57ZXF1YXRpb259DQpcRGVsdGEgXHRhdSAoXHRhdV97YTF9KSBcYXBwcm94IGZfXGJldGEgXGJpZyhlXntcYmV0YSAoXHRhdV97YTJ9IC0gXHRhdV97YTF9KX0gZ19cYmV0YShcRGVsdGEgXHRhdShcdGF1X3thMn0pKSBcYmlnKQ0KKFwjZXE6ZXExMGIpDQpcZW5ke2VxdWF0aW9ufQ0KDQpgYGB7ciBwcmVkNCwgZmlnLmNhcCA9ICJQcmVkaWN0aW5nIGxvd2VyIHRlbXBlcmF0dXJlIGhlYXRpbmcgdG9sZXJhbmNlIGZyb20gaGlnaGVyIHRlbXBlcmF0dXJlIGhlYXRpbmcgdG9sZXJhbmNlIn0NCnByZWQ0IDwtIHByZWQxICsgYWVzKHggPSBkZWx0YV90YXVfbG93X2hhdCAqIFRrLA0KICAgICAgICAgICAgICAgICAgICAgeSA9IGRlbHRhX3RhdV9sb3cgKiBUaykgKyANCiAgIyBnZ3RpdGxlKCJQcmVkaWN0IGxvdyBmcm9tIGhpZ2giKSArDQogIGxhYnMoeCA9IGV4cHJlc3Npb24oIlByZWRpY3RlZCBoZWF0aW5nIHRvbGVyYW5jZSAoXHUwMEIwQykiKSwgDQogICAgICAgeSA9IGV4cHJlc3Npb24oIk9ic2VydmVkIGhlYXRpbmcgdG9sZXJhbmNlIChcdTAwQjBDKSIpKSANCg0KcHJlZDQNCmBgYA0KDQpgYGB7ciBwcmVkNC1sbSwgaW5jbHVkZT1GQUxTRX0NCiMgbG93IGZyb20gaGlnaA0KcHJlZF9sb3dfaGlnaCA8LSBsbShkZWx0YV90YXVfbG93IH4gZGVsdGFfdGF1X2xvd19oYXQsIA0KICAgICAgICAgICAgICAgICAgIG9mZnNldCA9IGRlbHRhX3RhdV9sb3dfaGF0LCANCiAgICAgICAgICAgICAgICAgICBkYXRhID0gQVJSKQ0KYGBgDQoNClRoZSAkUl4yJCBpcyBgciByb3VuZChzdW1tYXJ5KHByZWRfbG93X2hpZ2gpJHIuc3F1YXJlZCwgNCkqMTAwYCUuIEVxdWF0aW9ucyBcQHJlZihlcTplcTEwKSBhbmQgXEByZWYoZXE6ZXExMGIpIGNvbnZlcnRzIG5vcm1hbGlzZWQgaGVhdGluZyB0b2xlcmFuY2UgYXQgb25lIGFjY2xpbWF0aW9uIHRlbXBlcmF0dXJlIGludG8gcmVzY2FsZWQgaGVhdGluZyB0b2xlcmFuY2UgKHZpYSAkZ19cYmV0YSQpLCBjb3JyZWN0cyBmb3IgdGhlIGRpZmZlcmVuY2UgaW4gYWNjbGltYXRpb24gdGVtcGVyYXR1cmUgYWxvbmcgdGhlIG5vbi1saW5lYXIgVW5pdmVyc2FsIFRlbXBlcmF0dXJlIERlcGVuZGVuY2UgKHZpYSAkZV57XGJldGFcdGF1fSQpLCBhbmQgY29udmVydHMgcmVzY2FsZWQgYW5kIGJpb2xvZ2ljYWwgcmF0ZS1jb3JyZWN0ZWQgaGVhdGluZyB0b2xlcmFuY2UgaW50byBub3JtYWxpc2VkIGhlYXRpbmcgdG9sZXJhbmNlIGF0IHRoZSBvdGhlciBhY2NsaW1hdGlvbiB0ZW1wZXJhdHVyZSAodmlhICRmX1xiZXRhJCkuIA0KDQoqKioqKioNCg0KIyBUaGUgZWZmZWN0IG9mIGhlYXRpbmcgcmF0ZSBvbiByZXNjYWxlZCBoZWF0aW5nIGR1cmF0aW9uIHsjaGVhdGluZy1yYXRlfQ0KDQpgYGB7ciB2YXJ5aW5nLXJhdGVzfQ0KdmFyeWluZ19yYXRlcyA8LSByZWFkLmNzdigiTW9ybGV5X2V0X2FsXzIwMTYuY3N2IikgJT4lIA0KICByZW5hbWUoaGVhdGluZ19yYXRlID0gOCwNCiAgICAgICAgIHRhID0gOSwNCiAgICAgICAgIHRjID0gMTApICU+JSANCiAgIG11dGF0ZShHZW51cyA9IGlmZWxzZShTcGVjaWVzID09ICJib3JjaGdyZXZpbmtpIiwgIlBhZ290aGVuaWEiLCBnZW51cykpICU+JSAjIFN5bm9ueW0gVHJlbWF0b211cyBQYWdvdGhlbmlhIFBhZ290aGVuaWEgaW4gQVJSIGRhdGFzZXQNCiAgbXV0YXRlKE5hbWUgPSBwYXN0ZShHZW51cywgU3BlY2llcyksIA0KICAgICAgICAgZXhwZXJpbWVudCA9ICJ2YXJpYWJsZSIsDQogICAgICAgICBsYW1iZGEgPSBoZWF0aW5nX3JhdGUgLyBUaykgJT4lDQogIG11dGF0ZShQaHlsYSA9IGNhc2Vfd2hlbihwaHlsYSA9PSAibW9sbHVzYyIgfiAiTW9sbHVzY2EiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgcGh5bGEgPT0gIkZpc2giIH4gIkNob3JkYXRhIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHBoeWxhID09ICJBc2NpZGlhbnMiIH4gIkNob3JkYXRhIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHBoeWxhID09ICJDcnVzdGFjZWFuIiB+ICJBcnRocm9wb2RhIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiBwaHlsYSkpICU+JQ0KICBncm91cF9ieShOYW1lKSAlPiUNCiAgZGlzdGluY3QoKSAlPiUgIyByZW1vdmUgZHVwbGljYXRlZCByb3dzDQogIGZpbHRlcihuKCk+MSkgJT4lICMgcmVtb3ZlIHNwZWNpZXMgd2l0aCAxIG9ic2VydmF0aW9uDQogIHVuZ3JvdXAoKQ0KYGBgDQoNClRvIGV4YW1pbmUgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGhlYXRpbmcgcmF0ZSBhbmQgcmVzY2FsZWQgaGVhdGluZyBkdXJhdGlvbiBmdXJ0aGVyLCB3ZSB1c2VkIGEgc2Vjb25kIGRhdGFzZXQgY29udGFpbmluZyAkVF9jJCBtZWFzdXJlZCBmcm9tIHRoZSBzYW1lICRUX2EkIHVuZGVyIGRpZmZlcmVudCBoZWF0aW5nIHJhdGVzICgkXGxhbWJkYSQpIFtATW9ybGV5MjAxNl0uIFNwZWNpZXMgd2l0aCBvbmx5IG9uZSBvYnNlcnZhdGlvbiBhcmUgcmVtb3ZlZCAobiA9IDMpLiBUaGUgZGF0YXNldCBoYXMgYHIgbnJvdyh2YXJ5aW5nX3JhdGVzKWAgb2JzZXJ2YXRpb25zIGZyb20gYHIgbGVuZ3RoKHVuaXF1ZSh2YXJ5aW5nX3JhdGVzJFBoeWxhKSlgIHBoeWxhLiAqVHJlbWF0b211cyBib3JjaGdyZXZpbmtpKiBpcyByZW5hbWVkIHRvICpQYWdvdGhlbmlhIGJvcmNoZ3Jldmlua2kqIGJlY2F1c2UgKlBhZ290aGVuaWEqIGlzIHRoZSBhY2NlcHRlZCBnZW51cyBhbmQgaXMgYWxzbyB1c2VkIGluIHRoZSBBUlIgZGF0YXNldC4gV2UgY29tYmluZWQgdGhpcyBkYXRhc2V0IHdpdGggZGF0YSBmcm9tIHRoZSBjb25zdGFudCBoZWF0aW5nIHJhdGUgZXhwZXJpbWVudHMgZm9yIHNwZWNpZXMgdGhhdCBhbHNvIGhhZCB2YXJpYWJsZSBoZWF0aW5nIHJhdGUgZGF0YSB3aXRoIHRoZW0gKDEyOSBvYnNlcnZhdGlvbnMgZnJvbSAzNyBzcGVjaWVzKS4NCg0KVGhlIG9yaWdpbmFsIEFSUiBkYXRhc2V0IHdhcyBjb252ZXJ0ZWQgdG8gYSBsb25nIGZvcm1hdCB0byBqb2luIHdpdGggdGhlIHZhcnlpbmcgaGVhdGluZyByYXRlIGRhdGFzZXQgKGBzcGVjaWVzX2RhdGFgKS4gVGhlIGRhdGFzZXRzIGFyZSBpZGVudGlmaWVkIGJ5IGBleHBlcmltZW50YCAoYHZhcmlhYmxlYCBvciBgY29uc3RhbnRgKSBhbmQgYG9jY3VycmVuY2VgIChpZGVudGlmeWluZyBzcGVjaWVzIHRoYXQgb2NjdXIgaW4gYm90aCBkYXRhc2V0cykuIA0KDQpgYGB7ciB2YXJ5aW5nfQ0Kc3BlY2llc19kYXRhIDwtIEFSUiAlPiUNCiAgIyBUcmFuc2Zvcm0gdGhlIEFSUiBkYXRhc2V0IHRvIGxvbmcgZm9ybWF0DQogIHBpdm90X2xvbmdlcihjb2xzID0gc3RhcnRzX3dpdGgoYygidGFfIiwgInRjXyIpKSwNCiAgICAgICAgICAgICAgIG5hbWVzX3RvID0gYygiLnZhbHVlIiwgImFzc2F5IiksDQogICAgICAgICAgICAgICBuYW1lc19zZXAgPSAiXyIpICU+JQ0KICBtdXRhdGUoZXhwZXJpbWVudCA9ICJjb25zdGFudCIpICU+JSANCiAgIyBKb2luIGRhdGFzZXRzIGFuZCBnZXQgb2NjdXJlbmNlcyBvZiBzcGVjaWVzIGluIGVhY2ggZGF0YXNldA0KICBmdWxsX2pvaW4oLiwNCiAgICAgICAgICAgIHZhcnlpbmdfcmF0ZXMsIA0KICAgICAgICAgICAgYnkgPSBjKCJHZW51cyIsICJTcGVjaWVzIiwgIk5hbWUiLCAiZXhwZXJpbWVudCIsICJ0YSIsICJ0YyIsICJsYW1iZGEiKSwNCiAgICAgICAgICAgIHN1ZmZpeCA9IGMoIl9jb25zdGFudCIsICJfdmFyaWFibGUiKSkgJT4lIA0KICAjIE5vcm1hbGlzZSB0ZW1wZXJhdHVyZQ0KICBtdXRhdGUodGF1X2EgPSB0YSAvIFRrLCANCiAgICAgICAgIHRhdV9jID0gdGMgLyBUaywNCiAgICAgICAgIGRlbHRhX3RhdSA9IHRhdV9jIC0gdGF1X2EpICU+JSANCiAgZ3JvdXBfYnkoTmFtZSkgJT4lIA0KICBtdXRhdGUob2NjdXJyZW5jZSA9IGxlbmd0aCh1bmlxdWUoZXhwZXJpbWVudCkpKSAlPiUNCiAgdW5ncm91cCgpICU+JSANCiAgIyBLZWVwIHNwZWNpZXMgd2l0aCBtb3JlIHRoYW4gMSBoZWF0aW5nIHJhdGUgZnJvbSBlaXRoZXIgZGF0YXNldA0KICBmaWx0ZXIoZXhwZXJpbWVudCA9PSAidmFyaWFibGUiIHwgb2NjdXJyZW5jZSA9PSAyKSAlPiUgDQogICMgQ2FsY3VsYXRlIHJlc2NhbGVkIGhlYXRpbmcgZHVyYXRpb24gKEVxdWF0aW9uIDgpDQogIG11dGF0ZShkZWx0YV90ciA9IHBtYXBfZGJsKGxpc3QodGF1X2EgPSB0YXVfYSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0YXVfYyA9IHRhdV9jLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhbWJkYSA9IGxhbWJkYSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlbHRhX3RyX2Z1bikpDQoNCnJhdGVfcmF0aW9zIDwtIHNwZWNpZXNfZGF0YSAlPiUgDQogICMgR3JvdXAgYnkgbmFtZQ0KICBncm91cF9ieShOYW1lKSAlPiUgDQogICMgRm9yIGVhY2ggc3BlY2llcyBjcmVhdGUgYWxsIGNvbWJpbmF0aW9ucyBvZiBoZWF0aW5nIHJhdGUgd2l0aCBjb3ZhcmlhdGVzDQogIGdyb3VwX21vZGlmeSh+ZXhwYW5kX2dyaWQoLngsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdCgueCwgbGFtYmRhLCBkZWx0YV90ciwgZGVsdGFfdGF1LCB0YXVfYSksDQogICMgQWRkIG51bWJlcmVkIHN1ZmZpeCB0byBhbGwgY29sdW1uczsgdW5pcXVlIGZvciBkdXBsaWNhdGlvbnMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAubmFtZV9yZXBhaXIgPSBmdW5jdGlvbiAoeCkgYXZlKHgsIHgsIEZVTiA9IGZ1bmN0aW9uKGkpIHN0cl9jKGksIHNlcV9hbG9uZyhpKSkpKSkgJT4lDQogICMgQ2FsY3VsYXRlIHJhdGlvIG9mIHJlc2NhbGVkIGR1cmF0aW9uIGFuZCBoZWF0aW5nIHJhdGUgKEVxdWF0aW9uIDE5KQ0KICBtdXRhdGUobGFtYmRhX3JhdGlvID0gbGFtYmRhMi9sYW1iZGExLA0KICAgICAgICAgdF9yYXRpbyA9IGRlbHRhX3RyMi9kZWx0YV90cjEpICU+JQ0KICAjIENhbGN1bGF0ZSBzY2FsaW5nIGNvZWZmaWNpZW50IGdhbW1hIGZvciBlYWNoIHNwZWNpZXMgKEVxdWF0aW9uIDE5KQ0KICBncm91cF9tb2RpZnkoZnVuY3Rpb24oeCwgeSl7DQogICAgeCRnZyA8LSBhYnMoYXMubnVtZXJpYyhjb2VmKGxtKGxvZyh0X3JhdGlvKSB+IGxvZyhsYW1iZGFfcmF0aW8pLCB4KSlbMl0pKQ0KICAgIHJldHVybih4KX0pICU+JSANCiAgZGlzdGluY3QoKSAlPiUgIyBSZW1vdmUgZHVwbGljYXRpb25zIGNyZWF0ZWQgYnkgZXhwYW5kIGdyaWQNCiAgdW5ncm91cCgpICU+JSANCiAgIyBDYWxjdWxhdGUgcHJlZGljdGVkIG5vcm1hbGlzZWQgaGVhdGluZyB0b2xlcmFuY2UgYXQgdGhlIHNlY29uZCBhY2NsaW1hdGlvbiB0ZW1wZXJhdHVyZSwgY29ycmVjdGVkIGZvciBoZWF0aW5nIHJhdGUgKEVxdWF0aW9uIDIwKQ0KICBtdXRhdGUoZGVsdGFfdGF1Ml9oYXQgPSBmX2JldGFfZnVuKGV4cChiZXRhX0sgKiAodGF1X2ExLXRhdV9hMikpICogKGxhbWJkYV9yYXRpbyBeICgxIC0gZ2cpKSAqIGdfYmV0YV9mdW4oZGVsdGFfdGF1MSkpLA0KICAgICAgICAgZGVsdGFfdGF1Ml9oYXRfaW50ZXIgPSBmX2JldGFfZnVuKGV4cChiZXRhX0sgKiAodGF1X2ExLXRhdV9hMikpICogKGxhbWJkYV9yYXRpbyBeICgxIC0gMC43NjU2NTQ4KSkgKiBnX2JldGFfZnVuKGRlbHRhX3RhdTEpKSkNCg0KIyBpbnRlcnNwZWNpZmljIGdhbW1hDQpnYW1tYSA8LSBhYnMoY29lZihnbG0obG9nKHRfcmF0aW8pIH4gbG9nKGxhbWJkYV9yYXRpbyksIGRhdGEgPSByYXRlX3JhdGlvcykpWzJdKQ0KYGBgDQoNCioqKg0KDQojIyBUZXN0aW5nIGEgbnVsbCBlZmZlY3Qgb2YgaGVhdGluZyByYXRlcyBvbiByZXNjYWxlZCBoZWF0aW5nIGR1cmF0aW9uDQoNCldlIGZpcnN0IGNvbnNpZGVyZWQgYSBudWxsIGh5cG90aGVzaXMgdGhhdCByZXNjYWxlZCBoZWF0aW5nIGR1cmF0aW9uIGRvZXMgbm90IGRlcGVuZCBvbiBoZWF0aW5nIHJhdGUuIEVxdWF0aW9uIFxAcmVmKGVxOmVxN2IpIHN1Z2dlc3RzIHRoYXQgZm9yIGFueSBoZWF0aW5nIHJhdGU6DQoNClxiZWdpbntlcXVhdGlvbn0NClxEZWx0YSBcdGF1IChcbGFtYmRhKT0gZl9cYmV0YSAoZV57LVxiZXRhIFx0YXVfe2F9fSBcbGFtYmRhIFxEZWx0YSB0X3IoXGxhbWJkYSkpIA0KKFwjZXE6ZXExMSkNClxlbmR7ZXF1YXRpb259DQoNCklmIHRoZSBudWxsIGh5cG90aGVzaXMgaXMgc3VwcG9ydGVkLCB0aGVuICRcRGVsdGEgdF9yIChcbGFtYmRhKSA9IFxEZWx0YSB0X3IgKDApJCBhbmQgdGh1cyBFcXVhdGlvbiBcQHJlZihlcTplcTExKSBiZWNvbWVzDQoNClxiZWdpbntlcXVhdGlvbn0NClxEZWx0YSBcdGF1IChcbGFtYmRhKSA9IGZfXGJldGEgKGVeey1cYmV0YSBcdGF1X3thfX0gXGxhbWJkYSBcRGVsdGEgdF9yICgwKSkNCihcI2VxOmVxMTIpDQpcZW5ke2VxdWF0aW9ufQ0KDQp3aGljaCBpcyBhIGxvZ2FyaXRobWljLCB0ZW1wZXJhdHVyZS1kZXBlbmRlbnQgcmVsYXRpb25zaGlwIGJldHdlZW4gb2JzZXJ2ZWQgaGVhdGluZyB0b2xlcmFuY2UgYW5kIGhlYXRpbmcgcmF0ZS4gRXF1YXRpb24gXEByZWYoZXE6ZXExMikgY2FuIGJlIHRlc3RlZCBieSBjb25kdWN0aW5nIHJhbXBpbmcgYXNzYXlzIHN0YXJ0aW5nIGF0IHRoZSBzYW1lIGFjY2xpbWF0aW9uIHRlbXBlcmF0dXJlIGJ1dCB1c2luZyBkaWZmZXJlbnQgaGVhdGluZyByYXRlcy4gRnJvbSB0aGVzZSBkYXRhIHdlIGNhbiBpbmZlciAkXERlbHRhIHRfciAoMCkkIGZyb20gdGhlIGV4cGVyaW1lbnQgd2l0aCB0aGUgc2xvd2VzdCBoZWF0aW5nIHJhdGUgJFxsYW1iZGFfe21pbn0kLiBXZSBzaG91bGQgdGhlbiBoYXZlIHRoYXQNCg0KXGJlZ2lue2VxdWF0aW9ufQ0KXERlbHRhIFx0YXUgKFxsYW1iZGEpID0gZl9cYmV0YSAoXGhhdHtcbGFtYmRhfSksIFwgXHRleHR7d2hlcmV9IFwgXGhhdHtcbGFtYmRhfSA9IFxmcmFje1xsYW1iZGF9e1xsYW1iZGFfe21pbn19IGdfXGJldGEgKFxEZWx0YSBcdGF1IChcbGFtYmRhX3ttaW59KSkNCihcI2VxOmVxMTMpDQpcZW5ke2VxdWF0aW9ufQ0KDQpJbiBhIHBsb3Qgb2Ygbm9ybWFsaXNlZCBoZWF0aW5nIHRvbGVyYW5jZSAoJFxEZWx0YSBcdGF1JCkgYWdhaW5zdCB0aGUgdHJhbnNmb3JtZWQgdmFyaWFibGUgJGZfXGJldGEgKFxoYXR7XGxhbWJkYX0pJCwgdGhlIG51bGwgaHlwb3RoZXNpcyBpcyBzdXBwb3J0ZWQgaWYgdGhlIHBvaW50cyBmYWxsIGFsb25nIHRoZSBpZGVudGl0eSAoMToxKSBsaW5lLiBJZiBwb2ludHMgc3lzdGVtYXRpY2FsbHkgZmFsbCBiZWxvdyB0aGUgMToxIGxpbmUsIHRoZW4gdGhlIG51bGwgaHlwb3RoZXNpcyBpcyBub3Qgc3VwcG9ydGVkLg0KDQpgYGB7ciBkZXBhcnR1cmUsIGZpZy5jYXAgPSAiUHJlZGljdGVkIGhlYXRpbmcgdG9sZXJhbmNlIHZlcnN1cyBvYnNlcnZlZCBoZWF0aW5nIHRvbGVyYW5jZSBmb3Igc3BlY2llcyB3aXRoIHZhcnlpbmcgaGVhdGluZyByYXRlcyAoMTA3IG9ic2VydmF0aW9ucykuIENvbG91cnMgYXJlIHNwZWNpZXMgKG4gPSAzNykuIn0NCmdfZGVwYXJ0dXJlIDwtIHNwZWNpZXNfZGF0YSAlPiUNCiAgZmlsdGVyKGV4cGVyaW1lbnQgPT0gInZhcmlhYmxlIikgJT4lIA0KICBncm91cF9ieShOYW1lKSAlPiUgDQogIG11dGF0ZShsYW1iZGFfbWluID0gbWluKGxhbWJkYSksDQogICAgICAgICBkZWx0YV90YXVfbWluID0gZGVsdGFfdGF1W3doaWNoLm1pbihsYW1iZGEpXSkgJT4lIA0KICB1bmdyb3VwKCkgJT4lIA0KICBnZ3Bsb3QobWFwcGluZyA9IGFlcyh4ID0gZl9iZXRhX2Z1bihsYW1iZGEgLyBsYW1iZGFfbWluICogZ19iZXRhX2Z1bihkZWx0YV90YXVfbWluKSkgKiBUaywNCiAgICAgICAgICAgICAgICAgICAgICAgeSA9IGRlbHRhX3RhdSAqIFRrLA0KICAgICAgICAgICAgICAgICAgICAgICBjb2wgPSBOYW1lKSkgKyANCiAgZ2VvbV9wb2ludCgpICsgDQogIGdlb21fbGluZShhbHBoYSA9IDAuNSkgKw0KICBnZW9tX2FibGluZShzbG9wZSA9IDEsIGludGVyY2VwdCA9IDAsIGx0eSA9IDIsIGFscGhhID0gMC42KSArDQogIGxhYnMoeCA9IGV4cHJlc3Npb24oIlByZWRpY3RlZCBoZWF0aW5nIHRvbGVyYW5jZSAoXHUwMEIwQykiKSwgDQogICAgICAgeSA9IGV4cHJlc3Npb24oIk9ic2VydmVkIGhlYXRpbmcgdG9sZXJhbmNlIChcdTAwQjBDKSIpKSArDQogIHNjYWxlX2NvbG91cl92aXJpZGlzX2Qob3B0aW9uID0gIkMiKSArDQogIHNjYWxlX3hfY29udGludW91cyhleHBhbmQgPSBjKDAsMCksIGxpbWl0cyA9IGMoMCwgMTAwKSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApLCBsaW1pdHMgPSBjKDAsIDI1KSkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiLCBwbG90Lm1hcmdpbiA9IG1hcmdpbig1LjUsIDcsIDUuNSwgNS41LCB1bml0ID0gInB0IikpDQoNCmdfZGVwYXJ0dXJlDQpgYGANCg0KV2UgdXNlZCB0aGUgc2xvd2VzdCBoZWF0aW5nIHJhdGUgb2YgZWFjaCBzcGVjaWVzIHRvIHRlc3Qgd2hldGhlciBoZWF0aW5nIHJhdGUgaGFkIG5vIGVmZmVjdCBvbiByZXNjYWxlZCBoZWF0aW5nIGR1cmF0aW9uIGFuZCB0aHVzIHByZWRpY3RlZCBoZWF0aW5nIHRvbGVyYW5jZS4gVGhlIG51bGwgaHlwb3RoZXNpcyB3YXMgbm90IHN1cHBvcnRlZCBiZWNhdXNlIHBvaW50cyBzeXN0ZW1hdGljYWxseSBmYWxsIGJlbG93IHRoZSAxOjEgbGluZSAoRmlndXJlIFxAcmVmKGZpZzpkZXBhcnR1cmUpKS4NCg0KVG8gdmlzdWFsaXplIHRoZSBlZmZlY3Qgb2YgaGVhdGluZyByYXRlIG9uIHJlc2NhbGVkIGhlYXRpbmcgdG9sZXJhbmNlLCB3ZSBwbG90IHRoZSByYXRpbyBvZiByZXNjYWxlZCBoZWF0aW5nIGR1cmF0aW9uIGZvciBhIHBhaXJlZCBvYnNlcnZhdGlvbiB3aXRoaW4gYSBzcGVjaWVzIHdpdGggdGhlIGNvcnJlc3BvbmRpbmcgcmF0aW8gZm9yIHBhaXJlZCBoZWF0aW5nIHJhdGUuIFRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgcmF0aW8gb2YgcmVzY2FsZWQgaGVhdGluZyBkdXJhdGlvbiBhbmQgdGhlIHJhdGlvIG9mIGhlYXRpbmcgcmF0ZSBpcyBkZXNjcmliZWQgYnkgYW4gYWxsb21ldHJpYyBzY2FsaW5nIGVxdWF0aW9uIGluIHRoZSBmb3JtICRcRGVsdGEgdF9yIChcbGFtYmRhKSBcc2ltIGMgXGxhbWJkYV57LSBcZ2FtbWF9JCB3aGVyZSAkYyQgZGVwZW5kcyBvbmx5IG9uIHRoZSBleHBlcmltZW50YWwgcHJvdG9jb2wgYW5kIHRoZSBzcGVjaWVzLXNwZWNpZmljIHNjYWxpbmcgZXhwb25lbnQsICRcZ2FtbWEkLiBQb2ludHMgc2hvdWxkIGZhbGwgYWxvbmcgdGhlIGlkZW50aXR5IGxpbmUgaWYgaGVhdGluZyByYXRlIGRvZXMgbm90IGFmZmVjdCByZXNjYWxlZCBoZWF0aW5nIHRvbGVyYW5jZSAoaS5lLiwgYSBzY2FsaW5nIGV4cG9uZW50IG9mIC0xKS4NCg0KQ2hhbmdlIGluIHJlc2NhbGVkIGhlYXRpbmcgZHVyYXRpb24sIGFuZCB0aHVzIGhlYXRpbmcgdG9sZXJhbmNlLCBzY2FsZXMgd2l0aCBjaGFuZ2UgaW4gaGVhdGluZyByYXRlIGFjY29yZGluZyB0byBhbiBhbGxvbWV0cmljIHNjYWxpbmcgZXF1YXRpb24uIFRoZXJlIGlzIHNvbWUgc3BlY2llcy1zcGVjaWZpYyB2YXJpYXRpb24gaW4gdGhlIHNsb3BlIG9mIHRoZSByZWdyZXNzaW9uICRcZ2FtbWEkIChjb2xvdXJzKS4gT3ZlcmFsbCwgdGhlcmUgaXMgYW4gaW50ZXJzcGVjaWZpYyBzY2FsaW5nIGV4cG9uZW50IG9mIGFwcHJveGltYXRlbHkgJFxnYW1tYSA9JCBgciByb3VuZChnYW1tYSwgMylgIGNhbGN1bGF0ZWQgZnJvbSBhIGxpbmVhciByZWdyZXNzaW9uIG9mIHJhdGlvcyBvZiBoZWF0aW5nIHJhdGUgYW5kIHJhdGlvcyBvZiByZXNjYWxlZCBoZWF0aW5nIGR1cmF0aW9uIG9uIExvZ34xMH4gc2NhbGVzIChGaWd1cmUgXEByZWYoZmlnOmR0ZHQpKS4gDQoNCmBgYHtyIGR0ZHQsIGZpZy5jYXAgPSAiSW50ZXJzcGVjaWZpYyBzY2FsaW5nIG9mIHJlc2NhbGVkIGhlYXRpbmcgZHVyYXRpb24gd2l0aCBoZWF0aW5nIHJhdGUuIFZhcmlhdGlvbiB3aXRoaW4gZWFjaCBzcGVjaWVzIGlzIHNob3duIGJ5IHRoZSBmaXR0ZWQgbGluZXMgYmV0d2VlbiBwb2ludHMgKDEyOSBvYnNlcnZhdGlvbnMpLiBUaGUgZGFzaGVkIGlkZW50aXR5IGxpbmUgaXMgdGhlIGV4cGVjdGVkIHJlbGF0aW9uc2hpcCBmb2xsb3dpbmcgdGhlIG51bGwgaHlwb3RoZXNpcy4gQXhlcyBhcmUgTG9nMTAgdHJhbnNmb3JtZWQuIENvbG91cnMgYXJlIHNwZWNpZXMgKG4gPSAzNykuIn0NCmdfc2NhbGluZyA8LSBnZ3Bsb3QoZGF0YSA9IHJhdGVfcmF0aW9zLA0KICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSBsYW1iZGFfcmF0aW8sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSB0X3JhdGlvLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cCA9IE5hbWUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sID0gTmFtZSkpICsgDQogIGdlb21fbGluZShzdGF0ID0ic21vb3RoIiwgbWV0aG9kID0gImxtIiwgYWxwaGEgPSAwLjUpICsNCiAgZ2VvbV9wb2ludCgpICsgDQogIGdlb21fYWJsaW5lKHNsb3BlID0gLTEsIGludGVyY2VwdCA9IDAsIGx0eSA9IDIsIGFscGhhID0gMC42KSArDQogIGdlb21fc21vb3RoKGFlcyhncm91cCA9IDEpLCBtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFLCBjb2wgPSAxKSArDQogc2NhbGVfeF9sb2cxMCgNCiAgIGJyZWFrcyA9IHNjYWxlczo6dHJhbnNfYnJlYWtzKCJsb2cxMCIsIGZ1bmN0aW9uKHgpIDEwXngpLA0KICAgbGFiZWxzID0gc2NhbGVzOjp0cmFuc19mb3JtYXQoImxvZzEwIiwgc2NhbGVzOjptYXRoX2Zvcm1hdCgxMF4ueCkpDQogKSArDQogc2NhbGVfeV9sb2cxMCgNCiAgIGJyZWFrcyA9IHNjYWxlczo6dHJhbnNfYnJlYWtzKCJsb2cxMCIsIGZ1bmN0aW9uKHgpIDEwXngpLA0KICAgbGFiZWxzID0gc2NhbGVzOjp0cmFuc19mb3JtYXQoImxvZzEwIiwgc2NhbGVzOjptYXRoX2Zvcm1hdCgxMF4ueCkpDQogKSArDQogIGdndGl0bGUocGFzdGUwKCJzbG9wZSA9ICIsIA0KICAgICAgICAgICAgICAgICByb3VuZChnYW1tYSwgMykpKSArDQogIGxhYnMoeCA9ICJIZWF0aW5nIHJhdGUgcmF0aW8iLCB5ID0gIlJlc2NhbGVkIGhlYXRpbmcgZHVyYXRpb24gcmF0aW8iKSArDQogIHNjYWxlX2NvbG91cl92aXJpZGlzX2Qob3B0aW9uID0gIkMiKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpDQoNCmdfc2NhbGluZw0KYGBgDQoNCioqKg0KDQojIyBRdWFudGlmeWluZyB0aGUgZWZmZWN0IG9mIGhlYXRpbmcgcmF0ZXMgb24gcmVzY2FsZWQgaGVhdGluZyB0b2xlcmFuY2UNCg0KU2luY2UgaGlnaGVyIGhlYXRpbmcgcmF0ZXMgcmVkdWNlcyByZXNjYWxlZCBoZWF0aW5nIHRvbGVyYW5jZSBmb2xsb3dpbmcgYSBwaGVub21lbm9sb2dpY2FsIHBvd2VyIGxhdywgdGhlbiB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gdHdvIGV4cGVyaW1lbnRzIGRvbmUgYXQgdHdvIGhlYXRpbmcgcmF0ZXMsICRcbGFtYmRhXzEkIGFuZCAkXGxhbWJkYV8yJCwgcmVnYXJkbGVzcyBvZiB0aGUgc3RhcnRpbmcgdGVtcGVyYXR1cmUsIGNhbiBiZSBkZXNjcmliZWQgYnk6DQoNClxiZWdpbntlcXVhdGlvbn0NClxmcmFje1xsYW1iZGFfMiBcRGVsdGEgdF9yIChcbGFtYmRhXzIpfXtcbGFtYmRhXzEgXERlbHRhIHRfciAoXGxhbWJkYV8xKX0gXGFwcHJveCBcYmlnZyhcZnJhY3tcbGFtYmRhXzJ9e1xsYW1iZGFfMX1cYmlnZyleezEtXGdhbW1hfQ0KKFwjZXE6ZXExNCkNClxlbmR7ZXF1YXRpb259DQoNCmFuZCB0aGVyZWZvcmUgdGhhdCBmcm9tIG9uZSBoZWF0aW5nIHRvbGVyYW5jZSAkXERlbHRhIFx0YXVfMSQgd2Ugc2hvdWxkIGJlIGFibGUgdG8gcHJlZGljdCBhbnkgb3RoZXIgJFxEZWx0YSBcdGF1XzIkLiBVc2luZyBFcXVhdGlvbiBcQHJlZihlcTplcTE0KSB3ZSBjYW4gZGVkdWNlICRcRGVsdGEgdF9yIChcbGFtYmRhXzIpJCBhbmQgZnJvbSBFcXVhdGlvbnMgXEByZWYoZXE6ZXE3YSkgYW5kIFxAcmVmKGVxOmVxN2IpIGxlYWRzIHRvOg0KDQpcYmVnaW57ZXF1YXRpb259DQpcRGVsdGFcdGF1XzIgPSBmX3tcYmV0YX1cQmlnZyhlXntcYmV0YShcdGF1X3thMX0tXHRhdV97YTJ9KX1cYmlnZyhcZnJhY3tcbGFtYmRhXzJ9e1xsYW1iZGFfMX1cYmlnZyleezEtXGdhbW1hfWdfe1xiZXRhfVxiaWcoXERlbHRhXHRhdV8xXGJpZylcQmlnZykNCihcI2VxOmVxMTUpDQpcZW5ke2VxdWF0aW9ufQ0KDQpUaGF0IGlzLCB3ZSBjYW4gcHJlZGljdCBvbmUgaGVhdGluZyB0b2xlcmFuY2UgJFxEZWx0YVx0YXVfMiQgZnJvbSBhbm90aGVyICRcRGVsdGFcdGF1XzEkIHVzaW5nIEVxdWF0aW9uIFxAcmVmKGVxOmVxMTUpIHdoaWNoIGluY29ycG9yYXRlcyB0aGUgY29ycmVjdGlvbiBmb3IgdGhlIGVmZmVjdCBvZiBoZWF0aW5nIHJhdGUgb24gcmVzY2FsZWQgaGVhdGluZyBkdXJhdGlvbiB1c2luZyBhIHNwZWNpZXMgc3BlY2lmaWMgc2NhbGluZyBleHBvbmVudCAoJFxnYW1tYSQpLiBXZSB1c2Ugc3BlY2llcy1zcGVjaWZpYyBzY2FsaW5nIGV4cG9uZW50cyBpbiBzdWJzZXF1ZW50IGNhbGN1bGF0aW9ucyBmb3IgcHJlY2lzaW9uLiBEb2luZyBzbywgd2Ugc2VlIHN0cm9uZyBjb25jb3JkYW5jZSBvZiB0aGUgb2JzZXJ2ZWQgaGVhdGluZyB0b2xlcmFuY2UgKGBkZWx0YV90YXUyYCkgYW5kIHRoZSBlc3RpbWF0ZWQgdmFsdWUgdXNpbmcgRXF1YXRpb24gXEByZWYoZXE6ZXExNSkgKGBkZWx0YV90YXUyX2hhdGApLg0KDQpgYGB7ciBnYW1tYSwgZmlnLmNhcCA9ICJQcmVkaWN0ZWQgaGVhdGluZyB0b2xlcmFuY2UgY29ycmVjdGVkIHVzaW5nIHNwZWNpZXMtc3BlY2lmaWMgc2NhbGluZyBleHBvbmVudHMgZm9yIHRoZSBhbGxvbWV0cmljIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHJlc2NhbGVkIGhlYXRpbmcgZHVyYXRpb24gYW5kIGhlYXRpbmcgcmF0ZS4gQ29sb3VycyBhcmUgc3BlY2llcy4ifQ0KZ19wcmVkaWN0X3RhdSA8LSByYXRlX3JhdGlvcyAlPiUgDQogIGZpbHRlcih0X3JhdGlvICE9IDEgJiBsYW1iZGFfcmF0aW8gIT0gMSkgJT4lICMgcmVtb3ZlIHRyaXZpYWwgcGFpcnMgd2hlcmUgaXQgaXMgdGhlIGxvd2VzdCBoZWF0aW5nIHJhdGUNCiAgZ2dwbG90KG1hcHBpbmcgPSBhZXMoeCA9IGRlbHRhX3RhdTJfaGF0ICogVGssIA0KICAgICAgICAgICAgICAgICAgICAgICB5ID0gZGVsdGFfdGF1MiAqIFRrLA0KICAgICAgICAgICAgICAgICAgICAgICBjb2wgPSBOYW1lKSkgKyANCiAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwLCBsdHkgPSAyLCBhbHBoYSA9IDAuNikgKw0KICBnZW9tX3BvaW50KCkgKyANCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSwgY29sID0gMSkgKyANCiAgbGFicyh4ID0gZXhwcmVzc2lvbigiUHJlZGljdGVkIGhlYXRpbmcgdG9sZXJhbmNlIChcdTAwQjBDKSIpLCANCiAgICAgICB5ID0gZXhwcmVzc2lvbigiT2JzZXJ2ZWQgaGVhdGluZyB0b2xlcmFuY2UgKFx1MDBCMEMpIikpICsNCiAgc2NhbGVfY29sb3VyX3ZpcmlkaXNfZChvcHRpb24gPSAiQyIpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwwKSwgbGltaXRzID0gYygwLCAzMCkpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwwKSwgbGltaXRzID0gYygwLCAzMCkpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikNCg0KZ19wcmVkaWN0X3RhdQ0KYGBgDQoNCldlIGNhbiBwbG90IHRoZSBzYW1lIGFzIEZpZ3VyZSBcQHJlZihmaWc6Z2FtbWEpIGJ1dCB1c2luZyB0aGUgaW50ZXJzcGVjaWZpYyB2YWx1ZSBvZiBgciByb3VuZChnYW1tYSwzKWAgZm9yICRcZ2FtbWEkIChGaWd1cmUgXEByZWYoZmlnOmludGVyLWdhbW1hKSkuIERvaW5nIHNvIGluY3JlYXNlcyBvdXIgcHJlZGljdGlvbiBlcnJvciBmb3IgYSBzcGVjaWVzLg0KDQpgYGB7ciBpbnRlci1nYW1tYSwgZWNobyA9IEZBTFNFLCBmaWcuY2FwID0gIlByZWRpY3RlZCBoZWF0aW5nIHRvbGVyYW5jZXMgY2FsY3VsYXRlZCB1c2luZyBhIHZhbHVlIG9mIDAuNzY2IGZvciBnYW1tYSwgcmVwcmVzZW50aW5nIGFuIGludGVyc3BlY2lmaWMgcGFyYW1ldGVyLiBDb2xvdXJzIGFyZSBzcGVjaWVzLiJ9DQpyYXRlX3JhdGlvcyAlPiUgDQogICBmaWx0ZXIodF9yYXRpbyAhPSAxICYgbGFtYmRhX3JhdGlvICE9IDEpICU+JSAjIHJlbW92ZSB0cml2aWFsIHBhaXJzIHdoZXJlIGl0IGlzIHRoZSBsb3dlc3QgaGVhdGluZyByYXRlDQogIGdncGxvdChtYXBwaW5nID0gYWVzKHggPSBkZWx0YV90YXUyX2hhdF9pbnRlciAqIFRrLCANCiAgICAgICAgICAgICAgICAgICAgICAgeSA9IGRlbHRhX3RhdTIgKiBUaywNCiAgICAgICAgICAgICAgICAgICAgICAgY29sID0gTmFtZSkpICsgDQogIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gMCwgbHR5ID0gMiwgYWxwaGEgPSAwLjYpICsNCiAgZ2VvbV9wb2ludCgpICsgDQogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UsIGNvbCA9IDEpICsgDQogIHNjYWxlX3hfY29udGludW91cyhleHBhbmQgPSBjKDAsMCksIGxpbWl0cyA9IGMoMCwgMzApKSArDQogIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKDAsMCksIGxpbWl0cyA9IGMoMCwgMzApKSArDQogIGxhYnMoeCA9IGV4cHJlc3Npb24oIlByZWRpY3RlZCBoZWF0aW5nIHRvbGVyYW5jZSAoXHUwMEIwQykiKSwgDQogICAgICAgeSA9IGV4cHJlc3Npb24oIk9ic2VydmVkIGhlYXRpbmcgdG9sZXJhbmNlIChcdTAwQjBDKSIpKSArDQogIHNjYWxlX2NvbG91cl92aXJpZGlzX2Qob3B0aW9uID0gIkMiKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpDQpgYGANCg0KKioqDQoNCiMgR2VuZXJhbGlzZWQgZ3JhcGhzIG9mIHJlc2NhbGVkIGhlYXRpbmcgdG9sZXJhbmNlcw0KDQpXZSBjYW4gdmlzdWFsaXNlIHRoZSBnZW5lcmFsIHJlbGF0aW9uc2hpcCBkZXNjcmliZWQgYnkgRXF1YXRpb24gXEByZWYoZXE6ZXExNSksIHVzaW5nIG1lZGlhbiB2YWx1ZXMgb2YgaGVhdGluZyByYXRlLCAkVF9jJCBhbmQgJFRfYSQgYWNyb3NzIGFsbCBzcGVjaWVzIGFuZCAkXGdhbW1hID0kIGByIHJvdW5kKGdhbW1hLDMpYC4NCg0KYGBge3IgZ2VuLCBmaWcuY2FwID0gIkdlbmVyYWxpc2VkIGdyYXBoIG9mIHByZWRpY3RlZCBoZWF0aW5nIHRvbGVyYW5jZSBieSBhY2NsaW1hdGlvbiB0ZW1wZXJhdHVyZSBhbmQgaGVhdGluZyByYXRlIChjb2xvdXJzKS4ifQ0Kc3BfaGVhdF9yYXRlID0gbWVkaWFuKEFSUiRoZWF0aW5nX3JhdGUpDQpzcF90YSA9IG1lZGlhbihBUlIkdGFfbG93KQ0Kc3BfdGMgPSBtZWRpYW4oQVJSJHRjX2xvdykNCg0KaGVhdGluZ19yYXRlIDwtIHJvdW5kKHNvcnQoYygxMF4oc2VxKGxvZzEwKDAuMDA0KSwgbG9nMTAoNjApLCBsZW5ndGgub3V0ID0gMTQpKSwgMC4wMTUsIDEsIDAuMDQyLCAxOCkpLCAzKSAjIG9uIGxvZzEwIHNjYWxlIGZvciBlcXVpZGlzdGFudCBwb2ludHMNCmhlYXRpbmdfcmF0ZSA8LSBoZWF0aW5nX3JhdGVbIWhlYXRpbmdfcmF0ZSAlaW4lIGMoMC4wMTgsIDAuMDM3LCAxMy42NjcpXSAjIG5lYXRlbiBsaW5lcw0KdGEgPC0gc2VxKDUsIDQwLCAxKSAjIHJhbmdlIG9mIGFjY2xpbWF0aW9uIHRlbXBlcmF0dXJlcw0KcGFsX2NvbHMgPC0gdmlyaWRpc0xpdGU6OnZpcmlkaXMobiA9IGxlbmd0aChoZWF0aW5nX3JhdGUpLCBlbmQgPSAxKSAjIGNvbG91ciBwYWxldHRlIGZvciBwb2ludHMNCg0KZ2VuX2VjdG8gPC0gZXhwYW5kX2dyaWQoaGVhdGluZ19yYXRlLCB0YSkgJT4lIA0KICBtdXRhdGUoc3BfbGFtYmRhID0gc3BfaGVhdF9yYXRlIC8gVGssDQogICAgICAgICBzcF90YXVfYSA9IHNwX3RhIC8gVGssDQogICAgICAgICBzcF90YXVfYyA9IHNwX3RjIC8gVGssDQogICAgICAgICBzcF9kZWx0YV90YXUgPSBzcF90YXVfYyAtIHNwX3RhdV9hLA0KICAgICAgICAgdGF1X2EgPSB0YSAvIFRrLCANCiAgICAgICAgIGRlbHRhX3RhdV9hID0gIHNwX3RhdV9hIC0gdGF1X2EsDQogICAgICAgICBsYW1iZGEgPSBoZWF0aW5nX3JhdGUgLyBUaywNCiAgICAgICAgIGxhbWJkYV9yYXRpbyA9IGxhbWJkYS9zcF9sYW1iZGEpICAlPiUgDQogIG11dGF0ZShkZWx0YV90YXVfaGF0ID0gIGZfYmV0YV9mdW4oZXhwKGJldGFfSyAqIGRlbHRhX3RhdV9hKSAqIChsYW1iZGFfcmF0aW8gXiAoMSAtIGdhbW1hKSkgKiBnX2JldGFfZnVuKHNwX2RlbHRhX3RhdSkpKSAlPiUgDQogIGdncGxvdCgpICsgDQogIGdlb21fbGluZShhZXModGEsIGRlbHRhX3RhdV9oYXQgKiBUaywgZ3JvdXAgPSBoZWF0aW5nX3JhdGUsIGNvbCA9IGhlYXRpbmdfcmF0ZSkpICsNCiAgbGFicyh4ID0gZXhwcmVzc2lvbigiQWNjbGltYXRpb24gdGVtcGVyYXR1cmUgKFx1MDBCMEMpIiksIA0KICAgICAgIHkgPSBleHByZXNzaW9uKCJFeHBlY3RlZCBoZWF0aW5nIHRvbGVyYW5jZSAoXHUwMEIwQykiKSkgKw0KICBzY2FsZV9jb2xvdXJfdmlyaWRpc19jKG5hbWUgPSBleHByZXNzaW9uKCJIZWF0aW5nIHJhdGUgKFx1MDBCMEMgaCIgXi0xICogIikiKSwgdHJhbnMgPSAibG9nMTAiLCBsYWJlbHMgPSBmdW5jdGlvbih4KSBzaWduaWYoeCkpIA0KDQpnZW5fZWN0bw0KYGBgDQoNCkZpZ3VyZSBcQHJlZihmaWc6Z2VuKSBjYW4gYWxzbyBiZSB2aXN1YWxpc2VkIGFzIHByZWRpY3RlZCB1cHBlciB0aGVybWFsIHRvbGVyYW5jZSBsaW1pdCAkVF9jJCBmb3IgYW55IGFjY2xpbWF0aW9uIHRlbXBlcmF0dXJlICRUX2EkLg0KDQpgYGB7ciBwcmVkaWN0LXRjLCBmaWcuY2FwID0gIkdlbmVyYWxpc2VkIGdyYXBoIG9mIHByZWRpY3RlZCB1cHBlciB0aGVybWFsIHRvbGVyYW5jZSBsaW1pdCBieSBhY2NsaW1hdGlvbiB0ZW1wZXJhdHVyZSBhbmQgaGVhdGluZyByYXRlIChjb2xvdXJzKS4ifQ0KZXhwYW5kX2dyaWQoaGVhdGluZ19yYXRlLCB0YSkgJT4lIA0KICBtdXRhdGUoc3BfbGFtYmRhID0gc3BfaGVhdF9yYXRlIC8gVGssDQogICAgICAgICBzcF90YXVfYSA9IHNwX3RhIC8gVGssDQogICAgICAgICBzcF90YXVfYyA9IHNwX3RjIC8gVGssDQogICAgICAgICBzcF9kZWx0YV90YXUgPSBzcF90YXVfYyAtIHNwX3RhdV9hLA0KICAgICAgICAgdGF1X2EgPSB0YSAvIFRrLCANCiAgICAgICAgIGRlbHRhX3RhdV9hID0gIHNwX3RhdV9hIC0gdGF1X2EsDQogICAgICAgICBsYW1iZGEgPSBoZWF0aW5nX3JhdGUgLyBUaywNCiAgICAgICAgIGxhbWJkYV9yYXRpbyA9IGxhbWJkYS9zcF9sYW1iZGEpICAlPiUgDQogIG11dGF0ZShkZWx0YV90YXVfaGF0ID0gIGZfYmV0YV9mdW4oZXhwKGJldGFfSyAqIGRlbHRhX3RhdV9hKSAqIChsYW1iZGFfcmF0aW8gXiAoMSAtIGdhbW1hKSkgKiBnX2JldGFfZnVuKHNwX2RlbHRhX3RhdSkpKSAlPiUgDQogIGdncGxvdCgpICsgDQogIGdlb21fbGluZShhZXModGEsIGRlbHRhX3RhdV9oYXQgKiBUayArIHRhLCBncm91cCA9IGhlYXRpbmdfcmF0ZSwgY29sID0gaGVhdGluZ19yYXRlKSkgKw0KICBsYWJzKHggPSBleHByZXNzaW9uKCJBY2NsaW1hdGlvbiB0ZW1wZXJhdHVyZSAoXHUwMEIwQykiKSwgDQogICAgICAgeSA9IGV4cHJlc3Npb24oIlVwcGVyIHRoZXJtYWwgdG9sZXJhbmNlIGxpbWl0IChcdTAwQjBDKSIpKSArDQogIHNjYWxlX2NvbG91cl92aXJpZGlzX2MobmFtZSA9IGV4cHJlc3Npb24oIkhlYXRpbmcgcmF0ZSAoXHUwMEIwQyBoIiBeLTEgKiAiKSIpLCB0cmFucyA9ICJsb2cxMCIsIGxhYmVscyA9IGZ1bmN0aW9uKHgpIHNpZ25pZih4KSkgDQpgYGANCg0KKioqDQojIE5vdGF0aW9uIHRhYmxlDQoNClRhYmxlOiAoXCN0YWI6bWF0aHMpIE1haW4gbWF0aGVtYXRpY2FsIG5vdGF0aW9uIGFuZCBkZXNjcmlwdGlvbiB1c2VkLg0KDQp8IFN5bWJvbCB8IERlc2NyaXB0aW9uIHwNCnw6LS0tLS0tOnw6LS0tLS0tLS0tLS0tfA0KfCAkSCQgfCBIZWF0aW5nIHRvbGVyYW5jZTsgcmFuZ2Ugb2YgdGVtcGVyYXR1cmVzIGJldHdlZW4gJFRfYSQgYW5kICRUX2MkCXwgDQp8ICRcRGVsdGEgdCQgfCBFbGFwc2VkIGR1cmF0aW9uIG9mIGEgaGVhdGluZyBhc3NheSBiZXR3ZWVuICR0X2EkIGFuZCAkdF9jJAl8DQp8ICRfciQgCXwgVmFyaWFibGVzIHJlc2NhbGVkIGJ5IHRoZSBVbml2ZXJzYWwgVGVtcGVyYXR1cmUgRGVwZW5kZW5jZQl8DQp8ICRfYSQgCXwgVmFyaWFibGVzIHJlZmVycmluZyB0byBhY2NsaW1hdGlvbiBvciBzdGFydGluZyB0ZW1wZXJhdHVyZSBvZiBhIGhlYXRpbmcgYXNzYXkJfA0KfCAkX2MkIAl8IFZhcmlhYmxlcyByZWZlcnJpbmcgdG8gdGhlIHVwcGVyIHRoZXJtYWwgdG9sZXJhbmNlIGxpbWl0IG9mIGEgaGVhdGluZyBhc3NheQl8DQp8ICRcdGF1JCB8IE5vcm1hbGlzZWQgdGVtcGVyYXR1cmUgc2NhbGUgY2VudHJlZCBhcm91bmQgJFRfSyQgKG5vcm1hbGlzYXRpb24gY29uc3RhbnQgYHIgVGtgSykgfCANCnwgJFxsYW1iZGEkIHwgTm9ybWFsaXNlZCBoZWF0aW5nIHJhdGUgY2VudHJlZCBhcm91bmQgJFRfSyQgfCANCnwgJFxnYW1tYSQgfCBTY2FsaW5nIGV4cG9uZW50IGZvciB0aGUgZWZmZWN0IG9mICRcbGFtYmRhJCBvbiAkXERlbHRhIHRfciQJfCANCg0KKioqDQoNCiMgTWFudXNjcmlwdCBGaWd1cmVzDQoNCmBgYHtyIGZpZ3MsIGV2YWw9RkFMU0V9DQojIHJlc2NhbGVkIGdyYXBocw0KbGVnZW5kIDwtIGdldF9sZWdlbmQoaGVhdGluZ19ncmFwaCArIHRoZW1lKGxlZ2VuZC5ib3gubWFyZ2luID0gbWFyZ2luKDAsIDAsIDAsIDApKSkNCg0KcDIgPC0gcGxvdF9ncmlkKGhlYXRpbmdfZ3JhcGggKyB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSwNCiAgICAgICAgICAgICAgICByZXNjYWxlZF9kdXJhdGlvbiArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpLA0KICAgICAgICAgICAgICAgICMgcmVzY2FsZWRfdG9sZXJhbmNlcyArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpLA0KICAgICAgICAgICAgICAgIGxhYmVscyA9ICJBVVRPIiwgbnJvdyA9IDEsIGFsaWduID0gImh2IiwgaGp1c3QgPSAtMSwgbGFiZWxfc2l6ZSA9IDEwKQ0KDQpmaWcyIDwtIHBsb3RfZ3JpZChwMiwgbGVnZW5kLCByZWxfd2lkdGhzID1jKDMsIDAuNSkpDQpmaWcyDQoNCiMgcHJlZGljdGlvbiBncmFwaHMNCnByZWRfaGlnaF9sb3cgPC0gcHJlZDMgKyBhZXMoY29sID0gaGVhdGluZ19yYXRlKSArIA0KICBzY2FsZV94X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApLCBsaW1pdHMgPSBjKDAsIDQwKSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApLCBsaW1pdHMgPSBjKDAsIDQwKSkgKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFLCBjb2wgPSAxKSArDQogIHNjYWxlX2NvbG91cl92aXJpZGlzX2MobmFtZSA9IGV4cHJlc3Npb24oIkhlYXRpbmcgcmF0ZSAoXHUwMEIwQyBoIiBeLTEgKiAiKSIpLCB0cmFucyA9ICJsb2cxMCIsIGxhYmVscyA9IGZ1bmN0aW9uKHgpIHNpZ25pZih4KSkgKw0KICBnZ3RpdGxlKCJQcmVkaWN0IGZyb20gbG93ZXIgYWNjbGltYXRpb24gdGVtcGVyYXR1cmUiKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpDQoNCnByZWRfbG93X2hpZ2ggPC0gcHJlZDQgKyBhZXMoY29sID0gaGVhdGluZ19yYXRlKSArIA0KICBzY2FsZV94X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApLCBsaW1pdHMgPSBjKDAsIDQwKSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApLCBsaW1pdHMgPSBjKDAsIDQwKSkgKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFLCBjb2wgPSAxKSArDQogIHNjYWxlX2NvbG91cl92aXJpZGlzX2MobmFtZSA9IGV4cHJlc3Npb24oIkhlYXRpbmcgcmF0ZSAoXHUwMEIwQyBoIiBeLTEgKiAiKSIpLCB0cmFucyA9ICJsb2cxMCIsIGxhYmVscyA9IGZ1bmN0aW9uKHgpIHNpZ25pZih4KSkgKw0KICBnZ3RpdGxlKCJQcmVkaWN0IGZyb20gaGlnaGVyIGFjY2xpbWF0aW9uIHRlbXBlcmF0dXJlIikgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKQ0KDQpwMyA8LSBwbG90X2dyaWQocHJlZF9oaWdoX2xvdywgcHJlZF9sb3dfaGlnaCwgbGFiZWxzID0gIkFVVE8iLCBucm93ID0gMSwgYWxpZ24gPSAiaCIsIGhqdXN0ID0gLTEsIGxhYmVsX3NpemUgPSAxMCkNCmZpZzMgPC0gcGxvdF9ncmlkKHAzLCBsZWdlbmQsIHJlbF93aWR0aHMgPWMoMywgMC41KSkNCmZpZzMNCg0KIyBIZWF0aW5nIHJhdGUgZWZmZWN0DQpmaWc1IDwtIHBsb3RfZ3JpZChnX2RlcGFydHVyZSwgZ19zY2FsaW5nLCBnX3ByZWRpY3RfdGF1LCBsYWJlbHMgPSAiQVVUTyIsIG5yb3cgPSAxLCBhbGlnbiA9ICJoIiwgaGp1c3QgPSAtMSwgbGFiZWxfc2l6ZSA9IDEwKQ0KZmlnNQ0KYGBgDQoNCkZpZ3VyZXMgc2F2ZWQgYXMgVElGRi4gUmVzdWx0aW5nIGRhdGFzZXQgKGBBUlJgKSBzYXZlZCBhcyBDU1YuDQoNCmBgYHtyIHNhdmUsIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0V9DQpqb3VybmFsIDwtICJCaW9yaXZ4Ig0KZGlyLmNyZWF0ZShwYXN0ZTAoIi4uL2ZpZ3VyZXMvIiwgam91cm5hbCwgIi8iKSkNCg0KZm9yKGkgaW4gYygidGlmZiIsICJqcGVnIikpew0Kc2F2ZV9wbG90KHBsb3QgPSBmaWcyLCBmaWxlbmFtZSA9IHBhc3RlMCgiLi4vZmlndXJlcy8iLCBqb3VybmFsLCAiL2ZpZzIuIiwgaSksIGRwaSA9IDMwMCwgYmFzZV93aWR0aCA9IDEwLCBiZyA9ICJ3aGl0ZSIpDQpzYXZlX3Bsb3QocGxvdCA9IGZpZzMsIGZpbGVuYW1lID0gcGFzdGUwKCIuLi9maWd1cmVzLyIsIGpvdXJuYWwsICIvZmlnMy4iLCBpKSwgZHBpID0gMzAwLCBiYXNlX3dpZHRoID0gMTAsIGJnID0gIndoaXRlIikNCnNhdmVfcGxvdChwbG90ID0gZmlnNSwgZmlsZW5hbWUgPSBwYXN0ZTAoIi4uL2ZpZ3VyZXMvIiwgam91cm5hbCwgIi9maWc1LiIsIGkpLCBkcGkgPSAzMDAsIGJhc2Vfd2lkdGggPSA4LCBiYXNlX2hlaWdodCA9IDMsIGJnID0gIndoaXRlIikNCn0NCg0KIyBTdXBwbGVtZW50YXJ5DQpzYXZlX3Bsb3QocGxvdCA9IHNlbnNpX3Bsb3QsIGZpbGVuYW1lID0gcGFzdGUwKCIuLi9maWd1cmVzLyIsIGpvdXJuYWwsICIvZmlnUzEuanBlZyIpLCBkcGkgPSAzMDAsIGJhc2Vfd2lkdGggPSAxMCwgYmFzZV9oZWlnaHQgPSA1LCBiZyA9ICJ3aGl0ZSIpDQpzYXZlX3Bsb3QocGxvdCA9IHJlc2NhbGVkX3RvbGVyYW5jZXMsIGZpbGVuYW1lID0gcGFzdGUwKCIuLi9maWd1cmVzLyIsIGpvdXJuYWwsICIvZmlnUzIuanBlZyIpLCBkcGkgPSAzMDAsIGJnID0gIndoaXRlIikNCnNhdmVfcGxvdChwbG90ID0gcHJlZDEsIGZpbGVuYW1lID0gcGFzdGUwKCIuLi9maWd1cmVzLyIsIGpvdXJuYWwsICIvZmlnUzMuanBlZyIpLCBkcGkgPSAzMDAsIGJnID0gIndoaXRlIikNCnNhdmVfcGxvdChwbG90ID0gcHJlZDIsIGZpbGVuYW1lID0gcGFzdGUwKCIuLi9maWd1cmVzLyIsIGpvdXJuYWwsICIvZmlnUzQuanBlZyIpLCBkcGkgPSAzMDAsIGJnID0gIndoaXRlIikNCg0KIyBkYXRhDQojIHdyaXRlLmNzdihBUlIsIGZpbGUgPSAicmVzY2FsZWRfaGVhdGluZ190b2xlcmFuY2VzX2RhdGEuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpDQpgYGANCg0KKioqDQoNCiMgU2Vzc2lvbiBpbmZvDQpgYGB7ciBzZXNzaW9uLCBlY2hvPUZBTFNFfQ0Kc2Vzc2lvbkluZm8oKQ0KYGBgDQoNCioqKg0KDQojIFJlZmVyZW5jZXMNCg==