Assignment Objectives

  • Master the fundamental concepts of point estimation and performance metrics

  • Understand the theoretical foundation of the method of moments estimator (MME)

  • Implement MME in R, incorporating numerical approximation methods


Use of AI Tools

Policy on AI Tool Use: Students must 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.


Log-logistic Distribution

The log-logistic distribution (also known as the Fisk distribution) is a continuous probability distribution that is particularly useful in contexts where data exhibit non-negative, skewed behavior and where the hazard rate is unimodal (increases to a peak and then decreases). It has been widely used in the areas such as survival analysis and reliability engineering, environmental science, economics, pharmacology, finance and risk management, etc.

For given shape parameter \(\beta\) and scale parameter \(\alpha\), the cumulative distribution function

\[ F(x) = \frac{1}{1+(x/\alpha)^{-\beta}} \]

As an exercise, you can derive the density in the following form

\[ f(x) = \frac{(\beta/\alpha)(x/\alpha)^{\beta-1}}{[1+(x/\alpha)^\beta]^2}, \ \ \text{ for } \ \ x > 0. \]

After some algebra, we can find the \(k\)th moment

\[ \mu_k = E[X^k] = \alpha^k B\left(1+\frac{k}{\beta}, 1 - \frac{k}{\beta} \right). \]

This assignment will focus on finding MME of parameters \(\alpha\) and \(\beta\) based on a real-world application data set.


Question 1: Derive the log-logistic density function

Given the CDF of the two-parameter log-logistic distribution

\[ F(x) = \frac{1}{1+(x/\alpha)^{-\beta}}. \]

Answer to Question 1

\[ F(x) = \frac{1}{1+(x/\alpha)^{-\beta}}=(1+(x/\alpha)^{-\beta})^{-1}\\\\ F'(x)=f(x)=-(1+(x/\alpha)^{-\beta})^{-2}(-\beta(x/\alpha)^{-\beta-1})(1/\alpha)=\frac{(\alpha/\beta)(x/\alpha)^{-\beta-1}}{(1+(x/\alpha)^{-\beta})^2}\\\\ f(x)=\frac{(\alpha/\beta)(x/\alpha)^{-\beta-1}}{(1+(x/\alpha)^{-\beta})^2}=\frac{((x/\alpha)^\beta)^2}{((x/\alpha)^\beta)^2}\cdot\frac{(\alpha/\beta)(x/\alpha)^{-\beta-1}}{(1+(x/\alpha)^{-\beta})^2}=\frac{(\alpha/\beta)(x/\alpha)^{\beta-1}}{((x/\alpha)^{\beta}+1)^2}\\\\ f(x)=\frac{(\beta/\alpha)(x/\alpha)^{\beta-1}}{[1+(x/\alpha)^\beta]^2}, \ \ \text{ for } \ \ x > 0 \]

Question 2: Distribution of Recovery Time from A Surgery

Time to recovery (in days) after a specific knee surgery procedure. This follows a typical log-logistic pattern in medical survival/recovery analysis:

8.23, 12.74, 14.83, 16.61, 18.16, 19.55, 20.80, 21.94, 23.00, 23.98, 24.89, 25.75, 26.56, 
27.34, 28.08, 28.79, 29.48, 30.15, 30.81, 31.45, 32.08, 32.70, 33.31, 33.92, 34.53, 35.13, 
35.73, 36.33, 36.93, 37.53, 38.14, 38.75, 39.37, 40.00, 40.64, 41.29, 41.95, 42.63, 43.33, 
44.05, 44.79, 45.56, 46.36, 47.20, 48.08, 49.02, 50.03, 51.12, 52.32, 53.65

Based on the above data to perform the following analysis.

  1. Using method of moment estimation to estimate \(\alpha\) and \(\beta\), denoted by \(\hat{\alpha}\) and \(\hat{\beta}\), respectively.

Answer to Question 2 Part A:

Formula for k-th moment: \[ \mu_k = E[X^k] = \alpha^k B\left(1+\frac{k}{\beta}, 1 - \frac{k}{\beta} \right)=\alpha^k\cdot\frac{\Gamma(1+k/\beta)\cdot\Gamma(1-k/\beta)}{\Gamma(1+k/\beta+1-k/\beta)}=\alpha^k\cdot\Gamma(1+k/\beta)\cdot\Gamma(1-k/\beta) \]

First and second population moments:

\[ \mu_1=E[X]=\alpha\cdot\Gamma(1+1/\beta)\cdot\Gamma(1-1/\beta)\\\\ \mu_2=E[X^2]=\alpha^2\cdot\Gamma(1+2/\beta)\cdot\Gamma(1-2/\beta) \]

First and second sample moments:

\[ m_1=\frac{1}{n}\sum_{i=1}^{n} X_i\\\\ m_2=\frac{1}{n}\sum_{i=1}^{n} X_i^2 \]

Method of Moments Equations:

\[ m_1=\alpha\cdot\Gamma(1+1/\beta)\cdot\Gamma(1-1/\beta)\\\\ m_2=\alpha^2\cdot\Gamma(1+2/\beta)\cdot\Gamma(1-2/\beta) \]

Finding equations to solve numerically for \(\alpha\) and \(\beta\):

\[ m_1^2=\alpha^2\cdot(\Gamma(1+1/\beta)\cdot\Gamma(1-1/\beta))^2\\\\ \frac{m_2}{m_1^2}=\frac{\alpha^2\cdot\Gamma(1+2/\beta)\cdot\Gamma(1-2/\beta)}{\alpha^2\cdot(\Gamma(1+1/\beta)\cdot\Gamma(1-1/\beta))^2}=\frac{\Gamma(1+2/\beta)\cdot\Gamma(1-2/\beta)}{(\Gamma(1+1/\beta)\cdot\Gamma(1-1/\beta))^2} \]

Let \(\hat{\beta}\) be the solution to:

\[ \frac{m_2}{m_1^2}=\frac{\Gamma(1+2/\beta)\cdot\Gamma(1-2/\beta)}{(\Gamma(1+1/\beta)\cdot\Gamma(1-1/\beta))^2} \]

Let \(\hat{\alpha}\) be obtained from:

\[ \hat{\alpha}=\frac{m_1}{\Gamma(1+1/\beta)\cdot\Gamma(1-1/\beta)} \]

The parameter \(\beta\) can be solved numerically from the following equation:

\[ g(\beta)=\frac{\Gamma(1+2/\beta)\cdot\Gamma(1-2/\beta)}{(\Gamma(1+1/\beta)\cdot\Gamma(1-1/\beta))^2}-\frac{m_2}{m_1^2}=0 \] Plotting \(g(\beta)\) to identify the interval where the root is located:

#Setting the sample of the recovery time in days (data is above) equal to x.
x <-  c(8.23, 12.74, 14.83, 16.61, 18.16, 19.55, 20.80, 21.94, 23.00, 23.98, 24.89, 25.75, 26.56, 
27.34, 28.08, 28.79, 29.48, 30.15, 30.81, 31.45, 32.08, 32.70, 33.31, 33.92, 34.53, 35.13, 
35.73, 36.33, 36.93, 37.53, 38.14, 38.75, 39.37, 40.00, 40.64, 41.29, 41.95, 42.63, 43.33, 
44.05, 44.79, 45.56, 46.36, 47.20, 48.08, 49.02, 50.03, 51.12, 52.32, 53.65)

#Finding 1st and 2nd moments of sample.
m1 <- mean(x)
m2 <- mean(x^2)

#Allows us to use g(beta) function from above in R (here using b for simplicity)
gb <- function(b){((gamma(1+2/b))*(gamma(1-2/b))/(((gamma(1+1/b))*(gamma(1-1/b)))^2)) - m2/(m1^2)}

#Creating data frame with x values between 4 and 10 and y values calculated from gb based on those x values.
x_vals <- seq(4,10,length.out=50)
dframe <- data.frame(x=x_vals, y=gb(x_vals))

#Creates plot of gb values from dframe with plotted x and y axis.
gb.plot <- ggplot(dframe, aes(x = x, y = y)) +
  geom_line(color="steelblue", size= 1) +
  geom_hline(yintercept = 0, linetype = "dashed", alpha = 0.5) +
  geom_vline(xintercept = 0, linetype = "dashed", alpha = 0.5) +
  labs(title = "The curve of function g(beta)",
       x = "beta",
       y = "g(beta)") +
  theme(plot.title = element_text(hjust = 0.5),
        plot.margin = margin(t = 35, r = 20, l = 30, unit = "pt"))
ggplotly(gb.plot)

The curve above indicates that the root lies in (5,7.5). We can use this to find beta and alpha:

library(stats)
#Using uniroot() to find beta
beta <- uniroot(gb, interval = c(5, 7.5))$root
#Using beta to find alpha from equation determing above.
alpha <- m1/((gamma(1+1/beta))*(gamma(1-1/beta)))
pander(cbind(alpha = alpha, beta = beta))
alpha beta
32.65 6.006

Estimating \(\alpha\) and \(\beta\), denoted by \(\hat{\alpha}\) and \(\hat{\beta}\), respectively, we get the result \(\hat{\alpha}=32.65\) and \(\hat{\beta}=6.006\)

  1. Since the moment estimates \(\hat{\alpha}\) and \(\hat{\beta}\) are random, construct bootstrap sampling distributions for each. To visualize these distributions, plot separate bootstrap histograms for \(\hat{\alpha}\) and \(\hat{\beta}\). hen, overlay a smooth density curve on each histogram using Gaussian kernel density estimation. Finally, describe the patterns of these density curves.

Answer to Question 2 Part B:

set.seed(123) ##Used to set seed so that result can be replicated

optim_mom <- function(data){ #Creates function that can be used later
  m1 <- mean(data)
  m2 <- mean(data^2)
  target <- m2/(m1^2) #Used to get part of objective function
  
  
  objective <- function(k){
    part1 <- gamma(1+2/k)*gamma(1-2/k)
    part2 <- gamma(1+1/k)*gamma(1-1/k)
    (part1/(part2^2)-target)^2    #Objective function to minimize                   
  }
  #Optimizes for k using Brent's Method to get minimized value
  opt <- optimize(objective, interval=c(0.1,10))
  beta_hat <- opt$minimum
  alpha_hat <- m1/((gamma(1+1/beta_hat))*(gamma(1-1/beta_hat)))
  
  return(list(alpha = alpha_hat, beta = beta_hat))
}


n <- length(x) #Sets sample size for bootstrap equal to length of original sample
B <- 1000 #How many times we should bootstrap sample

bootstrap.beta <- numeric(B) #Resets 'bootstrap.beta' 
bootstrap.alpha <- numeric(B) #Resets 'bootstrap.alpha'



for (i in 1:B){
  boot.sample <- sample(x, size=n, replace=TRUE)
  result <- optim_mom(boot.sample) #Uses function created above and stores results in 'result'
  bootstrap.beta[i] <- result$beta
  bootstrap.alpha[i] <- result$alpha
  #Used to randomly sample (with replacement) from 'x' 'B' times to get sample beta-hats and alpha-hats
}

hist(bootstrap.alpha, prob=TRUE, #Creates histogram of bootstrap alpha-hats
     main = "Bootstrap Distribution of Alpha-Hat",
     xlab = "Alpha-Hats")
lines(density(bootstrap.alpha, kernel = "gaussian", bw=1), col="steelblue", lwd=2) #Creates density curve usin Guassian kernel

hist(bootstrap.beta, prob=TRUE, #Creates histogram of bootstrap beta-hats
     main = "Bootstrap Distribution of Beta-Hats",
     xlab = "Beta-Hats")
lines(density(bootstrap.beta, kernel = "gaussian", bw=0.2), col="steelblue", lwd=2) #Creates density curve usin Guassian kernel

The histogram for the bootstrap \(\hat{\alpha}\)’s is centered somewhere between 32 and 34 (which makes sense given that the \(\hat{\alpha}\) for the sample was 32.65). The density curve for this histogram appears to follow a symmetric distribution. Alternatively, the histogram for the bootstrap \(\hat{\beta}\) is centered around 6 (which again makes sense given that the \(\hat{\beta}\) for the sample was 6.006). The density curve for this histogram appears to be skewed slightly to the right.

LS0tDQp0aXRsZTogIkFzc2lnbm1lbnQgMzogTWV0aG9kcyBvZiBNb21lbnQgRXN0aW1hdGlvbiINCmF1dGhvcjogIkdyYWNlIExpcHBlcnQiDQpkYXRlOiAiIER1ZTogMi8yNC8yMDI2Ig0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50OiANCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogNA0KICAgIHRvY19mbG9hdDogeWVzDQogICAgbnVtYmVyX3NlY3Rpb25zOiBubw0KICAgIHRvY19jb2xsYXBzZWQ6IHllcw0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIGNvZGVfZG93bmxvYWQ6IHllcw0KICAgIHNtb290aF9zY3JvbGw6IHllcw0KICAgIHRoZW1lOiBsdW1lbg0KICBwZGZfZG9jdW1lbnQ6IA0KICAgIHRvYzogeWVzDQogICAgdG9jX2RlcHRoOiA0DQogICAgZmlnX2NhcHRpb246IHllcw0KICAgIG51bWJlcl9zZWN0aW9uczogeWVzDQogICAgZmlnX3dpZHRoOiAzDQogICAgZmlnX2hlaWdodDogMw0KICB3b3JkX2RvY3VtZW50OiANCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogNA0KICAgIGZpZ19jYXB0aW9uOiB5ZXMNCiAgICBrZWVwX21kOiB5ZXMNCmVkaXRvcl9vcHRpb25zOiANCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQ0KLS0tDQoNCmBgYHtjc3MsIGVjaG8gPSBGQUxTRX0NCiNUT0M6OmJlZm9yZSB7DQogIGNvbnRlbnQ6ICJUYWJsZSBvZiBDb250ZW50cyI7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KICBmb250LXNpemU6IDEuMmVtOw0KICBkaXNwbGF5OiBibG9jazsNCiAgY29sb3I6IG5hdnk7DQogIG1hcmdpbi1ib3R0b206IDEwcHg7DQp9DQoNCg0KZGl2I1RPQyBsaSB7ICAgICAvKiB0YWJsZSBvZiBjb250ZW50ICAqLw0KICAgIGxpc3Qtc3R5bGU6dXBwZXItcm9tYW47DQogICAgYmFja2dyb3VuZC1pbWFnZTpub25lOw0KICAgIGJhY2tncm91bmQtcmVwZWF0Om5vbmU7DQogICAgYmFja2dyb3VuZC1wb3NpdGlvbjowOw0KfQ0KDQpoMS50aXRsZSB7ICAgIC8qIGxldmVsIDEgaGVhZGVyIG9mIHRpdGxlICAqLw0KICBmb250LXNpemU6IDIycHg7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KICBjb2xvcjogRGFya1JlZDsNCiAgdGV4dC1hbGlnbjogY2VudGVyOw0KICBmb250LWZhbWlseTogIkdpbGwgU2FucyIsIHNhbnMtc2VyaWY7DQp9DQoNCmg0LmF1dGhvciB7IC8qIEhlYWRlciA0IC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovDQogIGZvbnQtc2l6ZTogMTVweDsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogIGZvbnQtZmFtaWx5OiBzeXN0ZW0tdWk7DQogIGNvbG9yOiBuYXZ5Ow0KICB0ZXh0LWFsaWduOiBjZW50ZXI7DQp9DQoNCmg0LmRhdGUgeyAvKiBIZWFkZXIgNCAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICBmb250LXNpemU6IDE4cHg7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KICBmb250LWZhbWlseTogIkdpbGwgU2FucyIsIHNhbnMtc2VyaWY7DQogIGNvbG9yOiBEYXJrQmx1ZTsNCiAgdGV4dC1hbGlnbjogY2VudGVyOw0KfQ0KDQpoMSB7IC8qIEhlYWRlciAxIC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovDQogICAgZm9udC1zaXplOiAyMHB4Ow0KICAgIGZvbnQtd2VpZ2h0OiBib2xkOw0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBkYXJrcmVkOw0KICAgIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCg0KaDIgeyAvKiBIZWFkZXIgMiAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICAgIGZvbnQtc2l6ZTogMThweDsNCiAgICBmb250LXdlaWdodDogYm9sZDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogbmF2eTsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KDQpoMyB7IC8qIEhlYWRlciAzIC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovDQogICAgZm9udC1zaXplOiAxNnB4Ow0KICAgIGZvbnQtd2VpZ2h0OiBib2xkOw0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBuYXZ5Ow0KICAgIHRleHQtYWxpZ246IGxlZnQ7DQp9DQoNCmg0IHsgLyogSGVhZGVyIDQgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgICBmb250LXNpemU6IDE0cHg7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBkYXJrcmVkOw0KICAgIHRleHQtYWxpZ246IGxlZnQ7DQp9DQoNCi8qIEFkZCBkb3RzIGFmdGVyIG51bWJlcmVkIGhlYWRlcnMgKi8NCi5oZWFkZXItc2VjdGlvbi1udW1iZXI6OmFmdGVyIHsNCiAgY29udGVudDogIi4iOw0KDQpib2R5IHsgYmFja2dyb3VuZC1jb2xvcjp3aGl0ZTsgfQ0KDQouaGlnaGxpZ2h0bWUgeyBiYWNrZ3JvdW5kLWNvbG9yOnllbGxvdzsgfQ0KDQpwIHsgYmFja2dyb3VuZC1jb2xvcjp3aGl0ZTsgfQ0KDQp9DQpgYGANCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQojIGNvZGUgY2h1bmsgc3BlY2lmaWVzIHdoZXRoZXIgdGhlIFIgY29kZSwgd2FybmluZ3MsIGFuZCBvdXRwdXQgDQojIHdpbGwgYmUgaW5jbHVkZWQgaW4gdGhlIG91dHB1dCBmaWxlcy4NCmlmICghcmVxdWlyZSgia25pdHIiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygia25pdHIiKQ0KICAgbGlicmFyeShrbml0cikNCn0NCmlmICghcmVxdWlyZSgicGFuZGVyIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoInBhbmRlciIpDQogICBsaWJyYXJ5KHBhbmRlcikNCn0NCmlmICghcmVxdWlyZSgiZ2dwbG90MiIpKSB7DQogIGluc3RhbGwucGFja2FnZXMoImdncGxvdDIiKQ0KICBsaWJyYXJ5KGdncGxvdDIpDQp9DQppZiAoIXJlcXVpcmUoInRpZHl2ZXJzZSIpKSB7DQogIGluc3RhbGwucGFja2FnZXMoInRpZHl2ZXJzZSIpDQogIGxpYnJhcnkodGlkeXZlcnNlKQ0KfQ0KDQppZiAoIXJlcXVpcmUoInBsb3RseSIpKSB7DQogIGluc3RhbGwucGFja2FnZXMoInBsb3RseSIpDQogIGxpYnJhcnkocGxvdGx5KQ0KfQ0KIyMjIw0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCAgICAgICAjIGluY2x1ZGUgY29kZSBjaHVuayBpbiB0aGUgb3V0cHV0IGZpbGUNCiAgICAgICAgICAgICAgICAgICAgICB3YXJuaW5nID0gRkFMU0UsICAgIyBzb21ldGltZXMsIHlvdSBjb2RlIG1heSBwcm9kdWNlIHdhcm5pbmcgbWVzc2FnZXMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgeW91IGNhbiBjaG9vc2UgdG8gaW5jbHVkZSB0aGUgd2FybmluZyBtZXNzYWdlcyBpbg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHRoZSBvdXRwdXQgZmlsZS4gDQogICAgICAgICAgICAgICAgICAgICAgcmVzdWx0cyA9IFRSVUUsICAgICMgeW91IGNhbiBhbHNvIGRlY2lkZSB3aGV0aGVyIHRvIGluY2x1ZGUgdGhlIG91dHB1dA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGluIHRoZSBvdXRwdXQgZmlsZS4NCiAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlID0gRkFMU0UsDQogICAgICAgICAgICAgICAgICAgICAgY29tbWVudCA9IE5BDQogICAgICAgICAgICAgICAgICAgICAgKSAgDQpgYGANCiANCiBcDQogDQojIyAqKkFzc2lnbm1lbnQgT2JqZWN0aXZlcyoqIA0KDQoqIE1hc3RlciB0aGUgZnVuZGFtZW50YWwgY29uY2VwdHMgb2YgcG9pbnQgZXN0aW1hdGlvbiBhbmQgcGVyZm9ybWFuY2UgbWV0cmljcw0KDQoqIFVuZGVyc3RhbmQgdGhlIHRoZW9yZXRpY2FsIGZvdW5kYXRpb24gb2YgdGhlIG1ldGhvZCBvZiBtb21lbnRzIGVzdGltYXRvciAoTU1FKQ0KDQoqIEltcGxlbWVudCBNTUUgaW4gUiwgaW5jb3Jwb3JhdGluZyBudW1lcmljYWwgYXBwcm94aW1hdGlvbiBtZXRob2RzDQoNClwNCg0KKipVc2Ugb2YgQUkgVG9vbHMqKg0KDQoqKlBvbGljeSBvbiBBSSBUb29sIFVzZSoqOiBTdHVkZW50cyBtdXN0IGFkaGVyZSB0byB0aGUgQUkgdG9vbCBwb2xpY3kgc3BlY2lmaWVkIGluIHRoZSBjb3Vyc2Ugc3lsbGFidXMuIFRoZSBkaXJlY3QgY29weWluZyBvZiBBSS1nZW5lcmF0ZWQgY29udGVudCBpcyBzdHJpY3RseSBwcm9oaWJpdGVkLiBBbGwgc3VibWl0dGVkIHdvcmsgbXVzdCByZWZsZWN0IHlvdXIgb3duIHVuZGVyc3RhbmRpbmc7IHdoZXJlIGV4dGVybmFsIHRvb2xzIGFyZSBjb25zdWx0ZWQsIGNvbnRlbnQgbXVzdCBiZSB0aG9yb3VnaGx5IHJlcGhyYXNlZCBhbmQgc3ludGhlc2l6ZWQgaW4geW91ciBvd24gd29yZHMuDQoNCioqQ29kZSBJbmNsdXNpb24gUmVxdWlyZW1lbnQqKjogQW55IGNvZGUgaW5jbHVkZWQgaW4geW91ciBlc3NheSBtdXN0IGJlIHByb3Blcmx5IGNvbW1lbnRlZCB0byBleHBsYWluIHRoZSBwdXJwb3NlIGFuZC9vciBleHBlY3RlZCBvdXRwdXQgb2Yga2V5IGNvZGUgbGluZXMuIFN1Ym1pdHRpbmcgQUktZ2VuZXJhdGVkIGNvZGUgd2l0aG91dCBtZWFuaW5nZnVsLCBzdHVkZW50LWFkZGVkIGNvbW1lbnRzIHdpbGwgbm90IGJlIGFjY2VwdGVkLg0KDQpcDQoNCioqTG9nLWxvZ2lzdGljIERpc3RyaWJ1dGlvbioqDQoNClRoZSBsb2ctbG9naXN0aWMgZGlzdHJpYnV0aW9uIChhbHNvIGtub3duIGFzIHRoZSBGaXNrIGRpc3RyaWJ1dGlvbikgaXMgYSBjb250aW51b3VzIHByb2JhYmlsaXR5IGRpc3RyaWJ1dGlvbiB0aGF0IGlzIHBhcnRpY3VsYXJseSB1c2VmdWwgaW4gY29udGV4dHMgd2hlcmUgZGF0YSBleGhpYml0IG5vbi1uZWdhdGl2ZSwgc2tld2VkIGJlaGF2aW9yIGFuZCB3aGVyZSB0aGUgaGF6YXJkIHJhdGUgaXMgdW5pbW9kYWwgKGluY3JlYXNlcyB0byBhIHBlYWsgYW5kIHRoZW4gZGVjcmVhc2VzKS4gSXQgaGFzIGJlZW4gd2lkZWx5IHVzZWQgaW4gdGhlIGFyZWFzIHN1Y2ggYXMgc3Vydml2YWwgYW5hbHlzaXMgYW5kIHJlbGlhYmlsaXR5IGVuZ2luZWVyaW5nLCBlbnZpcm9ubWVudGFsIHNjaWVuY2UsIGVjb25vbWljcywgcGhhcm1hY29sb2d5LCBmaW5hbmNlIGFuZCByaXNrIG1hbmFnZW1lbnQsIGV0Yy4gDQoNCkZvciBnaXZlbiBzaGFwZSBwYXJhbWV0ZXIgJFxiZXRhJCBhbmQgc2NhbGUgcGFyYW1ldGVyICRcYWxwaGEkLCB0aGUgY3VtdWxhdGl2ZSBkaXN0cmlidXRpb24gZnVuY3Rpb24NCg0KJCQNCkYoeCkgPSBcZnJhY3sxfXsxKyh4L1xhbHBoYSleey1cYmV0YX19DQokJA0KDQpBcyBhbiBleGVyY2lzZSwgeW91IGNhbiBkZXJpdmUgdGhlIGRlbnNpdHkgaW4gdGhlIGZvbGxvd2luZyBmb3JtDQoNCiQkDQpmKHgpID0gXGZyYWN7KFxiZXRhL1xhbHBoYSkoeC9cYWxwaGEpXntcYmV0YS0xfX17WzErKHgvXGFscGhhKV5cYmV0YV1eMn0sIFwgXCBcdGV4dHsgZm9yIH0gXCBcIHggPiAwLg0KJCQNCg0KQWZ0ZXIgc29tZSBhbGdlYnJhLCB3ZSBjYW4gZmluZCB0aGUgJGskdGggbW9tZW50DQoNCiQkDQpcbXVfayA9IEVbWF5rXSA9IFxhbHBoYV5rIEJcbGVmdCgxK1xmcmFje2t9e1xiZXRhfSwgMSAtIFxmcmFje2t9e1xiZXRhfSBccmlnaHQpLg0KJCQNCg0KVGhpcyBhc3NpZ25tZW50IHdpbGwgZm9jdXMgb24gZmluZGluZyBNTUUgb2YgcGFyYW1ldGVycyAkXGFscGhhJCBhbmQgJFxiZXRhJCBiYXNlZCBvbiBhIHJlYWwtd29ybGQgYXBwbGljYXRpb24gZGF0YSBzZXQuDQoNCg0KXA0KDQojIyAqKlF1ZXN0aW9uIDE6IERlcml2ZSB0aGUgbG9nLWxvZ2lzdGljIGRlbnNpdHkgZnVuY3Rpb24gKioNCg0KR2l2ZW4gdGhlIENERiBvZiB0aGUgdHdvLXBhcmFtZXRlciBsb2ctbG9naXN0aWMgZGlzdHJpYnV0aW9uDQoNCiQkDQpGKHgpID0gXGZyYWN7MX17MSsoeC9cYWxwaGEpXnstXGJldGF9fS4NCiQkDQoNCiMgQW5zd2VyIHRvIFF1ZXN0aW9uIDENCg0KDQokJA0KRih4KSA9IFxmcmFjezF9ezErKHgvXGFscGhhKV57LVxiZXRhfX09KDErKHgvXGFscGhhKV57LVxiZXRhfSleey0xfVxcXFwNCkYnKHgpPWYoeCk9LSgxKyh4L1xhbHBoYSleey1cYmV0YX0pXnstMn0oLVxiZXRhKHgvXGFscGhhKV57LVxiZXRhLTF9KSgxL1xhbHBoYSk9XGZyYWN7KFxhbHBoYS9cYmV0YSkoeC9cYWxwaGEpXnstXGJldGEtMX19eygxKyh4L1xhbHBoYSleey1cYmV0YX0pXjJ9XFxcXA0KZih4KT1cZnJhY3soXGFscGhhL1xiZXRhKSh4L1xhbHBoYSleey1cYmV0YS0xfX17KDErKHgvXGFscGhhKV57LVxiZXRhfSleMn09XGZyYWN7KCh4L1xhbHBoYSleXGJldGEpXjJ9eygoeC9cYWxwaGEpXlxiZXRhKV4yfVxjZG90XGZyYWN7KFxhbHBoYS9cYmV0YSkoeC9cYWxwaGEpXnstXGJldGEtMX19eygxKyh4L1xhbHBoYSleey1cYmV0YX0pXjJ9PVxmcmFjeyhcYWxwaGEvXGJldGEpKHgvXGFscGhhKV57XGJldGEtMX19eygoeC9cYWxwaGEpXntcYmV0YX0rMSleMn1cXFxcDQpmKHgpPVxmcmFjeyhcYmV0YS9cYWxwaGEpKHgvXGFscGhhKV57XGJldGEtMX19e1sxKyh4L1xhbHBoYSleXGJldGFdXjJ9LCBcIFwgXHRleHR7IGZvciB9IFwgXCB4ID4gMA0KJCQNCg0KDQojIyAqKlF1ZXN0aW9uIDI6IERpc3RyaWJ1dGlvbiBvZiBSZWNvdmVyeSBUaW1lIGZyb20gQSBTdXJnZXJ5KioNCg0KVGltZSB0byByZWNvdmVyeSAoaW4gZGF5cykgYWZ0ZXIgYSBzcGVjaWZpYyBrbmVlIHN1cmdlcnkgcHJvY2VkdXJlLiBUaGlzIGZvbGxvd3MgYSB0eXBpY2FsICoqbG9nLWxvZ2lzdGljIHBhdHRlcm4qKiBpbiBtZWRpY2FsIHN1cnZpdmFsL3JlY292ZXJ5IGFuYWx5c2lzOg0KDQpgYGANCjguMjMsIDEyLjc0LCAxNC44MywgMTYuNjEsIDE4LjE2LCAxOS41NSwgMjAuODAsIDIxLjk0LCAyMy4wMCwgMjMuOTgsIDI0Ljg5LCAyNS43NSwgMjYuNTYsIA0KMjcuMzQsIDI4LjA4LCAyOC43OSwgMjkuNDgsIDMwLjE1LCAzMC44MSwgMzEuNDUsIDMyLjA4LCAzMi43MCwgMzMuMzEsIDMzLjkyLCAzNC41MywgMzUuMTMsIA0KMzUuNzMsIDM2LjMzLCAzNi45MywgMzcuNTMsIDM4LjE0LCAzOC43NSwgMzkuMzcsIDQwLjAwLCA0MC42NCwgNDEuMjksIDQxLjk1LCA0Mi42MywgNDMuMzMsIA0KNDQuMDUsIDQ0Ljc5LCA0NS41NiwgNDYuMzYsIDQ3LjIwLCA0OC4wOCwgNDkuMDIsIDUwLjAzLCA1MS4xMiwgNTIuMzIsIDUzLjY1DQpgYGANCkJhc2VkIG9uIHRoZSBhYm92ZSBkYXRhIHRvIHBlcmZvcm0gdGhlIGZvbGxvd2luZyBhbmFseXNpcy4NCg0KYSkgVXNpbmcgbWV0aG9kIG9mIG1vbWVudCBlc3RpbWF0aW9uIHRvIGVzdGltYXRlICRcYWxwaGEkIGFuZCAkXGJldGEkLCBkZW5vdGVkIGJ5ICRcaGF0e1xhbHBoYX0kIGFuZCAkXGhhdHtcYmV0YX0kLCByZXNwZWN0aXZlbHkuDQoNCiMgQW5zd2VyIHRvIFF1ZXN0aW9uIDIgUGFydCBBOg0KDQpGb3JtdWxhIGZvciBrLXRoIG1vbWVudDoNCiQkDQpcbXVfayA9IEVbWF5rXSA9IFxhbHBoYV5rIEJcbGVmdCgxK1xmcmFje2t9e1xiZXRhfSwgMSAtIFxmcmFje2t9e1xiZXRhfSBccmlnaHQpPVxhbHBoYV5rXGNkb3RcZnJhY3tcR2FtbWEoMStrL1xiZXRhKVxjZG90XEdhbW1hKDEtay9cYmV0YSl9e1xHYW1tYSgxK2svXGJldGErMS1rL1xiZXRhKX09XGFscGhhXmtcY2RvdFxHYW1tYSgxK2svXGJldGEpXGNkb3RcR2FtbWEoMS1rL1xiZXRhKQ0KJCQNCg0KRmlyc3QgYW5kIHNlY29uZCBwb3B1bGF0aW9uIG1vbWVudHM6DQoNCiQkDQpcbXVfMT1FW1hdPVxhbHBoYVxjZG90XEdhbW1hKDErMS9cYmV0YSlcY2RvdFxHYW1tYSgxLTEvXGJldGEpXFxcXA0KXG11XzI9RVtYXjJdPVxhbHBoYV4yXGNkb3RcR2FtbWEoMSsyL1xiZXRhKVxjZG90XEdhbW1hKDEtMi9cYmV0YSkNCiQkDQoNCkZpcnN0IGFuZCBzZWNvbmQgc2FtcGxlIG1vbWVudHM6DQoNCiQkDQptXzE9XGZyYWN7MX17bn1cc3VtX3tpPTF9XntufSBYX2lcXFxcDQptXzI9XGZyYWN7MX17bn1cc3VtX3tpPTF9XntufSBYX2leMg0KJCQNCg0KTWV0aG9kIG9mIE1vbWVudHMgRXF1YXRpb25zOg0KDQokJA0KbV8xPVxhbHBoYVxjZG90XEdhbW1hKDErMS9cYmV0YSlcY2RvdFxHYW1tYSgxLTEvXGJldGEpXFxcXA0KbV8yPVxhbHBoYV4yXGNkb3RcR2FtbWEoMSsyL1xiZXRhKVxjZG90XEdhbW1hKDEtMi9cYmV0YSkNCiQkDQoNCkZpbmRpbmcgZXF1YXRpb25zIHRvIHNvbHZlIG51bWVyaWNhbGx5IGZvciAkXGFscGhhJCBhbmQgJFxiZXRhJDoNCg0KJCQNCm1fMV4yPVxhbHBoYV4yXGNkb3QoXEdhbW1hKDErMS9cYmV0YSlcY2RvdFxHYW1tYSgxLTEvXGJldGEpKV4yXFxcXA0KXGZyYWN7bV8yfXttXzFeMn09XGZyYWN7XGFscGhhXjJcY2RvdFxHYW1tYSgxKzIvXGJldGEpXGNkb3RcR2FtbWEoMS0yL1xiZXRhKX17XGFscGhhXjJcY2RvdChcR2FtbWEoMSsxL1xiZXRhKVxjZG90XEdhbW1hKDEtMS9cYmV0YSkpXjJ9PVxmcmFje1xHYW1tYSgxKzIvXGJldGEpXGNkb3RcR2FtbWEoMS0yL1xiZXRhKX17KFxHYW1tYSgxKzEvXGJldGEpXGNkb3RcR2FtbWEoMS0xL1xiZXRhKSleMn0NCiQkDQoNCkxldCAkXGhhdHtcYmV0YX0kIGJlIHRoZSBzb2x1dGlvbiB0bzoNCg0KJCQNClxmcmFje21fMn17bV8xXjJ9PVxmcmFje1xHYW1tYSgxKzIvXGJldGEpXGNkb3RcR2FtbWEoMS0yL1xiZXRhKX17KFxHYW1tYSgxKzEvXGJldGEpXGNkb3RcR2FtbWEoMS0xL1xiZXRhKSleMn0NCiQkDQoNCkxldCAkXGhhdHtcYWxwaGF9JCBiZSBvYnRhaW5lZCBmcm9tOg0KDQokJA0KXGhhdHtcYWxwaGF9PVxmcmFje21fMX17XEdhbW1hKDErMS9cYmV0YSlcY2RvdFxHYW1tYSgxLTEvXGJldGEpfQ0KJCQNCg0KVGhlIHBhcmFtZXRlciAkXGJldGEkIGNhbiBiZSBzb2x2ZWQgbnVtZXJpY2FsbHkgZnJvbSB0aGUgZm9sbG93aW5nIGVxdWF0aW9uOg0KDQokJA0KZyhcYmV0YSk9XGZyYWN7XEdhbW1hKDErMi9cYmV0YSlcY2RvdFxHYW1tYSgxLTIvXGJldGEpfXsoXEdhbW1hKDErMS9cYmV0YSlcY2RvdFxHYW1tYSgxLTEvXGJldGEpKV4yfS1cZnJhY3ttXzJ9e21fMV4yfT0wDQokJA0KUGxvdHRpbmcgJGcoXGJldGEpJCB0byBpZGVudGlmeSB0aGUgaW50ZXJ2YWwgd2hlcmUgdGhlIHJvb3QgaXMgbG9jYXRlZDoNCg0KYGBge3J9DQojU2V0dGluZyB0aGUgc2FtcGxlIG9mIHRoZSByZWNvdmVyeSB0aW1lIGluIGRheXMgKGRhdGEgaXMgYWJvdmUpIGVxdWFsIHRvIHguDQp4IDwtICBjKDguMjMsIDEyLjc0LCAxNC44MywgMTYuNjEsIDE4LjE2LCAxOS41NSwgMjAuODAsIDIxLjk0LCAyMy4wMCwgMjMuOTgsIDI0Ljg5LCAyNS43NSwgMjYuNTYsIA0KMjcuMzQsIDI4LjA4LCAyOC43OSwgMjkuNDgsIDMwLjE1LCAzMC44MSwgMzEuNDUsIDMyLjA4LCAzMi43MCwgMzMuMzEsIDMzLjkyLCAzNC41MywgMzUuMTMsIA0KMzUuNzMsIDM2LjMzLCAzNi45MywgMzcuNTMsIDM4LjE0LCAzOC43NSwgMzkuMzcsIDQwLjAwLCA0MC42NCwgNDEuMjksIDQxLjk1LCA0Mi42MywgNDMuMzMsIA0KNDQuMDUsIDQ0Ljc5LCA0NS41NiwgNDYuMzYsIDQ3LjIwLCA0OC4wOCwgNDkuMDIsIDUwLjAzLCA1MS4xMiwgNTIuMzIsIDUzLjY1KQ0KDQojRmluZGluZyAxc3QgYW5kIDJuZCBtb21lbnRzIG9mIHNhbXBsZS4NCm0xIDwtIG1lYW4oeCkNCm0yIDwtIG1lYW4oeF4yKQ0KDQojQWxsb3dzIHVzIHRvIHVzZSBnKGJldGEpIGZ1bmN0aW9uIGZyb20gYWJvdmUgaW4gUiAoaGVyZSB1c2luZyBiIGZvciBzaW1wbGljaXR5KQ0KZ2IgPC0gZnVuY3Rpb24oYil7KChnYW1tYSgxKzIvYikpKihnYW1tYSgxLTIvYikpLygoKGdhbW1hKDErMS9iKSkqKGdhbW1hKDEtMS9iKSkpXjIpKSAtIG0yLyhtMV4yKX0NCg0KI0NyZWF0aW5nIGRhdGEgZnJhbWUgd2l0aCB4IHZhbHVlcyBiZXR3ZWVuIDQgYW5kIDEwIGFuZCB5IHZhbHVlcyBjYWxjdWxhdGVkIGZyb20gZ2IgYmFzZWQgb24gdGhvc2UgeCB2YWx1ZXMuDQp4X3ZhbHMgPC0gc2VxKDQsMTAsbGVuZ3RoLm91dD01MCkNCmRmcmFtZSA8LSBkYXRhLmZyYW1lKHg9eF92YWxzLCB5PWdiKHhfdmFscykpDQoNCiNDcmVhdGVzIHBsb3Qgb2YgZ2IgdmFsdWVzIGZyb20gZGZyYW1lIHdpdGggcGxvdHRlZCB4IGFuZCB5IGF4aXMuDQpnYi5wbG90IDwtIGdncGxvdChkZnJhbWUsIGFlcyh4ID0geCwgeSA9IHkpKSArDQogIGdlb21fbGluZShjb2xvcj0ic3RlZWxibHVlIiwgc2l6ZT0gMSkgKw0KICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBhbHBoYSA9IDAuNSkgKw0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBhbHBoYSA9IDAuNSkgKw0KICBsYWJzKHRpdGxlID0gIlRoZSBjdXJ2ZSBvZiBmdW5jdGlvbiBnKGJldGEpIiwNCiAgICAgICB4ID0gImJldGEiLA0KICAgICAgIHkgPSAiZyhiZXRhKSIpICsNCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksDQogICAgICAgIHBsb3QubWFyZ2luID0gbWFyZ2luKHQgPSAzNSwgciA9IDIwLCBsID0gMzAsIHVuaXQgPSAicHQiKSkNCmdncGxvdGx5KGdiLnBsb3QpDQpgYGANCg0KVGhlIGN1cnZlIGFib3ZlIGluZGljYXRlcyB0aGF0IHRoZSByb290IGxpZXMgaW4gKDUsNy41KS4gIFdlIGNhbiB1c2UgdGhpcyB0byBmaW5kIGJldGEgYW5kIGFscGhhOg0KDQpgYGB7cn0NCmxpYnJhcnkoc3RhdHMpDQojVXNpbmcgdW5pcm9vdCgpIHRvIGZpbmQgYmV0YQ0KYmV0YSA8LSB1bmlyb290KGdiLCBpbnRlcnZhbCA9IGMoNSwgNy41KSkkcm9vdA0KI1VzaW5nIGJldGEgdG8gZmluZCBhbHBoYSBmcm9tIGVxdWF0aW9uIGRldGVybWluZyBhYm92ZS4NCmFscGhhIDwtIG0xLygoZ2FtbWEoMSsxL2JldGEpKSooZ2FtbWEoMS0xL2JldGEpKSkNCnBhbmRlcihjYmluZChhbHBoYSA9IGFscGhhLCBiZXRhID0gYmV0YSkpDQpgYGANCg0KRXN0aW1hdGluZyAkXGFscGhhJCBhbmQgJFxiZXRhJCwgZGVub3RlZCBieSAkXGhhdHtcYWxwaGF9JCBhbmQgJFxoYXR7XGJldGF9JCwgcmVzcGVjdGl2ZWx5LCB3ZSBnZXQgdGhlIHJlc3VsdCAkXGhhdHtcYWxwaGF9PTMyLjY1JCBhbmQgJFxoYXR7XGJldGF9PTYuMDA2JA0KDQpiKSBTaW5jZSB0aGUgbW9tZW50IGVzdGltYXRlcyAkXGhhdHtcYWxwaGF9JCBhbmQgJFxoYXR7XGJldGF9JCBhcmUgcmFuZG9tLCBjb25zdHJ1Y3QgYm9vdHN0cmFwIHNhbXBsaW5nIGRpc3RyaWJ1dGlvbnMgZm9yIGVhY2guIFRvIHZpc3VhbGl6ZSB0aGVzZSBkaXN0cmlidXRpb25zLCBwbG90IHNlcGFyYXRlIGJvb3RzdHJhcCBoaXN0b2dyYW1zIGZvciAkXGhhdHtcYWxwaGF9JCBhbmQgJFxoYXR7XGJldGF9JC4gIGhlbiwgb3ZlcmxheSBhIHNtb290aCBkZW5zaXR5IGN1cnZlIG9uIGVhY2ggaGlzdG9ncmFtIHVzaW5nIEdhdXNzaWFuIGtlcm5lbCBkZW5zaXR5IGVzdGltYXRpb24uIEZpbmFsbHksIGRlc2NyaWJlIHRoZSBwYXR0ZXJucyBvZiB0aGVzZSBkZW5zaXR5IGN1cnZlcy4NCg0KIyBBbnN3ZXIgdG8gUXVlc3Rpb24gMiBQYXJ0IEI6DQoNCmBgYHtyfQ0Kc2V0LnNlZWQoMTIzKSAjI1VzZWQgdG8gc2V0IHNlZWQgc28gdGhhdCByZXN1bHQgY2FuIGJlIHJlcGxpY2F0ZWQNCg0Kb3B0aW1fbW9tIDwtIGZ1bmN0aW9uKGRhdGEpeyAjQ3JlYXRlcyBmdW5jdGlvbiB0aGF0IGNhbiBiZSB1c2VkIGxhdGVyDQogIG0xIDwtIG1lYW4oZGF0YSkNCiAgbTIgPC0gbWVhbihkYXRhXjIpDQogIHRhcmdldCA8LSBtMi8obTFeMikgI1VzZWQgdG8gZ2V0IHBhcnQgb2Ygb2JqZWN0aXZlIGZ1bmN0aW9uDQogIA0KICANCiAgb2JqZWN0aXZlIDwtIGZ1bmN0aW9uKGspew0KICAgIHBhcnQxIDwtIGdhbW1hKDErMi9rKSpnYW1tYSgxLTIvaykNCiAgICBwYXJ0MiA8LSBnYW1tYSgxKzEvaykqZ2FtbWEoMS0xL2spDQogICAgKHBhcnQxLyhwYXJ0Ml4yKS10YXJnZXQpXjIgICAgI09iamVjdGl2ZSBmdW5jdGlvbiB0byBtaW5pbWl6ZSAgICAgICAgICAgICAgICAgICANCiAgfQ0KICAjT3B0aW1pemVzIGZvciBrIHVzaW5nIEJyZW50J3MgTWV0aG9kIHRvIGdldCBtaW5pbWl6ZWQgdmFsdWUNCiAgb3B0IDwtIG9wdGltaXplKG9iamVjdGl2ZSwgaW50ZXJ2YWw9YygwLjEsMTApKQ0KICBiZXRhX2hhdCA8LSBvcHQkbWluaW11bQ0KICBhbHBoYV9oYXQgPC0gbTEvKChnYW1tYSgxKzEvYmV0YV9oYXQpKSooZ2FtbWEoMS0xL2JldGFfaGF0KSkpDQogIA0KICByZXR1cm4obGlzdChhbHBoYSA9IGFscGhhX2hhdCwgYmV0YSA9IGJldGFfaGF0KSkNCn0NCg0KDQpuIDwtIGxlbmd0aCh4KSAjU2V0cyBzYW1wbGUgc2l6ZSBmb3IgYm9vdHN0cmFwIGVxdWFsIHRvIGxlbmd0aCBvZiBvcmlnaW5hbCBzYW1wbGUNCkIgPC0gMTAwMCAjSG93IG1hbnkgdGltZXMgd2Ugc2hvdWxkIGJvb3RzdHJhcCBzYW1wbGUNCg0KYm9vdHN0cmFwLmJldGEgPC0gbnVtZXJpYyhCKSAjUmVzZXRzICdib290c3RyYXAuYmV0YScgDQpib290c3RyYXAuYWxwaGEgPC0gbnVtZXJpYyhCKSAjUmVzZXRzICdib290c3RyYXAuYWxwaGEnDQoNCg0KDQpmb3IgKGkgaW4gMTpCKXsNCiAgYm9vdC5zYW1wbGUgPC0gc2FtcGxlKHgsIHNpemU9biwgcmVwbGFjZT1UUlVFKQ0KICByZXN1bHQgPC0gb3B0aW1fbW9tKGJvb3Quc2FtcGxlKSAjVXNlcyBmdW5jdGlvbiBjcmVhdGVkIGFib3ZlIGFuZCBzdG9yZXMgcmVzdWx0cyBpbiAncmVzdWx0Jw0KICBib290c3RyYXAuYmV0YVtpXSA8LSByZXN1bHQkYmV0YQ0KICBib290c3RyYXAuYWxwaGFbaV0gPC0gcmVzdWx0JGFscGhhDQogICNVc2VkIHRvIHJhbmRvbWx5IHNhbXBsZSAod2l0aCByZXBsYWNlbWVudCkgZnJvbSAneCcgJ0InIHRpbWVzIHRvIGdldCBzYW1wbGUgYmV0YS1oYXRzIGFuZCBhbHBoYS1oYXRzDQp9DQoNCmhpc3QoYm9vdHN0cmFwLmFscGhhLCBwcm9iPVRSVUUsICNDcmVhdGVzIGhpc3RvZ3JhbSBvZiBib290c3RyYXAgYWxwaGEtaGF0cw0KICAgICBtYWluID0gIkJvb3RzdHJhcCBEaXN0cmlidXRpb24gb2YgQWxwaGEtSGF0IiwNCiAgICAgeGxhYiA9ICJBbHBoYS1IYXRzIikNCmxpbmVzKGRlbnNpdHkoYm9vdHN0cmFwLmFscGhhLCBrZXJuZWwgPSAiZ2F1c3NpYW4iLCBidz0xKSwgY29sPSJzdGVlbGJsdWUiLCBsd2Q9MikgI0NyZWF0ZXMgZGVuc2l0eSBjdXJ2ZSB1c2luIEd1YXNzaWFuIGtlcm5lbA0KDQpoaXN0KGJvb3RzdHJhcC5iZXRhLCBwcm9iPVRSVUUsICNDcmVhdGVzIGhpc3RvZ3JhbSBvZiBib290c3RyYXAgYmV0YS1oYXRzDQogICAgIG1haW4gPSAiQm9vdHN0cmFwIERpc3RyaWJ1dGlvbiBvZiBCZXRhLUhhdHMiLA0KICAgICB4bGFiID0gIkJldGEtSGF0cyIpDQpsaW5lcyhkZW5zaXR5KGJvb3RzdHJhcC5iZXRhLCBrZXJuZWwgPSAiZ2F1c3NpYW4iLCBidz0wLjIpLCBjb2w9InN0ZWVsYmx1ZSIsIGx3ZD0yKSAjQ3JlYXRlcyBkZW5zaXR5IGN1cnZlIHVzaW4gR3Vhc3NpYW4ga2VybmVsDQoNCmBgYA0KDQpUaGUgaGlzdG9ncmFtIGZvciB0aGUgYm9vdHN0cmFwICRcaGF0e1xhbHBoYX0kJ3MgaXMgY2VudGVyZWQgc29tZXdoZXJlIGJldHdlZW4gMzIgYW5kIDM0ICh3aGljaCBtYWtlcyBzZW5zZSBnaXZlbiB0aGF0IHRoZSAkXGhhdHtcYWxwaGF9JCBmb3IgdGhlIHNhbXBsZSB3YXMgMzIuNjUpLiAgVGhlIGRlbnNpdHkgY3VydmUgZm9yIHRoaXMgaGlzdG9ncmFtIGFwcGVhcnMgdG8gZm9sbG93IGEgc3ltbWV0cmljIGRpc3RyaWJ1dGlvbi4gIEFsdGVybmF0aXZlbHksIHRoZSBoaXN0b2dyYW0gZm9yIHRoZSBib290c3RyYXAgJFxoYXR7XGJldGF9JCBpcyBjZW50ZXJlZCBhcm91bmQgNiAod2hpY2ggYWdhaW4gbWFrZXMgc2Vuc2UgZ2l2ZW4gdGhhdCB0aGUgJFxoYXR7XGJldGF9JCBmb3IgdGhlIHNhbXBsZSB3YXMgNi4wMDYpLiAgVGhlIGRlbnNpdHkgY3VydmUgZm9yIHRoaXMgaGlzdG9ncmFtIGFwcGVhcnMgdG8gYmUgc2tld2VkIHNsaWdodGx5IHRvIHRoZSByaWdodC4gIA0KDQoNCg0KDQoNCg0KDQo=