Processing math: 100%

The code below reproduces key computations from the paper “Regulation of fish stocks without stock-recruitment relationships: the case of small pelagic fish” by Mariella Canales, Gustav Delius and Richard Law, using the R package mizer to implement the size-spectrum model. This notebook should be used after reading that paper.

This notebook requires mizer version 2.0 or later.

Setting up the model

We set up the model according to the description in the paper in Appendix A, with the parameters from Appendix B, but without diffusion (term (e) in equation (A.1)).

Parameters

We create a list holding the model parameters

p <- list(
    dt = 0.001,
    dx = 0.1,
    w_min = 0.0003,
    w_inf = 66.5,
    ppmr_min = 100,
    ppmr_max = 30000,
    gamma = 750,
    alpha = 0.85, # q
    K = 0.1, # alpha
    # Larval mortality
    mu_l = 0,
    w_l = 0.03,
    rho_l = 5,
    # background mortality
    mu_0 = 1,
    rho_b = -0.25,
    # Senescent mortality
    w_s = 0.5,
    rho_s = 1,
    # reproduction
    w_mat = 10,
    rho_m = 15,
    rho_inf = 0.2,
    epsilon_R = 0.1,
    # plankton
    w_pp_cutoff = 0.1,
    r0 = 10,
    a0 = 100,
    i0 = 100,
    rho = 0.85,
    lambda = 2
)

Mortality

We define a function for setting the background and larval mortality as described in equations (A.5) and (A.6).

setAnchovyMort <- 
  function(params, p) {
    mu_b <- rep(0, length(params@w))
    mu_b[params@w <= p$w_s] <- 
      (p$mu_0 * (params@w / p$w_min)^p$rho_b)[params@w < p$w_s]
    if (p$mu_0 > 0) {
      mu_s <- min(mu_b[params@w <= p$w_s])
    } else {
      mu_s <- p$mu_s
    }
    mu_b[params@w >= p$w_s] <- 
      (mu_s * (params@w / p$w_s)^p$rho_s)[params@w >= p$w_s]
    # Add larval mortality
    mu_b <- mu_b + p$mu_l / (1 + (params@w / p$w_l)^p$rho_l)
    
    params@mu_b[] <- mu_b
    return(params)
  }

Plankton dynamics

To prepare for random changes in plankton carrying capacity every half year, we create an environment to maintain state between function calls.

plankton_state <- new.env(parent = emptyenv())
plankton_state$time <- 0
plankton_state$factor <- 1
plankton_state$random <- FALSE
plankton_state$phi <- 0
plankton_state$sigma <- 0.5

We implement the logistic plankton dynamics with immigration, as described in equation (A.11), allowing the carrying capacity to be random when required.

plankton_logistic <- function(params, n, n_pp, n_other, rates, dt = 0.1, ...) {
    plankton_state$time <- plankton_state$time + dt
    if (plankton_state$random == "paper" && plankton_state$time >= 0.5) {
        # This is the random factor by which we multiply the carrying capacity
        # in the paper, which changes once every six months to a new
        # independent random value
        plankton_state$factor <- exp(runif(1, log(1/2), log(2)))
        plankton_state$time <- 0
    } else if (plankton_state$random == "red") {
        # Here the random factor multiplying the carrying capacity changes
        # at every time step and is given as the exponential of an AR(1)
        # process, i.e., red noise.
        plankton_state$factor <- plankton_state$factor ^ plankton_state$phi * 
          exp(rnorm(1, 0, plankton_state$sigma))
    }
    f <- params@rr_pp * n_pp * (1 - n_pp / params@cc_pp / plankton_state$factor) + 
        i - rates$resource_mort * n_pp 
    f[is.na(f)] <- 0
    return(n_pp + dt * f)
}

Feeding kernel

We define the feeding kernel described in equation (A.2)

norm_box_pred_kernel <- function(ppmr, ppmr_min, ppmr_max) {
    phi <- rep(1, length(ppmr))
    phi[ppmr > ppmr_max] <- 0
    phi[ppmr < ppmr_min] <- 0
    # Do not allow feeding at own size
    phi[1] <- 0
    # normalise in log space
    logppmr <- log(ppmr)
    dl <- logppmr[2] - logppmr[1]
    N <- sum(phi) * dl
    phi <- phi / N
    return(phi)
}

Set model

We are now ready to set up the MizerParams object describing the Anchovy - Plankton model from the paper:

setModel <- function(p) {
  kappa = p$a0 * exp(-6.9*(p$lambda - 1))
  n = 2/3 # irrelevant value
  
  species_params <- data.frame(
    species = "Anchovy",
    w_min = p$w_min,
    w_mat = p$w_mat,
    m = p$rho_inf + n,
    w_inf = p$w_inf,
    erepro = p$epsilon_R,
    alpha = p$K,
    ks = 0,
    gamma = p$gamma,
    ppmr_min = p$ppmr_min,
    ppmr_max = p$ppmr_max,
    pred_kernel_type = "norm_box",
    h = Inf,
    R_max = Inf,
    linecolour = "brown",
    stringsAsFactors = FALSE)
  
  no_w <- round(log(p$w_inf / p$w_min) / p$dx)
  
  params <- set_multispecies_model(
    species_params,
    no_w = no_w,
    lambda = p$lambda,
    kappa = kappa,
    w_pp_cutoff = p$w_pp_cutoff,
    q = p$alpha,
    resource_dynamics = "plankton_logistic")

  params@rr_pp[] <- p$r0 * params@w_full^(p$rho - 1)
  return(params)
}

params <- setModel(p)
Warning: `set_multispecies_model()` was deprecated in mizer 2.0.0.
Please use `newMultispeciesParams()` instead.
Note: No sel_func column in species data frame. Setting selectivity to be 'knife_edge' for all species.
Note: No knife_edge_size column in species data frame. Setting knife edge selectivity equal to w_mat.
Using z0 = z0pre * w_inf ^ z0exp for missing z0 values.
i <- p$i0 * params@w_full^(-p$lambda) * exp(-6.9*(p$lambda - 1))

Without larval mortality or cannibalism

We first run the model without larval mortality and without cannibalism

p$mu_l <- 0
params <- setAnchovyMort(params, p)
params@interaction[] <- 0

We set an initial abundance and run for 10 years.

params@initial_n[] <- 0.001 * params@w^(-1.8)
params@initial_n_pp[] <- params@cc_pp
sim <- project(params, t_max = 10, dt = p$dt, progress_bar = FALSE)

At this point we reduce the anchovy abundance by an overall factor of 10^7 and then run the simulation for a further 30 years.

sim@n[11, , ] <- sim@n[11, , ] / 10^7
sim <- project(sim, t_max = 30, dt = p$dt, t_save = 0.2, progress_bar = FALSE)

Figure 2a

Plotting the spectra at year 30 gives Figure 2a. Here we plot the plankton spectrum and the anchovy spectrum using the same y-axis. Figure 2a in the paper uses different axes.

plotSpectra(sim, power = 2, wlim = c(1e-8, NA), ylim = c(1e-5, NA),
            time_range = 30)

This does not look exactly the same as the corresponding graph in the paper because the pile-up is not smoothed by diffusion, but it displays the same qualitative behaviour.

Figure 2b

Figure 2b plots the death rate on the anchovy as a function of anchovy body size.

t <- as.numeric(dimnames(sim@n)$time) == 30
nt <- params@initial_n # Just to get the right dimensions
nt[] <- sim@n[t, , ]
mort <- getMort(params, n = nt, n_pp = sim@n_pp[t, ], effort = 0)
mort <- melt(mort)
plot_ly(mort) %>% 
    add_lines(x = ~w_prey, y = ~value) %>% 
    layout(p, xaxis = list(type = "log", exponentformat = "power",
                           title_text = "body mass (g)"),
           yaxis = list(title_text = "death rate (1/year)"))
10​−310​−210​−111005101520
body mass (g)death rate (1/year)

Figure 2c

abm <- melt(getBiomass(sim))
pbm <- sim@n_pp %*% (params@w_full * params@dw_full)
pbm <- melt(pbm)
pbm$Var2 <- NULL
pbm$sp = "Plankton"
bm <- rbind(pbm, abm)
plot_ly(bm) %>% 
    filter(time >= 10) %>% 
    add_lines(x = ~time, y = ~value, color = ~sp) %>% 
    # Use logarithmic axes
    layout(p, yaxis = list(type = "log", exponentformat = "power",
                           title_text = "biomass (g/m^3)"),
           xaxis = list(title_text = "time (year)"))
1020304010​−710​−610​−510​−410​−310​−210​−11
AnchovyPlanktontime (year)biomass (g/m^3)

With cannibalism

Turn on cannibalism

params@interaction[] <- 1

We set an initial abundance and run for 10 years.

params@initial_n[] <- 0.001 * params@w^(-1.8)
params@initial_n_pp[] <- params@cc_pp
simc <- project(params, t_max = 10, dt = p$dt, progress_bar = FALSE)

At this point we reduce the anchovy abundance by an overall factor of 10^7 and then run the simulation for a further 30 years.

simc@n[11, , ] <- simc@n[11, , ] / 10^7
simc <- project(simc, t_max = 30, dt = p$dt, t_save = 0.2, progress_bar = FALSE)

Figure 2d

While Figure 2d shows the background death and the larval death separately, here for simplicity we plot only their sum.

t <- as.numeric(dimnames(simc@n)$time) == 36.8
nt <- params@initial_n # Just to get the right dimensions
nt[] <- simc@n[t, , ]
mort <- getMort(params, n = nt, n_pp = simc@n_pp[t, ], effort = 0)
mort <- melt(mort)
plot_ly(mort) %>% 
    add_lines(x = ~w_prey, y = ~value) %>% 
    layout(p, xaxis = list(type = "log", exponentformat = "power",
                           title_text = "body mass (g)"),
           yaxis = list(title_text = "death rate (1/year)"))
10​−310​−210​−111005101520
body mass (g)death rate (1/year)

We made the plot for time = 36.8 years because the oscillations of the spectrum are shifted with respect to those in the paper, as the following figure shows.

Figure 2e

abm <- melt(getBiomass(simc))
abmr <- melt(getBiomass(simc, min_w = 0.01, max_w = 0.4))
abmr$sp = "small Anchovy"
pbm <- simc@n_pp %*% (params@w_full * params@dw_full)
pbm <- melt(pbm)
pbm$Var2 <- NULL
pbm$sp = "Plankton"
bm <- rbind(pbm, abm, abmr)
plot_ly(bm) %>% 
    filter(time >= 10) %>% 
    add_lines(x = ~time, y = ~value, color = ~sp) %>% 
    # Use logarithmic axes
    layout(p, yaxis = list(type = "log", exponentformat = "power",
                           title_text = "biomass (g/m^3)",
                           range = c(-7, 2)),
           xaxis = list(title_text = "time (year)"))
1020304010​−710​−610​−510​−410​−310​−210​−111010​2
AnchovyPlanktonsmall Anchovytime (year)biomass (g/m^3)

Animation

Here is an animation showing the evolution of the spectra from year 26 to year 40.

nf <- melt(simc@n)
n_ppf <- melt(simc@n_pp)
n_ppf$sp <- "Plankton"
nf <- rbind(nf, n_ppf)

plot_ly(nf) %>%
    # show only part of plankton spectrum
    filter(w > 10^-5) %>% 
    # start at time 20
    filter(time >= 26) %>% 
    # calculate biomass density with respect to log size
    mutate(b = value * w^2) %>% 
    # Plot lines
    add_lines(
        x = ~w, y = ~b,
        color = ~sp,
        frame = ~time,
        line = list(simplify = FALSE)
    ) %>% 
    # Use logarithmic axes
    layout(p, xaxis = list(type = "log", exponentformat = "power",
                           title_text = "body mass (g)"),
           yaxis = list(type = "log", exponentformat = "power",
                        title_text = "biomass (g/m^3)",
                        range = c(-8, 0)))
10​−410​−2110​210​−810​−710​−610​−510​−410​−310​−210​−11
AnchovyPlanktontime: 262627.829.631.433.23536.838.6body mass (g)biomass (g/m^3)Play

With larval mortality

Turn on larval mortality

p$mu_l <- 21
params <- setAnchovyMort(params, p)

We set an initial abundance and run for 10 years.

params@initial_n[] <- 0.001 * params@w^(-1.8)
params@initial_n_pp[] <- params@cc_pp
siml <- project(params, t_max = 10, dt = p$dt, progress_bar = FALSE)

At this point we reduce the anchovy abundance by an overall factor of 10^7 and then run the simulation for a further 30 years.

siml@n[11, , ] <- siml@n[11, , ] / 10^7
siml <- project(siml, t_max = 30, dt = p$dt, t_save = 0.2, progress_bar = FALSE)

Figure 2f

I have not yet split the mortality up into its causes in the following figure. But overall it looks right.

t <- as.numeric(dimnames(siml@n)$time) == 30
nt <- params@initial_n # Just to get the right dimensions
nt[] <- siml@n[t, , ]
mort <- getMort(params, n = nt, n_pp = siml@n_pp[t, ], effort = 0)
mort <- melt(mort)
plot_ly(mort) %>% 
    add_lines(x = ~w_prey, y = ~value) %>% 
    layout(p, xaxis = list(type = "log", exponentformat = "power",
                           title_text = "body mass (g)"),
           yaxis = list(title_text = "death rate (1/year)"))
10​−310​−210​−11100510152025
body mass (g)death rate (1/year)

Figure 2g

abm <- melt(getBiomass(siml))
pbm <- siml@n_pp %*% (params@w_full * params@dw_full)
pbm <- melt(pbm)
pbm$Var2 <- NULL
pbm$sp = "Plankton"
bm <- rbind(abm, pbm)
plot_ly(bm) %>% 
    filter(time >= 10) %>% 
    add_lines(x = ~time, y = ~value, color = ~sp) %>% 
    # Use logarithmic axes
    layout(p, yaxis = list(type = "log", exponentformat = "power",
                           title_text = "biomass (g/m^3)",
                           range = c(-7, 2)),
           xaxis = list(title_text = "time (year)"))
1020304010​−710​−610​−510​−410​−310​−210​−111010​2
AnchovyPlanktontime (year)biomass (g/m^3)

Figure 3a

gcp <- plotGrowthCurves(siml, max_age = 4)
gcp + scale_y_continuous(trans = "log10")
Scale for 'y' is already present. Adding another scale for 'y', which will replace the existing scale.

Figure 3b

t_min_idx <- sum(as.numeric(dimnames(siml@n)$time) <= 15)
t_max_idx <- dim(siml@n)[1]
t_step_idx <- 1 / 0.2  # 1 year steps
ssb <- getSSB(siml)[seq(t_min_idx, t_max_idx - t_step_idx, t_step_idx)]
rec_idx <- sum(params@w < 10)
n_rec <- siml@n[seq(t_min_idx + t_step_idx, t_max_idx, t_step_idx), , rec_idx]
# Convert to density in log weight
n_rec <- n_rec * params@w[rec_idx]
plot(ssb, n_rec, type = "l", log = "xy",
     xlim = c(1e-5, 1e-1), ylim = c(1e-5, 1e-2))

Random plankton

Switch on the randomness for plankton carrying capacity used in the original paper.

set.seed(0)
plankton_state$random <- "paper"
plankton_state$factor <- 1

Of course our figures will not look exactly like those in the paper because we will get a different randomisation, but they will be qualitatively the same.

We set an initial abundance and run for 10 years.

params@initial_n[] <- 0.001 * params@w^(-1.8)
params@initial_n_pp[] <- params@cc_pp
simr <- project(params, t_max = 10, dt = p$dt, progress_bar = FALSE)

At this point we reduce the anchovy abundance by an overall factor of 10^7 and then run the simulation for a further 30 years.

simr@n[11, , ] <- simr@n[11, , ] / 10^7
simr <- project(simr, t_max = 30, dt = p$dt, t_save = 0.2, progress_bar = FALSE)

Figure 4a

abm <- melt(getBiomass(simr))
pbm <- simr@n_pp %*% (params@w_full * params@dw_full)
pbm <- melt(pbm)
pbm$Var2 <- NULL
pbm$sp = "Plankton"
bm <- rbind(abm, pbm)
plot_ly(bm) %>% 
    filter(time >= 10) %>% 
    add_lines(x = ~time, y = ~value, color = ~sp) %>% 
    # Use logarithmic axes
    layout(p, yaxis = list(type = "log", exponentformat = "power",
                           title_text = "biomass (g/m^3)",
                           range = c(-3.2, 0.8)),
           xaxis = list(title_text = "time (year)"))
1020304010​−32510​−22510​−125125
AnchovyPlanktontime (year)biomass (g/m^3)

Figure 4b

t_min_idx <- sum(as.numeric(dimnames(simr@n)$time) <= 15)
t_max_idx <- dim(simr@n)[1]
t_step_idx <- 1 / 0.2  # 1 year steps
ssb <- getSSB(simr)[seq(t_min_idx, t_max_idx - t_step_idx, t_step_idx)]
rec_idx <- sum(params@w < 10)
n_rec <- simr@n[seq(t_min_idx + t_step_idx, t_max_idx, t_step_idx), , rec_idx]
# Convert to density in log weight
n_rec <- n_rec * params@w[rec_idx]
plot(ssb, n_rec, log = "xy", ylim = c(1e-5, 1e-1), pch = 20,
     xlab = "spawning stock biomass (g/m^3)", xlim = c(1e-3, 1),
     ylab = "density of recruits (1/m^3)")

Survivorship

Figure 5b

First we calculate survivorship for a cohort as a function of size.

Random plankton driven by red noise

One of the referees suggested we should use red noise to drive the plankton randomness. So we now multiply the carrying capacity of the plankton by a factor given by the exponential of an AR(1) process. Denoting the carrying capacity at time t for plankton of size w, we use K(w,t)=K(w,0)exp(X(t)) where X(t+dt)=(10.5dt)X(t)+10η(t)dt and η(t) are independent standard normally distributed random variables. We start with X(0)=0. This process can be seen as the discretisation of the Ornstein-Uhlenbeck process satisfying the SDE dX(t)=0.5X(t)dt+10dW(t) where W is the Wiener process.

The random factor F(t)=exp(X(t)) satisfies F(t+dt)=F(t)10.5dtexp(10ηdt) with F(0)=1. We will use a time step dt= 0.001

set.seed(0)
plankton_state$random <- "red"
plankton_state$factor <- 1
plankton_state$sigma <- 10 * p$dt
plankton_state$phi <- 1 - 0.5 * p$dt

We set an initial abundance and run for 10 years.

params@initial_n[] <- 0.001 * params@w^(-1.8)
params@initial_n_pp[] <- params@cc_pp
simrr <- project(params, t_max = 10, dt = p$dt, progress_bar = FALSE)

At this point we reduce the anchovy abundance by an overall factor of 10^7 and then run the simulation for a further 30 years.

simrr@n[11, , ] <- simrr@n[11, , ] / 10^7
simrr <- project(simrr, t_max = 30, dt = p$dt, t_save = 0.1, progress_bar = FALSE)

Figure 4a

abm <- melt(getBiomass(simrr))
pbm <- simrr@n_pp %*% (params@w_full * params@dw_full)
pbm <- melt(pbm)
pbm$Var2 <- NULL
pbm$sp = "Plankton"
bm <- rbind(abm, pbm)
plot_ly(bm) %>% 
    filter(time >= 10) %>% 
    add_lines(x = ~time, y = ~value, color = ~sp) %>% 
    # Use logarithmic axes
    layout(p, yaxis = list(type = "log", exponentformat = "power",
                           title_text = "biomass (g/m^3)",
                           range = c(-3, 0.8)),
           xaxis = list(title_text = "time (year)"))
1020304010​−32510​−22510​−125125
AnchovyPlanktontime (year)biomass (g/m^3)

Figure 4b

t_min_idx <- sum(as.numeric(dimnames(simrr@n)$time) <= 15)
t_max_idx <- dim(simrr@n)[1]
t_step_idx <- 1 / 0.1  # 1 year steps
ssb <- getSSB(simrr)[seq(t_min_idx, t_max_idx - t_step_idx, t_step_idx)]
rec_idx <- sum(params@w < 10)
n_rec <- simrr@n[seq(t_min_idx + t_step_idx, t_max_idx, t_step_idx), , rec_idx]
# Convert to density in log weight
n_rec <- n_rec * params@w[rec_idx]
plot(ssb, n_rec, log = "xy", ylim = c(1e-5, 1e-1), pch = 20,
     xlab = "spawning stock biomass (g/m^3)", xlim = c(1e-3, 1),
     ylab = "density of recruits (1/m^3)")

LS0tCnRpdGxlOiAiUmVndWxhdGlvbiBvZiBmaXNoIHN0b2NrcyB3aXRob3V0IHN0b2NrLXJlY3J1aXRtZW50IHJlbGF0aW9uc2hpcHM6IHRoZSBjYXNlIG9mIHNtYWxsIHBlbGFnaWMgZmlzaCIKb3V0cHV0OiAKICBodG1sX25vdGVib29rOgogICAgdG9jOiB0cnVlCmZpZ19oZWlnaHQ6IDQKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQpsaWJyYXJ5KG1pemVyKQpsaWJyYXJ5KG1hZ3JpdHRyKQpsaWJyYXJ5KHBsb3RseSkKYGBgCgpUaGUgY29kZSBiZWxvdyByZXByb2R1Y2VzIGtleSBjb21wdXRhdGlvbnMgZnJvbSB0aGUgcGFwZXIKIlJlZ3VsYXRpb24gb2YgZmlzaCBzdG9ja3Mgd2l0aG91dCBzdG9jay1yZWNydWl0bWVudCByZWxhdGlvbnNoaXBzOiB0aGUgY2FzZSBvZiAKc21hbGwgcGVsYWdpYyBmaXNoIiBieSBNYXJpZWxsYSBDYW5hbGVzLCBHdXN0YXYgRGVsaXVzIGFuZCBSaWNoYXJkIExhdywgdXNpbmcgCnRoZSBSIHBhY2thZ2UgbWl6ZXIgdG8gaW1wbGVtZW50IHRoZSBzaXplLXNwZWN0cnVtIG1vZGVsLiBUaGlzIG5vdGVib29rIHNob3VsZCAKYmUgdXNlZCBhZnRlciByZWFkaW5nIHRoYXQgcGFwZXIuIAoKVGhpcyBub3RlYm9vayByZXF1aXJlcyBtaXplciB2ZXJzaW9uIDIuMCBvciBsYXRlci4KCiMgU2V0dGluZyB1cCB0aGUgbW9kZWwKV2Ugc2V0IHVwIHRoZSBtb2RlbCBhY2NvcmRpbmcgdG8gdGhlIGRlc2NyaXB0aW9uIGluIHRoZSBwYXBlciBpbiBBcHBlbmRpeCBBLAp3aXRoIHRoZSBwYXJhbWV0ZXJzIGZyb20gQXBwZW5kaXggQiwgYnV0IHdpdGhvdXQgZGlmZnVzaW9uICh0ZXJtIChlKSBpbiAKZXF1YXRpb24gKEEuMSkpLiAKCiMjIFBhcmFtZXRlcnMKV2UgY3JlYXRlIGEgbGlzdCBob2xkaW5nIHRoZSBtb2RlbCBwYXJhbWV0ZXJzCmBgYHtyfQpwIDwtIGxpc3QoCiAgICBkdCA9IDAuMDAxLAogICAgZHggPSAwLjEsCiAgICB3X21pbiA9IDAuMDAwMywKICAgIHdfaW5mID0gNjYuNSwKICAgIHBwbXJfbWluID0gMTAwLAogICAgcHBtcl9tYXggPSAzMDAwMCwKICAgIGdhbW1hID0gNzUwLAogICAgYWxwaGEgPSAwLjg1LCAjIHEKICAgIEsgPSAwLjEsICMgYWxwaGEKICAgICMgTGFydmFsIG1vcnRhbGl0eQogICAgbXVfbCA9IDAsCiAgICB3X2wgPSAwLjAzLAogICAgcmhvX2wgPSA1LAogICAgIyBiYWNrZ3JvdW5kIG1vcnRhbGl0eQogICAgbXVfMCA9IDEsCiAgICByaG9fYiA9IC0wLjI1LAogICAgIyBTZW5lc2NlbnQgbW9ydGFsaXR5CiAgICB3X3MgPSAwLjUsCiAgICByaG9fcyA9IDEsCiAgICAjIHJlcHJvZHVjdGlvbgogICAgd19tYXQgPSAxMCwKICAgIHJob19tID0gMTUsCiAgICByaG9faW5mID0gMC4yLAogICAgZXBzaWxvbl9SID0gMC4xLAogICAgIyBwbGFua3RvbgogICAgd19wcF9jdXRvZmYgPSAwLjEsCiAgICByMCA9IDEwLAogICAgYTAgPSAxMDAsCiAgICBpMCA9IDEwMCwKICAgIHJobyA9IDAuODUsCiAgICBsYW1iZGEgPSAyCikKYGBgCgojIyBNb3J0YWxpdHkKV2UgZGVmaW5lIGEgZnVuY3Rpb24gZm9yIHNldHRpbmcgdGhlIGJhY2tncm91bmQgYW5kIGxhcnZhbCBtb3J0YWxpdHkgYXMgCmRlc2NyaWJlZCBpbiBlcXVhdGlvbnMgKEEuNSkgYW5kIChBLjYpLgpgYGB7cn0Kc2V0QW5jaG92eU1vcnQgPC0gCiAgZnVuY3Rpb24ocGFyYW1zLCBwKSB7CiAgICBtdV9iIDwtIHJlcCgwLCBsZW5ndGgocGFyYW1zQHcpKQogICAgbXVfYltwYXJhbXNAdyA8PSBwJHdfc10gPC0gCiAgICAgIChwJG11XzAgKiAocGFyYW1zQHcgLyBwJHdfbWluKV5wJHJob19iKVtwYXJhbXNAdyA8IHAkd19zXQogICAgaWYgKHAkbXVfMCA+IDApIHsKICAgICAgbXVfcyA8LSBtaW4obXVfYltwYXJhbXNAdyA8PSBwJHdfc10pCiAgICB9IGVsc2UgewogICAgICBtdV9zIDwtIHAkbXVfcwogICAgfQogICAgbXVfYltwYXJhbXNAdyA+PSBwJHdfc10gPC0gCiAgICAgIChtdV9zICogKHBhcmFtc0B3IC8gcCR3X3MpXnAkcmhvX3MpW3BhcmFtc0B3ID49IHAkd19zXQogICAgIyBBZGQgbGFydmFsIG1vcnRhbGl0eQogICAgbXVfYiA8LSBtdV9iICsgcCRtdV9sIC8gKDEgKyAocGFyYW1zQHcgLyBwJHdfbClecCRyaG9fbCkKICAgIAogICAgcGFyYW1zQG11X2JbXSA8LSBtdV9iCiAgICByZXR1cm4ocGFyYW1zKQogIH0KYGBgCgojIyBQbGFua3RvbiBkeW5hbWljcwpUbyBwcmVwYXJlIGZvciByYW5kb20gY2hhbmdlcyBpbiBwbGFua3RvbiBjYXJyeWluZyBjYXBhY2l0eSBldmVyeSBoYWxmIHllYXIsCndlIGNyZWF0ZSBhbiBlbnZpcm9ubWVudCB0byBtYWludGFpbiBzdGF0ZSBiZXR3ZWVuIGZ1bmN0aW9uIGNhbGxzLgpgYGB7cn0KcGxhbmt0b25fc3RhdGUgPC0gbmV3LmVudihwYXJlbnQgPSBlbXB0eWVudigpKQpwbGFua3Rvbl9zdGF0ZSR0aW1lIDwtIDAKcGxhbmt0b25fc3RhdGUkZmFjdG9yIDwtIDEKcGxhbmt0b25fc3RhdGUkcmFuZG9tIDwtIEZBTFNFCnBsYW5rdG9uX3N0YXRlJHBoaSA8LSAwCnBsYW5rdG9uX3N0YXRlJHNpZ21hIDwtIDAuNQpgYGAKCldlIGltcGxlbWVudCB0aGUgbG9naXN0aWMgcGxhbmt0b24gZHluYW1pY3Mgd2l0aCBpbW1pZ3JhdGlvbiwgYXMgZGVzY3JpYmVkIGluCmVxdWF0aW9uIChBLjExKSwgYWxsb3dpbmcgdGhlIGNhcnJ5aW5nIGNhcGFjaXR5IHRvIGJlIHJhbmRvbSB3aGVuIHJlcXVpcmVkLgpgYGB7cn0KcGxhbmt0b25fbG9naXN0aWMgPC0gZnVuY3Rpb24ocGFyYW1zLCBuLCBuX3BwLCBuX290aGVyLCByYXRlcywgZHQgPSAwLjEsIC4uLikgewogICAgcGxhbmt0b25fc3RhdGUkdGltZSA8LSBwbGFua3Rvbl9zdGF0ZSR0aW1lICsgZHQKICAgIGlmIChwbGFua3Rvbl9zdGF0ZSRyYW5kb20gPT0gInBhcGVyIiAmJiBwbGFua3Rvbl9zdGF0ZSR0aW1lID49IDAuNSkgewogICAgICAgICMgVGhpcyBpcyB0aGUgcmFuZG9tIGZhY3RvciBieSB3aGljaCB3ZSBtdWx0aXBseSB0aGUgY2FycnlpbmcgY2FwYWNpdHkKICAgICAgICAjIGluIHRoZSBwYXBlciwgd2hpY2ggY2hhbmdlcyBvbmNlIGV2ZXJ5IHNpeCBtb250aHMgdG8gYSBuZXcKICAgICAgICAjIGluZGVwZW5kZW50IHJhbmRvbSB2YWx1ZQogICAgICAgIHBsYW5rdG9uX3N0YXRlJGZhY3RvciA8LSBleHAocnVuaWYoMSwgbG9nKDEvMiksIGxvZygyKSkpCiAgICAgICAgcGxhbmt0b25fc3RhdGUkdGltZSA8LSAwCiAgICB9IGVsc2UgaWYgKHBsYW5rdG9uX3N0YXRlJHJhbmRvbSA9PSAicmVkIikgewogICAgICAgICMgSGVyZSB0aGUgcmFuZG9tIGZhY3RvciBtdWx0aXBseWluZyB0aGUgY2FycnlpbmcgY2FwYWNpdHkgY2hhbmdlcwogICAgICAgICMgYXQgZXZlcnkgdGltZSBzdGVwIGFuZCBpcyBnaXZlbiBhcyB0aGUgZXhwb25lbnRpYWwgb2YgYW4gQVIoMSkKICAgICAgICAjIHByb2Nlc3MsIGkuZS4sIHJlZCBub2lzZS4KICAgICAgICBwbGFua3Rvbl9zdGF0ZSRmYWN0b3IgPC0gcGxhbmt0b25fc3RhdGUkZmFjdG9yIF4gcGxhbmt0b25fc3RhdGUkcGhpICogCiAgICAgICAgICBleHAocm5vcm0oMSwgMCwgcGxhbmt0b25fc3RhdGUkc2lnbWEpKQogICAgfQogICAgZiA8LSBwYXJhbXNAcnJfcHAgKiBuX3BwICogKDEgLSBuX3BwIC8gcGFyYW1zQGNjX3BwIC8gcGxhbmt0b25fc3RhdGUkZmFjdG9yKSArIAogICAgICAgIGkgLSByYXRlcyRyZXNvdXJjZV9tb3J0ICogbl9wcCAKICAgIGZbaXMubmEoZildIDwtIDAKICAgIHJldHVybihuX3BwICsgZHQgKiBmKQp9CmBgYAoKIyMgRmVlZGluZyBrZXJuZWwKV2UgZGVmaW5lIHRoZSBmZWVkaW5nIGtlcm5lbCBkZXNjcmliZWQgaW4gZXF1YXRpb24gKEEuMikKYGBge3J9Cm5vcm1fYm94X3ByZWRfa2VybmVsIDwtIGZ1bmN0aW9uKHBwbXIsIHBwbXJfbWluLCBwcG1yX21heCkgewogICAgcGhpIDwtIHJlcCgxLCBsZW5ndGgocHBtcikpCiAgICBwaGlbcHBtciA+IHBwbXJfbWF4XSA8LSAwCiAgICBwaGlbcHBtciA8IHBwbXJfbWluXSA8LSAwCiAgICAjIERvIG5vdCBhbGxvdyBmZWVkaW5nIGF0IG93biBzaXplCiAgICBwaGlbMV0gPC0gMAogICAgIyBub3JtYWxpc2UgaW4gbG9nIHNwYWNlCiAgICBsb2dwcG1yIDwtIGxvZyhwcG1yKQogICAgZGwgPC0gbG9ncHBtclsyXSAtIGxvZ3BwbXJbMV0KICAgIE4gPC0gc3VtKHBoaSkgKiBkbAogICAgcGhpIDwtIHBoaSAvIE4KICAgIHJldHVybihwaGkpCn0KYGBgCgojIyBTZXQgbW9kZWwKV2UgYXJlIG5vdyByZWFkeSB0byBzZXQgdXAgdGhlIE1pemVyUGFyYW1zIG9iamVjdCBkZXNjcmliaW5nIHRoZSAKQW5jaG92eSAtIFBsYW5rdG9uIG1vZGVsIGZyb20gdGhlIHBhcGVyOgpgYGB7ciBtZXNzYWdlPUZBTFNFfQpzZXRNb2RlbCA8LSBmdW5jdGlvbihwKSB7CiAga2FwcGEgPSBwJGEwICogZXhwKC02LjkqKHAkbGFtYmRhIC0gMSkpCiAgbiA9IDIvMyAjIGlycmVsZXZhbnQgdmFsdWUKICAKICBzcGVjaWVzX3BhcmFtcyA8LSBkYXRhLmZyYW1lKAogICAgc3BlY2llcyA9ICJBbmNob3Z5IiwKICAgIHdfbWluID0gcCR3X21pbiwKICAgIHdfbWF0ID0gcCR3X21hdCwKICAgIG0gPSBwJHJob19pbmYgKyBuLAogICAgd19pbmYgPSBwJHdfaW5mLAogICAgZXJlcHJvID0gcCRlcHNpbG9uX1IsCiAgICBhbHBoYSA9IHAkSywKICAgIGtzID0gMCwKICAgIGdhbW1hID0gcCRnYW1tYSwKICAgIHBwbXJfbWluID0gcCRwcG1yX21pbiwKICAgIHBwbXJfbWF4ID0gcCRwcG1yX21heCwKICAgIHByZWRfa2VybmVsX3R5cGUgPSAibm9ybV9ib3giLAogICAgaCA9IEluZiwKICAgIFJfbWF4ID0gSW5mLAogICAgbGluZWNvbG91ciA9ICJicm93biIsCiAgICBzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpCiAgCiAgbm9fdyA8LSByb3VuZChsb2cocCR3X2luZiAvIHAkd19taW4pIC8gcCRkeCkKICAKICBwYXJhbXMgPC0gc2V0X211bHRpc3BlY2llc19tb2RlbCgKICAgIHNwZWNpZXNfcGFyYW1zLAogICAgbm9fdyA9IG5vX3csCiAgICBsYW1iZGEgPSBwJGxhbWJkYSwKICAgIGthcHBhID0ga2FwcGEsCiAgICB3X3BwX2N1dG9mZiA9IHAkd19wcF9jdXRvZmYsCiAgICBxID0gcCRhbHBoYSwKICAgIHJlc291cmNlX2R5bmFtaWNzID0gInBsYW5rdG9uX2xvZ2lzdGljIikKCiAgcGFyYW1zQHJyX3BwW10gPC0gcCRyMCAqIHBhcmFtc0B3X2Z1bGxeKHAkcmhvIC0gMSkKICByZXR1cm4ocGFyYW1zKQp9CgpwYXJhbXMgPC0gc2V0TW9kZWwocCkKaSA8LSBwJGkwICogcGFyYW1zQHdfZnVsbF4oLXAkbGFtYmRhKSAqIGV4cCgtNi45KihwJGxhbWJkYSAtIDEpKQpgYGAKCiMgV2l0aG91dCBsYXJ2YWwgbW9ydGFsaXR5IG9yIGNhbm5pYmFsaXNtCldlIGZpcnN0IHJ1biB0aGUgbW9kZWwgd2l0aG91dCBsYXJ2YWwgbW9ydGFsaXR5IGFuZCB3aXRob3V0IGNhbm5pYmFsaXNtCmBgYHtyfQpwJG11X2wgPC0gMApwYXJhbXMgPC0gc2V0QW5jaG92eU1vcnQocGFyYW1zLCBwKQpwYXJhbXNAaW50ZXJhY3Rpb25bXSA8LSAwCmBgYAoKV2Ugc2V0IGFuIGluaXRpYWwgYWJ1bmRhbmNlIGFuZCBydW4gZm9yIDEwIHllYXJzLgpgYGB7cn0KcGFyYW1zQGluaXRpYWxfbltdIDwtIDAuMDAxICogcGFyYW1zQHdeKC0xLjgpCnBhcmFtc0Bpbml0aWFsX25fcHBbXSA8LSBwYXJhbXNAY2NfcHAKc2ltIDwtIHByb2plY3QocGFyYW1zLCB0X21heCA9IDEwLCBkdCA9IHAkZHQsIHByb2dyZXNzX2JhciA9IEZBTFNFKQpgYGAKCkF0IHRoaXMgcG9pbnQgd2UgcmVkdWNlIHRoZSBhbmNob3Z5IGFidW5kYW5jZSBieSBhbiBvdmVyYWxsIGZhY3RvciBvZiAxMF43CmFuZCB0aGVuIHJ1biB0aGUgc2ltdWxhdGlvbiBmb3IgYSBmdXJ0aGVyIDMwIHllYXJzLgoKYGBge3J9CnNpbUBuWzExLCAsIF0gPC0gc2ltQG5bMTEsICwgXSAvIDEwXjcKc2ltIDwtIHByb2plY3Qoc2ltLCB0X21heCA9IDMwLCBkdCA9IHAkZHQsIHRfc2F2ZSA9IDAuMiwgcHJvZ3Jlc3NfYmFyID0gRkFMU0UpCmBgYAoKIyMgRmlndXJlIDJhClBsb3R0aW5nIHRoZSBzcGVjdHJhIGF0IHllYXIgMzAgZ2l2ZXMgRmlndXJlIDJhLiBIZXJlIHdlIHBsb3QgdGhlIApwbGFua3RvbiBzcGVjdHJ1bSBhbmQgdGhlIGFuY2hvdnkgc3BlY3RydW0gdXNpbmcgdGhlIHNhbWUgeS1heGlzLgpGaWd1cmUgMmEgaW4gdGhlIHBhcGVyIHVzZXMgZGlmZmVyZW50IGF4ZXMuCmBgYHtyfQpwbG90U3BlY3RyYShzaW0sIHBvd2VyID0gMiwgd2xpbSA9IGMoMWUtOCwgTkEpLCB5bGltID0gYygxZS01LCBOQSksCiAgICAgICAgICAgIHRpbWVfcmFuZ2UgPSAzMCkKYGBgCgpUaGlzIGRvZXMgbm90IGxvb2sgZXhhY3RseSB0aGUgc2FtZSBhcyB0aGUgY29ycmVzcG9uZGluZyBncmFwaCBpbiB0aGUgcGFwZXIKYmVjYXVzZSB0aGUgcGlsZS11cCBpcyBub3Qgc21vb3RoZWQgYnkgZGlmZnVzaW9uLCBidXQgaXQgZGlzcGxheXMgdGhlIHNhbWUgCnF1YWxpdGF0aXZlIGJlaGF2aW91ci4KCgoKIyMgRmlndXJlIDJiCkZpZ3VyZSAyYiBwbG90cyB0aGUgZGVhdGggcmF0ZSBvbiB0aGUgYW5jaG92eSBhcyBhIGZ1bmN0aW9uIG9mIGFuY2hvdnkgYm9keSAKc2l6ZS4KYGBge3J9CnQgPC0gYXMubnVtZXJpYyhkaW1uYW1lcyhzaW1AbikkdGltZSkgPT0gMzAKbnQgPC0gcGFyYW1zQGluaXRpYWxfbiAjIEp1c3QgdG8gZ2V0IHRoZSByaWdodCBkaW1lbnNpb25zCm50W10gPC0gc2ltQG5bdCwgLCBdCm1vcnQgPC0gZ2V0TW9ydChwYXJhbXMsIG4gPSBudCwgbl9wcCA9IHNpbUBuX3BwW3QsIF0sIGVmZm9ydCA9IDApCm1vcnQgPC0gbWVsdChtb3J0KQpwbG90X2x5KG1vcnQpICU+JSAKICAgIGFkZF9saW5lcyh4ID0gfndfcHJleSwgeSA9IH52YWx1ZSkgJT4lIAogICAgbGF5b3V0KHAsIHhheGlzID0gbGlzdCh0eXBlID0gImxvZyIsIGV4cG9uZW50Zm9ybWF0ID0gInBvd2VyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGVfdGV4dCA9ICJib2R5IG1hc3MgKGcpIiksCiAgICAgICAgICAgeWF4aXMgPSBsaXN0KHRpdGxlX3RleHQgPSAiZGVhdGggcmF0ZSAoMS95ZWFyKSIpKQpgYGAKCgojIyBGaWd1cmUgMmMKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KYWJtIDwtIG1lbHQoZ2V0QmlvbWFzcyhzaW0pKQpwYm0gPC0gc2ltQG5fcHAgJSolIChwYXJhbXNAd19mdWxsICogcGFyYW1zQGR3X2Z1bGwpCnBibSA8LSBtZWx0KHBibSkKcGJtJFZhcjIgPC0gTlVMTApwYm0kc3AgPSAiUGxhbmt0b24iCmJtIDwtIHJiaW5kKHBibSwgYWJtKQpwbG90X2x5KGJtKSAlPiUgCiAgICBmaWx0ZXIodGltZSA+PSAxMCkgJT4lIAogICAgYWRkX2xpbmVzKHggPSB+dGltZSwgeSA9IH52YWx1ZSwgY29sb3IgPSB+c3ApICU+JSAKICAgICMgVXNlIGxvZ2FyaXRobWljIGF4ZXMKICAgIGxheW91dChwLCB5YXhpcyA9IGxpc3QodHlwZSA9ICJsb2ciLCBleHBvbmVudGZvcm1hdCA9ICJwb3dlciIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlX3RleHQgPSAiYmlvbWFzcyAoZy9tXjMpIiksCiAgICAgICAgICAgeGF4aXMgPSBsaXN0KHRpdGxlX3RleHQgPSAidGltZSAoeWVhcikiKSkKYGBgCgoKIyBXaXRoIGNhbm5pYmFsaXNtClR1cm4gb24gY2FubmliYWxpc20KYGBge3J9CnBhcmFtc0BpbnRlcmFjdGlvbltdIDwtIDEKYGBgCgpXZSBzZXQgYW4gaW5pdGlhbCBhYnVuZGFuY2UgYW5kIHJ1biBmb3IgMTAgeWVhcnMuCmBgYHtyfQpwYXJhbXNAaW5pdGlhbF9uW10gPC0gMC4wMDEgKiBwYXJhbXNAd14oLTEuOCkKcGFyYW1zQGluaXRpYWxfbl9wcFtdIDwtIHBhcmFtc0BjY19wcApzaW1jIDwtIHByb2plY3QocGFyYW1zLCB0X21heCA9IDEwLCBkdCA9IHAkZHQsIHByb2dyZXNzX2JhciA9IEZBTFNFKQpgYGAKCkF0IHRoaXMgcG9pbnQgd2UgcmVkdWNlIHRoZSBhbmNob3Z5IGFidW5kYW5jZSBieSBhbiBvdmVyYWxsIGZhY3RvciBvZiAxMF43CmFuZCB0aGVuIHJ1biB0aGUgc2ltdWxhdGlvbiBmb3IgYSBmdXJ0aGVyIDMwIHllYXJzLgoKYGBge3J9CnNpbWNAblsxMSwgLCBdIDwtIHNpbWNAblsxMSwgLCBdIC8gMTBeNwpzaW1jIDwtIHByb2plY3Qoc2ltYywgdF9tYXggPSAzMCwgZHQgPSBwJGR0LCB0X3NhdmUgPSAwLjIsIHByb2dyZXNzX2JhciA9IEZBTFNFKQpgYGAKCgojIyBGaWd1cmUgMmQKV2hpbGUgRmlndXJlIDJkIHNob3dzIHRoZSBiYWNrZ3JvdW5kIGRlYXRoIGFuZCB0aGUgbGFydmFsIGRlYXRoIHNlcGFyYXRlbHksCmhlcmUgZm9yIHNpbXBsaWNpdHkgd2UgcGxvdCBvbmx5IHRoZWlyIHN1bS4KYGBge3J9CnQgPC0gYXMubnVtZXJpYyhkaW1uYW1lcyhzaW1jQG4pJHRpbWUpID09IDM2LjgKbnQgPC0gcGFyYW1zQGluaXRpYWxfbiAjIEp1c3QgdG8gZ2V0IHRoZSByaWdodCBkaW1lbnNpb25zCm50W10gPC0gc2ltY0BuW3QsICwgXQptb3J0IDwtIGdldE1vcnQocGFyYW1zLCBuID0gbnQsIG5fcHAgPSBzaW1jQG5fcHBbdCwgXSwgZWZmb3J0ID0gMCkKbW9ydCA8LSBtZWx0KG1vcnQpCnBsb3RfbHkobW9ydCkgJT4lIAogICAgYWRkX2xpbmVzKHggPSB+d19wcmV5LCB5ID0gfnZhbHVlKSAlPiUgCiAgICBsYXlvdXQocCwgeGF4aXMgPSBsaXN0KHR5cGUgPSAibG9nIiwgZXhwb25lbnRmb3JtYXQgPSAicG93ZXIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZV90ZXh0ID0gImJvZHkgbWFzcyAoZykiKSwKICAgICAgICAgICB5YXhpcyA9IGxpc3QodGl0bGVfdGV4dCA9ICJkZWF0aCByYXRlICgxL3llYXIpIikpCmBgYAoKV2UgbWFkZSB0aGUgcGxvdCBmb3IgdGltZSA9IDM2LjggeWVhcnMgYmVjYXVzZSB0aGUgb3NjaWxsYXRpb25zIG9mIHRoZSBzcGVjdHJ1bQphcmUgc2hpZnRlZCB3aXRoIHJlc3BlY3QgdG8gdGhvc2UgaW4gdGhlIHBhcGVyLCBhcyB0aGUgZm9sbG93aW5nIGZpZ3VyZSBzaG93cy4KCiMjIEZpZ3VyZSAyZQpgYGB7cn0KYWJtIDwtIG1lbHQoZ2V0QmlvbWFzcyhzaW1jKSkKYWJtciA8LSBtZWx0KGdldEJpb21hc3Moc2ltYywgbWluX3cgPSAwLjAxLCBtYXhfdyA9IDAuNCkpCmFibXIkc3AgPSAic21hbGwgQW5jaG92eSIKcGJtIDwtIHNpbWNAbl9wcCAlKiUgKHBhcmFtc0B3X2Z1bGwgKiBwYXJhbXNAZHdfZnVsbCkKcGJtIDwtIG1lbHQocGJtKQpwYm0kVmFyMiA8LSBOVUxMCnBibSRzcCA9ICJQbGFua3RvbiIKYm0gPC0gcmJpbmQocGJtLCBhYm0sIGFibXIpCnBsb3RfbHkoYm0pICU+JSAKICAgIGZpbHRlcih0aW1lID49IDEwKSAlPiUgCiAgICBhZGRfbGluZXMoeCA9IH50aW1lLCB5ID0gfnZhbHVlLCBjb2xvciA9IH5zcCkgJT4lIAogICAgIyBVc2UgbG9nYXJpdGhtaWMgYXhlcwogICAgbGF5b3V0KHAsIHlheGlzID0gbGlzdCh0eXBlID0gImxvZyIsIGV4cG9uZW50Zm9ybWF0ID0gInBvd2VyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGVfdGV4dCA9ICJiaW9tYXNzIChnL21eMykiLAogICAgICAgICAgICAgICAgICAgICAgICAgICByYW5nZSA9IGMoLTcsIDIpKSwKICAgICAgICAgICB4YXhpcyA9IGxpc3QodGl0bGVfdGV4dCA9ICJ0aW1lICh5ZWFyKSIpKQpgYGAKCiMjIEFuaW1hdGlvbgpIZXJlIGlzIGFuIGFuaW1hdGlvbiBzaG93aW5nIHRoZSBldm9sdXRpb24gb2YgdGhlCnNwZWN0cmEgZnJvbSB5ZWFyIDI2IHRvIHllYXIgNDAuCmBgYHtyIHdhcm5pbmc9RkFMU0V9Cm5mIDwtIG1lbHQoc2ltY0BuKQpuX3BwZiA8LSBtZWx0KHNpbWNAbl9wcCkKbl9wcGYkc3AgPC0gIlBsYW5rdG9uIgpuZiA8LSByYmluZChuZiwgbl9wcGYpCgpwbG90X2x5KG5mKSAlPiUKICAgICMgc2hvdyBvbmx5IHBhcnQgb2YgcGxhbmt0b24gc3BlY3RydW0KICAgIGZpbHRlcih3ID4gMTBeLTUpICU+JSAKICAgICMgc3RhcnQgYXQgdGltZSAyMAogICAgZmlsdGVyKHRpbWUgPj0gMjYpICU+JSAKICAgICMgY2FsY3VsYXRlIGJpb21hc3MgZGVuc2l0eSB3aXRoIHJlc3BlY3QgdG8gbG9nIHNpemUKICAgIG11dGF0ZShiID0gdmFsdWUgKiB3XjIpICU+JSAKICAgICMgUGxvdCBsaW5lcwogICAgYWRkX2xpbmVzKAogICAgICAgIHggPSB+dywgeSA9IH5iLAogICAgICAgIGNvbG9yID0gfnNwLAogICAgICAgIGZyYW1lID0gfnRpbWUsCiAgICAgICAgbGluZSA9IGxpc3Qoc2ltcGxpZnkgPSBGQUxTRSkKICAgICkgJT4lIAogICAgIyBVc2UgbG9nYXJpdGhtaWMgYXhlcwogICAgbGF5b3V0KHAsIHhheGlzID0gbGlzdCh0eXBlID0gImxvZyIsIGV4cG9uZW50Zm9ybWF0ID0gInBvd2VyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGVfdGV4dCA9ICJib2R5IG1hc3MgKGcpIiksCiAgICAgICAgICAgeWF4aXMgPSBsaXN0KHR5cGUgPSAibG9nIiwgZXhwb25lbnRmb3JtYXQgPSAicG93ZXIiLAogICAgICAgICAgICAgICAgICAgICAgICB0aXRsZV90ZXh0ID0gImJpb21hc3MgKGcvbV4zKSIsCiAgICAgICAgICAgICAgICAgICAgICAgIHJhbmdlID0gYygtOCwgMCkpKQpgYGAKCgoKIyBXaXRoIGxhcnZhbCBtb3J0YWxpdHkKVHVybiBvbiBsYXJ2YWwgbW9ydGFsaXR5CmBgYHtyfQpwJG11X2wgPC0gMjEKcGFyYW1zIDwtIHNldEFuY2hvdnlNb3J0KHBhcmFtcywgcCkKYGBgCgpXZSBzZXQgYW4gaW5pdGlhbCBhYnVuZGFuY2UgYW5kIHJ1biBmb3IgMTAgeWVhcnMuCmBgYHtyfQpwYXJhbXNAaW5pdGlhbF9uW10gPC0gMC4wMDEgKiBwYXJhbXNAd14oLTEuOCkKcGFyYW1zQGluaXRpYWxfbl9wcFtdIDwtIHBhcmFtc0BjY19wcApzaW1sIDwtIHByb2plY3QocGFyYW1zLCB0X21heCA9IDEwLCBkdCA9IHAkZHQsIHByb2dyZXNzX2JhciA9IEZBTFNFKQpgYGAKCkF0IHRoaXMgcG9pbnQgd2UgcmVkdWNlIHRoZSBhbmNob3Z5IGFidW5kYW5jZSBieSBhbiBvdmVyYWxsIGZhY3RvciBvZiAxMF43CmFuZCB0aGVuIHJ1biB0aGUgc2ltdWxhdGlvbiBmb3IgYSBmdXJ0aGVyIDMwIHllYXJzLgoKYGBge3J9CnNpbWxAblsxMSwgLCBdIDwtIHNpbWxAblsxMSwgLCBdIC8gMTBeNwpzaW1sIDwtIHByb2plY3Qoc2ltbCwgdF9tYXggPSAzMCwgZHQgPSBwJGR0LCB0X3NhdmUgPSAwLjIsIHByb2dyZXNzX2JhciA9IEZBTFNFKQpgYGAKCiMjIEZpZ3VyZSAyZgpJIGhhdmUgbm90IHlldCBzcGxpdCB0aGUgbW9ydGFsaXR5IHVwIGludG8gaXRzIGNhdXNlcyBpbiB0aGUgZm9sbG93aW5nIGZpZ3VyZS4gQnV0IG92ZXJhbGwgaXQgbG9va3MgcmlnaHQuCmBgYHtyfQp0IDwtIGFzLm51bWVyaWMoZGltbmFtZXMoc2ltbEBuKSR0aW1lKSA9PSAzMApudCA8LSBwYXJhbXNAaW5pdGlhbF9uICMgSnVzdCB0byBnZXQgdGhlIHJpZ2h0IGRpbWVuc2lvbnMKbnRbXSA8LSBzaW1sQG5bdCwgLCBdCm1vcnQgPC0gZ2V0TW9ydChwYXJhbXMsIG4gPSBudCwgbl9wcCA9IHNpbWxAbl9wcFt0LCBdLCBlZmZvcnQgPSAwKQptb3J0IDwtIG1lbHQobW9ydCkKcGxvdF9seShtb3J0KSAlPiUgCiAgICBhZGRfbGluZXMoeCA9IH53X3ByZXksIHkgPSB+dmFsdWUpICU+JSAKICAgIGxheW91dChwLCB4YXhpcyA9IGxpc3QodHlwZSA9ICJsb2ciLCBleHBvbmVudGZvcm1hdCA9ICJwb3dlciIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlX3RleHQgPSAiYm9keSBtYXNzIChnKSIpLAogICAgICAgICAgIHlheGlzID0gbGlzdCh0aXRsZV90ZXh0ID0gImRlYXRoIHJhdGUgKDEveWVhcikiKSkKYGBgCgojIyBGaWd1cmUgMmcKYGBge3Igd2FybmluZz1GQUxTRX0KYWJtIDwtIG1lbHQoZ2V0QmlvbWFzcyhzaW1sKSkKcGJtIDwtIHNpbWxAbl9wcCAlKiUgKHBhcmFtc0B3X2Z1bGwgKiBwYXJhbXNAZHdfZnVsbCkKcGJtIDwtIG1lbHQocGJtKQpwYm0kVmFyMiA8LSBOVUxMCnBibSRzcCA9ICJQbGFua3RvbiIKYm0gPC0gcmJpbmQoYWJtLCBwYm0pCnBsb3RfbHkoYm0pICU+JSAKICAgIGZpbHRlcih0aW1lID49IDEwKSAlPiUgCiAgICBhZGRfbGluZXMoeCA9IH50aW1lLCB5ID0gfnZhbHVlLCBjb2xvciA9IH5zcCkgJT4lIAogICAgIyBVc2UgbG9nYXJpdGhtaWMgYXhlcwogICAgbGF5b3V0KHAsIHlheGlzID0gbGlzdCh0eXBlID0gImxvZyIsIGV4cG9uZW50Zm9ybWF0ID0gInBvd2VyIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgdGl0bGVfdGV4dCA9ICJiaW9tYXNzIChnL21eMykiLAogICAgICAgICAgICAgICAgICAgICAgICAgICByYW5nZSA9IGMoLTcsIDIpKSwKICAgICAgICAgICB4YXhpcyA9IGxpc3QodGl0bGVfdGV4dCA9ICJ0aW1lICh5ZWFyKSIpKQpgYGAKCiMjIEZpZ3VyZSAzYQoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZ2NwIDwtIHBsb3RHcm93dGhDdXJ2ZXMoc2ltbCwgbWF4X2FnZSA9IDQpCmdjcCArIHNjYWxlX3lfY29udGludW91cyh0cmFucyA9ICJsb2cxMCIpCmBgYAoKIyMgRmlndXJlIDNiCgpgYGB7cn0KdF9taW5faWR4IDwtIHN1bShhcy5udW1lcmljKGRpbW5hbWVzKHNpbWxAbikkdGltZSkgPD0gMTUpCnRfbWF4X2lkeCA8LSBkaW0oc2ltbEBuKVsxXQp0X3N0ZXBfaWR4IDwtIDEgLyAwLjIgICMgMSB5ZWFyIHN0ZXBzCnNzYiA8LSBnZXRTU0Ioc2ltbClbc2VxKHRfbWluX2lkeCwgdF9tYXhfaWR4IC0gdF9zdGVwX2lkeCwgdF9zdGVwX2lkeCldCnJlY19pZHggPC0gc3VtKHBhcmFtc0B3IDwgMTApCm5fcmVjIDwtIHNpbWxAbltzZXEodF9taW5faWR4ICsgdF9zdGVwX2lkeCwgdF9tYXhfaWR4LCB0X3N0ZXBfaWR4KSwgLCByZWNfaWR4XQojIENvbnZlcnQgdG8gZGVuc2l0eSBpbiBsb2cgd2VpZ2h0Cm5fcmVjIDwtIG5fcmVjICogcGFyYW1zQHdbcmVjX2lkeF0KcGxvdChzc2IsIG5fcmVjLCB0eXBlID0gImwiLCBsb2cgPSAieHkiLAogICAgIHhsaW0gPSBjKDFlLTUsIDFlLTEpLCB5bGltID0gYygxZS01LCAxZS0yKSkKYGBgCgoKIyBSYW5kb20gcGxhbmt0b24KClN3aXRjaCBvbiB0aGUgcmFuZG9tbmVzcyBmb3IgcGxhbmt0b24gY2FycnlpbmcgY2FwYWNpdHkgdXNlZCBpbiB0aGUgb3JpZ2luYWwKcGFwZXIuCmBgYHtyfQpzZXQuc2VlZCgwKQpwbGFua3Rvbl9zdGF0ZSRyYW5kb20gPC0gInBhcGVyIgpwbGFua3Rvbl9zdGF0ZSRmYWN0b3IgPC0gMQpgYGAKT2YgY291cnNlIG91ciBmaWd1cmVzIHdpbGwgbm90IGxvb2sgZXhhY3RseSBsaWtlIHRob3NlIGluIHRoZSBwYXBlciBiZWNhdXNlIHdlCndpbGwgZ2V0IGEgZGlmZmVyZW50IHJhbmRvbWlzYXRpb24sIGJ1dCB0aGV5IHdpbGwgYmUgcXVhbGl0YXRpdmVseSB0aGUgc2FtZS4KCldlIHNldCBhbiBpbml0aWFsIGFidW5kYW5jZSBhbmQgcnVuIGZvciAxMCB5ZWFycy4KYGBge3J9CnBhcmFtc0Bpbml0aWFsX25bXSA8LSAwLjAwMSAqIHBhcmFtc0B3XigtMS44KQpwYXJhbXNAaW5pdGlhbF9uX3BwW10gPC0gcGFyYW1zQGNjX3BwCnNpbXIgPC0gcHJvamVjdChwYXJhbXMsIHRfbWF4ID0gMTAsIGR0ID0gcCRkdCwgcHJvZ3Jlc3NfYmFyID0gRkFMU0UpCmBgYAoKQXQgdGhpcyBwb2ludCB3ZSByZWR1Y2UgdGhlIGFuY2hvdnkgYWJ1bmRhbmNlIGJ5IGFuIG92ZXJhbGwgZmFjdG9yIG9mIDEwXjcKYW5kIHRoZW4gcnVuIHRoZSBzaW11bGF0aW9uIGZvciBhIGZ1cnRoZXIgMzAgeWVhcnMuCgpgYGB7cn0Kc2ltckBuWzExLCAsIF0gPC0gc2ltckBuWzExLCAsIF0gLyAxMF43CnNpbXIgPC0gcHJvamVjdChzaW1yLCB0X21heCA9IDMwLCBkdCA9IHAkZHQsIHRfc2F2ZSA9IDAuMiwgcHJvZ3Jlc3NfYmFyID0gRkFMU0UpCmBgYAoKIyMgRmlndXJlIDRhCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmFibSA8LSBtZWx0KGdldEJpb21hc3Moc2ltcikpCnBibSA8LSBzaW1yQG5fcHAgJSolIChwYXJhbXNAd19mdWxsICogcGFyYW1zQGR3X2Z1bGwpCnBibSA8LSBtZWx0KHBibSkKcGJtJFZhcjIgPC0gTlVMTApwYm0kc3AgPSAiUGxhbmt0b24iCmJtIDwtIHJiaW5kKGFibSwgcGJtKQpwbG90X2x5KGJtKSAlPiUgCiAgICBmaWx0ZXIodGltZSA+PSAxMCkgJT4lIAogICAgYWRkX2xpbmVzKHggPSB+dGltZSwgeSA9IH52YWx1ZSwgY29sb3IgPSB+c3ApICU+JSAKICAgICMgVXNlIGxvZ2FyaXRobWljIGF4ZXMKICAgIGxheW91dChwLCB5YXhpcyA9IGxpc3QodHlwZSA9ICJsb2ciLCBleHBvbmVudGZvcm1hdCA9ICJwb3dlciIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlX3RleHQgPSAiYmlvbWFzcyAoZy9tXjMpIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgcmFuZ2UgPSBjKC0zLjIsIDAuOCkpLAogICAgICAgICAgIHhheGlzID0gbGlzdCh0aXRsZV90ZXh0ID0gInRpbWUgKHllYXIpIikpCmBgYAoKIyMgRmlndXJlIDRiCgpgYGB7cn0KdF9taW5faWR4IDwtIHN1bShhcy5udW1lcmljKGRpbW5hbWVzKHNpbXJAbikkdGltZSkgPD0gMTUpCnRfbWF4X2lkeCA8LSBkaW0oc2ltckBuKVsxXQp0X3N0ZXBfaWR4IDwtIDEgLyAwLjIgICMgMSB5ZWFyIHN0ZXBzCnNzYiA8LSBnZXRTU0Ioc2ltcilbc2VxKHRfbWluX2lkeCwgdF9tYXhfaWR4IC0gdF9zdGVwX2lkeCwgdF9zdGVwX2lkeCldCnJlY19pZHggPC0gc3VtKHBhcmFtc0B3IDwgMTApCm5fcmVjIDwtIHNpbXJAbltzZXEodF9taW5faWR4ICsgdF9zdGVwX2lkeCwgdF9tYXhfaWR4LCB0X3N0ZXBfaWR4KSwgLCByZWNfaWR4XQojIENvbnZlcnQgdG8gZGVuc2l0eSBpbiBsb2cgd2VpZ2h0Cm5fcmVjIDwtIG5fcmVjICogcGFyYW1zQHdbcmVjX2lkeF0KcGxvdChzc2IsIG5fcmVjLCBsb2cgPSAieHkiLCB5bGltID0gYygxZS01LCAxZS0xKSwgcGNoID0gMjAsCiAgICAgeGxhYiA9ICJzcGF3bmluZyBzdG9jayBiaW9tYXNzIChnL21eMykiLCB4bGltID0gYygxZS0zLCAxKSwKICAgICB5bGFiID0gImRlbnNpdHkgb2YgcmVjcnVpdHMgKDEvbV4zKSIpCmBgYAoKIyBTdXJ2aXZvcnNoaXAKCiMjIEZpZ3VyZSA1YgoKRmlyc3Qgd2UgY2FsY3VsYXRlIHN1cnZpdm9yc2hpcCBmb3IgYSBjb2hvcnQgYXMgYSBmdW5jdGlvbiBvZiBzaXplLgpgYGB7cn0KCmBgYAoKCiMgUmFuZG9tIHBsYW5rdG9uIGRyaXZlbiBieSByZWQgbm9pc2UKCk9uZSBvZiB0aGUgcmVmZXJlZXMgc3VnZ2VzdGVkIHdlIHNob3VsZCB1c2UgcmVkIG5vaXNlIHRvIGRyaXZlIHRoZSBwbGFua3RvbgpyYW5kb21uZXNzLiBTbyB3ZSBub3cgbXVsdGlwbHkgdGhlIGNhcnJ5aW5nIGNhcGFjaXR5IG9mIHRoZSBwbGFua3RvbiBieSBhCmZhY3RvciBnaXZlbiBieSB0aGUgZXhwb25lbnRpYWwgb2YgYW4gQVIoMSkgcHJvY2Vzcy4gRGVub3RpbmcgdGhlIGNhcnJ5aW5nCmNhcGFjaXR5IGF0IHRpbWUgJHQkIGZvciBwbGFua3RvbiBvZiBzaXplICR3JCwgd2UgdXNlCiQkSyh3LCB0KSA9IEsodywgMCkgIFxleHAoWCh0KSkkJAp3aGVyZQokJFgodCtkdCkgPSAoMSAtIDAuNVwsZHQpIFgodCkgKyAxMFwsIFxldGEodClcLCBkdCQkCmFuZCAkXGV0YSh0KSQgYXJlIGluZGVwZW5kZW50IHN0YW5kYXJkIG5vcm1hbGx5IGRpc3RyaWJ1dGVkIHJhbmRvbSB2YXJpYWJsZXMuIApXZSBzdGFydCB3aXRoICRYKDApPTAkLiBUaGlzIHByb2Nlc3MgY2FuIGJlIHNlZW4gYXMgdGhlIGRpc2NyZXRpc2F0aW9uIG9mIHRoZSAKT3Juc3RlaW4tVWhsZW5iZWNrIHByb2Nlc3Mgc2F0aXNmeWluZyB0aGUgU0RFCiQkZFgodCkgPSAtMC41XCwgWCh0KVwsIGR0ICsgMTBcLCBkVyh0KSQkCndoZXJlICRXJCBpcyB0aGUgV2llbmVyIHByb2Nlc3MuCgpUaGUgcmFuZG9tIGZhY3RvciAkRih0KT1cZXhwKFgodCkpJCBzYXRpc2ZpZXMKJCRGKHQrZHQpID0gRih0KV57MS0wLjVkdH1cZXhwKDEwXCxcZXRhXCwgZHQpJCQKd2l0aCAkRigwKT0xJC4gV2Ugd2lsbCB1c2UgYSB0aW1lIHN0ZXAgXChkdCA9XCkgYHIgcCRkdGAKYGBge3J9CnNldC5zZWVkKDApCnBsYW5rdG9uX3N0YXRlJHJhbmRvbSA8LSAicmVkIgpwbGFua3Rvbl9zdGF0ZSRmYWN0b3IgPC0gMQpwbGFua3Rvbl9zdGF0ZSRzaWdtYSA8LSAxMCAqIHAkZHQKcGxhbmt0b25fc3RhdGUkcGhpIDwtIDEgLSAwLjUgKiBwJGR0CmBgYAoKV2Ugc2V0IGFuIGluaXRpYWwgYWJ1bmRhbmNlIGFuZCBydW4gZm9yIDEwIHllYXJzLgpgYGB7cn0KcGFyYW1zQGluaXRpYWxfbltdIDwtIDAuMDAxICogcGFyYW1zQHdeKC0xLjgpCnBhcmFtc0Bpbml0aWFsX25fcHBbXSA8LSBwYXJhbXNAY2NfcHAKc2ltcnIgPC0gcHJvamVjdChwYXJhbXMsIHRfbWF4ID0gMTAsIGR0ID0gcCRkdCwgcHJvZ3Jlc3NfYmFyID0gRkFMU0UpCmBgYAoKQXQgdGhpcyBwb2ludCB3ZSByZWR1Y2UgdGhlIGFuY2hvdnkgYWJ1bmRhbmNlIGJ5IGFuIG92ZXJhbGwgZmFjdG9yIG9mIDEwXjcKYW5kIHRoZW4gcnVuIHRoZSBzaW11bGF0aW9uIGZvciBhIGZ1cnRoZXIgMzAgeWVhcnMuCgpgYGB7cn0Kc2ltcnJAblsxMSwgLCBdIDwtIHNpbXJyQG5bMTEsICwgXSAvIDEwXjcKc2ltcnIgPC0gcHJvamVjdChzaW1yciwgdF9tYXggPSAzMCwgZHQgPSBwJGR0LCB0X3NhdmUgPSAwLjEsIHByb2dyZXNzX2JhciA9IEZBTFNFKQpgYGAKCiMjIEZpZ3VyZSA0YQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQphYm0gPC0gbWVsdChnZXRCaW9tYXNzKHNpbXJyKSkKcGJtIDwtIHNpbXJyQG5fcHAgJSolIChwYXJhbXNAd19mdWxsICogcGFyYW1zQGR3X2Z1bGwpCnBibSA8LSBtZWx0KHBibSkKcGJtJFZhcjIgPC0gTlVMTApwYm0kc3AgPSAiUGxhbmt0b24iCmJtIDwtIHJiaW5kKGFibSwgcGJtKQpwbG90X2x5KGJtKSAlPiUgCiAgICBmaWx0ZXIodGltZSA+PSAxMCkgJT4lIAogICAgYWRkX2xpbmVzKHggPSB+dGltZSwgeSA9IH52YWx1ZSwgY29sb3IgPSB+c3ApICU+JSAKICAgICMgVXNlIGxvZ2FyaXRobWljIGF4ZXMKICAgIGxheW91dChwLCB5YXhpcyA9IGxpc3QodHlwZSA9ICJsb2ciLCBleHBvbmVudGZvcm1hdCA9ICJwb3dlciIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlX3RleHQgPSAiYmlvbWFzcyAoZy9tXjMpIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgcmFuZ2UgPSBjKC0zLCAwLjgpKSwKICAgICAgICAgICB4YXhpcyA9IGxpc3QodGl0bGVfdGV4dCA9ICJ0aW1lICh5ZWFyKSIpKQpgYGAKCiMjIEZpZ3VyZSA0YgoKYGBge3J9CnRfbWluX2lkeCA8LSBzdW0oYXMubnVtZXJpYyhkaW1uYW1lcyhzaW1yckBuKSR0aW1lKSA8PSAxNSkKdF9tYXhfaWR4IDwtIGRpbShzaW1yckBuKVsxXQp0X3N0ZXBfaWR4IDwtIDEgLyAwLjEgICMgMSB5ZWFyIHN0ZXBzCnNzYiA8LSBnZXRTU0Ioc2ltcnIpW3NlcSh0X21pbl9pZHgsIHRfbWF4X2lkeCAtIHRfc3RlcF9pZHgsIHRfc3RlcF9pZHgpXQpyZWNfaWR4IDwtIHN1bShwYXJhbXNAdyA8IDEwKQpuX3JlYyA8LSBzaW1yckBuW3NlcSh0X21pbl9pZHggKyB0X3N0ZXBfaWR4LCB0X21heF9pZHgsIHRfc3RlcF9pZHgpLCAsIHJlY19pZHhdCiMgQ29udmVydCB0byBkZW5zaXR5IGluIGxvZyB3ZWlnaHQKbl9yZWMgPC0gbl9yZWMgKiBwYXJhbXNAd1tyZWNfaWR4XQpwbG90KHNzYiwgbl9yZWMsIGxvZyA9ICJ4eSIsIHlsaW0gPSBjKDFlLTUsIDFlLTEpLCBwY2ggPSAyMCwKICAgICB4bGFiID0gInNwYXduaW5nIHN0b2NrIGJpb21hc3MgKGcvbV4zKSIsIHhsaW0gPSBjKDFlLTMsIDEpLAogICAgIHlsYWIgPSAiZGVuc2l0eSBvZiByZWNydWl0cyAoMS9tXjMpIikKYGBgCg==