Introduction
In this talk, we explore the connection between the brain’s ability to predict and higher cognition (the role of prediction in ‘higher’ cognition). In particular, we take a closer look at the much-discussed connection between prediction and mental imagery (Moulton & Kosslyn, Koziol, Pezzulo, Andy Clark, Gambi & Pickering).
We implement a simple agent, consisting of a sensor, an internal state and an algorithm allowing the agent to perform sensory inference. The internal state can encode prior knowledge in the form of beliefs about himself and the environment (the agent and the environment together constitute the world).
The primary goal of the agent is to perform sensory inference about his rotational velocity \(\omega\) in real time.
In order to perform real time inference, the agent performs particle filtering (sequential Monte Carlo, or SMC). We implement the simplest form of SMC, the bootstrap particle filter, or SMC with multinomial resampling.
The goal of the agent is simply to track his rotational velocity during a simple event. Events consist of sinusoidal acceleration to the left or the right:
\[ \frac{d\omega}{dt} = A \sin(2\pi\frac{t}{T}) \]
This type of acceleration reflects a natural head movement to one side, and within a frequency band of \(0.1 - 100\) [check this], the SCC provides measurement signal that are proportional to the velocity:
\[ \omega = A\frac{T}{2\pi}\Big(1-\cos(2\pi \frac{t}{T})\Big) \]
We choose a frequency \(\mathcal{f}\) of 0.5 Hz. The agent’s sensor provides a sequence of noisy measurements \(y_{t}\) of his angular velocity \(\omega^{true}_{t}\):
\[ y_{t} \sim \mathcal{N}(\omega^{true}_{t}, \sigma^{2}_{sensor}) \]
where \(\omega^{true}_{t}\) is the actual angular velocity, and \(\sigma^{2}_{sensor}\) is the noise of the sensor (physical characteristic of the sensor).
Figure 1 shows the acceleration, velocity, resulting angular deflection, and the agent’s noisy sensory measurements:
set.seed(8529573L)
data <- generate_data(T = 2, amplitude = 20, sensor_sd = 1.7) %>%
t() %>%
data.frame()
plot_trajectories(data = data)

For all simulation, we use a sensor standard deviation \(\sigma^{2}_{sensor}\) of \(1.7^\circ\).
Particle filter implementation
We will go step-by-step through the basic SMC algorithm. The agents goal is to infer the current angular velocity \(\omega_{t}\), which is a latent variable, given noisy sensory measurements of \(\omega_{t}\). The agent thus requires a generative model of its measurements, which in this case is given by:
\[ y_{t} \sim \mathcal{N}(\omega_{t}, \sigma^2_y) \]
This is the agent’s measurement model:
- \(\sigma^2_y\) is the agent’s model of the sensor noise - this is distinct from the actual (true) sensor noise \(\sigma^2_{sensor}\).
In addition, the agent must have a model of the evolution of its state variable through time, i.e. a model of the dynamics of the latent state \(\omega\). This is given by:
\[ \omega_{t} \sim \mathcal{N}(\omega_{t-1} + A \sin(\frac{2\pi t}{T}), \sigma^2_{process}) \]
where \(A \sin(\frac{2\pi t}{T})\) represents a ‘known’ control input and \(\sigma^2_{process}\) is the process standard deviation. This term encodes the agent’s certainty in his process model. The control input is assumed to have been learned by the agent, and represent knowledge of the sensory consequences of active head movements. This represents the concept typically known as an ‘efference copy’, although in our model this is merely a statistical model, of the sensory effects of motor action, and is thus equivalent to a ‘known’ covariate that the agent can use to predict the latent state.
Particle filter step-by-step (during real-time interaction with the environment)
prior to filtering: The agent chooses parameters for the filtering algorithm:
sdx <- 0.5 # process noise
sdy <- 2 # sensor noise
A <- 2 # motion amplitude
The agent also decides which process model to use:
# process model (transition model)
f <- function(x, Time, A, sd, N) {
rnorm(n = N, mean = x[, ] + A * sin(2*pi/Time), sd = sd)
}
In addition, the agent decides how many resources to allocate to this particular problem, in the form of the number of particles (samples) to use.
at \(t_0\): The agent starts by making an initial guess about \(\omega\). This means that the agent draws a sample from the initial distribution; in our model, we assume that the agent starts in an unbiased state with a high degree of certainty:
In the following code, the state variable \(\omega_t\) is denoted as \(x_t\).
# x is drawn from the prior distribution with
# expected value 0 and a small standard deviation 0.1)
# The agent has decided to use 100 particles
N <- 100
x_init <- rnorm(N, 0, 0.1)

The agent thus represents his belief about the initial velocity as a collection of 100 samples from the prior distribution.
The agent then predicts the state at the next time increment \(t_1\) by applying the process model to each of the \(N\) particles. The process model reflects the agents knowledge about Newtonian dynamics:
Time <- 20
# N <- 100
x <- matrix(rep(0, N*Time), nrow = N, ncol = Time) #matrix(nrow = N, ncol = Time)
weights <- matrix(rep(0, N*Time), nrow = N, ncol = Time)
xmean <- rep(0, Time) # mean of estimated state
xvar <- rep(0, Time) # variance of estimated state
x[, 1] <- rnorm(n = N, mean = x_init + A * sin(2*pi/Time), sdx)
# x[, 1] <- f(x_init, Time, A, sd = sdx, N)

In MCMC terminology, the predicted states represent samples from a proposal distribution.
at \(t_1\): There are sensory measurements available, so the agent can use these in order to update his internal estimate of his state. To do so, he evaluates the likelihood of each particle, i.e. he evaluated the probability of observing the measurement at time \(t_1\) given the predicted velocity:
weights[, 1] <- dnorm(data$observations[1], x[, 1], sdy)
The probabilities are then used as importance weights for each particle. Intuitively, this means that the agent selects those particles that predicted the data well, and discards those particles that predicted the data poorly. This is achieved by a weighted sampling with replacement from the set of particles (multinomial resampling). The weights are first normalized, so that they represent a probability distribution.
x[, 1] <- sample(x[, 1], replace = TRUE, size = N, prob = weights[, 1])
xmean[1] <- mean(x[, 1])
xvar <- var(x[, 1])
By applying this simple procedure recursively, the agent can track his latent velocity, given the sequence of noisy sensory measurements. At any time step, the agent thus performs the following sequence of computations:
- prediction (propagation) step: predict the state 1 step ahead
- update step: obtain importance weights from sensory measurements, and select particles for ‘survival’
- compute summary statistics, e.g. mean and variance of estimated state
Figure 2 shows a visualization of the computations performed at each time step. After the prediction step, the set of particles represent the new belief before ‘seeing’ the new evidence. All particles thus have equal weights, given \(\frac{1}{N}\). Subsequently, the probability of observing the evidence is evaluated for each particle, giving new weight. Each particle’s size reflects its importance, i.e. how well it predicted the new measurement. The final step consists of sampling 100 new particles with replacement from the set of particles, with a probability of being chosen given by their importance weights. (This is the multinomial resampling part). Particles that did not predict the data well may therefore be eliminated.
The purple line shows the estimated mean of the distribution being ‘shifted’ during a single time increment, and the black rectangle show the observations; at the first step, before seeing the new data, the observation is at the previous value. At the updating step (step 2), a new measurement is available. The closer to the measurement, the larger the diameter of the particle.
Warning: Removed 1 rows containing missing values (geom_point).

Figure 2 demonstrates how, during real-time interaction with the environment, 1-step ahead prediction is performed continuously and is a vital ingredient in (normal) sensory inference.
Predicting k steps ahead (what happens when data are unavailable)
Next, we consider an interaction episode during which sensory data temporarily become unavailable.
In the visual system, this is fairly common: lights out, eyes closed, fog, etc. What are analogies in the the vestibular system?
Figure 3 shows the agent enganged in real-time sensory inference during a 2 second motion event. The dotted line shows the true velocity, the black rectangles are the sensory measurements, the solid line show the agents estimated head velocity, and the bands surrounding the solid line reflect the agents \(95\%\) credible interval.
Due to the process of predicting and updating, the confidence region remains approximately constant throughout the event. Predicting increases uncertainty, updating reduces it again.
Figure 4 shows the same sensory event, but after 1 seconds, there is sensor failure, and the agent no longer receives any measurements. Forced to rely on his internal model, the agent is only able to predict the next steps, without being able to update. This is implemented by letting the agent monitor whether data are available, and then performing weighting according to the likelihood if they are. IN the case of missing data, the agent simply assigns a uniform probability distribution to the weights. Resampling is subsequently performed, but if the data are missing, this has no effect, because the resampled set of particles are simply drawn with equal probabilities from the old set. The particles therefore do not move torward the target distribution, and the variance of the samples increases over time. Note that the estimate remains unbiased, because the agent is using a ‘good’ generative model, i.e. the agent is correctly modelling the cause of the true velocity. This is illustrated by the fact that the estimated line lies ‘on top of’ the true velocity. (In fact, if the agent is using a good process model, the recovered estimate is actually better if he is not forced to incorporate noisy measurements; maybe the figure should not show this?).
Many would claim that this is already imagery, of guided hallucination…
run_particle_filter <- function(data, N, Time, x_init, sdx_init,
params, resample = TRUE, rs_thresh = 0.5) {
sdc <- params$sdc
sdx <- params$sdx
sdy <- params$sdy
fun_x <- params$funx_x
fun_c <- params$fun_c
A <- params$A
x <- matrix(rep(0, N*Time), nrow = N, ncol = Time) #matrix(nrow = N, ncol = Time)
weights <- matrix(rep(0, N*Time), nrow = N, ncol = Time) #matrix(nrow = N, ncol = Time)
loglik <- rep(0, Time)
x[, 1] <- rnorm(N, x_init, sdx_init)
weights[, 1] <- dnorm(data$observations[1], x[, 1], sdy)
weights[, 1] <- weights[, 1]/sum(weights[, 1])
x[, 1] <- sample(x[, 1], replace = TRUE, size = N, prob = weights[, 1])
for (t in seq(2, Time)) {
x[, t] <- f(x, t, Time, A, sd = sdx, N)
if (!is.na(data$observations[t])) {
weights[, t] <- dnorm(data$observations[t], x[, t], sdy)
} else {
weights[, t] <- 1/N
}
if (resample) {
if (neff(weights[, t]) < rs_thresh * N) {
x[, t] <- sample(x[, t], replace = TRUE, size = N, prob = weights[, t])
}
}
# TODO: do we need to reset weights after resampling?
# weights[, t] <- 1/N
}
out <- list(x = x, weights = weights, loglik = loglik,
x_means = apply(x, 2, mean),
x_medians = apply(x, 2, median),
x_quantiles = apply(x, 2,
function(x) quantile(x,
probs = c(0.025,
0.975))),
Time = Time,
N = N)
}
f <- function(x, t, Time, A, sd, N) {
rnorm(n = N, mean = x[, t-1] + A * sin(2*pi*(t-1)/Time), sd = sd)
}
f1 <- function(x, t, Time, A, sd, N) {
rnorm(n = N, mean = x[, t-1], sd = sd)
}
f2 <- function(x, t, Time, A, sd, N) {
# A * sin(2*pi*(t-1)/Time)
rnorm(n = N, mean = A * sin(2*pi*(t-1)/Time), sd = sd)
}
params <- list(sdx = 1.2, sdy = 4.0, A = 2.0, fun_x = f)
out <- run_particle_filter(data = data, N = 100, Time = length(data$observations),
x_init = 0, sdx_init = 0.5,
params, resample = TRUE, rs_thresh = 0.5)
plot_filtering_estimates(out, data = data)

params <- list(sdx = 1.2, sdy = 4.0, A = 2.0, fun_x = f)
data_missing <- data
data_missing$observations[10:length(data_missing$observations)] <- NA
out <- run_particle_filter(data = data_missing, N = 100, Time = length(data$observations),
x_init = 0, sdx_init = 0.5,
params, resample = TRUE, rs_thresh = 0.5)
plot_filtering_estimates(out, data = data_missing, predict = TRUE)

Running the particle filter with a misspecified process model
The next two Figures show what can happen when running the particle filter using a ‘wrong’ process model. Here, the agent believes that the direction of motion is in the opposite direction to the actual motion, leading to a misinterpretation.
params <- list(sdx = 1.2, sdy = 4.0, A = -2, fun_x = f)
out <- run_particle_filter(data = data, N = 100, Time = length(data$observations),
x_init = 0, sdx_init = 0.5,
params, resample = TRUE, rs_thresh = 0.5)
plot_filtering_estimates(out, data = data)

In the first Figure, the agent has a high degree of certainy in his process model: \(\sigma_{process}\) = 2.8.
params <- list(sdx = 2.2, sdy = 4.0, A = -2, fun_x = f)
out <- run_particle_filter(data = data, N = 100, Time = length(data$observations),
x_init = 0, sdx_init = 0.5,
params, resample = TRUE, rs_thresh = 0.5)
plot_filtering_estimates(out, data = data)

In the second Figure, the agent has a lower degree of certainy in his process model: \(\sigma_{process}\) = 2.8.
Thus, using the same process model, with the same sensory input, the agent may interpret the data differently, depending on how certain he is in his own predictions (due to his process model).
Question: But is this already enough for imagery/SPT?
I think not, because in all the above scenarios, the agent was still engaged in real-time interaction with the environment, i.e. the agent’s goal was to explain the sensory. IN all cases, he wanted to uncover the causes of his sensory input, and was able to allow for missing data, or used a wrong process model.
Running the particle filter offline (without resampling)
Now comes the important next step: in order to perform SPT, etc., the agent must actively disengage from his real-time interaction with the environment, otherwise he would perform compensatory eye movements, etc. But what can the agent do in order to go offline? Of course, assuming the agent resuses his sensory circuit for ‘cognition’.
In addition to the previous abilities:
- ability to predict (1 step ahead)
- ability to deal with missing data (predict multiple (k) steps ahead)
- ability to apply a process model (control signal)
the agent must perform an active intervention in his probabilistic model; our proposal is that he can change his resampling strategy - he can choose not to resample. By not resampling he can ignore the incoming data.
An advantage of this strategy is that he is running a model, and the sensory data are still coming in. Therefore, he can still monitor the likelihood of his model, i.e. he can do a reality check (hypothesis test) to make sure that his ‘fantasy’ model does not explain reality, i.e. it is not real.
The next Figure shows the agent’s sensory input whilst remaining stationary.
set.seed(8529573L)
data_offline <- generate_data(T = 2, amplitude = 0, sensor_sd = 1.7) %>%
t() %>%
data.frame()
plot_trajectories(data = data_offline)

The last two Figures show the agent shows the agent engaged in ‘imagining’ a rightward motion, with amplitude \(A\) = -2, using two different degrees of certainty. In the first, the agents
params <- list(sdx = 0.8, sdy = 4.0, A = 5, fun_x = f)
out <- run_particle_filter(data = data_offline, N = 100, Time = length(data$observations),
x_init = 0, sdx_init = 0.5,
params, resample = FALSE, rs_thresh = 0.5)
plot_filtering_estimates(out, data = data_offline)

In the first, \(\sigma_{process}\) = 2.8; therefore, the agent is very certain of his belief, i.e. he is experiencing vivid imagery.
params <- list(sdx = 2.8, sdy = 4.0, A = -2, fun_x = f)
out <- run_particle_filter(data = data_offline, N = 100, Time = length(data$observations),
x_init = 0, sdx_init = 0.5,
params, resample = FALSE, rs_thresh = 0.5)
plot_filtering_estimates(out, data = data_offline)

In the second, \(\sigma_{process}\) = 2.8; therefore, the agent is very uncertain of his belief, i.e. his imagery is not very vivid.
Note, however, that in both cases, the agent is not interested in ‘explaining’ the sensory data, i.e. his imagined motion is not constrained by the measurements.
LS0tCnRpdGxlOiAiU2ltcGxlIHBhcnRpY2xlIGZpbHRlciBkZW1vIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIGZpZ19jYXB0aW9uOiB5ZXMKICAgIGZpZ19oZWlnaHQ6IDUKICAgIGZpZ193aWR0aDogNwogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMKICAgIHRoZW1lOiBzcGFjZWxhYgogICAgdG9jOiB5ZXMKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiB5ZXMKICB3b3JkX2RvY3VtZW50OgogICAgZmlnX2hlaWdodDogOQogICAgZmlnX3dpZHRoOiAxMgogICAgdG9jOiB5ZXMKLS0tCgpgYGB7ciBwcmVsaW1pbmFyeSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHRpZHlyKQoKa25pdHI6Om9wdHNfY2h1bmskc2V0KGZpZy53aWR0aD0xMiwgZmlnLmhlaWdodD04LAogICAgICAgICAgICAgICAgICAgICAgZHBpID0gMzAwLCBmaWcucGF0aCA9ICJGaWd1cmVzLyIsIAogICAgICAgICAgICAgICAgICAgICAgZGV2PWMoJ3BkZicsICdwbmcnKSkgCgojIHBsb3Qgc2V0dGluZ3MgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KbGlicmFyeSh2aXJpZGlzKQpjb2xvcl9wYWxldHRlIDwtIHZpcmlkaXM6OnBsYXNtYShuID0gOSkKIyBjYl9wYWxldHRlIDwtIGMoIiMwMDAwMDAiLCAiI0U2OUYwMCIsICIjNTZCNEU5IiwgIiNDQzc5QTciLCAiI0YwRTQ0MiIsCiAgICAgICAgICAgICAgICAjICIjMDA3MkIyIiwgIiNENTVFMDAiLCAiIzAwOUU3MyIsICJncmV5ODAiKQojIGdncGxvdDI6OnRoZW1lX3NldCh0aGVtZV9idygpKQpnZ3Bsb3QyOjp0aGVtZV9zZXQodGhlbWVfY2xhc3NpYygpICsgCmdncGxvdDI6OnRoZW1lKGF4aXMubGluZS54ID0gZWxlbWVudF9saW5lKGNvbG91ciA9ICdibGFjaycsIHNpemUgPSAwLjUsIGxpbmV0eXBlID0gJ3NvbGlkJyksCiAgICAgICAgICAgICAgYXhpcy5saW5lLnkgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gJ2JsYWNrJywgc2l6ZSA9IDAuNSwgbGluZXR5cGUgPSAnc29saWQnKSkgKwogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLCB0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNikpKQpgYGAKUHJlbGltaW5hcnkgc3R1ZmYKYGBge3IgZ2VuZXJhdGUtZGF0YS1mdW4sIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CiMgZ2VuZXJhdGUgdHJhamVjdG9yeSBhbmQgbm9pc3kgbWVhc3VyZW1lbnRzIC0tLS0KZ2VuZXJhdGVfZGF0YSA8LSBmdW5jdGlvbihUID0gMiwgZHQgPSAwLjEsIGFtcGxpdHVkZSA9IDIwLCBzZW5zb3Jfc2QgPSAxLjcpIHsKICAgIG5zdGVwcyA8LSBUL2R0CiAgICB0IDwtIHNlcShmcm9tID0gMCwgdG8gPSBULCBsZW5ndGgub3V0ID0gbnN0ZXBzKQogICAgCiAgICAjIHRoZSBmb2xsb3dpbmcgZ2VuZXJhdGVzIGEgbW90aW9uIHByb2ZpbGUgd2l0aCBzaW5nbGUtY3ljbGUgc2ludXNvaWRhbAogICAgIyBhY2NlbGVyYXRpb24KICAgIHRpbWUgPC0gdAogICAgcG9zaXRpb24gPC0gYW1wbGl0dWRlKlQvKDIqcGkpICogKHQtKFQvKDIqcGkpKSAqIHNpbigyKnBpKnQvVCkpCiAgICB2ZWxvY2l0eSA8LSBhbXBsaXR1ZGUgKiBULygyICogcGkpICogKDEtY29zKDIgKiBwaSAqIHQvVCkpCiAgICBhY2NlbGVyYXRpb24gPC0gYW1wbGl0dWRlICogc2luKDIgKiBwaSAqIHQvVCkKICAgIHRyYWplY3RvcnkgPC0gcmJpbmQocG9zaXRpb24sIHZlbG9jaXR5LCBhY2NlbGVyYXRpb24pCgogICAgb2JzZXJ2YXRpb25zIDwtIHJub3JtKG5jb2wodHJhamVjdG9yeSksIHRyYWplY3RvcnlbMixdLCBzZW5zb3Jfc2QpCiAgICBvdXQgPC0gcmJpbmQodGltZSwgdHJhamVjdG9yeSwgb2JzZXJ2YXRpb25zKQp9CmBgYAoKCmBgYHtyIGhlbHBlci1mdW5jdGlvbnMsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CnNkMnByZWNpc2lvbiA8LSBmdW5jdGlvbihzZCkgewogICAgcHJlYyA8LSAxLyhzZF4yKQogICAgcHJlYwp9CgpuZWZmIDwtIGZ1bmN0aW9uKHdlaWdodHMpIHsKICAgIDEvc3VtKHdlaWdodHNeMikKfQoKTW9kZSA8LSBmdW5jdGlvbih2KSB7CiAgIHVuaXF2IDwtIHVuaXF1ZSh2KQogICB1bmlxdlt3aGljaC5tYXgodGFidWxhdGUobWF0Y2godiwgdW5pcXYpKSldCn0KYGBgCgoKYGBge3IgcGxvdF90cmFqZWN0b3J5LWZ1biwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KcGxvdF90cmFqZWN0b3JpZXMgPC0gZnVuY3Rpb24oZGF0YSkgewogICAgc2V0LnNlZWQoNDQyMzQpCiAgICBkYXRhIDwtIGRhdGEgJT4lIGdhdGhlcihrZXkgPSAia2V5IiwgdmFsdWUgPSAidmFsdWUiLCAtdGltZSkKICAgIAogICAgZyA8LSBnZ3Bsb3QoZGF0YSA9IGRhdGEsIGFlcyh4ID0gdGltZSwgeSA9IHZhbHVlLCBjb2xvciA9IGtleSkpICsKICAgICAgICBnZW9tX2xpbmUoZGF0YSA9IGZpbHRlcihkYXRhLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrZXkgJWluJSBjKCJhY2NlbGVyYXRpb24iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ2ZWxvY2l0eSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInBvc2l0aW9uIikpLAogICAgICAgICAgICAgICAgICBzaXplID0gMikgKyAKICAgICAgICBnZW9tX3BvaW50KGRhdGEgPSBmaWx0ZXIoZGF0YSwga2V5ID09ICJvYnNlcnZhdGlvbnMiKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSAzLCBzaGFwZSA9IDE1LCBjb2xvciA9ICJibGFjayIpICsKICAgICAgICB4bGFiKCJUaW1lIikgKyB5bGFiKCJBbmd1bGFyIHZlbG9jaXR5IFtkZWddIikgKwogICAgICAgICMgbGFicyh0aXRsZSA9ICJOYXR1cmFsIGhlYWQgbW90aW9uIikgKwogICAgICAgICMgc2NhbGVfY29sb3VyX2JyZXdlcihwYWxldHRlID0gIlNldDEiKQogICAgICAgIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gc2FtcGxlKGNvbG9yX3BhbGV0dGUpKSArCiAgICAgICAgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQogICAgcHJpbnQoZykgICAgCn0KYGBgCiMgSW50cm9kdWN0aW9uCgpJbiB0aGlzIHRhbGssIHdlIGV4cGxvcmUgdGhlIGNvbm5lY3Rpb24gYmV0d2VlbiB0aGUgYnJhaW4ncyBhYmlsaXR5IHRvIHByZWRpY3QgYW5kIGhpZ2hlciBjb2duaXRpb24gKHRoZSByb2xlIG9mIHByZWRpY3Rpb24gaW4gJ2hpZ2hlcicgY29nbml0aW9uKS4gSW4gcGFydGljdWxhciwgd2UgdGFrZSBhIGNsb3NlciBsb29rIGF0IHRoZSBtdWNoLWRpc2N1c3NlZCBjb25uZWN0aW9uIGJldHdlZW4gcHJlZGljdGlvbiBhbmQgbWVudGFsIGltYWdlcnkgKE1vdWx0b24gJiBLb3NzbHluLCBLb3ppb2wsIFBlenp1bG8sIEFuZHkgQ2xhcmssIEdhbWJpICYgUGlja2VyaW5nKS4KCldlIGltcGxlbWVudCBhIHNpbXBsZSBhZ2VudCwgY29uc2lzdGluZyBvZiBhIHNlbnNvciwgYW4gaW50ZXJuYWwgc3RhdGUgYW5kIGFuIGFsZ29yaXRobSBhbGxvd2luZyB0aGUgYWdlbnQgdG8gcGVyZm9ybSBzZW5zb3J5IGluZmVyZW5jZS4gVGhlIGludGVybmFsIHN0YXRlIGNhbiBlbmNvZGUgcHJpb3Iga25vd2xlZGdlIGluIHRoZSBmb3JtIG9mIGJlbGllZnMgYWJvdXQgaGltc2VsZiBhbmQgdGhlIGVudmlyb25tZW50ICh0aGUgX2FnZW50XyBhbmQgdGhlIF9lbnZpcm9ubWVudF8gdG9nZXRoZXIgY29uc3RpdHV0ZSB0aGUgX3dvcmxkXykuCgpUaGUgcHJpbWFyeSBnb2FsIG9mIHRoZSBhZ2VudCBpcyB0byBwZXJmb3JtIHNlbnNvcnkgaW5mZXJlbmNlIGFib3V0IGhpcyByb3RhdGlvbmFsIHZlbG9jaXR5ICRcb21lZ2EkIGluIF9yZWFsIHRpbWVfLiAKCkluIG9yZGVyIHRvIHBlcmZvcm0gcmVhbCB0aW1lIGluZmVyZW5jZSwgdGhlIGFnZW50IHBlcmZvcm1zIHBhcnRpY2xlIGZpbHRlcmluZyAoc2VxdWVudGlhbCBNb250ZSBDYXJsbywgb3IgU01DKS4gV2UgaW1wbGVtZW50IHRoZSBzaW1wbGVzdCBmb3JtIG9mIFNNQywgdGhlIGJvb3RzdHJhcCBwYXJ0aWNsZSBmaWx0ZXIsIG9yIFNNQyB3aXRoIG11bHRpbm9taWFsIHJlc2FtcGxpbmcuCgpUaGUgX2dvYWxfIG9mIHRoZSBhZ2VudCBpcyBzaW1wbHkgdG8gdHJhY2sgaGlzIHJvdGF0aW9uYWwgdmVsb2NpdHkgZHVyaW5nIGEgc2ltcGxlIGV2ZW50LiBFdmVudHMgY29uc2lzdCBvZiBzaW51c29pZGFsIGFjY2VsZXJhdGlvbiB0byB0aGUgbGVmdCBvciB0aGUgcmlnaHQ6IAoKJCQgXGZyYWN7ZFxvbWVnYX17ZHR9ID0gQSBcc2luKDJccGlcZnJhY3t0fXtUfSkgJCQKClRoaXMgdHlwZSBvZiBhY2NlbGVyYXRpb24gcmVmbGVjdHMgYSBuYXR1cmFsIGhlYWQgbW92ZW1lbnQgdG8gb25lIHNpZGUsIGFuZCB3aXRoaW4gYSBmcmVxdWVuY3kgYmFuZCBvZiAkMC4xIC0gMTAwJCBbY2hlY2sgdGhpc10sIHRoZSBTQ0MgcHJvdmlkZXMgbWVhc3VyZW1lbnQgc2lnbmFsIHRoYXQgYXJlIHByb3BvcnRpb25hbCB0byB0aGUgdmVsb2NpdHk6CgokJCBcb21lZ2EgPSBBXGZyYWN7VH17MlxwaX1cQmlnKDEtXGNvcygyXHBpIFxmcmFje3R9e1R9KVxCaWcpICQkCgpXZSBjaG9vc2UgYSBmcmVxdWVuY3kgJFxtYXRoY2Fse2Z9JCBvZiAwLjUgSHouIFRoZSBhZ2VudCdzIHNlbnNvciBwcm92aWRlcyBhIHNlcXVlbmNlIG9mIG5vaXN5IG1lYXN1cmVtZW50cyAkeV97dH0kIG9mIGhpcyBhbmd1bGFyIHZlbG9jaXR5ICRcb21lZ2Fee3RydWV9X3t0fSQ6CgokJCB5X3t0fSBcc2ltIFxtYXRoY2Fse059KFxvbWVnYV57dHJ1ZX1fe3R9LCBcc2lnbWFeezJ9X3tzZW5zb3J9KSAkJAoKd2hlcmUgJFxvbWVnYV57dHJ1ZX1fe3R9JCBpcyB0aGUgYWN0dWFsIGFuZ3VsYXIgdmVsb2NpdHksIGFuZCAkXHNpZ21hXnsyfV97c2Vuc29yfSQgaXMgdGhlIG5vaXNlIG9mIHRoZSBzZW5zb3IgKHBoeXNpY2FsIGNoYXJhY3RlcmlzdGljIG9mIHRoZSBzZW5zb3IpLgoKCkZpZ3VyZSAxIHNob3dzIHRoZSBhY2NlbGVyYXRpb24sIHZlbG9jaXR5LCByZXN1bHRpbmcgYW5ndWxhciBkZWZsZWN0aW9uLCBhbmQgdGhlIGFnZW50J3Mgbm9pc3kgc2Vuc29yeSBtZWFzdXJlbWVudHM6CgoKYGBge3IgZ2VuZXJhdGUtcGxvdC10cmFqZWN0b3J5fQpzZXQuc2VlZCg4NTI5NTczTCkKZGF0YSA8LSBnZW5lcmF0ZV9kYXRhKFQgPSAyLCBhbXBsaXR1ZGUgPSAyMCwgc2Vuc29yX3NkID0gMS43KSAlPiUgCiAgICB0KCkgJT4lIAogICAgZGF0YS5mcmFtZSgpCgpwbG90X3RyYWplY3RvcmllcyhkYXRhID0gZGF0YSkKYGBgCgoKRm9yIGFsbCBzaW11bGF0aW9uLCB3ZSB1c2UgYSBzZW5zb3Igc3RhbmRhcmQgZGV2aWF0aW9uICRcc2lnbWFeezJ9X3tzZW5zb3J9JCBvZiAkMS43XlxjaXJjJC4gCgojIyBQYXJ0aWNsZSBmaWx0ZXIgaW1wbGVtZW50YXRpb24KV2Ugd2lsbCBnbyBzdGVwLWJ5LXN0ZXAgdGhyb3VnaCB0aGUgYmFzaWMgU01DIGFsZ29yaXRobS4gVGhlIGFnZW50cyBnb2FsIGlzIHRvIGluZmVyIHRoZSBjdXJyZW50IGFuZ3VsYXIgdmVsb2NpdHkgJFxvbWVnYV97dH0kLCB3aGljaCBpcyBhIGxhdGVudCB2YXJpYWJsZSwgZ2l2ZW4gbm9pc3kgc2Vuc29yeSBtZWFzdXJlbWVudHMgb2YgJFxvbWVnYV97dH0kLiBUaGUgYWdlbnQgdGh1cyByZXF1aXJlcyBhIGdlbmVyYXRpdmUgbW9kZWwgb2YgaXRzIG1lYXN1cmVtZW50cywgd2hpY2ggaW4gdGhpcyBjYXNlIGlzIGdpdmVuIGJ5OgoKJCQgeV97dH0gXHNpbSBcbWF0aGNhbHtOfShcb21lZ2Ffe3R9LCBcc2lnbWFeMl95KSAkJAoKVGhpcyBpcyB0aGUgYWdlbnQncyBtZWFzdXJlbWVudCBtb2RlbDoKCi0gJFxzaWdtYV4yX3kkIGlzIHRoZSBhZ2VudCdzIG1vZGVsIG9mIHRoZSBzZW5zb3Igbm9pc2UgLSB0aGlzIGlzIGRpc3RpbmN0IGZyb20gdGhlIGFjdHVhbCAodHJ1ZSkgc2Vuc29yIG5vaXNlICRcc2lnbWFeMl97c2Vuc29yfSQuCgoKSW4gYWRkaXRpb24sIHRoZSBhZ2VudCBtdXN0IGhhdmUgYSBtb2RlbCBvZiB0aGUgZXZvbHV0aW9uIG9mIGl0cyBzdGF0ZSB2YXJpYWJsZSB0aHJvdWdoIHRpbWUsIGkuZS4gYSBtb2RlbCBvZiB0aGUgZHluYW1pY3Mgb2YgdGhlIGxhdGVudCBzdGF0ZSAkXG9tZWdhJC4gVGhpcyBpcyBnaXZlbiBieToKCiQkIFxvbWVnYV97dH0gXHNpbSBcbWF0aGNhbHtOfShcb21lZ2Ffe3QtMX0gKyBBIFxzaW4oXGZyYWN7MlxwaSB0fXtUfSksIFxzaWdtYV4yX3twcm9jZXNzfSkgJCQKCgo8IS0tIFxEZWx0YSB0IFxhbHBoYV97dC0xfSAtLT4KCndoZXJlICRBIFxzaW4oXGZyYWN7MlxwaSB0fXtUfSkkIHJlcHJlc2VudHMgYSAna25vd24nIGNvbnRyb2wgaW5wdXQgYW5kICRcc2lnbWFeMl97cHJvY2Vzc30kIGlzIHRoZSBwcm9jZXNzIHN0YW5kYXJkIGRldmlhdGlvbi4gVGhpcyB0ZXJtIGVuY29kZXMgdGhlIGFnZW50J3MgY2VydGFpbnR5IGluIGhpcyBwcm9jZXNzIG1vZGVsLiBUaGUgY29udHJvbCBpbnB1dCBpcyBhc3N1bWVkIHRvIGhhdmUgYmVlbiBsZWFybmVkIGJ5IHRoZSBhZ2VudCwgYW5kIHJlcHJlc2VudCBrbm93bGVkZ2Ugb2YgdGhlIHNlbnNvcnkgY29uc2VxdWVuY2VzIG9mIGFjdGl2ZSBoZWFkIG1vdmVtZW50cy4gVGhpcyByZXByZXNlbnRzIHRoZSBjb25jZXB0IHR5cGljYWxseSBrbm93biBhcyBhbiAnZWZmZXJlbmNlIGNvcHknLCBhbHRob3VnaCBpbiBvdXIgbW9kZWwgdGhpcyBpcyBtZXJlbHkgYSBzdGF0aXN0aWNhbCBtb2RlbCwgb2YgdGhlIHNlbnNvcnkgZWZmZWN0cyBvZiBtb3RvciBhY3Rpb24sIGFuZCBpcyB0aHVzIGVxdWl2YWxlbnQgdG8gYSAna25vd24nIGNvdmFyaWF0ZSB0aGF0IHRoZSBhZ2VudCBjYW4gdXNlIHRvIHByZWRpY3QgdGhlIGxhdGVudCBzdGF0ZS4KCiMjIFBhcnRpY2xlIGZpbHRlciBzdGVwLWJ5LXN0ZXAgKGR1cmluZyByZWFsLXRpbWUgaW50ZXJhY3Rpb24gd2l0aCB0aGUgZW52aXJvbm1lbnQpCgpfX3ByaW9yIHRvIGZpbHRlcmluZzpfXyBUaGUgYWdlbnQgY2hvb3NlcyBwYXJhbWV0ZXJzIGZvciB0aGUgZmlsdGVyaW5nIGFsZ29yaXRobToKCmBgYHtyfQpzZHggPC0gMC41ICMgcHJvY2VzcyBub2lzZQpzZHkgPC0gMiAjIHNlbnNvciBub2lzZQpBIDwtIDIgIyBtb3Rpb24gYW1wbGl0dWRlCmBgYAoKVGhlIGFnZW50IGFsc28gZGVjaWRlcyB3aGljaCBwcm9jZXNzIG1vZGVsIHRvIHVzZToKYGBge3J9CiMgcHJvY2VzcyBtb2RlbCAodHJhbnNpdGlvbiBtb2RlbCkKZiA8LSBmdW5jdGlvbih4LCBUaW1lLCBBLCBzZCwgTikgewogICAgcm5vcm0obiA9IE4sIG1lYW4gPSAgeFssIF0gKyBBICogc2luKDIqcGkvVGltZSksIHNkID0gc2QpIAp9CmBgYAoKSW4gYWRkaXRpb24sIHRoZSBhZ2VudCBkZWNpZGVzIGhvdyBtYW55IHJlc291cmNlcyB0byBhbGxvY2F0ZSB0byB0aGlzIHBhcnRpY3VsYXIgcHJvYmxlbSwgaW4gdGhlIGZvcm0gb2YgdGhlIG51bWJlciBvZiBwYXJ0aWNsZXMgKHNhbXBsZXMpIHRvIHVzZS4KCl9fYXQgJHRfMCQ6X18gVGhlIGFnZW50IHN0YXJ0cyBieSBtYWtpbmcgYW4gaW5pdGlhbCBndWVzcyBhYm91dCAkXG9tZWdhJC4gVGhpcyBtZWFucyB0aGF0IHRoZSBhZ2VudCBkcmF3cyBhIHNhbXBsZSBmcm9tIHRoZSBpbml0aWFsIGRpc3RyaWJ1dGlvbjsgaW4gb3VyIG1vZGVsLCB3ZSBhc3N1bWUgdGhhdCB0aGUgYWdlbnQgc3RhcnRzIGluIGFuIHVuYmlhc2VkIHN0YXRlIHdpdGggYSBoaWdoIGRlZ3JlZSBvZiBjZXJ0YWludHk6CgpJbiB0aGUgZm9sbG93aW5nIGNvZGUsIHRoZSBzdGF0ZSB2YXJpYWJsZSAkXG9tZWdhX3QkIGlzIGRlbm90ZWQgYXMgJHhfdCQuCgpgYGB7cn0KIyB4IGlzIGRyYXduIGZyb20gdGhlIHByaW9yIGRpc3RyaWJ1dGlvbiB3aXRoIAojIGV4cGVjdGVkIHZhbHVlIDAgYW5kIGEgc21hbGwgc3RhbmRhcmQgZGV2aWF0aW9uIDAuMSkKIyBUaGUgYWdlbnQgaGFzIGRlY2lkZWQgdG8gdXNlIDEwMCBwYXJ0aWNsZXMKTiA8LSAxMDAKCnhfaW5pdCA8LSBybm9ybShOLCAwLCAwLjEpCmBgYAoKYGBge3IsIGVjaG89RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnFwbG90KHhfaW5pdCwgeSA9IC4uZGVuc2l0eS4uLCBnZW9tID0gImhpc3RvZ3JhbSIsIGJpbndpZHRoID0gMC4wMSwKICAgICAgbWFpbiA9ICJQcmlvciBiZWxpZWYiKQpgYGAKCgpUaGUgYWdlbnQgdGh1cyByZXByZXNlbnRzIGhpcyBiZWxpZWYgYWJvdXQgdGhlIGluaXRpYWwgdmVsb2NpdHkgYXMgYSBjb2xsZWN0aW9uIG9mIDEwMCBzYW1wbGVzIGZyb20gdGhlIHByaW9yIGRpc3RyaWJ1dGlvbi4KClRoZSBhZ2VudCB0aGVuIF9fcHJlZGljdHNfXyB0aGUgc3RhdGUgYXQgdGhlIG5leHQgdGltZSBpbmNyZW1lbnQgJHRfMSQgYnkgYXBwbHlpbmcgdGhlIHByb2Nlc3MgbW9kZWwgdG8gZWFjaCBvZiB0aGUgJE4kIHBhcnRpY2xlcy4gVGhlIHByb2Nlc3MgbW9kZWwgcmVmbGVjdHMgdGhlIGFnZW50cyBrbm93bGVkZ2UgYWJvdXQgTmV3dG9uaWFuIGR5bmFtaWNzOgoKYGBge3J9ClRpbWUgPC0gMjAKIyBOIDwtIDEwMAp4IDwtIG1hdHJpeChyZXAoMCwgTipUaW1lKSwgbnJvdyA9IE4sIG5jb2wgPSBUaW1lKSAgI21hdHJpeChucm93ID0gIE4sIG5jb2wgPSBUaW1lKQp3ZWlnaHRzIDwtIG1hdHJpeChyZXAoMCwgTipUaW1lKSwgbnJvdyA9IE4sIG5jb2wgPSBUaW1lKQoKeG1lYW4gPC0gcmVwKDAsIFRpbWUpICMgbWVhbiBvZiBlc3RpbWF0ZWQgc3RhdGUKeHZhciA8LSByZXAoMCwgVGltZSkgIyB2YXJpYW5jZSBvZiBlc3RpbWF0ZWQgc3RhdGUKCnhbLCAxXSA8LSBybm9ybShuID0gTiwgbWVhbiA9ICB4X2luaXQgKyBBICogc2luKDIqcGkvVGltZSksIHNkeCkKIyB4WywgMV0gPC0gZih4X2luaXQsIFRpbWUsIEEsIHNkID0gc2R4LCBOKQpgYGAKCgpgYGB7ciwgZWNobz1GQUxTRX0KcXBsb3QoeFssIDFdLCB5ID0gLi5kZW5zaXR5Li4sIGdlb20gPSAiaGlzdG9ncmFtIiwgYmlud2lkdGggPSAwLjA1LAogICAgICBtYWluID0gIkJlbGllZiBhdCB0aW1lIHN0ZXAgMSIpCmBgYAoKCkluIE1DTUMgdGVybWlub2xvZ3ksIHRoZSBwcmVkaWN0ZWQgc3RhdGVzIHJlcHJlc2VudCBzYW1wbGVzIGZyb20gYSBfX3Byb3Bvc2FsIGRpc3RyaWJ1dGlvbl9fLgoKX19hdCAkdF8xJDpfXyBUaGVyZSBhcmUgc2Vuc29yeSBtZWFzdXJlbWVudHMgYXZhaWxhYmxlLCBzbyB0aGUgYWdlbnQgY2FuIHVzZSB0aGVzZSBpbiBvcmRlciB0byB1cGRhdGUgaGlzIGludGVybmFsIGVzdGltYXRlIG9mIGhpcyBzdGF0ZS4gVG8gZG8gc28sIGhlIGV2YWx1YXRlcyB0aGUgbGlrZWxpaG9vZCBvZiBlYWNoIHBhcnRpY2xlLCBpLmUuIGhlIGV2YWx1YXRlZCB0aGUgcHJvYmFiaWxpdHkgb2Ygb2JzZXJ2aW5nIHRoZSBtZWFzdXJlbWVudCBhdCB0aW1lICR0XzEkIGdpdmVuIHRoZSBwcmVkaWN0ZWQgdmVsb2NpdHk6CgoKYGBge3J9CndlaWdodHNbLCAxXSA8LSBkbm9ybShkYXRhJG9ic2VydmF0aW9uc1sxXSwgeFssIDFdLCBzZHkpCmBgYAoKVGhlIHByb2JhYmlsaXRpZXMgYXJlIHRoZW4gdXNlZCBhcyBfX2ltcG9ydGFuY2Ugd2VpZ2h0c19fIGZvciBlYWNoIHBhcnRpY2xlLiBJbnR1aXRpdmVseSwgdGhpcyBtZWFucyB0aGF0IHRoZSBhZ2VudCBzZWxlY3RzIHRob3NlIHBhcnRpY2xlcyB0aGF0IHByZWRpY3RlZCB0aGUgZGF0YSB3ZWxsLCBhbmQgZGlzY2FyZHMgdGhvc2UgcGFydGljbGVzIHRoYXQgcHJlZGljdGVkIHRoZSBkYXRhIHBvb3JseS4gVGhpcyBpcyBhY2hpZXZlZCBieSBhIHdlaWdodGVkIHNhbXBsaW5nIHdpdGggcmVwbGFjZW1lbnQgZnJvbSB0aGUgc2V0IG9mIHBhcnRpY2xlcyAobXVsdGlub21pYWwgcmVzYW1wbGluZykuIFRoZSB3ZWlnaHRzIGFyZSBmaXJzdCBub3JtYWxpemVkLCBzbyB0aGF0IHRoZXkgcmVwcmVzZW50IGEgcHJvYmFiaWxpdHkgZGlzdHJpYnV0aW9uLgoKYGBge3J9CnhbLCAxXSA8LSBzYW1wbGUoeFssIDFdLCByZXBsYWNlID0gVFJVRSwgc2l6ZSA9IE4sIHByb2IgPSB3ZWlnaHRzWywgMV0pCnhtZWFuWzFdIDwtIG1lYW4oeFssIDFdKQp4dmFyIDwtIHZhcih4WywgMV0pCmBgYAoKCkJ5IGFwcGx5aW5nIHRoaXMgc2ltcGxlIHByb2NlZHVyZSByZWN1cnNpdmVseSwgdGhlIGFnZW50IGNhbiB0cmFjayBoaXMgbGF0ZW50IHZlbG9jaXR5LCBnaXZlbiB0aGUgc2VxdWVuY2Ugb2Ygbm9pc3kgc2Vuc29yeSBtZWFzdXJlbWVudHMuIEF0IGFueSB0aW1lIHN0ZXAsIHRoZSBhZ2VudCB0aHVzIHBlcmZvcm1zIHRoZSBmb2xsb3dpbmcgc2VxdWVuY2Ugb2YgY29tcHV0YXRpb25zOgoKMSkgcHJlZGljdGlvbiAocHJvcGFnYXRpb24pIHN0ZXA6IHByZWRpY3QgdGhlIHN0YXRlIDEgc3RlcCBhaGVhZAoyKSB1cGRhdGUgc3RlcDogb2J0YWluIGltcG9ydGFuY2Ugd2VpZ2h0cyBmcm9tIHNlbnNvcnkgbWVhc3VyZW1lbnRzLCBhbmQgc2VsZWN0IHBhcnRpY2xlcyBmb3IgJ3N1cnZpdmFsJwozKSBjb21wdXRlIHN1bW1hcnkgc3RhdGlzdGljcywgZS5nLiBtZWFuIGFuZCB2YXJpYW5jZSBvZiBlc3RpbWF0ZWQgc3RhdGUKCkZpZ3VyZSAyIHNob3dzIGEgdmlzdWFsaXphdGlvbiBvZiB0aGUgY29tcHV0YXRpb25zIHBlcmZvcm1lZCBhdCBlYWNoIHRpbWUgc3RlcC4gQWZ0ZXIgdGhlIF9fcHJlZGljdGlvbiBzdGVwX18sIHRoZSBzZXQgb2YgcGFydGljbGVzIHJlcHJlc2VudCB0aGUgbmV3IGJlbGllZiBiZWZvcmUgJ3NlZWluZycgdGhlIG5ldyBldmlkZW5jZS4gQWxsIHBhcnRpY2xlcyB0aHVzIGhhdmUgZXF1YWwgd2VpZ2h0cywgZ2l2ZW4gJFxmcmFjezF9e059JC4gU3Vic2VxdWVudGx5LCB0aGUgcHJvYmFiaWxpdHkgb2Ygb2JzZXJ2aW5nIHRoZSBldmlkZW5jZSBpcyBldmFsdWF0ZWQgZm9yIGVhY2ggcGFydGljbGUsIGdpdmluZyAgbmV3IHdlaWdodC4gRWFjaCBwYXJ0aWNsZSdzIHNpemUgcmVmbGVjdHMgaXRzIGltcG9ydGFuY2UsIGkuZS4gaG93IHdlbGwgaXQgcHJlZGljdGVkIHRoZSBuZXcgbWVhc3VyZW1lbnQuIFRoZSBmaW5hbCBzdGVwIGNvbnNpc3RzIG9mIHNhbXBsaW5nIDEwMCBuZXcgcGFydGljbGVzIHdpdGggcmVwbGFjZW1lbnQgZnJvbSB0aGUgc2V0IG9mIHBhcnRpY2xlcywgd2l0aCBhIHByb2JhYmlsaXR5IG9mIGJlaW5nIGNob3NlbiBnaXZlbiBieSB0aGVpciBpbXBvcnRhbmNlIHdlaWdodHMuIChUaGlzIGlzIHRoZSBtdWx0aW5vbWlhbCByZXNhbXBsaW5nIHBhcnQpLiBQYXJ0aWNsZXMgdGhhdCBkaWQgbm90IHByZWRpY3QgdGhlIGRhdGEgd2VsbCBtYXkgdGhlcmVmb3JlIGJlIGVsaW1pbmF0ZWQuCgpUaGUgcHVycGxlIGxpbmUgc2hvd3MgdGhlIGVzdGltYXRlZCBtZWFuIG9mIHRoZSBkaXN0cmlidXRpb24gYmVpbmcgJ3NoaWZ0ZWQnIGR1cmluZyBhIHNpbmdsZSB0aW1lIGluY3JlbWVudCwgYW5kIHRoZSBibGFjayByZWN0YW5nbGUgc2hvdyB0aGUgb2JzZXJ2YXRpb25zOyBhdCB0aGUgZmlyc3Qgc3RlcCwgYmVmb3JlIHNlZWluZyB0aGUgbmV3IGRhdGEsIHRoZSBvYnNlcnZhdGlvbiBpcyBhdCB0aGUgcHJldmlvdXMgdmFsdWUuIEF0IHRoZSB1cGRhdGluZyBzdGVwIChzdGVwIDIpLCBhIG5ldyBtZWFzdXJlbWVudCBpcyBhdmFpbGFibGUuIF9UaGUgY2xvc2VyIHRvIHRoZSBtZWFzdXJlbWVudCwgdGhlIGxhcmdlciB0aGUgZGlhbWV0ZXIgb2YgdGhlIHBhcnRpY2xlLl8KCmBgYHtyLCBpbmNsdWRlPUZBTFNFfQoKc2V0LnNlZWQoMzQ1MjM0KQp4WywgMl0gPC0gcm5vcm0obiA9IE4sIG1lYW4gPSAgeFssIDFdICsgQSAqIHNpbigyKnBpL1RpbWUpLCBzZHgpCnhfcHJlZGljdGVkIDwtIGRhdGEuZnJhbWUoeCA9IHhbLCAyXSwgd2VpZ2h0ID0gMS9OLCB0ID0gMSwgc3RlcCA9ICdwcmVkaWN0ZWQnKQoKd2VpZ2h0c1ssIDJdIDwtIGRub3JtKGRhdGEkb2JzZXJ2YXRpb25zWzJdLCB4WywgMl0sIHNkeSkKeF91cGRhdGVkIDwtIGRhdGEuZnJhbWUoeCA9IHhbLCAyXSwgd2VpZ2h0ID0gd2VpZ2h0c1ssIDJdLCB0ID0gMiwgc3RlcCA9ICd1cGRhdGVkJykKCnhbLCAyXSA8LSBzYW1wbGUoeFssIDJdLCByZXBsYWNlID0gVFJVRSwgc2l6ZSA9IE4sIHByb2IgPSB3ZWlnaHRzWywgMl0pCnhfcmVzYW1wbGVkIDwtIGRhdGEuZnJhbWUoeCA9IHhbLCAyXSwgd2VpZ2h0ID0gMS9OLCB0ID0gMywgc3RlcCA9ICdyZXNhbXBsZWQnKQoKeG1lYW5bMV0gPC0gbWVhbih4WywgMl0pCnh2YXIgPC0gdmFyKHhbLCAyXSkKCiMgVE9ETzogbW9yZSBzb3BoaXN0aWNhdGVkIHNvbHV0aW9uCmRmIDwtIHJiaW5kKHhfcHJlZGljdGVkLCB4X3VwZGF0ZWQsIHhfcmVzYW1wbGVkKQoKZGYkc3RlcCA8LSBvcmRlcmVkKGRmJHN0ZXAsIGxldmVscyA9IGMoInByZWRpY3RlZCIsICJ1cGRhdGVkIiwgInJlc2FtcGxlZCIpKQpvYnMgPC0gZGF0YS5mcmFtZShvYnMgPSBjKE5BLCBkYXRhJG9ic2VydmF0aW9uWzJdLCBkYXRhJG9ic2VydmF0aW9uWzJdKSwgc3RlcCA9IGMoInByZWRpY3RlZCIsICJ1cGRhdGVkIiwgInJlc2FtcGxlZCIpKQojIG9icyA8LSBkYXRhLmZyYW1lKG9icyA9IGMoZGF0YSRvYnNlcnZhdGlvblsxOjJdLCBkYXRhJG9ic2VydmF0aW9uWzJdKSwgc3RlcCA9IGMoInByZWRpY3RlZCIsICJ1cGRhdGVkIiwgInJlc2FtcGxlZCIpKQojIGRmIDwtIGRmICU+JSBnYXRoZXIoa2V5ID0gInZhciIsICJwcmVkaWN0ZWQiLCAidXBkYXRlZCIsIC13ZWlnaHQpCmBgYAoKYGBge3IgMS1zdGVwLWFoZWFkLCBlY2hvPUZBTFNFfQpwbG90XzFfc3RlcF9haGVhZCA8LSBmdW5jdGlvbihkZikgewogICAgZyA8LSBnZ3Bsb3QoZGF0YSA9IGRmLCBhZXMoeCA9IHN0ZXAsIHkgPSB4KSkgKwogICAgICAgICBnZW9tX2ppdHRlcihhZXMoc2l6ZSA9IHdlaWdodCksIGFscGhhID0gMC40LCAKICAgICAgICAgICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9qaXR0ZXIod2lkdGggPSAuMjUpLCBjb2xvciA9IGNvbG9yX3BhbGV0dGVbM10pICsKICAgICAgICAgc3RhdF9zdW1tYXJ5KGFlcyhncm91cCA9IDEpLCBmdW4ueSA9IG1lYW4sIGNvbG9yID0gY29sb3JfcGFsZXR0ZVs4XSwgCiAgICAgICAgICAgICAgICAgICAgICBnZW9tID0gImxpbmUiLCBzaXplID0gMiwgYWxwaGEgPSAwLjYpICsgCiAgICAgICAgIHNjYWxlX3hfZGlzY3JldGUobGFiZWxzID0gYygicHJlZGljdGVkIiA9ICIxOiBQcmVkaWN0aW9uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInVwZGF0ZWQiID0gIjI6IFdlaWdodGluZyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicmVzYW1wbGVkIiA9ICIzOiBSZXNhbXBsaW5nIikpICsKICAgICAgICAgeWxhYihleHByZXNzaW9uKHBhc3RlKCJMYXRlbnQgc3RhdGU6ICIsIG9tZWdhKSkpICsgCiAgICAgICAgIHhsYWIoIiIpICsKICAgICAgICAgZ3VpZGVzKHNpemUgPSBGQUxTRSkgKwogICAgICAgICAjIGdndGl0bGUoIlByb2plY3RpbmcgdGhlIGxhdGVudCBzdGF0ZSAxIHN0ZXAgYWhlYWQiKSArCiAgICAgICAgIGdlb21fcG9pbnQoZGF0YSA9IG9icywgYWVzKHkgPSBvYnMpLCBjb2xvcj0gImJsYWNrIiwgc2hhcGUgPSAxNSwgc2l6ZSA9IDUsIGFscGhhID0gMC44KQoKICAgIHByaW50KGcpCn0KCnBsb3RfMV9zdGVwX2FoZWFkKGRmKQpgYGAKCgoKCgpGaWd1cmUgMiBkZW1vbnN0cmF0ZXMgaG93LCBkdXJpbmcgcmVhbC10aW1lIGludGVyYWN0aW9uIHdpdGggdGhlIGVudmlyb25tZW50LCAxLXN0ZXAgYWhlYWQgcHJlZGljdGlvbiBpcyBwZXJmb3JtZWQgY29udGludW91c2x5IGFuZCBpcyBhIHZpdGFsIGluZ3JlZGllbnQgaW4gKG5vcm1hbCkgc2Vuc29yeSBpbmZlcmVuY2UuCgoKCiMjIFByZWRpY3RpbmcgayBzdGVwcyBhaGVhZCAod2hhdCBoYXBwZW5zIHdoZW4gZGF0YSBhcmUgdW5hdmFpbGFibGUpCgpOZXh0LCB3ZSBjb25zaWRlciBhbiBpbnRlcmFjdGlvbiBlcGlzb2RlIGR1cmluZyB3aGljaCBzZW5zb3J5IGRhdGEgdGVtcG9yYXJpbHkgYmVjb21lIHVuYXZhaWxhYmxlLiAKCj4gSW4gdGhlIHZpc3VhbCBzeXN0ZW0sIHRoaXMgaXMgZmFpcmx5IGNvbW1vbjogbGlnaHRzIG91dCwgZXllcyBjbG9zZWQsIGZvZywgZXRjLiBXaGF0IGFyZSBhbmFsb2dpZXMgaW4gdGhlIHRoZSB2ZXN0aWJ1bGFyIHN5c3RlbT8KCkZpZ3VyZSAzIHNob3dzIHRoZSBhZ2VudCBlbmdhbmdlZCBpbiByZWFsLXRpbWUgc2Vuc29yeSBpbmZlcmVuY2UgZHVyaW5nIGEgMiBzZWNvbmQgbW90aW9uIGV2ZW50LiBUaGUgZG90dGVkIGxpbmUgc2hvd3MgdGhlIHRydWUgdmVsb2NpdHksIHRoZSBibGFjayByZWN0YW5nbGVzIGFyZSB0aGUgc2Vuc29yeSBtZWFzdXJlbWVudHMsIHRoZSBzb2xpZCBsaW5lIHNob3cgdGhlIGFnZW50cyBlc3RpbWF0ZWQgaGVhZCB2ZWxvY2l0eSwgYW5kIHRoZSBiYW5kcyBzdXJyb3VuZGluZyB0aGUgc29saWQgbGluZSByZWZsZWN0IHRoZSBhZ2VudHMgJDk1XCUkIGNyZWRpYmxlIGludGVydmFsLgoKRHVlIHRvIHRoZSBwcm9jZXNzIG9mIHByZWRpY3RpbmcgYW5kIHVwZGF0aW5nLCB0aGUgY29uZmlkZW5jZSByZWdpb24gcmVtYWlucyBhcHByb3hpbWF0ZWx5IGNvbnN0YW50IHRocm91Z2hvdXQgdGhlIGV2ZW50LiBQcmVkaWN0aW5nIGluY3JlYXNlcyB1bmNlcnRhaW50eSwgdXBkYXRpbmcgcmVkdWNlcyBpdCBhZ2Fpbi4KCkZpZ3VyZSA0IHNob3dzIHRoZSBzYW1lIHNlbnNvcnkgZXZlbnQsIGJ1dCBhZnRlciAxIHNlY29uZHMsIHRoZXJlIGlzIHNlbnNvciBmYWlsdXJlLCBhbmQgdGhlIGFnZW50IG5vIGxvbmdlciByZWNlaXZlcyBhbnkgbWVhc3VyZW1lbnRzLiBGb3JjZWQgdG8gcmVseSBvbiBoaXMgaW50ZXJuYWwgbW9kZWwsIHRoZSBhZ2VudCBpcyBvbmx5IGFibGUgdG8gcHJlZGljdCB0aGUgbmV4dCBzdGVwcywgd2l0aG91dCBiZWluZyBhYmxlIHRvIHVwZGF0ZS4gVGhpcyBpcyBpbXBsZW1lbnRlZCBieSBsZXR0aW5nIHRoZSBhZ2VudCBtb25pdG9yIHdoZXRoZXIgZGF0YSBhcmUgYXZhaWxhYmxlLCBhbmQgdGhlbiBwZXJmb3JtaW5nIHdlaWdodGluZyBhY2NvcmRpbmcgdG8gdGhlIGxpa2VsaWhvb2QgaWYgdGhleSBhcmUuIElOIHRoZSBjYXNlIG9mIG1pc3NpbmcgZGF0YSwgdGhlIGFnZW50IHNpbXBseSBhc3NpZ25zIGEgdW5pZm9ybSBwcm9iYWJpbGl0eSBkaXN0cmlidXRpb24gdG8gdGhlIHdlaWdodHMuIFJlc2FtcGxpbmcgaXMgc3Vic2VxdWVudGx5IHBlcmZvcm1lZCwgYnV0IGlmIHRoZSBkYXRhIGFyZSBtaXNzaW5nLCB0aGlzIGhhcyBubyBlZmZlY3QsIGJlY2F1c2UgdGhlIHJlc2FtcGxlZCBzZXQgb2YgcGFydGljbGVzIGFyZSBzaW1wbHkgZHJhd24gd2l0aCBlcXVhbCBwcm9iYWJpbGl0aWVzIGZyb20gdGhlIG9sZCBzZXQuIFRoZSBwYXJ0aWNsZXMgdGhlcmVmb3JlIGRvIG5vdCBtb3ZlIHRvcndhcmQgdGhlIHRhcmdldCBkaXN0cmlidXRpb24sIGFuZCBfdGhlIHZhcmlhbmNlIG9mIHRoZSBzYW1wbGVzIGluY3JlYXNlcyBvdmVyIHRpbWUuXyBOb3RlIHRoYXQgdGhlIGVzdGltYXRlIHJlbWFpbnMgdW5iaWFzZWQsIGJlY2F1c2UgdGhlIGFnZW50IGlzIHVzaW5nIGEgJ2dvb2QnIGdlbmVyYXRpdmUgbW9kZWwsIGkuZS4gdGhlIGFnZW50IGlzIGNvcnJlY3RseSBtb2RlbGxpbmcgdGhlIGNhdXNlIG9mIHRoZSB0cnVlIHZlbG9jaXR5LiBUaGlzIGlzIGlsbHVzdHJhdGVkIGJ5IHRoZSBmYWN0IHRoYXQgdGhlIGVzdGltYXRlZCBsaW5lIGxpZXMgJ29uIHRvcCBvZicgdGhlIHRydWUgdmVsb2NpdHkuIChJbiBmYWN0LCBpZiB0aGUgYWdlbnQgaXMgdXNpbmcgYSBnb29kIHByb2Nlc3MgbW9kZWwsIHRoZSByZWNvdmVyZWQgZXN0aW1hdGUgaXMgYWN0dWFsbHkgYmV0dGVyIGlmIGhlIGlzIG5vdCBmb3JjZWQgdG8gaW5jb3Jwb3JhdGUgbm9pc3kgbWVhc3VyZW1lbnRzOyBtYXliZSB0aGUgZmlndXJlIHNob3VsZCBub3Qgc2hvdyB0aGlzPykuCgoKCj4gTWFueSB3b3VsZCBjbGFpbSB0aGF0IHRoaXMgaXMgYWxyZWFkeSBpbWFnZXJ5LCBvZiBndWlkZWQgaGFsbHVjaW5hdGlvbi4uLgoKCgoKCmBgYHtyIHBhcnRpY2xlLWZpbHRlci1mdW59CnJ1bl9wYXJ0aWNsZV9maWx0ZXIgPC0gZnVuY3Rpb24oZGF0YSwgTiwgVGltZSwgeF9pbml0LCBzZHhfaW5pdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJhbXMsIHJlc2FtcGxlID0gVFJVRSwgcnNfdGhyZXNoID0gMC41KSB7CiAgICAKICAgIAogICAgc2RjIDwtIHBhcmFtcyRzZGMKICAgIHNkeCA8LSBwYXJhbXMkc2R4CiAgICBzZHkgPC0gcGFyYW1zJHNkeQogICAgZnVuX3ggPC0gcGFyYW1zJGZ1bnhfeAogICAgZnVuX2MgPC0gcGFyYW1zJGZ1bl9jCiAgICBBIDwtIHBhcmFtcyRBCiAgICAKICAgIHggPC0gbWF0cml4KHJlcCgwLCBOKlRpbWUpLCBucm93ID0gTiwgbmNvbCA9IFRpbWUpICAjbWF0cml4KG5yb3cgPSAgTiwgbmNvbCA9IFRpbWUpCiAgICB3ZWlnaHRzIDwtIG1hdHJpeChyZXAoMCwgTipUaW1lKSwgbnJvdyA9IE4sIG5jb2wgPSBUaW1lKSAjbWF0cml4KG5yb3cgPSAgTiwgbmNvbCA9IFRpbWUpCiAgICBsb2dsaWsgPC0gcmVwKDAsIFRpbWUpCiAgICAKICAgIHhbLCAxXSA8LSBybm9ybShOLCB4X2luaXQsIHNkeF9pbml0KQogICAgd2VpZ2h0c1ssIDFdIDwtIGRub3JtKGRhdGEkb2JzZXJ2YXRpb25zWzFdLCB4WywgMV0sIHNkeSkKICAgIHdlaWdodHNbLCAxXSA8LSB3ZWlnaHRzWywgMV0vc3VtKHdlaWdodHNbLCAxXSkKCiAgICB4WywgMV0gPC0gc2FtcGxlKHhbLCAxXSwgcmVwbGFjZSA9IFRSVUUsIHNpemUgPSBOLCBwcm9iID0gd2VpZ2h0c1ssIDFdKQogICAgCiAgICAKICAgIGZvciAodCBpbiBzZXEoMiwgVGltZSkpIHsKCiAgICAgICAgeFssIHRdIDwtIGYoeCwgdCwgVGltZSwgQSwgc2QgPSBzZHgsIE4pCiAgICAgICAgCiAgICAgICAgaWYgKCFpcy5uYShkYXRhJG9ic2VydmF0aW9uc1t0XSkpIHsKICAgICAgICAgICAgd2VpZ2h0c1ssIHRdIDwtIGRub3JtKGRhdGEkb2JzZXJ2YXRpb25zW3RdLCB4WywgdF0sIHNkeSkKICAgICAgICB9IGVsc2UgewogICAgICAgICAgICB3ZWlnaHRzWywgdF0gPC0gMS9OCiAgICAgICAgfQogICAgICAgIAoKICAgICAgICBpZiAocmVzYW1wbGUpIHsKICAgICAgICAgICAgICAgIGlmIChuZWZmKHdlaWdodHNbLCB0XSkgPCByc190aHJlc2ggKiBOKSB7CiAgICAgICAgICAgICAgICAgICAgeFssIHRdIDwtIHNhbXBsZSh4WywgdF0sIHJlcGxhY2UgPSBUUlVFLCBzaXplID0gTiwgcHJvYiA9IHdlaWdodHNbLCB0XSkgCiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgCiAgICAgICAgIyBUT0RPOiBkbyB3ZSBuZWVkIHRvIHJlc2V0IHdlaWdodHMgYWZ0ZXIgcmVzYW1wbGluZz8KICAgICAgICAjIHdlaWdodHNbLCB0XSA8LSAxL04KCiAgICB9CiAgICAKICAgIG91dCA8LSBsaXN0KHggPSB4LCB3ZWlnaHRzID0gd2VpZ2h0cywgbG9nbGlrID0gbG9nbGlrLAogICAgICAgICAgICAgICAgeF9tZWFucyA9IGFwcGx5KHgsIDIsIG1lYW4pLAogICAgICAgICAgICAgICAgeF9tZWRpYW5zID0gYXBwbHkoeCwgMiwgbWVkaWFuKSwKICAgICAgICAgICAgICAgIHhfcXVhbnRpbGVzID0gYXBwbHkoeCwgMiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uKHgpIHF1YW50aWxlKHgsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9icyA9IGMoMC4wMjUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgMC45NzUpKSksCiAgICAgICAgICAgICAgICBUaW1lID0gVGltZSwKICAgICAgICAgICAgICAgIE4gPSBOKQp9CmBgYAoKYGBge3IgcHJvY2Vzcy1tb2RlbHN9CgpmIDwtIGZ1bmN0aW9uKHgsIHQsIFRpbWUsIEEsIHNkLCBOKSB7CiAgICBybm9ybShuID0gTiwgbWVhbiA9ICB4WywgdC0xXSArIEEgKiBzaW4oMipwaSoodC0xKS9UaW1lKSwgc2QgPSBzZCkgCn0KCmYxIDwtIGZ1bmN0aW9uKHgsIHQsIFRpbWUsIEEsIHNkLCBOKSB7CiAgICBybm9ybShuID0gTiwgbWVhbiA9ICB4WywgdC0xXSwgc2QgPSBzZCkgCn0KCmYyIDwtIGZ1bmN0aW9uKHgsIHQsIFRpbWUsIEEsIHNkLCBOKSB7CiAgICAjIEEgKiBzaW4oMipwaSoodC0xKS9UaW1lKQogICAgcm5vcm0obiA9IE4sIG1lYW4gPSAgQSAqIHNpbigyKnBpKih0LTEpL1RpbWUpLCBzZCA9IHNkKSAKfQpgYGAKCgpgYGB7ciBwbG90LWZpbHRlcmluZy1lc3RpbWF0ZXMsIGluY2x1ZGU9RkFMU0V9CnBsb3RfZmlsdGVyaW5nX2VzdGltYXRlcyA8LSBmdW5jdGlvbihvYmplY3QsIGRhdGEsIHByZWRpY3QgPSBGQUxTRSkgewogICAgCiAgICBkZiA8LSB3aXRoKG9iamVjdCwgewogICAgICAgIGRhdGFfZnJhbWUodCA9IHNlcSgxLCBUaW1lKSwKICAgICAgICAgICAgICAgICBtZWFuID0geF9tZWFucywKICAgICAgICAgICAgICAgICBtZWRpYW4gPSB4X21lZGlhbnMsCiAgICAgICAgICAgICAgICAgbG93ZXIgPSB4X3F1YW50aWxlc1sxLCBdLAogICAgICAgICAgICAgICAgIHVwcGVyID0geF9xdWFudGlsZXNbMiwgXSwKICAgICAgICAgICAgICAgICB4X3RydWUgPSBkYXRhJHZlbG9jaXR5LAogICAgICAgICAgICAgICAgIG9ic2VydmF0aW9ucyA9IGRhdGEkb2JzZXJ2YXRpb25zLAogICAgICAgICAgICAgICAgIGxvZ2xpayA9IGxvZ2xpaykKICAgIH0pCiAgICAKICAgIHAgPC0gZ2dwbG90KGRhdGEgPSBkZiwgYWVzKHggPSB0KSkgKwogICAgICAgIGdlb21fcmliYm9uKGFlcyh5bWluID0gbG93ZXIsIHltYXggPSB1cHBlciksIGFscGhhID0gMC4xLAogICAgICAgICAgICAgICAgICAgIGZpbGwgPSBjb2xvcl9wYWxldHRlWzJdKSArCiAgICAgICAgZ2VvbV9saW5lKGFlcyh5ID0geF90cnVlKSwgY29sb3VyID0gY29sb3JfcGFsZXR0ZVs3XSwgYWxwaGEgPSAwLjksCiAgICAgICAgICAgICAgICAgIGxpbmV0eXBlID0gImRhc2hlZCIsIHNpemUgPSAxLjIpICsKICAgICAgICAjIGdlb21fbGluZShhZXMoeSA9IG1lYW4pLCBjb2xvdXIgPSBjb2xvcl9wYWxldHRlWzZdLCBzaXplID0gMS40KSArCiAgICAgICAgZ2VvbV9saW5lKGFlcyh5ID0gbWVkaWFuKSwgY29sb3VyID0gY29sb3JfcGFsZXR0ZVsxXSwgc2l6ZSA9IDEuNCwgYWxwaGEgPSAwLjYpICsKICAgICAgICAKICAgICAgICBnZW9tX3BvaW50KGFlcyh5ID0gb2JzZXJ2YXRpb25zKSwgY29sb3VyID0gImJsYWNrIiwKICAgICAgICAgICAgICAgICAgIHNpemUgPSAzLCBzaGFwZSA9IDE1LCBhbHBoYSA9IDAuNSkgKwogICAgICAgIGdlb21fbGluZShhZXMoeSA9IG9ic2VydmF0aW9ucyksIGNvbG91ciA9ICJibGFjayIsIHNpemUgPSAxLAogICAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMiwgbGluZXR5cGUgPSAiZG90dGVkIikgKwogICAgICAgIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKDEsIDIwKSwgYnJlYWtzID0gYygwLCA1LCAxMCwgMTUsIDIwKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIjAiLCAiMC41IiwgIjEiLCAiMS41IiwgIjIiKSkgKwogICAgICAgIHlsYWIoZXhwcmVzc2lvbihwYXN0ZSgiTGF0ZW50IHN0YXRlOiAiLCBvbWVnYSkpKSArIHhsYWIoIlRpbWUgW3NlY10iKQogICAgCiAgICBpZiAocHJlZGljdCkgewogICAgICAgIHAgPC0gcCArIAogICAgICAgICAgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAxMCwgbGluZXR5cGUgPSAiZGFzaGVkIiwgCiAgICAgICAgICAgICAgICBjb2xvciA9IGNvbG9yX3BhbGV0dGVbNF0sIHNpemUgPSAxLjUsIGFscGhhID0gMC42KSArCiAgICAgICAgICAgIGdlb21fcmliYm9uKGRhdGEgPSBmaWx0ZXIoZGYsIHQgPiA5KSwKICAgICAgICAgICAgICAgICAgICAgICAgYWVzKHltaW4gPSBsb3dlciwgeW1heCA9IHVwcGVyKSwgYWxwaGEgPSAwLjQsCiAgICAgICAgICAgICAgICAgICAgZmlsbCA9IGNvbG9yX3BhbGV0dGVbNF0pCiAgICB9CiAgICBwcmludChwKQp9CmBgYAoKCgoKCgpgYGB7ciBydW4tcGFydGljbGUtZmlsdGVyLXJlYWxfdGltZS13aXRoLWRhdGF9CnBhcmFtcyA8LSBsaXN0KHNkeCA9IDEuMiwgc2R5ID0gNC4wLCBBID0gMi4wLCBmdW5feCA9IGYpCgpvdXQgPC0gcnVuX3BhcnRpY2xlX2ZpbHRlcihkYXRhID0gZGF0YSwgTiA9IDEwMCwgVGltZSA9IGxlbmd0aChkYXRhJG9ic2VydmF0aW9ucyksCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHhfaW5pdCA9IDAsIHNkeF9pbml0ID0gMC41LAogICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJhbXMsIHJlc2FtcGxlID0gVFJVRSwgcnNfdGhyZXNoID0gMC41KQpwbG90X2ZpbHRlcmluZ19lc3RpbWF0ZXMob3V0LCBkYXRhID0gZGF0YSkKYGBgCgpgYGB7ciBydW4tcGFydGljbGUtZmlsdGVyLXJlYWwtdGltZS1taXNzaW5nLWRhdGEsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnBhcmFtcyA8LSBsaXN0KHNkeCA9IDEuMiwgc2R5ID0gNC4wLCBBID0gMi4wLCBmdW5feCA9IGYpCgpkYXRhX21pc3NpbmcgPC0gZGF0YQpkYXRhX21pc3Npbmckb2JzZXJ2YXRpb25zWzEwOmxlbmd0aChkYXRhX21pc3Npbmckb2JzZXJ2YXRpb25zKV0gPC0gTkEKCm91dCA8LSBydW5fcGFydGljbGVfZmlsdGVyKGRhdGEgPSBkYXRhX21pc3NpbmcsIE4gPSAxMDAsIFRpbWUgPSBsZW5ndGgoZGF0YSRvYnNlcnZhdGlvbnMpLAogICAgICAgICAgICAgICAgICAgICAgICAgICB4X2luaXQgPSAwLCBzZHhfaW5pdCA9IDAuNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFyYW1zLCByZXNhbXBsZSA9IFRSVUUsIHJzX3RocmVzaCA9IDAuNSkKcGxvdF9maWx0ZXJpbmdfZXN0aW1hdGVzKG91dCwgZGF0YSA9IGRhdGFfbWlzc2luZywgcHJlZGljdCA9IFRSVUUpCmBgYAoKCiMjIFJ1bm5pbmcgdGhlIHBhcnRpY2xlIGZpbHRlciB3aXRoIGEgbWlzc3BlY2lmaWVkIHByb2Nlc3MgbW9kZWwKClRoZSBuZXh0IHR3byBGaWd1cmVzIHNob3cgd2hhdCBjYW4gaGFwcGVuIHdoZW4gcnVubmluZyB0aGUgcGFydGljbGUgZmlsdGVyIHVzaW5nIGEgJ3dyb25nJyBwcm9jZXNzIG1vZGVsLiBIZXJlLCB0aGUgYWdlbnQgYmVsaWV2ZXMgdGhhdCB0aGUgZGlyZWN0aW9uIG9mIG1vdGlvbiBpcyBpbiB0aGUgb3Bwb3NpdGUgZGlyZWN0aW9uIHRvIHRoZSBhY3R1YWwgbW90aW9uLCBsZWFkaW5nIHRvIGEgX21pc2ludGVycHJldGF0aW9uXy4gCgpgYGB7ciBydW4tcGFydGljbGUtZmlsdGVyLXJlYWwtdGltZS13aXRoLXdyb25nLW1vZGVsLTF9CnBhcmFtcyA8LSBsaXN0KHNkeCA9IDEuMiwgc2R5ID0gNC4wLCBBID0gLTIsIGZ1bl94ID0gZikKCm91dCA8LSBydW5fcGFydGljbGVfZmlsdGVyKGRhdGEgPSBkYXRhLCBOID0gMTAwLCBUaW1lID0gbGVuZ3RoKGRhdGEkb2JzZXJ2YXRpb25zKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgeF9pbml0ID0gMCwgc2R4X2luaXQgPSAwLjUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFtcywgcmVzYW1wbGUgPSBUUlVFLCByc190aHJlc2ggPSAwLjUpCnBsb3RfZmlsdGVyaW5nX2VzdGltYXRlcyhvdXQsIGRhdGEgPSBkYXRhKQpgYGAKCgpJbiB0aGUgZmlyc3QgRmlndXJlLCB0aGUgYWdlbnQgaGFzIGEgaGlnaCBkZWdyZWUgb2YgY2VydGFpbnkgaW4gaGlzIHByb2Nlc3MgbW9kZWw6ICRcc2lnbWFfe3Byb2Nlc3N9JCA9IGByIHBhcmFtcyRzZHhgLgoKCmBgYHtyIHJ1bi1wYXJ0aWNsZS1maWx0ZXItcmVhbC10aW1lLXdpdGgtd3JvbmctbW9kZWwtMn0KcGFyYW1zIDwtIGxpc3Qoc2R4ID0gMi4yLCBzZHkgPSA0LjAsIEEgPSAtMiwgZnVuX3ggPSBmKQoKb3V0IDwtIHJ1bl9wYXJ0aWNsZV9maWx0ZXIoZGF0YSA9IGRhdGEsIE4gPSAxMDAsIFRpbWUgPSBsZW5ndGgoZGF0YSRvYnNlcnZhdGlvbnMpLAogICAgICAgICAgICAgICAgICAgICAgICAgICB4X2luaXQgPSAwLCBzZHhfaW5pdCA9IDAuNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFyYW1zLCByZXNhbXBsZSA9IFRSVUUsIHJzX3RocmVzaCA9IDAuNSkKcGxvdF9maWx0ZXJpbmdfZXN0aW1hdGVzKG91dCwgZGF0YSA9IGRhdGEpCmBgYAoKSW4gdGhlIHNlY29uZCBGaWd1cmUsIHRoZSBhZ2VudCBoYXMgYSBsb3dlciBkZWdyZWUgb2YgY2VydGFpbnkgaW4gaGlzIHByb2Nlc3MgbW9kZWw6ICRcc2lnbWFfe3Byb2Nlc3N9JCA9IGByIHBhcmFtcyRzZHhgLgoKVGh1cywgdXNpbmcgdGhlIHNhbWUgcHJvY2VzcyBtb2RlbCwgd2l0aCB0aGUgc2FtZSBzZW5zb3J5IGlucHV0LCB0aGUgYWdlbnQgbWF5IGludGVycHJldCB0aGUgZGF0YSBkaWZmZXJlbnRseSwgZGVwZW5kaW5nIG9uIGhvdyBjZXJ0YWluIGhlIGlzIGluIGhpcyBvd24gcHJlZGljdGlvbnMgKGR1ZSB0byBoaXMgcHJvY2VzcyBtb2RlbCkuCgoKX19RdWVzdGlvbjpfXyBCdXQgaXMgdGhpcyBhbHJlYWR5IGVub3VnaCBmb3IgaW1hZ2VyeS9TUFQ/CgpJIHRoaW5rIG5vdCwgYmVjYXVzZSBpbiBhbGwgdGhlIGFib3ZlIHNjZW5hcmlvcywgdGhlIGFnZW50IHdhcyBzdGlsbCBlbmdhZ2VkIGluIHJlYWwtdGltZSBpbnRlcmFjdGlvbiB3aXRoIHRoZSBlbnZpcm9ubWVudCwgaS5lLiB0aGUgYWdlbnQncyBnb2FsIHdhcyB0byBleHBsYWluIHRoZSBzZW5zb3J5LiBJTiBhbGwgY2FzZXMsIGhlIHdhbnRlZCB0byB1bmNvdmVyIHRoZSBjYXVzZXMgb2YgaGlzIHNlbnNvcnkgaW5wdXQsIGFuZCB3YXMgYWJsZSB0byBhbGxvdyBmb3IgbWlzc2luZyBkYXRhLCBvciB1c2VkIGEgd3JvbmcgcHJvY2VzcyBtb2RlbC4gCgogCgojIyBSdW5uaW5nIHRoZSBwYXJ0aWNsZSBmaWx0ZXIgb2ZmbGluZSAod2l0aG91dCByZXNhbXBsaW5nKQpOb3cgY29tZXMgdGhlIGltcG9ydGFudCBuZXh0IHN0ZXA6IGluIG9yZGVyIHRvIHBlcmZvcm0gU1BULCBldGMuLCB0aGUgYWdlbnQgbXVzdCBhY3RpdmVseSBkaXNlbmdhZ2UgZnJvbSBoaXMgcmVhbC10aW1lIGludGVyYWN0aW9uIHdpdGggdGhlIGVudmlyb25tZW50LCBvdGhlcndpc2UgaGUgd291bGQgcGVyZm9ybSBjb21wZW5zYXRvcnkgZXllIG1vdmVtZW50cywgZXRjLiBCdXQgd2hhdCBjYW4gdGhlIGFnZW50IGRvIGluIG9yZGVyIHRvIGdvIG9mZmxpbmU/IE9mIGNvdXJzZSwgYXNzdW1pbmcgdGhlIGFnZW50IHJlc3VzZXMgaGlzIHNlbnNvcnkgY2lyY3VpdCBmb3IgJ2NvZ25pdGlvbicuCgpJbiBhZGRpdGlvbiB0byB0aGUgcHJldmlvdXMgYWJpbGl0aWVzOgoKLSBhYmlsaXR5IHRvIHByZWRpY3QgKDEgc3RlcCBhaGVhZCkKLSBhYmlsaXR5IHRvIGRlYWwgd2l0aCBtaXNzaW5nIGRhdGEgKHByZWRpY3QgbXVsdGlwbGUgKGspIHN0ZXBzIGFoZWFkKQotIGFiaWxpdHkgdG8gYXBwbHkgYSBwcm9jZXNzIG1vZGVsIChjb250cm9sIHNpZ25hbCkKCnRoZSBhZ2VudCBtdXN0IHBlcmZvcm0gYW4gYWN0aXZlIGludGVydmVudGlvbiBpbiBoaXMgcHJvYmFiaWxpc3RpYyBtb2RlbDsgb3VyIHByb3Bvc2FsIGlzIHRoYXQgaGUgY2FuIGNoYW5nZSBoaXMgcmVzYW1wbGluZyBzdHJhdGVneSAtIF9faGUgY2FuIGNob29zZSBub3QgdG8gcmVzYW1wbGVfXy4gQnkgbm90IHJlc2FtcGxpbmcgaGUgY2FuIGlnbm9yZSB0aGUgaW5jb21pbmcgZGF0YS4gCgo+IEFuIGFkdmFudGFnZSBvZiB0aGlzIHN0cmF0ZWd5IGlzIHRoYXQgaGUgaXMgcnVubmluZyBhIG1vZGVsLCBhbmQgdGhlIHNlbnNvcnkgZGF0YSBhcmUgc3RpbGwgY29taW5nIGluLiBUaGVyZWZvcmUsIGhlIGNhbiBzdGlsbCBtb25pdG9yIHRoZSBsaWtlbGlob29kIG9mIGhpcyBtb2RlbCwgaS5lLiBoZSBjYW4gZG8gYSByZWFsaXR5IGNoZWNrIChoeXBvdGhlc2lzIHRlc3QpIHRvIG1ha2Ugc3VyZSB0aGF0IGhpcyAnZmFudGFzeScgbW9kZWwgZG9lcyBub3QgZXhwbGFpbiByZWFsaXR5LCBpLmUuIGl0IGlzIG5vdCByZWFsLgoKVGhlIG5leHQgRmlndXJlIHNob3dzIHRoZSBhZ2VudCdzIHNlbnNvcnkgaW5wdXQgd2hpbHN0IHJlbWFpbmluZyBzdGF0aW9uYXJ5LgoKCgpgYGB7ciBnZW5lcmF0ZS1wbG90LW9mZmxpbmUtdHJhamVjdG9yeX0Kc2V0LnNlZWQoODUyOTU3M0wpCmRhdGFfb2ZmbGluZSA8LSBnZW5lcmF0ZV9kYXRhKFQgPSAyLCBhbXBsaXR1ZGUgPSAwLCBzZW5zb3Jfc2QgPSAxLjcpICU+JSAKICAgIHQoKSAlPiUgCiAgICBkYXRhLmZyYW1lKCkKCnBsb3RfdHJhamVjdG9yaWVzKGRhdGEgPSBkYXRhX29mZmxpbmUpCmBgYAoKClRoZSBsYXN0IHR3byBGaWd1cmVzIHNob3cgdGhlIGFnZW50IHNob3dzIHRoZSBhZ2VudCBlbmdhZ2VkIGluICdpbWFnaW5pbmcnIGEgcmlnaHR3YXJkIG1vdGlvbiwgd2l0aCBhbXBsaXR1ZGUgJEEkID0gYHIgcGFyYW1zJEFgLCB1c2luZyB0d28gZGlmZmVyZW50IGRlZ3JlZXMgb2YgY2VydGFpbnR5LiBJbiB0aGUgZmlyc3QsIHRoZSBhZ2VudHMgCgoKYGBge3IgcnVuLXBhcnRpY2xlLWZpbHRlci13aXRob3V0LXJlc2FtcGxpbmctMX0KcGFyYW1zIDwtIGxpc3Qoc2R4ID0gMC44LCBzZHkgPSA0LjAsIEEgPSA1LCBmdW5feCA9IGYpCgpvdXQgPC0gcnVuX3BhcnRpY2xlX2ZpbHRlcihkYXRhID0gZGF0YV9vZmZsaW5lLCBOID0gMTAwLCBUaW1lID0gbGVuZ3RoKGRhdGEkb2JzZXJ2YXRpb25zKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgeF9pbml0ID0gMCwgc2R4X2luaXQgPSAwLjUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFtcywgcmVzYW1wbGUgPSBGQUxTRSwgcnNfdGhyZXNoID0gMC41KQpwbG90X2ZpbHRlcmluZ19lc3RpbWF0ZXMob3V0LCBkYXRhID0gZGF0YV9vZmZsaW5lKQpgYGAKCkluIHRoZSBmaXJzdCwgJFxzaWdtYV97cHJvY2Vzc30kID0gYHIgcGFyYW1zJHNkeGA7IHRoZXJlZm9yZSwgdGhlIGFnZW50IGlzIHZlcnkgY2VydGFpbiBvZiBoaXMgYmVsaWVmLCBpLmUuIGhlIGlzIGV4cGVyaWVuY2luZyBfX3ZpdmlkIGltYWdlcnlfXy4KCmBgYHtyIHJ1bi1wYXJ0aWNsZS1maWx0ZXItd2l0aG91dC1yZXNhbXBsaW5nLTJ9CnBhcmFtcyA8LSBsaXN0KHNkeCA9IDIuOCwgc2R5ID0gNC4wLCBBID0gLTIsIGZ1bl94ID0gZikKCm91dCA8LSBydW5fcGFydGljbGVfZmlsdGVyKGRhdGEgPSBkYXRhX29mZmxpbmUsIE4gPSAxMDAsIFRpbWUgPSBsZW5ndGgoZGF0YSRvYnNlcnZhdGlvbnMpLAogICAgICAgICAgICAgICAgICAgICAgICAgICB4X2luaXQgPSAwLCBzZHhfaW5pdCA9IDAuNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFyYW1zLCByZXNhbXBsZSA9IEZBTFNFLCByc190aHJlc2ggPSAwLjUpCnBsb3RfZmlsdGVyaW5nX2VzdGltYXRlcyhvdXQsIGRhdGEgPSBkYXRhX29mZmxpbmUpCmBgYAoKSW4gdGhlIHNlY29uZCwgJFxzaWdtYV97cHJvY2Vzc30kID0gYHIgcGFyYW1zJHNkeGA7IHRoZXJlZm9yZSwgdGhlIGFnZW50IGlzIHZlcnkgdW5jZXJ0YWluIG9mIGhpcyBiZWxpZWYsIGkuZS4gaGlzIF9faW1hZ2VyeV9fIGlzIG5vdCB2ZXJ5IHZpdmlkLgoKTm90ZSwgaG93ZXZlciwgdGhhdCBpbiBib3RoIGNhc2VzLCB0aGUgYWdlbnQgaXMgbm90IGludGVyZXN0ZWQgaW4gJ2V4cGxhaW5pbmcnIHRoZSBzZW5zb3J5IGRhdGEsIGkuZS4gaGlzIGltYWdpbmVkIG1vdGlvbiBpcyBub3QgY29uc3RyYWluZWQgYnkgdGhlIG1lYXN1cmVtZW50cy4K