data = rbind.data.frame(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)
colnames(data) = "time"

Intro and Setup

For this analysis we are examining a dataset composed of 50 survival times (the recorded times from start until failure) of identically manufactured ball bearings. Over previous months, associates have recognized what they believe to be an increase in the unreliability of these bearings. A summary and visualization of the 50 recorded survival times are below.

sum_stats_table = function(variable){
  table = cbind(
    round(min(variable),2),
    round(quantile(variable, 0.25),2),
    round(median(variable),2),
    round(mean(variable),2),
    round(quantile(variable, 0.75),2),
    round(max(variable),2)
  )
  colnames(table) = c("Min", "Q1", "Med", "Mean", "Q3", "Max")
  rownames(table) = NULL
  return(table)
}

Summary_Table = sum_stats_table(variable = data$time)
kable(Summary_Table,align = "c",
      caption = "<span style='color:##000000;'>
      Summary Stats of Survival Times </span>") %>%
  kable_styling(
    bootstrap_options = c("striped", "bordered"),
    full_width = FALSE,
    position = "center")
Summary Stats of Survival Times
Min Q1 Med Mean Q3 Max
12.4 53.05 84.55 87.61 119.27 175.9
ggplot(data = data) +
  geom_histogram(mapping = aes(x = time, y = after_stat(density)),
                 color = "black",
                  # argument color in geom_histogram is for color of bin lines
                 fill = "lightblue",
                 bins = 10,) +
  labs(title = "Distribution of Survival Times",
       x = "Time",
       y = "Density") + 
  theme(
    panel.border = element_rect(color = "black", fill = NA, linewidth = 3)
  ) # this is the equivalent of box(lwd = 3) in base R

For the purposes of this analysis, our default assumption (null hypothesis) is that the \(\beta\) term of the broader population of ball bearings at hand is equal to 1. If this is truly the case, then our population is exponentially distributed. However, given the makeup of the density formulas for both exponential and Weibull distributions, if \(\beta \ne\) 1, that means our population is Weibull distributed. Knowing a population’s true distribution is valuable for future predictive analysis, making this a worthwhile exercise.

\[\begin{align} H_0&: \beta = 1 \quad \text{Takeaway: Exponential} \\ H_a&: \beta \neq 1 \quad \text{Takeaway: Weibull} \end{align}\]

a.) MLE of Weibull Distribution

The first way that we will attempt to estimate \(\beta\) (the shape parameter) is via maximum likelihood estimation (MLE). We will also simultaneously use MLE to estimate the scale parameter, \(\lambda\). We will denote these estimates as \(\hat{\beta}\) and \(\hat{\lambda}\) respectively.

In the process of performing likelihood estimation, the log-likelihood function for the Weibull distribution as well as the partial derivatives of that very function with respect to both \(\beta\) and \(\lambda\) are below.

\[\Large \ell(\beta,\lambda|t) = [n * ln(\beta)] - [n*\beta *ln(\lambda)] + [(\beta - 1) * \sum(ln(t_i))] - \sum(\frac{(t_i)}{\lambda})^\beta \]

\[\Large \frac{\partial f}{\partial \beta} = \frac{n}{\beta} - n * ln(\lambda) + \sum(ln(t_i) - \sum(ln\frac{t_i}{\lambda}) * (\frac{t_i}{\lambda})^\beta \]
\[\Large \frac{\partial f}{\partial \lambda} = \frac{\beta}{\lambda} * \sum(\frac{t_i}{\lambda})^\beta - n \]

## the log likelihood function simply runs a logarithm through all the terms and accounts for the summation of all data points, as opposed to one value of our variable t


##### Overall process is from section 5.2 of this week's notes

## reference week 7 section 5 notes for distribution-specific functions and formulas below

#### define likelihood function
## *negative* log likelihood function for Weibull distribution
  # by negative log likelihood, this function....
log_likelihood = function(params, data) {
  beta = params[1]  # shape
  lambda = params[2]  # scale 
  
  # Ensure parameters are positive
  if (beta <= 0 || lambda <= 0) {
    return(1e10)  # Return large value for invalid parameters
  }
  
  n = length(data)
  log_lik = n * log(beta) - n * beta * log(lambda) + 
    (beta - 1) * sum(log(data)) - sum((data / lambda)^beta)
  
  return(log_lik)  # Return log-likelihood! NOT the negative log-likelihood
}


#### define score equations (partial derivatives)
## gradient (partial derivatives) of *negative* log likelihood function  for Weibull distribution
log_likelihood_gradient = function(params, data) {
  beta = params[1]       # shape parameter
  lambda = params[2]  # scale parameter
  
  n = length(data)
  
  partial_deriv_beta = n/beta - n * log(lambda) + sum(log(data)) - 
        sum(log(data/lambda) * (data/lambda)^beta)
  
  partial_deriv_lambda =  (beta/lambda)*(sum((data/lambda)^beta) -n)
  
  return(c(partial_deriv_beta,
           partial_deriv_lambda))  # Gradient of log-likelihood, NOT the negative scores
}


#### use log likelihood and score equations in optim function

# need to have good initial guesses for beta and lambda for the optim function
  # reference section 5.2 of week 7 "Asymptotic Sampling" notes
beta_guess = (sd(data$time)/mean(data$time))^(-1.086)

lambda_guess = mean(data$time)/gamma(1 + 1/beta_guess)


weib_mle_estimates = optim(
  par = c(beta_guess, lambda_guess), # par argument is initial "guesses"
  data = data$time,
  fn = log_likelihood,
  gr = log_likelihood_gradient,
  method = "L-BFGS-B",
  hessian = TRUE,
    # will use the Hessian matrix later on
  control = list(maxit = 1000, 
                 fnscale  = -1,
                 trace = FALSE,
                 abstol = 1e-8)
)
#weib_mle_estimates
  
weib_mle_beta = weib_mle_estimates$par[1] # shape
weib_mle_lambda = weib_mle_estimates$par[2] # scale

Utilizing R’s optim() function, along with the log likelihood and partial derivatives of the Weibull distribution, this round of MLE-based estimates yielded a value for \(\beta\) of roughly 2.206 and an approximation of 99.021 for \(\lambda\).

As a means of further investigation, I overlaid the density curve of a Weibull distribution with those exact shape (\(\beta\)) and scale (\(\lambda\)) characteristics atop the histogram of our available sample data. The results below show that our sample data certainly does not seem to strongly reject the potential accuracy of our maximum likelihood estimation.

ggplot(data = data) +
  geom_histogram(mapping = aes(x = time, y = after_stat(density)),
                 color = "black",
                  # argument color in geom_histogram is for color of bin lines
                 fill = "lightblue",
                 bins = 10,) +
  # use stat_function in ggplot to show density curves of other distributions
    stat_function(fun = dweibull, 
                args = list(shape = weib_mle_beta, scale = weib_mle_lambda),
                color = "black",
                linewidth = 1.5,
                xlim = range(0:200))+
            # xlim argument so curve doesn't awkardly cut out at edge points of data
  labs(title = "Distribution of Survival Times",
       x = "Time",
       y = "Density") + 
  theme(
    panel.border = element_rect(color = "black", fill = NA, linewidth = 3),
    legend.position = c(0.85, 0.85)
  )

If the population of ball bearing survival times truly is distributed in a Weibull manner, then it seems very likely that \(\beta\) and \(\lambda\) are about equal to 2.206 and 99.021 respectively. I will now perform the MLE process again, this time operating under the assertion that the population is exponentially distributed.

b.) MLE of Exponential Distribution

\[\Large \ell(\lambda|t) = -[n * ln(\lambda)] - \frac{\sum(t_i)}{\lambda} \]

\[\Large \frac{\partial f}{\partial \lambda} = \frac{n}{\lambda} + \frac{\sum(t_i)}{\lambda^2} \]


# exponential log likelihood follows same pattern as Weibull log likelihood but a MUCH simpler distribution
exp_log_likelihood = function(lambda, data) {
 if (lambda <= 0) return (1e10)
 n = length(data)
 log_lik = -n * log(lambda) - sum(data)/lambda
 return(log_lik)
}

### now define partial derivative w/ respect to lambda (the score function or gradient)
  # performed via quick hand calculation

exp_gradient = function(lambda, data) {
  if (lambda <= 0) return (NA)
  n = length(data)
  partial_deriv_lambda = (n/lambda) + (sum(data)/(lambda^2))
  return(partial_deriv_lambda)
}


exp_mle_estimates = optim(
  par = 1/mean(data$time),
    # the initial guess can simply be 1/(mean of the data) since we are performing this analysis under the theoretical that it is an EXPONENTIAL distribution. The mean of an exponential distribution is 1 divided by the the rate parameter lambda
  data = data$time,
  fn = exp_log_likelihood,
  gr = exp_gradient,
  method = "L-BFGS-B",
  hessian = TRUE,
    # will use the Hessian matrix later on
  control = list(maxit = 1000, 
                 fnscale  = -1,
                 trace = FALSE,
                 abstol = 1e-8)
)
  
#exp_mle_estimates$par

exp_mle_lambda = exp_mle_estimates$par

Once again using Utilizing R’s optim() along with the principles of maximum likelihood estimation, I calculated an estimation of \(\lambda\). Under the assumption that the ball bearing survival time population is exponentially distributed, we would estimate \(\lambda\) to be roughly 88.132.

Below is the sample data with an exponential curve with said lambda (scale) parameter overlaid. While this does curve not appear to match the data to as close an extent as the previous Weibull curve did, it is still reasonably similar in pattern and scale.

ggplot(data = data) +
  geom_histogram(mapping = aes(x = time, y = after_stat(density)),
                 color = "black",
                  # argument color in geom_histogram is for color of bin lines
                 fill = "lightblue",
                 bins = 10,) +
  # use stat_function in ggplot to show density curves of other distributions
    stat_function(fun = dexp, 
                args = list(rate = 1/exp_mle_lambda),
                color = "red",
                linewidth = 1.5,
                xlim = range(0:200)
                )+
            # xlim argument so curve doesn't awkardly cut out at edge points of data
  labs(title = "Distribution of Survival Times",
       x = "Time",
       y = "Density") + 
  theme(
    panel.border = element_rect(color = "black", fill = NA, linewidth = 3),
    legend.position = c(0.85, 0.85)
  )

c.) Likelihood Ratio Test

Now having two different estimates of \(\lambda\), formulated via two differing distribution assumptions, I went ahead and performed a likelihood ratio test to help determine which presumed value of \(\lambda\) is more effective as per our sample data serving as evidence.

The likelihood ratio test, which involves the subtraction of the log likelihood estimate of a simpler model (the exponential performed in part b) from the log likelihood estimate of a more complex and more parameterized model (the Weibull performed in part a), is meant to measure the improvement in fit that the more complex and unrestricted model provides. The null hypothesis of this test is that, outside of sampling variation, there is no sufficient difference in fit between the simpler and more complex models. The test statistic for this hypothesis test, \(\Lambda\), follows a chi-square distribution with degrees of freedom equaling the number of parameters actively being tested for.

###### handle Weibull distribution first
# weib_mle_beta and weib_mle_lambda are UNRESTRICTED MLE VALUES, but now we must find

# null hypothesis is that beta = 1
# if null hypothesis is true, then distribution is really just exponential

## the likelihood ratio test is just 2 * 
  # [log likelihood evaluated in unrestricted way(which is what we did in part a)] -
  # [log likelihood evaluated in restricted or simple way(which we did in part b)]

# test stat for likelihood ratio test is uppercase Lambda

Lambda = 2 * (weib_mle_lambda - exp_mle_lambda)

p_value_likelihoodratio = 1 - pchisq(Lambda, df = 1)
  # test stat distribution for likelihood ratio test is chi-square distributed
  # df = number of parameters we are estimating in function

Performing the likelihood ratio test, the resulting value of \(\Lambda\) was roughly 21.779, which yielded a p value of roughly 3^{-6}. This of course leads us to reject the null hypothesis, as there seems to be a large enough amount of evidence that significant amount of fit is lost by operating under the assumption of an exponential distribution. The findings of this test are rather unsurprising, given the histogram visuals we looked at earlier.

d.) Wald Test

For further confirmation that the greater complexity which the Weibull carries in comparison to the exponential distribution is a worthwhile tradeoff for increased accuracy, I also performed the Wald test. Like the likelihood ratio test, the Wald test also follows a chi-square distribution, with the degrees of freedom acting as the number of parameters being estimated at that time.

The null hypothesis of the Wald test is that the parameter of interest (\(\beta\) in our case) is close enough or equal to whatever previously hypothesized value. In this instance, we will compare the unconstrained MLE-based estimate of \(\beta\) found in part a to the value of \(\beta\) (1) that would make this distribution of ball bearing survival times truly exponential.

invisible(
  weib_mle_estimates$hessian
)
## the inverse of the Hessian matrix is the covariance
 # in R, the solve function returns the inverse of a matrix object
covar_matrix = solve(-weib_mle_estimates$hessian)

# already have weib_mle_beta as our estiamte based on the unrestricted likelihood estimation method

var_beta = covar_matrix[1,1]

wald_stat = (weib_mle_beta - 1)^2 / var_beta

## once again, wald_stat is chi square just like likelihood ratio
p_value_wald = 1 - pchisq(wald_stat, df = 1)

Per the results of the Wald test, there is sufficient statistical evidence that we cannot simply operate under the assumption that the true shape parameter \(\beta\) of our distribution is 1. The Wald test yielded a test statistic and p value of approximately 23.111 and 2^{-6} respectively.

e.) Summary and Conclusions

Given the results of the two performed hypothesis tests, we cannot justify treating the distribution of ball bearing survival times as exponential. Doing so would result in a significant amount of predictive accuracy lost per the results of the likelihood ratio test. And per the Wald test, there is not sufficient evidence that the \(\beta\) parameter is “flexible” enough to be assumed at a value of one, given our available data.

Knowing this, we should move forward with the assumptions that the broader population of bearing survival times is Weibull distributed, with a shape parameter of approximately 2.206 and a scale parameter of about 99.021. The visual for this distribution is below once again.

ggplot(data = data) +
  geom_histogram(mapping = aes(x = time, y = after_stat(density)),
                 color = "black",
                  # argument color in geom_histogram is for color of bin lines
                 fill = "lightblue",
                 bins = 10,) +
  # use stat_function in ggplot to show density curves of other distributions
    stat_function(fun = dweibull, 
                args = list(shape = weib_mle_beta, scale = weib_mle_lambda),
                color = "black",
                linewidth = 1.5,
                xlim = range(0:200))+
            # xlim argument so curve doesn't awkardly cut out at edge points of data
  labs(title = "Distribution of Survival Times",
       x = "Time",
       y = "Density") + 
  theme(
    panel.border = element_rect(color = "black", fill = NA, linewidth = 3),
    legend.position = c(0.85, 0.85)
  )

Our visual shows a rather immediate uptick in values, and then a noticeable rightward skew. This is a standard pattern for a Weibull distribution, making it a powerful modeling framework for areas like engineering and life expectancies.

LS0tCnRpdGxlOiAiSHlwb3RoZXNpcyBUZXN0aW5nIHRvIERldGVybWluZSBQb3RlbnRpYWwgT3ZlcmZpdHRpbmcgb2YgRGlzdHJpYnV0aW9uIgphdXRob3I6ICJDaHJpcyBCYWhtIgpkYXRlOiAiQXByaWwgMTMsIDIwMjYiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6CiAgICAgIGNvbGxhcHNlZDogdHJ1ZQogICAgICBzbW9vdGhfc2Nyb2xsOiB0cnVlCiAgICB0b2NfZGVwdGg6IDQKICAgIGZpZ193aWR0aDogNgogICAgZmlnX2hlaWdodDogNAogICAgZmlnX2NhcHRpb246IHRydWUKICAgIG51bWJlcl9zZWN0aW9uczogZmFsc2UKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgdGhlbWU6IGx1bWVuCiAgICBoaWdobGlnaHQ6IHRhbmdvCiAgcGRmX2RvY3VtZW50OgogICAgdG9jOiB0cnVlCiAgICB0b2NfZGVwdGg6IDQKICAgIGZpZ19jYXB0aW9uOiB0cnVlCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICB3b3JkX2RvY3VtZW50OgogICAgdG9jOiB0cnVlCiAgICB0b2NfZGVwdGg6IDQKLS0tCgpgYGB7Y3NzLCBlY2hvID0gRkFMU0V9CmRpdiNUT0MgbGkgeyAgICAgLyogdGFibGUgb2YgY29udGVudCAgKi8KICAgIGxpc3Qtc3R5bGU6dXBwZXItcm9tYW47CiAgICBiYWNrZ3JvdW5kLWltYWdlOm5vbmU7CiAgICBiYWNrZ3JvdW5kLXJlcGVhdDpub25lOwogICAgYmFja2dyb3VuZC1wb3NpdGlvbjowOwp9CgpoMS50aXRsZSB7ICAgIC8qIGxldmVsIDEgaGVhZGVyIG9mIHRpdGxlICAqLwogIGZvbnQtc2l6ZTogMjRweDsKICBmb250LXdlaWdodDogYm9sZDsKICBjb2xvcjogRGFya1JlZDsKICB0ZXh0LWFsaWduOiBjZW50ZXI7Cn0KCmg0LmF1dGhvciB7IC8qIEhlYWRlciA0IC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovCiAgZm9udC1zaXplOiAxOHB4OwogIGZvbnQtd2VpZ2h0OiBib2xkOwogIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOwogIGNvbG9yOiBEYXJrUmVkOwogIHRleHQtYWxpZ246IGNlbnRlcjsKfQoKaDQuZGF0ZSB7IC8qIEhlYWRlciA0IC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovCiAgZm9udC1zaXplOiAxOHB4OwogIGZvbnQtd2VpZ2h0OiBib2xkOwogIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOwogIGNvbG9yOiBEYXJrQmx1ZTsKICB0ZXh0LWFsaWduOiBjZW50ZXI7Cn0KCmgxIHsgLyogSGVhZGVyIDEgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8KICAgIGZvbnQtc2l6ZTogMjBweDsKICAgIGZvbnQtd2VpZ2h0OiBib2xkOwogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7CiAgICBjb2xvcjogZGFya3JlZDsKICAgIHRleHQtYWxpZ246IGNlbnRlcjsKfQoKaDIgeyAvKiBIZWFkZXIgMiAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLwogICAgZm9udC1zaXplOiAxOHB4OwogICAgZm9udC13ZWlnaHQ6IGJvbGQ7CiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsKICAgIGNvbG9yOiBuYXZ5OwogICAgdGV4dC1hbGlnbjogbGVmdDsKfQoKaDMgeyAvKiBIZWFkZXIgMyAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLwogICAgZm9udC1zaXplOiAxNnB4OwogICAgZm9udC13ZWlnaHQ6IGJvbGQ7CiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsKICAgIGNvbG9yOiBuYXZ5OwogICAgdGV4dC1hbGlnbjogbGVmdDsKfQoKaDQgeyAvKiBIZWFkZXIgNCAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLwogICAgZm9udC1zaXplOiAxNHB4OwogIGZvbnQtd2VpZ2h0OiBib2xkOwogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7CiAgICBjb2xvcjogZGFya3JlZDsKICAgIHRleHQtYWxpZ246IGxlZnQ7Cn0KCi8qIEFkZCBkb3RzIGFmdGVyIG51bWJlcmVkIGhlYWRlcnMgKi8KLmhlYWRlci1zZWN0aW9uLW51bWJlcjo6YWZ0ZXIgewogIGNvbnRlbnQ6ICIuIjsKfQpgYGAKCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQojIGNvZGUgY2h1bmsgc3BlY2lmaWVzIHdoZXRoZXIgdGhlIFIgY29kZSwgd2FybmluZ3MsIGFuZCBvdXRwdXQgCiMgd2lsbCBiZSBpbmNsdWRlZCBpbiB0aGUgb3V0cHV0IGZpbGVzLgoKaWYgKCFyZXF1aXJlKCJrbml0ciIpKSB7ICAgICAgICAgICAgICAgICAgICAgICMgdXNlIGNvbmRpdGlvbmFsIHN0YXRlbWVudCB0byBkZXRlY3QKICAgaW5zdGFsbC5wYWNrYWdlcygia25pdHIiKSAgICAgICAgICAgICAgICAgICMgd2hldGhlciBhIHBhY2thZ2Ugd2FzIGluc3RhbGxlZCBpbgogICBsaWJyYXJ5KGtuaXRyKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyB5b3VyIG1hY2hpbmUuIElmIG5vdCwgaW5zdGFsbCBpdCBhbmQKfSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgbG9hZCBpdCB0byB0aGUgd29ya2luZyBkaXJlY3RvcnkuCgppZiAoIXJlcXVpcmUodGlkeXZlcnNlKSkge2xpYnJhcnkodGlkeXZzZXJzZSl9IAoKaWYgKCFyZXF1aXJlKEdHYWxseSkpIHtsaWJyYXJ5KEdHYWxseSl9IAoKaWYgKCFyZXF1aXJlKGthYmxlRXh0cmEpKSB7bGlicmFyeShrYWJsZUV4dHJhKX0gCgppZiAoIXJlcXVpcmUoZ2dwbG90MikpIHtsaWJyYXJ5KGdncGxvdDIpfSAKCmlmICghcmVxdWlyZShjYXIpKSB7bGlicmFyeShjYXIpfSAKCmlmICghcmVxdWlyZShkcGx5cikpIHtsaWJyYXJ5KGRwbHlyKX0gCgppZiAoIXJlcXVpcmUocGFuZGVyKSkge2xpYnJhcnkocGFuZGVyKX0gCgppZiAoIXJlcXVpcmUoZm9yZWNhc3QpKSB7bGlicmFyeShmb3JlY2FzdCl9IAoKaWYgKCFyZXF1aXJlKGx1YnJpZGF0ZSkpIHtsaWJyYXJ5KGx1YnJpZGF0ZSl9IAoKaWYgKCFyZXF1aXJlKCJzY2FsZXMiKSkgewppbnN0YWxsLnBhY2thZ2VzKCJzY2FsZXMiKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKbGlicmFyeSgic2NhbGVzIikgCn0KCmtuaXRyOjpvcHRzX2NodW5rJHNldCgKCWVjaG8gPSBUUlVFLAoJbWVzc2FnZSA9IEZBTFNFLAoJd2FybmluZyA9IEZBTFNFLAoJY29tbWVudCA9IE5BLAoJcmVzdWx0cyA9IFRSVUUsCglmaWcuYWxpZ24gPSAiY2VudGVyIgopCmBgYAoKYGBge3J9CmRhdGEgPSByYmluZC5kYXRhLmZyYW1lKDEyLjQsIDE4LjcsIDI1LjMsIDMwLjEsIDMzLjUsIDM1LjIsIDM4LjksIDQwLjMsIDQyLjcsIDQ1LjEsIDQ3LjYsIDQ5LjgsIDUyLjQsIDU1LjAsIAo1Ny4zLCA2MC4yLCA2Mi44LCA2NS4xLCA2Ny45LCA3MC41LCA3Mi4zLCA3NS42LCA3OC4yLCA4MC45LCA4My40LCA4NS43LCA4OC4xLCA5MC42LCAKOTMuMiwgOTUuOCwgOTguNCwgMTAxLjAsIDEwNC41LCAxMDcuMywgMTEwLjYsIDExMy4yLCAxMTYuOCwgMTIwLjEsIDEyMy43LCAxMjcuNCwKMTMwLjksIDEzNC41LCAxMzguMiwgMTQyLjAsIDE0Ni4zLCAxNTAuNywgMTU1LjIsIDE2MC44LCAxNjguNCwgMTc1LjkpCmNvbG5hbWVzKGRhdGEpID0gInRpbWUiCmBgYAoKIyBJbnRybyBhbmQgU2V0dXAKRm9yIHRoaXMgYW5hbHlzaXMgd2UgYXJlIGV4YW1pbmluZyBhIGRhdGFzZXQgY29tcG9zZWQgb2YgYHIgbnJvdyhkYXRhKWAgc3Vydml2YWwgdGltZXMgKHRoZSByZWNvcmRlZCB0aW1lcyBmcm9tIHN0YXJ0IHVudGlsIGZhaWx1cmUpIG9mIGlkZW50aWNhbGx5IG1hbnVmYWN0dXJlZCBiYWxsIGJlYXJpbmdzLiBPdmVyIHByZXZpb3VzIG1vbnRocywgYXNzb2NpYXRlcyBoYXZlIHJlY29nbml6ZWQgd2hhdCB0aGV5IGJlbGlldmUgdG8gYmUgYW4gaW5jcmVhc2UgaW4gdGhlIHVucmVsaWFiaWxpdHkgb2YgdGhlc2UgYmVhcmluZ3MuIEEgc3VtbWFyeSBhbmQgdmlzdWFsaXphdGlvbiBvZiB0aGUgYHIgbnJvdyhkYXRhKWAgcmVjb3JkZWQgc3Vydml2YWwgdGltZXMgYXJlIGJlbG93LgpgYGB7cn0Kc3VtX3N0YXRzX3RhYmxlID0gZnVuY3Rpb24odmFyaWFibGUpewogIHRhYmxlID0gY2JpbmQoCiAgICByb3VuZChtaW4odmFyaWFibGUpLDIpLAogICAgcm91bmQocXVhbnRpbGUodmFyaWFibGUsIDAuMjUpLDIpLAogICAgcm91bmQobWVkaWFuKHZhcmlhYmxlKSwyKSwKICAgIHJvdW5kKG1lYW4odmFyaWFibGUpLDIpLAogICAgcm91bmQocXVhbnRpbGUodmFyaWFibGUsIDAuNzUpLDIpLAogICAgcm91bmQobWF4KHZhcmlhYmxlKSwyKQogICkKICBjb2xuYW1lcyh0YWJsZSkgPSBjKCJNaW4iLCAiUTEiLCAiTWVkIiwgIk1lYW4iLCAiUTMiLCAiTWF4IikKICByb3duYW1lcyh0YWJsZSkgPSBOVUxMCiAgcmV0dXJuKHRhYmxlKQp9CgpTdW1tYXJ5X1RhYmxlID0gc3VtX3N0YXRzX3RhYmxlKHZhcmlhYmxlID0gZGF0YSR0aW1lKQprYWJsZShTdW1tYXJ5X1RhYmxlLGFsaWduID0gImMiLAogICAgICBjYXB0aW9uID0gIjxzcGFuIHN0eWxlPSdjb2xvcjojIzAwMDAwMDsnPgogICAgICBTdW1tYXJ5IFN0YXRzIG9mIFN1cnZpdmFsIFRpbWVzIDwvc3Bhbj4iKSAlPiUKICBrYWJsZV9zdHlsaW5nKAogICAgYm9vdHN0cmFwX29wdGlvbnMgPSBjKCJzdHJpcGVkIiwgImJvcmRlcmVkIiksCiAgICBmdWxsX3dpZHRoID0gRkFMU0UsCiAgICBwb3NpdGlvbiA9ICJjZW50ZXIiKQoKCmdncGxvdChkYXRhID0gZGF0YSkgKwogIGdlb21faGlzdG9ncmFtKG1hcHBpbmcgPSBhZXMoeCA9IHRpbWUsIHkgPSBhZnRlcl9zdGF0KGRlbnNpdHkpKSwKICAgICAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIsCiAgICAgICAgICAgICAgICAgICMgYXJndW1lbnQgY29sb3IgaW4gZ2VvbV9oaXN0b2dyYW0gaXMgZm9yIGNvbG9yIG9mIGJpbiBsaW5lcwogICAgICAgICAgICAgICAgIGZpbGwgPSAibGlnaHRibHVlIiwKICAgICAgICAgICAgICAgICBiaW5zID0gMTAsKSArCiAgbGFicyh0aXRsZSA9ICJEaXN0cmlidXRpb24gb2YgU3Vydml2YWwgVGltZXMiLAogICAgICAgeCA9ICJUaW1lIiwKICAgICAgIHkgPSAiRGVuc2l0eSIpICsgCiAgdGhlbWUoCiAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3IgPSAiYmxhY2siLCBmaWxsID0gTkEsIGxpbmV3aWR0aCA9IDMpCiAgKSAjIHRoaXMgaXMgdGhlIGVxdWl2YWxlbnQgb2YgYm94KGx3ZCA9IDMpIGluIGJhc2UgUgoKCmBgYAoKRm9yIHRoZSBwdXJwb3NlcyBvZiB0aGlzIGFuYWx5c2lzLCBvdXIgZGVmYXVsdCBhc3N1bXB0aW9uIChudWxsIGh5cG90aGVzaXMpIGlzIHRoYXQgdGhlICRcYmV0YSQgdGVybSBvZiB0aGUgYnJvYWRlciBwb3B1bGF0aW9uIG9mIGJhbGwgYmVhcmluZ3MgYXQgaGFuZCBpcyBlcXVhbCB0byAxLiBJZiB0aGlzIGlzIHRydWx5IHRoZSBjYXNlLCB0aGVuIG91ciBwb3B1bGF0aW9uIGlzICpleHBvbmVudGlhbGx5KiBkaXN0cmlidXRlZC4gSG93ZXZlciwgZ2l2ZW4gdGhlIG1ha2V1cCBvZiB0aGUgZGVuc2l0eSBmb3JtdWxhcyBmb3IgYm90aCBleHBvbmVudGlhbCBhbmQgV2VpYnVsbCBkaXN0cmlidXRpb25zLCBpZiAkXGJldGEgXG5lJCAxLCB0aGF0IG1lYW5zIG91ciBwb3B1bGF0aW9uIGlzICpXZWlidWxsKiBkaXN0cmlidXRlZC4gS25vd2luZyBhIHBvcHVsYXRpb24ncyB0cnVlIGRpc3RyaWJ1dGlvbiBpcyB2YWx1YWJsZSBmb3IgZnV0dXJlIHByZWRpY3RpdmUgYW5hbHlzaXMsIG1ha2luZyB0aGlzIGEgd29ydGh3aGlsZSBleGVyY2lzZS4KClxiZWdpbnthbGlnbn0KSF8wJjogXGJldGEgPSAxIFxxdWFkIFx0ZXh0e1Rha2Vhd2F5OiBFeHBvbmVudGlhbH0gXFwKSF9hJjogXGJldGEgXG5lcSAxIFxxdWFkIFx0ZXh0e1Rha2Vhd2F5OiBXZWlidWxsfQpcZW5ke2FsaWdufQoKCiMgYS4pIE1MRSBvZiBXZWlidWxsIERpc3RyaWJ1dGlvbgpUaGUgZmlyc3Qgd2F5IHRoYXQgd2Ugd2lsbCBhdHRlbXB0IHRvIGVzdGltYXRlICRcYmV0YSQgKHRoZSBzaGFwZSBwYXJhbWV0ZXIpIGlzIHZpYSBtYXhpbXVtIGxpa2VsaWhvb2QgZXN0aW1hdGlvbiAoTUxFKS4gV2Ugd2lsbCBhbHNvIHNpbXVsdGFuZW91c2x5IHVzZSBNTEUgdG8gZXN0aW1hdGUgdGhlIHNjYWxlIHBhcmFtZXRlciwgJFxsYW1iZGEkLiBXZSB3aWxsIGRlbm90ZSB0aGVzZSBlc3RpbWF0ZXMgYXMgJFxoYXR7XGJldGF9JCBhbmQgJFxoYXR7XGxhbWJkYX0kIHJlc3BlY3RpdmVseS4KCkluIHRoZSBwcm9jZXNzIG9mIHBlcmZvcm1pbmcgbGlrZWxpaG9vZCBlc3RpbWF0aW9uLCB0aGUgbG9nLWxpa2VsaWhvb2QgZnVuY3Rpb24gZm9yIHRoZSBXZWlidWxsIGRpc3RyaWJ1dGlvbiBhcyB3ZWxsIGFzIHRoZSBwYXJ0aWFsIGRlcml2YXRpdmVzIG9mIHRoYXQgdmVyeSBmdW5jdGlvbiB3aXRoIHJlc3BlY3QgdG8gYm90aCAkXGJldGEkIGFuZCAkXGxhbWJkYSQgYXJlIGJlbG93LgoKJCRcTGFyZ2UgXGVsbChcYmV0YSxcbGFtYmRhfHQpID0gW24gKiBsbihcYmV0YSldIC0gW24qXGJldGEgKmxuKFxsYW1iZGEpXSArIFsoXGJldGEgLSAxKSAqIFxzdW0obG4odF9pKSldIC0gXHN1bShcZnJhY3sodF9pKX17XGxhbWJkYX0pXlxiZXRhICQkCjxicj4KCiQkXExhcmdlIFxmcmFje1xwYXJ0aWFsIGZ9e1xwYXJ0aWFsIFxiZXRhfSA9IFxmcmFje259e1xiZXRhfSAtIG4gKiBsbihcbGFtYmRhKSArIFxzdW0obG4odF9pKSAtIFxzdW0obG5cZnJhY3t0X2l9e1xsYW1iZGF9KSAqIChcZnJhY3t0X2l9e1xsYW1iZGF9KV5cYmV0YSAgICAkJAo8YnI+CiQkXExhcmdlIFxmcmFje1xwYXJ0aWFsIGZ9e1xwYXJ0aWFsIFxsYW1iZGF9ID0gIFxmcmFje1xiZXRhfXtcbGFtYmRhfSAqIFxzdW0oXGZyYWN7dF9pfXtcbGFtYmRhfSleXGJldGEgLSBuICAgICQkCjxicj4KCmBgYHtyfQojIyB0aGUgbG9nIGxpa2VsaWhvb2QgZnVuY3Rpb24gc2ltcGx5IHJ1bnMgYSBsb2dhcml0aG0gdGhyb3VnaCBhbGwgdGhlIHRlcm1zIGFuZCBhY2NvdW50cyBmb3IgdGhlIHN1bW1hdGlvbiBvZiBhbGwgZGF0YSBwb2ludHMsIGFzIG9wcG9zZWQgdG8gb25lIHZhbHVlIG9mIG91ciB2YXJpYWJsZSB0CgoKIyMjIyMgT3ZlcmFsbCBwcm9jZXNzIGlzIGZyb20gc2VjdGlvbiA1LjIgb2YgdGhpcyB3ZWVrJ3Mgbm90ZXMKCiMjIHJlZmVyZW5jZSB3ZWVrIDcgc2VjdGlvbiA1IG5vdGVzIGZvciBkaXN0cmlidXRpb24tc3BlY2lmaWMgZnVuY3Rpb25zIGFuZCBmb3JtdWxhcyBiZWxvdwoKIyMjIyBkZWZpbmUgbGlrZWxpaG9vZCBmdW5jdGlvbgojIyAqbmVnYXRpdmUqIGxvZyBsaWtlbGlob29kIGZ1bmN0aW9uIGZvciBXZWlidWxsIGRpc3RyaWJ1dGlvbgogICMgYnkgbmVnYXRpdmUgbG9nIGxpa2VsaWhvb2QsIHRoaXMgZnVuY3Rpb24uLi4uCmxvZ19saWtlbGlob29kID0gZnVuY3Rpb24ocGFyYW1zLCBkYXRhKSB7CiAgYmV0YSA9IHBhcmFtc1sxXSAgIyBzaGFwZQogIGxhbWJkYSA9IHBhcmFtc1syXSAgIyBzY2FsZSAKICAKICAjIEVuc3VyZSBwYXJhbWV0ZXJzIGFyZSBwb3NpdGl2ZQogIGlmIChiZXRhIDw9IDAgfHwgbGFtYmRhIDw9IDApIHsKICAgIHJldHVybigxZTEwKSAgIyBSZXR1cm4gbGFyZ2UgdmFsdWUgZm9yIGludmFsaWQgcGFyYW1ldGVycwogIH0KICAKICBuID0gbGVuZ3RoKGRhdGEpCiAgbG9nX2xpayA9IG4gKiBsb2coYmV0YSkgLSBuICogYmV0YSAqIGxvZyhsYW1iZGEpICsgCiAgICAoYmV0YSAtIDEpICogc3VtKGxvZyhkYXRhKSkgLSBzdW0oKGRhdGEgLyBsYW1iZGEpXmJldGEpCiAgCiAgcmV0dXJuKGxvZ19saWspICAjIFJldHVybiBsb2ctbGlrZWxpaG9vZCEgTk9UIHRoZSBuZWdhdGl2ZSBsb2ctbGlrZWxpaG9vZAp9CgoKIyMjIyBkZWZpbmUgc2NvcmUgZXF1YXRpb25zIChwYXJ0aWFsIGRlcml2YXRpdmVzKQojIyBncmFkaWVudCAocGFydGlhbCBkZXJpdmF0aXZlcykgb2YgKm5lZ2F0aXZlKiBsb2cgbGlrZWxpaG9vZCBmdW5jdGlvbiAgZm9yIFdlaWJ1bGwgZGlzdHJpYnV0aW9uCmxvZ19saWtlbGlob29kX2dyYWRpZW50ID0gZnVuY3Rpb24ocGFyYW1zLCBkYXRhKSB7CiAgYmV0YSA9IHBhcmFtc1sxXSAgICAgICAjIHNoYXBlIHBhcmFtZXRlcgogIGxhbWJkYSA9IHBhcmFtc1syXSAgIyBzY2FsZSBwYXJhbWV0ZXIKICAKICBuID0gbGVuZ3RoKGRhdGEpCiAgCiAgcGFydGlhbF9kZXJpdl9iZXRhID0gbi9iZXRhIC0gbiAqIGxvZyhsYW1iZGEpICsgc3VtKGxvZyhkYXRhKSkgLSAKICAgICAgICBzdW0obG9nKGRhdGEvbGFtYmRhKSAqIChkYXRhL2xhbWJkYSleYmV0YSkKICAKICBwYXJ0aWFsX2Rlcml2X2xhbWJkYSA9ICAoYmV0YS9sYW1iZGEpKihzdW0oKGRhdGEvbGFtYmRhKV5iZXRhKSAtbikKICAKICByZXR1cm4oYyhwYXJ0aWFsX2Rlcml2X2JldGEsCiAgICAgICAgICAgcGFydGlhbF9kZXJpdl9sYW1iZGEpKSAgIyBHcmFkaWVudCBvZiBsb2ctbGlrZWxpaG9vZCwgTk9UIHRoZSBuZWdhdGl2ZSBzY29yZXMKfQoKCiMjIyMgdXNlIGxvZyBsaWtlbGlob29kIGFuZCBzY29yZSBlcXVhdGlvbnMgaW4gb3B0aW0gZnVuY3Rpb24KCiMgbmVlZCB0byBoYXZlIGdvb2QgaW5pdGlhbCBndWVzc2VzIGZvciBiZXRhIGFuZCBsYW1iZGEgZm9yIHRoZSBvcHRpbSBmdW5jdGlvbgogICMgcmVmZXJlbmNlIHNlY3Rpb24gNS4yIG9mIHdlZWsgNyAiQXN5bXB0b3RpYyBTYW1wbGluZyIgbm90ZXMKYmV0YV9ndWVzcyA9IChzZChkYXRhJHRpbWUpL21lYW4oZGF0YSR0aW1lKSleKC0xLjA4NikKCmxhbWJkYV9ndWVzcyA9IG1lYW4oZGF0YSR0aW1lKS9nYW1tYSgxICsgMS9iZXRhX2d1ZXNzKQoKCndlaWJfbWxlX2VzdGltYXRlcyA9IG9wdGltKAogIHBhciA9IGMoYmV0YV9ndWVzcywgbGFtYmRhX2d1ZXNzKSwgIyBwYXIgYXJndW1lbnQgaXMgaW5pdGlhbCAiZ3Vlc3NlcyIKICBkYXRhID0gZGF0YSR0aW1lLAogIGZuID0gbG9nX2xpa2VsaWhvb2QsCiAgZ3IgPSBsb2dfbGlrZWxpaG9vZF9ncmFkaWVudCwKICBtZXRob2QgPSAiTC1CRkdTLUIiLAogIGhlc3NpYW4gPSBUUlVFLAogICAgIyB3aWxsIHVzZSB0aGUgSGVzc2lhbiBtYXRyaXggbGF0ZXIgb24KICBjb250cm9sID0gbGlzdChtYXhpdCA9IDEwMDAsIAogICAgICAgICAgICAgICAgIGZuc2NhbGUgID0gLTEsCiAgICAgICAgICAgICAgICAgdHJhY2UgPSBGQUxTRSwKICAgICAgICAgICAgICAgICBhYnN0b2wgPSAxZS04KQopCiN3ZWliX21sZV9lc3RpbWF0ZXMKICAKd2VpYl9tbGVfYmV0YSA9IHdlaWJfbWxlX2VzdGltYXRlcyRwYXJbMV0gIyBzaGFwZQp3ZWliX21sZV9sYW1iZGEgPSB3ZWliX21sZV9lc3RpbWF0ZXMkcGFyWzJdICMgc2NhbGUKCmBgYApVdGlsaXppbmcgUidzIDxzcGFuIHN0eWxlPSJjb2xvcjpibHVlOyI+b3B0aW0oKTwvc3Bhbj4gZnVuY3Rpb24sIGFsb25nIHdpdGggdGhlIGxvZyBsaWtlbGlob29kIGFuZCBwYXJ0aWFsIGRlcml2YXRpdmVzIG9mIHRoZSBXZWlidWxsIGRpc3RyaWJ1dGlvbiwgdGhpcyByb3VuZCBvZiBNTEUtYmFzZWQgZXN0aW1hdGVzIHlpZWxkZWQgYSB2YWx1ZSBmb3IgJFxiZXRhJCBvZiByb3VnaGx5IGByIHJvdW5kKHdlaWJfbWxlX2JldGEsMylgIGFuZCBhbiBhcHByb3hpbWF0aW9uIG9mIGByIHJvdW5kKHdlaWJfbWxlX2xhbWJkYSwzKWAgZm9yICRcbGFtYmRhJC4gCgpBcyBhIG1lYW5zIG9mIGZ1cnRoZXIgaW52ZXN0aWdhdGlvbiwgSSBvdmVybGFpZCB0aGUgZGVuc2l0eSBjdXJ2ZSBvZiBhICoqV2VpYnVsbCBkaXN0cmlidXRpb24qKiB3aXRoIHRob3NlIGV4YWN0IHNoYXBlICgkXGJldGEkKSBhbmQgc2NhbGUgKCRcbGFtYmRhJCkgY2hhcmFjdGVyaXN0aWNzIGF0b3AgdGhlIGhpc3RvZ3JhbSBvZiBvdXIgYXZhaWxhYmxlIHNhbXBsZSBkYXRhLiBUaGUgcmVzdWx0cyBiZWxvdyBzaG93IHRoYXQgb3VyIHNhbXBsZSBkYXRhIGNlcnRhaW5seSBkb2VzIG5vdCBzZWVtIHRvIHN0cm9uZ2x5IHJlamVjdCB0aGUgcG90ZW50aWFsIGFjY3VyYWN5IG9mIG91ciBtYXhpbXVtIGxpa2VsaWhvb2QgZXN0aW1hdGlvbi4KYGBge3J9CmdncGxvdChkYXRhID0gZGF0YSkgKwogIGdlb21faGlzdG9ncmFtKG1hcHBpbmcgPSBhZXMoeCA9IHRpbWUsIHkgPSBhZnRlcl9zdGF0KGRlbnNpdHkpKSwKICAgICAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIsCiAgICAgICAgICAgICAgICAgICMgYXJndW1lbnQgY29sb3IgaW4gZ2VvbV9oaXN0b2dyYW0gaXMgZm9yIGNvbG9yIG9mIGJpbiBsaW5lcwogICAgICAgICAgICAgICAgIGZpbGwgPSAibGlnaHRibHVlIiwKICAgICAgICAgICAgICAgICBiaW5zID0gMTAsKSArCiAgIyB1c2Ugc3RhdF9mdW5jdGlvbiBpbiBnZ3Bsb3QgdG8gc2hvdyBkZW5zaXR5IGN1cnZlcyBvZiBvdGhlciBkaXN0cmlidXRpb25zCiAgICBzdGF0X2Z1bmN0aW9uKGZ1biA9IGR3ZWlidWxsLCAKICAgICAgICAgICAgICAgIGFyZ3MgPSBsaXN0KHNoYXBlID0gd2VpYl9tbGVfYmV0YSwgc2NhbGUgPSB3ZWliX21sZV9sYW1iZGEpLAogICAgICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLAogICAgICAgICAgICAgICAgbGluZXdpZHRoID0gMS41LAogICAgICAgICAgICAgICAgeGxpbSA9IHJhbmdlKDA6MjAwKSkrCiAgICAgICAgICAgICMgeGxpbSBhcmd1bWVudCBzbyBjdXJ2ZSBkb2Vzbid0IGF3a2FyZGx5IGN1dCBvdXQgYXQgZWRnZSBwb2ludHMgb2YgZGF0YQogIGxhYnModGl0bGUgPSAiRGlzdHJpYnV0aW9uIG9mIFN1cnZpdmFsIFRpbWVzIiwKICAgICAgIHggPSAiVGltZSIsCiAgICAgICB5ID0gIkRlbnNpdHkiKSArIAogIHRoZW1lKAogICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG9yID0gImJsYWNrIiwgZmlsbCA9IE5BLCBsaW5ld2lkdGggPSAzKSwKICAgIGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC44NSwgMC44NSkKICApCgpgYGAKCklmIHRoZSBwb3B1bGF0aW9uIG9mIGJhbGwgYmVhcmluZyBzdXJ2aXZhbCB0aW1lcyB0cnVseSBpcyBkaXN0cmlidXRlZCBpbiBhIFdlaWJ1bGwgbWFubmVyLCB0aGVuIGl0IHNlZW1zIHZlcnkgbGlrZWx5IHRoYXQgJFxiZXRhJCBhbmQgJFxsYW1iZGEkIGFyZSBhYm91dCBlcXVhbCB0byBgciByb3VuZCh3ZWliX21sZV9iZXRhLDMpYCBhbmQgIGByIHJvdW5kKHdlaWJfbWxlX2xhbWJkYSwzKWAgcmVzcGVjdGl2ZWx5LiBJIHdpbGwgbm93IHBlcmZvcm0gdGhlIE1MRSBwcm9jZXNzIGFnYWluLCB0aGlzIHRpbWUgb3BlcmF0aW5nIHVuZGVyIHRoZSBhc3NlcnRpb24gdGhhdCB0aGUgcG9wdWxhdGlvbiBpcyAqZXhwb25lbnRpYWxseSogZGlzdHJpYnV0ZWQuCgoKIyBiLikgTUxFIG9mIEV4cG9uZW50aWFsIERpc3RyaWJ1dGlvbgoKJCRcTGFyZ2UgXGVsbChcbGFtYmRhfHQpID0gLVtuICogbG4oXGxhbWJkYSldIC0gXGZyYWN7XHN1bSh0X2kpfXtcbGFtYmRhfSAgJCQKPGJyPgoKJCRcTGFyZ2UgXGZyYWN7XHBhcnRpYWwgZn17XHBhcnRpYWwgXGxhbWJkYX0gPSBcZnJhY3tufXtcbGFtYmRhfSArIFxmcmFje1xzdW0odF9pKX17XGxhbWJkYV4yfSAgICQkCgo8YnI+CgpgYGB7cn0KIyBleHBvbmVudGlhbCBsb2cgbGlrZWxpaG9vZCBmb2xsb3dzIHNhbWUgcGF0dGVybiBhcyBXZWlidWxsIGxvZyBsaWtlbGlob29kIGJ1dCBhIE1VQ0ggc2ltcGxlciBkaXN0cmlidXRpb24KZXhwX2xvZ19saWtlbGlob29kID0gZnVuY3Rpb24obGFtYmRhLCBkYXRhKSB7CiBpZiAobGFtYmRhIDw9IDApIHJldHVybiAoMWUxMCkKIG4gPSBsZW5ndGgoZGF0YSkKIGxvZ19saWsgPSAtbiAqIGxvZyhsYW1iZGEpIC0gc3VtKGRhdGEpL2xhbWJkYQogcmV0dXJuKGxvZ19saWspCn0KCiMjIyBub3cgZGVmaW5lIHBhcnRpYWwgZGVyaXZhdGl2ZSB3LyByZXNwZWN0IHRvIGxhbWJkYSAodGhlIHNjb3JlIGZ1bmN0aW9uIG9yIGdyYWRpZW50KQogICMgcGVyZm9ybWVkIHZpYSBxdWljayBoYW5kIGNhbGN1bGF0aW9uCgpleHBfZ3JhZGllbnQgPSBmdW5jdGlvbihsYW1iZGEsIGRhdGEpIHsKICBpZiAobGFtYmRhIDw9IDApIHJldHVybiAoTkEpCiAgbiA9IGxlbmd0aChkYXRhKQogIHBhcnRpYWxfZGVyaXZfbGFtYmRhID0gKG4vbGFtYmRhKSArIChzdW0oZGF0YSkvKGxhbWJkYV4yKSkKICByZXR1cm4ocGFydGlhbF9kZXJpdl9sYW1iZGEpCn0KCgpleHBfbWxlX2VzdGltYXRlcyA9IG9wdGltKAogIHBhciA9IDEvbWVhbihkYXRhJHRpbWUpLAogICAgIyB0aGUgaW5pdGlhbCBndWVzcyBjYW4gc2ltcGx5IGJlIDEvKG1lYW4gb2YgdGhlIGRhdGEpIHNpbmNlIHdlIGFyZSBwZXJmb3JtaW5nIHRoaXMgYW5hbHlzaXMgdW5kZXIgdGhlIHRoZW9yZXRpY2FsIHRoYXQgaXQgaXMgYW4gRVhQT05FTlRJQUwgZGlzdHJpYnV0aW9uLiBUaGUgbWVhbiBvZiBhbiBleHBvbmVudGlhbCBkaXN0cmlidXRpb24gaXMgMSBkaXZpZGVkIGJ5IHRoZSB0aGUgcmF0ZSBwYXJhbWV0ZXIgbGFtYmRhCiAgZGF0YSA9IGRhdGEkdGltZSwKICBmbiA9IGV4cF9sb2dfbGlrZWxpaG9vZCwKICBnciA9IGV4cF9ncmFkaWVudCwKICBtZXRob2QgPSAiTC1CRkdTLUIiLAogIGhlc3NpYW4gPSBUUlVFLAogICAgIyB3aWxsIHVzZSB0aGUgSGVzc2lhbiBtYXRyaXggbGF0ZXIgb24KICBjb250cm9sID0gbGlzdChtYXhpdCA9IDEwMDAsIAogICAgICAgICAgICAgICAgIGZuc2NhbGUgID0gLTEsCiAgICAgICAgICAgICAgICAgdHJhY2UgPSBGQUxTRSwKICAgICAgICAgICAgICAgICBhYnN0b2wgPSAxZS04KQopCiAgCiNleHBfbWxlX2VzdGltYXRlcyRwYXIKCmV4cF9tbGVfbGFtYmRhID0gZXhwX21sZV9lc3RpbWF0ZXMkcGFyCmBgYApPbmNlIGFnYWluIHVzaW5nIFV0aWxpemluZyBSJ3MgPHNwYW4gc3R5bGU9ImNvbG9yOmJsdWU7Ij5vcHRpbSgpPC9zcGFuPiBhbG9uZyB3aXRoIHRoZSBwcmluY2lwbGVzIG9mIG1heGltdW0gbGlrZWxpaG9vZCBlc3RpbWF0aW9uLCBJIGNhbGN1bGF0ZWQgYW4gZXN0aW1hdGlvbiBvZiAkXGxhbWJkYSQuIFVuZGVyIHRoZSBhc3N1bXB0aW9uIHRoYXQgdGhlIGJhbGwgYmVhcmluZyBzdXJ2aXZhbCB0aW1lIHBvcHVsYXRpb24gaXMgKmV4cG9uZW50aWFsbHkqIGRpc3RyaWJ1dGVkLCB3ZSB3b3VsZCBlc3RpbWF0ZSAkXGxhbWJkYSQgdG8gYmUgcm91Z2hseSBgciByb3VuZChleHBfbWxlX2xhbWJkYSwzKWAuIAoKQmVsb3cgaXMgdGhlIHNhbXBsZSBkYXRhIHdpdGggYW4gPHNwYW4gc3R5bGU9ImNvbG9yOnJlZDsiPmV4cG9uZW50aWFsIGN1cnZlPC9zcGFuPiB3aXRoIHNhaWQgbGFtYmRhIChzY2FsZSkgcGFyYW1ldGVyIG92ZXJsYWlkLiBXaGlsZSB0aGlzIGRvZXMgY3VydmUgbm90IGFwcGVhciB0byBtYXRjaCB0aGUgZGF0YSB0byBhcyBjbG9zZSBhbiBleHRlbnQgYXMgdGhlIHByZXZpb3VzIFdlaWJ1bGwgY3VydmUgZGlkLCBpdCBpcyBzdGlsbCByZWFzb25hYmx5IHNpbWlsYXIgaW4gcGF0dGVybiBhbmQgc2NhbGUuCmBgYHtyfQpnZ3Bsb3QoZGF0YSA9IGRhdGEpICsKICBnZW9tX2hpc3RvZ3JhbShtYXBwaW5nID0gYWVzKHggPSB0aW1lLCB5ID0gYWZ0ZXJfc3RhdChkZW5zaXR5KSksCiAgICAgICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLAogICAgICAgICAgICAgICAgICAjIGFyZ3VtZW50IGNvbG9yIGluIGdlb21faGlzdG9ncmFtIGlzIGZvciBjb2xvciBvZiBiaW4gbGluZXMKICAgICAgICAgICAgICAgICBmaWxsID0gImxpZ2h0Ymx1ZSIsCiAgICAgICAgICAgICAgICAgYmlucyA9IDEwLCkgKwogICMgdXNlIHN0YXRfZnVuY3Rpb24gaW4gZ2dwbG90IHRvIHNob3cgZGVuc2l0eSBjdXJ2ZXMgb2Ygb3RoZXIgZGlzdHJpYnV0aW9ucwogICAgc3RhdF9mdW5jdGlvbihmdW4gPSBkZXhwLCAKICAgICAgICAgICAgICAgIGFyZ3MgPSBsaXN0KHJhdGUgPSAxL2V4cF9tbGVfbGFtYmRhKSwKICAgICAgICAgICAgICAgIGNvbG9yID0gInJlZCIsCiAgICAgICAgICAgICAgICBsaW5ld2lkdGggPSAxLjUsCiAgICAgICAgICAgICAgICB4bGltID0gcmFuZ2UoMDoyMDApCiAgICAgICAgICAgICAgICApKwogICAgICAgICAgICAjIHhsaW0gYXJndW1lbnQgc28gY3VydmUgZG9lc24ndCBhd2thcmRseSBjdXQgb3V0IGF0IGVkZ2UgcG9pbnRzIG9mIGRhdGEKICBsYWJzKHRpdGxlID0gIkRpc3RyaWJ1dGlvbiBvZiBTdXJ2aXZhbCBUaW1lcyIsCiAgICAgICB4ID0gIlRpbWUiLAogICAgICAgeSA9ICJEZW5zaXR5IikgKyAKICB0aGVtZSgKICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvciA9ICJibGFjayIsIGZpbGwgPSBOQSwgbGluZXdpZHRoID0gMyksCiAgICBsZWdlbmQucG9zaXRpb24gPSBjKDAuODUsIDAuODUpCiAgKQoKYGBgCgoKIyBjLikgTGlrZWxpaG9vZCBSYXRpbyBUZXN0Ck5vdyBoYXZpbmcgdHdvIGRpZmZlcmVudCBlc3RpbWF0ZXMgb2YgJFxsYW1iZGEkLCBmb3JtdWxhdGVkIHZpYSB0d28gZGlmZmVyaW5nIGRpc3RyaWJ1dGlvbiBhc3N1bXB0aW9ucywgSSB3ZW50IGFoZWFkIGFuZCBwZXJmb3JtZWQgYSBsaWtlbGlob29kIHJhdGlvIHRlc3QgdG8gaGVscCBkZXRlcm1pbmUgd2hpY2ggcHJlc3VtZWQgdmFsdWUgb2YgJFxsYW1iZGEkIGlzIG1vcmUgZWZmZWN0aXZlIGFzIHBlciBvdXIgc2FtcGxlIGRhdGEgc2VydmluZyBhcyBldmlkZW5jZS4gCgpUaGUgbGlrZWxpaG9vZCByYXRpbyB0ZXN0LCB3aGljaCBpbnZvbHZlcyB0aGUgc3VidHJhY3Rpb24gb2YgdGhlIGxvZyBsaWtlbGlob29kIGVzdGltYXRlIG9mIGEgc2ltcGxlciBtb2RlbCAodGhlIGV4cG9uZW50aWFsIHBlcmZvcm1lZCBpbiBwYXJ0IGIpIGZyb20gdGhlIGxvZyBsaWtlbGlob29kIGVzdGltYXRlIG9mIGEgbW9yZSBjb21wbGV4IGFuZCBtb3JlIHBhcmFtZXRlcml6ZWQgbW9kZWwgKHRoZSBXZWlidWxsIHBlcmZvcm1lZCBpbiBwYXJ0IGEpLCBpcyBtZWFudCB0byBtZWFzdXJlIHRoZSBpbXByb3ZlbWVudCBpbiBmaXQgdGhhdCB0aGUgbW9yZSBjb21wbGV4IGFuZCB1bnJlc3RyaWN0ZWQgbW9kZWwgcHJvdmlkZXMuIFRoZSBudWxsIGh5cG90aGVzaXMgb2YgdGhpcyB0ZXN0IGlzIHRoYXQsIG91dHNpZGUgb2Ygc2FtcGxpbmcgdmFyaWF0aW9uLCB0aGVyZSBpcyBubyBzdWZmaWNpZW50IGRpZmZlcmVuY2UgaW4gZml0IGJldHdlZW4gdGhlIHNpbXBsZXIgYW5kIG1vcmUgY29tcGxleCBtb2RlbHMuIFRoZSB0ZXN0IHN0YXRpc3RpYyBmb3IgdGhpcyBoeXBvdGhlc2lzIHRlc3QsICRcTGFtYmRhJCwgZm9sbG93cyBhIGNoaS1zcXVhcmUgZGlzdHJpYnV0aW9uIHdpdGggZGVncmVlcyBvZiBmcmVlZG9tIGVxdWFsaW5nIHRoZSBudW1iZXIgb2YgcGFyYW1ldGVycyBhY3RpdmVseSBiZWluZyB0ZXN0ZWQgZm9yLgoKYGBge3J9CiMjIyMjIyBoYW5kbGUgV2VpYnVsbCBkaXN0cmlidXRpb24gZmlyc3QKIyB3ZWliX21sZV9iZXRhIGFuZCB3ZWliX21sZV9sYW1iZGEgYXJlIFVOUkVTVFJJQ1RFRCBNTEUgVkFMVUVTLCBidXQgbm93IHdlIG11c3QgZmluZAoKIyBudWxsIGh5cG90aGVzaXMgaXMgdGhhdCBiZXRhID0gMQojIGlmIG51bGwgaHlwb3RoZXNpcyBpcyB0cnVlLCB0aGVuIGRpc3RyaWJ1dGlvbiBpcyByZWFsbHkganVzdCBleHBvbmVudGlhbAoKIyMgdGhlIGxpa2VsaWhvb2QgcmF0aW8gdGVzdCBpcyBqdXN0IDIgKiAKICAjIFtsb2cgbGlrZWxpaG9vZCBldmFsdWF0ZWQgaW4gdW5yZXN0cmljdGVkIHdheSh3aGljaCBpcyB3aGF0IHdlIGRpZCBpbiBwYXJ0IGEpXSAtCiAgIyBbbG9nIGxpa2VsaWhvb2QgZXZhbHVhdGVkIGluIHJlc3RyaWN0ZWQgb3Igc2ltcGxlIHdheSh3aGljaCB3ZSBkaWQgaW4gcGFydCBiKV0KCiMgdGVzdCBzdGF0IGZvciBsaWtlbGlob29kIHJhdGlvIHRlc3QgaXMgdXBwZXJjYXNlIExhbWJkYQoKTGFtYmRhID0gMiAqICh3ZWliX21sZV9sYW1iZGEgLSBleHBfbWxlX2xhbWJkYSkKCnBfdmFsdWVfbGlrZWxpaG9vZHJhdGlvID0gMSAtIHBjaGlzcShMYW1iZGEsIGRmID0gMSkKICAjIHRlc3Qgc3RhdCBkaXN0cmlidXRpb24gZm9yIGxpa2VsaWhvb2QgcmF0aW8gdGVzdCBpcyBjaGktc3F1YXJlIGRpc3RyaWJ1dGVkCiAgIyBkZiA9IG51bWJlciBvZiBwYXJhbWV0ZXJzIHdlIGFyZSBlc3RpbWF0aW5nIGluIGZ1bmN0aW9uCgpgYGAKClBlcmZvcm1pbmcgdGhlIGxpa2VsaWhvb2QgcmF0aW8gdGVzdCwgdGhlIHJlc3VsdGluZyB2YWx1ZSBvZiAkXExhbWJkYSQgd2FzIHJvdWdobHkgYHIgcm91bmQoTGFtYmRhLDMpYCwgd2hpY2ggeWllbGRlZCBhIHAgdmFsdWUgb2Ygcm91Z2hseSBgciByb3VuZChwX3ZhbHVlX2xpa2VsaWhvb2RyYXRpbywgNilgLiBUaGlzIG9mIGNvdXJzZSBsZWFkcyB1cyB0byByZWplY3QgdGhlIG51bGwgaHlwb3RoZXNpcywgYXMgdGhlcmUgc2VlbXMgdG8gYmUgYSBsYXJnZSBlbm91Z2ggYW1vdW50IG9mIGV2aWRlbmNlIHRoYXQgc2lnbmlmaWNhbnQgYW1vdW50IG9mIGZpdCBpcyBsb3N0IGJ5IG9wZXJhdGluZyB1bmRlciB0aGUgYXNzdW1wdGlvbiBvZiBhbiBleHBvbmVudGlhbCBkaXN0cmlidXRpb24uIFRoZSBmaW5kaW5ncyBvZiB0aGlzIHRlc3QgYXJlIHJhdGhlciB1bnN1cnByaXNpbmcsIGdpdmVuIHRoZSBoaXN0b2dyYW0gdmlzdWFscyB3ZSBsb29rZWQgYXQgZWFybGllci4KCiMgZC4pIFdhbGQgVGVzdAoKRm9yIGZ1cnRoZXIgY29uZmlybWF0aW9uIHRoYXQgdGhlIGdyZWF0ZXIgY29tcGxleGl0eSB3aGljaCB0aGUgV2VpYnVsbCBjYXJyaWVzIGluIGNvbXBhcmlzb24gdG8gdGhlIGV4cG9uZW50aWFsIGRpc3RyaWJ1dGlvbiBpcyBhIHdvcnRod2hpbGUgdHJhZGVvZmYgZm9yIGluY3JlYXNlZCBhY2N1cmFjeSwgSSBhbHNvIHBlcmZvcm1lZCB0aGUgV2FsZCB0ZXN0LiBMaWtlIHRoZSBsaWtlbGlob29kIHJhdGlvIHRlc3QsIHRoZSBXYWxkIHRlc3QgYWxzbyBmb2xsb3dzIGEgY2hpLXNxdWFyZSBkaXN0cmlidXRpb24sIHdpdGggdGhlIGRlZ3JlZXMgb2YgZnJlZWRvbSBhY3RpbmcgYXMgdGhlIG51bWJlciBvZiBwYXJhbWV0ZXJzIGJlaW5nIGVzdGltYXRlZCBhdCB0aGF0IHRpbWUuIAoKVGhlIG51bGwgaHlwb3RoZXNpcyBvZiB0aGUgV2FsZCB0ZXN0IGlzIHRoYXQgdGhlIHBhcmFtZXRlciBvZiBpbnRlcmVzdCAoJFxiZXRhJCBpbiBvdXIgY2FzZSkgaXMgY2xvc2UgZW5vdWdoIG9yIGVxdWFsIHRvIHdoYXRldmVyIHByZXZpb3VzbHkgaHlwb3RoZXNpemVkIHZhbHVlLiBJbiB0aGlzIGluc3RhbmNlLCB3ZSB3aWxsIGNvbXBhcmUgdGhlIHVuY29uc3RyYWluZWQgTUxFLWJhc2VkIGVzdGltYXRlIG9mICRcYmV0YSQgZm91bmQgaW4gcGFydCBhIHRvIHRoZSB2YWx1ZSBvZiAkXGJldGEkICgxKSB0aGF0IHdvdWxkIG1ha2UgdGhpcyBkaXN0cmlidXRpb24gb2YgYmFsbCBiZWFyaW5nIHN1cnZpdmFsIHRpbWVzIHRydWx5IGV4cG9uZW50aWFsLgpgYGB7cn0KaW52aXNpYmxlKAogIHdlaWJfbWxlX2VzdGltYXRlcyRoZXNzaWFuCikKIyMgdGhlIGludmVyc2Ugb2YgdGhlIEhlc3NpYW4gbWF0cml4IGlzIHRoZSBjb3ZhcmlhbmNlCiAjIGluIFIsIHRoZSBzb2x2ZSBmdW5jdGlvbiByZXR1cm5zIHRoZSBpbnZlcnNlIG9mIGEgbWF0cml4IG9iamVjdApjb3Zhcl9tYXRyaXggPSBzb2x2ZSgtd2VpYl9tbGVfZXN0aW1hdGVzJGhlc3NpYW4pCgojIGFscmVhZHkgaGF2ZSB3ZWliX21sZV9iZXRhIGFzIG91ciBlc3RpYW10ZSBiYXNlZCBvbiB0aGUgdW5yZXN0cmljdGVkIGxpa2VsaWhvb2QgZXN0aW1hdGlvbiBtZXRob2QKCnZhcl9iZXRhID0gY292YXJfbWF0cml4WzEsMV0KCndhbGRfc3RhdCA9ICh3ZWliX21sZV9iZXRhIC0gMSleMiAvIHZhcl9iZXRhCgojIyBvbmNlIGFnYWluLCB3YWxkX3N0YXQgaXMgY2hpIHNxdWFyZSBqdXN0IGxpa2UgbGlrZWxpaG9vZCByYXRpbwpwX3ZhbHVlX3dhbGQgPSAxIC0gcGNoaXNxKHdhbGRfc3RhdCwgZGYgPSAxKQoKYGBgCgpQZXIgdGhlIHJlc3VsdHMgb2YgdGhlIFdhbGQgdGVzdCwgdGhlcmUgaXMgc3VmZmljaWVudCBzdGF0aXN0aWNhbCBldmlkZW5jZSB0aGF0IHdlICoqY2Fubm90Kiogc2ltcGx5IG9wZXJhdGUgdW5kZXIgdGhlIGFzc3VtcHRpb24gdGhhdCB0aGUgdHJ1ZSBzaGFwZSBwYXJhbWV0ZXIgJFxiZXRhJCBvZiBvdXIgZGlzdHJpYnV0aW9uIGlzIDEuIFRoZSBXYWxkIHRlc3QgeWllbGRlZCBhIHRlc3Qgc3RhdGlzdGljIGFuZCBwIHZhbHVlIG9mIGFwcHJveGltYXRlbHkgYHIgcm91bmQod2FsZF9zdGF0LCAzKWAgYW5kIGByIHJvdW5kKHBfdmFsdWVfd2FsZCw2KWAgcmVzcGVjdGl2ZWx5LgoKIyBlLikgU3VtbWFyeSBhbmQgQ29uY2x1c2lvbnMKR2l2ZW4gdGhlIHJlc3VsdHMgb2YgdGhlIHR3byBwZXJmb3JtZWQgaHlwb3RoZXNpcyB0ZXN0cywgd2UgKipjYW5ub3QqKiBqdXN0aWZ5IHRyZWF0aW5nIHRoZSBkaXN0cmlidXRpb24gb2YgYmFsbCBiZWFyaW5nIHN1cnZpdmFsIHRpbWVzIGFzIGV4cG9uZW50aWFsLiBEb2luZyBzbyB3b3VsZCByZXN1bHQgaW4gYSBzaWduaWZpY2FudCBhbW91bnQgb2YgcHJlZGljdGl2ZSBhY2N1cmFjeSBsb3N0IHBlciB0aGUgcmVzdWx0cyBvZiB0aGUgbGlrZWxpaG9vZCByYXRpbyB0ZXN0LiBBbmQgcGVyIHRoZSBXYWxkIHRlc3QsIHRoZXJlIGlzIG5vdCBzdWZmaWNpZW50IGV2aWRlbmNlIHRoYXQgdGhlICRcYmV0YSQgcGFyYW1ldGVyIGlzICJmbGV4aWJsZSIgZW5vdWdoIHRvIGJlIGFzc3VtZWQgYXQgYSB2YWx1ZSBvZiBvbmUsIGdpdmVuIG91ciBhdmFpbGFibGUgZGF0YS4KCktub3dpbmcgdGhpcywgd2Ugc2hvdWxkIG1vdmUgZm9yd2FyZCB3aXRoIHRoZSBhc3N1bXB0aW9ucyB0aGF0IHRoZSBicm9hZGVyIHBvcHVsYXRpb24gb2YgYmVhcmluZyBzdXJ2aXZhbCB0aW1lcyBpcyAqKldlaWJ1bGwgZGlzdHJpYnV0ZWQqKiwgd2l0aCBhIHNoYXBlIHBhcmFtZXRlciBvZiBhcHByb3hpbWF0ZWx5IGByIHJvdW5kKHdlaWJfbWxlX2JldGEsMylgIGFuZCBhIHNjYWxlIHBhcmFtZXRlciBvZiBhYm91dCBgciByb3VuZCh3ZWliX21sZV9sYW1iZGEsMylgLiBUaGUgdmlzdWFsIGZvciB0aGlzIGRpc3RyaWJ1dGlvbiBpcyBiZWxvdyBvbmNlIGFnYWluLgoKYGBge3J9CmdncGxvdChkYXRhID0gZGF0YSkgKwogIGdlb21faGlzdG9ncmFtKG1hcHBpbmcgPSBhZXMoeCA9IHRpbWUsIHkgPSBhZnRlcl9zdGF0KGRlbnNpdHkpKSwKICAgICAgICAgICAgICAgICBjb2xvciA9ICJibGFjayIsCiAgICAgICAgICAgICAgICAgICMgYXJndW1lbnQgY29sb3IgaW4gZ2VvbV9oaXN0b2dyYW0gaXMgZm9yIGNvbG9yIG9mIGJpbiBsaW5lcwogICAgICAgICAgICAgICAgIGZpbGwgPSAibGlnaHRibHVlIiwKICAgICAgICAgICAgICAgICBiaW5zID0gMTAsKSArCiAgIyB1c2Ugc3RhdF9mdW5jdGlvbiBpbiBnZ3Bsb3QgdG8gc2hvdyBkZW5zaXR5IGN1cnZlcyBvZiBvdGhlciBkaXN0cmlidXRpb25zCiAgICBzdGF0X2Z1bmN0aW9uKGZ1biA9IGR3ZWlidWxsLCAKICAgICAgICAgICAgICAgIGFyZ3MgPSBsaXN0KHNoYXBlID0gd2VpYl9tbGVfYmV0YSwgc2NhbGUgPSB3ZWliX21sZV9sYW1iZGEpLAogICAgICAgICAgICAgICAgY29sb3IgPSAiYmxhY2siLAogICAgICAgICAgICAgICAgbGluZXdpZHRoID0gMS41LAogICAgICAgICAgICAgICAgeGxpbSA9IHJhbmdlKDA6MjAwKSkrCiAgICAgICAgICAgICMgeGxpbSBhcmd1bWVudCBzbyBjdXJ2ZSBkb2Vzbid0IGF3a2FyZGx5IGN1dCBvdXQgYXQgZWRnZSBwb2ludHMgb2YgZGF0YQogIGxhYnModGl0bGUgPSAiRGlzdHJpYnV0aW9uIG9mIFN1cnZpdmFsIFRpbWVzIiwKICAgICAgIHggPSAiVGltZSIsCiAgICAgICB5ID0gIkRlbnNpdHkiKSArIAogIHRoZW1lKAogICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG9yID0gImJsYWNrIiwgZmlsbCA9IE5BLCBsaW5ld2lkdGggPSAzKSwKICAgIGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC44NSwgMC44NSkKICApCgpgYGAKCk91ciB2aXN1YWwgc2hvd3MgYSByYXRoZXIgaW1tZWRpYXRlIHVwdGljayBpbiB2YWx1ZXMsIGFuZCB0aGVuIGEgbm90aWNlYWJsZSByaWdodHdhcmQgc2tldy4gVGhpcyBpcyBhIHN0YW5kYXJkIHBhdHRlcm4gZm9yIGEgV2VpYnVsbCBkaXN0cmlidXRpb24sIG1ha2luZyBpdCBhIHBvd2VyZnVsIG1vZGVsaW5nIGZyYW1ld29yayBmb3IgYXJlYXMgbGlrZSBlbmdpbmVlcmluZyBhbmQgbGlmZSBleHBlY3RhbmNpZXMuCg==