Midterm Exam Objectives

  • Understand the definition and relationship between PDFs and CDFs, including their non-parametric estimators: the empirical distribution function and kernel density estimation (KDE).

  • Estimate sampling distributions using simulation-based methods, specifically the bootstrap.

  • Derive point estimates of parameters using the method of moments and maximum likelihood estimation (MLE).

  • Describe the asymptotic (normal) and bootstrap sampling distributions of maximum likelihood estimators.

  • Apply all the above inferential procedures in a programming environment to perform numerical data analysis.


Policies of Using 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.


Policies of the Midterm Exam

  • This exam must be completed independently. Collaboration with others is not permitted.

  • You may consult class notes and online resources. However, please ensure that your use of AI tools complies with the AI policy established for this course.

  • All work must be submitted by the deadline. Submissions (including partial work) received after the deadline will not be accepted.


Submission Preparation

Since this exam involves derivations, you can use the following approaches to prepare your submission and save time:

  1. Handwrite the derivation on paper and take a photo. From there, you can either use AI tools to convert it into LaTeX code and paste it into RMarkdown, or insert the image directly into your RMarkdown document, following the example shown in class this week.

  2. Prepare the formulas using other non-programmatic editors and take a screenshot to embed the image in your RMarkdown document using knitr::include_graphics.

  3. Compile all handwritten derivations into a single file and submit it as an attachment.

Please follow the same submission procedure as used for the weekly assignments.


Exam Questions

Caution: Please follow the suggested expressions and guided steps to complete the exam. Other approaches, such as transformations that trivialize the problems, will not meet the exam objectives.

Log-normal Distribution

The log-normal distributions have been widely used in many different fields such as finance and economics, engineering and reliability, environmental science, medical and biology etc.

If \(X\) follows a lognormal distribution:

\[ f(x; \mu, \sigma^2) = \frac{1}{x\sqrt{2\pi \sigma^2}} \exp\left[-\frac{(\ln x - \mu)^2}{2\sigma^2}\right], \quad x > 0 \]

where \(\mu \in \mathbb{R}\) is the mean of \(\ln X\) and \(\sigma^2 > 0\) is the variance of \(\ln X\).

Caution: \(\mu\) and \(\sigma^2\) are not population mean and variance of the lognormal distribution!. Instead, we will use \(\mu_{LN}\) and \(\sigma_{LN}^2\) to denote the lognormal mean and variance respectively.

For an i.i.d. random sample \(x_1, x_2, \dots, x_n\):

\[\begin{align*} \ell(\mu, \sigma^2) &= \sum_{i=1}^n \ln f(x_i; \mu, \sigma^2) \\ &= -\frac{n}{2} \ln(2\pi) - \frac{n}{2} \ln \sigma^2 - \sum_{i=1}^n \ln x_i - \frac{1}{2\sigma^2} \sum_{i=1}^n (\ln x_i - \mu)^2 \end{align*}\]

The \(k\)-th moment of log normal distribution given by

\[ \boxed{ \mathbb{E}[X^k] = \exp\left( k\mu + \frac{1}{2} k^2 \sigma^2 \right). } \]

Particularly, the mean of the above lognormal distribution, denoted by \(\mu_{LN}\), is given by

\[ \mu_{LN} = \mathbb{E}[X] = \exp\left( \mu + \frac{1}{2} \sigma^2 \right). \]

Once the parameters were estimated, say \((\overline{\mu}, \overline{\sigma^2})\), we can use the plug-in Principle to estimate the lognormal mean by

\[ \boxed{\overline{\mu_{LN}} = \exp\left( \overline{\mu} + \frac{1}{2} \overline{\sigma^2} \right).} \]

Working Dataset: A reservoir engineer at an oil exploration company has recently drilled 50 new wells in a shale formation. According to geological theory, the size of oil reserves in this type of formation is often modeled using a log-normal distribution. The engineer is responsible for estimating the typical reserve size and quantifying the uncertainty of these estimates for a presentation to senior management. The estimated ultimate recovery (EUR) for the 50 wells, measured in thousands of barrels (Mbbl), is as follows:

17.3, 24.8, 8.2, 31.5, 14.1, 42.7, 11.9, 55.3, 21.4, 9.7, 36.2, 18.6, 63.1, 13.2, 28.9, 
47.5, 19.8, 7.5, 33.4, 52.1, 16.0, 25.9, 38.7, 10.3, 44.2, 22.5, 58.6, 12.8, 30.3, 48.9, 
20.1, 35.4, 15.7, 60.2, 26.7, 41.3, 18.1, 53.8, 23.9, 46.2, 29.4, 37.6, 14.9, 50.5, 32.8, 
19.3, 56.7, 11.2, 39.5, 27.1

This assignment focuses on finding the asymptotic sampling distributions of the MLE \(\hat{\mu}\) and \(\hat{\sigma^2}\) corresponding to \(\mu\) and \(\sigma^2\) based on an environmental study data.


data <- c(
17.3,24.8,8.2,31.5,14.1,42.7,11.9,55.3,21.4,9.7,
36.2,18.6,63.1,13.2,28.9,47.5,19.8,7.5,33.4,52.1,
16.0,25.9,38.7,10.3,44.2,22.5,58.6,12.8,30.3,48.9,
20.1,35.4,15.7,60.2,26.7,41.3,18.1,53.8,23.9,46.2,
29.4,37.6,14.9,50.5,32.8,19.3,56.7,11.2,39.5,27.1
)


length(data)
[1] 50
mean(data)
[1] 30.516

Question 1: Method of Moments Estimation (MME) of \(\mu\) and \(\sigma^2\)

Estimate the parameters \(\mu\) and \(\sigma^2\) (caution: not \(\sigma\)!) from the raw oil reserve data using the given \(k\)-th moment function. Organize your work into three parts:

  1. Derive the system of two equations for the method of moments estimators (MMEs) of \(\mu\) and \(\sigma^2\).
knitr::include_graphics("IMG_6220.jpg")

  1. Derive the closed-form expressions for the MMEs of \(\mu\), \(\sigma^2\), and \(\mu_{LN}\), denoted by \(\widetilde{\mu}\), \(\widetilde{\sigma^2}\), and \(\widetilde{\mu_{LN}}\), respectively.
knitr::include_graphics("IMG_6221.jpg")

  1. Write an R function that outputs the MMEs \(\widetilde{\mu}\), \(\widetilde{\sigma^2}\), and \(\widetilde{\mu_{LN}}\) based on the given data set.
# Function to compute Method of Moments Estimators for a lognormal distribution
mme_lognormal <- function(x){

  # Sample first moment
  x_bar <- mean(x)
  
  # Sample second moment
  x2_bar <- mean(x^2)
  
  # MME of sigma^2
  sigma2_tilde <- log(x2_bar / (x_bar^2))
  
  # MME of mu
  mu_tilde <- log(x_bar) - 0.5 * sigma2_tilde
  
  # MME of lognormal mean
  muLN_tilde <- exp(mu_tilde + 0.5 * sigma2_tilde)
  
  # Return results
  return(list(
    mu_tilde = mu_tilde,
    sigma2_tilde = sigma2_tilde,
    muLN_tilde = muLN_tilde
  ))
}


Question 2: Finding the MLE of \(\mu\) and \(\sigma^2\)

This question involves two parts:

(1). Derive the score functions (i.e., the gradient of the log-likelihood) for the parameters of the log-normal distribution, and set them to zero to obtain the system of score equations. Begin with the full log-likelihood and compute its partial derivatives with respect to \(\mu\) and \(\sigma^2\). [Hint: letting \(\beta = \sigma^2\) may simplify differentiation.]

Assume that \(\{x_1, x_2, \cdots, x_n \} \to \text{ LN }(\mu, \sigma^2)\) with density function given by

\[ \ell(\mu, \sigma^2) = -\frac{n}{2} \ln(2\pi) - n \ln \sigma - \sum_{i=1}^n \ln x_i - \frac{1}{2\sigma^2} \sum_{i=1}^n (\ln x_i - \mu)^2 \]

knitr::include_graphics("IMG_6222.jpg")

(2). Perform some algebra to find the closed form of the MLE of \(\mu\) and \(\sigma^2\), denoted by \(\widehat{\mu}\) and \(\widehat{\sigma^2}\).

knitr::include_graphics("IMG_6224.jpg")

(3). Recall that lognormal population mean (i.e., the first moment) is

\[ \mu_{LN} = \mathbb{E}[X] = \exp\left( \mu + \frac{1}{2} \sigma^2 \right). \]

Using the relationship between variance and the first and second moments, \(\text{Var}(X) = \mathbb{E}[X^2] - \left(\mathbb{E}[X]\right)^2\), we derive the population variance of the lognormal distribution, denoted as \(\sigma_{\text{LN}}^2\). This result will be used in applying the Central Limit Theorem in subsequent questions

knitr::include_graphics("IMG_6225.jpg")


Question 3: Sampling Distribution of Lognormal Sample Mean \(\widehat{\mu_{LN}}\)

We have derived two different estimators of lognormal population mean \(\mu_{LN}\). This Question focuses on the sampling distribution of lognormal sample sample means based on MLE. The following are detailed instructions.

(1). Write an R function to estimate the MLE of \(\mu\) and \(\sigma^2\), denoted by \(\widehat{\mu}\) and \(\widehat{\sigma^2}\) and return the MLE of \(\mu_{LN}\), denoted by \(\widehat{\mu_{LN}}\).

mle_lognormal <- function(x) {
  # Check for positive values
  if(any(x <= 0)) stop("All data must be positive for lognormal MLE")
  
  # 1. Take log of data
  log_x <- log(x)
  
  # 2. Compute MLEs for mu and sigma^2
  mu_hat <- mean(log_x)
  sigma2_hat <- mean((log_x - mu_hat)^2)  # divide by n for MLE, not n-1
  
  # 3. Compute MLE of lognormal mean
  mu_LN_hat <- exp(mu_hat + 0.5 * sigma2_hat)
  
  # Return results as a list
  return(list(mu_hat = mu_hat, sigma2_hat = sigma2_hat, mu_LN_hat = mu_LN_hat))
}

(2). Take 1000 Bootstrap samples from the raw oil data set. For each bootstrap sample, call the above R function to find the bootstrap MLE of \(\mu_{LN}\), denoted by \(\widehat{\mu_{LN}^*}^{(1)}, \widehat{\mu_{LN}^*}^{(2)}, \cdots, \widehat{\mu_{LN}^*}^{(1000)}\).

# Define the MLE function
mle_lognormal <- function(x) {
  if(any(x <= 0)) stop("All data must be positive for lognormal MLE")
  log_x <- log(x)
  mu_hat <- mean(log_x)
  sigma2_hat <- mean((log_x - mu_hat)^2)
  mu_LN_hat <- exp(mu_hat + 0.5 * sigma2_hat)
  return(list(mu_hat = mu_hat, sigma2_hat = sigma2_hat, mu_LN_hat = mu_LN_hat))
}

# Set up bootstrap
set.seed(123)      # reproducibility
B <- 1000          # number of bootstrap samples
n <- length(data)  # sample size
bootstrap_mu_LN <- numeric(B)

# Bootstrap loop
for(b in 1:B){
  boot_sample <- sample(data, size = n, replace = TRUE)
  bootstrap_mu_LN[b] <- mle_lognormal(boot_sample)$mu_LN_hat
}

# Part 2 outputs
head(bootstrap_mu_LN)  # first few bootstrap MLEs
[1] 29.59169 32.56873 31.24326 36.33202 28.26600 27.76990
mean(bootstrap_mu_LN)  # bootstrap mean
[1] 30.89796
sd(bootstrap_mu_LN)    # bootstrap standard deviation
[1] 2.292654

(3). Using kernel density estimation approach to estimate the bootstrap density curves based on the bootstrap MLEs: \(\widehat{\mu_{LN}^*}^{(1)}, \widehat{\mu_{LN}^*}^{(2)}, \cdots, \widehat{\mu_{LN}^*}^{(1000)}\).

# Kernel density estimation for the bootstrap MLEs
dens <- density(bootstrap_mu_LN)

# Plot the bootstrap density
plot(dens, 
     main = expression("Bootstrap KDE of "*hat(mu)[LN]), 
     xlab = expression(hat(mu)[LN]), 
     ylab = "Density", 
     col = "blue", 
     lwd = 2)

# Add rug plot for the bootstrap points
rug(bootstrap_mu_LN, col = "red")

(4). In order to find the asymptotic sampling distribution using the central limit theorem (CLT). That is, when sample size is large,

\[ \bar{X} \to N \left(\mu_{LN}, \frac{\sigma_{LN}}{\sqrt{n}}\right) \]

where \(\mu_{LN}\) and \(\sigma_{LN}\) can be estimated by using the plug-in principle of MLE. Based on the asymptotic sampling distribution of lognormal sample mean \(\bar{X}\), add the asymptotic density curve to the above Bootstrap kernel density curve.

# 1. Compute MLEs from the original data
mle_results <- mle_lognormal(data)
mu_hat <- mle_results$mu_hat
sigma2_hat <- mle_results$sigma2_hat

# Plug-in estimates
mu_LN_hat <- mle_results$mu_LN_hat
sigma_LN_hat <- sqrt((exp(sigma2_hat) - 1) * exp(2*mu_hat + sigma2_hat))

n <- length(data)

# 2. Kernel density estimate of bootstrap MLEs
dens <- density(bootstrap_mu_LN)

# 3. Plot bootstrap KDE
plot(dens, 
     main = expression("Bootstrap KDE with Asymptotic CLT Density"), 
     xlab = expression(hat(mu)[LN]), 
     ylab = "Density", 
     col = "blue", 
     lwd = 2)


# 4. Overlay asymptotic normal density
x_vals <- seq(min(bootstrap_mu_LN), max(bootstrap_mu_LN), length.out = 500)
clt_density <- dnorm(x_vals, mean = mu_LN_hat, sd = sigma_LN_hat / sqrt(n))

lines(x_vals, clt_density, col = "darkgreen", lwd = 2, lty = 2)

# 5. Add legend
legend("topright", legend = c("Bootstrap KDE", "Asymptotic CLT"), 
       col = c("blue", "darkgreen"), lwd = 2, lty = c(1,2))

(5). Write a short summary to compare the two sampling distributions of the sample mean of the lognormal distribution.

The bootstrap sampling distribution is obtained by repeatedly resampling the observed data and recalculating the estimators as this approach approximates the true sampling distribution without relying on theoretical assumptions. Since the underlying lognormal distribution is skewed, the bootstrap distribution may also appear slightly skewed.

The asymptotic sampling distribution is based on the Central Limit Theorem which states that the sample mean approaches a normal distribution as the sample size increases. This approximation assumes that the sample size is sufficiently large and therefore produces a symmetric normal curve.

For this dataset, the two distributions should appear fairly similar, although the bootstrap distribution may show mild right skewness reflecting the skewness of the underlying lognormal data.

Question 4: Extra Bonus Credit

Derive the Hessian matrix by computing the second-order partial derivatives of the log-likelihood function (with respect to \(\mu\) and \(\sigma^2\)). Then, translate the derived Hessian into an R function that takes the MLEs of the parameters and the data as inputs and returns the Hessian matrix. Finally, compare your analytically derived Hessian with the numerical Hessian returned by optim().

LS0tDQp0aXRsZTogIlNUQSA1MDYgLSBNaWR0ZXJtIEV4YW1pbmF0aW9uIg0KYXV0aG9yOiAiU3ByaW5nIDIwMjYgIg0KZGF0ZTogIiBEdWU6IFN1bmRheSwgMDMvMDggYXQgMTE6NTkgUE0iDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6IA0KICAgIHRvYzogeWVzDQogICAgdG9jX2RlcHRoOiA0DQogICAgdG9jX2Zsb2F0OiB5ZXMNCiAgICBudW1iZXJfc2VjdGlvbnM6IG5vDQogICAgdG9jX2NvbGxhcHNlZDogeWVzDQogICAgY29kZV9mb2xkaW5nOiBoaWRlDQogICAgY29kZV9kb3dubG9hZDogeWVzDQogICAgc21vb3RoX3Njcm9sbDogeWVzDQogICAgaGlnaGxpZ2h0OiBtb25vY2hyb21lDQogICAgdGhlbWU6IHNwYWNlbGFiDQogIHBkZl9kb2N1bWVudDogDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDQNCiAgICBmaWdfY2FwdGlvbjogeWVzDQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgICBmaWdfd2lkdGg6IDMNCiAgICBmaWdfaGVpZ2h0OiAzDQogIHdvcmRfZG9jdW1lbnQ6IA0KICAgIHRvYzogeWVzDQogICAgdG9jX2RlcHRoOiA0DQogICAgZmlnX2NhcHRpb246IHllcw0KICAgIGtlZXBfbWQ6IHllcw0KZWRpdG9yX29wdGlvbnM6IA0KICBjaHVua19vdXRwdXRfdHlwZTogaW5saW5lDQotLS0NCg0KYGBge2NzcywgZWNobyA9IEZBTFNFfQ0KI1RPQzo6YmVmb3JlIHsNCiAgY29udGVudDogIlRhYmxlIG9mIENvbnRlbnRzIjsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogIGZvbnQtc2l6ZTogMS4yZW07DQogIGRpc3BsYXk6IGJsb2NrOw0KICBjb2xvcjogbmF2eTsNCiAgbWFyZ2luLWJvdHRvbTogMTBweDsNCn0NCg0KDQpkaXYjVE9DIGxpIHsgICAgIC8qIHRhYmxlIG9mIGNvbnRlbnQgICovDQogICAgbGlzdC1zdHlsZTp1cHBlci1yb21hbjsNCiAgICBiYWNrZ3JvdW5kLWltYWdlOm5vbmU7DQogICAgYmFja2dyb3VuZC1yZXBlYXQ6bm9uZTsNCiAgICBiYWNrZ3JvdW5kLXBvc2l0aW9uOjA7DQp9DQoNCmgxLnRpdGxlIHsgICAgLyogbGV2ZWwgMSBoZWFkZXIgb2YgdGl0bGUgICovDQogIGZvbnQtc2l6ZTogMjJweDsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogIGNvbG9yOiBEYXJrUmVkOw0KICB0ZXh0LWFsaWduOiBjZW50ZXI7DQogIGZvbnQtZmFtaWx5OiAiR2lsbCBTYW5zIiwgc2Fucy1zZXJpZjsNCn0NCg0KaDQuYXV0aG9yIHsgLyogSGVhZGVyIDQgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgZm9udC1zaXplOiAxNXB4Ow0KICBmb250LXdlaWdodDogYm9sZDsNCiAgZm9udC1mYW1pbHk6IHN5c3RlbS11aTsNCiAgY29sb3I6IG5hdnk7DQogIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCg0KaDQuZGF0ZSB7IC8qIEhlYWRlciA0IC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovDQogIGZvbnQtc2l6ZTogMThweDsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogIGZvbnQtZmFtaWx5OiAiR2lsbCBTYW5zIiwgc2Fucy1zZXJpZjsNCiAgY29sb3I6IERhcmtCbHVlOw0KICB0ZXh0LWFsaWduOiBjZW50ZXI7DQp9DQoNCmgxIHsgLyogSGVhZGVyIDEgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgICBmb250LXNpemU6IDIwcHg7DQogICAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IGRhcmtyZWQ7DQogICAgdGV4dC1hbGlnbjogY2VudGVyOw0KfQ0KDQpoMiB7IC8qIEhlYWRlciAyIC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovDQogICAgZm9udC1zaXplOiAxOHB4Ow0KICAgIGZvbnQtd2VpZ2h0OiBib2xkOw0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBuYXZ5Ow0KICAgIHRleHQtYWxpZ246IGxlZnQ7DQp9DQoNCmgzIHsgLyogSGVhZGVyIDMgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgICBmb250LXNpemU6IDE2cHg7DQogICAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IG5hdnk7DQogICAgdGV4dC1hbGlnbjogbGVmdDsNCn0NCg0KaDQgeyAvKiBIZWFkZXIgNCAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICAgIGZvbnQtc2l6ZTogMTRweDsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IGRhcmtyZWQ7DQogICAgdGV4dC1hbGlnbjogbGVmdDsNCn0NCg0KLyogQWRkIGRvdHMgYWZ0ZXIgbnVtYmVyZWQgaGVhZGVycyAqLw0KLmhlYWRlci1zZWN0aW9uLW51bWJlcjo6YWZ0ZXIgew0KICBjb250ZW50OiAiLiI7DQoNCmJvZHkgeyBiYWNrZ3JvdW5kLWNvbG9yOndoaXRlOyB9DQoNCi5oaWdobGlnaHRtZSB7IGJhY2tncm91bmQtY29sb3I6eWVsbG93OyB9DQoNCnAgeyBiYWNrZ3JvdW5kLWNvbG9yOndoaXRlOyB9DQoNCn0NCmBgYA0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCiMgY29kZSBjaHVuayBzcGVjaWZpZXMgd2hldGhlciB0aGUgUiBjb2RlLCB3YXJuaW5ncywgYW5kIG91dHB1dCANCiMgd2lsbCBiZSBpbmNsdWRlZCBpbiB0aGUgb3V0cHV0IGZpbGVzLg0KaWYgKCFyZXF1aXJlKCJrbml0ciIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJrbml0ciIpDQogICBsaWJyYXJ5KGtuaXRyKQ0KfQ0KaWYgKCFyZXF1aXJlKCJwYW5kZXIiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygicGFuZGVyIikNCiAgIGxpYnJhcnkocGFuZGVyKQ0KfQ0KaWYgKCFyZXF1aXJlKCJnZ3Bsb3QyIikpIHsNCiAgaW5zdGFsbC5wYWNrYWdlcygiZ2dwbG90MiIpDQogIGxpYnJhcnkoZ2dwbG90MikNCn0NCmlmICghcmVxdWlyZSgidGlkeXZlcnNlIikpIHsNCiAgaW5zdGFsbC5wYWNrYWdlcygidGlkeXZlcnNlIikNCiAgbGlicmFyeSh0aWR5dmVyc2UpDQp9DQoNCmlmICghcmVxdWlyZSgicGxvdGx5IikpIHsNCiAgaW5zdGFsbC5wYWNrYWdlcygicGxvdGx5IikNCiAgbGlicmFyeShwbG90bHkpDQp9DQojIyMjDQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsICAgICAgICMgaW5jbHVkZSBjb2RlIGNodW5rIGluIHRoZSBvdXRwdXQgZmlsZQ0KICAgICAgICAgICAgICAgICAgICAgIHdhcm5pbmcgPSBGQUxTRSwgICAjIHNvbWV0aW1lcywgeW91IGNvZGUgbWF5IHByb2R1Y2Ugd2FybmluZyBtZXNzYWdlcywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyB5b3UgY2FuIGNob29zZSB0byBpbmNsdWRlIHRoZSB3YXJuaW5nIG1lc3NhZ2VzIGluDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgdGhlIG91dHB1dCBmaWxlLiANCiAgICAgICAgICAgICAgICAgICAgICByZXN1bHRzID0gVFJVRSwgICAgIyB5b3UgY2FuIGFsc28gZGVjaWRlIHdoZXRoZXIgdG8gaW5jbHVkZSB0aGUgb3V0cHV0DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgaW4gdGhlIG91dHB1dCBmaWxlLg0KICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSwNCiAgICAgICAgICAgICAgICAgICAgICBjb21tZW50ID0gTkENCiAgICAgICAgICAgICAgICAgICAgICApICANCmBgYA0KIA0KIFwNCiANCiMgKipNaWR0ZXJtIEV4YW0gT2JqZWN0aXZlcyoqIA0KDQoqIFVuZGVyc3RhbmQgdGhlIGRlZmluaXRpb24gYW5kIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIFBERnMgYW5kIENERnMsIGluY2x1ZGluZyB0aGVpciBub24tcGFyYW1ldHJpYyBlc3RpbWF0b3JzOiB0aGUgZW1waXJpY2FsIGRpc3RyaWJ1dGlvbiBmdW5jdGlvbiBhbmQga2VybmVsIGRlbnNpdHkgZXN0aW1hdGlvbiAoS0RFKS4NCg0KKiBFc3RpbWF0ZSBzYW1wbGluZyBkaXN0cmlidXRpb25zIHVzaW5nIHNpbXVsYXRpb24tYmFzZWQgbWV0aG9kcywgc3BlY2lmaWNhbGx5IHRoZSBib290c3RyYXAuDQoNCiogRGVyaXZlIHBvaW50IGVzdGltYXRlcyBvZiBwYXJhbWV0ZXJzIHVzaW5nIHRoZSBtZXRob2Qgb2YgbW9tZW50cyBhbmQgbWF4aW11bSBsaWtlbGlob29kIGVzdGltYXRpb24gKE1MRSkuDQoNCiogRGVzY3JpYmUgdGhlIGFzeW1wdG90aWMgKG5vcm1hbCkgYW5kIGJvb3RzdHJhcCBzYW1wbGluZyBkaXN0cmlidXRpb25zIG9mIG1heGltdW0gbGlrZWxpaG9vZCBlc3RpbWF0b3JzLg0KDQoqIEFwcGx5IGFsbCB0aGUgYWJvdmUgaW5mZXJlbnRpYWwgcHJvY2VkdXJlcyBpbiBhIHByb2dyYW1taW5nIGVudmlyb25tZW50IHRvIHBlcmZvcm0gbnVtZXJpY2FsIGRhdGEgYW5hbHlzaXMuDQoNClwNCg0KIyAqKlBvbGljaWVzIG9mIFVzaW5nIEFJIFRvb2xzKioNCg0KKiAqKlBvbGljeSBvbiBBSSBUb29sIFVzZSoqOiBTdHVkZW50cyBtdXN0IGFkaGVyZSB0byB0aGUgQUkgdG9vbCBwb2xpY3kgc3BlY2lmaWVkIGluIHRoZSBjb3Vyc2Ugc3lsbGFidXMuIFRoZSBkaXJlY3QgY29weWluZyBvZiBBSS1nZW5lcmF0ZWQgY29udGVudCBpcyBzdHJpY3RseSBwcm9oaWJpdGVkLiBBbGwgc3VibWl0dGVkIHdvcmsgbXVzdCByZWZsZWN0IHlvdXIgb3duIHVuZGVyc3RhbmRpbmc7IHdoZXJlIGV4dGVybmFsIHRvb2xzIGFyZSBjb25zdWx0ZWQsIGNvbnRlbnQgbXVzdCBiZSB0aG9yb3VnaGx5IHJlcGhyYXNlZCBhbmQgc3ludGhlc2l6ZWQgaW4geW91ciBvd24gd29yZHMuDQoNCiogKipDb2RlIEluY2x1c2lvbiBSZXF1aXJlbWVudCoqOiBBbnkgY29kZSBpbmNsdWRlZCBpbiB5b3VyIGVzc2F5IG11c3QgYmUgcHJvcGVybHkgY29tbWVudGVkIHRvIGV4cGxhaW4gdGhlIHB1cnBvc2UgYW5kL29yIGV4cGVjdGVkIG91dHB1dCBvZiBrZXkgY29kZSBsaW5lcy4gU3VibWl0dGluZyBBSS1nZW5lcmF0ZWQgY29kZSB3aXRob3V0IG1lYW5pbmdmdWwsIHN0dWRlbnQtYWRkZWQgY29tbWVudHMgd2lsbCBub3QgYmUgYWNjZXB0ZWQuDQoNClwNCg0KIyAqKlBvbGljaWVzIG9mIHRoZSBNaWR0ZXJtIEV4YW0qKg0KDQoqIFRoaXMgZXhhbSBtdXN0IGJlIGNvbXBsZXRlZCBpbmRlcGVuZGVudGx5LiBDb2xsYWJvcmF0aW9uIHdpdGggb3RoZXJzIGlzIG5vdCBwZXJtaXR0ZWQuDQoNCiogWW91IG1heSBjb25zdWx0IGNsYXNzIG5vdGVzIGFuZCBvbmxpbmUgcmVzb3VyY2VzLiBIb3dldmVyLCBwbGVhc2UgZW5zdXJlIHRoYXQgeW91ciB1c2Ugb2YgQUkgdG9vbHMgY29tcGxpZXMgd2l0aCB0aGUgQUkgcG9saWN5IGVzdGFibGlzaGVkIGZvciB0aGlzIGNvdXJzZS4NCg0KKiBBbGwgd29yayBtdXN0IGJlIHN1Ym1pdHRlZCBieSB0aGUgZGVhZGxpbmUuIFN1Ym1pc3Npb25zIChpbmNsdWRpbmcgcGFydGlhbCB3b3JrKSByZWNlaXZlZCBhZnRlciB0aGUgZGVhZGxpbmUgd2lsbCBub3QgYmUgYWNjZXB0ZWQuDQoNClwNCg0KIyAqKlN1Ym1pc3Npb24gUHJlcGFyYXRpb24qKg0KDQpTaW5jZSB0aGlzIGV4YW0gaW52b2x2ZXMgZGVyaXZhdGlvbnMsIHlvdSBjYW4gdXNlIHRoZSBmb2xsb3dpbmcgYXBwcm9hY2hlcyB0byBwcmVwYXJlIHlvdXIgc3VibWlzc2lvbiBhbmQgc2F2ZSB0aW1lOg0KDQoxLiBIYW5kd3JpdGUgdGhlIGRlcml2YXRpb24gb24gcGFwZXIgYW5kIHRha2UgYSBwaG90by4gRnJvbSB0aGVyZSwgeW91IGNhbiBlaXRoZXIgdXNlIEFJIHRvb2xzIHRvIGNvbnZlcnQgaXQgaW50byBMYVRlWCBjb2RlIGFuZCBwYXN0ZSBpdCBpbnRvIFJNYXJrZG93biwgb3IgaW5zZXJ0IHRoZSBpbWFnZSBkaXJlY3RseSBpbnRvIHlvdXIgUk1hcmtkb3duIGRvY3VtZW50LCBmb2xsb3dpbmcgdGhlIGV4YW1wbGUgc2hvd24gaW4gY2xhc3MgdGhpcyB3ZWVrLg0KDQoyLiBQcmVwYXJlIHRoZSBmb3JtdWxhcyB1c2luZyBvdGhlciBub24tcHJvZ3JhbW1hdGljIGVkaXRvcnMgYW5kIHRha2UgYSBzY3JlZW5zaG90IHRvIGVtYmVkIHRoZSBpbWFnZSBpbiB5b3VyIFJNYXJrZG93biBkb2N1bWVudCB1c2luZyBga25pdHI6OmluY2x1ZGVfZ3JhcGhpY3NgLg0KDQozLiBDb21waWxlIGFsbCBoYW5kd3JpdHRlbiBkZXJpdmF0aW9ucyBpbnRvIGEgc2luZ2xlIGZpbGUgYW5kIHN1Ym1pdCBpdCBhcyBhbiBhdHRhY2htZW50Lg0KDQpQbGVhc2UgZm9sbG93IHRoZSBzYW1lIHN1Ym1pc3Npb24gcHJvY2VkdXJlIGFzIHVzZWQgZm9yIHRoZSB3ZWVrbHkgYXNzaWdubWVudHMuDQoNClwNCg0KIyAqKkV4YW0gUXVlc3Rpb25zKioNCg0KPGZvbnQgY29sb3IgPSAib3JhbmdlIj4qKlxjb2xvcntyZWR9Q2F1dGlvbioqOiAqXGNvbG9ye3JlZH1QbGVhc2UgZm9sbG93IHRoZSBzdWdnZXN0ZWQgZXhwcmVzc2lvbnMgYW5kIGd1aWRlZCBzdGVwcyB0byBjb21wbGV0ZSB0aGUgZXhhbS4gT3RoZXIgYXBwcm9hY2hlcywgc3VjaCBhcyB0cmFuc2Zvcm1hdGlvbnMgdGhhdCB0cml2aWFsaXplIHRoZSBwcm9ibGVtcywgd2lsbCBub3QgbWVldCB0aGUgZXhhbSBvYmplY3RpdmVzLio8L2ZvbnQ+DQoNCiMjICoqTG9nLW5vcm1hbCBEaXN0cmlidXRpb24qKg0KDQpUaGUgbG9nLW5vcm1hbCBkaXN0cmlidXRpb25zIGhhdmUgYmVlbiB3aWRlbHkgdXNlZCBpbiBtYW55IGRpZmZlcmVudCBmaWVsZHMgc3VjaCBhcyBmaW5hbmNlIGFuZCBlY29ub21pY3MsIGVuZ2luZWVyaW5nIGFuZCByZWxpYWJpbGl0eSwgZW52aXJvbm1lbnRhbCBzY2llbmNlLCBtZWRpY2FsIGFuZCBiaW9sb2d5IGV0Yy4gDQoNCklmICRYJCBmb2xsb3dzIGEgbG9nbm9ybWFsIGRpc3RyaWJ1dGlvbjoNCg0KJCQNCmYoeDsgXG11LCBcc2lnbWFeMikgPSBcZnJhY3sxfXt4XHNxcnR7MlxwaSBcc2lnbWFeMn19IA0KXGV4cFxsZWZ0Wy1cZnJhY3soXGxuIHggLSBcbXUpXjJ9ezJcc2lnbWFeMn1ccmlnaHRdLCBccXVhZCB4ID4gMA0KJCQNCg0Kd2hlcmUgICRcbXUgXGluIFxtYXRoYmJ7Un0kIGlzIHRoZSBtZWFuIG9mICRcbG4gWCQgYW5kICRcc2lnbWFeMiA+IDAkIGlzIHRoZSB2YXJpYW5jZSBvZiAkXGxuIFgkLg0KDQo8Zm9udCBjb2xvciA9InJlZCI+KipcY29sb3J7cmVkfUNhdXRpb246KiogKlxjb2xvcntyZWR9JFxtdSQgYW5kICRcc2lnbWFeMiQgYXJlIG5vdCBwb3B1bGF0aW9uIG1lYW4gYW5kIHZhcmlhbmNlIG9mIHRoZSBsb2dub3JtYWwgZGlzdHJpYnV0aW9uISouICoqXGNvbG9ye2JsdWV9IEluc3RlYWQsIHdlIHdpbGwgdXNlICRcbXVfe0xOfSQgYW5kICRcc2lnbWFfe0xOfV4yJCB0byBkZW5vdGUgdGhlIGxvZ25vcm1hbCBtZWFuIGFuZCB2YXJpYW5jZSByZXNwZWN0aXZlbHkuKio8L2ZvbnQ+DQoNCg0KRm9yIGFuIGkuaS5kLiByYW5kb20gc2FtcGxlICR4XzEsIHhfMiwgXGRvdHMsIHhfbiQ6DQoNCg0KXGJlZ2lue2FsaWduKn0NClxlbGwoXG11LCBcc2lnbWFeMikgJj0gXHN1bV97aT0xfV5uIFxsbiBmKHhfaTsgXG11LCBcc2lnbWFeMikgXFwNCiY9IC1cZnJhY3tufXsyfSBcbG4oMlxwaSkgLSBcZnJhY3tufXsyfSBcbG4gXHNpZ21hXjIgLSBcc3VtX3tpPTF9Xm4gXGxuIHhfaSANCiAgIC0gXGZyYWN7MX17MlxzaWdtYV4yfSBcc3VtX3tpPTF9Xm4gKFxsbiB4X2kgLSBcbXUpXjINClxlbmR7YWxpZ24qfQ0KDQoNClRoZSAkayQtdGggbW9tZW50IG9mIGxvZyBub3JtYWwgZGlzdHJpYnV0aW9uIGdpdmVuIGJ5DQoNCiQkDQpcYm94ZWR7IFxtYXRoYmJ7RX1bWF5rXSA9IFxleHBcbGVmdCgga1xtdSArIFxmcmFjezF9ezJ9IGteMiBcc2lnbWFeMiBccmlnaHQpLiB9DQokJA0KDQpQYXJ0aWN1bGFybHksIHRoZSBtZWFuIG9mIHRoZSBhYm92ZSBsb2dub3JtYWwgZGlzdHJpYnV0aW9uLCBkZW5vdGVkIGJ5ICRcbXVfe0xOfSQsIGlzIGdpdmVuIGJ5DQoNCiQkDQpcbXVfe0xOfSA9IFxtYXRoYmJ7RX1bWF0gPSBcZXhwXGxlZnQoIFxtdSArIFxmcmFjezF9ezJ9ICBcc2lnbWFeMiBccmlnaHQpLg0KJCQNCg0KT25jZSB0aGUgcGFyYW1ldGVycyB3ZXJlIGVzdGltYXRlZCwgc2F5ICQoXG92ZXJsaW5le1xtdX0sIFxvdmVybGluZXtcc2lnbWFeMn0pJCwgd2UgY2FuIHVzZSAqKnRoZSBwbHVnLWluIFByaW5jaXBsZSoqIHRvIGVzdGltYXRlIHRoZSBsb2dub3JtYWwgbWVhbiBieQ0KDQokJA0KXGJveGVke1xvdmVybGluZXtcbXVfe0xOfX0gPSAgXGV4cFxsZWZ0KCBcb3ZlcmxpbmV7XG11fSArIFxmcmFjezF9ezJ9ICBcb3ZlcmxpbmV7XHNpZ21hXjJ9IFxyaWdodCkufQ0KJCQNCg0KDQoNCg0KDQoqKldvcmtpbmcgRGF0YXNldCoqOiBBIHJlc2Vydm9pciBlbmdpbmVlciBhdCBhbiBvaWwgZXhwbG9yYXRpb24gY29tcGFueSBoYXMgcmVjZW50bHkgZHJpbGxlZCA1MCBuZXcgd2VsbHMgaW4gYSBzaGFsZSBmb3JtYXRpb24uIEFjY29yZGluZyB0byBnZW9sb2dpY2FsIHRoZW9yeSwgdGhlIHNpemUgb2Ygb2lsIHJlc2VydmVzIGluIHRoaXMgdHlwZSBvZiBmb3JtYXRpb24gaXMgb2Z0ZW4gbW9kZWxlZCB1c2luZyBhIGxvZy1ub3JtYWwgZGlzdHJpYnV0aW9uLiBUaGUgZW5naW5lZXIgaXMgcmVzcG9uc2libGUgZm9yIGVzdGltYXRpbmcgdGhlIHR5cGljYWwgcmVzZXJ2ZSBzaXplIGFuZCBxdWFudGlmeWluZyB0aGUgdW5jZXJ0YWludHkgb2YgdGhlc2UgZXN0aW1hdGVzIGZvciBhIHByZXNlbnRhdGlvbiB0byBzZW5pb3IgbWFuYWdlbWVudC4gVGhlIGVzdGltYXRlZCB1bHRpbWF0ZSByZWNvdmVyeSAoRVVSKSBmb3IgdGhlIDUwIHdlbGxzLCBtZWFzdXJlZCBpbiB0aG91c2FuZHMgb2YgYmFycmVscyAoTWJibCksIGlzIGFzIGZvbGxvd3M6DQoNCmBgYA0KMTcuMywgMjQuOCwgOC4yLCAzMS41LCAxNC4xLCA0Mi43LCAxMS45LCA1NS4zLCAyMS40LCA5LjcsIDM2LjIsIDE4LjYsIDYzLjEsIDEzLjIsIDI4LjksIA0KNDcuNSwgMTkuOCwgNy41LCAzMy40LCA1Mi4xLCAxNi4wLCAyNS45LCAzOC43LCAxMC4zLCA0NC4yLCAyMi41LCA1OC42LCAxMi44LCAzMC4zLCA0OC45LCANCjIwLjEsIDM1LjQsIDE1LjcsIDYwLjIsIDI2LjcsIDQxLjMsIDE4LjEsIDUzLjgsIDIzLjksIDQ2LjIsIDI5LjQsIDM3LjYsIDE0LjksIDUwLjUsIDMyLjgsIA0KMTkuMywgNTYuNywgMTEuMiwgMzkuNSwgMjcuMQ0KYGBgDQoNCg0KPGZvbnQgY29sb3IgPSAiYmx1ZSI+VGhpcyBhc3NpZ25tZW50IGZvY3VzZXMgb24gZmluZGluZyB0aGUgYXN5bXB0b3RpYyBzYW1wbGluZyBkaXN0cmlidXRpb25zIG9mIHRoZSBNTEUgJFxoYXR7XG11fSQgYW5kICRcaGF0e1xzaWdtYV4yfSQgY29ycmVzcG9uZGluZyB0byAkXG11JCBhbmQgJFxzaWdtYV4yJCBiYXNlZCBvbiBhbiBlbnZpcm9ubWVudGFsIHN0dWR5IGRhdGEuPC9mb250Pg0KDQoNClwNCg0KYGBge3J9DQpkYXRhIDwtIGMoDQoxNy4zLDI0LjgsOC4yLDMxLjUsMTQuMSw0Mi43LDExLjksNTUuMywyMS40LDkuNywNCjM2LjIsMTguNiw2My4xLDEzLjIsMjguOSw0Ny41LDE5LjgsNy41LDMzLjQsNTIuMSwNCjE2LjAsMjUuOSwzOC43LDEwLjMsNDQuMiwyMi41LDU4LjYsMTIuOCwzMC4zLDQ4LjksDQoyMC4xLDM1LjQsMTUuNyw2MC4yLDI2LjcsNDEuMywxOC4xLDUzLjgsMjMuOSw0Ni4yLA0KMjkuNCwzNy42LDE0LjksNTAuNSwzMi44LDE5LjMsNTYuNywxMS4yLDM5LjUsMjcuMQ0KKQ0KDQoNCmxlbmd0aChkYXRhKQ0KbWVhbihkYXRhKQ0KYGBgDQoNCiMjICoqUXVlc3Rpb24gMSoqOiBNZXRob2Qgb2YgTW9tZW50cyBFc3RpbWF0aW9uIChNTUUpIG9mICRcbXUkIGFuZCAkXHNpZ21hXjIkDQoNCkVzdGltYXRlIHRoZSBwYXJhbWV0ZXJzICRcbXUkIGFuZCAkXHNpZ21hXjIkICg8Zm9udCBjb2xvcj0icmVkIj4qXGNvbG9ye3JlZH1jYXV0aW9uOiBub3QgJFxzaWdtYSQhKjwvZm9udD4pIGZyb20gdGhlIHJhdyBvaWwgcmVzZXJ2ZSBkYXRhIHVzaW5nIHRoZSBnaXZlbiAkayQtdGggbW9tZW50IGZ1bmN0aW9uLiBPcmdhbml6ZSB5b3VyIHdvcmsgaW50byB0aHJlZSBwYXJ0czoNCg0KKGEpIERlcml2ZSB0aGUgc3lzdGVtIG9mIHR3byBlcXVhdGlvbnMgZm9yIHRoZSBtZXRob2Qgb2YgbW9tZW50cyBlc3RpbWF0b3JzIChNTUVzKSBvZiAkXG11JCBhbmQgJFxzaWdtYV4yJC4NCg0KYGBge3J9DQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiSU1HXzYyMjAuanBnIikNCmBgYA0KDQooYikgRGVyaXZlIHRoZSBjbG9zZWQtZm9ybSBleHByZXNzaW9ucyBmb3IgdGhlIE1NRXMgb2YgJFxtdSQsICRcc2lnbWFeMiQsIGFuZCAkXG11X3tMTn0kLCBkZW5vdGVkIGJ5ICRcd2lkZXRpbGRle1xtdX0kLCAkXHdpZGV0aWxkZXtcc2lnbWFeMn0kLCBhbmQgJFx3aWRldGlsZGV7XG11X3tMTn19JCwgcmVzcGVjdGl2ZWx5Lg0KDQpgYGB7cn0NCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJJTUdfNjIyMS5qcGciKQ0KYGBgDQoNCihjKSBXcml0ZSBhbiBSIGZ1bmN0aW9uIHRoYXQgb3V0cHV0cyB0aGUgTU1FcyAkXHdpZGV0aWxkZXtcbXV9JCwgJFx3aWRldGlsZGV7XHNpZ21hXjJ9JCwgYW5kICRcd2lkZXRpbGRle1xtdV97TE59fSQgYmFzZWQgb24gdGhlIGdpdmVuIGRhdGEgc2V0Lg0KDQpgYGB7cn0NCiMgRnVuY3Rpb24gdG8gY29tcHV0ZSBNZXRob2Qgb2YgTW9tZW50cyBFc3RpbWF0b3JzIGZvciBhIGxvZ25vcm1hbCBkaXN0cmlidXRpb24NCm1tZV9sb2dub3JtYWwgPC0gZnVuY3Rpb24oeCl7DQoNCiAgIyBTYW1wbGUgZmlyc3QgbW9tZW50DQogIHhfYmFyIDwtIG1lYW4oeCkNCiAgDQogICMgU2FtcGxlIHNlY29uZCBtb21lbnQNCiAgeDJfYmFyIDwtIG1lYW4oeF4yKQ0KICANCiAgIyBNTUUgb2Ygc2lnbWFeMg0KICBzaWdtYTJfdGlsZGUgPC0gbG9nKHgyX2JhciAvICh4X2Jhcl4yKSkNCiAgDQogICMgTU1FIG9mIG11DQogIG11X3RpbGRlIDwtIGxvZyh4X2JhcikgLSAwLjUgKiBzaWdtYTJfdGlsZGUNCiAgDQogICMgTU1FIG9mIGxvZ25vcm1hbCBtZWFuDQogIG11TE5fdGlsZGUgPC0gZXhwKG11X3RpbGRlICsgMC41ICogc2lnbWEyX3RpbGRlKQ0KICANCiAgIyBSZXR1cm4gcmVzdWx0cw0KICByZXR1cm4obGlzdCgNCiAgICBtdV90aWxkZSA9IG11X3RpbGRlLA0KICAgIHNpZ21hMl90aWxkZSA9IHNpZ21hMl90aWxkZSwNCiAgICBtdUxOX3RpbGRlID0gbXVMTl90aWxkZQ0KICApKQ0KfQ0KYGBgIA0KDQpcDQoNCg0KIyMgKipRdWVzdGlvbiAyKio6IEZpbmRpbmcgdGhlIE1MRSBvZiAkXG11JCBhbmQgJFxzaWdtYV4yJA0KDQpUaGlzIHF1ZXN0aW9uIGludm9sdmVzIHR3byBwYXJ0czoNCg0KKDEpLiBEZXJpdmUgdGhlIHNjb3JlIGZ1bmN0aW9ucyAoaS5lLiwgdGhlIGdyYWRpZW50IG9mIHRoZSBsb2ctbGlrZWxpaG9vZCkgZm9yIHRoZSBwYXJhbWV0ZXJzIG9mIHRoZSBsb2ctbm9ybWFsIGRpc3RyaWJ1dGlvbiwgYW5kIHNldCB0aGVtIHRvIHplcm8gdG8gb2J0YWluIHRoZSBzeXN0ZW0gb2Ygc2NvcmUgZXF1YXRpb25zLiBCZWdpbiB3aXRoIHRoZSBmdWxsIGxvZy1saWtlbGlob29kIGFuZCBjb21wdXRlIGl0cyBwYXJ0aWFsIGRlcml2YXRpdmVzIHdpdGggcmVzcGVjdCB0byAkXG11JCBhbmQgJFxzaWdtYV4yJC4gW0hpbnQ6IGxldHRpbmcgJFxiZXRhID0gXHNpZ21hXjIkIG1heSBzaW1wbGlmeSBkaWZmZXJlbnRpYXRpb24uXQ0KDQpBc3N1bWUgdGhhdCAkXHt4XzEsIHhfMiwgXGNkb3RzLCB4X24gXH0gXHRvIFx0ZXh0eyBMTiB9KFxtdSwgXHNpZ21hXjIpJCB3aXRoIGRlbnNpdHkgZnVuY3Rpb24gZ2l2ZW4gYnkNCg0KJCQNClxlbGwoXG11LCBcc2lnbWFeMikgPSAtXGZyYWN7bn17Mn0gXGxuKDJccGkpIC0gbiBcbG4gXHNpZ21hIC0gXHN1bV97aT0xfV5uIFxsbiB4X2kgDQogICAtIFxmcmFjezF9ezJcc2lnbWFeMn0gXHN1bV97aT0xfV5uIChcbG4geF9pIC0gXG11KV4yDQokJA0KDQpgYGB7cn0NCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJJTUdfNjIyMi5qcGciKQ0KYGBgDQoNCigyKS4gUGVyZm9ybSBzb21lIGFsZ2VicmEgdG8gZmluZCB0aGUgY2xvc2VkIGZvcm0gb2YgdGhlIE1MRSBvZiAkXG11JCBhbmQgJFxzaWdtYV4yJCwgZGVub3RlZCBieSAkXHdpZGVoYXR7XG11fSQgYW5kICRcd2lkZWhhdHtcc2lnbWFeMn0kLg0KDQpgYGB7cn0NCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJJTUdfNjIyNC5qcGciKQ0KYGBgDQoNCigzKS4gUmVjYWxsIHRoYXQgbG9nbm9ybWFsIHBvcHVsYXRpb24gbWVhbiAoaS5lLiwgdGhlIGZpcnN0IG1vbWVudCkgaXMgDQoNCiQkDQpcbXVfe0xOfSA9IFxtYXRoYmJ7RX1bWF0gPSBcZXhwXGxlZnQoIFxtdSArIFxmcmFjezF9ezJ9ICBcc2lnbWFeMiBccmlnaHQpLg0KJCQNCg0KVXNpbmcgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHZhcmlhbmNlIGFuZCB0aGUgZmlyc3QgYW5kIHNlY29uZCBtb21lbnRzLCAkXHRleHR7VmFyfShYKSA9IFxtYXRoYmJ7RX1bWF4yXSAtIFxsZWZ0KFxtYXRoYmJ7RX1bWF1ccmlnaHQpXjIkLCB3ZSBkZXJpdmUgdGhlIHBvcHVsYXRpb24gdmFyaWFuY2Ugb2YgdGhlIGxvZ25vcm1hbCBkaXN0cmlidXRpb24sIGRlbm90ZWQgYXMgJFxzaWdtYV97XHRleHR7TE59fV4yJC4gVGhpcyByZXN1bHQgd2lsbCBiZSB1c2VkIGluIGFwcGx5aW5nIHRoZSBDZW50cmFsIExpbWl0IFRoZW9yZW0gaW4gc3Vic2VxdWVudCBxdWVzdGlvbnMNCg0KYGBge3J9DQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiSU1HXzYyMjUuanBnIikNCmBgYA0KXA0KDQoNCiMjICoqUXVlc3Rpb24gMyoqOiBTYW1wbGluZyBEaXN0cmlidXRpb24gb2YgTG9nbm9ybWFsICoqU2FtcGxlIE1lYW4qKiAkXHdpZGVoYXR7XG11X3tMTn19JA0KDQpXZSBoYXZlIGRlcml2ZWQgdHdvIGRpZmZlcmVudCBlc3RpbWF0b3JzIG9mIGxvZ25vcm1hbCBwb3B1bGF0aW9uIG1lYW4gJFxtdV97TE59JC4gVGhpcyBRdWVzdGlvbiBmb2N1c2VzIG9uIHRoZSBzYW1wbGluZyBkaXN0cmlidXRpb24gb2YgbG9nbm9ybWFsIHNhbXBsZSBzYW1wbGUgbWVhbnMgYmFzZWQgb24gTUxFLiBUaGUgZm9sbG93aW5nIGFyZSBkZXRhaWxlZCBpbnN0cnVjdGlvbnMuDQoNCigxKS4gV3JpdGUgYW4gUiBmdW5jdGlvbiB0byBlc3RpbWF0ZSB0aGUgTUxFIG9mICRcbXUkIGFuZCAkXHNpZ21hXjIkLCBkZW5vdGVkIGJ5ICRcd2lkZWhhdHtcbXV9JCBhbmQgJFx3aWRlaGF0e1xzaWdtYV4yfSQgYW5kIHJldHVybiB0aGUgTUxFIG9mICRcbXVfe0xOfSQsIGRlbm90ZWQgYnkgJFx3aWRlaGF0e1xtdV97TE59fSQuDQoNCmBgYHtyfQ0KbWxlX2xvZ25vcm1hbCA8LSBmdW5jdGlvbih4KSB7DQogICMgQ2hlY2sgZm9yIHBvc2l0aXZlIHZhbHVlcw0KICBpZihhbnkoeCA8PSAwKSkgc3RvcCgiQWxsIGRhdGEgbXVzdCBiZSBwb3NpdGl2ZSBmb3IgbG9nbm9ybWFsIE1MRSIpDQogIA0KICAjIDEuIFRha2UgbG9nIG9mIGRhdGENCiAgbG9nX3ggPC0gbG9nKHgpDQogIA0KICAjIDIuIENvbXB1dGUgTUxFcyBmb3IgbXUgYW5kIHNpZ21hXjINCiAgbXVfaGF0IDwtIG1lYW4obG9nX3gpDQogIHNpZ21hMl9oYXQgPC0gbWVhbigobG9nX3ggLSBtdV9oYXQpXjIpICAjIGRpdmlkZSBieSBuIGZvciBNTEUsIG5vdCBuLTENCiAgDQogICMgMy4gQ29tcHV0ZSBNTEUgb2YgbG9nbm9ybWFsIG1lYW4NCiAgbXVfTE5faGF0IDwtIGV4cChtdV9oYXQgKyAwLjUgKiBzaWdtYTJfaGF0KQ0KICANCiAgIyBSZXR1cm4gcmVzdWx0cyBhcyBhIGxpc3QNCiAgcmV0dXJuKGxpc3QobXVfaGF0ID0gbXVfaGF0LCBzaWdtYTJfaGF0ID0gc2lnbWEyX2hhdCwgbXVfTE5faGF0ID0gbXVfTE5faGF0KSkNCn0NCmBgYA0KDQooMikuIFRha2UgMTAwMCBCb290c3RyYXAgc2FtcGxlcyBmcm9tIHRoZSByYXcgb2lsIGRhdGEgc2V0LiBGb3IgZWFjaCBib290c3RyYXAgc2FtcGxlLCBjYWxsIHRoZSBhYm92ZSBSIGZ1bmN0aW9uIHRvIGZpbmQgdGhlICoqYm9vdHN0cmFwIE1MRSoqIG9mICRcbXVfe0xOfSQsIGRlbm90ZWQgYnkgJFx3aWRlaGF0e1xtdV97TE59Xip9XnsoMSl9LCBcd2lkZWhhdHtcbXVfe0xOfV4qfV57KDIpfSwgXGNkb3RzLCBcd2lkZWhhdHtcbXVfe0xOfV4qfV57KDEwMDApfSQuDQoNCmBgYHtyfQ0KIyBEZWZpbmUgdGhlIE1MRSBmdW5jdGlvbg0KbWxlX2xvZ25vcm1hbCA8LSBmdW5jdGlvbih4KSB7DQogIGlmKGFueSh4IDw9IDApKSBzdG9wKCJBbGwgZGF0YSBtdXN0IGJlIHBvc2l0aXZlIGZvciBsb2dub3JtYWwgTUxFIikNCiAgbG9nX3ggPC0gbG9nKHgpDQogIG11X2hhdCA8LSBtZWFuKGxvZ194KQ0KICBzaWdtYTJfaGF0IDwtIG1lYW4oKGxvZ194IC0gbXVfaGF0KV4yKQ0KICBtdV9MTl9oYXQgPC0gZXhwKG11X2hhdCArIDAuNSAqIHNpZ21hMl9oYXQpDQogIHJldHVybihsaXN0KG11X2hhdCA9IG11X2hhdCwgc2lnbWEyX2hhdCA9IHNpZ21hMl9oYXQsIG11X0xOX2hhdCA9IG11X0xOX2hhdCkpDQp9DQoNCiMgU2V0IHVwIGJvb3RzdHJhcA0Kc2V0LnNlZWQoMTIzKSAgICAgICMgcmVwcm9kdWNpYmlsaXR5DQpCIDwtIDEwMDAgICAgICAgICAgIyBudW1iZXIgb2YgYm9vdHN0cmFwIHNhbXBsZXMNCm4gPC0gbGVuZ3RoKGRhdGEpICAjIHNhbXBsZSBzaXplDQpib290c3RyYXBfbXVfTE4gPC0gbnVtZXJpYyhCKQ0KDQojIEJvb3RzdHJhcCBsb29wDQpmb3IoYiBpbiAxOkIpew0KICBib290X3NhbXBsZSA8LSBzYW1wbGUoZGF0YSwgc2l6ZSA9IG4sIHJlcGxhY2UgPSBUUlVFKQ0KICBib290c3RyYXBfbXVfTE5bYl0gPC0gbWxlX2xvZ25vcm1hbChib290X3NhbXBsZSkkbXVfTE5faGF0DQp9DQoNCiMgUGFydCAyIG91dHB1dHMNCmhlYWQoYm9vdHN0cmFwX211X0xOKSAgIyBmaXJzdCBmZXcgYm9vdHN0cmFwIE1MRXMNCm1lYW4oYm9vdHN0cmFwX211X0xOKSAgIyBib290c3RyYXAgbWVhbg0Kc2QoYm9vdHN0cmFwX211X0xOKSAgICAjIGJvb3RzdHJhcCBzdGFuZGFyZCBkZXZpYXRpb24NCg0KDQpgYGANCigzKS4gVXNpbmcga2VybmVsIGRlbnNpdHkgZXN0aW1hdGlvbiBhcHByb2FjaCB0byBlc3RpbWF0ZSB0aGUgYm9vdHN0cmFwIGRlbnNpdHkgY3VydmVzIGJhc2VkIG9uIHRoZSBib290c3RyYXAgTUxFczogJFx3aWRlaGF0e1xtdV97TE59Xip9XnsoMSl9LCBcd2lkZWhhdHtcbXVfe0xOfV4qfV57KDIpfSwgXGNkb3RzLCBcd2lkZWhhdHtcbXVfe0xOfV4qfV57KDEwMDApfSQuDQoNCmBgYHtyfQ0KIyBLZXJuZWwgZGVuc2l0eSBlc3RpbWF0aW9uIGZvciB0aGUgYm9vdHN0cmFwIE1MRXMNCmRlbnMgPC0gZGVuc2l0eShib290c3RyYXBfbXVfTE4pDQoNCiMgUGxvdCB0aGUgYm9vdHN0cmFwIGRlbnNpdHkNCnBsb3QoZGVucywgDQogICAgIG1haW4gPSBleHByZXNzaW9uKCJCb290c3RyYXAgS0RFIG9mICIqaGF0KG11KVtMTl0pLCANCiAgICAgeGxhYiA9IGV4cHJlc3Npb24oaGF0KG11KVtMTl0pLCANCiAgICAgeWxhYiA9ICJEZW5zaXR5IiwgDQogICAgIGNvbCA9ICJibHVlIiwgDQogICAgIGx3ZCA9IDIpDQoNCiMgQWRkIHJ1ZyBwbG90IGZvciB0aGUgYm9vdHN0cmFwIHBvaW50cw0KcnVnKGJvb3RzdHJhcF9tdV9MTiwgY29sID0gInJlZCIpDQoNCmBgYA0KDQooNCkuIEluIG9yZGVyIHRvIGZpbmQgdGhlIGFzeW1wdG90aWMgc2FtcGxpbmcgZGlzdHJpYnV0aW9uIHVzaW5nIHRoZSAqKmNlbnRyYWwgbGltaXQgdGhlb3JlbSAoQ0xUKSoqLiBUaGF0IGlzLCB3aGVuIHNhbXBsZSBzaXplIGlzIGxhcmdlLCANCg0KJCQNClxiYXJ7WH0gXHRvIE4gXGxlZnQoXG11X3tMTn0sIFxmcmFje1xzaWdtYV97TE59fXtcc3FydHtufX1ccmlnaHQpDQokJA0KDQp3aGVyZSAkXG11X3tMTn0kIGFuZCAkXHNpZ21hX3tMTn0kIGNhbiBiZSBlc3RpbWF0ZWQgYnkgdXNpbmcgdGhlICoqcGx1Zy1pbiBwcmluY2lwbGUgb2YgTUxFKiouIEJhc2VkIG9uIHRoZSBhc3ltcHRvdGljIHNhbXBsaW5nIGRpc3RyaWJ1dGlvbiBvZiAqKmxvZ25vcm1hbCBzYW1wbGUgbWVhbioqICRcYmFye1h9JCwgYWRkIHRoZSBhc3ltcHRvdGljIGRlbnNpdHkgY3VydmUgdG8gdGhlIGFib3ZlIEJvb3RzdHJhcCBrZXJuZWwgZGVuc2l0eSBjdXJ2ZS4NCg0KYGBge3J9DQojIDEuIENvbXB1dGUgTUxFcyBmcm9tIHRoZSBvcmlnaW5hbCBkYXRhDQptbGVfcmVzdWx0cyA8LSBtbGVfbG9nbm9ybWFsKGRhdGEpDQptdV9oYXQgPC0gbWxlX3Jlc3VsdHMkbXVfaGF0DQpzaWdtYTJfaGF0IDwtIG1sZV9yZXN1bHRzJHNpZ21hMl9oYXQNCg0KIyBQbHVnLWluIGVzdGltYXRlcw0KbXVfTE5faGF0IDwtIG1sZV9yZXN1bHRzJG11X0xOX2hhdA0Kc2lnbWFfTE5faGF0IDwtIHNxcnQoKGV4cChzaWdtYTJfaGF0KSAtIDEpICogZXhwKDIqbXVfaGF0ICsgc2lnbWEyX2hhdCkpDQoNCm4gPC0gbGVuZ3RoKGRhdGEpDQoNCiMgMi4gS2VybmVsIGRlbnNpdHkgZXN0aW1hdGUgb2YgYm9vdHN0cmFwIE1MRXMNCmRlbnMgPC0gZGVuc2l0eShib290c3RyYXBfbXVfTE4pDQoNCiMgMy4gUGxvdCBib290c3RyYXAgS0RFDQpwbG90KGRlbnMsIA0KICAgICBtYWluID0gZXhwcmVzc2lvbigiQm9vdHN0cmFwIEtERSB3aXRoIEFzeW1wdG90aWMgQ0xUIERlbnNpdHkiKSwgDQogICAgIHhsYWIgPSBleHByZXNzaW9uKGhhdChtdSlbTE5dKSwgDQogICAgIHlsYWIgPSAiRGVuc2l0eSIsIA0KICAgICBjb2wgPSAiYmx1ZSIsIA0KICAgICBsd2QgPSAyKQ0KDQoNCiMgNC4gT3ZlcmxheSBhc3ltcHRvdGljIG5vcm1hbCBkZW5zaXR5DQp4X3ZhbHMgPC0gc2VxKG1pbihib290c3RyYXBfbXVfTE4pLCBtYXgoYm9vdHN0cmFwX211X0xOKSwgbGVuZ3RoLm91dCA9IDUwMCkNCmNsdF9kZW5zaXR5IDwtIGRub3JtKHhfdmFscywgbWVhbiA9IG11X0xOX2hhdCwgc2QgPSBzaWdtYV9MTl9oYXQgLyBzcXJ0KG4pKQ0KDQpsaW5lcyh4X3ZhbHMsIGNsdF9kZW5zaXR5LCBjb2wgPSAiZGFya2dyZWVuIiwgbHdkID0gMiwgbHR5ID0gMikNCg0KIyA1LiBBZGQgbGVnZW5kDQpsZWdlbmQoInRvcHJpZ2h0IiwgbGVnZW5kID0gYygiQm9vdHN0cmFwIEtERSIsICJBc3ltcHRvdGljIENMVCIpLCANCiAgICAgICBjb2wgPSBjKCJibHVlIiwgImRhcmtncmVlbiIpLCBsd2QgPSAyLCBsdHkgPSBjKDEsMikpDQpgYGANCg0KKDUpLiBXcml0ZSBhIHNob3J0IHN1bW1hcnkgdG8gY29tcGFyZSB0aGUgdHdvIHNhbXBsaW5nIGRpc3RyaWJ1dGlvbnMgb2YgdGhlIHNhbXBsZSBtZWFuIG9mIHRoZSBsb2dub3JtYWwgZGlzdHJpYnV0aW9uLg0KDQoqKlRoZSBib290c3RyYXAgc2FtcGxpbmcgZGlzdHJpYnV0aW9uIGlzIG9idGFpbmVkIGJ5IHJlcGVhdGVkbHkgcmVzYW1wbGluZyB0aGUgb2JzZXJ2ZWQgZGF0YSBhbmQgcmVjYWxjdWxhdGluZyB0aGUgZXN0aW1hdG9ycyBhcyB0aGlzIGFwcHJvYWNoIGFwcHJveGltYXRlcyB0aGUgdHJ1ZSBzYW1wbGluZyBkaXN0cmlidXRpb24gd2l0aG91dCByZWx5aW5nIG9uIHRoZW9yZXRpY2FsIGFzc3VtcHRpb25zLiBTaW5jZSB0aGUgdW5kZXJseWluZyBsb2dub3JtYWwgZGlzdHJpYnV0aW9uIGlzIHNrZXdlZCwgdGhlIGJvb3RzdHJhcCBkaXN0cmlidXRpb24gbWF5IGFsc28gYXBwZWFyIHNsaWdodGx5IHNrZXdlZC4qKg0KDQoqKlRoZSBhc3ltcHRvdGljIHNhbXBsaW5nIGRpc3RyaWJ1dGlvbiBpcyBiYXNlZCBvbiB0aGUgQ2VudHJhbCBMaW1pdCBUaGVvcmVtIHdoaWNoIHN0YXRlcyB0aGF0IHRoZSBzYW1wbGUgbWVhbiBhcHByb2FjaGVzIGEgbm9ybWFsIGRpc3RyaWJ1dGlvbiBhcyB0aGUgc2FtcGxlIHNpemUgaW5jcmVhc2VzLiBUaGlzIGFwcHJveGltYXRpb24gYXNzdW1lcyB0aGF0IHRoZSBzYW1wbGUgc2l6ZSBpcyBzdWZmaWNpZW50bHkgbGFyZ2UgYW5kIHRoZXJlZm9yZSBwcm9kdWNlcyBhIHN5bW1ldHJpYyBub3JtYWwgY3VydmUuKioNCg0KKipGb3IgdGhpcyBkYXRhc2V0LCB0aGUgdHdvIGRpc3RyaWJ1dGlvbnMgc2hvdWxkIGFwcGVhciBmYWlybHkgc2ltaWxhciwgYWx0aG91Z2ggdGhlIGJvb3RzdHJhcCBkaXN0cmlidXRpb24gbWF5IHNob3cgbWlsZCByaWdodCBza2V3bmVzcyByZWZsZWN0aW5nIHRoZSBza2V3bmVzcyBvZiB0aGUgdW5kZXJseWluZyBsb2dub3JtYWwgZGF0YS4qKg0KDQoNCiMjICoqUXVlc3Rpb24gNCoqOiBFeHRyYSBCb251cyBDcmVkaXQNCg0KRGVyaXZlIHRoZSBIZXNzaWFuIG1hdHJpeCBieSBjb21wdXRpbmcgdGhlIHNlY29uZC1vcmRlciBwYXJ0aWFsIGRlcml2YXRpdmVzIG9mIHRoZSBsb2ctbGlrZWxpaG9vZCBmdW5jdGlvbiAod2l0aCByZXNwZWN0IHRvICRcbXUkIGFuZCAkXHNpZ21hXjIkKS4gVGhlbiwgdHJhbnNsYXRlIHRoZSBkZXJpdmVkIEhlc3NpYW4gaW50byBhbiBSIGZ1bmN0aW9uIHRoYXQgdGFrZXMgdGhlIE1MRXMgb2YgdGhlIHBhcmFtZXRlcnMgYW5kIHRoZSBkYXRhIGFzIGlucHV0cyBhbmQgcmV0dXJucyB0aGUgSGVzc2lhbiBtYXRyaXguIEZpbmFsbHksIGNvbXBhcmUgeW91ciBhbmFseXRpY2FsbHkgZGVyaXZlZCBIZXNzaWFuIHdpdGggdGhlIG51bWVyaWNhbCBIZXNzaWFuIHJldHVybmVkIGJ5IGBvcHRpbSgpYC4NCg==