Assignment Objectives

  • Comprehend the likelihood function and its properties.

  • Master the maximum likelihood estimation framework and required components.

  • Understand the plug-in principle underlying MLE.

  • Implement maximum likelihood estimation procedures in R.


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.


Gamma Distribution Revisited

Let \(X\) be the two parameter Gamma random variable with density function

\[ f(x \mid \alpha, \beta) = \frac{1}{\Gamma(\alpha)\beta^\alpha} x^{\alpha-1} e^{-x/\beta} \ \ \text{for} \ \ x > 0, \]

where with \(\alpha > 0\) (shape), \(\beta>0\) (scale), and

\[ \Gamma(\alpha) = \int_{0}^{\infty} t^{\alpha-1} e^{-t} \, dt, \quad \alpha > 0. \]

\(\Gamma(x)\) can be computed in R using the gamma() function. The derivative of \(\Gamma(x)\) are given respectively by

\[ \Gamma^\prime(z) = \Gamma (z)\psi_0(z) \]

where \(\psi_0(z) = \frac{d}{dz} \ln \Gamma{z}\). In R, the digamma function \(\psi_0(z)\) is evaluated by digamma().


This assignment focuses on finding maximum likelihood estimate of parameters \(\alpha\) and \(\beta\) based on a real-world application data set.


Question 1: Derive gradient (first order partial derivative) of likelihood function

Assume that \(\{x_1, x_2, \cdots, x_n \} \to \text{ gamma }(\alpha, \beta)\) with density function given by

\[ f(x \mid \alpha, \beta) = \frac{1}{\Gamma(\alpha)\beta^\alpha} x^{\alpha-1} e^{-x/\beta} \ \ \text{for} \ \ x > 0, \]

Derive the gradient of the log-likelihood function with respect to the gamma distribution parameters \(\alpha\) and \(\beta\). To this end,

a). Write out the full log-likelihood function based on the given data and the density function provided above.

Answer to Question 1 Part A

The Gamma distribution is defined by the probability density function:

\[ f(x \mid \alpha, \beta) = \frac{1}{\Gamma(\alpha)\beta^\alpha} x^{\alpha-1} e^{-x/\beta} \ \ \text{for} \ \ x > 0 \]

where \(\alpha > 0\) is the shape parameter and \(\beta>0\) is the scale parameter.

Therefore the likelihood function is:

\[ L(\alpha,\beta \mid x)=\prod_{i=1}^{n}{f(x_i\mid\alpha,\beta)}=\prod_{i=1}^{n}{\frac{1}{\Gamma(\alpha)\beta^{\alpha}}x_i^{\alpha-1}e^{-x_i/\beta}} \]

And the log-likelihood function is:

\[ \ell(\alpha,\beta\mid x)=\ln{L(\alpha,\beta \mid x)}=\sum_{i=1}^{n}{\ln{\left[\frac{1}{\Gamma(\alpha)\beta^{\alpha}}x_i^{\alpha-1}e^{-x_i/\beta}\right]}} \]

This can be further simplified to:

$$ \[\begin{aligned} \ell(\alpha,\beta\mid x) &= \sum_{i=1}^{n}{\ln{\left[\frac{1}{\Gamma(\alpha)\beta^{\alpha}}x_i^{\alpha-1}e^{-x_i/\beta}\right]}} \\\\ &= \sum_{i=1}^{n}{\left[\ln{1}-(\ln{\Gamma(\alpha)}+\alpha\ln{\beta})+(\alpha-1)\ln{x_i}-\frac{x_i}{\beta}\right]}\\\\ &= -n\ln{\Gamma(\alpha)}-n\alpha\ln{\beta}+(\alpha-1)\sum_{i=1}^{n}{\ln{x_i}}-\frac{1}{\beta}\sum_{i=1}^{n}{x_i} \end{aligned}\]

$$

Therefore, the simplifed log-liklihood function is:

\[ \ell(\alpha,\beta\mid x)=-n\ln{\Gamma(\alpha)}-n\alpha\ln{\beta}+(\alpha-1)\sum_{i=1}^{n}{\ln{x_i}}-\frac{1}{\beta}\sum_{i=1}^{n}{x_i} \]

b). Derive the score functions (the gradient of the log-likelihood) from the full log-likelihood function in part (a).

Answer to Question 1 Part B

To find the first score function we will differentiate with respect \(\beta\).

$$ \[\begin{aligned} \frac{\partial\ell}{\partial\beta} &= \frac{\partial}{\partial\beta}\left[-n\ln{\Gamma(\alpha)}-n\alpha\ln{\beta}+(\alpha-1)\sum_{i=1}^{n}{\ln{x_i}}-\frac{1}{\beta}\sum_{i=1}^{n}{x_i}\right]\\\\ &= -n\alpha\frac{1}{\beta}+\frac{1}{\beta^2}\sum_{i=1}^{n}{x_i} \end{aligned}\]

$$

To find the second score function we will differentiate with respect of \(\alpha\):

$$ \[\begin{aligned} \frac{\partial\ell}{\partial\alpha} &= \frac{\partial}{\partial\alpha} \left[-n\ln{\Gamma(\alpha)}-n\alpha\ln{\beta}+(\alpha-1)\sum_{i=1}^{n}{\ln{x_i}}-\frac{1}{\beta}\sum_{i=1}^{n}{x_i}\right] \\\\ &= -n\frac{\Gamma (\alpha)\psi_0(\alpha)}{\Gamma(\alpha)}-n\ln{\beta}+\sum_{i=1}^{n}{\ln{x_i}} \end{aligned}\]

$$


Question 2: Birth data set

The following R code reads in a data set containing, for each of 7 days, the lengths of time in hours spent by women in the delivery suite while giving birth (without a ceasarian section) at John Radcliffe Hospital in Oxford, England. The data are taken from Davison (Statistical Models. Cambridge University Press, 2003).

2.1, 3.4, 4.25, 5.6, 6.4, 7.3, 8.5, 8.75, 8.9, 9.5, 9.75, 10, 10.4, 10.4, 16, 19,
4, 4.1, 5, 5.5, 5.7, 6.5, 7.25, 7.3, 7.5, 8.2, 8.5, 9.75, 11, 11.2, 15, 16.5, 2.6, 
3.6, 3.6, 6.4, 6.8, 7.5, 7.5, 8.25, 8.5, 10.4, 10.75, 14.25, 14.5, 1.5, 4.7, 4.7, 
7.2, 7.25, 8.1, 8.5, 9.2, 9.5, 10.7, 11.5, 2.5, 2.5, 3.4, 4.2, 5.9, 6.25, 7.3, 7.5, 
7.8, 8.3, 8.3, 10.25, 12.9, 14.3, 4, 4, 5.25, 6.1, 6.5, 6.9, 7, 8.45, 9.25, 10.1, 
10.2, 12.75, 14.6, 2, 2.7, 2.75, 3.4, 4.2, 4.3, 4.9, 6.25, 7, 9, 9.25, 10.7

Assume the data are generated from a gamma distribution. The objective is to use these data and the designated algorithm to find the maximum likelihood estimates (MLEs) of the parameters \(\alpha\) and \(\beta\).

a). Find the MLEs of \(\alpha\) and \(\beta\), denoted by \(\hat{\alpha}\) and \(\hat{\beta}\), using gradient-based optimization via the R function optim() with the gradient vector derived in Question 1.

Answer to Question 2 Part A

birth <- c(2.1, 3.4, 4.25, 5.6, 6.4, 7.3, 8.5, 8.75, 8.9, 9.5, 9.75, 10, 10.4, 10.4, 16, 19,
4, 4.1, 5, 5.5, 5.7, 6.5, 7.25, 7.3, 7.5, 8.2, 8.5, 9.75, 11, 11.2, 15, 16.5, 2.6, 
3.6, 3.6, 6.4, 6.8, 7.5, 7.5, 8.25, 8.5, 10.4, 10.75, 14.25, 14.5, 1.5, 4.7, 4.7, 
7.2, 7.25, 8.1, 8.5, 9.2, 9.5, 10.7, 11.5, 2.5, 2.5, 3.4, 4.2, 5.9, 6.25, 7.3, 7.5, 
7.8, 8.3, 8.3, 10.25, 12.9, 14.3, 4, 4, 5.25, 6.1, 6.5, 6.9, 7, 8.45, 9.25, 10.1, 
10.2, 12.75, 14.6, 2, 2.7, 2.75, 3.4, 4.2, 4.3, 4.9, 6.25, 7, 9, 9.25, 10.7)

#Used to enter log-logistic function
gamma.loglik <- function(params, data) {
  shape <- params[1]  # Used to get initial parameters
  scale <- params[2]
  n <- length(data)   # Used to get sample size
  

  loglik <- -n*log(gamma(shape))-n*shape*log(scale)+(shape-1)*sum(log(data))-(1/scale)*sum(data) 
  
  return(loglik)    # Return negative for minimization
}


# Used to enter gradient functions

gamma.score <- function(params, data) {
  shape <- params[1] #Used to get initial parameters
  scale <- params[2]
  n <- length(data) #Used to get sample size
  
  # Gradient for shape parameter
  grad_shape <-  -n*digamma(shape)-n*log(scale)+sum(log(data))
  
  # Gradient for scale parameter
  grad_scale <- -n*shape*(1/scale)+(1/(scale**2))*sum(data)
  
  return(c(grad_shape, grad_scale))
}


# Entering initial guessed parameters
initial.params <- c(shape = 2.2, scale = 1.5)  


# Using optim and previous functions to get results
mle.result <- optim(
  par = initial.params,
  fn = gamma.loglik,
  gr = gamma.score,
  data = birth,
  method = "L-BFGS-B",
  lower = c(1e-6, 1e-6),
  hessian = TRUE,
  control = list(trace = FALSE,
                 fnscale = -1,
                 maxit = 500,
                 abstol = 1e-8)
)
##
mle.result #printing mle.result determined earlier
$par
   shape    scale 
4.387881 1.760111 

$value
[1] -251.1173

$counts
function gradient 
      15       15 

$convergence
[1] 0

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

$hessian
          shape      scale
shape -24.30316  -53.97386
scale -53.97386 -134.55458

Therefore the MLE estimations for \(\alpha\) and \(\beta\) are \(\hat{\alpha}=4.387881\) and \(\hat{\beta}=1.760111\).

b). Apply the method of moments to obtain estimators for \(\alpha\) and \(\beta\). Denote these moment estimators as \(\tilde{\alpha}\) and \(\tilde{\beta}\).

Answer to Question 2 Part B

As determined in the 5th Week Lecture, the method of moment estimators for a gamma distribution are:

$$ \[\begin{aligned} \hat{\mu} &= \frac{1}{n}\sum_{i=1}^{n}{X_i}=\bar{X}\\\\ \hat{\sigma^2} &= \frac{1}{n}\sum_{i=1}^{n}{X_i^2-\bar{X}^2}=\frac{1}{n}\sum_{i=1}^{n}{(X_i-\bar{X})^2} \end{aligned}\]

$$

We can use these method of moment estimators to obtain estimators for \(\alpha\) and \(\beta\) for our datset:

# Method of Moments estimation
mom_mu <- mean(birth) #Used to get moments from sample
mom_sigma_sq <- mean(birth^2) - mom_mu^2
mom_sigma <- sqrt(mom_sigma_sq)

cat("MoM estimates: μ_tilde =", round(mom_mu, 3), #Used to print moments
    ", σ_tilde =", round(mom_sigma, 3), "\n")
MoM estimates: μ_tilde = 7.723 , σ_tilde = 3.549 

Therefore the MME estimations for \(\alpha\) and \(\beta\) are \(\tilde{\alpha}=7.723\) and \(\tilde{\beta}=3.549\).

c). Conduct a brief literature review comparing the method of moments estimation (MME) and maximum likelihood estimation (MLE). Synthesize the key advantages and limitations of each, concluding with a practical recommendation.

Answer to Question 2 Part C

Method of moments estimation and maximum likelihood estimation are both methods of estimating the parameters of a distribution using sample data. Method of moments attempts to estimate these parameters by matching moments of the sample to moments of a theoretical probability model. Alternatively, maximum likelihood estimation considers how likely certain parameter values are given the sampled data. Given that MME only considers a few specific moments, it is less powerful, but also less computationally intense. Alternatively, MLE is more computationally intense but more powerful method of estimating parameters. MME would most likely be better if you just need a rough estimate of the parameters, while MLE might be better if you need a result that takes into account the entire shape of a probability distribution.

LS0tDQp0aXRsZTogIkFzc2lnbm1lbnQgNDogTWF4aW11bSBMaWtlbGlob29kIEVzdGltYXRpb24iDQphdXRob3I6ICJHcmFjZSBMaXBwZXJ0ICINCmRhdGU6ICIgRHVlOiAzLzMvMjAyNiINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDogDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDQNCiAgICB0b2NfZmxvYXQ6IHllcw0KICAgIG51bWJlcl9zZWN0aW9uczogbm8NCiAgICB0b2NfY29sbGFwc2VkOiB5ZXMNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMNCiAgICBzbW9vdGhfc2Nyb2xsOiB5ZXMNCiAgICB0aGVtZTogbHVtZW4NCiAgcGRmX2RvY3VtZW50OiANCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogNA0KICAgIGZpZ19jYXB0aW9uOiB5ZXMNCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcw0KICAgIGZpZ193aWR0aDogMw0KICAgIGZpZ19oZWlnaHQ6IDMNCiAgd29yZF9kb2N1bWVudDogDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDQNCiAgICBmaWdfY2FwdGlvbjogeWVzDQogICAga2VlcF9tZDogeWVzDQplZGl0b3Jfb3B0aW9uczogDQogIGNodW5rX291dHB1dF90eXBlOiBpbmxpbmUNCi0tLQ0KDQpgYGB7Y3NzLCBlY2hvID0gRkFMU0V9DQojVE9DOjpiZWZvcmUgew0KICBjb250ZW50OiAiVGFibGUgb2YgQ29udGVudHMiOw0KICBmb250LXdlaWdodDogYm9sZDsNCiAgZm9udC1zaXplOiAxLjJlbTsNCiAgZGlzcGxheTogYmxvY2s7DQogIGNvbG9yOiBuYXZ5Ow0KICBtYXJnaW4tYm90dG9tOiAxMHB4Ow0KfQ0KDQoNCmRpdiNUT0MgbGkgeyAgICAgLyogdGFibGUgb2YgY29udGVudCAgKi8NCiAgICBsaXN0LXN0eWxlOnVwcGVyLXJvbWFuOw0KICAgIGJhY2tncm91bmQtaW1hZ2U6bm9uZTsNCiAgICBiYWNrZ3JvdW5kLXJlcGVhdDpub25lOw0KICAgIGJhY2tncm91bmQtcG9zaXRpb246MDsNCn0NCg0KaDEudGl0bGUgeyAgICAvKiBsZXZlbCAxIGhlYWRlciBvZiB0aXRsZSAgKi8NCiAgZm9udC1zaXplOiAyMnB4Ow0KICBmb250LXdlaWdodDogYm9sZDsNCiAgY29sb3I6IERhcmtSZWQ7DQogIHRleHQtYWxpZ246IGNlbnRlcjsNCiAgZm9udC1mYW1pbHk6ICJHaWxsIFNhbnMiLCBzYW5zLXNlcmlmOw0KfQ0KDQpoNC5hdXRob3IgeyAvKiBIZWFkZXIgNCAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICBmb250LXNpemU6IDE1cHg7DQogIGZvbnQtd2VpZ2h0OiBib2xkOw0KICBmb250LWZhbWlseTogc3lzdGVtLXVpOw0KICBjb2xvcjogbmF2eTsNCiAgdGV4dC1hbGlnbjogY2VudGVyOw0KfQ0KDQpoNC5kYXRlIHsgLyogSGVhZGVyIDQgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgZm9udC1zaXplOiAxOHB4Ow0KICBmb250LXdlaWdodDogYm9sZDsNCiAgZm9udC1mYW1pbHk6ICJHaWxsIFNhbnMiLCBzYW5zLXNlcmlmOw0KICBjb2xvcjogRGFya0JsdWU7DQogIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCg0KaDEgeyAvKiBIZWFkZXIgMSAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICAgIGZvbnQtc2l6ZTogMjBweDsNCiAgICBmb250LXdlaWdodDogYm9sZDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogZGFya3JlZDsNCiAgICB0ZXh0LWFsaWduOiBjZW50ZXI7DQp9DQoNCmgyIHsgLyogSGVhZGVyIDIgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgICBmb250LXNpemU6IDE4cHg7DQogICAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IG5hdnk7DQogICAgdGV4dC1hbGlnbjogbGVmdDsNCn0NCg0KaDMgeyAvKiBIZWFkZXIgMyAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICAgIGZvbnQtc2l6ZTogMTZweDsNCiAgICBmb250LXdlaWdodDogYm9sZDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogbmF2eTsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KDQpoNCB7IC8qIEhlYWRlciA0IC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovDQogICAgZm9udC1zaXplOiAxNHB4Ow0KICBmb250LXdlaWdodDogYm9sZDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogZGFya3JlZDsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KDQovKiBBZGQgZG90cyBhZnRlciBudW1iZXJlZCBoZWFkZXJzICovDQouaGVhZGVyLXNlY3Rpb24tbnVtYmVyOjphZnRlciB7DQogIGNvbnRlbnQ6ICIuIjsNCg0KYm9keSB7IGJhY2tncm91bmQtY29sb3I6d2hpdGU7IH0NCg0KLmhpZ2hsaWdodG1lIHsgYmFja2dyb3VuZC1jb2xvcjp5ZWxsb3c7IH0NCg0KcCB7IGJhY2tncm91bmQtY29sb3I6d2hpdGU7IH0NCg0KfQ0KYGBgDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0KIyBjb2RlIGNodW5rIHNwZWNpZmllcyB3aGV0aGVyIHRoZSBSIGNvZGUsIHdhcm5pbmdzLCBhbmQgb3V0cHV0IA0KIyB3aWxsIGJlIGluY2x1ZGVkIGluIHRoZSBvdXRwdXQgZmlsZXMuDQppZiAoIXJlcXVpcmUoImtuaXRyIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoImtuaXRyIikNCiAgIGxpYnJhcnkoa25pdHIpDQp9DQppZiAoIXJlcXVpcmUoInBhbmRlciIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJwYW5kZXIiKQ0KICAgbGlicmFyeShwYW5kZXIpDQp9DQppZiAoIXJlcXVpcmUoImdncGxvdDIiKSkgew0KICBpbnN0YWxsLnBhY2thZ2VzKCJnZ3Bsb3QyIikNCiAgbGlicmFyeShnZ3Bsb3QyKQ0KfQ0KaWYgKCFyZXF1aXJlKCJ0aWR5dmVyc2UiKSkgew0KICBpbnN0YWxsLnBhY2thZ2VzKCJ0aWR5dmVyc2UiKQ0KICBsaWJyYXJ5KHRpZHl2ZXJzZSkNCn0NCg0KaWYgKCFyZXF1aXJlKCJwbG90bHkiKSkgew0KICBpbnN0YWxsLnBhY2thZ2VzKCJwbG90bHkiKQ0KICBsaWJyYXJ5KHBsb3RseSkNCn0NCiMjIyMNCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgICAgICAgIyBpbmNsdWRlIGNvZGUgY2h1bmsgaW4gdGhlIG91dHB1dCBmaWxlDQogICAgICAgICAgICAgICAgICAgICAgd2FybmluZyA9IEZBTFNFLCAgICMgc29tZXRpbWVzLCB5b3UgY29kZSBtYXkgcHJvZHVjZSB3YXJuaW5nIG1lc3NhZ2VzLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHlvdSBjYW4gY2hvb3NlIHRvIGluY2x1ZGUgdGhlIHdhcm5pbmcgbWVzc2FnZXMgaW4NCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyB0aGUgb3V0cHV0IGZpbGUuIA0KICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdHMgPSBUUlVFLCAgICAjIHlvdSBjYW4gYWxzbyBkZWNpZGUgd2hldGhlciB0byBpbmNsdWRlIHRoZSBvdXRwdXQNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBpbiB0aGUgb3V0cHV0IGZpbGUuDQogICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZSA9IEZBTFNFLA0KICAgICAgICAgICAgICAgICAgICAgIGNvbW1lbnQgPSBOQQ0KICAgICAgICAgICAgICAgICAgICAgICkgIA0KYGBgDQogDQpcDQogDQojIyAqKkFzc2lnbm1lbnQgT2JqZWN0aXZlcyoqIA0KDQoqIENvbXByZWhlbmQgdGhlIGxpa2VsaWhvb2QgZnVuY3Rpb24gYW5kIGl0cyBwcm9wZXJ0aWVzLg0KDQoqIE1hc3RlciB0aGUgbWF4aW11bSBsaWtlbGlob29kIGVzdGltYXRpb24gZnJhbWV3b3JrIGFuZCByZXF1aXJlZCBjb21wb25lbnRzLg0KDQoqIFVuZGVyc3RhbmQgdGhlIHBsdWctaW4gcHJpbmNpcGxlIHVuZGVybHlpbmcgTUxFLg0KDQoqIEltcGxlbWVudCBtYXhpbXVtIGxpa2VsaWhvb2QgZXN0aW1hdGlvbiBwcm9jZWR1cmVzIGluIFIuDQoNClwNCg0KIyMgKipQb2xpY2llcyBvZiBVc2luZyBBSSBUb29scyoqDQoNCioqUG9saWN5IG9uIEFJIFRvb2wgVXNlKio6IFN0dWRlbnRzIG11c3QgYWRoZXJlIHRvIHRoZSBBSSB0b29sIHBvbGljeSBzcGVjaWZpZWQgaW4gdGhlIGNvdXJzZSBzeWxsYWJ1cy4gVGhlIGRpcmVjdCBjb3B5aW5nIG9mIEFJLWdlbmVyYXRlZCBjb250ZW50IGlzIHN0cmljdGx5IHByb2hpYml0ZWQuIEFsbCBzdWJtaXR0ZWQgd29yayBtdXN0IHJlZmxlY3QgeW91ciBvd24gdW5kZXJzdGFuZGluZzsgd2hlcmUgZXh0ZXJuYWwgdG9vbHMgYXJlIGNvbnN1bHRlZCwgY29udGVudCBtdXN0IGJlIHRob3JvdWdobHkgcmVwaHJhc2VkIGFuZCBzeW50aGVzaXplZCBpbiB5b3VyIG93biB3b3Jkcy4NCg0KKipDb2RlIEluY2x1c2lvbiBSZXF1aXJlbWVudCoqOiBBbnkgY29kZSBpbmNsdWRlZCBpbiB5b3VyIGVzc2F5IG11c3QgYmUgcHJvcGVybHkgY29tbWVudGVkIHRvIGV4cGxhaW4gdGhlIHB1cnBvc2UgYW5kL29yIGV4cGVjdGVkIG91dHB1dCBvZiBrZXkgY29kZSBsaW5lcy4gU3VibWl0dGluZyBBSS1nZW5lcmF0ZWQgY29kZSB3aXRob3V0IG1lYW5pbmdmdWwsIHN0dWRlbnQtYWRkZWQgY29tbWVudHMgd2lsbCBub3QgYmUgYWNjZXB0ZWQuDQoNClwNCg0KKipHYW1tYSBEaXN0cmlidXRpb24gUmV2aXNpdGVkKioNCg0KTGV0ICRYJCBiZSB0aGUgdHdvIHBhcmFtZXRlciBHYW1tYSByYW5kb20gdmFyaWFibGUgd2l0aCBkZW5zaXR5IGZ1bmN0aW9uDQoNCiQkDQpmKHggXG1pZCBcYWxwaGEsIFxiZXRhKSA9IFxmcmFjezF9e1xHYW1tYShcYWxwaGEpXGJldGFeXGFscGhhfSB4XntcYWxwaGEtMX0gZV57LXgvXGJldGF9ICBcIFwgXHRleHR7Zm9yfSBcIFwgIHggPiAwLA0KJCQNCg0Kd2hlcmUgd2l0aCAkXGFscGhhID4gMCQgKHNoYXBlKSwgJFxiZXRhPjAkIChzY2FsZSksIGFuZA0KDQokJA0KXEdhbW1hKFxhbHBoYSkgPSBcaW50X3swfV57XGluZnR5fSB0XntcYWxwaGEtMX0gZV57LXR9IFwsIGR0LCBccXVhZCBcYWxwaGEgPiAwLg0KJCQNCg0KJFxHYW1tYSh4KSQgY2FuIGJlIGNvbXB1dGVkIGluIFIgdXNpbmcgdGhlIGBnYW1tYSgpYCBmdW5jdGlvbi4gVGhlIGRlcml2YXRpdmUgb2YgJFxHYW1tYSh4KSQgYXJlIGdpdmVuIHJlc3BlY3RpdmVseSBieQ0KDQokJA0KXEdhbW1hXlxwcmltZSh6KSA9IFxHYW1tYSAoeilccHNpXzAoeikNCiQkDQoNCndoZXJlICRccHNpXzAoeikgPSBcZnJhY3tkfXtken0gXGxuIFxHYW1tYXt6fSQuIEluIFIsIHRoZSBkaWdhbW1hIGZ1bmN0aW9uICRccHNpXzAoeikkIGlzIGV2YWx1YXRlZCBieSBgZGlnYW1tYSgpYC4NCg0KDQoNClwNCg0KPGZvbnQgY29sb3IgPSAiYmx1ZSI+VGhpcyBhc3NpZ25tZW50IGZvY3VzZXMgb24gZmluZGluZyBtYXhpbXVtIGxpa2VsaWhvb2QgZXN0aW1hdGUgb2YgcGFyYW1ldGVycyAkXGFscGhhJCBhbmQgJFxiZXRhJCBiYXNlZCBvbiBhIHJlYWwtd29ybGQgYXBwbGljYXRpb24gZGF0YSBzZXQuPC9mb250Pg0KDQoNClwNCg0KIyMgKipRdWVzdGlvbiAxOiBEZXJpdmUgZ3JhZGllbnQgKGZpcnN0IG9yZGVyIHBhcnRpYWwgZGVyaXZhdGl2ZSkgb2YgbGlrZWxpaG9vZCBmdW5jdGlvbioqDQoNCkFzc3VtZSB0aGF0ICRce3hfMSwgeF8yLCBcY2RvdHMsIHhfbiBcfSBcdG8gXHRleHR7IGdhbW1hIH0oXGFscGhhLCBcYmV0YSkkIHdpdGggZGVuc2l0eSBmdW5jdGlvbiBnaXZlbiBieQ0KDQokJA0KZih4IFxtaWQgXGFscGhhLCBcYmV0YSkgPSBcZnJhY3sxfXtcR2FtbWEoXGFscGhhKVxiZXRhXlxhbHBoYX0geF57XGFscGhhLTF9IGVeey14L1xiZXRhfSAgXCBcIFx0ZXh0e2Zvcn0gXCBcICB4ID4gMCwNCiQkDQoNCkRlcml2ZSB0aGUgZ3JhZGllbnQgb2YgdGhlICoqbG9nLWxpa2VsaWhvb2QgZnVuY3Rpb24qKiB3aXRoIHJlc3BlY3QgdG8gdGhlIGdhbW1hIGRpc3RyaWJ1dGlvbiBwYXJhbWV0ZXJzICRcYWxwaGEkIGFuZCAkXGJldGEkLiBUbyB0aGlzIGVuZCwNCg0KDQphKS4gV3JpdGUgb3V0IHRoZSBmdWxsICoqbG9nLWxpa2VsaWhvb2QgZnVuY3Rpb24qKiBiYXNlZCBvbiB0aGUgZ2l2ZW4gZGF0YSBhbmQgdGhlIGRlbnNpdHkgZnVuY3Rpb24gcHJvdmlkZWQgYWJvdmUuDQoNCiMgQW5zd2VyIHRvIFF1ZXN0aW9uIDEgUGFydCBBDQoNClRoZSBHYW1tYSBkaXN0cmlidXRpb24gaXMgZGVmaW5lZCBieSB0aGUgcHJvYmFiaWxpdHkgZGVuc2l0eSBmdW5jdGlvbjoNCg0KJCQNCmYoeCBcbWlkIFxhbHBoYSwgXGJldGEpID0gXGZyYWN7MX17XEdhbW1hKFxhbHBoYSlcYmV0YV5cYWxwaGF9IHhee1xhbHBoYS0xfSBlXnsteC9cYmV0YX0gIFwgXCBcdGV4dHtmb3J9IFwgXCAgeCA+IDANCiQkDQoNCndoZXJlICRcYWxwaGEgPiAwJCBpcyB0aGUgc2hhcGUgcGFyYW1ldGVyIGFuZCAkXGJldGE+MCQgaXMgdGhlIHNjYWxlIHBhcmFtZXRlci4NCg0KVGhlcmVmb3JlIHRoZSBsaWtlbGlob29kIGZ1bmN0aW9uIGlzOg0KDQokJA0KTChcYWxwaGEsXGJldGEgXG1pZCB4KT1ccHJvZF97aT0xfV57bn17Zih4X2lcbWlkXGFscGhhLFxiZXRhKX09XHByb2Rfe2k9MX1ee259e1xmcmFjezF9e1xHYW1tYShcYWxwaGEpXGJldGFee1xhbHBoYX19eF9pXntcYWxwaGEtMX1lXnsteF9pL1xiZXRhfX0NCiQkDQoNCkFuZCB0aGUgbG9nLWxpa2VsaWhvb2QgZnVuY3Rpb24gaXM6DQoNCiQkDQpcZWxsKFxhbHBoYSxcYmV0YVxtaWQgeCk9XGxue0woXGFscGhhLFxiZXRhIFxtaWQgeCl9PVxzdW1fe2k9MX1ee259e1xsbntcbGVmdFtcZnJhY3sxfXtcR2FtbWEoXGFscGhhKVxiZXRhXntcYWxwaGF9fXhfaV57XGFscGhhLTF9ZV57LXhfaS9cYmV0YX1ccmlnaHRdfX0NCiQkDQoNClRoaXMgY2FuIGJlIGZ1cnRoZXIgc2ltcGxpZmllZCB0bzoNCg0KJCQNClxiZWdpbnthbGlnbmVkfQ0KDQpcZWxsKFxhbHBoYSxcYmV0YVxtaWQgeCkgJj0gXHN1bV97aT0xfV57bn17XGxue1xsZWZ0W1xmcmFjezF9e1xHYW1tYShcYWxwaGEpXGJldGFee1xhbHBoYX19eF9pXntcYWxwaGEtMX1lXnsteF9pL1xiZXRhfVxyaWdodF19fSBcXFxcDQoNCiY9IFxzdW1fe2k9MX1ee259e1xsZWZ0W1xsbnsxfS0oXGxue1xHYW1tYShcYWxwaGEpfStcYWxwaGFcbG57XGJldGF9KSsoXGFscGhhLTEpXGxue3hfaX0tXGZyYWN7eF9pfXtcYmV0YX1ccmlnaHRdfVxcXFwNCg0KJj0gLW5cbG57XEdhbW1hKFxhbHBoYSl9LW5cYWxwaGFcbG57XGJldGF9KyhcYWxwaGEtMSlcc3VtX3tpPTF9XntufXtcbG57eF9pfX0tXGZyYWN7MX17XGJldGF9XHN1bV97aT0xfV57bn17eF9pfQ0KXGVuZHthbGlnbmVkfQ0KJCQNCg0KVGhlcmVmb3JlLCB0aGUgc2ltcGxpZmVkIGxvZy1saWtsaWhvb2QgZnVuY3Rpb24gaXM6DQoNCiQkDQpcZWxsKFxhbHBoYSxcYmV0YVxtaWQgeCk9LW5cbG57XEdhbW1hKFxhbHBoYSl9LW5cYWxwaGFcbG57XGJldGF9KyhcYWxwaGEtMSlcc3VtX3tpPTF9XntufXtcbG57eF9pfX0tXGZyYWN7MX17XGJldGF9XHN1bV97aT0xfV57bn17eF9pfQ0KJCQNCg0KDQoNCmIpLiBEZXJpdmUgdGhlIHNjb3JlIGZ1bmN0aW9ucyAodGhlIGdyYWRpZW50IG9mIHRoZSBsb2ctbGlrZWxpaG9vZCkgZnJvbSB0aGUgZnVsbCAqKmxvZy1saWtlbGlob29kIGZ1bmN0aW9uKiogaW4gcGFydCAoYSkuDQoNCiMgQW5zd2VyIHRvIFF1ZXN0aW9uIDEgUGFydCBCDQoNClRvIGZpbmQgdGhlIGZpcnN0IHNjb3JlIGZ1bmN0aW9uIHdlIHdpbGwgZGlmZmVyZW50aWF0ZSB3aXRoIHJlc3BlY3QgJFxiZXRhJC4NCg0KJCQNClxiZWdpbnthbGlnbmVkfQ0KDQpcZnJhY3tccGFydGlhbFxlbGx9e1xwYXJ0aWFsXGJldGF9ICY9IFxmcmFje1xwYXJ0aWFsfXtccGFydGlhbFxiZXRhfVxsZWZ0Wy1uXGxue1xHYW1tYShcYWxwaGEpfS1uXGFscGhhXGxue1xiZXRhfSsoXGFscGhhLTEpXHN1bV97aT0xfV57bn17XGxue3hfaX19LVxmcmFjezF9e1xiZXRhfVxzdW1fe2k9MX1ee259e3hfaX1ccmlnaHRdXFxcXA0KDQomPSAtblxhbHBoYVxmcmFjezF9e1xiZXRhfStcZnJhY3sxfXtcYmV0YV4yfVxzdW1fe2k9MX1ee259e3hfaX0NCg0KXGVuZHthbGlnbmVkfQ0KJCQNCg0KVG8gZmluZCB0aGUgc2Vjb25kIHNjb3JlIGZ1bmN0aW9uIHdlIHdpbGwgZGlmZmVyZW50aWF0ZSB3aXRoIHJlc3BlY3Qgb2YgJFxhbHBoYSQ6DQoNCiQkDQpcYmVnaW57YWxpZ25lZH0NCg0KXGZyYWN7XHBhcnRpYWxcZWxsfXtccGFydGlhbFxhbHBoYX0gJj0gXGZyYWN7XHBhcnRpYWx9e1xwYXJ0aWFsXGFscGhhfSBcbGVmdFstblxsbntcR2FtbWEoXGFscGhhKX0tblxhbHBoYVxsbntcYmV0YX0rKFxhbHBoYS0xKVxzdW1fe2k9MX1ee259e1xsbnt4X2l9fS1cZnJhY3sxfXtcYmV0YX1cc3VtX3tpPTF9XntufXt4X2l9XHJpZ2h0XSBcXFxcDQoNCiY9IC1uXGZyYWN7XEdhbW1hIChcYWxwaGEpXHBzaV8wKFxhbHBoYSl9e1xHYW1tYShcYWxwaGEpfS1uXGxue1xiZXRhfStcc3VtX3tpPTF9XntufXtcbG57eF9pfX0NCg0KXGVuZHthbGlnbmVkfQ0KJCQNCg0KDQpcDQoNCiMjICoqUXVlc3Rpb24gMjogQmlydGggZGF0YSBzZXQqKg0KDQpUaGUgZm9sbG93aW5nIFIgY29kZSByZWFkcyBpbiBhIGRhdGEgc2V0IGNvbnRhaW5pbmcsIGZvciBlYWNoIG9mIDcgZGF5cywgdGhlIGxlbmd0aHMgb2YgdGltZSBpbiBob3VycyBzcGVudCBieQ0Kd29tZW4gaW4gdGhlIGRlbGl2ZXJ5IHN1aXRlIHdoaWxlIGdpdmluZyBiaXJ0aCAod2l0aG91dCBhIGNlYXNhcmlhbiBzZWN0aW9uKSBhdCBKb2huIFJhZGNsaWZmZSBIb3NwaXRhbCBpbg0KT3hmb3JkLCBFbmdsYW5kLiBUaGUgZGF0YSBhcmUgdGFrZW4gZnJvbSBEYXZpc29uIChTdGF0aXN0aWNhbCBNb2RlbHMuIENhbWJyaWRnZSBVbml2ZXJzaXR5IFByZXNzLCAyMDAzKS4NCg0KYGBgDQoyLjEsIDMuNCwgNC4yNSwgNS42LCA2LjQsIDcuMywgOC41LCA4Ljc1LCA4LjksIDkuNSwgOS43NSwgMTAsIDEwLjQsIDEwLjQsIDE2LCAxOSwNCjQsIDQuMSwgNSwgNS41LCA1LjcsIDYuNSwgNy4yNSwgNy4zLCA3LjUsIDguMiwgOC41LCA5Ljc1LCAxMSwgMTEuMiwgMTUsIDE2LjUsIDIuNiwgDQozLjYsIDMuNiwgNi40LCA2LjgsIDcuNSwgNy41LCA4LjI1LCA4LjUsIDEwLjQsIDEwLjc1LCAxNC4yNSwgMTQuNSwgMS41LCA0LjcsIDQuNywgDQo3LjIsIDcuMjUsIDguMSwgOC41LCA5LjIsIDkuNSwgMTAuNywgMTEuNSwgMi41LCAyLjUsIDMuNCwgNC4yLCA1LjksIDYuMjUsIDcuMywgNy41LCANCjcuOCwgOC4zLCA4LjMsIDEwLjI1LCAxMi45LCAxNC4zLCA0LCA0LCA1LjI1LCA2LjEsIDYuNSwgNi45LCA3LCA4LjQ1LCA5LjI1LCAxMC4xLCANCjEwLjIsIDEyLjc1LCAxNC42LCAyLCAyLjcsIDIuNzUsIDMuNCwgNC4yLCA0LjMsIDQuOSwgNi4yNSwgNywgOSwgOS4yNSwgMTAuNw0KYGBgDQoNCkFzc3VtZSB0aGUgZGF0YSBhcmUgZ2VuZXJhdGVkIGZyb20gYSBnYW1tYSBkaXN0cmlidXRpb24uIFRoZSBvYmplY3RpdmUgaXMgdG8gdXNlIHRoZXNlIGRhdGEgYW5kIHRoZSBkZXNpZ25hdGVkIGFsZ29yaXRobSB0byBmaW5kIHRoZSBtYXhpbXVtIGxpa2VsaWhvb2QgZXN0aW1hdGVzIChNTEVzKSBvZiB0aGUgcGFyYW1ldGVycyAkXGFscGhhJCBhbmQgJFxiZXRhJC4NCg0KDQphKS4gRmluZCB0aGUgTUxFcyBvZiAkXGFscGhhJCBhbmQgJFxiZXRhJCwgZGVub3RlZCBieSAkXGhhdHtcYWxwaGF9JCBhbmQgJFxoYXR7XGJldGF9JCwgIHVzaW5nIGdyYWRpZW50LWJhc2VkIG9wdGltaXphdGlvbiB2aWEgdGhlIFIgZnVuY3Rpb24gYG9wdGltKClgIHdpdGggdGhlIGdyYWRpZW50IHZlY3RvciBkZXJpdmVkIGluIFF1ZXN0aW9uIDEuDQoNCiMgQW5zd2VyIHRvIFF1ZXN0aW9uIDIgUGFydCBBDQoNCmBgYHtyfQ0KYmlydGggPC0gYygyLjEsIDMuNCwgNC4yNSwgNS42LCA2LjQsIDcuMywgOC41LCA4Ljc1LCA4LjksIDkuNSwgOS43NSwgMTAsIDEwLjQsIDEwLjQsIDE2LCAxOSwNCjQsIDQuMSwgNSwgNS41LCA1LjcsIDYuNSwgNy4yNSwgNy4zLCA3LjUsIDguMiwgOC41LCA5Ljc1LCAxMSwgMTEuMiwgMTUsIDE2LjUsIDIuNiwgDQozLjYsIDMuNiwgNi40LCA2LjgsIDcuNSwgNy41LCA4LjI1LCA4LjUsIDEwLjQsIDEwLjc1LCAxNC4yNSwgMTQuNSwgMS41LCA0LjcsIDQuNywgDQo3LjIsIDcuMjUsIDguMSwgOC41LCA5LjIsIDkuNSwgMTAuNywgMTEuNSwgMi41LCAyLjUsIDMuNCwgNC4yLCA1LjksIDYuMjUsIDcuMywgNy41LCANCjcuOCwgOC4zLCA4LjMsIDEwLjI1LCAxMi45LCAxNC4zLCA0LCA0LCA1LjI1LCA2LjEsIDYuNSwgNi45LCA3LCA4LjQ1LCA5LjI1LCAxMC4xLCANCjEwLjIsIDEyLjc1LCAxNC42LCAyLCAyLjcsIDIuNzUsIDMuNCwgNC4yLCA0LjMsIDQuOSwgNi4yNSwgNywgOSwgOS4yNSwgMTAuNykNCg0KI1VzZWQgdG8gZW50ZXIgbG9nLWxvZ2lzdGljIGZ1bmN0aW9uDQpnYW1tYS5sb2dsaWsgPC0gZnVuY3Rpb24ocGFyYW1zLCBkYXRhKSB7DQogIHNoYXBlIDwtIHBhcmFtc1sxXSAgIyBVc2VkIHRvIGdldCBpbml0aWFsIHBhcmFtZXRlcnMNCiAgc2NhbGUgPC0gcGFyYW1zWzJdDQogIG4gPC0gbGVuZ3RoKGRhdGEpICAgIyBVc2VkIHRvIGdldCBzYW1wbGUgc2l6ZQ0KICANCg0KICBsb2dsaWsgPC0gLW4qbG9nKGdhbW1hKHNoYXBlKSktbipzaGFwZSpsb2coc2NhbGUpKyhzaGFwZS0xKSpzdW0obG9nKGRhdGEpKS0oMS9zY2FsZSkqc3VtKGRhdGEpIA0KICANCiAgcmV0dXJuKGxvZ2xpaykgICAgIyBSZXR1cm4gbmVnYXRpdmUgZm9yIG1pbmltaXphdGlvbg0KfQ0KDQoNCiMgVXNlZCB0byBlbnRlciBncmFkaWVudCBmdW5jdGlvbnMNCg0KZ2FtbWEuc2NvcmUgPC0gZnVuY3Rpb24ocGFyYW1zLCBkYXRhKSB7DQogIHNoYXBlIDwtIHBhcmFtc1sxXSAjVXNlZCB0byBnZXQgaW5pdGlhbCBwYXJhbWV0ZXJzDQogIHNjYWxlIDwtIHBhcmFtc1syXQ0KICBuIDwtIGxlbmd0aChkYXRhKSAjVXNlZCB0byBnZXQgc2FtcGxlIHNpemUNCiAgDQogICMgR3JhZGllbnQgZm9yIHNoYXBlIHBhcmFtZXRlcg0KICBncmFkX3NoYXBlIDwtICAtbipkaWdhbW1hKHNoYXBlKS1uKmxvZyhzY2FsZSkrc3VtKGxvZyhkYXRhKSkNCiAgDQogICMgR3JhZGllbnQgZm9yIHNjYWxlIHBhcmFtZXRlcg0KICBncmFkX3NjYWxlIDwtIC1uKnNoYXBlKigxL3NjYWxlKSsoMS8oc2NhbGUqKjIpKSpzdW0oZGF0YSkNCiAgDQogIHJldHVybihjKGdyYWRfc2hhcGUsIGdyYWRfc2NhbGUpKQ0KfQ0KDQoNCiMgRW50ZXJpbmcgaW5pdGlhbCBndWVzc2VkIHBhcmFtZXRlcnMNCmluaXRpYWwucGFyYW1zIDwtIGMoc2hhcGUgPSAyLjIsIHNjYWxlID0gMS41KSAgDQoNCg0KIyBVc2luZyBvcHRpbSBhbmQgcHJldmlvdXMgZnVuY3Rpb25zIHRvIGdldCByZXN1bHRzDQptbGUucmVzdWx0IDwtIG9wdGltKA0KICBwYXIgPSBpbml0aWFsLnBhcmFtcywNCiAgZm4gPSBnYW1tYS5sb2dsaWssDQogIGdyID0gZ2FtbWEuc2NvcmUsDQogIGRhdGEgPSBiaXJ0aCwNCiAgbWV0aG9kID0gIkwtQkZHUy1CIiwNCiAgbG93ZXIgPSBjKDFlLTYsIDFlLTYpLA0KICBoZXNzaWFuID0gVFJVRSwNCiAgY29udHJvbCA9IGxpc3QodHJhY2UgPSBGQUxTRSwNCiAgICAgICAgICAgICAgICAgZm5zY2FsZSA9IC0xLA0KICAgICAgICAgICAgICAgICBtYXhpdCA9IDUwMCwNCiAgICAgICAgICAgICAgICAgYWJzdG9sID0gMWUtOCkNCikNCiMjDQptbGUucmVzdWx0ICNwcmludGluZyBtbGUucmVzdWx0IGRldGVybWluZWQgZWFybGllcg0KDQpgYGANCg0KVGhlcmVmb3JlIHRoZSBNTEUgZXN0aW1hdGlvbnMgZm9yICRcYWxwaGEkIGFuZCAkXGJldGEkIGFyZSAkXGhhdHtcYWxwaGF9PTQuMzg3ODgxJCBhbmQgJFxoYXR7XGJldGF9PTEuNzYwMTExJC4NCg0KYikuIEFwcGx5IHRoZSBtZXRob2Qgb2YgbW9tZW50cyB0byBvYnRhaW4gZXN0aW1hdG9ycyBmb3IgJFxhbHBoYSQgYW5kICRcYmV0YSQuIERlbm90ZSB0aGVzZSBtb21lbnQgZXN0aW1hdG9ycyBhcyAkXHRpbGRle1xhbHBoYX0kIGFuZCAkXHRpbGRle1xiZXRhfSQuDQoNCiMgQW5zd2VyIHRvIFF1ZXN0aW9uIDIgUGFydCBCDQoNCkFzIGRldGVybWluZWQgaW4gdGhlIDV0aCBXZWVrIExlY3R1cmUsIHRoZSBtZXRob2Qgb2YgbW9tZW50IGVzdGltYXRvcnMgZm9yIGEgZ2FtbWEgZGlzdHJpYnV0aW9uIGFyZToNCg0KJCQNClxiZWdpbnthbGlnbmVkfQ0KDQpcaGF0e1xtdX0gJj0gXGZyYWN7MX17bn1cc3VtX3tpPTF9XntufXtYX2l9PVxiYXJ7WH1cXFxcDQpcaGF0e1xzaWdtYV4yfSAmPSBcZnJhY3sxfXtufVxzdW1fe2k9MX1ee259e1hfaV4yLVxiYXJ7WH1eMn09XGZyYWN7MX17bn1cc3VtX3tpPTF9XntufXsoWF9pLVxiYXJ7WH0pXjJ9DQoNCg0KXGVuZHthbGlnbmVkfQ0KJCQNCg0KV2UgY2FuIHVzZSB0aGVzZSBtZXRob2Qgb2YgbW9tZW50IGVzdGltYXRvcnMgdG8gb2J0YWluIGVzdGltYXRvcnMgZm9yICRcYWxwaGEkIGFuZCAkXGJldGEkIGZvciBvdXIgZGF0c2V0Og0KDQpgYGB7cn0NCiMgTWV0aG9kIG9mIE1vbWVudHMgZXN0aW1hdGlvbg0KbW9tX211IDwtIG1lYW4oYmlydGgpICNVc2VkIHRvIGdldCBtb21lbnRzIGZyb20gc2FtcGxlDQptb21fc2lnbWFfc3EgPC0gbWVhbihiaXJ0aF4yKSAtIG1vbV9tdV4yDQptb21fc2lnbWEgPC0gc3FydChtb21fc2lnbWFfc3EpDQoNCmNhdCgiTW9NIGVzdGltYXRlczogzrxfdGlsZGUgPSIsIHJvdW5kKG1vbV9tdSwgMyksICNVc2VkIHRvIHByaW50IG1vbWVudHMNCiAgICAiLCDPg190aWxkZSA9Iiwgcm91bmQobW9tX3NpZ21hLCAzKSwgIlxuIikNCmBgYA0KDQpUaGVyZWZvcmUgdGhlIE1NRSBlc3RpbWF0aW9ucyBmb3IgJFxhbHBoYSQgYW5kICRcYmV0YSQgYXJlICRcdGlsZGV7XGFscGhhfT03LjcyMyQgYW5kICRcdGlsZGV7XGJldGF9PTMuNTQ5JC4NCg0KYykuIENvbmR1Y3QgYSBicmllZiBsaXRlcmF0dXJlIHJldmlldyBjb21wYXJpbmcgdGhlIG1ldGhvZCBvZiBtb21lbnRzIGVzdGltYXRpb24gKE1NRSkgYW5kIG1heGltdW0gbGlrZWxpaG9vZCBlc3RpbWF0aW9uIChNTEUpLiBTeW50aGVzaXplIHRoZSBrZXkgYWR2YW50YWdlcyBhbmQgbGltaXRhdGlvbnMgb2YgZWFjaCwgY29uY2x1ZGluZyB3aXRoIGEgcHJhY3RpY2FsIHJlY29tbWVuZGF0aW9uLg0KDQojIEFuc3dlciB0byBRdWVzdGlvbiAyIFBhcnQgQw0KDQpNZXRob2Qgb2YgbW9tZW50cyBlc3RpbWF0aW9uIGFuZCBtYXhpbXVtIGxpa2VsaWhvb2QgZXN0aW1hdGlvbiBhcmUgYm90aCBtZXRob2RzIG9mIGVzdGltYXRpbmcgdGhlIHBhcmFtZXRlcnMgb2YgYSBkaXN0cmlidXRpb24gdXNpbmcgc2FtcGxlIGRhdGEuICBNZXRob2Qgb2YgbW9tZW50cyBhdHRlbXB0cyB0byBlc3RpbWF0ZSB0aGVzZSBwYXJhbWV0ZXJzIGJ5IG1hdGNoaW5nIG1vbWVudHMgb2YgdGhlIHNhbXBsZSB0byBtb21lbnRzIG9mIGEgdGhlb3JldGljYWwgcHJvYmFiaWxpdHkgbW9kZWwuICBBbHRlcm5hdGl2ZWx5LCBtYXhpbXVtIGxpa2VsaWhvb2QgZXN0aW1hdGlvbiBjb25zaWRlcnMgaG93IGxpa2VseSBjZXJ0YWluIHBhcmFtZXRlciB2YWx1ZXMgYXJlIGdpdmVuIHRoZSBzYW1wbGVkIGRhdGEuICBHaXZlbiB0aGF0IE1NRSBvbmx5IGNvbnNpZGVycyBhIGZldyBzcGVjaWZpYyBtb21lbnRzLCBpdCBpcyBsZXNzIHBvd2VyZnVsLCBidXQgYWxzbyBsZXNzIGNvbXB1dGF0aW9uYWxseSBpbnRlbnNlLiAgQWx0ZXJuYXRpdmVseSwgTUxFIGlzIG1vcmUgY29tcHV0YXRpb25hbGx5IGludGVuc2UgYnV0IG1vcmUgcG93ZXJmdWwgbWV0aG9kIG9mIGVzdGltYXRpbmcgcGFyYW1ldGVycy4gIE1NRSB3b3VsZCBtb3N0IGxpa2VseSBiZSBiZXR0ZXIgaWYgeW91IGp1c3QgbmVlZCBhIHJvdWdoIGVzdGltYXRlIG9mIHRoZSBwYXJhbWV0ZXJzLCB3aGlsZSBNTEUgbWlnaHQgYmUgYmV0dGVyIGlmIHlvdSBuZWVkIGEgcmVzdWx0IHRoYXQgdGFrZXMgaW50byBhY2NvdW50IHRoZSBlbnRpcmUgc2hhcGUgb2YgYSBwcm9iYWJpbGl0eSBkaXN0cmlidXRpb24uICANCg0KDQoNCg0K