1 Introduction

The bootstrap is a resampling technique introduced by Efron (1979) that allows us to estimate the sampling distribution of a statistic by repeatedly sampling with replacement from the observed data.

The Key Principle is treat the empirical distribution function (EDF) of the sample as an approximation to the true population distribution:

\[ \hat{F}_n(x) = \frac{1}{n} \sum_{i=1}^n I(X_i \leq x) \]

This key principle is backed by the well known Glivenko–Cantelli Theorem: EDF converges uniformly to CDF for i.i.d. data.


1.1 Key Explicit and Implicit Assumptions

Bootstrap samples represent the original population when the original sample itself is a good representation of the population. This is the fundamental bootstrap principle.

  • Key Explicit Conditions
    • Independence of observations: The original data should be independent and identically distributed (i.i.d.) or at least exchangeable. The standard bootstrap sampling fails for time series with strong autocorrelation, spatial data, clustered data (without special resampling methods).
    • Sample size sufficiently large: The original sample size \(n\) should be large enough to capture the population’s variability. Small samples can still be bootstrapped, but the bootstrap distribution may be coarse and might miss extreme quantiles of the population
    • Statistic is smooth and well-behaved: Bootstrap works well for statistics that are smooth functions of the sample (e.g., mean, variance, regression coefficients). However, it can fail for non-smooth statistics (e.g., median with very small samples, extreme order statistics).
  • Key Implicit Assumptions
    • The empirical distribution function (EDF) is a good estimate of the population CDF because bootstrap resampling approximates sampling from the EDF, not directly from the population. If the original sample is not representative (e.g., biased sampling), bootstrap will replicate the bias.
    • The underlying population distribution has finite variance which ensures consistency of bootstrap for the sample mean (and related statistics) in large samples.
    • No extreme outliers driving the estimate because bootstrap samples from the observed data, a single extreme outlier can appear multiple times in a bootstrap sample, distorting the bootstrap distribution more than the actual sampling distribution.


1.2 When Bootstrap Fails or Is Problematic

  • Heavy-tailed distributions with small n — bootstrap can be inconsistent.

  • Non-smooth parameters (e.g., estimating max of distribution).

  • Data with dependency structure (unless block bootstrap or similar is used).

  • Insufficient sample size for complex statistics.


2 Bootstrap Algorithm vs Bootstrap Sampling Distribution

The Basic Bootstrap Algorithm (also called the nonparametric bootstrap) is a resampling-based statistical method introduced by Bradley Efron in 1979. It provides a way to estimate the sampling distribution of almost any statistic without making strong distributional assumptions. It’s power lies in its simplicity: by letting the computer do the heavy lifting through resampling, we can make inferences that would be mathematically intractable using traditional methods.

2.1 Bootstrap Algorithm

The bootstrap algorithm is a resampling technique that uses a single dataset to estimate the sampling distribution of a statistic by repeatedly drawing samples with replacement from the original data and recalculating the statistic.

2.1.1 Mathematical Algorithm

Let \(X = \{x_1, x_2, ..., x_n\}\) be the original sample:

  • Compute the statistic of interest: \(\hat{\theta} = T(X)\)

  • For \(b = 1\) to \(B\):

    • Draw a bootstrap sample \(X_b^*\) by sampling \(n\) observations with replacement from \(X\)
    • Compute \(\hat{\theta}_b^* = T(X_b^*)\)
  • The bootstrap distribution is \(\{\hat{\theta}_1^*, \hat{\theta}_2^*, \cdots, \hat{\theta}_B^*\}\)


2.1.2 Pseudo-code

function basic_bootstrap(data, statistic, B=1000):
    n = length(data)
    theta_hat = statistic(data)
    bootstrap_dist = empty vector of size B
    
    for b in 1:B:
        bootstrap_sample = sample(data, size=n, replace=TRUE)
        bootstrap_dist[b] = statistic(bootstrap_sample)
    
    return (theta_hat, bootstrap_dist)


2.1.3 Types of Bootstrap Algorithms

  • Nonparametric Bootstrap is the most common type (described above). It makes no assumptions about population distribution and resamples directly from observed data.

  • Parametric Bootstrap assumes data comes from parametric family \(F(x; \theta)\). We take an original sample from the population and estimate \(\theta\) from data. The bootstrap samples from \(F(x; \hat{\theta}\) (instead of the ECDF \(F_n(x)\)) and calculate statistics from these parametric bootstrap samples.

  • Specialized Bootstrap is for non-i.i.d. data or data with special probability structures. We will not explore this direction in depth.


2.2 Bootstrap Sampling Distributions

Bootstrap is a versatile, assumption-lean method for estimating sampling distributions of sample statistics, particularly valuable when theoretical distributions of these statistics are unknown or difficult to derive, but requires careful implementation and interpretation.

The following is a list frequently used bootstrap sampling distributions used in practice.

  • Distribution of bootstrap sample means

  • Distribution of bootstrap sample medians

  • Distribution of bootstrap sample variances or standard deviations

  • Distribution of bootstrap correlation coefficients (Pearson’s r)

  • Distribution of bootstrap regression coefficients

  • Distribution of bootstrap sample proportions

  • Distribution of bootstrap ratios of sample statistics (e.g., cost-effectiveness ratios)

  • Distribution of bootstrap statistics of any population parameters

The above statistics can be estimated based on any formal estimation methods such as method of moments estimator (MME) and maximum likelihood estimator (MLE).


2.3 Applications of Bootstrap Sampling Distribution

The applications of Bootstrap Sampling Distribution span many areas of statistics and data science, primarily focused on estimation, inference, and assessing uncertainty when theoretical formulas are unavailable or unreliable. This course, we explore the applications in estimation and hypothesis testing.

2.3.1 Point and Interval Estimation

Bootstrap sampling distribution can be used for point and interval estimation. The

2.3.2 Hypothesis Testing

3 Types of Bootstrap Confidence Intervals

Bootstrap CIs include the percentile method (simple, range-preserving), BCa (corrects bias/skew, recommended default), bootstrap-t (most accurate with stable SE), and normal approximation (fast but assumes normality). BCa generally offers the best balance of accuracy and practicality for most applications.

3.1 Normal (Standard) Bootstrap CI

This bootstrap confidence interval assumes that bootstrap sampling distribution is approximately normally distributed.

3.1.1 Mathematical Algorithm

The algorithm is relatively straightforward and simple. We summarize it in the following 4 steps:

  • Compute \(\hat{\theta}\) from original sample

  • Generate bootstrap distribution \(\{\hat{\theta}_b^*\}_{b=1}^B\)

  • Estimate standard error: with \(\bar{\theta}^* = \frac{1}{B}\sum_{b=1}^B \hat{\theta}_b^*\)

\[ \hat{se}_{boot} = \sqrt{\frac{1}{B-1}\sum_{b=1}^B (\hat{\theta}_b^* - \bar{\theta}^*)^2} \]

  • Confidence interval:

\[ \hat{\theta} \pm z_{\alpha/2} \cdot \hat{se}_{boot} \]

3.1.2 Pseudo-code

Instead of writing an R function to implement the normal (standard bootstrap) confidence interval, this is a good coding exercise to translate the pseudo code into a workable R function to construct the normal bootstrap confidence interval.

function normal_bootstrap_ci(data, statistic, B=1000, alpha=0.05):
    theta_hat, boot_dist = basic_bootstrap(data, statistic, B)
    se_boot = sd(boot_dist)
    z = qnorm(1 - alpha/2)
    lower = theta_hat - z * se_boot
    upper = theta_hat + z * se_boot
    return (lower, upper)

3.1.3 An R Example

In this example, we present a step-by-step approach for calculating the normal confidence interval using R code with a simulated data set.

# Normal Bootstrap CI for mean
set.seed(123)
example1.dat <- rnorm(30, mean=50, sd=10)  # simulate a normal random sample

# Manual implementation
B <- 1000
n <- length(example1.dat)
boot_means <- numeric(B)     # empty vector to store bootstrap sample means

for(b in 1:B) {
  boot_sample <- sample(example1.dat, n, replace=TRUE)  # generating bootstrap sample
  boot_means[b] <- mean(boot_sample)            # calculate bootstrap means
}

theta_hat <- mean(example1.dat)   # same mean from the original sample
se_boot <- sd(boot_means)
z <- qnorm(0.975)
ci_normal <- c(LCI = theta_hat - z*se_boot, xbar = theta_hat, UCL=theta_hat + z*se_boot)
ci_normal
     LCI     xbar      UCL 
46.02590 49.52896 53.03203 

3.2 Percentile Bootstrap CI

Percentile bootstrap confidence intervals are the simplest form of bootstrap CIs. They are constructed by directly taking the corresponding quantiles (e.g., 2.5% and 97.5%) from the empirical distribution of bootstrap estimates. This method is range-preserving (e.g., stays within [0,1] for proportions) and works well when the bootstrap distribution is roughly symmetric and the estimator has little bias.

3.2.1 Mathematical Algorithm

  • Resample: Draw B independent bootstrap samples (with replacement) of size n from the original data.

  • Compute statistic: Generate bootstrap distribution \(\{\hat{\theta}_b^*\}_{b=1}^B\)

  • Empirical distribution: Sort bootstrap statistics:

\[ \hat{\theta}_{(1)}^* \leq \hat{\theta}_{(2)}^* \leq ... \leq \hat{\theta}_{(B)}^* \]

  • Percentiles: For a \((1-\alpha\) confidence interval, take the \(\alpha/2\) and \(1-\alpha/2\) empirical percentiles of the bootstrap distribution.

\[ \text{Percentile CI} = \left[\hat{\theta}_{(B\cdot\alpha/2)}^*, \hat{\theta}_{(B\cdot(1-\alpha/2))}^*\right] \]

3.2.2 Pseudo-code

The percentile bootstrap method is widely used in practice, especially when dealing with skewed bootstrap sampling distributions. The following pseudocode details the steps required to write an R function for constructing percentile bootstrap confidence intervals.

function percentile_ci(data, statistic, B=1000, alpha=0.05):
    theta_hat, boot_dist = basic_bootstrap(data, statistic, B)
    sorted_boot = sort(boot_dist)
    lower_idx = floor(B * alpha/2)
    upper_idx = ceiling(B * (1 - alpha/2))
    lower = sorted_boot[lower_idx]
    upper = sorted_boot[upper_idx]
    return (lower, upper)

3.2.3 An R Example

We will use built-in R functions boot() and boot.ci() to construct the percentile bootstrap confidence interval based on a simulated random sample from an exponential distribution. A manual calculation based on the formula of the percentile bootstrap confidence interval using the same data

# Percentile Bootstrap CI
set.seed(123)
data <- rexp(25, rate=0.1)  # generating exponential data

# Using boot package
# library(boot)

# Define statistic function
mean_stat <- function(data, indices) {
  sample_data <- data[indices]
  return(mean(sample_data))
}

# Perform bootstrap
boot_result <- boot(data, mean_stat, R=1000)

# Percentile CI
boot.ci(boot_result, type="perc")
BOOTSTRAP CONFIDENCE INTERVAL CALCULATIONS
Based on 1000 bootstrap replicates

CALL : 
boot.ci(boot.out = boot_result, type = "perc")

Intervals : 
Level     Percentile     
95%   ( 5.819, 12.504 )  
Calculations and Intervals on Original Scale
# Manual calculation
boot_vals <- boot_result$t
alpha <- 0.05
ci_perc <- quantile(boot_vals, probs=c(alpha/2, 1-alpha/2))
ci_perc
     2.5%     97.5% 
 5.862205 12.492416 

3.3 Bias-Corrected and Accelerated (BCa) CI

BCa (Bias-Corrected and Accelerated) is an improved bootstrap CI that adjusts for both bias and skewness in the sampling distribution. It computes adjusted percentiles using two correction factors:

  • Bias correction (\(z_0\)): measures median bias by comparing bootstrap estimates to the original estimate.

  • Acceleration (a): measures how the standard error changes with the parameter value (estimated via jackknife).

It generally provides more accurate coverage than the simple percentile method, especially for skewed distributions or biased estimators, and remains transformation-respecting. It is often the recommended default for bootstrap confidence intervals when higher accuracy is needed.

Constructing of BCa CI requires Jackknife algorithm which is resampling technique used primarily for bias correction and variance estimation. It systematically recomputes a statistic by leaving out one observation at a time from the sample, creating multiple pseudo-samples of size \(n-1\).

In the next subsection, we present the two mathematical algorithms.

3.3.1 Mathematical Algorithms


Jackknife Resampling

  • Original sample: \(x_1, x_2, \dots, x_n\) with statistic \(\hat{\theta}\).

  • Jackknife samples: Create \(n\) subsamples, each omitting one observation:

    \[\begin{align*} \text{Sample}_1 &: \; x_2, x_3, \dots, x_n, \\ \text{Sample}_2 &: \; x_1, x_3, \dots, x_n, \\ & \quad \vdots \\ \text{Sample}_n &: \; x_1, x_2, \dots, x_{n-1}. \end{align*}\]

  • Compute statistic: Calculate \(\hat{\theta}_{(i)}\) for each jackknife sample.


BCa CI Algorithm

  • Compute bias correction:

\[ \hat{z}_0 = \Phi^{-1}\left(\frac{\#\{\hat{\theta}_b^* < \hat{\theta}\}}{B}\right) \]

  • Compute acceleration \(\hat{a}\) using jackknife:

\[\begin{align*} \hat{\theta}_{(i)} &= T(X_{-i}) \\ \hat{\theta}_{(\cdot)} &= \frac{1}{n}\sum_{i=1}^n \hat{\theta}_{(i)} \\ \hat{a} &= \frac{\sum_{i=1}^n (\hat{\theta}_{(\cdot)} - \hat{\theta}_{(i)})^3} {6\left[\sum_{i=1}^n (\hat{\theta}_{(\cdot)} - \hat{\theta}_{(i)})^2\right]^{3/2}} \end{align*}\]

  • Compute adjusted percentiles:

\[\begin{align*} \alpha_1 &= \Phi\left(\hat{z}_0 + \frac{\hat{z}_0 + z_{\alpha/2}}{1 - \hat{a}(\hat{z}_0 + z_{\alpha/2})}\right) \\ \alpha_2 &= \Phi\left(\hat{z}_0 + \frac{\hat{z}_0 + z_{1-\alpha/2}}{1 - \hat{a}(\hat{z}_0 + z_{1-\alpha/2})}\right) \end{align*}\]

  • Confidence interval:

\[ \left[\hat{\theta}_{(B\cdot\alpha_1)}^*, \hat{\theta}_{(B\cdot\alpha_2)}^*\right] \]

3.3.2 Pseudo-code

The following pseudo code for BCa CI contains Jackknife Algorithm for calculating the acceleration doefficient.

function bca_ci(data, statistic, B=1000, alpha=0.05):
    theta_hat, boot_dist = basic_bootstrap(data, statistic, B)
    
    # Bias correction
    prop_less = sum(boot_dist < theta_hat) / B
    z0 = qnorm(prop_less)
    
    # Acceleration (jackknife)
    n = length(data)
    jack_vals = numeric(n)
    for i in 1:n:
        jack_sample = data[-i]
        jack_vals[i] = statistic(jack_sample)
    theta_jack_mean = mean(jack_vals)
    numerator = sum((theta_jack_mean - jack_vals)^3)
    denominator = sum((theta_jack_mean - jack_vals)^2)
    a_hat = numerator / (6 * denominator^(3/2))
    
    # Adjusted percentiles
    z_alpha = qnorm(alpha/2)
    z_1alpha = qnorm(1 - alpha/2)
    
    alpha1 = pnorm(z0 + (z0 + z_alpha)/(1 - a_hat*(z0 + z_alpha)))
    alpha2 = pnorm(z0 + (z0 + z_1alpha)/(1 - a_hat*(z0 + z_1alpha)))
    
    sorted_boot = sort(boot_dist)
    lower = quantile(sorted_boot, probs=alpha1)
    upper = quantile(sorted_boot, probs=alpha2)
    
    return (lower, upper)

3.3.3 Practical Recommendations

BCa is the most reliable general-purpose bootstrap CI method for non-symmetric distributions but requires careful implementation and diagnostic checking. When in doubt, compare with percentile and studentized intervals (to be introduced in the next subsection) for consistency

  • When to Use:
    • Non-symmetric distributions, small-to-medium samples (n < 200), biased estimators
    • Avoid for n < 20 or extremely heavy-tailed data
  • Implementation:
    • Minimum \(B = 1,000\) replicates ($ ,000$ for publication/research)
    • Always check bootstrap distribution shape visually
    • Monitor stability: increase \(B\) until intervals change \(< 1\%\)
  • Key Diagnostics:
    • Acceleration value \(|acc| < 0.3\) (red flag if \(> 0.5\))
    • Compare with percentile method - results should be similar for symmetric data
    • Plot histogram of bootstrap replicates for skewness assessment
  • Common Pitfalls:
    • Too few replicates \(\Rightarrow\) unstable intervals
    • Discrete/discontinuous statistics \(\Rightarrow\) use smoothed bootstrap
    • Clustered/time series data \(\Rightarrow\) need specialized bootstrap variants
  • Reporting:
    • Always specify: point estimate, CI, confidence level, B, n
    • Example: “15.2 (BCa 95% CI: [8.7, 21.9]; B=10,000, n=45)”

3.3.4 An R Example

In the following example with simulated data, we use the built-in R functions boot() and boot.ci with an argument to specify the type of bootstrap confidence interval.

# BCa Bootstrap CI for median
library(boot)

median_stat <- function(data, indices) {
  return(median(data[indices]))
}

set.seed(123)
data <- rgamma(30, shape=2, rate=0.5)
boot_result <- boot(data, median_stat, R=2000)

# BCa CI
bca_ci <- boot.ci(boot_result, type="bca")
bca_ci
BOOTSTRAP CONFIDENCE INTERVAL CALCULATIONS
Based on 2000 bootstrap replicates

CALL : 
boot.ci(boot.out = boot_result, type = "bca")

Intervals : 
Level       BCa          
95%   ( 1.954,  4.004 )  
Calculations and Intervals on Original Scale
# Compare different methods
boot.ci(boot_result, type=c("norm", "perc", "bca"))
BOOTSTRAP CONFIDENCE INTERVAL CALCULATIONS
Based on 2000 bootstrap replicates

CALL : 
boot.ci(boot.out = boot_result, type = c("norm", "perc", "bca"))

Intervals : 
Level      Normal             Percentile            BCa          
95%   ( 1.904,  3.662 )   ( 2.057,  4.004 )   ( 1.954,  4.004 )  
Calculations and Intervals on Original Scale

3.4 Studentized (Bootstrap-t) CI

The Studentized bootstrap-t method (also called bootstrap-t) is a bootstrap approach for constructing confidence intervals that accounts for the variability in the estimate’s standard error across bootstrap samples.

3.4.1 Mathematical Algorithm

  • For each bootstrap sample \(b = 1,...,B\):
    • Compute \(\hat{\theta}_b^* = T(X_b^*)\)
    • Estimate standard error \(\hat{se}_b^*\) using a second-level bootstrap
    • Compute: \(t_b^* = \frac{\hat{\theta}_b^* - \hat{\theta}}{\hat{se}_b^*}\)
  • Sort \(t_b^*\) values: \(t_{(1)}^* \leq t_{(2)}^* \leq ... \leq t_{(B)}^*\)
  • Confidence interval:

\[ \left[\hat{\theta} - t_{(1-\alpha/2)}^* \cdot \hat{se}, \hat{\theta} - t_{(\alpha/2)}^* \cdot \hat{se}\right] \]

3.4.2 Pseudo-code

function studentized_ci(data, statistic, B=1000, B2=100, alpha=0.05):
    theta_hat = statistic(data)
    n = length(data)
    t_star = numeric(B)
    
    for b in 1:B:
        # First-level bootstrap
        sample_b = sample(data, n, replace=TRUE)
        theta_b = statistic(sample_b)
        
        # Second-level bootstrap for SE
        theta_b2 = numeric(B2)
        for b2 in 1:B2:
            sample_b2 = sample(sample_b, n, replace=TRUE)
            theta_b2[b2] = statistic(sample_b2)
        se_b = sd(theta_b2)
        
        t_star[b] = (theta_b - theta_hat) / se_b
    
    # Estimate SE of original statistic
    se_hat = sd(replicate(B2, statistic(sample(data, n, replace=TRUE))))
    
    # Get critical values
    t_crit = quantile(t_star, probs=c(1-alpha/2, alpha/2))
    
    lower = theta_hat - t_crit[1] * se_hat
    upper = theta_hat - t_crit[2] * se_hat
    
    return (lower, upper)

3.4.3 An R Example

In the following example with simulated data, we also use the built-in R functions boot() and boot.ci with an argument to specify the type of bootstrap confidence interval.

# Studentized Bootstrap CI
#library(boot)

# Statistic function with variance estimate
mean_var_stat <- function(data, indices) {
  sample_data <- data[indices]
  mean_val <- mean(sample_data)
  
  # Internal bootstrap for variance
  n_inner <- length(sample_data)
  inner_boot <- replicate(200, {
    mean(sample(sample_data, n_inner, replace=TRUE))
  })
  var_val <- var(inner_boot)
  
  return(c(mean_val, var_val))
}

set.seed(123)
data <- rlnorm(20, meanlog=2, sdlog=1)
boot_result <- boot(data, mean_var_stat, R=1000)
boot.ci(boot_result, type="stud")
BOOTSTRAP CONFIDENCE INTERVAL CALCULATIONS
Based on 1000 bootstrap replicates

CALL : 
boot.ci(boot.out = boot_result, type = "stud")

Intervals : 
Level    Studentized     
95%   ( 8.40, 24.12 )  
Calculations and Intervals on Original Scale

3.5 Practical Guidelines

3.5.1 Choosing the Right Method

Method Use Case
Normal CI When bootstrap distribution is approximately normal
Percentile CI Simple method, transformation-respecting
BCa CI More accurate, accounts for bias and skewness
Studentized CI Good for location statistics, accounts for variance variability
Likelihood-based When likelihood inference is appropriate

3.5.2 Number of Bootstrap Replicates

  • Basic estimates: \(B \geq 1000\)
  • Variance estimation: \(B \geq 2000\)
  • Percentile/BCa intervals: \(B \geq 2000-5000\)
  • Studentized intervals: \(B \geq 1000\), with \(B2 \geq 200\) for inner loop

3.5.3 Common Pitfalls

  • Too few bootstrap samples: Leads to unstable intervals
  • Small sample sizes: Bootstrap may not perform well with \(n < 20\)
  • Heavy dependence in data: Requires specialized blocking methods
  • Discrete data: Percentile methods may have poor coverage

R Packages for Bootstrap

  • boot: Comprehensive bootstrap functions
  • bootstrap: Basic bootstrap operations
  • resample: Alternative implementation
  • infer: Tidyverse approach to resampling

4 Overiew of Likelihood-Based Bootstrap CI (optional)

In classical parametric inference, we assume a model \(f(y|\theta)\) and use the likelihood function \(L(\theta)\) to estimate parameters and construct confidence intervals (e.g., using the likelihood ratio test and Wilks’ theorem). However, when the sample size is small or the model is complex, asymptotic likelihood theory may not be reliable.

Likelihood-based bootstrap confidence intervals combine classical likelihood inference with bootstrap resampling to produce more accurate intervals, especially in small samples or non-standard situations.

This is a relatively more advanced topic. We will not discuss it in detail. Instead, we will provide an overview of two likelihood-based confidence intervals and outline the related algorithms. If you are interested in learning more, you can translate the algorithms into R code to implement them and compare the resulting confidence intervals with other types of confidence intervals you have learned previously.

4.1 Percentile Likelihood Bootstrap

The percentile likelihood bootstrap merges two approaches:

  • Likelihood principle: Use the shape of the likelihood function to define plausibility of parameters.

  • Bootstrap principle: Resample data to approximate the sampling distribution of estimates without relying solely on asymptotics.

The method can yield more accurate confidence intervals in finite samples while respecting the likelihood. The brief steps for implementing this bootstrap procedure is summarized in the following algorithm.


Algorithm

Step 1: Resample data with replacement

Step 2: For each bootstrap sample, let \(\hat{\theta}^*\) be the MLE of \(\theta\). compute the likelihood ratio statistic:

\[ \Lambda^*(\theta) = 2[\ell(\hat{\theta}^*) - \ell(\theta)] \]

Step 3: The percentile bootstrap confidence interval is:

\[ \{\theta : \Lambda^*(\theta) \leq \chi^2_{1-\alpha}(1)\} \]

4.2 Bootstrap Calibrated Likelihood Ratio Intervals

These intervals improve upon standard Likelihood Ratio (LR) intervals by correcting their coverage properties through calibration, ensuring the nominal confidence level (e.g., 95%) is closer to the true coverage probability.

For a parameter \(\theta\), the standard LR statistic is:

\[ W(\theta) = 2\bigl[\ell(\hat{\theta}) - \ell(\theta)\bigr] \]

where \(\hat{\theta}\) is the MLE.

Asymptotically: \(W(\theta) \sim \chi_1^2\) under \(H_0: \theta = \theta_0\).

The standard \((1-\alpha)\) LR interval is:

\[ \bigl\{\theta : W(\theta) \leq \chi_{1,1-\alpha}^2 \bigr\} \]

The problem is that this \(\chi^2\) approximation may be poor with small samples and high dimensional inferences.


Algorithm

Step 1: Compute observed LR statistic \(W_{\text{obs}}(\theta)\) for each \(\theta\)

Step 2: Bootstrap resampling:

  • Fit model, get \(\hat{\theta}\)
  • Generate datasets from \(F_{\hat{\theta}}\)
  • Recompute \(W^{*}\) for each

Step 3: Estimate coverage function: \[ \pi(c) = P^{*}(W^{*} \leq c) \]

Step 4: Find calibrated threshold \(c_{\alpha}\) where

\[ \pi(c_{\alpha}) = 1 - \alpha \]

Step 5: Invert test: Include \(\theta\) if

\[ W_{\text{obs}}(\theta) \leq c_{\alpha} \]

LS0tDQp0aXRsZTogIkJvb3RzdHJhcCBDb25maWRlbmNlIEludGVydmFscyINCmF1dGhvcjogIkNoZW5nIFBlbmciDQpkYXRlOiAiV2VzdCBDaGVzdGVyIFVuaXZlcnNpdHkiDQpsYW5nOiBlbg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50OiANCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogNA0KICAgIHRvY19mbG9hdDogeWVzDQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgICB0b2NfY29sbGFwc2VkOiB5ZXMNCiAgICBjb2RlX2ZvbGRpbmc6IHNob3cNCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMNCiAgICBzbW9vdGhfc2Nyb2xsOiB5ZXMNCiAgICAjaGlnaGxpZ2h0OiB6ZW5idXJuDQogICAgI3RoZW1lOiBjZXJ1bGVhbg0KICBwZGZfZG9jdW1lbnQ6IA0KICAgIGtlZXAtdGV4OiB0cnVlDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDQNCiAgICBmaWdfY2FwdGlvbjogeWVzDQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgICBmaWdfd2lkdGg6IDMNCiAgICBmaWdfaGVpZ2h0OiAzDQogIHdvcmRfZG9jdW1lbnQ6IA0KICAgIHRvYzogeWVzDQogICAgdG9jX2RlcHRoOiA0DQogICAgZmlnX2NhcHRpb246IHllcw0KICAgIGtlZXBfbWQ6IHllcw0KZWRpdG9yX29wdGlvbnM6IA0KICBjaHVua19vdXRwdXRfdHlwZTogaW5saW5lDQotLS0NCg0KYGBge2NzcywgZWNobyA9IEZBTFNFfQ0KI1RPQzo6YmVmb3JlIHsNCiAgY29udGVudDogIlRhYmxlIG9mIENvbnRlbnRzIjsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogIGZvbnQtc2l6ZTogMS4yZW07DQogIGRpc3BsYXk6IGJsb2NrOw0KICBjb2xvcjogbmF2eTsNCiAgbWFyZ2luLWJvdHRvbTogMTBweDsNCn0NCg0KDQpkaXYjVE9DIGxpIHsgICAgIC8qIHRhYmxlIG9mIGNvbnRlbnQgICovDQogICAgbGlzdC1zdHlsZTp1cHBlci1yb21hbjsNCiAgICBiYWNrZ3JvdW5kLWltYWdlOm5vbmU7DQogICAgYmFja2dyb3VuZC1yZXBlYXQ6bm9uZTsNCiAgICBiYWNrZ3JvdW5kLXBvc2l0aW9uOjA7DQp9DQoNCmgxLnRpdGxlIHsgICAgLyogbGV2ZWwgMSBoZWFkZXIgb2YgdGl0bGUgICovDQogIGZvbnQtc2l6ZTogMjJweDsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogIGNvbG9yOiBEYXJrUmVkOw0KICB0ZXh0LWFsaWduOiBjZW50ZXI7DQogIGZvbnQtZmFtaWx5OiAiR2lsbCBTYW5zIiwgc2Fucy1zZXJpZjsNCn0NCg0KaDQuYXV0aG9yIHsgLyogSGVhZGVyIDQgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgZm9udC1zaXplOiAxNXB4Ow0KICBmb250LXdlaWdodDogYm9sZDsNCiAgZm9udC1mYW1pbHk6IHN5c3RlbS11aTsNCiAgY29sb3I6IG5hdnk7DQogIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCg0KaDQuZGF0ZSB7IC8qIEhlYWRlciA0IC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovDQogIGZvbnQtc2l6ZTogMThweDsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogIGZvbnQtZmFtaWx5OiAiR2lsbCBTYW5zIiwgc2Fucy1zZXJpZjsNCiAgY29sb3I6IERhcmtCbHVlOw0KICB0ZXh0LWFsaWduOiBjZW50ZXI7DQp9DQoNCmgxIHsgLyogSGVhZGVyIDEgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgICBmb250LXNpemU6IDIwcHg7DQogICAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IGRhcmtyZWQ7DQogICAgdGV4dC1hbGlnbjogY2VudGVyOw0KfQ0KDQpoMiB7IC8qIEhlYWRlciAyIC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovDQogICAgZm9udC1zaXplOiAxOHB4Ow0KICAgIGZvbnQtd2VpZ2h0OiBib2xkOw0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBuYXZ5Ow0KICAgIHRleHQtYWxpZ246IGxlZnQ7DQp9DQoNCmgzIHsgLyogSGVhZGVyIDMgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8NCiAgICBmb250LXNpemU6IDE4cHg7DQogICAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IG5hdnk7DQogICAgdGV4dC1hbGlnbjogbGVmdDsNCn0NCg0KaDQgeyAvKiBIZWFkZXIgNCAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLw0KICAgIGZvbnQtc2l6ZTogMTZweDsNCiAgZm9udC13ZWlnaHQ6IGJvbGQ7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IGRhcmtyZWQ7DQogICAgdGV4dC1hbGlnbjogbGVmdDsNCn0NCg0KLyogQWRkIGRvdHMgYWZ0ZXIgbnVtYmVyZWQgaGVhZGVycyAqLw0KLmhlYWRlci1zZWN0aW9uLW51bWJlcjo6YWZ0ZXIgew0KICBjb250ZW50OiAiLiI7DQoNCmJvZHkge2JhY2tncm91bmQtY29sb3I6ICNmZmZmZmY7DQogICAgICBjb2xvcjogIzAwMDAwMDsNCiAgICAgIGZvbnQtZmFtaWx5OiBBcmlhbCwgc2Fucy1zZXJpZjsNCiAgICAgIGZvbnQtc2l6ZTogMXJlbTsNCiAgICAgIGxpbmUtaGVpZ2h0OiAxLjY7DQogICAgICB9DQoNCi5oaWdobGlnaHRtZSB7IGJhY2tncm91bmQtY29sb3I6eWVsbG93OyB9DQoNCnAgeyBiYWNrZ3JvdW5kLWNvbG9yOndoaXRlOyB9DQoNCn0NCg0KDQoNCg0KDQoNCmBgYA0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCiMgY29kZSBjaHVuayBzcGVjaWZpZXMgd2hldGhlciB0aGUgUiBjb2RlLCB3YXJuaW5ncywgYW5kIG91dHB1dCANCiMgd2lsbCBiZSBpbmNsdWRlZCBpbiB0aGUgb3V0cHV0IGZpbGVzLg0KaWYgKCFyZXF1aXJlKCJrbml0ciIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJrbml0ciIpDQogICBsaWJyYXJ5KGtuaXRyKQ0KfQ0KaWYgKCFyZXF1aXJlKCJwYW5kZXIiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygicGFuZGVyIikNCiAgIGxpYnJhcnkocGFuZGVyKQ0KfQ0KaWYgKCFyZXF1aXJlKCJnZ3Bsb3QyIikpIHsNCiAgaW5zdGFsbC5wYWNrYWdlcygiZ2dwbG90MiIpDQogIGxpYnJhcnkoZ2dwbG90MikNCn0NCmlmICghcmVxdWlyZSgidGlkeXZlcnNlIikpIHsNCiAgaW5zdGFsbC5wYWNrYWdlcygidGlkeXZlcnNlIikNCiAgbGlicmFyeSh0aWR5dmVyc2UpDQp9DQoNCmlmICghcmVxdWlyZSgicGxvdGx5IikpIHsNCiAgaW5zdGFsbC5wYWNrYWdlcygicGxvdGx5IikNCiAgbGlicmFyeShwbG90bHkpDQp9DQppZiAoIXJlcXVpcmUoImZpdGRpc3RycGx1cyIpKSB7DQogIGluc3RhbGwucGFja2FnZXMoImZpdGRpc3RycGx1cyIpDQogIGxpYnJhcnkoZml0ZGlzdHJwbHVzKQ0KfQ0KaWYgKCFyZXF1aXJlKCJib290IikpIHsNCiAgaW5zdGFsbC5wYWNrYWdlcygiYm9vdCIpDQogIGxpYnJhcnkoYm9vdCkNCn0NCiMjICBHbG9iYWwgb3B0aW9ucyBmb3IgYWxsIGNvZGUgY2h1bmtzDQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsICAgICAgICMgaW5jbHVkZSBjb2RlIGNodW5rIGluIHRoZSBvdXRwdXQgZmlsZQ0KICAgICAgICAgICAgICAgICAgICAgIHdhcm5pbmcgPSBGQUxTRSwgICAjIHNvbWV0aW1lcywgeW91IGNvZGUgbWF5IHByb2R1Y2Ugd2FybmluZyBtZXNzYWdlcywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyB5b3UgY2FuIGNob29zZSB0byBpbmNsdWRlIHRoZSB3YXJuaW5nIG1lc3NhZ2VzIGluDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgdGhlIG91dHB1dCBmaWxlLiANCiAgICAgICAgICAgICAgICAgICAgICByZXN1bHRzID0gVFJVRSwgICAgIyB5b3UgY2FuIGFsc28gZGVjaWRlIHdoZXRoZXIgdG8gaW5jbHVkZSB0aGUgb3V0cHV0DQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgaW4gdGhlIG91dHB1dCBmaWxlLg0KICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSwNCiAgICAgICAgICAgICAgICAgICAgICBjb21tZW50ID0gTkENCiAgICAgICAgICAgICAgICAgICAgICApICANCiMjICBvcHRpb25zIGZvciBhbHRlcm5hdGl2ZSB0ZXh0IGFuZCBjYXB0aW9uIG9mIGZpZ3VyZXMNCmtuaXRyOjprbml0X2hvb2tzJHNldChwbG90ID0gZnVuY3Rpb24oeCxvcHRpb25zKSB7DQogICAgICBiYXNlID0ga25pdHI6Om9wdHNfa25pdCRnZXQoJ2Jhc2UudXJsJykNCiAgICAgIGlmIChpcy5udWxsKGJhc2UpKSBiYXNlID0gJycNCiAgICAgIGFsdCA9IGlmZWxzZSAoaXMubnVsbChvcHRpb25zJGFsdCksIiIsb3B0aW9ucyRhbHQpDQogICAgICBjYXAgPSBpZmVsc2UgKGlzLm51bGwob3B0aW9ucyRjYXB0aW9uKSwiIixvcHRpb25zJGNhcHRpb24pDQogICAgICBpZiAoYWx0ICE9ICIiKXsNCiAgICAgICAgc3ByaW50ZignIVslc10oJXMlcyAiJXMiKScsIGNhcCwgYmFzZSwgeCwgYWx0KQ0KICAgICAgfSBlbHNlIHsNCiAgICAgICAgc3ByaW50ZignIVslc10oJXMlcyknLCBjYXAsIGJhc2UsIHgpICANCiAgICAgICAgfQ0KICB9KQ0KYGBgDQoNClwNCg0KIyBJbnRyb2R1Y3Rpb24NCg0KDQpUaGUgYm9vdHN0cmFwIGlzIGEgcmVzYW1wbGluZyB0ZWNobmlxdWUgaW50cm9kdWNlZCBieSBFZnJvbiAoMTk3OSkgdGhhdCBhbGxvd3MgdXMgdG8gZXN0aW1hdGUgdGhlIHNhbXBsaW5nIGRpc3RyaWJ1dGlvbiBvZiBhIHN0YXRpc3RpYyBieSAqKnJlcGVhdGVkbHkqKiBzYW1wbGluZyAqKndpdGggcmVwbGFjZW1lbnQqKiBmcm9tIHRoZSAqKm9ic2VydmVkIGRhdGEqKi4NCg0KVGhlICoqS2V5IFByaW5jaXBsZSoqIGlzIHRyZWF0IHRoZSBlbXBpcmljYWwgZGlzdHJpYnV0aW9uIGZ1bmN0aW9uIChFREYpIG9mIHRoZSBzYW1wbGUgYXMgYW4gYXBwcm94aW1hdGlvbiB0byB0aGUgdHJ1ZSBwb3B1bGF0aW9uIGRpc3RyaWJ1dGlvbjoNCg0KJCQNClxoYXR7Rn1fbih4KSA9IFxmcmFjezF9e259IFxzdW1fe2k9MX1ebiBJKFhfaSBcbGVxIHgpDQokJA0KDQpUaGlzIGtleSBwcmluY2lwbGUgaXMgYmFja2VkIGJ5IHRoZSB3ZWxsIGtub3duICoqR2xpdmVua2/igJNDYW50ZWxsaSBUaGVvcmVtKio6IEVERiBjb252ZXJnZXMgdW5pZm9ybWx5IHRvIENERiBmb3IgaS5pLmQuIGRhdGEuDQoNClwNCg0KIyMgS2V5IEV4cGxpY2l0IGFuZCBJbXBsaWNpdCBBc3N1bXB0aW9ucw0KDQpCb290c3RyYXAgc2FtcGxlcyByZXByZXNlbnQgdGhlIG9yaWdpbmFsIHBvcHVsYXRpb24gd2hlbiB0aGUgb3JpZ2luYWwgc2FtcGxlIGl0c2VsZiBpcyBhIGdvb2QgcmVwcmVzZW50YXRpb24gb2YgdGhlIHBvcHVsYXRpb24uIFRoaXMgaXMgdGhlIGZ1bmRhbWVudGFsIGJvb3RzdHJhcCBwcmluY2lwbGUuDQoNCiogS2V5IEV4cGxpY2l0IENvbmRpdGlvbnMNCiAgKyAqKkluZGVwZW5kZW5jZSBvZiBvYnNlcnZhdGlvbnMqKjogVGhlIG9yaWdpbmFsIGRhdGEgc2hvdWxkIGJlIGluZGVwZW5kZW50IGFuZCBpZGVudGljYWxseSBkaXN0cmlidXRlZCAoaS5pLmQuKSBvciBhdCBsZWFzdCBleGNoYW5nZWFibGUuIFRoZSBzdGFuZGFyZCBib290c3RyYXAgc2FtcGxpbmcgZmFpbHMgZm9yIHRpbWUgc2VyaWVzIHdpdGggc3Ryb25nIGF1dG9jb3JyZWxhdGlvbiwgc3BhdGlhbCBkYXRhLCBjbHVzdGVyZWQgZGF0YSAod2l0aG91dCBzcGVjaWFsIHJlc2FtcGxpbmcgbWV0aG9kcykuDQogICsgKipTYW1wbGUgc2l6ZSBzdWZmaWNpZW50bHkgbGFyZ2UqKjogVGhlIG9yaWdpbmFsIHNhbXBsZSBzaXplICRuJCBzaG91bGQgYmUgbGFyZ2UgZW5vdWdoIHRvIGNhcHR1cmUgdGhlIHBvcHVsYXRpb27igJlzIHZhcmlhYmlsaXR5LiA8Zm9udCBjb2xvciA9ICJyZWQiPlNtYWxsIHNhbXBsZXMgY2FuIHN0aWxsIGJlIGJvb3RzdHJhcHBlZCwgYnV0IHRoZSBib290c3RyYXAgZGlzdHJpYnV0aW9uIG1heSBiZSBjb2Fyc2UgYW5kIG1pZ2h0IG1pc3MgZXh0cmVtZSBxdWFudGlsZXMgb2YgdGhlIHBvcHVsYXRpb248L2ZvbnQ+DQogICsgKipTdGF0aXN0aWMgaXMgc21vb3RoIGFuZCB3ZWxsLWJlaGF2ZWQqKjogQm9vdHN0cmFwIHdvcmtzIHdlbGwgZm9yIHN0YXRpc3RpY3MgdGhhdCBhcmUgc21vb3RoIGZ1bmN0aW9ucyBvZiB0aGUgc2FtcGxlIChlLmcuLCBtZWFuLCB2YXJpYW5jZSwgcmVncmVzc2lvbiBjb2VmZmljaWVudHMpLiAqKkhvd2V2ZXIqKiwgaXQgY2FuIGZhaWwgZm9yIG5vbi1zbW9vdGggc3RhdGlzdGljcyAoZS5nLiwgbWVkaWFuIHdpdGggdmVyeSBzbWFsbCBzYW1wbGVzLCBleHRyZW1lIG9yZGVyIHN0YXRpc3RpY3MpLg0KDQoNCiogS2V5IEltcGxpY2l0IEFzc3VtcHRpb25zDQogICsgKipUaGUgZW1waXJpY2FsIGRpc3RyaWJ1dGlvbiBmdW5jdGlvbiAoRURGKSBpcyBhIGdvb2QgZXN0aW1hdGUgb2YgdGhlIHBvcHVsYXRpb24gQ0RGKiogYmVjYXVzZSBib290c3RyYXAgcmVzYW1wbGluZyBhcHByb3hpbWF0ZXMgc2FtcGxpbmcgZnJvbSB0aGUgRURGLCBub3QgZGlyZWN0bHkgZnJvbSB0aGUgcG9wdWxhdGlvbi4gSWYgdGhlIG9yaWdpbmFsIHNhbXBsZSBpcyBub3QgcmVwcmVzZW50YXRpdmUgKGUuZy4sIGJpYXNlZCBzYW1wbGluZyksIGJvb3RzdHJhcCB3aWxsIHJlcGxpY2F0ZSB0aGUgYmlhcy4NCiAgKyAqKlRoZSB1bmRlcmx5aW5nIHBvcHVsYXRpb24gZGlzdHJpYnV0aW9uIGhhcyBmaW5pdGUgdmFyaWFuY2UqKiB3aGljaCBlbnN1cmVzIGNvbnNpc3RlbmN5IG9mIGJvb3RzdHJhcCBmb3IgdGhlIHNhbXBsZSBtZWFuIChhbmQgcmVsYXRlZCBzdGF0aXN0aWNzKSBpbiBsYXJnZSBzYW1wbGVzLg0KICArICoqTm8gZXh0cmVtZSBvdXRsaWVycyBkcml2aW5nIHRoZSBlc3RpbWF0ZSoqIGJlY2F1c2UgYm9vdHN0cmFwIHNhbXBsZXMgZnJvbSB0aGUgb2JzZXJ2ZWQgZGF0YSwgYSBzaW5nbGUgZXh0cmVtZSBvdXRsaWVyIGNhbiBhcHBlYXIgbXVsdGlwbGUgdGltZXMgaW4gYSBib290c3RyYXAgc2FtcGxlLCBkaXN0b3J0aW5nIHRoZSBib290c3RyYXAgZGlzdHJpYnV0aW9uIG1vcmUgdGhhbiB0aGUgYWN0dWFsIHNhbXBsaW5nIGRpc3RyaWJ1dGlvbi4NCg0KXA0KDQoNCiMjIFdoZW4gQm9vdHN0cmFwIEZhaWxzIG9yIElzIFByb2JsZW1hdGljDQoNCiogKipIZWF2eS10YWlsZWQgZGlzdHJpYnV0aW9ucyB3aXRoIHNtYWxsIG4qKiDigJQgYm9vdHN0cmFwIGNhbiBiZSBpbmNvbnNpc3RlbnQuDQoNCiogKipOb24tc21vb3RoIHBhcmFtZXRlcnMqKiAoZS5nLiwgZXN0aW1hdGluZyBtYXggb2YgZGlzdHJpYnV0aW9uKS4NCg0KKiAqKkRhdGEgd2l0aCBkZXBlbmRlbmN5IHN0cnVjdHVyZSoqICh1bmxlc3MgYmxvY2sgYm9vdHN0cmFwIG9yIHNpbWlsYXIgaXMgdXNlZCkuDQoNCiogKipJbnN1ZmZpY2llbnQgc2FtcGxlIHNpemUqKiBmb3IgY29tcGxleCBzdGF0aXN0aWNzLg0KDQoNClwNCg0KDQojIEJvb3RzdHJhcCBBbGdvcml0aG0gdnMgQm9vdHN0cmFwIFNhbXBsaW5nIERpc3RyaWJ1dGlvbg0KDQpUaGUgQmFzaWMgQm9vdHN0cmFwIEFsZ29yaXRobSAoYWxzbyBjYWxsZWQgdGhlICoqbm9ucGFyYW1ldHJpYyBib290c3RyYXAqKikgaXMgYSByZXNhbXBsaW5nLWJhc2VkIHN0YXRpc3RpY2FsIG1ldGhvZCBpbnRyb2R1Y2VkIGJ5IEJyYWRsZXkgRWZyb24gaW4gMTk3OS4gSXQgcHJvdmlkZXMgYSB3YXkgdG8gZXN0aW1hdGUgdGhlIHNhbXBsaW5nIGRpc3RyaWJ1dGlvbiBvZiAqKmFsbW9zdCBhbnkgc3RhdGlzdGljIHdpdGhvdXQgbWFraW5nIHN0cm9uZyBkaXN0cmlidXRpb25hbCBhc3N1bXB0aW9ucyoqLiBJdCdzIHBvd2VyIGxpZXMgaW4gaXRzIHNpbXBsaWNpdHk6IGJ5IGxldHRpbmcgdGhlIGNvbXB1dGVyIGRvIHRoZSBoZWF2eSBsaWZ0aW5nIHRocm91Z2ggcmVzYW1wbGluZywgd2UgY2FuIG1ha2UgaW5mZXJlbmNlcyB0aGF0IHdvdWxkIGJlIG1hdGhlbWF0aWNhbGx5IGludHJhY3RhYmxlIHVzaW5nIHRyYWRpdGlvbmFsIG1ldGhvZHMuDQoNCg0KIyMgQm9vdHN0cmFwIEFsZ29yaXRobSANCg0KVGhlIGJvb3RzdHJhcCBhbGdvcml0aG0gaXMgYSByZXNhbXBsaW5nIHRlY2huaXF1ZSB0aGF0IHVzZXMgYSBzaW5nbGUgZGF0YXNldCB0byBlc3RpbWF0ZSB0aGUgc2FtcGxpbmcgZGlzdHJpYnV0aW9uIG9mIGEgc3RhdGlzdGljIGJ5IHJlcGVhdGVkbHkgZHJhd2luZyBzYW1wbGVzIHdpdGggcmVwbGFjZW1lbnQgZnJvbSB0aGUgb3JpZ2luYWwgZGF0YSBhbmQgcmVjYWxjdWxhdGluZyB0aGUgc3RhdGlzdGljLg0KDQojIyMgTWF0aGVtYXRpY2FsIEFsZ29yaXRobQ0KDQpMZXQgJFggPSBce3hfMSwgeF8yLCAuLi4sIHhfblx9JCBiZSB0aGUgb3JpZ2luYWwgc2FtcGxlOg0KDQoqIENvbXB1dGUgdGhlIHN0YXRpc3RpYyBvZiBpbnRlcmVzdDogJFxoYXR7XHRoZXRhfSA9IFQoWCkkDQoNCiogRm9yICRiID0gMSQgdG8gJEIkOg0KICArIERyYXcgYSBib290c3RyYXAgc2FtcGxlICRYX2JeKiQgYnkgc2FtcGxpbmcgJG4kIG9ic2VydmF0aW9ucyB3aXRoIHJlcGxhY2VtZW50IGZyb20gJFgkDQogICsgQ29tcHV0ZSAkXGhhdHtcdGhldGF9X2JeKiA9IFQoWF9iXiopJA0KICANCiogVGhlIGJvb3RzdHJhcCBkaXN0cmlidXRpb24gaXMgJFx7XGhhdHtcdGhldGF9XzFeKiwgXGhhdHtcdGhldGF9XzJeKiwgXGNkb3RzLCBcaGF0e1x0aGV0YX1fQl4qXH0kDQogDQpcDQoNCiMjIyBQc2V1ZG8tY29kZQ0KDQpgYGANCmZ1bmN0aW9uIGJhc2ljX2Jvb3RzdHJhcChkYXRhLCBzdGF0aXN0aWMsIEI9MTAwMCk6DQogICAgbiA9IGxlbmd0aChkYXRhKQ0KICAgIHRoZXRhX2hhdCA9IHN0YXRpc3RpYyhkYXRhKQ0KICAgIGJvb3RzdHJhcF9kaXN0ID0gZW1wdHkgdmVjdG9yIG9mIHNpemUgQg0KICAgIA0KICAgIGZvciBiIGluIDE6QjoNCiAgICAgICAgYm9vdHN0cmFwX3NhbXBsZSA9IHNhbXBsZShkYXRhLCBzaXplPW4sIHJlcGxhY2U9VFJVRSkNCiAgICAgICAgYm9vdHN0cmFwX2Rpc3RbYl0gPSBzdGF0aXN0aWMoYm9vdHN0cmFwX3NhbXBsZSkNCiAgICANCiAgICByZXR1cm4gKHRoZXRhX2hhdCwgYm9vdHN0cmFwX2Rpc3QpDQpgYGANClwNCg0KIyMjIFR5cGVzIG9mIEJvb3RzdHJhcCBBbGdvcml0aG1zDQoNCiogKipOb25wYXJhbWV0cmljIEJvb3RzdHJhcCoqIGlzIHRoZSBtb3N0IGNvbW1vbiB0eXBlIChkZXNjcmliZWQgYWJvdmUpLiBJdCBtYWtlcyBubyBhc3N1bXB0aW9ucyBhYm91dCBwb3B1bGF0aW9uIGRpc3RyaWJ1dGlvbiBhbmQgcmVzYW1wbGVzIGRpcmVjdGx5IGZyb20gb2JzZXJ2ZWQgZGF0YS4NCg0KKiAqKlBhcmFtZXRyaWMgQm9vdHN0cmFwKiogYXNzdW1lcyBkYXRhIGNvbWVzIGZyb20gcGFyYW1ldHJpYyBmYW1pbHkgJEYoeDsgXHRoZXRhKSQuIFdlIHRha2UgYW4gb3JpZ2luYWwgc2FtcGxlIGZyb20gdGhlIHBvcHVsYXRpb24gYW5kIGVzdGltYXRlICRcdGhldGEkIGZyb20gZGF0YS4gVGhlICoqYm9vdHN0cmFwIHNhbXBsZXMqKiBmcm9tICRGKHg7IFxoYXR7XHRoZXRhfSQgKGluc3RlYWQgb2YgdGhlIEVDREYgJEZfbih4KSQpIGFuZCBjYWxjdWxhdGUgc3RhdGlzdGljcyBmcm9tIHRoZXNlICoqcGFyYW1ldHJpYyoqIGJvb3RzdHJhcCBzYW1wbGVzLg0KDQoqICoqU3BlY2lhbGl6ZWQgQm9vdHN0cmFwKiogaXMgZm9yIG5vbi1pLmkuZC4gZGF0YSBvciBkYXRhIHdpdGggc3BlY2lhbCBwcm9iYWJpbGl0eSBzdHJ1Y3R1cmVzLiBXZSB3aWxsIG5vdCBleHBsb3JlIHRoaXMgZGlyZWN0aW9uIGluIGRlcHRoLg0KDQpcDQoNCiMjIEJvb3RzdHJhcCBTYW1wbGluZyBEaXN0cmlidXRpb25zDQoNCkJvb3RzdHJhcCBpcyBhIHZlcnNhdGlsZSwgYXNzdW1wdGlvbi1sZWFuIG1ldGhvZCBmb3IgZXN0aW1hdGluZyBzYW1wbGluZyBkaXN0cmlidXRpb25zIG9mICoqc2FtcGxlIHN0YXRpc3RpY3MqKiwgcGFydGljdWxhcmx5IHZhbHVhYmxlIHdoZW4gdGhlb3JldGljYWwgZGlzdHJpYnV0aW9ucyBvZiB0aGVzZSBzdGF0aXN0aWNzIGFyZSB1bmtub3duIG9yIGRpZmZpY3VsdCB0byBkZXJpdmUsIGJ1dCByZXF1aXJlcyBjYXJlZnVsIGltcGxlbWVudGF0aW9uIGFuZCBpbnRlcnByZXRhdGlvbi4NCg0KVGhlIGZvbGxvd2luZyBpcyBhIGxpc3QgZnJlcXVlbnRseSB1c2VkIGJvb3RzdHJhcCBzYW1wbGluZyBkaXN0cmlidXRpb25zIHVzZWQgaW4gcHJhY3RpY2UuDQoNCiogKipEaXN0cmlidXRpb24gb2YgYm9vdHN0cmFwIHNhbXBsZSBtZWFucyoqDQoNCiogKipEaXN0cmlidXRpb24gb2YgYm9vdHN0cmFwIHNhbXBsZSBtZWRpYW5zKioNCg0KKiAqKkRpc3RyaWJ1dGlvbiBvZiBib290c3RyYXAgc2FtcGxlIHZhcmlhbmNlcyBvciBzdGFuZGFyZCBkZXZpYXRpb25zKioNCg0KKiAqKkRpc3RyaWJ1dGlvbiBvZiBib290c3RyYXAgY29ycmVsYXRpb24gY29lZmZpY2llbnRzIChQZWFyc29uJ3MgcikqKg0KDQoqICoqRGlzdHJpYnV0aW9uIG9mIGJvb3RzdHJhcCByZWdyZXNzaW9uIGNvZWZmaWNpZW50cyoqDQoNCiogKipEaXN0cmlidXRpb24gb2YgYm9vdHN0cmFwIHNhbXBsZSBwcm9wb3J0aW9ucyoqDQoNCiogKipEaXN0cmlidXRpb24gb2YgYm9vdHN0cmFwIHJhdGlvcyBvZiBzYW1wbGUgc3RhdGlzdGljcyAoZS5nLiwgY29zdC1lZmZlY3RpdmVuZXNzIHJhdGlvcykqKg0KDQoqICoqRGlzdHJpYnV0aW9uIG9mIGJvb3RzdHJhcCBzdGF0aXN0aWNzIG9mIGFueSBwb3B1bGF0aW9uIHBhcmFtZXRlcnMqKiAgDQoNClRoZSBhYm92ZSBzdGF0aXN0aWNzIGNhbiBiZSBlc3RpbWF0ZWQgYmFzZWQgb24gYW55IGZvcm1hbCBlc3RpbWF0aW9uIG1ldGhvZHMgc3VjaCBhcyBtZXRob2Qgb2YgbW9tZW50cyBlc3RpbWF0b3IgKE1NRSkgYW5kIG1heGltdW0gbGlrZWxpaG9vZCBlc3RpbWF0b3IgKE1MRSkuDQoNClwNCg0KIyMgQXBwbGljYXRpb25zIG9mIEJvb3RzdHJhcCBTYW1wbGluZyBEaXN0cmlidXRpb24NCg0KVGhlIGFwcGxpY2F0aW9ucyBvZiBCb290c3RyYXAgU2FtcGxpbmcgRGlzdHJpYnV0aW9uIHNwYW4gbWFueSBhcmVhcyBvZiBzdGF0aXN0aWNzIGFuZCBkYXRhIHNjaWVuY2UsIHByaW1hcmlseSBmb2N1c2VkIG9uICoqZXN0aW1hdGlvbioqLCAqKmluZmVyZW5jZSoqLCBhbmQgKiphc3Nlc3NpbmcgdW5jZXJ0YWludHkqKiB3aGVuIHRoZW9yZXRpY2FsIGZvcm11bGFzIGFyZSB1bmF2YWlsYWJsZSBvciB1bnJlbGlhYmxlLiBUaGlzIGNvdXJzZSwgd2UgZXhwbG9yZSB0aGUgYXBwbGljYXRpb25zIGluIGVzdGltYXRpb24gYW5kIGh5cG90aGVzaXMgdGVzdGluZy4NCg0KDQojIyMgUG9pbnQgYW5kIEludGVydmFsIEVzdGltYXRpb24NCg0KQm9vdHN0cmFwIHNhbXBsaW5nIGRpc3RyaWJ1dGlvbiBjYW4gYmUgdXNlZCBmb3IgcG9pbnQgYW5kIGludGVydmFsIGVzdGltYXRpb24uIFRoZSANCg0KDQoNCiMjIyBIeXBvdGhlc2lzIFRlc3RpbmcNCg0KDQoNCg0KDQoNCg0KIyBUeXBlcyBvZiBCb290c3RyYXAgQ29uZmlkZW5jZSBJbnRlcnZhbHMNCg0KQm9vdHN0cmFwIENJcyBpbmNsdWRlIHRoZSBwZXJjZW50aWxlIG1ldGhvZCAoc2ltcGxlLCByYW5nZS1wcmVzZXJ2aW5nKSwgQkNhIChjb3JyZWN0cyBiaWFzL3NrZXcsIHJlY29tbWVuZGVkIGRlZmF1bHQpLCBib290c3RyYXAtdCAobW9zdCBhY2N1cmF0ZSB3aXRoIHN0YWJsZSBTRSksIGFuZCBub3JtYWwgYXBwcm94aW1hdGlvbiAoZmFzdCBidXQgYXNzdW1lcyBub3JtYWxpdHkpLiBCQ2EgZ2VuZXJhbGx5IG9mZmVycyB0aGUgYmVzdCBiYWxhbmNlIG9mIGFjY3VyYWN5IGFuZCBwcmFjdGljYWxpdHkgZm9yIG1vc3QgYXBwbGljYXRpb25zLg0KDQoNCiMjIE5vcm1hbCAoU3RhbmRhcmQpIEJvb3RzdHJhcCBDSQ0KDQpUaGlzIGJvb3RzdHJhcCBjb25maWRlbmNlIGludGVydmFsICoqYXNzdW1lcyoqIHRoYXQgYm9vdHN0cmFwIHNhbXBsaW5nIGRpc3RyaWJ1dGlvbiBpcyBhcHByb3hpbWF0ZWx5IG5vcm1hbGx5IGRpc3RyaWJ1dGVkLg0KDQojIyMgTWF0aGVtYXRpY2FsIEFsZ29yaXRobQ0KDQpUaGUgYWxnb3JpdGhtIGlzIHJlbGF0aXZlbHkgc3RyYWlnaHRmb3J3YXJkIGFuZCBzaW1wbGUuIFdlIHN1bW1hcml6ZSBpdCBpbiB0aGUgZm9sbG93aW5nIDQgc3RlcHM6DQoNCg0KKiAgQ29tcHV0ZSAkXGhhdHtcdGhldGF9JCBmcm9tIG9yaWdpbmFsIHNhbXBsZQ0KDQoqICBHZW5lcmF0ZSBib290c3RyYXAgZGlzdHJpYnV0aW9uICRce1xoYXR7XHRoZXRhfV9iXipcfV97Yj0xfV5CJA0KDQoqICBFc3RpbWF0ZSBzdGFuZGFyZCBlcnJvcjogd2l0aCAkXGJhcntcdGhldGF9XiogPSBcZnJhY3sxfXtCfVxzdW1fe2I9MX1eQiBcaGF0e1x0aGV0YX1fYl4qJA0KDQokJA0KXGhhdHtzZX1fe2Jvb3R9ID0gXHNxcnR7XGZyYWN7MX17Qi0xfVxzdW1fe2I9MX1eQiAoXGhhdHtcdGhldGF9X2JeKiAtIFxiYXJ7XHRoZXRhfV4qKV4yfQ0KJCQNCg0KKiAgQ29uZmlkZW5jZSBpbnRlcnZhbDoNCg0KJCQNClxoYXR7XHRoZXRhfSBccG0gel97XGFscGhhLzJ9IFxjZG90IFxoYXR7c2V9X3tib290fQ0KJCQNCg0KDQojIyMgUHNldWRvLWNvZGUNCg0KSW5zdGVhZCBvZiB3cml0aW5nIGFuIFIgZnVuY3Rpb24gdG8gaW1wbGVtZW50IHRoZSBub3JtYWwgKHN0YW5kYXJkIGJvb3RzdHJhcCkgY29uZmlkZW5jZSBpbnRlcnZhbCwgdGhpcyBpcyBhIGdvb2QgY29kaW5nIGV4ZXJjaXNlIHRvIHRyYW5zbGF0ZSB0aGUgcHNldWRvIGNvZGUgaW50byBhIHdvcmthYmxlIFIgZnVuY3Rpb24gdG8gY29uc3RydWN0IHRoZSBub3JtYWwgYm9vdHN0cmFwIGNvbmZpZGVuY2UgaW50ZXJ2YWwuDQoNCmBgYA0KZnVuY3Rpb24gbm9ybWFsX2Jvb3RzdHJhcF9jaShkYXRhLCBzdGF0aXN0aWMsIEI9MTAwMCwgYWxwaGE9MC4wNSk6DQogICAgdGhldGFfaGF0LCBib290X2Rpc3QgPSBiYXNpY19ib290c3RyYXAoZGF0YSwgc3RhdGlzdGljLCBCKQ0KICAgIHNlX2Jvb3QgPSBzZChib290X2Rpc3QpDQogICAgeiA9IHFub3JtKDEgLSBhbHBoYS8yKQ0KICAgIGxvd2VyID0gdGhldGFfaGF0IC0geiAqIHNlX2Jvb3QNCiAgICB1cHBlciA9IHRoZXRhX2hhdCArIHogKiBzZV9ib290DQogICAgcmV0dXJuIChsb3dlciwgdXBwZXIpDQpgYGANCg0KDQojIyMgQW4gUiBFeGFtcGxlDQoNCkluIHRoaXMgZXhhbXBsZSwgd2UgcHJlc2VudCBhIHN0ZXAtYnktc3RlcCBhcHByb2FjaCBmb3IgY2FsY3VsYXRpbmcgdGhlIG5vcm1hbCBjb25maWRlbmNlIGludGVydmFsIHVzaW5nIFIgY29kZSB3aXRoIGEgc2ltdWxhdGVkIGRhdGEgc2V0Lg0KDQpgYGB7cn0NCiMgTm9ybWFsIEJvb3RzdHJhcCBDSSBmb3IgbWVhbg0Kc2V0LnNlZWQoMTIzKQ0KZXhhbXBsZTEuZGF0IDwtIHJub3JtKDMwLCBtZWFuPTUwLCBzZD0xMCkgICMgc2ltdWxhdGUgYSBub3JtYWwgcmFuZG9tIHNhbXBsZQ0KDQojIE1hbnVhbCBpbXBsZW1lbnRhdGlvbg0KQiA8LSAxMDAwDQpuIDwtIGxlbmd0aChleGFtcGxlMS5kYXQpDQpib290X21lYW5zIDwtIG51bWVyaWMoQikgICAgICMgZW1wdHkgdmVjdG9yIHRvIHN0b3JlIGJvb3RzdHJhcCBzYW1wbGUgbWVhbnMNCg0KZm9yKGIgaW4gMTpCKSB7DQogIGJvb3Rfc2FtcGxlIDwtIHNhbXBsZShleGFtcGxlMS5kYXQsIG4sIHJlcGxhY2U9VFJVRSkgICMgZ2VuZXJhdGluZyBib290c3RyYXAgc2FtcGxlDQogIGJvb3RfbWVhbnNbYl0gPC0gbWVhbihib290X3NhbXBsZSkgICAgICAgICAgICAjIGNhbGN1bGF0ZSBib290c3RyYXAgbWVhbnMNCn0NCg0KdGhldGFfaGF0IDwtIG1lYW4oZXhhbXBsZTEuZGF0KSAgICMgc2FtZSBtZWFuIGZyb20gdGhlIG9yaWdpbmFsIHNhbXBsZQ0Kc2VfYm9vdCA8LSBzZChib290X21lYW5zKQ0KeiA8LSBxbm9ybSgwLjk3NSkNCmNpX25vcm1hbCA8LSBjKExDSSA9IHRoZXRhX2hhdCAtIHoqc2VfYm9vdCwgeGJhciA9IHRoZXRhX2hhdCwgVUNMPXRoZXRhX2hhdCArIHoqc2VfYm9vdCkNCmNpX25vcm1hbA0KYGBgDQoNCg0KIyMgUGVyY2VudGlsZSBCb290c3RyYXAgQ0kNCg0KUGVyY2VudGlsZSBib290c3RyYXAgY29uZmlkZW5jZSBpbnRlcnZhbHMgYXJlIHRoZSBzaW1wbGVzdCBmb3JtIG9mIGJvb3RzdHJhcCBDSXMuIFRoZXkgYXJlIGNvbnN0cnVjdGVkIGJ5IGRpcmVjdGx5IHRha2luZyB0aGUgY29ycmVzcG9uZGluZyBxdWFudGlsZXMgKGUuZy4sIDIuNSUgYW5kIDk3LjUlKSBmcm9tIHRoZSBlbXBpcmljYWwgZGlzdHJpYnV0aW9uIG9mIGJvb3RzdHJhcCBlc3RpbWF0ZXMuIFRoaXMgbWV0aG9kIGlzIHJhbmdlLXByZXNlcnZpbmcgKGUuZy4sIHN0YXlzIHdpdGhpbiBbMCwxXSBmb3IgcHJvcG9ydGlvbnMpIGFuZCB3b3JrcyB3ZWxsIHdoZW4gdGhlIGJvb3RzdHJhcCBkaXN0cmlidXRpb24gaXMgcm91Z2hseSBzeW1tZXRyaWMgYW5kIHRoZSBlc3RpbWF0b3IgaGFzIGxpdHRsZSBiaWFzLiANCg0KDQojIyMgTWF0aGVtYXRpY2FsIEFsZ29yaXRobQ0KDQoqICoqUmVzYW1wbGUqKjogRHJhdyBCIGluZGVwZW5kZW50IGJvb3RzdHJhcCBzYW1wbGVzICh3aXRoIHJlcGxhY2VtZW50KSBvZiBzaXplIG4gZnJvbSB0aGUgb3JpZ2luYWwgZGF0YS4NCg0KKiAqKkNvbXB1dGUgc3RhdGlzdGljKio6IEdlbmVyYXRlIGJvb3RzdHJhcCBkaXN0cmlidXRpb24gJFx7XGhhdHtcdGhldGF9X2JeKlx9X3tiPTF9XkIkDQoNCiogKipFbXBpcmljYWwgZGlzdHJpYnV0aW9uKio6IFNvcnQgYm9vdHN0cmFwIHN0YXRpc3RpY3M6IA0KDQokJA0KXGhhdHtcdGhldGF9X3soMSl9XiogXGxlcSBcaGF0e1x0aGV0YX1feygyKX1eKiBcbGVxIC4uLiBcbGVxIFxoYXR7XHRoZXRhfV97KEIpfV4qDQokJA0KDQoqICoqUGVyY2VudGlsZXMqKjogRm9yIGEgJCgxLVxhbHBoYSQgY29uZmlkZW5jZSBpbnRlcnZhbCwgdGFrZSB0aGUgJFxhbHBoYS8yJCBhbmQgJDEtXGFscGhhLzIkIGVtcGlyaWNhbCBwZXJjZW50aWxlcyBvZiB0aGUgYm9vdHN0cmFwIGRpc3RyaWJ1dGlvbi4NCg0KJCQNClx0ZXh0e1BlcmNlbnRpbGUgQ0l9ID0gXGxlZnRbXGhhdHtcdGhldGF9X3soQlxjZG90XGFscGhhLzIpfV4qLCBcaGF0e1x0aGV0YX1feyhCXGNkb3QoMS1cYWxwaGEvMikpfV4qXHJpZ2h0XQ0KJCQNCg0KDQojIyMgUHNldWRvLWNvZGUNCg0KVGhlIHBlcmNlbnRpbGUgYm9vdHN0cmFwIG1ldGhvZCBpcyB3aWRlbHkgdXNlZCBpbiBwcmFjdGljZSwgZXNwZWNpYWxseSB3aGVuIGRlYWxpbmcgd2l0aCBza2V3ZWQgYm9vdHN0cmFwIHNhbXBsaW5nIGRpc3RyaWJ1dGlvbnMuIFRoZSBmb2xsb3dpbmcgcHNldWRvY29kZSBkZXRhaWxzIHRoZSBzdGVwcyByZXF1aXJlZCB0byB3cml0ZSBhbiBSIGZ1bmN0aW9uIGZvciBjb25zdHJ1Y3RpbmcgcGVyY2VudGlsZSBib290c3RyYXAgY29uZmlkZW5jZSBpbnRlcnZhbHMuDQoNCmBgYA0KZnVuY3Rpb24gcGVyY2VudGlsZV9jaShkYXRhLCBzdGF0aXN0aWMsIEI9MTAwMCwgYWxwaGE9MC4wNSk6DQogICAgdGhldGFfaGF0LCBib290X2Rpc3QgPSBiYXNpY19ib290c3RyYXAoZGF0YSwgc3RhdGlzdGljLCBCKQ0KICAgIHNvcnRlZF9ib290ID0gc29ydChib290X2Rpc3QpDQogICAgbG93ZXJfaWR4ID0gZmxvb3IoQiAqIGFscGhhLzIpDQogICAgdXBwZXJfaWR4ID0gY2VpbGluZyhCICogKDEgLSBhbHBoYS8yKSkNCiAgICBsb3dlciA9IHNvcnRlZF9ib290W2xvd2VyX2lkeF0NCiAgICB1cHBlciA9IHNvcnRlZF9ib290W3VwcGVyX2lkeF0NCiAgICByZXR1cm4gKGxvd2VyLCB1cHBlcikNCmBgYA0KDQoNCiMjIyBBbiBSIEV4YW1wbGUNCg0KV2Ugd2lsbCB1c2UgYnVpbHQtaW4gUiBmdW5jdGlvbnMgYGJvb3QoKWAgYW5kIGBib290LmNpKClgIHRvIGNvbnN0cnVjdCB0aGUgcGVyY2VudGlsZSBib290c3RyYXAgY29uZmlkZW5jZSBpbnRlcnZhbCBiYXNlZCBvbiBhIHNpbXVsYXRlZCByYW5kb20gc2FtcGxlIGZyb20gYW4gZXhwb25lbnRpYWwgZGlzdHJpYnV0aW9uLiBBIG1hbnVhbCBjYWxjdWxhdGlvbiBiYXNlZCBvbiB0aGUgZm9ybXVsYSBvZiB0aGUgcGVyY2VudGlsZSBib290c3RyYXAgY29uZmlkZW5jZSBpbnRlcnZhbCB1c2luZyB0aGUgc2FtZSBkYXRhIA0KDQoNCmBgYHtyfQ0KIyBQZXJjZW50aWxlIEJvb3RzdHJhcCBDSQ0Kc2V0LnNlZWQoMTIzKQ0KZGF0YSA8LSByZXhwKDI1LCByYXRlPTAuMSkgICMgZ2VuZXJhdGluZyBleHBvbmVudGlhbCBkYXRhDQoNCiMgVXNpbmcgYm9vdCBwYWNrYWdlDQojIGxpYnJhcnkoYm9vdCkNCg0KIyBEZWZpbmUgc3RhdGlzdGljIGZ1bmN0aW9uDQptZWFuX3N0YXQgPC0gZnVuY3Rpb24oZGF0YSwgaW5kaWNlcykgew0KICBzYW1wbGVfZGF0YSA8LSBkYXRhW2luZGljZXNdDQogIHJldHVybihtZWFuKHNhbXBsZV9kYXRhKSkNCn0NCg0KIyBQZXJmb3JtIGJvb3RzdHJhcA0KYm9vdF9yZXN1bHQgPC0gYm9vdChkYXRhLCBtZWFuX3N0YXQsIFI9MTAwMCkNCg0KIyBQZXJjZW50aWxlIENJDQpib290LmNpKGJvb3RfcmVzdWx0LCB0eXBlPSJwZXJjIikNCg0KIyBNYW51YWwgY2FsY3VsYXRpb24NCmJvb3RfdmFscyA8LSBib290X3Jlc3VsdCR0DQphbHBoYSA8LSAwLjA1DQpjaV9wZXJjIDwtIHF1YW50aWxlKGJvb3RfdmFscywgcHJvYnM9YyhhbHBoYS8yLCAxLWFscGhhLzIpKQ0KY2lfcGVyYw0KYGBgDQoNCg0KDQoNCiMjIEJpYXMtQ29ycmVjdGVkIGFuZCBBY2NlbGVyYXRlZCAoQkNhKSBDSQ0KDQoqKkJDYSAoQmlhcy1Db3JyZWN0ZWQgYW5kIEFjY2VsZXJhdGVkKSoqIGlzIGFuIGltcHJvdmVkIGJvb3RzdHJhcCBDSSB0aGF0IGFkanVzdHMgZm9yIGJvdGggYmlhcyBhbmQgc2tld25lc3MgaW4gdGhlIHNhbXBsaW5nIGRpc3RyaWJ1dGlvbi4gIEl0IGNvbXB1dGVzIGFkanVzdGVkIHBlcmNlbnRpbGVzIHVzaW5nIHR3byBjb3JyZWN0aW9uIGZhY3RvcnM6DQoNCiogKipCaWFzIGNvcnJlY3Rpb24gKCR6XzAkKSoqOiBtZWFzdXJlcyBtZWRpYW4gYmlhcyBieSBjb21wYXJpbmcgYm9vdHN0cmFwIGVzdGltYXRlcyB0byB0aGUgb3JpZ2luYWwgZXN0aW1hdGUuDQoNCiogKipBY2NlbGVyYXRpb24gKGEpKio6IG1lYXN1cmVzIGhvdyB0aGUgc3RhbmRhcmQgZXJyb3IgY2hhbmdlcyB3aXRoIHRoZSBwYXJhbWV0ZXIgdmFsdWUgKGVzdGltYXRlZCB2aWEgamFja2tuaWZlKS4NCg0KSXQgZ2VuZXJhbGx5IHByb3ZpZGVzIG1vcmUgYWNjdXJhdGUgY292ZXJhZ2UgdGhhbiB0aGUgc2ltcGxlIHBlcmNlbnRpbGUgbWV0aG9kLCBlc3BlY2lhbGx5IGZvciBza2V3ZWQgZGlzdHJpYnV0aW9ucyBvciBiaWFzZWQgZXN0aW1hdG9ycywgYW5kIHJlbWFpbnMgdHJhbnNmb3JtYXRpb24tcmVzcGVjdGluZy4gSXQgaXMgb2Z0ZW4gdGhlIHJlY29tbWVuZGVkIGRlZmF1bHQgZm9yIGJvb3RzdHJhcCBjb25maWRlbmNlIGludGVydmFscyB3aGVuIGhpZ2hlciBhY2N1cmFjeSBpcyBuZWVkZWQuDQoNCkNvbnN0cnVjdGluZyBvZiAqKkJDYSBDSSoqIHJlcXVpcmVzICoqSmFja2tuaWZlKiogYWxnb3JpdGhtIHdoaWNoIGlzICoqcmVzYW1wbGluZyB0ZWNobmlxdWUqKiB1c2VkIHByaW1hcmlseSBmb3IgKipiaWFzIGNvcnJlY3Rpb24qKiBhbmQgKip2YXJpYW5jZSBlc3RpbWF0aW9uKiouIEl0IHN5c3RlbWF0aWNhbGx5IHJlY29tcHV0ZXMgYSBzdGF0aXN0aWMgYnkgKipsZWF2aW5nIG91dCBvbmUgb2JzZXJ2YXRpb24gYXQgYSB0aW1lKiogZnJvbSB0aGUgc2FtcGxlLCBjcmVhdGluZyBtdWx0aXBsZSAqKnBzZXVkby1zYW1wbGVzKiogb2Ygc2l6ZSAkbi0xJC4NCg0KDQpJbiB0aGUgbmV4dCBzdWJzZWN0aW9uLCB3ZSBwcmVzZW50IHRoZSB0d28gbWF0aGVtYXRpY2FsIGFsZ29yaXRobXMuDQoNCg0KIyMjIE1hdGhlbWF0aWNhbCBBbGdvcml0aG1zDQoNClwNCg0KPGZvbnQgY29sb3IgPSAiZGFya3JlZCI+KipKYWNra25pZmUgUmVzYW1wbGluZyoqPC9mb250Pg0KDQoqICoqT3JpZ2luYWwgc2FtcGxlKio6ICR4XzEsIHhfMiwgXGRvdHMsIHhfbiQgd2l0aCBzdGF0aXN0aWMgJFxoYXR7XHRoZXRhfSQuDQoNCiogKipKYWNra25pZmUgc2FtcGxlcyoqOiBDcmVhdGUgJG4kIHN1YnNhbXBsZXMsIGVhY2ggb21pdHRpbmcgb25lIG9ic2VydmF0aW9uOg0KDQogICAgXGJlZ2lue2FsaWduKn0NCiAgICAgICAgXHRleHR7U2FtcGxlfV8xICY6IFw7IHhfMiwgeF8zLCBcZG90cywgeF9uLCBcXA0KICAgICAgICBcdGV4dHtTYW1wbGV9XzIgJjogXDsgeF8xLCB4XzMsIFxkb3RzLCB4X24sIFxcDQogICAgICAgICYgXHF1YWQgXHZkb3RzIFxcDQogICAgICAgIFx0ZXh0e1NhbXBsZX1fbiAmOiBcOyB4XzEsIHhfMiwgXGRvdHMsIHhfe24tMX0uDQogICAgXGVuZHthbGlnbip9DQogICAgDQoqICoqQ29tcHV0ZSBzdGF0aXN0aWMqKjogQ2FsY3VsYXRlICRcaGF0e1x0aGV0YX1feyhpKX0kIGZvciBlYWNoIGphY2trbmlmZSBzYW1wbGUuDQoNClwNCg0KPGZvbnQgY29sb3IgPSAiZGFya3JlZCI+KipCQ2EgQ0kgQWxnb3JpdGhtKio8L2ZvbnQ+DQoNCiogQ29tcHV0ZSBiaWFzIGNvcnJlY3Rpb246DQoNCiQkDQpcaGF0e3p9XzAgPSBcUGhpXnstMX1cbGVmdChcZnJhY3tcI1x7XGhhdHtcdGhldGF9X2JeKiA8IFxoYXR7XHRoZXRhfVx9fXtCfVxyaWdodCkNCiQkDQogICAgDQoqIENvbXB1dGUgYWNjZWxlcmF0aW9uICRcaGF0e2F9JCB1c2luZyBqYWNra25pZmU6DQoNCg0KXGJlZ2lue2FsaWduKn0NClxoYXR7XHRoZXRhfV97KGkpfSAmPSBUKFhfey1pfSkgXFwNClxoYXR7XHRoZXRhfV97KFxjZG90KX0gJj0gXGZyYWN7MX17bn1cc3VtX3tpPTF9Xm4gXGhhdHtcdGhldGF9X3soaSl9IFxcDQpcaGF0e2F9ICY9IFxmcmFje1xzdW1fe2k9MX1ebiAoXGhhdHtcdGhldGF9X3soXGNkb3QpfSAtIFxoYXR7XHRoZXRhfV97KGkpfSleM30NCiAgICAgICAgICAgICAgICAgICB7NlxsZWZ0W1xzdW1fe2k9MX1ebiAoXGhhdHtcdGhldGF9X3soXGNkb3QpfSAtIFxoYXR7XHRoZXRhfV97KGkpfSleMlxyaWdodF1eezMvMn19DQpcZW5ke2FsaWduKn0NCg0KDQoqIENvbXB1dGUgYWRqdXN0ZWQgcGVyY2VudGlsZXM6DQoNCg0KXGJlZ2lue2FsaWduKn0NClxhbHBoYV8xICY9IFxQaGlcbGVmdChcaGF0e3p9XzAgKyBcZnJhY3tcaGF0e3p9XzAgKyB6X3tcYWxwaGEvMn19ezEgLSBcaGF0e2F9KFxoYXR7en1fMCArIHpfe1xhbHBoYS8yfSl9XHJpZ2h0KSBcXA0KXGFscGhhXzIgJj0gXFBoaVxsZWZ0KFxoYXR7en1fMCArIFxmcmFje1xoYXR7en1fMCArIHpfezEtXGFscGhhLzJ9fXsxIC0gXGhhdHthfShcaGF0e3p9XzAgKyB6X3sxLVxhbHBoYS8yfSl9XHJpZ2h0KQ0KXGVuZHthbGlnbip9DQoNCg0KKiAgQ29uZmlkZW5jZSBpbnRlcnZhbDoNCg0KJCQNClxsZWZ0W1xoYXR7XHRoZXRhfV97KEJcY2RvdFxhbHBoYV8xKX1eKiwgXGhhdHtcdGhldGF9X3soQlxjZG90XGFscGhhXzIpfV4qXHJpZ2h0XQ0KJCQNCg0KDQojIyMgUHNldWRvLWNvZGUNCg0KVGhlIGZvbGxvd2luZyBwc2V1ZG8gY29kZSBmb3IgQkNhIENJIGNvbnRhaW5zICoqSmFja2tuaWZlIEFsZ29yaXRobSoqIGZvciBjYWxjdWxhdGluZyB0aGUgYWNjZWxlcmF0aW9uIGRvZWZmaWNpZW50Lg0KDQoNCmBgYHt9DQpmdW5jdGlvbiBiY2FfY2koZGF0YSwgc3RhdGlzdGljLCBCPTEwMDAsIGFscGhhPTAuMDUpOg0KICAgIHRoZXRhX2hhdCwgYm9vdF9kaXN0ID0gYmFzaWNfYm9vdHN0cmFwKGRhdGEsIHN0YXRpc3RpYywgQikNCiAgICANCiAgICAjIEJpYXMgY29ycmVjdGlvbg0KICAgIHByb3BfbGVzcyA9IHN1bShib290X2Rpc3QgPCB0aGV0YV9oYXQpIC8gQg0KICAgIHowID0gcW5vcm0ocHJvcF9sZXNzKQ0KICAgIA0KICAgICMgQWNjZWxlcmF0aW9uIChqYWNra25pZmUpDQogICAgbiA9IGxlbmd0aChkYXRhKQ0KICAgIGphY2tfdmFscyA9IG51bWVyaWMobikNCiAgICBmb3IgaSBpbiAxOm46DQogICAgICAgIGphY2tfc2FtcGxlID0gZGF0YVstaV0NCiAgICAgICAgamFja192YWxzW2ldID0gc3RhdGlzdGljKGphY2tfc2FtcGxlKQ0KICAgIHRoZXRhX2phY2tfbWVhbiA9IG1lYW4oamFja192YWxzKQ0KICAgIG51bWVyYXRvciA9IHN1bSgodGhldGFfamFja19tZWFuIC0gamFja192YWxzKV4zKQ0KICAgIGRlbm9taW5hdG9yID0gc3VtKCh0aGV0YV9qYWNrX21lYW4gLSBqYWNrX3ZhbHMpXjIpDQogICAgYV9oYXQgPSBudW1lcmF0b3IgLyAoNiAqIGRlbm9taW5hdG9yXigzLzIpKQ0KICAgIA0KICAgICMgQWRqdXN0ZWQgcGVyY2VudGlsZXMNCiAgICB6X2FscGhhID0gcW5vcm0oYWxwaGEvMikNCiAgICB6XzFhbHBoYSA9IHFub3JtKDEgLSBhbHBoYS8yKQ0KICAgIA0KICAgIGFscGhhMSA9IHBub3JtKHowICsgKHowICsgel9hbHBoYSkvKDEgLSBhX2hhdCooejAgKyB6X2FscGhhKSkpDQogICAgYWxwaGEyID0gcG5vcm0oejAgKyAoejAgKyB6XzFhbHBoYSkvKDEgLSBhX2hhdCooejAgKyB6XzFhbHBoYSkpKQ0KICAgIA0KICAgIHNvcnRlZF9ib290ID0gc29ydChib290X2Rpc3QpDQogICAgbG93ZXIgPSBxdWFudGlsZShzb3J0ZWRfYm9vdCwgcHJvYnM9YWxwaGExKQ0KICAgIHVwcGVyID0gcXVhbnRpbGUoc29ydGVkX2Jvb3QsIHByb2JzPWFscGhhMikNCiAgICANCiAgICByZXR1cm4gKGxvd2VyLCB1cHBlcikNCmBgYA0KDQoNCg0KIyMjIFByYWN0aWNhbCBSZWNvbW1lbmRhdGlvbnMNCg0KQkNhIGlzIHRoZSBtb3N0IHJlbGlhYmxlIGdlbmVyYWwtcHVycG9zZSBib290c3RyYXAgQ0kgbWV0aG9kIGZvciBub24tc3ltbWV0cmljIGRpc3RyaWJ1dGlvbnMgYnV0IHJlcXVpcmVzIGNhcmVmdWwgaW1wbGVtZW50YXRpb24gYW5kIGRpYWdub3N0aWMgY2hlY2tpbmcuIFdoZW4gaW4gZG91YnQsIGNvbXBhcmUgd2l0aCAqKnBlcmNlbnRpbGUqKiBhbmQgKipzdHVkZW50aXplZCBpbnRlcnZhbHMqKiAoPGZvbnQgY29sb3IgPSAiZGFya3JlZCI+dG8gYmUgaW50cm9kdWNlZCBpbiB0aGUgbmV4dCBzdWJzZWN0aW9uPC9mb250PikgZm9yIGNvbnNpc3RlbmN5DQoNCiogKipXaGVuIHRvIFVzZSoqOg0KICArIE5vbi1zeW1tZXRyaWMgZGlzdHJpYnV0aW9ucywgc21hbGwtdG8tbWVkaXVtIHNhbXBsZXMgKG4gPCAyMDApLCBiaWFzZWQgZXN0aW1hdG9ycw0KICArIEF2b2lkIGZvciBuIDwgMjAgb3IgZXh0cmVtZWx5IGhlYXZ5LXRhaWxlZCBkYXRhDQoNCiogKipJbXBsZW1lbnRhdGlvbioqOg0KICArIE1pbmltdW0gJEIgPSAxLDAwMCQgcmVwbGljYXRlcyAoJCBcZ2UgMTAsMDAwJCBmb3IgcHVibGljYXRpb24vcmVzZWFyY2gpDQogICsgQWx3YXlzIGNoZWNrIGJvb3RzdHJhcCBkaXN0cmlidXRpb24gc2hhcGUgdmlzdWFsbHkNCiAgKyBNb25pdG9yIHN0YWJpbGl0eTogaW5jcmVhc2UgJEIkIHVudGlsIGludGVydmFscyBjaGFuZ2UgJDwgMVwlJA0KDQoqICoqS2V5IERpYWdub3N0aWNzKio6DQogICsgQWNjZWxlcmF0aW9uIHZhbHVlICR8YWNjfCA8IDAuMyQgKHJlZCBmbGFnIGlmICQ+IDAuNSQpDQogICsgQ29tcGFyZSB3aXRoIHBlcmNlbnRpbGUgbWV0aG9kIC0gcmVzdWx0cyBzaG91bGQgYmUgc2ltaWxhciBmb3Igc3ltbWV0cmljIGRhdGENCiAgKyBQbG90IGhpc3RvZ3JhbSBvZiBib290c3RyYXAgcmVwbGljYXRlcyBmb3Igc2tld25lc3MgYXNzZXNzbWVudA0KDQoqICoqQ29tbW9uIFBpdGZhbGxzKio6DQogICsgVG9vIGZldyByZXBsaWNhdGVzICRcUmlnaHRhcnJvdyQgdW5zdGFibGUgaW50ZXJ2YWxzDQogICsgRGlzY3JldGUvZGlzY29udGludW91cyBzdGF0aXN0aWNzICRcUmlnaHRhcnJvdyQgdXNlIHNtb290aGVkIGJvb3RzdHJhcA0KICArIENsdXN0ZXJlZC90aW1lIHNlcmllcyBkYXRhICRcUmlnaHRhcnJvdyQgbmVlZCBzcGVjaWFsaXplZCBib290c3RyYXAgdmFyaWFudHMNCg0KKiAqKlJlcG9ydGluZyoqOg0KICArICoqQWx3YXlzIHNwZWNpZnkqKjogcG9pbnQgZXN0aW1hdGUsIENJLCBjb25maWRlbmNlIGxldmVsLCBCLCBuDQogICsgKipFeGFtcGxlKio6ICIxNS4yIChCQ2EgOTUlIENJOiBbOC43LCAyMS45XTsgQj0xMCwwMDAsIG49NDUpIg0KDQoNCiMjIyBBbiBSIEV4YW1wbGUNCg0KSW4gdGhlIGZvbGxvd2luZyBleGFtcGxlIHdpdGggc2ltdWxhdGVkIGRhdGEsIHdlIHVzZSB0aGUgYnVpbHQtaW4gUiBmdW5jdGlvbnMgYGJvb3QoKWAgYW5kIGBib290LmNpYCB3aXRoIGFuIGFyZ3VtZW50IHRvIHNwZWNpZnkgdGhlIHR5cGUgb2YgYm9vdHN0cmFwIGNvbmZpZGVuY2UgaW50ZXJ2YWwuDQoNCg0KYGBge3J9DQojIEJDYSBCb290c3RyYXAgQ0kgZm9yIG1lZGlhbg0KbGlicmFyeShib290KQ0KDQptZWRpYW5fc3RhdCA8LSBmdW5jdGlvbihkYXRhLCBpbmRpY2VzKSB7DQogIHJldHVybihtZWRpYW4oZGF0YVtpbmRpY2VzXSkpDQp9DQoNCnNldC5zZWVkKDEyMykNCmRhdGEgPC0gcmdhbW1hKDMwLCBzaGFwZT0yLCByYXRlPTAuNSkNCmJvb3RfcmVzdWx0IDwtIGJvb3QoZGF0YSwgbWVkaWFuX3N0YXQsIFI9MjAwMCkNCg0KIyBCQ2EgQ0kNCmJjYV9jaSA8LSBib290LmNpKGJvb3RfcmVzdWx0LCB0eXBlPSJiY2EiKQ0KYmNhX2NpDQoNCiMgQ29tcGFyZSBkaWZmZXJlbnQgbWV0aG9kcw0KYm9vdC5jaShib290X3Jlc3VsdCwgdHlwZT1jKCJub3JtIiwgInBlcmMiLCAiYmNhIikpDQpgYGANCg0KIyMgU3R1ZGVudGl6ZWQgKEJvb3RzdHJhcC10KSBDSQ0KDQpUaGUgU3R1ZGVudGl6ZWQgYm9vdHN0cmFwLXQgbWV0aG9kIChhbHNvIGNhbGxlZCBib290c3RyYXAtdCkgaXMgYSBib290c3RyYXAgYXBwcm9hY2ggZm9yIGNvbnN0cnVjdGluZyBjb25maWRlbmNlIGludGVydmFscyB0aGF0IGFjY291bnRzIGZvciB0aGUgdmFyaWFiaWxpdHkgaW4gdGhlIGVzdGltYXRl4oCZcyBzdGFuZGFyZCBlcnJvciBhY3Jvc3MgYm9vdHN0cmFwIHNhbXBsZXMuDQoNCg0KIyMjIE1hdGhlbWF0aWNhbCBBbGdvcml0aG0NCg0KKiBGb3IgZWFjaCBib290c3RyYXAgc2FtcGxlICRiID0gMSwuLi4sQiQ6DQogICsgIENvbXB1dGUgJFxoYXR7XHRoZXRhfV9iXiogPSBUKFhfYl4qKSQNCiAgKyAgRXN0aW1hdGUgc3RhbmRhcmQgZXJyb3IgJFxoYXR7c2V9X2JeKiQgdXNpbmcgYSBzZWNvbmQtbGV2ZWwgYm9vdHN0cmFwDQogICsgIENvbXB1dGU6ICR0X2JeKiA9IFxmcmFje1xoYXR7XHRoZXRhfV9iXiogLSBcaGF0e1x0aGV0YX19e1xoYXR7c2V9X2JeKn0kDQoqIFNvcnQgJHRfYl4qJCB2YWx1ZXM6ICR0X3soMSl9XiogXGxlcSB0X3soMil9XiogXGxlcSAuLi4gXGxlcSB0X3soQil9XiokDQoqIENvbmZpZGVuY2UgaW50ZXJ2YWw6DQoNCiQkDQpcbGVmdFtcaGF0e1x0aGV0YX0gLSB0X3soMS1cYWxwaGEvMil9XiogXGNkb3QgXGhhdHtzZX0sIA0KICAgXGhhdHtcdGhldGF9IC0gdF97KFxhbHBoYS8yKX1eKiBcY2RvdCBcaGF0e3NlfVxyaWdodF0NCiQkDQoNCg0KIyMjIFBzZXVkby1jb2RlDQoNCmBgYA0KZnVuY3Rpb24gc3R1ZGVudGl6ZWRfY2koZGF0YSwgc3RhdGlzdGljLCBCPTEwMDAsIEIyPTEwMCwgYWxwaGE9MC4wNSk6DQogICAgdGhldGFfaGF0ID0gc3RhdGlzdGljKGRhdGEpDQogICAgbiA9IGxlbmd0aChkYXRhKQ0KICAgIHRfc3RhciA9IG51bWVyaWMoQikNCiAgICANCiAgICBmb3IgYiBpbiAxOkI6DQogICAgICAgICMgRmlyc3QtbGV2ZWwgYm9vdHN0cmFwDQogICAgICAgIHNhbXBsZV9iID0gc2FtcGxlKGRhdGEsIG4sIHJlcGxhY2U9VFJVRSkNCiAgICAgICAgdGhldGFfYiA9IHN0YXRpc3RpYyhzYW1wbGVfYikNCiAgICAgICAgDQogICAgICAgICMgU2Vjb25kLWxldmVsIGJvb3RzdHJhcCBmb3IgU0UNCiAgICAgICAgdGhldGFfYjIgPSBudW1lcmljKEIyKQ0KICAgICAgICBmb3IgYjIgaW4gMTpCMjoNCiAgICAgICAgICAgIHNhbXBsZV9iMiA9IHNhbXBsZShzYW1wbGVfYiwgbiwgcmVwbGFjZT1UUlVFKQ0KICAgICAgICAgICAgdGhldGFfYjJbYjJdID0gc3RhdGlzdGljKHNhbXBsZV9iMikNCiAgICAgICAgc2VfYiA9IHNkKHRoZXRhX2IyKQ0KICAgICAgICANCiAgICAgICAgdF9zdGFyW2JdID0gKHRoZXRhX2IgLSB0aGV0YV9oYXQpIC8gc2VfYg0KICAgIA0KICAgICMgRXN0aW1hdGUgU0Ugb2Ygb3JpZ2luYWwgc3RhdGlzdGljDQogICAgc2VfaGF0ID0gc2QocmVwbGljYXRlKEIyLCBzdGF0aXN0aWMoc2FtcGxlKGRhdGEsIG4sIHJlcGxhY2U9VFJVRSkpKSkNCiAgICANCiAgICAjIEdldCBjcml0aWNhbCB2YWx1ZXMNCiAgICB0X2NyaXQgPSBxdWFudGlsZSh0X3N0YXIsIHByb2JzPWMoMS1hbHBoYS8yLCBhbHBoYS8yKSkNCiAgICANCiAgICBsb3dlciA9IHRoZXRhX2hhdCAtIHRfY3JpdFsxXSAqIHNlX2hhdA0KICAgIHVwcGVyID0gdGhldGFfaGF0IC0gdF9jcml0WzJdICogc2VfaGF0DQogICAgDQogICAgcmV0dXJuIChsb3dlciwgdXBwZXIpDQpgYGANCg0KDQoNCiMjIyBBbiBSIEV4YW1wbGUNCg0KSW4gdGhlIGZvbGxvd2luZyBleGFtcGxlIHdpdGggc2ltdWxhdGVkIGRhdGEsIHdlIGFsc28gdXNlIHRoZSBidWlsdC1pbiBSIGZ1bmN0aW9ucyBgYm9vdCgpYCBhbmQgYGJvb3QuY2lgIHdpdGggYW4gYXJndW1lbnQgdG8gc3BlY2lmeSB0aGUgdHlwZSBvZiBib290c3RyYXAgY29uZmlkZW5jZSBpbnRlcnZhbC4NCg0KDQpgYGB7cn0NCiMgU3R1ZGVudGl6ZWQgQm9vdHN0cmFwIENJDQojbGlicmFyeShib290KQ0KDQojIFN0YXRpc3RpYyBmdW5jdGlvbiB3aXRoIHZhcmlhbmNlIGVzdGltYXRlDQptZWFuX3Zhcl9zdGF0IDwtIGZ1bmN0aW9uKGRhdGEsIGluZGljZXMpIHsNCiAgc2FtcGxlX2RhdGEgPC0gZGF0YVtpbmRpY2VzXQ0KICBtZWFuX3ZhbCA8LSBtZWFuKHNhbXBsZV9kYXRhKQ0KICANCiAgIyBJbnRlcm5hbCBib290c3RyYXAgZm9yIHZhcmlhbmNlDQogIG5faW5uZXIgPC0gbGVuZ3RoKHNhbXBsZV9kYXRhKQ0KICBpbm5lcl9ib290IDwtIHJlcGxpY2F0ZSgyMDAsIHsNCiAgICBtZWFuKHNhbXBsZShzYW1wbGVfZGF0YSwgbl9pbm5lciwgcmVwbGFjZT1UUlVFKSkNCiAgfSkNCiAgdmFyX3ZhbCA8LSB2YXIoaW5uZXJfYm9vdCkNCiAgDQogIHJldHVybihjKG1lYW5fdmFsLCB2YXJfdmFsKSkNCn0NCg0Kc2V0LnNlZWQoMTIzKQ0KZGF0YSA8LSBybG5vcm0oMjAsIG1lYW5sb2c9Miwgc2Rsb2c9MSkNCmJvb3RfcmVzdWx0IDwtIGJvb3QoZGF0YSwgbWVhbl92YXJfc3RhdCwgUj0xMDAwKQ0KYm9vdC5jaShib290X3Jlc3VsdCwgdHlwZT0ic3R1ZCIpDQpgYGANCg0KDQoNCg0KIyMgUHJhY3RpY2FsIEd1aWRlbGluZXMNCg0KIyMjIENob29zaW5nIHRoZSBSaWdodCBNZXRob2QNCg0KfCBNZXRob2QgIHwgIFVzZSBDYXNlICB8DQp8Oi0tLS0tLS0tLS18Oi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tfA0KfCBOb3JtYWwgQ0kgfCAgV2hlbiBib290c3RyYXAgZGlzdHJpYnV0aW9uIGlzIGFwcHJveGltYXRlbHkgbm9ybWFsIHwgDQp8IFBlcmNlbnRpbGUgQ0kgfCAgU2ltcGxlIG1ldGhvZCwgdHJhbnNmb3JtYXRpb24tcmVzcGVjdGluZyB8IA0KfCBCQ2EgQ0kgfCAgTW9yZSBhY2N1cmF0ZSwgYWNjb3VudHMgZm9yIGJpYXMgYW5kIHNrZXduZXNzIHwgDQp8IFN0dWRlbnRpemVkIENJIHwgIEdvb2QgZm9yIGxvY2F0aW9uIHN0YXRpc3RpY3MsIGFjY291bnRzIGZvciB2YXJpYW5jZSB2YXJpYWJpbGl0eXwgDQp8IExpa2VsaWhvb2QtYmFzZWQgfCAgV2hlbiBsaWtlbGlob29kIGluZmVyZW5jZSBpcyBhcHByb3ByaWF0ZSB8IA0KDQoNCg0KIyMjIE51bWJlciBvZiBCb290c3RyYXAgUmVwbGljYXRlcw0KDQoqIEJhc2ljIGVzdGltYXRlczogJEIgXGdlcSAxMDAwJA0KKiBWYXJpYW5jZSBlc3RpbWF0aW9uOiAkQiBcZ2VxIDIwMDAkDQoqIFBlcmNlbnRpbGUvQkNhIGludGVydmFsczogJEIgXGdlcSAyMDAwLTUwMDAkDQoqIFN0dWRlbnRpemVkIGludGVydmFsczogJEIgXGdlcSAxMDAwJCwgd2l0aCAkQjIgXGdlcSAyMDAkIGZvciBpbm5lciBsb29wDQoNCg0KIyMjIENvbW1vbiBQaXRmYWxscw0KDQoqICoqVG9vIGZldyBib290c3RyYXAgc2FtcGxlcyoqOiBMZWFkcyB0byB1bnN0YWJsZSBpbnRlcnZhbHMNCiogKipTbWFsbCBzYW1wbGUgc2l6ZXMqKjogQm9vdHN0cmFwIG1heSBub3QgcGVyZm9ybSB3ZWxsIHdpdGggJG4gPCAyMCQNCiogKipIZWF2eSBkZXBlbmRlbmNlIGluIGRhdGEqKjogUmVxdWlyZXMgc3BlY2lhbGl6ZWQgYmxvY2tpbmcgbWV0aG9kcw0KKiAqKkRpc2NyZXRlIGRhdGEqKjogUGVyY2VudGlsZSBtZXRob2RzIG1heSBoYXZlIHBvb3IgY292ZXJhZ2UNCg0KDQoqKlIgUGFja2FnZXMgZm9yIEJvb3RzdHJhcCoqDQoNCiogKipib290Kio6IENvbXByZWhlbnNpdmUgYm9vdHN0cmFwIGZ1bmN0aW9ucw0KKiAqKmJvb3RzdHJhcCoqOiBCYXNpYyBib290c3RyYXAgb3BlcmF0aW9ucw0KKiAqKnJlc2FtcGxlKio6IEFsdGVybmF0aXZlIGltcGxlbWVudGF0aW9uDQoqICoqaW5mZXIqKjogVGlkeXZlcnNlIGFwcHJvYWNoIHRvIHJlc2FtcGxpbmcNCg0KDQoNCg0KIyBPdmVyaWV3IG9mIExpa2VsaWhvb2QtQmFzZWQgQm9vdHN0cmFwIENJIDxmb250IGNvbG9yID0gInJlZCI+KG9wdGlvbmFsKTwvZm9udD4NCg0KSW4gY2xhc3NpY2FsIHBhcmFtZXRyaWMgaW5mZXJlbmNlLCB3ZSBhc3N1bWUgYSBtb2RlbCAkZih5fFx0aGV0YSkkIGFuZCB1c2UgdGhlIGxpa2VsaWhvb2QgZnVuY3Rpb24gJEwoXHRoZXRhKSQgdG8gZXN0aW1hdGUgcGFyYW1ldGVycyBhbmQgY29uc3RydWN0IGNvbmZpZGVuY2UgaW50ZXJ2YWxzIChlLmcuLCB1c2luZyB0aGUgbGlrZWxpaG9vZCByYXRpbyB0ZXN0IGFuZCBXaWxrc+KAmSB0aGVvcmVtKS4gSG93ZXZlciwgd2hlbiB0aGUgc2FtcGxlIHNpemUgaXMgc21hbGwgb3IgdGhlIG1vZGVsIGlzIGNvbXBsZXgsIGFzeW1wdG90aWMgbGlrZWxpaG9vZCB0aGVvcnkgbWF5IG5vdCBiZSByZWxpYWJsZS4NCg0KKipMaWtlbGlob29kLWJhc2VkIGJvb3RzdHJhcCBjb25maWRlbmNlIGludGVydmFscyoqIGNvbWJpbmUgY2xhc3NpY2FsIGxpa2VsaWhvb2QgaW5mZXJlbmNlIHdpdGggYm9vdHN0cmFwIHJlc2FtcGxpbmcgdG8gcHJvZHVjZSBtb3JlIGFjY3VyYXRlIGludGVydmFscywgZXNwZWNpYWxseSBpbiBzbWFsbCBzYW1wbGVzIG9yIG5vbi1zdGFuZGFyZCBzaXR1YXRpb25zLg0KDQpUaGlzIGlzIGEgcmVsYXRpdmVseSBtb3JlIGFkdmFuY2VkIHRvcGljLiBXZSB3aWxsIG5vdCBkaXNjdXNzIGl0IGluIGRldGFpbC4gSW5zdGVhZCwgd2Ugd2lsbCBwcm92aWRlIGFuIG92ZXJ2aWV3IG9mIHR3byBsaWtlbGlob29kLWJhc2VkIGNvbmZpZGVuY2UgaW50ZXJ2YWxzIGFuZCBvdXRsaW5lIHRoZSByZWxhdGVkIGFsZ29yaXRobXMuIElmIHlvdSBhcmUgaW50ZXJlc3RlZCBpbiBsZWFybmluZyBtb3JlLCB5b3UgY2FuIHRyYW5zbGF0ZSB0aGUgYWxnb3JpdGhtcyBpbnRvIFIgY29kZSB0byBpbXBsZW1lbnQgdGhlbSBhbmQgY29tcGFyZSB0aGUgcmVzdWx0aW5nIGNvbmZpZGVuY2UgaW50ZXJ2YWxzIHdpdGggb3RoZXIgdHlwZXMgb2YgY29uZmlkZW5jZSBpbnRlcnZhbHMgeW91IGhhdmUgbGVhcm5lZCBwcmV2aW91c2x5Lg0KDQoNCiMjIFBlcmNlbnRpbGUgTGlrZWxpaG9vZCBCb290c3RyYXANCg0KDQpUaGUgcGVyY2VudGlsZSBsaWtlbGlob29kIGJvb3RzdHJhcCBtZXJnZXMgdHdvIGFwcHJvYWNoZXM6DQoNCiogKipMaWtlbGlob29kIHByaW5jaXBsZSoqOiBVc2UgdGhlIHNoYXBlIG9mIHRoZSBsaWtlbGlob29kIGZ1bmN0aW9uIHRvIGRlZmluZSBwbGF1c2liaWxpdHkgb2YgcGFyYW1ldGVycy4NCg0KKiAqKkJvb3RzdHJhcCBwcmluY2lwbGUqKjogUmVzYW1wbGUgZGF0YSB0byBhcHByb3hpbWF0ZSB0aGUgc2FtcGxpbmcgZGlzdHJpYnV0aW9uIG9mIGVzdGltYXRlcyB3aXRob3V0IHJlbHlpbmcgc29sZWx5IG9uIGFzeW1wdG90aWNzLg0KDQpUaGUgbWV0aG9kIGNhbiB5aWVsZCBtb3JlIGFjY3VyYXRlIGNvbmZpZGVuY2UgaW50ZXJ2YWxzIGluIGZpbml0ZSBzYW1wbGVzIHdoaWxlIHJlc3BlY3RpbmcgdGhlIGxpa2VsaWhvb2QuIFRoZSBicmllZiBzdGVwcyBmb3IgaW1wbGVtZW50aW5nIHRoaXMgYm9vdHN0cmFwIHByb2NlZHVyZSBpcyBzdW1tYXJpemVkIGluIHRoZSBmb2xsb3dpbmcgYWxnb3JpdGhtLg0KDQpcDQoNCjxmb250IGNvbG9yID0gImJsdWUiPioqQWxnb3JpdGhtKio8L2ZvbnQ+DQoNCioqU3RlcCAxKio6IFJlc2FtcGxlIGRhdGEgd2l0aCByZXBsYWNlbWVudA0KDQoqKlN0ZXAgMioqOiBGb3IgZWFjaCBib290c3RyYXAgc2FtcGxlLCBsZXQgJFxoYXR7XHRoZXRhfV4qJCBiZSB0aGUgTUxFIG9mICRcdGhldGEkLiAgY29tcHV0ZSB0aGUgbGlrZWxpaG9vZCByYXRpbyBzdGF0aXN0aWM6IA0KDQokJA0KXExhbWJkYV4qKFx0aGV0YSkgPSAyW1xlbGwoXGhhdHtcdGhldGF9XiopIC0gXGVsbChcdGhldGEpXQ0KJCQNCg0KKipTdGVwIDMqKjogVGhlIHBlcmNlbnRpbGUgYm9vdHN0cmFwIGNvbmZpZGVuY2UgaW50ZXJ2YWwgaXM6IA0KDQokJA0KXHtcdGhldGEgOiBcTGFtYmRhXiooXHRoZXRhKSBcbGVxIFxjaGleMl97MS1cYWxwaGF9KDEpXH0NCiQkDQoNCg0KDQojIyBCb290c3RyYXAgQ2FsaWJyYXRlZCBMaWtlbGlob29kIFJhdGlvIEludGVydmFscw0KDQpUaGVzZSBpbnRlcnZhbHMgaW1wcm92ZSB1cG9uIHN0YW5kYXJkIExpa2VsaWhvb2QgUmF0aW8gKExSKSBpbnRlcnZhbHMgYnkgY29ycmVjdGluZyB0aGVpciBjb3ZlcmFnZSBwcm9wZXJ0aWVzIHRocm91Z2ggY2FsaWJyYXRpb24sIGVuc3VyaW5nIHRoZSBub21pbmFsIGNvbmZpZGVuY2UgbGV2ZWwgKGUuZy4sIDk1JSkgaXMgY2xvc2VyIHRvIHRoZSB0cnVlIGNvdmVyYWdlIHByb2JhYmlsaXR5Lg0KDQoNCkZvciBhIHBhcmFtZXRlciAkXHRoZXRhJCwgdGhlIHN0YW5kYXJkIExSIHN0YXRpc3RpYyBpczoNCg0KJCQNClcoXHRoZXRhKSA9IDJcYmlnbFtcZWxsKFxoYXR7XHRoZXRhfSkgLSBcZWxsKFx0aGV0YSlcYmlncl0NCiQkDQoNCndoZXJlICRcaGF0e1x0aGV0YX0kIGlzIHRoZSBNTEUuDQoNCkFzeW1wdG90aWNhbGx5OiAkVyhcdGhldGEpIFxzaW0gXGNoaV8xXjIkIHVuZGVyICRIXzA6IFx0aGV0YSA9IFx0aGV0YV8wJC4NCg0KVGhlIHN0YW5kYXJkICQoMS1cYWxwaGEpJCBMUiBpbnRlcnZhbCBpczoNCg0KJCQNClxiaWdsXHtcdGhldGEgOiBXKFx0aGV0YSkgXGxlcSBcY2hpX3sxLDEtXGFscGhhfV4yIFxiaWdyXH0NCiQkDQoNClRoZSBwcm9ibGVtIGlzIHRoYXQgdGhpcyAkXGNoaV4yJCBhcHByb3hpbWF0aW9uIG1heSBiZSBwb29yIHdpdGggc21hbGwgc2FtcGxlcyBhbmQgaGlnaCBkaW1lbnNpb25hbCBpbmZlcmVuY2VzLg0KDQpcDQoNCjxmb250IGNvbG9yID0gImJsdWUiPioqQWxnb3JpdGhtKio8L2ZvbnQ+DQoNCioqU3RlcCAxKio6IENvbXB1dGUgb2JzZXJ2ZWQgTFIgc3RhdGlzdGljICRXX3tcdGV4dHtvYnN9fShcdGhldGEpJCBmb3IgZWFjaCAkXHRoZXRhJA0KICAgIA0KKipTdGVwIDIqKjogQm9vdHN0cmFwIHJlc2FtcGxpbmc6DQoNCiAgKyBGaXQgbW9kZWwsIGdldCAkXGhhdHtcdGhldGF9JA0KICArIEdlbmVyYXRlIGRhdGFzZXRzIGZyb20gJEZfe1xoYXR7XHRoZXRhfX0kDQogICsgUmVjb21wdXRlICRXXnsqfSQgZm9yIGVhY2gNCg0KICAgIA0KICoqU3RlcCAzKio6IEVzdGltYXRlIGNvdmVyYWdlIGZ1bmN0aW9uOg0KJCQNClxwaShjKSA9IFBeeyp9KFdeeyp9IFxsZXEgYykNCiQkDQogDQoqKlN0ZXAgNCoqOiBGaW5kIGNhbGlicmF0ZWQgdGhyZXNob2xkICRjX3tcYWxwaGF9JCB3aGVyZSANCg0KJCQNClxwaShjX3tcYWxwaGF9KSA9IDEgLSBcYWxwaGENCiQkDQogICAgDQoqKlN0ZXAgNSoqOiBJbnZlcnQgdGVzdDogSW5jbHVkZSAkXHRoZXRhJCBpZiANCg0KJCQNCiBXX3tcdGV4dHtvYnN9fShcdGhldGEpIFxsZXEgY197XGFscGhhfQ0KJCQNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg==