Data and Setup

data = rbind.data.frame(0.85, 1.23, 0.92, 3.45, 2.11, 1.56, 4.89, 2.34, 1.78, 6.72, 0.95, 1.34, 8.91, 
2.67, 1.89, 5.43, 1.12, 3.78, 2.45, 7.65, 1.05, 1.45, 12.34, 2.89, 2.01, 4.56, 
1.23, 4.32, 2.67, 9.87, 0.99, 1.56, 15.23, 3.12, 2.34, 3.89, 1.34, 5.67, 2.89, 
11.45, 1.12, 1.67, 18.90, 3.45, 2.56, 3.45, 1.45, 6.78, 3.12, 14.56, 1.23, 1.78, 
22.34, 3.78, 2.78)
colnames(data) = "soil"

For this analysis, we will be examining a dataset of 55 urban garden sites’ soil lead concentrations. These concentrations of soil lead (chemical prefix “Pb”) are measured in mg/kg. Moving forward in this analysis, we will assume the data, and broader population of lead concentrations in urban sites follow a log-normal distribution. This assumption is predicated on the fact that samples such as what we are working with are typically notably right skewed and by nature must be non-negative.

Summary statistics and a histogram of the dataset at hand are below.

sum_stats_table = function(variable){
  table = cbind(
    round(min(variable),2),
    round(quantile(variable, 0.25),2),
    round(median(variable),2),
    round(mean(variable),2),
    round(quantile(variable, 0.75),2),
    round(max(variable),2)
  )
  colnames(table) = c("Min", "Q1", "Med", "Mean", "Q3", "Max")
  rownames(table) = NULL
  return(table)
}

Summary_Table = sum_stats_table(variable = data$soil)
kable(Summary_Table,align = "c",
      caption = "<span style='color:##000000;'>
      Summary Stats of Soil Times </span>") %>%
  kable_styling(
    bootstrap_options = c("striped", "bordered"),
    full_width = FALSE,
    position = "center")
Summary Stats of Soil Times
Min Q1 Med Mean Q3 Max
0.85 1.5 2.67 4.4 4.72 22.34
hist(data$soil, 
     main = "Distribution of Concentrations",
     xlab = "Concentrations (mg/kg)",
     prob = TRUE,
     col = "lightblue"
)
box(lwd=3)

Using our available sample data, and our presumption of log-normality, the following sections will consist of attempts to estimate the average lead concentrations (mg/kg) across the broad population of urban sites similar to those that were observed for our sample. For mathematical notation purposes, this mean lead concentration will be denoted as E[X]. I will perform both point estimation and interval estimation.

To find an initial point estimate for E[X], I utilized the MLE estimation formulas for the log normal distribution as well as standard algebraic substitution. The relevant formulas are visible below.

knitr::include_graphics("/Users/chrisbahm/Library/Mobile Documents/com~apple~CloudDocs/West Chester/Spring 2026/STA 506 - Grad Math Stat 2 /STA 506 R Folder/Week 9 - Bootstrap Confidence Intervals/MLE.png")

knitr::include_graphics("/Users/chrisbahm/Library/Mobile Documents/com~apple~CloudDocs/West Chester/Spring 2026/STA 506 - Grad Math Stat 2 /STA 506 R Folder/Week 9 - Bootstrap Confidence Intervals/EX.png")

sample_mean = mean(data$soil)

  # based on GIVEN formula in assignment instructions for MLE estimator of mu
mu_hat = sum(log(data$soil))/nrow(data)

 # based on GIVEN formula in assignment instructions for MLE estimator of theta squared
theta_squared_hat = sum((log(data$soil) - mu_hat)^2)/nrow(data)

Ex_hat = exp(mu_hat + (theta_squared_hat/2))

# E[x] = lognormal population mean

Per this mathematical setup, our starting estimate of population average lead concentration is approximately 4.218.

a.) Bootstrap Sampling Distribution

Next, I used bootstrapping to acquire a broader sampling distribution of the average lead concentration point estimate. After performing 5,000 iterations of bootstrap sampling, and calculating E[X] for each sample, the sampling distribution of population mean estimates is visible below.

library(boot)
set.seed(100) # setting seed now for entire program

bootstrap_Ex = function(data, b) {
  n = length(data)
  bootstrap_ex_estimates = numeric(b)
  
    # START FOR LOOP
   for (i in 1:b){
     boot_sample = sample(data, size = n, replace= TRUE)
     mu_hat[i] = sum(log(boot_sample))/n
        # make sure to use boot_sample in this line, previously I was using data inside the log function and my output was the same value for every element of the vector
     
     theta_squared_hat[i] = sum((log(boot_sample) - mu_hat[i])^2)/n
     
     bootstrap_ex_estimates[i] = exp(mu_hat[i] +
                                       (theta_squared_hat[i]/2))
   }
    # END FOR LOOP
  
  return(bootstrap_ex_estimates) # final output
}

  # always remember to set the seed for consistent repetition
Ex_sampling_distribution = bootstrap_Ex(data = data$soil, b = 5000)

hist(Ex_sampling_distribution, 
     main = "Sampling Distribution of Population Mean Estimates",
     xlab = "Concentrations (mg/kg)",
     prob = TRUE,
     col = "lightblue"
)

box(lwd=3)

As we can see from our histogram, the sampling distribution of E[X] estimates is roughly log-normal distributed, with a rightward skew. The mean of our sampling distribution is roughly 4.248, which is extraordinarily close to the population mean estimate acquired strictly from our available sample data of 4.218.

b.) Bootstrap Percentile CI

After finding a sample distribution, I once again employ bootstrapping, this time to construct a percentile confidence interval for E[X]. Percentile intervals are a solid foundation for parameter estimation. They are the least mathematically complex of all confidence intervals, relying on the left and right quantile cutoffs of our distribution, as per the chosen level of \(\alpha\). Since the confidence level for this interval will be 95%, \(\alpha\) = 0.05 in this instance.

custom_ci_percentile = function(data, b, alpha){
  n = length(data)
  bootstrap_ex_estimates = numeric(b)
  mu_hat = numeric(b)
  theta_squared_hat = numeric(b)
  
  # for this function can use the same bootstrapping procedure from above to obtain the bootstrap_ex estimates vector
    # START FOR LOOP
    for(i in 1:b){
     boot_sample = sample(data, size = n, replace= TRUE)
     mu_hat[i] = sum(log(boot_sample))/n
     theta_squared_hat[i] = sum((log(boot_sample) - mu_hat[i])^2)/n
     bootstrap_ex_estimates[i] = exp(mu_hat[i] +
                                       (theta_squared_hat[i]/2))
    } # END FOR LOOP
  
  
  sort_bootstrap_ex_estimates = sort(bootstrap_ex_estimates)
  lower_quant = (alpha/2)
  higher_quant = (1-(alpha/2))
  lower_estimate = quantile(sort_bootstrap_ex_estimates, lower_quant)
  higher_estimate = quantile(sort_bootstrap_ex_estimates, higher_quant)
  results = rbind(lower_estimate,
                  higher_estimate)
  colnames(results) = "Custom Percent"
  rownames(results) = c("Lower Estimate", "Higher Estimate")
 
  return (results)
}

ci_percent_custom = custom_ci_percentile(data$soil, b = 5000, alpha = 0.05)

#ci_percent_custom
### built-in R function

######
# reference section 3.2.3 of notes

## create stat function that finds E[X] from a singular bootstrap sample of our data

find_ex = function(data, indices){
  n = length(data)
  sample_data = data[indices]
  
  mu_hat = sum(log(sample_data))/n
  theta_squared_hat = sum((log(data) - mu_hat)^2)/n
  
  ex_estimate = exp(mu_hat + 
                      (theta_squared_hat/2))
}
  # now that this function is made, plug it into the boot function

boot_result = boot(data$soil, find_ex, R = 5000)

ci_percent_r_stats = boot.ci(boot_result, type = "perc")
  # Note: boot.ci function defaults to 95% confidence level, can change this using the conf = argument

#ci_percent_r_stats

#ci_percent_r_stats$percent

#ci_percent_r_stats$percent[4] # = lower interval end
#ci_percent_r_stats$percent[5] # = higher interval end

ci_percent_r = rbind(ci_percent_r_stats$percent[4],
                     ci_percent_r_stats$percent[5])

rownames(ci_percent_r) = c("Lower Estimate", "Higher Estimate")
colnames(ci_percent_r) = "Percentile"

#ci_percent_r

To construct the percentile confidence interval for the mean soil concentration amongst the broader population of urban sites, I resorted to both custom function creation as well as R’s boot() function. Per these results, we can say with approximately 95% confidence that the population mean is either between 3.154 and 5.565 mg/kg or 3.456 and 5.413 mg/kg.

c.) Bootstrap BCa CI

After creating the percentile intervals, I then moved forward with bootstrap BCa (bias-corrected and accelerated) intervals. BCa intervals are a more sophisticated option to their standard percentile counterparts. They are especially valued when dealing with skewed distributions/data or biased estimators, something that the percentile option does not account for nearly as much.

### custom function
# reference section 3.3.2

# START FUNCTION
custom_ci_bca = function(data, b, alpha, original_estimate){ 
  n = length(data)
  bootstrap_ex_estimates = numeric(b)
  
# bias correction "measures median bias by comparing bootstrap estimates to the original estimate."
  
  prop_less = 0 # initialize counting variable at = 0
  
  for (i in 1:b){ # START BOOTSTRAP LOOP
     boot_sample = sample(data, size = n, replace= TRUE)
     mu_hat[i] = sum(log(boot_sample))/n
     theta_squared_hat[i] = sum((log(boot_sample) - mu_hat[i])^2)/n
     bootstrap_ex_estimates[i] = exp(mu_hat[i] +
                                       (theta_squared_hat[i]/2))
     
     # bias correction factor below
     ## can use normal if statement syntax, just incorporate the [i] to indicate that the statement is evaluating element by element
         if (bootstrap_ex_estimates[i] < original_estimate){
          prop_less = prop_less + 1
         }
     } # END BOOTSTRAP LOOP
     
      #### START CORRECTION CALCULATION  
        prop_less = prop_less/b
        z0 = qnorm(prop_less)
        # now have bias correction
      #### END BIAS CORRECTION CALCULATION
  
        
      #### START ACCELERATION CALCULATION
          # good practice to use different "counting variable than was earlier used in function, I'll use j instead of i
     jack_vals = numeric(n)
     
     for (j in 1:n){ # START JACK LOOP
       jack_sample = data[-j]
       
       mu_jack = sum(log(jack_sample)) / (n-1)
        # the jackknife estimate is computed by leaving OUT the ith observation
       theta_squared_jack = sum((log(jack_sample)-mu_jack)^2) / (n-1)
       jack_vals[j] = exp(mu_jack + (theta_squared_jack/2))
     } # END JACK LOOP
     
       theta_jack_mean = mean(jack_vals)
             # we want the difference between the total average and each jackknife estimate that left one out
       numerator = sum((theta_jack_mean - jack_vals)^3)
       denominator = sum((theta_jack_mean - jack_vals)^2)
       
       a_hat = numerator/ (6 * denominator^(3/2))
     #### END ACCELERATION CALCULATION
       
       
    ### FINAL OUTPUT/INTERVAL
       z_score1 = qnorm(alpha/2)
       z_score2 = qnorm(1-alpha/2)
       alpha1 = pnorm(z0 + (z0 + z_score1)/(1-a_hat*(z0 + z_score1)))
       alpha2 = pnorm(z0 + (z0 + z_score2)/(1-a_hat*(z0 + z_score2)))
       
       lower = quantile(bootstrap_ex_estimates, alpha1)
       upper = quantile(bootstrap_ex_estimates, alpha2)
       results = rbind(lower,upper)
       rownames(results) = c("Lower Estimate", "Higher Estimate")
       colnames(results) = "BCA"
       
       return(results)
            
} # END FUNCTION


#test
ci_bca_custom = custom_ci_bca(data = data$soil, b= 5000, alpha = 0.05, original_estimate = Ex_hat)

#ci_bca_custom
### built-in R function

# can use boot_result object from section b
# once again using boot.ci function, however argument changes to "bca"
ci_bca_r_stats = boot.ci(boot_result, type = "bca")

#ci_bca_r_stats
  # interval between 3.515 and 5.515

#ci_bca_r_stats$bca

#ci_bca_r_stats$bca[4] # = lower interval end
#ci_bca_r_stats$bca[5] # = higher interval end

ci_bca_r = rbind(ci_bca_r_stats$bca[4],
                     ci_bca_r_stats$bca[5])

rownames(ci_bca_r) = c("Lower Estimate", "Higher Estimate")
colnames(ci_bca_r) = "BCA"

#ci_bca_r

Once again utilizing two different coding methods, my BCa results were the following. With approximately 95% confidence, we can claim that the population mean of lead concentration in urban sites is somewhere between 3.244 and 5.85 mg/kg or 3.473 and 5.443 mg/kg.

d.) Asymptotic CI

Lastly, I attempted to estimate the population mean lead concentration, E[X], via an asymptotic or “normal” approach. Asymptotic sampling is of course predicated on the idea of the central limit theorem, meaning that an increase in sample size is correlated with an increase in normalization.

A fundamental difference in asymptotic and percentile interval estimation is that the critical value term for asymptotic intervals, which the standard error is multiplied by, is dependent on the qualities of the normal distribution. On the other hand, the critical value term for percentile intervals is dependent on the qualities of the bootstrap samples’ distribution. A downside of normal bootstrap intervals is the assumption of normally distributed data, which is not quite met to a large degree in this instance.

### custom function
  # reference section 3.1 from notes
  # can use bootstrap_Ex function from part a

custom_ci_asym = function(data, b, alpha) {
  n = length(data)
  bootstrap_ex_estimates = numeric(b)
  
  # call to previous function
  bootstrap_ex_estimates = bootstrap_Ex(data = data, b = b)
  
  # now estimate SE
  sum_part = sum((bootstrap_ex_estimates - 
                    mean(bootstrap_ex_estimates))^2)
  se = sqrt((1/(b-1))*sum_part)
  
  # now find and output interval
  crit_value = abs(qnorm(alpha/2))
  lower = mean(bootstrap_ex_estimates) - (crit_value*se)
  upper = mean(bootstrap_ex_estimates) + (crit_value*se)
  results = rbind(lower,upper)
  colnames(results) = "Custom Asym"
  rownames(results) = c("Lower Estimate", "Higher Estimate")
  
  return(results)
}

ci_asym_custom = custom_ci_asym(data = data$soil, b = 5000, alpha = 0.05)
### built-in R function

# once again use boot_result object and boot.ci function

ci_asym_r_stats = boot.ci(boot_result, type = "norm")
  # using argument "norm"; as sample size increases so does resemblance to normality as per CLT and asymptotic theory

#ci_asym_r_stats
  # about 3.162 to 5.148

#ci_asym_r_stats$normal[2] = lower interval
#ci_asym_r_stats$normal[3] = higher interval

ci_asym_r = rbind(ci_asym_r_stats$normal[2],
                  ci_asym_r_stats$normal[3])

rownames(ci_asym_r) = c("Lower Estimate", "Higher Estimate")
colnames(ci_asym_r) = "Asymptotic"

#ci_asym_r

Per the asymptotic method, we can say with roughly 95% certainty that the mean lead concentration amongst urban sites is either between 2.974 and 5.493 mg/kg or 3.184 and 5.135 mg/kg

e.) Interval Comparison

Below are two comparison tables displaying the results of each of the three interval methods that have been discussed. The top table compares results that were computed via R’s boot() function, while the latter table shows results calculated via my custom-built functions. The code for each custom function can be found underneath the respective sections.

## comparing the intervals created via R's boot function
r_intervals = cbind(round(ci_percent_r,3),
                    round(ci_bca_r,3),
                    round(ci_asym_r,3))
rownames(r_intervals) = c("Lower Estimate", "Higher Estimate")

kable(r_intervals,align = "c",
      caption = "<span style='color:##000000;'>
      Intervals via R's Boot Function </span>") %>%
  kable_styling(
    bootstrap_options = c("striped", "bordered"),
    full_width = FALSE,
    position = "center")
Intervals via R’s Boot Function
Percentile BCA Asymptotic
Lower Estimate 3.456 3.473 3.184
Higher Estimate 5.413 5.443 5.135
## comparing the intervals created via my custom functions
custom_intervals = cbind(round(ci_percent_custom,3),
                    round(ci_bca_custom,3),
                    round(ci_asym_custom,3))
rownames(custom_intervals) = c("Lower Estimate", "Higher Estimate")
colnames(custom_intervals) = c("Percentile", "BCA", "Asymptotic")

kable(custom_intervals,align = "c",
      caption = "<span style='color:##000000;'>
      Intervals via Custom-Built Function </span>") %>%
  kable_styling(
    bootstrap_options = c("striped", "bordered"),
    full_width = FALSE,
    position = "center")
Intervals via Custom-Built Function
Percentile BCA Asymptotic
Lower Estimate 3.154 3.244 2.974
Higher Estimate 5.565 5.850 5.493

Final Recommendation

Taking everything into consideration, I would suggest moving forward under the assumption that the BCa interval is the most accurate.

As I alluded to in a previous section, use of the the asymptotic interval generally assumes a relatively normal distribution of the population of interest. In this scenario, we have not assumed normality for the population of urban sites’ lead concentrations, but rather log-normality. Beyond that, the BCa interval method is the most robust in the face of skewness and bias. Its bias correction component utilizes the median statistic to counterbalance outliers, something that is certainly relevant to both our sample data and bootstrap distribution of E[X] estimates.

Below are the histograms for both the sample data, and population mean bootstrap estimates, this time with the 90th percentile of the dataset marked. This allows us to see how great of a rightward skew is applicable to this particular analysis.

hist(data$soil, 
     main = "Distribution of Concentrations",
     xlab = "Concentrations (mg/kg)",
     prob = TRUE,
     col = "lightblue"
)

 # Data point 90th percentile
    segments(
      x0 = quantile(data$soil,0.9),
      y0 = 0,
      x1 = quantile(data$soil,0.9),
      y1 = 1,
      col = "black",
      lwd = 4,
      lty = 3
    )

legend("topright",
       legend = "90th Percentile",
       col = "black",
       lwd = 4,
       lty = 3,
       box.lwd=3)

box(lwd=3)

hist(Ex_sampling_distribution, 
     main = "Sampling Distribution of Population Mean Estimates",
     xlab = "Concentrations (mg/kg)",
     prob = TRUE,
     col = "lightblue"
)

 # Data point 90th percentile
    segments(
      x0 = quantile(Ex_sampling_distribution,0.9),
      y0 = 0,
      x1 = quantile(Ex_sampling_distribution,0.9),
      y1 = 1,
      col = "black",
      lwd = 4,
      lty = 3
    )

legend("topright",
       legend = "90th Percentile",
       col = "black",
       lwd = 4,
       lty = 3,
       box.lwd=3)    
  
box(lwd=3)

LS0tCnRpdGxlOiAiQm9vdHN0cmFwIENvbmZpZGVuY2UgSW50ZXJ2YWxzIgphdXRob3I6ICJDaHJpcyBCYWhtIgpkYXRlOiAiTWFyY2ggMjksIDIwMjYiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6CiAgICAgIGNvbGxhcHNlZDogdHJ1ZQogICAgICBzbW9vdGhfc2Nyb2xsOiB0cnVlCiAgICB0b2NfZGVwdGg6IDQKICAgIGZpZ193aWR0aDogNgogICAgZmlnX2hlaWdodDogNAogICAgZmlnX2NhcHRpb246IHRydWUKICAgIG51bWJlcl9zZWN0aW9uczogZmFsc2UKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgdGhlbWU6IGx1bWVuCiAgICBoaWdobGlnaHQ6IHRhbmdvCiAgcGRmX2RvY3VtZW50OgogICAgdG9jOiB0cnVlCiAgICB0b2NfZGVwdGg6IDQKICAgIGZpZ19jYXB0aW9uOiB0cnVlCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICB3b3JkX2RvY3VtZW50OgogICAgdG9jOiB0cnVlCiAgICB0b2NfZGVwdGg6IDQKLS0tCgpgYGB7Y3NzLCBlY2hvID0gRkFMU0V9CmRpdiNUT0MgbGkgeyAgICAgLyogdGFibGUgb2YgY29udGVudCAgKi8KICAgIGxpc3Qtc3R5bGU6dXBwZXItcm9tYW47CiAgICBiYWNrZ3JvdW5kLWltYWdlOm5vbmU7CiAgICBiYWNrZ3JvdW5kLXJlcGVhdDpub25lOwogICAgYmFja2dyb3VuZC1wb3NpdGlvbjowOwp9CgpoMS50aXRsZSB7ICAgIC8qIGxldmVsIDEgaGVhZGVyIG9mIHRpdGxlICAqLwogIGZvbnQtc2l6ZTogMjRweDsKICBmb250LXdlaWdodDogYm9sZDsKICBjb2xvcjogRGFya1JlZDsKICB0ZXh0LWFsaWduOiBjZW50ZXI7Cn0KCmg0LmF1dGhvciB7IC8qIEhlYWRlciA0IC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovCiAgZm9udC1zaXplOiAxOHB4OwogIGZvbnQtd2VpZ2h0OiBib2xkOwogIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOwogIGNvbG9yOiBEYXJrUmVkOwogIHRleHQtYWxpZ246IGNlbnRlcjsKfQoKaDQuZGF0ZSB7IC8qIEhlYWRlciA0IC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovCiAgZm9udC1zaXplOiAxOHB4OwogIGZvbnQtd2VpZ2h0OiBib2xkOwogIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOwogIGNvbG9yOiBEYXJrQmx1ZTsKICB0ZXh0LWFsaWduOiBjZW50ZXI7Cn0KCmgxIHsgLyogSGVhZGVyIDEgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8KICAgIGZvbnQtc2l6ZTogMjBweDsKICAgIGZvbnQtd2VpZ2h0OiBib2xkOwogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7CiAgICBjb2xvcjogZGFya3JlZDsKICAgIHRleHQtYWxpZ246IGNlbnRlcjsKfQoKaDIgeyAvKiBIZWFkZXIgMiAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLwogICAgZm9udC1zaXplOiAxOHB4OwogICAgZm9udC13ZWlnaHQ6IGJvbGQ7CiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsKICAgIGNvbG9yOiBuYXZ5OwogICAgdGV4dC1hbGlnbjogbGVmdDsKfQoKaDMgeyAvKiBIZWFkZXIgMyAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLwogICAgZm9udC1zaXplOiAxNnB4OwogICAgZm9udC13ZWlnaHQ6IGJvbGQ7CiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsKICAgIGNvbG9yOiBuYXZ5OwogICAgdGV4dC1hbGlnbjogbGVmdDsKfQoKaDQgeyAvKiBIZWFkZXIgNCAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLwogICAgZm9udC1zaXplOiAxNHB4OwogIGZvbnQtd2VpZ2h0OiBib2xkOwogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7CiAgICBjb2xvcjogZGFya3JlZDsKICAgIHRleHQtYWxpZ246IGxlZnQ7Cn0KCi8qIEFkZCBkb3RzIGFmdGVyIG51bWJlcmVkIGhlYWRlcnMgKi8KLmhlYWRlci1zZWN0aW9uLW51bWJlcjo6YWZ0ZXIgewogIGNvbnRlbnQ6ICIuIjsKfQpgYGAKCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQojIGNvZGUgY2h1bmsgc3BlY2lmaWVzIHdoZXRoZXIgdGhlIFIgY29kZSwgd2FybmluZ3MsIGFuZCBvdXRwdXQgCiMgd2lsbCBiZSBpbmNsdWRlZCBpbiB0aGUgb3V0cHV0IGZpbGVzLgoKaWYgKCFyZXF1aXJlKCJrbml0ciIpKSB7ICAgICAgICAgICAgICAgICAgICAgICMgdXNlIGNvbmRpdGlvbmFsIHN0YXRlbWVudCB0byBkZXRlY3QKICAgaW5zdGFsbC5wYWNrYWdlcygia25pdHIiKSAgICAgICAgICAgICAgICAgICMgd2hldGhlciBhIHBhY2thZ2Ugd2FzIGluc3RhbGxlZCBpbgogICBsaWJyYXJ5KGtuaXRyKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyB5b3VyIG1hY2hpbmUuIElmIG5vdCwgaW5zdGFsbCBpdCBhbmQKfSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgbG9hZCBpdCB0byB0aGUgd29ya2luZyBkaXJlY3RvcnkuCgppZiAoIXJlcXVpcmUodGlkeXZlcnNlKSkge2xpYnJhcnkodGlkeXZzZXJzZSl9IAoKaWYgKCFyZXF1aXJlKEdHYWxseSkpIHtsaWJyYXJ5KEdHYWxseSl9IAoKaWYgKCFyZXF1aXJlKGthYmxlRXh0cmEpKSB7bGlicmFyeShrYWJsZUV4dHJhKX0gCgppZiAoIXJlcXVpcmUoZ2dwbG90MikpIHtsaWJyYXJ5KGdncGxvdDIpfSAKCmlmICghcmVxdWlyZShjYXIpKSB7bGlicmFyeShjYXIpfSAKCmlmICghcmVxdWlyZShkcGx5cikpIHtsaWJyYXJ5KGRwbHlyKX0gCgppZiAoIXJlcXVpcmUocGFuZGVyKSkge2xpYnJhcnkocGFuZGVyKX0gCgppZiAoIXJlcXVpcmUoZm9yZWNhc3QpKSB7bGlicmFyeShmb3JlY2FzdCl9IAoKaWYgKCFyZXF1aXJlKGx1YnJpZGF0ZSkpIHtsaWJyYXJ5KGx1YnJpZGF0ZSl9IAoKaWYgKCFyZXF1aXJlKCJzY2FsZXMiKSkgewppbnN0YWxsLnBhY2thZ2VzKCJzY2FsZXMiKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKbGlicmFyeSgic2NhbGVzIikgCn0KCmtuaXRyOjpvcHRzX2NodW5rJHNldCgKCWVjaG8gPSBUUlVFLAoJbWVzc2FnZSA9IEZBTFNFLAoJd2FybmluZyA9IEZBTFNFLAoJY29tbWVudCA9IE5BLAoJcmVzdWx0cyA9IFRSVUUsCglmaWcuYWxpZ24gPSAiY2VudGVyIgopCmBgYAoKCiMgRGF0YSBhbmQgU2V0dXAKCmBgYHtyfQpkYXRhID0gcmJpbmQuZGF0YS5mcmFtZSgwLjg1LCAxLjIzLCAwLjkyLCAzLjQ1LCAyLjExLCAxLjU2LCA0Ljg5LCAyLjM0LCAxLjc4LCA2LjcyLCAwLjk1LCAxLjM0LCA4LjkxLCAKMi42NywgMS44OSwgNS40MywgMS4xMiwgMy43OCwgMi40NSwgNy42NSwgMS4wNSwgMS40NSwgMTIuMzQsIDIuODksIDIuMDEsIDQuNTYsIAoxLjIzLCA0LjMyLCAyLjY3LCA5Ljg3LCAwLjk5LCAxLjU2LCAxNS4yMywgMy4xMiwgMi4zNCwgMy44OSwgMS4zNCwgNS42NywgMi44OSwgCjExLjQ1LCAxLjEyLCAxLjY3LCAxOC45MCwgMy40NSwgMi41NiwgMy40NSwgMS40NSwgNi43OCwgMy4xMiwgMTQuNTYsIDEuMjMsIDEuNzgsIAoyMi4zNCwgMy43OCwgMi43OCkKY29sbmFtZXMoZGF0YSkgPSAic29pbCIKYGBgCkZvciB0aGlzIGFuYWx5c2lzLCB3ZSB3aWxsIGJlIGV4YW1pbmluZyBhIGRhdGFzZXQgb2YgYHIgbnJvdyhkYXRhKWAgdXJiYW4gZ2FyZGVuIHNpdGVzJyBzb2lsIGxlYWQgY29uY2VudHJhdGlvbnMuIFRoZXNlIGNvbmNlbnRyYXRpb25zIG9mIHNvaWwgbGVhZCAoY2hlbWljYWwgcHJlZml4ICJQYiIpIGFyZSBtZWFzdXJlZCBpbiBtZy9rZy4gTW92aW5nIGZvcndhcmQgaW4gdGhpcyBhbmFseXNpcywgd2Ugd2lsbCBhc3N1bWUgdGhlIGRhdGEsIGFuZCBicm9hZGVyIHBvcHVsYXRpb24gb2YgbGVhZCBjb25jZW50cmF0aW9ucyBpbiB1cmJhbiBzaXRlcyBmb2xsb3cgYSAqKmxvZy1ub3JtYWwgZGlzdHJpYnV0aW9uKiouIFRoaXMgYXNzdW1wdGlvbiBpcyBwcmVkaWNhdGVkIG9uIHRoZSBmYWN0IHRoYXQgc2FtcGxlcyBzdWNoIGFzIHdoYXQgd2UgYXJlIHdvcmtpbmcgd2l0aCBhcmUgdHlwaWNhbGx5IG5vdGFibHkgcmlnaHQgc2tld2VkIGFuZCBieSBuYXR1cmUgbXVzdCBiZSBub24tbmVnYXRpdmUuCgpTdW1tYXJ5IHN0YXRpc3RpY3MgYW5kIGEgaGlzdG9ncmFtIG9mIHRoZSBkYXRhc2V0IGF0IGhhbmQgYXJlIGJlbG93LgoKYGBge3IsIGZpZy5oZWlnaHQ9NS41LCBmaWcud2lkdGg9Ni41fQpzdW1fc3RhdHNfdGFibGUgPSBmdW5jdGlvbih2YXJpYWJsZSl7CiAgdGFibGUgPSBjYmluZCgKICAgIHJvdW5kKG1pbih2YXJpYWJsZSksMiksCiAgICByb3VuZChxdWFudGlsZSh2YXJpYWJsZSwgMC4yNSksMiksCiAgICByb3VuZChtZWRpYW4odmFyaWFibGUpLDIpLAogICAgcm91bmQobWVhbih2YXJpYWJsZSksMiksCiAgICByb3VuZChxdWFudGlsZSh2YXJpYWJsZSwgMC43NSksMiksCiAgICByb3VuZChtYXgodmFyaWFibGUpLDIpCiAgKQogIGNvbG5hbWVzKHRhYmxlKSA9IGMoIk1pbiIsICJRMSIsICJNZWQiLCAiTWVhbiIsICJRMyIsICJNYXgiKQogIHJvd25hbWVzKHRhYmxlKSA9IE5VTEwKICByZXR1cm4odGFibGUpCn0KClN1bW1hcnlfVGFibGUgPSBzdW1fc3RhdHNfdGFibGUodmFyaWFibGUgPSBkYXRhJHNvaWwpCmthYmxlKFN1bW1hcnlfVGFibGUsYWxpZ24gPSAiYyIsCiAgICAgIGNhcHRpb24gPSAiPHNwYW4gc3R5bGU9J2NvbG9yOiMjMDAwMDAwOyc+CiAgICAgIFN1bW1hcnkgU3RhdHMgb2YgU29pbCBUaW1lcyA8L3NwYW4+IikgJT4lCiAga2FibGVfc3R5bGluZygKICAgIGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJib3JkZXJlZCIpLAogICAgZnVsbF93aWR0aCA9IEZBTFNFLAogICAgcG9zaXRpb24gPSAiY2VudGVyIikKCgpoaXN0KGRhdGEkc29pbCwgCiAgICAgbWFpbiA9ICJEaXN0cmlidXRpb24gb2YgQ29uY2VudHJhdGlvbnMiLAogICAgIHhsYWIgPSAiQ29uY2VudHJhdGlvbnMgKG1nL2tnKSIsCiAgICAgcHJvYiA9IFRSVUUsCiAgICAgY29sID0gImxpZ2h0Ymx1ZSIKKQpib3gobHdkPTMpCgpgYGAKClVzaW5nIG91ciBhdmFpbGFibGUgc2FtcGxlIGRhdGEsIGFuZCBvdXIgcHJlc3VtcHRpb24gb2YgbG9nLW5vcm1hbGl0eSwgdGhlIGZvbGxvd2luZyBzZWN0aW9ucyB3aWxsIGNvbnNpc3Qgb2YgYXR0ZW1wdHMgdG8gZXN0aW1hdGUgdGhlICoqYXZlcmFnZSBsZWFkIGNvbmNlbnRyYXRpb25zKiogKG1nL2tnKSBhY3Jvc3MgdGhlICoqYnJvYWQgcG9wdWxhdGlvbioqIG9mIHVyYmFuIHNpdGVzIHNpbWlsYXIgdG8gdGhvc2UgdGhhdCB3ZXJlIG9ic2VydmVkIGZvciBvdXIgc2FtcGxlLiBGb3IgbWF0aGVtYXRpY2FsIG5vdGF0aW9uIHB1cnBvc2VzLCB0aGlzIG1lYW4gbGVhZCBjb25jZW50cmF0aW9uIHdpbGwgYmUgZGVub3RlZCBhcyAqKkVbWF0qKi4gSSB3aWxsIHBlcmZvcm0gYm90aCBwb2ludCBlc3RpbWF0aW9uIGFuZCBpbnRlcnZhbCBlc3RpbWF0aW9uLgoKVG8gZmluZCBhbiBpbml0aWFsIHBvaW50IGVzdGltYXRlIGZvciBFW1hdLCBJIHV0aWxpemVkIHRoZSBNTEUgZXN0aW1hdGlvbiBmb3JtdWxhcyBmb3IgdGhlIGxvZyBub3JtYWwgZGlzdHJpYnV0aW9uIGFzIHdlbGwgYXMgc3RhbmRhcmQgYWxnZWJyYWljIHN1YnN0aXR1dGlvbi4gVGhlIHJlbGV2YW50IGZvcm11bGFzIGFyZSB2aXNpYmxlIGJlbG93LgoKYGBge3J9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCIvVXNlcnMvY2hyaXNiYWhtL0xpYnJhcnkvTW9iaWxlIERvY3VtZW50cy9jb21+YXBwbGV+Q2xvdWREb2NzL1dlc3QgQ2hlc3Rlci9TcHJpbmcgMjAyNi9TVEEgNTA2IC0gR3JhZCBNYXRoIFN0YXQgMiAvU1RBIDUwNiBSIEZvbGRlci9XZWVrIDkgLSBCb290c3RyYXAgQ29uZmlkZW5jZSBJbnRlcnZhbHMvTUxFLnBuZyIpCgprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiL1VzZXJzL2NocmlzYmFobS9MaWJyYXJ5L01vYmlsZSBEb2N1bWVudHMvY29tfmFwcGxlfkNsb3VkRG9jcy9XZXN0IENoZXN0ZXIvU3ByaW5nIDIwMjYvU1RBIDUwNiAtIEdyYWQgTWF0aCBTdGF0IDIgL1NUQSA1MDYgUiBGb2xkZXIvV2VlayA5IC0gQm9vdHN0cmFwIENvbmZpZGVuY2UgSW50ZXJ2YWxzL0VYLnBuZyIpCmBgYAoKCmBgYHtyfQpzYW1wbGVfbWVhbiA9IG1lYW4oZGF0YSRzb2lsKQoKICAjIGJhc2VkIG9uIEdJVkVOIGZvcm11bGEgaW4gYXNzaWdubWVudCBpbnN0cnVjdGlvbnMgZm9yIE1MRSBlc3RpbWF0b3Igb2YgbXUKbXVfaGF0ID0gc3VtKGxvZyhkYXRhJHNvaWwpKS9ucm93KGRhdGEpCgogIyBiYXNlZCBvbiBHSVZFTiBmb3JtdWxhIGluIGFzc2lnbm1lbnQgaW5zdHJ1Y3Rpb25zIGZvciBNTEUgZXN0aW1hdG9yIG9mIHRoZXRhIHNxdWFyZWQKdGhldGFfc3F1YXJlZF9oYXQgPSBzdW0oKGxvZyhkYXRhJHNvaWwpIC0gbXVfaGF0KV4yKS9ucm93KGRhdGEpCgpFeF9oYXQgPSBleHAobXVfaGF0ICsgKHRoZXRhX3NxdWFyZWRfaGF0LzIpKQoKIyBFW3hdID0gbG9nbm9ybWFsIHBvcHVsYXRpb24gbWVhbgpgYGAKClBlciB0aGlzIG1hdGhlbWF0aWNhbCBzZXR1cCwgb3VyIHN0YXJ0aW5nIGVzdGltYXRlIG9mIHBvcHVsYXRpb24gYXZlcmFnZSBsZWFkIGNvbmNlbnRyYXRpb24gaXMgYXBwcm94aW1hdGVseSBgciByb3VuZChFeF9oYXQsMylgLiAKCgojIGEuKSBCb290c3RyYXAgU2FtcGxpbmcgRGlzdHJpYnV0aW9uCk5leHQsIEkgdXNlZCBib290c3RyYXBwaW5nIHRvIGFjcXVpcmUgYSBicm9hZGVyIHNhbXBsaW5nIGRpc3RyaWJ1dGlvbiBvZiB0aGUgYXZlcmFnZSBsZWFkIGNvbmNlbnRyYXRpb24gcG9pbnQgZXN0aW1hdGUuIEFmdGVyIHBlcmZvcm1pbmcgNSwwMDAgaXRlcmF0aW9ucyBvZiBib290c3RyYXAgc2FtcGxpbmcsIGFuZCBjYWxjdWxhdGluZyBFW1hdIGZvciBlYWNoIHNhbXBsZSwgdGhlIHNhbXBsaW5nIGRpc3RyaWJ1dGlvbiBvZiBwb3B1bGF0aW9uIG1lYW4gZXN0aW1hdGVzIGlzIHZpc2libGUgYmVsb3cuCgpgYGB7ciwgZmlnLmhlaWdodD01LjUsIGZpZy53aWR0aD02LjV9CmxpYnJhcnkoYm9vdCkKc2V0LnNlZWQoMTAwKSAjIHNldHRpbmcgc2VlZCBub3cgZm9yIGVudGlyZSBwcm9ncmFtCgpib290c3RyYXBfRXggPSBmdW5jdGlvbihkYXRhLCBiKSB7CiAgbiA9IGxlbmd0aChkYXRhKQogIGJvb3RzdHJhcF9leF9lc3RpbWF0ZXMgPSBudW1lcmljKGIpCiAgCiAgICAjIFNUQVJUIEZPUiBMT09QCiAgIGZvciAoaSBpbiAxOmIpewogICAgIGJvb3Rfc2FtcGxlID0gc2FtcGxlKGRhdGEsIHNpemUgPSBuLCByZXBsYWNlPSBUUlVFKQogICAgIG11X2hhdFtpXSA9IHN1bShsb2coYm9vdF9zYW1wbGUpKS9uCiAgICAgICAgIyBtYWtlIHN1cmUgdG8gdXNlIGJvb3Rfc2FtcGxlIGluIHRoaXMgbGluZSwgcHJldmlvdXNseSBJIHdhcyB1c2luZyBkYXRhIGluc2lkZSB0aGUgbG9nIGZ1bmN0aW9uIGFuZCBteSBvdXRwdXQgd2FzIHRoZSBzYW1lIHZhbHVlIGZvciBldmVyeSBlbGVtZW50IG9mIHRoZSB2ZWN0b3IKICAgICAKICAgICB0aGV0YV9zcXVhcmVkX2hhdFtpXSA9IHN1bSgobG9nKGJvb3Rfc2FtcGxlKSAtIG11X2hhdFtpXSleMikvbgogICAgIAogICAgIGJvb3RzdHJhcF9leF9lc3RpbWF0ZXNbaV0gPSBleHAobXVfaGF0W2ldICsKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKHRoZXRhX3NxdWFyZWRfaGF0W2ldLzIpKQogICB9CiAgICAjIEVORCBGT1IgTE9PUAogIAogIHJldHVybihib290c3RyYXBfZXhfZXN0aW1hdGVzKSAjIGZpbmFsIG91dHB1dAp9CgogICMgYWx3YXlzIHJlbWVtYmVyIHRvIHNldCB0aGUgc2VlZCBmb3IgY29uc2lzdGVudCByZXBldGl0aW9uCkV4X3NhbXBsaW5nX2Rpc3RyaWJ1dGlvbiA9IGJvb3RzdHJhcF9FeChkYXRhID0gZGF0YSRzb2lsLCBiID0gNTAwMCkKCmhpc3QoRXhfc2FtcGxpbmdfZGlzdHJpYnV0aW9uLCAKICAgICBtYWluID0gIlNhbXBsaW5nIERpc3RyaWJ1dGlvbiBvZiBQb3B1bGF0aW9uIE1lYW4gRXN0aW1hdGVzIiwKICAgICB4bGFiID0gIkNvbmNlbnRyYXRpb25zIChtZy9rZykiLAogICAgIHByb2IgPSBUUlVFLAogICAgIGNvbCA9ICJsaWdodGJsdWUiCikKCmJveChsd2Q9MykKYGBgCgpBcyB3ZSBjYW4gc2VlIGZyb20gb3VyIGhpc3RvZ3JhbSwgdGhlIHNhbXBsaW5nIGRpc3RyaWJ1dGlvbiBvZiBFW1hdIGVzdGltYXRlcyBpcyByb3VnaGx5IGxvZy1ub3JtYWwgZGlzdHJpYnV0ZWQsIHdpdGggYSByaWdodHdhcmQgc2tldy4gVGhlIG1lYW4gb2Ygb3VyIHNhbXBsaW5nIGRpc3RyaWJ1dGlvbiBpcyByb3VnaGx5IGByIHJvdW5kKG1lYW4oRXhfc2FtcGxpbmdfZGlzdHJpYnV0aW9uKSwzKWAsIHdoaWNoIGlzIGV4dHJhb3JkaW5hcmlseSBjbG9zZSB0byB0aGUgcG9wdWxhdGlvbiBtZWFuIGVzdGltYXRlIGFjcXVpcmVkIHN0cmljdGx5IGZyb20gb3VyIGF2YWlsYWJsZSBzYW1wbGUgZGF0YSBvZiBgciByb3VuZChFeF9oYXQsMylgLgoKCiMgYi4pIEJvb3RzdHJhcCBQZXJjZW50aWxlIENJCkFmdGVyIGZpbmRpbmcgYSBzYW1wbGUgZGlzdHJpYnV0aW9uLCBJIG9uY2UgYWdhaW4gZW1wbG95IGJvb3RzdHJhcHBpbmcsIHRoaXMgdGltZSB0byBjb25zdHJ1Y3QgYSBwZXJjZW50aWxlIGNvbmZpZGVuY2UgaW50ZXJ2YWwgZm9yIEVbWF0uIFBlcmNlbnRpbGUgaW50ZXJ2YWxzIGFyZSBhIHNvbGlkIGZvdW5kYXRpb24gZm9yIHBhcmFtZXRlciBlc3RpbWF0aW9uLiBUaGV5IGFyZSB0aGUgbGVhc3QgbWF0aGVtYXRpY2FsbHkgY29tcGxleCBvZiBhbGwgY29uZmlkZW5jZSBpbnRlcnZhbHMsIHJlbHlpbmcgb24gdGhlIGxlZnQgYW5kIHJpZ2h0IHF1YW50aWxlIGN1dG9mZnMgb2Ygb3VyIGRpc3RyaWJ1dGlvbiwgYXMgcGVyIHRoZSBjaG9zZW4gbGV2ZWwgb2YgJFxhbHBoYSQuIFNpbmNlIHRoZSBjb25maWRlbmNlIGxldmVsIGZvciB0aGlzIGludGVydmFsIHdpbGwgYmUgOTUlLCAkXGFscGhhJCA9IDAuMDUgaW4gdGhpcyBpbnN0YW5jZS4KCmBgYHtyfQpjdXN0b21fY2lfcGVyY2VudGlsZSA9IGZ1bmN0aW9uKGRhdGEsIGIsIGFscGhhKXsKICBuID0gbGVuZ3RoKGRhdGEpCiAgYm9vdHN0cmFwX2V4X2VzdGltYXRlcyA9IG51bWVyaWMoYikKICBtdV9oYXQgPSBudW1lcmljKGIpCiAgdGhldGFfc3F1YXJlZF9oYXQgPSBudW1lcmljKGIpCiAgCiAgIyBmb3IgdGhpcyBmdW5jdGlvbiBjYW4gdXNlIHRoZSBzYW1lIGJvb3RzdHJhcHBpbmcgcHJvY2VkdXJlIGZyb20gYWJvdmUgdG8gb2J0YWluIHRoZSBib290c3RyYXBfZXggZXN0aW1hdGVzIHZlY3RvcgogICAgIyBTVEFSVCBGT1IgTE9PUAogICAgZm9yKGkgaW4gMTpiKXsKICAgICBib290X3NhbXBsZSA9IHNhbXBsZShkYXRhLCBzaXplID0gbiwgcmVwbGFjZT0gVFJVRSkKICAgICBtdV9oYXRbaV0gPSBzdW0obG9nKGJvb3Rfc2FtcGxlKSkvbgogICAgIHRoZXRhX3NxdWFyZWRfaGF0W2ldID0gc3VtKChsb2coYm9vdF9zYW1wbGUpIC0gbXVfaGF0W2ldKV4yKS9uCiAgICAgYm9vdHN0cmFwX2V4X2VzdGltYXRlc1tpXSA9IGV4cChtdV9oYXRbaV0gKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAodGhldGFfc3F1YXJlZF9oYXRbaV0vMikpCiAgICB9ICMgRU5EIEZPUiBMT09QCiAgCiAgCiAgc29ydF9ib290c3RyYXBfZXhfZXN0aW1hdGVzID0gc29ydChib290c3RyYXBfZXhfZXN0aW1hdGVzKQogIGxvd2VyX3F1YW50ID0gKGFscGhhLzIpCiAgaGlnaGVyX3F1YW50ID0gKDEtKGFscGhhLzIpKQogIGxvd2VyX2VzdGltYXRlID0gcXVhbnRpbGUoc29ydF9ib290c3RyYXBfZXhfZXN0aW1hdGVzLCBsb3dlcl9xdWFudCkKICBoaWdoZXJfZXN0aW1hdGUgPSBxdWFudGlsZShzb3J0X2Jvb3RzdHJhcF9leF9lc3RpbWF0ZXMsIGhpZ2hlcl9xdWFudCkKICByZXN1bHRzID0gcmJpbmQobG93ZXJfZXN0aW1hdGUsCiAgICAgICAgICAgICAgICAgIGhpZ2hlcl9lc3RpbWF0ZSkKICBjb2xuYW1lcyhyZXN1bHRzKSA9ICJDdXN0b20gUGVyY2VudCIKICByb3duYW1lcyhyZXN1bHRzKSA9IGMoIkxvd2VyIEVzdGltYXRlIiwgIkhpZ2hlciBFc3RpbWF0ZSIpCiAKICByZXR1cm4gKHJlc3VsdHMpCn0KCmNpX3BlcmNlbnRfY3VzdG9tID0gY3VzdG9tX2NpX3BlcmNlbnRpbGUoZGF0YSRzb2lsLCBiID0gNTAwMCwgYWxwaGEgPSAwLjA1KQoKI2NpX3BlcmNlbnRfY3VzdG9tCmBgYAoKYGBge3J9CiMjIyBidWlsdC1pbiBSIGZ1bmN0aW9uCgojIyMjIyMKIyByZWZlcmVuY2Ugc2VjdGlvbiAzLjIuMyBvZiBub3RlcwoKIyMgY3JlYXRlIHN0YXQgZnVuY3Rpb24gdGhhdCBmaW5kcyBFW1hdIGZyb20gYSBzaW5ndWxhciBib290c3RyYXAgc2FtcGxlIG9mIG91ciBkYXRhCgpmaW5kX2V4ID0gZnVuY3Rpb24oZGF0YSwgaW5kaWNlcyl7CiAgbiA9IGxlbmd0aChkYXRhKQogIHNhbXBsZV9kYXRhID0gZGF0YVtpbmRpY2VzXQogIAogIG11X2hhdCA9IHN1bShsb2coc2FtcGxlX2RhdGEpKS9uCiAgdGhldGFfc3F1YXJlZF9oYXQgPSBzdW0oKGxvZyhkYXRhKSAtIG11X2hhdCleMikvbgogIAogIGV4X2VzdGltYXRlID0gZXhwKG11X2hhdCArIAogICAgICAgICAgICAgICAgICAgICAgKHRoZXRhX3NxdWFyZWRfaGF0LzIpKQp9CiAgIyBub3cgdGhhdCB0aGlzIGZ1bmN0aW9uIGlzIG1hZGUsIHBsdWcgaXQgaW50byB0aGUgYm9vdCBmdW5jdGlvbgoKYm9vdF9yZXN1bHQgPSBib290KGRhdGEkc29pbCwgZmluZF9leCwgUiA9IDUwMDApCgpjaV9wZXJjZW50X3Jfc3RhdHMgPSBib290LmNpKGJvb3RfcmVzdWx0LCB0eXBlID0gInBlcmMiKQogICMgTm90ZTogYm9vdC5jaSBmdW5jdGlvbiBkZWZhdWx0cyB0byA5NSUgY29uZmlkZW5jZSBsZXZlbCwgY2FuIGNoYW5nZSB0aGlzIHVzaW5nIHRoZSBjb25mID0gYXJndW1lbnQKCiNjaV9wZXJjZW50X3Jfc3RhdHMKCiNjaV9wZXJjZW50X3Jfc3RhdHMkcGVyY2VudAoKI2NpX3BlcmNlbnRfcl9zdGF0cyRwZXJjZW50WzRdICMgPSBsb3dlciBpbnRlcnZhbCBlbmQKI2NpX3BlcmNlbnRfcl9zdGF0cyRwZXJjZW50WzVdICMgPSBoaWdoZXIgaW50ZXJ2YWwgZW5kCgpjaV9wZXJjZW50X3IgPSByYmluZChjaV9wZXJjZW50X3Jfc3RhdHMkcGVyY2VudFs0XSwKICAgICAgICAgICAgICAgICAgICAgY2lfcGVyY2VudF9yX3N0YXRzJHBlcmNlbnRbNV0pCgpyb3duYW1lcyhjaV9wZXJjZW50X3IpID0gYygiTG93ZXIgRXN0aW1hdGUiLCAiSGlnaGVyIEVzdGltYXRlIikKY29sbmFtZXMoY2lfcGVyY2VudF9yKSA9ICJQZXJjZW50aWxlIgoKI2NpX3BlcmNlbnRfcgpgYGAKClRvIGNvbnN0cnVjdCB0aGUgcGVyY2VudGlsZSBjb25maWRlbmNlIGludGVydmFsIGZvciB0aGUgbWVhbiBzb2lsIGNvbmNlbnRyYXRpb24gYW1vbmdzdCB0aGUgYnJvYWRlciBwb3B1bGF0aW9uIG9mIHVyYmFuIHNpdGVzLCBJIHJlc29ydGVkIHRvIGJvdGggY3VzdG9tIGZ1bmN0aW9uIGNyZWF0aW9uIGFzIHdlbGwgYXMgUidzIDxzcGFuIHN0eWxlPSJjb2xvcjpibHVlOyI+Ym9vdCgpPC9zcGFuPiBmdW5jdGlvbi4gUGVyIHRoZXNlIHJlc3VsdHMsIHdlIGNhbiBzYXkgd2l0aCBhcHByb3hpbWF0ZWx5IDk1JSBjb25maWRlbmNlIHRoYXQgdGhlIHBvcHVsYXRpb24gbWVhbiBpcyBlaXRoZXIgYmV0d2VlbiBgciByb3VuZChjaV9wZXJjZW50X2N1c3RvbVsxXSwzKWAgYW5kIGByIHJvdW5kKGNpX3BlcmNlbnRfY3VzdG9tWzJdLDMpYCBtZy9rZyAqb3IqIGByIHJvdW5kKGNpX3BlcmNlbnRfclsxXSwzKWAgYW5kIGByIHJvdW5kKGNpX3BlcmNlbnRfclsyXSwzKWAgbWcva2cuCgojIGMuKSBCb290c3RyYXAgQkNhIENJIApBZnRlciBjcmVhdGluZyB0aGUgcGVyY2VudGlsZSBpbnRlcnZhbHMsIEkgdGhlbiBtb3ZlZCBmb3J3YXJkIHdpdGggYm9vdHN0cmFwIEJDYSAoYmlhcy1jb3JyZWN0ZWQgYW5kIGFjY2VsZXJhdGVkKSBpbnRlcnZhbHMuIEJDYSBpbnRlcnZhbHMgYXJlIGEgbW9yZSBzb3BoaXN0aWNhdGVkIG9wdGlvbiB0byB0aGVpciBzdGFuZGFyZCBwZXJjZW50aWxlIGNvdW50ZXJwYXJ0cy4gVGhleSBhcmUgZXNwZWNpYWxseSB2YWx1ZWQgd2hlbiBkZWFsaW5nIHdpdGggc2tld2VkIGRpc3RyaWJ1dGlvbnMvZGF0YSBvciBiaWFzZWQgZXN0aW1hdG9ycywgc29tZXRoaW5nIHRoYXQgdGhlIHBlcmNlbnRpbGUgb3B0aW9uIGRvZXMgKm5vdCogYWNjb3VudCBmb3IgbmVhcmx5IGFzIG11Y2guCgpgYGB7cn0KIyMjIGN1c3RvbSBmdW5jdGlvbgojIHJlZmVyZW5jZSBzZWN0aW9uIDMuMy4yCgojIFNUQVJUIEZVTkNUSU9OCmN1c3RvbV9jaV9iY2EgPSBmdW5jdGlvbihkYXRhLCBiLCBhbHBoYSwgb3JpZ2luYWxfZXN0aW1hdGUpeyAKICBuID0gbGVuZ3RoKGRhdGEpCiAgYm9vdHN0cmFwX2V4X2VzdGltYXRlcyA9IG51bWVyaWMoYikKICAKIyBiaWFzIGNvcnJlY3Rpb24gIm1lYXN1cmVzIG1lZGlhbiBiaWFzIGJ5IGNvbXBhcmluZyBib290c3RyYXAgZXN0aW1hdGVzIHRvIHRoZSBvcmlnaW5hbCBlc3RpbWF0ZS4iCiAgCiAgcHJvcF9sZXNzID0gMCAjIGluaXRpYWxpemUgY291bnRpbmcgdmFyaWFibGUgYXQgPSAwCiAgCiAgZm9yIChpIGluIDE6Yil7ICMgU1RBUlQgQk9PVFNUUkFQIExPT1AKICAgICBib290X3NhbXBsZSA9IHNhbXBsZShkYXRhLCBzaXplID0gbiwgcmVwbGFjZT0gVFJVRSkKICAgICBtdV9oYXRbaV0gPSBzdW0obG9nKGJvb3Rfc2FtcGxlKSkvbgogICAgIHRoZXRhX3NxdWFyZWRfaGF0W2ldID0gc3VtKChsb2coYm9vdF9zYW1wbGUpIC0gbXVfaGF0W2ldKV4yKS9uCiAgICAgYm9vdHN0cmFwX2V4X2VzdGltYXRlc1tpXSA9IGV4cChtdV9oYXRbaV0gKwogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAodGhldGFfc3F1YXJlZF9oYXRbaV0vMikpCiAgICAgCiAgICAgIyBiaWFzIGNvcnJlY3Rpb24gZmFjdG9yIGJlbG93CiAgICAgIyMgY2FuIHVzZSBub3JtYWwgaWYgc3RhdGVtZW50IHN5bnRheCwganVzdCBpbmNvcnBvcmF0ZSB0aGUgW2ldIHRvIGluZGljYXRlIHRoYXQgdGhlIHN0YXRlbWVudCBpcyBldmFsdWF0aW5nIGVsZW1lbnQgYnkgZWxlbWVudAogICAgICAgICBpZiAoYm9vdHN0cmFwX2V4X2VzdGltYXRlc1tpXSA8IG9yaWdpbmFsX2VzdGltYXRlKXsKICAgICAgICAgIHByb3BfbGVzcyA9IHByb3BfbGVzcyArIDEKICAgICAgICAgfQogICAgIH0gIyBFTkQgQk9PVFNUUkFQIExPT1AKICAgICAKICAgICAgIyMjIyBTVEFSVCBDT1JSRUNUSU9OIENBTENVTEFUSU9OICAKICAgICAgICBwcm9wX2xlc3MgPSBwcm9wX2xlc3MvYgogICAgICAgIHowID0gcW5vcm0ocHJvcF9sZXNzKQogICAgICAgICMgbm93IGhhdmUgYmlhcyBjb3JyZWN0aW9uCiAgICAgICMjIyMgRU5EIEJJQVMgQ09SUkVDVElPTiBDQUxDVUxBVElPTgogIAogICAgICAgIAogICAgICAjIyMjIFNUQVJUIEFDQ0VMRVJBVElPTiBDQUxDVUxBVElPTgogICAgICAgICAgIyBnb29kIHByYWN0aWNlIHRvIHVzZSBkaWZmZXJlbnQgImNvdW50aW5nIHZhcmlhYmxlIHRoYW4gd2FzIGVhcmxpZXIgdXNlZCBpbiBmdW5jdGlvbiwgSSdsbCB1c2UgaiBpbnN0ZWFkIG9mIGkKICAgICBqYWNrX3ZhbHMgPSBudW1lcmljKG4pCiAgICAgCiAgICAgZm9yIChqIGluIDE6bil7ICMgU1RBUlQgSkFDSyBMT09QCiAgICAgICBqYWNrX3NhbXBsZSA9IGRhdGFbLWpdCiAgICAgICAKICAgICAgIG11X2phY2sgPSBzdW0obG9nKGphY2tfc2FtcGxlKSkgLyAobi0xKQogICAgICAgICMgdGhlIGphY2trbmlmZSBlc3RpbWF0ZSBpcyBjb21wdXRlZCBieSBsZWF2aW5nIE9VVCB0aGUgaXRoIG9ic2VydmF0aW9uCiAgICAgICB0aGV0YV9zcXVhcmVkX2phY2sgPSBzdW0oKGxvZyhqYWNrX3NhbXBsZSktbXVfamFjayleMikgLyAobi0xKQogICAgICAgamFja192YWxzW2pdID0gZXhwKG11X2phY2sgKyAodGhldGFfc3F1YXJlZF9qYWNrLzIpKQogICAgIH0gIyBFTkQgSkFDSyBMT09QCiAgICAgCiAgICAgICB0aGV0YV9qYWNrX21lYW4gPSBtZWFuKGphY2tfdmFscykKICAgICAgICAgICAgICMgd2Ugd2FudCB0aGUgZGlmZmVyZW5jZSBiZXR3ZWVuIHRoZSB0b3RhbCBhdmVyYWdlIGFuZCBlYWNoIGphY2trbmlmZSBlc3RpbWF0ZSB0aGF0IGxlZnQgb25lIG91dAogICAgICAgbnVtZXJhdG9yID0gc3VtKCh0aGV0YV9qYWNrX21lYW4gLSBqYWNrX3ZhbHMpXjMpCiAgICAgICBkZW5vbWluYXRvciA9IHN1bSgodGhldGFfamFja19tZWFuIC0gamFja192YWxzKV4yKQogICAgICAgCiAgICAgICBhX2hhdCA9IG51bWVyYXRvci8gKDYgKiBkZW5vbWluYXRvcl4oMy8yKSkKICAgICAjIyMjIEVORCBBQ0NFTEVSQVRJT04gQ0FMQ1VMQVRJT04KICAgICAgIAogICAgICAgCiAgICAjIyMgRklOQUwgT1VUUFVUL0lOVEVSVkFMCiAgICAgICB6X3Njb3JlMSA9IHFub3JtKGFscGhhLzIpCiAgICAgICB6X3Njb3JlMiA9IHFub3JtKDEtYWxwaGEvMikKICAgICAgIGFscGhhMSA9IHBub3JtKHowICsgKHowICsgel9zY29yZTEpLygxLWFfaGF0Kih6MCArIHpfc2NvcmUxKSkpCiAgICAgICBhbHBoYTIgPSBwbm9ybSh6MCArICh6MCArIHpfc2NvcmUyKS8oMS1hX2hhdCooejAgKyB6X3Njb3JlMikpKQogICAgICAgCiAgICAgICBsb3dlciA9IHF1YW50aWxlKGJvb3RzdHJhcF9leF9lc3RpbWF0ZXMsIGFscGhhMSkKICAgICAgIHVwcGVyID0gcXVhbnRpbGUoYm9vdHN0cmFwX2V4X2VzdGltYXRlcywgYWxwaGEyKQogICAgICAgcmVzdWx0cyA9IHJiaW5kKGxvd2VyLHVwcGVyKQogICAgICAgcm93bmFtZXMocmVzdWx0cykgPSBjKCJMb3dlciBFc3RpbWF0ZSIsICJIaWdoZXIgRXN0aW1hdGUiKQogICAgICAgY29sbmFtZXMocmVzdWx0cykgPSAiQkNBIgogICAgICAgCiAgICAgICByZXR1cm4ocmVzdWx0cykKICAgICAgICAgICAgCn0gIyBFTkQgRlVOQ1RJT04KCgojdGVzdApjaV9iY2FfY3VzdG9tID0gY3VzdG9tX2NpX2JjYShkYXRhID0gZGF0YSRzb2lsLCBiPSA1MDAwLCBhbHBoYSA9IDAuMDUsIG9yaWdpbmFsX2VzdGltYXRlID0gRXhfaGF0KQoKI2NpX2JjYV9jdXN0b20KYGBgCgpgYGB7cn0KIyMjIGJ1aWx0LWluIFIgZnVuY3Rpb24KCiMgY2FuIHVzZSBib290X3Jlc3VsdCBvYmplY3QgZnJvbSBzZWN0aW9uIGIKIyBvbmNlIGFnYWluIHVzaW5nIGJvb3QuY2kgZnVuY3Rpb24sIGhvd2V2ZXIgYXJndW1lbnQgY2hhbmdlcyB0byAiYmNhIgpjaV9iY2Ffcl9zdGF0cyA9IGJvb3QuY2koYm9vdF9yZXN1bHQsIHR5cGUgPSAiYmNhIikKCiNjaV9iY2Ffcl9zdGF0cwogICMgaW50ZXJ2YWwgYmV0d2VlbiAzLjUxNSBhbmQgNS41MTUKCiNjaV9iY2Ffcl9zdGF0cyRiY2EKCiNjaV9iY2Ffcl9zdGF0cyRiY2FbNF0gIyA9IGxvd2VyIGludGVydmFsIGVuZAojY2lfYmNhX3Jfc3RhdHMkYmNhWzVdICMgPSBoaWdoZXIgaW50ZXJ2YWwgZW5kCgpjaV9iY2FfciA9IHJiaW5kKGNpX2JjYV9yX3N0YXRzJGJjYVs0XSwKICAgICAgICAgICAgICAgICAgICAgY2lfYmNhX3Jfc3RhdHMkYmNhWzVdKQoKcm93bmFtZXMoY2lfYmNhX3IpID0gYygiTG93ZXIgRXN0aW1hdGUiLCAiSGlnaGVyIEVzdGltYXRlIikKY29sbmFtZXMoY2lfYmNhX3IpID0gIkJDQSIKCiNjaV9iY2FfcgpgYGAKCk9uY2UgYWdhaW4gdXRpbGl6aW5nIHR3byBkaWZmZXJlbnQgY29kaW5nIG1ldGhvZHMsIG15IEJDYSByZXN1bHRzIHdlcmUgdGhlIGZvbGxvd2luZy4gV2l0aCBhcHByb3hpbWF0ZWx5IDk1JSBjb25maWRlbmNlLCB3ZSBjYW4gY2xhaW0gdGhhdCB0aGUgcG9wdWxhdGlvbiBtZWFuIG9mIGxlYWQgY29uY2VudHJhdGlvbiBpbiB1cmJhbiBzaXRlcyBpcyBzb21ld2hlcmUgYmV0d2VlbiBgciByb3VuZChjaV9iY2FfY3VzdG9tWzFdLDMpYCBhbmQgYHIgcm91bmQoY2lfYmNhX2N1c3RvbVsyXSwzKWAgbWcva2cgKm9yKiBgciByb3VuZChjaV9iY2FfclsxXSwzKWAgYW5kIGByIHJvdW5kKGNpX2JjYV9yWzJdLDMpYCBtZy9rZy4KCgojIGQuKSBBc3ltcHRvdGljIENJIApMYXN0bHksIEkgYXR0ZW1wdGVkIHRvIGVzdGltYXRlIHRoZSBwb3B1bGF0aW9uIG1lYW4gbGVhZCBjb25jZW50cmF0aW9uLCBFW1hdLCB2aWEgYW4gYXN5bXB0b3RpYyBvciAibm9ybWFsIiBhcHByb2FjaC4gQXN5bXB0b3RpYyBzYW1wbGluZyBpcyBvZiBjb3Vyc2UgcHJlZGljYXRlZCBvbiB0aGUgaWRlYSBvZiB0aGUgY2VudHJhbCBsaW1pdCB0aGVvcmVtLCBtZWFuaW5nIHRoYXQgYW4gaW5jcmVhc2UgaW4gc2FtcGxlIHNpemUgaXMgY29ycmVsYXRlZCB3aXRoIGFuIGluY3JlYXNlIGluIG5vcm1hbGl6YXRpb24uIAoKQSBmdW5kYW1lbnRhbCBkaWZmZXJlbmNlIGluIGFzeW1wdG90aWMgYW5kIHBlcmNlbnRpbGUgaW50ZXJ2YWwgZXN0aW1hdGlvbiBpcyB0aGF0IHRoZSBjcml0aWNhbCB2YWx1ZSB0ZXJtIGZvciBhc3ltcHRvdGljIGludGVydmFscywgd2hpY2ggdGhlIHN0YW5kYXJkIGVycm9yIGlzIG11bHRpcGxpZWQgYnksIGlzIGRlcGVuZGVudCBvbiB0aGUgcXVhbGl0aWVzIG9mIHRoZSBub3JtYWwgZGlzdHJpYnV0aW9uLiBPbiB0aGUgb3RoZXIgaGFuZCwgdGhlIGNyaXRpY2FsIHZhbHVlIHRlcm0gZm9yIHBlcmNlbnRpbGUgaW50ZXJ2YWxzIGlzIGRlcGVuZGVudCBvbiB0aGUgcXVhbGl0aWVzIG9mIHRoZSBib290c3RyYXAgc2FtcGxlcycgZGlzdHJpYnV0aW9uLiBBIGRvd25zaWRlIG9mIG5vcm1hbCBib290c3RyYXAgaW50ZXJ2YWxzIGlzIHRoZSBhc3N1bXB0aW9uIG9mIG5vcm1hbGx5IGRpc3RyaWJ1dGVkIGRhdGEsIHdoaWNoIGlzIG5vdCBxdWl0ZSBtZXQgdG8gYSBsYXJnZSBkZWdyZWUgaW4gdGhpcyBpbnN0YW5jZS4KCgpgYGB7ciwgaW5jbHVkZT1GQUxTRX0KIyMjIHRlc3RpbmcgY2h1bmsKICAjIGVuZGluZyB1cCBub3QgZ29pbmcgdGhpcyByb3V0ZQoKIyMgYmVsb3cgaXMgImZvcm11bGEiIGZvciBjcmVhdGluZyBsYXJnZXIgcG9wdWxhdGlvbiBvZiBsb2cgbm9ybSBkaXN0cmlidXRlZCBkYXRhIHNpbWlsYXIgdG8gb3VyIHNhbXBsZSBkYXRhCmxhcmdlX3BvcCA9IHJsbm9ybSg1MCwgbWVhbiA9IGxvZyhFeF9oYXQpLCBzZCA9IHRoZXRhX3NxdWFyZWRfaGF0KQpsYXJnZV9wb3AgPSBzb3J0KGxhcmdlX3BvcCkKc29ydCA9IHNvcnQoZGF0YSRzb2lsKQoKbGFyZ2VfcG9wCnNvcnQKbWVhbihsYXJnZV9wb3ApCm1lYW4oZGF0YSRzb2lsKQoKIyMgbWFrZSBsYXJnZSBwb3B1bGF0aW9uIHdpdGggY2hhcmFjdGVyaXN0aWNzIG9mIG91ciBzYW1wbGUgLyBwb3B1bGF0aW9uIGRpc3RyaWJ1dGlvbgpsYXJnZV9wb3AgPSBybG5vcm0oMTAwMDAsIG1lYW4gPSBsb2coRXhfaGF0KSwgc2QgPSB0aGV0YV9zcXVhcmVkX2hhdCkKCiNtZWFuKGxhcmdlX3BvcCkKI21lYW4oZGF0YSRzb2lsKQogICMgbWVhbnMgYXJlIG9mIHNpbWlsYXIgdmFsdWUKCiMjIG5vdyB0YWtlIGJvb3RzdHJhcCBzYW1wbGVzIG9mIHRoYXQgbGFyZ2UgcG9wdWxhdGlvbgoKI2NpX2FzeW1fY3VzdG9tID0gY3VzdG9tX2NpX2FzeW0oZGF0YSA9IGxhcmdlX3BvcCwgYiA9IDUwMDAsIGFscGhhID0gMC4wNSkKCgpgYGAKCmBgYHtyfQojIyMgY3VzdG9tIGZ1bmN0aW9uCiAgIyByZWZlcmVuY2Ugc2VjdGlvbiAzLjEgZnJvbSBub3RlcwogICMgY2FuIHVzZSBib290c3RyYXBfRXggZnVuY3Rpb24gZnJvbSBwYXJ0IGEKCmN1c3RvbV9jaV9hc3ltID0gZnVuY3Rpb24oZGF0YSwgYiwgYWxwaGEpIHsKICBuID0gbGVuZ3RoKGRhdGEpCiAgYm9vdHN0cmFwX2V4X2VzdGltYXRlcyA9IG51bWVyaWMoYikKICAKICAjIGNhbGwgdG8gcHJldmlvdXMgZnVuY3Rpb24KICBib290c3RyYXBfZXhfZXN0aW1hdGVzID0gYm9vdHN0cmFwX0V4KGRhdGEgPSBkYXRhLCBiID0gYikKICAKICAjIG5vdyBlc3RpbWF0ZSBTRQogIHN1bV9wYXJ0ID0gc3VtKChib290c3RyYXBfZXhfZXN0aW1hdGVzIC0gCiAgICAgICAgICAgICAgICAgICAgbWVhbihib290c3RyYXBfZXhfZXN0aW1hdGVzKSleMikKICBzZSA9IHNxcnQoKDEvKGItMSkpKnN1bV9wYXJ0KQogIAogICMgbm93IGZpbmQgYW5kIG91dHB1dCBpbnRlcnZhbAogIGNyaXRfdmFsdWUgPSBhYnMocW5vcm0oYWxwaGEvMikpCiAgbG93ZXIgPSBtZWFuKGJvb3RzdHJhcF9leF9lc3RpbWF0ZXMpIC0gKGNyaXRfdmFsdWUqc2UpCiAgdXBwZXIgPSBtZWFuKGJvb3RzdHJhcF9leF9lc3RpbWF0ZXMpICsgKGNyaXRfdmFsdWUqc2UpCiAgcmVzdWx0cyA9IHJiaW5kKGxvd2VyLHVwcGVyKQogIGNvbG5hbWVzKHJlc3VsdHMpID0gIkN1c3RvbSBBc3ltIgogIHJvd25hbWVzKHJlc3VsdHMpID0gYygiTG93ZXIgRXN0aW1hdGUiLCAiSGlnaGVyIEVzdGltYXRlIikKICAKICByZXR1cm4ocmVzdWx0cykKfQoKY2lfYXN5bV9jdXN0b20gPSBjdXN0b21fY2lfYXN5bShkYXRhID0gZGF0YSRzb2lsLCBiID0gNTAwMCwgYWxwaGEgPSAwLjA1KQoKYGBgCgpgYGB7cn0KIyMjIGJ1aWx0LWluIFIgZnVuY3Rpb24KCiMgb25jZSBhZ2FpbiB1c2UgYm9vdF9yZXN1bHQgb2JqZWN0IGFuZCBib290LmNpIGZ1bmN0aW9uCgpjaV9hc3ltX3Jfc3RhdHMgPSBib290LmNpKGJvb3RfcmVzdWx0LCB0eXBlID0gIm5vcm0iKQogICMgdXNpbmcgYXJndW1lbnQgIm5vcm0iOyBhcyBzYW1wbGUgc2l6ZSBpbmNyZWFzZXMgc28gZG9lcyByZXNlbWJsYW5jZSB0byBub3JtYWxpdHkgYXMgcGVyIENMVCBhbmQgYXN5bXB0b3RpYyB0aGVvcnkKCiNjaV9hc3ltX3Jfc3RhdHMKICAjIGFib3V0IDMuMTYyIHRvIDUuMTQ4CgojY2lfYXN5bV9yX3N0YXRzJG5vcm1hbFsyXSA9IGxvd2VyIGludGVydmFsCiNjaV9hc3ltX3Jfc3RhdHMkbm9ybWFsWzNdID0gaGlnaGVyIGludGVydmFsCgpjaV9hc3ltX3IgPSByYmluZChjaV9hc3ltX3Jfc3RhdHMkbm9ybWFsWzJdLAogICAgICAgICAgICAgICAgICBjaV9hc3ltX3Jfc3RhdHMkbm9ybWFsWzNdKQoKcm93bmFtZXMoY2lfYXN5bV9yKSA9IGMoIkxvd2VyIEVzdGltYXRlIiwgIkhpZ2hlciBFc3RpbWF0ZSIpCmNvbG5hbWVzKGNpX2FzeW1fcikgPSAiQXN5bXB0b3RpYyIKCiNjaV9hc3ltX3IKYGBgCgpQZXIgdGhlIGFzeW1wdG90aWMgbWV0aG9kLCB3ZSBjYW4gc2F5IHdpdGggcm91Z2hseSA5NSUgY2VydGFpbnR5IHRoYXQgdGhlIG1lYW4gbGVhZCBjb25jZW50cmF0aW9uIGFtb25nc3QgdXJiYW4gc2l0ZXMgaXMgZWl0aGVyIGJldHdlZW4gYHIgcm91bmQoY2lfYXN5bV9jdXN0b21bMV0sIDMpYCBhbmQgYHIgcm91bmQoY2lfYXN5bV9jdXN0b21bMl0sIDMpYCBtZy9rZyAqb3IqIGByIHJvdW5kKGNpX2FzeW1fclsxXSwgMylgIGFuZCBgciByb3VuZChjaV9hc3ltX3JbMl0sIDMpYCBtZy9rZwoKIyBlLikgSW50ZXJ2YWwgQ29tcGFyaXNvbgpCZWxvdyBhcmUgdHdvIGNvbXBhcmlzb24gdGFibGVzIGRpc3BsYXlpbmcgdGhlIHJlc3VsdHMgb2YgZWFjaCBvZiB0aGUgdGhyZWUgaW50ZXJ2YWwgbWV0aG9kcyB0aGF0IGhhdmUgYmVlbiBkaXNjdXNzZWQuIFRoZSB0b3AgdGFibGUgY29tcGFyZXMgcmVzdWx0cyB0aGF0IHdlcmUgY29tcHV0ZWQgdmlhIFIncyA8c3BhbiBzdHlsZT0iY29sb3I6Ymx1ZTsiPmJvb3QoKTwvc3Bhbj4gZnVuY3Rpb24sIHdoaWxlIHRoZSBsYXR0ZXIgdGFibGUgc2hvd3MgcmVzdWx0cyBjYWxjdWxhdGVkIHZpYSBteSBjdXN0b20tYnVpbHQgZnVuY3Rpb25zLiBUaGUgY29kZSBmb3IgZWFjaCBjdXN0b20gZnVuY3Rpb24gY2FuIGJlIGZvdW5kIHVuZGVybmVhdGggdGhlIHJlc3BlY3RpdmUgc2VjdGlvbnMuCgpgYGB7cn0KIyMgY29tcGFyaW5nIHRoZSBpbnRlcnZhbHMgY3JlYXRlZCB2aWEgUidzIGJvb3QgZnVuY3Rpb24Kcl9pbnRlcnZhbHMgPSBjYmluZChyb3VuZChjaV9wZXJjZW50X3IsMyksCiAgICAgICAgICAgICAgICAgICAgcm91bmQoY2lfYmNhX3IsMyksCiAgICAgICAgICAgICAgICAgICAgcm91bmQoY2lfYXN5bV9yLDMpKQpyb3duYW1lcyhyX2ludGVydmFscykgPSBjKCJMb3dlciBFc3RpbWF0ZSIsICJIaWdoZXIgRXN0aW1hdGUiKQoKa2FibGUocl9pbnRlcnZhbHMsYWxpZ24gPSAiYyIsCiAgICAgIGNhcHRpb24gPSAiPHNwYW4gc3R5bGU9J2NvbG9yOiMjMDAwMDAwOyc+CiAgICAgIEludGVydmFscyB2aWEgUidzIEJvb3QgRnVuY3Rpb24gPC9zcGFuPiIpICU+JQogIGthYmxlX3N0eWxpbmcoCiAgICBib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiYm9yZGVyZWQiKSwKICAgIGZ1bGxfd2lkdGggPSBGQUxTRSwKICAgIHBvc2l0aW9uID0gImNlbnRlciIpCgojIyBjb21wYXJpbmcgdGhlIGludGVydmFscyBjcmVhdGVkIHZpYSBteSBjdXN0b20gZnVuY3Rpb25zCmN1c3RvbV9pbnRlcnZhbHMgPSBjYmluZChyb3VuZChjaV9wZXJjZW50X2N1c3RvbSwzKSwKICAgICAgICAgICAgICAgICAgICByb3VuZChjaV9iY2FfY3VzdG9tLDMpLAogICAgICAgICAgICAgICAgICAgIHJvdW5kKGNpX2FzeW1fY3VzdG9tLDMpKQpyb3duYW1lcyhjdXN0b21faW50ZXJ2YWxzKSA9IGMoIkxvd2VyIEVzdGltYXRlIiwgIkhpZ2hlciBFc3RpbWF0ZSIpCmNvbG5hbWVzKGN1c3RvbV9pbnRlcnZhbHMpID0gYygiUGVyY2VudGlsZSIsICJCQ0EiLCAiQXN5bXB0b3RpYyIpCgprYWJsZShjdXN0b21faW50ZXJ2YWxzLGFsaWduID0gImMiLAogICAgICBjYXB0aW9uID0gIjxzcGFuIHN0eWxlPSdjb2xvcjojIzAwMDAwMDsnPgogICAgICBJbnRlcnZhbHMgdmlhIEN1c3RvbS1CdWlsdCBGdW5jdGlvbiA8L3NwYW4+IikgJT4lCiAga2FibGVfc3R5bGluZygKICAgIGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJib3JkZXJlZCIpLAogICAgZnVsbF93aWR0aCA9IEZBTFNFLAogICAgcG9zaXRpb24gPSAiY2VudGVyIikKCmBgYAoKIyMgRmluYWwgUmVjb21tZW5kYXRpb24KVGFraW5nIGV2ZXJ5dGhpbmcgaW50byBjb25zaWRlcmF0aW9uLCBJIHdvdWxkIHN1Z2dlc3QgbW92aW5nIGZvcndhcmQgdW5kZXIgdGhlIGFzc3VtcHRpb24gdGhhdCB0aGUgKipCQ2EgaW50ZXJ2YWwqKiBpcyB0aGUgbW9zdCBhY2N1cmF0ZS4gCgpBcyBJIGFsbHVkZWQgdG8gaW4gYSBwcmV2aW91cyBzZWN0aW9uLCB1c2Ugb2YgdGhlIHRoZSBhc3ltcHRvdGljIGludGVydmFsIGdlbmVyYWxseSBhc3N1bWVzIGEgcmVsYXRpdmVseSBub3JtYWwgZGlzdHJpYnV0aW9uIG9mIHRoZSBwb3B1bGF0aW9uIG9mIGludGVyZXN0LiBJbiB0aGlzIHNjZW5hcmlvLCB3ZSBoYXZlIG5vdCBhc3N1bWVkIG5vcm1hbGl0eSBmb3IgdGhlIHBvcHVsYXRpb24gb2YgdXJiYW4gc2l0ZXMnIGxlYWQgY29uY2VudHJhdGlvbnMsIGJ1dCByYXRoZXIgbG9nLW5vcm1hbGl0eS4gQmV5b25kIHRoYXQsIHRoZSBCQ2EgaW50ZXJ2YWwgbWV0aG9kIGlzIHRoZSBtb3N0IHJvYnVzdCBpbiB0aGUgZmFjZSBvZiBza2V3bmVzcyBhbmQgYmlhcy4gSXRzIGJpYXMgY29ycmVjdGlvbiBjb21wb25lbnQgdXRpbGl6ZXMgdGhlIG1lZGlhbiBzdGF0aXN0aWMgdG8gY291bnRlcmJhbGFuY2Ugb3V0bGllcnMsIHNvbWV0aGluZyB0aGF0IGlzIGNlcnRhaW5seSByZWxldmFudCB0byBib3RoIG91ciBzYW1wbGUgZGF0YSBhbmQgYm9vdHN0cmFwIGRpc3RyaWJ1dGlvbiBvZiBFW1hdIGVzdGltYXRlcy4gCgpCZWxvdyBhcmUgdGhlIGhpc3RvZ3JhbXMgZm9yIGJvdGggdGhlIHNhbXBsZSBkYXRhLCBhbmQgcG9wdWxhdGlvbiBtZWFuIGJvb3RzdHJhcCBlc3RpbWF0ZXMsIHRoaXMgdGltZSB3aXRoIHRoZSA5MHRoIHBlcmNlbnRpbGUgb2YgdGhlIGRhdGFzZXQgbWFya2VkLiBUaGlzIGFsbG93cyB1cyB0byBzZWUgaG93IGdyZWF0IG9mIGEgcmlnaHR3YXJkIHNrZXcgaXMgYXBwbGljYWJsZSB0byB0aGlzIHBhcnRpY3VsYXIgYW5hbHlzaXMuCgpgYGB7ciwgZmlnLmhlaWdodD01LjUsIGZpZy53aWR0aD02LjV9Cmhpc3QoZGF0YSRzb2lsLCAKICAgICBtYWluID0gIkRpc3RyaWJ1dGlvbiBvZiBDb25jZW50cmF0aW9ucyIsCiAgICAgeGxhYiA9ICJDb25jZW50cmF0aW9ucyAobWcva2cpIiwKICAgICBwcm9iID0gVFJVRSwKICAgICBjb2wgPSAibGlnaHRibHVlIgopCgogIyBEYXRhIHBvaW50IDkwdGggcGVyY2VudGlsZQogICAgc2VnbWVudHMoCiAgICAgIHgwID0gcXVhbnRpbGUoZGF0YSRzb2lsLDAuOSksCiAgICAgIHkwID0gMCwKICAgICAgeDEgPSBxdWFudGlsZShkYXRhJHNvaWwsMC45KSwKICAgICAgeTEgPSAxLAogICAgICBjb2wgPSAiYmxhY2siLAogICAgICBsd2QgPSA0LAogICAgICBsdHkgPSAzCiAgICApCgpsZWdlbmQoInRvcHJpZ2h0IiwKICAgICAgIGxlZ2VuZCA9ICI5MHRoIFBlcmNlbnRpbGUiLAogICAgICAgY29sID0gImJsYWNrIiwKICAgICAgIGx3ZCA9IDQsCiAgICAgICBsdHkgPSAzLAogICAgICAgYm94Lmx3ZD0zKQoKYm94KGx3ZD0zKQpgYGAKCgpgYGB7ciwgZmlnLmhlaWdodD01LjUsIGZpZy53aWR0aD02LjV9Cmhpc3QoRXhfc2FtcGxpbmdfZGlzdHJpYnV0aW9uLCAKICAgICBtYWluID0gIlNhbXBsaW5nIERpc3RyaWJ1dGlvbiBvZiBQb3B1bGF0aW9uIE1lYW4gRXN0aW1hdGVzIiwKICAgICB4bGFiID0gIkNvbmNlbnRyYXRpb25zIChtZy9rZykiLAogICAgIHByb2IgPSBUUlVFLAogICAgIGNvbCA9ICJsaWdodGJsdWUiCikKCiAjIERhdGEgcG9pbnQgOTB0aCBwZXJjZW50aWxlCiAgICBzZWdtZW50cygKICAgICAgeDAgPSBxdWFudGlsZShFeF9zYW1wbGluZ19kaXN0cmlidXRpb24sMC45KSwKICAgICAgeTAgPSAwLAogICAgICB4MSA9IHF1YW50aWxlKEV4X3NhbXBsaW5nX2Rpc3RyaWJ1dGlvbiwwLjkpLAogICAgICB5MSA9IDEsCiAgICAgIGNvbCA9ICJibGFjayIsCiAgICAgIGx3ZCA9IDQsCiAgICAgIGx0eSA9IDMKICAgICkKCmxlZ2VuZCgidG9wcmlnaHQiLAogICAgICAgbGVnZW5kID0gIjkwdGggUGVyY2VudGlsZSIsCiAgICAgICBjb2wgPSAiYmxhY2siLAogICAgICAgbHdkID0gNCwKICAgICAgIGx0eSA9IDMsCiAgICAgICBib3gubHdkPTMpICAgIAogIApib3gobHdkPTMpCmBgYAo=