This notebook is part of the material presented in R/Finance 2017. Please, see the README file.

\[ \newcommand{\mat}[1]{\mathbf{#1}} \newcommand{\EE}[1]{\mathbb{E}\left[ #1 \right]} \newcommand{\VV}[1]{\mathbb{V}\left[ #1 \right]} \newcommand{\RR}{\mathbb{r}} \newcommand{\II}{\mathbb{I}} \newcommand{\NN}{\mathbb{N}} \newcommand{\bp}{\mathbf{p}} \newcommand{\bT}{\mathbf{T}} \newcommand{\btheta}{\mathbf{\theta}} \]

What’s all this about?

The aim of this notebook is twofold. First, I’d like to draw your attention to a small fact observed in financial assets prices when filtered through a Markov Switching GARCH model: when log returns are filtered through a GARCH model with Markovian dynamics, the belief states (low/high volatility) are correlated across assets. It’s not a game changer but hopefully it will trigger some new ideas to improve your trading strategy or risk model. Second, I’ll use this small fact as an excuse to introduce you to a few small concepts that certainly will be of help to any financial analyst.

You’ll be exposed to the following concepts:

  1. Mixture Normal and Markov Switching GARCH model.
  2. Hidden Markov Model and the forward algorithm.
  3. Bayesian statistics and Stan, a probabilistic programming language for statistical inference.
  4. Neat plots.

Worried by the broad scope? I’ll only explain the basics and leave many, many references. Hopefully, this will be enough exposure for you to decide if the topic is worth investing more effort.

Mixture of Normals Conditional Heteroskedasticity

Conditional Heteroskedasticity

Also known as volatility clustering, conditional heteroskedasticity is a key feature of economic time series, in particular of returns of financial assets. Relatively volatile periods, characterized by large price changes and large returns, alternate with more calm periods with stable prices and small returns (Franses, Dijk, and Opschoor 2014, 26).

Let \(P_t\) be the price of an asset at time \(t\) and \(r_t = log(P_t) - log(P_{t-1})\) be the log return. The expected return \(m_t\) is estimated by any model for the mean that leaves an unexplained component \(\epsilon_t\) called stochastic error or random shock:

\[ r_t = m_t + \epsilon_t. \] As will be seen later, the shock is related to the variance of the returns and may be modelled deterministically or stochastically. In the first case, the error is assumed to have the form \(\epsilon_t = v_t \sqrt{h_t}\), where \(v_t\) is a standardized random variable, i.e. independent and identically distributed with zero mean and unit variance. Note we’ve not assumed a Gaussian shape. Franses, Dijk, and Opschoor (2014) pp. 170 shows that the shocks have a constant unconditional variance equal to \(\sigma^2\) and a distribution conditional on past information \(\II_{t-1}\) with mean zero and variance \(h_t\). That is,

\[ \EE{\epsilon_t} = 0, \quad \VV{\epsilon_t} = \sigma^2, \quad \EE{\epsilon_t | \II_{t-1}} = 0, \quad \VV{\epsilon_t | \II_{t-1}} = h_t. \] Building upon Autoregressive Conditional Heteroskedasticity (ARCH), Bollerslev (1986) proposed the Generalized Autoregressive Conditional Heteroskedasticity (GARCH). The conditional variance is a deterministic function of its past values and past squared shocks:

\[ (1) \quad \quad h_t = \alpha_0 + \sum_{i=1}^{q}{\alpha_i \ \epsilon^2_{t-1}} + \sum_{j=1}^{p}{\beta_i \ h_{t-j}},\] with \(\alpha_0 > 0\), \(\alpha_i \ge 0\), \(\beta_j \ge 0\) and \(\sum_{i=1}^{max(m, s)}{(\alpha_i + \beta_j)} < 1\) (\(\alpha_i = 0 \ \forall \ i > m\) and \(\beta_j = 0 \ \forall \ j > s\)).

What does all this mean? Simply, that the volatility of returns - measured as the conditional second moment of the series - varies deterministically with time. Changes in conditional volatility are led by past volatility and shocks. The larger the last \(q\) shocks or the observed volatility in the last \(p\) periods, the more uncertain we are about the next return. It’s more uncertain to place a bet on today’s close price if the stock just moved far from its expected value. A fairly simple model indeed, but it makes sense.

By the way, the GARCH family is HUGE. There’s a vast literature originated in the academy during the 90’s and fueled by its extensive use in the industry in the 00’s. Many variations allow for more complex patterns like non-linearity, asymmetry and fatter tails: Integrated GARCH, GARCH in mean, Exponential GARCH, Threshold GARCH, GJR GARCH, Asymmetric Power GARCH, student t and Generalized Error Distribution, among many others. See Franses, Dijk, and Opschoor (2014) pp. 176 and Ghalanos (2015), Vignettes.

Mixture of Normals

A random variable \(\epsilon\) is said to have a univariate finite normal mixture distribution if the unconditional density is given by

\[ MN(\epsilon) = \sum_{j=1}^{K}{\lambda_j \ N(\epsilon | \mu_j, \ \sigma^2_j)}, \] where \(K \in \NN\) is the number of components, \(N(\mu, \ \sigma^2)\) is the Gaussian density with mean \(\mu\) and variance \(\sigma^2\), and \(\lambda_j\) are the mixing weights with \(\lambda_j > 0 \ \forall \ j\) and \(\sum_{j=1}^{k}{\lambda_j} = 1\) (Haas, Mittnik, and Paolella 2004).

A mixture of distribution is an old statistical trick to accomodate skewness and excess kurtosis. It has an extra feature in economics: the components are usually subject to simple yet useful interpretations. The variable of interest has a different mean and variance depending on which state the process is. In our model, states may represent recession/expansion, bearish/bullish, low/high volatility, risk off/on, and so on. Of course, the choice isn’t necessarily binary. Keep reading to know more!

Mixture of Normals + Conditional Heteroskedasticity

If the time series \(\{\epsilon_t\}\) is generated by a \(K\)-componentMixture of Normals \(GARCH(p, q)\) process, then the conditional density of the shock is given by \[ f(\epsilon_t | \II_{t-1}) = MN(\lambda_1, \dots, \lambda_K, h_{1t}, h_{Kt}),\] where \(\II_{t-1}\) is the information set at time \(t-1\), \(\lambda_i \in (0, 1) \ i = 1, \dots, K\) and \(\sum_{i=1}^{K}{\lambda_i} = 1\). In the simplest case (diagonal symmetric), each possible \(k = 1, \dots, K\) state has its own conditional volatility governed by its own GARCH deterministic dynamics and its own state-dependent parameters:

\[ (2) \quad \quad h_{kt} = \alpha_{k0} + \sum_{i=1}^{q}{\alpha_{ki} \ \epsilon^2_{t-1}} + \sum_{j=1}^{p}{\beta_{kj} \ h_{k, \ t-j}}. \]

This is interesting now. We only observe one series of log returns which follows only one path of conditional volatility. Nonetheless, volatility at any given time \(t\) comes from one of the \(K\) different states or regimes, each one with its own level and dynamics. Regime switching allows for non-linearity in the model and allow our estimates to quickly adjust to changes in the market.

Hidden Markov Model + Conditional Heteroskedasticity

Hidden Markov Model (HMM) involves two interconnected models. The state model consists of a discrete-time, discrete-state Markov chain with hidden states \(z_t \in \{1, \dots, K\}\) that transition according to \(p(z_t | z_{t-1})\). Additionally, the observation model is governed by \(p(\mat{y}_t | z_t)\), where \(\mat{y}_t\) are the observations, emissions or output. In our case, the latter is represented by the GARCH equation.

It is a specific instance of the state space model family in which the latent variables are discrete. Each single time slice corresponds to a mixture distribution with component densities given by \(p(\mat{y}_t | z_t)\), thus HMM may be interpreted as an extension of a mixture model in which the choice of component for each observation is not selected independently but depends on the choice of component for the previous observation. In the case of a simple mixture model for an identically independently distributed sample, the parameters of the transition matrix inside the \(i\)-th column are the same, so that the conditional distribution \(p(z_t | z_{t-1})\) is independent of \(z_{t-1}\).

In other words, HMM are equivalent to a Gaussian mixture model with cluster membership ruled by Markovian dynamics, also known as Markov Switching Models (MSM). Multiple sequential observations tend to share the same location until they suddenly jump into a new cluster.

Bayesian estimation with Stan

Specification

The Hidden Markov Model + Conditional Heteroskedasticity proposed above involves only \(K\) weights \(\lambda_1, \dots, \lambda_K\) that are constant over time. We further assume that the discrete \(K\) regimes follow a first-order Markov process led by transition probabilities \(\bp\). Since we don’t observe the states directly, we say they are hidden and we then estimate a probability distribution over the possible outputs. Remember that there is one set of parameters for the GARCH equation in each state.

Let \(z_{t}\) be the discrete component, state or regime at time point \(t\). The state dynamics are governed by the transition matrix \(\mat{\Psi}\) of size \(K \times K\) and elements \(\Psi(i, j) = p(z_{t} = j \ | \ z_{t-1} = i)\) with \(0 \le \Psi(i, j) \le 1\) and \(\sum_{j}{\Psi(i, j)} = 1\). The matrix has \(K(K-1)\) independent parameters. The initial latent node \(z_{1}\) doesn’t have a parent node and has a marginal distribution \(p(z_1)\).

The specification of the probabilistic model is completed by the conditional distributions of the observed variables \(p(\epsilon | z_t, \btheta)\) where \(\btheta\) are a set of parameters for this distribution. Usually known as the emission probabilities in the machine learning jargon, each element of this \(K\)-sized vector represents the probabilities that any given observation of the volatility corresponds to the \(K\) possible states.

Forward algorithm

The forward algorithm is used to estimate the belief state \(p(z_{t} | \ \II_{t})\), the joint probability of a state at a certain time and the information available up the moment. Estimating the \(K\)-sized vector is known as filtering. When run altogether with the backward algorithm, you get the smoothed probability \(p(z_{t} \ | \ \II_{T})\).

A filter infers the belief state based on all the available information up to that point \(p(z_t | \mat{y}_{1:t})\). It achieves better noise reduction than simply estimating the hidden state based on the current estimate. The filtering process can be run online, or recursively, as new data streams in.

Filtered maginals can be computed recursively by means of the forward algorithm Baum and Eagon (1967). Let \(\psi_t(j) = p(\mat{y}_t | z_t = j)\) be the local evidence at time \(t\) and \(\Psi(i, j) = p(z_t = j | z_{t-1} = i)\) be the transition probability. First, the one-step-ahead predictive density is computed

\[ p(z_t = j | \mat{y}_{1:t-1}) = \sum_{i}{\Psi(i, j) p(z_{t-1} = i | \mat{y}_{1:t-1})}. \]

Acting as prior information, this quantity is updated with observed data at the point \(t\) using Bayes rule, \[\begin{align*} \label{eq:filtered-belief_state} \alpha_t(j) & \triangleq p(z_t = j | \mat{y}_{1:t}) \\ &= p(z_t = j | \mat{y}_{t}, \mat{y}_{1:t-1}) \\ &= Z_t^{-1} \psi_t(j) p(z_t = j | \mat{y}_{1:t-1}) \\ &= Z_t^{-1} \psi_t(j) \alpha_{t-1}(j), \end{align*}\]

where the normalization constant is given by

\[ Z_t \triangleq p(\mat{y}_t | \mat{y}_{1:t-1}) = \sum_{l}{p(\mat{y}_{t} | z_t = l) p(z_t = l | \mat{y}_{1:t-1})}, = \sum_{l}{p(\mat{y}_{t} | z_t = l) \alpha_{t-1}(l)}. \]

This predict-update cycle results in the filtered belief states at point \(t\). As this algorithm only requires the evaluation of the quantities \(\psi_t(j)\) for each value of \(z_t\) for every \(t\) and fixed \(\mat{y}_t\), the posterior distribution of the latent states is independent of the form of the observation density or indeed of whether the observed variables are continuous or discrete Jordan (2003).

Let \(\mat{\alpha}_t\) be a \(K\)-sized vector with the filtered belief states at point \(t\), \(\mat{\psi}_t(j)\) be the \(K\)-sized vector of local evidence at point \(t\), \(\mat{\Psi}\) be the transition matrix and \(\mat{u} \odot \mat{v}\) is the Hadamard product, representing elementwise vector multiplication. Then, the bayesian updating procedure can be expressed in matrix notitation as

\[ \mat{\alpha}_t \propto \mat{\psi}_t \odot (\mat{\Psi}^T \mat{\alpha}_{t-1}). \]

In addition to computing the hidden states, the algorithm yields the log probability of the evidence

\[ \log p(\mat{y}_{1:T} | \mat{\theta}) = \sum_{t=1}^{T}{p(\mat{y}_{1:t} | \mat{y}_{1:t-1})} = \sum_{t=1}^{T}{\log Z_t}. \]

Log domain should be preferred to avoid numerical underflow.

Case Study

Let’s set math and computations aside for a while and focus on finance: what can we make out of a model like this?

Preamble

Before we get moving, make sure you’ve downloaded all the auxiliary file to the same folder. We first check all the required packages for this notebook are avaliable.

packages.req <- c('quantmod', 'rugarch', 'rstan', 'shinystan', 'lattice', 'gridExtra', 'gridBase', 'HH')
packages.mis <- packages.req[!(packages.req %in% rownames(installed.packages()))]

if (length(packages.mis)) {
  stop(paste('Please, first install the following packages:', packages.mis))
  # We could write a script to install them directly, but this may mess up other code of yours
}

Fetching the Data

We choose \(N = 5\) series from 2011-01-01 to 2016-12-31 (\(T = 1502\)): ^GSPC, F, GM, THO and AIR. The data is downloaded and pre-processed using quantmod (Ryan, Ulrich, and Thielen 2016).

library(quantmod)
syms <- c('^GSPC', 'F', 'GM', 'THO', 'AIR')

usecache = TRUE
cache.filename <- 'data/symsret.RDS'
if (usecache && file.exists(cache.filename)) {
  y_t <- readRDS(cache.filename)
} else {
  y_t = as.matrix(
    do.call(cbind, lapply(syms, function(s) {
      p <- getSymbols(s, src = "yahoo", from = "2011-01-01", to = "2016-12-31", auto.assign = FALSE)
      r <- periodReturn(p, period = 'daily', type = 'log')
      colnames(r) <- s
      r * 100
    })))
}

Inference

The (very) naive implementation of the algorithm in Stan is only meant for illustration. A few good practices were neglected, convergence is not guaranteed, there is much room left for optimization and fitting N different independent models is probably not a reasonable choice for production sampler. The main takeaway of this presentation is the ideas behind the code but not the code itself.

We’ll load Stan (2016) and run the model for \(K = 2\) states. Since the sampler may take a few minutes, I’ve built a very basic caching feature.

library(rstan)
rstan_options(auto_write = TRUE)  # Writes down the compiled sampler
options(mc.cores = parallel::detectCores()) # Use all available cores

K = 2 # Number of states
bmodel = 'stan/hmmgarch.stan' # Name of the model file
standata = list(
  N = ncol(y_t),
  T = nrow(y_t),
  K = K,
  y = t(y_t)
)

usecache = TRUE
cache.filename <- paste0('stan/hmmgarch-cache.rds')
if (usecache && file.exists(cache.filename)) {
  stan.fit <- readRDS(cache.filename)
} else {
  stan.fit <- stan(file = bmodel,
                   model_name = "Bayesian Hierarchical Mixture GARCH",
                   data = standata, verbose = T,
                   iter = 200, warmup = 100, thin = 1, chains = 4, cores = 4,
                   control = list(adapt_delta = 0.80))
  
  saveRDS(stan.fit, file = cache.filename)
}

We’ll also fit a single regime GARCH model with rugarch (Ghalanos 2015). Sidenote: I’ve used rugarch considerably and it proved to be very reliable, it’s a fine work of software engineering.

library(rugarch)
SR <- lapply(1:ncol(y_t), function(n) {
  mle.specSR <- ugarchspec(
    variance.model = list(model = "sGARCH", garchOrder = c(1, 1),
                          submodel = NULL, external.regressors = NULL, variance.targeting = FALSE),
    mean.model = list(armaOrder = c(0, 0), include.mean = FALSE, archm = FALSE),
    distribution.model = 'norm'
  )
  mle.fitSR  <- ugarchfit(mle.specSR, y_t[, n])
  list(as.numeric(sigma(mle.fitSR)), uncvariance(mle.fitSR))
})

Plots

We’ll make extensive use of plots, mainly based on Lattice (Sarkar 2008). For better organization, plot logic is consolidated into an auxiliary script.

source('R/plots.R')

Findings

We filter the daily log returns through a single regime \(GARCH(1, 1)\) model with Gaussian density.

  q <- queue[[1]]
  tscsplot(q$getMat(), q$getMain())

We first observe that volatility has positive linear correlation across assets. This is pretty self-explanatory: although each asset has its own volatility level and dynamics, volatility across stocks tend to increase or decrease at the same time. Moreover, the strength of the observed relationship depends on the pairs of assets. The volatility in the log return of F and GM shows a stronger positive correlation than, say, F and AIR. Stronger correlations are expected among stocks with similar business model, industry or exposure to macroeconomic factors. Assets react differently to news. It is well expected that bad news about in the car manufacturing industry will impact F and GM in a similar way and hit AIR only indirectly.

From the figure above it’s evident that this analysis is just an approximation. First of all, data points form a funnel: the volatility spread across assets is larger when volatility increases. Second, there are many extreme values. It is very important that any analysis is checked for robustness. A first thought, logarithmic transformation would allow for multiplicative spreads, stabilize variance and partially tame extreme values at the same time. This would also map a positive bounded variable to Reals, which may or not be of interest for some purposes (for example sampling and priors).

So far we’ve only seen that volatility is correlated across assets. You may say this was pretty obvious and you’re not satisfied, so we’ll keep digging. We accept the idea that market has two states and we filter the same series through a HMM Conditional Heteroskedasticity Model. Now, F looks as follows:

  n <- 2 # Ford
  q <- queue[[8]]
tscpplot(q$getMat(), q$getMain())

With unconditional volatilities of 0.62 and 1.76, the states can be identified as low and high volatility days respectively. We also see that the market spends more time in the low volatility state.

  q <- queue[[9]]
  cstscpplot(q$getMat(), q$getMain())

Another three interesting things to note. First, we observe that the first state is more probable when the log returns are close to zero. This is exactly what we expected when we named it the low volatility state. Second, the filtered probabilities are autocorrelated. This hints that some kind of memory structure may help in prediction, knowing on which state we currently are decreases uncertainty about tomorrow. Finally, the square of the volatility (the variance) estimated for each state are linearly related with intercept and slope different from zero. These features should be tested for reasonability in your own use case.

We end showing that belief state across assets are correlated.

  q <- queue[[5]]
  tscsplot(q$getMat(), q$getMain())

We noted that states and log returns are related: cross correlation in log returns may explain correlation among states. We also noted that predictability could be improved profiting from the memory structure in the states. On the whole, these feature may be of value for trading strategies or risk models.

Discussion & further research

It’s evident that states are shared among assets. Again, the strength of the relationship depends on each asset. We may even hypothesize that states follow a hierarchical structure: for example, the risk state of a global portfolio may be broken down into Country + Industry + Stock Individual. The challenge lies in finding a way to filter the emission probabilities considering that states are hierarchical using a Hierarchical Hidden Markov Model. This is clearly a perfect setting for bayesian estimation where parameter hierarchy is naturally modelled. This, I believe, is the most promising path for the analysis.

References

Baum, Leonard E., and J. A. Eagon. 1967. “An Inequality with Applications to Statistical Estimation for Probabilistic Functions of Markov Processes and to a Model for Ecology.” Bulletin of the American Mathematical Society 73 (3). American Mathematical Society (AMS): 360–64. doi:10.1090/s0002-9904-1967-11751-8.

Bollerslev, Tim. 1986. “Generalized Autoregressive Conditional Heteroskedasticity.” Journal of Econometrics 31 (3). Elsevier: 307–27.

Franses, Philip Hans, Dick van Dijk, and Anne Opschoor. 2014. “Time Series Models for Business and Economic Forecasting.” Cambridge University Press.

Ghalanos, Alexios. 2015. Rugarch: Univariate Garch Models.

Haas, Markus, Stefan Mittnik, and Marc S Paolella. 2004. “Mixed Normal Conditional Heteroskedasticity.” Journal of Financial Econometrics 2 (2). Oxford Univ Press: 211–50.

Jordan, Michael I. 2003. “An Introduction to Probabilistic Graphical Models.” preparation.

Ryan, Jeffrey, Joshua Ulrich, and Wouter Thielen. 2016. Quantmod: Quantitative Financial Modelling Framework.

Sarkar, Deepayan. 2008. Lattice: Multivariate Data Visualization with R. New York: Springer.

Team, Stan Development. 2016. Stan Modeling Language: User’s Guide and Reference Manual.

LS0tDQp0aXRsZTogIkEgcXVpY2sgaW50cm8gdG8gSGlkZGVuIE1hcmtvdiBNb2RlbHMgYXBwbGllZCB0byBTdG9jayBWb2xhdGlsaXR5Ig0KYXV0aG9yOiAiTHVpcyBEYW1pYW5vIg0KZGF0ZTogIlIvRmluYW5jZSAyMDE3IHwgTWF5IDE5Ig0Kb3V0cHV0OiBodG1sX25vdGVib29rICMgaHRtbF9kb2N1bWVudA0KYmlibGlvZ3JhcGh5OiBiaWJsaW9ncmFwaHkuYmliDQotLS0NCg0KVGhpcyBub3RlYm9vayBpcyBwYXJ0IG9mIHRoZSBtYXRlcmlhbCBwcmVzZW50ZWQgaW4gW1IvRmluYW5jZV0oaHR0cDovL3d3dy5yaW5maW5hbmNlLmNvbS8pIDIwMTcuIFBsZWFzZSwgc2VlIHRoZSBbUkVBRE1FXSguLi9SRUFETUUubWQpIGZpbGUuDQoNClxbDQpcbmV3Y29tbWFuZHtcbWF0fVsxXXtcbWF0aGJmeyMxfX0NClxuZXdjb21tYW5ke1xFRX1bMV17XG1hdGhiYntFfVxsZWZ0WyAjMSBccmlnaHRdfQ0KXG5ld2NvbW1hbmR7XFZWfVsxXXtcbWF0aGJie1Z9XGxlZnRbICMxIFxyaWdodF19DQpcbmV3Y29tbWFuZHtcUlJ9e1xtYXRoYmJ7cn19DQpcbmV3Y29tbWFuZHtcSUl9e1xtYXRoYmJ7SX19DQpcbmV3Y29tbWFuZHtcTk59e1xtYXRoYmJ7Tn19DQpcbmV3Y29tbWFuZHtcYnB9e1xtYXRoYmZ7cH19DQpcbmV3Y29tbWFuZHtcYlR9e1xtYXRoYmZ7VH19DQpcbmV3Y29tbWFuZHtcYnRoZXRhfXtcbWF0aGJme1x0aGV0YX19DQpcXQ0KDQojIFdoYXQncyBhbGwgdGhpcyBhYm91dD8NClRoZSBhaW0gb2YgdGhpcyBub3RlYm9vayBpcyB0d29mb2xkLiBGaXJzdCwgSSdkIGxpa2UgdG8gZHJhdyB5b3VyIGF0dGVudGlvbiB0byBhIHNtYWxsIGZhY3Qgb2JzZXJ2ZWQgaW4gZmluYW5jaWFsIGFzc2V0cyBwcmljZXMgd2hlbiBmaWx0ZXJlZCB0aHJvdWdoIGEgTWFya292IFN3aXRjaGluZyBHQVJDSCBtb2RlbDogd2hlbiBsb2cgcmV0dXJucyBhcmUgZmlsdGVyZWQgdGhyb3VnaCBhIEdBUkNIIG1vZGVsIHdpdGggTWFya292aWFuIGR5bmFtaWNzLCB0aGUgYmVsaWVmIHN0YXRlcyAobG93L2hpZ2ggdm9sYXRpbGl0eSkgYXJlIGNvcnJlbGF0ZWQgYWNyb3NzIGFzc2V0cy4gSXQncyBub3QgYSBnYW1lIGNoYW5nZXIgYnV0IGhvcGVmdWxseSBpdCB3aWxsIHRyaWdnZXIgc29tZSBuZXcgaWRlYXMgdG8gaW1wcm92ZSB5b3VyIHRyYWRpbmcgc3RyYXRlZ3kgb3IgcmlzayBtb2RlbC4gU2Vjb25kLCBJJ2xsIHVzZSB0aGlzIHNtYWxsIGZhY3QgYXMgYW4gZXhjdXNlIHRvIGludHJvZHVjZSB5b3UgdG8gYSBmZXcgc21hbGwgY29uY2VwdHMgdGhhdCBjZXJ0YWlubHkgd2lsbCBiZSBvZiBoZWxwIHRvIGFueSBmaW5hbmNpYWwgYW5hbHlzdC4NCg0KWW91J2xsIGJlIGV4cG9zZWQgdG8gdGhlIGZvbGxvd2luZyBjb25jZXB0czoNCg0KMS4gTWl4dHVyZSBOb3JtYWwgYW5kIE1hcmtvdiBTd2l0Y2hpbmcgR0FSQ0ggbW9kZWwuDQoyLiBIaWRkZW4gTWFya292IE1vZGVsIGFuZCB0aGUgZm9yd2FyZCBhbGdvcml0aG0uDQozLiBCYXllc2lhbiBzdGF0aXN0aWNzIGFuZCBTdGFuLCBhIHByb2JhYmlsaXN0aWMgcHJvZ3JhbW1pbmcgbGFuZ3VhZ2UgZm9yIHN0YXRpc3RpY2FsIGluZmVyZW5jZS4NCjQuIE5lYXQgcGxvdHMuDQoNCldvcnJpZWQgYnkgdGhlIGJyb2FkIHNjb3BlPyBJJ2xsIG9ubHkgZXhwbGFpbiB0aGUgYmFzaWNzIGFuZCBsZWF2ZSBtYW55LCBtYW55IHJlZmVyZW5jZXMuIEhvcGVmdWxseSwgdGhpcyB3aWxsIGJlIGVub3VnaCBleHBvc3VyZSBmb3IgeW91IHRvIGRlY2lkZSBpZiB0aGUgdG9waWMgaXMgd29ydGggaW52ZXN0aW5nIG1vcmUgZWZmb3J0Lg0KDQojTWl4dHVyZSBvZiBOb3JtYWxzIENvbmRpdGlvbmFsIEhldGVyb3NrZWRhc3RpY2l0eQ0KDQojIyMgQ29uZGl0aW9uYWwgSGV0ZXJvc2tlZGFzdGljaXR5DQpBbHNvIGtub3duIGFzIHZvbGF0aWxpdHkgY2x1c3RlcmluZywgY29uZGl0aW9uYWwgaGV0ZXJvc2tlZGFzdGljaXR5IGlzIGEga2V5IGZlYXR1cmUgb2YgZWNvbm9taWMgdGltZSBzZXJpZXMsIGluIHBhcnRpY3VsYXIgb2YgcmV0dXJucyBvZiBmaW5hbmNpYWwgYXNzZXRzLiAgUmVsYXRpdmVseSB2b2xhdGlsZSBwZXJpb2RzLCBjaGFyYWN0ZXJpemVkIGJ5IGxhcmdlIHByaWNlIGNoYW5nZXMgYW5kIGxhcmdlIHJldHVybnMsIGFsdGVybmF0ZSB3aXRoIG1vcmUgY2FsbSBwZXJpb2RzIHdpdGggc3RhYmxlIHByaWNlcyBhbmQgc21hbGwgcmV0dXJucyBbQGZyYW5zZXMyMDE0dGltZSwgcHAuIDI2XS4NCg0KTGV0ICRQX3QkIGJlIHRoZSBwcmljZSBvZiBhbiBhc3NldCBhdCB0aW1lICR0JCBhbmQgJHJfdCA9IGxvZyhQX3QpIC0gbG9nKFBfe3QtMX0pJCBiZSB0aGUgbG9nIHJldHVybi4gVGhlIGV4cGVjdGVkIHJldHVybiAkbV90JCBpcyBlc3RpbWF0ZWQgYnkgYW55IG1vZGVsIGZvciB0aGUgbWVhbiB0aGF0IGxlYXZlcyBhbiB1bmV4cGxhaW5lZCBjb21wb25lbnQgJFxlcHNpbG9uX3QkIGNhbGxlZCBzdG9jaGFzdGljIGVycm9yIG9yIHJhbmRvbSBzaG9jazoNCg0KJCQgcl90ID0gbV90ICsgXGVwc2lsb25fdC4gJCQNCkFzIHdpbGwgYmUgc2VlbiBsYXRlciwgdGhlIHNob2NrIGlzIHJlbGF0ZWQgdG8gdGhlIHZhcmlhbmNlIG9mIHRoZSByZXR1cm5zIGFuZCBtYXkgYmUgbW9kZWxsZWQgZGV0ZXJtaW5pc3RpY2FsbHkgb3Igc3RvY2hhc3RpY2FsbHkuIEluIHRoZSBmaXJzdCBjYXNlLCB0aGUgZXJyb3IgaXMgYXNzdW1lZCB0byBoYXZlIHRoZSBmb3JtICRcZXBzaWxvbl90ID0gdl90IFxzcXJ0e2hfdH0kLCB3aGVyZSAkdl90JCBpcyBhIHN0YW5kYXJkaXplZCByYW5kb20gdmFyaWFibGUsIGkuZS4gaW5kZXBlbmRlbnQgYW5kIGlkZW50aWNhbGx5IGRpc3RyaWJ1dGVkIHdpdGggemVybyBtZWFuIGFuZCB1bml0IHZhcmlhbmNlLiBOb3RlIHdlJ3ZlIG5vdCBhc3N1bWVkIGEgR2F1c3NpYW4gc2hhcGUuIEBmcmFuc2VzMjAxNHRpbWUgcHAuIDE3MCBzaG93cyB0aGF0IHRoZSBzaG9ja3MgaGF2ZSBhIGNvbnN0YW50IHVuY29uZGl0aW9uYWwgdmFyaWFuY2UgZXF1YWwgdG8gJFxzaWdtYV4yJCBhbmQgYSBkaXN0cmlidXRpb24gY29uZGl0aW9uYWwgb24gcGFzdCBpbmZvcm1hdGlvbiAkXElJX3t0LTF9JCB3aXRoIG1lYW4gemVybyBhbmQgdmFyaWFuY2UgJGhfdCQuIFRoYXQgaXMsDQoNCiQkIFxFRXtcZXBzaWxvbl90fSA9IDAsIFxxdWFkIFxWVntcZXBzaWxvbl90fSA9IFxzaWdtYV4yLCBccXVhZCBcRUV7XGVwc2lsb25fdCB8IFxJSV97dC0xfX0gPSAwLCBccXVhZCBcVlZ7XGVwc2lsb25fdCB8IFxJSV97dC0xfX0gPSBoX3QuICQkDQpCdWlsZGluZyB1cG9uIEF1dG9yZWdyZXNzaXZlIENvbmRpdGlvbmFsIEhldGVyb3NrZWRhc3RpY2l0eSAoQVJDSCksIEBib2xsZXJzbGV2MTk4NmdlbmVyYWxpemVkIHByb3Bvc2VkIHRoZSBHZW5lcmFsaXplZCBBdXRvcmVncmVzc2l2ZSBDb25kaXRpb25hbCBIZXRlcm9za2VkYXN0aWNpdHkgKEdBUkNIKS4gVGhlIGNvbmRpdGlvbmFsIHZhcmlhbmNlIGlzIGEgZGV0ZXJtaW5pc3RpYyBmdW5jdGlvbiBvZiBpdHMgcGFzdCB2YWx1ZXMgYW5kIHBhc3Qgc3F1YXJlZCBzaG9ja3M6DQoNCiQkICgxKSBccXVhZCBccXVhZCBoX3QgPSBcYWxwaGFfMCArIFxzdW1fe2k9MX1ee3F9e1xhbHBoYV9pIFwgXGVwc2lsb25eMl97dC0xfX0gKyBcc3VtX3tqPTF9XntwfXtcYmV0YV9pIFwgaF97dC1qfX0sJCQgDQp3aXRoICRcYWxwaGFfMCA+IDAkLCAkXGFscGhhX2kgXGdlIDAkLCAkXGJldGFfaiBcZ2UgMCQgYW5kICRcc3VtX3tpPTF9XnttYXgobSwgcyl9eyhcYWxwaGFfaSArIFxiZXRhX2opfSA8IDEkICgkXGFscGhhX2kgPSAwIFwgXGZvcmFsbCBcIGkgPiBtJCBhbmQgJFxiZXRhX2ogPSAwIFwgXGZvcmFsbCBcIGogPiBzJCkuDQoNCldoYXQgZG9lcyBhbGwgdGhpcyBtZWFuPyBTaW1wbHksIHRoYXQgdGhlIHZvbGF0aWxpdHkgb2YgcmV0dXJucyAtIG1lYXN1cmVkIGFzIHRoZSBjb25kaXRpb25hbCBzZWNvbmQgbW9tZW50IG9mIHRoZSBzZXJpZXMgLSB2YXJpZXMgZGV0ZXJtaW5pc3RpY2FsbHkgd2l0aCB0aW1lLiBDaGFuZ2VzIGluIGNvbmRpdGlvbmFsIHZvbGF0aWxpdHkgYXJlIGxlZCBieSBwYXN0IHZvbGF0aWxpdHkgYW5kIHNob2Nrcy4gVGhlIGxhcmdlciB0aGUgbGFzdCAkcSQgc2hvY2tzIG9yIHRoZSBvYnNlcnZlZCB2b2xhdGlsaXR5IGluIHRoZSBsYXN0ICRwJCBwZXJpb2RzLCB0aGUgbW9yZSB1bmNlcnRhaW4gd2UgYXJlIGFib3V0IHRoZSBuZXh0IHJldHVybi4gSXQncyBtb3JlIHVuY2VydGFpbiB0byBwbGFjZSBhIGJldCBvbiB0b2RheSdzIGNsb3NlIHByaWNlIGlmIHRoZSBzdG9jayBqdXN0IG1vdmVkIGZhciBmcm9tIGl0cyBleHBlY3RlZCB2YWx1ZS4gQSBmYWlybHkgc2ltcGxlIG1vZGVsIGluZGVlZCwgYnV0IGl0IG1ha2VzIHNlbnNlLg0KDQpCeSB0aGUgd2F5LCB0aGUgR0FSQ0ggZmFtaWx5IGlzIF9IVUdFXy4gVGhlcmUncyBhIHZhc3QgbGl0ZXJhdHVyZSBvcmlnaW5hdGVkIGluIHRoZSBhY2FkZW15IGR1cmluZyB0aGUgOTAncyBhbmQgZnVlbGVkIGJ5IGl0cyBleHRlbnNpdmUgdXNlIGluIHRoZSBpbmR1c3RyeSBpbiB0aGUgMDAncy4gTWFueSB2YXJpYXRpb25zIGFsbG93IGZvciBtb3JlIGNvbXBsZXggcGF0dGVybnMgbGlrZSBub24tbGluZWFyaXR5LCBhc3ltbWV0cnkgYW5kIGZhdHRlciB0YWlsczogSW50ZWdyYXRlZCBHQVJDSCwgR0FSQ0ggaW4gbWVhbiwgRXhwb25lbnRpYWwgR0FSQ0gsIFRocmVzaG9sZCBHQVJDSCwgR0pSIEdBUkNILCBBc3ltbWV0cmljIFBvd2VyIEdBUkNILCBzdHVkZW50IHQgYW5kIEdlbmVyYWxpemVkIEVycm9yIERpc3RyaWJ1dGlvbiwgYW1vbmcgbWFueSBvdGhlcnMuIFNlZSBAZnJhbnNlczIwMTR0aW1lIHBwLiAxNzYgYW5kIEBydWdhcmNoMjAxNSwgVmlnbmV0dGVzLg0KDQojIyNNaXh0dXJlIG9mIE5vcm1hbHMNCkEgcmFuZG9tIHZhcmlhYmxlICRcZXBzaWxvbiQgaXMgc2FpZCB0byBoYXZlIGEgdW5pdmFyaWF0ZSBmaW5pdGUgbm9ybWFsIG1peHR1cmUgZGlzdHJpYnV0aW9uIGlmIHRoZSB1bmNvbmRpdGlvbmFsIGRlbnNpdHkgaXMgZ2l2ZW4gYnkgDQoNCiQkIE1OKFxlcHNpbG9uKSA9IFxzdW1fe2o9MX1ee0t9e1xsYW1iZGFfaiBcIE4oXGVwc2lsb24gfCBcbXVfaiwgXCBcc2lnbWFeMl9qKX0sICQkDQp3aGVyZSAkSyBcaW4gXE5OJCBpcyB0aGUgbnVtYmVyIG9mIGNvbXBvbmVudHMsICROKFxtdSwgXCBcc2lnbWFeMikkIGlzIHRoZSBHYXVzc2lhbiBkZW5zaXR5IHdpdGggbWVhbiAkXG11JCBhbmQgdmFyaWFuY2UgJFxzaWdtYV4yJCwgYW5kICRcbGFtYmRhX2okIGFyZSB0aGUgbWl4aW5nIHdlaWdodHMgd2l0aCAkXGxhbWJkYV9qID4gMCBcIFxmb3JhbGwgXCBqJCBhbmQgJFxzdW1fe2o9MX1ee2t9e1xsYW1iZGFfan0gPSAxJCBbQGhhYXMyMDA0bWl4ZWRdLg0KDQpBIG1peHR1cmUgb2YgZGlzdHJpYnV0aW9uIGlzIGFuIG9sZCBzdGF0aXN0aWNhbCB0cmljayB0byBhY2NvbW9kYXRlIHNrZXduZXNzIGFuZCBleGNlc3Mga3VydG9zaXMuIEl0IGhhcyBhbiBleHRyYSBmZWF0dXJlIGluIGVjb25vbWljczogdGhlIGNvbXBvbmVudHMgYXJlIHVzdWFsbHkgc3ViamVjdCB0byBzaW1wbGUgeWV0IHVzZWZ1bCBpbnRlcnByZXRhdGlvbnMuIFRoZSB2YXJpYWJsZSBvZiBpbnRlcmVzdCBoYXMgYSBkaWZmZXJlbnQgbWVhbiBhbmQgdmFyaWFuY2UgZGVwZW5kaW5nIG9uIHdoaWNoIHN0YXRlIHRoZSBwcm9jZXNzIGlzLiBJbiBvdXIgbW9kZWwsIHN0YXRlcyBtYXkgcmVwcmVzZW50IHJlY2Vzc2lvbi9leHBhbnNpb24sIGJlYXJpc2gvYnVsbGlzaCwgbG93L2hpZ2ggdm9sYXRpbGl0eSwgcmlzayBvZmYvb24sIGFuZCBzbyBvbi4gT2YgY291cnNlLCB0aGUgY2hvaWNlIGlzbid0IG5lY2Vzc2FyaWx5IGJpbmFyeS4gS2VlcCByZWFkaW5nIHRvIGtub3cgbW9yZSENCg0KIyMjTWl4dHVyZSBvZiBOb3JtYWxzICsgQ29uZGl0aW9uYWwgSGV0ZXJvc2tlZGFzdGljaXR5DQpJZiB0aGUgdGltZSBzZXJpZXMgJFx7XGVwc2lsb25fdFx9JCBpcyBnZW5lcmF0ZWQgYnkgYSAkSyQtY29tcG9uZW50TWl4dHVyZSBvZiBOb3JtYWxzICRHQVJDSChwLCBxKSQgcHJvY2VzcywgdGhlbiB0aGUgY29uZGl0aW9uYWwgZGVuc2l0eSBvZiB0aGUgc2hvY2sgaXMgZ2l2ZW4gYnkNCiQkIGYoXGVwc2lsb25fdCB8IFxJSV97dC0xfSkgPSBNTihcbGFtYmRhXzEsIFxkb3RzLCBcbGFtYmRhX0ssIGhfezF0fSwgaF97S3R9KSwkJA0Kd2hlcmUgJFxJSV97dC0xfSQgaXMgdGhlIGluZm9ybWF0aW9uIHNldCBhdCB0aW1lICR0LTEkLCAkXGxhbWJkYV9pIFxpbiAoMCwgMSkgXCBpID0gMSwgXGRvdHMsIEskIGFuZCAkXHN1bV97aT0xfV57S317XGxhbWJkYV9pfSA9IDEkLiBJbiB0aGUgc2ltcGxlc3QgY2FzZSAoZGlhZ29uYWwgc3ltbWV0cmljKSwgZWFjaCBwb3NzaWJsZSAkayA9IDEsIFxkb3RzLCBLJCBzdGF0ZSBoYXMgaXRzIG93biBjb25kaXRpb25hbCB2b2xhdGlsaXR5IGdvdmVybmVkIGJ5IGl0cyBvd24gR0FSQ0ggZGV0ZXJtaW5pc3RpYyBkeW5hbWljcyBhbmQgaXRzIG93biBzdGF0ZS1kZXBlbmRlbnQgcGFyYW1ldGVyczoNCg0KJCQgKDIpIFxxdWFkIFxxdWFkIGhfe2t0fSA9IFxhbHBoYV97azB9ICsgXHN1bV97aT0xfV57cX17XGFscGhhX3traX0gXCBcZXBzaWxvbl4yX3t0LTF9fSArIFxzdW1fe2o9MX1ee3B9e1xiZXRhX3tran0gXCBoX3trLCBcIHQtan19LiAkJCANCg0KVGhpcyBpcyBpbnRlcmVzdGluZyBub3cuIFdlIG9ubHkgb2JzZXJ2ZSBvbmUgc2VyaWVzIG9mIGxvZyByZXR1cm5zIHdoaWNoIGZvbGxvd3Mgb25seSBvbmUgcGF0aCBvZiBjb25kaXRpb25hbCB2b2xhdGlsaXR5LiBOb25ldGhlbGVzcywgdm9sYXRpbGl0eSBhdCBhbnkgZ2l2ZW4gdGltZSAkdCQgY29tZXMgZnJvbSBvbmUgb2YgdGhlICRLJCBkaWZmZXJlbnQgc3RhdGVzIG9yIHJlZ2ltZXMsIGVhY2ggb25lIHdpdGggaXRzIG93biBsZXZlbCBhbmQgZHluYW1pY3MuIFJlZ2ltZSBzd2l0Y2hpbmcgYWxsb3dzIGZvciBub24tbGluZWFyaXR5IGluIHRoZSBtb2RlbCBhbmQgYWxsb3cgb3VyIGVzdGltYXRlcyB0byBxdWlja2x5IGFkanVzdCB0byBjaGFuZ2VzIGluIHRoZSBtYXJrZXQuDQoNCiMjIyBIaWRkZW4gTWFya292IE1vZGVsICsgQ29uZGl0aW9uYWwgSGV0ZXJvc2tlZGFzdGljaXR5DQoNCkhpZGRlbiBNYXJrb3YgTW9kZWwgKEhNTSkgaW52b2x2ZXMgdHdvIGludGVyY29ubmVjdGVkIG1vZGVscy4gVGhlIHN0YXRlIG1vZGVsIGNvbnNpc3RzIG9mIGEgZGlzY3JldGUtdGltZSwgZGlzY3JldGUtc3RhdGUgTWFya292IGNoYWluIHdpdGggaGlkZGVuIHN0YXRlcyAkel90IFxpbiBcezEsIFxkb3RzLCBLXH0kIHRoYXQgdHJhbnNpdGlvbiBhY2NvcmRpbmcgdG8gJHAoel90IHwgel97dC0xfSkkLiBBZGRpdGlvbmFsbHksIHRoZSBvYnNlcnZhdGlvbiBtb2RlbCBpcyBnb3Zlcm5lZCBieSAkcChcbWF0e3l9X3QgfCB6X3QpJCwgd2hlcmUgJFxtYXR7eX1fdCQgYXJlIHRoZSBvYnNlcnZhdGlvbnMsIGVtaXNzaW9ucyBvciBvdXRwdXQuIEluIG91ciBjYXNlLCB0aGUgbGF0dGVyIGlzIHJlcHJlc2VudGVkIGJ5IHRoZSBHQVJDSCBlcXVhdGlvbi4NCg0KSXQgaXMgYSBzcGVjaWZpYyBpbnN0YW5jZSBvZiB0aGUgc3RhdGUgc3BhY2UgbW9kZWwgZmFtaWx5IGluIHdoaWNoIHRoZSBsYXRlbnQgdmFyaWFibGVzIGFyZSBkaXNjcmV0ZS4gRWFjaCBzaW5nbGUgdGltZSBzbGljZSBjb3JyZXNwb25kcyB0byBhIG1peHR1cmUgZGlzdHJpYnV0aW9uIHdpdGggY29tcG9uZW50IGRlbnNpdGllcyBnaXZlbiBieSAkcChcbWF0e3l9X3QgfCB6X3QpJCwgdGh1cyBITU0gbWF5IGJlIGludGVycHJldGVkIGFzIGFuIGV4dGVuc2lvbiBvZiBhIG1peHR1cmUgbW9kZWwgaW4gd2hpY2ggdGhlIGNob2ljZSBvZiBjb21wb25lbnQgZm9yIGVhY2ggb2JzZXJ2YXRpb24gaXMgbm90IHNlbGVjdGVkIGluZGVwZW5kZW50bHkgYnV0IGRlcGVuZHMgb24gdGhlIGNob2ljZSBvZiBjb21wb25lbnQgZm9yIHRoZSBwcmV2aW91cyBvYnNlcnZhdGlvbi4gSW4gdGhlIGNhc2Ugb2YgYSBzaW1wbGUgbWl4dHVyZSBtb2RlbCBmb3IgYW4gaWRlbnRpY2FsbHkgaW5kZXBlbmRlbnRseSBkaXN0cmlidXRlZCBzYW1wbGUsIHRoZSBwYXJhbWV0ZXJzIG9mIHRoZSB0cmFuc2l0aW9uIG1hdHJpeCBpbnNpZGUgdGhlICRpJC10aCBjb2x1bW4gYXJlIHRoZSBzYW1lLCBzbyB0aGF0IHRoZSBjb25kaXRpb25hbCBkaXN0cmlidXRpb24gJHAoel90IHwgel97dC0xfSkkIGlzIGluZGVwZW5kZW50IG9mICR6X3t0LTF9JC4NCg0KSW4gb3RoZXIgd29yZHMsIEhNTSBhcmUgZXF1aXZhbGVudCB0byBhIEdhdXNzaWFuIG1peHR1cmUgbW9kZWwgd2l0aCBjbHVzdGVyIG1lbWJlcnNoaXAgcnVsZWQgYnkgTWFya292aWFuIGR5bmFtaWNzLCBhbHNvIGtub3duIGFzIE1hcmtvdiBTd2l0Y2hpbmcgTW9kZWxzIChNU00pLiBNdWx0aXBsZSBzZXF1ZW50aWFsIG9ic2VydmF0aW9ucyB0ZW5kIHRvIHNoYXJlIHRoZSBzYW1lIGxvY2F0aW9uIHVudGlsIHRoZXkgc3VkZGVubHkganVtcCBpbnRvIGEgbmV3IGNsdXN0ZXIuDQoNCiMgQmF5ZXNpYW4gZXN0aW1hdGlvbiB3aXRoIFN0YW4NCg0KIyMjIFNwZWNpZmljYXRpb24NClRoZSBIaWRkZW4gTWFya292IE1vZGVsICsgQ29uZGl0aW9uYWwgSGV0ZXJvc2tlZGFzdGljaXR5IHByb3Bvc2VkIGFib3ZlIGludm9sdmVzIG9ubHkgJEskIHdlaWdodHMgJFxsYW1iZGFfMSwgXGRvdHMsIFxsYW1iZGFfSyQgdGhhdCBhcmUgY29uc3RhbnQgb3ZlciB0aW1lLiBXZSBmdXJ0aGVyIGFzc3VtZSB0aGF0IHRoZSBkaXNjcmV0ZSAkSyQgcmVnaW1lcyBmb2xsb3cgYSBmaXJzdC1vcmRlciBNYXJrb3YgcHJvY2VzcyBsZWQgYnkgdHJhbnNpdGlvbiBwcm9iYWJpbGl0aWVzICRcYnAkLiBTaW5jZSB3ZSBkb24ndCBvYnNlcnZlIHRoZSBzdGF0ZXMgZGlyZWN0bHksIHdlIHNheSB0aGV5IGFyZSBoaWRkZW4gYW5kIHdlIHRoZW4gZXN0aW1hdGUgYSBwcm9iYWJpbGl0eSBkaXN0cmlidXRpb24gb3ZlciB0aGUgcG9zc2libGUgb3V0cHV0cy4gUmVtZW1iZXIgdGhhdCB0aGVyZSBpcyBvbmUgc2V0IG9mIHBhcmFtZXRlcnMgZm9yIHRoZSBHQVJDSCBlcXVhdGlvbiBpbiBlYWNoIHN0YXRlLg0KDQpMZXQgJHpfe3R9JCBiZSB0aGUgZGlzY3JldGUgY29tcG9uZW50LCBzdGF0ZSBvciByZWdpbWUgYXQgdGltZSBwb2ludCAkdCQuIFRoZSBzdGF0ZSBkeW5hbWljcyBhcmUgZ292ZXJuZWQgYnkgdGhlIHRyYW5zaXRpb24gbWF0cml4ICRcbWF0e1xQc2l9JCBvZiBzaXplICRLIFx0aW1lcyBLJCBhbmQgZWxlbWVudHMgJFxQc2koaSwgaikgPSBwKHpfe3R9ID0gaiBcIHwgXCB6X3t0LTF9ID0gaSkkIHdpdGggJDAgXGxlIFxQc2koaSwgaikgXGxlIDEkIGFuZCAkXHN1bV97an17XFBzaShpLCBqKX0gPSAxJC4gVGhlIG1hdHJpeCBoYXMgJEsoSy0xKSQgaW5kZXBlbmRlbnQgcGFyYW1ldGVycy4gVGhlIGluaXRpYWwgbGF0ZW50IG5vZGUgJHpfezF9JCBkb2Vzbid0IGhhdmUgYSBwYXJlbnQgbm9kZSBhbmQgaGFzIGEgbWFyZ2luYWwgZGlzdHJpYnV0aW9uICRwKHpfMSkkLg0KDQpUaGUgc3BlY2lmaWNhdGlvbiBvZiB0aGUgcHJvYmFiaWxpc3RpYyBtb2RlbCBpcyBjb21wbGV0ZWQgYnkgdGhlIGNvbmRpdGlvbmFsIGRpc3RyaWJ1dGlvbnMgb2YgdGhlIG9ic2VydmVkIHZhcmlhYmxlcyAkcChcZXBzaWxvbiB8IHpfdCwgXGJ0aGV0YSkkIHdoZXJlICRcYnRoZXRhJCBhcmUgYSBzZXQgb2YgcGFyYW1ldGVycyBmb3IgdGhpcyBkaXN0cmlidXRpb24uIFVzdWFsbHkga25vd24gYXMgdGhlIGVtaXNzaW9uIHByb2JhYmlsaXRpZXMgaW4gdGhlIG1hY2hpbmUgbGVhcm5pbmcgamFyZ29uLCBlYWNoIGVsZW1lbnQgb2YgdGhpcyAkSyQtc2l6ZWQgdmVjdG9yIHJlcHJlc2VudHMgdGhlIHByb2JhYmlsaXRpZXMgdGhhdCBhbnkgZ2l2ZW4gb2JzZXJ2YXRpb24gb2YgdGhlIHZvbGF0aWxpdHkgY29ycmVzcG9uZHMgdG8gdGhlICRLJCBwb3NzaWJsZSBzdGF0ZXMuDQoNCiMjIyBGb3J3YXJkIGFsZ29yaXRobQ0KDQpUaGUgZm9yd2FyZCBhbGdvcml0aG0gaXMgdXNlZCB0byBlc3RpbWF0ZSB0aGUgYmVsaWVmIHN0YXRlICRwKHpfe3R9IHwgXCBcSUlfe3R9KSQsIHRoZSBqb2ludCBwcm9iYWJpbGl0eSBvZiBhIHN0YXRlIGF0IGEgY2VydGFpbiB0aW1lIGFuZCB0aGUgaW5mb3JtYXRpb24gYXZhaWxhYmxlIHVwIHRoZSBtb21lbnQuIEVzdGltYXRpbmcgdGhlICRLJC1zaXplZCB2ZWN0b3IgaXMga25vd24gYXMgZmlsdGVyaW5nLiBXaGVuIHJ1biBhbHRvZ2V0aGVyIHdpdGggdGhlIGJhY2t3YXJkIGFsZ29yaXRobSwgeW91IGdldCB0aGUgc21vb3RoZWQgcHJvYmFiaWxpdHkgJHAoel97dH0gXCB8IFwgXElJX3tUfSkkLg0KDQpBIGZpbHRlciBpbmZlcnMgdGhlIGJlbGllZiBzdGF0ZSBiYXNlZCBvbiBhbGwgdGhlIGF2YWlsYWJsZSBpbmZvcm1hdGlvbiB1cCB0byB0aGF0IHBvaW50ICRwKHpfdCB8IFxtYXR7eX1fezE6dH0pJC4gSXQgYWNoaWV2ZXMgYmV0dGVyIG5vaXNlIHJlZHVjdGlvbiB0aGFuIHNpbXBseSBlc3RpbWF0aW5nIHRoZSBoaWRkZW4gc3RhdGUgYmFzZWQgb24gdGhlIGN1cnJlbnQgZXN0aW1hdGUuIFRoZSBmaWx0ZXJpbmcgcHJvY2VzcyBjYW4gYmUgcnVuIG9ubGluZSwgb3IgcmVjdXJzaXZlbHksIGFzIG5ldyBkYXRhIHN0cmVhbXMgaW4uDQoNCkZpbHRlcmVkIG1hZ2luYWxzIGNhbiBiZSBjb21wdXRlZCByZWN1cnNpdmVseSBieSBtZWFucyBvZiB0aGUgZm9yd2FyZCBhbGdvcml0aG0gQGJhdW0xOTY3aW5lcXVhbGl0eS4gTGV0ICRccHNpX3QoaikgPSBwKFxtYXR7eX1fdCB8IHpfdCA9IGopJCBiZSB0aGUgbG9jYWwgZXZpZGVuY2UgYXQgdGltZSAkdCQgYW5kICRcUHNpKGksIGopID0gcCh6X3QgPSBqIHwgel97dC0xfSA9IGkpJCBiZSB0aGUgdHJhbnNpdGlvbiBwcm9iYWJpbGl0eS4gRmlyc3QsIHRoZSBvbmUtc3RlcC1haGVhZCBwcmVkaWN0aXZlIGRlbnNpdHkgaXMgY29tcHV0ZWQNCg0KXFsNCnAoel90ID0gaiB8IFxtYXR7eX1fezE6dC0xfSkgPSBcc3VtX3tpfXtcUHNpKGksIGopIHAoel97dC0xfSA9IGkgfCBcbWF0e3l9X3sxOnQtMX0pfS4NClxdDQoNCkFjdGluZyBhcyBwcmlvciBpbmZvcm1hdGlvbiwgdGhpcyBxdWFudGl0eSBpcyB1cGRhdGVkIHdpdGggb2JzZXJ2ZWQgZGF0YSBhdCB0aGUgcG9pbnQgJHQkIHVzaW5nIEJheWVzIHJ1bGUsDQpcYmVnaW57YWxpZ24qfQ0KXGxhYmVse2VxOmZpbHRlcmVkLWJlbGllZl9zdGF0ZX0NClxhbHBoYV90KGopIA0KICAmIFx0cmlhbmdsZXEgIHAoel90ID0gaiB8IFxtYXR7eX1fezE6dH0pIFxcDQogICY9IHAoel90ID0gaiB8IFxtYXR7eX1fe3R9LCBcbWF0e3l9X3sxOnQtMX0pIFxcDQogICY9IFpfdF57LTF9IFxwc2lfdChqKSBwKHpfdCA9IGogfCBcbWF0e3l9X3sxOnQtMX0pIFxcDQogICY9IFpfdF57LTF9IFxwc2lfdChqKSBcYWxwaGFfe3QtMX0oaiksDQpcZW5ke2FsaWduKn0NCg0Kd2hlcmUgdGhlIG5vcm1hbGl6YXRpb24gY29uc3RhbnQgaXMgZ2l2ZW4gYnkNCg0KXFsNClpfdA0KICBcdHJpYW5nbGVxICBwKFxtYXR7eX1fdCB8IFxtYXR7eX1fezE6dC0xfSkNCiAgPSBcc3VtX3tsfXtwKFxtYXR7eX1fe3R9IHwgel90ID0gbCkgcCh6X3QgPSBsIHwgXG1hdHt5fV97MTp0LTF9KX0sDQogID0gXHN1bV97bH17cChcbWF0e3l9X3t0fSB8IHpfdCA9IGwpIFxhbHBoYV97dC0xfShsKX0uDQpcXQ0KDQpUaGlzIHByZWRpY3QtdXBkYXRlIGN5Y2xlIHJlc3VsdHMgaW4gdGhlIGZpbHRlcmVkIGJlbGllZiBzdGF0ZXMgYXQgcG9pbnQgJHQkLiBBcyB0aGlzIGFsZ29yaXRobSBvbmx5IHJlcXVpcmVzIHRoZSBldmFsdWF0aW9uIG9mIHRoZSBxdWFudGl0aWVzICRccHNpX3QoaikkIGZvciBlYWNoIHZhbHVlIG9mICR6X3QkIGZvciBldmVyeSAkdCQgYW5kIGZpeGVkICRcbWF0e3l9X3QkLCB0aGUgcG9zdGVyaW9yIGRpc3RyaWJ1dGlvbiBvZiB0aGUgbGF0ZW50IHN0YXRlcyBpcyBpbmRlcGVuZGVudCBvZiB0aGUgZm9ybSBvZiB0aGUgb2JzZXJ2YXRpb24gZGVuc2l0eSBvciBpbmRlZWQgb2Ygd2hldGhlciB0aGUgb2JzZXJ2ZWQgdmFyaWFibGVzIGFyZSBjb250aW51b3VzIG9yIGRpc2NyZXRlIEBqb3JkYW4yMDAzaW50cm9kdWN0aW9uLg0KDQpMZXQgJFxtYXR7XGFscGhhfV90JCBiZSBhICRLJC1zaXplZCB2ZWN0b3Igd2l0aCB0aGUgZmlsdGVyZWQgYmVsaWVmIHN0YXRlcyBhdCBwb2ludCAkdCQsICRcbWF0e1xwc2l9X3QoaikkIGJlIHRoZSAkSyQtc2l6ZWQgdmVjdG9yIG9mIGxvY2FsIGV2aWRlbmNlIGF0IHBvaW50ICR0JCwgJFxtYXR7XFBzaX0kIGJlIHRoZSB0cmFuc2l0aW9uIG1hdHJpeCBhbmQgJFxtYXR7dX0gXG9kb3QgXG1hdHt2fSQgaXMgdGhlIEhhZGFtYXJkIHByb2R1Y3QsIHJlcHJlc2VudGluZyBlbGVtZW50d2lzZSB2ZWN0b3IgbXVsdGlwbGljYXRpb24uIFRoZW4sIHRoZSBiYXllc2lhbiB1cGRhdGluZyBwcm9jZWR1cmUgY2FuIGJlIGV4cHJlc3NlZCBpbiBtYXRyaXggbm90aXRhdGlvbiBhcw0KDQpcWw0KXG1hdHtcYWxwaGF9X3QgXHByb3B0byBcbWF0e1xwc2l9X3QgXG9kb3QgKFxtYXR7XFBzaX1eVCBcbWF0e1xhbHBoYX1fe3QtMX0pLg0KXF0NCg0KSW4gYWRkaXRpb24gdG8gY29tcHV0aW5nIHRoZSBoaWRkZW4gc3RhdGVzLCB0aGUgYWxnb3JpdGhtIHlpZWxkcyB0aGUgbG9nIHByb2JhYmlsaXR5IG9mIHRoZSBldmlkZW5jZQ0KDQpcWw0KXGxvZyBwKFxtYXR7eX1fezE6VH0gfCBcbWF0e1x0aGV0YX0pID0gXHN1bV97dD0xfV57VH17cChcbWF0e3l9X3sxOnR9IHwgXG1hdHt5fV97MTp0LTF9KX0gPSBcc3VtX3t0PTF9XntUfXtcbG9nIFpfdH0uDQpcXQ0KDQpMb2cgZG9tYWluIHNob3VsZCBiZSBwcmVmZXJyZWQgdG8gYXZvaWQgbnVtZXJpY2FsIHVuZGVyZmxvdy4NCg0KXGJlZ2lue2FsZ29yaXRobX1bSF0NCiAgXERvbnRQcmludFNlbWljb2xvbg0KICBcU2V0S3dJbk91dHtJbnB1dH17aW5wdXR9DQogIFxTZXRLd0luT3V0e091dHB1dH17b3V0cHV0fQ0KICBcU2V0S3dQcm9ne0ZufXtkZWZ9e1xzdHJpbmc6fXt9DQogIA0KICBcSW5wdXR7VHJhbnNpdGlvbiBtYXRyaXggJFxtYXR7XFBzaX0kLCBsb2NhbCBldmlkZW5jZSB2ZWN0b3IgJFxtYXR7XHBzaX1fdCQgYW5kIGluaXRpYWwgc3RhdGUgZGlzdHJpYnV0aW9uICRcbWF0e1xwaX0kLn0NCiAgXE91dHB1dHtCZWxpZWYgc3RhdGUgdmVjdG9yICRcbWF0e1xhbHBoYX1fezE6VH0kIGFuZCBsb2cgcHJvYmFiaWxpdHkgb2YgdGhlIGV2aWRlbmNlICRcbG9nIHAoXG1hdHt5fV97MTpUfSA9IFxzdW1fe3R9IFxsb2cgWl90JCkufQ0KICBcQmxhbmtMaW5lDQoNCiAgXFNldEt3RnVuY3Rpb257RlVOQ25vcm1hbGl6ZX17bm9ybWFsaXplfQ0KICBcRm4oKXsNCiAgICBcRlVOQ25vcm1hbGl6ZXskXG1hdHt1fSR9DQogIH17DQogICAgICAkWiA9IFxzdW1faiA9IHVfaiRcOw0KICAgICAgJHZfaiA9IHVfaiAvIFokXDsNCiAgICAgIFxLd1JldHskXG1hdHt2fSQsIFp9DQogIH0NCg0KICBcQmxhbmtMaW5lDQoNCiAgJFxhbHBoYV8xLCBaXzEgPSBcRnVuY1N0eXtub3JtYWxpemV9KFxtYXR7XHBzaX1fMSBcb2RvdCBcbWF0e1xwaX0pJCBcOw0KICBcRm9ye3QgPSAyIFxLd1RvIFR9ew0KICAgICRcYWxwaGFfdCwgWl90ID0gXEZ1bmNTdHl7bm9ybWFsaXplfShcbWF0e1xwc2l9X3QgXG9kb3QgKFxtYXR7XFBzaX1eVCBcbWF0e1xhbHBoYX1fe3QtMX0pKSQgXDsNCiAgfQ0KICBcS3dSZXR7JFxtYXR7XGFscGhhfSQsICRcc3VtX3t0fSBcbG9nIFpfdCR9DQogIFxjYXB0aW9ue0ZvcndhcmQgQWxnb3JpdGhtfQ0KXGVuZHthbGdvcml0aG19DQoNCiMgQ2FzZSBTdHVkeQ0KTGV0J3Mgc2V0IG1hdGggYW5kIGNvbXB1dGF0aW9ucyBhc2lkZSBmb3IgYSB3aGlsZSBhbmQgZm9jdXMgb24gZmluYW5jZTogd2hhdCBjYW4gd2UgbWFrZSBvdXQgb2YgYSBtb2RlbCBsaWtlIHRoaXM/DQoNCiMjIyBQcmVhbWJsZQ0KQmVmb3JlIHdlIGdldCBtb3ZpbmcsIG1ha2Ugc3VyZSB5b3UndmUgZG93bmxvYWRlZCBhbGwgdGhlIGF1eGlsaWFyeSBmaWxlIHRvIHRoZSBzYW1lIGZvbGRlci4gV2UgZmlyc3QgY2hlY2sgYWxsIHRoZSByZXF1aXJlZCBwYWNrYWdlcyBmb3IgdGhpcyBub3RlYm9vayBhcmUgYXZhbGlhYmxlLg0KDQpgYGB7cn0NCnBhY2thZ2VzLnJlcSA8LSBjKCdxdWFudG1vZCcsICdydWdhcmNoJywgJ3JzdGFuJywgJ3NoaW55c3RhbicsICdsYXR0aWNlJywgJ2dyaWRFeHRyYScsICdncmlkQmFzZScsICdISCcpDQpwYWNrYWdlcy5taXMgPC0gcGFja2FnZXMucmVxWyEocGFja2FnZXMucmVxICVpbiUgcm93bmFtZXMoaW5zdGFsbGVkLnBhY2thZ2VzKCkpKV0NCg0KaWYgKGxlbmd0aChwYWNrYWdlcy5taXMpKSB7DQogIHN0b3AocGFzdGUoJ1BsZWFzZSwgZmlyc3QgaW5zdGFsbCB0aGUgZm9sbG93aW5nIHBhY2thZ2VzOicsIHBhY2thZ2VzLm1pcykpDQogICMgV2UgY291bGQgd3JpdGUgYSBzY3JpcHQgdG8gaW5zdGFsbCB0aGVtIGRpcmVjdGx5LCBidXQgdGhpcyBtYXkgbWVzcyB1cCBvdGhlciBjb2RlIG9mIHlvdXJzDQp9DQpgYGANCg0KIyMjIEZldGNoaW5nIHRoZSBEYXRhDQpXZSBjaG9vc2UgJE4gPSA1JCBzZXJpZXMgZnJvbSAyMDExLTAxLTAxIHRvIDIwMTYtMTItMzEgKCRUID0gMTUwMiQpOiAqKl5HU1BDKiosICoqRioqLCAqKkdNKiosICoqVEhPKiogYW5kICoqQUlSKiouIFRoZSBkYXRhIGlzIGRvd25sb2FkZWQgYW5kIHByZS1wcm9jZXNzZWQgdXNpbmcgcXVhbnRtb2QgW0ByeWFuMjAxNnF1YW50bW9kXS4NCg0KYGBge3IgbWVzc2FnZSA9IEZBTFNFLCB3YXJuaW5nID0gRkFMU0V9DQpsaWJyYXJ5KHF1YW50bW9kKQ0Kc3ltcyA8LSBjKCdeR1NQQycsICdGJywgJ0dNJywgJ1RITycsICdBSVInKQ0KDQp1c2VjYWNoZSA9IFRSVUUNCmNhY2hlLmZpbGVuYW1lIDwtICdkYXRhL3N5bXNyZXQuUkRTJw0KaWYgKHVzZWNhY2hlICYmIGZpbGUuZXhpc3RzKGNhY2hlLmZpbGVuYW1lKSkgew0KICB5X3QgPC0gcmVhZFJEUyhjYWNoZS5maWxlbmFtZSkNCn0gZWxzZSB7DQogIHlfdCA9IGFzLm1hdHJpeCgNCiAgICBkby5jYWxsKGNiaW5kLCBsYXBwbHkoc3ltcywgZnVuY3Rpb24ocykgew0KICAgICAgcCA8LSBnZXRTeW1ib2xzKHMsIHNyYyA9ICJ5YWhvbyIsIGZyb20gPSAiMjAxMS0wMS0wMSIsIHRvID0gIjIwMTYtMTItMzEiLCBhdXRvLmFzc2lnbiA9IEZBTFNFKQ0KICAgICAgciA8LSBwZXJpb2RSZXR1cm4ocCwgcGVyaW9kID0gJ2RhaWx5JywgdHlwZSA9ICdsb2cnKQ0KICAgICAgY29sbmFtZXMocikgPC0gcw0KICAgICAgciAqIDEwMA0KICAgIH0pKSkNCn0NCmBgYA0KDQojIyMgSW5mZXJlbmNlDQpUaGUgKHZlcnkpICoqbmFpdmUqKiBpbXBsZW1lbnRhdGlvbiBvZiB0aGUgYWxnb3JpdGhtIGluIFN0YW4gaXMgb25seSBtZWFudCBmb3IgaWxsdXN0cmF0aW9uLiBBIGZldyBnb29kIHByYWN0aWNlcyB3ZXJlIG5lZ2xlY3RlZCwgY29udmVyZ2VuY2UgaXMgbm90IGd1YXJhbnRlZWQsIHRoZXJlIGlzIG11Y2ggcm9vbSBsZWZ0IGZvciBvcHRpbWl6YXRpb24gYW5kIGZpdHRpbmcgKk4qIGRpZmZlcmVudCBpbmRlcGVuZGVudCBtb2RlbHMgaXMgcHJvYmFibHkgbm90IGEgcmVhc29uYWJsZSBjaG9pY2UgZm9yIHByb2R1Y3Rpb24gc2FtcGxlci4gVGhlIG1haW4gdGFrZWF3YXkgb2YgdGhpcyBwcmVzZW50YXRpb24gaXMgdGhlIGlkZWFzIGJlaGluZCB0aGUgY29kZSBidXQgbm90IHRoZSBjb2RlIGl0c2VsZi4NCg0KV2UnbGwgbG9hZCBTdGFuIFstQHN0YW4yMDE2bWFudWFsXSBhbmQgcnVuIHRoZSBtb2RlbCBmb3IgJEsgPSAyJCBzdGF0ZXMuIFNpbmNlIHRoZSBzYW1wbGVyIG1heSB0YWtlIGEgZmV3IG1pbnV0ZXMsIEkndmUgYnVpbHQgYSB2ZXJ5IGJhc2ljIGNhY2hpbmcgZmVhdHVyZS4NCg0KYGBge3IgbWVzc2FnZSA9IEZBTFNFfQ0KbGlicmFyeShyc3RhbikNCnJzdGFuX29wdGlvbnMoYXV0b193cml0ZSA9IFRSVUUpICAjIFdyaXRlcyBkb3duIHRoZSBjb21waWxlZCBzYW1wbGVyDQpvcHRpb25zKG1jLmNvcmVzID0gcGFyYWxsZWw6OmRldGVjdENvcmVzKCkpICMgVXNlIGFsbCBhdmFpbGFibGUgY29yZXMNCg0KSyA9IDIgIyBOdW1iZXIgb2Ygc3RhdGVzDQpibW9kZWwgPSAnc3Rhbi9obW1nYXJjaC5zdGFuJyAjIE5hbWUgb2YgdGhlIG1vZGVsIGZpbGUNCnN0YW5kYXRhID0gbGlzdCgNCiAgTiA9IG5jb2woeV90KSwNCiAgVCA9IG5yb3coeV90KSwNCiAgSyA9IEssDQogIHkgPSB0KHlfdCkNCikNCg0KdXNlY2FjaGUgPSBUUlVFDQpjYWNoZS5maWxlbmFtZSA8LSBwYXN0ZTAoJ3N0YW4vaG1tZ2FyY2gtY2FjaGUucmRzJykNCmlmICh1c2VjYWNoZSAmJiBmaWxlLmV4aXN0cyhjYWNoZS5maWxlbmFtZSkpIHsNCiAgc3Rhbi5maXQgPC0gcmVhZFJEUyhjYWNoZS5maWxlbmFtZSkNCn0gZWxzZSB7DQogIHN0YW4uZml0IDwtIHN0YW4oZmlsZSA9IGJtb2RlbCwNCiAgICAgICAgICAgICAgICAgICBtb2RlbF9uYW1lID0gIkJheWVzaWFuIEhpZXJhcmNoaWNhbCBNaXh0dXJlIEdBUkNIIiwNCiAgICAgICAgICAgICAgICAgICBkYXRhID0gc3RhbmRhdGEsIHZlcmJvc2UgPSBULA0KICAgICAgICAgICAgICAgICAgIGl0ZXIgPSAyMDAsIHdhcm11cCA9IDEwMCwgdGhpbiA9IDEsIGNoYWlucyA9IDQsIGNvcmVzID0gNCwNCiAgICAgICAgICAgICAgICAgICBjb250cm9sID0gbGlzdChhZGFwdF9kZWx0YSA9IDAuODApKQ0KICANCiAgc2F2ZVJEUyhzdGFuLmZpdCwgZmlsZSA9IGNhY2hlLmZpbGVuYW1lKQ0KfQ0KYGBgDQoNCldlJ2xsIGFsc28gZml0IGEgc2luZ2xlIHJlZ2ltZSBHQVJDSCBtb2RlbCB3aXRoIHJ1Z2FyY2ggW0BydWdhcmNoMjAxNV0uICpTaWRlbm90ZTogSSd2ZSB1c2VkIHJ1Z2FyY2ggY29uc2lkZXJhYmx5IGFuZCBpdCBwcm92ZWQgdG8gYmUgdmVyeSByZWxpYWJsZSwgaXQncyBhIGZpbmUgd29yayBvZiBzb2Z0d2FyZSBlbmdpbmVlcmluZyouDQoNCmBgYHtyIG1lc3NhZ2UgPSBGQUxTRX0NCmxpYnJhcnkocnVnYXJjaCkNClNSIDwtIGxhcHBseSgxOm5jb2woeV90KSwgZnVuY3Rpb24obikgew0KICBtbGUuc3BlY1NSIDwtIHVnYXJjaHNwZWMoDQogICAgdmFyaWFuY2UubW9kZWwgPSBsaXN0KG1vZGVsID0gInNHQVJDSCIsIGdhcmNoT3JkZXIgPSBjKDEsIDEpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBzdWJtb2RlbCA9IE5VTEwsIGV4dGVybmFsLnJlZ3Jlc3NvcnMgPSBOVUxMLCB2YXJpYW5jZS50YXJnZXRpbmcgPSBGQUxTRSksDQogICAgbWVhbi5tb2RlbCA9IGxpc3QoYXJtYU9yZGVyID0gYygwLCAwKSwgaW5jbHVkZS5tZWFuID0gRkFMU0UsIGFyY2htID0gRkFMU0UpLA0KICAgIGRpc3RyaWJ1dGlvbi5tb2RlbCA9ICdub3JtJw0KICApDQogIG1sZS5maXRTUiAgPC0gdWdhcmNoZml0KG1sZS5zcGVjU1IsIHlfdFssIG5dKQ0KICBsaXN0KGFzLm51bWVyaWMoc2lnbWEobWxlLmZpdFNSKSksIHVuY3ZhcmlhbmNlKG1sZS5maXRTUikpDQp9KQ0KYGBgDQoNCiMjIyBQbG90cw0KV2UnbGwgbWFrZSBleHRlbnNpdmUgdXNlIG9mIHBsb3RzLCBtYWlubHkgYmFzZWQgb24gTGF0dGljZSBbQHNhcmthcjIwMDhsYXR0aWNlXS4gRm9yIGJldHRlciBvcmdhbml6YXRpb24sIHBsb3QgbG9naWMgaXMgY29uc29saWRhdGVkIGludG8gYW4gW2F1eGlsaWFyeSBzY3JpcHRdKFIvcGxvdHMuUikuDQoNCmBgYHtyIG1lc3NhZ2UgPSBGQUxTRX0NCnNvdXJjZSgnUi9wbG90cy5SJykNCmBgYA0KDQojIyMgRmluZGluZ3MNCldlIGZpbHRlciB0aGUgZGFpbHkgbG9nIHJldHVybnMgdGhyb3VnaCBhIHNpbmdsZSByZWdpbWUgJEdBUkNIKDEsIDEpJCBtb2RlbCB3aXRoIEdhdXNzaWFuIGRlbnNpdHkuDQoNCmBgYHtyLCBmaWcud2lkdGggPSAxNSwgZmlnLmhlaWdodCA9IDIyLCBmaWcua2VlcCA9ICdsYXN0J30NCiAgcSA8LSBxdWV1ZVtbMV1dDQogIHRzY3NwbG90KHEkZ2V0TWF0KCksIHEkZ2V0TWFpbigpKQ0KYGBgDQoNCldlIGZpcnN0IG9ic2VydmUgdGhhdCB2b2xhdGlsaXR5IGhhcyBwb3NpdGl2ZSBsaW5lYXIgY29ycmVsYXRpb24gYWNyb3NzIGFzc2V0cy4gVGhpcyBpcyBwcmV0dHkgc2VsZi1leHBsYW5hdG9yeTogYWx0aG91Z2ggZWFjaCBhc3NldCBoYXMgaXRzIG93biB2b2xhdGlsaXR5IGxldmVsIGFuZCBkeW5hbWljcywgdm9sYXRpbGl0eSBhY3Jvc3Mgc3RvY2tzIHRlbmQgdG8gaW5jcmVhc2Ugb3IgZGVjcmVhc2UgYXQgdGhlIHNhbWUgdGltZS4gTW9yZW92ZXIsIHRoZSBzdHJlbmd0aCBvZiB0aGUgb2JzZXJ2ZWQgcmVsYXRpb25zaGlwIGRlcGVuZHMgb24gdGhlIHBhaXJzIG9mIGFzc2V0cy4gVGhlIHZvbGF0aWxpdHkgaW4gdGhlIGxvZyByZXR1cm4gb2YgKipGKiogYW5kICoqR00qKiBzaG93cyBhIHN0cm9uZ2VyIHBvc2l0aXZlIGNvcnJlbGF0aW9uIHRoYW4sIHNheSwgKipGKiogYW5kICoqQUlSKiouIFN0cm9uZ2VyIGNvcnJlbGF0aW9ucyBhcmUgZXhwZWN0ZWQgYW1vbmcgc3RvY2tzIHdpdGggc2ltaWxhciBidXNpbmVzcyBtb2RlbCwgaW5kdXN0cnkgb3IgZXhwb3N1cmUgdG8gbWFjcm9lY29ub21pYyBmYWN0b3JzLiBBc3NldHMgcmVhY3QgZGlmZmVyZW50bHkgdG8gbmV3cy4gSXQgaXMgd2VsbCBleHBlY3RlZCB0aGF0IGJhZCBuZXdzIGFib3V0IGluIHRoZSBjYXIgbWFudWZhY3R1cmluZyBpbmR1c3RyeSB3aWxsIGltcGFjdCAqKkYqKiBhbmQgKipHTSoqIGluIGEgc2ltaWxhciB3YXkgYW5kIGhpdCAqKkFJUioqIG9ubHkgaW5kaXJlY3RseS4NCg0KRnJvbSB0aGUgZmlndXJlIGFib3ZlIGl0J3MgZXZpZGVudCB0aGF0IHRoaXMgYW5hbHlzaXMgaXMganVzdCBhbiBhcHByb3hpbWF0aW9uLiBGaXJzdCBvZiBhbGwsIGRhdGEgcG9pbnRzIGZvcm0gYSBmdW5uZWw6IHRoZSB2b2xhdGlsaXR5IHNwcmVhZCBhY3Jvc3MgYXNzZXRzIGlzIGxhcmdlciB3aGVuIHZvbGF0aWxpdHkgaW5jcmVhc2VzLiBTZWNvbmQsIHRoZXJlIGFyZSBtYW55IGV4dHJlbWUgdmFsdWVzLiBJdCBpcyB2ZXJ5IGltcG9ydGFudCB0aGF0IGFueSBhbmFseXNpcyBpcyBjaGVja2VkIGZvciByb2J1c3RuZXNzLiBBIGZpcnN0IHRob3VnaHQsIGxvZ2FyaXRobWljIHRyYW5zZm9ybWF0aW9uIHdvdWxkIGFsbG93IGZvciBtdWx0aXBsaWNhdGl2ZSBzcHJlYWRzLCBzdGFiaWxpemUgdmFyaWFuY2UgYW5kIHBhcnRpYWxseSB0YW1lIGV4dHJlbWUgdmFsdWVzIGF0IHRoZSBzYW1lIHRpbWUuIFRoaXMgd291bGQgYWxzbyBtYXAgYSBwb3NpdGl2ZSBib3VuZGVkIHZhcmlhYmxlIHRvIFJlYWxzLCB3aGljaCBtYXkgb3Igbm90IGJlIG9mIGludGVyZXN0IGZvciBzb21lIHB1cnBvc2VzIChmb3IgZXhhbXBsZSBzYW1wbGluZyBhbmQgcHJpb3JzKS4NCg0KU28gZmFyIHdlJ3ZlIG9ubHkgc2VlbiB0aGF0IHZvbGF0aWxpdHkgaXMgY29ycmVsYXRlZCBhY3Jvc3MgYXNzZXRzLiBZb3UgbWF5IHNheSB0aGlzIHdhcyBwcmV0dHkgb2J2aW91cyBhbmQgeW91J3JlIG5vdCBzYXRpc2ZpZWQsIHNvIHdlJ2xsIGtlZXAgZGlnZ2luZy4gV2UgYWNjZXB0IHRoZSBpZGVhIHRoYXQgbWFya2V0IGhhcyB0d28gc3RhdGVzIGFuZCB3ZSBmaWx0ZXIgdGhlIHNhbWUgc2VyaWVzIHRocm91Z2ggYSBITU0gQ29uZGl0aW9uYWwgSGV0ZXJvc2tlZGFzdGljaXR5IE1vZGVsLiBOb3csICoqRioqIGxvb2tzIGFzIGZvbGxvd3M6DQoNCmBgYHtyLCBmaWcud2lkdGggPSAxNSwgZmlnLmhlaWdodCA9IDYsIGZpZy5rZWVwID0gJ2xhc3QnfQ0KICBuIDwtIDIgIyBGb3JkDQogIHEgPC0gcXVldWVbWzhdXQ0KdHNjcHBsb3QocSRnZXRNYXQoKSwgcSRnZXRNYWluKCkpDQpgYGANCg0KV2l0aCB1bmNvbmRpdGlvbmFsIHZvbGF0aWxpdGllcyBvZiBgciBzcHJpbnRmKCclMC4yZicsIGNvbE1lZGlhbnMoZXh0cmFjdChzdGFuLmZpdCwgcGFycyA9ICdzaWdtYScpW1sxXV1bLCBuLCAxXSkpYCBhbmQgYHIgc3ByaW50ZignJTAuMmYnLCBjb2xNZWRpYW5zKGV4dHJhY3Qoc3Rhbi5maXQsIHBhcnMgPSAnc2lnbWEnKVtbMV1dWywgbiwgMl0pKWAsIHRoZSBzdGF0ZXMgY2FuIGJlIGlkZW50aWZpZWQgYXMgbG93IGFuZCBoaWdoIHZvbGF0aWxpdHkgZGF5cyByZXNwZWN0aXZlbHkuIFdlIGFsc28gc2VlIHRoYXQgdGhlIG1hcmtldCBzcGVuZHMgbW9yZSB0aW1lIGluIHRoZSBsb3cgdm9sYXRpbGl0eSBzdGF0ZS4NCg0KYGBge3IsIGZpZy53aWR0aCA9IDE1LCBmaWcuaGVpZ2h0ID0gNiwgZmlnLmtlZXAgPSAnbGFzdCd9DQogIHEgPC0gcXVldWVbWzldXQ0KICBjc3RzY3BwbG90KHEkZ2V0TWF0KCksIHEkZ2V0TWFpbigpKQ0KYGBgDQoNCkFub3RoZXIgdGhyZWUgaW50ZXJlc3RpbmcgdGhpbmdzIHRvIG5vdGUuIEZpcnN0LCB3ZSBvYnNlcnZlIHRoYXQgdGhlIGZpcnN0IHN0YXRlIGlzIG1vcmUgcHJvYmFibGUgd2hlbiB0aGUgbG9nIHJldHVybnMgYXJlIGNsb3NlIHRvIHplcm8uIFRoaXMgaXMgZXhhY3RseSB3aGF0IHdlIGV4cGVjdGVkIHdoZW4gd2UgbmFtZWQgaXQgKnRoZSBsb3cgdm9sYXRpbGl0eSBzdGF0ZSouIFNlY29uZCwgdGhlIGZpbHRlcmVkIHByb2JhYmlsaXRpZXMgYXJlIGF1dG9jb3JyZWxhdGVkLiBUaGlzIGhpbnRzIHRoYXQgc29tZSBraW5kIG9mIG1lbW9yeSBzdHJ1Y3R1cmUgbWF5IGhlbHAgaW4gcHJlZGljdGlvbiwga25vd2luZyBvbiB3aGljaCBzdGF0ZSB3ZSBjdXJyZW50bHkgYXJlIGRlY3JlYXNlcyB1bmNlcnRhaW50eSBhYm91dCB0b21vcnJvdy4gRmluYWxseSwgdGhlIHNxdWFyZSBvZiB0aGUgdm9sYXRpbGl0eSAodGhlIHZhcmlhbmNlKSBlc3RpbWF0ZWQgZm9yIGVhY2ggc3RhdGUgYXJlIGxpbmVhcmx5IHJlbGF0ZWQgd2l0aCBpbnRlcmNlcHQgYW5kIHNsb3BlIGRpZmZlcmVudCBmcm9tIHplcm8uIFRoZXNlIGZlYXR1cmVzIHNob3VsZCBiZSB0ZXN0ZWQgZm9yIHJlYXNvbmFiaWxpdHkgaW4geW91ciBvd24gdXNlIGNhc2UuDQoNCldlIGVuZCBzaG93aW5nIHRoYXQgYmVsaWVmIHN0YXRlIGFjcm9zcyBhc3NldHMgYXJlIGNvcnJlbGF0ZWQuDQoNCmBgYHtyLCBmaWcud2lkdGggPSAxNSwgZmlnLmhlaWdodCA9IDIyLCBmaWcua2VlcCA9ICdsYXN0J30NCiAgcSA8LSBxdWV1ZVtbNV1dDQogIHRzY3NwbG90KHEkZ2V0TWF0KCksIHEkZ2V0TWFpbigpKQ0KYGBgDQpXZSBub3RlZCB0aGF0IHN0YXRlcyBhbmQgbG9nIHJldHVybnMgYXJlIHJlbGF0ZWQ6IGNyb3NzIGNvcnJlbGF0aW9uIGluIGxvZyByZXR1cm5zIG1heSBleHBsYWluIGNvcnJlbGF0aW9uIGFtb25nIHN0YXRlcy4gV2UgYWxzbyBub3RlZCB0aGF0IHByZWRpY3RhYmlsaXR5IGNvdWxkIGJlIGltcHJvdmVkIHByb2ZpdGluZyBmcm9tIHRoZSBtZW1vcnkgc3RydWN0dXJlIGluIHRoZSBzdGF0ZXMuIE9uIHRoZSB3aG9sZSwgdGhlc2UgZmVhdHVyZSBtYXkgYmUgb2YgdmFsdWUgZm9yIHRyYWRpbmcgc3RyYXRlZ2llcyBvciByaXNrIG1vZGVscy4NCg0KIyBEaXNjdXNzaW9uICYgZnVydGhlciByZXNlYXJjaA0KSXQncyBldmlkZW50IHRoYXQgc3RhdGVzIGFyZSBzaGFyZWQgYW1vbmcgYXNzZXRzLiBBZ2FpbiwgdGhlIHN0cmVuZ3RoIG9mIHRoZSByZWxhdGlvbnNoaXAgZGVwZW5kcyBvbiBlYWNoIGFzc2V0LiBXZSBtYXkgZXZlbiBoeXBvdGhlc2l6ZSB0aGF0IHN0YXRlcyBmb2xsb3cgYSBoaWVyYXJjaGljYWwgc3RydWN0dXJlOiBmb3IgZXhhbXBsZSwgdGhlIHJpc2sgc3RhdGUgb2YgYSBnbG9iYWwgcG9ydGZvbGlvIG1heSBiZSBicm9rZW4gZG93biBpbnRvIENvdW50cnkgKyBJbmR1c3RyeSArIFN0b2NrIEluZGl2aWR1YWwuIFRoZSBjaGFsbGVuZ2UgbGllcyBpbiBmaW5kaW5nIGEgd2F5IHRvIGZpbHRlciB0aGUgZW1pc3Npb24gcHJvYmFiaWxpdGllcyBjb25zaWRlcmluZyB0aGF0IHN0YXRlcyBhcmUgaGllcmFyY2hpY2FsIHVzaW5nIGEgSGllcmFyY2hpY2FsIEhpZGRlbiBNYXJrb3YgTW9kZWwuIFRoaXMgaXMgY2xlYXJseSBhIHBlcmZlY3Qgc2V0dGluZyBmb3IgYmF5ZXNpYW4gZXN0aW1hdGlvbiB3aGVyZSBwYXJhbWV0ZXIgaGllcmFyY2h5IGlzIG5hdHVyYWxseSBtb2RlbGxlZC4gVGhpcywgSSBiZWxpZXZlLCBpcyB0aGUgbW9zdCBwcm9taXNpbmcgcGF0aCBmb3IgdGhlIGFuYWx5c2lzLg0KDQojIFJlZmVyZW5jZXMNCg==