1 Introduction

1.1 About this document

This working document is the second step in evaluating various assessment models for the newly combined Plaice stock, across the Sub Divisions 21 - 32. In the first document ( Ple.27.3a.21-32_Assessments ), Some of the more fundamental decisions about input data were evaluated and decided upon. In this document, we focus in on an issue that is new to the stocks in this area, namely natural mortality. Because of the rapidly increasing density derived from consecutive years of high recruitment and low fishing pressure, we see decreasing stock weights at age, lengths at age and we anticipate increasing mortality across ages. This is especially true in the younger ages, where recent record breaking cohorts continue to top each other. In this document we investigate the different ways that these new estimations of mortality can be introduced to the model and the effect that this has on the model fit and predictive power.

Throughout the document, the code used to undertake each step precedes the output and can be accessed by clicking on the drop-down arrows to the right of the page.

Data compilation is done externally, and this document deals only with the finalised input files. All models are build using the State-Space Assessment Model (SAM), and in this version of the document, all model input files and configurations are downloaded directly from the publicly available versions on stockassessment.org.

1.2 Preparation

To run the scripts embedded in this document (if you would like to run the assessment yourself) you require the following packages and functions:

require(data.table)
require(reshape2)
require(knitr)
require(scales)
require(bookdown)
require(ggplot2)
require(ggthemes)
require(stringr)
require(lattice)
require(plyr)
require(plotly)
require(icesAdvice)
require("stockassessment")  # available from https://github.com/fishfollower/SAM
require(parallel)
require(sf)

myprop <- function(df, nomo = "nomo", NoAtLngt = "CANoAtLngt") {
    t <- sum(df$nomo)/sum(df$CANoAtLngt)
}

catchFrac <- function(x, nm, w, frac) {
    F <- getF(x)
    Z <- F + nm
    N <- getN(x)
    C <- F/Z * (1 - exp(-Z)) * N
    return(sum(frac * w * C))
}

We also need to set a the DataYear, which is the year immediately preceeding the assessment year or the year for which the most recent data is available.

DataYear <- 2023
LastIcesAdvice <- 21735  # Advised catch for areas 21-32 (from stock splitting table in advice)
isFinal <- FALSE
# isFinal <- TRUE

2 Baseline

In this working document, the baseline model was selected from the immediately preceding working document, titled: Ple.27.21-32_WKBPLAICE_Assessments.Rmd.

2.1 BioPar & Five Year Sliding Windows (Survey Variation)

This assessment combines two approaches to utilise the internal smoothing that SAM can do for biological data, while not over-parameterising the model. That is we utilise the biiopar smoothing for the more monotonic and faster changing stock-weights-at-age data, while we retain the simpler sliding window mean for the maturity ogives.

In preparing the input files, the sliding window mean simply averages the preceding x-1 years’ observations with each subsequent year to reduce the effect of annual variability. In this case x = 5, for a five year sliding window.

The biopar option is configured to treat all ages independently.

In this and all future iterations, we extended the time series to include the within-assessment year Q1 survey data.

2.1.1 Model Configuration

  • Survey age classes:
  • 1-7+
  • Coefficients of variation are integrated into model estimation of values and uncertainties.
  • Catches age classes:
  • 1-7+
  • Maturity ogives:
  • Five year sliding-mean starting with survey data from 1999 (with the first year repeated backwards to 1998) to inform data years 2002:2023.
  • Provided to SAM as “true” observations.
  • Combined sexes
  • Mean of weight at age in stock
  • Determined from survey observations (Q1 surveys)
  • Annually varying observations (2002:2023) fit within the model using “biopar” options.
  • Observation variance is coupled for ages 2 through 5.
  • Fbar
  • ages 3-5 (inclusive)
  • Natural Mortality
  • age 1 = 0.2
  • ages 2+ = 0.1 (assumed low due to low rates of otoliths in predator stomachs, but work is ongoing on this topic)
  • Fishing mortality is coupled for ages 6 + 7
  • Survey catchability is coupled for:
  • Q1 survey: ages 3 to 5
  • Q3/4 survey: ages 4 to 7
  • Correlation structure in the observations is
  • allowed to vary independently across ages, for for the catches and for the Q1 survey.
  • has an AR process applied across ages for the Q3/4 survey, with ages 1 & 2, 3 & 4, and 5 & 6 coupled as pairs.

2.1.2 Model Download

To run the model, we must first download the input data and configuration files from their public repository. The data in these files has been presented in another working document and in plenary, but in these downloads it has been reformatted to fit with SAM, commonly known as the Lowestoft, CEFAS, or xsa format.

# === Read in data and assign appropriate names ====
fit_bio_5y_SV = fitfromweb("ple.27.21-32_WKBPLAICE_2024_BioParsw_survCor")

# olco <- fit_bio_5y_SV$conf$keyStockWeightObsVar
# fit_bio_5y_SV$conf$keyStockWeightObsVar <- earlierKSOV
# fit_bio_5y_SV$conf$keyStockWeightObsVar <- olco

# olco <- fit_bio_5y_SV$conf$keyVarObs fit_bio_5y_SV$conf$keyVarObs <-
# earlierKVO fit_bio_5y_SV$conf$keyVarObs <- olco

# fit_bio_5y_SV <- stockassessment:::refit(fit_bio_5y_SV) =====

2.1.3 Model Results

2.1.3.1 Compared to Baseline Model

This section interrogates the model fit and generates tables and figures that describe the fit. In the background, these are saved to disk but also printed here for visibility in the rendered document.

Because we are using the BIOPAR option in SAM to smooth the input of annually varying stock weights at age, we can first investigate the result of this part of the fit.

## Extract SW Fits from the model object
sw_fits <- as.data.frame(exp(fit_bio_5y_SV$pl$logSW)[1:length(2002:(DataYear + 1)),
    ])
colnames(sw_fits) <- as.character(c(1:7))

sw_fits$year <- factor(as.character(c(2002:(DataYear + 1))), levels = as.character(c((2002:(DataYear +
    1)))))

sw_fitsL <- reshape(data = sw_fits, varying = as.character(c(1:7)), v.names = "swFits",
    timevar = "Age", times = as.character(c(1:7)), idvar = "year", direction = "long")

## Extract SDs from the fit
sw_SDs <- as.data.frame(exp(fit_bio_5y_SV$plsd$logSW)[1:length(2002:(DataYear + 1)),
    ])
colnames(sw_SDs) <- as.character(c(1:7))

sw_SDs$year <- factor(as.character(c(2002:(DataYear + 1))), levels = as.character(c((2002:(DataYear +
    1)))))

sw_SDsL <- reshape(data = sw_SDs, varying = as.character(c(1:7)), v.names = "swSDs",
    timevar = "Age", times = as.character(c(1:7)), idvar = "year", direction = "long")

## Extract SW observations from the model object
sw_obs <- as.data.frame(fit_bio_5y_SV$data$stockMeanWeight)[1:length(2002:(DataYear +
    1)), ]
colnames(sw_obs) <- as.character(c(1:7))

sw_obs$year <- factor(as.character(c(2002:(DataYear + 1))), levels = as.character(c((2002:(DataYear +
    1)))))

sw_obsL <- reshape(data = sw_obs, varying = as.character(c(1:7)), v.names = "swObs",
    timevar = "Age", times = as.character(c(1:7)), idvar = "year", direction = "long")

sw_mod <- merge(sw_fitsL, sw_SDsL, by = c("year", "Age"), all = TRUE)
sw_mod <- merge(sw_mod, sw_obsL, by = c("year", "Age"), all = TRUE)
sw_mod$year <- as.numeric(as.character(sw_mod$year))

ggplotly(ggplot(data = sw_mod) + geom_line(mapping = aes(x = year, y = swFits, colour = Age)) +
    geom_point(mapping = aes(x = year, y = swObs, colour = Age), shape = 21) + facet_wrap(. ~
    Age, scales = "free_y") + theme_few() + theme(axis.text.x = element_text(angle = 45,
    hjust = 1, vjust = 1)) + scale_x_continuous(breaks = function(x) pretty(x, n = 5)) +
    scale_color_manual(values = c(ebpal)) + scale_fill_manual(values = c(ebpal)) +
    guides(colour = "none", fill = "none"))

Figure 2.1: Fits to the stock weights at age, from the model with biopar on stock weights at age and sliding window on maturity. Annual observations are points, model fits are solid lines. Note the varying y axes.

The baseline assessment described first in this document, is now used as a comparison for the changes made in this version of the model.

# === Create dataframe of current year's fit for plotting ==== IC_agg_temp <-
# aggregate(CATON~Year, ic_clean[ic_clean$CatchCategory %in% c('Landings',
# 'Discards'), ], FUN = 'sum')
asum_bio_5y_SV <- as.data.frame(summary(fit_bio_5y_SV))
asum_bio_5y_SV$Year <- as.integer(row.names(summary(fit_bio_5y_SV)))
ct_bio_5y_SV <- as.data.frame(catchtable(fit_bio_5y_SV, obs.show = TRUE))
ct_bio_5y_SV$Year <- as.integer(rownames(ct_bio_5y_SV))
rownames(ct_bio_5y_SV) <- NULL
ct_bio_5y_SV <- rbind(ct_bio_5y_SV, data.frame(Estimate = NA, Low = NA, High = NA,
    sop.catch = NA, Year = as.integer(2024)))
asum_bio_5y_SV <- merge(x = asum_bio_5y_SV, y = ct_bio_5y_SV, by = "Year")
colnames(asum_bio_5y_SV) <- c("Year", "R_age1", "Rlow", "Rhigh", "SSB", "SSBlow",
    "SSBhigh", "Fbar", "Flow", "Fhigh", "CatchEst", "Catchlow", "Catchhigh", "CatchObs")
# =====

We can see in this model, as in the biopar model, that the changes in stock weights at age are probably reflected in the lower estimates of SSB, albeit with a higher interannual variability than is the case for the baseline model, which uses a fixed stock weight at age for all years.

# ssblines <- data.frame(yintercept=c(4730, 4370, 3635), Lines = factor(x =
# c('MSY-Btrigger', 'Bpa', 'Blim'),levels = c('MSY-Btrigger', 'Bpa', 'Blim')))
pssb <- ggplot() + geom_line(data = asum_bio_5y_SV, mapping = aes(x = Year, y = SSB),
    colour = ebpal[1]) + geom_ribbon(data = asum_bio_5y_SV, mapping = aes(x = Year,
    ymin = SSBlow, ymax = SSBhigh), fill = ebpal[1], alpha = 0.3) + theme_clean()

ggplotly(pssb)

Figure 2.2: Model with Biopar on SWA and five year SWM on MO (survey variation) estimated spawning stock biomass for ple.27.21-32 and point wise 95% confidence intervals are shown by line and shaded area (tonnes)

Fishing pressure over time seems to respond to the changes in the estimations of SSB, while input data for catches (obviously) remain the same betwen the two models.

# flines <- data.frame(yintercept=c(0.31, 0.81, 1.00), Lines = factor(x =
# c('FMSY', 'Fpa', 'Flim'), levels = c('FMSY', 'Fpa', 'Flim')))
ggplotly(ggplot() + geom_line(data = asum_bio_5y_SV, mapping = aes(x = Year, y = Fbar),
    colour = ebpal[1]) + geom_ribbon(data = asum_bio_5y_SV, mapping = aes(x = Year,
    ymin = Flow, ymax = Fhigh), fill = ebpal[1], alpha = 0.3) + theme_clean())

Figure 2.3: Model with Biopar on SWA and five year SWM on MO (survey variation) annual fishing mortality estimates for ple.27.21-32 ages 3-5 and point wise 95% confidence intervals are shown by line and shaded area.

Estimations of recruitment in the most recent years fall, as SSB also falls in this version of the model, again probably due to the reduction in stock weights at age.

ggplotly(ggplot() + geom_line(data = asum_bio_5y_SV, mapping = aes(x = Year, y = R_age1),
    colour = ebpal[1]) + geom_ribbon(data = asum_bio_5y_SV, mapping = aes(x = Year,
    ymin = Rlow, ymax = Rhigh), fill = ebpal[1], alpha = 0.3) + theme_clean())

Figure 2.4: Model with Biopar on SWA and five year SWM on MO (survey variation) annual recruitment estimates for ple.27.21-32 and point wise 95% confidence intervals are shown by line and shaded area (numbers).

ggplotly(ggplot() + geom_line(data = asum_bio_5y_SV[asum_bio_5y_SV$Year != (DataYear +
    1), ], mapping = aes(x = Year, y = CatchEst), colour = ebpal[1]) + geom_ribbon(data = asum_bio_5y_SV[asum_bio_5y_SV$Year !=
    (DataYear + 1), ], mapping = aes(x = Year, ymin = Catchlow, ymax = Catchhigh),
    fill = ebpal[1], alpha = 0.3) + geom_point(data = asum_bio_5y_SV[asum_bio_5y_SV$Year !=
    (DataYear + 1), ], mapping = aes(x = Year, y = CatchObs), shape = 3, colour = ebpal[11],
    fill = ebpal[11]) + ylab("Catch (tonnes)") + theme_clean())

Figure 2.5: Model with Biopar on SWA and five year SWM on MO (survey variation) annual catch estimates and 95% confidence intervals (line and shaded area, respectively) for ple.27.21-32 and point annual observations (points).

2.1.3.2 Other results from the Biopar/Five Year Sliding Window model

### Data Prep
F_bio_5y_SV <- as.data.frame(faytable(fit_bio_5y_SV))
F_bio_5y_SV$Year <- rownames(F_bio_5y_SV)
rownames(F_bio_5y_SV) <- NULL
F_bio_5y_SVLng <- melt(data = F_bio_5y_SV, id.vars = "Year", variable.name = "Age",
    value.name = "F_atAge")
F_bio_5y_SVLng$Year <- as.numeric(as.character(F_bio_5y_SVLng$Year))

### Plot
ggplotly(ggplot() + geom_line(data = F_bio_5y_SVLng, mapping = aes(x = Year, y = F_atAge,
    colour = Age)) + scale_color_manual(values = ebpal, ) + scale_x_continuous(breaks = unique(F_bio_5y_SVLng$Year)) +
    theme_few() + theme(axis.text.x = element_text(angle = 45)))

Figure 2.6: Partial F at age; Model with Biopar on SWA and five year SWM on MO (survey variation)

2.1.4 Model Fit

When the model is run we can easily see from warnings/errors if there is a convergence issue. However, we can also confirm this, explicitly: - The final model gradient: 135 - That there is a positive definite hessian: TRUE

Furthermore, SAM does not utilise “bounds” when fitting the model, and therefore, as standard check of whether model parameters are approaching their bounds is irrelevant.

We can investigate the variance around the different catch/stock components.

sdplot(fit_bio_5y_SV, marg = c(5, 4, 1, 1))
Standard Devations by Fleet; base model

Figure 2.7: Standard Devations by Fleet; base model

2.1.4.1 Residual Plots

Next we can look at how the model fits the observations per age in the different fleets.

## Extract data from model object
logObs_bio_5y_SV <- split(fit_bio_5y_SV$data$logobs, ceiling(seq_along(fit_bio_5y_SV$data$logobs)/fit_bio_5y_SV$data$maxAgePerFleet[1]))
logPred_bio_5y_SV <- split(fit_bio_5y_SV$rep$predObs, ceiling(seq_along(fit_bio_5y_SV$rep$predObs)/fit_bio_5y_SV$data$maxAgePerFleet[1]))

## Transform data to useable dataframes
### Initialize an empty data frame for observations
logObs_bio_5y_SV_df <- data.frame(age = integer(),
                                  fleet = integer(),
                                  year = integer(),
                                  logObs = numeric())

### Populate the data frame for observations
for (i in seq_along(logObs_bio_5y_SV)) {
  # Calculate the group and year
  year <- ((i - 1) %/% 3) + 1
  fleet <- ((i - 1) %% 3) + 1
  
  ### Create a temporary data frame and append to the main data frame for observations
  temp_df <- data.frame(age = 1:7,
                        fleet = fleet,
                        year = year+2001,
                        logObs = logObs_bio_5y_SV[[i]])
  logObs_bio_5y_SV_df <- rbind(logObs_bio_5y_SV_df, temp_df)
}

### Initialize an empty data frame for predictions
logPred_bio_5y_SV_df <- data.frame(age = integer(),
                                   fleet = integer(),
                                   year = integer(),
                                   logPred = numeric())

### Populate the data frame for predictions
for (i in seq_along(logPred_bio_5y_SV)) {
  # Calculate the group and year
  year <- ((i - 1) %/% 3) + 1
  fleet <- ((i - 1) %% 3) + 1
  
  ### Create a temporary data frame and append to the main data frame for predictions
  temp_df <- data.frame(age = 1:7,
                        fleet = fleet,
                        year = year+2001,
                        logPred = logPred_bio_5y_SV[[i]])
  logPred_bio_5y_SV_df <- rbind(logPred_bio_5y_SV_df, temp_df)
}

## Plot
logPred_bio_5y_SV_df$age <- as.character(logPred_bio_5y_SV_df$age)
logObs_bio_5y_SV_df$age <- as.character(logObs_bio_5y_SV_df$age)

ggplotly(ggplot()+
           geom_point(data = logObs_bio_5y_SV_df[logObs_bio_5y_SV_df$fleet == 1 & logObs_bio_5y_SV_df$year != (DataYear+1), ],
                      mapping = aes(x = year,
                                    y = logObs,
                                    colour = age),
                      shape = 21) +
           geom_line(data = logPred_bio_5y_SV_df[logPred_bio_5y_SV_df$fleet == 1 & logPred_bio_5y_SV_df$year != (DataYear+1), ],
                     mapping = aes(x = year,
                                   y = logPred,
                                   colour = age)) +
           facet_wrap(facets = "age") + #, scales = "free_y") +
           scale_color_manual(values = ebpal, guide = FALSE) +
           guides(colour=FALSE, shape=FALSE) +
           theme_few())

Figure 2.8: Model with Biopar on SWA and five year SWM on MO (survey variation) fit to catch data by age (values on the model link function scale).

# fitplot(fit_bio_5y_SV, fleets=1)
ggplotly(ggplot()+
           geom_point(data = logObs_bio_5y_SV_df[logObs_bio_5y_SV_df$fleet == 2 & logObs_bio_5y_SV_df$year != (DataYear+1), ],
                      mapping = aes(x = year,
                                    y = logObs,
                                    colour = age),
                      shape = 21) +
           geom_line(data = logPred_bio_5y_SV_df[logPred_bio_5y_SV_df$fleet == 2 & logPred_bio_5y_SV_df$year != (DataYear+1), ],
                     mapping = aes(x = year,
                                   y = logPred,
                                   colour = age)) +
           facet_wrap(facets = "age") + #, scales = "free_y") +
           scale_color_manual(values = ebpal, guide = FALSE) +
           guides(colour=FALSE, shape=FALSE) +
           theme_few())

Figure 2.9: Model with Biopar on SWA and five year SWM on MO (survey variation) fit to Q1 survey data by age (values on the model link function scale).

# fitplot(fit_bio_5y_SV, fleets=2)
ggplotly(ggplot()+
           geom_point(data = logObs_bio_5y_SV_df[logObs_bio_5y_SV_df$fleet == 3 & logObs_bio_5y_SV_df$year != (DataYear+1), ],
                      mapping = aes(x = year,
                                    y = logObs,
                                    colour = age),
                      shape = 21) +
           geom_line(data = logPred_bio_5y_SV_df[logPred_bio_5y_SV_df$fleet == 3 & logPred_bio_5y_SV_df$year != (DataYear+1), ],
                     mapping = aes(x = year,
                                   y = logPred,
                                   colour = age)) +
           facet_wrap(facets = "age") + #, scales = "free_y") +
           scale_color_manual(values = ebpal, guide = FALSE) +
           guides(colour=FALSE, shape=FALSE) +
           theme_few())

Figure 2.10: Model with Biopar on SWA and five year SWM on MO (survey variation) fit to Q3/4 survey data by age (values on the model link function scale).

# fitplot(fit_bio_5y_SV, fleets=3)

Now we can also calculate the residuals of our observations from our model.

resid_bio_5y_SV <- residuals(fit_bio_5y_SV)
resid_bio_5y_SV_df <- data.frame(year = resid_bio_5y_SV$year, fleet = resid_bio_5y_SV$fleet,
    age = resid_bio_5y_SV$age, observation = resid_bio_5y_SV$observation, mean = resid_bio_5y_SV$mean,
    residual = resid_bio_5y_SV$residual)
resid_bio_5y_SV_df$fleetName <- ifelse(resid_bio_5y_SV_df$fleet == 1, attributes(resid_bio_5y_SV)$fleetNames[1],
    ifelse(resid_bio_5y_SV_df$fleet == 2, attributes(resid_bio_5y_SV)$fleetNames[2],
        ifelse(resid_bio_5y_SV_df$fleet == 3, attributes(resid_bio_5y_SV)$fleetNames[3],
            NA)))

resid_bio_5y_SV_df$fleetAltName <- ifelse(resid_bio_5y_SV_df$fleet == 1, "Residual Fishing",
    ifelse(resid_bio_5y_SV_df$fleet == 2, "Q1 Surveys", ifelse(resid_bio_5y_SV_df$fleet ==
        3, "Q3/4 Surveys", NA)))

We can also look for patterns of correlation in the residuals, indicating unexplained trends. Ideally, there will be no large patterns, especially those weighted asymmetrically in the figures. For fleets where configuration allows for a correlation structure between ages, from year to year (i.e. Q3/4 surveys), this is especially important.

if (!all(fit_bio_5y_SV$conf$obsCorStruct == "ID")) {
    corplot(fit_bio_5y_SV)
    # setcap('Estimated correlations', 'Estimates correlations between age
    # groups for each fleet') stampit(fit)
} else {
    print("No correlation structure configured for residuals across age.")
}
Estimated correlations in residual variation between ages for each of the fishing fleet (top) and the two surveys (middle & bottom), from the bio_5y_SV model.

Figure 2.11: Estimated correlations in residual variation between ages for each of the fishing fleet (top) and the two surveys (middle & bottom), from the bio_5y_SV model.

ggplotly(ggplot(resid_bio_5y_SV_df) + geom_point(mapping = aes(x = year, y = age,
    size = abs(residual), colour = residual >= 0), alpha = 0.7) + facet_grid(rows = "fleetAltName") +
    scale_colour_manual(values = c(`TRUE` = ebpal[8], `FALSE` = ebpal[9])) + scale_y_continuous(limits = c(-1,
    9), breaks = c(1:9)) + guides(colour = FALSE) + theme_few())

Figure 2.12: One observation ahead residuals for the three fleets (red/pink = observation lower than model estimate, blue = observation higher than model estimate, size = magnitude of residual), from the Model with Biopar on SWA and five year SWM on MO (with survey variation).

2.1.4.2 Jittering

We can also test to see if the model is converging on some local minimum (i.e. it’s fitting to some solution close to initialising values that represents noise and not the global solution, that is the proper solution). To do this, we add random noise to the initial parameter values to see if the model will converge on a different minimum in it’s data-space. The easiest way to investigate this is to see if the model fits vary alot depending on the starting values:

jit_bio_5y_SV <- jit(fit = fit_bio_5y_SV)

mt <- as.data.frame(modeltable(jit_bio_5y_SV))
mt$model <- rownames(mt)
rownames(mt) <- NULL

kable(x = mt, digits = 3, caption = "Measures of  fit for a series of model refits with jitter applied to the input parameters.")
(#tab:Jitter_bio_5y_SV)Measures of fit for a series of model refits with jitter applied to the input parameters.
log(L) #par AIC model
-127.608 36 327.216 M1
-127.608 36 327.216 M2
-127.608 36 327.216 M3
-127.608 36 327.216 M4
-127.608 36 327.216 M5
-127.608 36 327.216 M6
-127.608 36 327.216 M7
-127.608 36 327.216 M8
-127.608 36 327.216 M9
-127.608 36 327.216 M10
-127.608 36 327.216 M11

2.1.4.3 Leave-One-Out Analyses

A leave-one-out analysis is a form of sensitivity analysis, showing the impact the data from each tuning fleet has on the estimation of the key variables being estimated; namely SSB, F and recruitment.

First we must run the leave-one-out analysis which refits the model in two iterations, removing one survey at a time. Then we can plot each of these new model fits over the full model to see the impact the removal of each has.

LO_bio_5y_SV <- leaveout(fit_bio_5y_SV)

# === Get data from sam objects and generate useable dataframes ====
q1mat <- as.data.frame(summary(LO_bio_5y_SV$`w.o. Q1IBTS+BITS+CodSD21-25`))
q3mat <- as.data.frame(summary(LO_bio_5y_SV$`w.o. Q34IBTS+BITS+CodSD21-25`))


woq1 <- data.frame(Year = as.integer(row.names(summary(LO_bio_5y_SV$`w.o. Q1IBTS+BITS+CodSD21-25`))),
    SSB = q1mat$SSB, Fbar = q1mat$`Fbar(3-5)`, R_age1 = q1mat$`R(age 1)`, CatchEst = catchtable(LO_bio_5y_SV$`w.o. Q1IBTS+BITS+CodSD21-25`)[,
        1], series = rep("wo_Q1", times = nrow(q1mat)))

woq34 <- data.frame(Year = as.integer(row.names(q3mat[(2002:DataYear) - 2001, ])),
    SSB = q3mat[(2002:DataYear) - 2001, "SSB"], Fbar = q3mat[(2002:DataYear) - 2001,
        "Fbar(3-5)"], R_age1 = q3mat[(2002:DataYear) - 2001, "R(age 1)"], CatchEst = catchtable(LO_bio_5y_SV$`w.o. Q34IBTS+BITS+CodSD21-25`)[,
        1], series = rep("wo_Q34", times = (nrow(q3mat) - 1)))


asum_bio_5y_SV$series <- rep("full", times = nrow(asum_bio_5y_SV))
asumi_bio_5y_SV <- asum_bio_5y_SV[, c("Year", "SSB", "Fbar", "R_age1", "CatchEst",
    "series")]
# =====

losum_bio_5y_SV <- rbind(woq1, woq34, asumi_bio_5y_SV)
# ssbplot(LO)
lossb_bio_5y_SV <- ggplotly(ggplot() + geom_line(data = losum_bio_5y_SV, mapping = aes(x = Year,
    y = SSB, colour = series)) + geom_ribbon(data = asum_bio_5y_SV, mapping = aes(x = Year,
    ymin = SSBlow, ymax = SSBhigh), fill = "black", alpha = 0.2) + scale_colour_manual(values = c("black",
    ebpal[8:9])) + theme_clean() + theme(axis.title.y.left = element_text(vjust = -0.05,
    hjust = 0.95)))

# Fplot(LO)
lof_bio_5y_SV <- ggplotly(ggplot() + geom_line(data = losum_bio_5y_SV, mapping = aes(x = Year,
    y = Fbar, colour = series)) + geom_ribbon(data = asum_bio_5y_SV, mapping = aes(x = Year,
    ymin = Flow, ymax = Fhigh), fill = "black", alpha = 0.3) + scale_colour_manual(values = c("black",
    ebpal[8:9])) + theme_clean() + theme(axis.title.y.left = element_text(vjust = -0.05,
    hjust = 0.95)))

# recplot(LO)
lorec_bio_5y_SV <- ggplotly(ggplot() + geom_line(data = losum_bio_5y_SV, mapping = aes(x = Year,
    y = R_age1, colour = series)) + geom_ribbon(data = asum_bio_5y_SV, mapping = aes(x = Year,
    ymin = Rlow, ymax = Rhigh), fill = "black", alpha = 0.3) + scale_colour_manual(values = c("black",
    ebpal[8:9])) + theme_clean() + theme(axis.title.y.left = element_text(vjust = -0.05,
    hjust = 0.95)))

# Catch plot (LO)
loca_bio_5y_SV <- ggplotly(ggplot() + geom_line(data = losum_bio_5y_SV, mapping = aes(x = Year,
    y = CatchEst, colour = series)) + geom_ribbon(data = asum_bio_5y_SV[asum_bio_5y_SV$Year !=
    (DataYear + 1), ], mapping = aes(x = Year, ymin = Catchlow, ymax = Catchhigh),
    fill = "black", alpha = 0.3) + geom_point(data = asum_bio_5y_SV[asum_bio_5y_SV$Year !=
    (DataYear + 1), ], mapping = aes(x = Year, y = CatchObs), shape = 3, colour = ebpal[5],
    fill = ebpal[5]) + ylab("Catch (tonnes)") + scale_colour_manual(values = c("black",
    ebpal[8:9])) + theme_clean() + theme(axis.title.y.left = element_text(vjust = -0.05,
    hjust = 0.95)))

layout(subplot(lossb_bio_5y_SV, lof_bio_5y_SV, lorec_bio_5y_SV, loca_bio_5y_SV, nrows = 2,
    shareX = TRUE, titleY = TRUE), showlegend = FALSE)

Figure 2.13: Leave-one-out re-fits for the Model with Biopar on SWA and five year SWM on MO (without Q1 = blue, without Q3/4 = purple), overlain with full model estimates (black line and grey ribbon) of SSB (top left), F (top right), Recruitment (bottom left), and catch (bottom right; observations as yellow +).

2.1.4.4 Retrospective Analyses

Another way to interrogate the model’s ability to fit to data is to change the input data. By dropping years sequentially from the latest year, backwards, and refitting the model to these data, we can visualise how this “tuned” model performs in different data situations.

In this case, our model fit included the within-assessement year Q1 survey index as a tuning fleet, therefore, we are doing the peels and calculating the Mohn’s rho on data truncated by one year, so that we aren’t judging the model fit with the year in which it doesn’t have catch data nor the second index.

RETRO_bio_5y_SV <- retro(fit_bio_5y_SV, year = 5)
rho_bio_5y_SV <- mohn(RETRO_bio_5y_SV, lag = 1)

## Make RETROs in better plotting format
ret_bio_5y_SV_df <- asum_bio_5y_SV[asum_bio_5y_SV$Year != max(asum_bio_5y_SV$Year),
    ]
ret_bio_5y_SV_df$series <- rep("full", nrow(ret_bio_5y_SV_df))

for (i in 1:length(RETRO_bio_5y_SV)) {
    tsum <- as.data.frame(summary(RETRO_bio_5y_SV[[i]]))
    tsum$Year <- as.integer(row.names(summary(RETRO_bio_5y_SV[[i]])))
    tsum <- cbind(tsum, catchtable(RETRO_bio_5y_SV[[i]], obs.show = TRUE))
    tsum$series <- as.character(rep(i, nrow(tsum)))
    colnames(tsum) <- c("R_age1", "Rlow", "Rhigh", "SSB", "SSBlow", "SSBhigh", "Fbar",
        "Flow", "Fhigh", "Year", "CatchEst", "Catchlow", "Catchhigh", "CatchObs",
        "series")
    tsum <- tsum[tsum$Year != max(tsum$Year), ]
    ret_bio_5y_SV_df <- rbind(ret_bio_5y_SV_df, tsum)
}
ret_bio_5y_SV_df$series <- factor(ret_bio_5y_SV_df$series, levels = c("full", "1",
    "2", "3", "4", "5"))
# ssbplot(RETRO)
retssb_bio_5y_SV <- layout(ggplotly(ggplot() + geom_line(data = ret_bio_5y_SV_df,
    mapping = aes(x = Year, y = SSB, colour = series)) + geom_ribbon(data = asum_bio_5y_SV[asum_bio_5y_SV$Year !=
    max(asum_bio_5y_SV$Year), ], mapping = aes(x = Year, ymin = SSBlow, ymax = SSBhigh),
    fill = "black", alpha = 0.2) + annotate(geom = "text", y = max(ret_bio_5y_SV_df$SSBhigh) *
    0.85, x = ((max(ret_bio_5y_SV_df$Year) - min(ret_bio_5y_SV_df$Year)) * 0.2) +
    min(ret_bio_5y_SV_df$Year), label = paste0("Mohn's Rho = ", round(rho_bio_5y_SV[2],
    digits = 3))) + scale_colour_manual(values = c("black", ebpal[(length(ebpal) -
    4):length(ebpal)])) + theme_clean() + theme(legend.position = "none", axis.title.y.left = element_text(vjust = -0.05,
    hjust = 0.95))), showlegend = FALSE)

# Fplot(RETRO)
retf_bio_5y_SV <- layout(ggplotly(ggplot() + geom_line(data = ret_bio_5y_SV_df, mapping = aes(x = Year,
    y = Fbar, colour = series)) + geom_ribbon(data = asum_bio_5y_SV[asum_bio_5y_SV$Year !=
    max(asum_bio_5y_SV$Year), ], mapping = aes(x = Year, ymin = Flow, ymax = Fhigh),
    fill = "black", alpha = 0.3) + annotate(geom = "text", y = max(ret_bio_5y_SV_df$Fhigh) *
    0.85, x = ((max(ret_bio_5y_SV_df$Year) - min(ret_bio_5y_SV_df$Year)) * 0.8) +
    min(ret_bio_5y_SV_df$Year), label = paste0("Mohn's Rho = ", round(rho_bio_5y_SV[3],
    digits = 3))) + scale_colour_manual(values = c("black", ebpal[(length(ebpal) -
    4):length(ebpal)])) + theme_clean() + theme(legend.position = "none", axis.title.y.left = element_text(vjust = -0.05,
    hjust = 0.95))), showlegend = FALSE)

# recplot(RETRO)
retrec_bio_5y_SV <- layout(ggplotly(ggplot() + geom_line(data = ret_bio_5y_SV_df,
    mapping = aes(x = Year, y = R_age1, colour = series)) + geom_ribbon(data = asum_bio_5y_SV[asum_bio_5y_SV$Year !=
    max(asum_bio_5y_SV$Year), ], mapping = aes(x = Year, ymin = Rlow, ymax = Rhigh),
    fill = "black", alpha = 0.3) + annotate(geom = "text", y = max(ret_bio_5y_SV_df$Rhigh) *
    0.85, x = ((max(ret_bio_5y_SV_df$Year) - min(ret_bio_5y_SV_df$Year)) * 0.2) +
    min(ret_bio_5y_SV_df$Year), label = paste0("Mohn's Rho = ", round(rho_bio_5y_SV[1],
    digits = 3))) + scale_colour_manual(values = c("black", ebpal[(length(ebpal) -
    4):length(ebpal)])) + theme_clean() + theme(legend.position = "none", axis.title.y.left = element_text(vjust = -0.05,
    hjust = 0.95))), showlegend = FALSE)

# Catch plot (RETRO)
retca_bio_5y_SV <- ggplotly(ggplot() + geom_line(data = ret_bio_5y_SV_df, mapping = aes(x = Year,
    y = CatchEst, colour = series)) + geom_ribbon(data = asum_bio_5y_SV[asum_bio_5y_SV$Year !=
    max(asum_bio_5y_SV$Year), ], mapping = aes(x = Year, ymin = Catchlow, ymax = Catchhigh),
    fill = "black", alpha = 0.3) + geom_point(data = asum_bio_5y_SV[asum_bio_5y_SV$Year !=
    max(asum_bio_5y_SV$Year), ], mapping = aes(x = Year, y = CatchObs), shape = 3,
    colour = ebpal[5], fill = ebpal[5]) + ylab("Catch (tonnes)") + scale_colour_manual(values = c("black",
    ebpal[(length(ebpal) - 4):length(ebpal)])) + theme_clean() + theme(axis.title.y.left = element_text(vjust = -0.05,
    hjust = 0.95)))

ret_fp <- style(subplot(retssb_bio_5y_SV, retf_bio_5y_SV, retrec_bio_5y_SV, retca_bio_5y_SV,
    nrows = 2, shareX = FALSE, shareY = FALSE, titleY = TRUE), showlegend = FALSE,
    traces = c(8:((7 * 4) + 2)))

layout(ret_fp, legend = list(orientation = "h", x = 0.5, xanchor = "center", y = -0.05,
    yanchor = "top", borderwidth = 0))

Figure 2.14: Retrospective analyses for SSB (top-left), F for ages 3-5 (top-right), recruitment (bottom-left), and catch (bottom-right), from the model utilising Biopar for SWA and five year sliding window means for maturity and survey indices’ coefficients of variaton.

2.1.5 Remarks about the Model with Biopar on SWA and five year SWM on MO (survey variation) Configuration

The combination of the biopar smoothing on the stock weights at age and the sliding window mean on the maturity ogives, results in more variability in SSB estimates, than the five year sliding window applied to both. The extension of the time series to include the Q1 survey from the in-assessment-year, leads to a higher SSB estimate in later years.

Large negative residuals in the most recent years, across most (sometimes all) ages and all fleets, are persistent across all options of model structure and model tuning. This suggests that there may be unexplained mortality in our model and that we may need to adjust the fixed natural mortality values that we’ve inherited from the previous two independent plaice stocks.

3 Models with New Natural Morality - Growth parameters from data

Based on discussion in the working group, the model that utilises SAM’s BioPar option for fitting to observed stock weights at age and a five year sliding window for the maturity ogives was selected to continue investigations.

However, like most other model runs, this model retains a lot of negative residuals in recent years, across all fleets, indicating that catches were below what was estimated for all fleets. This was concerning, as there appeared to be no basis in the data for the model estimations in the latest years. Based on this we decided to re-visit the inherited natural mortalities from the Ple.27.21-23 and Ple.27.24-32 stocks. These were time invariant and set to 0.2 for age 1, and 0.1 for all other ages.

In this section we change only the input values for the natural mortality and we do so based on three hypotheses: 1. That natural mortality is higher for younger ages and that it follows a general model elaborated by Gislason et al., 2010. a. this model is based on life-history parameters and size. b. this model is generally applicable across the whole time series. 2. That the shape of the decline in natural mortality with age from Gislason et al.’s model is correct, but that for the time invariant version of these natural mortalities, the absolute values may be different, due to un-calculated weighting in the numbers used to calculate the time-invariant mean. 3. That a Gislason model paramaterised by life-history traits collated across the whole time-series can be applied to annual length-at-age data to accurately produce time and age varying mortalities. a. these annually varying mortalities may be noisy due to noise in annual length samples, therefore a five-year sliding window mean is applied to them before input to SAM.

3.1 Time Invariant, Gislason Natural Mortality

3.1.1 Fits to data

fit_nmG <- fitfromweb("ple.27.21-32_WKBPLAICE_2024_BioParsw_SV_nmG")
# fit_nmG <- stockassessment:::refit(fit_nmG)
# === Create dataframe of current year's fit for plotting ==== IC_agg_temp <-
# aggregate(CATON~Year, ic_clean[ic_clean$CatchCategory %in% c('Landings',
# 'Discards'), ], FUN = 'sum')
asum_nmG <- as.data.frame(summary(fit_nmG))
asum_nmG$Year <- as.integer(row.names(summary(fit_nmG)))
ct_nmG <- as.data.frame(catchtable(fit_nmG, obs.show = TRUE))
ct_nmG$Year <- as.integer(rownames(ct_nmG))
rownames(ct_nmG) <- NULL
ct_nmG <- rbind(ct_nmG, data.frame(Estimate = NA, Low = NA, High = NA, sop.catch = NA,
    Year = as.integer(2024)))
asum_nmG <- merge(x = asum_nmG, y = ct_nmG, by = "Year")
colnames(asum_nmG) <- c("Year", "R_age1", "Rlow", "Rhigh", "SSB", "SSBlow", "SSBhigh",
    "Fbar", "Flow", "Fhigh", "CatchEst", "Catchlow", "Catchhigh", "CatchObs")
# =====

When the model is run we can easily see from warnings/errors if there is a convergence issue. However, we can also confirm this, explicitly: - The final model gradient: 131 - That there is a positive definite hessian: TRUE

Furthermore, SAM does not utilise “bounds” when fitting the model, and therefore, as standard check of whether model parameters are approaching their bounds is irrelevant.

Already with the new mortalities we see reduced directionality in the residuals for all fleets in recent years. Fits to observed catches also look much better.

## Extract data from model object
logObs_nmG <- split(fit_nmG$data$logobs, ceiling(seq_along(fit_nmG$data$logobs)/fit_nmG$data$maxAgePerFleet[1]))
logPred_nmG <- split(fit_nmG$rep$predObs, ceiling(seq_along(fit_nmG$rep$predObs)/fit_nmG$data$maxAgePerFleet[1]))

## Transform data to useable dataframes
### Initialize an empty data frame for observations
logObs_nmG_df <- data.frame(age = integer(),
                            fleet = integer(),
                            year = integer(),
                            logObs = numeric())

### Populate the data frame for observations
for (i in seq_along(logObs_nmG)) {
  # Calculate the group and year
  year <- ((i - 1) %/% 3) + 1
  fleet <- ((i - 1) %% 3) + 1
  
  ### Create a temporary data frame and append to the main data frame for observations
  temp_df <- data.frame(age = 1:7,
                        fleet = fleet,
                        year = year+2001,
                        logObs = logObs_nmG[[i]])
  logObs_nmG_df <- rbind(logObs_nmG_df, temp_df)
}

### Initialize an empty data frame for predictions
logPred_nmG_df <- data.frame(age = integer(),
                             fleet = integer(),
                             year = integer(),
                             logPred = numeric())

### Populate the data frame for predictions
for (i in seq_along(logPred_nmG)) {
  # Calculate the group and year
  year <- ((i - 1) %/% 3) + 1
  fleet <- ((i - 1) %% 3) + 1
  
  ### Create a temporary data frame and append to the main data frame for predictions
  temp_df <- data.frame(age = 1:7,
                        fleet = fleet,
                        year = year+2001,
                        logPred = logPred_nmG[[i]])
  logPred_nmG_df <- rbind(logPred_nmG_df, temp_df)
}

## Plot
logPred_nmG_df$age <- as.character(logPred_nmG_df$age)
logObs_nmG_df$age <- as.character(logObs_nmG_df$age)

ggplotly(ggplot()+
           geom_point(data = logObs_nmG_df[logObs_nmG_df$fleet == 1 & logObs_nmG_df$year != (DataYear+1), ],
                      mapping = aes(x = year,
                                    y = logObs,
                                    colour = age),
                      shape = 21) +
           geom_line(data = logPred_nmG_df[logPred_nmG_df$fleet == 1 & logPred_nmG_df$year != (DataYear+1), ],
                     mapping = aes(x = year,
                                   y = logPred,
                                   colour = age)) +
           facet_wrap(facets = "age") + #, scales = "free_y") +
           scale_color_manual(values = ebpal, guide = FALSE) +
           guides(colour=FALSE, shape=FALSE) +
           theme_few())

Figure 3.1: Model with time invariant Gislason natural mortalities fit to catch data by age (values on the model link function scale).

# fitplot(fit_nmG, fleets=1)
ggplotly(ggplot()+
           geom_point(data = logObs_nmG_df[logObs_nmG_df$fleet == 2 & logObs_nmG_df$year != (DataYear+1), ],
                      mapping = aes(x = year,
                                    y = logObs,
                                    colour = age),
                      shape = 21) +
           geom_line(data = logPred_nmG_df[logPred_nmG_df$fleet == 2 & logPred_nmG_df$year != (DataYear+1), ],
                     mapping = aes(x = year,
                                   y = logPred,
                                   colour = age)) +
           facet_wrap(facets = "age") + #, scales = "free_y") +
           scale_color_manual(values = ebpal, guide = FALSE) +
           guides(colour=FALSE, shape=FALSE) +
           theme_few())

Figure 3.2: Model with time invariant Gislason natural mortalities fit to Q1 survey data by age (values on the model link function scale).

# fitplot(fit_nmG, fleets=2)
ggplotly(ggplot()+
           geom_point(data = logObs_nmG_df[logObs_nmG_df$fleet == 3 & logObs_nmG_df$year != (DataYear+1), ],
                      mapping = aes(x = year,
                                    y = logObs,
                                    colour = age),
                      shape = 21) +
           geom_line(data = logPred_nmG_df[logPred_nmG_df$fleet == 3 & logPred_nmG_df$year != (DataYear+1), ],
                     mapping = aes(x = year,
                                   y = logPred,
                                   colour = age)) +
           facet_wrap(facets = "age") + #, scales = "free_y") +
           scale_color_manual(values = ebpal, guide = FALSE) +
           guides(colour=FALSE, shape=FALSE) +
           theme_few())

Figure 3.3: Model with time invariant Gislason natural mortalities fit to Q3/4 survey data by age (values on the model link function scale).

# fitplot(fit_nmG, fleets=3)
sdplot(fit_nmG, marg = c(5, 4, 1, 1))
Standard Devations by Fleet; Gislason, time-invariant mortality

Figure 3.4: Standard Devations by Fleet; Gislason, time-invariant mortality

3.1.2 Residuals

resid_nmG <- residuals(fit_nmG)
resid_nmG_df <- data.frame(year = resid_nmG$year, fleet = resid_nmG$fleet, age = resid_nmG$age,
    observation = resid_nmG$observation, mean = resid_nmG$mean, residual = resid_nmG$residual)
resid_nmG_df$fleetName <- ifelse(resid_nmG_df$fleet == 1, attributes(resid_nmG)$fleetNames[1],
    ifelse(resid_nmG_df$fleet == 2, attributes(resid_nmG)$fleetNames[2], ifelse(resid_nmG_df$fleet ==
        3, attributes(resid_nmG)$fleetNames[3], NA)))

resid_nmG_df$fleetAltName <- ifelse(resid_nmG_df$fleet == 1, "Residual Fishing",
    ifelse(resid_nmG_df$fleet == 2, "Q1 Surveys", ifelse(resid_nmG_df$fleet == 3,
        "Q3/4 Surveys", NA)))
if (!all(fit_nmG$conf$obsCorStruct == "ID")) {
    corplot(fit_nmG)
    # setcap('Estimated correlations', 'Estimates correlations between age
    # groups for each fleet') stampit(fit)
} else {
    print("No correlation structure configured for residuals across age.")
}
Estimated correlations in residual variation between ages for each of the fishing fleet (top) and the two surveys (middle & bottom), from the model with time invariant Gislason natural mortalities.

Figure 3.5: Estimated correlations in residual variation between ages for each of the fishing fleet (top) and the two surveys (middle & bottom), from the model with time invariant Gislason natural mortalities.

ggplotly(ggplot(resid_nmG_df) + geom_point(mapping = aes(x = year, y = age, size = abs(residual),
    colour = residual >= 0), alpha = 0.7) + facet_grid(rows = "fleetAltName") + scale_colour_manual(values = c(`TRUE` = ebpal[8],
    `FALSE` = ebpal[9])) + scale_y_continuous(limits = c(-1, 9), breaks = c(1:9)) +
    guides(colour = FALSE) + theme_few())

Figure 3.6: One observation ahead residuals for the three fleets (red/pink = observation lower than model estimate, blue = observation higher than model estimate, size = magnitude of residual), from the model with time invariant Gislason natural mortalities.

3.1.2.1 Jittering

We can also test to see if the model is converging on some local minimum (i.e. it’s fitting to some solution close to initialising values that represents noise and not the global solution, that is the proper solution). To do this, we add random noise to the initial parameter values to see if the model will converge on a different minimum in it’s data-space. The easiest way to investigate this is to see if the model fits vary alot depending on the starting values:

jit_nmG <- jit(fit = fit_nmG)

mt <- as.data.frame(modeltable(jit_nmG))
mt$model <- rownames(mt)
rownames(mt) <- NULL

kable(x = mt, digits = 3, caption = "Measures of  fit for a series of model refits with jitter applied to the input parameters.")
(#tab:Jitter_nmG)Measures of fit for a series of model refits with jitter applied to the input parameters.
log(L) #par AIC model
-97.153 36 266.306 M1
-97.153 36 266.306 M2
-97.153 36 266.306 M3
-97.153 36 266.306 M4
-97.153 36 266.306 M5
-97.153 36 266.306 M6
-97.153 36 266.306 M7
-97.153 36 266.306 M8
-97.153 36 266.306 M9
-97.153 36 266.306 M10
-97.153 36 266.306 M11

3.1.2.2 Leave-One-Out Analyses

A leave-one-out analysis is a form of sensitivity analysis, showing the impact the data from each tuning fleet has on the estimation of the key variables being estimated; namely SSB, F and recruitment.

First we must run the leave-one-out analysis which refits the model in two iterations, removing one survey at a time. Then we can plot each of these new model fits over the full model to see the impact the removal of each has.

LO_nmG <- leaveout(fit_nmG)

# === Get data from sam objects and generate useable dataframes ====
q1mat <- as.data.frame(summary(LO_nmG$`w.o. Q1IBTS+BITS+CodSD21-25`))
q3mat <- as.data.frame(summary(LO_nmG$`w.o. Q34IBTS+BITS+CodSD21-25`))


woq1 <- data.frame(Year = as.integer(row.names(summary(LO_nmG$`w.o. Q1IBTS+BITS+CodSD21-25`))),
    SSB = q1mat$SSB, Fbar = q1mat$`Fbar(3-5)`, R_age1 = q1mat$`R(age 1)`, CatchEst = catchtable(LO_nmG$`w.o. Q1IBTS+BITS+CodSD21-25`)[,
        1], series = rep("wo_Q1", times = nrow(q1mat)))

woq34 <- data.frame(Year = as.integer(row.names(q3mat[(2002:DataYear) - 2001, ])),
    SSB = q3mat[(2002:DataYear) - 2001, "SSB"], Fbar = q3mat[(2002:DataYear) - 2001,
        "Fbar(3-5)"], R_age1 = q3mat[(2002:DataYear) - 2001, "R(age 1)"], CatchEst = catchtable(LO_nmG$`w.o. Q34IBTS+BITS+CodSD21-25`)[,
        1], series = rep("wo_Q34", times = (nrow(q3mat) - 1)))


asum_nmG$series <- rep("full", times = nrow(asum_nmG))
asumi_nmG <- asum_nmG[, c("Year", "SSB", "Fbar", "R_age1", "CatchEst", "series")]
# =====

losum_nmG <- rbind(woq1, woq34, asumi_nmG)
# ssbplot(LO)
lossb_nmG <- ggplotly(ggplot() + geom_line(data = losum_nmG, mapping = aes(x = Year,
    y = SSB, colour = series)) + geom_ribbon(data = asum_nmG, mapping = aes(x = Year,
    ymin = SSBlow, ymax = SSBhigh), fill = "black", alpha = 0.2) + scale_colour_manual(values = c("black",
    ebpal[8:9])) + theme_clean() + theme(axis.title.y.left = element_text(vjust = -0.05,
    hjust = 0.95)))

# Fplot(LO)
lof_nmG <- ggplotly(ggplot() + geom_line(data = losum_nmG, mapping = aes(x = Year,
    y = Fbar, colour = series)) + geom_ribbon(data = asum_nmG, mapping = aes(x = Year,
    ymin = Flow, ymax = Fhigh), fill = "black", alpha = 0.3) + scale_colour_manual(values = c("black",
    ebpal[8:9])) + theme_clean() + theme(axis.title.y.left = element_text(vjust = -0.05,
    hjust = 0.95)))

# recplot(LO)
lorec_nmG <- ggplotly(ggplot() + geom_line(data = losum_nmG, mapping = aes(x = Year,
    y = R_age1, colour = series)) + geom_ribbon(data = asum_nmG, mapping = aes(x = Year,
    ymin = Rlow, ymax = Rhigh), fill = "black", alpha = 0.3) + scale_colour_manual(values = c("black",
    ebpal[8:9])) + theme_clean() + theme(axis.title.y.left = element_text(vjust = -0.05,
    hjust = 0.95)))

# Catch plot (LO)
loca_nmG <- ggplotly(ggplot() + geom_line(data = losum_nmG, mapping = aes(x = Year,
    y = CatchEst, colour = series)) + geom_ribbon(data = asum_nmG[asum_nmG$Year !=
    (DataYear + 1), ], mapping = aes(x = Year, ymin = Catchlow, ymax = Catchhigh),
    fill = "black", alpha = 0.3) + geom_point(data = asum_nmG[asum_nmG$Year != (DataYear +
    1), ], mapping = aes(x = Year, y = CatchObs), shape = 3, colour = ebpal[5], fill = ebpal[5]) +
    ylab("Catch (tonnes)") + scale_colour_manual(values = c("black", ebpal[8:9])) +
    theme_clean() + theme(axis.title.y.left = element_text(vjust = -0.05, hjust = 0.95)))

layout(subplot(lossb_nmG, lof_nmG, lorec_nmG, loca_nmG, nrows = 2, shareX = TRUE,
    titleY = TRUE), showlegend = FALSE)

Figure 3.7: Leave-one-out re-fits for the Time invariant, Gislason natural mortalities (without Q1 survey = blue, without Q3/4 survey = purple), overlain with full model estimates (black line and grey ribbon) of SSB (top left), F (top right), Recruitment (bottom left), and catch (bottom right; observations as yellow +).

3.1.3 Retrospectives

# === Create dataframe of current year's fit for plotting ==== IC_agg_temp <-
# aggregate(CATON~Year, ic_clean[ic_clean$CatchCategory %in% c('Landings',
# 'Discards'), ], FUN = 'sum')
asum_nmG <- as.data.frame(summary(fit_nmG))
asum_nmG$Year <- as.integer(row.names(summary(fit_nmG)))
ct_nmG <- as.data.frame(catchtable(fit_nmG, obs.show = TRUE))
ct_nmG$Year <- as.integer(rownames(ct_nmG))
rownames(ct_nmG) <- NULL
ct_nmG <- rbind(ct_nmG, data.frame(Estimate = NA, Low = NA, High = NA, sop.catch = NA,
    Year = as.integer(2024)))
asum_nmG <- merge(x = asum_nmG, y = ct_nmG, by = "Year")
colnames(asum_nmG) <- c("Year", "R_age1", "Rlow", "Rhigh", "SSB", "SSBlow", "SSBhigh",
    "Fbar", "Flow", "Fhigh", "CatchEst", "Catchlow", "Catchhigh", "CatchObs")

asum_nmG$series <- rep("full", times = nrow(asum_nmG))

# =====
RETRO_nmG <- retro(fit_nmG, year = 5)
rho_nmG <- mohn(RETRO_nmG, lag = 1)

## Make RETROs in better plotting format
ret_nmG_df <- asum_nmG[asum_nmG$Year != max(asum_nmG$Year), ]

for (i in 1:length(RETRO_nmG)) {
    tsum <- as.data.frame(summary(RETRO_nmG[[i]]))
    tsum$Year <- as.integer(row.names(summary(RETRO_nmG[[i]])))
    tsum <- cbind(tsum, catchtable(RETRO_nmG[[i]], obs.show = TRUE))
    tsum$series <- as.character(rep(i, nrow(tsum)))
    colnames(tsum) <- c("R_age1", "Rlow", "Rhigh", "SSB", "SSBlow", "SSBhigh", "Fbar",
        "Flow", "Fhigh", "Year", "CatchEst", "Catchlow", "Catchhigh", "CatchObs",
        "series")
    tsum <- tsum[tsum$Year != max(tsum$Year), ]
    ret_nmG_df <- rbind(ret_nmG_df, tsum)
}
ret_nmG_df$series <- factor(ret_nmG_df$series, levels = c("full", "1", "2", "3",
    "4", "5"))
# ssbplot(RETRO)
retssb_nmG <- layout(ggplotly(ggplot() + geom_line(data = ret_nmG_df, mapping = aes(x = Year,
    y = SSB, colour = series)) + geom_ribbon(data = asum_nmG[asum_nmG$Year != max(asum_nmG$Year),
    ], mapping = aes(x = Year, ymin = SSBlow, ymax = SSBhigh), fill = "black", alpha = 0.2) +
    annotate(geom = "text", y = max(ret_nmG_df$SSBhigh) * 0.85, x = ((max(ret_nmG_df$Year) -
        min(ret_nmG_df$Year)) * 0.2) + min(ret_nmG_df$Year), label = paste0("Mohn's Rho = ",
        round(rho_nmG[2], digits = 3))) + scale_colour_manual(values = c("black",
    ebpal[(length(ebpal) - 4):length(ebpal)])) + theme_clean() + theme(legend.position = "none",
    axis.title.y.left = element_text(vjust = -0.05, hjust = 0.95))), showlegend = FALSE)

# Fplot(RETRO)
retf_nmG <- layout(ggplotly(ggplot() + geom_line(data = ret_nmG_df, mapping = aes(x = Year,
    y = Fbar, colour = series)) + geom_ribbon(data = asum_nmG[asum_nmG$Year != max(asum_nmG$Year),
    ], mapping = aes(x = Year, ymin = Flow, ymax = Fhigh), fill = "black", alpha = 0.3) +
    annotate(geom = "text", y = max(ret_nmG_df$Fhigh) * 0.85, x = ((max(ret_nmG_df$Year) -
        min(ret_nmG_df$Year)) * 0.8) + min(ret_nmG_df$Year), label = paste0("Mohn's Rho = ",
        round(rho_nmG[3], digits = 3))) + scale_colour_manual(values = c("black",
    ebpal[(length(ebpal) - 4):length(ebpal)])) + theme_clean() + theme(legend.position = "none",
    axis.title.y.left = element_text(vjust = -0.05, hjust = 0.95))), showlegend = FALSE)

# recplot(RETRO)
retrec_nmG <- layout(ggplotly(ggplot() + geom_line(data = ret_nmG_df, mapping = aes(x = Year,
    y = R_age1, colour = series)) + geom_ribbon(data = asum_nmG[asum_nmG$Year !=
    max(asum_nmG$Year), ], mapping = aes(x = Year, ymin = Rlow, ymax = Rhigh), fill = "black",
    alpha = 0.3) + annotate(geom = "text", y = max(ret_nmG_df$Rhigh) * 0.85, x = ((max(ret_nmG_df$Year) -
    min(ret_nmG_df$Year)) * 0.2) + min(ret_nmG_df$Year), label = paste0("Mohn's Rho = ",
    round(rho_nmG[1], digits = 3))) + scale_colour_manual(values = c("black", ebpal[(length(ebpal) -
    4):length(ebpal)])) + theme_clean() + theme(legend.position = "none", axis.title.y.left = element_text(vjust = -0.05,
    hjust = 0.95))), showlegend = FALSE)

# Catch plot (RETRO)
retca_nmG <- ggplotly(ggplot() + geom_line(data = ret_nmG_df, mapping = aes(x = Year,
    y = CatchEst, colour = series)) + geom_ribbon(data = asum_nmG[asum_nmG$Year !=
    max(asum_nmG$Year), ], mapping = aes(x = Year, ymin = Catchlow, ymax = Catchhigh),
    fill = "black", alpha = 0.3) + geom_point(data = asum_nmG[asum_nmG$Year != max(asum_nmG$Year),
    ], mapping = aes(x = Year, y = CatchObs), shape = 3, colour = ebpal[5], fill = ebpal[5]) +
    ylab("Catch (tonnes)") + scale_colour_manual(values = c("black", ebpal[(length(ebpal) -
    4):length(ebpal)])) + theme_clean() + theme(axis.title.y.left = element_text(vjust = -0.05,
    hjust = 0.95)))

ret_fp <- style(subplot(retssb_nmG, retf_nmG, retrec_nmG, retca_nmG, nrows = 2, shareX = FALSE,
    shareY = FALSE, titleY = TRUE), showlegend = FALSE, traces = c(8:((7 * 4) + 2)))

layout(ret_fp, legend = list(orientation = "h", x = 0.5, xanchor = "center", y = -0.05,
    yanchor = "top", borderwidth = 0))

Figure 3.8: Retrospective analyses for SSB (top-left), F for ages 3-5 (top-right), recruitment (bottom-left), and catch (bottom-right), from the model utilising time invariant, Gislason natural mortalities.

3.2 Scaled, Time Invariant, Gislason Natural mortalities

3.2.1 Scaling and optimising

# === Scale natural mortality by a range of multipliers ====
profs = list()
nm = fit_nmG$data$natMor
mults = seq(0.1, 2, by = 0.1)

## Re-fit to scaled mortalities
for (mult in mults) {

    fit_nmG$data$natMor = nm * mult

    profs[[as.character(mult)]] = stockassessment:::refit(fit_nmG, silent = TRUE)
}
# ====
# === Aggregate AIC values and plot results ====
ll = sapply(profs, AIC)
plot(mults, ll)
Likelihood profile of scaled time invariant, Gislason natural mortalities. Y-axis = AIC, x-axis = scaling factor on nm.

Figure 3.9: Likelihood profile of scaled time invariant, Gislason natural mortalities. Y-axis = AIC, x-axis = scaling factor on nm.

# ====

We can now investigate if averaging the Gislason natural mortalities over the time series creates some scaling issues by ignoring weightings of numbers of observations contributing to each annual estimate. To partially address this we can investigate scaling these time invariant values up and down, to find where the best fit of this “shape” of natural mortalities across ages is.

By scaling the nm values up and down across a range of multipliers from 0.1 to 2, in increments of 0.1, we create 20 different runs from which we can compare AIC values. Here we find that a scaling value of 1.2 is responsible for the optimum model fit.

3.2.2 Investigating the scaled model

Therefore, below we investigate the model fit and residuals for a model with the Gislason, time invariant mortalities at age that have been scaled by a factor of 1.2 across all ages.

fit_nmGS <- fitfromweb("ple.27.21-32_WKBPLAICE_2024_BioParsw_nmG_S")
# === Create dataframe of current year's fit for plotting ==== IC_agg_temp <-
# aggregate(CATON~Year, ic_clean[ic_clean$CatchCategory %in% c('Landings',
# 'Discards'), ], FUN = 'sum')
asum_nmGS <- as.data.frame(summary(fit_nmGS))
asum_nmGS$Year <- as.integer(row.names(summary(fit_nmGS)))
ct_nmGS <- as.data.frame(catchtable(fit_nmGS, obs.show = TRUE))
ct_nmGS$Year <- as.integer(rownames(ct_nmGS))
rownames(ct_nmGS) <- NULL
ct_nmGS <- rbind(ct_nmGS, data.frame(Estimate = NA, Low = NA, High = NA, sop.catch = NA,
    Year = as.integer(2024)))
asum_nmGS <- merge(x = asum_nmGS, y = ct_nmGS, by = "Year")
colnames(asum_nmGS) <- c("Year", "R_age1", "Rlow", "Rhigh", "SSB", "SSBlow", "SSBhigh",
    "Fbar", "Flow", "Fhigh", "CatchEst", "Catchlow", "Catchhigh", "CatchObs")
# =====

3.2.2.1 Fits to data

When the model is run we can easily see from warnings/errors if there is a convergence issue. However, we can also confirm this, explicitly: - The final model gradient: 141 - That there is a positive definite hessian: TRUE

Furthermore, SAM does not utilise “bounds” when fitting the model, and therefore, as standard check of whether model parameters are approaching their bounds is irrelevant.

## Extract data from model object
logObs_nmGS <- split(fit_nmGS$data$logobs, ceiling(seq_along(fit_nmGS$data$logobs)/fit_nmGS$data$maxAgePerFleet[1]))
logPred_nmGS <- split(fit_nmGS$rep$predObs, ceiling(seq_along(fit_nmGS$rep$predObs)/fit_nmGS$data$maxAgePerFleet[1]))

## Transform data to useable dataframes
### Initialize an empty data frame for observations
logObs_nmGS_df <- data.frame(age = integer(),
                             fleet = integer(),
                             year = integer(),
                             logObs = numeric())

### Populate the data frame for observations
for (i in seq_along(logObs_nmGS)) {
  # Calculate the group and year
  year <- ((i - 1) %/% 3) + 1
  fleet <- ((i - 1) %% 3) + 1
  
  ### Create a temporary data frame and append to the main data frame for observations
  temp_df <- data.frame(age = 1:7,
                        fleet = fleet,
                        year = year+2001,
                        logObs = logObs_nmGS[[i]])
  logObs_nmGS_df <- rbind(logObs_nmGS_df, temp_df)
}

### Initialize an empty data frame for predictions
logPred_nmGS_df <- data.frame(age = integer(),
                              fleet = integer(),
                              year = integer(),
                              logPred = numeric())

### Populate the data frame for predictions
for (i in seq_along(logPred_nmGS)) {
  # Calculate the group and year
  year <- ((i - 1) %/% 3) + 1
  fleet <- ((i - 1) %% 3) + 1
  
  ### Create a temporary data frame and append to the main data frame for predictions
  temp_df <- data.frame(age = 1:7,
                        fleet = fleet,
                        year = year+2001,
                        logPred = logPred_nmGS[[i]])
  logPred_nmGS_df <- rbind(logPred_nmGS_df, temp_df)
}

## Plot
logPred_nmGS_df$age <- as.character(logPred_nmGS_df$age)
logObs_nmGS_df$age <- as.character(logObs_nmGS_df$age)

ggplotly(ggplot()+
           geom_point(data = logObs_nmGS_df[logObs_nmGS_df$fleet == 1 & logObs_nmGS_df$year != (DataYear+1), ],
                      mapping = aes(x = year,
                                    y = logObs,
                                    colour = age),
                      shape = 21) +
           geom_line(data = logPred_nmGS_df[logPred_nmGS_df$fleet == 1 & logPred_nmGS_df$year != (DataYear+1), ],
                     mapping = aes(x = year,
                                   y = logPred,
                                   colour = age)) +
           facet_wrap(facets = "age") + #, scales = "free_y") +
           scale_color_manual(values = ebpal, guide = FALSE) +
           guides(colour=FALSE, shape=FALSE) +
           theme_few())

Figure 3.10: Model with SCALED time invariant Gislason natural mortalities fit to catch data by age (values on the model link function scale).

# fitplot(fit_nmGS, fleets=1)
ggplotly(ggplot()+
           geom_point(data = logObs_nmGS_df[logObs_nmGS_df$fleet == 2 & logObs_nmGS_df$year != (DataYear+1), ],
                      mapping = aes(x = year,
                                    y = logObs,
                                    colour = age),
                      shape = 21) +
           geom_line(data = logPred_nmGS_df[logPred_nmGS_df$fleet == 2 & logPred_nmGS_df$year != (DataYear+1), ],
                     mapping = aes(x = year,
                                   y = logPred,
                                   colour = age)) +
           facet_wrap(facets = "age") + #, scales = "free_y") +
           scale_color_manual(values = ebpal, guide = FALSE) +
           guides(colour=FALSE, shape=FALSE) +
           theme_few())

Figure 3.11: Model with SCALED time invariant Gislason natural mortalities fit to Q1 survey data by age (values on the model link function scale).

# fitplot(fit_nmGS, fleets=2)
ggplotly(ggplot()+
           geom_point(data = logObs_nmGS_df[logObs_nmGS_df$fleet == 3 & logObs_nmGS_df$year != (DataYear+1), ],
                      mapping = aes(x = year,
                                    y = logObs,
                                    colour = age),
                      shape = 21) +
           geom_line(data = logPred_nmGS_df[logPred_nmGS_df$fleet == 3 & logPred_nmGS_df$year != (DataYear+1), ],
                     mapping = aes(x = year,
                                   y = logPred,
                                   colour = age)) +
           facet_wrap(facets = "age") + #, scales = "free_y") +
           scale_color_manual(values = ebpal, guide = FALSE) +
           guides(colour=FALSE, shape=FALSE) +
           theme_few())

Figure 3.12: Model with SCALED time invariant Gislason natural mortalities fit to Q3/4 survey data by age (values on the model link function scale).

# fitplot(fit_nmGS, fleets=3)
sdplot(fit_nmGS, marg = c(5, 4, 1, 1))
Standard Devations by Fleet; Gislason, scaled, time-invariant mortality

Figure 3.13: Standard Devations by Fleet; Gislason, scaled, time-invariant mortality

3.2.2.2 Residuals

resid_nmGS <- residuals(fit_nmGS)
resid_nmGS_df <- data.frame(year = resid_nmGS$year, fleet = resid_nmGS$fleet, age = resid_nmGS$age,
    observation = resid_nmGS$observation, mean = resid_nmGS$mean, residual = resid_nmGS$residual)
resid_nmGS_df$fleetName <- ifelse(resid_nmGS_df$fleet == 1, attributes(resid_nmGS)$fleetNames[1],
    ifelse(resid_nmGS_df$fleet == 2, attributes(resid_nmGS)$fleetNames[2], ifelse(resid_nmGS_df$fleet ==
        3, attributes(resid_nmGS)$fleetNames[3], NA)))

resid_nmGS_df$fleetAltName <- ifelse(resid_nmGS_df$fleet == 1, "Residual Fishing",
    ifelse(resid_nmGS_df$fleet == 2, "Q1 Surveys", ifelse(resid_nmGS_df$fleet ==
        3, "Q3/4 Surveys", NA)))
if (!all(fit_nmGS$conf$obsCorStruct == "ID")) {
    corplot(fit_nmGS)
    # setcap('Estimated correlations', 'Estimates correlations between age
    # groups for each fleet') stampit(fit)
} else {
    print("No correlation structure configured for residuals across age.")
}
Estimated correlations in residual variation between ages for each of the fishing fleet (top) and the two surveys (middle & bottom), from the Model with SCALED time invariant Gislason natural mortalities.

Figure 3.14: Estimated correlations in residual variation between ages for each of the fishing fleet (top) and the two surveys (middle & bottom), from the Model with SCALED time invariant Gislason natural mortalities.

ggplotly(ggplot(resid_nmGS_df) + geom_point(mapping = aes(x = year, y = age, size = abs(residual),
    colour = residual >= 0), alpha = 0.7) + facet_grid(rows = "fleetAltName") + scale_colour_manual(values = c(`TRUE` = ebpal[8],
    `FALSE` = ebpal[9])) + scale_y_continuous(limits = c(-1, 9), breaks = c(1:9)) +
    guides(colour = FALSE) + theme_few())

Figure 3.15: One observation ahead residuals for the three fleets (red/pink = observation lower than model estimate, blue = observation higher than model estimate, size = magnitude of residual), from the Model with SCALED time invariant Gislason natural mortalities.

3.2.2.3 Jittering

We can also test to see if the model is converging on some local minimum (i.e. it’s fitting to some solution close to initialising values that represents noise and not the global solution, that is the proper solution). To do this, we add random noise to the initial parameter values to see if the model will converge on a different minimum in it’s data-space. The easiest way to investigate this is to see if the model fits vary alot depending on the starting values:

jit_nmGS <- jit(fit = fit_nmGS)

mt <- as.data.frame(modeltable(jit_nmGS))
mt$model <- rownames(mt)
rownames(mt) <- NULL

kable(x = mt, digits = 3, caption = "Measures of  fit for a series of model refits with jitter applied to the input parameters.")
(#tab:Jitter_nmGS)Measures of fit for a series of model refits with jitter applied to the input parameters.
log(L) #par AIC model
-95.067 36 262.133 M1
-95.067 36 262.133 M2
-95.067 36 262.133 M3
-95.067 36 262.133 M4
-95.067 36 262.133 M5
-95.067 36 262.133 M6
-95.067 36 262.133 M7
-95.067 36 262.133 M8
-95.067 36 262.133 M9
-95.067 36 262.133 M10
-95.067 36 262.133 M11

3.2.2.4 Leave-One-Out Analyses

A leave-one-out analysis is a form of sensitivity analysis, showing the impact the data from each tuning fleet has on the estimation of the key variables being estimated; namely SSB, F and recruitment.

First we must run the leave-one-out analysis which refits the model in two iterations, removing one survey at a time. Then we can plot each of these new model fits over the full model to see the impact the removal of each has.

LO_nmGS <- leaveout(fit_nmGS)

# === Get data from sam objects and generate useable dataframes ====
q1mat <- as.data.frame(summary(LO_nmGS$`w.o. Q1IBTS+BITS+CodSD21-25`))
q3mat <- as.data.frame(summary(LO_nmGS$`w.o. Q34IBTS+BITS+CodSD21-25`))


woq1 <- data.frame(Year = as.integer(row.names(summary(LO_nmGS$`w.o. Q1IBTS+BITS+CodSD21-25`))),
    SSB = q1mat$SSB, Fbar = q1mat$`Fbar(3-5)`, R_age1 = q1mat$`R(age 1)`, CatchEst = catchtable(LO_nmGS$`w.o. Q1IBTS+BITS+CodSD21-25`)[,
        1], series = rep("wo_Q1", times = nrow(q1mat)))

woq34 <- data.frame(Year = as.integer(row.names(q3mat[(2002:DataYear) - 2001, ])),
    SSB = q3mat[(2002:DataYear) - 2001, "SSB"], Fbar = q3mat[(2002:DataYear) - 2001,
        "Fbar(3-5)"], R_age1 = q3mat[(2002:DataYear) - 2001, "R(age 1)"], CatchEst = catchtable(LO_nmGS$`w.o. Q34IBTS+BITS+CodSD21-25`)[,
        1], series = rep("wo_Q34", times = (nrow(q3mat) - 1)))


asum_nmGS$series <- rep("full", times = nrow(asum_nmGS))
asumi_nmGS <- asum_nmGS[, c("Year", "SSB", "Fbar", "R_age1", "CatchEst", "series")]
# =====

losum_nmGS <- rbind(woq1, woq34, asumi_nmGS)
# ssbplot(LO)
lossb_nmGS <- ggplotly(ggplot() + geom_line(data = losum_nmGS, mapping = aes(x = Year,
    y = SSB, colour = series)) + geom_ribbon(data = asum_nmGS, mapping = aes(x = Year,
    ymin = SSBlow, ymax = SSBhigh), fill = "black", alpha = 0.2) + scale_colour_manual(values = c("black",
    ebpal[8:9])) + theme_clean() + theme(axis.title.y.left = element_text(vjust = -0.05,
    hjust = 0.95)))

# Fplot(LO)
lof_nmGS <- ggplotly(ggplot() + geom_line(data = losum_nmGS, mapping = aes(x = Year,
    y = Fbar, colour = series)) + geom_ribbon(data = asum_nmGS, mapping = aes(x = Year,
    ymin = Flow, ymax = Fhigh), fill = "black", alpha = 0.3) + scale_colour_manual(values = c("black",
    ebpal[8:9])) + theme_clean() + theme(axis.title.y.left = element_text(vjust = -0.05,
    hjust = 0.95)))

# recplot(LO)
lorec_nmGS <- ggplotly(ggplot() + geom_line(data = losum_nmGS, mapping = aes(x = Year,
    y = R_age1, colour = series)) + geom_ribbon(data = asum_nmGS, mapping = aes(x = Year,
    ymin = Rlow, ymax = Rhigh), fill = "black", alpha = 0.3) + scale_colour_manual(values = c("black",
    ebpal[8:9])) + theme_clean() + theme(axis.title.y.left = element_text(vjust = -0.05,
    hjust = 0.95)))

# Catch plot (LO)
loca_nmGS <- ggplotly(ggplot() + geom_line(data = losum_nmGS, mapping = aes(x = Year,
    y = CatchEst, colour = series)) + geom_ribbon(data = asum_nmGS[asum_nmGS$Year !=
    (DataYear + 1), ], mapping = aes(x = Year, ymin = Catchlow, ymax = Catchhigh),
    fill = "black", alpha = 0.3) + geom_point(data = asum_nmGS[asum_nmGS$Year !=
    (DataYear + 1), ], mapping = aes(x = Year, y = CatchObs), shape = 3, colour = ebpal[5],
    fill = ebpal[5]) + ylab("Catch (tonnes)") + scale_colour_manual(values = c("black",
    ebpal[8:9])) + theme_clean() + theme(axis.title.y.left = element_text(vjust = -0.05,
    hjust = 0.95)))

layout(subplot(lossb_nmGS, lof_nmGS, lorec_nmGS, loca_nmGS, nrows = 2, shareX = TRUE,
    titleY = TRUE), showlegend = FALSE)

Figure 3.16: Leave-one-out re-fits for the Time invariant, scaled, Gislason natural mortalities (without Q1 survey = blue, without Q3/4 survey = purple), overlain with full model estimates (black line and grey ribbon) of SSB (top left), F (top right), Recruitment (bottom left), and catch (bottom right; observations as yellow +).

3.2.2.5 Retrospectives

# === Create dataframe of current year's fit for plotting ==== IC_agg_temp <-
# aggregate(CATON~Year, ic_clean[ic_clean$CatchCategory %in% c('Landings',
# 'Discards'), ], FUN = 'sum')
asum_nmGS <- as.data.frame(summary(fit_nmGS))
asum_nmGS$Year <- as.integer(row.names(summary(fit_nmGS)))
ct_nmGS <- as.data.frame(catchtable(fit_nmGS, obs.show = TRUE))
ct_nmGS$Year <- as.integer(rownames(ct_nmGS))
rownames(ct_nmGS) <- NULL
ct_nmGS <- rbind(ct_nmGS, data.frame(Estimate = NA, Low = NA, High = NA, sop.catch = NA,
    Year = as.integer(2024)))
asum_nmGS <- merge(x = asum_nmGS, y = ct_nmGS, by = "Year")
colnames(asum_nmGS) <- c("Year", "R_age1", "Rlow", "Rhigh", "SSB", "SSBlow", "SSBhigh",
    "Fbar", "Flow", "Fhigh", "CatchEst", "Catchlow", "Catchhigh", "CatchObs")

asum_nmGS$series <- rep("full", times = nrow(asum_nmGS))

# =====
RETRO_nmGS <- retro(fit_nmGS, year = 5)
rho_nmGS <- mohn(RETRO_nmGS, lag = 1)

## Make RETROs in better plotting format
ret_nmGS_df <- asum_nmGS[asum_nmGS$Year != max(asum_nmGS$Year), ]

for (i in 1:length(RETRO_nmGS)) {
    tsum <- as.data.frame(summary(RETRO_nmGS[[i]]))
    tsum$Year <- as.integer(row.names(summary(RETRO_nmGS[[i]])))
    tsum <- cbind(tsum, catchtable(RETRO_nmGS[[i]], obs.show = TRUE))
    tsum$series <- as.character(rep(i, nrow(tsum)))
    colnames(tsum) <- c("R_age1", "Rlow", "Rhigh", "SSB", "SSBlow", "SSBhigh", "Fbar",
        "Flow", "Fhigh", "Year", "CatchEst", "Catchlow", "Catchhigh", "CatchObs",
        "series")
    tsum <- tsum[tsum$Year != max(tsum$Year), ]
    ret_nmGS_df <- rbind(ret_nmGS_df, tsum)
}
ret_nmGS_df$series <- factor(ret_nmGS_df$series, levels = c("full", "1", "2", "3",
    "4", "5"))
# ssbplot(RETRO)
retssb_nmGS <- layout(ggplotly(ggplot() + geom_line(data = ret_nmGS_df, mapping = aes(x = Year,
    y = SSB, colour = series)) + geom_ribbon(data = asum_nmGS[asum_nmGS$Year != max(asum_nmGS$Year),
    ], mapping = aes(x = Year, ymin = SSBlow, ymax = SSBhigh), fill = "black", alpha = 0.2) +
    annotate(geom = "text", y = max(ret_nmGS_df$SSBhigh) * 0.85, x = ((max(ret_nmGS_df$Year) -
        min(ret_nmGS_df$Year)) * 0.2) + min(ret_nmGS_df$Year), label = paste0("Mohn's Rho = ",
        round(rho_nmGS[2], digits = 3))) + scale_colour_manual(values = c("black",
    ebpal[(length(ebpal) - 4):length(ebpal)])) + theme_clean() + theme(legend.position = "none",
    axis.title.y.left = element_text(vjust = -0.05, hjust = 0.95))), showlegend = FALSE)

# Fplot(RETRO)
retf_nmGS <- layout(ggplotly(ggplot() + geom_line(data = ret_nmGS_df, mapping = aes(x = Year,
    y = Fbar, colour = series)) + geom_ribbon(data = asum_nmGS[asum_nmGS$Year !=
    max(asum_nmGS$Year), ], mapping = aes(x = Year, ymin = Flow, ymax = Fhigh), fill = "black",
    alpha = 0.3) + annotate(geom = "text", y = max(ret_nmGS_df$Fhigh) * 0.85, x = ((max(ret_nmGS_df$Year) -
    min(ret_nmGS_df$Year)) * 0.8) + min(ret_nmGS_df$Year), label = paste0("Mohn's Rho = ",
    round(rho_nmGS[3], digits = 3))) + scale_colour_manual(values = c("black", ebpal[(length(ebpal) -
    4):length(ebpal)])) + theme_clean() + theme(legend.position = "none", axis.title.y.left = element_text(vjust = -0.05,
    hjust = 0.95))), showlegend = FALSE)

# recplot(RETRO)
retrec_nmGS <- layout(ggplotly(ggplot() + geom_line(data = ret_nmGS_df, mapping = aes(x = Year,
    y = R_age1, colour = series)) + geom_ribbon(data = asum_nmGS[asum_nmGS$Year !=
    max(asum_nmGS$Year), ], mapping = aes(x = Year, ymin = Rlow, ymax = Rhigh), fill = "black",
    alpha = 0.3) + annotate(geom = "text", y = max(ret_nmGS_df$Rhigh) * 0.85, x = ((max(ret_nmGS_df$Year) -
    min(ret_nmGS_df$Year)) * 0.2) + min(ret_nmGS_df$Year), label = paste0("Mohn's Rho = ",
    round(rho_nmGS[1], digits = 3))) + scale_colour_manual(values = c("black", ebpal[(length(ebpal) -
    4):length(ebpal)])) + theme_clean() + theme(legend.position = "none", axis.title.y.left = element_text(vjust = -0.05,
    hjust = 0.95))), showlegend = FALSE)

# Catch plot (RETRO)
retca_nmGS <- ggplotly(ggplot() + geom_line(data = ret_nmGS_df, mapping = aes(x = Year,
    y = CatchEst, colour = series)) + geom_ribbon(data = asum_nmGS[asum_nmGS$Year !=
    max(asum_nmGS$Year), ], mapping = aes(x = Year, ymin = Catchlow, ymax = Catchhigh),
    fill = "black", alpha = 0.3) + geom_point(data = asum_nmGS[asum_nmGS$Year !=
    max(asum_nmGS$Year), ], mapping = aes(x = Year, y = CatchObs), shape = 3, colour = ebpal[5],
    fill = ebpal[5]) + ylab("Catch (tonnes)") + scale_colour_manual(values = c("black",
    ebpal[(length(ebpal) - 4):length(ebpal)])) + theme_clean() + theme(axis.title.y.left = element_text(vjust = -0.05,
    hjust = 0.95)))

ret_fp <- style(subplot(retssb_nmGS, retf_nmGS, retrec_nmGS, retca_nmGS, nrows = 2,
    shareX = FALSE, shareY = FALSE, titleY = TRUE), showlegend = FALSE, traces = c(8:((7 *
    4) + 2)))

layout(ret_fp, legend = list(orientation = "h", x = 0.5, xanchor = "center", y = -0.05,
    yanchor = "top", borderwidth = 0))

Figure 3.17: Retrospective analyses for SSB (top-left), F for ages 3-5 (top-right), recruitment (bottom-left), and catch (bottom-right), from the model utilising SCALED time invariant, Gislason natural mortalities.

3.3 Time and Age Variant, Gislason Natural Mortalities

An alternate way to dealing with the issue of taking the unweighted means over the time series is to not use the full time-series means. While the life-history parameters \(L_{\infty}\) and \(K\) are calculated from all ages observations (q1 surveys) for the whole time series, they can be applied in the Gislason model to specific years, by utilising the lengths at age for each year. Due to the sampling rates these data will be inherently noisey, just as is the case for the stock weights at age and the maturity ogives, hence we need some method of smoothing out this noise. In this example we utilise a five-year sliding window mean on the annual estimates of natural mortality at age, to allow mortality at age to vary in time without introducing too much interannual variation.

fit_nmG5ysw <- fitfromweb("ple.27.21-32_WKBPLAICE_2024_BioParsw_nmG5ysw")
# === Create dataframe of current year's fit for plotting ====
asum_nmG5ysw <- as.data.frame(summary(fit_nmG5ysw))
asum_nmG5ysw$Year <- as.integer(row.names(summary(fit_nmG5ysw)))
ct_nmG5ysw <- as.data.frame(catchtable(fit_nmG5ysw, obs.show = TRUE))
ct_nmG5ysw$Year <- as.integer(rownames(ct_nmG5ysw))
rownames(ct_nmG5ysw) <- NULL
ct_nmG5ysw <- rbind(ct_nmG5ysw, data.frame(Estimate = NA, Low = NA, High = NA, sop.catch = NA,
    Year = as.integer(2024)))
asum_nmG5ysw <- merge(x = asum_nmG5ysw, y = ct_nmG5ysw, by = "Year")
colnames(asum_nmG5ysw) <- c("Year", "R_age1", "Rlow", "Rhigh", "SSB", "SSBlow", "SSBhigh",
    "Fbar", "Flow", "Fhigh", "CatchEst", "Catchlow", "Catchhigh", "CatchObs")
# =====

3.3.1 Fits to data

When the model is run we can easily see from warnings/errors if there is a convergence issue. However, we can also confirm this, explicitly: - The final model gradient: 137 - That there is a positive definite hessian: TRUE

Furthermore, SAM does not utilise “bounds” when fitting the model, and therefore, as standard check of whether model parameters are approaching their bounds is irrelevant.

## Extract data from model object
logObs_nmG5ysw <- split(fit_nmG5ysw$data$logobs, ceiling(seq_along(fit_nmG5ysw$data$logobs)/fit_nmG5ysw$data$maxAgePerFleet[1]))
logPred_nmG5ysw <- split(fit_nmG5ysw$rep$predObs, ceiling(seq_along(fit_nmG5ysw$rep$predObs)/fit_nmG5ysw$data$maxAgePerFleet[1]))

## Transform data to useable dataframes
### Initialize an empty data frame for observations
logObs_nmG5ysw_df <- data.frame(age = integer(),
                                fleet = integer(),
                                year = integer(),
                                logObs = numeric())

### Populate the data frame for observations
for (i in seq_along(logObs_nmG5ysw)) {
  # Calculate the group and year
  year <- ((i - 1) %/% 3) + 1
  fleet <- ((i - 1) %% 3) + 1
  
  ### Create a temporary data frame and append to the main data frame for observations
  temp_df <- data.frame(age = 1:7,
                        fleet = fleet,
                        year = year+2001,
                        logObs = logObs_nmG5ysw[[i]])
  logObs_nmG5ysw_df <- rbind(logObs_nmG5ysw_df, temp_df)
}

### Initialize an empty data frame for predictions
logPred_nmG5ysw_df <- data.frame(age = integer(),
                                 fleet = integer(),
                                 year = integer(),
                                 logPred = numeric())

### Populate the data frame for predictions
for (i in seq_along(logPred_nmG5ysw)) {
  # Calculate the group and year
  year <- ((i - 1) %/% 3) + 1
  fleet <- ((i - 1) %% 3) + 1
  
  ### Create a temporary data frame and append to the main data frame for predictions
  temp_df <- data.frame(age = 1:7,
                        fleet = fleet,
                        year = year+2001,
                        logPred = logPred_nmG5ysw[[i]])
  logPred_nmG5ysw_df <- rbind(logPred_nmG5ysw_df, temp_df)
}

## Plot
logPred_nmG5ysw_df$age <- as.character(logPred_nmG5ysw_df$age)
logObs_nmG5ysw_df$age <- as.character(logObs_nmG5ysw_df$age)

ggplotly(ggplot()+
           geom_point(data = logObs_nmG5ysw_df[logObs_nmG5ysw_df$fleet == 1 & logObs_nmG5ysw_df$year != (DataYear+1), ],
                      mapping = aes(x = year,
                                    y = logObs,
                                    colour = age),
                      shape = 21) +
           geom_line(data = logPred_nmG5ysw_df[logPred_nmG5ysw_df$fleet == 1 & logPred_nmG5ysw_df$year != (DataYear+1), ],
                     mapping = aes(x = year,
                                   y = logPred,
                                   colour = age)) +
           facet_wrap(facets = "age") + #, scales = "free_y") +
           scale_color_manual(values = ebpal, guide = FALSE) +
           guides(colour=FALSE, shape=FALSE) +
           theme_few())

Figure 3.18: Model with time varying (five year sliiding window mean), age varying, Gislason natural mortalities fit to catch data by age (values on the model link function scale).

# fitplot(fit_nmG5ysw, fleets=1)
ggplotly(ggplot()+
           geom_point(data = logObs_nmG5ysw_df[logObs_nmG5ysw_df$fleet == 2 & logObs_nmG5ysw_df$year != (DataYear+1), ],
                      mapping = aes(x = year,
                                    y = logObs,
                                    colour = age),
                      shape = 21) +
           geom_line(data = logPred_nmG5ysw_df[logPred_nmG5ysw_df$fleet == 2 & logPred_nmG5ysw_df$year != (DataYear+1), ],
                     mapping = aes(x = year,
                                   y = logPred,
                                   colour = age)) +
           facet_wrap(facets = "age") + #, scales = "free_y") +
           scale_color_manual(values = ebpal, guide = FALSE) +
           guides(colour=FALSE, shape=FALSE) +
           theme_few())

Figure 3.19: Model with time varying (five year sliiding window mean), age varying, Gislason natural mortalities fit to Q1 survey data by age (values on the model link function scale).

# fitplot(fit_nmG5ysw, fleets=2)
ggplotly(ggplot()+
           geom_point(data = logObs_nmG5ysw_df[logObs_nmG5ysw_df$fleet == 3 & logObs_nmG5ysw_df$year != (DataYear+1), ],
                      mapping = aes(x = year,
                                    y = logObs,
                                    colour = age),
                      shape = 21) +
           geom_line(data = logPred_nmG5ysw_df[logPred_nmG5ysw_df$fleet == 3 & logPred_nmG5ysw_df$year != (DataYear+1), ],
                     mapping = aes(x = year,
                                   y = logPred,
                                   colour = age)) +
           facet_wrap(facets = "age") + #, scales = "free_y") +
           scale_color_manual(values = ebpal, guide = FALSE) +
           guides(colour=FALSE, shape=FALSE) +
           theme_few())

Figure 3.20: Model with time varying (five year sliiding window mean), age varying, Gislason natural mortalities fit to Q3/4 survey data by age (values on the model link function scale).

# fitplot(fit_nmG5ysw, fleets=3)
sdplot(fit_nmG5ysw, marg = c(5, 4, 1, 1))
Standard Devations by Fleet; Gislason, time-variant mortality

Figure 3.21: Standard Devations by Fleet; Gislason, time-variant mortality

3.3.2 Residuals

resid_nmG5ysw <- residuals(fit_nmG5ysw)
resid_nmG5ysw_df <- data.frame(year = resid_nmG5ysw$year, fleet = resid_nmG5ysw$fleet,
    age = resid_nmG5ysw$age, observation = resid_nmG5ysw$observation, mean = resid_nmG5ysw$mean,
    residual = resid_nmG5ysw$residual)
resid_nmG5ysw_df$fleetName <- ifelse(resid_nmG5ysw_df$fleet == 1, attributes(resid_nmG5ysw)$fleetNames[1],
    ifelse(resid_nmG5ysw_df$fleet == 2, attributes(resid_nmG5ysw)$fleetNames[2],
        ifelse(resid_nmG5ysw_df$fleet == 3, attributes(resid_nmG5ysw)$fleetNames[3],
            NA)))

resid_nmG5ysw_df$fleetAltName <- ifelse(resid_nmG5ysw_df$fleet == 1, "Residual Fishing",
    ifelse(resid_nmG5ysw_df$fleet == 2, "Q1 Surveys", ifelse(resid_nmG5ysw_df$fleet ==
        3, "Q3/4 Surveys", NA)))
if (!all(fit_nmG5ysw$conf$obsCorStruct == "ID")) {
    corplot(fit_nmG5ysw)
    # setcap('Estimated correlations', 'Estimates correlations between age
    # groups for each fleet') stampit(fit)
} else {
    print("No correlation structure configured for residuals across age.")
}
Estimated correlations in residual variation between ages for each of the fishing fleet (top) and the two surveys (middle & bottom), from the Model with time varying (five year sliiding window mean), age varying, Gislason natural mortalities.

Figure 3.22: Estimated correlations in residual variation between ages for each of the fishing fleet (top) and the two surveys (middle & bottom), from the Model with time varying (five year sliiding window mean), age varying, Gislason natural mortalities.

ggplotly(ggplot(resid_nmG5ysw_df) + geom_point(mapping = aes(x = year, y = age, size = abs(residual),
    colour = residual >= 0), alpha = 0.7) + facet_grid(rows = "fleetAltName") + scale_colour_manual(values = c(`TRUE` = ebpal[8],
    `FALSE` = ebpal[9])) + scale_y_continuous(limits = c(-1, 9), breaks = c(1:9)) +
    guides(colour = FALSE) + theme_few())

Figure 3.23: One observation ahead residuals for the three fleets (red/pink = observation lower than model estimate, blue = observation higher than model estimate, size = magnitude of residual), from the Model with time varying (five year sliiding window mean), age varying, Gislason natural mortalities.

3.3.2.1 Jittering

We can also test to see if the model is converging on some local minimum (i.e. it’s fitting to some solution close to initialising values that represents noise and not the global solution, that is the proper solution). To do this, we add random noise to the initial parameter values to see if the model will converge on a different minimum in it’s data-space. The easiest way to investigate this is to see if the model fits vary alot depending on the starting values:

jit_nmG5ysw <- jit(fit = fit_nmG5ysw)

mt <- as.data.frame(modeltable(jit_nmG5ysw))
mt$model <- rownames(mt)
rownames(mt) <- NULL

kable(x = mt, digits = 3, caption = "Measures of  fit for a series of model refits with jitter applied to the input parameters.")
(#tab:Jitter_nmG5ysw)Measures of fit for a series of model refits with jitter applied to the input parameters.
log(L) #par AIC model
-95.445 36 262.89 M1
-95.445 36 262.89 M2
-95.445 36 262.89 M3
-95.445 36 262.89 M4
-95.445 36 262.89 M5
-95.445 36 262.89 M6
-95.445 36 262.89 M7
-95.445 36 262.89 M8
-95.445 36 262.89 M9
-95.445 36 262.89 M10
-95.445 36 262.89 M11

3.3.2.2 Leave-One-Out Analyses

A leave-one-out analysis is a form of sensitivity analysis, showing the impact the data from each tuning fleet has on the estimation of the key variables being estimated; namely SSB, F and recruitment.

First we must run the leave-one-out analysis which refits the model in two iterations, removing one survey at a time. Then we can plot each of these new model fits over the full model to see the impact the removal of each has.

LO_nmG5ysw <- leaveout(fit_nmG5ysw)

# === Get data from sam objects and generate useable dataframes ====
q1mat <- as.data.frame(summary(LO_nmG5ysw$`w.o. Q1IBTS+BITS+CodSD21-25`))
q3mat <- as.data.frame(summary(LO_nmG5ysw$`w.o. Q34IBTS+BITS+CodSD21-25`))


woq1 <- data.frame(Year = as.integer(row.names(summary(LO_nmG5ysw$`w.o. Q1IBTS+BITS+CodSD21-25`))),
    SSB = q1mat$SSB, Fbar = q1mat$`Fbar(3-5)`, R_age1 = q1mat$`R(age 1)`, CatchEst = catchtable(LO_nmG5ysw$`w.o. Q1IBTS+BITS+CodSD21-25`)[,
        1], series = rep("wo_Q1", times = nrow(q1mat)))

woq34 <- data.frame(Year = as.integer(row.names(q3mat[(2002:DataYear) - 2001, ])),
    SSB = q3mat[(2002:DataYear) - 2001, "SSB"], Fbar = q3mat[(2002:DataYear) - 2001,
        "Fbar(3-5)"], R_age1 = q3mat[(2002:DataYear) - 2001, "R(age 1)"], CatchEst = catchtable(LO_nmG5ysw$`w.o. Q34IBTS+BITS+CodSD21-25`)[,
        1], series = rep("wo_Q34", times = (nrow(q3mat) - 1)))


asum_nmG5ysw$series <- rep("full", times = nrow(asum_nmG5ysw))
asumi_nmG5ysw <- asum_nmG5ysw[, c("Year", "SSB", "Fbar", "R_age1", "CatchEst", "series")]
# =====

losum_nmG5ysw <- rbind(woq1, woq34, asumi_nmG5ysw)
# ssbplot(LO)
lossb_nmG5ysw <- ggplotly(ggplot() + geom_line(data = losum_nmG5ysw, mapping = aes(x = Year,
    y = SSB, colour = series)) + geom_ribbon(data = asum_nmG5ysw, mapping = aes(x = Year,
    ymin = SSBlow, ymax = SSBhigh), fill = "black", alpha = 0.2) + scale_colour_manual(values = c("black",
    ebpal[8:9])) + theme_clean() + theme(axis.title.y.left = element_text(vjust = -0.05,
    hjust = 0.95)))

# Fplot(LO)
lof_nmG5ysw <- ggplotly(ggplot() + geom_line(data = losum_nmG5ysw, mapping = aes(x = Year,
    y = Fbar, colour = series)) + geom_ribbon(data = asum_nmG5ysw, mapping = aes(x = Year,
    ymin = Flow, ymax = Fhigh), fill = "black", alpha = 0.3) + scale_colour_manual(values = c("black",
    ebpal[8:9])) + theme_clean() + theme(axis.title.y.left = element_text(vjust = -0.05,
    hjust = 0.95)))

# recplot(LO)
lorec_nmG5ysw <- ggplotly(ggplot() + geom_line(data = losum_nmG5ysw, mapping = aes(x = Year,
    y = R_age1, colour = series)) + geom_ribbon(data = asum_nmG5ysw, mapping = aes(x = Year,
    ymin = Rlow, ymax = Rhigh), fill = "black", alpha = 0.3) + scale_colour_manual(values = c("black",
    ebpal[8:9])) + theme_clean() + theme(axis.title.y.left = element_text(vjust = -0.05,
    hjust = 0.95)))

# Catch plot (LO)
loca_nmG5ysw <- ggplotly(ggplot() + geom_line(data = losum_nmG5ysw, mapping = aes(x = Year,
    y = CatchEst, colour = series)) + geom_ribbon(data = asum_nmG5ysw[asum_nmG5ysw$Year !=
    (DataYear + 1), ], mapping = aes(x = Year, ymin = Catchlow, ymax = Catchhigh),
    fill = "black", alpha = 0.3) + geom_point(data = asum_nmG5ysw[asum_nmG5ysw$Year !=
    (DataYear + 1), ], mapping = aes(x = Year, y = CatchObs), shape = 3, colour = ebpal[5],
    fill = ebpal[5]) + ylab("Catch (tonnes)") + scale_colour_manual(values = c("black",
    ebpal[8:9])) + theme_clean() + theme(axis.title.y.left = element_text(vjust = -0.05,
    hjust = 0.95)))

layout(subplot(lossb_nmG5ysw, lof_nmG5ysw, lorec_nmG5ysw, loca_nmG5ysw, nrows = 2,
    shareX = TRUE, titleY = TRUE), showlegend = FALSE)

Figure 3.24: Leave-one-out re-fits for the Time varying with five year sliding window, Gislason natural mortalities (without Q1 survey = blue, without Q3/4 survey = purple), overlain with full model estimates (black line and grey ribbon) of SSB (top left), F (top right), Recruitment (bottom left), and catch (bottom right; observations as yellow +).

3.3.3 Retrospectives

# === Create dataframe of current year's fit for plotting ==== IC_agg_temp <-
# aggregate(CATON~Year, ic_clean[ic_clean$CatchCategory %in% c('Landings',
# 'Discards'), ], FUN = 'sum')
asum_nmG5ysw <- as.data.frame(summary(fit_nmG5ysw))
asum_nmG5ysw$Year <- as.integer(row.names(summary(fit_nmG5ysw)))
ct_nmG5ysw <- as.data.frame(catchtable(fit_nmG5ysw, obs.show = TRUE))
ct_nmG5ysw$Year <- as.integer(rownames(ct_nmG5ysw))
rownames(ct_nmG5ysw) <- NULL
ct_nmG5ysw <- rbind(ct_nmG5ysw, data.frame(Estimate = NA, Low = NA, High = NA, sop.catch = NA,
    Year = as.integer(2024)))
asum_nmG5ysw <- merge(x = asum_nmG5ysw, y = ct_nmG5ysw, by = "Year")
colnames(asum_nmG5ysw) <- c("Year", "R_age1", "Rlow", "Rhigh", "SSB", "SSBlow", "SSBhigh",
    "Fbar", "Flow", "Fhigh", "CatchEst", "Catchlow", "Catchhigh", "CatchObs")

asum_nmG5ysw$series <- rep("full", times = nrow(asum_nmG5ysw))

# =====
RETRO_nmG5ysw <- retro(fit_nmG5ysw, year = 5)
rho_nmG5ysw <- mohn(RETRO_nmG5ysw, lag = 1)

## Make RETROs in better plotting format
ret_nmG5ysw_df <- asum_nmG5ysw[asum_nmG5ysw$Year != max(asum_nmG5ysw$Year), ]

for (i in 1:length(RETRO_nmG5ysw)) {
    tsum <- as.data.frame(summary(RETRO_nmG5ysw[[i]]))
    tsum$Year <- as.integer(row.names(summary(RETRO_nmG5ysw[[i]])))
    tsum <- cbind(tsum, catchtable(RETRO_nmG5ysw[[i]], obs.show = TRUE))
    tsum$series <- as.character(rep(i, nrow(tsum)))
    colnames(tsum) <- c("R_age1", "Rlow", "Rhigh", "SSB", "SSBlow", "SSBhigh", "Fbar",
        "Flow", "Fhigh", "Year", "CatchEst", "Catchlow", "Catchhigh", "CatchObs",
        "series")
    tsum <- tsum[tsum$Year != max(tsum$Year), ]
    ret_nmG5ysw_df <- rbind(ret_nmG5ysw_df, tsum)
}
ret_nmG5ysw_df$series <- factor(ret_nmG5ysw_df$series, levels = c("full", "1", "2",
    "3", "4", "5"))
# ssbplot(RETRO)
retssb_nmG5ysw <- layout(ggplotly(ggplot() + geom_line(data = ret_nmG5ysw_df, mapping = aes(x = Year,
    y = SSB, colour = series)) + geom_ribbon(data = asum_nmG5ysw[asum_nmG5ysw$Year !=
    max(asum_nmG5ysw$Year), ], mapping = aes(x = Year, ymin = SSBlow, ymax = SSBhigh),
    fill = "black", alpha = 0.2) + annotate(geom = "text", y = max(ret_nmG5ysw_df$SSBhigh) *
    0.85, x = ((max(ret_nmG5ysw_df$Year) - min(ret_nmG5ysw_df$Year)) * 0.2) + min(ret_nmG5ysw_df$Year),
    label = paste0("Mohn's Rho = ", round(rho_nmG5ysw[2], digits = 3))) + scale_colour_manual(values = c("black",
    ebpal[(length(ebpal) - 4):length(ebpal)])) + theme_clean() + theme(legend.position = "none",
    axis.title.y.left = element_text(vjust = -0.05, hjust = 0.95))), showlegend = FALSE)

# Fplot(RETRO)
retf_nmG5ysw <- layout(ggplotly(ggplot() + geom_line(data = ret_nmG5ysw_df, mapping = aes(x = Year,
    y = Fbar, colour = series)) + geom_ribbon(data = asum_nmG5ysw[asum_nmG5ysw$Year !=
    max(asum_nmG5ysw$Year), ], mapping = aes(x = Year, ymin = Flow, ymax = Fhigh),
    fill = "black", alpha = 0.3) + annotate(geom = "text", y = max(ret_nmG5ysw_df$Fhigh) *
    0.85, x = ((max(ret_nmG5ysw_df$Year) - min(ret_nmG5ysw_df$Year)) * 0.8) + min(ret_nmG5ysw_df$Year),
    label = paste0("Mohn's Rho = ", round(rho_nmG5ysw[3], digits = 3))) + scale_colour_manual(values = c("black",
    ebpal[(length(ebpal) - 4):length(ebpal)])) + theme_clean() + theme(legend.position = "none",
    axis.title.y.left = element_text(vjust = -0.05, hjust = 0.95))), showlegend = FALSE)

# recplot(RETRO)
retrec_nmG5ysw <- layout(ggplotly(ggplot() + geom_line(data = ret_nmG5ysw_df, mapping = aes(x = Year,
    y = R_age1, colour = series)) + geom_ribbon(data = asum_nmG5ysw[asum_nmG5ysw$Year !=
    max(asum_nmG5ysw$Year), ], mapping = aes(x = Year, ymin = Rlow, ymax = Rhigh),
    fill = "black", alpha = 0.3) + annotate(geom = "text", y = max(ret_nmG5ysw_df$Rhigh) *
    0.85, x = ((max(ret_nmG5ysw_df$Year) - min(ret_nmG5ysw_df$Year)) * 0.2) + min(ret_nmG5ysw_df$Year),
    label = paste0("Mohn's Rho = ", round(rho_nmG5ysw[1], digits = 3))) + scale_colour_manual(values = c("black",
    ebpal[(length(ebpal) - 4):length(ebpal)])) + theme_clean() + theme(legend.position = "none",
    axis.title.y.left = element_text(vjust = -0.05, hjust = 0.95))), showlegend = FALSE)

# Catch plot (RETRO)
retca_nmG5ysw <- ggplotly(ggplot() + geom_line(data = ret_nmG5ysw_df, mapping = aes(x = Year,
    y = CatchEst, colour = series)) + geom_ribbon(data = asum_nmG5ysw[asum_nmG5ysw$Year !=
    max(asum_nmG5ysw$Year), ], mapping = aes(x = Year, ymin = Catchlow, ymax = Catchhigh),
    fill = "black", alpha = 0.3) + geom_point(data = asum_nmG5ysw[asum_nmG5ysw$Year !=
    max(asum_nmG5ysw$Year), ], mapping = aes(x = Year, y = CatchObs), shape = 3,
    colour = ebpal[5], fill = ebpal[5]) + ylab("Catch (tonnes)") + scale_colour_manual(values = c("black",
    ebpal[(length(ebpal) - 4):length(ebpal)])) + theme_clean() + theme(axis.title.y.left = element_text(vjust = -0.05,
    hjust = 0.95)))

ret_fp <- style(subplot(retssb_nmG5ysw, retf_nmG5ysw, retrec_nmG5ysw, retca_nmG5ysw,
    nrows = 2, shareX = FALSE, shareY = FALSE, titleY = TRUE), showlegend = FALSE,
    traces = c(8:((7 * 4) + 2)))

layout(ret_fp, legend = list(orientation = "h", x = 0.5, xanchor = "center", y = -0.05,
    yanchor = "top", borderwidth = 0))

Figure 3.25: Retrospective analyses for SSB (top-left), F for ages 3-5 (top-right), recruitment (bottom-left), and catch (bottom-right), from the model utilising time variant (5 year sliding window mean), Gislason natural mortalities.

4 Models with New Natural Mortalities Informed by FishBase Growth parameters

4.1 Time Invariant, Gislason Natural Mortality From FishBase

4.1.1 Fits to data

fit_nmGFb <- fitfromweb("ple.27.21-32_WKBPLAICE_2024_BioParsw_SV_nmGFb")
# === Create dataframe of current year's fit for plotting ====
asum_nmGFb <- as.data.frame(summary(fit_nmGFb))
asum_nmGFb$Year <- as.integer(row.names(summary(fit_nmGFb)))
ct_nmGFb <- as.data.frame(catchtable(fit_nmGFb, obs.show = TRUE))
ct_nmGFb$Year <- as.integer(rownames(ct_nmGFb))
rownames(ct_nmGFb) <- NULL
ct_nmGFb <- rbind(ct_nmGFb, data.frame(Estimate = NA, Low = NA, High = NA, sop.catch = NA,
    Year = as.integer(2024)))
asum_nmGFb <- merge(x = asum_nmGFb, y = ct_nmGFb, by = "Year")
colnames(asum_nmGFb) <- c("Year", "R_age1", "Rlow", "Rhigh", "SSB", "SSBlow", "SSBhigh",
    "Fbar", "Flow", "Fhigh", "CatchEst", "Catchlow", "Catchhigh", "CatchObs")
# =====

When the model is run we can easily see from warnings/errors if there is a convergence issue. However, we can also confirm this, explicitly: - The final model gradient: 145 - That there is a positive definite hessian: TRUE

Furthermore, SAM does not utilise “bounds” when fitting the model, and therefore, as standard check of whether model parameters are approaching their bounds is irrelevant.

## Extract data from model object
logObs_nmGFb <- split(fit_nmGFb$data$logobs, ceiling(seq_along(fit_nmGFb$data$logobs)/fit_nmGFb$data$maxAgePerFleet[1]))
logPred_nmGFb <- split(fit_nmGFb$rep$predObs, ceiling(seq_along(fit_nmGFb$rep$predObs)/fit_nmGFb$data$maxAgePerFleet[1]))

## Transform data to useable dataframes
### Initialize an empty data frame for observations
logObs_nmGFb_df <- data.frame(age = integer(),
                              fleet = integer(),
                              year = integer(),
                              logObs = numeric())

### Populate the data frame for observations
for (i in seq_along(logObs_nmGFb)) {
  # Calculate the group and year
  year <- ((i - 1) %/% 3) + 1
  fleet <- ((i - 1) %% 3) + 1
  
  ### Create a temporary data frame and append to the main data frame for observations
  temp_df <- data.frame(age = 1:7,
                        fleet = fleet,
                        year = year+2001,
                        logObs = logObs_nmGFb[[i]])
  logObs_nmGFb_df <- rbind(logObs_nmGFb_df, temp_df)
}

### Initialize an empty data frame for predictions
logPred_nmGFb_df <- data.frame(age = integer(),
                               fleet = integer(),
                               year = integer(),
                               logPred = numeric())

### Populate the data frame for predictions
for (i in seq_along(logPred_nmGFb)) {
  # Calculate the group and year
  year <- ((i - 1) %/% 3) + 1
  fleet <- ((i - 1) %% 3) + 1
  
  ### Create a temporary data frame and append to the main data frame for predictions
  temp_df <- data.frame(age = 1:7,
                        fleet = fleet,
                        year = year+2001,
                        logPred = logPred_nmGFb[[i]])
  logPred_nmGFb_df <- rbind(logPred_nmGFb_df, temp_df)
}

## Plot
logPred_nmGFb_df$age <- as.character(logPred_nmGFb_df$age)
logObs_nmGFb_df$age <- as.character(logObs_nmGFb_df$age)

ggplotly(ggplot()+
           geom_point(data = logObs_nmGFb_df[logObs_nmGFb_df$fleet == 1 & logObs_nmGFb_df$year != (DataYear+1), ],
                      mapping = aes(x = year,
                                    y = logObs,
                                    colour = age),
                      shape = 21) +
           geom_line(data = logPred_nmGFb_df[logPred_nmGFb_df$fleet == 1 & logPred_nmGFb_df$year != (DataYear+1), ],
                     mapping = aes(x = year,
                                   y = logPred,
                                   colour = age)) +
           facet_wrap(facets = "age") + #, scales = "free_y") +
           scale_color_manual(values = ebpal, guide = FALSE) +
           guides(colour=FALSE, shape=FALSE) +
           theme_few())

Figure 4.1: Model with time invariant Gislason natural mortalities (FishBase) fit to catch data by age (values on the model link function scale).

# fitplot(fit_nmGFb, fleets=1)
ggplotly(ggplot()+
           geom_point(data = logObs_nmGFb_df[logObs_nmGFb_df$fleet == 2 & logObs_nmGFb_df$year != (DataYear+1), ],
                      mapping = aes(x = year,
                                    y = logObs,
                                    colour = age),
                      shape = 21) +
           geom_line(data = logPred_nmGFb_df[logPred_nmGFb_df$fleet == 2 & logPred_nmGFb_df$year != (DataYear+1), ],
                     mapping = aes(x = year,
                                   y = logPred,
                                   colour = age)) +
           facet_wrap(facets = "age") + #, scales = "free_y") +
           scale_color_manual(values = ebpal, guide = FALSE) +
           guides(colour=FALSE, shape=FALSE) +
           theme_few())

Figure 4.2: Model with time invariant Gislason natural mortalities (FishBase) fit to Q1 survey data by age (values on the model link function scale).

# fitplot(fit_nmGFb, fleets=2)
ggplotly(ggplot()+
           geom_point(data = logObs_nmGFb_df[logObs_nmGFb_df$fleet == 3 & logObs_nmGFb_df$year != (DataYear+1), ],
                      mapping = aes(x = year,
                                    y = logObs,
                                    colour = age),
                      shape = 21) +
           geom_line(data = logPred_nmGFb_df[logPred_nmGFb_df$fleet == 3 & logPred_nmGFb_df$year != (DataYear+1), ],
                     mapping = aes(x = year,
                                   y = logPred,
                                   colour = age)) +
           facet_wrap(facets = "age") + #, scales = "free_y") +
           scale_color_manual(values = ebpal, guide = FALSE) +
           guides(colour=FALSE, shape=FALSE) +
           theme_few())

Figure 4.3: Model with time invariant Gislason natural mortalities (FishBase) fit to Q3/4 survey data by age (values on the model link function scale).

# fitplot(fit_nmGFb, fleets=3)
sdplot(fit_nmGFb, marg = c(5, 4, 1, 1))
Standard Devations by Fleet; Gislason, time-invariant mortality (FishBase)

Figure 4.4: Standard Devations by Fleet; Gislason, time-invariant mortality (FishBase)

4.1.2 Residuals

resid_nmGFb <- residuals(fit_nmGFb)
resid_nmGFb_df <- data.frame(year = resid_nmGFb$year, fleet = resid_nmGFb$fleet,
    age = resid_nmGFb$age, observation = resid_nmGFb$observation, mean = resid_nmGFb$mean,
    residual = resid_nmGFb$residual)
resid_nmGFb_df$fleetName <- ifelse(resid_nmGFb_df$fleet == 1, attributes(resid_nmGFb)$fleetNames[1],
    ifelse(resid_nmGFb_df$fleet == 2, attributes(resid_nmGFb)$fleetNames[2], ifelse(resid_nmGFb_df$fleet ==
        3, attributes(resid_nmGFb)$fleetNames[3], NA)))

resid_nmGFb_df$fleetAltName <- ifelse(resid_nmGFb_df$fleet == 1, "Residual Fishing",
    ifelse(resid_nmGFb_df$fleet == 2, "Q1 Surveys", ifelse(resid_nmGFb_df$fleet ==
        3, "Q3/4 Surveys", NA)))
if (!all(fit_nmGFb$conf$obsCorStruct == "ID")) {
    corplot(fit_nmGFb)
    # setcap('Estimated correlations', 'Estimates correlations between age
    # groups for each fleet') stampit(fit)
} else {
    print("No correlation structure configured for residuals across age.")
}
Estimated correlations in residual variation between ages for each of the fishing fleet (top) and the two surveys (middle & bottom), from the model with time invariant Gislason natural mortalities (FishBase).

Figure 4.5: Estimated correlations in residual variation between ages for each of the fishing fleet (top) and the two surveys (middle & bottom), from the model with time invariant Gislason natural mortalities (FishBase).

ggplotly(ggplot(resid_nmGFb_df) + geom_point(mapping = aes(x = year, y = age, size = abs(residual),
    colour = residual >= 0), alpha = 0.7) + facet_grid(rows = "fleetAltName") + scale_colour_manual(values = c(`TRUE` = ebpal[8],
    `FALSE` = ebpal[9])) + scale_y_continuous(limits = c(-1, 9), breaks = c(1:9)) +
    guides(colour = FALSE) + theme_few())

Figure 4.6: One observation ahead residuals for the three fleets (red/pink = observation lower than model estimate, blue = observation higher than model estimate, size = magnitude of residual), from the model with time invariant Gislason natural mortalities (FishBase).

4.1.2.1 Jittering

We can also test to see if the model is converging on some local minimum (i.e. it’s fitting to some solution close to initialising values that represents noise and not the global solution, that is the proper solution). To do this, we add random noise to the initial parameter values to see if the model will converge on a different minimum in it’s data-space. The easiest way to investigate this is to see if the model fits vary alot depending on the starting values:

jit_nmGFb <- jit(fit = fit_nmGFb)

mt <- as.data.frame(modeltable(jit_nmGFb))
mt$model <- rownames(mt)
rownames(mt) <- NULL

kable(x = mt, digits = 3, caption = "Measures of  fit for a series of model refits with jitter applied to the input parameters.")
(#tab:Jitter_nmGFb)Measures of fit for a series of model refits with jitter applied to the input parameters.
log(L) #par AIC model
-96.82 36 265.64 M1
-96.82 36 265.64 M2
-96.82 36 265.64 M3
-96.82 36 265.64 M4
-96.82 36 265.64 M5
-96.82 36 265.64 M6
-96.82 36 265.64 M7
-96.82 36 265.64 M8
-96.82 36 265.64 M9
-96.82 36 265.64 M10
-96.82 36 265.64 M11

4.1.2.2 Leave-One-Out Analyses

A leave-one-out analysis is a form of sensitivity analysis, showing the impact the data from each tuning fleet has on the estimation of the key variables being estimated; namely SSB, F and recruitment.

First we must run the leave-one-out analysis which refits the model in two iterations, removing one survey at a time. Then we can plot each of these new model fits over the full model to see the impact the removal of each has.

LO_nmGFb <- leaveout(fit_nmGFb)

# === Get data from sam objects and generate useable dataframes ====
q1mat <- as.data.frame(summary(LO_nmGFb$`w.o. Q1IBTS+BITS+CodSD21-25`))
q3mat <- as.data.frame(summary(LO_nmGFb$`w.o. Q34IBTS+BITS+CodSD21-25`))


woq1 <- data.frame(Year = as.integer(row.names(summary(LO_nmGFb$`w.o. Q1IBTS+BITS+CodSD21-25`))),
    SSB = q1mat$SSB, Fbar = q1mat$`Fbar(3-5)`, R_age1 = q1mat$`R(age 1)`, CatchEst = catchtable(LO_nmGFb$`w.o. Q1IBTS+BITS+CodSD21-25`)[,
        1], series = rep("wo_Q1", times = nrow(q1mat)))

woq34 <- data.frame(Year = as.integer(row.names(q3mat[(2002:DataYear) - 2001, ])),
    SSB = q3mat[(2002:DataYear) - 2001, "SSB"], Fbar = q3mat[(2002:DataYear) - 2001,
        "Fbar(3-5)"], R_age1 = q3mat[(2002:DataYear) - 2001, "R(age 1)"], CatchEst = catchtable(LO_nmGFb$`w.o. Q34IBTS+BITS+CodSD21-25`)[,
        1], series = rep("wo_Q34", times = (nrow(q3mat) - 1)))


asum_nmGFb$series <- rep("full", times = nrow(asum_nmGFb))
asumi_nmGFb <- asum_nmGFb[, c("Year", "SSB", "Fbar", "R_age1", "CatchEst", "series")]
# =====

losum_nmGFb <- rbind(woq1, woq34, asumi_nmGFb)
# ssbplot(LO)
lossb_nmGFb <- ggplotly(ggplot() + geom_line(data = losum_nmGFb, mapping = aes(x = Year,
    y = SSB, colour = series)) + geom_ribbon(data = asum_nmGFb, mapping = aes(x = Year,
    ymin = SSBlow, ymax = SSBhigh), fill = "black", alpha = 0.2) + scale_colour_manual(values = c("black",
    ebpal[8:9])) + theme_clean() + theme(axis.title.y.left = element_text(vjust = -0.05,
    hjust = 0.95)))

# Fplot(LO)
lof_nmGFb <- ggplotly(ggplot() + geom_line(data = losum_nmGFb, mapping = aes(x = Year,
    y = Fbar, colour = series)) + geom_ribbon(data = asum_nmGFb, mapping = aes(x = Year,
    ymin = Flow, ymax = Fhigh), fill = "black", alpha = 0.3) + scale_colour_manual(values = c("black",
    ebpal[8:9])) + theme_clean() + theme(axis.title.y.left = element_text(vjust = -0.05,
    hjust = 0.95)))

# recplot(LO)
lorec_nmGFb <- ggplotly(ggplot() + geom_line(data = losum_nmGFb, mapping = aes(x = Year,
    y = R_age1, colour = series)) + geom_ribbon(data = asum_nmGFb, mapping = aes(x = Year,
    ymin = Rlow, ymax = Rhigh), fill = "black", alpha = 0.3) + scale_colour_manual(values = c("black",
    ebpal[8:9])) + theme_clean() + theme(axis.title.y.left = element_text(vjust = -0.05,
    hjust = 0.95)))

# Catch plot (LO)
loca_nmGFb <- ggplotly(ggplot() + geom_line(data = losum_nmGFb, mapping = aes(x = Year,
    y = CatchEst, colour = series)) + geom_ribbon(data = asum_nmGFb[asum_nmGFb$Year !=
    (DataYear + 1), ], mapping = aes(x = Year, ymin = Catchlow, ymax = Catchhigh),
    fill = "black", alpha = 0.3) + geom_point(data = asum_nmGFb[asum_nmGFb$Year !=
    (DataYear + 1), ], mapping = aes(x = Year, y = CatchObs), shape = 3, colour = ebpal[5],
    fill = ebpal[5]) + ylab("Catch (tonnes)") + scale_colour_manual(values = c("black",
    ebpal[8:9])) + theme_clean() + theme(axis.title.y.left = element_text(vjust = -0.05,
    hjust = 0.95)))

layout(subplot(lossb_nmGFb, lof_nmGFb, lorec_nmGFb, loca_nmGFb, nrows = 2, shareX = TRUE,
    titleY = TRUE), showlegend = FALSE)

Figure 4.7: Leave-one-out re-fits for the Time invariant, Gislason natural mortalities calculated from life-history off of fishbase (without Q1 survey = blue, without Q3/4 survey = purple), overlain with full model estimates (black line and grey ribbon) of SSB (top left), F (top right), Recruitment (bottom left), and catch (bottom right; observations as yellow +).

4.1.3 Retrospectives

# === Create dataframe of current year's fit for plotting ==== IC_agg_temp <-
# aggregate(CATON~Year, ic_clean[ic_clean$CatchCategory %in% c('Landings',
# 'Discards'), ], FUN = 'sum')
asum_nmGFb <- as.data.frame(summary(fit_nmGFb))
asum_nmGFb$Year <- as.integer(row.names(summary(fit_nmGFb)))
ct_nmGFb <- as.data.frame(catchtable(fit_nmGFb, obs.show = TRUE))
ct_nmGFb$Year <- as.integer(rownames(ct_nmGFb))
rownames(ct_nmGFb) <- NULL
ct_nmGFb <- rbind(ct_nmGFb, data.frame(Estimate = NA, Low = NA, High = NA, sop.catch = NA,
    Year = as.integer(2024)))
asum_nmGFb <- merge(x = asum_nmGFb, y = ct_nmGFb, by = "Year")
colnames(asum_nmGFb) <- c("Year", "R_age1", "Rlow", "Rhigh", "SSB", "SSBlow", "SSBhigh",
    "Fbar", "Flow", "Fhigh", "CatchEst", "Catchlow", "Catchhigh", "CatchObs")

asum_nmGFb$series <- rep("full", times = nrow(asum_nmGFb))

# =====
RETRO_nmGFb <- retro(fit_nmGFb, year = 5)
rho_nmGFb <- mohn(RETRO_nmGFb, lag = 1)

## Make RETROs in better plotting format
ret_nmGFb_df <- asum_nmGFb[asum_nmGFb$Year != max(asum_nmGFb$Year), ]

for (i in 1:length(RETRO_nmGFb)) {
    tsum <- as.data.frame(summary(RETRO_nmGFb[[i]]))
    tsum$Year <- as.integer(row.names(summary(RETRO_nmGFb[[i]])))
    tsum <- cbind(tsum, catchtable(RETRO_nmGFb[[i]], obs.show = TRUE))
    tsum$series <- as.character(rep(i, nrow(tsum)))
    colnames(tsum) <- c("R_age1", "Rlow", "Rhigh", "SSB", "SSBlow", "SSBhigh", "Fbar",
        "Flow", "Fhigh", "Year", "CatchEst", "Catchlow", "Catchhigh", "CatchObs",
        "series")
    tsum <- tsum[tsum$Year != max(tsum$Year), ]
    ret_nmGFb_df <- rbind(ret_nmGFb_df, tsum)
}
ret_nmGFb_df$series <- factor(ret_nmGFb_df$series, levels = c("full", "1", "2", "3",
    "4", "5"))
# ssbplot(RETRO)
retssb_nmGFb <- layout(ggplotly(ggplot() + geom_line(data = ret_nmGFb_df, mapping = aes(x = Year,
    y = SSB, colour = series)) + geom_ribbon(data = asum_nmGFb[asum_nmGFb$Year !=
    max(asum_nmGFb$Year), ], mapping = aes(x = Year, ymin = SSBlow, ymax = SSBhigh),
    fill = "black", alpha = 0.2) + annotate(geom = "text", y = max(ret_nmGFb_df$SSBhigh) *
    0.85, x = ((max(ret_nmGFb_df$Year) - min(ret_nmGFb_df$Year)) * 0.2) + min(ret_nmGFb_df$Year),
    label = paste0("Mohn's Rho = ", round(rho_nmGFb[2], digits = 3))) + scale_colour_manual(values = c("black",
    ebpal[(length(ebpal) - 4):length(ebpal)])) + theme_clean() + theme(legend.position = "none",
    axis.title.y.left = element_text(vjust = -0.05, hjust = 0.95))), showlegend = FALSE)

# Fplot(RETRO)
retf_nmGFb <- layout(ggplotly(ggplot() + geom_line(data = ret_nmGFb_df, mapping = aes(x = Year,
    y = Fbar, colour = series)) + geom_ribbon(data = asum_nmGFb[asum_nmGFb$Year !=
    max(asum_nmGFb$Year), ], mapping = aes(x = Year, ymin = Flow, ymax = Fhigh),
    fill = "black", alpha = 0.3) + annotate(geom = "text", y = max(ret_nmGFb_df$Fhigh) *
    0.85, x = ((max(ret_nmGFb_df$Year) - min(ret_nmGFb_df$Year)) * 0.8) + min(ret_nmGFb_df$Year),
    label = paste0("Mohn's Rho = ", round(rho_nmGFb[3], digits = 3))) + scale_colour_manual(values = c("black",
    ebpal[(length(ebpal) - 4):length(ebpal)])) + theme_clean() + theme(legend.position = "none",
    axis.title.y.left = element_text(vjust = -0.05, hjust = 0.95))), showlegend = FALSE)

# recplot(RETRO)
retrec_nmGFb <- layout(ggplotly(ggplot() + geom_line(data = ret_nmGFb_df, mapping = aes(x = Year,
    y = R_age1, colour = series)) + geom_ribbon(data = asum_nmGFb[asum_nmGFb$Year !=
    max(asum_nmGFb$Year), ], mapping = aes(x = Year, ymin = Rlow, ymax = Rhigh),
    fill = "black", alpha = 0.3) + annotate(geom = "text", y = max(ret_nmGFb_df$Rhigh) *
    0.85, x = ((max(ret_nmGFb_df$Year) - min(ret_nmGFb_df$Year)) * 0.2) + min(ret_nmGFb_df$Year),
    label = paste0("Mohn's Rho = ", round(rho_nmGFb[1], digits = 3))) + scale_colour_manual(values = c("black",
    ebpal[(length(ebpal) - 4):length(ebpal)])) + theme_clean() + theme(legend.position = "none",
    axis.title.y.left = element_text(vjust = -0.05, hjust = 0.95))), showlegend = FALSE)

# Catch plot (RETRO)
retca_nmGFb <- ggplotly(ggplot() + geom_line(data = ret_nmGFb_df, mapping = aes(x = Year,
    y = CatchEst, colour = series)) + geom_ribbon(data = asum_nmGFb[asum_nmGFb$Year !=
    max(asum_nmGFb$Year), ], mapping = aes(x = Year, ymin = Catchlow, ymax = Catchhigh),
    fill = "black", alpha = 0.3) + geom_point(data = asum_nmGFb[asum_nmGFb$Year !=
    max(asum_nmGFb$Year), ], mapping = aes(x = Year, y = CatchObs), shape = 3, colour = ebpal[5],
    fill = ebpal[5]) + ylab("Catch (tonnes)") + scale_colour_manual(values = c("black",
    ebpal[(length(ebpal) - 4):length(ebpal)])) + theme_clean() + theme(axis.title.y.left = element_text(vjust = -0.05,
    hjust = 0.95)))

ret_fp <- style(subplot(retssb_nmGFb, retf_nmGFb, retrec_nmGFb, retca_nmGFb, nrows = 2,
    shareX = FALSE, shareY = FALSE, titleY = TRUE), showlegend = FALSE, traces = c(8:((7 *
    4) + 2)))

layout(ret_fp, legend = list(orientation = "h", x = 0.5, xanchor = "center", y = -0.05,
    yanchor = "top", borderwidth = 0))

Figure 4.8: Retrospective analyses for SSB (top-left), F for ages 3-5 (top-right), recruitment (bottom-left), and catch (bottom-right), from the model utilising time invariant, Gislason natural mortalities (FishBase).

4.2 Scaled, Time Invariant, Gislason Natural mortalities

4.2.1 Scaling and optimising

# === Scale natural mortality by a range of multipliers ====
fit_nmGFb <- fitfromweb("ple.27.21-32_WKBPLAICE_2024_BioParsw_SV_nmGFb")

profs = list()
nm = fit_nmGFb$data$natMor
mults = seq(0.1, 2, by = 0.1)

## Re-fit to scaled mortalities
for (mult in mults) {

    fit_nmGFb$data$natMor = nm * mult

    profs[[as.character(mult)]] = stockassessment:::refit(fit_nmGFb, silent = TRUE)
}
# ====
# === Aggregate AIC values and plot results ====
ll = sapply(profs, AIC)
plot(mults, ll)
Likelihood profile of scaled time invariant, Gislason natural mortalities (FishBase). Y-axis = AIC, x-axis = scaling factor on nm.

Figure 4.9: Likelihood profile of scaled time invariant, Gislason natural mortalities (FishBase). Y-axis = AIC, x-axis = scaling factor on nm.

# ====

We can now investigate if averaging the Gislason natural mortalities over the time series creates some scaling issues by ignoring weightings of numbers of observations contributing to each annual estimate. To partially address this we can investigate scaling these time invariant values up and down, to find where the best fit of this “shape” of natural mortalities across ages is.

By scaling the nm values up and down across a range of multipliers from 0.1 to 2, in increments of 0.1, we create 20 different runs from which we can compare AIC values. Here we find that a scaling value of 1.2 is responsible for the optimum model fit.

4.2.2 Investigating the scaled model

Therefore, below we investigate the model fit and residuals for a model with the Gislason, time invariant mortalities at age that have been scaled by a factor of 1.2 across all ages.

fit_nmG_SFb <- fitfromweb("ple.27.21-32_WKBPLAICE_2024_BioParsw_nmG_SFb")
# === Create dataframe of current year's fit for plotting ====
asum_nmG_SFb <- as.data.frame(summary(fit_nmG_SFb))
asum_nmG_SFb$Year <- as.integer(row.names(summary(fit_nmG_SFb)))
ct_nmG_SFb <- as.data.frame(catchtable(fit_nmG_SFb, obs.show = TRUE))
ct_nmG_SFb$Year <- as.integer(rownames(ct_nmG_SFb))
rownames(ct_nmG_SFb) <- NULL
ct_nmG_SFb <- rbind(ct_nmG_SFb, data.frame(Estimate = NA, Low = NA, High = NA, sop.catch = NA,
    Year = as.integer(2024)))
asum_nmG_SFb <- merge(x = asum_nmG_SFb, y = ct_nmG_SFb, by = "Year")
colnames(asum_nmG_SFb) <- c("Year", "R_age1", "Rlow", "Rhigh", "SSB", "SSBlow", "SSBhigh",
    "Fbar", "Flow", "Fhigh", "CatchEst", "Catchlow", "Catchhigh", "CatchObs")
# =====

4.2.2.1 Fits to data

When the model is run we can easily see from warnings/errors if there is a convergence issue. However, we can also confirm this, explicitly: - The final model gradient: 132 - That there is a positive definite hessian: TRUE

Furthermore, SAM does not utilise “bounds” when fitting the model, and therefore, as standard check of whether model parameters are approaching their bounds is irrelevant.

## Extract data from model object
logObs_nmG_SFb <- split(fit_nmG_SFb$data$logobs, ceiling(seq_along(fit_nmG_SFb$data$logobs)/fit_nmG_SFb$data$maxAgePerFleet[1]))
logPred_nmG_SFb <- split(fit_nmG_SFb$rep$predObs, ceiling(seq_along(fit_nmG_SFb$rep$predObs)/fit_nmG_SFb$data$maxAgePerFleet[1]))

## Transform data to useable dataframes
### Initialize an empty data frame for observations
logObs_nmG_SFb_df <- data.frame(age = integer(),
                                fleet = integer(),
                                year = integer(),
                                logObs = numeric())

### Populate the data frame for observations
for (i in seq_along(logObs_nmG_SFb)) {
  # Calculate the group and year
  year <- ((i - 1) %/% 3) + 1
  fleet <- ((i - 1) %% 3) + 1
  
  ### Create a temporary data frame and append to the main data frame for observations
  temp_df <- data.frame(age = 1:7,
                        fleet = fleet,
                        year = year+2001,
                        logObs = logObs_nmG_SFb[[i]])
  logObs_nmG_SFb_df <- rbind(logObs_nmG_SFb_df, temp_df)
}

### Initialize an empty data frame for predictions
logPred_nmG_SFb_df <- data.frame(age = integer(),
                                 fleet = integer(),
                                 year = integer(),
                                 logPred = numeric())

### Populate the data frame for predictions
for (i in seq_along(logPred_nmG_SFb)) {
  # Calculate the group and year
  year <- ((i - 1) %/% 3) + 1
  fleet <- ((i - 1) %% 3) + 1
  
  ### Create a temporary data frame and append to the main data frame for predictions
  temp_df <- data.frame(age = 1:7,
                        fleet = fleet,
                        year = year+2001,
                        logPred = logPred_nmG_SFb[[i]])
  logPred_nmG_SFb_df <- rbind(logPred_nmG_SFb_df, temp_df)
}

## Plot
logPred_nmG_SFb_df$age <- as.character(logPred_nmG_SFb_df$age)
logObs_nmG_SFb_df$age <- as.character(logObs_nmG_SFb_df$age)

ggplotly(ggplot()+
           geom_point(data = logObs_nmG_SFb_df[logObs_nmG_SFb_df$fleet == 1 & logObs_nmG_SFb_df$year != (DataYear+1), ],
                      mapping = aes(x = year,
                                    y = logObs,
                                    colour = age),
                      shape = 21) +
           geom_line(data = logPred_nmG_SFb_df[logPred_nmG_SFb_df$fleet == 1 & logPred_nmG_SFb_df$year != (DataYear+1), ],
                     mapping = aes(x = year,
                                   y = logPred,
                                   colour = age)) +
           facet_wrap(facets = "age") + #, scales = "free_y") +
           scale_color_manual(values = ebpal, guide = FALSE) +
           guides(colour=FALSE, shape=FALSE) +
           theme_few())

Figure 4.10: Model with SCALED time invariant Gislason natural mortalities (FishBase) fit to catch data by age (values on the model link function scale).

# fitplot(fit_nmG_SFb, fleets=1)
ggplotly(ggplot()+
           geom_point(data = logObs_nmG_SFb_df[logObs_nmG_SFb_df$fleet == 2 & logObs_nmG_SFb_df$year != (DataYear+1), ],
                      mapping = aes(x = year,
                                    y = logObs,
                                    colour = age),
                      shape = 21) +
           geom_line(data = logPred_nmG_SFb_df[logPred_nmG_SFb_df$fleet == 2 & logPred_nmG_SFb_df$year != (DataYear+1), ],
                     mapping = aes(x = year,
                                   y = logPred,
                                   colour = age)) +
           facet_wrap(facets = "age") + #, scales = "free_y") +
           scale_color_manual(values = ebpal, guide = FALSE) +
           guides(colour=FALSE, shape=FALSE) +
           theme_few())

Figure 4.11: Model with SCALED time invariant Gislason natural mortalities (FishBase) fit to Q1 survey data by age (values on the model link function scale).

# fitplot(fit_nmG_SFb, fleets=2)
ggplotly(ggplot()+
           geom_point(data = logObs_nmG_SFb_df[logObs_nmG_SFb_df$fleet == 3 & logObs_nmG_SFb_df$year != (DataYear+1), ],
                      mapping = aes(x = year,
                                    y = logObs,
                                    colour = age),
                      shape = 21) +
           geom_line(data = logPred_nmG_SFb_df[logPred_nmG_SFb_df$fleet == 3 & logPred_nmG_SFb_df$year != (DataYear+1), ],
                     mapping = aes(x = year,
                                   y = logPred,
                                   colour = age)) +
           facet_wrap(facets = "age") + #, scales = "free_y") +
           scale_color_manual(values = ebpal, guide = FALSE) +
           guides(colour=FALSE, shape=FALSE) +
           theme_few())

Figure 4.12: Model with SCALED time invariant Gislason natural mortalities (FishBase) fit to Q3/4 survey data by age (values on the model link function scale).

# fitplot(fit_nmG_SFb, fleets=3)
sdplot(fit_nmG_SFb, marg = c(5, 4, 1, 1))
Standard Devations by Fleet; Gislason, scaled, time-invariant mortality (FishBase)

Figure 4.13: Standard Devations by Fleet; Gislason, scaled, time-invariant mortality (FishBase)

4.2.2.2 Residuals

resid_nmG_SFb <- residuals(fit_nmG_SFb)
resid_nmG_SFb_df <- data.frame(year = resid_nmG_SFb$year, fleet = resid_nmG_SFb$fleet,
    age = resid_nmG_SFb$age, observation = resid_nmG_SFb$observation, mean = resid_nmG_SFb$mean,
    residual = resid_nmG_SFb$residual)
resid_nmG_SFb_df$fleetName <- ifelse(resid_nmG_SFb_df$fleet == 1, attributes(resid_nmG_SFb)$fleetNames[1],
    ifelse(resid_nmG_SFb_df$fleet == 2, attributes(resid_nmG_SFb)$fleetNames[2],
        ifelse(resid_nmG_SFb_df$fleet == 3, attributes(resid_nmG_SFb)$fleetNames[3],
            NA)))

resid_nmG_SFb_df$fleetAltName <- ifelse(resid_nmG_SFb_df$fleet == 1, "Residual Fishing",
    ifelse(resid_nmG_SFb_df$fleet == 2, "Q1 Surveys", ifelse(resid_nmG_SFb_df$fleet ==
        3, "Q3/4 Surveys", NA)))
if (!all(fit_nmG_SFb$conf$obsCorStruct == "ID")) {
    corplot(fit_nmG_SFb)
    # setcap('Estimated correlations', 'Estimates correlations between age
    # groups for each fleet') stampit(fit)
} else {
    print("No correlation structure configured for residuals across age.")
}
Estimated correlations in residual variation between ages for each of the fishing fleet (top) and the two surveys (middle & bottom), from the Model with SCALED time invariant Gislason natural mortalities (FishBase).

Figure 4.14: Estimated correlations in residual variation between ages for each of the fishing fleet (top) and the two surveys (middle & bottom), from the Model with SCALED time invariant Gislason natural mortalities (FishBase).

ggplotly(ggplot(resid_nmG_SFb_df) + geom_point(mapping = aes(x = year, y = age, size = abs(residual),
    colour = residual >= 0), alpha = 0.7) + facet_grid(rows = "fleetAltName") + scale_colour_manual(values = c(`TRUE` = ebpal[8],
    `FALSE` = ebpal[9])) + scale_y_continuous(limits = c(-1, 9), breaks = c(1:9)) +
    guides(colour = FALSE) + theme_few())

Figure 4.15: One observation ahead residuals for the three fleets (red/pink = observation lower than model estimate, blue = observation higher than model estimate, size = magnitude of residual), from the Model with SCALED time invariant Gislason natural mortalities (FishBase).

4.2.2.3 Jittering

We can also test to see if the model is converging on some local minimum (i.e. it’s fitting to some solution close to initialising values that represents noise and not the global solution, that is the proper solution). To do this, we add random noise to the initial parameter values to see if the model will converge on a different minimum in it’s data-space. The easiest way to investigate this is to see if the model fits vary alot depending on the starting values:

jit_nmG_SFb <- jit(fit = fit_nmG_SFb)

mt <- as.data.frame(modeltable(jit_nmG_SFb))
mt$model <- rownames(mt)
rownames(mt) <- NULL

kable(x = mt, digits = 3, caption = "Measures of  fit for a series of model refits with jitter applied to the input parameters.")
(#tab:Jitter_nmG_SFb)Measures of fit for a series of model refits with jitter applied to the input parameters.
log(L) #par AIC model
-95.066 36 262.132 M1
-95.066 36 262.132 M2
-95.066 36 262.132 M3
-95.066 36 262.132 M4
-95.066 36 262.132 M5
-95.066 36 262.132 M6
-95.066 36 262.132 M7
-95.066 36 262.132 M8
-95.066 36 262.132 M9
-95.066 36 262.132 M10
-95.066 36 262.132 M11

4.2.2.4 Leave-One-Out Analyses

A leave-one-out analysis is a form of sensitivity analysis, showing the impact the data from each tuning fleet has on the estimation of the key variables being estimated; namely SSB, F and recruitment.

First we must run the leave-one-out analysis which refits the model in two iterations, removing one survey at a time. Then we can plot each of these new model fits over the full model to see the impact the removal of each has.

LO_nmG_SFb <- leaveout(fit_nmG_SFb)

# === Get data from sam objects and generate useable dataframes ====
q1mat <- as.data.frame(summary(LO_nmG_SFb$`w.o. Q1IBTS+BITS+CodSD21-25`))
q3mat <- as.data.frame(summary(LO_nmG_SFb$`w.o. Q34IBTS+BITS+CodSD21-25`))


woq1 <- data.frame(Year = as.integer(row.names(summary(LO_nmG_SFb$`w.o. Q1IBTS+BITS+CodSD21-25`))),
    SSB = q1mat$SSB, Fbar = q1mat$`Fbar(3-5)`, R_age1 = q1mat$`R(age 1)`, CatchEst = catchtable(LO_nmG_SFb$`w.o. Q1IBTS+BITS+CodSD21-25`)[,
        1], series = rep("wo_Q1", times = nrow(q1mat)))

woq34 <- data.frame(Year = as.integer(row.names(q3mat[(2002:DataYear) - 2001, ])),
    SSB = q3mat[(2002:DataYear) - 2001, "SSB"], Fbar = q3mat[(2002:DataYear) - 2001,
        "Fbar(3-5)"], R_age1 = q3mat[(2002:DataYear) - 2001, "R(age 1)"], CatchEst = catchtable(LO_nmG_SFb$`w.o. Q34IBTS+BITS+CodSD21-25`)[,
        1], series = rep("wo_Q34", times = (nrow(q3mat) - 1)))


asum_nmG_SFb$series <- rep("full", times = nrow(asum_nmG_SFb))
asumi_nmG_SFb <- asum_nmG_SFb[, c("Year", "SSB", "Fbar", "R_age1", "CatchEst", "series")]
# =====

losum_nmG_SFb <- rbind(woq1, woq34, asumi_nmG_SFb)
# ssbplot(LO)
lossb_nmG_SFb <- ggplotly(ggplot() + geom_line(data = losum_nmG_SFb, mapping = aes(x = Year,
    y = SSB, colour = series)) + geom_ribbon(data = asum_nmG_SFb, mapping = aes(x = Year,
    ymin = SSBlow, ymax = SSBhigh), fill = "black", alpha = 0.2) + scale_colour_manual(values = c("black",
    ebpal[8:9])) + theme_clean() + theme(axis.title.y.left = element_text(vjust = -0.05,
    hjust = 0.95)))

# Fplot(LO)
lof_nmG_SFb <- ggplotly(ggplot() + geom_line(data = losum_nmG_SFb, mapping = aes(x = Year,
    y = Fbar, colour = series)) + geom_ribbon(data = asum_nmG_SFb, mapping = aes(x = Year,
    ymin = Flow, ymax = Fhigh), fill = "black", alpha = 0.3) + scale_colour_manual(values = c("black",
    ebpal[8:9])) + theme_clean() + theme(axis.title.y.left = element_text(vjust = -0.05,
    hjust = 0.95)))

# recplot(LO)
lorec_nmG_SFb <- ggplotly(ggplot() + geom_line(data = losum_nmG_SFb, mapping = aes(x = Year,
    y = R_age1, colour = series)) + geom_ribbon(data = asum_nmG_SFb, mapping = aes(x = Year,
    ymin = Rlow, ymax = Rhigh), fill = "black", alpha = 0.3) + scale_colour_manual(values = c("black",
    ebpal[8:9])) + theme_clean() + theme(axis.title.y.left = element_text(vjust = -0.05,
    hjust = 0.95)))

# Catch plot (LO)
loca_nmG_SFb <- ggplotly(ggplot() + geom_line(data = losum_nmG_SFb, mapping = aes(x = Year,
    y = CatchEst, colour = series)) + geom_ribbon(data = asum_nmG_SFb[asum_nmG_SFb$Year !=
    (DataYear + 1), ], mapping = aes(x = Year, ymin = Catchlow, ymax = Catchhigh),
    fill = "black", alpha = 0.3) + geom_point(data = asum_nmG_SFb[asum_nmG_SFb$Year !=
    (DataYear + 1), ], mapping = aes(x = Year, y = CatchObs), shape = 3, colour = ebpal[5],
    fill = ebpal[5]) + ylab("Catch (tonnes)") + scale_colour_manual(values = c("black",
    ebpal[8:9])) + theme_clean() + theme(axis.title.y.left = element_text(vjust = -0.05,
    hjust = 0.95)))

layout(subplot(lossb_nmG_SFb, lof_nmG_SFb, lorec_nmG_SFb, loca_nmG_SFb, nrows = 2,
    shareX = TRUE, titleY = TRUE), showlegend = FALSE)

Figure 4.16: Leave-one-out re-fits for the Time invariant, scaled, Gislason natural mortalities calculated from life-history off of fishbase (without Q1 survey = blue, without Q3/4 survey = purple), overlain with full model estimates (black line and grey ribbon) of SSB (top left), F (top right), Recruitment (bottom left), and catch (bottom right; observations as yellow +).

4.2.2.5 Retrospectives

# === Create dataframe of current year's fit for plotting ==== IC_agg_temp <-
# aggregate(CATON~Year, ic_clean[ic_clean$CatchCategory %in% c('Landings',
# 'Discards'), ], FUN = 'sum')
asum_nmG_SFb <- as.data.frame(summary(fit_nmG_SFb))
asum_nmG_SFb$Year <- as.integer(row.names(summary(fit_nmG_SFb)))
ct_nmG_SFb <- as.data.frame(catchtable(fit_nmG_SFb, obs.show = TRUE))
ct_nmG_SFb$Year <- as.integer(rownames(ct_nmG_SFb))
rownames(ct_nmG_SFb) <- NULL
ct_nmG_SFb <- rbind(ct_nmG_SFb, data.frame(Estimate = NA, Low = NA, High = NA, sop.catch = NA,
    Year = as.integer(2024)))
asum_nmG_SFb <- merge(x = asum_nmG_SFb, y = ct_nmG_SFb, by = "Year")
colnames(asum_nmG_SFb) <- c("Year", "R_age1", "Rlow", "Rhigh", "SSB", "SSBlow", "SSBhigh",
    "Fbar", "Flow", "Fhigh", "CatchEst", "Catchlow", "Catchhigh", "CatchObs")

asum_nmG_SFb$series <- rep("full", times = nrow(asum_nmG_SFb))

# =====
RETRO_nmG_SFb <- retro(fit_nmG_SFb, year = 5)
rho_nmG_SFb <- mohn(RETRO_nmG_SFb, lag = 1)

## Make RETROs in better plotting format
ret_nmG_SFb_df <- asum_nmG_SFb[asum_nmG_SFb$Year != max(asum_nmG_SFb$Year), ]

for (i in 1:length(RETRO_nmG_SFb)) {
    tsum <- as.data.frame(summary(RETRO_nmG_SFb[[i]]))
    tsum$Year <- as.integer(row.names(summary(RETRO_nmG_SFb[[i]])))
    tsum <- cbind(tsum, catchtable(RETRO_nmG_SFb[[i]], obs.show = TRUE))
    tsum$series <- as.character(rep(i, nrow(tsum)))
    colnames(tsum) <- c("R_age1", "Rlow", "Rhigh", "SSB", "SSBlow", "SSBhigh", "Fbar",
        "Flow", "Fhigh", "Year", "CatchEst", "Catchlow", "Catchhigh", "CatchObs",
        "series")
    tsum <- tsum[tsum$Year != max(tsum$Year), ]
    ret_nmG_SFb_df <- rbind(ret_nmG_SFb_df, tsum)
}
ret_nmG_SFb_df$series <- factor(ret_nmG_SFb_df$series, levels = c("full", "1", "2",
    "3", "4", "5"))
# ssbplot(RETRO)
retssb_nmG_SFb <- layout(ggplotly(ggplot() + geom_line(data = ret_nmG_SFb_df, mapping = aes(x = Year,
    y = SSB, colour = series)) + geom_ribbon(data = asum_nmG_SFb[asum_nmG_SFb$Year !=
    max(asum_nmG_SFb$Year), ], mapping = aes(x = Year, ymin = SSBlow, ymax = SSBhigh),
    fill = "black", alpha = 0.2) + annotate(geom = "text", y = max(ret_nmG_SFb_df$SSBhigh) *
    0.85, x = ((max(ret_nmG_SFb_df$Year) - min(ret_nmG_SFb_df$Year)) * 0.2) + min(ret_nmG_SFb_df$Year),
    label = paste0("Mohn's Rho = ", round(rho_nmG_SFb[2], digits = 3))) + scale_colour_manual(values = c("black",
    ebpal[(length(ebpal) - 4):length(ebpal)])) + theme_clean() + theme(legend.position = "none",
    axis.title.y.left = element_text(vjust = -0.05, hjust = 0.95))), showlegend = FALSE)

# Fplot(RETRO)
retf_nmG_SFb <- layout(ggplotly(ggplot() + geom_line(data = ret_nmG_SFb_df, mapping = aes(x = Year,
    y = Fbar, colour = series)) + geom_ribbon(data = asum_nmG_SFb[asum_nmG_SFb$Year !=
    max(asum_nmG_SFb$Year), ], mapping = aes(x = Year, ymin = Flow, ymax = Fhigh),
    fill = "black", alpha = 0.3) + annotate(geom = "text", y = max(ret_nmG_SFb_df$Fhigh) *
    0.85, x = ((max(ret_nmG_SFb_df$Year) - min(ret_nmG_SFb_df$Year)) * 0.8) + min(ret_nmG_SFb_df$Year),
    label = paste0("Mohn's Rho = ", round(rho_nmG_SFb[3], digits = 3))) + scale_colour_manual(values = c("black",
    ebpal[(length(ebpal) - 4):length(ebpal)])) + theme_clean() + theme(legend.position = "none",
    axis.title.y.left = element_text(vjust = -0.05, hjust = 0.95))), showlegend = FALSE)

# recplot(RETRO)
retrec_nmG_SFb <- layout(ggplotly(ggplot() + geom_line(data = ret_nmG_SFb_df, mapping = aes(x = Year,
    y = R_age1, colour = series)) + geom_ribbon(data = asum_nmG_SFb[asum_nmG_SFb$Year !=
    max(asum_nmG_SFb$Year), ], mapping = aes(x = Year, ymin = Rlow, ymax = Rhigh),
    fill = "black", alpha = 0.3) + annotate(geom = "text", y = max(ret_nmG_SFb_df$Rhigh) *
    0.85, x = ((max(ret_nmG_SFb_df$Year) - min(ret_nmG_SFb_df$Year)) * 0.2) + min(ret_nmG_SFb_df$Year),
    label = paste0("Mohn's Rho = ", round(rho_nmG_SFb[1], digits = 3))) + scale_colour_manual(values = c("black",
    ebpal[(length(ebpal) - 4):length(ebpal)])) + theme_clean() + theme(legend.position = "none",
    axis.title.y.left = element_text(vjust = -0.05, hjust = 0.95))), showlegend = FALSE)

# Catch plot (RETRO)
retca_nmG_SFb <- ggplotly(ggplot() + geom_line(data = ret_nmG_SFb_df, mapping = aes(x = Year,
    y = CatchEst, colour = series)) + geom_ribbon(data = asum_nmG_SFb[asum_nmG_SFb$Year !=
    max(asum_nmG_SFb$Year), ], mapping = aes(x = Year, ymin = Catchlow, ymax = Catchhigh),
    fill = "black", alpha = 0.3) + geom_point(data = asum_nmG_SFb[asum_nmG_SFb$Year !=
    max(asum_nmG_SFb$Year), ], mapping = aes(x = Year, y = CatchObs), shape = 3,
    colour = ebpal[5], fill = ebpal[5]) + ylab("Catch (tonnes)") + scale_colour_manual(values = c("black",
    ebpal[(length(ebpal) - 4):length(ebpal)])) + theme_clean() + theme(axis.title.y.left = element_text(vjust = -0.05,
    hjust = 0.95)))

ret_fp <- style(subplot(retssb_nmG_SFb, retf_nmG_SFb, retrec_nmG_SFb, retca_nmG_SFb,
    nrows = 2, shareX = FALSE, shareY = FALSE, titleY = TRUE), showlegend = FALSE,
    traces = c(8:((7 * 4) + 2)))

layout(ret_fp, legend = list(orientation = "h", x = 0.5, xanchor = "center", y = -0.05,
    yanchor = "top", borderwidth = 0))

Figure 4.17: Retrospective analyses for SSB (top-left), F for ages 3-5 (top-right), recruitment (bottom-left), and catch (bottom-right), from the model utilising SCALED time invariant, Gislason natural mortalities (FishBase).

4.3 Time and Age Variant, Gislason Natural Mortalities

An alternate way to dealing with the issue of taking the unweighted means over the time series is to not use the full time-series means. While the life-history parameters \(L_{\infty}\) and \(K\) are calculated from all ages observations (q1 surveys) for the whole time series, they can be applied in the Gislason model to specific years, by utilising the lengths at age for each year. Due to the sampling rates these data will be inherently noisey, just as is the case for the stock weights at age and the maturity ogives, hence we need some method of smoothing out this noise. In this example we utilise a five-year sliding window mean on the annual estimates of natural mortality at age, to allow mortality at age to vary in time without introducing too much interannual variation.

fit_nmG5Fb <- fitfromweb("ple.27.21-32_WKBPLAICE_2024_BioParsw_nmG5Fb")
# === Create dataframe of current year's fit for plotting ====
asum_nmG5Fb <- as.data.frame(summary(fit_nmG5Fb))
asum_nmG5Fb$Year <- as.integer(row.names(summary(fit_nmG5Fb)))
ct_nmG5Fb <- as.data.frame(catchtable(fit_nmG5Fb, obs.show = TRUE))
ct_nmG5Fb$Year <- as.integer(rownames(ct_nmG5Fb))
rownames(ct_nmG5Fb) <- NULL
ct_nmG5Fb <- rbind(ct_nmG5Fb, data.frame(Estimate = NA, Low = NA, High = NA, sop.catch = NA,
    Year = as.integer(2024)))
asum_nmG5Fb <- merge(x = asum_nmG5Fb, y = ct_nmG5Fb, by = "Year")
colnames(asum_nmG5Fb) <- c("Year", "R_age1", "Rlow", "Rhigh", "SSB", "SSBlow", "SSBhigh",
    "Fbar", "Flow", "Fhigh", "CatchEst", "Catchlow", "Catchhigh", "CatchObs")
# =====

4.3.1 Fits to data

When the model is run we can easily see from warnings/errors if there is a convergence issue. However, we can also confirm this, explicitly: - The final model gradient: 136 - That there is a positive definite hessian: TRUE

Furthermore, SAM does not utilise “bounds” when fitting the model, and therefore, as standard check of whether model parameters are approaching their bounds is irrelevant.

## Extract data from model object
logObs_nmG5Fb <- split(fit_nmG5Fb$data$logobs, ceiling(seq_along(fit_nmG5Fb$data$logobs)/fit_nmG5Fb$data$maxAgePerFleet[1]))
logPred_nmG5Fb <- split(fit_nmG5Fb$rep$predObs, ceiling(seq_along(fit_nmG5Fb$rep$predObs)/fit_nmG5Fb$data$maxAgePerFleet[1]))

## Transform data to useable dataframes
### Initialize an empty data frame for observations
logObs_nmG5Fb_df <- data.frame(age = integer(),
                               fleet = integer(),
                               year = integer(),
                               logObs = numeric())

### Populate the data frame for observations
for (i in seq_along(logObs_nmG5Fb)) {
  # Calculate the group and year
  year <- ((i - 1) %/% 3) + 1
  fleet <- ((i - 1) %% 3) + 1
  
  ### Create a temporary data frame and append to the main data frame for observations
  temp_df <- data.frame(age = 1:7,
                        fleet = fleet,
                        year = year+2001,
                        logObs = logObs_nmG5Fb[[i]])
  logObs_nmG5Fb_df <- rbind(logObs_nmG5Fb_df, temp_df)
}

### Initialize an empty data frame for predictions
logPred_nmG5Fb_df <- data.frame(age = integer(),
                                fleet = integer(),
                                year = integer(),
                                logPred = numeric())

### Populate the data frame for predictions
for (i in seq_along(logPred_nmG5Fb)) {
  # Calculate the group and year
  year <- ((i - 1) %/% 3) + 1
  fleet <- ((i - 1) %% 3) + 1
  
  ### Create a temporary data frame and append to the main data frame for predictions
  temp_df <- data.frame(age = 1:7,
                        fleet = fleet,
                        year = year+2001,
                        logPred = logPred_nmG5Fb[[i]])
  logPred_nmG5Fb_df <- rbind(logPred_nmG5Fb_df, temp_df)
}

## Plot
logPred_nmG5Fb_df$age <- as.character(logPred_nmG5Fb_df$age)
logObs_nmG5Fb_df$age <- as.character(logObs_nmG5Fb_df$age)

ggplotly(ggplot()+
           geom_point(data = logObs_nmG5Fb_df[logObs_nmG5Fb_df$fleet == 1 & logObs_nmG5Fb_df$year != (DataYear+1), ],
                      mapping = aes(x = year,
                                    y = logObs,
                                    colour = age),
                      shape = 21) +
           geom_line(data = logPred_nmG5Fb_df[logPred_nmG5Fb_df$fleet == 1 & logPred_nmG5Fb_df$year != (DataYear+1), ],
                     mapping = aes(x = year,
                                   y = logPred,
                                   colour = age)) +
           facet_wrap(facets = "age") + #, scales = "free_y") +
           scale_color_manual(values = ebpal, guide = FALSE) +
           guides(colour=FALSE, shape=FALSE) +
           theme_few())

Figure 4.18: Model with time varying (five year sliiding window mean), age varying, Gislason natural mortalities (FishBase) fit to catch data by age (values on the model link function scale).

# fitplot(fit_nmG5Fb, fleets=1)
ggplotly(ggplot()+
           geom_point(data = logObs_nmG5Fb_df[logObs_nmG5Fb_df$fleet == 2 & logObs_nmG5Fb_df$year != (DataYear+1), ],
                      mapping = aes(x = year,
                                    y = logObs,
                                    colour = age),
                      shape = 21) +
           geom_line(data = logPred_nmG5Fb_df[logPred_nmG5Fb_df$fleet == 2 & logPred_nmG5Fb_df$year != (DataYear+1), ],
                     mapping = aes(x = year,
                                   y = logPred,
                                   colour = age)) +
           facet_wrap(facets = "age") + #, scales = "free_y") +
           scale_color_manual(values = ebpal, guide = FALSE) +
           guides(colour=FALSE, shape=FALSE) +
           theme_few())

Figure 4.19: Model with time varying (five year sliiding window mean), age varying, Gislason natural mortalities (FishBase) fit to Q1 survey data by age (values on the model link function scale).

# fitplot(fit_nmG5Fb, fleets=2)
ggplotly(ggplot()+
           geom_point(data = logObs_nmG5Fb_df[logObs_nmG5Fb_df$fleet == 3 & logObs_nmG5Fb_df$year != (DataYear+1), ],
                      mapping = aes(x = year,
                                    y = logObs,
                                    colour = age),
                      shape = 21) +
           geom_line(data = logPred_nmG5Fb_df[logPred_nmG5Fb_df$fleet == 3 & logPred_nmG5Fb_df$year != (DataYear+1), ],
                     mapping = aes(x = year,
                                   y = logPred,
                                   colour = age)) +
           facet_wrap(facets = "age") + #, scales = "free_y") +
           scale_color_manual(values = ebpal, guide = FALSE) +
           guides(colour=FALSE, shape=FALSE) +
           theme_few())

Figure 4.20: Model with time varying (five year sliiding window mean), age varying, Gislason natural mortalities (FishBase) fit to Q3/4 survey data by age (values on the model link function scale).

# fitplot(fit_nmG5Fb, fleets=3)
sdplot(fit_nmG5Fb, marg = c(5, 4, 1, 1))
Standard Devations by Fleet; Gislason, time-varying mortality (FishBase)

Figure 4.21: Standard Devations by Fleet; Gislason, time-varying mortality (FishBase)

4.3.2 Residuals

resid_nmG5Fb <- residuals(fit_nmG5Fb)
resid_nmG5Fb_df <- data.frame(year = resid_nmG5Fb$year, fleet = resid_nmG5Fb$fleet,
    age = resid_nmG5Fb$age, observation = resid_nmG5Fb$observation, mean = resid_nmG5Fb$mean,
    residual = resid_nmG5Fb$residual)
resid_nmG5Fb_df$fleetName <- ifelse(resid_nmG5Fb_df$fleet == 1, attributes(resid_nmG5Fb)$fleetNames[1],
    ifelse(resid_nmG5Fb_df$fleet == 2, attributes(resid_nmG5Fb)$fleetNames[2], ifelse(resid_nmG5Fb_df$fleet ==
        3, attributes(resid_nmG5Fb)$fleetNames[3], NA)))

resid_nmG5Fb_df$fleetAltName <- ifelse(resid_nmG5Fb_df$fleet == 1, "Residual Fishing",
    ifelse(resid_nmG5Fb_df$fleet == 2, "Q1 Surveys", ifelse(resid_nmG5Fb_df$fleet ==
        3, "Q3/4 Surveys", NA)))
if (!all(fit_nmG5Fb$conf$obsCorStruct == "ID")) {
    corplot(fit_nmG5Fb)
    # setcap('Estimated correlations', 'Estimates correlations between age
    # groups for each fleet') stampit(fit)
} else {
    print("No correlation structure configured for residuals across age.")
}
Estimated correlations in residual variation between ages for each of the fishing fleet (top) and the two surveys (middle & bottom), from the Model with time varying (five year sliiding window mean), age varying, Gislason natural mortalities (FishBase).

Figure 4.22: Estimated correlations in residual variation between ages for each of the fishing fleet (top) and the two surveys (middle & bottom), from the Model with time varying (five year sliiding window mean), age varying, Gislason natural mortalities (FishBase).

ggplotly(ggplot(resid_nmG5Fb_df) + geom_point(mapping = aes(x = year, y = age, size = abs(residual),
    colour = residual >= 0), alpha = 0.7) + facet_grid(rows = "fleetAltName") + scale_colour_manual(values = c(`TRUE` = ebpal[8],
    `FALSE` = ebpal[9])) + scale_y_continuous(limits = c(-1, 9), breaks = c(1:9)) +
    guides(colour = FALSE) + theme_few())

Figure 4.23: One observation ahead residuals for the three fleets (red/pink = observation lower than model estimate, blue = observation higher than model estimate, size = magnitude of residual), from the Model with time varying (five year sliiding window mean), age varying, Gislason natural mortalities (FishBase).

4.3.2.1 Jittering

We can also test to see if the model is converging on some local minimum (i.e. it’s fitting to some solution close to initialising values that represents noise and not the global solution, that is the proper solution). To do this, we add random noise to the initial parameter values to see if the model will converge on a different minimum in it’s data-space. The easiest way to investigate this is to see if the model fits vary alot depending on the starting values:

jit_nmG5Fb <- jit(fit = fit_nmG5Fb)

mt <- as.data.frame(modeltable(jit_nmG5Fb))
mt$model <- rownames(mt)
rownames(mt) <- NULL

kable(x = mt, digits = 3, caption = "Measures of  fit for a series of model refits with jitter applied to the input parameters.")
(#tab:Jitter_nmG5Fb)Measures of fit for a series of model refits with jitter applied to the input parameters.
log(L) #par AIC model
-95.16 36 262.32 M1
-95.16 36 262.32 M2
-95.16 36 262.32 M3
-95.16 36 262.32 M4
-95.16 36 262.32 M5
-95.16 36 262.32 M6
-95.16 36 262.32 M7
-95.16 36 262.32 M8
-95.16 36 262.32 M9
-95.16 36 262.32 M10
-95.16 36 262.32 M11

4.3.2.2 Leave-One-Out Analyses

A leave-one-out analysis is a form of sensitivity analysis, showing the impact the data from each tuning fleet has on the estimation of the key variables being estimated; namely SSB, F and recruitment.

First we must run the leave-one-out analysis which refits the model in two iterations, removing one survey at a time. Then we can plot each of these new model fits over the full model to see the impact the removal of each has.

LO_nmG5Fb <- leaveout(fit_nmG5Fb)

# === Get data from sam objects and generate useable dataframes ====
q1mat <- as.data.frame(summary(LO_nmG5Fb$`w.o. Q1IBTS+BITS+CodSD21-25`))
q3mat <- as.data.frame(summary(LO_nmG5Fb$`w.o. Q34IBTS+BITS+CodSD21-25`))


woq1 <- data.frame(Year = as.integer(row.names(summary(LO_nmG5Fb$`w.o. Q1IBTS+BITS+CodSD21-25`))),
    SSB = q1mat$SSB, Fbar = q1mat$`Fbar(3-5)`, R_age1 = q1mat$`R(age 1)`, CatchEst = catchtable(LO_nmG5Fb$`w.o. Q1IBTS+BITS+CodSD21-25`)[,
        1], series = rep("wo_Q1", times = nrow(q1mat)))

woq34 <- data.frame(Year = as.integer(row.names(q3mat[(2002:DataYear) - 2001, ])),
    SSB = q3mat[(2002:DataYear) - 2001, "SSB"], Fbar = q3mat[(2002:DataYear) - 2001,
        "Fbar(3-5)"], R_age1 = q3mat[(2002:DataYear) - 2001, "R(age 1)"], CatchEst = catchtable(LO_nmG5Fb$`w.o. Q34IBTS+BITS+CodSD21-25`)[,
        1], series = rep("wo_Q34", times = (nrow(q3mat) - 1)))


asum_nmG5Fb$series <- rep("full", times = nrow(asum_nmG5Fb))
asumi_nmG5Fb <- asum_nmG5Fb[, c("Year", "SSB", "Fbar", "R_age1", "CatchEst", "series")]
# =====

losum_nmG5Fb <- rbind(woq1, woq34, asumi_nmG5Fb)
# ssbplot(LO)
lossb_nmG5Fb <- ggplotly(ggplot() + geom_line(data = losum_nmG5Fb, mapping = aes(x = Year,
    y = SSB, colour = series)) + geom_ribbon(data = asum_nmG5Fb, mapping = aes(x = Year,
    ymin = SSBlow, ymax = SSBhigh), fill = "black", alpha = 0.2) + scale_colour_manual(values = c("black",
    ebpal[8:9])) + theme_clean() + theme(axis.title.y.left = element_text(vjust = -0.05,
    hjust = 0.95)))

# Fplot(LO)
lof_nmG5Fb <- ggplotly(ggplot() + geom_line(data = losum_nmG5Fb, mapping = aes(x = Year,
    y = Fbar, colour = series)) + geom_ribbon(data = asum_nmG5Fb, mapping = aes(x = Year,
    ymin = Flow, ymax = Fhigh), fill = "black", alpha = 0.3) + scale_colour_manual(values = c("black",
    ebpal[8:9])) + theme_clean() + theme(axis.title.y.left = element_text(vjust = -0.05,
    hjust = 0.95)))

# recplot(LO)
lorec_nmG5Fb <- ggplotly(ggplot() + geom_line(data = losum_nmG5Fb, mapping = aes(x = Year,
    y = R_age1, colour = series)) + geom_ribbon(data = asum_nmG5Fb, mapping = aes(x = Year,
    ymin = Rlow, ymax = Rhigh), fill = "black", alpha = 0.3) + scale_colour_manual(values = c("black",
    ebpal[8:9])) + theme_clean() + theme(axis.title.y.left = element_text(vjust = -0.05,
    hjust = 0.95)))

# Catch plot (LO)
loca_nmG5Fb <- ggplotly(ggplot() + geom_line(data = losum_nmG5Fb, mapping = aes(x = Year,
    y = CatchEst, colour = series)) + geom_ribbon(data = asum_nmG5Fb[asum_nmG5Fb$Year !=
    (DataYear + 1), ], mapping = aes(x = Year, ymin = Catchlow, ymax = Catchhigh),
    fill = "black", alpha = 0.3) + geom_point(data = asum_nmG5Fb[asum_nmG5Fb$Year !=
    (DataYear + 1), ], mapping = aes(x = Year, y = CatchObs), shape = 3, colour = ebpal[5],
    fill = ebpal[5]) + ylab("Catch (tonnes)") + scale_colour_manual(values = c("black",
    ebpal[8:9])) + theme_clean() + theme(axis.title.y.left = element_text(vjust = -0.05,
    hjust = 0.95)))

layout(subplot(lossb_nmG5Fb, lof_nmG5Fb, lorec_nmG5Fb, loca_nmG5Fb, nrows = 2, shareX = TRUE,
    titleY = TRUE), showlegend = FALSE)

Figure 4.24: Leave-one-out re-fits for the Time varying, Gislason natural mortalities calculated from life-history off of fishbase (without Q1 survey = blue, without Q3/4 survey = purple), overlain with full model estimates (black line and grey ribbon) of SSB (top left), F (top right), Recruitment (bottom left), and catch (bottom right; observations as yellow +).

4.3.3 Retrospectives

# === Create dataframe of current year's fit for plotting ==== IC_agg_temp <-
# aggregate(CATON~Year, ic_clean[ic_clean$CatchCategory %in% c('Landings',
# 'Discards'), ], FUN = 'sum')
asum_nmG5Fb <- as.data.frame(summary(fit_nmG5Fb))
asum_nmG5Fb$Year <- as.integer(row.names(summary(fit_nmG5Fb)))
ct_nmG5Fb <- as.data.frame(catchtable(fit_nmG5Fb, obs.show = TRUE))
ct_nmG5Fb$Year <- as.integer(rownames(ct_nmG5Fb))
rownames(ct_nmG5Fb) <- NULL
ct_nmG5Fb <- rbind(ct_nmG5Fb, data.frame(Estimate = NA, Low = NA, High = NA, sop.catch = NA,
    Year = as.integer(2024)))
asum_nmG5Fb <- merge(x = asum_nmG5Fb, y = ct_nmG5Fb, by = "Year")
colnames(asum_nmG5Fb) <- c("Year", "R_age1", "Rlow", "Rhigh", "SSB", "SSBlow", "SSBhigh",
    "Fbar", "Flow", "Fhigh", "CatchEst", "Catchlow", "Catchhigh", "CatchObs")

asum_nmG5Fb$series <- rep("full", times = nrow(asum_nmG5Fb))

# =====
RETRO_nmG5Fb <- retro(fit_nmG5Fb, year = 5)
rho_nmG5Fb <- mohn(RETRO_nmG5Fb, lag = 1)

## Make RETROs in better plotting format
ret_nmG5Fb_df <- asum_nmG5Fb[asum_nmG5Fb$Year != max(asum_nmG5Fb$Year), ]

for (i in 1:length(RETRO_nmG5Fb)) {
    tsum <- as.data.frame(summary(RETRO_nmG5Fb[[i]]))
    tsum$Year <- as.integer(row.names(summary(RETRO_nmG5Fb[[i]])))
    tsum <- cbind(tsum, catchtable(RETRO_nmG5Fb[[i]], obs.show = TRUE))
    tsum$series <- as.character(rep(i, nrow(tsum)))
    colnames(tsum) <- c("R_age1", "Rlow", "Rhigh", "SSB", "SSBlow", "SSBhigh", "Fbar",
        "Flow", "Fhigh", "Year", "CatchEst", "Catchlow", "Catchhigh", "CatchObs",
        "series")
    tsum <- tsum[tsum$Year != max(tsum$Year), ]
    ret_nmG5Fb_df <- rbind(ret_nmG5Fb_df, tsum)
}
ret_nmG5Fb_df$series <- factor(ret_nmG5Fb_df$series, levels = c("full", "1", "2",
    "3", "4", "5"))
# ssbplot(RETRO)
retssb_nmG5Fb <- layout(ggplotly(ggplot() + geom_line(data = ret_nmG5Fb_df, mapping = aes(x = Year,
    y = SSB, colour = series)) + geom_ribbon(data = asum_nmG5Fb[asum_nmG5Fb$Year !=
    max(asum_nmG5Fb$Year), ], mapping = aes(x = Year, ymin = SSBlow, ymax = SSBhigh),
    fill = "black", alpha = 0.2) + annotate(geom = "text", y = max(ret_nmG5Fb_df$SSBhigh) *
    0.85, x = ((max(ret_nmG5Fb_df$Year) - min(ret_nmG5Fb_df$Year)) * 0.2) + min(ret_nmG5Fb_df$Year),
    label = paste0("Mohn's Rho = ", round(rho_nmG5Fb[2], digits = 3))) + scale_colour_manual(values = c("black",
    ebpal[(length(ebpal) - 4):length(ebpal)])) + theme_clean() + theme(legend.position = "none",
    axis.title.y.left = element_text(vjust = -0.05, hjust = 0.95))), showlegend = FALSE)

# Fplot(RETRO)
retf_nmG5Fb <- layout(ggplotly(ggplot() + geom_line(data = ret_nmG5Fb_df, mapping = aes(x = Year,
    y = Fbar, colour = series)) + geom_ribbon(data = asum_nmG5Fb[asum_nmG5Fb$Year !=
    max(asum_nmG5Fb$Year), ], mapping = aes(x = Year, ymin = Flow, ymax = Fhigh),
    fill = "black", alpha = 0.3) + annotate(geom = "text", y = max(ret_nmG5Fb_df$Fhigh) *
    0.85, x = ((max(ret_nmG5Fb_df$Year) - min(ret_nmG5Fb_df$Year)) * 0.8) + min(ret_nmG5Fb_df$Year),
    label = paste0("Mohn's Rho = ", round(rho_nmG5Fb[3], digits = 3))) + scale_colour_manual(values = c("black",
    ebpal[(length(ebpal) - 4):length(ebpal)])) + theme_clean() + theme(legend.position = "none",
    axis.title.y.left = element_text(vjust = -0.05, hjust = 0.95))), showlegend = FALSE)

# recplot(RETRO)
retrec_nmG5Fb <- layout(ggplotly(ggplot() + geom_line(data = ret_nmG5Fb_df, mapping = aes(x = Year,
    y = R_age1, colour = series)) + geom_ribbon(data = asum_nmG5Fb[asum_nmG5Fb$Year !=
    max(asum_nmG5Fb$Year), ], mapping = aes(x = Year, ymin = Rlow, ymax = Rhigh),
    fill = "black", alpha = 0.3) + annotate(geom = "text", y = max(ret_nmG5Fb_df$Rhigh) *
    0.85, x = ((max(ret_nmG5Fb_df$Year) - min(ret_nmG5Fb_df$Year)) * 0.2) + min(ret_nmG5Fb_df$Year),
    label = paste0("Mohn's Rho = ", round(rho_nmG5Fb[1], digits = 3))) + scale_colour_manual(values = c("black",
    ebpal[(length(ebpal) - 4):length(ebpal)])) + theme_clean() + theme(legend.position = "none",
    axis.title.y.left = element_text(vjust = -0.05, hjust = 0.95))), showlegend = FALSE)

# Catch plot (RETRO)
retca_nmG5Fb <- ggplotly(ggplot() + geom_line(data = ret_nmG5Fb_df, mapping = aes(x = Year,
    y = CatchEst, colour = series)) + geom_ribbon(data = asum_nmG5Fb[asum_nmG5Fb$Year !=
    max(asum_nmG5Fb$Year), ], mapping = aes(x = Year, ymin = Catchlow, ymax = Catchhigh),
    fill = "black", alpha = 0.3) + geom_point(data = asum_nmG5Fb[asum_nmG5Fb$Year !=
    max(asum_nmG5Fb$Year), ], mapping = aes(x = Year, y = CatchObs), shape = 3, colour = ebpal[5],
    fill = ebpal[5]) + ylab("Catch (tonnes)") + scale_colour_manual(values = c("black",
    ebpal[(length(ebpal) - 4):length(ebpal)])) + theme_clean() + theme(axis.title.y.left = element_text(vjust = -0.05,
    hjust = 0.95)))

ret_fp <- style(subplot(retssb_nmG5Fb, retf_nmG5Fb, retrec_nmG5Fb, retca_nmG5Fb,
    nrows = 2, shareX = FALSE, shareY = FALSE, titleY = TRUE), showlegend = FALSE,
    traces = c(8:((7 * 4) + 2)))

layout(ret_fp, legend = list(orientation = "h", x = 0.5, xanchor = "center", y = -0.05,
    yanchor = "top", borderwidth = 0))

Figure 4.25: Retrospective analyses for SSB (top-left), F for ages 3-5 (top-right), recruitment (bottom-left), and catch (bottom-right), from the model utilising time variant (5 year sliding window mean), Gislason natural mortalities (FishBase).

4.4 Comparison of Natural Mortality Hypotheses

After interrogating the residuals and the model fits to observations, we can also compare the AICs of these models, as we’ve only modified the input data. We’ll also aggregate all of the Mohn’s rho values for easier comparisons.

4.4.1 Basic fit and diagnostic variables

nmAIC <- data.frame(`Type of M` = c("Historic M", "Time invariant, Gislason", "Optimally scaled, time invariant, Gislason",
    "Time varying (5ysw), Gislason", "Time invariant, Gislason & FishBase", "Optimally scaled, time invariant, Gislason & FishBase",
    "Time varying (5ysw), Gislason & FishBase"), AIC = c(AIC(fit_bio_5y_SV), AIC(fit_nmG),
    AIC(fit_nmGS), AIC(fit_nmG5ysw), AIC(fit_nmGFb), AIC(fit_nmG_SFb), AIC(fit_nmG5Fb)),
    No.Params = c(length(coef(fit_bio_5y_SV)), length(coef(fit_nmG)), length(coef(fit_nmGS)),
        length(coef(fit_nmG5ysw)), length(coef(fit_nmGFb)), length(coef(fit_nmG_SFb)),
        length(coef(fit_nmG5Fb))), Rho.SSB = c(rho_bio_5y_SV[2], rho_nmG[2], rho_nmGS[2],
        rho_nmG5ysw[2], rho_nmGFb[2], rho_nmG_SFb[2], rho_nmG5Fb[2]), Rho.F = c(rho_bio_5y_SV[3],
        rho_nmG[3], rho_nmGS[3], rho_nmG5ysw[3], rho_nmGFb[3], rho_nmG_SFb[3], rho_nmG5Fb[3]),
    Rho.Rec = c(rho_bio_5y_SV[1], rho_nmG[1], rho_nmGS[1], rho_nmG5ysw[1], rho_nmGFb[1],
        rho_nmG_SFb[1], rho_nmG5Fb[1]))

kable(nmAIC, caption = "Measures of model fit under various hypotheses of natural mortality.")
Table 4.1: Measures of model fit under various hypotheses of natural mortality.
Type.of.M AIC No.Params Rho.SSB Rho.F Rho.Rec
Historic M 327.2155 36 0.1201919 -0.0259916 0.3158176
Time invariant, Gislason 266.3056 36 0.0961543 -0.0177057 0.2170079
Optimally scaled, time invariant, Gislason 262.1331 36 0.0778651 0.0072884 0.1811353
Time varying (5ysw), Gislason 262.8897 36 0.0625855 -0.0177211 0.1195901
Time invariant, Gislason & FishBase 265.6402 36 0.0945449 -0.0156215 0.2137940
Optimally scaled, time invariant, Gislason & FishBase 262.1320 36 0.0759293 0.0101150 0.1773563
Time varying (5ysw), Gislason & FishBase 262.3204 36 0.0600907 -0.0158922 0.1149631

4.5 Comparison of model estimates

Now that we’ve considered the model fits, diagnostics and tuning, we might as well have a look at how the models’ estimates compare.

# ssblines <- data.frame(yintercept=c(4730, 4370, 3635), Lines = factor(x = c("MSY-Btrigger", "Bpa", "Blim"),levels = c("MSY-Btrigger", "Bpa", "Blim")))
pssb <- ggplot() +
  geom_line(data = asum_bio_5y_SV, 
            mapping = aes(x=Year,
                          y=SSB,
                          series="Historic nm"),
            colour = ebpal[1]) +
  geom_ribbon(data = asum_bio_5y_SV, 
              mapping = aes(x=Year,
                            ymin=SSBlow,
                            ymax=SSBhigh,
                            series="Historic nm"),
              fill = ebpal[1],
              alpha = 0.3) +
  geom_line(data = asum_nmG,
            mapping = aes(x=Year,
                          y=SSB,
                          series="Time-invariant Gislason nm"),
            colour = ebpal[2]) +
  geom_ribbon(data = asum_nmG,
              mapping = aes(x=Year,
                            ymin=SSBlow,
                            ymax=SSBhigh,
                            series="Time-invariant Gislason nm"),
              fill = ebpal[2],
              alpha = 0.3) +
  geom_line(data = asum_nmGS,
            mapping = aes(x=Year,
                          y=SSB,
                          series="Scaled, time-invariant Gislason nm"),
            colour = ebpal[3]) +
  geom_ribbon(data = asum_nmGS,
              mapping = aes(x=Year,
                            ymin=SSBlow,
                            ymax=SSBhigh,
                            series="Scaled, time-invariant Gislason nm"),
              fill = ebpal[3],
              alpha = 0.3) +
  geom_line(data = asum_nmG5ysw,
            mapping = aes(x=Year,
                          y=SSB,
                          series="Time varying (5ysw) Gislason nm"),
            colour = ebpal[4]) +
  geom_ribbon(data = asum_nmG5ysw,
              mapping = aes(x=Year,
                            ymin=SSBlow,
                            ymax=SSBhigh,
                            series="Time varying (5ysw) Gislason nm"),
              fill = ebpal[4],
              alpha = 0.3) +
  geom_line(data = asum_nmGFb,
            mapping = aes(x=Year,
                          y=SSB,
                          series="Time invariant, Gislason & FishBase"),
            colour = ebpal[5]) +
  geom_ribbon(data = asum_nmGFb,
              mapping = aes(x=Year,
                            ymin=SSBlow,
                            ymax=SSBhigh,
                            series="Time invariant, Gislason & FishBase"),
              fill = ebpal[5],
              alpha = 0.3) +
  geom_line(data = asum_nmG_SFb,
            mapping = aes(x=Year,
                          y=SSB,
                          series="Time invariant, scaled Gislason & FishBase"),
            colour = ebpal[6]) +
  geom_ribbon(data = asum_nmG_SFb,
              mapping = aes(x=Year,
                            ymin=SSBlow,
                            ymax=SSBhigh,
                            series="Time invariant, scaled Gislason & FishBase"),
              fill = ebpal[6],
              alpha = 0.3) +
  geom_line(data = asum_nmG5Fb,
            mapping = aes(x=Year,
                          y=SSB,
                          series="Time varying (5ysw) Gislason & FishBase"),
            
            colour = ebpal[7]) +
  geom_ribbon(data = asum_nmG5Fb,
              mapping = aes(x=Year,
                            ymin=SSBlow,
                            ymax=SSBhigh),
              series="Time varying (5ysw) Gislason & FishBase",
              fill = ebpal[7],
              alpha = 0.3) +
  theme_clean()

ggplotly(pssb, tooltip = c("series", "x", "y"))

Figure 4.26: Estimated spawning stock biomass for ple.27.21-32 and 95% confidence intervals (tonnes). Purple is the model with the historic mortalities, dark green is with time invariant Gislason mortalities, dark orange is with scaled-time-invariant Gislason mortalities, and blue is with time varying Gislason mortalities. Yellow, light-green, and light-orange, are in the same order as the previous three, except all mortalities are calculated with life-history data from FishBase, instead of survey observations.

Fishing pressure over time seems to respond to the changes in the estimations of SSB, while input data for catches (obviously) remain the same betwen the two models.

# flines <- data.frame(yintercept=c(0.31, 0.81, 1.00), Lines = factor(x =
# c('FMSY', 'Fpa', 'Flim'), levels = c('FMSY', 'Fpa', 'Flim')))
ggplotly(ggplot() + geom_line(data = asum_bio_5y_SV, mapping = aes(x = Year, y = Fbar,
    series = "Historic nm"), colour = ebpal[1]) + geom_ribbon(data = asum_bio_5y_SV,
    mapping = aes(x = Year, ymin = Flow, ymax = Fhigh, series = "Historic nm"), fill = ebpal[1],
    alpha = 0.3) + geom_line(data = asum_nmG, mapping = aes(x = Year, y = Fbar, series = "Time-invariant Gislason nm"),
    colour = ebpal[2]) + geom_ribbon(data = asum_nmG, mapping = aes(x = Year, ymin = Flow,
    ymax = Fhigh, series = "Time-invariant Gislason nm"), fill = ebpal[2], alpha = 0.3) +
    geom_line(data = asum_nmGS, mapping = aes(x = Year, y = Fbar, series = "Scaled, time-invariant Gislason nm"),
        colour = ebpal[3]) + geom_ribbon(data = asum_nmGS, mapping = aes(x = Year,
    ymin = Flow, ymax = Fhigh, series = "Scaled, time-invariant Gislason nm"), fill = ebpal[3],
    alpha = 0.3) + geom_line(data = asum_nmG5ysw, mapping = aes(x = Year, y = Fbar,
    series = "Time varying (5ysw) Gislason nm"), colour = ebpal[4]) + geom_ribbon(data = asum_nmG5ysw,
    mapping = aes(x = Year, ymin = Flow, ymax = Fhigh, series = "Time varying (5ysw) Gislason nm"),
    fill = ebpal[4], alpha = 0.3) + geom_line(data = asum_nmGFb, mapping = aes(x = Year,
    y = Fbar, series = "Time invariant, Gislason & FishBase"), colour = ebpal[5]) +
    geom_ribbon(data = asum_nmGFb, mapping = aes(x = Year, ymin = Flow, ymax = Fhigh,
        series = "Time invariant, Gislason & FishBase"), fill = ebpal[5], alpha = 0.3) +
    geom_line(data = asum_nmG_SFb, mapping = aes(x = Year, y = Fbar, series = "Time invariant, scaled Gislason & FishBase"),
        colour = ebpal[6]) + geom_ribbon(data = asum_nmG_SFb, mapping = aes(x = Year,
    ymin = Flow, ymax = Fhigh, series = "Time invariant, scaled Gislason & FishBase"),
    fill = ebpal[6], alpha = 0.3) + geom_line(data = asum_nmG5Fb, mapping = aes(x = Year,
    y = Fbar, series = "Time varying (5ysw) Gislason & FishBase"), colour = ebpal[7]) +
    geom_ribbon(data = asum_nmG5Fb, mapping = aes(x = Year, ymin = Flow, ymax = Fhigh,
        series = "Time varying (5ysw) Gislason & FishBase"), fill = ebpal[7], alpha = 0.3) +
    theme_clean())

Figure 4.27: Annual fishing mortality estimates for ple.27.21-32 ages 3-5 and point wise 95% confidence intervals are shown by line and shaded area. Purple is the model with the historic mortalities, dark green is with time invariant Gislason mortalities, dark orange is with scaled-time-invariant Gislason mortalities, and blue is with time varying Gislason mortalities. Yellow, light-green, and light-orange, are in the same order as the previous three, except all mortalities are calculated with life-history data from FishBase, instead of survey observations.

Estimations of recruitment in the most recent years fall, as SSB also falls in this version of the model, again probably due to the reduction in stock weights at age.

ggplotly(ggplot() + geom_line(data = asum_bio_5y_SV, mapping = aes(x = Year, y = R_age1,
    series = "Historic nm"), colour = ebpal[1]) + geom_ribbon(data = asum_bio_5y_SV,
    mapping = aes(x = Year, ymin = Rlow, ymax = Rhigh, series = "Historic nm"), fill = ebpal[1],
    alpha = 0.3) + geom_line(data = asum_nmG, mapping = aes(x = Year, y = R_age1,
    series = "Time-invariant Gislason nm"), colour = ebpal[2]) + geom_ribbon(data = asum_nmG,
    mapping = aes(x = Year, ymin = Rlow, ymax = Rhigh, series = "Time-invariant Gislason nm"),
    fill = ebpal[2], alpha = 0.3) + geom_line(data = asum_nmGS, mapping = aes(x = Year,
    y = R_age1, series = "Scaled, time-invariant Gislason nm"), colour = ebpal[3]) +
    geom_ribbon(data = asum_nmGS, mapping = aes(x = Year, ymin = Rlow, ymax = Rhigh,
        series = "Scaled, time-invariant Gislason nm"), fill = ebpal[3], alpha = 0.3) +
    geom_line(data = asum_nmG5ysw, mapping = aes(x = Year, y = R_age1, series = "Time varying (5ysw) Gislason nm"),
        colour = ebpal[4]) + geom_ribbon(data = asum_nmG5ysw, mapping = aes(x = Year,
    ymin = Rlow, ymax = Rhigh, series = "Time varying (5ysw) Gislason nm"), fill = ebpal[4],
    alpha = 0.3) + geom_line(data = asum_nmGFb, mapping = aes(x = Year, y = R_age1,
    series = "Time invariant, Gislason & FishBase"), colour = ebpal[5]) + geom_ribbon(data = asum_nmGFb,
    mapping = aes(x = Year, ymin = Rlow, ymax = Rhigh, series = "Time invariant, Gislason & FishBase"),
    fill = ebpal[5], alpha = 0.3) + geom_line(data = asum_nmG_SFb, mapping = aes(x = Year,
    y = R_age1, series = "Time invariant, scaled Gislason & FishBase"), colour = ebpal[6]) +
    geom_ribbon(data = asum_nmG_SFb, mapping = aes(x = Year, ymin = Rlow, ymax = Rhigh,
        series = "Time invariant, scaled Gislason & FishBase"), fill = ebpal[6],
        alpha = 0.3) + geom_line(data = asum_nmG5Fb, mapping = aes(x = Year, y = R_age1,
    series = "Time varying (5ysw) Gislason & FishBase"), colour = ebpal[7]) + geom_ribbon(data = asum_nmG5Fb,
    mapping = aes(x = Year, ymin = Rlow, ymax = Rhigh, series = "Time varying (5ysw) Gislason & FishBase"),
    fill = ebpal[7], alpha = 0.3) + theme_clean())

Figure 4.28: Five year sliding window model annual recruitment estimates for ple.27.21-32 and point wise 95% confidence intervals are shown by line and shaded area (numbers). Purple is the model with the historic mortalities, dark green is with time invariant Gislason mortalities, dark orange is with scaled-time-invariant Gislason mortalities, and blue is with time varying Gislason mortalities. Yellow, light-green, and light-orange, are in the same order as the previous three, except all mortalities are calculated with life-history data from FishBase, instead of survey observations.

ggplotly(ggplot() + geom_line(data = asum_bio_5y_SV[asum_bio_5y_SV$Year != (DataYear +
    1), ], mapping = aes(x = Year, y = CatchEst, series = "Historic nm"), colour = ebpal[1]) +
    geom_ribbon(data = asum_bio_5y_SV[asum_bio_5y_SV$Year != (DataYear + 1), ], mapping = aes(x = Year,
        ymin = Catchlow, ymax = Catchhigh, series = "Historic nm"), fill = ebpal[1],
        alpha = 0.3) + geom_line(data = asum_nmG[asum_nmG$Year != (DataYear + 1),
    ], mapping = aes(x = Year, y = CatchEst, series = "Time-invariant Gislason nm"),
    colour = ebpal[2]) + geom_ribbon(data = asum_nmG[asum_nmG$Year != (DataYear +
    1), ], mapping = aes(x = Year, ymin = Catchlow, ymax = Catchhigh, series = "Time-invariant Gislason nm"),
    fill = ebpal[2], alpha = 0.3) + geom_line(data = asum_nmGS[asum_nmGS$Year !=
    (DataYear + 1), ], mapping = aes(x = Year, y = CatchEst, series = "Scaled, time-invariant Gislason nm"),
    colour = ebpal[3]) + geom_ribbon(data = asum_nmGS[asum_nmGS$Year != (DataYear +
    1), ], mapping = aes(x = Year, ymin = Catchlow, ymax = Catchhigh, series = "Scaled, time-invariant Gislason nm"),
    fill = ebpal[3], alpha = 0.3) + geom_line(data = asum_nmG5ysw[asum_nmG5ysw$Year !=
    (DataYear + 1), ], mapping = aes(x = Year, y = CatchEst, series = "Time varying (5ysw) Gislason nm"),
    colour = ebpal[4]) + geom_ribbon(data = asum_nmG5ysw[asum_nmG5ysw$Year != (DataYear +
    1), ], mapping = aes(x = Year, ymin = Catchlow, ymax = Catchhigh, series = "Time varying (5ysw) Gislason nm"),
    fill = ebpal[4], alpha = 0.3) + geom_point(data = asum_nmG5ysw[asum_nmG5ysw$Year !=
    (DataYear + 1), ], mapping = aes(x = Year, y = CatchObs), shape = 3, colour = "black",
    fill = "black") + geom_line(data = asum_nmGFb[asum_nmGFb$Year != (DataYear +
    1), ], mapping = aes(x = Year, y = CatchEst, series = "Time invariant, Gislason & FishBase"),
    colour = ebpal[5]) + geom_ribbon(data = asum_nmGFb[asum_nmGFb$Year != (DataYear +
    1), ], mapping = aes(x = Year, ymin = Catchlow, ymax = Catchhigh, series = "Time invariant, Gislason & FishBase"),
    fill = ebpal[5], alpha = 0.3) + geom_line(data = asum_nmG_SFb[asum_nmG_SFb$Year !=
    (DataYear + 1), ], mapping = aes(x = Year, y = CatchEst, series = "Time invariant, scaled Gislason & FishBase"),
    colour = ebpal[6]) + geom_ribbon(data = asum_nmG_SFb[asum_nmG_SFb$Year != (DataYear +
    1), ], mapping = aes(x = Year, ymin = Catchlow, ymax = Catchhigh, series = "Time invariant, scaled Gislason & FishBase"),
    fill = ebpal[6], alpha = 0.3) + geom_line(data = asum_nmG5Fb[asum_nmG5Fb$Year !=
    (DataYear + 1), ], mapping = aes(x = Year, y = CatchEst, series = "Time varying (5ysw) Gislason & FishBase"),
    colour = ebpal[7]) + geom_ribbon(data = asum_nmG5Fb[asum_nmG5Fb$Year != (DataYear +
    1), ], mapping = aes(x = Year, ymin = Catchlow, ymax = Catchhigh, series = "Time varying (5ysw) Gislason & FishBase"),
    fill = ebpal[7], alpha = 0.3) + ylab("Catch (tonnes)") + theme_clean())

Figure 4.29: Annual catch estimates and 95% confidence intervals (line and shaded area, respectively) for ple.27.21-32 and point annual observations (points). Purple is the model with the historic mortalities, dark green is with time invariant Gislason mortalities, dark orange is with scaled-time-invariant Gislason mortalities, and blue is with time varying Gislason mortalities. Yellow, light-green, and light-orange, are in the same order as the previous three, except all mortalities are calculated with life-history data from FishBase, instead of survey observations.

5 Conclusions

From the diagnostics of these plots we can see that the inclusion of the new natural mortality estimates greatly improves the model fits. Furthermore, we see that having age and time varying natural mortality provides the best fit overall. This is likely due to the fact that the Gislason mortalities are based on both life-history traits and size, and therefore, as the size at age has been decreasing over time, the time varying nm better matches this change than does a fixed, average nm based on average size. The option of time-varying nm is also internally coherent, as we have included time-varying stock weights-at-age as the best representation of stock development and so we should reflect this development in our estimations of natural mortality as well.

Hence, as discussed in the workshop plenary, there are three lines of reasoning for utilising the time & age varying Gislason et al (2010) natural mortality estimates:

  • With the historic age varying but time static natural mortalities (fixed as some “magic numbers”), our models all displayed residual patterns indicative of unexplained mortality.
  • Calculating natural mortalities based on the Gislason model, greatly increased natural mortalities and provided a typical mortality at age curve, which removed the unidirectional patterns in the residual catch at ages.
  • Scaling these time-invariant natural mortalities, calculated from time-series averages of size at age, simply selected for a model that had mortalities applied across the whole time-series, that were biased towards the higher mortalities seen in recent years.
  • The time-varying natural mortalities provides the best model fit (based on AIC)

In the next working document we will investigate the utility of setting maturity at age-1 to zero, based on basic biological knowledge of the species, and the fact that there may be some age reading errors meaning that older fish are being aged to 1. Furthermore, we will investigate a range of ways of including discard survival in the assessment process before finally attempting to include recently available German recreational fisheries data.

LS0tDQp0aXRsZTogIlBsZS4yNy4zYS4yMS0zMl9XS0JQTEFJQ0VfTmV3TW9ydGFsaXR5Ig0KYXV0aG9yOg0KICAtIG5hbWU6ICJFbGxpb3QgSi4gQnJvd24iDQogIC0gbmFtZTogIkNhc3BlciBXLiBCZXJnIg0KICAtIG5hbWU6ICJTdmVuIFN0w7Z0ZXJhIg0KZGF0ZTogImByIFN5cy5EYXRlKClgIg0Kb3V0cHV0OiANCiAgYm9va2Rvd246Omh0bWxfZG9jdW1lbnQyOg0KICAgIHRvYzogdHJ1ZQ0KICAgIHRvY19mbG9hdDogdHJ1ZQ0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCi0tLQ0KDQo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPg0KLm1haW4tY29udGFpbmVyIHsNCm1heC13aWR0aDogOTAlICFpbXBvcnRhbnQ7DQptYXJnaW46IGF1dG87DQp9DQpwLmNhcHRpb24gew0KZm9udC1zaXplOiAwLjhlbTsNCmZvbnQtc3R5bGU6IGl0YWxpYzsNCn0NCjwvc3R5bGU+DQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG89VFJVRSwNCiAgICAgICAgICAgICAgICAgICAgICBldmFsID0gVFJVRSwNCiAgICAgICAgICAgICAgICAgICAgICB3YXJuaW5nID0gRkFMU0UsDQogICAgICAgICAgICAgICAgICAgICAgZmlnLmFsaWduID0gImNlbnRlciIsDQogICAgICAgICAgICAgICAgICAgICAgdGlkeSA9ICdmb3JtYXRSJywNCiAgICAgICAgICAgICAgICAgICAgICBvdXQud2lkdGggPSAiOTAlIikNCg0KIz09PQ0KIyBNYW51YWwgc2V0dGluZ3MgZm9yIGZpZ3VyZSBmb3JtYXR0aW5nDQojPT09PQ0KIyBlYnBhbCA8LSBjKCIjMkYzRUVBIiwgIiMxRkQwODIiLCAiIzAzMEY0RiIsICIjRjZEMDREIiwgIiNGQzc2MzQiLCAiI0Y3QkJCMSIsICIjRTgzRjQ4IiwgIiMwMDg4MzUiLCAiIzc5MjM4RSIpDQplYnBhbCA8LSBjKCIjODAwMDgwIiwgIiMwMDY0MDAiLCAiI0Q1NUUwMCIsICIjMDA3MkIyIiwgIiNGMEU0NDIiLCAiIzAwOUU3MyIsICIjRTY5RjAwIiwgIiM1NkI0RTkiLCAiI0NDNzlBNyIsICIjNURBNURBIiwgIiNGRjgwMDAiLCAiIzg5Q0ZGMCIsICIjQTUyQTJBIiwgIiM3N0RENzciLCAiI0ZGRkFDRCIpDQojPT09PT0NCmBgYA0KDQojIEludHJvZHVjdGlvbg0KIyMgQWJvdXQgdGhpcyBkb2N1bWVudA0KVGhpcyB3b3JraW5nIGRvY3VtZW50IGlzIHRoZSBzZWNvbmQgc3RlcCBpbiBldmFsdWF0aW5nIHZhcmlvdXMgYXNzZXNzbWVudCBtb2RlbHMgZm9yIHRoZSBuZXdseSBjb21iaW5lZCBQbGFpY2Ugc3RvY2ssIGFjcm9zcyB0aGUgU3ViIERpdmlzaW9ucyAyMSAtIDMyLiAgSW4gdGhlIGZpcnN0IGRvY3VtZW50ICggX1BsZS4yNy4zYS4yMS0zMl9Bc3Nlc3NtZW50c18gKSwgU29tZSBvZiB0aGUgbW9yZSBmdW5kYW1lbnRhbCBkZWNpc2lvbnMgYWJvdXQgaW5wdXQgZGF0YSB3ZXJlIGV2YWx1YXRlZCBhbmQgZGVjaWRlZCB1cG9uLiBJbiB0aGlzIGRvY3VtZW50LCB3ZSBmb2N1cyBpbiBvbiBhbiBpc3N1ZSB0aGF0IGlzIG5ldyB0byB0aGUgc3RvY2tzIGluIHRoaXMgYXJlYSwgbmFtZWx5IG5hdHVyYWwgbW9ydGFsaXR5LiAgQmVjYXVzZSBvZiB0aGUgcmFwaWRseSBpbmNyZWFzaW5nIGRlbnNpdHkgZGVyaXZlZCBmcm9tIGNvbnNlY3V0aXZlIHllYXJzIG9mIGhpZ2ggcmVjcnVpdG1lbnQgYW5kIGxvdyBmaXNoaW5nIHByZXNzdXJlLCB3ZSBzZWUgZGVjcmVhc2luZyBzdG9jayB3ZWlnaHRzIGF0IGFnZSwgbGVuZ3RocyBhdCBhZ2UgYW5kIHdlIGFudGljaXBhdGUgaW5jcmVhc2luZyBtb3J0YWxpdHkgYWNyb3NzIGFnZXMuICBUaGlzIGlzIGVzcGVjaWFsbHkgdHJ1ZSBpbiB0aGUgeW91bmdlciBhZ2VzLCB3aGVyZSByZWNlbnQgcmVjb3JkIGJyZWFraW5nIGNvaG9ydHMgY29udGludWUgdG8gdG9wIGVhY2ggb3RoZXIuIEluIHRoaXMgZG9jdW1lbnQgd2UgaW52ZXN0aWdhdGUgdGhlIGRpZmZlcmVudCB3YXlzIHRoYXQgdGhlc2UgbmV3IGVzdGltYXRpb25zIG9mIG1vcnRhbGl0eSBjYW4gYmUgaW50cm9kdWNlZCB0byB0aGUgbW9kZWwgYW5kIHRoZSBlZmZlY3QgdGhhdCB0aGlzIGhhcyBvbiB0aGUgbW9kZWwgZml0IGFuZCBwcmVkaWN0aXZlIHBvd2VyLiANCg0KVGhyb3VnaG91dCB0aGUgZG9jdW1lbnQsIHRoZSBjb2RlIHVzZWQgdG8gdW5kZXJ0YWtlIGVhY2ggc3RlcCBwcmVjZWRlcyB0aGUgb3V0cHV0IGFuZCBjYW4gYmUgYWNjZXNzZWQgYnkgY2xpY2tpbmcgb24gdGhlIGRyb3AtZG93biBhcnJvd3MgdG8gdGhlIHJpZ2h0IG9mIHRoZSBwYWdlLg0KDQpEYXRhIGNvbXBpbGF0aW9uIGlzIGRvbmUgZXh0ZXJuYWxseSwgYW5kIHRoaXMgZG9jdW1lbnQgZGVhbHMgb25seSB3aXRoIHRoZSBmaW5hbGlzZWQgaW5wdXQgZmlsZXMuIEFsbCBtb2RlbHMgYXJlIGJ1aWxkIHVzaW5nIHRoZSBTdGF0ZS1TcGFjZSBBc3Nlc3NtZW50IE1vZGVsIChTQU0pLCBhbmQgaW4gdGhpcyB2ZXJzaW9uIG9mIHRoZSBkb2N1bWVudCwgYWxsIG1vZGVsIGlucHV0IGZpbGVzIGFuZCBjb25maWd1cmF0aW9ucyBhcmUgZG93bmxvYWRlZCBkaXJlY3RseSBmcm9tIHRoZSBwdWJsaWNseSBhdmFpbGFibGUgdmVyc2lvbnMgb24gW3N0b2NrYXNzZXNzbWVudC5vcmddKGh0dHBzOi8vc3RvY2thc3Nlc3NtZW50Lm9yZykuDQoNCiMjIFByZXBhcmF0aW9uDQpUbyBydW4gdGhlIHNjcmlwdHMgZW1iZWRkZWQgaW4gdGhpcyBkb2N1bWVudCAoaWYgeW91IHdvdWxkIGxpa2UgdG8gcnVuIHRoZSBhc3Nlc3NtZW50IHlvdXJzZWxmKSB5b3UgcmVxdWlyZSB0aGUgZm9sbG93aW5nIHBhY2thZ2VzIGFuZCBmdW5jdGlvbnM6DQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHJlc3VsdHM9ImhpZGUifQ0KcmVxdWlyZShkYXRhLnRhYmxlKQ0KcmVxdWlyZShyZXNoYXBlMikNCnJlcXVpcmUoa25pdHIpDQpyZXF1aXJlKHNjYWxlcykNCnJlcXVpcmUoYm9va2Rvd24pDQpyZXF1aXJlKGdncGxvdDIpDQpyZXF1aXJlKGdndGhlbWVzKQ0KcmVxdWlyZShzdHJpbmdyKQ0KcmVxdWlyZShsYXR0aWNlKQ0KcmVxdWlyZShwbHlyKQ0KcmVxdWlyZShwbG90bHkpDQpyZXF1aXJlKGljZXNBZHZpY2UpDQpyZXF1aXJlKCJzdG9ja2Fzc2Vzc21lbnQiKSAjIGF2YWlsYWJsZSBmcm9tIGh0dHBzOi8vZ2l0aHViLmNvbS9maXNoZm9sbG93ZXIvU0FNDQpyZXF1aXJlKHBhcmFsbGVsKQ0KcmVxdWlyZShzZikNCg0KbXlwcm9wIDwtIGZ1bmN0aW9uKGRmLCBub21vID0gIm5vbW8iLCBOb0F0TG5ndCA9ICJDQU5vQXRMbmd0Iil7DQogIHQgPC0gc3VtKGRmJG5vbW8pL3N1bShkZiRDQU5vQXRMbmd0KQ0KfQ0KDQpjYXRjaEZyYWMgPC0gZnVuY3Rpb24oeCwgbm0sIHcsIGZyYWMpew0KICBGIDwtIGdldEYoeCkNCiAgWiA8LSBGK25tDQogIE4gPC0gZ2V0Tih4KQ0KICBDIDwtIEYvWiooMS1leHAoLVopKSpODQogIHJldHVybihzdW0oZnJhYyp3KkMpKQ0KfQ0KDQpgYGANCg0KV2UgYWxzbyBuZWVkIHRvIHNldCBhIHRoZSAqRGF0YVllYXIqLCB3aGljaCBpcyB0aGUgeWVhciBpbW1lZGlhdGVseSBwcmVjZWVkaW5nIHRoZSBhc3Nlc3NtZW50IHllYXIgb3IgdGhlIHllYXIgZm9yIHdoaWNoIHRoZSBtb3N0IHJlY2VudCBkYXRhIGlzIGF2YWlsYWJsZS4gIA0KDQpgYGB7cn0NCkRhdGFZZWFyIDwtIDIwMjMNCkxhc3RJY2VzQWR2aWNlIDwtIDIxNzM1ICMgQWR2aXNlZCBjYXRjaCBmb3IgYXJlYXMgMjEtMzIgKGZyb20gc3RvY2sgc3BsaXR0aW5nIHRhYmxlIGluIGFkdmljZSkNCmlzRmluYWwgPC0gRkFMU0UNCiMgaXNGaW5hbCA8LSBUUlVFDQpgYGANCg0KIyBCYXNlbGluZQ0KSW4gdGhpcyB3b3JraW5nIGRvY3VtZW50LCB0aGUgYmFzZWxpbmUgbW9kZWwgd2FzIHNlbGVjdGVkIGZyb20gIHRoZSBpbW1lZGlhdGVseSBwcmVjZWRpbmcgd29ya2luZyBkb2N1bWVudCwgdGl0bGVkOiBfUGxlLjI3LjIxLTMyX1dLQlBMQUlDRV9Bc3Nlc3NtZW50cy5SbWRfLg0KDQojIyBCaW9QYXIgJiBGaXZlIFllYXIgU2xpZGluZyBXaW5kb3dzIChTdXJ2ZXkgVmFyaWF0aW9uKQ0KVGhpcyBhc3Nlc3NtZW50IGNvbWJpbmVzIHR3byBhcHByb2FjaGVzIHRvIHV0aWxpc2UgdGhlIGludGVybmFsIHNtb290aGluZyB0aGF0IFNBTSBjYW4gZG8gZm9yIGJpb2xvZ2ljYWwgZGF0YSwgd2hpbGUgbm90IG92ZXItcGFyYW1ldGVyaXNpbmcgdGhlIG1vZGVsLiAgVGhhdCBpcyB3ZSB1dGlsaXNlIHRoZSBiaWlvcGFyIHNtb290aGluZyBmb3IgdGhlIG1vcmUgbW9ub3RvbmljIGFuZCBmYXN0ZXIgY2hhbmdpbmcgc3RvY2std2VpZ2h0cy1hdC1hZ2UgZGF0YSwgd2hpbGUgd2UgcmV0YWluIHRoZSBzaW1wbGVyIHNsaWRpbmcgd2luZG93IG1lYW4gZm9yIHRoZSBtYXR1cml0eSBvZ2l2ZXMuDQoNCkluIHByZXBhcmluZyB0aGUgaW5wdXQgZmlsZXMsIHRoZSBzbGlkaW5nIHdpbmRvdyBtZWFuIHNpbXBseSBhdmVyYWdlcyB0aGUgcHJlY2VkaW5nIF94Xy0xIHllYXJzJyBvYnNlcnZhdGlvbnMgd2l0aCBlYWNoIHN1YnNlcXVlbnQgeWVhciB0byByZWR1Y2UgdGhlIGVmZmVjdCBvZiBhbm51YWwgdmFyaWFiaWxpdHkuIEluIHRoaXMgY2FzZSBfeF8gPSA1LCBmb3IgYSBmaXZlIHllYXIgc2xpZGluZyB3aW5kb3cuDQoNClRoZSBiaW9wYXIgb3B0aW9uIGlzIGNvbmZpZ3VyZWQgdG8gdHJlYXQgYWxsIGFnZXMgaW5kZXBlbmRlbnRseS4NCg0KSW4gdGhpcyBhbmQgYWxsIGZ1dHVyZSBpdGVyYXRpb25zLCB3ZSBleHRlbmRlZCB0aGUgdGltZSBzZXJpZXMgdG8gaW5jbHVkZSB0aGUgd2l0aGluLWFzc2Vzc21lbnQgeWVhciBRMSBzdXJ2ZXkgZGF0YS4NCg0KIyMjIE1vZGVsIENvbmZpZ3VyYXRpb24NCi0gU3VydmV5IGFnZSBjbGFzc2VzOg0KLSAxLTcrDQotIENvZWZmaWNpZW50cyBvZiB2YXJpYXRpb24gYXJlIGludGVncmF0ZWQgaW50byBtb2RlbCBlc3RpbWF0aW9uIG9mIHZhbHVlcyBhbmQgdW5jZXJ0YWludGllcy4NCi0gQ2F0Y2hlcyBhZ2UgY2xhc3NlczoNCi0gMS03Kw0KLSBNYXR1cml0eSBvZ2l2ZXM6DQotIEZpdmUgeWVhciBzbGlkaW5nLW1lYW4gc3RhcnRpbmcgd2l0aCBzdXJ2ZXkgZGF0YSBmcm9tIDE5OTkgKHdpdGggdGhlIGZpcnN0IHllYXIgcmVwZWF0ZWQgYmFja3dhcmRzIHRvIDE5OTgpIHRvIGluZm9ybSBkYXRhIHllYXJzIDIwMDI6YHIgRGF0YVllYXJgLg0KLSBQcm92aWRlZCB0byBTQU0gYXMgInRydWUiIG9ic2VydmF0aW9ucy4NCi0gQ29tYmluZWQgc2V4ZXMgDQotIE1lYW4gb2Ygd2VpZ2h0IGF0IGFnZSBpbiBzdG9jaw0KLSBEZXRlcm1pbmVkIGZyb20gc3VydmV5IG9ic2VydmF0aW9ucyAoUTEgc3VydmV5cykNCi0gQW5udWFsbHkgdmFyeWluZyBvYnNlcnZhdGlvbnMgKDIwMDI6YHIgRGF0YVllYXJgKSBmaXQgd2l0aGluIHRoZSBtb2RlbCB1c2luZyAiYmlvcGFyIiBvcHRpb25zLg0KLSBPYnNlcnZhdGlvbiB2YXJpYW5jZSBpcyBjb3VwbGVkIGZvciBhZ2VzIDIgdGhyb3VnaCA1Lg0KLSBGfmJhcn4gDQotIGFnZXMgMy01IChpbmNsdXNpdmUpDQotIE5hdHVyYWwgTW9ydGFsaXR5DQotIGFnZSAxID0gMC4yDQotIGFnZXMgMisgPSAwLjEgKGFzc3VtZWQgbG93IGR1ZSB0byBsb3cgcmF0ZXMgb2Ygb3RvbGl0aHMgaW4gcHJlZGF0b3Igc3RvbWFjaHMsIGJ1dCB3b3JrIGlzIG9uZ29pbmcgb24gdGhpcyB0b3BpYykNCi0gRmlzaGluZyBtb3J0YWxpdHkgaXMgY291cGxlZCBmb3IgYWdlcyA2ICsgNw0KLSBTdXJ2ZXkgY2F0Y2hhYmlsaXR5IGlzIGNvdXBsZWQgZm9yOg0KLSBRMSBzdXJ2ZXk6IGFnZXMgMyB0byA1DQotIFEzLzQgc3VydmV5OiBhZ2VzIDQgdG8gNw0KLSBDb3JyZWxhdGlvbiBzdHJ1Y3R1cmUgaW4gdGhlIG9ic2VydmF0aW9ucyBpcw0KLSBhbGxvd2VkIHRvIHZhcnkgaW5kZXBlbmRlbnRseSBhY3Jvc3MgYWdlcywgZm9yIGZvciB0aGUgY2F0Y2hlcyBhbmQgZm9yIHRoZSBRMSBzdXJ2ZXkuDQotIGhhcyBhbiBBUiBwcm9jZXNzIGFwcGxpZWQgYWNyb3NzIGFnZXMgZm9yIHRoZSBRMy80IHN1cnZleSwgd2l0aCBhZ2VzIDEgJiAyLCAzICYgNCwgYW5kIDUgJiA2IGNvdXBsZWQgYXMgcGFpcnMuDQoNCiMjIyBNb2RlbCBEb3dubG9hZA0KVG8gcnVuIHRoZSBtb2RlbCwgd2UgbXVzdCBmaXJzdCBkb3dubG9hZCB0aGUgaW5wdXQgZGF0YSBhbmQgY29uZmlndXJhdGlvbiBmaWxlcyBmcm9tIHRoZWlyIHB1YmxpYyByZXBvc2l0b3J5LiBUaGUgZGF0YSBpbiB0aGVzZSBmaWxlcyBoYXMgYmVlbiBwcmVzZW50ZWQgaW4gYW5vdGhlciB3b3JraW5nIGRvY3VtZW50IGFuZCBpbiBwbGVuYXJ5LCBidXQgaW4gdGhlc2UgZG93bmxvYWRzIGl0IGhhcyBiZWVuIHJlZm9ybWF0dGVkIHRvIGZpdCB3aXRoIFNBTSwgY29tbW9ubHkga25vd24gYXMgdGhlIExvd2VzdG9mdCwgQ0VGQVMsIG9yIFt4c2EgZm9ybWF0XShodHRwczovL3N0b2NrYXNzZXNzbWVudC5vcmcvZG9jcy94c2Fmb3JtYXQucGRmKS4NCg0KYGBge3IgYWx0ZXJuYXRlQ29uZmlndHJvdWJsZXNob290aW5nLCBldmFsPUZBTFNFLCBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQ0KZWFybGllcktWTyA8LSByYmluZChyZXAoMCwgdGltZXMgPSA3KSwgcmVwKDEsIHRpbWVzID0gNyksIHJlcCgyLCB0aW1lcyA9IDcpKQ0KcGFtZWxhS1ZPIDwtIHJiaW5kKGMoMCwgcmVwKDEsIHRpbWVzPTYpKSwgDQogICAgICAgICAgICAgICAgICAgcmVwKDIsIHRpbWVzPTcpLA0KICAgICAgICAgICAgICAgICAgIGMoMywgcmVwKDQsIHRpbWVzPTQpLCA1LCA1KSkNCg0KZWFybGllcktTT1YgPC0gYygwLCAxLCAyLCAzLCA0LCA1LCA2KQ0KcGFtZWxhS1NPViA8LSBjKDAsIDEsIDEsIDEsIDEsIDIsIDMpDQpgYGANCg0KYGBge3IgSW1wb3J0TW9kZWxGaWxlc19iaW9fNXlfU1Z9DQojPT09DQojIFJlYWQgaW4gZGF0YSBhbmQgYXNzaWduIGFwcHJvcHJpYXRlIG5hbWVzDQojPT09PQ0KZml0X2Jpb181eV9TViA9IGZpdGZyb213ZWIoInBsZS4yNy4yMS0zMl9XS0JQTEFJQ0VfMjAyNF9CaW9QYXJzd19zdXJ2Q29yIikNCg0KIyBvbGNvIDwtIGZpdF9iaW9fNXlfU1YkY29uZiRrZXlTdG9ja1dlaWdodE9ic1Zhcg0KIyBmaXRfYmlvXzV5X1NWJGNvbmYka2V5U3RvY2tXZWlnaHRPYnNWYXIgPC0gZWFybGllcktTT1YNCiMgZml0X2Jpb181eV9TViRjb25mJGtleVN0b2NrV2VpZ2h0T2JzVmFyIDwtIG9sY28NCg0KIyBvbGNvIDwtIGZpdF9iaW9fNXlfU1YkY29uZiRrZXlWYXJPYnMNCiMgZml0X2Jpb181eV9TViRjb25mJGtleVZhck9icyA8LSBlYXJsaWVyS1ZPDQojIGZpdF9iaW9fNXlfU1YkY29uZiRrZXlWYXJPYnMgPC0gb2xjbw0KDQojIGZpdF9iaW9fNXlfU1YgPC0gc3RvY2thc3Nlc3NtZW50Ojo6cmVmaXQoZml0X2Jpb181eV9TVikNCiM9PT09PQ0KYGBgDQoNCiMjIyBNb2RlbCBSZXN1bHRzDQojIyMjIENvbXBhcmVkIHRvIEJhc2VsaW5lIE1vZGVsDQpUaGlzIHNlY3Rpb24gaW50ZXJyb2dhdGVzIHRoZSBtb2RlbCBmaXQgYW5kIGdlbmVyYXRlcyB0YWJsZXMgYW5kIGZpZ3VyZXMgdGhhdCBkZXNjcmliZSB0aGUgZml0LiAgSW4gdGhlIGJhY2tncm91bmQsIHRoZXNlIGFyZSBzYXZlZCB0byBkaXNrIGJ1dCBhbHNvIHByaW50ZWQgaGVyZSBmb3IgdmlzaWJpbGl0eSBpbiB0aGUgcmVuZGVyZWQgZG9jdW1lbnQuIA0KDQpCZWNhdXNlIHdlIGFyZSB1c2luZyB0aGUgQklPUEFSIG9wdGlvbiBpbiBTQU0gdG8gc21vb3RoIHRoZSBpbnB1dCBvZiBhbm51YWxseSB2YXJ5aW5nIHN0b2NrIHdlaWdodHMgYXQgYWdlLCB3ZSBjYW4gZmlyc3QgaW52ZXN0aWdhdGUgdGhlIHJlc3VsdCBvZiB0aGlzIHBhcnQgb2YgdGhlIGZpdC4gDQpgYGB7ciBmaWcuY2FwPSJGaXRzIHRvIHRoZSBzdG9jayB3ZWlnaHRzIGF0IGFnZSwgZnJvbSB0aGUgbW9kZWwgd2l0aCBiaW9wYXIgb24gc3RvY2sgd2VpZ2h0cyBhdCBhZ2UgYW5kIHNsaWRpbmcgd2luZG93IG9uIG1hdHVyaXR5LiAgQW5udWFsIG9ic2VydmF0aW9ucyBhcmUgcG9pbnRzLCBtb2RlbCBmaXRzIGFyZSBzb2xpZCBsaW5lcy4gTm90ZSB0aGUgdmFyeWluZyB5IGF4ZXMuIn0NCiMjIEV4dHJhY3QgU1cgRml0cyBmcm9tIHRoZSBtb2RlbCBvYmplY3QNCnN3X2ZpdHMgPC0gYXMuZGF0YS5mcmFtZShleHAoZml0X2Jpb181eV9TViRwbCRsb2dTVylbMTpsZW5ndGgoMjAwMjooRGF0YVllYXIrMSkpLF0pDQpjb2xuYW1lcyhzd19maXRzKSA8LSBhcy5jaGFyYWN0ZXIoYygxOjcpKQ0KDQpzd19maXRzJHllYXIgPC0gZmFjdG9yKGFzLmNoYXJhY3RlcihjKDIwMDI6KERhdGFZZWFyKzEpKSksIGxldmVscyA9IGFzLmNoYXJhY3RlcihjKCgyMDAyOihEYXRhWWVhcisxKSkpKSkNCg0Kc3dfZml0c0wgPC0gcmVzaGFwZShkYXRhID0gc3dfZml0cywNCiAgICAgICAgICAgICAgICAgICAgdmFyeWluZyA9IGFzLmNoYXJhY3RlcihjKDE6NykpLA0KICAgICAgICAgICAgICAgICAgICB2Lm5hbWVzID0gInN3Rml0cyIsDQogICAgICAgICAgICAgICAgICAgIHRpbWV2YXIgPSAiQWdlIiwNCiAgICAgICAgICAgICAgICAgICAgdGltZXMgPSBhcy5jaGFyYWN0ZXIoYygxOjcpKSwNCiAgICAgICAgICAgICAgICAgICAgaWR2YXIgPSAieWVhciIsDQogICAgICAgICAgICAgICAgICAgIGRpcmVjdGlvbiA9ICJsb25nIikNCg0KIyMgRXh0cmFjdCBTRHMgZnJvbSB0aGUgZml0DQpzd19TRHMgPC0gYXMuZGF0YS5mcmFtZShleHAoZml0X2Jpb181eV9TViRwbHNkJGxvZ1NXKVsxOmxlbmd0aCgyMDAyOihEYXRhWWVhcisxKSksXSkNCmNvbG5hbWVzKHN3X1NEcykgPC0gYXMuY2hhcmFjdGVyKGMoMTo3KSkNCg0Kc3dfU0RzJHllYXIgPC0gZmFjdG9yKGFzLmNoYXJhY3RlcihjKDIwMDI6KERhdGFZZWFyKzEpKSksIGxldmVscyA9IGFzLmNoYXJhY3RlcihjKCgyMDAyOihEYXRhWWVhcisxKSkpKSkNCg0Kc3dfU0RzTCA8LSByZXNoYXBlKGRhdGEgPSBzd19TRHMsDQogICAgICAgICAgICAgICAgICAgdmFyeWluZyA9IGFzLmNoYXJhY3RlcihjKDE6NykpLA0KICAgICAgICAgICAgICAgICAgIHYubmFtZXMgPSAic3dTRHMiLA0KICAgICAgICAgICAgICAgICAgIHRpbWV2YXIgPSAiQWdlIiwNCiAgICAgICAgICAgICAgICAgICB0aW1lcyA9IGFzLmNoYXJhY3RlcihjKDE6NykpLA0KICAgICAgICAgICAgICAgICAgIGlkdmFyID0gInllYXIiLA0KICAgICAgICAgICAgICAgICAgIGRpcmVjdGlvbiA9ICJsb25nIikNCg0KIyMgRXh0cmFjdCBTVyBvYnNlcnZhdGlvbnMgZnJvbSB0aGUgbW9kZWwgb2JqZWN0DQpzd19vYnMgPC0gYXMuZGF0YS5mcmFtZShmaXRfYmlvXzV5X1NWJGRhdGEkc3RvY2tNZWFuV2VpZ2h0KVsxOmxlbmd0aCgyMDAyOihEYXRhWWVhcisxKSksXQ0KY29sbmFtZXMoc3dfb2JzKSA8LSBhcy5jaGFyYWN0ZXIoYygxOjcpKQ0KDQpzd19vYnMkeWVhciA8LSBmYWN0b3IoYXMuY2hhcmFjdGVyKGMoMjAwMjooRGF0YVllYXIrMSkpKSwgbGV2ZWxzID0gYXMuY2hhcmFjdGVyKGMoKDIwMDI6KERhdGFZZWFyKzEpKSkpKQ0KDQpzd19vYnNMIDwtIHJlc2hhcGUoZGF0YSA9IHN3X29icywNCiAgICAgICAgICAgICAgICAgICB2YXJ5aW5nID0gYXMuY2hhcmFjdGVyKGMoMTo3KSksDQogICAgICAgICAgICAgICAgICAgdi5uYW1lcyA9ICJzd09icyIsDQogICAgICAgICAgICAgICAgICAgdGltZXZhciA9ICJBZ2UiLA0KICAgICAgICAgICAgICAgICAgIHRpbWVzID0gYXMuY2hhcmFjdGVyKGMoMTo3KSksDQogICAgICAgICAgICAgICAgICAgaWR2YXIgPSAieWVhciIsDQogICAgICAgICAgICAgICAgICAgZGlyZWN0aW9uID0gImxvbmciKQ0KDQpzd19tb2QgPC0gbWVyZ2Uoc3dfZml0c0wsIHN3X1NEc0wsIGJ5ID0gYygieWVhciIsICJBZ2UiKSwgYWxsID0gVFJVRSkNCnN3X21vZCA8LSBtZXJnZShzd19tb2QsIHN3X29ic0wsIGJ5ID0gYygieWVhciIsICJBZ2UiKSwgYWxsID0gVFJVRSkNCnN3X21vZCR5ZWFyIDwtIGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKHN3X21vZCR5ZWFyKSkNCg0KZ2dwbG90bHkoZ2dwbG90KGRhdGEgPSBzd19tb2QpICsNCiAgICAgICAgICAgZ2VvbV9saW5lKG1hcHBpbmcgPSBhZXMoeCA9IHllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBzd0ZpdHMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IEFnZSkpICsNCiAgICAgICAgICAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSB5ZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IHN3T2JzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gQWdlKSwNCiAgICAgICAgICAgICAgICAgICAgICBzaGFwZT0gMjEpICsNCiAgICAgICAgICAgZmFjZXRfd3JhcCgufkFnZSwgc2NhbGVzID0gImZyZWVfeSIpKw0KICAgICAgICAgICB0aGVtZV9mZXcoKSsNCiAgICAgICAgICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxLCB2anVzdCA9IDEpKSArDQogICAgICAgICAgIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBmdW5jdGlvbih4KSBwcmV0dHkoeCwgbiA9IDUpKSArDQogICAgICAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjKGVicGFsKSkgKw0KICAgICAgICAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKGVicGFsKSkgKw0KICAgICAgICAgICBndWlkZXMoY29sb3VyID0gIm5vbmUiLCBmaWxsID0gIm5vbmUiKQ0KKQ0KDQoNCg0KYGBgDQoNCg0KVGhlIGJhc2VsaW5lIGFzc2Vzc21lbnQgZGVzY3JpYmVkIGZpcnN0IGluIHRoaXMgZG9jdW1lbnQsIGlzIG5vdyB1c2VkIGFzIGEgY29tcGFyaXNvbiBmb3IgdGhlIGNoYW5nZXMgbWFkZSBpbiB0aGlzIHZlcnNpb24gb2YgdGhlIG1vZGVsLg0KDQpgYGB7ciBkYXRhZnJhbWVTdW1tYXJ5X2Jpb181eV9TViwgcmVzdWx0cz0naGlkZScsIGZpZy5zaG93PSdoaWRlJ30NCiM9PT0NCiMgQ3JlYXRlIGRhdGFmcmFtZSBvZiBjdXJyZW50IHllYXIncyBmaXQgZm9yIHBsb3R0aW5nDQojPT09PQ0KIyBJQ19hZ2dfdGVtcCA8LSBhZ2dyZWdhdGUoQ0FUT05+WWVhciwgaWNfY2xlYW5baWNfY2xlYW4kQ2F0Y2hDYXRlZ29yeSAlaW4lIGMoIkxhbmRpbmdzIiwgIkRpc2NhcmRzIiksIF0sIEZVTiA9ICJzdW0iKQ0KYXN1bV9iaW9fNXlfU1YgPC0gYXMuZGF0YS5mcmFtZShzdW1tYXJ5KGZpdF9iaW9fNXlfU1YpKQ0KYXN1bV9iaW9fNXlfU1YkWWVhciA8LSBhcy5pbnRlZ2VyKHJvdy5uYW1lcyhzdW1tYXJ5KGZpdF9iaW9fNXlfU1YpKSkNCmN0X2Jpb181eV9TViA8LSBhcy5kYXRhLmZyYW1lKGNhdGNodGFibGUoZml0X2Jpb181eV9TViwgb2JzLnNob3cgPSBUUlVFKSkNCmN0X2Jpb181eV9TViRZZWFyIDwtIGFzLmludGVnZXIocm93bmFtZXMoY3RfYmlvXzV5X1NWKSkNCnJvd25hbWVzKGN0X2Jpb181eV9TVikgPC0gTlVMTA0KY3RfYmlvXzV5X1NWIDwtIHJiaW5kKGN0X2Jpb181eV9TViwgZGF0YS5mcmFtZShFc3RpbWF0ZSA9IE5BLCBMb3c9TkEsIEhpZ2g9TkEsIHNvcC5jYXRjaD1OQSwgWWVhcj1hcy5pbnRlZ2VyKDIwMjQpKSkNCmFzdW1fYmlvXzV5X1NWIDwtIG1lcmdlKHggPSBhc3VtX2Jpb181eV9TViwgeSA9IGN0X2Jpb181eV9TViwgYnkgPSAiWWVhciIpDQpjb2xuYW1lcyhhc3VtX2Jpb181eV9TVikgPC0gYygiWWVhciIsICJSX2FnZTEiLCAiUmxvdyIsICJSaGlnaCIsICJTU0IiLCAiU1NCbG93IiwgIlNTQmhpZ2giLCAiRmJhciIsICJGbG93IiwgIkZoaWdoIiwgIkNhdGNoRXN0IiwgIkNhdGNobG93IiwgIkNhdGNoaGlnaCIsICJDYXRjaE9icyIpDQojPT09PT0NCmBgYA0KDQpXZSBjYW4gc2VlIGluIHRoaXMgbW9kZWwsIGFzIGluIHRoZSBiaW9wYXIgbW9kZWwsIHRoYXQgdGhlIGNoYW5nZXMgaW4gc3RvY2sgd2VpZ2h0cyBhdCBhZ2UgYXJlIHByb2JhYmx5IHJlZmxlY3RlZCBpbiB0aGUgbG93ZXIgZXN0aW1hdGVzIG9mIFNTQiwgYWxiZWl0IHdpdGggYSBoaWdoZXIgaW50ZXJhbm51YWwgdmFyaWFiaWxpdHkgdGhhbiBpcyB0aGUgY2FzZSBmb3IgdGhlIGJhc2VsaW5lIG1vZGVsLCB3aGljaCB1c2VzIGEgZml4ZWQgc3RvY2sgd2VpZ2h0IGF0IGFnZSBmb3IgYWxsIHllYXJzLiANCmBgYHtyIGZpZy5jYXA9ICJNb2RlbCB3aXRoIEJpb3BhciBvbiBTV0EgYW5kIGZpdmUgeWVhciBTV00gb24gTU8gKHN1cnZleSB2YXJpYXRpb24pIGVzdGltYXRlZCBzcGF3bmluZyBzdG9jayBiaW9tYXNzIGZvciBwbGUuMjcuMjEtMzIgYW5kIHBvaW50IHdpc2UgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWxzIGFyZSBzaG93biBieSBsaW5lIGFuZCBzaGFkZWQgYXJlYSAodG9ubmVzKSJ9DQojIHNzYmxpbmVzIDwtIGRhdGEuZnJhbWUoeWludGVyY2VwdD1jKDQ3MzAsIDQzNzAsIDM2MzUpLCBMaW5lcyA9IGZhY3Rvcih4ID0gYygiTVNZLUJ0cmlnZ2VyIiwgIkJwYSIsICJCbGltIiksbGV2ZWxzID0gYygiTVNZLUJ0cmlnZ2VyIiwgIkJwYSIsICJCbGltIikpKQ0KcHNzYiA8LSBnZ3Bsb3QoKSArDQogIGdlb21fbGluZShkYXRhID0gYXN1bV9iaW9fNXlfU1YsIA0KICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgIHk9U1NCKSwNCiAgICAgICAgICAgIGNvbG91ciA9IGVicGFsWzFdKSArDQogIGdlb21fcmliYm9uKGRhdGEgPSBhc3VtX2Jpb181eV9TViwgDQogICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW49U1NCbG93LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltYXg9U1NCaGlnaCksDQogICAgICAgICAgICAgIGZpbGwgPSBlYnBhbFsxXSwNCiAgICAgICAgICAgICAgYWxwaGEgPSAwLjMpICsNCiAgdGhlbWVfY2xlYW4oKQ0KDQpnZ3Bsb3RseShwc3NiKQ0KYGBgDQoNCkZpc2hpbmcgcHJlc3N1cmUgb3ZlciB0aW1lIHNlZW1zIHRvIHJlc3BvbmQgdG8gdGhlIGNoYW5nZXMgaW4gdGhlIGVzdGltYXRpb25zIG9mIFNTQiwgd2hpbGUgaW5wdXQgZGF0YSBmb3IgY2F0Y2hlcyAob2J2aW91c2x5KSByZW1haW4gdGhlIHNhbWUgYmV0d2VuIHRoZSB0d28gbW9kZWxzLiANCg0KYGBge3IgZmlnLmNhcD0gIk1vZGVsIHdpdGggQmlvcGFyIG9uIFNXQSBhbmQgZml2ZSB5ZWFyIFNXTSBvbiBNTyAoc3VydmV5IHZhcmlhdGlvbikgYW5udWFsIGZpc2hpbmcgbW9ydGFsaXR5IGVzdGltYXRlcyBmb3IgcGxlLjI3LjIxLTMyIGFnZXMgMy01IGFuZCBwb2ludCB3aXNlIDk1JSBjb25maWRlbmNlIGludGVydmFscyBhcmUgc2hvd24gYnkgbGluZSBhbmQgc2hhZGVkIGFyZWEuIn0NCiMgZmxpbmVzIDwtIGRhdGEuZnJhbWUoeWludGVyY2VwdD1jKDAuMzEsIDAuODEsIDEuMDApLCBMaW5lcyA9IGZhY3Rvcih4ID0gYygiRk1TWSIsICJGcGEiLCAiRmxpbSIpLCBsZXZlbHMgPSBjKCJGTVNZIiwgIkZwYSIsICJGbGltIikpKQ0KZ2dwbG90bHkoZ2dwbG90KCkgKw0KICAgICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IGFzdW1fYmlvXzV5X1NWLCANCiAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PUZiYXIpLA0KICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gZWJwYWxbMV0pICsNCiAgICAgICAgICAgZ2VvbV9yaWJib24oZGF0YSA9IGFzdW1fYmlvXzV5X1NWLCANCiAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1pbj1GbG93LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltYXg9RmhpZ2gpLA0KICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gZWJwYWxbMV0sDQogICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4zKSArDQogICAgICAgICAgIHRoZW1lX2NsZWFuKCkpDQpgYGANCg0KRXN0aW1hdGlvbnMgb2YgcmVjcnVpdG1lbnQgaW4gdGhlIG1vc3QgcmVjZW50IHllYXJzIGZhbGwsIGFzIFNTQiBhbHNvIGZhbGxzIGluIHRoaXMgdmVyc2lvbiBvZiB0aGUgbW9kZWwsIGFnYWluIHByb2JhYmx5IGR1ZSB0byB0aGUgcmVkdWN0aW9uIGluIHN0b2NrIHdlaWdodHMgYXQgYWdlLg0KDQpgYGB7ciBmaWcuY2FwPSAiTW9kZWwgd2l0aCBCaW9wYXIgb24gU1dBIGFuZCBmaXZlIHllYXIgU1dNIG9uIE1PIChzdXJ2ZXkgdmFyaWF0aW9uKSBhbm51YWwgcmVjcnVpdG1lbnQgZXN0aW1hdGVzIGZvciBwbGUuMjcuMjEtMzIgYW5kIHBvaW50IHdpc2UgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWxzIGFyZSBzaG93biBieSBsaW5lIGFuZCBzaGFkZWQgYXJlYSAobnVtYmVycykuIn0NCmdncGxvdGx5KGdncGxvdCgpICsNCiAgICAgICAgICAgZ2VvbV9saW5lKGRhdGEgPSBhc3VtX2Jpb181eV9TViwgDQogICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1SX2FnZTEpLA0KICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gZWJwYWxbMV0pICsNCiAgICAgICAgICAgZ2VvbV9yaWJib24oZGF0YSA9IGFzdW1fYmlvXzV5X1NWLCANCiAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1pbj1SbG93LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltYXg9UmhpZ2gpLA0KICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gZWJwYWxbMV0sDQogICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4zKSArDQogICAgICAgICAgIHRoZW1lX2NsZWFuKCkpDQpgYGANCg0KYGBge3IgZmlnLmNhcD0gIk1vZGVsIHdpdGggQmlvcGFyIG9uIFNXQSBhbmQgZml2ZSB5ZWFyIFNXTSBvbiBNTyAoc3VydmV5IHZhcmlhdGlvbikgYW5udWFsIGNhdGNoIGVzdGltYXRlcyBhbmQgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWxzIChsaW5lIGFuZCBzaGFkZWQgYXJlYSwgcmVzcGVjdGl2ZWx5KSBmb3IgcGxlLjI3LjIxLTMyIGFuZCBwb2ludCBhbm51YWwgb2JzZXJ2YXRpb25zIChwb2ludHMpLiJ9DQpnZ3Bsb3RseShnZ3Bsb3QoKSArDQogICAgICAgICAgIGdlb21fbGluZShkYXRhID0gYXN1bV9iaW9fNXlfU1ZbYXN1bV9iaW9fNXlfU1YkWWVhciAhPSAoRGF0YVllYXIrMSksXSwgDQogICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1DYXRjaEVzdCksDQogICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBlYnBhbFsxXSkgKw0KICAgICAgICAgICBnZW9tX3JpYmJvbihkYXRhID0gYXN1bV9iaW9fNXlfU1ZbYXN1bV9iaW9fNXlfU1YkWWVhciAhPSAoRGF0YVllYXIrMSksXSwgDQogICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW49Q2F0Y2hsb3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1heD1DYXRjaGhpZ2gpLA0KICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gZWJwYWxbMV0sDQogICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4zKSArDQogICAgICAgICAgIGdlb21fcG9pbnQoZGF0YSA9IGFzdW1fYmlvXzV5X1NWW2FzdW1fYmlvXzV5X1NWJFllYXIgIT0gKERhdGFZZWFyKzEpLF0sDQogICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PUNhdGNoT2JzKSwNCiAgICAgICAgICAgICAgICAgICAgICBzaGFwZSA9IDMsDQogICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gZWJwYWxbMTFdLA0KICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBlYnBhbFsxMV0pICsNCiAgICAgICAgICAgeWxhYigiQ2F0Y2ggKHRvbm5lcykiKSArDQogICAgICAgICAgIHRoZW1lX2NsZWFuKCkpDQpgYGANCg0KIyMjIyBPdGhlciByZXN1bHRzIGZyb20gdGhlIEJpb3Bhci9GaXZlIFllYXIgU2xpZGluZyBXaW5kb3cgbW9kZWwNCmBgYHtyIGZpZy5jYXA9IlBhcnRpYWwgRiBhdCBhZ2U7IE1vZGVsIHdpdGggQmlvcGFyIG9uIFNXQSBhbmQgZml2ZSB5ZWFyIFNXTSBvbiBNTyAoc3VydmV5IHZhcmlhdGlvbikifQ0KIyMjIERhdGEgUHJlcA0KRl9iaW9fNXlfU1Y8LSBhcy5kYXRhLmZyYW1lKGZheXRhYmxlKGZpdF9iaW9fNXlfU1YpKQ0KRl9iaW9fNXlfU1YkWWVhciA8LSByb3duYW1lcyhGX2Jpb181eV9TVikNCnJvd25hbWVzKEZfYmlvXzV5X1NWKSA8LSBOVUxMDQpGX2Jpb181eV9TVkxuZyA8LSBtZWx0KGRhdGEgPSBGX2Jpb181eV9TViwgaWQudmFycyA9ICJZZWFyIiwgdmFyaWFibGUubmFtZSA9ICJBZ2UiLCB2YWx1ZS5uYW1lID0gIkZfYXRBZ2UiKQ0KRl9iaW9fNXlfU1ZMbmckWWVhciA8LSBhcy5udW1lcmljKGFzLmNoYXJhY3RlcihGX2Jpb181eV9TVkxuZyRZZWFyKSkNCg0KIyMjIFBsb3QNCmdncGxvdGx5KGdncGxvdCgpKw0KICAgICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IEZfYmlvXzV5X1NWTG5nLA0KICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0gWWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IEZfYXRBZ2UsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IEFnZSkpICsNCiAgICAgICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGVicGFsLCApICsNCiAgICAgICAgICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz11bmlxdWUoRl9iaW9fNXlfU1ZMbmckWWVhcikpICsNCiAgICAgICAgICAgdGhlbWVfZmV3KCkrDQogICAgICAgICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUpKSkNCmBgYA0KDQojIyMgTW9kZWwgRml0DQpXaGVuIHRoZSBtb2RlbCBpcyBydW4gd2UgY2FuIGVhc2lseSBzZWUgZnJvbSB3YXJuaW5ncy9lcnJvcnMgaWYgdGhlcmUgaXMgYSBjb252ZXJnZW5jZSBpc3N1ZS4gIEhvd2V2ZXIsIHdlIGNhbiBhbHNvIGNvbmZpcm0gdGhpcywgZXhwbGljaXRseToNCi0gVGhlIGZpbmFsIG1vZGVsIGdyYWRpZW50OiBgciBmaXRfYmlvXzV5X1NWJG9wdCRldmFsdWF0aW9uc1syXWANCi0gVGhhdCB0aGVyZSBpcyBhIHBvc2l0aXZlIGRlZmluaXRlIGhlc3NpYW46IGByIGFsbChlaWdlbihmaXRfYmlvXzV5X1NWJG9wdCRoZSkkdmFsdWVzID4wKWANCg0KRnVydGhlcm1vcmUsIFNBTSBkb2VzIG5vdCB1dGlsaXNlICJib3VuZHMiIHdoZW4gZml0dGluZyB0aGUgbW9kZWwsIGFuZCB0aGVyZWZvcmUsIGFzIHN0YW5kYXJkIGNoZWNrIG9mIHdoZXRoZXIgbW9kZWwgcGFyYW1ldGVycyBhcmUgYXBwcm9hY2hpbmcgdGhlaXIgYm91bmRzIGlzIGlycmVsZXZhbnQuIA0KDQpXZSBjYW4gaW52ZXN0aWdhdGUgdGhlIHZhcmlhbmNlIGFyb3VuZCB0aGUgZGlmZmVyZW50IGNhdGNoL3N0b2NrIGNvbXBvbmVudHMuDQpgYGB7ciBmaWcuY2FwPSJTdGFuZGFyZCBEZXZhdGlvbnMgYnkgRmxlZXQ7IGJhc2UgbW9kZWwiLCBoZWlnaHQ9MTB9DQpzZHBsb3QoZml0X2Jpb181eV9TViwgbWFyZyA9IGMoNSw0LDEsMSkpDQpgYGANCg0KDQojIyMjIFJlc2lkdWFsIFBsb3RzDQpOZXh0IHdlIGNhbiBsb29rIGF0IGhvdyB0aGUgbW9kZWwgZml0cyB0aGUgb2JzZXJ2YXRpb25zIHBlciBhZ2UgaW4gdGhlIGRpZmZlcmVudCBmbGVldHMuDQpgYGB7ciBmaWcuY2FwPSJNb2RlbCB3aXRoIEJpb3BhciBvbiBTV0EgYW5kIGZpdmUgeWVhciBTV00gb24gTU8gKHN1cnZleSB2YXJpYXRpb24pIGZpdCB0byBjYXRjaCBkYXRhIGJ5IGFnZSAodmFsdWVzIG9uIHRoZSBtb2RlbCBsaW5rIGZ1bmN0aW9uIHNjYWxlKS4ifQ0KIyMgRXh0cmFjdCBkYXRhIGZyb20gbW9kZWwgb2JqZWN0DQpsb2dPYnNfYmlvXzV5X1NWIDwtIHNwbGl0KGZpdF9iaW9fNXlfU1YkZGF0YSRsb2dvYnMsIGNlaWxpbmcoc2VxX2Fsb25nKGZpdF9iaW9fNXlfU1YkZGF0YSRsb2dvYnMpL2ZpdF9iaW9fNXlfU1YkZGF0YSRtYXhBZ2VQZXJGbGVldFsxXSkpDQpsb2dQcmVkX2Jpb181eV9TViA8LSBzcGxpdChmaXRfYmlvXzV5X1NWJHJlcCRwcmVkT2JzLCBjZWlsaW5nKHNlcV9hbG9uZyhmaXRfYmlvXzV5X1NWJHJlcCRwcmVkT2JzKS9maXRfYmlvXzV5X1NWJGRhdGEkbWF4QWdlUGVyRmxlZXRbMV0pKQ0KDQojIyBUcmFuc2Zvcm0gZGF0YSB0byB1c2VhYmxlIGRhdGFmcmFtZXMNCiMjIyBJbml0aWFsaXplIGFuIGVtcHR5IGRhdGEgZnJhbWUgZm9yIG9ic2VydmF0aW9ucw0KbG9nT2JzX2Jpb181eV9TVl9kZiA8LSBkYXRhLmZyYW1lKGFnZSA9IGludGVnZXIoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmbGVldCA9IGludGVnZXIoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ZWFyID0gaW50ZWdlcigpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZ09icyA9IG51bWVyaWMoKSkNCg0KIyMjIFBvcHVsYXRlIHRoZSBkYXRhIGZyYW1lIGZvciBvYnNlcnZhdGlvbnMNCmZvciAoaSBpbiBzZXFfYWxvbmcobG9nT2JzX2Jpb181eV9TVikpIHsNCiAgIyBDYWxjdWxhdGUgdGhlIGdyb3VwIGFuZCB5ZWFyDQogIHllYXIgPC0gKChpIC0gMSkgJS8lIDMpICsgMQ0KICBmbGVldCA8LSAoKGkgLSAxKSAlJSAzKSArIDENCiAgDQogICMjIyBDcmVhdGUgYSB0ZW1wb3JhcnkgZGF0YSBmcmFtZSBhbmQgYXBwZW5kIHRvIHRoZSBtYWluIGRhdGEgZnJhbWUgZm9yIG9ic2VydmF0aW9ucw0KICB0ZW1wX2RmIDwtIGRhdGEuZnJhbWUoYWdlID0gMTo3LA0KICAgICAgICAgICAgICAgICAgICAgICAgZmxlZXQgPSBmbGVldCwNCiAgICAgICAgICAgICAgICAgICAgICAgIHllYXIgPSB5ZWFyKzIwMDEsDQogICAgICAgICAgICAgICAgICAgICAgICBsb2dPYnMgPSBsb2dPYnNfYmlvXzV5X1NWW1tpXV0pDQogIGxvZ09ic19iaW9fNXlfU1ZfZGYgPC0gcmJpbmQobG9nT2JzX2Jpb181eV9TVl9kZiwgdGVtcF9kZikNCn0NCg0KIyMjIEluaXRpYWxpemUgYW4gZW1wdHkgZGF0YSBmcmFtZSBmb3IgcHJlZGljdGlvbnMNCmxvZ1ByZWRfYmlvXzV5X1NWX2RmIDwtIGRhdGEuZnJhbWUoYWdlID0gaW50ZWdlcigpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmbGVldCA9IGludGVnZXIoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeWVhciA9IGludGVnZXIoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9nUHJlZCA9IG51bWVyaWMoKSkNCg0KIyMjIFBvcHVsYXRlIHRoZSBkYXRhIGZyYW1lIGZvciBwcmVkaWN0aW9ucw0KZm9yIChpIGluIHNlcV9hbG9uZyhsb2dQcmVkX2Jpb181eV9TVikpIHsNCiAgIyBDYWxjdWxhdGUgdGhlIGdyb3VwIGFuZCB5ZWFyDQogIHllYXIgPC0gKChpIC0gMSkgJS8lIDMpICsgMQ0KICBmbGVldCA8LSAoKGkgLSAxKSAlJSAzKSArIDENCiAgDQogICMjIyBDcmVhdGUgYSB0ZW1wb3JhcnkgZGF0YSBmcmFtZSBhbmQgYXBwZW5kIHRvIHRoZSBtYWluIGRhdGEgZnJhbWUgZm9yIHByZWRpY3Rpb25zDQogIHRlbXBfZGYgPC0gZGF0YS5mcmFtZShhZ2UgPSAxOjcsDQogICAgICAgICAgICAgICAgICAgICAgICBmbGVldCA9IGZsZWV0LA0KICAgICAgICAgICAgICAgICAgICAgICAgeWVhciA9IHllYXIrMjAwMSwNCiAgICAgICAgICAgICAgICAgICAgICAgIGxvZ1ByZWQgPSBsb2dQcmVkX2Jpb181eV9TVltbaV1dKQ0KICBsb2dQcmVkX2Jpb181eV9TVl9kZiA8LSByYmluZChsb2dQcmVkX2Jpb181eV9TVl9kZiwgdGVtcF9kZikNCn0NCg0KIyMgUGxvdA0KbG9nUHJlZF9iaW9fNXlfU1ZfZGYkYWdlIDwtIGFzLmNoYXJhY3Rlcihsb2dQcmVkX2Jpb181eV9TVl9kZiRhZ2UpDQpsb2dPYnNfYmlvXzV5X1NWX2RmJGFnZSA8LSBhcy5jaGFyYWN0ZXIobG9nT2JzX2Jpb181eV9TVl9kZiRhZ2UpDQoNCmdncGxvdGx5KGdncGxvdCgpKw0KICAgICAgICAgICBnZW9tX3BvaW50KGRhdGEgPSBsb2dPYnNfYmlvXzV5X1NWX2RmW2xvZ09ic19iaW9fNXlfU1ZfZGYkZmxlZXQgPT0gMSAmIGxvZ09ic19iaW9fNXlfU1ZfZGYkeWVhciAhPSAoRGF0YVllYXIrMSksIF0sDQogICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0geWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBsb2dPYnMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBhZ2UpLA0KICAgICAgICAgICAgICAgICAgICAgIHNoYXBlID0gMjEpICsNCiAgICAgICAgICAgZ2VvbV9saW5lKGRhdGEgPSBsb2dQcmVkX2Jpb181eV9TVl9kZltsb2dQcmVkX2Jpb181eV9TVl9kZiRmbGVldCA9PSAxICYgbG9nUHJlZF9iaW9fNXlfU1ZfZGYkeWVhciAhPSAoRGF0YVllYXIrMSksIF0sDQogICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSB5ZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gbG9nUHJlZCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gYWdlKSkgKw0KICAgICAgICAgICBmYWNldF93cmFwKGZhY2V0cyA9ICJhZ2UiKSArICMsIHNjYWxlcyA9ICJmcmVlX3kiKSArDQogICAgICAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBlYnBhbCwgZ3VpZGUgPSBGQUxTRSkgKw0KICAgICAgICAgICBndWlkZXMoY29sb3VyPUZBTFNFLCBzaGFwZT1GQUxTRSkgKw0KICAgICAgICAgICB0aGVtZV9mZXcoKSkNCg0KIyBmaXRwbG90KGZpdF9iaW9fNXlfU1YsIGZsZWV0cz0xKQ0KYGBgDQoNCmBgYHtyIGZpZy5jYXA9Ik1vZGVsIHdpdGggQmlvcGFyIG9uIFNXQSBhbmQgZml2ZSB5ZWFyIFNXTSBvbiBNTyAoc3VydmV5IHZhcmlhdGlvbikgZml0IHRvIFExIHN1cnZleSBkYXRhIGJ5IGFnZSAodmFsdWVzIG9uIHRoZSBtb2RlbCBsaW5rIGZ1bmN0aW9uIHNjYWxlKS4ifQ0KZ2dwbG90bHkoZ2dwbG90KCkrDQogICAgICAgICAgIGdlb21fcG9pbnQoZGF0YSA9IGxvZ09ic19iaW9fNXlfU1ZfZGZbbG9nT2JzX2Jpb181eV9TVl9kZiRmbGVldCA9PSAyICYgbG9nT2JzX2Jpb181eV9TVl9kZiR5ZWFyICE9IChEYXRhWWVhcisxKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSB5ZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGxvZ09icywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IGFnZSksDQogICAgICAgICAgICAgICAgICAgICAgc2hhcGUgPSAyMSkgKw0KICAgICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IGxvZ1ByZWRfYmlvXzV5X1NWX2RmW2xvZ1ByZWRfYmlvXzV5X1NWX2RmJGZsZWV0ID09IDIgJiBsb2dQcmVkX2Jpb181eV9TVl9kZiR5ZWFyICE9IChEYXRhWWVhcisxKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IHllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBsb2dQcmVkLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBhZ2UpKSArDQogICAgICAgICAgIGZhY2V0X3dyYXAoZmFjZXRzID0gImFnZSIpICsgIywgc2NhbGVzID0gImZyZWVfeSIpICsNCiAgICAgICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGVicGFsLCBndWlkZSA9IEZBTFNFKSArDQogICAgICAgICAgIGd1aWRlcyhjb2xvdXI9RkFMU0UsIHNoYXBlPUZBTFNFKSArDQogICAgICAgICAgIHRoZW1lX2ZldygpKQ0KIyBmaXRwbG90KGZpdF9iaW9fNXlfU1YsIGZsZWV0cz0yKQ0KYGBgDQoNCmBgYHtyIGZpZy5jYXA9Ik1vZGVsIHdpdGggQmlvcGFyIG9uIFNXQSBhbmQgZml2ZSB5ZWFyIFNXTSBvbiBNTyAoc3VydmV5IHZhcmlhdGlvbikgZml0IHRvIFEzLzQgc3VydmV5IGRhdGEgYnkgYWdlICh2YWx1ZXMgb24gdGhlIG1vZGVsIGxpbmsgZnVuY3Rpb24gc2NhbGUpLiJ9DQpnZ3Bsb3RseShnZ3Bsb3QoKSsNCiAgICAgICAgICAgZ2VvbV9wb2ludChkYXRhID0gbG9nT2JzX2Jpb181eV9TVl9kZltsb2dPYnNfYmlvXzV5X1NWX2RmJGZsZWV0ID09IDMgJiBsb2dPYnNfYmlvXzV5X1NWX2RmJHllYXIgIT0gKERhdGFZZWFyKzEpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IHllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gbG9nT2JzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gYWdlKSwNCiAgICAgICAgICAgICAgICAgICAgICBzaGFwZSA9IDIxKSArDQogICAgICAgICAgIGdlb21fbGluZShkYXRhID0gbG9nUHJlZF9iaW9fNXlfU1ZfZGZbbG9nUHJlZF9iaW9fNXlfU1ZfZGYkZmxlZXQgPT0gMyAmIGxvZ1ByZWRfYmlvXzV5X1NWX2RmJHllYXIgIT0gKERhdGFZZWFyKzEpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0geWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGxvZ1ByZWQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IGFnZSkpICsNCiAgICAgICAgICAgZmFjZXRfd3JhcChmYWNldHMgPSAiYWdlIikgKyAjLCBzY2FsZXMgPSAiZnJlZV95IikgKw0KICAgICAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gZWJwYWwsIGd1aWRlID0gRkFMU0UpICsNCiAgICAgICAgICAgZ3VpZGVzKGNvbG91cj1GQUxTRSwgc2hhcGU9RkFMU0UpICsNCiAgICAgICAgICAgdGhlbWVfZmV3KCkpDQoNCiMgZml0cGxvdChmaXRfYmlvXzV5X1NWLCBmbGVldHM9MykNCmBgYA0KTm93IHdlIGNhbiBhbHNvIGNhbGN1bGF0ZSB0aGUgcmVzaWR1YWxzIG9mIG91ciBvYnNlcnZhdGlvbnMgZnJvbSBvdXIgbW9kZWwuIA0KDQpgYGB7ciBjYWxjdWxhdGVSZXNpZHVhbHNfYmlvXzV5X1NWLCB3YXJuaW5nPUZBTFNFLCByZXN1bHRzPSdoaWRlJ30NCnJlc2lkX2Jpb181eV9TViA8LSByZXNpZHVhbHMoZml0X2Jpb181eV9TVikNCnJlc2lkX2Jpb181eV9TVl9kZiA8LSBkYXRhLmZyYW1lKHllYXIgPSByZXNpZF9iaW9fNXlfU1YkeWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZsZWV0ID0gcmVzaWRfYmlvXzV5X1NWJGZsZWV0LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWdlID0gcmVzaWRfYmlvXzV5X1NWJGFnZSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9ic2VydmF0aW9uID0gcmVzaWRfYmlvXzV5X1NWJG9ic2VydmF0aW9uLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWVhbiA9IHJlc2lkX2Jpb181eV9TViRtZWFuLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzaWR1YWwgPSByZXNpZF9iaW9fNXlfU1YkcmVzaWR1YWwpDQpyZXNpZF9iaW9fNXlfU1ZfZGYkZmxlZXROYW1lIDwtIGlmZWxzZShyZXNpZF9iaW9fNXlfU1ZfZGYkZmxlZXQgPT0gMSwgYXR0cmlidXRlcyhyZXNpZF9iaW9fNXlfU1YpJGZsZWV0TmFtZXNbMV0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKHJlc2lkX2Jpb181eV9TVl9kZiRmbGVldCA9PSAyLCBhdHRyaWJ1dGVzKHJlc2lkX2Jpb181eV9TVikkZmxlZXROYW1lc1syXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKHJlc2lkX2Jpb181eV9TVl9kZiRmbGVldCA9PSAzLCBhdHRyaWJ1dGVzKHJlc2lkX2Jpb181eV9TVikkZmxlZXROYW1lc1szXSwgTkEpKSkNCg0KcmVzaWRfYmlvXzV5X1NWX2RmJGZsZWV0QWx0TmFtZSA8LSBpZmVsc2UocmVzaWRfYmlvXzV5X1NWX2RmJGZsZWV0ID09IDEsICJSZXNpZHVhbCBGaXNoaW5nIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UocmVzaWRfYmlvXzV5X1NWX2RmJGZsZWV0ID09IDIsICJRMSBTdXJ2ZXlzIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKHJlc2lkX2Jpb181eV9TVl9kZiRmbGVldCA9PSAzLCAiUTMvNCBTdXJ2ZXlzIiwgTkEpKSkNCmBgYA0KDQoNCldlIGNhbiBhbHNvIGxvb2sgZm9yIHBhdHRlcm5zIG9mIGNvcnJlbGF0aW9uIGluIHRoZSByZXNpZHVhbHMsIGluZGljYXRpbmcgdW5leHBsYWluZWQgdHJlbmRzLiAgSWRlYWxseSwgdGhlcmUgd2lsbCBiZSBubyBsYXJnZSBwYXR0ZXJucywgZXNwZWNpYWxseSB0aG9zZSB3ZWlnaHRlZCBhc3ltbWV0cmljYWxseSBpbiB0aGUgZmlndXJlcy4gIEZvciBmbGVldHMgd2hlcmUgY29uZmlndXJhdGlvbiBhbGxvd3MgZm9yIGEgY29ycmVsYXRpb24gc3RydWN0dXJlIGJldHdlZW4gYWdlcywgZnJvbSB5ZWFyIHRvIHllYXIgKGkuZS4gYHIgaWZlbHNlKHBhc3RlKGMoImZpc2hpbmcgZmxlZXQiLCAiUTEgc3VydmV5cyIsICJRMy80IHN1cnZleXMiKVshZml0X2Jpb181eV9TViRjb25mJG9ic0NvclN0cnVjdD09IklEIl0sIGNvbGxhcHNlID0gIiwgIikgPT0gIiIsIHBhc3RlMCgiTm8gZmxlZXRzIG1hdGNoIHRoaXMgY3JpdGVyaWEgaW4gdGhpcyBtb2RlbCBjb25maWd1cmF0aW9uLiIpLCBwYXN0ZShjKCJmaXNoaW5nIGZsZWV0IiwgIlExIHN1cnZleXMiLCAiUTMvNCBzdXJ2ZXlzIilbIWZpdF9iaW9fNXlfU1YkY29uZiRvYnNDb3JTdHJ1Y3Q9PSJJRCJdLCBjb2xsYXBzZSA9ICIsICIpKWApLCB0aGlzIGlzIGVzcGVjaWFsbHkgaW1wb3J0YW50Lg0KDQpgYGB7ciBmaWcuY2FwPSJFc3RpbWF0ZWQgY29ycmVsYXRpb25zIGluIHJlc2lkdWFsIHZhcmlhdGlvbiBiZXR3ZWVuIGFnZXMgZm9yIGVhY2ggb2YgdGhlIGZpc2hpbmcgZmxlZXQgKHRvcCkgYW5kIHRoZSB0d28gc3VydmV5cyAobWlkZGxlICYgYm90dG9tKSwgZnJvbSB0aGUgYmlvXzV5X1NWIG1vZGVsLiJ9DQoNCmlmKCFhbGwoZml0X2Jpb181eV9TViRjb25mJG9ic0NvclN0cnVjdD09IklEIikpeyANCiAgY29ycGxvdChmaXRfYmlvXzV5X1NWKQkJCSAgDQogICMgc2V0Y2FwKCJFc3RpbWF0ZWQgY29ycmVsYXRpb25zIiwgIkVzdGltYXRlcyBjb3JyZWxhdGlvbnMgYmV0d2VlbiBhZ2UgZ3JvdXBzIGZvciBlYWNoIGZsZWV0IikNCiAgIyBzdGFtcGl0KGZpdCkNCn0gZWxzZSB7DQogIHByaW50KCJObyBjb3JyZWxhdGlvbiBzdHJ1Y3R1cmUgY29uZmlndXJlZCBmb3IgcmVzaWR1YWxzIGFjcm9zcyBhZ2UuIikNCn0NCg0KYGBgDQoNCmBgYHtyIGZpZy5jYXA9Ik9uZSBvYnNlcnZhdGlvbiBhaGVhZCByZXNpZHVhbHMgZm9yIHRoZSB0aHJlZSBmbGVldHMgKHJlZC9waW5rID0gb2JzZXJ2YXRpb24gbG93ZXIgdGhhbiBtb2RlbCBlc3RpbWF0ZSwgYmx1ZSA9IG9ic2VydmF0aW9uIGhpZ2hlciB0aGFuIG1vZGVsIGVzdGltYXRlLCBzaXplID0gbWFnbml0dWRlIG9mIHJlc2lkdWFsKSwgZnJvbSB0aGUgTW9kZWwgd2l0aCBCaW9wYXIgb24gU1dBIGFuZCBmaXZlIHllYXIgU1dNIG9uIE1PICh3aXRoIHN1cnZleSB2YXJpYXRpb24pLiJ9DQpnZ3Bsb3RseShnZ3Bsb3QocmVzaWRfYmlvXzV5X1NWX2RmKSArDQogICAgICAgICAgIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0geWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBhZ2UsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gYWJzKHJlc2lkdWFsKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IHJlc2lkdWFsID49IDApLA0KICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC43KSArDQogICAgICAgICAgIGZhY2V0X2dyaWQocm93cyA9ICJmbGVldEFsdE5hbWUiKSArDQogICAgICAgICAgIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiVFJVRSIgPSBlYnBhbFs4XSwgIkZBTFNFIiA9IGVicGFsWzldKSkgKw0KICAgICAgICAgICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygtMSwgOSksIGJyZWFrcyA9IGMoMTo5KSkgKw0KICAgICAgICAgICBndWlkZXMoY29sb3VyPUZBTFNFKSArDQogICAgICAgICAgIHRoZW1lX2ZldygpKQ0KDQpgYGANCg0KIyMjIyBKaXR0ZXJpbmcNCldlIGNhbiBhbHNvIHRlc3QgdG8gc2VlIGlmIHRoZSBtb2RlbCBpcyBjb252ZXJnaW5nIG9uIHNvbWUgbG9jYWwgbWluaW11bSAoaS5lLiBpdCdzIGZpdHRpbmcgdG8gc29tZSBzb2x1dGlvbiBjbG9zZSB0byBpbml0aWFsaXNpbmcgdmFsdWVzIHRoYXQgcmVwcmVzZW50cyBub2lzZSBhbmQgbm90IHRoZSBnbG9iYWwgc29sdXRpb24sIHRoYXQgaXMgdGhlIHByb3BlciBzb2x1dGlvbikuICBUbyBkbyB0aGlzLCB3ZSBhZGQgcmFuZG9tIG5vaXNlIHRvIHRoZSBpbml0aWFsIHBhcmFtZXRlciB2YWx1ZXMgdG8gc2VlIGlmIHRoZSBtb2RlbCB3aWxsIGNvbnZlcmdlIG9uIGEgZGlmZmVyZW50IG1pbmltdW0gaW4gaXQncyBkYXRhLXNwYWNlLiBUaGUgZWFzaWVzdCB3YXkgdG8gaW52ZXN0aWdhdGUgdGhpcyBpcyB0byBzZWUgaWYgdGhlIG1vZGVsIGZpdHMgdmFyeSBhbG90IGRlcGVuZGluZyBvbiB0aGUgc3RhcnRpbmcgdmFsdWVzOg0KYGBge3IgSml0dGVyX2Jpb181eV9TVn0NCmppdF9iaW9fNXlfU1YgPC0gaml0KGZpdCA9IGZpdF9iaW9fNXlfU1YpDQoNCm10IDwtIGFzLmRhdGEuZnJhbWUobW9kZWx0YWJsZShqaXRfYmlvXzV5X1NWKSkNCm10JG1vZGVsIDwtIHJvd25hbWVzKG10KQ0Kcm93bmFtZXMobXQpIDwtIE5VTEwNCg0Ka2FibGUoeCA9IG10LA0KICAgICAgZGlnaXRzID0gMywNCiAgICAgIGNhcHRpb24gPSAiTWVhc3VyZXMgb2YgIGZpdCBmb3IgYSBzZXJpZXMgb2YgbW9kZWwgcmVmaXRzIHdpdGggaml0dGVyIGFwcGxpZWQgdG8gdGhlIGlucHV0IHBhcmFtZXRlcnMuIikNCmBgYA0KDQojIyMjIExlYXZlLU9uZS1PdXQgQW5hbHlzZXMNCkEgbGVhdmUtb25lLW91dCBhbmFseXNpcyBpcyBhIGZvcm0gb2Ygc2Vuc2l0aXZpdHkgYW5hbHlzaXMsIHNob3dpbmcgdGhlIGltcGFjdCB0aGUgZGF0YSBmcm9tIGVhY2ggdHVuaW5nIGZsZWV0IGhhcyBvbiB0aGUgZXN0aW1hdGlvbiBvZiB0aGUga2V5IHZhcmlhYmxlcyBiZWluZyBlc3RpbWF0ZWQ7IG5hbWVseSBTU0IsIEYgYW5kIHJlY3J1aXRtZW50LiAgDQoNCkZpcnN0IHdlIG11c3QgcnVuIHRoZSBsZWF2ZS1vbmUtb3V0IGFuYWx5c2lzIHdoaWNoIHJlZml0cyB0aGUgbW9kZWwgaW4gdHdvIGl0ZXJhdGlvbnMsIHJlbW92aW5nIG9uZSBzdXJ2ZXkgYXQgYSB0aW1lLiBUaGVuIHdlIGNhbiBwbG90IGVhY2ggb2YgdGhlc2UgbmV3IG1vZGVsIGZpdHMgb3ZlciB0aGUgZnVsbCBtb2RlbCB0byBzZWUgdGhlIGltcGFjdCB0aGUgcmVtb3ZhbCBvZiBlYWNoIGhhcy4gDQoNCmBgYHtyIExlYXZlT25lT3V0X2Jpb181eV9TVn0NCkxPX2Jpb181eV9TViA8LSBsZWF2ZW91dChmaXRfYmlvXzV5X1NWKQ0KDQojPT09IA0KIyBHZXQgZGF0YSBmcm9tIHNhbSBvYmplY3RzIGFuZCBnZW5lcmF0ZSB1c2VhYmxlIGRhdGFmcmFtZXMNCiM9PT09DQpxMW1hdCA8LSBhcy5kYXRhLmZyYW1lKHN1bW1hcnkoTE9fYmlvXzV5X1NWJGB3Lm8uIFExSUJUUytCSVRTK0NvZFNEMjEtMjVgKSkNCnEzbWF0IDwtIGFzLmRhdGEuZnJhbWUoc3VtbWFyeShMT19iaW9fNXlfU1YkYHcuby4gUTM0SUJUUytCSVRTK0NvZFNEMjEtMjVgKSkNCg0KDQp3b3ExIDwtIGRhdGEuZnJhbWUoWWVhciA9IGFzLmludGVnZXIocm93Lm5hbWVzKHN1bW1hcnkoTE9fYmlvXzV5X1NWJGB3Lm8uIFExSUJUUytCSVRTK0NvZFNEMjEtMjVgKSkpLA0KICAgICAgICAgICAgICAgICAgIFNTQiA9IHExbWF0JFNTQiwNCiAgICAgICAgICAgICAgICAgICBGYmFyID0gcTFtYXQkYEZiYXIoMy01KWAsDQogICAgICAgICAgICAgICAgICAgUl9hZ2UxID0gcTFtYXQkYFIoYWdlIDEpYCwNCiAgICAgICAgICAgICAgICAgICBDYXRjaEVzdCA9IGNhdGNodGFibGUoTE9fYmlvXzV5X1NWJGB3Lm8uIFExSUJUUytCSVRTK0NvZFNEMjEtMjVgKVssMV0sDQogICAgICAgICAgICAgICAgICAgc2VyaWVzID0gcmVwKCJ3b19RMSIsIHRpbWVzID0gbnJvdyhxMW1hdCkpKQ0KDQp3b3EzNCA8LSBkYXRhLmZyYW1lKFllYXIgPSBhcy5pbnRlZ2VyKHJvdy5uYW1lcyhxM21hdFsoMjAwMjpEYXRhWWVhciktMjAwMSxdKSksDQogICAgICAgICAgICAgICAgICAgIFNTQiA9IHEzbWF0WygyMDAyOkRhdGFZZWFyKS0yMDAxLCAiU1NCIl0sDQogICAgICAgICAgICAgICAgICAgIEZiYXIgPSBxM21hdFsoMjAwMjpEYXRhWWVhciktMjAwMSwiRmJhcigzLTUpIl0sDQogICAgICAgICAgICAgICAgICAgIFJfYWdlMSA9IHEzbWF0WygyMDAyOkRhdGFZZWFyKS0yMDAxLCJSKGFnZSAxKSJdLA0KICAgICAgICAgICAgICAgICAgICBDYXRjaEVzdCA9IGNhdGNodGFibGUoTE9fYmlvXzV5X1NWJGB3Lm8uIFEzNElCVFMrQklUUytDb2RTRDIxLTI1YClbLDFdLA0KICAgICAgICAgICAgICAgICAgICBzZXJpZXMgPSByZXAoIndvX1EzNCIsIHRpbWVzID0gKG5yb3cocTNtYXQpLTEpKSkNCg0KDQphc3VtX2Jpb181eV9TViRzZXJpZXMgPC0gcmVwKCJmdWxsIiwgdGltZXMgPSBucm93KGFzdW1fYmlvXzV5X1NWKSkNCmFzdW1pX2Jpb181eV9TViA8LSBhc3VtX2Jpb181eV9TVlssIGMoIlllYXIiLCAiU1NCIiwgIkZiYXIiLCAiUl9hZ2UxIiwgIkNhdGNoRXN0IiAsInNlcmllcyIpXQ0KIz09PT09DQoNCmxvc3VtX2Jpb181eV9TViA8LSByYmluZCh3b3ExLCB3b3EzNCwgYXN1bWlfYmlvXzV5X1NWKQ0KDQpgYGANCg0KYGBge3IgZmlnLmNhcD0iTGVhdmUtb25lLW91dCByZS1maXRzIGZvciB0aGUgTW9kZWwgd2l0aCBCaW9wYXIgb24gU1dBIGFuZCBmaXZlIHllYXIgU1dNIG9uIE1PICh3aXRob3V0IFExID0gYmx1ZSwgd2l0aG91dCBRMy80ID0gcHVycGxlKSwgb3ZlcmxhaW4gd2l0aCBmdWxsIG1vZGVsIGVzdGltYXRlcyAoYmxhY2sgbGluZSBhbmQgZ3JleSByaWJib24pIG9mIFNTQiAodG9wIGxlZnQpLCBGICh0b3AgcmlnaHQpLCBSZWNydWl0bWVudCAoYm90dG9tIGxlZnQpLCBhbmQgY2F0Y2ggKGJvdHRvbSByaWdodDsgb2JzZXJ2YXRpb25zIGFzIHllbGxvdyArKS4ifQ0KIyBzc2JwbG90KExPKQ0KbG9zc2JfYmlvXzV5X1NWIDwtIGdncGxvdGx5KGdncGxvdCgpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fbGluZShkYXRhID0gbG9zdW1fYmlvXzV5X1NWLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1TU0IsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBzZXJpZXMpKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3JpYmJvbihkYXRhID0gYXN1bV9iaW9fNXlfU1YsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1pbj1TU0Jsb3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltYXg9U1NCaGlnaCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gImJsYWNrIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4yKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoImJsYWNrIiwgZWJwYWxbODo5XSkpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2NsZWFuKCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWUoYXhpcy50aXRsZS55LmxlZnQgPSBlbGVtZW50X3RleHQodmp1c3QgPSAtMC4wNSwgaGp1c3QgPSAwLjk1KSkpDQoNCiMgRnBsb3QoTE8pDQpsb2ZfYmlvXzV5X1NWIDwtIGdncGxvdGx5KGdncGxvdCgpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IGxvc3VtX2Jpb181eV9TViwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1GYmFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IHNlcmllcykpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3JpYmJvbihkYXRhID0gYXN1bV9iaW9fNXlfU1YsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWluPUZsb3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4PUZoaWdoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gImJsYWNrIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMykgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiYmxhY2siLCBlYnBhbFs4OjldKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2NsZWFuKCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKGF4aXMudGl0bGUueS5sZWZ0ID0gZWxlbWVudF90ZXh0KHZqdXN0ID0gLTAuMDUsIGhqdXN0ID0gMC45NSkpKQ0KDQojIHJlY3Bsb3QoTE8pDQpsb3JlY19iaW9fNXlfU1YgPC0gZ2dwbG90bHkoZ2dwbG90KCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9saW5lKGRhdGEgPSBsb3N1bV9iaW9fNXlfU1YsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PVJfYWdlMSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IHNlcmllcykpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fcmliYm9uKGRhdGEgPSBhc3VtX2Jpb181eV9TViwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWluPVJsb3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltYXg9UmhpZ2gpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9ICJibGFjayIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMykgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCJibGFjayIsIGVicGFsWzg6OV0pKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9jbGVhbigpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKGF4aXMudGl0bGUueS5sZWZ0ID0gZWxlbWVudF90ZXh0KHZqdXN0ID0gLTAuMDUsIGhqdXN0ID0gMC45NSkpKQ0KDQojIENhdGNoIHBsb3QgKExPKQ0KbG9jYV9iaW9fNXlfU1YgPC0gZ2dwbG90bHkoZ2dwbG90KCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IGxvc3VtX2Jpb181eV9TViwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PUNhdGNoRXN0LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBzZXJpZXMpKSsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9yaWJib24oZGF0YSA9IGFzdW1fYmlvXzV5X1NWW2FzdW1fYmlvXzV5X1NWJFllYXIgIT0gKERhdGFZZWFyKzEpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWluPUNhdGNobG93LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltYXg9Q2F0Y2hoaWdoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9ICJibGFjayIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4zKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fcG9pbnQoZGF0YSA9IGFzdW1fYmlvXzV5X1NWW2FzdW1fYmlvXzV5X1NWJFllYXIgIT0gKERhdGFZZWFyKzEpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1DYXRjaE9icyksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hhcGUgPSAzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IGVicGFsWzVdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBlYnBhbFs1XSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bGFiKCJDYXRjaCAodG9ubmVzKSIpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCJibGFjayIsIGVicGFsWzg6OV0pKSsgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2NsZWFuKCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZShheGlzLnRpdGxlLnkubGVmdCA9IGVsZW1lbnRfdGV4dCh2anVzdCA9IC0wLjA1LCBoanVzdCA9IDAuOTUpKSkNCg0KbGF5b3V0KHN1YnBsb3QobG9zc2JfYmlvXzV5X1NWLCBsb2ZfYmlvXzV5X1NWLCBsb3JlY19iaW9fNXlfU1YsIGxvY2FfYmlvXzV5X1NWLCBucm93cyA9IDIsIHNoYXJlWCA9IFRSVUUsIHRpdGxlWSA9IFRSVUUpLCBzaG93bGVnZW5kPUZBTFNFKQ0KYGBgDQoNCiMjIyMgUmV0cm9zcGVjdGl2ZSBBbmFseXNlcw0KQW5vdGhlciB3YXkgdG8gaW50ZXJyb2dhdGUgdGhlIG1vZGVsJ3MgYWJpbGl0eSB0byBmaXQgdG8gZGF0YSBpcyB0byBjaGFuZ2UgdGhlIGlucHV0IGRhdGEuIEJ5IGRyb3BwaW5nIHllYXJzIHNlcXVlbnRpYWxseSBmcm9tIHRoZSBsYXRlc3QgeWVhciwgYmFja3dhcmRzLCBhbmQgcmVmaXR0aW5nIHRoZSBtb2RlbCB0byB0aGVzZSBkYXRhLCB3ZSBjYW4gdmlzdWFsaXNlIGhvdyB0aGlzICJ0dW5lZCIgbW9kZWwgcGVyZm9ybXMgaW4gZGlmZmVyZW50IGRhdGEgc2l0dWF0aW9ucy4gDQoNCkluIHRoaXMgY2FzZSwgb3VyIG1vZGVsIGZpdCBpbmNsdWRlZCB0aGUgd2l0aGluLWFzc2Vzc2VtZW50IHllYXIgUTEgc3VydmV5IGluZGV4IGFzIGEgdHVuaW5nIGZsZWV0LCB0aGVyZWZvcmUsIHdlIGFyZSBkb2luZyB0aGUgcGVlbHMgYW5kIGNhbGN1bGF0aW5nIHRoZSBNb2huJ3MgcmhvIG9uIGRhdGEgdHJ1bmNhdGVkIGJ5IG9uZSB5ZWFyLCBzbyB0aGF0IHdlIGFyZW4ndCBqdWRnaW5nIHRoZSBtb2RlbCBmaXQgd2l0aCB0aGUgeWVhciBpbiB3aGljaCBpdCBkb2Vzbid0IGhhdmUgY2F0Y2ggZGF0YSBub3IgdGhlIHNlY29uZCBpbmRleC4gDQoNCmBgYHtyIGNhbGN1bGF0ZVJldHJvc19iaW9fNXlfU1Z9DQpSRVRST19iaW9fNXlfU1Y8LXJldHJvKGZpdF9iaW9fNXlfU1YsIHllYXI9NSkNCnJob19iaW9fNXlfU1YgPC0gbW9obihSRVRST19iaW9fNXlfU1YsIGxhZyA9IDEpDQoNCiMjIE1ha2UgUkVUUk9zIGluIGJldHRlciBwbG90dGluZyBmb3JtYXQNCnJldF9iaW9fNXlfU1ZfZGYgPC0gYXN1bV9iaW9fNXlfU1ZbYXN1bV9iaW9fNXlfU1YkWWVhciAhPSBtYXgoYXN1bV9iaW9fNXlfU1YkWWVhciksIF0NCnJldF9iaW9fNXlfU1ZfZGYkc2VyaWVzIDwtIHJlcCgiZnVsbCIsIG5yb3cocmV0X2Jpb181eV9TVl9kZikpDQoNCmZvcihpIGluIDE6bGVuZ3RoKFJFVFJPX2Jpb181eV9TVikpew0KICB0c3VtIDwtIGFzLmRhdGEuZnJhbWUoc3VtbWFyeShSRVRST19iaW9fNXlfU1ZbW2ldXSkpDQogIHRzdW0kWWVhciA8LSBhcy5pbnRlZ2VyKHJvdy5uYW1lcyhzdW1tYXJ5KFJFVFJPX2Jpb181eV9TVltbaV1dKSkpDQogIHRzdW0gPC0gY2JpbmQodHN1bSwgY2F0Y2h0YWJsZShSRVRST19iaW9fNXlfU1ZbW2ldXSwgb2JzLnNob3cgPSBUUlVFKSkNCiAgdHN1bSRzZXJpZXMgPC0gYXMuY2hhcmFjdGVyKHJlcChpLCBucm93KHRzdW0pKSkNCiAgY29sbmFtZXModHN1bSkgPC0gYygiUl9hZ2UxIiwgIlJsb3ciLCAiUmhpZ2giLCAiU1NCIiwgIlNTQmxvdyIsICJTU0JoaWdoIiwgIkZiYXIiLCAiRmxvdyIsICJGaGlnaCIsICJZZWFyIiwgIkNhdGNoRXN0IiwgIkNhdGNobG93IiwgIkNhdGNoaGlnaCIsICJDYXRjaE9icyIsICJzZXJpZXMiKQ0KICB0c3VtIDwtIHRzdW1bdHN1bSRZZWFyICE9IG1heCh0c3VtJFllYXIpLCBdDQogIHJldF9iaW9fNXlfU1ZfZGYgPC0gcmJpbmQocmV0X2Jpb181eV9TVl9kZiwgdHN1bSkNCn0NCnJldF9iaW9fNXlfU1ZfZGYkc2VyaWVzIDwtIGZhY3RvcihyZXRfYmlvXzV5X1NWX2RmJHNlcmllcywgbGV2ZWxzID0gYygiZnVsbCIsICIxIiwgIjIiLCAiMyIsICI0IiwgIjUiKSkNCmBgYA0KDQpgYGB7ciBmaWcuY2FwPSJSZXRyb3NwZWN0aXZlIGFuYWx5c2VzIGZvciBTU0IgKHRvcC1sZWZ0KSwgRiBmb3IgYWdlcyAzLTUgKHRvcC1yaWdodCksIHJlY3J1aXRtZW50IChib3R0b20tbGVmdCksIGFuZCBjYXRjaCAoYm90dG9tLXJpZ2h0KSwgZnJvbSB0aGUgbW9kZWwgdXRpbGlzaW5nIEJpb3BhciBmb3IgU1dBIGFuZCBmaXZlIHllYXIgc2xpZGluZyB3aW5kb3cgbWVhbnMgZm9yIG1hdHVyaXR5IGFuZCBzdXJ2ZXkgaW5kaWNlcycgY29lZmZpY2llbnRzIG9mIHZhcmlhdG9uLiJ9DQojIHNzYnBsb3QoUkVUUk8pDQpyZXRzc2JfYmlvXzV5X1NWIDwtIGxheW91dChnZ3Bsb3RseShnZ3Bsb3QoKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fbGluZShkYXRhID0gcmV0X2Jpb181eV9TVl9kZiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PVNTQiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gc2VyaWVzKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3JpYmJvbihkYXRhID0gYXN1bV9iaW9fNXlfU1ZbYXN1bV9iaW9fNXlfU1YkWWVhciAhPSBtYXgoYXN1bV9iaW9fNXlfU1YkWWVhciksIF0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW49U1NCbG93LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltYXg9U1NCaGlnaCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSAiYmxhY2siLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMikgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbm5vdGF0ZShnZW9tID0gInRleHQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gbWF4KHJldF9iaW9fNXlfU1ZfZGYkU1NCaGlnaCkqMC44NSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeCA9ICgobWF4KHJldF9iaW9fNXlfU1ZfZGYkWWVhciktbWluKHJldF9iaW9fNXlfU1ZfZGYkWWVhcikpKjAuMjApK21pbihyZXRfYmlvXzV5X1NWX2RmJFllYXIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbCA9IHBhc3RlMCgiTW9obidzIFJobyA9ICIsIHJvdW5kKHJob19iaW9fNXlfU1ZbMl0sIGRpZ2l0cyA9IDMpKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoImJsYWNrIiwgZWJwYWxbKGxlbmd0aChlYnBhbCktNCk6bGVuZ3RoKGVicGFsKV0pKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2NsZWFuKCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF4aXMudGl0bGUueS5sZWZ0ID0gZWxlbWVudF90ZXh0KHZqdXN0ID0gLTAuMDUsIGhqdXN0ID0gMC45NSkpKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHNob3dsZWdlbmQgPSBGQUxTRSkNCg0KIyBGcGxvdChSRVRSTykNCnJldGZfYmlvXzV5X1NWIDwtIGxheW91dChnZ3Bsb3RseShnZ3Bsb3QoKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IHJldF9iaW9fNXlfU1ZfZGYsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PUZiYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBzZXJpZXMpKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3JpYmJvbihkYXRhID0gYXN1bV9iaW9fNXlfU1ZbYXN1bV9iaW9fNXlfU1YkWWVhciAhPSBtYXgoYXN1bV9iaW9fNXlfU1YkWWVhciksIF0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1pbj1GbG93LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4PUZoaWdoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSAiYmxhY2siLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjMpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFubm90YXRlKGdlb20gPSAidGV4dCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gbWF4KHJldF9iaW9fNXlfU1ZfZGYkRmhpZ2gpKjAuODUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4ID0gKChtYXgocmV0X2Jpb181eV9TVl9kZiRZZWFyKS1taW4ocmV0X2Jpb181eV9TVl9kZiRZZWFyKSkqMC44MCkrbWluKHJldF9iaW9fNXlfU1ZfZGYkWWVhciksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbCA9IHBhc3RlMCgiTW9obidzIFJobyA9ICIsIHJvdW5kKHJob19iaW9fNXlfU1ZbM10sIGRpZ2l0cyA9IDMpKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCJibGFjayIsIGVicGFsWyhsZW5ndGgoZWJwYWwpLTQpOmxlbmd0aChlYnBhbCldKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWVfY2xlYW4oKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBheGlzLnRpdGxlLnkubGVmdCA9IGVsZW1lbnRfdGV4dCh2anVzdCA9IC0wLjA1LCBoanVzdCA9IDAuOTUpKSksDQogICAgICAgICAgICAgICAgICAgICAgICAgc2hvd2xlZ2VuZCA9IEZBTFNFKQ0KDQojIHJlY3Bsb3QoUkVUUk8pDQpyZXRyZWNfYmlvXzV5X1NWIDwtIGxheW91dChnZ3Bsb3RseShnZ3Bsb3QoKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fbGluZShkYXRhID0gcmV0X2Jpb181eV9TVl9kZiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PVJfYWdlMSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gc2VyaWVzKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3JpYmJvbihkYXRhID0gYXN1bV9iaW9fNXlfU1ZbYXN1bV9iaW9fNXlfU1YkWWVhciAhPSBtYXgoYXN1bV9iaW9fNXlfU1YkWWVhciksIF0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW49UmxvdywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4PVJoaWdoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9ICJibGFjayIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4zKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFubm90YXRlKGdlb20gPSAidGV4dCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9IG1heChyZXRfYmlvXzV5X1NWX2RmJFJoaWdoKSowLjg1LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4ID0gKChtYXgocmV0X2Jpb181eV9TVl9kZiRZZWFyKS1taW4ocmV0X2Jpb181eV9TVl9kZiRZZWFyKSkqMC4yMCkrbWluKHJldF9iaW9fNXlfU1ZfZGYkWWVhciksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsID0gcGFzdGUwKCJNb2huJ3MgUmhvID0gIiwgcm91bmQocmhvX2Jpb181eV9TVlsxXSwgZGlnaXRzID0gMykpKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiYmxhY2siLCBlYnBhbFsobGVuZ3RoKGVicGFsKS00KTpsZW5ndGgoZWJwYWwpXSkpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWVfY2xlYW4oKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXhpcy50aXRsZS55LmxlZnQgPSBlbGVtZW50X3RleHQodmp1c3QgPSAtMC4wNSwgaGp1c3QgPSAwLjk1KSkpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hvd2xlZ2VuZCA9IEZBTFNFKQ0KDQojIENhdGNoIHBsb3QgKFJFVFJPKQ0KcmV0Y2FfYmlvXzV5X1NWIDwtIGdncGxvdGx5KGdncGxvdCgpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fbGluZShkYXRhID0gcmV0X2Jpb181eV9TVl9kZiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9Q2F0Y2hFc3QsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBzZXJpZXMpKSsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fcmliYm9uKGRhdGEgPSBhc3VtX2Jpb181eV9TVlthc3VtX2Jpb181eV9TViRZZWFyICE9IG1heChhc3VtX2Jpb181eV9TViRZZWFyKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWluPUNhdGNobG93LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4PUNhdGNoaGlnaCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gImJsYWNrIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4zKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3BvaW50KGRhdGEgPSBhc3VtX2Jpb181eV9TVlthc3VtX2Jpb181eV9TViRZZWFyICE9IG1heChhc3VtX2Jpb181eV9TViRZZWFyKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1DYXRjaE9icyksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNoYXBlID0gMywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gZWJwYWxbNV0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBlYnBhbFs1XSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeWxhYigiQ2F0Y2ggKHRvbm5lcykiKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoImJsYWNrIiwgZWJwYWxbKGxlbmd0aChlYnBhbCktNCk6bGVuZ3RoKGVicGFsKV0pKSsgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9jbGVhbigpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKGF4aXMudGl0bGUueS5sZWZ0ID0gZWxlbWVudF90ZXh0KHZqdXN0ID0gLTAuMDUsIGhqdXN0ID0gMC45NSkpKQ0KDQpyZXRfZnAgPC0gc3R5bGUoc3VicGxvdChyZXRzc2JfYmlvXzV5X1NWLCByZXRmX2Jpb181eV9TViwgcmV0cmVjX2Jpb181eV9TViwgcmV0Y2FfYmlvXzV5X1NWLCBucm93cyA9IDIsIHNoYXJlWCA9IEZBTFNFLCBzaGFyZVkgPSBGQUxTRSwgdGl0bGVZID0gVFJVRSksDQogICAgICAgICAgICAgICAgc2hvd2xlZ2VuZD1GQUxTRSwNCiAgICAgICAgICAgICAgICB0cmFjZXMgPSBjKDg6KCg3KjQpKzIpKSkNCg0KbGF5b3V0KHJldF9mcCwgbGVnZW5kID0gbGlzdChvcmllbnRhdGlvbiA9ICdoJywgeCA9IDAuNSwgeGFuY2hvciA9ICdjZW50ZXInLCB5ID0gLTAuMDUsIHlhbmNob3IgPSAndG9wJywgYm9yZGVyd2lkdGggPSAwKSkNCmBgYA0KDQojIyMgUmVtYXJrcyBhYm91dCB0aGUgTW9kZWwgd2l0aCBCaW9wYXIgb24gU1dBIGFuZCBmaXZlIHllYXIgU1dNIG9uIE1PIChzdXJ2ZXkgdmFyaWF0aW9uKSBDb25maWd1cmF0aW9uDQpUaGUgY29tYmluYXRpb24gb2YgdGhlIGJpb3BhciBzbW9vdGhpbmcgb24gdGhlIHN0b2NrIHdlaWdodHMgYXQgYWdlIGFuZCB0aGUgc2xpZGluZyB3aW5kb3cgbWVhbiBvbiB0aGUgbWF0dXJpdHkgb2dpdmVzLCByZXN1bHRzIGluIG1vcmUgdmFyaWFiaWxpdHkgaW4gU1NCIGVzdGltYXRlcywgdGhhbiB0aGUgZml2ZSB5ZWFyIHNsaWRpbmcgd2luZG93IGFwcGxpZWQgdG8gYm90aC4gIFRoZSBleHRlbnNpb24gb2YgdGhlIHRpbWUgc2VyaWVzIHRvIGluY2x1ZGUgdGhlIFExIHN1cnZleSBmcm9tIHRoZSBpbi1hc3Nlc3NtZW50LXllYXIsIGxlYWRzIHRvIGEgaGlnaGVyIFNTQiBlc3RpbWF0ZSBpbiBsYXRlciB5ZWFycy4NCg0KTGFyZ2UgbmVnYXRpdmUgcmVzaWR1YWxzIGluIHRoZSBtb3N0IHJlY2VudCB5ZWFycywgYWNyb3NzIG1vc3QgKHNvbWV0aW1lcyBhbGwpIGFnZXMgYW5kIGFsbCBmbGVldHMsIGFyZSBwZXJzaXN0ZW50IGFjcm9zcyBhbGwgb3B0aW9ucyBvZiBtb2RlbCBzdHJ1Y3R1cmUgYW5kIG1vZGVsIHR1bmluZy4gVGhpcyBzdWdnZXN0cyB0aGF0IHRoZXJlIG1heSBiZSB1bmV4cGxhaW5lZCBtb3J0YWxpdHkgaW4gb3VyIG1vZGVsIGFuZCB0aGF0IHdlIG1heSBuZWVkIHRvIGFkanVzdCB0aGUgZml4ZWQgbmF0dXJhbCBtb3J0YWxpdHkgdmFsdWVzIHRoYXQgd2UndmUgaW5oZXJpdGVkIGZyb20gdGhlIHByZXZpb3VzIHR3byBpbmRlcGVuZGVudCBwbGFpY2Ugc3RvY2tzLiANCg0KIyBNb2RlbHMgd2l0aCBOZXcgTmF0dXJhbCBNb3JhbGl0eSAtIEdyb3d0aCBwYXJhbWV0ZXJzIGZyb20gZGF0YQ0KQmFzZWQgb24gZGlzY3Vzc2lvbiBpbiB0aGUgd29ya2luZyBncm91cCwgdGhlIG1vZGVsIHRoYXQgdXRpbGlzZXMgU0FNJ3MgQmlvUGFyIG9wdGlvbiBmb3IgZml0dGluZyB0byBvYnNlcnZlZCBzdG9jayB3ZWlnaHRzIGF0IGFnZSBhbmQgYSBmaXZlIHllYXIgc2xpZGluZyB3aW5kb3cgZm9yIHRoZSBtYXR1cml0eSBvZ2l2ZXMgd2FzIHNlbGVjdGVkIHRvIGNvbnRpbnVlIGludmVzdGlnYXRpb25zLiANCg0KSG93ZXZlciwgbGlrZSBtb3N0IG90aGVyIG1vZGVsIHJ1bnMsIHRoaXMgbW9kZWwgcmV0YWlucyBhIGxvdCBvZiBuZWdhdGl2ZSByZXNpZHVhbHMgaW4gcmVjZW50IHllYXJzLCBhY3Jvc3MgYWxsIGZsZWV0cywgaW5kaWNhdGluZyB0aGF0IGNhdGNoZXMgd2VyZSBiZWxvdyB3aGF0IHdhcyBlc3RpbWF0ZWQgZm9yIGFsbCBmbGVldHMuICBUaGlzIHdhcyBjb25jZXJuaW5nLCBhcyB0aGVyZSBhcHBlYXJlZCB0byBiZSBubyBiYXNpcyBpbiB0aGUgZGF0YSBmb3IgdGhlIG1vZGVsIGVzdGltYXRpb25zIGluIHRoZSBsYXRlc3QgeWVhcnMuICBCYXNlZCBvbiB0aGlzIHdlIGRlY2lkZWQgdG8gcmUtdmlzaXQgdGhlIF9pbmhlcml0ZWRfIG5hdHVyYWwgbW9ydGFsaXRpZXMgZnJvbSB0aGUgUGxlLjI3LjIxLTIzIGFuZCBQbGUuMjcuMjQtMzIgc3RvY2tzLiAgVGhlc2Ugd2VyZSB0aW1lIGludmFyaWFudCBhbmQgc2V0IHRvIDAuMiBmb3IgYWdlIDEsIGFuZCAwLjEgZm9yIGFsbCBvdGhlciBhZ2VzLiANCg0KSW4gdGhpcyBzZWN0aW9uIHdlIGNoYW5nZSBvbmx5IHRoZSBpbnB1dCB2YWx1ZXMgZm9yIHRoZSBuYXR1cmFsIG1vcnRhbGl0eSBhbmQgd2UgZG8gc28gYmFzZWQgb24gdGhyZWUgaHlwb3RoZXNlczoNCjEuIFRoYXQgbmF0dXJhbCBtb3J0YWxpdHkgaXMgaGlnaGVyIGZvciB5b3VuZ2VyIGFnZXMgYW5kIHRoYXQgaXQgZm9sbG93cyBhIGdlbmVyYWwgbW9kZWwgZWxhYm9yYXRlZCBieSBHaXNsYXNvbiBldCBhbC4sIDIwMTAuDQphLiB0aGlzIG1vZGVsIGlzIGJhc2VkIG9uIGxpZmUtaGlzdG9yeSBwYXJhbWV0ZXJzIGFuZCBzaXplLg0KYi4gdGhpcyBtb2RlbCBpcyBnZW5lcmFsbHkgYXBwbGljYWJsZSBhY3Jvc3MgdGhlIHdob2xlIHRpbWUgc2VyaWVzLg0KMi4gVGhhdCB0aGUgc2hhcGUgb2YgdGhlIGRlY2xpbmUgaW4gbmF0dXJhbCBtb3J0YWxpdHkgd2l0aCBhZ2UgZnJvbSBHaXNsYXNvbiBldCBhbC4ncyBtb2RlbCBpcyBjb3JyZWN0LCBidXQgdGhhdCBmb3IgdGhlIHRpbWUgaW52YXJpYW50IHZlcnNpb24gb2YgdGhlc2UgbmF0dXJhbCBtb3J0YWxpdGllcywgdGhlIGFic29sdXRlIHZhbHVlcyBtYXkgYmUgZGlmZmVyZW50LCBkdWUgdG8gdW4tY2FsY3VsYXRlZCB3ZWlnaHRpbmcgaW4gdGhlIG51bWJlcnMgdXNlZCB0byBjYWxjdWxhdGUgdGhlIHRpbWUtaW52YXJpYW50IG1lYW4uIA0KMy4gVGhhdCBhIEdpc2xhc29uIG1vZGVsIHBhcmFtYXRlcmlzZWQgYnkgbGlmZS1oaXN0b3J5IHRyYWl0cyBjb2xsYXRlZCBhY3Jvc3MgdGhlIHdob2xlIHRpbWUtc2VyaWVzIGNhbiBiZSBhcHBsaWVkIHRvIGFubnVhbCBsZW5ndGgtYXQtYWdlIGRhdGEgdG8gYWNjdXJhdGVseSBwcm9kdWNlIHRpbWUgYW5kIGFnZSB2YXJ5aW5nIG1vcnRhbGl0aWVzLg0KYS4gdGhlc2UgYW5udWFsbHkgdmFyeWluZyBtb3J0YWxpdGllcyBtYXkgYmUgbm9pc3kgZHVlIHRvIG5vaXNlIGluIGFubnVhbCBsZW5ndGggc2FtcGxlcywgdGhlcmVmb3JlIGEgZml2ZS15ZWFyIHNsaWRpbmcgd2luZG93IG1lYW4gaXMgYXBwbGllZCB0byB0aGVtIGJlZm9yZSBpbnB1dCB0byBTQU0uDQoNCiMjIFRpbWUgSW52YXJpYW50LCBHaXNsYXNvbiBOYXR1cmFsIE1vcnRhbGl0eQ0KIyMjIEZpdHMgdG8gZGF0YQ0KDQpgYGB7ciBubUdGaXRGcm9tV2VifQ0KZml0X25tRyA8LSBmaXRmcm9td2ViKCJwbGUuMjcuMjEtMzJfV0tCUExBSUNFXzIwMjRfQmlvUGFyc3dfU1Zfbm1HIikNCiMgZml0X25tRyA8LSBzdG9ja2Fzc2Vzc21lbnQ6OjpyZWZpdChmaXRfbm1HKQ0KYGBgDQoNCmBgYHtyIGRhdGFmcmFtZVN1bW1hcnlfbm1HLCByZXN1bHRzPSdoaWRlJywgZmlnLnNob3c9J2hpZGUnfQ0KIz09PQ0KIyBDcmVhdGUgZGF0YWZyYW1lIG9mIGN1cnJlbnQgeWVhcidzIGZpdCBmb3IgcGxvdHRpbmcNCiM9PT09DQojIElDX2FnZ190ZW1wIDwtIGFnZ3JlZ2F0ZShDQVRPTn5ZZWFyLCBpY19jbGVhbltpY19jbGVhbiRDYXRjaENhdGVnb3J5ICVpbiUgYygiTGFuZGluZ3MiLCAiRGlzY2FyZHMiKSwgXSwgRlVOID0gInN1bSIpDQphc3VtX25tRyA8LSBhcy5kYXRhLmZyYW1lKHN1bW1hcnkoZml0X25tRykpDQphc3VtX25tRyRZZWFyIDwtIGFzLmludGVnZXIocm93Lm5hbWVzKHN1bW1hcnkoZml0X25tRykpKQ0KY3Rfbm1HIDwtIGFzLmRhdGEuZnJhbWUoY2F0Y2h0YWJsZShmaXRfbm1HLCBvYnMuc2hvdyA9IFRSVUUpKQ0KY3Rfbm1HJFllYXIgPC0gYXMuaW50ZWdlcihyb3duYW1lcyhjdF9ubUcpKQ0Kcm93bmFtZXMoY3Rfbm1HKSA8LSBOVUxMDQpjdF9ubUcgPC0gcmJpbmQoY3Rfbm1HLCBkYXRhLmZyYW1lKEVzdGltYXRlID0gTkEsIExvdz1OQSwgSGlnaD1OQSwgc29wLmNhdGNoPU5BLCBZZWFyPWFzLmludGVnZXIoMjAyNCkpKQ0KYXN1bV9ubUcgPC0gbWVyZ2UoeCA9IGFzdW1fbm1HLCB5ID0gY3Rfbm1HLCBieSA9ICJZZWFyIikNCmNvbG5hbWVzKGFzdW1fbm1HKSA8LSBjKCJZZWFyIiwgIlJfYWdlMSIsICJSbG93IiwgIlJoaWdoIiwgIlNTQiIsICJTU0Jsb3ciLCAiU1NCaGlnaCIsICJGYmFyIiwgIkZsb3ciLCAiRmhpZ2giLCAiQ2F0Y2hFc3QiLCAiQ2F0Y2hsb3ciLCAiQ2F0Y2hoaWdoIiwgIkNhdGNoT2JzIikNCiM9PT09PQ0KYGBgDQoNCldoZW4gdGhlIG1vZGVsIGlzIHJ1biB3ZSBjYW4gZWFzaWx5IHNlZSBmcm9tIHdhcm5pbmdzL2Vycm9ycyBpZiB0aGVyZSBpcyBhIGNvbnZlcmdlbmNlIGlzc3VlLiAgSG93ZXZlciwgd2UgY2FuIGFsc28gY29uZmlybSB0aGlzLCBleHBsaWNpdGx5Og0KLSBUaGUgZmluYWwgbW9kZWwgZ3JhZGllbnQ6IGByIGZpdF9ubUckb3B0JGV2YWx1YXRpb25zWzJdYA0KLSBUaGF0IHRoZXJlIGlzIGEgcG9zaXRpdmUgZGVmaW5pdGUgaGVzc2lhbjogYHIgYWxsKGVpZ2VuKGZpdF9ubUckb3B0JGhlKSR2YWx1ZXMgPjApYA0KDQpGdXJ0aGVybW9yZSwgU0FNIGRvZXMgbm90IHV0aWxpc2UgImJvdW5kcyIgd2hlbiBmaXR0aW5nIHRoZSBtb2RlbCwgYW5kIHRoZXJlZm9yZSwgYXMgc3RhbmRhcmQgY2hlY2sgb2Ygd2hldGhlciBtb2RlbCBwYXJhbWV0ZXJzIGFyZSBhcHByb2FjaGluZyB0aGVpciBib3VuZHMgaXMgaXJyZWxldmFudC4NCg0KQWxyZWFkeSB3aXRoIHRoZSBuZXcgbW9ydGFsaXRpZXMgd2Ugc2VlIHJlZHVjZWQgZGlyZWN0aW9uYWxpdHkgaW4gdGhlIHJlc2lkdWFscyBmb3IgYWxsIGZsZWV0cyBpbiByZWNlbnQgeWVhcnMuICBGaXRzIHRvIG9ic2VydmVkIGNhdGNoZXMgYWxzbyBsb29rIG11Y2ggYmV0dGVyLg0KDQpgYGB7ciBmaWcuY2FwPSJNb2RlbCB3aXRoIHRpbWUgaW52YXJpYW50IEdpc2xhc29uIG5hdHVyYWwgbW9ydGFsaXRpZXMgZml0IHRvIGNhdGNoIGRhdGEgYnkgYWdlICh2YWx1ZXMgb24gdGhlIG1vZGVsIGxpbmsgZnVuY3Rpb24gc2NhbGUpLiJ9DQojIyBFeHRyYWN0IGRhdGEgZnJvbSBtb2RlbCBvYmplY3QNCmxvZ09ic19ubUcgPC0gc3BsaXQoZml0X25tRyRkYXRhJGxvZ29icywgY2VpbGluZyhzZXFfYWxvbmcoZml0X25tRyRkYXRhJGxvZ29icykvZml0X25tRyRkYXRhJG1heEFnZVBlckZsZWV0WzFdKSkNCmxvZ1ByZWRfbm1HIDwtIHNwbGl0KGZpdF9ubUckcmVwJHByZWRPYnMsIGNlaWxpbmcoc2VxX2Fsb25nKGZpdF9ubUckcmVwJHByZWRPYnMpL2ZpdF9ubUckZGF0YSRtYXhBZ2VQZXJGbGVldFsxXSkpDQoNCiMjIFRyYW5zZm9ybSBkYXRhIHRvIHVzZWFibGUgZGF0YWZyYW1lcw0KIyMjIEluaXRpYWxpemUgYW4gZW1wdHkgZGF0YSBmcmFtZSBmb3Igb2JzZXJ2YXRpb25zDQpsb2dPYnNfbm1HX2RmIDwtIGRhdGEuZnJhbWUoYWdlID0gaW50ZWdlcigpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZsZWV0ID0gaW50ZWdlcigpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllYXIgPSBpbnRlZ2VyKCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9nT2JzID0gbnVtZXJpYygpKQ0KDQojIyMgUG9wdWxhdGUgdGhlIGRhdGEgZnJhbWUgZm9yIG9ic2VydmF0aW9ucw0KZm9yIChpIGluIHNlcV9hbG9uZyhsb2dPYnNfbm1HKSkgew0KICAjIENhbGN1bGF0ZSB0aGUgZ3JvdXAgYW5kIHllYXINCiAgeWVhciA8LSAoKGkgLSAxKSAlLyUgMykgKyAxDQogIGZsZWV0IDwtICgoaSAtIDEpICUlIDMpICsgMQ0KICANCiAgIyMjIENyZWF0ZSBhIHRlbXBvcmFyeSBkYXRhIGZyYW1lIGFuZCBhcHBlbmQgdG8gdGhlIG1haW4gZGF0YSBmcmFtZSBmb3Igb2JzZXJ2YXRpb25zDQogIHRlbXBfZGYgPC0gZGF0YS5mcmFtZShhZ2UgPSAxOjcsDQogICAgICAgICAgICAgICAgICAgICAgICBmbGVldCA9IGZsZWV0LA0KICAgICAgICAgICAgICAgICAgICAgICAgeWVhciA9IHllYXIrMjAwMSwNCiAgICAgICAgICAgICAgICAgICAgICAgIGxvZ09icyA9IGxvZ09ic19ubUdbW2ldXSkNCiAgbG9nT2JzX25tR19kZiA8LSByYmluZChsb2dPYnNfbm1HX2RmLCB0ZW1wX2RmKQ0KfQ0KDQojIyMgSW5pdGlhbGl6ZSBhbiBlbXB0eSBkYXRhIGZyYW1lIGZvciBwcmVkaWN0aW9ucw0KbG9nUHJlZF9ubUdfZGYgPC0gZGF0YS5mcmFtZShhZ2UgPSBpbnRlZ2VyKCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZsZWV0ID0gaW50ZWdlcigpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ZWFyID0gaW50ZWdlcigpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2dQcmVkID0gbnVtZXJpYygpKQ0KDQojIyMgUG9wdWxhdGUgdGhlIGRhdGEgZnJhbWUgZm9yIHByZWRpY3Rpb25zDQpmb3IgKGkgaW4gc2VxX2Fsb25nKGxvZ1ByZWRfbm1HKSkgew0KICAjIENhbGN1bGF0ZSB0aGUgZ3JvdXAgYW5kIHllYXINCiAgeWVhciA8LSAoKGkgLSAxKSAlLyUgMykgKyAxDQogIGZsZWV0IDwtICgoaSAtIDEpICUlIDMpICsgMQ0KICANCiAgIyMjIENyZWF0ZSBhIHRlbXBvcmFyeSBkYXRhIGZyYW1lIGFuZCBhcHBlbmQgdG8gdGhlIG1haW4gZGF0YSBmcmFtZSBmb3IgcHJlZGljdGlvbnMNCiAgdGVtcF9kZiA8LSBkYXRhLmZyYW1lKGFnZSA9IDE6NywNCiAgICAgICAgICAgICAgICAgICAgICAgIGZsZWV0ID0gZmxlZXQsDQogICAgICAgICAgICAgICAgICAgICAgICB5ZWFyID0geWVhcisyMDAxLA0KICAgICAgICAgICAgICAgICAgICAgICAgbG9nUHJlZCA9IGxvZ1ByZWRfbm1HW1tpXV0pDQogIGxvZ1ByZWRfbm1HX2RmIDwtIHJiaW5kKGxvZ1ByZWRfbm1HX2RmLCB0ZW1wX2RmKQ0KfQ0KDQojIyBQbG90DQpsb2dQcmVkX25tR19kZiRhZ2UgPC0gYXMuY2hhcmFjdGVyKGxvZ1ByZWRfbm1HX2RmJGFnZSkNCmxvZ09ic19ubUdfZGYkYWdlIDwtIGFzLmNoYXJhY3Rlcihsb2dPYnNfbm1HX2RmJGFnZSkNCg0KZ2dwbG90bHkoZ2dwbG90KCkrDQogICAgICAgICAgIGdlb21fcG9pbnQoZGF0YSA9IGxvZ09ic19ubUdfZGZbbG9nT2JzX25tR19kZiRmbGVldCA9PSAxICYgbG9nT2JzX25tR19kZiR5ZWFyICE9IChEYXRhWWVhcisxKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSB5ZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGxvZ09icywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IGFnZSksDQogICAgICAgICAgICAgICAgICAgICAgc2hhcGUgPSAyMSkgKw0KICAgICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IGxvZ1ByZWRfbm1HX2RmW2xvZ1ByZWRfbm1HX2RmJGZsZWV0ID09IDEgJiBsb2dQcmVkX25tR19kZiR5ZWFyICE9IChEYXRhWWVhcisxKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IHllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBsb2dQcmVkLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBhZ2UpKSArDQogICAgICAgICAgIGZhY2V0X3dyYXAoZmFjZXRzID0gImFnZSIpICsgIywgc2NhbGVzID0gImZyZWVfeSIpICsNCiAgICAgICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGVicGFsLCBndWlkZSA9IEZBTFNFKSArDQogICAgICAgICAgIGd1aWRlcyhjb2xvdXI9RkFMU0UsIHNoYXBlPUZBTFNFKSArDQogICAgICAgICAgIHRoZW1lX2ZldygpKQ0KDQojIGZpdHBsb3QoZml0X25tRywgZmxlZXRzPTEpDQpgYGANCg0KYGBge3IgZmlnLmNhcD0iTW9kZWwgd2l0aCB0aW1lIGludmFyaWFudCBHaXNsYXNvbiBuYXR1cmFsIG1vcnRhbGl0aWVzIGZpdCB0byBRMSBzdXJ2ZXkgZGF0YSBieSBhZ2UgKHZhbHVlcyBvbiB0aGUgbW9kZWwgbGluayBmdW5jdGlvbiBzY2FsZSkuIn0NCmdncGxvdGx5KGdncGxvdCgpKw0KICAgICAgICAgICBnZW9tX3BvaW50KGRhdGEgPSBsb2dPYnNfbm1HX2RmW2xvZ09ic19ubUdfZGYkZmxlZXQgPT0gMiAmIGxvZ09ic19ubUdfZGYkeWVhciAhPSAoRGF0YVllYXIrMSksIF0sDQogICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0geWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBsb2dPYnMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBhZ2UpLA0KICAgICAgICAgICAgICAgICAgICAgIHNoYXBlID0gMjEpICsNCiAgICAgICAgICAgZ2VvbV9saW5lKGRhdGEgPSBsb2dQcmVkX25tR19kZltsb2dQcmVkX25tR19kZiRmbGVldCA9PSAyICYgbG9nUHJlZF9ubUdfZGYkeWVhciAhPSAoRGF0YVllYXIrMSksIF0sDQogICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSB5ZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gbG9nUHJlZCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gYWdlKSkgKw0KICAgICAgICAgICBmYWNldF93cmFwKGZhY2V0cyA9ICJhZ2UiKSArICMsIHNjYWxlcyA9ICJmcmVlX3kiKSArDQogICAgICAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBlYnBhbCwgZ3VpZGUgPSBGQUxTRSkgKw0KICAgICAgICAgICBndWlkZXMoY29sb3VyPUZBTFNFLCBzaGFwZT1GQUxTRSkgKw0KICAgICAgICAgICB0aGVtZV9mZXcoKSkNCiMgZml0cGxvdChmaXRfbm1HLCBmbGVldHM9MikNCmBgYA0KDQpgYGB7ciBmaWcuY2FwPSJNb2RlbCB3aXRoIHRpbWUgaW52YXJpYW50IEdpc2xhc29uIG5hdHVyYWwgbW9ydGFsaXRpZXMgZml0IHRvIFEzLzQgc3VydmV5IGRhdGEgYnkgYWdlICh2YWx1ZXMgb24gdGhlIG1vZGVsIGxpbmsgZnVuY3Rpb24gc2NhbGUpLiJ9DQpnZ3Bsb3RseShnZ3Bsb3QoKSsNCiAgICAgICAgICAgZ2VvbV9wb2ludChkYXRhID0gbG9nT2JzX25tR19kZltsb2dPYnNfbm1HX2RmJGZsZWV0ID09IDMgJiBsb2dPYnNfbm1HX2RmJHllYXIgIT0gKERhdGFZZWFyKzEpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IHllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gbG9nT2JzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gYWdlKSwNCiAgICAgICAgICAgICAgICAgICAgICBzaGFwZSA9IDIxKSArDQogICAgICAgICAgIGdlb21fbGluZShkYXRhID0gbG9nUHJlZF9ubUdfZGZbbG9nUHJlZF9ubUdfZGYkZmxlZXQgPT0gMyAmIGxvZ1ByZWRfbm1HX2RmJHllYXIgIT0gKERhdGFZZWFyKzEpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0geWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGxvZ1ByZWQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IGFnZSkpICsNCiAgICAgICAgICAgZmFjZXRfd3JhcChmYWNldHMgPSAiYWdlIikgKyAjLCBzY2FsZXMgPSAiZnJlZV95IikgKw0KICAgICAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gZWJwYWwsIGd1aWRlID0gRkFMU0UpICsNCiAgICAgICAgICAgZ3VpZGVzKGNvbG91cj1GQUxTRSwgc2hhcGU9RkFMU0UpICsNCiAgICAgICAgICAgdGhlbWVfZmV3KCkpDQoNCiMgZml0cGxvdChmaXRfbm1HLCBmbGVldHM9MykNCmBgYA0KDQpgYGB7ciBmaWcuY2FwPSJTdGFuZGFyZCBEZXZhdGlvbnMgYnkgRmxlZXQ7IEdpc2xhc29uLCB0aW1lLWludmFyaWFudCBtb3J0YWxpdHkiLCBoZWlnaHQ9MTB9DQpzZHBsb3QoZml0X25tRywgbWFyZyA9IGMoNSw0LDEsMSkpDQpgYGANCg0KIyMjIFJlc2lkdWFscw0KYGBge3IgY2FsY3VsYXRlUmVzaWR1YWxzX25tRywgd2FybmluZz1GQUxTRSwgcmVzdWx0cz0naGlkZSd9DQpyZXNpZF9ubUcgPC0gcmVzaWR1YWxzKGZpdF9ubUcpDQpyZXNpZF9ubUdfZGYgPC0gZGF0YS5mcmFtZSh5ZWFyID0gcmVzaWRfbm1HJHllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICBmbGVldCA9IHJlc2lkX25tRyRmbGVldCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGFnZSA9IHJlc2lkX25tRyRhZ2UsDQogICAgICAgICAgICAgICAgICAgICAgICAgICBvYnNlcnZhdGlvbiA9IHJlc2lkX25tRyRvYnNlcnZhdGlvbiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG1lYW4gPSByZXNpZF9ubUckbWVhbiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc2lkdWFsID0gcmVzaWRfbm1HJHJlc2lkdWFsKQ0KcmVzaWRfbm1HX2RmJGZsZWV0TmFtZSA8LSBpZmVsc2UocmVzaWRfbm1HX2RmJGZsZWV0ID09IDEsIGF0dHJpYnV0ZXMocmVzaWRfbm1HKSRmbGVldE5hbWVzWzFdLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShyZXNpZF9ubUdfZGYkZmxlZXQgPT0gMiwgYXR0cmlidXRlcyhyZXNpZF9ubUcpJGZsZWV0TmFtZXNbMl0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShyZXNpZF9ubUdfZGYkZmxlZXQgPT0gMywgYXR0cmlidXRlcyhyZXNpZF9ubUcpJGZsZWV0TmFtZXNbM10sIE5BKSkpDQoNCnJlc2lkX25tR19kZiRmbGVldEFsdE5hbWUgPC0gaWZlbHNlKHJlc2lkX25tR19kZiRmbGVldCA9PSAxLCAiUmVzaWR1YWwgRmlzaGluZyIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKHJlc2lkX25tR19kZiRmbGVldCA9PSAyLCAiUTEgU3VydmV5cyIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShyZXNpZF9ubUdfZGYkZmxlZXQgPT0gMywgIlEzLzQgU3VydmV5cyIsIE5BKSkpDQpgYGANCg0KYGBge3IgZmlnLmNhcD0iRXN0aW1hdGVkIGNvcnJlbGF0aW9ucyBpbiByZXNpZHVhbCB2YXJpYXRpb24gYmV0d2VlbiBhZ2VzIGZvciBlYWNoIG9mIHRoZSBmaXNoaW5nIGZsZWV0ICh0b3ApIGFuZCB0aGUgdHdvIHN1cnZleXMgKG1pZGRsZSAmIGJvdHRvbSksIGZyb20gdGhlIG1vZGVsIHdpdGggdGltZSBpbnZhcmlhbnQgR2lzbGFzb24gbmF0dXJhbCBtb3J0YWxpdGllcy4ifQ0KDQppZighYWxsKGZpdF9ubUckY29uZiRvYnNDb3JTdHJ1Y3Q9PSJJRCIpKXsgDQogIGNvcnBsb3QoZml0X25tRykJCQkgIA0KICAjIHNldGNhcCgiRXN0aW1hdGVkIGNvcnJlbGF0aW9ucyIsICJFc3RpbWF0ZXMgY29ycmVsYXRpb25zIGJldHdlZW4gYWdlIGdyb3VwcyBmb3IgZWFjaCBmbGVldCIpDQogICMgc3RhbXBpdChmaXQpDQp9IGVsc2Ugew0KICBwcmludCgiTm8gY29ycmVsYXRpb24gc3RydWN0dXJlIGNvbmZpZ3VyZWQgZm9yIHJlc2lkdWFscyBhY3Jvc3MgYWdlLiIpDQp9DQoNCmBgYA0KDQpgYGB7ciBmaWcuY2FwPSJPbmUgb2JzZXJ2YXRpb24gYWhlYWQgcmVzaWR1YWxzIGZvciB0aGUgdGhyZWUgZmxlZXRzIChyZWQvcGluayA9IG9ic2VydmF0aW9uIGxvd2VyIHRoYW4gbW9kZWwgZXN0aW1hdGUsIGJsdWUgPSBvYnNlcnZhdGlvbiBoaWdoZXIgdGhhbiBtb2RlbCBlc3RpbWF0ZSwgc2l6ZSA9IG1hZ25pdHVkZSBvZiByZXNpZHVhbCksIGZyb20gdGhlIG1vZGVsIHdpdGggdGltZSBpbnZhcmlhbnQgR2lzbGFzb24gbmF0dXJhbCBtb3J0YWxpdGllcy4ifQ0KZ2dwbG90bHkoZ2dwbG90KHJlc2lkX25tR19kZikgKw0KICAgICAgICAgICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IHllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gYWdlLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IGFicyhyZXNpZHVhbCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSByZXNpZHVhbCA+PSAwKSwNCiAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuNykgKw0KICAgICAgICAgICBmYWNldF9ncmlkKHJvd3MgPSAiZmxlZXRBbHROYW1lIikgKw0KICAgICAgICAgICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoIlRSVUUiID0gZWJwYWxbOF0sICJGQUxTRSIgPSBlYnBhbFs5XSkpICsNCiAgICAgICAgICAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoLTEsIDkpLCBicmVha3MgPSBjKDE6OSkpICsNCiAgICAgICAgICAgZ3VpZGVzKGNvbG91cj1GQUxTRSkgKw0KICAgICAgICAgICB0aGVtZV9mZXcoKSkNCg0KYGBgDQoNCiMjIyMgSml0dGVyaW5nDQpXZSBjYW4gYWxzbyB0ZXN0IHRvIHNlZSBpZiB0aGUgbW9kZWwgaXMgY29udmVyZ2luZyBvbiBzb21lIGxvY2FsIG1pbmltdW0gKGkuZS4gaXQncyBmaXR0aW5nIHRvIHNvbWUgc29sdXRpb24gY2xvc2UgdG8gaW5pdGlhbGlzaW5nIHZhbHVlcyB0aGF0IHJlcHJlc2VudHMgbm9pc2UgYW5kIG5vdCB0aGUgZ2xvYmFsIHNvbHV0aW9uLCB0aGF0IGlzIHRoZSBwcm9wZXIgc29sdXRpb24pLiAgVG8gZG8gdGhpcywgd2UgYWRkIHJhbmRvbSBub2lzZSB0byB0aGUgaW5pdGlhbCBwYXJhbWV0ZXIgdmFsdWVzIHRvIHNlZSBpZiB0aGUgbW9kZWwgd2lsbCBjb252ZXJnZSBvbiBhIGRpZmZlcmVudCBtaW5pbXVtIGluIGl0J3MgZGF0YS1zcGFjZS4gVGhlIGVhc2llc3Qgd2F5IHRvIGludmVzdGlnYXRlIHRoaXMgaXMgdG8gc2VlIGlmIHRoZSBtb2RlbCBmaXRzIHZhcnkgYWxvdCBkZXBlbmRpbmcgb24gdGhlIHN0YXJ0aW5nIHZhbHVlczoNCmBgYHtyIEppdHRlcl9ubUd9DQpqaXRfbm1HIDwtIGppdChmaXQgPSBmaXRfbm1HKQ0KDQptdCA8LSBhcy5kYXRhLmZyYW1lKG1vZGVsdGFibGUoaml0X25tRykpDQptdCRtb2RlbCA8LSByb3duYW1lcyhtdCkNCnJvd25hbWVzKG10KSA8LSBOVUxMDQoNCmthYmxlKHggPSBtdCwNCiAgICAgIGRpZ2l0cyA9IDMsDQogICAgICBjYXB0aW9uID0gIk1lYXN1cmVzIG9mICBmaXQgZm9yIGEgc2VyaWVzIG9mIG1vZGVsIHJlZml0cyB3aXRoIGppdHRlciBhcHBsaWVkIHRvIHRoZSBpbnB1dCBwYXJhbWV0ZXJzLiIpDQpgYGANCg0KIyMjIyBMZWF2ZS1PbmUtT3V0IEFuYWx5c2VzDQpBIGxlYXZlLW9uZS1vdXQgYW5hbHlzaXMgaXMgYSBmb3JtIG9mIHNlbnNpdGl2aXR5IGFuYWx5c2lzLCBzaG93aW5nIHRoZSBpbXBhY3QgdGhlIGRhdGEgZnJvbSBlYWNoIHR1bmluZyBmbGVldCBoYXMgb24gdGhlIGVzdGltYXRpb24gb2YgdGhlIGtleSB2YXJpYWJsZXMgYmVpbmcgZXN0aW1hdGVkOyBuYW1lbHkgU1NCLCBGIGFuZCByZWNydWl0bWVudC4gIA0KDQpGaXJzdCB3ZSBtdXN0IHJ1biB0aGUgbGVhdmUtb25lLW91dCBhbmFseXNpcyB3aGljaCByZWZpdHMgdGhlIG1vZGVsIGluIHR3byBpdGVyYXRpb25zLCByZW1vdmluZyBvbmUgc3VydmV5IGF0IGEgdGltZS4gVGhlbiB3ZSBjYW4gcGxvdCBlYWNoIG9mIHRoZXNlIG5ldyBtb2RlbCBmaXRzIG92ZXIgdGhlIGZ1bGwgbW9kZWwgdG8gc2VlIHRoZSBpbXBhY3QgdGhlIHJlbW92YWwgb2YgZWFjaCBoYXMuIA0KDQpgYGB7ciBMZWF2ZU9uZU91dF9ubUd9DQpMT19ubUcgPC0gbGVhdmVvdXQoZml0X25tRykNCg0KIz09PSANCiMgR2V0IGRhdGEgZnJvbSBzYW0gb2JqZWN0cyBhbmQgZ2VuZXJhdGUgdXNlYWJsZSBkYXRhZnJhbWVzDQojPT09PQ0KcTFtYXQgPC0gYXMuZGF0YS5mcmFtZShzdW1tYXJ5KExPX25tRyRgdy5vLiBRMUlCVFMrQklUUytDb2RTRDIxLTI1YCkpDQpxM21hdCA8LSBhcy5kYXRhLmZyYW1lKHN1bW1hcnkoTE9fbm1HJGB3Lm8uIFEzNElCVFMrQklUUytDb2RTRDIxLTI1YCkpDQoNCg0Kd29xMSA8LSBkYXRhLmZyYW1lKFllYXIgPSBhcy5pbnRlZ2VyKHJvdy5uYW1lcyhzdW1tYXJ5KExPX25tRyRgdy5vLiBRMUlCVFMrQklUUytDb2RTRDIxLTI1YCkpKSwNCiAgICAgICAgICAgICAgICAgICBTU0IgPSBxMW1hdCRTU0IsDQogICAgICAgICAgICAgICAgICAgRmJhciA9IHExbWF0JGBGYmFyKDMtNSlgLA0KICAgICAgICAgICAgICAgICAgIFJfYWdlMSA9IHExbWF0JGBSKGFnZSAxKWAsDQogICAgICAgICAgICAgICAgICAgQ2F0Y2hFc3QgPSBjYXRjaHRhYmxlKExPX25tRyRgdy5vLiBRMUlCVFMrQklUUytDb2RTRDIxLTI1YClbLDFdLA0KICAgICAgICAgICAgICAgICAgIHNlcmllcyA9IHJlcCgid29fUTEiLCB0aW1lcyA9IG5yb3cocTFtYXQpKSkNCg0Kd29xMzQgPC0gZGF0YS5mcmFtZShZZWFyID0gYXMuaW50ZWdlcihyb3cubmFtZXMocTNtYXRbKDIwMDI6RGF0YVllYXIpLTIwMDEsXSkpLA0KICAgICAgICAgICAgICAgICAgICBTU0IgPSBxM21hdFsoMjAwMjpEYXRhWWVhciktMjAwMSwgIlNTQiJdLA0KICAgICAgICAgICAgICAgICAgICBGYmFyID0gcTNtYXRbKDIwMDI6RGF0YVllYXIpLTIwMDEsIkZiYXIoMy01KSJdLA0KICAgICAgICAgICAgICAgICAgICBSX2FnZTEgPSBxM21hdFsoMjAwMjpEYXRhWWVhciktMjAwMSwiUihhZ2UgMSkiXSwNCiAgICAgICAgICAgICAgICAgICAgQ2F0Y2hFc3QgPSBjYXRjaHRhYmxlKExPX25tRyRgdy5vLiBRMzRJQlRTK0JJVFMrQ29kU0QyMS0yNWApWywxXSwNCiAgICAgICAgICAgICAgICAgICAgc2VyaWVzID0gcmVwKCJ3b19RMzQiLCB0aW1lcyA9IChucm93KHEzbWF0KS0xKSkpDQoNCg0KYXN1bV9ubUckc2VyaWVzIDwtIHJlcCgiZnVsbCIsIHRpbWVzID0gbnJvdyhhc3VtX25tRykpDQphc3VtaV9ubUcgPC0gYXN1bV9ubUdbLCBjKCJZZWFyIiwgIlNTQiIsICJGYmFyIiwgIlJfYWdlMSIsICJDYXRjaEVzdCIgLCJzZXJpZXMiKV0NCiM9PT09PQ0KDQpsb3N1bV9ubUcgPC0gcmJpbmQod29xMSwgd29xMzQsIGFzdW1pX25tRykNCg0KYGBgDQoNCmBgYHtyIGZpZy5jYXA9IkxlYXZlLW9uZS1vdXQgcmUtZml0cyBmb3IgdGhlIFRpbWUgaW52YXJpYW50LCBHaXNsYXNvbiBuYXR1cmFsIG1vcnRhbGl0aWVzICh3aXRob3V0IFExIHN1cnZleSA9IGJsdWUsIHdpdGhvdXQgUTMvNCBzdXJ2ZXkgPSBwdXJwbGUpLCBvdmVybGFpbiB3aXRoIGZ1bGwgbW9kZWwgZXN0aW1hdGVzIChibGFjayBsaW5lIGFuZCBncmV5IHJpYmJvbikgb2YgU1NCICh0b3AgbGVmdCksIEYgKHRvcCByaWdodCksIFJlY3J1aXRtZW50IChib3R0b20gbGVmdCksIGFuZCBjYXRjaCAoYm90dG9tIHJpZ2h0OyBvYnNlcnZhdGlvbnMgYXMgeWVsbG93ICspLiJ9DQojIHNzYnBsb3QoTE8pDQpsb3NzYl9ubUcgPC0gZ2dwbG90bHkoZ2dwbG90KCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9saW5lKGRhdGEgPSBsb3N1bV9ubUcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PVNTQiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IHNlcmllcykpICsNCiAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fcmliYm9uKGRhdGEgPSBhc3VtX25tRywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWluPVNTQmxvdywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1heD1TU0JoaWdoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSAiYmxhY2siLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjIpICsNCiAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiYmxhY2siLCBlYnBhbFs4OjldKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWVfY2xlYW4oKSArDQogICAgICAgICAgICAgICAgICAgICAgICB0aGVtZShheGlzLnRpdGxlLnkubGVmdCA9IGVsZW1lbnRfdGV4dCh2anVzdCA9IC0wLjA1LCBoanVzdCA9IDAuOTUpKSkNCg0KIyBGcGxvdChMTykNCmxvZl9ubUcgPC0gZ2dwbG90bHkoZ2dwbG90KCkgKw0KICAgICAgICAgICAgICAgICAgICAgIGdlb21fbGluZShkYXRhID0gbG9zdW1fbm1HLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PUZiYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gc2VyaWVzKSkgKw0KICAgICAgICAgICAgICAgICAgICAgIGdlb21fcmliYm9uKGRhdGEgPSBhc3VtX25tRywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW49RmxvdywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltYXg9RmhpZ2gpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSAiYmxhY2siLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4zKSArDQogICAgICAgICAgICAgICAgICAgICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCJibGFjayIsIGVicGFsWzg6OV0pKSArDQogICAgICAgICAgICAgICAgICAgICAgdGhlbWVfY2xlYW4oKSArDQogICAgICAgICAgICAgICAgICAgICAgdGhlbWUoYXhpcy50aXRsZS55LmxlZnQgPSBlbGVtZW50X3RleHQodmp1c3QgPSAtMC4wNSwgaGp1c3QgPSAwLjk1KSkpDQoNCiMgcmVjcGxvdChMTykNCmxvcmVjX25tRyA8LSBnZ3Bsb3RseShnZ3Bsb3QoKSArDQogICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IGxvc3VtX25tRywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9Ul9hZ2UxLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gc2VyaWVzKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9yaWJib24oZGF0YSA9IGFzdW1fbm1HLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW49UmxvdywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1heD1SaGlnaCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gImJsYWNrIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4zKSArDQogICAgICAgICAgICAgICAgICAgICAgICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoImJsYWNrIiwgZWJwYWxbODo5XSkpICsNCiAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2NsZWFuKCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWUoYXhpcy50aXRsZS55LmxlZnQgPSBlbGVtZW50X3RleHQodmp1c3QgPSAtMC4wNSwgaGp1c3QgPSAwLjk1KSkpDQoNCiMgQ2F0Y2ggcGxvdCAoTE8pDQpsb2NhX25tRyA8LSBnZ3Bsb3RseShnZ3Bsb3QoKSArDQogICAgICAgICAgICAgICAgICAgICAgIGdlb21fbGluZShkYXRhID0gbG9zdW1fbm1HLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9Q2F0Y2hFc3QsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IHNlcmllcykpKw0KICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3JpYmJvbihkYXRhID0gYXN1bV9ubUdbYXN1bV9ubUckWWVhciAhPSAoRGF0YVllYXIrMSksIF0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW49Q2F0Y2hsb3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1heD1DYXRjaGhpZ2gpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gImJsYWNrIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjMpICsNCiAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9wb2ludChkYXRhID0gYXN1bV9ubUdbYXN1bV9ubUckWWVhciAhPSAoRGF0YVllYXIrMSksIF0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PUNhdGNoT2JzKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaGFwZSA9IDMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gZWJwYWxbNV0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IGVicGFsWzVdKSArDQogICAgICAgICAgICAgICAgICAgICAgIHlsYWIoIkNhdGNoICh0b25uZXMpIikgKw0KICAgICAgICAgICAgICAgICAgICAgICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoImJsYWNrIiwgZWJwYWxbODo5XSkpKyANCiAgICAgICAgICAgICAgICAgICAgICAgdGhlbWVfY2xlYW4oKSArDQogICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKGF4aXMudGl0bGUueS5sZWZ0ID0gZWxlbWVudF90ZXh0KHZqdXN0ID0gLTAuMDUsIGhqdXN0ID0gMC45NSkpKQ0KDQpsYXlvdXQoc3VicGxvdChsb3NzYl9ubUcsIGxvZl9ubUcsIGxvcmVjX25tRywgbG9jYV9ubUcsIG5yb3dzID0gMiwgc2hhcmVYID0gVFJVRSwgdGl0bGVZID0gVFJVRSksIHNob3dsZWdlbmQ9RkFMU0UpDQpgYGANCg0KIyMjIFJldHJvc3BlY3RpdmVzDQpgYGB7ciBjYWxjdWxhdGVSZXRyb3Nfbm1HfQ0KIz09PQ0KIyBDcmVhdGUgZGF0YWZyYW1lIG9mIGN1cnJlbnQgeWVhcidzIGZpdCBmb3IgcGxvdHRpbmcNCiM9PT09DQojIElDX2FnZ190ZW1wIDwtIGFnZ3JlZ2F0ZShDQVRPTn5ZZWFyLCBpY19jbGVhbltpY19jbGVhbiRDYXRjaENhdGVnb3J5ICVpbiUgYygiTGFuZGluZ3MiLCAiRGlzY2FyZHMiKSwgXSwgRlVOID0gInN1bSIpDQphc3VtX25tRyA8LSBhcy5kYXRhLmZyYW1lKHN1bW1hcnkoZml0X25tRykpDQphc3VtX25tRyRZZWFyIDwtIGFzLmludGVnZXIocm93Lm5hbWVzKHN1bW1hcnkoZml0X25tRykpKQ0KY3Rfbm1HIDwtIGFzLmRhdGEuZnJhbWUoY2F0Y2h0YWJsZShmaXRfbm1HLCBvYnMuc2hvdyA9IFRSVUUpKQ0KY3Rfbm1HJFllYXIgPC0gYXMuaW50ZWdlcihyb3duYW1lcyhjdF9ubUcpKQ0Kcm93bmFtZXMoY3Rfbm1HKSA8LSBOVUxMDQpjdF9ubUcgPC0gcmJpbmQoY3Rfbm1HLCBkYXRhLmZyYW1lKEVzdGltYXRlID0gTkEsIExvdz1OQSwgSGlnaD1OQSwgc29wLmNhdGNoPU5BLCBZZWFyPWFzLmludGVnZXIoMjAyNCkpKQ0KYXN1bV9ubUcgPC0gbWVyZ2UoeCA9IGFzdW1fbm1HLCB5ID0gY3Rfbm1HLCBieSA9ICJZZWFyIikNCmNvbG5hbWVzKGFzdW1fbm1HKSA8LSBjKCJZZWFyIiwgIlJfYWdlMSIsICJSbG93IiwgIlJoaWdoIiwgIlNTQiIsICJTU0Jsb3ciLCAiU1NCaGlnaCIsICJGYmFyIiwgIkZsb3ciLCAiRmhpZ2giLCAiQ2F0Y2hFc3QiLCAiQ2F0Y2hsb3ciLCAiQ2F0Y2hoaWdoIiwgIkNhdGNoT2JzIikNCg0KYXN1bV9ubUckc2VyaWVzIDwtIHJlcCgiZnVsbCIsIHRpbWVzID0gbnJvdyhhc3VtX25tRykpDQoNCiM9PT09PQ0KUkVUUk9fbm1HPC1yZXRybyhmaXRfbm1HLCB5ZWFyPTUpDQpyaG9fbm1HIDwtIG1vaG4oUkVUUk9fbm1HLCBsYWcgPSAxKQ0KDQojIyBNYWtlIFJFVFJPcyBpbiBiZXR0ZXIgcGxvdHRpbmcgZm9ybWF0DQpyZXRfbm1HX2RmIDwtIGFzdW1fbm1HW2FzdW1fbm1HJFllYXIgIT0gbWF4KGFzdW1fbm1HJFllYXIpLCBdDQoNCmZvcihpIGluIDE6bGVuZ3RoKFJFVFJPX25tRykpew0KICB0c3VtIDwtIGFzLmRhdGEuZnJhbWUoc3VtbWFyeShSRVRST19ubUdbW2ldXSkpDQogIHRzdW0kWWVhciA8LSBhcy5pbnRlZ2VyKHJvdy5uYW1lcyhzdW1tYXJ5KFJFVFJPX25tR1tbaV1dKSkpDQogIHRzdW0gPC0gY2JpbmQodHN1bSwgY2F0Y2h0YWJsZShSRVRST19ubUdbW2ldXSwgb2JzLnNob3cgPSBUUlVFKSkNCiAgdHN1bSRzZXJpZXMgPC0gYXMuY2hhcmFjdGVyKHJlcChpLCBucm93KHRzdW0pKSkNCiAgY29sbmFtZXModHN1bSkgPC0gYygiUl9hZ2UxIiwgIlJsb3ciLCAiUmhpZ2giLCAiU1NCIiwgIlNTQmxvdyIsICJTU0JoaWdoIiwgIkZiYXIiLCAiRmxvdyIsICJGaGlnaCIsICJZZWFyIiwgIkNhdGNoRXN0IiwgIkNhdGNobG93IiwgIkNhdGNoaGlnaCIsICJDYXRjaE9icyIsICJzZXJpZXMiKQ0KICB0c3VtIDwtIHRzdW1bdHN1bSRZZWFyICE9IG1heCh0c3VtJFllYXIpLCBdDQogIHJldF9ubUdfZGYgPC0gcmJpbmQocmV0X25tR19kZiwgdHN1bSkNCn0NCnJldF9ubUdfZGYkc2VyaWVzIDwtIGZhY3RvcihyZXRfbm1HX2RmJHNlcmllcywgbGV2ZWxzID0gYygiZnVsbCIsICIxIiwgIjIiLCAiMyIsICI0IiwgIjUiKSkNCmBgYA0KDQpgYGB7ciBmaWcuY2FwPSJSZXRyb3NwZWN0aXZlIGFuYWx5c2VzIGZvciBTU0IgKHRvcC1sZWZ0KSwgRiBmb3IgYWdlcyAzLTUgKHRvcC1yaWdodCksIHJlY3J1aXRtZW50IChib3R0b20tbGVmdCksIGFuZCBjYXRjaCAoYm90dG9tLXJpZ2h0KSwgZnJvbSB0aGUgbW9kZWwgdXRpbGlzaW5nIHRpbWUgaW52YXJpYW50LCBHaXNsYXNvbiBuYXR1cmFsIG1vcnRhbGl0aWVzLiJ9DQojIHNzYnBsb3QoUkVUUk8pDQpyZXRzc2Jfbm1HIDwtIGxheW91dChnZ3Bsb3RseShnZ3Bsb3QoKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fbGluZShkYXRhID0gcmV0X25tR19kZiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PVNTQiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gc2VyaWVzKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3JpYmJvbihkYXRhID0gYXN1bV9ubUdbYXN1bV9ubUckWWVhciAhPSBtYXgoYXN1bV9ubUckWWVhciksIF0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW49U1NCbG93LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltYXg9U1NCaGlnaCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSAiYmxhY2siLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMikgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbm5vdGF0ZShnZW9tID0gInRleHQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gbWF4KHJldF9ubUdfZGYkU1NCaGlnaCkqMC44NSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeCA9ICgobWF4KHJldF9ubUdfZGYkWWVhciktbWluKHJldF9ubUdfZGYkWWVhcikpKjAuMjApK21pbihyZXRfbm1HX2RmJFllYXIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbCA9IHBhc3RlMCgiTW9obidzIFJobyA9ICIsIHJvdW5kKHJob19ubUdbMl0sIGRpZ2l0cyA9IDMpKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoImJsYWNrIiwgZWJwYWxbKGxlbmd0aChlYnBhbCktNCk6bGVuZ3RoKGVicGFsKV0pKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2NsZWFuKCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF4aXMudGl0bGUueS5sZWZ0ID0gZWxlbWVudF90ZXh0KHZqdXN0ID0gLTAuMDUsIGhqdXN0ID0gMC45NSkpKSwNCiAgICAgICAgICAgICAgICAgICAgIHNob3dsZWdlbmQgPSBGQUxTRSkNCg0KIyBGcGxvdChSRVRSTykNCnJldGZfbm1HIDwtIGxheW91dChnZ3Bsb3RseShnZ3Bsb3QoKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IHJldF9ubUdfZGYsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PUZiYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBzZXJpZXMpKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3JpYmJvbihkYXRhID0gYXN1bV9ubUdbYXN1bV9ubUckWWVhciAhPSBtYXgoYXN1bV9ubUckWWVhciksIF0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1pbj1GbG93LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4PUZoaWdoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSAiYmxhY2siLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjMpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFubm90YXRlKGdlb20gPSAidGV4dCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gbWF4KHJldF9ubUdfZGYkRmhpZ2gpKjAuODUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4ID0gKChtYXgocmV0X25tR19kZiRZZWFyKS1taW4ocmV0X25tR19kZiRZZWFyKSkqMC44MCkrbWluKHJldF9ubUdfZGYkWWVhciksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbCA9IHBhc3RlMCgiTW9obidzIFJobyA9ICIsIHJvdW5kKHJob19ubUdbM10sIGRpZ2l0cyA9IDMpKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCJibGFjayIsIGVicGFsWyhsZW5ndGgoZWJwYWwpLTQpOmxlbmd0aChlYnBhbCldKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWVfY2xlYW4oKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBheGlzLnRpdGxlLnkubGVmdCA9IGVsZW1lbnRfdGV4dCh2anVzdCA9IC0wLjA1LCBoanVzdCA9IDAuOTUpKSksDQogICAgICAgICAgICAgICAgICAgc2hvd2xlZ2VuZCA9IEZBTFNFKQ0KDQojIHJlY3Bsb3QoUkVUUk8pDQpyZXRyZWNfbm1HIDwtIGxheW91dChnZ3Bsb3RseShnZ3Bsb3QoKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fbGluZShkYXRhID0gcmV0X25tR19kZiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PVJfYWdlMSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gc2VyaWVzKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3JpYmJvbihkYXRhID0gYXN1bV9ubUdbYXN1bV9ubUckWWVhciAhPSBtYXgoYXN1bV9ubUckWWVhciksIF0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW49UmxvdywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4PVJoaWdoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9ICJibGFjayIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4zKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFubm90YXRlKGdlb20gPSAidGV4dCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9IG1heChyZXRfbm1HX2RmJFJoaWdoKSowLjg1LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4ID0gKChtYXgocmV0X25tR19kZiRZZWFyKS1taW4ocmV0X25tR19kZiRZZWFyKSkqMC4yMCkrbWluKHJldF9ubUdfZGYkWWVhciksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsID0gcGFzdGUwKCJNb2huJ3MgUmhvID0gIiwgcm91bmQocmhvX25tR1sxXSwgZGlnaXRzID0gMykpKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiYmxhY2siLCBlYnBhbFsobGVuZ3RoKGVicGFsKS00KTpsZW5ndGgoZWJwYWwpXSkpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWVfY2xlYW4oKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXhpcy50aXRsZS55LmxlZnQgPSBlbGVtZW50X3RleHQodmp1c3QgPSAtMC4wNSwgaGp1c3QgPSAwLjk1KSkpLA0KICAgICAgICAgICAgICAgICAgICAgc2hvd2xlZ2VuZCA9IEZBTFNFKQ0KDQojIENhdGNoIHBsb3QgKFJFVFJPKQ0KcmV0Y2Ffbm1HIDwtIGdncGxvdGx5KGdncGxvdCgpICsNCiAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fbGluZShkYXRhID0gcmV0X25tR19kZiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9Q2F0Y2hFc3QsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBzZXJpZXMpKSsNCiAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fcmliYm9uKGRhdGEgPSBhc3VtX25tR1thc3VtX25tRyRZZWFyICE9IG1heChhc3VtX25tRyRZZWFyKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWluPUNhdGNobG93LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4PUNhdGNoaGlnaCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gImJsYWNrIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4zKSArDQogICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3BvaW50KGRhdGEgPSBhc3VtX25tR1thc3VtX25tRyRZZWFyICE9IG1heChhc3VtX25tRyRZZWFyKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1DYXRjaE9icyksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNoYXBlID0gMywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gZWJwYWxbNV0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBlYnBhbFs1XSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgeWxhYigiQ2F0Y2ggKHRvbm5lcykiKSArDQogICAgICAgICAgICAgICAgICAgICAgICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoImJsYWNrIiwgZWJwYWxbKGxlbmd0aChlYnBhbCktNCk6bGVuZ3RoKGVicGFsKV0pKSsgDQogICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9jbGVhbigpICsNCiAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKGF4aXMudGl0bGUueS5sZWZ0ID0gZWxlbWVudF90ZXh0KHZqdXN0ID0gLTAuMDUsIGhqdXN0ID0gMC45NSkpKQ0KDQpyZXRfZnAgPC0gc3R5bGUoc3VicGxvdChyZXRzc2Jfbm1HLCByZXRmX25tRywgcmV0cmVjX25tRywgcmV0Y2Ffbm1HLCBucm93cyA9IDIsIHNoYXJlWCA9IEZBTFNFLCBzaGFyZVkgPSBGQUxTRSwgdGl0bGVZID0gVFJVRSksDQogICAgICAgICAgICAgICAgc2hvd2xlZ2VuZD1GQUxTRSwNCiAgICAgICAgICAgICAgICB0cmFjZXMgPSBjKDg6KCg3KjQpKzIpKSkNCg0KbGF5b3V0KHJldF9mcCwgbGVnZW5kID0gbGlzdChvcmllbnRhdGlvbiA9ICdoJywgeCA9IDAuNSwgeGFuY2hvciA9ICdjZW50ZXInLCB5ID0gLTAuMDUsIHlhbmNob3IgPSAndG9wJywgYm9yZGVyd2lkdGggPSAwKSkNCmBgYA0KDQojIyBTY2FsZWQsIFRpbWUgSW52YXJpYW50LCBHaXNsYXNvbiBOYXR1cmFsIG1vcnRhbGl0aWVzDQojIyMgU2NhbGluZyBhbmQgb3B0aW1pc2luZw0KDQpgYGB7ciBsaWtlbGlob29kUHJvZmlsZU5NLCByZXN1bHRzPSdoaWRlJywgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0NCg0KIz09PQ0KIyBTY2FsZSBuYXR1cmFsIG1vcnRhbGl0eSBieSBhIHJhbmdlIG9mIG11bHRpcGxpZXJzDQojPT09PQ0KcHJvZnMgPSBsaXN0KCkNCm5tID0gZml0X25tRyRkYXRhJG5hdE1vcg0KbXVsdHMgPSBzZXEoMC4xLDIsYnk9MC4xKQ0KDQojIyBSZS1maXQgdG8gc2NhbGVkIG1vcnRhbGl0aWVzDQpmb3IobXVsdCBpbiBtdWx0cyl7DQogIA0KICBmaXRfbm1HJGRhdGEkbmF0TW9yID0gbm0qbXVsdA0KICANCiAgcHJvZnNbW2FzLmNoYXJhY3RlcihtdWx0KV1dPSBzdG9ja2Fzc2Vzc21lbnQ6OjpyZWZpdChmaXRfbm1HLCBzaWxlbnQgPSBUUlVFKQ0KfQ0KIz09PT0NCmBgYA0KDQpgYGB7ciBmaWcuY2FwPSJMaWtlbGlob29kIHByb2ZpbGUgb2Ygc2NhbGVkIHRpbWUgaW52YXJpYW50LCBHaXNsYXNvbiBuYXR1cmFsIG1vcnRhbGl0aWVzLiBZLWF4aXMgPSBBSUMsIHgtYXhpcyA9IHNjYWxpbmcgZmFjdG9yIG9uIG5tLiJ9DQojPT09DQojIEFnZ3JlZ2F0ZSBBSUMgdmFsdWVzIGFuZCBwbG90IHJlc3VsdHMNCiM9PT09DQpsbCA9IHNhcHBseShwcm9mcyxBSUMpDQpwbG90KG11bHRzLGxsKQ0KIz09PT0NCmBgYA0KDQoNCldlIGNhbiBub3cgaW52ZXN0aWdhdGUgaWYgYXZlcmFnaW5nIHRoZSBHaXNsYXNvbiBuYXR1cmFsIG1vcnRhbGl0aWVzIG92ZXIgdGhlIHRpbWUgc2VyaWVzIGNyZWF0ZXMgc29tZSBzY2FsaW5nIGlzc3VlcyBieSBpZ25vcmluZyB3ZWlnaHRpbmdzIG9mIG51bWJlcnMgb2Ygb2JzZXJ2YXRpb25zIGNvbnRyaWJ1dGluZyB0byBlYWNoIGFubnVhbCBlc3RpbWF0ZS4gVG8gcGFydGlhbGx5IGFkZHJlc3MgdGhpcyB3ZSBjYW4gaW52ZXN0aWdhdGUgc2NhbGluZyB0aGVzZSB0aW1lIGludmFyaWFudCB2YWx1ZXMgdXAgYW5kIGRvd24sIHRvIGZpbmQgd2hlcmUgdGhlIGJlc3QgZml0IG9mIHRoaXMgInNoYXBlIiBvZiBuYXR1cmFsIG1vcnRhbGl0aWVzIGFjcm9zcyBhZ2VzIGlzLg0KDQpCeSBzY2FsaW5nIHRoZSBubSB2YWx1ZXMgdXAgYW5kIGRvd24gYWNyb3NzIGEgcmFuZ2Ugb2YgbXVsdGlwbGllcnMgZnJvbSAwLjEgdG8gMiwgaW4gaW5jcmVtZW50cyBvZiAwLjEsIHdlIGNyZWF0ZSAyMCBkaWZmZXJlbnQgcnVucyBmcm9tIHdoaWNoIHdlIGNhbiBjb21wYXJlIEFJQyB2YWx1ZXMuICBIZXJlIHdlIGZpbmQgdGhhdCBhIHNjYWxpbmcgdmFsdWUgb2YgYHIgbXVsdHNbIHdoaWNoLm1pbihsbCkgXWAgaXMgcmVzcG9uc2libGUgZm9yIHRoZSBvcHRpbXVtIG1vZGVsIGZpdC4gDQoNCiMjIyBJbnZlc3RpZ2F0aW5nIHRoZSBzY2FsZWQgbW9kZWwNCg0KVGhlcmVmb3JlLCBiZWxvdyB3ZSBpbnZlc3RpZ2F0ZSB0aGUgbW9kZWwgZml0IGFuZCByZXNpZHVhbHMgZm9yIGEgbW9kZWwgd2l0aCB0aGUgR2lzbGFzb24sIHRpbWUgaW52YXJpYW50IG1vcnRhbGl0aWVzIGF0IGFnZSB0aGF0IGhhdmUgYmVlbiBzY2FsZWQgYnkgYSBmYWN0b3Igb2YgYHIgbXVsdHNbIHdoaWNoLm1pbihsbCkgXWAgYWNyb3NzIGFsbCBhZ2VzLg0KDQpgYGB7ciBubUdTRml0RnJvbVdlYn0NCmZpdF9ubUdTIDwtIGZpdGZyb213ZWIoInBsZS4yNy4yMS0zMl9XS0JQTEFJQ0VfMjAyNF9CaW9QYXJzd19ubUdfUyIpDQpgYGANCg0KYGBge3IgZGF0YWZyYW1lU3VtbWFyeV9ubUdTLCByZXN1bHRzPSdoaWRlJywgZmlnLnNob3c9J2hpZGUnfQ0KIz09PQ0KIyBDcmVhdGUgZGF0YWZyYW1lIG9mIGN1cnJlbnQgeWVhcidzIGZpdCBmb3IgcGxvdHRpbmcNCiM9PT09DQojIElDX2FnZ190ZW1wIDwtIGFnZ3JlZ2F0ZShDQVRPTn5ZZWFyLCBpY19jbGVhbltpY19jbGVhbiRDYXRjaENhdGVnb3J5ICVpbiUgYygiTGFuZGluZ3MiLCAiRGlzY2FyZHMiKSwgXSwgRlVOID0gInN1bSIpDQphc3VtX25tR1MgPC0gYXMuZGF0YS5mcmFtZShzdW1tYXJ5KGZpdF9ubUdTKSkNCmFzdW1fbm1HUyRZZWFyIDwtIGFzLmludGVnZXIocm93Lm5hbWVzKHN1bW1hcnkoZml0X25tR1MpKSkNCmN0X25tR1MgPC0gYXMuZGF0YS5mcmFtZShjYXRjaHRhYmxlKGZpdF9ubUdTLCBvYnMuc2hvdyA9IFRSVUUpKQ0KY3Rfbm1HUyRZZWFyIDwtIGFzLmludGVnZXIocm93bmFtZXMoY3Rfbm1HUykpDQpyb3duYW1lcyhjdF9ubUdTKSA8LSBOVUxMDQpjdF9ubUdTIDwtIHJiaW5kKGN0X25tR1MsIGRhdGEuZnJhbWUoRXN0aW1hdGUgPSBOQSwgTG93PU5BLCBIaWdoPU5BLCBzb3AuY2F0Y2g9TkEsIFllYXI9YXMuaW50ZWdlcigyMDI0KSkpDQphc3VtX25tR1MgPC0gbWVyZ2UoeCA9IGFzdW1fbm1HUywgeSA9IGN0X25tR1MsIGJ5ID0gIlllYXIiKQ0KY29sbmFtZXMoYXN1bV9ubUdTKSA8LSBjKCJZZWFyIiwgIlJfYWdlMSIsICJSbG93IiwgIlJoaWdoIiwgIlNTQiIsICJTU0Jsb3ciLCAiU1NCaGlnaCIsICJGYmFyIiwgIkZsb3ciLCAiRmhpZ2giLCAiQ2F0Y2hFc3QiLCAiQ2F0Y2hsb3ciLCAiQ2F0Y2hoaWdoIiwgIkNhdGNoT2JzIikNCiM9PT09PQ0KYGBgDQoNCiMjIyMgRml0cyB0byBkYXRhDQpXaGVuIHRoZSBtb2RlbCBpcyBydW4gd2UgY2FuIGVhc2lseSBzZWUgZnJvbSB3YXJuaW5ncy9lcnJvcnMgaWYgdGhlcmUgaXMgYSBjb252ZXJnZW5jZSBpc3N1ZS4gIEhvd2V2ZXIsIHdlIGNhbiBhbHNvIGNvbmZpcm0gdGhpcywgZXhwbGljaXRseToNCi0gVGhlIGZpbmFsIG1vZGVsIGdyYWRpZW50OiBgciBmaXRfbm1HUyRvcHQkZXZhbHVhdGlvbnNbMl1gDQotIFRoYXQgdGhlcmUgaXMgYSBwb3NpdGl2ZSBkZWZpbml0ZSBoZXNzaWFuOiBgciBhbGwoZWlnZW4oZml0X25tR1Mkb3B0JGhlKSR2YWx1ZXMgPjApYA0KDQpGdXJ0aGVybW9yZSwgU0FNIGRvZXMgbm90IHV0aWxpc2UgImJvdW5kcyIgd2hlbiBmaXR0aW5nIHRoZSBtb2RlbCwgYW5kIHRoZXJlZm9yZSwgYXMgc3RhbmRhcmQgY2hlY2sgb2Ygd2hldGhlciBtb2RlbCBwYXJhbWV0ZXJzIGFyZSBhcHByb2FjaGluZyB0aGVpciBib3VuZHMgaXMgaXJyZWxldmFudC4NCg0KDQpgYGB7ciBmaWcuY2FwPSJNb2RlbCB3aXRoIFNDQUxFRCB0aW1lIGludmFyaWFudCBHaXNsYXNvbiBuYXR1cmFsIG1vcnRhbGl0aWVzIGZpdCB0byBjYXRjaCBkYXRhIGJ5IGFnZSAodmFsdWVzIG9uIHRoZSBtb2RlbCBsaW5rIGZ1bmN0aW9uIHNjYWxlKS4ifQ0KIyMgRXh0cmFjdCBkYXRhIGZyb20gbW9kZWwgb2JqZWN0DQpsb2dPYnNfbm1HUyA8LSBzcGxpdChmaXRfbm1HUyRkYXRhJGxvZ29icywgY2VpbGluZyhzZXFfYWxvbmcoZml0X25tR1MkZGF0YSRsb2dvYnMpL2ZpdF9ubUdTJGRhdGEkbWF4QWdlUGVyRmxlZXRbMV0pKQ0KbG9nUHJlZF9ubUdTIDwtIHNwbGl0KGZpdF9ubUdTJHJlcCRwcmVkT2JzLCBjZWlsaW5nKHNlcV9hbG9uZyhmaXRfbm1HUyRyZXAkcHJlZE9icykvZml0X25tR1MkZGF0YSRtYXhBZ2VQZXJGbGVldFsxXSkpDQoNCiMjIFRyYW5zZm9ybSBkYXRhIHRvIHVzZWFibGUgZGF0YWZyYW1lcw0KIyMjIEluaXRpYWxpemUgYW4gZW1wdHkgZGF0YSBmcmFtZSBmb3Igb2JzZXJ2YXRpb25zDQpsb2dPYnNfbm1HU19kZiA8LSBkYXRhLmZyYW1lKGFnZSA9IGludGVnZXIoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmxlZXQgPSBpbnRlZ2VyKCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllYXIgPSBpbnRlZ2VyKCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZ09icyA9IG51bWVyaWMoKSkNCg0KIyMjIFBvcHVsYXRlIHRoZSBkYXRhIGZyYW1lIGZvciBvYnNlcnZhdGlvbnMNCmZvciAoaSBpbiBzZXFfYWxvbmcobG9nT2JzX25tR1MpKSB7DQogICMgQ2FsY3VsYXRlIHRoZSBncm91cCBhbmQgeWVhcg0KICB5ZWFyIDwtICgoaSAtIDEpICUvJSAzKSArIDENCiAgZmxlZXQgPC0gKChpIC0gMSkgJSUgMykgKyAxDQogIA0KICAjIyMgQ3JlYXRlIGEgdGVtcG9yYXJ5IGRhdGEgZnJhbWUgYW5kIGFwcGVuZCB0byB0aGUgbWFpbiBkYXRhIGZyYW1lIGZvciBvYnNlcnZhdGlvbnMNCiAgdGVtcF9kZiA8LSBkYXRhLmZyYW1lKGFnZSA9IDE6NywNCiAgICAgICAgICAgICAgICAgICAgICAgIGZsZWV0ID0gZmxlZXQsDQogICAgICAgICAgICAgICAgICAgICAgICB5ZWFyID0geWVhcisyMDAxLA0KICAgICAgICAgICAgICAgICAgICAgICAgbG9nT2JzID0gbG9nT2JzX25tR1NbW2ldXSkNCiAgbG9nT2JzX25tR1NfZGYgPC0gcmJpbmQobG9nT2JzX25tR1NfZGYsIHRlbXBfZGYpDQp9DQoNCiMjIyBJbml0aWFsaXplIGFuIGVtcHR5IGRhdGEgZnJhbWUgZm9yIHByZWRpY3Rpb25zDQpsb2dQcmVkX25tR1NfZGYgPC0gZGF0YS5mcmFtZShhZ2UgPSBpbnRlZ2VyKCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmbGVldCA9IGludGVnZXIoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllYXIgPSBpbnRlZ2VyKCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2dQcmVkID0gbnVtZXJpYygpKQ0KDQojIyMgUG9wdWxhdGUgdGhlIGRhdGEgZnJhbWUgZm9yIHByZWRpY3Rpb25zDQpmb3IgKGkgaW4gc2VxX2Fsb25nKGxvZ1ByZWRfbm1HUykpIHsNCiAgIyBDYWxjdWxhdGUgdGhlIGdyb3VwIGFuZCB5ZWFyDQogIHllYXIgPC0gKChpIC0gMSkgJS8lIDMpICsgMQ0KICBmbGVldCA8LSAoKGkgLSAxKSAlJSAzKSArIDENCiAgDQogICMjIyBDcmVhdGUgYSB0ZW1wb3JhcnkgZGF0YSBmcmFtZSBhbmQgYXBwZW5kIHRvIHRoZSBtYWluIGRhdGEgZnJhbWUgZm9yIHByZWRpY3Rpb25zDQogIHRlbXBfZGYgPC0gZGF0YS5mcmFtZShhZ2UgPSAxOjcsDQogICAgICAgICAgICAgICAgICAgICAgICBmbGVldCA9IGZsZWV0LA0KICAgICAgICAgICAgICAgICAgICAgICAgeWVhciA9IHllYXIrMjAwMSwNCiAgICAgICAgICAgICAgICAgICAgICAgIGxvZ1ByZWQgPSBsb2dQcmVkX25tR1NbW2ldXSkNCiAgbG9nUHJlZF9ubUdTX2RmIDwtIHJiaW5kKGxvZ1ByZWRfbm1HU19kZiwgdGVtcF9kZikNCn0NCg0KIyMgUGxvdA0KbG9nUHJlZF9ubUdTX2RmJGFnZSA8LSBhcy5jaGFyYWN0ZXIobG9nUHJlZF9ubUdTX2RmJGFnZSkNCmxvZ09ic19ubUdTX2RmJGFnZSA8LSBhcy5jaGFyYWN0ZXIobG9nT2JzX25tR1NfZGYkYWdlKQ0KDQpnZ3Bsb3RseShnZ3Bsb3QoKSsNCiAgICAgICAgICAgZ2VvbV9wb2ludChkYXRhID0gbG9nT2JzX25tR1NfZGZbbG9nT2JzX25tR1NfZGYkZmxlZXQgPT0gMSAmIGxvZ09ic19ubUdTX2RmJHllYXIgIT0gKERhdGFZZWFyKzEpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IHllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gbG9nT2JzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gYWdlKSwNCiAgICAgICAgICAgICAgICAgICAgICBzaGFwZSA9IDIxKSArDQogICAgICAgICAgIGdlb21fbGluZShkYXRhID0gbG9nUHJlZF9ubUdTX2RmW2xvZ1ByZWRfbm1HU19kZiRmbGVldCA9PSAxICYgbG9nUHJlZF9ubUdTX2RmJHllYXIgIT0gKERhdGFZZWFyKzEpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0geWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGxvZ1ByZWQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IGFnZSkpICsNCiAgICAgICAgICAgZmFjZXRfd3JhcChmYWNldHMgPSAiYWdlIikgKyAjLCBzY2FsZXMgPSAiZnJlZV95IikgKw0KICAgICAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gZWJwYWwsIGd1aWRlID0gRkFMU0UpICsNCiAgICAgICAgICAgZ3VpZGVzKGNvbG91cj1GQUxTRSwgc2hhcGU9RkFMU0UpICsNCiAgICAgICAgICAgdGhlbWVfZmV3KCkpDQoNCiMgZml0cGxvdChmaXRfbm1HUywgZmxlZXRzPTEpDQpgYGANCg0KYGBge3IgZmlnLmNhcD0iTW9kZWwgd2l0aCBTQ0FMRUQgdGltZSBpbnZhcmlhbnQgR2lzbGFzb24gbmF0dXJhbCBtb3J0YWxpdGllcyBmaXQgdG8gUTEgc3VydmV5IGRhdGEgYnkgYWdlICh2YWx1ZXMgb24gdGhlIG1vZGVsIGxpbmsgZnVuY3Rpb24gc2NhbGUpLiJ9DQpnZ3Bsb3RseShnZ3Bsb3QoKSsNCiAgICAgICAgICAgZ2VvbV9wb2ludChkYXRhID0gbG9nT2JzX25tR1NfZGZbbG9nT2JzX25tR1NfZGYkZmxlZXQgPT0gMiAmIGxvZ09ic19ubUdTX2RmJHllYXIgIT0gKERhdGFZZWFyKzEpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IHllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gbG9nT2JzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gYWdlKSwNCiAgICAgICAgICAgICAgICAgICAgICBzaGFwZSA9IDIxKSArDQogICAgICAgICAgIGdlb21fbGluZShkYXRhID0gbG9nUHJlZF9ubUdTX2RmW2xvZ1ByZWRfbm1HU19kZiRmbGVldCA9PSAyICYgbG9nUHJlZF9ubUdTX2RmJHllYXIgIT0gKERhdGFZZWFyKzEpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0geWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGxvZ1ByZWQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IGFnZSkpICsNCiAgICAgICAgICAgZmFjZXRfd3JhcChmYWNldHMgPSAiYWdlIikgKyAjLCBzY2FsZXMgPSAiZnJlZV95IikgKw0KICAgICAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gZWJwYWwsIGd1aWRlID0gRkFMU0UpICsNCiAgICAgICAgICAgZ3VpZGVzKGNvbG91cj1GQUxTRSwgc2hhcGU9RkFMU0UpICsNCiAgICAgICAgICAgdGhlbWVfZmV3KCkpDQojIGZpdHBsb3QoZml0X25tR1MsIGZsZWV0cz0yKQ0KYGBgDQoNCmBgYHtyIGZpZy5jYXA9Ik1vZGVsIHdpdGggU0NBTEVEIHRpbWUgaW52YXJpYW50IEdpc2xhc29uIG5hdHVyYWwgbW9ydGFsaXRpZXMgZml0IHRvIFEzLzQgc3VydmV5IGRhdGEgYnkgYWdlICh2YWx1ZXMgb24gdGhlIG1vZGVsIGxpbmsgZnVuY3Rpb24gc2NhbGUpLiJ9DQpnZ3Bsb3RseShnZ3Bsb3QoKSsNCiAgICAgICAgICAgZ2VvbV9wb2ludChkYXRhID0gbG9nT2JzX25tR1NfZGZbbG9nT2JzX25tR1NfZGYkZmxlZXQgPT0gMyAmIGxvZ09ic19ubUdTX2RmJHllYXIgIT0gKERhdGFZZWFyKzEpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IHllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gbG9nT2JzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gYWdlKSwNCiAgICAgICAgICAgICAgICAgICAgICBzaGFwZSA9IDIxKSArDQogICAgICAgICAgIGdlb21fbGluZShkYXRhID0gbG9nUHJlZF9ubUdTX2RmW2xvZ1ByZWRfbm1HU19kZiRmbGVldCA9PSAzICYgbG9nUHJlZF9ubUdTX2RmJHllYXIgIT0gKERhdGFZZWFyKzEpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0geWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGxvZ1ByZWQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IGFnZSkpICsNCiAgICAgICAgICAgZmFjZXRfd3JhcChmYWNldHMgPSAiYWdlIikgKyAjLCBzY2FsZXMgPSAiZnJlZV95IikgKw0KICAgICAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gZWJwYWwsIGd1aWRlID0gRkFMU0UpICsNCiAgICAgICAgICAgZ3VpZGVzKGNvbG91cj1GQUxTRSwgc2hhcGU9RkFMU0UpICsNCiAgICAgICAgICAgdGhlbWVfZmV3KCkpDQoNCiMgZml0cGxvdChmaXRfbm1HUywgZmxlZXRzPTMpDQpgYGANCg0KYGBge3IgZmlnLmNhcD0iU3RhbmRhcmQgRGV2YXRpb25zIGJ5IEZsZWV0OyBHaXNsYXNvbiwgc2NhbGVkLCB0aW1lLWludmFyaWFudCBtb3J0YWxpdHkiLCBoZWlnaHQ9MTB9DQpzZHBsb3QoZml0X25tR1MsIG1hcmcgPSBjKDUsNCwxLDEpKQ0KYGBgDQoNCiMjIyMgUmVzaWR1YWxzDQpgYGB7ciBjYWxjdWxhdGVSZXNpZHVhbHNfbm1HUywgd2FybmluZz1GQUxTRSwgcmVzdWx0cz0naGlkZSd9DQpyZXNpZF9ubUdTIDwtIHJlc2lkdWFscyhmaXRfbm1HUykNCnJlc2lkX25tR1NfZGYgPC0gZGF0YS5mcmFtZSh5ZWFyID0gcmVzaWRfbm1HUyR5ZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZsZWV0ID0gcmVzaWRfbm1HUyRmbGVldCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZ2UgPSByZXNpZF9ubUdTJGFnZSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBvYnNlcnZhdGlvbiA9IHJlc2lkX25tR1Mkb2JzZXJ2YXRpb24sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgbWVhbiA9IHJlc2lkX25tR1MkbWVhbiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXNpZHVhbCA9IHJlc2lkX25tR1MkcmVzaWR1YWwpDQpyZXNpZF9ubUdTX2RmJGZsZWV0TmFtZSA8LSBpZmVsc2UocmVzaWRfbm1HU19kZiRmbGVldCA9PSAxLCBhdHRyaWJ1dGVzKHJlc2lkX25tR1MpJGZsZWV0TmFtZXNbMV0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShyZXNpZF9ubUdTX2RmJGZsZWV0ID09IDIsIGF0dHJpYnV0ZXMocmVzaWRfbm1HUykkZmxlZXROYW1lc1syXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShyZXNpZF9ubUdTX2RmJGZsZWV0ID09IDMsIGF0dHJpYnV0ZXMocmVzaWRfbm1HUykkZmxlZXROYW1lc1szXSwgTkEpKSkNCg0KcmVzaWRfbm1HU19kZiRmbGVldEFsdE5hbWUgPC0gaWZlbHNlKHJlc2lkX25tR1NfZGYkZmxlZXQgPT0gMSwgIlJlc2lkdWFsIEZpc2hpbmciLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UocmVzaWRfbm1HU19kZiRmbGVldCA9PSAyLCAiUTEgU3VydmV5cyIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UocmVzaWRfbm1HU19kZiRmbGVldCA9PSAzLCAiUTMvNCBTdXJ2ZXlzIiwgTkEpKSkNCmBgYA0KDQpgYGB7ciBmaWcuY2FwPSJFc3RpbWF0ZWQgY29ycmVsYXRpb25zIGluIHJlc2lkdWFsIHZhcmlhdGlvbiBiZXR3ZWVuIGFnZXMgZm9yIGVhY2ggb2YgdGhlIGZpc2hpbmcgZmxlZXQgKHRvcCkgYW5kIHRoZSB0d28gc3VydmV5cyAobWlkZGxlICYgYm90dG9tKSwgZnJvbSB0aGUgTW9kZWwgd2l0aCBTQ0FMRUQgdGltZSBpbnZhcmlhbnQgR2lzbGFzb24gbmF0dXJhbCBtb3J0YWxpdGllcy4ifQ0KDQppZighYWxsKGZpdF9ubUdTJGNvbmYkb2JzQ29yU3RydWN0PT0iSUQiKSl7IA0KICBjb3JwbG90KGZpdF9ubUdTKQkJCSAgDQogICMgc2V0Y2FwKCJFc3RpbWF0ZWQgY29ycmVsYXRpb25zIiwgIkVzdGltYXRlcyBjb3JyZWxhdGlvbnMgYmV0d2VlbiBhZ2UgZ3JvdXBzIGZvciBlYWNoIGZsZWV0IikNCiAgIyBzdGFtcGl0KGZpdCkNCn0gZWxzZSB7DQogIHByaW50KCJObyBjb3JyZWxhdGlvbiBzdHJ1Y3R1cmUgY29uZmlndXJlZCBmb3IgcmVzaWR1YWxzIGFjcm9zcyBhZ2UuIikNCn0NCg0KYGBgDQoNCmBgYHtyIGZpZy5jYXA9Ik9uZSBvYnNlcnZhdGlvbiBhaGVhZCByZXNpZHVhbHMgZm9yIHRoZSB0aHJlZSBmbGVldHMgKHJlZC9waW5rID0gb2JzZXJ2YXRpb24gbG93ZXIgdGhhbiBtb2RlbCBlc3RpbWF0ZSwgYmx1ZSA9IG9ic2VydmF0aW9uIGhpZ2hlciB0aGFuIG1vZGVsIGVzdGltYXRlLCBzaXplID0gbWFnbml0dWRlIG9mIHJlc2lkdWFsKSwgZnJvbSB0aGUgTW9kZWwgd2l0aCBTQ0FMRUQgdGltZSBpbnZhcmlhbnQgR2lzbGFzb24gbmF0dXJhbCBtb3J0YWxpdGllcy4ifQ0KZ2dwbG90bHkoZ2dwbG90KHJlc2lkX25tR1NfZGYpICsNCiAgICAgICAgICAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSB5ZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGFnZSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSBhYnMocmVzaWR1YWwpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gcmVzaWR1YWwgPj0gMCksDQogICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjcpICsNCiAgICAgICAgICAgZmFjZXRfZ3JpZChyb3dzID0gImZsZWV0QWx0TmFtZSIpICsNCiAgICAgICAgICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCJUUlVFIiA9IGVicGFsWzhdLCAiRkFMU0UiID0gZWJwYWxbOV0pKSArDQogICAgICAgICAgIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKC0xLCA5KSwgYnJlYWtzID0gYygxOjkpKSArDQogICAgICAgICAgIGd1aWRlcyhjb2xvdXI9RkFMU0UpICsNCiAgICAgICAgICAgdGhlbWVfZmV3KCkpDQoNCmBgYA0KDQojIyMjIEppdHRlcmluZw0KV2UgY2FuIGFsc28gdGVzdCB0byBzZWUgaWYgdGhlIG1vZGVsIGlzIGNvbnZlcmdpbmcgb24gc29tZSBsb2NhbCBtaW5pbXVtIChpLmUuIGl0J3MgZml0dGluZyB0byBzb21lIHNvbHV0aW9uIGNsb3NlIHRvIGluaXRpYWxpc2luZyB2YWx1ZXMgdGhhdCByZXByZXNlbnRzIG5vaXNlIGFuZCBub3QgdGhlIGdsb2JhbCBzb2x1dGlvbiwgdGhhdCBpcyB0aGUgcHJvcGVyIHNvbHV0aW9uKS4gIFRvIGRvIHRoaXMsIHdlIGFkZCByYW5kb20gbm9pc2UgdG8gdGhlIGluaXRpYWwgcGFyYW1ldGVyIHZhbHVlcyB0byBzZWUgaWYgdGhlIG1vZGVsIHdpbGwgY29udmVyZ2Ugb24gYSBkaWZmZXJlbnQgbWluaW11bSBpbiBpdCdzIGRhdGEtc3BhY2UuIFRoZSBlYXNpZXN0IHdheSB0byBpbnZlc3RpZ2F0ZSB0aGlzIGlzIHRvIHNlZSBpZiB0aGUgbW9kZWwgZml0cyB2YXJ5IGFsb3QgZGVwZW5kaW5nIG9uIHRoZSBzdGFydGluZyB2YWx1ZXM6DQpgYGB7ciBKaXR0ZXJfbm1HU30NCmppdF9ubUdTIDwtIGppdChmaXQgPSBmaXRfbm1HUykNCg0KbXQgPC0gYXMuZGF0YS5mcmFtZShtb2RlbHRhYmxlKGppdF9ubUdTKSkNCm10JG1vZGVsIDwtIHJvd25hbWVzKG10KQ0Kcm93bmFtZXMobXQpIDwtIE5VTEwNCg0Ka2FibGUoeCA9IG10LA0KICAgICAgZGlnaXRzID0gMywNCiAgICAgIGNhcHRpb24gPSAiTWVhc3VyZXMgb2YgIGZpdCBmb3IgYSBzZXJpZXMgb2YgbW9kZWwgcmVmaXRzIHdpdGggaml0dGVyIGFwcGxpZWQgdG8gdGhlIGlucHV0IHBhcmFtZXRlcnMuIikNCmBgYA0KDQojIyMjIExlYXZlLU9uZS1PdXQgQW5hbHlzZXMNCkEgbGVhdmUtb25lLW91dCBhbmFseXNpcyBpcyBhIGZvcm0gb2Ygc2Vuc2l0aXZpdHkgYW5hbHlzaXMsIHNob3dpbmcgdGhlIGltcGFjdCB0aGUgZGF0YSBmcm9tIGVhY2ggdHVuaW5nIGZsZWV0IGhhcyBvbiB0aGUgZXN0aW1hdGlvbiBvZiB0aGUga2V5IHZhcmlhYmxlcyBiZWluZyBlc3RpbWF0ZWQ7IG5hbWVseSBTU0IsIEYgYW5kIHJlY3J1aXRtZW50LiAgDQoNCkZpcnN0IHdlIG11c3QgcnVuIHRoZSBsZWF2ZS1vbmUtb3V0IGFuYWx5c2lzIHdoaWNoIHJlZml0cyB0aGUgbW9kZWwgaW4gdHdvIGl0ZXJhdGlvbnMsIHJlbW92aW5nIG9uZSBzdXJ2ZXkgYXQgYSB0aW1lLiBUaGVuIHdlIGNhbiBwbG90IGVhY2ggb2YgdGhlc2UgbmV3IG1vZGVsIGZpdHMgb3ZlciB0aGUgZnVsbCBtb2RlbCB0byBzZWUgdGhlIGltcGFjdCB0aGUgcmVtb3ZhbCBvZiBlYWNoIGhhcy4gDQoNCmBgYHtyIExlYXZlT25lT3V0X25tR1N9DQpMT19ubUdTIDwtIGxlYXZlb3V0KGZpdF9ubUdTKQ0KDQojPT09IA0KIyBHZXQgZGF0YSBmcm9tIHNhbSBvYmplY3RzIGFuZCBnZW5lcmF0ZSB1c2VhYmxlIGRhdGFmcmFtZXMNCiM9PT09DQpxMW1hdCA8LSBhcy5kYXRhLmZyYW1lKHN1bW1hcnkoTE9fbm1HUyRgdy5vLiBRMUlCVFMrQklUUytDb2RTRDIxLTI1YCkpDQpxM21hdCA8LSBhcy5kYXRhLmZyYW1lKHN1bW1hcnkoTE9fbm1HUyRgdy5vLiBRMzRJQlRTK0JJVFMrQ29kU0QyMS0yNWApKQ0KDQoNCndvcTEgPC0gZGF0YS5mcmFtZShZZWFyID0gYXMuaW50ZWdlcihyb3cubmFtZXMoc3VtbWFyeShMT19ubUdTJGB3Lm8uIFExSUJUUytCSVRTK0NvZFNEMjEtMjVgKSkpLA0KICAgICAgICAgICAgICAgICAgIFNTQiA9IHExbWF0JFNTQiwNCiAgICAgICAgICAgICAgICAgICBGYmFyID0gcTFtYXQkYEZiYXIoMy01KWAsDQogICAgICAgICAgICAgICAgICAgUl9hZ2UxID0gcTFtYXQkYFIoYWdlIDEpYCwNCiAgICAgICAgICAgICAgICAgICBDYXRjaEVzdCA9IGNhdGNodGFibGUoTE9fbm1HUyRgdy5vLiBRMUlCVFMrQklUUytDb2RTRDIxLTI1YClbLDFdLA0KICAgICAgICAgICAgICAgICAgIHNlcmllcyA9IHJlcCgid29fUTEiLCB0aW1lcyA9IG5yb3cocTFtYXQpKSkNCg0Kd29xMzQgPC0gZGF0YS5mcmFtZShZZWFyID0gYXMuaW50ZWdlcihyb3cubmFtZXMocTNtYXRbKDIwMDI6RGF0YVllYXIpLTIwMDEsXSkpLA0KICAgICAgICAgICAgICAgICAgICBTU0IgPSBxM21hdFsoMjAwMjpEYXRhWWVhciktMjAwMSwgIlNTQiJdLA0KICAgICAgICAgICAgICAgICAgICBGYmFyID0gcTNtYXRbKDIwMDI6RGF0YVllYXIpLTIwMDEsIkZiYXIoMy01KSJdLA0KICAgICAgICAgICAgICAgICAgICBSX2FnZTEgPSBxM21hdFsoMjAwMjpEYXRhWWVhciktMjAwMSwiUihhZ2UgMSkiXSwNCiAgICAgICAgICAgICAgICAgICAgQ2F0Y2hFc3QgPSBjYXRjaHRhYmxlKExPX25tR1MkYHcuby4gUTM0SUJUUytCSVRTK0NvZFNEMjEtMjVgKVssMV0sDQogICAgICAgICAgICAgICAgICAgIHNlcmllcyA9IHJlcCgid29fUTM0IiwgdGltZXMgPSAobnJvdyhxM21hdCktMSkpKQ0KDQoNCmFzdW1fbm1HUyRzZXJpZXMgPC0gcmVwKCJmdWxsIiwgdGltZXMgPSBucm93KGFzdW1fbm1HUykpDQphc3VtaV9ubUdTIDwtIGFzdW1fbm1HU1ssIGMoIlllYXIiLCAiU1NCIiwgIkZiYXIiLCAiUl9hZ2UxIiwgIkNhdGNoRXN0IiAsInNlcmllcyIpXQ0KIz09PT09DQoNCmxvc3VtX25tR1MgPC0gcmJpbmQod29xMSwgd29xMzQsIGFzdW1pX25tR1MpDQoNCmBgYA0KDQpgYGB7ciBmaWcuY2FwPSJMZWF2ZS1vbmUtb3V0IHJlLWZpdHMgZm9yIHRoZSBUaW1lIGludmFyaWFudCwgc2NhbGVkLCBHaXNsYXNvbiBuYXR1cmFsIG1vcnRhbGl0aWVzICh3aXRob3V0IFExIHN1cnZleSA9IGJsdWUsIHdpdGhvdXQgUTMvNCBzdXJ2ZXkgPSBwdXJwbGUpLCBvdmVybGFpbiB3aXRoIGZ1bGwgbW9kZWwgZXN0aW1hdGVzIChibGFjayBsaW5lIGFuZCBncmV5IHJpYmJvbikgb2YgU1NCICh0b3AgbGVmdCksIEYgKHRvcCByaWdodCksIFJlY3J1aXRtZW50IChib3R0b20gbGVmdCksIGFuZCBjYXRjaCAoYm90dG9tIHJpZ2h0OyBvYnNlcnZhdGlvbnMgYXMgeWVsbG93ICspLiJ9DQojIHNzYnBsb3QoTE8pDQpsb3NzYl9ubUdTIDwtIGdncGxvdGx5KGdncGxvdCgpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IGxvc3VtX25tR1MsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9U1NCLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IHNlcmllcykpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3JpYmJvbihkYXRhID0gYXN1bV9ubUdTLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1pbj1TU0Jsb3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4PVNTQmhpZ2gpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSAiYmxhY2siLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4yKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCJibGFjayIsIGVicGFsWzg6OV0pKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWVfY2xlYW4oKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWUoYXhpcy50aXRsZS55LmxlZnQgPSBlbGVtZW50X3RleHQodmp1c3QgPSAtMC4wNSwgaGp1c3QgPSAwLjk1KSkpDQoNCiMgRnBsb3QoTE8pDQpsb2Zfbm1HUyA8LSBnZ3Bsb3RseShnZ3Bsb3QoKSArDQogICAgICAgICAgICAgICAgICAgICAgIGdlb21fbGluZShkYXRhID0gbG9zdW1fbm1HUywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PUZiYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IHNlcmllcykpICsNCiAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9yaWJib24oZGF0YSA9IGFzdW1fbm1HUywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1pbj1GbG93LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltYXg9RmhpZ2gpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gImJsYWNrIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjMpICsNCiAgICAgICAgICAgICAgICAgICAgICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCJibGFjayIsIGVicGFsWzg6OV0pKSArDQogICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2NsZWFuKCkgKw0KICAgICAgICAgICAgICAgICAgICAgICB0aGVtZShheGlzLnRpdGxlLnkubGVmdCA9IGVsZW1lbnRfdGV4dCh2anVzdCA9IC0wLjA1LCBoanVzdCA9IDAuOTUpKSkNCg0KIyByZWNwbG90KExPKQ0KbG9yZWNfbm1HUyA8LSBnZ3Bsb3RseShnZ3Bsb3QoKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9saW5lKGRhdGEgPSBsb3N1bV9ubUdTLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PVJfYWdlMSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBzZXJpZXMpKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9yaWJib24oZGF0YSA9IGFzdW1fbm1HUywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW49UmxvdywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltYXg9UmhpZ2gpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSAiYmxhY2siLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4zKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCJibGFjayIsIGVicGFsWzg6OV0pKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWVfY2xlYW4oKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWUoYXhpcy50aXRsZS55LmxlZnQgPSBlbGVtZW50X3RleHQodmp1c3QgPSAtMC4wNSwgaGp1c3QgPSAwLjk1KSkpDQoNCiMgQ2F0Y2ggcGxvdCAoTE8pDQpsb2NhX25tR1MgPC0gZ2dwbG90bHkoZ2dwbG90KCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9saW5lKGRhdGEgPSBsb3N1bV9ubUdTLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1DYXRjaEVzdCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IHNlcmllcykpKw0KICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9yaWJib24oZGF0YSA9IGFzdW1fbm1HU1thc3VtX25tR1MkWWVhciAhPSAoRGF0YVllYXIrMSksIF0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1pbj1DYXRjaGxvdywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1heD1DYXRjaGhpZ2gpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9ICJibGFjayIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMykgKw0KICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9wb2ludChkYXRhID0gYXN1bV9ubUdTW2FzdW1fbm1HUyRZZWFyICE9IChEYXRhWWVhcisxKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1DYXRjaE9icyksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNoYXBlID0gMywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gZWJwYWxbNV0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBlYnBhbFs1XSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgeWxhYigiQ2F0Y2ggKHRvbm5lcykiKSArDQogICAgICAgICAgICAgICAgICAgICAgICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoImJsYWNrIiwgZWJwYWxbODo5XSkpKyANCiAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2NsZWFuKCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWUoYXhpcy50aXRsZS55LmxlZnQgPSBlbGVtZW50X3RleHQodmp1c3QgPSAtMC4wNSwgaGp1c3QgPSAwLjk1KSkpDQoNCmxheW91dChzdWJwbG90KGxvc3NiX25tR1MsIGxvZl9ubUdTLCBsb3JlY19ubUdTLCBsb2NhX25tR1MsIG5yb3dzID0gMiwgc2hhcmVYID0gVFJVRSwgdGl0bGVZID0gVFJVRSksIHNob3dsZWdlbmQ9RkFMU0UpDQpgYGANCg0KIyMjIyBSZXRyb3NwZWN0aXZlcw0KYGBge3IgY2FsY3VsYXRlUmV0cm9zX25tR1N9DQojPT09DQojIENyZWF0ZSBkYXRhZnJhbWUgb2YgY3VycmVudCB5ZWFyJ3MgZml0IGZvciBwbG90dGluZw0KIz09PT0NCiMgSUNfYWdnX3RlbXAgPC0gYWdncmVnYXRlKENBVE9OflllYXIsIGljX2NsZWFuW2ljX2NsZWFuJENhdGNoQ2F0ZWdvcnkgJWluJSBjKCJMYW5kaW5ncyIsICJEaXNjYXJkcyIpLCBdLCBGVU4gPSAic3VtIikNCmFzdW1fbm1HUyA8LSBhcy5kYXRhLmZyYW1lKHN1bW1hcnkoZml0X25tR1MpKQ0KYXN1bV9ubUdTJFllYXIgPC0gYXMuaW50ZWdlcihyb3cubmFtZXMoc3VtbWFyeShmaXRfbm1HUykpKQ0KY3Rfbm1HUyA8LSBhcy5kYXRhLmZyYW1lKGNhdGNodGFibGUoZml0X25tR1MsIG9icy5zaG93ID0gVFJVRSkpDQpjdF9ubUdTJFllYXIgPC0gYXMuaW50ZWdlcihyb3duYW1lcyhjdF9ubUdTKSkNCnJvd25hbWVzKGN0X25tR1MpIDwtIE5VTEwNCmN0X25tR1MgPC0gcmJpbmQoY3Rfbm1HUywgZGF0YS5mcmFtZShFc3RpbWF0ZSA9IE5BLCBMb3c9TkEsIEhpZ2g9TkEsIHNvcC5jYXRjaD1OQSwgWWVhcj1hcy5pbnRlZ2VyKDIwMjQpKSkNCmFzdW1fbm1HUyA8LSBtZXJnZSh4ID0gYXN1bV9ubUdTLCB5ID0gY3Rfbm1HUywgYnkgPSAiWWVhciIpDQpjb2xuYW1lcyhhc3VtX25tR1MpIDwtIGMoIlllYXIiLCAiUl9hZ2UxIiwgIlJsb3ciLCAiUmhpZ2giLCAiU1NCIiwgIlNTQmxvdyIsICJTU0JoaWdoIiwgIkZiYXIiLCAiRmxvdyIsICJGaGlnaCIsICJDYXRjaEVzdCIsICJDYXRjaGxvdyIsICJDYXRjaGhpZ2giLCAiQ2F0Y2hPYnMiKQ0KDQphc3VtX25tR1Mkc2VyaWVzIDwtIHJlcCgiZnVsbCIsIHRpbWVzID0gbnJvdyhhc3VtX25tR1MpKQ0KDQojPT09PT0NClJFVFJPX25tR1M8LXJldHJvKGZpdF9ubUdTLCB5ZWFyPTUpDQpyaG9fbm1HUyA8LSBtb2huKFJFVFJPX25tR1MsIGxhZyA9IDEpDQoNCiMjIE1ha2UgUkVUUk9zIGluIGJldHRlciBwbG90dGluZyBmb3JtYXQNCnJldF9ubUdTX2RmIDwtIGFzdW1fbm1HU1thc3VtX25tR1MkWWVhciAhPSBtYXgoYXN1bV9ubUdTJFllYXIpLCBdDQoNCmZvcihpIGluIDE6bGVuZ3RoKFJFVFJPX25tR1MpKXsNCiAgdHN1bSA8LSBhcy5kYXRhLmZyYW1lKHN1bW1hcnkoUkVUUk9fbm1HU1tbaV1dKSkNCiAgdHN1bSRZZWFyIDwtIGFzLmludGVnZXIocm93Lm5hbWVzKHN1bW1hcnkoUkVUUk9fbm1HU1tbaV1dKSkpDQogIHRzdW0gPC0gY2JpbmQodHN1bSwgY2F0Y2h0YWJsZShSRVRST19ubUdTW1tpXV0sIG9icy5zaG93ID0gVFJVRSkpDQogIHRzdW0kc2VyaWVzIDwtIGFzLmNoYXJhY3RlcihyZXAoaSwgbnJvdyh0c3VtKSkpDQogIGNvbG5hbWVzKHRzdW0pIDwtIGMoIlJfYWdlMSIsICJSbG93IiwgIlJoaWdoIiwgIlNTQiIsICJTU0Jsb3ciLCAiU1NCaGlnaCIsICJGYmFyIiwgIkZsb3ciLCAiRmhpZ2giLCAiWWVhciIsICJDYXRjaEVzdCIsICJDYXRjaGxvdyIsICJDYXRjaGhpZ2giLCAiQ2F0Y2hPYnMiLCAic2VyaWVzIikNCiAgdHN1bSA8LSB0c3VtW3RzdW0kWWVhciAhPSBtYXgodHN1bSRZZWFyKSwgXQ0KICByZXRfbm1HU19kZiA8LSByYmluZChyZXRfbm1HU19kZiwgdHN1bSkNCn0NCnJldF9ubUdTX2RmJHNlcmllcyA8LSBmYWN0b3IocmV0X25tR1NfZGYkc2VyaWVzLCBsZXZlbHMgPSBjKCJmdWxsIiwgIjEiLCAiMiIsICIzIiwgIjQiLCAiNSIpKQ0KYGBgDQoNCmBgYHtyIGZpZy5jYXA9IlJldHJvc3BlY3RpdmUgYW5hbHlzZXMgZm9yIFNTQiAodG9wLWxlZnQpLCBGIGZvciBhZ2VzIDMtNSAodG9wLXJpZ2h0KSwgcmVjcnVpdG1lbnQgKGJvdHRvbS1sZWZ0KSwgYW5kIGNhdGNoIChib3R0b20tcmlnaHQpLCBmcm9tIHRoZSBtb2RlbCB1dGlsaXNpbmcgU0NBTEVEIHRpbWUgaW52YXJpYW50LCBHaXNsYXNvbiBuYXR1cmFsIG1vcnRhbGl0aWVzLiJ9DQojIHNzYnBsb3QoUkVUUk8pDQpyZXRzc2Jfbm1HUyA8LSBsYXlvdXQoZ2dwbG90bHkoZ2dwbG90KCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9saW5lKGRhdGEgPSByZXRfbm1HU19kZiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9U1NCLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gc2VyaWVzKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9yaWJib24oZGF0YSA9IGFzdW1fbm1HU1thc3VtX25tR1MkWWVhciAhPSBtYXgoYXN1bV9ubUdTJFllYXIpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW49U1NCbG93LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4PVNTQmhpZ2gpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9ICJibGFjayIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMikgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYW5ub3RhdGUoZ2VvbSA9ICJ0ZXh0IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBtYXgocmV0X25tR1NfZGYkU1NCaGlnaCkqMC44NSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHggPSAoKG1heChyZXRfbm1HU19kZiRZZWFyKS1taW4ocmV0X25tR1NfZGYkWWVhcikpKjAuMjApK21pbihyZXRfbm1HU19kZiRZZWFyKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsID0gcGFzdGUwKCJNb2huJ3MgUmhvID0gIiwgcm91bmQocmhvX25tR1NbMl0sIGRpZ2l0cyA9IDMpKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCJibGFjayIsIGVicGFsWyhsZW5ndGgoZWJwYWwpLTQpOmxlbmd0aChlYnBhbCldKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWVfY2xlYW4oKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBheGlzLnRpdGxlLnkubGVmdCA9IGVsZW1lbnRfdGV4dCh2anVzdCA9IC0wLjA1LCBoanVzdCA9IDAuOTUpKSksDQogICAgICAgICAgICAgICAgICAgICAgc2hvd2xlZ2VuZCA9IEZBTFNFKQ0KDQojIEZwbG90KFJFVFJPKQ0KcmV0Zl9ubUdTIDwtIGxheW91dChnZ3Bsb3RseShnZ3Bsb3QoKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9saW5lKGRhdGEgPSByZXRfbm1HU19kZiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1GYmFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IHNlcmllcykpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3JpYmJvbihkYXRhID0gYXN1bV9ubUdTW2FzdW1fbm1HUyRZZWFyICE9IG1heChhc3VtX25tR1MkWWVhciksIF0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWluPUZsb3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4PUZoaWdoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gImJsYWNrIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMykgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFubm90YXRlKGdlb20gPSAidGV4dCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IG1heChyZXRfbm1HU19kZiRGaGlnaCkqMC44NSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4ID0gKChtYXgocmV0X25tR1NfZGYkWWVhciktbWluKHJldF9ubUdTX2RmJFllYXIpKSowLjgwKSttaW4ocmV0X25tR1NfZGYkWWVhciksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSBwYXN0ZTAoIk1vaG4ncyBSaG8gPSAiLCByb3VuZChyaG9fbm1HU1szXSwgZGlnaXRzID0gMykpKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCJibGFjayIsIGVicGFsWyhsZW5ndGgoZWJwYWwpLTQpOmxlbmd0aChlYnBhbCldKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2NsZWFuKCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBheGlzLnRpdGxlLnkubGVmdCA9IGVsZW1lbnRfdGV4dCh2anVzdCA9IC0wLjA1LCBoanVzdCA9IDAuOTUpKSksDQogICAgICAgICAgICAgICAgICAgIHNob3dsZWdlbmQgPSBGQUxTRSkNCg0KIyByZWNwbG90KFJFVFJPKQ0KcmV0cmVjX25tR1MgPC0gbGF5b3V0KGdncGxvdGx5KGdncGxvdCgpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fbGluZShkYXRhID0gcmV0X25tR1NfZGYsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PVJfYWdlMSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IHNlcmllcykpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fcmliYm9uKGRhdGEgPSBhc3VtX25tR1NbYXN1bV9ubUdTJFllYXIgIT0gbWF4KGFzdW1fbm1HUyRZZWFyKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWluPVJsb3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltYXg9UmhpZ2gpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9ICJibGFjayIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMykgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYW5ub3RhdGUoZ2VvbSA9ICJ0ZXh0IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9IG1heChyZXRfbm1HU19kZiRSaGlnaCkqMC44NSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHggPSAoKG1heChyZXRfbm1HU19kZiRZZWFyKS1taW4ocmV0X25tR1NfZGYkWWVhcikpKjAuMjApK21pbihyZXRfbm1HU19kZiRZZWFyKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsID0gcGFzdGUwKCJNb2huJ3MgUmhvID0gIiwgcm91bmQocmhvX25tR1NbMV0sIGRpZ2l0cyA9IDMpKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCJibGFjayIsIGVicGFsWyhsZW5ndGgoZWJwYWwpLTQpOmxlbmd0aChlYnBhbCldKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWVfY2xlYW4oKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBheGlzLnRpdGxlLnkubGVmdCA9IGVsZW1lbnRfdGV4dCh2anVzdCA9IC0wLjA1LCBoanVzdCA9IDAuOTUpKSksDQogICAgICAgICAgICAgICAgICAgICAgc2hvd2xlZ2VuZCA9IEZBTFNFKQ0KDQojIENhdGNoIHBsb3QgKFJFVFJPKQ0KcmV0Y2Ffbm1HUyA8LSBnZ3Bsb3RseShnZ3Bsb3QoKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9saW5lKGRhdGEgPSByZXRfbm1HU19kZiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1DYXRjaEVzdCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBzZXJpZXMpKSsNCiAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3JpYmJvbihkYXRhID0gYXN1bV9ubUdTW2FzdW1fbm1HUyRZZWFyICE9IG1heChhc3VtX25tR1MkWWVhciksIF0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWluPUNhdGNobG93LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1heD1DYXRjaGhpZ2gpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSAiYmxhY2siLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4zKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9wb2ludChkYXRhID0gYXN1bV9ubUdTW2FzdW1fbm1HUyRZZWFyICE9IG1heChhc3VtX25tR1MkWWVhciksIF0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1DYXRjaE9icyksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaGFwZSA9IDMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBlYnBhbFs1XSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBlYnBhbFs1XSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgIHlsYWIoIkNhdGNoICh0b25uZXMpIikgKw0KICAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiYmxhY2siLCBlYnBhbFsobGVuZ3RoKGVicGFsKS00KTpsZW5ndGgoZWJwYWwpXSkpKyANCiAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9jbGVhbigpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZShheGlzLnRpdGxlLnkubGVmdCA9IGVsZW1lbnRfdGV4dCh2anVzdCA9IC0wLjA1LCBoanVzdCA9IDAuOTUpKSkNCg0KcmV0X2ZwIDwtIHN0eWxlKHN1YnBsb3QocmV0c3NiX25tR1MsIHJldGZfbm1HUywgcmV0cmVjX25tR1MsIHJldGNhX25tR1MsIG5yb3dzID0gMiwgc2hhcmVYID0gRkFMU0UsIHNoYXJlWSA9IEZBTFNFLCB0aXRsZVkgPSBUUlVFKSwNCiAgICAgICAgICAgICAgICBzaG93bGVnZW5kPUZBTFNFLA0KICAgICAgICAgICAgICAgIHRyYWNlcyA9IGMoODooKDcqNCkrMikpKQ0KDQpsYXlvdXQocmV0X2ZwLCBsZWdlbmQgPSBsaXN0KG9yaWVudGF0aW9uID0gJ2gnLCB4ID0gMC41LCB4YW5jaG9yID0gJ2NlbnRlcicsIHkgPSAtMC4wNSwgeWFuY2hvciA9ICd0b3AnLCBib3JkZXJ3aWR0aCA9IDApKQ0KYGBgDQoNCiMjIFRpbWUgYW5kIEFnZSBWYXJpYW50LCBHaXNsYXNvbiBOYXR1cmFsIE1vcnRhbGl0aWVzDQpBbiBhbHRlcm5hdGUgd2F5IHRvIGRlYWxpbmcgd2l0aCB0aGUgaXNzdWUgb2YgdGFraW5nIHRoZSB1bndlaWdodGVkIG1lYW5zIG92ZXIgdGhlIHRpbWUgc2VyaWVzIGlzIHRvIG5vdCB1c2UgdGhlIGZ1bGwgdGltZS1zZXJpZXMgbWVhbnMuIFdoaWxlIHRoZSBsaWZlLWhpc3RvcnkgcGFyYW1ldGVycyAkTF97XGluZnR5fSQgYW5kICRLJCBhcmUgY2FsY3VsYXRlZCBmcm9tIGFsbCBhZ2VzIG9ic2VydmF0aW9ucyAocTEgc3VydmV5cykgZm9yIHRoZSB3aG9sZSB0aW1lIHNlcmllcywgdGhleSBjYW4gYmUgYXBwbGllZCBpbiB0aGUgR2lzbGFzb24gbW9kZWwgdG8gc3BlY2lmaWMgeWVhcnMsIGJ5IHV0aWxpc2luZyB0aGUgbGVuZ3RocyBhdCBhZ2UgZm9yIGVhY2ggeWVhci4gIER1ZSB0byB0aGUgc2FtcGxpbmcgcmF0ZXMgdGhlc2UgZGF0YSB3aWxsIGJlIGluaGVyZW50bHkgbm9pc2V5LCBqdXN0IGFzIGlzIHRoZSBjYXNlIGZvciB0aGUgc3RvY2sgd2VpZ2h0cyBhdCBhZ2UgYW5kIHRoZSBtYXR1cml0eSBvZ2l2ZXMsIGhlbmNlIHdlIG5lZWQgc29tZSBtZXRob2Qgb2Ygc21vb3RoaW5nIG91dCB0aGlzIG5vaXNlLiAgSW4gdGhpcyBleGFtcGxlIHdlIHV0aWxpc2UgYSBmaXZlLXllYXIgc2xpZGluZyB3aW5kb3cgbWVhbiBvbiB0aGUgYW5udWFsIGVzdGltYXRlcyBvZiBuYXR1cmFsIG1vcnRhbGl0eSBhdCBhZ2UsIHRvIGFsbG93IG1vcnRhbGl0eSBhdCBhZ2UgdG8gdmFyeSBpbiB0aW1lIHdpdGhvdXQgaW50cm9kdWNpbmcgdG9vIG11Y2ggaW50ZXJhbm51YWwgdmFyaWF0aW9uLiANCg0KYGBge3Igbm1HNXlzd0ZpdEZyb21XZWJ9DQpmaXRfbm1HNXlzdyA8LSBmaXRmcm9td2ViKCJwbGUuMjcuMjEtMzJfV0tCUExBSUNFXzIwMjRfQmlvUGFyc3dfbm1HNXlzdyIpDQpgYGANCg0KYGBge3IgZGF0YWZyYW1lU3VtbWFyeV9ubUc1eXN3LCByZXN1bHRzPSdoaWRlJywgZmlnLnNob3c9J2hpZGUnfQ0KIz09PQ0KIyBDcmVhdGUgZGF0YWZyYW1lIG9mIGN1cnJlbnQgeWVhcidzIGZpdCBmb3IgcGxvdHRpbmcNCiM9PT09DQphc3VtX25tRzV5c3cgPC0gYXMuZGF0YS5mcmFtZShzdW1tYXJ5KGZpdF9ubUc1eXN3KSkNCmFzdW1fbm1HNXlzdyRZZWFyIDwtIGFzLmludGVnZXIocm93Lm5hbWVzKHN1bW1hcnkoZml0X25tRzV5c3cpKSkNCmN0X25tRzV5c3cgPC0gYXMuZGF0YS5mcmFtZShjYXRjaHRhYmxlKGZpdF9ubUc1eXN3LCBvYnMuc2hvdyA9IFRSVUUpKQ0KY3Rfbm1HNXlzdyRZZWFyIDwtIGFzLmludGVnZXIocm93bmFtZXMoY3Rfbm1HNXlzdykpDQpyb3duYW1lcyhjdF9ubUc1eXN3KSA8LSBOVUxMDQpjdF9ubUc1eXN3IDwtIHJiaW5kKGN0X25tRzV5c3csIGRhdGEuZnJhbWUoRXN0aW1hdGUgPSBOQSwgTG93PU5BLCBIaWdoPU5BLCBzb3AuY2F0Y2g9TkEsIFllYXI9YXMuaW50ZWdlcigyMDI0KSkpDQphc3VtX25tRzV5c3cgPC0gbWVyZ2UoeCA9IGFzdW1fbm1HNXlzdywgeSA9IGN0X25tRzV5c3csIGJ5ID0gIlllYXIiKQ0KY29sbmFtZXMoYXN1bV9ubUc1eXN3KSA8LSBjKCJZZWFyIiwgIlJfYWdlMSIsICJSbG93IiwgIlJoaWdoIiwgIlNTQiIsICJTU0Jsb3ciLCAiU1NCaGlnaCIsICJGYmFyIiwgIkZsb3ciLCAiRmhpZ2giLCAiQ2F0Y2hFc3QiLCAiQ2F0Y2hsb3ciLCAiQ2F0Y2hoaWdoIiwgIkNhdGNoT2JzIikNCiM9PT09PQ0KYGBgDQoNCiMjIyBGaXRzIHRvIGRhdGENCldoZW4gdGhlIG1vZGVsIGlzIHJ1biB3ZSBjYW4gZWFzaWx5IHNlZSBmcm9tIHdhcm5pbmdzL2Vycm9ycyBpZiB0aGVyZSBpcyBhIGNvbnZlcmdlbmNlIGlzc3VlLiAgSG93ZXZlciwgd2UgY2FuIGFsc28gY29uZmlybSB0aGlzLCBleHBsaWNpdGx5Og0KLSBUaGUgZmluYWwgbW9kZWwgZ3JhZGllbnQ6IGByIGZpdF9ubUc1eXN3JG9wdCRldmFsdWF0aW9uc1syXWANCi0gVGhhdCB0aGVyZSBpcyBhIHBvc2l0aXZlIGRlZmluaXRlIGhlc3NpYW46IGByIGFsbChlaWdlbihmaXRfbm1HNXlzdyRvcHQkaGUpJHZhbHVlcyA+MClgDQoNCkZ1cnRoZXJtb3JlLCBTQU0gZG9lcyBub3QgdXRpbGlzZSAiYm91bmRzIiB3aGVuIGZpdHRpbmcgdGhlIG1vZGVsLCBhbmQgdGhlcmVmb3JlLCBhcyBzdGFuZGFyZCBjaGVjayBvZiB3aGV0aGVyIG1vZGVsIHBhcmFtZXRlcnMgYXJlIGFwcHJvYWNoaW5nIHRoZWlyIGJvdW5kcyBpcyBpcnJlbGV2YW50Lg0KDQpgYGB7ciBmaWcuY2FwPSJNb2RlbCB3aXRoIHRpbWUgdmFyeWluZyAoZml2ZSB5ZWFyIHNsaWlkaW5nIHdpbmRvdyBtZWFuKSwgYWdlIHZhcnlpbmcsIEdpc2xhc29uIG5hdHVyYWwgbW9ydGFsaXRpZXMgZml0IHRvIGNhdGNoIGRhdGEgYnkgYWdlICh2YWx1ZXMgb24gdGhlIG1vZGVsIGxpbmsgZnVuY3Rpb24gc2NhbGUpLiJ9DQojIyBFeHRyYWN0IGRhdGEgZnJvbSBtb2RlbCBvYmplY3QNCmxvZ09ic19ubUc1eXN3IDwtIHNwbGl0KGZpdF9ubUc1eXN3JGRhdGEkbG9nb2JzLCBjZWlsaW5nKHNlcV9hbG9uZyhmaXRfbm1HNXlzdyRkYXRhJGxvZ29icykvZml0X25tRzV5c3ckZGF0YSRtYXhBZ2VQZXJGbGVldFsxXSkpDQpsb2dQcmVkX25tRzV5c3cgPC0gc3BsaXQoZml0X25tRzV5c3ckcmVwJHByZWRPYnMsIGNlaWxpbmcoc2VxX2Fsb25nKGZpdF9ubUc1eXN3JHJlcCRwcmVkT2JzKS9maXRfbm1HNXlzdyRkYXRhJG1heEFnZVBlckZsZWV0WzFdKSkNCg0KIyMgVHJhbnNmb3JtIGRhdGEgdG8gdXNlYWJsZSBkYXRhZnJhbWVzDQojIyMgSW5pdGlhbGl6ZSBhbiBlbXB0eSBkYXRhIGZyYW1lIGZvciBvYnNlcnZhdGlvbnMNCmxvZ09ic19ubUc1eXN3X2RmIDwtIGRhdGEuZnJhbWUoYWdlID0gaW50ZWdlcigpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmbGVldCA9IGludGVnZXIoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeWVhciA9IGludGVnZXIoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9nT2JzID0gbnVtZXJpYygpKQ0KDQojIyMgUG9wdWxhdGUgdGhlIGRhdGEgZnJhbWUgZm9yIG9ic2VydmF0aW9ucw0KZm9yIChpIGluIHNlcV9hbG9uZyhsb2dPYnNfbm1HNXlzdykpIHsNCiAgIyBDYWxjdWxhdGUgdGhlIGdyb3VwIGFuZCB5ZWFyDQogIHllYXIgPC0gKChpIC0gMSkgJS8lIDMpICsgMQ0KICBmbGVldCA8LSAoKGkgLSAxKSAlJSAzKSArIDENCiAgDQogICMjIyBDcmVhdGUgYSB0ZW1wb3JhcnkgZGF0YSBmcmFtZSBhbmQgYXBwZW5kIHRvIHRoZSBtYWluIGRhdGEgZnJhbWUgZm9yIG9ic2VydmF0aW9ucw0KICB0ZW1wX2RmIDwtIGRhdGEuZnJhbWUoYWdlID0gMTo3LA0KICAgICAgICAgICAgICAgICAgICAgICAgZmxlZXQgPSBmbGVldCwNCiAgICAgICAgICAgICAgICAgICAgICAgIHllYXIgPSB5ZWFyKzIwMDEsDQogICAgICAgICAgICAgICAgICAgICAgICBsb2dPYnMgPSBsb2dPYnNfbm1HNXlzd1tbaV1dKQ0KICBsb2dPYnNfbm1HNXlzd19kZiA8LSByYmluZChsb2dPYnNfbm1HNXlzd19kZiwgdGVtcF9kZikNCn0NCg0KIyMjIEluaXRpYWxpemUgYW4gZW1wdHkgZGF0YSBmcmFtZSBmb3IgcHJlZGljdGlvbnMNCmxvZ1ByZWRfbm1HNXlzd19kZiA8LSBkYXRhLmZyYW1lKGFnZSA9IGludGVnZXIoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZsZWV0ID0gaW50ZWdlcigpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeWVhciA9IGludGVnZXIoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZ1ByZWQgPSBudW1lcmljKCkpDQoNCiMjIyBQb3B1bGF0ZSB0aGUgZGF0YSBmcmFtZSBmb3IgcHJlZGljdGlvbnMNCmZvciAoaSBpbiBzZXFfYWxvbmcobG9nUHJlZF9ubUc1eXN3KSkgew0KICAjIENhbGN1bGF0ZSB0aGUgZ3JvdXAgYW5kIHllYXINCiAgeWVhciA8LSAoKGkgLSAxKSAlLyUgMykgKyAxDQogIGZsZWV0IDwtICgoaSAtIDEpICUlIDMpICsgMQ0KICANCiAgIyMjIENyZWF0ZSBhIHRlbXBvcmFyeSBkYXRhIGZyYW1lIGFuZCBhcHBlbmQgdG8gdGhlIG1haW4gZGF0YSBmcmFtZSBmb3IgcHJlZGljdGlvbnMNCiAgdGVtcF9kZiA8LSBkYXRhLmZyYW1lKGFnZSA9IDE6NywNCiAgICAgICAgICAgICAgICAgICAgICAgIGZsZWV0ID0gZmxlZXQsDQogICAgICAgICAgICAgICAgICAgICAgICB5ZWFyID0geWVhcisyMDAxLA0KICAgICAgICAgICAgICAgICAgICAgICAgbG9nUHJlZCA9IGxvZ1ByZWRfbm1HNXlzd1tbaV1dKQ0KICBsb2dQcmVkX25tRzV5c3dfZGYgPC0gcmJpbmQobG9nUHJlZF9ubUc1eXN3X2RmLCB0ZW1wX2RmKQ0KfQ0KDQojIyBQbG90DQpsb2dQcmVkX25tRzV5c3dfZGYkYWdlIDwtIGFzLmNoYXJhY3Rlcihsb2dQcmVkX25tRzV5c3dfZGYkYWdlKQ0KbG9nT2JzX25tRzV5c3dfZGYkYWdlIDwtIGFzLmNoYXJhY3Rlcihsb2dPYnNfbm1HNXlzd19kZiRhZ2UpDQoNCmdncGxvdGx5KGdncGxvdCgpKw0KICAgICAgICAgICBnZW9tX3BvaW50KGRhdGEgPSBsb2dPYnNfbm1HNXlzd19kZltsb2dPYnNfbm1HNXlzd19kZiRmbGVldCA9PSAxICYgbG9nT2JzX25tRzV5c3dfZGYkeWVhciAhPSAoRGF0YVllYXIrMSksIF0sDQogICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0geWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBsb2dPYnMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBhZ2UpLA0KICAgICAgICAgICAgICAgICAgICAgIHNoYXBlID0gMjEpICsNCiAgICAgICAgICAgZ2VvbV9saW5lKGRhdGEgPSBsb2dQcmVkX25tRzV5c3dfZGZbbG9nUHJlZF9ubUc1eXN3X2RmJGZsZWV0ID09IDEgJiBsb2dQcmVkX25tRzV5c3dfZGYkeWVhciAhPSAoRGF0YVllYXIrMSksIF0sDQogICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSB5ZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gbG9nUHJlZCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gYWdlKSkgKw0KICAgICAgICAgICBmYWNldF93cmFwKGZhY2V0cyA9ICJhZ2UiKSArICMsIHNjYWxlcyA9ICJmcmVlX3kiKSArDQogICAgICAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBlYnBhbCwgZ3VpZGUgPSBGQUxTRSkgKw0KICAgICAgICAgICBndWlkZXMoY29sb3VyPUZBTFNFLCBzaGFwZT1GQUxTRSkgKw0KICAgICAgICAgICB0aGVtZV9mZXcoKSkNCg0KIyBmaXRwbG90KGZpdF9ubUc1eXN3LCBmbGVldHM9MSkNCmBgYA0KDQpgYGB7ciBmaWcuY2FwPSJNb2RlbCB3aXRoIHRpbWUgdmFyeWluZyAoZml2ZSB5ZWFyIHNsaWlkaW5nIHdpbmRvdyBtZWFuKSwgYWdlIHZhcnlpbmcsIEdpc2xhc29uIG5hdHVyYWwgbW9ydGFsaXRpZXMgZml0IHRvIFExIHN1cnZleSBkYXRhIGJ5IGFnZSAodmFsdWVzIG9uIHRoZSBtb2RlbCBsaW5rIGZ1bmN0aW9uIHNjYWxlKS4ifQ0KZ2dwbG90bHkoZ2dwbG90KCkrDQogICAgICAgICAgIGdlb21fcG9pbnQoZGF0YSA9IGxvZ09ic19ubUc1eXN3X2RmW2xvZ09ic19ubUc1eXN3X2RmJGZsZWV0ID09IDIgJiBsb2dPYnNfbm1HNXlzd19kZiR5ZWFyICE9IChEYXRhWWVhcisxKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSB5ZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGxvZ09icywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IGFnZSksDQogICAgICAgICAgICAgICAgICAgICAgc2hhcGUgPSAyMSkgKw0KICAgICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IGxvZ1ByZWRfbm1HNXlzd19kZltsb2dQcmVkX25tRzV5c3dfZGYkZmxlZXQgPT0gMiAmIGxvZ1ByZWRfbm1HNXlzd19kZiR5ZWFyICE9IChEYXRhWWVhcisxKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IHllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBsb2dQcmVkLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBhZ2UpKSArDQogICAgICAgICAgIGZhY2V0X3dyYXAoZmFjZXRzID0gImFnZSIpICsgIywgc2NhbGVzID0gImZyZWVfeSIpICsNCiAgICAgICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGVicGFsLCBndWlkZSA9IEZBTFNFKSArDQogICAgICAgICAgIGd1aWRlcyhjb2xvdXI9RkFMU0UsIHNoYXBlPUZBTFNFKSArDQogICAgICAgICAgIHRoZW1lX2ZldygpKQ0KIyBmaXRwbG90KGZpdF9ubUc1eXN3LCBmbGVldHM9MikNCmBgYA0KDQpgYGB7ciBmaWcuY2FwPSJNb2RlbCB3aXRoIHRpbWUgdmFyeWluZyAoZml2ZSB5ZWFyIHNsaWlkaW5nIHdpbmRvdyBtZWFuKSwgYWdlIHZhcnlpbmcsIEdpc2xhc29uIG5hdHVyYWwgbW9ydGFsaXRpZXMgZml0IHRvIFEzLzQgc3VydmV5IGRhdGEgYnkgYWdlICh2YWx1ZXMgb24gdGhlIG1vZGVsIGxpbmsgZnVuY3Rpb24gc2NhbGUpLiJ9DQpnZ3Bsb3RseShnZ3Bsb3QoKSsNCiAgICAgICAgICAgZ2VvbV9wb2ludChkYXRhID0gbG9nT2JzX25tRzV5c3dfZGZbbG9nT2JzX25tRzV5c3dfZGYkZmxlZXQgPT0gMyAmIGxvZ09ic19ubUc1eXN3X2RmJHllYXIgIT0gKERhdGFZZWFyKzEpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IHllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gbG9nT2JzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gYWdlKSwNCiAgICAgICAgICAgICAgICAgICAgICBzaGFwZSA9IDIxKSArDQogICAgICAgICAgIGdlb21fbGluZShkYXRhID0gbG9nUHJlZF9ubUc1eXN3X2RmW2xvZ1ByZWRfbm1HNXlzd19kZiRmbGVldCA9PSAzICYgbG9nUHJlZF9ubUc1eXN3X2RmJHllYXIgIT0gKERhdGFZZWFyKzEpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0geWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGxvZ1ByZWQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IGFnZSkpICsNCiAgICAgICAgICAgZmFjZXRfd3JhcChmYWNldHMgPSAiYWdlIikgKyAjLCBzY2FsZXMgPSAiZnJlZV95IikgKw0KICAgICAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gZWJwYWwsIGd1aWRlID0gRkFMU0UpICsNCiAgICAgICAgICAgZ3VpZGVzKGNvbG91cj1GQUxTRSwgc2hhcGU9RkFMU0UpICsNCiAgICAgICAgICAgdGhlbWVfZmV3KCkpDQoNCiMgZml0cGxvdChmaXRfbm1HNXlzdywgZmxlZXRzPTMpDQpgYGANCg0KYGBge3IgZmlnLmNhcD0iU3RhbmRhcmQgRGV2YXRpb25zIGJ5IEZsZWV0OyBHaXNsYXNvbiwgdGltZS12YXJpYW50IG1vcnRhbGl0eSIsIGhlaWdodD0xMH0NCnNkcGxvdChmaXRfbm1HNXlzdywgbWFyZyA9IGMoNSw0LDEsMSkpDQpgYGANCg0KIyMjIFJlc2lkdWFscw0KYGBge3IgY2FsY3VsYXRlUmVzaWR1YWxzX25tRzV5c3csIHdhcm5pbmc9RkFMU0UsIHJlc3VsdHM9J2hpZGUnfQ0KcmVzaWRfbm1HNXlzdyA8LSByZXNpZHVhbHMoZml0X25tRzV5c3cpDQpyZXNpZF9ubUc1eXN3X2RmIDwtIGRhdGEuZnJhbWUoeWVhciA9IHJlc2lkX25tRzV5c3ckeWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmbGVldCA9IHJlc2lkX25tRzV5c3ckZmxlZXQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWdlID0gcmVzaWRfbm1HNXlzdyRhZ2UsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb2JzZXJ2YXRpb24gPSByZXNpZF9ubUc1eXN3JG9ic2VydmF0aW9uLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1lYW4gPSByZXNpZF9ubUc1eXN3JG1lYW4sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzaWR1YWwgPSByZXNpZF9ubUc1eXN3JHJlc2lkdWFsKQ0KcmVzaWRfbm1HNXlzd19kZiRmbGVldE5hbWUgPC0gaWZlbHNlKHJlc2lkX25tRzV5c3dfZGYkZmxlZXQgPT0gMSwgYXR0cmlidXRlcyhyZXNpZF9ubUc1eXN3KSRmbGVldE5hbWVzWzFdLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UocmVzaWRfbm1HNXlzd19kZiRmbGVldCA9PSAyLCBhdHRyaWJ1dGVzKHJlc2lkX25tRzV5c3cpJGZsZWV0TmFtZXNbMl0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UocmVzaWRfbm1HNXlzd19kZiRmbGVldCA9PSAzLCBhdHRyaWJ1dGVzKHJlc2lkX25tRzV5c3cpJGZsZWV0TmFtZXNbM10sIE5BKSkpDQoNCnJlc2lkX25tRzV5c3dfZGYkZmxlZXRBbHROYW1lIDwtIGlmZWxzZShyZXNpZF9ubUc1eXN3X2RmJGZsZWV0ID09IDEsICJSZXNpZHVhbCBGaXNoaW5nIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKHJlc2lkX25tRzV5c3dfZGYkZmxlZXQgPT0gMiwgIlExIFN1cnZleXMiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKHJlc2lkX25tRzV5c3dfZGYkZmxlZXQgPT0gMywgIlEzLzQgU3VydmV5cyIsIE5BKSkpDQpgYGANCg0KYGBge3IgZmlnLmNhcD0iRXN0aW1hdGVkIGNvcnJlbGF0aW9ucyBpbiByZXNpZHVhbCB2YXJpYXRpb24gYmV0d2VlbiBhZ2VzIGZvciBlYWNoIG9mIHRoZSBmaXNoaW5nIGZsZWV0ICh0b3ApIGFuZCB0aGUgdHdvIHN1cnZleXMgKG1pZGRsZSAmIGJvdHRvbSksIGZyb20gdGhlIE1vZGVsIHdpdGggdGltZSB2YXJ5aW5nIChmaXZlIHllYXIgc2xpaWRpbmcgd2luZG93IG1lYW4pLCBhZ2UgdmFyeWluZywgR2lzbGFzb24gbmF0dXJhbCBtb3J0YWxpdGllcy4ifQ0KDQppZighYWxsKGZpdF9ubUc1eXN3JGNvbmYkb2JzQ29yU3RydWN0PT0iSUQiKSl7IA0KICBjb3JwbG90KGZpdF9ubUc1eXN3KQkJCSAgDQogICMgc2V0Y2FwKCJFc3RpbWF0ZWQgY29ycmVsYXRpb25zIiwgIkVzdGltYXRlcyBjb3JyZWxhdGlvbnMgYmV0d2VlbiBhZ2UgZ3JvdXBzIGZvciBlYWNoIGZsZWV0IikNCiAgIyBzdGFtcGl0KGZpdCkNCn0gZWxzZSB7DQogIHByaW50KCJObyBjb3JyZWxhdGlvbiBzdHJ1Y3R1cmUgY29uZmlndXJlZCBmb3IgcmVzaWR1YWxzIGFjcm9zcyBhZ2UuIikNCn0NCg0KYGBgDQoNCmBgYHtyIGZpZy5jYXA9Ik9uZSBvYnNlcnZhdGlvbiBhaGVhZCByZXNpZHVhbHMgZm9yIHRoZSB0aHJlZSBmbGVldHMgKHJlZC9waW5rID0gb2JzZXJ2YXRpb24gbG93ZXIgdGhhbiBtb2RlbCBlc3RpbWF0ZSwgYmx1ZSA9IG9ic2VydmF0aW9uIGhpZ2hlciB0aGFuIG1vZGVsIGVzdGltYXRlLCBzaXplID0gbWFnbml0dWRlIG9mIHJlc2lkdWFsKSwgZnJvbSB0aGUgTW9kZWwgd2l0aCB0aW1lIHZhcnlpbmcgKGZpdmUgeWVhciBzbGlpZGluZyB3aW5kb3cgbWVhbiksIGFnZSB2YXJ5aW5nLCBHaXNsYXNvbiBuYXR1cmFsIG1vcnRhbGl0aWVzLiJ9DQpnZ3Bsb3RseShnZ3Bsb3QocmVzaWRfbm1HNXlzd19kZikgKw0KICAgICAgICAgICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IHllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gYWdlLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IGFicyhyZXNpZHVhbCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSByZXNpZHVhbCA+PSAwKSwNCiAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuNykgKw0KICAgICAgICAgICBmYWNldF9ncmlkKHJvd3MgPSAiZmxlZXRBbHROYW1lIikgKw0KICAgICAgICAgICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoIlRSVUUiID0gZWJwYWxbOF0sICJGQUxTRSIgPSBlYnBhbFs5XSkpICsNCiAgICAgICAgICAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoLTEsIDkpLCBicmVha3MgPSBjKDE6OSkpICsNCiAgICAgICAgICAgZ3VpZGVzKGNvbG91cj1GQUxTRSkgKw0KICAgICAgICAgICB0aGVtZV9mZXcoKSkNCg0KYGBgDQoNCiMjIyMgSml0dGVyaW5nDQpXZSBjYW4gYWxzbyB0ZXN0IHRvIHNlZSBpZiB0aGUgbW9kZWwgaXMgY29udmVyZ2luZyBvbiBzb21lIGxvY2FsIG1pbmltdW0gKGkuZS4gaXQncyBmaXR0aW5nIHRvIHNvbWUgc29sdXRpb24gY2xvc2UgdG8gaW5pdGlhbGlzaW5nIHZhbHVlcyB0aGF0IHJlcHJlc2VudHMgbm9pc2UgYW5kIG5vdCB0aGUgZ2xvYmFsIHNvbHV0aW9uLCB0aGF0IGlzIHRoZSBwcm9wZXIgc29sdXRpb24pLiAgVG8gZG8gdGhpcywgd2UgYWRkIHJhbmRvbSBub2lzZSB0byB0aGUgaW5pdGlhbCBwYXJhbWV0ZXIgdmFsdWVzIHRvIHNlZSBpZiB0aGUgbW9kZWwgd2lsbCBjb252ZXJnZSBvbiBhIGRpZmZlcmVudCBtaW5pbXVtIGluIGl0J3MgZGF0YS1zcGFjZS4gVGhlIGVhc2llc3Qgd2F5IHRvIGludmVzdGlnYXRlIHRoaXMgaXMgdG8gc2VlIGlmIHRoZSBtb2RlbCBmaXRzIHZhcnkgYWxvdCBkZXBlbmRpbmcgb24gdGhlIHN0YXJ0aW5nIHZhbHVlczoNCmBgYHtyIEppdHRlcl9ubUc1eXN3fQ0Kaml0X25tRzV5c3cgPC0gaml0KGZpdCA9IGZpdF9ubUc1eXN3KQ0KDQptdCA8LSBhcy5kYXRhLmZyYW1lKG1vZGVsdGFibGUoaml0X25tRzV5c3cpKQ0KbXQkbW9kZWwgPC0gcm93bmFtZXMobXQpDQpyb3duYW1lcyhtdCkgPC0gTlVMTA0KDQprYWJsZSh4ID0gbXQsDQogICAgICBkaWdpdHMgPSAzLA0KICAgICAgY2FwdGlvbiA9ICJNZWFzdXJlcyBvZiAgZml0IGZvciBhIHNlcmllcyBvZiBtb2RlbCByZWZpdHMgd2l0aCBqaXR0ZXIgYXBwbGllZCB0byB0aGUgaW5wdXQgcGFyYW1ldGVycy4iKQ0KYGBgDQoNCiMjIyMgTGVhdmUtT25lLU91dCBBbmFseXNlcw0KQSBsZWF2ZS1vbmUtb3V0IGFuYWx5c2lzIGlzIGEgZm9ybSBvZiBzZW5zaXRpdml0eSBhbmFseXNpcywgc2hvd2luZyB0aGUgaW1wYWN0IHRoZSBkYXRhIGZyb20gZWFjaCB0dW5pbmcgZmxlZXQgaGFzIG9uIHRoZSBlc3RpbWF0aW9uIG9mIHRoZSBrZXkgdmFyaWFibGVzIGJlaW5nIGVzdGltYXRlZDsgbmFtZWx5IFNTQiwgRiBhbmQgcmVjcnVpdG1lbnQuICANCg0KRmlyc3Qgd2UgbXVzdCBydW4gdGhlIGxlYXZlLW9uZS1vdXQgYW5hbHlzaXMgd2hpY2ggcmVmaXRzIHRoZSBtb2RlbCBpbiB0d28gaXRlcmF0aW9ucywgcmVtb3Zpbmcgb25lIHN1cnZleSBhdCBhIHRpbWUuIFRoZW4gd2UgY2FuIHBsb3QgZWFjaCBvZiB0aGVzZSBuZXcgbW9kZWwgZml0cyBvdmVyIHRoZSBmdWxsIG1vZGVsIHRvIHNlZSB0aGUgaW1wYWN0IHRoZSByZW1vdmFsIG9mIGVhY2ggaGFzLiANCg0KYGBge3IgTGVhdmVPbmVPdXRfbm1HNXlzd30NCkxPX25tRzV5c3cgPC0gbGVhdmVvdXQoZml0X25tRzV5c3cpDQoNCiM9PT0gDQojIEdldCBkYXRhIGZyb20gc2FtIG9iamVjdHMgYW5kIGdlbmVyYXRlIHVzZWFibGUgZGF0YWZyYW1lcw0KIz09PT0NCnExbWF0IDwtIGFzLmRhdGEuZnJhbWUoc3VtbWFyeShMT19ubUc1eXN3JGB3Lm8uIFExSUJUUytCSVRTK0NvZFNEMjEtMjVgKSkNCnEzbWF0IDwtIGFzLmRhdGEuZnJhbWUoc3VtbWFyeShMT19ubUc1eXN3JGB3Lm8uIFEzNElCVFMrQklUUytDb2RTRDIxLTI1YCkpDQoNCg0Kd29xMSA8LSBkYXRhLmZyYW1lKFllYXIgPSBhcy5pbnRlZ2VyKHJvdy5uYW1lcyhzdW1tYXJ5KExPX25tRzV5c3ckYHcuby4gUTFJQlRTK0JJVFMrQ29kU0QyMS0yNWApKSksDQogICAgICAgICAgICAgICAgICAgU1NCID0gcTFtYXQkU1NCLA0KICAgICAgICAgICAgICAgICAgIEZiYXIgPSBxMW1hdCRgRmJhcigzLTUpYCwNCiAgICAgICAgICAgICAgICAgICBSX2FnZTEgPSBxMW1hdCRgUihhZ2UgMSlgLA0KICAgICAgICAgICAgICAgICAgIENhdGNoRXN0ID0gY2F0Y2h0YWJsZShMT19ubUc1eXN3JGB3Lm8uIFExSUJUUytCSVRTK0NvZFNEMjEtMjVgKVssMV0sDQogICAgICAgICAgICAgICAgICAgc2VyaWVzID0gcmVwKCJ3b19RMSIsIHRpbWVzID0gbnJvdyhxMW1hdCkpKQ0KDQp3b3EzNCA8LSBkYXRhLmZyYW1lKFllYXIgPSBhcy5pbnRlZ2VyKHJvdy5uYW1lcyhxM21hdFsoMjAwMjpEYXRhWWVhciktMjAwMSxdKSksDQogICAgICAgICAgICAgICAgICAgIFNTQiA9IHEzbWF0WygyMDAyOkRhdGFZZWFyKS0yMDAxLCAiU1NCIl0sDQogICAgICAgICAgICAgICAgICAgIEZiYXIgPSBxM21hdFsoMjAwMjpEYXRhWWVhciktMjAwMSwiRmJhcigzLTUpIl0sDQogICAgICAgICAgICAgICAgICAgIFJfYWdlMSA9IHEzbWF0WygyMDAyOkRhdGFZZWFyKS0yMDAxLCJSKGFnZSAxKSJdLA0KICAgICAgICAgICAgICAgICAgICBDYXRjaEVzdCA9IGNhdGNodGFibGUoTE9fbm1HNXlzdyRgdy5vLiBRMzRJQlRTK0JJVFMrQ29kU0QyMS0yNWApWywxXSwNCiAgICAgICAgICAgICAgICAgICAgc2VyaWVzID0gcmVwKCJ3b19RMzQiLCB0aW1lcyA9IChucm93KHEzbWF0KS0xKSkpDQoNCg0KYXN1bV9ubUc1eXN3JHNlcmllcyA8LSByZXAoImZ1bGwiLCB0aW1lcyA9IG5yb3coYXN1bV9ubUc1eXN3KSkNCmFzdW1pX25tRzV5c3cgPC0gYXN1bV9ubUc1eXN3WywgYygiWWVhciIsICJTU0IiLCAiRmJhciIsICJSX2FnZTEiLCAiQ2F0Y2hFc3QiICwic2VyaWVzIildDQojPT09PT0NCg0KbG9zdW1fbm1HNXlzdyA8LSByYmluZCh3b3ExLCB3b3EzNCwgYXN1bWlfbm1HNXlzdykNCg0KYGBgDQoNCmBgYHtyIGZpZy5jYXA9IkxlYXZlLW9uZS1vdXQgcmUtZml0cyBmb3IgdGhlIFRpbWUgdmFyeWluZyB3aXRoIGZpdmUgeWVhciBzbGlkaW5nIHdpbmRvdywgR2lzbGFzb24gbmF0dXJhbCBtb3J0YWxpdGllcyAod2l0aG91dCBRMSBzdXJ2ZXkgPSBibHVlLCB3aXRob3V0IFEzLzQgc3VydmV5ID0gcHVycGxlKSwgb3ZlcmxhaW4gd2l0aCBmdWxsIG1vZGVsIGVzdGltYXRlcyAoYmxhY2sgbGluZSBhbmQgZ3JleSByaWJib24pIG9mIFNTQiAodG9wIGxlZnQpLCBGICh0b3AgcmlnaHQpLCBSZWNydWl0bWVudCAoYm90dG9tIGxlZnQpLCBhbmQgY2F0Y2ggKGJvdHRvbSByaWdodDsgb2JzZXJ2YXRpb25zIGFzIHllbGxvdyArKS4ifQ0KIyBzc2JwbG90KExPKQ0KbG9zc2Jfbm1HNXlzdyA8LSBnZ3Bsb3RseShnZ3Bsb3QoKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9saW5lKGRhdGEgPSBsb3N1bV9ubUc1eXN3LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PVNTQiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBzZXJpZXMpKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9yaWJib24oZGF0YSA9IGFzdW1fbm1HNXlzdywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW49U1NCbG93LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1heD1TU0JoaWdoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gImJsYWNrIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMikgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiYmxhY2siLCBlYnBhbFs4OjldKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2NsZWFuKCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKGF4aXMudGl0bGUueS5sZWZ0ID0gZWxlbWVudF90ZXh0KHZqdXN0ID0gLTAuMDUsIGhqdXN0ID0gMC45NSkpKQ0KDQojIEZwbG90KExPKQ0KbG9mX25tRzV5c3cgPC0gZ2dwbG90bHkoZ2dwbG90KCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IGxvc3VtX25tRzV5c3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1GYmFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBzZXJpZXMpKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fcmliYm9uKGRhdGEgPSBhc3VtX25tRzV5c3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW49RmxvdywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4PUZoaWdoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9ICJibGFjayIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4zKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiYmxhY2siLCBlYnBhbFs4OjldKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9jbGVhbigpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWUoYXhpcy50aXRsZS55LmxlZnQgPSBlbGVtZW50X3RleHQodmp1c3QgPSAtMC4wNSwgaGp1c3QgPSAwLjk1KSkpDQoNCiMgcmVjcGxvdChMTykNCmxvcmVjX25tRzV5c3cgPC0gZ2dwbG90bHkoZ2dwbG90KCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fbGluZShkYXRhID0gbG9zdW1fbm1HNXlzdywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1SX2FnZTEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gc2VyaWVzKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fcmliYm9uKGRhdGEgPSBhc3VtX25tRzV5c3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWluPVJsb3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4PVJoaWdoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gImJsYWNrIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMykgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiYmxhY2siLCBlYnBhbFs4OjldKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2NsZWFuKCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKGF4aXMudGl0bGUueS5sZWZ0ID0gZWxlbWVudF90ZXh0KHZqdXN0ID0gLTAuMDUsIGhqdXN0ID0gMC45NSkpKQ0KDQojIENhdGNoIHBsb3QgKExPKQ0KbG9jYV9ubUc1eXN3IDwtIGdncGxvdGx5KGdncGxvdCgpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fbGluZShkYXRhID0gbG9zdW1fbm1HNXlzdywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9Q2F0Y2hFc3QsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBzZXJpZXMpKSsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fcmliYm9uKGRhdGEgPSBhc3VtX25tRzV5c3dbYXN1bV9ubUc1eXN3JFllYXIgIT0gKERhdGFZZWFyKzEpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW49Q2F0Y2hsb3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltYXg9Q2F0Y2hoaWdoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSAiYmxhY2siLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjMpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fcG9pbnQoZGF0YSA9IGFzdW1fbm1HNXlzd1thc3VtX25tRzV5c3ckWWVhciAhPSAoRGF0YVllYXIrMSksIF0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9Q2F0Y2hPYnMpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaGFwZSA9IDMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IGVicGFsWzVdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gZWJwYWxbNV0pICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHlsYWIoIkNhdGNoICh0b25uZXMpIikgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCJibGFjayIsIGVicGFsWzg6OV0pKSsgDQogICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9jbGVhbigpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKGF4aXMudGl0bGUueS5sZWZ0ID0gZWxlbWVudF90ZXh0KHZqdXN0ID0gLTAuMDUsIGhqdXN0ID0gMC45NSkpKQ0KDQpsYXlvdXQoc3VicGxvdChsb3NzYl9ubUc1eXN3LCBsb2Zfbm1HNXlzdywgbG9yZWNfbm1HNXlzdywgbG9jYV9ubUc1eXN3LCBucm93cyA9IDIsIHNoYXJlWCA9IFRSVUUsIHRpdGxlWSA9IFRSVUUpLCBzaG93bGVnZW5kPUZBTFNFKQ0KYGBgDQoNCiMjIyBSZXRyb3NwZWN0aXZlcw0KYGBge3IgY2FsY3VsYXRlUmV0cm9zX25tRzV5c3d9DQojPT09DQojIENyZWF0ZSBkYXRhZnJhbWUgb2YgY3VycmVudCB5ZWFyJ3MgZml0IGZvciBwbG90dGluZw0KIz09PT0NCiMgSUNfYWdnX3RlbXAgPC0gYWdncmVnYXRlKENBVE9OflllYXIsIGljX2NsZWFuW2ljX2NsZWFuJENhdGNoQ2F0ZWdvcnkgJWluJSBjKCJMYW5kaW5ncyIsICJEaXNjYXJkcyIpLCBdLCBGVU4gPSAic3VtIikNCmFzdW1fbm1HNXlzdyA8LSBhcy5kYXRhLmZyYW1lKHN1bW1hcnkoZml0X25tRzV5c3cpKQ0KYXN1bV9ubUc1eXN3JFllYXIgPC0gYXMuaW50ZWdlcihyb3cubmFtZXMoc3VtbWFyeShmaXRfbm1HNXlzdykpKQ0KY3Rfbm1HNXlzdyA8LSBhcy5kYXRhLmZyYW1lKGNhdGNodGFibGUoZml0X25tRzV5c3csIG9icy5zaG93ID0gVFJVRSkpDQpjdF9ubUc1eXN3JFllYXIgPC0gYXMuaW50ZWdlcihyb3duYW1lcyhjdF9ubUc1eXN3KSkNCnJvd25hbWVzKGN0X25tRzV5c3cpIDwtIE5VTEwNCmN0X25tRzV5c3cgPC0gcmJpbmQoY3Rfbm1HNXlzdywgZGF0YS5mcmFtZShFc3RpbWF0ZSA9IE5BLCBMb3c9TkEsIEhpZ2g9TkEsIHNvcC5jYXRjaD1OQSwgWWVhcj1hcy5pbnRlZ2VyKDIwMjQpKSkNCmFzdW1fbm1HNXlzdyA8LSBtZXJnZSh4ID0gYXN1bV9ubUc1eXN3LCB5ID0gY3Rfbm1HNXlzdywgYnkgPSAiWWVhciIpDQpjb2xuYW1lcyhhc3VtX25tRzV5c3cpIDwtIGMoIlllYXIiLCAiUl9hZ2UxIiwgIlJsb3ciLCAiUmhpZ2giLCAiU1NCIiwgIlNTQmxvdyIsICJTU0JoaWdoIiwgIkZiYXIiLCAiRmxvdyIsICJGaGlnaCIsICJDYXRjaEVzdCIsICJDYXRjaGxvdyIsICJDYXRjaGhpZ2giLCAiQ2F0Y2hPYnMiKQ0KDQphc3VtX25tRzV5c3ckc2VyaWVzIDwtIHJlcCgiZnVsbCIsIHRpbWVzID0gbnJvdyhhc3VtX25tRzV5c3cpKQ0KDQojPT09PT0NClJFVFJPX25tRzV5c3c8LXJldHJvKGZpdF9ubUc1eXN3LCB5ZWFyPTUpDQpyaG9fbm1HNXlzdyA8LSBtb2huKFJFVFJPX25tRzV5c3csIGxhZyA9IDEpDQoNCiMjIE1ha2UgUkVUUk9zIGluIGJldHRlciBwbG90dGluZyBmb3JtYXQNCnJldF9ubUc1eXN3X2RmIDwtIGFzdW1fbm1HNXlzd1thc3VtX25tRzV5c3ckWWVhciAhPSBtYXgoYXN1bV9ubUc1eXN3JFllYXIpLCBdDQoNCmZvcihpIGluIDE6bGVuZ3RoKFJFVFJPX25tRzV5c3cpKXsNCiAgdHN1bSA8LSBhcy5kYXRhLmZyYW1lKHN1bW1hcnkoUkVUUk9fbm1HNXlzd1tbaV1dKSkNCiAgdHN1bSRZZWFyIDwtIGFzLmludGVnZXIocm93Lm5hbWVzKHN1bW1hcnkoUkVUUk9fbm1HNXlzd1tbaV1dKSkpDQogIHRzdW0gPC0gY2JpbmQodHN1bSwgY2F0Y2h0YWJsZShSRVRST19ubUc1eXN3W1tpXV0sIG9icy5zaG93ID0gVFJVRSkpDQogIHRzdW0kc2VyaWVzIDwtIGFzLmNoYXJhY3RlcihyZXAoaSwgbnJvdyh0c3VtKSkpDQogIGNvbG5hbWVzKHRzdW0pIDwtIGMoIlJfYWdlMSIsICJSbG93IiwgIlJoaWdoIiwgIlNTQiIsICJTU0Jsb3ciLCAiU1NCaGlnaCIsICJGYmFyIiwgIkZsb3ciLCAiRmhpZ2giLCAiWWVhciIsICJDYXRjaEVzdCIsICJDYXRjaGxvdyIsICJDYXRjaGhpZ2giLCAiQ2F0Y2hPYnMiLCAic2VyaWVzIikNCiAgdHN1bSA8LSB0c3VtW3RzdW0kWWVhciAhPSBtYXgodHN1bSRZZWFyKSwgXQ0KICByZXRfbm1HNXlzd19kZiA8LSByYmluZChyZXRfbm1HNXlzd19kZiwgdHN1bSkNCn0NCnJldF9ubUc1eXN3X2RmJHNlcmllcyA8LSBmYWN0b3IocmV0X25tRzV5c3dfZGYkc2VyaWVzLCBsZXZlbHMgPSBjKCJmdWxsIiwgIjEiLCAiMiIsICIzIiwgIjQiLCAiNSIpKQ0KYGBgDQoNCmBgYHtyIGZpZy5jYXA9IlJldHJvc3BlY3RpdmUgYW5hbHlzZXMgZm9yIFNTQiAodG9wLWxlZnQpLCBGIGZvciBhZ2VzIDMtNSAodG9wLXJpZ2h0KSwgcmVjcnVpdG1lbnQgKGJvdHRvbS1sZWZ0KSwgYW5kIGNhdGNoIChib3R0b20tcmlnaHQpLCBmcm9tIHRoZSBtb2RlbCB1dGlsaXNpbmcgdGltZSB2YXJpYW50ICg1IHllYXIgc2xpZGluZyB3aW5kb3cgbWVhbiksIEdpc2xhc29uIG5hdHVyYWwgbW9ydGFsaXRpZXMuIn0NCiMgc3NicGxvdChSRVRSTykNCnJldHNzYl9ubUc1eXN3IDwtIGxheW91dChnZ3Bsb3RseShnZ3Bsb3QoKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IHJldF9ubUc1eXN3X2RmLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1TU0IsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBzZXJpZXMpKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3JpYmJvbihkYXRhID0gYXN1bV9ubUc1eXN3W2FzdW1fbm1HNXlzdyRZZWFyICE9IG1heChhc3VtX25tRzV5c3ckWWVhciksIF0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1pbj1TU0Jsb3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltYXg9U1NCaGlnaCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gImJsYWNrIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4yKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbm5vdGF0ZShnZW9tID0gInRleHQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IG1heChyZXRfbm1HNXlzd19kZiRTU0JoaWdoKSowLjg1LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeCA9ICgobWF4KHJldF9ubUc1eXN3X2RmJFllYXIpLW1pbihyZXRfbm1HNXlzd19kZiRZZWFyKSkqMC4yMCkrbWluKHJldF9ubUc1eXN3X2RmJFllYXIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSBwYXN0ZTAoIk1vaG4ncyBSaG8gPSAiLCByb3VuZChyaG9fbm1HNXlzd1syXSwgZGlnaXRzID0gMykpKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoImJsYWNrIiwgZWJwYWxbKGxlbmd0aChlYnBhbCktNCk6bGVuZ3RoKGVicGFsKV0pKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9jbGVhbigpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF4aXMudGl0bGUueS5sZWZ0ID0gZWxlbWVudF90ZXh0KHZqdXN0ID0gLTAuMDUsIGhqdXN0ID0gMC45NSkpKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICBzaG93bGVnZW5kID0gRkFMU0UpDQoNCiMgRnBsb3QoUkVUUk8pDQpyZXRmX25tRzV5c3cgPC0gbGF5b3V0KGdncGxvdGx5KGdncGxvdCgpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IHJldF9ubUc1eXN3X2RmLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PUZiYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gc2VyaWVzKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fcmliYm9uKGRhdGEgPSBhc3VtX25tRzV5c3dbYXN1bV9ubUc1eXN3JFllYXIgIT0gbWF4KGFzdW1fbm1HNXlzdyRZZWFyKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW49RmxvdywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltYXg9RmhpZ2gpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSAiYmxhY2siLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4zKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYW5ub3RhdGUoZ2VvbSA9ICJ0ZXh0IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gbWF4KHJldF9ubUc1eXN3X2RmJEZoaWdoKSowLjg1LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHggPSAoKG1heChyZXRfbm1HNXlzd19kZiRZZWFyKS1taW4ocmV0X25tRzV5c3dfZGYkWWVhcikpKjAuODApK21pbihyZXRfbm1HNXlzd19kZiRZZWFyKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbCA9IHBhc3RlMCgiTW9obidzIFJobyA9ICIsIHJvdW5kKHJob19ubUc1eXN3WzNdLCBkaWdpdHMgPSAzKSkpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoImJsYWNrIiwgZWJwYWxbKGxlbmd0aChlYnBhbCktNCk6bGVuZ3RoKGVicGFsKV0pKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWVfY2xlYW4oKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF4aXMudGl0bGUueS5sZWZ0ID0gZWxlbWVudF90ZXh0KHZqdXN0ID0gLTAuMDUsIGhqdXN0ID0gMC45NSkpKSwNCiAgICAgICAgICAgICAgICAgICAgICAgc2hvd2xlZ2VuZCA9IEZBTFNFKQ0KDQojIHJlY3Bsb3QoUkVUUk8pDQpyZXRyZWNfbm1HNXlzdyA8LSBsYXlvdXQoZ2dwbG90bHkoZ2dwbG90KCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9saW5lKGRhdGEgPSByZXRfbm1HNXlzd19kZiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9Ul9hZ2UxLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gc2VyaWVzKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9yaWJib24oZGF0YSA9IGFzdW1fbm1HNXlzd1thc3VtX25tRzV5c3ckWWVhciAhPSBtYXgoYXN1bV9ubUc1eXN3JFllYXIpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW49UmxvdywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1heD1SaGlnaCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gImJsYWNrIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4zKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbm5vdGF0ZShnZW9tID0gInRleHQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT0gbWF4KHJldF9ubUc1eXN3X2RmJFJoaWdoKSowLjg1LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeCA9ICgobWF4KHJldF9ubUc1eXN3X2RmJFllYXIpLW1pbihyZXRfbm1HNXlzd19kZiRZZWFyKSkqMC4yMCkrbWluKHJldF9ubUc1eXN3X2RmJFllYXIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSBwYXN0ZTAoIk1vaG4ncyBSaG8gPSAiLCByb3VuZChyaG9fbm1HNXlzd1sxXSwgZGlnaXRzID0gMykpKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoImJsYWNrIiwgZWJwYWxbKGxlbmd0aChlYnBhbCktNCk6bGVuZ3RoKGVicGFsKV0pKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9jbGVhbigpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF4aXMudGl0bGUueS5sZWZ0ID0gZWxlbWVudF90ZXh0KHZqdXN0ID0gLTAuMDUsIGhqdXN0ID0gMC45NSkpKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICBzaG93bGVnZW5kID0gRkFMU0UpDQoNCiMgQ2F0Y2ggcGxvdCAoUkVUUk8pDQpyZXRjYV9ubUc1eXN3IDwtIGdncGxvdGx5KGdncGxvdCgpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IHJldF9ubUc1eXN3X2RmLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PUNhdGNoRXN0LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IHNlcmllcykpKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fcmliYm9uKGRhdGEgPSBhc3VtX25tRzV5c3dbYXN1bV9ubUc1eXN3JFllYXIgIT0gbWF4KGFzdW1fbm1HNXlzdyRZZWFyKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW49Q2F0Y2hsb3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4PUNhdGNoaGlnaCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9ICJibGFjayIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjMpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3BvaW50KGRhdGEgPSBhc3VtX25tRzV5c3dbYXN1bV9ubUc1eXN3JFllYXIgIT0gbWF4KGFzdW1fbm1HNXlzdyRZZWFyKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PUNhdGNoT2JzKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNoYXBlID0gMywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IGVicGFsWzVdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IGVicGFsWzVdKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgeWxhYigiQ2F0Y2ggKHRvbm5lcykiKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCJibGFjayIsIGVicGFsWyhsZW5ndGgoZWJwYWwpLTQpOmxlbmd0aChlYnBhbCldKSkrIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2NsZWFuKCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKGF4aXMudGl0bGUueS5sZWZ0ID0gZWxlbWVudF90ZXh0KHZqdXN0ID0gLTAuMDUsIGhqdXN0ID0gMC45NSkpKQ0KDQpyZXRfZnAgPC0gc3R5bGUoc3VicGxvdChyZXRzc2Jfbm1HNXlzdywgcmV0Zl9ubUc1eXN3LCByZXRyZWNfbm1HNXlzdywgcmV0Y2Ffbm1HNXlzdywgbnJvd3MgPSAyLCBzaGFyZVggPSBGQUxTRSwgc2hhcmVZID0gRkFMU0UsIHRpdGxlWSA9IFRSVUUpLA0KICAgICAgICAgICAgICAgIHNob3dsZWdlbmQ9RkFMU0UsDQogICAgICAgICAgICAgICAgdHJhY2VzID0gYyg4OigoNyo0KSsyKSkpDQoNCmxheW91dChyZXRfZnAsIGxlZ2VuZCA9IGxpc3Qob3JpZW50YXRpb24gPSAnaCcsIHggPSAwLjUsIHhhbmNob3IgPSAnY2VudGVyJywgeSA9IC0wLjA1LCB5YW5jaG9yID0gJ3RvcCcsIGJvcmRlcndpZHRoID0gMCkpDQpgYGANCiMgTW9kZWxzIHdpdGggTmV3IE5hdHVyYWwgTW9ydGFsaXRpZXMgSW5mb3JtZWQgYnkgRmlzaEJhc2UgR3Jvd3RoIHBhcmFtZXRlcnMNCiMjIFRpbWUgSW52YXJpYW50LCBHaXNsYXNvbiBOYXR1cmFsIE1vcnRhbGl0eSBGcm9tIEZpc2hCYXNlDQojIyMgRml0cyB0byBkYXRhDQpgYGB7ciBubUdGYkZpdEZyb21XZWJ9DQpmaXRfbm1HRmIgPC0gZml0ZnJvbXdlYigicGxlLjI3LjIxLTMyX1dLQlBMQUlDRV8yMDI0X0Jpb1BhcnN3X1NWX25tR0ZiIikNCmBgYA0KDQpgYGB7ciBkYXRhZnJhbWVTdW1tYXJ5X25tR0ZiLCByZXN1bHRzPSdoaWRlJywgZmlnLnNob3c9J2hpZGUnfQ0KIz09PQ0KIyBDcmVhdGUgZGF0YWZyYW1lIG9mIGN1cnJlbnQgeWVhcidzIGZpdCBmb3IgcGxvdHRpbmcNCiM9PT09DQphc3VtX25tR0ZiIDwtIGFzLmRhdGEuZnJhbWUoc3VtbWFyeShmaXRfbm1HRmIpKQ0KYXN1bV9ubUdGYiRZZWFyIDwtIGFzLmludGVnZXIocm93Lm5hbWVzKHN1bW1hcnkoZml0X25tR0ZiKSkpDQpjdF9ubUdGYiA8LSBhcy5kYXRhLmZyYW1lKGNhdGNodGFibGUoZml0X25tR0ZiLCBvYnMuc2hvdyA9IFRSVUUpKQ0KY3Rfbm1HRmIkWWVhciA8LSBhcy5pbnRlZ2VyKHJvd25hbWVzKGN0X25tR0ZiKSkNCnJvd25hbWVzKGN0X25tR0ZiKSA8LSBOVUxMDQpjdF9ubUdGYiA8LSByYmluZChjdF9ubUdGYiwgZGF0YS5mcmFtZShFc3RpbWF0ZSA9IE5BLCBMb3c9TkEsIEhpZ2g9TkEsIHNvcC5jYXRjaD1OQSwgWWVhcj1hcy5pbnRlZ2VyKDIwMjQpKSkNCmFzdW1fbm1HRmIgPC0gbWVyZ2UoeCA9IGFzdW1fbm1HRmIsIHkgPSBjdF9ubUdGYiwgYnkgPSAiWWVhciIpDQpjb2xuYW1lcyhhc3VtX25tR0ZiKSA8LSBjKCJZZWFyIiwgIlJfYWdlMSIsICJSbG93IiwgIlJoaWdoIiwgIlNTQiIsICJTU0Jsb3ciLCAiU1NCaGlnaCIsICJGYmFyIiwgIkZsb3ciLCAiRmhpZ2giLCAiQ2F0Y2hFc3QiLCAiQ2F0Y2hsb3ciLCAiQ2F0Y2hoaWdoIiwgIkNhdGNoT2JzIikNCiM9PT09PQ0KYGBgDQoNCldoZW4gdGhlIG1vZGVsIGlzIHJ1biB3ZSBjYW4gZWFzaWx5IHNlZSBmcm9tIHdhcm5pbmdzL2Vycm9ycyBpZiB0aGVyZSBpcyBhIGNvbnZlcmdlbmNlIGlzc3VlLiAgSG93ZXZlciwgd2UgY2FuIGFsc28gY29uZmlybSB0aGlzLCBleHBsaWNpdGx5Og0KLSBUaGUgZmluYWwgbW9kZWwgZ3JhZGllbnQ6IGByIGZpdF9ubUdGYiRvcHQkZXZhbHVhdGlvbnNbMl1gDQotIFRoYXQgdGhlcmUgaXMgYSBwb3NpdGl2ZSBkZWZpbml0ZSBoZXNzaWFuOiBgciBhbGwoZWlnZW4oZml0X25tR0ZiJG9wdCRoZSkkdmFsdWVzID4wKWANCg0KRnVydGhlcm1vcmUsIFNBTSBkb2VzIG5vdCB1dGlsaXNlICJib3VuZHMiIHdoZW4gZml0dGluZyB0aGUgbW9kZWwsIGFuZCB0aGVyZWZvcmUsIGFzIHN0YW5kYXJkIGNoZWNrIG9mIHdoZXRoZXIgbW9kZWwgcGFyYW1ldGVycyBhcmUgYXBwcm9hY2hpbmcgdGhlaXIgYm91bmRzIGlzIGlycmVsZXZhbnQuDQoNCmBgYHtyIGZpZy5jYXA9Ik1vZGVsIHdpdGggdGltZSBpbnZhcmlhbnQgR2lzbGFzb24gbmF0dXJhbCBtb3J0YWxpdGllcyAoRmlzaEJhc2UpIGZpdCB0byBjYXRjaCBkYXRhIGJ5IGFnZSAodmFsdWVzIG9uIHRoZSBtb2RlbCBsaW5rIGZ1bmN0aW9uIHNjYWxlKS4ifQ0KIyMgRXh0cmFjdCBkYXRhIGZyb20gbW9kZWwgb2JqZWN0DQpsb2dPYnNfbm1HRmIgPC0gc3BsaXQoZml0X25tR0ZiJGRhdGEkbG9nb2JzLCBjZWlsaW5nKHNlcV9hbG9uZyhmaXRfbm1HRmIkZGF0YSRsb2dvYnMpL2ZpdF9ubUdGYiRkYXRhJG1heEFnZVBlckZsZWV0WzFdKSkNCmxvZ1ByZWRfbm1HRmIgPC0gc3BsaXQoZml0X25tR0ZiJHJlcCRwcmVkT2JzLCBjZWlsaW5nKHNlcV9hbG9uZyhmaXRfbm1HRmIkcmVwJHByZWRPYnMpL2ZpdF9ubUdGYiRkYXRhJG1heEFnZVBlckZsZWV0WzFdKSkNCg0KIyMgVHJhbnNmb3JtIGRhdGEgdG8gdXNlYWJsZSBkYXRhZnJhbWVzDQojIyMgSW5pdGlhbGl6ZSBhbiBlbXB0eSBkYXRhIGZyYW1lIGZvciBvYnNlcnZhdGlvbnMNCmxvZ09ic19ubUdGYl9kZiA8LSBkYXRhLmZyYW1lKGFnZSA9IGludGVnZXIoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZsZWV0ID0gaW50ZWdlcigpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeWVhciA9IGludGVnZXIoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZ09icyA9IG51bWVyaWMoKSkNCg0KIyMjIFBvcHVsYXRlIHRoZSBkYXRhIGZyYW1lIGZvciBvYnNlcnZhdGlvbnMNCmZvciAoaSBpbiBzZXFfYWxvbmcobG9nT2JzX25tR0ZiKSkgew0KICAjIENhbGN1bGF0ZSB0aGUgZ3JvdXAgYW5kIHllYXINCiAgeWVhciA8LSAoKGkgLSAxKSAlLyUgMykgKyAxDQogIGZsZWV0IDwtICgoaSAtIDEpICUlIDMpICsgMQ0KICANCiAgIyMjIENyZWF0ZSBhIHRlbXBvcmFyeSBkYXRhIGZyYW1lIGFuZCBhcHBlbmQgdG8gdGhlIG1haW4gZGF0YSBmcmFtZSBmb3Igb2JzZXJ2YXRpb25zDQogIHRlbXBfZGYgPC0gZGF0YS5mcmFtZShhZ2UgPSAxOjcsDQogICAgICAgICAgICAgICAgICAgICAgICBmbGVldCA9IGZsZWV0LA0KICAgICAgICAgICAgICAgICAgICAgICAgeWVhciA9IHllYXIrMjAwMSwNCiAgICAgICAgICAgICAgICAgICAgICAgIGxvZ09icyA9IGxvZ09ic19ubUdGYltbaV1dKQ0KICBsb2dPYnNfbm1HRmJfZGYgPC0gcmJpbmQobG9nT2JzX25tR0ZiX2RmLCB0ZW1wX2RmKQ0KfQ0KDQojIyMgSW5pdGlhbGl6ZSBhbiBlbXB0eSBkYXRhIGZyYW1lIGZvciBwcmVkaWN0aW9ucw0KbG9nUHJlZF9ubUdGYl9kZiA8LSBkYXRhLmZyYW1lKGFnZSA9IGludGVnZXIoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmbGVldCA9IGludGVnZXIoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ZWFyID0gaW50ZWdlcigpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZ1ByZWQgPSBudW1lcmljKCkpDQoNCiMjIyBQb3B1bGF0ZSB0aGUgZGF0YSBmcmFtZSBmb3IgcHJlZGljdGlvbnMNCmZvciAoaSBpbiBzZXFfYWxvbmcobG9nUHJlZF9ubUdGYikpIHsNCiAgIyBDYWxjdWxhdGUgdGhlIGdyb3VwIGFuZCB5ZWFyDQogIHllYXIgPC0gKChpIC0gMSkgJS8lIDMpICsgMQ0KICBmbGVldCA8LSAoKGkgLSAxKSAlJSAzKSArIDENCiAgDQogICMjIyBDcmVhdGUgYSB0ZW1wb3JhcnkgZGF0YSBmcmFtZSBhbmQgYXBwZW5kIHRvIHRoZSBtYWluIGRhdGEgZnJhbWUgZm9yIHByZWRpY3Rpb25zDQogIHRlbXBfZGYgPC0gZGF0YS5mcmFtZShhZ2UgPSAxOjcsDQogICAgICAgICAgICAgICAgICAgICAgICBmbGVldCA9IGZsZWV0LA0KICAgICAgICAgICAgICAgICAgICAgICAgeWVhciA9IHllYXIrMjAwMSwNCiAgICAgICAgICAgICAgICAgICAgICAgIGxvZ1ByZWQgPSBsb2dQcmVkX25tR0ZiW1tpXV0pDQogIGxvZ1ByZWRfbm1HRmJfZGYgPC0gcmJpbmQobG9nUHJlZF9ubUdGYl9kZiwgdGVtcF9kZikNCn0NCg0KIyMgUGxvdA0KbG9nUHJlZF9ubUdGYl9kZiRhZ2UgPC0gYXMuY2hhcmFjdGVyKGxvZ1ByZWRfbm1HRmJfZGYkYWdlKQ0KbG9nT2JzX25tR0ZiX2RmJGFnZSA8LSBhcy5jaGFyYWN0ZXIobG9nT2JzX25tR0ZiX2RmJGFnZSkNCg0KZ2dwbG90bHkoZ2dwbG90KCkrDQogICAgICAgICAgIGdlb21fcG9pbnQoZGF0YSA9IGxvZ09ic19ubUdGYl9kZltsb2dPYnNfbm1HRmJfZGYkZmxlZXQgPT0gMSAmIGxvZ09ic19ubUdGYl9kZiR5ZWFyICE9IChEYXRhWWVhcisxKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSB5ZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGxvZ09icywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IGFnZSksDQogICAgICAgICAgICAgICAgICAgICAgc2hhcGUgPSAyMSkgKw0KICAgICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IGxvZ1ByZWRfbm1HRmJfZGZbbG9nUHJlZF9ubUdGYl9kZiRmbGVldCA9PSAxICYgbG9nUHJlZF9ubUdGYl9kZiR5ZWFyICE9IChEYXRhWWVhcisxKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IHllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBsb2dQcmVkLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBhZ2UpKSArDQogICAgICAgICAgIGZhY2V0X3dyYXAoZmFjZXRzID0gImFnZSIpICsgIywgc2NhbGVzID0gImZyZWVfeSIpICsNCiAgICAgICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGVicGFsLCBndWlkZSA9IEZBTFNFKSArDQogICAgICAgICAgIGd1aWRlcyhjb2xvdXI9RkFMU0UsIHNoYXBlPUZBTFNFKSArDQogICAgICAgICAgIHRoZW1lX2ZldygpKQ0KDQojIGZpdHBsb3QoZml0X25tR0ZiLCBmbGVldHM9MSkNCmBgYA0KDQpgYGB7ciBmaWcuY2FwPSJNb2RlbCB3aXRoIHRpbWUgaW52YXJpYW50IEdpc2xhc29uIG5hdHVyYWwgbW9ydGFsaXRpZXMgKEZpc2hCYXNlKSBmaXQgdG8gUTEgc3VydmV5IGRhdGEgYnkgYWdlICh2YWx1ZXMgb24gdGhlIG1vZGVsIGxpbmsgZnVuY3Rpb24gc2NhbGUpLiJ9DQpnZ3Bsb3RseShnZ3Bsb3QoKSsNCiAgICAgICAgICAgZ2VvbV9wb2ludChkYXRhID0gbG9nT2JzX25tR0ZiX2RmW2xvZ09ic19ubUdGYl9kZiRmbGVldCA9PSAyICYgbG9nT2JzX25tR0ZiX2RmJHllYXIgIT0gKERhdGFZZWFyKzEpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IHllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gbG9nT2JzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gYWdlKSwNCiAgICAgICAgICAgICAgICAgICAgICBzaGFwZSA9IDIxKSArDQogICAgICAgICAgIGdlb21fbGluZShkYXRhID0gbG9nUHJlZF9ubUdGYl9kZltsb2dQcmVkX25tR0ZiX2RmJGZsZWV0ID09IDIgJiBsb2dQcmVkX25tR0ZiX2RmJHllYXIgIT0gKERhdGFZZWFyKzEpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0geWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGxvZ1ByZWQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IGFnZSkpICsNCiAgICAgICAgICAgZmFjZXRfd3JhcChmYWNldHMgPSAiYWdlIikgKyAjLCBzY2FsZXMgPSAiZnJlZV95IikgKw0KICAgICAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gZWJwYWwsIGd1aWRlID0gRkFMU0UpICsNCiAgICAgICAgICAgZ3VpZGVzKGNvbG91cj1GQUxTRSwgc2hhcGU9RkFMU0UpICsNCiAgICAgICAgICAgdGhlbWVfZmV3KCkpDQojIGZpdHBsb3QoZml0X25tR0ZiLCBmbGVldHM9MikNCmBgYA0KDQpgYGB7ciBmaWcuY2FwPSJNb2RlbCB3aXRoIHRpbWUgaW52YXJpYW50IEdpc2xhc29uIG5hdHVyYWwgbW9ydGFsaXRpZXMgKEZpc2hCYXNlKSBmaXQgdG8gUTMvNCBzdXJ2ZXkgZGF0YSBieSBhZ2UgKHZhbHVlcyBvbiB0aGUgbW9kZWwgbGluayBmdW5jdGlvbiBzY2FsZSkuIn0NCmdncGxvdGx5KGdncGxvdCgpKw0KICAgICAgICAgICBnZW9tX3BvaW50KGRhdGEgPSBsb2dPYnNfbm1HRmJfZGZbbG9nT2JzX25tR0ZiX2RmJGZsZWV0ID09IDMgJiBsb2dPYnNfbm1HRmJfZGYkeWVhciAhPSAoRGF0YVllYXIrMSksIF0sDQogICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0geWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBsb2dPYnMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBhZ2UpLA0KICAgICAgICAgICAgICAgICAgICAgIHNoYXBlID0gMjEpICsNCiAgICAgICAgICAgZ2VvbV9saW5lKGRhdGEgPSBsb2dQcmVkX25tR0ZiX2RmW2xvZ1ByZWRfbm1HRmJfZGYkZmxlZXQgPT0gMyAmIGxvZ1ByZWRfbm1HRmJfZGYkeWVhciAhPSAoRGF0YVllYXIrMSksIF0sDQogICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSB5ZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gbG9nUHJlZCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gYWdlKSkgKw0KICAgICAgICAgICBmYWNldF93cmFwKGZhY2V0cyA9ICJhZ2UiKSArICMsIHNjYWxlcyA9ICJmcmVlX3kiKSArDQogICAgICAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBlYnBhbCwgZ3VpZGUgPSBGQUxTRSkgKw0KICAgICAgICAgICBndWlkZXMoY29sb3VyPUZBTFNFLCBzaGFwZT1GQUxTRSkgKw0KICAgICAgICAgICB0aGVtZV9mZXcoKSkNCg0KIyBmaXRwbG90KGZpdF9ubUdGYiwgZmxlZXRzPTMpDQpgYGANCg0KYGBge3IgZmlnLmNhcD0iU3RhbmRhcmQgRGV2YXRpb25zIGJ5IEZsZWV0OyBHaXNsYXNvbiwgdGltZS1pbnZhcmlhbnQgbW9ydGFsaXR5IChGaXNoQmFzZSkiLCBoZWlnaHQ9MTB9DQpzZHBsb3QoZml0X25tR0ZiLCBtYXJnID0gYyg1LDQsMSwxKSkNCmBgYA0KDQojIyMgUmVzaWR1YWxzDQpgYGB7ciBjYWxjdWxhdGVSZXNpZHVhbHNfbm1HRmIsIHdhcm5pbmc9RkFMU0UsIHJlc3VsdHM9J2hpZGUnfQ0KcmVzaWRfbm1HRmIgPC0gcmVzaWR1YWxzKGZpdF9ubUdGYikNCnJlc2lkX25tR0ZiX2RmIDwtIGRhdGEuZnJhbWUoeWVhciA9IHJlc2lkX25tR0ZiJHllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZsZWV0ID0gcmVzaWRfbm1HRmIkZmxlZXQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFnZSA9IHJlc2lkX25tR0ZiJGFnZSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb2JzZXJ2YXRpb24gPSByZXNpZF9ubUdGYiRvYnNlcnZhdGlvbiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWVhbiA9IHJlc2lkX25tR0ZiJG1lYW4sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc2lkdWFsID0gcmVzaWRfbm1HRmIkcmVzaWR1YWwpDQpyZXNpZF9ubUdGYl9kZiRmbGVldE5hbWUgPC0gaWZlbHNlKHJlc2lkX25tR0ZiX2RmJGZsZWV0ID09IDEsIGF0dHJpYnV0ZXMocmVzaWRfbm1HRmIpJGZsZWV0TmFtZXNbMV0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UocmVzaWRfbm1HRmJfZGYkZmxlZXQgPT0gMiwgYXR0cmlidXRlcyhyZXNpZF9ubUdGYikkZmxlZXROYW1lc1syXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UocmVzaWRfbm1HRmJfZGYkZmxlZXQgPT0gMywgYXR0cmlidXRlcyhyZXNpZF9ubUdGYikkZmxlZXROYW1lc1szXSwgTkEpKSkNCg0KcmVzaWRfbm1HRmJfZGYkZmxlZXRBbHROYW1lIDwtIGlmZWxzZShyZXNpZF9ubUdGYl9kZiRmbGVldCA9PSAxLCAiUmVzaWR1YWwgRmlzaGluZyIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UocmVzaWRfbm1HRmJfZGYkZmxlZXQgPT0gMiwgIlExIFN1cnZleXMiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShyZXNpZF9ubUdGYl9kZiRmbGVldCA9PSAzLCAiUTMvNCBTdXJ2ZXlzIiwgTkEpKSkNCmBgYA0KDQpgYGB7ciBmaWcuY2FwPSJFc3RpbWF0ZWQgY29ycmVsYXRpb25zIGluIHJlc2lkdWFsIHZhcmlhdGlvbiBiZXR3ZWVuIGFnZXMgZm9yIGVhY2ggb2YgdGhlIGZpc2hpbmcgZmxlZXQgKHRvcCkgYW5kIHRoZSB0d28gc3VydmV5cyAobWlkZGxlICYgYm90dG9tKSwgZnJvbSB0aGUgbW9kZWwgd2l0aCB0aW1lIGludmFyaWFudCBHaXNsYXNvbiBuYXR1cmFsIG1vcnRhbGl0aWVzIChGaXNoQmFzZSkuIn0NCg0KaWYoIWFsbChmaXRfbm1HRmIkY29uZiRvYnNDb3JTdHJ1Y3Q9PSJJRCIpKXsgDQogIGNvcnBsb3QoZml0X25tR0ZiKQkJCSAgDQogICMgc2V0Y2FwKCJFc3RpbWF0ZWQgY29ycmVsYXRpb25zIiwgIkVzdGltYXRlcyBjb3JyZWxhdGlvbnMgYmV0d2VlbiBhZ2UgZ3JvdXBzIGZvciBlYWNoIGZsZWV0IikNCiAgIyBzdGFtcGl0KGZpdCkNCn0gZWxzZSB7DQogIHByaW50KCJObyBjb3JyZWxhdGlvbiBzdHJ1Y3R1cmUgY29uZmlndXJlZCBmb3IgcmVzaWR1YWxzIGFjcm9zcyBhZ2UuIikNCn0NCg0KYGBgDQoNCmBgYHtyIGZpZy5jYXA9Ik9uZSBvYnNlcnZhdGlvbiBhaGVhZCByZXNpZHVhbHMgZm9yIHRoZSB0aHJlZSBmbGVldHMgKHJlZC9waW5rID0gb2JzZXJ2YXRpb24gbG93ZXIgdGhhbiBtb2RlbCBlc3RpbWF0ZSwgYmx1ZSA9IG9ic2VydmF0aW9uIGhpZ2hlciB0aGFuIG1vZGVsIGVzdGltYXRlLCBzaXplID0gbWFnbml0dWRlIG9mIHJlc2lkdWFsKSwgZnJvbSB0aGUgbW9kZWwgd2l0aCB0aW1lIGludmFyaWFudCBHaXNsYXNvbiBuYXR1cmFsIG1vcnRhbGl0aWVzIChGaXNoQmFzZSkuIn0NCmdncGxvdGx5KGdncGxvdChyZXNpZF9ubUdGYl9kZikgKw0KICAgICAgICAgICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IHllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gYWdlLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IGFicyhyZXNpZHVhbCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSByZXNpZHVhbCA+PSAwKSwNCiAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuNykgKw0KICAgICAgICAgICBmYWNldF9ncmlkKHJvd3MgPSAiZmxlZXRBbHROYW1lIikgKw0KICAgICAgICAgICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoIlRSVUUiID0gZWJwYWxbOF0sICJGQUxTRSIgPSBlYnBhbFs5XSkpICsNCiAgICAgICAgICAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoLTEsIDkpLCBicmVha3MgPSBjKDE6OSkpICsNCiAgICAgICAgICAgZ3VpZGVzKGNvbG91cj1GQUxTRSkgKw0KICAgICAgICAgICB0aGVtZV9mZXcoKSkNCg0KYGBgDQoNCiMjIyMgSml0dGVyaW5nDQpXZSBjYW4gYWxzbyB0ZXN0IHRvIHNlZSBpZiB0aGUgbW9kZWwgaXMgY29udmVyZ2luZyBvbiBzb21lIGxvY2FsIG1pbmltdW0gKGkuZS4gaXQncyBmaXR0aW5nIHRvIHNvbWUgc29sdXRpb24gY2xvc2UgdG8gaW5pdGlhbGlzaW5nIHZhbHVlcyB0aGF0IHJlcHJlc2VudHMgbm9pc2UgYW5kIG5vdCB0aGUgZ2xvYmFsIHNvbHV0aW9uLCB0aGF0IGlzIHRoZSBwcm9wZXIgc29sdXRpb24pLiAgVG8gZG8gdGhpcywgd2UgYWRkIHJhbmRvbSBub2lzZSB0byB0aGUgaW5pdGlhbCBwYXJhbWV0ZXIgdmFsdWVzIHRvIHNlZSBpZiB0aGUgbW9kZWwgd2lsbCBjb252ZXJnZSBvbiBhIGRpZmZlcmVudCBtaW5pbXVtIGluIGl0J3MgZGF0YS1zcGFjZS4gVGhlIGVhc2llc3Qgd2F5IHRvIGludmVzdGlnYXRlIHRoaXMgaXMgdG8gc2VlIGlmIHRoZSBtb2RlbCBmaXRzIHZhcnkgYWxvdCBkZXBlbmRpbmcgb24gdGhlIHN0YXJ0aW5nIHZhbHVlczoNCmBgYHtyIEppdHRlcl9ubUdGYn0NCmppdF9ubUdGYiA8LSBqaXQoZml0ID0gZml0X25tR0ZiKQ0KDQptdCA8LSBhcy5kYXRhLmZyYW1lKG1vZGVsdGFibGUoaml0X25tR0ZiKSkNCm10JG1vZGVsIDwtIHJvd25hbWVzKG10KQ0Kcm93bmFtZXMobXQpIDwtIE5VTEwNCg0Ka2FibGUoeCA9IG10LA0KICAgICAgZGlnaXRzID0gMywNCiAgICAgIGNhcHRpb24gPSAiTWVhc3VyZXMgb2YgIGZpdCBmb3IgYSBzZXJpZXMgb2YgbW9kZWwgcmVmaXRzIHdpdGggaml0dGVyIGFwcGxpZWQgdG8gdGhlIGlucHV0IHBhcmFtZXRlcnMuIikNCmBgYA0KDQojIyMjIExlYXZlLU9uZS1PdXQgQW5hbHlzZXMNCkEgbGVhdmUtb25lLW91dCBhbmFseXNpcyBpcyBhIGZvcm0gb2Ygc2Vuc2l0aXZpdHkgYW5hbHlzaXMsIHNob3dpbmcgdGhlIGltcGFjdCB0aGUgZGF0YSBmcm9tIGVhY2ggdHVuaW5nIGZsZWV0IGhhcyBvbiB0aGUgZXN0aW1hdGlvbiBvZiB0aGUga2V5IHZhcmlhYmxlcyBiZWluZyBlc3RpbWF0ZWQ7IG5hbWVseSBTU0IsIEYgYW5kIHJlY3J1aXRtZW50LiAgDQoNCkZpcnN0IHdlIG11c3QgcnVuIHRoZSBsZWF2ZS1vbmUtb3V0IGFuYWx5c2lzIHdoaWNoIHJlZml0cyB0aGUgbW9kZWwgaW4gdHdvIGl0ZXJhdGlvbnMsIHJlbW92aW5nIG9uZSBzdXJ2ZXkgYXQgYSB0aW1lLiBUaGVuIHdlIGNhbiBwbG90IGVhY2ggb2YgdGhlc2UgbmV3IG1vZGVsIGZpdHMgb3ZlciB0aGUgZnVsbCBtb2RlbCB0byBzZWUgdGhlIGltcGFjdCB0aGUgcmVtb3ZhbCBvZiBlYWNoIGhhcy4gDQoNCmBgYHtyIExlYXZlT25lT3V0X25tR0ZifQ0KTE9fbm1HRmIgPC0gbGVhdmVvdXQoZml0X25tR0ZiKQ0KDQojPT09IA0KIyBHZXQgZGF0YSBmcm9tIHNhbSBvYmplY3RzIGFuZCBnZW5lcmF0ZSB1c2VhYmxlIGRhdGFmcmFtZXMNCiM9PT09DQpxMW1hdCA8LSBhcy5kYXRhLmZyYW1lKHN1bW1hcnkoTE9fbm1HRmIkYHcuby4gUTFJQlRTK0JJVFMrQ29kU0QyMS0yNWApKQ0KcTNtYXQgPC0gYXMuZGF0YS5mcmFtZShzdW1tYXJ5KExPX25tR0ZiJGB3Lm8uIFEzNElCVFMrQklUUytDb2RTRDIxLTI1YCkpDQoNCg0Kd29xMSA8LSBkYXRhLmZyYW1lKFllYXIgPSBhcy5pbnRlZ2VyKHJvdy5uYW1lcyhzdW1tYXJ5KExPX25tR0ZiJGB3Lm8uIFExSUJUUytCSVRTK0NvZFNEMjEtMjVgKSkpLA0KICAgICAgICAgICAgICAgICAgIFNTQiA9IHExbWF0JFNTQiwNCiAgICAgICAgICAgICAgICAgICBGYmFyID0gcTFtYXQkYEZiYXIoMy01KWAsDQogICAgICAgICAgICAgICAgICAgUl9hZ2UxID0gcTFtYXQkYFIoYWdlIDEpYCwNCiAgICAgICAgICAgICAgICAgICBDYXRjaEVzdCA9IGNhdGNodGFibGUoTE9fbm1HRmIkYHcuby4gUTFJQlRTK0JJVFMrQ29kU0QyMS0yNWApWywxXSwNCiAgICAgICAgICAgICAgICAgICBzZXJpZXMgPSByZXAoIndvX1ExIiwgdGltZXMgPSBucm93KHExbWF0KSkpDQoNCndvcTM0IDwtIGRhdGEuZnJhbWUoWWVhciA9IGFzLmludGVnZXIocm93Lm5hbWVzKHEzbWF0WygyMDAyOkRhdGFZZWFyKS0yMDAxLF0pKSwNCiAgICAgICAgICAgICAgICAgICAgU1NCID0gcTNtYXRbKDIwMDI6RGF0YVllYXIpLTIwMDEsICJTU0IiXSwNCiAgICAgICAgICAgICAgICAgICAgRmJhciA9IHEzbWF0WygyMDAyOkRhdGFZZWFyKS0yMDAxLCJGYmFyKDMtNSkiXSwNCiAgICAgICAgICAgICAgICAgICAgUl9hZ2UxID0gcTNtYXRbKDIwMDI6RGF0YVllYXIpLTIwMDEsIlIoYWdlIDEpIl0sDQogICAgICAgICAgICAgICAgICAgIENhdGNoRXN0ID0gY2F0Y2h0YWJsZShMT19ubUdGYiRgdy5vLiBRMzRJQlRTK0JJVFMrQ29kU0QyMS0yNWApWywxXSwNCiAgICAgICAgICAgICAgICAgICAgc2VyaWVzID0gcmVwKCJ3b19RMzQiLCB0aW1lcyA9IChucm93KHEzbWF0KS0xKSkpDQoNCg0KYXN1bV9ubUdGYiRzZXJpZXMgPC0gcmVwKCJmdWxsIiwgdGltZXMgPSBucm93KGFzdW1fbm1HRmIpKQ0KYXN1bWlfbm1HRmIgPC0gYXN1bV9ubUdGYlssIGMoIlllYXIiLCAiU1NCIiwgIkZiYXIiLCAiUl9hZ2UxIiwgIkNhdGNoRXN0IiAsInNlcmllcyIpXQ0KIz09PT09DQoNCmxvc3VtX25tR0ZiIDwtIHJiaW5kKHdvcTEsIHdvcTM0LCBhc3VtaV9ubUdGYikNCg0KYGBgDQoNCmBgYHtyIGZpZy5jYXA9IkxlYXZlLW9uZS1vdXQgcmUtZml0cyBmb3IgdGhlIFRpbWUgaW52YXJpYW50LCBHaXNsYXNvbiBuYXR1cmFsIG1vcnRhbGl0aWVzIGNhbGN1bGF0ZWQgZnJvbSBsaWZlLWhpc3Rvcnkgb2ZmIG9mIGZpc2hiYXNlICh3aXRob3V0IFExIHN1cnZleSA9IGJsdWUsIHdpdGhvdXQgUTMvNCBzdXJ2ZXkgPSBwdXJwbGUpLCBvdmVybGFpbiB3aXRoIGZ1bGwgbW9kZWwgZXN0aW1hdGVzIChibGFjayBsaW5lIGFuZCBncmV5IHJpYmJvbikgb2YgU1NCICh0b3AgbGVmdCksIEYgKHRvcCByaWdodCksIFJlY3J1aXRtZW50IChib3R0b20gbGVmdCksIGFuZCBjYXRjaCAoYm90dG9tIHJpZ2h0OyBvYnNlcnZhdGlvbnMgYXMgeWVsbG93ICspLiJ9DQojIHNzYnBsb3QoTE8pDQpsb3NzYl9ubUdGYiA8LSBnZ3Bsb3RseShnZ3Bsb3QoKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fbGluZShkYXRhID0gbG9zdW1fbm1HRmIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1TU0IsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IHNlcmllcykpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9yaWJib24oZGF0YSA9IGFzdW1fbm1HRmIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW49U1NCbG93LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltYXg9U1NCaGlnaCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSAiYmxhY2siLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMikgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoImJsYWNrIiwgZWJwYWxbODo5XSkpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWVfY2xlYW4oKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKGF4aXMudGl0bGUueS5sZWZ0ID0gZWxlbWVudF90ZXh0KHZqdXN0ID0gLTAuMDUsIGhqdXN0ID0gMC45NSkpKQ0KDQojIEZwbG90KExPKQ0KbG9mX25tR0ZiIDwtIGdncGxvdGx5KGdncGxvdCgpICsNCiAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fbGluZShkYXRhID0gbG9zdW1fbm1HRmIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PUZiYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBzZXJpZXMpKSArDQogICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3JpYmJvbihkYXRhID0gYXN1bV9ubUdGYiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWluPUZsb3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltYXg9RmhpZ2gpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9ICJibGFjayIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMykgKw0KICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCJibGFjayIsIGVicGFsWzg6OV0pKSArDQogICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9jbGVhbigpICsNCiAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKGF4aXMudGl0bGUueS5sZWZ0ID0gZWxlbWVudF90ZXh0KHZqdXN0ID0gLTAuMDUsIGhqdXN0ID0gMC45NSkpKQ0KDQojIHJlY3Bsb3QoTE8pDQpsb3JlY19ubUdGYiA8LSBnZ3Bsb3RseShnZ3Bsb3QoKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fbGluZShkYXRhID0gbG9zdW1fbm1HRmIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1SX2FnZTEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IHNlcmllcykpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9yaWJib24oZGF0YSA9IGFzdW1fbm1HRmIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW49UmxvdywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4PVJoaWdoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9ICJibGFjayIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4zKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiYmxhY2siLCBlYnBhbFs4OjldKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9jbGVhbigpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWUoYXhpcy50aXRsZS55LmxlZnQgPSBlbGVtZW50X3RleHQodmp1c3QgPSAtMC4wNSwgaGp1c3QgPSAwLjk1KSkpDQoNCiMgQ2F0Y2ggcGxvdCAoTE8pDQpsb2NhX25tR0ZiIDwtIGdncGxvdGx5KGdncGxvdCgpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IGxvc3VtX25tR0ZiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PUNhdGNoRXN0LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IHNlcmllcykpKw0KICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fcmliYm9uKGRhdGEgPSBhc3VtX25tR0ZiW2FzdW1fbm1HRmIkWWVhciAhPSAoRGF0YVllYXIrMSksIF0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWluPUNhdGNobG93LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1heD1DYXRjaGhpZ2gpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSAiYmxhY2siLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4zKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9wb2ludChkYXRhID0gYXN1bV9ubUdGYlthc3VtX25tR0ZiJFllYXIgIT0gKERhdGFZZWFyKzEpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9Q2F0Y2hPYnMpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hhcGUgPSAzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gZWJwYWxbNV0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gZWJwYWxbNV0pICsNCiAgICAgICAgICAgICAgICAgICAgICAgICB5bGFiKCJDYXRjaCAodG9ubmVzKSIpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoImJsYWNrIiwgZWJwYWxbODo5XSkpKyANCiAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9jbGVhbigpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZShheGlzLnRpdGxlLnkubGVmdCA9IGVsZW1lbnRfdGV4dCh2anVzdCA9IC0wLjA1LCBoanVzdCA9IDAuOTUpKSkNCg0KbGF5b3V0KHN1YnBsb3QobG9zc2Jfbm1HRmIsIGxvZl9ubUdGYiwgbG9yZWNfbm1HRmIsIGxvY2Ffbm1HRmIsIG5yb3dzID0gMiwgc2hhcmVYID0gVFJVRSwgdGl0bGVZID0gVFJVRSksIHNob3dsZWdlbmQ9RkFMU0UpDQpgYGANCg0KIyMjIFJldHJvc3BlY3RpdmVzDQpgYGB7ciBjYWxjdWxhdGVSZXRyb3Nfbm1HRmJ9DQojPT09DQojIENyZWF0ZSBkYXRhZnJhbWUgb2YgY3VycmVudCB5ZWFyJ3MgZml0IGZvciBwbG90dGluZw0KIz09PT0NCiMgSUNfYWdnX3RlbXAgPC0gYWdncmVnYXRlKENBVE9OflllYXIsIGljX2NsZWFuW2ljX2NsZWFuJENhdGNoQ2F0ZWdvcnkgJWluJSBjKCJMYW5kaW5ncyIsICJEaXNjYXJkcyIpLCBdLCBGVU4gPSAic3VtIikNCmFzdW1fbm1HRmIgPC0gYXMuZGF0YS5mcmFtZShzdW1tYXJ5KGZpdF9ubUdGYikpDQphc3VtX25tR0ZiJFllYXIgPC0gYXMuaW50ZWdlcihyb3cubmFtZXMoc3VtbWFyeShmaXRfbm1HRmIpKSkNCmN0X25tR0ZiIDwtIGFzLmRhdGEuZnJhbWUoY2F0Y2h0YWJsZShmaXRfbm1HRmIsIG9icy5zaG93ID0gVFJVRSkpDQpjdF9ubUdGYiRZZWFyIDwtIGFzLmludGVnZXIocm93bmFtZXMoY3Rfbm1HRmIpKQ0Kcm93bmFtZXMoY3Rfbm1HRmIpIDwtIE5VTEwNCmN0X25tR0ZiIDwtIHJiaW5kKGN0X25tR0ZiLCBkYXRhLmZyYW1lKEVzdGltYXRlID0gTkEsIExvdz1OQSwgSGlnaD1OQSwgc29wLmNhdGNoPU5BLCBZZWFyPWFzLmludGVnZXIoMjAyNCkpKQ0KYXN1bV9ubUdGYiA8LSBtZXJnZSh4ID0gYXN1bV9ubUdGYiwgeSA9IGN0X25tR0ZiLCBieSA9ICJZZWFyIikNCmNvbG5hbWVzKGFzdW1fbm1HRmIpIDwtIGMoIlllYXIiLCAiUl9hZ2UxIiwgIlJsb3ciLCAiUmhpZ2giLCAiU1NCIiwgIlNTQmxvdyIsICJTU0JoaWdoIiwgIkZiYXIiLCAiRmxvdyIsICJGaGlnaCIsICJDYXRjaEVzdCIsICJDYXRjaGxvdyIsICJDYXRjaGhpZ2giLCAiQ2F0Y2hPYnMiKQ0KDQphc3VtX25tR0ZiJHNlcmllcyA8LSByZXAoImZ1bGwiLCB0aW1lcyA9IG5yb3coYXN1bV9ubUdGYikpDQoNCiM9PT09PQ0KUkVUUk9fbm1HRmI8LXJldHJvKGZpdF9ubUdGYiwgeWVhcj01KQ0KcmhvX25tR0ZiIDwtIG1vaG4oUkVUUk9fbm1HRmIsIGxhZyA9IDEpDQoNCiMjIE1ha2UgUkVUUk9zIGluIGJldHRlciBwbG90dGluZyBmb3JtYXQNCnJldF9ubUdGYl9kZiA8LSBhc3VtX25tR0ZiW2FzdW1fbm1HRmIkWWVhciAhPSBtYXgoYXN1bV9ubUdGYiRZZWFyKSwgXQ0KDQpmb3IoaSBpbiAxOmxlbmd0aChSRVRST19ubUdGYikpew0KICB0c3VtIDwtIGFzLmRhdGEuZnJhbWUoc3VtbWFyeShSRVRST19ubUdGYltbaV1dKSkNCiAgdHN1bSRZZWFyIDwtIGFzLmludGVnZXIocm93Lm5hbWVzKHN1bW1hcnkoUkVUUk9fbm1HRmJbW2ldXSkpKQ0KICB0c3VtIDwtIGNiaW5kKHRzdW0sIGNhdGNodGFibGUoUkVUUk9fbm1HRmJbW2ldXSwgb2JzLnNob3cgPSBUUlVFKSkNCiAgdHN1bSRzZXJpZXMgPC0gYXMuY2hhcmFjdGVyKHJlcChpLCBucm93KHRzdW0pKSkNCiAgY29sbmFtZXModHN1bSkgPC0gYygiUl9hZ2UxIiwgIlJsb3ciLCAiUmhpZ2giLCAiU1NCIiwgIlNTQmxvdyIsICJTU0JoaWdoIiwgIkZiYXIiLCAiRmxvdyIsICJGaGlnaCIsICJZZWFyIiwgIkNhdGNoRXN0IiwgIkNhdGNobG93IiwgIkNhdGNoaGlnaCIsICJDYXRjaE9icyIsICJzZXJpZXMiKQ0KICB0c3VtIDwtIHRzdW1bdHN1bSRZZWFyICE9IG1heCh0c3VtJFllYXIpLCBdDQogIHJldF9ubUdGYl9kZiA8LSByYmluZChyZXRfbm1HRmJfZGYsIHRzdW0pDQp9DQpyZXRfbm1HRmJfZGYkc2VyaWVzIDwtIGZhY3RvcihyZXRfbm1HRmJfZGYkc2VyaWVzLCBsZXZlbHMgPSBjKCJmdWxsIiwgIjEiLCAiMiIsICIzIiwgIjQiLCAiNSIpKQ0KYGBgDQoNCmBgYHtyIGZpZy5jYXA9IlJldHJvc3BlY3RpdmUgYW5hbHlzZXMgZm9yIFNTQiAodG9wLWxlZnQpLCBGIGZvciBhZ2VzIDMtNSAodG9wLXJpZ2h0KSwgcmVjcnVpdG1lbnQgKGJvdHRvbS1sZWZ0KSwgYW5kIGNhdGNoIChib3R0b20tcmlnaHQpLCBmcm9tIHRoZSBtb2RlbCB1dGlsaXNpbmcgdGltZSBpbnZhcmlhbnQsIEdpc2xhc29uIG5hdHVyYWwgbW9ydGFsaXRpZXMgKEZpc2hCYXNlKS4ifQ0KIyBzc2JwbG90KFJFVFJPKQ0KcmV0c3NiX25tR0ZiIDwtIGxheW91dChnZ3Bsb3RseShnZ3Bsb3QoKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9saW5lKGRhdGEgPSByZXRfbm1HRmJfZGYsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9U1NCLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IHNlcmllcykpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3JpYmJvbihkYXRhID0gYXN1bV9ubUdGYlthc3VtX25tR0ZiJFllYXIgIT0gbWF4KGFzdW1fbm1HRmIkWWVhciksIF0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWluPVNTQmxvdywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltYXg9U1NCaGlnaCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9ICJibGFjayIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjIpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbm5vdGF0ZShnZW9tID0gInRleHQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBtYXgocmV0X25tR0ZiX2RmJFNTQmhpZ2gpKjAuODUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeCA9ICgobWF4KHJldF9ubUdGYl9kZiRZZWFyKS1taW4ocmV0X25tR0ZiX2RmJFllYXIpKSowLjIwKSttaW4ocmV0X25tR0ZiX2RmJFllYXIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsID0gcGFzdGUwKCJNb2huJ3MgUmhvID0gIiwgcm91bmQocmhvX25tR0ZiWzJdLCBkaWdpdHMgPSAzKSkpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoImJsYWNrIiwgZWJwYWxbKGxlbmd0aChlYnBhbCktNCk6bGVuZ3RoKGVicGFsKV0pKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWVfY2xlYW4oKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF4aXMudGl0bGUueS5sZWZ0ID0gZWxlbWVudF90ZXh0KHZqdXN0ID0gLTAuMDUsIGhqdXN0ID0gMC45NSkpKSwNCiAgICAgICAgICAgICAgICAgICAgICAgc2hvd2xlZ2VuZCA9IEZBTFNFKQ0KDQojIEZwbG90KFJFVFJPKQ0KcmV0Zl9ubUdGYiA8LSBsYXlvdXQoZ2dwbG90bHkoZ2dwbG90KCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IHJldF9ubUdGYl9kZiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PUZiYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IHNlcmllcykpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9yaWJib24oZGF0YSA9IGFzdW1fbm1HRmJbYXN1bV9ubUdGYiRZZWFyICE9IG1heChhc3VtX25tR0ZiJFllYXIpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWluPUZsb3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1heD1GaGlnaCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSAiYmxhY2siLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMykgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbm5vdGF0ZShnZW9tID0gInRleHQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gbWF4KHJldF9ubUdGYl9kZiRGaGlnaCkqMC44NSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeCA9ICgobWF4KHJldF9ubUdGYl9kZiRZZWFyKS1taW4ocmV0X25tR0ZiX2RmJFllYXIpKSowLjgwKSttaW4ocmV0X25tR0ZiX2RmJFllYXIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbCA9IHBhc3RlMCgiTW9obidzIFJobyA9ICIsIHJvdW5kKHJob19ubUdGYlszXSwgZGlnaXRzID0gMykpKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiYmxhY2siLCBlYnBhbFsobGVuZ3RoKGVicGFsKS00KTpsZW5ndGgoZWJwYWwpXSkpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWVfY2xlYW4oKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXhpcy50aXRsZS55LmxlZnQgPSBlbGVtZW50X3RleHQodmp1c3QgPSAtMC4wNSwgaGp1c3QgPSAwLjk1KSkpLA0KICAgICAgICAgICAgICAgICAgICAgc2hvd2xlZ2VuZCA9IEZBTFNFKQ0KDQojIHJlY3Bsb3QoUkVUUk8pDQpyZXRyZWNfbm1HRmIgPC0gbGF5b3V0KGdncGxvdGx5KGdncGxvdCgpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IHJldF9ubUdGYl9kZiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1SX2FnZTEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gc2VyaWVzKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fcmliYm9uKGRhdGEgPSBhc3VtX25tR0ZiW2FzdW1fbm1HRmIkWWVhciAhPSBtYXgoYXN1bV9ubUdGYiRZZWFyKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW49UmxvdywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltYXg9UmhpZ2gpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSAiYmxhY2siLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4zKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYW5ub3RhdGUoZ2VvbSA9ICJ0ZXh0IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PSBtYXgocmV0X25tR0ZiX2RmJFJoaWdoKSowLjg1LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHggPSAoKG1heChyZXRfbm1HRmJfZGYkWWVhciktbWluKHJldF9ubUdGYl9kZiRZZWFyKSkqMC4yMCkrbWluKHJldF9ubUdGYl9kZiRZZWFyKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbCA9IHBhc3RlMCgiTW9obidzIFJobyA9ICIsIHJvdW5kKHJob19ubUdGYlsxXSwgZGlnaXRzID0gMykpKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCJibGFjayIsIGVicGFsWyhsZW5ndGgoZWJwYWwpLTQpOmxlbmd0aChlYnBhbCldKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2NsZWFuKCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBheGlzLnRpdGxlLnkubGVmdCA9IGVsZW1lbnRfdGV4dCh2anVzdCA9IC0wLjA1LCBoanVzdCA9IDAuOTUpKSksDQogICAgICAgICAgICAgICAgICAgICAgIHNob3dsZWdlbmQgPSBGQUxTRSkNCg0KIyBDYXRjaCBwbG90IChSRVRSTykNCnJldGNhX25tR0ZiIDwtIGdncGxvdGx5KGdncGxvdCgpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9saW5lKGRhdGEgPSByZXRfbm1HRmJfZGYsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1DYXRjaEVzdCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gc2VyaWVzKSkrDQogICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fcmliYm9uKGRhdGEgPSBhc3VtX25tR0ZiW2FzdW1fbm1HRmIkWWVhciAhPSBtYXgoYXN1bV9ubUdGYiRZZWFyKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1pbj1DYXRjaGxvdywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4PUNhdGNoaGlnaCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSAiYmxhY2siLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMykgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3BvaW50KGRhdGEgPSBhc3VtX25tR0ZiW2FzdW1fbm1HRmIkWWVhciAhPSBtYXgoYXN1bV9ubUdGYiRZZWFyKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9Q2F0Y2hPYnMpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNoYXBlID0gMywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBlYnBhbFs1XSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gZWJwYWxbNV0pICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgeWxhYigiQ2F0Y2ggKHRvbm5lcykiKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiYmxhY2siLCBlYnBhbFsobGVuZ3RoKGVicGFsKS00KTpsZW5ndGgoZWJwYWwpXSkpKyANCiAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWVfY2xlYW4oKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKGF4aXMudGl0bGUueS5sZWZ0ID0gZWxlbWVudF90ZXh0KHZqdXN0ID0gLTAuMDUsIGhqdXN0ID0gMC45NSkpKQ0KDQpyZXRfZnAgPC0gc3R5bGUoc3VicGxvdChyZXRzc2Jfbm1HRmIsIHJldGZfbm1HRmIsIHJldHJlY19ubUdGYiwgcmV0Y2Ffbm1HRmIsIG5yb3dzID0gMiwgc2hhcmVYID0gRkFMU0UsIHNoYXJlWSA9IEZBTFNFLCB0aXRsZVkgPSBUUlVFKSwNCiAgICAgICAgICAgICAgICBzaG93bGVnZW5kPUZBTFNFLA0KICAgICAgICAgICAgICAgIHRyYWNlcyA9IGMoODooKDcqNCkrMikpKQ0KDQpsYXlvdXQocmV0X2ZwLCBsZWdlbmQgPSBsaXN0KG9yaWVudGF0aW9uID0gJ2gnLCB4ID0gMC41LCB4YW5jaG9yID0gJ2NlbnRlcicsIHkgPSAtMC4wNSwgeWFuY2hvciA9ICd0b3AnLCBib3JkZXJ3aWR0aCA9IDApKQ0KYGBgDQoNCiMjIFNjYWxlZCwgVGltZSBJbnZhcmlhbnQsIEdpc2xhc29uIE5hdHVyYWwgbW9ydGFsaXRpZXMNCiMjIyBTY2FsaW5nIGFuZCBvcHRpbWlzaW5nDQoNCmBgYHtyIGxpa2VsaWhvb2RQcm9maWxlTk1fbm1HRmIsIHJlc3VsdHM9J2hpZGUnLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQ0KDQojPT09DQojIFNjYWxlIG5hdHVyYWwgbW9ydGFsaXR5IGJ5IGEgcmFuZ2Ugb2YgbXVsdGlwbGllcnMNCiM9PT09DQpmaXRfbm1HRmIgPC0gZml0ZnJvbXdlYigicGxlLjI3LjIxLTMyX1dLQlBMQUlDRV8yMDI0X0Jpb1BhcnN3X1NWX25tR0ZiIikNCg0KcHJvZnMgPSBsaXN0KCkNCm5tID0gZml0X25tR0ZiJGRhdGEkbmF0TW9yDQptdWx0cyA9IHNlcSgwLjEsIDIsIGJ5PTAuMSkNCg0KIyMgUmUtZml0IHRvIHNjYWxlZCBtb3J0YWxpdGllcw0KZm9yKG11bHQgaW4gbXVsdHMpew0KICANCiAgZml0X25tR0ZiJGRhdGEkbmF0TW9yID0gbm0qbXVsdA0KICANCiAgcHJvZnNbW2FzLmNoYXJhY3RlcihtdWx0KV1dPSBzdG9ja2Fzc2Vzc21lbnQ6OjpyZWZpdChmaXRfbm1HRmIsIHNpbGVudCA9IFRSVUUpDQp9DQojPT09PQ0KYGBgDQoNCmBgYHtyIGZpZy5jYXA9Ikxpa2VsaWhvb2QgcHJvZmlsZSBvZiBzY2FsZWQgdGltZSBpbnZhcmlhbnQsIEdpc2xhc29uIG5hdHVyYWwgbW9ydGFsaXRpZXMgKEZpc2hCYXNlKS4gWS1heGlzID0gQUlDLCB4LWF4aXMgPSBzY2FsaW5nIGZhY3RvciBvbiBubS4ifQ0KIz09PQ0KIyBBZ2dyZWdhdGUgQUlDIHZhbHVlcyBhbmQgcGxvdCByZXN1bHRzDQojPT09PQ0KbGwgPSBzYXBwbHkocHJvZnMsQUlDKQ0KcGxvdChtdWx0cyxsbCkNCiM9PT09DQpgYGANCg0KDQpXZSBjYW4gbm93IGludmVzdGlnYXRlIGlmIGF2ZXJhZ2luZyB0aGUgR2lzbGFzb24gbmF0dXJhbCBtb3J0YWxpdGllcyBvdmVyIHRoZSB0aW1lIHNlcmllcyBjcmVhdGVzIHNvbWUgc2NhbGluZyBpc3N1ZXMgYnkgaWdub3Jpbmcgd2VpZ2h0aW5ncyBvZiBudW1iZXJzIG9mIG9ic2VydmF0aW9ucyBjb250cmlidXRpbmcgdG8gZWFjaCBhbm51YWwgZXN0aW1hdGUuIFRvIHBhcnRpYWxseSBhZGRyZXNzIHRoaXMgd2UgY2FuIGludmVzdGlnYXRlIHNjYWxpbmcgdGhlc2UgdGltZSBpbnZhcmlhbnQgdmFsdWVzIHVwIGFuZCBkb3duLCB0byBmaW5kIHdoZXJlIHRoZSBiZXN0IGZpdCBvZiB0aGlzICJzaGFwZSIgb2YgbmF0dXJhbCBtb3J0YWxpdGllcyBhY3Jvc3MgYWdlcyBpcy4NCg0KQnkgc2NhbGluZyB0aGUgbm0gdmFsdWVzIHVwIGFuZCBkb3duIGFjcm9zcyBhIHJhbmdlIG9mIG11bHRpcGxpZXJzIGZyb20gMC4xIHRvIDIsIGluIGluY3JlbWVudHMgb2YgMC4xLCB3ZSBjcmVhdGUgMjAgZGlmZmVyZW50IHJ1bnMgZnJvbSB3aGljaCB3ZSBjYW4gY29tcGFyZSBBSUMgdmFsdWVzLiAgSGVyZSB3ZSBmaW5kIHRoYXQgYSBzY2FsaW5nIHZhbHVlIG9mIGByIG11bHRzWyB3aGljaC5taW4obGwpIF1gIGlzIHJlc3BvbnNpYmxlIGZvciB0aGUgb3B0aW11bSBtb2RlbCBmaXQuIA0KDQojIyMgSW52ZXN0aWdhdGluZyB0aGUgc2NhbGVkIG1vZGVsDQoNClRoZXJlZm9yZSwgYmVsb3cgd2UgaW52ZXN0aWdhdGUgdGhlIG1vZGVsIGZpdCBhbmQgcmVzaWR1YWxzIGZvciBhIG1vZGVsIHdpdGggdGhlIEdpc2xhc29uLCB0aW1lIGludmFyaWFudCBtb3J0YWxpdGllcyBhdCBhZ2UgdGhhdCBoYXZlIGJlZW4gc2NhbGVkIGJ5IGEgZmFjdG9yIG9mIGByIG11bHRzWyB3aGljaC5taW4obGwpIF1gIGFjcm9zcyBhbGwgYWdlcy4NCg0KYGBge3Igbm1HX1NGYkZpdEZyb21XZWJ9DQpmaXRfbm1HX1NGYiA8LSBmaXRmcm9td2ViKCJwbGUuMjcuMjEtMzJfV0tCUExBSUNFXzIwMjRfQmlvUGFyc3dfbm1HX1NGYiIpDQpgYGANCg0KYGBge3IgZGF0YWZyYW1lU3VtbWFyeV9ubUdfU0ZiLCByZXN1bHRzPSdoaWRlJywgZmlnLnNob3c9J2hpZGUnfQ0KIz09PQ0KIyBDcmVhdGUgZGF0YWZyYW1lIG9mIGN1cnJlbnQgeWVhcidzIGZpdCBmb3IgcGxvdHRpbmcNCiM9PT09DQphc3VtX25tR19TRmIgPC0gYXMuZGF0YS5mcmFtZShzdW1tYXJ5KGZpdF9ubUdfU0ZiKSkNCmFzdW1fbm1HX1NGYiRZZWFyIDwtIGFzLmludGVnZXIocm93Lm5hbWVzKHN1bW1hcnkoZml0X25tR19TRmIpKSkNCmN0X25tR19TRmIgPC0gYXMuZGF0YS5mcmFtZShjYXRjaHRhYmxlKGZpdF9ubUdfU0ZiLCBvYnMuc2hvdyA9IFRSVUUpKQ0KY3Rfbm1HX1NGYiRZZWFyIDwtIGFzLmludGVnZXIocm93bmFtZXMoY3Rfbm1HX1NGYikpDQpyb3duYW1lcyhjdF9ubUdfU0ZiKSA8LSBOVUxMDQpjdF9ubUdfU0ZiIDwtIHJiaW5kKGN0X25tR19TRmIsIGRhdGEuZnJhbWUoRXN0aW1hdGUgPSBOQSwgTG93PU5BLCBIaWdoPU5BLCBzb3AuY2F0Y2g9TkEsIFllYXI9YXMuaW50ZWdlcigyMDI0KSkpDQphc3VtX25tR19TRmIgPC0gbWVyZ2UoeCA9IGFzdW1fbm1HX1NGYiwgeSA9IGN0X25tR19TRmIsIGJ5ID0gIlllYXIiKQ0KY29sbmFtZXMoYXN1bV9ubUdfU0ZiKSA8LSBjKCJZZWFyIiwgIlJfYWdlMSIsICJSbG93IiwgIlJoaWdoIiwgIlNTQiIsICJTU0Jsb3ciLCAiU1NCaGlnaCIsICJGYmFyIiwgIkZsb3ciLCAiRmhpZ2giLCAiQ2F0Y2hFc3QiLCAiQ2F0Y2hsb3ciLCAiQ2F0Y2hoaWdoIiwgIkNhdGNoT2JzIikNCiM9PT09PQ0KYGBgDQoNCiMjIyMgRml0cyB0byBkYXRhDQpXaGVuIHRoZSBtb2RlbCBpcyBydW4gd2UgY2FuIGVhc2lseSBzZWUgZnJvbSB3YXJuaW5ncy9lcnJvcnMgaWYgdGhlcmUgaXMgYSBjb252ZXJnZW5jZSBpc3N1ZS4gIEhvd2V2ZXIsIHdlIGNhbiBhbHNvIGNvbmZpcm0gdGhpcywgZXhwbGljaXRseToNCi0gVGhlIGZpbmFsIG1vZGVsIGdyYWRpZW50OiBgciBmaXRfbm1HX1NGYiRvcHQkZXZhbHVhdGlvbnNbMl1gDQotIFRoYXQgdGhlcmUgaXMgYSBwb3NpdGl2ZSBkZWZpbml0ZSBoZXNzaWFuOiBgciBhbGwoZWlnZW4oZml0X25tR19TRmIkb3B0JGhlKSR2YWx1ZXMgPjApYA0KDQpGdXJ0aGVybW9yZSwgU0FNIGRvZXMgbm90IHV0aWxpc2UgImJvdW5kcyIgd2hlbiBmaXR0aW5nIHRoZSBtb2RlbCwgYW5kIHRoZXJlZm9yZSwgYXMgc3RhbmRhcmQgY2hlY2sgb2Ygd2hldGhlciBtb2RlbCBwYXJhbWV0ZXJzIGFyZSBhcHByb2FjaGluZyB0aGVpciBib3VuZHMgaXMgaXJyZWxldmFudC4NCg0KYGBge3IgZmlnLmNhcD0iTW9kZWwgd2l0aCBTQ0FMRUQgdGltZSBpbnZhcmlhbnQgR2lzbGFzb24gbmF0dXJhbCBtb3J0YWxpdGllcyAoRmlzaEJhc2UpIGZpdCB0byBjYXRjaCBkYXRhIGJ5IGFnZSAodmFsdWVzIG9uIHRoZSBtb2RlbCBsaW5rIGZ1bmN0aW9uIHNjYWxlKS4ifQ0KIyMgRXh0cmFjdCBkYXRhIGZyb20gbW9kZWwgb2JqZWN0DQpsb2dPYnNfbm1HX1NGYiA8LSBzcGxpdChmaXRfbm1HX1NGYiRkYXRhJGxvZ29icywgY2VpbGluZyhzZXFfYWxvbmcoZml0X25tR19TRmIkZGF0YSRsb2dvYnMpL2ZpdF9ubUdfU0ZiJGRhdGEkbWF4QWdlUGVyRmxlZXRbMV0pKQ0KbG9nUHJlZF9ubUdfU0ZiIDwtIHNwbGl0KGZpdF9ubUdfU0ZiJHJlcCRwcmVkT2JzLCBjZWlsaW5nKHNlcV9hbG9uZyhmaXRfbm1HX1NGYiRyZXAkcHJlZE9icykvZml0X25tR19TRmIkZGF0YSRtYXhBZ2VQZXJGbGVldFsxXSkpDQoNCiMjIFRyYW5zZm9ybSBkYXRhIHRvIHVzZWFibGUgZGF0YWZyYW1lcw0KIyMjIEluaXRpYWxpemUgYW4gZW1wdHkgZGF0YSBmcmFtZSBmb3Igb2JzZXJ2YXRpb25zDQpsb2dPYnNfbm1HX1NGYl9kZiA8LSBkYXRhLmZyYW1lKGFnZSA9IGludGVnZXIoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmxlZXQgPSBpbnRlZ2VyKCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllYXIgPSBpbnRlZ2VyKCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZ09icyA9IG51bWVyaWMoKSkNCg0KIyMjIFBvcHVsYXRlIHRoZSBkYXRhIGZyYW1lIGZvciBvYnNlcnZhdGlvbnMNCmZvciAoaSBpbiBzZXFfYWxvbmcobG9nT2JzX25tR19TRmIpKSB7DQogICMgQ2FsY3VsYXRlIHRoZSBncm91cCBhbmQgeWVhcg0KICB5ZWFyIDwtICgoaSAtIDEpICUvJSAzKSArIDENCiAgZmxlZXQgPC0gKChpIC0gMSkgJSUgMykgKyAxDQogIA0KICAjIyMgQ3JlYXRlIGEgdGVtcG9yYXJ5IGRhdGEgZnJhbWUgYW5kIGFwcGVuZCB0byB0aGUgbWFpbiBkYXRhIGZyYW1lIGZvciBvYnNlcnZhdGlvbnMNCiAgdGVtcF9kZiA8LSBkYXRhLmZyYW1lKGFnZSA9IDE6NywNCiAgICAgICAgICAgICAgICAgICAgICAgIGZsZWV0ID0gZmxlZXQsDQogICAgICAgICAgICAgICAgICAgICAgICB5ZWFyID0geWVhcisyMDAxLA0KICAgICAgICAgICAgICAgICAgICAgICAgbG9nT2JzID0gbG9nT2JzX25tR19TRmJbW2ldXSkNCiAgbG9nT2JzX25tR19TRmJfZGYgPC0gcmJpbmQobG9nT2JzX25tR19TRmJfZGYsIHRlbXBfZGYpDQp9DQoNCiMjIyBJbml0aWFsaXplIGFuIGVtcHR5IGRhdGEgZnJhbWUgZm9yIHByZWRpY3Rpb25zDQpsb2dQcmVkX25tR19TRmJfZGYgPC0gZGF0YS5mcmFtZShhZ2UgPSBpbnRlZ2VyKCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmbGVldCA9IGludGVnZXIoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllYXIgPSBpbnRlZ2VyKCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2dQcmVkID0gbnVtZXJpYygpKQ0KDQojIyMgUG9wdWxhdGUgdGhlIGRhdGEgZnJhbWUgZm9yIHByZWRpY3Rpb25zDQpmb3IgKGkgaW4gc2VxX2Fsb25nKGxvZ1ByZWRfbm1HX1NGYikpIHsNCiAgIyBDYWxjdWxhdGUgdGhlIGdyb3VwIGFuZCB5ZWFyDQogIHllYXIgPC0gKChpIC0gMSkgJS8lIDMpICsgMQ0KICBmbGVldCA8LSAoKGkgLSAxKSAlJSAzKSArIDENCiAgDQogICMjIyBDcmVhdGUgYSB0ZW1wb3JhcnkgZGF0YSBmcmFtZSBhbmQgYXBwZW5kIHRvIHRoZSBtYWluIGRhdGEgZnJhbWUgZm9yIHByZWRpY3Rpb25zDQogIHRlbXBfZGYgPC0gZGF0YS5mcmFtZShhZ2UgPSAxOjcsDQogICAgICAgICAgICAgICAgICAgICAgICBmbGVldCA9IGZsZWV0LA0KICAgICAgICAgICAgICAgICAgICAgICAgeWVhciA9IHllYXIrMjAwMSwNCiAgICAgICAgICAgICAgICAgICAgICAgIGxvZ1ByZWQgPSBsb2dQcmVkX25tR19TRmJbW2ldXSkNCiAgbG9nUHJlZF9ubUdfU0ZiX2RmIDwtIHJiaW5kKGxvZ1ByZWRfbm1HX1NGYl9kZiwgdGVtcF9kZikNCn0NCg0KIyMgUGxvdA0KbG9nUHJlZF9ubUdfU0ZiX2RmJGFnZSA8LSBhcy5jaGFyYWN0ZXIobG9nUHJlZF9ubUdfU0ZiX2RmJGFnZSkNCmxvZ09ic19ubUdfU0ZiX2RmJGFnZSA8LSBhcy5jaGFyYWN0ZXIobG9nT2JzX25tR19TRmJfZGYkYWdlKQ0KDQpnZ3Bsb3RseShnZ3Bsb3QoKSsNCiAgICAgICAgICAgZ2VvbV9wb2ludChkYXRhID0gbG9nT2JzX25tR19TRmJfZGZbbG9nT2JzX25tR19TRmJfZGYkZmxlZXQgPT0gMSAmIGxvZ09ic19ubUdfU0ZiX2RmJHllYXIgIT0gKERhdGFZZWFyKzEpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IHllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gbG9nT2JzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gYWdlKSwNCiAgICAgICAgICAgICAgICAgICAgICBzaGFwZSA9IDIxKSArDQogICAgICAgICAgIGdlb21fbGluZShkYXRhID0gbG9nUHJlZF9ubUdfU0ZiX2RmW2xvZ1ByZWRfbm1HX1NGYl9kZiRmbGVldCA9PSAxICYgbG9nUHJlZF9ubUdfU0ZiX2RmJHllYXIgIT0gKERhdGFZZWFyKzEpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0geWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGxvZ1ByZWQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IGFnZSkpICsNCiAgICAgICAgICAgZmFjZXRfd3JhcChmYWNldHMgPSAiYWdlIikgKyAjLCBzY2FsZXMgPSAiZnJlZV95IikgKw0KICAgICAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gZWJwYWwsIGd1aWRlID0gRkFMU0UpICsNCiAgICAgICAgICAgZ3VpZGVzKGNvbG91cj1GQUxTRSwgc2hhcGU9RkFMU0UpICsNCiAgICAgICAgICAgdGhlbWVfZmV3KCkpDQoNCiMgZml0cGxvdChmaXRfbm1HX1NGYiwgZmxlZXRzPTEpDQpgYGANCg0KYGBge3IgZmlnLmNhcD0iTW9kZWwgd2l0aCBTQ0FMRUQgdGltZSBpbnZhcmlhbnQgR2lzbGFzb24gbmF0dXJhbCBtb3J0YWxpdGllcyAoRmlzaEJhc2UpIGZpdCB0byBRMSBzdXJ2ZXkgZGF0YSBieSBhZ2UgKHZhbHVlcyBvbiB0aGUgbW9kZWwgbGluayBmdW5jdGlvbiBzY2FsZSkuIn0NCmdncGxvdGx5KGdncGxvdCgpKw0KICAgICAgICAgICBnZW9tX3BvaW50KGRhdGEgPSBsb2dPYnNfbm1HX1NGYl9kZltsb2dPYnNfbm1HX1NGYl9kZiRmbGVldCA9PSAyICYgbG9nT2JzX25tR19TRmJfZGYkeWVhciAhPSAoRGF0YVllYXIrMSksIF0sDQogICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0geWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBsb2dPYnMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBhZ2UpLA0KICAgICAgICAgICAgICAgICAgICAgIHNoYXBlID0gMjEpICsNCiAgICAgICAgICAgZ2VvbV9saW5lKGRhdGEgPSBsb2dQcmVkX25tR19TRmJfZGZbbG9nUHJlZF9ubUdfU0ZiX2RmJGZsZWV0ID09IDIgJiBsb2dQcmVkX25tR19TRmJfZGYkeWVhciAhPSAoRGF0YVllYXIrMSksIF0sDQogICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSB5ZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gbG9nUHJlZCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gYWdlKSkgKw0KICAgICAgICAgICBmYWNldF93cmFwKGZhY2V0cyA9ICJhZ2UiKSArICMsIHNjYWxlcyA9ICJmcmVlX3kiKSArDQogICAgICAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBlYnBhbCwgZ3VpZGUgPSBGQUxTRSkgKw0KICAgICAgICAgICBndWlkZXMoY29sb3VyPUZBTFNFLCBzaGFwZT1GQUxTRSkgKw0KICAgICAgICAgICB0aGVtZV9mZXcoKSkNCiMgZml0cGxvdChmaXRfbm1HX1NGYiwgZmxlZXRzPTIpDQpgYGANCg0KYGBge3IgZmlnLmNhcD0iTW9kZWwgd2l0aCBTQ0FMRUQgdGltZSBpbnZhcmlhbnQgR2lzbGFzb24gbmF0dXJhbCBtb3J0YWxpdGllcyAoRmlzaEJhc2UpIGZpdCB0byBRMy80IHN1cnZleSBkYXRhIGJ5IGFnZSAodmFsdWVzIG9uIHRoZSBtb2RlbCBsaW5rIGZ1bmN0aW9uIHNjYWxlKS4ifQ0KZ2dwbG90bHkoZ2dwbG90KCkrDQogICAgICAgICAgIGdlb21fcG9pbnQoZGF0YSA9IGxvZ09ic19ubUdfU0ZiX2RmW2xvZ09ic19ubUdfU0ZiX2RmJGZsZWV0ID09IDMgJiBsb2dPYnNfbm1HX1NGYl9kZiR5ZWFyICE9IChEYXRhWWVhcisxKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSB5ZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGxvZ09icywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IGFnZSksDQogICAgICAgICAgICAgICAgICAgICAgc2hhcGUgPSAyMSkgKw0KICAgICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IGxvZ1ByZWRfbm1HX1NGYl9kZltsb2dQcmVkX25tR19TRmJfZGYkZmxlZXQgPT0gMyAmIGxvZ1ByZWRfbm1HX1NGYl9kZiR5ZWFyICE9IChEYXRhWWVhcisxKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IHllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBsb2dQcmVkLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBhZ2UpKSArDQogICAgICAgICAgIGZhY2V0X3dyYXAoZmFjZXRzID0gImFnZSIpICsgIywgc2NhbGVzID0gImZyZWVfeSIpICsNCiAgICAgICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGVicGFsLCBndWlkZSA9IEZBTFNFKSArDQogICAgICAgICAgIGd1aWRlcyhjb2xvdXI9RkFMU0UsIHNoYXBlPUZBTFNFKSArDQogICAgICAgICAgIHRoZW1lX2ZldygpKQ0KDQojIGZpdHBsb3QoZml0X25tR19TRmIsIGZsZWV0cz0zKQ0KYGBgDQoNCmBgYHtyIGZpZy5jYXA9IlN0YW5kYXJkIERldmF0aW9ucyBieSBGbGVldDsgR2lzbGFzb24sIHNjYWxlZCwgdGltZS1pbnZhcmlhbnQgbW9ydGFsaXR5IChGaXNoQmFzZSkiLCBoZWlnaHQ9MTB9DQpzZHBsb3QoZml0X25tR19TRmIsIG1hcmcgPSBjKDUsNCwxLDEpKQ0KYGBgDQoNCiMjIyMgUmVzaWR1YWxzDQpgYGB7ciBjYWxjdWxhdGVSZXNpZHVhbHNfbm1HX1NGYiwgd2FybmluZz1GQUxTRSwgcmVzdWx0cz0naGlkZSd9DQpyZXNpZF9ubUdfU0ZiIDwtIHJlc2lkdWFscyhmaXRfbm1HX1NGYikNCnJlc2lkX25tR19TRmJfZGYgPC0gZGF0YS5mcmFtZSh5ZWFyID0gcmVzaWRfbm1HX1NGYiR5ZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZsZWV0ID0gcmVzaWRfbm1HX1NGYiRmbGVldCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZ2UgPSByZXNpZF9ubUdfU0ZiJGFnZSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvYnNlcnZhdGlvbiA9IHJlc2lkX25tR19TRmIkb2JzZXJ2YXRpb24sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWVhbiA9IHJlc2lkX25tR19TRmIkbWVhbiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXNpZHVhbCA9IHJlc2lkX25tR19TRmIkcmVzaWR1YWwpDQpyZXNpZF9ubUdfU0ZiX2RmJGZsZWV0TmFtZSA8LSBpZmVsc2UocmVzaWRfbm1HX1NGYl9kZiRmbGVldCA9PSAxLCBhdHRyaWJ1dGVzKHJlc2lkX25tR19TRmIpJGZsZWV0TmFtZXNbMV0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShyZXNpZF9ubUdfU0ZiX2RmJGZsZWV0ID09IDIsIGF0dHJpYnV0ZXMocmVzaWRfbm1HX1NGYikkZmxlZXROYW1lc1syXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShyZXNpZF9ubUdfU0ZiX2RmJGZsZWV0ID09IDMsIGF0dHJpYnV0ZXMocmVzaWRfbm1HX1NGYikkZmxlZXROYW1lc1szXSwgTkEpKSkNCg0KcmVzaWRfbm1HX1NGYl9kZiRmbGVldEFsdE5hbWUgPC0gaWZlbHNlKHJlc2lkX25tR19TRmJfZGYkZmxlZXQgPT0gMSwgIlJlc2lkdWFsIEZpc2hpbmciLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UocmVzaWRfbm1HX1NGYl9kZiRmbGVldCA9PSAyLCAiUTEgU3VydmV5cyIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UocmVzaWRfbm1HX1NGYl9kZiRmbGVldCA9PSAzLCAiUTMvNCBTdXJ2ZXlzIiwgTkEpKSkNCmBgYA0KDQpgYGB7ciBmaWcuY2FwPSJFc3RpbWF0ZWQgY29ycmVsYXRpb25zIGluIHJlc2lkdWFsIHZhcmlhdGlvbiBiZXR3ZWVuIGFnZXMgZm9yIGVhY2ggb2YgdGhlIGZpc2hpbmcgZmxlZXQgKHRvcCkgYW5kIHRoZSB0d28gc3VydmV5cyAobWlkZGxlICYgYm90dG9tKSwgZnJvbSB0aGUgTW9kZWwgd2l0aCBTQ0FMRUQgdGltZSBpbnZhcmlhbnQgR2lzbGFzb24gbmF0dXJhbCBtb3J0YWxpdGllcyAoRmlzaEJhc2UpLiJ9DQoNCmlmKCFhbGwoZml0X25tR19TRmIkY29uZiRvYnNDb3JTdHJ1Y3Q9PSJJRCIpKXsgDQogIGNvcnBsb3QoZml0X25tR19TRmIpCQkJICANCiAgIyBzZXRjYXAoIkVzdGltYXRlZCBjb3JyZWxhdGlvbnMiLCAiRXN0aW1hdGVzIGNvcnJlbGF0aW9ucyBiZXR3ZWVuIGFnZSBncm91cHMgZm9yIGVhY2ggZmxlZXQiKQ0KICAjIHN0YW1waXQoZml0KQ0KfSBlbHNlIHsNCiAgcHJpbnQoIk5vIGNvcnJlbGF0aW9uIHN0cnVjdHVyZSBjb25maWd1cmVkIGZvciByZXNpZHVhbHMgYWNyb3NzIGFnZS4iKQ0KfQ0KDQpgYGANCg0KYGBge3IgZmlnLmNhcD0iT25lIG9ic2VydmF0aW9uIGFoZWFkIHJlc2lkdWFscyBmb3IgdGhlIHRocmVlIGZsZWV0cyAocmVkL3BpbmsgPSBvYnNlcnZhdGlvbiBsb3dlciB0aGFuIG1vZGVsIGVzdGltYXRlLCBibHVlID0gb2JzZXJ2YXRpb24gaGlnaGVyIHRoYW4gbW9kZWwgZXN0aW1hdGUsIHNpemUgPSBtYWduaXR1ZGUgb2YgcmVzaWR1YWwpLCBmcm9tIHRoZSBNb2RlbCB3aXRoIFNDQUxFRCB0aW1lIGludmFyaWFudCBHaXNsYXNvbiBuYXR1cmFsIG1vcnRhbGl0aWVzIChGaXNoQmFzZSkuIn0NCmdncGxvdGx5KGdncGxvdChyZXNpZF9ubUdfU0ZiX2RmKSArDQogICAgICAgICAgIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0geWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBhZ2UsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gYWJzKHJlc2lkdWFsKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IHJlc2lkdWFsID49IDApLA0KICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC43KSArDQogICAgICAgICAgIGZhY2V0X2dyaWQocm93cyA9ICJmbGVldEFsdE5hbWUiKSArDQogICAgICAgICAgIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiVFJVRSIgPSBlYnBhbFs4XSwgIkZBTFNFIiA9IGVicGFsWzldKSkgKw0KICAgICAgICAgICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygtMSwgOSksIGJyZWFrcyA9IGMoMTo5KSkgKw0KICAgICAgICAgICBndWlkZXMoY29sb3VyPUZBTFNFKSArDQogICAgICAgICAgIHRoZW1lX2ZldygpKQ0KDQpgYGANCg0KIyMjIyBKaXR0ZXJpbmcNCldlIGNhbiBhbHNvIHRlc3QgdG8gc2VlIGlmIHRoZSBtb2RlbCBpcyBjb252ZXJnaW5nIG9uIHNvbWUgbG9jYWwgbWluaW11bSAoaS5lLiBpdCdzIGZpdHRpbmcgdG8gc29tZSBzb2x1dGlvbiBjbG9zZSB0byBpbml0aWFsaXNpbmcgdmFsdWVzIHRoYXQgcmVwcmVzZW50cyBub2lzZSBhbmQgbm90IHRoZSBnbG9iYWwgc29sdXRpb24sIHRoYXQgaXMgdGhlIHByb3BlciBzb2x1dGlvbikuICBUbyBkbyB0aGlzLCB3ZSBhZGQgcmFuZG9tIG5vaXNlIHRvIHRoZSBpbml0aWFsIHBhcmFtZXRlciB2YWx1ZXMgdG8gc2VlIGlmIHRoZSBtb2RlbCB3aWxsIGNvbnZlcmdlIG9uIGEgZGlmZmVyZW50IG1pbmltdW0gaW4gaXQncyBkYXRhLXNwYWNlLiBUaGUgZWFzaWVzdCB3YXkgdG8gaW52ZXN0aWdhdGUgdGhpcyBpcyB0byBzZWUgaWYgdGhlIG1vZGVsIGZpdHMgdmFyeSBhbG90IGRlcGVuZGluZyBvbiB0aGUgc3RhcnRpbmcgdmFsdWVzOg0KYGBge3IgSml0dGVyX25tR19TRmJ9DQpqaXRfbm1HX1NGYiA8LSBqaXQoZml0ID0gZml0X25tR19TRmIpDQoNCm10IDwtIGFzLmRhdGEuZnJhbWUobW9kZWx0YWJsZShqaXRfbm1HX1NGYikpDQptdCRtb2RlbCA8LSByb3duYW1lcyhtdCkNCnJvd25hbWVzKG10KSA8LSBOVUxMDQoNCmthYmxlKHggPSBtdCwNCiAgICAgIGRpZ2l0cyA9IDMsDQogICAgICBjYXB0aW9uID0gIk1lYXN1cmVzIG9mICBmaXQgZm9yIGEgc2VyaWVzIG9mIG1vZGVsIHJlZml0cyB3aXRoIGppdHRlciBhcHBsaWVkIHRvIHRoZSBpbnB1dCBwYXJhbWV0ZXJzLiIpDQpgYGANCg0KIyMjIyBMZWF2ZS1PbmUtT3V0IEFuYWx5c2VzDQpBIGxlYXZlLW9uZS1vdXQgYW5hbHlzaXMgaXMgYSBmb3JtIG9mIHNlbnNpdGl2aXR5IGFuYWx5c2lzLCBzaG93aW5nIHRoZSBpbXBhY3QgdGhlIGRhdGEgZnJvbSBlYWNoIHR1bmluZyBmbGVldCBoYXMgb24gdGhlIGVzdGltYXRpb24gb2YgdGhlIGtleSB2YXJpYWJsZXMgYmVpbmcgZXN0aW1hdGVkOyBuYW1lbHkgU1NCLCBGIGFuZCByZWNydWl0bWVudC4gIA0KDQpGaXJzdCB3ZSBtdXN0IHJ1biB0aGUgbGVhdmUtb25lLW91dCBhbmFseXNpcyB3aGljaCByZWZpdHMgdGhlIG1vZGVsIGluIHR3byBpdGVyYXRpb25zLCByZW1vdmluZyBvbmUgc3VydmV5IGF0IGEgdGltZS4gVGhlbiB3ZSBjYW4gcGxvdCBlYWNoIG9mIHRoZXNlIG5ldyBtb2RlbCBmaXRzIG92ZXIgdGhlIGZ1bGwgbW9kZWwgdG8gc2VlIHRoZSBpbXBhY3QgdGhlIHJlbW92YWwgb2YgZWFjaCBoYXMuIA0KDQpgYGB7ciBMZWF2ZU9uZU91dF9ubUdfU0ZifQ0KTE9fbm1HX1NGYiA8LSBsZWF2ZW91dChmaXRfbm1HX1NGYikNCg0KIz09PSANCiMgR2V0IGRhdGEgZnJvbSBzYW0gb2JqZWN0cyBhbmQgZ2VuZXJhdGUgdXNlYWJsZSBkYXRhZnJhbWVzDQojPT09PQ0KcTFtYXQgPC0gYXMuZGF0YS5mcmFtZShzdW1tYXJ5KExPX25tR19TRmIkYHcuby4gUTFJQlRTK0JJVFMrQ29kU0QyMS0yNWApKQ0KcTNtYXQgPC0gYXMuZGF0YS5mcmFtZShzdW1tYXJ5KExPX25tR19TRmIkYHcuby4gUTM0SUJUUytCSVRTK0NvZFNEMjEtMjVgKSkNCg0KDQp3b3ExIDwtIGRhdGEuZnJhbWUoWWVhciA9IGFzLmludGVnZXIocm93Lm5hbWVzKHN1bW1hcnkoTE9fbm1HX1NGYiRgdy5vLiBRMUlCVFMrQklUUytDb2RTRDIxLTI1YCkpKSwNCiAgICAgICAgICAgICAgICAgICBTU0IgPSBxMW1hdCRTU0IsDQogICAgICAgICAgICAgICAgICAgRmJhciA9IHExbWF0JGBGYmFyKDMtNSlgLA0KICAgICAgICAgICAgICAgICAgIFJfYWdlMSA9IHExbWF0JGBSKGFnZSAxKWAsDQogICAgICAgICAgICAgICAgICAgQ2F0Y2hFc3QgPSBjYXRjaHRhYmxlKExPX25tR19TRmIkYHcuby4gUTFJQlRTK0JJVFMrQ29kU0QyMS0yNWApWywxXSwNCiAgICAgICAgICAgICAgICAgICBzZXJpZXMgPSByZXAoIndvX1ExIiwgdGltZXMgPSBucm93KHExbWF0KSkpDQoNCndvcTM0IDwtIGRhdGEuZnJhbWUoWWVhciA9IGFzLmludGVnZXIocm93Lm5hbWVzKHEzbWF0WygyMDAyOkRhdGFZZWFyKS0yMDAxLF0pKSwNCiAgICAgICAgICAgICAgICAgICAgU1NCID0gcTNtYXRbKDIwMDI6RGF0YVllYXIpLTIwMDEsICJTU0IiXSwNCiAgICAgICAgICAgICAgICAgICAgRmJhciA9IHEzbWF0WygyMDAyOkRhdGFZZWFyKS0yMDAxLCJGYmFyKDMtNSkiXSwNCiAgICAgICAgICAgICAgICAgICAgUl9hZ2UxID0gcTNtYXRbKDIwMDI6RGF0YVllYXIpLTIwMDEsIlIoYWdlIDEpIl0sDQogICAgICAgICAgICAgICAgICAgIENhdGNoRXN0ID0gY2F0Y2h0YWJsZShMT19ubUdfU0ZiJGB3Lm8uIFEzNElCVFMrQklUUytDb2RTRDIxLTI1YClbLDFdLA0KICAgICAgICAgICAgICAgICAgICBzZXJpZXMgPSByZXAoIndvX1EzNCIsIHRpbWVzID0gKG5yb3cocTNtYXQpLTEpKSkNCg0KDQphc3VtX25tR19TRmIkc2VyaWVzIDwtIHJlcCgiZnVsbCIsIHRpbWVzID0gbnJvdyhhc3VtX25tR19TRmIpKQ0KYXN1bWlfbm1HX1NGYiA8LSBhc3VtX25tR19TRmJbLCBjKCJZZWFyIiwgIlNTQiIsICJGYmFyIiwgIlJfYWdlMSIsICJDYXRjaEVzdCIgLCJzZXJpZXMiKV0NCiM9PT09PQ0KDQpsb3N1bV9ubUdfU0ZiIDwtIHJiaW5kKHdvcTEsIHdvcTM0LCBhc3VtaV9ubUdfU0ZiKQ0KDQpgYGANCg0KYGBge3IgZmlnLmNhcD0iTGVhdmUtb25lLW91dCByZS1maXRzIGZvciB0aGUgVGltZSBpbnZhcmlhbnQsIHNjYWxlZCwgR2lzbGFzb24gbmF0dXJhbCBtb3J0YWxpdGllcyBjYWxjdWxhdGVkIGZyb20gbGlmZS1oaXN0b3J5IG9mZiBvZiBmaXNoYmFzZSAod2l0aG91dCBRMSBzdXJ2ZXkgPSBibHVlLCB3aXRob3V0IFEzLzQgc3VydmV5ID0gcHVycGxlKSwgb3ZlcmxhaW4gd2l0aCBmdWxsIG1vZGVsIGVzdGltYXRlcyAoYmxhY2sgbGluZSBhbmQgZ3JleSByaWJib24pIG9mIFNTQiAodG9wIGxlZnQpLCBGICh0b3AgcmlnaHQpLCBSZWNydWl0bWVudCAoYm90dG9tIGxlZnQpLCBhbmQgY2F0Y2ggKGJvdHRvbSByaWdodDsgb2JzZXJ2YXRpb25zIGFzIHllbGxvdyArKS4ifQ0KIyBzc2JwbG90KExPKQ0KbG9zc2Jfbm1HX1NGYiA8LSBnZ3Bsb3RseShnZ3Bsb3QoKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9saW5lKGRhdGEgPSBsb3N1bV9ubUdfU0ZiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PVNTQiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBzZXJpZXMpKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9yaWJib24oZGF0YSA9IGFzdW1fbm1HX1NGYiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW49U1NCbG93LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1heD1TU0JoaWdoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gImJsYWNrIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMikgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiYmxhY2siLCBlYnBhbFs4OjldKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2NsZWFuKCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKGF4aXMudGl0bGUueS5sZWZ0ID0gZWxlbWVudF90ZXh0KHZqdXN0ID0gLTAuMDUsIGhqdXN0ID0gMC45NSkpKQ0KDQojIEZwbG90KExPKQ0KbG9mX25tR19TRmIgPC0gZ2dwbG90bHkoZ2dwbG90KCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IGxvc3VtX25tR19TRmIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1GYmFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBzZXJpZXMpKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fcmliYm9uKGRhdGEgPSBhc3VtX25tR19TRmIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW49RmxvdywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4PUZoaWdoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9ICJibGFjayIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4zKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiYmxhY2siLCBlYnBhbFs4OjldKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9jbGVhbigpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWUoYXhpcy50aXRsZS55LmxlZnQgPSBlbGVtZW50X3RleHQodmp1c3QgPSAtMC4wNSwgaGp1c3QgPSAwLjk1KSkpDQoNCiMgcmVjcGxvdChMTykNCmxvcmVjX25tR19TRmIgPC0gZ2dwbG90bHkoZ2dwbG90KCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fbGluZShkYXRhID0gbG9zdW1fbm1HX1NGYiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1SX2FnZTEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gc2VyaWVzKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fcmliYm9uKGRhdGEgPSBhc3VtX25tR19TRmIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWluPVJsb3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4PVJoaWdoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gImJsYWNrIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMykgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiYmxhY2siLCBlYnBhbFs4OjldKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2NsZWFuKCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKGF4aXMudGl0bGUueS5sZWZ0ID0gZWxlbWVudF90ZXh0KHZqdXN0ID0gLTAuMDUsIGhqdXN0ID0gMC45NSkpKQ0KDQojIENhdGNoIHBsb3QgKExPKQ0KbG9jYV9ubUdfU0ZiIDwtIGdncGxvdGx5KGdncGxvdCgpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fbGluZShkYXRhID0gbG9zdW1fbm1HX1NGYiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9Q2F0Y2hFc3QsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBzZXJpZXMpKSsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fcmliYm9uKGRhdGEgPSBhc3VtX25tR19TRmJbYXN1bV9ubUdfU0ZiJFllYXIgIT0gKERhdGFZZWFyKzEpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW49Q2F0Y2hsb3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltYXg9Q2F0Y2hoaWdoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSAiYmxhY2siLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjMpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fcG9pbnQoZGF0YSA9IGFzdW1fbm1HX1NGYlthc3VtX25tR19TRmIkWWVhciAhPSAoRGF0YVllYXIrMSksIF0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9Q2F0Y2hPYnMpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaGFwZSA9IDMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IGVicGFsWzVdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gZWJwYWxbNV0pICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHlsYWIoIkNhdGNoICh0b25uZXMpIikgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCJibGFjayIsIGVicGFsWzg6OV0pKSsgDQogICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9jbGVhbigpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKGF4aXMudGl0bGUueS5sZWZ0ID0gZWxlbWVudF90ZXh0KHZqdXN0ID0gLTAuMDUsIGhqdXN0ID0gMC45NSkpKQ0KDQpsYXlvdXQoc3VicGxvdChsb3NzYl9ubUdfU0ZiLCBsb2Zfbm1HX1NGYiwgbG9yZWNfbm1HX1NGYiwgbG9jYV9ubUdfU0ZiLCBucm93cyA9IDIsIHNoYXJlWCA9IFRSVUUsIHRpdGxlWSA9IFRSVUUpLCBzaG93bGVnZW5kPUZBTFNFKQ0KYGBgDQoNCiMjIyMgUmV0cm9zcGVjdGl2ZXMNCmBgYHtyIGNhbGN1bGF0ZVJldHJvc19ubUdfU0ZifQ0KIz09PQ0KIyBDcmVhdGUgZGF0YWZyYW1lIG9mIGN1cnJlbnQgeWVhcidzIGZpdCBmb3IgcGxvdHRpbmcNCiM9PT09DQojIElDX2FnZ190ZW1wIDwtIGFnZ3JlZ2F0ZShDQVRPTn5ZZWFyLCBpY19jbGVhbltpY19jbGVhbiRDYXRjaENhdGVnb3J5ICVpbiUgYygiTGFuZGluZ3MiLCAiRGlzY2FyZHMiKSwgXSwgRlVOID0gInN1bSIpDQphc3VtX25tR19TRmIgPC0gYXMuZGF0YS5mcmFtZShzdW1tYXJ5KGZpdF9ubUdfU0ZiKSkNCmFzdW1fbm1HX1NGYiRZZWFyIDwtIGFzLmludGVnZXIocm93Lm5hbWVzKHN1bW1hcnkoZml0X25tR19TRmIpKSkNCmN0X25tR19TRmIgPC0gYXMuZGF0YS5mcmFtZShjYXRjaHRhYmxlKGZpdF9ubUdfU0ZiLCBvYnMuc2hvdyA9IFRSVUUpKQ0KY3Rfbm1HX1NGYiRZZWFyIDwtIGFzLmludGVnZXIocm93bmFtZXMoY3Rfbm1HX1NGYikpDQpyb3duYW1lcyhjdF9ubUdfU0ZiKSA8LSBOVUxMDQpjdF9ubUdfU0ZiIDwtIHJiaW5kKGN0X25tR19TRmIsIGRhdGEuZnJhbWUoRXN0aW1hdGUgPSBOQSwgTG93PU5BLCBIaWdoPU5BLCBzb3AuY2F0Y2g9TkEsIFllYXI9YXMuaW50ZWdlcigyMDI0KSkpDQphc3VtX25tR19TRmIgPC0gbWVyZ2UoeCA9IGFzdW1fbm1HX1NGYiwgeSA9IGN0X25tR19TRmIsIGJ5ID0gIlllYXIiKQ0KY29sbmFtZXMoYXN1bV9ubUdfU0ZiKSA8LSBjKCJZZWFyIiwgIlJfYWdlMSIsICJSbG93IiwgIlJoaWdoIiwgIlNTQiIsICJTU0Jsb3ciLCAiU1NCaGlnaCIsICJGYmFyIiwgIkZsb3ciLCAiRmhpZ2giLCAiQ2F0Y2hFc3QiLCAiQ2F0Y2hsb3ciLCAiQ2F0Y2hoaWdoIiwgIkNhdGNoT2JzIikNCg0KYXN1bV9ubUdfU0ZiJHNlcmllcyA8LSByZXAoImZ1bGwiLCB0aW1lcyA9IG5yb3coYXN1bV9ubUdfU0ZiKSkNCg0KIz09PT09DQpSRVRST19ubUdfU0ZiPC1yZXRybyhmaXRfbm1HX1NGYiwgeWVhcj01KQ0KcmhvX25tR19TRmIgPC0gbW9obihSRVRST19ubUdfU0ZiLCBsYWcgPSAxKQ0KDQojIyBNYWtlIFJFVFJPcyBpbiBiZXR0ZXIgcGxvdHRpbmcgZm9ybWF0DQpyZXRfbm1HX1NGYl9kZiA8LSBhc3VtX25tR19TRmJbYXN1bV9ubUdfU0ZiJFllYXIgIT0gbWF4KGFzdW1fbm1HX1NGYiRZZWFyKSwgXQ0KDQpmb3IoaSBpbiAxOmxlbmd0aChSRVRST19ubUdfU0ZiKSl7DQogIHRzdW0gPC0gYXMuZGF0YS5mcmFtZShzdW1tYXJ5KFJFVFJPX25tR19TRmJbW2ldXSkpDQogIHRzdW0kWWVhciA8LSBhcy5pbnRlZ2VyKHJvdy5uYW1lcyhzdW1tYXJ5KFJFVFJPX25tR19TRmJbW2ldXSkpKQ0KICB0c3VtIDwtIGNiaW5kKHRzdW0sIGNhdGNodGFibGUoUkVUUk9fbm1HX1NGYltbaV1dLCBvYnMuc2hvdyA9IFRSVUUpKQ0KICB0c3VtJHNlcmllcyA8LSBhcy5jaGFyYWN0ZXIocmVwKGksIG5yb3codHN1bSkpKQ0KICBjb2xuYW1lcyh0c3VtKSA8LSBjKCJSX2FnZTEiLCAiUmxvdyIsICJSaGlnaCIsICJTU0IiLCAiU1NCbG93IiwgIlNTQmhpZ2giLCAiRmJhciIsICJGbG93IiwgIkZoaWdoIiwgIlllYXIiLCAiQ2F0Y2hFc3QiLCAiQ2F0Y2hsb3ciLCAiQ2F0Y2hoaWdoIiwgIkNhdGNoT2JzIiwgInNlcmllcyIpDQogIHRzdW0gPC0gdHN1bVt0c3VtJFllYXIgIT0gbWF4KHRzdW0kWWVhciksIF0NCiAgcmV0X25tR19TRmJfZGYgPC0gcmJpbmQocmV0X25tR19TRmJfZGYsIHRzdW0pDQp9DQpyZXRfbm1HX1NGYl9kZiRzZXJpZXMgPC0gZmFjdG9yKHJldF9ubUdfU0ZiX2RmJHNlcmllcywgbGV2ZWxzID0gYygiZnVsbCIsICIxIiwgIjIiLCAiMyIsICI0IiwgIjUiKSkNCmBgYA0KDQpgYGB7ciBmaWcuY2FwPSJSZXRyb3NwZWN0aXZlIGFuYWx5c2VzIGZvciBTU0IgKHRvcC1sZWZ0KSwgRiBmb3IgYWdlcyAzLTUgKHRvcC1yaWdodCksIHJlY3J1aXRtZW50IChib3R0b20tbGVmdCksIGFuZCBjYXRjaCAoYm90dG9tLXJpZ2h0KSwgZnJvbSB0aGUgbW9kZWwgdXRpbGlzaW5nIFNDQUxFRCB0aW1lIGludmFyaWFudCwgR2lzbGFzb24gbmF0dXJhbCBtb3J0YWxpdGllcyAoRmlzaEJhc2UpLiJ9DQojIHNzYnBsb3QoUkVUUk8pDQpyZXRzc2Jfbm1HX1NGYiA8LSBsYXlvdXQoZ2dwbG90bHkoZ2dwbG90KCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9saW5lKGRhdGEgPSByZXRfbm1HX1NGYl9kZiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9U1NCLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gc2VyaWVzKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9yaWJib24oZGF0YSA9IGFzdW1fbm1HX1NGYlthc3VtX25tR19TRmIkWWVhciAhPSBtYXgoYXN1bV9ubUdfU0ZiJFllYXIpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW49U1NCbG93LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4PVNTQmhpZ2gpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9ICJibGFjayIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMikgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYW5ub3RhdGUoZ2VvbSA9ICJ0ZXh0IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBtYXgocmV0X25tR19TRmJfZGYkU1NCaGlnaCkqMC44NSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHggPSAoKG1heChyZXRfbm1HX1NGYl9kZiRZZWFyKS1taW4ocmV0X25tR19TRmJfZGYkWWVhcikpKjAuMjApK21pbihyZXRfbm1HX1NGYl9kZiRZZWFyKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsID0gcGFzdGUwKCJNb2huJ3MgUmhvID0gIiwgcm91bmQocmhvX25tR19TRmJbMl0sIGRpZ2l0cyA9IDMpKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCJibGFjayIsIGVicGFsWyhsZW5ndGgoZWJwYWwpLTQpOmxlbmd0aChlYnBhbCldKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWVfY2xlYW4oKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBheGlzLnRpdGxlLnkubGVmdCA9IGVsZW1lbnRfdGV4dCh2anVzdCA9IC0wLjA1LCBoanVzdCA9IDAuOTUpKSksDQogICAgICAgICAgICAgICAgICAgICAgICAgc2hvd2xlZ2VuZCA9IEZBTFNFKQ0KDQojIEZwbG90KFJFVFJPKQ0KcmV0Zl9ubUdfU0ZiIDwtIGxheW91dChnZ3Bsb3RseShnZ3Bsb3QoKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9saW5lKGRhdGEgPSByZXRfbm1HX1NGYl9kZiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1GYmFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IHNlcmllcykpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3JpYmJvbihkYXRhID0gYXN1bV9ubUdfU0ZiW2FzdW1fbm1HX1NGYiRZZWFyICE9IG1heChhc3VtX25tR19TRmIkWWVhciksIF0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWluPUZsb3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4PUZoaWdoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gImJsYWNrIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMykgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFubm90YXRlKGdlb20gPSAidGV4dCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IG1heChyZXRfbm1HX1NGYl9kZiRGaGlnaCkqMC44NSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4ID0gKChtYXgocmV0X25tR19TRmJfZGYkWWVhciktbWluKHJldF9ubUdfU0ZiX2RmJFllYXIpKSowLjgwKSttaW4ocmV0X25tR19TRmJfZGYkWWVhciksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSBwYXN0ZTAoIk1vaG4ncyBSaG8gPSAiLCByb3VuZChyaG9fbm1HX1NGYlszXSwgZGlnaXRzID0gMykpKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCJibGFjayIsIGVicGFsWyhsZW5ndGgoZWJwYWwpLTQpOmxlbmd0aChlYnBhbCldKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2NsZWFuKCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBheGlzLnRpdGxlLnkubGVmdCA9IGVsZW1lbnRfdGV4dCh2anVzdCA9IC0wLjA1LCBoanVzdCA9IDAuOTUpKSksDQogICAgICAgICAgICAgICAgICAgICAgIHNob3dsZWdlbmQgPSBGQUxTRSkNCg0KIyByZWNwbG90KFJFVFJPKQ0KcmV0cmVjX25tR19TRmIgPC0gbGF5b3V0KGdncGxvdGx5KGdncGxvdCgpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fbGluZShkYXRhID0gcmV0X25tR19TRmJfZGYsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PVJfYWdlMSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IHNlcmllcykpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fcmliYm9uKGRhdGEgPSBhc3VtX25tR19TRmJbYXN1bV9ubUdfU0ZiJFllYXIgIT0gbWF4KGFzdW1fbm1HX1NGYiRZZWFyKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWluPVJsb3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltYXg9UmhpZ2gpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9ICJibGFjayIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMykgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYW5ub3RhdGUoZ2VvbSA9ICJ0ZXh0IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9IG1heChyZXRfbm1HX1NGYl9kZiRSaGlnaCkqMC44NSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHggPSAoKG1heChyZXRfbm1HX1NGYl9kZiRZZWFyKS1taW4ocmV0X25tR19TRmJfZGYkWWVhcikpKjAuMjApK21pbihyZXRfbm1HX1NGYl9kZiRZZWFyKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsID0gcGFzdGUwKCJNb2huJ3MgUmhvID0gIiwgcm91bmQocmhvX25tR19TRmJbMV0sIGRpZ2l0cyA9IDMpKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCJibGFjayIsIGVicGFsWyhsZW5ndGgoZWJwYWwpLTQpOmxlbmd0aChlYnBhbCldKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWVfY2xlYW4oKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBheGlzLnRpdGxlLnkubGVmdCA9IGVsZW1lbnRfdGV4dCh2anVzdCA9IC0wLjA1LCBoanVzdCA9IDAuOTUpKSksDQogICAgICAgICAgICAgICAgICAgICAgICAgc2hvd2xlZ2VuZCA9IEZBTFNFKQ0KDQojIENhdGNoIHBsb3QgKFJFVFJPKQ0KcmV0Y2Ffbm1HX1NGYiA8LSBnZ3Bsb3RseShnZ3Bsb3QoKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9saW5lKGRhdGEgPSByZXRfbm1HX1NGYl9kZiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1DYXRjaEVzdCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBzZXJpZXMpKSsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3JpYmJvbihkYXRhID0gYXN1bV9ubUdfU0ZiW2FzdW1fbm1HX1NGYiRZZWFyICE9IG1heChhc3VtX25tR19TRmIkWWVhciksIF0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWluPUNhdGNobG93LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1heD1DYXRjaGhpZ2gpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSAiYmxhY2siLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4zKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9wb2ludChkYXRhID0gYXN1bV9ubUdfU0ZiW2FzdW1fbm1HX1NGYiRZZWFyICE9IG1heChhc3VtX25tR19TRmIkWWVhciksIF0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1DYXRjaE9icyksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaGFwZSA9IDMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBlYnBhbFs1XSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBlYnBhbFs1XSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHlsYWIoIkNhdGNoICh0b25uZXMpIikgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiYmxhY2siLCBlYnBhbFsobGVuZ3RoKGVicGFsKS00KTpsZW5ndGgoZWJwYWwpXSkpKyANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9jbGVhbigpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZShheGlzLnRpdGxlLnkubGVmdCA9IGVsZW1lbnRfdGV4dCh2anVzdCA9IC0wLjA1LCBoanVzdCA9IDAuOTUpKSkNCg0KcmV0X2ZwIDwtIHN0eWxlKHN1YnBsb3QocmV0c3NiX25tR19TRmIsIHJldGZfbm1HX1NGYiwgcmV0cmVjX25tR19TRmIsIHJldGNhX25tR19TRmIsIG5yb3dzID0gMiwgc2hhcmVYID0gRkFMU0UsIHNoYXJlWSA9IEZBTFNFLCB0aXRsZVkgPSBUUlVFKSwNCiAgICAgICAgICAgICAgICBzaG93bGVnZW5kPUZBTFNFLA0KICAgICAgICAgICAgICAgIHRyYWNlcyA9IGMoODooKDcqNCkrMikpKQ0KDQpsYXlvdXQocmV0X2ZwLCBsZWdlbmQgPSBsaXN0KG9yaWVudGF0aW9uID0gJ2gnLCB4ID0gMC41LCB4YW5jaG9yID0gJ2NlbnRlcicsIHkgPSAtMC4wNSwgeWFuY2hvciA9ICd0b3AnLCBib3JkZXJ3aWR0aCA9IDApKQ0KYGBgDQoNCiMjIFRpbWUgYW5kIEFnZSBWYXJpYW50LCBHaXNsYXNvbiBOYXR1cmFsIE1vcnRhbGl0aWVzDQpBbiBhbHRlcm5hdGUgd2F5IHRvIGRlYWxpbmcgd2l0aCB0aGUgaXNzdWUgb2YgdGFraW5nIHRoZSB1bndlaWdodGVkIG1lYW5zIG92ZXIgdGhlIHRpbWUgc2VyaWVzIGlzIHRvIG5vdCB1c2UgdGhlIGZ1bGwgdGltZS1zZXJpZXMgbWVhbnMuIFdoaWxlIHRoZSBsaWZlLWhpc3RvcnkgcGFyYW1ldGVycyAkTF97XGluZnR5fSQgYW5kICRLJCBhcmUgY2FsY3VsYXRlZCBmcm9tIGFsbCBhZ2VzIG9ic2VydmF0aW9ucyAocTEgc3VydmV5cykgZm9yIHRoZSB3aG9sZSB0aW1lIHNlcmllcywgdGhleSBjYW4gYmUgYXBwbGllZCBpbiB0aGUgR2lzbGFzb24gbW9kZWwgdG8gc3BlY2lmaWMgeWVhcnMsIGJ5IHV0aWxpc2luZyB0aGUgbGVuZ3RocyBhdCBhZ2UgZm9yIGVhY2ggeWVhci4gIER1ZSB0byB0aGUgc2FtcGxpbmcgcmF0ZXMgdGhlc2UgZGF0YSB3aWxsIGJlIGluaGVyZW50bHkgbm9pc2V5LCBqdXN0IGFzIGlzIHRoZSBjYXNlIGZvciB0aGUgc3RvY2sgd2VpZ2h0cyBhdCBhZ2UgYW5kIHRoZSBtYXR1cml0eSBvZ2l2ZXMsIGhlbmNlIHdlIG5lZWQgc29tZSBtZXRob2Qgb2Ygc21vb3RoaW5nIG91dCB0aGlzIG5vaXNlLiAgSW4gdGhpcyBleGFtcGxlIHdlIHV0aWxpc2UgYSBmaXZlLXllYXIgc2xpZGluZyB3aW5kb3cgbWVhbiBvbiB0aGUgYW5udWFsIGVzdGltYXRlcyBvZiBuYXR1cmFsIG1vcnRhbGl0eSBhdCBhZ2UsIHRvIGFsbG93IG1vcnRhbGl0eSBhdCBhZ2UgdG8gdmFyeSBpbiB0aW1lIHdpdGhvdXQgaW50cm9kdWNpbmcgdG9vIG11Y2ggaW50ZXJhbm51YWwgdmFyaWF0aW9uLiANCg0KYGBge3Igbm1HNUZiRml0RnJvbVdlYn0NCmZpdF9ubUc1RmIgPC0gZml0ZnJvbXdlYigicGxlLjI3LjIxLTMyX1dLQlBMQUlDRV8yMDI0X0Jpb1BhcnN3X25tRzVGYiIpDQpgYGANCg0KYGBge3IgZGF0YWZyYW1lU3VtbWFyeV9ubUc1RmIsIHJlc3VsdHM9J2hpZGUnLCBmaWcuc2hvdz0naGlkZSd9DQojPT09DQojIENyZWF0ZSBkYXRhZnJhbWUgb2YgY3VycmVudCB5ZWFyJ3MgZml0IGZvciBwbG90dGluZw0KIz09PT0NCmFzdW1fbm1HNUZiIDwtIGFzLmRhdGEuZnJhbWUoc3VtbWFyeShmaXRfbm1HNUZiKSkNCmFzdW1fbm1HNUZiJFllYXIgPC0gYXMuaW50ZWdlcihyb3cubmFtZXMoc3VtbWFyeShmaXRfbm1HNUZiKSkpDQpjdF9ubUc1RmIgPC0gYXMuZGF0YS5mcmFtZShjYXRjaHRhYmxlKGZpdF9ubUc1RmIsIG9icy5zaG93ID0gVFJVRSkpDQpjdF9ubUc1RmIkWWVhciA8LSBhcy5pbnRlZ2VyKHJvd25hbWVzKGN0X25tRzVGYikpDQpyb3duYW1lcyhjdF9ubUc1RmIpIDwtIE5VTEwNCmN0X25tRzVGYiA8LSByYmluZChjdF9ubUc1RmIsIGRhdGEuZnJhbWUoRXN0aW1hdGUgPSBOQSwgTG93PU5BLCBIaWdoPU5BLCBzb3AuY2F0Y2g9TkEsIFllYXI9YXMuaW50ZWdlcigyMDI0KSkpDQphc3VtX25tRzVGYiA8LSBtZXJnZSh4ID0gYXN1bV9ubUc1RmIsIHkgPSBjdF9ubUc1RmIsIGJ5ID0gIlllYXIiKQ0KY29sbmFtZXMoYXN1bV9ubUc1RmIpIDwtIGMoIlllYXIiLCAiUl9hZ2UxIiwgIlJsb3ciLCAiUmhpZ2giLCAiU1NCIiwgIlNTQmxvdyIsICJTU0JoaWdoIiwgIkZiYXIiLCAiRmxvdyIsICJGaGlnaCIsICJDYXRjaEVzdCIsICJDYXRjaGxvdyIsICJDYXRjaGhpZ2giLCAiQ2F0Y2hPYnMiKQ0KIz09PT09DQpgYGANCg0KIyMjIEZpdHMgdG8gZGF0YQ0KV2hlbiB0aGUgbW9kZWwgaXMgcnVuIHdlIGNhbiBlYXNpbHkgc2VlIGZyb20gd2FybmluZ3MvZXJyb3JzIGlmIHRoZXJlIGlzIGEgY29udmVyZ2VuY2UgaXNzdWUuICBIb3dldmVyLCB3ZSBjYW4gYWxzbyBjb25maXJtIHRoaXMsIGV4cGxpY2l0bHk6DQotIFRoZSBmaW5hbCBtb2RlbCBncmFkaWVudDogYHIgZml0X25tRzVGYiRvcHQkZXZhbHVhdGlvbnNbMl1gDQotIFRoYXQgdGhlcmUgaXMgYSBwb3NpdGl2ZSBkZWZpbml0ZSBoZXNzaWFuOiBgciBhbGwoZWlnZW4oZml0X25tRzVGYiRvcHQkaGUpJHZhbHVlcyA+MClgDQoNCkZ1cnRoZXJtb3JlLCBTQU0gZG9lcyBub3QgdXRpbGlzZSAiYm91bmRzIiB3aGVuIGZpdHRpbmcgdGhlIG1vZGVsLCBhbmQgdGhlcmVmb3JlLCBhcyBzdGFuZGFyZCBjaGVjayBvZiB3aGV0aGVyIG1vZGVsIHBhcmFtZXRlcnMgYXJlIGFwcHJvYWNoaW5nIHRoZWlyIGJvdW5kcyBpcyBpcnJlbGV2YW50Lg0KDQpgYGB7ciBmaWcuY2FwPSJNb2RlbCB3aXRoIHRpbWUgdmFyeWluZyAoZml2ZSB5ZWFyIHNsaWlkaW5nIHdpbmRvdyBtZWFuKSwgYWdlIHZhcnlpbmcsIEdpc2xhc29uIG5hdHVyYWwgbW9ydGFsaXRpZXMgKEZpc2hCYXNlKSBmaXQgdG8gY2F0Y2ggZGF0YSBieSBhZ2UgKHZhbHVlcyBvbiB0aGUgbW9kZWwgbGluayBmdW5jdGlvbiBzY2FsZSkuIn0NCiMjIEV4dHJhY3QgZGF0YSBmcm9tIG1vZGVsIG9iamVjdA0KbG9nT2JzX25tRzVGYiA8LSBzcGxpdChmaXRfbm1HNUZiJGRhdGEkbG9nb2JzLCBjZWlsaW5nKHNlcV9hbG9uZyhmaXRfbm1HNUZiJGRhdGEkbG9nb2JzKS9maXRfbm1HNUZiJGRhdGEkbWF4QWdlUGVyRmxlZXRbMV0pKQ0KbG9nUHJlZF9ubUc1RmIgPC0gc3BsaXQoZml0X25tRzVGYiRyZXAkcHJlZE9icywgY2VpbGluZyhzZXFfYWxvbmcoZml0X25tRzVGYiRyZXAkcHJlZE9icykvZml0X25tRzVGYiRkYXRhJG1heEFnZVBlckZsZWV0WzFdKSkNCg0KIyMgVHJhbnNmb3JtIGRhdGEgdG8gdXNlYWJsZSBkYXRhZnJhbWVzDQojIyMgSW5pdGlhbGl6ZSBhbiBlbXB0eSBkYXRhIGZyYW1lIGZvciBvYnNlcnZhdGlvbnMNCmxvZ09ic19ubUc1RmJfZGYgPC0gZGF0YS5mcmFtZShhZ2UgPSBpbnRlZ2VyKCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmxlZXQgPSBpbnRlZ2VyKCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeWVhciA9IGludGVnZXIoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2dPYnMgPSBudW1lcmljKCkpDQoNCiMjIyBQb3B1bGF0ZSB0aGUgZGF0YSBmcmFtZSBmb3Igb2JzZXJ2YXRpb25zDQpmb3IgKGkgaW4gc2VxX2Fsb25nKGxvZ09ic19ubUc1RmIpKSB7DQogICMgQ2FsY3VsYXRlIHRoZSBncm91cCBhbmQgeWVhcg0KICB5ZWFyIDwtICgoaSAtIDEpICUvJSAzKSArIDENCiAgZmxlZXQgPC0gKChpIC0gMSkgJSUgMykgKyAxDQogIA0KICAjIyMgQ3JlYXRlIGEgdGVtcG9yYXJ5IGRhdGEgZnJhbWUgYW5kIGFwcGVuZCB0byB0aGUgbWFpbiBkYXRhIGZyYW1lIGZvciBvYnNlcnZhdGlvbnMNCiAgdGVtcF9kZiA8LSBkYXRhLmZyYW1lKGFnZSA9IDE6NywNCiAgICAgICAgICAgICAgICAgICAgICAgIGZsZWV0ID0gZmxlZXQsDQogICAgICAgICAgICAgICAgICAgICAgICB5ZWFyID0geWVhcisyMDAxLA0KICAgICAgICAgICAgICAgICAgICAgICAgbG9nT2JzID0gbG9nT2JzX25tRzVGYltbaV1dKQ0KICBsb2dPYnNfbm1HNUZiX2RmIDwtIHJiaW5kKGxvZ09ic19ubUc1RmJfZGYsIHRlbXBfZGYpDQp9DQoNCiMjIyBJbml0aWFsaXplIGFuIGVtcHR5IGRhdGEgZnJhbWUgZm9yIHByZWRpY3Rpb25zDQpsb2dQcmVkX25tRzVGYl9kZiA8LSBkYXRhLmZyYW1lKGFnZSA9IGludGVnZXIoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmxlZXQgPSBpbnRlZ2VyKCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllYXIgPSBpbnRlZ2VyKCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZ1ByZWQgPSBudW1lcmljKCkpDQoNCiMjIyBQb3B1bGF0ZSB0aGUgZGF0YSBmcmFtZSBmb3IgcHJlZGljdGlvbnMNCmZvciAoaSBpbiBzZXFfYWxvbmcobG9nUHJlZF9ubUc1RmIpKSB7DQogICMgQ2FsY3VsYXRlIHRoZSBncm91cCBhbmQgeWVhcg0KICB5ZWFyIDwtICgoaSAtIDEpICUvJSAzKSArIDENCiAgZmxlZXQgPC0gKChpIC0gMSkgJSUgMykgKyAxDQogIA0KICAjIyMgQ3JlYXRlIGEgdGVtcG9yYXJ5IGRhdGEgZnJhbWUgYW5kIGFwcGVuZCB0byB0aGUgbWFpbiBkYXRhIGZyYW1lIGZvciBwcmVkaWN0aW9ucw0KICB0ZW1wX2RmIDwtIGRhdGEuZnJhbWUoYWdlID0gMTo3LA0KICAgICAgICAgICAgICAgICAgICAgICAgZmxlZXQgPSBmbGVldCwNCiAgICAgICAgICAgICAgICAgICAgICAgIHllYXIgPSB5ZWFyKzIwMDEsDQogICAgICAgICAgICAgICAgICAgICAgICBsb2dQcmVkID0gbG9nUHJlZF9ubUc1RmJbW2ldXSkNCiAgbG9nUHJlZF9ubUc1RmJfZGYgPC0gcmJpbmQobG9nUHJlZF9ubUc1RmJfZGYsIHRlbXBfZGYpDQp9DQoNCiMjIFBsb3QNCmxvZ1ByZWRfbm1HNUZiX2RmJGFnZSA8LSBhcy5jaGFyYWN0ZXIobG9nUHJlZF9ubUc1RmJfZGYkYWdlKQ0KbG9nT2JzX25tRzVGYl9kZiRhZ2UgPC0gYXMuY2hhcmFjdGVyKGxvZ09ic19ubUc1RmJfZGYkYWdlKQ0KDQpnZ3Bsb3RseShnZ3Bsb3QoKSsNCiAgICAgICAgICAgZ2VvbV9wb2ludChkYXRhID0gbG9nT2JzX25tRzVGYl9kZltsb2dPYnNfbm1HNUZiX2RmJGZsZWV0ID09IDEgJiBsb2dPYnNfbm1HNUZiX2RmJHllYXIgIT0gKERhdGFZZWFyKzEpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IHllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gbG9nT2JzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gYWdlKSwNCiAgICAgICAgICAgICAgICAgICAgICBzaGFwZSA9IDIxKSArDQogICAgICAgICAgIGdlb21fbGluZShkYXRhID0gbG9nUHJlZF9ubUc1RmJfZGZbbG9nUHJlZF9ubUc1RmJfZGYkZmxlZXQgPT0gMSAmIGxvZ1ByZWRfbm1HNUZiX2RmJHllYXIgIT0gKERhdGFZZWFyKzEpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0geWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGxvZ1ByZWQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IGFnZSkpICsNCiAgICAgICAgICAgZmFjZXRfd3JhcChmYWNldHMgPSAiYWdlIikgKyAjLCBzY2FsZXMgPSAiZnJlZV95IikgKw0KICAgICAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gZWJwYWwsIGd1aWRlID0gRkFMU0UpICsNCiAgICAgICAgICAgZ3VpZGVzKGNvbG91cj1GQUxTRSwgc2hhcGU9RkFMU0UpICsNCiAgICAgICAgICAgdGhlbWVfZmV3KCkpDQoNCiMgZml0cGxvdChmaXRfbm1HNUZiLCBmbGVldHM9MSkNCmBgYA0KDQpgYGB7ciBmaWcuY2FwPSJNb2RlbCB3aXRoIHRpbWUgdmFyeWluZyAoZml2ZSB5ZWFyIHNsaWlkaW5nIHdpbmRvdyBtZWFuKSwgYWdlIHZhcnlpbmcsIEdpc2xhc29uIG5hdHVyYWwgbW9ydGFsaXRpZXMgKEZpc2hCYXNlKSBmaXQgdG8gUTEgc3VydmV5IGRhdGEgYnkgYWdlICh2YWx1ZXMgb24gdGhlIG1vZGVsIGxpbmsgZnVuY3Rpb24gc2NhbGUpLiJ9DQpnZ3Bsb3RseShnZ3Bsb3QoKSsNCiAgICAgICAgICAgZ2VvbV9wb2ludChkYXRhID0gbG9nT2JzX25tRzVGYl9kZltsb2dPYnNfbm1HNUZiX2RmJGZsZWV0ID09IDIgJiBsb2dPYnNfbm1HNUZiX2RmJHllYXIgIT0gKERhdGFZZWFyKzEpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IHllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gbG9nT2JzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gYWdlKSwNCiAgICAgICAgICAgICAgICAgICAgICBzaGFwZSA9IDIxKSArDQogICAgICAgICAgIGdlb21fbGluZShkYXRhID0gbG9nUHJlZF9ubUc1RmJfZGZbbG9nUHJlZF9ubUc1RmJfZGYkZmxlZXQgPT0gMiAmIGxvZ1ByZWRfbm1HNUZiX2RmJHllYXIgIT0gKERhdGFZZWFyKzEpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0geWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGxvZ1ByZWQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IGFnZSkpICsNCiAgICAgICAgICAgZmFjZXRfd3JhcChmYWNldHMgPSAiYWdlIikgKyAjLCBzY2FsZXMgPSAiZnJlZV95IikgKw0KICAgICAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gZWJwYWwsIGd1aWRlID0gRkFMU0UpICsNCiAgICAgICAgICAgZ3VpZGVzKGNvbG91cj1GQUxTRSwgc2hhcGU9RkFMU0UpICsNCiAgICAgICAgICAgdGhlbWVfZmV3KCkpDQojIGZpdHBsb3QoZml0X25tRzVGYiwgZmxlZXRzPTIpDQpgYGANCg0KYGBge3IgZmlnLmNhcD0iTW9kZWwgd2l0aCB0aW1lIHZhcnlpbmcgKGZpdmUgeWVhciBzbGlpZGluZyB3aW5kb3cgbWVhbiksIGFnZSB2YXJ5aW5nLCBHaXNsYXNvbiBuYXR1cmFsIG1vcnRhbGl0aWVzIChGaXNoQmFzZSkgZml0IHRvIFEzLzQgc3VydmV5IGRhdGEgYnkgYWdlICh2YWx1ZXMgb24gdGhlIG1vZGVsIGxpbmsgZnVuY3Rpb24gc2NhbGUpLiJ9DQpnZ3Bsb3RseShnZ3Bsb3QoKSsNCiAgICAgICAgICAgZ2VvbV9wb2ludChkYXRhID0gbG9nT2JzX25tRzVGYl9kZltsb2dPYnNfbm1HNUZiX2RmJGZsZWV0ID09IDMgJiBsb2dPYnNfbm1HNUZiX2RmJHllYXIgIT0gKERhdGFZZWFyKzEpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IHllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gbG9nT2JzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gYWdlKSwNCiAgICAgICAgICAgICAgICAgICAgICBzaGFwZSA9IDIxKSArDQogICAgICAgICAgIGdlb21fbGluZShkYXRhID0gbG9nUHJlZF9ubUc1RmJfZGZbbG9nUHJlZF9ubUc1RmJfZGYkZmxlZXQgPT0gMyAmIGxvZ1ByZWRfbm1HNUZiX2RmJHllYXIgIT0gKERhdGFZZWFyKzEpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0geWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGxvZ1ByZWQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IGFnZSkpICsNCiAgICAgICAgICAgZmFjZXRfd3JhcChmYWNldHMgPSAiYWdlIikgKyAjLCBzY2FsZXMgPSAiZnJlZV95IikgKw0KICAgICAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gZWJwYWwsIGd1aWRlID0gRkFMU0UpICsNCiAgICAgICAgICAgZ3VpZGVzKGNvbG91cj1GQUxTRSwgc2hhcGU9RkFMU0UpICsNCiAgICAgICAgICAgdGhlbWVfZmV3KCkpDQoNCiMgZml0cGxvdChmaXRfbm1HNUZiLCBmbGVldHM9MykNCmBgYA0KDQpgYGB7ciBmaWcuY2FwPSJTdGFuZGFyZCBEZXZhdGlvbnMgYnkgRmxlZXQ7IEdpc2xhc29uLCB0aW1lLXZhcnlpbmcgbW9ydGFsaXR5IChGaXNoQmFzZSkiLCBoZWlnaHQ9MTB9DQpzZHBsb3QoZml0X25tRzVGYiwgbWFyZyA9IGMoNSw0LDEsMSkpDQpgYGANCg0KIyMjIFJlc2lkdWFscw0KYGBge3IgY2FsY3VsYXRlUmVzaWR1YWxzX25tRzVGYiwgd2FybmluZz1GQUxTRSwgcmVzdWx0cz0naGlkZSd9DQpyZXNpZF9ubUc1RmIgPC0gcmVzaWR1YWxzKGZpdF9ubUc1RmIpDQpyZXNpZF9ubUc1RmJfZGYgPC0gZGF0YS5mcmFtZSh5ZWFyID0gcmVzaWRfbm1HNUZiJHllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmbGVldCA9IHJlc2lkX25tRzVGYiRmbGVldCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFnZSA9IHJlc2lkX25tRzVGYiRhZ2UsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvYnNlcnZhdGlvbiA9IHJlc2lkX25tRzVGYiRvYnNlcnZhdGlvbiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1lYW4gPSByZXNpZF9ubUc1RmIkbWVhbiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc2lkdWFsID0gcmVzaWRfbm1HNUZiJHJlc2lkdWFsKQ0KcmVzaWRfbm1HNUZiX2RmJGZsZWV0TmFtZSA8LSBpZmVsc2UocmVzaWRfbm1HNUZiX2RmJGZsZWV0ID09IDEsIGF0dHJpYnV0ZXMocmVzaWRfbm1HNUZiKSRmbGVldE5hbWVzWzFdLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShyZXNpZF9ubUc1RmJfZGYkZmxlZXQgPT0gMiwgYXR0cmlidXRlcyhyZXNpZF9ubUc1RmIpJGZsZWV0TmFtZXNbMl0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShyZXNpZF9ubUc1RmJfZGYkZmxlZXQgPT0gMywgYXR0cmlidXRlcyhyZXNpZF9ubUc1RmIpJGZsZWV0TmFtZXNbM10sIE5BKSkpDQoNCnJlc2lkX25tRzVGYl9kZiRmbGVldEFsdE5hbWUgPC0gaWZlbHNlKHJlc2lkX25tRzVGYl9kZiRmbGVldCA9PSAxLCAiUmVzaWR1YWwgRmlzaGluZyIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKHJlc2lkX25tRzVGYl9kZiRmbGVldCA9PSAyLCAiUTEgU3VydmV5cyIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShyZXNpZF9ubUc1RmJfZGYkZmxlZXQgPT0gMywgIlEzLzQgU3VydmV5cyIsIE5BKSkpDQpgYGANCg0KYGBge3IgZmlnLmNhcD0iRXN0aW1hdGVkIGNvcnJlbGF0aW9ucyBpbiByZXNpZHVhbCB2YXJpYXRpb24gYmV0d2VlbiBhZ2VzIGZvciBlYWNoIG9mIHRoZSBmaXNoaW5nIGZsZWV0ICh0b3ApIGFuZCB0aGUgdHdvIHN1cnZleXMgKG1pZGRsZSAmIGJvdHRvbSksIGZyb20gdGhlIE1vZGVsIHdpdGggdGltZSB2YXJ5aW5nIChmaXZlIHllYXIgc2xpaWRpbmcgd2luZG93IG1lYW4pLCBhZ2UgdmFyeWluZywgR2lzbGFzb24gbmF0dXJhbCBtb3J0YWxpdGllcyAoRmlzaEJhc2UpLiJ9DQoNCmlmKCFhbGwoZml0X25tRzVGYiRjb25mJG9ic0NvclN0cnVjdD09IklEIikpeyANCiAgY29ycGxvdChmaXRfbm1HNUZiKQkJCSAgDQogICMgc2V0Y2FwKCJFc3RpbWF0ZWQgY29ycmVsYXRpb25zIiwgIkVzdGltYXRlcyBjb3JyZWxhdGlvbnMgYmV0d2VlbiBhZ2UgZ3JvdXBzIGZvciBlYWNoIGZsZWV0IikNCiAgIyBzdGFtcGl0KGZpdCkNCn0gZWxzZSB7DQogIHByaW50KCJObyBjb3JyZWxhdGlvbiBzdHJ1Y3R1cmUgY29uZmlndXJlZCBmb3IgcmVzaWR1YWxzIGFjcm9zcyBhZ2UuIikNCn0NCg0KYGBgDQoNCmBgYHtyIGZpZy5jYXA9Ik9uZSBvYnNlcnZhdGlvbiBhaGVhZCByZXNpZHVhbHMgZm9yIHRoZSB0aHJlZSBmbGVldHMgKHJlZC9waW5rID0gb2JzZXJ2YXRpb24gbG93ZXIgdGhhbiBtb2RlbCBlc3RpbWF0ZSwgYmx1ZSA9IG9ic2VydmF0aW9uIGhpZ2hlciB0aGFuIG1vZGVsIGVzdGltYXRlLCBzaXplID0gbWFnbml0dWRlIG9mIHJlc2lkdWFsKSwgZnJvbSB0aGUgTW9kZWwgd2l0aCB0aW1lIHZhcnlpbmcgKGZpdmUgeWVhciBzbGlpZGluZyB3aW5kb3cgbWVhbiksIGFnZSB2YXJ5aW5nLCBHaXNsYXNvbiBuYXR1cmFsIG1vcnRhbGl0aWVzIChGaXNoQmFzZSkuIn0NCmdncGxvdGx5KGdncGxvdChyZXNpZF9ubUc1RmJfZGYpICsNCiAgICAgICAgICAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSB5ZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGFnZSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSBhYnMocmVzaWR1YWwpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gcmVzaWR1YWwgPj0gMCksDQogICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjcpICsNCiAgICAgICAgICAgZmFjZXRfZ3JpZChyb3dzID0gImZsZWV0QWx0TmFtZSIpICsNCiAgICAgICAgICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCJUUlVFIiA9IGVicGFsWzhdLCAiRkFMU0UiID0gZWJwYWxbOV0pKSArDQogICAgICAgICAgIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKC0xLCA5KSwgYnJlYWtzID0gYygxOjkpKSArDQogICAgICAgICAgIGd1aWRlcyhjb2xvdXI9RkFMU0UpICsNCiAgICAgICAgICAgdGhlbWVfZmV3KCkpDQoNCmBgYA0KDQojIyMjIEppdHRlcmluZw0KV2UgY2FuIGFsc28gdGVzdCB0byBzZWUgaWYgdGhlIG1vZGVsIGlzIGNvbnZlcmdpbmcgb24gc29tZSBsb2NhbCBtaW5pbXVtIChpLmUuIGl0J3MgZml0dGluZyB0byBzb21lIHNvbHV0aW9uIGNsb3NlIHRvIGluaXRpYWxpc2luZyB2YWx1ZXMgdGhhdCByZXByZXNlbnRzIG5vaXNlIGFuZCBub3QgdGhlIGdsb2JhbCBzb2x1dGlvbiwgdGhhdCBpcyB0aGUgcHJvcGVyIHNvbHV0aW9uKS4gIFRvIGRvIHRoaXMsIHdlIGFkZCByYW5kb20gbm9pc2UgdG8gdGhlIGluaXRpYWwgcGFyYW1ldGVyIHZhbHVlcyB0byBzZWUgaWYgdGhlIG1vZGVsIHdpbGwgY29udmVyZ2Ugb24gYSBkaWZmZXJlbnQgbWluaW11bSBpbiBpdCdzIGRhdGEtc3BhY2UuIFRoZSBlYXNpZXN0IHdheSB0byBpbnZlc3RpZ2F0ZSB0aGlzIGlzIHRvIHNlZSBpZiB0aGUgbW9kZWwgZml0cyB2YXJ5IGFsb3QgZGVwZW5kaW5nIG9uIHRoZSBzdGFydGluZyB2YWx1ZXM6DQpgYGB7ciBKaXR0ZXJfbm1HNUZifQ0Kaml0X25tRzVGYiA8LSBqaXQoZml0ID0gZml0X25tRzVGYikNCg0KbXQgPC0gYXMuZGF0YS5mcmFtZShtb2RlbHRhYmxlKGppdF9ubUc1RmIpKQ0KbXQkbW9kZWwgPC0gcm93bmFtZXMobXQpDQpyb3duYW1lcyhtdCkgPC0gTlVMTA0KDQprYWJsZSh4ID0gbXQsDQogICAgICBkaWdpdHMgPSAzLA0KICAgICAgY2FwdGlvbiA9ICJNZWFzdXJlcyBvZiAgZml0IGZvciBhIHNlcmllcyBvZiBtb2RlbCByZWZpdHMgd2l0aCBqaXR0ZXIgYXBwbGllZCB0byB0aGUgaW5wdXQgcGFyYW1ldGVycy4iKQ0KYGBgDQoNCiMjIyMgTGVhdmUtT25lLU91dCBBbmFseXNlcw0KQSBsZWF2ZS1vbmUtb3V0IGFuYWx5c2lzIGlzIGEgZm9ybSBvZiBzZW5zaXRpdml0eSBhbmFseXNpcywgc2hvd2luZyB0aGUgaW1wYWN0IHRoZSBkYXRhIGZyb20gZWFjaCB0dW5pbmcgZmxlZXQgaGFzIG9uIHRoZSBlc3RpbWF0aW9uIG9mIHRoZSBrZXkgdmFyaWFibGVzIGJlaW5nIGVzdGltYXRlZDsgbmFtZWx5IFNTQiwgRiBhbmQgcmVjcnVpdG1lbnQuICANCg0KRmlyc3Qgd2UgbXVzdCBydW4gdGhlIGxlYXZlLW9uZS1vdXQgYW5hbHlzaXMgd2hpY2ggcmVmaXRzIHRoZSBtb2RlbCBpbiB0d28gaXRlcmF0aW9ucywgcmVtb3Zpbmcgb25lIHN1cnZleSBhdCBhIHRpbWUuIFRoZW4gd2UgY2FuIHBsb3QgZWFjaCBvZiB0aGVzZSBuZXcgbW9kZWwgZml0cyBvdmVyIHRoZSBmdWxsIG1vZGVsIHRvIHNlZSB0aGUgaW1wYWN0IHRoZSByZW1vdmFsIG9mIGVhY2ggaGFzLiANCg0KYGBge3IgTGVhdmVPbmVPdXRfbm1HNUZifQ0KTE9fbm1HNUZiIDwtIGxlYXZlb3V0KGZpdF9ubUc1RmIpDQoNCiM9PT0gDQojIEdldCBkYXRhIGZyb20gc2FtIG9iamVjdHMgYW5kIGdlbmVyYXRlIHVzZWFibGUgZGF0YWZyYW1lcw0KIz09PT0NCnExbWF0IDwtIGFzLmRhdGEuZnJhbWUoc3VtbWFyeShMT19ubUc1RmIkYHcuby4gUTFJQlRTK0JJVFMrQ29kU0QyMS0yNWApKQ0KcTNtYXQgPC0gYXMuZGF0YS5mcmFtZShzdW1tYXJ5KExPX25tRzVGYiRgdy5vLiBRMzRJQlRTK0JJVFMrQ29kU0QyMS0yNWApKQ0KDQoNCndvcTEgPC0gZGF0YS5mcmFtZShZZWFyID0gYXMuaW50ZWdlcihyb3cubmFtZXMoc3VtbWFyeShMT19ubUc1RmIkYHcuby4gUTFJQlRTK0JJVFMrQ29kU0QyMS0yNWApKSksDQogICAgICAgICAgICAgICAgICAgU1NCID0gcTFtYXQkU1NCLA0KICAgICAgICAgICAgICAgICAgIEZiYXIgPSBxMW1hdCRgRmJhcigzLTUpYCwNCiAgICAgICAgICAgICAgICAgICBSX2FnZTEgPSBxMW1hdCRgUihhZ2UgMSlgLA0KICAgICAgICAgICAgICAgICAgIENhdGNoRXN0ID0gY2F0Y2h0YWJsZShMT19ubUc1RmIkYHcuby4gUTFJQlRTK0JJVFMrQ29kU0QyMS0yNWApWywxXSwNCiAgICAgICAgICAgICAgICAgICBzZXJpZXMgPSByZXAoIndvX1ExIiwgdGltZXMgPSBucm93KHExbWF0KSkpDQoNCndvcTM0IDwtIGRhdGEuZnJhbWUoWWVhciA9IGFzLmludGVnZXIocm93Lm5hbWVzKHEzbWF0WygyMDAyOkRhdGFZZWFyKS0yMDAxLF0pKSwNCiAgICAgICAgICAgICAgICAgICAgU1NCID0gcTNtYXRbKDIwMDI6RGF0YVllYXIpLTIwMDEsICJTU0IiXSwNCiAgICAgICAgICAgICAgICAgICAgRmJhciA9IHEzbWF0WygyMDAyOkRhdGFZZWFyKS0yMDAxLCJGYmFyKDMtNSkiXSwNCiAgICAgICAgICAgICAgICAgICAgUl9hZ2UxID0gcTNtYXRbKDIwMDI6RGF0YVllYXIpLTIwMDEsIlIoYWdlIDEpIl0sDQogICAgICAgICAgICAgICAgICAgIENhdGNoRXN0ID0gY2F0Y2h0YWJsZShMT19ubUc1RmIkYHcuby4gUTM0SUJUUytCSVRTK0NvZFNEMjEtMjVgKVssMV0sDQogICAgICAgICAgICAgICAgICAgIHNlcmllcyA9IHJlcCgid29fUTM0IiwgdGltZXMgPSAobnJvdyhxM21hdCktMSkpKQ0KDQoNCmFzdW1fbm1HNUZiJHNlcmllcyA8LSByZXAoImZ1bGwiLCB0aW1lcyA9IG5yb3coYXN1bV9ubUc1RmIpKQ0KYXN1bWlfbm1HNUZiIDwtIGFzdW1fbm1HNUZiWywgYygiWWVhciIsICJTU0IiLCAiRmJhciIsICJSX2FnZTEiLCAiQ2F0Y2hFc3QiICwic2VyaWVzIildDQojPT09PT0NCg0KbG9zdW1fbm1HNUZiIDwtIHJiaW5kKHdvcTEsIHdvcTM0LCBhc3VtaV9ubUc1RmIpDQoNCmBgYA0KDQpgYGB7ciBmaWcuY2FwPSJMZWF2ZS1vbmUtb3V0IHJlLWZpdHMgZm9yIHRoZSBUaW1lIHZhcnlpbmcsIEdpc2xhc29uIG5hdHVyYWwgbW9ydGFsaXRpZXMgY2FsY3VsYXRlZCBmcm9tIGxpZmUtaGlzdG9yeSBvZmYgb2YgZmlzaGJhc2UgKHdpdGhvdXQgUTEgc3VydmV5ID0gYmx1ZSwgd2l0aG91dCBRMy80IHN1cnZleSA9IHB1cnBsZSksIG92ZXJsYWluIHdpdGggZnVsbCBtb2RlbCBlc3RpbWF0ZXMgKGJsYWNrIGxpbmUgYW5kIGdyZXkgcmliYm9uKSBvZiBTU0IgKHRvcCBsZWZ0KSwgRiAodG9wIHJpZ2h0KSwgUmVjcnVpdG1lbnQgKGJvdHRvbSBsZWZ0KSwgYW5kIGNhdGNoIChib3R0b20gcmlnaHQ7IG9ic2VydmF0aW9ucyBhcyB5ZWxsb3cgKykuIn0NCiMgc3NicGxvdChMTykNCmxvc3NiX25tRzVGYiA8LSBnZ3Bsb3RseShnZ3Bsb3QoKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IGxvc3VtX25tRzVGYiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9U1NCLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gc2VyaWVzKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9yaWJib24oZGF0YSA9IGFzdW1fbm1HNUZiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW49U1NCbG93LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4PVNTQmhpZ2gpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9ICJibGFjayIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMikgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCJibGFjayIsIGVicGFsWzg6OV0pKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9jbGVhbigpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKGF4aXMudGl0bGUueS5sZWZ0ID0gZWxlbWVudF90ZXh0KHZqdXN0ID0gLTAuMDUsIGhqdXN0ID0gMC45NSkpKQ0KDQojIEZwbG90KExPKQ0KbG9mX25tRzVGYiA8LSBnZ3Bsb3RseShnZ3Bsb3QoKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9saW5lKGRhdGEgPSBsb3N1bV9ubUc1RmIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9RmJhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBzZXJpZXMpKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9yaWJib24oZGF0YSA9IGFzdW1fbm1HNUZiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1pbj1GbG93LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1heD1GaGlnaCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9ICJibGFjayIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjMpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoImJsYWNrIiwgZWJwYWxbODo5XSkpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9jbGVhbigpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZShheGlzLnRpdGxlLnkubGVmdCA9IGVsZW1lbnRfdGV4dCh2anVzdCA9IC0wLjA1LCBoanVzdCA9IDAuOTUpKSkNCg0KIyByZWNwbG90KExPKQ0KbG9yZWNfbm1HNUZiIDwtIGdncGxvdGx5KGdncGxvdCgpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fbGluZShkYXRhID0gbG9zdW1fbm1HNUZiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1SX2FnZTEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBzZXJpZXMpKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3JpYmJvbihkYXRhID0gYXN1bV9ubUc1RmIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1pbj1SbG93LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4PVJoaWdoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSAiYmxhY2siLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjMpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiYmxhY2siLCBlYnBhbFs4OjldKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWVfY2xlYW4oKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZShheGlzLnRpdGxlLnkubGVmdCA9IGVsZW1lbnRfdGV4dCh2anVzdCA9IC0wLjA1LCBoanVzdCA9IDAuOTUpKSkNCg0KIyBDYXRjaCBwbG90IChMTykNCmxvY2Ffbm1HNUZiIDwtIGdncGxvdGx5KGdncGxvdCgpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9saW5lKGRhdGEgPSBsb3N1bV9ubUc1RmIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1DYXRjaEVzdCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gc2VyaWVzKSkrDQogICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fcmliYm9uKGRhdGEgPSBhc3VtX25tRzVGYlthc3VtX25tRzVGYiRZZWFyICE9IChEYXRhWWVhcisxKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1pbj1DYXRjaGxvdywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4PUNhdGNoaGlnaCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSAiYmxhY2siLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMykgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3BvaW50KGRhdGEgPSBhc3VtX25tRzVGYlthc3VtX25tRzVGYiRZZWFyICE9IChEYXRhWWVhcisxKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9Q2F0Y2hPYnMpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNoYXBlID0gMywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBlYnBhbFs1XSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gZWJwYWxbNV0pICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgeWxhYigiQ2F0Y2ggKHRvbm5lcykiKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiYmxhY2siLCBlYnBhbFs4OjldKSkrIA0KICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9jbGVhbigpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWUoYXhpcy50aXRsZS55LmxlZnQgPSBlbGVtZW50X3RleHQodmp1c3QgPSAtMC4wNSwgaGp1c3QgPSAwLjk1KSkpDQoNCmxheW91dChzdWJwbG90KGxvc3NiX25tRzVGYiwgbG9mX25tRzVGYiwgbG9yZWNfbm1HNUZiLCBsb2NhX25tRzVGYiwgbnJvd3MgPSAyLCBzaGFyZVggPSBUUlVFLCB0aXRsZVkgPSBUUlVFKSwgc2hvd2xlZ2VuZD1GQUxTRSkNCmBgYA0KDQojIyMgUmV0cm9zcGVjdGl2ZXMNCmBgYHtyIGNhbGN1bGF0ZVJldHJvc19ubUc1RmJ9DQojPT09DQojIENyZWF0ZSBkYXRhZnJhbWUgb2YgY3VycmVudCB5ZWFyJ3MgZml0IGZvciBwbG90dGluZw0KIz09PT0NCiMgSUNfYWdnX3RlbXAgPC0gYWdncmVnYXRlKENBVE9OflllYXIsIGljX2NsZWFuW2ljX2NsZWFuJENhdGNoQ2F0ZWdvcnkgJWluJSBjKCJMYW5kaW5ncyIsICJEaXNjYXJkcyIpLCBdLCBGVU4gPSAic3VtIikNCmFzdW1fbm1HNUZiIDwtIGFzLmRhdGEuZnJhbWUoc3VtbWFyeShmaXRfbm1HNUZiKSkNCmFzdW1fbm1HNUZiJFllYXIgPC0gYXMuaW50ZWdlcihyb3cubmFtZXMoc3VtbWFyeShmaXRfbm1HNUZiKSkpDQpjdF9ubUc1RmIgPC0gYXMuZGF0YS5mcmFtZShjYXRjaHRhYmxlKGZpdF9ubUc1RmIsIG9icy5zaG93ID0gVFJVRSkpDQpjdF9ubUc1RmIkWWVhciA8LSBhcy5pbnRlZ2VyKHJvd25hbWVzKGN0X25tRzVGYikpDQpyb3duYW1lcyhjdF9ubUc1RmIpIDwtIE5VTEwNCmN0X25tRzVGYiA8LSByYmluZChjdF9ubUc1RmIsIGRhdGEuZnJhbWUoRXN0aW1hdGUgPSBOQSwgTG93PU5BLCBIaWdoPU5BLCBzb3AuY2F0Y2g9TkEsIFllYXI9YXMuaW50ZWdlcigyMDI0KSkpDQphc3VtX25tRzVGYiA8LSBtZXJnZSh4ID0gYXN1bV9ubUc1RmIsIHkgPSBjdF9ubUc1RmIsIGJ5ID0gIlllYXIiKQ0KY29sbmFtZXMoYXN1bV9ubUc1RmIpIDwtIGMoIlllYXIiLCAiUl9hZ2UxIiwgIlJsb3ciLCAiUmhpZ2giLCAiU1NCIiwgIlNTQmxvdyIsICJTU0JoaWdoIiwgIkZiYXIiLCAiRmxvdyIsICJGaGlnaCIsICJDYXRjaEVzdCIsICJDYXRjaGxvdyIsICJDYXRjaGhpZ2giLCAiQ2F0Y2hPYnMiKQ0KDQphc3VtX25tRzVGYiRzZXJpZXMgPC0gcmVwKCJmdWxsIiwgdGltZXMgPSBucm93KGFzdW1fbm1HNUZiKSkNCg0KIz09PT09DQpSRVRST19ubUc1RmI8LXJldHJvKGZpdF9ubUc1RmIsIHllYXI9NSkNCnJob19ubUc1RmIgPC0gbW9obihSRVRST19ubUc1RmIsIGxhZyA9IDEpDQoNCiMjIE1ha2UgUkVUUk9zIGluIGJldHRlciBwbG90dGluZyBmb3JtYXQNCnJldF9ubUc1RmJfZGYgPC0gYXN1bV9ubUc1RmJbYXN1bV9ubUc1RmIkWWVhciAhPSBtYXgoYXN1bV9ubUc1RmIkWWVhciksIF0NCg0KZm9yKGkgaW4gMTpsZW5ndGgoUkVUUk9fbm1HNUZiKSl7DQogIHRzdW0gPC0gYXMuZGF0YS5mcmFtZShzdW1tYXJ5KFJFVFJPX25tRzVGYltbaV1dKSkNCiAgdHN1bSRZZWFyIDwtIGFzLmludGVnZXIocm93Lm5hbWVzKHN1bW1hcnkoUkVUUk9fbm1HNUZiW1tpXV0pKSkNCiAgdHN1bSA8LSBjYmluZCh0c3VtLCBjYXRjaHRhYmxlKFJFVFJPX25tRzVGYltbaV1dLCBvYnMuc2hvdyA9IFRSVUUpKQ0KICB0c3VtJHNlcmllcyA8LSBhcy5jaGFyYWN0ZXIocmVwKGksIG5yb3codHN1bSkpKQ0KICBjb2xuYW1lcyh0c3VtKSA8LSBjKCJSX2FnZTEiLCAiUmxvdyIsICJSaGlnaCIsICJTU0IiLCAiU1NCbG93IiwgIlNTQmhpZ2giLCAiRmJhciIsICJGbG93IiwgIkZoaWdoIiwgIlllYXIiLCAiQ2F0Y2hFc3QiLCAiQ2F0Y2hsb3ciLCAiQ2F0Y2hoaWdoIiwgIkNhdGNoT2JzIiwgInNlcmllcyIpDQogIHRzdW0gPC0gdHN1bVt0c3VtJFllYXIgIT0gbWF4KHRzdW0kWWVhciksIF0NCiAgcmV0X25tRzVGYl9kZiA8LSByYmluZChyZXRfbm1HNUZiX2RmLCB0c3VtKQ0KfQ0KcmV0X25tRzVGYl9kZiRzZXJpZXMgPC0gZmFjdG9yKHJldF9ubUc1RmJfZGYkc2VyaWVzLCBsZXZlbHMgPSBjKCJmdWxsIiwgIjEiLCAiMiIsICIzIiwgIjQiLCAiNSIpKQ0KYGBgDQoNCmBgYHtyIGZpZy5jYXA9IlJldHJvc3BlY3RpdmUgYW5hbHlzZXMgZm9yIFNTQiAodG9wLWxlZnQpLCBGIGZvciBhZ2VzIDMtNSAodG9wLXJpZ2h0KSwgcmVjcnVpdG1lbnQgKGJvdHRvbS1sZWZ0KSwgYW5kIGNhdGNoIChib3R0b20tcmlnaHQpLCBmcm9tIHRoZSBtb2RlbCB1dGlsaXNpbmcgdGltZSB2YXJpYW50ICg1IHllYXIgc2xpZGluZyB3aW5kb3cgbWVhbiksIEdpc2xhc29uIG5hdHVyYWwgbW9ydGFsaXRpZXMgKEZpc2hCYXNlKS4ifQ0KIyBzc2JwbG90KFJFVFJPKQ0KcmV0c3NiX25tRzVGYiA8LSBsYXlvdXQoZ2dwbG90bHkoZ2dwbG90KCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IHJldF9ubUc1RmJfZGYsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1TU0IsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IHNlcmllcykpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9yaWJib24oZGF0YSA9IGFzdW1fbm1HNUZiW2FzdW1fbm1HNUZiJFllYXIgIT0gbWF4KGFzdW1fbm1HNUZiJFllYXIpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWluPVNTQmxvdywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4PVNTQmhpZ2gpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gImJsYWNrIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjIpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYW5ub3RhdGUoZ2VvbSA9ICJ0ZXh0IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IG1heChyZXRfbm1HNUZiX2RmJFNTQmhpZ2gpKjAuODUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHggPSAoKG1heChyZXRfbm1HNUZiX2RmJFllYXIpLW1pbihyZXRfbm1HNUZiX2RmJFllYXIpKSowLjIwKSttaW4ocmV0X25tRzVGYl9kZiRZZWFyKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSBwYXN0ZTAoIk1vaG4ncyBSaG8gPSAiLCByb3VuZChyaG9fbm1HNUZiWzJdLCBkaWdpdHMgPSAzKSkpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCJibGFjayIsIGVicGFsWyhsZW5ndGgoZWJwYWwpLTQpOmxlbmd0aChlYnBhbCldKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9jbGVhbigpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBheGlzLnRpdGxlLnkubGVmdCA9IGVsZW1lbnRfdGV4dCh2anVzdCA9IC0wLjA1LCBoanVzdCA9IDAuOTUpKSksDQogICAgICAgICAgICAgICAgICAgICAgICBzaG93bGVnZW5kID0gRkFMU0UpDQoNCiMgRnBsb3QoUkVUUk8pDQpyZXRmX25tRzVGYiA8LSBsYXlvdXQoZ2dwbG90bHkoZ2dwbG90KCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9saW5lKGRhdGEgPSByZXRfbm1HNUZiX2RmLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1GYmFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gc2VyaWVzKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9yaWJib24oZGF0YSA9IGFzdW1fbm1HNUZiW2FzdW1fbm1HNUZiJFllYXIgIT0gbWF4KGFzdW1fbm1HNUZiJFllYXIpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW49RmxvdywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1heD1GaGlnaCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gImJsYWNrIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4zKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbm5vdGF0ZShnZW9tID0gInRleHQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IG1heChyZXRfbm1HNUZiX2RmJEZoaWdoKSowLjg1LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeCA9ICgobWF4KHJldF9ubUc1RmJfZGYkWWVhciktbWluKHJldF9ubUc1RmJfZGYkWWVhcikpKjAuODApK21pbihyZXRfbm1HNUZiX2RmJFllYXIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSBwYXN0ZTAoIk1vaG4ncyBSaG8gPSAiLCByb3VuZChyaG9fbm1HNUZiWzNdLCBkaWdpdHMgPSAzKSkpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiYmxhY2siLCBlYnBhbFsobGVuZ3RoKGVicGFsKS00KTpsZW5ndGgoZWJwYWwpXSkpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2NsZWFuKCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXhpcy50aXRsZS55LmxlZnQgPSBlbGVtZW50X3RleHQodmp1c3QgPSAtMC4wNSwgaGp1c3QgPSAwLjk1KSkpLA0KICAgICAgICAgICAgICAgICAgICAgIHNob3dsZWdlbmQgPSBGQUxTRSkNCg0KIyByZWNwbG90KFJFVFJPKQ0KcmV0cmVjX25tRzVGYiA8LSBsYXlvdXQoZ2dwbG90bHkoZ2dwbG90KCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IHJldF9ubUc1RmJfZGYsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1SX2FnZTEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IHNlcmllcykpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9yaWJib24oZGF0YSA9IGFzdW1fbm1HNUZiW2FzdW1fbm1HNUZiJFllYXIgIT0gbWF4KGFzdW1fbm1HNUZiJFllYXIpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWluPVJsb3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1heD1SaGlnaCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSAiYmxhY2siLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMykgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbm5vdGF0ZShnZW9tID0gInRleHQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PSBtYXgocmV0X25tRzVGYl9kZiRSaGlnaCkqMC44NSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeCA9ICgobWF4KHJldF9ubUc1RmJfZGYkWWVhciktbWluKHJldF9ubUc1RmJfZGYkWWVhcikpKjAuMjApK21pbihyZXRfbm1HNUZiX2RmJFllYXIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbCA9IHBhc3RlMCgiTW9obidzIFJobyA9ICIsIHJvdW5kKHJob19ubUc1RmJbMV0sIGRpZ2l0cyA9IDMpKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoImJsYWNrIiwgZWJwYWxbKGxlbmd0aChlYnBhbCktNCk6bGVuZ3RoKGVicGFsKV0pKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2NsZWFuKCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF4aXMudGl0bGUueS5sZWZ0ID0gZWxlbWVudF90ZXh0KHZqdXN0ID0gLTAuMDUsIGhqdXN0ID0gMC45NSkpKSwNCiAgICAgICAgICAgICAgICAgICAgICAgIHNob3dsZWdlbmQgPSBGQUxTRSkNCg0KIyBDYXRjaCBwbG90IChSRVRSTykNCnJldGNhX25tRzVGYiA8LSBnZ3Bsb3RseShnZ3Bsb3QoKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IHJldF9ubUc1RmJfZGYsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PUNhdGNoRXN0LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gc2VyaWVzKSkrDQogICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3JpYmJvbihkYXRhID0gYXN1bV9ubUc1RmJbYXN1bV9ubUc1RmIkWWVhciAhPSBtYXgoYXN1bV9ubUc1RmIkWWVhciksIF0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1pbj1DYXRjaGxvdywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1heD1DYXRjaGhpZ2gpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9ICJibGFjayIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMykgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9wb2ludChkYXRhID0gYXN1bV9ubUc1RmJbYXN1bV9ubUc1RmIkWWVhciAhPSBtYXgoYXN1bV9ubUc1RmIkWWVhciksIF0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9Q2F0Y2hPYnMpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaGFwZSA9IDMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IGVicGFsWzVdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gZWJwYWxbNV0pICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHlsYWIoIkNhdGNoICh0b25uZXMpIikgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCJibGFjayIsIGVicGFsWyhsZW5ndGgoZWJwYWwpLTQpOmxlbmd0aChlYnBhbCldKSkrIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWVfY2xlYW4oKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZShheGlzLnRpdGxlLnkubGVmdCA9IGVsZW1lbnRfdGV4dCh2anVzdCA9IC0wLjA1LCBoanVzdCA9IDAuOTUpKSkNCg0KcmV0X2ZwIDwtIHN0eWxlKHN1YnBsb3QocmV0c3NiX25tRzVGYiwgcmV0Zl9ubUc1RmIsIHJldHJlY19ubUc1RmIsIHJldGNhX25tRzVGYiwgbnJvd3MgPSAyLCBzaGFyZVggPSBGQUxTRSwgc2hhcmVZID0gRkFMU0UsIHRpdGxlWSA9IFRSVUUpLA0KICAgICAgICAgICAgICAgIHNob3dsZWdlbmQ9RkFMU0UsDQogICAgICAgICAgICAgICAgdHJhY2VzID0gYyg4OigoNyo0KSsyKSkpDQoNCmxheW91dChyZXRfZnAsIGxlZ2VuZCA9IGxpc3Qob3JpZW50YXRpb24gPSAnaCcsIHggPSAwLjUsIHhhbmNob3IgPSAnY2VudGVyJywgeSA9IC0wLjA1LCB5YW5jaG9yID0gJ3RvcCcsIGJvcmRlcndpZHRoID0gMCkpDQpgYGANCg0KIyMgQ29tcGFyaXNvbiBvZiBOYXR1cmFsIE1vcnRhbGl0eSBIeXBvdGhlc2VzDQpBZnRlciBpbnRlcnJvZ2F0aW5nIHRoZSByZXNpZHVhbHMgYW5kIHRoZSBtb2RlbCBmaXRzIHRvIG9ic2VydmF0aW9ucywgd2UgY2FuIGFsc28gY29tcGFyZSB0aGUgQUlDcyBvZiB0aGVzZSBtb2RlbHMsIGFzIHdlJ3ZlIG9ubHkgbW9kaWZpZWQgdGhlIGlucHV0IGRhdGEuICBXZSdsbCBhbHNvIGFnZ3JlZ2F0ZSBhbGwgb2YgdGhlIE1vaG4ncyByaG8gdmFsdWVzIGZvciBlYXNpZXIgY29tcGFyaXNvbnMuDQoNCiMjIyBCYXNpYyBmaXQgYW5kIGRpYWdub3N0aWMgdmFyaWFibGVzDQpgYGB7ciBubUFJQ1RhYmxlfQ0Kbm1BSUMgPC0gZGF0YS5mcmFtZSgnVHlwZSBvZiBNJyA9IGMoIkhpc3RvcmljIE0iLCAiVGltZSBpbnZhcmlhbnQsIEdpc2xhc29uIiwgIk9wdGltYWxseSBzY2FsZWQsIHRpbWUgaW52YXJpYW50LCBHaXNsYXNvbiIsICJUaW1lIHZhcnlpbmcgKDV5c3cpLCBHaXNsYXNvbiIsICJUaW1lIGludmFyaWFudCwgR2lzbGFzb24gJiBGaXNoQmFzZSIsICJPcHRpbWFsbHkgc2NhbGVkLCB0aW1lIGludmFyaWFudCwgR2lzbGFzb24gJiBGaXNoQmFzZSIsICJUaW1lIHZhcnlpbmcgKDV5c3cpLCBHaXNsYXNvbiAmIEZpc2hCYXNlIiksDQogICAgICAgICAgICAgICAgICAgIEFJQyA9IGMoQUlDKGZpdF9iaW9fNXlfU1YpLCBBSUMoZml0X25tRyksIEFJQyhmaXRfbm1HUyksIEFJQyhmaXRfbm1HNXlzdyksIEFJQyhmaXRfbm1HRmIpLCBBSUMoZml0X25tR19TRmIpLCBBSUMoZml0X25tRzVGYikpLA0KICAgICAgICAgICAgICAgICAgICBOby5QYXJhbXMgPSBjKGxlbmd0aChjb2VmKGZpdF9iaW9fNXlfU1YpKSwgbGVuZ3RoKGNvZWYoZml0X25tRykpLCBsZW5ndGgoY29lZihmaXRfbm1HUykpLCBsZW5ndGgoY29lZihmaXRfbm1HNXlzdykpLCBsZW5ndGgoY29lZihmaXRfbm1HRmIpKSwgbGVuZ3RoKGNvZWYoZml0X25tR19TRmIpKSwgbGVuZ3RoKGNvZWYoZml0X25tRzVGYikpKSwNCiAgICAgICAgICAgICAgICAgICAgUmhvLlNTQiA9IGMocmhvX2Jpb181eV9TVlsyXSwgcmhvX25tR1syXSwgcmhvX25tR1NbMl0sIHJob19ubUc1eXN3WzJdLCByaG9fbm1HRmJbMl0sIHJob19ubUdfU0ZiWzJdLCByaG9fbm1HNUZiWzJdKSwNCiAgICAgICAgICAgICAgICAgICAgUmhvLkYgPSBjKHJob19iaW9fNXlfU1ZbM10sIHJob19ubUdbM10sIHJob19ubUdTWzNdLCByaG9fbm1HNXlzd1szXSwgcmhvX25tR0ZiWzNdLCByaG9fbm1HX1NGYlszXSwgcmhvX25tRzVGYlszXSksDQogICAgICAgICAgICAgICAgICAgIFJoby5SZWMgPSBjKHJob19iaW9fNXlfU1ZbMV0sIHJob19ubUdbMV0sIHJob19ubUdTWzFdLCByaG9fbm1HNXlzd1sxXSwgcmhvX25tR0ZiWzFdLCByaG9fbm1HX1NGYlsxXSwgcmhvX25tRzVGYlsxXSkpDQoNCmthYmxlKG5tQUlDLA0KICAgICAgY2FwdGlvbiA9ICJNZWFzdXJlcyBvZiBtb2RlbCBmaXQgdW5kZXIgdmFyaW91cyBoeXBvdGhlc2VzIG9mIG5hdHVyYWwgbW9ydGFsaXR5LiIpDQpgYGANCg0KIyMgQ29tcGFyaXNvbiBvZiBtb2RlbCBlc3RpbWF0ZXMNCk5vdyB0aGF0IHdlJ3ZlIGNvbnNpZGVyZWQgdGhlIG1vZGVsIGZpdHMsIGRpYWdub3N0aWNzIGFuZCB0dW5pbmcsIHdlIG1pZ2h0IGFzIHdlbGwgaGF2ZSBhIGxvb2sgYXQgaG93IHRoZSBtb2RlbHMnIGVzdGltYXRlcyBjb21wYXJlLg0KDQpgYGB7ciBmaWcuY2FwPSAiRXN0aW1hdGVkIHNwYXduaW5nIHN0b2NrIGJpb21hc3MgZm9yIHBsZS4yNy4yMS0zMiBhbmQgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWxzICh0b25uZXMpLiAgUHVycGxlIGlzIHRoZSBtb2RlbCB3aXRoIHRoZSBoaXN0b3JpYyBtb3J0YWxpdGllcywgZGFyayBncmVlbiBpcyB3aXRoIHRpbWUgaW52YXJpYW50IEdpc2xhc29uIG1vcnRhbGl0aWVzLCBkYXJrIG9yYW5nZSBpcyB3aXRoIHNjYWxlZC10aW1lLWludmFyaWFudCBHaXNsYXNvbiBtb3J0YWxpdGllcywgYW5kIGJsdWUgaXMgd2l0aCB0aW1lIHZhcnlpbmcgR2lzbGFzb24gbW9ydGFsaXRpZXMuIFllbGxvdywgbGlnaHQtZ3JlZW4sIGFuZCBsaWdodC1vcmFuZ2UsIGFyZSBpbiB0aGUgc2FtZSBvcmRlciBhcyB0aGUgcHJldmlvdXMgdGhyZWUsIGV4Y2VwdCBhbGwgbW9ydGFsaXRpZXMgYXJlIGNhbGN1bGF0ZWQgd2l0aCBsaWZlLWhpc3RvcnkgZGF0YSBmcm9tIEZpc2hCYXNlLCBpbnN0ZWFkIG9mIHN1cnZleSBvYnNlcnZhdGlvbnMuIn0NCiMgc3NibGluZXMgPC0gZGF0YS5mcmFtZSh5aW50ZXJjZXB0PWMoNDczMCwgNDM3MCwgMzYzNSksIExpbmVzID0gZmFjdG9yKHggPSBjKCJNU1ktQnRyaWdnZXIiLCAiQnBhIiwgIkJsaW0iKSxsZXZlbHMgPSBjKCJNU1ktQnRyaWdnZXIiLCAiQnBhIiwgIkJsaW0iKSkpDQpwc3NiIDwtIGdncGxvdCgpICsNCiAgZ2VvbV9saW5lKGRhdGEgPSBhc3VtX2Jpb181eV9TViwgDQogICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgeT1TU0IsDQogICAgICAgICAgICAgICAgICAgICAgICAgIHNlcmllcz0iSGlzdG9yaWMgbm0iKSwNCiAgICAgICAgICAgIGNvbG91ciA9IGVicGFsWzFdKSArDQogIGdlb21fcmliYm9uKGRhdGEgPSBhc3VtX2Jpb181eV9TViwgDQogICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW49U1NCbG93LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltYXg9U1NCaGlnaCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXJpZXM9Ikhpc3RvcmljIG5tIiksDQogICAgICAgICAgICAgIGZpbGwgPSBlYnBhbFsxXSwNCiAgICAgICAgICAgICAgYWxwaGEgPSAwLjMpICsNCiAgZ2VvbV9saW5lKGRhdGEgPSBhc3VtX25tRywNCiAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICB5PVNTQiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgc2VyaWVzPSJUaW1lLWludmFyaWFudCBHaXNsYXNvbiBubSIpLA0KICAgICAgICAgICAgY29sb3VyID0gZWJwYWxbMl0pICsNCiAgZ2VvbV9yaWJib24oZGF0YSA9IGFzdW1fbm1HLA0KICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWluPVNTQmxvdywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4PVNTQmhpZ2gsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VyaWVzPSJUaW1lLWludmFyaWFudCBHaXNsYXNvbiBubSIpLA0KICAgICAgICAgICAgICBmaWxsID0gZWJwYWxbMl0sDQogICAgICAgICAgICAgIGFscGhhID0gMC4zKSArDQogIGdlb21fbGluZShkYXRhID0gYXN1bV9ubUdTLA0KICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgIHk9U1NCLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBzZXJpZXM9IlNjYWxlZCwgdGltZS1pbnZhcmlhbnQgR2lzbGFzb24gbm0iKSwNCiAgICAgICAgICAgIGNvbG91ciA9IGVicGFsWzNdKSArDQogIGdlb21fcmliYm9uKGRhdGEgPSBhc3VtX25tR1MsDQogICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW49U1NCbG93LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltYXg9U1NCaGlnaCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXJpZXM9IlNjYWxlZCwgdGltZS1pbnZhcmlhbnQgR2lzbGFzb24gbm0iKSwNCiAgICAgICAgICAgICAgZmlsbCA9IGVicGFsWzNdLA0KICAgICAgICAgICAgICBhbHBoYSA9IDAuMykgKw0KICBnZW9tX2xpbmUoZGF0YSA9IGFzdW1fbm1HNXlzdywNCiAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICB5PVNTQiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgc2VyaWVzPSJUaW1lIHZhcnlpbmcgKDV5c3cpIEdpc2xhc29uIG5tIiksDQogICAgICAgICAgICBjb2xvdXIgPSBlYnBhbFs0XSkgKw0KICBnZW9tX3JpYmJvbihkYXRhID0gYXN1bV9ubUc1eXN3LA0KICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWluPVNTQmxvdywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4PVNTQmhpZ2gsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VyaWVzPSJUaW1lIHZhcnlpbmcgKDV5c3cpIEdpc2xhc29uIG5tIiksDQogICAgICAgICAgICAgIGZpbGwgPSBlYnBhbFs0XSwNCiAgICAgICAgICAgICAgYWxwaGEgPSAwLjMpICsNCiAgZ2VvbV9saW5lKGRhdGEgPSBhc3VtX25tR0ZiLA0KICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgIHk9U1NCLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBzZXJpZXM9IlRpbWUgaW52YXJpYW50LCBHaXNsYXNvbiAmIEZpc2hCYXNlIiksDQogICAgICAgICAgICBjb2xvdXIgPSBlYnBhbFs1XSkgKw0KICBnZW9tX3JpYmJvbihkYXRhID0gYXN1bV9ubUdGYiwNCiAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1pbj1TU0Jsb3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1heD1TU0JoaWdoLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcmllcz0iVGltZSBpbnZhcmlhbnQsIEdpc2xhc29uICYgRmlzaEJhc2UiKSwNCiAgICAgICAgICAgICAgZmlsbCA9IGVicGFsWzVdLA0KICAgICAgICAgICAgICBhbHBoYSA9IDAuMykgKw0KICBnZW9tX2xpbmUoZGF0YSA9IGFzdW1fbm1HX1NGYiwNCiAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICB5PVNTQiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgc2VyaWVzPSJUaW1lIGludmFyaWFudCwgc2NhbGVkIEdpc2xhc29uICYgRmlzaEJhc2UiKSwNCiAgICAgICAgICAgIGNvbG91ciA9IGVicGFsWzZdKSArDQogIGdlb21fcmliYm9uKGRhdGEgPSBhc3VtX25tR19TRmIsDQogICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW49U1NCbG93LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltYXg9U1NCaGlnaCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXJpZXM9IlRpbWUgaW52YXJpYW50LCBzY2FsZWQgR2lzbGFzb24gJiBGaXNoQmFzZSIpLA0KICAgICAgICAgICAgICBmaWxsID0gZWJwYWxbNl0sDQogICAgICAgICAgICAgIGFscGhhID0gMC4zKSArDQogIGdlb21fbGluZShkYXRhID0gYXN1bV9ubUc1RmIsDQogICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgeT1TU0IsDQogICAgICAgICAgICAgICAgICAgICAgICAgIHNlcmllcz0iVGltZSB2YXJ5aW5nICg1eXN3KSBHaXNsYXNvbiAmIEZpc2hCYXNlIiksDQogICAgICAgICAgICANCiAgICAgICAgICAgIGNvbG91ciA9IGVicGFsWzddKSArDQogIGdlb21fcmliYm9uKGRhdGEgPSBhc3VtX25tRzVGYiwNCiAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1pbj1TU0Jsb3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1heD1TU0JoaWdoKSwNCiAgICAgICAgICAgICAgc2VyaWVzPSJUaW1lIHZhcnlpbmcgKDV5c3cpIEdpc2xhc29uICYgRmlzaEJhc2UiLA0KICAgICAgICAgICAgICBmaWxsID0gZWJwYWxbN10sDQogICAgICAgICAgICAgIGFscGhhID0gMC4zKSArDQogIHRoZW1lX2NsZWFuKCkNCg0KZ2dwbG90bHkocHNzYiwgdG9vbHRpcCA9IGMoInNlcmllcyIsICJ4IiwgInkiKSkNCmBgYA0KDQpGaXNoaW5nIHByZXNzdXJlIG92ZXIgdGltZSBzZWVtcyB0byByZXNwb25kIHRvIHRoZSBjaGFuZ2VzIGluIHRoZSBlc3RpbWF0aW9ucyBvZiBTU0IsIHdoaWxlIGlucHV0IGRhdGEgZm9yIGNhdGNoZXMgKG9idmlvdXNseSkgcmVtYWluIHRoZSBzYW1lIGJldHdlbiB0aGUgdHdvIG1vZGVscy4gDQoNCmBgYHtyIGZpZy5jYXA9ICJBbm51YWwgZmlzaGluZyBtb3J0YWxpdHkgZXN0aW1hdGVzIGZvciBwbGUuMjcuMjEtMzIgYWdlcyAzLTUgYW5kIHBvaW50IHdpc2UgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWxzIGFyZSBzaG93biBieSBsaW5lIGFuZCBzaGFkZWQgYXJlYS4gUHVycGxlIGlzIHRoZSBtb2RlbCB3aXRoIHRoZSBoaXN0b3JpYyBtb3J0YWxpdGllcywgZGFyayBncmVlbiBpcyB3aXRoIHRpbWUgaW52YXJpYW50IEdpc2xhc29uIG1vcnRhbGl0aWVzLCBkYXJrIG9yYW5nZSBpcyB3aXRoIHNjYWxlZC10aW1lLWludmFyaWFudCBHaXNsYXNvbiBtb3J0YWxpdGllcywgYW5kIGJsdWUgaXMgd2l0aCB0aW1lIHZhcnlpbmcgR2lzbGFzb24gbW9ydGFsaXRpZXMuIFllbGxvdywgbGlnaHQtZ3JlZW4sIGFuZCBsaWdodC1vcmFuZ2UsIGFyZSBpbiB0aGUgc2FtZSBvcmRlciBhcyB0aGUgcHJldmlvdXMgdGhyZWUsIGV4Y2VwdCBhbGwgbW9ydGFsaXRpZXMgYXJlIGNhbGN1bGF0ZWQgd2l0aCBsaWZlLWhpc3RvcnkgZGF0YSBmcm9tIEZpc2hCYXNlLCBpbnN0ZWFkIG9mIHN1cnZleSBvYnNlcnZhdGlvbnMuIn0NCiMgZmxpbmVzIDwtIGRhdGEuZnJhbWUoeWludGVyY2VwdD1jKDAuMzEsIDAuODEsIDEuMDApLCBMaW5lcyA9IGZhY3Rvcih4ID0gYygiRk1TWSIsICJGcGEiLCAiRmxpbSIpLCBsZXZlbHMgPSBjKCJGTVNZIiwgIkZwYSIsICJGbGltIikpKQ0KZ2dwbG90bHkoZ2dwbG90KCkgKw0KICAgICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IGFzdW1fYmlvXzV5X1NWLCANCiAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PUZiYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcmllcz0iSGlzdG9yaWMgbm0iKSwNCiAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IGVicGFsWzFdKSArDQogICAgICAgICAgIGdlb21fcmliYm9uKGRhdGEgPSBhc3VtX2Jpb181eV9TViwgDQogICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW49RmxvdywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4PUZoaWdoLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcmllcz0iSGlzdG9yaWMgbm0iKSwNCiAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IGVicGFsWzFdLA0KICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMykgKw0KICAgICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IGFzdW1fbm1HLA0KICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9RmJhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VyaWVzPSJUaW1lLWludmFyaWFudCBHaXNsYXNvbiBubSIpLA0KICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gZWJwYWxbMl0pICsNCiAgICAgICAgICAgZ2VvbV9yaWJib24oZGF0YSA9IGFzdW1fbm1HLA0KICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWluPUZsb3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1heD1GaGlnaCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXJpZXM9IlRpbWUtaW52YXJpYW50IEdpc2xhc29uIG5tIiksDQogICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBlYnBhbFsyXSwNCiAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjMpICsNCiAgICAgICAgICAgZ2VvbV9saW5lKGRhdGEgPSBhc3VtX25tR1MsDQogICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1GYmFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXJpZXM9IlNjYWxlZCwgdGltZS1pbnZhcmlhbnQgR2lzbGFzb24gbm0iKSwNCiAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IGVicGFsWzNdKSArDQogICAgICAgICAgIGdlb21fcmliYm9uKGRhdGEgPSBhc3VtX25tR1MsDQogICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW49RmxvdywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4PUZoaWdoLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcmllcz0iU2NhbGVkLCB0aW1lLWludmFyaWFudCBHaXNsYXNvbiBubSIpLA0KICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gZWJwYWxbM10sDQogICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4zKSArDQogICAgICAgICAgIGdlb21fbGluZShkYXRhID0gYXN1bV9ubUc1eXN3LA0KICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9RmJhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VyaWVzPSJUaW1lIHZhcnlpbmcgKDV5c3cpIEdpc2xhc29uIG5tIiksDQogICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBlYnBhbFs0XSkgKw0KICAgICAgICAgICBnZW9tX3JpYmJvbihkYXRhID0gYXN1bV9ubUc1eXN3LA0KICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWluPUZsb3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1heD1GaGlnaCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXJpZXM9IlRpbWUgdmFyeWluZyAoNXlzdykgR2lzbGFzb24gbm0iKSwNCiAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IGVicGFsWzRdLA0KICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMykgKw0KICAgICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IGFzdW1fbm1HRmIsDQogICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1GYmFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXJpZXM9IlRpbWUgaW52YXJpYW50LCBHaXNsYXNvbiAmIEZpc2hCYXNlIiksDQogICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBlYnBhbFs1XSkgKw0KICAgICAgICAgICBnZW9tX3JpYmJvbihkYXRhID0gYXN1bV9ubUdGYiwNCiAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1pbj1GbG93LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltYXg9RmhpZ2gsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VyaWVzPSJUaW1lIGludmFyaWFudCwgR2lzbGFzb24gJiBGaXNoQmFzZSIpLA0KICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gZWJwYWxbNV0sDQogICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4zKSArDQogICAgICAgICAgIGdlb21fbGluZShkYXRhID0gYXN1bV9ubUdfU0ZiLA0KICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9RmJhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VyaWVzPSJUaW1lIGludmFyaWFudCwgc2NhbGVkIEdpc2xhc29uICYgRmlzaEJhc2UiKSwNCiAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IGVicGFsWzZdKSArDQogICAgICAgICAgIGdlb21fcmliYm9uKGRhdGEgPSBhc3VtX25tR19TRmIsDQogICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW49RmxvdywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4PUZoaWdoLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcmllcz0iVGltZSBpbnZhcmlhbnQsIHNjYWxlZCBHaXNsYXNvbiAmIEZpc2hCYXNlIiksDQogICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBlYnBhbFs2XSwNCiAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjMpICsNCiAgICAgICAgICAgZ2VvbV9saW5lKGRhdGEgPSBhc3VtX25tRzVGYiwNCiAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PUZiYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcmllcz0iVGltZSB2YXJ5aW5nICg1eXN3KSBHaXNsYXNvbiAmIEZpc2hCYXNlIiksDQogICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBlYnBhbFs3XSkgKw0KICAgICAgICAgICBnZW9tX3JpYmJvbihkYXRhID0gYXN1bV9ubUc1RmIsDQogICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW49RmxvdywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4PUZoaWdoLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcmllcz0iVGltZSB2YXJ5aW5nICg1eXN3KSBHaXNsYXNvbiAmIEZpc2hCYXNlIiksDQogICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBlYnBhbFs3XSwNCiAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjMpICsNCiAgICAgICAgICAgdGhlbWVfY2xlYW4oKSkNCmBgYA0KDQpFc3RpbWF0aW9ucyBvZiByZWNydWl0bWVudCBpbiB0aGUgbW9zdCByZWNlbnQgeWVhcnMgZmFsbCwgYXMgU1NCIGFsc28gZmFsbHMgaW4gdGhpcyB2ZXJzaW9uIG9mIHRoZSBtb2RlbCwgYWdhaW4gcHJvYmFibHkgZHVlIHRvIHRoZSByZWR1Y3Rpb24gaW4gc3RvY2sgd2VpZ2h0cyBhdCBhZ2UuDQoNCmBgYHtyIGZpZy5jYXA9ICJGaXZlIHllYXIgc2xpZGluZyB3aW5kb3cgbW9kZWwgYW5udWFsIHJlY3J1aXRtZW50IGVzdGltYXRlcyBmb3IgcGxlLjI3LjIxLTMyIGFuZCBwb2ludCB3aXNlIDk1JSBjb25maWRlbmNlIGludGVydmFscyBhcmUgc2hvd24gYnkgbGluZSBhbmQgc2hhZGVkIGFyZWEgKG51bWJlcnMpLiAgIFB1cnBsZSBpcyB0aGUgbW9kZWwgd2l0aCB0aGUgaGlzdG9yaWMgbW9ydGFsaXRpZXMsIGRhcmsgZ3JlZW4gaXMgd2l0aCB0aW1lIGludmFyaWFudCBHaXNsYXNvbiBtb3J0YWxpdGllcywgZGFyayBvcmFuZ2UgaXMgd2l0aCBzY2FsZWQtdGltZS1pbnZhcmlhbnQgR2lzbGFzb24gbW9ydGFsaXRpZXMsIGFuZCBibHVlIGlzIHdpdGggdGltZSB2YXJ5aW5nIEdpc2xhc29uIG1vcnRhbGl0aWVzLiBZZWxsb3csIGxpZ2h0LWdyZWVuLCBhbmQgbGlnaHQtb3JhbmdlLCBhcmUgaW4gdGhlIHNhbWUgb3JkZXIgYXMgdGhlIHByZXZpb3VzIHRocmVlLCBleGNlcHQgYWxsIG1vcnRhbGl0aWVzIGFyZSBjYWxjdWxhdGVkIHdpdGggbGlmZS1oaXN0b3J5IGRhdGEgZnJvbSBGaXNoQmFzZSwgaW5zdGVhZCBvZiBzdXJ2ZXkgb2JzZXJ2YXRpb25zLiJ9DQpnZ3Bsb3RseShnZ3Bsb3QoKSArDQogICAgICAgICAgIGdlb21fbGluZShkYXRhID0gYXN1bV9iaW9fNXlfU1YsIA0KICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9Ul9hZ2UxLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXJpZXM9Ikhpc3RvcmljIG5tIiksDQogICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBlYnBhbFsxXSkgKw0KICAgICAgICAgICBnZW9tX3JpYmJvbihkYXRhID0gYXN1bV9iaW9fNXlfU1YsIA0KICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWluPVJsb3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1heD1SaGlnaCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXJpZXM9Ikhpc3RvcmljIG5tIiksDQogICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBlYnBhbFsxXSwNCiAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjMpICsNCiAgICAgICAgICAgZ2VvbV9saW5lKGRhdGEgPSBhc3VtX25tRywNCiAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PVJfYWdlMSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VyaWVzPSJUaW1lLWludmFyaWFudCBHaXNsYXNvbiBubSIpLA0KICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gZWJwYWxbMl0pICsNCiAgICAgICAgICAgZ2VvbV9yaWJib24oZGF0YSA9IGFzdW1fbm1HLA0KICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWluPVJsb3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1heD1SaGlnaCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXJpZXM9IlRpbWUtaW52YXJpYW50IEdpc2xhc29uIG5tIiksDQogICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBlYnBhbFsyXSwNCiAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjMpICsNCiAgICAgICAgICAgZ2VvbV9saW5lKGRhdGEgPSBhc3VtX25tR1MsDQogICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1SX2FnZTEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcmllcz0iU2NhbGVkLCB0aW1lLWludmFyaWFudCBHaXNsYXNvbiBubSIpLA0KICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gZWJwYWxbM10pICsNCiAgICAgICAgICAgZ2VvbV9yaWJib24oZGF0YSA9IGFzdW1fbm1HUywNCiAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1pbj1SbG93LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltYXg9UmhpZ2gsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VyaWVzPSJTY2FsZWQsIHRpbWUtaW52YXJpYW50IEdpc2xhc29uIG5tIiksDQogICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBlYnBhbFszXSwNCiAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjMpICsNCiAgICAgICAgICAgZ2VvbV9saW5lKGRhdGEgPSBhc3VtX25tRzV5c3csDQogICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1SX2FnZTEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcmllcz0iVGltZSB2YXJ5aW5nICg1eXN3KSBHaXNsYXNvbiBubSIpLA0KICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gZWJwYWxbNF0pICsNCiAgICAgICAgICAgZ2VvbV9yaWJib24oZGF0YSA9IGFzdW1fbm1HNXlzdywNCiAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1pbj1SbG93LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltYXg9UmhpZ2gsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VyaWVzPSJUaW1lIHZhcnlpbmcgKDV5c3cpIEdpc2xhc29uIG5tIiksDQogICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBlYnBhbFs0XSwNCiAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjMpICsNCiAgICAgICAgICAgZ2VvbV9saW5lKGRhdGEgPSBhc3VtX25tR0ZiLA0KICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9Ul9hZ2UxLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXJpZXM9IlRpbWUgaW52YXJpYW50LCBHaXNsYXNvbiAmIEZpc2hCYXNlIiksDQogICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBlYnBhbFs1XSkgKw0KICAgICAgICAgICBnZW9tX3JpYmJvbihkYXRhID0gYXN1bV9ubUdGYiwNCiAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1pbj1SbG93LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltYXg9UmhpZ2gsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VyaWVzPSJUaW1lIGludmFyaWFudCwgR2lzbGFzb24gJiBGaXNoQmFzZSIpLA0KICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gZWJwYWxbNV0sDQogICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4zKSArDQogICAgICAgICAgIGdlb21fbGluZShkYXRhID0gYXN1bV9ubUdfU0ZiLA0KICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9Ul9hZ2UxLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXJpZXM9IlRpbWUgaW52YXJpYW50LCBzY2FsZWQgR2lzbGFzb24gJiBGaXNoQmFzZSIpLA0KICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gZWJwYWxbNl0pICsNCiAgICAgICAgICAgZ2VvbV9yaWJib24oZGF0YSA9IGFzdW1fbm1HX1NGYiwNCiAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1pbj1SbG93LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltYXg9UmhpZ2gsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VyaWVzPSJUaW1lIGludmFyaWFudCwgc2NhbGVkIEdpc2xhc29uICYgRmlzaEJhc2UiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IGVicGFsWzZdLA0KICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMykgKw0KICAgICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IGFzdW1fbm1HNUZiLA0KICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9Ul9hZ2UxLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXJpZXM9IlRpbWUgdmFyeWluZyAoNXlzdykgR2lzbGFzb24gJiBGaXNoQmFzZSIpLA0KICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gZWJwYWxbN10pICsNCiAgICAgICAgICAgZ2VvbV9yaWJib24oZGF0YSA9IGFzdW1fbm1HNUZiLA0KICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWluPVJsb3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1heD1SaGlnaCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXJpZXM9IlRpbWUgdmFyeWluZyAoNXlzdykgR2lzbGFzb24gJiBGaXNoQmFzZSIpLA0KICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gZWJwYWxbN10sDQogICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4zKSArDQogICAgICAgICAgIHRoZW1lX2NsZWFuKCkpDQpgYGANCg0KYGBge3IgZmlnLmNhcD0gIkFubnVhbCBjYXRjaCBlc3RpbWF0ZXMgYW5kIDk1JSBjb25maWRlbmNlIGludGVydmFscyAobGluZSBhbmQgc2hhZGVkIGFyZWEsIHJlc3BlY3RpdmVseSkgZm9yIHBsZS4yNy4yMS0zMiBhbmQgcG9pbnQgYW5udWFsIG9ic2VydmF0aW9ucyAocG9pbnRzKS4gIFB1cnBsZSBpcyB0aGUgbW9kZWwgd2l0aCB0aGUgaGlzdG9yaWMgbW9ydGFsaXRpZXMsIGRhcmsgZ3JlZW4gaXMgd2l0aCB0aW1lIGludmFyaWFudCBHaXNsYXNvbiBtb3J0YWxpdGllcywgZGFyayBvcmFuZ2UgaXMgd2l0aCBzY2FsZWQtdGltZS1pbnZhcmlhbnQgR2lzbGFzb24gbW9ydGFsaXRpZXMsIGFuZCBibHVlIGlzIHdpdGggdGltZSB2YXJ5aW5nIEdpc2xhc29uIG1vcnRhbGl0aWVzLiBZZWxsb3csIGxpZ2h0LWdyZWVuLCBhbmQgbGlnaHQtb3JhbmdlLCBhcmUgaW4gdGhlIHNhbWUgb3JkZXIgYXMgdGhlIHByZXZpb3VzIHRocmVlLCBleGNlcHQgYWxsIG1vcnRhbGl0aWVzIGFyZSBjYWxjdWxhdGVkIHdpdGggbGlmZS1oaXN0b3J5IGRhdGEgZnJvbSBGaXNoQmFzZSwgaW5zdGVhZCBvZiBzdXJ2ZXkgb2JzZXJ2YXRpb25zLiJ9DQpnZ3Bsb3RseShnZ3Bsb3QoKSArDQogICAgICAgICAgIGdlb21fbGluZShkYXRhID0gYXN1bV9iaW9fNXlfU1ZbYXN1bV9iaW9fNXlfU1YkWWVhciAhPSAoRGF0YVllYXIrMSksIF0sIA0KICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9Q2F0Y2hFc3QsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcmllcz0iSGlzdG9yaWMgbm0iKSwNCiAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IGVicGFsWzFdKSArDQogICAgICAgICAgIGdlb21fcmliYm9uKGRhdGEgPSBhc3VtX2Jpb181eV9TVlthc3VtX2Jpb181eV9TViRZZWFyICE9IChEYXRhWWVhcisxKSwgXSwgDQogICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW49Q2F0Y2hsb3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1heD1DYXRjaGhpZ2gsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VyaWVzPSJIaXN0b3JpYyBubSIpLA0KICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gZWJwYWxbMV0sDQogICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4zKSArDQogICAgICAgICAgIGdlb21fbGluZShkYXRhID0gYXN1bV9ubUdbYXN1bV9ubUckWWVhciAhPSAoRGF0YVllYXIrMSksIF0sDQogICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1DYXRjaEVzdCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VyaWVzPSJUaW1lLWludmFyaWFudCBHaXNsYXNvbiBubSIpLA0KICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gZWJwYWxbMl0pICsNCiAgICAgICAgICAgZ2VvbV9yaWJib24oZGF0YSA9IGFzdW1fbm1HW2FzdW1fbm1HJFllYXIgIT0gKERhdGFZZWFyKzEpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWluPUNhdGNobG93LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltYXg9Q2F0Y2hoaWdoLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcmllcz0iVGltZS1pbnZhcmlhbnQgR2lzbGFzb24gbm0iKSwNCiAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IGVicGFsWzJdLA0KICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMykgKw0KICAgICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IGFzdW1fbm1HU1thc3VtX25tR1MkWWVhciAhPSAoRGF0YVllYXIrMSksIF0sDQogICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1DYXRjaEVzdCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VyaWVzPSJTY2FsZWQsIHRpbWUtaW52YXJpYW50IEdpc2xhc29uIG5tIiksDQogICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBlYnBhbFszXSkgKw0KICAgICAgICAgICBnZW9tX3JpYmJvbihkYXRhID0gYXN1bV9ubUdTW2FzdW1fbm1HUyRZZWFyICE9IChEYXRhWWVhcisxKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1pbj1DYXRjaGxvdywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4PUNhdGNoaGlnaCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXJpZXM9IlNjYWxlZCwgdGltZS1pbnZhcmlhbnQgR2lzbGFzb24gbm0iKSwNCiAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IGVicGFsWzNdLA0KICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMykgKw0KICAgICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IGFzdW1fbm1HNXlzd1thc3VtX25tRzV5c3ckWWVhciAhPSAoRGF0YVllYXIrMSksIF0sDQogICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1DYXRjaEVzdCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VyaWVzPSJUaW1lIHZhcnlpbmcgKDV5c3cpIEdpc2xhc29uIG5tIiksDQogICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBlYnBhbFs0XSkgKw0KICAgICAgICAgICBnZW9tX3JpYmJvbihkYXRhID0gYXN1bV9ubUc1eXN3W2FzdW1fbm1HNXlzdyRZZWFyICE9IChEYXRhWWVhcisxKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1pbj1DYXRjaGxvdywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4PUNhdGNoaGlnaCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXJpZXM9IlRpbWUgdmFyeWluZyAoNXlzdykgR2lzbGFzb24gbm0iKSwNCiAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IGVicGFsWzRdLA0KICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMykgKw0KICAgICAgICAgICBnZW9tX3BvaW50KGRhdGEgPSBhc3VtX25tRzV5c3dbYXN1bV9ubUc1eXN3JFllYXIgIT0gKERhdGFZZWFyKzEpLF0sDQogICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PUNhdGNoT2JzKSwNCiAgICAgICAgICAgICAgICAgICAgICBzaGFwZSA9IDMsDQogICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gImJsYWNrIiwNCiAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gImJsYWNrIikgKw0KICAgICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IGFzdW1fbm1HRmJbYXN1bV9ubUdGYiRZZWFyICE9IChEYXRhWWVhcisxKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PUNhdGNoRXN0LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXJpZXM9IlRpbWUgaW52YXJpYW50LCBHaXNsYXNvbiAmIEZpc2hCYXNlIiksDQogICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBlYnBhbFs1XSkgKw0KICAgICAgICAgICBnZW9tX3JpYmJvbihkYXRhID0gYXN1bV9ubUdGYlthc3VtX25tR0ZiJFllYXIgIT0gKERhdGFZZWFyKzEpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWluPUNhdGNobG93LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltYXg9Q2F0Y2hoaWdoLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcmllcz0iVGltZSBpbnZhcmlhbnQsIEdpc2xhc29uICYgRmlzaEJhc2UiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IGVicGFsWzVdLA0KICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMykgKw0KICAgICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IGFzdW1fbm1HX1NGYlthc3VtX25tR19TRmIkWWVhciAhPSAoRGF0YVllYXIrMSksIF0sDQogICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1DYXRjaEVzdCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VyaWVzPSJUaW1lIGludmFyaWFudCwgc2NhbGVkIEdpc2xhc29uICYgRmlzaEJhc2UiKSwNCiAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IGVicGFsWzZdKSArDQogICAgICAgICAgIGdlb21fcmliYm9uKGRhdGEgPSBhc3VtX25tR19TRmJbYXN1bV9ubUdfU0ZiJFllYXIgIT0gKERhdGFZZWFyKzEpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWluPUNhdGNobG93LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltYXg9Q2F0Y2hoaWdoLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcmllcz0iVGltZSBpbnZhcmlhbnQsIHNjYWxlZCBHaXNsYXNvbiAmIEZpc2hCYXNlIiksDQogICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBlYnBhbFs2XSwNCiAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjMpICsNCiAgICAgICAgICAgZ2VvbV9saW5lKGRhdGEgPSBhc3VtX25tRzVGYlthc3VtX25tRzVGYiRZZWFyICE9IChEYXRhWWVhcisxKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PUNhdGNoRXN0LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXJpZXM9IlRpbWUgdmFyeWluZyAoNXlzdykgR2lzbGFzb24gJiBGaXNoQmFzZSIpLA0KICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gZWJwYWxbN10pICsNCiAgICAgICAgICAgZ2VvbV9yaWJib24oZGF0YSA9IGFzdW1fbm1HNUZiW2FzdW1fbm1HNUZiJFllYXIgIT0gKERhdGFZZWFyKzEpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWluPUNhdGNobG93LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltYXg9Q2F0Y2hoaWdoLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcmllcz0iVGltZSB2YXJ5aW5nICg1eXN3KSBHaXNsYXNvbiAmIEZpc2hCYXNlIiksDQogICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBlYnBhbFs3XSwNCiAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjMpICsNCiAgICAgICAgICAgeWxhYigiQ2F0Y2ggKHRvbm5lcykiKSArDQogICAgICAgICAgIHRoZW1lX2NsZWFuKCkpDQpgYGANCg0KIyBDb25jbHVzaW9ucw0KRnJvbSB0aGUgZGlhZ25vc3RpY3Mgb2YgdGhlc2UgcGxvdHMgd2UgY2FuIHNlZSB0aGF0IHRoZSBpbmNsdXNpb24gb2YgdGhlIG5ldyBuYXR1cmFsIG1vcnRhbGl0eSBlc3RpbWF0ZXMgZ3JlYXRseSBpbXByb3ZlcyB0aGUgbW9kZWwgZml0cy4gRnVydGhlcm1vcmUsIHdlIHNlZSB0aGF0IGhhdmluZyBhZ2UgYW5kIHRpbWUgdmFyeWluZyBuYXR1cmFsIG1vcnRhbGl0eSBwcm92aWRlcyB0aGUgYmVzdCBmaXQgb3ZlcmFsbC4gICBUaGlzIGlzIGxpa2VseSBkdWUgdG8gdGhlIGZhY3QgdGhhdCB0aGUgR2lzbGFzb24gbW9ydGFsaXRpZXMgYXJlIGJhc2VkIG9uIGJvdGggbGlmZS1oaXN0b3J5IHRyYWl0cyBhbmQgc2l6ZSwgYW5kIHRoZXJlZm9yZSwgYXMgdGhlIHNpemUgYXQgYWdlIGhhcyBiZWVuIGRlY3JlYXNpbmcgb3ZlciB0aW1lLCB0aGUgdGltZSB2YXJ5aW5nIG5tIGJldHRlciBtYXRjaGVzIHRoaXMgY2hhbmdlIHRoYW4gZG9lcyBhIGZpeGVkLCBhdmVyYWdlIG5tIGJhc2VkIG9uIGF2ZXJhZ2Ugc2l6ZS4gIFRoZSBvcHRpb24gb2YgdGltZS12YXJ5aW5nIG5tIGlzIGFsc28gaW50ZXJuYWxseSBjb2hlcmVudCwgYXMgd2UgaGF2ZSBpbmNsdWRlZCB0aW1lLXZhcnlpbmcgc3RvY2sgd2VpZ2h0cy1hdC1hZ2UgYXMgdGhlIGJlc3QgcmVwcmVzZW50YXRpb24gb2Ygc3RvY2sgZGV2ZWxvcG1lbnQgYW5kIHNvIHdlIHNob3VsZCByZWZsZWN0IHRoaXMgZGV2ZWxvcG1lbnQgaW4gb3VyIGVzdGltYXRpb25zIG9mIG5hdHVyYWwgbW9ydGFsaXR5IGFzIHdlbGwuDQoNCkhlbmNlLCBhcyBkaXNjdXNzZWQgaW4gdGhlIHdvcmtzaG9wIHBsZW5hcnksIHRoZXJlIGFyZSB0aHJlZSBsaW5lcyBvZiByZWFzb25pbmcgZm9yIHV0aWxpc2luZyB0aGUgdGltZSAmIGFnZSB2YXJ5aW5nIEdpc2xhc29uIGV0IGFsICgyMDEwKSBuYXR1cmFsIG1vcnRhbGl0eSBlc3RpbWF0ZXM6DQoNCi0gV2l0aCB0aGUgaGlzdG9yaWMgYWdlIHZhcnlpbmcgYnV0IHRpbWUgc3RhdGljIG5hdHVyYWwgbW9ydGFsaXRpZXMgKGZpeGVkIGFzIHNvbWUgIm1hZ2ljIG51bWJlcnMiKSwgb3VyIG1vZGVscyBhbGwgZGlzcGxheWVkIHJlc2lkdWFsIHBhdHRlcm5zIGluZGljYXRpdmUgb2YgdW5leHBsYWluZWQgbW9ydGFsaXR5Lg0KLSBDYWxjdWxhdGluZyBuYXR1cmFsIG1vcnRhbGl0aWVzIGJhc2VkIG9uIHRoZSBHaXNsYXNvbiBtb2RlbCwgZ3JlYXRseSBpbmNyZWFzZWQgbmF0dXJhbCBtb3J0YWxpdGllcyBhbmQgcHJvdmlkZWQgYSB0eXBpY2FsIG1vcnRhbGl0eSBhdCBhZ2UgY3VydmUsIHdoaWNoIHJlbW92ZWQgdGhlIHVuaWRpcmVjdGlvbmFsIHBhdHRlcm5zIGluIHRoZSByZXNpZHVhbCBjYXRjaCBhdCBhZ2VzLg0KLSBTY2FsaW5nIHRoZXNlIHRpbWUtaW52YXJpYW50IG5hdHVyYWwgbW9ydGFsaXRpZXMsIGNhbGN1bGF0ZWQgZnJvbSB0aW1lLXNlcmllcyBhdmVyYWdlcyBvZiBzaXplIGF0IGFnZSwgc2ltcGx5IHNlbGVjdGVkIGZvciBhIG1vZGVsIHRoYXQgaGFkIG1vcnRhbGl0aWVzIGFwcGxpZWQgYWNyb3NzIHRoZSB3aG9sZSB0aW1lLXNlcmllcywgdGhhdCB3ZXJlIGJpYXNlZCB0b3dhcmRzIHRoZSBoaWdoZXIgbW9ydGFsaXRpZXMgc2VlbiBpbiByZWNlbnQgeWVhcnMuDQotIFRoZSB0aW1lLXZhcnlpbmcgbmF0dXJhbCBtb3J0YWxpdGllcyBwcm92aWRlcyB0aGUgYmVzdCBtb2RlbCBmaXQgKGJhc2VkIG9uIEFJQykNCg0KSW4gdGhlIG5leHQgd29ya2luZyBkb2N1bWVudCB3ZSB3aWxsIGludmVzdGlnYXRlIHRoZSB1dGlsaXR5IG9mIHNldHRpbmcgbWF0dXJpdHkgYXQgYWdlLTEgdG8gemVybywgYmFzZWQgb24gYmFzaWMgYmlvbG9naWNhbCBrbm93bGVkZ2Ugb2YgdGhlIHNwZWNpZXMsIGFuZCB0aGUgZmFjdCB0aGF0IHRoZXJlIG1heSBiZSBzb21lIGFnZSByZWFkaW5nIGVycm9ycyBtZWFuaW5nIHRoYXQgb2xkZXIgZmlzaCBhcmUgYmVpbmcgYWdlZCB0byAxLiBGdXJ0aGVybW9yZSwgd2Ugd2lsbCBpbnZlc3RpZ2F0ZSBhIHJhbmdlIG9mIHdheXMgb2YgaW5jbHVkaW5nIGRpc2NhcmQgc3Vydml2YWwgaW4gdGhlIGFzc2Vzc21lbnQgcHJvY2VzcyBiZWZvcmUgZmluYWxseSBhdHRlbXB0aW5nIHRvIGluY2x1ZGUgcmVjZW50bHkgYXZhaWxhYmxlIEdlcm1hbiByZWNyZWF0aW9uYWwgZmlzaGVyaWVzIGRhdGEuIA==