1 Introduction

Maximum Likelihood Estimation (MLE) is one of the most widely used methods for parameter estimation in statistical inference. Given a statistical model with probability density (or mass) function \(f(x|\theta)\) and a random sample \(\mathbf{X} = (X_1, X_2, \ldots, X_n)\), the likelihood function is defined as:

\[ L(\theta|\mathbf{x}) = \prod_{i=1}^n f(x_i|\theta) \]

The maximum likelihood estimator \(\hat{\theta}_{MLE}\) is the value that maximizes this likelihood function. Note that MLE is only a point estimate, the next step is to characterize the (asymptotic) sampling distribution of the MLE. Before discussing the sampling distribution of MLE, we review the basics of multivariate normal distribution with a primary focus on bivariate normal distribution.

2 Some Foundamental Concepts

To discuss the asymptotic sampling distribution of the MLE of parameters, we need to understand a few important concepts. We will not dive into deep weed of derivation. Instead, we will only explain these concept using minimum mathematics.

2.1 Illustration of Covariance Matrix

A covariance matrix provides a complete picture of the pairwise linear relationships between variables. Its diagonal represents the individual variance of each variable, while the off-diagonal entries indicate how pairs of variables move together. A positive value means the two variables tend to increase together (i.e., are positively correlated), while a negative value means one tends to increase as the other decreases (i.e., they are negatively correlated). The magnitude of each entry (relative to the variances) indicates the strength of the linear relationship. In short, a covariance matrix captures the linear correlations among the variables that define it.

All covariance matrices are symmetric - this because correlation between \(X\) and \(Y\) is the as between \(Y\) and \(X\).

To have better understanding , we use an artificial example with three variables: Height (H), Weight (W), and Age (A). Assume that their covariance matrix is:

\[ \mathbf{\Sigma} = \begin{bmatrix} \color{blue}{25} & \color{green}{12} & \color{purple}{8} \\[4pt] \color{green}{12} & \color{blue}{36} & \color{orange}{6} \\[4pt] \color{purple}{8} & \color{orange}{6} & \color{blue}{16} \end{bmatrix} \]

Diagonals (in blue) Are Variances

Diagonal elements \(\Sigma_{ii}\) represent variances of individual variables:

  • \(\Sigma_{11} = 25\): Variance of Height

\[ \sigma_H = \sqrt{25} = 5 \text{cm} \]

  • \(\Sigma_{22} = 36\): Variance of Weight

\[ \sigma_W = \sqrt{36} = 6 \text{kg} \]

  • \(\Sigma_{33} = 16\): Variance of Age

\[ \sigma_A = \sqrt{16} = 4 \text{yr} \]

Off-diagonal Elements (Covariances in Green, Purple, Orange)

  • Height-Weight Covariance: \(\Sigma_{12} = \Sigma_{21} = 12\)
    • Sign: Positive \(\rightarrow\), Taller people tend to weigh more
    • Correlation coefficient: \(\rho_{HW} = \frac{12}{\sqrt{25 \cdot 36}} = \frac{12}{5 \times 6} = 0.4\), moderate positive correlation.
  • Height-Age Covariance: \(\Sigma_{13} = \Sigma_{31} = 8\)
    • sign: Positive \(\rightarrow\) Older people tend to be taller
    • Correlation coefficient: \(\rho_{HA} = \frac{8}{\sqrt{25 \cdot 16}} = \frac{8}{5 \times 4} = 0.4\), moderate positive correlation
  • Weight-Age Covariance: \(\Sigma_{23} = \Sigma_{32} = 6\)
    • sign: Positive but smallest magnitude.
    • Correlation coefficient: \(\rho_{WA} = \frac{6}{\sqrt{36 \cdot 16}} = \frac{6}{6 \times 4} = 0.25\), weak positive correlation.


Some Extreme Cases

  • Diagonal Matrix (Uncorrelated Variables): All covariances = 0 \(\rightarrow\) variables are uncorrelated

\[ \mathbf{\Sigma}_{\text{diag}} = \begin{bmatrix} 25 & 0 & 0 \\ 0 & 36 & 0 \\ 0 & 0 & 16 \end{bmatrix} \]

  • High Correlation Matrix: Large off-diagonals \(\rightarrow\) stronger relationships

\[ \mathbf{\Sigma}_{\text{high}} = \begin{bmatrix} 25 & 20 & 15 \\ 20 & 36 & 18 \\ 15 & 18 & 16 \end{bmatrix} \]

  • Mixed Sign: Height-Weight negative correlation

\[ \mathbf{\Sigma}_{\text{mixed}} = \begin{bmatrix} 25 & -12 & 8 \\ -12 & 36 & -6 \\ 8 & -6 & 16 \end{bmatrix} \]

2.2 Coveriance Matrix of MLE

As we know, maximum likelihood estimators (MLEs) of population parameters are derived from random samples. For instance, let \(\hat{\alpha}\) and \(\hat{\beta}\) denote the MLEs of \(\alpha\) and \(\beta\), respectively. Since \(\hat{\alpha}\) and \(\hat{\beta}\) are estimated from the same random sample, they are:

  1. Random variables

  2. Generally correlated

To fully characterize the correlation between \(\hat{\alpha}\) and \(\hat{\beta}\), we require their covariance matrix. Direct derivation of this covariance matrix is often analytically demanding. As an alternative approach, we introduce two key matrices derived from the log-likelihood function: the Hessian matrix and the Fisher information matrix.

2.2.1 Observed Hessian and Fisher Information Matrices

Let \(\{x_1, x_2, \cdots, x_n \}\) be an i.i.d. random sample from a population with density function \(f(x: \alpha, \beta)\). The likelihood function of \(\alpha\) and \(\beta\) is

\[ L(\alpha, \beta) = \prod_{i=1}^n f(x_i:\alpha, \beta) \]

The log-likelihood function is

\[ l(\alpha, \beta) = \sum_{i=1}^n \log f(x_i:\alpha, \beta) \]

**

The Hessian matrix of \(\alpha\) and \(\beta\) is defined to be

\[ \mathcal{H}(\alpha, \beta) = \begin{bmatrix} \frac{\partial l(\alpha, \beta)}{\partial \alpha^2} & \frac{\partial l(\alpha, \beta)}{\partial \alpha \partial \beta}\\ \frac{\partial l(\alpha, \beta)}{ \partial \beta\partial \alpha} & \frac{\partial l(\alpha, \beta)}{\partial \beta^2} \\ \end{bmatrix}. \]

plugging the MLE to the Hessian matrix, we have observed Hessian matrix

\[ \mathcal{H}(\hat{\alpha}, \hat{\beta}) = \begin{bmatrix} \frac{\partial l(\alpha, \beta)}{\partial \alpha^2} & \frac{\partial l(\alpha, \beta)}{\partial \alpha \partial \beta}\\ \frac{\partial l(\alpha, \beta)}{ \partial \beta\partial \alpha} & \frac{\partial l(\alpha, \beta)}{\partial \beta^2} \\ \end{bmatrix} \Bigg|_{\alpha = \hat{\alpha} \\ \beta = \hat{\beta}}. \]

This means that for a given random sample from a population, we can find the observed Hessian matrix in two Steps:

  • Finding the MLE of the population parameters.

  • Substituting the MLE estimates into the Hessian matrix.

The observed Fisher Information Matrix based on a random sample with size \(n\) is equal to the negative of the observed Hessian Matrix. That is,

\[ \mathcal{J}_n(\hat{\alpha}, \hat{\beta}) = - \mathcal H(\hat{\alpha}, \hat{\beta}) \]

Note that \(\mathcal{J}_n(\hat{\alpha}, \hat{\beta})\) is completely dependent on the random sample. The theoretical Fisher information matrix is denoted by

\[ \mathbb{I}_n(\alpha, \beta) = \mathbb{E}[\mathcal{H}(\alpha, \beta)]. \] This theoretical Fisher information matrix will be used later in hypothesis testing.


2.2.2 Covariance Metrix of MLE

After some algebra (integral and derivative), the variance-covariance matrix of the MLE of \(\alpha\) and \(\beta\) can be expressed in the following

\[ \text{cov}(\hat{\alpha}, \hat{\beta}) = \mathbb{I}_n^{-1}(\alpha, \beta). \]

This means the covariance matrix of the MLE depends on the unknown parameters \(\alpha\) and \(\beta\). We therefore estimate it by applying the MLE plug-in principle:

The estimator \(\mathbb{I}_n^{-1}(\hat{\alpha}, \hat{\beta})\) is used to estimate \(\mathbb{I}_n^{-1}(\alpha, \beta)\), with \(\hat{\alpha}\) and \(\hat{\beta}\) being the MLEs of \(\alpha\) and \(\beta\).

Following the MLE plug-in principle, the estimator of the covariance matrix \(\text{cov}(\hat{\alpha}, \hat{\beta})\) takes the following form:

\[ \widehat{\text{cov}(\hat{\alpha}, \hat{\beta})} = \mathbb{I}_n^{-1}(\hat{\alpha}, \hat{\beta}) \approx \mathcal{J}_n^{-1}(\hat{\alpha}, \hat{\beta}) \]

This means that the covariance matrix of the maximum likelihood estimator is approximated by the inverse of the observed Hessian matrix.


2.2.3 A Numerical Example

We consider an example based on the two-parameter Weibull distribution. The following are kep steps for finding the covariance matrix of the MLE.

1. Model and Data

Recall that the 2-parameter Weibull density function is given by

\[ f(x;\alpha,\beta)=\frac{\beta}{\alpha}\left(\frac{x}{\alpha}\right)^{\beta-1} e^{-(x/\alpha)^\beta},\; x>0. \]

Assume the following small sample (for illustration) is from a Weibull population

\[ \{ x_1,\dots,x_5\} = \{2.3,\;1.4,\;2.6,\;3.1,\;1.8\}. \]

2. Log-Likelihood

\[ \ell(\alpha,\beta)=n\ln\beta - n\beta\ln\alpha + (\beta-1)\sum_{i=1}^n \ln x_i - \sum_{i=1}^n \left(\frac{x_i}{\alpha}\right)^\beta. \]

The score equations (i.e., gradient functions)

\[ \frac{\partial \ell(\alpha,\beta)}{\partial \alpha} = \frac{n}{\beta} + \sum_{i=1}^n \ln\!\left( \frac{x_i}{\alpha} \right) - \sum_{i=1}^n \left( \frac{x_i}{\alpha} \right)^{\beta} \ln\!\left( \frac{x_i}{\alpha} \right) \] \[ \frac{\partial \ell(\alpha,\beta)}{\partial \beta} =\frac{\beta}{\alpha} \Bigg[ \sum_{i=1}^n \left( \frac{x_i}{\alpha} \right)^{\beta} - n \Bigg] \]

Setting the above score functions to zero, we have

\[ \frac{\partial\ell}{\partial\alpha}=0 \quad\Rightarrow\quad \hat{\alpha}(\beta)=\left[\frac{1}{n}\sum_{i=1}^n x_i^\beta \right]^{1/\beta}. \]

\[ \frac{\partial\ell}{\partial\beta}=0 \quad\Rightarrow\quad \frac{n}{\beta} - n\ln\hat{\alpha} + \sum \ln x_i - \sum \left(\frac{x_i}{\hat{\alpha}}\right)^\beta \ln\left(\frac{x_i}{\hat{\alpha}}\right)=0. \]

3. Numerical MLE

Solving the profile likelihood yields:

\[ \hat{\beta} \approx 4.0, \qquad \hat{\alpha} \approx 2.449. \]

To check the solution,

we would expect to check whether \(\frac{\partial \ell(\alpha,\beta)}{\partial \alpha} \approx 0\) and \(\frac{\partial \ell(\alpha,\beta)}{\partial \beta} \approx 0\) at \(\hat{\alpha} \approx 2.449\) and \(\hat{\beta} \approx 4.0\)

We manually check

\[ \frac{\partial \ell(\alpha,\beta)}{\partial \beta} \approx 0 \ \ \text{ implies } \ \ \frac{\beta}{\alpha} \Bigg[ \sum_{i=1}^n \left( \frac{x_i}{\alpha} \right)^{\beta} - n \Bigg] \approx0, \]

which is equivalent to

\[ \sum_{i=1}^n \left( \frac{x_i}{\alpha} \right)^{\beta} - n \approx 0 \]

To check the above approximation, let \(y_i=(x_i/\hat{\alpha})^{\hat{\beta}}\). We only need to check: \(\sum y_i - n \approx 0\):

\[ y_i \approx 0.777,\;0.1068,\;1.271,\;2.566,\;0.2918, \quad \sum y_i \approx 5.0126 \approx 5. \]

We can similarly check

\[ \frac{\partial \ell(\alpha,\beta)}{\partial \alpha} \approx 0. \]

4. Observed Fisher Information Matrix

Define

\[ t_i=\ln\left(\frac{x_i}{\hat{\alpha}}\right) \ \ \text{ and } \ \ y_i=\left(\frac{x_i}{\hat{\alpha}}\right)^{\hat{\beta}}. \]

The Hessian \(H(\hat{\alpha},\hat{\beta})\) of the log-likelihood is:

\[\begin{align*} \frac{\partial^2\ell}{\partial\alpha^2} &= -\frac{\hat{\beta}^2 n}{\hat{\alpha}^2}, \\ \frac{\partial^2\ell}{\partial\beta^2} &= -\frac{n}{\hat{\beta}^2} - \sum_{i=1}^n y_i t_i^2, \\ \frac{\partial^2\ell}{\partial\alpha\partial\beta} &= \frac{\hat{\beta}}{\hat{\alpha}} \sum_{i=1}^n y_i t_i. \end{align*}\]

Numerical values of MLE: (\(\hat{\alpha}=2.449\), \(\hat{\beta}=4.0\))

  • \(\sum y_i t_i^2 \approx 0.210971\).

  • \(\sum y_i t_i \approx 0.4820\).

Thus,

\[\begin{align*} H_{11} &= -\frac{4^2\cdot5}{2.449^2} \approx -13.338, \\ H_{22} &= -\frac{5}{16} - 0.210971 \approx -0.52347, \\ H_{12} = H_{21} &= \frac{4}{2.449}\times 0.4820 \approx 0.7875. \end{align*}\]

The observed Hessian matrix is

\[ \mathcal{H}(\hat{\alpha}=2.449, \hat{\beta}=4.0) = \begin{pmatrix} -13.338 & 0.7875 \\ 0.7875 & -0.52347 \end{pmatrix}. \]

Therefore, the Observed Fisher Information Matrix is

\[ \mathcal{J}(\hat{\alpha}=2.449, \hat{\beta}=4.0) =-\mathcal{H}(\hat{\alpha}=2.449, \hat{\beta}=4.0) =\begin{pmatrix} 13.338 & -0.7875 \\ -0.7875 & 0.52347 \end{pmatrix}. \]

5. Estimated Covariance Matrix of MLE

\[ \widehat{\text{Cov}}(\hat{\alpha},\hat{\beta}) =\mathcal{J}^{-1}(\hat{\alpha},\hat{\beta}). \]

\[ \det(\mathcal{J}) = (13.338)(0.52347) - (0.7875)^2 \approx 6.980 - 0.620 = 6.360. \]

Therefore,

\[ \mathcal{J}^{-1}(\hat{\alpha},\hat{\beta}) = \frac{1}{6.360} \begin{pmatrix} 0.52347 & 0.7875 \\ 0.7875 & 13.338 \end{pmatrix}. \] \[ \widehat{\text{Var}}(\hat{\alpha}) \approx 0.0823, \quad \widehat{\text{Var}}(\hat{\beta}) \approx 2.097, \quad \text{and } \quad \widehat{\text{Cov}}(\hat{\alpha},\hat{\beta}) \approx 0.1238. \]

Finally, the covariance matrix id given by

\[ \boxed{\widehat{\text{Cov}} = \begin{pmatrix} 0.0823 & 0.1238 \\ 0.1238 & 2.097 \end{pmatrix}}. \]

3 Bivariate Normal Distribution of MLE

Recall that the sample mean (\(\bar{x}\)), as an estimate of the population mean, serves as the maximum likelihood estimator (MLE) for distributions including the normal and Poisson. By applying the Central Limit Theorem (CLT), we have the following asymptotic sampling distribution

\[ \bar{x} \to N(\mu, \sigma^2) \]

Where \(\mu\) and \(\sigma^2\) are the population mean and variance, respectively. How would we characterize the joint asymptotic sampling distribution of MLE \((\bar{x}, s^2)\) for the parameters \((\mu, \sigma^2)\)? We need multivariate normal distribution to characterize the sampling distribution of the MLE of population parameters.

Since the density function of a joint distribution with more than two variables becomes very complicated, we use the vector representation of the multivariate normal distribution. For convenience, we will use the trivariate normal distribution as an example. Recall our artificial example with three variables: Height (H), Weight (W), and Age (A). Assume their covariance matrix is:

\[ \mathbf{\Sigma} = \begin{bmatrix} \color{blue}{25} & \color{green}{12} & \color{purple}{8} \\[4pt] \color{green}{12} & \color{blue}{36} & \color{orange}{6} \\[4pt] \color{purple}{8} & \color{orange}{6} & \color{blue}{16} \end{bmatrix} \]

Furthermore, assume \(E[H] = \mu_h, E[W] = \mu_w\) and \(E[A] = \mu_a\). Denote

\[ \mathbf{X} = \begin{bmatrix} H\\[4pt] W\\[4pt] A \end{bmatrix} \quad \text{and} \quad E[\mathbf{X}] = \begin{bmatrix} \mu_h\\[4pt] \mu_w \\[4pt] \mu_a \end{bmatrix}. \]

The joint density function of trivariate normal distribution is given in the following vector form

\[ f(h, w, a)=f(\mathbf{x}) = \frac{1}{(2\pi)^{p/2} \, |\mathbf{\Sigma}|^{1/2}} \exp\left\{ -\frac{1}{2} (\mathbf{x} - \mathbf{\mu})^{\top} \mathbf{\Sigma}^{-1} (\mathbf{x} - \mathbf{\mu}) \right\} \]

Using the above density function, we have complete information about the three random variables height, weight, and age and their relationships. While the mathematical expression may appear complex, we will not work with it directly for computation or derivation, but only for illustration.

4 Asymptotic Sampling Distribution

Following the above technical review of related mathematical and statistical concepts, we now state the fundamental property of MLE. To make this presentation self-contained, we will repeat the basic notations and concepts introduced in earlier sections.

To explain the basic idea, we consider estimating a population with two parameters. Assume an i.i.d random sample \(\{ x_1, x_2, \cdots, x_n\} \to f(x:\alpha, \beta)\), where \(\alpha\) and \(\beta\) are unknown. Let \(\hat{\alpha}\) and \(\hat{\beta}\) be the MLE of \(\alpha\) and \(\beta\) obtained from the maximum likelihood procedure introduced in the previous module.

Let \(\mathcal{J_n}\) be the observed Fisher Information Matrix and

\[ \mathbf{\Sigma}(\alpha, \beta) = \mathcal{I_n}^{-1}(\alpha, \beta) \equiv \begin{bmatrix} \sigma_{\alpha}^2 & \sigma_{\alpha\beta}\\[4pt] \sigma_{\alpha\beta} & \sigma_{\beta}^2 \end{bmatrix} \]

Using the MLE plug-in principle

\[ \widehat{\mathbf{\Sigma}}(\hat{\alpha}, \hat{\beta}) = \mathcal{I_n}^{-1}(\hat{\alpha}, \hat{\beta}) \equiv \begin{bmatrix} \hat{\sigma}_{\alpha}^2 & \hat{\sigma}_{\alpha\beta}\\[4pt] \hat{\sigma}_{\alpha\beta} & \hat{\sigma}_{\beta}^2 \end{bmatrix} \approx \mathcal{J}_n^{-1}(\hat{\alpha}, \hat{\beta}) \]

be the covariance of \((\hat{\alpha}, \hat{\beta})\).

If the sample size is large, we have the following asymptotic sampling distribution.

\[ \begin{bmatrix} \hat{\alpha}\\[4pt] \hat{\beta} \end{bmatrix} \to \mathcal{N}_2 \left( \begin{bmatrix} \alpha\\[4pt] \beta \end{bmatrix}, \ \begin{bmatrix} \sigma_{\alpha}^2 & \sigma_{\alpha\beta}\\[4pt] \sigma_{\alpha\beta} & \sigma_{\beta}^2 \end{bmatrix} \right) \]

This is a special version of bivariate central limit theorem! With the above bivariate normal distribution, we can find the asymptotic sampling distributions of \(\hat{\alpha}\) and \(\hat{\beta}\) in the following

\[ \hat{\alpha} \to N(\alpha,\hat{\sigma}_{\alpha}^2 ) \ \ \text{ and } \ \ \hat{\beta} \to N(\beta, \hat{\sigma}_{\beta}^2). \]

They are the marginal distribution of \((\hat{\alpha}, \hat{\beta})\).

5 A Numerical Example Using R

To conclude this module, we present a numerical example following the same methodology used in Section 2.2.3, where a small toy dataset was employed. Each step will be documented in the accompanying code.

Data Set: Let’s use wind speed data (in m/s) from a wind energy application. The Weibull distribution is commonly used to model wind speeds for wind power generation analysis.

12.4 2.7 4.3 4.3 11.1 2.5 5.3 8.7 11.4 4.2 7.5 6.5 12.1 3.2 2.5 8.5

4.2 7.2 16.0 7.0 9.5 6.3 7.9 2.7 10.9 1.1 4.6 10.4 4.2 0.6 4.8 4.8 3.7

15.6 13.3 0.4 12.1 3.2 15.2 1.5 2.5 6.2 5.4 3.4 2.8 0.8 4.0 0.5 5.4 6.5


5.1 Implementation of optim()

optim() is a powerful but black-box optimization routine. Blindly accepting its output can lead to wrong estimates, misleading uncertainty quantification, and incorrect inferences. When use it to find the MLE, please pay attention to the following key information.

Key Cautionary Points

  • Local vs. global optima: optim() finds a local optimum, not necessarily the global MLE. This is especially problematic for multi-modal likelihoods.

  • Convergence codes are not guarantees: A convergence code of 0 does not guarantee you’ve found the true MLE, only that optim()’s internal stopping conditions were met. However, if it is not 0, the reported parameter value is not the true MLE.

  • Sensitivity to initial values: Different starting points can lead to different results. Try several set of slightly different initial values to test the resulting parameter values are stable.

  • Incorrect Hessian approximation: If you use hessian = TRUE, optim() returns a finite-difference approximation, which can be inaccurate (especially if parameters are at very different scales).

  • Boundary issues: optim() can converge to values at the boundary of plausible parameter space, which may not satisfy theoretical regularity conditions for MLE asymptotics.

  • Poorly behaved likelihood: Flat regions, discontinuities, or numerical instability can cause optim() to fail silently.


5.2 Suggested Syntax for Calling optim()

In this subsection, we employ a common optimization technique: using the control statement in optim() to request maximization of the log-likelihood. This approach spares us from manually adding negative signs to the log-likelihood and gradient functions. Since the derivations have already been covered, we will not repeat them here. Please examine the code closely to understand the implementation.

KEY IMPLEMENTATION STEPS


Step 1: Data Loading

wspeed <- c(12.4, 2.7, 4.3, 4.3, 11.1, 2.5, 5.3, 8.7, 11.4, 4.2, 7.5, 6.5, 12.1, 3.2, 
            2.5, 8.5, 4.2, 7.2, 16.0, 7.0, 9.5, 6.3, 7.9, 2.7, 10.9, 1.1, 4.6, 10.4, 
            4.2, 0.6, 4.8, 4.8, 3.7, 15.6, 13.3, 0.4, 12.1, 3.2, 15.2, 1.5, 2.5, 6.2, 
            5.4, 3.4, 2.8, 0.8, 4.0, 0.5, 5.4, 6.5)

Step 2: Likelihood and Gradient Functions

We translate the log-likelihood function and score (gradient) functions in section 2.2.3 into R code directly in the following.

###
# **Negative** log-likelihood function for Weibull distribution
log_likelihood <- function(params, data) {
  k <- params[1]       # shape parameter
  lambda <- params[2]  # scale parameter
  
  # Ensure parameters are positive
  if (k <= 0 || lambda <= 0) {
    return(1e10)  # Return large value for invalid parameters
  }
  
  n <- length(data)
  log_lik <- n * log(k) - n * k * log(lambda) + 
    (k - 1) * sum(log(data)) - sum((data / lambda)^k)
  
  return(log_lik)  # Return log-likelihood! NOT the negative log-likelihood
}
###
###
# Gradient of **negative** log-likelihood function
log_likelihood_gradient <- function(params, data) {
  k <- params[1]       # shape parameter
  lambda <- params[2]  # scale parameter
  
  n <- length(data)
  
  # Partial derivatives
  dk <- n/k - n * log(lambda) + sum(log(data)) - 
        sum(log(data/lambda) * (data/lambda)^k)
  
  dlambda <-  (k/lambda)*(sum((data/lambda)^k) -n)
  
  return(c(dk, dlambda))  # Gradient of log-likelihood, NOT the negative scores
}

Step 3: Calling optim()

# Finding Initial Values
## It is critical to select appropriate initial values to
## ensure fast convergence. In general, we can use whatever
## methods (such as MME) that are available to get appropriate
## initial values

# Initial parameter estimates (method of moments)

initial_k <- (sd(wspeed)/mean(wspeed))^(-1.086)

initial_lambda <- mean(wspeed)/gamma(1 + 1/initial_k)

####
# MLE using optim() with gradient
mle_result <- optim(
  #par = c(initial_k,initial_lambda),
  par = c(1,6),
  fn = log_likelihood,
  gr = log_likelihood_gradient,
  data = wspeed,
  method = "L-BFGS-B",         # BFGS can use gradient information L-BFGS-B
  hessian = TRUE,          # this is the observed Hessian matrix 
  control = list(maxit = 1000, 
                 fnscale  = -1,
                 trace = FALSE,
                 abstol = 1e-8)
)
##
mle_result
$par
[1] 1.504317 6.903181

$value
[1] -136.0852

$counts
function gradient 
      11       11 

$convergence
[1] 0

$message
[1] "CONVERGENCE: REL_REDUCTION_OF_F <= FACTR*EPSMCH"

$hessian
          [,1]      [,2]
[1,] -38.53682  2.963880
[2,]   2.96388 -2.374384

To check the validity of the above procedure, we use an alternative R function to find the MLE of this special Weibull distribution:

fitdist(wspeed, "weibull", method = "mle", calcvcov=TRUE)
Fitting of the distribution ' weibull ' by maximum likelihood 
Parameters:
      estimate Std. Error
shape 1.504629  0.1694532
scale 6.903717  0.6824966

The two procedures yields the results!

CAUTION: Before reporting any estimates, validate the optimization output with the following steps:

  • Check the convergence code. A code of 0 indicates the algorithm completed its process, but this is only an internal check—it does not confirm the parameters are the true MLE.

  • Test different starting values. The final parameter estimates should not be identical to the initial guesses. Running the optimization from multiple starting points helps verify that the solution is robust and not an artifact of the initial conditions.

  • Verify the gradient is near zero. Compute the gradient at the reported solution. A near-zero gradient confirms a critical point has been reached.

  • Inspect the inverse Hessian. Calculate the inverse of the Hessian matrix. The diagonal elements of this matrix (the estimated variances) must be positive.

  • If optim() fails to work properly, consider using alternative optimization functions like optimx() (optimx package), nlminb()/nlm() (stats package), or DEoptim() (DEoptim package) for global optimization.

Step 4: Checking Score and Observed Fisher Information Matrix

The score equations in the following code.

log_likelihood_gradient(mle_result$par, wspeed)
[1] 2.487547e-04 1.171059e-05

Both score functions are close to zero as expected. The estimated covariance matrix, the inverse of the negative Hessian, can be extracted from the optim() in the following

Hess <- mle_result$hessian
covar<- solve(-Hess)  # solve() finds the inverse of a square matrix
covar
           [,1]       [,2]
[1,] 0.02870504 0.03583173
[2,] 0.03583173 0.46588968

Step 5: Final Sampling Distribution of MLE”

\[ \begin{bmatrix} \hat{\alpha} - \alpha\\[4pt] \hat{\beta} - \beta \end{bmatrix} \to \mathcal{N}_2 \left( \begin{bmatrix} 0\\[4pt] 0 \end{bmatrix}, \ \begin{bmatrix} 0.02871135 & 0.03583949\\[4pt] 0.03583949 & 0.46580012 \end{bmatrix} \right) \]

The two marginal distributions are explicitly given below

\[ \hat{\alpha} \to N(\alpha, \sigma_\alpha^2 = 0.0287) \ \ \text{ and } \ \ \hat{\beta} \to N(\beta, \sigma_\beta^2 = 0.4658) \]

The asymptotic univariate distributions discussed above will form the basis for subsequent inference procedures in the following modules.


Concluding Remarks: We have examined several optimization functions available in R packages. After performing appropriate checks to ensure the parameter estimates constitute maximum likelihood estimates, the Hessian matrix should be extracted and inverted to obtain the covariance matrix for subsequent inference. When utilizing functions other than optim(), you should consult the corresponding documentation or AI tools to understand the expected inputs and the nature of the outputs. Before applying optimization methods to your analytical tasks, it is helpful to practice with numerical examples from the documentation or those generated by AI tools.

LS0tDQp0aXRsZTogIkFzeW1wdG90aWMgU2FtcGxpbmcgRGlzdHJpYnV0aW9ucyBvZiBNTEVzIg0KYXV0aG9yOiAiQ2hlbmcgUGVuZyINCmRhdGU6ICJXZXN0IENoZXN0ZXIgVW5pdmVyc2l0eSINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDogDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDQNCiAgICB0b2NfZmxvYXQ6IHllcw0KICAgIG51bWJlcl9zZWN0aW9uczogeWVzDQogICAgdG9jX2NvbGxhcHNlZDogeWVzDQogICAgY29kZV9mb2xkaW5nOiBzaG93DQogICAgY29kZV9kb3dubG9hZDogeWVzDQogICAgc21vb3RoX3Njcm9sbDogeWVzDQogICAgaGlnaGxpZ2h0OiBtb25vY2hyb21lDQogICAgdGhlbWU6IHNwYWNlbGFiDQogIHBkZl9kb2N1bWVudDogDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDQNCiAgICBmaWdfY2FwdGlvbjogeWVzDQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgICBmaWdfd2lkdGg6IDMNCiAgICBmaWdfaGVpZ2h0OiAzDQogIHdvcmRfZG9jdW1lbnQ6IA0KICAgIHRvYzogeWVzDQogICAgdG9jX2RlcHRoOiA0DQogICAgZmlnX2NhcHRpb246IHllcw0KICAgIGtlZXBfbWQ6IHllcw0KZWRpdG9yX29wdGlvbnM6IA0KICBjaHVua19vdXRwdXRfdHlwZTogaW5saW5lDQotLS0NCg0KYGBge2NzcywgZWNobyA9IEZBTFNFfQ0KI1RPQzo6YmVmb3JlIHsNCiAgY29udGVudDogIlRhYmxlIG9mIENvbnRlbnRzIjsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogIGZvbnQtc2l6ZTogMS4yZW07DQogIGRpc3BsYXk6IGJsb2NrOw0KICBjb2xvcjogbmF2eTsNCiAgbWFyZ2luLWJvdHRvbTogMTBweDsNCn0NCg0KDQpkaXYjVE9DIGxpIHsgICAgIC8qIHRhYmxlIG9mIGNvbnRlbnQgICovDQogICAgbGlzdC1zdHlsZTp1cHBlci1yb21hbjsNCiAgICBiYWNrZ3JvdW5kLWltYWdlOm5vbmU7DQogICAgYmFja2dyb3VuZC1yZXBlYXQ6bm9uZTsNCiAgICBiYWNrZ3JvdW5kLXBvc2l0aW9uOjA7DQp9DQoNCmgxLnRpdGxlIHsgICAgLyogbGV2ZWwgMSBoZWFkZXIgb2YgdGl0bGUgICovDQogIGZvbnQtc2l6ZTogMjJweDsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogIGNvbG9yOiBEYXJrUmVkOw0KICB0ZXh0LWFsaWduOiBjZW50ZXI7DQogIGZvbnQtZmFtaWx5OiAiR2lsbCBTYW5zIiwgc2Fucy1zZXJpZjsNCn0NCg0KaDQuYXV0aG9yIHsgLyogSGVhZGVyIDQgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgZm9udC1zaXplOiAxNXB4Ow0KICBmb250LXdlaWdodDogYm9sZDsNCiAgZm9udC1mYW1pbHk6IHN5c3RlbS11aTsNCiAgY29sb3I6IG5hdnk7DQogIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCg0KaDQuZGF0ZSB7IC8qIEhlYWRlciA0IC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovDQogIGZvbnQtc2l6ZTogMThweDsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogIGZvbnQtZmFtaWx5OiAiR2lsbCBTYW5zIiwgc2Fucy1zZXJpZjsNCiAgY29sb3I6IERhcmtCbHVlOw0KICB0ZXh0LWFsaWduOiBjZW50ZXI7DQp9DQoNCmgxIHsgLyogSGVhZGVyIDEgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgICBmb250LXNpemU6IDIwcHg7DQogICAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IGRhcmtyZWQ7DQogICAgdGV4dC1hbGlnbjogY2VudGVyOw0KfQ0KDQpoMiB7IC8qIEhlYWRlciAyIC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovDQogICAgZm9udC1zaXplOiAxOHB4Ow0KICAgIGZvbnQtd2VpZ2h0OiBib2xkOw0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBuYXZ5Ow0KICAgIHRleHQtYWxpZ246IGxlZnQ7DQp9DQoNCmgzIHsgLyogSGVhZGVyIDMgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgICBmb250LXNpemU6IDE2cHg7DQogICAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IG5hdnk7DQogICAgdGV4dC1hbGlnbjogbGVmdDsNCn0NCg0KaDQgeyAvKiBIZWFkZXIgNCAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICAgIGZvbnQtc2l6ZTogMTRweDsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IGRhcmtyZWQ7DQogICAgdGV4dC1hbGlnbjogbGVmdDsNCn0NCg0KLyogQWRkIGRvdHMgYWZ0ZXIgbnVtYmVyZWQgaGVhZGVycyAqLw0KLmhlYWRlci1zZWN0aW9uLW51bWJlcjo6YWZ0ZXIgew0KICBjb250ZW50OiAiLiI7DQoNCmJvZHkgeyBiYWNrZ3JvdW5kLWNvbG9yOndoaXRlOyB9DQoNCi5oaWdobGlnaHRtZSB7IGJhY2tncm91bmQtY29sb3I6eWVsbG93OyB9DQoNCnAgeyBiYWNrZ3JvdW5kLWNvbG9yOndoaXRlOyB9DQoNCn0NCmBgYA0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCiMgY29kZSBjaHVuayBzcGVjaWZpZXMgd2hldGhlciB0aGUgUiBjb2RlLCB3YXJuaW5ncywgYW5kIG91dHB1dCANCiMgd2lsbCBiZSBpbmNsdWRlZCBpbiB0aGUgb3V0cHV0IGZpbGVzLg0KaWYgKCFyZXF1aXJlKCJrbml0ciIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJrbml0ciIpDQogICBsaWJyYXJ5KGtuaXRyKQ0KfQ0KaWYgKCFyZXF1aXJlKCJwYW5kZXIiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygicGFuZGVyIikNCiAgIGxpYnJhcnkocGFuZGVyKQ0KfQ0KaWYgKCFyZXF1aXJlKCJnZ3Bsb3QyIikpIHsNCiAgaW5zdGFsbC5wYWNrYWdlcygiZ2dwbG90MiIpDQogIGxpYnJhcnkoZ2dwbG90MikNCn0NCmlmICghcmVxdWlyZSgidGlkeXZlcnNlIikpIHsNCiAgaW5zdGFsbC5wYWNrYWdlcygidGlkeXZlcnNlIikNCiAgbGlicmFyeSh0aWR5dmVyc2UpDQp9DQoNCmlmICghcmVxdWlyZSgicGxvdGx5IikpIHsNCiAgaW5zdGFsbC5wYWNrYWdlcygicGxvdGx5IikNCiAgbGlicmFyeShwbG90bHkpDQp9DQppZiAoIXJlcXVpcmUoImZpdGRpc3RycGx1cyIpKSB7DQogIGluc3RhbGwucGFja2FnZXMoImZpdGRpc3RycGx1cyIpDQogIGxpYnJhcnkoZml0ZGlzdHJwbHVzKQ0KfQ0KaWYgKCFyZXF1aXJlKCJvcHRpbXgiKSkgeyAgIyMgRm9yIG1vcmUgcm9idXN0IG9wdGltaXphdGlvbg0KICBpbnN0YWxsLnBhY2thZ2VzKCJvcHRpbXgiKQ0KICBsaWJyYXJ5KG9wdGlteCkNCn0NCmlmICghcmVxdWlyZSgiREVvcHRpbSIpKSB7ICAjIyBGb3IgZGlmZmljdWx0IHByb2JsZW1zLCBjb25zaWRlciBnbG9iYWwgb3B0aW1pemF0aW9uDQogIGluc3RhbGwucGFja2FnZXMoIkRFb3B0aW0iKQ0KICBsaWJyYXJ5KERFb3B0aW0pDQp9DQojIw0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCAgICAgICAjIGluY2x1ZGUgY29kZSBjaHVuayBpbiB0aGUgb3V0cHV0IGZpbGUNCiAgICAgICAgICAgICAgICAgICAgICB3YXJuaW5nID0gRkFMU0UsICAgIyBzb21ldGltZXMsIHlvdSBjb2RlIG1heSBwcm9kdWNlIHdhcm5pbmcgbWVzc2FnZXMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgeW91IGNhbiBjaG9vc2UgdG8gaW5jbHVkZSB0aGUgd2FybmluZyBtZXNzYWdlcyBpbg0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHRoZSBvdXRwdXQgZmlsZS4gDQogICAgICAgICAgICAgICAgICAgICAgcmVzdWx0cyA9IFRSVUUsICAgICMgeW91IGNhbiBhbHNvIGRlY2lkZSB3aGV0aGVyIHRvIGluY2x1ZGUgdGhlIG91dHB1dA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGluIHRoZSBvdXRwdXQgZmlsZS4NCiAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlID0gRkFMU0UsDQogICAgICAgICAgICAgICAgICAgICAgY29tbWVudCA9IE5BDQogICAgICAgICAgICAgICAgICAgICAgKSAgDQpgYGANCg0KXA0KDQojIEludHJvZHVjdGlvbg0KDQpNYXhpbXVtIExpa2VsaWhvb2QgRXN0aW1hdGlvbiAoTUxFKSBpcyBvbmUgb2YgdGhlIG1vc3Qgd2lkZWx5IHVzZWQgbWV0aG9kcyBmb3IgcGFyYW1ldGVyIGVzdGltYXRpb24gaW4gc3RhdGlzdGljYWwgaW5mZXJlbmNlLiBHaXZlbiBhIHN0YXRpc3RpY2FsIG1vZGVsIHdpdGggcHJvYmFiaWxpdHkgZGVuc2l0eSAob3IgbWFzcykgZnVuY3Rpb24gJGYoeHxcdGhldGEpJCBhbmQgYSByYW5kb20gc2FtcGxlICRcbWF0aGJme1h9ID0gKFhfMSwgWF8yLCBcbGRvdHMsIFhfbikkLCB0aGUgbGlrZWxpaG9vZCBmdW5jdGlvbiBpcyBkZWZpbmVkIGFzOg0KDQokJA0KTChcdGhldGF8XG1hdGhiZnt4fSkgPSBccHJvZF97aT0xfV5uIGYoeF9pfFx0aGV0YSkNCiQkDQoNClRoZSBtYXhpbXVtIGxpa2VsaWhvb2QgZXN0aW1hdG9yICRcaGF0e1x0aGV0YX1fe01MRX0kIGlzIHRoZSB2YWx1ZSB0aGF0IG1heGltaXplcyB0aGlzIGxpa2VsaWhvb2QgZnVuY3Rpb24uIE5vdGUgdGhhdCBNTEUgaXMgb25seSBhIHBvaW50IGVzdGltYXRlLCB0aGUgbmV4dCBzdGVwIGlzIHRvIGNoYXJhY3Rlcml6ZSB0aGUgKGFzeW1wdG90aWMpIHNhbXBsaW5nIGRpc3RyaWJ1dGlvbiBvZiB0aGUgTUxFLiBCZWZvcmUgZGlzY3Vzc2luZyB0aGUgc2FtcGxpbmcgZGlzdHJpYnV0aW9uIG9mIE1MRSwgd2UgcmV2aWV3IHRoZSBiYXNpY3Mgb2YgbXVsdGl2YXJpYXRlIG5vcm1hbCBkaXN0cmlidXRpb24gd2l0aCBhIHByaW1hcnkgZm9jdXMgb24gYml2YXJpYXRlIG5vcm1hbCBkaXN0cmlidXRpb24uDQoNCg0KDQojIFNvbWUgRm91bmRhbWVudGFsIENvbmNlcHRzDQoNClRvIGRpc2N1c3MgdGhlIGFzeW1wdG90aWMgc2FtcGxpbmcgZGlzdHJpYnV0aW9uIG9mIHRoZSBNTEUgb2YgcGFyYW1ldGVycywgd2UgbmVlZCB0byB1bmRlcnN0YW5kIGEgZmV3IGltcG9ydGFudCBjb25jZXB0cy4gV2Ugd2lsbCBub3QgZGl2ZSBpbnRvIGRlZXAgd2VlZCBvZiBkZXJpdmF0aW9uLiBJbnN0ZWFkLCB3ZSB3aWxsIG9ubHkgZXhwbGFpbiB0aGVzZSBjb25jZXB0IHVzaW5nIG1pbmltdW0gbWF0aGVtYXRpY3MuDQoNCg0KIyMgSWxsdXN0cmF0aW9uIG9mIENvdmFyaWFuY2UgTWF0cml4DQoNCkEgKipjb3ZhcmlhbmNlIG1hdHJpeCoqIHByb3ZpZGVzIGEgY29tcGxldGUgcGljdHVyZSBvZiB0aGUgcGFpcndpc2UgbGluZWFyIHJlbGF0aW9uc2hpcHMgYmV0d2VlbiB2YXJpYWJsZXMuIEl0cyAqKmRpYWdvbmFsKiogcmVwcmVzZW50cyB0aGUgaW5kaXZpZHVhbCB2YXJpYW5jZSBvZiBlYWNoIHZhcmlhYmxlLCB3aGlsZSB0aGUgKipvZmYtZGlhZ29uYWwqKiBlbnRyaWVzIGluZGljYXRlIGhvdyBwYWlycyBvZiB2YXJpYWJsZXMgbW92ZSB0b2dldGhlci4gQSBwb3NpdGl2ZSB2YWx1ZSBtZWFucyB0aGUgdHdvIHZhcmlhYmxlcyAqKnRlbmQgdG8gaW5jcmVhc2UgdG9nZXRoZXIqKiAoaS5lLiwgYXJlIHBvc2l0aXZlbHkgY29ycmVsYXRlZCksIHdoaWxlIGEgbmVnYXRpdmUgdmFsdWUgbWVhbnMgKipvbmUgdGVuZHMgdG8gaW5jcmVhc2UgYXMgdGhlIG90aGVyIGRlY3JlYXNlcyoqIChpLmUuLCB0aGV5IGFyZSBuZWdhdGl2ZWx5IGNvcnJlbGF0ZWQpLiBUaGUgbWFnbml0dWRlIG9mIGVhY2ggZW50cnkgKHJlbGF0aXZlIHRvIHRoZSB2YXJpYW5jZXMpIGluZGljYXRlcyB0aGUgc3RyZW5ndGggb2YgdGhlIGxpbmVhciByZWxhdGlvbnNoaXAuIEluIHNob3J0LCBhIGNvdmFyaWFuY2UgbWF0cml4IGNhcHR1cmVzIHRoZSAqKmxpbmVhciBjb3JyZWxhdGlvbnMqKiBhbW9uZyB0aGUgdmFyaWFibGVzIHRoYXQgZGVmaW5lIGl0Lg0KDQoqKkFsbCBjb3ZhcmlhbmNlIG1hdHJpY2VzIGFyZSBzeW1tZXRyaWMqKiAtIHRoaXMgYmVjYXVzZSBjb3JyZWxhdGlvbiBiZXR3ZWVuICRYJCBhbmQgJFkkIGlzIHRoZSBhcyBiZXR3ZWVuICRZJCBhbmQgJFgkLg0KDQoNClRvIGhhdmUgYmV0dGVyIHVuZGVyc3RhbmRpbmcgLCB3ZSB1c2UgYW4gYXJ0aWZpY2lhbCBleGFtcGxlIHdpdGggdGhyZWUgdmFyaWFibGVzOiAqKkhlaWdodCAoSCkqKiwgKipXZWlnaHQgKFcpKiosIGFuZCAqKkFnZSAoQSkqKi4gQXNzdW1lIHRoYXQgdGhlaXIgY292YXJpYW5jZSBtYXRyaXggaXM6DQoNCiQkDQpcbWF0aGJme1xTaWdtYX0gPSANClxiZWdpbntibWF0cml4fQ0KXGNvbG9ye2JsdWV9ezI1fSAmIFxjb2xvcntncmVlbn17MTJ9ICYgXGNvbG9ye3B1cnBsZX17OH0gXFxbNHB0XQ0KXGNvbG9ye2dyZWVufXsxMn0gJiBcY29sb3J7Ymx1ZX17MzZ9ICYgXGNvbG9ye29yYW5nZX17Nn0gXFxbNHB0XQ0KXGNvbG9ye3B1cnBsZX17OH0gJiBcY29sb3J7b3JhbmdlfXs2fSAmIFxjb2xvcntibHVlfXsxNn0NClxlbmR7Ym1hdHJpeH0NCiQkDQoNCioqRGlhZ29uYWxzIChpbiBibHVlKSBBcmUgVmFyaWFuY2VzKioNCg0KRGlhZ29uYWwgZWxlbWVudHMgJFxTaWdtYV97aWl9JCByZXByZXNlbnQgdmFyaWFuY2VzIG9mIGluZGl2aWR1YWwgdmFyaWFibGVzOg0KDQoNCiogICRcU2lnbWFfezExfSA9IDI1JDogVmFyaWFuY2Ugb2YgKipIZWlnaHQqKg0KDQokJA0KXHNpZ21hX0ggPSBcc3FydHsyNX0gPSA1IFx0ZXh0e2NtfQ0KJCQNCg0KKiAgJFxTaWdtYV97MjJ9ID0gMzYkOiBWYXJpYW5jZSBvZiAqKldlaWdodCoqDQoNCiQkDQpcc2lnbWFfVyA9IFxzcXJ0ezM2fSA9ICA2IFx0ZXh0e2tnfQ0KJCQNCg0KKiAgJFxTaWdtYV97MzN9ID0gMTYkOiBWYXJpYW5jZSBvZiAqKkFnZSoqDQoNCiQkDQpcc2lnbWFfQSA9IFxzcXJ0ezE2fSA9ICA0IFx0ZXh0e3lyfQ0KJCQNCg0KKipPZmYtZGlhZ29uYWwgRWxlbWVudHMgKENvdmFyaWFuY2VzIGluIEdyZWVuLCBQdXJwbGUsIE9yYW5nZSkqKg0KDQoqIEhlaWdodC1XZWlnaHQgQ292YXJpYW5jZTogJFxTaWdtYV97MTJ9ID0gXFNpZ21hX3syMX0gPSAxMiQNCiAgKyAqKlNpZ24qKjogUG9zaXRpdmUgJFxyaWdodGFycm93JCwgVGFsbGVyIHBlb3BsZSB0ZW5kIHRvIHdlaWdoIG1vcmUNCiAgKyAqKkNvcnJlbGF0aW9uIGNvZWZmaWNpZW50Kio6ICRccmhvX3tIV30gPSBcZnJhY3sxMn17XHNxcnR7MjUgXGNkb3QgMzZ9fSA9IFxmcmFjezEyfXs1IFx0aW1lcyA2fSA9IDAuNCQsIG1vZGVyYXRlIHBvc2l0aXZlIGNvcnJlbGF0aW9uLg0KICANCiogSGVpZ2h0LUFnZSBDb3ZhcmlhbmNlOiAkXFNpZ21hX3sxM30gPSBcU2lnbWFfezMxfSA9IDgkDQogICsgKipzaWduKio6IFBvc2l0aXZlICRccmlnaHRhcnJvdyQgT2xkZXIgcGVvcGxlIHRlbmQgdG8gYmUgdGFsbGVyDQogICsgKipDb3JyZWxhdGlvbiBjb2VmZmljaWVudCoqOiAkXHJob197SEF9ID0gXGZyYWN7OH17XHNxcnR7MjUgXGNkb3QgMTZ9fSA9IFxmcmFjezh9ezUgXHRpbWVzIDR9ID0gMC40JCwgbW9kZXJhdGUgcG9zaXRpdmUgY29ycmVsYXRpb24NCg0KKiBXZWlnaHQtQWdlIENvdmFyaWFuY2U6ICRcU2lnbWFfezIzfSA9IFxTaWdtYV97MzJ9ID0gNiQNCiAgKyAqKnNpZ24qKjogUG9zaXRpdmUgYnV0IHNtYWxsZXN0IG1hZ25pdHVkZS4NCiAgKyAqKkNvcnJlbGF0aW9uIGNvZWZmaWNpZW50Kio6ICRccmhvX3tXQX0gPSBcZnJhY3s2fXtcc3FydHszNiBcY2RvdCAxNn19ID0gXGZyYWN7Nn17NiBcdGltZXMgNH0gPSAwLjI1JCwgd2VhayBwb3NpdGl2ZSBjb3JyZWxhdGlvbi4NCg0KXA0KDQoqKlNvbWUgRXh0cmVtZSBDYXNlcyoqDQoNCiogKipEaWFnb25hbCBNYXRyaXggKFVuY29ycmVsYXRlZCBWYXJpYWJsZXMpKio6IEFsbCBjb3ZhcmlhbmNlcyA9IDAgJFxyaWdodGFycm93JCB2YXJpYWJsZXMgYXJlIHVuY29ycmVsYXRlZCANCg0KJCQNClxtYXRoYmZ7XFNpZ21hfV97XHRleHR7ZGlhZ319ID0gDQpcYmVnaW57Ym1hdHJpeH0NCjI1ICYgMCAmIDAgXFwNCjAgJiAzNiAmIDAgXFwNCjAgJiAwICYgMTYNClxlbmR7Ym1hdHJpeH0NCiQkDQoNCiogKipIaWdoIENvcnJlbGF0aW9uIE1hdHJpeCoqOiBMYXJnZSBvZmYtZGlhZ29uYWxzICRccmlnaHRhcnJvdyQgc3Ryb25nZXIgcmVsYXRpb25zaGlwcw0KDQoNCiQkDQpcbWF0aGJme1xTaWdtYX1fe1x0ZXh0e2hpZ2h9fSA9IA0KXGJlZ2lue2JtYXRyaXh9DQoyNSAmIDIwICYgMTUgXFwNCjIwICYgMzYgJiAxOCBcXA0KMTUgJiAxOCAmIDE2DQpcZW5ke2JtYXRyaXh9DQokJA0KDQoNCiogKipNaXhlZCBTaWduKio6IEhlaWdodC1XZWlnaHQgbmVnYXRpdmUgY29ycmVsYXRpb24NCg0KJCQNClxtYXRoYmZ7XFNpZ21hfV97XHRleHR7bWl4ZWR9fSA9IA0KXGJlZ2lue2JtYXRyaXh9DQoyNSAmIC0xMiAmIDggXFwNCi0xMiAmIDM2ICYgLTYgXFwNCjggJiAtNiAmIDE2DQpcZW5ke2JtYXRyaXh9DQokJA0KDQoNCiMjIENvdmVyaWFuY2UgTWF0cml4IG9mIE1MRSANCg0KDQpBcyB3ZSBrbm93LCBtYXhpbXVtIGxpa2VsaWhvb2QgZXN0aW1hdG9ycyAoTUxFcykgb2YgcG9wdWxhdGlvbiBwYXJhbWV0ZXJzIGFyZSBkZXJpdmVkIGZyb20gcmFuZG9tIHNhbXBsZXMuIEZvciBpbnN0YW5jZSwgbGV0ICRcaGF0e1xhbHBoYX0kIGFuZCAkXGhhdHtcYmV0YX0kIGRlbm90ZSB0aGUgTUxFcyBvZiAkXGFscGhhJCBhbmQgJFxiZXRhJCwgcmVzcGVjdGl2ZWx5LiBTaW5jZSAkXGhhdHtcYWxwaGF9JCBhbmQgJFxoYXR7XGJldGF9JCBhcmUgZXN0aW1hdGVkIGZyb20gdGhlIHNhbWUgcmFuZG9tIHNhbXBsZSwgdGhleSBhcmU6DQoNCjEuICoqUmFuZG9tIHZhcmlhYmxlcyoqDQoNCjIuICoqR2VuZXJhbGx5IGNvcnJlbGF0ZWQqKg0KDQpUbyBmdWxseSBjaGFyYWN0ZXJpemUgdGhlIGNvcnJlbGF0aW9uIGJldHdlZW4gJFxoYXR7XGFscGhhfSQgYW5kICRcaGF0e1xiZXRhfSQsIHdlIHJlcXVpcmUgdGhlaXIgY292YXJpYW5jZSBtYXRyaXguIERpcmVjdCBkZXJpdmF0aW9uIG9mIHRoaXMgY292YXJpYW5jZSBtYXRyaXggaXMgb2Z0ZW4gYW5hbHl0aWNhbGx5IGRlbWFuZGluZy4gQXMgYW4gYWx0ZXJuYXRpdmUgYXBwcm9hY2gsIHdlIGludHJvZHVjZSB0d28ga2V5IG1hdHJpY2VzIGRlcml2ZWQgZnJvbSB0aGUgbG9nLWxpa2VsaWhvb2QgZnVuY3Rpb246IHRoZSBIZXNzaWFuIG1hdHJpeCBhbmQgdGhlIEZpc2hlciBpbmZvcm1hdGlvbiBtYXRyaXguDQogDQogDQojIyMgT2JzZXJ2ZWQgSGVzc2lhbiBhbmQgRmlzaGVyIEluZm9ybWF0aW9uIE1hdHJpY2VzDQoNCkxldCAkXHt4XzEsIHhfMiwgXGNkb3RzLCB4X24gXH0kIGJlIGFuIGkuaS5kLiByYW5kb20gc2FtcGxlIGZyb20gYSBwb3B1bGF0aW9uIHdpdGggZGVuc2l0eSBmdW5jdGlvbiAkZih4OiBcYWxwaGEsIFxiZXRhKSQuIFRoZSBsaWtlbGlob29kIGZ1bmN0aW9uIG9mICRcYWxwaGEkIGFuZCAkXGJldGEkIGlzIA0KDQokJA0KTChcYWxwaGEsIFxiZXRhKSA9IFxwcm9kX3tpPTF9Xm4gZih4X2k6XGFscGhhLCBcYmV0YSkNCiQkDQoNClRoZSBsb2ctbGlrZWxpaG9vZCBmdW5jdGlvbiBpcw0KDQokJA0KbChcYWxwaGEsIFxiZXRhKSA9IFxzdW1fe2k9MX1ebiBcbG9nIGYoeF9pOlxhbHBoYSwgXGJldGEpDQokJA0KDQoqKg0KDQoNClRoZSBIZXNzaWFuIG1hdHJpeCBvZiAkXGFscGhhJCBhbmQgJFxiZXRhJCBpcyBkZWZpbmVkIHRvIGJlDQoNCiQkDQpcbWF0aGNhbHtIfShcYWxwaGEsIFxiZXRhKSA9IA0KXGJlZ2lue2JtYXRyaXh9DQogXGZyYWN7XHBhcnRpYWwgbChcYWxwaGEsIFxiZXRhKX17XHBhcnRpYWwgXGFscGhhXjJ9ICYgXGZyYWN7XHBhcnRpYWwgbChcYWxwaGEsIFxiZXRhKX17XHBhcnRpYWwgXGFscGhhIFxwYXJ0aWFsIFxiZXRhfVxcDQogXGZyYWN7XHBhcnRpYWwgbChcYWxwaGEsIFxiZXRhKX17IFxwYXJ0aWFsIFxiZXRhXHBhcnRpYWwgXGFscGhhfSAmICBcZnJhY3tccGFydGlhbCBsKFxhbHBoYSwgXGJldGEpfXtccGFydGlhbCBcYmV0YV4yfSAgXFwNClxlbmR7Ym1hdHJpeH0uDQokJA0KDQpwbHVnZ2luZyB0aGUgTUxFIHRvIHRoZSBIZXNzaWFuIG1hdHJpeCwgd2UgaGF2ZSAqKm9ic2VydmVkIEhlc3NpYW4qKiBtYXRyaXgNCg0KJCQNClxtYXRoY2Fse0h9KFxoYXR7XGFscGhhfSwgXGhhdHtcYmV0YX0pID0gDQpcYmVnaW57Ym1hdHJpeH0NCiBcZnJhY3tccGFydGlhbCBsKFxhbHBoYSwgXGJldGEpfXtccGFydGlhbCBcYWxwaGFeMn0gJiBcZnJhY3tccGFydGlhbCBsKFxhbHBoYSwgXGJldGEpfXtccGFydGlhbCBcYWxwaGEgXHBhcnRpYWwgXGJldGF9XFwNCiBcZnJhY3tccGFydGlhbCBsKFxhbHBoYSwgXGJldGEpfXsgXHBhcnRpYWwgXGJldGFccGFydGlhbCBcYWxwaGF9ICYgIFxmcmFje1xwYXJ0aWFsIGwoXGFscGhhLCBcYmV0YSl9e1xwYXJ0aWFsIFxiZXRhXjJ9ICBcXA0KXGVuZHtibWF0cml4fSBcQmlnZ3xfe1xhbHBoYSA9IFxoYXR7XGFscGhhfSBcXCBcYmV0YSA9IFxoYXR7XGJldGF9fS4NCiQkDQoNClRoaXMgbWVhbnMgdGhhdCBmb3IgYSBnaXZlbiByYW5kb20gc2FtcGxlIGZyb20gYSBwb3B1bGF0aW9uLCB3ZSBjYW4gZmluZCB0aGUgKipvYnNlcnZlZCBIZXNzaWFuIG1hdHJpeCoqIGluIHR3byBTdGVwczoNCg0KKiBGaW5kaW5nIHRoZSBNTEUgb2YgdGhlIHBvcHVsYXRpb24gcGFyYW1ldGVycy4NCg0KKiBTdWJzdGl0dXRpbmcgdGhlIE1MRSBlc3RpbWF0ZXMgaW50byB0aGUgSGVzc2lhbiBtYXRyaXguDQoNCg0KVGhlIDxmb250IGNvbG9yID0gImRhcmtyZWQiPioqb2JzZXJ2ZWQqKjwvZm9udD4gKipGaXNoZXIgSW5mb3JtYXRpb24gTWF0cml4KiogYmFzZWQgb24gYSByYW5kb20gc2FtcGxlIHdpdGggc2l6ZSAkbiQgaXMgZXF1YWwgdG8gdGhlICoqbmVnYXRpdmUqKiBvZiB0aGUgPGZvbnQgY29sb3IgPSAiZGFya3JlZCI+KipvYnNlcnZlZCoqPC9mb250PiAqKkhlc3NpYW4gTWF0cml4KiouIFRoYXQgaXMsDQoNCiQkDQpcbWF0aGNhbHtKfV9uKFxoYXR7XGFscGhhfSwgXGhhdHtcYmV0YX0pID0gLSBcbWF0aGNhbCBIKFxoYXR7XGFscGhhfSwgXGhhdHtcYmV0YX0pIA0KJCQNCg0KTm90ZSB0aGF0ICRcbWF0aGNhbHtKfV9uKFxoYXR7XGFscGhhfSwgXGhhdHtcYmV0YX0pJCBpcyBjb21wbGV0ZWx5IGRlcGVuZGVudCBvbiB0aGUgcmFuZG9tIHNhbXBsZS4gVGhlIHRoZW9yZXRpY2FsIEZpc2hlciBpbmZvcm1hdGlvbiBtYXRyaXggaXMgZGVub3RlZCBieSANCg0KJCQNClxtYXRoYmJ7SX1fbihcYWxwaGEsIFxiZXRhKSA9IFxtYXRoYmJ7RX1bXG1hdGhjYWx7SH0oXGFscGhhLCBcYmV0YSldLg0KJCQNClRoaXMgdGhlb3JldGljYWwgRmlzaGVyIGluZm9ybWF0aW9uIG1hdHJpeCB3aWxsIGJlIHVzZWQgbGF0ZXIgaW4gaHlwb3RoZXNpcyB0ZXN0aW5nLg0KDQpcDQoNCiMjIyBDb3ZhcmlhbmNlIE1ldHJpeCBvZiBNTEUNCg0KQWZ0ZXIgc29tZSBhbGdlYnJhIChpbnRlZ3JhbCBhbmQgZGVyaXZhdGl2ZSksIHRoZSB2YXJpYW5jZS1jb3ZhcmlhbmNlIG1hdHJpeCBvZiB0aGUgTUxFIG9mICRcYWxwaGEkIGFuZCAkXGJldGEkIGNhbiBiZSBleHByZXNzZWQgaW4gdGhlIGZvbGxvd2luZw0KDQokJA0KXHRleHR7Y292fShcaGF0e1xhbHBoYX0sIFxoYXR7XGJldGF9KSA9IFxtYXRoYmJ7SX1fbl57LTF9KFxhbHBoYSwgXGJldGEpLg0KJCQNCg0KVGhpcyBtZWFucyB0aGUgY292YXJpYW5jZSBtYXRyaXggb2YgdGhlIE1MRSBkZXBlbmRzIG9uIHRoZSB1bmtub3duIHBhcmFtZXRlcnMgJFxhbHBoYSQgYW5kICRcYmV0YSQuIFdlIHRoZXJlZm9yZSBlc3RpbWF0ZSBpdCBieSBhcHBseWluZyB0aGUgTUxFIHBsdWctaW4gcHJpbmNpcGxlOg0KDQo+IFRoZSBlc3RpbWF0b3IgJFxtYXRoYmJ7SX1fbl57LTF9KFxoYXR7XGFscGhhfSwgXGhhdHtcYmV0YX0pJCBpcyB1c2VkIHRvIGVzdGltYXRlICRcbWF0aGJie0l9X25eey0xfShcYWxwaGEsIFxiZXRhKSQsIHdpdGggJFxoYXR7XGFscGhhfSQgYW5kICRcaGF0e1xiZXRhfSQgYmVpbmcgdGhlIE1MRXMgb2YgJFxhbHBoYSQgYW5kICRcYmV0YSQuDQoNCg0KRm9sbG93aW5nIHRoZSBNTEUgcGx1Zy1pbiBwcmluY2lwbGUsIHRoZSBlc3RpbWF0b3Igb2YgdGhlIGNvdmFyaWFuY2UgbWF0cml4ICRcdGV4dHtjb3Z9KFxoYXR7XGFscGhhfSwgXGhhdHtcYmV0YX0pJCB0YWtlcyB0aGUgZm9sbG93aW5nIGZvcm06DQoNCiQkDQpcd2lkZWhhdHtcdGV4dHtjb3Z9KFxoYXR7XGFscGhhfSwgXGhhdHtcYmV0YX0pfSA9IFxtYXRoYmJ7SX1fbl57LTF9KFxoYXR7XGFscGhhfSwgXGhhdHtcYmV0YX0pIFxhcHByb3ggXG1hdGhjYWx7Sn1fbl57LTF9KFxoYXR7XGFscGhhfSwgXGhhdHtcYmV0YX0pDQokJA0KDQpUaGlzIG1lYW5zIHRoYXQgdGhlIGNvdmFyaWFuY2UgbWF0cml4IG9mIHRoZSBtYXhpbXVtIGxpa2VsaWhvb2QgZXN0aW1hdG9yIGlzIGFwcHJveGltYXRlZCBieSB0aGUgKippbnZlcnNlKiogb2YgdGhlICoqb2JzZXJ2ZWQgSGVzc2lhbiBtYXRyaXgqKi4NCg0KXA0KDQojIyMgQSBOdW1lcmljYWwgRXhhbXBsZQ0KDQpXZSBjb25zaWRlciBhbiBleGFtcGxlIGJhc2VkIG9uIHRoZSB0d28tcGFyYW1ldGVyIFdlaWJ1bGwgZGlzdHJpYnV0aW9uLiBUaGUgZm9sbG93aW5nIGFyZSBrZXAgc3RlcHMgZm9yIGZpbmRpbmcgdGhlIGNvdmFyaWFuY2UgbWF0cml4IG9mIHRoZSBNTEUuDQoNCioqMS4gTW9kZWwgYW5kIERhdGEqKg0KDQpSZWNhbGwgdGhhdCB0aGUgMi1wYXJhbWV0ZXIgV2VpYnVsbCBkZW5zaXR5IGZ1bmN0aW9uIGlzIGdpdmVuIGJ5DQoNCiQkDQpmKHg7XGFscGhhLFxiZXRhKT1cZnJhY3tcYmV0YX17XGFscGhhfVxsZWZ0KFxmcmFje3h9e1xhbHBoYX1ccmlnaHQpXntcYmV0YS0xfSBlXnstKHgvXGFscGhhKV5cYmV0YX0sXDsgeD4wLg0KJCQNCg0KQXNzdW1lIHRoZSBmb2xsb3dpbmcgc21hbGwgc2FtcGxlIChmb3IgaWxsdXN0cmF0aW9uKSBpcyBmcm9tIGEgV2VpYnVsbCBwb3B1bGF0aW9uDQoNCiQkDQpceyB4XzEsXGRvdHMseF81XH0gPSBcezIuMyxcOzEuNCxcOzIuNixcOzMuMSxcOzEuOFx9Lg0KJCQNCg0KKioyLiBMb2ctTGlrZWxpaG9vZCoqDQoNCiQkDQpcZWxsKFxhbHBoYSxcYmV0YSk9blxsblxiZXRhIC0gblxiZXRhXGxuXGFscGhhICsgKFxiZXRhLTEpXHN1bV97aT0xfV5uIFxsbiB4X2kgLSBcc3VtX3tpPTF9Xm4gXGxlZnQoXGZyYWN7eF9pfXtcYWxwaGF9XHJpZ2h0KV5cYmV0YS4NCiQkDQoNClRoZSBzY29yZSBlcXVhdGlvbnMgKGkuZS4sIGdyYWRpZW50IGZ1bmN0aW9ucykNCg0KDQokJA0KXGZyYWN7XHBhcnRpYWwgXGVsbChcYWxwaGEsXGJldGEpfXtccGFydGlhbCBcYWxwaGF9ID0gXGZyYWN7bn17XGJldGF9ICsgXHN1bV97aT0xfV5uIFxsblwhXGxlZnQoIFxmcmFje3hfaX17XGFscGhhfSBccmlnaHQpIA0KLSBcc3VtX3tpPTF9Xm4gXGxlZnQoIFxmcmFje3hfaX17XGFscGhhfSBccmlnaHQpXntcYmV0YX0gDQpcbG5cIVxsZWZ0KCBcZnJhY3t4X2l9e1xhbHBoYX0gXHJpZ2h0KSAgDQokJA0KJCQNClxmcmFje1xwYXJ0aWFsIFxlbGwoXGFscGhhLFxiZXRhKX17XHBhcnRpYWwgXGJldGF9ID1cZnJhY3tcYmV0YX17XGFscGhhfQ0KXEJpZ2dbIFxzdW1fe2k9MX1ebiBcbGVmdCggXGZyYWN7eF9pfXtcYWxwaGF9IFxyaWdodClee1xiZXRhfSAtIG4gXEJpZ2ddDQokJA0KDQpTZXR0aW5nIHRoZSBhYm92ZSBzY29yZSBmdW5jdGlvbnMgdG8gemVybywgd2UgaGF2ZQ0KDQokJA0KXGZyYWN7XHBhcnRpYWxcZWxsfXtccGFydGlhbFxhbHBoYX09MCBccXVhZFxSaWdodGFycm93XHF1YWQgXGhhdHtcYWxwaGF9KFxiZXRhKT1cbGVmdFtcZnJhY3sxfXtufVxzdW1fe2k9MX1ebiB4X2leXGJldGEgXHJpZ2h0XV57MS9cYmV0YX0uDQokJA0KDQokJA0KXGZyYWN7XHBhcnRpYWxcZWxsfXtccGFydGlhbFxiZXRhfT0wIFxxdWFkXFJpZ2h0YXJyb3dccXVhZCBcZnJhY3tufXtcYmV0YX0gLSBuXGxuXGhhdHtcYWxwaGF9ICsgXHN1bSBcbG4geF9pIC0gXHN1bSBcbGVmdChcZnJhY3t4X2l9e1xoYXR7XGFscGhhfX1ccmlnaHQpXlxiZXRhIFxsblxsZWZ0KFxmcmFje3hfaX17XGhhdHtcYWxwaGF9fVxyaWdodCk9MC4NCiQkDQoNCg0KKiozLiBOdW1lcmljYWwgTUxFKioNCg0KU29sdmluZyB0aGUgcHJvZmlsZSBsaWtlbGlob29kIHlpZWxkczoNCg0KJCQNClxoYXR7XGJldGF9IFxhcHByb3ggNC4wLCBccXF1YWQgXGhhdHtcYWxwaGF9IFxhcHByb3ggMi40NDkuDQokJA0KDQpUbyBjaGVjayB0aGUgc29sdXRpb24sDQoNCndlIHdvdWxkIGV4cGVjdCB0byBjaGVjayB3aGV0aGVyICRcZnJhY3tccGFydGlhbCBcZWxsKFxhbHBoYSxcYmV0YSl9e1xwYXJ0aWFsIFxhbHBoYX0gXGFwcHJveCAwJCBhbmQgJFxmcmFje1xwYXJ0aWFsIFxlbGwoXGFscGhhLFxiZXRhKX17XHBhcnRpYWwgXGJldGF9IFxhcHByb3ggMCQgYXQgJFxoYXR7XGFscGhhfSBcYXBwcm94IDIuNDQ5JCBhbmQgJFxoYXR7XGJldGF9IFxhcHByb3ggNC4wJA0KDQpXZSBtYW51YWxseSBjaGVjayANCg0KJCQNClxmcmFje1xwYXJ0aWFsIFxlbGwoXGFscGhhLFxiZXRhKX17XHBhcnRpYWwgXGJldGF9IFxhcHByb3ggMCBcIFwgXHRleHR7IGltcGxpZXMgfSBcIFwgXGZyYWN7XGJldGF9e1xhbHBoYX0NClxCaWdnWyBcc3VtX3tpPTF9Xm4gXGxlZnQoIFxmcmFje3hfaX17XGFscGhhfSBccmlnaHQpXntcYmV0YX0gLSBuIFxCaWdnXSBcYXBwcm94MCwNCiQkDQoNCndoaWNoIGlzIGVxdWl2YWxlbnQgdG8NCg0KJCQNClxzdW1fe2k9MX1ebiBcbGVmdCggXGZyYWN7eF9pfXtcYWxwaGF9IFxyaWdodClee1xiZXRhfSAtIG4gXGFwcHJveCAwDQokJA0KDQpUbyBjaGVjayB0aGUgYWJvdmUgYXBwcm94aW1hdGlvbiwgbGV0ICR5X2k9KHhfaS9caGF0e1xhbHBoYX0pXntcaGF0e1xiZXRhfX0kLiBXZSBvbmx5IG5lZWQgdG8gY2hlY2s6ICRcc3VtIHlfaSAtIG4gXGFwcHJveCAwJDoNCg0KJCQNCnlfaSBcYXBwcm94IDAuNzc3LFw7MC4xMDY4LFw7MS4yNzEsXDsyLjU2NixcOzAuMjkxOCwgXHF1YWQgXHN1bSB5X2kgXGFwcHJveCA1LjAxMjYgXGFwcHJveCA1Lg0KJCQNCg0KV2UgY2FuIHNpbWlsYXJseSBjaGVjaw0KDQokJA0KXGZyYWN7XHBhcnRpYWwgXGVsbChcYWxwaGEsXGJldGEpfXtccGFydGlhbCBcYWxwaGF9IFxhcHByb3ggMC4gDQokJA0KDQoqKjQuIE9ic2VydmVkIEZpc2hlciBJbmZvcm1hdGlvbiBNYXRyaXgqKg0KDQpEZWZpbmUgDQoNCiQkDQp0X2k9XGxuXGxlZnQoXGZyYWN7eF9pfXtcaGF0e1xhbHBoYX19XHJpZ2h0KSAgXCAgXCAgXHRleHR7IGFuZCB9IFwgXCB5X2k9XGxlZnQoXGZyYWN7eF9pfXtcaGF0e1xhbHBoYX19XHJpZ2h0KV57XGhhdHtcYmV0YX19Lg0KJCQgICANCg0KVGhlIEhlc3NpYW4gJEgoXGhhdHtcYWxwaGF9LFxoYXR7XGJldGF9KSQgb2YgdGhlIGxvZy1saWtlbGlob29kIGlzOg0KDQoNClxiZWdpbnthbGlnbip9DQpcZnJhY3tccGFydGlhbF4yXGVsbH17XHBhcnRpYWxcYWxwaGFeMn0gJj0gLVxmcmFje1xoYXR7XGJldGF9XjIgbn17XGhhdHtcYWxwaGF9XjJ9LCBcXA0KXGZyYWN7XHBhcnRpYWxeMlxlbGx9e1xwYXJ0aWFsXGJldGFeMn0gJj0gLVxmcmFje259e1xoYXR7XGJldGF9XjJ9IC0gXHN1bV97aT0xfV5uIHlfaSB0X2leMiwgXFwNClxmcmFje1xwYXJ0aWFsXjJcZWxsfXtccGFydGlhbFxhbHBoYVxwYXJ0aWFsXGJldGF9ICY9IFxmcmFje1xoYXR7XGJldGF9fXtcaGF0e1xhbHBoYX19IFxzdW1fe2k9MX1ebiB5X2kgdF9pLg0KXGVuZHthbGlnbip9DQoNCg0KKipOdW1lcmljYWwgdmFsdWVzIG9mIE1MRSoqOiAoJFxoYXR7XGFscGhhfT0yLjQ0OSQsICRcaGF0e1xiZXRhfT00LjAkKQ0KDQoqICRcc3VtIHlfaSB0X2leMiBcYXBwcm94IDAuMjEwOTcxJC4NCg0KKiAkXHN1bSB5X2kgdF9pIFxhcHByb3ggMC40ODIwJC4NCg0KVGh1cywNCg0KDQpcYmVnaW57YWxpZ24qfQ0KSF97MTF9ICY9IC1cZnJhY3s0XjJcY2RvdDV9ezIuNDQ5XjJ9IFxhcHByb3ggLTEzLjMzOCwgXFwNCkhfezIyfSAmPSAtXGZyYWN7NX17MTZ9IC0gMC4yMTA5NzEgXGFwcHJveCAtMC41MjM0NywgXFwNCkhfezEyfSA9IEhfezIxfSAmPSBcZnJhY3s0fXsyLjQ0OX1cdGltZXMgMC40ODIwIFxhcHByb3ggMC43ODc1Lg0KXGVuZHthbGlnbip9DQoNCg0KVGhlICoqb2JzZXJ2ZWQqKiBIZXNzaWFuIG1hdHJpeCBpcyANCg0KJCQNClxtYXRoY2Fse0h9KFxoYXR7XGFscGhhfT0yLjQ0OSwgXGhhdHtcYmV0YX09NC4wKSA9IFxiZWdpbntwbWF0cml4fQ0KLTEzLjMzOCAmIDAuNzg3NSBcXA0KMC43ODc1ICYgLTAuNTIzNDcNClxlbmR7cG1hdHJpeH0uDQokJA0KDQpUaGVyZWZvcmUsIHRoZSAqKk9ic2VydmVkIEZpc2hlciBJbmZvcm1hdGlvbiBNYXRyaXgqKiBpcw0KDQokJA0KXG1hdGhjYWx7Sn0oXGhhdHtcYWxwaGF9PTIuNDQ5LCBcaGF0e1xiZXRhfT00LjApID0tXG1hdGhjYWx7SH0oXGhhdHtcYWxwaGF9PTIuNDQ5LCBcaGF0e1xiZXRhfT00LjApID1cYmVnaW57cG1hdHJpeH0gDQoxMy4zMzggJiAtMC43ODc1IFxcDQotMC43ODc1ICYgMC41MjM0Nw0KXGVuZHtwbWF0cml4fS4NCiQkDQoNCioqNS4gRXN0aW1hdGVkIENvdmFyaWFuY2UgTWF0cml4IG9mIE1MRSoqDQoNCiQkDQpcd2lkZWhhdHtcdGV4dHtDb3Z9fShcaGF0e1xhbHBoYX0sXGhhdHtcYmV0YX0pID1cbWF0aGNhbHtKfV57LTF9KFxoYXR7XGFscGhhfSxcaGF0e1xiZXRhfSkuDQokJA0KDQoNCiQkDQpcZGV0KFxtYXRoY2Fse0p9KSA9ICgxMy4zMzgpKDAuNTIzNDcpIC0gKDAuNzg3NSleMiBcYXBwcm94IDYuOTgwIC0gMC42MjAgPSA2LjM2MC4NCiQkDQoNClRoZXJlZm9yZSwNCg0KJCQNClxtYXRoY2Fse0p9XnstMX0oXGhhdHtcYWxwaGF9LFxoYXR7XGJldGF9KSA9IFxmcmFjezF9ezYuMzYwfQ0KXGJlZ2lue3BtYXRyaXh9DQowLjUyMzQ3ICYgMC43ODc1IFxcDQowLjc4NzUgJiAxMy4zMzgNClxlbmR7cG1hdHJpeH0uDQokJA0KJCQNClx3aWRlaGF0e1x0ZXh0e1Zhcn19KFxoYXR7XGFscGhhfSkgXGFwcHJveCAwLjA4MjMsIFxxdWFkIFx3aWRlaGF0e1x0ZXh0e1Zhcn19KFxoYXR7XGJldGF9KSBcYXBwcm94IDIuMDk3LCAgXHF1YWQgXHRleHR7YW5kIH0gIFxxdWFkIFx3aWRlaGF0e1x0ZXh0e0Nvdn19KFxoYXR7XGFscGhhfSxcaGF0e1xiZXRhfSkgXGFwcHJveCAwLjEyMzguDQokJA0KDQpGaW5hbGx5LCB0aGUgY292YXJpYW5jZSBtYXRyaXggaWQgZ2l2ZW4gYnkNCg0KJCQNClxib3hlZHtcd2lkZWhhdHtcdGV4dHtDb3Z9fSA9IFxiZWdpbntwbWF0cml4fQ0KMC4wODIzICYgMC4xMjM4IFxcDQowLjEyMzggJiAyLjA5Nw0KXGVuZHtwbWF0cml4fX0uDQokJA0KDQoNCg0KDQojIEJpdmFyaWF0ZSBOb3JtYWwgRGlzdHJpYnV0aW9uIG9mIE1MRQ0KDQpSZWNhbGwgdGhhdCB0aGUgc2FtcGxlIG1lYW4gKCRcYmFye3h9JCksIGFzIGFuIGVzdGltYXRlIG9mIHRoZSBwb3B1bGF0aW9uIG1lYW4sIHNlcnZlcyBhcyB0aGUgbWF4aW11bSBsaWtlbGlob29kIGVzdGltYXRvciAoTUxFKSBmb3IgZGlzdHJpYnV0aW9ucyBpbmNsdWRpbmcgdGhlIG5vcm1hbCBhbmQgUG9pc3Nvbi4gQnkgYXBwbHlpbmcgdGhlIENlbnRyYWwgTGltaXQgVGhlb3JlbSAoQ0xUKSwgd2UgaGF2ZSB0aGUgZm9sbG93aW5nICoqYXN5bXB0b3RpYyBzYW1wbGluZyBkaXN0cmlidXRpb24qKg0KDQokJA0KXGJhcnt4fSBcdG8gTihcbXUsIFxzaWdtYV4yKQ0KJCQNCg0KV2hlcmUgJFxtdSQgYW5kICRcc2lnbWFeMiQgYXJlIHRoZSBwb3B1bGF0aW9uIG1lYW4gYW5kIHZhcmlhbmNlLCByZXNwZWN0aXZlbHkuIEhvdyB3b3VsZCB3ZSBjaGFyYWN0ZXJpemUgdGhlICoqam9pbnQgYXN5bXB0b3RpYyBzYW1wbGluZyBkaXN0cmlidXRpb24qKiBvZiBNTEUgJChcYmFye3h9LCBzXjIpJCBmb3IgdGhlIHBhcmFtZXRlcnMgJChcbXUsIFxzaWdtYV4yKSQ/IFdlIG5lZWQgbXVsdGl2YXJpYXRlIG5vcm1hbCBkaXN0cmlidXRpb24gdG8gY2hhcmFjdGVyaXplIHRoZSBzYW1wbGluZyBkaXN0cmlidXRpb24gb2YgdGhlIE1MRSBvZiBwb3B1bGF0aW9uIHBhcmFtZXRlcnMuDQoNClNpbmNlIHRoZSBkZW5zaXR5IGZ1bmN0aW9uIG9mIGEgam9pbnQgZGlzdHJpYnV0aW9uIHdpdGggbW9yZSB0aGFuIHR3byB2YXJpYWJsZXMgYmVjb21lcyB2ZXJ5IGNvbXBsaWNhdGVkLCB3ZSB1c2UgdGhlIHZlY3RvciByZXByZXNlbnRhdGlvbiBvZiB0aGUgbXVsdGl2YXJpYXRlIG5vcm1hbCBkaXN0cmlidXRpb24uIEZvciBjb252ZW5pZW5jZSwgd2Ugd2lsbCB1c2UgdGhlICoqdHJpdmFyaWF0ZSBub3JtYWwgZGlzdHJpYnV0aW9uKiogYXMgYW4gZXhhbXBsZS4gUmVjYWxsIG91ciBhcnRpZmljaWFsIGV4YW1wbGUgd2l0aCB0aHJlZSB2YXJpYWJsZXM6ICoqSGVpZ2h0IChIKSoqLCAqKldlaWdodCAoVykqKiwgYW5kICoqQWdlIChBKSoqLiBBc3N1bWUgdGhlaXIgY292YXJpYW5jZSBtYXRyaXggaXM6DQoNCiQkDQpcbWF0aGJme1xTaWdtYX0gPSANClxiZWdpbntibWF0cml4fQ0KXGNvbG9ye2JsdWV9ezI1fSAmIFxjb2xvcntncmVlbn17MTJ9ICYgXGNvbG9ye3B1cnBsZX17OH0gXFxbNHB0XQ0KXGNvbG9ye2dyZWVufXsxMn0gJiBcY29sb3J7Ymx1ZX17MzZ9ICYgXGNvbG9ye29yYW5nZX17Nn0gXFxbNHB0XQ0KXGNvbG9ye3B1cnBsZX17OH0gJiBcY29sb3J7b3JhbmdlfXs2fSAmIFxjb2xvcntibHVlfXsxNn0NClxlbmR7Ym1hdHJpeH0NCiQkDQoNCkZ1cnRoZXJtb3JlLCBhc3N1bWUgJEVbSF0gPSBcbXVfaCwgRVtXXSA9IFxtdV93JCBhbmQgJEVbQV0gPSBcbXVfYSQuIERlbm90ZQ0KDQokJA0KXG1hdGhiZntYfSA9DQpcYmVnaW57Ym1hdHJpeH0NCkhcXFs0cHRdDQpXXFxbNHB0XQ0KQQ0KXGVuZHtibWF0cml4fQ0KXHF1YWQgXHRleHR7YW5kfSBccXVhZA0KRVtcbWF0aGJme1h9XSA9IA0KXGJlZ2lue2JtYXRyaXh9DQpcbXVfaFxcWzRwdF0NClxtdV93IFxcWzRwdF0NClxtdV9hDQpcZW5ke2JtYXRyaXh9Lg0KJCQNCg0KVGhlIGpvaW50IGRlbnNpdHkgZnVuY3Rpb24gb2YgdHJpdmFyaWF0ZSBub3JtYWwgZGlzdHJpYnV0aW9uIGlzIGdpdmVuIGluIHRoZSBmb2xsb3dpbmcgdmVjdG9yIGZvcm0NCg0KJCQNCmYoaCwgdywgYSk9ZihcbWF0aGJme3h9KSA9IFxmcmFjezF9eygyXHBpKV57cC8yfSBcLCB8XG1hdGhiZntcU2lnbWF9fF57MS8yfX0NClxleHBcbGVmdFx7IC1cZnJhY3sxfXsyfSAoXG1hdGhiZnt4fSAtIFxtYXRoYmZ7XG11fSlee1x0b3B9IFxtYXRoYmZ7XFNpZ21hfV57LTF9IChcbWF0aGJme3h9IC0gXG1hdGhiZntcbXV9KSBccmlnaHRcfQ0KJCQNCg0KVXNpbmcgdGhlIGFib3ZlIGRlbnNpdHkgZnVuY3Rpb24sIHdlIGhhdmUgY29tcGxldGUgaW5mb3JtYXRpb24gYWJvdXQgdGhlIHRocmVlIHJhbmRvbSB2YXJpYWJsZXMgKipoZWlnaHQqKiwgKip3ZWlnaHQqKiwgYW5kICoqYWdlKiogYW5kIHRoZWlyIHJlbGF0aW9uc2hpcHMuIFdoaWxlIHRoZSBtYXRoZW1hdGljYWwgZXhwcmVzc2lvbiBtYXkgYXBwZWFyIGNvbXBsZXgsIHdlIHdpbGwgbm90IHdvcmsgd2l0aCBpdCBkaXJlY3RseSBmb3IgY29tcHV0YXRpb24gb3IgZGVyaXZhdGlvbiwgYnV0IG9ubHkgZm9yIGlsbHVzdHJhdGlvbi4NCg0KDQoNCiMgQXN5bXB0b3RpYyBTYW1wbGluZyBEaXN0cmlidXRpb24NCg0KRm9sbG93aW5nIHRoZSBhYm92ZSB0ZWNobmljYWwgcmV2aWV3IG9mIHJlbGF0ZWQgbWF0aGVtYXRpY2FsIGFuZCBzdGF0aXN0aWNhbCBjb25jZXB0cywgd2Ugbm93IHN0YXRlIHRoZSBmdW5kYW1lbnRhbCBwcm9wZXJ0eSBvZiBNTEUuIFRvIG1ha2UgdGhpcyBwcmVzZW50YXRpb24gc2VsZi1jb250YWluZWQsIHdlIHdpbGwgcmVwZWF0IHRoZSBiYXNpYyBub3RhdGlvbnMgYW5kIGNvbmNlcHRzIGludHJvZHVjZWQgaW4gZWFybGllciBzZWN0aW9ucy4NCg0KVG8gZXhwbGFpbiB0aGUgYmFzaWMgaWRlYSwgd2UgY29uc2lkZXIgZXN0aW1hdGluZyBhIHBvcHVsYXRpb24gd2l0aCB0d28gcGFyYW1ldGVycy4gQXNzdW1lIGFuIGkuaS5kIHJhbmRvbSBzYW1wbGUgJFx7IHhfMSwgeF8yLCBcY2RvdHMsIHhfblx9IFx0byBmKHg6XGFscGhhLCBcYmV0YSkkLCB3aGVyZSAkXGFscGhhJCBhbmQgJFxiZXRhJCBhcmUgdW5rbm93bi4gTGV0ICRcaGF0e1xhbHBoYX0kIGFuZCAkXGhhdHtcYmV0YX0kIGJlIHRoZSBNTEUgb2YgJFxhbHBoYSQgYW5kICRcYmV0YSQgb2J0YWluZWQgZnJvbSB0aGUgbWF4aW11bSBsaWtlbGlob29kIHByb2NlZHVyZSBpbnRyb2R1Y2VkIGluIHRoZSBwcmV2aW91cyBtb2R1bGUuDQoNCkxldCAkXG1hdGhjYWx7Sl9ufSQgYmUgdGhlICoqb2JzZXJ2ZWQgRmlzaGVyIEluZm9ybWF0aW9uIE1hdHJpeCoqIGFuZCANCg0KJCQNClxtYXRoYmZ7XFNpZ21hfShcYWxwaGEsIFxiZXRhKSA9IFxtYXRoY2Fse0lfbn1eey0xfShcYWxwaGEsIFxiZXRhKSBcZXF1aXYgXGJlZ2lue2JtYXRyaXh9DQpcc2lnbWFfe1xhbHBoYX1eMiAmIFxzaWdtYV97XGFscGhhXGJldGF9XFxbNHB0XQ0KXHNpZ21hX3tcYWxwaGFcYmV0YX0gJiBcc2lnbWFfe1xiZXRhfV4yDQpcZW5ke2JtYXRyaXh9IA0KJCQNCg0KVXNpbmcgdGhlIE1MRSBwbHVnLWluIHByaW5jaXBsZQ0KDQokJA0KXHdpZGVoYXR7XG1hdGhiZntcU2lnbWF9fShcaGF0e1xhbHBoYX0sIFxoYXR7XGJldGF9KSA9IFxtYXRoY2Fse0lfbn1eey0xfShcaGF0e1xhbHBoYX0sIFxoYXR7XGJldGF9KSBcZXF1aXYgXGJlZ2lue2JtYXRyaXh9DQpcaGF0e1xzaWdtYX1fe1xhbHBoYX1eMiAmIFxoYXR7XHNpZ21hfV97XGFscGhhXGJldGF9XFxbNHB0XQ0KXGhhdHtcc2lnbWF9X3tcYWxwaGFcYmV0YX0gJiBcaGF0e1xzaWdtYX1fe1xiZXRhfV4yDQpcZW5ke2JtYXRyaXh9IFxhcHByb3ggXG1hdGhjYWx7Sn1fbl57LTF9KFxoYXR7XGFscGhhfSwgXGhhdHtcYmV0YX0pDQokJA0KDQpiZSB0aGUgY292YXJpYW5jZSBvZiAkKFxoYXR7XGFscGhhfSwgXGhhdHtcYmV0YX0pJC4gDQoNCklmIHRoZSBzYW1wbGUgc2l6ZSBpcyBsYXJnZSwgd2UgaGF2ZSB0aGUgZm9sbG93aW5nIGFzeW1wdG90aWMgc2FtcGxpbmcgZGlzdHJpYnV0aW9uLg0KDQokJA0KXGJlZ2lue2JtYXRyaXh9DQpcaGF0e1xhbHBoYX1cXFs0cHRdDQpcaGF0e1xiZXRhfQ0KXGVuZHtibWF0cml4fSBcdG8NClxtYXRoY2Fse059XzIgXGxlZnQoDQpcYmVnaW57Ym1hdHJpeH0NClxhbHBoYVxcWzRwdF0NClxiZXRhDQpcZW5ke2JtYXRyaXh9LCBcIFxiZWdpbntibWF0cml4fQ0KXHNpZ21hX3tcYWxwaGF9XjIgJiBcc2lnbWFfe1xhbHBoYVxiZXRhfVxcWzRwdF0NClxzaWdtYV97XGFscGhhXGJldGF9ICYgXHNpZ21hX3tcYmV0YX1eMg0KXGVuZHtibWF0cml4fSANClxyaWdodCkNCiQkDQoNClRoaXMgaXMgYSBzcGVjaWFsIHZlcnNpb24gb2YgYml2YXJpYXRlIGNlbnRyYWwgbGltaXQgdGhlb3JlbSEgV2l0aCB0aGUgYWJvdmUgYml2YXJpYXRlIG5vcm1hbCBkaXN0cmlidXRpb24sIHdlIGNhbiBmaW5kIHRoZSBhc3ltcHRvdGljIHNhbXBsaW5nIGRpc3RyaWJ1dGlvbnMgb2YgJFxoYXR7XGFscGhhfSQgYW5kICRcaGF0e1xiZXRhfSQgaW4gdGhlIGZvbGxvd2luZw0KDQokJA0KXGhhdHtcYWxwaGF9IFx0byBOKFxhbHBoYSxcaGF0e1xzaWdtYX1fe1xhbHBoYX1eMiApIFwgXCBcdGV4dHsgYW5kIH0gXCBcIFxoYXR7XGJldGF9IFx0byBOKFxiZXRhLCBcaGF0e1xzaWdtYX1fe1xiZXRhfV4yKS4NCiQkDQoNClRoZXkgYXJlIHRoZSBtYXJnaW5hbCBkaXN0cmlidXRpb24gb2YgJChcaGF0e1xhbHBoYX0sIFxoYXR7XGJldGF9KSQuDQoNCg0KIyBBIE51bWVyaWNhbCBFeGFtcGxlIFVzaW5nIFINCg0KDQpUbyBjb25jbHVkZSB0aGlzIG1vZHVsZSwgd2UgcHJlc2VudCBhIG51bWVyaWNhbCBleGFtcGxlIGZvbGxvd2luZyB0aGUgc2FtZSBtZXRob2RvbG9neSB1c2VkIGluIFNlY3Rpb24gMi4yLjMsIHdoZXJlIGEgc21hbGwgdG95IGRhdGFzZXQgd2FzIGVtcGxveWVkLiBFYWNoIHN0ZXAgd2lsbCBiZSBkb2N1bWVudGVkIGluIHRoZSBhY2NvbXBhbnlpbmcgY29kZS4NCg0KKipEYXRhIFNldCoqOiAgTGV0J3MgdXNlIHdpbmQgc3BlZWQgZGF0YSAoaW4gbS9zKSBmcm9tIGEgd2luZCBlbmVyZ3kgYXBwbGljYXRpb24uIFRoZSBXZWlidWxsIGRpc3RyaWJ1dGlvbiBpcyBjb21tb25seSB1c2VkIHRvIG1vZGVsIHdpbmQgc3BlZWRzIGZvciB3aW5kIHBvd2VyIGdlbmVyYXRpb24gYW5hbHlzaXMuDQoNCjEyLjQgIDIuNyAgNC4zICA0LjMgMTEuMSAgMi41ICA1LjMgIDguNyAxMS40ICA0LjIgIDcuNSAgNi41IDEyLjEgIDMuMiAgMi41ICA4LjUgDQoNCjQuMiAgNy4yIDE2LjAgIDcuMCAgOS41ICA2LjMgIDcuOSAgMi43IDEwLjkgMS4xIDQuNiAxMC40ICA0LjIgMC42ICA0LjggIDQuOCAzLjcgDQoNCjE1LjYgMTMuMyAgMC40IDEyLjEgIDMuMiAxNS4yICAxLjUgMi41ICA2LjIgNS40ICAzLjQgMi44ICAwLjggNC4wIDAuNSAgNS40ICA2LjUNCg0KXA0KDQoNCiMjIEltcGxlbWVudGF0aW9uIG9mIGBvcHRpbSgpYCANCg0KYG9wdGltKClgIGlzIGEgcG93ZXJmdWwgYnV0ICoqYmxhY2stYm94Kiogb3B0aW1pemF0aW9uIHJvdXRpbmUuIEJsaW5kbHkgYWNjZXB0aW5nIGl0cyBvdXRwdXQgY2FuIGxlYWQgdG8gd3JvbmcgZXN0aW1hdGVzLCBtaXNsZWFkaW5nIHVuY2VydGFpbnR5IHF1YW50aWZpY2F0aW9uLCBhbmQgaW5jb3JyZWN0IGluZmVyZW5jZXMuIFdoZW4gdXNlIGl0IHRvIGZpbmQgdGhlIE1MRSwgcGxlYXNlIHBheSBhdHRlbnRpb24gdG8gdGhlIGZvbGxvd2luZyBrZXkgaW5mb3JtYXRpb24uDQoNCioqS2V5IENhdXRpb25hcnkgUG9pbnRzKioNCg0KKiAqKkxvY2FsIHZzLiBnbG9iYWwgb3B0aW1hKio6IGBvcHRpbSgpYCBmaW5kcyBhIGxvY2FsIG9wdGltdW0sIG5vdCBuZWNlc3NhcmlseSB0aGUgZ2xvYmFsIE1MRS4gVGhpcyBpcyBlc3BlY2lhbGx5IHByb2JsZW1hdGljIGZvciBtdWx0aS1tb2RhbCBsaWtlbGlob29kcy4NCg0KKiAqKkNvbnZlcmdlbmNlIGNvZGVzIGFyZSBub3QgZ3VhcmFudGVlcyoqOiBBIGNvbnZlcmdlbmNlIGNvZGUgb2YgMCAqKmRvZXMgbm90KiogZ3VhcmFudGVlIHlvdeKAmXZlIGZvdW5kIHRoZSB0cnVlIE1MRSwgb25seSB0aGF0IG9wdGltKCnigJlzIGludGVybmFsIHN0b3BwaW5nIGNvbmRpdGlvbnMgd2VyZSBtZXQuIDxmb250IGNvbG9yID0gInJlZCI+KipIb3dldmVyLCBpZiBpdCBpcyBub3QgMCwgdGhlIHJlcG9ydGVkIHBhcmFtZXRlciB2YWx1ZSBpcyBub3QgdGhlIHRydWUgTUxFLioqIDwvZm9udD4NCg0KKiAqKlNlbnNpdGl2aXR5IHRvIGluaXRpYWwgdmFsdWVzKio6IERpZmZlcmVudCBzdGFydGluZyBwb2ludHMgY2FuIGxlYWQgdG8gZGlmZmVyZW50IHJlc3VsdHMuICoqVHJ5IHNldmVyYWwgc2V0IG9mIHNsaWdodGx5IGRpZmZlcmVudCBpbml0aWFsIHZhbHVlcyB0byB0ZXN0IHRoZSByZXN1bHRpbmcgcGFyYW1ldGVyIHZhbHVlcyBhcmUgc3RhYmxlKiouDQoNCiogKipJbmNvcnJlY3QgSGVzc2lhbiBhcHByb3hpbWF0aW9uKio6IElmIHlvdSB1c2UgYGhlc3NpYW4gPSBUUlVFYCwgYG9wdGltKClgIHJldHVybnMgYSBmaW5pdGUtZGlmZmVyZW5jZSBhcHByb3hpbWF0aW9uLCB3aGljaCBjYW4gYmUgaW5hY2N1cmF0ZSAoZXNwZWNpYWxseSBpZiBwYXJhbWV0ZXJzIGFyZSBhdCB2ZXJ5IGRpZmZlcmVudCBzY2FsZXMpLg0KDQoqICoqQm91bmRhcnkgaXNzdWVzKio6IGBvcHRpbSgpYCBjYW4gY29udmVyZ2UgdG8gdmFsdWVzIGF0IHRoZSBib3VuZGFyeSBvZiBwbGF1c2libGUgcGFyYW1ldGVyIHNwYWNlLCB3aGljaCBtYXkgbm90IHNhdGlzZnkgdGhlb3JldGljYWwgcmVndWxhcml0eSBjb25kaXRpb25zIGZvciBNTEUgYXN5bXB0b3RpY3MuDQoNCiogKipQb29ybHkgYmVoYXZlZCBsaWtlbGlob29kKio6IEZsYXQgcmVnaW9ucywgZGlzY29udGludWl0aWVzLCBvciBudW1lcmljYWwgaW5zdGFiaWxpdHkgY2FuIGNhdXNlIGBvcHRpbSgpYCB0byBmYWlsIHNpbGVudGx5Lg0KDQpcDQoNCiMjIDxmb250IGNvbG9yID0gImJsdWUiPioqXGNvbG9ye2JsdWV9U3VnZ2VzdGVkIFN5bnRheCBmb3IgQ2FsbGluZyBgb3B0aW0oKWAqKjwvZm9udD4NCg0KSW4gdGhpcyBzdWJzZWN0aW9uLCB3ZSBlbXBsb3kgYSBjb21tb24gb3B0aW1pemF0aW9uIHRlY2huaXF1ZTogdXNpbmcgdGhlIGNvbnRyb2wgc3RhdGVtZW50IGluIGBvcHRpbSgpYCB0byByZXF1ZXN0IG1heGltaXphdGlvbiBvZiB0aGUgbG9nLWxpa2VsaWhvb2QuIFRoaXMgYXBwcm9hY2ggc3BhcmVzIHVzIGZyb20gbWFudWFsbHkgYWRkaW5nIG5lZ2F0aXZlIHNpZ25zIHRvIHRoZSBsb2ctbGlrZWxpaG9vZCBhbmQgZ3JhZGllbnQgZnVuY3Rpb25zLiBTaW5jZSB0aGUgZGVyaXZhdGlvbnMgaGF2ZSBhbHJlYWR5IGJlZW4gY292ZXJlZCwgd2Ugd2lsbCBub3QgcmVwZWF0IHRoZW0gaGVyZS4gUGxlYXNlIGV4YW1pbmUgdGhlIGNvZGUgY2xvc2VseSB0byB1bmRlcnN0YW5kIHRoZSBpbXBsZW1lbnRhdGlvbi4NCg0KPGZvbnQgY29sb3IgPSAicmVkIj4qKktFWSBJTVBMRU1FTlRBVElPTiBTVEVQUyoqPC9mb250Pg0KDQpcDQoNCg0KKipTdGVwIDE6IERhdGEgTG9hZGluZyoqDQoNCmBgYHtyfQ0Kd3NwZWVkIDwtIGMoMTIuNCwgMi43LCA0LjMsIDQuMywgMTEuMSwgMi41LCA1LjMsIDguNywgMTEuNCwgNC4yLCA3LjUsIDYuNSwgMTIuMSwgMy4yLCANCiAgICAgICAgICAgIDIuNSwgOC41LCA0LjIsIDcuMiwgMTYuMCwgNy4wLCA5LjUsIDYuMywgNy45LCAyLjcsIDEwLjksIDEuMSwgNC42LCAxMC40LCANCiAgICAgICAgICAgIDQuMiwgMC42LCA0LjgsIDQuOCwgMy43LCAxNS42LCAxMy4zLCAwLjQsIDEyLjEsIDMuMiwgMTUuMiwgMS41LCAyLjUsIDYuMiwgDQogICAgICAgICAgICA1LjQsIDMuNCwgMi44LCAwLjgsIDQuMCwgMC41LCA1LjQsIDYuNSkNCmBgYA0KDQoqKlN0ZXAgMjogTGlrZWxpaG9vZCBhbmQgR3JhZGllbnQgRnVuY3Rpb25zKioNCg0KV2UgdHJhbnNsYXRlIHRoZSBsb2ctbGlrZWxpaG9vZCBmdW5jdGlvbiBhbmQgc2NvcmUgKGdyYWRpZW50KSBmdW5jdGlvbnMgaW4gc2VjdGlvbiAyLjIuMyBpbnRvIFIgY29kZSBkaXJlY3RseSBpbiB0aGUgZm9sbG93aW5nLg0KDQpgYGB7cn0NCiMjIw0KIyAqKk5lZ2F0aXZlKiogbG9nLWxpa2VsaWhvb2QgZnVuY3Rpb24gZm9yIFdlaWJ1bGwgZGlzdHJpYnV0aW9uDQpsb2dfbGlrZWxpaG9vZCA8LSBmdW5jdGlvbihwYXJhbXMsIGRhdGEpIHsNCiAgayA8LSBwYXJhbXNbMV0gICAgICAgIyBzaGFwZSBwYXJhbWV0ZXINCiAgbGFtYmRhIDwtIHBhcmFtc1syXSAgIyBzY2FsZSBwYXJhbWV0ZXINCiAgDQogICMgRW5zdXJlIHBhcmFtZXRlcnMgYXJlIHBvc2l0aXZlDQogIGlmIChrIDw9IDAgfHwgbGFtYmRhIDw9IDApIHsNCiAgICByZXR1cm4oMWUxMCkgICMgUmV0dXJuIGxhcmdlIHZhbHVlIGZvciBpbnZhbGlkIHBhcmFtZXRlcnMNCiAgfQ0KICANCiAgbiA8LSBsZW5ndGgoZGF0YSkNCiAgbG9nX2xpayA8LSBuICogbG9nKGspIC0gbiAqIGsgKiBsb2cobGFtYmRhKSArIA0KICAgIChrIC0gMSkgKiBzdW0obG9nKGRhdGEpKSAtIHN1bSgoZGF0YSAvIGxhbWJkYSleaykNCiAgDQogIHJldHVybihsb2dfbGlrKSAgIyBSZXR1cm4gbG9nLWxpa2VsaWhvb2QhIE5PVCB0aGUgbmVnYXRpdmUgbG9nLWxpa2VsaWhvb2QNCn0NCiMjIw0KIyMjDQojIEdyYWRpZW50IG9mICoqbmVnYXRpdmUqKiBsb2ctbGlrZWxpaG9vZCBmdW5jdGlvbg0KbG9nX2xpa2VsaWhvb2RfZ3JhZGllbnQgPC0gZnVuY3Rpb24ocGFyYW1zLCBkYXRhKSB7DQogIGsgPC0gcGFyYW1zWzFdICAgICAgICMgc2hhcGUgcGFyYW1ldGVyDQogIGxhbWJkYSA8LSBwYXJhbXNbMl0gICMgc2NhbGUgcGFyYW1ldGVyDQogIA0KICBuIDwtIGxlbmd0aChkYXRhKQ0KICANCiAgIyBQYXJ0aWFsIGRlcml2YXRpdmVzDQogIGRrIDwtIG4vayAtIG4gKiBsb2cobGFtYmRhKSArIHN1bShsb2coZGF0YSkpIC0gDQogICAgICAgIHN1bShsb2coZGF0YS9sYW1iZGEpICogKGRhdGEvbGFtYmRhKV5rKQ0KICANCiAgZGxhbWJkYSA8LSAgKGsvbGFtYmRhKSooc3VtKChkYXRhL2xhbWJkYSleaykgLW4pDQogIA0KICByZXR1cm4oYyhkaywgZGxhbWJkYSkpICAjIEdyYWRpZW50IG9mIGxvZy1saWtlbGlob29kLCBOT1QgdGhlIG5lZ2F0aXZlIHNjb3Jlcw0KfQ0KDQpgYGANCg0KDQoqKlN0ZXAgMzogQ2FsbGluZyBgb3B0aW0oKWAqKg0KDQpgYGB7cn0NCiMgRmluZGluZyBJbml0aWFsIFZhbHVlcw0KIyMgSXQgaXMgY3JpdGljYWwgdG8gc2VsZWN0IGFwcHJvcHJpYXRlIGluaXRpYWwgdmFsdWVzIHRvDQojIyBlbnN1cmUgZmFzdCBjb252ZXJnZW5jZS4gSW4gZ2VuZXJhbCwgd2UgY2FuIHVzZSB3aGF0ZXZlcg0KIyMgbWV0aG9kcyAoc3VjaCBhcyBNTUUpIHRoYXQgYXJlIGF2YWlsYWJsZSB0byBnZXQgYXBwcm9wcmlhdGUNCiMjIGluaXRpYWwgdmFsdWVzDQoNCiMgSW5pdGlhbCBwYXJhbWV0ZXIgZXN0aW1hdGVzIChtZXRob2Qgb2YgbW9tZW50cykNCg0KaW5pdGlhbF9rIDwtIChzZCh3c3BlZWQpL21lYW4od3NwZWVkKSleKC0xLjA4NikNCg0KaW5pdGlhbF9sYW1iZGEgPC0gbWVhbih3c3BlZWQpL2dhbW1hKDEgKyAxL2luaXRpYWxfaykNCg0KIyMjIw0KIyBNTEUgdXNpbmcgb3B0aW0oKSB3aXRoIGdyYWRpZW50DQptbGVfcmVzdWx0IDwtIG9wdGltKA0KICAjcGFyID0gYyhpbml0aWFsX2ssaW5pdGlhbF9sYW1iZGEpLA0KICBwYXIgPSBjKDEsNiksDQogIGZuID0gbG9nX2xpa2VsaWhvb2QsDQogIGdyID0gbG9nX2xpa2VsaWhvb2RfZ3JhZGllbnQsDQogIGRhdGEgPSB3c3BlZWQsDQogIG1ldGhvZCA9ICJMLUJGR1MtQiIsICAgICAgICAgIyBCRkdTIGNhbiB1c2UgZ3JhZGllbnQgaW5mb3JtYXRpb24gTC1CRkdTLUINCiAgaGVzc2lhbiA9IFRSVUUsICAgICAgICAgICMgdGhpcyBpcyB0aGUgb2JzZXJ2ZWQgSGVzc2lhbiBtYXRyaXggDQogIGNvbnRyb2wgPSBsaXN0KG1heGl0ID0gMTAwMCwgDQogICAgICAgICAgICAgICAgIGZuc2NhbGUgID0gLTEsDQogICAgICAgICAgICAgICAgIHRyYWNlID0gRkFMU0UsDQogICAgICAgICAgICAgICAgIGFic3RvbCA9IDFlLTgpDQopDQojIw0KbWxlX3Jlc3VsdA0KYGBgDQoNClRvIGNoZWNrIHRoZSB2YWxpZGl0eSBvZiB0aGUgYWJvdmUgcHJvY2VkdXJlLCB3ZSB1c2UgYW4gYWx0ZXJuYXRpdmUgUiBmdW5jdGlvbiB0byBmaW5kIHRoZSBNTEUgb2YgdGhpcyBzcGVjaWFsIFdlaWJ1bGwgZGlzdHJpYnV0aW9uOg0KDQpgYGB7cn0NCmZpdGRpc3Qod3NwZWVkLCAid2VpYnVsbCIsIG1ldGhvZCA9ICJtbGUiLCBjYWxjdmNvdj1UUlVFKQ0KYGBgDQoNCg0KVGhlIHR3byBwcm9jZWR1cmVzIHlpZWxkcyB0aGUgcmVzdWx0cyENCg0KDQoNCjxmb250IGNvbG9yID0gImRhcmtyZWQiPioqQ0FVVElPTioqPC9mb250PjogQmVmb3JlIHJlcG9ydGluZyBhbnkgZXN0aW1hdGVzLCB2YWxpZGF0ZSB0aGUgb3B0aW1pemF0aW9uIG91dHB1dCB3aXRoIHRoZSBmb2xsb3dpbmcgc3RlcHM6DQoNCiogKipDaGVjayB0aGUgY29udmVyZ2VuY2UgY29kZSoqLiBBIGNvZGUgb2YgMCBpbmRpY2F0ZXMgdGhlIGFsZ29yaXRobSBjb21wbGV0ZWQgaXRzIHByb2Nlc3MsIGJ1dCB0aGlzIGlzIG9ubHkgYW4gaW50ZXJuYWwgY2hlY2vigJRpdCBkb2VzIG5vdCBjb25maXJtIHRoZSBwYXJhbWV0ZXJzIGFyZSB0aGUgdHJ1ZSBNTEUuDQoNCiogKipUZXN0IGRpZmZlcmVudCBzdGFydGluZyB2YWx1ZXMqKi4gVGhlIGZpbmFsIHBhcmFtZXRlciBlc3RpbWF0ZXMgc2hvdWxkIG5vdCBiZSBpZGVudGljYWwgdG8gdGhlIGluaXRpYWwgZ3Vlc3Nlcy4gUnVubmluZyB0aGUgb3B0aW1pemF0aW9uIGZyb20gbXVsdGlwbGUgc3RhcnRpbmcgcG9pbnRzIGhlbHBzIHZlcmlmeSB0aGF0IHRoZSBzb2x1dGlvbiBpcyByb2J1c3QgYW5kIG5vdCBhbiBhcnRpZmFjdCBvZiB0aGUgaW5pdGlhbCBjb25kaXRpb25zLg0KDQoqICoqVmVyaWZ5IHRoZSBncmFkaWVudCBpcyBuZWFyIHplcm8qKi4gQ29tcHV0ZSB0aGUgZ3JhZGllbnQgYXQgdGhlIHJlcG9ydGVkIHNvbHV0aW9uLiBBIG5lYXItemVybyBncmFkaWVudCBjb25maXJtcyBhIGNyaXRpY2FsIHBvaW50IGhhcyBiZWVuIHJlYWNoZWQuDQoNCiogKipJbnNwZWN0IHRoZSBpbnZlcnNlIEhlc3NpYW4qKi4gQ2FsY3VsYXRlIHRoZSBpbnZlcnNlIG9mIHRoZSBIZXNzaWFuIG1hdHJpeC4gVGhlIGRpYWdvbmFsIGVsZW1lbnRzIG9mIHRoaXMgbWF0cml4ICh0aGUgZXN0aW1hdGVkIHZhcmlhbmNlcykgbXVzdCBiZSBwb3NpdGl2ZS4NCg0KKiBJZiBgb3B0aW0oKWAgZmFpbHMgdG8gd29yayBwcm9wZXJseSwgY29uc2lkZXIgdXNpbmcgYWx0ZXJuYXRpdmUgb3B0aW1pemF0aW9uIGZ1bmN0aW9ucyBsaWtlIGBvcHRpbXgoKWAgKCoqb3B0aW14KiogcGFja2FnZSksIGBubG1pbmIoKWAvYG5sbSgpYCAoKipzdGF0cyoqIHBhY2thZ2UpLCBvciBgREVvcHRpbSgpYCAoKipERW9wdGltKiogcGFja2FnZSkgZm9yIGdsb2JhbCBvcHRpbWl6YXRpb24uDQoNCg0KDQoqKlN0ZXAgNDogQ2hlY2tpbmcgU2NvcmUgYW5kIE9ic2VydmVkIEZpc2hlciBJbmZvcm1hdGlvbiBNYXRyaXgqKg0KDQpUaGUgc2NvcmUgZXF1YXRpb25zIGluIHRoZSBmb2xsb3dpbmcgY29kZS4NCg0KYGBge3J9DQpsb2dfbGlrZWxpaG9vZF9ncmFkaWVudChtbGVfcmVzdWx0JHBhciwgd3NwZWVkKQ0KYGBgDQoNCkJvdGggc2NvcmUgZnVuY3Rpb25zIGFyZSBjbG9zZSB0byB6ZXJvIGFzIGV4cGVjdGVkLiBUaGUgKiplc3RpbWF0ZWQgY292YXJpYW5jZSBtYXRyaXgqKiwgdGhlIGludmVyc2Ugb2YgdGhlIG5lZ2F0aXZlIEhlc3NpYW4sIGNhbiBiZSBleHRyYWN0ZWQgZnJvbSB0aGUgYG9wdGltKClgIGluIHRoZSBmb2xsb3dpbmcNCg0KYGBge3J9DQpIZXNzIDwtIG1sZV9yZXN1bHQkaGVzc2lhbg0KY292YXI8LSBzb2x2ZSgtSGVzcykgICMgc29sdmUoKSBmaW5kcyB0aGUgaW52ZXJzZSBvZiBhIHNxdWFyZSBtYXRyaXgNCmNvdmFyDQpgYGANCg0KKipTdGVwIDU6IEZpbmFsIFNhbXBsaW5nIERpc3RyaWJ1dGlvbiBvZiBNTEUiKioNCg0KJCQNClxiZWdpbntibWF0cml4fQ0KXGhhdHtcYWxwaGF9IC0gXGFscGhhXFxbNHB0XQ0KXGhhdHtcYmV0YX0gLSBcYmV0YQ0KXGVuZHtibWF0cml4fSBcdG8NClxtYXRoY2Fse059XzIgXGxlZnQoDQpcYmVnaW57Ym1hdHJpeH0NCjBcXFs0cHRdDQowDQpcZW5ke2JtYXRyaXh9LCBcIFxiZWdpbntibWF0cml4fQ0KMC4wMjg3MTEzNSAmIDAuMDM1ODM5NDlcXFs0cHRdDQowLjAzNTgzOTQ5ICYgMC40NjU4MDAxMg0KXGVuZHtibWF0cml4fSANClxyaWdodCkNCiQkDQoNClRoZSB0d28gbWFyZ2luYWwgZGlzdHJpYnV0aW9ucyBhcmUgZXhwbGljaXRseSBnaXZlbiBiZWxvdw0KDQokJA0KXGhhdHtcYWxwaGF9IFx0byBOKFxhbHBoYSwgXHNpZ21hX1xhbHBoYV4yID0gMC4wMjg3KSBcIFwgXHRleHR7IGFuZCB9IFwgXCBcaGF0e1xiZXRhfSBcdG8gTihcYmV0YSwgXHNpZ21hX1xiZXRhXjIgPSAwLjQ2NTgpDQokJA0KDQpUaGUgYXN5bXB0b3RpYyB1bml2YXJpYXRlIGRpc3RyaWJ1dGlvbnMgZGlzY3Vzc2VkIGFib3ZlIHdpbGwgZm9ybSB0aGUgYmFzaXMgZm9yIHN1YnNlcXVlbnQgaW5mZXJlbmNlIHByb2NlZHVyZXMgaW4gdGhlIGZvbGxvd2luZyBtb2R1bGVzLg0KDQpcDQoNCioqQ29uY2x1ZGluZyBSZW1hcmtzKio6IFdlIGhhdmUgZXhhbWluZWQgc2V2ZXJhbCBvcHRpbWl6YXRpb24gZnVuY3Rpb25zIGF2YWlsYWJsZSBpbiBSIHBhY2thZ2VzLiBBZnRlciBwZXJmb3JtaW5nIGFwcHJvcHJpYXRlIGNoZWNrcyB0byBlbnN1cmUgdGhlIHBhcmFtZXRlciBlc3RpbWF0ZXMgY29uc3RpdHV0ZSBtYXhpbXVtIGxpa2VsaWhvb2QgZXN0aW1hdGVzLCB0aGUgSGVzc2lhbiBtYXRyaXggc2hvdWxkIGJlIGV4dHJhY3RlZCBhbmQgaW52ZXJ0ZWQgdG8gb2J0YWluIHRoZSBjb3ZhcmlhbmNlIG1hdHJpeCBmb3Igc3Vic2VxdWVudCBpbmZlcmVuY2UuIFdoZW4gdXRpbGl6aW5nIGZ1bmN0aW9ucyBvdGhlciB0aGFuIGBvcHRpbSgpYCwgeW91IHNob3VsZCBjb25zdWx0IHRoZSBjb3JyZXNwb25kaW5nIGRvY3VtZW50YXRpb24gb3IgQUkgdG9vbHMgdG8gdW5kZXJzdGFuZCB0aGUgZXhwZWN0ZWQgaW5wdXRzIGFuZCB0aGUgbmF0dXJlIG9mIHRoZSBvdXRwdXRzLiBCZWZvcmUgYXBwbHlpbmcgb3B0aW1pemF0aW9uIG1ldGhvZHMgdG8geW91ciBhbmFseXRpY2FsIHRhc2tzLCBpdCBpcyBoZWxwZnVsIHRvIHByYWN0aWNlIHdpdGggbnVtZXJpY2FsIGV4YW1wbGVzIGZyb20gdGhlIGRvY3VtZW50YXRpb24gb3IgdGhvc2UgZ2VuZXJhdGVkIGJ5IEFJIHRvb2xzLg0KDQoNCg0KDQoNCg0KDQoNCg==