1 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)

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

3 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 

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

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

6 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==