1.) Log Density Derivation

Here we are examining the log-logistic (or Fisk) distribution, a popular distribution when dealing with non-negative and rightly skewed data (think survival analysis or income distributions for example).

Using R’s built-in D function, I was able to quickly find this distribution’s relative probability density function (PDF), after already being provided its cumulative distribution function (CDF). These calculations are predicated on the fact that a distribution’s PDF is simply the first derivative of its CDF. Since a derivative is the rate of change of a function at a given point, deriving a CDF across the entirety of its bounds allows for an understanding of how relative probability changes throughout. Below are the Fisk distribution’s PDF and CDF, denoted by f(x) and F(x) respectively.

CDF_function = function(x, alpha, beta){
1/(1+(x/alpha)^(-beta))
}

CDF_expression = expression(
  1/(1+(x/alpha)^(-beta))
  )


# Creating both an expression object and function object since the deriv function I am about to use only takes expression objects
  
  # Will use D function to see the returned PDF in algebraic form
  # Will use deriv function to get an expression that can be used for evaluations

## PDF = first derivative of CDF
PDFD = D(CDF_expression, "x")
#PDFD  # = ((x/alpha)^((-beta) - 1) * ((-beta) * (1/alpha))/(1 + ((x/alpha)^(-beta)))^2)
  # Wrote this down, did some additional algebra before writing up Latex below

PDF_Function = function(x, alpha, beta){
  ifelse(x <= 0, 0,
         (beta/alpha) * (x/alpha)^(beta - 1) / (1 + (x/alpha)^beta)^2)
}
  # Had to include the ifelse component because x will always be positive in the scenario of our data (recovery times) and in accordance with the properties of the Fisk distribution
    # I previously did NOT have that ifelse component and my visual confirmation further along was not effective


PDF_deriv = deriv(CDF_expression, "x")

\[{\Large F(x) = \frac{1}{1 + (x/\alpha)^{-\beta}}} \hspace{0.5cm}\Large , \hspace{0.5cm} X>=0 \]

\[{\Large f(x) = \frac{\beta}{\alpha} * \frac{(x/\alpha)^{\beta-1}}{\alpha(1+(x/\alpha)^\beta)^2}} \hspace{0.5cm}\Large , \hspace{0.5cm}X>=0 \]

2.) Recovery Time Distribution

The dataset we have on hand is composed of 50 different patients’ observed recovery times (in days) following a particular knee surgery procedure. We will operate the analysis of this dataset under the assumption that the underlying population of knee surgery recovery times is distributed in a log-logistic manner. Below are both the summary statistics and a histogram of the dataset’s values.

Days = c(8.23, 12.74, 14.83, 16.61, 18.16, 19.55, 20.80, 21.94, 23.00, 23.98, 24.89, 25.75, 26.56, 
27.34, 28.08, 28.79, 29.48, 30.15, 30.81, 31.45, 32.08, 32.70, 33.31, 33.92, 34.53, 35.13, 
35.73, 36.33, 36.93, 37.53, 38.14, 38.75, 39.37, 40.00, 40.64, 41.29, 41.95, 42.63, 43.33, 
44.05, 44.79, 45.56, 46.36, 47.20, 48.08, 49.02, 50.03, 51.12, 52.32, 53.65)
  # n = 50
Data_Days = data.frame(Days)

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)
}
  # I created a table for summary statistics of a variable, can use this moving forward instead of manually putting the summary stats in table form


Summary_Table = sum_stats_table(variable = Days)
kable(Summary_Table,align = "c",
      caption = "<span style='color:##000000;'>Summary Stats of Recovery Times</span>") %>%
  kable_styling(
    bootstrap_options = c("striped", "bordered"),
    full_width = FALSE,
    position = "center")
Summary Stats of Recovery Times
Min Q1 Med Mean Q3 Max
8.23 26.75 34.83 34.19 42.46 53.65
hist(Days, 
     main = "Distribution of Recovery Times",
     xlab = "Recovery Time (Days)",
     ylab = "Count",
)
box(lwd=3)

2a.) Moment Estimation

As stated above, we are operating under the assumption of our data stemming from a Fisk distribution. Therefore, there are two population parameters of interest, \(\alpha\) (rate of scale) and \(\beta\) (rate of shape), which we would like to use our sample data to estimate.

Using moment estimation, general formula tells us that the kth moment (\(m_k\)) of a distribution can be found by summing said dataset’s values (each raised to the k power) and then divided by the sample size. Additionally, and more specifically to the Fisk distribution, we can directly equate the different moments of a distribution to functions of the \(\alpha\) and \(\beta\) parameters. The formulas and calculations of the first two moments (\(m_1\) and \(m_2\)) are below.

## Reference Section 4.2 example 2 from lecture notes

# Mean of log logistic distribution = (alpha * pi)
                                      #      / (beta * sin(alpha/beta))

## Reference formula from Section 3.1
# moment 1 = mean of data # = 34.1922 = (alpha * pi)
                                      #      / (beta * sin(alpha/beta))

# moment 2 = mean of (data squared) = 1288.845

Moment1 = mean(Days)
Moment2 = mean(Days^2)

\[\Large Moment 1 = {\alpha^1*\Gamma(1 + 1/\beta) * \Gamma(1 - 1/\beta)} = \bar{x} \approx 34.1922 \]

\[\Large Moment 2 = {\alpha^2*\Gamma(1 + 2/\beta) * \Gamma(1 - 2/\beta)} = \bar{x^2} \approx 1288.84483 \]

Utilizing our dataset’s first two moments, we then create a system of equations via R’s uniroot and custom function capabilities, to estimate \(\alpha\) and \(\beta\) though numerical methods. Numerical methods are needed since pure algebraic tactics are unable to solve the inequalities for this distribution. Since we are finding estimates of the broader population parameters of a Fisk distributed population, we label these estimates \(\hat{\alpha}\) and \(\hat{\beta}\) to represent \(\alpha\) and \(\beta\) respectively.

## From assignment instructions:
## (alpha^k) * beta function (1 + (k/beta), 1 - (k/beta))
  # Capital B denotes the beta function


Beta_Hat = uniroot(function(Beta){
    # The uniroot function tells us what value of specific variable will lead our function to equal zero or approach zero
    # In this case, we are finding f(beta) = 0 because there is not an algebraic way to find a difference of zero between sample variance and theoretical variance
  
  A = (pi/Beta)/
        sin(pi/Beta)
    # One portion of Fisk Distribution variance formula
  
  B = (2*pi/Beta)/
      sin(2*pi/Beta)
    # Other portion of Fisk Distribution variance formula
  
  Alpha_Beta = Moment1 / A
  Alpha_Beta^2 * (B - A^2) - (Moment2 - Moment1^2)
}, lower = 2.000001, upper = 2000000)$root
  # Set lower bound of search to 2.000001 because, per properties of Fisk Distribution moments, beta must be greater than moment 2 in order for variance to exist
  # upper bound set arbitrarily

Alpha_Hat = Moment1 / ((pi/Beta_Hat)/sin(pi/Beta_Hat))

invisible(
  Alpha_Hat
)

invisible(
  Beta_Hat
)

\[\Large \hat{\alpha} \approx 32.65\] \[\Large \hat{\beta} \approx 6.01\]

To confirm relative accuracy of our estimates, below I overlaid the Fisk distribution’s PDF with given alpha and beta parameters over top our available sample data of patient recovery times. There is moderate overlap between our distribution curve and histogram data. This leads me to believe that there very well could be an underestimate of our \(\alpha\) parameter, as the value of \(\alpha\) traditionally controls the horizontal location of a curve’s peak and decline.

hist(Days, 
     main = "Distribution of Recovery Times",
     xlab = "Recovery Time (Days)",
     ylab = "Probability Density",
     ylim = c(0, 0.05),
     breaks = 10,
     prob = TRUE)


curve(PDF_Function(x , alpha = 32.65431, beta = 6.006248), 
      col = "red",
      lwd = 3,
      add = TRUE)

legend("topright",
       legend = "Fisk (32.65, 6.07)",
       col = "red",
       lwd = 3,
       box.lwd=3)

box(lwd=3)

2b.)

Given the inherent variation that exists in sampling, I chose to execute a bootstrapping sequence. I performed 1,000 iterations of samples (n = 50 each time) for both our parameters estimators, \(\hat{\alpha}\) and \(\hat{\beta}\).

Pictured below are the sampling distributions for both parameters, each of them with a Gaussian kernel density curve layered above and said curve’s respective bandwidth notated in parentheses. Bandwidths were chosen in accordance with Silverman’s standard formula and calculated via a custom-built R function.

# Bootstrap Calculations
set.seed(100)

Alpha_Bootstraps = 0
Beta_Bootstraps = 0
  # Set these variables equal to zero as they will be constantly updated throughout the for loop's iterations

for(i in 1:1000){
  ith_Sample = sample(Days, size = length(Days), replace = TRUE)
    # Always use replacement when bootstrapping
  ith_Moment1 = mean(ith_Sample)
  ith_Moment2 = mean(ith_Sample^2)
  
# Copied function from part 2a: removed comments as process is the same for each bootstrap sample
    # updated variable names for the bootstrap procedure
    Boot_Beta_Hat = uniroot(function(Beta){
    A = (pi/Beta)/
          sin(pi/Beta)
    
    B = (2*pi/Beta)/
        sin(2*pi/Beta)
    
    Alpha_Beta = ith_Moment1 / A
    Alpha_Beta^2 * (B - A^2) - (ith_Moment2 - ith_Moment1^2)
  }, lower = 2.000001, upper = 2000000)$root
  
  Boot_Alpha_Hat = ith_Moment1 / ((pi/Beta_Hat)/sin(pi/Beta_Hat))
  
  Alpha_Bootstraps[i] = Boot_Alpha_Hat
  Beta_Bootstraps[i] = Boot_Beta_Hat
}
## Create custom function for finding Gaussian bw quickly in future
Gaussian_BW = function(Data){
  IQR = quantile(Data, 0.75) - quantile(Data, 0.25)
  Min_Part = min(sd(Data),(IQR/1.34))
  BW = 0.9 * Min_Part * (length(Data)^(-0.2))
  return(BW)
}

invisible(
  Gaussian_BW(Data = Alpha_Bootstraps) # = 0.3183099
)


hist(Alpha_Bootstraps,
     main = "Bootstrap Distribution of Alpha Hat",
     xlab = "Sampling Means",
     ylab = "Probability Density",
     prob = TRUE
     )

# bandwidth calculations below
Gaussian = density(Alpha_Bootstraps, bw = 0.3183099, kernel = "gaussian")
lines(Gaussian,
      lwd = 3,
      col = "blue"
      )

legend("topright",
       legend = "Gaussian (0.32)",
       col = "blue",
       lwd = 3,
       box.lwd=3)

box(lwd=3)

invisible(
  Gaussian_BW(Data = Beta_Bootstraps) # = 0.1303286
)

hist(Beta_Bootstraps,
     main = "Bootstrap Distribution of Beta Hat",
     xlab = "Sampling Means",
     ylab = "Probability Density",
     prob = TRUE,
     ylim = c(0,0.7)
     )
box(lwd=3)

Gaussian = density(Beta_Bootstraps, bw = 0.1303286, kernel = "gaussian")
lines(Gaussian,
      lwd = 3,
      col = "blue"
      )

legend("topright",
       legend = "Gaussian (0.13)",
       col = "blue",
       lwd = 3,
       box.lwd=3)

What the bootstrap distribution for \(\hat{\alpha}\) and \(\hat{\beta}\) display is a far greater resemblance with their Gaussian PDF estimations than what was seen above, comparing our data to the curve of a standard Fisk distribution with said values for \(\alpha\) and \(\beta\).

Two possible suggestions that this relevation brings are: perhaps the population from which these sampled surgery recovery times came from is not truly as Fisk distributed as we initially believed, or as stated previously there could be an underestimate of the \(\alpha\) parameter.

LS0tCnRpdGxlOiAiTW9tZW50IEVzdGltYXRpb24gTWV0aG9kcyIKYXV0aG9yOiAiQ2hyaXMgQmFobSIKZGF0ZTogImByIGZvcm1hdChTeXMuRGF0ZSgpLCAnJUIgJWQsICVZJylgIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OgogICAgICBjb2xsYXBzZWQ6IHRydWUKICAgICAgc21vb3RoX3Njcm9sbDogdHJ1ZQogICAgdG9jX2RlcHRoOiA0CiAgICBmaWdfd2lkdGg6IDYKICAgIGZpZ19oZWlnaHQ6IDQKICAgIGZpZ19jYXB0aW9uOiB0cnVlCiAgICBudW1iZXJfc2VjdGlvbnM6IGZhbHNlCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIHRoZW1lOiBsdW1lbgogICAgaGlnaGxpZ2h0OiB0YW5nbwogIHBkZl9kb2N1bWVudDoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2RlcHRoOiA0CiAgICBmaWdfY2FwdGlvbjogdHJ1ZQogICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgd29yZF9kb2N1bWVudDoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2RlcHRoOiA0Ci0tLQoKYGBge2NzcywgZWNobyA9IEZBTFNFfQpkaXYjVE9DIGxpIHsgICAgIC8qIHRhYmxlIG9mIGNvbnRlbnQgICovCiAgICBsaXN0LXN0eWxlOnVwcGVyLXJvbWFuOwogICAgYmFja2dyb3VuZC1pbWFnZTpub25lOwogICAgYmFja2dyb3VuZC1yZXBlYXQ6bm9uZTsKICAgIGJhY2tncm91bmQtcG9zaXRpb246MDsKfQoKaDEudGl0bGUgeyAgICAvKiBsZXZlbCAxIGhlYWRlciBvZiB0aXRsZSAgKi8KICBmb250LXNpemU6IDI0cHg7CiAgZm9udC13ZWlnaHQ6IGJvbGQ7CiAgY29sb3I6IERhcmtSZWQ7CiAgdGV4dC1hbGlnbjogY2VudGVyOwp9CgpoNC5hdXRob3IgeyAvKiBIZWFkZXIgNCAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLwogIGZvbnQtc2l6ZTogMThweDsKICBmb250LXdlaWdodDogYm9sZDsKICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsKICBjb2xvcjogRGFya1JlZDsKICB0ZXh0LWFsaWduOiBjZW50ZXI7Cn0KCmg0LmRhdGUgeyAvKiBIZWFkZXIgNCAtIGFuZCB0aGUgYXV0aG9yIGFuZCBkYXRhIGhlYWRlcnMgdXNlIHRoaXMgdG9vICAqLwogIGZvbnQtc2l6ZTogMThweDsKICBmb250LXdlaWdodDogYm9sZDsKICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsKICBjb2xvcjogRGFya0JsdWU7CiAgdGV4dC1hbGlnbjogY2VudGVyOwp9CgpoMSB7IC8qIEhlYWRlciAxIC0gYW5kIHRoZSBhdXRob3IgYW5kIGRhdGEgaGVhZGVycyB1c2UgdGhpcyB0b28gICovCiAgICBmb250LXNpemU6IDIwcHg7CiAgICBmb250LXdlaWdodDogYm9sZDsKICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOwogICAgY29sb3I6IGRhcmtyZWQ7CiAgICB0ZXh0LWFsaWduOiBjZW50ZXI7Cn0KCmgyIHsgLyogSGVhZGVyIDIgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8KICAgIGZvbnQtc2l6ZTogMThweDsKICAgIGZvbnQtd2VpZ2h0OiBib2xkOwogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7CiAgICBjb2xvcjogbmF2eTsKICAgIHRleHQtYWxpZ246IGxlZnQ7Cn0KCmgzIHsgLyogSGVhZGVyIDMgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8KICAgIGZvbnQtc2l6ZTogMTZweDsKICAgIGZvbnQtd2VpZ2h0OiBib2xkOwogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7CiAgICBjb2xvcjogbmF2eTsKICAgIHRleHQtYWxpZ246IGxlZnQ7Cn0KCmg0IHsgLyogSGVhZGVyIDQgLSBhbmQgdGhlIGF1dGhvciBhbmQgZGF0YSBoZWFkZXJzIHVzZSB0aGlzIHRvbyAgKi8KICAgIGZvbnQtc2l6ZTogMTRweDsKICBmb250LXdlaWdodDogYm9sZDsKICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOwogICAgY29sb3I6IGRhcmtyZWQ7CiAgICB0ZXh0LWFsaWduOiBsZWZ0Owp9CgovKiBBZGQgZG90cyBhZnRlciBudW1iZXJlZCBoZWFkZXJzICovCi5oZWFkZXItc2VjdGlvbi1udW1iZXI6OmFmdGVyIHsKICBjb250ZW50OiAiLiI7Cn0KYGBgCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0KIyBjb2RlIGNodW5rIHNwZWNpZmllcyB3aGV0aGVyIHRoZSBSIGNvZGUsIHdhcm5pbmdzLCBhbmQgb3V0cHV0IAojIHdpbGwgYmUgaW5jbHVkZWQgaW4gdGhlIG91dHB1dCBmaWxlcy4KCmlmICghcmVxdWlyZSgia25pdHIiKSkgeyAgICAgICAgICAgICAgICAgICAgICAjIHVzZSBjb25kaXRpb25hbCBzdGF0ZW1lbnQgdG8gZGV0ZWN0CiAgIGluc3RhbGwucGFja2FnZXMoImtuaXRyIikgICAgICAgICAgICAgICAgICAjIHdoZXRoZXIgYSBwYWNrYWdlIHdhcyBpbnN0YWxsZWQgaW4KICAgbGlicmFyeShrbml0cikgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgeW91ciBtYWNoaW5lLiBJZiBub3QsIGluc3RhbGwgaXQgYW5kCn0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGxvYWQgaXQgdG8gdGhlIHdvcmtpbmcgZGlyZWN0b3J5LgoKaWYgKCFyZXF1aXJlKHRpZHl2ZXJzZSkpIHtsaWJyYXJ5KHRpZHl2c2Vyc2UpfSAKCmlmICghcmVxdWlyZShHR2FsbHkpKSB7bGlicmFyeShHR2FsbHkpfSAKCmlmICghcmVxdWlyZShrYWJsZUV4dHJhKSkge2xpYnJhcnkoa2FibGVFeHRyYSl9IAoKaWYgKCFyZXF1aXJlKGdncGxvdDIpKSB7bGlicmFyeShnZ3Bsb3QyKX0gCgppZiAoIXJlcXVpcmUoY2FyKSkge2xpYnJhcnkoY2FyKX0gCgppZiAoIXJlcXVpcmUoZHBseXIpKSB7bGlicmFyeShkcGx5cil9IAoKaWYgKCFyZXF1aXJlKHBhbmRlcikpIHtsaWJyYXJ5KHBhbmRlcil9IAoKaWYgKCFyZXF1aXJlKGZvcmVjYXN0KSkge2xpYnJhcnkoZm9yZWNhc3QpfSAKCmlmICghcmVxdWlyZShsdWJyaWRhdGUpKSB7bGlicmFyeShsdWJyaWRhdGUpfSAKCmlmICghcmVxdWlyZSgic2NhbGVzIikpIHsKaW5zdGFsbC5wYWNrYWdlcygic2NhbGVzIikgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCmxpYnJhcnkoInNjYWxlcyIpIAp9Cgprbml0cjo6b3B0c19jaHVuayRzZXQoCgllY2hvID0gVFJVRSwKCW1lc3NhZ2UgPSBGQUxTRSwKCXdhcm5pbmcgPSBGQUxTRSwKCWNvbW1lbnQgPSBOQSwKCXJlc3VsdHMgPSBUUlVFLAoJZmlnLmFsaWduID0gImNlbnRlciIKKQpgYGAKCgojIDEuKSBMb2cgRGVuc2l0eSBEZXJpdmF0aW9uCkhlcmUgd2UgYXJlIGV4YW1pbmluZyB0aGUgbG9nLWxvZ2lzdGljIChvciBGaXNrKSBkaXN0cmlidXRpb24sIGEgcG9wdWxhciBkaXN0cmlidXRpb24gd2hlbiBkZWFsaW5nIHdpdGggbm9uLW5lZ2F0aXZlIGFuZCByaWdodGx5IHNrZXdlZCBkYXRhICh0aGluayBzdXJ2aXZhbCBhbmFseXNpcyBvciBpbmNvbWUgZGlzdHJpYnV0aW9ucyBmb3IgZXhhbXBsZSkuIAoKVXNpbmcgUidzIGJ1aWx0LWluIDxzcGFuIHN0eWxlPSJjb2xvcjpibHVlOyI+RDwvc3Bhbj4gIGZ1bmN0aW9uLCBJIHdhcyBhYmxlIHRvIHF1aWNrbHkgZmluZCB0aGlzIGRpc3RyaWJ1dGlvbidzIHJlbGF0aXZlIHByb2JhYmlsaXR5IGRlbnNpdHkgZnVuY3Rpb24gKFBERiksIGFmdGVyIGFscmVhZHkgYmVpbmcgcHJvdmlkZWQgaXRzIGN1bXVsYXRpdmUgZGlzdHJpYnV0aW9uIGZ1bmN0aW9uIChDREYpLiBUaGVzZSBjYWxjdWxhdGlvbnMgYXJlIHByZWRpY2F0ZWQgb24gdGhlIGZhY3QgdGhhdCBhIGRpc3RyaWJ1dGlvbidzIFBERiBpcyBzaW1wbHkgdGhlIGZpcnN0IGRlcml2YXRpdmUgb2YgaXRzIENERi4gU2luY2UgYSBkZXJpdmF0aXZlIGlzIHRoZSByYXRlIG9mIGNoYW5nZSBvZiBhIGZ1bmN0aW9uIGF0IGEgZ2l2ZW4gcG9pbnQsIGRlcml2aW5nIGEgQ0RGIGFjcm9zcyB0aGUgZW50aXJldHkgb2YgaXRzIGJvdW5kcyBhbGxvd3MgZm9yIGFuIHVuZGVyc3RhbmRpbmcgb2YgaG93IHJlbGF0aXZlIHByb2JhYmlsaXR5IGNoYW5nZXMgdGhyb3VnaG91dC4gQmVsb3cgYXJlIHRoZSBGaXNrIGRpc3RyaWJ1dGlvbidzIFBERiBhbmQgQ0RGLCBkZW5vdGVkIGJ5IGYoeCkgYW5kIEYoeCkgcmVzcGVjdGl2ZWx5LgoKCmBgYHtyfQpDREZfZnVuY3Rpb24gPSBmdW5jdGlvbih4LCBhbHBoYSwgYmV0YSl7CjEvKDErKHgvYWxwaGEpXigtYmV0YSkpCn0KCkNERl9leHByZXNzaW9uID0gZXhwcmVzc2lvbigKICAxLygxKyh4L2FscGhhKV4oLWJldGEpKQogICkKCgojIENyZWF0aW5nIGJvdGggYW4gZXhwcmVzc2lvbiBvYmplY3QgYW5kIGZ1bmN0aW9uIG9iamVjdCBzaW5jZSB0aGUgZGVyaXYgZnVuY3Rpb24gSSBhbSBhYm91dCB0byB1c2Ugb25seSB0YWtlcyBleHByZXNzaW9uIG9iamVjdHMKICAKICAjIFdpbGwgdXNlIEQgZnVuY3Rpb24gdG8gc2VlIHRoZSByZXR1cm5lZCBQREYgaW4gYWxnZWJyYWljIGZvcm0KICAjIFdpbGwgdXNlIGRlcml2IGZ1bmN0aW9uIHRvIGdldCBhbiBleHByZXNzaW9uIHRoYXQgY2FuIGJlIHVzZWQgZm9yIGV2YWx1YXRpb25zCgojIyBQREYgPSBmaXJzdCBkZXJpdmF0aXZlIG9mIENERgpQREZEID0gRChDREZfZXhwcmVzc2lvbiwgIngiKQojUERGRCAgIyA9ICgoeC9hbHBoYSleKCgtYmV0YSkgLSAxKSAqICgoLWJldGEpICogKDEvYWxwaGEpKS8oMSArICgoeC9hbHBoYSleKC1iZXRhKSkpXjIpCiAgIyBXcm90ZSB0aGlzIGRvd24sIGRpZCBzb21lIGFkZGl0aW9uYWwgYWxnZWJyYSBiZWZvcmUgd3JpdGluZyB1cCBMYXRleCBiZWxvdwoKUERGX0Z1bmN0aW9uID0gZnVuY3Rpb24oeCwgYWxwaGEsIGJldGEpewogIGlmZWxzZSh4IDw9IDAsIDAsCiAgICAgICAgIChiZXRhL2FscGhhKSAqICh4L2FscGhhKV4oYmV0YSAtIDEpIC8gKDEgKyAoeC9hbHBoYSleYmV0YSleMikKfQogICMgSGFkIHRvIGluY2x1ZGUgdGhlIGlmZWxzZSBjb21wb25lbnQgYmVjYXVzZSB4IHdpbGwgYWx3YXlzIGJlIHBvc2l0aXZlIGluIHRoZSBzY2VuYXJpbyBvZiBvdXIgZGF0YSAocmVjb3ZlcnkgdGltZXMpIGFuZCBpbiBhY2NvcmRhbmNlIHdpdGggdGhlIHByb3BlcnRpZXMgb2YgdGhlIEZpc2sgZGlzdHJpYnV0aW9uCiAgICAjIEkgcHJldmlvdXNseSBkaWQgTk9UIGhhdmUgdGhhdCBpZmVsc2UgY29tcG9uZW50IGFuZCBteSB2aXN1YWwgY29uZmlybWF0aW9uIGZ1cnRoZXIgYWxvbmcgd2FzIG5vdCBlZmZlY3RpdmUKCgpQREZfZGVyaXYgPSBkZXJpdihDREZfZXhwcmVzc2lvbiwgIngiKQoKYGBgCgoKJCR7XExhcmdlIEYoeCkgPSBcZnJhY3sxfXsxICsgKHgvXGFscGhhKV57LVxiZXRhfX19IFxoc3BhY2V7MC41Y219XExhcmdlICwgXGhzcGFjZXswLjVjbX0gWD49MCAgJCQKPGJyPgoKCiQke1xMYXJnZSBmKHgpID0gXGZyYWN7XGJldGF9e1xhbHBoYX0gKiBcZnJhY3soeC9cYWxwaGEpXntcYmV0YS0xfX17XGFscGhhKDErKHgvXGFscGhhKV5cYmV0YSleMn19IFxoc3BhY2V7MC41Y219XExhcmdlICwgXGhzcGFjZXswLjVjbX1YPj0wICAkJAo8YnI+CgoKIyAyLikgUmVjb3ZlcnkgVGltZSBEaXN0cmlidXRpb24KVGhlIGRhdGFzZXQgd2UgaGF2ZSBvbiBoYW5kIGlzIGNvbXBvc2VkIG9mIDUwIGRpZmZlcmVudCBwYXRpZW50cycgb2JzZXJ2ZWQgcmVjb3ZlcnkgdGltZXMgKGluIGRheXMpIGZvbGxvd2luZyBhIHBhcnRpY3VsYXIga25lZSBzdXJnZXJ5IHByb2NlZHVyZS4gV2Ugd2lsbCBvcGVyYXRlIHRoZSBhbmFseXNpcyBvZiB0aGlzIGRhdGFzZXQgdW5kZXIgdGhlIGFzc3VtcHRpb24gdGhhdCB0aGUgdW5kZXJseWluZyBwb3B1bGF0aW9uIG9mIGtuZWUgc3VyZ2VyeSByZWNvdmVyeSB0aW1lcyBpcyBkaXN0cmlidXRlZCBpbiBhIGxvZy1sb2dpc3RpYyBtYW5uZXIuIEJlbG93IGFyZSBib3RoIHRoZSBzdW1tYXJ5IHN0YXRpc3RpY3MgYW5kIGEgaGlzdG9ncmFtIG9mIHRoZSBkYXRhc2V0J3MgdmFsdWVzLgoKYGBge3IsIGZpZy5oZWlnaHQ9NX0KRGF5cyA9IGMoOC4yMywgMTIuNzQsIDE0LjgzLCAxNi42MSwgMTguMTYsIDE5LjU1LCAyMC44MCwgMjEuOTQsIDIzLjAwLCAyMy45OCwgMjQuODksIDI1Ljc1LCAyNi41NiwgCjI3LjM0LCAyOC4wOCwgMjguNzksIDI5LjQ4LCAzMC4xNSwgMzAuODEsIDMxLjQ1LCAzMi4wOCwgMzIuNzAsIDMzLjMxLCAzMy45MiwgMzQuNTMsIDM1LjEzLCAKMzUuNzMsIDM2LjMzLCAzNi45MywgMzcuNTMsIDM4LjE0LCAzOC43NSwgMzkuMzcsIDQwLjAwLCA0MC42NCwgNDEuMjksIDQxLjk1LCA0Mi42MywgNDMuMzMsIAo0NC4wNSwgNDQuNzksIDQ1LjU2LCA0Ni4zNiwgNDcuMjAsIDQ4LjA4LCA0OS4wMiwgNTAuMDMsIDUxLjEyLCA1Mi4zMiwgNTMuNjUpCiAgIyBuID0gNTAKRGF0YV9EYXlzID0gZGF0YS5mcmFtZShEYXlzKQoKc3VtX3N0YXRzX3RhYmxlID0gZnVuY3Rpb24odmFyaWFibGUpewogIHRhYmxlID0gY2JpbmQoCiAgICByb3VuZChtaW4odmFyaWFibGUpLDIpLAogICAgcm91bmQocXVhbnRpbGUodmFyaWFibGUsIDAuMjUpLDIpLAogICAgcm91bmQobWVkaWFuKHZhcmlhYmxlKSwyKSwKICAgIHJvdW5kKG1lYW4odmFyaWFibGUpLDIpLAogICAgcm91bmQocXVhbnRpbGUodmFyaWFibGUsIDAuNzUpLDIpLAogICAgcm91bmQobWF4KHZhcmlhYmxlKSwyKQogICkKICBjb2xuYW1lcyh0YWJsZSkgPSBjKCJNaW4iLCAiUTEiLCAiTWVkIiwgIk1lYW4iLCAiUTMiLCAiTWF4IikKICByb3duYW1lcyh0YWJsZSkgPSBOVUxMCiAgcmV0dXJuKHRhYmxlKQp9CiAgIyBJIGNyZWF0ZWQgYSB0YWJsZSBmb3Igc3VtbWFyeSBzdGF0aXN0aWNzIG9mIGEgdmFyaWFibGUsIGNhbiB1c2UgdGhpcyBtb3ZpbmcgZm9yd2FyZCBpbnN0ZWFkIG9mIG1hbnVhbGx5IHB1dHRpbmcgdGhlIHN1bW1hcnkgc3RhdHMgaW4gdGFibGUgZm9ybQoKClN1bW1hcnlfVGFibGUgPSBzdW1fc3RhdHNfdGFibGUodmFyaWFibGUgPSBEYXlzKQprYWJsZShTdW1tYXJ5X1RhYmxlLGFsaWduID0gImMiLAogICAgICBjYXB0aW9uID0gIjxzcGFuIHN0eWxlPSdjb2xvcjojIzAwMDAwMDsnPlN1bW1hcnkgU3RhdHMgb2YgUmVjb3ZlcnkgVGltZXM8L3NwYW4+IikgJT4lCiAga2FibGVfc3R5bGluZygKICAgIGJvb3RzdHJhcF9vcHRpb25zID0gYygic3RyaXBlZCIsICJib3JkZXJlZCIpLAogICAgZnVsbF93aWR0aCA9IEZBTFNFLAogICAgcG9zaXRpb24gPSAiY2VudGVyIikKCgpoaXN0KERheXMsIAogICAgIG1haW4gPSAiRGlzdHJpYnV0aW9uIG9mIFJlY292ZXJ5IFRpbWVzIiwKICAgICB4bGFiID0gIlJlY292ZXJ5IFRpbWUgKERheXMpIiwKICAgICB5bGFiID0gIkNvdW50IiwKKQpib3gobHdkPTMpCgpgYGAKCiMjIDJhLikgTW9tZW50IEVzdGltYXRpb24KCkFzIHN0YXRlZCBhYm92ZSwgd2UgYXJlIG9wZXJhdGluZyB1bmRlciB0aGUgYXNzdW1wdGlvbiBvZiBvdXIgZGF0YSBzdGVtbWluZyBmcm9tIGEgRmlzayBkaXN0cmlidXRpb24uIFRoZXJlZm9yZSwgdGhlcmUgYXJlIHR3byBwb3B1bGF0aW9uIHBhcmFtZXRlcnMgb2YgaW50ZXJlc3QsICRcYWxwaGEkIChyYXRlIG9mIHNjYWxlKSBhbmQgJFxiZXRhJCAocmF0ZSBvZiBzaGFwZSksIHdoaWNoIHdlIHdvdWxkIGxpa2UgdG8gdXNlIG91ciBzYW1wbGUgZGF0YSB0byBlc3RpbWF0ZS4gCgpVc2luZyBtb21lbnQgZXN0aW1hdGlvbiwgZ2VuZXJhbCBmb3JtdWxhIHRlbGxzIHVzIHRoYXQgdGhlIGt0aCBtb21lbnQgKCRtX2skKSBvZiBhIGRpc3RyaWJ1dGlvbiBjYW4gYmUgZm91bmQgYnkgc3VtbWluZyBzYWlkIGRhdGFzZXQncyB2YWx1ZXMgKGVhY2ggcmFpc2VkIHRvIHRoZSBrIHBvd2VyKSBhbmQgdGhlbiBkaXZpZGVkIGJ5IHRoZSBzYW1wbGUgc2l6ZS4gQWRkaXRpb25hbGx5LCBhbmQgbW9yZSBzcGVjaWZpY2FsbHkgdG8gdGhlIEZpc2sgZGlzdHJpYnV0aW9uLCB3ZSBjYW4gZGlyZWN0bHkgZXF1YXRlIHRoZSBkaWZmZXJlbnQgbW9tZW50cyBvZiBhIGRpc3RyaWJ1dGlvbiB0byBmdW5jdGlvbnMgb2YgdGhlICRcYWxwaGEkIGFuZCAkXGJldGEkIHBhcmFtZXRlcnMuIFRoZSBmb3JtdWxhcyBhbmQgY2FsY3VsYXRpb25zIG9mIHRoZSBmaXJzdCB0d28gbW9tZW50cyAoJG1fMSQgYW5kICRtXzIkKSBhcmUgYmVsb3cuCgpgYGB7cn0KIyMgUmVmZXJlbmNlIFNlY3Rpb24gNC4yIGV4YW1wbGUgMiBmcm9tIGxlY3R1cmUgbm90ZXMKCiMgTWVhbiBvZiBsb2cgbG9naXN0aWMgZGlzdHJpYnV0aW9uID0gKGFscGhhICogcGkpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyAgICAgIC8gKGJldGEgKiBzaW4oYWxwaGEvYmV0YSkpCgojIyBSZWZlcmVuY2UgZm9ybXVsYSBmcm9tIFNlY3Rpb24gMy4xCiMgbW9tZW50IDEgPSBtZWFuIG9mIGRhdGEgIyA9IDM0LjE5MjIgPSAoYWxwaGEgKiBwaSkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjICAgICAgLyAoYmV0YSAqIHNpbihhbHBoYS9iZXRhKSkKCiMgbW9tZW50IDIgPSBtZWFuIG9mIChkYXRhIHNxdWFyZWQpID0gMTI4OC44NDUKCk1vbWVudDEgPSBtZWFuKERheXMpCk1vbWVudDIgPSBtZWFuKERheXNeMikKYGBgCgokJFxMYXJnZSBNb21lbnQgMSA9IHtcYWxwaGFeMSpcR2FtbWEoMSArIDEvXGJldGEpICogXEdhbW1hKDEgLSAxL1xiZXRhKX0gPSAgXGJhcnt4fSBcYXBwcm94IGByIE1vbWVudDFgICAkJAoKJCRcTGFyZ2UgTW9tZW50IDIgPSB7XGFscGhhXjIqXEdhbW1hKDEgKyAyL1xiZXRhKSAqIFxHYW1tYSgxIC0gMi9cYmV0YSl9ID0gIFxiYXJ7eF4yfSBcYXBwcm94IGByIE1vbWVudDJgICAkJAoKVXRpbGl6aW5nIG91ciBkYXRhc2V0J3MgZmlyc3QgdHdvIG1vbWVudHMsIHdlIHRoZW4gY3JlYXRlIGEgc3lzdGVtIG9mIGVxdWF0aW9ucyB2aWEgUidzIDxzcGFuIHN0eWxlPSJjb2xvcjpibHVlOyI+dW5pcm9vdDwvc3Bhbj4gIGFuZCBjdXN0b20gPHNwYW4gc3R5bGU9ImNvbG9yOmJsdWU7Ij5mdW5jdGlvbjwvc3Bhbj4gY2FwYWJpbGl0aWVzLCB0byBlc3RpbWF0ZSAkXGFscGhhJCBhbmQgJFxiZXRhJCB0aG91Z2ggbnVtZXJpY2FsIG1ldGhvZHMuIE51bWVyaWNhbCBtZXRob2RzIGFyZSBuZWVkZWQgc2luY2UgcHVyZSBhbGdlYnJhaWMgdGFjdGljcyBhcmUgdW5hYmxlIHRvIHNvbHZlIHRoZSBpbmVxdWFsaXRpZXMgZm9yIHRoaXMgZGlzdHJpYnV0aW9uLiBTaW5jZSB3ZSBhcmUgZmluZGluZyAqZXN0aW1hdGVzKiBvZiB0aGUgYnJvYWRlciBwb3B1bGF0aW9uIHBhcmFtZXRlcnMgb2YgYSBGaXNrIGRpc3RyaWJ1dGVkIHBvcHVsYXRpb24sIHdlIGxhYmVsIHRoZXNlIGVzdGltYXRlcyAkXGhhdHtcYWxwaGF9JCBhbmQgJFxoYXR7XGJldGF9JCB0byByZXByZXNlbnQgJFxhbHBoYSQgYW5kICRcYmV0YSQgcmVzcGVjdGl2ZWx5LgoKYGBge3J9CiMjIEZyb20gYXNzaWdubWVudCBpbnN0cnVjdGlvbnM6CiMjIChhbHBoYV5rKSAqIGJldGEgZnVuY3Rpb24gKDEgKyAoay9iZXRhKSwgMSAtIChrL2JldGEpKQogICMgQ2FwaXRhbCBCIGRlbm90ZXMgdGhlIGJldGEgZnVuY3Rpb24KCgpCZXRhX0hhdCA9IHVuaXJvb3QoZnVuY3Rpb24oQmV0YSl7CiAgICAjIFRoZSB1bmlyb290IGZ1bmN0aW9uIHRlbGxzIHVzIHdoYXQgdmFsdWUgb2Ygc3BlY2lmaWMgdmFyaWFibGUgd2lsbCBsZWFkIG91ciBmdW5jdGlvbiB0byBlcXVhbCB6ZXJvIG9yIGFwcHJvYWNoIHplcm8KICAgICMgSW4gdGhpcyBjYXNlLCB3ZSBhcmUgZmluZGluZyBmKGJldGEpID0gMCBiZWNhdXNlIHRoZXJlIGlzIG5vdCBhbiBhbGdlYnJhaWMgd2F5IHRvIGZpbmQgYSBkaWZmZXJlbmNlIG9mIHplcm8gYmV0d2VlbiBzYW1wbGUgdmFyaWFuY2UgYW5kIHRoZW9yZXRpY2FsIHZhcmlhbmNlCiAgCiAgQSA9IChwaS9CZXRhKS8KICAgICAgICBzaW4ocGkvQmV0YSkKICAgICMgT25lIHBvcnRpb24gb2YgRmlzayBEaXN0cmlidXRpb24gdmFyaWFuY2UgZm9ybXVsYQogIAogIEIgPSAoMipwaS9CZXRhKS8KICAgICAgc2luKDIqcGkvQmV0YSkKICAgICMgT3RoZXIgcG9ydGlvbiBvZiBGaXNrIERpc3RyaWJ1dGlvbiB2YXJpYW5jZSBmb3JtdWxhCiAgCiAgQWxwaGFfQmV0YSA9IE1vbWVudDEgLyBBCiAgQWxwaGFfQmV0YV4yICogKEIgLSBBXjIpIC0gKE1vbWVudDIgLSBNb21lbnQxXjIpCn0sIGxvd2VyID0gMi4wMDAwMDEsIHVwcGVyID0gMjAwMDAwMCkkcm9vdAogICMgU2V0IGxvd2VyIGJvdW5kIG9mIHNlYXJjaCB0byAyLjAwMDAwMSBiZWNhdXNlLCBwZXIgcHJvcGVydGllcyBvZiBGaXNrIERpc3RyaWJ1dGlvbiBtb21lbnRzLCBiZXRhIG11c3QgYmUgZ3JlYXRlciB0aGFuIG1vbWVudCAyIGluIG9yZGVyIGZvciB2YXJpYW5jZSB0byBleGlzdAogICMgdXBwZXIgYm91bmQgc2V0IGFyYml0cmFyaWx5CgpBbHBoYV9IYXQgPSBNb21lbnQxIC8gKChwaS9CZXRhX0hhdCkvc2luKHBpL0JldGFfSGF0KSkKCmludmlzaWJsZSgKICBBbHBoYV9IYXQKKQoKaW52aXNpYmxlKAogIEJldGFfSGF0CikKYGBgCgoKJCRcTGFyZ2UgXGhhdHtcYWxwaGF9IFxhcHByb3ggYHIgcm91bmQoQWxwaGFfSGF0LDIpYCQkCiQkXExhcmdlIFxoYXR7XGJldGF9IFxhcHByb3ggYHIgcm91bmQoQmV0YV9IYXQsMilgJCQKClRvIGNvbmZpcm0gcmVsYXRpdmUgYWNjdXJhY3kgb2Ygb3VyIGVzdGltYXRlcywgYmVsb3cgSSBvdmVybGFpZCB0aGUgRmlzayBkaXN0cmlidXRpb24ncyBQREYgd2l0aCBnaXZlbiBhbHBoYSBhbmQgYmV0YSBwYXJhbWV0ZXJzIG92ZXIgdG9wIG91ciBhdmFpbGFibGUgc2FtcGxlIGRhdGEgb2YgcGF0aWVudCByZWNvdmVyeSB0aW1lcy4gVGhlcmUgaXMgbW9kZXJhdGUgb3ZlcmxhcCBiZXR3ZWVuIG91ciBkaXN0cmlidXRpb24gY3VydmUgYW5kIGhpc3RvZ3JhbSBkYXRhLiBUaGlzIGxlYWRzIG1lIHRvIGJlbGlldmUgdGhhdCB0aGVyZSB2ZXJ5IHdlbGwgY291bGQgYmUgYW4gdW5kZXJlc3RpbWF0ZSBvZiBvdXIgJFxhbHBoYSQgcGFyYW1ldGVyLCBhcyB0aGUgdmFsdWUgb2YgJFxhbHBoYSQgdHJhZGl0aW9uYWxseSBjb250cm9scyB0aGUgaG9yaXpvbnRhbCBsb2NhdGlvbiBvZiBhIGN1cnZlJ3MgcGVhayBhbmQgZGVjbGluZS4KCmBgYHtyLCBmaWcuaGVpZ2h0PTV9Cmhpc3QoRGF5cywgCiAgICAgbWFpbiA9ICJEaXN0cmlidXRpb24gb2YgUmVjb3ZlcnkgVGltZXMiLAogICAgIHhsYWIgPSAiUmVjb3ZlcnkgVGltZSAoRGF5cykiLAogICAgIHlsYWIgPSAiUHJvYmFiaWxpdHkgRGVuc2l0eSIsCiAgICAgeWxpbSA9IGMoMCwgMC4wNSksCiAgICAgYnJlYWtzID0gMTAsCiAgICAgcHJvYiA9IFRSVUUpCgoKY3VydmUoUERGX0Z1bmN0aW9uKHggLCBhbHBoYSA9IDMyLjY1NDMxLCBiZXRhID0gNi4wMDYyNDgpLCAKICAgICAgY29sID0gInJlZCIsCiAgICAgIGx3ZCA9IDMsCiAgICAgIGFkZCA9IFRSVUUpCgpsZWdlbmQoInRvcHJpZ2h0IiwKICAgICAgIGxlZ2VuZCA9ICJGaXNrICgzMi42NSwgNi4wNykiLAogICAgICAgY29sID0gInJlZCIsCiAgICAgICBsd2QgPSAzLAogICAgICAgYm94Lmx3ZD0zKQoKYm94KGx3ZD0zKQpgYGAKCgojIyAyYi4pIApHaXZlbiB0aGUgaW5oZXJlbnQgdmFyaWF0aW9uIHRoYXQgZXhpc3RzIGluIHNhbXBsaW5nLCBJIGNob3NlIHRvIGV4ZWN1dGUgYSBib290c3RyYXBwaW5nIHNlcXVlbmNlLiBJIHBlcmZvcm1lZCAxLDAwMCBpdGVyYXRpb25zIG9mIHNhbXBsZXMgKG4gPSA1MCBlYWNoIHRpbWUpIGZvciBib3RoIG91ciBwYXJhbWV0ZXJzIGVzdGltYXRvcnMsICRcaGF0e1xhbHBoYX0kIGFuZCAkXGhhdHtcYmV0YX0kLiAKClBpY3R1cmVkIGJlbG93IGFyZSB0aGUgc2FtcGxpbmcgZGlzdHJpYnV0aW9ucyBmb3IgYm90aCBwYXJhbWV0ZXJzLCBlYWNoIG9mIHRoZW0gd2l0aCBhIEdhdXNzaWFuIGtlcm5lbCBkZW5zaXR5IGN1cnZlIGxheWVyZWQgYWJvdmUgYW5kIHNhaWQgY3VydmUncyByZXNwZWN0aXZlIGJhbmR3aWR0aCBub3RhdGVkIGluIHBhcmVudGhlc2VzLiBCYW5kd2lkdGhzIHdlcmUgY2hvc2VuIGluIGFjY29yZGFuY2Ugd2l0aCBTaWx2ZXJtYW4ncyBzdGFuZGFyZCBmb3JtdWxhIGFuZCBjYWxjdWxhdGVkIHZpYSBhIGN1c3RvbS1idWlsdCBSIGZ1bmN0aW9uLgoKYGBge3J9CiMgQm9vdHN0cmFwIENhbGN1bGF0aW9ucwpzZXQuc2VlZCgxMDApCgpBbHBoYV9Cb290c3RyYXBzID0gMApCZXRhX0Jvb3RzdHJhcHMgPSAwCiAgIyBTZXQgdGhlc2UgdmFyaWFibGVzIGVxdWFsIHRvIHplcm8gYXMgdGhleSB3aWxsIGJlIGNvbnN0YW50bHkgdXBkYXRlZCB0aHJvdWdob3V0IHRoZSBmb3IgbG9vcCdzIGl0ZXJhdGlvbnMKCmZvcihpIGluIDE6MTAwMCl7CiAgaXRoX1NhbXBsZSA9IHNhbXBsZShEYXlzLCBzaXplID0gbGVuZ3RoKERheXMpLCByZXBsYWNlID0gVFJVRSkKICAgICMgQWx3YXlzIHVzZSByZXBsYWNlbWVudCB3aGVuIGJvb3RzdHJhcHBpbmcKICBpdGhfTW9tZW50MSA9IG1lYW4oaXRoX1NhbXBsZSkKICBpdGhfTW9tZW50MiA9IG1lYW4oaXRoX1NhbXBsZV4yKQogIAojIENvcGllZCBmdW5jdGlvbiBmcm9tIHBhcnQgMmE6IHJlbW92ZWQgY29tbWVudHMgYXMgcHJvY2VzcyBpcyB0aGUgc2FtZSBmb3IgZWFjaCBib290c3RyYXAgc2FtcGxlCiAgICAjIHVwZGF0ZWQgdmFyaWFibGUgbmFtZXMgZm9yIHRoZSBib290c3RyYXAgcHJvY2VkdXJlCiAgICBCb290X0JldGFfSGF0ID0gdW5pcm9vdChmdW5jdGlvbihCZXRhKXsKICAgIEEgPSAocGkvQmV0YSkvCiAgICAgICAgICBzaW4ocGkvQmV0YSkKICAgIAogICAgQiA9ICgyKnBpL0JldGEpLwogICAgICAgIHNpbigyKnBpL0JldGEpCiAgICAKICAgIEFscGhhX0JldGEgPSBpdGhfTW9tZW50MSAvIEEKICAgIEFscGhhX0JldGFeMiAqIChCIC0gQV4yKSAtIChpdGhfTW9tZW50MiAtIGl0aF9Nb21lbnQxXjIpCiAgfSwgbG93ZXIgPSAyLjAwMDAwMSwgdXBwZXIgPSAyMDAwMDAwKSRyb290CiAgCiAgQm9vdF9BbHBoYV9IYXQgPSBpdGhfTW9tZW50MSAvICgocGkvQmV0YV9IYXQpL3NpbihwaS9CZXRhX0hhdCkpCiAgCiAgQWxwaGFfQm9vdHN0cmFwc1tpXSA9IEJvb3RfQWxwaGFfSGF0CiAgQmV0YV9Cb290c3RyYXBzW2ldID0gQm9vdF9CZXRhX0hhdAp9CmBgYAoKCmBgYHtyLCBmaWcuaGVpZ2h0PTV9CgojIyBDcmVhdGUgY3VzdG9tIGZ1bmN0aW9uIGZvciBmaW5kaW5nIEdhdXNzaWFuIGJ3IHF1aWNrbHkgaW4gZnV0dXJlCkdhdXNzaWFuX0JXID0gZnVuY3Rpb24oRGF0YSl7CiAgSVFSID0gcXVhbnRpbGUoRGF0YSwgMC43NSkgLSBxdWFudGlsZShEYXRhLCAwLjI1KQogIE1pbl9QYXJ0ID0gbWluKHNkKERhdGEpLChJUVIvMS4zNCkpCiAgQlcgPSAwLjkgKiBNaW5fUGFydCAqIChsZW5ndGgoRGF0YSleKC0wLjIpKQogIHJldHVybihCVykKfQoKaW52aXNpYmxlKAogIEdhdXNzaWFuX0JXKERhdGEgPSBBbHBoYV9Cb290c3RyYXBzKSAjID0gMC4zMTgzMDk5CikKCgpoaXN0KEFscGhhX0Jvb3RzdHJhcHMsCiAgICAgbWFpbiA9ICJCb290c3RyYXAgRGlzdHJpYnV0aW9uIG9mIEFscGhhIEhhdCIsCiAgICAgeGxhYiA9ICJTYW1wbGluZyBNZWFucyIsCiAgICAgeWxhYiA9ICJQcm9iYWJpbGl0eSBEZW5zaXR5IiwKICAgICBwcm9iID0gVFJVRQogICAgICkKCiMgYmFuZHdpZHRoIGNhbGN1bGF0aW9ucyBiZWxvdwpHYXVzc2lhbiA9IGRlbnNpdHkoQWxwaGFfQm9vdHN0cmFwcywgYncgPSAwLjMxODMwOTksIGtlcm5lbCA9ICJnYXVzc2lhbiIpCmxpbmVzKEdhdXNzaWFuLAogICAgICBsd2QgPSAzLAogICAgICBjb2wgPSAiYmx1ZSIKICAgICAgKQoKbGVnZW5kKCJ0b3ByaWdodCIsCiAgICAgICBsZWdlbmQgPSAiR2F1c3NpYW4gKDAuMzIpIiwKICAgICAgIGNvbCA9ICJibHVlIiwKICAgICAgIGx3ZCA9IDMsCiAgICAgICBib3gubHdkPTMpCgpib3gobHdkPTMpCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQ9NX0KCmludmlzaWJsZSgKICBHYXVzc2lhbl9CVyhEYXRhID0gQmV0YV9Cb290c3RyYXBzKSAjID0gMC4xMzAzMjg2CikKCmhpc3QoQmV0YV9Cb290c3RyYXBzLAogICAgIG1haW4gPSAiQm9vdHN0cmFwIERpc3RyaWJ1dGlvbiBvZiBCZXRhIEhhdCIsCiAgICAgeGxhYiA9ICJTYW1wbGluZyBNZWFucyIsCiAgICAgeWxhYiA9ICJQcm9iYWJpbGl0eSBEZW5zaXR5IiwKICAgICBwcm9iID0gVFJVRSwKICAgICB5bGltID0gYygwLDAuNykKICAgICApCmJveChsd2Q9MykKCkdhdXNzaWFuID0gZGVuc2l0eShCZXRhX0Jvb3RzdHJhcHMsIGJ3ID0gMC4xMzAzMjg2LCBrZXJuZWwgPSAiZ2F1c3NpYW4iKQpsaW5lcyhHYXVzc2lhbiwKICAgICAgbHdkID0gMywKICAgICAgY29sID0gImJsdWUiCiAgICAgICkKCmxlZ2VuZCgidG9wcmlnaHQiLAogICAgICAgbGVnZW5kID0gIkdhdXNzaWFuICgwLjEzKSIsCiAgICAgICBjb2wgPSAiYmx1ZSIsCiAgICAgICBsd2QgPSAzLAogICAgICAgYm94Lmx3ZD0zKQoKYGBgCgpXaGF0IHRoZSBib290c3RyYXAgZGlzdHJpYnV0aW9uIGZvciAkXGhhdHtcYWxwaGF9JCBhbmQgJFxoYXR7XGJldGF9JCBkaXNwbGF5IGlzIGEgZmFyICpncmVhdGVyKiByZXNlbWJsYW5jZSB3aXRoIHRoZWlyIEdhdXNzaWFuIFBERiBlc3RpbWF0aW9ucyB0aGFuIHdoYXQgd2FzIHNlZW4gYWJvdmUsIGNvbXBhcmluZyBvdXIgZGF0YSB0byB0aGUgY3VydmUgb2YgYSBzdGFuZGFyZCBGaXNrIGRpc3RyaWJ1dGlvbiB3aXRoIHNhaWQgdmFsdWVzIGZvciAkXGFscGhhJCBhbmQgJFxiZXRhJC4gCgpUd28gcG9zc2libGUgc3VnZ2VzdGlvbnMgdGhhdCB0aGlzIHJlbGV2YXRpb24gYnJpbmdzIGFyZTogcGVyaGFwcyB0aGUgcG9wdWxhdGlvbiBmcm9tIHdoaWNoIHRoZXNlIHNhbXBsZWQgc3VyZ2VyeSByZWNvdmVyeSB0aW1lcyBjYW1lIGZyb20gaXMgbm90IHRydWx5IGFzIEZpc2sgZGlzdHJpYnV0ZWQgYXMgd2UgaW5pdGlhbGx5IGJlbGlldmVkLCBvciBhcyBzdGF0ZWQgcHJldmlvdXNseSB0aGVyZSBjb3VsZCBiZSBhbiB1bmRlcmVzdGltYXRlIG9mIHRoZSAkXGFscGhhJCBwYXJhbWV0ZXIuCg==