Testing Overfitting/Underfitting

In Machine Learning and Statistics, overfitting occurs when a model is too complex and learns noise, leading to poor performance on new data, while underfitting happens when a model is too simple to capture important patterns, resulting in high errors overall; both issues are explained by the Bias–Variance Tradeoff and can cause unreliable predictions in real-world applications.

The probability density function (PDF) of the Weibull distribution is:

\[ f(t; \lambda, \beta) = \frac{\beta}{\lambda} \left( \frac{t}{\lambda} \right)^{\beta-1} \exp\left[ -\left( \frac{t}{\lambda} \right)^\beta \right], \quad t \ge 0 \] where \(\lambda > 0\) is the scale parameter (characteristic life) and \(\beta > 0\) is the shape parameter.

When \(\beta = 1\), the Weibull PDF simplifies to the exponential PDF:

\[ f(t; \lambda) = \frac{1}{\lambda} \exp\left( -\frac{t}{\lambda} \right) \] with constant hazard rate \(h(t) = 1/\lambda\).

This assignment focuses on performing a hypothesis test for the shape parameter (\(\beta\)) of the Weibull distribution within a reliability mode

\[\begin{align} H_0&: \beta = 1 \quad \text{(Exponential model, simpler)} \\ H_1&: \beta \neq 1 \quad \text{(Weibull model, more complex)} \end{align}\]

Steps of the BLRT

  • Fit models under \(H_0\) and \(H_1\)} to the original data, compute \(\Lambda_{\text{obs}}\).

  • Generate bootstrap samples under \(H_0\)}:

    • Estimate parameters under \(H_0\) from the original data.
    • Generate \(B\) datasets by sampling from the model under \(H_0\) (parametric bootstrap) or by resampling residuals/cases (nonparametric bootstrap; parametric is common for BLRT).
  • For each bootstrap sample \(b = 1,\dots,B\):

    • Fit \(H_0\) and \(H_1\) models.
    • Compute \(\Lambda_b = -2[\ell_{0,b} - \ell_{1,b}]\).
  • Approximate p-value:

\[ p = \frac{1}{B} \sum_{b=1}^B I(\Lambda_b \ge \Lambda_{\text{obs}}) \] (Often a small adjustment is made for stability: \((1 + \#\{\Lambda_b \ge \Lambda_{\text{obs}}\})/(B+1)\)).


Question: Reliability Application

A wind energy company monitors the reliability of gearboxes in 75 identical wind turbines located in a coastal wind farm. The gearbox is a critical component; its failure often leads to costly downtime and repairs. Previous studies suggest that the hazard rate (failure risk) may increase over time due to mechanical wear (fatigue, pitting, bearing degradation). Engineers want to test whether the failure time distribution follows an exponential model (constant hazard, random failures) or a Weibull model with shape parameter \(k>1\) (increasing hazard, indicative of aging/degradation). The failure times (in months) are:

   5.2,  7.8,  9.1, 11.3, 12.5, 13.0, 14.2, 15.1, 15.9, 16.7, 17.2, 17.8, 18.4, 18.9, 
  19.3, 19.7, 20.2, 20.6, 21.0, 21.5, 21.9, 22.3, 22.7, 23.1, 23.5, 23.9, 24.3, 24.7, 
  25.1, 25.5, 25.9, 26.3, 26.7, 27.1, 27.5, 27.9, 28.3, 28.7, 29.1, 29.5, 29.9, 30.3, 
  30.7, 31.1, 31.5, 31.9, 32.3, 32.7, 33.1, 33.5, 33.9, 34.3, 34.7, 35.1, 35.5, 35.9, 
  36.3, 36.7, 37.1, 37.5, 37.9, 38.3, 38.7, 39.1, 39.5, 39.9, 40.3, 40.7, 41.1, 41.5,
  41.9, 42.3, 42.7, 43.1, 43.5

This assignment focuses on hypothesis \(H_0: \beta = 1\) (exponential) against \(H_1: \beta \neq 1\) (Weibull). This framework detects overfitting (fitting a Weibull when exponential is true) and underfitting (fitting exponential when Weibull with \(\beta \neq 1\) is true).

a). Find the MLE of the Weibull parameters \(\lambda\) (scale) and \(\beta\) (shape), denoted by \(\hat{\lambda}\) and \(\hat{\beta}\), respectively, using the optim() procedure. [Hint: You should provide explicit expressions for the log-likelihood and gradient functions of the Weibull distribution parameters.]

We test

\(H_0: \beta = 1\) (Exponential model)

versus

\(H_1: \beta \ne 1\) (Weibull model).

Under \(H_0\), the hazard is constant. Under \(H_1\), the hazard may increase or decrease with time.

The probability density function (PDF) of the Weibull distribution is:

\[ f(t; \lambda, \beta) = \frac{\beta}{\lambda} \left( \frac{t}{\lambda} \right)^{\beta-1} \exp\left[ -\left( \frac{t}{\lambda} \right)^\beta \right], \quad t \ge 0 \] where \(\lambda>0\) is the scale parameter and \(\beta>0\) is the shape parameter. so that \[ \ell(\lambda, \beta) = \sum_{i=1}^{n} \log f(x_i; \lambda, \beta) = n \log \beta - n \beta \log \lambda + (\beta - 1) \sum_{i=1}^{n} \log x_i - \sum_{i=1}^{n} \left( \frac{x_i}{\lambda} \right)^\beta \]

The gradient functions (partial derivatives) are \[ \frac{\partial \ell}{\partial \lambda} = \frac{\beta}{\lambda} \left[ \sum_{i=1}^n \left( \frac{x_i}{\lambda} \right)^\beta - n \right] \] \[ \frac{\partial \ell}{\partial \beta} = \frac{n}{\beta} - n \log \lambda + \sum_{i=1}^{n} \log x_i - \sum_{i=1}^{n} \left( \frac{x_i}{\lambda} \right)^\beta \log \left( \frac{x_i}{\lambda} \right) \]

x <- c(
  5.2, 7.8, 9.1, 11.3, 12.5, 13.0, 14.2, 15.1, 15.9, 16.7, 17.2, 17.8, 18.4, 18.9,
  19.3, 19.7, 20.2, 20.6, 21.0, 21.5, 21.9, 22.3, 22.7, 23.1, 23.5, 23.9, 24.3, 24.7,
  25.1, 25.5, 25.9, 26.3, 26.7, 27.1, 27.5, 27.9, 28.3, 28.7, 29.1, 29.5, 29.9, 30.3,
  30.7, 31.1, 31.5, 31.9, 32.3, 32.7, 33.1, 33.5, 33.9, 34.3, 34.7, 35.1, 35.5, 35.9,
  36.3, 36.7, 37.1, 37.5, 37.9, 38.3, 38.7, 39.1, 39.5, 39.9, 40.3, 40.7, 41.1, 41.5,
  41.9, 42.3, 42.7, 43.1, 43.5
)
n <- length(x)

# Log-likelihood function
weibull_loglik <- function(par, data) {

  lambda <- par[1]
  beta   <- par[2]

  # Parameter constraint
  if (lambda <= 0 || beta <= 0) return(-Inf)

  ll <- length(data) * log(beta) -
        length(data) * beta * log(lambda) +
        (beta - 1) * sum(log(data)) -
        sum((data / lambda)^beta)

  return(ll)
}

# Negative log-likelihood (for minimization)
weibull_nll <- function(par, data) {
  return(-weibull_loglik(par, data))
}

# Gradient function
weibull_grad <- function(par, data) {

  lambda <- par[1]
  beta   <- par[2]
  n <- length(data)

  z <- (data / lambda)^beta

  # derivative wrt lambda
  d_lambda <- - (beta / lambda) * (sum(z) - n)

  # derivative wrt beta
  d_beta <- - (n / beta -
               n * log(lambda) +
               sum(log(data)) -
               sum(z * log(data / lambda)))

  return(c(d_lambda, d_beta))
}

# Run optimization
fit_weibull <- optim(
  par = c(mean(x), 1.5),   # initial values
  fn  = weibull_nll,
  gr  = weibull_grad,
  data = x,
  method = "L-BFGS-B",
  lower = c(1e-8, 1e-8)
)

fit_weibull$par
[1] 31.418211  3.370789

Summary: Using optim(), the maximum likelihood estimates are \(\hat{\beta} \approx 3.37\). Thus the fitted Weibull model is \(\hat{\lambda} \approx 31.42\).

Since \(\hat{\beta} > 1\), the fitted model suggests an increasing hazard rate, which is consistent with mechanical wear and aging.

b). Find the MLE of the exponential parameter \(\lambda\) (scale), denoted by \(\hat{\lambda}\), using any procedure. [Hint: You should provide explicit expressions for the log-likelihood and gradient functions of the exponential distribution parameters.]

Step 1: Model

When \(\beta =1\) \(f(t;\lambda) = \frac{1}{\lambda} e^{-t/\lambda}\)

Step 2: Log likelihood

\(\ell(\lambda) = -n \log \lambda - \frac{1}{\lambda} \sum_{i=1}^{n} x_i\)

Step 3: Derivative

\(\frac{d\ell}{d\lambda} = -\frac{n}{\lambda} + \frac{\sum x_i}{\lambda^2}\) Set to zero:\(\hat{\lambda} = \bar{x}\)

# Exponential MLE
lambda0_hat <- mean(x)

lambda0_hat
[1] 28.18533

Summary:

The estimate is\(\hat{\lambda}_0 = \bar{x} \approx 28.1853\).

c). Use a) and b) to perform the regular likelihood ratio \(\chi^2\) test for \(\beta = 1\) and report the p-value.

Step 1: Statistic

\(LR = -2[\ell_0 - \ell_1]\)

Step 2:

# Exponential log-likelihood
exp_loglik <- function(lambda, data) {
  -length(data) * log(lambda) - sum(data) / lambda
}

# Compute log-likelihoods
logLik0 <- exp_loglik(lambda0_hat, x)

lambda1_hat <- fit_weibull$par[1]
beta1_hat   <- fit_weibull$par[2]

logLik1 <- weibull_loglik(c(lambda1_hat, beta1_hat), x)

# Likelihood ratio
LR_obs <- -2 * (logLik0 - logLik1)

# p-value (chi-square)
p_chisq <- 1 - pchisq(LR_obs, df = 1)

LR_obs
[1] 100.6144
p_chisq
[1] 0

Summary: Because \(LR \approx 100.61\) \(p < 2.2 \times 10^{-16}\) Therefore, Reject \(H_0\).

d). Use the BLRT algorithm to perform a bootstrap likelihood ratio test and report the bootstrap p-value. Note that you are expected to translate the BLRT algorithm into R code to perform the BLRT. [Hint: The chi-square distribution should not be used in this part of the analysis.]

Step 1: IdeaInstead of: \(LR \sim \chi^2\) we approximate the distribution using bootstrap.

Step 2: Algorithm Fit model under \(H_0\). Then, generate bootstrap samples from exponential and compute LR each time. Last, Compare with observed.

Step 3:

set.seed(123)

# Fit exponential
fit_exp_mle <- function(data) {
  lambda_hat <- mean(data)
  logLik <- -length(data) * log(lambda_hat) - sum(data) / lambda_hat
  return(list(lambda_hat = lambda_hat, logLik = logLik))
}

# Fit Weibull
fit_weibull_mle <- function(data) {
  out <- optim(
    par = c(mean(data), 1.5),
    fn = weibull_nll,
    gr = weibull_grad,
    data = data,
    method = "L-BFGS-B",
    lower = c(1e-8, 1e-8)
  )

  return(list(
    lambda_hat = out$par[1],
    beta_hat   = out$par[2],
    logLik     = -out$value
  ))
}

# Observed statistic
fit0 <- fit_exp_mle(x)
fit1 <- fit_weibull_mle(x)

LR_obs <- -2 * (fit0$logLik - fit1$logLik)

# Bootstrap
B <- 2000
LR_boot <- numeric(B)

for (b in 1:B) {

  # Generate from H0
  x_star <- rexp(n, rate = 1 / fit0$lambda_hat)

  fit0_b <- fit_exp_mle(x_star)
  fit1_b <- fit_weibull_mle(x_star)

  LR_boot[b] <- -2 * (fit0_b$logLik - fit1_b$logLik)
}

# Bootstrap p-value
p_boot <- (1 + sum(LR_boot >= LR_obs)) / (B + 1)

p_boot
[1] 0.0004997501

Summary:

Using \(B=2000\) bootstrap samples, the bootstrap p-value is:\(p_{boot} \approx 0.0005\)This is extremely small, so the BLRT also rejects \(H_0\).Because bootstrap results depend slightly on the random seed and the chosen \(B\), the exact value may vary a little, but it will still be very small.DecisionSince \(p_{boot} \approx 0.0005 < 0.05\), we again reject \(H_0: \beta = 1\).

e). Write a summary of the above analyses to address the following:

  • Whether the two tests generated the same results.

Summary: Both the classical likelihood ratio test and the bootstrap LRT reject \(H_0: \beta=1\), with p-values near zero (\(p < 2.2 \times 10^{-16}\) and \(p_{boot} \approx 0.0005\)). This provides strong evidence that the exponential model does not fit the data. The estimated Weibull shape parameter \(\hat{\beta} \approx 3.37 > 1\) indicates an increasing hazard rate over time, consistent with mechanical wear. Therefore, the Weibull model is preferred, while the exponential model underfits the data.

  • Which model is recommended for the data.

Summary: Weibull model is recommended because it captures increasing failure risk and fits the data significantly better.

LS0tDQp0aXRsZTogIkFzc2lnbm1lbnQgMTI6IEJvb3RzdHJhcCBMaWtlbGlob29kIFJhdGlvIFRlc3QgKEJMUlQpIg0KYXV0aG9yOiAiIFhpYW95aW5nIE1hICINCmRhdGU6ICIgRHVlOiAwNC8yMS8yMDI2ICINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDogDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDQNCiAgICB0b2NfZmxvYXQ6IHllcw0KICAgIG51bWJlcl9zZWN0aW9uczogbm8NCiAgICB0b2NfY29sbGFwc2VkOiB5ZXMNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMNCiAgICBzbW9vdGhfc2Nyb2xsOiB5ZXMNCiAgICBoaWdobGlnaHQ6IG1vbm9jaHJvbWUNCiAgICB0aGVtZTogc3BhY2VsYWINCiAgd29yZF9kb2N1bWVudDogDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDQNCiAgICBmaWdfY2FwdGlvbjogeWVzDQogICAga2VlcF9tZDogeWVzDQogIHBkZl9kb2N1bWVudDogDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDQNCiAgICBmaWdfY2FwdGlvbjogeWVzDQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgICBmaWdfd2lkdGg6IDMNCiAgICBmaWdfaGVpZ2h0OiAzDQplZGl0b3Jfb3B0aW9uczogDQogIGNodW5rX291dHB1dF90eXBlOiBpbmxpbmUNCi0tLQ0KDQpgYGB7Y3NzLCBlY2hvID0gRkFMU0V9DQojVE9DOjpiZWZvcmUgew0KICBjb250ZW50OiAiVGFibGUgb2YgQ29udGVudHMiOw0KICBmb250LXdlaWdodDogYm9sZDsNCiAgZm9udC1zaXplOiAxLjJlbTsNCiAgZGlzcGxheTogYmxvY2s7DQogIGNvbG9yOiBuYXZ5Ow0KICBtYXJnaW4tYm90dG9tOiAxMHB4Ow0KfQ0KDQoNCmRpdiNUT0MgbGkgeyAgICAgLyogdGFibGUgb2YgY29udGVudCAgKi8NCiAgICBsaXN0LXN0eWxlOnVwcGVyLXJvbWFuOw0KICAgIGJhY2tncm91bmQtaW1hZ2U6bm9uZTsNCiAgICBiYWNrZ3JvdW5kLXJlcGVhdDpub25lOw0KICAgIGJhY2tncm91bmQtcG9zaXRpb246MDsNCn0NCg0KaDEudGl0bGUgeyAgICAvKiBsZXZlbCAxIGhlYWRlciBvZiB0aXRsZSAgKi8NCiAgZm9udC1zaXplOiAyMnB4Ow0KICBmb250LXdlaWdodDogYm9sZDsNCiAgY29sb3I6IERhcmtSZWQ7DQogIHRleHQtYWxpZ246IGNlbnRlcjsNCiAgZm9udC1mYW1pbHk6ICJHaWxsIFNhbnMiLCBzYW5zLXNlcmlmOw0KfQ0KDQpoNC5hdXRob3IgeyAvKiBIZWFkZXIgNCAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICBmb250LXNpemU6IDE1cHg7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KICBmb250LWZhbWlseTogc3lzdGVtLXVpOw0KICBjb2xvcjogbmF2eTsNCiAgdGV4dC1hbGlnbjogY2VudGVyOw0KfQ0KDQpoNC5kYXRlIHsgLyogSGVhZGVyIDQgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgZm9udC1zaXplOiAxOHB4Ow0KICBmb250LXdlaWdodDogYm9sZDsNCiAgZm9udC1mYW1pbHk6ICJHaWxsIFNhbnMiLCBzYW5zLXNlcmlmOw0KICBjb2xvcjogRGFya0JsdWU7DQogIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCg0KaDEgeyAvKiBIZWFkZXIgMSAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICAgIGZvbnQtc2l6ZTogMjBweDsNCiAgICBmb250LXdlaWdodDogYm9sZDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogZGFya3JlZDsNCiAgICB0ZXh0LWFsaWduOiBjZW50ZXI7DQp9DQoNCmgyIHsgLyogSGVhZGVyIDIgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgICBmb250LXNpemU6IDE4cHg7DQogICAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IG5hdnk7DQogICAgdGV4dC1hbGlnbjogbGVmdDsNCn0NCg0KaDMgeyAvKiBIZWFkZXIgMyAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICAgIGZvbnQtc2l6ZTogMTZweDsNCiAgICBmb250LXdlaWdodDogYm9sZDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogbmF2eTsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KDQpoNCB7IC8qIEhlYWRlciA0IC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovDQogICAgZm9udC1zaXplOiAxNHB4Ow0KICBmb250LXdlaWdodDogYm9sZDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogZGFya3JlZDsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KDQovKiBBZGQgZG90cyBhZnRlciBudW1iZXJlZCBoZWFkZXJzICovDQouaGVhZGVyLXNlY3Rpb24tbnVtYmVyOjphZnRlciB7DQogIGNvbnRlbnQ6ICIuIjsNCg0KYm9keSB7YmFja2dyb3VuZC1jb2xvcjogI2ZmZmZmZjsNCiAgICAgIGNvbG9yOiAjMDAwMDAwOw0KICAgICAgZm9udC1mYW1pbHk6IEFyaWFsLCBzYW5zLXNlcmlmOw0KICAgICAgZm9udC1zaXplOiAxcmVtOw0KICAgICAgbGluZS1oZWlnaHQ6IDEuNjsNCiAgICAgIH0NCg0KLmhpZ2hsaWdodG1lIHsgYmFja2dyb3VuZC1jb2xvcjp5ZWxsb3c7IH0NCg0KcCB7IGJhY2tncm91bmQtY29sb3I6d2hpdGU7IH0NCg0KfQ0KYGBgDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0KIyBjb2RlIGNodW5rIHNwZWNpZmllcyB3aGV0aGVyIHRoZSBSIGNvZGUsIHdhcm5pbmdzLCBhbmQgb3V0cHV0IA0KIyB3aWxsIGJlIGluY2x1ZGVkIGluIHRoZSBvdXRwdXQgZmlsZXMuDQppZiAoIXJlcXVpcmUoImtuaXRyIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoImtuaXRyIikNCiAgIGxpYnJhcnkoa25pdHIpDQp9DQppZiAoIXJlcXVpcmUoInBhbmRlciIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJwYW5kZXIiKQ0KICAgbGlicmFyeShwYW5kZXIpDQp9DQppZiAoIXJlcXVpcmUoImdncGxvdDIiKSkgew0KICBpbnN0YWxsLnBhY2thZ2VzKCJnZ3Bsb3QyIikNCiAgbGlicmFyeShnZ3Bsb3QyKQ0KfQ0KaWYgKCFyZXF1aXJlKCJ0aWR5dmVyc2UiKSkgew0KICBpbnN0YWxsLnBhY2thZ2VzKCJ0aWR5dmVyc2UiKQ0KICBsaWJyYXJ5KHRpZHl2ZXJzZSkNCn0NCg0KaWYgKCFyZXF1aXJlKCJwbG90bHkiKSkgew0KICBpbnN0YWxsLnBhY2thZ2VzKCJwbG90bHkiKQ0KICBsaWJyYXJ5KHBsb3RseSkNCn0NCg0KaWYgKCFyZXF1aXJlKCJWR0FNIikpIHsNCiAgaW5zdGFsbC5wYWNrYWdlcygiVkdBTSIpDQogIGxpYnJhcnkoVkdBTSkNCn0NCiMjIyMgVkdBTQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCAgICAgICAjIGluY2x1ZGUgY29kZSBjaHVuayBpbiB0aGUgb3V0cHV0IGZpbGUNCiAgICAgICAgICAgICAgICAgICAgICB3YXJuaW5nID0gRkFMU0UsICAgIyBzb21ldGltZXMsIHlvdSBjb2RlIG1heSBwcm9kdWNlIHdhcm5pbmcgbWVzc2FnZXMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgeW91IGNhbiBjaG9vc2UgdG8gaW5jbHVkZSB0aGUgd2FybmluZyBtZXNzYWdlcyBpbg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHRoZSBvdXRwdXQgZmlsZS4gDQogICAgICAgICAgICAgICAgICAgICAgcmVzdWx0cyA9IFRSVUUsICAgICMgeW91IGNhbiBhbHNvIGRlY2lkZSB3aGV0aGVyIHRvIGluY2x1ZGUgdGhlIG91dHB1dA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGluIHRoZSBvdXRwdXQgZmlsZS4NCiAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlID0gRkFMU0UsDQogICAgICAgICAgICAgICAgICAgICAgY29tbWVudCA9IE5BDQogICAgICAgICAgICAgICAgICAgICAgKSAgDQpgYGANCiANCg0KDQoNCiMjIFRlc3RpbmcgT3ZlcmZpdHRpbmcvVW5kZXJmaXR0aW5nDQoNCkluIE1hY2hpbmUgTGVhcm5pbmcgYW5kIFN0YXRpc3RpY3MsIG92ZXJmaXR0aW5nIG9jY3VycyB3aGVuIGEgbW9kZWwgaXMgdG9vIGNvbXBsZXggYW5kIGxlYXJucyBub2lzZSwgbGVhZGluZyB0byBwb29yIHBlcmZvcm1hbmNlIG9uIG5ldyBkYXRhLCB3aGlsZSB1bmRlcmZpdHRpbmcgaGFwcGVucyB3aGVuIGEgbW9kZWwgaXMgdG9vIHNpbXBsZSB0byBjYXB0dXJlIGltcG9ydGFudCBwYXR0ZXJucywgcmVzdWx0aW5nIGluIGhpZ2ggZXJyb3JzIG92ZXJhbGw7IGJvdGggaXNzdWVzIGFyZSBleHBsYWluZWQgYnkgdGhlIEJpYXPigJNWYXJpYW5jZSBUcmFkZW9mZiBhbmQgY2FuIGNhdXNlIHVucmVsaWFibGUgcHJlZGljdGlvbnMgaW4gcmVhbC13b3JsZCBhcHBsaWNhdGlvbnMuDQoNCg0KVGhlIHByb2JhYmlsaXR5IGRlbnNpdHkgZnVuY3Rpb24gKFBERikgb2YgdGhlIFdlaWJ1bGwgZGlzdHJpYnV0aW9uIGlzOg0KDQokJA0KZih0OyBcbGFtYmRhLCBcYmV0YSkgPSBcZnJhY3tcYmV0YX17XGxhbWJkYX0gXGxlZnQoIFxmcmFje3R9e1xsYW1iZGF9IFxyaWdodClee1xiZXRhLTF9IFxleHBcbGVmdFsgLVxsZWZ0KCBcZnJhY3t0fXtcbGFtYmRhfSBccmlnaHQpXlxiZXRhIFxyaWdodF0sIFxxdWFkIHQgXGdlIDANCiQkDQp3aGVyZSAkXGxhbWJkYSA+IDAkIGlzIHRoZSBzY2FsZSBwYXJhbWV0ZXIgKGNoYXJhY3RlcmlzdGljIGxpZmUpIGFuZCAkXGJldGEgPiAwJCBpcyB0aGUgc2hhcGUgcGFyYW1ldGVyLg0KDQpXaGVuICRcYmV0YSA9IDEkLCB0aGUgV2VpYnVsbCBQREYgc2ltcGxpZmllcyB0byB0aGUgZXhwb25lbnRpYWwgUERGOg0KDQokJA0KZih0OyBcbGFtYmRhKSA9IFxmcmFjezF9e1xsYW1iZGF9IFxleHBcbGVmdCggLVxmcmFje3R9e1xsYW1iZGF9IFxyaWdodCkNCiQkDQp3aXRoIGNvbnN0YW50IGhhemFyZCByYXRlICRoKHQpID0gMS9cbGFtYmRhJC4NCg0KDQo8cD48Zm9udCBjb2xvciA9ICJkYXJrcmVkIj4qKlRoaXMgYXNzaWdubWVudCBmb2N1c2VzIG9uIHBlcmZvcm1pbmcgYSBoeXBvdGhlc2lzIHRlc3QgZm9yIHRoZSBzaGFwZSBwYXJhbWV0ZXIgKCRcYmV0YSQpIG9mIHRoZSBXZWlidWxsIGRpc3RyaWJ1dGlvbiB3aXRoaW4gYSByZWxpYWJpbGl0eSBtb2RlKio8L2ZvbnQ+PC9wPg0KDQoNClxiZWdpbnthbGlnbn0NCkhfMCY6IFxiZXRhID0gMSBccXVhZCBcdGV4dHsoRXhwb25lbnRpYWwgbW9kZWwsIHNpbXBsZXIpfSBcXA0KSF8xJjogXGJldGEgXG5lcSAxIFxxdWFkIFx0ZXh0eyhXZWlidWxsIG1vZGVsLCBtb3JlIGNvbXBsZXgpfQ0KXGVuZHthbGlnbn0NCg0KDQoNCiMjIFN0ZXBzIG9mIHRoZSBCTFJUDQoNCg0KKiBGaXQgbW9kZWxzIHVuZGVyICRIXzAkIGFuZCAkSF8xJH0gdG8gdGhlIG9yaWdpbmFsIGRhdGEsIGNvbXB1dGUgJFxMYW1iZGFfe1x0ZXh0e29ic319JC4NCg0KKiBHZW5lcmF0ZSBib290c3RyYXAgc2FtcGxlcyB1bmRlciAkSF8wJH06IA0KICArIEVzdGltYXRlIHBhcmFtZXRlcnMgdW5kZXIgJEhfMCQgZnJvbSB0aGUgb3JpZ2luYWwgZGF0YS4NCiAgKyBHZW5lcmF0ZSAkQiQgZGF0YXNldHMgYnkgc2FtcGxpbmcgZnJvbSB0aGUgbW9kZWwgdW5kZXIgJEhfMCQgKHBhcmFtZXRyaWMgYm9vdHN0cmFwKSBvciBieSByZXNhbXBsaW5nIHJlc2lkdWFscy9jYXNlcyAobm9ucGFyYW1ldHJpYyBib290c3RyYXA7IHBhcmFtZXRyaWMgaXMgY29tbW9uIGZvciBCTFJUKS4NCg0KKiBGb3IgZWFjaCBib290c3RyYXAgc2FtcGxlICRiID0gMSxcZG90cyxCJDoNCiAgKyBGaXQgJEhfMCQgYW5kICRIXzEkIG1vZGVscy4NCiAgKyBDb21wdXRlICRcTGFtYmRhX2IgPSAtMltcZWxsX3swLGJ9IC0gXGVsbF97MSxifV0kLg0KDQoqIEFwcHJveGltYXRlIHAtdmFsdWU6DQoNCiQkDQogIHAgPSBcZnJhY3sxfXtCfSBcc3VtX3tiPTF9XkIgSShcTGFtYmRhX2IgXGdlIFxMYW1iZGFfe1x0ZXh0e29ic319KQ0KJCQNCihPZnRlbiBhIHNtYWxsIGFkanVzdG1lbnQgaXMgbWFkZSBmb3Igc3RhYmlsaXR5OiAkKDEgKyBcI1x7XExhbWJkYV9iIFxnZSBcTGFtYmRhX3tcdGV4dHtvYnN9fVx9KS8oQisxKSQpLg0KDQoNCg0KXA0KDQojIyAqKlF1ZXN0aW9uOiBSZWxpYWJpbGl0eSBBcHBsaWNhdGlvbioqDQoNCjxwPg0KQSB3aW5kIGVuZXJneSBjb21wYW55IG1vbml0b3JzIHRoZSByZWxpYWJpbGl0eSBvZiBnZWFyYm94ZXMgaW4gNzUgaWRlbnRpY2FsIHdpbmQgdHVyYmluZXMgbG9jYXRlZCBpbiBhIGNvYXN0YWwgd2luZCBmYXJtLiBUaGUgZ2VhcmJveCBpcyBhIGNyaXRpY2FsIGNvbXBvbmVudDsgaXRzIGZhaWx1cmUgb2Z0ZW4gbGVhZHMgdG8gY29zdGx5IGRvd250aW1lIGFuZCByZXBhaXJzLiBQcmV2aW91cyBzdHVkaWVzIHN1Z2dlc3QgdGhhdCB0aGUgaGF6YXJkIHJhdGUgKGZhaWx1cmUgcmlzaykgbWF5IGluY3JlYXNlIG92ZXIgdGltZSBkdWUgdG8gbWVjaGFuaWNhbCB3ZWFyIChmYXRpZ3VlLCBwaXR0aW5nLCBiZWFyaW5nIGRlZ3JhZGF0aW9uKS4gRW5naW5lZXJzIHdhbnQgdG8gdGVzdCB3aGV0aGVyIHRoZSBmYWlsdXJlIHRpbWUgZGlzdHJpYnV0aW9uIGZvbGxvd3MgYW4gZXhwb25lbnRpYWwgbW9kZWwgKGNvbnN0YW50IGhhemFyZCwgcmFuZG9tIGZhaWx1cmVzKSBvciBhIFdlaWJ1bGwgbW9kZWwgd2l0aCBzaGFwZSBwYXJhbWV0ZXIgJGs+MSQgKGluY3JlYXNpbmcgaGF6YXJkLCBpbmRpY2F0aXZlIG9mIGFnaW5nL2RlZ3JhZGF0aW9uKS4gVGhlIGZhaWx1cmUgdGltZXMgKGluIG1vbnRocykgYXJlOg0KDQpgYGANCiAgIDUuMiwgIDcuOCwgIDkuMSwgMTEuMywgMTIuNSwgMTMuMCwgMTQuMiwgMTUuMSwgMTUuOSwgMTYuNywgMTcuMiwgMTcuOCwgMTguNCwgMTguOSwgDQogIDE5LjMsIDE5LjcsIDIwLjIsIDIwLjYsIDIxLjAsIDIxLjUsIDIxLjksIDIyLjMsIDIyLjcsIDIzLjEsIDIzLjUsIDIzLjksIDI0LjMsIDI0LjcsIA0KICAyNS4xLCAyNS41LCAyNS45LCAyNi4zLCAyNi43LCAyNy4xLCAyNy41LCAyNy45LCAyOC4zLCAyOC43LCAyOS4xLCAyOS41LCAyOS45LCAzMC4zLCANCiAgMzAuNywgMzEuMSwgMzEuNSwgMzEuOSwgMzIuMywgMzIuNywgMzMuMSwgMzMuNSwgMzMuOSwgMzQuMywgMzQuNywgMzUuMSwgMzUuNSwgMzUuOSwgDQogIDM2LjMsIDM2LjcsIDM3LjEsIDM3LjUsIDM3LjksIDM4LjMsIDM4LjcsIDM5LjEsIDM5LjUsIDM5LjksIDQwLjMsIDQwLjcsIDQxLjEsIDQxLjUsDQogIDQxLjksIDQyLjMsIDQyLjcsIDQzLjEsIDQzLjUNCmBgYA0KPC9wPg0KDQpUaGlzIGFzc2lnbm1lbnQgZm9jdXNlcyBvbiBoeXBvdGhlc2lzICRIXzA6IFxiZXRhID0gMSQgKGV4cG9uZW50aWFsKSBhZ2FpbnN0ICRIXzE6IFxiZXRhIFxuZXEgMSQgKFdlaWJ1bGwpLiBUaGlzIGZyYW1ld29yayBkZXRlY3RzIG92ZXJmaXR0aW5nIChmaXR0aW5nIGEgV2VpYnVsbCB3aGVuIGV4cG9uZW50aWFsIGlzIHRydWUpIGFuZCB1bmRlcmZpdHRpbmcgKGZpdHRpbmcgZXhwb25lbnRpYWwgd2hlbiBXZWlidWxsIHdpdGggJFxiZXRhIFxuZXEgMSQgaXMgdHJ1ZSkuIA0KDQoNCjxwPg0KDQphKS4gRmluZCB0aGUgTUxFIG9mIHRoZSBXZWlidWxsIHBhcmFtZXRlcnMgJFxsYW1iZGEkIChzY2FsZSkgYW5kICRcYmV0YSQgKHNoYXBlKSwgZGVub3RlZCBieSAkXGhhdHtcbGFtYmRhfSQgYW5kICRcaGF0e1xiZXRhfSQsIHJlc3BlY3RpdmVseSwgdXNpbmcgdGhlIGBvcHRpbSgpYCBwcm9jZWR1cmUuIFsqSGludDogWW91IHNob3VsZCBwcm92aWRlIGV4cGxpY2l0IGV4cHJlc3Npb25zIGZvciB0aGUgbG9nLWxpa2VsaWhvb2QgYW5kIGdyYWRpZW50IGZ1bmN0aW9ucyBvZiB0aGUgV2VpYnVsbCBkaXN0cmlidXRpb24gcGFyYW1ldGVycy4qXSAgDQoNCldlIHRlc3QgDQoNCiRIXzA6IFxiZXRhID0gMSQgKEV4cG9uZW50aWFsIG1vZGVsKQ0KDQp2ZXJzdXMNCg0KJEhfMTogXGJldGEgXG5lIDEkIChXZWlidWxsIG1vZGVsKS4NCg0KVW5kZXIgJEhfMCQsIHRoZSBoYXphcmQgaXMgY29uc3RhbnQuIFVuZGVyICRIXzEkLCB0aGUgaGF6YXJkIG1heSBpbmNyZWFzZSBvciBkZWNyZWFzZSB3aXRoIHRpbWUuDQoNCg0KVGhlIHByb2JhYmlsaXR5IGRlbnNpdHkgZnVuY3Rpb24gKFBERikgb2YgdGhlIFdlaWJ1bGwgZGlzdHJpYnV0aW9uIGlzOg0KDQokJA0KZih0OyBcbGFtYmRhLCBcYmV0YSkgPSBcZnJhY3tcYmV0YX17XGxhbWJkYX0gXGxlZnQoIFxmcmFje3R9e1xsYW1iZGF9IFxyaWdodClee1xiZXRhLTF9IFxleHBcbGVmdFsgLVxsZWZ0KCBcZnJhY3t0fXtcbGFtYmRhfSBccmlnaHQpXlxiZXRhIFxyaWdodF0sIFxxdWFkIHQgXGdlIDANCiQkDQp3aGVyZSAkXGxhbWJkYT4wJCBpcyB0aGUgc2NhbGUgcGFyYW1ldGVyIGFuZCAkXGJldGE+MCQgaXMgdGhlIHNoYXBlIHBhcmFtZXRlci4NCnNvIHRoYXQNCiQkDQpcZWxsKFxsYW1iZGEsIFxiZXRhKSA9IFxzdW1fe2k9MX1ee259IFxsb2cgZih4X2k7IFxsYW1iZGEsIFxiZXRhKSA9IG4gXGxvZyBcYmV0YSAtIG4gXGJldGEgXGxvZyBcbGFtYmRhICsgKFxiZXRhIC0gMSkgXHN1bV97aT0xfV57bn0gXGxvZyB4X2kgLSBcc3VtX3tpPTF9XntufSBcbGVmdCggXGZyYWN7eF9pfXtcbGFtYmRhfSBccmlnaHQpXlxiZXRhDQokJA0KDQpUaGUgZ3JhZGllbnQgZnVuY3Rpb25zIChwYXJ0aWFsIGRlcml2YXRpdmVzKSBhcmUNCiQkDQpcZnJhY3tccGFydGlhbCBcZWxsfXtccGFydGlhbCBcbGFtYmRhfSA9IFxmcmFje1xiZXRhfXtcbGFtYmRhfSBcbGVmdFsgXHN1bV97aT0xfV5uIFxsZWZ0KCBcZnJhY3t4X2l9e1xsYW1iZGF9IFxyaWdodCleXGJldGEgLSBuIFxyaWdodF0NCiQkDQokJA0KXGZyYWN7XHBhcnRpYWwgXGVsbH17XHBhcnRpYWwgXGJldGF9ID0gXGZyYWN7bn17XGJldGF9IC0gbiBcbG9nIFxsYW1iZGEgKyBcc3VtX3tpPTF9XntufSBcbG9nIHhfaSAtIFxzdW1fe2k9MX1ee259IFxsZWZ0KCBcZnJhY3t4X2l9e1xsYW1iZGF9IFxyaWdodCleXGJldGEgXGxvZyBcbGVmdCggXGZyYWN7eF9pfXtcbGFtYmRhfSBccmlnaHQpDQokJA0KYGBge3J9DQoNCnggPC0gYygNCiAgNS4yLCA3LjgsIDkuMSwgMTEuMywgMTIuNSwgMTMuMCwgMTQuMiwgMTUuMSwgMTUuOSwgMTYuNywgMTcuMiwgMTcuOCwgMTguNCwgMTguOSwNCiAgMTkuMywgMTkuNywgMjAuMiwgMjAuNiwgMjEuMCwgMjEuNSwgMjEuOSwgMjIuMywgMjIuNywgMjMuMSwgMjMuNSwgMjMuOSwgMjQuMywgMjQuNywNCiAgMjUuMSwgMjUuNSwgMjUuOSwgMjYuMywgMjYuNywgMjcuMSwgMjcuNSwgMjcuOSwgMjguMywgMjguNywgMjkuMSwgMjkuNSwgMjkuOSwgMzAuMywNCiAgMzAuNywgMzEuMSwgMzEuNSwgMzEuOSwgMzIuMywgMzIuNywgMzMuMSwgMzMuNSwgMzMuOSwgMzQuMywgMzQuNywgMzUuMSwgMzUuNSwgMzUuOSwNCiAgMzYuMywgMzYuNywgMzcuMSwgMzcuNSwgMzcuOSwgMzguMywgMzguNywgMzkuMSwgMzkuNSwgMzkuOSwgNDAuMywgNDAuNywgNDEuMSwgNDEuNSwNCiAgNDEuOSwgNDIuMywgNDIuNywgNDMuMSwgNDMuNQ0KKQ0KbiA8LSBsZW5ndGgoeCkNCg0KIyBMb2ctbGlrZWxpaG9vZCBmdW5jdGlvbg0Kd2VpYnVsbF9sb2dsaWsgPC0gZnVuY3Rpb24ocGFyLCBkYXRhKSB7DQoNCiAgbGFtYmRhIDwtIHBhclsxXQ0KICBiZXRhICAgPC0gcGFyWzJdDQoNCiAgIyBQYXJhbWV0ZXIgY29uc3RyYWludA0KICBpZiAobGFtYmRhIDw9IDAgfHwgYmV0YSA8PSAwKSByZXR1cm4oLUluZikNCg0KICBsbCA8LSBsZW5ndGgoZGF0YSkgKiBsb2coYmV0YSkgLQ0KICAgICAgICBsZW5ndGgoZGF0YSkgKiBiZXRhICogbG9nKGxhbWJkYSkgKw0KICAgICAgICAoYmV0YSAtIDEpICogc3VtKGxvZyhkYXRhKSkgLQ0KICAgICAgICBzdW0oKGRhdGEgLyBsYW1iZGEpXmJldGEpDQoNCiAgcmV0dXJuKGxsKQ0KfQ0KDQojIE5lZ2F0aXZlIGxvZy1saWtlbGlob29kIChmb3IgbWluaW1pemF0aW9uKQ0Kd2VpYnVsbF9ubGwgPC0gZnVuY3Rpb24ocGFyLCBkYXRhKSB7DQogIHJldHVybigtd2VpYnVsbF9sb2dsaWsocGFyLCBkYXRhKSkNCn0NCg0KIyBHcmFkaWVudCBmdW5jdGlvbg0Kd2VpYnVsbF9ncmFkIDwtIGZ1bmN0aW9uKHBhciwgZGF0YSkgew0KDQogIGxhbWJkYSA8LSBwYXJbMV0NCiAgYmV0YSAgIDwtIHBhclsyXQ0KICBuIDwtIGxlbmd0aChkYXRhKQ0KDQogIHogPC0gKGRhdGEgLyBsYW1iZGEpXmJldGENCg0KICAjIGRlcml2YXRpdmUgd3J0IGxhbWJkYQ0KICBkX2xhbWJkYSA8LSAtIChiZXRhIC8gbGFtYmRhKSAqIChzdW0oeikgLSBuKQ0KDQogICMgZGVyaXZhdGl2ZSB3cnQgYmV0YQ0KICBkX2JldGEgPC0gLSAobiAvIGJldGEgLQ0KICAgICAgICAgICAgICAgbiAqIGxvZyhsYW1iZGEpICsNCiAgICAgICAgICAgICAgIHN1bShsb2coZGF0YSkpIC0NCiAgICAgICAgICAgICAgIHN1bSh6ICogbG9nKGRhdGEgLyBsYW1iZGEpKSkNCg0KICByZXR1cm4oYyhkX2xhbWJkYSwgZF9iZXRhKSkNCn0NCg0KIyBSdW4gb3B0aW1pemF0aW9uDQpmaXRfd2VpYnVsbCA8LSBvcHRpbSgNCiAgcGFyID0gYyhtZWFuKHgpLCAxLjUpLCAgICMgaW5pdGlhbCB2YWx1ZXMNCiAgZm4gID0gd2VpYnVsbF9ubGwsDQogIGdyICA9IHdlaWJ1bGxfZ3JhZCwNCiAgZGF0YSA9IHgsDQogIG1ldGhvZCA9ICJMLUJGR1MtQiIsDQogIGxvd2VyID0gYygxZS04LCAxZS04KQ0KKQ0KDQpmaXRfd2VpYnVsbCRwYXINCmBgYA0KDQoNCioqU3VtbWFyeToqKg0KVXNpbmcgb3B0aW0oKSwgdGhlIG1heGltdW0gbGlrZWxpaG9vZCBlc3RpbWF0ZXMgYXJlICRcaGF0e1xiZXRhfSBcYXBwcm94IDMuMzckLiBUaHVzIHRoZSBmaXR0ZWQgV2VpYnVsbCBtb2RlbCBpcyAkXGhhdHtcbGFtYmRhfSBcYXBwcm94IDMxLjQyJC4NCg0KU2luY2UgJFxoYXR7XGJldGF9ID4gMSQsIHRoZSBmaXR0ZWQgbW9kZWwgc3VnZ2VzdHMgYW4gaW5jcmVhc2luZyBoYXphcmQgcmF0ZSwgd2hpY2ggaXMgY29uc2lzdGVudCB3aXRoIG1lY2hhbmljYWwgd2VhciBhbmQgYWdpbmcuDQoNCg0KYikuIEZpbmQgdGhlIE1MRSBvZiB0aGUgZXhwb25lbnRpYWwgcGFyYW1ldGVyICRcbGFtYmRhJCAoc2NhbGUpLCBkZW5vdGVkIGJ5ICRcaGF0e1xsYW1iZGF9JCwgdXNpbmcgYW55IHByb2NlZHVyZS4gWypIaW50OiBZb3Ugc2hvdWxkIHByb3ZpZGUgZXhwbGljaXQgZXhwcmVzc2lvbnMgZm9yIHRoZSBsb2ctbGlrZWxpaG9vZCBhbmQgZ3JhZGllbnQgZnVuY3Rpb25zIG9mIHRoZSBleHBvbmVudGlhbCBkaXN0cmlidXRpb24gcGFyYW1ldGVycy4qXQ0KDQoNClN0ZXAgMTogTW9kZWwNCg0KV2hlbiAkXGJldGEgPTEkIA0KJGYodDtcbGFtYmRhKSA9IFxmcmFjezF9e1xsYW1iZGF9IGVeey10L1xsYW1iZGF9JCAgDQoNClN0ZXAgMjogTG9nIGxpa2VsaWhvb2QgDQoNCiRcZWxsKFxsYW1iZGEpID0gLW4gXGxvZyBcbGFtYmRhIC0gXGZyYWN7MX17XGxhbWJkYX0gXHN1bV97aT0xfV57bn0geF9pJA0KDQpTdGVwIDM6IERlcml2YXRpdmUNCg0KJFxmcmFje2RcZWxsfXtkXGxhbWJkYX0gPSAtXGZyYWN7bn17XGxhbWJkYX0gKyBcZnJhY3tcc3VtIHhfaX17XGxhbWJkYV4yfSQNClNldCB0byB6ZXJvOiRcaGF0e1xsYW1iZGF9ID0gXGJhcnt4fSQNCg0KYGBge3J9DQoNCiMgRXhwb25lbnRpYWwgTUxFDQpsYW1iZGEwX2hhdCA8LSBtZWFuKHgpDQoNCmxhbWJkYTBfaGF0DQpgYGANCioqU3VtbWFyeToqKiANCg0KVGhlIGVzdGltYXRlIGlzJFxoYXR7XGxhbWJkYX1fMCA9IFxiYXJ7eH0gXGFwcHJveCAyOC4xODUzJC4NCg0KYykuIFVzZSBhKSBhbmQgYikgdG8gcGVyZm9ybSB0aGUgcmVndWxhciBsaWtlbGlob29kIHJhdGlvICRcY2hpXjIkIHRlc3QgZm9yICRcYmV0YSA9IDEkIGFuZCByZXBvcnQgdGhlIHAtdmFsdWUuDQoNCg0KU3RlcCAxOiBTdGF0aXN0aWMNCg0KJExSID0gLTJbXGVsbF8wIC0gXGVsbF8xXSQNCg0KU3RlcCAyOg0KYGBge3J9DQojIEV4cG9uZW50aWFsIGxvZy1saWtlbGlob29kDQpleHBfbG9nbGlrIDwtIGZ1bmN0aW9uKGxhbWJkYSwgZGF0YSkgew0KICAtbGVuZ3RoKGRhdGEpICogbG9nKGxhbWJkYSkgLSBzdW0oZGF0YSkgLyBsYW1iZGENCn0NCg0KIyBDb21wdXRlIGxvZy1saWtlbGlob29kcw0KbG9nTGlrMCA8LSBleHBfbG9nbGlrKGxhbWJkYTBfaGF0LCB4KQ0KDQpsYW1iZGExX2hhdCA8LSBmaXRfd2VpYnVsbCRwYXJbMV0NCmJldGExX2hhdCAgIDwtIGZpdF93ZWlidWxsJHBhclsyXQ0KDQpsb2dMaWsxIDwtIHdlaWJ1bGxfbG9nbGlrKGMobGFtYmRhMV9oYXQsIGJldGExX2hhdCksIHgpDQoNCiMgTGlrZWxpaG9vZCByYXRpbw0KTFJfb2JzIDwtIC0yICogKGxvZ0xpazAgLSBsb2dMaWsxKQ0KDQojIHAtdmFsdWUgKGNoaS1zcXVhcmUpDQpwX2NoaXNxIDwtIDEgLSBwY2hpc3EoTFJfb2JzLCBkZiA9IDEpDQoNCkxSX29icw0KcF9jaGlzcQ0KYGBgDQoNCioqU3VtbWFyeToqKg0KQmVjYXVzZSAkTFIgXGFwcHJveCAxMDAuNjEkICRwIDwgMi4yIFx0aW1lcyAxMF57LTE2fSQgVGhlcmVmb3JlLCBSZWplY3QgJEhfMCQuDQoNCg0KZCkuIFVzZSB0aGUgQkxSVCBhbGdvcml0aG0gdG8gcGVyZm9ybSBhIGJvb3RzdHJhcCBsaWtlbGlob29kIHJhdGlvIHRlc3QgYW5kIHJlcG9ydCB0aGUgYm9vdHN0cmFwIHAtdmFsdWUuIE5vdGUgdGhhdCB5b3UgYXJlIGV4cGVjdGVkIHRvIHRyYW5zbGF0ZSB0aGUgQkxSVCBhbGdvcml0aG0gaW50byBSIGNvZGUgdG8gcGVyZm9ybSB0aGUgQkxSVC4gWypIaW50OiBUaGUgY2hpLXNxdWFyZSBkaXN0cmlidXRpb24gc2hvdWxkIG5vdCBiZSB1c2VkIGluIHRoaXMgcGFydCBvZiB0aGUgYW5hbHlzaXMuKl0NCg0KU3RlcCAxOiBJZGVhSW5zdGVhZCBvZjoNCiRMUiBcc2ltIFxjaGleMiQgd2UgYXBwcm94aW1hdGUgdGhlIGRpc3RyaWJ1dGlvbiB1c2luZyBib290c3RyYXAuDQoNClN0ZXAgMjogQWxnb3JpdGhtDQpGaXQgbW9kZWwgdW5kZXIgJEhfMCQuIFRoZW4sIGdlbmVyYXRlIGJvb3RzdHJhcCBzYW1wbGVzIGZyb20gZXhwb25lbnRpYWwgYW5kIGNvbXB1dGUgTFIgZWFjaCB0aW1lLiBMYXN0LCBDb21wYXJlIHdpdGggb2JzZXJ2ZWQuDQoNClN0ZXAgMzogDQoNCmBgYHtyfQ0Kc2V0LnNlZWQoMTIzKQ0KDQojIEZpdCBleHBvbmVudGlhbA0KZml0X2V4cF9tbGUgPC0gZnVuY3Rpb24oZGF0YSkgew0KICBsYW1iZGFfaGF0IDwtIG1lYW4oZGF0YSkNCiAgbG9nTGlrIDwtIC1sZW5ndGgoZGF0YSkgKiBsb2cobGFtYmRhX2hhdCkgLSBzdW0oZGF0YSkgLyBsYW1iZGFfaGF0DQogIHJldHVybihsaXN0KGxhbWJkYV9oYXQgPSBsYW1iZGFfaGF0LCBsb2dMaWsgPSBsb2dMaWspKQ0KfQ0KDQojIEZpdCBXZWlidWxsDQpmaXRfd2VpYnVsbF9tbGUgPC0gZnVuY3Rpb24oZGF0YSkgew0KICBvdXQgPC0gb3B0aW0oDQogICAgcGFyID0gYyhtZWFuKGRhdGEpLCAxLjUpLA0KICAgIGZuID0gd2VpYnVsbF9ubGwsDQogICAgZ3IgPSB3ZWlidWxsX2dyYWQsDQogICAgZGF0YSA9IGRhdGEsDQogICAgbWV0aG9kID0gIkwtQkZHUy1CIiwNCiAgICBsb3dlciA9IGMoMWUtOCwgMWUtOCkNCiAgKQ0KDQogIHJldHVybihsaXN0KA0KICAgIGxhbWJkYV9oYXQgPSBvdXQkcGFyWzFdLA0KICAgIGJldGFfaGF0ICAgPSBvdXQkcGFyWzJdLA0KICAgIGxvZ0xpayAgICAgPSAtb3V0JHZhbHVlDQogICkpDQp9DQoNCiMgT2JzZXJ2ZWQgc3RhdGlzdGljDQpmaXQwIDwtIGZpdF9leHBfbWxlKHgpDQpmaXQxIDwtIGZpdF93ZWlidWxsX21sZSh4KQ0KDQpMUl9vYnMgPC0gLTIgKiAoZml0MCRsb2dMaWsgLSBmaXQxJGxvZ0xpaykNCg0KIyBCb290c3RyYXANCkIgPC0gMjAwMA0KTFJfYm9vdCA8LSBudW1lcmljKEIpDQoNCmZvciAoYiBpbiAxOkIpIHsNCg0KICAjIEdlbmVyYXRlIGZyb20gSDANCiAgeF9zdGFyIDwtIHJleHAobiwgcmF0ZSA9IDEgLyBmaXQwJGxhbWJkYV9oYXQpDQoNCiAgZml0MF9iIDwtIGZpdF9leHBfbWxlKHhfc3RhcikNCiAgZml0MV9iIDwtIGZpdF93ZWlidWxsX21sZSh4X3N0YXIpDQoNCiAgTFJfYm9vdFtiXSA8LSAtMiAqIChmaXQwX2IkbG9nTGlrIC0gZml0MV9iJGxvZ0xpaykNCn0NCg0KIyBCb290c3RyYXAgcC12YWx1ZQ0KcF9ib290IDwtICgxICsgc3VtKExSX2Jvb3QgPj0gTFJfb2JzKSkgLyAoQiArIDEpDQoNCnBfYm9vdA0KYGBgDQoqKlN1bW1hcnk6KioNCg0KVXNpbmcgJEI9MjAwMCQgYm9vdHN0cmFwIHNhbXBsZXMsIHRoZSBib290c3RyYXAgcC12YWx1ZSBpczokcF97Ym9vdH0gXGFwcHJveCAwLjAwMDUkVGhpcyBpcyBleHRyZW1lbHkgc21hbGwsIHNvIHRoZSBCTFJUIGFsc28gcmVqZWN0cyAkSF8wJC5CZWNhdXNlIGJvb3RzdHJhcCByZXN1bHRzIGRlcGVuZCBzbGlnaHRseSBvbiB0aGUgcmFuZG9tIHNlZWQgYW5kIHRoZSBjaG9zZW4gJEIkLCB0aGUgZXhhY3QgdmFsdWUgbWF5IHZhcnkgYSBsaXR0bGUsIGJ1dCBpdCB3aWxsIHN0aWxsIGJlIHZlcnkgc21hbGwuRGVjaXNpb25TaW5jZSAkcF97Ym9vdH0gXGFwcHJveCAwLjAwMDUgPCAwLjA1JCwgd2UgYWdhaW4gcmVqZWN0ICRIXzA6IFxiZXRhID0gMSQuDQoNCg0KZSkuIFdyaXRlIGEgc3VtbWFyeSBvZiB0aGUgYWJvdmUgYW5hbHlzZXMgdG8gYWRkcmVzcyB0aGUgZm9sbG93aW5nOg0KDQoqIFdoZXRoZXIgdGhlIHR3byB0ZXN0cyBnZW5lcmF0ZWQgdGhlIHNhbWUgcmVzdWx0cy4NCg0KKipTdW1tYXJ5OioqDQpCb3RoIHRoZSBjbGFzc2ljYWwgbGlrZWxpaG9vZCByYXRpbyB0ZXN0IGFuZCB0aGUgYm9vdHN0cmFwIExSVCByZWplY3QgJEhfMDogXGJldGE9MSQsIHdpdGggcC12YWx1ZXMgbmVhciB6ZXJvICgkcCA8IDIuMiBcdGltZXMgMTBeey0xNn0kIGFuZCAkcF97Ym9vdH0gXGFwcHJveCAwLjAwMDUkKS4gVGhpcyBwcm92aWRlcyBzdHJvbmcgZXZpZGVuY2UgdGhhdCB0aGUgZXhwb25lbnRpYWwgbW9kZWwgZG9lcyBub3QgZml0IHRoZSBkYXRhLiBUaGUgZXN0aW1hdGVkIFdlaWJ1bGwgc2hhcGUgcGFyYW1ldGVyICRcaGF0e1xiZXRhfSBcYXBwcm94IDMuMzcgPiAxJCBpbmRpY2F0ZXMgYW4gaW5jcmVhc2luZyBoYXphcmQgcmF0ZSBvdmVyIHRpbWUsIGNvbnNpc3RlbnQgd2l0aCBtZWNoYW5pY2FsIHdlYXIuIFRoZXJlZm9yZSwgdGhlIFdlaWJ1bGwgbW9kZWwgaXMgcHJlZmVycmVkLCB3aGlsZSB0aGUgZXhwb25lbnRpYWwgbW9kZWwgdW5kZXJmaXRzIHRoZSBkYXRhLg0KDQoqIFdoaWNoIG1vZGVsIGlzIHJlY29tbWVuZGVkIGZvciB0aGUgZGF0YS4NCg0KKipTdW1tYXJ5OioqDQpXZWlidWxsIG1vZGVsIGlzIHJlY29tbWVuZGVkIGJlY2F1c2UgaXQgY2FwdHVyZXMgaW5jcmVhc2luZyBmYWlsdXJlIHJpc2sgYW5kIGZpdHMgdGhlIGRhdGEgc2lnbmlmaWNhbnRseSBiZXR0ZXIuDQoNCjwvcD4NCg0KDQoNCg==