This is a notebook-companion to my post. It considers simple linear regression coefficients as least squares estimators for the parameters \(\beta_0^*\) and \(\beta_1^*\) of the assumed affine underlying dependency between random variables \(X\) and \(Y\).

Theory Review

2-Step Generative Model

\[X_i \stackrel{iid}{\sim} Exp(\lambda)\] \[\mathcal{E}_i\stackrel{iid}{\sim} \mathcal{N}(0, \sigma^2) \quad \mbox{(so-called noise)}\] \[Y_i = \beta_0^* + \beta_1^* \cdot X_i + \mathcal{E}_i\] Given a \(n\)-sized sample of random variables \(X\) and \(Y\): \(x_1,\dots,x_n\) and \(y_1,\dots,y_n\), a least squares estimator for \(\beta_0^*\) and \(\beta_1^*\) can be computed as follows:

\[\hat{\beta_1} = \frac{\sum_{i=1}^n y_i \cdot x_i - \overline{y} \cdot \sum_{i=1}^{n}{x_i}}{ \sum_{i=1}^n{x_i^2} - \overline{x} \cdot \sum_{i=1}^n {x_i} } = \frac{S_{xy}}{S_{xx}}\] \[\hat{\beta_0} = \overline{y} - \hat{\beta_1} \cdot \overline{x}\] Estimators are sample statistics. Replicating the sampling process indefinitely, we can treat the estimators as random variables dependent on \(2\cdot n\) variables: \(X_i\) and \(Y_i\), each of \(X_i\) and \(Y_i\) distributed identically to \(X\) and \(Y\) respectively.

\[\overline{X} = \frac{1}{n} \cdot \sum_{i=1}^{n} X_i; \quad \overline{Y} = \frac{1}{n} \cdot \sum_{i=1}^{n} Y_i\]

\[\widehat{\mathcal{B}_1} = \frac{\sum_{i=1}^n Y_i \cdot X_i - \overline{Y} \cdot \sum_{i=1}^{n}{X_i}}{ \sum_{i=1}^n{X_i^2} - \overline{X} \cdot \sum_{i=1}^n {X_i} } = \frac{S_{XY}}{S_{XX}}\] \[\widehat{\mathcal{B}_0} = \overline{Y} - \widehat{\mathcal{B}_1} \cdot \overline{X}\] Multiplying numerator and denominator by \(\frac{1}{n - 1}\), one can express \(\widehat{\mathcal{B}_1}\) in terms of sample variance for \(X\) and empirical covariance between \(X\) and \(Y\).

\[\widehat{\mathcal{B}_1} = \frac{\frac{1}{n-1} \cdot \left(\sum_{i=1}^n Y_i \cdot X_i - n \cdot \overline{Y} \cdot \overline{X}\right)}{\frac{1}{n - 1} \cdot \left(\sum_{i=1}^n{X_i^2} - n \cdot \overline{X} \cdot \overline{X}\right)} = \frac{\widehat{cov[X,Y]}}{\widehat{var[X]}}\]

It can be shown that \(E[\widehat{\mathcal{B}_0}] = \beta_0^*\) and \(E[\widehat{\mathcal{B}_1}] = \beta_1^*\). Computed here are the theoretical means (expectations) of \(\widehat{\mathcal{B}_0}\) and \(\widehat{\mathcal{B}_1}\) (\(\widehat{\mathcal{B}_i}\) being treated as random variables). In practical terms, we can only repeat the sampling process a finite number of times (say, \(m\)), taking \(m\cdot n\) samples of \(X\) and \(Y\) in the process. Thereby we will have \(m\) different estimated values \(\hat{\beta_1}^{(1)},\dots,\hat{\beta_1}^{(m)}\) and \(\hat{\beta_0}^{(1)},\dots,\hat{\beta_0}^{(m)}\).

By the law of large numbers (not going into detail concerning difference between strong and weak LLN and associated types of convergence), \(\overline{\hat{\beta_1}} \longrightarrow E[\widehat{\mathcal{B}_1}] = \beta_1^*\) as \(m \rightarrow \infty\), where \(\overline{\hat{\beta_1}}\) is computed as follows: \[\overline{\hat{\beta_1}} = \frac{1}{m} \cdot \sum_{i=1}^{m} \hat{\beta_1}^{(i)}\] Identical (up to the 0/1 index) expression can be written for \(\beta_0\). In other words, in practice expectations are replaced by averages.

1-Step Generative Model

This model is simpler than the previous one in that it uses deterministic values instead of sampling \(X\). We are given \(n\) constants \(x_i, \dots, x_n\) and they will remain the same throughout the entire sample collection process. The simplified generative model is as follows:

\[\mathcal{E}_i\stackrel{iid}{\sim} \mathcal{N}(0, \sigma^2)\]

\[Y_i = \beta_0^* + \beta_1^* \cdot x_i + \mathcal{E}_i\] The expressions for the random variables \(\widehat{\mathcal{B}_1}\) and \(\widehat{\mathcal{B}_0}\) change slightly:

\[\widehat{\mathcal{B}_1} = \frac{\sum_{i=1}^n Y_i \cdot x_i - \overline{Y} \cdot \sum_{i=1}^{n}{x_i}}{ \sum_{i=1}^n{x_i^2} - \overline{x} \cdot \sum_{i=1}^n {x_i} } = \frac{S_{xY}}{S_{xx}}\] \[\widehat{\mathcal{B}_0} = \overline{Y} - \widehat{\mathcal{B}_1} \cdot \overline{x}\]

As before, \(E[\widehat{\mathcal{B}_0}] = \beta_0^*\) and \(E[\widehat{\mathcal{B}_1}] = \beta_1^*\), but now that \(S_{xx}\) is a constant (rather than a random variable) it becomes easy to compute variances of \(\widehat{\mathcal{B}_i}\). It turns out, from the normality assumption about the noise, we can even deduce distributions of these random variables:

\[\widehat{\mathcal{B}_0} \sim \mathcal{N}\left(\beta_0^*, \; \sigma^2 \cdot \left(\frac{1}{n} + \frac{\overline{x}^2}{S_{xx}} \right)\right)\] \[\widehat{\mathcal{B}_1} \sim \mathcal{N}\left(\beta_1^*, \; \frac{\sigma^2}{S_{xx}} \right)\] The results given by the law of large numbers still hold: \(\lim_{m\rightarrow \infty} \overline{\hat{\beta_1}} = E[\widehat{\mathcal{B}_1}] = \beta_1^*\) and \(\lim_{m\rightarrow \infty} \overline{\hat{\beta_0}} = E[\widehat{\mathcal{B}_0}] = \beta_0^*\). However, it is also known that sample variance converges almost surely (and in probability, of course) to the population variance.

\[\lim_{m\rightarrow \infty} var[\hat{\beta_1}] = var[\widehat{\mathcal{B}_1}] = \frac{\sigma^2}{S_{xx}}\]

\[\lim_{m\rightarrow \infty} var[\hat{\beta_0}] = var[\widehat{\mathcal{B}_0}] = \sigma^2 \cdot \left(\frac{1}{n} + \frac{\overline{x}^2}{S_{xx}}\right)\]

Further, applying central limit theorem, we obtain:

\[\sqrt{m} \cdot \left(\frac{\overline{\widehat{\mathcal{B_0}}} - \beta_0^*}{\sigma \cdot \sqrt{\frac{1}{n} + \frac{\overline{x}^2}{S_{xx}}}} \right) \stackrel{d}{\longrightarrow} \mathcal{N}(0,1)\] \[\sqrt{m} \cdot \frac{\overline{\widehat{\mathcal{B_1}}} - \beta_1^*}{\frac{\sigma}{\sqrt{S_{xx}}}} \stackrel{d}{\longrightarrow} \mathcal{N}(0,1)\] Thus we can conclude that \(\overline{\widehat{\mathcal{B_i}}}\) follow Gaussian distribution in limit; notice that this result did not involve restrictions on the distribution of \(\mathcal{E}\) or \(Y\). Under additional assumptions, stronger statements can be made. Below is progression from the strongest to the weakest statement:

The Experiment

Generative Models Implementation

The code chunk below defines functions that generate random samples and compute linear regression coefficients. Since multiple generative models are supported and parameters required to specify these models differ, we will use R’s environments (passed as a parameter named “varargs”) in order to implement the variable number of arguments.

library(rlang)

Sxy <- function(x, y) {
  sum(x * y) - mean(x) * sum(y)
}

gaussian_noise <- function(n, varargs) {
  stopifnot(env_has(varargs, "noise_sd"))
  rnorm(n, mean = 0, sd = varargs$noise_sd)
}

#explanation variable for the 2-Step generative model
exponential_feature <- function(n, varargs) {
  stopifnot(env_has(varargs, "FeatureParam"))
  rexp(n, varargs$FeatureParam)
}

#explanation variable for the 1-Step generative model
deterministic_feature <- function(n, varargs) {
  stopifnot(env_has(varargs, "XSource"))
  varargs$XSource[1:n]
}

#Replicates computing least squares estimates for coefficients of 
#simple linear regression based on a n-sized sample m times
sample_beta_estimator <- function(m, n, beta0, beta1, varargs) {
  
  beta_hats <- vector()

  for (i in 1:m) {
  
    #data generation
    X <- varargs$gen_feature(n, varargs)
    eps <- varargs$gen_noise(n, varargs)
    Y <- beta0 + beta1 * X + eps
    
    #computing the estimator
    Y_bar <- mean(Y)
    X_bar <- mean(X)
    beta_hat <- c(Y_bar - (Sxy(X, Y) / Sxy(X, X)) * X_bar, Sxy(X, Y) / Sxy(X, X))
    
    beta_hats <- rbind(beta_hats, beta_hat)
  }
  
  beta_hats
}

#Computes empirical mean and variance of estimated linear regression
#coefficients averaged over m runs, each involving calculation of the 
#least squares estimates for a sample of size n
moments_of_beta_estimator <- function(m, n, beta0, beta1, varargs) {
  
  beta_hats <- sample_beta_estimator(m, n, beta0, beta1, varargs)

  #average is in itself an estimator of the expectation of the least squares estimator 
  beta_hat_bar <- c( mean(beta_hats[, 1]), mean(beta_hats[, 2]) )
  beta_hat_var <- c( var(beta_hats[, 1]), var(beta_hats[, 2]) )
  
  c(beta_hat_bar, beta_hat_var)
}

Next global parameters used in generating the data are defined.

#sample size for the experiments where it remains unchanged
n_fixed <- 1000
#the maximum sample size that will ever be used 
n_max <- 100000
#minimum value for n (n should be greater than 1 for X to have non-zero variance)
n_min <- 5

#Distribution parameter for the explanatory variable  
lambda <- 2
#Standard deviation for the Gaussian noise
sigma <- 3
#True (latent) values for regression coefficients
beta_star <- c(5.5, 2.2)
#Deterministic X for the 1-Step model (not treated as a random variable)
Xfull <- rexp(n_max, lambda) 

#The maximum number of times beta estimates are sampled to demo the absence of bias;
#this value cannot be as large as n_max to keep the running time within reasonable limits
m_max_nobias <- 19999

#Parameters for the 2-Step generative model
env_2st <- env(gen_noise = gaussian_noise, noise_sd = sigma, gen_feature = exponential_feature, FeatureParam = lambda)
#Parameters for the 1-Step generative model
env_1st <- env(gen_noise = gaussian_noise, noise_sd = sigma, gen_feature = deterministic_feature, XSource = Xfull)

Plotting: Setting Up the Parameters

color_basic = "#333399"
color_highlight = "#FF6633"
line_width = 2
dot_shape = 21

Visualizing Consistency of the Estimators (Data Collection)

Here the data necessary to demonstrate consistency of estimators for linear regression coefficients is collected. In order to reduce running time, the sequence of sample sizes will be non-linear with the greater density of points near small \(n\)s, where we expect greater variability in the estimator’s values.

#Computes β0 and β1 estimates for gradually increasing sample sizes in order to show consistency of the estimator
collect_data_for_consistency_demo <- function(varargs) {
  
  n_seq <- c(seq(100, 999, 100), seq(1000, m_max_nobias, 500), seq(m_max_nobias + 1, n_max, 1000))

  beta_hats <- data.frame()
  for (n in n_seq) {
    #m == 1, the estimates are computed once only for each n
    beta_hats <- rbind(beta_hats, c(n, sample_beta_estimator(1, n, beta_star[1], beta_star[2], varargs)))
  }
  
  names(beta_hats) <- c("n", "beta0", "beta1")
  
  beta_hats
}

beta_hats_2step <- collect_data_for_consistency_demo(env_2st)
beta_hats_1step <- collect_data_for_consistency_demo(env_1st)

Visualizing Consistency of the Estimators (Plotting)

Visualizing Unbiasedness of the Estimators (Data Collection)

This time the sample size is kept fixed at n_fixed and the sampling procedure is repeated \(m\) times. For each sample, we compute the LS estimators as statistics of that sample and then average the estimated values over \(m\) experiments thereby obtaining the estimators’ empirical means and variances. As before, a non-linear sequence of \(m\) is used, but in order to keep the running time within reasonable limits we have to limit the number of experiments.

#Computes sample mean and variance for a sequence of m-sized samples of estimated β0 and β1, 
#each, in turn, computed based on a n_fixed-sized sample of X and Y. 
collect_data_for_bias_demo <- function(varargs) {
  
  m_seq <- c(seq(100, 999, 100), seq(1000, m_max_nobias, 500))

  beta_hat_means <- data.frame()
  for (m in m_seq) {
    beta_hat_means <- rbind(beta_hat_means, 
        c(m, moments_of_beta_estimator(m, n_fixed, beta_star[1], beta_star[2], varargs)))
  }
  
  names(beta_hat_means) <- c("m", "mean_beta0", "mean_beta1", "var_beta0", "var_beta1")
  
  beta_hat_means
}

beta_hat_means_2step <- collect_data_for_bias_demo(env_2st)
beta_hat_means_1step <- collect_data_for_bias_demo(env_1st)

Visualizing Unbiasedness of the Estimators (Plotting the Means)

By the law of large numbers, average and sample variance of a random variable should go to its expectation and population variance respectively as the sample size goes to infinity. Moreover, expectations of the LS estimators have been shown to be the true values of the coefficients in the underlying affine relation, therefore, as \(m\) increases, we should observe average estimated values for a coefficient concentrate around its true value.


demo_absense_of_bias <- function(bhs, steps, beta_idx) {
  
  sidx <- paste0("mean_beta", beta_idx)
  all_data <- c(bhs[[1]][, sidx], bhs[[2]][, sidx])
  
  plot(bhs[[steps]][,"m"], bhs[[steps]][, sidx], 
       bg = color_basic, pch = dot_shape,
       ylim = c(min(all_data), max(all_data)),
       xlab = "m", ylab = paste0("Mean Estimated beta", beta_idx), 
       main = paste0(steps, "-Step Generative Model"))
  
  lines(bhs[[steps]][,"m"], rep(beta_star[beta_idx + 1], dim(bhs[[steps]])[1]), 
        col = color_highlight, lwd = line_width)
}


par(mfcol = c(2, 2))

bhs <- list(beta_hat_means_1step, beta_hat_means_2step)
demo_absense_of_bias(bhs, 2, 0)
demo_absense_of_bias(bhs, 2, 1)
demo_absense_of_bias(bhs, 1, 0)
demo_absense_of_bias(bhs, 1, 1)

Variance of the Estimates

var_beta_0 <- function(noise_sd, x) {
  noise_sd^2 * (1/length(x) + (mean(x)^2)/Sxy(x, x))
}

var_beta_1 <- function(noise_sd, x) {
  noise_sd^2 / Sxy(x, x)
}

On Convergence Rates

This section, rather than being essential to the analysis of the experimental results, is more of a curiosity and, as such, it can be safely skipped.

Having compared the convergence plots illustrating consistency and unbiasedness properties of the LS estimators, one may falsely conclude that in the case of consistency, the observed values converge to the true ones faster. However, it is only an illusion created by the difference in the restriction we have put on the maximum values of n and m and the resulting difference in scale.

In order to estimate the actual convergence rates, we combine data points for the same values of n and m on a single figure. In particular, an absolute difference between the estimated and true value of the coefficient \(\beta_1\) in the 1-Step model will be plotted. It may also be helpful to consider the difference in variances of the estimated values \(\hat{\beta_1}\) and the same, averaged over m samples, while keeping in mind that smaller variances translate into faster convergence rates.

par(mfcol = c(2, 1))

lim_n = dim(beta_hat_means_1step)[1]

all_data <- c(abs(beta_hat_means_1step$mean_beta1[1:lim_n] - rep(beta_star[2], lim_n)), 
              abs(beta_hats_1step$beta1[1:lim_n] - rep(beta_star[2], lim_n)))

plot(beta_hat_means_1step$m[1:lim_n], 
     abs(beta_hat_means_1step$mean_beta1[1:lim_n] - rep(beta_star[2], lim_n)), 
     ylim = c(min(all_data), max(all_data)), bg = color_basic, pch = dot_shape, 
     xlab = "sample size", 
     ylab = "|estimated beta1 - beta1*|", main = "Convergence Rates for the 1-Step Generative Model")

points(beta_hats_1step$n[1:lim_n], 
      abs(beta_hats_1step$beta1[1:lim_n] - rep(beta_star[2], lim_n)),
      bg = color_highlight,  pch = dot_shape)

legend(x = "topright", legend = c("mean beta1 estimate (from bias check)", 
                                  "beta1 etimate (from consistency check)"), 
       pch = 20, col = c(color_basic, color_highlight))

vars_cons <- vector()
vars_bias <- vector()
first_n <- n_min #skip the first few extra large variances to obtain a better-scaled plot
for (num in first_n:lim_n) {
  vars_cons <- c(vars_cons, var_beta_1(sigma, Xfull[1:beta_hats_1step$n[num]]))
  vars_bias <- c(vars_bias, var_beta_1(sigma, Xfull[1:n_fixed]) / beta_hat_means_1step$m[num])
}

plot(beta_hats_1step$n[first_n:lim_n], vars_cons, type = "l", 
     col = color_highlight, lwd = line_width, 
     xlab = "sample size", ylab = "Variance")
lines(beta_hats_1step$n[first_n:lim_n], vars_bias, col = color_basic, lwd = line_width)

legend(x = "topright", legend = c("variance of mean beta1 estimates (from bias check)", 
                                  "variance of beta1 etimates (from consistency check)"), 
       pch = 20, col = c(color_basic, color_highlight))

Visualizing the LLN Results for Variances

Similar to the means, sample variances of the estimators go to the respective population variances as the number of runs (m) increases. Apart from the fact that we derived expressions for population variances in the setting of the 1-Step Model only, the plots are constructed similar to the ones for means.


par(mfcol = c(2, 2))

#Empirical beta variance for the 2-Step Model (population variance is outside the scope of this work) 
plot(beta_hat_means_2step$m, beta_hat_means_2step$var_beta0, bg = color_basic, pch = dot_shape, 
     xlab = "m", ylab = "Variance of Estimated beta0", main = "2-Step Generative Model")
plot(beta_hat_means_2step$m, beta_hat_means_2step$var_beta1, bg = color_basic, pch = dot_shape, 
     xlab = "m", ylab = "Variance of Estimated beta1", main = "2-Step Generative Model")

#Sample and population beta variances for the 1-Step Model
plot(beta_hat_means_1step$m, beta_hat_means_1step$var_beta0, bg = color_basic, pch = dot_shape, 
     xlab = "m", ylab = "Variance of Estimated beta0", main = "1-Step Generative Model")
lines(beta_hat_means_1step$m, rep(var_beta_0(sigma, Xfull[1:n_fixed]), dim(beta_hat_means_1step)[1]), 
      col = color_highlight, lwd = line_width)     

plot(beta_hat_means_1step$m, beta_hat_means_1step$var_beta1, bg = color_basic, pch = dot_shape, 
     xlab = "m", ylab = "Variance of Estimated beta1", main = "1-Step Generative Model")
lines(beta_hat_means_1step$m, rep(var_beta_1(sigma, Xfull[1:n_fixed]), dim(beta_hat_means_1step)[1]), 
      col = color_highlight, lwd = line_width)

Distribution of the Estimated Values

In the setting of the 1-Step Model, the estimated values for the hidden parameters \(\beta_0^*\) and \(\beta_1^*\) are known to be normally distributed with the means equal to \(\beta_0^*\) and \(\beta_1^*\) respectively and variances dependent on \(X\) and standard deviation of noise.

As before, the sampling procedure is repeated \(m\) times with the key difference being that \(m\) remains fixed rather than an increasing sequence of values; the estimated values are collected in the process thereby resulting in \(m\) values of \(\hat{\beta_0}\) and \(\hat{\beta_1}\) each (no averages are computed). Then we construct histograms of the estimated values and see how well they match the theoretical PDFs.

m <- 10000
hist_bins <- 50

#computes a normal PDF with mean mu and standard deviation sg 
#limited to the values in the vector x 
normal_curve <- function(x, mu, sg) {
  
  xd <- seq(min(x), max(x), 0.01)
  yd <- dnorm(xd, mean = mu, sd = sg)
  cbind(xd, yd)
}

#collecting data for the 2-step model 
beta_hats_2step_h <- sample_beta_estimator(m, n_fixed, beta_star[1], beta_star[2], env_2st)

#collecting data for the 1-step model
beta_hats_1step_h <- sample_beta_estimator(m, n_fixed, beta_star[1], beta_star[2], env_1st)
#computing theoretical beta PDFs for the 1-step model
beta0_pdf <- normal_curve(beta_hats_1step_h[,1], beta_star[1], 
                              sqrt(var_beta_0(sigma, Xfull[1:n_fixed])))
beta1_pdf <- normal_curve(beta_hats_1step_h[,2], beta_star[2], 
                              sqrt(var_beta_1(sigma, Xfull[1:n_fixed])))

par(mfcol = c(2, 2))

#2-Step Model (no theoretical results concerning the underlying distribution in this work)
hist(beta_hats_2step_h[,1], breaks = hist_bins, freq = FALSE, 
     main = "2-Step Generative Model", xlab = "beta0", col = color_basic)

hist(beta_hats_2step_h[,2], breaks = hist_bins, freq = FALSE, 
     main = "2-Step Generative Model", xlab = "beta1", col = color_basic)

#1-Step Model
hist(beta_hats_1step_h[,1], breaks = hist_bins, freq = FALSE, 
     main = "1-Step Generative Model", xlab = "beta0", col = color_basic)
lines(beta0_pdf[,1], beta0_pdf[,2], lwd = line_width, col = color_highlight)

hist(beta_hats_1step_h[,2], breaks = hist_bins, freq = FALSE, 
     main = "1-Step Generative Model", xlab = "beta1", col = color_basic)
lines(beta1_pdf[,1], beta1_pdf[,2], lwd = line_width, col = color_highlight)

Distribution of the Estimator’s Means (Data Collecation)

Not only do we know how the estimated beta values are distributed, сentral limit theorem also gives us the information concerning distribution of mean values of the estimators (in the limit). Let us construct histograms for various values of \(m\) in an effort to confirm that the distribution of \(\sqrt{m} \cdot (\overline{\widehat{\mathcal{B}_i}} - \beta_i^*) / \sqrt{var[\widehat{\mathcal{B}_i}]}\), indeed, approaches standard normal. In order to achieve this, we must wrap our data collection procedure in another loop, this time over \(k\).

The demonstration will be limited to the 1-step generative model.

k_max <- 2000
m_seq <- c(1, 10, 1000)

#Collects k samples of mean estimated values for the linear regression coefficients
#along with respective sample variances.
#Each estimated value is computed for a n-sized sample of X and Y; then an average
#and sample variance are calculated over m such values.
replicate_average_estimator <- function(m, n, k, varargs) {
  
  bh <- data.frame()
  
  for (i in 1:k) {
    bh <- rbind(bh, c(moments_of_beta_estimator(m, n, beta_star[1], beta_star[2], varargs)))
  }
  
  names(bh) <- c("mean_beta0", "mean_beta1", "var_beta0", "var_beta1")
  bh
}

#running replicate_average_estimator for various values of m (given by the sequence m_seq)
beta_hat_means_1step_cm <- lapply(m_seq, replicate_average_estimator, n_min, k_max, env_1st)
#theoretical variances of estimated linear regression coefficients
beta_vars_cm <- c(var_beta_0(sigma, Xfull[1:n_min]), var_beta_1(sigma, Xfull[1:n_min]))

Distribution of the Estimator’s Means (Plotting)

Here we plot the PDFs interpolated from histograms for the data collected at the previous step along with a PDF of the standard normal distribution for various values of m. What we are hoping to see is the reconstructed PDF gradually shaping into that of \(\mathcal{N}(0, 1)\).

par(mfcol = c(2, length(beta_hat_means_1step_cm)))

show_density <- function(m, bhms, beta_vars, beta_idx) {
  
  #either mean_beta0 or mean_beta1 (depending on the value of beta_idx)
  b = bhms[, beta_idx + 1]
  
  #theoretical variance of beta0 or beta1 (depending on the value of beta_idx)
  bvar = beta_vars[beta_idx + 1]
  
  #computing an r.v. that should converge to N(0, 1) in distribution
  clt = sqrt(m) * (b - rep(beta_star[beta_idx + 1], length(b))) / sqrt(bvar)
  dclt = density(clt)
  
  #pdf of standard normal distribution 
  curve(dnorm(x, mean = 0, sd = 1), from =-4, to = 4, col = color_highlight, ylim = c(0, max(0.4, max(dclt$y))),
        ylab = "density", xlab = paste("mean beta", beta_idx), main = paste("m = ", m), lwd = line_width)
  
  #interpolate clt's pdf from its histogram
  lines(dclt, col = color_basic, lw = line_width, lty = 2)
}

for (idx in 1:length(beta_hat_means_1step_cm)) {
  show_density(m_seq[idx], beta_hat_means_1step_cm[[idx]], beta_vars_cm, 0)
  show_density(m_seq[idx], beta_hat_means_1step_cm[[idx]], beta_vars_cm, 1)
}

The plots do not seem to change drastically with an increase in sample size and the effect of convergence in distribution is not clearly visible. It should not be. When the noise is Gaussian, the estimated values themselves are already normally distributed and so are their averages, even for very small m. Let us try another distribution for the noise.

Distribution of the Estimator’s Means (Beta-Distributed Noise)

Which of the known distributions can we choose? The possibilities are numerous while restrictions are not: the distribution of choice must have finite variance and zero mean. Why not Beta distribution shifted to the left by the value of its mean?

alpha <- 1.1
beta <- 9

#samples n values from beta distribution
beta_noise <- function(n, varargs) {
  stopifnot(env_has(varargs, "alpha"))
  stopifnot(env_has(varargs, "beta"))
  rbeta(n, varargs$alpha, varargs$beta) - varargs$alpha / (varargs$alpha + varargs$beta)
}

env_1st_bn <- env(gen_noise = beta_noise, alpha = alpha, beta = beta, gen_feature = deterministic_feature, XSource = Xfull)

beta_hat_means_1step_bncm <- lapply(m_seq, replicate_average_estimator, n_min, k_max, env_1st_bn)
#standard deviation of Beta distribution
bn_sd <- sqrt((alpha * beta)/(alpha + beta + 1.0)) * (1.0/(alpha + beta))
beta_vars_bncm <- c(var_beta_0(bn_sd, Xfull[1:n_min]), var_beta_1(bn_sd, Xfull[1:n_min]))

An interesting feature of Beta distribution with these particular parameters is its asymmetry relative to the mean (one of the reasons why I picked it).

curve(dbeta(x, alpha, beta), col = color_basic, ylab = "beta PDF",lwd = line_width)
beta_mean <- alpha / (alpha + beta)
mean_ln <- seq(0, dbeta(beta_mean, alpha, beta), 0.1)
lines(rep(beta_mean, length(mean_ln)), mean_ln, col = color_highlight, lwd = line_width)

A cursory glance at the formula for computing the \(\hat{\beta_1}\) estimator leads us to the conclusion that the estimated values may still be roughly normally distributed (even if the noise is not Gaussian) if \(n\) is large enough, therefore n_min is used in place of n_fixed.

Let us now repeat the experiment with the new distribution for the noise.

par(mfcol = c(2, length(beta_hat_means_1step_bncm)))

for (idx in 1:length(beta_hat_means_1step_cm)) {
  show_density(m_seq[idx], beta_hat_means_1step_bncm[[idx]], beta_vars_bncm, 0)
  show_density(m_seq[idx], beta_hat_means_1step_bncm[[idx]], beta_vars_bncm, 1)
}

LS0tDQp0aXRsZTogIkV4cGVyaW1lbnRhbCBSZXN1bHRzIGZvciB0aGUgRXhwZWN0YXRpb24gb2YgTGVhc3QgU3F1YXJlcyBFc3RpbWF0b3IiDQphdXRob3I6ICJSQXVzYyINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCjxzdHlsZT4NCiAgaDEgeyBjb2xvcjogI2U5M2YwMDsgfQ0KICBoMiB7IGNvbG9yOiAjZTkzZjAwOyB9DQogIGgzIHsgY29sb3I6ICNlOTNmMDA7IH0NCjwvc3R5bGU+DQoNClRoaXMgaXMgYSBub3RlYm9vay1jb21wYW5pb24gdG8gbXkgcG9zdC4gSXQgY29uc2lkZXJzIHNpbXBsZSBsaW5lYXIgcmVncmVzc2lvbiBjb2VmZmljaWVudHMgYXMgbGVhc3Qgc3F1YXJlcyBlc3RpbWF0b3JzIGZvciB0aGUgcGFyYW1ldGVycyAkXGJldGFfMF4qJCBhbmQgJFxiZXRhXzFeKiQgb2YgdGhlIGFzc3VtZWQgYWZmaW5lIHVuZGVybHlpbmcgZGVwZW5kZW5jeSBiZXR3ZWVuIHJhbmRvbSB2YXJpYWJsZXMgJFgkIGFuZCAkWSQuDQoNCiMjIFRoZW9yeSBSZXZpZXcNCg0KIyMjIDItU3RlcCBHZW5lcmF0aXZlIE1vZGVsDQoNCiQkWF9pIFxzdGFja3JlbHtpaWR9e1xzaW19IEV4cChcbGFtYmRhKSQkIA0KJCRcbWF0aGNhbHtFfV9pXHN0YWNrcmVse2lpZH17XHNpbX0gXG1hdGhjYWx7Tn0oMCwgXHNpZ21hXjIpIFxxdWFkIFxtYm94eyhzby1jYWxsZWQgbm9pc2UpfSQkIA0KJCRZX2kgPSBcYmV0YV8wXiogKyBcYmV0YV8xXiogXGNkb3QgWF9pICsgXG1hdGhjYWx7RX1faSQkDQpHaXZlbiBhICRuJC1zaXplZCBzYW1wbGUgb2YgcmFuZG9tIHZhcmlhYmxlcyAkWCQgYW5kICRZJDogJHhfMSxcZG90cyx4X24kIGFuZCAkeV8xLFxkb3RzLHlfbiQsIGEgbGVhc3Qgc3F1YXJlcyBlc3RpbWF0b3IgZm9yICRcYmV0YV8wXiokIGFuZCAkXGJldGFfMV4qJCBjYW4gYmUgY29tcHV0ZWQgYXMgZm9sbG93czoNCg0KJCRcaGF0e1xiZXRhXzF9ID0gXGZyYWN7XHN1bV97aT0xfV5uIHlfaSBcY2RvdCB4X2kgLSBcb3ZlcmxpbmV7eX0gXGNkb3QgXHN1bV97aT0xfV57bn17eF9pfX17IFxzdW1fe2k9MX1ebnt4X2leMn0gLSBcb3ZlcmxpbmV7eH0gXGNkb3QgXHN1bV97aT0xfV5uIHt4X2l9IH0gPSBcZnJhY3tTX3t4eX19e1Nfe3h4fX0kJA0KJCRcaGF0e1xiZXRhXzB9ID0gXG92ZXJsaW5le3l9IC0gXGhhdHtcYmV0YV8xfSBcY2RvdCBcb3ZlcmxpbmV7eH0kJA0KRXN0aW1hdG9ycyBhcmUgc2FtcGxlIHN0YXRpc3RpY3MuIFJlcGxpY2F0aW5nIHRoZSBzYW1wbGluZyBwcm9jZXNzIGluZGVmaW5pdGVseSwgd2UgY2FuIHRyZWF0IHRoZSBlc3RpbWF0b3JzIGFzIHJhbmRvbSB2YXJpYWJsZXMgZGVwZW5kZW50IG9uICQyXGNkb3QgbiQgdmFyaWFibGVzOiAkWF9pJCBhbmQgJFlfaSQsIGVhY2ggb2YgJFhfaSQgYW5kICRZX2kkIGRpc3RyaWJ1dGVkIGlkZW50aWNhbGx5IHRvICRYJCBhbmQgJFkkIHJlc3BlY3RpdmVseS4gDQoNCiQkXG92ZXJsaW5le1h9ID0gXGZyYWN7MX17bn0gXGNkb3QgXHN1bV97aT0xfV57bn0gWF9pOyBccXVhZCBcb3ZlcmxpbmV7WX0gPSBcZnJhY3sxfXtufSBcY2RvdCBcc3VtX3tpPTF9XntufSBZX2kkJA0KDQokJFx3aWRlaGF0e1xtYXRoY2Fse0J9XzF9ID0gXGZyYWN7XHN1bV97aT0xfV5uIFlfaSBcY2RvdCBYX2kgLSBcb3ZlcmxpbmV7WX0gXGNkb3QgXHN1bV97aT0xfV57bn17WF9pfX17IFxzdW1fe2k9MX1ebntYX2leMn0gLSBcb3ZlcmxpbmV7WH0gXGNkb3QgXHN1bV97aT0xfV5uIHtYX2l9IH0gPSBcZnJhY3tTX3tYWX19e1Nfe1hYfX0kJA0KJCRcd2lkZWhhdHtcbWF0aGNhbHtCfV8wfSA9IFxvdmVybGluZXtZfSAtIFx3aWRlaGF0e1xtYXRoY2Fse0J9XzF9IFxjZG90IFxvdmVybGluZXtYfSQkDQpNdWx0aXBseWluZyBudW1lcmF0b3IgYW5kIGRlbm9taW5hdG9yIGJ5ICRcZnJhY3sxfXtuIC0gMX0kLCBvbmUgY2FuIGV4cHJlc3MgJFx3aWRlaGF0e1xtYXRoY2Fse0J9XzF9JCBpbiB0ZXJtcyBvZiBzYW1wbGUgdmFyaWFuY2UgZm9yICRYJCBhbmQgZW1waXJpY2FsIGNvdmFyaWFuY2UgYmV0d2VlbiAkWCQgYW5kICRZJC4NCg0KJCRcd2lkZWhhdHtcbWF0aGNhbHtCfV8xfSA9IFxmcmFje1xmcmFjezF9e24tMX0gXGNkb3QgXGxlZnQoXHN1bV97aT0xfV5uIFlfaSBcY2RvdCBYX2kgLSBuIFxjZG90IFxvdmVybGluZXtZfSBcY2RvdCBcb3ZlcmxpbmV7WH1ccmlnaHQpfXtcZnJhY3sxfXtuIC0gMX0gXGNkb3QgXGxlZnQoXHN1bV97aT0xfV5ue1hfaV4yfSAtIG4gXGNkb3QgXG92ZXJsaW5le1h9IFxjZG90IFxvdmVybGluZXtYfVxyaWdodCl9ID0gXGZyYWN7XHdpZGVoYXR7Y292W1gsWV19fXtcd2lkZWhhdHt2YXJbWF19fSQkDQoNCkl0IGNhbiBiZSBzaG93biB0aGF0ICRFW1x3aWRlaGF0e1xtYXRoY2Fse0J9XzB9XSA9IFxiZXRhXzBeKiQgYW5kICRFW1x3aWRlaGF0e1xtYXRoY2Fse0J9XzF9XSA9IFxiZXRhXzFeKiQuIENvbXB1dGVkIGhlcmUgYXJlIHRoZSB0aGVvcmV0aWNhbCBtZWFucyAoZXhwZWN0YXRpb25zKSBvZiAkXHdpZGVoYXR7XG1hdGhjYWx7Qn1fMH0kIGFuZCAkXHdpZGVoYXR7XG1hdGhjYWx7Qn1fMX0kICgkXHdpZGVoYXR7XG1hdGhjYWx7Qn1faX0kIGJlaW5nIHRyZWF0ZWQgYXMgcmFuZG9tIHZhcmlhYmxlcykuIEluIHByYWN0aWNhbCB0ZXJtcywgd2UgY2FuIG9ubHkgcmVwZWF0IHRoZSBzYW1wbGluZyBwcm9jZXNzIGEgZmluaXRlIG51bWJlciBvZiB0aW1lcyAoc2F5LCAkbSQpLCB0YWtpbmcgJG1cY2RvdCBuJCBzYW1wbGVzIG9mICRYJCBhbmQgJFkkIGluIHRoZSBwcm9jZXNzLiBUaGVyZWJ5IHdlIHdpbGwgaGF2ZSAkbSQgZGlmZmVyZW50IGVzdGltYXRlZCB2YWx1ZXMgICRcaGF0e1xiZXRhXzF9XnsoMSl9LFxkb3RzLFxoYXR7XGJldGFfMX1eeyhtKX0kIGFuZCAkXGhhdHtcYmV0YV8wfV57KDEpfSxcZG90cyxcaGF0e1xiZXRhXzB9XnsobSl9JC4gDQoNCkJ5IHRoZSBsYXcgb2YgbGFyZ2UgbnVtYmVycyAobm90IGdvaW5nIGludG8gZGV0YWlsIGNvbmNlcm5pbmcgZGlmZmVyZW5jZSBiZXR3ZWVuIHN0cm9uZyBhbmQgd2VhayBMTE4gYW5kIGFzc29jaWF0ZWQgdHlwZXMgb2YgY29udmVyZ2VuY2UpLCAkXG92ZXJsaW5le1xoYXR7XGJldGFfMX19IFxsb25ncmlnaHRhcnJvdyBFW1x3aWRlaGF0e1xtYXRoY2Fse0J9XzF9XSA9IFxiZXRhXzFeKiQgYXMgJG0gXHJpZ2h0YXJyb3cgXGluZnR5JCwgd2hlcmUgJFxvdmVybGluZXtcaGF0e1xiZXRhXzF9fSQgaXMgY29tcHV0ZWQgYXMgZm9sbG93czogDQokJFxvdmVybGluZXtcaGF0e1xiZXRhXzF9fSA9IFxmcmFjezF9e219IFxjZG90IFxzdW1fe2k9MX1ee219IFxoYXR7XGJldGFfMX1eeyhpKX0kJA0KSWRlbnRpY2FsICh1cCB0byB0aGUgMC8xIGluZGV4KSBleHByZXNzaW9uIGNhbiBiZSB3cml0dGVuIGZvciAkXGJldGFfMCQuIEluIG90aGVyIHdvcmRzLCBpbiBwcmFjdGljZSBleHBlY3RhdGlvbnMgYXJlIHJlcGxhY2VkIGJ5IGF2ZXJhZ2VzLiANCg0KDQojIyMgMS1TdGVwIEdlbmVyYXRpdmUgTW9kZWwNCg0KVGhpcyBtb2RlbCBpcyBzaW1wbGVyIHRoYW4gdGhlIHByZXZpb3VzIG9uZSBpbiB0aGF0IGl0IHVzZXMgZGV0ZXJtaW5pc3RpYyB2YWx1ZXMgaW5zdGVhZCBvZiBzYW1wbGluZyAkWCQuIFdlIGFyZSBnaXZlbiAkbiQgY29uc3RhbnRzICR4X2ksIFxkb3RzLCB4X24kIGFuZCB0aGV5IHdpbGwgcmVtYWluIHRoZSBzYW1lIHRocm91Z2hvdXQgdGhlIGVudGlyZSBzYW1wbGUgY29sbGVjdGlvbiBwcm9jZXNzLiBUaGUgc2ltcGxpZmllZCBnZW5lcmF0aXZlIG1vZGVsIGlzIGFzIGZvbGxvd3M6DQoNCiQkXG1hdGhjYWx7RX1faVxzdGFja3JlbHtpaWR9e1xzaW19IFxtYXRoY2Fse059KDAsIFxzaWdtYV4yKSQkDQoNCiQkWV9pID0gXGJldGFfMF4qICsgXGJldGFfMV4qIFxjZG90IHhfaSArIFxtYXRoY2Fse0V9X2kkJA0KVGhlIGV4cHJlc3Npb25zIGZvciB0aGUgcmFuZG9tIHZhcmlhYmxlcyAkXHdpZGVoYXR7XG1hdGhjYWx7Qn1fMX0kIGFuZCAkXHdpZGVoYXR7XG1hdGhjYWx7Qn1fMH0kIGNoYW5nZSBzbGlnaHRseToNCg0KJCRcd2lkZWhhdHtcbWF0aGNhbHtCfV8xfSA9IFxmcmFje1xzdW1fe2k9MX1ebiBZX2kgXGNkb3QgeF9pIC0gXG92ZXJsaW5le1l9IFxjZG90IFxzdW1fe2k9MX1ee259e3hfaX19eyBcc3VtX3tpPTF9Xm57eF9pXjJ9IC0gXG92ZXJsaW5le3h9IFxjZG90IFxzdW1fe2k9MX1ebiB7eF9pfSB9ID0gXGZyYWN7U197eFl9fXtTX3t4eH19JCQNCiQkXHdpZGVoYXR7XG1hdGhjYWx7Qn1fMH0gPSBcb3ZlcmxpbmV7WX0gLSBcd2lkZWhhdHtcbWF0aGNhbHtCfV8xfSBcY2RvdCBcb3ZlcmxpbmV7eH0kJA0KDQpBcyBiZWZvcmUsICRFW1x3aWRlaGF0e1xtYXRoY2Fse0J9XzB9XSA9IFxiZXRhXzBeKiQgYW5kICRFW1x3aWRlaGF0e1xtYXRoY2Fse0J9XzF9XSA9IFxiZXRhXzFeKiQsIGJ1dCBub3cgdGhhdCAkU197eHh9JCBpcyBhIGNvbnN0YW50IChyYXRoZXIgdGhhbiBhIHJhbmRvbSB2YXJpYWJsZSkgaXQgYmVjb21lcyBlYXN5IHRvIGNvbXB1dGUgdmFyaWFuY2VzIG9mICRcd2lkZWhhdHtcbWF0aGNhbHtCfV9pfSQuIEl0IHR1cm5zIG91dCwgZnJvbSB0aGUgbm9ybWFsaXR5IGFzc3VtcHRpb24gYWJvdXQgdGhlIG5vaXNlLCB3ZSBjYW4gZXZlbiBkZWR1Y2UgZGlzdHJpYnV0aW9ucyBvZiB0aGVzZSByYW5kb20gdmFyaWFibGVzOg0KDQokJFx3aWRlaGF0e1xtYXRoY2Fse0J9XzB9IFxzaW0gXG1hdGhjYWx7Tn1cbGVmdChcYmV0YV8wXiosIFw7IFxzaWdtYV4yIFxjZG90IFxsZWZ0KFxmcmFjezF9e259ICsgXGZyYWN7XG92ZXJsaW5le3h9XjJ9e1Nfe3h4fX0gXHJpZ2h0KVxyaWdodCkkJA0KJCRcd2lkZWhhdHtcbWF0aGNhbHtCfV8xfSBcc2ltIFxtYXRoY2Fse059XGxlZnQoXGJldGFfMV4qLCBcOyAgXGZyYWN7XHNpZ21hXjJ9e1Nfe3h4fX0gXHJpZ2h0KSQkDQpUaGUgcmVzdWx0cyBnaXZlbiBieSB0aGUgbGF3IG9mIGxhcmdlIG51bWJlcnMgc3RpbGwgaG9sZDogJFxsaW1fe21ccmlnaHRhcnJvdyBcaW5mdHl9IFxvdmVybGluZXtcaGF0e1xiZXRhXzF9fSA9IEVbXHdpZGVoYXR7XG1hdGhjYWx7Qn1fMX1dID0gXGJldGFfMV4qJCBhbmQgJFxsaW1fe21ccmlnaHRhcnJvdyBcaW5mdHl9IFxvdmVybGluZXtcaGF0e1xiZXRhXzB9fSA9IEVbXHdpZGVoYXR7XG1hdGhjYWx7Qn1fMH1dID0gXGJldGFfMF4qJC4gSG93ZXZlciwgaXQgaXMgYWxzbyBrbm93biB0aGF0IHNhbXBsZSB2YXJpYW5jZSBjb252ZXJnZXMgYWxtb3N0IHN1cmVseSAoYW5kIGluIHByb2JhYmlsaXR5LCBvZiBjb3Vyc2UpIHRvIHRoZSBwb3B1bGF0aW9uIHZhcmlhbmNlLg0KDQokJFxsaW1fe21ccmlnaHRhcnJvdyBcaW5mdHl9IHZhcltcaGF0e1xiZXRhXzF9XSA9IHZhcltcd2lkZWhhdHtcbWF0aGNhbHtCfV8xfV0gPSBcZnJhY3tcc2lnbWFeMn17U197eHh9fSQkDQogDQokJFxsaW1fe21ccmlnaHRhcnJvdyBcaW5mdHl9IHZhcltcaGF0e1xiZXRhXzB9XSA9IHZhcltcd2lkZWhhdHtcbWF0aGNhbHtCfV8wfV0gPSBcc2lnbWFeMiBcY2RvdCBcbGVmdChcZnJhY3sxfXtufSArIFxmcmFje1xvdmVybGluZXt4fV4yfXtTX3t4eH19XHJpZ2h0KSQkDQoNCg0KIyMgVGhlIFRoaW5nIFdlIGFyZSBOb3QgQ29tcHV0aW5nDQoNCkZvciBjb252ZXJnZW5jZSBpbiBwcm9iYWJpbGl0eTogQ0RGIGNvbnZlcmdlcyB0byBhIHVuaXQgc3RlcC4gaHR0cHM6Ly93d3cueW91dHViZS5jb20vd2F0Y2g/dj11SE1WSkpIc3ltNCZsaXN0PVBMRUVGNTMyMkIzMzFDMUI5OCBhdCAyNDo0NyAoYW5kIHRoZSBuZXh0IGluIHRoZSBsaXN0KS4gaHR0cHM6Ly93d3cueW91dHViZS5jb20vd2F0Y2g/dj0wZXlEU3JLcGZ2WS4gKEphdmVkIEh1c3NhaW4pIFJpZ29yb3VzIG1hdGhlbWF0aWNhbCBkZWZpbml0aW9uLiANCg0KRnVydGhlciwgYXBwbHlpbmcgY2VudHJhbCBsaW1pdCB0aGVvcmVtLCB3ZSBvYnRhaW46DQoNCiQkXHNxcnR7bX0gXGNkb3QgXGxlZnQoXGZyYWN7XG92ZXJsaW5le1x3aWRlaGF0e1xtYXRoY2Fse0JfMH19fSAtIFxiZXRhXzBeKn17XHNpZ21hIFxjZG90IFxzcXJ0e1xmcmFjezF9e259ICsgXGZyYWN7XG92ZXJsaW5le3h9XjJ9e1Nfe3h4fX19fSBccmlnaHQpIFxzdGFja3JlbHtkfXtcbG9uZ3JpZ2h0YXJyb3d9IFxtYXRoY2Fse059KDAsMSkkJA0KJCRcc3FydHttfSBcY2RvdCBcZnJhY3tcb3ZlcmxpbmV7XHdpZGVoYXR7XG1hdGhjYWx7Ql8xfX19IC0gXGJldGFfMV4qfXtcZnJhY3tcc2lnbWF9e1xzcXJ0e1Nfe3h4fX19fSBcc3RhY2tyZWx7ZH17XGxvbmdyaWdodGFycm93fSBcbWF0aGNhbHtOfSgwLDEpJCQNClRodXMgd2UgY2FuIGNvbmNsdWRlIHRoYXQgJFxvdmVybGluZXtcd2lkZWhhdHtcbWF0aGNhbHtCX2l9fX0kIGZvbGxvdyBHYXVzc2lhbiBkaXN0cmlidXRpb24gaW4gbGltaXQ7IG5vdGljZSB0aGF0IHRoaXMgcmVzdWx0IGRpZCBub3QgaW52b2x2ZSByZXN0cmljdGlvbnMgb24gdGhlIGRpc3RyaWJ1dGlvbiBvZiAkXG1hdGhjYWx7RX0kIG9yICRZJC4gVW5kZXIgYWRkaXRpb25hbCBhc3N1bXB0aW9ucywgc3Ryb25nZXIgc3RhdGVtZW50cyBjYW4gYmUgbWFkZS4gQmVsb3cgaXMgcHJvZ3Jlc3Npb24gZnJvbSB0aGUgc3Ryb25nZXN0IHRvIHRoZSB3ZWFrZXN0IHN0YXRlbWVudDoNCg0KKiAkXHdpZGVoYXR7XG1hdGhjYWx7Qn1faX0kIGFyZSBub3JtYWxseSBkaXN0cmlidXRlZCBpZiB0aGUgbm9pc2UgaXMuDQoqICRcd2lkZWhhdHtcbWF0aGNhbHtCfV9pfSQgYXJlIG5vcm1hbGx5IGRpc3RyaWJ1dGVkIGlmICRuJCBpcyBsYXJnZSwgYmVjYXVzZSBzdW1zIGFuZCBhdmVyYWdlcyB0ZW5kIHRvIGJlIG5vcm1hbGx5IGRpc3RyaWJ1dGVkIChpcnJlc3BlY3RpdmUgb2Ygbm9pc2UgZGlzdHJpYnV0aW9uKQ0KKiAkXG92ZXJsaW5le1x3aWRlaGF0e1xtYXRoY2Fse0J9X2l9fSQgaXMgbm9ybWFsbHkgZGlzdHJpYnV0ZWQgaW4gbGltaXQgJG0gXHJpZ2h0YXJyb3cgXGluZnR5JCBpcnJlc3BlY3RpdmUgb2Ygbm9pc2UgZGlzdHJpYnV0aW9uIG9yIHNhbXBsZSBzaXplcy4NCg0KDQojIyBUaGUgRXhwZXJpbWVudCAgDQoNCiMjIyBHZW5lcmF0aXZlIE1vZGVscyBJbXBsZW1lbnRhdGlvbg0KDQpUaGUgY29kZSBjaHVuayBiZWxvdyBkZWZpbmVzIGZ1bmN0aW9ucyB0aGF0IGdlbmVyYXRlIHJhbmRvbSBzYW1wbGVzIGFuZCBjb21wdXRlIGxpbmVhciByZWdyZXNzaW9uIGNvZWZmaWNpZW50cy4gU2luY2UgbXVsdGlwbGUgZ2VuZXJhdGl2ZSBtb2RlbHMgYXJlIHN1cHBvcnRlZCBhbmQgcGFyYW1ldGVycyByZXF1aXJlZCB0byBzcGVjaWZ5IHRoZXNlIG1vZGVscyBkaWZmZXIsIHdlIHdpbGwgdXNlIFIncyBlbnZpcm9ubWVudHMgKHVzdWFsbHkgcGFzc2VkIGFzIGEgcGFyYW1ldGVyIG5hbWVkICJ2YXJhcmdzIikgaW4gb3JkZXIgdG8gaW1wbGVtZW50IHRoZSB2YXJpYWJsZSBudW1iZXIgb2YgYXJndW1lbnRzLiANCg0KYGBge3J9DQpsaWJyYXJ5KHJsYW5nKQ0KDQpTeHkgPC0gZnVuY3Rpb24oeCwgeSkgew0KICBzdW0oeCAqIHkpIC0gbWVhbih4KSAqIHN1bSh5KQ0KfQ0KDQpnYXVzc2lhbl9ub2lzZSA8LSBmdW5jdGlvbihuLCB2YXJhcmdzKSB7DQogIHN0b3BpZm5vdChlbnZfaGFzKHZhcmFyZ3MsICJub2lzZV9zZCIpKQ0KICBybm9ybShuLCBtZWFuID0gMCwgc2QgPSB2YXJhcmdzJG5vaXNlX3NkKQ0KfQ0KDQojZXhwbGFuYXRpb24gdmFyaWFibGUgZm9yIHRoZSAyLVN0ZXAgZ2VuZXJhdGl2ZSBtb2RlbA0KZXhwb25lbnRpYWxfZmVhdHVyZSA8LSBmdW5jdGlvbihuLCB2YXJhcmdzKSB7DQogIHN0b3BpZm5vdChlbnZfaGFzKHZhcmFyZ3MsICJGZWF0dXJlUGFyYW0iKSkNCiAgcmV4cChuLCB2YXJhcmdzJEZlYXR1cmVQYXJhbSkNCn0NCg0KI2V4cGxhbmF0aW9uIHZhcmlhYmxlIGZvciB0aGUgMS1TdGVwIGdlbmVyYXRpdmUgbW9kZWwNCmRldGVybWluaXN0aWNfZmVhdHVyZSA8LSBmdW5jdGlvbihuLCB2YXJhcmdzKSB7DQogIHN0b3BpZm5vdChlbnZfaGFzKHZhcmFyZ3MsICJYU291cmNlIikpDQogIHZhcmFyZ3MkWFNvdXJjZVsxOm5dDQp9DQoNCiNSZXBsaWNhdGVzIGNvbXB1dGluZyBsZWFzdCBzcXVhcmVzIGVzdGltYXRlcyBmb3IgY29lZmZpY2llbnRzIG9mIA0KI3NpbXBsZSBsaW5lYXIgcmVncmVzc2lvbiBiYXNlZCBvbiBhIG4tc2l6ZWQgc2FtcGxlIG0gdGltZXMNCnNhbXBsZV9iZXRhX2VzdGltYXRvciA8LSBmdW5jdGlvbihtLCBuLCBiZXRhMCwgYmV0YTEsIHZhcmFyZ3MpIHsNCiAgDQogIGJldGFfaGF0cyA8LSB2ZWN0b3IoKQ0KDQogIGZvciAoaSBpbiAxOm0pIHsNCiAgDQogICAgI2RhdGEgZ2VuZXJhdGlvbg0KICAgIFggPC0gdmFyYXJncyRnZW5fZmVhdHVyZShuLCB2YXJhcmdzKQ0KICAgIGVwcyA8LSB2YXJhcmdzJGdlbl9ub2lzZShuLCB2YXJhcmdzKQ0KICAgIFkgPC0gYmV0YTAgKyBiZXRhMSAqIFggKyBlcHMNCiAgICANCiAgICAjY29tcHV0aW5nIHRoZSBlc3RpbWF0b3INCiAgICBZX2JhciA8LSBtZWFuKFkpDQogICAgWF9iYXIgPC0gbWVhbihYKQ0KICAgIGJldGFfaGF0IDwtIGMoWV9iYXIgLSAoU3h5KFgsIFkpIC8gU3h5KFgsIFgpKSAqIFhfYmFyLCBTeHkoWCwgWSkgLyBTeHkoWCwgWCkpDQogICAgDQogICAgYmV0YV9oYXRzIDwtIHJiaW5kKGJldGFfaGF0cywgYmV0YV9oYXQpDQogIH0NCiAgDQogIGJldGFfaGF0cw0KfQ0KDQojQ29tcHV0ZXMgZW1waXJpY2FsIG1lYW4gYW5kIHZhcmlhbmNlIG9mIGVzdGltYXRlZCBsaW5lYXIgcmVncmVzc2lvbg0KI2NvZWZmaWNpZW50cyBhdmVyYWdlZCBvdmVyIG0gcnVucywgZWFjaCBpbnZvbHZpbmcgY2FsY3VsYXRpb24gb2YgdGhlIA0KI2xlYXN0IHNxdWFyZXMgZXN0aW1hdGVzIGZvciBhIHNhbXBsZSBvZiBzaXplIG4NCm1vbWVudHNfb2ZfYmV0YV9lc3RpbWF0b3IgPC0gZnVuY3Rpb24obSwgbiwgYmV0YTAsIGJldGExLCB2YXJhcmdzKSB7DQogIA0KICBiZXRhX2hhdHMgPC0gc2FtcGxlX2JldGFfZXN0aW1hdG9yKG0sIG4sIGJldGEwLCBiZXRhMSwgdmFyYXJncykNCg0KICAjYXZlcmFnZSBpcyBpbiBpdHNlbGYgYW4gZXN0aW1hdG9yIG9mIHRoZSBleHBlY3RhdGlvbiBvZiB0aGUgbGVhc3Qgc3F1YXJlcyBlc3RpbWF0b3IgDQogIGJldGFfaGF0X2JhciA8LSBjKCBtZWFuKGJldGFfaGF0c1ssIDFdKSwgbWVhbihiZXRhX2hhdHNbLCAyXSkgKQ0KICBiZXRhX2hhdF92YXIgPC0gYyggdmFyKGJldGFfaGF0c1ssIDFdKSwgdmFyKGJldGFfaGF0c1ssIDJdKSApDQogIA0KICBjKGJldGFfaGF0X2JhciwgYmV0YV9oYXRfdmFyKQ0KfQ0KYGBgDQoNCk5leHQgZ2xvYmFsIHBhcmFtZXRlcnMgdXNlZCBpbiBnZW5lcmF0aW5nIHRoZSBkYXRhIGFyZSBkZWZpbmVkLg0KDQpgYGB7cn0NCiNzYW1wbGUgc2l6ZSBmb3IgdGhlIGV4cGVyaW1lbnRzIHdoZXJlIGl0IHJlbWFpbnMgdW5jaGFuZ2VkDQpuX2ZpeGVkIDwtIDEwMDANCiN0aGUgbWF4aW11bSBzYW1wbGUgc2l6ZSB0aGF0IHdpbGwgZXZlciBiZSB1c2VkIA0Kbl9tYXggPC0gMTAwMDAwDQojbWluaW11bSB2YWx1ZSBmb3IgbiAobiBzaG91bGQgYmUgZ3JlYXRlciB0aGFuIDEgZm9yIFggdG8gaGF2ZSBub24temVybyB2YXJpYW5jZSkNCm5fbWluIDwtIDUNCg0KI0Rpc3RyaWJ1dGlvbiBwYXJhbWV0ZXIgZm9yIHRoZSBleHBsYW5hdG9yeSB2YXJpYWJsZSAgDQpsYW1iZGEgPC0gMg0KI1N0YW5kYXJkIGRldmlhdGlvbiBmb3IgdGhlIEdhdXNzaWFuIG5vaXNlDQpzaWdtYSA8LSAzDQojVHJ1ZSAobGF0ZW50KSB2YWx1ZXMgZm9yIHJlZ3Jlc3Npb24gY29lZmZpY2llbnRzDQpiZXRhX3N0YXIgPC0gYyg1LjUsIDIuMikNCiNEZXRlcm1pbmlzdGljIFggZm9yIHRoZSAxLVN0ZXAgbW9kZWwgKG5vdCB0cmVhdGVkIGFzIGEgcmFuZG9tIHZhcmlhYmxlKQ0KWGZ1bGwgPC0gcmV4cChuX21heCwgbGFtYmRhKSANCg0KI1RoZSBtYXhpbXVtIG51bWJlciBvZiB0aW1lcyBiZXRhIGVzdGltYXRlcyBhcmUgc2FtcGxlZCB0byBkZW1vIHRoZSBhYnNlbmNlIG9mIGJpYXM7DQojdGhpcyB2YWx1ZSBjYW5ub3QgYmUgYXMgbGFyZ2UgYXMgbl9tYXggdG8ga2VlcCB0aGUgcnVubmluZyB0aW1lIHdpdGhpbiByZWFzb25hYmxlIGxpbWl0cw0KbV9tYXhfbm9iaWFzIDwtIDE5OTk5DQoNCiNQYXJhbWV0ZXJzIGZvciB0aGUgMi1TdGVwIGdlbmVyYXRpdmUgbW9kZWwNCmVudl8yc3QgPC0gZW52KGdlbl9ub2lzZSA9IGdhdXNzaWFuX25vaXNlLCBub2lzZV9zZCA9IHNpZ21hLCBnZW5fZmVhdHVyZSA9IGV4cG9uZW50aWFsX2ZlYXR1cmUsIEZlYXR1cmVQYXJhbSA9IGxhbWJkYSkNCiNQYXJhbWV0ZXJzIGZvciB0aGUgMS1TdGVwIGdlbmVyYXRpdmUgbW9kZWwNCmVudl8xc3QgPC0gZW52KGdlbl9ub2lzZSA9IGdhdXNzaWFuX25vaXNlLCBub2lzZV9zZCA9IHNpZ21hLCBnZW5fZmVhdHVyZSA9IGRldGVybWluaXN0aWNfZmVhdHVyZSwgWFNvdXJjZSA9IFhmdWxsKQ0KYGBgDQoNCg0KIyMjIFBsb3R0aW5nOiBTZXR0aW5nIFVwIHRoZSBQYXJhbWV0ZXJzDQoNCmBgYHtyfQ0KY29sb3JfYmFzaWMgPSAiIzMzMzM5OSINCmNvbG9yX2hpZ2hsaWdodCA9ICIjRkY2NjMzIg0KbGluZV93aWR0aCA9IDINCmRvdF9zaGFwZSA9IDIxDQpgYGANCg0KDQojIyMgVmlzdWFsaXppbmcgQ29uc2lzdGVuY3kgb2YgdGhlIEVzdGltYXRvcnMgKERhdGEgQ29sbGVjdGlvbikNCg0KSGVyZSB0aGUgZGF0YSBuZWNlc3NhcnkgdG8gZGVtb25zdHJhdGUgY29uc2lzdGVuY3kgb2YgZXN0aW1hdG9ycyBmb3IgbGluZWFyIHJlZ3Jlc3Npb24gY29lZmZpY2llbnRzIGlzIGNvbGxlY3RlZC4gSW4gb3JkZXIgdG8gcmVkdWNlIHJ1bm5pbmcgdGltZSwgdGhlIHNlcXVlbmNlIG9mIHNhbXBsZSBzaXplcyB3aWxsIGJlIG5vbi1saW5lYXIgd2l0aCB0aGUgZ3JlYXRlciBkZW5zaXR5IG9mIHBvaW50cyBuZWFyIHNtYWxsICRuJHMsIHdoZXJlIHdlIGV4cGVjdCBncmVhdGVyIHZhcmlhYmlsaXR5IGluIHRoZSBlc3RpbWF0b3IncyB2YWx1ZXMuIA0KDQpgYGB7cn0NCiNDb21wdXRlcyDOsjAgYW5kIM6yMSBlc3RpbWF0ZXMgZm9yIGdyYWR1YWxseSBpbmNyZWFzaW5nIHNhbXBsZSBzaXplcyBpbiBvcmRlciB0byBzaG93IGNvbnNpc3RlbmN5IG9mIHRoZSBlc3RpbWF0b3INCmNvbGxlY3RfZGF0YV9mb3JfY29uc2lzdGVuY3lfZGVtbyA8LSBmdW5jdGlvbih2YXJhcmdzKSB7DQogIA0KICBuX3NlcSA8LSBjKHNlcSgxMDAsIDk5OSwgMTAwKSwgc2VxKDEwMDAsIG1fbWF4X25vYmlhcywgNTAwKSwgc2VxKG1fbWF4X25vYmlhcyArIDEsIG5fbWF4LCAxMDAwKSkNCg0KICBiZXRhX2hhdHMgPC0gZGF0YS5mcmFtZSgpDQogIGZvciAobiBpbiBuX3NlcSkgew0KICAgICNtID09IDEsIHRoZSBlc3RpbWF0ZXMgYXJlIGNvbXB1dGVkIG9uY2Ugb25seSBmb3IgZWFjaCBuDQogICAgYmV0YV9oYXRzIDwtIHJiaW5kKGJldGFfaGF0cywgYyhuLCBzYW1wbGVfYmV0YV9lc3RpbWF0b3IoMSwgbiwgYmV0YV9zdGFyWzFdLCBiZXRhX3N0YXJbMl0sIHZhcmFyZ3MpKSkNCiAgfQ0KICANCiAgbmFtZXMoYmV0YV9oYXRzKSA8LSBjKCJuIiwgImJldGEwIiwgImJldGExIikNCiAgDQogIGJldGFfaGF0cw0KfQ0KDQpiZXRhX2hhdHNfMnN0ZXAgPC0gY29sbGVjdF9kYXRhX2Zvcl9jb25zaXN0ZW5jeV9kZW1vKGVudl8yc3QpDQpiZXRhX2hhdHNfMXN0ZXAgPC0gY29sbGVjdF9kYXRhX2Zvcl9jb25zaXN0ZW5jeV9kZW1vKGVudl8xc3QpDQpgYGANCg0KDQojIyMgVmlzdWFsaXppbmcgQ29uc2lzdGVuY3kgb2YgdGhlIEVzdGltYXRvcnMgKFBsb3R0aW5nKQ0KDQpgYGB7ciBmaWcuYWxpZ249ImNlbnRlciIsIGVjaG8gPSBGQUxTRSwgZmlnLndpZHRoID0gOH0NCiNQbG90cyBleHBlY3RhdGlvbnMgKHRoZW9yZXRpY2FsIG1lYW5zKSBvZiBMUyBlc3RpbWF0b3JzIGZvciDOsjAgYW5kIM6yMSAoaW4gb3JhbmdlKQ0KI2Fsb25nIHdpdGggb2JzZXJ2ZWQgKHJhbmRvbSEpIGVzdGltYXRlZCB2YWx1ZXMgYWdhaW5zdCBzYW1wbGUgc2l6ZQ0KZGVtb19jb25zaXN0ZW5jeSA8LSBmdW5jdGlvbihiaHMsIHN0ZXBzLCBiZXRhX2lkeCkgew0KICANCiAgc2lkeCA8LSBwYXN0ZTAoImJldGEiLCBiZXRhX2lkeCkNCiAgYWxsX2RhdGEgPC0gYyhiaHNbWzFdXVssIHNpZHhdLCBiaHNbWzJdXVssIHNpZHhdKQ0KICANCiAgcGxvdChiaHNbW3N0ZXBzXV1bLCJuIl0sIGJoc1tbc3RlcHNdXVssIHNpZHhdLCANCiAgICAgICBiZyA9IGNvbG9yX2Jhc2ljLCBwY2ggPSBkb3Rfc2hhcGUsDQogICAgICAgeWxpbSA9IGMobWluKGFsbF9kYXRhKSwgbWF4KGFsbF9kYXRhKSksDQogICAgICAgeGxhYiA9ICJuIiwgeWxhYiA9IHBhc3RlMCgiRXN0aW1hdGVkIGJldGEiLCBiZXRhX2lkeCksIA0KICAgICAgIG1haW4gPSBwYXN0ZTAoc3RlcHMsICItU3RlcCBHZW5lcmF0aXZlIE1vb2RlbCIpKQ0KICANCiAgbGluZXMoYmhzW1tzdGVwc11dWywibiJdLCByZXAoYmV0YV9zdGFyW2JldGFfaWR4ICsgMV0sIGRpbShiaHNbW3N0ZXBzXV0pW1sxXV0pLCANCiAgICAgICAgY29sID0gY29sb3JfaGlnaGxpZ2h0LCBsd2QgPSBsaW5lX3dpZHRoKQ0KfQ0KDQpiaHMgPC0gbGlzdChiZXRhX2hhdHNfMXN0ZXAsIGJldGFfaGF0c18yc3RlcCkNCnBhcihtZmNvbCA9IGMoMiwgMikpDQpkZW1vX2NvbnNpc3RlbmN5KGJocywgMiwgMCkNCmRlbW9fY29uc2lzdGVuY3koYmhzLCAyLCAxKQ0KZGVtb19jb25zaXN0ZW5jeShiaHMsIDEsIDApDQpkZW1vX2NvbnNpc3RlbmN5KGJocywgMSwgMSkNCmBgYA0KDQoNCiMjIFZpc3VhbGl6aW5nIFVuYmlhc2VkbmVzcyBvZiB0aGUgRXN0aW1hdG9ycyAoRGF0YSBDb2xsZWN0aW9uKQ0KDQpUaGlzIHRpbWUgdGhlIHNhbXBsZSBzaXplIGlzIGtlcHQgZml4ZWQgYXQgbl9maXhlZCBhbmQgdGhlIHNhbXBsaW5nIHByb2NlZHVyZSBpcyByZXBlYXRlZCAkbSQgdGltZXMuIEZvciBlYWNoIHNhbXBsZSwgd2UgY29tcHV0ZSB0aGUgTFMgZXN0aW1hdG9ycyBhcyBzdGF0aXN0aWNzIG9mIHRoYXQgc2FtcGxlIGFuZCB0aGVuIGF2ZXJhZ2UgdGhlIGVzdGltYXRlZCB2YWx1ZXMgb3ZlciAkbSQgZXhwZXJpbWVudHMgdGhlcmVieSBvYnRhaW5pbmcgdGhlIGVzdGltYXRvcnMnIGVtcGlyaWNhbCBtZWFucyBhbmQgdmFyaWFuY2VzLiBBcyBiZWZvcmUsIGEgbm9uLWxpbmVhciBzZXF1ZW5jZSBvZiAkbSQgaXMgdXNlZCwgYnV0IGluIG9yZGVyIHRvIGtlZXAgdGhlIHJ1bm5pbmcgdGltZSB3aXRoaW4gcmVhc29uYWJsZSBsaW1pdHMgd2UgaGF2ZSB0byBsaW1pdCB0aGUgbnVtYmVyIG9mIGV4cGVyaW1lbnRzLiANCg0KYGBge3J9DQojQ29tcHV0ZXMgc2FtcGxlIG1lYW4gYW5kIHZhcmlhbmNlIGZvciBhIHNlcXVlbmNlIG9mIG0tc2l6ZWQgc2FtcGxlcyBvZiBlc3RpbWF0ZWQgzrIwIGFuZCDOsjEsIA0KI2VhY2gsIGluIHR1cm4sIGNvbXB1dGVkIGJhc2VkIG9uIGEgbl9maXhlZC1zaXplZCBzYW1wbGUgb2YgWCBhbmQgWS4gDQpjb2xsZWN0X2RhdGFfZm9yX2JpYXNfZGVtbyA8LSBmdW5jdGlvbih2YXJhcmdzKSB7DQogIA0KICBtX3NlcSA8LSBjKHNlcSgxMDAsIDk5OSwgMTAwKSwgc2VxKDEwMDAsIG1fbWF4X25vYmlhcywgNTAwKSkNCg0KICBiZXRhX2hhdF9tZWFucyA8LSBkYXRhLmZyYW1lKCkNCiAgZm9yIChtIGluIG1fc2VxKSB7DQogICAgYmV0YV9oYXRfbWVhbnMgPC0gcmJpbmQoYmV0YV9oYXRfbWVhbnMsIA0KICAgICAgICBjKG0sIG1vbWVudHNfb2ZfYmV0YV9lc3RpbWF0b3IobSwgbl9maXhlZCwgYmV0YV9zdGFyWzFdLCBiZXRhX3N0YXJbMl0sIHZhcmFyZ3MpKSkNCiAgfQ0KICANCiAgbmFtZXMoYmV0YV9oYXRfbWVhbnMpIDwtIGMoIm0iLCAibWVhbl9iZXRhMCIsICJtZWFuX2JldGExIiwgInZhcl9iZXRhMCIsICJ2YXJfYmV0YTEiKQ0KICANCiAgYmV0YV9oYXRfbWVhbnMNCn0NCg0KYmV0YV9oYXRfbWVhbnNfMnN0ZXAgPC0gY29sbGVjdF9kYXRhX2Zvcl9iaWFzX2RlbW8oZW52XzJzdCkNCmJldGFfaGF0X21lYW5zXzFzdGVwIDwtIGNvbGxlY3RfZGF0YV9mb3JfYmlhc19kZW1vKGVudl8xc3QpDQpgYGANCg0KDQojIyBWaXN1YWxpemluZyBVbmJpYXNlZG5lc3Mgb2YgdGhlIEVzdGltYXRvcnMgKFBsb3R0aW5nIHRoZSBNZWFucykNCg0KQnkgdGhlIGxhdyBvZiBsYXJnZSBudW1iZXJzLCBhdmVyYWdlIGFuZCBzYW1wbGUgdmFyaWFuY2Ugb2YgYSByYW5kb20gdmFyaWFibGUgc2hvdWxkIGdvIHRvIGl0cyBleHBlY3RhdGlvbiBhbmQgcG9wdWxhdGlvbiB2YXJpYW5jZSByZXNwZWN0aXZlbHkgYXMgdGhlIHNhbXBsZSBzaXplIGdvZXMgdG8gaW5maW5pdHkuIE1vcmVvdmVyLCBleHBlY3RhdGlvbnMgb2YgdGhlIExTIGVzdGltYXRvcnMgaGF2ZSBiZWVuIHNob3duIHRvIGJlIHRoZSB0cnVlIHZhbHVlcyBvZiB0aGUgY29lZmZpY2llbnRzIGluIHRoZSB1bmRlcmx5aW5nIGFmZmluZSByZWxhdGlvbiwgdGhlcmVmb3JlLCBhcyAkbSQgaW5jcmVhc2VzLCB3ZSBzaG91bGQgb2JzZXJ2ZSBhdmVyYWdlIGVzdGltYXRlZCB2YWx1ZXMgZm9yIGEgY29lZmZpY2llbnQgY29uY2VudHJhdGUgYXJvdW5kIGl0cyB0cnVlIHZhbHVlLg0KDQpgYGB7ciBmaWcuYWxpZ249ImNlbnRlciIsIGVjaG8gPSBUUlVFLCBmaWcud2lkdGggPSA4fQ0KDQpkZW1vX2Fic2Vuc2Vfb2ZfYmlhcyA8LSBmdW5jdGlvbihiaHMsIHN0ZXBzLCBiZXRhX2lkeCkgew0KICANCiAgc2lkeCA8LSBwYXN0ZTAoIm1lYW5fYmV0YSIsIGJldGFfaWR4KQ0KICBhbGxfZGF0YSA8LSBjKGJoc1tbMV1dWywgc2lkeF0sIGJoc1tbMl1dWywgc2lkeF0pDQogIA0KICBwbG90KGJoc1tbc3RlcHNdXVssIm0iXSwgYmhzW1tzdGVwc11dWywgc2lkeF0sIA0KICAgICAgIGJnID0gY29sb3JfYmFzaWMsIHBjaCA9IGRvdF9zaGFwZSwNCiAgICAgICB5bGltID0gYyhtaW4oYWxsX2RhdGEpLCBtYXgoYWxsX2RhdGEpKSwNCiAgICAgICB4bGFiID0gIm0iLCB5bGFiID0gcGFzdGUwKCJNZWFuIEVzdGltYXRlZCBiZXRhIiwgYmV0YV9pZHgpLCANCiAgICAgICBtYWluID0gcGFzdGUwKHN0ZXBzLCAiLVN0ZXAgR2VuZXJhdGl2ZSBNb2RlbCIpKQ0KICANCiAgbGluZXMoYmhzW1tzdGVwc11dWywibSJdLCByZXAoYmV0YV9zdGFyW2JldGFfaWR4ICsgMV0sIGRpbShiaHNbW3N0ZXBzXV0pWzFdKSwgDQogICAgICAgIGNvbCA9IGNvbG9yX2hpZ2hsaWdodCwgbHdkID0gbGluZV93aWR0aCkNCn0NCg0KDQpwYXIobWZjb2wgPSBjKDIsIDIpKQ0KDQpiaHMgPC0gbGlzdChiZXRhX2hhdF9tZWFuc18xc3RlcCwgYmV0YV9oYXRfbWVhbnNfMnN0ZXApDQpkZW1vX2Fic2Vuc2Vfb2ZfYmlhcyhiaHMsIDIsIDApDQpkZW1vX2Fic2Vuc2Vfb2ZfYmlhcyhiaHMsIDIsIDEpDQpkZW1vX2Fic2Vuc2Vfb2ZfYmlhcyhiaHMsIDEsIDApDQpkZW1vX2Fic2Vuc2Vfb2ZfYmlhcyhiaHMsIDEsIDEpDQpgYGANCg0KDQojIyMgVmFyaWFuZSBvZiB0aGUgRXN0aW1hdG9yIGFzIGEgUmFuZG9tIFZhcmlhYmxlDQoNCmBgYHtyfQ0KdmFyX2JldGFfMCA8LSBmdW5jdGlvbihub2lzZV9zZCwgeCkgew0KICBub2lzZV9zZF4yICogKDEvbGVuZ3RoKHgpICsgKG1lYW4oeCleMikvU3h5KHgsIHgpKQ0KfQ0KDQp2YXJfYmV0YV8xIDwtIGZ1bmN0aW9uKG5vaXNlX3NkLCB4KSB7DQogIG5vaXNlX3NkXjIgLyBTeHkoeCwgeCkNCn0NCmBgYA0KDQoNCiMjIyBPbiBDb252ZXJnZW5jZSBSYXRlcw0KDQpUaGlzIHNlY3Rpb24sIHJhdGhlciB0aGFuIGJlaW5nIGVzc2VudGlhbCB0byB0aGUgYW5hbHlzaXMgb2YgdGhlIGV4cGVyaW1lbnRhbCByZXN1bHRzLCBpcyBtb3JlIG9mIGEgY3VyaW9zaXR5IGFuZCwgYXMgc3VjaCwgaXQgY2FuIGJlIHNhZmVseSBza2lwcGVkLiAqKkl0IHNlZW1zIGxpa2UgYW4gZXhlcmNpc2UgaW4gY29tcGFyaW5nIG9yYW5nZXMgYW5kIGFwcGxlcyoqLg0KDQpDb21wYXJpbmcgdGhlIGNvbnZlcmdlbmNlIHBsb3RzIGlsbHVzdHJhdGluZyB0aGUgY29uc2lzdGVuY3kgYW5kIHVuYmlhc2VkbmVzcyBwcm9wZXJ0aWVzIG9mIHRoZSBMUyBlc3RpbWF0b3JzLCBvbmUgbWF5IGZhbHNlbHkgY29uY2x1ZGUgdGhhdCBpbiB0aGUgY2FzZSBvZiB0aGUgY29uc2lzdGVuY3ksIHRoZSBvYnNlcnZlZCB2YWx1ZXMgY29udmVyZ2UgdG8gdGhlIHRydWUgb25lcyBmYXN0ZXIuIEhvd2V2ZXIsIGl0IGlzIG9ubHkgYW4gaWxsdXNpb24gY3JlYXRlZCBieSB0aGUgZGlmZmVyZW5jZSBpbiB0aGUgcmVzdHJpY3Rpb24gd2UgaGF2ZSBwdXQgb24gdGhlIG1heGltdW0gdmFsdWVzIG9mIG4gYW5kIG0gYW5kIHJlc3VsdGluZyBkaWZmZXJlbmNlIGluIHNjYWxlLg0KDQpJbiBvcmRlciB0byBlc3RpbWF0ZSB0aGUgYWN0dWFsIGNvbnZlcmdlbmNlIHJhdGVzLCB3ZSBjb21iaW5lIGRhdGEgcG9pbnRzIGZvciB0aGUgc2FtZSB2YWx1ZXMgb2YgbiBhbmQgbSBvbiBhIHNpbmdsZSBmaWd1cmUuIEluIHBhcnRpY3VsYXIsIGFuIGFic29sdXRlIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgZXN0aW1hdGVkIGFuZCB0cnVlIHZhbHVlIG9mIHRoZSBjb2VmZmljaWVudCAkXGJldGFfMSQgaW4gdGhlIDEtU3RlcCBtb2RlbCB3aWxsIGJlIHBsb3R0ZWQuIEl0IG1heSBhbHNvIGJlIGhlbHBmdWwgdG8gY29uc2lkZXIgdGhlIGRpZmZlcmVuY2UgaW4gdmFyaWFuY2VzIG9mIHRoZSBlc3RpbWF0ZWQgdmFsdWVzICRcaGF0e1xiZXRhXzF9JCBhbmQgdGhlIHNhbWUsIGF2ZXJhZ2VkIG92ZXIgbSBzYW1wbGVzLCB3aGlsZSBrZWVwaW5nIGluIG1pbmQgdGhhdCBzbWFsbGVyIHZhcmlhbmNlcyB0cmFuc2xhdGUgaW50byBmYXN0ZXIgY29udmVyZ2VuY2UgcmF0ZXMuICANCg0KDQpgYGB7ciBmaWcud2lkdGggPSA2LCBmaWcuaGVpZ2h0ID0gN30NCnBhcihtZmNvbCA9IGMoMiwgMSkpDQoNCmxpbV9uID0gZGltKGJldGFfaGF0X21lYW5zXzFzdGVwKVsxXQ0KDQphbGxfZGF0YSA8LSBjKGFicyhiZXRhX2hhdF9tZWFuc18xc3RlcCRtZWFuX2JldGExWzE6bGltX25dIC0gcmVwKGJldGFfc3RhclsyXSwgbGltX24pKSwgDQogICAgICAgICAgICAgIGFicyhiZXRhX2hhdHNfMXN0ZXAkYmV0YTFbMTpsaW1fbl0gLSByZXAoYmV0YV9zdGFyWzJdLCBsaW1fbikpKQ0KDQpwbG90KGJldGFfaGF0X21lYW5zXzFzdGVwJG1bMTpsaW1fbl0sIA0KICAgICBhYnMoYmV0YV9oYXRfbWVhbnNfMXN0ZXAkbWVhbl9iZXRhMVsxOmxpbV9uXSAtIHJlcChiZXRhX3N0YXJbMl0sIGxpbV9uKSksIA0KICAgICB5bGltID0gYyhtaW4oYWxsX2RhdGEpLCBtYXgoYWxsX2RhdGEpKSwgYmcgPSBjb2xvcl9iYXNpYywgcGNoID0gZG90X3NoYXBlLCANCiAgICAgeGxhYiA9ICJzYW1wbGUgc2l6ZSIsIA0KICAgICB5bGFiID0gInxlc3RpbWF0ZWQgYmV0YTEgLSBiZXRhMSp8IiwgbWFpbiA9ICJDb252ZXJnZW5jZSBSYXRlcyBmb3IgdGhlIDEtU3RlcCBHZW5lcmF0aXZlIE1vZGVsIikNCg0KcG9pbnRzKGJldGFfaGF0c18xc3RlcCRuWzE6bGltX25dLCANCiAgICAgIGFicyhiZXRhX2hhdHNfMXN0ZXAkYmV0YTFbMTpsaW1fbl0gLSByZXAoYmV0YV9zdGFyWzJdLCBsaW1fbikpLA0KICAgICAgYmcgPSBjb2xvcl9oaWdobGlnaHQsICBwY2ggPSBkb3Rfc2hhcGUpDQoNCmxlZ2VuZCh4ID0gInRvcHJpZ2h0IiwgbGVnZW5kID0gYygibWVhbiBiZXRhMSBlc3RpbWF0ZSAoZnJvbSBiaWFzIGNoZWNrKSIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJiZXRhMSBldGltYXRlIChmcm9tIGNvbnNpc3RlbmN5IGNoZWNrKSIpLCANCiAgICAgICBwY2ggPSAyMCwgY29sID0gYyhjb2xvcl9iYXNpYywgY29sb3JfaGlnaGxpZ2h0KSkNCg0KdmFyc19jb25zIDwtIHZlY3RvcigpDQp2YXJzX2JpYXMgPC0gdmVjdG9yKCkNCmZpcnN0X24gPC0gbl9taW4gI3NraXAgdGhlIGZpcnN0IGZldyBleHRyYSBsYXJnZSB2YXJpYW5jZXMgdG8gb2J0YWluIGEgYmV0dGVyIHNjYWxlZCBwbG90DQpmb3IgKG51bSBpbiBmaXJzdF9uOmxpbV9uKSB7DQogIHZhcnNfY29ucyA8LSBjKHZhcnNfY29ucywgdmFyX2JldGFfMShzaWdtYSwgWGZ1bGxbMTpiZXRhX2hhdHNfMXN0ZXAkbltudW1dXSkpDQogIHZhcnNfYmlhcyA8LSBjKHZhcnNfYmlhcywgdmFyX2JldGFfMShzaWdtYSwgWGZ1bGxbMTpuX2ZpeGVkXSkgLyBiZXRhX2hhdF9tZWFuc18xc3RlcCRtW251bV0pDQp9DQoNCnBsb3QoYmV0YV9oYXRzXzFzdGVwJG5bZmlyc3RfbjpsaW1fbl0sIHZhcnNfY29ucywgdHlwZSA9ICJsIiwgDQogICAgIGNvbCA9IGNvbG9yX2hpZ2hsaWdodCwgbHdkID0gbGluZV93aWR0aCwgDQogICAgIHhsYWIgPSAic2FtcGxlIHNpemUiLCB5bGFiID0gIlZhcmlhbmNlIikNCmxpbmVzKGJldGFfaGF0c18xc3RlcCRuW2ZpcnN0X246bGltX25dLCB2YXJzX2JpYXMsIGNvbCA9IGNvbG9yX2Jhc2ljLCBsd2QgPSBsaW5lX3dpZHRoKQ0KDQpsZWdlbmQoeCA9ICJ0b3ByaWdodCIsIGxlZ2VuZCA9IGMoInZhcmlhbmNlIG9mIG1lYW4gYmV0YTEgZXN0aW1hdGVzIChmcm9tIGJpYXMgY2hlY2spIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInZhcmlhbmNlIG9mIGJldGExIGV0aW1hdGVzIChmcm9tIGNvbnNpc3RlbmN5IGNoZWNrKSIpLCANCiAgICAgICBwY2ggPSAyMCwgY29sID0gYyhjb2xvcl9iYXNpYywgY29sb3JfaGlnaGxpZ2h0KSkNCmBgYA0KDQoNCiMjIyBWaXN1YWxpemluZyB0aGUgTExOIFJlc3VsdHMgZm9yIFZhcmlhbmNlcw0KDQpTaW1pbGFyIHRvIHRoZSBtZWFucywgc2FtcGxlIHZhcmlhbmNlcyBvZiB0aGUgZXN0aW1hdG9ycyBnbyB0byB0aGUgcmVzcGVjdGl2ZSBwb3B1bGF0aW9uIHZhcmlhbmNlcyBhcyB0aGUgbnVtYmVyIG9mIHJ1bnMgKG0pIGluY3JlYXNlcy4gQXBhcnQgZnJvbSB0aGUgZmFjdCB0aGF0IHdlIGRlcml2ZWQgZXhwcmVzc2lvbnMgZm9yIHBvcHVsYXRpb24gdmFyaWFuY2VzIGluIHRoZSBzZXR0aW5nIG9mIHRoZSAxLVN0ZXAgTW9kZWwgb25seSwgdGhlIHBsb3RzIGFyZSBjb25zdHJ1Y3RlZCBzaW1pbGFyIHRvIHRoZSBvbmVzIGZvciBtZWFucy4NCg0KYGBge3IgZmlnLmFsaWduPSJjZW50ZXIiLCBlY2hvID0gVFJVRSwgZmlnLndpZHRoID0gOH0NCg0KcGFyKG1mY29sID0gYygyLCAyKSkNCg0KI0VtcGlyaWNhbCBiZXRhIHZhcmlhbmNlIGZvciB0aGUgMi1TdGVwIE1vZGVsIChwb3B1bGF0aW9uIHZhcmlhbmNlIGlzIG91dHNpZGUgdGhlIHNjb3BlIG9mIHRoaXMgd29yaykgDQpwbG90KGJldGFfaGF0X21lYW5zXzJzdGVwJG0sIGJldGFfaGF0X21lYW5zXzJzdGVwJHZhcl9iZXRhMCwgYmcgPSBjb2xvcl9iYXNpYywgcGNoID0gZG90X3NoYXBlLCANCiAgICAgeGxhYiA9ICJtIiwgeWxhYiA9ICJWYXJpYW5jZSBvZiBFc3RpbWF0ZWQgYmV0YTAiLCBtYWluID0gIjItU3RlcCBHZW5lcmF0aXZlIE1vZGVsIikNCnBsb3QoYmV0YV9oYXRfbWVhbnNfMnN0ZXAkbSwgYmV0YV9oYXRfbWVhbnNfMnN0ZXAkdmFyX2JldGExLCBiZyA9IGNvbG9yX2Jhc2ljLCBwY2ggPSBkb3Rfc2hhcGUsIA0KICAgICB4bGFiID0gIm0iLCB5bGFiID0gIlZhcmlhbmNlIG9mIEVzdGltYXRlZCBiZXRhMSIsIG1haW4gPSAiMi1TdGVwIEdlbmVyYXRpdmUgTW9kZWwiKQ0KDQojU2FtcGxlIGFuZCBwb3B1bGF0aW9uIGJldGEgdmFyaWFuY2VzIGZvciB0aGUgMi1TdGVwIE1vZGVsDQpwbG90KGJldGFfaGF0X21lYW5zXzFzdGVwJG0sIGJldGFfaGF0X21lYW5zXzFzdGVwJHZhcl9iZXRhMCwgYmcgPSBjb2xvcl9iYXNpYywgcGNoID0gZG90X3NoYXBlLCANCiAgICAgeGxhYiA9ICJtIiwgeWxhYiA9ICJWYXJpYW5jZSBvZiBFc3RpbWF0ZWQgYmV0YTAiLCBtYWluID0gIjEtU3RlcCBHZW5lcmF0aXZlIE1vZGVsIikNCmxpbmVzKGJldGFfaGF0X21lYW5zXzFzdGVwJG0sIHJlcCh2YXJfYmV0YV8wKHNpZ21hLCBYZnVsbFsxOm5fZml4ZWRdKSwgZGltKGJldGFfaGF0X21lYW5zXzFzdGVwKVsxXSksIA0KICAgICAgY29sID0gY29sb3JfaGlnaGxpZ2h0LCBsd2QgPSBsaW5lX3dpZHRoKQ0KDQpwbG90KGJldGFfaGF0X21lYW5zXzFzdGVwJG0sIGJldGFfaGF0X21lYW5zXzFzdGVwJHZhcl9iZXRhMSwgYmcgPSBjb2xvcl9iYXNpYywgcGNoID0gZG90X3NoYXBlLCANCiAgICAgeGxhYiA9ICJtIiwgeWxhYiA9ICJWYXJpYW5jZSBvZiBFc3RpbWF0ZWQgYmV0YTEiLCBtYWluID0gIjEtU3RlcCBHZW5lcmF0aXZlIE1vZGVsIikNCmxpbmVzKGJldGFfaGF0X21lYW5zXzFzdGVwJG0sIHJlcCh2YXJfYmV0YV8xKHNpZ21hLCBYZnVsbFsxOm5fZml4ZWRdKSwgZGltKGJldGFfaGF0X21lYW5zXzFzdGVwKVsxXSksIA0KICAgICAgY29sID0gY29sb3JfaGlnaGxpZ2h0LCBsd2QgPSBsaW5lX3dpZHRoKQ0KYGBgDQoNCg0KIyMjIERpc3RyaWJ1dGlvbiBvZiB0aGUgRXN0aW1hdGVkIFZhbHVlcw0KDQpJbiB0aGUgc2V0dGluZyBvZiB0aGUgMS1TdGVwIE1vZGVsLCB0aGUgZXN0aW1hdGVkIHZhbHVlcyBmb3IgdGhlIGhpZGRlbiBwYXJhbWV0ZXJzICRcYmV0YV8wXiokIGFuZCAkXGJldGFfMV4qJCBhcmUga25vd24gdG8gYmUgbm9ybWFsbHkgZGlzdHJpYnV0ZWQgd2l0aCB0aGUgbWVhbnMgZXF1YWwgdG8gJFxiZXRhXzBeKiQgYW5kICRcYmV0YV8xXiokIHJlc3BlY3RpdmVseSBhbmQgdmFyaWFuY2VzIGRlcGVuZGVudCBvbiAkWCQgYW5kIHN0YW5kYXJkIGRldmlhdGlvbiBvZiBub2lzZS4gDQoNCkFzIGJlZm9yZSwgdGhlIHNhbXBsaW5nIHByb2NlZHVyZSBpcyByZXBlYXRlZCAkbSQgdGltZXMgd2l0aCB0aGUga2V5IGRpZmZlcmVuY2UgYmVpbmcgdGhhdCAkbSQgcmVtYWlucyBmaXhlZCByYXRoZXIgdGhhbiBhbiBpbmNyZWFzaW5nIHNlcXVlbmNlIG9mIHZhbHVlczsgdGhlIGVzdGltYXRlZCB2YWx1ZXMgYXJlIGNvbGxlY3RlZCBpbiB0aGUgcHJvY2VzcyByZXN1bHRpbmcgaW4gJG0kIHZhbHVlcyBvZiAkXGhhdHtcYmV0YV8wfSQgYW5kICRcaGF0e1xiZXRhXzF9JCBlYWNoIChubyBhdmVyYWdlcyBhcmUgY29tcHV0ZWQpLiBUaGVuIHdlIGNvbnN0cnVjdCBoaXN0b2dyYW1zIG9mIHRoZSBlc3RpbWF0ZWQgdmFsdWVzIGFuZCBzZWUgaG93IHdlbGwgdGhleSBtYXRjaCB0aGUgdGhlb3JldGljYWwgUERGcy4NCg0KYGBge3J9DQptIDwtIDEwMDAwDQpoaXN0X2JpbnMgPC0gNTANCg0KI2NvbXB1dGVzIGEgbm9ybWFsIFBERiB3aXRoIG1lYW4gbXUgYW5kIHN0YW5kYXJkIGRldmlhdGlvbiBzZyANCiNsaW1pdGVkIHRvIHRoZSB2YWx1ZXMgaW4gdGhlIHZlY3RvciB4IA0Kbm9ybWFsX2N1cnZlIDwtIGZ1bmN0aW9uKHgsIG11LCBzZykgew0KICANCiAgeGQgPC0gc2VxKG1pbih4KSwgbWF4KHgpLCAwLjAxKQ0KICB5ZCA8LSBkbm9ybSh4ZCwgbWVhbiA9IG11LCBzZCA9IHNnKQ0KICBjYmluZCh4ZCwgeWQpDQp9DQoNCiNjb2xsZWN0aW5nIGRhdGEgZm9yIHRoZSAyLXN0ZXAgbW9kZWwgDQpiZXRhX2hhdHNfMnN0ZXBfaCA8LSBzYW1wbGVfYmV0YV9lc3RpbWF0b3IobSwgbl9maXhlZCwgYmV0YV9zdGFyWzFdLCBiZXRhX3N0YXJbMl0sIGVudl8yc3QpDQoNCiNjb2xsZWN0aW5nIGRhdGEgZm9yIHRoZSAxLXN0ZXAgbW9kZWwNCmJldGFfaGF0c18xc3RlcF9oIDwtIHNhbXBsZV9iZXRhX2VzdGltYXRvcihtLCBuX2ZpeGVkLCBiZXRhX3N0YXJbMV0sIGJldGFfc3RhclsyXSwgZW52XzFzdCkNCiNjb21wdXRpbmcgdGhlb3JldGljYWwgYmV0YSBQREZzIGZvciB0aGUgMS1zdGVwIG1vZGVsDQpiZXRhMF9wZGYgPC0gbm9ybWFsX2N1cnZlKGJldGFfaGF0c18xc3RlcF9oWywxXSwgYmV0YV9zdGFyWzFdLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNxcnQodmFyX2JldGFfMChzaWdtYSwgWGZ1bGxbMTpuX2ZpeGVkXSkpKQ0KYmV0YTFfcGRmIDwtIG5vcm1hbF9jdXJ2ZShiZXRhX2hhdHNfMXN0ZXBfaFssMl0sIGJldGFfc3RhclsyXSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzcXJ0KHZhcl9iZXRhXzEoc2lnbWEsIFhmdWxsWzE6bl9maXhlZF0pKSkNCg0KcGFyKG1mY29sID0gYygyLCAyKSkNCg0KIzItU3RlcCBNb2RlbCAobm8gdGhlb3JldGljYWwgcmVzdWx0cyBjb25jZXJuaW5nIHRoZSB1bmRlcmx5aW5nIGRpc3RyaWJ1dGlvbiBpbiB0aGlzIHdvcmspDQpoaXN0KGJldGFfaGF0c18yc3RlcF9oWywxXSwgYnJlYWtzID0gaGlzdF9iaW5zLCBmcmVxID0gRkFMU0UsIA0KICAgICBtYWluID0gIjItU3RlcCBHZW5lcmF0aXZlIE1vZGVsIiwgeGxhYiA9ICJiZXRhMCIsIGNvbCA9IGNvbG9yX2Jhc2ljKQ0KDQpoaXN0KGJldGFfaGF0c18yc3RlcF9oWywyXSwgYnJlYWtzID0gaGlzdF9iaW5zLCBmcmVxID0gRkFMU0UsIA0KICAgICBtYWluID0gIjItU3RlcCBHZW5lcmF0aXZlIE1vZGVsIiwgeGxhYiA9ICJiZXRhMSIsIGNvbCA9IGNvbG9yX2Jhc2ljKQ0KDQojMS1TdGVwIE1vZGVsDQpoaXN0KGJldGFfaGF0c18xc3RlcF9oWywxXSwgYnJlYWtzID0gaGlzdF9iaW5zLCBmcmVxID0gRkFMU0UsIA0KICAgICBtYWluID0gIjEtU3RlcCBHZW5lcmF0aXZlIE1vZGVsIiwgeGxhYiA9ICJiZXRhMCIsIGNvbCA9IGNvbG9yX2Jhc2ljKQ0KbGluZXMoYmV0YTBfcGRmWywxXSwgYmV0YTBfcGRmWywyXSwgbHdkID0gbGluZV93aWR0aCwgY29sID0gY29sb3JfaGlnaGxpZ2h0KQ0KDQpoaXN0KGJldGFfaGF0c18xc3RlcF9oWywyXSwgYnJlYWtzID0gaGlzdF9iaW5zLCBmcmVxID0gRkFMU0UsIA0KICAgICBtYWluID0gIjEtU3RlcCBHZW5lcmF0aXZlIE1vZGVsIiwgeGxhYiA9ICJiZXRhMSIsIGNvbCA9IGNvbG9yX2Jhc2ljKQ0KbGluZXMoYmV0YTFfcGRmWywxXSwgYmV0YTFfcGRmWywyXSwgbHdkID0gbGluZV93aWR0aCwgY29sID0gY29sb3JfaGlnaGxpZ2h0KQ0KYGBgDQoNCg0KIyMjIERpc3RyaWJ1dGlvbiBvZiB0aGUgRXN0aW1hdG9yJ3MgTWVhbnMgKERhdGEgQ29sbGVjYXRpb24pDQoNCk5vdCBvbmx5IGRvIHdlIGtub3cgaG93IHRoZSBlc3RpbWF0ZWQgYmV0YSB2YWx1ZXMgYXJlIGRpc3RyaWJ1dGVkLCDRgWVudHJhbCBsaW1pdCB0aGVvcmVtIGFsc28gZ2l2ZXMgdXMgdGhlIGluZm9ybWF0aW9uIGNvbmNlcm5pbmcgZGlzdHJpYnV0aW9uIG9mIG1lYW4gdmFsdWVzIG9mIHRoZSBlc3RpbWF0b3JzIChpbiB0aGUgbGltaXQpLiBMZXQgdXMgY29uc3RydWN0IGhpc3RvZ3JhbXMgZm9yIHZhcmlvdXMgdmFsdWVzIG9mICRtJCBpbiBvcmRlciB0byBzZWUgaWYgdGhlIGRpc3RyaWJ1dGlvbiBvZiAkXHNxcnR7bX0gXGNkb3QgKFxvdmVybGluZXtcd2lkZWhhdHtcbWF0aGNhbHtCX2l9fX0gLSBcYmV0YV9pXiopIC8gdmFyW1x3aWRlaGF0e1xtYXRoY2Fse0JfaX19XSQsIGluZGVlZCwgYXBwcm9hY2hlcyBzdGFuZGFyZCBub3JtYWwuIEluIG9yZGVyIHRvIGFjaGlldmUgdGhpcywgd2UgbXVzdCB3cmFwIG91ciBkYXRhIGNvbGxlY3Rpb24gcHJvY2VkdXJlIGluIGFub3RoZXIgbG9vcCwgdGhpcyB0aW1lIG92ZXIgJGskLg0KDQpUaGUgZGVtb25zdHJhdGlvbiB3aWxsIGJlIGxpbWl0ZWQgdG8gdGhlIDEtc3RlcCBnZW5lcmF0aXZlIG1vZGVsLg0KDQpgYGB7cn0NCmtfbWF4IDwtIDIwMDANCm1fc2VxIDwtIGMoMSwgMTAsIDEwMDApDQoNCiNDb2xsZWN0cyBrIHNhbXBsZXMgb2YgbWVhbiBlc3RpbWF0ZWQgdmFsdWVzIGZvciB0aGUgbGluZWFyIHJlZ3Jlc3Npb24gY29lZmZpY2llbnRzDQojYWxvbmcgd2l0aCByZXNwZWN0aXZlIHNhbXBsZSB2YXJpYW5jZXMuDQojRWFjaCBlc3RpbWF0ZWQgdmFsdWUgaXMgY29tcHV0ZWQgZm9yIGEgbi1zaXplZCBzYW1wbGUgb2YgWCBhbmQgWTsgdGhlbiBhbiBhdmVyYWdlDQojYW5kIHNhbXBsZSB2YXJpYW5jZSBhcmUgY2FsY3VsYXRlZCBvdmVyIG0gc3VjaCB2YWx1ZXMuDQpyZXBsaWNhdGVfYXZlcmFnZV9lc3RpbWF0b3IgPC0gZnVuY3Rpb24obSwgbiwgaywgdmFyYXJncykgew0KICANCiAgYmggPC0gZGF0YS5mcmFtZSgpDQogIA0KICBmb3IgKGkgaW4gMTprKSB7DQogICAgYmggPC0gcmJpbmQoYmgsIGMobW9tZW50c19vZl9iZXRhX2VzdGltYXRvcihtLCBuLCBiZXRhX3N0YXJbMV0sIGJldGFfc3RhclsyXSwgdmFyYXJncykpKQ0KICB9DQogIA0KICBuYW1lcyhiaCkgPC0gYygibWVhbl9iZXRhMCIsICJtZWFuX2JldGExIiwgInZhcl9iZXRhMCIsICJ2YXJfYmV0YTEiKQ0KICBiaA0KfQ0KDQojcnVubmluZyByZXBsaWNhdGVfYXZlcmFnZV9lc3RpbWF0b3IgZm9yIHZhcmlvdXMgdmFsdWVzIG9mIG0gKGdpdmVuIGJ5IHRoZSBzZXF1ZW5jZSBtX3NlcSkNCmJldGFfaGF0X21lYW5zXzFzdGVwX2NtIDwtIGxhcHBseShtX3NlcSwgcmVwbGljYXRlX2F2ZXJhZ2VfZXN0aW1hdG9yLCBuX21pbiwga19tYXgsIGVudl8xc3QpDQojdGhlb3JldGljYWwgdmFyaWFuY2VzIG9mIGVzdGltYXRlZCBsaW5lYXIgcmVncmVzc2lvbiBjb2VmZmljaWVudHMNCmJldGFfdmFyc19jbSA8LSBjKHZhcl9iZXRhXzAoc2lnbWEsIFhmdWxsWzE6bl9taW5dKSwgdmFyX2JldGFfMShzaWdtYSwgWGZ1bGxbMTpuX21pbl0pKQ0KYGBgDQoNCg0KIyMjIERpc3RyaWJ1dGlvbiBvZiB0aGUgRXN0aW1hdG9yJ3MgTWVhbnMgKFBsb3R0aW5nKQ0KDQpIZXJlIHdlIHBsb3QgdGhlIFBERnMgaW50ZXJwb2xhdGVkIGZyb20gaGlzdG9ncmFtcyBmb3IgdGhlIGRhdGEgY29sbGVjdGVkIGF0IHRoZSBwcmV2aW91cyBzdGVwIGFsb25nIHdpdGggYSBQREYgb2YgdGhlIHN0YW5kYXJkIG5vcm1hbCBkaXN0cmlidXRpb24gZm9yIHZhcmlvdXMgdmFsdWVzIG9mIG0uIFdoYXQgd2UgYXJlIGhvcGluZyB0byBzZWUgaXMgdGhlIHJlY29uc3RydWN0ZWQgUERGIGdyYWR1YWxseSBzaGFwaW5nIGludG8gdGhhdCBvZiAkXG1hdGhjYWx7Tn0oMCwgMSkkLg0KDQpgYGB7ciBmaWcud2lkdGggPSA4LCBmaWcuaGVpZ2h0PTMuNX0NCnBhcihtZmNvbCA9IGMoMiwgbGVuZ3RoKGJldGFfaGF0X21lYW5zXzFzdGVwX2NtKSkpDQoNCnNob3dfZGVuc2l0eSA8LSBmdW5jdGlvbihtLCBiaG1zLCBiZXRhX3ZhcnMsIGJldGFfaWR4KSB7DQogIA0KICAjZWl0aGVyIG1lYW5fYmV0YTAgb3IgbWVhbl9iZXRhMSAoZGVwZW5kaW5nIG9uIHRoZSB2YWx1ZSBvZiBiZXRhX2lkeCkNCiAgYiA9IGJobXNbLCBiZXRhX2lkeCArIDFdDQogIA0KICAjdGhlb3JldGljYWwgdmFyaWFuY2Ugb2YgYmV0YTAgb3IgYmV0YTEgKGRlcGVuZGluZyBvbiB0aGUgdmFsdWUgb2YgYmV0YV9pZHgpDQogIGJ2YXIgPSBiZXRhX3ZhcnNbYmV0YV9pZHggKyAxXQ0KICANCiAgI2NvbXB1dGluZyBhbiByLnYuIHRoYXQgc2hvdWxkIGNvbnZlcmdlIHRvIE4oMCwgMSkgaW4gZGlzdHJpYnV0aW9uDQogIGNsdCA9IHNxcnQobSkgKiAoYiAtIHJlcChiZXRhX3N0YXJbYmV0YV9pZHggKyAxXSwgbGVuZ3RoKGIpKSkgLyBzcXJ0KGJ2YXIpDQogIGRjbHQgPSBkZW5zaXR5KGNsdCkNCiAgDQogICNwZGYgb2Ygc3RhbmRhcmQgbm9ybWFsIGRpc3RyaWJ1dGlvbiANCiAgY3VydmUoZG5vcm0oeCwgbWVhbiA9IDAsIHNkID0gMSksIGZyb20gPS00LCB0byA9IDQsIGNvbCA9IGNvbG9yX2hpZ2hsaWdodCwgeWxpbSA9IGMoMCwgbWF4KDAuNCwgbWF4KGRjbHQkeSkpKSwNCiAgICAgICAgeWxhYiA9ICJkZW5zaXR5IiwgeGxhYiA9IHBhc3RlKCJtZWFuIGJldGEiLCBiZXRhX2lkeCksIG1haW4gPSBwYXN0ZSgibSA9ICIsIG0pLCBsd2QgPSBsaW5lX3dpZHRoKQ0KICANCiAgI2ludGVycG9sYXRlIGNsdCdzIHBkZiBmcm9tIGl0cyBoaXN0b2dyYW0NCiAgbGluZXMoZGNsdCwgY29sID0gY29sb3JfYmFzaWMsIGx3ID0gbGluZV93aWR0aCwgbHR5ID0gMikNCn0NCg0KZm9yIChpZHggaW4gMTpsZW5ndGgoYmV0YV9oYXRfbWVhbnNfMXN0ZXBfY20pKSB7DQogIHNob3dfZGVuc2l0eShtX3NlcVtpZHhdLCBiZXRhX2hhdF9tZWFuc18xc3RlcF9jbVtbaWR4XV0sIGJldGFfdmFyc19jbSwgMCkNCiAgc2hvd19kZW5zaXR5KG1fc2VxW2lkeF0sIGJldGFfaGF0X21lYW5zXzFzdGVwX2NtW1tpZHhdXSwgYmV0YV92YXJzX2NtLCAxKQ0KfQ0KYGBgDQoNClRoZSBwbG90cyBkbyBub3Qgc2VlbSB0byBjaGFuZ2UgZHJhc3RpY2FsbHkgd2l0aCBhbiBpbmNyZWFzZSBpbiBzYW1wbGUgc2l6ZSBhbmQgdGhlIGVmZmVjdCBvZiBjb252ZXJnZW5jZSBpbiBkaXN0cmlidXRpb24gaXMgbm90IGNsZWFybHkgdmlzaWJsZS4gSXQgc2hvdWxkIG5vdCBiZS4gV2hlbiB0aGUgbm9pc2UgaXMgR2F1c3NpYW4sIHRoZSBlc3RpbWF0ZWQgdmFsdWVzIHRoZW1zZWx2ZXMgYXJlIGFscmVhZHkgbm9ybWFsbHkgZGlzdHJpYnV0ZWQgYW5kIHNvIGFyZSB0aGVpciBhdmVyYWdlcywgZXZlbiBmb3IgdmVyeSBzbWFsbCBtLiBMZXQgdXMgdHJ5IGFub3RoZXIgZGlzdHJpYnV0aW9uIGZvciB0aGUgbm9pc2UuDQoNCg0KIyMjIERpc3RyaWJ1dGlvbiBvZiB0aGUgRXN0aW1hdG9yJ3MgTWVhbnMgKEJldGEtRGlzdHJpYnV0ZWQgTm9pc2UpDQoNCldoaWNoIG9mIHRoZSBrbm93biBkaXN0cmlidXRpb25zIHdlIGNhbiBjaG9vc2U/IFRoZSBwb3NzaWJpbGl0aWVzIGFyZSBudW1lcm91cyB3aGlsZSByZXN0cmljdGlvbnMgYXJlIG5vdDogdGhlIGRpc3RyaWJ1dGlvbiBvZiBjaG9pY2UgbXVzdCBoYXZlIGZpbml0ZSB2YXJpYW5jZSBhbmQgemVybyBtZWFuLiBXaHkgbm90IEJldGEgZGlzdHJpYnV0aW9uIHNrZXdlZCB0byB0aGUgbGVmdCBieSB0aGUgdmFsdWUgb2YgaXRzIG1lYW4/IA0KDQpgYGB7cn0NCmFscGhhIDwtIDEuMQ0KYmV0YSA8LSA5DQoNCiNzYW1wbGVzIG4gdmFsdWVzIGZyb20gYmV0YSBkaXN0cmlidXRpb24NCmJldGFfbm9pc2UgPC0gZnVuY3Rpb24obiwgdmFyYXJncykgew0KICBzdG9waWZub3QoZW52X2hhcyh2YXJhcmdzLCAiYWxwaGEiKSkNCiAgc3RvcGlmbm90KGVudl9oYXModmFyYXJncywgImJldGEiKSkNCiAgcmJldGEobiwgdmFyYXJncyRhbHBoYSwgdmFyYXJncyRiZXRhKSAtIHZhcmFyZ3MkYWxwaGEgLyAodmFyYXJncyRhbHBoYSArIHZhcmFyZ3MkYmV0YSkNCn0NCg0KZW52XzFzdF9ibiA8LSBlbnYoZ2VuX25vaXNlID0gYmV0YV9ub2lzZSwgYWxwaGEgPSBhbHBoYSwgYmV0YSA9IGJldGEsIGdlbl9mZWF0dXJlID0gZGV0ZXJtaW5pc3RpY19mZWF0dXJlLCBYU291cmNlID0gWGZ1bGwpDQoNCmJldGFfaGF0X21lYW5zXzFzdGVwX2JuY20gPC0gbGFwcGx5KG1fc2VxLCByZXBsaWNhdGVfYXZlcmFnZV9lc3RpbWF0b3IsIG5fbWluLCBrX21heCwgZW52XzFzdF9ibikNCiNzdGFuZGFyZCBkZXZpYXRpb24gb2YgQmV0YSBkaXN0cmlidXRpb24NCmJuX3NkIDwtIHNxcnQoKGFscGhhICogYmV0YSkvKGFscGhhICsgYmV0YSArIDEuMCkpICogKDEuMC8oYWxwaGEgKyBiZXRhKSkNCmJldGFfdmFyc19ibmNtIDwtIGModmFyX2JldGFfMChibl9zZCwgWGZ1bGxbMTpuX21pbl0pLCB2YXJfYmV0YV8xKGJuX3NkLCBYZnVsbFsxOm5fbWluXSkpDQpgYGANCg0KQW4gaW50ZXJlc3RpbmcgZmVhdHVyZSBvZiBiZXRhIGRpc3RyaWJ1dGlvbiB3aXRoIHRoZXNlIHBhcnRpY3VsYXIgcGFyYW1ldGVycyBpcyBpdHMgYXN5bW1ldHJ5IHJlbGF0aXZlIHRvIHRoZSBtZWFuIChvbmUgb2YgdGhlIHJlYXNvbnMgd2h5IEkgcGlja2VkIGl0KS4gDQoNCmBgYHtyfQ0KY3VydmUoZGJldGEoeCwgYWxwaGEsIGJldGEpLCBjb2wgPSBjb2xvcl9iYXNpYywgeWxhYiA9ICJiZXRhIFBERiIsbHdkID0gbGluZV93aWR0aCkNCmJldGFfbWVhbiA8LSBhbHBoYSAvIChhbHBoYSArIGJldGEpDQptZWFuX2xuIDwtIHNlcSgwLCBkYmV0YShiZXRhX21lYW4sIGFscGhhLCBiZXRhKSwgMC4xKQ0KbGluZXMocmVwKGJldGFfbWVhbiwgbGVuZ3RoKG1lYW5fbG4pKSwgbWVhbl9sbiwgY29sID0gY29sb3JfaGlnaGxpZ2h0LCBsd2QgPSBsaW5lX3dpZHRoKQ0KYGBgDQoNCkEgY3Vyc29yeSBnbGFuY2UgYXQgdGhlIGZvcm11bGEgZm9yIGNvbXB1dGluZyB0aGUgJFxoYXR7XGJldGFfMX0kIGVzdGltYXRvciBsZWFkcyB1cyB0byB0aGUgY29uY2x1c2lvbiB0aGF0IHRoZSBlc3RpbWF0ZWQgdmFsdWVzIG1heSBzdGlsbCBiZSByb3VnaGx5IG5vcm1hbGx5IGRpc3RyaWJ1dGVkIChldmVuIGlmIHRoZSBub2lzZSBpcyBub3QgR2F1c3NpYW4pIGlmICRuJCBpcyBsYXJnZSBlbm91Z2gsIHRoZXJlZm9yZSBuX21pbiBpcyB1c2VkIGluIHBsYWNlIG9mIG5fZml4ZWQuDQoNCkxldCB1cyBub3cgcmVwZWF0IHRoZSBleHBlcmltZW50IHdpdGggdGhlIG5ldyBkaXN0cmlidXRpb24gZm9yIHRoZSBub2lzZS4NCg0KYGBge3IgZmlnLndpZHRoID0gOCwgZmlnLmhlaWdodD0zLjV9DQpwYXIobWZjb2wgPSBjKDIsIGxlbmd0aChiZXRhX2hhdF9tZWFuc18xc3RlcF9ibmNtKSkpDQoNCmZvciAoaWR4IGluIDE6bGVuZ3RoKGJldGFfaGF0X21lYW5zXzFzdGVwX2NtKSkgew0KICBzaG93X2RlbnNpdHkobV9zZXFbaWR4XSwgYmV0YV9oYXRfbWVhbnNfMXN0ZXBfYm5jbVtbaWR4XV0sIGJldGFfdmFyc19ibmNtLCAwKQ0KICBzaG93X2RlbnNpdHkobV9zZXFbaWR4XSwgYmV0YV9oYXRfbWVhbnNfMXN0ZXBfYm5jbVtbaWR4XV0sIGJldGFfdmFyc19ibmNtLCAxKQ0KfQ0KYGBg