Introduction
For this assignment, we will focus on performing asymptotic \(\chi^2\) hypothesis tests to determine
whether or not a sample came from one distribution or another.
Specifically, we will do a likelihood ratio and Wald \(\chi^2\) to determine if a sample came from
a weibull distribution or an exponential distribution.
The sample we will use for our tests is a sample consisting of
failure times (in hours) for bearings used in motor assemblies at a
distribution company’s facility.
times <- 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)
Part A:
For this part, we will find the maximum likelihood estimators of the
Weibull distribution, treating this sample as if it comes from a Weibull
distribution.
First, we’ll start with the log-likelihood function for the weibull
distribution: $$ \[\begin{align}
\ell(k, \lambda; \mathbf{t}) &= \ln L(k, \lambda; \mathbf{t}) \\
&= \sum_{i=1}^{n} \ln \left[ \frac{k}{\lambda} \left(
\frac{t_i}{\lambda} \right)^{k-1} \exp\left( -\left( \frac{t_i}{\lambda}
\right)^k \right) \right] \\
&= \sum_{i=1}^{n} \left[ \ln k - \ln \lambda + (k-1)(\ln t_i -
\ln \lambda) - \left( \frac{t_i}{\lambda} \right)^k \right] \\
&= \sum_{i=1}^{n} \left[ \ln k - k \ln \lambda + (k-1) \ln t_i -
\left( \frac{t_i}{\lambda} \right)^k \right]
\end{align}\]
$$
From there, we can take the partial derivatives (one with respect to
each variable), set them both equal to 0, and then solve for the two
parameters and get their maximum likelihood estimates. If done right,
the maximum likelihood estimates are: \[
\begin{align}
\hat{\lambda} &= \left( \frac{1}{n} \sum_{i=1}^{n}
x_i^{\hat{\beta}} \right)^{1/\hat{\beta}} \quad \\
\frac{1}{\hat{\beta}} &= \frac{\sum_{i=1}^{n} (t_i^{\hat{\beta}}
\ln x_i)}{\sum_{i=1}^{n} x_i^{\hat{\beta}}} - \frac{1}{n} \sum_{i=1}^{n}
\ln x_i \quad
\end{align}
\]
Where \(\lambda\) is the scale
parameter and \(\beta\) is the shape
parameter.
To obtain these parameters, we will use R’s built in optim()
function, which will solve a system of equations numerically. The
following code will be used to obtain the parameter estimates:
## Manual MLE implementation for Weibull distribution
# Create Weibull log-likelihood function
weibull.loglik <- function(params, data) {
shape <- params[1] # passing the parameters
scale <- params[2]
n <- length(data) # sample size
# Log-likelihood for Weibull distribution
loglik <- n * log(shape) - n * shape * log(scale) +
(shape - 1) * sum(log(data)) -
sum((data / scale)^shape)
return(loglik) # Return
}
# Score equation
weibull.score <- function(params, data) {
shape <- params[1]
scale <- params[2]
n <- length(data)
# Gradient for shape parameter
grad_shape <- n/shape - n * log(scale) +
sum(log(data)) -
sum((data/scale)^shape * log(data/scale))
# Gradient for scale parameter
grad_scale <- -(n * shape)/scale +
(shape/scale) * sum((data/scale)^shape)
return(c(grad_shape, grad_scale))
}
# Need to provide initial values for parameters
initial.params <- c(shape = 1, scale = 5) # Reasonable starting values
# Using optim with Nelder-Mead method
mle.result.weibull <- optim(
par = initial.params,
fn = weibull.loglik,
gr = weibull.score,
data = times,
method = "L-BFGS-B",
hessian = TRUE,
control = list(trace = FALSE,
fnscale = -1,
maxit = 500,
abstol = 1e-8)
)
##
mle.result.weibull$par
shape scale
2.205999 99.020285
mle.result.weibull$hessian
shape scale
shape -17.5910623 0.20545481
scale 0.2054548 -0.02481605
The estimate for the shape parameter is 2.206, while the estimate for
the scale parameter is 99.0203.
To verify, we can use the fitdistr() function from the MASS
package
mle.weibull.fit <- fitdistr(times, "weibull")
mle.weibull.fit
shape scale
2.2064616 99.0593897
( 0.2508946) ( 6.6816324)
They’re just about the same, so we can say that our original
estimates are correct.
Part B
For this part, we will find the maximum likelihood estimator for the
exponential distribution, treating this sample as if it came from an
exponential distribution.
In the case of the exponential distribution, we are only estimating
the scale parameter because an exponential random variable is just a
Weibull random variable with the shape parameter, \(\beta\), set to 1.
Depending on how we write the density function for the exponential,
the resulting maximum likelihood estimate for the scale parameter is:
\[
\hat{\lambda} = \frac{1}{n} \sum x_i = \bar{x} \implies
\frac{1}{\hat{\lambda}} = \frac{n}{\sum x_i} = \frac{1}{\bar{x}}
\]
Regardless of how the estimator is written, the process for solving
for \(\lambda\) is the same. In this
case, since we only have one parameter to solve for, and it has a simple
form, we can use simpler methods to solve for it. Since we already
determined that \(\lambda\) is just the
sample mean, we will use that estimate.
First, since we did it manually in Part A, we can do it manually in
this part as well.
## Manual MLE implementation for Exponential distribution
# Create Exponential Log-Likelihood Function
exponential.loglik <- function(params, data) {
scale <- params[1]
n <- length(data) # sample size
# Log-likelihood for Exponential Distribution
loglik <- -n*log(scale) - sum(data)/scale
return(loglik) # Return
}
# Score equation
exponential.score <- function(params, data) {
scale <- params[1]
n <- length(data)
# Gradient for scale parameter
grad_scale <- -(n/scale) + sum(data)/scale^2
return(grad_scale)
}
# Need to provide initial values for parameters
# Reasonable starting values
# Using optim with Nelder-Mead method
mle.result.exponential <- optim(
par = 5, # Just a generic number for an estimate
fn = exponential.loglik,
gr = exponential.score,
data = times,
method = "L-BFGS-B",
hessian = TRUE,
control = list(trace = FALSE,
fnscale = -1,
maxit = 500,
abstol = 1e-8)
)
##
mle.result.exponential$par
[1] 87.61
Now let’s plug the sample mean for the mle:
## Using Sample Mean as MLE For Exponential
mle.exponential.scale <- mean(times)
mle.exponential.scale
[1] 87.61
The mean of our sample is 87.61, so the estimate for our scale
parameter is 87.61.
To verify, we can use fitdistr() from the MASS
package:
## Verifying MLE For Exponential via fitdistr()
exponential.fit <- fitdistr(times, "exponential")
exponential.fit
rate
0.011414222
(0.001614215)
As we can see, R gave us the estimate for the rate parameter. But we
need the estimate for the scale parameter. The good news is that we can
get the estimate for the scale parameter, as it is just the inverse of
the rate parameter. In other words, scale = 1/rate.
mle.fit <- 1/exponential.fit$estimate
mle.fit
rate
87.61
Part C:
For this part, we will conduct the first of two hypothesis tests to
determine whether or not this data comes from a Weibull distribution or
an exponential distribution. Specifically, we will conduct a likelihood
ratio \(\chi^2\) test. Our null
hypothesis, \(H_0\), is that this data
comes from an exponential distribution. In other words, our null
hypothesis is that \(\beta = 1\). Our
alternative hypothesis, \(H_a\), is
that it our data comes from a Weibull distribution. In other words, our
alternative hypothesis is that \(\beta \neq
1\). To put into symbols: \[
H_0: \beta = 1 (Exponential) \\
H_a: \beta \neq 1 (Weibull)
\]
This test will be done at significance level \(\alpha = 0.05\).
## Likelihood Ratio Test using both Log-Likelihood Functions
# Weibull Log-Likelihood Function
loglike.weibull <- function(data, lambda, beta){
n <- length(data)
n*log(beta)-n*beta*log(lambda)+(beta-1)*sum(log(data))-sum((data/lambda)^beta)
}
# Exponential Log-Likelihood Function
loglike.exponential <- function(data, lambda){
n <- length(data)
-n*log(lambda)-sum(data)/lambda
}
## Evaluate Log Likelihood @ MLE
scale.est.weibull <- mle.result.weibull$par[[2]]
shape.est.weibull <- mle.result.weibull$par[[1]]
scale.est.exponential <- mle.fit
# Exponential vs Weibull Hypotheses
LogLike.Alt <- loglike.weibull(times, scale.est.weibull, shape.est.weibull)
LogLike.Null <- loglike.exponential(times, scale.est.exponential)
ratio <- 2*(LogLike.Alt - LogLike.Null) #Computes likelihood ratio
ratio
rate
34.44995
## Getting p-value for ratio test
pvalue.ratio <- 1 - pchisq(ratio, df = 1) #Gets p-value
pvalue.ratio
rate
4.373531e-09
Our \(\chi^2\) statistic is
34.44995, and the p-value is 4.37 x \(10^-9\), which is obviously less than 0.05,
so it’s safe to say that we can reject the null hypothesis and conclude
that this sample came from a Weibull distribution.
Part D
For this part, we will conduct the second of our two hypothesis tests
to determine whether or not our data came from an exponential or Weibull
distribution. Specifically, we will conduct a Wald \(\chi^2\). The null hypothesis, the
alternative hypothesis, and the level of significance are all the same
as the ones from the likelihood-ratio test from Part C.
First, we have to get the Fisher Information matrix to get the
standard error required for the test.
## Obtaining Hessian and Fisher Matrices
result <- optim(
par = c(1,1),
#need to provide initial values to start the iteration.
# Choosing appropriate initial values is critical.
fn = weibull.loglik, # Caution: need negative log-likelihood
gr = weibull.score,
data = times, # also nee negative score
method = "BFGS", # calling BFGS algorithm
hessian = TRUE, # return Hessian matrix
control = list( # some controls in numerical iteration
fnscale = -1, # turn the minimization to maximization problem
maxit = 1000, # stopping rule 1: cap number of iterations
reltol = 1e-8, # stopping rule: precision control
REPORT = 10) # The algorithm will print progress updates
# every 10 iterations
)
Hess <- result$hessian
Hess
[,1] [,2]
[1,] -17.591017 0.20545403
[2,] 0.205454 -0.02481605
Fisher <- -Hess
Fisher
[,1] [,2]
[1,] 17.591017 -0.20545403
[2,] -0.205454 0.02481605
Covar <- Fisher^-1
Covar
[,1] [,2]
[1,] 0.05684719 -4.867269
[2,] -4.86726882 40.296494
Next, we
## Obtaining Standard Error for the Wald Test
var.shape <- Covar[2, 2] # Gets variance of beta
se.shape <- sqrt(var.shape) # Gets standard deviation of beta
shape.est <- result$par[1] #Gets MLE of beta
shape.est
[1] 2.206002
Wald <- (shape.est - 1)^2/var.shape #Gets Wald test statistic
Wald
[1] 0.03609346
pvalue.wald <- 1 - pchisq(Wald, df = 1)
pvalue.ratio
rate
4.373531e-09
Our Wald chi-square statistic is 0.0361, and the p-value is 4.37 x
10^-9, which is way less than 0.05, which means we can reject our null
hypothesis and conclude that our data came from a weibull
distribution.
Part E
With both of our tests, we rejected the null hypothesis, meaning we
concluded that there is evidence to suggest that our data came from a
weibull distribution with both tests. Since that is the case, the
weibull distribution is recommended for this sample.
LS0tDQp0aXRsZTogIlNUQSA1MDYgQXNzaWdubWVudCAxMDogV2FsZCwgU2NvcmUsIGFuZCBMaWtlbGlob29kIFJhdGlvIFRlc3RzIg0KYXV0aG9yOiAiSWFuIFZhbldyaWdodCINCmRhdGU6ICIwNC8xNi8yMDI2Ig0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50OiANCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogNA0KICAgIHRvY19mbG9hdDogeWVzDQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgICB0b2NfY29sbGFwc2VkOiB5ZXMNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMNCiAgICBzbW9vdGhfc2Nyb2xsOiB5ZXMNCiAgICB0aGVtZTogbHVtZW4NCiAgcGRmX2RvY3VtZW50OiANCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogNA0KICAgIGZpZ19jYXB0aW9uOiB5ZXMNCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcw0KICAgIGZpZ193aWR0aDogMw0KICAgIGZpZ19oZWlnaHQ6IDMNCiAgd29yZF9kb2N1bWVudDogDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDQNCiAgICBmaWdfY2FwdGlvbjogeWVzDQogICAga2VlcF9tZDogeWVzDQplZGl0b3Jfb3B0aW9uczogDQogIGNodW5rX291dHB1dF90eXBlOiBpbmxpbmUNCi0tLQ0KDQpgYGB7Y3NzLCBlY2hvID0gRkFMU0V9DQojVE9DOjpiZWZvcmUgew0KICBjb250ZW50OiAiVGFibGUgb2YgQ29udGVudHMiOw0KICBmb250LXdlaWdodDogYm9sZDsNCiAgZm9udC1zaXplOiAxLjJlbTsNCiAgZGlzcGxheTogYmxvY2s7DQogIGNvbG9yOiBuYXZ5Ow0KICBtYXJnaW4tYm90dG9tOiAxMHB4Ow0KfQ0KDQoNCmRpdiNUT0MgbGkgeyAgICAgLyogdGFibGUgb2YgY29udGVudCAgKi8NCiAgICBsaXN0LXN0eWxlOnVwcGVyLXJvbWFuOw0KICAgIGJhY2tncm91bmQtaW1hZ2U6bm9uZTsNCiAgICBiYWNrZ3JvdW5kLXJlcGVhdDpub25lOw0KICAgIGJhY2tncm91bmQtcG9zaXRpb246MDsNCn0NCg0KaDEudGl0bGUgeyAgICAvKiBsZXZlbCAxIGhlYWRlciBvZiB0aXRsZSAgKi8NCiAgZm9udC1zaXplOiAyMnB4Ow0KICBmb250LXdlaWdodDogYm9sZDsNCiAgY29sb3I6IERhcmtSZWQ7DQogIHRleHQtYWxpZ246IGNlbnRlcjsNCiAgZm9udC1mYW1pbHk6ICJHaWxsIFNhbnMiLCBzYW5zLXNlcmlmOw0KfQ0KDQpoNC5hdXRob3IgeyAvKiBIZWFkZXIgNCAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICBmb250LXNpemU6IDE1cHg7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KICBmb250LWZhbWlseTogc3lzdGVtLXVpOw0KICBjb2xvcjogbmF2eTsNCiAgdGV4dC1hbGlnbjogY2VudGVyOw0KfQ0KDQpoNC5kYXRlIHsgLyogSGVhZGVyIDQgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgZm9udC1zaXplOiAxOHB4Ow0KICBmb250LXdlaWdodDogYm9sZDsNCiAgZm9udC1mYW1pbHk6ICJHaWxsIFNhbnMiLCBzYW5zLXNlcmlmOw0KICBjb2xvcjogRGFya0JsdWU7DQogIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCg0KaDEgeyAvKiBIZWFkZXIgMSAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICAgIGZvbnQtc2l6ZTogMjBweDsNCiAgICBmb250LXdlaWdodDogYm9sZDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogZGFya3JlZDsNCiAgICB0ZXh0LWFsaWduOiBjZW50ZXI7DQp9DQoNCmgyIHsgLyogSGVhZGVyIDIgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgICBmb250LXNpemU6IDE4cHg7DQogICAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IG5hdnk7DQogICAgdGV4dC1hbGlnbjogbGVmdDsNCn0NCg0KaDMgeyAvKiBIZWFkZXIgMyAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICAgIGZvbnQtc2l6ZTogMTZweDsNCiAgICBmb250LXdlaWdodDogYm9sZDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogbmF2eTsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KDQpoNCB7IC8qIEhlYWRlciA0IC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovDQogICAgZm9udC1zaXplOiAxNHB4Ow0KICBmb250LXdlaWdodDogYm9sZDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogZGFya3JlZDsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KDQovKiBBZGQgZG90cyBhZnRlciBudW1iZXJlZCBoZWFkZXJzICovDQouaGVhZGVyLXNlY3Rpb24tbnVtYmVyOjphZnRlciB7DQogIGNvbnRlbnQ6ICIuIjsNCg0KYm9keSB7IGJhY2tncm91bmQtY29sb3I6d2hpdGU7IH0NCg0KLmhpZ2hsaWdodG1lIHsgYmFja2dyb3VuZC1jb2xvcjp5ZWxsb3c7IH0NCg0KcCB7IGJhY2tncm91bmQtY29sb3I6d2hpdGU7IH0NCg0KfQ0KYGBgDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0KIyBjb2RlIGNodW5rIHNwZWNpZmllcyB3aGV0aGVyIHRoZSBSIGNvZGUsIHdhcm5pbmdzLCBhbmQgb3V0cHV0IA0KIyB3aWxsIGJlIGluY2x1ZGVkIGluIHRoZSBvdXRwdXQgZmlsZXMuDQppZiAoIXJlcXVpcmUoImtuaXRyIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoImtuaXRyIikNCiAgIGxpYnJhcnkoa25pdHIpDQp9DQppZiAoIXJlcXVpcmUoInBhbmRlciIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJwYW5kZXIiKQ0KICAgbGlicmFyeShwYW5kZXIpDQp9DQppZiAoIXJlcXVpcmUoInBzeWNoIikpIHsNCiAgaW5zdGFsbC5wYWNrYWdlcygicHN5Y2giKQ0KICBsaWJyYXJ5KHBzeWNoKQ0KfQ0KaWYgKCFyZXF1aXJlKCJSQ29sb3JCcmV3ZXIiKSkgew0KICBpbnN0YWxsLnBhY2thZ2VzKCJSQ29sb3JCcmV3ZXIiKQ0KICBsaWJyYXJ5KFJDb2xvckJyZXdlcikNCn0NCg0KaWYgKCFyZXF1aXJlKCJib290IikpIHsNCiAgaW5zdGFsbC5wYWNrYWdlcygiYm9vdCIpDQogIGxpYnJhcnkoYm9vdCkNCn0NCmlmICghcmVxdWlyZSgiZWZmc2l6ZSIpKSB7DQogIGluc3RhbGwucGFja2FnZXMoImVmZnNpemUiKQ0KICBsaWJyYXJ5KGVmZnNpemUpDQp9DQppZiAoIXJlcXVpcmUoIk1BU1MiKSkgew0KICBpbnN0YWxsLnBhY2thZ2VzKCJNQVNTIikNCiAgbGlicmFyeShNQVNTKQ0KfQ0KDQojIyBsaWJyYXJ5KGVmZnNpemUpDQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsICAgICAgICMgaW5jbHVkZSBjb2RlIGNodW5rIGluIHRoZSBvdXRwdXQgZmlsZQ0KICAgICAgICAgICAgICAgICAgICAgIHdhcm5pbmcgPSBGQUxTRSwgICAjIHNvbWV0aW1lcywgeW91IGNvZGUgbWF5IHByb2R1Y2Ugd2FybmluZyBtZXNzYWdlcywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyB5b3UgY2FuIGNob29zZSB0byBpbmNsdWRlIHRoZSB3YXJuaW5nIG1lc3NhZ2VzIGluDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgdGhlIG91dHB1dCBmaWxlLiANCiAgICAgICAgICAgICAgICAgICAgICByZXN1bHRzID0gVFJVRSwgICAgIyB5b3UgY2FuIGFsc28gZGVjaWRlIHdoZXRoZXIgdG8gaW5jbHVkZSB0aGUgb3V0cHV0DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgaW4gdGhlIG91dHB1dCBmaWxlLg0KICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSwNCiAgICAgICAgICAgICAgICAgICAgICBjb21tZW50ID0gTkENCiAgICAgICAgICAgICAgICAgICAgICApICANCmBgYA0KDQpcDQoNCiMgSW50cm9kdWN0aW9uDQpGb3IgdGhpcyBhc3NpZ25tZW50LCB3ZSB3aWxsIGZvY3VzIG9uIHBlcmZvcm1pbmcgYXN5bXB0b3RpYyAkXGNoaV4yJCBoeXBvdGhlc2lzIHRlc3RzIHRvIGRldGVybWluZSB3aGV0aGVyIG9yIG5vdCBhIHNhbXBsZSBjYW1lIGZyb20gb25lIGRpc3RyaWJ1dGlvbiBvciBhbm90aGVyLiBTcGVjaWZpY2FsbHksIHdlIHdpbGwgZG8gYSBsaWtlbGlob29kIHJhdGlvIGFuZCBXYWxkICRcY2hpXjIkIHRvIGRldGVybWluZSBpZiBhIHNhbXBsZSBjYW1lIGZyb20gYSB3ZWlidWxsIGRpc3RyaWJ1dGlvbiBvciBhbiBleHBvbmVudGlhbCBkaXN0cmlidXRpb24uDQoNClRoZSBzYW1wbGUgd2Ugd2lsbCB1c2UgZm9yIG91ciB0ZXN0cyBpcyBhIHNhbXBsZSBjb25zaXN0aW5nIG9mIGZhaWx1cmUgdGltZXMgKGluIGhvdXJzKSBmb3IgYmVhcmluZ3MgdXNlZCBpbiBtb3RvciBhc3NlbWJsaWVzIGF0IGEgZGlzdHJpYnV0aW9uIGNvbXBhbnkncyBmYWNpbGl0eS4NCmBgYHtyfQ0KdGltZXMgPC0gYygxMi40LCAxOC43LCAyNS4zLCAzMC4xLCAzMy41LCAzNS4yLCAzOC45LCA0MC4zLCA0Mi43LCA0NS4xLCA0Ny42LCA0OS44LCA1Mi40LCA1NS4wLCANCjU3LjMsIDYwLjIsIDYyLjgsIDY1LjEsIDY3LjksIDcwLjUsIDcyLjMsIDc1LjYsIDc4LjIsIDgwLjksIDgzLjQsIDg1LjcsIDg4LjEsIDkwLjYsIA0KOTMuMiwgOTUuOCwgOTguNCwgMTAxLjAsIDEwNC41LCAxMDcuMywgMTEwLjYsIDExMy4yLCAxMTYuOCwgMTIwLjEsIDEyMy43LCAxMjcuNCwNCjEzMC45LCAxMzQuNSwgMTM4LjIsIDE0Mi4wLCAxNDYuMywgMTUwLjcsIDE1NS4yLCAxNjAuOCwgMTY4LjQsIDE3NS45KQ0KYGBgDQoNCiMgUGFydCBBOg0KRm9yIHRoaXMgcGFydCwgd2Ugd2lsbCBmaW5kIHRoZSBtYXhpbXVtIGxpa2VsaWhvb2QgZXN0aW1hdG9ycyBvZiB0aGUgV2VpYnVsbCBkaXN0cmlidXRpb24sIHRyZWF0aW5nIHRoaXMgc2FtcGxlIGFzIGlmIGl0IGNvbWVzIGZyb20gYSBXZWlidWxsIGRpc3RyaWJ1dGlvbi4NCg0KRmlyc3QsIHdlJ2xsIHN0YXJ0IHdpdGggdGhlIGxvZy1saWtlbGlob29kIGZ1bmN0aW9uIGZvciB0aGUgd2VpYnVsbCBkaXN0cmlidXRpb246DQokJA0KXGJlZ2lue2FsaWdufQ0KICAgIFxlbGwoaywgXGxhbWJkYTsgXG1hdGhiZnt0fSkgJj0gXGxuIEwoaywgXGxhbWJkYTsgXG1hdGhiZnt0fSkgXFwNCiAgICAmPSBcc3VtX3tpPTF9XntufSBcbG4gXGxlZnRbIFxmcmFje2t9e1xsYW1iZGF9IFxsZWZ0KCBcZnJhY3t0X2l9e1xsYW1iZGF9IFxyaWdodClee2stMX0gXGV4cFxsZWZ0KCAtXGxlZnQoIFxmcmFje3RfaX17XGxhbWJkYX0gXHJpZ2h0KV5rIFxyaWdodCkgXHJpZ2h0XSBcXA0KICAgICY9IFxzdW1fe2k9MX1ee259IFxsZWZ0WyBcbG4gayAtIFxsbiBcbGFtYmRhICsgKGstMSkoXGxuIHRfaSAtIFxsbiBcbGFtYmRhKSAtIFxsZWZ0KCBcZnJhY3t0X2l9e1xsYW1iZGF9IFxyaWdodCleayBccmlnaHRdIFxcDQogICAgJj0gXHN1bV97aT0xfV57bn0gXGxlZnRbIFxsbiBrIC0gayBcbG4gXGxhbWJkYSArIChrLTEpIFxsbiB0X2kgLSBcbGVmdCggXGZyYWN7dF9pfXtcbGFtYmRhfSBccmlnaHQpXmsgXHJpZ2h0XQ0KXGVuZHthbGlnbn0NCg0KJCQNCg0KRnJvbSB0aGVyZSwgd2UgY2FuIHRha2UgdGhlIHBhcnRpYWwgZGVyaXZhdGl2ZXMgKG9uZSB3aXRoIHJlc3BlY3QgdG8gZWFjaCB2YXJpYWJsZSksIHNldCB0aGVtIGJvdGggZXF1YWwgdG8gMCwgYW5kIHRoZW4gc29sdmUgZm9yIHRoZSB0d28gcGFyYW1ldGVycyBhbmQgZ2V0IHRoZWlyIG1heGltdW0gbGlrZWxpaG9vZCBlc3RpbWF0ZXMuIElmIGRvbmUgcmlnaHQsIHRoZSBtYXhpbXVtIGxpa2VsaWhvb2QgZXN0aW1hdGVzIGFyZToNCiQkDQpcYmVnaW57YWxpZ259DQogICAgXGhhdHtcbGFtYmRhfSAmPSBcbGVmdCggXGZyYWN7MX17bn0gXHN1bV97aT0xfV57bn0geF9pXntcaGF0e1xiZXRhfX0gXHJpZ2h0KV57MS9caGF0e1xiZXRhfX0gXHF1YWQgXFwNCiAgICBcZnJhY3sxfXtcaGF0e1xiZXRhfX0gJj0gXGZyYWN7XHN1bV97aT0xfV57bn0gKHRfaV57XGhhdHtcYmV0YX19IFxsbiB4X2kpfXtcc3VtX3tpPTF9XntufSB4X2lee1xoYXR7XGJldGF9fX0gLSBcZnJhY3sxfXtufSBcc3VtX3tpPTF9XntufSBcbG4geF9pIFxxdWFkDQpcZW5ke2FsaWdufQ0KJCQNCg0KV2hlcmUgJFxsYW1iZGEkIGlzIHRoZSBzY2FsZSBwYXJhbWV0ZXIgYW5kICRcYmV0YSQgaXMgdGhlIHNoYXBlIHBhcmFtZXRlci4NCg0KVG8gb2J0YWluIHRoZXNlIHBhcmFtZXRlcnMsIHdlIHdpbGwgdXNlIFIncyBidWlsdCBpbiBvcHRpbSgpIGZ1bmN0aW9uLCB3aGljaCB3aWxsIHNvbHZlIGEgc3lzdGVtIG9mIGVxdWF0aW9ucyBudW1lcmljYWxseS4gVGhlIGZvbGxvd2luZyBjb2RlIHdpbGwgYmUgdXNlZCB0byBvYnRhaW4gdGhlIHBhcmFtZXRlciBlc3RpbWF0ZXM6DQpgYGB7cn0NCiMjIE1hbnVhbCBNTEUgaW1wbGVtZW50YXRpb24gZm9yIFdlaWJ1bGwgZGlzdHJpYnV0aW9uDQoNCiMgQ3JlYXRlIFdlaWJ1bGwgbG9nLWxpa2VsaWhvb2QgZnVuY3Rpb24NCndlaWJ1bGwubG9nbGlrIDwtIGZ1bmN0aW9uKHBhcmFtcywgZGF0YSkgew0KICBzaGFwZSA8LSBwYXJhbXNbMV0gICMgcGFzc2luZyB0aGUgcGFyYW1ldGVycw0KICBzY2FsZSA8LSBwYXJhbXNbMl0NCg0KbiA8LSBsZW5ndGgoZGF0YSkgICAjIHNhbXBsZSBzaXplDQogIA0KIyBMb2ctbGlrZWxpaG9vZCBmb3IgV2VpYnVsbCBkaXN0cmlidXRpb24NCmxvZ2xpayA8LSBuICogbG9nKHNoYXBlKSAtIG4gKiBzaGFwZSAqIGxvZyhzY2FsZSkgKyANCiAgICAgICAgICAgIChzaGFwZSAtIDEpICogc3VtKGxvZyhkYXRhKSkgLSANCiAgICAgICAgICAgIHN1bSgoZGF0YSAvIHNjYWxlKV5zaGFwZSkNCiAgDQogIHJldHVybihsb2dsaWspICAgICMgUmV0dXJuDQp9DQoNCg0KIyBTY29yZSBlcXVhdGlvbg0KDQp3ZWlidWxsLnNjb3JlIDwtIGZ1bmN0aW9uKHBhcmFtcywgZGF0YSkgew0KICBzaGFwZSA8LSBwYXJhbXNbMV0NCiAgc2NhbGUgPC0gcGFyYW1zWzJdDQogIG4gPC0gbGVuZ3RoKGRhdGEpDQogIA0KIyBHcmFkaWVudCBmb3Igc2hhcGUgcGFyYW1ldGVyDQpncmFkX3NoYXBlIDwtIG4vc2hhcGUgLSBuICogbG9nKHNjYWxlKSArIA0KICAgICAgICAgICAgICAgIHN1bShsb2coZGF0YSkpIC0gDQogICAgICAgICAgICAgICAgc3VtKChkYXRhL3NjYWxlKV5zaGFwZSAqIGxvZyhkYXRhL3NjYWxlKSkNCiAgDQojIEdyYWRpZW50IGZvciBzY2FsZSBwYXJhbWV0ZXINCmdyYWRfc2NhbGUgPC0gLShuICogc2hhcGUpL3NjYWxlICsgDQogICAgICAgICAgICAgICAgKHNoYXBlL3NjYWxlKSAqIHN1bSgoZGF0YS9zY2FsZSlec2hhcGUpDQogIA0KICByZXR1cm4oYyhncmFkX3NoYXBlLCBncmFkX3NjYWxlKSkNCn0NCg0KIyBOZWVkIHRvIHByb3ZpZGUgaW5pdGlhbCB2YWx1ZXMgZm9yIHBhcmFtZXRlcnMNCmluaXRpYWwucGFyYW1zIDwtIGMoc2hhcGUgPSAxLCBzY2FsZSA9IDUpICAjIFJlYXNvbmFibGUgc3RhcnRpbmcgdmFsdWVzDQoNCg0KIyBVc2luZyBvcHRpbSB3aXRoIE5lbGRlci1NZWFkIG1ldGhvZA0KbWxlLnJlc3VsdC53ZWlidWxsIDwtIG9wdGltKA0KICBwYXIgPSBpbml0aWFsLnBhcmFtcywNCiAgZm4gPSB3ZWlidWxsLmxvZ2xpaywNCiAgZ3IgPSB3ZWlidWxsLnNjb3JlLA0KICBkYXRhID0gdGltZXMsDQogIG1ldGhvZCA9ICJMLUJGR1MtQiIsDQogIGhlc3NpYW4gPSBUUlVFLA0KICBjb250cm9sID0gbGlzdCh0cmFjZSA9IEZBTFNFLA0KICAgICAgICAgICAgICAgICBmbnNjYWxlID0gLTEsDQogICAgICAgICAgICAgICAgIG1heGl0ID0gNTAwLA0KICAgICAgICAgICAgICAgICBhYnN0b2wgPSAxZS04KQ0KKQ0KIyMNCm1sZS5yZXN1bHQud2VpYnVsbCRwYXINCm1sZS5yZXN1bHQud2VpYnVsbCRoZXNzaWFuDQpgYGANClRoZSBlc3RpbWF0ZSBmb3IgdGhlIHNoYXBlIHBhcmFtZXRlciBpcyAyLjIwNiwgd2hpbGUgdGhlIGVzdGltYXRlIGZvciB0aGUgc2NhbGUgcGFyYW1ldGVyIGlzIDk5LjAyMDMuDQoNClRvIHZlcmlmeSwgd2UgY2FuIHVzZSB0aGUgZml0ZGlzdHIoKSBmdW5jdGlvbiBmcm9tIHRoZSBNQVNTIHBhY2thZ2UNCg0KYGBge3J9DQptbGUud2VpYnVsbC5maXQgPC0gZml0ZGlzdHIodGltZXMsICJ3ZWlidWxsIikNCm1sZS53ZWlidWxsLmZpdA0KYGBgDQpUaGV5J3JlIGp1c3QgYWJvdXQgdGhlIHNhbWUsIHNvIHdlIGNhbiBzYXkgdGhhdCBvdXIgb3JpZ2luYWwgZXN0aW1hdGVzIGFyZSBjb3JyZWN0Lg0KDQoNCiMgUGFydCBCDQpGb3IgdGhpcyBwYXJ0LCB3ZSB3aWxsIGZpbmQgdGhlIG1heGltdW0gbGlrZWxpaG9vZCBlc3RpbWF0b3IgZm9yIHRoZSBleHBvbmVudGlhbCBkaXN0cmlidXRpb24sIHRyZWF0aW5nIHRoaXMgc2FtcGxlIGFzIGlmIGl0IGNhbWUgZnJvbSBhbiBleHBvbmVudGlhbCBkaXN0cmlidXRpb24uDQoNCkluIHRoZSBjYXNlIG9mIHRoZSBleHBvbmVudGlhbCBkaXN0cmlidXRpb24sIHdlIGFyZSBvbmx5IGVzdGltYXRpbmcgdGhlIHNjYWxlIHBhcmFtZXRlciBiZWNhdXNlIGFuIGV4cG9uZW50aWFsIHJhbmRvbSB2YXJpYWJsZSBpcyBqdXN0IGEgV2VpYnVsbCByYW5kb20gdmFyaWFibGUgd2l0aCB0aGUgc2hhcGUgcGFyYW1ldGVyLCAkXGJldGEkLCBzZXQgdG8gMS4NCg0KRGVwZW5kaW5nIG9uIGhvdyB3ZSB3cml0ZSB0aGUgZGVuc2l0eSBmdW5jdGlvbiBmb3IgdGhlIGV4cG9uZW50aWFsLCB0aGUgcmVzdWx0aW5nIG1heGltdW0gbGlrZWxpaG9vZCBlc3RpbWF0ZSBmb3IgdGhlIHNjYWxlIHBhcmFtZXRlciBpczoNCiQkDQpcaGF0e1xsYW1iZGF9ID0gXGZyYWN7MX17bn0gXHN1bSB4X2kgPSBcYmFye3h9IFxpbXBsaWVzIFxmcmFjezF9e1xoYXR7XGxhbWJkYX19ID0gXGZyYWN7bn17XHN1bSB4X2l9ID0gXGZyYWN7MX17XGJhcnt4fX0NCiQkIA0KDQpSZWdhcmRsZXNzIG9mIGhvdyB0aGUgZXN0aW1hdG9yIGlzIHdyaXR0ZW4sIHRoZSBwcm9jZXNzIGZvciBzb2x2aW5nIGZvciAkXGxhbWJkYSQgaXMgdGhlIHNhbWUuIEluIHRoaXMgY2FzZSwgc2luY2Ugd2Ugb25seSBoYXZlIG9uZSBwYXJhbWV0ZXIgdG8gc29sdmUgZm9yLCBhbmQgaXQgaGFzIGEgc2ltcGxlIGZvcm0sIHdlIGNhbiB1c2Ugc2ltcGxlciBtZXRob2RzIHRvIHNvbHZlIGZvciBpdC4gU2luY2Ugd2UgYWxyZWFkeSBkZXRlcm1pbmVkIHRoYXQgJFxsYW1iZGEkIGlzIGp1c3QgdGhlIHNhbXBsZSBtZWFuLCB3ZSB3aWxsIHVzZSB0aGF0IGVzdGltYXRlLg0KDQpGaXJzdCwgc2luY2Ugd2UgZGlkIGl0IG1hbnVhbGx5IGluIFBhcnQgQSwgd2UgY2FuIGRvIGl0IG1hbnVhbGx5IGluIHRoaXMgcGFydCBhcyB3ZWxsLg0KDQpgYGB7cn0NCiMjIE1hbnVhbCBNTEUgaW1wbGVtZW50YXRpb24gZm9yIEV4cG9uZW50aWFsIGRpc3RyaWJ1dGlvbg0KDQojIENyZWF0ZSBFeHBvbmVudGlhbCBMb2ctTGlrZWxpaG9vZCBGdW5jdGlvbg0KZXhwb25lbnRpYWwubG9nbGlrIDwtIGZ1bmN0aW9uKHBhcmFtcywgZGF0YSkgew0KICBzY2FsZSA8LSBwYXJhbXNbMV0NCg0KbiA8LSBsZW5ndGgoZGF0YSkgICAjIHNhbXBsZSBzaXplDQogIA0KIyBMb2ctbGlrZWxpaG9vZCBmb3IgRXhwb25lbnRpYWwgRGlzdHJpYnV0aW9uDQpsb2dsaWsgPC0gLW4qbG9nKHNjYWxlKSAtIHN1bShkYXRhKS9zY2FsZQ0KICANCiAgcmV0dXJuKGxvZ2xpaykgICAgIyBSZXR1cm4gDQp9DQoNCg0KIyBTY29yZSBlcXVhdGlvbg0KDQpleHBvbmVudGlhbC5zY29yZSA8LSBmdW5jdGlvbihwYXJhbXMsIGRhdGEpIHsNCiAgc2NhbGUgPC0gcGFyYW1zWzFdDQogIG4gPC0gbGVuZ3RoKGRhdGEpDQoNCiAgDQojIEdyYWRpZW50IGZvciBzY2FsZSBwYXJhbWV0ZXINCmdyYWRfc2NhbGUgPC0gLShuL3NjYWxlKSArIHN1bShkYXRhKS9zY2FsZV4yDQoNCiAgcmV0dXJuKGdyYWRfc2NhbGUpDQp9DQoNCiMgTmVlZCB0byBwcm92aWRlIGluaXRpYWwgdmFsdWVzIGZvciBwYXJhbWV0ZXJzDQogICMgUmVhc29uYWJsZSBzdGFydGluZyB2YWx1ZXMNCg0KDQojIFVzaW5nIG9wdGltIHdpdGggTmVsZGVyLU1lYWQgbWV0aG9kDQptbGUucmVzdWx0LmV4cG9uZW50aWFsIDwtIG9wdGltKA0KICBwYXIgPSA1LCAjIEp1c3QgYSBnZW5lcmljIG51bWJlciBmb3IgYW4gZXN0aW1hdGUNCiAgZm4gPSBleHBvbmVudGlhbC5sb2dsaWssDQogIGdyID0gZXhwb25lbnRpYWwuc2NvcmUsDQogIGRhdGEgPSB0aW1lcywNCiAgbWV0aG9kID0gIkwtQkZHUy1CIiwNCiAgaGVzc2lhbiA9IFRSVUUsDQogIGNvbnRyb2wgPSBsaXN0KHRyYWNlID0gRkFMU0UsDQogICAgICAgICAgICAgICAgIGZuc2NhbGUgPSAtMSwNCiAgICAgICAgICAgICAgICAgbWF4aXQgPSA1MDAsDQogICAgICAgICAgICAgICAgIGFic3RvbCA9IDFlLTgpDQopDQojIw0KbWxlLnJlc3VsdC5leHBvbmVudGlhbCRwYXINCmBgYA0KTm93IGxldCdzIHBsdWcgdGhlIHNhbXBsZSBtZWFuIGZvciB0aGUgbWxlOg0KYGBge3J9DQojIyBVc2luZyBTYW1wbGUgTWVhbiBhcyBNTEUgRm9yIEV4cG9uZW50aWFsIA0KDQptbGUuZXhwb25lbnRpYWwuc2NhbGUgPC0gbWVhbih0aW1lcykNCm1sZS5leHBvbmVudGlhbC5zY2FsZQ0KYGBgDQoNClRoZSBtZWFuIG9mIG91ciBzYW1wbGUgaXMgODcuNjEsIHNvIHRoZSBlc3RpbWF0ZSBmb3Igb3VyIHNjYWxlIHBhcmFtZXRlciBpcyA4Ny42MS4NCg0KVG8gdmVyaWZ5LCB3ZSBjYW4gdXNlIGZpdGRpc3RyKCkgZnJvbSB0aGUgYE1BU1NgIHBhY2thZ2U6DQpgYGB7cn0NCiMjIFZlcmlmeWluZyBNTEUgRm9yIEV4cG9uZW50aWFsIHZpYSBmaXRkaXN0cigpDQoNCmV4cG9uZW50aWFsLmZpdCA8LSBmaXRkaXN0cih0aW1lcywgImV4cG9uZW50aWFsIikNCmV4cG9uZW50aWFsLmZpdA0KYGBgDQpBcyB3ZSBjYW4gc2VlLCBSIGdhdmUgdXMgdGhlIGVzdGltYXRlIGZvciB0aGUgcmF0ZSBwYXJhbWV0ZXIuIEJ1dCB3ZSBuZWVkIHRoZSBlc3RpbWF0ZSBmb3IgdGhlIHNjYWxlIHBhcmFtZXRlci4gVGhlIGdvb2QgbmV3cyBpcyB0aGF0IHdlIGNhbiBnZXQgdGhlIGVzdGltYXRlIGZvciB0aGUgc2NhbGUgcGFyYW1ldGVyLCBhcyBpdCBpcyBqdXN0IHRoZSBpbnZlcnNlIG9mIHRoZSByYXRlIHBhcmFtZXRlci4gSW4gb3RoZXIgd29yZHMsIHNjYWxlID0gMS9yYXRlLg0KDQpgYGB7cn0NCm1sZS5maXQgPC0gMS9leHBvbmVudGlhbC5maXQkZXN0aW1hdGUNCm1sZS5maXQNCmBgYA0KDQojIFBhcnQgQzoNCkZvciB0aGlzIHBhcnQsIHdlIHdpbGwgY29uZHVjdCB0aGUgZmlyc3Qgb2YgdHdvIGh5cG90aGVzaXMgdGVzdHMgdG8gZGV0ZXJtaW5lIHdoZXRoZXIgb3Igbm90IHRoaXMgZGF0YSBjb21lcyBmcm9tIGEgV2VpYnVsbCBkaXN0cmlidXRpb24gb3IgYW4gZXhwb25lbnRpYWwgZGlzdHJpYnV0aW9uLiBTcGVjaWZpY2FsbHksIHdlIHdpbGwgY29uZHVjdCBhIGxpa2VsaWhvb2QgcmF0aW8gJFxjaGleMiQgdGVzdC4gT3VyIG51bGwgaHlwb3RoZXNpcywgJEhfMCQsIGlzIHRoYXQgdGhpcyBkYXRhIGNvbWVzIGZyb20gYW4gZXhwb25lbnRpYWwgZGlzdHJpYnV0aW9uLiBJbiBvdGhlciB3b3Jkcywgb3VyIG51bGwgaHlwb3RoZXNpcyBpcyB0aGF0ICRcYmV0YSA9IDEkLiBPdXIgYWx0ZXJuYXRpdmUgaHlwb3RoZXNpcywgJEhfYSQsIGlzIHRoYXQgaXQgb3VyIGRhdGEgY29tZXMgZnJvbSBhIFdlaWJ1bGwgZGlzdHJpYnV0aW9uLiBJbiBvdGhlciB3b3Jkcywgb3VyIGFsdGVybmF0aXZlIGh5cG90aGVzaXMgaXMgdGhhdCAkXGJldGEgXG5lcSAxJC4gVG8gcHV0IGludG8gc3ltYm9sczoNCiQkDQpIXzA6IFxiZXRhID0gMSAoRXhwb25lbnRpYWwpIFxcDQpIX2E6IFxiZXRhIFxuZXEgMSAoV2VpYnVsbCkNCiQkIA0KDQpUaGlzIHRlc3Qgd2lsbCBiZSBkb25lIGF0IHNpZ25pZmljYW5jZSBsZXZlbCAkXGFscGhhID0gMC4wNSQuIA0KYGBge3J9DQojIyBMaWtlbGlob29kIFJhdGlvIFRlc3QgdXNpbmcgYm90aCBMb2ctTGlrZWxpaG9vZCBGdW5jdGlvbnMNCg0KIyBXZWlidWxsIExvZy1MaWtlbGlob29kIEZ1bmN0aW9uDQpsb2dsaWtlLndlaWJ1bGwgPC0gZnVuY3Rpb24oZGF0YSwgbGFtYmRhLCBiZXRhKXsNCiAgbiA8LSBsZW5ndGgoZGF0YSkNCiAgbipsb2coYmV0YSktbipiZXRhKmxvZyhsYW1iZGEpKyhiZXRhLTEpKnN1bShsb2coZGF0YSkpLXN1bSgoZGF0YS9sYW1iZGEpXmJldGEpDQp9DQoNCiMgRXhwb25lbnRpYWwgTG9nLUxpa2VsaWhvb2QgRnVuY3Rpb24NCmxvZ2xpa2UuZXhwb25lbnRpYWwgPC0gZnVuY3Rpb24oZGF0YSwgbGFtYmRhKXsgDQogIG4gPC0gbGVuZ3RoKGRhdGEpDQogIC1uKmxvZyhsYW1iZGEpLXN1bShkYXRhKS9sYW1iZGENCn0NCg0KIyMgRXZhbHVhdGUgTG9nIExpa2VsaWhvb2QgQCBNTEUNCnNjYWxlLmVzdC53ZWlidWxsIDwtIG1sZS5yZXN1bHQud2VpYnVsbCRwYXJbWzJdXQ0Kc2hhcGUuZXN0LndlaWJ1bGwgPC0gbWxlLnJlc3VsdC53ZWlidWxsJHBhcltbMV1dDQpzY2FsZS5lc3QuZXhwb25lbnRpYWwgPC0gbWxlLmZpdA0KDQojIEV4cG9uZW50aWFsIHZzIFdlaWJ1bGwgSHlwb3RoZXNlcw0KTG9nTGlrZS5BbHQgPC0gbG9nbGlrZS53ZWlidWxsKHRpbWVzLCBzY2FsZS5lc3Qud2VpYnVsbCwgc2hhcGUuZXN0LndlaWJ1bGwpDQpMb2dMaWtlLk51bGwgPC0gbG9nbGlrZS5leHBvbmVudGlhbCh0aW1lcywgc2NhbGUuZXN0LmV4cG9uZW50aWFsKQ0KDQpyYXRpbyA8LSAyKihMb2dMaWtlLkFsdCAtIExvZ0xpa2UuTnVsbCkgI0NvbXB1dGVzIGxpa2VsaWhvb2QgcmF0aW8NCnJhdGlvDQpgYGANCg0KYGBge3J9DQojIyBHZXR0aW5nIHAtdmFsdWUgZm9yIHJhdGlvIHRlc3QNCnB2YWx1ZS5yYXRpbyA8LSAxIC0gcGNoaXNxKHJhdGlvLCBkZiA9IDEpICNHZXRzIHAtdmFsdWUNCnB2YWx1ZS5yYXRpbw0KYGBgDQpPdXIgJFxjaGleMiQgc3RhdGlzdGljIGlzIDM0LjQ0OTk1LCBhbmQgdGhlIHAtdmFsdWUgaXMgNC4zNyB4ICQxMF4tOSQsIHdoaWNoIGlzIG9idmlvdXNseSBsZXNzIHRoYW4gMC4wNSwgc28gaXQncyBzYWZlIHRvIHNheSB0aGF0IHdlIGNhbiByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcyBhbmQgY29uY2x1ZGUgdGhhdCB0aGlzIHNhbXBsZSBjYW1lIGZyb20gYSBXZWlidWxsIGRpc3RyaWJ1dGlvbi4NCg0KIyBQYXJ0IEQNCkZvciB0aGlzIHBhcnQsIHdlIHdpbGwgY29uZHVjdCB0aGUgc2Vjb25kIG9mIG91ciB0d28gaHlwb3RoZXNpcyB0ZXN0cyB0byBkZXRlcm1pbmUgd2hldGhlciBvciBub3Qgb3VyIGRhdGEgY2FtZSBmcm9tIGFuIGV4cG9uZW50aWFsIG9yIFdlaWJ1bGwgZGlzdHJpYnV0aW9uLiBTcGVjaWZpY2FsbHksIHdlIHdpbGwgY29uZHVjdCBhIFdhbGQgJFxjaGleMiQuIFRoZSBudWxsIGh5cG90aGVzaXMsIHRoZSBhbHRlcm5hdGl2ZSBoeXBvdGhlc2lzLCBhbmQgdGhlIGxldmVsIG9mIHNpZ25pZmljYW5jZSBhcmUgYWxsIHRoZSBzYW1lIGFzIHRoZSBvbmVzIGZyb20gdGhlIGxpa2VsaWhvb2QtcmF0aW8gdGVzdCBmcm9tIFBhcnQgQy4NCg0KRmlyc3QsIHdlIGhhdmUgdG8gZ2V0IHRoZSBGaXNoZXIgSW5mb3JtYXRpb24gbWF0cml4IHRvIGdldCB0aGUgc3RhbmRhcmQgZXJyb3IgcmVxdWlyZWQgZm9yIHRoZSB0ZXN0Lg0KYGBge3J9DQojIyBPYnRhaW5pbmcgSGVzc2lhbiBhbmQgRmlzaGVyIE1hdHJpY2VzDQoNCnJlc3VsdCA8LSBvcHRpbSgNCiAgICAgICAgICBwYXIgPSBjKDEsMSksIA0KICAgICAgICAgICNuZWVkIHRvIHByb3ZpZGUgaW5pdGlhbCB2YWx1ZXMgdG8gc3RhcnQgdGhlIGl0ZXJhdGlvbi4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgQ2hvb3NpbmcgYXBwcm9wcmlhdGUgaW5pdGlhbCB2YWx1ZXMgaXMgY3JpdGljYWwuDQogICAgICAgICAgZm4gPSB3ZWlidWxsLmxvZ2xpaywgICAgICMgQ2F1dGlvbjogbmVlZCBuZWdhdGl2ZSBsb2ctbGlrZWxpaG9vZA0KICAgICAgICAgIGdyID0gd2VpYnVsbC5zY29yZSwgDQogICAgICAgICAgZGF0YSA9IHRpbWVzLCAjIGFsc28gbmVlIG5lZ2F0aXZlIHNjb3JlDQogICAgICAgICAgbWV0aG9kID0gIkJGR1MiLCAgICAgICAgICAjIGNhbGxpbmcgQkZHUyBhbGdvcml0aG0NCiAgICAgICAgICBoZXNzaWFuID0gVFJVRSwgICAgICAgICAgICMgcmV0dXJuIEhlc3NpYW4gbWF0cml4DQogICAgICAgICAgY29udHJvbCA9IGxpc3QoICAgICAgICAgICAjIHNvbWUgY29udHJvbHMgaW4gbnVtZXJpY2FsIGl0ZXJhdGlvbg0KICAgICAgICAgICAgICAgIGZuc2NhbGUgPSAtMSwgICAgICAgIyB0dXJuIHRoZSBtaW5pbWl6YXRpb24gdG8gbWF4aW1pemF0aW9uIHByb2JsZW0NCiAgICAgICAgICAgICAgICBtYXhpdCA9IDEwMDAsICAgICAgICMgc3RvcHBpbmcgcnVsZSAxOiBjYXAgbnVtYmVyIG9mIGl0ZXJhdGlvbnMNCiAgICAgICAgICAgICAgICByZWx0b2wgPSAxZS04LCAgICAgICMgc3RvcHBpbmcgcnVsZTogcHJlY2lzaW9uIGNvbnRyb2wNCiAgICAgICAgICAgICAgICBSRVBPUlQgPSAxMCkgICAgICAgICAjIFRoZSBhbGdvcml0aG0gd2lsbCBwcmludCBwcm9ncmVzcyB1cGRhdGVzIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBldmVyeSAxMCBpdGVyYXRpb25zDQopDQoNCkhlc3MgPC0gcmVzdWx0JGhlc3NpYW4NCkhlc3MNCkZpc2hlciA8LSAtSGVzcw0KRmlzaGVyDQpDb3ZhciA8LSBGaXNoZXJeLTENCkNvdmFyDQpgYGANCk5leHQsIHdlIA0KYGBge3J9DQojIyBPYnRhaW5pbmcgU3RhbmRhcmQgRXJyb3IgZm9yIHRoZSBXYWxkIFRlc3QNCg0KdmFyLnNoYXBlIDwtIENvdmFyWzIsIDJdICMgR2V0cyB2YXJpYW5jZSBvZiBiZXRhDQpzZS5zaGFwZSA8LSBzcXJ0KHZhci5zaGFwZSkgIyBHZXRzIHN0YW5kYXJkIGRldmlhdGlvbiBvZiBiZXRhDQoNCnNoYXBlLmVzdCA8LSByZXN1bHQkcGFyWzFdICNHZXRzIE1MRSBvZiBiZXRhDQpzaGFwZS5lc3QNCg0KV2FsZCA8LSAoc2hhcGUuZXN0IC0gMSleMi92YXIuc2hhcGUgI0dldHMgV2FsZCB0ZXN0IHN0YXRpc3RpYw0KV2FsZA0KDQpwdmFsdWUud2FsZCA8LSAxIC0gcGNoaXNxKFdhbGQsIGRmID0gMSkNCnB2YWx1ZS5yYXRpbw0KYGBgDQpPdXIgV2FsZCBjaGktc3F1YXJlIHN0YXRpc3RpYyBpcyAwLjAzNjEsIGFuZCB0aGUgcC12YWx1ZSBpcyA0LjM3IHggMTBeLTksIHdoaWNoIGlzIHdheSBsZXNzIHRoYW4gMC4wNSwgd2hpY2ggbWVhbnMgd2UgY2FuIHJlamVjdCBvdXIgbnVsbCBoeXBvdGhlc2lzIGFuZCBjb25jbHVkZSB0aGF0IG91ciBkYXRhIGNhbWUgZnJvbSBhIHdlaWJ1bGwgZGlzdHJpYnV0aW9uLg0KDQojIFBhcnQgRQ0KV2l0aCBib3RoIG9mIG91ciB0ZXN0cywgd2UgcmVqZWN0ZWQgdGhlIG51bGwgaHlwb3RoZXNpcywgbWVhbmluZyB3ZSBjb25jbHVkZWQgdGhhdCB0aGVyZSBpcyBldmlkZW5jZSB0byBzdWdnZXN0IHRoYXQgb3VyIGRhdGEgY2FtZSBmcm9tIGEgd2VpYnVsbCBkaXN0cmlidXRpb24gd2l0aCBib3RoIHRlc3RzLiBTaW5jZSB0aGF0IGlzIHRoZSBjYXNlLCB0aGUgd2VpYnVsbCBkaXN0cmlidXRpb24gaXMgcmVjb21tZW5kZWQgZm9yIHRoaXMgc2FtcGxlLg==