Solving ODEs with the package DeSolve

A first example

Load the library deSolve.

library(deSolve)

Define the ODE system to solve: equations, parameter values, initial condition, and time span. Equations are defined as a function, the function must be defined as

func <- function(t,y,pars,...)

where t is the time, y is the vector of the state variables and pars is a vector or list of parameters. The return value of the function should be a list, whose first element is a vector of the derivative of y with respect to time: dy/dt. The next elements are used to pass global values. For example, the equations for the Lorenz system for atmoshperic chaos are defined in the function Lorenz:

Lorenz <- function(t, state, parameters) {
  with(as.list(c(state, parameters)), {
    dX <-  a * X + Y * Z
    dY <-  b * (Y - Z)
    dZ <- -X * Y + c * Y - Z
    list(c(dX, dY, dZ))
  })
}

Here, the argument state expects an array with names X, Y and Z. The initial conditions both define the names and the initial values of the variables.

vars <- c(X = 1, Y = 1, Z = 1)

The parameter values are set in a named list:

params <- c(a = -8/3, b = -10, c = 28)

The time points at which the solution musst be computed

tim <- seq(0, 100, by = 0.01)

The main interface for solving ODEs is the function ode. It takes following arguments:

ode(y, times, func, parms)

For the Lorenz system we have just defined, the call to ode is

sol <- ode(y = vars, times = tim, func = Lorenz, parms = params)

The output is a deSolve matrix. The first colmun is time, the other columns are the solution for each of the variables of the equations. The is a plot method (plot.deSolve) for plotting the solution, with can be called just with plot.

plot(sol)

The solution can also be plotted with the default plot command

plot(sol[,'Y'], sol[,'Z'], ty = 'l')

Or the argument which can be used to select which variables to plot.

plot(sol, which = c('Y','Z'))

The optional argument method selects the numerical integrator among several. The default integrator is lsoda. LSODA is an integrator for solving stiff and non-stiff systems of ordinary differential equations. It was written in FORTRAN by Linda Petzold and Alan Hindmarsh. It can solve systems with dense or banded Jacobian when the problem is stiff. LSODA autamatically selects between a stiff solver (backward differencing formulae, BDF) and a non-stiff solver (Adams). This and other integrators can be used directly by their names. LSODA should be the first integrator to try when solving a new system.

sol.lsoda <- lsoda(y = vars, times = tim, func = Lorenz, parms = params)
plot(sol.lsoda, which = 'X')

Stiff equations

The stiffness of an equation has many definitions. Mathematically, a system

\[ \frac{dx}{dt} = F(x)\]

is stiff if some of the eigenvalues \(\lambda_1, \lambda_2\), of the Jacobian matrix of \(F\) have much different orders of magnitudes

\[|\lambda_1| \ll |\lambda_2|.\]

Numerically, stiff systems are best solved with implicit methods. Solving stiff equations with explicit methods while maintaining a good accuracy is very slow. Let’s use a prototype stiff system, the van der Pol oscillator. The van der Pol oscillator is a second-order equation

\[\frac{d^2x}{dt} = \mu \Bigl( (1-x^2) \frac{dx}{dt} - x \Bigr) + F(t).\] The term \(F(t)\) is a force term that we set to zero. The van der Pol oscilator is a nonlinear oscillator. Superficially, it looks like a damped harmonic oscillator, except that the damping force is negative when \(x\) is small, so that instead of losing energy, the system gains in energy. The system is stiff when the paramter value is large; we will set \(\mu = 1e6\).

Solve the van der Pol equation with an explicit integrator first, for times between 0 and 6.3, with \(y(0)=0.0\) and \(x(0) = 2.0\). First, express the equation as a system of two first-order equations

\[\frac{dy}{dt} = \mu \Bigl( (1-x^2) y - x \Bigr),\] \[\frac{dx}{dt} = y.\]

We use the Runge-Kutta method rk45ck. This is an explicit, variable step method of the fourth and fifth orders.

vanDerPol <- function(t, state, parameters) {
  with(as.list(c(state, parameters)), {
    dx <-  y
    dy <-  mu*((1-x*x)*y - x)
    list(c(dx, dy))
  })
}
vars <- c(x = 2.0, y = 0.0)
params <- c(mu = 1e6)
tim <- seq(0, 6.3, by = 0.01)
start_time <- Sys.time()
sol.rk <- rk(y = vars, times = tim, func = vanDerPol, parms = params, method = 'rk45ck', rtol = 1e-6, atol = 1e-6)

So it doesn’t work at all. Let’s try with a mininal time step, to speed things up, at the expense of accuracy, of course. The maximal number of steps also need to be increased.

tim <- seq(0, 6.3, by = 0.01)
start_time <- Sys.time()
sol.rk45 <- rk(y = vars, times = tim, func = vanDerPol, parms = params, method = 'rk45ck', hmin = 1e-7, rtol = 1e-6, atol = 1e-6, maxsteps = 1e8)
end_time <- Sys.time()
end_time - start_time
Time difference of 7.264611 mins
plot(sol.rk45, which = 'y')

Now, we use a backward-differentiation formula BDF to solve the system

tim <- seq(0, 6.3, by = 0.01)
start_time <- Sys.time()
sol.bdf <- ode(y = vars, times = tim, func = vanDerPol, parms = params, method = 'bdf', rtol = 1e-6, atol = 1e-6)
end_time <- Sys.time()
end_time - start_time
Time difference of 0.2508869 secs
plot(sol.bdf, which = 'y')

Plot both solutions on the same axes

The implicit BDF method is much faster than the explicit RK method.

Non-stiff systems are much easier to solve, and in most cases, explicit integrators are faster. If low accuracy is acceptable (for a non-stiff system), lower-order integrators such as ode23/rk23bs. Using explicit methods for stiff system leads either very small step sizes or to blow up of the solutions. In the worst case, the step size becomes so small it is smaller than espilon machine, so that t+dt = t, and the integrator becomes stuck. Blow up of solutions occurs when the time step is too large and solutions go out of their range of definition. For example, solution may become negative if the derivative is negative. Nonlinear rhs functions may not be appropriately defined for negative solutions, take \(1/(1+x)\), which is bounded for \(x>0\) but unbounded near \(x=-1\).

Non-stiff equations

Subtrate Producer Consumer model (3D) with a nonlinear function passed as argument to the model

Error control

The integrators lsoda and other routines of the deSolve package have error control. The numerical methods compute approximate solution at the next time step at two different order of accuracy. The difference between the two solutions is a good approximation of the size of the true error. This error is local, i.e. it is calculated assuming that the solution at time \(t\) is exact. Error is controled by setting tolerance options; if the error is larger than the tolerance, the integrator will reject the new solution and pick a smaller time step. If the error is less than the tolerance, the integrator will accept the new solution and increase the next time step to speed up the computation.

Two errors are computed, the relative error and the absolute error. In lsoda the solution is accepted if

\[err = \max |y_{high} - y_{low}| < \mathrm{rtol} \times |y| + \mathrm{atol}\] The option rtol and atol are the relative tolerance and the absolute tolerance respectively. The smaller the tolerance the more stringent the condition for accpeting the solution. The relative tolerance control the precision of the solution when far away from zero. A relative tolerance of 1e-6 specifies 6 digits of accuracy. The absolute tolerance specifies the accuracy when solutions are close to zero. An absolute tolerance of 1e-6 states that any solution smaller than 1e-6 should be regarded as effectively zero. for system of equations, the error is set to the max of the errors on each coefficients.

Remark The error control expression involves the sum of the tolerances. This is equivalent to an OR: if the error is smaller than either tolerances, the solution will be accepted. Therefore, it is absolutely possible to set rtol or atol to zero (but not both).

In summary, rtol controls the solution away from zero and atol controls the solution close to zero.

Non-negative solutions

It can often inconvenient to have negative a solution to an initial value problem to ODEs that theoretically should have only positive solution. Problems in biology and chemistry involving concentrations or population densities should admit only positive solutions, the RHS of the ODEs are often not defined outside the range of positive states. The initial value problem (IVP) for a system of ODE is

\[\frac{dy}{dt} = f(y,t), \; y(0) = y_0.\] For example, the IVP

\[\frac{dy}{dt} = -|y|, \; y(0) = 1.\] The solution is \(y(t) = \exp(-t)\) is positive, and decays to zero. Suppose that the numerical solution reaches a value \(y^* < 0\) at a time \(t^*\). Then the solution, starting at \(t^*\), is \(u(t) = y^*\exp(t-t^*)\). This solution is decreasing (towards \(-\infty\)). Thus the IVP is unstable, in the sense that small pertubation of the solution lead to large deviation from the true solution. This IVP will be the first test problem, solved on \([0,40]\)

# define the ODE equations
nonStiffTest1 <- function(t, x, parms)  {
  with(as.list(c(parms, x)), {
    dy <- - abs(y)
    list(dy)
  })
}
# set time points
times <- seq(0, 40)
# set initial conditions
y0 <- c(y = 1)
# solve the ODE system
sol <- ode(y = y0, times = times, parms = NULL, func = nonStiffTest1)
# plot solutions
plot(sol)

The second test is the Robertson problem. It is a semi-stable chemical reaction system

\[ \frac{dy_1}{dt} = -0.04 y_1 + 10^4 y_2 y_3, \\ \frac{dy_2}{dt} = 0.04 y_1 - 10^4 y_2 y_3 - 3 \times 10^7 y_2^2, \\ \frac{dy_3}{dt} = 3 \times 10^7 y_2^2, \]

with initial conditions \((1,0,0)^t\) with time interval \([0,4\times 10^{11}\). This is a stiff problem that need to be solved over a very large time interval.

Robertson <- function(t, state, parameters) {
  with(as.list(c(state, parameters)), {
    dy1 <-  -a*y1 + b*y2*y3
    dy2 <-   a*y1 - b*y2*y3 - c*y2*y2
    dy3 <-   c*y2*y2
    list(c(dy1, dy2, dy3))
  })
}
# set the parameter names and values
pars <- c(a = 0.04, b = 1e4, c = 3e7)
# set time points
times <- seq(0, 4e11, length.out = 50)
# set initial conditions
y0 <- c(y1 = 1, y2 = 0, y3 = 0)
# solve the ODE system
sol <- ode(y = y0, times = times, parms = pars, func = Robertson, rtol = 1e-6, atol = 1e-6)
# plot solutions
plot(sol, which = 'y1')

The Lotka-Volterra model for predator-prey dynamics admits oscillatory solutions that periodically come arbitrarily close to zero. The IVP is

\[ \frac{dy_1}{dt} = 0.5 y_1 \Bigl( 1 - \frac{y_1}{20} \Bigr) - 0.1 y_1 y_2, \\ \frac{dy_2}{dt} = 0.01 y_1 y_2 - 0.001 y_2, \] with initial conditions \((25,5)^t\) over the time interval \([0,870]\). If at some time \(t^*\) the numerical solution \(y_1^* < 0\), and the solution is then reset at \((0,y_2^*)^t\), the solution has \(y_1(t) = 0\) for all \(t > t^*\).

LotkaVolterra <- function(t, state, parameters) {
  with(as.list(c(state, parameters)), {
    dy1 <-  a * y1 * ( 1 - y1/b ) - c * y1 * y2
    dy2 <-  d * y1*y2 - e * y2
    list(c(dy1, dy2))
  })
}
# set the parameter names and values
pars <- c(a = 0.5, b = 20, c = 0.1, d = 0.01, e = 0.001)
# set time points
times <- seq(0,1000,length.out = 2)
# set initial conditions
y0 <- c(y1 = 25, y2 = 5)
# solve the ODE system
sol1 <- ode(y = y0, times = c(0,1000), parms = pars, func = LotkaVolterra, atol = 1e-12)
sol2 <- ode(y = y0, times = seq(0,1000,length.out = 1000), parms = pars, func = LotkaVolterra, atol = 1e-12)
# plot solutions
plot(sol1[,1],sol1[,'y1'])
lines(sol2[,1],sol2[,'y1'])

The IVP

\[\frac{dy}{dt} = \sqrt{1-y^2}, \; y(0) = 0.\] The solution \(y(t) = \sin(t)\) increases to 1 at \(t = \pi /2\), and the rhs is not defined for \(y>1\) (it is not Lipschitz). The solution it not unique after \(t^* = \pi/2\).

# define the ODE equations
Ball <- function(t, x, parms)  {
  with(as.list(c(parms, x)), {
    dy <- sqrt(1-y*y)
    list(dy)
  })
}
# set time points
times <- seq(0, 3, length.out = 100)
# set initial conditions
y0 <- c(y = 0)
# solve the ODE system
sol <- ode(y = y0, times = times, parms = NULL, func = Ball, method = 'bdf')
NaNs producedNaNs producedNaNs producedNaNs producedNaNs producedNaNs producedNaNs producedNaNs producedNaNs producedNaNs producedNaNs producedNaNs producedNaNs producedNaNs producedNaNs producedNaNs producedNaNs producedNaNs producedNaNs producedNaNs producedNaNs producedNaNs producedNaNs producedNaNs producedNaNs produced
DLSODE-  At T (=R1) and step size H (=R2), the    
      corrector convergence failed repeatedly     
      or with ABS(H) = HMIN   
In above message, R1 = 1.57137, R2 = 7.22481e-09
 
repeated convergence test failures on a step, but integration was successful - inaccurate Jacobian matrix?Returning early. Results are accurate, as far as they go
# plot solutions
plot(sol)

Example of a Runge-Kutta pair of order 2 and 3: Bogacki-Shampine RK3(2)

The numerical scheme is a pair of Runge-Kutta formulas, one of order 3 and one of order 2. For the differential equation

\[\frac{dy(t)}{dt} = f(t,y(t)), \; a \leq t \leq b,\] \[y(a) = y_a.\]

The two formulas are used to advance the solution by a time step \(h\), given a solution \(y_n\) at time step \(t_n\). The difference between the third order \(\hat y_{n+1}\) and the second order step \(y_{n+1}\) provides an estimate of the error \(E\) to the true solution. Each formula requires several evaluations of the function \(f\). Evaluation is done in \(S\) stages:

\[y_{n+1} = \hat y_{n} + h \sum_{i=1}^S b_i k_i.\]

Stages \(k_i\) are calculated iteratively: \(k_i\) depends only on the previous \(k_j\), \(j=1,...,i-1\). The first stage is always

\[k_1 = f(t_n, y_n).\]

The other stages are

\[k_i = f \bigl( x_n + c_i h, y_n + h \sum_{j=1}^{i-1} a_{i,j} k_j \bigr),\] and

\[c_i = \sum_{j=1}^{i-1} a_{i,j}\]

To reduce the total number of function evaluations, a strategy consists in sharing the stages \(k_i\) between the two formulas, this is called embedding. Third order Runge-Kutta formulas need at least three stages, and second order formulas at least two stages. Each stage require one evalutation of the function \(f\). The first step \(k_1\) is always shared. If the second stage of the third order formula is also used in the second order formula, the total number of function evaluations is 3: we get the second order approximation almost for free.

However, Bogacki and Shampine reason in a different way. They want to match as closely as possible the regions of stability of the two formulas. All two-stage, second order formulas have the same region of stability and have all three-stages, third order formulas. The only way to match the regions of stability is to increase the number of stages. Increasing the number of stages leaves quite a lot of room for choosing the coefficient, and Bogacki and Shampine took a four stages for the second order formula. This seems rather superfluous, but they also reuse the first three stages in the second-order formula. The fourth stage of the second order formula is

\[k_4 = f(t_n + h, \hat y_n + h \sum_{j=1}^3 \hat b_j k_j).\] Notice that \(k_4\) is excatly the value of the function \(f\) at \(t_{n+1} = t_n + h\) and \(\hat y_{n+1} = \hat y_n + h \sum_{j=1}^3 \hat b_j k_j\). This is the first stage \(k_1\) of the next time step! Once we realize that most steps are successful, we see that the four-stage, second order formula come at little extra computational cost: \(k_4\) is carried over to the next time step. This approach is call FSAL: First Same As Last.

The Butcher tableau for the pair of formula is

0   | 
1/2 | 1/2
3/4 |   0   3/4
  1 | 2/9   1/3 4/9
--- - ----  --- --- ---
    | 2/9   1/3 4/9   0
    | 7/24  1/4 1/3 1/8     

# Event location

Event location is an option to track the solution of a system of ODE while it is being solved for. This useful, but not limited to cases when the dynamic variable are suddenly changed, i.e. when the dynamical variables are discontinuous. Normal integration routines cannot deal very well with discontinuities. The events option specifies when the events or discontiuities should occur, so that the integrator can deal with it. Events are imposed either by a data.frame that specifies the times at which the variables have jumps, or by an event function that monitor the state of the variable. A root function will trigger an event when the function takes the value zero.

The event function has the same syntax as the ode funcion: function(t,y,params, ...). The data.frame should have the folowing columns, in that order: var the state variable name or number affected by the event, time the time at which the event takes place, value the magnitude of the event, method how to set the new values, one of “replace”, “add”, “multiply”.

The row:

"v1" 10 2 "add"

would add 2 to the variable v1 at time 10.

The routines lsoda (and some others) have root-finding abilities. If a root function is specified, the solver will stop at the first root. To monitor the location of many events, an event function must be set that will leave the state variables unaltered.

Example 1 Event in a data.frame

# ODE function
myOdefunc <- function(t, var, pars) 
{
  with(as.list(c(pars, var)), {
    dx <- 0
    dy <- - a * y
    list(c(dx,dy))
  })
}
y0 <- c(x = 0, y = 1) # initial condition (x,y must be the same x,y as inside myOdeFunc)
pars <- c(a = 1.2) # parameters (a must be the same a as inisde myOdeFunc)
times <- seq(0,10,by=0.1)
# define a data.frame called eventDataFrame
eventDataFrame <- data.frame(var = c("x", "y", "y", "x"),
                             time = c(1,1,5,9),
                             value = c(1,2,3,4),
                             method = c("add", "mult", "rep", "add"))
sol <- ode(y = y0, func = myOdefunc, times = times, parms = pars, 
           event = list(data = eventDataFrame))
plot(sol)

Example 2 Event in a function

myOdefunc <- function(t, var, pars) 
{
  with(as.list(c(pars, var)), {
    dx <- 0
    dy <- - a * y
    list(c(dx,dy))
  })
}
# events: add 1 to x, multiply y with a random number
eventFun <- function(t, var, parms){
  with (as.list(var),{
    x <- x + 1
    y <- 5 * runif(1)
    return(c(x, y))
  })
}
y0 <- c(x = 1, y = 2)
times <- seq(0, 10, by = 0.1)
pars <- c(a = 1.2)
sol <- ode(func = myOdefunc, y = y0, times = times, parms = pars,
           events = list(func = eventFun, time = c(1:9, 2.2, 2.4)) )
Not all event times 'events$time' are in output 'times' so they are automatically included.Some time steps were very close to events - only the event times are used in these cases.
plot(sol, type = "l")

Event triggered by a root function

## ODE: simple first-order decay
firstOrderDecay <- function(t, var, pars) {
  with(as.list(c(pars, var)), {
    dy <- - a * y
    list(c(dy))
  })
}
## event triggered if state variable y = 0.5
rootFun <- function (t, var, pars) {
  with(as.list(c(pars, var)), {
    y - 0.5
  })
}
## sets state variable = 1
eventFun <- function(t, y, pars) {
    with (as.list(var),{
    y <- 1
    return(y)
  })
}
y0 <- c(y = 2)
times <- seq(0, 100, 0.1)
pars <- c(a = 0.1)
## uses ode to solve; root = TRUE specifies that the event is
## triggered by a root.
sol <- ode(times = times, y = y0, func = firstOrderDecay, parms = pars,
           events = list(func = eventFun, root = TRUE),
           rootfun = rootFun)
plot(sol, type = "l")
## time of the root:
times_root <- attributes(sol)$troot
points(times_root, rep(0.5, length(times_root)))

LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyBTb2x2aW5nIE9ERXMgd2l0aCB0aGUgcGFja2FnZSBgRGVTb2x2ZWAKCiMjIEEgZmlyc3QgZXhhbXBsZQoKTG9hZCB0aGUgbGlicmFyeSBgZGVTb2x2ZWAuCgpgYGB7cn0KbGlicmFyeShkZVNvbHZlKQpgYGAKCkRlZmluZSB0aGUgT0RFIHN5c3RlbSB0byBzb2x2ZTogZXF1YXRpb25zLCBwYXJhbWV0ZXIgdmFsdWVzLCBpbml0aWFsIGNvbmRpdGlvbiwgYW5kIHRpbWUgc3Bhbi4gIEVxdWF0aW9ucyBhcmUgZGVmaW5lZCBhcyBhIGBmdW5jdGlvbmAsIHRoZSBmdW5jdGlvbiBtdXN0IGJlIGRlZmluZWQgYXMKCmBgYApmdW5jIDwtIGZ1bmN0aW9uKHQseSxwYXJzLC4uLikKYGBgCgp3aGVyZSBgdGAgaXMgdGhlIHRpbWUsIGB5YCBpcyB0aGUgdmVjdG9yIG9mIHRoZSBzdGF0ZSB2YXJpYWJsZXMgYW5kIGBwYXJzYCBpcyBhIHZlY3RvciBvciBsaXN0IG9mIHBhcmFtZXRlcnMuIApUaGUgcmV0dXJuIHZhbHVlIG9mIHRoZSBmdW5jdGlvbiBzaG91bGQgYmUgYSBsaXN0LCB3aG9zZSBmaXJzdCBlbGVtZW50IGlzIGEgdmVjdG9yIG9mIHRoZSBkZXJpdmF0aXZlIG9mIHkgd2l0aCAKcmVzcGVjdCB0byB0aW1lOiBkeS9kdC4gVGhlIG5leHQgZWxlbWVudHMgYXJlIHVzZWQgdG8gcGFzcyBnbG9iYWwgdmFsdWVzLiBGb3IgZXhhbXBsZSwgdGhlIGVxdWF0aW9ucyBmb3IgdGhlIExvcmVueiBzeXN0ZW0gZm9yIGF0bW9zaHBlcmljIGNoYW9zIGFyZSBkZWZpbmVkIGluIHRoZSBmdW5jdGlvbiBgTG9yZW56YDoKCmBgYHtyfQpMb3JlbnogPC0gZnVuY3Rpb24odCwgc3RhdGUsIHBhcmFtZXRlcnMpIHsKICB3aXRoKGFzLmxpc3QoYyhzdGF0ZSwgcGFyYW1ldGVycykpLCB7CiAgICBkWCA8LSAgYSAqIFggKyBZICogWgogICAgZFkgPC0gIGIgKiAoWSAtIFopCiAgICBkWiA8LSAtWCAqIFkgKyBjICogWSAtIFoKICAgIGxpc3QoYyhkWCwgZFksIGRaKSkKICB9KQp9CmBgYAoKSGVyZSwgdGhlIGFyZ3VtZW50IGBzdGF0ZWAgZXhwZWN0cyBhbiBhcnJheSB3aXRoIG5hbWVzIGBYYCwgYFlgIGFuZCBgWmAuIFRoZSBpbml0aWFsIGNvbmRpdGlvbnMgYm90aCBkZWZpbmUgdGhlIG5hbWVzIGFuZCB0aGUgaW5pdGlhbCB2YWx1ZXMgb2YgdGhlIHZhcmlhYmxlcy4KCmBgYHtyfQp2YXJzIDwtIGMoWCA9IDEsIFkgPSAxLCBaID0gMSkKYGBgCgpUaGUgcGFyYW1ldGVyIHZhbHVlcyBhcmUgc2V0IGluIGEgbmFtZWQgbGlzdDoKCmBgYHtyfQpwYXJhbXMgPC0gYyhhID0gLTgvMywgYiA9IC0xMCwgYyA9IDI4KQpgYGAKClRoZSB0aW1lIHBvaW50cyBhdCB3aGljaCB0aGUgc29sdXRpb24gbXVzc3QgYmUgY29tcHV0ZWQKCmBgYHtyfQp0aW0gPC0gc2VxKDAsIDEwMCwgYnkgPSAwLjAxKQpgYGAKClRoZSBtYWluIGludGVyZmFjZSBmb3Igc29sdmluZyBPREVzIGlzIHRoZSBmdW5jdGlvbiBgb2RlYC4gSXQgdGFrZXMgZm9sbG93aW5nIGFyZ3VtZW50czoKCmBgYApvZGUoeSwgdGltZXMsIGZ1bmMsIHBhcm1zKQpgYGAKCkZvciB0aGUgTG9yZW56IHN5c3RlbSB3ZSBoYXZlIGp1c3QgZGVmaW5lZCwgdGhlIGNhbGwgdG8gIGBvZGVgIGlzCgpgYGB7cn0Kc29sIDwtIG9kZSh5ID0gdmFycywgdGltZXMgPSB0aW0sIGZ1bmMgPSBMb3JlbnosIHBhcm1zID0gcGFyYW1zKQpgYGAKClRoZSBvdXRwdXQgaXMgYSBkZVNvbHZlIG1hdHJpeC4gVGhlIGZpcnN0IGNvbG11biBpcyB0aW1lLCB0aGUgb3RoZXIgY29sdW1ucyBhcmUgdGhlIHNvbHV0aW9uIGZvciBlYWNoIG9mIHRoZSB2YXJpYWJsZXMgb2YgdGhlIGVxdWF0aW9ucy4gVGhlIGlzIGEgcGxvdCBtZXRob2QgKGBwbG90LmRlU29sdmVgKSBmb3IgcGxvdHRpbmcgdGhlIHNvbHV0aW9uLCB3aXRoIGNhbiBiZSBjYWxsZWQganVzdCB3aXRoIGBwbG90YC4KCmBgYHtyfQpwbG90KHNvbCkKYGBgCgoKVGhlIHNvbHV0aW9uIGNhbiBhbHNvICBiZSBwbG90dGVkIHdpdGggdGhlIGRlZmF1bHQgcGxvdCBjb21tYW5kCgpgYGB7cn0KcGxvdChzb2xbLCdZJ10sIHNvbFssJ1onXSwgdHkgPSAnbCcpCmBgYAoKT3IgdGhlIGFyZ3VtZW50IGB3aGljaGAgY2FuIGJlIHVzZWQgdG8gc2VsZWN0IHdoaWNoIHZhcmlhYmxlcyB0byBwbG90LgoKYGBge3J9CnBsb3Qoc29sLCB3aGljaCA9IGMoJ1knLCdaJykpCmBgYAoKVGhlIG9wdGlvbmFsIGFyZ3VtZW50IGBtZXRob2RgIHNlbGVjdHMgdGhlIG51bWVyaWNhbCBpbnRlZ3JhdG9yIGFtb25nIHNldmVyYWwuIFRoZSBkZWZhdWx0IGludGVncmF0b3IgaXMgYGxzb2RhYC4KTFNPREEgaXMgYW4gaW50ZWdyYXRvciBmb3Igc29sdmluZyBzdGlmZiBhbmQgbm9uLXN0aWZmIHN5c3RlbXMgb2Ygb3JkaW5hcnkgZGlmZmVyZW50aWFsIGVxdWF0aW9ucy4gSXQgd2FzIHdyaXR0ZW4gaW4gRk9SVFJBTiBieSBMaW5kYSBQZXR6b2xkIGFuZCBBbGFuIEhpbmRtYXJzaC4gSXQgY2FuIHNvbHZlIHN5c3RlbXMgd2l0aCBkZW5zZSBvciBiYW5kZWQgSmFjb2JpYW4gd2hlbiB0aGUgcHJvYmxlbSBpcyBzdGlmZi4gTFNPREEgYXV0YW1hdGljYWxseSBzZWxlY3RzIGJldHdlZW4gYSBzdGlmZiBzb2x2ZXIgKGJhY2t3YXJkIGRpZmZlcmVuY2luZyBmb3JtdWxhZSwgQkRGKSBhbmQgYSBub24tc3RpZmYgc29sdmVyIChBZGFtcykuIFRoaXMgYW5kIG90aGVyIGludGVncmF0b3JzIGNhbiBiZSB1c2VkIGRpcmVjdGx5IGJ5IHRoZWlyIG5hbWVzLiBMU09EQSBzaG91bGQgYmUgdGhlIGZpcnN0IGludGVncmF0b3IgdG8gdHJ5IHdoZW4gc29sdmluZyBhIG5ldyBzeXN0ZW0uIAoKYGBge3J9CnNvbC5sc29kYSA8LSBsc29kYSh5ID0gdmFycywgdGltZXMgPSB0aW0sIGZ1bmMgPSBMb3JlbnosIHBhcm1zID0gcGFyYW1zKQpwbG90KHNvbC5sc29kYSwgd2hpY2ggPSAnWCcpCmBgYAoKIyBTdGlmZiBlcXVhdGlvbnMKClRoZSBzdGlmZm5lc3Mgb2YgYW4gZXF1YXRpb24gaGFzIG1hbnkgZGVmaW5pdGlvbnMuIE1hdGhlbWF0aWNhbGx5LCBhIHN5c3RlbSAKCiQkIFxmcmFje2R4fXtkdH0gPSBGKHgpJCQKCmlzIHN0aWZmIGlmIHNvbWUgb2YgdGhlIGVpZ2VudmFsdWVzICRcbGFtYmRhXzEsIFxsYW1iZGFfMiQsIG9mIHRoZSBKYWNvYmlhbiBtYXRyaXggb2YgJEYkIGhhdmUgbXVjaCBkaWZmZXJlbnQgb3JkZXJzIG9mIG1hZ25pdHVkZXMgCgokJHxcbGFtYmRhXzF8IFxsbCB8XGxhbWJkYV8yfC4kJAoKTnVtZXJpY2FsbHksIHN0aWZmIHN5c3RlbXMgYXJlIGJlc3Qgc29sdmVkIHdpdGggKmltcGxpY2l0KiBtZXRob2RzLiBTb2x2aW5nIHN0aWZmIGVxdWF0aW9ucyB3aXRoIGV4cGxpY2l0IG1ldGhvZHMgd2hpbGUgbWFpbnRhaW5pbmcgYSBnb29kIGFjY3VyYWN5IGlzIHZlcnkgc2xvdy4gTGV0J3MgdXNlIGEgcHJvdG90eXBlIHN0aWZmIHN5c3RlbSwgdGhlIHZhbiBkZXIgUG9sIG9zY2lsbGF0b3IuClRoZSB2YW4gZGVyIFBvbCBvc2NpbGxhdG9yIGlzIGEgc2Vjb25kLW9yZGVyIGVxdWF0aW9uIAoKJCRcZnJhY3tkXjJ4fXtkdH0gPSBcbXUgXEJpZ2woICgxLXheMikgXGZyYWN7ZHh9e2R0fSAtIHggXEJpZ3IpICsgRih0KS4kJCAKVGhlIHRlcm0gJEYodCkkICBpcyBhIGZvcmNlIHRlcm0gdGhhdCB3ZSBzZXQgdG8gemVyby4gVGhlIHZhbiBkZXIgUG9sIG9zY2lsYXRvciBpcyBhIG5vbmxpbmVhciBvc2NpbGxhdG9yLiBTdXBlcmZpY2lhbGx5LCBpdCBsb29rcyBsaWtlIGEgZGFtcGVkIGhhcm1vbmljIG9zY2lsbGF0b3IsIGV4Y2VwdCB0aGF0IHRoZSBkYW1waW5nIGZvcmNlIGlzICpuZWdhdGl2ZSogd2hlbiAkeCQgaXMgc21hbGwsIHNvIHRoYXQgaW5zdGVhZCBvZiBsb3NpbmcgZW5lcmd5LCB0aGUgc3lzdGVtIGdhaW5zIGluIGVuZXJneS4gVGhlIHN5c3RlbSBpcyBzdGlmZiB3aGVuIHRoZSBwYXJhbXRlciB2YWx1ZSBpcyBsYXJnZTsgd2Ugd2lsbCBzZXQgJFxtdSA9IDFlNiQuCgpTb2x2ZSB0aGUgdmFuIGRlciBQb2wgZXF1YXRpb24gd2l0aCBhbiBleHBsaWNpdCBpbnRlZ3JhdG9yIGZpcnN0LCBmb3IgdGltZXMgYmV0d2VlbiAwIGFuZCA2LjMsIHdpdGggJHkoMCk9MC4wJCBhbmQKJHgoMCkgPSAyLjAkLiBGaXJzdCwgZXhwcmVzcyB0aGUgZXF1YXRpb24gYXMgYSBzeXN0ZW0gb2YgdHdvIGZpcnN0LW9yZGVyIGVxdWF0aW9ucwoKJCRcZnJhY3tkeX17ZHR9ID0gXG11IFxCaWdsKCAoMS14XjIpIHkgLSB4IFxCaWdyKSwkJAokJFxmcmFje2R4fXtkdH0gPSB5LiQkCgpXZSB1c2UgdGhlIFJ1bmdlLUt1dHRhIG1ldGhvZCBgcms0NWNrYC4gVGhpcyBpcyBhbiBleHBsaWNpdCwgdmFyaWFibGUgc3RlcCBtZXRob2Qgb2YgdGhlIGZvdXJ0aCBhbmQgZmlmdGggb3JkZXJzLiAKCgpgYGB7cn0KdmFuRGVyUG9sIDwtIGZ1bmN0aW9uKHQsIHN0YXRlLCBwYXJhbWV0ZXJzKSB7CiAgd2l0aChhcy5saXN0KGMoc3RhdGUsIHBhcmFtZXRlcnMpKSwgewogICAgZHggPC0gIHkKICAgIGR5IDwtICBtdSooKDEteCp4KSp5IC0geCkKICAgIGxpc3QoYyhkeCwgZHkpKQogIH0pCn0KdmFycyA8LSBjKHggPSAyLjAsIHkgPSAwLjApCnBhcmFtcyA8LSBjKG11ID0gMWU2KQp0aW0gPC0gc2VxKDAsIDYuMywgYnkgPSAwLjAxKQoKc3RhcnRfdGltZSA8LSBTeXMudGltZSgpCnNvbC5yayA8LSByayh5ID0gdmFycywgdGltZXMgPSB0aW0sIGZ1bmMgPSB2YW5EZXJQb2wsIHBhcm1zID0gcGFyYW1zLCBtZXRob2QgPSAncms0NWNrJywgcnRvbCA9IDFlLTYsIGF0b2wgPSAxZS02KQplbmRfdGllbSA8LSBTeXMudGltZSgpCmVuZF90aW1lIC0gc3RhcnRfdGltZQpgYGAKClNvIGl0IGRvZXNuJ3Qgd29yayBhdCBhbGwuIExldCdzIHRyeSB3aXRoIGEgbWluaW5hbCB0aW1lIHN0ZXAsIHRvIHNwZWVkIHRoaW5ncyB1cCwgYXQgdGhlIGV4cGVuc2Ugb2YgYWNjdXJhY3ksICBvZiBjb3Vyc2UuIFRoZSBtYXhpbWFsIG51bWJlciBvZiBzdGVwcyBhbHNvIG5lZWQgdG8gYmUgaW5jcmVhc2VkLiAKCmBgYHtyfQp0aW0gPC0gc2VxKDAsIDYuMywgYnkgPSAwLjAxKQpzdGFydF90aW1lIDwtIFN5cy50aW1lKCkKc29sLnJrNDUgPC0gcmsoeSA9IHZhcnMsIHRpbWVzID0gdGltLCBmdW5jID0gdmFuRGVyUG9sLCBwYXJtcyA9IHBhcmFtcywgbWV0aG9kID0gJ3JrNDVjaycsIGhtaW4gPSAxZS03LCBydG9sID0gMWUtNiwgYXRvbCA9IDFlLTYsIG1heHN0ZXBzID0gMWU4KQplbmRfdGltZSA8LSBTeXMudGltZSgpCmVuZF90aW1lIC0gc3RhcnRfdGltZQpgYGAKCmBgYHtyfQpwbG90KHNvbC5yazQ1LCB3aGljaCA9ICd5JykKYGBgCgpOb3csIHdlIHVzZSBhIGJhY2t3YXJkLWRpZmZlcmVudGlhdGlvbiBmb3JtdWxhIGBCREZgIHRvIHNvbHZlIHRoZSBzeXN0ZW0KCmBgYHtyfQp0aW0gPC0gc2VxKDAsIDYuMywgYnkgPSAwLjAxKQpzdGFydF90aW1lIDwtIFN5cy50aW1lKCkKc29sLmJkZiA8LSBvZGUoeSA9IHZhcnMsIHRpbWVzID0gdGltLCBmdW5jID0gdmFuRGVyUG9sLCBwYXJtcyA9IHBhcmFtcywgbWV0aG9kID0gJ2JkZicsIHJ0b2wgPSAxZS02LCBhdG9sID0gMWUtNikKZW5kX3RpbWUgPC0gU3lzLnRpbWUoKQplbmRfdGltZSAtIHN0YXJ0X3RpbWUKYGBgCgpgYGB7cn0KcGxvdChzb2wuYmRmLCB3aGljaCA9ICd5JykKYGBgCgpQbG90IGJvdGggc29sdXRpb25zIG9uIHRoZSBzYW1lIGF4ZXMKCmBgYHtyfQpwbG90KHNvbC5yazQ1LCB3aGljaCA9ICd5JywgeWxpbSA9IGMoLTQsNCkpCmxpbmVzKHNvbC5iZGZbLCd0aW1lJ10sc29sLmJkZlssJ3knXSwgY29sID0gJ2JsdWUnKQpgYGAKClRoZSBpbXBsaWNpdCBCREYgbWV0aG9kIGlzICptdWNoKiBmYXN0ZXIgdGhhbiB0aGUgZXhwbGljaXQgUksgbWV0aG9kLiAKCk5vbi1zdGlmZiBzeXN0ZW1zIGFyZSBtdWNoIGVhc2llciB0byBzb2x2ZSwgYW5kIGluIG1vc3QgY2FzZXMsIGV4cGxpY2l0IGludGVncmF0b3JzIGFyZSBmYXN0ZXIuIElmIGxvdyBhY2N1cmFjeSBpcyBhY2NlcHRhYmxlIChmb3IgYSBub24tc3RpZmYgc3lzdGVtKSwgbG93ZXItb3JkZXIgaW50ZWdyYXRvcnMgc3VjaCBhcyBgb2RlMjNgL2ByazIzYnNgLiBVc2luZyBleHBsaWNpdCBtZXRob2RzIGZvciBzdGlmZiBzeXN0ZW0gbGVhZHMgZWl0aGVyIHZlcnkgc21hbGwgc3RlcCBzaXplcyBvciB0byBibG93IHVwIG9mIHRoZSBzb2x1dGlvbnMuIEluIHRoZSB3b3JzdCBjYXNlLCB0aGUgc3RlcCBzaXplIGJlY29tZXMgc28gc21hbGwgaXQgaXMgc21hbGxlciB0aGFuIGVzcGlsb24gbWFjaGluZSwgc28gdGhhdCB0K2R0ID0gdCwgYW5kIHRoZSBpbnRlZ3JhdG9yIGJlY29tZXMgc3R1Y2suIEJsb3cgdXAgb2Ygc29sdXRpb25zIG9jY3VycyB3aGVuIHRoZSB0aW1lIHN0ZXAgaXMgdG9vIGxhcmdlIGFuZCBzb2x1dGlvbnMgZ28gb3V0IG9mIHRoZWlyIHJhbmdlIG9mIGRlZmluaXRpb24uIEZvciBleGFtcGxlLCBzb2x1dGlvbiBtYXkgYmVjb21lIG5lZ2F0aXZlIGlmIHRoZSBkZXJpdmF0aXZlIGlzIG5lZ2F0aXZlLiBOb25saW5lYXIgcmhzIGZ1bmN0aW9ucyBtYXkgbm90IGJlIGFwcHJvcHJpYXRlbHkgZGVmaW5lZCBmb3IgbmVnYXRpdmUgc29sdXRpb25zLCB0YWtlICQxLygxK3gpJCwgd2hpY2ggaXMgYm91bmRlZCBmb3IgJHg+MCQgYnV0IHVuYm91bmRlZCBuZWFyICR4PS0xJC4KCiMgTm9uLXN0aWZmIGVxdWF0aW9ucwoKU3VidHJhdGUgUHJvZHVjZXIgQ29uc3VtZXIgbW9kZWwgKDNEKSB3aXRoIGEgbm9ubGluZWFyIGZ1bmN0aW9uIHBhc3NlZCBhcyBhcmd1bWVudCB0byB0aGUgbW9kZWwKCmBgYHtyfQojIGRlZmluZSB0aGUgT0RFIGVxdWF0aW9ucwpTUENtb2RlbCA8LSBmdW5jdGlvbih0LCB4LCBwYXJtcywgaW5wdXQpICB7CiAgd2l0aChhcy5saXN0KGMocGFybXMsIHgpKSwgewogICAgczAgPC0gaW5wdXQodCkgICAgICAgICAgICAgICAgICAgICAgIyBzdWJzdHJhdGUgcHJvZHVjdGlvbiBpcyB0aW1lLWRlcGVuZGVudAogICAgZFMgPC0gczAgLSBiKlMqUCArIGcqQyAgICAgICAgICAgICAgIyBzdWJzdHJhdGUKICAgIGRQIDwtIGMqUypQICAtIGQqQypQICAgICAgICAgICAgICAgICMgcHJvZHVjZXIKICAgIGRDIDwtIGUqUCpDICAtIGYqQyAgICAgICAgICAgICAgICAgICMgY29uc3VtZXIKICAgIHJlcyA8LSBjKGRTLCBkUCwgZEMpCiAgICBsaXN0KHJlcykKICB9KQp9CgojIHNldCB0aGUgcGFyYW1ldGVyIG5hbWVzIGFuZCB2YWx1ZXMKcGFycyA8LSBjKGIgPSAwLjAwMSwgYyA9IDAuMSwgZCA9IDAuMSwgZSA9IDAuMSwgZiA9IDAuMSwgZyA9IDAuMCkKCiMgc2V0IHRpbWUgcG9pbnRzCnRpbWVzIDwtIHNlcSgwLCAyMDAsIGJ5ID0gMS4wKQoKIyBkZWZpbmUgdGhlIHN1YnN0cmF0ZSBwcm9kdWN0aW9uIGZ1bmN0aW9uCnN1YnMgPC0gZGF0YS5mcmFtZSh0aW1lcyA9IHRpbWVzLAogICAgICAgICAgICAgICAgICAgICBwcm9kID0gcmVwKDAsIGxlbmd0aCh0aW1lcykpKQoKIyA9IDAuMiBiZXR3ZWVuIHQgPSAxMCBhbmQgdCA9IDExCnN1YnMkcHJvZFtzdWJzJHRpbWVzID49IDEwICYgc3VicyR0aW1lcyA8PSAxMV0gPC0gMC4yCgojIGZ1bmN0aW9uIGludGVycG9sYXRpbmcgdGhlIHZlY3RvciBzdWJzJHByb2QKc3Vic3Byb2QgPC0gYXBwcm94ZnVuKHN1YnMkdGltZXMsIHN1YnMkcHJvZCwgcnVsZSA9IDIpCgojIHNldCBpbml0aWFsIGNvbmRpdGlvbnMKaW5pdF9jb25kcyA8LSBjKFMgPSAxLCBQID0gMSwgQyA9IDEpCgojIHNvbHZlIHRoZSBPREUgc3lzdGVtCnNvbCA8LSBvZGUoeSA9IGluaXRfY29uZHMsIHRpbWVzID0gdGltZXMsIGZ1bmMgPSBTUENtb2RlbCwgcGFybXMgPSBwYXJzLCBpbnB1dCA9IHN1YnNwcm9kKQoKIyBwbG90IHNvbHV0aW9ucwpwbG90KHNvbCkKYGBgCgojIEVycm9yIGNvbnRyb2wKClRoZSBpbnRlZ3JhdG9ycyBgbHNvZGFgIGFuZCBvdGhlciByb3V0aW5lcyBvZiB0aGUgYGRlU29sdmVgIHBhY2thZ2UgaGF2ZSAqZXJyb3IgY29udHJvbCouIApUaGUgbnVtZXJpY2FsIG1ldGhvZHMgY29tcHV0ZSBhcHByb3hpbWF0ZSBzb2x1dGlvbiBhdCB0aGUgbmV4dCB0aW1lIHN0ZXAgYXQgdHdvIGRpZmZlcmVudCBvcmRlciBvZiBhY2N1cmFjeS4gVGhlIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgdHdvIHNvbHV0aW9ucyBpcyBhIGdvb2QgYXBwcm94aW1hdGlvbiBvZiB0aGUKc2l6ZSBvZiB0aGUgdHJ1ZSBlcnJvci4gVGhpcyBlcnJvciBpcyBsb2NhbCwgaS5lLiBpdCBpcyBjYWxjdWxhdGVkIGFzc3VtaW5nIHRoYXQgdGhlIApzb2x1dGlvbiBhdCB0aW1lICR0JCBpcyBleGFjdC4gRXJyb3IgaXMgY29udHJvbGVkIGJ5IHNldHRpbmcgKnRvbGVyYW5jZSogb3B0aW9uczsgaWYKdGhlIGVycm9yIGlzIGxhcmdlciB0aGFuIHRoZSB0b2xlcmFuY2UsIHRoZSBpbnRlZ3JhdG9yIHdpbGwgcmVqZWN0IHRoZSBuZXcgc29sdXRpb24gYW5kIHBpY2sgYSBzbWFsbGVyIHRpbWUgc3RlcC4gSWYgdGhlIGVycm9yIGlzIGxlc3MgdGhhbiB0aGUgdG9sZXJhbmNlLCB0aGUgaW50ZWdyYXRvciB3aWxsIGFjY2VwdAp0aGUgbmV3IHNvbHV0aW9uIGFuZCBpbmNyZWFzZSB0aGUgbmV4dCB0aW1lIHN0ZXAgdG8gc3BlZWQgdXAgdGhlIGNvbXB1dGF0aW9uLgoKVHdvIGVycm9ycyBhcmUgY29tcHV0ZWQsIHRoZSAqcmVsYXRpdmUgZXJyb3IqIGFuZCB0aGUgKmFic29sdXRlIGVycm9yKi4gSW4gYGxzb2RhYCB0aGUgc29sdXRpb24gaXMgYWNjZXB0ZWQgaWYgIAoKJCRlcnIgPSBcbWF4IHx5X3toaWdofSAtIHlfe2xvd318IDwgXG1hdGhybXtydG9sfSBcdGltZXMgfHl8ICsgXG1hdGhybXthdG9sfSQkClRoZSBvcHRpb24gYHJ0b2xgIGFuZCBgYXRvbGAgYXJlIHRoZSAqcmVsYXRpdmUgdG9sZXJhbmNlKiBhbmQgdGhlICphYnNvbHV0ZSB0b2xlcmFuY2UqIHJlc3BlY3RpdmVseS4gVGhlIHNtYWxsZXIgdGhlIHRvbGVyYW5jZSB0aGUgbW9yZSBzdHJpbmdlbnQgdGhlIGNvbmRpdGlvbiBmb3IgYWNjcGV0aW5nIHRoZSBzb2x1dGlvbi4gVGhlIHJlbGF0aXZlIHRvbGVyYW5jZSBjb250cm9sIHRoZSBwcmVjaXNpb24gb2YgdGhlIHNvbHV0aW9uIHdoZW4gZmFyIGF3YXkgZnJvbSB6ZXJvLiBBIHJlbGF0aXZlIHRvbGVyYW5jZSBvZiAxZS02IHNwZWNpZmllcyA2IGRpZ2l0cyBvZiBhY2N1cmFjeS4gVGhlIGFic29sdXRlIHRvbGVyYW5jZSAKc3BlY2lmaWVzIHRoZSBhY2N1cmFjeSB3aGVuIHNvbHV0aW9ucyBhcmUgY2xvc2UgdG8gemVyby4gQW4gYWJzb2x1dGUgdG9sZXJhbmNlIG9mIDFlLTYgc3RhdGVzIHRoYXQgYW55IHNvbHV0aW9uIHNtYWxsZXIgdGhhbiAxZS02IHNob3VsZCBiZSByZWdhcmRlZCBhcyBlZmZlY3RpdmVseSB6ZXJvLiAKZm9yIHN5c3RlbSBvZiBlcXVhdGlvbnMsIHRoZSBlcnJvciBpcyBzZXQgdG8gdGhlIG1heCBvZiB0aGUgZXJyb3JzIG9uIGVhY2ggY29lZmZpY2llbnRzLgoKKlJlbWFyayogVGhlIGVycm9yIGNvbnRyb2wgZXhwcmVzc2lvbiBpbnZvbHZlcyB0aGUgc3VtIG9mIHRoZSB0b2xlcmFuY2VzLiBUaGlzIGlzIGVxdWl2YWxlbnQgdG8gYW4gT1I6IGlmIHRoZSBlcnJvciBpcyBzbWFsbGVyIHRoYW4gZWl0aGVyIHRvbGVyYW5jZXMsIHRoZSBzb2x1dGlvbiB3aWxsIGJlIGFjY2VwdGVkLiBUaGVyZWZvcmUsIGl0IGlzIGFic29sdXRlbHkgcG9zc2libGUgdG8gc2V0IHJ0b2wgb3IgYXRvbCB0byB6ZXJvIChidXQgbm90IGJvdGgpLgoKSW4gc3VtbWFyeSwgcnRvbCBjb250cm9scyB0aGUgc29sdXRpb24gYXdheSBmcm9tIHplcm8gYW5kIGF0b2wgY29udHJvbHMgdGhlIHNvbHV0aW9uIGNsb3NlIHRvIHplcm8uCgojIE5vbi1uZWdhdGl2ZSBzb2x1dGlvbnMKCkl0IGNhbiBvZnRlbiBpbmNvbnZlbmllbnQgdG8gaGF2ZSBuZWdhdGl2ZSBhIHNvbHV0aW9uIHRvIGFuIGluaXRpYWwgdmFsdWUgcHJvYmxlbSB0byBPREVzIHRoYXQgdGhlb3JldGljYWxseSBzaG91bGQgaGF2ZSBvbmx5IHBvc2l0aXZlIHNvbHV0aW9uLiAKUHJvYmxlbXMgaW4gYmlvbG9neSBhbmQgY2hlbWlzdHJ5IGludm9sdmluZyBjb25jZW50cmF0aW9ucyBvciBwb3B1bGF0aW9uIGRlbnNpdGllcyBzaG91bGQgYWRtaXQgb25seSBwb3NpdGl2ZSBzb2x1dGlvbnMsIHRoZSBSSFMgb2YgdGhlIE9ERXMgYXJlIG9mdGVuIG5vdApkZWZpbmVkIG91dHNpZGUgdGhlIHJhbmdlIG9mIHBvc2l0aXZlIHN0YXRlcy4gVGhlIGluaXRpYWwgdmFsdWUgcHJvYmxlbSAoSVZQKSBmb3IgYSBzeXN0ZW0gb2YgT0RFIGlzCgokJFxmcmFje2R5fXtkdH0gPSBmKHksdCksIFw7IHkoMCkgPSB5XzAuJCQKRm9yIGV4YW1wbGUsIHRoZSBJVlAKCiQkXGZyYWN7ZHl9e2R0fSA9IC18eXwsIFw7IHkoMCkgPSAxLiQkClRoZSBzb2x1dGlvbiBpcyAkeSh0KSA9IFxleHAoLXQpJCBpcyBwb3NpdGl2ZSwgYW5kIGRlY2F5cyB0byB6ZXJvLiBTdXBwb3NlIHRoYXQgdGhlIG51bWVyaWNhbCBzb2x1dGlvbiByZWFjaGVzIGEgdmFsdWUgJHleKiA8IDAkIGF0IGEgdGltZSAkdF4qJC4gClRoZW4gdGhlIHNvbHV0aW9uLCBzdGFydGluZyBhdCAkdF4qJCwgaXMgJHUodCkgPSB5XipcZXhwKHQtdF4qKSQuIFRoaXMgc29sdXRpb24gaXMgZGVjcmVhc2luZyAodG93YXJkcyAkLVxpbmZ0eSQpLiBUaHVzIHRoZSBJVlAgaXMgKnVuc3RhYmxlKiwgaW4gdGhlIHNlbnNlIHRoYXQgc21hbGwgCnBlcnR1YmF0aW9uIG9mIHRoZSBzb2x1dGlvbiBsZWFkIHRvIGxhcmdlIGRldmlhdGlvbiBmcm9tIHRoZSB0cnVlIHNvbHV0aW9uLiBUaGlzIElWUCB3aWxsIGJlIHRoZSBmaXJzdCB0ZXN0IHByb2JsZW0sIHNvbHZlZCBvbiAkWzAsNDBdJAoKYGBge3J9CiMgZGVmaW5lIHRoZSBPREUgZXF1YXRpb25zCm5vblN0aWZmVGVzdDEgPC0gZnVuY3Rpb24odCwgeCwgcGFybXMpICB7CiAgd2l0aChhcy5saXN0KGMocGFybXMsIHgpKSwgewogICAgZHkgPC0gLSBhYnMoeSkKICAgIGxpc3QoZHkpCiAgfSkKfQoKIyBzZXQgdGltZSBwb2ludHMKdGltZXMgPC0gc2VxKDAsIDQwKQoKIyBzZXQgaW5pdGlhbCBjb25kaXRpb25zCnkwIDwtIGMoeSA9IDEpCgojIHNvbHZlIHRoZSBPREUgc3lzdGVtCnNvbCA8LSBvZGUoeSA9IHkwLCB0aW1lcyA9IHRpbWVzLCBwYXJtcyA9IE5VTEwsIGZ1bmMgPSBub25TdGlmZlRlc3QxKQoKIyBwbG90IHNvbHV0aW9ucwpwbG90KHNvbCkKYGBgCgpUaGUgc2Vjb25kIHRlc3QgaXMgdGhlIFJvYmVydHNvbiBwcm9ibGVtLiBJdCBpcyBhIHNlbWktc3RhYmxlIGNoZW1pY2FsIHJlYWN0aW9uIHN5c3RlbQoKJCQKXGZyYWN7ZHlfMX17ZHR9ICA9IC0wLjA0IHlfMSArIDEwXjQgeV8yIHlfMywgXFwKXGZyYWN7ZHlfMn17ZHR9ICA9ICAwLjA0ICB5XzEgLSAxMF40IHlfMiB5XzMgLSAzIFx0aW1lcyAxMF43IHlfMl4yLCBcXApcZnJhY3tkeV8zfXtkdH0gID0gIDMgXHRpbWVzIDEwXjcgeV8yXjIsCiQkCgp3aXRoIGluaXRpYWwgY29uZGl0aW9ucyAkKDEsMCwwKV50JCB3aXRoIHRpbWUgaW50ZXJ2YWwgJFswLDRcdGltZXMgMTBeezExfSQuIFRoaXMgaXMgYSAqc3RpZmYqIHByb2JsZW0gdGhhdCBuZWVkIHRvIGJlIHNvbHZlZCBvdmVyIGEgdmVyeSBsYXJnZSB0aW1lIGludGVydmFsLgoKYGBge3J9ClJvYmVydHNvbiA8LSBmdW5jdGlvbih0LCBzdGF0ZSwgcGFyYW1ldGVycykgewogIHdpdGgoYXMubGlzdChjKHN0YXRlLCBwYXJhbWV0ZXJzKSksIHsKICAgIGR5MSA8LSAgLWEqeTEgKyBiKnkyKnkzCiAgICBkeTIgPC0gICBhKnkxIC0gYip5Mip5MyAtIGMqeTIqeTIKICAgIGR5MyA8LSAgIGMqeTIqeTIKICAgIGxpc3QoYyhkeTEsIGR5MiwgZHkzKSkKICB9KQp9CgojIHNldCB0aGUgcGFyYW1ldGVyIG5hbWVzIGFuZCB2YWx1ZXMKcGFycyA8LSBjKGEgPSAwLjA0LCBiID0gMWU0LCBjID0gM2U3KQoKIyBzZXQgdGltZSBwb2ludHMKdGltZXMgPC0gc2VxKDAsIDRlMTEsIGxlbmd0aC5vdXQgPSA1MCkKCiMgc2V0IGluaXRpYWwgY29uZGl0aW9ucwp5MCA8LSBjKHkxID0gMSwgeTIgPSAwLCB5MyA9IDApCgojIHNvbHZlIHRoZSBPREUgc3lzdGVtCnNvbCA8LSBvZGUoeSA9IHkwLCB0aW1lcyA9IHRpbWVzLCBwYXJtcyA9IHBhcnMsIGZ1bmMgPSBSb2JlcnRzb24sIHJ0b2wgPSAxZS02LCBhdG9sID0gMWUtNikKYGBgCgpgYGB7cn0KIyBwbG90IHNvbHV0aW9ucwpwbG90KHNvbCwgd2hpY2ggPSAneTEnKQpgYGAKClRoZSBMb3RrYS1Wb2x0ZXJyYSBtb2RlbCBmb3IgcHJlZGF0b3ItcHJleSBkeW5hbWljcyBhZG1pdHMgb3NjaWxsYXRvcnkgc29sdXRpb25zIAp0aGF0IHBlcmlvZGljYWxseSBjb21lIGFyYml0cmFyaWx5IGNsb3NlIHRvIHplcm8uIFRoZSBJVlAgaXMgCgokJApcZnJhY3tkeV8xfXtkdH0gID0gIDAuNSB5XzEgXEJpZ2woIDEgLSBcZnJhY3t5XzF9ezIwfSBcQmlncikgLSAwLjEgeV8xIHlfMiwgXFwKXGZyYWN7ZHlfMn17ZHR9ICA9ICAwLjAxICB5XzEgeV8yIC0gMC4wMDEgeV8yLAokJAp3aXRoIGluaXRpYWwgY29uZGl0aW9ucyAkKDI1LDUpXnQkIG92ZXIgdGhlIHRpbWUgaW50ZXJ2YWwgJFswLDg3MF0kLiBJZiBhdCBzb21lIHRpbWUgJHReKiQgdGhlIG51bWVyaWNhbCBzb2x1dGlvbiAgJHlfMV4qIDwgMCQsIGFuZCB0aGUgc29sdXRpb24gaXMgdGhlbiByZXNldCBhdCAkKDAseV8yXiopXnQkLCB0aGUKc29sdXRpb24gaGFzICR5XzEodCkgPSAwJCBmb3IgYWxsICR0ID4gdF4qJC4KCmBgYHtyfQpMb3RrYVZvbHRlcnJhIDwtIGZ1bmN0aW9uKHQsIHN0YXRlLCBwYXJhbWV0ZXJzKSB7CiAgd2l0aChhcy5saXN0KGMoc3RhdGUsIHBhcmFtZXRlcnMpKSwgewogICAgZHkxIDwtICBhICogeTEgKiAoIDEgLSB5MS9iICkgLSBjICogeTEgKiB5MgogICAgZHkyIDwtICBkICogeTEqeTIgLSBlICogeTIKICAgIGxpc3QoYyhkeTEsIGR5MikpCiAgfSkKfQoKIyBzZXQgdGhlIHBhcmFtZXRlciBuYW1lcyBhbmQgdmFsdWVzCnBhcnMgPC0gYyhhID0gMC41LCBiID0gMjAsIGMgPSAwLjEsIGQgPSAwLjAxLCBlID0gMC4wMDEpCgojIHNldCB0aW1lIHBvaW50cwp0aW1lcyA8LSBzZXEoMCwxMDAwLGxlbmd0aC5vdXQgPSAyKQoKIyBzZXQgaW5pdGlhbCBjb25kaXRpb25zCnkwIDwtIGMoeTEgPSAyNSwgeTIgPSA1KQoKIyBzb2x2ZSB0aGUgT0RFIHN5c3RlbQpzb2wxIDwtIG9kZSh5ID0geTAsIHRpbWVzID0gYygwLDEwMDApLCBwYXJtcyA9IHBhcnMsIGZ1bmMgPSBMb3RrYVZvbHRlcnJhLCBhdG9sID0gMWUtMTIpCnNvbDIgPC0gb2RlKHkgPSB5MCwgdGltZXMgPSBzZXEoMCwxMDAwLGxlbmd0aC5vdXQgPSAxMDAwKSwgcGFybXMgPSBwYXJzLCBmdW5jID0gTG90a2FWb2x0ZXJyYSwgYXRvbCA9IDFlLTEyKQpgYGAKCmBgYHtyfQojIHBsb3Qgc29sdXRpb25zCnBsb3Qoc29sMVssMV0sc29sMVssJ3kxJ10pCmxpbmVzKHNvbDJbLDFdLHNvbDJbLCd5MSddKQpgYGAKClRoZSBJVlAKCiQkXGZyYWN7ZHl9e2R0fSA9IFxzcXJ0ezEteV4yfSwgXDsgeSgwKSA9IDAuJCQKVGhlIHNvbHV0aW9uICR5KHQpID0gXHNpbih0KSQgaW5jcmVhc2VzIHRvIDEgYXQgJHQgPSBccGkgLzIkLCBhbmQgdGhlIHJocyBpcyBub3QgZGVmaW5lZApmb3IgJHk+MSQgKGl0IGlzIG5vdCBMaXBzY2hpdHopLiBUaGUgc29sdXRpb24gaXQgbm90IHVuaXF1ZSBhZnRlciAkdF4qID0gXHBpLzIkLiAKCmBgYHtyfQojIGRlZmluZSB0aGUgT0RFIGVxdWF0aW9ucwpCYWxsIDwtIGZ1bmN0aW9uKHQsIHgsIHBhcm1zKSAgewogIHdpdGgoYXMubGlzdChjKHBhcm1zLCB4KSksIHsKICAgIGR5IDwtIHNxcnQoMS15KnkpCiAgICBsaXN0KGR5KQogIH0pCn0KCiMgc2V0IHRpbWUgcG9pbnRzCnRpbWVzIDwtIHNlcSgwLCAzLCBsZW5ndGgub3V0ID0gMTAwKQoKIyBzZXQgaW5pdGlhbCBjb25kaXRpb25zCnkwIDwtIGMoeSA9IDApCgojIHNvbHZlIHRoZSBPREUgc3lzdGVtCnNvbCA8LSBvZGUoeSA9IHkwLCB0aW1lcyA9IHRpbWVzLCBwYXJtcyA9IE5VTEwsIGZ1bmMgPSBCYWxsLCBtZXRob2QgPSAnYmRmJykKCiMgcGxvdCBzb2x1dGlvbnMKcGxvdChzb2wpCmBgYAoKCiMgRXhhbXBsZSBvZiBhIFJ1bmdlLUt1dHRhIHBhaXIgb2Ygb3JkZXIgMiBhbmQgMzogQm9nYWNraS1TaGFtcGluZSBSSzMoMikKClRoZSBudW1lcmljYWwgc2NoZW1lIGlzIGEgcGFpciBvZiBSdW5nZS1LdXR0YSBmb3JtdWxhcywgb25lIG9mIG9yZGVyIDMgYW5kIG9uZSBvZiBvcmRlciAyLiBGb3IgdGhlIGRpZmZlcmVudGlhbAplcXVhdGlvbgoKJCRcZnJhY3tkeSh0KX17ZHR9ID0gZih0LHkodCkpLCBcOyBhIFxsZXEgdCBcbGVxIGIsJCQKJCR5KGEpID0geV9hLiQkCgpUaGUgdHdvIGZvcm11bGFzIGFyZSB1c2VkIHRvIGFkdmFuY2UgdGhlIHNvbHV0aW9uIGJ5IGEgdGltZSBzdGVwICRoJCwgCmdpdmVuIGEgc29sdXRpb24gJHlfbiQgYXQgdGltZSBzdGVwICR0X24kLiBUaGUgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSB0aGlyZCBvcmRlciAkXGhhdCB5X3tuKzF9JCBhbmQgdGhlIHNlY29uZCBvcmRlciBzdGVwICR5X3tuKzF9JCBwcm92aWRlcyBhbiBlc3RpbWF0ZSBvZiB0aGUgZXJyb3IgJEUkIHRvIHRoZSB0cnVlIHNvbHV0aW9uLiAKRWFjaCBmb3JtdWxhIHJlcXVpcmVzIHNldmVyYWwgZXZhbHVhdGlvbnMgb2YgdGhlIGZ1bmN0aW9uICRmJC4gRXZhbHVhdGlvbiBpcyBkb25lIGluICRTJCBzdGFnZXM6CgokJHlfe24rMX0gPSBcaGF0IHlfe259ICsgaCBcc3VtX3tpPTF9XlMgYl9pIGtfaS4kJAoKU3RhZ2VzICRrX2kkIGFyZSBjYWxjdWxhdGVkIGl0ZXJhdGl2ZWx5OiAka19pJCBkZXBlbmRzIG9ubHkgb24gdGhlIHByZXZpb3VzICRrX2okLCAkaj0xLC4uLixpLTEkLiBUaGUgZmlyc3Qgc3RhZ2UgaXMgYWx3YXlzCgokJGtfMSA9IGYodF9uLCB5X24pLiQkCgpUaGUgb3RoZXIgc3RhZ2VzIGFyZQoKJCRrX2kgPSBmIFxiaWdsKCB4X24gKyBjX2kgaCwgeV9uICsgaCBcc3VtX3tqPTF9XntpLTF9IGFfe2ksan0ga19qIFxiaWdyKSwkJAphbmQKCiQkY19pID0gXHN1bV97aj0xfV57aS0xfSBhX3tpLGp9JCQKClRvIHJlZHVjZSB0aGUgdG90YWwgbnVtYmVyIG9mIGZ1bmN0aW9uIGV2YWx1YXRpb25zLCBhIHN0cmF0ZWd5IGNvbnNpc3RzIGluIHNoYXJpbmcgdGhlIHN0YWdlcyAka19pJCBiZXR3ZWVuIHRoZSB0d28gZm9ybXVsYXMsIHRoaXMgaXMgY2FsbGVkIGVtYmVkZGluZy4gVGhpcmQgb3JkZXIgUnVuZ2UtS3V0dGEgZm9ybXVsYXMgbmVlZCBhdCBsZWFzdCB0aHJlZSBzdGFnZXMsIGFuZCBzZWNvbmQgb3JkZXIgZm9ybXVsYXMgYXQgbGVhc3QgdHdvIHN0YWdlcy4gRWFjaCBzdGFnZSByZXF1aXJlIG9uZSBldmFsdXRhdGlvbiBvZiB0aGUgZnVuY3Rpb24gJGYkLiBUaGUgZmlyc3Qgc3RlcCAka18xJCBpcyBhbHdheXMgc2hhcmVkLiBJZiB0aGUgc2Vjb25kIHN0YWdlIG9mIHRoZSB0aGlyZCBvcmRlciBmb3JtdWxhIGlzIGFsc28gdXNlZCBpbiB0aGUgc2Vjb25kIG9yZGVyIGZvcm11bGEsIHRoZSB0b3RhbCBudW1iZXIgb2YgZnVuY3Rpb24gZXZhbHVhdGlvbnMgaXMgMzogd2UgZ2V0IHRoZSBzZWNvbmQgb3JkZXIgYXBwcm94aW1hdGlvbiBhbG1vc3QgZm9yIGZyZWUuIAoKSG93ZXZlciwgQm9nYWNraSBhbmQgU2hhbXBpbmUgcmVhc29uIGluIGEgZGlmZmVyZW50IHdheS4gVGhleSB3YW50IHRvIG1hdGNoIGFzIGNsb3NlbHkgYXMgcG9zc2libGUgdGhlIHJlZ2lvbnMgb2Ygc3RhYmlsaXR5IG9mIHRoZSB0d28gZm9ybXVsYXMuIEFsbCB0d28tc3RhZ2UsIHNlY29uZCBvcmRlciBmb3JtdWxhcyBoYXZlIHRoZSBzYW1lIHJlZ2lvbiBvZiBzdGFiaWxpdHkgYW5kIGhhdmUgYWxsIHRocmVlLXN0YWdlcywgdGhpcmQgb3JkZXIgZm9ybXVsYXMuIFRoZSBvbmx5IHdheSB0byBtYXRjaCB0aGUgcmVnaW9ucyBvZiBzdGFiaWxpdHkgaXMgdG8gaW5jcmVhc2UgdGhlIG51bWJlciBvZiBzdGFnZXMuIEluY3JlYXNpbmcgdGhlIG51bWJlciBvZiBzdGFnZXMgbGVhdmVzIHF1aXRlIGEgbG90IG9mIHJvb20gZm9yIGNob29zaW5nIHRoZSBjb2VmZmljaWVudCwgYW5kIEJvZ2Fja2kgYW5kIFNoYW1waW5lIHRvb2sgYSBmb3VyIHN0YWdlcyBmb3IgdGhlIHNlY29uZCBvcmRlciBmb3JtdWxhLiBUaGlzIHNlZW1zIHJhdGhlciBzdXBlcmZsdW91cywgYnV0IHRoZXkgYWxzbyByZXVzZSB0aGUgZmlyc3QgdGhyZWUgc3RhZ2VzIGluIHRoZSBzZWNvbmQtb3JkZXIgZm9ybXVsYS4gVGhlIGZvdXJ0aCBzdGFnZSBvZiB0aGUgc2Vjb25kIG9yZGVyIGZvcm11bGEgaXMgCgokJGtfNCA9IGYodF9uICsgaCwgXGhhdCB5X24gKyBoIFxzdW1fe2o9MX1eMyBcaGF0IGJfaiBrX2opLiQkCk5vdGljZSB0aGF0ICRrXzQkIGlzIGV4Y2F0bHkgdGhlIHZhbHVlIG9mIHRoZSBmdW5jdGlvbiAkZiQgYXQgJHRfe24rMX0gPSB0X24gKyBoJCBhbmQgJFxoYXQgeV97bisxfSA9IFxoYXQgeV9uICsgaCBcc3VtX3tqPTF9XjMgXGhhdCBiX2oga19qJC4gVGhpcyBpcyB0aGUgZmlyc3Qgc3RhZ2UgJGtfMSQgb2YgdGhlIG5leHQgdGltZSBzdGVwISBPbmNlIHdlIHJlYWxpemUgdGhhdCBtb3N0IHN0ZXBzIGFyZSBzdWNjZXNzZnVsLCB3ZSBzZWUgdGhhdCB0aGUgZm91ci1zdGFnZSwgc2Vjb25kIG9yZGVyIGZvcm11bGEgY29tZSBhdCBsaXR0bGUgZXh0cmEgY29tcHV0YXRpb25hbCBjb3N0OiAka180JCBpcyBjYXJyaWVkIG92ZXIgdG8gdGhlIG5leHQgdGltZSBzdGVwLiBUaGlzIGFwcHJvYWNoIGlzIGNhbGwgRlNBTDogRmlyc3QgU2FtZSBBcyBMYXN0LgoKVGhlIEJ1dGNoZXIgdGFibGVhdSBmb3IgdGhlIHBhaXIgb2YgZm9ybXVsYSBpcwoKICAgIDAgICB8IAogICAgMS8yIHwgMS8yCiAgICAzLzQgfCAgIDAgICAzLzQKICAgICAgMSB8IDIvOSAgIDEvMyA0LzkKICAgIC0tLSAtIC0tLS0gIC0tLSAtLS0gLS0tCiAgICAgICAgfCAyLzkgICAxLzMgNC85ICAgMAogICAgICAgIHwgNy8yNCAgMS80IDEvMyAxLzggICAgIAoKCiAjIEV2ZW50IGxvY2F0aW9uCiAKIEV2ZW50IGxvY2F0aW9uIGlzIGFuIG9wdGlvbiB0byB0cmFjayB0aGUgc29sdXRpb24gb2YgYSBzeXN0ZW0gb2YgT0RFIHdoaWxlIGl0IGlzIGJlaW5nCiBzb2x2ZWQgZm9yLiBUaGlzIHVzZWZ1bCwgYnV0IG5vdCBsaW1pdGVkIHRvIGNhc2VzIHdoZW4gdGhlIGR5bmFtaWMgdmFyaWFibGUgYXJlCiBzdWRkZW5seSBjaGFuZ2VkLCBpLmUuIHdoZW4gdGhlIGR5bmFtaWNhbCB2YXJpYWJsZXMgYXJlIGRpc2NvbnRpbnVvdXMuCiBOb3JtYWwgaW50ZWdyYXRpb24gcm91dGluZXMgY2Fubm90IGRlYWwgdmVyeSB3ZWxsIHdpdGggZGlzY29udGludWl0aWVzLiBUaGUgYGV2ZW50c2Agb3B0aW9uIHNwZWNpZmllcyB3aGVuIHRoZSBldmVudHMgb3IgZGlzY29udGl1aXRpZXMgc2hvdWxkIG9jY3VyLCBzbyB0aGF0IHRoZSBpbnRlZ3JhdG9yIGNhbiBkZWFsIHdpdGggaXQuIEV2ZW50cyBhcmUgaW1wb3NlZCBlaXRoZXIgYnkgYSBgZGF0YS5mcmFtZWAgdGhhdCBzcGVjaWZpZXMgdGhlIHRpbWVzIGF0IHdoaWNoIHRoZSB2YXJpYWJsZXMgaGF2ZSBqdW1wcywgb3IgYnkgYW4gYGV2ZW50IGZ1bmN0aW9uYCB0aGF0IG1vbml0b3IgdGhlIHN0YXRlIG9mIHRoZSB2YXJpYWJsZS4gQSBgcm9vdCBmdW5jdGlvbmAgd2lsbCB0cmlnZ2VyIGFuIGV2ZW50IHdoZW4gdGhlIGZ1bmN0aW9uIHRha2VzIHRoZSB2YWx1ZSB6ZXJvLgogClRoZSBldmVudCBmdW5jdGlvbiBoYXMgdGhlIHNhbWUgc3ludGF4IGFzIHRoZSBvZGUgZnVuY2lvbjogYGZ1bmN0aW9uKHQseSxwYXJhbXMsIC4uLilgLgpUaGUgYGRhdGEuZnJhbWVgIHNob3VsZCBoYXZlIHRoZSBmb2xvd2luZyBjb2x1bW5zLCBpbiB0aGF0IG9yZGVyOiBgdmFyYCB0aGUgc3RhdGUgdmFyaWFibGUKbmFtZSBvciBudW1iZXIgYWZmZWN0ZWQgYnkgdGhlIGV2ZW50LCBgdGltZWAgdGhlIHRpbWUgYXQgd2hpY2ggdGhlIGV2ZW50IHRha2VzIHBsYWNlLApgdmFsdWVgIHRoZSBtYWduaXR1ZGUgb2YgdGhlIGV2ZW50LCBgbWV0aG9kYCBob3cgdG8gc2V0IHRoZSBuZXcgdmFsdWVzLCBvbmUgb2YgInJlcGxhY2UiLCAiYWRkIiwgIm11bHRpcGx5Ii4KClRoZSByb3c6IAoKICAgICJ2MSIgMTAgMiAiYWRkIgogICAgCndvdWxkICoqYWRkKiogMiB0byB0aGUgdmFyaWFibGUgYHYxYCBhdCB0aW1lIDEwLgoKVGhlIHJvdXRpbmVzIGBsc29kYWAgKGFuZCBzb21lIG90aGVycykgaGF2ZSByb290LWZpbmRpbmcgYWJpbGl0aWVzLiBJZiBhIHJvb3QgZnVuY3Rpb24gaXMgc3BlY2lmaWVkLCB0aGUgc29sdmVyIHdpbGwgc3RvcCBhdCB0aGUgZmlyc3Qgcm9vdC4gVG8gbW9uaXRvciB0aGUgbG9jYXRpb24gb2YgbWFueSBldmVudHMsIGFuIGV2ZW50IGZ1bmN0aW9uIG11c3QgYmUgc2V0IHRoYXQgd2lsbCBsZWF2ZSB0aGUgc3RhdGUgdmFyaWFibGVzIHVuYWx0ZXJlZC4KCiMjIEV4YW1wbGUgMSBFdmVudCBpbiBhIGRhdGEuZnJhbWUKCmBgYHtyfQojIE9ERSBmdW5jdGlvbgpteU9kZWZ1bmMgPC0gZnVuY3Rpb24odCwgdmFyLCBwYXJzKSAKewogIHdpdGgoYXMubGlzdChjKHBhcnMsIHZhcikpLCB7CiAgICBkeCA8LSAwCiAgICBkeSA8LSAtIGEgKiB5CiAgICBsaXN0KGMoZHgsZHkpKQogIH0pCn0KCnkwIDwtIGMoeCA9IDAsIHkgPSAxKSAjIGluaXRpYWwgY29uZGl0aW9uICh4LHkgbXVzdCBiZSB0aGUgc2FtZSB4LHkgYXMgaW5zaWRlIG15T2RlRnVuYykKcGFycyA8LSBjKGEgPSAxLjIpICMgcGFyYW1ldGVycyAoYSBtdXN0IGJlIHRoZSBzYW1lIGEgYXMgaW5pc2RlIG15T2RlRnVuYykKdGltZXMgPC0gc2VxKDAsMTAsYnk9MC4xKQoKIyBkZWZpbmUgYSBkYXRhLmZyYW1lIGNhbGxlZCBldmVudERhdGFGcmFtZQpldmVudERhdGFGcmFtZSA8LSBkYXRhLmZyYW1lKHZhciA9IGMoIngiLCAieSIsICJ5IiwgIngiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aW1lID0gYygxLDEsNSw5KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZSA9IGMoMSwyLDMsNCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWV0aG9kID0gYygiYWRkIiwgIm11bHQiLCAicmVwIiwgImFkZCIpKQoKc29sIDwtIG9kZSh5ID0geTAsIGZ1bmMgPSBteU9kZWZ1bmMsIHRpbWVzID0gdGltZXMsIHBhcm1zID0gcGFycywgCiAgICAgICAgICAgZXZlbnQgPSBsaXN0KGRhdGEgPSBldmVudERhdGFGcmFtZSkpCgpwbG90KHNvbCkKYGBgCiAKCiMjIEV4YW1wbGUgMiBFdmVudCBpbiBhIGZ1bmN0aW9uCgpgYGB7cn0KbXlPZGVmdW5jIDwtIGZ1bmN0aW9uKHQsIHZhciwgcGFycykgCnsKICB3aXRoKGFzLmxpc3QoYyhwYXJzLCB2YXIpKSwgewogICAgZHggPC0gMAogICAgZHkgPC0gLSBhICogeQogICAgbGlzdChjKGR4LGR5KSkKICB9KQp9CgoKCiMgZXZlbnRzOiBhZGQgMSB0byB4LCBtdWx0aXBseSB5IHdpdGggYSByYW5kb20gbnVtYmVyCmV2ZW50RnVuIDwtIGZ1bmN0aW9uKHQsIHZhciwgcGFybXMpewogIHdpdGggKGFzLmxpc3QodmFyKSx7CiAgICB4IDwtIHggKyAxCiAgICB5IDwtIDUgKiBydW5pZigxKQogICAgcmV0dXJuKGMoeCwgeSkpCiAgfSkKfQoKeTAgPC0gYyh4ID0gMSwgeSA9IDIpCnRpbWVzIDwtIHNlcSgwLCAxMCwgYnkgPSAwLjEpCnBhcnMgPC0gYyhhID0gMS4yKQoKc29sIDwtIG9kZShmdW5jID0gbXlPZGVmdW5jLCB5ID0geTAsIHRpbWVzID0gdGltZXMsIHBhcm1zID0gcGFycywKICAgICAgICAgICBldmVudHMgPSBsaXN0KGZ1bmMgPSBldmVudEZ1biwgdGltZSA9IGMoMTo5LCAyLjIsIDIuNCkpICkKcGxvdChzb2wsIHR5cGUgPSAibCIpCmBgYAoKIyBFdmVudCB0cmlnZ2VyZWQgYnkgYSByb290IGZ1bmN0aW9uCgpgYGB7cn0KIyMgT0RFOiBzaW1wbGUgZmlyc3Qtb3JkZXIgZGVjYXkKZmlyc3RPcmRlckRlY2F5IDwtIGZ1bmN0aW9uKHQsIHZhciwgcGFycykgewogIHdpdGgoYXMubGlzdChjKHBhcnMsIHZhcikpLCB7CiAgICBkeSA8LSAtIGEgKiB5CiAgICBsaXN0KGMoZHkpKQogIH0pCn0KCiMjIGV2ZW50IHRyaWdnZXJlZCBpZiBzdGF0ZSB2YXJpYWJsZSB5ID0gMC41CnJvb3RGdW4gPC0gZnVuY3Rpb24gKHQsIHZhciwgcGFycykgewogIHdpdGgoYXMubGlzdChjKHBhcnMsIHZhcikpLCB7CiAgICB5IC0gMC41CiAgfSkKfQoKIyMgc2V0cyBzdGF0ZSB2YXJpYWJsZSA9IDEKZXZlbnRGdW4gPC0gZnVuY3Rpb24odCwgeSwgcGFycykgewogICAgd2l0aCAoYXMubGlzdCh2YXIpLHsKICAgIHkgPC0gMQogICAgcmV0dXJuKHkpCiAgfSkKfQoKeTAgPC0gYyh5ID0gMikKdGltZXMgPC0gc2VxKDAsIDEwMCwgMC4xKQpwYXJzIDwtIGMoYSA9IDAuMSkKCiMjIHVzZXMgb2RlIHRvIHNvbHZlOyByb290ID0gVFJVRSBzcGVjaWZpZXMgdGhhdCB0aGUgZXZlbnQgaXMKIyMgdHJpZ2dlcmVkIGJ5IGEgcm9vdC4Kc29sIDwtIG9kZSh0aW1lcyA9IHRpbWVzLCB5ID0geTAsIGZ1bmMgPSBmaXJzdE9yZGVyRGVjYXksIHBhcm1zID0gcGFycywKICAgICAgICAgICBldmVudHMgPSBsaXN0KGZ1bmMgPSBldmVudEZ1biwgcm9vdCA9IFRSVUUpLAogICAgICAgICAgIHJvb3RmdW4gPSByb290RnVuKQoKcGxvdChzb2wsIHR5cGUgPSAibCIpCgojIyB0aW1lIG9mIHRoZSByb290Ogp0aW1lc19yb290IDwtIGF0dHJpYnV0ZXMoc29sKSR0cm9vdApwb2ludHModGltZXNfcm9vdCwgcmVwKDAuNSwgbGVuZ3RoKHRpbWVzX3Jvb3QpKSkKYGBgCg==