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}\]


Question: Reliability Application

A mid-sized manufacturing company producing industrial conveyor systems began experiencing unexpected downtime in one of its distribution facilities, prompting concern about the reliability of a newly sourced batch of ball bearings used in the motor assemblies. These bearings, supplied by a vendor adopting cost-saving production methods, were installed across multiple units operating under continuous load conditions. After several months, maintenance logs revealed a pattern of increasing failures, with components lasting anywhere from a few dozen to over 150 hours before breakdown. To investigate, the engineering team collected time-to-failure data from 50 identical bearings and conducted a Weibull analysis within the framework of Reliability Engineering. The 50 time-to-failure (survival time) are:

12.4, 18.7, 25.3, 30.1, 33.5, 35.2, 38.9, 40.3, 42.7, 45.1, 47.6, 49.8, 52.4, 55.0, 
57.3, 60.2, 62.8, 65.1, 67.9, 70.5, 72.3, 75.6, 78.2, 80.9, 83.4, 85.7, 88.1, 90.6, 
93.2, 95.8, 98.4, 101.0, 104.5, 107.3, 110.6, 113.2, 116.8, 120.1, 123.7, 127.4,
130.9, 134.5, 138.2, 142.0, 146.3, 150.7, 155.2, 160.8, 168.4, 175.9

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.]

#obderved data
x <- c(12.4, 18.7, 25.3, 30.1, 33.5, 35.2, 38.9, 40.3, 42.7, 45.1,
       47.6, 49.8, 52.4, 55.0, 57.3, 60.2, 62.8, 65.1, 67.9, 70.5,
       72.3, 75.6, 78.2, 80.9, 83.4, 85.7, 88.1, 90.6, 93.2, 95.8,
       98.4, 101.0, 104.5, 107.3, 110.6, 113.2, 116.8, 120.1, 123.7, 127.4,
       130.9, 134.5, 138.2, 142.0, 146.3, 150.7, 155.2, 160.8, 168.4, 175.9)
# sample size
n <- length(x)

Manual Solution:

Log-likelihood

For the Weibull density \[ f(t;\lambda,\beta)= \frac{\beta}{\lambda}\left( \frac{t}{\lambda} \right)^{\beta - 1}\exp\!\left[ -\left( \frac{t}{\lambda} \right)^{\beta} \right],\qquad t \ge 0, \] the log-likelihood function is \[ \ell(\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}. \] Score Equations \[ \frac{\partial \ell}{\partial\lambda}=-\frac{n\beta}{\lambda}+\frac{\beta}{\lambda}\sum_{i=1}^{n}\left( \frac{x_i}{\lambda} \right)^{\beta}. \]

\[ \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). \] The maximum likelihood estimates of \(\lambda\) and \(\beta\) , denoted by \(\hat{\lambda}\) and \(\hat{\beta}\), are the solutions to the above system of score equations.

R Verification

# loglikelihood function
log_likelihood <- function(param) {
  lambda <- param[1]
  beta <- param[2]
  ##
  if(lambda <= 0 || beta <= 0) return(-1e12)
  ##
  ll <- n * log(beta) - n * beta * log(lambda) + 
        (beta - 1) * sum(log(x)) - sum((x / lambda)^beta)
  ll
}

# score equations
score_equ <- function(par) {
  lambda <- par[1]
  beta <- par[2]
  ##
  score_lambda <- -n * beta / lambda + (beta / lambda) * sum((x / lambda)^beta)
  score_beta <- n / beta - n * log(lambda) + sum(log(x)) - 
                sum((x / lambda)^beta * log(x / lambda))
  c(score_lambda, score_beta)
}

# MLE
result <- optim(
  par = c(mean(x), 1.5),
  fn = log_likelihood,
  gr = score_equ,
  method = "BFGS",
  hessian = TRUE,
  control = list(fnscale = -1)
)
result
$par
[1] 98.992745  2.205676

$value
[1] -256.4198

$counts
function gradient 
      53       32 

$convergence
[1] 0

$message
NULL

$hessian
            [,1]        [,2]
[1,] -0.02484257   0.2061451
[2,]  0.20614514 -17.6034330
# variance-covariance matrix
varcov <- solve(-result$hessian)
varcov
          [,1]       [,2]
[1,] 44.586112 0.52212600
[2,]  0.522126 0.06292146

Summary: The MLEs of the Weibull parameters are obtained numerically using optim(). The estimated value of \(\beta\) is larger than 1, which suggests an increasing hazard rate over time.

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.]

Manual Solution:

The exponential distribution is a special case of the Weibull distribution when the shape parameter is strictly \(\beta = 1\).

For the exponential density with scale parameter \(\lambda\): \[ f(t; \lambda) = \frac{1}{\lambda} \exp\!\left[ -\frac{t}{\lambda} \right], \qquad t \ge 0 \]

The log-likelihood function is: \[ \ell(\lambda) = -n \log \lambda - \frac{1}{\lambda} \sum_{i=1}^n x_i \]

Solving the score equation yields the exact closed-form Maximum Likelihood Estimator (MLE): \[ \hat{\lambda} = \frac{1}{n} \sum_{i=1}^n x_i = \bar{x} \] \[ \hat{\lambda} = \bar{x} \]

R Verification:

# exponential loglikelihood
log_likelihood_exp <- function(lambda) {
  if(lambda <= 0) return(-1e12)
  -n * log(lambda) - sum(x) / lambda
}

# exponential MLE
lambda_hat_exp <- mean(x)
lambda_hat_exp
[1] 87.61

c). Perform the likelihood ratio \(\chi^2\) test on \(\beta = 1\). What is the p-value? [Hint: Use the results in a) and b).]

Manual Solution:

The likelihood ratio test compares the maximum log-likelihood of the unrestricted model (Weibull, where \(\beta\) is estimated) and the restricted model under \(H_0: \beta = 1\) (Exponential).

Let the unrestricted maximum log-likelihood evaluated at the MLEs be \(\ell(\hat{\lambda}, \hat{\beta})\) and the restricted maximum log-likelihood evaluated at the constrained MLE be \(\ell(\hat{\lambda}_{exp})\).

The likelihood ratio test statistic \(\Lambda\) (often denoted as \(LR\)) is given by: \[ \Lambda = -2 \left[ \ell(\hat{\lambda}_{exp}) - \ell(\hat{\lambda}, \hat{\beta}) \right] = 2 \left[ \ell(\hat{\lambda}, \hat{\beta}) - \ell(\hat{\lambda}_{exp}) \right] \]

Under the null hypothesis \(H_0: \beta = 1\), the test statistic asymptotically follows a chi-square distribution with \(q = 1\) degree of freedom: \[ \Lambda \xrightarrow{d} \chi^2_1 \] The p-value is then calculated as \(P(\chi^2_1 > \Lambda)\).

R Verification:

# compute log-likelihoods explicitly
ll_weibull <- log_likelihood(result$par)
ll_exp <- log_likelihood_exp(lambda_hat_exp)

# LR statistic
LR <- -2 * (ll_exp - ll_weibull)

# p-value
pval_LR <- 1 - pchisq(LR, df = 1)

cat("LR:", LR, "\n")
LR: 34.44994 
cat("p-value:", pval_LR, "\n")
p-value: 4.373569e-09 

d). Perform the Wald \(\chi^2\) on the same hypothesis \(\beta = 1\). What is the p-value? [Hint: You need to find the observed Fisher information matrix (i.e., the negative Hessian matrix from optim()) based on the Weibull distribution. The inverse of the negative observed Hessian matrix is the covariance matrix.] Manual Solution:

For the hypothesis \(H_0: \beta = 1\) versus \(H_1: \beta \neq 1\), the Wald test evaluates the distance between the unconstrained maximum likelihood estimate \(\hat{\beta}\) and the null value \(\beta_0 = 1\), scaled by the estimated variance of \(\hat{\beta}\).

The Wald test statistic is defined as: \[ W = \frac{(\hat{\beta} - 1)^2}{\widehat{\text{Var}}(\hat{\beta})} \] \[ W \xrightarrow{d} \chi^2_1 \]

R Verification:

# Wald test
beta_hat <- result$par[2]

# variance of beta
var_beta <- varcov[2,2]

# Wald statistic
W <- (beta_hat - 1)^2 / var_beta

# p-value
pval_W <- 1 - pchisq(W, df = 1)

cat("W:", W, "\n")
W: 23.10267 
cat("p-value:", pval_W, "\n")
p-value: 1.535777e-06 

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

  • Whether the two tests generated the same results.

Comparison of Tests: Both the Likelihood Ratio test and the Wald test strongly reject the null hypothesis \(H_0: \beta = 1\). While the exact numeric values of the test statistics \(\Lambda\) and \(W\) differ (which is expected in finite samples due to their different geometric approaches to the likelihood space), both yield p-values approaching zero (\(p < 0.001\)). Therefore, both tests provide consistent, overwhelming evidence against the exponential distribution assumption.

  • Which model is recommended for the data.

The Weibull model is recommended for this data. The exponential distribution strictly assumes a constant hazard rate (the memoryless property). However, the unconstrained Weibull model yielded a shape parameter \(\hat{\beta} > 1\) (specifically, \(\hat{\beta} \approx 2.25\)). Mathematically, \(\beta > 1\) indicates an increasing failure rate over time. This aligns perfectly with the physical reality of mechanical wear-out and fatigue in industrial bearings operating under continuous load.

  • Draw the density curve based on the MLE(s) of the parameter(s) and describe the distribution of the time-to-failure.

# plot
hist(x, prob = TRUE, breaks = 12,
     main = "Failure Time Distribution",
     xlab = "Time")

# Weibull
curve(dweibull(x, shape = result$par[2], scale = result$par[1]),
      add = TRUE, col = "blue", lwd = 2)

# exponential
curve(dexp(x, rate = 1/lambda_hat_exp),
      add = TRUE, col = "red", lty = 2, lwd = 2)

legend("topright",
       legend = c("Weibull", "Exponential"),
       col = c("blue","red"),
       lty = c(1,2),
       lwd = 2)

Summary: The histogram and overlapping density curves below illustrate why the Weibull distribution provides a superior fit. The time-to-failure distribution is slightly right-skewed but exhibits a clear peak (mode) around 80-90 hours, indicating that failures cluster around a specific “wear-out” timeframe rather than occurring continuously at random from \(t = 0\) (which the red exponential curve incorrectly assumes).

LS0tDQp0aXRsZTogIkFzc2lnbm1lbnQgOTogRGV0ZWN0aW5nIE92ZXJmaXR0aW5nIGFuZCBPdmVyZml0dGluZyBJc3N1ZXMiDQphdXRob3I6ICJYaWFveWluZyBNYSAiDQpkYXRlOiAiIER1ZTogMDQvMTQvMjAyNiAiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6IA0KICAgIHRvYzogeWVzDQogICAgdG9jX2RlcHRoOiA0DQogICAgdG9jX2Zsb2F0OiB5ZXMNCiAgICBudW1iZXJfc2VjdGlvbnM6IG5vDQogICAgdG9jX2NvbGxhcHNlZDogeWVzDQogICAgY29kZV9mb2xkaW5nOiBoaWRlDQogICAgY29kZV9kb3dubG9hZDogeWVzDQogICAgc21vb3RoX3Njcm9sbDogeWVzDQogICAgaGlnaGxpZ2h0OiBtb25vY2hyb21lDQogICAgdGhlbWU6IHNwYWNlbGFiDQogIHdvcmRfZG9jdW1lbnQ6IA0KICAgIHRvYzogeWVzDQogICAgdG9jX2RlcHRoOiA0DQogICAgZmlnX2NhcHRpb246IHllcw0KICAgIGtlZXBfbWQ6IHllcw0KICBwZGZfZG9jdW1lbnQ6IA0KICAgIHRvYzogeWVzDQogICAgdG9jX2RlcHRoOiA0DQogICAgZmlnX2NhcHRpb246IHllcw0KICAgIG51bWJlcl9zZWN0aW9uczogeWVzDQogICAgZmlnX3dpZHRoOiAzDQogICAgZmlnX2hlaWdodDogMw0KZWRpdG9yX29wdGlvbnM6IA0KICBjaHVua19vdXRwdXRfdHlwZTogaW5saW5lDQotLS0NCg0KYGBge2NzcywgZWNobyA9IEZBTFNFfQ0KI1RPQzo6YmVmb3JlIHsNCiAgY29udGVudDogIlRhYmxlIG9mIENvbnRlbnRzIjsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogIGZvbnQtc2l6ZTogMS4yZW07DQogIGRpc3BsYXk6IGJsb2NrOw0KICBjb2xvcjogbmF2eTsNCiAgbWFyZ2luLWJvdHRvbTogMTBweDsNCn0NCg0KDQpkaXYjVE9DIGxpIHsgICAgIC8qIHRhYmxlIG9mIGNvbnRlbnQgICovDQogICAgbGlzdC1zdHlsZTp1cHBlci1yb21hbjsNCiAgICBiYWNrZ3JvdW5kLWltYWdlOm5vbmU7DQogICAgYmFja2dyb3VuZC1yZXBlYXQ6bm9uZTsNCiAgICBiYWNrZ3JvdW5kLXBvc2l0aW9uOjA7DQp9DQoNCmgxLnRpdGxlIHsgICAgLyogbGV2ZWwgMSBoZWFkZXIgb2YgdGl0bGUgICovDQogIGZvbnQtc2l6ZTogMjJweDsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogIGNvbG9yOiBEYXJrUmVkOw0KICB0ZXh0LWFsaWduOiBjZW50ZXI7DQogIGZvbnQtZmFtaWx5OiAiR2lsbCBTYW5zIiwgc2Fucy1zZXJpZjsNCn0NCg0KaDQuYXV0aG9yIHsgLyogSGVhZGVyIDQgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgZm9udC1zaXplOiAxNXB4Ow0KICBmb250LXdlaWdodDogYm9sZDsNCiAgZm9udC1mYW1pbHk6IHN5c3RlbS11aTsNCiAgY29sb3I6IG5hdnk7DQogIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCg0KaDQuZGF0ZSB7IC8qIEhlYWRlciA0IC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovDQogIGZvbnQtc2l6ZTogMThweDsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogIGZvbnQtZmFtaWx5OiAiR2lsbCBTYW5zIiwgc2Fucy1zZXJpZjsNCiAgY29sb3I6IERhcmtCbHVlOw0KICB0ZXh0LWFsaWduOiBjZW50ZXI7DQp9DQoNCmgxIHsgLyogSGVhZGVyIDEgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgICBmb250LXNpemU6IDIwcHg7DQogICAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IGRhcmtyZWQ7DQogICAgdGV4dC1hbGlnbjogY2VudGVyOw0KfQ0KDQpoMiB7IC8qIEhlYWRlciAyIC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovDQogICAgZm9udC1zaXplOiAxOHB4Ow0KICAgIGZvbnQtd2VpZ2h0OiBib2xkOw0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBuYXZ5Ow0KICAgIHRleHQtYWxpZ246IGxlZnQ7DQp9DQoNCmgzIHsgLyogSGVhZGVyIDMgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgICBmb250LXNpemU6IDE2cHg7DQogICAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IG5hdnk7DQogICAgdGV4dC1hbGlnbjogbGVmdDsNCn0NCg0KaDQgeyAvKiBIZWFkZXIgNCAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICAgIGZvbnQtc2l6ZTogMTRweDsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IGRhcmtyZWQ7DQogICAgdGV4dC1hbGlnbjogbGVmdDsNCn0NCg0KLyogQWRkIGRvdHMgYWZ0ZXIgbnVtYmVyZWQgaGVhZGVycyAqLw0KLmhlYWRlci1zZWN0aW9uLW51bWJlcjo6YWZ0ZXIgew0KICBjb250ZW50OiAiLiI7DQoNCmJvZHkge2JhY2tncm91bmQtY29sb3I6ICNmZmZmZmY7DQogICAgICBjb2xvcjogIzAwMDAwMDsNCiAgICAgIGZvbnQtZmFtaWx5OiBBcmlhbCwgc2Fucy1zZXJpZjsNCiAgICAgIGZvbnQtc2l6ZTogMXJlbTsNCiAgICAgIGxpbmUtaGVpZ2h0OiAxLjY7DQogICAgICB9DQoNCi5oaWdobGlnaHRtZSB7IGJhY2tncm91bmQtY29sb3I6eWVsbG93OyB9DQoNCnAgeyBiYWNrZ3JvdW5kLWNvbG9yOndoaXRlOyB9DQoNCn0NCmBgYA0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCiMgY29kZSBjaHVuayBzcGVjaWZpZXMgd2hldGhlciB0aGUgUiBjb2RlLCB3YXJuaW5ncywgYW5kIG91dHB1dCANCiMgd2lsbCBiZSBpbmNsdWRlZCBpbiB0aGUgb3V0cHV0IGZpbGVzLg0KaWYgKCFyZXF1aXJlKCJrbml0ciIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJrbml0ciIpDQogICBsaWJyYXJ5KGtuaXRyKQ0KfQ0KaWYgKCFyZXF1aXJlKCJwYW5kZXIiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygicGFuZGVyIikNCiAgIGxpYnJhcnkocGFuZGVyKQ0KfQ0KaWYgKCFyZXF1aXJlKCJnZ3Bsb3QyIikpIHsNCiAgaW5zdGFsbC5wYWNrYWdlcygiZ2dwbG90MiIpDQogIGxpYnJhcnkoZ2dwbG90MikNCn0NCmlmICghcmVxdWlyZSgidGlkeXZlcnNlIikpIHsNCiAgaW5zdGFsbC5wYWNrYWdlcygidGlkeXZlcnNlIikNCiAgbGlicmFyeSh0aWR5dmVyc2UpDQp9DQoNCmlmICghcmVxdWlyZSgicGxvdGx5IikpIHsNCiAgaW5zdGFsbC5wYWNrYWdlcygicGxvdGx5IikNCiAgbGlicmFyeShwbG90bHkpDQp9DQoNCmlmICghcmVxdWlyZSgiVkdBTSIpKSB7DQogIGluc3RhbGwucGFja2FnZXMoIlZHQU0iKQ0KICBsaWJyYXJ5KFZHQU0pDQp9DQojIyMjIFZHQU0NCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgICAgICAgIyBpbmNsdWRlIGNvZGUgY2h1bmsgaW4gdGhlIG91dHB1dCBmaWxlDQogICAgICAgICAgICAgICAgICAgICAgd2FybmluZyA9IEZBTFNFLCAgICMgc29tZXRpbWVzLCB5b3UgY29kZSBtYXkgcHJvZHVjZSB3YXJuaW5nIG1lc3NhZ2VzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHlvdSBjYW4gY2hvb3NlIHRvIGluY2x1ZGUgdGhlIHdhcm5pbmcgbWVzc2FnZXMgaW4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyB0aGUgb3V0cHV0IGZpbGUuIA0KICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdHMgPSBUUlVFLCAgICAjIHlvdSBjYW4gYWxzbyBkZWNpZGUgd2hldGhlciB0byBpbmNsdWRlIHRoZSBvdXRwdXQNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBpbiB0aGUgb3V0cHV0IGZpbGUuDQogICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZSA9IEZBTFNFLA0KICAgICAgICAgICAgICAgICAgICAgIGNvbW1lbnQgPSBOQQ0KICAgICAgICAgICAgICAgICAgICAgICkgIA0KYGBgDQogDQogXA0KIA0KDQojIyBUZXN0aW5nIE92ZXJmaXR0aW5nL1VuZGVyZml0dGluZw0KDQpJbiBNYWNoaW5lIExlYXJuaW5nIGFuZCBTdGF0aXN0aWNzLCBvdmVyZml0dGluZyBvY2N1cnMgd2hlbiBhIG1vZGVsIGlzIHRvbyBjb21wbGV4IGFuZCBsZWFybnMgbm9pc2UsIGxlYWRpbmcgdG8gcG9vciBwZXJmb3JtYW5jZSBvbiBuZXcgZGF0YSwgd2hpbGUgdW5kZXJmaXR0aW5nIGhhcHBlbnMgd2hlbiBhIG1vZGVsIGlzIHRvbyBzaW1wbGUgdG8gY2FwdHVyZSBpbXBvcnRhbnQgcGF0dGVybnMsIHJlc3VsdGluZyBpbiBoaWdoIGVycm9ycyBvdmVyYWxsOyBib3RoIGlzc3VlcyBhcmUgZXhwbGFpbmVkIGJ5IHRoZSBCaWFz4oCTVmFyaWFuY2UgVHJhZGVvZmYgYW5kIGNhbiBjYXVzZSB1bnJlbGlhYmxlIHByZWRpY3Rpb25zIGluIHJlYWwtd29ybGQgYXBwbGljYXRpb25zLg0KDQoNClRoZSBwcm9iYWJpbGl0eSBkZW5zaXR5IGZ1bmN0aW9uIChQREYpIG9mIHRoZSBXZWlidWxsIGRpc3RyaWJ1dGlvbiBpczoNCg0KJCQNCmYodDsgXGxhbWJkYSwgXGJldGEpID0gXGZyYWN7XGJldGF9e1xsYW1iZGF9IFxsZWZ0KCBcZnJhY3t0fXtcbGFtYmRhfSBccmlnaHQpXntcYmV0YS0xfSBcZXhwXGxlZnRbIC1cbGVmdCggXGZyYWN7dH17XGxhbWJkYX0gXHJpZ2h0KV5cYmV0YSBccmlnaHRdLCBccXVhZCB0IFxnZSAwDQokJA0Kd2hlcmUgJFxsYW1iZGEgPiAwJCBpcyB0aGUgc2NhbGUgcGFyYW1ldGVyIChjaGFyYWN0ZXJpc3RpYyBsaWZlKSBhbmQgJFxiZXRhID4gMCQgaXMgdGhlIHNoYXBlIHBhcmFtZXRlci4NCg0KV2hlbiAkXGJldGEgPSAxJCwgdGhlIFdlaWJ1bGwgUERGIHNpbXBsaWZpZXMgdG8gdGhlIGV4cG9uZW50aWFsIFBERjoNCg0KJCQNCmYodDsgXGxhbWJkYSkgPSBcZnJhY3sxfXtcbGFtYmRhfSBcZXhwXGxlZnQoIC1cZnJhY3t0fXtcbGFtYmRhfSBccmlnaHQpDQokJA0Kd2l0aCBjb25zdGFudCBoYXphcmQgcmF0ZSAkaCh0KSA9IDEvXGxhbWJkYSQuDQoNCg0KPHA+PGZvbnQgY29sb3IgPSAiZGFya3JlZCI+KipUaGlzIGFzc2lnbm1lbnQgZm9jdXNlcyBvbiBwZXJmb3JtaW5nIGEgaHlwb3RoZXNpcyB0ZXN0IGZvciB0aGUgc2hhcGUgcGFyYW1ldGVyICgkXGJldGEkKSBvZiB0aGUgV2VpYnVsbCBkaXN0cmlidXRpb24gd2l0aGluIGEgcmVsaWFiaWxpdHkgbW9kZSoqPC9mb250PjwvcD4NCg0KDQpcYmVnaW57YWxpZ259DQpIXzAmOiBcYmV0YSA9IDEgXHF1YWQgXHRleHR7KEV4cG9uZW50aWFsIG1vZGVsLCBzaW1wbGVyKX0gXFwNCkhfMSY6IFxiZXRhIFxuZXEgMSBccXVhZCBcdGV4dHsoV2VpYnVsbCBtb2RlbCwgbW9yZSBjb21wbGV4KX0NClxlbmR7YWxpZ259DQoNCg0KXA0KDQojIyAqKlF1ZXN0aW9uOiBSZWxpYWJpbGl0eSBBcHBsaWNhdGlvbioqDQoNCjxwPg0KQSBtaWQtc2l6ZWQgbWFudWZhY3R1cmluZyBjb21wYW55IHByb2R1Y2luZyBpbmR1c3RyaWFsIGNvbnZleW9yIHN5c3RlbXMgYmVnYW4gZXhwZXJpZW5jaW5nIHVuZXhwZWN0ZWQgZG93bnRpbWUgaW4gb25lIG9mIGl0cyBkaXN0cmlidXRpb24gZmFjaWxpdGllcywgcHJvbXB0aW5nIGNvbmNlcm4gYWJvdXQgdGhlIHJlbGlhYmlsaXR5IG9mIGEgbmV3bHkgc291cmNlZCBiYXRjaCBvZiBiYWxsIGJlYXJpbmdzIHVzZWQgaW4gdGhlIG1vdG9yIGFzc2VtYmxpZXMuIFRoZXNlIGJlYXJpbmdzLCBzdXBwbGllZCBieSBhIHZlbmRvciBhZG9wdGluZyBjb3N0LXNhdmluZyBwcm9kdWN0aW9uIG1ldGhvZHMsIHdlcmUgaW5zdGFsbGVkIGFjcm9zcyBtdWx0aXBsZSB1bml0cyBvcGVyYXRpbmcgdW5kZXIgY29udGludW91cyBsb2FkIGNvbmRpdGlvbnMuIEFmdGVyIHNldmVyYWwgbW9udGhzLCBtYWludGVuYW5jZSBsb2dzIHJldmVhbGVkIGEgcGF0dGVybiBvZiBpbmNyZWFzaW5nIGZhaWx1cmVzLCB3aXRoIGNvbXBvbmVudHMgbGFzdGluZyBhbnl3aGVyZSBmcm9tIGEgZmV3IGRvemVuIHRvIG92ZXIgMTUwIGhvdXJzIGJlZm9yZSBicmVha2Rvd24uIFRvIGludmVzdGlnYXRlLCB0aGUgZW5naW5lZXJpbmcgdGVhbSBjb2xsZWN0ZWQgdGltZS10by1mYWlsdXJlIGRhdGEgZnJvbSA1MCBpZGVudGljYWwgYmVhcmluZ3MgYW5kIGNvbmR1Y3RlZCBhIFdlaWJ1bGwgYW5hbHlzaXMgd2l0aGluIHRoZSBmcmFtZXdvcmsgb2YgUmVsaWFiaWxpdHkgRW5naW5lZXJpbmcuIFRoZSA1MCB0aW1lLXRvLWZhaWx1cmUgKHN1cnZpdmFsIHRpbWUpIGFyZToNCg0KYGBgDQoxMi40LCAxOC43LCAyNS4zLCAzMC4xLCAzMy41LCAzNS4yLCAzOC45LCA0MC4zLCA0Mi43LCA0NS4xLCA0Ny42LCA0OS44LCA1Mi40LCA1NS4wLCANCjU3LjMsIDYwLjIsIDYyLjgsIDY1LjEsIDY3LjksIDcwLjUsIDcyLjMsIDc1LjYsIDc4LjIsIDgwLjksIDgzLjQsIDg1LjcsIDg4LjEsIDkwLjYsIA0KOTMuMiwgOTUuOCwgOTguNCwgMTAxLjAsIDEwNC41LCAxMDcuMywgMTEwLjYsIDExMy4yLCAxMTYuOCwgMTIwLjEsIDEyMy43LCAxMjcuNCwNCjEzMC45LCAxMzQuNSwgMTM4LjIsIDE0Mi4wLCAxNDYuMywgMTUwLjcsIDE1NS4yLCAxNjAuOCwgMTY4LjQsIDE3NS45DQpgYGANCjwvcD4NCg0KVGhpcyBhc3NpZ25tZW50IGZvY3VzZXMgb24gaHlwb3RoZXNpcyAkSF8wOiBcYmV0YSA9IDEkIChleHBvbmVudGlhbCkgYWdhaW5zdCAkSF8xOiBcYmV0YSBcbmVxIDEkIChXZWlidWxsKS4gVGhpcyBmcmFtZXdvcmsgZGV0ZWN0cyBvdmVyZml0dGluZyAoZml0dGluZyBhIFdlaWJ1bGwgd2hlbiBleHBvbmVudGlhbCBpcyB0cnVlKSBhbmQgdW5kZXJmaXR0aW5nIChmaXR0aW5nIGV4cG9uZW50aWFsIHdoZW4gV2VpYnVsbCB3aXRoICRcYmV0YSBcbmVxIDEkIGlzIHRydWUpLiANCg0KDQo8cD4NCmEpLiBGaW5kIHRoZSBNTEUgb2YgdGhlIFdlaWJ1bGwgcGFyYW1ldGVycyAkXGxhbWJkYSQgKHNjYWxlKSBhbmQgJFxiZXRhJCAoc2hhcGUpLCBkZW5vdGVkIGJ5ICRcaGF0e1xsYW1iZGF9JCBhbmQgJFxoYXR7XGJldGF9JCwgcmVzcGVjdGl2ZWx5LCB1c2luZyB0aGUgYG9wdGltKClgIHByb2NlZHVyZS4gWypIaW50OiBZb3Ugc2hvdWxkIHByb3ZpZGUgZXhwbGljaXQgZXhwcmVzc2lvbnMgZm9yIHRoZSBsb2ctbGlrZWxpaG9vZCBhbmQgZ3JhZGllbnQgZnVuY3Rpb25zIG9mIHRoZSBXZWlidWxsIGRpc3RyaWJ1dGlvbiBwYXJhbWV0ZXJzLipdDQoNCmBgYHtyfQ0KI29iZGVydmVkIGRhdGENCnggPC0gYygxMi40LCAxOC43LCAyNS4zLCAzMC4xLCAzMy41LCAzNS4yLCAzOC45LCA0MC4zLCA0Mi43LCA0NS4xLA0KICAgICAgIDQ3LjYsIDQ5LjgsIDUyLjQsIDU1LjAsIDU3LjMsIDYwLjIsIDYyLjgsIDY1LjEsIDY3LjksIDcwLjUsDQogICAgICAgNzIuMywgNzUuNiwgNzguMiwgODAuOSwgODMuNCwgODUuNywgODguMSwgOTAuNiwgOTMuMiwgOTUuOCwNCiAgICAgICA5OC40LCAxMDEuMCwgMTA0LjUsIDEwNy4zLCAxMTAuNiwgMTEzLjIsIDExNi44LCAxMjAuMSwgMTIzLjcsIDEyNy40LA0KICAgICAgIDEzMC45LCAxMzQuNSwgMTM4LjIsIDE0Mi4wLCAxNDYuMywgMTUwLjcsIDE1NS4yLCAxNjAuOCwgMTY4LjQsIDE3NS45KQ0KIyBzYW1wbGUgc2l6ZQ0KbiA8LSBsZW5ndGgoeCkNCmBgYA0KKipNYW51YWwgU29sdXRpb24qKjoNCg0KTG9nLWxpa2VsaWhvb2QNCg0KRm9yIHRoZSBXZWlidWxsIGRlbnNpdHkNCiQkDQpmKHQ7XGxhbWJkYSxcYmV0YSk9IFxmcmFje1xiZXRhfXtcbGFtYmRhfVxsZWZ0KCBcZnJhY3t0fXtcbGFtYmRhfSBccmlnaHQpXntcYmV0YSAtIDF9XGV4cFwhXGxlZnRbIC1cbGVmdCggXGZyYWN7dH17XGxhbWJkYX0gXHJpZ2h0KV57XGJldGF9IFxyaWdodF0sXHFxdWFkIHQgXGdlIDAsDQokJA0KdGhlIGxvZy1saWtlbGlob29kIGZ1bmN0aW9uIGlzDQokJA0KXGVsbChcbGFtYmRhLFxiZXRhKT0gbiBcbG9nIFxiZXRhLSBuIFxiZXRhIFxsb2cgXGxhbWJkYSsgKFxiZXRhIC0gMSlcc3VtX3tpPTF9XntufSBcbG9nIHhfaS0gXHN1bV97aT0xfV57bn0gXGxlZnQoIFxmcmFje3hfaX17XGxhbWJkYX0gXHJpZ2h0KV57XGJldGF9Lg0KJCQNClNjb3JlIEVxdWF0aW9ucw0KJCQNClxmcmFje1xwYXJ0aWFsIFxlbGx9e1xwYXJ0aWFsXGxhbWJkYX09LVxmcmFje25cYmV0YX17XGxhbWJkYX0rXGZyYWN7XGJldGF9e1xsYW1iZGF9XHN1bV97aT0xfV57bn1cbGVmdCggXGZyYWN7eF9pfXtcbGFtYmRhfSBccmlnaHQpXntcYmV0YX0uDQokJA0KDQokJA0KXGZyYWN7XHBhcnRpYWwgXGVsbH17XHBhcnRpYWwgXGJldGF9PSBcZnJhY3tufXtcYmV0YX0tIG4gXGxvZyBcbGFtYmRhDQorIFxzdW1fe2k9MX1ee259IFxsb2cgeF9pLSBcc3VtX3tpPTF9XntufVxsZWZ0KCBcZnJhY3t4X2l9e1xsYW1iZGF9IFxyaWdodClee1xiZXRhfVxsb2dcIVxsZWZ0KCBcZnJhY3t4X2l9e1xsYW1iZGF9IFxyaWdodCkuDQokJA0KVGhlIG1heGltdW0gbGlrZWxpaG9vZCBlc3RpbWF0ZXMgb2YgJFxsYW1iZGEkIGFuZCAkXGJldGEkICwgZGVub3RlZCBieSAkXGhhdHtcbGFtYmRhfSQgYW5kICRcaGF0e1xiZXRhfSQsIGFyZSB0aGUgc29sdXRpb25zIHRvIHRoZSBhYm92ZSBzeXN0ZW0gb2Ygc2NvcmUgZXF1YXRpb25zLg0KDQpSIFZlcmlmaWNhdGlvbg0KYGBge3J9DQojIGxvZ2xpa2VsaWhvb2QgZnVuY3Rpb24NCmxvZ19saWtlbGlob29kIDwtIGZ1bmN0aW9uKHBhcmFtKSB7DQogIGxhbWJkYSA8LSBwYXJhbVsxXQ0KICBiZXRhIDwtIHBhcmFtWzJdDQogICMjDQogIGlmKGxhbWJkYSA8PSAwIHx8IGJldGEgPD0gMCkgcmV0dXJuKC0xZTEyKQ0KICAjIw0KICBsbCA8LSBuICogbG9nKGJldGEpIC0gbiAqIGJldGEgKiBsb2cobGFtYmRhKSArIA0KICAgICAgICAoYmV0YSAtIDEpICogc3VtKGxvZyh4KSkgLSBzdW0oKHggLyBsYW1iZGEpXmJldGEpDQogIGxsDQp9DQoNCiMgc2NvcmUgZXF1YXRpb25zDQpzY29yZV9lcXUgPC0gZnVuY3Rpb24ocGFyKSB7DQogIGxhbWJkYSA8LSBwYXJbMV0NCiAgYmV0YSA8LSBwYXJbMl0NCiAgIyMNCiAgc2NvcmVfbGFtYmRhIDwtIC1uICogYmV0YSAvIGxhbWJkYSArIChiZXRhIC8gbGFtYmRhKSAqIHN1bSgoeCAvIGxhbWJkYSleYmV0YSkNCiAgc2NvcmVfYmV0YSA8LSBuIC8gYmV0YSAtIG4gKiBsb2cobGFtYmRhKSArIHN1bShsb2coeCkpIC0gDQogICAgICAgICAgICAgICAgc3VtKCh4IC8gbGFtYmRhKV5iZXRhICogbG9nKHggLyBsYW1iZGEpKQ0KICBjKHNjb3JlX2xhbWJkYSwgc2NvcmVfYmV0YSkNCn0NCg0KIyBNTEUNCnJlc3VsdCA8LSBvcHRpbSgNCiAgcGFyID0gYyhtZWFuKHgpLCAxLjUpLA0KICBmbiA9IGxvZ19saWtlbGlob29kLA0KICBnciA9IHNjb3JlX2VxdSwNCiAgbWV0aG9kID0gIkJGR1MiLA0KICBoZXNzaWFuID0gVFJVRSwNCiAgY29udHJvbCA9IGxpc3QoZm5zY2FsZSA9IC0xKQ0KKQ0KcmVzdWx0DQoNCiMgdmFyaWFuY2UtY292YXJpYW5jZSBtYXRyaXgNCnZhcmNvdiA8LSBzb2x2ZSgtcmVzdWx0JGhlc3NpYW4pDQp2YXJjb3YNCg0KYGBgDQoqKlN1bW1hcnk6KioNClRoZSBNTEVzIG9mIHRoZSBXZWlidWxsIHBhcmFtZXRlcnMgYXJlIG9idGFpbmVkIG51bWVyaWNhbGx5IHVzaW5nIG9wdGltKCkuIFRoZSBlc3RpbWF0ZWQgdmFsdWUgb2YgJFxiZXRhJCBpcyBsYXJnZXIgdGhhbiAxLCB3aGljaCBzdWdnZXN0cyBhbiBpbmNyZWFzaW5nIGhhemFyZCByYXRlIG92ZXIgdGltZS4NCg0KYikuIEZpbmQgdGhlIE1MRSBvZiB0aGUgZXhwb25lbnRpYWwgcGFyYW1ldGVyICRcbGFtYmRhJCAoc2NhbGUpLCBkZW5vdGVkIGJ5ICRcaGF0e1xsYW1iZGF9JCwgdXNpbmcgYW55IHByb2NlZHVyZS4gWypIaW50OiBZb3Ugc2hvdWxkIHByb3ZpZGUgZXhwbGljaXQgZXhwcmVzc2lvbnMgZm9yIHRoZSBsb2ctbGlrZWxpaG9vZCBhbmQgZ3JhZGllbnQgZnVuY3Rpb25zIG9mIHRoZSBleHBvbmVudGlhbCBkaXN0cmlidXRpb24gcGFyYW1ldGVycy4qXQ0KDQoqKk1hbnVhbCBTb2x1dGlvbioqOg0KDQpUaGUgZXhwb25lbnRpYWwgZGlzdHJpYnV0aW9uIGlzIGEgc3BlY2lhbCBjYXNlIG9mIHRoZSBXZWlidWxsIGRpc3RyaWJ1dGlvbiB3aGVuIHRoZSBzaGFwZSBwYXJhbWV0ZXIgaXMgc3RyaWN0bHkgJFxiZXRhID0gMSQuIA0KDQpGb3IgdGhlIGV4cG9uZW50aWFsIGRlbnNpdHkgd2l0aCBzY2FsZSBwYXJhbWV0ZXIgJFxsYW1iZGEkOg0KJCQNCmYodDsgXGxhbWJkYSkgPSBcZnJhY3sxfXtcbGFtYmRhfSBcZXhwXCFcbGVmdFsgLVxmcmFje3R9e1xsYW1iZGF9IFxyaWdodF0sIFxxcXVhZCB0IFxnZSAwDQokJA0KDQpUaGUgbG9nLWxpa2VsaWhvb2QgZnVuY3Rpb24gaXM6DQokJA0KXGVsbChcbGFtYmRhKSA9IC1uIFxsb2cgXGxhbWJkYSAtIFxmcmFjezF9e1xsYW1iZGF9IFxzdW1fe2k9MX1ebiB4X2kNCiQkDQoNClNvbHZpbmcgdGhlIHNjb3JlIGVxdWF0aW9uIHlpZWxkcyB0aGUgZXhhY3QgY2xvc2VkLWZvcm0gTWF4aW11bSBMaWtlbGlob29kIEVzdGltYXRvciAoTUxFKToNCiQkDQpcaGF0e1xsYW1iZGF9ID0gXGZyYWN7MX17bn0gXHN1bV97aT0xfV5uIHhfaSA9IFxiYXJ7eH0NCiQkDQokJA0KXGhhdHtcbGFtYmRhfSAgPSBcYmFye3h9DQokJA0KDQoqKlIgVmVyaWZpY2F0aW9uKio6DQoNCmBgYHtyfQ0KIyBleHBvbmVudGlhbCBsb2dsaWtlbGlob29kDQpsb2dfbGlrZWxpaG9vZF9leHAgPC0gZnVuY3Rpb24obGFtYmRhKSB7DQogIGlmKGxhbWJkYSA8PSAwKSByZXR1cm4oLTFlMTIpDQogIC1uICogbG9nKGxhbWJkYSkgLSBzdW0oeCkgLyBsYW1iZGENCn0NCg0KIyBleHBvbmVudGlhbCBNTEUNCmxhbWJkYV9oYXRfZXhwIDwtIG1lYW4oeCkNCmxhbWJkYV9oYXRfZXhwDQoNCmBgYA0KDQpjKS4gUGVyZm9ybSB0aGUgbGlrZWxpaG9vZCByYXRpbyAkXGNoaV4yJCB0ZXN0IG9uICRcYmV0YSA9IDEkLiBXaGF0IGlzIHRoZSBwLXZhbHVlPyBbKkhpbnQ6IFVzZSB0aGUgcmVzdWx0cyBpbiBhKSBhbmQgYikqLl0gDQoNCioqTWFudWFsIFNvbHV0aW9uKio6DQoNClRoZSBsaWtlbGlob29kIHJhdGlvIHRlc3QgY29tcGFyZXMgdGhlIG1heGltdW0gbG9nLWxpa2VsaWhvb2Qgb2YgdGhlIHVucmVzdHJpY3RlZCBtb2RlbCAoV2VpYnVsbCwgd2hlcmUgJFxiZXRhJCBpcyBlc3RpbWF0ZWQpIGFuZCB0aGUgcmVzdHJpY3RlZCBtb2RlbCB1bmRlciAkSF8wOiBcYmV0YSA9IDEkIChFeHBvbmVudGlhbCkuIA0KDQpMZXQgdGhlIHVucmVzdHJpY3RlZCBtYXhpbXVtIGxvZy1saWtlbGlob29kIGV2YWx1YXRlZCBhdCB0aGUgTUxFcyBiZSAkXGVsbChcaGF0e1xsYW1iZGF9LCBcaGF0e1xiZXRhfSkkIGFuZCB0aGUgcmVzdHJpY3RlZCBtYXhpbXVtIGxvZy1saWtlbGlob29kIGV2YWx1YXRlZCBhdCB0aGUgY29uc3RyYWluZWQgTUxFIGJlICRcZWxsKFxoYXR7XGxhbWJkYX1fe2V4cH0pJC4NCg0KVGhlIGxpa2VsaWhvb2QgcmF0aW8gdGVzdCBzdGF0aXN0aWMgJFxMYW1iZGEkIChvZnRlbiBkZW5vdGVkIGFzICRMUiQpIGlzIGdpdmVuIGJ5Og0KJCQNClxMYW1iZGEgPSAtMiBcbGVmdFsgXGVsbChcaGF0e1xsYW1iZGF9X3tleHB9KSAtIFxlbGwoXGhhdHtcbGFtYmRhfSwgXGhhdHtcYmV0YX0pIFxyaWdodF0gPSAyIFxsZWZ0WyBcZWxsKFxoYXR7XGxhbWJkYX0sIFxoYXR7XGJldGF9KSAtIFxlbGwoXGhhdHtcbGFtYmRhfV97ZXhwfSkgXHJpZ2h0XQ0KJCQNCg0KVW5kZXIgdGhlIG51bGwgaHlwb3RoZXNpcyAkSF8wOiBcYmV0YSA9IDEkLCB0aGUgdGVzdCBzdGF0aXN0aWMgYXN5bXB0b3RpY2FsbHkgZm9sbG93cyBhIGNoaS1zcXVhcmUgZGlzdHJpYnV0aW9uIHdpdGggJHEgPSAxJCBkZWdyZWUgb2YgZnJlZWRvbToNCiQkDQpcTGFtYmRhIFx4cmlnaHRhcnJvd3tkfSBcY2hpXjJfMQ0KJCQNClRoZSBwLXZhbHVlIGlzIHRoZW4gY2FsY3VsYXRlZCBhcyAkUChcY2hpXjJfMSA+IFxMYW1iZGEpJC4NCg0KKipSIFZlcmlmaWNhdGlvbioqOg0KDQpgYGB7cn0NCiMgY29tcHV0ZSBsb2ctbGlrZWxpaG9vZHMgZXhwbGljaXRseQ0KbGxfd2VpYnVsbCA8LSBsb2dfbGlrZWxpaG9vZChyZXN1bHQkcGFyKQ0KbGxfZXhwIDwtIGxvZ19saWtlbGlob29kX2V4cChsYW1iZGFfaGF0X2V4cCkNCg0KIyBMUiBzdGF0aXN0aWMNCkxSIDwtIC0yICogKGxsX2V4cCAtIGxsX3dlaWJ1bGwpDQoNCiMgcC12YWx1ZQ0KcHZhbF9MUiA8LSAxIC0gcGNoaXNxKExSLCBkZiA9IDEpDQoNCmNhdCgiTFI6IiwgTFIsICJcbiIpDQpjYXQoInAtdmFsdWU6IiwgcHZhbF9MUiwgIlxuIikNCmBgYA0KDQpkKS4gUGVyZm9ybSB0aGUgV2FsZCAkXGNoaV4yJCBvbiB0aGUgc2FtZSBoeXBvdGhlc2lzICRcYmV0YSA9IDEkLiBXaGF0IGlzIHRoZSBwLXZhbHVlPyBbKkhpbnQ6IFlvdSBuZWVkIHRvIGZpbmQgdGhlIG9ic2VydmVkIEZpc2hlciBpbmZvcm1hdGlvbiBtYXRyaXggKGkuZS4sIHRoZSBuZWdhdGl2ZSBIZXNzaWFuIG1hdHJpeCBmcm9tIGBvcHRpbSgpYCkgYmFzZWQgb24gdGhlIFdlaWJ1bGwgZGlzdHJpYnV0aW9uLiBUaGUgaW52ZXJzZSBvZiB0aGUgPGZvbnQgY29sb3IgPSAiYmx1ZSI+bmVnYXRpdmU8L2ZvbnQ+IG9ic2VydmVkIEhlc3NpYW4gbWF0cml4IGlzIHRoZSBjb3ZhcmlhbmNlIG1hdHJpeCouXSANCioqTWFudWFsIFNvbHV0aW9uKio6DQoNCkZvciB0aGUgaHlwb3RoZXNpcyAkSF8wOiBcYmV0YSA9IDEkIHZlcnN1cyAkSF8xOiBcYmV0YSBcbmVxIDEkLCB0aGUgV2FsZCB0ZXN0IGV2YWx1YXRlcyB0aGUgZGlzdGFuY2UgYmV0d2VlbiB0aGUgdW5jb25zdHJhaW5lZCBtYXhpbXVtIGxpa2VsaWhvb2QgZXN0aW1hdGUgJFxoYXR7XGJldGF9JCBhbmQgdGhlIG51bGwgdmFsdWUgJFxiZXRhXzAgPSAxJCwgc2NhbGVkIGJ5IHRoZSBlc3RpbWF0ZWQgdmFyaWFuY2Ugb2YgJFxoYXR7XGJldGF9JC4NCg0KVGhlIFdhbGQgdGVzdCBzdGF0aXN0aWMgaXMgZGVmaW5lZCBhczoNCiQkDQpXID0gXGZyYWN7KFxoYXR7XGJldGF9IC0gMSleMn17XHdpZGVoYXR7XHRleHR7VmFyfX0oXGhhdHtcYmV0YX0pfQ0KJCQNCiQkDQpXIFx4cmlnaHRhcnJvd3tkfSBcY2hpXjJfMQ0KJCQNCg0KDQoqKlIgVmVyaWZpY2F0aW9uKio6DQoNCmBgYHtyfQ0KIyBXYWxkIHRlc3QNCmJldGFfaGF0IDwtIHJlc3VsdCRwYXJbMl0NCg0KIyB2YXJpYW5jZSBvZiBiZXRhDQp2YXJfYmV0YSA8LSB2YXJjb3ZbMiwyXQ0KDQojIFdhbGQgc3RhdGlzdGljDQpXIDwtIChiZXRhX2hhdCAtIDEpXjIgLyB2YXJfYmV0YQ0KDQojIHAtdmFsdWUNCnB2YWxfVyA8LSAxIC0gcGNoaXNxKFcsIGRmID0gMSkNCg0KY2F0KCJXOiIsIFcsICJcbiIpDQpjYXQoInAtdmFsdWU6IiwgcHZhbF9XLCAiXG4iKQ0KYGBgDQoNCg0KZSkuIFdyaXRlIGEgc3VtbWFyeSBvZiB0aGUgYWJvdmUgYW5hbHlzZXMgdG8gYWRkcmVzcyB0aGUgZm9sbG93aW5nOg0KDQoqIFdoZXRoZXIgdGhlIHR3byB0ZXN0cyBnZW5lcmF0ZWQgdGhlIHNhbWUgcmVzdWx0cy4NCg0KQ29tcGFyaXNvbiBvZiBUZXN0czogQm90aCB0aGUgTGlrZWxpaG9vZCBSYXRpbyB0ZXN0IGFuZCB0aGUgV2FsZCB0ZXN0IHN0cm9uZ2x5IHJlamVjdCB0aGUgbnVsbCBoeXBvdGhlc2lzICRIXzA6IFxiZXRhID0gMSQuIFdoaWxlIHRoZSBleGFjdCBudW1lcmljIHZhbHVlcyBvZiB0aGUgdGVzdCBzdGF0aXN0aWNzICRcTGFtYmRhJCBhbmQgJFckIGRpZmZlciAod2hpY2ggaXMgZXhwZWN0ZWQgaW4gZmluaXRlIHNhbXBsZXMgZHVlIHRvIHRoZWlyIGRpZmZlcmVudCBnZW9tZXRyaWMgYXBwcm9hY2hlcyB0byB0aGUgbGlrZWxpaG9vZCBzcGFjZSksIGJvdGggeWllbGQgcC12YWx1ZXMgYXBwcm9hY2hpbmcgemVybyAoJHAgPCAwLjAwMSQpLiBUaGVyZWZvcmUsIGJvdGggdGVzdHMgcHJvdmlkZSBjb25zaXN0ZW50LCBvdmVyd2hlbG1pbmcgZXZpZGVuY2UgYWdhaW5zdCB0aGUgZXhwb25lbnRpYWwgZGlzdHJpYnV0aW9uIGFzc3VtcHRpb24uDQoNCiogV2hpY2ggbW9kZWwgaXMgcmVjb21tZW5kZWQgZm9yIHRoZSBkYXRhLg0KDQpUaGUgV2VpYnVsbCBtb2RlbCBpcyByZWNvbW1lbmRlZCBmb3IgdGhpcyBkYXRhLiBUaGUgZXhwb25lbnRpYWwgZGlzdHJpYnV0aW9uIHN0cmljdGx5IGFzc3VtZXMgYSBjb25zdGFudCBoYXphcmQgcmF0ZSAodGhlIG1lbW9yeWxlc3MgcHJvcGVydHkpLiBIb3dldmVyLCB0aGUgdW5jb25zdHJhaW5lZCBXZWlidWxsIG1vZGVsIHlpZWxkZWQgYSBzaGFwZSBwYXJhbWV0ZXIgJFxoYXR7XGJldGF9ID4gMSQgKHNwZWNpZmljYWxseSwgJFxoYXR7XGJldGF9IFxhcHByb3ggMi4yNSQpLiBNYXRoZW1hdGljYWxseSwgJFxiZXRhID4gMSQgaW5kaWNhdGVzIGFuIGluY3JlYXNpbmcgZmFpbHVyZSByYXRlIG92ZXIgdGltZS4gVGhpcyBhbGlnbnMgcGVyZmVjdGx5IHdpdGggdGhlIHBoeXNpY2FsIHJlYWxpdHkgb2YgbWVjaGFuaWNhbCB3ZWFyLW91dCBhbmQgZmF0aWd1ZSBpbiBpbmR1c3RyaWFsIGJlYXJpbmdzIG9wZXJhdGluZyB1bmRlciBjb250aW51b3VzIGxvYWQuDQoNCiogRHJhdyB0aGUgZGVuc2l0eSBjdXJ2ZSBiYXNlZCBvbiB0aGUgTUxFKHMpIG9mIHRoZSBwYXJhbWV0ZXIocykgYW5kIGRlc2NyaWJlIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIHRpbWUtdG8tZmFpbHVyZS4NCjwvcD4NCmBgYHtyfQ0KIyBwbG90DQpoaXN0KHgsIHByb2IgPSBUUlVFLCBicmVha3MgPSAxMiwNCiAgICAgbWFpbiA9ICJGYWlsdXJlIFRpbWUgRGlzdHJpYnV0aW9uIiwNCiAgICAgeGxhYiA9ICJUaW1lIikNCg0KIyBXZWlidWxsDQpjdXJ2ZShkd2VpYnVsbCh4LCBzaGFwZSA9IHJlc3VsdCRwYXJbMl0sIHNjYWxlID0gcmVzdWx0JHBhclsxXSksDQogICAgICBhZGQgPSBUUlVFLCBjb2wgPSAiYmx1ZSIsIGx3ZCA9IDIpDQoNCiMgZXhwb25lbnRpYWwNCmN1cnZlKGRleHAoeCwgcmF0ZSA9IDEvbGFtYmRhX2hhdF9leHApLA0KICAgICAgYWRkID0gVFJVRSwgY29sID0gInJlZCIsIGx0eSA9IDIsIGx3ZCA9IDIpDQoNCmxlZ2VuZCgidG9wcmlnaHQiLA0KICAgICAgIGxlZ2VuZCA9IGMoIldlaWJ1bGwiLCAiRXhwb25lbnRpYWwiKSwNCiAgICAgICBjb2wgPSBjKCJibHVlIiwicmVkIiksDQogICAgICAgbHR5ID0gYygxLDIpLA0KICAgICAgIGx3ZCA9IDIpDQoNCmBgYA0KDQoqKlN1bW1hcnk6KiogVGhlIGhpc3RvZ3JhbSBhbmQgb3ZlcmxhcHBpbmcgZGVuc2l0eSBjdXJ2ZXMgYmVsb3cgaWxsdXN0cmF0ZSB3aHkgdGhlIFdlaWJ1bGwgZGlzdHJpYnV0aW9uIHByb3ZpZGVzIGEgc3VwZXJpb3IgZml0LiBUaGUgdGltZS10by1mYWlsdXJlIGRpc3RyaWJ1dGlvbiBpcyBzbGlnaHRseSByaWdodC1za2V3ZWQgYnV0IGV4aGliaXRzIGEgY2xlYXIgcGVhayAobW9kZSkgYXJvdW5kIDgwLTkwIGhvdXJzLCBpbmRpY2F0aW5nIHRoYXQgZmFpbHVyZXMgY2x1c3RlciBhcm91bmQgYSBzcGVjaWZpYyAid2Vhci1vdXQiIHRpbWVmcmFtZSByYXRoZXIgdGhhbiBvY2N1cnJpbmcgY29udGludW91c2x5IGF0IHJhbmRvbSBmcm9tICR0ID0gMCQgKHdoaWNoIHRoZSByZWQgZXhwb25lbnRpYWwgY3VydmUgaW5jb3JyZWN0bHkgYXNzdW1lcyku