Assignment Objectives

  • Enhance understanding the procedure of Bootstrap hypothesis testing.

  • Implement the procedures for detecting overfitting/underfitting issues in practical applications using bootstrap likelihood ratio test.

Policies of Using AI Tools

Policy on AI Tool Use: Please adhere to the AI tool policy specified in the course syllabus. The direct copying of AI-generated content is strictly prohibited. All submitted work must reflect your own understanding; where external tools are consulted, content must be thoroughly rephrased and synthesized in your own words.

Code Inclusion Requirement: Any code included in your essay must be properly commented to explain the purpose and/or expected output of key code lines. Submitting AI-generated code without meaningful, student-added comments will not be accepted.

Testing Overfitting/Underfitting

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

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

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

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

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

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

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

Steps of the BLRT

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

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

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

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

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


Question: Reliability Application

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

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

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

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

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


n = length(windfarm)
#here we define the weibull log likelihood function
#
weibull_loglik = function(params, data) #weilbull distribution parameters: beta (shape), alpha (scale)
{
  sum(dweibull(data, shape = params[1], #beta shape parameter
                      scale = params[2], #lambda scale parameter
                      log = TRUE         #write the log likelihood of the weibull distribution
                ))
  
  
}


#Finding the MLEs using optim()
  #use mean of data as reference

mle_weibull = optim(par = c(1, mean(windfarm)),
                    fn = weibull_loglik, # minimizes function
                    data= windfarm,
                    control = list(fnscale= -1) #-1 for maximization
                    
                    )

hat_beta = mle_weibull$par[1]
hat_lambda = mle_weibull$par[2]
logL1_obs = mle_weibull$value


cat("Weibull MLEs Shape (Beta):", hat_beta, "Scale (Lambda):", hat_lambda)
Weibull MLEs Shape (Beta): 3.370336 Scale (Lambda): 31.41928

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

exp_loglik = function(lambda, data) #exponetial distrubution parameters: lambda
{
  sum(dexp(data, rate= 1/lambda , #solve for rate with lambda parameter
                      log = TRUE #write the log likelihood of the exponential distribution
                ))
  
  
}


#Finding the MLEs using optim()
  #use mean of data as reference

mle_exp = optim(par = c(mean(windfarm)), #intial guess starting point for lambda
                    fn = exp_loglik, # minimizes function
                    data= windfarm,
                    
                    control = list(fnscale= -1) #-1 for maximization
                    
                    )



hat_lambda_exp = mle_exp$par
loglike_exp_null = mle_exp$value


cat("Exponetial MLEs Scale (Lambda):", hat_lambda_exp, 
    "Max Log-Likelihood (Null):", loglike_exp_null)
Exponetial MLEs Scale (Lambda): 28.18533 Max Log-Likelihood (Null): -325.4101

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

#Calculating the p value

  #Find the difference of the from lower peak or higher peak

LR_obs = -2 *(loglike_exp_null - logL1_obs) #likelihood_ratio_test

#Calc p value w/ chisquare distrubution w/ 1 degree of freedom
p_val_chi2= 1-pchisq(LR_obs,1) #p_val =1-pchisq(likelihood_ratio_test,1)
  
  
cat("Likelihood Ratio Statistic (Observed):", LR_obs, 
    "\nChi-Square P-value:", p_val_chi2)
Likelihood Ratio Statistic (Observed): 100.6143 
Chi-Square P-value: 0

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

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

B = 9999
n = length(windfarm)

#finding weilbuil MLEs
#using MLEs found in earlier sections 

LR_obs = -2 * (loglike_exp_null - logL1_obs) #find log likehood ratio for observed values and force into a chi square distrubution

weibull_loglik = function(params, data) {
  sum(dweibull(data, shape = params[1], scale = params[2], log = TRUE))
}
################Bootstrap Building###333
boot_lrt= function(data, hat_lambda_exp, B=B){  
  
    n = length(data)
    LR_star = numeric(B) #bootstrap the log likelihood ratio
    
    
    
    # Bootstrap distribution
    LR_star <- numeric(B)
    for (b in 1:B) {
    
    #bootstrap sample under HO
      z_star = rexp(n, rate =1/hat_lambda_exp)
    
  # Fit null model (exponential distribution)

loglike_null_boot = sum(dexp(z_star, rate = 1 / mean(z_star), log = TRUE))
      
#Fit alternative  model (weibull distribution)

fit_star = optim(par = c(1, mean(z_star)), fn = weibull_loglik,  data = z_star, control = list(fnscale = -1))

logL1_star = fit_star$value

#Calculate the 'Fake' bootstrapped comparison Likelihood Ratio
    LR_star[b] = -2 * (loglike_null_boot - logL1_star)
    }
  
return(LR_star)

}

boot_results = boot_lrt(windfarm, hat_lambda_exp, B = B)

# Calculating the p-value:
#p_val_boot = (sum(boot_results >= LR_obs) + 1) / (length(boot_results) + 1)

p_val_boot = (sum(boot_results >= LR_obs)+1)/ (B+1) #number of bootstraps





cat("Bootstrap P-Value:", p_val_boot)
Bootstrap P-Value: 1e-04

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

  • Whether the two tests generated the same results.

  • Which model is recommended for the data.

Both hypothesis testing results preformed with MLE testing and bootstrapped hypothesis tested were statistically significant, suggesting that the complex model, the weibull distribution, is more significant. In both approaches, the Weibull distribution does a better job at explaining the data than the simpler, exponential model . In generality, both the bootstrapped hypothesis test 10^{-4} and the non-bootstrapped hypothesis test 0 convey the same information.

Considering the moderate sample size of 75 and further testing would be required to know if there are strong violations against distributional assumptions a bootstrap could be a strong recommendation over the traditional hypothesis testing.Bootstrap hypothesis testing provides robust analysis for small sample sizes and when distributional assumptions are violated. Additionally, we do not need to assume a chi square distribution for a bootstrap unlike the chi-square based likelihood ratio statistic, allowing us to likely better suit the data for analysis than a parametric test. Use a weibull distribution to monitor the reliability of gearboxes.

LS0tDQp0aXRsZTogIkFzc2lnbm1lbnQgMTI6IEJvb3RzdHJhcCBMaWtlbGlob29kIFJhdGlvIFRlc3QgKEJMUlQpIg0KYXV0aG9yOiAiRXphbmEgUml2ZXJzICINCmRhdGU6ICIgNC0yMTogIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50OiANCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogNA0KICAgIHRvY19mbG9hdDogeWVzDQogICAgbnVtYmVyX3NlY3Rpb25zOiBubw0KICAgIHRvY19jb2xsYXBzZWQ6IHllcw0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIGNvZGVfZG93bmxvYWQ6IHllcw0KICAgIHNtb290aF9zY3JvbGw6IHllcw0KICAgIGhpZ2hsaWdodDogbW9ub2Nocm9tZQ0KICAgIHRoZW1lOiBzcGFjZWxhYg0KICB3b3JkX2RvY3VtZW50OiANCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogNA0KICAgIGZpZ19jYXB0aW9uOiB5ZXMNCiAgICBrZWVwX21kOiB5ZXMNCiAgcGRmX2RvY3VtZW50OiANCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogNA0KICAgIGZpZ19jYXB0aW9uOiB5ZXMNCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcw0KICAgIGZpZ193aWR0aDogMw0KICAgIGZpZ19oZWlnaHQ6IDMNCmVkaXRvcl9vcHRpb25zOiANCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQ0KLS0tDQoNCmBgYHtjc3MsIGVjaG8gPSBGQUxTRX0NCiNUT0M6OmJlZm9yZSB7DQogIGNvbnRlbnQ6ICJUYWJsZSBvZiBDb250ZW50cyI7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KICBmb250LXNpemU6IDEuMmVtOw0KICBkaXNwbGF5OiBibG9jazsNCiAgY29sb3I6IG5hdnk7DQogIG1hcmdpbi1ib3R0b206IDEwcHg7DQp9DQoNCg0KZGl2I1RPQyBsaSB7ICAgICAvKiB0YWJsZSBvZiBjb250ZW50ICAqLw0KICAgIGxpc3Qtc3R5bGU6dXBwZXItcm9tYW47DQogICAgYmFja2dyb3VuZC1pbWFnZTpub25lOw0KICAgIGJhY2tncm91bmQtcmVwZWF0Om5vbmU7DQogICAgYmFja2dyb3VuZC1wb3NpdGlvbjowOw0KfQ0KDQpoMS50aXRsZSB7ICAgIC8qIGxldmVsIDEgaGVhZGVyIG9mIHRpdGxlICAqLw0KICBmb250LXNpemU6IDIycHg7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KICBjb2xvcjogRGFya1JlZDsNCiAgdGV4dC1hbGlnbjogY2VudGVyOw0KICBmb250LWZhbWlseTogIkdpbGwgU2FucyIsIHNhbnMtc2VyaWY7DQp9DQoNCmg0LmF1dGhvciB7IC8qIEhlYWRlciA0IC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovDQogIGZvbnQtc2l6ZTogMTVweDsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogIGZvbnQtZmFtaWx5OiBzeXN0ZW0tdWk7DQogIGNvbG9yOiBuYXZ5Ow0KICB0ZXh0LWFsaWduOiBjZW50ZXI7DQp9DQoNCmg0LmRhdGUgeyAvKiBIZWFkZXIgNCAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICBmb250LXNpemU6IDE4cHg7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KICBmb250LWZhbWlseTogIkdpbGwgU2FucyIsIHNhbnMtc2VyaWY7DQogIGNvbG9yOiBEYXJrQmx1ZTsNCiAgdGV4dC1hbGlnbjogY2VudGVyOw0KfQ0KDQpoMSB7IC8qIEhlYWRlciAxIC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovDQogICAgZm9udC1zaXplOiAyMHB4Ow0KICAgIGZvbnQtd2VpZ2h0OiBib2xkOw0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBkYXJrcmVkOw0KICAgIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCg0KaDIgeyAvKiBIZWFkZXIgMiAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICAgIGZvbnQtc2l6ZTogMThweDsNCiAgICBmb250LXdlaWdodDogYm9sZDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogbmF2eTsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KDQpoMyB7IC8qIEhlYWRlciAzIC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovDQogICAgZm9udC1zaXplOiAxNnB4Ow0KICAgIGZvbnQtd2VpZ2h0OiBib2xkOw0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBuYXZ5Ow0KICAgIHRleHQtYWxpZ246IGxlZnQ7DQp9DQoNCmg0IHsgLyogSGVhZGVyIDQgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgICBmb250LXNpemU6IDE0cHg7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBkYXJrcmVkOw0KICAgIHRleHQtYWxpZ246IGxlZnQ7DQp9DQoNCi8qIEFkZCBkb3RzIGFmdGVyIG51bWJlcmVkIGhlYWRlcnMgKi8NCi5oZWFkZXItc2VjdGlvbi1udW1iZXI6OmFmdGVyIHsNCiAgY29udGVudDogIi4iOw0KDQpib2R5IHtiYWNrZ3JvdW5kLWNvbG9yOiAjZmZmZmZmOw0KICAgICAgY29sb3I6ICMwMDAwMDA7DQogICAgICBmb250LWZhbWlseTogQXJpYWwsIHNhbnMtc2VyaWY7DQogICAgICBmb250LXNpemU6IDFyZW07DQogICAgICBsaW5lLWhlaWdodDogMS42Ow0KICAgICAgfQ0KDQouaGlnaGxpZ2h0bWUgeyBiYWNrZ3JvdW5kLWNvbG9yOnllbGxvdzsgfQ0KDQpwIHsgYmFja2dyb3VuZC1jb2xvcjp3aGl0ZTsgfQ0KDQp9DQpgYGANCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQojIGNvZGUgY2h1bmsgc3BlY2lmaWVzIHdoZXRoZXIgdGhlIFIgY29kZSwgd2FybmluZ3MsIGFuZCBvdXRwdXQgDQojIHdpbGwgYmUgaW5jbHVkZWQgaW4gdGhlIG91dHB1dCBmaWxlcy4NCmlmICghcmVxdWlyZSgia25pdHIiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygia25pdHIiKQ0KICAgbGlicmFyeShrbml0cikNCn0NCmlmICghcmVxdWlyZSgicGFuZGVyIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoInBhbmRlciIpDQogICBsaWJyYXJ5KHBhbmRlcikNCn0NCmlmICghcmVxdWlyZSgiZ2dwbG90MiIpKSB7DQogIGluc3RhbGwucGFja2FnZXMoImdncGxvdDIiKQ0KICBsaWJyYXJ5KGdncGxvdDIpDQp9DQppZiAoIXJlcXVpcmUoInRpZHl2ZXJzZSIpKSB7DQogIGluc3RhbGwucGFja2FnZXMoInRpZHl2ZXJzZSIpDQogIGxpYnJhcnkodGlkeXZlcnNlKQ0KfQ0KDQppZiAoIXJlcXVpcmUoInBsb3RseSIpKSB7DQogIGluc3RhbGwucGFja2FnZXMoInBsb3RseSIpDQogIGxpYnJhcnkocGxvdGx5KQ0KfQ0KDQppZiAoIXJlcXVpcmUoIlZHQU0iKSkgew0KICBpbnN0YWxsLnBhY2thZ2VzKCJWR0FNIikNCiAgbGlicmFyeShWR0FNKQ0KfQ0KIyMjIyBWR0FNDQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsICAgICAgICMgaW5jbHVkZSBjb2RlIGNodW5rIGluIHRoZSBvdXRwdXQgZmlsZQ0KICAgICAgICAgICAgICAgICAgICAgIHdhcm5pbmcgPSBGQUxTRSwgICAjIHNvbWV0aW1lcywgeW91IGNvZGUgbWF5IHByb2R1Y2Ugd2FybmluZyBtZXNzYWdlcywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyB5b3UgY2FuIGNob29zZSB0byBpbmNsdWRlIHRoZSB3YXJuaW5nIG1lc3NhZ2VzIGluDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgdGhlIG91dHB1dCBmaWxlLiANCiAgICAgICAgICAgICAgICAgICAgICByZXN1bHRzID0gVFJVRSwgICAgIyB5b3UgY2FuIGFsc28gZGVjaWRlIHdoZXRoZXIgdG8gaW5jbHVkZSB0aGUgb3V0cHV0DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgaW4gdGhlIG91dHB1dCBmaWxlLg0KICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSwNCiAgICAgICAgICAgICAgICAgICAgICBjb21tZW50ID0gTkENCiAgICAgICAgICAgICAgICAgICAgICApICANCmBgYA0KIA0KIFwNCiANCiMjICoqQXNzaWdubWVudCBPYmplY3RpdmVzKiogDQoNCjxwPg0KKiBFbmhhbmNlIHVuZGVyc3RhbmRpbmcgdGhlIHByb2NlZHVyZSBvZiBCb290c3RyYXAgaHlwb3RoZXNpcyB0ZXN0aW5nLg0KDQoqIEltcGxlbWVudCB0aGUgcHJvY2VkdXJlcyBmb3IgZGV0ZWN0aW5nIG92ZXJmaXR0aW5nL3VuZGVyZml0dGluZyBpc3N1ZXMgaW4gcHJhY3RpY2FsIGFwcGxpY2F0aW9ucyB1c2luZyBib290c3RyYXAgbGlrZWxpaG9vZCByYXRpbyB0ZXN0Lg0KPC9wPg0KDQoNCiMjICoqUG9saWNpZXMgb2YgVXNpbmcgQUkgVG9vbHMqKg0KDQo8cD4NCioqUG9saWN5IG9uIEFJIFRvb2wgVXNlKio6IFBsZWFzZSBhZGhlcmUgdG8gdGhlIEFJIHRvb2wgcG9saWN5IHNwZWNpZmllZCBpbiB0aGUgY291cnNlIHN5bGxhYnVzLiBUaGUgZGlyZWN0IGNvcHlpbmcgb2YgQUktZ2VuZXJhdGVkIGNvbnRlbnQgaXMgc3RyaWN0bHkgcHJvaGliaXRlZC4gQWxsIHN1Ym1pdHRlZCB3b3JrIG11c3QgcmVmbGVjdCB5b3VyIG93biB1bmRlcnN0YW5kaW5nOyB3aGVyZSBleHRlcm5hbCB0b29scyBhcmUgY29uc3VsdGVkLCBjb250ZW50IG11c3QgYmUgdGhvcm91Z2hseSByZXBocmFzZWQgYW5kIHN5bnRoZXNpemVkIGluIHlvdXIgb3duIHdvcmRzLg0KPC9wPg0KDQo8cD4NCioqQ29kZSBJbmNsdXNpb24gUmVxdWlyZW1lbnQqKjogQW55IGNvZGUgaW5jbHVkZWQgaW4geW91ciBlc3NheSBtdXN0IGJlIHByb3Blcmx5IGNvbW1lbnRlZCB0byBleHBsYWluIHRoZSBwdXJwb3NlIGFuZC9vciBleHBlY3RlZCBvdXRwdXQgb2Yga2V5IGNvZGUgbGluZXMuIFN1Ym1pdHRpbmcgQUktZ2VuZXJhdGVkIGNvZGUgd2l0aG91dCBtZWFuaW5nZnVsLCBzdHVkZW50LWFkZGVkIGNvbW1lbnRzIHdpbGwgbm90IGJlIGFjY2VwdGVkLg0KPC9wPg0KDQoNCg0KDQojIyBUZXN0aW5nIE92ZXJmaXR0aW5nL1VuZGVyZml0dGluZw0KDQpJbiBNYWNoaW5lIExlYXJuaW5nIGFuZCBTdGF0aXN0aWNzLCBvdmVyZml0dGluZyBvY2N1cnMgd2hlbiBhIG1vZGVsIGlzIHRvbyBjb21wbGV4IGFuZCBsZWFybnMgbm9pc2UsIGxlYWRpbmcgdG8gcG9vciBwZXJmb3JtYW5jZSBvbiBuZXcgZGF0YSwgd2hpbGUgdW5kZXJmaXR0aW5nIGhhcHBlbnMgd2hlbiBhIG1vZGVsIGlzIHRvbyBzaW1wbGUgdG8gY2FwdHVyZSBpbXBvcnRhbnQgcGF0dGVybnMsIHJlc3VsdGluZyBpbiBoaWdoIGVycm9ycyBvdmVyYWxsOyBib3RoIGlzc3VlcyBhcmUgZXhwbGFpbmVkIGJ5IHRoZSBCaWFz4oCTVmFyaWFuY2UgVHJhZGVvZmYgYW5kIGNhbiBjYXVzZSB1bnJlbGlhYmxlIHByZWRpY3Rpb25zIGluIHJlYWwtd29ybGQgYXBwbGljYXRpb25zLg0KDQoNClRoZSBwcm9iYWJpbGl0eSBkZW5zaXR5IGZ1bmN0aW9uIChQREYpIG9mIHRoZSBXZWlidWxsIGRpc3RyaWJ1dGlvbiBpczoNCg0KJCQNCmYodDsgXGxhbWJkYSwgXGJldGEpID0gXGZyYWN7XGJldGF9e1xsYW1iZGF9IFxsZWZ0KCBcZnJhY3t0fXtcbGFtYmRhfSBccmlnaHQpXntcYmV0YS0xfSBcZXhwXGxlZnRbIC1cbGVmdCggXGZyYWN7dH17XGxhbWJkYX0gXHJpZ2h0KV5cYmV0YSBccmlnaHRdLCBccXVhZCB0IFxnZSAwDQokJA0Kd2hlcmUgJFxsYW1iZGEgPiAwJCBpcyB0aGUgc2NhbGUgcGFyYW1ldGVyIChjaGFyYWN0ZXJpc3RpYyBsaWZlKSBhbmQgJFxiZXRhID4gMCQgaXMgdGhlIHNoYXBlIHBhcmFtZXRlci4NCg0KV2hlbiAkXGJldGEgPSAxJCwgdGhlIFdlaWJ1bGwgUERGIHNpbXBsaWZpZXMgdG8gdGhlIGV4cG9uZW50aWFsIFBERjoNCg0KJCQNCmYodDsgXGxhbWJkYSkgPSBcZnJhY3sxfXtcbGFtYmRhfSBcZXhwXGxlZnQoIC1cZnJhY3t0fXtcbGFtYmRhfSBccmlnaHQpDQokJA0Kd2l0aCBjb25zdGFudCBoYXphcmQgcmF0ZSAkaCh0KSA9IDEvXGxhbWJkYSQuDQoNCg0KPHA+PGZvbnQgY29sb3IgPSAiZGFya3JlZCI+KipUaGlzIGFzc2lnbm1lbnQgZm9jdXNlcyBvbiBwZXJmb3JtaW5nIGEgaHlwb3RoZXNpcyB0ZXN0IGZvciB0aGUgc2hhcGUgcGFyYW1ldGVyICgkXGJldGEkKSBvZiB0aGUgV2VpYnVsbCBkaXN0cmlidXRpb24gd2l0aGluIGEgcmVsaWFiaWxpdHkgbW9kZSoqPC9mb250PjwvcD4NCg0KDQpcYmVnaW57YWxpZ259DQpIXzAmOiBcYmV0YSA9IDEgXHF1YWQgXHRleHR7KEV4cG9uZW50aWFsIG1vZGVsLCBzaW1wbGVyKX0gXFwNCkhfMSY6IFxiZXRhIFxuZXEgMSBccXVhZCBcdGV4dHsoV2VpYnVsbCBtb2RlbCwgbW9yZSBjb21wbGV4KX0NClxlbmR7YWxpZ259DQoNCg0KDQojIyBTdGVwcyBvZiB0aGUgQkxSVA0KDQoNCiogRml0IG1vZGVscyB1bmRlciAkSF8wJCBhbmQgJEhfMSR9IHRvIHRoZSBvcmlnaW5hbCBkYXRhLCBjb21wdXRlICRcTGFtYmRhX3tcdGV4dHtvYnN9fSQuDQoNCiogR2VuZXJhdGUgYm9vdHN0cmFwIHNhbXBsZXMgdW5kZXIgJEhfMCR9OiANCiAgKyBFc3RpbWF0ZSBwYXJhbWV0ZXJzIHVuZGVyICRIXzAkIGZyb20gdGhlIG9yaWdpbmFsIGRhdGEuDQogICsgR2VuZXJhdGUgJEIkIGRhdGFzZXRzIGJ5IHNhbXBsaW5nIGZyb20gdGhlIG1vZGVsIHVuZGVyICRIXzAkIChwYXJhbWV0cmljIGJvb3RzdHJhcCkgb3IgYnkgcmVzYW1wbGluZyByZXNpZHVhbHMvY2FzZXMgKG5vbnBhcmFtZXRyaWMgYm9vdHN0cmFwOyBwYXJhbWV0cmljIGlzIGNvbW1vbiBmb3IgQkxSVCkuDQoNCiogRm9yIGVhY2ggYm9vdHN0cmFwIHNhbXBsZSAkYiA9IDEsXGRvdHMsQiQ6DQogICsgRml0ICRIXzAkIGFuZCAkSF8xJCBtb2RlbHMuDQogICsgQ29tcHV0ZSAkXExhbWJkYV9iID0gLTJbXGVsbF97MCxifSAtIFxlbGxfezEsYn1dJC4NCg0KKiBBcHByb3hpbWF0ZSBwLXZhbHVlOg0KDQokJA0KICBwID0gXGZyYWN7MX17Qn0gXHN1bV97Yj0xfV5CIEkoXExhbWJkYV9iIFxnZSBcTGFtYmRhX3tcdGV4dHtvYnN9fSkNCiQkDQooT2Z0ZW4gYSBzbWFsbCBhZGp1c3RtZW50IGlzIG1hZGUgZm9yIHN0YWJpbGl0eTogJCgxICsgXCNce1xMYW1iZGFfYiBcZ2UgXExhbWJkYV97XHRleHR7b2JzfX1cfSkvKEIrMSkkKS4NCg0KDQoNClwNCg0KIyMgKipRdWVzdGlvbjogUmVsaWFiaWxpdHkgQXBwbGljYXRpb24qKg0KDQo8cD4NCkEgd2luZCBlbmVyZ3kgY29tcGFueSBtb25pdG9ycyB0aGUgcmVsaWFiaWxpdHkgb2YgZ2VhcmJveGVzIGluIDc1IGlkZW50aWNhbCB3aW5kIHR1cmJpbmVzIGxvY2F0ZWQgaW4gYSBjb2FzdGFsIHdpbmQgZmFybS4gVGhlIGdlYXJib3ggaXMgYSBjcml0aWNhbCBjb21wb25lbnQ7IGl0cyBmYWlsdXJlIG9mdGVuIGxlYWRzIHRvIGNvc3RseSBkb3dudGltZSBhbmQgcmVwYWlycy4gUHJldmlvdXMgc3R1ZGllcyBzdWdnZXN0IHRoYXQgdGhlIGhhemFyZCByYXRlIChmYWlsdXJlIHJpc2spIG1heSBpbmNyZWFzZSBvdmVyIHRpbWUgZHVlIHRvIG1lY2hhbmljYWwgd2VhciAoZmF0aWd1ZSwgcGl0dGluZywgYmVhcmluZyBkZWdyYWRhdGlvbikuIEVuZ2luZWVycyB3YW50IHRvIHRlc3Qgd2hldGhlciB0aGUgZmFpbHVyZSB0aW1lIGRpc3RyaWJ1dGlvbiBmb2xsb3dzIGFuIGV4cG9uZW50aWFsIG1vZGVsIChjb25zdGFudCBoYXphcmQsIHJhbmRvbSBmYWlsdXJlcykgb3IgYSBXZWlidWxsIG1vZGVsIHdpdGggc2hhcGUgcGFyYW1ldGVyICRrPjEkIChpbmNyZWFzaW5nIGhhemFyZCwgaW5kaWNhdGl2ZSBvZiBhZ2luZy9kZWdyYWRhdGlvbikuIFRoZSBmYWlsdXJlIHRpbWVzIChpbiBtb250aHMpIGFyZToNCg0KYGBgDQogICA1LjIsICA3LjgsICA5LjEsIDExLjMsIDEyLjUsIDEzLjAsIDE0LjIsIDE1LjEsIDE1LjksIDE2LjcsIDE3LjIsIDE3LjgsIDE4LjQsIDE4LjksIA0KICAxOS4zLCAxOS43LCAyMC4yLCAyMC42LCAyMS4wLCAyMS41LCAyMS45LCAyMi4zLCAyMi43LCAyMy4xLCAyMy41LCAyMy45LCAyNC4zLCAyNC43LCANCiAgMjUuMSwgMjUuNSwgMjUuOSwgMjYuMywgMjYuNywgMjcuMSwgMjcuNSwgMjcuOSwgMjguMywgMjguNywgMjkuMSwgMjkuNSwgMjkuOSwgMzAuMywgDQogIDMwLjcsIDMxLjEsIDMxLjUsIDMxLjksIDMyLjMsIDMyLjcsIDMzLjEsIDMzLjUsIDMzLjksIDM0LjMsIDM0LjcsIDM1LjEsIDM1LjUsIDM1LjksIA0KICAzNi4zLCAzNi43LCAzNy4xLCAzNy41LCAzNy45LCAzOC4zLCAzOC43LCAzOS4xLCAzOS41LCAzOS45LCA0MC4zLCA0MC43LCA0MS4xLCA0MS41LA0KICA0MS45LCA0Mi4zLCA0Mi43LCA0My4xLCA0My41DQpgYGANCjwvcD4NCg0KVGhpcyBhc3NpZ25tZW50IGZvY3VzZXMgb24gaHlwb3RoZXNpcyAkSF8wOiBcYmV0YSA9IDEkIChleHBvbmVudGlhbCkgYWdhaW5zdCAkSF8xOiBcYmV0YSBcbmVxIDEkIChXZWlidWxsKS4gVGhpcyBmcmFtZXdvcmsgZGV0ZWN0cyBvdmVyZml0dGluZyAoZml0dGluZyBhIFdlaWJ1bGwgd2hlbiBleHBvbmVudGlhbCBpcyB0cnVlKSBhbmQgdW5kZXJmaXR0aW5nIChmaXR0aW5nIGV4cG9uZW50aWFsIHdoZW4gV2VpYnVsbCB3aXRoICRcYmV0YSBcbmVxIDEkIGlzIHRydWUpLiANCg0KDQo8cD4NCmEpLiBGaW5kIHRoZSBNTEUgb2YgdGhlIFdlaWJ1bGwgcGFyYW1ldGVycyAkXGxhbWJkYSQgKHNjYWxlKSBhbmQgJFxiZXRhJCAoc2hhcGUpLCBkZW5vdGVkIGJ5ICRcaGF0e1xsYW1iZGF9JCBhbmQgJFxoYXR7XGJldGF9JCwgcmVzcGVjdGl2ZWx5LCB1c2luZyB0aGUgYG9wdGltKClgIHByb2NlZHVyZS4gWypIaW50OiBZb3Ugc2hvdWxkIHByb3ZpZGUgZXhwbGljaXQgZXhwcmVzc2lvbnMgZm9yIHRoZSBsb2ctbGlrZWxpaG9vZCBhbmQgZ3JhZGllbnQgZnVuY3Rpb25zIG9mIHRoZSBXZWlidWxsIGRpc3RyaWJ1dGlvbiBwYXJhbWV0ZXJzLipdDQoNCmBgYHtyfQ0KDQp3aW5kZmFybT0gc29ydChjKDUuMiwgIDcuOCwgIDkuMSwgMTEuMywgMTIuNSwgMTMuMCwgMTQuMiwgMTUuMSwgMTUuOSwgMTYuNywgMTcuMiwgMTcuOCwgMTguNCwgMTguOSwgDQogIDE5LjMsIDE5LjcsIDIwLjIsIDIwLjYsIDIxLjAsIDIxLjUsIDIxLjksIDIyLjMsIDIyLjcsIDIzLjEsIDIzLjUsIDIzLjksIDI0LjMsIDI0LjcsIA0KICAyNS4xLCAyNS41LCAyNS45LCAyNi4zLCAyNi43LCAyNy4xLCAyNy41LCAyNy45LCAyOC4zLCAyOC43LCAyOS4xLCAyOS41LCAyOS45LCAzMC4zLCANCiAgMzAuNywgMzEuMSwgMzEuNSwgMzEuOSwgMzIuMywgMzIuNywgMzMuMSwgMzMuNSwgMzMuOSwgMzQuMywgMzQuNywgMzUuMSwgMzUuNSwgMzUuOSwgDQogIDM2LjMsIDM2LjcsIDM3LjEsIDM3LjUsIDM3LjksIDM4LjMsIDM4LjcsIDM5LjEsIDM5LjUsIDM5LjksIDQwLjMsIDQwLjcsIDQxLjEsIDQxLjUsDQogIDQxLjksIDQyLjMsIDQyLjcsIDQzLjEsIDQzLjUpKQ0KDQoNCm4gPSBsZW5ndGgod2luZGZhcm0pDQoNCg0KYGBgDQoNCg0KYGBge3J9DQojaGVyZSB3ZSBkZWZpbmUgdGhlIHdlaWJ1bGwgbG9nIGxpa2VsaWhvb2QgZnVuY3Rpb24NCiMNCndlaWJ1bGxfbG9nbGlrID0gZnVuY3Rpb24ocGFyYW1zLCBkYXRhKSAjd2VpbGJ1bGwgZGlzdHJpYnV0aW9uIHBhcmFtZXRlcnM6IGJldGEgKHNoYXBlKSwgYWxwaGEgKHNjYWxlKQ0Kew0KICBzdW0oZHdlaWJ1bGwoZGF0YSwgc2hhcGUgPSBwYXJhbXNbMV0sICNiZXRhIHNoYXBlIHBhcmFtZXRlcg0KICAgICAgICAgICAgICAgICAgICAgIHNjYWxlID0gcGFyYW1zWzJdLCAjbGFtYmRhIHNjYWxlIHBhcmFtZXRlcg0KICAgICAgICAgICAgICAgICAgICAgIGxvZyA9IFRSVUUgICAgICAgICAjd3JpdGUgdGhlIGxvZyBsaWtlbGlob29kIG9mIHRoZSB3ZWlidWxsIGRpc3RyaWJ1dGlvbg0KICAgICAgICAgICAgICAgICkpDQogIA0KICANCn0NCg0KDQojRmluZGluZyB0aGUgTUxFcyB1c2luZyBvcHRpbSgpDQogICN1c2UgbWVhbiBvZiBkYXRhIGFzIHJlZmVyZW5jZQ0KDQptbGVfd2VpYnVsbCA9IG9wdGltKHBhciA9IGMoMSwgbWVhbih3aW5kZmFybSkpLA0KICAgICAgICAgICAgICAgICAgICBmbiA9IHdlaWJ1bGxfbG9nbGlrLCAjIG1pbmltaXplcyBmdW5jdGlvbg0KICAgICAgICAgICAgICAgICAgICBkYXRhPSB3aW5kZmFybSwNCiAgICAgICAgICAgICAgICAgICAgY29udHJvbCA9IGxpc3QoZm5zY2FsZT0gLTEpICMtMSBmb3IgbWF4aW1pemF0aW9uDQogICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICApDQoNCmhhdF9iZXRhID0gbWxlX3dlaWJ1bGwkcGFyWzFdDQpoYXRfbGFtYmRhID0gbWxlX3dlaWJ1bGwkcGFyWzJdDQpsb2dMMV9vYnMgPSBtbGVfd2VpYnVsbCR2YWx1ZQ0KDQoNCmNhdCgiV2VpYnVsbCBNTEVzIFNoYXBlIChCZXRhKToiLCBoYXRfYmV0YSwgIlNjYWxlIChMYW1iZGEpOiIsIGhhdF9sYW1iZGEpDQoNCmBgYA0KDQoNCg0KDQpiKS4gRmluZCB0aGUgTUxFIG9mIHRoZSBleHBvbmVudGlhbCBwYXJhbWV0ZXIgJFxsYW1iZGEkIChzY2FsZSksIGRlbm90ZWQgYnkgJFxoYXR7XGxhbWJkYX0kLCB1c2luZyBhbnkgcHJvY2VkdXJlLiBbKkhpbnQ6IFlvdSBzaG91bGQgcHJvdmlkZSBleHBsaWNpdCBleHByZXNzaW9ucyBmb3IgdGhlIGxvZy1saWtlbGlob29kIGFuZCBncmFkaWVudCBmdW5jdGlvbnMgb2YgdGhlIGV4cG9uZW50aWFsIGRpc3RyaWJ1dGlvbiBwYXJhbWV0ZXJzLipdDQoNCmBgYHtyfQ0KDQpleHBfbG9nbGlrID0gZnVuY3Rpb24obGFtYmRhLCBkYXRhKSAjZXhwb25ldGlhbCBkaXN0cnVidXRpb24gcGFyYW1ldGVyczogbGFtYmRhDQp7DQogIHN1bShkZXhwKGRhdGEsIHJhdGU9IDEvbGFtYmRhICwgI3NvbHZlIGZvciByYXRlIHdpdGggbGFtYmRhIHBhcmFtZXRlcg0KICAgICAgICAgICAgICAgICAgICAgIGxvZyA9IFRSVUUgI3dyaXRlIHRoZSBsb2cgbGlrZWxpaG9vZCBvZiB0aGUgZXhwb25lbnRpYWwgZGlzdHJpYnV0aW9uDQogICAgICAgICAgICAgICAgKSkNCiAgDQogIA0KfQ0KDQoNCiNGaW5kaW5nIHRoZSBNTEVzIHVzaW5nIG9wdGltKCkNCiAgI3VzZSBtZWFuIG9mIGRhdGEgYXMgcmVmZXJlbmNlDQoNCm1sZV9leHAgPSBvcHRpbShwYXIgPSBjKG1lYW4od2luZGZhcm0pKSwgI2ludGlhbCBndWVzcyBzdGFydGluZyBwb2ludCBmb3IgbGFtYmRhDQogICAgICAgICAgICAgICAgICAgIGZuID0gZXhwX2xvZ2xpaywgIyBtaW5pbWl6ZXMgZnVuY3Rpb24NCiAgICAgICAgICAgICAgICAgICAgZGF0YT0gd2luZGZhcm0sDQogICAgICAgICAgICAgICAgICAgIA0KICAgICAgICAgICAgICAgICAgICBjb250cm9sID0gbGlzdChmbnNjYWxlPSAtMSkgIy0xIGZvciBtYXhpbWl6YXRpb24NCiAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgICkNCg0KDQoNCmhhdF9sYW1iZGFfZXhwID0gbWxlX2V4cCRwYXINCmxvZ2xpa2VfZXhwX251bGwgPSBtbGVfZXhwJHZhbHVlDQoNCg0KY2F0KCJFeHBvbmV0aWFsIE1MRXMgU2NhbGUgKExhbWJkYSk6IiwgaGF0X2xhbWJkYV9leHAsIA0KICAgICJNYXggTG9nLUxpa2VsaWhvb2QgKE51bGwpOiIsIGxvZ2xpa2VfZXhwX251bGwpDQpgYGANCg0KDQoNCmMpLiBVc2UgYSkgYW5kIGIpIHRvIHBlcmZvcm0gdGhlIHJlZ3VsYXIgbGlrZWxpaG9vZCByYXRpbyAkXGNoaV4yJCB0ZXN0IGZvciAkXGJldGEgPSAxJCBhbmQgcmVwb3J0IHRoZSBwLXZhbHVlLg0KDQoNCmBgYHtyfQ0KDQojQ2FsY3VsYXRpbmcgdGhlIHAgdmFsdWUNCg0KICAjRmluZCB0aGUgZGlmZmVyZW5jZSBvZiB0aGUgZnJvbSBsb3dlciBwZWFrIG9yIGhpZ2hlciBwZWFrDQoNCkxSX29icyA9IC0yICoobG9nbGlrZV9leHBfbnVsbCAtIGxvZ0wxX29icykgI2xpa2VsaWhvb2RfcmF0aW9fdGVzdA0KDQojQ2FsYyBwIHZhbHVlIHcvIGNoaXNxdWFyZSBkaXN0cnVidXRpb24gdy8gMSBkZWdyZWUgb2YgZnJlZWRvbQ0KcF92YWxfY2hpMj0gMS1wY2hpc3EoTFJfb2JzLDEpICNwX3ZhbCA9MS1wY2hpc3EobGlrZWxpaG9vZF9yYXRpb190ZXN0LDEpDQogIA0KICANCmNhdCgiTGlrZWxpaG9vZCBSYXRpbyBTdGF0aXN0aWMgKE9ic2VydmVkKToiLCBMUl9vYnMsIA0KICAgICJcbkNoaS1TcXVhcmUgUC12YWx1ZToiLCBwX3ZhbF9jaGkyKQ0KDQpgYGANCg0KDQoNCg0KZCkuIFVzZSB0aGUgQkxSVCBhbGdvcml0aG0gdG8gcGVyZm9ybSBhIGJvb3RzdHJhcCBsaWtlbGlob29kIHJhdGlvIHRlc3QgYW5kIHJlcG9ydCB0aGUgYm9vdHN0cmFwIHAtdmFsdWUuIE5vdGUgdGhhdCB5b3UgYXJlIGV4cGVjdGVkIHRvIHRyYW5zbGF0ZSB0aGUgQkxSVCBhbGdvcml0aG0gaW50byBSIGNvZGUgdG8gcGVyZm9ybSB0aGUgQkxSVC4gWypIaW50OiBUaGUgY2hpLXNxdWFyZSBkaXN0cmlidXRpb24gc2hvdWxkIG5vdCBiZSB1c2VkIGluIHRoaXMgcGFydCBvZiB0aGUgYW5hbHlzaXMuKl0NCioqQWxnb3JpdGhtKioNCg0KDQpgYGB7cn0NCg0KDQp3aW5kZmFybT0gc29ydChjKDUuMiwgIDcuOCwgIDkuMSwgMTEuMywgMTIuNSwgMTMuMCwgMTQuMiwgMTUuMSwgMTUuOSwgMTYuNywgMTcuMiwgMTcuOCwgMTguNCwgMTguOSwgDQogIDE5LjMsIDE5LjcsIDIwLjIsIDIwLjYsIDIxLjAsIDIxLjUsIDIxLjksIDIyLjMsIDIyLjcsIDIzLjEsIDIzLjUsIDIzLjksIDI0LjMsIDI0LjcsIA0KICAyNS4xLCAyNS41LCAyNS45LCAyNi4zLCAyNi43LCAyNy4xLCAyNy41LCAyNy45LCAyOC4zLCAyOC43LCAyOS4xLCAyOS41LCAyOS45LCAzMC4zLCANCiAgMzAuNywgMzEuMSwgMzEuNSwgMzEuOSwgMzIuMywgMzIuNywgMzMuMSwgMzMuNSwgMzMuOSwgMzQuMywgMzQuNywgMzUuMSwgMzUuNSwgMzUuOSwgDQogIDM2LjMsIDM2LjcsIDM3LjEsIDM3LjUsIDM3LjksIDM4LjMsIDM4LjcsIDM5LjEsIDM5LjUsIDM5LjksIDQwLjMsIDQwLjcsIDQxLjEsIDQxLjUsDQogIDQxLjksIDQyLjMsIDQyLjcsIDQzLjEsIDQzLjUpKQ0KDQpCID0gOTk5OQ0KbiA9IGxlbmd0aCh3aW5kZmFybSkNCg0KI2ZpbmRpbmcgd2VpbGJ1aWwgTUxFcw0KI3VzaW5nIE1MRXMgZm91bmQgaW4gZWFybGllciBzZWN0aW9ucyANCg0KTFJfb2JzID0gLTIgKiAobG9nbGlrZV9leHBfbnVsbCAtIGxvZ0wxX29icykgI2ZpbmQgbG9nIGxpa2Vob29kIHJhdGlvIGZvciBvYnNlcnZlZCB2YWx1ZXMgYW5kIGZvcmNlIGludG8gYSBjaGkgc3F1YXJlIGRpc3RydWJ1dGlvbg0KDQp3ZWlidWxsX2xvZ2xpayA9IGZ1bmN0aW9uKHBhcmFtcywgZGF0YSkgew0KICBzdW0oZHdlaWJ1bGwoZGF0YSwgc2hhcGUgPSBwYXJhbXNbMV0sIHNjYWxlID0gcGFyYW1zWzJdLCBsb2cgPSBUUlVFKSkNCn0NCiMjIyMjIyMjIyMjIyMjIyNCb290c3RyYXAgQnVpbGRpbmcjIyMzMzMNCmJvb3RfbHJ0PSBmdW5jdGlvbihkYXRhLCBoYXRfbGFtYmRhX2V4cCwgQj1CKXsgIA0KICANCiAgICBuID0gbGVuZ3RoKGRhdGEpDQogICAgTFJfc3RhciA9IG51bWVyaWMoQikgI2Jvb3RzdHJhcCB0aGUgbG9nIGxpa2VsaWhvb2QgcmF0aW8NCiAgICANCiAgICANCiAgICANCiAgICAjIEJvb3RzdHJhcCBkaXN0cmlidXRpb24NCiAgICBMUl9zdGFyIDwtIG51bWVyaWMoQikNCiAgICBmb3IgKGIgaW4gMTpCKSB7DQogICAgDQogICAgI2Jvb3RzdHJhcCBzYW1wbGUgdW5kZXIgSE8NCiAgICAgIHpfc3RhciA9IHJleHAobiwgcmF0ZSA9MS9oYXRfbGFtYmRhX2V4cCkNCiAgICANCiAgIyBGaXQgbnVsbCBtb2RlbCAoZXhwb25lbnRpYWwgZGlzdHJpYnV0aW9uKQ0KDQpsb2dsaWtlX251bGxfYm9vdCA9IHN1bShkZXhwKHpfc3RhciwgcmF0ZSA9IDEgLyBtZWFuKHpfc3RhciksIGxvZyA9IFRSVUUpKQ0KICAgICAgDQojRml0IGFsdGVybmF0aXZlICBtb2RlbCAod2VpYnVsbCBkaXN0cmlidXRpb24pDQoNCmZpdF9zdGFyID0gb3B0aW0ocGFyID0gYygxLCBtZWFuKHpfc3RhcikpLCBmbiA9IHdlaWJ1bGxfbG9nbGlrLCAgZGF0YSA9IHpfc3RhciwgY29udHJvbCA9IGxpc3QoZm5zY2FsZSA9IC0xKSkNCg0KbG9nTDFfc3RhciA9IGZpdF9zdGFyJHZhbHVlDQoNCiNDYWxjdWxhdGUgdGhlICdGYWtlJyBib290c3RyYXBwZWQgY29tcGFyaXNvbiBMaWtlbGlob29kIFJhdGlvDQogICAgTFJfc3RhcltiXSA9IC0yICogKGxvZ2xpa2VfbnVsbF9ib290IC0gbG9nTDFfc3RhcikNCiAgICB9DQogIA0KcmV0dXJuKExSX3N0YXIpDQoNCn0NCg0KYm9vdF9yZXN1bHRzID0gYm9vdF9scnQod2luZGZhcm0sIGhhdF9sYW1iZGFfZXhwLCBCID0gQikNCg0KIyBDYWxjdWxhdGluZyB0aGUgcC12YWx1ZToNCiNwX3ZhbF9ib290ID0gKHN1bShib290X3Jlc3VsdHMgPj0gTFJfb2JzKSArIDEpIC8gKGxlbmd0aChib290X3Jlc3VsdHMpICsgMSkNCg0KcF92YWxfYm9vdCA9IChzdW0oYm9vdF9yZXN1bHRzID49IExSX29icykrMSkvIChCKzEpICNudW1iZXIgb2YgYm9vdHN0cmFwcw0KDQoNCg0KDQoNCmNhdCgiQm9vdHN0cmFwIFAtVmFsdWU6IiwgcF92YWxfYm9vdCkNCg0KYGBgDQoNCg0KZSkuIFdyaXRlIGEgc3VtbWFyeSBvZiB0aGUgYWJvdmUgYW5hbHlzZXMgdG8gYWRkcmVzcyB0aGUgZm9sbG93aW5nOg0KDQoqIFdoZXRoZXIgdGhlIHR3byB0ZXN0cyBnZW5lcmF0ZWQgdGhlIHNhbWUgcmVzdWx0cy4NCg0KKiBXaGljaCBtb2RlbCBpcyByZWNvbW1lbmRlZCBmb3IgdGhlIGRhdGEuDQoNCjwvcD4NCiANCiANCkJvdGggaHlwb3RoZXNpcyB0ZXN0aW5nIHJlc3VsdHMgcHJlZm9ybWVkIHdpdGggTUxFIHRlc3RpbmcgYW5kIGJvb3RzdHJhcHBlZCBoeXBvdGhlc2lzIHRlc3RlZCB3ZXJlIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQsIHN1Z2dlc3RpbmcgdGhhdCB0aGUgY29tcGxleCBtb2RlbCwgdGhlIHdlaWJ1bGwgZGlzdHJpYnV0aW9uLCBpcyBtb3JlIHNpZ25pZmljYW50LiBJbiBib3RoIGFwcHJvYWNoZXMsIHRoZSBXZWlidWxsIGRpc3RyaWJ1dGlvbiBkb2VzIGEgYmV0dGVyIGpvYiBhdCBleHBsYWluaW5nIHRoZSBkYXRhIHRoYW4gdGhlIHNpbXBsZXIsIGV4cG9uZW50aWFsIG1vZGVsIC4gSW4gZ2VuZXJhbGl0eSwgYm90aCB0aGUgYm9vdHN0cmFwcGVkIGh5cG90aGVzaXMgdGVzdCBgciBwX3ZhbF9ib290YCBhbmQgdGhlIG5vbi1ib290c3RyYXBwZWQgaHlwb3RoZXNpcyB0ZXN0IGByIHBfdmFsX2NoaTJgIGNvbnZleSB0aGUgc2FtZSBpbmZvcm1hdGlvbi4gDQoNCg0KQ29uc2lkZXJpbmcgdGhlIG1vZGVyYXRlIHNhbXBsZSBzaXplIG9mIDc1IGFuZCBmdXJ0aGVyIHRlc3Rpbmcgd291bGQgYmUgcmVxdWlyZWQgdG8ga25vdyBpZiB0aGVyZSBhcmUgc3Ryb25nIHZpb2xhdGlvbnMgYWdhaW5zdCBkaXN0cmlidXRpb25hbCBhc3N1bXB0aW9ucyBhIGJvb3RzdHJhcCBjb3VsZCBiZSBhIHN0cm9uZyByZWNvbW1lbmRhdGlvbiBvdmVyIHRoZSB0cmFkaXRpb25hbCBoeXBvdGhlc2lzIHRlc3RpbmcuQm9vdHN0cmFwIGh5cG90aGVzaXMgdGVzdGluZyBwcm92aWRlcyByb2J1c3QgYW5hbHlzaXMgZm9yIHNtYWxsIHNhbXBsZSBzaXplcyBhbmQgd2hlbiBkaXN0cmlidXRpb25hbCBhc3N1bXB0aW9ucyBhcmUgdmlvbGF0ZWQuIA0KIEFkZGl0aW9uYWxseSwgd2UgZG8gbm90IG5lZWQgdG8gYXNzdW1lIGEgY2hpIHNxdWFyZSBkaXN0cmlidXRpb24gZm9yIGEgYm9vdHN0cmFwIHVubGlrZSB0aGUgY2hpLXNxdWFyZSBiYXNlZCBsaWtlbGlob29kIHJhdGlvIHN0YXRpc3RpYywgYWxsb3dpbmcgdXMgdG8gbGlrZWx5IGJldHRlciBzdWl0IHRoZSBkYXRhIGZvciBhbmFseXNpcyB0aGFuIGEgcGFyYW1ldHJpYyB0ZXN0LiBVc2UgYSB3ZWlidWxsIGRpc3RyaWJ1dGlvbiB0byAgbW9uaXRvciB0aGUgcmVsaWFiaWxpdHkgb2YgZ2VhcmJveGVzLg0KDQoNCg==