README
This document presents the full workflow of Heating tolerance of an ectotherm does not vary when temperature’s influence on biological rates is accounted for, including the full derivation of the equations, data processing and generating figures for the study. Figure and equation numbering here is independent of the main and supplemental text.

The analysis was conducted in R version 4.2.2 (2022-10-31 ucrt) (R Core Team 2022) running Tidyverse (Wickham 2019) & cowplot (Wilke 2020). This document was created using bookdown (Xie 2020) (Session info). Top right drop down menu can show code and download the Rmarkdown file.


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) \]


Heating tolerance

We defined heating tolerance (\(H\)) as

\[\begin{equation} H = T_c - T_a \tag{1} \end{equation}\]

where \(T_a\) is acclimation temperature (°C, also starting temperature of the heating assay) and \(T_c\) is upper thermal tolerance limit (°C). We calculated heating tolerances (\(H\)) at the lower (ht_low) and higher acclimation (ht_high) temperature.

# Calculate heating tolerances, H (Equation 1)
ARR <- ARR %>% 
  mutate(ht_low = tc_low - ta_low,
         ht_high = tc_high - ta_high)
Heating tolerances at the lower and higher acclimation temperatures for paired observations on Log10 transformed axes.

Figure 1: Heating tolerances at the lower and higher acclimation temperatures for paired observations on Log10 transformed axes.


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.

Rescaled heating duration at the lower and higher acclimation temperature on Log10 axes have a strong dependency with heating rate (colours).

Figure 2: Rescaled heating duration at the lower and higher acclimation temperature on Log10 axes have a strong dependency with heating rate (colours).


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.

Dimensionless rescaled heating durations at the lower and higher acclimation temperatures on Log10 axes.

Figure 3: Dimensionless rescaled heating durations at the lower and higher acclimation temperatures on Log10 axes.


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
Variation in activation energy (eV). Observations (points) with a fitted linear model (solid line) fall along the identity line (dashed line).

Figure 4: Variation in activation energy (eV). Observations (points) with a fitted linear model (solid line) fall along the identity line (dashed line).


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
Predicting higher acclimation temperature heating tolerance from lower acclimation temperature heating tolerance assuming heating tolerance is the same.

Figure 5: Predicting higher acclimation temperature heating tolerance from lower acclimation temperature heating tolerance assuming heating tolerance is the same.

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
Predicting higher acclimation temperature heating tolerance correcting for acclimation temperature

Figure 6: Predicting higher acclimation temperature heating tolerance correcting for acclimation temperature

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
Correction for acclimation temperature and change in temperature over time to predict heating tolerance at the higher acclimation temperature from the lower acclimation temperature.

Figure 7: Correction for acclimation temperature and change in temperature over time to predict heating tolerance at the higher acclimation temperature from the lower acclimation temperature.

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
Predicting lower temperature heating tolerance from higher temperature heating tolerance

Figure 8: Predicting lower temperature heating tolerance from higher temperature heating tolerance

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
Predicted heating tolerance versus observed heating tolerance for species with varying heating rates (107 observations). Colours are species (n = 37).

Figure 9: Predicted heating tolerance versus observed heating tolerance for species with varying heating rates (107 observations). Colours are species (n = 37).

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
Interspecific scaling of rescaled heating duration with heating rate. Variation within each species is shown by the fitted lines between points (129 observations). The dashed identity line is the expected relationship following the null hypothesis. Axes are Log10 transformed. Colours are species (n = 37).

Figure 10: Interspecific scaling of rescaled heating duration with heating rate. Variation within each species is shown by the fitted lines between points (129 observations). The dashed identity line is the expected relationship following the null hypothesis. Axes are Log10 transformed. Colours are species (n = 37).


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
Predicted heating tolerance corrected using species-specific scaling exponents for the allometric relationship between rescaled heating duration and heating rate. Colours are species.

Figure 11: Predicted heating tolerance corrected using species-specific scaling exponents for the allometric relationship between rescaled heating duration and heating rate. Colours are species.

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.

Predicted heating tolerances calculated using a value of 0.766 for gamma, representing an interspecific parameter. Colours are species.

Figure 12: Predicted heating tolerances calculated using a value of 0.766 for gamma, representing an interspecific parameter. Colours are 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
Generalised graph of predicted heating tolerance by acclimation temperature and heating rate (colours).

Figure 13: Generalised graph of predicted heating tolerance by acclimation temperature and heating rate (colours).

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)) 
Generalised graph of predicted upper thermal tolerance limit by acclimation temperature and heating rate (colours).

Figure 14: Generalised graph of predicted upper thermal tolerance limit by acclimation temperature and heating rate (colours).


Notation table

Table 1: Main mathematical notation and description used.
Symbol Description
\(H\) Heating tolerance; range of temperatures between \(T_a\) and \(T_c\)
\(\Delta t\) Elapsed duration of a heating assay between \(t_a\) and \(t_c\)
\(_r\) Variables rescaled by the Universal Temperature Dependence
\(_a\) Variables referring to acclimation or starting temperature of a heating assay
\(_c\) Variables referring to the upper thermal tolerance limit of a heating assay
\(\tau\) Normalised temperature scale centred around \(T_K\) (normalisation constant 273.15K)
\(\lambda\) Normalised heating rate centred around \(T_K\)
\(\gamma\) Scaling exponent for the effect of \(\lambda\) on \(\Delta t_r\)

Manuscript Figures

# rescaled graphs
legend <- get_legend(heating_graph + theme(legend.box.margin = margin(0, 0, 0, 0)))

p2 <- plot_grid(heating_graph + theme(legend.position="none"),
                rescaled_duration + theme(legend.position="none"),
                # rescaled_tolerances + theme(legend.position="none"),
                labels = "AUTO", nrow = 1, align = "hv", hjust = -1, label_size = 10)

fig2 <- plot_grid(p2, legend, rel_widths =c(3, 0.5))
fig2

# prediction graphs
pred_high_low <- pred3 + aes(col = heating_rate) + 
  scale_x_continuous(expand = c(0,0), limits = c(0, 40)) +
  scale_y_continuous(expand = c(0,0), limits = c(0, 40)) +
  geom_smooth(method = "lm", se = FALSE, col = 1) +
  scale_colour_viridis_c(name = expression("Heating rate (\u00B0C h" ^-1 * ")"), trans = "log10", labels = function(x) signif(x)) +
  ggtitle("Predict from lower acclimation temperature") +
  theme(legend.position="none")

pred_low_high <- pred4 + aes(col = heating_rate) + 
  scale_x_continuous(expand = c(0,0), limits = c(0, 40)) +
  scale_y_continuous(expand = c(0,0), limits = c(0, 40)) +
  geom_smooth(method = "lm", se = FALSE, col = 1) +
  scale_colour_viridis_c(name = expression("Heating rate (\u00B0C h" ^-1 * ")"), trans = "log10", labels = function(x) signif(x)) +
  ggtitle("Predict from higher acclimation temperature") +
  theme(legend.position="none")

p3 <- plot_grid(pred_high_low, pred_low_high, labels = "AUTO", nrow = 1, align = "h", hjust = -1, label_size = 10)
fig3 <- plot_grid(p3, legend, rel_widths =c(3, 0.5))
fig3

# Heating rate effect
fig5 <- plot_grid(g_departure, g_scaling, g_predict_tau, labels = "AUTO", nrow = 1, align = "h", hjust = -1, label_size = 10)
fig5

Figures saved as TIFF. Resulting dataset (ARR) saved as CSV.


Session info

R version 4.2.2 (2022-10-31 ucrt)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 10 x64 (build 19044)

Matrix products: default

locale:
[1] LC_COLLATE=English_United Kingdom.utf8 
[2] LC_CTYPE=English_United Kingdom.utf8   
[3] LC_MONETARY=English_United Kingdom.utf8
[4] LC_NUMERIC=C                           
[5] LC_TIME=English_United Kingdom.utf8    

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

other attached packages:
 [1] cowplot_1.1.1   forcats_0.5.2   stringr_1.4.1   dplyr_1.0.10   
 [5] purrr_0.3.5     readr_2.1.3     tidyr_1.2.1     tibble_3.1.8   
 [9] ggplot2_3.4.0   tidyverse_1.3.2

loaded via a namespace (and not attached):
 [1] lattice_0.20-45     lubridate_1.9.0     assertthat_0.2.1   
 [4] rprojroot_2.0.3     digest_0.6.30       utf8_1.2.2         
 [7] R6_2.5.1            cellranger_1.1.0    backports_1.4.1    
[10] reprex_2.0.2        evaluate_0.18       highr_0.9          
[13] httr_1.4.4          pillar_1.8.1        rlang_1.0.6        
[16] googlesheets4_1.0.1 readxl_1.4.1        rstudioapi_0.14    
[19] jquerylib_0.1.4     Matrix_1.5-1        rmarkdown_2.18     
[22] labeling_0.4.2      splines_4.2.2       googledrive_2.0.0  
[25] munsell_0.5.0       broom_1.0.1         compiler_4.2.2     
[28] modelr_0.1.9        xfun_0.34           pkgconfig_2.0.3    
[31] mgcv_1.8-41         htmltools_0.5.3     tidyselect_1.2.0   
[34] bookdown_0.30       viridisLite_0.4.1   fansi_1.0.3        
[37] crayon_1.5.2        tzdb_0.3.0          dbplyr_2.2.1       
[40] withr_2.5.0         grid_4.2.2          nlme_3.1-160       
[43] jsonlite_1.8.3      gtable_0.3.1        lifecycle_1.0.3    
[46] DBI_1.1.3           magrittr_2.0.3      scales_1.2.1       
[49] cli_3.4.1           stringi_1.7.8       cachem_1.0.6       
[52] farver_2.1.1        fs_1.5.2            xml2_1.3.3         
[55] bslib_0.4.1         ellipsis_0.3.2      generics_0.1.3     
[58] vctrs_0.5.0         tools_4.2.2         glue_1.6.2         
[61] hms_1.1.2           fastmap_1.1.0       yaml_2.3.6         
[64] timechange_0.1.1    colorspace_2.0-3    gargle_1.2.1       
[67] rvest_1.0.3         knitr_1.40          haven_2.5.1        
[70] sass_0.4.2         

References

Dell, Anthony I., Samraat Pawar, and Van M. Savage. 2011. “Systematic Variation in the Temperature Dependence of Physiological and Ecological Traits.” Journal Article. Proceedings of the National Academy of Sciences 108 (26): 10591–96. https://doi.org/10.1073/pnas.1015178108.
Morley, S. A., A. E. Bates, M. Lamare, J. Richard, K. D. Nguyen, J. Brown, and L. S. Peck. 2016. “Rates of Warming and the Global Sensitivity of Shallow Water Marine Invertebrates to Elevated Temperature.” Journal Article. Journal of the Marine Biological Association of the United Kingdom 96 (1): 159–65. https://doi.org/10.1017/S0025315414000307.
Morley, S. A., L. S. Peck, J. M. Sunday, S. Heiser, and A. E. Bates. 2019. “Physiological Acclimation and Persistence of Ectothermic Species Under Extreme Heat Events.” Journal Article. Global Ecology and Biogeography 28 (7): 1018–37. https://doi.org/10.1111/geb.12911.
Morley, S. A., L. S. Peck, J. Sunday, S. Heiser, and A. E. Bates. 2018. “Acclimation Potential of Global Ectothermic Species, Collated from Literature, 1960 to 2015.” Dataset. Natural Environment Research Council, Cambridge, UK. https://doi.org/https://doi.org/10.5285/20010bfb-c6d3-430f-b1f7-d16790ab8359.
R Core Team. 2022. R: A Language and Environment for Statistical Computing. Vienna, Austria: R Foundation for Statistical Computing. https://www.R-project.org/.
Wickham, Hadley. 2019. Tidyverse: Easily Install and Load the Tidyverse. https://CRAN.R-project.org/package=tidyverse.
Wilke, Claus O. 2020. Cowplot: Streamlined Plot Theme and Plot Annotations for ’Ggplot2’. https://CRAN.R-project.org/package=cowplot.
Xie, Yihui. 2020. Bookdown: Authoring Books and Technical Documents with r Markdown. https://github.com/rstudio/bookdown.

  1. Trinity College Dublin, Ireland, ↩︎

  2. Trinity College Dublin, Ireland, ↩︎

  3. Trinity College Dublin, Ireland, ↩︎

  4. CNRS, France, ↩︎

LS0tDQp0aXRsZTogIlN1cHBsZW1lbnRhcnkgTWF0ZXJpYWwiDQpzdWJ0aXRsZTogIkhlYXRpbmcgdG9sZXJhbmNlIG9mIGVjdG90aGVybXMgaXMgZXhwbGFpbmVkIGJ5IHRlbXBlcmF0dXJl4oCZcyBub24tbGluZWFyIGluZmx1ZW5jZSBvbiBiaW9sb2dpY2FsIHJhdGVzIg0KZGF0ZTogImByIGZvcm1hdChTeXMuRGF0ZSgpLCAnJWQvJW0vJVknKWAiDQphdXRob3I6DQogIC0gSmFjaW50YSBLb25nXltUcmluaXR5IENvbGxlZ2UgRHVibGluLCBJcmVsYW5kLCBrb25nakB0Y2QuaWVdDQogIC0gQW5kcmV3IEphY2tzb25eW1RyaW5pdHkgQ29sbGVnZSBEdWJsaW4sIElyZWxhbmQsIGphY2tzb2FuQHRjZC5pZV0NCiAgLSBOaWNob2xhcyBQYXluZV5bVHJpbml0eSBDb2xsZWdlIER1YmxpbiwgSXJlbGFuZCwgcGF5bmVuQHRjZC5pZV0NCiAgLSBKZWFuIEZyYW4mY2NlZGlsO29pcyBBcm5vbGRpXltDTlJTLCBGcmFuY2UsIGFybm9sZGkuamVmZkBnbWFpbC5jb21dDQpvdXRwdXQ6DQogIGJvb2tkb3duOjpodG1sX2RvY3VtZW50MjoNCiAgICBudW1iZXJfc2VjdGlvbnM6IEZBTFNFDQogICAgY29kZV9kb3dubG9hZDogeWVzDQogICAgY29kZV9mb2xkaW5nOiBoaWRlDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZmxvYXQ6IHllcw0KICAgIGhpZ2hsaWdodDogdGFuZ28NCiAgYm9va2Rvd246OndvcmRfZG9jdW1lbnQyOg0KICAgIG51bWJlcl9zZWN0aW9uczogRkFMU0UNCiAgYm9va2Rvd246OnBkZl9kb2N1bWVudDI6IGRlZmF1bHQNCmVkaXRvcl9vcHRpb25zOg0KICBjaHVua19vdXRwdXRfdHlwZTogY29uc29sZQ0KYmlibGlvZ3JhcGh5OiByYXRlcy5iaWINCi0tLQ0KDQpgYGB7ciBzZXR1cCwgbWVzc2FnZT1GQUxTRSwgZWNobyA9IEZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KA0KICBtZXNzYWdlID0gRkFMU0UsDQogIHdhcm5pbmcgPSBGQUxTRSwNCiAgY29tbWVudCA9IE5BLA0KICBlY2hvID0gVFJVRSwNCiAgZmlnLmFsaWduID0gJ2NlbnRlcicsDQogIGZpZy53aWR0aCA9IDYsDQogIGZpZy5oZWlnaHQgPSA1DQopDQoNCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShjb3dwbG90KQ0KdGhlbWVfc2V0KHRoZW1lX2NsYXNzaWMoYmFzZV9zaXplID0gMTApKSAjIHNldCBkZWZhdWx0IGZvbnQgc2l6ZQ0Kb3B0aW9ucyh0aWJibGUud2lkdGggPSBJbmYpDQpgYGANCg0KKipSRUFETUUqKiAgDQpUaGlzIGRvY3VtZW50IHByZXNlbnRzIHRoZSBmdWxsIHdvcmtmbG93IG9mICpIZWF0aW5nIHRvbGVyYW5jZSBvZiBhbiBlY3RvdGhlcm0gZG9lcyBub3QgdmFyeSB3aGVuIHRlbXBlcmF0dXJl4oCZcyBpbmZsdWVuY2Ugb24gYmlvbG9naWNhbCByYXRlcyBpcyBhY2NvdW50ZWQgZm9yKiwgaW5jbHVkaW5nIHRoZSBmdWxsIGRlcml2YXRpb24gb2YgdGhlIGVxdWF0aW9ucywgZGF0YSBwcm9jZXNzaW5nIGFuZCBnZW5lcmF0aW5nIGZpZ3VyZXMgZm9yIHRoZSBzdHVkeS4gRmlndXJlIGFuZCBlcXVhdGlvbiBudW1iZXJpbmcgaGVyZSBpcyBpbmRlcGVuZGVudCBvZiB0aGUgbWFpbiBhbmQgc3VwcGxlbWVudGFsIHRleHQuIA0KDQpUaGUgYW5hbHlzaXMgd2FzIGNvbmR1Y3RlZCBpbiBgciBSLnZlcnNpb24uc3RyaW5nYCBbQFItYmFzZV0gcnVubmluZyBgVGlkeXZlcnNlYCBbQFItdGlkeXZlcnNlXSAmIGBjb3dwbG90YCBbQFItY293cGxvdF0uIFRoaXMgZG9jdW1lbnQgd2FzIGNyZWF0ZWQgdXNpbmcgYGJvb2tkb3duYCBbQFItYm9va2Rvd25dIChbU2Vzc2lvbiBpbmZvXSkuIFRvcCByaWdodCBkcm9wIGRvd24gbWVudSBjYW4gc2hvdyBjb2RlIGFuZCBkb3dubG9hZCB0aGUgUm1hcmtkb3duIGZpbGUuIA0KDQoqKioNCg0KIyBIZWF0aW5nIHRvbGVyYW5jZSBkYXRhDQoNCmBgYHtyIGltcG9ydH0NCkFSUiA8LSByZWFkeGw6OnJlYWRfZXhjZWwoIi4uL2RhdGEvTW9ybGV5MjAxOC54bHN4IiwgIHNraXAgPSA4KSAlPiUgDQogICMgQWRkIHVuaXF1ZSBpZA0KICByb3dpZF90b19jb2x1bW4oInJvd19JRCIpICU+JSAgDQogICMgcmVtb3ZlIGJsYW5rIHJvd3MNCiAgZmlsdGVyKCFpcy5uYShUYXhvbikpICU+JQ0KICAjIHJlbmFtZSBjb2x1bW5zDQogIHJlbmFtZSgidGFfaGlnaCIgPSAxMSwgIyJIaWdoIGFjY2xpbWF0aW9uIFRlbXBlcmF0dXJlIC/CsEMiICwNCiAgICAgICAgICJ0YV9sb3ciID0gMTIsICMiTG93IEFjY2xpbWF0aW9uIFRlbXBlcmF0dXJlLyDCsEMiICwNCiAgICAgICAgICJBUlIiID0gMTcsICMiQ1RNYXggQVJSIiAsDQogICAgICAgICAidGNfaGlnaCIgPSAxNiwgIyJDVE1heC8gwrBDIiwgIyBDVCBtYXggb2YgdGhlIGhpZ2ggYWNjbGltYXRpb24gdGVtcGVyYXR1cmUNCiAgICAgICAgICJhY2NsaW1fd2luZG93IiA9IDEzLCAjIkFjY2xpbWF0aW9uIFdpbmRvdyAvwrBDIiwNCiAgICAgICAgICJoZWF0aW5nX3JhdGUiID0gMjIsICMiwrBDIGNoYW5nZSBoci0xIiwNCiAgICAgICAgICJjb2xsZWN0aW9uX2xhdGl0dWRlIiA9IDE5KSAlPiUgICMiTGF0aXR1ZGUgb2YgQ29sbGVjdGlvbi8gwrAiKSAlPiUNCiAgIyBmaXggdHlwbyBpbiB0YXhvbg0KICBtdXRhdGUoVGF4b24gPSBzdHJfcmVwbGFjZV9hbGwoVGF4b24sICJhbXBoaWJhaW5zIiwgImFtcGhpYmlhbnMiKSkgJT4lDQogICMgRml4IGluY29ycmVjdCBoZWF0aW5nIHJhdGUgaW4gRE9JIDEwLjEwMDcvczEwNjk1LTAxMy05NzkzLTcNCiAgbXV0YXRlKGhlYXRpbmdfcmF0ZSA9IGlmZWxzZShyb3dfSUQgID09IDM2NywgKDAuMyAqIDYwKSwgaGVhdGluZ19yYXRlKSkgJT4lDQogICMgQ2FsY3VsYXRlIGxvdyB0ZW1wZXJhdHVyZSBDVCBtYXgNCiAgbXV0YXRlKHRjX2xvdyA9IHRjX2hpZ2ggLSAoQVJSICogYWNjbGltX3dpbmRvdykpIA0KYGBgDQoNCldlIHVzZWQgdGhlIGFjY2xpbWF0aW9uIGRhdGFzZXQgYXZhaWxhYmxlIGZyb20gdGhlIFtQb2xhciBEYXRhIENlbnRyZV0oaHR0cHM6Ly9kb2kub3JnLzEwLjUyODUvMjAwMTBiZmItYzZkMy00MzBmLWIxZjctZDE2NzkwYWI4MzU5KSB1bmRlciBhbiBPcGVuIEdvdmVybm1lbnQgTGljZW5jZSB2My4wIFtATW9ybGV5MjAxOF0uIFRoZSBkYXRhIHdhcyBwdWJsaXNoZWQgaW4gQE1vcmxleTIwMTkuIFRoZSBkYXRhc2V0IGNvbnRhaW5zIEFjY2xpbWF0aW9uIFJlc3BvbnNlIFJhdGlvcyAoQVJSKSwgYWNjbGltYXRpb24gdGVtcGVyYXR1cmVzICgkVF9hJCkgYW5kIHVwcGVyIHRoZXJtYWwgdG9sZXJhbmNlIGxpbWl0cyAoJFRfYyQpIG9mIGVjdG90aGVybXMgY29tcGlsZWQgZnJvbSB0aGUgbGl0ZXJhdHVyZSBiZXR3ZWVuIDE5NjAgLSAyMDE1LiBFY3RvdGhlcm1zIHdlcmUgYWNjbGltYXRlZCBmb3IgYmV0d2VlbiBgciBtaW4oQVJSJCdBY2NsaW1hdGlvbiBkdXJhdGlvbi8gZGF5cycpYCBhbmQgYHIgbWF4KEFSUiQnQWNjbGltYXRpb24gZHVyYXRpb24vIGRheXMnKWAgZGF5cyB0byBhIGxvd2VyIHRlbXBlcmF0dXJlIChgdGFfbG93YCkgb3IgYSBoaWdoZXIgdGVtcGVyYXR1cmUgKGB0YV9oaWdoYCkgdG8gZ2l2ZSBwYWlyZWQgb2JzZXJ2YXRpb25zIGZvciBlYWNoIHNwZWNpZXMuIEFuaW1hbHMgd2VyZSBoZWF0ZWQgdW5kZXIgYSBjb25zdGFudCByYW1waW5nIHRlbXBlcmF0dXJlIGZyb20gJFRfYSQgdW50aWwgdGhlIHBvaW50IG9mIG9yZ2FuaXNtYWwgY29sbGFwc2UgKCRUX2MkKSwgY2FsbGVkIENUfm1heH4gaW4gQE1vcmxleTIwMTkuIFVwcGVyIHRoZXJtYWwgdG9sZXJhbmNlIGxpbWl0cyB3ZXJlIGFzc2F5ZWQgZm9yIGJvdGggYWNjbGltYXRpb24gdGVtcGVyYXR1cmVzIGluIHBhaXJlZCBvYnNlcnZhdGlvbnMgZm9yIGEgc3BlY2llcyAoYHRjX2xvd2Agb3IgYHRjX2hpZ2hgKS4gV2l0aGluIHBhaXJlZCBvYnNlcnZhdGlvbnMsIGVhY2ggc3BlY2llcyB3YXMgbWVhc3VyZWQgYXQgdGhlIHNhbWUgY29uc3RhbnQgaGVhdGluZyByYXRlLCBidXQgaGVhdGluZyByYXRlcyB2YXJpZWQgYW1vbmcgcGFpcmVkIG9ic2VydmF0aW9ucyByZXByZXNlbnRpbmcgaW5kZXBlbmRlbnQgc3BlY2llcyBvciBleHBlcmltZW50YWwgYXNzYXlzLiBEYXRhIHdlcmUgb25seSBpbmNsdWRlZCBpZiBlYWNoIHNwZWNpZXMgaGFkICRUX2MkIG1lYXN1cmVkIGZvciB0d28gZGlmZmVyZW50IHN0YXJ0aW5nICRUX2EkLCBhbGxvd2luZyB1cyB0byBjb21wYXJlIGhlYXRpbmcgdG9sZXJhbmNlcyBib3RoIHdpdGhpbiBhbmQgYW1vbmcgc3BlY2llcy4NCg0KVGhlIGRhdGFzZXQgY29udGFpbmVkIGByIG5yb3coQVJSKWAgb2JzZXJ2YXRpb25zIG9mIGByIGxlbmd0aCh1bmlxdWUoQVJSJE5hbWUpKWAgc3BlY2llcyBmcm9tIGByIGxlbmd0aCh1bmlxdWUoQVJSJENsYXNzKSlgIENsYXNzZXMgcmVwcmVzZW50aW5nIG1hcmluZSwgdGVycmVzdHJpYWwgYW5kIGZyZXNod2F0ZXIgaGFiaXRhdHMgKDcgUGh5bGE6IENob3JkYXRhLCBBcnRocm9wb2RhLCBNb2xsdXNjYSwgUGxhdHloZWxtaW50aGVzLCBFY2hpbm9kZXJtYXRhLCBCcmFjaGlvcG9kYSBhbmQgQ25pZGFyaWEpLg0KDQpUaGUgJFRfYyQgb2YgdGhlIGxvd2VyIGFjY2xpbWF0aW9uIHRlbXBlcmF0dXJlIHdhcyBub3QgcmVwb3J0ZWQgaW4gQE1vcmxleTIwMTkuIFdlIGRlcml2ZWQgdGhlICRUX2MkIG9mIHRoZSBsb3dlciBhY2NsaW1hdGlvbiB0ZW1wZXJhdHVyZSBmcm9tIHJlYXJyYW5naW5nIHRoZSBmb3JtdWxhIGZvciBBUlIuIFdlIGZpcnN0IGNhbGN1bGF0ZSB0aGUgZGlmZmVyZW5jZSBpbiAkVF9jJCBiZXR3ZWVuIHRoZSB0d28gYWNjbGltYXRpb24gdGVtcGVyYXR1cmVzIGZyb20gQVJSIG11bHRpcGxpZWQgYnkgdGhlIGRpZmZlcmVuY2UgaW4gYWNjbGltYXRpb24gdGVtcGVyYXR1cmVzOyBjYWxsZWQgYWNjbGltYXRpb24gd2luZG93IChgYWNjbGltX3dpbmRvd2ApIGZvbGxvd2luZyBATW9ybGV5MjAxOS4gV2UgdGhlbiBjYWxjdWxhdGUgJFRfYyQgb2YgdGhlIGxvd2VyIGFjY2xpbWF0aW9uIHRlbXBlcmF0dXJlIChgdGNfbG93YCkgYnkgc3VidHJhY3RpbmcgdGhlIGRpZmZlcmVuY2UgaW4gJFRfYyQgZnJvbSB0aGUgJFRfYyQgb2YgdGhlIGhpZ2hlciBhY2NsaW1hdGlvbiB0ZW1wZXJhdHVyZSAoYHRjX2hpZ2hgKS4NCg0KJCQNClRfe2MgXHNwYWNlIGxvd2VyfSA9IFRfe2MgXHNwYWNlIGhpZ2hlcn0gLSAoQVJSIFx0aW1lcyBhY2NsaW1hdGlvbiBcc3BhY2Ugd2luZG93KQ0KJCQNCg0KKioqDQoNCiMgSGVhdGluZyB0b2xlcmFuY2UNCg0KV2UgZGVmaW5lZCBoZWF0aW5nIHRvbGVyYW5jZSAoJEgkKSBhcw0KDQpcYmVnaW57ZXF1YXRpb259DQpIID0gVF9jIC0gVF9hIA0KKFwjZXE6SCkNClxlbmR7ZXF1YXRpb259DQoNCndoZXJlICRUX2EkIGlzIGFjY2xpbWF0aW9uIHRlbXBlcmF0dXJlICgmZGVnO0MsIGFsc28gc3RhcnRpbmcgdGVtcGVyYXR1cmUgb2YgdGhlIGhlYXRpbmcgYXNzYXkpIGFuZCAkVF9jJCBpcyB1cHBlciB0aGVybWFsIHRvbGVyYW5jZSBsaW1pdCAoJmRlZztDKS4gV2UgY2FsY3VsYXRlZCBoZWF0aW5nIHRvbGVyYW5jZXMgKCRIJCkgYXQgdGhlIGxvd2VyIChgaHRfbG93YCkgYW5kIGhpZ2hlciBhY2NsaW1hdGlvbiAoYGh0X2hpZ2hgKSB0ZW1wZXJhdHVyZS4NCg0KYGBge3IgSH0NCiMgQ2FsY3VsYXRlIGhlYXRpbmcgdG9sZXJhbmNlcywgSCAoRXF1YXRpb24gMSkNCkFSUiA8LSBBUlIgJT4lIA0KICBtdXRhdGUoaHRfbG93ID0gdGNfbG93IC0gdGFfbG93LA0KICAgICAgICAgaHRfaGlnaCA9IHRjX2hpZ2ggLSB0YV9oaWdoKQ0KYGBgDQoNCmBgYHtyIEgtZ3JhcGgsIGVjaG8gPSBGQUxTRSwgZmlnLmNhcCA9ICJIZWF0aW5nIHRvbGVyYW5jZXMgYXQgdGhlIGxvd2VyIGFuZCBoaWdoZXIgYWNjbGltYXRpb24gdGVtcGVyYXR1cmVzIGZvciBwYWlyZWQgb2JzZXJ2YXRpb25zIG9uIExvZzEwIHRyYW5zZm9ybWVkIGF4ZXMuIn0NCmhlYXRpbmdfZ3JhcGggPC0gQVJSICU+JSANCiAgZ2dwbG90KGFlcyhodF9sb3csIGh0X2hpZ2gsIGNvbCA9IGhlYXRpbmdfcmF0ZSkpICsNCiAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwLCBsdHkgPSAyLCBhbHBoYSA9IDAuNikgKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFLCBjb2wgPSAxKSArIA0KICBnZW9tX3BvaW50KCkgKw0KICBsYWJzKHggPSBleHByZXNzaW9uKCJMb3dlciBhY2NsaW1hdGlvbiB0ZW1wZXJhdHVyZSBIIChcdTAwQjBDKSIpLA0KICAgICAgIHkgPSBleHByZXNzaW9uKCJIaWdoZXIgYWNjbGltYXRpb24gdGVtcGVyYXR1cmUgSCAoXHUwMEIwQykiKSwNCiAgICAgICB0aXRsZSA9IGV4cHJlc3Npb24oIkhlYXRpbmcgdG9sZXJhbmNlLCBIIikpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMoMyw0MCksIGV4cGFuZCA9IGMoMCwwKSwgdHJhbnMgPSAibG9nMTAiKSArDQogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDMsNDApLCBleHBhbmQgPSBjKDAsMCksIHRyYW5zID0gImxvZzEwIikgKw0KICBjb29yZF9lcXVhbCgpICsgIA0KICBzY2FsZV9jb2xvdXJfdmlyaWRpc19jKG5hbWUgPSBleHByZXNzaW9uKCJIZWF0aW5nIHJhdGUgKFx1MDBCMEMgaCIgXi0xICogIikiKSwgdHJhbnMgPSAibG9nMTAiLCBsYWJlbHMgPSBmdW5jdGlvbih4KSBzaWduaWYoeCkpDQoNCmhlYXRpbmdfZ3JhcGgNCmBgYA0KDQoqKioNCg0KIyBSZXNjYWxpbmcgaGVhdGluZyB0b2xlcmFuY2UgdmlhIGhlYXRpbmcgZHVyYXRpb24NCiMjIFBoeXNpb2xvZ2ljYWwgcHJvY2Vzc2VzIHVuZGVybHlpbmcgaGVhdGluZyByZXNwb25zZXMgc2NhbGUgbm9uLWxpbmVhcmx5IHdpdGggdGVtcGVyYXR1cmUNCg0KYGBge3IgY29uc3RhbnRzfQ0KIyBEZWZpbmUgY29uc3RhbnRzIGZvciByZXNjYWxpbmcNCiMgQm9sdHptYW5uJ3MgY29uc3RhbnQsIGssICBpbiB1bml0cyBvZiBlViBLLTENCmsgPC0gOC42MTczMyAqIDEwIF4gLTUNCiMgS2VsdmluIHRvIENlbHNpdXMgY29udmVyc2lvbiBmb3Igbm9ybWFsaXNhdGlvbiBUX0sNClRrIDwtIDI3My4xNQ0KIyBkZWZpbmUgXGJldGEgZm9yIGEgZ2l2ZW4gYWN0aXZhdGlvbiBlbmVyZ3ksIEUgPSAwLjYgKEVxdWF0aW9uIDUpDQpiZXRhX0sgPC0gMC42IC8gKGsgKiBUaykNCmBgYA0KDQpJZiB0aGUgZW5kcG9pbnQgb2YgdXBwZXIgdGhlcm1hbCB0b2xlcmFuY2UgbGltaXRzIGlzIHRoZSBwcm9kdWN0IG9mIGJpb2xvZ2ljYWwgcHJvY2Vzc2VzIGFuZCByYXRlcywgdGhlbiB3ZSBtYXkgZXhwZWN0IHRoZXNlIHJhdGVzIHRvIHNjYWxlIHdpdGggdGVtcGVyYXR1cmUsIGluZGVwZW5kZW50IG9mIGhlYXRpbmcgcmF0ZS4gVGh1cywgYWNjbGltYXRpb24gdGVtcGVyYXR1cmUgaW5mbHVlbmNlcyB1cHBlciB0aGVybWFsIHRvbGVyYW5jZSBsaW1pdHMgdmlhIGEgbm9uLWxpbmVhciB0aGVybWFsIGRlcGVuZGVuY2UuIFdlIHVzZSB0aGUgVW5pdmVyc2FsIFRlbXBlcmF0dXJlIERlcGVuZGVuY2Ugb2YgYmlvbG9naWNhbCByYXRlcyAoaS5lLiwgQm9sdHptYW5uLUFycmhlbml1cyBlcXVhdGlvbiwgRXF1YXRpb24gXEByZWYoZXE6QkEpKSB0byByZXByZXNlbnQgdGhlIG5vbi1saW5lYXIgZWZmZWN0IG9mIHRlbXBlcmF0dXJlIG9uIGJpb2xvZ2ljYWwgcmF0ZXMuIFdlIGFzc3VtZSB0aGF0IHRoZSBCb2x0em1hbm4tQXJyaGVuaXVzIGVxdWF0aW9uIGFkZXF1YXRlbHkgZW5jb21wYXNzZXMgYWxsIHBoeXNpb2xvZ2ljYWwgcHJvY2Vzc2VzIHVuZGVybHlpbmcgaGVhdGluZyB0b2xlcmFuY2UgYW5kIHVwcGVyIHRoZXJtYWwgdG9sZXJhbmNlIGxpbWl0cywgYXQgbGVhc3QgcGhlbm9tZW5vbG9naWNhbGx5Lg0KDQpNYXNzLXNwZWNpZmljIGJpb2xvZ2ljYWwgcmF0ZXMgKCRyJCkgaW5jcmVhc2Ugd2l0aCB0ZW1wZXJhdHVyZSBmb2xsb3dpbmc6DQoNClxiZWdpbntlcXVhdGlvbn0NCiAgICByID0gUl8wIGVee1xmcmFjey1FfXtrVH19DQogICAgKFwjZXE6QkEpDQpcZW5ke2VxdWF0aW9ufQ0KDQpXaGVyZSAkUl8wJCBpcyBhIG5vcm1hbGlzYXRpb24gZmFjdG9yLCAkRSQgaXMgYWN0aXZhdGlvbiBlbmVyZ3ksICRrJCBpcyBCb2x0em1hbm4ncyBjb25zdGFudCAoJDguNjE3IHtcdGltZXN9IDEwXnstNX0kIGVWIEteLTFeKSBhbmQgJFQkIGlzIHRlbXBlcmF0dXJlIGluIEtlbHZpbi4gV2UgdXNlIGEgdmFsdWUgb2YgMC42IGVWIGZvciAkRSQgcmVwcmVzZW50aW5nIG1lYW4gYWN0aXZhdGlvbiBlbmVyZ3kgb2YgYmlvbG9naWNhbCByYXRlcyBhY3Jvc3MgdGF4YSBbQERlbGwyMDExXS4NCg0KQWx0aG91Z2ggJEUkIHZhcmllcyBncmVhdGx5IGFtb25nIHRheGEgYW5kIGJpb2xvZ2ljYWwgcmF0ZXMgb2YgaW50ZXJlc3QsIHZhcnlpbmcgdGhlIHZhbHVlIG9mICRFJCBkb2VzIG5vdCBtZWFuaW5nZnVsbHkgY2hhbmdlIG91ciByZXN1bHRzIChzZWUgW1NlbnNpdGl2aXR5IG9mIGFjdGl2YXRpb24gZW5lcmd5XSkuICRSXzAkIGlzIG5vdCB1c2VkIGluIHRoZSBjYWxjdWxhdGlvbiBvZiByZXNjYWxlZCBoZWF0aW5nIGR1cmF0aW9uIGFuZCBkb2VzIG5vdCBhZmZlY3Qgb3VyIHJlc3VsdHMuIA0KDQoqKioNCg0KIyMgVGltZSBpcyBpbXBsaWNpdCBpbiBoZWF0aW5nIHRvbGVyYW5jZXMgdGhyb3VnaCBoZWF0aW5nIHJhdGVzDQoNCkhlYXRpbmcgdG9sZXJhbmNlcyBoYXZlIGEgZGltZW5zaW9uIG9mIHRpbWUgKCR0JCkgaW1wbGljaXQgaW4gdGhlaXIgZGVmaW5pdGlvbi4gVW5kZXIgYSBjb25zdGFudCBoZWF0aW5nIHJhdGUsIGFuIG9yZ2FuaXNtIG11c3Qgd2l0aHN0YW5kIGhlYXRpbmcgb3ZlciB0aW1lIGJldHdlZW4gdGhlaXIgYWNjbGltYXRpb24gdGVtcGVyYXR1cmUgKCRUX2EkKSBhbmQgdXBwZXIgdGhlcm1hbCB0b2xlcmFuY2UgbGltaXRzICgkVF9jJCkuIA0KDQpJbiBvdGhlciB3b3JkcywgaGVhdGluZyB0b2xlcmFuY2VzIGFsc28gcmVwcmVzZW50IGEgZHVyYXRpb24gb2YgdGltZSAoaGVhdGluZyBkdXJhdGlvbiwgJFxEZWx0YSB0JCkgYmV0d2VlbiB0d28gdGltZSBwb2ludHMgKCR0X2EkLCB0aGUgc3RhcnQgb2YgdGhlIGhlYXRpbmcgYXNzYXksIGFuZCAkdF9jJCwgdGhlIGVuZCBvZiB0aGUgaGVhdGluZyBhc3NheSkgdGhhdCBoYXZlIGEgY29ycmVzcG9uZGluZyB0ZW1wZXJhdHVyZSAoJFRfYSQgYW5kICRUX2MkLCByZXNwZWN0aXZlbHkpLiANCg0KVGhlcmVmb3JlLCBhcyB3ZSBjYW4gZXhwZWN0IGJpb2xvZ2ljYWwgcHJvY2Vzc2VzIG9jY3VycmluZyBkdXJpbmcgaGVhdGluZyB0byBzY2FsZSB3aXRoIHRlbXBlcmF0dXJlIHdlIGNhbiBhbHNvIGV4cGVjdCB0aGUgZHVyYXRpb25zIG9mIHRoZXNlcyBiaW9sb2dpY2FsIHByb2Nlc3NlcyBhdCBvbmUgdGVtcGVyYXR1cmUsICRcRGVsdGEgdChUKSQsIHRvIHNjYWxlIHdpdGggdGVtcGVyYXR1cmUuIFdlIGNhbiBkZXNjcmliZSB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gaGVhdGluZyBkdXJhdGlvbnMgc3RhcnRpbmcgZnJvbSB0d28gdGVtcGVyYXR1cmVzICgkVF97YTF9JCBhbmQgJFRfe2EyfSQpIGFzOg0KDQpcYmVnaW57ZXF1YXRpb259DQpcZnJhY3tcRGVsdGEgdChUX3thMX0pfXtcRGVsdGEgdChUX3thMn0pfSBcYXBwcm94IGVee1xmcmFje0V9e2tUX3thMX19LVxmcmFje0V9e2tUX3thMn19fQ0KICAgIChcI2VxOmVxMSkNClxlbmR7ZXF1YXRpb259DQoNCioqKg0KDQojIyBSZXNjYWxpbmcgdGhlIGVmZmVjdCBvZiBhY2NsaW1hdGlvbiB0ZW1wZXJhdHVyZSBvbiBoZWF0aW5nIGR1cmF0aW9ucw0KDQpGb2xsb3dpbmcgRXF1YXRpb24gXEByZWYoZXE6ZXExKSwgd2UgY2FuIHVzZSBhIHJlZmVyZW5jZSB0ZW1wZXJhdHVyZSB0byBub3JtYWxpc2UgaGVhdGluZyBkdXJhdGlvbnMgZm9yIGNvbnZlbmllbmNlIGFuZCBkZXJpdmUgYW4gZXhwcmVzc2lvbiB0aGF0IGlzIGluZGVwZW5kZW50IG9mIHRlbXBlcmF0dXJlIGJ1dCByZXRhaW5zIGRpbWVuc2lvbnMgb2YgdGltZS4gV2UgdXNlIDAmZGVnO0MgYXMgdGhlIHJlZmVyZW5jZSB0ZW1wZXJhdHVyZSBhbmQgZGVmaW5lIGEgbm9ybWFsaXNhdGlvbiBjb25zdGFudCAoJFRfSyQpIHdpdGggYSB2YWx1ZSBvZiBgciBUa2AgKGkuZS4gMCZkZWc7QyBpbiBLZWx2aW4pIGZvciBjZW50cmluZyB0ZW1wZXJhdHVyZXMgKCRUJCkgaW4gJmRlZztDLg0KDQokJA0KXHRhdSA9IFxmcmFje1R9e1RfS30NCiQkDQoNCkhlcmUsICRUJCBhcmUgdGVtcGVyYXR1cmVzIGluIGRlZ3JlZXMgQ2Vsc2l1cyBhbmQgJFx0YXUkIGFyZSBub3JtYWxpc2VkIHRlbXBlcmF0dXJlcyB0aGF0IGFyZSBjZW50cmVkIGFyb3VuZCB0aGUgbm9ybWFsaXNhdGlvbiBjb25zdGFudCAkVF9LJC4gJFx0YXUkIGlzIHVuaXRsZXNzIGFuZCBjYW4gYmUgY29udmVydGVkIGJhY2sgaW50byBkZWdyZWVzIENlbHNpdXMgYnkgJFQgPSBcdGF1IFx0aW1lcyBUX0skLiANCg0KDQpTdWJzdGl0dXRpbmcgdGhlIG5vcm1hbGlzYXRpb24gY29uc3RhbnQgJFRfSyQgYXMgJFRfe2ExfSQgYW5kIHRlbXBlcmF0dXJlICRUJCAoaW4gJmRlZztDKSBhcyAkVF97YTJ9JCBpbiBFcXVhdGlvbiBcQHJlZihlcTplcTEpLCB3ZSBjYW4gZGVyaXZlIGFuIGluaXRpYWwgZXhwcmVzc2lvbiB0aGF0IHJlc2NhbGVzIGhlYXRpbmcgZHVyYXRpb25zIGJ5IGFjY291bnRpbmcgZm9yIGFjY2xpbWF0aW9uIHRlbXBlcmF0dXJlOiANCg0KJCRcRGVsdGEgdF9yID0gZV57XGZyYWN7RX17a1RfS319ZV57LVxmcmFje0V9e2tUfX0gXERlbHRhIHQoVCkkJA0KU3Vic2NyaXB0ICRyJCBkZW5vdGVzIHZhcmlhYmxlcyByZXNjYWxlZCBieSB0aGUgbm9uLWxpbmVhciB0ZW1wZXJhdHVyZSBkZXBlbmRlbmNlIG9mIHBoeXNpb2xvZ2ljYWwgcmF0ZXMgKFRhYmxlIFxAcmVmKHRhYjptYXRocykpLiAkXERlbHRhIHRfciQgYXJlIHJlc2NhbGVkIGhlYXRpbmcgZHVyYXRpb25zIHRoYXQgY29ycmVzcG9uZCB0byBub24tcmVzY2FsZWQgaGVhdGluZyBkdXJhdGlvbiAoJFxEZWx0YSB0JCkuDQoNClJlc2NhbGVkIGhlYXRpbmcgZHVyYXRpb24gY2FuIGJlIHdyaXR0ZW4gYXMgYW4gaW50ZWdyYWwgYmV0d2VlbiB0aGUgc3RhcnQgKCR0X2EkKSBhbmQgZW5kIHRpbWVzICgkdF9jJCkgb2YgdGhlIGhlYXRpbmcgYXNzYXksIGFzc3VtaW5nIGEgY29uc3RhbnQgdGVtcGVyYXR1cmUgcmFtcDoNCg0KXGJlZ2lue2VxdWF0aW9ufQ0KXERlbHRhIHRfciA9IGVee1xmcmFje0V9e2tUX0t9fSBcaW50X3t0X2F9Xnt0X2N9IGVeey1cZnJhY3tFfXtrVCh0KX19IGR0IChcI2VxOmVxMikNClxlbmR7ZXF1YXRpb259DQoNCldlIGNhbiBzaW1wbGlmeSBFcXVhdGlvbiBcQHJlZihlcTplcTIpIGJ5IHVzaW5nIHRoZSBub3JtYWxpc2VkIHRlbXBlcmF0dXJlIHNjYWxlICgkXHRhdSQpIGFuZCByZW1vdmluZyB0aGUgZGltZW5zaW9uIG9mIHRlbXBlcmF0dXJlLg0KDQpPbiBhIG5vcm1hbGlzZWQgdGVtcGVyYXR1cmUgc2NhbGUgKCRcdGF1JCksICRcZnJhY3tFfXtrVH0kIGluIEVxdWF0aW9uIFxAcmVmKGVxOmVxMikgYmVjb21lczoNCg0KXGJlZ2lue2FsaWdufQ0KXGZyYWN7RX17a1R9ICY9IHtcZnJhY3tFfXtrVF9LfX0ge1xmcmFjezF9ezEgKyBcZnJhY3tUfXtUX0t9fX0gXFwNCiYgPSB7XGZyYWN7RX17a1RfS319IHtcZnJhY3sxfXsxICsgXHRhdX19IFxcDQomIFxhcHByb3ggXGJldGEgKDEtXHRhdSkNClxlbmR7YWxpZ259DQoNCndoZXJlIA0KXGJlZ2lue2VxdWF0aW9ufQ0KXGJldGEgPSBcZnJhY3tFfXtrIFRfS30gKFwjZXE6ZXEzKQ0KXGVuZHtlcXVhdGlvbn0NCg0KJFxiZXRhJCBpcyBhIGNvbnN0YW50IHdpdGggYW4gYXBwcm94aW1hdGUgdmFsdWUgb2YgMjUuNSB1c2luZyAkRSA9JCAwLjYgKGBiZXRhX0tgKS4NCg0KVGh1cyBFcXVhdGlvbiBcQHJlZihlcTplcTIpIHNpbXBsaWZpZXMgdG8NCg0KXGJlZ2lue2VxdWF0aW9ufQ0KXERlbHRhIHRfciA9IFxpbnRfe3RfYX1ee3RfY30gZV57XGJldGEgXHRhdSAodCl9IGR0IChcI2VxOmVxNCkNClxlbmR7ZXF1YXRpb259DQoNCmRlc2NyaWJpbmcgcmVzY2FsZWQgaGVhdGluZyBkdXJhdGlvbiBhcyBhIGZ1bmN0aW9uIG9mIHRpbWUuIFJlc2NhbGVkIGhlYXRpbmcgZHVyYXRpb24gKCRcRGVsdGEgdF9yJCkgY2FuIGJlIGNvbnNpZGVyZWQgYXMgdGhlIGVmZmVjdGl2ZSBlbGFwc2VkIGR1cmF0aW9uIG9mIHRoZSBoZWF0aW5nIGFzc2F5IG9uY2UgdGhlIG5vbi1saW5lYXIgZWZmZWN0IG9mIGFjY2xpbWF0aW9uIHRlbXBlcmF0dXJlIGhhcyBiZWVuIGFjY291bnRlZCBmb3IuDQoNCkVxdWF0aW9uIFxAcmVmKGVxOmVxNCkgY2FuIGVxdWl2YWxlbnRseSBiZSBleHByZXNzZWQgYXMgYW4gaW50ZWdyYXRpb24gb3ZlciBub3JtYWxpc2VkIHRlbXBlcmF0dXJlIHNjYWxlcyAoJFx0YXUkKS4gIA0KDQpcYmVnaW57ZXF1YXRpb259DQpcRGVsdGEgdF9yID0gXGZyYWN7MX17XGxhbWJkYX0gXGludF97XHRhdV97YX19XntcdGF1X3tjfX0gZV57XGJldGEgXHRhdX0gZCBcdGF1IChcI2VxOmVxNSkNClxlbmR7ZXF1YXRpb259DQoNCkhlcmUsICRcdGF1X2EkIGlzIGFjY2xpbWF0aW9uIHRlbXBlcmF0dXJlIGFuZCAkXHRhdV9jJCBpcyB1cHBlciB0aGVybWFsIHRvbGVyYW5jZSBsaW1pdCBvbiBub3JtYWxpc2VkIHRlbXBlcmF0dXJlIHNjYWxlcyBhbmQgY29ycmVzcG9uZCB3aXRoICRUX2EkIGFuZCAkVF9jJCBvbiBkZWdyZWUgQ2Vsc2l1cyBzY2FsZXMsIHJlc3BlY3RpdmVseS4gJFxsYW1iZGEkIGlzIGhlYXRpbmcgcmF0ZSAoJmRlZztDKSBvbiBhIG5vcm1hbGlzZWQgdGVtcGVyYXR1cmUgc2NhbGUsIHdoZXJlICRcbGFtYmRhID0gSGVhdGluZyBcc3BhY2UgcmF0ZSAvIFRfSyQgd2l0aCB1bml0cyBvZiB0aW1lXi0xXi4NCg0KKioqDQoNCiMjIENhbGN1bGF0aW5nIHJlc2NhbGVkIGhlYXRpbmcgZHVyYXRpb24gZnJvbSBoZWF0aW5nIHRvbGVyYW5jZQ0KDQpJbnRlZ3JhdGlvbiBvZiBFcXVhdGlvbiBcQHJlZihlcTplcTUpIGdpdmVzIGFuIGV4cHJlc3Npb24gZm9yIHJlc2NhbGVkIGhlYXRpbmcgZHVyYXRpb24gJFxEZWx0YSB0X3IkIHRoYXQgZGVzY3JpYmVzIHRoZSBlZmZlY3Qgb2YgdGhlIG5vbi1saW5lYXIgY2hhbmdlIGluIHBoeXNpb2xvZ2ljYWwgcmF0ZXMgYXMgdGVtcGVyYXR1cmVzIGluY3JlYXNlZCBkdXJpbmcgdGhlIGhlYXRpbmcgYXNzYXksIG9uIG5vcm1hbGlzZWQgdGVtcGVyYXR1cmUgc2NhbGVzIChFcXVhdGlvbiBcQHJlZihlcTplcTdhKSkuDQoNCg0KXGJlZ2lue2VxdWF0aW9ufQ0KXERlbHRhIHRfciA9IGdfXGJldGEgKFxEZWx0YSBcdGF1KSBcZnJhY3tlXntcYmV0YSBcdGF1X2F9fXtcbGFtYmRhfSAoXCNlcTplcTdhKQ0KXGVuZHtlcXVhdGlvbn0NCg0KJFxEZWx0YSBcdGF1JCBpcyBoZWF0aW5nIHRvbGVyYW5jZSBvbiB0aGUgbm9ybWFsaXNlZCB0ZW1wZXJhdHVyZSBzY2FsZSwgd2hlcmUgJFxEZWx0YSBcdGF1ID0gXHRhdV9jIC0gXHRhdV9hJC4gJFxEZWx0YSBcdGF1JCBpcyBub3QgY29ycmVjdGVkIGZvciB0aGUgbm9uLWxpbmVhciB0ZW1wZXJhdHVyZSBkZXBlbmRlbmNlIG9mIHBoeXNpb2xvZ2ljYWwgcmF0ZXMuIFRoZSBmdW5jdGlvbiAkZ19cYmV0YSQgYWNjb3VudHMgZm9yIHRoZSBjaGFuZ2UgaW4gcmVzY2FsZWQgdGVtcGVyYXR1cmUgaW4gdGhlIGhlYXRpbmcgYXNzYXkgdmlhIGludGVncmF0aW9uOg0KDQpcYmVnaW57YWxpZ259DQpnX1xiZXRhICh4KSAmPSBcaW50X3tcdGF1X3thfX1ee1x0YXVfe2N9fSBlXntcYmV0YSB4fSBkeCBcXA0KJj0gXGZyYWN7ZV57XGJldGEgeH0gLSAxfXtcYmV0YX0NCihcI2VxOmVxNmEpDQpcZW5ke2FsaWdufQ0KDQpUaHVzLCBFcXVhdGlvbiBcQHJlZihlcTplcTdhKSBpcyB1c2VkIHRvIGNhbGN1bGF0ZSByZXNjYWxlZCBoZWF0aW5nIGR1cmF0aW9uICRcRGVsdGEgdF9yJCBmcm9tIGEga25vd24gaGVhdGluZyB0b2xlcmFuY2UgKGFzICRIJCBvciAkXERlbHRhIFx0YXUkKS4gTm9ybWFsaXNlZCBoZWF0aW5nIHRvbGVyYW5jZXMgJFxEZWx0YSBcdGF1JCBjYW4gcmVhZGlseSBiZSBjb252ZXJ0ZWQgaW50byBkZWdyZWVzIENlbHNpdXMgdG8gY2FsY3VsYXRlICRIJCBvciB2aWNlIHZlcnNhLiBSZXNjYWxlZCBoZWF0aW5nIGR1cmF0aW9ucyAkXERlbHRhIHRfciQgbWVhc3VyZWQgYXQgdHdvIGFjY2xpbWF0aW9uIHRlbXBlcmF0dXJlcyBhcmUgY29tcGFyYWJsZSB3aXRoaW4gYSBzcGVjaWVzLg0KDQoqKioNCg0KIyMgQ2FsY3VsYXRpbmcgaGVhdGluZyB0b2xlcmFuY2UgZnJvbSByZXNjYWxlZCBoZWF0aW5nIGR1cmF0aW9uDQoNCkNvbnZlcnNlbHksIG5vcm1hbGlzZWQgaGVhdGluZyB0b2xlcmFuY2UgJFxEZWx0YSBcdGF1JCBjYW4gYmUgY2FsY3VsYXRlZCBmcm9tIHJlc2NhbGVkIGhlYXRpbmcgZHVyYXRpb24gJFxEZWx0YSB0X3IkIHVzaW5nIHRoZSBpbnZlcnNlIG9mIEVxdWF0aW9uIFxAcmVmKGVxOmVxNmEpLg0KDQpcYmVnaW57ZXF1YXRpb259DQpcRGVsdGEgXHRhdSA9IGZfXGJldGEgKGVeey1cYmV0YSBcdGF1X3thfX0gXGxhbWJkYSBcRGVsdGEgdF9yKSAoXCNlcTplcTdiKQ0KXGVuZHtlcXVhdGlvbn0NCg0KV2hlcmUgJGZfXGJldGEkIGlzIHRoZSBpbnZlcnNlIG9mICRnX1xiZXRhJCAoRXF1YXRpb24gXEByZWYoZXE6ZXE2YSkpIHRoYXQgYWxzbyBhY2NvdW50cyBmb3IgdGhlIGNoYW5nZSBpbiByZXNjYWxlZCB0ZW1wZXJhdHVyZSBpbiB0aGUgaGVhdGluZyBhc3NheS4NCg0KXGJlZ2lue2FsaWdufQ0KZl9cYmV0YSh4KSAmPSBcZnJhY3tcbG9nICgxICsgXGJldGEgeCl9e1xiZXRhfSA9IDogZ157LTF9X1xiZXRhKHgpDQooXCNlcTplcTZiKQ0KXGVuZHthbGlnbn0NCg0KRXF1YXRpb25zIFxAcmVmKGVxOmVxNmEpIGFuZCBcQHJlZihlcTplcTZiKSBhcHByb2FjaCB0aGUgaWRlbnRpdHkgZm9yICRcYmV0YSB4IFxsbCAxJC4gDQoNClRodXMsIEVxdWF0aW9uIFxAcmVmKGVxOmVxN2IpIGNhbiBiZSB1c2VkIHRvIGNhbGN1bGF0ZSBub3JtYWxpc2VkIGhlYXRpbmcgdG9sZXJhbmNlcyAkXERlbHRhIFx0YXUkIGZyb20gYSBrbm93biByZXNjYWxlZCBoZWF0aW5nIGR1cmF0aW9uICRcRGVsdGEgdF9yJCwgYW5kIHRodXMgY2FuIGJlIHVzZWQgdG8gY2FsY3VsYXRlIGhlYXRpbmcgdG9sZXJhbmNlIGluIGRlZ3JlZXMgQ2Vsc2l1cywgJEgkLg0KDQpFcXVhdGlvbnMgXEByZWYoZXE6ZXE3YSkgYW5kIFxAcmVmKGVxOmVxN2IpIGludm9sdmVzIHR3byBzdGVwczogZmlyc3QgdGhlIGhlYXRpbmcgcmF0ZSBpcyByZXNjYWxlZCBieSB0aGUgdGVybSAkZV57XGJldGEgXHRhdV97YX19JCB0aGF0IGRlcGVuZHMgb24gdGhlIHN0YXJ0aW5nIHRlbXBlcmF0dXJlIG9mIHRoZSBhc3NheSAodG8gY29ycmVjdCBmb3IgYWNjbGltYXRpb24gdGVtcGVyYXR1cmUpLCBzZWNvbmQgRXF1YXRpb25zIFxAcmVmKGVxOmVxNmEpIGFuZCBcQHJlZihlcTplcTZiKSBhY2NvdW50IGZvciB0aGUgY2hhbmdlIGluIHRlbXBlcmF0dXJlIGFzIHRoZSBoZWF0aW5nIGFzc2F5IHByb2dyZXNzZXMgdmlhIGludGVncmF0aW9uIG9mIHRoZSBVbml2ZXJzYWwgVGVtcGVyYXR1cmUgRGVwZW5kZW5jZS4NCg0KUmVzY2FsaW5nIGhlYXRpbmcgZHVyYXRpb25zIGFuZCBoZWF0aW5nIHRvbGVyYW5jZSBpcyBkZXBlbmRlbnQgb24gdGhyZWUgYXNzdW1wdGlvbnM6IDEpIEhlYXRpbmcgdG9sZXJhbmNlIGlzIGFyYml0cmFyaWx5IGRlZmluZWQgd2l0aCByZXNwZWN0IHRvIDAmZGVnO0MsIDIpIGhlYXRpbmcgcmF0ZSBpcyBjb25zdGFudCwgYW5kIDMpIHRoZSBBcnJoZW5pdXMgcmVsYXRpb25zaGlwIGlzIG5vdCBhZmZlY3RlZCBieSB0aGUgcGh5c2lvbG9naWNhbCBzdGF0ZSBvZiB0aGUgb3JnYW5pc20gb3IgdGhlIGV4cGVyaW1lbnRhbCBjb25kaXRpb25zIChpLmUuLCAkRSQgZG9lcyBub3QgY2hhbmdlKS4NCg0KYGBge3IgcmVzY2FsaW5nfSANCiMgZnVuY3Rpb24gZm9yIGRlbHRhIHRfciB0aGF0IHVzZXMgZ19iZXRhX2Z1biAoRXF1YXRpb24gOCkNCmRlbHRhX3RyX2Z1biA8LSBmdW5jdGlvbih0YXVfYSwgdGF1X2MsIGxhbWJkYSl7DQogIGV4cChiZXRhX0sgKiB0YXVfYSkgLyBsYW1iZGEgKiBnX2JldGFfZnVuKHRhdV9jIC0gdGF1X2EpDQp9DQoNCiMgZnVuY3Rpb24gZyBvZiB4IGFuZCB0aGUgY29uc3RhbnQgYmV0YSAoRXF1YXRpb24gOSkNCmdfYmV0YV9mdW4gPC0gZnVuY3Rpb24oeCl7KGV4cChiZXRhX0sgKiB4KSAtIDEpIC8gYmV0YV9LfQ0KDQojIGZ1bmN0aW9uIGYgb2YgeCBhbmQgdGhlIGNvbnN0YW50IGJldGEgKEVxdWF0aW9uIDExKQ0KZl9iZXRhX2Z1biA8LSBmdW5jdGlvbih4KXtsb2coMSArIGJldGFfSyAqIHgpIC8gYmV0YV9LfQ0KYGBgDQoNCldlIGNhbGN1bGF0ZWQgaGVhdGluZyB0b2xlcmFuY2VzIGF0IHRoZSB0d28gYWNjbGltYXRpb24gdGVtcGVyYXR1cmVzIG9uIHRoZSBub3JtYWxpc2VkIHRlbXBlcmF0dXJlIHNjYWxlLiBXZSB0aGVuIGFwcGx5IEVxdWF0aW9uIFxAcmVmKGVxOmVxN2EpIHRvIGNhbGN1bGF0ZSByZXNjYWxlZCBoZWF0aW5nIGR1cmF0aW9uICRcRGVsdGEgdF9yJC4NCg0KYGBge3IgcmVzY2FsZX0NCiMgbm9ybWFsaXNlIFRhLCBUYyBhbmQgaGVhdGluZyByYXRlIGJ5IFRrLCBjYWxjdWxhdGUgbm9ybWFsaXNlZCBoZWF0aW5nIHRvbGVyYW5jZQ0KQVJSIDwtIEFSUiAlPiUgDQogIG11dGF0ZSh0YXVfYV9sb3cgPSB0YV9sb3cgLyBUaywNCiAgICAgICAgIHRhdV9hX2hpZ2ggPSB0YV9oaWdoIC8gVGssDQogICAgICAgICB0YXVfY19sb3cgPSB0Y19sb3cgLyBUaywNCiAgICAgICAgIHRhdV9jX2hpZ2ggPSB0Y19oaWdoIC8gVGssDQogICAgICAgICBsYW1iZGEgPSBoZWF0aW5nX3JhdGUgLyBUaywNCiAgICAgICAgIGRlbHRhX3RhdV9sb3cgPSB0YXVfY19sb3cgLSB0YXVfYV9sb3csDQogICAgICAgICBkZWx0YV90YXVfaGlnaCA9IHRhdV9jX2hpZ2ggLSB0YXVfYV9oaWdoKQ0KDQojIENhbGN1bGF0ZSByZXNjYWxlZCBoZWF0aW5nIGR1cmF0aW9uIGZvciBsb3dlciBhY2NsaW1hdGlvbiB0ZW1wZXJhdHVyZXMgKEVxdWF0aW9uIDgpDQpBUlIgPC0gQVJSICU+JSANCiAgbXV0YXRlKGRlbHRhX3RyX2xvdyA9IHBtYXBfZGJsKGxpc3QodGF1X2EgPSB0YXVfYV9sb3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGF1X2MgPSB0YXVfY19sb3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFtYmRhID0gbGFtYmRhKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVsdGFfdHJfZnVuKSkNCg0KIyBDYWxjdWxhdGUgcmVzY2FsZWQgaGVhdGluZyBkdXJhdGlvbiBmb3IgaGlnaGVyIGFjY2xpbWF0aW9uIHRlbXBlcmF0dXJlcyAoRXF1YXRpb24gOCkNCkFSUiA8LSBBUlIgJT4lIA0KICBtdXRhdGUoZGVsdGFfdHJfaGlnaCA9IHBtYXBfZGJsKGxpc3QodGF1X2EgPSB0YXVfYV9oaWdoLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0YXVfYyA9IHRhdV9jX2hpZ2gsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhbWJkYSA9IGxhbWJkYSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZWx0YV90cl9mdW4pKQ0KYGBgDQoNClJlc2NhbGVkIGhlYXRpbmcgZHVyYXRpb25zICRcRGVsdGEgdF9yJCBhcmUgaW5mbHVlbmNlZCBieSBoZWF0aW5nIHJhdGUgd2l0aCBsYXJnZXIgcmVzY2FsZWQgaGVhdGluZyBkdXJhdGlvbnMgYXNzb2NpYXRlZCB3aXRoIHNsb3dlciBoZWF0aW5nIHJhdGVzIChGaWd1cmUgXEByZWYoZmlnOmhlYXQtZHVyKSkuIFRoaXMgZGVwZW5kZW5jeSB3aXRoIGhlYXRpbmcgcmF0ZSBpcyBleHBsb3JlZCBbYmVsb3ddKCNoZWF0aW5nLXJhdGUpLg0KDQpgYGB7ciBoZWF0LWR1ciwgZWNobyA9IEZBTFNFLCBmaWcuY2FwID0gIlJlc2NhbGVkIGhlYXRpbmcgZHVyYXRpb24gYXQgdGhlIGxvd2VyIGFuZCBoaWdoZXIgYWNjbGltYXRpb24gdGVtcGVyYXR1cmUgb24gTG9nMTAgYXhlcyBoYXZlIGEgc3Ryb25nIGRlcGVuZGVuY3kgd2l0aCBoZWF0aW5nIHJhdGUgKGNvbG91cnMpLiJ9DQpyZXNjYWxlZF9kdXJhdGlvbiA8LSBnZ3Bsb3QoZGF0YSA9IEFSUiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSBkZWx0YV90cl9sb3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gZGVsdGFfdHJfaGlnaCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbCA9IGhlYXRpbmdfcmF0ZSkpICsNCiAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwLCBsdHkgPSAyLCBhbHBoYSA9IDAuNikgKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFLCBjb2wgPSAxKSArDQogIGdlb21fcG9pbnQoKSArDQogIHNjYWxlX3hfY29udGludW91cyh0cmFucyA9ICJsb2cxMCIsIGxhYmVscyA9IGZ1bmN0aW9uKHgpIHJvdW5kKHgpLCBleHBhbmQgPSBjKDAsMCksIGxpbWl0cyA9IGMoMC4xLCAxMDAwMCkpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKHRyYW5zID0gImxvZzEwIiwgbGFiZWxzID0gZnVuY3Rpb24oeCkgcm91bmQoeCksIGV4cGFuZCA9IGMoMCwwKSwgbGltaXRzID0gYygwLjEsIDEwMDAwKSkgKw0KICBjb29yZF9lcXVhbCgpICsNCiAgbGFicyh4ID0gZXhwcmVzc2lvbigiTG93ZXIgYWNjbGltYXRpb24gdGVtcGVyYXR1cmUgIiAqIERlbHRhICogdFtyXSksDQogICAgICAgeSA9IGV4cHJlc3Npb24oIkhpZ2hlciBhY2NsaW1hdGlvbiB0ZW1wZXJhdHVyZSAiICogRGVsdGEgKiB0W3JdKSkgKw0KICBnZ3RpdGxlKGV4cHJlc3Npb24ocGFzdGUoIlJlc2NhbGVkIGhlYXRpbmcgZHVyYXRpb24sICIpICogRGVsdGEgKiB0W3JdKSkgKw0KICBzY2FsZV9jb2xvdXJfdmlyaWRpc19jKG5hbWUgPSBleHByZXNzaW9uKCJIZWF0aW5nIHJhdGUgKFx1MDBCMEMgaCIgXi0xICogIikiKSwgdHJhbnMgPSAibG9nMTAiLCBsYWJlbHMgPSBmdW5jdGlvbih4KSBzaWduaWYoeCkpDQoNCnJlc2NhbGVkX2R1cmF0aW9uDQpgYGANCg0KKioqDQoNCiMjIERpbWVuc2lvbmxlc3MgcmVzY2FsZWQgaGVhdGluZyBkdXJhdGlvbg0KDQpBIHNpbXBsZSB3YXkgb2YgdmlzdWFsaXNpbmcgcmVzY2FsZWQgaGVhdGluZyBkdXJhdGlvbiB3aXRob3V0IGl0cyBkZXBlbmRlbmN5IG9uIGhlYXRpbmcgcmF0ZSBpcyB0byBtdWx0aXBseSByZXNjYWxlZCBoZWF0aW5nIGR1cmF0aW9uIGJ5IGhlYXRpbmcgcmF0ZSB0byBnaXZlIGEgZGltZW5zaW9ubGVzcyBxdWFudGl0eSAoJEhfciQpLiBUaGlzIGRpbWVuc2lvbmxlc3MgcXVhbnRpdHkgZGVtb25zdHJhdGVzIHRoZSBzdHJvbmcgcmVsYXRpb25zaGlwIGJldHdlZW4gcmVzY2FsZWQgaGVhdGluZyBkdXJhdGlvbnMgYXQgZWl0aGVyIGFjY2xpbWF0aW9uIHRlbXBlcmF0dXJlLCByZWdhcmRsZXNzIG9mIGhlYXRpbmcgcmF0ZSAoRmlndXJlIFxAcmVmKGZpZzpoZWF0LXRvbCkpLiBIb3dldmVyLCB0aGlzIGRpbWVuc2lvbmxlc3MgYW5hbHlzaXMgaGFzIGxpbWl0ZWQgdXRpbGl0eSBpbiB1bmRlcnN0YW5kaW5nIHRlbXBlcmF0dXJlLXJhdGUtdGltZSBkeW5hbWljcyBjb21wYXJlZCB3aXRoICRcRGVsdGEgdF9yJC4gJFxEZWx0YSB0X3IkIGluY2x1ZGVzIHRoZSBpbnRlZ3JhdGlvbiBvZiB0aGUgbm9uLWxpbmVhciB0ZW1wZXJhdHVyZSBkZXBlbmRlbmN5IG9mIGJpb2xvZ2ljYWwgcmF0ZXMgYW5kIGlzIG91ciBtYWluIGFpbSBvZiBvdXIgYW5hbHlzaXMuDQoNCmBgYHtyIGhlYXQtdG9sLCBlY2hvID0gRkFMU0UsIGZpZy5jYXAgPSAiRGltZW5zaW9ubGVzcyByZXNjYWxlZCBoZWF0aW5nIGR1cmF0aW9ucyBhdCB0aGUgbG93ZXIgYW5kIGhpZ2hlciBhY2NsaW1hdGlvbiB0ZW1wZXJhdHVyZXMgb24gTG9nMTAgYXhlcy4ifQ0KcmVzY2FsZWRfdG9sZXJhbmNlcyA8LSBnZ3Bsb3QoZGF0YSA9IEFSUiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSBleHAoYmV0YV9LICogdGF1X2FfbG93KSAqIGdfYmV0YV9mdW4odGF1X2NfbG93IC0gdGF1X2FfbG93KSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBleHAoYmV0YV9LICogdGF1X2FfaGlnaCkgKiBnX2JldGFfZnVuKHRhdV9jX2hpZ2ggLSB0YXVfYV9oaWdoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sID0gaGVhdGluZ19yYXRlKSkgKyANCiAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwLCBsdHkgPSAyLCBhbHBoYSA9IDAuNikgKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFLCBjb2wgPSAxKSArIA0KICBnZW9tX3BvaW50KCkgKyANCiAgc2NhbGVfeF9jb250aW51b3VzKHRyYW5zID0gImxvZzEwIiwgZXhwYW5kID0gYygwLDApKSArDQogIHNjYWxlX3lfY29udGludW91cyh0cmFucyA9ICJsb2cxMCIsIGV4cGFuZCA9IGMoMCwwKSkgKw0KICBjb29yZF9lcXVhbCgpICsgIA0KICBzY2FsZV9jb2xvdXJfdmlyaWRpc19jKG5hbWUgPSBleHByZXNzaW9uKCJIZWF0aW5nIHJhdGUgKFx1MDBCMEMgaCIgXi0xICogIikiKSwgdHJhbnMgPSAibG9nMTAiLCBsYWJlbHMgPSBmdW5jdGlvbih4KSBzaWduaWYoeCkpICsNCiAgbGFicyh4ID0gZXhwcmVzc2lvbigiTG93ZXIgYWNjbGltYXRpb24gdGVtcGVyYXR1cmUgIiAqIEhbcl0pLA0KICAgICAgIHkgPSBleHByZXNzaW9uKCJIaWdoZXIgYWNjbGltYXRpb24gdGVtcGVyYXR1cmUgIiAqIEhbcl0pKSArDQogIGdndGl0bGUoZXhwcmVzc2lvbihwYXN0ZSgiRGltZW5zaW9ubGVzcyByZXNjYWxlZCBoZWF0aW5nIGR1cmF0aW9uLCAiICogSFtyXSkpKSANCg0KcmVzY2FsZWRfdG9sZXJhbmNlcw0KYGBgDQoNCioqKg0KDQojIFNlbnNpdGl2aXR5IG9mIGFjdGl2YXRpb24gZW5lcmd5DQoNCkludHJhc3BlY2lmaWMgYWN0aXZhdGlvbiBlbmVyZ3kgb2YgdmFyaW91cyB0aGVybWFsbHktZGVwZW5kZW50IHRyYWl0cyByYW5nZXMgYmV0d2VlbiAwLjIgYW5kIDEuMiB3aXRoIGEgbWVkaWFuIG9mIDAuNTUgZVYgW0BEZWxsMjAxMV0uIENoYW5naW5nIGFjdGl2YXRpb24gZW5lcmd5IGFuZCB0aHVzICRcYmV0YSQgZG9lcyBub3QgbWVhbmluZ2Z1bGx5IGNoYW5nZSB0aGUgcmVwb3J0ZWQgcGF0dGVybnMgKEZpZ3VyZSBcQHJlZihmaWc6c2Vuc2l0aXZpdHkpKS4NCg0KYGRlbHRhX3RyX2dlbmAgaXMgYSBnZW5lcmFsaXNlZCBmdW5jdGlvbiB0byByZXNjYWxlIGhlYXRpbmcgdG9sZXJhbmNlIHdpdGggJEUkIGFzIGEgdmFyaWFibGUuICRcYmV0YSQgdmFsdWVzIGFyZSBjYWxjdWxhdGVkIGZvciBlYWNoIHZhbHVlIG9mICRFJC4NCg0KYGBge3IgYmlvdGltZV9nZW59DQojIEdlbmVyYWxpc2VkIGZ1bmN0aW9uDQpkZWx0YV90cl9nZW4gPC0gZnVuY3Rpb24oeCwgZXYsIGsgPSA4LjYxNzMzKjEwXi01LCBUayA9IDI3My4xNSkgeyAjIGV2IGlzIGFjdGl2YXRpb24gZW5lcmd5DQogIA0KICAjIGNhbGN1bGF0ZSBiZXRhIEsgY29uc3RhbnQNCiAgYmV0YV9LX3NlbnNpIDwtIGV2IC8gKGsgKiBUaykNCiAgDQogICMgZnVuY3Rpb24gZm9yIGRlbHRhIHRyIHRoYXQgdXNlcyBnX2JldGFfZnVuIChFcXVhdGlvbiA4KQ0KICBkZWx0YV90cl9nZW4gPC0gZnVuY3Rpb24odGF1X2EsIHRhdV9jLCBsYW1iZGEpew0KICAgIGV4cChiZXRhX0tfc2Vuc2kgKiB0YXVfYSkgLyBsYW1iZGEgKiBnX2JldGFfZnVuX2dlbih0YXVfYyAtIHRhdV9hKQ0KICB9DQoNCiAgIyBmdW5jdGlvbiBmIG9mIHggYW5kIHRoZSBjb25zdGFudCBiZXRhDQogIGZfYmV0YV9mdW5fZ2VuIDwtIGZ1bmN0aW9uKHgpe2xvZygxICsgYmV0YV9LX3NlbnNpICogeCkgLyBiZXRhX0tfc2Vuc2l9DQogIA0KICAjIGZ1bmN0aW9uIGcgb2YgeCBhbmQgdGhlIGNvbnN0YW50IGJldGENCiAgZ19iZXRhX2Z1bl9nZW4gPC0gZnVuY3Rpb24oeCl7KGV4cChiZXRhX0tfc2Vuc2kgKiB4KSAtIDEpIC8gYmV0YV9LX3NlbnNpfQ0KICANCiAgIyBub3JtYWxpc2UgVGEsIFRjIGFuZCBoZWF0aW5nIHJhdGUgYnkgVGsNCiAgeCA8LSB4ICU+JSAjIENhbGN1bGF0ZSBoZWF0aW5nIHJhdGUgYXMgbGFtYmRhDQogICAgbXV0YXRlKHRhdV9hX2xvdyA9IHRhX2xvdyAvIFRrLA0KICAgICAgICAgICB0YXVfYV9oaWdoID0gdGFfaGlnaCAvIFRrLA0KICAgICAgICAgICB0YXVfY19sb3cgPSB0Y19sb3cgLyBUaywNCiAgICAgICAgICAgdGF1X2NfaGlnaCA9IHRjX2hpZ2ggLyBUaywNCiAgICAgICAgICAgbGFtYmRhID0gaGVhdGluZ19yYXRlIC8gVGssDQogICAgICAgICAgIGRlbHRhX3RhdV9sb3cgPSB0YXVfY19sb3cgLSB0YXVfYV9sb3csICMgY2FsY3VsYXRlIGRlbHRhIHRhdXMNCiAgICAgICAgICAgZGVsdGFfdGF1X2hpZ2ggPSB0YXVfY19oaWdoIC0gdGF1X2FfaGlnaCkNCg0KICAjIG1hcCBvdmVyIGxvdyB0ZW1wZXJhdHVyZSBleHBlcmltZW50cw0KICB4IDwtIHggJT4lIA0KICAgIG11dGF0ZShkZWx0YV90cl9sb3cgPSBwbWFwX2RibChsaXN0KHRhdV9hID0gdGF1X2FfbG93LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGF1X2MgPSB0YXVfY19sb3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYW1iZGEgPSBsYW1iZGEpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlbHRhX3RyX2dlbikpDQogIA0KICAjIGRvIHRoZSBzYW1lIHdpdGggdGhlIGhpZ2ggdGVtcCBhY2NsaW1hdGVkIGRhdGENCiAgeCA8LSB4ICU+JSANCiAgICBtdXRhdGUoZGVsdGFfdHJfaGlnaCA9IHBtYXBfZGJsKGxpc3QodGF1X2EgPSB0YXVfYV9oaWdoLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRhdV9jID0gdGF1X2NfaGlnaCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYW1iZGEgPSBsYW1iZGEpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZWx0YV90cl9nZW4pKQ0KICANCiAgIyBBZGQgcHJlZGljdGlvbnMgb2YgaGlnaCBmcm9tIGxvdyBhbmQgY29udmVyc2VseSBsb3cgZnJvbSBoaWdoDQogIHggPC0geCAlPiUgDQogICAgbXV0YXRlKGFjdGl2YXRpb24gPSBldiwNCiAgICAgICAgICAgZGVsdGFfdGF1X2hpZ2hfaGF0ID0gZl9iZXRhX2Z1bl9nZW4oZXhwKGJldGFfS19zZW5zaSAqICh0YXVfYV9sb3cgLSB0YXVfYV9oaWdoKSkgKiBnX2JldGFfZnVuX2dlbihkZWx0YV90YXVfbG93KSksICMgcHJlZGljdCBoaWdoIGZyb20gbG93DQogICAgICAgICAgIGRlbHRhX3RhdV9sb3dfaGF0ID0gZl9iZXRhX2Z1bl9nZW4oZXhwKGJldGFfS19zZW5zaSAqICh0YXVfYV9oaWdoIC0gdGF1X2FfbG93KSkgKiBnX2JldGFfZnVuX2dlbihkZWx0YV90YXVfaGlnaCkpKSAjIHByZWRpY3QgbG93IGZyb20gaGlnaA0KDQogIHJldHVybih4KSAjIGFzIGxpc3QNCn0NCmBgYA0KDQpUaGUgZGF0YXNldCBpcyByZXBsaWNhdGVkIGZvciBhIHZlY3RvciBvZiBhY3RpdmF0aW9uIGVuZXJnaWVzLCB0aGVuIHRoZSBgZGVsdGFfdHJfZ2VuYCBmdW5jdGlvbiBpcyBhcHBsaWVkIHRvIGVhY2ggZWxlbWVudCBvZiB0aGUgbGlzdCB1c2luZyBgbWFwcGx5YC4NCg0KYGBge3Igc2Vuc2l0aXZpdHksIGZpZy5jYXA9ICJWYXJpYXRpb24gaW4gYWN0aXZhdGlvbiBlbmVyZ3kgKGVWKS4gT2JzZXJ2YXRpb25zIChwb2ludHMpIHdpdGggYSBmaXR0ZWQgbGluZWFyIG1vZGVsIChzb2xpZCBsaW5lKSBmYWxsIGFsb25nIHRoZSBpZGVudGl0eSBsaW5lIChkYXNoZWQgbGluZSkuIiwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTd9DQojIGRlZmluZSBhY3RpdmF0aW9uIGVuZXJnaWVzDQphY3RpdmF0aW9uIDwtIHNlcSgwLjIsIDEuMiwgMC4yKQ0KIyByZXBlYXQgQVJSIGRhdGFzZXQgb3ZlciBsZW5ndGggb2YgYWN0aXZhdGlvbiBlbmVyZ2llcw0KQVJSX2xpc3QgPC0gcmVwbGljYXRlKGxlbmd0aChhY3RpdmF0aW9uKSwgQVJSLCBzaW1wbGlmeSA9IEZBTFNFKQ0KIyBpbnRlZ3JhdGUgdW5kZXIgY3VydmUsIG1lcmdlIHRvIHNpbmdsZSBkYXRhIGZyYW1lDQpBUlJfbGlzdCA8LSBkby5jYWxsKHJiaW5kLCBtYXBwbHkoQVJSX2xpc3QsIEZVTiA9IGRlbHRhX3RyX2dlbiwgZXYgPSBhY3RpdmF0aW9uLCBTSU1QTElGWSA9IEZBTFNFKSkNCg0KIyBwbG90DQpzZW5zaV9wbG90IDwtIGdncGxvdChkYXRhID0gQVJSX2xpc3QsIA0KICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSBkZWx0YV90cl9sb3csIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBkZWx0YV90cl9oaWdoKSkgKyANCiAgZ2VvbV9wb2ludChjb2wgPSAiZ3JleSIpICsgDQogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UsIGNvbCA9ICJibGFjayIpICsgDQogIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gMCwgbHR5ID0gMiwgYWxwaGEgPSAwLjYpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKGV4cGFuZCA9IGMoMC4wMSwwKSwgdHJhbnMgPSAibG9nMTAiLCBsYWJlbHMgPSBmdW5jdGlvbih4KSBmb3JtYXQoeCwgc2NpZW50aWZpYyA9IEZBTFNFKSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLjAxLDApLCB0cmFucyA9ICJsb2cxMCIsIGxhYmVscyA9IGZ1bmN0aW9uKHgpIGZvcm1hdCh4LCBzY2llbnRpZmljID0gRkFMU0UpKSArDQogICMgc2NhbGVfY29sb3VyX3ZpcmlkaXNfYyhuYW1lID0gIkFjdGl2YXRpb24gZW5lcmd5IikgKw0KICBmYWNldF93cmFwKC5+YWN0aXZhdGlvbiwgbmNvbD0zLCBzY2FsZXMgPSAiZnJlZSIpICsNCiAgbGFicyh4ID0gZXhwcmVzc2lvbigiTG93ZXIgdGVtcGVyYXR1cmUgcmVzY2FsZWQgaGVhdGluZyBkdXJhdGlvbiIpLCB5ID0gZXhwcmVzc2lvbigiSGlnaGVyIHRlbXBlcmF0dXJlIHJlc2NhbGVkIGhlYXRpbmcgZHVyYXRpb24iKSkgKw0KICB0aGVtZV9jbGFzc2ljKGJhc2Vfc2l6ZSA9IDEyKQ0KDQpzZW5zaV9wbG90DQpgYGANCg0KKioqDQoNCiMgUHJlZGljdGluZyBoZWF0aW5nIHRvbGVyYW5jZSBmb3IgYSBuZXcgYWNjbGltYXRpb24gdGVtcGVyYXR1cmUNCg0KV2UgY2FuIHVzZSByZXNjYWxlZCBoZWF0aW5nIGR1cmF0aW9ucyB0byBwcmVkaWN0IGhlYXRpbmcgdG9sZXJhbmNlcyBtZWFzdXJlZCBhdCBhIGRpZmZlcmVudCBhY2NsaW1hdGlvbiB0ZW1wZXJhdHVyZSAoJGEyJCkgZnJvbSBhIGtub3duIGFjY2xpbWF0aW9uIHRlbXBlcmF0dXJlICgkYTEkKSBhbmQgaGVhdGluZyB0b2xlcmFuY2UuIA0KDQpgYGB7ciBwcmVkLWZ1bn0NCiMgQWRkIHByZWRpY3Rpb25zIG9mIGhpZ2ggZnJvbSBsb3cgYW5kIGNvbnZlcnNlbHkgbG93IGZyb20gaGlnaA0KQVJSIDwtIEFSUiAlPiUgDQogIG11dGF0ZShkZWx0YV90YXVfaGlnaF9oYXQgPSBmX2JldGFfZnVuKGV4cChiZXRhX0sgKiAodGF1X2FfbG93IC0gdGF1X2FfaGlnaCkpICogZ19iZXRhX2Z1bihkZWx0YV90YXVfbG93KSksICMgcHJlZGljdCBoaWdoIGZyb20gbG93IChFcXVhdGlvbiAxMikNCiAgICAgICAgIGRlbHRhX3RhdV9sb3dfaGF0ID0gZl9iZXRhX2Z1bihleHAoYmV0YV9LICogKHRhdV9hX2hpZ2ggLSB0YXVfYV9sb3cpKSAqIGdfYmV0YV9mdW4oZGVsdGFfdGF1X2hpZ2gpKSkgIyBwcmVkaWN0IGxvdyBmcm9tIGhpZ2ggKEVxdWF0aW9uIDEzKQ0KYGBgDQoNCiMjIEFzc3VtaW5nIGhlYXRpbmcgdG9sZXJhbmNlcyBhcmUgdGhlIHNhbWUNCg0KVGhlIHNpbXBsZXN0IG1vZGVsIHRvIHByZWRpY3QgYSBuZXcgaGVhdGluZyB0b2xlcmFuY2UgZnJvbSBhIG5ldyBhY2NsaW1hdGlvbiB0ZW1wZXJhdHVyZSBpcyB0byBhc3N1bWUgdGhhdCBoZWF0aW5nIHRvbGVyYW5jZXMgYXQgdGhlIGhpZ2hlciBhbmQgbG93ZXIgYWNjbGltYXRpb24gdGVtcGVyYXR1cmUgZXhwZXJpbWVudHMgYXJlIHRoZSBzYW1lLiBGb3IgZXhhbXBsZSwgd2UgY2FuIHByZWRpY3QgdGhlIGhlYXRpbmcgdG9sZXJhbmNlIGF0IHRoZSBoaWdoZXIgYWNjbGltYXRpb24gdGVtcGVyYXR1cmUgJFxEZWx0YSBcdGF1IChcdGF1X3thMn0pJCwgZnJvbSB0aGUgbG93ZXIgYWNjbGltYXRpb24gdGVtcGVyYXR1cmUsICRcRGVsdGEgXHRhdSAoXHRhdV97YTF9KSQuDQoNClxiZWdpbntlcXVhdGlvbn0NClxEZWx0YSBcdGF1IChcdGF1X3thMn0pIFxhcHByb3ggXERlbHRhIFx0YXUgKFx0YXVfe2ExfSkgKFwjZXE6ZXE4KQ0KXGVuZHtlcXVhdGlvbn0NCg0KYGBge3IgcHJlZDEsIGZpZy5jYXAgPSAiUHJlZGljdGluZyBoaWdoZXIgYWNjbGltYXRpb24gdGVtcGVyYXR1cmUgaGVhdGluZyB0b2xlcmFuY2UgZnJvbSBsb3dlciBhY2NsaW1hdGlvbiB0ZW1wZXJhdHVyZSBoZWF0aW5nIHRvbGVyYW5jZSBhc3N1bWluZyBoZWF0aW5nIHRvbGVyYW5jZSBpcyB0aGUgc2FtZS4ifQ0KcHJlZDEgPC0gZ2dwbG90KGRhdGEgPSBBUlIsDQogICAgICAgbWFwcGluZyA9IGFlcyh4ID0gZGVsdGFfdGF1X2xvdyAqIFRrLA0KICAgICAgICAgICAgICAgICAgICAgeSA9IGRlbHRhX3RhdV9oaWdoICogVGspKSArIA0KICBnZW9tX3BvaW50KCkgKyANCiAgZ2VvbV9hYmxpbmUoaW50ZXJjZXB0ID0gMCwgc2xvcGUgPSAxLCBsdHkgPSAyLCBhbHBoYSA9IDAuNikgKyANCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSwgY29sID0gImRhcmtncmV5IikgKyANCiAgbGFicyh4ID0gZXhwcmVzc2lvbigiUHJlZGljdGVkIGhlYXRpbmcgdG9sZXJhbmNlIChcdTAwQjBDKSIpLA0KICAgICAgIHkgPSBleHByZXNzaW9uKCJPYnNlcnZlZCBoZWF0aW5nIHRvbGVyYW5jZSAoXHUwMEIwQykiKSkgKyANCiAgc2NhbGVfeF9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwwKSwgbGltaXRzID0gYygwLCA0MCkpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwwKSwgbGltaXRzID0gYygwLCA0MCkpDQoNCnByZWQxDQpgYGANCg0KQXNzdW1pbmcgaGVhdGluZyB0b2xlcmFuY2UgaXMgdGhlIHNhbWUgYXQgYm90aCBhY2NsaW1hdGlvbiB0ZW1wZXJhdHVyZXMgb3ZlcmVzdGltYXRlcyB0aGUgaGVhdGluZyB0b2xlcmFuY2UgYXQgdGhlIGhpZ2hlciB0ZW1wZXJhdHVyZSAoRmlndXJlIFxAcmVmKGZpZzpwcmVkMSkpLg0KDQojIyBDb3JyZWN0IGZvciBhY2NsaW1hdGlvbiB0ZW1wZXJhdHVyZSBkaWZmZXJlbmNlDQoNCk5leHQsIHdlIGNhbiBjb3JyZWN0IGZvciB0aGUgZGlmZmVyZW5jZSBpbiBhY2NsaW1hdGlvbiB0ZW1wZXJhdHVyZXMgYnkgcmVzY2FsaW5nIGJ5IHRoZSBhY2NsaW1hdGlvbiB0ZW1wZXJhdHVyZSB2aWEgJGVee1xiZXRhIChcdGF1X3thMX0gLSBcdGF1X3thMn0pfSQ6DQoNClxiZWdpbntlcXVhdGlvbn0NClxEZWx0YSBcdGF1IChcdGF1X3thMn0pIFxhcHByb3ggXERlbHRhIFx0YXUgKFx0YXVfe2ExfSkgZV57XGJldGEgKFx0YXVfe2ExfSAtIFx0YXVfe2EyfSl9DQooXCNlcTplcTkpDQpcZW5ke2VxdWF0aW9ufQ0KDQpgYGB7ciBwcmVkMiwgZmlnLmNhcCA9ICJQcmVkaWN0aW5nIGhpZ2hlciBhY2NsaW1hdGlvbiB0ZW1wZXJhdHVyZSBoZWF0aW5nIHRvbGVyYW5jZSBjb3JyZWN0aW5nIGZvciBhY2NsaW1hdGlvbiB0ZW1wZXJhdHVyZSJ9DQpwcmVkMiA8LSBwcmVkMSArIGFlcyh4ID0gKGRlbHRhX3RhdV9sb3cgKiBleHAoYmV0YV9LICogKHRhdV9hX2xvdyAtIHRhdV9hX2hpZ2gpKSkgKiBUaykgKw0KICBsYWJzKHggPSBleHByZXNzaW9uKCJQcmVkaWN0ZWQgaGVhdGluZyB0b2xlcmFuY2UgKFx1MDBCMEMpIikpIA0KcHJlZDINCmBgYA0KDQpVc2luZyBFcXVhdGlvbiBcQHJlZihlcTplcTkpIHVuZGVyZXN0aW1hdGVzIHRoZSBoZWF0aW5nIHRvbGVyYW5jZSBhdCB0aGUgaGlnaGVyIGFjY2xpbWF0aW9uIHRlbXBlcmF0dXJlIChGaWd1cmUgXEByZWYoZmlnOnByZWQyKSkuIA0KDQojIyBBY2NvdW50IGZvciBkaWZmZXJlbmNlIGluIGFjY2xpbWF0aW9uIHRlbXBlcmF0dXJlIGFuZCBjaGFuZ2UgaW4gdGVtcGVyYXR1cmUNCg0KRmluYWxseSwgd2UgY2FuIGRlcml2ZSBhIG1vcmUgcHJlY2lzZSBwcmVkaWN0aW9uIHRoYXQgZnVsbHkgYWNjb3VudHMgZm9yIHRoZSBjaGFuZ2UgdG8gaGVhdGluZyB0b2xlcmFuY2UgdGhhdCBvY2N1cnMgZHVyaW5nIHRoZSBleHBlcmltZW50IGFzIHRoZSB0ZW1wZXJhdHVyZSBpcyBpbmNyZWFzZWQgdXNpbmcgRXF1YXRpb24gXEByZWYoZXE6ZXExMCkuDQoNClxiZWdpbntlcXVhdGlvbn0NClxEZWx0YSBcdGF1IChcdGF1X3thMn0pIFxhcHByb3ggZl9cYmV0YSBcYmlnKGVee1xiZXRhIChcdGF1X3thMX0gLSBcdGF1X3thMn0pfSBnX1xiZXRhKFxEZWx0YSBcdGF1KFx0YXVfe2ExfSkpIFxiaWcpDQooXCNlcTplcTEwKQ0KXGVuZHtlcXVhdGlvbn0NCg0KYGBge3IgcHJlZDMsIGZpZy5jYXAgPSAiQ29ycmVjdGlvbiBmb3IgYWNjbGltYXRpb24gdGVtcGVyYXR1cmUgYW5kIGNoYW5nZSBpbiB0ZW1wZXJhdHVyZSBvdmVyIHRpbWUgdG8gcHJlZGljdCBoZWF0aW5nIHRvbGVyYW5jZSBhdCB0aGUgaGlnaGVyIGFjY2xpbWF0aW9uIHRlbXBlcmF0dXJlIGZyb20gdGhlIGxvd2VyIGFjY2xpbWF0aW9uIHRlbXBlcmF0dXJlLiJ9DQpwcmVkMyA8LSBwcmVkMSArIGFlcyh4ID0gZGVsdGFfdGF1X2hpZ2hfaGF0ICogVGspICsgDQogIGxhYnMoeCA9IGV4cHJlc3Npb24oIlByZWRpY3RlZCBoZWF0aW5nIHRvbGVyYW5jZSAoXHUwMEIwQykiKSkNCnByZWQzDQpgYGANCg0KYGBge3IgcHJlZDMtbG0sIGluY2x1ZGU9RkFMU0V9DQojIGhpZ2ggZnJvbSBsb3cNCnByZWRfaGlnaF9sb3cgPC0gbG0oZGVsdGFfdGF1X2hpZ2ggfiBkZWx0YV90YXVfaGlnaF9oYXQsIA0KICAgICAgICAgICAgICAgICAgIG9mZnNldCA9IGRlbHRhX3RhdV9oaWdoX2hhdCwgDQogICAgICAgICAgICAgICAgICAgZGF0YSA9IEFSUikNCmBgYA0KDQpUaGUgJFJeMiQgaXMgYHIgcm91bmQoc3VtbWFyeShwcmVkX2hpZ2hfbG93KSRyLnNxdWFyZWQsIDQpKjEwMGAlLiBBbmQgYXMgd2UgY2FuIHByZWRpY3QgaGVhdGluZyB0b2xlcmFuY2UgYXQgdGhlIGhpZ2hlciBhY2NsaW1hdGlvbiB0ZW1wZXJhdHVyZSBmcm9tIHRoZSBsb3dlciBhY2NsaW1hdGlvbiB0ZW1wZXJhdHVyZSBpbiBGaWd1cmUgXEByZWYoZmlnOnByZWQzKSwgc28gd2UgY2FuIGFsc28gcHJlZGljdCBoZWF0aW5nIHRvbGVyYW5jZSBhdCB0aGUgbG93ZXIgYWNjbGltYXRpb24gdGVtcGVyYXR1cmUgZnJvbSBoZWF0aW5nIHRvbGVyYW5jZSBhdCB0aGUgaGlnaGVyIHRlbXBlcmF0dXJlIHVzaW5nIEVxdWF0aW9uIFxAcmVmKGVxOmVxMTBiKSAoRmlndXJlIFxAcmVmKGZpZzpwcmVkNCkpLg0KDQpcYmVnaW57ZXF1YXRpb259DQpcRGVsdGEgXHRhdSAoXHRhdV97YTF9KSBcYXBwcm94IGZfXGJldGEgXGJpZyhlXntcYmV0YSAoXHRhdV97YTJ9IC0gXHRhdV97YTF9KX0gZ19cYmV0YShcRGVsdGEgXHRhdShcdGF1X3thMn0pKSBcYmlnKQ0KKFwjZXE6ZXExMGIpDQpcZW5ke2VxdWF0aW9ufQ0KDQpgYGB7ciBwcmVkNCwgZmlnLmNhcCA9ICJQcmVkaWN0aW5nIGxvd2VyIHRlbXBlcmF0dXJlIGhlYXRpbmcgdG9sZXJhbmNlIGZyb20gaGlnaGVyIHRlbXBlcmF0dXJlIGhlYXRpbmcgdG9sZXJhbmNlIn0NCnByZWQ0IDwtIHByZWQxICsgYWVzKHggPSBkZWx0YV90YXVfbG93X2hhdCAqIFRrLA0KICAgICAgICAgICAgICAgICAgICAgeSA9IGRlbHRhX3RhdV9sb3cgKiBUaykgKyANCiAgIyBnZ3RpdGxlKCJQcmVkaWN0IGxvdyBmcm9tIGhpZ2giKSArDQogIGxhYnMoeCA9IGV4cHJlc3Npb24oIlByZWRpY3RlZCBoZWF0aW5nIHRvbGVyYW5jZSAoXHUwMEIwQykiKSwgDQogICAgICAgeSA9IGV4cHJlc3Npb24oIk9ic2VydmVkIGhlYXRpbmcgdG9sZXJhbmNlIChcdTAwQjBDKSIpKSANCg0KcHJlZDQNCmBgYA0KDQpgYGB7ciBwcmVkNC1sbSwgaW5jbHVkZT1GQUxTRX0NCiMgbG93IGZyb20gaGlnaA0KcHJlZF9sb3dfaGlnaCA8LSBsbShkZWx0YV90YXVfbG93IH4gZGVsdGFfdGF1X2xvd19oYXQsIA0KICAgICAgICAgICAgICAgICAgIG9mZnNldCA9IGRlbHRhX3RhdV9sb3dfaGF0LCANCiAgICAgICAgICAgICAgICAgICBkYXRhID0gQVJSKQ0KYGBgDQoNClRoZSAkUl4yJCBpcyBgciByb3VuZChzdW1tYXJ5KHByZWRfbG93X2hpZ2gpJHIuc3F1YXJlZCwgNCkqMTAwYCUuIEVxdWF0aW9ucyBcQHJlZihlcTplcTEwKSBhbmQgXEByZWYoZXE6ZXExMGIpIGNvbnZlcnRzIG5vcm1hbGlzZWQgaGVhdGluZyB0b2xlcmFuY2UgYXQgb25lIGFjY2xpbWF0aW9uIHRlbXBlcmF0dXJlIGludG8gcmVzY2FsZWQgaGVhdGluZyB0b2xlcmFuY2UgKHZpYSAkZ19cYmV0YSQpLCBjb3JyZWN0cyBmb3IgdGhlIGRpZmZlcmVuY2UgaW4gYWNjbGltYXRpb24gdGVtcGVyYXR1cmUgYWxvbmcgdGhlIG5vbi1saW5lYXIgVW5pdmVyc2FsIFRlbXBlcmF0dXJlIERlcGVuZGVuY2UgKHZpYSAkZV57XGJldGFcdGF1fSQpLCBhbmQgY29udmVydHMgcmVzY2FsZWQgYW5kIGJpb2xvZ2ljYWwgcmF0ZS1jb3JyZWN0ZWQgaGVhdGluZyB0b2xlcmFuY2UgaW50byBub3JtYWxpc2VkIGhlYXRpbmcgdG9sZXJhbmNlIGF0IHRoZSBvdGhlciBhY2NsaW1hdGlvbiB0ZW1wZXJhdHVyZSAodmlhICRmX1xiZXRhJCkuIA0KDQoqKioqKioNCg0KIyBUaGUgZWZmZWN0IG9mIGhlYXRpbmcgcmF0ZSBvbiByZXNjYWxlZCBoZWF0aW5nIGR1cmF0aW9uIHsjaGVhdGluZy1yYXRlfQ0KDQpgYGB7ciB2YXJ5aW5nLXJhdGVzfQ0KdmFyeWluZ19yYXRlcyA8LSByZWFkLmNzdigiTW9ybGV5X2V0X2FsXzIwMTYuY3N2IikgJT4lIA0KICByZW5hbWUoaGVhdGluZ19yYXRlID0gOCwNCiAgICAgICAgIHRhID0gOSwNCiAgICAgICAgIHRjID0gMTApICU+JSANCiAgIG11dGF0ZShHZW51cyA9IGlmZWxzZShTcGVjaWVzID09ICJib3JjaGdyZXZpbmtpIiwgIlBhZ290aGVuaWEiLCBnZW51cykpICU+JSAjIFN5bm9ueW0gVHJlbWF0b211cyBQYWdvdGhlbmlhIFBhZ290aGVuaWEgaW4gQVJSIGRhdGFzZXQNCiAgbXV0YXRlKE5hbWUgPSBwYXN0ZShHZW51cywgU3BlY2llcyksIA0KICAgICAgICAgZXhwZXJpbWVudCA9ICJ2YXJpYWJsZSIsDQogICAgICAgICBsYW1iZGEgPSBoZWF0aW5nX3JhdGUgLyBUaykgJT4lDQogIG11dGF0ZShQaHlsYSA9IGNhc2Vfd2hlbihwaHlsYSA9PSAibW9sbHVzYyIgfiAiTW9sbHVzY2EiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgcGh5bGEgPT0gIkZpc2giIH4gIkNob3JkYXRhIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHBoeWxhID09ICJBc2NpZGlhbnMiIH4gIkNob3JkYXRhIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHBoeWxhID09ICJDcnVzdGFjZWFuIiB+ICJBcnRocm9wb2RhIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiBwaHlsYSkpICU+JQ0KICBncm91cF9ieShOYW1lKSAlPiUNCiAgZGlzdGluY3QoKSAlPiUgIyByZW1vdmUgZHVwbGljYXRlZCByb3dzDQogIGZpbHRlcihuKCk+MSkgJT4lICMgcmVtb3ZlIHNwZWNpZXMgd2l0aCAxIG9ic2VydmF0aW9uDQogIHVuZ3JvdXAoKQ0KYGBgDQoNClRvIGV4YW1pbmUgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGhlYXRpbmcgcmF0ZSBhbmQgcmVzY2FsZWQgaGVhdGluZyBkdXJhdGlvbiBmdXJ0aGVyLCB3ZSB1c2VkIGEgc2Vjb25kIGRhdGFzZXQgY29udGFpbmluZyAkVF9jJCBtZWFzdXJlZCBmcm9tIHRoZSBzYW1lICRUX2EkIHVuZGVyIGRpZmZlcmVudCBoZWF0aW5nIHJhdGVzICgkXGxhbWJkYSQpIFtATW9ybGV5MjAxNl0uIFNwZWNpZXMgd2l0aCBvbmx5IG9uZSBvYnNlcnZhdGlvbiBhcmUgcmVtb3ZlZCAobiA9IDMpLiBUaGUgZGF0YXNldCBoYXMgYHIgbnJvdyh2YXJ5aW5nX3JhdGVzKWAgb2JzZXJ2YXRpb25zIGZyb20gYHIgbGVuZ3RoKHVuaXF1ZSh2YXJ5aW5nX3JhdGVzJFBoeWxhKSlgIHBoeWxhLiAqVHJlbWF0b211cyBib3JjaGdyZXZpbmtpKiBpcyByZW5hbWVkIHRvICpQYWdvdGhlbmlhIGJvcmNoZ3Jldmlua2kqIGJlY2F1c2UgKlBhZ290aGVuaWEqIGlzIHRoZSBhY2NlcHRlZCBnZW51cyBhbmQgaXMgYWxzbyB1c2VkIGluIHRoZSBBUlIgZGF0YXNldC4gV2UgY29tYmluZWQgdGhpcyBkYXRhc2V0IHdpdGggZGF0YSBmcm9tIHRoZSBjb25zdGFudCBoZWF0aW5nIHJhdGUgZXhwZXJpbWVudHMgZm9yIHNwZWNpZXMgdGhhdCBhbHNvIGhhZCB2YXJpYWJsZSBoZWF0aW5nIHJhdGUgZGF0YSB3aXRoIHRoZW0gKDEyOSBvYnNlcnZhdGlvbnMgZnJvbSAzNyBzcGVjaWVzKS4NCg0KVGhlIG9yaWdpbmFsIEFSUiBkYXRhc2V0IHdhcyBjb252ZXJ0ZWQgdG8gYSBsb25nIGZvcm1hdCB0byBqb2luIHdpdGggdGhlIHZhcnlpbmcgaGVhdGluZyByYXRlIGRhdGFzZXQgKGBzcGVjaWVzX2RhdGFgKS4gVGhlIGRhdGFzZXRzIGFyZSBpZGVudGlmaWVkIGJ5IGBleHBlcmltZW50YCAoYHZhcmlhYmxlYCBvciBgY29uc3RhbnRgKSBhbmQgYG9jY3VycmVuY2VgIChpZGVudGlmeWluZyBzcGVjaWVzIHRoYXQgb2NjdXIgaW4gYm90aCBkYXRhc2V0cykuIA0KDQpgYGB7ciB2YXJ5aW5nfQ0Kc3BlY2llc19kYXRhIDwtIEFSUiAlPiUNCiAgIyBUcmFuc2Zvcm0gdGhlIEFSUiBkYXRhc2V0IHRvIGxvbmcgZm9ybWF0DQogIHBpdm90X2xvbmdlcihjb2xzID0gc3RhcnRzX3dpdGgoYygidGFfIiwgInRjXyIpKSwNCiAgICAgICAgICAgICAgIG5hbWVzX3RvID0gYygiLnZhbHVlIiwgImFzc2F5IiksDQogICAgICAgICAgICAgICBuYW1lc19zZXAgPSAiXyIpICU+JQ0KICBtdXRhdGUoZXhwZXJpbWVudCA9ICJjb25zdGFudCIpICU+JSANCiAgIyBKb2luIGRhdGFzZXRzIGFuZCBnZXQgb2NjdXJlbmNlcyBvZiBzcGVjaWVzIGluIGVhY2ggZGF0YXNldA0KICBmdWxsX2pvaW4oLiwNCiAgICAgICAgICAgIHZhcnlpbmdfcmF0ZXMsIA0KICAgICAgICAgICAgYnkgPSBjKCJHZW51cyIsICJTcGVjaWVzIiwgIk5hbWUiLCAiZXhwZXJpbWVudCIsICJ0YSIsICJ0YyIsICJsYW1iZGEiKSwNCiAgICAgICAgICAgIHN1ZmZpeCA9IGMoIl9jb25zdGFudCIsICJfdmFyaWFibGUiKSkgJT4lIA0KICAjIE5vcm1hbGlzZSB0ZW1wZXJhdHVyZQ0KICBtdXRhdGUodGF1X2EgPSB0YSAvIFRrLCANCiAgICAgICAgIHRhdV9jID0gdGMgLyBUaywNCiAgICAgICAgIGRlbHRhX3RhdSA9IHRhdV9jIC0gdGF1X2EpICU+JSANCiAgZ3JvdXBfYnkoTmFtZSkgJT4lIA0KICBtdXRhdGUob2NjdXJyZW5jZSA9IGxlbmd0aCh1bmlxdWUoZXhwZXJpbWVudCkpKSAlPiUNCiAgdW5ncm91cCgpICU+JSANCiAgIyBLZWVwIHNwZWNpZXMgd2l0aCBtb3JlIHRoYW4gMSBoZWF0aW5nIHJhdGUgZnJvbSBlaXRoZXIgZGF0YXNldA0KICBmaWx0ZXIoZXhwZXJpbWVudCA9PSAidmFyaWFibGUiIHwgb2NjdXJyZW5jZSA9PSAyKSAlPiUgDQogICMgQ2FsY3VsYXRlIHJlc2NhbGVkIGhlYXRpbmcgZHVyYXRpb24gKEVxdWF0aW9uIDgpDQogIG11dGF0ZShkZWx0YV90ciA9IHBtYXBfZGJsKGxpc3QodGF1X2EgPSB0YXVfYSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0YXVfYyA9IHRhdV9jLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhbWJkYSA9IGxhbWJkYSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlbHRhX3RyX2Z1bikpDQoNCnJhdGVfcmF0aW9zIDwtIHNwZWNpZXNfZGF0YSAlPiUgDQogICMgR3JvdXAgYnkgbmFtZQ0KICBncm91cF9ieShOYW1lKSAlPiUgDQogICMgRm9yIGVhY2ggc3BlY2llcyBjcmVhdGUgYWxsIGNvbWJpbmF0aW9ucyBvZiBoZWF0aW5nIHJhdGUgd2l0aCBjb3ZhcmlhdGVzDQogIGdyb3VwX21vZGlmeSh+ZXhwYW5kX2dyaWQoLngsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdCgueCwgbGFtYmRhLCBkZWx0YV90ciwgZGVsdGFfdGF1LCB0YXVfYSksDQogICMgQWRkIG51bWJlcmVkIHN1ZmZpeCB0byBhbGwgY29sdW1uczsgdW5pcXVlIGZvciBkdXBsaWNhdGlvbnMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAubmFtZV9yZXBhaXIgPSBmdW5jdGlvbiAoeCkgYXZlKHgsIHgsIEZVTiA9IGZ1bmN0aW9uKGkpIHN0cl9jKGksIHNlcV9hbG9uZyhpKSkpKSkgJT4lDQogICMgQ2FsY3VsYXRlIHJhdGlvIG9mIHJlc2NhbGVkIGR1cmF0aW9uIGFuZCBoZWF0aW5nIHJhdGUgKEVxdWF0aW9uIDE5KQ0KICBtdXRhdGUobGFtYmRhX3JhdGlvID0gbGFtYmRhMi9sYW1iZGExLA0KICAgICAgICAgdF9yYXRpbyA9IGRlbHRhX3RyMi9kZWx0YV90cjEpICU+JQ0KICAjIENhbGN1bGF0ZSBzY2FsaW5nIGNvZWZmaWNpZW50IGdhbW1hIGZvciBlYWNoIHNwZWNpZXMgKEVxdWF0aW9uIDE5KQ0KICBncm91cF9tb2RpZnkoZnVuY3Rpb24oeCwgeSl7DQogICAgeCRnZyA8LSBhYnMoYXMubnVtZXJpYyhjb2VmKGxtKGxvZyh0X3JhdGlvKSB+IGxvZyhsYW1iZGFfcmF0aW8pLCB4KSlbMl0pKQ0KICAgIHJldHVybih4KX0pICU+JSANCiAgZGlzdGluY3QoKSAlPiUgIyBSZW1vdmUgZHVwbGljYXRpb25zIGNyZWF0ZWQgYnkgZXhwYW5kIGdyaWQNCiAgdW5ncm91cCgpICU+JSANCiAgIyBDYWxjdWxhdGUgcHJlZGljdGVkIG5vcm1hbGlzZWQgaGVhdGluZyB0b2xlcmFuY2UgYXQgdGhlIHNlY29uZCBhY2NsaW1hdGlvbiB0ZW1wZXJhdHVyZSwgY29ycmVjdGVkIGZvciBoZWF0aW5nIHJhdGUgKEVxdWF0aW9uIDIwKQ0KICBtdXRhdGUoZGVsdGFfdGF1Ml9oYXQgPSBmX2JldGFfZnVuKGV4cChiZXRhX0sgKiAodGF1X2ExLXRhdV9hMikpICogKGxhbWJkYV9yYXRpbyBeICgxIC0gZ2cpKSAqIGdfYmV0YV9mdW4oZGVsdGFfdGF1MSkpLA0KICAgICAgICAgZGVsdGFfdGF1Ml9oYXRfaW50ZXIgPSBmX2JldGFfZnVuKGV4cChiZXRhX0sgKiAodGF1X2ExLXRhdV9hMikpICogKGxhbWJkYV9yYXRpbyBeICgxIC0gMC43NjU2NTQ4KSkgKiBnX2JldGFfZnVuKGRlbHRhX3RhdTEpKSkNCg0KIyBpbnRlcnNwZWNpZmljIGdhbW1hDQpnYW1tYSA8LSBhYnMoY29lZihnbG0obG9nKHRfcmF0aW8pIH4gbG9nKGxhbWJkYV9yYXRpbyksIGRhdGEgPSByYXRlX3JhdGlvcykpWzJdKQ0KYGBgDQoNCioqKg0KDQojIyBUZXN0aW5nIGEgbnVsbCBlZmZlY3Qgb2YgaGVhdGluZyByYXRlcyBvbiByZXNjYWxlZCBoZWF0aW5nIGR1cmF0aW9uDQoNCldlIGZpcnN0IGNvbnNpZGVyZWQgYSBudWxsIGh5cG90aGVzaXMgdGhhdCByZXNjYWxlZCBoZWF0aW5nIGR1cmF0aW9uIGRvZXMgbm90IGRlcGVuZCBvbiBoZWF0aW5nIHJhdGUuIEVxdWF0aW9uIFxAcmVmKGVxOmVxN2IpIHN1Z2dlc3RzIHRoYXQgZm9yIGFueSBoZWF0aW5nIHJhdGU6DQoNClxiZWdpbntlcXVhdGlvbn0NClxEZWx0YSBcdGF1IChcbGFtYmRhKT0gZl9cYmV0YSAoZV57LVxiZXRhIFx0YXVfe2F9fSBcbGFtYmRhIFxEZWx0YSB0X3IoXGxhbWJkYSkpIA0KKFwjZXE6ZXExMSkNClxlbmR7ZXF1YXRpb259DQoNCklmIHRoZSBudWxsIGh5cG90aGVzaXMgaXMgc3VwcG9ydGVkLCB0aGVuICRcRGVsdGEgdF9yIChcbGFtYmRhKSA9IFxEZWx0YSB0X3IgKDApJCBhbmQgdGh1cyBFcXVhdGlvbiBcQHJlZihlcTplcTExKSBiZWNvbWVzDQoNClxiZWdpbntlcXVhdGlvbn0NClxEZWx0YSBcdGF1IChcbGFtYmRhKSA9IGZfXGJldGEgKGVeey1cYmV0YSBcdGF1X3thfX0gXGxhbWJkYSBcRGVsdGEgdF9yICgwKSkNCihcI2VxOmVxMTIpDQpcZW5ke2VxdWF0aW9ufQ0KDQp3aGljaCBpcyBhIGxvZ2FyaXRobWljLCB0ZW1wZXJhdHVyZS1kZXBlbmRlbnQgcmVsYXRpb25zaGlwIGJldHdlZW4gb2JzZXJ2ZWQgaGVhdGluZyB0b2xlcmFuY2UgYW5kIGhlYXRpbmcgcmF0ZS4gRXF1YXRpb24gXEByZWYoZXE6ZXExMikgY2FuIGJlIHRlc3RlZCBieSBjb25kdWN0aW5nIHJhbXBpbmcgYXNzYXlzIHN0YXJ0aW5nIGF0IHRoZSBzYW1lIGFjY2xpbWF0aW9uIHRlbXBlcmF0dXJlIGJ1dCB1c2luZyBkaWZmZXJlbnQgaGVhdGluZyByYXRlcy4gRnJvbSB0aGVzZSBkYXRhIHdlIGNhbiBpbmZlciAkXERlbHRhIHRfciAoMCkkIGZyb20gdGhlIGV4cGVyaW1lbnQgd2l0aCB0aGUgc2xvd2VzdCBoZWF0aW5nIHJhdGUgJFxsYW1iZGFfe21pbn0kLiBXZSBzaG91bGQgdGhlbiBoYXZlIHRoYXQNCg0KXGJlZ2lue2VxdWF0aW9ufQ0KXERlbHRhIFx0YXUgKFxsYW1iZGEpID0gZl9cYmV0YSAoXGhhdHtcbGFtYmRhfSksIFwgXHRleHR7d2hlcmV9IFwgXGhhdHtcbGFtYmRhfSA9IFxmcmFje1xsYW1iZGF9e1xsYW1iZGFfe21pbn19IGdfXGJldGEgKFxEZWx0YSBcdGF1IChcbGFtYmRhX3ttaW59KSkNCihcI2VxOmVxMTMpDQpcZW5ke2VxdWF0aW9ufQ0KDQpJbiBhIHBsb3Qgb2Ygbm9ybWFsaXNlZCBoZWF0aW5nIHRvbGVyYW5jZSAoJFxEZWx0YSBcdGF1JCkgYWdhaW5zdCB0aGUgdHJhbnNmb3JtZWQgdmFyaWFibGUgJGZfXGJldGEgKFxoYXR7XGxhbWJkYX0pJCwgdGhlIG51bGwgaHlwb3RoZXNpcyBpcyBzdXBwb3J0ZWQgaWYgdGhlIHBvaW50cyBmYWxsIGFsb25nIHRoZSBpZGVudGl0eSAoMToxKSBsaW5lLiBJZiBwb2ludHMgc3lzdGVtYXRpY2FsbHkgZmFsbCBiZWxvdyB0aGUgMToxIGxpbmUsIHRoZW4gdGhlIG51bGwgaHlwb3RoZXNpcyBpcyBub3Qgc3VwcG9ydGVkLg0KDQpgYGB7ciBkZXBhcnR1cmUsIGZpZy5jYXAgPSAiUHJlZGljdGVkIGhlYXRpbmcgdG9sZXJhbmNlIHZlcnN1cyBvYnNlcnZlZCBoZWF0aW5nIHRvbGVyYW5jZSBmb3Igc3BlY2llcyB3aXRoIHZhcnlpbmcgaGVhdGluZyByYXRlcyAoMTA3IG9ic2VydmF0aW9ucykuIENvbG91cnMgYXJlIHNwZWNpZXMgKG4gPSAzNykuIn0NCmdfZGVwYXJ0dXJlIDwtIHNwZWNpZXNfZGF0YSAlPiUNCiAgZmlsdGVyKGV4cGVyaW1lbnQgPT0gInZhcmlhYmxlIikgJT4lIA0KICBncm91cF9ieShOYW1lKSAlPiUgDQogIG11dGF0ZShsYW1iZGFfbWluID0gbWluKGxhbWJkYSksDQogICAgICAgICBkZWx0YV90YXVfbWluID0gZGVsdGFfdGF1W3doaWNoLm1pbihsYW1iZGEpXSkgJT4lIA0KICB1bmdyb3VwKCkgJT4lIA0KICBnZ3Bsb3QobWFwcGluZyA9IGFlcyh4ID0gZl9iZXRhX2Z1bihsYW1iZGEgLyBsYW1iZGFfbWluICogZ19iZXRhX2Z1bihkZWx0YV90YXVfbWluKSkgKiBUaywNCiAgICAgICAgICAgICAgICAgICAgICAgeSA9IGRlbHRhX3RhdSAqIFRrLA0KICAgICAgICAgICAgICAgICAgICAgICBjb2wgPSBOYW1lKSkgKyANCiAgZ2VvbV9wb2ludCgpICsgDQogIGdlb21fbGluZShhbHBoYSA9IDAuNSkgKw0KICBnZW9tX2FibGluZShzbG9wZSA9IDEsIGludGVyY2VwdCA9IDAsIGx0eSA9IDIsIGFscGhhID0gMC42KSArDQogIGxhYnMoeCA9IGV4cHJlc3Npb24oIlByZWRpY3RlZCBoZWF0aW5nIHRvbGVyYW5jZSAoXHUwMEIwQykiKSwgDQogICAgICAgeSA9IGV4cHJlc3Npb24oIk9ic2VydmVkIGhlYXRpbmcgdG9sZXJhbmNlIChcdTAwQjBDKSIpKSArDQogIHNjYWxlX2NvbG91cl92aXJpZGlzX2Qob3B0aW9uID0gIkMiKSArDQogIHNjYWxlX3hfY29udGludW91cyhleHBhbmQgPSBjKDAsMCksIGxpbWl0cyA9IGMoMCwgMTAwKSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApLCBsaW1pdHMgPSBjKDAsIDI1KSkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiLCBwbG90Lm1hcmdpbiA9IG1hcmdpbig1LjUsIDcsIDUuNSwgNS41LCB1bml0ID0gInB0IikpDQoNCmdfZGVwYXJ0dXJlDQpgYGANCg0KV2UgdXNlZCB0aGUgc2xvd2VzdCBoZWF0aW5nIHJhdGUgb2YgZWFjaCBzcGVjaWVzIHRvIHRlc3Qgd2hldGhlciBoZWF0aW5nIHJhdGUgaGFkIG5vIGVmZmVjdCBvbiByZXNjYWxlZCBoZWF0aW5nIGR1cmF0aW9uIGFuZCB0aHVzIHByZWRpY3RlZCBoZWF0aW5nIHRvbGVyYW5jZS4gVGhlIG51bGwgaHlwb3RoZXNpcyB3YXMgbm90IHN1cHBvcnRlZCBiZWNhdXNlIHBvaW50cyBzeXN0ZW1hdGljYWxseSBmYWxsIGJlbG93IHRoZSAxOjEgbGluZSAoRmlndXJlIFxAcmVmKGZpZzpkZXBhcnR1cmUpKS4NCg0KVG8gdmlzdWFsaXplIHRoZSBlZmZlY3Qgb2YgaGVhdGluZyByYXRlIG9uIHJlc2NhbGVkIGhlYXRpbmcgdG9sZXJhbmNlLCB3ZSBwbG90IHRoZSByYXRpbyBvZiByZXNjYWxlZCBoZWF0aW5nIGR1cmF0aW9uIGZvciBhIHBhaXJlZCBvYnNlcnZhdGlvbiB3aXRoaW4gYSBzcGVjaWVzIHdpdGggdGhlIGNvcnJlc3BvbmRpbmcgcmF0aW8gZm9yIHBhaXJlZCBoZWF0aW5nIHJhdGUuIFRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0aGUgcmF0aW8gb2YgcmVzY2FsZWQgaGVhdGluZyBkdXJhdGlvbiBhbmQgdGhlIHJhdGlvIG9mIGhlYXRpbmcgcmF0ZSBpcyBkZXNjcmliZWQgYnkgYW4gYWxsb21ldHJpYyBzY2FsaW5nIGVxdWF0aW9uIGluIHRoZSBmb3JtICRcRGVsdGEgdF9yIChcbGFtYmRhKSBcc2ltIGMgXGxhbWJkYV57LSBcZ2FtbWF9JCB3aGVyZSAkYyQgZGVwZW5kcyBvbmx5IG9uIHRoZSBleHBlcmltZW50YWwgcHJvdG9jb2wgYW5kIHRoZSBzcGVjaWVzLXNwZWNpZmljIHNjYWxpbmcgZXhwb25lbnQsICRcZ2FtbWEkLiBQb2ludHMgc2hvdWxkIGZhbGwgYWxvbmcgdGhlIGlkZW50aXR5IGxpbmUgaWYgaGVhdGluZyByYXRlIGRvZXMgbm90IGFmZmVjdCByZXNjYWxlZCBoZWF0aW5nIHRvbGVyYW5jZSAoaS5lLiwgYSBzY2FsaW5nIGV4cG9uZW50IG9mIC0xKS4NCg0KQ2hhbmdlIGluIHJlc2NhbGVkIGhlYXRpbmcgZHVyYXRpb24sIGFuZCB0aHVzIGhlYXRpbmcgdG9sZXJhbmNlLCBzY2FsZXMgd2l0aCBjaGFuZ2UgaW4gaGVhdGluZyByYXRlIGFjY29yZGluZyB0byBhbiBhbGxvbWV0cmljIHNjYWxpbmcgZXF1YXRpb24uIFRoZXJlIGlzIHNvbWUgc3BlY2llcy1zcGVjaWZpYyB2YXJpYXRpb24gaW4gdGhlIHNsb3BlIG9mIHRoZSByZWdyZXNzaW9uICRcZ2FtbWEkIChjb2xvdXJzKS4gT3ZlcmFsbCwgdGhlcmUgaXMgYW4gaW50ZXJzcGVjaWZpYyBzY2FsaW5nIGV4cG9uZW50IG9mIGFwcHJveGltYXRlbHkgJFxnYW1tYSA9JCBgciByb3VuZChnYW1tYSwgMylgIGNhbGN1bGF0ZWQgZnJvbSBhIGxpbmVhciByZWdyZXNzaW9uIG9mIHJhdGlvcyBvZiBoZWF0aW5nIHJhdGUgYW5kIHJhdGlvcyBvZiByZXNjYWxlZCBoZWF0aW5nIGR1cmF0aW9uIG9uIExvZ34xMH4gc2NhbGVzIChGaWd1cmUgXEByZWYoZmlnOmR0ZHQpKS4gDQoNCmBgYHtyIGR0ZHQsIGZpZy5jYXAgPSAiSW50ZXJzcGVjaWZpYyBzY2FsaW5nIG9mIHJlc2NhbGVkIGhlYXRpbmcgZHVyYXRpb24gd2l0aCBoZWF0aW5nIHJhdGUuIFZhcmlhdGlvbiB3aXRoaW4gZWFjaCBzcGVjaWVzIGlzIHNob3duIGJ5IHRoZSBmaXR0ZWQgbGluZXMgYmV0d2VlbiBwb2ludHMgKDEyOSBvYnNlcnZhdGlvbnMpLiBUaGUgZGFzaGVkIGlkZW50aXR5IGxpbmUgaXMgdGhlIGV4cGVjdGVkIHJlbGF0aW9uc2hpcCBmb2xsb3dpbmcgdGhlIG51bGwgaHlwb3RoZXNpcy4gQXhlcyBhcmUgTG9nMTAgdHJhbnNmb3JtZWQuIENvbG91cnMgYXJlIHNwZWNpZXMgKG4gPSAzNykuIn0NCmdfc2NhbGluZyA8LSBnZ3Bsb3QoZGF0YSA9IHJhdGVfcmF0aW9zLA0KICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSBsYW1iZGFfcmF0aW8sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSB0X3JhdGlvLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cCA9IE5hbWUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sID0gTmFtZSkpICsgDQogIGdlb21fbGluZShzdGF0ID0ic21vb3RoIiwgbWV0aG9kID0gImxtIiwgYWxwaGEgPSAwLjUpICsNCiAgZ2VvbV9wb2ludCgpICsgDQogIGdlb21fYWJsaW5lKHNsb3BlID0gLTEsIGludGVyY2VwdCA9IDAsIGx0eSA9IDIsIGFscGhhID0gMC42KSArDQogIGdlb21fc21vb3RoKGFlcyhncm91cCA9IDEpLCBtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFLCBjb2wgPSAxKSArDQogc2NhbGVfeF9sb2cxMCgNCiAgIGJyZWFrcyA9IHNjYWxlczo6dHJhbnNfYnJlYWtzKCJsb2cxMCIsIGZ1bmN0aW9uKHgpIDEwXngpLA0KICAgbGFiZWxzID0gc2NhbGVzOjp0cmFuc19mb3JtYXQoImxvZzEwIiwgc2NhbGVzOjptYXRoX2Zvcm1hdCgxMF4ueCkpDQogKSArDQogc2NhbGVfeV9sb2cxMCgNCiAgIGJyZWFrcyA9IHNjYWxlczo6dHJhbnNfYnJlYWtzKCJsb2cxMCIsIGZ1bmN0aW9uKHgpIDEwXngpLA0KICAgbGFiZWxzID0gc2NhbGVzOjp0cmFuc19mb3JtYXQoImxvZzEwIiwgc2NhbGVzOjptYXRoX2Zvcm1hdCgxMF4ueCkpDQogKSArDQogIGdndGl0bGUocGFzdGUwKCJzbG9wZSA9ICIsIA0KICAgICAgICAgICAgICAgICByb3VuZChnYW1tYSwgMykpKSArDQogIGxhYnMoeCA9ICJIZWF0aW5nIHJhdGUgcmF0aW8iLCB5ID0gIlJlc2NhbGVkIGhlYXRpbmcgZHVyYXRpb24gcmF0aW8iKSArDQogIHNjYWxlX2NvbG91cl92aXJpZGlzX2Qob3B0aW9uID0gIkMiKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpDQoNCmdfc2NhbGluZw0KYGBgDQoNCioqKg0KDQojIyBRdWFudGlmeWluZyB0aGUgZWZmZWN0IG9mIGhlYXRpbmcgcmF0ZXMgb24gcmVzY2FsZWQgaGVhdGluZyB0b2xlcmFuY2UNCg0KU2luY2UgaGlnaGVyIGhlYXRpbmcgcmF0ZXMgcmVkdWNlcyByZXNjYWxlZCBoZWF0aW5nIHRvbGVyYW5jZSBmb2xsb3dpbmcgYSBwaGVub21lbm9sb2dpY2FsIHBvd2VyIGxhdywgdGhlbiB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gdHdvIGV4cGVyaW1lbnRzIGRvbmUgYXQgdHdvIGhlYXRpbmcgcmF0ZXMsICRcbGFtYmRhXzEkIGFuZCAkXGxhbWJkYV8yJCwgcmVnYXJkbGVzcyBvZiB0aGUgc3RhcnRpbmcgdGVtcGVyYXR1cmUsIGNhbiBiZSBkZXNjcmliZWQgYnk6DQoNClxiZWdpbntlcXVhdGlvbn0NClxmcmFje1xsYW1iZGFfMiBcRGVsdGEgdF9yIChcbGFtYmRhXzIpfXtcbGFtYmRhXzEgXERlbHRhIHRfciAoXGxhbWJkYV8xKX0gXGFwcHJveCBcYmlnZyhcZnJhY3tcbGFtYmRhXzJ9e1xsYW1iZGFfMX1cYmlnZyleezEtXGdhbW1hfQ0KKFwjZXE6ZXExNCkNClxlbmR7ZXF1YXRpb259DQoNCmFuZCB0aGVyZWZvcmUgdGhhdCBmcm9tIG9uZSBoZWF0aW5nIHRvbGVyYW5jZSAkXERlbHRhIFx0YXVfMSQgd2Ugc2hvdWxkIGJlIGFibGUgdG8gcHJlZGljdCBhbnkgb3RoZXIgJFxEZWx0YSBcdGF1XzIkLiBVc2luZyBFcXVhdGlvbiBcQHJlZihlcTplcTE0KSB3ZSBjYW4gZGVkdWNlICRcRGVsdGEgdF9yIChcbGFtYmRhXzIpJCBhbmQgZnJvbSBFcXVhdGlvbnMgXEByZWYoZXE6ZXE3YSkgYW5kIFxAcmVmKGVxOmVxN2IpIGxlYWRzIHRvOg0KDQpcYmVnaW57ZXF1YXRpb259DQpcRGVsdGFcdGF1XzIgPSBmX3tcYmV0YX1cQmlnZyhlXntcYmV0YShcdGF1X3thMX0tXHRhdV97YTJ9KX1cYmlnZyhcZnJhY3tcbGFtYmRhXzJ9e1xsYW1iZGFfMX1cYmlnZyleezEtXGdhbW1hfWdfe1xiZXRhfVxiaWcoXERlbHRhXHRhdV8xXGJpZylcQmlnZykNCihcI2VxOmVxMTUpDQpcZW5ke2VxdWF0aW9ufQ0KDQpUaGF0IGlzLCB3ZSBjYW4gcHJlZGljdCBvbmUgaGVhdGluZyB0b2xlcmFuY2UgJFxEZWx0YVx0YXVfMiQgZnJvbSBhbm90aGVyICRcRGVsdGFcdGF1XzEkIHVzaW5nIEVxdWF0aW9uIFxAcmVmKGVxOmVxMTUpIHdoaWNoIGluY29ycG9yYXRlcyB0aGUgY29ycmVjdGlvbiBmb3IgdGhlIGVmZmVjdCBvZiBoZWF0aW5nIHJhdGUgb24gcmVzY2FsZWQgaGVhdGluZyBkdXJhdGlvbiB1c2luZyBhIHNwZWNpZXMgc3BlY2lmaWMgc2NhbGluZyBleHBvbmVudCAoJFxnYW1tYSQpLiBXZSB1c2Ugc3BlY2llcy1zcGVjaWZpYyBzY2FsaW5nIGV4cG9uZW50cyBpbiBzdWJzZXF1ZW50IGNhbGN1bGF0aW9ucyBmb3IgcHJlY2lzaW9uLiBEb2luZyBzbywgd2Ugc2VlIHN0cm9uZyBjb25jb3JkYW5jZSBvZiB0aGUgb2JzZXJ2ZWQgaGVhdGluZyB0b2xlcmFuY2UgKGBkZWx0YV90YXUyYCkgYW5kIHRoZSBlc3RpbWF0ZWQgdmFsdWUgdXNpbmcgRXF1YXRpb24gXEByZWYoZXE6ZXExNSkgKGBkZWx0YV90YXUyX2hhdGApLg0KDQpgYGB7ciBnYW1tYSwgZmlnLmNhcCA9ICJQcmVkaWN0ZWQgaGVhdGluZyB0b2xlcmFuY2UgY29ycmVjdGVkIHVzaW5nIHNwZWNpZXMtc3BlY2lmaWMgc2NhbGluZyBleHBvbmVudHMgZm9yIHRoZSBhbGxvbWV0cmljIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHJlc2NhbGVkIGhlYXRpbmcgZHVyYXRpb24gYW5kIGhlYXRpbmcgcmF0ZS4gQ29sb3VycyBhcmUgc3BlY2llcy4ifQ0KZ19wcmVkaWN0X3RhdSA8LSByYXRlX3JhdGlvcyAlPiUgDQogIGZpbHRlcih0X3JhdGlvICE9IDEgJiBsYW1iZGFfcmF0aW8gIT0gMSkgJT4lICMgcmVtb3ZlIHRyaXZpYWwgcGFpcnMgd2hlcmUgaXQgaXMgdGhlIGxvd2VzdCBoZWF0aW5nIHJhdGUNCiAgZ2dwbG90KG1hcHBpbmcgPSBhZXMoeCA9IGRlbHRhX3RhdTJfaGF0ICogVGssIA0KICAgICAgICAgICAgICAgICAgICAgICB5ID0gZGVsdGFfdGF1MiAqIFRrLA0KICAgICAgICAgICAgICAgICAgICAgICBjb2wgPSBOYW1lKSkgKyANCiAgZ2VvbV9hYmxpbmUoc2xvcGUgPSAxLCBpbnRlcmNlcHQgPSAwLCBsdHkgPSAyLCBhbHBoYSA9IDAuNikgKw0KICBnZW9tX3BvaW50KCkgKyANCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSwgY29sID0gMSkgKyANCiAgbGFicyh4ID0gZXhwcmVzc2lvbigiUHJlZGljdGVkIGhlYXRpbmcgdG9sZXJhbmNlIChcdTAwQjBDKSIpLCANCiAgICAgICB5ID0gZXhwcmVzc2lvbigiT2JzZXJ2ZWQgaGVhdGluZyB0b2xlcmFuY2UgKFx1MDBCMEMpIikpICsNCiAgc2NhbGVfY29sb3VyX3ZpcmlkaXNfZChvcHRpb24gPSAiQyIpICsNCiAgc2NhbGVfeF9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwwKSwgbGltaXRzID0gYygwLCAzMCkpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGMoMCwwKSwgbGltaXRzID0gYygwLCAzMCkpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikNCg0KZ19wcmVkaWN0X3RhdQ0KYGBgDQoNCldlIGNhbiBwbG90IHRoZSBzYW1lIGFzIEZpZ3VyZSBcQHJlZihmaWc6Z2FtbWEpIGJ1dCB1c2luZyB0aGUgaW50ZXJzcGVjaWZpYyB2YWx1ZSBvZiBgciByb3VuZChnYW1tYSwzKWAgZm9yICRcZ2FtbWEkIChGaWd1cmUgXEByZWYoZmlnOmludGVyLWdhbW1hKSkuIERvaW5nIHNvIGluY3JlYXNlcyBvdXIgcHJlZGljdGlvbiBlcnJvciBmb3IgYSBzcGVjaWVzLg0KDQpgYGB7ciBpbnRlci1nYW1tYSwgZWNobyA9IEZBTFNFLCBmaWcuY2FwID0gIlByZWRpY3RlZCBoZWF0aW5nIHRvbGVyYW5jZXMgY2FsY3VsYXRlZCB1c2luZyBhIHZhbHVlIG9mIDAuNzY2IGZvciBnYW1tYSwgcmVwcmVzZW50aW5nIGFuIGludGVyc3BlY2lmaWMgcGFyYW1ldGVyLiBDb2xvdXJzIGFyZSBzcGVjaWVzLiJ9DQpyYXRlX3JhdGlvcyAlPiUgDQogICBmaWx0ZXIodF9yYXRpbyAhPSAxICYgbGFtYmRhX3JhdGlvICE9IDEpICU+JSAjIHJlbW92ZSB0cml2aWFsIHBhaXJzIHdoZXJlIGl0IGlzIHRoZSBsb3dlc3QgaGVhdGluZyByYXRlDQogIGdncGxvdChtYXBwaW5nID0gYWVzKHggPSBkZWx0YV90YXUyX2hhdF9pbnRlciAqIFRrLCANCiAgICAgICAgICAgICAgICAgICAgICAgeSA9IGRlbHRhX3RhdTIgKiBUaywNCiAgICAgICAgICAgICAgICAgICAgICAgY29sID0gTmFtZSkpICsgDQogIGdlb21fYWJsaW5lKHNsb3BlID0gMSwgaW50ZXJjZXB0ID0gMCwgbHR5ID0gMiwgYWxwaGEgPSAwLjYpICsNCiAgZ2VvbV9wb2ludCgpICsgDQogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UsIGNvbCA9IDEpICsgDQogIHNjYWxlX3hfY29udGludW91cyhleHBhbmQgPSBjKDAsMCksIGxpbWl0cyA9IGMoMCwgMzApKSArDQogIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBjKDAsMCksIGxpbWl0cyA9IGMoMCwgMzApKSArDQogIGxhYnMoeCA9IGV4cHJlc3Npb24oIlByZWRpY3RlZCBoZWF0aW5nIHRvbGVyYW5jZSAoXHUwMEIwQykiKSwgDQogICAgICAgeSA9IGV4cHJlc3Npb24oIk9ic2VydmVkIGhlYXRpbmcgdG9sZXJhbmNlIChcdTAwQjBDKSIpKSArDQogIHNjYWxlX2NvbG91cl92aXJpZGlzX2Qob3B0aW9uID0gIkMiKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpDQpgYGANCg0KKioqDQoNCiMgR2VuZXJhbGlzZWQgZ3JhcGhzIG9mIHJlc2NhbGVkIGhlYXRpbmcgdG9sZXJhbmNlcw0KDQpXZSBjYW4gdmlzdWFsaXNlIHRoZSBnZW5lcmFsIHJlbGF0aW9uc2hpcCBkZXNjcmliZWQgYnkgRXF1YXRpb24gXEByZWYoZXE6ZXExNSksIHVzaW5nIG1lZGlhbiB2YWx1ZXMgb2YgaGVhdGluZyByYXRlLCAkVF9jJCBhbmQgJFRfYSQgYWNyb3NzIGFsbCBzcGVjaWVzIGFuZCAkXGdhbW1hID0kIGByIHJvdW5kKGdhbW1hLDMpYC4NCg0KYGBge3IgZ2VuLCBmaWcuY2FwID0gIkdlbmVyYWxpc2VkIGdyYXBoIG9mIHByZWRpY3RlZCBoZWF0aW5nIHRvbGVyYW5jZSBieSBhY2NsaW1hdGlvbiB0ZW1wZXJhdHVyZSBhbmQgaGVhdGluZyByYXRlIChjb2xvdXJzKS4ifQ0Kc3BfaGVhdF9yYXRlID0gbWVkaWFuKEFSUiRoZWF0aW5nX3JhdGUpDQpzcF90YSA9IG1lZGlhbihBUlIkdGFfbG93KQ0Kc3BfdGMgPSBtZWRpYW4oQVJSJHRjX2xvdykNCg0KaGVhdGluZ19yYXRlIDwtIHJvdW5kKHNvcnQoYygxMF4oc2VxKGxvZzEwKDAuMDA0KSwgbG9nMTAoNjApLCBsZW5ndGgub3V0ID0gMTQpKSwgMC4wMTUsIDEsIDAuMDQyLCAxOCkpLCAzKSAjIG9uIGxvZzEwIHNjYWxlIGZvciBlcXVpZGlzdGFudCBwb2ludHMNCmhlYXRpbmdfcmF0ZSA8LSBoZWF0aW5nX3JhdGVbIWhlYXRpbmdfcmF0ZSAlaW4lIGMoMC4wMTgsIDAuMDM3LCAxMy42NjcpXSAjIG5lYXRlbiBsaW5lcw0KdGEgPC0gc2VxKDUsIDQwLCAxKSAjIHJhbmdlIG9mIGFjY2xpbWF0aW9uIHRlbXBlcmF0dXJlcw0KcGFsX2NvbHMgPC0gdmlyaWRpc0xpdGU6OnZpcmlkaXMobiA9IGxlbmd0aChoZWF0aW5nX3JhdGUpLCBlbmQgPSAxKSAjIGNvbG91ciBwYWxldHRlIGZvciBwb2ludHMNCg0KZ2VuX2VjdG8gPC0gZXhwYW5kX2dyaWQoaGVhdGluZ19yYXRlLCB0YSkgJT4lIA0KICBtdXRhdGUoc3BfbGFtYmRhID0gc3BfaGVhdF9yYXRlIC8gVGssDQogICAgICAgICBzcF90YXVfYSA9IHNwX3RhIC8gVGssDQogICAgICAgICBzcF90YXVfYyA9IHNwX3RjIC8gVGssDQogICAgICAgICBzcF9kZWx0YV90YXUgPSBzcF90YXVfYyAtIHNwX3RhdV9hLA0KICAgICAgICAgdGF1X2EgPSB0YSAvIFRrLCANCiAgICAgICAgIGRlbHRhX3RhdV9hID0gIHNwX3RhdV9hIC0gdGF1X2EsDQogICAgICAgICBsYW1iZGEgPSBoZWF0aW5nX3JhdGUgLyBUaywNCiAgICAgICAgIGxhbWJkYV9yYXRpbyA9IGxhbWJkYS9zcF9sYW1iZGEpICAlPiUgDQogIG11dGF0ZShkZWx0YV90YXVfaGF0ID0gIGZfYmV0YV9mdW4oZXhwKGJldGFfSyAqIGRlbHRhX3RhdV9hKSAqIChsYW1iZGFfcmF0aW8gXiAoMSAtIGdhbW1hKSkgKiBnX2JldGFfZnVuKHNwX2RlbHRhX3RhdSkpKSAlPiUgDQogIGdncGxvdCgpICsgDQogIGdlb21fbGluZShhZXModGEsIGRlbHRhX3RhdV9oYXQgKiBUaywgZ3JvdXAgPSBoZWF0aW5nX3JhdGUsIGNvbCA9IGhlYXRpbmdfcmF0ZSkpICsNCiAgbGFicyh4ID0gZXhwcmVzc2lvbigiQWNjbGltYXRpb24gdGVtcGVyYXR1cmUgKFx1MDBCMEMpIiksIA0KICAgICAgIHkgPSBleHByZXNzaW9uKCJFeHBlY3RlZCBoZWF0aW5nIHRvbGVyYW5jZSAoXHUwMEIwQykiKSkgKw0KICBzY2FsZV9jb2xvdXJfdmlyaWRpc19jKG5hbWUgPSBleHByZXNzaW9uKCJIZWF0aW5nIHJhdGUgKFx1MDBCMEMgaCIgXi0xICogIikiKSwgdHJhbnMgPSAibG9nMTAiLCBsYWJlbHMgPSBmdW5jdGlvbih4KSBzaWduaWYoeCkpIA0KDQpnZW5fZWN0bw0KYGBgDQoNCkZpZ3VyZSBcQHJlZihmaWc6Z2VuKSBjYW4gYWxzbyBiZSB2aXN1YWxpc2VkIGFzIHByZWRpY3RlZCB1cHBlciB0aGVybWFsIHRvbGVyYW5jZSBsaW1pdCAkVF9jJCBmb3IgYW55IGFjY2xpbWF0aW9uIHRlbXBlcmF0dXJlICRUX2EkLg0KDQpgYGB7ciBwcmVkaWN0LXRjLCBmaWcuY2FwID0gIkdlbmVyYWxpc2VkIGdyYXBoIG9mIHByZWRpY3RlZCB1cHBlciB0aGVybWFsIHRvbGVyYW5jZSBsaW1pdCBieSBhY2NsaW1hdGlvbiB0ZW1wZXJhdHVyZSBhbmQgaGVhdGluZyByYXRlIChjb2xvdXJzKS4ifQ0KZXhwYW5kX2dyaWQoaGVhdGluZ19yYXRlLCB0YSkgJT4lIA0KICBtdXRhdGUoc3BfbGFtYmRhID0gc3BfaGVhdF9yYXRlIC8gVGssDQogICAgICAgICBzcF90YXVfYSA9IHNwX3RhIC8gVGssDQogICAgICAgICBzcF90YXVfYyA9IHNwX3RjIC8gVGssDQogICAgICAgICBzcF9kZWx0YV90YXUgPSBzcF90YXVfYyAtIHNwX3RhdV9hLA0KICAgICAgICAgdGF1X2EgPSB0YSAvIFRrLCANCiAgICAgICAgIGRlbHRhX3RhdV9hID0gIHNwX3RhdV9hIC0gdGF1X2EsDQogICAgICAgICBsYW1iZGEgPSBoZWF0aW5nX3JhdGUgLyBUaywNCiAgICAgICAgIGxhbWJkYV9yYXRpbyA9IGxhbWJkYS9zcF9sYW1iZGEpICAlPiUgDQogIG11dGF0ZShkZWx0YV90YXVfaGF0ID0gIGZfYmV0YV9mdW4oZXhwKGJldGFfSyAqIGRlbHRhX3RhdV9hKSAqIChsYW1iZGFfcmF0aW8gXiAoMSAtIGdhbW1hKSkgKiBnX2JldGFfZnVuKHNwX2RlbHRhX3RhdSkpKSAlPiUgDQogIGdncGxvdCgpICsgDQogIGdlb21fbGluZShhZXModGEsIGRlbHRhX3RhdV9oYXQgKiBUayArIHRhLCBncm91cCA9IGhlYXRpbmdfcmF0ZSwgY29sID0gaGVhdGluZ19yYXRlKSkgKw0KICBsYWJzKHggPSBleHByZXNzaW9uKCJBY2NsaW1hdGlvbiB0ZW1wZXJhdHVyZSAoXHUwMEIwQykiKSwgDQogICAgICAgeSA9IGV4cHJlc3Npb24oIlVwcGVyIHRoZXJtYWwgdG9sZXJhbmNlIGxpbWl0IChcdTAwQjBDKSIpKSArDQogIHNjYWxlX2NvbG91cl92aXJpZGlzX2MobmFtZSA9IGV4cHJlc3Npb24oIkhlYXRpbmcgcmF0ZSAoXHUwMEIwQyBoIiBeLTEgKiAiKSIpLCB0cmFucyA9ICJsb2cxMCIsIGxhYmVscyA9IGZ1bmN0aW9uKHgpIHNpZ25pZih4KSkgDQpgYGANCg0KKioqDQojIE5vdGF0aW9uIHRhYmxlDQoNClRhYmxlOiAoXCN0YWI6bWF0aHMpIE1haW4gbWF0aGVtYXRpY2FsIG5vdGF0aW9uIGFuZCBkZXNjcmlwdGlvbiB1c2VkLg0KDQp8IFN5bWJvbCB8IERlc2NyaXB0aW9uIHwNCnw6LS0tLS0tOnw6LS0tLS0tLS0tLS0tfA0KfCAkSCQgfCBIZWF0aW5nIHRvbGVyYW5jZTsgcmFuZ2Ugb2YgdGVtcGVyYXR1cmVzIGJldHdlZW4gJFRfYSQgYW5kICRUX2MkCXwgDQp8ICRcRGVsdGEgdCQgfCBFbGFwc2VkIGR1cmF0aW9uIG9mIGEgaGVhdGluZyBhc3NheSBiZXR3ZWVuICR0X2EkIGFuZCAkdF9jJAl8DQp8ICRfciQgCXwgVmFyaWFibGVzIHJlc2NhbGVkIGJ5IHRoZSBVbml2ZXJzYWwgVGVtcGVyYXR1cmUgRGVwZW5kZW5jZQl8DQp8ICRfYSQgCXwgVmFyaWFibGVzIHJlZmVycmluZyB0byBhY2NsaW1hdGlvbiBvciBzdGFydGluZyB0ZW1wZXJhdHVyZSBvZiBhIGhlYXRpbmcgYXNzYXkJfA0KfCAkX2MkIAl8IFZhcmlhYmxlcyByZWZlcnJpbmcgdG8gdGhlIHVwcGVyIHRoZXJtYWwgdG9sZXJhbmNlIGxpbWl0IG9mIGEgaGVhdGluZyBhc3NheQl8DQp8ICRcdGF1JCB8IE5vcm1hbGlzZWQgdGVtcGVyYXR1cmUgc2NhbGUgY2VudHJlZCBhcm91bmQgJFRfSyQgKG5vcm1hbGlzYXRpb24gY29uc3RhbnQgYHIgVGtgSykgfCANCnwgJFxsYW1iZGEkIHwgTm9ybWFsaXNlZCBoZWF0aW5nIHJhdGUgY2VudHJlZCBhcm91bmQgJFRfSyQgfCANCnwgJFxnYW1tYSQgfCBTY2FsaW5nIGV4cG9uZW50IGZvciB0aGUgZWZmZWN0IG9mICRcbGFtYmRhJCBvbiAkXERlbHRhIHRfciQJfCANCg0KKioqDQoNCiMgTWFudXNjcmlwdCBGaWd1cmVzDQoNCmBgYHtyIGZpZ3MsIGV2YWw9RkFMU0V9DQojIHJlc2NhbGVkIGdyYXBocw0KbGVnZW5kIDwtIGdldF9sZWdlbmQoaGVhdGluZ19ncmFwaCArIHRoZW1lKGxlZ2VuZC5ib3gubWFyZ2luID0gbWFyZ2luKDAsIDAsIDAsIDApKSkNCg0KcDIgPC0gcGxvdF9ncmlkKGhlYXRpbmdfZ3JhcGggKyB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSwNCiAgICAgICAgICAgICAgICByZXNjYWxlZF9kdXJhdGlvbiArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpLA0KICAgICAgICAgICAgICAgICMgcmVzY2FsZWRfdG9sZXJhbmNlcyArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpLA0KICAgICAgICAgICAgICAgIGxhYmVscyA9ICJBVVRPIiwgbnJvdyA9IDEsIGFsaWduID0gImh2IiwgaGp1c3QgPSAtMSwgbGFiZWxfc2l6ZSA9IDEwKQ0KDQpmaWcyIDwtIHBsb3RfZ3JpZChwMiwgbGVnZW5kLCByZWxfd2lkdGhzID1jKDMsIDAuNSkpDQpmaWcyDQoNCiMgcHJlZGljdGlvbiBncmFwaHMNCnByZWRfaGlnaF9sb3cgPC0gcHJlZDMgKyBhZXMoY29sID0gaGVhdGluZ19yYXRlKSArIA0KICBzY2FsZV94X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApLCBsaW1pdHMgPSBjKDAsIDQwKSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApLCBsaW1pdHMgPSBjKDAsIDQwKSkgKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFLCBjb2wgPSAxKSArDQogIHNjYWxlX2NvbG91cl92aXJpZGlzX2MobmFtZSA9IGV4cHJlc3Npb24oIkhlYXRpbmcgcmF0ZSAoXHUwMEIwQyBoIiBeLTEgKiAiKSIpLCB0cmFucyA9ICJsb2cxMCIsIGxhYmVscyA9IGZ1bmN0aW9uKHgpIHNpZ25pZih4KSkgKw0KICBnZ3RpdGxlKCJQcmVkaWN0IGZyb20gbG93ZXIgYWNjbGltYXRpb24gdGVtcGVyYXR1cmUiKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpDQoNCnByZWRfbG93X2hpZ2ggPC0gcHJlZDQgKyBhZXMoY29sID0gaGVhdGluZ19yYXRlKSArIA0KICBzY2FsZV94X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApLCBsaW1pdHMgPSBjKDAsIDQwKSkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gYygwLDApLCBsaW1pdHMgPSBjKDAsIDQwKSkgKw0KICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFLCBjb2wgPSAxKSArDQogIHNjYWxlX2NvbG91cl92aXJpZGlzX2MobmFtZSA9IGV4cHJlc3Npb24oIkhlYXRpbmcgcmF0ZSAoXHUwMEIwQyBoIiBeLTEgKiAiKSIpLCB0cmFucyA9ICJsb2cxMCIsIGxhYmVscyA9IGZ1bmN0aW9uKHgpIHNpZ25pZih4KSkgKw0KICBnZ3RpdGxlKCJQcmVkaWN0IGZyb20gaGlnaGVyIGFjY2xpbWF0aW9uIHRlbXBlcmF0dXJlIikgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKQ0KDQpwMyA8LSBwbG90X2dyaWQocHJlZF9oaWdoX2xvdywgcHJlZF9sb3dfaGlnaCwgbGFiZWxzID0gIkFVVE8iLCBucm93ID0gMSwgYWxpZ24gPSAiaCIsIGhqdXN0ID0gLTEsIGxhYmVsX3NpemUgPSAxMCkNCmZpZzMgPC0gcGxvdF9ncmlkKHAzLCBsZWdlbmQsIHJlbF93aWR0aHMgPWMoMywgMC41KSkNCmZpZzMNCg0KIyBIZWF0aW5nIHJhdGUgZWZmZWN0DQpmaWc1IDwtIHBsb3RfZ3JpZChnX2RlcGFydHVyZSwgZ19zY2FsaW5nLCBnX3ByZWRpY3RfdGF1LCBsYWJlbHMgPSAiQVVUTyIsIG5yb3cgPSAxLCBhbGlnbiA9ICJoIiwgaGp1c3QgPSAtMSwgbGFiZWxfc2l6ZSA9IDEwKQ0KZmlnNQ0KYGBgDQoNCkZpZ3VyZXMgc2F2ZWQgYXMgVElGRi4gUmVzdWx0aW5nIGRhdGFzZXQgKGBBUlJgKSBzYXZlZCBhcyBDU1YuDQoNCmBgYHtyIHNhdmUsIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0V9DQpqb3VybmFsIDwtICJCaW9yaXZ4Ig0KZGlyLmNyZWF0ZShwYXN0ZTAoIi4uL2ZpZ3VyZXMvIiwgam91cm5hbCwgIi8iKSkNCg0KZm9yKGkgaW4gYygidGlmZiIsICJqcGVnIikpew0Kc2F2ZV9wbG90KHBsb3QgPSBmaWcyLCBmaWxlbmFtZSA9IHBhc3RlMCgiLi4vZmlndXJlcy8iLCBqb3VybmFsLCAiL2ZpZzIuIiwgaSksIGRwaSA9IDMwMCwgYmFzZV93aWR0aCA9IDEwLCBiZyA9ICJ3aGl0ZSIpDQpzYXZlX3Bsb3QocGxvdCA9IGZpZzMsIGZpbGVuYW1lID0gcGFzdGUwKCIuLi9maWd1cmVzLyIsIGpvdXJuYWwsICIvZmlnMy4iLCBpKSwgZHBpID0gMzAwLCBiYXNlX3dpZHRoID0gMTAsIGJnID0gIndoaXRlIikNCnNhdmVfcGxvdChwbG90ID0gZmlnNSwgZmlsZW5hbWUgPSBwYXN0ZTAoIi4uL2ZpZ3VyZXMvIiwgam91cm5hbCwgIi9maWc1LiIsIGkpLCBkcGkgPSAzMDAsIGJhc2Vfd2lkdGggPSA4LCBiYXNlX2hlaWdodCA9IDMsIGJnID0gIndoaXRlIikNCn0NCg0KIyBTdXBwbGVtZW50YXJ5DQpzYXZlX3Bsb3QocGxvdCA9IHNlbnNpX3Bsb3QsIGZpbGVuYW1lID0gcGFzdGUwKCIuLi9maWd1cmVzLyIsIGpvdXJuYWwsICIvZmlnUzEuanBlZyIpLCBkcGkgPSAzMDAsIGJhc2Vfd2lkdGggPSAxMCwgYmFzZV9oZWlnaHQgPSA1LCBiZyA9ICJ3aGl0ZSIpDQpzYXZlX3Bsb3QocGxvdCA9IHJlc2NhbGVkX3RvbGVyYW5jZXMsIGZpbGVuYW1lID0gcGFzdGUwKCIuLi9maWd1cmVzLyIsIGpvdXJuYWwsICIvZmlnUzIuanBlZyIpLCBkcGkgPSAzMDAsIGJnID0gIndoaXRlIikNCnNhdmVfcGxvdChwbG90ID0gcHJlZDEsIGZpbGVuYW1lID0gcGFzdGUwKCIuLi9maWd1cmVzLyIsIGpvdXJuYWwsICIvZmlnUzMuanBlZyIpLCBkcGkgPSAzMDAsIGJnID0gIndoaXRlIikNCnNhdmVfcGxvdChwbG90ID0gcHJlZDIsIGZpbGVuYW1lID0gcGFzdGUwKCIuLi9maWd1cmVzLyIsIGpvdXJuYWwsICIvZmlnUzQuanBlZyIpLCBkcGkgPSAzMDAsIGJnID0gIndoaXRlIikNCg0KIyBkYXRhDQojIHdyaXRlLmNzdihBUlIsIGZpbGUgPSAicmVzY2FsZWRfaGVhdGluZ190b2xlcmFuY2VzX2RhdGEuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpDQpgYGANCg0KKioqDQoNCiMgU2Vzc2lvbiBpbmZvDQpgYGB7ciBzZXNzaW9uLCBlY2hvPUZBTFNFfQ0Kc2Vzc2lvbkluZm8oKQ0KYGBgDQoNCioqKg0KDQojIFJlZmVyZW5jZXMNCg==