Choice of stock recruitment model
Many investigations were made to try and choose an appropriate stock-recruitment model. However, the working group agreed that there was no suitable standard model to fit these data. As can be seen below, the stock starts in a “low productivity” state with relatively low SSB and recruitment, but then rapidly rises in recent history, in an almost linear trend with no sign of reaching an asymptote. Because of this dramatic change and the fact that the stock is still not reaching some form of equilibrium all standard models assume an infinite relationship with no cap on recruitment.
To view the detail of the data at the beginning of the time series, click and drag a rectangle over the bottom left portion of the plot area.
ggplotly(ggplot(asum, mapping = aes(x = SSB, y = R_age1)) + geom_path(colour = ebpal[1]) +
geom_text(mapping = aes(label = Year), colour = ebpal[2], alpha = 0.5) + xlab("SSB (tonnes)") +
ylab("Recruitment (numbers)") + theme_clean())
To better view the trends, across the large shift in scale, we can also visualize this in the log-scale.
ggplotly(ggplot(asum, mapping = aes(x = SSB, y = log(R_age1))) + geom_path(colour = ebpal[1]) +
geom_text(mapping = aes(label = Year), colour = ebpal[2], alpha = 0.5) + xlab("SSB (tonnes)") +
ylab("Recruitment (log of numbers)") + theme_clean())
When we force a segmented regression (hockey-stick) through the data, the result is indicative of the non-equilibrium status of the stock, with no identified break-point.
set.seed(123)
eqfit <- eqsr_fit(stk = stk, nsamp = noSims, models = c("Segreg"))
# models = c('Smooth_hockey','Bevholt', 'Segreg'))
# eqsr_plot(eqfit)
eqsr_plot(eqfit, n = 20000, ggPlot = TRUE, Scale = 1000) #nicer ggplot colors
To further interrogate the potential relationships between ssb and recruitment, we can visualise it another way, using a direct ratio of recruits per SSB.
stockName <- "ple.27.21-32"
df <- data.frame(summary(samfit))
df$year <- rownames(df)
rownames(df) <- NULL
rec <- df[2:nrow(df), "R.age.1."] # in raw numbers.
ssb <- df[1:(nrow(df) - 1), "SSB"] # in tonnes.
df$rec.ssb <- c(NA, (rec/ssb))
ggplot(data = df) + geom_point(mapping = aes(x = year, y = rec.ssb), shape = 0) +
geom_line(mapping = aes(x = year, y = rec.ssb, group = 1), linetype = "dashed") +
xlab("Year of recruitment") + ylab("Recruitment (000's) /\nSSB of the previous year (tonnes)") +
theme_clean() + theme(axis.text.x.bottom = element_text(angle = 90, vjust = 0.5))
Calculate reference points
Before we begin calculating the various reference points, we must first decide on some data truncation and settings for the simulation.
Because of the rapid changes in stock dynamics in recent years, the decision was made to run simulations for reference points based on the period before stock-weights-at-age began to decline, recruitment increased and SSB increased. It was thought that this most recent period of high recruitment of poor-condition reflects a rare episode of overshooting carrying capacity, so experts expected that this period is unlikely to continue in the long-term.
## Reference points
refPts <- matrix(NA, nrow = 1, ncol = 9, dimnames = list("value", c("Btrigger", "Bpa",
"Blim", "5thPerc_SSBmsy", "Fpa", "Flim", "Fp05", "Fmsy_unconstr", "Fmsy")))
ssb_med <- median(ssb)
rec_med <- median(rec)
## Years by which to truncate dataset.
rmSRRYrs <- c(2019:maxYear) # specify here which other years (e.g. early period) should be left out
# PJW removed here redundant maxYear def and added maxYear to above
## Decisions and settings for use in forward simulations How many years to
## average over (resample from) for biological data
numAvgYrsB <- 5 #PJW: I changed this to 5 from 10 for testing... I think we said either was ok
### How many years to sample from for stock variability
numAvgYrsS <- 5 #PJW: I changed this to 5 from 10 for testing... I think we said either was ok
srYears <- setdiff(c(minYear:(maxYear)), rmSRRYrs)
Nruns <- 200
FsToScan <- seq(0, 1, by = 0.005) #seq(0, 0.9, len = 200) # changed max to 1 - earlier versions you showed did not have leveling off in Flim runs so F needs to be increased
Calculate/estimate \(B_{lim}\) and \(B_{pa}\)
Blim is the key PA reference point. The other precautionary approach points (Bpa, Flim, and Fpa) are all estimated from Blim. In a few cases, the available information does not allow direct estimation of Blim; Bpa is then estimated directly, and Blim may be derived from Bpa.
While Stock Types 1 and 5 from the guidelines call for using Bloss as Blim, the experts in the working group recognised that Bloss (2010) is less than many other SSB values that were also low and during a period of high fishing mortality (2002-2009). Therefore, setting Blim to Bloss may not be sufficiently precautionary.
Therefore, we also decided to try to apply the rules used for Gulf of Riga herring, namely that we take as Bpa the mean SSB of those years where:
- SSB <= median SSB AND
- recruitment >= median recruitment
The logic here, is that we are finding those years where low SSB still results in relatively high recruitment and using the mean ssb of those years to identify Bpa and calculate Blim from there.
refPts[, "Bpa"] <- mean(df[df$R.age.1. >= median(df$R.age.1.) & df$SSB <= median(df$SSB) &
df$year != 2024, "SSB"])
refPts[, "Blim"] <- refPts[, "Bpa"]/1.4
kable(refPts)
value |
NA |
12180.5 |
8700.357 |
NA |
NA |
NA |
NA |
NA |
NA |
This resulted in a Bpa based on two of the lowest observed SSB in the time series, which corresponded to essentially Bloss by other stock category definitions and a Blim value lower than observed in the time series. Furthermore, this method led to a value appeared to be less than 10% of estimates of B0 (calculated subsequently). Therefore this method was also rejected.
In a second approach, Blim was estimated by using the “empirical approach” and using B empirical as Blim. In a review of ICES reference points Silvar-Viladomiu et al. (2022) found that after Bloss, the most used method to define Blim was an empirical method based on identifying the lowest biomass that resulted in good recruitment. The “StockRecruit” R package available in GitHub provides a function that formalizes this method, and identifies the lowest biomasses that results in above median recruitment.
Then Blim is defined as the average of the identified set of lowest biomasses that can be formed by just one point or several. WKNEWREF proposed then a fourth method to define Blim , the ‘empirical approach’, in which Blim is defined as “lowest biomass (SSB) that resulted in a good recruitment (i.e., a recruitment above the median).”
## FLSR object
flsr <- as.FLSR(stk)
S <- an(ssb(flsr))
R <- an(rec(flsr))
# Minimum SSB level that resulted in a recruitment higher that the median.
Blim_emp <- calcBlim(S, R, quant = 0.5, type = 1)
Using the definition of WKNEWREF of 2024 and the “StockRecruitSET” package, the Blim empirical is about 8697.8973408 tons. The empirical Blim is very close the the previously estimated Blim value of 8700.3571429 tons and would face similar issues when used as a reference point. The Blim empirical approach was therefore also rejected.
As no standard solution was found, it was decided to modify the definition of Bloss given for Stock Types 1 and 5 to be based on the mean of several similar SSB values that spanned the ranges of having yielded both decent recruitment in two cases (2010 & 2011) and rather low recruitment in 8 cases (2002:2009). As noted above, setting Bloss to be the minimum SSB observed in 2010 was not considered a candidate for Blim because it’s value was less then the 8 values considered to have yielded rather low recruitment earlier in the time series. Any choice of SSB values greater than the 2010 value was therefore arbitrary, so the expert group decided to include as many as possible to reflect the group of similar SSB and recruitment value early in the time series. The 2002 - 2011 values were deemed ‘decent’ because they appeared to sustain rather stable SSB and recruitment values during the mid-range of the time series, before the productivity shift began in 2021. Bloss was therefore considered to be the mean SSB from the first ten years of the time series, where recruitment and SSB both remained rather low, albeit variable. Furthermore, this method led to a value roughly 15% of estimates of B0 (calculated subsequently), and Blim was set to this newly defined Bloss value.
refPts[, "Blim"] <- mean(df[df$year %in% c(2002:2011), "SSB"])
refPts[, "Bpa"] <- refPts[, "Blim"] * exp(1.645 * sigmaSSB)
kable(refPts)
value |
NA |
13460.43 |
11118.6 |
NA |
NA |
NA |
NA |
NA |
NA |
Having agreed and established Blim and Bpa, we now move on to other reference points.
Calculate \(F_{lim}\) and \(F_{pa}\)
## Refit stock recruitment relationship based on truncated time series
set.seed(123)
eqfit <- eqsr_fit(stk = stk, nsamp = noSims, models = c("Segreg"), remove.years = rmSRRYrs)
## Plot
eqsr_plot(eqfit, n = 20000, ggPlot = TRUE, Scale = 1000)
In forward projections, we can use a hockey-stock function to reflect the stock-recruitment relationship, but force it to use our pre-defined Blim as the breakpoint. This requires fitting the “stick” portion of the hockey-stick function above the breakpoint to recruitment observations.
## determine segreg model with Blim breakpoint and (roughly) geomean rec above
## this
SegregBlim <- function(ab, ssb) log(ifelse(ssb >= refPts[, "Blim"], ab$a * refPts[,
"Blim"], ab$a * ssb))
# ## determine segreg model with Bloss breakpoint and (roughly) geomean rec
# above this SegregBloss <- function(ab, ssb) log(ifelse(ssb >= min(ssb(stk)),
# ab$a * min(ssb(stk)), ab$a * ssb)) ## Remove the last year from FLstock
# object to prevent NA issues further down (as 2024 is based only on one ) stk1
# <- trim(stk, year =
# c((as.numeric(stk@range['minyear'])):((as.numeric(stk@range['maxyear']))-1)))
## Refit stock recruitment relationship based on truncated time series
set.seed(123)
eqfit <- eqsr_fit(stk = stk, nsamp = noSims, models = c("SegregBlim"), remove.years = rmSRRYrs)
## removing (ssb) years:
## 2019, 2020, 2021, 2022
## from the recruitment fitting procedure.
## Plot
eqsr_plot(eqfit, n = 20000, ggPlot = TRUE, Scale = 1000)
Based on this final stock-recruitment relationship, we can begin to estimate MSY reference points. To calculate Flim, we run a series of simulations with fixed biological parameters and no variability in the estimates of F and SSB.
set.seed(123)
SIM_SegregBlim <- eqsim_run(eqfit, bio.years = c((maxYear - numAvgYrsB), maxYear),
bio.const = TRUE, sel.years = c((maxYear - numAvgYrsS), maxYear), sel.const = TRUE,
Fcv = 0, Fphi = 0, SSBcv = 0, rhologRec = rhoRec, Btrigger = 0, Blim = refPts[,
"Blim"], Bpa = refPts[, "Bpa"], Nrun = Nruns, Fscan = FsToScan, verbose = T)
# save MSY and lim values
tmp1 <- t(SIM_SegregBlim$Refs)
eqsim_plot(SIM_SegregBlim, catch = TRUE)
refPts[, "Flim"] <- tmp1["F50", "catF"]
tmpFpa <- refPts[, "Flim"] * exp(-sigmaF * 1.645)
# PJW: This is fine but keep in mind later when reporting that this Fpa
# definition is outdated and now based on Fp05
if (tmpFpa < 0.2) refPts[, "Fpa"] <- round(tmpFpa, 3) else refPts[, "Fpa"] <- round(tmpFpa,
2)
kable(data.frame(refPts[, "Flim"], refPts[, "Fpa"]), col.names = c("Flim", "Fpa"))
The calculated values for Flim and Fpa are quite low and did not reasonably reflect the stock. The low values show a mismatch between the retained recruitment series (before 2019) and the resampled biological variables (last 5 years). Thus, the truncation of the sampled years for the B and S calculation was increased to include the last 10 years (instead of 5 years) to tackle the mismatch between the natural mortality values and the recruitment.
The Recruitment-autocorrelation (RhoLogRec) is also high (>0.9) when estimated from SAM directly and is influencing the estimation of the reference points. The high value seems to be driven by the exceptionally high R in the latest year classes which, for that reason, were already excluded from the Blim estimation (see above). Generally, Rho is much smaller in fish and not easy to estimate within assessment models without bias because it is a random effect, so that Johnson et al. (2016) recommends to do the estimation outside the model and then fix it.
The Recruitment-autocorrelation (RhoLogRec) was set to a conservative level at 0.6, which is similar to other Rho values for plaice derived from FISHLIFE (i.e., 0.58 for plaice, Thorson et al., 2023).
# Testing whether mismatch between natural mortality values in the last 5 years
# vs recruitment values previously could also be a culprit
numAvgYrsB <- numAvgYrsS <- 10
refPts3 <- matrix(NA, nrow = 1, ncol = 9, dimnames = list("value", c("Btrigger",
"Bpa", "Blim", "5thPerc_SSBmsy", "Fpa", "Flim", "Fp05", "Fmsy_unconstr", "Fmsy")))
refPts3[, "Blim"] <- mean(df[df$year %in% c(2002:2011), "SSB"]) # refPts3[,'Blim'] <- refPts[,'Blim']
refPts3[, "Bpa"] <- refPts3[, "Blim"] * exp(1.645 * sigmaSSB) # refPts3[,'Bpa'] <- refPts[,'Bpa']
set.seed(123)
SIM_SegregBlim_lowerRhohighernumAvgYrs <- eqsim_run(eqfit, bio.years = c((maxYear -
numAvgYrsB), maxYear), bio.const = TRUE, sel.years = c((maxYear - numAvgYrsS),
maxYear), sel.const = TRUE, Fcv = 0, Fphi = 0, SSBcv = 0, rhologRec = c(0.6),
Btrigger = 0, Blim = refPts3[, "Blim"], Bpa = refPts3[, "Bpa"], Nrun = Nruns,
Fscan = FsToScan, verbose = T)
tmp1 <- t(SIM_SegregBlim_lowerRhohighernumAvgYrs$Refs)
refPts3[, "Flim"] <- tmp1["F50", "catF"]
# tmpFpa <- refPts3[,'Flim'] * exp(-sigmaF * 1.645) PJW: This is fine but keep
# in mind later when reporting that this Fpa definition is outdated and now
# based on Fp05
tmpFpa <- refPts3[, "Fpa"] <- refPts3[, "Fp05"] <- tmp1["F05", "catF"]
if (tmpFpa < 0.2) refPts3[, "Fpa"] <- round(tmpFpa, 3) else refPts3[, "Fpa"] <- round(tmpFpa,
2)
The resulting Flim and Fpa reference points were closer to similar values in other plaice stocks and more fitting to the development of the stocks since 2019 and thus were kept for the following calculations.
kable(data.frame(refPts3[, "Flim"], refPts3[, "Fpa"]), col.names = c("Flim", "Fpa"))
eqsim_plot(SIM_SegregBlim_lowerRhohighernumAvgYrs, catch = TRUE)
However, while Flim may still be derived from Blim (and used to assess the F that drives the stock to Blim, based on the equilibrium curve of stock), it is no longer used by ICES as basis of precautionary approach (PA) and MSY reference points to assess the state of stocks and exploitation, and to provide advice on fishing opportunities WKNEWREF4, ICES 2024d). It is therefore only used for information, but not recognized as reference point for the assessment and advice and not included in the final reference point list.
calculate \(F_{MSY}\) (unconstrained)
Unlike the simulations used to estimate Flim, the unconstrained FMSY should initially be calculated based on a constant F evaluation with the inclusion of stochasticity in population and exploitation as well as assessment/advice error. Appropriate SRRs should be specified.
Also here, value was recalculated using the 10 year avg instead of 5 years
set.seed(123)
SIM_Segreg_noTrig_lowerRhohighernumAvgYrs <- eqsim_run(eqfit, bio.years = c(maxYear -
numAvgYrsB, maxYear), bio.const = FALSE, sel.years = c(maxYear - numAvgYrsS,
maxYear), sel.const = FALSE, Fcv = cvF, Fphi = phiF, SSBcv = cvSSB, rhologRec = c(0.6),
keep.sims = TRUE, Btrigger = 0, Blim = refPts3[, "Blim"], Bpa = refPts3[, "Bpa"],
Nrun = Nruns, Fscan = FsToScan, verbose = T)
tmp2 <- t(SIM_Segreg_noTrig_lowerRhohighernumAvgYrs$Refs)
Fmsy_tmp <- tmp2["medianMSY", "catF"] #note: was previously landings F for Fmsy, from the wrong output (refs2 output tables)
tmpFpa <- refPts3[, "Fpa"] <- refPts3[, "Fp05"] <- tmp2["F05", "catF"]
refPts3[, "Fmsy_unconstr"] <- Fmsy_tmp
if (Fmsy_tmp > refPts3[, "Fpa"]) {
refPts3[, "Fmsy"] <- refPts3[, "Fpa"] #PJW: make sure this is Fp05
} else {
refPts3[, "Fmsy"] <- Fmsy_tmp
}
The resulting unconstrained FMSY is about0.46. The unconstrained value is used as basis for the next steps in the reference point calculations.
eqsim_plot(SIM_Segreg_noTrig_lowerRhohighernumAvgYrs, catch = TRUE)
\(MSY_{B trigger}\)
MSY B trigger is a lower bound of the SSB distribution when the stock is fished at F MSY (ICES, 2021).
As stated in the ICES technical guidelines, recent fishing mortality estimates need to be considered to set MSY B trigger as for most stocks that lack data on fishing at F MSY, MSY B trigger is set at Bpa. Here, the stock has been fished below F MSY (0.137358) for the last 5 years. Next step is to look if the 5th percentile of B MSY > Bpa.
data.05 <- SIM_Segreg_noTrig_lowerRhohighernumAvgYrs$rbp
x.05 <- data.05[data.05$variable == "Spawning stock biomass", ]$Ftarget
b.05 <- data.05[data.05$variable == "Spawning stock biomass", ]$p05
# plot(b.05~x.05, ylab='SSB', xlab='F')
b.lm <- loess(b.05 ~ x.05)
refPts3[, "5thPerc_SSBmsy"] <- predict(b.lm, refPts3[, "Fmsy"])
The group agreed to use a simple version to set B trigger as Bpa
### simplified solution after web meeting with Colin (smoothing function is
### creating a weird B trigger)
refPts3[, "Btrigger"] <- refPts[, "Bpa"]
# This plot is only needed if you are going to use 5th percentile definition,
# and according to the above this stock doesn't qualify anyway, even if we
# thought it was a goood idea to use it. I added eval = FALSE to the chunk
# code. Side note - I think the loess smoother needs more nodes or something
# because it doesn't look like its fitting anyway.
ggplotly(ggplot(data = NULL, mapping = aes(x = x.05, y = b.05)) + geom_point(shape = 21) +
geom_smooth(method = "loess", se = F, colour = ebpal[1]) + ylab("SSB (tonnes) with F that gives\n5% chance of going below Bpa") +
xlab("Fishing pressure (F)") + theme_clean())
In this case the 5th percentile of B MSY is not greater than Bpa. Therefore following the ICES technical guidelines the MSY B trigger will be equal to Bpa , MSY B trigger = 1.3460426^{4} tonnes.MSY Btrigger should be selected to safeguard against an undesirable or unexpected low SSB when fishing at FMSY.
require(kableExtra) #PJW: Added this
dt <- refPts3[, c(1, 2, 4)]
dt %>%
kbl(booktabs = TRUE, caption = "Btrigger and Bpa reference points for ple.27.21-32") %>%
kable_material_dark()
(#tab:intermediate btrigger table)Btrigger and Bpa reference points for ple.27.21-32
|
x
|
Btrigger
|
13460.43
|
Bpa
|
13460.43
|
5thPerc_SSBmsy
|
11251.37
|
final \(F_{MSY}\)
The ICES MSY Advice Rule should be evaluated to check that the FMSY and MSY Btrigger combination adheres to precautionary considerations:
* in the long term, P(SSB<Blim)<5%
The evaluation must include:
* realistic assessment (advice) error
* stochasticity in population biology and fishery exploitation.
* Appropriate SRRs should be specified (here using segregation model with fixed breakpoint)
set.seed(123)
SIM_Segreg_Trig_lowerRhohighernumAvgYrs <- eqsim_run(eqfit, bio.years = c(maxYear -
numAvgYrsB, maxYear), bio.const = FALSE, sel.years = c(maxYear - numAvgYrsS,
maxYear), sel.const = FALSE, Fcv = cvF, Fphi = phiF, SSBcv = cvSSB, rhologRec = c(0.6),
keep.sims = TRUE, Btrigger = refPts3[, "Btrigger"], Blim = refPts3[, "Blim"],
Bpa = refPts3[, "Bpa"], Nrun = Nruns, Fscan = FsToScan, verbose = TRUE)
tmp3 <- t(SIM_Segreg_Trig_lowerRhohighernumAvgYrs$Refs)
refPts3[, "Fp05"] <- refPts3[, "Fpa"] <- tmp3["F05", "catF"] #note: catch F for Fp05
refPts3[, "Fmsy_unconstr"] <- Fmsy_tmp
if (Fmsy_tmp > refPts3[, "Fpa"]) {
refPts3[, "Fmsy"] <- refPts3[, "Fpa"]
} else {
refPts3[, "Fmsy"] <- Fmsy_tmp
}
# This shows that the mismatch between the recruitment series we retained
# (before 2019) and the biological variables we resampled (last 5 years), also
# caused some confusion. I think it is best to continue with this version above
# - look for a reasonable rho value (in the range 0.3 - 0.6 I think), and keep
# the last 10 years for sampling.
sim <- SIM_Segreg_Trig_lowerRhohighernumAvgYrs
# sim <- SIM_Segreg_noTrig_lowerRhohighernumAvgYrs # this one for unconstrained
# FMSY upper and lower
interval = 0.95
data.95 <- sim$rbp
x.95 <- data.95[data.95$variable == "Catch", ]$Ftarget
y.95 <- data.95[data.95$variable == "Catch", ]$Mean
yield.p95 <- interval * max(y.95, na.rm = TRUE)
# Fit loess smoother to curve
x.lm <- stats::loess(y.95 ~ x.95, span = 0.2)
lm.pred <- data.frame(x = seq(min(x.95), max(x.95), length = 1000), y = rep(NA, 1000))
lm.pred$y <- stats::predict(x.lm, newdata = lm.pred$x)
# Limit fitted curve to values greater than the 95% cutoff
lm.pred.95 <- lm.pred[lm.pred$y >= yield.p95, ]
fmsy.lower <- min(lm.pred.95$x)
fmsy.upper <- max(lm.pred.95$x)
fmsy.lower.mean <- fmsy.lower
fmsy.upper.mean <- fmsy.upper
catch.lower.mean <- lm.pred.95[lm.pred.95$x == fmsy.lower.mean, ]$y
catch.upper.mean <- lm.pred.95[lm.pred.95$x == fmsy.upper.mean, ]$y
# Repeat for 95% of yield at F(05):
f05 <- sim$Refs["catF", "F05"]
yield.f05 <- stats::predict(x.lm, newdata = f05)
yield.f05.95 <- interval * yield.f05
lm.pred.f05.95 <- lm.pred[lm.pred$y >= yield.f05.95, ]
f05.lower <- min(lm.pred.f05.95$x)
f05.upper <- max(lm.pred.f05.95$x)
# add upper and lower estimates to Ref2 table
SIM_Segreg_Trig_lowerRhohighernumAvgYrs$Refs2["catF", "Meanlower"] <- f05.lower
SIM_Segreg_Trig_lowerRhohighernumAvgYrs$Refs2["catF", "Meanupper"] <- f05.upper
To ensure consistency between the precautionary and the MSY frameworks, FMSY is not allowed to be above Fp05; therefore, if the initial FMSY value is above Fp05, FMSY is reduced to Fp05. Fp05 was calculated by running EqSim with assessment/advice error, with advice rule, and with a segmented regression with breaking point fixed at Bpa to ensure that the long-term risk of SSB < Blim of any F used does not exceed 5% when applying the advice rule. Fp05 was estimated to be 0.1491946 (F05 for catF). Therefore, as explained above, 0.1491946. The upper and lower ranges are given in the following table.
dt2 <- refPts3[, c(7, 9)]
dt2$Fmsy_lower <- SIM_Segreg_Trig_lowerRhohighernumAvgYrs$Refs2["catF", "Meanlower"]
dt2$Fmsy_upper <- SIM_Segreg_Trig_lowerRhohighernumAvgYrs$Refs2["catF", "Meanupper"]
dt2 <- t(dt2)
dt2 %>%
kbl(booktabs = TRUE, caption = "Fp05 and Fmsy reference points for ple.27.21-32",
digits = 4) %>%
kable_material_dark()
(#tab:final fmsy table update)Fp05 and Fmsy reference points for ple.27.21-32
Fp05
|
Fmsy
|
Fmsy_lower
|
Fmsy_upper
|
0.149194630872483
|
0.149194630872483
|
0.137137137137137
|
1
|
In case of limitation by FMSY = Fpa, the upper FMSY limit equals the (capped) FMSY and the lower limit is re-calculated using the capped FMSY value (in this case, FMSY = NA instead of using the unconstrained FMSY = 0.46)
final graphs
What final graphs do we really want to see?
eqsim_plot_range(SIM_Segreg_noTrig_lowerRhohighernumAvgYrs, type = "mean")

eqsim_plot_range(SIM_Segreg_noTrig_lowerRhohighernumAvgYrs, type = "median")

eqsim_plot_range(SIM_Segreg_Trig_lowerRhohighernumAvgYrs, type = "ssb")

eqsim_plot_range(SIM_Segreg_Trig_lowerRhohighernumAvgYrs, type = "mean")

additional scenarios:
non-truncated Recruitment series
Sensitivity run using the non-truncated recruit time series. All other settings are identical to the final settings of the reference point calculation above:
- Blim as average SSB of the first ten years of the time series
- last 10 years of biological data used for S and B estimation in the reference point models
- autocorrelation of recruitment fixed to RhoLogRec = 0.6
# set up new Ref table for untruncated series
refPts5 <- matrix(NA, nrow = 1, ncol = 9, dimnames = list("value", c("Btrigger",
"Bpa", "Blim", "5thPerc_SSBmsy", "Fpa", "Flim", "Fp05", "Fmsy_unconstr", "Fmsy")))
# keep Blim and Bpa
refPts5[, "Blim"] <- mean(df[df$year %in% c(2002:2011), "SSB"])
refPts5[, "Bpa"] <- refPts[, "Blim"] * exp(1.645 * sigmaSSB)
# no truncation
rmSRRYrs <- 0
SegregBlim <- function(ab, ssb) log(ifelse(ssb >= refPts[, "Blim"], ab$a * refPts[,
"Blim"], ab$a * ssb))
## Refit stock recruitment relationship based on truncated time series
set.seed(123)
eqfit <- eqsr_fit(stk = stk, nsamp = noSims, models = c("SegregBlim"), remove.years = rmSRRYrs)
## Plot
eqsr_plot(eqfit, n = 20000, ggPlot = TRUE, Scale = 1000)
set.seed(123)
SIM_SegregBlim_lowerRhohighernumAvgYrs <- eqsim_run(eqfit, bio.years = c((maxYear -
numAvgYrsB), maxYear), bio.const = TRUE, sel.years = c((maxYear - numAvgYrsS),
maxYear), sel.const = TRUE, Fcv = 0, Fphi = 0, SSBcv = 0, rhologRec = c(0.6),
Btrigger = 0, Blim = refPts5[, "Blim"], Bpa = refPts5[, "Bpa"], Nrun = Nruns,
Fscan = FsToScan, verbose = T)
tmp1 <- t(SIM_SegregBlim_lowerRhohighernumAvgYrs$Refs)
refPts5[, "Flim"] <- tmp1["F50", "catF"]
tmpFpa <- refPts5[, "Fpa"] <- refPts5[, "Fp05"] <- tmp1["F05", "catF"]
if (tmpFpa < 0.2) refPts5[, "Fpa"] <- round(tmpFpa, 3) else refPts5[, "Fpa"] <- round(tmpFpa,
2)
set.seed(123)
SIM_Segreg_noTrig_lowerRhohighernumAvgYrs <- eqsim_run(eqfit, bio.years = c(maxYear -
numAvgYrsB, maxYear), bio.const = FALSE, sel.years = c(maxYear - numAvgYrsS,
maxYear), sel.const = FALSE, Fcv = cvF, Fphi = phiF, SSBcv = cvSSB, rhologRec = c(0.6),
keep.sims = TRUE, Btrigger = 0, Blim = refPts5[, "Blim"], Bpa = refPts5[, "Bpa"],
Nrun = Nruns, Fscan = FsToScan, verbose = T)
tmp2 <- t(SIM_Segreg_noTrig_lowerRhohighernumAvgYrs$Refs)
Fmsy_tmp <- tmp2["medianMSY", "catF"] #note: was previously landings F for Fmsy, from the wrong output (refs2 output tables)
tmpFpa <- refPts5[, "Fpa"] <- refPts5[, "Fp05"] <- tmp2["F05", "catF"]
refPts5[, "Fmsy_unconstr"] <- Fmsy_tmp
if (Fmsy_tmp > refPts5[, "Fpa"]) {
refPts5[, "Fmsy"] <- refPts5[, "Fpa"] #PJW: make sure this is Fp05
} else {
refPts5[, "Fmsy"] <- Fmsy_tmp
}
data.05 <- SIM_Segreg_noTrig_lowerRhohighernumAvgYrs$rbp
x.05 <- data.05[data.05$variable == "Spawning stock biomass", ]$Ftarget
b.05 <- data.05[data.05$variable == "Spawning stock biomass", ]$p05
# plot(b.05~x.05, ylab='SSB', xlab='F')
b.lm <- loess(b.05 ~ x.05)
refPts5[, "5thPerc_SSBmsy"] <- predict(b.lm, refPts5[, "Fmsy"])
refPts5[, "Btrigger"] <- refPts[, "Bpa"]
set.seed(123)
SIM_Segreg_Trig_lowerRhohighernumAvgYrs <- eqsim_run(eqfit, bio.years = c(maxYear -
numAvgYrsB, maxYear), bio.const = FALSE, sel.years = c(maxYear - numAvgYrsS,
maxYear), sel.const = FALSE, Fcv = cvF, Fphi = phiF, SSBcv = cvSSB, rhologRec = c(0.6),
keep.sims = TRUE, Btrigger = refPts5[, "Btrigger"], Blim = refPts5[, "Blim"],
Bpa = refPts5[, "Bpa"], Nrun = Nruns, Fscan = FsToScan, verbose = TRUE)
tmp3 <- t(SIM_Segreg_Trig_lowerRhohighernumAvgYrs$Refs)
refPts5[, "Fp05"] <- refPts5[, "Fpa"] <- tmp3["F05", "catF"] #note: catch F for Fp05
refPts5[, "Fmsy_unconstr"] <- Fmsy_tmp
if (Fmsy_tmp > refPts5[, "Fpa"]) {
refPts5[, "Fmsy"] <- refPts5[, "Fpa"]
} else {
refPts5[, "Fmsy"] <- Fmsy_tmp
}
refPts6 <- refPts5[, c(1, 2, 3, 4, 5, 8, 9)]
t(refPts6) %>%
kbl(booktabs = TRUE, caption = "reference points for ple.27.21-32, using the non-truncated recruitment") %>%
kable_material_dark()
(#tab:final table of ref points, no truncation)reference points for ple.27.21-32, using the non-truncated recruitment
Btrigger
|
Bpa
|
Blim
|
5thPerc_SSBmsy
|
Fpa
|
Fmsy_unconstr
|
Fmsy
|
13460.43
|
13460.43
|
11118.6
|
11435.24
|
0.1893137
|
0.8275
|
0.1893137
|
lower RhoLogRec value
Sensitivity run assuming a lower autocorrelation in the recruitment, RhoLogRec = 0.3. All other settings are identical to the final settings of the reference point calculation above:
- Blim as average SSB of the first ten years of the time series
- last 10 years of biological data used for S and B estimation in the reference point models
- SSR time series truncated, only using the data before the exceptionally strong increase in 2019
refPts7 <- matrix(NA, nrow = 1, ncol = 9, dimnames = list("value", c("Btrigger",
"Bpa", "Blim", "5thPerc_SSBmsy", "Fpa", "Flim", "Fp05", "Fmsy_unconstr", "Fmsy")))
# keep Blim and Bpa
refPts7[, "Blim"] <- mean(df[df$year %in% c(2002:2011), "SSB"])
refPts7[, "Bpa"] <- refPts[, "Blim"] * exp(1.645 * sigmaSSB)
# add truncation
rmSRRYrs <- c(2019:maxYear) # specify here which other years (e.g. early period) should be left out
SegregBlim <- function(ab, ssb) log(ifelse(ssb >= refPts[, "Blim"], ab$a * refPts[,
"Blim"], ab$a * ssb))
## Refit stock recruitment relationship based on truncated time series
set.seed(123)
eqfit <- eqsr_fit(stk = stk, nsamp = noSims, models = c("SegregBlim"), remove.years = rmSRRYrs)
## Plot
eqsr_plot(eqfit, n = 20000, ggPlot = TRUE, Scale = 1000)
set.seed(123)
SIM_SegregBlim_lowerRhohighernumAvgYrs <- eqsim_run(eqfit, bio.years = c((maxYear -
numAvgYrsB), maxYear), bio.const = TRUE, sel.years = c((maxYear - numAvgYrsS),
maxYear), sel.const = TRUE, Fcv = 0, Fphi = 0, SSBcv = 0, rhologRec = c(0.3),
Btrigger = 0, Blim = refPts7[, "Blim"], Bpa = refPts7[, "Bpa"], Nrun = Nruns,
Fscan = FsToScan, verbose = T)
tmp1 <- t(SIM_SegregBlim_lowerRhohighernumAvgYrs$Refs)
refPts7[, "Flim"] <- tmp1["F50", "catF"]
tmpFpa <- refPts7[, "Fpa"] <- refPts7[, "Fp05"] <- tmp1["F05", "catF"]
if (tmpFpa < 0.2) refPts7[, "Fpa"] <- round(tmpFpa, 3) else refPts7[, "Fpa"] <- round(tmpFpa,
2)
set.seed(123)
SIM_Segreg_noTrig_lowerRhohighernumAvgYrs <- eqsim_run(eqfit, bio.years = c(maxYear -
numAvgYrsB, maxYear), bio.const = FALSE, sel.years = c(maxYear - numAvgYrsS,
maxYear), sel.const = FALSE, Fcv = cvF, Fphi = phiF, SSBcv = cvSSB, rhologRec = c(0.3),
keep.sims = TRUE, Btrigger = 0, Blim = refPts7[, "Blim"], Bpa = refPts7[, "Bpa"],
Nrun = Nruns, Fscan = FsToScan, verbose = T)
tmp2 <- t(SIM_Segreg_noTrig_lowerRhohighernumAvgYrs$Refs)
Fmsy_tmp <- tmp2["medianMSY", "catF"] #note: was previously landings F for Fmsy, from the wrong output (refs2 output tables)
tmpFpa <- refPts7[, "Fpa"] <- refPts7[, "Fp05"] <- tmp2["F05", "catF"]
refPts7[, "Fmsy_unconstr"] <- Fmsy_tmp
if (Fmsy_tmp > refPts7[, "Fpa"]) {
refPts7[, "Fmsy"] <- refPts7[, "Fpa"] #PJW: make sure this is Fp05
} else {
refPts7[, "Fmsy"] <- Fmsy_tmp
}
data.05 <- SIM_Segreg_noTrig_lowerRhohighernumAvgYrs$rbp
x.05 <- data.05[data.05$variable == "Spawning stock biomass", ]$Ftarget
b.05 <- data.05[data.05$variable == "Spawning stock biomass", ]$p05
# plot(b.05~x.05, ylab='SSB', xlab='F')
b.lm <- loess(b.05 ~ x.05)
refPts7[, "5thPerc_SSBmsy"] <- predict(b.lm, refPts7[, "Fmsy"])
refPts7[, "Btrigger"] <- refPts[, "Bpa"]
set.seed(123)
SIM_Segreg_Trig_lowerRhohighernumAvgYrs <- eqsim_run(eqfit, bio.years = c(maxYear -
numAvgYrsB, maxYear), bio.const = FALSE, sel.years = c(maxYear - numAvgYrsS,
maxYear), sel.const = FALSE, Fcv = cvF, Fphi = phiF, SSBcv = cvSSB, rhologRec = c(0.3),
keep.sims = TRUE, Btrigger = refPts7[, "Btrigger"], Blim = refPts7[, "Blim"],
Bpa = refPts7[, "Bpa"], Nrun = Nruns, Fscan = FsToScan, verbose = TRUE)
tmp3 <- t(SIM_Segreg_Trig_lowerRhohighernumAvgYrs$Refs)
refPts7[, "Fp05"] <- refPts7[, "Fpa"] <- tmp3["F05", "catF"] #note: catch F for Fp05
refPts7[, "Fmsy_unconstr"] <- Fmsy_tmp
if (Fmsy_tmp > refPts7[, "Fpa"]) {
refPts7[, "Fmsy"] <- refPts7[, "Fpa"]
} else {
refPts7[, "Fmsy"] <- Fmsy_tmp
}
refPts8 <- refPts7[, c(1, 2, 3, 4, 5, 8, 9)]
t(refPts8) %>%
kbl(booktabs = TRUE, caption = "reference points for ple.27.21-32, assuming RhoLogRec = 0.3") %>%
kable_material_dark()
(#tab:final table of ref points, lower Rho)reference points for ple.27.21-32, assuming RhoLogRec = 0.3
Btrigger
|
Bpa
|
Blim
|
5thPerc_SSBmsy
|
Fpa
|
Fmsy_unconstr
|
Fmsy
|
13460.43
|
13460.43
|
11118.6
|
11458.4
|
0.1944366
|
0.515
|
0.1944366
|
LS0tDQp0aXRsZTogIlBsZS4yNy4yMS0zMiBSZWZlcmVuY2UgUG9pbnQgRXN0aW1hdGlvbiINCmF1dGhvcjoNCiAgLSBuYW1lOiAiU3ZlbiBTdMO2dGVyYSINCiAgLSBuYW1lOiAiRWxsaW90IEouIEJyb3duIg0KICAtIG5hbWU6ICJQYW1lbGEgV29vZHMiDQpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiDQpvdXRwdXQ6IA0KICBib29rZG93bjo6aHRtbF9kb2N1bWVudDI6DQogICAgdG9jOiB0cnVlDQogICAgdG9jX2Zsb2F0OiB0cnVlDQogICAgY29kZV9mb2xkaW5nOiBoaWRlDQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KLS0tDQoNCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+DQoubWFpbi1jb250YWluZXIgew0KbWF4LXdpZHRoOiA5MCUgIWltcG9ydGFudDsNCm1hcmdpbjogYXV0bzsNCn0NCnAuY2FwdGlvbiB7DQpmb250LXNpemU6IDAuOGVtOw0KZm9udC1zdHlsZTogaXRhbGljOw0KfQ0KPC9zdHlsZT4NCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobz1UUlVFLA0KICAgICAgICAgICAgICAgICAgICAgIGV2YWwgPSBUUlVFLA0KICAgICAgICAgICAgICAgICAgICAgIHdhcm5pbmcgPSBGQUxTRSwNCiAgICAgICAgICAgICAgICAgICAgICBmaWcuYWxpZ24gPSAiY2VudGVyIiwNCiAgICAgICAgICAgICAgICAgICAgICB0aWR5ID0gJ2Zvcm1hdFInLA0KICAgICAgICAgICAgICAgICAgICAgIG91dC53aWR0aCA9ICI5MCUiKQ0KDQojPT09DQojIE1hbnVhbCBzZXR0aW5ncyBmb3IgZmlndXJlIGZvcm1hdHRpbmcNCiM9PT09DQojIGVicGFsIDwtIGMoIiMyRjNFRUEiLCAiIzFGRDA4MiIsICIjMDMwRjRGIiwgIiNGNkQwNEQiLCAiI0ZDNzYzNCIsICIjRjdCQkIxIiwgIiNFODNGNDgiLCAiIzAwODgzNSIsICIjNzkyMzhFIikNCmVicGFsIDwtIGMoIiM4MDAwODAiLCAiIzAwNjQwMCIsICIjRDU1RTAwIiwgIiMwMDcyQjIiLCAiI0YwRTQ0MiIsICIjMDA5RTczIiwgIiNFNjlGMDAiLCAiIzU2QjRFOSIsICIjQ0M3OUE3IiwgIiM1REE1REEiLCAiI0ZGODAwMCIsICIjODlDRkYwIiwgIiNBNTJBMkEiLCAiIzc3REQ3NyIsICIjRkZGQUNEIikNCg0KIz09PQ0KIyBQYWNrYWdlcw0KIz09PT0NCnJlcXVpcmUocmVzaGFwZTIpDQpyZXF1aXJlKGtuaXRyKQ0KcmVxdWlyZShzY2FsZXMpDQpyZXF1aXJlKGJvb2tkb3duKQ0KcmVxdWlyZShnZ3Bsb3QyKQ0KcmVxdWlyZShnZ3Bsb3RGTCkNCnJlcXVpcmUoZHBseXIpDQpyZXF1aXJlKGdndGhlbWVzKQ0KcmVxdWlyZShwbG90bHkpDQpyZXF1aXJlKGljZXNBZHZpY2UpDQpyZXF1aXJlKCJzdG9ja2Fzc2Vzc21lbnQiKSAjIGF2YWlsYWJsZSBmcm9tIGh0dHBzOi8vZ2l0aHViLmNvbS9maXNoZm9sbG93ZXIvU0FNDQpyZXF1aXJlKHBhcmFsbGVsKQ0KcmVxdWlyZShtc3kpICAgICAgICAgICAgICAgIyBkZXZ0b29sczo6aW5zdGFsbF9naXRodWIoImljZXMtdG9vbHMtcHJvZC9tc3kiKQ0KcmVxdWlyZShGTENvcmUpDQpyZXF1aXJlKEZMU0FNKSAgICAgICAgICAgICAjIGluc3RhbGwucGFja2FnZXMoIkZMU0FNIiwgcmVwb3M9Imh0dHA6Ly9mbHItcHJvamVjdC5vcmcvUiIpDQpyZXF1aXJlKEZMZnNlKSAgICAgICAgICAgICAjIHJlbW90ZXM6Omluc3RhbGxfZ2l0aHViKCJzaGZpc2NoZXIvRkxmc2UvRkxmc2UiKQ0KcmVxdWlyZShrYWJsZUV4dHJhKQ0KcmVxdWlyZShTdG9ja1JlY3J1aXRTRVQpICMgZGV2dG9vbHM6Omluc3RhbGxfZ2l0aHViKCJtZWJyb29rcy9zdG9ja3JlY3J1aXQvU3RvY2tSZWNydWl0U0VUIiwgYnVpbGRfb3B0cyA9IGMoIi0tbm8tcmVzYXZlLWRhdGEiLCAiLS1uby1tYW51YWwiKSkNCg0KDQojPT09PQ0KYGBgDQoNCjxjZW50ZXI+DQoNCiFbXShpbWFnZS9QTEUucG5nKQ0KPC9jZW50ZXI+DQoNCg0KDQojIERvd25sb2FkIFNlbGVjdCBNb2RlbA0KVGhlIGZpbmFsIFNBTSBydW4sIHRoZSBtb2RlbCBvdXRwdXQsIGRhdGEgYW5kIGNvbmZpZyBhcmUgZGlyZWN0bHkgdGFrZW4gZnJvbSBbc3RvY2thc3Nlc3NtZW50Lm9yZ10oaHR0cHM6Ly93d3cuc3RvY2thc3Nlc3NtZW50Lm9yZykuIA0KYGBge3IgZG93bmxvYWRtb2RlbH0NCnNhbWZpdCA8LSBmaXRmcm9td2ViKCJwbGUuMjcuMjEtMzJfV0tCUExBSUNFXzIwMjRfbm1HNUZiX21vMV9kc21lZDYiKQ0KDQojIyBleHRyYWN0IHJlbGV2YW50IGRhdGEgZnJvbSBtb2RlbA0KYXN1bSA8LSBhcy5kYXRhLmZyYW1lKHN1bW1hcnkoc2FtZml0KSkNCmFzdW0kWWVhciA8LSBhcy5pbnRlZ2VyKHJvdy5uYW1lcyhzdW1tYXJ5KHNhbWZpdCkpKQ0KY29sbmFtZXMoYXN1bSkgPC0gYygiUl9hZ2UxIiwgIlJsb3ciLCAiUmhpZ2giLCAiU1NCIiwgIlNTQmxvdyIsICJTU0JoaWdoIiwgIkZiYXIiLCAiRmxvdyIsICJGaGlnaCIsICJZZWFyIikNCmBgYA0KDQpUaGUgY2hvc2VuIGFzc2Vzc21lbnQgcnVuLCBhcyB3ZWxsIGFzIHRoZSBzZXR0aW5ncyBhbmQgZGV0YWlscyBvbiBzZW5zaXRpdml0eSBydW5zLCBldGMuIGFyZSBleHBsYWluZWQgaW4gdGhlIFdLQlBMQUlDRSByZXBvcnQgYW5kIHRoZSBhY2NvbXBhbnlpbmcgd29ya2luZyBkb2N1bWVudHM6DQpXRDEgCVN0b2NrIElkZW50aXR5IGFuZCBzdG9jayBtZXJnaW5nDQpXRDIgCVN0b2NrIGNvb3JkaW5hdGlvbiBhbmQgZGF0YSBvdmVydmlld3MNCldEMyAJT3ZlcnZpZXcgb2YgdGhlIGFzc2Vzc21lbnQgcnVucyBhbmQgc2Vuc2l0aXZpdHkNCldENCAJTmV3IG5hdHVyYWwgbW9ydGFsaXR5DQpXRDUgCUluY2x1c2lvbiBvZiBkaXNjYXJkIHN1cnZpdmFsDQoNCg0KIyBDcmVhdGUgRVEtU2ltIElucHV0IERhdGENCiMjIElucHV0cyBmcm9tIE1vZGVsDQpFUVNJTSByZXF1aXJlcyBkYXRhIGluIHRoZSAiRkxTdG9jayIgZm9ybWF0LiBUaGUgZG93bmxvYWRlZCBTQU0gb2JqZWN0IGlzIHRyYW5zZm9ybWVkLCBhZGRpbmcgYSBkZXNjcmlwdGlvbiBvZiB0aGUgc3RvY2ssIGNvbXB1dGVzIHRvdGFsIHdlaWdodHMgYW5kIGFkZCByZXNwZWN0aXZlIHVuaXRzLiAgDQpgYGB7ciBzZXQgdW5pdHMgaW4gRkxzdG9ja30NCnN0ayA8LSBTQU0yRkxTdG9jayhzYW1maXQsIHN0b2NrLnd0X2VzdCA9IFRSVUUpDQoNCiNQSlc6DQojIyMgVHJpbSBvZmYgbGFzdCB5ZWFyIG9mIHRoZSBzdG9jayBvYmplY3QgKG9ubHkgaWYgaW5jb21wbGV0ZSBkYXRhIGZvciBsYXN0IGFzc2Vzc21lbnQgeWVhcikNCm9yaWdTdGsgPC0gc3RrDQpzdGsgPC0gd2luZG93KHN0aywgc3RhcnQ9cmFuZ2Uoc3RrKVsibWlueWVhciJdLCBlbmQ9KHJhbmdlKHN0aylbIm1heHllYXIiXS0xKSkNCg0KIyBhZGQgbmFtZSBhbmQgZGVzY3JpcHRpb24gb2YgdGhlIHN0b2NrDQpuYW1lKHN0aykgPC1zdG9ja05hbWU8LSJQTEUuMjcuMjEtMzIiDQpkZXNjKHN0aykgPC0gIlBsYWljZSBpbiB0aGUgQmFsdGljIFNlYSBhbmQgS2F0dGVnYXQiDQoNCiMjIFVuaXRzDQp1bml0cyhjYXRjaChzdGspKSA8LSB1bml0cyhkaXNjYXJkcyhzdGspKSA8LSB1bml0cyhsYW5kaW5ncyhzdGspKSA8LSB1bml0cyhzdG9jayhzdGspKSA8LSAndCcNCnVuaXRzKGNhdGNoLm4oc3RrKSkgPC0gdW5pdHMoZGlzY2FyZHMubihzdGspKSA8LSB1bml0cyhsYW5kaW5ncy5uKHN0aykpIDwtIHVuaXRzKHN0b2NrLm4oc3RrKSkgPC0gJzEwMDAnDQp1bml0cyhjYXRjaC53dChzdGspKSA8LSB1bml0cyhkaXNjYXJkcy53dChzdGspKSA8LSB1bml0cyhsYW5kaW5ncy53dChzdGspKSA8LSB1bml0cyhzdG9jay53dChzdGspKSA8LSAna2cnDQoNCg0KIyBvdmVydmlldyBvZiBkYXRhIGltcG9ydGVkIGludG8gdGhlIEZMU3RvY2sgKGZyb20gdGhlIFNBTSBvdXRwdXQpDQpzdW1tYXJ5KHN0aykNCg0KYGBgDQoNCiMjIFVzZXIgc3BlY2lmaWVkIGlucHV0cw0KU29tZSBtYW51YWwgaW5wdXRzIGFuZCBjb25maWd1cmF0aW9uIGZvciBFUS1zaW0gYXJlIHJlcXVpcmVkLiBGb3IgdGhlIGxhdGVyIGNhbGN1bGF0aW9uIG9mIHJlZmVyZW5jZSBwb2ludHMsIHRoZSBkYXRhIHllYXIgYW5kIHRpbWUgc2VyaWVzIHJhbmdlIGFyZSBzZXQuDQpUaGUgZm9yZWNhc3QgZXJyb3JzIGFyZSBzZXQgdG8gZGVmYXVsdCB2YWx1ZXMsIHdoaWxlIHRoZSB1bmNlcnRhaW50aWVzIG9mIHRoZSBsYXN0IHllYXIgKHNpZ21hRiBhbmQgc2lnbWEgU1NCKSBhcmUgdGFrZW4gZGlyZWN0bHkgZnJvbSB0aGUgU0FNIG91dHB1dC4gDQoNCmBgYHtyIHJlZi1wb2ludCBzZXR0dGluZ3N9DQojIFNpbXVsYXRpb24gc2V0dGluZ3MNCkRhdGFZZWFyIDwtIDIwMjMNCm1pblllYXIgPC0gcmFuZ2Uoc3RrKVsibWlueWVhciJdDQptYXhZZWFyIDwtIHJhbmdlKHN0aylbIm1heHllYXIiXSAjUEpXOiBub3cgY29ycmVzcG9uZHMgd2l0aCBEYXRhWWVhciBkdWUgdG8gdHJpbW1pbmcgdGhlIHN0b2NrIG9iamVjdA0KDQojIyBOdW1iZXIgb2Ygc2ltcw0Kbm9TaW1zIDwtIDEwMDAgI1BKVzogV291bGQgYmUgYmV0dGVyIHRvIHVwZ3JhZGUgdG8gMjAwMCB3aXRoIGZpbmFsIHJ1bg0KcmhvUmVjIDwtIFQNCg0KIyMgRm9yZWNhc3QgZXJyb3INCmN2RiAgPC0gMC4yNQ0KcGhpRiA8LQkwLjMgIyBjdkYgIDwtIDAuMjEyZGVmYXVsdCB2YWx1ZXMsIGxvb2sgaW4gV0tNU1lSRUY0IChhbHRob3VnaCBjb25mdXNpb24gd2l0aCAwLjIzMz8pDQpjdlNTQiA8LSAwDQpwaGlTU0IgPC0gMA0KDQojIyA1dGggcGVyY2VudGlsZSBvZiBTU0IgaW4gdGhlIGZpbmFsIHllYXIgb2YgdGhlIGFzc2Vzc21lbnQNClNTQjA1PC0wICAjIHVzZWQgaW4gTVNZIEJ0cmlnZ2VyIGNhbGN1bGF0aW9uLiBJZiBzZXQgYXQgMCwgaWdub3JlZA0KDQojIyBVbmNlcnRhaW50eSBsYXN0IHllYXINCiMgUEpXOiByZW1vdmVkIC0xIGJlY2F1c2UgdGhpcyBmaXhlZCBieSB0cmltbWluZyBzdGsgb2JqZWN0DQojIyMgRiANCnNpZ21hRiA8LSBzYW1maXQkc2RyZXAkc2RbbmFtZXMoc2FtZml0JHNkcmVwJHZhbHVlKSA9PSAibG9nZmJhciJdW3NhbWZpdCRkYXRhJHllYXJzICVpbiUgKG1heChzYW1maXQkZGF0YSR5ZWFycykpXSAjIEV4dHJhY3RzIHRoZSBsYXN0IEZVTEwgeWVhcidzIHNkKGxvZyhGYmFyKSkgdmFsdWUgZnJvbSB0aGUgbW9kZWwgb2JqZWN0DQoNCiMjIyBTU0IgDQpzaWdtYVNTQiA8LSBzYW1maXQkc2RyZXAkc2RbbmFtZXMoc2FtZml0JHNkcmVwJHZhbHVlKSA9PSAibG9nc3NiIl1bc2FtZml0JGRhdGEkeWVhcnMgJWluJSAobWF4KHNhbWZpdCRkYXRhJHllYXJzKSldICMgRXh0cmFjdHMgdGhlIGxhc3QgRlVMTCB5ZWFyJ3Mgc2QobG9nKFNTQikpIHZhbHVlIGZyb20gdGhlIG1vZGVsIG9iamVjdA0KDQojIERpc3BsYXkgYWxsIHNldHRpbmdzIA0KYWxsX3NldHRpbmdzIDwtIGRhdGEuZnJhbWUobWluX1llYXIgPSBtaW5ZZWFyLCBtYXhfeWVhciA9IG1heFllYXIsIGN2RiA9IGN2RiwgUGhpRiA9IHBoaUYsIGN2U1NCID0gY3ZTU0IsIHBoaVNTQiA9IHBoaVNTQiwgU1NCMDUgPSBTU0IwNSwgc2lnbWFGID0gc2lnbWFGLCBzaWdtYVNTQiA9IHNpZ21hU1NCKQ0KDQprYWJsZShhbGxfc2V0dGluZ3MsIGNhcHRpb249ImFsbCBzZXR0aW5ncyBmb3IgdGhlIHJlZnBvaW50IGNhbGN1bGF0aW9ucyIpDQoNCg0KYGBgDQoNCiMjIGNhbGN1bGF0ZSBsYW5kaW5ncywgZGlzY2FyZHMgYW5kIGNhdGNoIGZyb20gaW5wdXQgbnVtYmVycyBhbmQgd2VpZ2h0DQpgYGB7ciBjb21wdXRlIHRvdGFsIHdlaWdodHMsIGZpZy5jYXA9IlN1bW1hcnkgb2Ygc3RvY2sgb2JqZWN0LiJ9DQpsYW5kaW5ncyhzdGspIDwtIGNvbXB1dGVMYW5kaW5ncyhzdGspDQpkaXNjYXJkcyhzdGspIDwtIGNvbXB1dGVEaXNjYXJkcyhzdGspDQojIGFuZCB0aGVuIHRoZSBjYXRjaCBzbG90cyBmcm9tIGJvdGggbGFuZGluZ3MgYW5kIGRpc2NhcmRzDQpjYXRjaChzdGspIDwtIGNvbXB1dGVDYXRjaChzdGssIHNsb3Q9ImFsbCIpDQoNCnN0b2NrKHN0aykgPC0gY29tcHV0ZVN0b2NrKHN0aykNCg0KcGxvdChzdGspDQpgYGANCg0KYGBge3IgcGxvdCBjYXRjaCBsYW5kaW5ncywgZmlnLmNhcD0iQ2F0Y2hlcyBhbmQgbGFuZGluZ3MsIHRpbWVzZXJpZXMsIGluZGVwZW5kZW50bHkuIiwgZXZhbD1GQUxTRX0NCnBsb3QobWV0cmljcyhzdGssIENhdGNoPWNhdGNoLCBMYW5kaW5ncz1sYW5kaW5ncykpDQpgYGANCg0KIyMgU2VsZWN0aXZpdHkvY2F0Y2hhYmlsaXR5IA0KQWdlZC1iYXNlZCBzZWxlY3Rpdml0eS9jYXRjaGFiaWxpdHkgcGxvdHMgYXMgcmVxdWVzdGVkIGJ5IHdvcmtpbmcgZ3JvdXAuDQoNCg0KDQpgYGB7ciBjYXRjaGFiaWxpdHkgcGxvdHMsIGZpZy5jYXA9IlNlbGVjdGl2aXR5L0NhdGNoYWJpbGl0eSBvZiB0aGUgc3RvY2ssIG92ZXIgdGltZSwgYnkgYWdlLiJ9DQphZ2VzIDwtIHNhbWZpdCRjb25mJG1pbkFnZTpzYW1maXQkY29uZiRtYXhBZ2UNCnllYXJzIDwtIHNhbWZpdCRkYXRhJHllYXJzDQptZWFuRmFnZXMgPC0gc2FtZml0JGNvbmYkZmJhclJhbmdlDQoNCiMgIyMjIEVsbGlvdCdzIGNvcnJlY3RlZCB2ZXJzaW9uLCBvZiB3aGF0IHNlZW1zIGEgcG9pbnRsZXNzIGV4Y2hhbmdlLiAuIC4gLiANCiMgaGFydmVzdChzdGspIDwtIGV4cChzYW1maXQkcGwkbG9nRilbYyhhZ2VzWy1sZW5ndGgoYWdlcyldLCAobWF4KGFnZXMpLTEpKSxdDQoNCm1lYW5GIDwtIGFwcGx5KGhhcnZlc3Qoc3RrKVthcy5jaGFyYWN0ZXIobWVhbkZhZ2VzKSxdLDIsICJtZWFuIikNCnNlbCA8LSBzd2VlcChoYXJ2ZXN0KHN0ayksMixtZWFuRiwiLyIpDQoNCnBsb3QoYWdlcyxzZWxbLGFjKG1heCh5ZWFycyktMSldLCB0eXBlPSJsIiwgeWxpbT1jKDAsbWF4KHNlbCkpLCB4bGFiPSJBZ2UiLCB5bGFiPSJTZWxlY3Rpdml0eSIsIG1haW49IlNlbGVjdGl2aXR5IikNCmZvciAoaSBpbiBhYygobWF4WWVhci0xOSApOm1heFllYXIpKSBsaW5lcyhhZ2VzLHNlbFssaV0sIGNvbD1pKQ0KbGluZXMoYWdlcyxhcHBseShzZWxbLGFjKChtYXhZZWFyLTIpOm1heFllYXIpXSwxLG1lYW4pLCBjb2w9MSwgbHdkPTUpDQpsaW5lcyhhZ2VzLGFwcGx5KHNlbFssYWMoKG1heFllYXItNCk6bWF4WWVhcildLDEsbWVhbiksIGNvbD0yLCBsd2Q9NSkNCmxpbmVzKGFnZXMsYXBwbHkoc2VsWyxhYygobWF4WWVhci05KTptYXhZZWFyKV0sMSxtZWFuKSwgY29sPTMsIGx3ZD01KQ0KbGluZXMoYWdlcyxhcHBseShzZWxbLGFjKChtYXhZZWFyLTE5KTptYXhZZWFyKV0sMSxtZWFuKSwgY29sPTQsIGx3ZD01KQ0KbGVnZW5kKCJ0b3BsZWZ0IiwgbGVnZW5kPWMoIk1lYW4gbGFzdCAzeXJzIiwiTWVhbiBsYXN0IDV5cnMiLCJNZWFuIGxhc3QgMTB5cnMiLCJNZWFuIGxhc3QgMjB5cnMiKSwgbHdkPTUsIGNvbD0xOjQsIGJ0eT0ibiIpDQoNCg0KYGBgDQoNCiMgQ2hvaWNlIG9mIHN0b2NrIHJlY3J1aXRtZW50IG1vZGVsDQpNYW55IGludmVzdGlnYXRpb25zIHdlcmUgbWFkZSB0byB0cnkgYW5kIGNob29zZSBhbiBhcHByb3ByaWF0ZSBzdG9jay1yZWNydWl0bWVudCBtb2RlbC4gSG93ZXZlciwgdGhlIHdvcmtpbmcgZ3JvdXAgYWdyZWVkIHRoYXQgdGhlcmUgd2FzIG5vIHN1aXRhYmxlIHN0YW5kYXJkIG1vZGVsIHRvIGZpdCB0aGVzZSBkYXRhLiAgQXMgY2FuIGJlIHNlZW4gYmVsb3csIHRoZSBzdG9jayBzdGFydHMgaW4gYSAibG93IHByb2R1Y3Rpdml0eSIgc3RhdGUgd2l0aCByZWxhdGl2ZWx5IGxvdyBTU0IgYW5kIHJlY3J1aXRtZW50LCBidXQgdGhlbiByYXBpZGx5IHJpc2VzIGluIHJlY2VudCBoaXN0b3J5LCBpbiBhbiBhbG1vc3QgbGluZWFyIHRyZW5kIHdpdGggbm8gc2lnbiBvZiByZWFjaGluZyBhbiBhc3ltcHRvdGUuIEJlY2F1c2Ugb2YgdGhpcyBkcmFtYXRpYyBjaGFuZ2UgYW5kIHRoZSBmYWN0IHRoYXQgdGhlIHN0b2NrIGlzIHN0aWxsIG5vdCByZWFjaGluZyBzb21lIGZvcm0gb2YgZXF1aWxpYnJpdW0gYWxsIHN0YW5kYXJkIG1vZGVscyBhc3N1bWUgYW4gaW5maW5pdGUgcmVsYXRpb25zaGlwIHdpdGggbm8gY2FwIG9uIHJlY3J1aXRtZW50Lg0KDQpUbyB2aWV3IHRoZSBkZXRhaWwgb2YgdGhlIGRhdGEgYXQgdGhlIGJlZ2lubmluZyBvZiB0aGUgdGltZSBzZXJpZXMsIGNsaWNrIGFuZCBkcmFnIGEgcmVjdGFuZ2xlIG92ZXIgdGhlIGJvdHRvbSBsZWZ0IHBvcnRpb24gb2YgdGhlIHBsb3QgYXJlYS4gDQoNCmBgYHtyIGZpZy5jYXA9IlN0b2NrIFJlY3J1aXRtZW50IFJlbGF0aW9uc2hpcC4ifQ0KZ2dwbG90bHkoZ2dwbG90KGFzdW0sDQogICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4PVNTQiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9Ul9hZ2UxKSkgKw0KICAgICAgICAgICBnZW9tX3BhdGgoY29sb3VyID0gZWJwYWxbMV0pICsNCiAgICAgICAgICAgZ2VvbV90ZXh0KG1hcHBpbmcgPSBhZXMobGFiZWw9WWVhciksDQogICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBlYnBhbFsyXSwNCiAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC41KSArDQogICAgICAgICAgIHhsYWIoIlNTQiAodG9ubmVzKSIpICsNCiAgICAgICAgICAgeWxhYigiUmVjcnVpdG1lbnQgKG51bWJlcnMpIikgKw0KICAgICAgICAgICB0aGVtZV9jbGVhbigpKQ0KYGBgDQoNClRvIGJldHRlciB2aWV3IHRoZSB0cmVuZHMsIGFjcm9zcyB0aGUgbGFyZ2Ugc2hpZnQgaW4gc2NhbGUsIHdlIGNhbiBhbHNvIHZpc3VhbGl6ZSB0aGlzIGluIHRoZSBsb2ctc2NhbGUuIA0KDQpgYGB7ciwgU1IgcmVsYXRpb24sIGZpZy5jYXAgPSAiU1JSIG9mIHBsZS4yNy4yMS0zMi4gUiBpcyBsb2ctc2NhbGVkIHRvIGVuaGFuY2UgdGhlIHJlc29sdXRpb24gb2YgdGggZWFybHkgeWVhcnMgaW4gdGhlIHRpbWUtc2VyaWVzLiJ9DQpnZ3Bsb3RseShnZ3Bsb3QoYXN1bSwNCiAgICAgICAgICAgICAgICBtYXBwaW5nID0gYWVzKHg9U1NCLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT1sb2coUl9hZ2UxKSkpICsNCiAgICAgICAgICAgZ2VvbV9wYXRoKGNvbG91ciA9IGVicGFsWzFdKSArDQogICAgICAgICAgIGdlb21fdGV4dChtYXBwaW5nID0gYWVzKGxhYmVsPVllYXIpLA0KICAgICAgICAgICAgICAgICAgICAgY29sb3VyID0gZWJwYWxbMl0sDQogICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuNSkgKw0KICAgICAgICAgICB4bGFiKCJTU0IgKHRvbm5lcykiKSArDQogICAgICAgICAgIHlsYWIoIlJlY3J1aXRtZW50IChsb2cgb2YgbnVtYmVycykiKSArDQogICAgICAgICAgIHRoZW1lX2NsZWFuKCkpDQpgYGANCg0KV2hlbiB3ZSBmb3JjZSBhIHNlZ21lbnRlZCByZWdyZXNzaW9uIChob2NrZXktc3RpY2spIHRocm91Z2ggdGhlIGRhdGEsIHRoZSByZXN1bHQgaXMgaW5kaWNhdGl2ZSBvZiB0aGUgbm9uLWVxdWlsaWJyaXVtIHN0YXR1cyBvZiB0aGUgc3RvY2ssIHdpdGggbm8gaWRlbnRpZmllZCBicmVhay1wb2ludC4NCg0KYGBge3IgZml0IGVxc2ltfQ0Kc2V0LnNlZWQoMTIzKQ0KZXFmaXQgPC0gZXFzcl9maXQoc3RrID0gc3RrLA0KICAgICAgICAgICAgICAgICAgbnNhbXAgPSBub1NpbXMsDQogICAgICAgICAgICAgICAgICBtb2RlbHMgPSBjKCJTZWdyZWciKSkNCiMgICAgICAgICAgICAgICAgICBtb2RlbHMgPSBjKCJTbW9vdGhfaG9ja2V5IiwiQmV2aG9sdCIsICJTZWdyZWciKSkNCmBgYA0KDQoNCmBgYHtyIGVxc2ltIFNSIHBsb3QgZml0dGVkLCBmaWcuY2FwPSJTZWdtZW50ZWQgcmVncmVzc2lvbiBmaXQgb2Ygc3RvY2stcmVjcnVpdG1lbnQgZGF0YS4ifQ0KIyBlcXNyX3Bsb3QoZXFmaXQpDQogZXFzcl9wbG90KGVxZml0LG49MmU0LGdnUGxvdD1UUlVFLFNjYWxlPTFlMykgI25pY2VyIGdncGxvdCBjb2xvcnMgDQpgYGANCg0KVG8gZnVydGhlciBpbnRlcnJvZ2F0ZSB0aGUgcG90ZW50aWFsIHJlbGF0aW9uc2hpcHMgYmV0d2VlbiBzc2IgYW5kIHJlY3J1aXRtZW50LCB3ZSBjYW4gdmlzdWFsaXNlIGl0IGFub3RoZXIgd2F5LCB1c2luZyBhIGRpcmVjdCByYXRpbyBvZiByZWNydWl0cyBwZXIgU1NCLg0KDQpgYGB7ciBwbG90IFIgcGVyIHNzYiwgZmlnLmNhcD0iUmVjcnVpdHMgcGVyIFNTQiBvdmVyIHRpbWUuIn0NCnN0b2NrTmFtZSA8LSAicGxlLjI3LjIxLTMyIg0KZGYgPC0gZGF0YS5mcmFtZShzdW1tYXJ5KHNhbWZpdCkpDQpkZiR5ZWFyIDwtIHJvd25hbWVzKGRmKQ0Kcm93bmFtZXMoZGYpIDwtIE5VTEwNCg0KcmVjIDwtIGRmWzI6bnJvdyhkZiksICJSLmFnZS4xLiJdICMgaW4gcmF3IG51bWJlcnMuDQpzc2IgPC0gZGZbMToobnJvdyhkZiktMSksICJTU0IiXSAjIGluIHRvbm5lcy4NCmRmJHJlYy5zc2IgPC0gYyhOQSwgKHJlYy9zc2IpKQ0KDQpnZ3Bsb3QoZGF0YSA9IGRmKSArDQogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0geWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSByZWMuc3NiKSwNCiAgICAgICAgICAgICBzaGFwZSA9IDApICsgIA0KICBnZW9tX2xpbmUobWFwcGluZyA9IGFlcyh4ID0geWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IHJlYy5zc2IsDQogICAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0gMSksDQogICAgICAgICAgICAgbGluZXR5cGUgPSAiZGFzaGVkIikgKw0KICB4bGFiKCJZZWFyIG9mIHJlY3J1aXRtZW50IikgKw0KICB5bGFiKCJSZWNydWl0bWVudCAoMDAwJ3MpIC9cblNTQiBvZiB0aGUgcHJldmlvdXMgeWVhciAodG9ubmVzKSIpICsNCiAgdGhlbWVfY2xlYW4oKSArDQogIHRoZW1lKGF4aXMudGV4dC54LmJvdHRvbSA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSkpDQoNCg0KDQpgYGANCg0KIyBQcmVwYXJhdGlvbiBvZiByZWZlcmVuY2UgcG9pbnQgY2FsY3VsYXRpb24NCiMjIEd1aWRlbGluZXMgYW5kIG90aGVyIHByZWNlZGVudHMNCklDRVMgaGFzIHNwZWNpZmljIGd1aWRlbGluZXMgZm9yIGRldGVybWluaW5nIHJlZmVyZW5jZSBwb2ludHMuIFRoZSBndWlkZWxpbmVzIGNhbiBiZSBmb3VuZCBbaGVyZV0oaHR0cHM6Ly9odHRwczovL2ljZXMtbGlicmFyeS5maWdzaGFyZS5jb20vYXJ0aWNsZXMvcmVwb3J0L1RlY2huaWNhbF9HdWlkZWxpbmVzXy1fSUNFU19maXNoZXJpZXNfbWFuYWdlbWVudF9yZWZlcmVuY2VfcG9pbnRzX2Zvcl9jYXRlZ29yeV8xX2FuZF8yX3N0b2Nrc18yMDIxXy8xODYzODE1MD9maWxlPTMzNDE3NTUxKQ0KDQpBcyBkZW1vbnN0cmF0ZWQgYWJvdmUsIG5vIHN0b2NrLXJlY3J1aXRtZW50IHJlbGF0aW9uc2hpcCBjYW4gYmUgZXN0aW1hdGVkIGZyb20gdGhlIGRhdGEsIHNvIGEgU3RvY2sgVHlwZSAyIHN0b2NrLXJlY3J1aXRtZW50IGNhdGVnb3JpemF0aW9uIHdhcyBydWxlZCBvdXQuICBUaGlzIHdhcyBpbnZlc3RpZ2F0ZWQgYm90aCB3aXRoIGFuZCB3aXRob3V0IHRoZSA1IGxhc3QgeWVhcnMgb2YgZGF0YSwgd2hlcmUgdGhlIHN0b2NrIGFwcGVhcnMgdG8gYmUgc2hpZnRpbmcgaW50byBhIG5ldyByZWdpbWUuDQoNCkFsdGhvdWdoIHRoZSBzdG9jay1yZWNydWl0bWVudCBwYXR0ZXJuIHdhcyB2aXN1YWxseSBzaW1pbGFyIHRvIGEgU3RvY2sgVHlwZSAzLCB0aGlzIGNhdGVnb3J5IHdhcyBydWxlZCBvdXQgYmVjYXVzZSB0aGlzIHBsYWljZSBzdG9jayBpcyBjYXVnaHQgbWFpbmx5IGFzIGEgYnljYXRjaCBmaXNoZXJ5LCBhbmQgaXQgd2FzIG5vdCBiZWxpZXZlZCBieSBleHBlcnRzIHRoYXQgdGhlIGVudGlyZSB0aW1lIHNlcmllcyBjb3VsZCBiZSByZWZsZWN0aXZlIG9mIGFuIG92ZXJmaXNoZWQgcGVyaW9kLiBJdCB3YXMgaW5zdGVhZCBiZWxpZXZlZCB0aGF0IHRoYXQgZWFybGllc3QgeWVhcnMgY291bGQgcmVmbGVjdCBhbiBvdmVyZmlzaGVkIHN0YXRlIHdpdGggcmVjcnVpdG1lbnQgaW1wYWlybWVudCBkdWUgdG8gaGlnaCBkaXNjYXJkaW5nIG9mIHBsYWljZSBpbiB0aGUgdGFyZ2V0ZWQgY29kIGZpc2hlcnksIGJ1dCBpdCB3b3VsZCBiZSBkaWZmaWN1bHQgdG8ganVzdGlmeSBhIGJlbGllZiB0aGF0IHJlY3J1aXRtZW50IGltcGFpcm1lbnQgY291bGQgYmUgZXhwZXJpZW5jZWQgYWxzbyBpbiB0aGUgbGF0dGVyIHBvcnRpb24gb2YgdGhlIHRpbWUgc2VyaWVzLg0KDQpUaGVyZWZvcmUsIGFmdGVyIG11Y2ggZGlzY3Vzc2lvbiwgaXQgd2FzIGRldGVybWluZWQgdGhhdCB0aGlzIHN0b2NrIGZhbGxzIGVpdGhlciBpbnRvIHR5cGUgMSBvciA1IChmcm9tIHRoZSBhZm9yZW1lbnRpb25lZCBndWlkZWxpbmVzKS4gDQoNCiMgQ2FsY3VsYXRlIHJlZmVyZW5jZSBwb2ludHMNCkJlZm9yZSB3ZSBiZWdpbiBjYWxjdWxhdGluZyB0aGUgdmFyaW91cyByZWZlcmVuY2UgcG9pbnRzLCB3ZSBtdXN0IGZpcnN0IGRlY2lkZSBvbiBzb21lIGRhdGEgdHJ1bmNhdGlvbiBhbmQgc2V0dGluZ3MgZm9yIHRoZSBzaW11bGF0aW9uLiANCg0KQmVjYXVzZSBvZiB0aGUgcmFwaWQgY2hhbmdlcyBpbiBzdG9jayBkeW5hbWljcyBpbiByZWNlbnQgeWVhcnMsIHRoZSBkZWNpc2lvbiB3YXMgbWFkZSB0byBydW4gc2ltdWxhdGlvbnMgZm9yIHJlZmVyZW5jZSBwb2ludHMgYmFzZWQgb24gdGhlIHBlcmlvZCBiZWZvcmUgc3RvY2std2VpZ2h0cy1hdC1hZ2UgYmVnYW4gdG8gZGVjbGluZSwgcmVjcnVpdG1lbnQgaW5jcmVhc2VkIGFuZCBTU0IgaW5jcmVhc2VkLiBJdCB3YXMgdGhvdWdodCB0aGF0IHRoaXMgbW9zdCByZWNlbnQgcGVyaW9kIG9mIGhpZ2ggcmVjcnVpdG1lbnQgb2YgcG9vci1jb25kaXRpb24gcmVmbGVjdHMgYSByYXJlIGVwaXNvZGUgb2Ygb3ZlcnNob290aW5nIGNhcnJ5aW5nIGNhcGFjaXR5LCBzbyBleHBlcnRzIGV4cGVjdGVkIHRoYXQgdGhpcyBwZXJpb2QgaXMgdW5saWtlbHkgdG8gY29udGludWUgaW4gdGhlIGxvbmctdGVybS4NCg0KYGBge3IgcmVmcG9pbnR0YWJsZSBhbmQgc2V0dGluZ3N9DQoNCiMjIFJlZmVyZW5jZSBwb2ludHMNCnJlZlB0cyA8LSBtYXRyaXgoTkEsbnJvdz0xLG5jb2w9OSwgZGltbmFtZXM9bGlzdCgidmFsdWUiLGMoIkJ0cmlnZ2VyIiwiQnBhIiwiQmxpbSIsIjV0aFBlcmNfU1NCbXN5IiwiRnBhIiwiRmxpbSIsICJGcDA1IiwiRm1zeV91bmNvbnN0ciIsIkZtc3kiKSkpDQoNCnNzYl9tZWQgPC0gbWVkaWFuKHNzYikNCnJlY19tZWQgPC0gbWVkaWFuKHJlYykNCg0KIyMgWWVhcnMgYnkgd2hpY2ggdG8gdHJ1bmNhdGUgZGF0YXNldC4NCnJtU1JSWXJzIDwtIGMoMjAxOTptYXhZZWFyKSAgIyBzcGVjaWZ5IGhlcmUgd2hpY2ggb3RoZXIgeWVhcnMgKGUuZy4gZWFybHkgcGVyaW9kKSBzaG91bGQgYmUgbGVmdCBvdXQNCiNQSlcgcmVtb3ZlZCBoZXJlIHJlZHVuZGFudCBtYXhZZWFyIGRlZiBhbmQgYWRkZWQgbWF4WWVhciB0byBhYm92ZQ0KDQojIyBEZWNpc2lvbnMgYW5kIHNldHRpbmdzIGZvciB1c2UgaW4gZm9yd2FyZCBzaW11bGF0aW9ucw0KIyMjIEhvdyBtYW55IHllYXJzIHRvIGF2ZXJhZ2Ugb3ZlciAocmVzYW1wbGUgZnJvbSkgZm9yIGJpb2xvZ2ljYWwgZGF0YQ0KbnVtQXZnWXJzQiA8LSA1ICNQSlc6IEkgY2hhbmdlZCB0aGlzIHRvIDUgZnJvbSAxMCBmb3IgdGVzdGluZy4uLiBJIHRoaW5rIHdlIHNhaWQgZWl0aGVyIHdhcyBvaw0KIyMjIEhvdyBtYW55IHllYXJzIHRvIHNhbXBsZSBmcm9tIGZvciBzdG9jayB2YXJpYWJpbGl0eQ0KbnVtQXZnWXJzUyA8LSA1ICNQSlc6IEkgY2hhbmdlZCB0aGlzIHRvIDUgZnJvbSAxMCBmb3IgdGVzdGluZy4uLiBJIHRoaW5rIHdlIHNhaWQgZWl0aGVyIHdhcyBvaw0Kc3JZZWFycyA8LSBzZXRkaWZmKGMobWluWWVhcjoobWF4WWVhcikpLHJtU1JSWXJzKQ0KTnJ1bnMgPC0gMjAwIA0KRnNUb1NjYW4gPC0gIHNlcSgwLDEsIGJ5ID0gMC4wMDUpICNzZXEoMCwgMC45LCBsZW4gPSAyMDApICMgY2hhbmdlZCBtYXggdG8gMSAtIGVhcmxpZXIgdmVyc2lvbnMgeW91IHNob3dlZCBkaWQgbm90IGhhdmUgbGV2ZWxpbmcgb2ZmIGluIEZsaW0gcnVucyBzbyBGIG5lZWRzIHRvIGJlIGluY3JlYXNlZA0KDQpgYGANCg0KIyMgQ2FsY3VsYXRlL2VzdGltYXRlICRCX3tsaW19JCBhbmQgJEJfe3BhfSQNCkJsaW0gaXMgdGhlIGtleSBQQSByZWZlcmVuY2UgcG9pbnQuIFRoZSBvdGhlciBwcmVjYXV0aW9uYXJ5IGFwcHJvYWNoIHBvaW50cyAoQnBhLCBGbGltLCBhbmQgRnBhKSBhcmUgYWxsIGVzdGltYXRlZCBmcm9tIEJsaW0uIEluIGEgZmV3IGNhc2VzLCB0aGUgYXZhaWxhYmxlIGluZm9ybWF0aW9uIGRvZXMgbm90IGFsbG93IGRpcmVjdCBlc3RpbWF0aW9uIG9mIEJsaW07IEJwYSBpcyB0aGVuIGVzdGltYXRlZCBkaXJlY3RseSwgYW5kIEJsaW0gIG1heSBiZSBkZXJpdmVkIGZyb20gQnBhLiANCg0KV2hpbGUgU3RvY2sgVHlwZXMgMSBhbmQgNSBmcm9tIHRoZSBndWlkZWxpbmVzIGNhbGwgZm9yIHVzaW5nIEJsb3NzIGFzIEJsaW0sIHRoZSBleHBlcnRzIGluIHRoZSB3b3JraW5nIGdyb3VwIHJlY29nbmlzZWQgdGhhdCBCbG9zcyAoMjAxMCkgaXMgbGVzcyB0aGFuIG1hbnkgb3RoZXIgU1NCIHZhbHVlcyB0aGF0IHdlcmUgYWxzbyBsb3cgYW5kIGR1cmluZyBhIHBlcmlvZCBvZiBoaWdoIGZpc2hpbmcgbW9ydGFsaXR5ICgyMDAyLTIwMDkpLiBUaGVyZWZvcmUsIHNldHRpbmcgQmxpbSB0byBCbG9zcyBtYXkgbm90IGJlIHN1ZmZpY2llbnRseSBwcmVjYXV0aW9uYXJ5Lg0KDQpUaGVyZWZvcmUsIHdlIGFsc28gZGVjaWRlZCB0byB0cnkgdG8gYXBwbHkgdGhlIHJ1bGVzIHVzZWQgZm9yIEd1bGYgb2YgUmlnYSBoZXJyaW5nLCBuYW1lbHkgdGhhdCB3ZSB0YWtlIGFzIEJwYSB0aGUgbWVhbiBTU0Igb2YgdGhvc2UgeWVhcnMgd2hlcmU6DQoNCiAtIFNTQiA8PSBtZWRpYW4gU1NCIEFORCANCiAtIHJlY3J1aXRtZW50ID49IG1lZGlhbiByZWNydWl0bWVudA0KDQpUaGUgbG9naWMgaGVyZSwgaXMgdGhhdCB3ZSBhcmUgZmluZGluZyB0aG9zZSB5ZWFycyB3aGVyZSBsb3cgU1NCIHN0aWxsIHJlc3VsdHMgaW4gcmVsYXRpdmVseSBoaWdoIHJlY3J1aXRtZW50IGFuZCB1c2luZyB0aGUgbWVhbiBzc2Igb2YgdGhvc2UgeWVhcnMgdG8gaWRlbnRpZnkgQnBhIGFuZCBjYWxjdWxhdGUgQmxpbSBmcm9tIHRoZXJlLiANCg0KYGBge3IgQmxpbSBhbmQgQnBhIGJhc2VkIG9uIEdvUiBIZXJyaW5nfQ0KcmVmUHRzWywgIkJwYSJdIDwtIG1lYW4oZGZbZGYkUi5hZ2UuMS4gPj0gbWVkaWFuKGRmJFIuYWdlLjEuKSAmIGRmJFNTQiA8PSBtZWRpYW4oZGYkU1NCKSAmIGRmJHllYXIgIT0gMjAyNCwgIlNTQiJdKQ0KcmVmUHRzWywiQmxpbSJdICA8LSByZWZQdHNbLCJCcGEiXS8xLjQNCg0Ka2FibGUocmVmUHRzKQ0KYGBgDQoNClRoaXMgcmVzdWx0ZWQgaW4gYSBCcGEgYmFzZWQgb24gdHdvIG9mIHRoZSBsb3dlc3Qgb2JzZXJ2ZWQgU1NCIGluIHRoZSB0aW1lIHNlcmllcywgd2hpY2ggY29ycmVzcG9uZGVkIHRvIGVzc2VudGlhbGx5IEJsb3NzIGJ5IG90aGVyIHN0b2NrIGNhdGVnb3J5IGRlZmluaXRpb25zIGFuZCBhIEJsaW0gdmFsdWUgbG93ZXIgdGhhbiBvYnNlcnZlZCBpbiB0aGUgdGltZSBzZXJpZXMuIEZ1cnRoZXJtb3JlLCB0aGlzIG1ldGhvZCBsZWQgdG8gYSB2YWx1ZSBhcHBlYXJlZCB0byBiZSBsZXNzIHRoYW4gMTAlIG9mIGVzdGltYXRlcyBvZiBCMCAoY2FsY3VsYXRlZCBzdWJzZXF1ZW50bHkpLiBUaGVyZWZvcmUgdGhpcyBtZXRob2Qgd2FzIGFsc28gcmVqZWN0ZWQuDQoNCkluIGEgc2Vjb25kIGFwcHJvYWNoLCBCbGltIHdhcyBlc3RpbWF0ZWQgYnkgdXNpbmcgdGhlICJlbXBpcmljYWwgYXBwcm9hY2giIGFuZCB1c2luZyBCIGVtcGlyaWNhbCBhcyBCbGltLiBJbiBhIHJldmlldyBvZiBJQ0VTIHJlZmVyZW5jZSBwb2ludHMgU2lsdmFyLVZpbGFkb21pdSBldCBhbC4gKDIwMjIpIGZvdW5kIHRoYXQgYWZ0ZXIgQmxvc3MsIHRoZSBtb3N0IHVzZWQgbWV0aG9kIHRvIGRlZmluZSBCbGltIHdhcyBhbiBlbXBpcmljYWwgbWV0aG9kIGJhc2VkIG9uIGlkZW50aWZ5aW5nIHRoZSBsb3dlc3QgYmlvbWFzcyB0aGF0IHJlc3VsdGVkIGluIGdvb2QgcmVjcnVpdG1lbnQuIFRoZSDigJxTdG9ja1JlY3J1aXTigJ0gUiBwYWNrYWdlIGF2YWlsYWJsZSBpbiBHaXRIdWIgcHJvdmlkZXMgYSBmdW5jdGlvbiB0aGF0IGZvcm1hbGl6ZXMgdGhpcyBtZXRob2QsIGFuZCBpZGVudGlmaWVzIHRoZSBsb3dlc3QgYmlvbWFzc2VzIHRoYXQgcmVzdWx0cyBpbiBhYm92ZSBtZWRpYW4gcmVjcnVpdG1lbnQuIA0KVGhlbiBCbGltIGlzIGRlZmluZWQgYXMgdGhlIGF2ZXJhZ2Ugb2YgdGhlIGlkZW50aWZpZWQgc2V0IG9mIGxvd2VzdCBiaW9tYXNzZXMgdGhhdCBjYW4gYmUgZm9ybWVkIGJ5IGp1c3Qgb25lIHBvaW50IG9yIHNldmVyYWwuIFdLTkVXUkVGIHByb3Bvc2VkIHRoZW4gYSBmb3VydGggbWV0aG9kIHRvIGRlZmluZSBCbGltICwgdGhlIOKAmGVtcGlyaWNhbCBhcHByb2FjaCcsIGluIHdoaWNoIEJsaW0gaXMgZGVmaW5lZCBhcyAibG93ZXN0IGJpb21hc3MgKFNTQikgdGhhdCByZXN1bHRlZCBpbiBhIGdvb2QgcmVjcnVpdG1lbnQgKGkuZS4sIGEgcmVjcnVpdG1lbnQgYWJvdmUgdGhlIG1lZGlhbikuIiANCg0KDQpgYGB7ciB1c2UgQmxpbSBlbXByaWNpYWwgaW5zdGVhZCBvZiBCbGltIGNsYXNzaWN9DQoNCiMjIEZMU1Igb2JqZWN0DQpmbHNyIDwtIGFzLkZMU1Ioc3RrKQ0KUyA8LSBhbihzc2IoZmxzcikpDQpSIDwtIGFuKHJlYyhmbHNyKSkNCg0KIyBNaW5pbXVtIFNTQiBsZXZlbCB0aGF0IHJlc3VsdGVkIGluIGEgcmVjcnVpdG1lbnQgaGlnaGVyIHRoYXQgdGhlIG1lZGlhbi4NCg0KQmxpbV9lbXAgPC0gY2FsY0JsaW0oUywgUiwgcXVhbnQgPSAwLjUsIHR5cGUgPSAxKQ0KDQoNCg0KYGBgDQoNClVzaW5nIHRoZSBkZWZpbml0aW9uIG9mIFdLTkVXUkVGIG9mIDIwMjQgYW5kIHRoZSAiU3RvY2tSZWNydWl0U0VUIiBwYWNrYWdlLCB0aGUgQmxpbSBlbXBpcmljYWwgaXMgYWJvdXQgYHIgQmxpbV9lbXBgIHRvbnMuIFRoZSBlbXBpcmljYWwgQmxpbSBpcyB2ZXJ5IGNsb3NlIHRoZSB0aGUgcHJldmlvdXNseSBlc3RpbWF0ZWQgQmxpbSB2YWx1ZSBvZiBgciByZWZQdHNbLCAiQmxpbSJdYCB0b25zIGFuZCB3b3VsZCBmYWNlIHNpbWlsYXIgaXNzdWVzIHdoZW4gdXNlZCBhcyBhIHJlZmVyZW5jZSBwb2ludC4gVGhlIEJsaW0gZW1waXJpY2FsIGFwcHJvYWNoIHdhcyB0aGVyZWZvcmUgYWxzbyByZWplY3RlZC4gDQoNCkFzIG5vIHN0YW5kYXJkIHNvbHV0aW9uIHdhcyBmb3VuZCwgaXQgd2FzIGRlY2lkZWQgdG8gbW9kaWZ5IHRoZSBkZWZpbml0aW9uIG9mIEJsb3NzIGdpdmVuIGZvciBTdG9jayBUeXBlcyAxIGFuZCA1IHRvIGJlIGJhc2VkIG9uIHRoZSBtZWFuIG9mIHNldmVyYWwgc2ltaWxhciBTU0IgdmFsdWVzIHRoYXQgc3Bhbm5lZCB0aGUgcmFuZ2VzIG9mIGhhdmluZyB5aWVsZGVkIGJvdGggZGVjZW50IHJlY3J1aXRtZW50IGluIHR3byBjYXNlcyAoMjAxMCAmIDIwMTEpIGFuZCByYXRoZXIgbG93IHJlY3J1aXRtZW50IGluIDggY2FzZXMgKDIwMDI6MjAwOSkuIEFzIG5vdGVkIGFib3ZlLCBzZXR0aW5nIEJsb3NzIHRvIGJlIHRoZSBtaW5pbXVtIFNTQiBvYnNlcnZlZCBpbiAyMDEwIHdhcyBub3QgY29uc2lkZXJlZCBhIGNhbmRpZGF0ZSBmb3IgQmxpbSBiZWNhdXNlIGl0J3MgdmFsdWUgd2FzIGxlc3MgdGhlbiB0aGUgOCB2YWx1ZXMgY29uc2lkZXJlZCB0byBoYXZlIHlpZWxkZWQgcmF0aGVyIGxvdyByZWNydWl0bWVudCBlYXJsaWVyIGluIHRoZSB0aW1lIHNlcmllcy4gQW55IGNob2ljZSBvZiBTU0IgdmFsdWVzIGdyZWF0ZXIgdGhhbiB0aGUgMjAxMCB2YWx1ZSB3YXMgdGhlcmVmb3JlIGFyYml0cmFyeSwgc28gdGhlIGV4cGVydCBncm91cCBkZWNpZGVkIHRvIGluY2x1ZGUgYXMgbWFueSBhcyBwb3NzaWJsZSB0byByZWZsZWN0IHRoZSBncm91cCBvZiBzaW1pbGFyIFNTQiBhbmQgcmVjcnVpdG1lbnQgdmFsdWUgZWFybHkgaW4gdGhlIHRpbWUgc2VyaWVzLiBUaGUgMjAwMiAtIDIwMTEgdmFsdWVzIHdlcmUgZGVlbWVkICdkZWNlbnQnIGJlY2F1c2UgdGhleSBhcHBlYXJlZCB0byBzdXN0YWluIHJhdGhlciBzdGFibGUgU1NCIGFuZCByZWNydWl0bWVudCB2YWx1ZXMgZHVyaW5nIHRoZSBtaWQtcmFuZ2Ugb2YgdGhlIHRpbWUgc2VyaWVzLCBiZWZvcmUgdGhlIHByb2R1Y3Rpdml0eSBzaGlmdCBiZWdhbiBpbiAyMDIxLiBCbG9zcyB3YXMgdGhlcmVmb3JlIGNvbnNpZGVyZWQgdG8gYmUgdGhlIG1lYW4gU1NCIGZyb20gdGhlIGZpcnN0IHRlbiB5ZWFycyBvZiB0aGUgdGltZSBzZXJpZXMsIHdoZXJlIHJlY3J1aXRtZW50IGFuZCBTU0IgYm90aCByZW1haW5lZCByYXRoZXIgbG93LCBhbGJlaXQgdmFyaWFibGUuIEZ1cnRoZXJtb3JlLCB0aGlzIG1ldGhvZCBsZWQgdG8gYSB2YWx1ZSByb3VnaGx5IDE1JSBvZiBlc3RpbWF0ZXMgb2YgQjAgKGNhbGN1bGF0ZWQgc3Vic2VxdWVudGx5KSwgYW5kIEJsaW0gd2FzIHNldCB0byB0aGlzIG5ld2x5IGRlZmluZWQgQmxvc3MgdmFsdWUuDQoNCmBgYHtyIGNhbGN1bGF0ZSBCcGEgYW5kIEJsaW0gb3B0aW9uIDJ9DQoNCnJlZlB0c1ssIkJsaW0iXSA8LSBtZWFuKGRmW2RmJHllYXIgJWluJSBjKDIwMDI6MjAxMSksICJTU0IiXSkNCg0KcmVmUHRzWywiQnBhIl0gIDwtcmVmUHRzWywiQmxpbSJdKmV4cCgxLjY0NSpzaWdtYVNTQikNCg0Ka2FibGUocmVmUHRzKQ0KYGBgDQoNCg0KDQoNCg0KDQoNCg0KSGF2aW5nIGFncmVlZCBhbmQgZXN0YWJsaXNoZWQgQmxpbSBhbmQgQnBhLCB3ZSBub3cgbW92ZSBvbiB0byBvdGhlciByZWZlcmVuY2UgcG9pbnRzLg0KDQojIyBDYWxjdWxhdGUgJEZfe2xpbX0kIGFuZCAkRl97cGF9JA0KPCEtLSBQSlc6IFRoaXMgaXMgbm8gbG9uZ2VyIHRydWUgRnBhIGlzIGRlcml2ZWQgZnJvbSBGbGltIGluIHRoZSByZXZlcnNlIG9mIHRoZSB3YXkgQnBhIGlzIGRlcml2ZWQgZnJvbSBCbGltLiAtLT4NCg0KPCEtLSBQSlc6IFRoZXNlIFNlZ1JlZyBtb2RlbHMgd2VyZSBhbHJlYWR5IHByZXNlbnRlZCBlYXJsaWVyIC0gc2tpcCAoSSBhZGRlZCAnZXZhbCA9IEYnIHRvIHRoZSBSIGNodW5rcykgVXNpbmcgYSBzZWdtZW50ZWQgcmVncmVzc2lvbiBvbiB0aGUgdHJ1bmNhdGVkIHRpbWVzZXJpZXMsIHdlIHNlZSBhIHBsYXRlYXUgd2l0aCBhIGJyZWFrcG9pbnQgYXJvdW5kIHRoZSBtYXhpbXVtIG9ic2VydmF0aW9uLiAtLT4NCg0KYGBge3IgcmVmaXQgZXFmaXQgdHJ1bmNhdGVkLCBmaWcuY2FwPSJFcWZpdCBTdG9jay1SZWNydWl0bWVudCBTZWctcmVnIG1vZGVsIG9uIHRydW5jYXRlZCBkYXRhc2VyaWVzLiIsIGV2YWwgPSBGfQ0KIyMgUmVmaXQgc3RvY2sgcmVjcnVpdG1lbnQgcmVsYXRpb25zaGlwIGJhc2VkIG9uIHRydW5jYXRlZCB0aW1lIHNlcmllcw0Kc2V0LnNlZWQoMTIzKQ0KZXFmaXQgPC0gZXFzcl9maXQoc3RrID0gc3RrLA0KICAgICAgICAgICAgICAgICAgbnNhbXAgPSBub1NpbXMsDQogICAgICAgICAgICAgICAgICBtb2RlbHMgPSBjKCJTZWdyZWciKSwNCiAgICAgICAgICAgICAgICAgIHJlbW92ZS55ZWFycyA9IHJtU1JSWXJzKQ0KDQojIyBQbG90DQplcXNyX3Bsb3QoZXFmaXQsbj0yZTQsZ2dQbG90PVRSVUUsU2NhbGU9MWUzKQ0KYGBgDQoNCkluIGZvcndhcmQgcHJvamVjdGlvbnMsIHdlIGNhbiB1c2UgYSBob2NrZXktc3RvY2sgZnVuY3Rpb24gdG8gcmVmbGVjdCB0aGUgc3RvY2stcmVjcnVpdG1lbnQgcmVsYXRpb25zaGlwLCBidXQgZm9yY2UgaXQgdG8gdXNlIG91ciBwcmUtZGVmaW5lZCBCbGltIGFzIHRoZSBicmVha3BvaW50LiBUaGlzIHJlcXVpcmVzIGZpdHRpbmcgdGhlICJzdGljayIgcG9ydGlvbiBvZiB0aGUgaG9ja2V5LXN0aWNrIGZ1bmN0aW9uIGFib3ZlIHRoZSBicmVha3BvaW50IHRvIHJlY3J1aXRtZW50IG9ic2VydmF0aW9ucy4NCg0KYGBge3IgcmVmaXQgZXFmaXQgdHJ1bmNhdGVkIEJsaW1CcmVhaywgZmlnLmNhcD0iRXFmaXQgU3RvY2stUmVjcnVpdG1lbnQgU2VnLXJlZyBtb2RlbCB3aXRoIEJsaW0gYnJlYWtwb2ludCBvbiB0cnVuY2F0ZWQgZGF0YXNlcmllcy4ifQ0KIyMgZGV0ZXJtaW5lIHNlZ3JlZyBtb2RlbCB3aXRoIEJsaW0gYnJlYWtwb2ludCBhbmQgKHJvdWdobHkpIGdlb21lYW4gcmVjIGFib3ZlIHRoaXMNClNlZ3JlZ0JsaW0gIDwtIGZ1bmN0aW9uKGFiLCBzc2IpIGxvZyhpZmVsc2Uoc3NiID49IHJlZlB0c1ssIkJsaW0iXSwgYWIkYSAqIHJlZlB0c1ssIkJsaW0iXSwgYWIkYSAqIHNzYikpDQoNCiMgIyMgZGV0ZXJtaW5lIHNlZ3JlZyBtb2RlbCB3aXRoIEJsb3NzIGJyZWFrcG9pbnQgYW5kIChyb3VnaGx5KSBnZW9tZWFuIHJlYyBhYm92ZSB0aGlzDQojIFNlZ3JlZ0Jsb3NzICA8LSBmdW5jdGlvbihhYiwgc3NiKSBsb2coaWZlbHNlKHNzYiA+PSBtaW4oc3NiKHN0aykpLCBhYiRhICogbWluKHNzYihzdGspKSwgYWIkYSAqIHNzYikpDQojIA0KIyAjIyBSZW1vdmUgdGhlIGxhc3QgeWVhciBmcm9tIEZMc3RvY2sgb2JqZWN0IHRvIHByZXZlbnQgTkEgaXNzdWVzIGZ1cnRoZXIgZG93biAoYXMgMjAyNCBpcyBiYXNlZCBvbmx5IG9uIG9uZSApDQojIHN0azEgPC0gdHJpbShzdGssIHllYXIgPSBjKChhcy5udW1lcmljKHN0a0ByYW5nZVsibWlueWVhciJdKSk6KChhcy5udW1lcmljKHN0a0ByYW5nZVsibWF4eWVhciJdKSktMSkpKQ0KDQojIyBSZWZpdCBzdG9jayByZWNydWl0bWVudCByZWxhdGlvbnNoaXAgYmFzZWQgb24gdHJ1bmNhdGVkIHRpbWUgc2VyaWVzDQpzZXQuc2VlZCgxMjMpDQplcWZpdCA8LSBlcXNyX2ZpdChzdGsgPSBzdGssDQogICAgICAgICAgICAgICAgICBuc2FtcCA9IG5vU2ltcywNCiAgICAgICAgICAgICAgICAgIG1vZGVscyA9IGMoIlNlZ3JlZ0JsaW0iKSwNCiAgICAgICAgICAgICAgICAgIHJlbW92ZS55ZWFycyA9IHJtU1JSWXJzKQ0KDQojIyBQbG90DQplcXNyX3Bsb3QoZXFmaXQsbj0yZTQsZ2dQbG90PVRSVUUsU2NhbGU9MWUzKQ0KYGBgDQoNCkJhc2VkIG9uIHRoaXMgZmluYWwgc3RvY2stcmVjcnVpdG1lbnQgcmVsYXRpb25zaGlwLCB3ZSBjYW4gYmVnaW4gdG8gZXN0aW1hdGUgTVNZIHJlZmVyZW5jZSBwb2ludHMuIFRvIGNhbGN1bGF0ZSBGbGltLCB3ZSBydW4gYSBzZXJpZXMgb2Ygc2ltdWxhdGlvbnMgd2l0aCBmaXhlZCBiaW9sb2dpY2FsIHBhcmFtZXRlcnMgYW5kIG5vIHZhcmlhYmlsaXR5IGluIHRoZSBlc3RpbWF0ZXMgb2YgRiBhbmQgU1NCLg0KDQpgYGB7ciBjYWxjdWxhdGUgRmxpbSBhbmQgRnBhLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCByZXN1bHRzPSdoaWRlJywgZmlnLnNob3c9J2hpZGUnfQ0KDQpzZXQuc2VlZCgxMjMpDQpTSU1fU2VncmVnQmxpbSA8LSBlcXNpbV9ydW4oZXFmaXQsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiaW8ueWVhcnMgPSBjKChtYXhZZWFyLW51bUF2Z1lyc0IpLCBtYXhZZWFyKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmlvLmNvbnN0ID0gVFJVRSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsLnllYXJzID0gYygobWF4WWVhci1udW1BdmdZcnNTKSwgbWF4WWVhciksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbC5jb25zdCA9IFRSVUUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZjdiA9IDAsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZwaGkgPSAwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBTU0JjdiA9IDAsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJob2xvZ1JlYyA9IHJob1JlYywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQnRyaWdnZXIgPSAwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBCbGltID0gcmVmUHRzWywiQmxpbSJdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBCcGEgPSByZWZQdHNbLCJCcGEiXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTnJ1biA9IE5ydW5zLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGc2NhbiA9IEZzVG9TY2FuLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2ZXJib3NlPVQpDQoNCiMgc2F2ZSBNU1kgYW5kIGxpbSB2YWx1ZXMNCnRtcDEgPC0gdChTSU1fU2VncmVnQmxpbSRSZWZzKQ0KYGBgDQoNCmBgYHtyIEZwYSBwbG90cyB1cGRhdGUsIGZpZy5jYXA9IlBsb3RzIG9mIHN0b2NrIGR5bmFtaWNzIHVuZGVyIHNpbXVsYXRpb24gYXMgc3BlY2lmaWVkIGZvciBlc3RpbWF0aW9uIG9mIEZsaW0uIn0NCmVxc2ltX3Bsb3QoU0lNX1NlZ3JlZ0JsaW0sIGNhdGNoPVRSVUUpDQpgYGANCg0KYGBge3IgUmVjb3JkIEYgcmVmc30NCnJlZlB0c1ssIkZsaW0iXSA8LSB0bXAxWyJGNTAiLCJjYXRGIl0NCnRtcEZwYSA8LSByZWZQdHNbLCJGbGltIl0gKiBleHAoLXNpZ21hRiAqIDEuNjQ1KQ0KI1BKVzogVGhpcyBpcyBmaW5lIGJ1dCBrZWVwIGluIG1pbmQgbGF0ZXIgd2hlbiByZXBvcnRpbmcgdGhhdCB0aGlzIEZwYSBkZWZpbml0aW9uIGlzIG91dGRhdGVkIGFuZCBub3cgYmFzZWQgb24gRnAwNQ0KaWYgKHRtcEZwYTwwLjIpIHJlZlB0c1ssIkZwYSJdIDwtIHJvdW5kKHRtcEZwYSwgMykgZWxzZSByZWZQdHNbLCJGcGEiXSA8LSByb3VuZCh0bXBGcGEsIDIpDQpgYGANCg0KYGBge3IgRnBhIHRhYmxlIHVwZGF0ZX0NCg0Ka2FibGUoZGF0YS5mcmFtZShyZWZQdHNbLCJGbGltIl0scmVmUHRzWywiRnBhIl0pLCBjb2wubmFtZXMgPWMoIkZsaW0iLCAiRnBhIikpDQogICAgICANCg0KYGBgDQoNClRoZSBjYWxjdWxhdGVkIHZhbHVlcyBmb3IgRmxpbSBhbmQgRnBhIGFyZSBxdWl0ZSBsb3cgYW5kIGRpZCBub3QgcmVhc29uYWJseSByZWZsZWN0IHRoZSBzdG9jay4gVGhlIGxvdyB2YWx1ZXMgc2hvdyBhIG1pc21hdGNoIGJldHdlZW4gdGhlIHJldGFpbmVkIHJlY3J1aXRtZW50IHNlcmllcyAoYmVmb3JlIDIwMTkpIGFuZCB0aGUgcmVzYW1wbGVkIGJpb2xvZ2ljYWwgdmFyaWFibGVzIChsYXN0IDUgeWVhcnMpLiBUaHVzLCB0aGUgdHJ1bmNhdGlvbiBvZiB0aGUgc2FtcGxlZCB5ZWFycyBmb3IgdGhlIEIgYW5kIFMgY2FsY3VsYXRpb24gd2FzIGluY3JlYXNlZCB0byBpbmNsdWRlIHRoZSBsYXN0IDEwIHllYXJzIChpbnN0ZWFkIG9mIDUgeWVhcnMpIHRvIHRhY2tsZSB0aGUgbWlzbWF0Y2ggYmV0d2VlbiB0aGUgbmF0dXJhbCBtb3J0YWxpdHkgdmFsdWVzIGFuZCB0aGUgcmVjcnVpdG1lbnQuIA0KDQpUaGUgUmVjcnVpdG1lbnQtYXV0b2NvcnJlbGF0aW9uIChSaG9Mb2dSZWMpIGlzIGFsc28gaGlnaCAoPjAuOSkgd2hlbiBlc3RpbWF0ZWQgZnJvbSBTQU0gZGlyZWN0bHkgYW5kIGlzIGluZmx1ZW5jaW5nIHRoZSBlc3RpbWF0aW9uIG9mIHRoZSByZWZlcmVuY2UgcG9pbnRzLiBUaGUgaGlnaCB2YWx1ZSBzZWVtcyB0byBiZSBkcml2ZW4gYnkgdGhlIGV4Y2VwdGlvbmFsbHkgaGlnaCBSIGluIHRoZSBsYXRlc3QgeWVhciBjbGFzc2VzIHdoaWNoLCBmb3IgdGhhdCByZWFzb24sIHdlcmUgYWxyZWFkeSBleGNsdWRlZCBmcm9tIHRoZSBCbGltIGVzdGltYXRpb24gKHNlZSBhYm92ZSkuIEdlbmVyYWxseSwgUmhvIGlzIG11Y2ggc21hbGxlciBpbiBmaXNoIGFuZCBub3QgZWFzeSB0byBlc3RpbWF0ZSB3aXRoaW4gYXNzZXNzbWVudCBtb2RlbHMgd2l0aG91dCBiaWFzIGJlY2F1c2UgaXQgaXMgYSByYW5kb20gZWZmZWN0LCBzbyB0aGF0IEpvaG5zb24gZXQgYWwuICgyMDE2KSByZWNvbW1lbmRzIHRvIGRvIHRoZSBlc3RpbWF0aW9uIG91dHNpZGUgdGhlIG1vZGVsIGFuZCB0aGVuIGZpeCBpdC4gDQoNClRoZSBSZWNydWl0bWVudC1hdXRvY29ycmVsYXRpb24gKFJob0xvZ1JlYykgd2FzIHNldCB0byBhIGNvbnNlcnZhdGl2ZSBsZXZlbCBhdCAwLjYsIHdoaWNoIGlzIHNpbWlsYXIgdG8gb3RoZXIgUmhvIHZhbHVlcyBmb3IgcGxhaWNlIGRlcml2ZWQgZnJvbSBGSVNITElGRSAoaS5lLiwgMC41OCBmb3IgcGxhaWNlLCBUaG9yc29uIGV0IGFsLiwgMjAyMykuIA0KDQoNCmBgYHtyIHNpbXNhZ2Fpbmxvd2VyUmhvaGlnaGVybnVtQXZnWXJzLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCByZXN1bHRzPSdoaWRlJywgZmlnLnNob3c9J2hpZGUnfQ0KIyBUZXN0aW5nIHdoZXRoZXIgbWlzbWF0Y2ggYmV0d2VlbiBuYXR1cmFsIG1vcnRhbGl0eSB2YWx1ZXMgaW4gdGhlIGxhc3QgNSB5ZWFycyB2cyByZWNydWl0bWVudCB2YWx1ZXMgcHJldmlvdXNseSBjb3VsZCBhbHNvIGJlIGEgY3VscHJpdA0KDQpudW1BdmdZcnNCIDwtIG51bUF2Z1lyc1MgPC0gMTANCg0KcmVmUHRzMyA8LSBtYXRyaXgoTkEsbnJvdz0xLG5jb2w9OSwgZGltbmFtZXM9bGlzdCgidmFsdWUiLGMoIkJ0cmlnZ2VyIiwiQnBhIiwiQmxpbSIsIjV0aFBlcmNfU1NCbXN5IiwiRnBhIiwiRmxpbSIsICJGcDA1IiwiRm1zeV91bmNvbnN0ciIsIkZtc3kiKSkpDQoNCiByZWZQdHMzWywiQmxpbSJdIDwtIG1lYW4oZGZbZGYkeWVhciAlaW4lIGMoMjAwMjoyMDExKSwgIlNTQiJdKSAjIHJlZlB0czNbLCJCbGltIl0gPC0gcmVmUHRzWywiQmxpbSJdDQogcmVmUHRzM1ssIkJwYSJdICA8LXJlZlB0czNbLCJCbGltIl0qZXhwKDEuNjQ1KnNpZ21hU1NCKSAjIHJlZlB0czNbLCJCcGEiXSA8LSByZWZQdHNbLCJCcGEiXSANCg0Kc2V0LnNlZWQoMTIzKQ0KU0lNX1NlZ3JlZ0JsaW1fbG93ZXJSaG9oaWdoZXJudW1BdmdZcnMgPC0gZXFzaW1fcnVuKGVxZml0LCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmlvLnllYXJzID0gYygobWF4WWVhci1udW1BdmdZcnNCKSwgbWF4WWVhciksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJpby5jb25zdCA9IFRSVUUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbC55ZWFycyA9IGMoKG1heFllYXItbnVtQXZnWXJzUyksIG1heFllYXIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWwuY29uc3QgPSBUUlVFLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGY3YgPSAwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGcGhpID0gMCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU1NCY3YgPSAwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICByaG9sb2dSZWMgPSBjKDAuNiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIEJ0cmlnZ2VyID0gMCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQmxpbSA9IHJlZlB0czNbLCJCbGltIl0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIEJwYSA9IHJlZlB0czNbLCJCcGEiXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTnJ1biA9IE5ydW5zLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGc2NhbiA9IEZzVG9TY2FuLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2ZXJib3NlPVQpDQp0bXAxIDwtIHQoU0lNX1NlZ3JlZ0JsaW1fbG93ZXJSaG9oaWdoZXJudW1BdmdZcnMkUmVmcykNCnJlZlB0czNbLCJGbGltIl0gPC0gdG1wMVsiRjUwIiwiY2F0RiJdDQojdG1wRnBhIDwtIHJlZlB0czNbLCJGbGltIl0gKiBleHAoLXNpZ21hRiAqIDEuNjQ1KQ0KI1BKVzogVGhpcyBpcyBmaW5lIGJ1dCBrZWVwIGluIG1pbmQgbGF0ZXIgd2hlbiByZXBvcnRpbmcgdGhhdCB0aGlzIEZwYSBkZWZpbml0aW9uIGlzIG91dGRhdGVkIGFuZCBub3cgYmFzZWQgb24gRnAwNQ0KdG1wRnBhIDwtIHJlZlB0czNbLCJGcGEiXSA8LSByZWZQdHMzWywiRnAwNSJdIDwtIHRtcDFbIkYwNSIsImNhdEYiXQ0KDQppZiAodG1wRnBhPDAuMikgcmVmUHRzM1ssIkZwYSJdIDwtIHJvdW5kKHRtcEZwYSwgMykgZWxzZSByZWZQdHMzWywiRnBhIl0gPC0gcm91bmQodG1wRnBhLCAyKQ0KDQpgYGANCg0KVGhlIHJlc3VsdGluZyBGbGltIGFuZCBGcGEgcmVmZXJlbmNlIHBvaW50cyB3ZXJlIGNsb3NlciB0byBzaW1pbGFyIHZhbHVlcyBpbiBvdGhlciBwbGFpY2Ugc3RvY2tzIGFuZCBtb3JlIGZpdHRpbmcgdG8gdGhlIGRldmVsb3BtZW50IG9mIHRoZSBzdG9ja3Mgc2luY2UgMjAxOSBhbmQgdGh1cyB3ZXJlIGtlcHQgZm9yIHRoZSBmb2xsb3dpbmcgY2FsY3VsYXRpb25zLg0KDQpgYGB7ciBGcGEgdGFibGUgdXBkYXRlIHdpdGggMTB5ZWFyIGF2ZyB2YWx1ZXN9DQoNCmthYmxlKGRhdGEuZnJhbWUocmVmUHRzM1ssIkZsaW0iXSxyZWZQdHMzWywiRnBhIl0pLCBjb2wubmFtZXMgPWMoIkZsaW0iLCAiRnBhIikpDQogICAgICANCg0KYGBgDQoNCg0KYGBge3IgRnBhIHBsb3RzIHVwZGF0ZWQgd2l0aCAxMHlyIGF2ZywgZmlnLmNhcD0iUGxvdHMgb2Ygc3RvY2sgZHluYW1pY3MgdW5kZXIgc2ltdWxhdGlvbiBhcyBzcGVjaWZpZWQgZm9yIGVzdGltYXRpb24gb2YgRmxpbS4ifQ0KZXFzaW1fcGxvdChTSU1fU2VncmVnQmxpbV9sb3dlclJob2hpZ2hlcm51bUF2Z1lycywgY2F0Y2g9VFJVRSkNCmBgYA0KDQpIb3dldmVyLCB3aGlsZSBGbGltIG1heSBzdGlsbCBiZSBkZXJpdmVkIGZyb20gQmxpbSAoYW5kIHVzZWQgdG8gYXNzZXNzIHRoZSBGIHRoYXQgZHJpdmVzIHRoZSBzdG9jayB0byBCbGltLCBiYXNlZCBvbiB0aGUgZXF1aWxpYnJpdW0gY3VydmUgb2Ygc3RvY2spLCBpdCBpcyBubyBsb25nZXIgdXNlZCBieSBJQ0VTIGFzIGJhc2lzIG9mIHByZWNhdXRpb25hcnkgYXBwcm9hY2ggKFBBKSBhbmQgTVNZIHJlZmVyZW5jZSBwb2ludHMgdG8gYXNzZXNzIHRoZSBzdGF0ZSBvZiBzdG9ja3MgYW5kIGV4cGxvaXRhdGlvbiwgYW5kIHRvIHByb3ZpZGUgYWR2aWNlIG9uIGZpc2hpbmcgb3Bwb3J0dW5pdGllcyBXS05FV1JFRjQsIElDRVMgMjAyNGQpLiBJdCBpcyB0aGVyZWZvcmUgb25seSB1c2VkIGZvciBpbmZvcm1hdGlvbiwgYnV0IG5vdCByZWNvZ25pemVkIGFzIHJlZmVyZW5jZSBwb2ludCBmb3IgdGhlIGFzc2Vzc21lbnQgYW5kIGFkdmljZSBhbmQgbm90IGluY2x1ZGVkIGluIHRoZSBmaW5hbCByZWZlcmVuY2UgcG9pbnQgbGlzdC4NCg0KDQojIyBjYWxjdWxhdGUgJEZfe01TWX0kICh1bmNvbnN0cmFpbmVkKQ0KVW5saWtlIHRoZSBzaW11bGF0aW9ucyB1c2VkIHRvIGVzdGltYXRlIEZsaW0sIHRoZSB1bmNvbnN0cmFpbmVkIEZNU1kgc2hvdWxkIGluaXRpYWxseSBiZSBjYWxjdWxhdGVkIGJhc2VkIG9uIGEgY29uc3RhbnQgRiBldmFsdWF0aW9uIHdpdGggdGhlIGluY2x1c2lvbiBvZiBzdG9jaGFzdGljaXR5IGluIHBvcHVsYXRpb24gYW5kIGV4cGxvaXRhdGlvbiBhcyB3ZWxsIGFzIGFzc2Vzc21lbnQvYWR2aWNlIGVycm9yLiBBcHByb3ByaWF0ZSBTUlJzIHNob3VsZCBiZSBzcGVjaWZpZWQuDQoNCkFsc28gaGVyZSwgdmFsdWUgd2FzIHJlY2FsY3VsYXRlZCB1c2luZyB0aGUgMTAgeWVhciBhdmcgaW5zdGVhZCBvZiA1IHllYXJzDQoNCmBgYHtyIHJlY2FsY3VsYXRlIEZtc3kgd2l0aCAxMHllYXIgYXZnIHZhbHVlcywgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgcmVzdWx0cz0naGlkZScsIGZpZy5zaG93PSdoaWRlJ30NCg0Kc2V0LnNlZWQoMTIzKQ0KU0lNX1NlZ3JlZ19ub1RyaWdfbG93ZXJSaG9oaWdoZXJudW1BdmdZcnMgPC0gZXFzaW1fcnVuKGVxZml0LCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBiaW8ueWVhcnMgPSBjKG1heFllYXItbnVtQXZnWXJzQiwgbWF4WWVhciksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgYmlvLmNvbnN0ID0gRkFMU0UsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsLnllYXJzID0gYyhtYXhZZWFyLW51bUF2Z1lyc1MsIG1heFllYXIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbC5jb25zdCA9IEZBTFNFLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZjdj1jdkYsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZwaGk9cGhpRiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBTU0Jjdj1jdlNTQiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICByaG9sb2dSZWM9YygwLjYpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGtlZXAuc2ltcyA9IFRSVUUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgQnRyaWdnZXIgPSAwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIEJsaW09cmVmUHRzM1ssIkJsaW0iXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBCcGE9cmVmUHRzM1ssIkJwYSJdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIE5ydW49TnJ1bnMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgRnNjYW4gPSBGc1RvU2NhbiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2ZXJib3NlPVQpDQoNCnRtcDIgPC0gdChTSU1fU2VncmVnX25vVHJpZ19sb3dlclJob2hpZ2hlcm51bUF2Z1lycyRSZWZzKQ0KRm1zeV90bXAgPC0gdG1wMlsibWVkaWFuTVNZIiwiY2F0RiJdICNub3RlOiAgd2FzIHByZXZpb3VzbHkgbGFuZGluZ3MgRiBmb3IgRm1zeSwgZnJvbSB0aGUgd3Jvbmcgb3V0cHV0IChyZWZzMiBvdXRwdXQgdGFibGVzKQ0KDQp0bXBGcGEgPC0gcmVmUHRzM1ssIkZwYSJdIDwtIHJlZlB0czNbLCJGcDA1Il0gPC0gdG1wMlsiRjA1IiwiY2F0RiJdDQoNCg0KcmVmUHRzM1ssIkZtc3lfdW5jb25zdHIiXSA8LSBGbXN5X3RtcCANCmlmIChGbXN5X3RtcCA+IHJlZlB0czNbLCJGcGEiXSkgew0KICByZWZQdHMzWywiRm1zeSJdIDwtIHJlZlB0czNbLCJGcGEiXSAjUEpXOiBtYWtlIHN1cmUgdGhpcyBpcyBGcDA1DQp9IGVsc2Ugew0KcmVmUHRzM1ssIkZtc3kiXSA8LSBGbXN5X3RtcA0KfQ0KDQoNCmBgYA0KVGhlIHJlc3VsdGluZyB1bmNvbnN0cmFpbmVkIEZNU1kgaXMgYWJvdXRgciByZWZQdHMzWywgIkZtc3lfdW5jb25zdHIiXWAuIFRoZSB1bmNvbnN0cmFpbmVkIHZhbHVlIGlzIHVzZWQgYXMgYmFzaXMgZm9yIHRoZSBuZXh0IHN0ZXBzIGluIHRoZSByZWZlcmVuY2UgcG9pbnQgY2FsY3VsYXRpb25zLg0KDQoNCmBgYHtyIEZNU1kgcGxvdHMgdXBkYXRlZCB3aXRoIDEweXIgYXZnLCBmaWcuY2FwPSJQbG90cyBvZiBzdG9jayBkeW5hbWljcyB1bmRlciBzaW11bGF0aW9uIGFzIHNwZWNpZmllZCBmb3IgZXN0aW1hdGlvbiBvZiBGTVNZLiJ9DQplcXNpbV9wbG90KFNJTV9TZWdyZWdfbm9UcmlnX2xvd2VyUmhvaGlnaGVybnVtQXZnWXJzLCBjYXRjaD1UUlVFKQ0KYGBgDQoNCg0KIyMgJE1TWV97QiB0cmlnZ2VyfSQNCk1TWSBCIHRyaWdnZXIgaXMgYSBsb3dlciBib3VuZCBvZiB0aGUgU1NCIGRpc3RyaWJ1dGlvbiB3aGVuIHRoZSBzdG9jayBpcyBmaXNoZWQgYXQgRiBNU1kgKElDRVMsIDIwMjEpLiANCkFzIHN0YXRlZCBpbiB0aGUgSUNFUyB0ZWNobmljYWwgZ3VpZGVsaW5lcywgcmVjZW50IGZpc2hpbmcgbW9ydGFsaXR5IGVzdGltYXRlcyBuZWVkIHRvIGJlIGNvbnNpZGVyZWQgdG8gc2V0IE1TWSBCIHRyaWdnZXIgYXMgZm9yIG1vc3Qgc3RvY2tzIHRoYXQgbGFjayBkYXRhIG9uIGZpc2hpbmcgYXQgRiBNU1ksIE1TWSBCIHRyaWdnZXIgaXMgc2V0IGF0IEJwYS4gSGVyZSwgdGhlIHN0b2NrIGhhcyBiZWVuIGZpc2hlZCBiZWxvdyBGIE1TWSAoYHIgcmVmUHRzM1ssICJGbXN5Il1gKSBmb3IgdGhlIGxhc3QgNSB5ZWFycy4gTmV4dCBzdGVwIGlzIHRvIGxvb2sgaWYgdGhlIDV0aCBwZXJjZW50aWxlIG9mIEIgTVNZID4gQnBhLiAgDQoNCmBgYHtyIGNhbGN1bGF0ZSA1dGhQZXJjIFNTQk1TWSBmcm9tIFNJTV9TZWdyZWdfbm9UcmlnX2xvd2VyUmhvaGlnaGVybnVtQXZnWXJzfQ0KZGF0YS4wNTwtU0lNX1NlZ3JlZ19ub1RyaWdfbG93ZXJSaG9oaWdoZXJudW1BdmdZcnMkcmJwDQp4LjA1IDwtIGRhdGEuMDVbZGF0YS4wNSR2YXJpYWJsZSA9PSAiU3Bhd25pbmcgc3RvY2sgYmlvbWFzcyIsIF0kRnRhcmdldA0KYi4wNSA8LSBkYXRhLjA1W2RhdGEuMDUkdmFyaWFibGUgPT0gIlNwYXduaW5nIHN0b2NrIGJpb21hc3MiLCBdJHAwNQ0KIyBwbG90KGIuMDV+eC4wNSwgeWxhYj0iU1NCIiwgeGxhYj0iRiIpDQpiLmxtIDwtIGxvZXNzKGIuMDUgfiB4LjA1KQ0KcmVmUHRzM1ssIjV0aFBlcmNfU1NCbXN5Il0gPC0gcHJlZGljdChiLmxtLCByZWZQdHMzWywiRm1zeSJdKQ0KDQpgYGANCg0KYGBge3IgY2FsY3VsYXRlIEJ0cmlnZ2VyLCBldmFsID0gRkFMU0UsIGVjaG8gPSBGQUxTRX0NCg0KIyBjaGVjayBpZiBGPEZtc3kgbGFzdCA1IHllYXJzDQppZiAoc3VtKGFzLm51bWVyaWMoZmJhcihzdGspWyxhYygobWF4WWVhci00KTptYXhZZWFyKV0pPD1yZWZQdHMzWywiRm1zeSJdKTwzKSB7DQogIHJlZlB0czNbLCJCdHJpZ2dlciJdICA8LSByZWZQdHMzWywiQnBhIl0gIA0KfSBlbHNlIHsNCiAgIyBDaGVjayBpZiBCbXN5XzA1PkJwYQ0KICByZWZQdHMzWywiQnRyaWdnZXIiXSA8LWlmZWxzZShyZWZQdHMzWywiNXRoUGVyY19TU0Jtc3kiXT5yZWZQdHMzWywiQnBhIl0scmVmUHRzM1ssIjV0aFBlcmNfU1NCbXN5Il0scmVmUHRzM1ssIkJwYSJdKQ0KICAjIENoZWNrIGlmIEJtc3lfMDUgPiBTU0JjdXJfMDUNCiAgcmVmUHRzM1ssIkJ0cmlnZ2VyIl0gPC1pZmVsc2UocmVmUHRzM1ssIjV0aFBlcmNfU1NCbXN5Il0gPiBTU0IwNSxtYXgocmVmUHRzM1ssIkJwYSJdLFNTQjA1KSxyZWZQdHMzWywiNXRoUGVyY19TU0Jtc3kiXSkgIA0KfQ0KDQoNCmBgYA0KDQpUaGUgZ3JvdXAgYWdyZWVkIHRvIHVzZSBhIHNpbXBsZSB2ZXJzaW9uIHRvIHNldCBCIHRyaWdnZXIgYXMgQnBhDQoNCmBgYHtyIHNpbXBsZSBCIHRyaWdnZXIgdmVyc2lvbn0NCg0KIyMjIHNpbXBsaWZpZWQgc29sdXRpb24gYWZ0ZXIgd2ViIG1lZXRpbmcgd2l0aCBDb2xpbiAoc21vb3RoaW5nIGZ1bmN0aW9uIGlzIGNyZWF0aW5nIGEgd2VpcmQgQiB0cmlnZ2VyKQ0KDQpyZWZQdHMzWywiQnRyaWdnZXIiXSA8LSByZWZQdHNbLCJCcGEiXQ0KDQpgYGANCg0KDQpgYGB7ciBwbG90IHNzYl9QMDUgYXQgRiwgZmlnLmNhcD0iU1NCIGF0IEYgd2l0aCBQMDUgb2YgZ29pbmcgYmVsb3cgQnBhIChsaW5lIGlzIGEgbG9lc3Mgc21vb3RoZXIgdXNlZCB0byBlc3RpbWF0ZSB0aGUgU1NCIHdpdGggNSUgcmlzayBvZiBCcGEgYXQgRm1zeSkuIiwgZXZhbCA9IEZBTFNFfQ0KDQojIFRoaXMgcGxvdCBpcyBvbmx5IG5lZWRlZCBpZiB5b3UgYXJlIGdvaW5nIHRvIHVzZSA1dGggcGVyY2VudGlsZSBkZWZpbml0aW9uLCBhbmQgYWNjb3JkaW5nIHRvIHRoZSBhYm92ZSB0aGlzIHN0b2NrIGRvZXNuJ3QgcXVhbGlmeSBhbnl3YXksIGV2ZW4gaWYgd2UgdGhvdWdodCBpdCB3YXMgYSBnb29vZCBpZGVhIHRvIHVzZSBpdC4gSSBhZGRlZCBldmFsID0gRkFMU0UgdG8gdGhlIGNodW5rIGNvZGUuIFNpZGUgbm90ZSAtIEkgdGhpbmsgdGhlIGxvZXNzIHNtb290aGVyIG5lZWRzIG1vcmUgbm9kZXMgb3Igc29tZXRoaW5nIGJlY2F1c2UgaXQgZG9lc24ndCBsb29rIGxpa2UgaXRzIGZpdHRpbmcgYW55d2F5Lg0KDQpnZ3Bsb3RseShnZ3Bsb3QoZGF0YSA9IE5VTEwsDQogICAgICAgICAgICAgICAgICAgICAgbWFwcGluZyA9IGFlcyh4ID0geC4wNSwgeSA9IGIuMDUpKSsNCiAgICAgICAgICAgZ2VvbV9wb2ludChzaGFwZSA9IDIxKSsNCiAgICAgICAgICAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxvZXNzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgc2UgPSBGLA0KICAgICAgICAgICAgICAgICAgICAgICBjb2xvdXIgPSBlYnBhbFsxXSkgKw0KICAgICAgICAgICB5bGFiKCJTU0IgKHRvbm5lcykgd2l0aCBGIHRoYXQgZ2l2ZXNcbjUlIGNoYW5jZSBvZiBnb2luZyBiZWxvdyBCcGEiKSsNCiAgICAgICAgICAgeGxhYigiRmlzaGluZyBwcmVzc3VyZSAoRikiKSArDQogICAgICAgICAgIHRoZW1lX2NsZWFuKCkNCiAgICAgICAgICAgKQ0KYGBgDQoNCg0KSW4gdGhpcyBjYXNlIHRoZSA1dGggcGVyY2VudGlsZSBvZiBCIE1TWSBpcyBub3QgZ3JlYXRlciB0aGFuIEJwYS4gIFRoZXJlZm9yZSBmb2xsb3dpbmcgdGhlIElDRVMgdGVjaG5pY2FsIGd1aWRlbGluZXMgdGhlIE1TWSBCIHRyaWdnZXIgIHdpbGwgYmUgZXF1YWwgdG8gQnBhICwgTVNZIEIgdHJpZ2dlciAgPSBgciByZWZQdHMzWywgIkJ0cmlnZ2VyIl1gIHRvbm5lcy5NU1kgQnRyaWdnZXIgc2hvdWxkIGJlIHNlbGVjdGVkIHRvIHNhZmVndWFyZCBhZ2FpbnN0IGFuIHVuZGVzaXJhYmxlIG9yIHVuZXhwZWN0ZWQgbG93IFNTQiB3aGVuIGZpc2hpbmcgYXQgRk1TWS4NCg0KDQpgYGB7ciBpbnRlcm1lZGlhdGUgYnRyaWdnZXIgdGFibGV9DQpyZXF1aXJlKGthYmxlRXh0cmEpICNQSlc6IEFkZGVkIHRoaXMNCg0KZHQgPC0gcmVmUHRzM1ssIGMoMSwyLDQpXQ0KDQpkdCAlPiUNCiAga2JsKGJvb2t0YWJzID0gVFJVRSwgY2FwdGlvbj0iQnRyaWdnZXIgYW5kIEJwYSByZWZlcmVuY2UgcG9pbnRzIGZvciBwbGUuMjcuMjEtMzIiKSAlPiUNCiAga2FibGVfbWF0ZXJpYWxfZGFyaygpDQoNCmBgYA0KDQojIyBmaW5hbCAkRl97TVNZfSQgDQpUaGUgSUNFUyBNU1kgQWR2aWNlIFJ1bGUgc2hvdWxkIGJlIGV2YWx1YXRlZCB0byBjaGVjayB0aGF0IHRoZSBGTVNZIGFuZCBNU1kgQnRyaWdnZXIgY29tYmluYXRpb24gYWRoZXJlcyB0byBwcmVjYXV0aW9uYXJ5IGNvbnNpZGVyYXRpb25zOiANCiogaW4gdGhlIGxvbmcgdGVybSwgUChTU0I8QmxpbSk8NSUNClRoZSBldmFsdWF0aW9uIG11c3QgaW5jbHVkZToNCiogcmVhbGlzdGljIGFzc2Vzc21lbnQgKGFkdmljZSkgZXJyb3INCiogc3RvY2hhc3RpY2l0eSBpbiBwb3B1bGF0aW9uIGJpb2xvZ3kgYW5kIGZpc2hlcnkgZXhwbG9pdGF0aW9uLg0KKiBBcHByb3ByaWF0ZSBTUlJzIHNob3VsZCBiZSBzcGVjaWZpZWQgKGhlcmUgdXNpbmcgc2VncmVnYXRpb24gbW9kZWwgd2l0aCBmaXhlZCBicmVha3BvaW50KQ0KDQpgYGB7ciBmaW5hbCBGbXN5IGFuZCB0YWJsZSB1cGRhdGVzLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCByZXN1bHRzPSdoaWRlJywgZmlnLnNob3c9J2hpZGUnfQ0Kc2V0LnNlZWQoMTIzKQ0KU0lNX1NlZ3JlZ19UcmlnX2xvd2VyUmhvaGlnaGVybnVtQXZnWXJzIDwtIGVxc2ltX3J1bihlcWZpdCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgYmlvLnllYXJzID0gYyhtYXhZZWFyLW51bUF2Z1lyc0IsIG1heFllYXIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBiaW8uY29uc3QgPSBGQUxTRSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsLnllYXJzID0gYyhtYXhZZWFyLW51bUF2Z1lyc1MsIG1heFllYXIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBzZWwuY29uc3QgPSBGQUxTRSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgRmN2PWN2RiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgRnBoaT1waGlGLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBTU0Jjdj1jdlNTQiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgcmhvbG9nUmVjPWMoMC42KSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAga2VlcC5zaW1zID0gVFJVRSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgQnRyaWdnZXIgPSByZWZQdHMzWywiQnRyaWdnZXIiXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgQmxpbT1yZWZQdHMzWywiQmxpbSJdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBCcGE9cmVmUHRzM1ssIkJwYSJdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBOcnVuPU5ydW5zLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBGc2NhbiA9IEZzVG9TY2FuLA0KICAgICAgICAgICAgICAgICAgICAgICAgICB2ZXJib3NlPVRSVUUpDQp0bXAzIDwtIHQoU0lNX1NlZ3JlZ19UcmlnX2xvd2VyUmhvaGlnaGVybnVtQXZnWXJzJFJlZnMpDQpyZWZQdHMzWywiRnAwNSJdIDwtIHJlZlB0czNbLCJGcGEiXSA8LSB0bXAzWyJGMDUiLCJjYXRGIl0gI25vdGU6IGNhdGNoIEYgZm9yIEZwMDUNCg0KDQpyZWZQdHMzWywiRm1zeV91bmNvbnN0ciJdIDwtIEZtc3lfdG1wIA0KaWYgKEZtc3lfdG1wID4gcmVmUHRzM1ssIkZwYSJdKSB7DQogIHJlZlB0czNbLCJGbXN5Il0gPC0gcmVmUHRzM1ssIkZwYSJdDQp9IGVsc2Ugew0KcmVmUHRzM1ssIkZtc3kiXSA8LSBGbXN5X3RtcA0KfQ0KI1RoaXMgc2hvd3MgdGhhdCB0aGUgbWlzbWF0Y2ggYmV0d2VlbiB0aGUgcmVjcnVpdG1lbnQgc2VyaWVzIHdlIHJldGFpbmVkIChiZWZvcmUgMjAxOSkgYW5kIHRoZSBiaW9sb2dpY2FsIHZhcmlhYmxlcyB3ZSByZXNhbXBsZWQgKGxhc3QgNSB5ZWFycyksIGFsc28gY2F1c2VkIHNvbWUgY29uZnVzaW9uLiBJIHRoaW5rIGl0IGlzIGJlc3QgdG8gY29udGludWUgd2l0aCB0aGlzIHZlcnNpb24gYWJvdmUgLSBsb29rIGZvciBhIHJlYXNvbmFibGUgcmhvIHZhbHVlIChpbiB0aGUgcmFuZ2UgMC4zIC0gMC42IEkgdGhpbmspLCBhbmQga2VlcCB0aGUgbGFzdCAxMCB5ZWFycyBmb3Igc2FtcGxpbmcuDQoNCmBgYA0KDQpgYGB7ciBhZGQgdXBwZXIgYW5kIGxvd2VyIE1TWSB2YWx1ZSBmb3IgQ2F0RiBGMDV9DQoNCnNpbSA8LSBTSU1fU2VncmVnX1RyaWdfbG93ZXJSaG9oaWdoZXJudW1BdmdZcnMNCiMgc2ltIDwtIFNJTV9TZWdyZWdfbm9UcmlnX2xvd2VyUmhvaGlnaGVybnVtQXZnWXJzICMgdGhpcyBvbmUgZm9yIHVuY29uc3RyYWluZWQgRk1TWSB1cHBlciBhbmQgbG93ZXINCiBpbnRlcnZhbCA9IDAuOTUNCiBkYXRhLjk1IDwtIHNpbSRyYnANCiAgICB4Ljk1IDwtIGRhdGEuOTVbZGF0YS45NSR2YXJpYWJsZSA9PSAiQ2F0Y2giLF0kRnRhcmdldA0KICAgIHkuOTUgPC0gZGF0YS45NVtkYXRhLjk1JHZhcmlhYmxlID09ICJDYXRjaCIsXSRNZWFuDQoNCiAgICB5aWVsZC5wOTUgPC0gaW50ZXJ2YWwgKiBtYXgoeS45NSwgbmEucm0gPSBUUlVFKQ0KICAgDQogICAgIyBGaXQgbG9lc3Mgc21vb3RoZXIgdG8gY3VydmUNCiAgICB4LmxtIDwtIHN0YXRzOjpsb2Vzcyh5Ljk1IH4geC45NSwgc3BhbiA9IDAuMikNCiAgICBsbS5wcmVkIDwtIGRhdGEuZnJhbWUoeCA9IHNlcShtaW4oeC45NSksIG1heCh4Ljk1KSwgbGVuZ3RoID0gMTAwMCksDQogICAgICAgICAgICAgICAgICAgICAgICAgIHkgPSByZXAoTkEsIDEwMDApKQ0KICAgIGxtLnByZWQkeSA8LSBzdGF0czo6cHJlZGljdCh4LmxtLCBuZXdkYXRhID0gbG0ucHJlZCR4KQ0KICANCiAgICAjIExpbWl0IGZpdHRlZCBjdXJ2ZSB0byB2YWx1ZXMgZ3JlYXRlciB0aGFuIHRoZSA5NSUgY3V0b2ZmDQogICAgbG0ucHJlZC45NSA8LSBsbS5wcmVkW2xtLnByZWQkeSA+PSB5aWVsZC5wOTUsXQ0KICAgIGZtc3kubG93ZXIgPC0gbWluKGxtLnByZWQuOTUkeCkNCiAgICBmbXN5LnVwcGVyIDwtIG1heChsbS5wcmVkLjk1JHgpDQogICAgDQogICAgZm1zeS5sb3dlci5tZWFuIDwtIGZtc3kubG93ZXINCiAgICBmbXN5LnVwcGVyLm1lYW4gPC0gZm1zeS51cHBlcg0KICAgIGNhdGNoLmxvd2VyLm1lYW4gPC0gbG0ucHJlZC45NVtsbS5wcmVkLjk1JHggPT0gZm1zeS5sb3dlci5tZWFuLF0keQ0KICAgIGNhdGNoLnVwcGVyLm1lYW4gPC0gbG0ucHJlZC45NVtsbS5wcmVkLjk1JHggPT0gZm1zeS51cHBlci5tZWFuLF0keQ0KDQogICAgIyBSZXBlYXQgZm9yIDk1JSBvZiB5aWVsZCBhdCBGKDA1KToNCiAgICBmMDUgPC0gc2ltJFJlZnNbImNhdEYiLCJGMDUiXQ0KICAgIHlpZWxkLmYwNSA8LSBzdGF0czo6cHJlZGljdCh4LmxtLCBuZXdkYXRhID0gZjA1KQ0KICAgIHlpZWxkLmYwNS45NSA8LSBpbnRlcnZhbCAqIHlpZWxkLmYwNSAgDQogICAgbG0ucHJlZC5mMDUuOTUgPC0gbG0ucHJlZFtsbS5wcmVkJHkgPj0geWllbGQuZjA1Ljk1LF0NCiAgICBmMDUubG93ZXIgPC0gbWluKGxtLnByZWQuZjA1Ljk1JHgpDQogICAgZjA1LnVwcGVyIDwtIG1heChsbS5wcmVkLmYwNS45NSR4KQ0KDQogICMgYWRkIHVwcGVyIGFuZCBsb3dlciBlc3RpbWF0ZXMgdG8gUmVmMiB0YWJsZQ0KICBTSU1fU2VncmVnX1RyaWdfbG93ZXJSaG9oaWdoZXJudW1BdmdZcnMkUmVmczJbImNhdEYiLCJNZWFubG93ZXIiXSA8LSBmMDUubG93ZXINCiAgU0lNX1NlZ3JlZ19UcmlnX2xvd2VyUmhvaGlnaGVybnVtQXZnWXJzJFJlZnMyWyJjYXRGIiwiTWVhbnVwcGVyIl0gPC0gZjA1LnVwcGVyDQoNCmBgYA0KDQpUbyBlbnN1cmUgY29uc2lzdGVuY3kgYmV0d2VlbiB0aGUgcHJlY2F1dGlvbmFyeSBhbmQgdGhlIE1TWSBmcmFtZXdvcmtzLCBGTVNZIGlzIG5vdCBhbGxvd2VkIHRvIGJlIGFib3ZlIEZwMDU7IHRoZXJlZm9yZSwgaWYgdGhlIGluaXRpYWwgRk1TWSB2YWx1ZSBpcyBhYm92ZSBGcDA1LCBGTVNZIGlzIHJlZHVjZWQgdG8gRnAwNS4gRnAwNSB3YXMgY2FsY3VsYXRlZCBieSBydW5uaW5nIEVxU2ltIHdpdGggYXNzZXNzbWVudC9hZHZpY2UgZXJyb3IsIHdpdGggYWR2aWNlIHJ1bGUsIGFuZCB3aXRoIGEgc2VnbWVudGVkIHJlZ3Jlc3Npb24gd2l0aCBicmVha2luZyBwb2ludCBmaXhlZCBhdCBCcGEgdG8gZW5zdXJlIHRoYXQgdGhlIGxvbmctdGVybSByaXNrIG9mIFNTQiA8IEJsaW0gb2YgYW55IEYgdXNlZCBkb2VzIG5vdCBleGNlZWQgNSUgd2hlbiBhcHBseWluZyB0aGUgYWR2aWNlIHJ1bGUuIEZwMDUgd2FzIGVzdGltYXRlZCB0byBiZSBgciByZWZQdHMzWywgIkZtc3kiXWAgKEYwNSBmb3IgY2F0RikuIFRoZXJlZm9yZSwgYXMgZXhwbGFpbmVkIGFib3ZlLCBgciByZWZQdHMzWywgIkZtc3kiXWAuIFRoZSB1cHBlciBhbmQgbG93ZXIgcmFuZ2VzIGFyZSBnaXZlbiBpbiB0aGUgZm9sbG93aW5nIHRhYmxlLiANCg0KDQpgYGB7ciBmaW5hbCBmbXN5IHRhYmxlIHVwZGF0ZX0NCg0KZHQyIDwtIHJlZlB0czNbLCBjKDcsOSldDQoNCmR0MiRGbXN5X2xvd2VyIDwtICBTSU1fU2VncmVnX1RyaWdfbG93ZXJSaG9oaWdoZXJudW1BdmdZcnMkUmVmczJbImNhdEYiLCJNZWFubG93ZXIiXSANCmR0MiRGbXN5X3VwcGVyIDwtICBTSU1fU2VncmVnX1RyaWdfbG93ZXJSaG9oaWdoZXJudW1BdmdZcnMkUmVmczJbImNhdEYiLCJNZWFudXBwZXIiXQ0KZHQyIDwtdChkdDIpDQoNCmR0MiAlPiUNCiAga2JsKGJvb2t0YWJzID0gVFJVRSwgY2FwdGlvbj0iRnAwNSBhbmQgRm1zeSByZWZlcmVuY2UgcG9pbnRzIGZvciBwbGUuMjcuMjEtMzIiLCBkaWdpdHMgPSA0KSAlPiUNCiAga2FibGVfbWF0ZXJpYWxfZGFyaygpDQoNCg0KDQpgYGANCg0KSW4gY2FzZSBvZiBsaW1pdGF0aW9uIGJ5IEZNU1kgPSBGcGEsIHRoZSB1cHBlciBGTVNZIGxpbWl0IGVxdWFscyB0aGUgKGNhcHBlZCkgRk1TWSBhbmQgdGhlIGxvd2VyIGxpbWl0IGlzIHJlLWNhbGN1bGF0ZWQgdXNpbmcgdGhlIGNhcHBlZCBGTVNZIHZhbHVlIChpbiB0aGlzIGNhc2UsIEZNU1kgPSBgciByZWZQdHNbLCAiRm1zeSJdYCBpbnN0ZWFkIG9mIHVzaW5nIHRoZSB1bmNvbnN0cmFpbmVkIEZNU1kgPSBgciByZWZQdHMzWywgIkZtc3lfdW5jb25zdHIiXWApDQoNCg0KDQojIyBmaW5hbCBncmFwaHMNCg0KV2hhdCBmaW5hbCBncmFwaHMgZG8gd2UgcmVhbGx5IHdhbnQgdG8gc2VlPw0KDQpgYGB7ciBmaW5hbCBncmFwaHMsIGV2YWwgPSBGQUxTRSwgZWNobyA9IEZBTFNFfQ0KIyBkaXNwbGF5IEVxdWlsaWJyaXVtIHBsb3RzDQoNCg0KcmVmcG9pbnRzPC1hcy5kYXRhLmZyYW1lKFNJTV9TZWdyZWdfVHJpZ19sb3dlclJob2hpZ2hlcm51bUF2Z1lycyRSZWZzKQ0KYXJncyhlcXNyX2ZpdCkNCnN0cihlcWZpdCwgMiwgZ2l2ZS5hdHRyPUZBTFNFKQ0KZXFmaXQkc3IuZGV0DQoNCmVxc3JfcGxvdChlcWZpdCxuPTJlNCxnZ1Bsb3Q9VFJVRSxTY2FsZT0xZTMpDQojc3RyKFNJTV9TZWdyZWdfVHJpZywgMixGIGdpdmUuYXR0ciA9IEZBTFNFKQ0KdChTSU1fU2VncmVnX1RyaWdfbG93ZXJSaG9oaWdoZXJudW1BdmdZcnMkcmVmc19pbnRlcnZhbCkNCnQoU0lNX1NlZ3JlZ19ub1RyaWdfbG93ZXJSaG9oaWdoZXJudW1BdmdZcnMkcmVmc19pbnRlcnZhbCkNCnQoU0lNX1NlZ3JlZ19ub1RyaWdfbG93ZXJSaG9oaWdoZXJudW1BdmdZcnMkUmVmcykNCg0KDQpgYGANCg0KYGBge3IsIGV2YWwgPSBGQUxTRSwgZWNobyA9IEZBTFNFfQ0KZXFzaW1fcGxvdChTSU1fU2VncmVnQmxpbV9sb3dlclJob2hpZ2hlcm51bUF2Z1lycywgY2F0Y2g9VFJVRSkNCmBgYA0KDQpgYGB7ciwgZXZhbCA9IEZBTFNFLCBlY2hvID0gRkFMU0V9DQplcXNpbV9wbG90KFNJTV9TZWdyZWdfbm9UcmlnX2xvd2VyUmhvaGlnaGVybnVtQXZnWXJzLCBjYXRjaD1UUlVFKQ0KYGBgDQoNCmBgYHtyLCBldmFsID0gRkFMU0UsIGVjaG8gPSBGQUxTRX0NCmVxc2ltX3Bsb3QoU0lNX1NlZ3JlZ19UcmlnX2xvd2VyUmhvaGlnaGVybnVtQXZnWXJzLCBjYXRjaD1UUlVFKQ0KYGBgDQoNCg0KYGBge3IgZmluYWwgZXFzaW0gcmFuZ2UgcGxvdHN9DQoNCmVxc2ltX3Bsb3RfcmFuZ2UoU0lNX1NlZ3JlZ19ub1RyaWdfbG93ZXJSaG9oaWdoZXJudW1BdmdZcnMsIHR5cGU9Im1lYW4iKQ0KZXFzaW1fcGxvdF9yYW5nZShTSU1fU2VncmVnX25vVHJpZ19sb3dlclJob2hpZ2hlcm51bUF2Z1lycywgdHlwZT0ibWVkaWFuIikNCmVxc2ltX3Bsb3RfcmFuZ2UoU0lNX1NlZ3JlZ19UcmlnX2xvd2VyUmhvaGlnaGVybnVtQXZnWXJzLCB0eXBlPSJzc2IiKQ0KDQpgYGANCg0KDQoNCmBgYHtyIGZpbmFsIGVxc2ltIGZtc3kgcGxvdH0NCg0KZXFzaW1fcGxvdF9yYW5nZShTSU1fU2VncmVnX1RyaWdfbG93ZXJSaG9oaWdoZXJudW1BdmdZcnMsIHR5cGU9Im1lYW4iKQ0KDQpgYGANCg0KDQojIGZpbmFsIHJlZmVyZW5jZSBwb2ludCB0YWJsZQ0KVGhlIGZpbmFsIHJlZmVyZW5jZSBwb2ludHMgYXJlIHJlZmxlY3RpbmcgdGhlIGNoYW5nZXMgb2YgdGhlIHN0b2NrIHNpbmNlIHRoZSBsYXN0IGJlbmNobWFyay4gVGhlIG5ldyB2YWx1ZXMgY2Fubm90IGJlIGNvbXBhcmVkIHdpdGggdGhlIG9sZCByZWZlcmVuY2UgcG9pbnRzIGRpcmVjdGx5LiBOb3Qgb25seSBkaWQgdGhlIHN0b2NrIHVuaXQgY2hhbmdlIGJ5IG1lcmdpbmcgdHdvIHN0b2NrcywgYnV0IGFsc28gdGhlIGJpb2xvZ2ljYWwgcGFyYW1ldGVyIGluIHRoZSBhc3Nlc3NtZW50IGhhdmUgYmVlbiBjaGFuZ2VkIChlLmcuLCBieSB1c2luZyBzbGlkaW5nIHdpbmRvdyBhdmVyYWdlcyBmb3Igd2VpZ2h0LWF0LWFnZSBhbmQgbWF0dXJpdHksIGFzIHdlbGwgYXMgaW5jb3Jwb3JhdGluZyBuZXcgbmF0dXJhbCBtb3J0YWxpdHkgZXN0aW1hdGVzIGFuZCBkaXNjYXJkIHN1cnZpdmFsKS4gQWRkaXRpb25hbGx5LCB0aGUgc3RvY2sgaXMgZGlzcGxheWluZyBhbiBleGNlcHRpb25hbCBpbmNyZWFzZSBpbiBiaW9tYXNzLCB3aGljaCBoYXMgbm90IGJlZW4gcHJlc2VudCBhdCB0aGUgbGFzdCBiZW5jaG1hcmsuIEFzIEZwYSA9IEZwMDUgKElDRVMgMjAyNGQpLCBvbmx5IHRoZSBGcGEgdmFsdWUgaXMgZGlzcGxheWVkIGluIHRoZSB0YWJsZS4gDQoNCg0KYGBge3IgZmluYWwgcmVmcG9pbnQgdGFibGV9DQojUmVmUG9pbnRUYWJsZSA8LSBhcy5kYXRhLmZyYW1lKHQocmVmUHRzMykpDQojUmVmUG9pbnRUYWJsZSRSZWZlcmVuY2VQb2ludCA8LSByb3duYW1lcyhSZWZQb2ludFRhYmxlKQ0KI3Jvd25hbWVzKFJlZlBvaW50VGFibGUpIDwtIE5VTEwNCiNSZWZQb2ludFRhYmxlJFVuaXRzIDwtIGMoInQiLCAidCIsICJ0IiwgInQiLCAiRiIsICJGIiwgIkYiLCAiRiIsICJGIikNCiNSZWZQb2ludFRhYmxlIDwtIFJlZlBvaW50VGFibGVbLCBjKDIsMSwzKV0NCiNSZWZQb2ludFRhYmxlJFJvdW5kZWRWYWx1ZSA8LSBpZmVsc2UoUmVmUG9pbnRUYWJsZSRVbml0cyA9PSAiRiIsDQojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShSZWZQb2ludFRhYmxlJHZhbHVlPDAuMiwgcm91bmQoUmVmUG9pbnRUYWJsZSR2YWx1ZSwgMyksIHJvdW5kKFJlZlBvaW50VGFibGUkdmFsdWUsIDIpKSwNCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcm91bmQoUmVmUG9pbnRUYWJsZSR2YWx1ZSwgMCkpDQpyZWZQdHM0IDwtIHJlZlB0czNbLCBjKDEsMiwzLDQsNSw4LDkpXQ0KDQp0KHJlZlB0czQpICU+JQ0KICAgIGtibChib29rdGFicyA9IFRSVUUsIGNhcHRpb249InJlZmVyZW5jZSBwb2ludHMgZm9yIHBsZS4yNy4yMS0zMiIpICU+JQ0KICAgIGthYmxlX21hdGVyaWFsX2RhcmsoKQ0KDQoNCg0KYGBgDQoNCjxjZW50ZXI+DQoNCiFbXShpbWFnZS9QTEUucG5nKQ0KPC9jZW50ZXI+DQoNCg0KIyBhZGRpdGlvbmFsIHNjZW5hcmlvczogDQojIyBub24tdHJ1bmNhdGVkIFJlY3J1aXRtZW50IHNlcmllcw0KU2Vuc2l0aXZpdHkgcnVuIHVzaW5nIHRoZSBub24tdHJ1bmNhdGVkIHJlY3J1aXQgdGltZSBzZXJpZXMuIEFsbCBvdGhlciBzZXR0aW5ncyBhcmUgaWRlbnRpY2FsIHRvIHRoZSBmaW5hbCBzZXR0aW5ncyBvZiB0aGUgcmVmZXJlbmNlIHBvaW50IGNhbGN1bGF0aW9uIGFib3ZlOg0KLSBCbGltIGFzIGF2ZXJhZ2UgU1NCIG9mIHRoZSBmaXJzdCB0ZW4geWVhcnMgb2YgdGhlIHRpbWUgc2VyaWVzDQotIGxhc3QgMTAgeWVhcnMgb2YgYmlvbG9naWNhbCBkYXRhIHVzZWQgZm9yIFMgYW5kIEIgZXN0aW1hdGlvbiBpbiB0aGUgcmVmZXJlbmNlIHBvaW50IG1vZGVscw0KLSBhdXRvY29ycmVsYXRpb24gb2YgcmVjcnVpdG1lbnQgZml4ZWQgdG8gUmhvTG9nUmVjID0gMC42DQoNCg0KYGBge3Igbm9uIHJlY3J1aXRtZW50IHRydW5jYXRpb24sIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIHJlc3VsdHM9J2hpZGUnLCBmaWcuc2hvdz0naGlkZSd9DQoNCiMgc2V0IHVwIG5ldyBSZWYgdGFibGUgZm9yIHVudHJ1bmNhdGVkIHNlcmllcw0KcmVmUHRzNSA8LSBtYXRyaXgoTkEsbnJvdz0xLG5jb2w9OSwgZGltbmFtZXM9bGlzdCgidmFsdWUiLGMoIkJ0cmlnZ2VyIiwiQnBhIiwiQmxpbSIsIjV0aFBlcmNfU1NCbXN5IiwiRnBhIiwiRmxpbSIsICJGcDA1IiwiRm1zeV91bmNvbnN0ciIsIkZtc3kiKSkpDQoNCiMga2VlcCBCbGltIGFuZCBCcGENCnJlZlB0czVbLCJCbGltIl0gPC0gbWVhbihkZltkZiR5ZWFyICVpbiUgYygyMDAyOjIwMTEpLCAiU1NCIl0pDQpyZWZQdHM1WywiQnBhIl0gIDwtcmVmUHRzWywiQmxpbSJdKmV4cCgxLjY0NSpzaWdtYVNTQikNCg0KIyBubyB0cnVuY2F0aW9uDQpybVNSUllycyA8LSAwDQoNClNlZ3JlZ0JsaW0gIDwtIGZ1bmN0aW9uKGFiLCBzc2IpIGxvZyhpZmVsc2Uoc3NiID49IHJlZlB0c1ssIkJsaW0iXSwgYWIkYSAqIHJlZlB0c1ssIkJsaW0iXSwgYWIkYSAqIHNzYikpDQoNCiMjIFJlZml0IHN0b2NrIHJlY3J1aXRtZW50IHJlbGF0aW9uc2hpcCBiYXNlZCBvbiB0cnVuY2F0ZWQgdGltZSBzZXJpZXMNCnNldC5zZWVkKDEyMykNCmVxZml0IDwtIGVxc3JfZml0KHN0ayA9IHN0aywNCiAgICAgICAgICAgICAgICAgIG5zYW1wID0gbm9TaW1zLA0KICAgICAgICAgICAgICAgICAgbW9kZWxzID0gYygiU2VncmVnQmxpbSIpLA0KICAgICAgICAgICAgICAgICAgcmVtb3ZlLnllYXJzID0gcm1TUlJZcnMpDQojIyBQbG90DQplcXNyX3Bsb3QoZXFmaXQsbj0yZTQsZ2dQbG90PVRSVUUsU2NhbGU9MWUzKQ0KDQoNCnNldC5zZWVkKDEyMykNClNJTV9TZWdyZWdCbGltX2xvd2VyUmhvaGlnaGVybnVtQXZnWXJzIDwtIGVxc2ltX3J1bihlcWZpdCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJpby55ZWFycyA9IGMoKG1heFllYXItbnVtQXZnWXJzQiksIG1heFllYXIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiaW8uY29uc3QgPSBUUlVFLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWwueWVhcnMgPSBjKChtYXhZZWFyLW51bUF2Z1lyc1MpLCBtYXhZZWFyKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsLmNvbnN0ID0gVFJVRSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRmN2ID0gMCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRnBoaSA9IDAsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIFNTQmN2ID0gMCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmhvbG9nUmVjID0gYygwLjYpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBCdHJpZ2dlciA9IDAsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIEJsaW0gPSByZWZQdHM1WywiQmxpbSJdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBCcGEgPSByZWZQdHM1WywiQnBhIl0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIE5ydW4gPSBOcnVucywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRnNjYW4gPSBGc1RvU2NhbiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmVyYm9zZT1UKQ0KDQp0bXAxIDwtIHQoU0lNX1NlZ3JlZ0JsaW1fbG93ZXJSaG9oaWdoZXJudW1BdmdZcnMkUmVmcykNCg0KcmVmUHRzNVssIkZsaW0iXSA8LSB0bXAxWyJGNTAiLCJjYXRGIl0NCg0KdG1wRnBhIDwtIHJlZlB0czVbLCJGcGEiXSA8LSByZWZQdHM1WywiRnAwNSJdIDwtIHRtcDFbIkYwNSIsImNhdEYiXQ0KDQppZiAodG1wRnBhPDAuMikgcmVmUHRzNVssIkZwYSJdIDwtIHJvdW5kKHRtcEZwYSwgMykgZWxzZSByZWZQdHM1WywiRnBhIl0gPC0gcm91bmQodG1wRnBhLCAyKQ0KDQpzZXQuc2VlZCgxMjMpDQpTSU1fU2VncmVnX25vVHJpZ19sb3dlclJob2hpZ2hlcm51bUF2Z1lycyA8LSBlcXNpbV9ydW4oZXFmaXQsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJpby55ZWFycyA9IGMobWF4WWVhci1udW1BdmdZcnNCLCBtYXhZZWFyKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBiaW8uY29uc3QgPSBGQUxTRSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWwueWVhcnMgPSBjKG1heFllYXItbnVtQXZnWXJzUywgbWF4WWVhciksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsLmNvbnN0ID0gRkFMU0UsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgRmN2PWN2RiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgRnBoaT1waGlGLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIFNTQmN2PWN2U1NCLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJob2xvZ1JlYz1jKDAuNiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAga2VlcC5zaW1zID0gVFJVRSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBCdHJpZ2dlciA9IDAsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgQmxpbT1yZWZQdHM1WywiQmxpbSJdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIEJwYT1yZWZQdHM1WywiQnBhIl0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgTnJ1bj1OcnVucywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBGc2NhbiA9IEZzVG9TY2FuLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZlcmJvc2U9VCkNCg0KdG1wMiA8LSB0KFNJTV9TZWdyZWdfbm9UcmlnX2xvd2VyUmhvaGlnaGVybnVtQXZnWXJzJFJlZnMpDQpGbXN5X3RtcCA8LSB0bXAyWyJtZWRpYW5NU1kiLCJjYXRGIl0gI25vdGU6ICB3YXMgcHJldmlvdXNseSBsYW5kaW5ncyBGIGZvciBGbXN5LCBmcm9tIHRoZSB3cm9uZyBvdXRwdXQgKHJlZnMyIG91dHB1dCB0YWJsZXMpDQoNCnRtcEZwYSA8LSByZWZQdHM1WywiRnBhIl0gPC0gcmVmUHRzNVssIkZwMDUiXSA8LSB0bXAyWyJGMDUiLCJjYXRGIl0NCg0KDQpyZWZQdHM1WywiRm1zeV91bmNvbnN0ciJdIDwtIEZtc3lfdG1wIA0KaWYgKEZtc3lfdG1wID4gcmVmUHRzNVssIkZwYSJdKSB7DQogIHJlZlB0czVbLCJGbXN5Il0gPC0gcmVmUHRzNVssIkZwYSJdICNQSlc6IG1ha2Ugc3VyZSB0aGlzIGlzIEZwMDUNCn0gZWxzZSB7DQpyZWZQdHM1WywiRm1zeSJdIDwtIEZtc3lfdG1wDQp9DQoNCg0KZGF0YS4wNTwtU0lNX1NlZ3JlZ19ub1RyaWdfbG93ZXJSaG9oaWdoZXJudW1BdmdZcnMkcmJwDQp4LjA1IDwtIGRhdGEuMDVbZGF0YS4wNSR2YXJpYWJsZSA9PSAiU3Bhd25pbmcgc3RvY2sgYmlvbWFzcyIsIF0kRnRhcmdldA0KYi4wNSA8LSBkYXRhLjA1W2RhdGEuMDUkdmFyaWFibGUgPT0gIlNwYXduaW5nIHN0b2NrIGJpb21hc3MiLCBdJHAwNQ0KIyBwbG90KGIuMDV+eC4wNSwgeWxhYj0iU1NCIiwgeGxhYj0iRiIpDQpiLmxtIDwtIGxvZXNzKGIuMDUgfiB4LjA1KQ0KcmVmUHRzNVssIjV0aFBlcmNfU1NCbXN5Il0gPC0gcHJlZGljdChiLmxtLCByZWZQdHM1WywiRm1zeSJdKQ0KDQoNCnJlZlB0czVbLCJCdHJpZ2dlciJdIDwtIHJlZlB0c1ssIkJwYSJdDQoNCnNldC5zZWVkKDEyMykNClNJTV9TZWdyZWdfVHJpZ19sb3dlclJob2hpZ2hlcm51bUF2Z1lycyA8LSBlcXNpbV9ydW4oZXFmaXQsDQogICAgICAgICAgICAgICAgICAgICAgICAgIGJpby55ZWFycyA9IGMobWF4WWVhci1udW1BdmdZcnNCLCBtYXhZZWFyKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgYmlvLmNvbnN0ID0gRkFMU0UsDQogICAgICAgICAgICAgICAgICAgICAgICAgIHNlbC55ZWFycyA9IGMobWF4WWVhci1udW1BdmdZcnNTLCBtYXhZZWFyKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsLmNvbnN0ID0gRkFMU0UsDQogICAgICAgICAgICAgICAgICAgICAgICAgIEZjdj1jdkYsDQogICAgICAgICAgICAgICAgICAgICAgICAgIEZwaGk9cGhpRiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgU1NCY3Y9Y3ZTU0IsDQogICAgICAgICAgICAgICAgICAgICAgICAgIHJob2xvZ1JlYz1jKDAuNiksDQogICAgICAgICAgICAgICAgICAgICAgICAgIGtlZXAuc2ltcyA9IFRSVUUsDQogICAgICAgICAgICAgICAgICAgICAgICAgIEJ0cmlnZ2VyID0gcmVmUHRzNVssIkJ0cmlnZ2VyIl0sDQogICAgICAgICAgICAgICAgICAgICAgICAgIEJsaW09cmVmUHRzNVssIkJsaW0iXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgQnBhPXJlZlB0czVbLCJCcGEiXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgTnJ1bj1OcnVucywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgRnNjYW4gPSBGc1RvU2NhbiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgdmVyYm9zZT1UUlVFKQ0KdG1wMyA8LSB0KFNJTV9TZWdyZWdfVHJpZ19sb3dlclJob2hpZ2hlcm51bUF2Z1lycyRSZWZzKQ0KcmVmUHRzNVssIkZwMDUiXSA8LSByZWZQdHM1WywiRnBhIl0gPC0gdG1wM1siRjA1IiwiY2F0RiJdICNub3RlOiBjYXRjaCBGIGZvciBGcDA1DQoNCg0KcmVmUHRzNVssIkZtc3lfdW5jb25zdHIiXSA8LSBGbXN5X3RtcCANCmlmIChGbXN5X3RtcCA+IHJlZlB0czVbLCJGcGEiXSkgew0KICByZWZQdHM1WywiRm1zeSJdIDwtIHJlZlB0czVbLCJGcGEiXQ0KfSBlbHNlIHsNCnJlZlB0czVbLCJGbXN5Il0gPC0gRm1zeV90bXANCn0NCg0KYGBgDQoNCmBgYHtyIGZpbmFsIHRhYmxlIG9mIHJlZiBwb2ludHMsIG5vIHRydW5jYXRpb259DQoNCg0KcmVmUHRzNiA8LSByZWZQdHM1WywgYygxLDIsMyw0LDUsOCw5KV0NCg0KdChyZWZQdHM2KSAlPiUNCiAgICBrYmwoYm9va3RhYnMgPSBUUlVFLCBjYXB0aW9uPSJyZWZlcmVuY2UgcG9pbnRzIGZvciBwbGUuMjcuMjEtMzIsIHVzaW5nIHRoZSBub24tdHJ1bmNhdGVkIHJlY3J1aXRtZW50IikgJT4lDQogICAga2FibGVfbWF0ZXJpYWxfZGFyaygpDQoNCg0KYGBgDQoNCg0KDQojIyBsb3dlciBSaG9Mb2dSZWMgdmFsdWUNClNlbnNpdGl2aXR5IHJ1biBhc3N1bWluZyBhIGxvd2VyIGF1dG9jb3JyZWxhdGlvbiBpbiB0aGUgcmVjcnVpdG1lbnQsIFJob0xvZ1JlYyA9IDAuMy4gQWxsIG90aGVyIHNldHRpbmdzIGFyZSBpZGVudGljYWwgdG8gdGhlIGZpbmFsIHNldHRpbmdzIG9mIHRoZSByZWZlcmVuY2UgcG9pbnQgY2FsY3VsYXRpb24gYWJvdmU6DQotIEJsaW0gYXMgYXZlcmFnZSBTU0Igb2YgdGhlIGZpcnN0IHRlbiB5ZWFycyBvZiB0aGUgdGltZSBzZXJpZXMNCi0gbGFzdCAxMCB5ZWFycyBvZiBiaW9sb2dpY2FsIGRhdGEgdXNlZCBmb3IgUyBhbmQgQiBlc3RpbWF0aW9uIGluIHRoZSByZWZlcmVuY2UgcG9pbnQgbW9kZWxzDQotIFNTUiB0aW1lIHNlcmllcyB0cnVuY2F0ZWQsIG9ubHkgdXNpbmcgdGhlIGRhdGEgYmVmb3JlIHRoZSBleGNlcHRpb25hbGx5IHN0cm9uZyBpbmNyZWFzZSBpbiAyMDE5DQoNCg0KYGBge3IgbG93ZXIgcmhvIHZhbHVlLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCByZXN1bHRzPSdoaWRlJywgZmlnLnNob3c9J2hpZGUnfQ0KcmVmUHRzNyA8LSBtYXRyaXgoTkEsbnJvdz0xLG5jb2w9OSwgZGltbmFtZXM9bGlzdCgidmFsdWUiLGMoIkJ0cmlnZ2VyIiwiQnBhIiwiQmxpbSIsIjV0aFBlcmNfU1NCbXN5IiwiRnBhIiwiRmxpbSIsICJGcDA1IiwiRm1zeV91bmNvbnN0ciIsIkZtc3kiKSkpDQoNCiMga2VlcCBCbGltIGFuZCBCcGENCnJlZlB0czdbLCJCbGltIl0gPC0gbWVhbihkZltkZiR5ZWFyICVpbiUgYygyMDAyOjIwMTEpLCAiU1NCIl0pDQpyZWZQdHM3WywiQnBhIl0gIDwtcmVmUHRzWywiQmxpbSJdKmV4cCgxLjY0NSpzaWdtYVNTQikNCg0KIyBhZGQgdHJ1bmNhdGlvbg0Kcm1TUlJZcnMgPC0gYygyMDE5Om1heFllYXIpICAjIHNwZWNpZnkgaGVyZSB3aGljaCBvdGhlciB5ZWFycyAoZS5nLiBlYXJseSBwZXJpb2QpIHNob3VsZCBiZSBsZWZ0IG91dA0KDQpTZWdyZWdCbGltICA8LSBmdW5jdGlvbihhYiwgc3NiKSBsb2coaWZlbHNlKHNzYiA+PSByZWZQdHNbLCJCbGltIl0sIGFiJGEgKiByZWZQdHNbLCJCbGltIl0sIGFiJGEgKiBzc2IpKQ0KDQojIyBSZWZpdCBzdG9jayByZWNydWl0bWVudCByZWxhdGlvbnNoaXAgYmFzZWQgb24gdHJ1bmNhdGVkIHRpbWUgc2VyaWVzDQpzZXQuc2VlZCgxMjMpDQplcWZpdCA8LSBlcXNyX2ZpdChzdGsgPSBzdGssDQogICAgICAgICAgICAgICAgICBuc2FtcCA9IG5vU2ltcywNCiAgICAgICAgICAgICAgICAgIG1vZGVscyA9IGMoIlNlZ3JlZ0JsaW0iKSwNCiAgICAgICAgICAgICAgICAgIHJlbW92ZS55ZWFycyA9IHJtU1JSWXJzKQ0KIyMgUGxvdA0KZXFzcl9wbG90KGVxZml0LG49MmU0LGdnUGxvdD1UUlVFLFNjYWxlPTFlMykNCg0KDQpzZXQuc2VlZCgxMjMpDQpTSU1fU2VncmVnQmxpbV9sb3dlclJob2hpZ2hlcm51bUF2Z1lycyA8LSBlcXNpbV9ydW4oZXFmaXQsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiaW8ueWVhcnMgPSBjKChtYXhZZWFyLW51bUF2Z1lyc0IpLCBtYXhZZWFyKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYmlvLmNvbnN0ID0gVFJVRSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsLnllYXJzID0gYygobWF4WWVhci1udW1BdmdZcnNTKSwgbWF4WWVhciksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbC5jb25zdCA9IFRSVUUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZjdiA9IDAsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZwaGkgPSAwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBTU0JjdiA9IDAsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJob2xvZ1JlYyA9IGMoMC4zKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQnRyaWdnZXIgPSAwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBCbGltID0gcmVmUHRzN1ssIkJsaW0iXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQnBhID0gcmVmUHRzN1ssIkJwYSJdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBOcnVuID0gTnJ1bnMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZzY2FuID0gRnNUb1NjYW4sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZlcmJvc2U9VCkNCg0KdG1wMSA8LSB0KFNJTV9TZWdyZWdCbGltX2xvd2VyUmhvaGlnaGVybnVtQXZnWXJzJFJlZnMpDQoNCnJlZlB0czdbLCJGbGltIl0gPC0gdG1wMVsiRjUwIiwiY2F0RiJdDQoNCnRtcEZwYSA8LSByZWZQdHM3WywiRnBhIl0gPC0gcmVmUHRzN1ssIkZwMDUiXSA8LSB0bXAxWyJGMDUiLCJjYXRGIl0NCg0KaWYgKHRtcEZwYTwwLjIpIHJlZlB0czdbLCJGcGEiXSA8LSByb3VuZCh0bXBGcGEsIDMpIGVsc2UgcmVmUHRzN1ssIkZwYSJdIDwtIHJvdW5kKHRtcEZwYSwgMikNCg0Kc2V0LnNlZWQoMTIzKQ0KU0lNX1NlZ3JlZ19ub1RyaWdfbG93ZXJSaG9oaWdoZXJudW1BdmdZcnMgPC0gZXFzaW1fcnVuKGVxZml0LCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBiaW8ueWVhcnMgPSBjKG1heFllYXItbnVtQXZnWXJzQiwgbWF4WWVhciksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgYmlvLmNvbnN0ID0gRkFMU0UsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsLnllYXJzID0gYyhtYXhZZWFyLW51bUF2Z1lyc1MsIG1heFllYXIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbC5jb25zdCA9IEZBTFNFLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZjdj1jdkYsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIEZwaGk9cGhpRiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBTU0Jjdj1jdlNTQiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICByaG9sb2dSZWM9YygwLjMpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIGtlZXAuc2ltcyA9IFRSVUUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgQnRyaWdnZXIgPSAwLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIEJsaW09cmVmUHRzN1ssIkJsaW0iXSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBCcGE9cmVmUHRzN1ssIkJwYSJdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIE5ydW49TnJ1bnMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgRnNjYW4gPSBGc1RvU2NhbiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2ZXJib3NlPVQpDQoNCnRtcDIgPC0gdChTSU1fU2VncmVnX25vVHJpZ19sb3dlclJob2hpZ2hlcm51bUF2Z1lycyRSZWZzKQ0KRm1zeV90bXAgPC0gdG1wMlsibWVkaWFuTVNZIiwiY2F0RiJdICNub3RlOiAgd2FzIHByZXZpb3VzbHkgbGFuZGluZ3MgRiBmb3IgRm1zeSwgZnJvbSB0aGUgd3Jvbmcgb3V0cHV0IChyZWZzMiBvdXRwdXQgdGFibGVzKQ0KDQp0bXBGcGEgPC0gcmVmUHRzN1ssIkZwYSJdIDwtIHJlZlB0czdbLCJGcDA1Il0gPC0gdG1wMlsiRjA1IiwiY2F0RiJdDQoNCg0KcmVmUHRzN1ssIkZtc3lfdW5jb25zdHIiXSA8LSBGbXN5X3RtcCANCmlmIChGbXN5X3RtcCA+IHJlZlB0czdbLCJGcGEiXSkgew0KICByZWZQdHM3WywiRm1zeSJdIDwtIHJlZlB0czdbLCJGcGEiXSAjUEpXOiBtYWtlIHN1cmUgdGhpcyBpcyBGcDA1DQp9IGVsc2Ugew0KcmVmUHRzN1ssIkZtc3kiXSA8LSBGbXN5X3RtcA0KfQ0KDQoNCmRhdGEuMDU8LVNJTV9TZWdyZWdfbm9UcmlnX2xvd2VyUmhvaGlnaGVybnVtQXZnWXJzJHJicA0KeC4wNSA8LSBkYXRhLjA1W2RhdGEuMDUkdmFyaWFibGUgPT0gIlNwYXduaW5nIHN0b2NrIGJpb21hc3MiLCBdJEZ0YXJnZXQNCmIuMDUgPC0gZGF0YS4wNVtkYXRhLjA1JHZhcmlhYmxlID09ICJTcGF3bmluZyBzdG9jayBiaW9tYXNzIiwgXSRwMDUNCiMgcGxvdChiLjA1fnguMDUsIHlsYWI9IlNTQiIsIHhsYWI9IkYiKQ0KYi5sbSA8LSBsb2VzcyhiLjA1IH4geC4wNSkNCnJlZlB0czdbLCI1dGhQZXJjX1NTQm1zeSJdIDwtIHByZWRpY3QoYi5sbSwgcmVmUHRzN1ssIkZtc3kiXSkNCg0KDQpyZWZQdHM3WywiQnRyaWdnZXIiXSA8LSByZWZQdHNbLCJCcGEiXQ0KDQpzZXQuc2VlZCgxMjMpDQpTSU1fU2VncmVnX1RyaWdfbG93ZXJSaG9oaWdoZXJudW1BdmdZcnMgPC0gZXFzaW1fcnVuKGVxZml0LA0KICAgICAgICAgICAgICAgICAgICAgICAgICBiaW8ueWVhcnMgPSBjKG1heFllYXItbnVtQXZnWXJzQiwgbWF4WWVhciksDQogICAgICAgICAgICAgICAgICAgICAgICAgIGJpby5jb25zdCA9IEZBTFNFLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBzZWwueWVhcnMgPSBjKG1heFllYXItbnVtQXZnWXJzUywgbWF4WWVhciksDQogICAgICAgICAgICAgICAgICAgICAgICAgIHNlbC5jb25zdCA9IEZBTFNFLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBGY3Y9Y3ZGLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBGcGhpPXBoaUYsDQogICAgICAgICAgICAgICAgICAgICAgICAgIFNTQmN2PWN2U1NCLA0KICAgICAgICAgICAgICAgICAgICAgICAgICByaG9sb2dSZWM9YygwLjMpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBrZWVwLnNpbXMgPSBUUlVFLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBCdHJpZ2dlciA9IHJlZlB0czdbLCJCdHJpZ2dlciJdLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBCbGltPXJlZlB0czdbLCJCbGltIl0sDQogICAgICAgICAgICAgICAgICAgICAgICAgIEJwYT1yZWZQdHM3WywiQnBhIl0sDQogICAgICAgICAgICAgICAgICAgICAgICAgIE5ydW49TnJ1bnMsDQogICAgICAgICAgICAgICAgICAgICAgICAgIEZzY2FuID0gRnNUb1NjYW4sDQogICAgICAgICAgICAgICAgICAgICAgICAgIHZlcmJvc2U9VFJVRSkNCnRtcDMgPC0gdChTSU1fU2VncmVnX1RyaWdfbG93ZXJSaG9oaWdoZXJudW1BdmdZcnMkUmVmcykNCnJlZlB0czdbLCJGcDA1Il0gPC0gcmVmUHRzN1ssIkZwYSJdIDwtIHRtcDNbIkYwNSIsImNhdEYiXSAjbm90ZTogY2F0Y2ggRiBmb3IgRnAwNQ0KDQoNCnJlZlB0czdbLCJGbXN5X3VuY29uc3RyIl0gPC0gRm1zeV90bXAgDQppZiAoRm1zeV90bXAgPiByZWZQdHM3WywiRnBhIl0pIHsNCiAgcmVmUHRzN1ssIkZtc3kiXSA8LSByZWZQdHM3WywiRnBhIl0NCn0gZWxzZSB7DQpyZWZQdHM3WywiRm1zeSJdIDwtIEZtc3lfdG1wDQp9DQoNCmBgYA0KDQoNCg0KYGBge3IgZmluYWwgdGFibGUgb2YgcmVmIHBvaW50cywgbG93ZXIgUmhvfQ0KDQoNCnJlZlB0czggPC0gcmVmUHRzN1ssIGMoMSwyLDMsNCw1LDgsOSldDQoNCnQocmVmUHRzOCkgJT4lDQogICAga2JsKGJvb2t0YWJzID0gVFJVRSwgY2FwdGlvbj0icmVmZXJlbmNlIHBvaW50cyBmb3IgcGxlLjI3LjIxLTMyLCBhc3N1bWluZyBSaG9Mb2dSZWMgPSAwLjMiKSAlPiUNCiAgICBrYWJsZV9tYXRlcmlhbF9kYXJrKCkNCg0KYGBgDQoNCg0KDQoNCg0KDQoNCg==