Log-normal Distribution

The log-normal distributions have been widely used in many different fields such as finance and economics, engineering and reliability, environmental science, medical and biology etc.

If \(X\) follows a lognormal distribution:

\[ f(x; \mu, \sigma^2) = \frac{1}{x\sqrt{2\pi \sigma^2}} \exp\left[-\frac{(\ln x - \mu)^2}{2\sigma^2}\right], \quad x > 0 \]

where \(\mu \in \mathbb{R}\) is the mean of \(\ln X\) and \(\sigma^2 > 0\) is the variance of \(\ln X\).

Caution: \(\mu\) and \(\sigma^2\) are not population mean and variance of the lognormal distribution!. Instead, we will use \(\mu_{LN}\) and \(\sigma_{LN}^2\) to denote the lognormal mean and variance respectively.

For an i.i.d. random sample \(x_1, x_2, \dots, x_n\):

\[\begin{align*} \ell(\mu, \sigma^2) &= \sum_{i=1}^n \ln f(x_i; \mu, \sigma^2) \\ &= -\frac{n}{2} \ln(2\pi) - \frac{n}{2} \ln \sigma^2 - \sum_{i=1}^n \ln x_i - \frac{1}{2\sigma^2} \sum_{i=1}^n (\ln x_i - \mu)^2 \end{align*}\]

The \(k\)-th moment of log normal distribution given by

\[ \boxed{ \mathbb{E}[X^k] = \exp\left( k\mu + \frac{1}{2} k^2 \sigma^2 \right). } \]

Particularly, the mean of the above lognormal distribution, denoted by \(\mu_{LN}\), is given by

\[ \mu_{LN} = \mathbb{E}[X] = \exp\left( \mu + \frac{1}{2} \sigma^2 \right). \]

Once the parameters were estimated, say \((\overline{\mu}, \overline{\sigma^2})\), we can use the plug-in Principle to estimate the lognormal mean by

\[ \boxed{\overline{\mu_{LN}} = \exp\left( \overline{\mu} + \frac{1}{2} \overline{\sigma^2} \right).} \]

Working Dataset: A reservoir engineer at an oil exploration company has recently drilled 50 new wells in a shale formation. According to geological theory, the size of oil reserves in this type of formation is often modeled using a log-normal distribution. The engineer is responsible for estimating the typical reserve size and quantifying the uncertainty of these estimates for a presentation to senior management. The estimated ultimate recovery (EUR) for the 50 wells, measured in thousands of barrels (Mbbl), is as follows:

17.3, 24.8, 8.2, 31.5, 14.1, 42.7, 11.9, 55.3, 21.4, 9.7, 36.2, 18.6, 63.1, 13.2, 28.9, 
47.5, 19.8, 7.5, 33.4, 52.1, 16.0, 25.9, 38.7, 10.3, 44.2, 22.5, 58.6, 12.8, 30.3, 48.9, 
20.1, 35.4, 15.7, 60.2, 26.7, 41.3, 18.1, 53.8, 23.9, 46.2, 29.4, 37.6, 14.9, 50.5, 32.8, 
19.3, 56.7, 11.2, 39.5, 27.1

This assignment focuses on finding the asymptotic sampling distributions of the MLE \(\hat{\mu}\) and \(\hat{\sigma^2}\) corresponding to \(\mu\) and \(\sigma^2\) based on an environmental study data.


# Oil reserve data
x <- c(
  17.3, 24.8, 8.2, 31.5, 14.1, 42.7, 11.9, 55.3, 21.4, 9.7,
  36.2, 18.6, 63.1, 13.2, 28.9, 47.5, 19.8, 7.5, 33.4, 52.1,
  16.0, 25.9, 38.7, 10.3, 44.2, 22.5, 58.6, 12.8, 30.3, 48.9,
  20.1, 35.4, 15.7, 60.2, 26.7, 41.3, 18.1, 53.8, 23.9, 46.2,
  29.4, 37.6, 14.9, 50.5, 32.8, 19.3, 56.7, 11.2, 39.5, 27.1
)

# Sample size
n <- length(x)

Question 1: Method of Moments Estimation (MME) of \(\mu\) and \(\sigma^2\)

Estimate the parameters \(\mu\) and \(\sigma^2\) (caution: not \(\sigma\)!) from the raw oil reserve data using the given \(k\)-th moment function. Organize your work into three parts:

  1. Derive the system of two equations for the method of moments estimators (MMEs) of \(\mu\) and \(\sigma^2\).

Let the first two sample moments be

\[ m_1=\frac{1}{n}\sum_{i=1}^n x_i,\qquad m_2=\frac{1}{n}\sum_{i=1}^n x_i^2. \]

For the lognormal distribution,

\[ \mu_1=\mathbb{E}[X]=\exp\left(\mu+\frac{1}{2}\sigma^2\right) \] and \[ \mu_2=\mathbb{E}[X^2]=\exp\left(2\mu+2\sigma^2\right). \]

The method of moments sets

\[ \exp\left(\mu+\frac{1}{2}\sigma^2\right)=m_1 \]

\[ \exp\left(2\mu+2\sigma^2\right)=m_2. \]

These are two MME equations used to solve for \(\mu\) and \(\sigma^2\).

  1. Derive the closed-form expressions for the MMEs of \(\mu\), \(\sigma^2\), and \(\mu_{LN}\), denoted by \(\widetilde{\mu}\), \(\widetilde{\sigma^2}\), and \(\widetilde{\mu_{LN}}\), respectively.

Taking logarithms gives

\[ \mu+\frac{1}{2}\sigma^2=\ln(m_1) \]

\[ 2\mu+2\sigma^2=\ln(m_2). \]

From the first equation,

\[ 2\mu+\sigma^2=2\ln(m_1). \]

Subtracting this from the second equation gives

\[ \sigma^2=\ln(m_2)-2\ln(m_1)=\ln\left(\frac{m_2}{m_1^2}\right). \]

Thus,

\[ \widetilde{\sigma^2}=\ln\left(\frac{m_2}{m_1^2}\right). \]

Substituting into the first equation,

\[ \widetilde{\mu}=\ln(m_1)-\frac{1}{2}\widetilde{\sigma^2}. \]

The plug-in estimator of the lognormal mean is

\[ \widetilde{\mu_{LN}}=\exp\left(\widetilde{\mu}+\frac{1}{2}\widetilde{\sigma^2}\right) \]

Since \(m_1=\bar X\), we have

\[ \boxed{\widetilde{\mu_{LN}}=\bar X} \]

  1. Write an R function that outputs the MMEs \(\widetilde{\mu}\), \(\widetilde{\sigma^2}\), and \(\widetilde{\mu_{LN}}\) based on the given data set.
# Method of Moments estimation for lognormal parameters
lognormal.mme <- function(x){
  m1 <- mean(x) #First sample moment
  m2 <- mean(x^2) #Second sample moment

  #MME of sigma^2 derived from moment equations   
  sigma2.tilde <- log(m2 / (m1^2))
  
  # MME of mu obtained by substituting sigma^2 into first equation
  mu.tilde <- log(m1) - 0.5 * sigma2.tilde
  
  # Plug-in estimator for the lognormal mean
  muLN.tilde <- exp(mu.tilde + 0.5 * sigma2.tilde)
  
  # Return the estimates
  data.frame(
    mu_tilde = mu.tilde,
    sigma2_tilde = sigma2.tilde,
    muLN_tilde = muLN.tilde
  )
}

# Return the estimates
lognormal.mme(x)
  mu_tilde sigma2_tilde muLN_tilde
1 3.301269    0.2339652     30.516


Question 2: Finding the MLE of \(\mu\) and \(\sigma^2\)

This question involves two parts:

(1). Derive the score functions (i.e., the gradient of the log-likelihood) for the parameters of the log-normal distribution, and set them to zero to obtain the system of score equations. Begin with the full log-likelihood and compute its partial derivatives with respect to \(\mu\) and \(\sigma^2\). [Hint: letting \(\beta = \sigma^2\) may simplify differentiation.]

Assume that \(\{x_1, x_2, \cdots, x_n \} \to \text{ LN }(\mu, \sigma^2)\) with density function given by

\[ \ell(\mu, \sigma^2) = -\frac{n}{2} \ln(2\pi) - n \ln \sigma - \sum_{i=1}^n \ln x_i - \frac{1}{2\sigma^2} \sum_{i=1}^n (\ln x_i - \mu)^2 \] The log-likelihood function is

\[ \ell(\mu,\sigma^2)=-\frac{n}{2}\ln(2\pi)-\frac{n}{2}\ln(\sigma^2)-\sum_{i=1}^n \ln x_i-\frac{1}{2\sigma^2}\sum_{i=1}^n(\ln x_i-\mu)^2. \]

Let \(\beta=\sigma^2\).

\[ \frac{\partial \ell}{\partial \mu}=\frac{1}{\beta}\sum_{i=1}^n(\ln x_i-\mu). \]

Setting this equal to zero gives \[ \hat{\mu}=\frac{1}{n}\sum_{i=1}^n \ln x_i. \]

\[ \frac{\partial \ell}{\partial \beta}=-\frac{n}{2\beta}+\frac{1}{2\beta^2}\sum_{i=1}^n(\ln x_i-\mu)^2. \]

Setting this equal to zero yields

\[ \widehat{\sigma^2}=\frac{1}{n}\sum_{i=1}^n(\ln x_i-\hat{\mu})^2. \]

(2). Perform some algebra to find the closed form of the MLE of \(\mu\) and \(\sigma^2\), denoted by \(\widehat{\mu}\) and \(\widehat{\sigma^2}\).

\[ \boxed{\hat{\mu}=\frac{1}{n}\sum_{i=1}^n \ln x_i} \] and

\[ \boxed{\widehat{\sigma^2}=\frac{1}{n}\sum_{i=1}^n(\ln x_i-\hat{\mu})^2}. \]

(3). Recall that lognormal population mean (i.e., the first moment) is

\[ \mu_{LN} = \mathbb{E}[X] = \exp\left( \mu + \frac{1}{2} \sigma^2 \right). \]

Using the relationship between variance and the first and second moments, \(\text{Var}(X) = \mathbb{E}[X^2] - \left(\mathbb{E}[X]\right)^2\), we derive the population variance of the lognormal distribution, denoted as \(\sigma_{\text{LN}}^2\). This result will be used in applying the Central Limit Theorem in subsequent questions

The lognormal mean is

\[ \mu_{LN}=\exp\left(\mu+\frac{1}{2}\sigma^2\right). \] Also, \[ \mathbb{E}[X^2]=\exp(2\mu+2\sigma^2). \] Therefore \[ \sigma_{LN}^2=\mathbb{E}[X^2]-(\mathbb{E}[X])^2=\exp(2\mu+2\sigma^2)-\exp(2\mu+\sigma^2). \]

Equivalently, \[ \sigma_{LN}^2=\exp(2\mu+\sigma^2)\left(\exp(\sigma^2)-1\right). \]

Question 3: Sampling Distribution of Lognormal Sample Mean \(\widehat{\mu_{LN}}\)

We have derived two different estimators of lognormal population mean \(\mu_{LN}\). This Question focuses on the sampling distribution of lognormal sample sample means based on MLE. The following are detailed instructions.

(1). Write an R function to estimate the MLE of \(\mu\) and \(\sigma^2\), denoted by \(\widehat{\mu}\) and \(\widehat{\sigma^2}\) and return the MLE of \(\mu_{LN}\), denoted by \(\widehat{\mu_{LN}}\).

# Function to compute MLE of mu, sigma^2, and lognormal mean
lognormal_mle <- function(x){

  y <- log(x)# Take natural log of data
  mu_hat <- mean(y) # MLE of mu 

  # MLE of sigma^2 
  sigma2_hat <- mean((y - mu_hat)^2)

  # Plug-in estimate of lognormal population mean
  muLN_hat <- exp(mu_hat + 0.5 * sigma2_hat)

  # Return estimates
  c(mu_hat = mu_hat,
    sigma2_hat = sigma2_hat,
    muLN_hat = muLN_hat)
}

# Compute MLE estimates
lognormal_mle(x)
    mu_hat sigma2_hat   muLN_hat 
 3.2685359  0.3271989 30.9426444 

(2). Take 1000 Bootstrap samples from the raw oil data set. For each bootstrap sample, call the above R function to find the bootstrap MLE of \(\mu_{LN}\), denoted by \(\widehat{\mu_{LN}^*}^{(1)}, \widehat{\mu_{LN}^*}^{(2)}, \cdots, \widehat{\mu_{LN}^*}^{(1000)}\).

set.seed(123)

B <- 1000 # Number of bootstrap samples
n <- length(x)

boot_muLN <- NULL # Vector to store bootstrap estimates

# Bootstrap loop
for(i in 1:B){

  # Draw bootstrap sample with replacement
  sample_i <- sample(x, size = n, replace = TRUE)

  # Compute bootstrap MLE of lognormal mean
  boot_muLN[i] <- lognormal_mle(sample_i)[3]
}

(3). Using kernel density estimation approach to estimate the bootstrap density curves based on the bootstrap MLEs: \(\widehat{\mu_{LN}^*}^{(1)}, \widehat{\mu_{LN}^*}^{(2)}, \cdots, \widehat{\mu_{LN}^*}^{(1000)}\).

# Plot histogram of bootstrap estimates
hist(boot_muLN,
     probability = TRUE,
     breaks = 20,
     main = "Bootstrap Sampling Distribution of mu_LN",
     xlab = "Bootstrap Estimates of mu_LN")

# Add kernel density curve
lines(density(boot_muLN),
      col = "blue",
      lwd = 2)

(4). In order to find the asymptotic sampling distribution using the central limit theorem (CLT). That is, when sample size is large,

\[ \bar{X} \to N \left(\mu_{LN}, \frac{\sigma_{LN}}{\sqrt{n}}\right) \]

where \(\mu_{LN}\) and \(\sigma_{LN}\) can be estimated by using the plug-in principle of MLE. Based on the asymptotic sampling distribution of lognormal sample mean \(\bar{X}\), add the asymptotic density curve to the above Bootstrap kernel density curve.

# Obtain MLE estimates from original data
mle_out <- lognormal_mle(x)

mu_hat <- mle_out[1]
sigma2_hat <- mle_out[2]
muLN_hat <- mle_out[3]

# Plug-in estimate of lognormal variance
sigma2LN_hat <- exp(2 * mu_hat + sigma2_hat) * (exp(sigma2_hat) - 1)

# Standard deviation of lognormal distribution
sigmaLN_hat <- sqrt(sigma2LN_hat)

# Standard error of the sample mean using CLT
asym_se <- sigmaLN_hat / sqrt(n)

# Create grid of values for asymptotic density
grid_x <- seq(min(boot_muLN), max(boot_muLN), length.out = 400)

# Compute asymptotic normal density
asym_density <- dnorm(grid_x,
                      mean = muLN_hat,
                      sd = asym_se)

# Plot bootstrap distribution again
hist(boot_muLN,
     probability = TRUE,
     breaks = 20,
     main = "Bootstrap vs Asymptotic Sampling Distribution",
     xlab = "mu_LN")

# Add bootstrap kernel density
lines(density(boot_muLN),
      col = "blue",
      lwd = 2)

# Add asymptotic normal curve
lines(grid_x,
      asym_density,
      col = "red",
      lwd = 2,
      lty = 2)

# Add legend
legend("topright",
       legend = c("Bootstrap KDE", "Asymptotic Normal"),
       col = c("blue", "red"),
       lwd = 2,
       lty = c(1,2))

(5). Write a short summary to compare the two sampling distributions of the sample mean of the lognormal distribution.

Answer: The bootstrap distribution is obtained by resampling the data, so it reflects the shape of the data more directly. The asymptotic distribution is based on the Central Limit Theorem and assumes a Normal approximation. If the two curves are similar, the Normal approximation works well. If they differ, the bootstrap distribution gives a better description of the estimator’s sampling behavior.

Question 4: Extra Bonus Credit

Derive the Hessian matrix by computing the second-order partial derivatives of the log-likelihood function (with respect to \(\mu\) and \(\sigma^2\)). Then, translate the derived Hessian into an R function that takes the MLEs of the parameters and the data as inputs and returns the Hessian matrix. Finally, compare your analytically derived Hessian with the numerical Hessian returned by optim().

Let \(\beta=\sigma^2\).

The Hessian matrix of the log-likelihood is obtained from the second derivatives.

\[ \frac{\partial^2 \ell}{\partial \mu^2}=-\frac{n}{\beta} \]

\[ \frac{\partial^2 \ell}{\partial \mu \partial\beta}=-\frac{1}{\beta^2}\sum_{i=1}^n(\ln x_i-\mu) \]

\[ \frac{\partial^2 \ell}{\partial \beta^2}=\frac{n}{2\beta^2}-\frac{1}{\beta^3}\sum_{i=1}^n(\ln x_i-\mu)^2 \]

Thus the Hessian matrix is

\[ H(\mu,\beta) =\begin{bmatrix}-\frac{n}{\beta}&-\frac{1}{\beta^2}\sum_{i=1}^n(\ln x_i-\mu)\\-\frac{1}{\beta^2}\sum_{i=1}^n(\ln x_i-\mu)&\frac{n}{2\beta^2}-\frac{1}{\beta^3}\sum_{i=1}^n(\ln x_i-\mu)^2\end{bmatrix}. \]

# Function to compute analytic Hessian matrix of the log-likelihood
lognormal_hessian <- function(mu, sigma2, x){

  # Log transformed data
  y <- log(x)

  # Sample size
  n <- length(x)

  # Intermediate sums
  s1 <- sum(y - mu)
  s2 <- sum((y - mu)^2)

  # Second derivative with respect to mu
  h11 <- -n / sigma2

  # Cross derivative
  h12 <- -s1 / (sigma2^2)

  # Symmetry of Hessian
  h21 <- h12

  # Second derivative with respect to sigma^2
  h22 <- n / (2 * sigma2^2) - s2 / (sigma2^3)

  # Construct Hessian matrix
  matrix(c(h11, h12,
           h21, h22),
         nrow = 2,
         byrow = TRUE)
}

Compare with numerical Hessian from optim ()

# Negative log-likelihood for optim()
negloglik_lognormal <- function(par, x){
  mu <- par[1]
  sigma2 <- par[2]
  if(sigma2 <= 0) return(Inf)
  
  n <- length(x)
  y <- log(x)
  
  ll <- -n/2 * log(2*pi) - n/2 * log(sigma2) - sum(log(x)) -
    (1/(2*sigma2)) * sum((y - mu)^2)
  
  return(-ll)
}

# Gradient of negative log-likelihood
neggrad_lognormal <- function(par, x){
  mu <- par[1]
  sigma2 <- par[2]
  y <- log(x)
  n <- length(x)
  
  dmu <- -(1/sigma2) * sum(y - mu)
  dsigma2 <- n/(2*sigma2) - sum((y - mu)^2)/(2 * sigma2^2)
  
  return(c(dmu, dsigma2))
}

# optim
init <- c(mean(log(x)), var(log(x)))
fit <- optim(par = init,
             fn = negloglik_lognormal,
             gr = neggrad_lognormal,
             x = x,
             method = "L-BFGS-B",
             lower = c(-Inf, 1e-8),
             hessian = TRUE)

mu_hat_opt <- fit$par[1]
sigma2_hat_opt <- fit$par[2]

# Analytic Hessian of log-likelihood
H_analytic <- lognormal_hessian(mu_hat_opt, sigma2_hat_opt, x)

# Numerical Hessian from optim() is for negative log-likelihood
H_numeric <- fit$hessian

H_analytic
              [,1]          [,2]
[1,] -1.528111e+02  1.037003e-13
[2,]  1.037003e-13 -2.335090e+02
-H_analytic
              [,1]          [,2]
[1,]  1.528111e+02 -1.037003e-13
[2,] -1.037003e-13  2.335090e+02
H_numeric
              [,1]          [,2]
[1,]  1.528111e+02 -5.185066e-14
[2,] -5.185066e-14  2.335155e+02

The analytic Hessian and the numerical Hessian from optim() should be very close, except for small numerical differences due to finite-difference approximation. Since optim() is minimizing the negative log-likelihood, its Hessian should match the negative of the analytic Hessian of the log-likelihood.

LS0tDQp0aXRsZTogIlNUQSA1MDYgLSBNaWR0ZXJtIEV4YW1pbmF0aW9uIFNwcmluZyAyMDI2ICINCmF1dGhvcjogIiBYaWFveWluZyBNYSAiDQpkYXRlOiAiIER1ZTogU3VuZGF5LCAwMy8wOCBhdCAxMTo1OSBQTSINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDogDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDQNCiAgICB0b2NfZmxvYXQ6IHllcw0KICAgIG51bWJlcl9zZWN0aW9uczogbm8NCiAgICB0b2NfY29sbGFwc2VkOiB5ZXMNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMNCiAgICBzbW9vdGhfc2Nyb2xsOiB5ZXMNCiAgICBoaWdobGlnaHQ6IG1vbm9jaHJvbWUNCiAgICB0aGVtZTogc3BhY2VsYWINCiAgcGRmX2RvY3VtZW50OiANCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogNA0KICAgIGZpZ19jYXB0aW9uOiB5ZXMNCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcw0KICAgIGZpZ193aWR0aDogMw0KICAgIGZpZ19oZWlnaHQ6IDMNCiAgd29yZF9kb2N1bWVudDogDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDQNCiAgICBmaWdfY2FwdGlvbjogeWVzDQogICAga2VlcF9tZDogeWVzDQplZGl0b3Jfb3B0aW9uczogDQogIGNodW5rX291dHB1dF90eXBlOiBpbmxpbmUNCi0tLQ0KDQpgYGB7Y3NzLCBlY2hvID0gRkFMU0V9DQojVE9DOjpiZWZvcmUgew0KICBjb250ZW50OiAiVGFibGUgb2YgQ29udGVudHMiOw0KICBmb250LXdlaWdodDogYm9sZDsNCiAgZm9udC1zaXplOiAxLjJlbTsNCiAgZGlzcGxheTogYmxvY2s7DQogIGNvbG9yOiBuYXZ5Ow0KICBtYXJnaW4tYm90dG9tOiAxMHB4Ow0KfQ0KDQoNCmRpdiNUT0MgbGkgeyAgICAgLyogdGFibGUgb2YgY29udGVudCAgKi8NCiAgICBsaXN0LXN0eWxlOnVwcGVyLXJvbWFuOw0KICAgIGJhY2tncm91bmQtaW1hZ2U6bm9uZTsNCiAgICBiYWNrZ3JvdW5kLXJlcGVhdDpub25lOw0KICAgIGJhY2tncm91bmQtcG9zaXRpb246MDsNCn0NCg0KaDEudGl0bGUgeyAgICAvKiBsZXZlbCAxIGhlYWRlciBvZiB0aXRsZSAgKi8NCiAgZm9udC1zaXplOiAyMnB4Ow0KICBmb250LXdlaWdodDogYm9sZDsNCiAgY29sb3I6IERhcmtSZWQ7DQogIHRleHQtYWxpZ246IGNlbnRlcjsNCiAgZm9udC1mYW1pbHk6ICJHaWxsIFNhbnMiLCBzYW5zLXNlcmlmOw0KfQ0KDQpoNC5hdXRob3IgeyAvKiBIZWFkZXIgNCAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICBmb250LXNpemU6IDE1cHg7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KICBmb250LWZhbWlseTogc3lzdGVtLXVpOw0KICBjb2xvcjogbmF2eTsNCiAgdGV4dC1hbGlnbjogY2VudGVyOw0KfQ0KDQpoNC5kYXRlIHsgLyogSGVhZGVyIDQgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgZm9udC1zaXplOiAxOHB4Ow0KICBmb250LXdlaWdodDogYm9sZDsNCiAgZm9udC1mYW1pbHk6ICJHaWxsIFNhbnMiLCBzYW5zLXNlcmlmOw0KICBjb2xvcjogRGFya0JsdWU7DQogIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCg0KaDEgeyAvKiBIZWFkZXIgMSAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICAgIGZvbnQtc2l6ZTogMjBweDsNCiAgICBmb250LXdlaWdodDogYm9sZDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogZGFya3JlZDsNCiAgICB0ZXh0LWFsaWduOiBjZW50ZXI7DQp9DQoNCmgyIHsgLyogSGVhZGVyIDIgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgICBmb250LXNpemU6IDE4cHg7DQogICAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IG5hdnk7DQogICAgdGV4dC1hbGlnbjogbGVmdDsNCn0NCg0KaDMgeyAvKiBIZWFkZXIgMyAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICAgIGZvbnQtc2l6ZTogMTZweDsNCiAgICBmb250LXdlaWdodDogYm9sZDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogbmF2eTsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KDQpoNCB7IC8qIEhlYWRlciA0IC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovDQogICAgZm9udC1zaXplOiAxNHB4Ow0KICBmb250LXdlaWdodDogYm9sZDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogZGFya3JlZDsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KDQovKiBBZGQgZG90cyBhZnRlciBudW1iZXJlZCBoZWFkZXJzICovDQouaGVhZGVyLXNlY3Rpb24tbnVtYmVyOjphZnRlciB7DQogIGNvbnRlbnQ6ICIuIjsNCg0KYm9keSB7IGJhY2tncm91bmQtY29sb3I6d2hpdGU7IH0NCg0KLmhpZ2hsaWdodG1lIHsgYmFja2dyb3VuZC1jb2xvcjp5ZWxsb3c7IH0NCg0KcCB7IGJhY2tncm91bmQtY29sb3I6d2hpdGU7IH0NCg0KfQ0KYGBgDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0KIyBjb2RlIGNodW5rIHNwZWNpZmllcyB3aGV0aGVyIHRoZSBSIGNvZGUsIHdhcm5pbmdzLCBhbmQgb3V0cHV0IA0KIyB3aWxsIGJlIGluY2x1ZGVkIGluIHRoZSBvdXRwdXQgZmlsZXMuDQppZiAoIXJlcXVpcmUoImtuaXRyIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoImtuaXRyIikNCiAgIGxpYnJhcnkoa25pdHIpDQp9DQppZiAoIXJlcXVpcmUoInBhbmRlciIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJwYW5kZXIiKQ0KICAgbGlicmFyeShwYW5kZXIpDQp9DQppZiAoIXJlcXVpcmUoImdncGxvdDIiKSkgew0KICBpbnN0YWxsLnBhY2thZ2VzKCJnZ3Bsb3QyIikNCiAgbGlicmFyeShnZ3Bsb3QyKQ0KfQ0KaWYgKCFyZXF1aXJlKCJ0aWR5dmVyc2UiKSkgew0KICBpbnN0YWxsLnBhY2thZ2VzKCJ0aWR5dmVyc2UiKQ0KICBsaWJyYXJ5KHRpZHl2ZXJzZSkNCn0NCg0KaWYgKCFyZXF1aXJlKCJwbG90bHkiKSkgew0KICBpbnN0YWxsLnBhY2thZ2VzKCJwbG90bHkiKQ0KICBsaWJyYXJ5KHBsb3RseSkNCn0NCiMjIyMNCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgICAgICAgIyBpbmNsdWRlIGNvZGUgY2h1bmsgaW4gdGhlIG91dHB1dCBmaWxlDQogICAgICAgICAgICAgICAgICAgICAgd2FybmluZyA9IEZBTFNFLCAgICMgc29tZXRpbWVzLCB5b3UgY29kZSBtYXkgcHJvZHVjZSB3YXJuaW5nIG1lc3NhZ2VzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHlvdSBjYW4gY2hvb3NlIHRvIGluY2x1ZGUgdGhlIHdhcm5pbmcgbWVzc2FnZXMgaW4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyB0aGUgb3V0cHV0IGZpbGUuIA0KICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdHMgPSBUUlVFLCAgICAjIHlvdSBjYW4gYWxzbyBkZWNpZGUgd2hldGhlciB0byBpbmNsdWRlIHRoZSBvdXRwdXQNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBpbiB0aGUgb3V0cHV0IGZpbGUuDQogICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZSA9IEZBTFNFLA0KICAgICAgICAgICAgICAgICAgICAgIGNvbW1lbnQgPSBOQQ0KICAgICAgICAgICAgICAgICAgICAgICkgIA0KYGBgDQogDQogXA0KIA0KDQojIyAqKkxvZy1ub3JtYWwgRGlzdHJpYnV0aW9uKioNCg0KVGhlIGxvZy1ub3JtYWwgZGlzdHJpYnV0aW9ucyBoYXZlIGJlZW4gd2lkZWx5IHVzZWQgaW4gbWFueSBkaWZmZXJlbnQgZmllbGRzIHN1Y2ggYXMgZmluYW5jZSBhbmQgZWNvbm9taWNzLCBlbmdpbmVlcmluZyBhbmQgcmVsaWFiaWxpdHksIGVudmlyb25tZW50YWwgc2NpZW5jZSwgbWVkaWNhbCBhbmQgYmlvbG9neSBldGMuIA0KDQpJZiAkWCQgZm9sbG93cyBhIGxvZ25vcm1hbCBkaXN0cmlidXRpb246DQoNCiQkDQpmKHg7IFxtdSwgXHNpZ21hXjIpID0gXGZyYWN7MX17eFxzcXJ0ezJccGkgXHNpZ21hXjJ9fSANClxleHBcbGVmdFstXGZyYWN7KFxsbiB4IC0gXG11KV4yfXsyXHNpZ21hXjJ9XHJpZ2h0XSwgXHF1YWQgeCA+IDANCiQkDQoNCndoZXJlICAkXG11IFxpbiBcbWF0aGJie1J9JCBpcyB0aGUgbWVhbiBvZiAkXGxuIFgkIGFuZCAkXHNpZ21hXjIgPiAwJCBpcyB0aGUgdmFyaWFuY2Ugb2YgJFxsbiBYJC4NCg0KPGZvbnQgY29sb3IgPSJyZWQiPioqXGNvbG9ye3JlZH1DYXV0aW9uOioqICpcY29sb3J7cmVkfSRcbXUkIGFuZCAkXHNpZ21hXjIkIGFyZSBub3QgcG9wdWxhdGlvbiBtZWFuIGFuZCB2YXJpYW5jZSBvZiB0aGUgbG9nbm9ybWFsIGRpc3RyaWJ1dGlvbiEqLiAqKlxjb2xvcntibHVlfSBJbnN0ZWFkLCB3ZSB3aWxsIHVzZSAkXG11X3tMTn0kIGFuZCAkXHNpZ21hX3tMTn1eMiQgdG8gZGVub3RlIHRoZSBsb2dub3JtYWwgbWVhbiBhbmQgdmFyaWFuY2UgcmVzcGVjdGl2ZWx5LioqPC9mb250Pg0KDQoNCkZvciBhbiBpLmkuZC4gcmFuZG9tIHNhbXBsZSAkeF8xLCB4XzIsIFxkb3RzLCB4X24kOg0KDQoNClxiZWdpbnthbGlnbip9DQpcZWxsKFxtdSwgXHNpZ21hXjIpICY9IFxzdW1fe2k9MX1ebiBcbG4gZih4X2k7IFxtdSwgXHNpZ21hXjIpIFxcDQomPSAtXGZyYWN7bn17Mn0gXGxuKDJccGkpIC0gXGZyYWN7bn17Mn0gXGxuIFxzaWdtYV4yIC0gXHN1bV97aT0xfV5uIFxsbiB4X2kgDQogICAtIFxmcmFjezF9ezJcc2lnbWFeMn0gXHN1bV97aT0xfV5uIChcbG4geF9pIC0gXG11KV4yDQpcZW5ke2FsaWduKn0NCg0KDQpUaGUgJGskLXRoIG1vbWVudCBvZiBsb2cgbm9ybWFsIGRpc3RyaWJ1dGlvbiBnaXZlbiBieQ0KDQokJA0KXGJveGVkeyBcbWF0aGJie0V9W1hea10gPSBcZXhwXGxlZnQoIGtcbXUgKyBcZnJhY3sxfXsyfSBrXjIgXHNpZ21hXjIgXHJpZ2h0KS4gfQ0KJCQNCg0KUGFydGljdWxhcmx5LCB0aGUgbWVhbiBvZiB0aGUgYWJvdmUgbG9nbm9ybWFsIGRpc3RyaWJ1dGlvbiwgZGVub3RlZCBieSAkXG11X3tMTn0kLCBpcyBnaXZlbiBieQ0KDQokJA0KXG11X3tMTn0gPSBcbWF0aGJie0V9W1hdID0gXGV4cFxsZWZ0KCBcbXUgKyBcZnJhY3sxfXsyfSAgXHNpZ21hXjIgXHJpZ2h0KS4NCiQkDQoNCk9uY2UgdGhlIHBhcmFtZXRlcnMgd2VyZSBlc3RpbWF0ZWQsIHNheSAkKFxvdmVybGluZXtcbXV9LCBcb3ZlcmxpbmV7XHNpZ21hXjJ9KSQsIHdlIGNhbiB1c2UgKip0aGUgcGx1Zy1pbiBQcmluY2lwbGUqKiB0byBlc3RpbWF0ZSB0aGUgbG9nbm9ybWFsIG1lYW4gYnkNCg0KJCQNClxib3hlZHtcb3ZlcmxpbmV7XG11X3tMTn19ID0gIFxleHBcbGVmdCggXG92ZXJsaW5le1xtdX0gKyBcZnJhY3sxfXsyfSAgXG92ZXJsaW5le1xzaWdtYV4yfSBccmlnaHQpLn0NCiQkDQoNCg0KDQoNCg0KKipXb3JraW5nIERhdGFzZXQqKjogQSByZXNlcnZvaXIgZW5naW5lZXIgYXQgYW4gb2lsIGV4cGxvcmF0aW9uIGNvbXBhbnkgaGFzIHJlY2VudGx5IGRyaWxsZWQgNTAgbmV3IHdlbGxzIGluIGEgc2hhbGUgZm9ybWF0aW9uLiBBY2NvcmRpbmcgdG8gZ2VvbG9naWNhbCB0aGVvcnksIHRoZSBzaXplIG9mIG9pbCByZXNlcnZlcyBpbiB0aGlzIHR5cGUgb2YgZm9ybWF0aW9uIGlzIG9mdGVuIG1vZGVsZWQgdXNpbmcgYSBsb2ctbm9ybWFsIGRpc3RyaWJ1dGlvbi4gVGhlIGVuZ2luZWVyIGlzIHJlc3BvbnNpYmxlIGZvciBlc3RpbWF0aW5nIHRoZSB0eXBpY2FsIHJlc2VydmUgc2l6ZSBhbmQgcXVhbnRpZnlpbmcgdGhlIHVuY2VydGFpbnR5IG9mIHRoZXNlIGVzdGltYXRlcyBmb3IgYSBwcmVzZW50YXRpb24gdG8gc2VuaW9yIG1hbmFnZW1lbnQuIFRoZSBlc3RpbWF0ZWQgdWx0aW1hdGUgcmVjb3ZlcnkgKEVVUikgZm9yIHRoZSA1MCB3ZWxscywgbWVhc3VyZWQgaW4gdGhvdXNhbmRzIG9mIGJhcnJlbHMgKE1iYmwpLCBpcyBhcyBmb2xsb3dzOg0KDQpgYGANCjE3LjMsIDI0LjgsIDguMiwgMzEuNSwgMTQuMSwgNDIuNywgMTEuOSwgNTUuMywgMjEuNCwgOS43LCAzNi4yLCAxOC42LCA2My4xLCAxMy4yLCAyOC45LCANCjQ3LjUsIDE5LjgsIDcuNSwgMzMuNCwgNTIuMSwgMTYuMCwgMjUuOSwgMzguNywgMTAuMywgNDQuMiwgMjIuNSwgNTguNiwgMTIuOCwgMzAuMywgNDguOSwgDQoyMC4xLCAzNS40LCAxNS43LCA2MC4yLCAyNi43LCA0MS4zLCAxOC4xLCA1My44LCAyMy45LCA0Ni4yLCAyOS40LCAzNy42LCAxNC45LCA1MC41LCAzMi44LCANCjE5LjMsIDU2LjcsIDExLjIsIDM5LjUsIDI3LjENCmBgYA0KDQoNCjxmb250IGNvbG9yID0gImJsdWUiPlRoaXMgYXNzaWdubWVudCBmb2N1c2VzIG9uIGZpbmRpbmcgdGhlIGFzeW1wdG90aWMgc2FtcGxpbmcgZGlzdHJpYnV0aW9ucyBvZiB0aGUgTUxFICRcaGF0e1xtdX0kIGFuZCAkXGhhdHtcc2lnbWFeMn0kIGNvcnJlc3BvbmRpbmcgdG8gJFxtdSQgYW5kICRcc2lnbWFeMiQgYmFzZWQgb24gYW4gZW52aXJvbm1lbnRhbCBzdHVkeSBkYXRhLjwvZm9udD4NCg0KDQpcDQoNCg0KYGBge3J9DQojIE9pbCByZXNlcnZlIGRhdGENCnggPC0gYygNCiAgMTcuMywgMjQuOCwgOC4yLCAzMS41LCAxNC4xLCA0Mi43LCAxMS45LCA1NS4zLCAyMS40LCA5LjcsDQogIDM2LjIsIDE4LjYsIDYzLjEsIDEzLjIsIDI4LjksIDQ3LjUsIDE5LjgsIDcuNSwgMzMuNCwgNTIuMSwNCiAgMTYuMCwgMjUuOSwgMzguNywgMTAuMywgNDQuMiwgMjIuNSwgNTguNiwgMTIuOCwgMzAuMywgNDguOSwNCiAgMjAuMSwgMzUuNCwgMTUuNywgNjAuMiwgMjYuNywgNDEuMywgMTguMSwgNTMuOCwgMjMuOSwgNDYuMiwNCiAgMjkuNCwgMzcuNiwgMTQuOSwgNTAuNSwgMzIuOCwgMTkuMywgNTYuNywgMTEuMiwgMzkuNSwgMjcuMQ0KKQ0KDQojIFNhbXBsZSBzaXplDQpuIDwtIGxlbmd0aCh4KQ0KDQpgYGANCg0KIyMgKipRdWVzdGlvbiAxKio6IE1ldGhvZCBvZiBNb21lbnRzIEVzdGltYXRpb24gKE1NRSkgb2YgJFxtdSQgYW5kICRcc2lnbWFeMiQNCg0KRXN0aW1hdGUgdGhlIHBhcmFtZXRlcnMgJFxtdSQgYW5kICRcc2lnbWFeMiQgKDxmb250IGNvbG9yPSJyZWQiPipcY29sb3J7cmVkfWNhdXRpb246IG5vdCAkXHNpZ21hJCEqPC9mb250PikgZnJvbSB0aGUgcmF3IG9pbCByZXNlcnZlIGRhdGEgdXNpbmcgdGhlIGdpdmVuICRrJC10aCBtb21lbnQgZnVuY3Rpb24uIE9yZ2FuaXplIHlvdXIgd29yayBpbnRvIHRocmVlIHBhcnRzOg0KDQooYSkgRGVyaXZlIHRoZSBzeXN0ZW0gb2YgdHdvIGVxdWF0aW9ucyBmb3IgdGhlIG1ldGhvZCBvZiBtb21lbnRzIGVzdGltYXRvcnMgKE1NRXMpIG9mICRcbXUkIGFuZCAkXHNpZ21hXjIkLg0KDQpMZXQgdGhlIGZpcnN0IHR3byBzYW1wbGUgbW9tZW50cyBiZQ0KDQokJA0KbV8xPVxmcmFjezF9e259XHN1bV97aT0xfV5uIHhfaSxccXF1YWQgbV8yPVxmcmFjezF9e259XHN1bV97aT0xfV5uIHhfaV4yLg0KJCQNCg0KRm9yIHRoZSBsb2dub3JtYWwgZGlzdHJpYnV0aW9uLA0KDQokJA0KXG11XzE9XG1hdGhiYntFfVtYXT1cZXhwXGxlZnQoXG11K1xmcmFjezF9ezJ9XHNpZ21hXjJccmlnaHQpDQokJA0KYW5kIA0KJCQNClxtdV8yPVxtYXRoYmJ7RX1bWF4yXT1cZXhwXGxlZnQoMlxtdSsyXHNpZ21hXjJccmlnaHQpLg0KJCQNCg0KVGhlIG1ldGhvZCBvZiBtb21lbnRzIHNldHMNCg0KJCQNClxleHBcbGVmdChcbXUrXGZyYWN7MX17Mn1cc2lnbWFeMlxyaWdodCk9bV8xDQokJA0KDQoNCiQkDQpcZXhwXGxlZnQoMlxtdSsyXHNpZ21hXjJccmlnaHQpPW1fMi4NCiQkDQoNClRoZXNlIGFyZSB0d28gTU1FIGVxdWF0aW9ucyB1c2VkIHRvIHNvbHZlIGZvciAkXG11JCBhbmQgJFxzaWdtYV4yJC4NCg0KDQooYikgRGVyaXZlIHRoZSBjbG9zZWQtZm9ybSBleHByZXNzaW9ucyBmb3IgdGhlIE1NRXMgb2YgJFxtdSQsICRcc2lnbWFeMiQsIGFuZCAkXG11X3tMTn0kLCBkZW5vdGVkIGJ5ICRcd2lkZXRpbGRle1xtdX0kLCAkXHdpZGV0aWxkZXtcc2lnbWFeMn0kLCBhbmQgJFx3aWRldGlsZGV7XG11X3tMTn19JCwgcmVzcGVjdGl2ZWx5Lg0KDQpUYWtpbmcgbG9nYXJpdGhtcyBnaXZlcw0KDQokJA0KXG11K1xmcmFjezF9ezJ9XHNpZ21hXjI9XGxuKG1fMSkNCiQkDQoNCiQkDQoyXG11KzJcc2lnbWFeMj1cbG4obV8yKS4NCiQkDQoNCkZyb20gdGhlIGZpcnN0IGVxdWF0aW9uLA0KDQokJA0KMlxtdStcc2lnbWFeMj0yXGxuKG1fMSkuDQokJA0KDQpTdWJ0cmFjdGluZyB0aGlzIGZyb20gdGhlIHNlY29uZCBlcXVhdGlvbiBnaXZlcw0KDQokJA0KXHNpZ21hXjI9XGxuKG1fMiktMlxsbihtXzEpPVxsblxsZWZ0KFxmcmFje21fMn17bV8xXjJ9XHJpZ2h0KS4NCiQkDQoNClRodXMsDQoNCiQkDQpcd2lkZXRpbGRle1xzaWdtYV4yfT1cbG5cbGVmdChcZnJhY3ttXzJ9e21fMV4yfVxyaWdodCkuDQokJA0KDQpTdWJzdGl0dXRpbmcgaW50byB0aGUgZmlyc3QgZXF1YXRpb24sDQoNCiQkDQpcd2lkZXRpbGRle1xtdX09XGxuKG1fMSktXGZyYWN7MX17Mn1cd2lkZXRpbGRle1xzaWdtYV4yfS4NCiQkDQoNClRoZSBwbHVnLWluIGVzdGltYXRvciBvZiB0aGUgbG9nbm9ybWFsIG1lYW4gaXMNCg0KJCQNClx3aWRldGlsZGV7XG11X3tMTn19PVxleHBcbGVmdChcd2lkZXRpbGRle1xtdX0rXGZyYWN7MX17Mn1cd2lkZXRpbGRle1xzaWdtYV4yfVxyaWdodCkNCiQkDQoNClNpbmNlICRtXzE9XGJhciBYJCwgd2UgaGF2ZQ0KDQokJA0KXGJveGVke1x3aWRldGlsZGV7XG11X3tMTn19PVxiYXIgWH0NCiQkDQoNCg0KKGMpIFdyaXRlIGFuIFIgZnVuY3Rpb24gdGhhdCBvdXRwdXRzIHRoZSBNTUVzICRcd2lkZXRpbGRle1xtdX0kLCAkXHdpZGV0aWxkZXtcc2lnbWFeMn0kLCBhbmQgJFx3aWRldGlsZGV7XG11X3tMTn19JCBiYXNlZCBvbiB0aGUgZ2l2ZW4gZGF0YSBzZXQuDQoNCmBgYHtyfQ0KIyBNZXRob2Qgb2YgTW9tZW50cyBlc3RpbWF0aW9uIGZvciBsb2dub3JtYWwgcGFyYW1ldGVycw0KbG9nbm9ybWFsLm1tZSA8LSBmdW5jdGlvbih4KXsNCiAgbTEgPC0gbWVhbih4KSAjRmlyc3Qgc2FtcGxlIG1vbWVudA0KICBtMiA8LSBtZWFuKHheMikgI1NlY29uZCBzYW1wbGUgbW9tZW50DQoNCiAgI01NRSBvZiBzaWdtYV4yIGRlcml2ZWQgZnJvbSBtb21lbnQgZXF1YXRpb25zICAgDQogIHNpZ21hMi50aWxkZSA8LSBsb2cobTIgLyAobTFeMikpDQogIA0KICAjIE1NRSBvZiBtdSBvYnRhaW5lZCBieSBzdWJzdGl0dXRpbmcgc2lnbWFeMiBpbnRvIGZpcnN0IGVxdWF0aW9uDQogIG11LnRpbGRlIDwtIGxvZyhtMSkgLSAwLjUgKiBzaWdtYTIudGlsZGUNCiAgDQogICMgUGx1Zy1pbiBlc3RpbWF0b3IgZm9yIHRoZSBsb2dub3JtYWwgbWVhbg0KICBtdUxOLnRpbGRlIDwtIGV4cChtdS50aWxkZSArIDAuNSAqIHNpZ21hMi50aWxkZSkNCiAgDQogICMgUmV0dXJuIHRoZSBlc3RpbWF0ZXMNCiAgZGF0YS5mcmFtZSgNCiAgICBtdV90aWxkZSA9IG11LnRpbGRlLA0KICAgIHNpZ21hMl90aWxkZSA9IHNpZ21hMi50aWxkZSwNCiAgICBtdUxOX3RpbGRlID0gbXVMTi50aWxkZQ0KICApDQp9DQoNCiMgUmV0dXJuIHRoZSBlc3RpbWF0ZXMNCmxvZ25vcm1hbC5tbWUoeCkNCmBgYA0KXA0KDQoNCiMjICoqUXVlc3Rpb24gMioqOiBGaW5kaW5nIHRoZSBNTEUgb2YgJFxtdSQgYW5kICRcc2lnbWFeMiQNCg0KVGhpcyBxdWVzdGlvbiBpbnZvbHZlcyB0d28gcGFydHM6DQoNCigxKS4gRGVyaXZlIHRoZSBzY29yZSBmdW5jdGlvbnMgKGkuZS4sIHRoZSBncmFkaWVudCBvZiB0aGUgbG9nLWxpa2VsaWhvb2QpIGZvciB0aGUgcGFyYW1ldGVycyBvZiB0aGUgbG9nLW5vcm1hbCBkaXN0cmlidXRpb24sIGFuZCBzZXQgdGhlbSB0byB6ZXJvIHRvIG9idGFpbiB0aGUgc3lzdGVtIG9mIHNjb3JlIGVxdWF0aW9ucy4gQmVnaW4gd2l0aCB0aGUgZnVsbCBsb2ctbGlrZWxpaG9vZCBhbmQgY29tcHV0ZSBpdHMgcGFydGlhbCBkZXJpdmF0aXZlcyB3aXRoIHJlc3BlY3QgdG8gJFxtdSQgYW5kICRcc2lnbWFeMiQuIFtIaW50OiBsZXR0aW5nICRcYmV0YSA9IFxzaWdtYV4yJCBtYXkgc2ltcGxpZnkgZGlmZmVyZW50aWF0aW9uLl0NCg0KQXNzdW1lIHRoYXQgJFx7eF8xLCB4XzIsIFxjZG90cywgeF9uIFx9IFx0byBcdGV4dHsgTE4gfShcbXUsIFxzaWdtYV4yKSQgd2l0aCBkZW5zaXR5IGZ1bmN0aW9uIGdpdmVuIGJ5DQoNCiQkDQpcZWxsKFxtdSwgXHNpZ21hXjIpID0gLVxmcmFje259ezJ9IFxsbigyXHBpKSAtIG4gXGxuIFxzaWdtYSAtIFxzdW1fe2k9MX1ebiBcbG4geF9pIA0KICAgLSBcZnJhY3sxfXsyXHNpZ21hXjJ9IFxzdW1fe2k9MX1ebiAoXGxuIHhfaSAtIFxtdSleMg0KJCQNClRoZSBsb2ctbGlrZWxpaG9vZCBmdW5jdGlvbiBpcw0KDQokJA0KXGVsbChcbXUsXHNpZ21hXjIpPS1cZnJhY3tufXsyfVxsbigyXHBpKS1cZnJhY3tufXsyfVxsbihcc2lnbWFeMiktXHN1bV97aT0xfV5uIFxsbiB4X2ktXGZyYWN7MX17MlxzaWdtYV4yfVxzdW1fe2k9MX1ebihcbG4geF9pLVxtdSleMi4NCiQkDQoNCkxldCAkXGJldGE9XHNpZ21hXjIkLg0KDQpcc3Vic2VjdGlvbip7U2NvcmUgZnVuY3Rpb24gZm9yICRcbXUkfQ0KDQokJA0KXGZyYWN7XHBhcnRpYWwgXGVsbH17XHBhcnRpYWwgXG11fT1cZnJhY3sxfXtcYmV0YX1cc3VtX3tpPTF9Xm4oXGxuIHhfaS1cbXUpLg0KJCQNCg0KU2V0dGluZyB0aGlzIGVxdWFsIHRvIHplcm8gZ2l2ZXMNCiQkDQpcaGF0e1xtdX09XGZyYWN7MX17bn1cc3VtX3tpPTF9Xm4gXGxuIHhfaS4NCiQkDQoNClxzdWJzZWN0aW9uKntTY29yZSBmdW5jdGlvbiBmb3IgJFxiZXRhPVxzaWdtYV4yJH0NCg0KJCQNClxmcmFje1xwYXJ0aWFsIFxlbGx9e1xwYXJ0aWFsIFxiZXRhfT0tXGZyYWN7bn17MlxiZXRhfStcZnJhY3sxfXsyXGJldGFeMn1cc3VtX3tpPTF9Xm4oXGxuIHhfaS1cbXUpXjIuDQokJA0KDQpTZXR0aW5nIHRoaXMgZXF1YWwgdG8gemVybyB5aWVsZHMNCg0KJCQNClx3aWRlaGF0e1xzaWdtYV4yfT1cZnJhY3sxfXtufVxzdW1fe2k9MX1ebihcbG4geF9pLVxoYXR7XG11fSleMi4NCiQkDQoNCg0KKDIpLiBQZXJmb3JtIHNvbWUgYWxnZWJyYSB0byBmaW5kIHRoZSBjbG9zZWQgZm9ybSBvZiB0aGUgTUxFIG9mICRcbXUkIGFuZCAkXHNpZ21hXjIkLCBkZW5vdGVkIGJ5ICRcd2lkZWhhdHtcbXV9JCBhbmQgJFx3aWRlaGF0e1xzaWdtYV4yfSQuDQoNCiQkDQpcYm94ZWR7XGhhdHtcbXV9PVxmcmFjezF9e259XHN1bV97aT0xfV5uIFxsbiB4X2l9DQokJA0KYW5kDQoNCiQkDQpcYm94ZWR7XHdpZGVoYXR7XHNpZ21hXjJ9PVxmcmFjezF9e259XHN1bV97aT0xfV5uKFxsbiB4X2ktXGhhdHtcbXV9KV4yfS4NCiQkDQoNCg0KKDMpLiBSZWNhbGwgdGhhdCBsb2dub3JtYWwgcG9wdWxhdGlvbiBtZWFuIChpLmUuLCB0aGUgZmlyc3QgbW9tZW50KSBpcyANCg0KJCQNClxtdV97TE59ID0gXG1hdGhiYntFfVtYXSA9IFxleHBcbGVmdCggXG11ICsgXGZyYWN7MX17Mn0gIFxzaWdtYV4yIFxyaWdodCkuDQokJA0KDQpVc2luZyB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gdmFyaWFuY2UgYW5kIHRoZSBmaXJzdCBhbmQgc2Vjb25kIG1vbWVudHMsICRcdGV4dHtWYXJ9KFgpID0gXG1hdGhiYntFfVtYXjJdIC0gXGxlZnQoXG1hdGhiYntFfVtYXVxyaWdodCleMiQsIHdlIGRlcml2ZSB0aGUgcG9wdWxhdGlvbiB2YXJpYW5jZSBvZiB0aGUgbG9nbm9ybWFsIGRpc3RyaWJ1dGlvbiwgZGVub3RlZCBhcyAkXHNpZ21hX3tcdGV4dHtMTn19XjIkLiBUaGlzIHJlc3VsdCB3aWxsIGJlIHVzZWQgaW4gYXBwbHlpbmcgdGhlIENlbnRyYWwgTGltaXQgVGhlb3JlbSBpbiBzdWJzZXF1ZW50IHF1ZXN0aW9ucw0KXHNlY3Rpb24qe0xvZ25vcm1hbCBNZWFuIGFuZCBWYXJpYW5jZX0NCg0KVGhlIGxvZ25vcm1hbCBtZWFuIGlzDQoNCiQkDQpcbXVfe0xOfT1cZXhwXGxlZnQoXG11K1xmcmFjezF9ezJ9XHNpZ21hXjJccmlnaHQpLg0KJCQNCkFsc28sDQokJA0KXG1hdGhiYntFfVtYXjJdPVxleHAoMlxtdSsyXHNpZ21hXjIpLg0KJCQNClRoZXJlZm9yZQ0KJCQNClxzaWdtYV97TE59XjI9XG1hdGhiYntFfVtYXjJdLShcbWF0aGJie0V9W1hdKV4yPVxleHAoMlxtdSsyXHNpZ21hXjIpLVxleHAoMlxtdStcc2lnbWFeMikuDQokJA0KDQpFcXVpdmFsZW50bHksDQokJA0KXHNpZ21hX3tMTn1eMj1cZXhwKDJcbXUrXHNpZ21hXjIpXGxlZnQoXGV4cChcc2lnbWFeMiktMVxyaWdodCkuDQokJA0KXA0KDQojIyAqKlF1ZXN0aW9uIDMqKjogU2FtcGxpbmcgRGlzdHJpYnV0aW9uIG9mIExvZ25vcm1hbCAqKlNhbXBsZSBNZWFuKiogJFx3aWRlaGF0e1xtdV97TE59fSQNCg0KV2UgaGF2ZSBkZXJpdmVkIHR3byBkaWZmZXJlbnQgZXN0aW1hdG9ycyBvZiBsb2dub3JtYWwgcG9wdWxhdGlvbiBtZWFuICRcbXVfe0xOfSQuIFRoaXMgUXVlc3Rpb24gZm9jdXNlcyBvbiB0aGUgc2FtcGxpbmcgZGlzdHJpYnV0aW9uIG9mIGxvZ25vcm1hbCBzYW1wbGUgc2FtcGxlIG1lYW5zIGJhc2VkIG9uIE1MRS4gVGhlIGZvbGxvd2luZyBhcmUgZGV0YWlsZWQgaW5zdHJ1Y3Rpb25zLg0KDQooMSkuIFdyaXRlIGFuIFIgZnVuY3Rpb24gdG8gZXN0aW1hdGUgdGhlIE1MRSBvZiAkXG11JCBhbmQgJFxzaWdtYV4yJCwgZGVub3RlZCBieSAkXHdpZGVoYXR7XG11fSQgYW5kICRcd2lkZWhhdHtcc2lnbWFeMn0kIGFuZCByZXR1cm4gdGhlIE1MRSBvZiAkXG11X3tMTn0kLCBkZW5vdGVkIGJ5ICRcd2lkZWhhdHtcbXVfe0xOfX0kLg0KDQpgYGB7cn0NCg0KIyBGdW5jdGlvbiB0byBjb21wdXRlIE1MRSBvZiBtdSwgc2lnbWFeMiwgYW5kIGxvZ25vcm1hbCBtZWFuDQpsb2dub3JtYWxfbWxlIDwtIGZ1bmN0aW9uKHgpew0KDQogIHkgPC0gbG9nKHgpIyBUYWtlIG5hdHVyYWwgbG9nIG9mIGRhdGENCiAgbXVfaGF0IDwtIG1lYW4oeSkgIyBNTEUgb2YgbXUgDQoNCiAgIyBNTEUgb2Ygc2lnbWFeMiANCiAgc2lnbWEyX2hhdCA8LSBtZWFuKCh5IC0gbXVfaGF0KV4yKQ0KDQogICMgUGx1Zy1pbiBlc3RpbWF0ZSBvZiBsb2dub3JtYWwgcG9wdWxhdGlvbiBtZWFuDQogIG11TE5faGF0IDwtIGV4cChtdV9oYXQgKyAwLjUgKiBzaWdtYTJfaGF0KQ0KDQogICMgUmV0dXJuIGVzdGltYXRlcw0KICBjKG11X2hhdCA9IG11X2hhdCwNCiAgICBzaWdtYTJfaGF0ID0gc2lnbWEyX2hhdCwNCiAgICBtdUxOX2hhdCA9IG11TE5faGF0KQ0KfQ0KDQojIENvbXB1dGUgTUxFIGVzdGltYXRlcw0KbG9nbm9ybWFsX21sZSh4KQ0KDQpgYGANCg0KKDIpLiBUYWtlIDEwMDAgQm9vdHN0cmFwIHNhbXBsZXMgZnJvbSB0aGUgcmF3IG9pbCBkYXRhIHNldC4gRm9yIGVhY2ggYm9vdHN0cmFwIHNhbXBsZSwgY2FsbCB0aGUgYWJvdmUgUiBmdW5jdGlvbiB0byBmaW5kIHRoZSAqKmJvb3RzdHJhcCBNTEUqKiBvZiAkXG11X3tMTn0kLCBkZW5vdGVkIGJ5ICRcd2lkZWhhdHtcbXVfe0xOfV4qfV57KDEpfSwgXHdpZGVoYXR7XG11X3tMTn1eKn1eeygyKX0sIFxjZG90cywgXHdpZGVoYXR7XG11X3tMTn1eKn1eeygxMDAwKX0kLg0KDQpgYGB7cn0NCg0Kc2V0LnNlZWQoMTIzKQ0KDQpCIDwtIDEwMDAgIyBOdW1iZXIgb2YgYm9vdHN0cmFwIHNhbXBsZXMNCm4gPC0gbGVuZ3RoKHgpDQoNCmJvb3RfbXVMTiA8LSBOVUxMICMgVmVjdG9yIHRvIHN0b3JlIGJvb3RzdHJhcCBlc3RpbWF0ZXMNCg0KIyBCb290c3RyYXAgbG9vcA0KZm9yKGkgaW4gMTpCKXsNCg0KICAjIERyYXcgYm9vdHN0cmFwIHNhbXBsZSB3aXRoIHJlcGxhY2VtZW50DQogIHNhbXBsZV9pIDwtIHNhbXBsZSh4LCBzaXplID0gbiwgcmVwbGFjZSA9IFRSVUUpDQoNCiAgIyBDb21wdXRlIGJvb3RzdHJhcCBNTEUgb2YgbG9nbm9ybWFsIG1lYW4NCiAgYm9vdF9tdUxOW2ldIDwtIGxvZ25vcm1hbF9tbGUoc2FtcGxlX2kpWzNdDQp9DQoNCmBgYA0KDQooMykuIFVzaW5nIGtlcm5lbCBkZW5zaXR5IGVzdGltYXRpb24gYXBwcm9hY2ggdG8gZXN0aW1hdGUgdGhlIGJvb3RzdHJhcCBkZW5zaXR5IGN1cnZlcyBiYXNlZCBvbiB0aGUgYm9vdHN0cmFwIE1MRXM6ICRcd2lkZWhhdHtcbXVfe0xOfV4qfV57KDEpfSwgXHdpZGVoYXR7XG11X3tMTn1eKn1eeygyKX0sIFxjZG90cywgXHdpZGVoYXR7XG11X3tMTn1eKn1eeygxMDAwKX0kLg0KDQpgYGB7cn0NCiMgUGxvdCBoaXN0b2dyYW0gb2YgYm9vdHN0cmFwIGVzdGltYXRlcw0KaGlzdChib290X211TE4sDQogICAgIHByb2JhYmlsaXR5ID0gVFJVRSwNCiAgICAgYnJlYWtzID0gMjAsDQogICAgIG1haW4gPSAiQm9vdHN0cmFwIFNhbXBsaW5nIERpc3RyaWJ1dGlvbiBvZiBtdV9MTiIsDQogICAgIHhsYWIgPSAiQm9vdHN0cmFwIEVzdGltYXRlcyBvZiBtdV9MTiIpDQoNCiMgQWRkIGtlcm5lbCBkZW5zaXR5IGN1cnZlDQpsaW5lcyhkZW5zaXR5KGJvb3RfbXVMTiksDQogICAgICBjb2wgPSAiYmx1ZSIsDQogICAgICBsd2QgPSAyKQ0KYGBgDQoNCig0KS4gSW4gb3JkZXIgdG8gZmluZCB0aGUgYXN5bXB0b3RpYyBzYW1wbGluZyBkaXN0cmlidXRpb24gdXNpbmcgdGhlICoqY2VudHJhbCBsaW1pdCB0aGVvcmVtIChDTFQpKiouIFRoYXQgaXMsIHdoZW4gc2FtcGxlIHNpemUgaXMgbGFyZ2UsIA0KDQokJA0KXGJhcntYfSBcdG8gTiBcbGVmdChcbXVfe0xOfSwgXGZyYWN7XHNpZ21hX3tMTn19e1xzcXJ0e259fVxyaWdodCkNCiQkDQoNCndoZXJlICRcbXVfe0xOfSQgYW5kICRcc2lnbWFfe0xOfSQgY2FuIGJlIGVzdGltYXRlZCBieSB1c2luZyB0aGUgKipwbHVnLWluIHByaW5jaXBsZSBvZiBNTEUqKi4gQmFzZWQgb24gdGhlIGFzeW1wdG90aWMgc2FtcGxpbmcgZGlzdHJpYnV0aW9uIG9mICoqbG9nbm9ybWFsIHNhbXBsZSBtZWFuKiogJFxiYXJ7WH0kLCBhZGQgdGhlIGFzeW1wdG90aWMgZGVuc2l0eSBjdXJ2ZSB0byB0aGUgYWJvdmUgQm9vdHN0cmFwIGtlcm5lbCBkZW5zaXR5IGN1cnZlLg0KDQpgYGB7cn0NCiMgT2J0YWluIE1MRSBlc3RpbWF0ZXMgZnJvbSBvcmlnaW5hbCBkYXRhDQptbGVfb3V0IDwtIGxvZ25vcm1hbF9tbGUoeCkNCg0KbXVfaGF0IDwtIG1sZV9vdXRbMV0NCnNpZ21hMl9oYXQgPC0gbWxlX291dFsyXQ0KbXVMTl9oYXQgPC0gbWxlX291dFszXQ0KDQojIFBsdWctaW4gZXN0aW1hdGUgb2YgbG9nbm9ybWFsIHZhcmlhbmNlDQpzaWdtYTJMTl9oYXQgPC0gZXhwKDIgKiBtdV9oYXQgKyBzaWdtYTJfaGF0KSAqIChleHAoc2lnbWEyX2hhdCkgLSAxKQ0KDQojIFN0YW5kYXJkIGRldmlhdGlvbiBvZiBsb2dub3JtYWwgZGlzdHJpYnV0aW9uDQpzaWdtYUxOX2hhdCA8LSBzcXJ0KHNpZ21hMkxOX2hhdCkNCg0KIyBTdGFuZGFyZCBlcnJvciBvZiB0aGUgc2FtcGxlIG1lYW4gdXNpbmcgQ0xUDQphc3ltX3NlIDwtIHNpZ21hTE5faGF0IC8gc3FydChuKQ0KDQojIENyZWF0ZSBncmlkIG9mIHZhbHVlcyBmb3IgYXN5bXB0b3RpYyBkZW5zaXR5DQpncmlkX3ggPC0gc2VxKG1pbihib290X211TE4pLCBtYXgoYm9vdF9tdUxOKSwgbGVuZ3RoLm91dCA9IDQwMCkNCg0KIyBDb21wdXRlIGFzeW1wdG90aWMgbm9ybWFsIGRlbnNpdHkNCmFzeW1fZGVuc2l0eSA8LSBkbm9ybShncmlkX3gsDQogICAgICAgICAgICAgICAgICAgICAgbWVhbiA9IG11TE5faGF0LA0KICAgICAgICAgICAgICAgICAgICAgIHNkID0gYXN5bV9zZSkNCg0KIyBQbG90IGJvb3RzdHJhcCBkaXN0cmlidXRpb24gYWdhaW4NCmhpc3QoYm9vdF9tdUxOLA0KICAgICBwcm9iYWJpbGl0eSA9IFRSVUUsDQogICAgIGJyZWFrcyA9IDIwLA0KICAgICBtYWluID0gIkJvb3RzdHJhcCB2cyBBc3ltcHRvdGljIFNhbXBsaW5nIERpc3RyaWJ1dGlvbiIsDQogICAgIHhsYWIgPSAibXVfTE4iKQ0KDQojIEFkZCBib290c3RyYXAga2VybmVsIGRlbnNpdHkNCmxpbmVzKGRlbnNpdHkoYm9vdF9tdUxOKSwNCiAgICAgIGNvbCA9ICJibHVlIiwNCiAgICAgIGx3ZCA9IDIpDQoNCiMgQWRkIGFzeW1wdG90aWMgbm9ybWFsIGN1cnZlDQpsaW5lcyhncmlkX3gsDQogICAgICBhc3ltX2RlbnNpdHksDQogICAgICBjb2wgPSAicmVkIiwNCiAgICAgIGx3ZCA9IDIsDQogICAgICBsdHkgPSAyKQ0KDQojIEFkZCBsZWdlbmQNCmxlZ2VuZCgidG9wcmlnaHQiLA0KICAgICAgIGxlZ2VuZCA9IGMoIkJvb3RzdHJhcCBLREUiLCAiQXN5bXB0b3RpYyBOb3JtYWwiKSwNCiAgICAgICBjb2wgPSBjKCJibHVlIiwgInJlZCIpLA0KICAgICAgIGx3ZCA9IDIsDQogICAgICAgbHR5ID0gYygxLDIpKQ0KYGBgDQoNCig1KS4gV3JpdGUgYSBzaG9ydCBzdW1tYXJ5IHRvIGNvbXBhcmUgdGhlIHR3byBzYW1wbGluZyBkaXN0cmlidXRpb25zIG9mIHRoZSBzYW1wbGUgbWVhbiBvZiB0aGUgbG9nbm9ybWFsIGRpc3RyaWJ1dGlvbi4NCg0KKipBbnN3ZXI6KiogVGhlIGJvb3RzdHJhcCBkaXN0cmlidXRpb24gaXMgb2J0YWluZWQgYnkgcmVzYW1wbGluZyB0aGUgZGF0YSwgc28gaXQgcmVmbGVjdHMgdGhlIHNoYXBlIG9mIHRoZSBkYXRhIG1vcmUgZGlyZWN0bHkuIFRoZSBhc3ltcHRvdGljIGRpc3RyaWJ1dGlvbiBpcyBiYXNlZCBvbiB0aGUgQ2VudHJhbCBMaW1pdCBUaGVvcmVtIGFuZCBhc3N1bWVzIGEgTm9ybWFsIGFwcHJveGltYXRpb24uIElmIHRoZSB0d28gY3VydmVzIGFyZSBzaW1pbGFyLCB0aGUgTm9ybWFsIGFwcHJveGltYXRpb24gd29ya3Mgd2VsbC4gSWYgdGhleSBkaWZmZXIsIHRoZSBib290c3RyYXAgZGlzdHJpYnV0aW9uIGdpdmVzIGEgYmV0dGVyIGRlc2NyaXB0aW9uIG9mIHRoZSBlc3RpbWF0b3LigJlzIHNhbXBsaW5nIGJlaGF2aW9yLg0KDQojIyAqKlF1ZXN0aW9uIDQqKjogRXh0cmEgQm9udXMgQ3JlZGl0DQoNCkRlcml2ZSB0aGUgSGVzc2lhbiBtYXRyaXggYnkgY29tcHV0aW5nIHRoZSBzZWNvbmQtb3JkZXIgcGFydGlhbCBkZXJpdmF0aXZlcyBvZiB0aGUgbG9nLWxpa2VsaWhvb2QgZnVuY3Rpb24gKHdpdGggcmVzcGVjdCB0byAkXG11JCBhbmQgJFxzaWdtYV4yJCkuIFRoZW4sIHRyYW5zbGF0ZSB0aGUgZGVyaXZlZCBIZXNzaWFuIGludG8gYW4gUiBmdW5jdGlvbiB0aGF0IHRha2VzIHRoZSBNTEVzIG9mIHRoZSBwYXJhbWV0ZXJzIGFuZCB0aGUgZGF0YSBhcyBpbnB1dHMgYW5kIHJldHVybnMgdGhlIEhlc3NpYW4gbWF0cml4LiBGaW5hbGx5LCBjb21wYXJlIHlvdXIgYW5hbHl0aWNhbGx5IGRlcml2ZWQgSGVzc2lhbiB3aXRoIHRoZSBudW1lcmljYWwgSGVzc2lhbiByZXR1cm5lZCBieSBgb3B0aW0oKWAuDQoNCkxldCAkXGJldGE9XHNpZ21hXjIkLg0KDQpUaGUgSGVzc2lhbiBtYXRyaXggb2YgdGhlIGxvZy1saWtlbGlob29kIGlzIG9idGFpbmVkIGZyb20gdGhlIHNlY29uZCBkZXJpdmF0aXZlcy4NCg0KJCQNClxmcmFje1xwYXJ0aWFsXjIgXGVsbH17XHBhcnRpYWwgXG11XjJ9PS1cZnJhY3tufXtcYmV0YX0NCiQkDQoNCiQkDQpcZnJhY3tccGFydGlhbF4yIFxlbGx9e1xwYXJ0aWFsIFxtdSBccGFydGlhbFxiZXRhfT0tXGZyYWN7MX17XGJldGFeMn1cc3VtX3tpPTF9Xm4oXGxuIHhfaS1cbXUpDQokJA0KDQokJA0KXGZyYWN7XHBhcnRpYWxeMiBcZWxsfXtccGFydGlhbCBcYmV0YV4yfT1cZnJhY3tufXsyXGJldGFeMn0tXGZyYWN7MX17XGJldGFeM31cc3VtX3tpPTF9Xm4oXGxuIHhfaS1cbXUpXjINCiQkDQoNClRodXMgdGhlIEhlc3NpYW4gbWF0cml4IGlzDQoNCiQkDQpIKFxtdSxcYmV0YSkgID1cYmVnaW57Ym1hdHJpeH0tXGZyYWN7bn17XGJldGF9Ji1cZnJhY3sxfXtcYmV0YV4yfVxzdW1fe2k9MX1ebihcbG4geF9pLVxtdSlcXC1cZnJhY3sxfXtcYmV0YV4yfVxzdW1fe2k9MX1ebihcbG4geF9pLVxtdSkmXGZyYWN7bn17MlxiZXRhXjJ9LVxmcmFjezF9e1xiZXRhXjN9XHN1bV97aT0xfV5uKFxsbiB4X2ktXG11KV4yXGVuZHtibWF0cml4fS4NCiQkDQoNCmBgYHtyfQ0KIyBGdW5jdGlvbiB0byBjb21wdXRlIGFuYWx5dGljIEhlc3NpYW4gbWF0cml4IG9mIHRoZSBsb2ctbGlrZWxpaG9vZA0KbG9nbm9ybWFsX2hlc3NpYW4gPC0gZnVuY3Rpb24obXUsIHNpZ21hMiwgeCl7DQoNCiAgIyBMb2cgdHJhbnNmb3JtZWQgZGF0YQ0KICB5IDwtIGxvZyh4KQ0KDQogICMgU2FtcGxlIHNpemUNCiAgbiA8LSBsZW5ndGgoeCkNCg0KICAjIEludGVybWVkaWF0ZSBzdW1zDQogIHMxIDwtIHN1bSh5IC0gbXUpDQogIHMyIDwtIHN1bSgoeSAtIG11KV4yKQ0KDQogICMgU2Vjb25kIGRlcml2YXRpdmUgd2l0aCByZXNwZWN0IHRvIG11DQogIGgxMSA8LSAtbiAvIHNpZ21hMg0KDQogICMgQ3Jvc3MgZGVyaXZhdGl2ZQ0KICBoMTIgPC0gLXMxIC8gKHNpZ21hMl4yKQ0KDQogICMgU3ltbWV0cnkgb2YgSGVzc2lhbg0KICBoMjEgPC0gaDEyDQoNCiAgIyBTZWNvbmQgZGVyaXZhdGl2ZSB3aXRoIHJlc3BlY3QgdG8gc2lnbWFeMg0KICBoMjIgPC0gbiAvICgyICogc2lnbWEyXjIpIC0gczIgLyAoc2lnbWEyXjMpDQoNCiAgIyBDb25zdHJ1Y3QgSGVzc2lhbiBtYXRyaXgNCiAgbWF0cml4KGMoaDExLCBoMTIsDQogICAgICAgICAgIGgyMSwgaDIyKSwNCiAgICAgICAgIG5yb3cgPSAyLA0KICAgICAgICAgYnlyb3cgPSBUUlVFKQ0KfQ0KYGBgDQoNCkNvbXBhcmUgd2l0aCBudW1lcmljYWwgSGVzc2lhbiBmcm9tIG9wdGltICgpDQoNCmBgYHtyfQ0KIyBOZWdhdGl2ZSBsb2ctbGlrZWxpaG9vZCBmb3Igb3B0aW0oKQ0KbmVnbG9nbGlrX2xvZ25vcm1hbCA8LSBmdW5jdGlvbihwYXIsIHgpew0KICBtdSA8LSBwYXJbMV0NCiAgc2lnbWEyIDwtIHBhclsyXQ0KICBpZihzaWdtYTIgPD0gMCkgcmV0dXJuKEluZikNCiAgDQogIG4gPC0gbGVuZ3RoKHgpDQogIHkgPC0gbG9nKHgpDQogIA0KICBsbCA8LSAtbi8yICogbG9nKDIqcGkpIC0gbi8yICogbG9nKHNpZ21hMikgLSBzdW0obG9nKHgpKSAtDQogICAgKDEvKDIqc2lnbWEyKSkgKiBzdW0oKHkgLSBtdSleMikNCiAgDQogIHJldHVybigtbGwpDQp9DQoNCiMgR3JhZGllbnQgb2YgbmVnYXRpdmUgbG9nLWxpa2VsaWhvb2QNCm5lZ2dyYWRfbG9nbm9ybWFsIDwtIGZ1bmN0aW9uKHBhciwgeCl7DQogIG11IDwtIHBhclsxXQ0KICBzaWdtYTIgPC0gcGFyWzJdDQogIHkgPC0gbG9nKHgpDQogIG4gPC0gbGVuZ3RoKHgpDQogIA0KICBkbXUgPC0gLSgxL3NpZ21hMikgKiBzdW0oeSAtIG11KQ0KICBkc2lnbWEyIDwtIG4vKDIqc2lnbWEyKSAtIHN1bSgoeSAtIG11KV4yKS8oMiAqIHNpZ21hMl4yKQ0KICANCiAgcmV0dXJuKGMoZG11LCBkc2lnbWEyKSkNCn0NCg0KIyBvcHRpbQ0KaW5pdCA8LSBjKG1lYW4obG9nKHgpKSwgdmFyKGxvZyh4KSkpDQpmaXQgPC0gb3B0aW0ocGFyID0gaW5pdCwNCiAgICAgICAgICAgICBmbiA9IG5lZ2xvZ2xpa19sb2dub3JtYWwsDQogICAgICAgICAgICAgZ3IgPSBuZWdncmFkX2xvZ25vcm1hbCwNCiAgICAgICAgICAgICB4ID0geCwNCiAgICAgICAgICAgICBtZXRob2QgPSAiTC1CRkdTLUIiLA0KICAgICAgICAgICAgIGxvd2VyID0gYygtSW5mLCAxZS04KSwNCiAgICAgICAgICAgICBoZXNzaWFuID0gVFJVRSkNCg0KbXVfaGF0X29wdCA8LSBmaXQkcGFyWzFdDQpzaWdtYTJfaGF0X29wdCA8LSBmaXQkcGFyWzJdDQoNCiMgQW5hbHl0aWMgSGVzc2lhbiBvZiBsb2ctbGlrZWxpaG9vZA0KSF9hbmFseXRpYyA8LSBsb2dub3JtYWxfaGVzc2lhbihtdV9oYXRfb3B0LCBzaWdtYTJfaGF0X29wdCwgeCkNCg0KIyBOdW1lcmljYWwgSGVzc2lhbiBmcm9tIG9wdGltKCkgaXMgZm9yIG5lZ2F0aXZlIGxvZy1saWtlbGlob29kDQpIX251bWVyaWMgPC0gZml0JGhlc3NpYW4NCg0KSF9hbmFseXRpYw0KLUhfYW5hbHl0aWMNCkhfbnVtZXJpYw0KYGBgDQpUaGUgYW5hbHl0aWMgSGVzc2lhbiBhbmQgdGhlIG51bWVyaWNhbCBIZXNzaWFuIGZyb20gb3B0aW0oKSBzaG91bGQgYmUgdmVyeSBjbG9zZSwgZXhjZXB0IGZvciBzbWFsbCBudW1lcmljYWwgZGlmZmVyZW5jZXMgZHVlIHRvIGZpbml0ZS1kaWZmZXJlbmNlIGFwcHJveGltYXRpb24uIFNpbmNlIG9wdGltKCkgaXMgbWluaW1pemluZyB0aGUgbmVnYXRpdmUgbG9nLWxpa2VsaWhvb2QsIGl0cyBIZXNzaWFuIHNob3VsZCBtYXRjaCB0aGUgbmVnYXRpdmUgb2YgdGhlIGFuYWx5dGljIEhlc3NpYW4gb2YgdGhlIGxvZy1saWtlbGlob29kLg==