1 Introduction

1.1 About this document

This working document is the third step in evaluating various assessment models for the newly combined Plaice stock, across the Sub Divisions 21 - 32. In the first assessment working document ( Ple.27.3a.21-32_Assessments ), Some of the more fundamental decisions about input data were evaluated and decided upon. In the second assessment working document ( Ple.27.3a.21-32_WKBPLAICE_NewMortality.RMD ), we focused in on an issue that is new to the stocks in this area, namely time-varying natural mortality. From this work we selected a model that uses Gislason et al (2010) natural mortalities calculated from life-history traits that were found from literature (via fishbase.se), and the varying length at age in the stock. Now, in this document, we investigate three different variations of input data to the selected model:

  1. The setting of maturity at age 1 to zero.
  2. Attempts to account for survival of discards from the commercial fishery.
  1. Scenario of relatively low levels of discard survival.
  2. Scenario of mid-levels of discards survival.
  3. Scenario of relatively high levels of discard survival.
  1. An attempt to integrate German recreational harvests into the assessment model.

In scenario 1, we investigate the effect of setting maturity at age 1 to zero. In the maturity ogives calculated from the surveys, we see that ~25% of age1 fish are found to be mature. This conflicts with fundamental knowledge of European plaice biology, even in the specific context of this stock. Furhtermore, there are some issues around aging fish with some systematic errors reported for counting the first year’s ring. Hence some individuals that are sampled as being mature, may be incorrectly aged as age 1, when they are in fact age 2. Because of the large influxes of recruitment, having a significant proportion of recruits as mature leads to a volatile inflation of the SSB and a perception of the stock as larger than it really is. By manually setting maturity at age 1 to zero, we over-write any errors introduced during sampling with expert knowledge that age 1 fish are extremely unlikely to be mature, which reduces this over-estimation and interannual volatility of SSB.

In scenario 2, we run a type of sensitivity analysis but base the range of values in the sensitivity profile on the best available knowledge for discard survival. Discard survival is difficult to estimate for this species and this stock for multiple reasons. Survival varies according to a range of factors, only some of which we can account for and for only a subset of which do we have literature based observations of survival. For example, Survival after discards has shown to be correlated with:

  • Time exposed to air
  • Temperature (season)
  • Gear type (varying across different metiers)
  • Dominant species in the haul
  • many others

In our data compilation process we can account for some of these to greater or lesser extents:

  • Temperature (season) by applying different survival rates per quarter.
  • Gear type by applying different survival rates to “active” and “passive” gears.
  • Geartype and Dominant species in the haul by utilising survival rates reported from studies in different management areas (e.g. studies in SD21/Kattegat or analagous Skagerrak, vs studies from the Belt Seas/Western Baltic Sea)

However, there are many more combinations of these factors than what is addressed in studies reported in primary or grey literature. Therefore, we’ve used the studies at face value, where they match some combinations of these factors, then used estimations for the gaps. The estimations are based on copying temporal trends from different fleet segments, where seasonal variation has been reported, and applying them to those segments where survival rates have only been reported for one season. Furthermore, because fleet segments in this stock are aggregated into “active” and “passive”, we take averages (unweighted) across different metiers where these are reported.

For more details on the evidence used and how it is applied, see another of the working documents from this workshop.

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 few variables manually.
The first is the DataYear, which is the year immediately preceeding the assessment year or the year for which the most recent catch 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

The baseline model we’ve selected for this working document, comes from the investigations into the different versions of natural mortality we investigated in the previous working document: Ple.27.3a.21-32_WKBPLAICE_NewMortality.RMD.

This baseline model is called ple.27.21-32_WKBPLAICE_2024_BioParsw_nmG5Fb and can be found on stockassessment.org.

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")
# =====

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: 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.

2.1.1 Visualise fits to data by age over time across fleets

## 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 2.1: 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 2.2: 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 2.3: 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 2.4: Standard Devations by Fleet; Gislason, time-varying mortality (FishBase)

2.1.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 2.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 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 2.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 varying (five year sliiding window mean), age varying, Gislason natural mortalities (FishBase).

2.1.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_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

2.1.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_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 2.7: 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 +).

2.1.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_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 2.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 variant (5 year sliding window mean), Gislason natural mortalities (FishBase).

3 Maturity Age1 Set to Zero

This model is called ple.27.21-32_WKBPLAICE_2024_BP_nmG5Fb_mo1 and can be found on stockassessment.org.

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

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.

3.1.1 Visualise fits to data by age over time across fleets

## Extract data from model object
logObs_nmG5Fb_mo1 <- split(fit_nmG5Fb_mo1$data$logobs, ceiling(seq_along(fit_nmG5Fb_mo1$data$logobs)/fit_nmG5Fb_mo1$data$maxAgePerFleet[1]))
logPred_nmG5Fb_mo1 <- split(fit_nmG5Fb_mo1$rep$predObs, ceiling(seq_along(fit_nmG5Fb_mo1$rep$predObs)/fit_nmG5Fb_mo1$data$maxAgePerFleet[1]))

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

### Populate the data frame for observations
for (i in seq_along(logObs_nmG5Fb_mo1)) {
  # 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_mo1[[i]])
  logObs_nmG5Fb_mo1_df <- rbind(logObs_nmG5Fb_mo1_df, temp_df)
}

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

### Populate the data frame for predictions
for (i in seq_along(logPred_nmG5Fb_mo1)) {
  # 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_mo1[[i]])
  logPred_nmG5Fb_mo1_df <- rbind(logPred_nmG5Fb_mo1_df, temp_df)
}

## Plot
logPred_nmG5Fb_mo1_df$age <- as.character(logPred_nmG5Fb_mo1_df$age)
logObs_nmG5Fb_mo1_df$age <- as.character(logObs_nmG5Fb_mo1_df$age)

ggplotly(ggplot()+
           geom_point(data = logObs_nmG5Fb_mo1_df[logObs_nmG5Fb_mo1_df$fleet == 1 & logObs_nmG5Fb_mo1_df$year != (DataYear+1), ],
                      mapping = aes(x = year,
                                    y = logObs,
                                    colour = age),
                      shape = 21) +
           geom_line(data = logPred_nmG5Fb_mo1_df[logPred_nmG5Fb_mo1_df$fleet == 1 & logPred_nmG5Fb_mo1_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 Age1 maturity set to zero, fit to catch data by age (values on the model link function scale).

# fitplot(fit_nmG5Fb_mo1, fleets=1)
ggplotly(ggplot()+
           geom_point(data = logObs_nmG5Fb_mo1_df[logObs_nmG5Fb_mo1_df$fleet == 2 & logObs_nmG5Fb_mo1_df$year != (DataYear+1), ],
                      mapping = aes(x = year,
                                    y = logObs,
                                    colour = age),
                      shape = 21) +
           geom_line(data = logPred_nmG5Fb_mo1_df[logPred_nmG5Fb_mo1_df$fleet == 2 & logPred_nmG5Fb_mo1_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 Age1 maturity set to zero, fit to Q1 survey data by age (values on the model link function scale).

# fitplot(fit_nmG5Fb_mo1, fleets=2)
ggplotly(ggplot()+
           geom_point(data = logObs_nmG5Fb_mo1_df[logObs_nmG5Fb_mo1_df$fleet == 3 & logObs_nmG5Fb_mo1_df$year != (DataYear+1), ],
                      mapping = aes(x = year,
                                    y = logObs,
                                    colour = age),
                      shape = 21) +
           geom_line(data = logPred_nmG5Fb_mo1_df[logPred_nmG5Fb_mo1_df$fleet == 3 & logPred_nmG5Fb_mo1_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 Age1 maturity set to zero, fit to Q3/4 survey data by age (values on the model link function scale).

# fitplot(fit_nmG5Fb_mo1, fleets=3)
sdplot(fit_nmG5Fb_mo1, marg = c(5, 4, 1, 1))
Standard Devations by Fleet; Age1 maturity set to zero.

Figure 3.4: Standard Devations by Fleet; Age1 maturity set to zero.

3.1.2 Residuals

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

resid_nmG5Fb_mo1_df$fleetAltName <- ifelse(resid_nmG5Fb_mo1_df$fleet == 1, "Residual Fishing",
    ifelse(resid_nmG5Fb_mo1_df$fleet == 2, "Q1 Surveys", ifelse(resid_nmG5Fb_mo1_df$fleet ==
        3, "Q3/4 Surveys", NA)))
if (!all(fit_nmG5Fb_mo1$conf$obsCorStruct == "ID")) {
    corplot(fit_nmG5Fb_mo1)
    # 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 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 varying (five year sliiding window mean), age varying, Gislason natural mortalities (FishBase).

ggplotly(ggplot(resid_nmG5Fb_mo1_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 age1 maturities set to zero.

3.1.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_nmG5Fb_mo1 <- jit(fit = fit_nmG5Fb_mo1)

mt <- as.data.frame(modeltable(jit_nmG5Fb_mo1))
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_mo1)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

3.1.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_nmG5Fb_mo1 <- leaveout(fit_nmG5Fb_mo1)

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


woq1 <- data.frame(Year = as.integer(row.names(summary(LO_nmG5Fb_mo1$`w.o. Q1IBTS+BITS+CodSD21-25`))),
    SSB = q1mat$SSB, Fbar = q1mat$`Fbar(3-5)`, R_age1 = q1mat$`R(age 1)`, CatchEst = catchtable(LO_nmG5Fb_mo1$`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_mo1$`w.o. Q34IBTS+BITS+CodSD21-25`)[,
        1], series = rep("wo_Q34", times = (nrow(q3mat) - 1)))


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

losum_nmG5Fb_mo1 <- rbind(woq1, woq34, asumi_nmG5Fb_mo1)
# ssbplot(LO)
lossb_nmG5Fb_mo1 <- ggplotly(ggplot() + geom_line(data = losum_nmG5Fb_mo1, mapping = aes(x = Year,
    y = SSB, colour = series)) + geom_ribbon(data = asum_nmG5Fb_mo1, 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_mo1 <- ggplotly(ggplot() + geom_line(data = losum_nmG5Fb_mo1, mapping = aes(x = Year,
    y = Fbar, colour = series)) + geom_ribbon(data = asum_nmG5Fb_mo1, 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_mo1 <- ggplotly(ggplot() + geom_line(data = losum_nmG5Fb_mo1, mapping = aes(x = Year,
    y = R_age1, colour = series)) + geom_ribbon(data = asum_nmG5Fb_mo1, 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_mo1 <- ggplotly(ggplot() + geom_line(data = losum_nmG5Fb_mo1, mapping = aes(x = Year,
    y = CatchEst, colour = series)) + geom_ribbon(data = asum_nmG5Fb_mo1[asum_nmG5Fb_mo1$Year !=
    (DataYear + 1), ], mapping = aes(x = Year, ymin = Catchlow, ymax = Catchhigh),
    fill = "black", alpha = 0.3) + geom_point(data = asum_nmG5Fb_mo1[asum_nmG5Fb_mo1$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_mo1, lof_nmG5Fb_mo1, lorec_nmG5Fb_mo1, loca_nmG5Fb_mo1,
    nrows = 2, shareX = TRUE, titleY = TRUE), showlegend = FALSE)

Figure 3.7: Leave-one-out re-fits for the model with age1 maturities set to zero (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.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_nmG5Fb_mo1 <- as.data.frame(summary(fit_nmG5Fb_mo1))
asum_nmG5Fb_mo1$Year <- as.integer(row.names(summary(fit_nmG5Fb_mo1)))
ct_nmG5Fb_mo1 <- as.data.frame(catchtable(fit_nmG5Fb_mo1, obs.show = TRUE))
ct_nmG5Fb_mo1$Year <- as.integer(rownames(ct_nmG5Fb_mo1))
rownames(ct_nmG5Fb_mo1) <- NULL
ct_nmG5Fb_mo1 <- rbind(ct_nmG5Fb_mo1, data.frame(Estimate = NA, Low = NA, High = NA,
    sop.catch = NA, Year = as.integer(2024)))
asum_nmG5Fb_mo1 <- merge(x = asum_nmG5Fb_mo1, y = ct_nmG5Fb_mo1, by = "Year")
colnames(asum_nmG5Fb_mo1) <- c("Year", "R_age1", "Rlow", "Rhigh", "SSB", "SSBlow",
    "SSBhigh", "Fbar", "Flow", "Fhigh", "CatchEst", "Catchlow", "Catchhigh", "CatchObs")

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

# =====
RETRO_nmG5Fb_mo1 <- retro(fit_nmG5Fb_mo1, year = 5)
rho_nmG5Fb_mo1 <- mohn(RETRO_nmG5Fb_mo1, lag = 1)

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

for (i in 1:length(RETRO_nmG5Fb_mo1)) {
    tsum <- as.data.frame(summary(RETRO_nmG5Fb_mo1[[i]]))
    tsum$Year <- as.integer(row.names(summary(RETRO_nmG5Fb_mo1[[i]])))
    tsum <- cbind(tsum, catchtable(RETRO_nmG5Fb_mo1[[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_mo1_df <- rbind(ret_nmG5Fb_mo1_df, tsum)
}
ret_nmG5Fb_mo1_df$series <- factor(ret_nmG5Fb_mo1_df$series, levels = c("full", "1",
    "2", "3", "4", "5"))
# ssbplot(RETRO)
retssb_nmG5Fb_mo1 <- layout(ggplotly(ggplot() + geom_line(data = ret_nmG5Fb_mo1_df,
    mapping = aes(x = Year, y = SSB, colour = series)) + geom_ribbon(data = asum_nmG5Fb_mo1[asum_nmG5Fb_mo1$Year !=
    max(asum_nmG5Fb_mo1$Year), ], mapping = aes(x = Year, ymin = SSBlow, ymax = SSBhigh),
    fill = "black", alpha = 0.2) + annotate(geom = "text", y = max(ret_nmG5Fb_mo1_df$SSBhigh) *
    0.85, x = ((max(ret_nmG5Fb_mo1_df$Year) - min(ret_nmG5Fb_mo1_df$Year)) * 0.2) +
    min(ret_nmG5Fb_mo1_df$Year), label = paste0("Mohn's Rho = ", round(rho_nmG5Fb_mo1[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_mo1 <- layout(ggplotly(ggplot() + geom_line(data = ret_nmG5Fb_mo1_df,
    mapping = aes(x = Year, y = Fbar, colour = series)) + geom_ribbon(data = asum_nmG5Fb_mo1[asum_nmG5Fb_mo1$Year !=
    max(asum_nmG5Fb_mo1$Year), ], mapping = aes(x = Year, ymin = Flow, ymax = Fhigh),
    fill = "black", alpha = 0.3) + annotate(geom = "text", y = max(ret_nmG5Fb_mo1_df$Fhigh) *
    0.85, x = ((max(ret_nmG5Fb_mo1_df$Year) - min(ret_nmG5Fb_mo1_df$Year)) * 0.8) +
    min(ret_nmG5Fb_mo1_df$Year), label = paste0("Mohn's Rho = ", round(rho_nmG5Fb_mo1[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_mo1 <- layout(ggplotly(ggplot() + geom_line(data = ret_nmG5Fb_mo1_df,
    mapping = aes(x = Year, y = R_age1, colour = series)) + geom_ribbon(data = asum_nmG5Fb_mo1[asum_nmG5Fb_mo1$Year !=
    max(asum_nmG5Fb_mo1$Year), ], mapping = aes(x = Year, ymin = Rlow, ymax = Rhigh),
    fill = "black", alpha = 0.3) + annotate(geom = "text", y = max(ret_nmG5Fb_mo1_df$Rhigh) *
    0.85, x = ((max(ret_nmG5Fb_mo1_df$Year) - min(ret_nmG5Fb_mo1_df$Year)) * 0.2) +
    min(ret_nmG5Fb_mo1_df$Year), label = paste0("Mohn's Rho = ", round(rho_nmG5Fb_mo1[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_mo1 <- ggplotly(ggplot() + geom_line(data = ret_nmG5Fb_mo1_df, mapping = aes(x = Year,
    y = CatchEst, colour = series)) + geom_ribbon(data = asum_nmG5Fb_mo1[asum_nmG5Fb_mo1$Year !=
    max(asum_nmG5Fb_mo1$Year), ], mapping = aes(x = Year, ymin = Catchlow, ymax = Catchhigh),
    fill = "black", alpha = 0.3) + geom_point(data = asum_nmG5Fb_mo1[asum_nmG5Fb_mo1$Year !=
    max(asum_nmG5Fb_mo1$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_mo1, retf_nmG5Fb_mo1, retrec_nmG5Fb_mo1, retca_nmG5Fb_mo1,
    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 with age1 maturities set to zero.

3.2 SimStudy

ss_nmG5Fb_mo1 <- simstudy(fit = fit_nmG5Fb_mo1, nsim = 10)

4 Discard Survival

4.1 Low Discard Survival Estimates

This model is called ple.27.21-32_WKBPLAICE_2024_nmG5Fb_mo1_dslow and can be found on stockassessment.org.

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

4.1.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: 129
  • 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.

4.1.1.1 Visualise fits to data by age over time across fleets

## Extract data from model object
logObs_nmG5Fb_mo1_dslow <- split(fit_nmG5Fb_mo1_dslow$data$logobs, ceiling(seq_along(fit_nmG5Fb_mo1_dslow$data$logobs)/fit_nmG5Fb_mo1_dslow$data$maxAgePerFleet[1]))
logPred_nmG5Fb_mo1_dslow <- split(fit_nmG5Fb_mo1_dslow$rep$predObs, ceiling(seq_along(fit_nmG5Fb_mo1_dslow$rep$predObs)/fit_nmG5Fb_mo1_dslow$data$maxAgePerFleet[1]))

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

### Populate the data frame for observations
for (i in seq_along(logObs_nmG5Fb_mo1_dslow)) {
  # 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_mo1_dslow[[i]])
  logObs_nmG5Fb_mo1_dslow_df <- rbind(logObs_nmG5Fb_mo1_dslow_df, temp_df)
}

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

### Populate the data frame for predictions
for (i in seq_along(logPred_nmG5Fb_mo1_dslow)) {
  # 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_mo1_dslow[[i]])
  logPred_nmG5Fb_mo1_dslow_df <- rbind(logPred_nmG5Fb_mo1_dslow_df, temp_df)
}

## Plot
logPred_nmG5Fb_mo1_dslow_df$age <- as.character(logPred_nmG5Fb_mo1_dslow_df$age)
logObs_nmG5Fb_mo1_dslow_df$age <- as.character(logObs_nmG5Fb_mo1_dslow_df$age)

ggplotly(ggplot()+
           geom_point(data = logObs_nmG5Fb_mo1_dslow_df[logObs_nmG5Fb_mo1_dslow_df$fleet == 1 & logObs_nmG5Fb_mo1_dslow_df$year != (DataYear+1), ],
                      mapping = aes(x = year,
                                    y = logObs,
                                    colour = age),
                      shape = 21) +
           geom_line(data = logPred_nmG5Fb_mo1_dslow_df[logPred_nmG5Fb_mo1_dslow_df$fleet == 1 & logPred_nmG5Fb_mo1_dslow_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 Low discard survival estimates, fit to catch data by age (values on the model link function scale).

# fitplot(fit_nmG5Fb_mo1_dslow, fleets=1)
ggplotly(ggplot()+
           geom_point(data = logObs_nmG5Fb_mo1_dslow_df[logObs_nmG5Fb_mo1_dslow_df$fleet == 2 & logObs_nmG5Fb_mo1_dslow_df$year != (DataYear+1), ],
                      mapping = aes(x = year,
                                    y = logObs,
                                    colour = age),
                      shape = 21) +
           geom_line(data = logPred_nmG5Fb_mo1_dslow_df[logPred_nmG5Fb_mo1_dslow_df$fleet == 2 & logPred_nmG5Fb_mo1_dslow_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 Low discard survival estimates, fit to Q1 survey data by age (values on the model link function scale).

# fitplot(fit_nmG5Fb_mo1_dslow, fleets=2)
ggplotly(ggplot()+
           geom_point(data = logObs_nmG5Fb_mo1_dslow_df[logObs_nmG5Fb_mo1_dslow_df$fleet == 3 & logObs_nmG5Fb_mo1_dslow_df$year != (DataYear+1), ],
                      mapping = aes(x = year,
                                    y = logObs,
                                    colour = age),
                      shape = 21) +
           geom_line(data = logPred_nmG5Fb_mo1_dslow_df[logPred_nmG5Fb_mo1_dslow_df$fleet == 3 & logPred_nmG5Fb_mo1_dslow_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 low discard survival estimates, fit to Q3/4 survey data by age (values on the model link function scale).

# fitplot(fit_nmG5Fb_mo1_dslow, fleets=3)
sdplot(fit_nmG5Fb_mo1_dslow, marg = c(5, 4, 1, 1))
Standard Devations by Fleet; low discard survival estimates.

Figure 4.4: Standard Devations by Fleet; low discard survival estimates.

4.1.1.2 Residuals

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

resid_nmG5Fb_mo1_dslow_df$fleetAltName <- ifelse(resid_nmG5Fb_mo1_dslow_df$fleet ==
    1, "Residual Fishing", ifelse(resid_nmG5Fb_mo1_dslow_df$fleet == 2, "Q1 Surveys",
    ifelse(resid_nmG5Fb_mo1_dslow_df$fleet == 3, "Q3/4 Surveys", NA)))
if (!all(fit_nmG5Fb_mo1_dslow$conf$obsCorStruct == "ID")) {
    corplot(fit_nmG5Fb_mo1_dslow)
    # 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 low discard survival estimates.

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 low discard survival estimates.

ggplotly(ggplot(resid_nmG5Fb_mo1_dslow_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 low discard survival estimates.

4.1.1.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_nmG5Fb_mo1_dslow <- jit(fit = fit_nmG5Fb_mo1_dslow)

mt <- as.data.frame(modeltable(jit_nmG5Fb_mo1_dslow))
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_mo1_dslow)Measures of fit for a series of model refits with jitter applied to the input parameters.
log(L) #par AIC model
-94.497 36 260.994 M1
-94.497 36 260.994 M2
-94.497 36 260.994 M3
-94.497 36 260.994 M4
-94.497 36 260.994 M5
-94.497 36 260.994 M6
-94.497 36 260.994 M7
-94.497 36 260.994 M8
-94.497 36 260.994 M9
-94.497 36 260.994 M10
-94.497 36 260.994 M11

4.1.1.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_nmG5Fb_mo1_dslow <- leaveout(fit_nmG5Fb_mo1_dslow)

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


woq1 <- data.frame(Year = as.integer(row.names(summary(LO_nmG5Fb_mo1_dslow$`w.o. Q1IBTS+BITS+CodSD21-25`))),
    SSB = q1mat$SSB, Fbar = q1mat$`Fbar(3-5)`, R_age1 = q1mat$`R(age 1)`, CatchEst = catchtable(LO_nmG5Fb_mo1_dslow$`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_mo1_dslow$`w.o. Q34IBTS+BITS+CodSD21-25`)[,
        1], series = rep("wo_Q34", times = (nrow(q3mat) - 1)))


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

losum_nmG5Fb_mo1_dslow <- rbind(woq1, woq34, asumi_nmG5Fb_mo1_dslow)
# ssbplot(LO)
lossb_nmG5Fb_mo1_dslow <- ggplotly(ggplot() + geom_line(data = losum_nmG5Fb_mo1_dslow,
    mapping = aes(x = Year, y = SSB, colour = series)) + geom_ribbon(data = asum_nmG5Fb_mo1_dslow,
    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_mo1_dslow <- ggplotly(ggplot() + geom_line(data = losum_nmG5Fb_mo1_dslow,
    mapping = aes(x = Year, y = Fbar, colour = series)) + geom_ribbon(data = asum_nmG5Fb_mo1_dslow,
    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_mo1_dslow <- ggplotly(ggplot() + geom_line(data = losum_nmG5Fb_mo1_dslow,
    mapping = aes(x = Year, y = R_age1, colour = series)) + geom_ribbon(data = asum_nmG5Fb_mo1_dslow,
    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_mo1_dslow <- ggplotly(ggplot() + geom_line(data = losum_nmG5Fb_mo1_dslow,
    mapping = aes(x = Year, y = CatchEst, colour = series)) + geom_ribbon(data = asum_nmG5Fb_mo1_dslow[asum_nmG5Fb_mo1_dslow$Year !=
    (DataYear + 1), ], mapping = aes(x = Year, ymin = Catchlow, ymax = Catchhigh),
    fill = "black", alpha = 0.3) + geom_point(data = asum_nmG5Fb_mo1_dslow[asum_nmG5Fb_mo1_dslow$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_mo1_dslow, lof_nmG5Fb_mo1_dslow, lorec_nmG5Fb_mo1_dslow,
    loca_nmG5Fb_mo1_dslow, nrows = 2, shareX = TRUE, titleY = TRUE), showlegend = FALSE)

Figure 4.7: Leave-one-out re-fits for the model with age1 maturities set to zero (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.1.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_nmG5Fb_mo1_dslow <- as.data.frame(summary(fit_nmG5Fb_mo1_dslow))
asum_nmG5Fb_mo1_dslow$Year <- as.integer(row.names(summary(fit_nmG5Fb_mo1_dslow)))
ct_nmG5Fb_mo1_dslow <- as.data.frame(catchtable(fit_nmG5Fb_mo1_dslow, obs.show = TRUE))
ct_nmG5Fb_mo1_dslow$Year <- as.integer(rownames(ct_nmG5Fb_mo1_dslow))
rownames(ct_nmG5Fb_mo1_dslow) <- NULL
ct_nmG5Fb_mo1_dslow <- rbind(ct_nmG5Fb_mo1_dslow, data.frame(Estimate = NA, Low = NA,
    High = NA, sop.catch = NA, Year = as.integer(2024)))
asum_nmG5Fb_mo1_dslow <- merge(x = asum_nmG5Fb_mo1_dslow, y = ct_nmG5Fb_mo1_dslow,
    by = "Year")
colnames(asum_nmG5Fb_mo1_dslow) <- c("Year", "R_age1", "Rlow", "Rhigh", "SSB", "SSBlow",
    "SSBhigh", "Fbar", "Flow", "Fhigh", "CatchEst", "Catchlow", "Catchhigh", "CatchObs")

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

# =====
RETRO_nmG5Fb_mo1_dslow <- retro(fit_nmG5Fb_mo1_dslow, year = 5)
rho_nmG5Fb_mo1_dslow <- mohn(RETRO_nmG5Fb_mo1_dslow, lag = 1)

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

for (i in 1:length(RETRO_nmG5Fb_mo1_dslow)) {
    tsum <- as.data.frame(summary(RETRO_nmG5Fb_mo1_dslow[[i]]))
    tsum$Year <- as.integer(row.names(summary(RETRO_nmG5Fb_mo1_dslow[[i]])))
    tsum <- cbind(tsum, catchtable(RETRO_nmG5Fb_mo1_dslow[[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_mo1_dslow_df <- rbind(ret_nmG5Fb_mo1_dslow_df, tsum)
}
ret_nmG5Fb_mo1_dslow_df$series <- factor(ret_nmG5Fb_mo1_dslow_df$series, levels = c("full",
    "1", "2", "3", "4", "5"))
# ssbplot(RETRO)
retssb_nmG5Fb_mo1_dslow <- layout(ggplotly(ggplot() + geom_line(data = ret_nmG5Fb_mo1_dslow_df,
    mapping = aes(x = Year, y = SSB, colour = series)) + geom_ribbon(data = asum_nmG5Fb_mo1_dslow[asum_nmG5Fb_mo1_dslow$Year !=
    max(asum_nmG5Fb_mo1_dslow$Year), ], mapping = aes(x = Year, ymin = SSBlow, ymax = SSBhigh),
    fill = "black", alpha = 0.2) + annotate(geom = "text", y = max(ret_nmG5Fb_mo1_dslow_df$SSBhigh) *
    0.85, x = ((max(ret_nmG5Fb_mo1_dslow_df$Year) - min(ret_nmG5Fb_mo1_dslow_df$Year)) *
    0.2) + min(ret_nmG5Fb_mo1_dslow_df$Year), label = paste0("Mohn's Rho = ", round(rho_nmG5Fb_mo1_dslow[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_mo1_dslow <- layout(ggplotly(ggplot() + geom_line(data = ret_nmG5Fb_mo1_dslow_df,
    mapping = aes(x = Year, y = Fbar, colour = series)) + geom_ribbon(data = asum_nmG5Fb_mo1_dslow[asum_nmG5Fb_mo1_dslow$Year !=
    max(asum_nmG5Fb_mo1_dslow$Year), ], mapping = aes(x = Year, ymin = Flow, ymax = Fhigh),
    fill = "black", alpha = 0.3) + annotate(geom = "text", y = max(ret_nmG5Fb_mo1_dslow_df$Fhigh) *
    0.85, x = ((max(ret_nmG5Fb_mo1_dslow_df$Year) - min(ret_nmG5Fb_mo1_dslow_df$Year)) *
    0.8) + min(ret_nmG5Fb_mo1_dslow_df$Year), label = paste0("Mohn's Rho = ", round(rho_nmG5Fb_mo1_dslow[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_mo1_dslow <- layout(ggplotly(ggplot() + geom_line(data = ret_nmG5Fb_mo1_dslow_df,
    mapping = aes(x = Year, y = R_age1, colour = series)) + geom_ribbon(data = asum_nmG5Fb_mo1_dslow[asum_nmG5Fb_mo1_dslow$Year !=
    max(asum_nmG5Fb_mo1_dslow$Year), ], mapping = aes(x = Year, ymin = Rlow, ymax = Rhigh),
    fill = "black", alpha = 0.3) + annotate(geom = "text", y = max(ret_nmG5Fb_mo1_dslow_df$Rhigh) *
    0.85, x = ((max(ret_nmG5Fb_mo1_dslow_df$Year) - min(ret_nmG5Fb_mo1_dslow_df$Year)) *
    0.2) + min(ret_nmG5Fb_mo1_dslow_df$Year), label = paste0("Mohn's Rho = ", round(rho_nmG5Fb_mo1_dslow[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_mo1_dslow <- ggplotly(ggplot() + geom_line(data = ret_nmG5Fb_mo1_dslow_df,
    mapping = aes(x = Year, y = CatchEst, colour = series)) + geom_ribbon(data = asum_nmG5Fb_mo1_dslow[asum_nmG5Fb_mo1_dslow$Year !=
    max(asum_nmG5Fb_mo1_dslow$Year), ], mapping = aes(x = Year, ymin = Catchlow,
    ymax = Catchhigh), fill = "black", alpha = 0.3) + geom_point(data = asum_nmG5Fb_mo1_dslow[asum_nmG5Fb_mo1_dslow$Year !=
    max(asum_nmG5Fb_mo1_dslow$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_mo1_dslow, retf_nmG5Fb_mo1_dslow, retrec_nmG5Fb_mo1_dslow,
    retca_nmG5Fb_mo1_dslow, 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 with low discard survival estimates.

4.2 Medium Discard Survival Estimates

This model is called ple.27.21-32_WKBPLAICE_2024_nmG5Fb_mo1_dsmed and can be found on stockassessment.org.

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

4.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: 133
  • 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.

4.2.1.1 Visualise fits to data by age over time across fleets

## Extract data from model object
logObs_nmG5Fb_mo1_dsmed <- split(fit_nmG5Fb_mo1_dsmed$data$logobs, ceiling(seq_along(fit_nmG5Fb_mo1_dsmed$data$logobs)/fit_nmG5Fb_mo1_dsmed$data$maxAgePerFleet[1]))
logPred_nmG5Fb_mo1_dsmed <- split(fit_nmG5Fb_mo1_dsmed$rep$predObs, ceiling(seq_along(fit_nmG5Fb_mo1_dsmed$rep$predObs)/fit_nmG5Fb_mo1_dsmed$data$maxAgePerFleet[1]))

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

### Populate the data frame for observations
for (i in seq_along(logObs_nmG5Fb_mo1_dsmed)) {
  # 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_mo1_dsmed[[i]])
  logObs_nmG5Fb_mo1_dsmed_df <- rbind(logObs_nmG5Fb_mo1_dsmed_df, temp_df)
}

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

### Populate the data frame for predictions
for (i in seq_along(logPred_nmG5Fb_mo1_dsmed)) {
  # 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_mo1_dsmed[[i]])
  logPred_nmG5Fb_mo1_dsmed_df <- rbind(logPred_nmG5Fb_mo1_dsmed_df, temp_df)
}

## Plot
logPred_nmG5Fb_mo1_dsmed_df$age <- as.character(logPred_nmG5Fb_mo1_dsmed_df$age)
logObs_nmG5Fb_mo1_dsmed_df$age <- as.character(logObs_nmG5Fb_mo1_dsmed_df$age)

ggplotly(ggplot()+
           geom_point(data = logObs_nmG5Fb_mo1_dsmed_df[logObs_nmG5Fb_mo1_dsmed_df$fleet == 1 & logObs_nmG5Fb_mo1_dsmed_df$year != (DataYear+1), ],
                      mapping = aes(x = year,
                                    y = logObs,
                                    colour = age),
                      shape = 21) +
           geom_line(data = logPred_nmG5Fb_mo1_dsmed_df[logPred_nmG5Fb_mo1_dsmed_df$fleet == 1 & logPred_nmG5Fb_mo1_dsmed_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.9: Model with medium discard survival estimates, fit to catch data by age (values on the model link function scale).

# fitplot(fit_nmG5Fb_mo1_dsmed, fleets=1)
ggplotly(ggplot()+
           geom_point(data = logObs_nmG5Fb_mo1_dsmed_df[logObs_nmG5Fb_mo1_dsmed_df$fleet == 2 & logObs_nmG5Fb_mo1_dsmed_df$year != (DataYear+1), ],
                      mapping = aes(x = year,
                                    y = logObs,
                                    colour = age),
                      shape = 21) +
           geom_line(data = logPred_nmG5Fb_mo1_dsmed_df[logPred_nmG5Fb_mo1_dsmed_df$fleet == 2 & logPred_nmG5Fb_mo1_dsmed_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 medium discard survival estimates, fit to Q1 survey data by age (values on the model link function scale).

# fitplot(fit_nmG5Fb_mo1_dsmed, fleets=2)
ggplotly(ggplot()+
           geom_point(data = logObs_nmG5Fb_mo1_dsmed_df[logObs_nmG5Fb_mo1_dsmed_df$fleet == 3 & logObs_nmG5Fb_mo1_dsmed_df$year != (DataYear+1), ],
                      mapping = aes(x = year,
                                    y = logObs,
                                    colour = age),
                      shape = 21) +
           geom_line(data = logPred_nmG5Fb_mo1_dsmed_df[logPred_nmG5Fb_mo1_dsmed_df$fleet == 3 & logPred_nmG5Fb_mo1_dsmed_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 medium discard survival estimates, fit to Q3/4 survey data by age (values on the model link function scale).

# fitplot(fit_nmG5Fb_mo1_dsmed, fleets=3)
sdplot(fit_nmG5Fb_mo1_dsmed, marg = c(5, 4, 1, 1))
Standard Devations by Fleet; medium discard survival estimates.

Figure 4.12: Standard Devations by Fleet; medium discard survival estimates.

4.2.1.2 Residuals

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

resid_nmG5Fb_mo1_dsmed_df$fleetAltName <- ifelse(resid_nmG5Fb_mo1_dsmed_df$fleet ==
    1, "Residual Fishing", ifelse(resid_nmG5Fb_mo1_dsmed_df$fleet == 2, "Q1 Surveys",
    ifelse(resid_nmG5Fb_mo1_dsmed_df$fleet == 3, "Q3/4 Surveys", NA)))
if (!all(fit_nmG5Fb_mo1_dsmed$conf$obsCorStruct == "ID")) {
    corplot(fit_nmG5Fb_mo1_dsmed)
    # 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 medium discard mortality.

Figure 4.13: Estimated correlations in residual variation between ages for each of the fishing fleet (top) and the two surveys (middle & bottom), from the Model with medium discard mortality.

ggplotly(ggplot(resid_nmG5Fb_mo1_dsmed_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.14: 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 medium discard mortality.

4.2.1.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_nmG5Fb_mo1_dsmed <- jit(fit = fit_nmG5Fb_mo1_dsmed)

mt <- as.data.frame(modeltable(jit_nmG5Fb_mo1_dsmed))
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_mo1_dsmed)Measures of fit for a series of model refits with jitter applied to the input parameters.
log(L) #par AIC model
-95.389 36 262.779 M1
-95.389 36 262.779 M2
-95.389 36 262.779 M3
-95.389 36 262.779 M4
-95.389 36 262.779 M5
-95.389 36 262.779 M6
-95.389 36 262.779 M7
-95.389 36 262.779 M8
-95.389 36 262.779 M9
-95.389 36 262.779 M10
-95.389 36 262.779 M11

4.2.1.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_nmG5Fb_mo1_dsmed <- leaveout(fit_nmG5Fb_mo1_dsmed)

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


woq1 <- data.frame(Year = as.integer(row.names(summary(LO_nmG5Fb_mo1_dsmed$`w.o. Q1IBTS+BITS+CodSD21-25`))),
    SSB = q1mat$SSB, Fbar = q1mat$`Fbar(3-5)`, R_age1 = q1mat$`R(age 1)`, CatchEst = catchtable(LO_nmG5Fb_mo1_dsmed$`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_mo1_dsmed$`w.o. Q34IBTS+BITS+CodSD21-25`)[,
        1], series = rep("wo_Q34", times = (nrow(q3mat) - 1)))


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

losum_nmG5Fb_mo1_dsmed <- rbind(woq1, woq34, asumi_nmG5Fb_mo1_dsmed)
# ssbplot(LO)
lossb_nmG5Fb_mo1_dsmed <- ggplotly(ggplot() + geom_line(data = losum_nmG5Fb_mo1_dsmed,
    mapping = aes(x = Year, y = SSB, colour = series)) + geom_ribbon(data = asum_nmG5Fb_mo1_dsmed,
    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_mo1_dsmed <- ggplotly(ggplot() + geom_line(data = losum_nmG5Fb_mo1_dsmed,
    mapping = aes(x = Year, y = Fbar, colour = series)) + geom_ribbon(data = asum_nmG5Fb_mo1_dsmed,
    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_mo1_dsmed <- ggplotly(ggplot() + geom_line(data = losum_nmG5Fb_mo1_dsmed,
    mapping = aes(x = Year, y = R_age1, colour = series)) + geom_ribbon(data = asum_nmG5Fb_mo1_dsmed,
    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_mo1_dsmed <- ggplotly(ggplot() + geom_line(data = losum_nmG5Fb_mo1_dsmed,
    mapping = aes(x = Year, y = CatchEst, colour = series)) + geom_ribbon(data = asum_nmG5Fb_mo1_dsmed[asum_nmG5Fb_mo1_dsmed$Year !=
    (DataYear + 1), ], mapping = aes(x = Year, ymin = Catchlow, ymax = Catchhigh),
    fill = "black", alpha = 0.3) + geom_point(data = asum_nmG5Fb_mo1_dsmed[asum_nmG5Fb_mo1_dsmed$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_mo1_dsmed, lof_nmG5Fb_mo1_dsmed, lorec_nmG5Fb_mo1_dsmed,
    loca_nmG5Fb_mo1_dsmed, nrows = 2, shareX = TRUE, titleY = TRUE), showlegend = FALSE)

Figure 4.15: Leave-one-out re-fits for the model with medium discard survival (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.1.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_nmG5Fb_mo1_dsmed <- as.data.frame(summary(fit_nmG5Fb_mo1_dsmed))
asum_nmG5Fb_mo1_dsmed$Year <- as.integer(row.names(summary(fit_nmG5Fb_mo1_dsmed)))
ct_nmG5Fb_mo1_dsmed <- as.data.frame(catchtable(fit_nmG5Fb_mo1_dsmed, obs.show = TRUE))
ct_nmG5Fb_mo1_dsmed$Year <- as.integer(rownames(ct_nmG5Fb_mo1_dsmed))
rownames(ct_nmG5Fb_mo1_dsmed) <- NULL
ct_nmG5Fb_mo1_dsmed <- rbind(ct_nmG5Fb_mo1_dsmed, data.frame(Estimate = NA, Low = NA,
    High = NA, sop.catch = NA, Year = as.integer(2024)))
asum_nmG5Fb_mo1_dsmed <- merge(x = asum_nmG5Fb_mo1_dsmed, y = ct_nmG5Fb_mo1_dsmed,
    by = "Year")
colnames(asum_nmG5Fb_mo1_dsmed) <- c("Year", "R_age1", "Rlow", "Rhigh", "SSB", "SSBlow",
    "SSBhigh", "Fbar", "Flow", "Fhigh", "CatchEst", "Catchlow", "Catchhigh", "CatchObs")

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

# =====
RETRO_nmG5Fb_mo1_dsmed <- retro(fit_nmG5Fb_mo1_dsmed, year = 5)
rho_nmG5Fb_mo1_dsmed <- mohn(RETRO_nmG5Fb_mo1_dsmed, lag = 1)

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

for (i in 1:length(RETRO_nmG5Fb_mo1_dsmed)) {
    tsum <- as.data.frame(summary(RETRO_nmG5Fb_mo1_dsmed[[i]]))
    tsum$Year <- as.integer(row.names(summary(RETRO_nmG5Fb_mo1_dsmed[[i]])))
    tsum <- cbind(tsum, catchtable(RETRO_nmG5Fb_mo1_dsmed[[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_mo1_dsmed_df <- rbind(ret_nmG5Fb_mo1_dsmed_df, tsum)
}
ret_nmG5Fb_mo1_dsmed_df$series <- factor(ret_nmG5Fb_mo1_dsmed_df$series, levels = c("full",
    "1", "2", "3", "4", "5"))
# ssbplot(RETRO)
retssb_nmG5Fb_mo1_dsmed <- layout(ggplotly(ggplot() + geom_line(data = ret_nmG5Fb_mo1_dsmed_df,
    mapping = aes(x = Year, y = SSB, colour = series)) + geom_ribbon(data = asum_nmG5Fb_mo1_dsmed[asum_nmG5Fb_mo1_dsmed$Year !=
    max(asum_nmG5Fb_mo1_dsmed$Year), ], mapping = aes(x = Year, ymin = SSBlow, ymax = SSBhigh),
    fill = "black", alpha = 0.2) + annotate(geom = "text", y = max(ret_nmG5Fb_mo1_dsmed_df$SSBhigh) *
    0.85, x = ((max(ret_nmG5Fb_mo1_dsmed_df$Year) - min(ret_nmG5Fb_mo1_dsmed_df$Year)) *
    0.2) + min(ret_nmG5Fb_mo1_dsmed_df$Year), label = paste0("Mohn's Rho = ", round(rho_nmG5Fb_mo1_dsmed[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_mo1_dsmed <- layout(ggplotly(ggplot() + geom_line(data = ret_nmG5Fb_mo1_dsmed_df,
    mapping = aes(x = Year, y = Fbar, colour = series)) + geom_ribbon(data = asum_nmG5Fb_mo1_dsmed[asum_nmG5Fb_mo1_dsmed$Year !=
    max(asum_nmG5Fb_mo1_dsmed$Year), ], mapping = aes(x = Year, ymin = Flow, ymax = Fhigh),
    fill = "black", alpha = 0.3) + annotate(geom = "text", y = max(ret_nmG5Fb_mo1_dsmed_df$Fhigh) *
    0.85, x = ((max(ret_nmG5Fb_mo1_dsmed_df$Year) - min(ret_nmG5Fb_mo1_dsmed_df$Year)) *
    0.8) + min(ret_nmG5Fb_mo1_dsmed_df$Year), label = paste0("Mohn's Rho = ", round(rho_nmG5Fb_mo1_dsmed[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_mo1_dsmed <- layout(ggplotly(ggplot() + geom_line(data = ret_nmG5Fb_mo1_dsmed_df,
    mapping = aes(x = Year, y = R_age1, colour = series)) + geom_ribbon(data = asum_nmG5Fb_mo1_dsmed[asum_nmG5Fb_mo1_dsmed$Year !=
    max(asum_nmG5Fb_mo1_dsmed$Year), ], mapping = aes(x = Year, ymin = Rlow, ymax = Rhigh),
    fill = "black", alpha = 0.3) + annotate(geom = "text", y = max(ret_nmG5Fb_mo1_dsmed_df$Rhigh) *
    0.85, x = ((max(ret_nmG5Fb_mo1_dsmed_df$Year) - min(ret_nmG5Fb_mo1_dsmed_df$Year)) *
    0.2) + min(ret_nmG5Fb_mo1_dsmed_df$Year), label = paste0("Mohn's Rho = ", round(rho_nmG5Fb_mo1_dsmed[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_mo1_dsmed <- ggplotly(ggplot() + geom_line(data = ret_nmG5Fb_mo1_dsmed_df,
    mapping = aes(x = Year, y = CatchEst, colour = series)) + geom_ribbon(data = asum_nmG5Fb_mo1_dsmed[asum_nmG5Fb_mo1_dsmed$Year !=
    max(asum_nmG5Fb_mo1_dsmed$Year), ], mapping = aes(x = Year, ymin = Catchlow,
    ymax = Catchhigh), fill = "black", alpha = 0.3) + geom_point(data = asum_nmG5Fb_mo1_dsmed[asum_nmG5Fb_mo1_dsmed$Year !=
    max(asum_nmG5Fb_mo1_dsmed$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_mo1_dsmed, retf_nmG5Fb_mo1_dsmed, retrec_nmG5Fb_mo1_dsmed,
    retca_nmG5Fb_mo1_dsmed, 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.16: Retrospective analyses for SSB (top-left), F for ages 3-5 (top-right), recruitment (bottom-left), and catch (bottom-right), from the model with medium discard survival.

4.3 High Discard Survival Estimates

This model is called ple.27.21-32_WKBPLAICE_2024_nmG5Fb_mo1_dshig and can be found on stockassessment.org.

fit_nmG5Fb_mo1_dshig <- fitfromweb("ple.27.21-32_WKBPLAICE_2024_nmG5Fb_mo1_dshig")
# === Create dataframe of current year's fit for plotting ====
asum_nmG5Fb_mo1_dshig <- as.data.frame(summary(fit_nmG5Fb_mo1_dshig))
asum_nmG5Fb_mo1_dshig$Year <- as.integer(row.names(summary(fit_nmG5Fb_mo1_dshig)))
ct_nmG5Fb_mo1_dshig <- as.data.frame(catchtable(fit_nmG5Fb_mo1_dshig, obs.show = TRUE))
ct_nmG5Fb_mo1_dshig$Year <- as.integer(rownames(ct_nmG5Fb_mo1_dshig))
rownames(ct_nmG5Fb_mo1_dshig) <- NULL
ct_nmG5Fb_mo1_dshig <- rbind(ct_nmG5Fb_mo1_dshig, data.frame(Estimate = NA, Low = NA,
    High = NA, sop.catch = NA, Year = as.integer(2024)))
asum_nmG5Fb_mo1_dshig <- merge(x = asum_nmG5Fb_mo1_dshig, y = ct_nmG5Fb_mo1_dshig,
    by = "Year")
colnames(asum_nmG5Fb_mo1_dshig) <- 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: 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.

4.3.1.1 Visualise fits to data by age over time across fleets

## Extract data from model object
logObs_nmG5Fb_mo1_dshig <- split(fit_nmG5Fb_mo1_dshig$data$logobs, ceiling(seq_along(fit_nmG5Fb_mo1_dshig$data$logobs)/fit_nmG5Fb_mo1_dshig$data$maxAgePerFleet[1]))
logPred_nmG5Fb_mo1_dshig <- split(fit_nmG5Fb_mo1_dshig$rep$predObs, ceiling(seq_along(fit_nmG5Fb_mo1_dshig$rep$predObs)/fit_nmG5Fb_mo1_dshig$data$maxAgePerFleet[1]))

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

### Populate the data frame for observations
for (i in seq_along(logObs_nmG5Fb_mo1_dshig)) {
  # 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_mo1_dshig[[i]])
  logObs_nmG5Fb_mo1_dshig_df <- rbind(logObs_nmG5Fb_mo1_dshig_df, temp_df)
}

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

### Populate the data frame for predictions
for (i in seq_along(logPred_nmG5Fb_mo1_dshig)) {
  # 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_mo1_dshig[[i]])
  logPred_nmG5Fb_mo1_dshig_df <- rbind(logPred_nmG5Fb_mo1_dshig_df, temp_df)
}

## Plot
logPred_nmG5Fb_mo1_dshig_df$age <- as.character(logPred_nmG5Fb_mo1_dshig_df$age)
logObs_nmG5Fb_mo1_dshig_df$age <- as.character(logObs_nmG5Fb_mo1_dshig_df$age)

ggplotly(ggplot()+
           geom_point(data = logObs_nmG5Fb_mo1_dshig_df[logObs_nmG5Fb_mo1_dshig_df$fleet == 1 & logObs_nmG5Fb_mo1_dshig_df$year != (DataYear+1), ],
                      mapping = aes(x = year,
                                    y = logObs,
                                    colour = age),
                      shape = 21) +
           geom_line(data = logPred_nmG5Fb_mo1_dshig_df[logPred_nmG5Fb_mo1_dshig_df$fleet == 1 & logPred_nmG5Fb_mo1_dshig_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.17: Model with high discard survival estimates, fit to catch data by age (values on the model link function scale).

# fitplot(fit_nmG5Fb_mo1_dshig, fleets=1)
ggplotly(ggplot()+
           geom_point(data = logObs_nmG5Fb_mo1_dshig_df[logObs_nmG5Fb_mo1_dshig_df$fleet == 2 & logObs_nmG5Fb_mo1_dshig_df$year != (DataYear+1), ],
                      mapping = aes(x = year,
                                    y = logObs,
                                    colour = age),
                      shape = 21) +
           geom_line(data = logPred_nmG5Fb_mo1_dshig_df[logPred_nmG5Fb_mo1_dshig_df$fleet == 2 & logPred_nmG5Fb_mo1_dshig_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 high discard survival estimates, fit to Q1 survey data by age (values on the model link function scale).

# fitplot(fit_nmG5Fb_mo1_dshig, fleets=2)
ggplotly(ggplot()+
           geom_point(data = logObs_nmG5Fb_mo1_dshig_df[logObs_nmG5Fb_mo1_dshig_df$fleet == 3 & logObs_nmG5Fb_mo1_dshig_df$year != (DataYear+1), ],
                      mapping = aes(x = year,
                                    y = logObs,
                                    colour = age),
                      shape = 21) +
           geom_line(data = logPred_nmG5Fb_mo1_dshig_df[logPred_nmG5Fb_mo1_dshig_df$fleet == 3 & logPred_nmG5Fb_mo1_dshig_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 high discard survival estimates, fit to Q3/4 survey data by age (values on the model link function scale).

# fitplot(fit_nmG5Fb_mo1_dshig, fleets=3)
sdplot(fit_nmG5Fb_mo1_dshig, marg = c(5, 4, 1, 1))
Standard Devations by Fleet; high discard survival estimates.

Figure 4.20: Standard Devations by Fleet; high discard survival estimates.

4.3.1.2 Residuals

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

resid_nmG5Fb_mo1_dshig_df$fleetAltName <- ifelse(resid_nmG5Fb_mo1_dshig_df$fleet ==
    1, "Residual Fishing", ifelse(resid_nmG5Fb_mo1_dshig_df$fleet == 2, "Q1 Surveys",
    ifelse(resid_nmG5Fb_mo1_dshig_df$fleet == 3, "Q3/4 Surveys", NA)))
if (!all(fit_nmG5Fb_mo1_dshig$conf$obsCorStruct == "ID")) {
    corplot(fit_nmG5Fb_mo1_dshig)
    # 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 high discard mortality.

Figure 4.21: Estimated correlations in residual variation between ages for each of the fishing fleet (top) and the two surveys (middle & bottom), from the Model with high discard mortality.

ggplotly(ggplot(resid_nmG5Fb_mo1_dshig_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.22: 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 high discard mortality.

4.3.1.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_nmG5Fb_mo1_dshig <- jit(fit = fit_nmG5Fb_mo1_dshig)

mt <- as.data.frame(modeltable(jit_nmG5Fb_mo1_dshig))
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_mo1_dshig)Measures of fit for a series of model refits with jitter applied to the input parameters.
log(L) #par AIC model
-96.835 36 265.67 M1
-96.835 36 265.67 M2
-96.835 36 265.67 M3
-96.835 36 265.67 M4
-96.835 36 265.67 M5
-96.835 36 265.67 M6
-96.835 36 265.67 M7
-96.835 36 265.67 M8
-96.835 36 265.67 M9
-96.835 36 265.67 M10
-96.835 36 265.67 M11

4.3.1.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_nmG5Fb_mo1_dshig <- leaveout(fit_nmG5Fb_mo1_dshig)

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


woq1 <- data.frame(Year = as.integer(row.names(summary(LO_nmG5Fb_mo1_dshig$`w.o. Q1IBTS+BITS+CodSD21-25`))),
    SSB = q1mat$SSB, Fbar = q1mat$`Fbar(3-5)`, R_age1 = q1mat$`R(age 1)`, CatchEst = catchtable(LO_nmG5Fb_mo1_dshig$`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_mo1_dshig$`w.o. Q34IBTS+BITS+CodSD21-25`)[,
        1], series = rep("wo_Q34", times = (nrow(q3mat) - 1)))


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

losum_nmG5Fb_mo1_dshig <- rbind(woq1, woq34, asumi_nmG5Fb_mo1_dshig)
# ssbplot(LO)
lossb_nmG5Fb_mo1_dshig <- ggplotly(ggplot() + geom_line(data = losum_nmG5Fb_mo1_dshig,
    mapping = aes(x = Year, y = SSB, colour = series)) + geom_ribbon(data = asum_nmG5Fb_mo1_dshig,
    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_mo1_dshig <- ggplotly(ggplot() + geom_line(data = losum_nmG5Fb_mo1_dshig,
    mapping = aes(x = Year, y = Fbar, colour = series)) + geom_ribbon(data = asum_nmG5Fb_mo1_dshig,
    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_mo1_dshig <- ggplotly(ggplot() + geom_line(data = losum_nmG5Fb_mo1_dshig,
    mapping = aes(x = Year, y = R_age1, colour = series)) + geom_ribbon(data = asum_nmG5Fb_mo1_dshig,
    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_mo1_dshig <- ggplotly(ggplot() + geom_line(data = losum_nmG5Fb_mo1_dshig,
    mapping = aes(x = Year, y = CatchEst, colour = series)) + geom_ribbon(data = asum_nmG5Fb_mo1_dshig[asum_nmG5Fb_mo1_dshig$Year !=
    (DataYear + 1), ], mapping = aes(x = Year, ymin = Catchlow, ymax = Catchhigh),
    fill = "black", alpha = 0.3) + geom_point(data = asum_nmG5Fb_mo1_dshig[asum_nmG5Fb_mo1_dshig$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_mo1_dshig, lof_nmG5Fb_mo1_dshig, lorec_nmG5Fb_mo1_dshig,
    loca_nmG5Fb_mo1_dshig, nrows = 2, shareX = TRUE, titleY = TRUE), showlegend = FALSE)

Figure 4.23: Leave-one-out re-fits for the model with high discard survival (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.1.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_nmG5Fb_mo1_dshig <- as.data.frame(summary(fit_nmG5Fb_mo1_dshig))
asum_nmG5Fb_mo1_dshig$Year <- as.integer(row.names(summary(fit_nmG5Fb_mo1_dshig)))
ct_nmG5Fb_mo1_dshig <- as.data.frame(catchtable(fit_nmG5Fb_mo1_dshig, obs.show = TRUE))
ct_nmG5Fb_mo1_dshig$Year <- as.integer(rownames(ct_nmG5Fb_mo1_dshig))
rownames(ct_nmG5Fb_mo1_dshig) <- NULL
ct_nmG5Fb_mo1_dshig <- rbind(ct_nmG5Fb_mo1_dshig, data.frame(Estimate = NA, Low = NA,
    High = NA, sop.catch = NA, Year = as.integer(2024)))
asum_nmG5Fb_mo1_dshig <- merge(x = asum_nmG5Fb_mo1_dshig, y = ct_nmG5Fb_mo1_dshig,
    by = "Year")
colnames(asum_nmG5Fb_mo1_dshig) <- c("Year", "R_age1", "Rlow", "Rhigh", "SSB", "SSBlow",
    "SSBhigh", "Fbar", "Flow", "Fhigh", "CatchEst", "Catchlow", "Catchhigh", "CatchObs")

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

# =====
RETRO_nmG5Fb_mo1_dshig <- retro(fit_nmG5Fb_mo1_dshig, year = 5)
rho_nmG5Fb_mo1_dshig <- mohn(RETRO_nmG5Fb_mo1_dshig, lag = 1)

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

for (i in 1:length(RETRO_nmG5Fb_mo1_dshig)) {
    tsum <- as.data.frame(summary(RETRO_nmG5Fb_mo1_dshig[[i]]))
    tsum$Year <- as.integer(row.names(summary(RETRO_nmG5Fb_mo1_dshig[[i]])))
    tsum <- cbind(tsum, catchtable(RETRO_nmG5Fb_mo1_dshig[[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_mo1_dshig_df <- rbind(ret_nmG5Fb_mo1_dshig_df, tsum)
}
ret_nmG5Fb_mo1_dshig_df$series <- factor(ret_nmG5Fb_mo1_dshig_df$series, levels = c("full",
    "1", "2", "3", "4", "5"))
# ssbplot(RETRO)
retssb_nmG5Fb_mo1_dshig <- layout(ggplotly(ggplot() + geom_line(data = ret_nmG5Fb_mo1_dshig_df,
    mapping = aes(x = Year, y = SSB, colour = series)) + geom_ribbon(data = asum_nmG5Fb_mo1_dshig[asum_nmG5Fb_mo1_dshig$Year !=
    max(asum_nmG5Fb_mo1_dshig$Year), ], mapping = aes(x = Year, ymin = SSBlow, ymax = SSBhigh),
    fill = "black", alpha = 0.2) + annotate(geom = "text", y = max(ret_nmG5Fb_mo1_dshig_df$SSBhigh) *
    0.85, x = ((max(ret_nmG5Fb_mo1_dshig_df$Year) - min(ret_nmG5Fb_mo1_dshig_df$Year)) *
    0.2) + min(ret_nmG5Fb_mo1_dshig_df$Year), label = paste0("Mohn's Rho = ", round(rho_nmG5Fb_mo1_dshig[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_mo1_dshig <- layout(ggplotly(ggplot() + geom_line(data = ret_nmG5Fb_mo1_dshig_df,
    mapping = aes(x = Year, y = Fbar, colour = series)) + geom_ribbon(data = asum_nmG5Fb_mo1_dshig[asum_nmG5Fb_mo1_dshig$Year !=
    max(asum_nmG5Fb_mo1_dshig$Year), ], mapping = aes(x = Year, ymin = Flow, ymax = Fhigh),
    fill = "black", alpha = 0.3) + annotate(geom = "text", y = max(ret_nmG5Fb_mo1_dshig_df$Fhigh) *
    0.85, x = ((max(ret_nmG5Fb_mo1_dshig_df$Year) - min(ret_nmG5Fb_mo1_dshig_df$Year)) *
    0.8) + min(ret_nmG5Fb_mo1_dshig_df$Year), label = paste0("Mohn's Rho = ", round(rho_nmG5Fb_mo1_dshig[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_mo1_dshig <- layout(ggplotly(ggplot() + geom_line(data = ret_nmG5Fb_mo1_dshig_df,
    mapping = aes(x = Year, y = R_age1, colour = series)) + geom_ribbon(data = asum_nmG5Fb_mo1_dshig[asum_nmG5Fb_mo1_dshig$Year !=
    max(asum_nmG5Fb_mo1_dshig$Year), ], mapping = aes(x = Year, ymin = Rlow, ymax = Rhigh),
    fill = "black", alpha = 0.3) + annotate(geom = "text", y = max(ret_nmG5Fb_mo1_dshig_df$Rhigh) *
    0.85, x = ((max(ret_nmG5Fb_mo1_dshig_df$Year) - min(ret_nmG5Fb_mo1_dshig_df$Year)) *
    0.2) + min(ret_nmG5Fb_mo1_dshig_df$Year), label = paste0("Mohn's Rho = ", round(rho_nmG5Fb_mo1_dshig[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_mo1_dshig <- ggplotly(ggplot() + geom_line(data = ret_nmG5Fb_mo1_dshig_df,
    mapping = aes(x = Year, y = CatchEst, colour = series)) + geom_ribbon(data = asum_nmG5Fb_mo1_dshig[asum_nmG5Fb_mo1_dshig$Year !=
    max(asum_nmG5Fb_mo1_dshig$Year), ], mapping = aes(x = Year, ymin = Catchlow,
    ymax = Catchhigh), fill = "black", alpha = 0.3) + geom_point(data = asum_nmG5Fb_mo1_dshig[asum_nmG5Fb_mo1_dshig$Year !=
    max(asum_nmG5Fb_mo1_dshig$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_mo1_dshig, retf_nmG5Fb_mo1_dshig, retrec_nmG5Fb_mo1_dshig,
    retca_nmG5Fb_mo1_dshig, 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.24: Retrospective analyses for SSB (top-left), F for ages 3-5 (top-right), recruitment (bottom-left), and catch (bottom-right), from the model with high discard survival.

5 Comparison of Discard Survival Scenarios

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.

5.1 Basic fit and diagnostic variables

nmAIC <- data.frame(`Type of M` = c("Base Model", "Age1 Maturity to Zero", "Low Discard Survival",
    "Medium Discard Survival", "High Discard Survival"), AIC = c(AIC(fit_nmG5Fb),
    AIC(fit_nmG5Fb_mo1), AIC(fit_nmG5Fb_mo1_dslow), AIC(fit_nmG5Fb_mo1_dsmed), AIC(fit_nmG5Fb_mo1_dshig)),
    No.Params = c(length(coef(fit_nmG5Fb)), length(coef(fit_nmG5Fb_mo1)), length(coef(fit_nmG5Fb_mo1_dslow)),
        length(coef(fit_nmG5Fb_mo1_dsmed)), length(coef(fit_nmG5Fb_mo1_dshig))),
    Rho.SSB = c(rho_nmG5Fb[2], rho_nmG5Fb_mo1[2], rho_nmG5Fb_mo1_dslow[2], rho_nmG5Fb_mo1_dsmed[2],
        rho_nmG5Fb_mo1_dshig[2]), Rho.F = c(rho_nmG5Fb[3], rho_nmG5Fb_mo1[3], rho_nmG5Fb_mo1_dslow[3],
        rho_nmG5Fb_mo1_dsmed[3], rho_nmG5Fb_mo1_dshig[3]), Rho.Rec = c(rho_nmG5Fb[1],
        rho_nmG5Fb_mo1[1], rho_nmG5Fb_mo1_dslow[1], rho_nmG5Fb_mo1_dsmed[1], rho_nmG5Fb_mo1_dshig[1]))

kable(nmAIC, caption = "Measures of model fit under various hypotheses of natural mortality.")
Table 5.1: Measures of model fit under various hypotheses of natural mortality.
Type.of.M AIC No.Params Rho.SSB Rho.F Rho.Rec
Base Model 262.3204 36 0.0600907 -0.0158922 0.1149631
Age1 Maturity to Zero 262.3204 36 0.0185523 -0.0158922 0.1149631
Low Discard Survival 260.9943 36 0.0084699 -0.0130867 0.0944167
Medium Discard Survival 262.7788 36 0.0068493 -0.0108810 0.0906564
High Discard Survival 265.6705 36 0.0051730 -0.0074690 0.0866411

5.2 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.

We can see from the graphs that attempts to account for discard survival by reducing the catches proportionally, have the result of scaling the estimates of SSB. In this case, in the latest data year (), we see a -15% change from the model not accounting for discard survival to the scenario with the lowest levels of survival. When we compare to the model with the highest levels of survival, we see an even greater change of -21%

# 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_nmG5Fb, mapping = aes(x = Year, y = SSB,
    series = "Baseline"), colour = ebpal[1]) + geom_ribbon(data = asum_nmG5Fb, mapping = aes(x = Year,
    ymin = SSBlow, ymax = SSBhigh), fill = ebpal[1], alpha = 0.3) + geom_line(data = asum_nmG5Fb_mo1,
    mapping = aes(x = Year, y = SSB, series = "Maturity at age1 set to zero"), colour = ebpal[2]) +
    geom_ribbon(data = asum_nmG5Fb_mo1, mapping = aes(x = Year, ymin = SSBlow, ymax = SSBhigh),
        fill = ebpal[2], alpha = 0.3) + geom_line(data = asum_nmG5Fb_mo1_dslow, mapping = aes(x = Year,
    y = SSB, series = "Low Discard Survival"), colour = ebpal[3]) + geom_ribbon(data = asum_nmG5Fb_mo1_dslow,
    mapping = aes(x = Year, ymin = SSBlow, ymax = SSBhigh), fill = ebpal[3], alpha = 0.3) +
    geom_line(data = asum_nmG5Fb_mo1_dsmed, mapping = aes(x = Year, y = SSB, series = "Medium Discard Survival"),
        colour = ebpal[4]) + geom_ribbon(data = asum_nmG5Fb_mo1_dsmed, mapping = aes(x = Year,
    ymin = SSBlow, ymax = SSBhigh), fill = ebpal[4], alpha = 0.3) + geom_line(data = asum_nmG5Fb_mo1_dshig,
    mapping = aes(x = Year, y = SSB, series = "High Discard Survival"), colour = ebpal[13]) +
    geom_ribbon(data = asum_nmG5Fb_mo1_dshig, mapping = aes(x = Year, ymin = SSBlow,
        ymax = SSBhigh), fill = ebpal[13], alpha = 0.3) + theme_clean()

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

Figure 5.1: Estimated spawning stock biomass for ple.27.21-32 and 95% confidence intervals (tonnes). Purple is the current working document’s baseline model, green is with maturity at age1 set to zero, orange is with Low discard Survival, blue is with medium discard survival, and red is with highdiscard survival.

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_nmG5Fb, mapping = aes(x = Year, y = Fbar,
    series = "Baseline"), colour = ebpal[1]) + geom_ribbon(data = asum_nmG5Fb, mapping = aes(x = Year,
    ymin = Flow, ymax = Fhigh, series = "Baseline"), fill = ebpal[1], alpha = 0.3) +
    geom_line(data = asum_nmG5Fb_mo1, mapping = aes(x = Year, y = Fbar, series = "Maturity at age1 set to zero"),
        colour = ebpal[2]) + geom_ribbon(data = asum_nmG5Fb_mo1, mapping = aes(x = Year,
    ymin = Flow, ymax = Fhigh, series = "Maturity at age1 set to zero"), fill = ebpal[2],
    alpha = 0.3) + geom_line(data = asum_nmG5Fb_mo1_dslow, mapping = aes(x = Year,
    y = Fbar, series = "Low Discard Survival"), colour = ebpal[3]) + geom_ribbon(data = asum_nmG5Fb_mo1_dslow,
    mapping = aes(x = Year, ymin = Flow, ymax = Fhigh, series = "Low Discard Survival"),
    fill = ebpal[3], alpha = 0.3) + geom_line(data = asum_nmG5Fb_mo1_dsmed, mapping = aes(x = Year,
    y = Fbar, series = "Medium Discard Survival"), colour = ebpal[4]) + geom_ribbon(data = asum_nmG5Fb_mo1_dsmed,
    mapping = aes(x = Year, ymin = Flow, ymax = Fhigh, series = "Medium Discard Survival"),
    fill = ebpal[4], alpha = 0.3) + geom_line(data = asum_nmG5Fb_mo1_dshig, mapping = aes(x = Year,
    y = Fbar, series = "High Discard Survival"), colour = ebpal[13]) + geom_ribbon(data = asum_nmG5Fb_mo1_dshig,
    mapping = aes(x = Year, ymin = Flow, ymax = Fhigh, series = "High Discard Survival"),
    fill = ebpal[13], alpha = 0.3) + theme_clean())

Figure 5.2: 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 current working document’s baseline model, green is with maturity at age1 set to zero, orange is with Low discard Survival, blue is with medium discard survival, and red is with highdiscard survival.

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_nmG5Fb, mapping = aes(x = Year, y = R_age1,
    series = "Baseline"), colour = ebpal[1]) + geom_ribbon(data = asum_nmG5Fb, mapping = aes(x = Year,
    ymin = Rlow, ymax = Rhigh, series = "Baseline"), fill = ebpal[1], alpha = 0.3) +
    geom_line(data = asum_nmG5Fb_mo1, mapping = aes(x = Year, y = R_age1, series = "Maturity at age1 set to zero"),
        colour = ebpal[2]) + geom_ribbon(data = asum_nmG5Fb_mo1, mapping = aes(x = Year,
    ymin = Rlow, ymax = Rhigh, series = "Maturity at age1 set to zero"), fill = ebpal[2],
    alpha = 0.3) + geom_line(data = asum_nmG5Fb_mo1_dslow, mapping = aes(x = Year,
    y = R_age1, series = "Low Discard Survival"), colour = ebpal[3]) + geom_ribbon(data = asum_nmG5Fb_mo1_dslow,
    mapping = aes(x = Year, ymin = Rlow, ymax = Rhigh, series = "Low Discard Survival"),
    fill = ebpal[3], alpha = 0.3) + geom_line(data = asum_nmG5Fb_mo1_dsmed, mapping = aes(x = Year,
    y = R_age1, series = "Medium Discard Survival"), colour = ebpal[4]) + geom_ribbon(data = asum_nmG5Fb_mo1_dsmed,
    mapping = aes(x = Year, ymin = Rlow, ymax = Rhigh, series = "Medium Discard Survival"),
    fill = ebpal[4], alpha = 0.3) + geom_line(data = asum_nmG5Fb_mo1_dshig, mapping = aes(x = Year,
    y = R_age1, series = "High Discard Survival"), colour = ebpal[13]) + geom_ribbon(data = asum_nmG5Fb_mo1_dshig,
    mapping = aes(x = Year, ymin = Rlow, ymax = Rhigh, series = "High Discard Survival"),
    fill = ebpal[13], alpha = 0.3) + theme_clean())

Figure 5.3: 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 current working document’s baseline model, green is with maturity at age1 set to zero, orange is with Low discard Survival, blue is with medium discard survival, and red is with highdiscard survival.

ggplotly(ggplot() + geom_line(data = asum_nmG5Fb[asum_nmG5Fb$Year != (DataYear +
    1), ], mapping = aes(x = Year, y = CatchEst, series = "Baseline"), colour = ebpal[1]) +
    geom_ribbon(data = asum_nmG5Fb[asum_nmG5Fb$Year != (DataYear + 1), ], mapping = aes(x = Year,
        ymin = Catchlow, ymax = Catchhigh, series = "Baseline"), fill = ebpal[1],
        alpha = 0.3) + geom_line(data = asum_nmG5Fb_mo1[asum_nmG5Fb_mo1$Year != (DataYear +
    1), ], mapping = aes(x = Year, y = CatchEst, series = "Maturity at age1 set to zero"),
    colour = ebpal[2]) + geom_ribbon(data = asum_nmG5Fb_mo1[asum_nmG5Fb_mo1$Year !=
    (DataYear + 1), ], mapping = aes(x = Year, ymin = Catchlow, ymax = Catchhigh,
    series = "Maturity at age1 set to zero"), fill = ebpal[2], alpha = 0.3) + geom_line(data = asum_nmG5Fb_mo1_dslow[asum_nmG5Fb_mo1_dslow$Year !=
    (DataYear + 1), ], mapping = aes(x = Year, y = CatchEst, series = "Low Discard Survival"),
    colour = ebpal[3]) + geom_ribbon(data = asum_nmG5Fb_mo1_dslow[asum_nmG5Fb_mo1_dslow$Year !=
    (DataYear + 1), ], mapping = aes(x = Year, ymin = Catchlow, ymax = Catchhigh,
    series = "Low Discard Survival"), fill = ebpal[3], alpha = 0.3) + geom_line(data = asum_nmG5Fb_mo1_dsmed[asum_nmG5Fb_mo1_dsmed$Year !=
    (DataYear + 1), ], mapping = aes(x = Year, y = CatchEst, series = "Medium Discard Survival"),
    colour = ebpal[4]) + geom_ribbon(data = asum_nmG5Fb_mo1_dsmed[asum_nmG5Fb_mo1_dsmed$Year !=
    (DataYear + 1), ], mapping = aes(x = Year, ymin = Catchlow, ymax = Catchhigh,
    series = "Medium Discard Survival"), fill = ebpal[4], alpha = 0.3) + geom_line(data = asum_nmG5Fb_mo1_dshig[asum_nmG5Fb_mo1_dshig$Year !=
    (DataYear + 1), ], mapping = aes(x = Year, y = CatchEst, series = "High Discard Survival"),
    colour = ebpal[13]) + geom_ribbon(data = asum_nmG5Fb_mo1_dshig[asum_nmG5Fb_mo1_dshig$Year !=
    (DataYear + 1), ], mapping = aes(x = Year, ymin = Catchlow, ymax = Catchhigh,
    series = "High Discard Survival"), fill = ebpal[13], alpha = 0.3) + ylab("Catch (tonnes)") +
    theme_clean())

Figure 5.4: 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 current working document’s baseline model, green is with maturity at age1 set to zero, orange is with Low discard Survival, blue is with medium discard survival, and red is with highdiscard survival.

6 Conclusions

6.1 Imposing assumptions about age 1 maturity

The setting of age 1 proportion mature to zero, overwrites proportions determined from surveys with an assumption based on expert knowledge. This would not, ordinarily, be best practice. However, due to the difficulty in getting reliable age reading rings from the first year of life, one can assume that some of the fish reported as mature in age 1, are from the age 2 cohort. Furthermore, juvenile and pre-adult plaice are known to distribute themselves across depth gradients according to their size. In this area, plaice are known to spawn and settle as juveniles over extended periods crossing seasons, which introduces length, growth and survival differentials into the various within-year, “settlement cohorts”. This means that the surveys that operate in deeper waters are more likely to catch individuals from the larger end of the size spectrum for any given age cohort, further biasing the proportion of mature fish at any given age. All experts in the workshop agreed that having significant proportions of age 1 plaice mature was unrealistic and that accepting these numbers (which are likely a result of sampling bias and observation error) was probably over-inflating our estimation of SSB.

Once set to zero, the model fit utilising these data does not change (AICs = 262.32, 262.32, respectively), only the SSB estimates scale up and down. The SSB estimates fall by -23% when setting age1 maturity to zero, and will likely reduce the inter-annual variability of the SSB estimates because of the larger variances around the estimations of numbers at age1.

6.2 Accounting for discard survival

In this section of the document we utilised the upper, lower, and middle values of estimates of discard survival from the literature, where studies existed. For catch segments where there was no data, we borrowed or extrapolated known values and trends (respectively) to ensure all segments had some estimate of survival. This provided us with three scenarios upon which we could run a type of sensitivity analysis, to visualise the impact that accounting for discard survival might have on both the model fit and the perception of the stock.

Here we see that utilising the any of the new catch scenarios has not substantial impact on the model fit, with all AIC values being within a range of five from one another, and all retro-plots / Mohn’s rho statistics being acceptable.

However, there are substantial impacts on our perception of the stock size, where the low end of the published survival estimates results in substantial change in the SSB (-15%), and recruitment (-16%).

When we compare the effects of selecting discard survival rates from across the ranges of those reported in the literature, we can see that the variation in our model estimates of SSB are not as great, relative to not accounting for any survival. This can be seen in the percentage difference between the low and the high estimates of discard, relative to the estimate made for the model with no survival for SSB (5% between low and high survival, vs -15% betwen low survival to no survival).

However, this difference is much reduced when comparing fishing pressure (6% between low and high survival, vs -8% between low survival to no survival).

6.3 Overall Conclusions

Based on the fact that there are likely biases and some errors in the collection of data for age 1 fish, and the fact that changing the maturity at age1 has no effect on the model fit, but down-scales the SSB estimates and likely reduces interannual variation in the estimates, then we recommend retaining this expert opinion based “over-write”.

As was stated at the beginning of the benchmark process, the information that exists for rates of survival in discarded plaice is weak, sparse and has proven to be massively dependent on factors that cannot be accounted for in an assessment process (i.e. time exposed to air, being the largest driver of survival).

In order to address a specific request from the European Commission to investigate incorporating discard survival into the assessment, we have borrowed information across various fleet strata and applied these ad-hoc across our catch dataset. The resultant model fits show that there is no substantial difference in the quality of the model fits (based on AIC) but that our perception of the stock is somewhat scaled, and scaled differently according to the indicator use (e.g. see SSB vs F discussion above).

Subsequent to this exercise, we realise that our status quo assumption is 0% survival, which does not seem to reflect reality, and that while studies on this topic are sparse, information does exist that we should not ignore. Our attempts to utilise this knowledge involve rudimentary ratio-based borrowing of information to cover the catch segments as best as possible, but whether this approach is robust enough to utilise in the production of advice remains up for debate with peers and reviewers.

Therefore, there remains a decision to be made, to select between the assessment without accounting for discard survival (but with age 1 maturity set to zero), or the medium discard survival scenario?

LS0tDQp0aXRsZTogIlBsZS4yNy4zYS4yMS0zMl9XS0JQTEFJQ0VfRGlzY2FyZFN1cnZpdmFsIg0KYXV0aG9yOg0KICAtIG5hbWU6ICJFbGxpb3QgSi4gQnJvd24iDQogIC0gbmFtZTogIkNhc3BlciBXLiBCZXJnIg0KICAtIG5hbWU6ICJTdmVuIFN0w7Z0ZXJhIg0KZGF0ZTogImByIFN5cy5EYXRlKClgIg0Kb3V0cHV0OiANCiAgYm9va2Rvd246Omh0bWxfZG9jdW1lbnQyOg0KICAgIHRvYzogdHJ1ZQ0KICAgIHRvY19mbG9hdDogdHJ1ZQ0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCi0tLQ0KDQo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPg0KLm1haW4tY29udGFpbmVyIHsNCm1heC13aWR0aDogOTAlICFpbXBvcnRhbnQ7DQptYXJnaW46IGF1dG87DQp9DQpwLmNhcHRpb24gew0KZm9udC1zaXplOiAwLjhlbTsNCmZvbnQtc3R5bGU6IGl0YWxpYzsNCn0NCjwvc3R5bGU+DQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG89VFJVRSwNCiAgICAgICAgICAgICAgICAgICAgICBldmFsID0gVFJVRSwNCiAgICAgICAgICAgICAgICAgICAgICB3YXJuaW5nID0gRkFMU0UsDQogICAgICAgICAgICAgICAgICAgICAgZmlnLmFsaWduID0gImNlbnRlciIsDQogICAgICAgICAgICAgICAgICAgICAgdGlkeSA9ICdmb3JtYXRSJywNCiAgICAgICAgICAgICAgICAgICAgICBvdXQud2lkdGggPSAiOTAlIikNCg0KIz09PQ0KIyBNYW51YWwgc2V0dGluZ3MgZm9yIGZpZ3VyZSBmb3JtYXR0aW5nDQojPT09PQ0KIyBlYnBhbCA8LSBjKCIjMkYzRUVBIiwgIiMxRkQwODIiLCAiIzAzMEY0RiIsICIjRjZEMDREIiwgIiNGQzc2MzQiLCAiI0Y3QkJCMSIsICIjRTgzRjQ4IiwgIiMwMDg4MzUiLCAiIzc5MjM4RSIpDQplYnBhbCA8LSBjKCIjODAwMDgwIiwgIiMwMDY0MDAiLCAiI0Q1NUUwMCIsICIjMDA3MkIyIiwgIiNGMEU0NDIiLCAiIzAwOUU3MyIsICIjRTY5RjAwIiwgIiM1NkI0RTkiLCAiI0NDNzlBNyIsICIjNURBNURBIiwgIiNGRjgwMDAiLCAiIzg5Q0ZGMCIsICIjQTUyQTJBIiwgIiM3N0RENzciLCAiI0ZGRkFDRCIpDQojPT09PT0NCmBgYA0KDQojIEludHJvZHVjdGlvbg0KIyMgQWJvdXQgdGhpcyBkb2N1bWVudA0KVGhpcyB3b3JraW5nIGRvY3VtZW50IGlzIHRoZSB0aGlyZCBzdGVwIGluIGV2YWx1YXRpbmcgdmFyaW91cyBhc3Nlc3NtZW50IG1vZGVscyBmb3IgdGhlIG5ld2x5IGNvbWJpbmVkIFBsYWljZSBzdG9jaywgYWNyb3NzIHRoZSBTdWIgRGl2aXNpb25zIDIxIC0gMzIuICBJbiB0aGUgZmlyc3QgYXNzZXNzbWVudCB3b3JraW5nIGRvY3VtZW50ICggX1BsZS4yNy4zYS4yMS0zMl9Bc3Nlc3NtZW50c18gKSwgU29tZSBvZiB0aGUgbW9yZSBmdW5kYW1lbnRhbCBkZWNpc2lvbnMgYWJvdXQgaW5wdXQgZGF0YSB3ZXJlIGV2YWx1YXRlZCBhbmQgZGVjaWRlZCB1cG9uLiBJbiB0aGUgc2Vjb25kIGFzc2Vzc21lbnQgd29ya2luZyBkb2N1bWVudCAoIF9QbGUuMjcuM2EuMjEtMzJfV0tCUExBSUNFX05ld01vcnRhbGl0eS5STURfICksIHdlIGZvY3VzZWQgaW4gb24gYW4gaXNzdWUgdGhhdCBpcyBuZXcgdG8gdGhlIHN0b2NrcyBpbiB0aGlzIGFyZWEsIG5hbWVseSB0aW1lLXZhcnlpbmcgbmF0dXJhbCBtb3J0YWxpdHkuICBGcm9tIHRoaXMgd29yayB3ZSBzZWxlY3RlZCBhIG1vZGVsIHRoYXQgdXNlcyBHaXNsYXNvbiBldCBhbCAoMjAxMCkgbmF0dXJhbCBtb3J0YWxpdGllcyBjYWxjdWxhdGVkIGZyb20gbGlmZS1oaXN0b3J5IHRyYWl0cyB0aGF0IHdlcmUgZm91bmQgZnJvbSBsaXRlcmF0dXJlICh2aWEgW2Zpc2hiYXNlLnNlXShodHRwczovL2Zpc2hiYXNlLnNlKSksIGFuZCB0aGUgdmFyeWluZyBsZW5ndGggYXQgYWdlIGluIHRoZSBzdG9jay4gTm93LCBpbiB0aGlzIGRvY3VtZW50LCB3ZSBpbnZlc3RpZ2F0ZSB0aHJlZSBkaWZmZXJlbnQgdmFyaWF0aW9ucyBvZiBpbnB1dCBkYXRhIHRvIHRoZSBzZWxlY3RlZCBtb2RlbDoNCg0KMS4gVGhlIHNldHRpbmcgb2YgbWF0dXJpdHkgYXQgYWdlIDEgdG8gemVyby4NCjIuIEF0dGVtcHRzIHRvIGFjY291bnQgZm9yIHN1cnZpdmFsIG9mIGRpc2NhcmRzIGZyb20gdGhlIGNvbW1lcmNpYWwgZmlzaGVyeS4NCmEuIFNjZW5hcmlvIG9mIHJlbGF0aXZlbHkgbG93IGxldmVscyBvZiBkaXNjYXJkIHN1cnZpdmFsLg0KYi4gU2NlbmFyaW8gb2YgbWlkLWxldmVscyBvZiBkaXNjYXJkcyBzdXJ2aXZhbC4NCmMuIFNjZW5hcmlvIG9mIHJlbGF0aXZlbHkgaGlnaCBsZXZlbHMgb2YgZGlzY2FyZCBzdXJ2aXZhbC4NCjMuIEFuIGF0dGVtcHQgdG8gaW50ZWdyYXRlIEdlcm1hbiByZWNyZWF0aW9uYWwgaGFydmVzdHMgaW50byB0aGUgYXNzZXNzbWVudCBtb2RlbC4NCg0KSW4gc2NlbmFyaW8gMSwgd2UgaW52ZXN0aWdhdGUgdGhlIGVmZmVjdCBvZiBzZXR0aW5nIG1hdHVyaXR5IGF0IGFnZSAxIHRvIHplcm8uICBJbiB0aGUgbWF0dXJpdHkgb2dpdmVzIGNhbGN1bGF0ZWQgZnJvbSB0aGUgc3VydmV5cywgd2Ugc2VlIHRoYXQgfjI1JSBvZiBhZ2UxIGZpc2ggYXJlIGZvdW5kIHRvIGJlIG1hdHVyZS4gIFRoaXMgY29uZmxpY3RzIHdpdGggZnVuZGFtZW50YWwga25vd2xlZGdlIG9mIEV1cm9wZWFuIHBsYWljZSBiaW9sb2d5LCBldmVuIGluIHRoZSBzcGVjaWZpYyBjb250ZXh0IG9mIHRoaXMgc3RvY2suICBGdXJodGVybW9yZSwgdGhlcmUgYXJlIHNvbWUgaXNzdWVzIGFyb3VuZCBhZ2luZyBmaXNoIHdpdGggc29tZSBzeXN0ZW1hdGljIGVycm9ycyByZXBvcnRlZCBmb3IgY291bnRpbmcgdGhlIGZpcnN0IHllYXIncyByaW5nLiAgSGVuY2Ugc29tZSBpbmRpdmlkdWFscyB0aGF0IGFyZSBzYW1wbGVkIGFzIGJlaW5nIG1hdHVyZSwgbWF5IGJlIGluY29ycmVjdGx5IGFnZWQgYXMgYWdlIDEsIHdoZW4gdGhleSBhcmUgaW4gZmFjdCBhZ2UgMi4gIEJlY2F1c2Ugb2YgdGhlIGxhcmdlIGluZmx1eGVzIG9mIHJlY3J1aXRtZW50LCBoYXZpbmcgYSBzaWduaWZpY2FudCBwcm9wb3J0aW9uIG9mIHJlY3J1aXRzIGFzIG1hdHVyZSBsZWFkcyB0byBhIHZvbGF0aWxlIGluZmxhdGlvbiBvZiB0aGUgU1NCIGFuZCBhIHBlcmNlcHRpb24gb2YgdGhlIHN0b2NrIGFzIGxhcmdlciB0aGFuIGl0IHJlYWxseSBpcy4gIEJ5IG1hbnVhbGx5IHNldHRpbmcgbWF0dXJpdHkgYXQgYWdlIDEgdG8gemVybywgd2Ugb3Zlci13cml0ZSBhbnkgZXJyb3JzIGludHJvZHVjZWQgZHVyaW5nIHNhbXBsaW5nIHdpdGggZXhwZXJ0IGtub3dsZWRnZSB0aGF0IGFnZSAxIGZpc2ggYXJlIGV4dHJlbWVseSB1bmxpa2VseSB0byBiZSBtYXR1cmUsIHdoaWNoIHJlZHVjZXMgdGhpcyBvdmVyLWVzdGltYXRpb24gYW5kIGludGVyYW5udWFsIHZvbGF0aWxpdHkgb2YgU1NCLg0KDQpJbiBzY2VuYXJpbyAyLCB3ZSBydW4gYSB0eXBlIG9mIHNlbnNpdGl2aXR5IGFuYWx5c2lzIGJ1dCBiYXNlIHRoZSByYW5nZSBvZiB2YWx1ZXMgaW4gdGhlIHNlbnNpdGl2aXR5IHByb2ZpbGUgb24gdGhlIGJlc3QgYXZhaWxhYmxlIGtub3dsZWRnZSBmb3IgZGlzY2FyZCBzdXJ2aXZhbC4gIERpc2NhcmQgc3Vydml2YWwgaXMgZGlmZmljdWx0IHRvIGVzdGltYXRlIGZvciB0aGlzIHNwZWNpZXMgYW5kIHRoaXMgc3RvY2sgZm9yIG11bHRpcGxlIHJlYXNvbnMuIFN1cnZpdmFsIHZhcmllcyBhY2NvcmRpbmcgdG8gYSByYW5nZSBvZiBmYWN0b3JzLCBvbmx5IHNvbWUgb2Ygd2hpY2ggd2UgY2FuIGFjY291bnQgZm9yIGFuZCBmb3Igb25seSBhIHN1YnNldCBvZiB3aGljaCBkbyB3ZSBoYXZlIGxpdGVyYXR1cmUgYmFzZWQgb2JzZXJ2YXRpb25zIG9mIHN1cnZpdmFsLiAgRm9yIGV4YW1wbGUsIFN1cnZpdmFsIGFmdGVyIGRpc2NhcmRzIGhhcyBzaG93biB0byBiZSBjb3JyZWxhdGVkIHdpdGg6DQoNCi0gVGltZSBleHBvc2VkIHRvIGFpcg0KLSBUZW1wZXJhdHVyZSAoc2Vhc29uKQ0KLSBHZWFyIHR5cGUgKHZhcnlpbmcgYWNyb3NzIGRpZmZlcmVudCBtZXRpZXJzKQ0KLSBEb21pbmFudCBzcGVjaWVzIGluIHRoZSBoYXVsDQotIG1hbnkgb3RoZXJzDQoNCkluIG91ciBkYXRhIGNvbXBpbGF0aW9uIHByb2Nlc3Mgd2UgY2FuIGFjY291bnQgZm9yIHNvbWUgb2YgdGhlc2UgdG8gZ3JlYXRlciBvciBsZXNzZXIgZXh0ZW50czoNCg0KLSBUZW1wZXJhdHVyZSAoc2Vhc29uKSBieSBhcHBseWluZyBkaWZmZXJlbnQgc3Vydml2YWwgcmF0ZXMgcGVyIHF1YXJ0ZXIuDQotIEdlYXIgdHlwZSBieSBhcHBseWluZyBkaWZmZXJlbnQgc3Vydml2YWwgcmF0ZXMgdG8gImFjdGl2ZSIgYW5kICJwYXNzaXZlIiBnZWFycy4NCi0gR2VhcnR5cGUgYW5kIERvbWluYW50IHNwZWNpZXMgaW4gdGhlIGhhdWwgYnkgdXRpbGlzaW5nIHN1cnZpdmFsIHJhdGVzIHJlcG9ydGVkIGZyb20gc3R1ZGllcyBpbiBkaWZmZXJlbnQgbWFuYWdlbWVudCBhcmVhcyAoZS5nLiBzdHVkaWVzIGluIFNEMjEvS2F0dGVnYXQgb3IgYW5hbGFnb3VzIFNrYWdlcnJhaywgdnMgc3R1ZGllcyBmcm9tIHRoZSBCZWx0IFNlYXMvV2VzdGVybiBCYWx0aWMgU2VhKQ0KDQpIb3dldmVyLCB0aGVyZSBhcmUgbWFueSBtb3JlIGNvbWJpbmF0aW9ucyBvZiB0aGVzZSBmYWN0b3JzIHRoYW4gd2hhdCBpcyBhZGRyZXNzZWQgaW4gc3R1ZGllcyByZXBvcnRlZCBpbiBwcmltYXJ5IG9yIGdyZXkgbGl0ZXJhdHVyZS4gVGhlcmVmb3JlLCB3ZSd2ZSB1c2VkIHRoZSBzdHVkaWVzIGF0IGZhY2UgdmFsdWUsIHdoZXJlIHRoZXkgbWF0Y2ggc29tZSBjb21iaW5hdGlvbnMgb2YgdGhlc2UgZmFjdG9ycywgdGhlbiB1c2VkIGVzdGltYXRpb25zIGZvciB0aGUgZ2Fwcy4gIFRoZSBlc3RpbWF0aW9ucyBhcmUgYmFzZWQgb24gY29weWluZyB0ZW1wb3JhbCB0cmVuZHMgZnJvbSBkaWZmZXJlbnQgZmxlZXQgc2VnbWVudHMsIHdoZXJlIHNlYXNvbmFsIHZhcmlhdGlvbiBoYXMgYmVlbiByZXBvcnRlZCwgYW5kIGFwcGx5aW5nIHRoZW0gdG8gdGhvc2Ugc2VnbWVudHMgd2hlcmUgc3Vydml2YWwgcmF0ZXMgaGF2ZSBvbmx5IGJlZW4gcmVwb3J0ZWQgZm9yIG9uZSBzZWFzb24uICBGdXJ0aGVybW9yZSwgYmVjYXVzZSBmbGVldCBzZWdtZW50cyBpbiB0aGlzIHN0b2NrIGFyZSBhZ2dyZWdhdGVkIGludG8gImFjdGl2ZSIgYW5kICJwYXNzaXZlIiwgd2UgdGFrZSBhdmVyYWdlcyAodW53ZWlnaHRlZCkgYWNyb3NzIGRpZmZlcmVudCBtZXRpZXJzIHdoZXJlIHRoZXNlIGFyZSByZXBvcnRlZC4NCg0KRm9yIG1vcmUgZGV0YWlscyBvbiB0aGUgZXZpZGVuY2UgdXNlZCBhbmQgaG93IGl0IGlzIGFwcGxpZWQsIHNlZSBhbm90aGVyIG9mIHRoZSB3b3JraW5nIGRvY3VtZW50cyBmcm9tIHRoaXMgd29ya3Nob3AuDQoNClRocm91Z2hvdXQgdGhlIGRvY3VtZW50LCB0aGUgY29kZSB1c2VkIHRvIHVuZGVydGFrZSBlYWNoIHN0ZXAgcHJlY2VkZXMgdGhlIG91dHB1dCBhbmQgY2FuIGJlIGFjY2Vzc2VkIGJ5IGNsaWNraW5nIG9uIHRoZSBkcm9wLWRvd24gYXJyb3dzIHRvIHRoZSByaWdodCBvZiB0aGUgcGFnZS4NCg0KRGF0YSBjb21waWxhdGlvbiBpcyBkb25lIGV4dGVybmFsbHksIGFuZCB0aGlzIGRvY3VtZW50IGRlYWxzIG9ubHkgd2l0aCB0aGUgZmluYWxpc2VkIGlucHV0IGZpbGVzLiBBbGwgbW9kZWxzIGFyZSBidWlsZCB1c2luZyB0aGUgU3RhdGUtU3BhY2UgQXNzZXNzbWVudCBNb2RlbCAoU0FNKSwgYW5kIGluIHRoaXMgdmVyc2lvbiBvZiB0aGUgZG9jdW1lbnQsIGFsbCBtb2RlbCBpbnB1dCBmaWxlcyBhbmQgY29uZmlndXJhdGlvbnMgYXJlIGRvd25sb2FkZWQgZGlyZWN0bHkgZnJvbSB0aGUgcHVibGljbHkgYXZhaWxhYmxlIHZlcnNpb25zIG9uIFtzdG9ja2Fzc2Vzc21lbnQub3JnXShodHRwczovL3N0b2NrYXNzZXNzbWVudC5vcmcpLg0KDQojIyBQcmVwYXJhdGlvbg0KVG8gcnVuIHRoZSBzY3JpcHRzIGVtYmVkZGVkIGluIHRoaXMgZG9jdW1lbnQgKGlmIHlvdSB3b3VsZCBsaWtlIHRvIHJ1biB0aGUgYXNzZXNzbWVudCB5b3Vyc2VsZikgeW91IHJlcXVpcmUgdGhlIGZvbGxvd2luZyBwYWNrYWdlcyBhbmQgZnVuY3Rpb25zOg0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCByZXN1bHRzPSJoaWRlIn0NCnJlcXVpcmUoZGF0YS50YWJsZSkNCnJlcXVpcmUocmVzaGFwZTIpDQpyZXF1aXJlKGtuaXRyKQ0KcmVxdWlyZShzY2FsZXMpDQpyZXF1aXJlKGJvb2tkb3duKQ0KcmVxdWlyZShnZ3Bsb3QyKQ0KcmVxdWlyZShnZ3RoZW1lcykNCnJlcXVpcmUoc3RyaW5ncikNCnJlcXVpcmUobGF0dGljZSkNCnJlcXVpcmUocGx5cikNCnJlcXVpcmUocGxvdGx5KQ0KcmVxdWlyZShpY2VzQWR2aWNlKQ0KcmVxdWlyZSgic3RvY2thc3Nlc3NtZW50IikgIyBhdmFpbGFibGUgZnJvbSBodHRwczovL2dpdGh1Yi5jb20vZmlzaGZvbGxvd2VyL1NBTQ0KcmVxdWlyZShwYXJhbGxlbCkNCnJlcXVpcmUoc2YpDQoNCm15cHJvcCA8LSBmdW5jdGlvbihkZiwgbm9tbyA9ICJub21vIiwgTm9BdExuZ3QgPSAiQ0FOb0F0TG5ndCIpew0KICB0IDwtIHN1bShkZiRub21vKS9zdW0oZGYkQ0FOb0F0TG5ndCkNCn0NCg0KY2F0Y2hGcmFjIDwtIGZ1bmN0aW9uKHgsIG5tLCB3LCBmcmFjKXsNCiAgRiA8LSBnZXRGKHgpDQogIFogPC0gRitubQ0KICBOIDwtIGdldE4oeCkNCiAgQyA8LSBGL1oqKDEtZXhwKC1aKSkqTg0KICByZXR1cm4oc3VtKGZyYWMqdypDKSkNCn0NCg0KYGBgDQoNCldlIGFsc28gbmVlZCB0byBzZXQgYSBmZXcgdmFyaWFibGVzIG1hbnVhbGx5LiAgDQpUaGUgZmlyc3QgaXMgdGhlICpEYXRhWWVhciosIHdoaWNoIGlzIHRoZSB5ZWFyIGltbWVkaWF0ZWx5IHByZWNlZWRpbmcgdGhlIGFzc2Vzc21lbnQgeWVhciBvciB0aGUgeWVhciBmb3Igd2hpY2ggdGhlIG1vc3QgcmVjZW50IGNhdGNoIGRhdGEgaXMgYXZhaWxhYmxlLiAgDQoNCmBgYHtyfQ0KRGF0YVllYXIgPC0gMjAyMw0KTGFzdEljZXNBZHZpY2UgPC0gMjE3MzUgIyBBZHZpc2VkIGNhdGNoIGZvciBhcmVhcyAyMS0zMiAoZnJvbSBzdG9jayBzcGxpdHRpbmcgdGFibGUgaW4gYWR2aWNlKQ0KaXNGaW5hbCA8LSBGQUxTRQ0KIyBpc0ZpbmFsIDwtIFRSVUUNCmBgYA0KDQojIEJhc2VsaW5lDQoNClRoZSBiYXNlbGluZSBtb2RlbCB3ZSd2ZSBzZWxlY3RlZCBmb3IgdGhpcyB3b3JraW5nIGRvY3VtZW50LCBjb21lcyBmcm9tIHRoZSBpbnZlc3RpZ2F0aW9ucyBpbnRvIHRoZSBkaWZmZXJlbnQgdmVyc2lvbnMgb2YgbmF0dXJhbCBtb3J0YWxpdHkgd2UgaW52ZXN0aWdhdGVkIGluIHRoZSBwcmV2aW91cyB3b3JraW5nIGRvY3VtZW50OiBfUGxlLjI3LjNhLjIxLTMyX1dLQlBMQUlDRV9OZXdNb3J0YWxpdHkuUk1EXy4gDQoNClRoaXMgYmFzZWxpbmUgbW9kZWwgaXMgY2FsbGVkIFtwbGUuMjcuMjEtMzJfV0tCUExBSUNFXzIwMjRfQmlvUGFyc3dfbm1HNUZiXShodHRwczovL3N0b2NrYXNzZXNzbWVudC5vcmcvc2V0U3RvY2sucGhwP3N0b2NrPXBsZS4yNy4yMS0zMl9XS0JQTEFJQ0VfMjAyNF9CaW9QYXJzd19ubUc1RmIpIGFuZCBjYW4gYmUgZm91bmQgb24gW3N0b2NrYXNzZXNzbWVudC5vcmddKGh0dHBzOi8vc3RvY2thc3Nlc3NtZW50Lm9yZykuIA0KDQpgYGB7ciBubUc1RmJGaXRGcm9tV2VifQ0KZml0X25tRzVGYiA8LSBmaXRmcm9td2ViKCJwbGUuMjcuMjEtMzJfV0tCUExBSUNFXzIwMjRfQmlvUGFyc3dfbm1HNUZiIikNCmBgYA0KDQpgYGB7ciBkYXRhZnJhbWVTdW1tYXJ5X25tRzVGYiwgcmVzdWx0cz0naGlkZScsIGZpZy5zaG93PSdoaWRlJ30NCiM9PT0NCiMgQ3JlYXRlIGRhdGFmcmFtZSBvZiBjdXJyZW50IHllYXIncyBmaXQgZm9yIHBsb3R0aW5nDQojPT09PQ0KYXN1bV9ubUc1RmIgPC0gYXMuZGF0YS5mcmFtZShzdW1tYXJ5KGZpdF9ubUc1RmIpKQ0KYXN1bV9ubUc1RmIkWWVhciA8LSBhcy5pbnRlZ2VyKHJvdy5uYW1lcyhzdW1tYXJ5KGZpdF9ubUc1RmIpKSkNCmN0X25tRzVGYiA8LSBhcy5kYXRhLmZyYW1lKGNhdGNodGFibGUoZml0X25tRzVGYiwgb2JzLnNob3cgPSBUUlVFKSkNCmN0X25tRzVGYiRZZWFyIDwtIGFzLmludGVnZXIocm93bmFtZXMoY3Rfbm1HNUZiKSkNCnJvd25hbWVzKGN0X25tRzVGYikgPC0gTlVMTA0KY3Rfbm1HNUZiIDwtIHJiaW5kKGN0X25tRzVGYiwgZGF0YS5mcmFtZShFc3RpbWF0ZSA9IE5BLCBMb3c9TkEsIEhpZ2g9TkEsIHNvcC5jYXRjaD1OQSwgWWVhcj1hcy5pbnRlZ2VyKDIwMjQpKSkNCmFzdW1fbm1HNUZiIDwtIG1lcmdlKHggPSBhc3VtX25tRzVGYiwgeSA9IGN0X25tRzVGYiwgYnkgPSAiWWVhciIpDQpjb2xuYW1lcyhhc3VtX25tRzVGYikgPC0gYygiWWVhciIsICJSX2FnZTEiLCAiUmxvdyIsICJSaGlnaCIsICJTU0IiLCAiU1NCbG93IiwgIlNTQmhpZ2giLCAiRmJhciIsICJGbG93IiwgIkZoaWdoIiwgIkNhdGNoRXN0IiwgIkNhdGNobG93IiwgIkNhdGNoaGlnaCIsICJDYXRjaE9icyIpDQojPT09PT0NCmBgYA0KDQojIyBGaXRzIHRvIGRhdGENCldoZW4gdGhlIG1vZGVsIGlzIHJ1biB3ZSBjYW4gZWFzaWx5IHNlZSBmcm9tIHdhcm5pbmdzL2Vycm9ycyBpZiB0aGVyZSBpcyBhIGNvbnZlcmdlbmNlIGlzc3VlLiAgSG93ZXZlciwgd2UgY2FuIGFsc28gY29uZmlybSB0aGlzLCBleHBsaWNpdGx5Og0KDQotIFRoZSBmaW5hbCBtb2RlbCBncmFkaWVudDogYHIgZml0X25tRzVGYiRvcHQkZXZhbHVhdGlvbnNbMl1gDQotIFRoYXQgdGhlcmUgaXMgYSBwb3NpdGl2ZSBkZWZpbml0ZSBoZXNzaWFuOiBgciBhbGwoZWlnZW4oZml0X25tRzVGYiRvcHQkaGUpJHZhbHVlcyA+MClgDQoNCkZ1cnRoZXJtb3JlLCBTQU0gZG9lcyBub3QgdXRpbGlzZSAiYm91bmRzIiB3aGVuIGZpdHRpbmcgdGhlIG1vZGVsLCBhbmQgdGhlcmVmb3JlLCBhcyBzdGFuZGFyZCBjaGVjayBvZiB3aGV0aGVyIG1vZGVsIHBhcmFtZXRlcnMgYXJlIGFwcHJvYWNoaW5nIHRoZWlyIGJvdW5kcyBpcyBpcnJlbGV2YW50Lg0KDQojIyMgVmlzdWFsaXNlIGZpdHMgdG8gZGF0YSBieSBhZ2Ugb3ZlciB0aW1lIGFjcm9zcyBmbGVldHMNCg0KYGBge3IgZmlnLmNhcD0iTW9kZWwgd2l0aCB0aW1lIHZhcnlpbmcgKGZpdmUgeWVhciBzbGlpZGluZyB3aW5kb3cgbWVhbiksIGFnZSB2YXJ5aW5nLCBHaXNsYXNvbiBuYXR1cmFsIG1vcnRhbGl0aWVzIChGaXNoQmFzZSkgZml0IHRvIGNhdGNoIGRhdGEgYnkgYWdlICh2YWx1ZXMgb24gdGhlIG1vZGVsIGxpbmsgZnVuY3Rpb24gc2NhbGUpLiJ9DQojIyBFeHRyYWN0IGRhdGEgZnJvbSBtb2RlbCBvYmplY3QNCmxvZ09ic19ubUc1RmIgPC0gc3BsaXQoZml0X25tRzVGYiRkYXRhJGxvZ29icywgY2VpbGluZyhzZXFfYWxvbmcoZml0X25tRzVGYiRkYXRhJGxvZ29icykvZml0X25tRzVGYiRkYXRhJG1heEFnZVBlckZsZWV0WzFdKSkNCmxvZ1ByZWRfbm1HNUZiIDwtIHNwbGl0KGZpdF9ubUc1RmIkcmVwJHByZWRPYnMsIGNlaWxpbmcoc2VxX2Fsb25nKGZpdF9ubUc1RmIkcmVwJHByZWRPYnMpL2ZpdF9ubUc1RmIkZGF0YSRtYXhBZ2VQZXJGbGVldFsxXSkpDQoNCiMjIFRyYW5zZm9ybSBkYXRhIHRvIHVzZWFibGUgZGF0YWZyYW1lcw0KIyMjIEluaXRpYWxpemUgYW4gZW1wdHkgZGF0YSBmcmFtZSBmb3Igb2JzZXJ2YXRpb25zDQpsb2dPYnNfbm1HNUZiX2RmIDwtIGRhdGEuZnJhbWUoYWdlID0gaW50ZWdlcigpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZsZWV0ID0gaW50ZWdlcigpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllYXIgPSBpbnRlZ2VyKCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9nT2JzID0gbnVtZXJpYygpKQ0KDQojIyMgUG9wdWxhdGUgdGhlIGRhdGEgZnJhbWUgZm9yIG9ic2VydmF0aW9ucw0KZm9yIChpIGluIHNlcV9hbG9uZyhsb2dPYnNfbm1HNUZiKSkgew0KICAjIENhbGN1bGF0ZSB0aGUgZ3JvdXAgYW5kIHllYXINCiAgeWVhciA8LSAoKGkgLSAxKSAlLyUgMykgKyAxDQogIGZsZWV0IDwtICgoaSAtIDEpICUlIDMpICsgMQ0KICANCiAgIyMjIENyZWF0ZSBhIHRlbXBvcmFyeSBkYXRhIGZyYW1lIGFuZCBhcHBlbmQgdG8gdGhlIG1haW4gZGF0YSBmcmFtZSBmb3Igb2JzZXJ2YXRpb25zDQogIHRlbXBfZGYgPC0gZGF0YS5mcmFtZShhZ2UgPSAxOjcsDQogICAgICAgICAgICAgICAgICAgICAgICBmbGVldCA9IGZsZWV0LA0KICAgICAgICAgICAgICAgICAgICAgICAgeWVhciA9IHllYXIrMjAwMSwNCiAgICAgICAgICAgICAgICAgICAgICAgIGxvZ09icyA9IGxvZ09ic19ubUc1RmJbW2ldXSkNCiAgbG9nT2JzX25tRzVGYl9kZiA8LSByYmluZChsb2dPYnNfbm1HNUZiX2RmLCB0ZW1wX2RmKQ0KfQ0KDQojIyMgSW5pdGlhbGl6ZSBhbiBlbXB0eSBkYXRhIGZyYW1lIGZvciBwcmVkaWN0aW9ucw0KbG9nUHJlZF9ubUc1RmJfZGYgPC0gZGF0YS5mcmFtZShhZ2UgPSBpbnRlZ2VyKCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZsZWV0ID0gaW50ZWdlcigpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ZWFyID0gaW50ZWdlcigpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2dQcmVkID0gbnVtZXJpYygpKQ0KDQojIyMgUG9wdWxhdGUgdGhlIGRhdGEgZnJhbWUgZm9yIHByZWRpY3Rpb25zDQpmb3IgKGkgaW4gc2VxX2Fsb25nKGxvZ1ByZWRfbm1HNUZiKSkgew0KICAjIENhbGN1bGF0ZSB0aGUgZ3JvdXAgYW5kIHllYXINCiAgeWVhciA8LSAoKGkgLSAxKSAlLyUgMykgKyAxDQogIGZsZWV0IDwtICgoaSAtIDEpICUlIDMpICsgMQ0KICANCiAgIyMjIENyZWF0ZSBhIHRlbXBvcmFyeSBkYXRhIGZyYW1lIGFuZCBhcHBlbmQgdG8gdGhlIG1haW4gZGF0YSBmcmFtZSBmb3IgcHJlZGljdGlvbnMNCiAgdGVtcF9kZiA8LSBkYXRhLmZyYW1lKGFnZSA9IDE6NywNCiAgICAgICAgICAgICAgICAgICAgICAgIGZsZWV0ID0gZmxlZXQsDQogICAgICAgICAgICAgICAgICAgICAgICB5ZWFyID0geWVhcisyMDAxLA0KICAgICAgICAgICAgICAgICAgICAgICAgbG9nUHJlZCA9IGxvZ1ByZWRfbm1HNUZiW1tpXV0pDQogIGxvZ1ByZWRfbm1HNUZiX2RmIDwtIHJiaW5kKGxvZ1ByZWRfbm1HNUZiX2RmLCB0ZW1wX2RmKQ0KfQ0KDQojIyBQbG90DQpsb2dQcmVkX25tRzVGYl9kZiRhZ2UgPC0gYXMuY2hhcmFjdGVyKGxvZ1ByZWRfbm1HNUZiX2RmJGFnZSkNCmxvZ09ic19ubUc1RmJfZGYkYWdlIDwtIGFzLmNoYXJhY3Rlcihsb2dPYnNfbm1HNUZiX2RmJGFnZSkNCg0KZ2dwbG90bHkoZ2dwbG90KCkrDQogICAgICAgICAgIGdlb21fcG9pbnQoZGF0YSA9IGxvZ09ic19ubUc1RmJfZGZbbG9nT2JzX25tRzVGYl9kZiRmbGVldCA9PSAxICYgbG9nT2JzX25tRzVGYl9kZiR5ZWFyICE9IChEYXRhWWVhcisxKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSB5ZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGxvZ09icywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IGFnZSksDQogICAgICAgICAgICAgICAgICAgICAgc2hhcGUgPSAyMSkgKw0KICAgICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IGxvZ1ByZWRfbm1HNUZiX2RmW2xvZ1ByZWRfbm1HNUZiX2RmJGZsZWV0ID09IDEgJiBsb2dQcmVkX25tRzVGYl9kZiR5ZWFyICE9IChEYXRhWWVhcisxKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IHllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBsb2dQcmVkLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBhZ2UpKSArDQogICAgICAgICAgIGZhY2V0X3dyYXAoZmFjZXRzID0gImFnZSIpICsgIywgc2NhbGVzID0gImZyZWVfeSIpICsNCiAgICAgICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGVicGFsLCBndWlkZSA9IEZBTFNFKSArDQogICAgICAgICAgIGd1aWRlcyhjb2xvdXI9RkFMU0UsIHNoYXBlPUZBTFNFKSArDQogICAgICAgICAgIHRoZW1lX2ZldygpKQ0KDQojIGZpdHBsb3QoZml0X25tRzVGYiwgZmxlZXRzPTEpDQpgYGANCg0KYGBge3IgZmlnLmNhcD0iTW9kZWwgd2l0aCB0aW1lIHZhcnlpbmcgKGZpdmUgeWVhciBzbGlpZGluZyB3aW5kb3cgbWVhbiksIGFnZSB2YXJ5aW5nLCBHaXNsYXNvbiBuYXR1cmFsIG1vcnRhbGl0aWVzIChGaXNoQmFzZSkgZml0IHRvIFExIHN1cnZleSBkYXRhIGJ5IGFnZSAodmFsdWVzIG9uIHRoZSBtb2RlbCBsaW5rIGZ1bmN0aW9uIHNjYWxlKS4ifQ0KZ2dwbG90bHkoZ2dwbG90KCkrDQogICAgICAgICAgIGdlb21fcG9pbnQoZGF0YSA9IGxvZ09ic19ubUc1RmJfZGZbbG9nT2JzX25tRzVGYl9kZiRmbGVldCA9PSAyICYgbG9nT2JzX25tRzVGYl9kZiR5ZWFyICE9IChEYXRhWWVhcisxKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSB5ZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGxvZ09icywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IGFnZSksDQogICAgICAgICAgICAgICAgICAgICAgc2hhcGUgPSAyMSkgKw0KICAgICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IGxvZ1ByZWRfbm1HNUZiX2RmW2xvZ1ByZWRfbm1HNUZiX2RmJGZsZWV0ID09IDIgJiBsb2dQcmVkX25tRzVGYl9kZiR5ZWFyICE9IChEYXRhWWVhcisxKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IHllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBsb2dQcmVkLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBhZ2UpKSArDQogICAgICAgICAgIGZhY2V0X3dyYXAoZmFjZXRzID0gImFnZSIpICsgIywgc2NhbGVzID0gImZyZWVfeSIpICsNCiAgICAgICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGVicGFsLCBndWlkZSA9IEZBTFNFKSArDQogICAgICAgICAgIGd1aWRlcyhjb2xvdXI9RkFMU0UsIHNoYXBlPUZBTFNFKSArDQogICAgICAgICAgIHRoZW1lX2ZldygpKQ0KIyBmaXRwbG90KGZpdF9ubUc1RmIsIGZsZWV0cz0yKQ0KYGBgDQoNCmBgYHtyIGZpZy5jYXA9Ik1vZGVsIHdpdGggdGltZSB2YXJ5aW5nIChmaXZlIHllYXIgc2xpaWRpbmcgd2luZG93IG1lYW4pLCBhZ2UgdmFyeWluZywgR2lzbGFzb24gbmF0dXJhbCBtb3J0YWxpdGllcyAoRmlzaEJhc2UpIGZpdCB0byBRMy80IHN1cnZleSBkYXRhIGJ5IGFnZSAodmFsdWVzIG9uIHRoZSBtb2RlbCBsaW5rIGZ1bmN0aW9uIHNjYWxlKS4ifQ0KZ2dwbG90bHkoZ2dwbG90KCkrDQogICAgICAgICAgIGdlb21fcG9pbnQoZGF0YSA9IGxvZ09ic19ubUc1RmJfZGZbbG9nT2JzX25tRzVGYl9kZiRmbGVldCA9PSAzICYgbG9nT2JzX25tRzVGYl9kZiR5ZWFyICE9IChEYXRhWWVhcisxKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSB5ZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGxvZ09icywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IGFnZSksDQogICAgICAgICAgICAgICAgICAgICAgc2hhcGUgPSAyMSkgKw0KICAgICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IGxvZ1ByZWRfbm1HNUZiX2RmW2xvZ1ByZWRfbm1HNUZiX2RmJGZsZWV0ID09IDMgJiBsb2dQcmVkX25tRzVGYl9kZiR5ZWFyICE9IChEYXRhWWVhcisxKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IHllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBsb2dQcmVkLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBhZ2UpKSArDQogICAgICAgICAgIGZhY2V0X3dyYXAoZmFjZXRzID0gImFnZSIpICsgIywgc2NhbGVzID0gImZyZWVfeSIpICsNCiAgICAgICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGVicGFsLCBndWlkZSA9IEZBTFNFKSArDQogICAgICAgICAgIGd1aWRlcyhjb2xvdXI9RkFMU0UsIHNoYXBlPUZBTFNFKSArDQogICAgICAgICAgIHRoZW1lX2ZldygpKQ0KDQojIGZpdHBsb3QoZml0X25tRzVGYiwgZmxlZXRzPTMpDQpgYGANCg0KYGBge3IgZmlnLmNhcD0iU3RhbmRhcmQgRGV2YXRpb25zIGJ5IEZsZWV0OyBHaXNsYXNvbiwgdGltZS12YXJ5aW5nIG1vcnRhbGl0eSAoRmlzaEJhc2UpIiwgaGVpZ2h0PTEwfQ0Kc2RwbG90KGZpdF9ubUc1RmIsIG1hcmcgPSBjKDUsNCwxLDEpKQ0KYGBgDQoNCiMjIyBSZXNpZHVhbHMNCmBgYHtyIGNhbGN1bGF0ZVJlc2lkdWFsc19ubUc1RmIsIHdhcm5pbmc9RkFMU0UsIHJlc3VsdHM9J2hpZGUnfQ0KcmVzaWRfbm1HNUZiIDwtIHJlc2lkdWFscyhmaXRfbm1HNUZiKQ0KcmVzaWRfbm1HNUZiX2RmIDwtIGRhdGEuZnJhbWUoeWVhciA9IHJlc2lkX25tRzVGYiR5ZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmxlZXQgPSByZXNpZF9ubUc1RmIkZmxlZXQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhZ2UgPSByZXNpZF9ubUc1RmIkYWdlLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb2JzZXJ2YXRpb24gPSByZXNpZF9ubUc1RmIkb2JzZXJ2YXRpb24sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZWFuID0gcmVzaWRfbm1HNUZiJG1lYW4sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXNpZHVhbCA9IHJlc2lkX25tRzVGYiRyZXNpZHVhbCkNCnJlc2lkX25tRzVGYl9kZiRmbGVldE5hbWUgPC0gaWZlbHNlKHJlc2lkX25tRzVGYl9kZiRmbGVldCA9PSAxLCBhdHRyaWJ1dGVzKHJlc2lkX25tRzVGYikkZmxlZXROYW1lc1sxXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UocmVzaWRfbm1HNUZiX2RmJGZsZWV0ID09IDIsIGF0dHJpYnV0ZXMocmVzaWRfbm1HNUZiKSRmbGVldE5hbWVzWzJdLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UocmVzaWRfbm1HNUZiX2RmJGZsZWV0ID09IDMsIGF0dHJpYnV0ZXMocmVzaWRfbm1HNUZiKSRmbGVldE5hbWVzWzNdLCBOQSkpKQ0KDQpyZXNpZF9ubUc1RmJfZGYkZmxlZXRBbHROYW1lIDwtIGlmZWxzZShyZXNpZF9ubUc1RmJfZGYkZmxlZXQgPT0gMSwgIlJlc2lkdWFsIEZpc2hpbmciLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShyZXNpZF9ubUc1RmJfZGYkZmxlZXQgPT0gMiwgIlExIFN1cnZleXMiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UocmVzaWRfbm1HNUZiX2RmJGZsZWV0ID09IDMsICJRMy80IFN1cnZleXMiLCBOQSkpKQ0KYGBgDQoNCmBgYHtyIGZpZy5jYXA9IkVzdGltYXRlZCBjb3JyZWxhdGlvbnMgaW4gcmVzaWR1YWwgdmFyaWF0aW9uIGJldHdlZW4gYWdlcyBmb3IgZWFjaCBvZiB0aGUgZmlzaGluZyBmbGVldCAodG9wKSBhbmQgdGhlIHR3byBzdXJ2ZXlzIChtaWRkbGUgJiBib3R0b20pLCBmcm9tIHRoZSBNb2RlbCB3aXRoIHRpbWUgdmFyeWluZyAoZml2ZSB5ZWFyIHNsaWlkaW5nIHdpbmRvdyBtZWFuKSwgYWdlIHZhcnlpbmcsIEdpc2xhc29uIG5hdHVyYWwgbW9ydGFsaXRpZXMgKEZpc2hCYXNlKS4ifQ0KDQppZighYWxsKGZpdF9ubUc1RmIkY29uZiRvYnNDb3JTdHJ1Y3Q9PSJJRCIpKXsgDQogIGNvcnBsb3QoZml0X25tRzVGYikJCQkgIA0KICAjIHNldGNhcCgiRXN0aW1hdGVkIGNvcnJlbGF0aW9ucyIsICJFc3RpbWF0ZXMgY29ycmVsYXRpb25zIGJldHdlZW4gYWdlIGdyb3VwcyBmb3IgZWFjaCBmbGVldCIpDQogICMgc3RhbXBpdChmaXQpDQp9IGVsc2Ugew0KICBwcmludCgiTm8gY29ycmVsYXRpb24gc3RydWN0dXJlIGNvbmZpZ3VyZWQgZm9yIHJlc2lkdWFscyBhY3Jvc3MgYWdlLiIpDQp9DQoNCmBgYA0KDQpgYGB7ciBmaWcuY2FwPSJPbmUgb2JzZXJ2YXRpb24gYWhlYWQgcmVzaWR1YWxzIGZvciB0aGUgdGhyZWUgZmxlZXRzIChyZWQvcGluayA9IG9ic2VydmF0aW9uIGxvd2VyIHRoYW4gbW9kZWwgZXN0aW1hdGUsIGJsdWUgPSBvYnNlcnZhdGlvbiBoaWdoZXIgdGhhbiBtb2RlbCBlc3RpbWF0ZSwgc2l6ZSA9IG1hZ25pdHVkZSBvZiByZXNpZHVhbCksIGZyb20gdGhlIE1vZGVsIHdpdGggdGltZSB2YXJ5aW5nIChmaXZlIHllYXIgc2xpaWRpbmcgd2luZG93IG1lYW4pLCBhZ2UgdmFyeWluZywgR2lzbGFzb24gbmF0dXJhbCBtb3J0YWxpdGllcyAoRmlzaEJhc2UpLiJ9DQpnZ3Bsb3RseShnZ3Bsb3QocmVzaWRfbm1HNUZiX2RmKSArDQogICAgICAgICAgIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0geWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBhZ2UsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gYWJzKHJlc2lkdWFsKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IHJlc2lkdWFsID49IDApLA0KICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC43KSArDQogICAgICAgICAgIGZhY2V0X2dyaWQocm93cyA9ICJmbGVldEFsdE5hbWUiKSArDQogICAgICAgICAgIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiVFJVRSIgPSBlYnBhbFs4XSwgIkZBTFNFIiA9IGVicGFsWzldKSkgKw0KICAgICAgICAgICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygtMSwgOSksIGJyZWFrcyA9IGMoMTo5KSkgKw0KICAgICAgICAgICBndWlkZXMoY29sb3VyPUZBTFNFKSArDQogICAgICAgICAgIHRoZW1lX2ZldygpKQ0KDQpgYGANCg0KIyMjIEppdHRlcmluZw0KV2UgY2FuIGFsc28gdGVzdCB0byBzZWUgaWYgdGhlIG1vZGVsIGlzIGNvbnZlcmdpbmcgb24gc29tZSBsb2NhbCBtaW5pbXVtIChpLmUuIGl0J3MgZml0dGluZyB0byBzb21lIHNvbHV0aW9uIGNsb3NlIHRvIGluaXRpYWxpc2luZyB2YWx1ZXMgdGhhdCByZXByZXNlbnRzIG5vaXNlIGFuZCBub3QgdGhlIGdsb2JhbCBzb2x1dGlvbiwgdGhhdCBpcyB0aGUgcHJvcGVyIHNvbHV0aW9uKS4gIFRvIGRvIHRoaXMsIHdlIGFkZCByYW5kb20gbm9pc2UgdG8gdGhlIGluaXRpYWwgcGFyYW1ldGVyIHZhbHVlcyB0byBzZWUgaWYgdGhlIG1vZGVsIHdpbGwgY29udmVyZ2Ugb24gYSBkaWZmZXJlbnQgbWluaW11bSBpbiBpdCdzIGRhdGEtc3BhY2UuIFRoZSBlYXNpZXN0IHdheSB0byBpbnZlc3RpZ2F0ZSB0aGlzIGlzIHRvIHNlZSBpZiB0aGUgbW9kZWwgZml0cyB2YXJ5IGFsb3QgZGVwZW5kaW5nIG9uIHRoZSBzdGFydGluZyB2YWx1ZXM6DQpgYGB7ciBKaXR0ZXJfbm1HNUZifQ0Kaml0X25tRzVGYiA8LSBqaXQoZml0ID0gZml0X25tRzVGYikNCg0KbXQgPC0gYXMuZGF0YS5mcmFtZShtb2RlbHRhYmxlKGppdF9ubUc1RmIpKQ0KbXQkbW9kZWwgPC0gcm93bmFtZXMobXQpDQpyb3duYW1lcyhtdCkgPC0gTlVMTA0KDQprYWJsZSh4ID0gbXQsDQogICAgICBkaWdpdHMgPSAzLA0KICAgICAgY2FwdGlvbiA9ICJNZWFzdXJlcyBvZiAgZml0IGZvciBhIHNlcmllcyBvZiBtb2RlbCByZWZpdHMgd2l0aCBqaXR0ZXIgYXBwbGllZCB0byB0aGUgaW5wdXQgcGFyYW1ldGVycy4iKQ0KYGBgDQoNCiMjIyBMZWF2ZS1PbmUtT3V0IEFuYWx5c2VzDQpBIGxlYXZlLW9uZS1vdXQgYW5hbHlzaXMgaXMgYSBmb3JtIG9mIHNlbnNpdGl2aXR5IGFuYWx5c2lzLCBzaG93aW5nIHRoZSBpbXBhY3QgdGhlIGRhdGEgZnJvbSBlYWNoIHR1bmluZyBmbGVldCBoYXMgb24gdGhlIGVzdGltYXRpb24gb2YgdGhlIGtleSB2YXJpYWJsZXMgYmVpbmcgZXN0aW1hdGVkOyBuYW1lbHkgU1NCLCBGIGFuZCByZWNydWl0bWVudC4gIA0KDQpGaXJzdCB3ZSBtdXN0IHJ1biB0aGUgbGVhdmUtb25lLW91dCBhbmFseXNpcyB3aGljaCByZWZpdHMgdGhlIG1vZGVsIGluIHR3byBpdGVyYXRpb25zLCByZW1vdmluZyBvbmUgc3VydmV5IGF0IGEgdGltZS4gVGhlbiB3ZSBjYW4gcGxvdCBlYWNoIG9mIHRoZXNlIG5ldyBtb2RlbCBmaXRzIG92ZXIgdGhlIGZ1bGwgbW9kZWwgdG8gc2VlIHRoZSBpbXBhY3QgdGhlIHJlbW92YWwgb2YgZWFjaCBoYXMuIA0KDQpgYGB7ciBMZWF2ZU9uZU91dF9ubUc1RmJ9DQpMT19ubUc1RmIgPC0gbGVhdmVvdXQoZml0X25tRzVGYikNCg0KIz09PSANCiMgR2V0IGRhdGEgZnJvbSBzYW0gb2JqZWN0cyBhbmQgZ2VuZXJhdGUgdXNlYWJsZSBkYXRhZnJhbWVzDQojPT09PQ0KcTFtYXQgPC0gYXMuZGF0YS5mcmFtZShzdW1tYXJ5KExPX25tRzVGYiRgdy5vLiBRMUlCVFMrQklUUytDb2RTRDIxLTI1YCkpDQpxM21hdCA8LSBhcy5kYXRhLmZyYW1lKHN1bW1hcnkoTE9fbm1HNUZiJGB3Lm8uIFEzNElCVFMrQklUUytDb2RTRDIxLTI1YCkpDQoNCg0Kd29xMSA8LSBkYXRhLmZyYW1lKFllYXIgPSBhcy5pbnRlZ2VyKHJvdy5uYW1lcyhzdW1tYXJ5KExPX25tRzVGYiRgdy5vLiBRMUlCVFMrQklUUytDb2RTRDIxLTI1YCkpKSwNCiAgICAgICAgICAgICAgICAgICBTU0IgPSBxMW1hdCRTU0IsDQogICAgICAgICAgICAgICAgICAgRmJhciA9IHExbWF0JGBGYmFyKDMtNSlgLA0KICAgICAgICAgICAgICAgICAgIFJfYWdlMSA9IHExbWF0JGBSKGFnZSAxKWAsDQogICAgICAgICAgICAgICAgICAgQ2F0Y2hFc3QgPSBjYXRjaHRhYmxlKExPX25tRzVGYiRgdy5vLiBRMUlCVFMrQklUUytDb2RTRDIxLTI1YClbLDFdLA0KICAgICAgICAgICAgICAgICAgIHNlcmllcyA9IHJlcCgid29fUTEiLCB0aW1lcyA9IG5yb3cocTFtYXQpKSkNCg0Kd29xMzQgPC0gZGF0YS5mcmFtZShZZWFyID0gYXMuaW50ZWdlcihyb3cubmFtZXMocTNtYXRbKDIwMDI6RGF0YVllYXIpLTIwMDEsXSkpLA0KICAgICAgICAgICAgICAgICAgICBTU0IgPSBxM21hdFsoMjAwMjpEYXRhWWVhciktMjAwMSwgIlNTQiJdLA0KICAgICAgICAgICAgICAgICAgICBGYmFyID0gcTNtYXRbKDIwMDI6RGF0YVllYXIpLTIwMDEsIkZiYXIoMy01KSJdLA0KICAgICAgICAgICAgICAgICAgICBSX2FnZTEgPSBxM21hdFsoMjAwMjpEYXRhWWVhciktMjAwMSwiUihhZ2UgMSkiXSwNCiAgICAgICAgICAgICAgICAgICAgQ2F0Y2hFc3QgPSBjYXRjaHRhYmxlKExPX25tRzVGYiRgdy5vLiBRMzRJQlRTK0JJVFMrQ29kU0QyMS0yNWApWywxXSwNCiAgICAgICAgICAgICAgICAgICAgc2VyaWVzID0gcmVwKCJ3b19RMzQiLCB0aW1lcyA9IChucm93KHEzbWF0KS0xKSkpDQoNCg0KYXN1bV9ubUc1RmIkc2VyaWVzIDwtIHJlcCgiZnVsbCIsIHRpbWVzID0gbnJvdyhhc3VtX25tRzVGYikpDQphc3VtaV9ubUc1RmIgPC0gYXN1bV9ubUc1RmJbLCBjKCJZZWFyIiwgIlNTQiIsICJGYmFyIiwgIlJfYWdlMSIsICJDYXRjaEVzdCIgLCJzZXJpZXMiKV0NCiM9PT09PQ0KDQpsb3N1bV9ubUc1RmIgPC0gcmJpbmQod29xMSwgd29xMzQsIGFzdW1pX25tRzVGYikNCg0KYGBgDQoNCmBgYHtyIGZpZy5jYXA9IkxlYXZlLW9uZS1vdXQgcmUtZml0cyBmb3IgdGhlIFRpbWUgdmFyeWluZywgR2lzbGFzb24gbmF0dXJhbCBtb3J0YWxpdGllcyBjYWxjdWxhdGVkIGZyb20gbGlmZS1oaXN0b3J5IG9mZiBvZiBmaXNoYmFzZSAod2l0aG91dCBRMSBzdXJ2ZXkgPSBibHVlLCB3aXRob3V0IFEzLzQgc3VydmV5ID0gcHVycGxlKSwgb3ZlcmxhaW4gd2l0aCBmdWxsIG1vZGVsIGVzdGltYXRlcyAoYmxhY2sgbGluZSBhbmQgZ3JleSByaWJib24pIG9mIFNTQiAodG9wIGxlZnQpLCBGICh0b3AgcmlnaHQpLCBSZWNydWl0bWVudCAoYm90dG9tIGxlZnQpLCBhbmQgY2F0Y2ggKGJvdHRvbSByaWdodDsgb2JzZXJ2YXRpb25zIGFzIHllbGxvdyArKS4ifQ0KIyBzc2JwbG90KExPKQ0KbG9zc2Jfbm1HNUZiIDwtIGdncGxvdGx5KGdncGxvdCgpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fbGluZShkYXRhID0gbG9zdW1fbm1HNUZiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1TU0IsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBzZXJpZXMpKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3JpYmJvbihkYXRhID0gYXN1bV9ubUc1RmIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1pbj1TU0Jsb3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltYXg9U1NCaGlnaCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gImJsYWNrIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4yKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoImJsYWNrIiwgZWJwYWxbODo5XSkpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2NsZWFuKCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWUoYXhpcy50aXRsZS55LmxlZnQgPSBlbGVtZW50X3RleHQodmp1c3QgPSAtMC4wNSwgaGp1c3QgPSAwLjk1KSkpDQoNCiMgRnBsb3QoTE8pDQpsb2Zfbm1HNUZiIDwtIGdncGxvdGx5KGdncGxvdCgpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IGxvc3VtX25tRzVGYiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1GYmFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IHNlcmllcykpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3JpYmJvbihkYXRhID0gYXN1bV9ubUc1RmIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWluPUZsb3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4PUZoaWdoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gImJsYWNrIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMykgKw0KICAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiYmxhY2siLCBlYnBhbFs4OjldKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2NsZWFuKCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKGF4aXMudGl0bGUueS5sZWZ0ID0gZWxlbWVudF90ZXh0KHZqdXN0ID0gLTAuMDUsIGhqdXN0ID0gMC45NSkpKQ0KDQojIHJlY3Bsb3QoTE8pDQpsb3JlY19ubUc1RmIgPC0gZ2dwbG90bHkoZ2dwbG90KCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9saW5lKGRhdGEgPSBsb3N1bV9ubUc1RmIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PVJfYWdlMSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IHNlcmllcykpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fcmliYm9uKGRhdGEgPSBhc3VtX25tRzVGYiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWluPVJsb3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltYXg9UmhpZ2gpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9ICJibGFjayIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMykgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCJibGFjayIsIGVicGFsWzg6OV0pKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9jbGVhbigpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKGF4aXMudGl0bGUueS5sZWZ0ID0gZWxlbWVudF90ZXh0KHZqdXN0ID0gLTAuMDUsIGhqdXN0ID0gMC45NSkpKQ0KDQojIENhdGNoIHBsb3QgKExPKQ0KbG9jYV9ubUc1RmIgPC0gZ2dwbG90bHkoZ2dwbG90KCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IGxvc3VtX25tRzVGYiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PUNhdGNoRXN0LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBzZXJpZXMpKSsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9yaWJib24oZGF0YSA9IGFzdW1fbm1HNUZiW2FzdW1fbm1HNUZiJFllYXIgIT0gKERhdGFZZWFyKzEpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWluPUNhdGNobG93LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltYXg9Q2F0Y2hoaWdoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9ICJibGFjayIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4zKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fcG9pbnQoZGF0YSA9IGFzdW1fbm1HNUZiW2FzdW1fbm1HNUZiJFllYXIgIT0gKERhdGFZZWFyKzEpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1DYXRjaE9icyksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hhcGUgPSAzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IGVicGFsWzVdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBlYnBhbFs1XSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICB5bGFiKCJDYXRjaCAodG9ubmVzKSIpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCJibGFjayIsIGVicGFsWzg6OV0pKSsgDQogICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2NsZWFuKCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZShheGlzLnRpdGxlLnkubGVmdCA9IGVsZW1lbnRfdGV4dCh2anVzdCA9IC0wLjA1LCBoanVzdCA9IDAuOTUpKSkNCg0KbGF5b3V0KHN1YnBsb3QobG9zc2Jfbm1HNUZiLCBsb2Zfbm1HNUZiLCBsb3JlY19ubUc1RmIsIGxvY2Ffbm1HNUZiLCBucm93cyA9IDIsIHNoYXJlWCA9IFRSVUUsIHRpdGxlWSA9IFRSVUUpLCBzaG93bGVnZW5kPUZBTFNFKQ0KYGBgDQoNCiMjIyBSZXRyb3NwZWN0aXZlcw0KYGBge3IgY2FsY3VsYXRlUmV0cm9zX25tRzVGYn0NCiM9PT0NCiMgQ3JlYXRlIGRhdGFmcmFtZSBvZiBjdXJyZW50IHllYXIncyBmaXQgZm9yIHBsb3R0aW5nDQojPT09PQ0KIyBJQ19hZ2dfdGVtcCA8LSBhZ2dyZWdhdGUoQ0FUT05+WWVhciwgaWNfY2xlYW5baWNfY2xlYW4kQ2F0Y2hDYXRlZ29yeSAlaW4lIGMoIkxhbmRpbmdzIiwgIkRpc2NhcmRzIiksIF0sIEZVTiA9ICJzdW0iKQ0KYXN1bV9ubUc1RmIgPC0gYXMuZGF0YS5mcmFtZShzdW1tYXJ5KGZpdF9ubUc1RmIpKQ0KYXN1bV9ubUc1RmIkWWVhciA8LSBhcy5pbnRlZ2VyKHJvdy5uYW1lcyhzdW1tYXJ5KGZpdF9ubUc1RmIpKSkNCmN0X25tRzVGYiA8LSBhcy5kYXRhLmZyYW1lKGNhdGNodGFibGUoZml0X25tRzVGYiwgb2JzLnNob3cgPSBUUlVFKSkNCmN0X25tRzVGYiRZZWFyIDwtIGFzLmludGVnZXIocm93bmFtZXMoY3Rfbm1HNUZiKSkNCnJvd25hbWVzKGN0X25tRzVGYikgPC0gTlVMTA0KY3Rfbm1HNUZiIDwtIHJiaW5kKGN0X25tRzVGYiwgZGF0YS5mcmFtZShFc3RpbWF0ZSA9IE5BLCBMb3c9TkEsIEhpZ2g9TkEsIHNvcC5jYXRjaD1OQSwgWWVhcj1hcy5pbnRlZ2VyKDIwMjQpKSkNCmFzdW1fbm1HNUZiIDwtIG1lcmdlKHggPSBhc3VtX25tRzVGYiwgeSA9IGN0X25tRzVGYiwgYnkgPSAiWWVhciIpDQpjb2xuYW1lcyhhc3VtX25tRzVGYikgPC0gYygiWWVhciIsICJSX2FnZTEiLCAiUmxvdyIsICJSaGlnaCIsICJTU0IiLCAiU1NCbG93IiwgIlNTQmhpZ2giLCAiRmJhciIsICJGbG93IiwgIkZoaWdoIiwgIkNhdGNoRXN0IiwgIkNhdGNobG93IiwgIkNhdGNoaGlnaCIsICJDYXRjaE9icyIpDQoNCmFzdW1fbm1HNUZiJHNlcmllcyA8LSByZXAoImZ1bGwiLCB0aW1lcyA9IG5yb3coYXN1bV9ubUc1RmIpKQ0KDQojPT09PT0NClJFVFJPX25tRzVGYjwtcmV0cm8oZml0X25tRzVGYiwgeWVhcj01KQ0KcmhvX25tRzVGYiA8LSBtb2huKFJFVFJPX25tRzVGYiwgbGFnID0gMSkNCg0KIyMgTWFrZSBSRVRST3MgaW4gYmV0dGVyIHBsb3R0aW5nIGZvcm1hdA0KcmV0X25tRzVGYl9kZiA8LSBhc3VtX25tRzVGYlthc3VtX25tRzVGYiRZZWFyICE9IG1heChhc3VtX25tRzVGYiRZZWFyKSwgXQ0KDQpmb3IoaSBpbiAxOmxlbmd0aChSRVRST19ubUc1RmIpKXsNCiAgdHN1bSA8LSBhcy5kYXRhLmZyYW1lKHN1bW1hcnkoUkVUUk9fbm1HNUZiW1tpXV0pKQ0KICB0c3VtJFllYXIgPC0gYXMuaW50ZWdlcihyb3cubmFtZXMoc3VtbWFyeShSRVRST19ubUc1RmJbW2ldXSkpKQ0KICB0c3VtIDwtIGNiaW5kKHRzdW0sIGNhdGNodGFibGUoUkVUUk9fbm1HNUZiW1tpXV0sIG9icy5zaG93ID0gVFJVRSkpDQogIHRzdW0kc2VyaWVzIDwtIGFzLmNoYXJhY3RlcihyZXAoaSwgbnJvdyh0c3VtKSkpDQogIGNvbG5hbWVzKHRzdW0pIDwtIGMoIlJfYWdlMSIsICJSbG93IiwgIlJoaWdoIiwgIlNTQiIsICJTU0Jsb3ciLCAiU1NCaGlnaCIsICJGYmFyIiwgIkZsb3ciLCAiRmhpZ2giLCAiWWVhciIsICJDYXRjaEVzdCIsICJDYXRjaGxvdyIsICJDYXRjaGhpZ2giLCAiQ2F0Y2hPYnMiLCAic2VyaWVzIikNCiAgdHN1bSA8LSB0c3VtW3RzdW0kWWVhciAhPSBtYXgodHN1bSRZZWFyKSwgXQ0KICByZXRfbm1HNUZiX2RmIDwtIHJiaW5kKHJldF9ubUc1RmJfZGYsIHRzdW0pDQp9DQpyZXRfbm1HNUZiX2RmJHNlcmllcyA8LSBmYWN0b3IocmV0X25tRzVGYl9kZiRzZXJpZXMsIGxldmVscyA9IGMoImZ1bGwiLCAiMSIsICIyIiwgIjMiLCAiNCIsICI1IikpDQpgYGANCg0KYGBge3IgZmlnLmNhcD0iUmV0cm9zcGVjdGl2ZSBhbmFseXNlcyBmb3IgU1NCICh0b3AtbGVmdCksIEYgZm9yIGFnZXMgMy01ICh0b3AtcmlnaHQpLCByZWNydWl0bWVudCAoYm90dG9tLWxlZnQpLCBhbmQgY2F0Y2ggKGJvdHRvbS1yaWdodCksIGZyb20gdGhlIG1vZGVsIHV0aWxpc2luZyB0aW1lIHZhcmlhbnQgKDUgeWVhciBzbGlkaW5nIHdpbmRvdyBtZWFuKSwgR2lzbGFzb24gbmF0dXJhbCBtb3J0YWxpdGllcyAoRmlzaEJhc2UpLiJ9DQojIHNzYnBsb3QoUkVUUk8pDQpyZXRzc2Jfbm1HNUZiIDwtIGxheW91dChnZ3Bsb3RseShnZ3Bsb3QoKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fbGluZShkYXRhID0gcmV0X25tRzVGYl9kZiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PVNTQiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gc2VyaWVzKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3JpYmJvbihkYXRhID0gYXN1bV9ubUc1RmJbYXN1bV9ubUc1RmIkWWVhciAhPSBtYXgoYXN1bV9ubUc1RmIkWWVhciksIF0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW49U1NCbG93LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltYXg9U1NCaGlnaCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSAiYmxhY2siLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMikgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbm5vdGF0ZShnZW9tID0gInRleHQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gbWF4KHJldF9ubUc1RmJfZGYkU1NCaGlnaCkqMC44NSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeCA9ICgobWF4KHJldF9ubUc1RmJfZGYkWWVhciktbWluKHJldF9ubUc1RmJfZGYkWWVhcikpKjAuMjApK21pbihyZXRfbm1HNUZiX2RmJFllYXIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbCA9IHBhc3RlMCgiTW9obidzIFJobyA9ICIsIHJvdW5kKHJob19ubUc1RmJbMl0sIGRpZ2l0cyA9IDMpKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoImJsYWNrIiwgZWJwYWxbKGxlbmd0aChlYnBhbCktNCk6bGVuZ3RoKGVicGFsKV0pKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2NsZWFuKCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF4aXMudGl0bGUueS5sZWZ0ID0gZWxlbWVudF90ZXh0KHZqdXN0ID0gLTAuMDUsIGhqdXN0ID0gMC45NSkpKSwNCiAgICAgICAgICAgICAgICAgICAgICAgIHNob3dsZWdlbmQgPSBGQUxTRSkNCg0KIyBGcGxvdChSRVRSTykNCnJldGZfbm1HNUZiIDwtIGxheW91dChnZ3Bsb3RseShnZ3Bsb3QoKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IHJldF9ubUc1RmJfZGYsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PUZiYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBzZXJpZXMpKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3JpYmJvbihkYXRhID0gYXN1bV9ubUc1RmJbYXN1bV9ubUc1RmIkWWVhciAhPSBtYXgoYXN1bV9ubUc1RmIkWWVhciksIF0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1pbj1GbG93LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4PUZoaWdoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSAiYmxhY2siLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjMpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFubm90YXRlKGdlb20gPSAidGV4dCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gbWF4KHJldF9ubUc1RmJfZGYkRmhpZ2gpKjAuODUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4ID0gKChtYXgocmV0X25tRzVGYl9kZiRZZWFyKS1taW4ocmV0X25tRzVGYl9kZiRZZWFyKSkqMC44MCkrbWluKHJldF9ubUc1RmJfZGYkWWVhciksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbCA9IHBhc3RlMCgiTW9obidzIFJobyA9ICIsIHJvdW5kKHJob19ubUc1RmJbM10sIGRpZ2l0cyA9IDMpKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCJibGFjayIsIGVicGFsWyhsZW5ndGgoZWJwYWwpLTQpOmxlbmd0aChlYnBhbCldKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWVfY2xlYW4oKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBheGlzLnRpdGxlLnkubGVmdCA9IGVsZW1lbnRfdGV4dCh2anVzdCA9IC0wLjA1LCBoanVzdCA9IDAuOTUpKSksDQogICAgICAgICAgICAgICAgICAgICAgc2hvd2xlZ2VuZCA9IEZBTFNFKQ0KDQojIHJlY3Bsb3QoUkVUUk8pDQpyZXRyZWNfbm1HNUZiIDwtIGxheW91dChnZ3Bsb3RseShnZ3Bsb3QoKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fbGluZShkYXRhID0gcmV0X25tRzVGYl9kZiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PVJfYWdlMSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gc2VyaWVzKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3JpYmJvbihkYXRhID0gYXN1bV9ubUc1RmJbYXN1bV9ubUc1RmIkWWVhciAhPSBtYXgoYXN1bV9ubUc1RmIkWWVhciksIF0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW49UmxvdywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4PVJoaWdoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9ICJibGFjayIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4zKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFubm90YXRlKGdlb20gPSAidGV4dCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9IG1heChyZXRfbm1HNUZiX2RmJFJoaWdoKSowLjg1LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4ID0gKChtYXgocmV0X25tRzVGYl9kZiRZZWFyKS1taW4ocmV0X25tRzVGYl9kZiRZZWFyKSkqMC4yMCkrbWluKHJldF9ubUc1RmJfZGYkWWVhciksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsID0gcGFzdGUwKCJNb2huJ3MgUmhvID0gIiwgcm91bmQocmhvX25tRzVGYlsxXSwgZGlnaXRzID0gMykpKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiYmxhY2siLCBlYnBhbFsobGVuZ3RoKGVicGFsKS00KTpsZW5ndGgoZWJwYWwpXSkpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWVfY2xlYW4oKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXhpcy50aXRsZS55LmxlZnQgPSBlbGVtZW50X3RleHQodmp1c3QgPSAtMC4wNSwgaGp1c3QgPSAwLjk1KSkpLA0KICAgICAgICAgICAgICAgICAgICAgICAgc2hvd2xlZ2VuZCA9IEZBTFNFKQ0KDQojIENhdGNoIHBsb3QgKFJFVFJPKQ0KcmV0Y2Ffbm1HNUZiIDwtIGdncGxvdGx5KGdncGxvdCgpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fbGluZShkYXRhID0gcmV0X25tRzVGYl9kZiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9Q2F0Y2hFc3QsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBzZXJpZXMpKSsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fcmliYm9uKGRhdGEgPSBhc3VtX25tRzVGYlthc3VtX25tRzVGYiRZZWFyICE9IG1heChhc3VtX25tRzVGYiRZZWFyKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWluPUNhdGNobG93LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4PUNhdGNoaGlnaCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gImJsYWNrIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4zKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3BvaW50KGRhdGEgPSBhc3VtX25tRzVGYlthc3VtX25tRzVGYiRZZWFyICE9IG1heChhc3VtX25tRzVGYiRZZWFyKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1DYXRjaE9icyksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNoYXBlID0gMywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gZWJwYWxbNV0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBlYnBhbFs1XSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgeWxhYigiQ2F0Y2ggKHRvbm5lcykiKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoImJsYWNrIiwgZWJwYWxbKGxlbmd0aChlYnBhbCktNCk6bGVuZ3RoKGVicGFsKV0pKSsgDQogICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9jbGVhbigpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKGF4aXMudGl0bGUueS5sZWZ0ID0gZWxlbWVudF90ZXh0KHZqdXN0ID0gLTAuMDUsIGhqdXN0ID0gMC45NSkpKQ0KDQpyZXRfZnAgPC0gc3R5bGUoc3VicGxvdChyZXRzc2Jfbm1HNUZiLCByZXRmX25tRzVGYiwgcmV0cmVjX25tRzVGYiwgcmV0Y2Ffbm1HNUZiLCBucm93cyA9IDIsIHNoYXJlWCA9IEZBTFNFLCBzaGFyZVkgPSBGQUxTRSwgdGl0bGVZID0gVFJVRSksDQogICAgICAgICAgICAgICAgc2hvd2xlZ2VuZD1GQUxTRSwNCiAgICAgICAgICAgICAgICB0cmFjZXMgPSBjKDg6KCg3KjQpKzIpKSkNCg0KbGF5b3V0KHJldF9mcCwgbGVnZW5kID0gbGlzdChvcmllbnRhdGlvbiA9ICdoJywgeCA9IDAuNSwgeGFuY2hvciA9ICdjZW50ZXInLCB5ID0gLTAuMDUsIHlhbmNob3IgPSAndG9wJywgYm9yZGVyd2lkdGggPSAwKSkNCmBgYA0KDQojIE1hdHVyaXR5IEFnZTEgU2V0IHRvIFplcm8NCg0KVGhpcyBtb2RlbCBpcyBjYWxsZWQgW3BsZS4yNy4yMS0zMl9XS0JQTEFJQ0VfMjAyNF9CUF9ubUc1RmJfbW8xXShodHRwczovL3N0b2NrYXNzZXNzbWVudC5vcmcvc2V0U3RvY2sucGhwP3N0b2NrPXBsZS4yNy4yMS0zMl9XS0JQTEFJQ0VfMjAyNF9CUF9ubUc1RmJfbW8xX21vMSkgYW5kIGNhbiBiZSBmb3VuZCBvbiBbc3RvY2thc3Nlc3NtZW50Lm9yZ10oaHR0cHM6Ly9zdG9ja2Fzc2Vzc21lbnQub3JnKS4gDQoNCmBgYHtyIG5tRzVGYl9tbzFGaXRGcm9tV2VifQ0KZml0X25tRzVGYl9tbzEgPC0gZml0ZnJvbXdlYigicGxlLjI3LjIxLTMyX1dLQlBMQUlDRV8yMDI0X0JQX25tRzVGYl9tbzEiKQ0KYGBgDQoNCmBgYHtyIGRhdGFmcmFtZVN1bW1hcnlfbm1HNUZiX21vMSwgcmVzdWx0cz0naGlkZScsIGZpZy5zaG93PSdoaWRlJ30NCiM9PT0NCiMgQ3JlYXRlIGRhdGFmcmFtZSBvZiBjdXJyZW50IHllYXIncyBmaXQgZm9yIHBsb3R0aW5nDQojPT09PQ0KYXN1bV9ubUc1RmJfbW8xIDwtIGFzLmRhdGEuZnJhbWUoc3VtbWFyeShmaXRfbm1HNUZiX21vMSkpDQphc3VtX25tRzVGYl9tbzEkWWVhciA8LSBhcy5pbnRlZ2VyKHJvdy5uYW1lcyhzdW1tYXJ5KGZpdF9ubUc1RmJfbW8xKSkpDQpjdF9ubUc1RmJfbW8xIDwtIGFzLmRhdGEuZnJhbWUoY2F0Y2h0YWJsZShmaXRfbm1HNUZiX21vMSwgb2JzLnNob3cgPSBUUlVFKSkNCmN0X25tRzVGYl9tbzEkWWVhciA8LSBhcy5pbnRlZ2VyKHJvd25hbWVzKGN0X25tRzVGYl9tbzEpKQ0Kcm93bmFtZXMoY3Rfbm1HNUZiX21vMSkgPC0gTlVMTA0KY3Rfbm1HNUZiX21vMSA8LSByYmluZChjdF9ubUc1RmJfbW8xLCBkYXRhLmZyYW1lKEVzdGltYXRlID0gTkEsIExvdz1OQSwgSGlnaD1OQSwgc29wLmNhdGNoPU5BLCBZZWFyPWFzLmludGVnZXIoMjAyNCkpKQ0KYXN1bV9ubUc1RmJfbW8xIDwtIG1lcmdlKHggPSBhc3VtX25tRzVGYl9tbzEsIHkgPSBjdF9ubUc1RmJfbW8xLCBieSA9ICJZZWFyIikNCmNvbG5hbWVzKGFzdW1fbm1HNUZiX21vMSkgPC0gYygiWWVhciIsICJSX2FnZTEiLCAiUmxvdyIsICJSaGlnaCIsICJTU0IiLCAiU1NCbG93IiwgIlNTQmhpZ2giLCAiRmJhciIsICJGbG93IiwgIkZoaWdoIiwgIkNhdGNoRXN0IiwgIkNhdGNobG93IiwgIkNhdGNoaGlnaCIsICJDYXRjaE9icyIpDQojPT09PT0NCmBgYA0KDQojIyBGaXRzIHRvIGRhdGENCldoZW4gdGhlIG1vZGVsIGlzIHJ1biB3ZSBjYW4gZWFzaWx5IHNlZSBmcm9tIHdhcm5pbmdzL2Vycm9ycyBpZiB0aGVyZSBpcyBhIGNvbnZlcmdlbmNlIGlzc3VlLiAgSG93ZXZlciwgd2UgY2FuIGFsc28gY29uZmlybSB0aGlzLCBleHBsaWNpdGx5Og0KDQotIFRoZSBmaW5hbCBtb2RlbCBncmFkaWVudDogYHIgZml0X25tRzVGYl9tbzEkb3B0JGV2YWx1YXRpb25zWzJdYA0KLSBUaGF0IHRoZXJlIGlzIGEgcG9zaXRpdmUgZGVmaW5pdGUgaGVzc2lhbjogYHIgYWxsKGVpZ2VuKGZpdF9ubUc1RmJfbW8xJG9wdCRoZSkkdmFsdWVzID4wKWANCg0KRnVydGhlcm1vcmUsIFNBTSBkb2VzIG5vdCB1dGlsaXNlICJib3VuZHMiIHdoZW4gZml0dGluZyB0aGUgbW9kZWwsIGFuZCB0aGVyZWZvcmUsIGFzIHN0YW5kYXJkIGNoZWNrIG9mIHdoZXRoZXIgbW9kZWwgcGFyYW1ldGVycyBhcmUgYXBwcm9hY2hpbmcgdGhlaXIgYm91bmRzIGlzIGlycmVsZXZhbnQuDQoNCiMjIyBWaXN1YWxpc2UgZml0cyB0byBkYXRhIGJ5IGFnZSBvdmVyIHRpbWUgYWNyb3NzIGZsZWV0cw0KDQpgYGB7ciBmaWcuY2FwPSJNb2RlbCB3aXRoIEFnZTEgbWF0dXJpdHkgc2V0IHRvIHplcm8sIGZpdCB0byBjYXRjaCBkYXRhIGJ5IGFnZSAodmFsdWVzIG9uIHRoZSBtb2RlbCBsaW5rIGZ1bmN0aW9uIHNjYWxlKS4ifQ0KIyMgRXh0cmFjdCBkYXRhIGZyb20gbW9kZWwgb2JqZWN0DQpsb2dPYnNfbm1HNUZiX21vMSA8LSBzcGxpdChmaXRfbm1HNUZiX21vMSRkYXRhJGxvZ29icywgY2VpbGluZyhzZXFfYWxvbmcoZml0X25tRzVGYl9tbzEkZGF0YSRsb2dvYnMpL2ZpdF9ubUc1RmJfbW8xJGRhdGEkbWF4QWdlUGVyRmxlZXRbMV0pKQ0KbG9nUHJlZF9ubUc1RmJfbW8xIDwtIHNwbGl0KGZpdF9ubUc1RmJfbW8xJHJlcCRwcmVkT2JzLCBjZWlsaW5nKHNlcV9hbG9uZyhmaXRfbm1HNUZiX21vMSRyZXAkcHJlZE9icykvZml0X25tRzVGYl9tbzEkZGF0YSRtYXhBZ2VQZXJGbGVldFsxXSkpDQoNCiMjIFRyYW5zZm9ybSBkYXRhIHRvIHVzZWFibGUgZGF0YWZyYW1lcw0KIyMjIEluaXRpYWxpemUgYW4gZW1wdHkgZGF0YSBmcmFtZSBmb3Igb2JzZXJ2YXRpb25zDQpsb2dPYnNfbm1HNUZiX21vMV9kZiA8LSBkYXRhLmZyYW1lKGFnZSA9IGludGVnZXIoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmxlZXQgPSBpbnRlZ2VyKCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllYXIgPSBpbnRlZ2VyKCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZ09icyA9IG51bWVyaWMoKSkNCg0KIyMjIFBvcHVsYXRlIHRoZSBkYXRhIGZyYW1lIGZvciBvYnNlcnZhdGlvbnMNCmZvciAoaSBpbiBzZXFfYWxvbmcobG9nT2JzX25tRzVGYl9tbzEpKSB7DQogICMgQ2FsY3VsYXRlIHRoZSBncm91cCBhbmQgeWVhcg0KICB5ZWFyIDwtICgoaSAtIDEpICUvJSAzKSArIDENCiAgZmxlZXQgPC0gKChpIC0gMSkgJSUgMykgKyAxDQogIA0KICAjIyMgQ3JlYXRlIGEgdGVtcG9yYXJ5IGRhdGEgZnJhbWUgYW5kIGFwcGVuZCB0byB0aGUgbWFpbiBkYXRhIGZyYW1lIGZvciBvYnNlcnZhdGlvbnMNCiAgdGVtcF9kZiA8LSBkYXRhLmZyYW1lKGFnZSA9IDE6NywNCiAgICAgICAgICAgICAgICAgICAgICAgIGZsZWV0ID0gZmxlZXQsDQogICAgICAgICAgICAgICAgICAgICAgICB5ZWFyID0geWVhcisyMDAxLA0KICAgICAgICAgICAgICAgICAgICAgICAgbG9nT2JzID0gbG9nT2JzX25tRzVGYl9tbzFbW2ldXSkNCiAgbG9nT2JzX25tRzVGYl9tbzFfZGYgPC0gcmJpbmQobG9nT2JzX25tRzVGYl9tbzFfZGYsIHRlbXBfZGYpDQp9DQoNCiMjIyBJbml0aWFsaXplIGFuIGVtcHR5IGRhdGEgZnJhbWUgZm9yIHByZWRpY3Rpb25zDQpsb2dQcmVkX25tRzVGYl9tbzFfZGYgPC0gZGF0YS5mcmFtZShhZ2UgPSBpbnRlZ2VyKCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmbGVldCA9IGludGVnZXIoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllYXIgPSBpbnRlZ2VyKCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2dQcmVkID0gbnVtZXJpYygpKQ0KDQojIyMgUG9wdWxhdGUgdGhlIGRhdGEgZnJhbWUgZm9yIHByZWRpY3Rpb25zDQpmb3IgKGkgaW4gc2VxX2Fsb25nKGxvZ1ByZWRfbm1HNUZiX21vMSkpIHsNCiAgIyBDYWxjdWxhdGUgdGhlIGdyb3VwIGFuZCB5ZWFyDQogIHllYXIgPC0gKChpIC0gMSkgJS8lIDMpICsgMQ0KICBmbGVldCA8LSAoKGkgLSAxKSAlJSAzKSArIDENCiAgDQogICMjIyBDcmVhdGUgYSB0ZW1wb3JhcnkgZGF0YSBmcmFtZSBhbmQgYXBwZW5kIHRvIHRoZSBtYWluIGRhdGEgZnJhbWUgZm9yIHByZWRpY3Rpb25zDQogIHRlbXBfZGYgPC0gZGF0YS5mcmFtZShhZ2UgPSAxOjcsDQogICAgICAgICAgICAgICAgICAgICAgICBmbGVldCA9IGZsZWV0LA0KICAgICAgICAgICAgICAgICAgICAgICAgeWVhciA9IHllYXIrMjAwMSwNCiAgICAgICAgICAgICAgICAgICAgICAgIGxvZ1ByZWQgPSBsb2dQcmVkX25tRzVGYl9tbzFbW2ldXSkNCiAgbG9nUHJlZF9ubUc1RmJfbW8xX2RmIDwtIHJiaW5kKGxvZ1ByZWRfbm1HNUZiX21vMV9kZiwgdGVtcF9kZikNCn0NCg0KIyMgUGxvdA0KbG9nUHJlZF9ubUc1RmJfbW8xX2RmJGFnZSA8LSBhcy5jaGFyYWN0ZXIobG9nUHJlZF9ubUc1RmJfbW8xX2RmJGFnZSkNCmxvZ09ic19ubUc1RmJfbW8xX2RmJGFnZSA8LSBhcy5jaGFyYWN0ZXIobG9nT2JzX25tRzVGYl9tbzFfZGYkYWdlKQ0KDQpnZ3Bsb3RseShnZ3Bsb3QoKSsNCiAgICAgICAgICAgZ2VvbV9wb2ludChkYXRhID0gbG9nT2JzX25tRzVGYl9tbzFfZGZbbG9nT2JzX25tRzVGYl9tbzFfZGYkZmxlZXQgPT0gMSAmIGxvZ09ic19ubUc1RmJfbW8xX2RmJHllYXIgIT0gKERhdGFZZWFyKzEpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IHllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gbG9nT2JzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gYWdlKSwNCiAgICAgICAgICAgICAgICAgICAgICBzaGFwZSA9IDIxKSArDQogICAgICAgICAgIGdlb21fbGluZShkYXRhID0gbG9nUHJlZF9ubUc1RmJfbW8xX2RmW2xvZ1ByZWRfbm1HNUZiX21vMV9kZiRmbGVldCA9PSAxICYgbG9nUHJlZF9ubUc1RmJfbW8xX2RmJHllYXIgIT0gKERhdGFZZWFyKzEpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0geWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGxvZ1ByZWQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IGFnZSkpICsNCiAgICAgICAgICAgZmFjZXRfd3JhcChmYWNldHMgPSAiYWdlIikgKyAjLCBzY2FsZXMgPSAiZnJlZV95IikgKw0KICAgICAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gZWJwYWwsIGd1aWRlID0gRkFMU0UpICsNCiAgICAgICAgICAgZ3VpZGVzKGNvbG91cj1GQUxTRSwgc2hhcGU9RkFMU0UpICsNCiAgICAgICAgICAgdGhlbWVfZmV3KCkpDQoNCiMgZml0cGxvdChmaXRfbm1HNUZiX21vMSwgZmxlZXRzPTEpDQpgYGANCg0KYGBge3IgZmlnLmNhcD0iTW9kZWwgd2l0aCBBZ2UxIG1hdHVyaXR5IHNldCB0byB6ZXJvLCBmaXQgdG8gUTEgc3VydmV5IGRhdGEgYnkgYWdlICh2YWx1ZXMgb24gdGhlIG1vZGVsIGxpbmsgZnVuY3Rpb24gc2NhbGUpLiJ9DQpnZ3Bsb3RseShnZ3Bsb3QoKSsNCiAgICAgICAgICAgZ2VvbV9wb2ludChkYXRhID0gbG9nT2JzX25tRzVGYl9tbzFfZGZbbG9nT2JzX25tRzVGYl9tbzFfZGYkZmxlZXQgPT0gMiAmIGxvZ09ic19ubUc1RmJfbW8xX2RmJHllYXIgIT0gKERhdGFZZWFyKzEpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IHllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gbG9nT2JzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gYWdlKSwNCiAgICAgICAgICAgICAgICAgICAgICBzaGFwZSA9IDIxKSArDQogICAgICAgICAgIGdlb21fbGluZShkYXRhID0gbG9nUHJlZF9ubUc1RmJfbW8xX2RmW2xvZ1ByZWRfbm1HNUZiX21vMV9kZiRmbGVldCA9PSAyICYgbG9nUHJlZF9ubUc1RmJfbW8xX2RmJHllYXIgIT0gKERhdGFZZWFyKzEpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0geWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGxvZ1ByZWQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IGFnZSkpICsNCiAgICAgICAgICAgZmFjZXRfd3JhcChmYWNldHMgPSAiYWdlIikgKyAjLCBzY2FsZXMgPSAiZnJlZV95IikgKw0KICAgICAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gZWJwYWwsIGd1aWRlID0gRkFMU0UpICsNCiAgICAgICAgICAgZ3VpZGVzKGNvbG91cj1GQUxTRSwgc2hhcGU9RkFMU0UpICsNCiAgICAgICAgICAgdGhlbWVfZmV3KCkpDQojIGZpdHBsb3QoZml0X25tRzVGYl9tbzEsIGZsZWV0cz0yKQ0KYGBgDQoNCmBgYHtyIGZpZy5jYXA9Ik1vZGVsIHdpdGggQWdlMSBtYXR1cml0eSBzZXQgdG8gemVybywgZml0IHRvIFEzLzQgc3VydmV5IGRhdGEgYnkgYWdlICh2YWx1ZXMgb24gdGhlIG1vZGVsIGxpbmsgZnVuY3Rpb24gc2NhbGUpLiJ9DQpnZ3Bsb3RseShnZ3Bsb3QoKSsNCiAgICAgICAgICAgZ2VvbV9wb2ludChkYXRhID0gbG9nT2JzX25tRzVGYl9tbzFfZGZbbG9nT2JzX25tRzVGYl9tbzFfZGYkZmxlZXQgPT0gMyAmIGxvZ09ic19ubUc1RmJfbW8xX2RmJHllYXIgIT0gKERhdGFZZWFyKzEpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IHllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gbG9nT2JzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gYWdlKSwNCiAgICAgICAgICAgICAgICAgICAgICBzaGFwZSA9IDIxKSArDQogICAgICAgICAgIGdlb21fbGluZShkYXRhID0gbG9nUHJlZF9ubUc1RmJfbW8xX2RmW2xvZ1ByZWRfbm1HNUZiX21vMV9kZiRmbGVldCA9PSAzICYgbG9nUHJlZF9ubUc1RmJfbW8xX2RmJHllYXIgIT0gKERhdGFZZWFyKzEpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0geWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGxvZ1ByZWQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IGFnZSkpICsNCiAgICAgICAgICAgZmFjZXRfd3JhcChmYWNldHMgPSAiYWdlIikgKyAjLCBzY2FsZXMgPSAiZnJlZV95IikgKw0KICAgICAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gZWJwYWwsIGd1aWRlID0gRkFMU0UpICsNCiAgICAgICAgICAgZ3VpZGVzKGNvbG91cj1GQUxTRSwgc2hhcGU9RkFMU0UpICsNCiAgICAgICAgICAgdGhlbWVfZmV3KCkpDQoNCiMgZml0cGxvdChmaXRfbm1HNUZiX21vMSwgZmxlZXRzPTMpDQpgYGANCg0KYGBge3IgZmlnLmNhcD0iU3RhbmRhcmQgRGV2YXRpb25zIGJ5IEZsZWV0OyBBZ2UxIG1hdHVyaXR5IHNldCB0byB6ZXJvLiIsIGhlaWdodD0xMH0NCnNkcGxvdChmaXRfbm1HNUZiX21vMSwgbWFyZyA9IGMoNSw0LDEsMSkpDQpgYGANCg0KIyMjIFJlc2lkdWFscw0KYGBge3IgY2FsY3VsYXRlUmVzaWR1YWxzX25tRzVGYl9tbzEsIHdhcm5pbmc9RkFMU0UsIHJlc3VsdHM9J2hpZGUnfQ0KcmVzaWRfbm1HNUZiX21vMSA8LSByZXNpZHVhbHMoZml0X25tRzVGYl9tbzEpDQpyZXNpZF9ubUc1RmJfbW8xX2RmIDwtIGRhdGEuZnJhbWUoeWVhciA9IHJlc2lkX25tRzVGYl9tbzEkeWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmbGVldCA9IHJlc2lkX25tRzVGYl9tbzEkZmxlZXQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWdlID0gcmVzaWRfbm1HNUZiX21vMSRhZ2UsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb2JzZXJ2YXRpb24gPSByZXNpZF9ubUc1RmJfbW8xJG9ic2VydmF0aW9uLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1lYW4gPSByZXNpZF9ubUc1RmJfbW8xJG1lYW4sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzaWR1YWwgPSByZXNpZF9ubUc1RmJfbW8xJHJlc2lkdWFsKQ0KcmVzaWRfbm1HNUZiX21vMV9kZiRmbGVldE5hbWUgPC0gaWZlbHNlKHJlc2lkX25tRzVGYl9tbzFfZGYkZmxlZXQgPT0gMSwgYXR0cmlidXRlcyhyZXNpZF9ubUc1RmJfbW8xKSRmbGVldE5hbWVzWzFdLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UocmVzaWRfbm1HNUZiX21vMV9kZiRmbGVldCA9PSAyLCBhdHRyaWJ1dGVzKHJlc2lkX25tRzVGYl9tbzEpJGZsZWV0TmFtZXNbMl0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UocmVzaWRfbm1HNUZiX21vMV9kZiRmbGVldCA9PSAzLCBhdHRyaWJ1dGVzKHJlc2lkX25tRzVGYl9tbzEpJGZsZWV0TmFtZXNbM10sIE5BKSkpDQoNCnJlc2lkX25tRzVGYl9tbzFfZGYkZmxlZXRBbHROYW1lIDwtIGlmZWxzZShyZXNpZF9ubUc1RmJfbW8xX2RmJGZsZWV0ID09IDEsICJSZXNpZHVhbCBGaXNoaW5nIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKHJlc2lkX25tRzVGYl9tbzFfZGYkZmxlZXQgPT0gMiwgIlExIFN1cnZleXMiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKHJlc2lkX25tRzVGYl9tbzFfZGYkZmxlZXQgPT0gMywgIlEzLzQgU3VydmV5cyIsIE5BKSkpDQpgYGANCg0KYGBge3IgZmlnLmNhcD0iRXN0aW1hdGVkIGNvcnJlbGF0aW9ucyBpbiByZXNpZHVhbCB2YXJpYXRpb24gYmV0d2VlbiBhZ2VzIGZvciBlYWNoIG9mIHRoZSBmaXNoaW5nIGZsZWV0ICh0b3ApIGFuZCB0aGUgdHdvIHN1cnZleXMgKG1pZGRsZSAmIGJvdHRvbSksIGZyb20gdGhlIE1vZGVsIHdpdGggdGltZSB2YXJ5aW5nIChmaXZlIHllYXIgc2xpaWRpbmcgd2luZG93IG1lYW4pLCBhZ2UgdmFyeWluZywgR2lzbGFzb24gbmF0dXJhbCBtb3J0YWxpdGllcyAoRmlzaEJhc2UpLiJ9DQoNCmlmKCFhbGwoZml0X25tRzVGYl9tbzEkY29uZiRvYnNDb3JTdHJ1Y3Q9PSJJRCIpKXsgDQogIGNvcnBsb3QoZml0X25tRzVGYl9tbzEpCQkJICANCiAgIyBzZXRjYXAoIkVzdGltYXRlZCBjb3JyZWxhdGlvbnMiLCAiRXN0aW1hdGVzIGNvcnJlbGF0aW9ucyBiZXR3ZWVuIGFnZSBncm91cHMgZm9yIGVhY2ggZmxlZXQiKQ0KICAjIHN0YW1waXQoZml0KQ0KfSBlbHNlIHsNCiAgcHJpbnQoIk5vIGNvcnJlbGF0aW9uIHN0cnVjdHVyZSBjb25maWd1cmVkIGZvciByZXNpZHVhbHMgYWNyb3NzIGFnZS4iKQ0KfQ0KDQpgYGANCg0KYGBge3IgZmlnLmNhcD0iT25lIG9ic2VydmF0aW9uIGFoZWFkIHJlc2lkdWFscyBmb3IgdGhlIHRocmVlIGZsZWV0cyAocmVkL3BpbmsgPSBvYnNlcnZhdGlvbiBsb3dlciB0aGFuIG1vZGVsIGVzdGltYXRlLCBibHVlID0gb2JzZXJ2YXRpb24gaGlnaGVyIHRoYW4gbW9kZWwgZXN0aW1hdGUsIHNpemUgPSBtYWduaXR1ZGUgb2YgcmVzaWR1YWwpLCBmcm9tIHRoZSBNb2RlbCB3aXRoIGFnZTEgbWF0dXJpdGllcyBzZXQgdG8gemVyby4ifQ0KZ2dwbG90bHkoZ2dwbG90KHJlc2lkX25tRzVGYl9tbzFfZGYpICsNCiAgICAgICAgICAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSB5ZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGFnZSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSBhYnMocmVzaWR1YWwpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gcmVzaWR1YWwgPj0gMCksDQogICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjcpICsNCiAgICAgICAgICAgZmFjZXRfZ3JpZChyb3dzID0gImZsZWV0QWx0TmFtZSIpICsNCiAgICAgICAgICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCJUUlVFIiA9IGVicGFsWzhdLCAiRkFMU0UiID0gZWJwYWxbOV0pKSArDQogICAgICAgICAgIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKC0xLCA5KSwgYnJlYWtzID0gYygxOjkpKSArDQogICAgICAgICAgIGd1aWRlcyhjb2xvdXI9RkFMU0UpICsNCiAgICAgICAgICAgdGhlbWVfZmV3KCkpDQoNCmBgYA0KDQojIyMgSml0dGVyaW5nDQpXZSBjYW4gYWxzbyB0ZXN0IHRvIHNlZSBpZiB0aGUgbW9kZWwgaXMgY29udmVyZ2luZyBvbiBzb21lIGxvY2FsIG1pbmltdW0gKGkuZS4gaXQncyBmaXR0aW5nIHRvIHNvbWUgc29sdXRpb24gY2xvc2UgdG8gaW5pdGlhbGlzaW5nIHZhbHVlcyB0aGF0IHJlcHJlc2VudHMgbm9pc2UgYW5kIG5vdCB0aGUgZ2xvYmFsIHNvbHV0aW9uLCB0aGF0IGlzIHRoZSBwcm9wZXIgc29sdXRpb24pLiAgVG8gZG8gdGhpcywgd2UgYWRkIHJhbmRvbSBub2lzZSB0byB0aGUgaW5pdGlhbCBwYXJhbWV0ZXIgdmFsdWVzIHRvIHNlZSBpZiB0aGUgbW9kZWwgd2lsbCBjb252ZXJnZSBvbiBhIGRpZmZlcmVudCBtaW5pbXVtIGluIGl0J3MgZGF0YS1zcGFjZS4gVGhlIGVhc2llc3Qgd2F5IHRvIGludmVzdGlnYXRlIHRoaXMgaXMgdG8gc2VlIGlmIHRoZSBtb2RlbCBmaXRzIHZhcnkgYWxvdCBkZXBlbmRpbmcgb24gdGhlIHN0YXJ0aW5nIHZhbHVlczoNCmBgYHtyIEppdHRlcl9ubUc1RmJfbW8xfQ0Kaml0X25tRzVGYl9tbzEgPC0gaml0KGZpdCA9IGZpdF9ubUc1RmJfbW8xKQ0KDQptdCA8LSBhcy5kYXRhLmZyYW1lKG1vZGVsdGFibGUoaml0X25tRzVGYl9tbzEpKQ0KbXQkbW9kZWwgPC0gcm93bmFtZXMobXQpDQpyb3duYW1lcyhtdCkgPC0gTlVMTA0KDQprYWJsZSh4ID0gbXQsDQogICAgICBkaWdpdHMgPSAzLA0KICAgICAgY2FwdGlvbiA9ICJNZWFzdXJlcyBvZiAgZml0IGZvciBhIHNlcmllcyBvZiBtb2RlbCByZWZpdHMgd2l0aCBqaXR0ZXIgYXBwbGllZCB0byB0aGUgaW5wdXQgcGFyYW1ldGVycy4iKQ0KYGBgDQoNCiMjIyBMZWF2ZS1PbmUtT3V0IEFuYWx5c2VzDQpBIGxlYXZlLW9uZS1vdXQgYW5hbHlzaXMgaXMgYSBmb3JtIG9mIHNlbnNpdGl2aXR5IGFuYWx5c2lzLCBzaG93aW5nIHRoZSBpbXBhY3QgdGhlIGRhdGEgZnJvbSBlYWNoIHR1bmluZyBmbGVldCBoYXMgb24gdGhlIGVzdGltYXRpb24gb2YgdGhlIGtleSB2YXJpYWJsZXMgYmVpbmcgZXN0aW1hdGVkOyBuYW1lbHkgU1NCLCBGIGFuZCByZWNydWl0bWVudC4gIA0KDQpGaXJzdCB3ZSBtdXN0IHJ1biB0aGUgbGVhdmUtb25lLW91dCBhbmFseXNpcyB3aGljaCByZWZpdHMgdGhlIG1vZGVsIGluIHR3byBpdGVyYXRpb25zLCByZW1vdmluZyBvbmUgc3VydmV5IGF0IGEgdGltZS4gVGhlbiB3ZSBjYW4gcGxvdCBlYWNoIG9mIHRoZXNlIG5ldyBtb2RlbCBmaXRzIG92ZXIgdGhlIGZ1bGwgbW9kZWwgdG8gc2VlIHRoZSBpbXBhY3QgdGhlIHJlbW92YWwgb2YgZWFjaCBoYXMuIA0KDQpgYGB7ciBMZWF2ZU9uZU91dF9ubUc1RmJfbW8xfQ0KTE9fbm1HNUZiX21vMSA8LSBsZWF2ZW91dChmaXRfbm1HNUZiX21vMSkNCg0KIz09PSANCiMgR2V0IGRhdGEgZnJvbSBzYW0gb2JqZWN0cyBhbmQgZ2VuZXJhdGUgdXNlYWJsZSBkYXRhZnJhbWVzDQojPT09PQ0KcTFtYXQgPC0gYXMuZGF0YS5mcmFtZShzdW1tYXJ5KExPX25tRzVGYl9tbzEkYHcuby4gUTFJQlRTK0JJVFMrQ29kU0QyMS0yNWApKQ0KcTNtYXQgPC0gYXMuZGF0YS5mcmFtZShzdW1tYXJ5KExPX25tRzVGYl9tbzEkYHcuby4gUTM0SUJUUytCSVRTK0NvZFNEMjEtMjVgKSkNCg0KDQp3b3ExIDwtIGRhdGEuZnJhbWUoWWVhciA9IGFzLmludGVnZXIocm93Lm5hbWVzKHN1bW1hcnkoTE9fbm1HNUZiX21vMSRgdy5vLiBRMUlCVFMrQklUUytDb2RTRDIxLTI1YCkpKSwNCiAgICAgICAgICAgICAgICAgICBTU0IgPSBxMW1hdCRTU0IsDQogICAgICAgICAgICAgICAgICAgRmJhciA9IHExbWF0JGBGYmFyKDMtNSlgLA0KICAgICAgICAgICAgICAgICAgIFJfYWdlMSA9IHExbWF0JGBSKGFnZSAxKWAsDQogICAgICAgICAgICAgICAgICAgQ2F0Y2hFc3QgPSBjYXRjaHRhYmxlKExPX25tRzVGYl9tbzEkYHcuby4gUTFJQlRTK0JJVFMrQ29kU0QyMS0yNWApWywxXSwNCiAgICAgICAgICAgICAgICAgICBzZXJpZXMgPSByZXAoIndvX1ExIiwgdGltZXMgPSBucm93KHExbWF0KSkpDQoNCndvcTM0IDwtIGRhdGEuZnJhbWUoWWVhciA9IGFzLmludGVnZXIocm93Lm5hbWVzKHEzbWF0WygyMDAyOkRhdGFZZWFyKS0yMDAxLF0pKSwNCiAgICAgICAgICAgICAgICAgICAgU1NCID0gcTNtYXRbKDIwMDI6RGF0YVllYXIpLTIwMDEsICJTU0IiXSwNCiAgICAgICAgICAgICAgICAgICAgRmJhciA9IHEzbWF0WygyMDAyOkRhdGFZZWFyKS0yMDAxLCJGYmFyKDMtNSkiXSwNCiAgICAgICAgICAgICAgICAgICAgUl9hZ2UxID0gcTNtYXRbKDIwMDI6RGF0YVllYXIpLTIwMDEsIlIoYWdlIDEpIl0sDQogICAgICAgICAgICAgICAgICAgIENhdGNoRXN0ID0gY2F0Y2h0YWJsZShMT19ubUc1RmJfbW8xJGB3Lm8uIFEzNElCVFMrQklUUytDb2RTRDIxLTI1YClbLDFdLA0KICAgICAgICAgICAgICAgICAgICBzZXJpZXMgPSByZXAoIndvX1EzNCIsIHRpbWVzID0gKG5yb3cocTNtYXQpLTEpKSkNCg0KDQphc3VtX25tRzVGYl9tbzEkc2VyaWVzIDwtIHJlcCgiZnVsbCIsIHRpbWVzID0gbnJvdyhhc3VtX25tRzVGYl9tbzEpKQ0KYXN1bWlfbm1HNUZiX21vMSA8LSBhc3VtX25tRzVGYl9tbzFbLCBjKCJZZWFyIiwgIlNTQiIsICJGYmFyIiwgIlJfYWdlMSIsICJDYXRjaEVzdCIgLCJzZXJpZXMiKV0NCiM9PT09PQ0KDQpsb3N1bV9ubUc1RmJfbW8xIDwtIHJiaW5kKHdvcTEsIHdvcTM0LCBhc3VtaV9ubUc1RmJfbW8xKQ0KDQpgYGANCg0KYGBge3IgZmlnLmNhcD0iTGVhdmUtb25lLW91dCByZS1maXRzIGZvciB0aGUgbW9kZWwgd2l0aCBhZ2UxIG1hdHVyaXRpZXMgc2V0IHRvIHplcm8gKHdpdGhvdXQgUTEgc3VydmV5ID0gYmx1ZSwgd2l0aG91dCBRMy80IHN1cnZleSA9IHB1cnBsZSksIG92ZXJsYWluIHdpdGggZnVsbCBtb2RlbCBlc3RpbWF0ZXMgKGJsYWNrIGxpbmUgYW5kIGdyZXkgcmliYm9uKSBvZiBTU0IgKHRvcCBsZWZ0KSwgRiAodG9wIHJpZ2h0KSwgUmVjcnVpdG1lbnQgKGJvdHRvbSBsZWZ0KSwgYW5kIGNhdGNoIChib3R0b20gcmlnaHQ7IG9ic2VydmF0aW9ucyBhcyB5ZWxsb3cgKykuIn0NCiMgc3NicGxvdChMTykNCmxvc3NiX25tRzVGYl9tbzEgPC0gZ2dwbG90bHkoZ2dwbG90KCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fbGluZShkYXRhID0gbG9zdW1fbm1HNUZiX21vMSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1TU0IsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gc2VyaWVzKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fcmliYm9uKGRhdGEgPSBhc3VtX25tRzVGYl9tbzEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWluPVNTQmxvdywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltYXg9U1NCaGlnaCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9ICJibGFjayIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjIpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoImJsYWNrIiwgZWJwYWxbODo5XSkpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9jbGVhbigpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZShheGlzLnRpdGxlLnkubGVmdCA9IGVsZW1lbnRfdGV4dCh2anVzdCA9IC0wLjA1LCBoanVzdCA9IDAuOTUpKSkNCg0KIyBGcGxvdChMTykNCmxvZl9ubUc1RmJfbW8xIDwtIGdncGxvdGx5KGdncGxvdCgpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9saW5lKGRhdGEgPSBsb3N1bV9ubUc1RmJfbW8xLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9RmJhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gc2VyaWVzKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3JpYmJvbihkYXRhID0gYXN1bV9ubUc1RmJfbW8xLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWluPUZsb3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1heD1GaGlnaCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSAiYmxhY2siLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMykgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoImJsYWNrIiwgZWJwYWxbODo5XSkpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWVfY2xlYW4oKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKGF4aXMudGl0bGUueS5sZWZ0ID0gZWxlbWVudF90ZXh0KHZqdXN0ID0gLTAuMDUsIGhqdXN0ID0gMC45NSkpKQ0KDQojIHJlY3Bsb3QoTE8pDQpsb3JlY19ubUc1RmJfbW8xIDwtIGdncGxvdGx5KGdncGxvdCgpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IGxvc3VtX25tRzVGYl9tbzEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9Ul9hZ2UxLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IHNlcmllcykpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3JpYmJvbihkYXRhID0gYXN1bV9ubUc1RmJfbW8xLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1pbj1SbG93LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1heD1SaGlnaCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9ICJibGFjayIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjMpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoImJsYWNrIiwgZWJwYWxbODo5XSkpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9jbGVhbigpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZShheGlzLnRpdGxlLnkubGVmdCA9IGVsZW1lbnRfdGV4dCh2anVzdCA9IC0wLjA1LCBoanVzdCA9IDAuOTUpKSkNCg0KIyBDYXRjaCBwbG90IChMTykNCmxvY2Ffbm1HNUZiX21vMSA8LSBnZ3Bsb3RseShnZ3Bsb3QoKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IGxvc3VtX25tRzVGYl9tbzEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PUNhdGNoRXN0LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gc2VyaWVzKSkrDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3JpYmJvbihkYXRhID0gYXN1bV9ubUc1RmJfbW8xW2FzdW1fbm1HNUZiX21vMSRZZWFyICE9IChEYXRhWWVhcisxKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWluPUNhdGNobG93LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4PUNhdGNoaGlnaCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gImJsYWNrIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4zKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3BvaW50KGRhdGEgPSBhc3VtX25tRzVGYl9tbzFbYXN1bV9ubUc1RmJfbW8xJFllYXIgIT0gKERhdGFZZWFyKzEpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PUNhdGNoT2JzKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hhcGUgPSAzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBlYnBhbFs1XSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IGVicGFsWzVdKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bGFiKCJDYXRjaCAodG9ubmVzKSIpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiYmxhY2siLCBlYnBhbFs4OjldKSkrIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWVfY2xlYW4oKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZShheGlzLnRpdGxlLnkubGVmdCA9IGVsZW1lbnRfdGV4dCh2anVzdCA9IC0wLjA1LCBoanVzdCA9IDAuOTUpKSkNCg0KbGF5b3V0KHN1YnBsb3QobG9zc2Jfbm1HNUZiX21vMSwgbG9mX25tRzVGYl9tbzEsIGxvcmVjX25tRzVGYl9tbzEsIGxvY2Ffbm1HNUZiX21vMSwgbnJvd3MgPSAyLCBzaGFyZVggPSBUUlVFLCB0aXRsZVkgPSBUUlVFKSwgc2hvd2xlZ2VuZD1GQUxTRSkNCmBgYA0KDQojIyMgUmV0cm9zcGVjdGl2ZXMNCmBgYHtyIGNhbGN1bGF0ZVJldHJvc19ubUc1RmJfbW8xfQ0KIz09PQ0KIyBDcmVhdGUgZGF0YWZyYW1lIG9mIGN1cnJlbnQgeWVhcidzIGZpdCBmb3IgcGxvdHRpbmcNCiM9PT09DQojIElDX2FnZ190ZW1wIDwtIGFnZ3JlZ2F0ZShDQVRPTn5ZZWFyLCBpY19jbGVhbltpY19jbGVhbiRDYXRjaENhdGVnb3J5ICVpbiUgYygiTGFuZGluZ3MiLCAiRGlzY2FyZHMiKSwgXSwgRlVOID0gInN1bSIpDQphc3VtX25tRzVGYl9tbzEgPC0gYXMuZGF0YS5mcmFtZShzdW1tYXJ5KGZpdF9ubUc1RmJfbW8xKSkNCmFzdW1fbm1HNUZiX21vMSRZZWFyIDwtIGFzLmludGVnZXIocm93Lm5hbWVzKHN1bW1hcnkoZml0X25tRzVGYl9tbzEpKSkNCmN0X25tRzVGYl9tbzEgPC0gYXMuZGF0YS5mcmFtZShjYXRjaHRhYmxlKGZpdF9ubUc1RmJfbW8xLCBvYnMuc2hvdyA9IFRSVUUpKQ0KY3Rfbm1HNUZiX21vMSRZZWFyIDwtIGFzLmludGVnZXIocm93bmFtZXMoY3Rfbm1HNUZiX21vMSkpDQpyb3duYW1lcyhjdF9ubUc1RmJfbW8xKSA8LSBOVUxMDQpjdF9ubUc1RmJfbW8xIDwtIHJiaW5kKGN0X25tRzVGYl9tbzEsIGRhdGEuZnJhbWUoRXN0aW1hdGUgPSBOQSwgTG93PU5BLCBIaWdoPU5BLCBzb3AuY2F0Y2g9TkEsIFllYXI9YXMuaW50ZWdlcigyMDI0KSkpDQphc3VtX25tRzVGYl9tbzEgPC0gbWVyZ2UoeCA9IGFzdW1fbm1HNUZiX21vMSwgeSA9IGN0X25tRzVGYl9tbzEsIGJ5ID0gIlllYXIiKQ0KY29sbmFtZXMoYXN1bV9ubUc1RmJfbW8xKSA8LSBjKCJZZWFyIiwgIlJfYWdlMSIsICJSbG93IiwgIlJoaWdoIiwgIlNTQiIsICJTU0Jsb3ciLCAiU1NCaGlnaCIsICJGYmFyIiwgIkZsb3ciLCAiRmhpZ2giLCAiQ2F0Y2hFc3QiLCAiQ2F0Y2hsb3ciLCAiQ2F0Y2hoaWdoIiwgIkNhdGNoT2JzIikNCg0KYXN1bV9ubUc1RmJfbW8xJHNlcmllcyA8LSByZXAoImZ1bGwiLCB0aW1lcyA9IG5yb3coYXN1bV9ubUc1RmJfbW8xKSkNCg0KIz09PT09DQpSRVRST19ubUc1RmJfbW8xPC1yZXRybyhmaXRfbm1HNUZiX21vMSwgeWVhcj01KQ0KcmhvX25tRzVGYl9tbzEgPC0gbW9obihSRVRST19ubUc1RmJfbW8xLCBsYWcgPSAxKQ0KDQojIyBNYWtlIFJFVFJPcyBpbiBiZXR0ZXIgcGxvdHRpbmcgZm9ybWF0DQpyZXRfbm1HNUZiX21vMV9kZiA8LSBhc3VtX25tRzVGYl9tbzFbYXN1bV9ubUc1RmJfbW8xJFllYXIgIT0gbWF4KGFzdW1fbm1HNUZiX21vMSRZZWFyKSwgXQ0KDQpmb3IoaSBpbiAxOmxlbmd0aChSRVRST19ubUc1RmJfbW8xKSl7DQogIHRzdW0gPC0gYXMuZGF0YS5mcmFtZShzdW1tYXJ5KFJFVFJPX25tRzVGYl9tbzFbW2ldXSkpDQogIHRzdW0kWWVhciA8LSBhcy5pbnRlZ2VyKHJvdy5uYW1lcyhzdW1tYXJ5KFJFVFJPX25tRzVGYl9tbzFbW2ldXSkpKQ0KICB0c3VtIDwtIGNiaW5kKHRzdW0sIGNhdGNodGFibGUoUkVUUk9fbm1HNUZiX21vMVtbaV1dLCBvYnMuc2hvdyA9IFRSVUUpKQ0KICB0c3VtJHNlcmllcyA8LSBhcy5jaGFyYWN0ZXIocmVwKGksIG5yb3codHN1bSkpKQ0KICBjb2xuYW1lcyh0c3VtKSA8LSBjKCJSX2FnZTEiLCAiUmxvdyIsICJSaGlnaCIsICJTU0IiLCAiU1NCbG93IiwgIlNTQmhpZ2giLCAiRmJhciIsICJGbG93IiwgIkZoaWdoIiwgIlllYXIiLCAiQ2F0Y2hFc3QiLCAiQ2F0Y2hsb3ciLCAiQ2F0Y2hoaWdoIiwgIkNhdGNoT2JzIiwgInNlcmllcyIpDQogIHRzdW0gPC0gdHN1bVt0c3VtJFllYXIgIT0gbWF4KHRzdW0kWWVhciksIF0NCiAgcmV0X25tRzVGYl9tbzFfZGYgPC0gcmJpbmQocmV0X25tRzVGYl9tbzFfZGYsIHRzdW0pDQp9DQpyZXRfbm1HNUZiX21vMV9kZiRzZXJpZXMgPC0gZmFjdG9yKHJldF9ubUc1RmJfbW8xX2RmJHNlcmllcywgbGV2ZWxzID0gYygiZnVsbCIsICIxIiwgIjIiLCAiMyIsICI0IiwgIjUiKSkNCmBgYA0KDQpgYGB7ciBmaWcuY2FwPSJSZXRyb3NwZWN0aXZlIGFuYWx5c2VzIGZvciBTU0IgKHRvcC1sZWZ0KSwgRiBmb3IgYWdlcyAzLTUgKHRvcC1yaWdodCksIHJlY3J1aXRtZW50IChib3R0b20tbGVmdCksIGFuZCBjYXRjaCAoYm90dG9tLXJpZ2h0KSwgZnJvbSB0aGUgbW9kZWwgd2l0aCBhZ2UxIG1hdHVyaXRpZXMgc2V0IHRvIHplcm8uIn0NCiMgc3NicGxvdChSRVRSTykNCnJldHNzYl9ubUc1RmJfbW8xIDwtIGxheW91dChnZ3Bsb3RseShnZ3Bsb3QoKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IHJldF9ubUc1RmJfbW8xX2RmLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1TU0IsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBzZXJpZXMpKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3JpYmJvbihkYXRhID0gYXN1bV9ubUc1RmJfbW8xW2FzdW1fbm1HNUZiX21vMSRZZWFyICE9IG1heChhc3VtX25tRzVGYl9tbzEkWWVhciksIF0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1pbj1TU0Jsb3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltYXg9U1NCaGlnaCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gImJsYWNrIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4yKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbm5vdGF0ZShnZW9tID0gInRleHQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IG1heChyZXRfbm1HNUZiX21vMV9kZiRTU0JoaWdoKSowLjg1LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeCA9ICgobWF4KHJldF9ubUc1RmJfbW8xX2RmJFllYXIpLW1pbihyZXRfbm1HNUZiX21vMV9kZiRZZWFyKSkqMC4yMCkrbWluKHJldF9ubUc1RmJfbW8xX2RmJFllYXIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSBwYXN0ZTAoIk1vaG4ncyBSaG8gPSAiLCByb3VuZChyaG9fbm1HNUZiX21vMVsyXSwgZGlnaXRzID0gMykpKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoImJsYWNrIiwgZWJwYWxbKGxlbmd0aChlYnBhbCktNCk6bGVuZ3RoKGVicGFsKV0pKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9jbGVhbigpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF4aXMudGl0bGUueS5sZWZ0ID0gZWxlbWVudF90ZXh0KHZqdXN0ID0gLTAuMDUsIGhqdXN0ID0gMC45NSkpKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaG93bGVnZW5kID0gRkFMU0UpDQoNCiMgRnBsb3QoUkVUUk8pDQpyZXRmX25tRzVGYl9tbzEgPC0gbGF5b3V0KGdncGxvdGx5KGdncGxvdCgpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IHJldF9ubUc1RmJfbW8xX2RmLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PUZiYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gc2VyaWVzKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fcmliYm9uKGRhdGEgPSBhc3VtX25tRzVGYl9tbzFbYXN1bV9ubUc1RmJfbW8xJFllYXIgIT0gbWF4KGFzdW1fbm1HNUZiX21vMSRZZWFyKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW49RmxvdywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltYXg9RmhpZ2gpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSAiYmxhY2siLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4zKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYW5ub3RhdGUoZ2VvbSA9ICJ0ZXh0IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gbWF4KHJldF9ubUc1RmJfbW8xX2RmJEZoaWdoKSowLjg1LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHggPSAoKG1heChyZXRfbm1HNUZiX21vMV9kZiRZZWFyKS1taW4ocmV0X25tRzVGYl9tbzFfZGYkWWVhcikpKjAuODApK21pbihyZXRfbm1HNUZiX21vMV9kZiRZZWFyKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbCA9IHBhc3RlMCgiTW9obidzIFJobyA9ICIsIHJvdW5kKHJob19ubUc1RmJfbW8xWzNdLCBkaWdpdHMgPSAzKSkpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoImJsYWNrIiwgZWJwYWxbKGxlbmd0aChlYnBhbCktNCk6bGVuZ3RoKGVicGFsKV0pKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWVfY2xlYW4oKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF4aXMudGl0bGUueS5sZWZ0ID0gZWxlbWVudF90ZXh0KHZqdXN0ID0gLTAuMDUsIGhqdXN0ID0gMC45NSkpKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgc2hvd2xlZ2VuZCA9IEZBTFNFKQ0KDQojIHJlY3Bsb3QoUkVUUk8pDQpyZXRyZWNfbm1HNUZiX21vMSA8LSBsYXlvdXQoZ2dwbG90bHkoZ2dwbG90KCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9saW5lKGRhdGEgPSByZXRfbm1HNUZiX21vMV9kZiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9Ul9hZ2UxLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gc2VyaWVzKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9yaWJib24oZGF0YSA9IGFzdW1fbm1HNUZiX21vMVthc3VtX25tRzVGYl9tbzEkWWVhciAhPSBtYXgoYXN1bV9ubUc1RmJfbW8xJFllYXIpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW49UmxvdywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1heD1SaGlnaCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gImJsYWNrIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4zKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbm5vdGF0ZShnZW9tID0gInRleHQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT0gbWF4KHJldF9ubUc1RmJfbW8xX2RmJFJoaWdoKSowLjg1LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeCA9ICgobWF4KHJldF9ubUc1RmJfbW8xX2RmJFllYXIpLW1pbihyZXRfbm1HNUZiX21vMV9kZiRZZWFyKSkqMC4yMCkrbWluKHJldF9ubUc1RmJfbW8xX2RmJFllYXIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSBwYXN0ZTAoIk1vaG4ncyBSaG8gPSAiLCByb3VuZChyaG9fbm1HNUZiX21vMVsxXSwgZGlnaXRzID0gMykpKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoImJsYWNrIiwgZWJwYWxbKGxlbmd0aChlYnBhbCktNCk6bGVuZ3RoKGVicGFsKV0pKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9jbGVhbigpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF4aXMudGl0bGUueS5sZWZ0ID0gZWxlbWVudF90ZXh0KHZqdXN0ID0gLTAuMDUsIGhqdXN0ID0gMC45NSkpKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaG93bGVnZW5kID0gRkFMU0UpDQoNCiMgQ2F0Y2ggcGxvdCAoUkVUUk8pDQpyZXRjYV9ubUc1RmJfbW8xIDwtIGdncGxvdGx5KGdncGxvdCgpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IHJldF9ubUc1RmJfbW8xX2RmLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PUNhdGNoRXN0LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IHNlcmllcykpKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fcmliYm9uKGRhdGEgPSBhc3VtX25tRzVGYl9tbzFbYXN1bV9ubUc1RmJfbW8xJFllYXIgIT0gbWF4KGFzdW1fbm1HNUZiX21vMSRZZWFyKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW49Q2F0Y2hsb3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4PUNhdGNoaGlnaCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9ICJibGFjayIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjMpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3BvaW50KGRhdGEgPSBhc3VtX25tRzVGYl9tbzFbYXN1bV9ubUc1RmJfbW8xJFllYXIgIT0gbWF4KGFzdW1fbm1HNUZiX21vMSRZZWFyKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PUNhdGNoT2JzKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNoYXBlID0gMywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IGVicGFsWzVdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IGVicGFsWzVdKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeWxhYigiQ2F0Y2ggKHRvbm5lcykiKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCJibGFjayIsIGVicGFsWyhsZW5ndGgoZWJwYWwpLTQpOmxlbmd0aChlYnBhbCldKSkrIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2NsZWFuKCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKGF4aXMudGl0bGUueS5sZWZ0ID0gZWxlbWVudF90ZXh0KHZqdXN0ID0gLTAuMDUsIGhqdXN0ID0gMC45NSkpKQ0KDQpyZXRfZnAgPC0gc3R5bGUoc3VicGxvdChyZXRzc2Jfbm1HNUZiX21vMSwgcmV0Zl9ubUc1RmJfbW8xLCByZXRyZWNfbm1HNUZiX21vMSwgcmV0Y2Ffbm1HNUZiX21vMSwgbnJvd3MgPSAyLCBzaGFyZVggPSBGQUxTRSwgc2hhcmVZID0gRkFMU0UsIHRpdGxlWSA9IFRSVUUpLA0KICAgICAgICAgICAgICAgIHNob3dsZWdlbmQ9RkFMU0UsDQogICAgICAgICAgICAgICAgdHJhY2VzID0gYyg4OigoNyo0KSsyKSkpDQoNCmxheW91dChyZXRfZnAsIGxlZ2VuZCA9IGxpc3Qob3JpZW50YXRpb24gPSAnaCcsIHggPSAwLjUsIHhhbmNob3IgPSAnY2VudGVyJywgeSA9IC0wLjA1LCB5YW5jaG9yID0gJ3RvcCcsIGJvcmRlcndpZHRoID0gMCkpDQpgYGANCg0KIyMgU2ltU3R1ZHkNCg0KYGBge3Igc2ltc3R1ZHlfbm1HNUZiX21vMSwgfQ0Kc3Nfbm1HNUZiX21vMSA8LSBzaW1zdHVkeShmaXQgPSBmaXRfbm1HNUZiX21vMSwgbnNpbSA9IDEwKQ0KDQoNCmBgYA0KDQoNCiMgRGlzY2FyZCBTdXJ2aXZhbA0KDQojIyBMb3cgRGlzY2FyZCBTdXJ2aXZhbCBFc3RpbWF0ZXMNCg0KVGhpcyBtb2RlbCBpcyBjYWxsZWQgW3BsZS4yNy4yMS0zMl9XS0JQTEFJQ0VfMjAyNF9ubUc1RmJfbW8xX2RzbG93XShodHRwczovL3N0b2NrYXNzZXNzbWVudC5vcmcvc2V0U3RvY2sucGhwP3N0b2NrPXBsZS4yNy4yMS0zMl9XS0JQTEFJQ0VfMjAyNF9ubUc1RmJfbW8xX2RzbG93KSBhbmQgY2FuIGJlIGZvdW5kIG9uIFtzdG9ja2Fzc2Vzc21lbnQub3JnXShodHRwczovL3N0b2NrYXNzZXNzbWVudC5vcmcpLiANCg0KYGBge3Igbm1HNUZiX21vMV9kc2xvd0ZpdEZyb21XZWJ9DQpmaXRfbm1HNUZiX21vMV9kc2xvdyA8LSBmaXRmcm9td2ViKCJwbGUuMjcuMjEtMzJfV0tCUExBSUNFXzIwMjRfbm1HNUZiX21vMV9kc2xvdyIpDQpgYGANCg0KYGBge3IgZGF0YWZyYW1lU3VtbWFyeV9ubUc1RmJfbW8xX2RzbG93LCByZXN1bHRzPSdoaWRlJywgZmlnLnNob3c9J2hpZGUnfQ0KIz09PQ0KIyBDcmVhdGUgZGF0YWZyYW1lIG9mIGN1cnJlbnQgeWVhcidzIGZpdCBmb3IgcGxvdHRpbmcNCiM9PT09DQphc3VtX25tRzVGYl9tbzFfZHNsb3cgPC0gYXMuZGF0YS5mcmFtZShzdW1tYXJ5KGZpdF9ubUc1RmJfbW8xX2RzbG93KSkNCmFzdW1fbm1HNUZiX21vMV9kc2xvdyRZZWFyIDwtIGFzLmludGVnZXIocm93Lm5hbWVzKHN1bW1hcnkoZml0X25tRzVGYl9tbzFfZHNsb3cpKSkNCmN0X25tRzVGYl9tbzFfZHNsb3cgPC0gYXMuZGF0YS5mcmFtZShjYXRjaHRhYmxlKGZpdF9ubUc1RmJfbW8xX2RzbG93LCBvYnMuc2hvdyA9IFRSVUUpKQ0KY3Rfbm1HNUZiX21vMV9kc2xvdyRZZWFyIDwtIGFzLmludGVnZXIocm93bmFtZXMoY3Rfbm1HNUZiX21vMV9kc2xvdykpDQpyb3duYW1lcyhjdF9ubUc1RmJfbW8xX2RzbG93KSA8LSBOVUxMDQpjdF9ubUc1RmJfbW8xX2RzbG93IDwtIHJiaW5kKGN0X25tRzVGYl9tbzFfZHNsb3csIGRhdGEuZnJhbWUoRXN0aW1hdGUgPSBOQSwgTG93PU5BLCBIaWdoPU5BLCBzb3AuY2F0Y2g9TkEsIFllYXI9YXMuaW50ZWdlcigyMDI0KSkpDQphc3VtX25tRzVGYl9tbzFfZHNsb3cgPC0gbWVyZ2UoeCA9IGFzdW1fbm1HNUZiX21vMV9kc2xvdywgeSA9IGN0X25tRzVGYl9tbzFfZHNsb3csIGJ5ID0gIlllYXIiKQ0KY29sbmFtZXMoYXN1bV9ubUc1RmJfbW8xX2RzbG93KSA8LSBjKCJZZWFyIiwgIlJfYWdlMSIsICJSbG93IiwgIlJoaWdoIiwgIlNTQiIsICJTU0Jsb3ciLCAiU1NCaGlnaCIsICJGYmFyIiwgIkZsb3ciLCAiRmhpZ2giLCAiQ2F0Y2hFc3QiLCAiQ2F0Y2hsb3ciLCAiQ2F0Y2hoaWdoIiwgIkNhdGNoT2JzIikNCiM9PT09PQ0KYGBgDQoNCiMjIyBGaXRzIHRvIGRhdGENCldoZW4gdGhlIG1vZGVsIGlzIHJ1biB3ZSBjYW4gZWFzaWx5IHNlZSBmcm9tIHdhcm5pbmdzL2Vycm9ycyBpZiB0aGVyZSBpcyBhIGNvbnZlcmdlbmNlIGlzc3VlLiAgSG93ZXZlciwgd2UgY2FuIGFsc28gY29uZmlybSB0aGlzLCBleHBsaWNpdGx5Og0KDQotIFRoZSBmaW5hbCBtb2RlbCBncmFkaWVudDogYHIgZml0X25tRzVGYl9tbzFfZHNsb3ckb3B0JGV2YWx1YXRpb25zWzJdYA0KLSBUaGF0IHRoZXJlIGlzIGEgcG9zaXRpdmUgZGVmaW5pdGUgaGVzc2lhbjogYHIgYWxsKGVpZ2VuKGZpdF9ubUc1RmJfbW8xX2RzbG93JG9wdCRoZSkkdmFsdWVzID4wKWANCg0KRnVydGhlcm1vcmUsIFNBTSBkb2VzIG5vdCB1dGlsaXNlICJib3VuZHMiIHdoZW4gZml0dGluZyB0aGUgbW9kZWwsIGFuZCB0aGVyZWZvcmUsIGFzIHN0YW5kYXJkIGNoZWNrIG9mIHdoZXRoZXIgbW9kZWwgcGFyYW1ldGVycyBhcmUgYXBwcm9hY2hpbmcgdGhlaXIgYm91bmRzIGlzIGlycmVsZXZhbnQuDQoNCiMjIyMgVmlzdWFsaXNlIGZpdHMgdG8gZGF0YSBieSBhZ2Ugb3ZlciB0aW1lIGFjcm9zcyBmbGVldHMNCg0KYGBge3IgZmlnLmNhcD0iTW9kZWwgd2l0aCBMb3cgZGlzY2FyZCBzdXJ2aXZhbCBlc3RpbWF0ZXMsIGZpdCB0byBjYXRjaCBkYXRhIGJ5IGFnZSAodmFsdWVzIG9uIHRoZSBtb2RlbCBsaW5rIGZ1bmN0aW9uIHNjYWxlKS4ifQ0KIyMgRXh0cmFjdCBkYXRhIGZyb20gbW9kZWwgb2JqZWN0DQpsb2dPYnNfbm1HNUZiX21vMV9kc2xvdyA8LSBzcGxpdChmaXRfbm1HNUZiX21vMV9kc2xvdyRkYXRhJGxvZ29icywgY2VpbGluZyhzZXFfYWxvbmcoZml0X25tRzVGYl9tbzFfZHNsb3ckZGF0YSRsb2dvYnMpL2ZpdF9ubUc1RmJfbW8xX2RzbG93JGRhdGEkbWF4QWdlUGVyRmxlZXRbMV0pKQ0KbG9nUHJlZF9ubUc1RmJfbW8xX2RzbG93IDwtIHNwbGl0KGZpdF9ubUc1RmJfbW8xX2RzbG93JHJlcCRwcmVkT2JzLCBjZWlsaW5nKHNlcV9hbG9uZyhmaXRfbm1HNUZiX21vMV9kc2xvdyRyZXAkcHJlZE9icykvZml0X25tRzVGYl9tbzFfZHNsb3ckZGF0YSRtYXhBZ2VQZXJGbGVldFsxXSkpDQoNCiMjIFRyYW5zZm9ybSBkYXRhIHRvIHVzZWFibGUgZGF0YWZyYW1lcw0KIyMjIEluaXRpYWxpemUgYW4gZW1wdHkgZGF0YSBmcmFtZSBmb3Igb2JzZXJ2YXRpb25zDQpsb2dPYnNfbm1HNUZiX21vMV9kc2xvd19kZiA8LSBkYXRhLmZyYW1lKGFnZSA9IGludGVnZXIoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmxlZXQgPSBpbnRlZ2VyKCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllYXIgPSBpbnRlZ2VyKCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZ09icyA9IG51bWVyaWMoKSkNCg0KIyMjIFBvcHVsYXRlIHRoZSBkYXRhIGZyYW1lIGZvciBvYnNlcnZhdGlvbnMNCmZvciAoaSBpbiBzZXFfYWxvbmcobG9nT2JzX25tRzVGYl9tbzFfZHNsb3cpKSB7DQogICMgQ2FsY3VsYXRlIHRoZSBncm91cCBhbmQgeWVhcg0KICB5ZWFyIDwtICgoaSAtIDEpICUvJSAzKSArIDENCiAgZmxlZXQgPC0gKChpIC0gMSkgJSUgMykgKyAxDQogIA0KICAjIyMgQ3JlYXRlIGEgdGVtcG9yYXJ5IGRhdGEgZnJhbWUgYW5kIGFwcGVuZCB0byB0aGUgbWFpbiBkYXRhIGZyYW1lIGZvciBvYnNlcnZhdGlvbnMNCiAgdGVtcF9kZiA8LSBkYXRhLmZyYW1lKGFnZSA9IDE6NywNCiAgICAgICAgICAgICAgICAgICAgICAgIGZsZWV0ID0gZmxlZXQsDQogICAgICAgICAgICAgICAgICAgICAgICB5ZWFyID0geWVhcisyMDAxLA0KICAgICAgICAgICAgICAgICAgICAgICAgbG9nT2JzID0gbG9nT2JzX25tRzVGYl9tbzFfZHNsb3dbW2ldXSkNCiAgbG9nT2JzX25tRzVGYl9tbzFfZHNsb3dfZGYgPC0gcmJpbmQobG9nT2JzX25tRzVGYl9tbzFfZHNsb3dfZGYsIHRlbXBfZGYpDQp9DQoNCiMjIyBJbml0aWFsaXplIGFuIGVtcHR5IGRhdGEgZnJhbWUgZm9yIHByZWRpY3Rpb25zDQpsb2dQcmVkX25tRzVGYl9tbzFfZHNsb3dfZGYgPC0gZGF0YS5mcmFtZShhZ2UgPSBpbnRlZ2VyKCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmbGVldCA9IGludGVnZXIoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllYXIgPSBpbnRlZ2VyKCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2dQcmVkID0gbnVtZXJpYygpKQ0KDQojIyMgUG9wdWxhdGUgdGhlIGRhdGEgZnJhbWUgZm9yIHByZWRpY3Rpb25zDQpmb3IgKGkgaW4gc2VxX2Fsb25nKGxvZ1ByZWRfbm1HNUZiX21vMV9kc2xvdykpIHsNCiAgIyBDYWxjdWxhdGUgdGhlIGdyb3VwIGFuZCB5ZWFyDQogIHllYXIgPC0gKChpIC0gMSkgJS8lIDMpICsgMQ0KICBmbGVldCA8LSAoKGkgLSAxKSAlJSAzKSArIDENCiAgDQogICMjIyBDcmVhdGUgYSB0ZW1wb3JhcnkgZGF0YSBmcmFtZSBhbmQgYXBwZW5kIHRvIHRoZSBtYWluIGRhdGEgZnJhbWUgZm9yIHByZWRpY3Rpb25zDQogIHRlbXBfZGYgPC0gZGF0YS5mcmFtZShhZ2UgPSAxOjcsDQogICAgICAgICAgICAgICAgICAgICAgICBmbGVldCA9IGZsZWV0LA0KICAgICAgICAgICAgICAgICAgICAgICAgeWVhciA9IHllYXIrMjAwMSwNCiAgICAgICAgICAgICAgICAgICAgICAgIGxvZ1ByZWQgPSBsb2dQcmVkX25tRzVGYl9tbzFfZHNsb3dbW2ldXSkNCiAgbG9nUHJlZF9ubUc1RmJfbW8xX2RzbG93X2RmIDwtIHJiaW5kKGxvZ1ByZWRfbm1HNUZiX21vMV9kc2xvd19kZiwgdGVtcF9kZikNCn0NCg0KIyMgUGxvdA0KbG9nUHJlZF9ubUc1RmJfbW8xX2RzbG93X2RmJGFnZSA8LSBhcy5jaGFyYWN0ZXIobG9nUHJlZF9ubUc1RmJfbW8xX2RzbG93X2RmJGFnZSkNCmxvZ09ic19ubUc1RmJfbW8xX2RzbG93X2RmJGFnZSA8LSBhcy5jaGFyYWN0ZXIobG9nT2JzX25tRzVGYl9tbzFfZHNsb3dfZGYkYWdlKQ0KDQpnZ3Bsb3RseShnZ3Bsb3QoKSsNCiAgICAgICAgICAgZ2VvbV9wb2ludChkYXRhID0gbG9nT2JzX25tRzVGYl9tbzFfZHNsb3dfZGZbbG9nT2JzX25tRzVGYl9tbzFfZHNsb3dfZGYkZmxlZXQgPT0gMSAmIGxvZ09ic19ubUc1RmJfbW8xX2RzbG93X2RmJHllYXIgIT0gKERhdGFZZWFyKzEpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IHllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gbG9nT2JzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gYWdlKSwNCiAgICAgICAgICAgICAgICAgICAgICBzaGFwZSA9IDIxKSArDQogICAgICAgICAgIGdlb21fbGluZShkYXRhID0gbG9nUHJlZF9ubUc1RmJfbW8xX2RzbG93X2RmW2xvZ1ByZWRfbm1HNUZiX21vMV9kc2xvd19kZiRmbGVldCA9PSAxICYgbG9nUHJlZF9ubUc1RmJfbW8xX2RzbG93X2RmJHllYXIgIT0gKERhdGFZZWFyKzEpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0geWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGxvZ1ByZWQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IGFnZSkpICsNCiAgICAgICAgICAgZmFjZXRfd3JhcChmYWNldHMgPSAiYWdlIikgKyAjLCBzY2FsZXMgPSAiZnJlZV95IikgKw0KICAgICAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gZWJwYWwsIGd1aWRlID0gRkFMU0UpICsNCiAgICAgICAgICAgZ3VpZGVzKGNvbG91cj1GQUxTRSwgc2hhcGU9RkFMU0UpICsNCiAgICAgICAgICAgdGhlbWVfZmV3KCkpDQoNCiMgZml0cGxvdChmaXRfbm1HNUZiX21vMV9kc2xvdywgZmxlZXRzPTEpDQpgYGANCg0KYGBge3IgZmlnLmNhcD0iTW9kZWwgd2l0aCBMb3cgZGlzY2FyZCBzdXJ2aXZhbCBlc3RpbWF0ZXMsIGZpdCB0byBRMSBzdXJ2ZXkgZGF0YSBieSBhZ2UgKHZhbHVlcyBvbiB0aGUgbW9kZWwgbGluayBmdW5jdGlvbiBzY2FsZSkuIn0NCmdncGxvdGx5KGdncGxvdCgpKw0KICAgICAgICAgICBnZW9tX3BvaW50KGRhdGEgPSBsb2dPYnNfbm1HNUZiX21vMV9kc2xvd19kZltsb2dPYnNfbm1HNUZiX21vMV9kc2xvd19kZiRmbGVldCA9PSAyICYgbG9nT2JzX25tRzVGYl9tbzFfZHNsb3dfZGYkeWVhciAhPSAoRGF0YVllYXIrMSksIF0sDQogICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0geWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBsb2dPYnMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBhZ2UpLA0KICAgICAgICAgICAgICAgICAgICAgIHNoYXBlID0gMjEpICsNCiAgICAgICAgICAgZ2VvbV9saW5lKGRhdGEgPSBsb2dQcmVkX25tRzVGYl9tbzFfZHNsb3dfZGZbbG9nUHJlZF9ubUc1RmJfbW8xX2RzbG93X2RmJGZsZWV0ID09IDIgJiBsb2dQcmVkX25tRzVGYl9tbzFfZHNsb3dfZGYkeWVhciAhPSAoRGF0YVllYXIrMSksIF0sDQogICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSB5ZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gbG9nUHJlZCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gYWdlKSkgKw0KICAgICAgICAgICBmYWNldF93cmFwKGZhY2V0cyA9ICJhZ2UiKSArICMsIHNjYWxlcyA9ICJmcmVlX3kiKSArDQogICAgICAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBlYnBhbCwgZ3VpZGUgPSBGQUxTRSkgKw0KICAgICAgICAgICBndWlkZXMoY29sb3VyPUZBTFNFLCBzaGFwZT1GQUxTRSkgKw0KICAgICAgICAgICB0aGVtZV9mZXcoKSkNCiMgZml0cGxvdChmaXRfbm1HNUZiX21vMV9kc2xvdywgZmxlZXRzPTIpDQpgYGANCg0KYGBge3IgZmlnLmNhcD0iTW9kZWwgd2l0aCBsb3cgZGlzY2FyZCBzdXJ2aXZhbCBlc3RpbWF0ZXMsIGZpdCB0byBRMy80IHN1cnZleSBkYXRhIGJ5IGFnZSAodmFsdWVzIG9uIHRoZSBtb2RlbCBsaW5rIGZ1bmN0aW9uIHNjYWxlKS4ifQ0KZ2dwbG90bHkoZ2dwbG90KCkrDQogICAgICAgICAgIGdlb21fcG9pbnQoZGF0YSA9IGxvZ09ic19ubUc1RmJfbW8xX2RzbG93X2RmW2xvZ09ic19ubUc1RmJfbW8xX2RzbG93X2RmJGZsZWV0ID09IDMgJiBsb2dPYnNfbm1HNUZiX21vMV9kc2xvd19kZiR5ZWFyICE9IChEYXRhWWVhcisxKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSB5ZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGxvZ09icywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IGFnZSksDQogICAgICAgICAgICAgICAgICAgICAgc2hhcGUgPSAyMSkgKw0KICAgICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IGxvZ1ByZWRfbm1HNUZiX21vMV9kc2xvd19kZltsb2dQcmVkX25tRzVGYl9tbzFfZHNsb3dfZGYkZmxlZXQgPT0gMyAmIGxvZ1ByZWRfbm1HNUZiX21vMV9kc2xvd19kZiR5ZWFyICE9IChEYXRhWWVhcisxKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IHllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBsb2dQcmVkLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBhZ2UpKSArDQogICAgICAgICAgIGZhY2V0X3dyYXAoZmFjZXRzID0gImFnZSIpICsgIywgc2NhbGVzID0gImZyZWVfeSIpICsNCiAgICAgICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGVicGFsLCBndWlkZSA9IEZBTFNFKSArDQogICAgICAgICAgIGd1aWRlcyhjb2xvdXI9RkFMU0UsIHNoYXBlPUZBTFNFKSArDQogICAgICAgICAgIHRoZW1lX2ZldygpKQ0KDQojIGZpdHBsb3QoZml0X25tRzVGYl9tbzFfZHNsb3csIGZsZWV0cz0zKQ0KYGBgDQoNCmBgYHtyIGZpZy5jYXA9IlN0YW5kYXJkIERldmF0aW9ucyBieSBGbGVldDsgbG93IGRpc2NhcmQgc3Vydml2YWwgZXN0aW1hdGVzLiIsIGhlaWdodD0xMH0NCnNkcGxvdChmaXRfbm1HNUZiX21vMV9kc2xvdywgbWFyZyA9IGMoNSw0LDEsMSkpDQpgYGANCg0KIyMjIyBSZXNpZHVhbHMNCmBgYHtyIGNhbGN1bGF0ZVJlc2lkdWFsc19ubUc1RmJfbW8xX2RzbG93LCB3YXJuaW5nPUZBTFNFLCByZXN1bHRzPSdoaWRlJ30NCnJlc2lkX25tRzVGYl9tbzFfZHNsb3cgPC0gcmVzaWR1YWxzKGZpdF9ubUc1RmJfbW8xX2RzbG93KQ0KcmVzaWRfbm1HNUZiX21vMV9kc2xvd19kZiA8LSBkYXRhLmZyYW1lKHllYXIgPSByZXNpZF9ubUc1RmJfbW8xX2RzbG93JHllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmxlZXQgPSByZXNpZF9ubUc1RmJfbW8xX2RzbG93JGZsZWV0LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFnZSA9IHJlc2lkX25tRzVGYl9tbzFfZHNsb3ckYWdlLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9ic2VydmF0aW9uID0gcmVzaWRfbm1HNUZiX21vMV9kc2xvdyRvYnNlcnZhdGlvbiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZWFuID0gcmVzaWRfbm1HNUZiX21vMV9kc2xvdyRtZWFuLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc2lkdWFsID0gcmVzaWRfbm1HNUZiX21vMV9kc2xvdyRyZXNpZHVhbCkNCnJlc2lkX25tRzVGYl9tbzFfZHNsb3dfZGYkZmxlZXROYW1lIDwtIGlmZWxzZShyZXNpZF9ubUc1RmJfbW8xX2RzbG93X2RmJGZsZWV0ID09IDEsIGF0dHJpYnV0ZXMocmVzaWRfbm1HNUZiX21vMV9kc2xvdykkZmxlZXROYW1lc1sxXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKHJlc2lkX25tRzVGYl9tbzFfZHNsb3dfZGYkZmxlZXQgPT0gMiwgYXR0cmlidXRlcyhyZXNpZF9ubUc1RmJfbW8xX2RzbG93KSRmbGVldE5hbWVzWzJdLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKHJlc2lkX25tRzVGYl9tbzFfZHNsb3dfZGYkZmxlZXQgPT0gMywgYXR0cmlidXRlcyhyZXNpZF9ubUc1RmJfbW8xX2RzbG93KSRmbGVldE5hbWVzWzNdLCBOQSkpKQ0KDQpyZXNpZF9ubUc1RmJfbW8xX2RzbG93X2RmJGZsZWV0QWx0TmFtZSA8LSBpZmVsc2UocmVzaWRfbm1HNUZiX21vMV9kc2xvd19kZiRmbGVldCA9PSAxLCAiUmVzaWR1YWwgRmlzaGluZyIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShyZXNpZF9ubUc1RmJfbW8xX2RzbG93X2RmJGZsZWV0ID09IDIsICJRMSBTdXJ2ZXlzIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShyZXNpZF9ubUc1RmJfbW8xX2RzbG93X2RmJGZsZWV0ID09IDMsICJRMy80IFN1cnZleXMiLCBOQSkpKQ0KYGBgDQoNCmBgYHtyIGZpZy5jYXA9IkVzdGltYXRlZCBjb3JyZWxhdGlvbnMgaW4gcmVzaWR1YWwgdmFyaWF0aW9uIGJldHdlZW4gYWdlcyBmb3IgZWFjaCBvZiB0aGUgZmlzaGluZyBmbGVldCAodG9wKSBhbmQgdGhlIHR3byBzdXJ2ZXlzIChtaWRkbGUgJiBib3R0b20pLCBmcm9tIHRoZSBNb2RlbCB3aXRoIGxvdyBkaXNjYXJkIHN1cnZpdmFsIGVzdGltYXRlcy4ifQ0KDQppZighYWxsKGZpdF9ubUc1RmJfbW8xX2RzbG93JGNvbmYkb2JzQ29yU3RydWN0PT0iSUQiKSl7IA0KICBjb3JwbG90KGZpdF9ubUc1RmJfbW8xX2RzbG93KQkJCSAgDQogICMgc2V0Y2FwKCJFc3RpbWF0ZWQgY29ycmVsYXRpb25zIiwgIkVzdGltYXRlcyBjb3JyZWxhdGlvbnMgYmV0d2VlbiBhZ2UgZ3JvdXBzIGZvciBlYWNoIGZsZWV0IikNCiAgIyBzdGFtcGl0KGZpdCkNCn0gZWxzZSB7DQogIHByaW50KCJObyBjb3JyZWxhdGlvbiBzdHJ1Y3R1cmUgY29uZmlndXJlZCBmb3IgcmVzaWR1YWxzIGFjcm9zcyBhZ2UuIikNCn0NCg0KYGBgDQoNCmBgYHtyIGZpZy5jYXA9Ik9uZSBvYnNlcnZhdGlvbiBhaGVhZCByZXNpZHVhbHMgZm9yIHRoZSB0aHJlZSBmbGVldHMgKHJlZC9waW5rID0gb2JzZXJ2YXRpb24gbG93ZXIgdGhhbiBtb2RlbCBlc3RpbWF0ZSwgYmx1ZSA9IG9ic2VydmF0aW9uIGhpZ2hlciB0aGFuIG1vZGVsIGVzdGltYXRlLCBzaXplID0gbWFnbml0dWRlIG9mIHJlc2lkdWFsKSwgZnJvbSB0aGUgTW9kZWwgd2l0aCBsb3cgZGlzY2FyZCBzdXJ2aXZhbCBlc3RpbWF0ZXMuIn0NCmdncGxvdGx5KGdncGxvdChyZXNpZF9ubUc1RmJfbW8xX2RzbG93X2RmKSArDQogICAgICAgICAgIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0geWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBhZ2UsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gYWJzKHJlc2lkdWFsKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IHJlc2lkdWFsID49IDApLA0KICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC43KSArDQogICAgICAgICAgIGZhY2V0X2dyaWQocm93cyA9ICJmbGVldEFsdE5hbWUiKSArDQogICAgICAgICAgIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiVFJVRSIgPSBlYnBhbFs4XSwgIkZBTFNFIiA9IGVicGFsWzldKSkgKw0KICAgICAgICAgICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygtMSwgOSksIGJyZWFrcyA9IGMoMTo5KSkgKw0KICAgICAgICAgICBndWlkZXMoY29sb3VyPUZBTFNFKSArDQogICAgICAgICAgIHRoZW1lX2ZldygpKQ0KDQpgYGANCg0KIyMjIyBKaXR0ZXJpbmcNCldlIGNhbiBhbHNvIHRlc3QgdG8gc2VlIGlmIHRoZSBtb2RlbCBpcyBjb252ZXJnaW5nIG9uIHNvbWUgbG9jYWwgbWluaW11bSAoaS5lLiBpdCdzIGZpdHRpbmcgdG8gc29tZSBzb2x1dGlvbiBjbG9zZSB0byBpbml0aWFsaXNpbmcgdmFsdWVzIHRoYXQgcmVwcmVzZW50cyBub2lzZSBhbmQgbm90IHRoZSBnbG9iYWwgc29sdXRpb24sIHRoYXQgaXMgdGhlIHByb3BlciBzb2x1dGlvbikuICBUbyBkbyB0aGlzLCB3ZSBhZGQgcmFuZG9tIG5vaXNlIHRvIHRoZSBpbml0aWFsIHBhcmFtZXRlciB2YWx1ZXMgdG8gc2VlIGlmIHRoZSBtb2RlbCB3aWxsIGNvbnZlcmdlIG9uIGEgZGlmZmVyZW50IG1pbmltdW0gaW4gaXQncyBkYXRhLXNwYWNlLiBUaGUgZWFzaWVzdCB3YXkgdG8gaW52ZXN0aWdhdGUgdGhpcyBpcyB0byBzZWUgaWYgdGhlIG1vZGVsIGZpdHMgdmFyeSBhbG90IGRlcGVuZGluZyBvbiB0aGUgc3RhcnRpbmcgdmFsdWVzOg0KYGBge3IgSml0dGVyX25tRzVGYl9tbzFfZHNsb3d9DQpqaXRfbm1HNUZiX21vMV9kc2xvdyA8LSBqaXQoZml0ID0gZml0X25tRzVGYl9tbzFfZHNsb3cpDQoNCm10IDwtIGFzLmRhdGEuZnJhbWUobW9kZWx0YWJsZShqaXRfbm1HNUZiX21vMV9kc2xvdykpDQptdCRtb2RlbCA8LSByb3duYW1lcyhtdCkNCnJvd25hbWVzKG10KSA8LSBOVUxMDQoNCmthYmxlKHggPSBtdCwNCiAgICAgIGRpZ2l0cyA9IDMsDQogICAgICBjYXB0aW9uID0gIk1lYXN1cmVzIG9mICBmaXQgZm9yIGEgc2VyaWVzIG9mIG1vZGVsIHJlZml0cyB3aXRoIGppdHRlciBhcHBsaWVkIHRvIHRoZSBpbnB1dCBwYXJhbWV0ZXJzLiIpDQpgYGANCg0KIyMjIyBMZWF2ZS1PbmUtT3V0IEFuYWx5c2VzDQpBIGxlYXZlLW9uZS1vdXQgYW5hbHlzaXMgaXMgYSBmb3JtIG9mIHNlbnNpdGl2aXR5IGFuYWx5c2lzLCBzaG93aW5nIHRoZSBpbXBhY3QgdGhlIGRhdGEgZnJvbSBlYWNoIHR1bmluZyBmbGVldCBoYXMgb24gdGhlIGVzdGltYXRpb24gb2YgdGhlIGtleSB2YXJpYWJsZXMgYmVpbmcgZXN0aW1hdGVkOyBuYW1lbHkgU1NCLCBGIGFuZCByZWNydWl0bWVudC4gIA0KDQpGaXJzdCB3ZSBtdXN0IHJ1biB0aGUgbGVhdmUtb25lLW91dCBhbmFseXNpcyB3aGljaCByZWZpdHMgdGhlIG1vZGVsIGluIHR3byBpdGVyYXRpb25zLCByZW1vdmluZyBvbmUgc3VydmV5IGF0IGEgdGltZS4gVGhlbiB3ZSBjYW4gcGxvdCBlYWNoIG9mIHRoZXNlIG5ldyBtb2RlbCBmaXRzIG92ZXIgdGhlIGZ1bGwgbW9kZWwgdG8gc2VlIHRoZSBpbXBhY3QgdGhlIHJlbW92YWwgb2YgZWFjaCBoYXMuIA0KDQpgYGB7ciBMZWF2ZU9uZU91dF9ubUc1RmJfbW8xX2RzbG93fQ0KTE9fbm1HNUZiX21vMV9kc2xvdyA8LSBsZWF2ZW91dChmaXRfbm1HNUZiX21vMV9kc2xvdykNCg0KIz09PSANCiMgR2V0IGRhdGEgZnJvbSBzYW0gb2JqZWN0cyBhbmQgZ2VuZXJhdGUgdXNlYWJsZSBkYXRhZnJhbWVzDQojPT09PQ0KcTFtYXQgPC0gYXMuZGF0YS5mcmFtZShzdW1tYXJ5KExPX25tRzVGYl9tbzFfZHNsb3ckYHcuby4gUTFJQlRTK0JJVFMrQ29kU0QyMS0yNWApKQ0KcTNtYXQgPC0gYXMuZGF0YS5mcmFtZShzdW1tYXJ5KExPX25tRzVGYl9tbzFfZHNsb3ckYHcuby4gUTM0SUJUUytCSVRTK0NvZFNEMjEtMjVgKSkNCg0KDQp3b3ExIDwtIGRhdGEuZnJhbWUoWWVhciA9IGFzLmludGVnZXIocm93Lm5hbWVzKHN1bW1hcnkoTE9fbm1HNUZiX21vMV9kc2xvdyRgdy5vLiBRMUlCVFMrQklUUytDb2RTRDIxLTI1YCkpKSwNCiAgICAgICAgICAgICAgICAgICBTU0IgPSBxMW1hdCRTU0IsDQogICAgICAgICAgICAgICAgICAgRmJhciA9IHExbWF0JGBGYmFyKDMtNSlgLA0KICAgICAgICAgICAgICAgICAgIFJfYWdlMSA9IHExbWF0JGBSKGFnZSAxKWAsDQogICAgICAgICAgICAgICAgICAgQ2F0Y2hFc3QgPSBjYXRjaHRhYmxlKExPX25tRzVGYl9tbzFfZHNsb3ckYHcuby4gUTFJQlRTK0JJVFMrQ29kU0QyMS0yNWApWywxXSwNCiAgICAgICAgICAgICAgICAgICBzZXJpZXMgPSByZXAoIndvX1ExIiwgdGltZXMgPSBucm93KHExbWF0KSkpDQoNCndvcTM0IDwtIGRhdGEuZnJhbWUoWWVhciA9IGFzLmludGVnZXIocm93Lm5hbWVzKHEzbWF0WygyMDAyOkRhdGFZZWFyKS0yMDAxLF0pKSwNCiAgICAgICAgICAgICAgICAgICAgU1NCID0gcTNtYXRbKDIwMDI6RGF0YVllYXIpLTIwMDEsICJTU0IiXSwNCiAgICAgICAgICAgICAgICAgICAgRmJhciA9IHEzbWF0WygyMDAyOkRhdGFZZWFyKS0yMDAxLCJGYmFyKDMtNSkiXSwNCiAgICAgICAgICAgICAgICAgICAgUl9hZ2UxID0gcTNtYXRbKDIwMDI6RGF0YVllYXIpLTIwMDEsIlIoYWdlIDEpIl0sDQogICAgICAgICAgICAgICAgICAgIENhdGNoRXN0ID0gY2F0Y2h0YWJsZShMT19ubUc1RmJfbW8xX2RzbG93JGB3Lm8uIFEzNElCVFMrQklUUytDb2RTRDIxLTI1YClbLDFdLA0KICAgICAgICAgICAgICAgICAgICBzZXJpZXMgPSByZXAoIndvX1EzNCIsIHRpbWVzID0gKG5yb3cocTNtYXQpLTEpKSkNCg0KDQphc3VtX25tRzVGYl9tbzFfZHNsb3ckc2VyaWVzIDwtIHJlcCgiZnVsbCIsIHRpbWVzID0gbnJvdyhhc3VtX25tRzVGYl9tbzFfZHNsb3cpKQ0KYXN1bWlfbm1HNUZiX21vMV9kc2xvdyA8LSBhc3VtX25tRzVGYl9tbzFfZHNsb3dbLCBjKCJZZWFyIiwgIlNTQiIsICJGYmFyIiwgIlJfYWdlMSIsICJDYXRjaEVzdCIgLCJzZXJpZXMiKV0NCiM9PT09PQ0KDQpsb3N1bV9ubUc1RmJfbW8xX2RzbG93IDwtIHJiaW5kKHdvcTEsIHdvcTM0LCBhc3VtaV9ubUc1RmJfbW8xX2RzbG93KQ0KDQpgYGANCg0KYGBge3IgZmlnLmNhcD0iTGVhdmUtb25lLW91dCByZS1maXRzIGZvciB0aGUgbW9kZWwgd2l0aCBhZ2UxIG1hdHVyaXRpZXMgc2V0IHRvIHplcm8gKHdpdGhvdXQgUTEgc3VydmV5ID0gYmx1ZSwgd2l0aG91dCBRMy80IHN1cnZleSA9IHB1cnBsZSksIG92ZXJsYWluIHdpdGggZnVsbCBtb2RlbCBlc3RpbWF0ZXMgKGJsYWNrIGxpbmUgYW5kIGdyZXkgcmliYm9uKSBvZiBTU0IgKHRvcCBsZWZ0KSwgRiAodG9wIHJpZ2h0KSwgUmVjcnVpdG1lbnQgKGJvdHRvbSBsZWZ0KSwgYW5kIGNhdGNoIChib3R0b20gcmlnaHQ7IG9ic2VydmF0aW9ucyBhcyB5ZWxsb3cgKykuIn0NCiMgc3NicGxvdChMTykNCmxvc3NiX25tRzVGYl9tbzFfZHNsb3cgPC0gZ2dwbG90bHkoZ2dwbG90KCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fbGluZShkYXRhID0gbG9zdW1fbm1HNUZiX21vMV9kc2xvdywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1TU0IsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gc2VyaWVzKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fcmliYm9uKGRhdGEgPSBhc3VtX25tRzVGYl9tbzFfZHNsb3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWluPVNTQmxvdywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltYXg9U1NCaGlnaCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9ICJibGFjayIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjIpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoImJsYWNrIiwgZWJwYWxbODo5XSkpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9jbGVhbigpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZShheGlzLnRpdGxlLnkubGVmdCA9IGVsZW1lbnRfdGV4dCh2anVzdCA9IC0wLjA1LCBoanVzdCA9IDAuOTUpKSkNCg0KIyBGcGxvdChMTykNCmxvZl9ubUc1RmJfbW8xX2RzbG93IDwtIGdncGxvdGx5KGdncGxvdCgpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9saW5lKGRhdGEgPSBsb3N1bV9ubUc1RmJfbW8xX2RzbG93LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9RmJhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gc2VyaWVzKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3JpYmJvbihkYXRhID0gYXN1bV9ubUc1RmJfbW8xX2RzbG93LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWluPUZsb3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1heD1GaGlnaCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSAiYmxhY2siLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMykgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoImJsYWNrIiwgZWJwYWxbODo5XSkpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWVfY2xlYW4oKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKGF4aXMudGl0bGUueS5sZWZ0ID0gZWxlbWVudF90ZXh0KHZqdXN0ID0gLTAuMDUsIGhqdXN0ID0gMC45NSkpKQ0KDQojIHJlY3Bsb3QoTE8pDQpsb3JlY19ubUc1RmJfbW8xX2RzbG93IDwtIGdncGxvdGx5KGdncGxvdCgpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IGxvc3VtX25tRzVGYl9tbzFfZHNsb3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9Ul9hZ2UxLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IHNlcmllcykpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3JpYmJvbihkYXRhID0gYXN1bV9ubUc1RmJfbW8xX2RzbG93LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1pbj1SbG93LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1heD1SaGlnaCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9ICJibGFjayIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjMpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoImJsYWNrIiwgZWJwYWxbODo5XSkpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9jbGVhbigpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZShheGlzLnRpdGxlLnkubGVmdCA9IGVsZW1lbnRfdGV4dCh2anVzdCA9IC0wLjA1LCBoanVzdCA9IDAuOTUpKSkNCg0KIyBDYXRjaCBwbG90IChMTykNCmxvY2Ffbm1HNUZiX21vMV9kc2xvdyA8LSBnZ3Bsb3RseShnZ3Bsb3QoKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IGxvc3VtX25tRzVGYl9tbzFfZHNsb3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PUNhdGNoRXN0LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gc2VyaWVzKSkrDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3JpYmJvbihkYXRhID0gYXN1bV9ubUc1RmJfbW8xX2RzbG93W2FzdW1fbm1HNUZiX21vMV9kc2xvdyRZZWFyICE9IChEYXRhWWVhcisxKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWluPUNhdGNobG93LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4PUNhdGNoaGlnaCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gImJsYWNrIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4zKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3BvaW50KGRhdGEgPSBhc3VtX25tRzVGYl9tbzFfZHNsb3dbYXN1bV9ubUc1RmJfbW8xX2RzbG93JFllYXIgIT0gKERhdGFZZWFyKzEpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PUNhdGNoT2JzKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hhcGUgPSAzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBlYnBhbFs1XSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IGVicGFsWzVdKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bGFiKCJDYXRjaCAodG9ubmVzKSIpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiYmxhY2siLCBlYnBhbFs4OjldKSkrIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWVfY2xlYW4oKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZShheGlzLnRpdGxlLnkubGVmdCA9IGVsZW1lbnRfdGV4dCh2anVzdCA9IC0wLjA1LCBoanVzdCA9IDAuOTUpKSkNCg0KbGF5b3V0KHN1YnBsb3QobG9zc2Jfbm1HNUZiX21vMV9kc2xvdywgbG9mX25tRzVGYl9tbzFfZHNsb3csIGxvcmVjX25tRzVGYl9tbzFfZHNsb3csIGxvY2Ffbm1HNUZiX21vMV9kc2xvdywgbnJvd3MgPSAyLCBzaGFyZVggPSBUUlVFLCB0aXRsZVkgPSBUUlVFKSwgc2hvd2xlZ2VuZD1GQUxTRSkNCmBgYA0KDQojIyMjIFJldHJvc3BlY3RpdmVzDQpgYGB7ciBjYWxjdWxhdGVSZXRyb3Nfbm1HNUZiX21vMV9kc2xvd30NCiM9PT0NCiMgQ3JlYXRlIGRhdGFmcmFtZSBvZiBjdXJyZW50IHllYXIncyBmaXQgZm9yIHBsb3R0aW5nDQojPT09PQ0KIyBJQ19hZ2dfdGVtcCA8LSBhZ2dyZWdhdGUoQ0FUT05+WWVhciwgaWNfY2xlYW5baWNfY2xlYW4kQ2F0Y2hDYXRlZ29yeSAlaW4lIGMoIkxhbmRpbmdzIiwgIkRpc2NhcmRzIiksIF0sIEZVTiA9ICJzdW0iKQ0KYXN1bV9ubUc1RmJfbW8xX2RzbG93IDwtIGFzLmRhdGEuZnJhbWUoc3VtbWFyeShmaXRfbm1HNUZiX21vMV9kc2xvdykpDQphc3VtX25tRzVGYl9tbzFfZHNsb3ckWWVhciA8LSBhcy5pbnRlZ2VyKHJvdy5uYW1lcyhzdW1tYXJ5KGZpdF9ubUc1RmJfbW8xX2RzbG93KSkpDQpjdF9ubUc1RmJfbW8xX2RzbG93IDwtIGFzLmRhdGEuZnJhbWUoY2F0Y2h0YWJsZShmaXRfbm1HNUZiX21vMV9kc2xvdywgb2JzLnNob3cgPSBUUlVFKSkNCmN0X25tRzVGYl9tbzFfZHNsb3ckWWVhciA8LSBhcy5pbnRlZ2VyKHJvd25hbWVzKGN0X25tRzVGYl9tbzFfZHNsb3cpKQ0Kcm93bmFtZXMoY3Rfbm1HNUZiX21vMV9kc2xvdykgPC0gTlVMTA0KY3Rfbm1HNUZiX21vMV9kc2xvdyA8LSByYmluZChjdF9ubUc1RmJfbW8xX2RzbG93LCBkYXRhLmZyYW1lKEVzdGltYXRlID0gTkEsIExvdz1OQSwgSGlnaD1OQSwgc29wLmNhdGNoPU5BLCBZZWFyPWFzLmludGVnZXIoMjAyNCkpKQ0KYXN1bV9ubUc1RmJfbW8xX2RzbG93IDwtIG1lcmdlKHggPSBhc3VtX25tRzVGYl9tbzFfZHNsb3csIHkgPSBjdF9ubUc1RmJfbW8xX2RzbG93LCBieSA9ICJZZWFyIikNCmNvbG5hbWVzKGFzdW1fbm1HNUZiX21vMV9kc2xvdykgPC0gYygiWWVhciIsICJSX2FnZTEiLCAiUmxvdyIsICJSaGlnaCIsICJTU0IiLCAiU1NCbG93IiwgIlNTQmhpZ2giLCAiRmJhciIsICJGbG93IiwgIkZoaWdoIiwgIkNhdGNoRXN0IiwgIkNhdGNobG93IiwgIkNhdGNoaGlnaCIsICJDYXRjaE9icyIpDQoNCmFzdW1fbm1HNUZiX21vMV9kc2xvdyRzZXJpZXMgPC0gcmVwKCJmdWxsIiwgdGltZXMgPSBucm93KGFzdW1fbm1HNUZiX21vMV9kc2xvdykpDQoNCiM9PT09PQ0KUkVUUk9fbm1HNUZiX21vMV9kc2xvdzwtcmV0cm8oZml0X25tRzVGYl9tbzFfZHNsb3csIHllYXI9NSkNCnJob19ubUc1RmJfbW8xX2RzbG93IDwtIG1vaG4oUkVUUk9fbm1HNUZiX21vMV9kc2xvdywgbGFnID0gMSkNCg0KIyMgTWFrZSBSRVRST3MgaW4gYmV0dGVyIHBsb3R0aW5nIGZvcm1hdA0KcmV0X25tRzVGYl9tbzFfZHNsb3dfZGYgPC0gYXN1bV9ubUc1RmJfbW8xX2RzbG93W2FzdW1fbm1HNUZiX21vMV9kc2xvdyRZZWFyICE9IG1heChhc3VtX25tRzVGYl9tbzFfZHNsb3ckWWVhciksIF0NCg0KZm9yKGkgaW4gMTpsZW5ndGgoUkVUUk9fbm1HNUZiX21vMV9kc2xvdykpew0KICB0c3VtIDwtIGFzLmRhdGEuZnJhbWUoc3VtbWFyeShSRVRST19ubUc1RmJfbW8xX2RzbG93W1tpXV0pKQ0KICB0c3VtJFllYXIgPC0gYXMuaW50ZWdlcihyb3cubmFtZXMoc3VtbWFyeShSRVRST19ubUc1RmJfbW8xX2RzbG93W1tpXV0pKSkNCiAgdHN1bSA8LSBjYmluZCh0c3VtLCBjYXRjaHRhYmxlKFJFVFJPX25tRzVGYl9tbzFfZHNsb3dbW2ldXSwgb2JzLnNob3cgPSBUUlVFKSkNCiAgdHN1bSRzZXJpZXMgPC0gYXMuY2hhcmFjdGVyKHJlcChpLCBucm93KHRzdW0pKSkNCiAgY29sbmFtZXModHN1bSkgPC0gYygiUl9hZ2UxIiwgIlJsb3ciLCAiUmhpZ2giLCAiU1NCIiwgIlNTQmxvdyIsICJTU0JoaWdoIiwgIkZiYXIiLCAiRmxvdyIsICJGaGlnaCIsICJZZWFyIiwgIkNhdGNoRXN0IiwgIkNhdGNobG93IiwgIkNhdGNoaGlnaCIsICJDYXRjaE9icyIsICJzZXJpZXMiKQ0KICB0c3VtIDwtIHRzdW1bdHN1bSRZZWFyICE9IG1heCh0c3VtJFllYXIpLCBdDQogIHJldF9ubUc1RmJfbW8xX2RzbG93X2RmIDwtIHJiaW5kKHJldF9ubUc1RmJfbW8xX2RzbG93X2RmLCB0c3VtKQ0KfQ0KcmV0X25tRzVGYl9tbzFfZHNsb3dfZGYkc2VyaWVzIDwtIGZhY3RvcihyZXRfbm1HNUZiX21vMV9kc2xvd19kZiRzZXJpZXMsIGxldmVscyA9IGMoImZ1bGwiLCAiMSIsICIyIiwgIjMiLCAiNCIsICI1IikpDQpgYGANCg0KYGBge3IgZmlnLmNhcD0iUmV0cm9zcGVjdGl2ZSBhbmFseXNlcyBmb3IgU1NCICh0b3AtbGVmdCksIEYgZm9yIGFnZXMgMy01ICh0b3AtcmlnaHQpLCByZWNydWl0bWVudCAoYm90dG9tLWxlZnQpLCBhbmQgY2F0Y2ggKGJvdHRvbS1yaWdodCksIGZyb20gdGhlIG1vZGVsIHdpdGggbG93IGRpc2NhcmQgc3Vydml2YWwgZXN0aW1hdGVzLiJ9DQojIHNzYnBsb3QoUkVUUk8pDQpyZXRzc2Jfbm1HNUZiX21vMV9kc2xvdyA8LSBsYXlvdXQoZ2dwbG90bHkoZ2dwbG90KCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9saW5lKGRhdGEgPSByZXRfbm1HNUZiX21vMV9kc2xvd19kZiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9U1NCLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gc2VyaWVzKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9yaWJib24oZGF0YSA9IGFzdW1fbm1HNUZiX21vMV9kc2xvd1thc3VtX25tRzVGYl9tbzFfZHNsb3ckWWVhciAhPSBtYXgoYXN1bV9ubUc1RmJfbW8xX2RzbG93JFllYXIpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW49U1NCbG93LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4PVNTQmhpZ2gpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9ICJibGFjayIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMikgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYW5ub3RhdGUoZ2VvbSA9ICJ0ZXh0IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBtYXgocmV0X25tRzVGYl9tbzFfZHNsb3dfZGYkU1NCaGlnaCkqMC44NSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHggPSAoKG1heChyZXRfbm1HNUZiX21vMV9kc2xvd19kZiRZZWFyKS1taW4ocmV0X25tRzVGYl9tbzFfZHNsb3dfZGYkWWVhcikpKjAuMjApK21pbihyZXRfbm1HNUZiX21vMV9kc2xvd19kZiRZZWFyKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsID0gcGFzdGUwKCJNb2huJ3MgUmhvID0gIiwgcm91bmQocmhvX25tRzVGYl9tbzFfZHNsb3dbMl0sIGRpZ2l0cyA9IDMpKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCJibGFjayIsIGVicGFsWyhsZW5ndGgoZWJwYWwpLTQpOmxlbmd0aChlYnBhbCldKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWVfY2xlYW4oKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBheGlzLnRpdGxlLnkubGVmdCA9IGVsZW1lbnRfdGV4dCh2anVzdCA9IC0wLjA1LCBoanVzdCA9IDAuOTUpKSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hvd2xlZ2VuZCA9IEZBTFNFKQ0KDQojIEZwbG90KFJFVFJPKQ0KcmV0Zl9ubUc1RmJfbW8xX2RzbG93IDwtIGxheW91dChnZ3Bsb3RseShnZ3Bsb3QoKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9saW5lKGRhdGEgPSByZXRfbm1HNUZiX21vMV9kc2xvd19kZiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1GYmFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IHNlcmllcykpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3JpYmJvbihkYXRhID0gYXN1bV9ubUc1RmJfbW8xX2RzbG93W2FzdW1fbm1HNUZiX21vMV9kc2xvdyRZZWFyICE9IG1heChhc3VtX25tRzVGYl9tbzFfZHNsb3ckWWVhciksIF0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWluPUZsb3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4PUZoaWdoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gImJsYWNrIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMykgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFubm90YXRlKGdlb20gPSAidGV4dCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IG1heChyZXRfbm1HNUZiX21vMV9kc2xvd19kZiRGaGlnaCkqMC44NSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4ID0gKChtYXgocmV0X25tRzVGYl9tbzFfZHNsb3dfZGYkWWVhciktbWluKHJldF9ubUc1RmJfbW8xX2RzbG93X2RmJFllYXIpKSowLjgwKSttaW4ocmV0X25tRzVGYl9tbzFfZHNsb3dfZGYkWWVhciksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSBwYXN0ZTAoIk1vaG4ncyBSaG8gPSAiLCByb3VuZChyaG9fbm1HNUZiX21vMV9kc2xvd1szXSwgZGlnaXRzID0gMykpKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCJibGFjayIsIGVicGFsWyhsZW5ndGgoZWJwYWwpLTQpOmxlbmd0aChlYnBhbCldKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2NsZWFuKCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBheGlzLnRpdGxlLnkubGVmdCA9IGVsZW1lbnRfdGV4dCh2anVzdCA9IC0wLjA1LCBoanVzdCA9IDAuOTUpKSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNob3dsZWdlbmQgPSBGQUxTRSkNCg0KIyByZWNwbG90KFJFVFJPKQ0KcmV0cmVjX25tRzVGYl9tbzFfZHNsb3cgPC0gbGF5b3V0KGdncGxvdGx5KGdncGxvdCgpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fbGluZShkYXRhID0gcmV0X25tRzVGYl9tbzFfZHNsb3dfZGYsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PVJfYWdlMSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IHNlcmllcykpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fcmliYm9uKGRhdGEgPSBhc3VtX25tRzVGYl9tbzFfZHNsb3dbYXN1bV9ubUc1RmJfbW8xX2RzbG93JFllYXIgIT0gbWF4KGFzdW1fbm1HNUZiX21vMV9kc2xvdyRZZWFyKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWluPVJsb3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltYXg9UmhpZ2gpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9ICJibGFjayIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMykgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYW5ub3RhdGUoZ2VvbSA9ICJ0ZXh0IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9IG1heChyZXRfbm1HNUZiX21vMV9kc2xvd19kZiRSaGlnaCkqMC44NSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHggPSAoKG1heChyZXRfbm1HNUZiX21vMV9kc2xvd19kZiRZZWFyKS1taW4ocmV0X25tRzVGYl9tbzFfZHNsb3dfZGYkWWVhcikpKjAuMjApK21pbihyZXRfbm1HNUZiX21vMV9kc2xvd19kZiRZZWFyKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsID0gcGFzdGUwKCJNb2huJ3MgUmhvID0gIiwgcm91bmQocmhvX25tRzVGYl9tbzFfZHNsb3dbMV0sIGRpZ2l0cyA9IDMpKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCJibGFjayIsIGVicGFsWyhsZW5ndGgoZWJwYWwpLTQpOmxlbmd0aChlYnBhbCldKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWVfY2xlYW4oKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBheGlzLnRpdGxlLnkubGVmdCA9IGVsZW1lbnRfdGV4dCh2anVzdCA9IC0wLjA1LCBoanVzdCA9IDAuOTUpKSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hvd2xlZ2VuZCA9IEZBTFNFKQ0KDQojIyBDYXRjaCBwbG90IChSRVRSTykNCnJldGNhX25tRzVGYl9tbzFfZHNsb3cgPC0gZ2dwbG90bHkoZ2dwbG90KCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fbGluZShkYXRhID0gcmV0X25tRzVGYl9tbzFfZHNsb3dfZGYsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9Q2F0Y2hFc3QsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gc2VyaWVzKSkrDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9yaWJib24oZGF0YSA9IGFzdW1fbm1HNUZiX21vMV9kc2xvd1thc3VtX25tRzVGYl9tbzFfZHNsb3ckWWVhciAhPSBtYXgoYXN1bV9ubUc1RmJfbW8xX2RzbG93JFllYXIpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1pbj1DYXRjaGxvdywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltYXg9Q2F0Y2hoaWdoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gImJsYWNrIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMykgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fcG9pbnQoZGF0YSA9IGFzdW1fbm1HNUZiX21vMV9kc2xvd1thc3VtX25tRzVGYl9tbzFfZHNsb3ckWWVhciAhPSBtYXgoYXN1bV9ubUc1RmJfbW8xX2RzbG93JFllYXIpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9Q2F0Y2hPYnMpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hhcGUgPSAzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gZWJwYWxbNV0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gZWJwYWxbNV0pICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bGFiKCJDYXRjaCAodG9ubmVzKSIpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoImJsYWNrIiwgZWJwYWxbKGxlbmd0aChlYnBhbCktNCk6bGVuZ3RoKGVicGFsKV0pKSsgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWVfY2xlYW4oKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWUoYXhpcy50aXRsZS55LmxlZnQgPSBlbGVtZW50X3RleHQodmp1c3QgPSAtMC4wNSwgaGp1c3QgPSAwLjk1KSkpDQoNCnJldF9mcCA8LSBzdHlsZShzdWJwbG90KHJldHNzYl9ubUc1RmJfbW8xX2RzbG93LCByZXRmX25tRzVGYl9tbzFfZHNsb3csIHJldHJlY19ubUc1RmJfbW8xX2RzbG93LCByZXRjYV9ubUc1RmJfbW8xX2RzbG93LCBucm93cyA9IDIsIHNoYXJlWCA9IEZBTFNFLCBzaGFyZVkgPSBGQUxTRSwgdGl0bGVZID0gVFJVRSksDQogICAgICAgICAgICAgICAgc2hvd2xlZ2VuZD1GQUxTRSwNCiAgICAgICAgICAgICAgICB0cmFjZXMgPSBjKDg6KCg3KjQpKzIpKSkNCg0KbGF5b3V0KHJldF9mcCwgbGVnZW5kID0gbGlzdChvcmllbnRhdGlvbiA9ICdoJywgeCA9IDAuNSwgeGFuY2hvciA9ICdjZW50ZXInLCB5ID0gLTAuMDUsIHlhbmNob3IgPSAndG9wJywgYm9yZGVyd2lkdGggPSAwKSkNCmBgYA0KDQojIyBNZWRpdW0gRGlzY2FyZCBTdXJ2aXZhbCBFc3RpbWF0ZXMNCg0KVGhpcyBtb2RlbCBpcyBjYWxsZWQgW3BsZS4yNy4yMS0zMl9XS0JQTEFJQ0VfMjAyNF9ubUc1RmJfbW8xX2RzbWVkXShodHRwczovL3N0b2NrYXNzZXNzbWVudC5vcmcvc2V0U3RvY2sucGhwP3N0b2NrPXBsZS4yNy4yMS0zMl9XS0JQTEFJQ0VfMjAyNF9ubUc1RmJfbW8xX2RzbWVkKSBhbmQgY2FuIGJlIGZvdW5kIG9uIFtzdG9ja2Fzc2Vzc21lbnQub3JnXShodHRwczovL3N0b2NrYXNzZXNzbWVudC5vcmcpLiANCg0KYGBge3Igbm1HNUZiX21vMV9kc21lZEZpdEZyb21XZWJ9DQpmaXRfbm1HNUZiX21vMV9kc21lZCA8LSBmaXRmcm9td2ViKCJwbGUuMjcuMjEtMzJfV0tCUExBSUNFXzIwMjRfbm1HNUZiX21vMV9kc21lZCIpDQpgYGANCg0KYGBge3IgZGF0YWZyYW1lU3VtbWFyeV9ubUc1RmJfbW8xX2RzbWVkLCByZXN1bHRzPSdoaWRlJywgZmlnLnNob3c9J2hpZGUnfQ0KIz09PQ0KIyBDcmVhdGUgZGF0YWZyYW1lIG9mIGN1cnJlbnQgeWVhcidzIGZpdCBmb3IgcGxvdHRpbmcNCiM9PT09DQphc3VtX25tRzVGYl9tbzFfZHNtZWQgPC0gYXMuZGF0YS5mcmFtZShzdW1tYXJ5KGZpdF9ubUc1RmJfbW8xX2RzbWVkKSkNCmFzdW1fbm1HNUZiX21vMV9kc21lZCRZZWFyIDwtIGFzLmludGVnZXIocm93Lm5hbWVzKHN1bW1hcnkoZml0X25tRzVGYl9tbzFfZHNtZWQpKSkNCmN0X25tRzVGYl9tbzFfZHNtZWQgPC0gYXMuZGF0YS5mcmFtZShjYXRjaHRhYmxlKGZpdF9ubUc1RmJfbW8xX2RzbWVkLCBvYnMuc2hvdyA9IFRSVUUpKQ0KY3Rfbm1HNUZiX21vMV9kc21lZCRZZWFyIDwtIGFzLmludGVnZXIocm93bmFtZXMoY3Rfbm1HNUZiX21vMV9kc21lZCkpDQpyb3duYW1lcyhjdF9ubUc1RmJfbW8xX2RzbWVkKSA8LSBOVUxMDQpjdF9ubUc1RmJfbW8xX2RzbWVkIDwtIHJiaW5kKGN0X25tRzVGYl9tbzFfZHNtZWQsIGRhdGEuZnJhbWUoRXN0aW1hdGUgPSBOQSwgTG93PU5BLCBIaWdoPU5BLCBzb3AuY2F0Y2g9TkEsIFllYXI9YXMuaW50ZWdlcigyMDI0KSkpDQphc3VtX25tRzVGYl9tbzFfZHNtZWQgPC0gbWVyZ2UoeCA9IGFzdW1fbm1HNUZiX21vMV9kc21lZCwgeSA9IGN0X25tRzVGYl9tbzFfZHNtZWQsIGJ5ID0gIlllYXIiKQ0KY29sbmFtZXMoYXN1bV9ubUc1RmJfbW8xX2RzbWVkKSA8LSBjKCJZZWFyIiwgIlJfYWdlMSIsICJSbG93IiwgIlJoaWdoIiwgIlNTQiIsICJTU0Jsb3ciLCAiU1NCaGlnaCIsICJGYmFyIiwgIkZsb3ciLCAiRmhpZ2giLCAiQ2F0Y2hFc3QiLCAiQ2F0Y2hsb3ciLCAiQ2F0Y2hoaWdoIiwgIkNhdGNoT2JzIikNCiM9PT09PQ0KYGBgDQoNCiMjIyBGaXRzIHRvIGRhdGENCldoZW4gdGhlIG1vZGVsIGlzIHJ1biB3ZSBjYW4gZWFzaWx5IHNlZSBmcm9tIHdhcm5pbmdzL2Vycm9ycyBpZiB0aGVyZSBpcyBhIGNvbnZlcmdlbmNlIGlzc3VlLiAgSG93ZXZlciwgd2UgY2FuIGFsc28gY29uZmlybSB0aGlzLCBleHBsaWNpdGx5Og0KDQotIFRoZSBmaW5hbCBtb2RlbCBncmFkaWVudDogYHIgZml0X25tRzVGYl9tbzFfZHNtZWQkb3B0JGV2YWx1YXRpb25zWzJdYA0KLSBUaGF0IHRoZXJlIGlzIGEgcG9zaXRpdmUgZGVmaW5pdGUgaGVzc2lhbjogYHIgYWxsKGVpZ2VuKGZpdF9ubUc1RmJfbW8xX2RzbWVkJG9wdCRoZSkkdmFsdWVzID4wKWANCg0KRnVydGhlcm1vcmUsIFNBTSBkb2VzIG5vdCB1dGlsaXNlICJib3VuZHMiIHdoZW4gZml0dGluZyB0aGUgbW9kZWwsIGFuZCB0aGVyZWZvcmUsIGFzIHN0YW5kYXJkIGNoZWNrIG9mIHdoZXRoZXIgbW9kZWwgcGFyYW1ldGVycyBhcmUgYXBwcm9hY2hpbmcgdGhlaXIgYm91bmRzIGlzIGlycmVsZXZhbnQuDQoNCiMjIyMgVmlzdWFsaXNlIGZpdHMgdG8gZGF0YSBieSBhZ2Ugb3ZlciB0aW1lIGFjcm9zcyBmbGVldHMNCg0KYGBge3IgZmlnLmNhcD0iTW9kZWwgd2l0aCBtZWRpdW0gZGlzY2FyZCBzdXJ2aXZhbCBlc3RpbWF0ZXMsIGZpdCB0byBjYXRjaCBkYXRhIGJ5IGFnZSAodmFsdWVzIG9uIHRoZSBtb2RlbCBsaW5rIGZ1bmN0aW9uIHNjYWxlKS4ifQ0KIyMgRXh0cmFjdCBkYXRhIGZyb20gbW9kZWwgb2JqZWN0DQpsb2dPYnNfbm1HNUZiX21vMV9kc21lZCA8LSBzcGxpdChmaXRfbm1HNUZiX21vMV9kc21lZCRkYXRhJGxvZ29icywgY2VpbGluZyhzZXFfYWxvbmcoZml0X25tRzVGYl9tbzFfZHNtZWQkZGF0YSRsb2dvYnMpL2ZpdF9ubUc1RmJfbW8xX2RzbWVkJGRhdGEkbWF4QWdlUGVyRmxlZXRbMV0pKQ0KbG9nUHJlZF9ubUc1RmJfbW8xX2RzbWVkIDwtIHNwbGl0KGZpdF9ubUc1RmJfbW8xX2RzbWVkJHJlcCRwcmVkT2JzLCBjZWlsaW5nKHNlcV9hbG9uZyhmaXRfbm1HNUZiX21vMV9kc21lZCRyZXAkcHJlZE9icykvZml0X25tRzVGYl9tbzFfZHNtZWQkZGF0YSRtYXhBZ2VQZXJGbGVldFsxXSkpDQoNCiMjIFRyYW5zZm9ybSBkYXRhIHRvIHVzZWFibGUgZGF0YWZyYW1lcw0KIyMjIEluaXRpYWxpemUgYW4gZW1wdHkgZGF0YSBmcmFtZSBmb3Igb2JzZXJ2YXRpb25zDQpsb2dPYnNfbm1HNUZiX21vMV9kc21lZF9kZiA8LSBkYXRhLmZyYW1lKGFnZSA9IGludGVnZXIoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmxlZXQgPSBpbnRlZ2VyKCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllYXIgPSBpbnRlZ2VyKCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZ09icyA9IG51bWVyaWMoKSkNCg0KIyMjIFBvcHVsYXRlIHRoZSBkYXRhIGZyYW1lIGZvciBvYnNlcnZhdGlvbnMNCmZvciAoaSBpbiBzZXFfYWxvbmcobG9nT2JzX25tRzVGYl9tbzFfZHNtZWQpKSB7DQogICMgQ2FsY3VsYXRlIHRoZSBncm91cCBhbmQgeWVhcg0KICB5ZWFyIDwtICgoaSAtIDEpICUvJSAzKSArIDENCiAgZmxlZXQgPC0gKChpIC0gMSkgJSUgMykgKyAxDQogIA0KICAjIyMgQ3JlYXRlIGEgdGVtcG9yYXJ5IGRhdGEgZnJhbWUgYW5kIGFwcGVuZCB0byB0aGUgbWFpbiBkYXRhIGZyYW1lIGZvciBvYnNlcnZhdGlvbnMNCiAgdGVtcF9kZiA8LSBkYXRhLmZyYW1lKGFnZSA9IDE6NywNCiAgICAgICAgICAgICAgICAgICAgICAgIGZsZWV0ID0gZmxlZXQsDQogICAgICAgICAgICAgICAgICAgICAgICB5ZWFyID0geWVhcisyMDAxLA0KICAgICAgICAgICAgICAgICAgICAgICAgbG9nT2JzID0gbG9nT2JzX25tRzVGYl9tbzFfZHNtZWRbW2ldXSkNCiAgbG9nT2JzX25tRzVGYl9tbzFfZHNtZWRfZGYgPC0gcmJpbmQobG9nT2JzX25tRzVGYl9tbzFfZHNtZWRfZGYsIHRlbXBfZGYpDQp9DQoNCiMjIyBJbml0aWFsaXplIGFuIGVtcHR5IGRhdGEgZnJhbWUgZm9yIHByZWRpY3Rpb25zDQpsb2dQcmVkX25tRzVGYl9tbzFfZHNtZWRfZGYgPC0gZGF0YS5mcmFtZShhZ2UgPSBpbnRlZ2VyKCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmbGVldCA9IGludGVnZXIoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllYXIgPSBpbnRlZ2VyKCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2dQcmVkID0gbnVtZXJpYygpKQ0KDQojIyMgUG9wdWxhdGUgdGhlIGRhdGEgZnJhbWUgZm9yIHByZWRpY3Rpb25zDQpmb3IgKGkgaW4gc2VxX2Fsb25nKGxvZ1ByZWRfbm1HNUZiX21vMV9kc21lZCkpIHsNCiAgIyBDYWxjdWxhdGUgdGhlIGdyb3VwIGFuZCB5ZWFyDQogIHllYXIgPC0gKChpIC0gMSkgJS8lIDMpICsgMQ0KICBmbGVldCA8LSAoKGkgLSAxKSAlJSAzKSArIDENCiAgDQogICMjIyBDcmVhdGUgYSB0ZW1wb3JhcnkgZGF0YSBmcmFtZSBhbmQgYXBwZW5kIHRvIHRoZSBtYWluIGRhdGEgZnJhbWUgZm9yIHByZWRpY3Rpb25zDQogIHRlbXBfZGYgPC0gZGF0YS5mcmFtZShhZ2UgPSAxOjcsDQogICAgICAgICAgICAgICAgICAgICAgICBmbGVldCA9IGZsZWV0LA0KICAgICAgICAgICAgICAgICAgICAgICAgeWVhciA9IHllYXIrMjAwMSwNCiAgICAgICAgICAgICAgICAgICAgICAgIGxvZ1ByZWQgPSBsb2dQcmVkX25tRzVGYl9tbzFfZHNtZWRbW2ldXSkNCiAgbG9nUHJlZF9ubUc1RmJfbW8xX2RzbWVkX2RmIDwtIHJiaW5kKGxvZ1ByZWRfbm1HNUZiX21vMV9kc21lZF9kZiwgdGVtcF9kZikNCn0NCg0KIyMgUGxvdA0KbG9nUHJlZF9ubUc1RmJfbW8xX2RzbWVkX2RmJGFnZSA8LSBhcy5jaGFyYWN0ZXIobG9nUHJlZF9ubUc1RmJfbW8xX2RzbWVkX2RmJGFnZSkNCmxvZ09ic19ubUc1RmJfbW8xX2RzbWVkX2RmJGFnZSA8LSBhcy5jaGFyYWN0ZXIobG9nT2JzX25tRzVGYl9tbzFfZHNtZWRfZGYkYWdlKQ0KDQpnZ3Bsb3RseShnZ3Bsb3QoKSsNCiAgICAgICAgICAgZ2VvbV9wb2ludChkYXRhID0gbG9nT2JzX25tRzVGYl9tbzFfZHNtZWRfZGZbbG9nT2JzX25tRzVGYl9tbzFfZHNtZWRfZGYkZmxlZXQgPT0gMSAmIGxvZ09ic19ubUc1RmJfbW8xX2RzbWVkX2RmJHllYXIgIT0gKERhdGFZZWFyKzEpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IHllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gbG9nT2JzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gYWdlKSwNCiAgICAgICAgICAgICAgICAgICAgICBzaGFwZSA9IDIxKSArDQogICAgICAgICAgIGdlb21fbGluZShkYXRhID0gbG9nUHJlZF9ubUc1RmJfbW8xX2RzbWVkX2RmW2xvZ1ByZWRfbm1HNUZiX21vMV9kc21lZF9kZiRmbGVldCA9PSAxICYgbG9nUHJlZF9ubUc1RmJfbW8xX2RzbWVkX2RmJHllYXIgIT0gKERhdGFZZWFyKzEpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0geWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGxvZ1ByZWQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IGFnZSkpICsNCiAgICAgICAgICAgZmFjZXRfd3JhcChmYWNldHMgPSAiYWdlIikgKyAjLCBzY2FsZXMgPSAiZnJlZV95IikgKw0KICAgICAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gZWJwYWwsIGd1aWRlID0gRkFMU0UpICsNCiAgICAgICAgICAgZ3VpZGVzKGNvbG91cj1GQUxTRSwgc2hhcGU9RkFMU0UpICsNCiAgICAgICAgICAgdGhlbWVfZmV3KCkpDQoNCiMgZml0cGxvdChmaXRfbm1HNUZiX21vMV9kc21lZCwgZmxlZXRzPTEpDQpgYGANCg0KYGBge3IgZmlnLmNhcD0iTW9kZWwgd2l0aCBtZWRpdW0gZGlzY2FyZCBzdXJ2aXZhbCBlc3RpbWF0ZXMsIGZpdCB0byBRMSBzdXJ2ZXkgZGF0YSBieSBhZ2UgKHZhbHVlcyBvbiB0aGUgbW9kZWwgbGluayBmdW5jdGlvbiBzY2FsZSkuIn0NCmdncGxvdGx5KGdncGxvdCgpKw0KICAgICAgICAgICBnZW9tX3BvaW50KGRhdGEgPSBsb2dPYnNfbm1HNUZiX21vMV9kc21lZF9kZltsb2dPYnNfbm1HNUZiX21vMV9kc21lZF9kZiRmbGVldCA9PSAyICYgbG9nT2JzX25tRzVGYl9tbzFfZHNtZWRfZGYkeWVhciAhPSAoRGF0YVllYXIrMSksIF0sDQogICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0geWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBsb2dPYnMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBhZ2UpLA0KICAgICAgICAgICAgICAgICAgICAgIHNoYXBlID0gMjEpICsNCiAgICAgICAgICAgZ2VvbV9saW5lKGRhdGEgPSBsb2dQcmVkX25tRzVGYl9tbzFfZHNtZWRfZGZbbG9nUHJlZF9ubUc1RmJfbW8xX2RzbWVkX2RmJGZsZWV0ID09IDIgJiBsb2dQcmVkX25tRzVGYl9tbzFfZHNtZWRfZGYkeWVhciAhPSAoRGF0YVllYXIrMSksIF0sDQogICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSB5ZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gbG9nUHJlZCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gYWdlKSkgKw0KICAgICAgICAgICBmYWNldF93cmFwKGZhY2V0cyA9ICJhZ2UiKSArICMsIHNjYWxlcyA9ICJmcmVlX3kiKSArDQogICAgICAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBlYnBhbCwgZ3VpZGUgPSBGQUxTRSkgKw0KICAgICAgICAgICBndWlkZXMoY29sb3VyPUZBTFNFLCBzaGFwZT1GQUxTRSkgKw0KICAgICAgICAgICB0aGVtZV9mZXcoKSkNCiMgZml0cGxvdChmaXRfbm1HNUZiX21vMV9kc21lZCwgZmxlZXRzPTIpDQpgYGANCg0KYGBge3IgZmlnLmNhcD0iTW9kZWwgd2l0aCBtZWRpdW0gZGlzY2FyZCBzdXJ2aXZhbCBlc3RpbWF0ZXMsIGZpdCB0byBRMy80IHN1cnZleSBkYXRhIGJ5IGFnZSAodmFsdWVzIG9uIHRoZSBtb2RlbCBsaW5rIGZ1bmN0aW9uIHNjYWxlKS4ifQ0KZ2dwbG90bHkoZ2dwbG90KCkrDQogICAgICAgICAgIGdlb21fcG9pbnQoZGF0YSA9IGxvZ09ic19ubUc1RmJfbW8xX2RzbWVkX2RmW2xvZ09ic19ubUc1RmJfbW8xX2RzbWVkX2RmJGZsZWV0ID09IDMgJiBsb2dPYnNfbm1HNUZiX21vMV9kc21lZF9kZiR5ZWFyICE9IChEYXRhWWVhcisxKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSB5ZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGxvZ09icywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IGFnZSksDQogICAgICAgICAgICAgICAgICAgICAgc2hhcGUgPSAyMSkgKw0KICAgICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IGxvZ1ByZWRfbm1HNUZiX21vMV9kc21lZF9kZltsb2dQcmVkX25tRzVGYl9tbzFfZHNtZWRfZGYkZmxlZXQgPT0gMyAmIGxvZ1ByZWRfbm1HNUZiX21vMV9kc21lZF9kZiR5ZWFyICE9IChEYXRhWWVhcisxKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeCA9IHllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBsb2dQcmVkLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBhZ2UpKSArDQogICAgICAgICAgIGZhY2V0X3dyYXAoZmFjZXRzID0gImFnZSIpICsgIywgc2NhbGVzID0gImZyZWVfeSIpICsNCiAgICAgICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGVicGFsLCBndWlkZSA9IEZBTFNFKSArDQogICAgICAgICAgIGd1aWRlcyhjb2xvdXI9RkFMU0UsIHNoYXBlPUZBTFNFKSArDQogICAgICAgICAgIHRoZW1lX2ZldygpKQ0KDQojIGZpdHBsb3QoZml0X25tRzVGYl9tbzFfZHNtZWQsIGZsZWV0cz0zKQ0KYGBgDQoNCmBgYHtyIGZpZy5jYXA9IlN0YW5kYXJkIERldmF0aW9ucyBieSBGbGVldDsgbWVkaXVtIGRpc2NhcmQgc3Vydml2YWwgZXN0aW1hdGVzLiIsIGhlaWdodD0xMH0NCnNkcGxvdChmaXRfbm1HNUZiX21vMV9kc21lZCwgbWFyZyA9IGMoNSw0LDEsMSkpDQpgYGANCg0KIyMjIyBSZXNpZHVhbHMNCmBgYHtyIGNhbGN1bGF0ZVJlc2lkdWFsc19ubUc1RmJfbW8xX2RzbWVkLCB3YXJuaW5nPUZBTFNFLCByZXN1bHRzPSdoaWRlJ30NCnJlc2lkX25tRzVGYl9tbzFfZHNtZWQgPC0gcmVzaWR1YWxzKGZpdF9ubUc1RmJfbW8xX2RzbWVkKQ0KcmVzaWRfbm1HNUZiX21vMV9kc21lZF9kZiA8LSBkYXRhLmZyYW1lKHllYXIgPSByZXNpZF9ubUc1RmJfbW8xX2RzbWVkJHllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmxlZXQgPSByZXNpZF9ubUc1RmJfbW8xX2RzbWVkJGZsZWV0LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFnZSA9IHJlc2lkX25tRzVGYl9tbzFfZHNtZWQkYWdlLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9ic2VydmF0aW9uID0gcmVzaWRfbm1HNUZiX21vMV9kc21lZCRvYnNlcnZhdGlvbiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZWFuID0gcmVzaWRfbm1HNUZiX21vMV9kc21lZCRtZWFuLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc2lkdWFsID0gcmVzaWRfbm1HNUZiX21vMV9kc21lZCRyZXNpZHVhbCkNCnJlc2lkX25tRzVGYl9tbzFfZHNtZWRfZGYkZmxlZXROYW1lIDwtIGlmZWxzZShyZXNpZF9ubUc1RmJfbW8xX2RzbWVkX2RmJGZsZWV0ID09IDEsIGF0dHJpYnV0ZXMocmVzaWRfbm1HNUZiX21vMV9kc21lZCkkZmxlZXROYW1lc1sxXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKHJlc2lkX25tRzVGYl9tbzFfZHNtZWRfZGYkZmxlZXQgPT0gMiwgYXR0cmlidXRlcyhyZXNpZF9ubUc1RmJfbW8xX2RzbWVkKSRmbGVldE5hbWVzWzJdLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKHJlc2lkX25tRzVGYl9tbzFfZHNtZWRfZGYkZmxlZXQgPT0gMywgYXR0cmlidXRlcyhyZXNpZF9ubUc1RmJfbW8xX2RzbWVkKSRmbGVldE5hbWVzWzNdLCBOQSkpKQ0KDQpyZXNpZF9ubUc1RmJfbW8xX2RzbWVkX2RmJGZsZWV0QWx0TmFtZSA8LSBpZmVsc2UocmVzaWRfbm1HNUZiX21vMV9kc21lZF9kZiRmbGVldCA9PSAxLCAiUmVzaWR1YWwgRmlzaGluZyIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShyZXNpZF9ubUc1RmJfbW8xX2RzbWVkX2RmJGZsZWV0ID09IDIsICJRMSBTdXJ2ZXlzIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShyZXNpZF9ubUc1RmJfbW8xX2RzbWVkX2RmJGZsZWV0ID09IDMsICJRMy80IFN1cnZleXMiLCBOQSkpKQ0KYGBgDQoNCmBgYHtyIGZpZy5jYXA9IkVzdGltYXRlZCBjb3JyZWxhdGlvbnMgaW4gcmVzaWR1YWwgdmFyaWF0aW9uIGJldHdlZW4gYWdlcyBmb3IgZWFjaCBvZiB0aGUgZmlzaGluZyBmbGVldCAodG9wKSBhbmQgdGhlIHR3byBzdXJ2ZXlzIChtaWRkbGUgJiBib3R0b20pLCBmcm9tIHRoZSBNb2RlbCB3aXRoIG1lZGl1bSBkaXNjYXJkIG1vcnRhbGl0eS4ifQ0KDQppZighYWxsKGZpdF9ubUc1RmJfbW8xX2RzbWVkJGNvbmYkb2JzQ29yU3RydWN0PT0iSUQiKSl7IA0KICBjb3JwbG90KGZpdF9ubUc1RmJfbW8xX2RzbWVkKQkJCSAgDQogICMgc2V0Y2FwKCJFc3RpbWF0ZWQgY29ycmVsYXRpb25zIiwgIkVzdGltYXRlcyBjb3JyZWxhdGlvbnMgYmV0d2VlbiBhZ2UgZ3JvdXBzIGZvciBlYWNoIGZsZWV0IikNCiAgIyBzdGFtcGl0KGZpdCkNCn0gZWxzZSB7DQogIHByaW50KCJObyBjb3JyZWxhdGlvbiBzdHJ1Y3R1cmUgY29uZmlndXJlZCBmb3IgcmVzaWR1YWxzIGFjcm9zcyBhZ2UuIikNCn0NCg0KYGBgDQoNCmBgYHtyIGZpZy5jYXA9Ik9uZSBvYnNlcnZhdGlvbiBhaGVhZCByZXNpZHVhbHMgZm9yIHRoZSB0aHJlZSBmbGVldHMgKHJlZC9waW5rID0gb2JzZXJ2YXRpb24gbG93ZXIgdGhhbiBtb2RlbCBlc3RpbWF0ZSwgYmx1ZSA9IG9ic2VydmF0aW9uIGhpZ2hlciB0aGFuIG1vZGVsIGVzdGltYXRlLCBzaXplID0gbWFnbml0dWRlIG9mIHJlc2lkdWFsKSwgZnJvbSB0aGUgTW9kZWwgd2l0aCBtZWRpdW0gZGlzY2FyZCBtb3J0YWxpdHkuIn0NCmdncGxvdGx5KGdncGxvdChyZXNpZF9ubUc1RmJfbW8xX2RzbWVkX2RmKSArDQogICAgICAgICAgIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0geWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBhZ2UsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gYWJzKHJlc2lkdWFsKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IHJlc2lkdWFsID49IDApLA0KICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC43KSArDQogICAgICAgICAgIGZhY2V0X2dyaWQocm93cyA9ICJmbGVldEFsdE5hbWUiKSArDQogICAgICAgICAgIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiVFJVRSIgPSBlYnBhbFs4XSwgIkZBTFNFIiA9IGVicGFsWzldKSkgKw0KICAgICAgICAgICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygtMSwgOSksIGJyZWFrcyA9IGMoMTo5KSkgKw0KICAgICAgICAgICBndWlkZXMoY29sb3VyPUZBTFNFKSArDQogICAgICAgICAgIHRoZW1lX2ZldygpKQ0KDQpgYGANCg0KIyMjIyBKaXR0ZXJpbmcNCldlIGNhbiBhbHNvIHRlc3QgdG8gc2VlIGlmIHRoZSBtb2RlbCBpcyBjb252ZXJnaW5nIG9uIHNvbWUgbG9jYWwgbWluaW11bSAoaS5lLiBpdCdzIGZpdHRpbmcgdG8gc29tZSBzb2x1dGlvbiBjbG9zZSB0byBpbml0aWFsaXNpbmcgdmFsdWVzIHRoYXQgcmVwcmVzZW50cyBub2lzZSBhbmQgbm90IHRoZSBnbG9iYWwgc29sdXRpb24sIHRoYXQgaXMgdGhlIHByb3BlciBzb2x1dGlvbikuICBUbyBkbyB0aGlzLCB3ZSBhZGQgcmFuZG9tIG5vaXNlIHRvIHRoZSBpbml0aWFsIHBhcmFtZXRlciB2YWx1ZXMgdG8gc2VlIGlmIHRoZSBtb2RlbCB3aWxsIGNvbnZlcmdlIG9uIGEgZGlmZmVyZW50IG1pbmltdW0gaW4gaXQncyBkYXRhLXNwYWNlLiBUaGUgZWFzaWVzdCB3YXkgdG8gaW52ZXN0aWdhdGUgdGhpcyBpcyB0byBzZWUgaWYgdGhlIG1vZGVsIGZpdHMgdmFyeSBhbG90IGRlcGVuZGluZyBvbiB0aGUgc3RhcnRpbmcgdmFsdWVzOg0KYGBge3IgSml0dGVyX25tRzVGYl9tbzFfZHNtZWR9DQpqaXRfbm1HNUZiX21vMV9kc21lZCA8LSBqaXQoZml0ID0gZml0X25tRzVGYl9tbzFfZHNtZWQpDQoNCm10IDwtIGFzLmRhdGEuZnJhbWUobW9kZWx0YWJsZShqaXRfbm1HNUZiX21vMV9kc21lZCkpDQptdCRtb2RlbCA8LSByb3duYW1lcyhtdCkNCnJvd25hbWVzKG10KSA8LSBOVUxMDQoNCmthYmxlKHggPSBtdCwNCiAgICAgIGRpZ2l0cyA9IDMsDQogICAgICBjYXB0aW9uID0gIk1lYXN1cmVzIG9mICBmaXQgZm9yIGEgc2VyaWVzIG9mIG1vZGVsIHJlZml0cyB3aXRoIGppdHRlciBhcHBsaWVkIHRvIHRoZSBpbnB1dCBwYXJhbWV0ZXJzLiIpDQpgYGANCg0KIyMjIyBMZWF2ZS1PbmUtT3V0IEFuYWx5c2VzDQpBIGxlYXZlLW9uZS1vdXQgYW5hbHlzaXMgaXMgYSBmb3JtIG9mIHNlbnNpdGl2aXR5IGFuYWx5c2lzLCBzaG93aW5nIHRoZSBpbXBhY3QgdGhlIGRhdGEgZnJvbSBlYWNoIHR1bmluZyBmbGVldCBoYXMgb24gdGhlIGVzdGltYXRpb24gb2YgdGhlIGtleSB2YXJpYWJsZXMgYmVpbmcgZXN0aW1hdGVkOyBuYW1lbHkgU1NCLCBGIGFuZCByZWNydWl0bWVudC4gIA0KDQpGaXJzdCB3ZSBtdXN0IHJ1biB0aGUgbGVhdmUtb25lLW91dCBhbmFseXNpcyB3aGljaCByZWZpdHMgdGhlIG1vZGVsIGluIHR3byBpdGVyYXRpb25zLCByZW1vdmluZyBvbmUgc3VydmV5IGF0IGEgdGltZS4gVGhlbiB3ZSBjYW4gcGxvdCBlYWNoIG9mIHRoZXNlIG5ldyBtb2RlbCBmaXRzIG92ZXIgdGhlIGZ1bGwgbW9kZWwgdG8gc2VlIHRoZSBpbXBhY3QgdGhlIHJlbW92YWwgb2YgZWFjaCBoYXMuIA0KDQpgYGB7ciBMZWF2ZU9uZU91dF9ubUc1RmJfbW8xX2RzbWVkfQ0KTE9fbm1HNUZiX21vMV9kc21lZCA8LSBsZWF2ZW91dChmaXRfbm1HNUZiX21vMV9kc21lZCkNCg0KIz09PSANCiMgR2V0IGRhdGEgZnJvbSBzYW0gb2JqZWN0cyBhbmQgZ2VuZXJhdGUgdXNlYWJsZSBkYXRhZnJhbWVzDQojPT09PQ0KcTFtYXQgPC0gYXMuZGF0YS5mcmFtZShzdW1tYXJ5KExPX25tRzVGYl9tbzFfZHNtZWQkYHcuby4gUTFJQlRTK0JJVFMrQ29kU0QyMS0yNWApKQ0KcTNtYXQgPC0gYXMuZGF0YS5mcmFtZShzdW1tYXJ5KExPX25tRzVGYl9tbzFfZHNtZWQkYHcuby4gUTM0SUJUUytCSVRTK0NvZFNEMjEtMjVgKSkNCg0KDQp3b3ExIDwtIGRhdGEuZnJhbWUoWWVhciA9IGFzLmludGVnZXIocm93Lm5hbWVzKHN1bW1hcnkoTE9fbm1HNUZiX21vMV9kc21lZCRgdy5vLiBRMUlCVFMrQklUUytDb2RTRDIxLTI1YCkpKSwNCiAgICAgICAgICAgICAgICAgICBTU0IgPSBxMW1hdCRTU0IsDQogICAgICAgICAgICAgICAgICAgRmJhciA9IHExbWF0JGBGYmFyKDMtNSlgLA0KICAgICAgICAgICAgICAgICAgIFJfYWdlMSA9IHExbWF0JGBSKGFnZSAxKWAsDQogICAgICAgICAgICAgICAgICAgQ2F0Y2hFc3QgPSBjYXRjaHRhYmxlKExPX25tRzVGYl9tbzFfZHNtZWQkYHcuby4gUTFJQlRTK0JJVFMrQ29kU0QyMS0yNWApWywxXSwNCiAgICAgICAgICAgICAgICAgICBzZXJpZXMgPSByZXAoIndvX1ExIiwgdGltZXMgPSBucm93KHExbWF0KSkpDQoNCndvcTM0IDwtIGRhdGEuZnJhbWUoWWVhciA9IGFzLmludGVnZXIocm93Lm5hbWVzKHEzbWF0WygyMDAyOkRhdGFZZWFyKS0yMDAxLF0pKSwNCiAgICAgICAgICAgICAgICAgICAgU1NCID0gcTNtYXRbKDIwMDI6RGF0YVllYXIpLTIwMDEsICJTU0IiXSwNCiAgICAgICAgICAgICAgICAgICAgRmJhciA9IHEzbWF0WygyMDAyOkRhdGFZZWFyKS0yMDAxLCJGYmFyKDMtNSkiXSwNCiAgICAgICAgICAgICAgICAgICAgUl9hZ2UxID0gcTNtYXRbKDIwMDI6RGF0YVllYXIpLTIwMDEsIlIoYWdlIDEpIl0sDQogICAgICAgICAgICAgICAgICAgIENhdGNoRXN0ID0gY2F0Y2h0YWJsZShMT19ubUc1RmJfbW8xX2RzbWVkJGB3Lm8uIFEzNElCVFMrQklUUytDb2RTRDIxLTI1YClbLDFdLA0KICAgICAgICAgICAgICAgICAgICBzZXJpZXMgPSByZXAoIndvX1EzNCIsIHRpbWVzID0gKG5yb3cocTNtYXQpLTEpKSkNCg0KDQphc3VtX25tRzVGYl9tbzFfZHNtZWQkc2VyaWVzIDwtIHJlcCgiZnVsbCIsIHRpbWVzID0gbnJvdyhhc3VtX25tRzVGYl9tbzFfZHNtZWQpKQ0KYXN1bWlfbm1HNUZiX21vMV9kc21lZCA8LSBhc3VtX25tRzVGYl9tbzFfZHNtZWRbLCBjKCJZZWFyIiwgIlNTQiIsICJGYmFyIiwgIlJfYWdlMSIsICJDYXRjaEVzdCIgLCJzZXJpZXMiKV0NCiM9PT09PQ0KDQpsb3N1bV9ubUc1RmJfbW8xX2RzbWVkIDwtIHJiaW5kKHdvcTEsIHdvcTM0LCBhc3VtaV9ubUc1RmJfbW8xX2RzbWVkKQ0KDQpgYGANCg0KYGBge3IgZmlnLmNhcD0iTGVhdmUtb25lLW91dCByZS1maXRzIGZvciB0aGUgbW9kZWwgd2l0aCBtZWRpdW0gZGlzY2FyZCBzdXJ2aXZhbCAod2l0aG91dCBRMSBzdXJ2ZXkgPSBibHVlLCB3aXRob3V0IFEzLzQgc3VydmV5ID0gcHVycGxlKSwgb3ZlcmxhaW4gd2l0aCBmdWxsIG1vZGVsIGVzdGltYXRlcyAoYmxhY2sgbGluZSBhbmQgZ3JleSByaWJib24pIG9mIFNTQiAodG9wIGxlZnQpLCBGICh0b3AgcmlnaHQpLCBSZWNydWl0bWVudCAoYm90dG9tIGxlZnQpLCBhbmQgY2F0Y2ggKGJvdHRvbSByaWdodDsgb2JzZXJ2YXRpb25zIGFzIHllbGxvdyArKS4ifQ0KIyBzc2JwbG90KExPKQ0KbG9zc2Jfbm1HNUZiX21vMV9kc21lZCA8LSBnZ3Bsb3RseShnZ3Bsb3QoKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9saW5lKGRhdGEgPSBsb3N1bV9ubUc1RmJfbW8xX2RzbWVkLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PVNTQiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBzZXJpZXMpKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9yaWJib24oZGF0YSA9IGFzdW1fbm1HNUZiX21vMV9kc21lZCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW49U1NCbG93LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1heD1TU0JoaWdoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gImJsYWNrIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMikgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiYmxhY2siLCBlYnBhbFs4OjldKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2NsZWFuKCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKGF4aXMudGl0bGUueS5sZWZ0ID0gZWxlbWVudF90ZXh0KHZqdXN0ID0gLTAuMDUsIGhqdXN0ID0gMC45NSkpKQ0KDQojIEZwbG90KExPKQ0KbG9mX25tRzVGYl9tbzFfZHNtZWQgPC0gZ2dwbG90bHkoZ2dwbG90KCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IGxvc3VtX25tRzVGYl9tbzFfZHNtZWQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1GYmFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBzZXJpZXMpKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fcmliYm9uKGRhdGEgPSBhc3VtX25tRzVGYl9tbzFfZHNtZWQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW49RmxvdywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4PUZoaWdoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9ICJibGFjayIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4zKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiYmxhY2siLCBlYnBhbFs4OjldKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9jbGVhbigpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWUoYXhpcy50aXRsZS55LmxlZnQgPSBlbGVtZW50X3RleHQodmp1c3QgPSAtMC4wNSwgaGp1c3QgPSAwLjk1KSkpDQoNCiMgcmVjcGxvdChMTykNCmxvcmVjX25tRzVGYl9tbzFfZHNtZWQgPC0gZ2dwbG90bHkoZ2dwbG90KCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fbGluZShkYXRhID0gbG9zdW1fbm1HNUZiX21vMV9kc21lZCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1SX2FnZTEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gc2VyaWVzKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fcmliYm9uKGRhdGEgPSBhc3VtX25tRzVGYl9tbzFfZHNtZWQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWluPVJsb3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4PVJoaWdoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gImJsYWNrIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMykgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiYmxhY2siLCBlYnBhbFs4OjldKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2NsZWFuKCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKGF4aXMudGl0bGUueS5sZWZ0ID0gZWxlbWVudF90ZXh0KHZqdXN0ID0gLTAuMDUsIGhqdXN0ID0gMC45NSkpKQ0KDQojIENhdGNoIHBsb3QgKExPKQ0KbG9jYV9ubUc1RmJfbW8xX2RzbWVkIDwtIGdncGxvdGx5KGdncGxvdCgpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fbGluZShkYXRhID0gbG9zdW1fbm1HNUZiX21vMV9kc21lZCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9Q2F0Y2hFc3QsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBzZXJpZXMpKSsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fcmliYm9uKGRhdGEgPSBhc3VtX25tRzVGYl9tbzFfZHNtZWRbYXN1bV9ubUc1RmJfbW8xX2RzbWVkJFllYXIgIT0gKERhdGFZZWFyKzEpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW49Q2F0Y2hsb3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltYXg9Q2F0Y2hoaWdoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSAiYmxhY2siLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjMpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fcG9pbnQoZGF0YSA9IGFzdW1fbm1HNUZiX21vMV9kc21lZFthc3VtX25tRzVGYl9tbzFfZHNtZWQkWWVhciAhPSAoRGF0YVllYXIrMSksIF0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9Q2F0Y2hPYnMpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaGFwZSA9IDMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IGVicGFsWzVdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gZWJwYWxbNV0pICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHlsYWIoIkNhdGNoICh0b25uZXMpIikgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCJibGFjayIsIGVicGFsWzg6OV0pKSsgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9jbGVhbigpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKGF4aXMudGl0bGUueS5sZWZ0ID0gZWxlbWVudF90ZXh0KHZqdXN0ID0gLTAuMDUsIGhqdXN0ID0gMC45NSkpKQ0KDQpsYXlvdXQoc3VicGxvdChsb3NzYl9ubUc1RmJfbW8xX2RzbWVkLCBsb2Zfbm1HNUZiX21vMV9kc21lZCwgbG9yZWNfbm1HNUZiX21vMV9kc21lZCwgbG9jYV9ubUc1RmJfbW8xX2RzbWVkLCBucm93cyA9IDIsIHNoYXJlWCA9IFRSVUUsIHRpdGxlWSA9IFRSVUUpLCBzaG93bGVnZW5kPUZBTFNFKQ0KYGBgDQoNCiMjIyMgUmV0cm9zcGVjdGl2ZXMNCmBgYHtyIGNhbGN1bGF0ZVJldHJvc19ubUc1RmJfbW8xX2RzbWVkfQ0KIz09PQ0KIyBDcmVhdGUgZGF0YWZyYW1lIG9mIGN1cnJlbnQgeWVhcidzIGZpdCBmb3IgcGxvdHRpbmcNCiM9PT09DQojIElDX2FnZ190ZW1wIDwtIGFnZ3JlZ2F0ZShDQVRPTn5ZZWFyLCBpY19jbGVhbltpY19jbGVhbiRDYXRjaENhdGVnb3J5ICVpbiUgYygiTGFuZGluZ3MiLCAiRGlzY2FyZHMiKSwgXSwgRlVOID0gInN1bSIpDQphc3VtX25tRzVGYl9tbzFfZHNtZWQgPC0gYXMuZGF0YS5mcmFtZShzdW1tYXJ5KGZpdF9ubUc1RmJfbW8xX2RzbWVkKSkNCmFzdW1fbm1HNUZiX21vMV9kc21lZCRZZWFyIDwtIGFzLmludGVnZXIocm93Lm5hbWVzKHN1bW1hcnkoZml0X25tRzVGYl9tbzFfZHNtZWQpKSkNCmN0X25tRzVGYl9tbzFfZHNtZWQgPC0gYXMuZGF0YS5mcmFtZShjYXRjaHRhYmxlKGZpdF9ubUc1RmJfbW8xX2RzbWVkLCBvYnMuc2hvdyA9IFRSVUUpKQ0KY3Rfbm1HNUZiX21vMV9kc21lZCRZZWFyIDwtIGFzLmludGVnZXIocm93bmFtZXMoY3Rfbm1HNUZiX21vMV9kc21lZCkpDQpyb3duYW1lcyhjdF9ubUc1RmJfbW8xX2RzbWVkKSA8LSBOVUxMDQpjdF9ubUc1RmJfbW8xX2RzbWVkIDwtIHJiaW5kKGN0X25tRzVGYl9tbzFfZHNtZWQsIGRhdGEuZnJhbWUoRXN0aW1hdGUgPSBOQSwgTG93PU5BLCBIaWdoPU5BLCBzb3AuY2F0Y2g9TkEsIFllYXI9YXMuaW50ZWdlcigyMDI0KSkpDQphc3VtX25tRzVGYl9tbzFfZHNtZWQgPC0gbWVyZ2UoeCA9IGFzdW1fbm1HNUZiX21vMV9kc21lZCwgeSA9IGN0X25tRzVGYl9tbzFfZHNtZWQsIGJ5ID0gIlllYXIiKQ0KY29sbmFtZXMoYXN1bV9ubUc1RmJfbW8xX2RzbWVkKSA8LSBjKCJZZWFyIiwgIlJfYWdlMSIsICJSbG93IiwgIlJoaWdoIiwgIlNTQiIsICJTU0Jsb3ciLCAiU1NCaGlnaCIsICJGYmFyIiwgIkZsb3ciLCAiRmhpZ2giLCAiQ2F0Y2hFc3QiLCAiQ2F0Y2hsb3ciLCAiQ2F0Y2hoaWdoIiwgIkNhdGNoT2JzIikNCg0KYXN1bV9ubUc1RmJfbW8xX2RzbWVkJHNlcmllcyA8LSByZXAoImZ1bGwiLCB0aW1lcyA9IG5yb3coYXN1bV9ubUc1RmJfbW8xX2RzbWVkKSkNCg0KIz09PT09DQpSRVRST19ubUc1RmJfbW8xX2RzbWVkPC1yZXRybyhmaXRfbm1HNUZiX21vMV9kc21lZCwgeWVhcj01KQ0KcmhvX25tRzVGYl9tbzFfZHNtZWQgPC0gbW9obihSRVRST19ubUc1RmJfbW8xX2RzbWVkLCBsYWcgPSAxKQ0KDQojIyBNYWtlIFJFVFJPcyBpbiBiZXR0ZXIgcGxvdHRpbmcgZm9ybWF0DQpyZXRfbm1HNUZiX21vMV9kc21lZF9kZiA8LSBhc3VtX25tRzVGYl9tbzFfZHNtZWRbYXN1bV9ubUc1RmJfbW8xX2RzbWVkJFllYXIgIT0gbWF4KGFzdW1fbm1HNUZiX21vMV9kc21lZCRZZWFyKSwgXQ0KDQpmb3IoaSBpbiAxOmxlbmd0aChSRVRST19ubUc1RmJfbW8xX2RzbWVkKSl7DQogIHRzdW0gPC0gYXMuZGF0YS5mcmFtZShzdW1tYXJ5KFJFVFJPX25tRzVGYl9tbzFfZHNtZWRbW2ldXSkpDQogIHRzdW0kWWVhciA8LSBhcy5pbnRlZ2VyKHJvdy5uYW1lcyhzdW1tYXJ5KFJFVFJPX25tRzVGYl9tbzFfZHNtZWRbW2ldXSkpKQ0KICB0c3VtIDwtIGNiaW5kKHRzdW0sIGNhdGNodGFibGUoUkVUUk9fbm1HNUZiX21vMV9kc21lZFtbaV1dLCBvYnMuc2hvdyA9IFRSVUUpKQ0KICB0c3VtJHNlcmllcyA8LSBhcy5jaGFyYWN0ZXIocmVwKGksIG5yb3codHN1bSkpKQ0KICBjb2xuYW1lcyh0c3VtKSA8LSBjKCJSX2FnZTEiLCAiUmxvdyIsICJSaGlnaCIsICJTU0IiLCAiU1NCbG93IiwgIlNTQmhpZ2giLCAiRmJhciIsICJGbG93IiwgIkZoaWdoIiwgIlllYXIiLCAiQ2F0Y2hFc3QiLCAiQ2F0Y2hsb3ciLCAiQ2F0Y2hoaWdoIiwgIkNhdGNoT2JzIiwgInNlcmllcyIpDQogIHRzdW0gPC0gdHN1bVt0c3VtJFllYXIgIT0gbWF4KHRzdW0kWWVhciksIF0NCiAgcmV0X25tRzVGYl9tbzFfZHNtZWRfZGYgPC0gcmJpbmQocmV0X25tRzVGYl9tbzFfZHNtZWRfZGYsIHRzdW0pDQp9DQpyZXRfbm1HNUZiX21vMV9kc21lZF9kZiRzZXJpZXMgPC0gZmFjdG9yKHJldF9ubUc1RmJfbW8xX2RzbWVkX2RmJHNlcmllcywgbGV2ZWxzID0gYygiZnVsbCIsICIxIiwgIjIiLCAiMyIsICI0IiwgIjUiKSkNCmBgYA0KDQpgYGB7ciBmaWcuY2FwPSJSZXRyb3NwZWN0aXZlIGFuYWx5c2VzIGZvciBTU0IgKHRvcC1sZWZ0KSwgRiBmb3IgYWdlcyAzLTUgKHRvcC1yaWdodCksIHJlY3J1aXRtZW50IChib3R0b20tbGVmdCksIGFuZCBjYXRjaCAoYm90dG9tLXJpZ2h0KSwgZnJvbSB0aGUgbW9kZWwgd2l0aCBtZWRpdW0gZGlzY2FyZCBzdXJ2aXZhbC4ifQ0KIyBzc2JwbG90KFJFVFJPKQ0KcmV0c3NiX25tRzVGYl9tbzFfZHNtZWQgPC0gbGF5b3V0KGdncGxvdGx5KGdncGxvdCgpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fbGluZShkYXRhID0gcmV0X25tRzVGYl9tbzFfZHNtZWRfZGYsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PVNTQiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IHNlcmllcykpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fcmliYm9uKGRhdGEgPSBhc3VtX25tRzVGYl9tbzFfZHNtZWRbYXN1bV9ubUc1RmJfbW8xX2RzbWVkJFllYXIgIT0gbWF4KGFzdW1fbm1HNUZiX21vMV9kc21lZCRZZWFyKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWluPVNTQmxvdywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1heD1TU0JoaWdoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSAiYmxhY2siLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjIpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFubm90YXRlKGdlb20gPSAidGV4dCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gbWF4KHJldF9ubUc1RmJfbW8xX2RzbWVkX2RmJFNTQmhpZ2gpKjAuODUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4ID0gKChtYXgocmV0X25tRzVGYl9tbzFfZHNtZWRfZGYkWWVhciktbWluKHJldF9ubUc1RmJfbW8xX2RzbWVkX2RmJFllYXIpKSowLjIwKSttaW4ocmV0X25tRzVGYl9tbzFfZHNtZWRfZGYkWWVhciksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbCA9IHBhc3RlMCgiTW9obidzIFJobyA9ICIsIHJvdW5kKHJob19ubUc1RmJfbW8xX2RzbWVkWzJdLCBkaWdpdHMgPSAzKSkpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiYmxhY2siLCBlYnBhbFsobGVuZ3RoKGVicGFsKS00KTpsZW5ndGgoZWJwYWwpXSkpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2NsZWFuKCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXhpcy50aXRsZS55LmxlZnQgPSBlbGVtZW50X3RleHQodmp1c3QgPSAtMC4wNSwgaGp1c3QgPSAwLjk1KSkpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNob3dsZWdlbmQgPSBGQUxTRSkNCg0KIyBGcGxvdChSRVRSTykNCnJldGZfbm1HNUZiX21vMV9kc21lZCA8LSBsYXlvdXQoZ2dwbG90bHkoZ2dwbG90KCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fbGluZShkYXRhID0gcmV0X25tRzVGYl9tbzFfZHNtZWRfZGYsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9RmJhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBzZXJpZXMpKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9yaWJib24oZGF0YSA9IGFzdW1fbm1HNUZiX21vMV9kc21lZFthc3VtX25tRzVGYl9tbzFfZHNtZWQkWWVhciAhPSBtYXgoYXN1bV9ubUc1RmJfbW8xX2RzbWVkJFllYXIpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1pbj1GbG93LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1heD1GaGlnaCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9ICJibGFjayIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjMpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbm5vdGF0ZShnZW9tID0gInRleHQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBtYXgocmV0X25tRzVGYl9tbzFfZHNtZWRfZGYkRmhpZ2gpKjAuODUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeCA9ICgobWF4KHJldF9ubUc1RmJfbW8xX2RzbWVkX2RmJFllYXIpLW1pbihyZXRfbm1HNUZiX21vMV9kc21lZF9kZiRZZWFyKSkqMC44MCkrbWluKHJldF9ubUc1RmJfbW8xX2RzbWVkX2RmJFllYXIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsID0gcGFzdGUwKCJNb2huJ3MgUmhvID0gIiwgcm91bmQocmhvX25tRzVGYl9tbzFfZHNtZWRbM10sIGRpZ2l0cyA9IDMpKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiYmxhY2siLCBlYnBhbFsobGVuZ3RoKGVicGFsKS00KTpsZW5ndGgoZWJwYWwpXSkpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9jbGVhbigpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXhpcy50aXRsZS55LmxlZnQgPSBlbGVtZW50X3RleHQodmp1c3QgPSAtMC4wNSwgaGp1c3QgPSAwLjk1KSkpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaG93bGVnZW5kID0gRkFMU0UpDQoNCiMgcmVjcGxvdChSRVRSTykNCnJldHJlY19ubUc1RmJfbW8xX2RzbWVkIDwtIGxheW91dChnZ3Bsb3RseShnZ3Bsb3QoKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IHJldF9ubUc1RmJfbW8xX2RzbWVkX2RmLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1SX2FnZTEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBzZXJpZXMpKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3JpYmJvbihkYXRhID0gYXN1bV9ubUc1RmJfbW8xX2RzbWVkW2FzdW1fbm1HNUZiX21vMV9kc21lZCRZZWFyICE9IG1heChhc3VtX25tRzVGYl9tbzFfZHNtZWQkWWVhciksIF0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1pbj1SbG93LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4PVJoaWdoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSAiYmxhY2siLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjMpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFubm90YXRlKGdlb20gPSAidGV4dCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PSBtYXgocmV0X25tRzVGYl9tbzFfZHNtZWRfZGYkUmhpZ2gpKjAuODUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4ID0gKChtYXgocmV0X25tRzVGYl9tbzFfZHNtZWRfZGYkWWVhciktbWluKHJldF9ubUc1RmJfbW8xX2RzbWVkX2RmJFllYXIpKSowLjIwKSttaW4ocmV0X25tRzVGYl9tbzFfZHNtZWRfZGYkWWVhciksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbCA9IHBhc3RlMCgiTW9obidzIFJobyA9ICIsIHJvdW5kKHJob19ubUc1RmJfbW8xX2RzbWVkWzFdLCBkaWdpdHMgPSAzKSkpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiYmxhY2siLCBlYnBhbFsobGVuZ3RoKGVicGFsKS00KTpsZW5ndGgoZWJwYWwpXSkpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2NsZWFuKCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXhpcy50aXRsZS55LmxlZnQgPSBlbGVtZW50X3RleHQodmp1c3QgPSAtMC4wNSwgaGp1c3QgPSAwLjk1KSkpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNob3dsZWdlbmQgPSBGQUxTRSkNCg0KIyMgQ2F0Y2ggcGxvdCAoUkVUUk8pDQpyZXRjYV9ubUc1RmJfbW8xX2RzbWVkIDwtIGdncGxvdGx5KGdncGxvdCgpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IHJldF9ubUc1RmJfbW8xX2RzbWVkX2RmLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PUNhdGNoRXN0LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IHNlcmllcykpKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fcmliYm9uKGRhdGEgPSBhc3VtX25tRzVGYl9tbzFfZHNtZWRbYXN1bV9ubUc1RmJfbW8xX2RzbWVkJFllYXIgIT0gbWF4KGFzdW1fbm1HNUZiX21vMV9kc21lZCRZZWFyKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW49Q2F0Y2hsb3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4PUNhdGNoaGlnaCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9ICJibGFjayIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjMpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3BvaW50KGRhdGEgPSBhc3VtX25tRzVGYl9tbzFfZHNtZWRbYXN1bV9ubUc1RmJfbW8xX2RzbWVkJFllYXIgIT0gbWF4KGFzdW1fbm1HNUZiX21vMV9kc21lZCRZZWFyKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PUNhdGNoT2JzKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNoYXBlID0gMywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IGVicGFsWzVdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IGVicGFsWzVdKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeWxhYigiQ2F0Y2ggKHRvbm5lcykiKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCJibGFjayIsIGVicGFsWyhsZW5ndGgoZWJwYWwpLTQpOmxlbmd0aChlYnBhbCldKSkrIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2NsZWFuKCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKGF4aXMudGl0bGUueS5sZWZ0ID0gZWxlbWVudF90ZXh0KHZqdXN0ID0gLTAuMDUsIGhqdXN0ID0gMC45NSkpKQ0KDQpyZXRfZnAgPC0gc3R5bGUoc3VicGxvdChyZXRzc2Jfbm1HNUZiX21vMV9kc21lZCwgcmV0Zl9ubUc1RmJfbW8xX2RzbWVkLCByZXRyZWNfbm1HNUZiX21vMV9kc21lZCwgcmV0Y2Ffbm1HNUZiX21vMV9kc21lZCwgbnJvd3MgPSAyLCBzaGFyZVggPSBGQUxTRSwgc2hhcmVZID0gRkFMU0UsIHRpdGxlWSA9IFRSVUUpLA0KICAgICAgICAgICAgICAgIHNob3dsZWdlbmQ9RkFMU0UsDQogICAgICAgICAgICAgICAgdHJhY2VzID0gYyg4OigoNyo0KSsyKSkpDQoNCmxheW91dChyZXRfZnAsIGxlZ2VuZCA9IGxpc3Qob3JpZW50YXRpb24gPSAnaCcsIHggPSAwLjUsIHhhbmNob3IgPSAnY2VudGVyJywgeSA9IC0wLjA1LCB5YW5jaG9yID0gJ3RvcCcsIGJvcmRlcndpZHRoID0gMCkpDQpgYGANCg0KDQojIyBIaWdoIERpc2NhcmQgU3Vydml2YWwgRXN0aW1hdGVzDQoNClRoaXMgbW9kZWwgaXMgY2FsbGVkIFtwbGUuMjcuMjEtMzJfV0tCUExBSUNFXzIwMjRfbm1HNUZiX21vMV9kc2hpZ10oaHR0cHM6Ly9zdG9ja2Fzc2Vzc21lbnQub3JnL3NldFN0b2NrLnBocD9zdG9jaz1wbGUuMjcuMjEtMzJfV0tCUExBSUNFXzIwMjRfbm1HNUZiX21vMV9kc2hpZykgYW5kIGNhbiBiZSBmb3VuZCBvbiBbc3RvY2thc3Nlc3NtZW50Lm9yZ10oaHR0cHM6Ly9zdG9ja2Fzc2Vzc21lbnQub3JnKS4gDQoNCmBgYHtyIG5tRzVGYl9tbzFfZHNoaWdGaXRGcm9tV2VifQ0KZml0X25tRzVGYl9tbzFfZHNoaWcgPC0gZml0ZnJvbXdlYigicGxlLjI3LjIxLTMyX1dLQlBMQUlDRV8yMDI0X25tRzVGYl9tbzFfZHNoaWciKQ0KYGBgDQoNCmBgYHtyIGRhdGFmcmFtZVN1bW1hcnlfbm1HNUZiX21vMV9kc2hpZywgcmVzdWx0cz0naGlkZScsIGZpZy5zaG93PSdoaWRlJ30NCiM9PT0NCiMgQ3JlYXRlIGRhdGFmcmFtZSBvZiBjdXJyZW50IHllYXIncyBmaXQgZm9yIHBsb3R0aW5nDQojPT09PQ0KYXN1bV9ubUc1RmJfbW8xX2RzaGlnIDwtIGFzLmRhdGEuZnJhbWUoc3VtbWFyeShmaXRfbm1HNUZiX21vMV9kc2hpZykpDQphc3VtX25tRzVGYl9tbzFfZHNoaWckWWVhciA8LSBhcy5pbnRlZ2VyKHJvdy5uYW1lcyhzdW1tYXJ5KGZpdF9ubUc1RmJfbW8xX2RzaGlnKSkpDQpjdF9ubUc1RmJfbW8xX2RzaGlnIDwtIGFzLmRhdGEuZnJhbWUoY2F0Y2h0YWJsZShmaXRfbm1HNUZiX21vMV9kc2hpZywgb2JzLnNob3cgPSBUUlVFKSkNCmN0X25tRzVGYl9tbzFfZHNoaWckWWVhciA8LSBhcy5pbnRlZ2VyKHJvd25hbWVzKGN0X25tRzVGYl9tbzFfZHNoaWcpKQ0Kcm93bmFtZXMoY3Rfbm1HNUZiX21vMV9kc2hpZykgPC0gTlVMTA0KY3Rfbm1HNUZiX21vMV9kc2hpZyA8LSByYmluZChjdF9ubUc1RmJfbW8xX2RzaGlnLCBkYXRhLmZyYW1lKEVzdGltYXRlID0gTkEsIExvdz1OQSwgSGlnaD1OQSwgc29wLmNhdGNoPU5BLCBZZWFyPWFzLmludGVnZXIoMjAyNCkpKQ0KYXN1bV9ubUc1RmJfbW8xX2RzaGlnIDwtIG1lcmdlKHggPSBhc3VtX25tRzVGYl9tbzFfZHNoaWcsIHkgPSBjdF9ubUc1RmJfbW8xX2RzaGlnLCBieSA9ICJZZWFyIikNCmNvbG5hbWVzKGFzdW1fbm1HNUZiX21vMV9kc2hpZykgPC0gYygiWWVhciIsICJSX2FnZTEiLCAiUmxvdyIsICJSaGlnaCIsICJTU0IiLCAiU1NCbG93IiwgIlNTQmhpZ2giLCAiRmJhciIsICJGbG93IiwgIkZoaWdoIiwgIkNhdGNoRXN0IiwgIkNhdGNobG93IiwgIkNhdGNoaGlnaCIsICJDYXRjaE9icyIpDQojPT09PT0NCmBgYA0KDQojIyMgRml0cyB0byBkYXRhDQpXaGVuIHRoZSBtb2RlbCBpcyBydW4gd2UgY2FuIGVhc2lseSBzZWUgZnJvbSB3YXJuaW5ncy9lcnJvcnMgaWYgdGhlcmUgaXMgYSBjb252ZXJnZW5jZSBpc3N1ZS4gIEhvd2V2ZXIsIHdlIGNhbiBhbHNvIGNvbmZpcm0gdGhpcywgZXhwbGljaXRseToNCg0KLSBUaGUgZmluYWwgbW9kZWwgZ3JhZGllbnQ6IGByIGZpdF9ubUc1RmJfbW8xX2RzaGlnJG9wdCRldmFsdWF0aW9uc1syXWANCi0gVGhhdCB0aGVyZSBpcyBhIHBvc2l0aXZlIGRlZmluaXRlIGhlc3NpYW46IGByIGFsbChlaWdlbihmaXRfbm1HNUZiX21vMV9kc2hpZyRvcHQkaGUpJHZhbHVlcyA+MClgDQoNCkZ1cnRoZXJtb3JlLCBTQU0gZG9lcyBub3QgdXRpbGlzZSAiYm91bmRzIiB3aGVuIGZpdHRpbmcgdGhlIG1vZGVsLCBhbmQgdGhlcmVmb3JlLCBhcyBzdGFuZGFyZCBjaGVjayBvZiB3aGV0aGVyIG1vZGVsIHBhcmFtZXRlcnMgYXJlIGFwcHJvYWNoaW5nIHRoZWlyIGJvdW5kcyBpcyBpcnJlbGV2YW50Lg0KDQojIyMjIFZpc3VhbGlzZSBmaXRzIHRvIGRhdGEgYnkgYWdlIG92ZXIgdGltZSBhY3Jvc3MgZmxlZXRzDQoNCmBgYHtyIGZpZy5jYXA9Ik1vZGVsIHdpdGggaGlnaCBkaXNjYXJkIHN1cnZpdmFsIGVzdGltYXRlcywgZml0IHRvIGNhdGNoIGRhdGEgYnkgYWdlICh2YWx1ZXMgb24gdGhlIG1vZGVsIGxpbmsgZnVuY3Rpb24gc2NhbGUpLiJ9DQojIyBFeHRyYWN0IGRhdGEgZnJvbSBtb2RlbCBvYmplY3QNCmxvZ09ic19ubUc1RmJfbW8xX2RzaGlnIDwtIHNwbGl0KGZpdF9ubUc1RmJfbW8xX2RzaGlnJGRhdGEkbG9nb2JzLCBjZWlsaW5nKHNlcV9hbG9uZyhmaXRfbm1HNUZiX21vMV9kc2hpZyRkYXRhJGxvZ29icykvZml0X25tRzVGYl9tbzFfZHNoaWckZGF0YSRtYXhBZ2VQZXJGbGVldFsxXSkpDQpsb2dQcmVkX25tRzVGYl9tbzFfZHNoaWcgPC0gc3BsaXQoZml0X25tRzVGYl9tbzFfZHNoaWckcmVwJHByZWRPYnMsIGNlaWxpbmcoc2VxX2Fsb25nKGZpdF9ubUc1RmJfbW8xX2RzaGlnJHJlcCRwcmVkT2JzKS9maXRfbm1HNUZiX21vMV9kc2hpZyRkYXRhJG1heEFnZVBlckZsZWV0WzFdKSkNCg0KIyMgVHJhbnNmb3JtIGRhdGEgdG8gdXNlYWJsZSBkYXRhZnJhbWVzDQojIyMgSW5pdGlhbGl6ZSBhbiBlbXB0eSBkYXRhIGZyYW1lIGZvciBvYnNlcnZhdGlvbnMNCmxvZ09ic19ubUc1RmJfbW8xX2RzaGlnX2RmIDwtIGRhdGEuZnJhbWUoYWdlID0gaW50ZWdlcigpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmbGVldCA9IGludGVnZXIoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeWVhciA9IGludGVnZXIoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbG9nT2JzID0gbnVtZXJpYygpKQ0KDQojIyMgUG9wdWxhdGUgdGhlIGRhdGEgZnJhbWUgZm9yIG9ic2VydmF0aW9ucw0KZm9yIChpIGluIHNlcV9hbG9uZyhsb2dPYnNfbm1HNUZiX21vMV9kc2hpZykpIHsNCiAgIyBDYWxjdWxhdGUgdGhlIGdyb3VwIGFuZCB5ZWFyDQogIHllYXIgPC0gKChpIC0gMSkgJS8lIDMpICsgMQ0KICBmbGVldCA8LSAoKGkgLSAxKSAlJSAzKSArIDENCiAgDQogICMjIyBDcmVhdGUgYSB0ZW1wb3JhcnkgZGF0YSBmcmFtZSBhbmQgYXBwZW5kIHRvIHRoZSBtYWluIGRhdGEgZnJhbWUgZm9yIG9ic2VydmF0aW9ucw0KICB0ZW1wX2RmIDwtIGRhdGEuZnJhbWUoYWdlID0gMTo3LA0KICAgICAgICAgICAgICAgICAgICAgICAgZmxlZXQgPSBmbGVldCwNCiAgICAgICAgICAgICAgICAgICAgICAgIHllYXIgPSB5ZWFyKzIwMDEsDQogICAgICAgICAgICAgICAgICAgICAgICBsb2dPYnMgPSBsb2dPYnNfbm1HNUZiX21vMV9kc2hpZ1tbaV1dKQ0KICBsb2dPYnNfbm1HNUZiX21vMV9kc2hpZ19kZiA8LSByYmluZChsb2dPYnNfbm1HNUZiX21vMV9kc2hpZ19kZiwgdGVtcF9kZikNCn0NCg0KIyMjIEluaXRpYWxpemUgYW4gZW1wdHkgZGF0YSBmcmFtZSBmb3IgcHJlZGljdGlvbnMNCmxvZ1ByZWRfbm1HNUZiX21vMV9kc2hpZ19kZiA8LSBkYXRhLmZyYW1lKGFnZSA9IGludGVnZXIoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZsZWV0ID0gaW50ZWdlcigpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeWVhciA9IGludGVnZXIoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvZ1ByZWQgPSBudW1lcmljKCkpDQoNCiMjIyBQb3B1bGF0ZSB0aGUgZGF0YSBmcmFtZSBmb3IgcHJlZGljdGlvbnMNCmZvciAoaSBpbiBzZXFfYWxvbmcobG9nUHJlZF9ubUc1RmJfbW8xX2RzaGlnKSkgew0KICAjIENhbGN1bGF0ZSB0aGUgZ3JvdXAgYW5kIHllYXINCiAgeWVhciA8LSAoKGkgLSAxKSAlLyUgMykgKyAxDQogIGZsZWV0IDwtICgoaSAtIDEpICUlIDMpICsgMQ0KICANCiAgIyMjIENyZWF0ZSBhIHRlbXBvcmFyeSBkYXRhIGZyYW1lIGFuZCBhcHBlbmQgdG8gdGhlIG1haW4gZGF0YSBmcmFtZSBmb3IgcHJlZGljdGlvbnMNCiAgdGVtcF9kZiA8LSBkYXRhLmZyYW1lKGFnZSA9IDE6NywNCiAgICAgICAgICAgICAgICAgICAgICAgIGZsZWV0ID0gZmxlZXQsDQogICAgICAgICAgICAgICAgICAgICAgICB5ZWFyID0geWVhcisyMDAxLA0KICAgICAgICAgICAgICAgICAgICAgICAgbG9nUHJlZCA9IGxvZ1ByZWRfbm1HNUZiX21vMV9kc2hpZ1tbaV1dKQ0KICBsb2dQcmVkX25tRzVGYl9tbzFfZHNoaWdfZGYgPC0gcmJpbmQobG9nUHJlZF9ubUc1RmJfbW8xX2RzaGlnX2RmLCB0ZW1wX2RmKQ0KfQ0KDQojIyBQbG90DQpsb2dQcmVkX25tRzVGYl9tbzFfZHNoaWdfZGYkYWdlIDwtIGFzLmNoYXJhY3Rlcihsb2dQcmVkX25tRzVGYl9tbzFfZHNoaWdfZGYkYWdlKQ0KbG9nT2JzX25tRzVGYl9tbzFfZHNoaWdfZGYkYWdlIDwtIGFzLmNoYXJhY3Rlcihsb2dPYnNfbm1HNUZiX21vMV9kc2hpZ19kZiRhZ2UpDQoNCmdncGxvdGx5KGdncGxvdCgpKw0KICAgICAgICAgICBnZW9tX3BvaW50KGRhdGEgPSBsb2dPYnNfbm1HNUZiX21vMV9kc2hpZ19kZltsb2dPYnNfbm1HNUZiX21vMV9kc2hpZ19kZiRmbGVldCA9PSAxICYgbG9nT2JzX25tRzVGYl9tbzFfZHNoaWdfZGYkeWVhciAhPSAoRGF0YVllYXIrMSksIF0sDQogICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0geWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBsb2dPYnMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBhZ2UpLA0KICAgICAgICAgICAgICAgICAgICAgIHNoYXBlID0gMjEpICsNCiAgICAgICAgICAgZ2VvbV9saW5lKGRhdGEgPSBsb2dQcmVkX25tRzVGYl9tbzFfZHNoaWdfZGZbbG9nUHJlZF9ubUc1RmJfbW8xX2RzaGlnX2RmJGZsZWV0ID09IDEgJiBsb2dQcmVkX25tRzVGYl9tbzFfZHNoaWdfZGYkeWVhciAhPSAoRGF0YVllYXIrMSksIF0sDQogICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSB5ZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gbG9nUHJlZCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gYWdlKSkgKw0KICAgICAgICAgICBmYWNldF93cmFwKGZhY2V0cyA9ICJhZ2UiKSArICMsIHNjYWxlcyA9ICJmcmVlX3kiKSArDQogICAgICAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBlYnBhbCwgZ3VpZGUgPSBGQUxTRSkgKw0KICAgICAgICAgICBndWlkZXMoY29sb3VyPUZBTFNFLCBzaGFwZT1GQUxTRSkgKw0KICAgICAgICAgICB0aGVtZV9mZXcoKSkNCg0KIyBmaXRwbG90KGZpdF9ubUc1RmJfbW8xX2RzaGlnLCBmbGVldHM9MSkNCmBgYA0KDQpgYGB7ciBmaWcuY2FwPSJNb2RlbCB3aXRoIGhpZ2ggZGlzY2FyZCBzdXJ2aXZhbCBlc3RpbWF0ZXMsIGZpdCB0byBRMSBzdXJ2ZXkgZGF0YSBieSBhZ2UgKHZhbHVlcyBvbiB0aGUgbW9kZWwgbGluayBmdW5jdGlvbiBzY2FsZSkuIn0NCmdncGxvdGx5KGdncGxvdCgpKw0KICAgICAgICAgICBnZW9tX3BvaW50KGRhdGEgPSBsb2dPYnNfbm1HNUZiX21vMV9kc2hpZ19kZltsb2dPYnNfbm1HNUZiX21vMV9kc2hpZ19kZiRmbGVldCA9PSAyICYgbG9nT2JzX25tRzVGYl9tbzFfZHNoaWdfZGYkeWVhciAhPSAoRGF0YVllYXIrMSksIF0sDQogICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0geWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBsb2dPYnMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBhZ2UpLA0KICAgICAgICAgICAgICAgICAgICAgIHNoYXBlID0gMjEpICsNCiAgICAgICAgICAgZ2VvbV9saW5lKGRhdGEgPSBsb2dQcmVkX25tRzVGYl9tbzFfZHNoaWdfZGZbbG9nUHJlZF9ubUc1RmJfbW8xX2RzaGlnX2RmJGZsZWV0ID09IDIgJiBsb2dQcmVkX25tRzVGYl9tbzFfZHNoaWdfZGYkeWVhciAhPSAoRGF0YVllYXIrMSksIF0sDQogICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSB5ZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gbG9nUHJlZCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gYWdlKSkgKw0KICAgICAgICAgICBmYWNldF93cmFwKGZhY2V0cyA9ICJhZ2UiKSArICMsIHNjYWxlcyA9ICJmcmVlX3kiKSArDQogICAgICAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBlYnBhbCwgZ3VpZGUgPSBGQUxTRSkgKw0KICAgICAgICAgICBndWlkZXMoY29sb3VyPUZBTFNFLCBzaGFwZT1GQUxTRSkgKw0KICAgICAgICAgICB0aGVtZV9mZXcoKSkNCiMgZml0cGxvdChmaXRfbm1HNUZiX21vMV9kc2hpZywgZmxlZXRzPTIpDQpgYGANCg0KYGBge3IgZmlnLmNhcD0iTW9kZWwgd2l0aCBoaWdoIGRpc2NhcmQgc3Vydml2YWwgZXN0aW1hdGVzLCBmaXQgdG8gUTMvNCBzdXJ2ZXkgZGF0YSBieSBhZ2UgKHZhbHVlcyBvbiB0aGUgbW9kZWwgbGluayBmdW5jdGlvbiBzY2FsZSkuIn0NCmdncGxvdGx5KGdncGxvdCgpKw0KICAgICAgICAgICBnZW9tX3BvaW50KGRhdGEgPSBsb2dPYnNfbm1HNUZiX21vMV9kc2hpZ19kZltsb2dPYnNfbm1HNUZiX21vMV9kc2hpZ19kZiRmbGVldCA9PSAzICYgbG9nT2JzX25tRzVGYl9tbzFfZHNoaWdfZGYkeWVhciAhPSAoRGF0YVllYXIrMSksIF0sDQogICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0geWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBsb2dPYnMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBhZ2UpLA0KICAgICAgICAgICAgICAgICAgICAgIHNoYXBlID0gMjEpICsNCiAgICAgICAgICAgZ2VvbV9saW5lKGRhdGEgPSBsb2dQcmVkX25tRzVGYl9tbzFfZHNoaWdfZGZbbG9nUHJlZF9ubUc1RmJfbW8xX2RzaGlnX2RmJGZsZWV0ID09IDMgJiBsb2dQcmVkX25tRzVGYl9tbzFfZHNoaWdfZGYkeWVhciAhPSAoRGF0YVllYXIrMSksIF0sDQogICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHggPSB5ZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gbG9nUHJlZCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gYWdlKSkgKw0KICAgICAgICAgICBmYWNldF93cmFwKGZhY2V0cyA9ICJhZ2UiKSArICMsIHNjYWxlcyA9ICJmcmVlX3kiKSArDQogICAgICAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBlYnBhbCwgZ3VpZGUgPSBGQUxTRSkgKw0KICAgICAgICAgICBndWlkZXMoY29sb3VyPUZBTFNFLCBzaGFwZT1GQUxTRSkgKw0KICAgICAgICAgICB0aGVtZV9mZXcoKSkNCg0KIyBmaXRwbG90KGZpdF9ubUc1RmJfbW8xX2RzaGlnLCBmbGVldHM9MykNCmBgYA0KDQpgYGB7ciBmaWcuY2FwPSJTdGFuZGFyZCBEZXZhdGlvbnMgYnkgRmxlZXQ7IGhpZ2ggZGlzY2FyZCBzdXJ2aXZhbCBlc3RpbWF0ZXMuIiwgaGVpZ2h0PTEwfQ0Kc2RwbG90KGZpdF9ubUc1RmJfbW8xX2RzaGlnLCBtYXJnID0gYyg1LDQsMSwxKSkNCmBgYA0KDQojIyMjIFJlc2lkdWFscw0KYGBge3IgY2FsY3VsYXRlUmVzaWR1YWxzX25tRzVGYl9tbzFfZHNoaWcsIHdhcm5pbmc9RkFMU0UsIHJlc3VsdHM9J2hpZGUnfQ0KcmVzaWRfbm1HNUZiX21vMV9kc2hpZyA8LSByZXNpZHVhbHMoZml0X25tRzVGYl9tbzFfZHNoaWcpDQpyZXNpZF9ubUc1RmJfbW8xX2RzaGlnX2RmIDwtIGRhdGEuZnJhbWUoeWVhciA9IHJlc2lkX25tRzVGYl9tbzFfZHNoaWckeWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmbGVldCA9IHJlc2lkX25tRzVGYl9tbzFfZHNoaWckZmxlZXQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWdlID0gcmVzaWRfbm1HNUZiX21vMV9kc2hpZyRhZ2UsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb2JzZXJ2YXRpb24gPSByZXNpZF9ubUc1RmJfbW8xX2RzaGlnJG9ic2VydmF0aW9uLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1lYW4gPSByZXNpZF9ubUc1RmJfbW8xX2RzaGlnJG1lYW4sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzaWR1YWwgPSByZXNpZF9ubUc1RmJfbW8xX2RzaGlnJHJlc2lkdWFsKQ0KcmVzaWRfbm1HNUZiX21vMV9kc2hpZ19kZiRmbGVldE5hbWUgPC0gaWZlbHNlKHJlc2lkX25tRzVGYl9tbzFfZHNoaWdfZGYkZmxlZXQgPT0gMSwgYXR0cmlidXRlcyhyZXNpZF9ubUc1RmJfbW8xX2RzaGlnKSRmbGVldE5hbWVzWzFdLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UocmVzaWRfbm1HNUZiX21vMV9kc2hpZ19kZiRmbGVldCA9PSAyLCBhdHRyaWJ1dGVzKHJlc2lkX25tRzVGYl9tbzFfZHNoaWcpJGZsZWV0TmFtZXNbMl0sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2UocmVzaWRfbm1HNUZiX21vMV9kc2hpZ19kZiRmbGVldCA9PSAzLCBhdHRyaWJ1dGVzKHJlc2lkX25tRzVGYl9tbzFfZHNoaWcpJGZsZWV0TmFtZXNbM10sIE5BKSkpDQoNCnJlc2lkX25tRzVGYl9tbzFfZHNoaWdfZGYkZmxlZXRBbHROYW1lIDwtIGlmZWxzZShyZXNpZF9ubUc1RmJfbW8xX2RzaGlnX2RmJGZsZWV0ID09IDEsICJSZXNpZHVhbCBGaXNoaW5nIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKHJlc2lkX25tRzVGYl9tbzFfZHNoaWdfZGYkZmxlZXQgPT0gMiwgIlExIFN1cnZleXMiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKHJlc2lkX25tRzVGYl9tbzFfZHNoaWdfZGYkZmxlZXQgPT0gMywgIlEzLzQgU3VydmV5cyIsIE5BKSkpDQpgYGANCg0KYGBge3IgZmlnLmNhcD0iRXN0aW1hdGVkIGNvcnJlbGF0aW9ucyBpbiByZXNpZHVhbCB2YXJpYXRpb24gYmV0d2VlbiBhZ2VzIGZvciBlYWNoIG9mIHRoZSBmaXNoaW5nIGZsZWV0ICh0b3ApIGFuZCB0aGUgdHdvIHN1cnZleXMgKG1pZGRsZSAmIGJvdHRvbSksIGZyb20gdGhlIE1vZGVsIHdpdGggaGlnaCBkaXNjYXJkIG1vcnRhbGl0eS4ifQ0KDQppZighYWxsKGZpdF9ubUc1RmJfbW8xX2RzaGlnJGNvbmYkb2JzQ29yU3RydWN0PT0iSUQiKSl7IA0KICBjb3JwbG90KGZpdF9ubUc1RmJfbW8xX2RzaGlnKQkJCSAgDQogICMgc2V0Y2FwKCJFc3RpbWF0ZWQgY29ycmVsYXRpb25zIiwgIkVzdGltYXRlcyBjb3JyZWxhdGlvbnMgYmV0d2VlbiBhZ2UgZ3JvdXBzIGZvciBlYWNoIGZsZWV0IikNCiAgIyBzdGFtcGl0KGZpdCkNCn0gZWxzZSB7DQogIHByaW50KCJObyBjb3JyZWxhdGlvbiBzdHJ1Y3R1cmUgY29uZmlndXJlZCBmb3IgcmVzaWR1YWxzIGFjcm9zcyBhZ2UuIikNCn0NCg0KYGBgDQoNCmBgYHtyIGZpZy5jYXA9Ik9uZSBvYnNlcnZhdGlvbiBhaGVhZCByZXNpZHVhbHMgZm9yIHRoZSB0aHJlZSBmbGVldHMgKHJlZC9waW5rID0gb2JzZXJ2YXRpb24gbG93ZXIgdGhhbiBtb2RlbCBlc3RpbWF0ZSwgYmx1ZSA9IG9ic2VydmF0aW9uIGhpZ2hlciB0aGFuIG1vZGVsIGVzdGltYXRlLCBzaXplID0gbWFnbml0dWRlIG9mIHJlc2lkdWFsKSwgZnJvbSB0aGUgTW9kZWwgd2l0aCBoaWdoIGRpc2NhcmQgbW9ydGFsaXR5LiJ9DQpnZ3Bsb3RseShnZ3Bsb3QocmVzaWRfbm1HNUZiX21vMV9kc2hpZ19kZikgKw0KICAgICAgICAgICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IHllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gYWdlLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IGFicyhyZXNpZHVhbCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSByZXNpZHVhbCA+PSAwKSwNCiAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuNykgKw0KICAgICAgICAgICBmYWNldF9ncmlkKHJvd3MgPSAiZmxlZXRBbHROYW1lIikgKw0KICAgICAgICAgICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoIlRSVUUiID0gZWJwYWxbOF0sICJGQUxTRSIgPSBlYnBhbFs5XSkpICsNCiAgICAgICAgICAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoLTEsIDkpLCBicmVha3MgPSBjKDE6OSkpICsNCiAgICAgICAgICAgZ3VpZGVzKGNvbG91cj1GQUxTRSkgKw0KICAgICAgICAgICB0aGVtZV9mZXcoKSkNCg0KYGBgDQoNCiMjIyMgSml0dGVyaW5nDQpXZSBjYW4gYWxzbyB0ZXN0IHRvIHNlZSBpZiB0aGUgbW9kZWwgaXMgY29udmVyZ2luZyBvbiBzb21lIGxvY2FsIG1pbmltdW0gKGkuZS4gaXQncyBmaXR0aW5nIHRvIHNvbWUgc29sdXRpb24gY2xvc2UgdG8gaW5pdGlhbGlzaW5nIHZhbHVlcyB0aGF0IHJlcHJlc2VudHMgbm9pc2UgYW5kIG5vdCB0aGUgZ2xvYmFsIHNvbHV0aW9uLCB0aGF0IGlzIHRoZSBwcm9wZXIgc29sdXRpb24pLiAgVG8gZG8gdGhpcywgd2UgYWRkIHJhbmRvbSBub2lzZSB0byB0aGUgaW5pdGlhbCBwYXJhbWV0ZXIgdmFsdWVzIHRvIHNlZSBpZiB0aGUgbW9kZWwgd2lsbCBjb252ZXJnZSBvbiBhIGRpZmZlcmVudCBtaW5pbXVtIGluIGl0J3MgZGF0YS1zcGFjZS4gVGhlIGVhc2llc3Qgd2F5IHRvIGludmVzdGlnYXRlIHRoaXMgaXMgdG8gc2VlIGlmIHRoZSBtb2RlbCBmaXRzIHZhcnkgYWxvdCBkZXBlbmRpbmcgb24gdGhlIHN0YXJ0aW5nIHZhbHVlczoNCmBgYHtyIEppdHRlcl9ubUc1RmJfbW8xX2RzaGlnfQ0Kaml0X25tRzVGYl9tbzFfZHNoaWcgPC0gaml0KGZpdCA9IGZpdF9ubUc1RmJfbW8xX2RzaGlnKQ0KDQptdCA8LSBhcy5kYXRhLmZyYW1lKG1vZGVsdGFibGUoaml0X25tRzVGYl9tbzFfZHNoaWcpKQ0KbXQkbW9kZWwgPC0gcm93bmFtZXMobXQpDQpyb3duYW1lcyhtdCkgPC0gTlVMTA0KDQprYWJsZSh4ID0gbXQsDQogICAgICBkaWdpdHMgPSAzLA0KICAgICAgY2FwdGlvbiA9ICJNZWFzdXJlcyBvZiAgZml0IGZvciBhIHNlcmllcyBvZiBtb2RlbCByZWZpdHMgd2l0aCBqaXR0ZXIgYXBwbGllZCB0byB0aGUgaW5wdXQgcGFyYW1ldGVycy4iKQ0KYGBgDQoNCiMjIyMgTGVhdmUtT25lLU91dCBBbmFseXNlcw0KQSBsZWF2ZS1vbmUtb3V0IGFuYWx5c2lzIGlzIGEgZm9ybSBvZiBzZW5zaXRpdml0eSBhbmFseXNpcywgc2hvd2luZyB0aGUgaW1wYWN0IHRoZSBkYXRhIGZyb20gZWFjaCB0dW5pbmcgZmxlZXQgaGFzIG9uIHRoZSBlc3RpbWF0aW9uIG9mIHRoZSBrZXkgdmFyaWFibGVzIGJlaW5nIGVzdGltYXRlZDsgbmFtZWx5IFNTQiwgRiBhbmQgcmVjcnVpdG1lbnQuICANCg0KRmlyc3Qgd2UgbXVzdCBydW4gdGhlIGxlYXZlLW9uZS1vdXQgYW5hbHlzaXMgd2hpY2ggcmVmaXRzIHRoZSBtb2RlbCBpbiB0d28gaXRlcmF0aW9ucywgcmVtb3Zpbmcgb25lIHN1cnZleSBhdCBhIHRpbWUuIFRoZW4gd2UgY2FuIHBsb3QgZWFjaCBvZiB0aGVzZSBuZXcgbW9kZWwgZml0cyBvdmVyIHRoZSBmdWxsIG1vZGVsIHRvIHNlZSB0aGUgaW1wYWN0IHRoZSByZW1vdmFsIG9mIGVhY2ggaGFzLiANCg0KYGBge3IgTGVhdmVPbmVPdXRfbm1HNUZiX21vMV9kc2hpZ30NCkxPX25tRzVGYl9tbzFfZHNoaWcgPC0gbGVhdmVvdXQoZml0X25tRzVGYl9tbzFfZHNoaWcpDQoNCiM9PT0gDQojIEdldCBkYXRhIGZyb20gc2FtIG9iamVjdHMgYW5kIGdlbmVyYXRlIHVzZWFibGUgZGF0YWZyYW1lcw0KIz09PT0NCnExbWF0IDwtIGFzLmRhdGEuZnJhbWUoc3VtbWFyeShMT19ubUc1RmJfbW8xX2RzaGlnJGB3Lm8uIFExSUJUUytCSVRTK0NvZFNEMjEtMjVgKSkNCnEzbWF0IDwtIGFzLmRhdGEuZnJhbWUoc3VtbWFyeShMT19ubUc1RmJfbW8xX2RzaGlnJGB3Lm8uIFEzNElCVFMrQklUUytDb2RTRDIxLTI1YCkpDQoNCg0Kd29xMSA8LSBkYXRhLmZyYW1lKFllYXIgPSBhcy5pbnRlZ2VyKHJvdy5uYW1lcyhzdW1tYXJ5KExPX25tRzVGYl9tbzFfZHNoaWckYHcuby4gUTFJQlRTK0JJVFMrQ29kU0QyMS0yNWApKSksDQogICAgICAgICAgICAgICAgICAgU1NCID0gcTFtYXQkU1NCLA0KICAgICAgICAgICAgICAgICAgIEZiYXIgPSBxMW1hdCRgRmJhcigzLTUpYCwNCiAgICAgICAgICAgICAgICAgICBSX2FnZTEgPSBxMW1hdCRgUihhZ2UgMSlgLA0KICAgICAgICAgICAgICAgICAgIENhdGNoRXN0ID0gY2F0Y2h0YWJsZShMT19ubUc1RmJfbW8xX2RzaGlnJGB3Lm8uIFExSUJUUytCSVRTK0NvZFNEMjEtMjVgKVssMV0sDQogICAgICAgICAgICAgICAgICAgc2VyaWVzID0gcmVwKCJ3b19RMSIsIHRpbWVzID0gbnJvdyhxMW1hdCkpKQ0KDQp3b3EzNCA8LSBkYXRhLmZyYW1lKFllYXIgPSBhcy5pbnRlZ2VyKHJvdy5uYW1lcyhxM21hdFsoMjAwMjpEYXRhWWVhciktMjAwMSxdKSksDQogICAgICAgICAgICAgICAgICAgIFNTQiA9IHEzbWF0WygyMDAyOkRhdGFZZWFyKS0yMDAxLCAiU1NCIl0sDQogICAgICAgICAgICAgICAgICAgIEZiYXIgPSBxM21hdFsoMjAwMjpEYXRhWWVhciktMjAwMSwiRmJhcigzLTUpIl0sDQogICAgICAgICAgICAgICAgICAgIFJfYWdlMSA9IHEzbWF0WygyMDAyOkRhdGFZZWFyKS0yMDAxLCJSKGFnZSAxKSJdLA0KICAgICAgICAgICAgICAgICAgICBDYXRjaEVzdCA9IGNhdGNodGFibGUoTE9fbm1HNUZiX21vMV9kc2hpZyRgdy5vLiBRMzRJQlRTK0JJVFMrQ29kU0QyMS0yNWApWywxXSwNCiAgICAgICAgICAgICAgICAgICAgc2VyaWVzID0gcmVwKCJ3b19RMzQiLCB0aW1lcyA9IChucm93KHEzbWF0KS0xKSkpDQoNCg0KYXN1bV9ubUc1RmJfbW8xX2RzaGlnJHNlcmllcyA8LSByZXAoImZ1bGwiLCB0aW1lcyA9IG5yb3coYXN1bV9ubUc1RmJfbW8xX2RzaGlnKSkNCmFzdW1pX25tRzVGYl9tbzFfZHNoaWcgPC0gYXN1bV9ubUc1RmJfbW8xX2RzaGlnWywgYygiWWVhciIsICJTU0IiLCAiRmJhciIsICJSX2FnZTEiLCAiQ2F0Y2hFc3QiICwic2VyaWVzIildDQojPT09PT0NCg0KbG9zdW1fbm1HNUZiX21vMV9kc2hpZyA8LSByYmluZCh3b3ExLCB3b3EzNCwgYXN1bWlfbm1HNUZiX21vMV9kc2hpZykNCg0KYGBgDQoNCmBgYHtyIGZpZy5jYXA9IkxlYXZlLW9uZS1vdXQgcmUtZml0cyBmb3IgdGhlIG1vZGVsIHdpdGggaGlnaCBkaXNjYXJkIHN1cnZpdmFsICh3aXRob3V0IFExIHN1cnZleSA9IGJsdWUsIHdpdGhvdXQgUTMvNCBzdXJ2ZXkgPSBwdXJwbGUpLCBvdmVybGFpbiB3aXRoIGZ1bGwgbW9kZWwgZXN0aW1hdGVzIChibGFjayBsaW5lIGFuZCBncmV5IHJpYmJvbikgb2YgU1NCICh0b3AgbGVmdCksIEYgKHRvcCByaWdodCksIFJlY3J1aXRtZW50IChib3R0b20gbGVmdCksIGFuZCBjYXRjaCAoYm90dG9tIHJpZ2h0OyBvYnNlcnZhdGlvbnMgYXMgeWVsbG93ICspLiJ9DQojIHNzYnBsb3QoTE8pDQpsb3NzYl9ubUc1RmJfbW8xX2RzaGlnIDwtIGdncGxvdGx5KGdncGxvdCgpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IGxvc3VtX25tRzVGYl9tbzFfZHNoaWcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9U1NCLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IHNlcmllcykpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3JpYmJvbihkYXRhID0gYXN1bV9ubUc1RmJfbW8xX2RzaGlnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1pbj1TU0Jsb3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4PVNTQmhpZ2gpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSAiYmxhY2siLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4yKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCJibGFjayIsIGVicGFsWzg6OV0pKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWVfY2xlYW4oKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWUoYXhpcy50aXRsZS55LmxlZnQgPSBlbGVtZW50X3RleHQodmp1c3QgPSAtMC4wNSwgaGp1c3QgPSAwLjk1KSkpDQoNCiMgRnBsb3QoTE8pDQpsb2Zfbm1HNUZiX21vMV9kc2hpZyA8LSBnZ3Bsb3RseShnZ3Bsb3QoKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fbGluZShkYXRhID0gbG9zdW1fbm1HNUZiX21vMV9kc2hpZywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PUZiYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IHNlcmllcykpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9yaWJib24oZGF0YSA9IGFzdW1fbm1HNUZiX21vMV9kc2hpZywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1pbj1GbG93LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltYXg9RmhpZ2gpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gImJsYWNrIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjMpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCJibGFjayIsIGVicGFsWzg6OV0pKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2NsZWFuKCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZShheGlzLnRpdGxlLnkubGVmdCA9IGVsZW1lbnRfdGV4dCh2anVzdCA9IC0wLjA1LCBoanVzdCA9IDAuOTUpKSkNCg0KIyByZWNwbG90KExPKQ0KbG9yZWNfbm1HNUZiX21vMV9kc2hpZyA8LSBnZ3Bsb3RseShnZ3Bsb3QoKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9saW5lKGRhdGEgPSBsb3N1bV9ubUc1RmJfbW8xX2RzaGlnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PVJfYWdlMSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBzZXJpZXMpKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9yaWJib24oZGF0YSA9IGFzdW1fbm1HNUZiX21vMV9kc2hpZywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW49UmxvdywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltYXg9UmhpZ2gpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSAiYmxhY2siLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4zKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCJibGFjayIsIGVicGFsWzg6OV0pKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWVfY2xlYW4oKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWUoYXhpcy50aXRsZS55LmxlZnQgPSBlbGVtZW50X3RleHQodmp1c3QgPSAtMC4wNSwgaGp1c3QgPSAwLjk1KSkpDQoNCiMgQ2F0Y2ggcGxvdCAoTE8pDQpsb2NhX25tRzVGYl9tbzFfZHNoaWcgPC0gZ2dwbG90bHkoZ2dwbG90KCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9saW5lKGRhdGEgPSBsb3N1bV9ubUc1RmJfbW8xX2RzaGlnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1DYXRjaEVzdCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IHNlcmllcykpKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9yaWJib24oZGF0YSA9IGFzdW1fbm1HNUZiX21vMV9kc2hpZ1thc3VtX25tRzVGYl9tbzFfZHNoaWckWWVhciAhPSAoRGF0YVllYXIrMSksIF0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1pbj1DYXRjaGxvdywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1heD1DYXRjaGhpZ2gpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9ICJibGFjayIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMykgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9wb2ludChkYXRhID0gYXN1bV9ubUc1RmJfbW8xX2RzaGlnW2FzdW1fbm1HNUZiX21vMV9kc2hpZyRZZWFyICE9IChEYXRhWWVhcisxKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1DYXRjaE9icyksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNoYXBlID0gMywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gZWJwYWxbNV0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBlYnBhbFs1XSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeWxhYigiQ2F0Y2ggKHRvbm5lcykiKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoImJsYWNrIiwgZWJwYWxbODo5XSkpKyANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2NsZWFuKCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWUoYXhpcy50aXRsZS55LmxlZnQgPSBlbGVtZW50X3RleHQodmp1c3QgPSAtMC4wNSwgaGp1c3QgPSAwLjk1KSkpDQoNCmxheW91dChzdWJwbG90KGxvc3NiX25tRzVGYl9tbzFfZHNoaWcsIGxvZl9ubUc1RmJfbW8xX2RzaGlnLCBsb3JlY19ubUc1RmJfbW8xX2RzaGlnLCBsb2NhX25tRzVGYl9tbzFfZHNoaWcsIG5yb3dzID0gMiwgc2hhcmVYID0gVFJVRSwgdGl0bGVZID0gVFJVRSksIHNob3dsZWdlbmQ9RkFMU0UpDQpgYGANCg0KIyMjIyBSZXRyb3NwZWN0aXZlcw0KYGBge3IgY2FsY3VsYXRlUmV0cm9zX25tRzVGYl9tbzFfZHNoaWd9DQojPT09DQojIENyZWF0ZSBkYXRhZnJhbWUgb2YgY3VycmVudCB5ZWFyJ3MgZml0IGZvciBwbG90dGluZw0KIz09PT0NCiMgSUNfYWdnX3RlbXAgPC0gYWdncmVnYXRlKENBVE9OflllYXIsIGljX2NsZWFuW2ljX2NsZWFuJENhdGNoQ2F0ZWdvcnkgJWluJSBjKCJMYW5kaW5ncyIsICJEaXNjYXJkcyIpLCBdLCBGVU4gPSAic3VtIikNCmFzdW1fbm1HNUZiX21vMV9kc2hpZyA8LSBhcy5kYXRhLmZyYW1lKHN1bW1hcnkoZml0X25tRzVGYl9tbzFfZHNoaWcpKQ0KYXN1bV9ubUc1RmJfbW8xX2RzaGlnJFllYXIgPC0gYXMuaW50ZWdlcihyb3cubmFtZXMoc3VtbWFyeShmaXRfbm1HNUZiX21vMV9kc2hpZykpKQ0KY3Rfbm1HNUZiX21vMV9kc2hpZyA8LSBhcy5kYXRhLmZyYW1lKGNhdGNodGFibGUoZml0X25tRzVGYl9tbzFfZHNoaWcsIG9icy5zaG93ID0gVFJVRSkpDQpjdF9ubUc1RmJfbW8xX2RzaGlnJFllYXIgPC0gYXMuaW50ZWdlcihyb3duYW1lcyhjdF9ubUc1RmJfbW8xX2RzaGlnKSkNCnJvd25hbWVzKGN0X25tRzVGYl9tbzFfZHNoaWcpIDwtIE5VTEwNCmN0X25tRzVGYl9tbzFfZHNoaWcgPC0gcmJpbmQoY3Rfbm1HNUZiX21vMV9kc2hpZywgZGF0YS5mcmFtZShFc3RpbWF0ZSA9IE5BLCBMb3c9TkEsIEhpZ2g9TkEsIHNvcC5jYXRjaD1OQSwgWWVhcj1hcy5pbnRlZ2VyKDIwMjQpKSkNCmFzdW1fbm1HNUZiX21vMV9kc2hpZyA8LSBtZXJnZSh4ID0gYXN1bV9ubUc1RmJfbW8xX2RzaGlnLCB5ID0gY3Rfbm1HNUZiX21vMV9kc2hpZywgYnkgPSAiWWVhciIpDQpjb2xuYW1lcyhhc3VtX25tRzVGYl9tbzFfZHNoaWcpIDwtIGMoIlllYXIiLCAiUl9hZ2UxIiwgIlJsb3ciLCAiUmhpZ2giLCAiU1NCIiwgIlNTQmxvdyIsICJTU0JoaWdoIiwgIkZiYXIiLCAiRmxvdyIsICJGaGlnaCIsICJDYXRjaEVzdCIsICJDYXRjaGxvdyIsICJDYXRjaGhpZ2giLCAiQ2F0Y2hPYnMiKQ0KDQphc3VtX25tRzVGYl9tbzFfZHNoaWckc2VyaWVzIDwtIHJlcCgiZnVsbCIsIHRpbWVzID0gbnJvdyhhc3VtX25tRzVGYl9tbzFfZHNoaWcpKQ0KDQojPT09PT0NClJFVFJPX25tRzVGYl9tbzFfZHNoaWc8LXJldHJvKGZpdF9ubUc1RmJfbW8xX2RzaGlnLCB5ZWFyPTUpDQpyaG9fbm1HNUZiX21vMV9kc2hpZyA8LSBtb2huKFJFVFJPX25tRzVGYl9tbzFfZHNoaWcsIGxhZyA9IDEpDQoNCiMjIE1ha2UgUkVUUk9zIGluIGJldHRlciBwbG90dGluZyBmb3JtYXQNCnJldF9ubUc1RmJfbW8xX2RzaGlnX2RmIDwtIGFzdW1fbm1HNUZiX21vMV9kc2hpZ1thc3VtX25tRzVGYl9tbzFfZHNoaWckWWVhciAhPSBtYXgoYXN1bV9ubUc1RmJfbW8xX2RzaGlnJFllYXIpLCBdDQoNCmZvcihpIGluIDE6bGVuZ3RoKFJFVFJPX25tRzVGYl9tbzFfZHNoaWcpKXsNCiAgdHN1bSA8LSBhcy5kYXRhLmZyYW1lKHN1bW1hcnkoUkVUUk9fbm1HNUZiX21vMV9kc2hpZ1tbaV1dKSkNCiAgdHN1bSRZZWFyIDwtIGFzLmludGVnZXIocm93Lm5hbWVzKHN1bW1hcnkoUkVUUk9fbm1HNUZiX21vMV9kc2hpZ1tbaV1dKSkpDQogIHRzdW0gPC0gY2JpbmQodHN1bSwgY2F0Y2h0YWJsZShSRVRST19ubUc1RmJfbW8xX2RzaGlnW1tpXV0sIG9icy5zaG93ID0gVFJVRSkpDQogIHRzdW0kc2VyaWVzIDwtIGFzLmNoYXJhY3RlcihyZXAoaSwgbnJvdyh0c3VtKSkpDQogIGNvbG5hbWVzKHRzdW0pIDwtIGMoIlJfYWdlMSIsICJSbG93IiwgIlJoaWdoIiwgIlNTQiIsICJTU0Jsb3ciLCAiU1NCaGlnaCIsICJGYmFyIiwgIkZsb3ciLCAiRmhpZ2giLCAiWWVhciIsICJDYXRjaEVzdCIsICJDYXRjaGxvdyIsICJDYXRjaGhpZ2giLCAiQ2F0Y2hPYnMiLCAic2VyaWVzIikNCiAgdHN1bSA8LSB0c3VtW3RzdW0kWWVhciAhPSBtYXgodHN1bSRZZWFyKSwgXQ0KICByZXRfbm1HNUZiX21vMV9kc2hpZ19kZiA8LSByYmluZChyZXRfbm1HNUZiX21vMV9kc2hpZ19kZiwgdHN1bSkNCn0NCnJldF9ubUc1RmJfbW8xX2RzaGlnX2RmJHNlcmllcyA8LSBmYWN0b3IocmV0X25tRzVGYl9tbzFfZHNoaWdfZGYkc2VyaWVzLCBsZXZlbHMgPSBjKCJmdWxsIiwgIjEiLCAiMiIsICIzIiwgIjQiLCAiNSIpKQ0KYGBgDQoNCmBgYHtyIGZpZy5jYXA9IlJldHJvc3BlY3RpdmUgYW5hbHlzZXMgZm9yIFNTQiAodG9wLWxlZnQpLCBGIGZvciBhZ2VzIDMtNSAodG9wLXJpZ2h0KSwgcmVjcnVpdG1lbnQgKGJvdHRvbS1sZWZ0KSwgYW5kIGNhdGNoIChib3R0b20tcmlnaHQpLCBmcm9tIHRoZSBtb2RlbCB3aXRoIGhpZ2ggZGlzY2FyZCBzdXJ2aXZhbC4ifQ0KIyBzc2JwbG90KFJFVFJPKQ0KcmV0c3NiX25tRzVGYl9tbzFfZHNoaWcgPC0gbGF5b3V0KGdncGxvdGx5KGdncGxvdCgpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fbGluZShkYXRhID0gcmV0X25tRzVGYl9tbzFfZHNoaWdfZGYsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PVNTQiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IHNlcmllcykpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fcmliYm9uKGRhdGEgPSBhc3VtX25tRzVGYl9tbzFfZHNoaWdbYXN1bV9ubUc1RmJfbW8xX2RzaGlnJFllYXIgIT0gbWF4KGFzdW1fbm1HNUZiX21vMV9kc2hpZyRZZWFyKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWluPVNTQmxvdywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1heD1TU0JoaWdoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSAiYmxhY2siLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjIpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFubm90YXRlKGdlb20gPSAidGV4dCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gbWF4KHJldF9ubUc1RmJfbW8xX2RzaGlnX2RmJFNTQmhpZ2gpKjAuODUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4ID0gKChtYXgocmV0X25tRzVGYl9tbzFfZHNoaWdfZGYkWWVhciktbWluKHJldF9ubUc1RmJfbW8xX2RzaGlnX2RmJFllYXIpKSowLjIwKSttaW4ocmV0X25tRzVGYl9tbzFfZHNoaWdfZGYkWWVhciksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbCA9IHBhc3RlMCgiTW9obidzIFJobyA9ICIsIHJvdW5kKHJob19ubUc1RmJfbW8xX2RzaGlnWzJdLCBkaWdpdHMgPSAzKSkpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiYmxhY2siLCBlYnBhbFsobGVuZ3RoKGVicGFsKS00KTpsZW5ndGgoZWJwYWwpXSkpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2NsZWFuKCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXhpcy50aXRsZS55LmxlZnQgPSBlbGVtZW50X3RleHQodmp1c3QgPSAtMC4wNSwgaGp1c3QgPSAwLjk1KSkpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNob3dsZWdlbmQgPSBGQUxTRSkNCg0KIyBGcGxvdChSRVRSTykNCnJldGZfbm1HNUZiX21vMV9kc2hpZyA8LSBsYXlvdXQoZ2dwbG90bHkoZ2dwbG90KCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fbGluZShkYXRhID0gcmV0X25tRzVGYl9tbzFfZHNoaWdfZGYsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9RmJhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBzZXJpZXMpKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2VvbV9yaWJib24oZGF0YSA9IGFzdW1fbm1HNUZiX21vMV9kc2hpZ1thc3VtX25tRzVGYl9tbzFfZHNoaWckWWVhciAhPSBtYXgoYXN1bV9ubUc1RmJfbW8xX2RzaGlnJFllYXIpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1pbj1GbG93LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1heD1GaGlnaCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9ICJibGFjayIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjMpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbm5vdGF0ZShnZW9tID0gInRleHQiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSBtYXgocmV0X25tRzVGYl9tbzFfZHNoaWdfZGYkRmhpZ2gpKjAuODUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeCA9ICgobWF4KHJldF9ubUc1RmJfbW8xX2RzaGlnX2RmJFllYXIpLW1pbihyZXRfbm1HNUZiX21vMV9kc2hpZ19kZiRZZWFyKSkqMC44MCkrbWluKHJldF9ubUc1RmJfbW8xX2RzaGlnX2RmJFllYXIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsID0gcGFzdGUwKCJNb2huJ3MgUmhvID0gIiwgcm91bmQocmhvX25tRzVGYl9tbzFfZHNoaWdbM10sIGRpZ2l0cyA9IDMpKSkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiYmxhY2siLCBlYnBhbFsobGVuZ3RoKGVicGFsKS00KTpsZW5ndGgoZWJwYWwpXSkpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZV9jbGVhbigpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXhpcy50aXRsZS55LmxlZnQgPSBlbGVtZW50X3RleHQodmp1c3QgPSAtMC4wNSwgaGp1c3QgPSAwLjk1KSkpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaG93bGVnZW5kID0gRkFMU0UpDQoNCiMgcmVjcGxvdChSRVRSTykNCnJldHJlY19ubUc1RmJfbW8xX2RzaGlnIDwtIGxheW91dChnZ3Bsb3RseShnZ3Bsb3QoKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IHJldF9ubUc1RmJfbW8xX2RzaGlnX2RmLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1SX2FnZTEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBzZXJpZXMpKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3JpYmJvbihkYXRhID0gYXN1bV9ubUc1RmJfbW8xX2RzaGlnW2FzdW1fbm1HNUZiX21vMV9kc2hpZyRZZWFyICE9IG1heChhc3VtX25tRzVGYl9tbzFfZHNoaWckWWVhciksIF0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1pbj1SbG93LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4PVJoaWdoKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSAiYmxhY2siLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjMpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFubm90YXRlKGdlb20gPSAidGV4dCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PSBtYXgocmV0X25tRzVGYl9tbzFfZHNoaWdfZGYkUmhpZ2gpKjAuODUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4ID0gKChtYXgocmV0X25tRzVGYl9tbzFfZHNoaWdfZGYkWWVhciktbWluKHJldF9ubUc1RmJfbW8xX2RzaGlnX2RmJFllYXIpKSowLjIwKSttaW4ocmV0X25tRzVGYl9tbzFfZHNoaWdfZGYkWWVhciksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbCA9IHBhc3RlMCgiTW9obidzIFJobyA9ICIsIHJvdW5kKHJob19ubUc1RmJfbW8xX2RzaGlnWzFdLCBkaWdpdHMgPSAzKSkpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiYmxhY2siLCBlYnBhbFsobGVuZ3RoKGVicGFsKS00KTpsZW5ndGgoZWJwYWwpXSkpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2NsZWFuKCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXhpcy50aXRsZS55LmxlZnQgPSBlbGVtZW50X3RleHQodmp1c3QgPSAtMC4wNSwgaGp1c3QgPSAwLjk1KSkpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNob3dsZWdlbmQgPSBGQUxTRSkNCg0KIyMgQ2F0Y2ggcGxvdCAoUkVUUk8pDQpyZXRjYV9ubUc1RmJfbW8xX2RzaGlnIDwtIGdncGxvdGx5KGdncGxvdCgpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IHJldF9ubUc1RmJfbW8xX2RzaGlnX2RmLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PUNhdGNoRXN0LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IHNlcmllcykpKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGdlb21fcmliYm9uKGRhdGEgPSBhc3VtX25tRzVGYl9tbzFfZHNoaWdbYXN1bV9ubUc1RmJfbW8xX2RzaGlnJFllYXIgIT0gbWF4KGFzdW1fbm1HNUZiX21vMV9kc2hpZyRZZWFyKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW49Q2F0Y2hsb3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4PUNhdGNoaGlnaCksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9ICJibGFjayIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjMpICsNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnZW9tX3BvaW50KGRhdGEgPSBhc3VtX25tRzVGYl9tbzFfZHNoaWdbYXN1bV9ubUc1RmJfbW8xX2RzaGlnJFllYXIgIT0gbWF4KGFzdW1fbm1HNUZiX21vMV9kc2hpZyRZZWFyKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PUNhdGNoT2JzKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNoYXBlID0gMywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IGVicGFsWzVdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IGVicGFsWzVdKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeWxhYigiQ2F0Y2ggKHRvbm5lcykiKSArDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCJibGFjayIsIGVicGFsWyhsZW5ndGgoZWJwYWwpLTQpOmxlbmd0aChlYnBhbCldKSkrIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lX2NsZWFuKCkgKw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZW1lKGF4aXMudGl0bGUueS5sZWZ0ID0gZWxlbWVudF90ZXh0KHZqdXN0ID0gLTAuMDUsIGhqdXN0ID0gMC45NSkpKQ0KDQpyZXRfZnAgPC0gc3R5bGUoc3VicGxvdChyZXRzc2Jfbm1HNUZiX21vMV9kc2hpZywgcmV0Zl9ubUc1RmJfbW8xX2RzaGlnLCByZXRyZWNfbm1HNUZiX21vMV9kc2hpZywgcmV0Y2Ffbm1HNUZiX21vMV9kc2hpZywgbnJvd3MgPSAyLCBzaGFyZVggPSBGQUxTRSwgc2hhcmVZID0gRkFMU0UsIHRpdGxlWSA9IFRSVUUpLA0KICAgICAgICAgICAgICAgIHNob3dsZWdlbmQ9RkFMU0UsDQogICAgICAgICAgICAgICAgdHJhY2VzID0gYyg4OigoNyo0KSsyKSkpDQoNCmxheW91dChyZXRfZnAsIGxlZ2VuZCA9IGxpc3Qob3JpZW50YXRpb24gPSAnaCcsIHggPSAwLjUsIHhhbmNob3IgPSAnY2VudGVyJywgeSA9IC0wLjA1LCB5YW5jaG9yID0gJ3RvcCcsIGJvcmRlcndpZHRoID0gMCkpDQpgYGANCg0KIyBDb21wYXJpc29uIG9mIERpc2NhcmQgU3Vydml2YWwgU2NlbmFyaW9zDQpBZnRlciBpbnRlcnJvZ2F0aW5nIHRoZSByZXNpZHVhbHMgYW5kIHRoZSBtb2RlbCBmaXRzIHRvIG9ic2VydmF0aW9ucywgd2UgY2FuIGFsc28gY29tcGFyZSB0aGUgQUlDcyBvZiB0aGVzZSBtb2RlbHMsIGFzIHdlJ3ZlIG9ubHkgbW9kaWZpZWQgdGhlIGlucHV0IGRhdGEuICBXZSdsbCBhbHNvIGFnZ3JlZ2F0ZSBhbGwgb2YgdGhlIE1vaG4ncyByaG8gdmFsdWVzIGZvciBlYXNpZXIgY29tcGFyaXNvbnMuDQoNCiMjIEJhc2ljIGZpdCBhbmQgZGlhZ25vc3RpYyB2YXJpYWJsZXMNCmBgYHtyIG5tQUlDVGFibGV9DQpubUFJQyA8LSBkYXRhLmZyYW1lKCdUeXBlIG9mIE0nID0gYygiQmFzZSBNb2RlbCIsICJBZ2UxIE1hdHVyaXR5IHRvIFplcm8iLCAiTG93IERpc2NhcmQgU3Vydml2YWwiLCAiTWVkaXVtIERpc2NhcmQgU3Vydml2YWwiLCAiSGlnaCBEaXNjYXJkIFN1cnZpdmFsIiksDQogICAgICAgICAgICAgICAgICAgIEFJQyA9IGMoQUlDKGZpdF9ubUc1RmIpLCBBSUMoZml0X25tRzVGYl9tbzEpLCBBSUMoZml0X25tRzVGYl9tbzFfZHNsb3cpLCBBSUMoZml0X25tRzVGYl9tbzFfZHNtZWQpLCBBSUMoZml0X25tRzVGYl9tbzFfZHNoaWcpKSwNCiAgICAgICAgICAgICAgICAgICAgTm8uUGFyYW1zID0gYyhsZW5ndGgoY29lZihmaXRfbm1HNUZiKSksIGxlbmd0aChjb2VmKGZpdF9ubUc1RmJfbW8xKSksIGxlbmd0aChjb2VmKGZpdF9ubUc1RmJfbW8xX2RzbG93KSksIGxlbmd0aChjb2VmKGZpdF9ubUc1RmJfbW8xX2RzbWVkKSksIGxlbmd0aChjb2VmKGZpdF9ubUc1RmJfbW8xX2RzaGlnKSkpLA0KICAgICAgICAgICAgICAgICAgICBSaG8uU1NCID0gYyhyaG9fbm1HNUZiWzJdLCByaG9fbm1HNUZiX21vMVsyXSwgcmhvX25tRzVGYl9tbzFfZHNsb3dbMl0sIHJob19ubUc1RmJfbW8xX2RzbWVkWzJdLCByaG9fbm1HNUZiX21vMV9kc2hpZ1syXSksDQogICAgICAgICAgICAgICAgICAgIFJoby5GID0gYyhyaG9fbm1HNUZiWzNdLCByaG9fbm1HNUZiX21vMVszXSwgcmhvX25tRzVGYl9tbzFfZHNsb3dbM10sIHJob19ubUc1RmJfbW8xX2RzbWVkWzNdLCByaG9fbm1HNUZiX21vMV9kc2hpZ1szXSksDQogICAgICAgICAgICAgICAgICAgIFJoby5SZWMgPSBjKHJob19ubUc1RmJbMV0sIHJob19ubUc1RmJfbW8xWzFdLCByaG9fbm1HNUZiX21vMV9kc2xvd1sxXSwgcmhvX25tRzVGYl9tbzFfZHNtZWRbMV0sIHJob19ubUc1RmJfbW8xX2RzaGlnWzFdKSkNCg0Ka2FibGUobm1BSUMsDQogICAgICBjYXB0aW9uID0gIk1lYXN1cmVzIG9mIG1vZGVsIGZpdCB1bmRlciB2YXJpb3VzIGh5cG90aGVzZXMgb2YgbmF0dXJhbCBtb3J0YWxpdHkuIikNCmBgYA0KDQojIyBDb21wYXJpc29uIG9mIG1vZGVsIGVzdGltYXRlcw0KTm93IHRoYXQgd2UndmUgY29uc2lkZXJlZCB0aGUgbW9kZWwgZml0cywgZGlhZ25vc3RpY3MgYW5kIHR1bmluZywgd2UgbWlnaHQgYXMgd2VsbCBoYXZlIGEgbG9vayBhdCBob3cgdGhlIG1vZGVscycgZXN0aW1hdGVzIGNvbXBhcmUuDQoNCldlIGNhbiBzZWUgZnJvbSB0aGUgZ3JhcGhzIHRoYXQgYXR0ZW1wdHMgdG8gYWNjb3VudCBmb3IgZGlzY2FyZCBzdXJ2aXZhbCBieSByZWR1Y2luZyB0aGUgY2F0Y2hlcyBwcm9wb3J0aW9uYWxseSwgaGF2ZSB0aGUgcmVzdWx0IG9mIHNjYWxpbmcgdGhlIGVzdGltYXRlcyBvZiBTU0IuIEluIHRoaXMgY2FzZSwgaW4gdGhlIGxhdGVzdCBkYXRhIHllYXIgKGByIHByaW50KERhdGFZZWFyKWApLCB3ZSBzZWUgYSBgciByb3VuZCgoKGFzdW1fbm1HNUZiX21vMV9kc2xvd1thc3VtX25tRzVGYl9tbzFfZHNsb3ckWWVhciA9PSBEYXRhWWVhciwgIlNTQiJdIC0gYXN1bV9ubUc1RmJfbW8xW2FzdW1fbm1HNUZiX21vMSRZZWFyID09IERhdGFZZWFyLCAiU1NCIl0pL2FzdW1fbm1HNUZiX21vMVthc3VtX25tRzVGYl9tbzEkWWVhciA9PSBEYXRhWWVhciwgIlNTQiJdKSoxMDAsIDApYCUgY2hhbmdlIGZyb20gdGhlIG1vZGVsIG5vdCBhY2NvdW50aW5nIGZvciBkaXNjYXJkIHN1cnZpdmFsIHRvIHRoZSBzY2VuYXJpbyB3aXRoIHRoZSBsb3dlc3QgbGV2ZWxzIG9mIHN1cnZpdmFsLiAgV2hlbiB3ZSBjb21wYXJlIHRvIHRoZSBtb2RlbCB3aXRoIHRoZSBoaWdoZXN0IGxldmVscyBvZiBzdXJ2aXZhbCwgd2Ugc2VlIGFuIGV2ZW4gZ3JlYXRlciBjaGFuZ2Ugb2YgYHIgcm91bmQoKChhc3VtX25tRzVGYl9tbzFfZHNoaWdbYXN1bV9ubUc1RmJfbW8xX2RzaGlnJFllYXIgPT0gRGF0YVllYXIsICJTU0IiXSAtIGFzdW1fbm1HNUZiX21vMVthc3VtX25tRzVGYl9tbzEkWWVhciA9PSBEYXRhWWVhciwgIlNTQiJdKS9hc3VtX25tRzVGYl9tbzFbYXN1bV9ubUc1RmJfbW8xJFllYXIgPT0gRGF0YVllYXIsICJTU0IiXSkqMTAwLCAwKWAlDQoNCmBgYHtyIGZpZy5jYXA9ICJFc3RpbWF0ZWQgc3Bhd25pbmcgc3RvY2sgYmlvbWFzcyBmb3IgcGxlLjI3LjIxLTMyIGFuZCA5NSUgY29uZmlkZW5jZSBpbnRlcnZhbHMgKHRvbm5lcykuIFB1cnBsZSBpcyB0aGUgY3VycmVudCB3b3JraW5nIGRvY3VtZW50J3MgYmFzZWxpbmUgbW9kZWwsIGdyZWVuIGlzIHdpdGggbWF0dXJpdHkgYXQgYWdlMSBzZXQgdG8gemVybywgb3JhbmdlIGlzIHdpdGggTG93IGRpc2NhcmQgU3Vydml2YWwsIGJsdWUgaXMgd2l0aCBtZWRpdW0gZGlzY2FyZCBzdXJ2aXZhbCwgYW5kIHJlZCBpcyB3aXRoIGhpZ2hkaXNjYXJkIHN1cnZpdmFsLiJ9DQojIHNzYmxpbmVzIDwtIGRhdGEuZnJhbWUoeWludGVyY2VwdD1jKDQ3MzAsIDQzNzAsIDM2MzUpLCBMaW5lcyA9IGZhY3Rvcih4ID0gYygiTVNZLUJ0cmlnZ2VyIiwgIkJwYSIsICJCbGltIiksbGV2ZWxzID0gYygiTVNZLUJ0cmlnZ2VyIiwgIkJwYSIsICJCbGltIikpKQ0KcHNzYiA8LSBnZ3Bsb3QoKSArDQogIGdlb21fbGluZShkYXRhID0gYXN1bV9ubUc1RmIsDQogICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgeT1TU0IsDQogICAgICAgICAgICAgICAgICAgICAgICAgIHNlcmllcz0iQmFzZWxpbmUiKSwNCiAgICAgICAgICAgIGNvbG91ciA9IGVicGFsWzFdKSArDQogIGdlb21fcmliYm9uKGRhdGEgPSBhc3VtX25tRzVGYiwNCiAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1pbj1TU0Jsb3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1heD1TU0JoaWdoKSwNCiAgICAgICAgICAgICAgZmlsbCA9IGVicGFsWzFdLA0KICAgICAgICAgICAgICBhbHBoYSA9IDAuMykgKw0KICBnZW9tX2xpbmUoZGF0YSA9IGFzdW1fbm1HNUZiX21vMSwNCiAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICB5PVNTQiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgc2VyaWVzPSJNYXR1cml0eSBhdCBhZ2UxIHNldCB0byB6ZXJvIiksDQogICAgICAgICAgICBjb2xvdXIgPSBlYnBhbFsyXSkgKw0KICBnZW9tX3JpYmJvbihkYXRhID0gYXN1bV9ubUc1RmJfbW8xLA0KICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWluPVNTQmxvdywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4PVNTQmhpZ2gpLA0KICAgICAgICAgICAgICBmaWxsID0gZWJwYWxbMl0sDQogICAgICAgICAgICAgIGFscGhhID0gMC4zKSArDQogIGdlb21fbGluZShkYXRhID0gYXN1bV9ubUc1RmJfbW8xX2RzbG93LA0KICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgIHk9U1NCLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBzZXJpZXM9IkxvdyBEaXNjYXJkIFN1cnZpdmFsIiksDQogICAgICAgICAgICBjb2xvdXIgPSBlYnBhbFszXSkgKw0KICBnZW9tX3JpYmJvbihkYXRhID0gYXN1bV9ubUc1RmJfbW8xX2RzbG93LA0KICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWluPVNTQmxvdywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4PVNTQmhpZ2gpLA0KICAgICAgICAgICAgICBmaWxsID0gZWJwYWxbM10sDQogICAgICAgICAgICAgIGFscGhhID0gMC4zKSArDQogIGdlb21fbGluZShkYXRhID0gYXN1bV9ubUc1RmJfbW8xX2RzbWVkLA0KICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgIHk9U1NCLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBzZXJpZXM9Ik1lZGl1bSBEaXNjYXJkIFN1cnZpdmFsIiksDQogICAgICAgICAgICBjb2xvdXIgPSBlYnBhbFs0XSkgKw0KICBnZW9tX3JpYmJvbihkYXRhID0gYXN1bV9ubUc1RmJfbW8xX2RzbWVkLA0KICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWluPVNTQmxvdywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4PVNTQmhpZ2gpLA0KICAgICAgICAgICAgICBmaWxsID0gZWJwYWxbNF0sDQogICAgICAgICAgICAgIGFscGhhID0gMC4zKSArDQogIGdlb21fbGluZShkYXRhID0gYXN1bV9ubUc1RmJfbW8xX2RzaGlnLA0KICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgIHk9U1NCLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBzZXJpZXM9IkhpZ2ggRGlzY2FyZCBTdXJ2aXZhbCIpLA0KICAgICAgICAgICAgY29sb3VyID0gZWJwYWxbMTNdKSArDQogIGdlb21fcmliYm9uKGRhdGEgPSBhc3VtX25tRzVGYl9tbzFfZHNoaWcsDQogICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW49U1NCbG93LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltYXg9U1NCaGlnaCksDQogICAgICAgICAgICAgIGZpbGwgPSBlYnBhbFsxM10sDQogICAgICAgICAgICAgIGFscGhhID0gMC4zKSArDQogIHRoZW1lX2NsZWFuKCkNCg0KZ2dwbG90bHkocHNzYiwgdG9vbHRpcCA9IGMoInNlcmllcyIsICJ4IiwgInkiKSkNCmBgYA0KDQpGaXNoaW5nIHByZXNzdXJlIG92ZXIgdGltZSBzZWVtcyB0byByZXNwb25kIHRvIHRoZSBjaGFuZ2VzIGluIHRoZSBlc3RpbWF0aW9ucyBvZiBTU0IsIHdoaWxlIGlucHV0IGRhdGEgZm9yIGNhdGNoZXMgKG9idmlvdXNseSkgcmVtYWluIHRoZSBzYW1lIGJldHdlbiB0aGUgdHdvIG1vZGVscy4gDQoNCmBgYHtyIGZpZy5jYXA9ICJBbm51YWwgZmlzaGluZyBtb3J0YWxpdHkgZXN0aW1hdGVzIGZvciBwbGUuMjcuMjEtMzIgYWdlcyAzLTUgYW5kIHBvaW50IHdpc2UgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWxzIGFyZSBzaG93biBieSBsaW5lIGFuZCBzaGFkZWQgYXJlYS4gICBQdXJwbGUgaXMgdGhlIGN1cnJlbnQgd29ya2luZyBkb2N1bWVudCdzIGJhc2VsaW5lIG1vZGVsLCBncmVlbiBpcyB3aXRoIG1hdHVyaXR5IGF0IGFnZTEgc2V0IHRvIHplcm8sIG9yYW5nZSBpcyB3aXRoIExvdyBkaXNjYXJkIFN1cnZpdmFsLCBibHVlIGlzIHdpdGggbWVkaXVtIGRpc2NhcmQgc3Vydml2YWwsIGFuZCByZWQgaXMgd2l0aCBoaWdoZGlzY2FyZCBzdXJ2aXZhbC4ifQ0KIyBmbGluZXMgPC0gZGF0YS5mcmFtZSh5aW50ZXJjZXB0PWMoMC4zMSwgMC44MSwgMS4wMCksIExpbmVzID0gZmFjdG9yKHggPSBjKCJGTVNZIiwgIkZwYSIsICJGbGltIiksIGxldmVscyA9IGMoIkZNU1kiLCAiRnBhIiwgIkZsaW0iKSkpDQpnZ3Bsb3RseShnZ3Bsb3QoKSArDQogICAgICAgICAgIGdlb21fbGluZShkYXRhID0gYXN1bV9ubUc1RmIsDQogICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1GYmFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXJpZXM9IkJhc2VsaW5lIiksDQogICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBlYnBhbFsxXSkgKw0KICAgICAgICAgICBnZW9tX3JpYmJvbihkYXRhID0gYXN1bV9ubUc1RmIsDQogICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW49RmxvdywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4PUZoaWdoLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcmllcz0iQmFzZWxpbmUiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IGVicGFsWzFdLA0KICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMykgKw0KICAgICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IGFzdW1fbm1HNUZiX21vMSwNCiAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PUZiYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcmllcz0iTWF0dXJpdHkgYXQgYWdlMSBzZXQgdG8gemVybyIpLA0KICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gZWJwYWxbMl0pICsNCiAgICAgICAgICAgZ2VvbV9yaWJib24oZGF0YSA9IGFzdW1fbm1HNUZiX21vMSwNCiAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1pbj1GbG93LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltYXg9RmhpZ2gsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VyaWVzPSJNYXR1cml0eSBhdCBhZ2UxIHNldCB0byB6ZXJvIiksDQogICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBlYnBhbFsyXSwNCiAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjMpICsNCiAgICAgICAgICAgZ2VvbV9saW5lKGRhdGEgPSBhc3VtX25tRzVGYl9tbzFfZHNsb3csDQogICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1GYmFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXJpZXM9IkxvdyBEaXNjYXJkIFN1cnZpdmFsIiksDQogICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBlYnBhbFszXSkgKw0KICAgICAgICAgICBnZW9tX3JpYmJvbihkYXRhID0gYXN1bV9ubUc1RmJfbW8xX2RzbG93LA0KICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWluPUZsb3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1heD1GaGlnaCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXJpZXM9IkxvdyBEaXNjYXJkIFN1cnZpdmFsIiksDQogICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBlYnBhbFszXSwNCiAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjMpICsNCiAgICAgICAgICAgZ2VvbV9saW5lKGRhdGEgPSBhc3VtX25tRzVGYl9tbzFfZHNtZWQsDQogICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1GYmFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXJpZXM9Ik1lZGl1bSBEaXNjYXJkIFN1cnZpdmFsIiksDQogICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBlYnBhbFs0XSkgKw0KICAgICAgICAgICBnZW9tX3JpYmJvbihkYXRhID0gYXN1bV9ubUc1RmJfbW8xX2RzbWVkLA0KICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWluPUZsb3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1heD1GaGlnaCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXJpZXM9Ik1lZGl1bSBEaXNjYXJkIFN1cnZpdmFsIiksDQogICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBlYnBhbFs0XSwNCiAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjMpICsNCiAgICAgICAgICAgZ2VvbV9saW5lKGRhdGEgPSBhc3VtX25tRzVGYl9tbzFfZHNoaWcsDQogICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1GYmFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXJpZXM9IkhpZ2ggRGlzY2FyZCBTdXJ2aXZhbCIpLA0KICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gZWJwYWxbMTNdKSArDQogICAgICAgICAgIGdlb21fcmliYm9uKGRhdGEgPSBhc3VtX25tRzVGYl9tbzFfZHNoaWcsDQogICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW49RmxvdywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4PUZoaWdoLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcmllcz0iSGlnaCBEaXNjYXJkIFN1cnZpdmFsIiksDQogICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBlYnBhbFsxM10sDQogICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4zKSArDQogICAgICAgICAgIHRoZW1lX2NsZWFuKCkpDQpgYGANCg0KRXN0aW1hdGlvbnMgb2YgcmVjcnVpdG1lbnQgaW4gdGhlIG1vc3QgcmVjZW50IHllYXJzIGZhbGwsIGFzIFNTQiBhbHNvIGZhbGxzIGluIHRoaXMgdmVyc2lvbiBvZiB0aGUgbW9kZWwsIGFnYWluIHByb2JhYmx5IGR1ZSB0byB0aGUgcmVkdWN0aW9uIGluIHN0b2NrIHdlaWdodHMgYXQgYWdlLg0KDQpgYGB7ciBmaWcuY2FwPSAiRml2ZSB5ZWFyIHNsaWRpbmcgd2luZG93IG1vZGVsIGFubnVhbCByZWNydWl0bWVudCBlc3RpbWF0ZXMgZm9yIHBsZS4yNy4yMS0zMiBhbmQgcG9pbnQgd2lzZSA5NSUgY29uZmlkZW5jZSBpbnRlcnZhbHMgYXJlIHNob3duIGJ5IGxpbmUgYW5kIHNoYWRlZCBhcmVhIChudW1iZXJzKS4gUHVycGxlIGlzIHRoZSBjdXJyZW50IHdvcmtpbmcgZG9jdW1lbnQncyBiYXNlbGluZSBtb2RlbCwgZ3JlZW4gaXMgd2l0aCBtYXR1cml0eSBhdCBhZ2UxIHNldCB0byB6ZXJvLCBvcmFuZ2UgaXMgd2l0aCBMb3cgZGlzY2FyZCBTdXJ2aXZhbCwgYmx1ZSBpcyB3aXRoIG1lZGl1bSBkaXNjYXJkIHN1cnZpdmFsLCBhbmQgcmVkIGlzIHdpdGggaGlnaGRpc2NhcmQgc3Vydml2YWwuIn0NCmdncGxvdGx5KGdncGxvdCgpICsNCiAgICAgICAgICAgZ2VvbV9saW5lKGRhdGEgPSBhc3VtX25tRzVGYiwNCiAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PVJfYWdlMSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VyaWVzPSJCYXNlbGluZSIpLA0KICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gZWJwYWxbMV0pICsNCiAgICAgICAgICAgZ2VvbV9yaWJib24oZGF0YSA9IGFzdW1fbm1HNUZiLA0KICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWluPVJsb3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1heD1SaGlnaCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXJpZXM9IkJhc2VsaW5lIiksDQogICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBlYnBhbFsxXSwNCiAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjMpICsNCiAgICAgICAgICAgZ2VvbV9saW5lKGRhdGEgPSBhc3VtX25tRzVGYl9tbzEsDQogICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1SX2FnZTEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcmllcz0iTWF0dXJpdHkgYXQgYWdlMSBzZXQgdG8gemVybyIpLA0KICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gZWJwYWxbMl0pICsNCiAgICAgICAgICAgZ2VvbV9yaWJib24oZGF0YSA9IGFzdW1fbm1HNUZiX21vMSwNCiAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1pbj1SbG93LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltYXg9UmhpZ2gsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VyaWVzPSJNYXR1cml0eSBhdCBhZ2UxIHNldCB0byB6ZXJvIiksDQogICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBlYnBhbFsyXSwNCiAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjMpICsNCiAgICAgICAgICAgZ2VvbV9saW5lKGRhdGEgPSBhc3VtX25tRzVGYl9tbzFfZHNsb3csDQogICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1SX2FnZTEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcmllcz0iTG93IERpc2NhcmQgU3Vydml2YWwiKSwNCiAgICAgICAgICAgICAgICAgICAgIGNvbG91ciA9IGVicGFsWzNdKSArDQogICAgICAgICAgIGdlb21fcmliYm9uKGRhdGEgPSBhc3VtX25tRzVGYl9tbzFfZHNsb3csDQogICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW49UmxvdywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4PVJoaWdoLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcmllcz0iTG93IERpc2NhcmQgU3Vydml2YWwiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IGVicGFsWzNdLA0KICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMykgKw0KICAgICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IGFzdW1fbm1HNUZiX21vMV9kc21lZCwNCiAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PVJfYWdlMSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VyaWVzPSJNZWRpdW0gRGlzY2FyZCBTdXJ2aXZhbCIpLA0KICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gZWJwYWxbNF0pICsNCiAgICAgICAgICAgZ2VvbV9yaWJib24oZGF0YSA9IGFzdW1fbm1HNUZiX21vMV9kc21lZCwNCiAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1pbj1SbG93LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltYXg9UmhpZ2gsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VyaWVzPSJNZWRpdW0gRGlzY2FyZCBTdXJ2aXZhbCIpLA0KICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gZWJwYWxbNF0sDQogICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4zKSArDQogICAgICAgICAgIGdlb21fbGluZShkYXRhID0gYXN1bV9ubUc1RmJfbW8xX2RzaGlnLA0KICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9Ul9hZ2UxLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXJpZXM9IkhpZ2ggRGlzY2FyZCBTdXJ2aXZhbCIpLA0KICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gZWJwYWxbMTNdKSArDQogICAgICAgICAgIGdlb21fcmliYm9uKGRhdGEgPSBhc3VtX25tRzVGYl9tbzFfZHNoaWcsDQogICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW49UmxvdywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4PVJoaWdoLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcmllcz0iSGlnaCBEaXNjYXJkIFN1cnZpdmFsIiksDQogICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBlYnBhbFsxM10sDQogICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4zKSArDQogICAgICAgICAgIHRoZW1lX2NsZWFuKCkpDQpgYGANCg0KYGBge3IgZmlnLmNhcD0gIkFubnVhbCBjYXRjaCBlc3RpbWF0ZXMgYW5kIDk1JSBjb25maWRlbmNlIGludGVydmFscyAobGluZSBhbmQgc2hhZGVkIGFyZWEsIHJlc3BlY3RpdmVseSkgZm9yIHBsZS4yNy4yMS0zMiBhbmQgcG9pbnQgYW5udWFsIG9ic2VydmF0aW9ucyAocG9pbnRzKS4gIFB1cnBsZSBpcyB0aGUgY3VycmVudCB3b3JraW5nIGRvY3VtZW50J3MgYmFzZWxpbmUgbW9kZWwsIGdyZWVuIGlzIHdpdGggbWF0dXJpdHkgYXQgYWdlMSBzZXQgdG8gemVybywgb3JhbmdlIGlzIHdpdGggTG93IGRpc2NhcmQgU3Vydml2YWwsIGJsdWUgaXMgd2l0aCBtZWRpdW0gZGlzY2FyZCBzdXJ2aXZhbCwgYW5kIHJlZCBpcyB3aXRoIGhpZ2hkaXNjYXJkIHN1cnZpdmFsLiJ9DQpnZ3Bsb3RseShnZ3Bsb3QoKSArDQogICAgICAgICAgIGdlb21fbGluZShkYXRhID0gYXN1bV9ubUc1RmJbYXN1bV9ubUc1RmIkWWVhciAhPSAoRGF0YVllYXIrMSksIF0sDQogICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1DYXRjaEVzdCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VyaWVzPSJCYXNlbGluZSIpLA0KICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gZWJwYWxbMV0pICsNCiAgICAgICAgICAgZ2VvbV9yaWJib24oZGF0YSA9IGFzdW1fbm1HNUZiW2FzdW1fbm1HNUZiJFllYXIgIT0gKERhdGFZZWFyKzEpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWluPUNhdGNobG93LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltYXg9Q2F0Y2hoaWdoLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcmllcz0iQmFzZWxpbmUiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IGVicGFsWzFdLA0KICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMykgKw0KICAgICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IGFzdW1fbm1HNUZiX21vMVthc3VtX25tRzVGYl9tbzEkWWVhciAhPSAoRGF0YVllYXIrMSksIF0sDQogICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1DYXRjaEVzdCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VyaWVzPSJNYXR1cml0eSBhdCBhZ2UxIHNldCB0byB6ZXJvIiksDQogICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBlYnBhbFsyXSkgKw0KICAgICAgICAgICBnZW9tX3JpYmJvbihkYXRhID0gYXN1bV9ubUc1RmJfbW8xW2FzdW1fbm1HNUZiX21vMSRZZWFyICE9IChEYXRhWWVhcisxKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1pbj1DYXRjaGxvdywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4PUNhdGNoaGlnaCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXJpZXM9Ik1hdHVyaXR5IGF0IGFnZTEgc2V0IHRvIHplcm8iKSwNCiAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IGVicGFsWzJdLA0KICAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMykgKw0KICAgICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IGFzdW1fbm1HNUZiX21vMV9kc2xvd1thc3VtX25tRzVGYl9tbzFfZHNsb3ckWWVhciAhPSAoRGF0YVllYXIrMSksIF0sDQogICAgICAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9WWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1DYXRjaEVzdCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VyaWVzPSJMb3cgRGlzY2FyZCBTdXJ2aXZhbCIpLA0KICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gZWJwYWxbM10pICsNCiAgICAgICAgICAgZ2VvbV9yaWJib24oZGF0YSA9IGFzdW1fbm1HNUZiX21vMV9kc2xvd1thc3VtX25tRzVGYl9tbzFfZHNsb3ckWWVhciAhPSAoRGF0YVllYXIrMSksIF0sDQogICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW49Q2F0Y2hsb3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1heD1DYXRjaGhpZ2gsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VyaWVzPSJMb3cgRGlzY2FyZCBTdXJ2aXZhbCIpLA0KICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gZWJwYWxbM10sDQogICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4zKSArDQogICAgICAgICAgIGdlb21fbGluZShkYXRhID0gYXN1bV9ubUc1RmJfbW8xX2RzbWVkW2FzdW1fbm1HNUZiX21vMV9kc21lZCRZZWFyICE9IChEYXRhWWVhcisxKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PUNhdGNoRXN0LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXJpZXM9Ik1lZGl1bSBEaXNjYXJkIFN1cnZpdmFsIiksDQogICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBlYnBhbFs0XSkgKw0KICAgICAgICAgICBnZW9tX3JpYmJvbihkYXRhID0gYXN1bV9ubUc1RmJfbW8xX2RzbWVkW2FzdW1fbm1HNUZiX21vMV9kc21lZCRZZWFyICE9IChEYXRhWWVhcisxKSwgXSwNCiAgICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1pbj1DYXRjaGxvdywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5bWF4PUNhdGNoaGlnaCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZXJpZXM9Ik1lZGl1bSBEaXNjYXJkIFN1cnZpdmFsIiksDQogICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBlYnBhbFs0XSwNCiAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjMpICsNCiAgICAgICAgICAgZ2VvbV9saW5lKGRhdGEgPSBhc3VtX25tRzVGYl9tbzFfZHNoaWdbYXN1bV9ubUc1RmJfbW8xX2RzaGlnJFllYXIgIT0gKERhdGFZZWFyKzEpLCBdLA0KICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVllYXIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9Q2F0Y2hFc3QsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcmllcz0iSGlnaCBEaXNjYXJkIFN1cnZpdmFsIiksDQogICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBlYnBhbFsxM10pICsNCiAgICAgICAgICAgZ2VvbV9yaWJib24oZGF0YSA9IGFzdW1fbm1HNUZiX21vMV9kc2hpZ1thc3VtX25tRzVGYl9tbzFfZHNoaWckWWVhciAhPSAoRGF0YVllYXIrMSksIF0sDQogICAgICAgICAgICAgICAgICAgICAgIG1hcHBpbmcgPSBhZXMoeD1ZZWFyLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHltaW49Q2F0Y2hsb3csDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeW1heD1DYXRjaGhpZ2gsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VyaWVzPSJIaWdoIERpc2NhcmQgU3Vydml2YWwiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IGVicGFsWzEzXSwNCiAgICAgICAgICAgICAgICAgICAgICAgYWxwaGEgPSAwLjMpICsNCiAgICAgICAgICAgeWxhYigiQ2F0Y2ggKHRvbm5lcykiKSArDQogICAgICAgICAgIHRoZW1lX2NsZWFuKCkpDQpgYGANCg0KIyBDb25jbHVzaW9ucw0KDQojIyBJbXBvc2luZyBhc3N1bXB0aW9ucyBhYm91dCBhZ2UgMSBtYXR1cml0eQ0KVGhlIHNldHRpbmcgb2YgYWdlIDEgcHJvcG9ydGlvbiBtYXR1cmUgdG8gemVybywgb3ZlcndyaXRlcyBwcm9wb3J0aW9ucyBkZXRlcm1pbmVkIGZyb20gc3VydmV5cyB3aXRoIGFuIGFzc3VtcHRpb24gYmFzZWQgb24gZXhwZXJ0IGtub3dsZWRnZS4gIFRoaXMgd291bGQgbm90LCBvcmRpbmFyaWx5LCBiZSBiZXN0IHByYWN0aWNlLiBIb3dldmVyLCBkdWUgdG8gdGhlIGRpZmZpY3VsdHkgaW4gZ2V0dGluZyByZWxpYWJsZSBhZ2UgcmVhZGluZyByaW5ncyBmcm9tIHRoZSBmaXJzdCB5ZWFyIG9mIGxpZmUsIG9uZSBjYW4gYXNzdW1lIHRoYXQgc29tZSBvZiB0aGUgZmlzaCByZXBvcnRlZCBhcyBtYXR1cmUgaW4gYWdlIDEsIGFyZSBmcm9tIHRoZSBhZ2UgMiBjb2hvcnQuICBGdXJ0aGVybW9yZSwganV2ZW5pbGUgYW5kIHByZS1hZHVsdCBwbGFpY2UgYXJlIGtub3duIHRvIGRpc3RyaWJ1dGUgdGhlbXNlbHZlcyBhY3Jvc3MgZGVwdGggZ3JhZGllbnRzIGFjY29yZGluZyB0byB0aGVpciBzaXplLiBJbiB0aGlzIGFyZWEsIHBsYWljZSBhcmUga25vd24gdG8gc3Bhd24gYW5kIHNldHRsZSBhcyBqdXZlbmlsZXMgb3ZlciBleHRlbmRlZCBwZXJpb2RzIGNyb3NzaW5nIHNlYXNvbnMsIHdoaWNoIGludHJvZHVjZXMgbGVuZ3RoLCBncm93dGggYW5kIHN1cnZpdmFsIGRpZmZlcmVudGlhbHMgaW50byB0aGUgdmFyaW91cyB3aXRoaW4teWVhciwgInNldHRsZW1lbnQgY29ob3J0cyIuICBUaGlzIG1lYW5zIHRoYXQgdGhlIHN1cnZleXMgdGhhdCBvcGVyYXRlIGluIGRlZXBlciB3YXRlcnMgYXJlIG1vcmUgbGlrZWx5IHRvIGNhdGNoIGluZGl2aWR1YWxzIGZyb20gdGhlIGxhcmdlciBlbmQgb2YgdGhlIHNpemUgc3BlY3RydW0gZm9yIGFueSBnaXZlbiBhZ2UgY29ob3J0LCBmdXJ0aGVyIGJpYXNpbmcgdGhlIHByb3BvcnRpb24gb2YgbWF0dXJlIGZpc2ggYXQgYW55IGdpdmVuIGFnZS4gIEFsbCBleHBlcnRzIGluIHRoZSB3b3Jrc2hvcCBhZ3JlZWQgdGhhdCBoYXZpbmcgc2lnbmlmaWNhbnQgcHJvcG9ydGlvbnMgb2YgYWdlIDEgcGxhaWNlIG1hdHVyZSB3YXMgdW5yZWFsaXN0aWMgYW5kIHRoYXQgYWNjZXB0aW5nIHRoZXNlIG51bWJlcnMgKHdoaWNoIGFyZSBsaWtlbHkgYSByZXN1bHQgb2Ygc2FtcGxpbmcgYmlhcyBhbmQgb2JzZXJ2YXRpb24gZXJyb3IpIHdhcyBwcm9iYWJseSBvdmVyLWluZmxhdGluZyBvdXIgZXN0aW1hdGlvbiBvZiBTU0IuDQoNCk9uY2Ugc2V0IHRvIHplcm8sIHRoZSBtb2RlbCBmaXQgdXRpbGlzaW5nIHRoZXNlIGRhdGEgZG9lcyBub3QgY2hhbmdlIChBSUNzID0gYHIgcm91bmQoYyhBSUMoZml0X25tRzVGYiksIEFJQyhmaXRfbm1HNUZiX21vMSkpLDIpYCwgcmVzcGVjdGl2ZWx5KSwgb25seSB0aGUgU1NCIGVzdGltYXRlcyBzY2FsZSB1cCBhbmQgZG93bi4gIFRoZSBTU0IgZXN0aW1hdGVzIGZhbGwgYnkgYHIgcm91bmQoKChhc3VtX25tRzVGYl9tbzFbYXN1bV9ubUc1RmJfbW8xJFllYXIgPT0gRGF0YVllYXIsICJTU0IiXSAtIGFzdW1fbm1HNUZiW2FzdW1fbm1HNUZiJFllYXIgPT0gRGF0YVllYXIsICJTU0IiXSkvYXN1bV9ubUc1RmJbYXN1bV9ubUc1RmIkWWVhciA9PSBEYXRhWWVhciwgIlNTQiJdKSoxMDAsIDApYCUgd2hlbiBzZXR0aW5nIGFnZTEgbWF0dXJpdHkgdG8gemVybywgYW5kIHdpbGwgbGlrZWx5IHJlZHVjZSB0aGUgaW50ZXItYW5udWFsIHZhcmlhYmlsaXR5IG9mIHRoZSBTU0IgZXN0aW1hdGVzIGJlY2F1c2Ugb2YgdGhlIGxhcmdlciB2YXJpYW5jZXMgYXJvdW5kIHRoZSBlc3RpbWF0aW9ucyBvZiBudW1iZXJzIGF0IGFnZTEuDQoNCiMjIEFjY291bnRpbmcgZm9yIGRpc2NhcmQgc3Vydml2YWwNCkluIHRoaXMgc2VjdGlvbiBvZiB0aGUgZG9jdW1lbnQgd2UgdXRpbGlzZWQgdGhlIHVwcGVyLCBsb3dlciwgYW5kIG1pZGRsZSB2YWx1ZXMgb2YgZXN0aW1hdGVzIG9mIGRpc2NhcmQgc3Vydml2YWwgZnJvbSB0aGUgbGl0ZXJhdHVyZSwgd2hlcmUgc3R1ZGllcyBleGlzdGVkLiBGb3IgY2F0Y2ggc2VnbWVudHMgd2hlcmUgdGhlcmUgd2FzIG5vIGRhdGEsIHdlIGJvcnJvd2VkIG9yIGV4dHJhcG9sYXRlZCBrbm93biB2YWx1ZXMgYW5kIHRyZW5kcyAocmVzcGVjdGl2ZWx5KSB0byBlbnN1cmUgYWxsIHNlZ21lbnRzIGhhZCBzb21lIGVzdGltYXRlIG9mIHN1cnZpdmFsLiBUaGlzIHByb3ZpZGVkIHVzIHdpdGggdGhyZWUgc2NlbmFyaW9zIHVwb24gd2hpY2ggd2UgY291bGQgcnVuIGEgdHlwZSBvZiBzZW5zaXRpdml0eSBhbmFseXNpcywgdG8gdmlzdWFsaXNlIHRoZSBpbXBhY3QgdGhhdCBhY2NvdW50aW5nIGZvciBkaXNjYXJkIHN1cnZpdmFsIG1pZ2h0IGhhdmUgb24gYm90aCB0aGUgbW9kZWwgZml0IGFuZCB0aGUgcGVyY2VwdGlvbiBvZiB0aGUgc3RvY2suIA0KDQpIZXJlIHdlIHNlZSB0aGF0IHV0aWxpc2luZyB0aGUgYW55IG9mIHRoZSBuZXcgY2F0Y2ggc2NlbmFyaW9zIGhhcyBub3Qgc3Vic3RhbnRpYWwgaW1wYWN0IG9uIHRoZSBtb2RlbCBmaXQsIHdpdGggYWxsIEFJQyB2YWx1ZXMgYmVpbmcgd2l0aGluIGEgcmFuZ2Ugb2YgZml2ZSBmcm9tIG9uZSBhbm90aGVyLCBhbmQgYWxsIHJldHJvLXBsb3RzIC8gTW9obidzIHJobyBzdGF0aXN0aWNzIGJlaW5nIGFjY2VwdGFibGUuDQoNCkhvd2V2ZXIsIHRoZXJlIGFyZSBzdWJzdGFudGlhbCBpbXBhY3RzIG9uIG91ciBwZXJjZXB0aW9uIG9mIHRoZSBzdG9jayBzaXplLCB3aGVyZSB0aGUgbG93IGVuZCBvZiB0aGUgcHVibGlzaGVkIHN1cnZpdmFsIGVzdGltYXRlcyByZXN1bHRzIGluIHN1YnN0YW50aWFsIGNoYW5nZSBpbiB0aGUgU1NCIChgciByb3VuZCgoKGFzdW1fbm1HNUZiX21vMV9kc2xvd1thc3VtX25tRzVGYl9tbzFfZHNsb3ckWWVhciA9PSBEYXRhWWVhciwgIlNTQiJdIC0gYXN1bV9ubUc1RmJfbW8xW2FzdW1fbm1HNUZiX21vMSRZZWFyID09IERhdGFZZWFyLCAiU1NCIl0pL2FzdW1fbm1HNUZiX21vMVthc3VtX25tRzVGYl9tbzEkWWVhciA9PSBEYXRhWWVhciwgIlNTQiJdKSoxMDAsIDApYCUpLCBhbmQgcmVjcnVpdG1lbnQgKGByIHJvdW5kKCgoYXN1bV9ubUc1RmJfbW8xX2RzbG93W2FzdW1fbm1HNUZiX21vMV9kc2xvdyRZZWFyID09IERhdGFZZWFyLCAiUl9hZ2UxIl0gLSBhc3VtX25tRzVGYl9tbzFbYXN1bV9ubUc1RmJfbW8xJFllYXIgPT0gRGF0YVllYXIsICJSX2FnZTEiXSkvYXN1bV9ubUc1RmJfbW8xW2FzdW1fbm1HNUZiX21vMSRZZWFyID09IERhdGFZZWFyLCAiUl9hZ2UxIl0pKjEwMCwgMClgJSkuDQoNCldoZW4gd2UgY29tcGFyZSB0aGUgZWZmZWN0cyBvZiBzZWxlY3RpbmcgZGlzY2FyZCBzdXJ2aXZhbCByYXRlcyBmcm9tIGFjcm9zcyB0aGUgcmFuZ2VzIG9mIHRob3NlIHJlcG9ydGVkIGluIHRoZSBsaXRlcmF0dXJlLCB3ZSBjYW4gc2VlIHRoYXQgdGhlIHZhcmlhdGlvbiBpbiBvdXIgbW9kZWwgZXN0aW1hdGVzIG9mIFNTQiBhcmUgbm90IGFzIGdyZWF0LCByZWxhdGl2ZSB0byBub3QgYWNjb3VudGluZyBmb3IgYW55IHN1cnZpdmFsLiAgVGhpcyBjYW4gYmUgc2VlbiBpbiB0aGUgcGVyY2VudGFnZSBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIGxvdyBhbmQgdGhlIGhpZ2ggZXN0aW1hdGVzIG9mIGRpc2NhcmQsIHJlbGF0aXZlIHRvIHRoZSBlc3RpbWF0ZSBtYWRlIGZvciB0aGUgbW9kZWwgd2l0aCBubyBzdXJ2aXZhbCBmb3IgU1NCIChgciByb3VuZCgoKGFzdW1fbm1HNUZiX21vMV9kc2xvd1thc3VtX25tRzVGYl9tbzFfZHNsb3ckWWVhciA9PSBEYXRhWWVhciwgIlNTQiJdIC0gYXN1bV9ubUc1RmJfbW8xX2RzaGlnW2FzdW1fbm1HNUZiX21vMV9kc2hpZyRZZWFyID09IERhdGFZZWFyLCAiU1NCIl0pL2FzdW1fbm1HNUZiX21vMVthc3VtX25tRzVGYl9tbzEkWWVhciA9PSBEYXRhWWVhciwgIlNTQiJdKSoxMDAsIDApYCUgYmV0d2VlbiBsb3cgYW5kIGhpZ2ggc3Vydml2YWwsIHZzIGByIHJvdW5kKCgoYXN1bV9ubUc1RmJfbW8xX2RzbG93W2FzdW1fbm1HNUZiX21vMV9kc2xvdyRZZWFyID09IERhdGFZZWFyLCAiU1NCIl0gLSBhc3VtX25tRzVGYl9tbzFbYXN1bV9ubUc1RmJfbW8xJFllYXIgPT0gRGF0YVllYXIsICJTU0IiXSkvYXN1bV9ubUc1RmJfbW8xW2FzdW1fbm1HNUZiX21vMSRZZWFyID09IERhdGFZZWFyLCAiU1NCIl0pKjEwMCwgMClgJSBiZXR3ZW4gbG93IHN1cnZpdmFsIHRvIG5vIHN1cnZpdmFsKS4gIA0KDQpIb3dldmVyLCB0aGlzIGRpZmZlcmVuY2UgaXMgbXVjaCByZWR1Y2VkIHdoZW4gY29tcGFyaW5nIGZpc2hpbmcgcHJlc3N1cmUgKGByIHJvdW5kKCgoYXN1bV9ubUc1RmJfbW8xX2RzbG93W2FzdW1fbm1HNUZiX21vMV9kc2xvdyRZZWFyID09IERhdGFZZWFyLCAiRmJhciJdIC0gYXN1bV9ubUc1RmJfbW8xX2RzaGlnW2FzdW1fbm1HNUZiX21vMV9kc2hpZyRZZWFyID09IERhdGFZZWFyLCAiRmJhciJdKS9hc3VtX25tRzVGYl9tbzFbYXN1bV9ubUc1RmJfbW8xJFllYXIgPT0gRGF0YVllYXIsICJGYmFyIl0pKjEwMCwgMClgJSBiZXR3ZWVuIGxvdyBhbmQgaGlnaCBzdXJ2aXZhbCwgdnMgYHIgcm91bmQoKChhc3VtX25tRzVGYl9tbzFfZHNsb3dbYXN1bV9ubUc1RmJfbW8xX2RzbG93JFllYXIgPT0gRGF0YVllYXIsICJGYmFyIl0gLSBhc3VtX25tRzVGYl9tbzFbYXN1bV9ubUc1RmJfbW8xJFllYXIgPT0gRGF0YVllYXIsICJGYmFyIl0pL2FzdW1fbm1HNUZiX21vMVthc3VtX25tRzVGYl9tbzEkWWVhciA9PSBEYXRhWWVhciwgIkZiYXIiXSkqMTAwLCAwKWAlIGJldHdlZW4gbG93IHN1cnZpdmFsIHRvIG5vIHN1cnZpdmFsKS4NCg0KIyMgT3ZlcmFsbCBDb25jbHVzaW9ucw0KQmFzZWQgb24gdGhlIGZhY3QgdGhhdCB0aGVyZSBhcmUgbGlrZWx5IGJpYXNlcyBhbmQgc29tZSBlcnJvcnMgaW4gdGhlIGNvbGxlY3Rpb24gb2YgZGF0YSBmb3IgYWdlIDEgZmlzaCwgYW5kIHRoZSBmYWN0IHRoYXQgY2hhbmdpbmcgdGhlIG1hdHVyaXR5IGF0IGFnZTEgaGFzIG5vIGVmZmVjdCBvbiB0aGUgbW9kZWwgZml0LCBidXQgZG93bi1zY2FsZXMgdGhlIFNTQiBlc3RpbWF0ZXMgYW5kIGxpa2VseSByZWR1Y2VzIGludGVyYW5udWFsIHZhcmlhdGlvbiBpbiB0aGUgZXN0aW1hdGVzLCB0aGVuIHdlIHJlY29tbWVuZCByZXRhaW5pbmcgdGhpcyBleHBlcnQgb3BpbmlvbiBiYXNlZCAib3Zlci13cml0ZSIuDQoNCkFzIHdhcyBzdGF0ZWQgYXQgdGhlIGJlZ2lubmluZyBvZiB0aGUgYmVuY2htYXJrIHByb2Nlc3MsIHRoZSBpbmZvcm1hdGlvbiB0aGF0IGV4aXN0cyBmb3IgcmF0ZXMgb2Ygc3Vydml2YWwgaW4gZGlzY2FyZGVkIHBsYWljZSBpcyAgd2VhaywgIHNwYXJzZSBhbmQgaGFzIHByb3ZlbiB0byBiZSBtYXNzaXZlbHkgZGVwZW5kZW50IG9uIGZhY3RvcnMgdGhhdCBjYW5ub3QgYmUgYWNjb3VudGVkIGZvciBpbiBhbiBhc3Nlc3NtZW50IHByb2Nlc3MgKGkuZS4gdGltZSBleHBvc2VkIHRvIGFpciwgYmVpbmcgdGhlIGxhcmdlc3QgZHJpdmVyIG9mIHN1cnZpdmFsKS4NCg0KSW4gb3JkZXIgdG8gYWRkcmVzcyBhIHNwZWNpZmljIHJlcXVlc3QgZnJvbSB0aGUgRXVyb3BlYW4gQ29tbWlzc2lvbiB0byBpbnZlc3RpZ2F0ZSBpbmNvcnBvcmF0aW5nIGRpc2NhcmQgc3Vydml2YWwgaW50byB0aGUgYXNzZXNzbWVudCwgd2UgaGF2ZSBib3Jyb3dlZCBpbmZvcm1hdGlvbiBhY3Jvc3MgdmFyaW91cyBmbGVldCBzdHJhdGEgYW5kIGFwcGxpZWQgdGhlc2UgYWQtaG9jIGFjcm9zcyBvdXIgY2F0Y2ggZGF0YXNldC4gIFRoZSByZXN1bHRhbnQgbW9kZWwgZml0cyBzaG93IHRoYXQgdGhlcmUgaXMgbm8gc3Vic3RhbnRpYWwgZGlmZmVyZW5jZSBpbiB0aGUgcXVhbGl0eSBvZiB0aGUgbW9kZWwgZml0cyAoYmFzZWQgb24gQUlDKSBidXQgdGhhdCBvdXIgcGVyY2VwdGlvbiBvZiB0aGUgc3RvY2sgaXMgc29tZXdoYXQgc2NhbGVkLCBhbmQgc2NhbGVkIGRpZmZlcmVudGx5IGFjY29yZGluZyB0byB0aGUgaW5kaWNhdG9yIHVzZSAoZS5nLiBzZWUgU1NCIHZzIEYgZGlzY3Vzc2lvbiBhYm92ZSkuIA0KDQpTdWJzZXF1ZW50IHRvIHRoaXMgZXhlcmNpc2UsIHdlIHJlYWxpc2UgdGhhdCBvdXIgc3RhdHVzIHF1byBhc3N1bXB0aW9uIGlzIDAlIHN1cnZpdmFsLCB3aGljaCBkb2VzIG5vdCBzZWVtIHRvIHJlZmxlY3QgcmVhbGl0eSwgYW5kIHRoYXQgd2hpbGUgc3R1ZGllcyBvbiB0aGlzIHRvcGljIGFyZSBzcGFyc2UsIGluZm9ybWF0aW9uIGRvZXMgZXhpc3QgdGhhdCB3ZSBzaG91bGQgbm90IGlnbm9yZS4gIE91ciBhdHRlbXB0cyB0byB1dGlsaXNlIHRoaXMga25vd2xlZGdlIGludm9sdmUgcnVkaW1lbnRhcnkgcmF0aW8tYmFzZWQgYm9ycm93aW5nIG9mIGluZm9ybWF0aW9uIHRvIGNvdmVyIHRoZSBjYXRjaCBzZWdtZW50cyBhcyBiZXN0IGFzIHBvc3NpYmxlLCBidXQgd2hldGhlciB0aGlzIGFwcHJvYWNoIGlzIHJvYnVzdCBlbm91Z2ggdG8gdXRpbGlzZSBpbiB0aGUgcHJvZHVjdGlvbiBvZiBhZHZpY2UgcmVtYWlucyB1cCBmb3IgZGViYXRlIHdpdGggcGVlcnMgYW5kIHJldmlld2Vycy4NCg0KVGhlcmVmb3JlLCB0aGVyZSByZW1haW5zIGEgZGVjaXNpb24gdG8gYmUgbWFkZSwgdG8gc2VsZWN0IGJldHdlZW4gdGhlIGFzc2Vzc21lbnQgd2l0aG91dCBhY2NvdW50aW5nIGZvciBkaXNjYXJkIHN1cnZpdmFsIChidXQgd2l0aCBhZ2UgMSBtYXR1cml0eSBzZXQgdG8gemVybyksIG9yIHRoZSBtZWRpdW0gZGlzY2FyZCBzdXJ2aXZhbCBzY2VuYXJpbz8NCg==