The Portfolio Problem
The decision-making problem is denoted by a decision vector \(\mathbf{d}\) and future realization of the underlying assets denoted by \(\mathbf{y}\). The former denotes the portfolio weights allocated to risky \(N\) assets, whereas the latter denotes the asset returns. The two vectors determine the wealth/reward of the investor, which is uncertain. It is commonly assumed that the parameters of the \(\mathbf{y}\) are known denoted by \(\boldsymbol{\theta}\), such that the density of \(\mathbf{y}\) is known. Nonetheless, in practice, these parameters are unknown, and their estimation is subjected to uncertainty. As a result, the decision process takes into account the conditional distribution of \(\mathbf{y}\mid\boldsymbol{\theta}\). In this regard, if we know the conditional distribution, then the decision-making process boils down to maximizing the following conditional expected utility: \[
\underset{\mathbf{d}}{\text{max}}\,\mathbb{E}\left[U(\mathbf{y}^{\top}\mathbf{d})\mid\boldsymbol{\theta}\right]
\]
The standard solution to the optimization problem replaces the parameters with the sample estimates and solves for optimal portfolio. This is known as the plug-in approach. However, it is well-recognized that such practice is associated with estimation risk and poor out-of-sample portfolio performance. Additionally, the derivation of this portfolio is inconsistent with utility theory (see, e.g., Klein and Bawa (1976)).
Uncertainty about \(\boldsymbol{\theta}\) can be taken into account employing Bayes’ decision criterion. According to the Bayes’ rule, we know that the posterior is proportional to the product between the likelihood function and the prior, i.e., \[\begin{equation}
p(\boldsymbol{\theta}\mid\mathbf{X},\boldsymbol{\theta}_{0})\propto p(\mathbf{X}\mid\boldsymbol{\theta})\pi(\boldsymbol{\theta})
\end{equation}\] where \(\mathbf{X}\) and \(\pi(\boldsymbol{\theta})\) denote, respectively, the sample-related information and the prior distribution. Here, \(\boldsymbol{\theta}_{0}\) denotes the beliefs about the unknown parameters.
Optimal Portfolio
Under the above assumptions, the posterior distribution \(p(\boldsymbol{\theta}\mid\mathbf{X},\boldsymbol{\theta}_{0})\) is known. We can determine the expected utility and, hence, the optimal portfolio accordingly. Under CARA utility, we have \[\begin{equation}
U(w)=-\frac{1}{\gamma}e^{-\gamma w}
\end{equation}\] with \(w=\mathbf{d}^{\top}\mathbf{y}\) denote the terminal wealth for allocation \(\mathbf{d}\). According to the tower property, we know that \[\begin{equation}
\mathbb{E}[U(w)]=\mathbb{E}_{\boldsymbol{\theta}}\left[\mathbb{E}[U(w)\mid\boldsymbol{\theta}]\right]
\end{equation}\] where \(\mathbb{E}_{\boldsymbol{\theta}}\) denotes the expectation condition on observing data \(\mathbf{X}\) and prior \(\boldsymbol{\theta}_{0}\).
If the parameters are known, then from the moment generating function of a Gaussian variable, we have \[\begin{equation}
\mathbb{E}[U(w)\mid\boldsymbol{\theta}]=-\frac{1}{\gamma}\mathbb{E}[e^{-\gamma\mathbf{d}^{\top}\mathbf{y}}\mid\boldsymbol{\theta}]=-\frac{1}{\gamma}e^{-\gamma\mathbf{d}^{\top}\boldsymbol{\mu}+\frac{\gamma^{2}}{2}\mathbf{d}^{\top}\boldsymbol{\Sigma}\mathbf{d}}
\end{equation}\] Finally, the expected utility function depends on finding the expectation of \[\begin{equation}
\mathbb{E}[U(w)]=-\frac{1}{\gamma}\mathbb{E}_{\boldsymbol{\theta}}\left[e^{-\gamma\mathbf{d}^{\top}\boldsymbol{\mu}+\frac{\gamma^{2}}{2}\mathbf{d}^{\top}\boldsymbol{\Sigma}\mathbf{d}}\right]
\end{equation}\] which requires knowing the posterior distribution \(p(\boldsymbol{\theta}\mid\mathbf{X},\boldsymbol{\theta}_{0})\). Alternatively, we can consider the predictive density function of \(\mathbf{y}\). Under the above assumptions, \(\mathbf{y}\mid\mathbf{X},\boldsymbol{\theta}_{0}\) follows a multivariate student-t distribution. Finding the expectation of which can be obtained numerically.
Known \(\Sigma\)
While a numerical solution provides a more accurate approximation, it comes at the cost of intuition. To gain further insights about the updating process, we make one simplification. We assume that the decision-maker knows the covariance matrix without any uncertainty. In this regards, we have \(\boldsymbol{\Sigma}=\boldsymbol{\Sigma}_{0}\). Therefore, the expected utility simplifies to \[\begin{equation}
\mathbb{E}[U(w)]=-\frac{1}{\gamma}e^{\frac{\gamma^{2}}{2}\mathbf{d}^{\top}\boldsymbol{\Sigma}\mathbf{d}}\mathbb{E}_{\boldsymbol{\theta}}\left[e^{-\gamma\mathbf{d}^{\top}\boldsymbol{\mu}}\right].
\end{equation}\]
In this case, we know that \[\begin{equation}
\boldsymbol{\mu}\mid\mathbf{X},\boldsymbol{\mu}_{0}\sim N\left(\boldsymbol{\Sigma}_{1}\boldsymbol{\Sigma}_{0}^{-1}\boldsymbol{\mu}_{0}+\boldsymbol{\Sigma}_{1}T\boldsymbol{\Sigma}_{0}^{-1}\bar{\mathbf{y}},\boldsymbol{\Sigma}_{1}\right)
\end{equation}\] with \[\begin{equation}
\boldsymbol{\Sigma}_{1}^{-1}=\boldsymbol{\Sigma}_{0}^{-1}+T\boldsymbol{\Sigma}^{-1}
\end{equation}\] Since \(\boldsymbol{\Sigma}=\boldsymbol{\Sigma}_{0}\), then \[\begin{equation}
\boldsymbol{\Sigma}_{1}=\frac{1}{1+T}\boldsymbol{\Sigma}_{0}
\end{equation}\] and \[\begin{equation}
\boldsymbol{\Sigma}_{1}\boldsymbol{\Sigma}_{0}^{-1}\boldsymbol{\mu}_{0}+\boldsymbol{\Sigma}_{1}T\boldsymbol{\Sigma}_{0}^{-1}\bar{\mathbf{y}}=\frac{1}{T}\boldsymbol{\mu}_{0}+\frac{T}{1+T}\bar{\mathbf{y}}
\end{equation}\] with \(T\) denoting the sample size. As a result, we have \[\begin{equation}
\boldsymbol{\mu}\mid\mathbf{X},\boldsymbol{\mu}_{0}\sim N\left(\alpha\boldsymbol{\mu}_{0}+(1-\alpha)\bar{\mathbf{y}},\frac{1}{1+T}\boldsymbol{\Sigma}_{0}\right)
\end{equation}\] with
\[\begin{equation}
\alpha=\frac{1}{1+T}\in(0,1)\:\text{for }T>0.
\end{equation}\] The expected utility is given by \[\begin{equation}
\mathbb{E}[U(w)]=-\frac{1}{\gamma}\text{exp}\left(-\gamma\mathbf{d}^{\top}\left[\alpha\boldsymbol{\mu}_{0}+(1-\alpha)\bar{\mathbf{y}}\right]+(1+\alpha)\frac{\gamma^{2}}{2}\mathbf{d}^{\top}\boldsymbol{\Sigma}_{0}\mathbf{d}\right).
\end{equation}\] Applying a positive transformation on the expected utility, its optimization is consistent with the following mean-variance (MV) preference: \[\begin{equation}
\mathbf{d}^{\top}\left[\alpha\boldsymbol{\mu}_{0}+(1-\alpha)\bar{\mathbf{y}}\right]-\frac{\gamma}{2}(1+\alpha)\mathbf{d}^{\top}\boldsymbol{\Sigma}_{0}\mathbf{d}
\end{equation}\]
Consider the case of full information in which \(T\rightarrow\infty\) such that \(\alpha\rightarrow0\). Under this extreme scenario, it is clear that the Bayesian portfolio problem converges to the conventional MV optimization. For a finite sample size, \(\alpha\) denotes the ambiguity about the mean return. The larger it is, the more variance the decision market assigns to the portfolio variance and the greater weight is attributed to the prior.
Under the constraint that \(\mathbf{d}^{\top}\mathbf{1}=1\), the optimal portfolio is given by \[\begin{equation}
\mathbf{d}^{*}=\mathbf{d}_{g}+\frac{1}{1+\alpha}\mathbf{B}[\alpha\boldsymbol{\mu}_{0}+(1-\alpha)\bar{\mathbf{y}}]
\end{equation}\] with \[\begin{equation}
\mathbf{d}_{g}=\frac{\boldsymbol{\Sigma}_{0}^{-1}\mathbf{1}}{\mathbf{1}^{\top}\boldsymbol{\Sigma}_{0}^{-1}\mathbf{1}}
\end{equation}\] denoting the global minimum variance (GMV) portfolio and \[\begin{equation}
\mathbf{B}=\boldsymbol{\Sigma}_{0}^{-1}\left[\mathbf{I}-\mathbf{1}\mathbf{d}_{g}^{\top}\right]
\end{equation}\] is a centering matrix around the GMV portfolio (see, e.g., Simaan et al. (2018)).
It is clear that the MV optimal portfolio consists of three funds. The first is the GMV. The second (third) is the arbitrage portfolio that depends on the prior (sample) mean return: \[\begin{equation}
\mathbf{d}^{*}=\mathbf{d}_{g}+\frac{\alpha}{1+\alpha}\mathbf{B}\boldsymbol{\mu}_{0}+\frac{1-\alpha}{1+\alpha}\mathbf{B}\bar{\mathbf{y}}.
\end{equation}\] To simplify, let \(\mathbf{B}_{\alpha}=(1+\alpha)^{-1}\mathbf{B}\), such that
\[\begin{equation}
\mathbf{d}^{*}=\mathbf{d}_{g}+\alpha\mathbf{B}_{\alpha}\boldsymbol{\mu}_{0}+(1-\alpha)\mathbf{B}_{\alpha}\bar{\mathbf{y}}.
\end{equation}\]
We observe that the Bayesian MV portfolio is a convex combination between two portfolios. Specifically, for \(\alpha\in(0,1)\) it follows that \[\begin{equation}
\mathbf{d}^{*}=\alpha\mathbf{d}^{*}(\boldsymbol{\mu}_{0})+\left[1-\alpha\right]\mathbf{d}^{*}(\bar{\mathbf{y}})
\end{equation}\] with
\[\begin{equation}
\mathbf{d}^{*}(\mathbf{u})=\mathbf{d}_{g}+\mathbf{B}_{\alpha}\mathbf{u},
\end{equation}\] denoting a linear function of vector \(\mathbf{u}\).
Empirical Example
Let us start with a simple numerical example. To do so, I will be working with two ETFs. The first one is the SPY ETF denoting the stock market portfolio, whereas the other is the IEF denoting the return on 7-10 years Treasury bonds.
library(quantmod)
library(lubridate)
v <- c("SPY","IEF")
t1 <- "1996-01-01" # the starting date
P.list <- lapply(v,function(x) get(getSymbols(x,from = t1)) )
P <- lapply(P.list,function(x) x[,grep("Adjusted",names(x))])
P <- Reduce(function(...) merge(...),P )
names(P) <- v
P <- apply.monthly(P,function(x) x[nrow(x),] )
R <- na.omit(P/lag(P)-1)
R <- R["/2020-12-31",]
We consider the returns on both ETFs up to late 2020. Note that the inception of the IEF took place during the second half of 2002. For this reason, the data dates between
range(date(R))
[1] "2002-08-30" "2020-12-31"
The key to applying the Bayesian portfolio is to construct several matrices and vectors. We are also interested in evaluating the portfolio weights over time and, hence, its performance. To do so, we perform a simple backtesting procedure. At the end of each month, we consider the recent \(T\) months of data as our sample.
d <- ncol(R)
T_sample <- 12*2
month_series <- unique(ceiling_date(date(R),"m") - 1)
month_series <- month_series[year(month_series) > 2004] # keep two years for initial estimation
d_star_mat <- data.frame()
for (month_i in month_series) {
alpha <- 1/(1+T_sample)
e <- rep(1,d) # vector of ones
I_mat <- diag(d) # diagonal matrix
R_sub <- R[date(R) <= month_i,]
R_sub <- tail(R_sub,T_sample) # sample
y_bar <- apply(R_sub,2,mean) # sample mean vector
mu_0 <- c(0.11,0.06)
Sigma <- var(R_sub) # covariance matrix
Sigma_inv <- solve(Sigma) # covariance matrix inverse
d_g <- Sigma_inv%*%e/sum(Sigma_inv)
B_mat <- Sigma_inv%*%(I_mat - e%*%t(d_g) )
B_mat_a <- (1/(1+alpha))*B_mat
d_star <- d_g + alpha*B_mat_a%*%mu_0 + (1-alpha)*B_mat_a%*%y_bar
d_star <- exp(d_star)/(1+exp(d_star))
d_star <- d_star/sum(d_star)
d_star_mat <- rbind(d_star_mat,t(d_star))
}
A number of comments are in order. First, we note that the above procedure loops through all unique months in the data one by one. This application allows updating the sample estimates on a monthly basis. Second, the prior above corresponds to the total sample estimates of the mean return of each ETF. This approach is subjected to data snooping (look-ahead bias), since such information is only revealed after the fact. However, we do so for the sake of illustration. In the following discussion, we consider the sensitivity of the results to different priors. Third, it is well-recognized that the MV portfolio weights result in extreme positions that are considered unrealistic. To mitigate this, we consider a simple logit transformation, which is applied using these two commands:
d_star <- exp(d_star)/(1+exp(d_star))
d_star <- d_star/sum(d_star)
The second command normalizes the portfolio weights, such that its weights sum to one. While this may seem like an ad-hoc approach, this transformation results in a lower portfolio norm and is consistent with DeMiguel et al. (2009).
The plot below illustrates the weight allocated to the SPY ETF over time. We observe that the weight is above 80% the majority of the time. The weight decreases during market selloffs such as the 2007-09 financial crisis, late 2016, and COVID-19.
rownames(d_star_mat) <- month_series
d_star_mat <- as.xts(d_star_mat)
plot(d_star_mat[,1],main = "Weight to SPY")

Let us evaluate the portfolio performance in terms of return over time
R_out <- R[year(date(R)) > 2004 ,]
R_out <- as.matrix(R_out[-1,])
W_in <- as.matrix(d_star_mat[-nrow(d_star_mat)])
r_port_oos <- apply(W_in*R_out,1,sum)
names(r_port_oos) <- rownames(R_out)
r_port_oos <- as.xts(r_port_oos)
As a benchmark, we consider the famous 60-40 decision rule
W_naive <- matrix(c(0.6,0.4),nrow = nrow(W_in),2,byrow = T)
r_port_oos_naive <- apply(W_naive*R_out,1,sum)
names(r_port_oos_naive) <- rownames(R_out)
r_port_oos_naive <- as.xts(r_port_oos_naive)
r_port_oos <- merge(r_port_oos,r_port_oos_naive)
names(r_port_oos) <- c("Bayes","Naive")
plot(cumprod(r_port_oos+1),main = "Cumulative Return",legend.loc = "topleft")

Overall, we observe that the Bayesian portfolio outperforms the 60-40 decision rule.
Different Priors
In this section, we repeat the above analysis for different priors. For example, suppose that the decision-maker believes that the return on the SPY is negative 11%, whereas the return on the IEF stays the same. In this case, the corresponding portfolio would be tilted further towards the IEF (safer asset). As the figure below demonstrates, we note that Bayes portfolio underperforms in terms of cumulative return.

In terms of risk-adjusted returns, we compute the Sharpe-ratio for each portfolio and report below
SR_f <- function(x) sqrt(12)*mean(x)/sd(x)
result <- apply(r_port_oos, 2, SR_f)
round(data.frame(t(result)),2)
While the Bayes results in lower volatility, it is also associated with a lower return. Taken altogether, we realize that the Bayes results in a roughly similar Sharpe ratio.
In the next example, we modify the backtesting program a little. In doing so, the prior incorporates the recent one-month return as the investor’s belief. For example, at the end of month \(t\), after realizing the monthly returns between \(t-1\) and \(t\) denoted by \(\mathbf{y}_t\), the decision-maker sets the prior to \(\boldsymbol{\mu}_0 = \mathbf{y}_t\). To do so, we repeat the previous commands, however, with a small tweak in defining the prior mu_0, i.e.,
mu_0 <- t(tail(R_sub,1))
We summarize the cumulative return in the plot below:

Interestingly, we observe that the Bayes portfolio outperforms the naive decision rule. Furthermore, in terms of risk-adjusted performance, we note that the Bayes rule outperforms the naive, resulting in a Sharpe ratio of 1.06:
result <- apply(r_port_oos, 2, SR_f)
round(data.frame(t(result)),2)
One concern with the above is that the Bayes portfolio may exhibit a higher turnover. Taking into account transaction costs (TC), it is unclear whether the Bayes still outperforms. To evaluate this, we consider a similar TC analysis pursued in this article
W_to <- W_in*(1+R_out)
W_to <- t(apply(W_to,1,function(x) t(x)/sum(x)))
W_to <- W_in[-1,] - W_to[-nrow(W_to),]
W_to <- mean(apply(W_to,1,function(x) sum(abs(x)) ))
TO_bayes <- W_to
whereas for the naive portfolio, we have
W_to <- W_naive*(1+R_out)
W_to <- t(apply(W_to,1,function(x) t(x)/sum(x)))
W_to <- W_in[-1,] - W_to[-nrow(W_to),]
W_to <- mean(apply(W_to,1,function(x) sum(abs(x)) ))
data.frame(Bayes = TO_bayes,Naive = W_to)
While the Bayes does include recent returns into the allocation and is subjected to more noise, its incorporation seems to have a mitigating effect. This result could potentially be due to the persistence of returns over time. To relate to this conjecture, consider the autocorrelation of each ETF over time. Using the same sample size T_sample, we compute the rolling window autocorrelation for each asset and plot the results below.
library(plyr)
R_lag <- na.omit(cbind(R_out,lag.xts(R_out,1)))
cor_roll <- rollapply(R_lag,T_sample, function(x) as.vector(cor(x)), by.column = F, align = "right")
cor_roll <- alply(cor_roll, 1, function(x) matrix(x, nrow = ncol(R_lag) ) )
spy_ar <- sapply(cor_roll,function(x) x[3,1])
ief_ar <- sapply(cor_roll,function(x) x[4,2])
AR_mat <- cbind(spy_ar,ief_ar)
rownames(AR_mat) <- rownames(R_lag)[T_sample:nrow(R_lag)]
AR_mat <- as.xts(AR_mat)
names(AR_mat) <- c("SPY","IEF")
plot(AR_mat,legend.loc = "bottomleft",main = "Autocorrelation")

The above analysis relies on the same trick done in the aforementioned article. Overall, we note the serial correlation varies over time, with values ranging between -53% and 45% for the SPY, whereas the corresponding numbers for IEF are -46% and 35%, respectively. Given the contemporaneous negative relation between the two ETFs, we also observe that both autocorrelations co-move together over time. Nonetheless, over the entire sample period, we note that both coefficients are positive.
AR_result <- data.frame(SPY = cor(R$SPY,lag(R$SPY), use = "pairwise"),
IEF = cor(R$IEF,lag(R$IEF), use = "pairwise"))
rownames(AR_result) <- "Autocorrelation (%)"
round(AR_result*100,2)
LS0tCnRpdGxlOiAiQmF5ZXNpYW4gUG9ydGZvbGlvIFNlbGVjdGlvbjogQXBwbGljYXRpb24gdG8gVGFjdGljYWwgQXNzZXQgQWxsb2NhdGlvbiIKI291dHB1dDogcm1hcmtkb3duOjpnaXRodWJfZG9jdW1lbnQKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQKICBwZGZfZG9jdW1lbnQ6IGRlZmF1bHQKYXV0aG9yOiBNYWplZWQgU2ltYWFuCmRhdGU6IEp1bHkgNywgMjAyMQpmaWdfd2lkdGg6IDIwCi0tLQoKIyBPdmVydmlldwpUaGUgbGl0ZXJhdHVyZSBvbiBwb3J0Zm9saW8gc2VsZWN0aW9uIHVuZGVyIHBhcmFtZXRlciB1bmNlcnRhaW50eSBpcyBudW1lcm91cy4gVGhlIG1vc3QgY29tbW9uIHRlY2huaXF1ZXMgaW52b2x2ZSBCYXllc2lhbiBzdGF0aXN0aWNzIG9yIHNocmlua2FnZS4gRm9yIGluc3RhbmNlLCBKb3Jpb24gKDE5ODYpIGRlbW9uc3RyYXRlcyBob3cgYSBkZWNpc2lvbi1tYWtlciBjYW4gZW1wbG95IEJheWVzaWFuIHN0YXRpc3RpY3MgZnJvbSBhIHNocmlua2FnZSBwb2ludCBvZiB2aWV3LiBUaGlzIGRlY2lzaW9uIHJ1bGUgaXMgY29tbW9ubHkga25vd24gYXMgdGhlIEJheWVzLVN0ZWluLiBBbm90aGVyIGZhbW91cyBwYXJhZGlnbSBpcyB0aGUgQmxhY2sgYW5kIExpdHRlcm1hbiAoMTk5MCkgIG1vZGVsLiBUaGUgbGF0dGVyIG1vZGVsIGFsbG93cyB0aGUgZGVjaXNpb24tbWFrZXIgdG8gaW5jb3Jwb3JhdGUgaW5kaXZpZHVhbCB2aWV3cy9iZWxpZWZzIGFib3V0IHRoZSB1bmRlcmx5aW5nIGFzc2V0cy4gQXMgdGhlIHBhcGVyJ3MgdGl0bGUgaW5kaWNhdGVzLCB0aGVzZSB2aWV3cyBjb3VsZCByZWZsZWN0IGEgZGV2aWF0aW9uIGZyb20gYW4gZXF1aWxpYnJpdW0gbW9kZWwuIEluIGVpdGhlciBjYXNlLCBzaW5jZSBlc3RpbWF0aW9uIGVycm9yIGNhbiBiZSBzZXZlcmUsIGVzcGVjaWFsbHkgZm9yIHRoZSBtZWFuIHJldHVybnMsIHRoZSBwcmVtaXNlIGJlaGluZCB0aGUgYW5hbHlzaXMgaXMgbW90aXZhdGVkIGJ5IGEgdmFyaWFuY2UtYmlhcyB0cmFkZS1vZmYuIE9uIHRoZSBvbmUgaGFuZCwgdGhlIGRlY2lzaW9uLW1ha2VyIGltcG9zZXMgYSBiaWFzIG9uIHRoZSBwb3J0Zm9saW8gd2VpZ2h0cy4gT24gdGhlIG90aGVyIGhhbmQsIHRoZSBpbmNsdXNpb24gb2YgdGhlIHByaW9yIGlzIGZpeGVkIGFuZCBsZXNzIHN1YmplY3RlZCB0byBlc3RpbWF0aW9uLiBPdmVyYWxsLCBpZiB0aGUgcHJpb3IgaXMgaW5mb3JtYXRpdmUsIG9uZSBleHBlY3RzIHRoYXQgaXRzIGluY2x1c2lvbiBsZWFkcyB0byBhIGxvd2VyIG1lYW4tc3F1YXJlZCBlcnJvci4KCgpUaGlzIGFydGljbGUgZGlzY3Vzc2VzIHRoZSBwb3J0Zm9saW8gc2VsZWN0aW9uIHByb2JsZW0gZnJvbSBhIEJheWVzaWFuIHBlcnNwZWN0aXZlLiBJbiBkb2luZyBzbywgSSBmaXJzdCBwcm92aWRlIGFuIG92ZXJ2aWV3IG9mIHRoZSBwb3J0Zm9saW8gcHJvYmxlbSBhbmQgbW90aXZhdGUgdGhlIGRlY2lzaW9uLW1ha2luZyBwcm9jZXNzIGZyb20gYW4gZXhwZWN0ZWQgdXRpbGl0eSBwb2ludCBvZiB2aWV3LiBUaGVuLCBJIGRlbW9uc3RyYXRlIHRoZSBhbmFseXRpY2FsIHNvbHV0aW9uIHRvIHRoZSBwcm9ibGVtIGFuZCBzdHJlc3MgdGhlIGludHVpdGlvbiBiZWhpbmQgdGhlIEJheWVzaWFuIGFwcGxpY2F0aW9uLiBJbiBwYXJ0aWN1bGFyLCBpbiB0aGUgY2FzZSBvZiByaXNreSBhc3NldHMsIHRoZSBvcHRpbWFsIHBvcnRmb2xpbyBjb3JyZXNwb25kcyB0byB0aHJlZSBmdW5kcy4gVGhlIGZpcnN0IGlzIHRoZSBtaW5pbXVtIHZhcmlhbmNlIHBvcnRmb2xpbywgd2hlcmVhcyB0aGUgb3RoZXJzIGRlbm90ZSB0d28gc2VsZi1maW5hbmNpbmcgcG9ydGZvbGlvcyBjb3JyZXNwb25kaW5nIHRvIHRoZSBtZWFuIHJldHVybnMuIFRoZSBjb21iaW5hdGlvbiBiZXR3ZWVuIHRoZSBmaXJzdCBhbmQgdGhlIHNlY29uZCBmdW5kcyBpcyBjb25zaXN0ZW50IHdpdGggdGhlIGNvbnZlbnRpb25hbCBtZWFuLXZhcmlhbmNlIHBvcnRmb2xpby4gRnVydGhlcm1vcmUsIHdpdGggdGhlIGluY2x1c2lvbiBvZiB0aGUgdGhpcmQgZnVuZCwgdGhlIHBvcnRmb2xpbyBpbmNvcnBvcmF0ZXMgdGhlIHByaW9ycy9iZWxpZWZzIG9mIHRoZSBkZWNpc2lvbi1tYWtpbmcgaW50byB0aGUgcG9ydGZvbGlvIHNlbGVjdGlvbi4gQmFzZWQgb24gdGhlIGFuYWx5dGljYWwgaW5zaWdodHMsIEkgY29uZHVjdCBhIHNtYWxsIGVtcGlyaWNhbCBleHBlcmltZW50IHVzaW5nIHR3byBFVEZzLiBUaGUgZXhwZXJpbWVudCBlbXVsYXRlcyBhIHRhY3RpY2FsIGFzc2V0IGFsbG9jYXRpb24gcHJvYmxlbS4gQWxsIHRoZSBlbXBpcmljYWwgYW5hbHlzaXMgaXMgY29uZHVjdGVkIHVzaW5nIFIuCgoKCiMgVGhlIFBvcnRmb2xpbyBQcm9ibGVtClRoZSBkZWNpc2lvbi1tYWtpbmcgcHJvYmxlbSBpcyBkZW5vdGVkIGJ5IGEgZGVjaXNpb24gdmVjdG9yICRcbWF0aGJme2R9JAphbmQgZnV0dXJlIHJlYWxpemF0aW9uIG9mIHRoZSB1bmRlcmx5aW5nIGFzc2V0cyBkZW5vdGVkIGJ5ICRcbWF0aGJme3l9JC4KVGhlIGZvcm1lciBkZW5vdGVzIHRoZSBwb3J0Zm9saW8gd2VpZ2h0cyBhbGxvY2F0ZWQgdG8gcmlza3kgJE4kIGFzc2V0cywKd2hlcmVhcyB0aGUgbGF0dGVyIGRlbm90ZXMgdGhlIGFzc2V0IHJldHVybnMuIFRoZSB0d28gdmVjdG9ycyBkZXRlcm1pbmUKdGhlIHdlYWx0aC9yZXdhcmQgb2YgdGhlIGludmVzdG9yLCB3aGljaCBpcyB1bmNlcnRhaW4uIEl0IGlzIGNvbW1vbmx5CmFzc3VtZWQgdGhhdCB0aGUgcGFyYW1ldGVycyBvZiB0aGUgJFxtYXRoYmZ7eX0kIGFyZSBrbm93biBkZW5vdGVkCmJ5ICRcYm9sZHN5bWJvbHtcdGhldGF9JCwgc3VjaCB0aGF0IHRoZSBkZW5zaXR5IG9mICRcbWF0aGJme3l9JAppcyBrbm93bi4gTm9uZXRoZWxlc3MsIGluIHByYWN0aWNlLCB0aGVzZSBwYXJhbWV0ZXJzIGFyZSB1bmtub3duLCBhbmQgdGhlaXIgZXN0aW1hdGlvbiBpcyBzdWJqZWN0ZWQgdG8gdW5jZXJ0YWludHkuIEFzIGEgcmVzdWx0LCB0aGUgZGVjaXNpb24gcHJvY2VzcyB0YWtlcyBpbnRvIGFjY291bnQgdGhlIGNvbmRpdGlvbmFsIGRpc3RyaWJ1dGlvbiBvZiAkXG1hdGhiZnt5fVxtaWRcYm9sZHN5bWJvbHtcdGhldGF9JC4KSW4gdGhpcyByZWdhcmQsIGlmIHdlIGtub3cgdGhlIGNvbmRpdGlvbmFsIGRpc3RyaWJ1dGlvbiwgdGhlbiB0aGUgZGVjaXNpb24tbWFraW5nIHByb2Nlc3MgYm9pbHMgZG93biB0bwptYXhpbWl6aW5nIHRoZSBmb2xsb3dpbmcgY29uZGl0aW9uYWwgZXhwZWN0ZWQgdXRpbGl0eToKJCQKXHVuZGVyc2V0e1xtYXRoYmZ7ZH19e1x0ZXh0e21heH19XCxcbWF0aGJie0V9XGxlZnRbVShcbWF0aGJme3l9XntcdG9wfVxtYXRoYmZ7ZH0pXG1pZFxib2xkc3ltYm9se1x0aGV0YX1ccmlnaHRdCiQkCgpUaGUgc3RhbmRhcmQgc29sdXRpb24gdG8gdGhlIG9wdGltaXphdGlvbiBwcm9ibGVtIHJlcGxhY2VzIHRoZSBwYXJhbWV0ZXJzIHdpdGggdGhlIHNhbXBsZSBlc3RpbWF0ZXMgYW5kIHNvbHZlcyBmb3Igb3B0aW1hbCBwb3J0Zm9saW8uIFRoaXMgaXMga25vd24gYXMgdGhlIHBsdWctaW4gYXBwcm9hY2guIEhvd2V2ZXIsIGl0IGlzIHdlbGwtcmVjb2duaXplZCB0aGF0IHN1Y2ggcHJhY3RpY2UgaXMgYXNzb2NpYXRlZCB3aXRoIGVzdGltYXRpb24gcmlzayBhbmQgcG9vciBvdXQtb2Ytc2FtcGxlIHBvcnRmb2xpbyBwZXJmb3JtYW5jZS4gQWRkaXRpb25hbGx5LCB0aGUgZGVyaXZhdGlvbiBvZiB0aGlzIHBvcnRmb2xpbyBpcyBpbmNvbnNpc3RlbnQgd2l0aCB1dGlsaXR5IHRoZW9yeSAoc2VlLCBlLmcuLCBLbGVpbiBhbmQgQmF3YSAoMTk3NikpLiAKClVuY2VydGFpbnR5IGFib3V0ICRcYm9sZHN5bWJvbHtcdGhldGF9JCBjYW4gYmUgdGFrZW4gaW50byBhY2NvdW50CmVtcGxveWluZyBCYXllcycgZGVjaXNpb24gY3JpdGVyaW9uLiBBY2NvcmRpbmcgdG8gdGhlIEJheWVzJyBydWxlLAp3ZSBrbm93IHRoYXQgdGhlIHBvc3RlcmlvciBpcyBwcm9wb3J0aW9uYWwgdG8gdGhlIHByb2R1Y3QgYmV0d2Vlbgp0aGUgbGlrZWxpaG9vZCBmdW5jdGlvbiBhbmQgdGhlIHByaW9yLCBpLmUuLApcYmVnaW57ZXF1YXRpb259CnAoXGJvbGRzeW1ib2x7XHRoZXRhfVxtaWRcbWF0aGJme1h9LFxib2xkc3ltYm9se1x0aGV0YX1fezB9KVxwcm9wdG8gcChcbWF0aGJme1h9XG1pZFxib2xkc3ltYm9se1x0aGV0YX0pXHBpKFxib2xkc3ltYm9se1x0aGV0YX0pClxlbmR7ZXF1YXRpb259CndoZXJlICRcbWF0aGJme1h9JCBhbmQgJFxwaShcYm9sZHN5bWJvbHtcdGhldGF9KSQgZGVub3RlLCByZXNwZWN0aXZlbHksCnRoZSBzYW1wbGUtcmVsYXRlZCBpbmZvcm1hdGlvbiBhbmQgdGhlIHByaW9yIGRpc3RyaWJ1dGlvbi4gSGVyZSwgJFxib2xkc3ltYm9se1x0aGV0YX1fezB9JApkZW5vdGVzIHRoZSBiZWxpZWZzIGFib3V0IHRoZSB1bmtub3duIHBhcmFtZXRlcnMuCgojIEFzc3VtcHRpb25zCldlIG1ha2UgYSBjb3VwbGUgb2YgYXNzdW1wdGlvbnMuIFRoZSBmaXJzdCBpcyB0aGF0IHRoZSBkZWNpc2lvbi1tYWtlcidzIHByZWZlcmVuY2UgaXMgcmVwcmVzZW50ZWQgdXNpbmcgYSBjb25zdGFudCBhYnNvbHV0ZSByaXNrCmF2ZXJzaW9uIChDQVJBKSB1dGlsaXR5IGZ1bmN0aW9uLiBUaGUgc2Vjb25kIGFzc3VtcHRpb24gcmVsYXRlcyB0bwp0aGUgZGlzdHJpYnV0aW9uIGZ1bmN0aW9uLiBGb3IgdGhlIHJldHVybnMsIHdlIGFzc3VtZSB0aGF0IHRoZSAKXGJlZ2lue2VxdWF0aW9ufQpcbWF0aGJme3l9XCxcbWlkXGJvbGRzeW1ib2x7XHRoZXRhfVxzaW0gTihcYm9sZHN5bWJvbHtcbXV9LFxib2xkc3ltYm9se1xTaWdtYX0pClxlbmR7ZXF1YXRpb259CndoZXJlICRcYm9sZHN5bWJvbHtcbXV9JCBhbmQgJFxib2xkc3ltYm9se1xTaWdtYX0kIGFyZSB1bmtub3duLiAKClRvIGRldGVybWluZSB0aGUgZXhwZWN0ZWQgdXRpbGl0eSwgd2UgbmVlZCB0byBwb3N0dWxhdGUgYW4gYXNzdW1wdGlvbgpyZWdhcmRpbmcgdGhlIHByaW9ycyBvZiB0aGVzZSB0d28gdW5rbm93bnMuIEluIHBhcnRpY3VsYXIsIHdlIGFzc3VtZQp0aGF0IHRoZSBqb2ludCBkaXN0cmlidXRpb24gYmV0d2VlbiB0aGUgdHdvIGlzIE5vcm1hbC1XaXNoYXJ0LCBzdWNoIHRoYXQKXGJlZ2lue2VxdWF0aW9ufQpcYm9sZHN5bWJvbHtcdGhldGF9XHNpbSBOV1xsZWZ0KFxib2xkc3ltYm9se1xtdX1fezB9LFx0YXUsXGJvbGRzeW1ib2x7XFNpZ21hfV97MH0sXG51XHJpZ2h0KQpcZW5ke2VxdWF0aW9ufQp3aXRoICRcdGF1JCBhbmQgJFxtdSQgZGVub3RpbmcgdGhlIHBhcmFtZXRlcnMgdGhhdCBkZXRlcm1pbmUgdGhlCnN0cmVuZ3RoIG9mIHRoZSBwcmlvciBiZWxpZWYsIHdoZXJlYXMgJFxib2xkc3ltYm9se1xtdX1fezB9JCBhbmQKJFxib2xkc3ltYm9se1xTaWdtYX1fezB9JCBkZW5vdGUgdGhlIHByaW9yIGtub3dsZWRnZSBhYm91dCB0aGUgbWVhbgp2ZWN0b3IgYW5kIHRoZSBjb3ZhcmlhbmNlIG1hdHJpeCwgcmVzcGVjdGl2ZWx5LgoKIyBPcHRpbWFsIFBvcnRmb2xpbwpVbmRlciB0aGUgYWJvdmUgYXNzdW1wdGlvbnMsIHRoZSBwb3N0ZXJpb3IgZGlzdHJpYnV0aW9uICRwKFxib2xkc3ltYm9se1x0aGV0YX1cbWlkXG1hdGhiZntYfSxcYm9sZHN5bWJvbHtcdGhldGF9X3swfSkkCmlzIGtub3duLiBXZSBjYW4gZGV0ZXJtaW5lIHRoZSBleHBlY3RlZCB1dGlsaXR5IGFuZCwgaGVuY2UsIHRoZSBvcHRpbWFsCnBvcnRmb2xpbyBhY2NvcmRpbmdseS4gVW5kZXIgQ0FSQSB1dGlsaXR5LCB3ZSBoYXZlIApcYmVnaW57ZXF1YXRpb259ClUodyk9LVxmcmFjezF9e1xnYW1tYX1lXnstXGdhbW1hIHd9ClxlbmR7ZXF1YXRpb259CndpdGggJHc9XG1hdGhiZntkfV57XHRvcH1cbWF0aGJme3l9JCBkZW5vdGUgdGhlIHRlcm1pbmFsIHdlYWx0aCBmb3IKYWxsb2NhdGlvbiAkXG1hdGhiZntkfSQuIEFjY29yZGluZyB0byB0aGUgdG93ZXIgcHJvcGVydHksIHdlIGtub3cKdGhhdApcYmVnaW57ZXF1YXRpb259ClxtYXRoYmJ7RX1bVSh3KV09XG1hdGhiYntFfV97XGJvbGRzeW1ib2x7XHRoZXRhfX1cbGVmdFtcbWF0aGJie0V9W1UodylcbWlkXGJvbGRzeW1ib2x7XHRoZXRhfV1ccmlnaHRdClxlbmR7ZXF1YXRpb259CndoZXJlICRcbWF0aGJie0V9X3tcYm9sZHN5bWJvbHtcdGhldGF9fSQgZGVub3RlcyB0aGUgZXhwZWN0YXRpb24KY29uZGl0aW9uIG9uIG9ic2VydmluZyBkYXRhICRcbWF0aGJme1h9JCBhbmQgcHJpb3IgJFxib2xkc3ltYm9se1x0aGV0YX1fezB9JC4KCklmIHRoZSBwYXJhbWV0ZXJzIGFyZSBrbm93biwgdGhlbiBmcm9tIHRoZSBtb21lbnQgZ2VuZXJhdGluZyBmdW5jdGlvbgpvZiBhIEdhdXNzaWFuIHZhcmlhYmxlLCB3ZSBoYXZlIApcYmVnaW57ZXF1YXRpb259ClxtYXRoYmJ7RX1bVSh3KVxtaWRcYm9sZHN5bWJvbHtcdGhldGF9XT0tXGZyYWN7MX17XGdhbW1hfVxtYXRoYmJ7RX1bZV57LVxnYW1tYVxtYXRoYmZ7ZH1ee1x0b3B9XG1hdGhiZnt5fX1cbWlkXGJvbGRzeW1ib2x7XHRoZXRhfV09LVxmcmFjezF9e1xnYW1tYX1lXnstXGdhbW1hXG1hdGhiZntkfV57XHRvcH1cYm9sZHN5bWJvbHtcbXV9K1xmcmFje1xnYW1tYV57Mn19ezJ9XG1hdGhiZntkfV57XHRvcH1cYm9sZHN5bWJvbHtcU2lnbWF9XG1hdGhiZntkfX0KXGVuZHtlcXVhdGlvbn0KRmluYWxseSwgdGhlIGV4cGVjdGVkIHV0aWxpdHkgZnVuY3Rpb24gZGVwZW5kcyBvbiBmaW5kaW5nIHRoZSBleHBlY3RhdGlvbgpvZiAKXGJlZ2lue2VxdWF0aW9ufQpcbWF0aGJie0V9W1UodyldPS1cZnJhY3sxfXtcZ2FtbWF9XG1hdGhiYntFfV97XGJvbGRzeW1ib2x7XHRoZXRhfX1cbGVmdFtlXnstXGdhbW1hXG1hdGhiZntkfV57XHRvcH1cYm9sZHN5bWJvbHtcbXV9K1xmcmFje1xnYW1tYV57Mn19ezJ9XG1hdGhiZntkfV57XHRvcH1cYm9sZHN5bWJvbHtcU2lnbWF9XG1hdGhiZntkfX1ccmlnaHRdClxlbmR7ZXF1YXRpb259CndoaWNoIHJlcXVpcmVzIGtub3dpbmcgdGhlIHBvc3RlcmlvciBkaXN0cmlidXRpb24gJHAoXGJvbGRzeW1ib2x7XHRoZXRhfVxtaWRcbWF0aGJme1h9LFxib2xkc3ltYm9se1x0aGV0YX1fezB9KSQuCkFsdGVybmF0aXZlbHksIHdlIGNhbiBjb25zaWRlciB0aGUgcHJlZGljdGl2ZSBkZW5zaXR5IGZ1bmN0aW9uIG9mCiRcbWF0aGJme3l9JC4gVW5kZXIgdGhlIGFib3ZlIGFzc3VtcHRpb25zLCAgJFxtYXRoYmZ7eX1cbWlkXG1hdGhiZntYfSxcYm9sZHN5bWJvbHtcdGhldGF9X3swfSQKZm9sbG93cyBhIG11bHRpdmFyaWF0ZSBzdHVkZW50LXQgZGlzdHJpYnV0aW9uLiBGaW5kaW5nIHRoZSBleHBlY3RhdGlvbgpvZiB3aGljaCBjYW4gYmUgb2J0YWluZWQgbnVtZXJpY2FsbHkuIAoKIyMgS25vd24gJFxTaWdtYSQKV2hpbGUgYSBudW1lcmljYWwgc29sdXRpb24gcHJvdmlkZXMgYSBtb3JlIGFjY3VyYXRlIGFwcHJveGltYXRpb24sIGl0IGNvbWVzIGF0IHRoZSBjb3N0IG9mIGludHVpdGlvbi4gVG8gZ2FpbiBmdXJ0aGVyIGluc2lnaHRzIGFib3V0IHRoZSB1cGRhdGluZyBwcm9jZXNzLCB3ZSBtYWtlIG9uZSBzaW1wbGlmaWNhdGlvbi4gV2UgYXNzdW1lIHRoYXQgdGhlIGRlY2lzaW9uLW1ha2VyIGtub3dzIHRoZSBjb3ZhcmlhbmNlIG1hdHJpeCB3aXRob3V0IGFueSB1bmNlcnRhaW50eS4gSW4gdGhpcyByZWdhcmRzLCB3ZSBoYXZlICRcYm9sZHN5bWJvbHtcU2lnbWF9PVxib2xkc3ltYm9se1xTaWdtYX1fezB9JC4gVGhlcmVmb3JlLCB0aGUgZXhwZWN0ZWQgdXRpbGl0eSBzaW1wbGlmaWVzIHRvIApcYmVnaW57ZXF1YXRpb259ClxtYXRoYmJ7RX1bVSh3KV09LVxmcmFjezF9e1xnYW1tYX1lXntcZnJhY3tcZ2FtbWFeezJ9fXsyfVxtYXRoYmZ7ZH1ee1x0b3B9XGJvbGRzeW1ib2x7XFNpZ21hfVxtYXRoYmZ7ZH19XG1hdGhiYntFfV97XGJvbGRzeW1ib2x7XHRoZXRhfX1cbGVmdFtlXnstXGdhbW1hXG1hdGhiZntkfV57XHRvcH1cYm9sZHN5bWJvbHtcbXV9fVxyaWdodF0uClxlbmR7ZXF1YXRpb259CgpJbiB0aGlzIGNhc2UsIHdlIGtub3cgdGhhdApcYmVnaW57ZXF1YXRpb259Clxib2xkc3ltYm9se1xtdX1cbWlkXG1hdGhiZntYfSxcYm9sZHN5bWJvbHtcbXV9X3swfVxzaW0gTlxsZWZ0KFxib2xkc3ltYm9se1xTaWdtYX1fezF9XGJvbGRzeW1ib2x7XFNpZ21hfV97MH1eey0xfVxib2xkc3ltYm9se1xtdX1fezB9K1xib2xkc3ltYm9se1xTaWdtYX1fezF9VFxib2xkc3ltYm9se1xTaWdtYX1fezB9XnstMX1cYmFye1xtYXRoYmZ7eX19LFxib2xkc3ltYm9se1xTaWdtYX1fezF9XHJpZ2h0KQpcZW5ke2VxdWF0aW9ufQp3aXRoClxiZWdpbntlcXVhdGlvbn0KXGJvbGRzeW1ib2x7XFNpZ21hfV97MX1eey0xfT1cYm9sZHN5bWJvbHtcU2lnbWF9X3swfV57LTF9K1RcYm9sZHN5bWJvbHtcU2lnbWF9XnstMX0KXGVuZHtlcXVhdGlvbn0KU2luY2UgJFxib2xkc3ltYm9se1xTaWdtYX09XGJvbGRzeW1ib2x7XFNpZ21hfV97MH0kLCB0aGVuClxiZWdpbntlcXVhdGlvbn0KXGJvbGRzeW1ib2x7XFNpZ21hfV97MX09XGZyYWN7MX17MStUfVxib2xkc3ltYm9se1xTaWdtYX1fezB9ClxlbmR7ZXF1YXRpb259CmFuZApcYmVnaW57ZXF1YXRpb259Clxib2xkc3ltYm9se1xTaWdtYX1fezF9XGJvbGRzeW1ib2x7XFNpZ21hfV97MH1eey0xfVxib2xkc3ltYm9se1xtdX1fezB9K1xib2xkc3ltYm9se1xTaWdtYX1fezF9VFxib2xkc3ltYm9se1xTaWdtYX1fezB9XnstMX1cYmFye1xtYXRoYmZ7eX19PVxmcmFjezF9e1R9XGJvbGRzeW1ib2x7XG11fV97MH0rXGZyYWN7VH17MStUfVxiYXJ7XG1hdGhiZnt5fX0KXGVuZHtlcXVhdGlvbn0Kd2l0aCAkVCQgZGVub3RpbmcgdGhlIHNhbXBsZSBzaXplLiBBcyBhIHJlc3VsdCwgd2UgaGF2ZQpcYmVnaW57ZXF1YXRpb259Clxib2xkc3ltYm9se1xtdX1cbWlkXG1hdGhiZntYfSxcYm9sZHN5bWJvbHtcbXV9X3swfVxzaW0gTlxsZWZ0KFxhbHBoYVxib2xkc3ltYm9se1xtdX1fezB9KygxLVxhbHBoYSlcYmFye1xtYXRoYmZ7eX19LFxmcmFjezF9ezErVH1cYm9sZHN5bWJvbHtcU2lnbWF9X3swfVxyaWdodCkKXGVuZHtlcXVhdGlvbn0Kd2l0aAoKXGJlZ2lue2VxdWF0aW9ufQpcYWxwaGE9XGZyYWN7MX17MStUfVxpbigwLDEpXDpcdGV4dHtmb3IgfVQ+MC4KXGVuZHtlcXVhdGlvbn0KVGhlIGV4cGVjdGVkIHV0aWxpdHkgaXMgZ2l2ZW4gYnkKXGJlZ2lue2VxdWF0aW9ufQpcbWF0aGJie0V9W1UodyldPS1cZnJhY3sxfXtcZ2FtbWF9XHRleHR7ZXhwfVxsZWZ0KC1cZ2FtbWFcbWF0aGJme2R9XntcdG9wfVxsZWZ0W1xhbHBoYVxib2xkc3ltYm9se1xtdX1fezB9KygxLVxhbHBoYSlcYmFye1xtYXRoYmZ7eX19XHJpZ2h0XSsoMStcYWxwaGEpXGZyYWN7XGdhbW1hXnsyfX17Mn1cbWF0aGJme2R9XntcdG9wfVxib2xkc3ltYm9se1xTaWdtYX1fezB9XG1hdGhiZntkfVxyaWdodCkuClxlbmR7ZXF1YXRpb259CkFwcGx5aW5nIGEgcG9zaXRpdmUgdHJhbnNmb3JtYXRpb24gb24gdGhlIGV4cGVjdGVkIHV0aWxpdHksIGl0cyBvcHRpbWl6YXRpb24KaXMgY29uc2lzdGVudCB3aXRoIHRoZSBmb2xsb3dpbmcgbWVhbi12YXJpYW5jZSAoTVYpIHByZWZlcmVuY2U6ClxiZWdpbntlcXVhdGlvbn0KXG1hdGhiZntkfV57XHRvcH1cbGVmdFtcYWxwaGFcYm9sZHN5bWJvbHtcbXV9X3swfSsoMS1cYWxwaGEpXGJhcntcbWF0aGJme3l9fVxyaWdodF0tXGZyYWN7XGdhbW1hfXsyfSgxK1xhbHBoYSlcbWF0aGJme2R9XntcdG9wfVxib2xkc3ltYm9se1xTaWdtYX1fezB9XG1hdGhiZntkfQpcZW5ke2VxdWF0aW9ufQoKQ29uc2lkZXIgdGhlIGNhc2Ugb2YgZnVsbCBpbmZvcm1hdGlvbiBpbiB3aGljaCAkVFxyaWdodGFycm93XGluZnR5JApzdWNoIHRoYXQgJFxhbHBoYVxyaWdodGFycm93MCQuIFVuZGVyIHRoaXMgZXh0cmVtZSBzY2VuYXJpbywgaXQgaXMKY2xlYXIgdGhhdCB0aGUgQmF5ZXNpYW4gcG9ydGZvbGlvIHByb2JsZW0gY29udmVyZ2VzIHRvIHRoZSBjb252ZW50aW9uYWwKTVYgb3B0aW1pemF0aW9uLiBGb3IgYSBmaW5pdGUgc2FtcGxlIHNpemUsICRcYWxwaGEkIGRlbm90ZXMgdGhlIGFtYmlndWl0eQphYm91dCB0aGUgbWVhbiByZXR1cm4uIFRoZSBsYXJnZXIgaXQgaXMsIHRoZSBtb3JlIHZhcmlhbmNlIHRoZSBkZWNpc2lvbgptYXJrZXQgYXNzaWducyB0byB0aGUgcG9ydGZvbGlvIHZhcmlhbmNlIGFuZCB0aGUgZ3JlYXRlciB3ZWlnaHQgaXMKYXR0cmlidXRlZCB0byB0aGUgcHJpb3IuCgpVbmRlciB0aGUgY29uc3RyYWludCB0aGF0ICRcbWF0aGJme2R9XntcdG9wfVxtYXRoYmZ7MX09MSQsIHRoZSBvcHRpbWFsCnBvcnRmb2xpbyBpcyBnaXZlbiBieSAKXGJlZ2lue2VxdWF0aW9ufQpcbWF0aGJme2R9XnsqfT1cbWF0aGJme2R9X3tnfStcZnJhY3sxfXsxK1xhbHBoYX1cbWF0aGJme0J9W1xhbHBoYVxib2xkc3ltYm9se1xtdX1fezB9KygxLVxhbHBoYSlcYmFye1xtYXRoYmZ7eX19XQpcZW5ke2VxdWF0aW9ufQp3aXRoIApcYmVnaW57ZXF1YXRpb259ClxtYXRoYmZ7ZH1fe2d9PVxmcmFje1xib2xkc3ltYm9se1xTaWdtYX1fezB9XnstMX1cbWF0aGJmezF9fXtcbWF0aGJmezF9XntcdG9wfVxib2xkc3ltYm9se1xTaWdtYX1fezB9XnstMX1cbWF0aGJmezF9fQpcZW5ke2VxdWF0aW9ufQpkZW5vdGluZyB0aGUgZ2xvYmFsIG1pbmltdW0gdmFyaWFuY2UgKEdNVikgcG9ydGZvbGlvIGFuZCAKXGJlZ2lue2VxdWF0aW9ufQpcbWF0aGJme0J9PVxib2xkc3ltYm9se1xTaWdtYX1fezB9XnstMX1cbGVmdFtcbWF0aGJme0l9LVxtYXRoYmZ7MX1cbWF0aGJme2R9X3tnfV57XHRvcH1ccmlnaHRdClxlbmR7ZXF1YXRpb259CmlzIGEgY2VudGVyaW5nIG1hdHJpeCBhcm91bmQgdGhlIEdNViBwb3J0Zm9saW8gKHNlZSwgZS5nLiwgU2ltYWFuIGV0IGFsLiAoMjAxOCkpLiAKCkl0IGlzIGNsZWFyIHRoYXQgdGhlIE1WIG9wdGltYWwgcG9ydGZvbGlvIGNvbnNpc3RzIG9mIHRocmVlIGZ1bmRzLiBUaGUgZmlyc3QgaXMgdGhlIEdNVi4gVGhlIHNlY29uZCAodGhpcmQpIGlzIHRoZSBhcmJpdHJhZ2UgcG9ydGZvbGlvIHRoYXQgZGVwZW5kcyBvbiB0aGUgcHJpb3IgKHNhbXBsZSkgbWVhbiByZXR1cm46ClxiZWdpbntlcXVhdGlvbn0KXG1hdGhiZntkfV57Kn09XG1hdGhiZntkfV97Z30rXGZyYWN7XGFscGhhfXsxK1xhbHBoYX1cbWF0aGJme0J9XGJvbGRzeW1ib2x7XG11fV97MH0rXGZyYWN7MS1cYWxwaGF9ezErXGFscGhhfVxtYXRoYmZ7Qn1cYmFye1xtYXRoYmZ7eX19LgpcZW5ke2VxdWF0aW9ufQpUbyBzaW1wbGlmeSwgbGV0ICRcbWF0aGJme0J9X3tcYWxwaGF9PSgxK1xhbHBoYSleey0xfVxtYXRoYmZ7Qn0kLApzdWNoIHRoYXQKClxiZWdpbntlcXVhdGlvbn0KXG1hdGhiZntkfV57Kn09XG1hdGhiZntkfV97Z30rXGFscGhhXG1hdGhiZntCfV97XGFscGhhfVxib2xkc3ltYm9se1xtdX1fezB9KygxLVxhbHBoYSlcbWF0aGJme0J9X3tcYWxwaGF9XGJhcntcbWF0aGJme3l9fS4KXGVuZHtlcXVhdGlvbn0KCldlIG9ic2VydmUgdGhhdCB0aGUgQmF5ZXNpYW4gTVYgcG9ydGZvbGlvIGlzIGEgY29udmV4IGNvbWJpbmF0aW9uCmJldHdlZW4gdHdvIHBvcnRmb2xpb3MuIFNwZWNpZmljYWxseSwgZm9yICRcYWxwaGFcaW4oMCwxKSQgaXQgZm9sbG93cwp0aGF0ClxiZWdpbntlcXVhdGlvbn0KXG1hdGhiZntkfV57Kn09XGFscGhhXG1hdGhiZntkfV57Kn0oXGJvbGRzeW1ib2x7XG11fV97MH0pK1xsZWZ0WzEtXGFscGhhXHJpZ2h0XVxtYXRoYmZ7ZH1eeyp9KFxiYXJ7XG1hdGhiZnt5fX0pClxlbmR7ZXF1YXRpb259CndpdGgKClxiZWdpbntlcXVhdGlvbn0KXG1hdGhiZntkfV57Kn0oXG1hdGhiZnt1fSk9XG1hdGhiZntkfV97Z30rXG1hdGhiZntCfV97XGFscGhhfVxtYXRoYmZ7dX0sClxlbmR7ZXF1YXRpb259CmRlbm90aW5nIGEgbGluZWFyIGZ1bmN0aW9uIG9mIHZlY3RvciAkXG1hdGhiZnt1fSQuIAoKIyBFbXBpcmljYWwgRXhhbXBsZQpMZXQgdXMgc3RhcnQgd2l0aCBhIHNpbXBsZSBudW1lcmljYWwgZXhhbXBsZS4gVG8gZG8gc28sIEkgd2lsbCBiZSB3b3JraW5nIHdpdGggdHdvIEVURnMuIFRoZSBmaXJzdCBvbmUgaXMgdGhlIFNQWSBFVEYgZGVub3RpbmcgdGhlIHN0b2NrIG1hcmtldCBwb3J0Zm9saW8sIHdoZXJlYXMgdGhlIG90aGVyIGlzIHRoZSBJRUYgZGVub3RpbmcgdGhlIHJldHVybiBvbiA3LTEwIHllYXJzIFRyZWFzdXJ5IGJvbmRzLiAKYGBge3IsbWVzc2FnZT1GLHdhcm5pbmc9Rn0KbGlicmFyeShxdWFudG1vZCkKbGlicmFyeShsdWJyaWRhdGUpCnYgPC0gYygiU1BZIiwiSUVGIikKdDEgPC0gIjE5OTYtMDEtMDEiICMgdGhlIHN0YXJ0aW5nIGRhdGUKUC5saXN0IDwtIGxhcHBseSh2LGZ1bmN0aW9uKHgpIGdldChnZXRTeW1ib2xzKHgsZnJvbSA9IHQxKSkgKQpQIDwtIGxhcHBseShQLmxpc3QsZnVuY3Rpb24oeCkgeFssZ3JlcCgiQWRqdXN0ZWQiLG5hbWVzKHgpKV0pClAgPC0gUmVkdWNlKGZ1bmN0aW9uKC4uLikgbWVyZ2UoLi4uKSxQICApCm5hbWVzKFApIDwtIHYKUCA8LSBhcHBseS5tb250aGx5KFAsZnVuY3Rpb24oeCkgeFtucm93KHgpLF0gKQpSIDwtIG5hLm9taXQoUC9sYWcoUCktMSkKUiA8LSBSWyIvMjAyMC0xMi0zMSIsXQpgYGAKCldlIGNvbnNpZGVyIHRoZSByZXR1cm5zIG9uIGJvdGggRVRGcyB1cCB0byBsYXRlIDIwMjAuIE5vdGUgdGhhdCB0aGUgaW5jZXB0aW9uIG9mIHRoZSBJRUYgdG9vayBwbGFjZSBkdXJpbmcgdGhlIHNlY29uZCBoYWxmIG9mIDIwMDIuICBGb3IgdGhpcyByZWFzb24sIHRoZSBkYXRhIGRhdGVzIGJldHdlZW4KYGBge3J9CnJhbmdlKGRhdGUoUikpCmBgYApUaGUga2V5IHRvIGFwcGx5aW5nIHRoZSBCYXllc2lhbiBwb3J0Zm9saW8gaXMgdG8gY29uc3RydWN0IHNldmVyYWwgbWF0cmljZXMgYW5kIHZlY3RvcnMuIFdlIGFyZSBhbHNvIGludGVyZXN0ZWQgaW4gZXZhbHVhdGluZyB0aGUgcG9ydGZvbGlvIHdlaWdodHMgb3ZlciB0aW1lIGFuZCwgaGVuY2UsIGl0cyBwZXJmb3JtYW5jZS4gVG8gZG8gc28sIHdlIHBlcmZvcm0gYSBzaW1wbGUgYmFja3Rlc3RpbmcgcHJvY2VkdXJlLiBBdCB0aGUgZW5kIG9mIGVhY2ggbW9udGgsIHdlIGNvbnNpZGVyIHRoZSByZWNlbnQgJFQkIG1vbnRocyBvZiBkYXRhIGFzIG91ciBzYW1wbGUuCmBgYHtyLG91dC53aWR0aCA9ICc3NSUnLGZpZy5hbGlnbj0iY2VudGVyIn0KZCA8LSBuY29sKFIpClRfc2FtcGxlIDwtIDEyKjIKbW9udGhfc2VyaWVzIDwtIHVuaXF1ZShjZWlsaW5nX2RhdGUoZGF0ZShSKSwibSIpIC0gMSkKbW9udGhfc2VyaWVzIDwtIG1vbnRoX3Nlcmllc1t5ZWFyKG1vbnRoX3NlcmllcykgPiAyMDA0XSAjIGtlZXAgdHdvIHllYXJzIGZvciBpbml0aWFsIGVzdGltYXRpb24KZF9zdGFyX21hdCA8LSBkYXRhLmZyYW1lKCkKZm9yIChtb250aF9pIGluIG1vbnRoX3NlcmllcykgewogIGFscGhhIDwtIDEvKDErVF9zYW1wbGUpCiAgZSA8LSByZXAoMSxkKSAjIHZlY3RvciBvZiBvbmVzCiAgSV9tYXQgPC0gZGlhZyhkKSAjIGRpYWdvbmFsIG1hdHJpeAogIFJfc3ViIDwtIFJbZGF0ZShSKSA8PSBtb250aF9pLF0KICBSX3N1YiA8LSB0YWlsKFJfc3ViLFRfc2FtcGxlKSAjIHNhbXBsZSAKICB5X2JhciA8LSBhcHBseShSX3N1YiwyLG1lYW4pICMgc2FtcGxlIG1lYW4gdmVjdG9yCiAgbXVfMCA8LSAgYygwLjExLDAuMDYpCiAgU2lnbWEgPC0gdmFyKFJfc3ViKSAjIGNvdmFyaWFuY2UgbWF0cml4CiAgU2lnbWFfaW52IDwtIHNvbHZlKFNpZ21hKSAjIGNvdmFyaWFuY2UgbWF0cml4IGludmVyc2UKICBkX2cgPC0gU2lnbWFfaW52JSolZS9zdW0oU2lnbWFfaW52KQogIEJfbWF0IDwtIFNpZ21hX2ludiUqJShJX21hdCAtIGUlKiV0KGRfZykgKQogIEJfbWF0X2EgPC0gKDEvKDErYWxwaGEpKSpCX21hdAogIGRfc3RhciA8LSBkX2cgKyBhbHBoYSpCX21hdF9hJSolbXVfMCArICgxLWFscGhhKSpCX21hdF9hJSoleV9iYXIKICBkX3N0YXIgPC0gZXhwKGRfc3RhcikvKDErZXhwKGRfc3RhcikpCiAgZF9zdGFyIDwtIGRfc3Rhci9zdW0oZF9zdGFyKQogIGRfc3Rhcl9tYXQgPC0gcmJpbmQoZF9zdGFyX21hdCx0KGRfc3RhcikpCn0KYGBgCkEgbnVtYmVyIG9mIGNvbW1lbnRzIGFyZSBpbiBvcmRlci4gRmlyc3QsIHdlIG5vdGUgdGhhdCB0aGUgYWJvdmUgcHJvY2VkdXJlIGxvb3BzIHRocm91Z2ggYWxsIHVuaXF1ZSBtb250aHMgaW4gdGhlIGRhdGEgb25lIGJ5IG9uZS4gVGhpcyBhcHBsaWNhdGlvbiBhbGxvd3MgdXBkYXRpbmcgdGhlIHNhbXBsZSBlc3RpbWF0ZXMgb24gYSBtb250aGx5IGJhc2lzLiAKU2Vjb25kLCB0aGUgcHJpb3IgYWJvdmUgY29ycmVzcG9uZHMgdG8gdGhlIHRvdGFsIHNhbXBsZSBlc3RpbWF0ZXMgb2YgdGhlIG1lYW4gcmV0dXJuIG9mIGVhY2ggRVRGLiBUaGlzIGFwcHJvYWNoIGlzIHN1YmplY3RlZCB0byBkYXRhIHNub29waW5nIChsb29rLWFoZWFkIGJpYXMpLCBzaW5jZSBzdWNoIGluZm9ybWF0aW9uIGlzIG9ubHkgcmV2ZWFsZWQgYWZ0ZXIgdGhlIGZhY3QuIEhvd2V2ZXIsIHdlIGRvIHNvIGZvciB0aGUgc2FrZSBvZiBpbGx1c3RyYXRpb24uIEluIHRoZSBmb2xsb3dpbmcgZGlzY3Vzc2lvbiwgd2UgY29uc2lkZXIgdGhlIHNlbnNpdGl2aXR5IG9mIHRoZSByZXN1bHRzIHRvIGRpZmZlcmVudCBwcmlvcnMuClRoaXJkLCBpdCBpcyB3ZWxsLXJlY29nbml6ZWQgdGhhdCB0aGUgTVYgcG9ydGZvbGlvIHdlaWdodHMgcmVzdWx0IGluIGV4dHJlbWUgcG9zaXRpb25zIHRoYXQgYXJlIGNvbnNpZGVyZWQgdW5yZWFsaXN0aWMuIFRvIG1pdGlnYXRlIHRoaXMsIHdlIGNvbnNpZGVyIGEgc2ltcGxlIGxvZ2l0IHRyYW5zZm9ybWF0aW9uLCB3aGljaCBpcyBhcHBsaWVkIHVzaW5nIHRoZXNlIHR3byBjb21tYW5kczoKYGBge3IsZXZhbD1GQUxTRX0KZF9zdGFyIDwtIGV4cChkX3N0YXIpLygxK2V4cChkX3N0YXIpKQpkX3N0YXIgPC0gZF9zdGFyL3N1bShkX3N0YXIpCmBgYApUaGUgc2Vjb25kIGNvbW1hbmQgbm9ybWFsaXplcyB0aGUgcG9ydGZvbGlvIHdlaWdodHMsIHN1Y2ggdGhhdCBpdHMgd2VpZ2h0cyBzdW0gdG8gb25lLiBXaGlsZSB0aGlzIG1heSBzZWVtIGxpa2UgYW4gYWQtaG9jIGFwcHJvYWNoLCB0aGlzIHRyYW5zZm9ybWF0aW9uIHJlc3VsdHMgaW4gYSBsb3dlciBwb3J0Zm9saW8gbm9ybSBhbmQgaXMgY29uc2lzdGVudCB3aXRoIERlTWlndWVsIGV0IGFsLiAoMjAwOSkuIAoKVGhlIHBsb3QgYmVsb3cgaWxsdXN0cmF0ZXMgdGhlIHdlaWdodCBhbGxvY2F0ZWQgdG8gdGhlIFNQWSBFVEYgb3ZlciB0aW1lLiBXZSBvYnNlcnZlIHRoYXQgdGhlIHdlaWdodCBpcyBhYm92ZSA4MFwlIHRoZSBtYWpvcml0eSBvZiB0aGUgdGltZS4gVGhlIHdlaWdodCBkZWNyZWFzZXMgZHVyaW5nIG1hcmtldCBzZWxsb2ZmcyBzdWNoIGFzIHRoZSAyMDA3LTA5IGZpbmFuY2lhbCBjcmlzaXMsIGxhdGUgMjAxNiwgYW5kIENPVklELTE5LiAKYGBge3J9CnJvd25hbWVzKGRfc3Rhcl9tYXQpIDwtIG1vbnRoX3NlcmllcwpkX3N0YXJfbWF0IDwtIGFzLnh0cyhkX3N0YXJfbWF0KQpwbG90KGRfc3Rhcl9tYXRbLDFdLG1haW4gPSAiV2VpZ2h0IHRvIFNQWSIpCmBgYAoKTGV0IHVzIGV2YWx1YXRlIHRoZSBwb3J0Zm9saW8gcGVyZm9ybWFuY2UgaW4gdGVybXMgb2YgcmV0dXJuIG92ZXIgdGltZQpgYGB7cn0KUl9vdXQgPC0gUlt5ZWFyKGRhdGUoUikpID4gMjAwNCAsXQpSX291dCA8LSBhcy5tYXRyaXgoUl9vdXRbLTEsXSkKV19pbiA8LSBhcy5tYXRyaXgoZF9zdGFyX21hdFstbnJvdyhkX3N0YXJfbWF0KV0pCnJfcG9ydF9vb3MgPC0gYXBwbHkoV19pbipSX291dCwxLHN1bSkKbmFtZXMocl9wb3J0X29vcykgPC0gcm93bmFtZXMoUl9vdXQpCnJfcG9ydF9vb3MgPC0gYXMueHRzKHJfcG9ydF9vb3MpCmBgYApBcyBhIGJlbmNobWFyaywgd2UgY29uc2lkZXIgdGhlIGZhbW91cyA2MC00MCBkZWNpc2lvbiBydWxlCmBgYHtyfQpXX25haXZlIDwtIG1hdHJpeChjKDAuNiwwLjQpLG5yb3cgPSBucm93KFdfaW4pLDIsYnlyb3cgPSBUKQpyX3BvcnRfb29zX25haXZlIDwtIGFwcGx5KFdfbmFpdmUqUl9vdXQsMSxzdW0pCm5hbWVzKHJfcG9ydF9vb3NfbmFpdmUpIDwtICByb3duYW1lcyhSX291dCkKcl9wb3J0X29vc19uYWl2ZSA8LSBhcy54dHMocl9wb3J0X29vc19uYWl2ZSkKYGBgCgpgYGB7cixvdXQud2lkdGggPSAnNzUlJyxmaWcuYWxpZ249ImNlbnRlciJ9CnJfcG9ydF9vb3MgPC0gbWVyZ2Uocl9wb3J0X29vcyxyX3BvcnRfb29zX25haXZlKSAKbmFtZXMocl9wb3J0X29vcykgPC0gYygiQmF5ZXMiLCJOYWl2ZSIpCnBsb3QoY3VtcHJvZChyX3BvcnRfb29zKzEpLG1haW4gPSAiQ3VtdWxhdGl2ZSBSZXR1cm4iLGxlZ2VuZC5sb2MgPSAidG9wbGVmdCIpCmBgYApPdmVyYWxsLCB3ZSBvYnNlcnZlIHRoYXQgdGhlIEJheWVzaWFuIHBvcnRmb2xpbyBvdXRwZXJmb3JtcyB0aGUgNjAtNDAgZGVjaXNpb24gcnVsZS4gCgojIyBEaWZmZXJlbnQgUHJpb3JzCkluIHRoaXMgc2VjdGlvbiwgd2UgcmVwZWF0IHRoZSBhYm92ZSBhbmFseXNpcyBmb3IgZGlmZmVyZW50IHByaW9ycy4gRm9yIGV4YW1wbGUsIHN1cHBvc2UgdGhhdCB0aGUgZGVjaXNpb24tbWFrZXIgYmVsaWV2ZXMgdGhhdCB0aGUgcmV0dXJuIG9uIHRoZSBTUFkgaXMgbmVnYXRpdmUgMTFcJSwgd2hlcmVhcyB0aGUgcmV0dXJuIG9uIHRoZSBJRUYgc3RheXMgdGhlIHNhbWUuIEluIHRoaXMgY2FzZSwgdGhlIGNvcnJlc3BvbmRpbmcgcG9ydGZvbGlvIHdvdWxkIGJlIHRpbHRlZCBmdXJ0aGVyIHRvd2FyZHMgdGhlIElFRiAoc2FmZXIgYXNzZXQpLiBBcyB0aGUgZmlndXJlIGJlbG93IGRlbW9uc3RyYXRlcywgd2Ugbm90ZSB0aGF0IEJheWVzIHBvcnRmb2xpbyB1bmRlcnBlcmZvcm1zIGluIHRlcm1zIG9mIGN1bXVsYXRpdmUgcmV0dXJuLgpgYGB7cixlY2hvPUYsZmlnLmFsaWduPSJjZW50ZXIiLG91dC53aWR0aCA9ICc3NSUnfQpkX3N0YXJfbWF0IDwtIGRhdGEuZnJhbWUoKQpmb3IgKG1vbnRoX2kgaW4gbW9udGhfc2VyaWVzKSB7CiAgYWxwaGEgPC0gMS8oMStUX3NhbXBsZSkKICBlIDwtIHJlcCgxLGQpICMgdmVjdG9yIG9mIG9uZXMKICBJX21hdCA8LSBkaWFnKGQpICMgZGlhZ29uYWwgbWF0cml4CiAgUl9zdWIgPC0gUltkYXRlKFIpIDw9IG1vbnRoX2ksXQogIFJfc3ViIDwtIHRhaWwoUl9zdWIsVF9zYW1wbGUpICMgc2FtcGxlIAogIHlfYmFyIDwtIGFwcGx5KFJfc3ViLDIsbWVhbikgIyBzYW1wbGUgbWVhbiB2ZWN0b3IKICBtdV8wIDwtICBjKC0wLjExLDAuMDYpCiAgU2lnbWEgPC0gdmFyKFJfc3ViKSAjIGNvdmFyaWFuY2UgbWF0cml4CiAgU2lnbWFfaW52IDwtIHNvbHZlKFNpZ21hKSAjIGNvdmFyaWFuY2UgbWF0cml4IGludmVyc2UKICBkX2cgPC0gU2lnbWFfaW52JSolZS9zdW0oU2lnbWFfaW52KQogIEJfbWF0IDwtIFNpZ21hX2ludiUqJShJX21hdCAtIGUlKiV0KGRfZykgKQogIEJfbWF0X2EgPC0gKDEvKDErYWxwaGEpKSpCX21hdAogIGRfc3RhciA8LSBkX2cgKyBhbHBoYSpCX21hdF9hJSolbXVfMCArICgxLWFscGhhKSpCX21hdF9hJSoleV9iYXIKICBkX3N0YXIgPC0gZXhwKGRfc3RhcikvKDErZXhwKGRfc3RhcikpCiAgZF9zdGFyIDwtIGRfc3Rhci9zdW0oZF9zdGFyKQogIGRfc3Rhcl9tYXQgPC0gcmJpbmQoZF9zdGFyX21hdCx0KGRfc3RhcikpCn0KCnJvd25hbWVzKGRfc3Rhcl9tYXQpIDwtIG1vbnRoX3NlcmllcwpkX3N0YXJfbWF0IDwtIGFzLnh0cyhkX3N0YXJfbWF0KQpSX291dCA8LSBSW3llYXIoZGF0ZShSKSkgPiAyMDA0ICxdClJfb3V0IDwtIGFzLm1hdHJpeChSX291dFstMSxdKQpXX2luIDwtIGFzLm1hdHJpeChkX3N0YXJfbWF0Wy1ucm93KGRfc3Rhcl9tYXQpXSkKcl9wb3J0X29vcyA8LSBhcHBseShXX2luKlJfb3V0LDEsc3VtKQpuYW1lcyhyX3BvcnRfb29zKSA8LSByb3duYW1lcyhSX291dCkKcl9wb3J0X29vcyA8LSBhcy54dHMocl9wb3J0X29vcykKCldfbmFpdmUgPC0gbWF0cml4KGMoMC42LDAuNCksbnJvdyA9IG5yb3coV19pbiksMixieXJvdyA9IFQpCnJfcG9ydF9vb3NfbmFpdmUgPC0gYXBwbHkoV19uYWl2ZSpSX291dCwxLHN1bSkKbmFtZXMocl9wb3J0X29vc19uYWl2ZSkgPC0gIHJvd25hbWVzKFJfb3V0KQpyX3BvcnRfb29zX25haXZlIDwtIGFzLnh0cyhyX3BvcnRfb29zX25haXZlKQoKcl9wb3J0X29vcyA8LSBtZXJnZShyX3BvcnRfb29zLHJfcG9ydF9vb3NfbmFpdmUpIApuYW1lcyhyX3BvcnRfb29zKSA8LSBjKCJCYXllcyIsIk5haXZlIikKcGxvdChjdW1wcm9kKHJfcG9ydF9vb3MrMSksbWFpbiA9ICJDdW11bGF0aXZlIFJldHVybiIsbGVnZW5kLmxvYyA9ICJ0b3BsZWZ0IikKYGBgCkluIHRlcm1zIG9mIHJpc2stYWRqdXN0ZWQgcmV0dXJucywgd2UgY29tcHV0ZSB0aGUgU2hhcnBlLXJhdGlvIGZvciBlYWNoIHBvcnRmb2xpbyBhbmQgcmVwb3J0IGJlbG93CmBgYHtyfQpTUl9mIDwtIGZ1bmN0aW9uKHgpIHNxcnQoMTIpKm1lYW4oeCkvc2QoeCkKcmVzdWx0IDwtIGFwcGx5KHJfcG9ydF9vb3MsIDIsIFNSX2YpCnJvdW5kKGRhdGEuZnJhbWUodChyZXN1bHQpKSwyKQpgYGAKV2hpbGUgdGhlIEJheWVzIHJlc3VsdHMgaW4gbG93ZXIgdm9sYXRpbGl0eSwgaXQgaXMgYWxzbyBhc3NvY2lhdGVkIHdpdGggYSBsb3dlciByZXR1cm4uIFRha2VuIGFsdG9nZXRoZXIsIHdlIHJlYWxpemUgdGhhdCB0aGUgQmF5ZXMgcmVzdWx0cyBpbiBhIHJvdWdobHkgc2ltaWxhciBTaGFycGUgcmF0aW8uCgpJbiB0aGUgbmV4dCBleGFtcGxlLCB3ZSBtb2RpZnkgdGhlIGJhY2t0ZXN0aW5nIHByb2dyYW0gYSBsaXR0bGUuIEluIGRvaW5nIHNvLCB0aGUgcHJpb3IgaW5jb3Jwb3JhdGVzIHRoZSByZWNlbnQgb25lLW1vbnRoIHJldHVybiBhcyB0aGUgaW52ZXN0b3IncyBiZWxpZWYuIEZvciBleGFtcGxlLCBhdCB0aGUgZW5kIG9mIG1vbnRoICR0JCwgYWZ0ZXIgcmVhbGl6aW5nIHRoZSBtb250aGx5IHJldHVybnMgYmV0d2VlbiAkdC0xJCBhbmQgJHQkIGRlbm90ZWQgYnkgJFxtYXRoYmZ7eX1fdCQsIHRoZSBkZWNpc2lvbi1tYWtlciBzZXRzIHRoZSBwcmlvciB0byAkXGJvbGRzeW1ib2x7XG11fV8wID0gXG1hdGhiZnt5fV90JC4gVG8gZG8gc28sIHdlIHJlcGVhdCB0aGUgcHJldmlvdXMgY29tbWFuZHMsIGhvd2V2ZXIsIHdpdGggYSBzbWFsbCB0d2VhayBpbiBkZWZpbmluZyB0aGUgcHJpb3IgYG11XzBgLCBpLmUuLApgYGB7cixldmFsPUZBTFNFfQptdV8wIDwtICB0KHRhaWwoUl9zdWIsMSkpCmBgYApXZSBzdW1tYXJpemUgdGhlIGN1bXVsYXRpdmUgcmV0dXJuIGluIHRoZSBwbG90IGJlbG93OgpgYGB7cixmaWcuYWxpZ249ImNlbnRlciIsZWNobz1GQUxTRSxvdXQud2lkdGggPSAnNzUlJ30KZF9zdGFyX21hdCA8LSBkYXRhLmZyYW1lKCkKZm9yIChtb250aF9pIGluIG1vbnRoX3NlcmllcykgewogIGFscGhhIDwtIDEvKDErVF9zYW1wbGUpCiAgZSA8LSByZXAoMSxkKSAjIHZlY3RvciBvZiBvbmVzCiAgSV9tYXQgPC0gZGlhZyhkKSAjIGRpYWdvbmFsIG1hdHJpeAogIFJfc3ViIDwtIFJbZGF0ZShSKSA8PSBtb250aF9pLF0KICBSX3N1YiA8LSB0YWlsKFJfc3ViLFRfc2FtcGxlKSAjIHNhbXBsZSAKICB5X2JhciA8LSBhcHBseShSX3N1YiwyLG1lYW4pICMgc2FtcGxlIG1lYW4gdmVjdG9yCiAgbXVfMCA8LSAgdCh0YWlsKFJfc3ViLDEpKQogIFNpZ21hIDwtIHZhcihSX3N1YikgIyBjb3ZhcmlhbmNlIG1hdHJpeAogIFNpZ21hX2ludiA8LSBzb2x2ZShTaWdtYSkgIyBjb3ZhcmlhbmNlIG1hdHJpeCBpbnZlcnNlCiAgZF9nIDwtIFNpZ21hX2ludiUqJWUvc3VtKFNpZ21hX2ludikKICBCX21hdCA8LSBTaWdtYV9pbnYlKiUoSV9tYXQgLSBlJSoldChkX2cpICkKICBCX21hdF9hIDwtICgxLygxK2FscGhhKSkqQl9tYXQKICBkX3N0YXIgPC0gZF9nICsgYWxwaGEqQl9tYXRfYSUqJW11XzAgKyAoMS1hbHBoYSkqQl9tYXRfYSUqJXlfYmFyCiAgZF9zdGFyIDwtIGV4cChkX3N0YXIpLygxK2V4cChkX3N0YXIpKQogIGRfc3RhciA8LSBkX3N0YXIvc3VtKGRfc3RhcikKICBkX3N0YXJfbWF0IDwtIHJiaW5kKGRfc3Rhcl9tYXQsdChkX3N0YXIpKQp9Cgpyb3duYW1lcyhkX3N0YXJfbWF0KSA8LSBtb250aF9zZXJpZXMKZF9zdGFyX21hdCA8LSBhcy54dHMoZF9zdGFyX21hdCkKUl9vdXQgPC0gUlt5ZWFyKGRhdGUoUikpID4gMjAwNCAsXQpSX291dCA8LSBhcy5tYXRyaXgoUl9vdXRbLTEsXSkKV19pbiA8LSBhcy5tYXRyaXgoZF9zdGFyX21hdFstbnJvdyhkX3N0YXJfbWF0KV0pCnJfcG9ydF9vb3MgPC0gYXBwbHkoV19pbipSX291dCwxLHN1bSkKbmFtZXMocl9wb3J0X29vcykgPC0gcm93bmFtZXMoUl9vdXQpCnJfcG9ydF9vb3MgPC0gYXMueHRzKHJfcG9ydF9vb3MpCgpXX25haXZlIDwtIG1hdHJpeChjKDAuNiwwLjQpLG5yb3cgPSBucm93KFdfaW4pLDIsYnlyb3cgPSBUKQpyX3BvcnRfb29zX25haXZlIDwtIGFwcGx5KFdfbmFpdmUqUl9vdXQsMSxzdW0pCm5hbWVzKHJfcG9ydF9vb3NfbmFpdmUpIDwtICByb3duYW1lcyhSX291dCkKcl9wb3J0X29vc19uYWl2ZSA8LSBhcy54dHMocl9wb3J0X29vc19uYWl2ZSkKCnJfcG9ydF9vb3MgPC0gbWVyZ2Uocl9wb3J0X29vcyxyX3BvcnRfb29zX25haXZlKSAKbmFtZXMocl9wb3J0X29vcykgPC0gYygiQmF5ZXMiLCJOYWl2ZSIpCnBsb3QoY3VtcHJvZChyX3BvcnRfb29zKzEpLG1haW4gPSAiQ3VtdWxhdGl2ZSBSZXR1cm4iLGxlZ2VuZC5sb2MgPSAidG9wbGVmdCIpCmBgYApJbnRlcmVzdGluZ2x5LCB3ZSBvYnNlcnZlIHRoYXQgdGhlIEJheWVzIHBvcnRmb2xpbyBvdXRwZXJmb3JtcyB0aGUgbmFpdmUgZGVjaXNpb24gcnVsZS4gRnVydGhlcm1vcmUsIGluIHRlcm1zIG9mIHJpc2stYWRqdXN0ZWQgcGVyZm9ybWFuY2UsIHdlIG5vdGUgdGhhdCB0aGUgQmF5ZXMgcnVsZSBvdXRwZXJmb3JtcyB0aGUgbmFpdmUsIHJlc3VsdGluZyBpbiBhIFNoYXJwZSByYXRpbyBvZiBgciByb3VuZChyZXN1bHQsMilbMV1gOgpgYGB7cn0KcmVzdWx0IDwtIGFwcGx5KHJfcG9ydF9vb3MsIDIsIFNSX2YpCnJvdW5kKGRhdGEuZnJhbWUodChyZXN1bHQpKSwyKQpgYGAKCk9uZSBjb25jZXJuIHdpdGggdGhlIGFib3ZlIGlzIHRoYXQgdGhlIEJheWVzIHBvcnRmb2xpbyBtYXkgZXhoaWJpdCBhIGhpZ2hlciB0dXJub3Zlci4gVGFraW5nIGludG8gYWNjb3VudCB0cmFuc2FjdGlvbiBjb3N0cyAoVEMpLCBpdCBpcyB1bmNsZWFyIHdoZXRoZXIgdGhlIEJheWVzIHN0aWxsIG91dHBlcmZvcm1zLiBUbyBldmFsdWF0ZSB0aGlzLCB3ZSBjb25zaWRlciBhIHNpbWlsYXIgVEMgYW5hbHlzaXMgcHVyc3VlZCBpbiB0aGlzIFthcnRpY2xlXShodHRwczovL3JwdWJzLmNvbS9zaW1hYW44NC9wb3J0X29wdCkKYGBge3J9CldfdG8gPC0gV19pbiooMStSX291dCkKV190byA8LSB0KGFwcGx5KFdfdG8sMSxmdW5jdGlvbih4KSB0KHgpL3N1bSh4KSkpCldfdG8gPC0gV19pblstMSxdIC0gV190b1stbnJvdyhXX3RvKSxdIApXX3RvIDwtIG1lYW4oYXBwbHkoV190bywxLGZ1bmN0aW9uKHgpIHN1bShhYnMoeCkpICApKQpUT19iYXllcyA8LSBXX3RvCmBgYAp3aGVyZWFzIGZvciB0aGUgbmFpdmUgcG9ydGZvbGlvLCB3ZSBoYXZlCmBgYHtyfQpXX3RvIDwtIFdfbmFpdmUqKDErUl9vdXQpCldfdG8gPC0gdChhcHBseShXX3RvLDEsZnVuY3Rpb24oeCkgdCh4KS9zdW0oeCkpKQpXX3RvIDwtIFdfaW5bLTEsXSAtIFdfdG9bLW5yb3coV190byksXSAKV190byA8LSBtZWFuKGFwcGx5KFdfdG8sMSxmdW5jdGlvbih4KSBzdW0oYWJzKHgpKSAgKSkKZGF0YS5mcmFtZShCYXllcyA9IFRPX2JheWVzLE5haXZlID0gV190bykKYGBgCgpXaGlsZSB0aGUgQmF5ZXMgZG9lcyBpbmNsdWRlIHJlY2VudCByZXR1cm5zIGludG8gdGhlIGFsbG9jYXRpb24gYW5kIGlzIHN1YmplY3RlZCB0byBtb3JlIG5vaXNlLCBpdHMgaW5jb3Jwb3JhdGlvbiBzZWVtcyB0byBoYXZlIGEgbWl0aWdhdGluZyBlZmZlY3QuIFRoaXMgcmVzdWx0IGNvdWxkIHBvdGVudGlhbGx5IGJlIGR1ZSB0byB0aGUgcGVyc2lzdGVuY2Ugb2YgcmV0dXJucyBvdmVyIHRpbWUuIFRvIHJlbGF0ZSB0byB0aGlzIGNvbmplY3R1cmUsIGNvbnNpZGVyIHRoZSBhdXRvY29ycmVsYXRpb24gb2YgZWFjaCBFVEYgb3ZlciB0aW1lLiBVc2luZyB0aGUgc2FtZSBzYW1wbGUgc2l6ZSBgVF9zYW1wbGVgLCB3ZSBjb21wdXRlIHRoZSByb2xsaW5nIHdpbmRvdyBhdXRvY29ycmVsYXRpb24gZm9yIGVhY2ggYXNzZXQgYW5kIHBsb3QgdGhlIHJlc3VsdHMgYmVsb3cuCmBgYHtyLHdhcm5pbmc9RixtZXNzYWdlPUYsb3V0LndpZHRoID0gJzc1JScsZmlnLmFsaWduPSJjZW50ZXIifQpsaWJyYXJ5KHBseXIpClJfbGFnIDwtIG5hLm9taXQoY2JpbmQoUl9vdXQsbGFnLnh0cyhSX291dCwxKSkpCmNvcl9yb2xsIDwtIHJvbGxhcHBseShSX2xhZyxUX3NhbXBsZSwgZnVuY3Rpb24oeCkgYXMudmVjdG9yKGNvcih4KSksIGJ5LmNvbHVtbiA9IEYsIGFsaWduID0gInJpZ2h0IikKY29yX3JvbGwgPC0gYWxwbHkoY29yX3JvbGwsIDEsIGZ1bmN0aW9uKHgpIG1hdHJpeCh4LCBucm93ID0gbmNvbChSX2xhZykgKSAgICkKCnNweV9hciA8LSBzYXBwbHkoY29yX3JvbGwsZnVuY3Rpb24oeCkgeFszLDFdKQppZWZfYXIgPC0gc2FwcGx5KGNvcl9yb2xsLGZ1bmN0aW9uKHgpIHhbNCwyXSkKQVJfbWF0IDwtIGNiaW5kKHNweV9hcixpZWZfYXIpCnJvd25hbWVzKEFSX21hdCkgPC0gcm93bmFtZXMoUl9sYWcpW1Rfc2FtcGxlOm5yb3coUl9sYWcpXQpBUl9tYXQgPC0gYXMueHRzKEFSX21hdCkKbmFtZXMoQVJfbWF0KSA8LSBjKCJTUFkiLCJJRUYiKQpwbG90KEFSX21hdCxsZWdlbmQubG9jID0gImJvdHRvbWxlZnQiLG1haW4gPSAiQXV0b2NvcnJlbGF0aW9uIikKCmBgYApUaGUgYWJvdmUgYW5hbHlzaXMgcmVsaWVzIG9uIHRoZSBzYW1lIHRyaWNrIGRvbmUgaW4gdGhlIGFmb3JlbWVudGlvbmVkIFthcnRpY2xlXShodHRwczovL3JwdWJzLmNvbS9zaW1hYW44NC9wb3J0X29wdCkuIE92ZXJhbGwsIHdlIG5vdGUgdGhlIHNlcmlhbCBjb3JyZWxhdGlvbiB2YXJpZXMgb3ZlciB0aW1lLCB3aXRoIHZhbHVlcyByYW5naW5nIGJldHdlZW4gLTUzXCUgYW5kIDQ1XCUgZm9yIHRoZSBTUFksIHdoZXJlYXMgdGhlIGNvcnJlc3BvbmRpbmcgbnVtYmVycyBmb3IgSUVGIGFyZSAtNDZcJSBhbmQgMzVcJSwgcmVzcGVjdGl2ZWx5LiBHaXZlbiB0aGUgY29udGVtcG9yYW5lb3VzIG5lZ2F0aXZlIHJlbGF0aW9uIGJldHdlZW4gdGhlIHR3byBFVEZzLCB3ZSBhbHNvIG9ic2VydmUgdGhhdCBib3RoIGF1dG9jb3JyZWxhdGlvbnMgY28tbW92ZSB0b2dldGhlciBvdmVyIHRpbWUuIE5vbmV0aGVsZXNzLCBvdmVyIHRoZSBlbnRpcmUgc2FtcGxlIHBlcmlvZCwgd2Ugbm90ZSB0aGF0IGJvdGggY29lZmZpY2llbnRzIGFyZSBwb3NpdGl2ZS4KYGBge3J9CkFSX3Jlc3VsdCA8LSBkYXRhLmZyYW1lKFNQWSA9IGNvcihSJFNQWSxsYWcoUiRTUFkpLCB1c2UgPSAicGFpcndpc2UiKSwKICAgICAgICAgICAgICAgICAgICAgICAgSUVGID0gY29yKFIkSUVGLGxhZyhSJElFRiksIHVzZSA9ICJwYWlyd2lzZSIpKQpyb3duYW1lcyhBUl9yZXN1bHQpIDwtICJBdXRvY29ycmVsYXRpb24gKCUpIgpyb3VuZChBUl9yZXN1bHQqMTAwLDIpCmBgYAoKIyBSZW1hcmtzClRoZSBhbmFseXNpcyBhYm92ZSBoaWdobGlnaHRzIHNldmVyYWwgaW1wb3J0YW50IGFzcGVjdHMuIEZpcnN0LCB0aGUgYXJ0aWNsZSBpbGx1c3RyYXRlcyBhIHNpbXBsZSB0aGVvcnkgdG8gbGluayBiZWxpZWZzIGludG8gdGhlIHBvcnRmb2xpbyBwcm9ibGVtLiBTZWNvbmQsIHRoZSBlbXBpcmljYWwgcmVzdWx0cyBpbGx1c3RyYXRlIGEgYmFja3Rlc3RpbmcgcHJvY2VkdXJlIHVzaW5nIHR3byBhc3NldHMgYW5kIGV2YWx1YXRlIHRoZSBzZW5zaXRpdml0eSBvZiB0aGUgcmVzdWx0cyB1c2luZyBkaWZmZXJlbnQgcHJpb3JzLiBGaW5hbGx5LCB0aGUgYWJvdmUgcGFyYWRpZ20gY291bGQgcHJvdmlkZSB0aGVvcmV0aWNhbCBqdXN0aWZpY2F0aW9uIGZvciBpbmNvcnBvcmF0aW5nIHByZWRpY3RpdmUgbW9kZWxzIGludG8gbWVhbi12YXJpYW5jZSBvcHRpbWl6YXRpb24uIEkgbGVhdmUgdGhpcyBmb3IgZnV0dXJlIHJlc2VhcmNoLiAgCgoKCiMgUmVmZXJlbmNlcyAKCjEuIEJsYWNrLCBGLiwgJiBMaXR0ZXJtYW4sIFIuICgxOTkwKS4gQXNzZXQgYWxsb2NhdGlvbjogY29tYmluaW5nIGludmVzdG9yIHZpZXdzIHdpdGggbWFya2V0IGVxdWlsaWJyaXVtLiBHb2xkbWFuIFNhY2hzIEZpeGVkIEluY29tZSBSZXNlYXJjaCwgMTE1LgoKMi4gRGVNaWd1ZWwsIFYuLCBHYXJsYXBwaSwgTC4sIE5vZ2FsZXMsIEYuIEouLCAmIFVwcGFsLCBSLiAoMjAwOSkuIEEgZ2VuZXJhbGl6ZWQgYXBwcm9hY2ggdG8gcG9ydGZvbGlvIG9wdGltaXphdGlvbjogSW1wcm92aW5nIHBlcmZvcm1hbmNlIGJ5IGNvbnN0cmFpbmluZyBwb3J0Zm9saW8gbm9ybXMuIE1hbmFnZW1lbnQgc2NpZW5jZSwgNTUoNSksIDc5OC04MTIuCgozLiBKb3Jpb24sIFAuICgxOTg2KS4gQmF5ZXMtU3RlaW4gZXN0aW1hdGlvbiBmb3IgcG9ydGZvbGlvIGFuYWx5c2lzLiBKb3VybmFsIG9mIEZpbmFuY2lhbCBhbmQgUXVhbnRpdGF0aXZlIGFuYWx5c2lzLCAyMSgzKSwgMjc5LTI5Mi4KCgo0LiBLbGVpbiwgUi4gVy4sICYgQmF3YSwgVi4gUy4gKDE5NzYpLiBUaGUgZWZmZWN0IG9mIGVzdGltYXRpb24gcmlzayBvbiBvcHRpbWFsIHBvcnRmb2xpbyBjaG9pY2UuIEpvdXJuYWwgb2YgZmluYW5jaWFsIGVjb25vbWljcywgMygzKSwgMjE1LTIzMS4KCgo1LiBTaW1hYW4sIE0uLCBTaW1hYW4sIFkuLCAmIFRhbmcsIFkuICgyMDE4KS4gRXN0aW1hdGlvbiBlcnJvciBpbiBtZWFuIHJldHVybnMgYW5kIHRoZSBtZWFuLXZhcmlhbmNlIGVmZmljaWVudCBmcm9udGllci4gSW50ZXJuYXRpb25hbCBSZXZpZXcgb2YgRWNvbm9taWNzICYgRmluYW5jZSwgNTYsIDEwOS0xMjQu