R Functions

  1. dpois
  2. ppois
  3. rpois

Random variable X is distributed \(X \sim P(\lambda)\) with mean \(\mu = \lambda\) and variance \(\sigma^2 = \lambda\) , if X=x is the number of successes in n (many) trials when the probability of success \(\lambda/n\) is small. The probability of X=k successes is \(P(X=k) = \frac {(e^{\lambda} * \lambda^k)} {k!}\) .

  1. R function dpois(x, lambda) is the probability of x successes in a period when the expected number of events is lambda.
  2. R function ppois(q, lambda, lower.tail) is the cumulative probability of less than or equal to q successes.
  3. R function rpois(n, lambda) returns n random numbers from the Poisson distribution x ~ P(lambda)

Examples

Example 1

What is the probability of making 2 to 4 sales in a week if the average sales rate is 3 per week?

# Using cumulative probability
ppois(q = 4, lambda = 3, lower.tail = TRUE) - 
  ppois(q = 1, lambda = 3, lower.tail = TRUE)
[1] 0.62
# Using exact probability
dpois(x = 2, lambda = 3) +
  dpois(x = 3, lambda = 3) +
  dpois(x = 4, lambda = 4)
[1] 0.64
# expected number of sales = lambda = 3

# variance = lambda = 3

library(ggplot2)
library(dplyr)
options(scipen = 999, digits = 2) # sig digits

events <- 0:10
density <- dpois(x = events, lambda = 3)
prob <- ppois(q = events, lambda = 3, lower.tail = TRUE)
df <- data.frame(events, density, prob)
df %>% ggplot( aes(x = factor(events), y = density)) +
  geom_col() +
  geom_text(
    aes(label = round(density,2), y = density + 0.01),
    position = position_dodge(0.9),
    size = 3,
    vjust = 0
  ) +
  labs(title = "PMF and CDF of Poisson Distribution",
       subtitle = "P(3).",
       x = "Events (x)",
       y = "Density") +
  geom_line(aes(x = events, y = prob))

Example 2 Suppose a baseball player has a p=.3 batting average. What is the probability of X<=150 hits in n=500 at bats? X=150? X>150?

# probability of x <= 150
ppois(q = 150, lambda = .3 * 500, lower.tail = TRUE)
[1] 0.52
# probability of x = 150
dpois(x = 150, lambda = .300 * 500)
[1] 0.033
# probability of x > 150
ppois(q = 150, lambda = .3 * 500, lower.tail =  FALSE) 
[1] 0.48

library(ggplot2)
library(dplyr)
options(scipen = 999, digits = 2) # sig digits

hits <- 0:300  
density <- dpois(x = hits, lambda = .300 * 500)
prob <- ppois(q = hits, lambda = .300 * 500, lower.tail = TRUE)
df <- data.frame(hits, density, prob)
ggplot(df, aes(x = hits, y = density)) +
  geom_col() +
  labs(title = "Poisson(150)",
       subtitle = "PMF and CDF of Poisson(150) distribution.",
       x = "Hits (x)",
       y = "Density") +
  geom_line(data = df, aes(x = hits, y = prob))

NA
NA

Example 3 If electricity power failures occur according to a Poisson distribution with an average of 3 failures every twenty weeks, calculate the probability that there will not be more than one failure during a particular week.

#"Not more than one failure" means we need to include the probabilities
#for "0 failures" plus "1 failure".

lamda <- 3/20 #per week
ppois(5,lamda , lower.tail = TRUE)
[1] 1
lamda <- 3/20 #per week
hits <- 0:10  
density <- dpois(x = hits, lambda =lamda)
prob <- ppois(q = hits, lambda = lamda, lower.tail = TRUE)
df <- data.frame(hits, density, prob)
ggplot(df, aes(x = hits, y = density)) +
  geom_col() +
  labs(title = "Poisson(3/20)",
       subtitle = "PMF and CDF of Poisson(3/20) distribution.",
       x = "Hits (x)",
       y = "Density") +
   geom_text(
    aes(label = round(density,2), y = density + 0.01),
    position = position_dodge(0.9),
    size = 3,
    vjust = 0
  ) +
  geom_line(data = df, aes(x = hits, y = prob))

Example 4 Suppose a bank knows that on average 60 customers arrive between 10 A.M. and 11 A.M. daily. Thus 1 customer arrives per minute. Find the probability that exactly two customers arrive in a given one minute time interval between 10 and 11 A.M.

dpois(2 , lambda = 1 )
[1] 0.18
lamda <- 1  #per minute 
hits <- 0:5  
density <- dpois(x = hits, lambda =lamda)
prob <- ppois(q = hits, lambda = lamda, lower.tail = TRUE)
df <- data.frame(hits, density, prob)
ggplot(df, aes(x = hits, y = density)) +
  geom_col(aes(fill = density)) +
  labs(title = "Poisson(1)",
       subtitle = "PMF and CDF of Poisson(1) distribution.",
       x = "Hits (x)",
       y = "Density") +
   geom_text(
    aes(label = round(density,2), y = density + 0.01),
    position = position_dodge(0.9),
    size = 3,
    vjust = 0
  ) +
  geom_line(data = df, aes(x = hits, y = prob ) )

Find the Estimator

Using The Moments Estimation

The Method of moments

Population moments \(M_r = E(x^r)\)

  1. \(M_0 = E(x^0) = E(1) = 1\)
  2. \(M_1 = E(x^1) = E(x) = \mu\) Population mean
  3. \(M_2 = E(x^2)\)
    \(\sigma^2 = M_2 - M_1^2\) Population Variance

Sample Moment

\(m_r = \frac{1}{n} \sum_{i = 1}^{n}{x_i^r}\)

  1. \(m_0 = \frac{1}{n} \sum_{i = 1}^{n}{x_i^0} = \frac{1}{n} *n = 1\)
  2. \(m_1 = \frac{1}{n} \sum_{i = 1}^{n}{x_i} = \bar{x}\)
  3. \(m_2 = \frac{1}{n} \sum_{i = 1}^{n}{x_i^2}\)
    \(s^2 = m_2 - m_1^2\) sample Variance

Let \(X \sim P(\lambda)\) , Find MME of \(\lambda\)

Population > Equation 1: $M_1 = E(x^1) = E(x) = = $

Sample > Equation 2 : \(m_1 = \frac{1}{n} \sum_{i = 1}^{n}{x_i} = \bar{x}\)

from equation(1) and equation(2)

\(M_1=m_1\) then \(\lambda = \bar{x}\)

Thus, the MME equal:

\(\lambda = \bar{x}\)

Maximum likelihood Estimation

Find MLE Poisson Distribution

Step 1: Write the PDF. \(f(x,\lambda) = \frac {(e^{-\lambda} \lambda^x)} {x!}\)

Step 2: Write the likelihood function. \(L(\lambda , x_1,x_2,...,x_n) = \prod_{x = 1}^{n} f(x,\lambda)\)

Step 3: Write the natural log likelihood function. \(L(\lambda , x_1,x_2,...,x_n) = ln(\prod_{x = 1}^{n} f(x,\lambda))\)

\(L(\lambda, x_1,x_2,...,x_n) = \sum_{x = 1}^{n} ln(f(x,\lambda))\)

\(L(\lambda , x_1,x_2,...,x_n) = ln(f(\lambda,x_1)) + ln(f(\lambda,x_2)) + ..... + ln(f(\lambda,x_n))\)

\(L(\lambda, x_1,x_2,...,x_n) = ln(\frac {(e^{-\lambda} \lambda^{x_1})} {x_1!}) + ln(\frac {(e^{-\lambda} \lambda^{x_2})} {x_2!}) + ..... + ln(\frac {(e^{\lambda} \lambda^{x_n})} {x_n!})\)

\(L(\lambda , x_1,x_2,...,x_n) = (-\lambda + x_1ln(\lambda) -log(x_1!)) + (-\lambda + x_2ln(\lambda) -log(x_2!)) + .... + (-\lambda + x_nln(\lambda) -log(x_n!))\)

\(L(\lambda , x_1,x_2,...,x_n) = -n\lambda + \sum_{i = 1}^{n}{x_i ln(\lambda)} - \sum_{i = 1}^{n}{x_i!}\)

Step 4: Calculate the derivative of the natural log likelihood function with respect to λ.

\(\frac {dL}{d\lambda} = -n + \sum_{i = 1}^{n}{x_i} * \frac{1}{\lambda} - 0\)

Step 5: Set the derivative equal to zero and solve for λ. \(\frac {dL}{d\lambda} = 0\)

\(-n + \sum_{i = 1}^{n}{x_i} * \frac{1}{\lambda} = 0\)

\(n = \frac{ \sum_{i = 1}^{n}{x_i}}{\lambda}\)

Thus, the MLE equal: \(\lambda = \frac{ \sum_{i = 1}^{n}{x_i}}{n}\)

\(\lambda = \bar{x}\)

SOME PROPERTIES OF ESTIMATORS

Unbiased Estimator (UE):

An estimator \(\hat\theta\) is an UE of the unknown parameter \(\theta\) ,if

\(E[\hat\theta]=\theta\) for all \(\theta \in \Omega\)

Otherwise, it is a Biased Estimator of \(\theta\).

Check if \(\bar{x}\) is Unbiased Estimator

\(E(\lambda) = \lambda\)

\(E(\bar{x}) = E(\frac{ \sum_{i = 1}^{n}{x_i}}{n})\)

\(= \frac{1}{n} E (\sum_{i = 1}^{n}{x_i})\)

\(=\frac{1}{n} \lambda n\)

\(=\lambda\)

\(E(\bar{x}) = E(\lambda) = \lambda\)

then \(\bar{x}\) is Unbiased Estimator

Consistent Estimator (CE):

if estimator \(\hat\theta\) is an Unbiased Estimator of the unknown parameter \(\theta\) and \(\lim_{x \to \infty} var(\hat\theta) = 0\) then \(\hat\theta\) is Consistent Estimator of \(\theta\)

Check if \(\bar{x}\) is Consistent Estimator

\(\lim_{x \to \infty} var(\bar{x})\)

\(lim_{x \to \infty} var(\frac{\sum_{i = 1}^{n}{x_i}}{n})\)

\(lim_{x \to \infty} \frac{1}{n^2} var(\sum_{i = 1}^{n}{x_i})\)

\(lim_{x \to \infty} \frac{1}{n^2} n\lambda\)

\(lim_{x \to \infty} \frac{\lambda}{n}\)

\(= 0\)

then \(\bar{x}\) is Consistent Estimator

Computing Confidence Interval for Poisson Mean

For Poisson distribution, there are many different ways for calculating the confidence interval.

The most commonly used method is

  1. The normal approximation (for large sample size)

  2. The exact method (for small sample size)

Normal Approximation:

For Poisson, the mean and the variance are both lambda (\(\lambda\)).

The standard error is calculated as:\(sqrt(\lambda /n)\) where \(\lambda\) is Poisson mean and \(n\) is sample size

The confidence interval can be calculated as: \(\lambda - z(\alpha/2)*sqrt(\lambda /n) < \hat{\lambda} < \lambda + z(\alpha/2)*sqrt(\lambda /n)\)

The 95-percent confidence interval is calculated as: $- 1.96sqrt(/n) < < + 1.96sqrt(/n) $

The 99-percent confidence interval is calculated as: \(\lambda - 2.58*sqrt(\lambda /n) < \hat{\lambda} < \lambda + 2.58*sqrt(\lambda /n)\)

EXACT method:

The confidence interval for event X is calculated as:

\((qchisq(\alpha/2, 2*x)/2, qchisq(1-\alpha/2, 2*(x+1))/2 )\)

Where x is the number of events occurred under Poisson distribution.

In order to calculate the exact confidence interval for Poisson mean, the obtained confidence interval for the number of events need to be converted to the confidence interval for Poisson mean.

Example 1:

Find upper and lower confidence levels for a Poisson distribution Observations (\(n\)) = 88 Sample mean (\(\lambda\)) = 47.18182 what would the 95% confidence look like for this?

With Normal Approximation, the 95% confidence interval is calculated as:

lamda <-   47.18182
n <- 88

lower <- lamda - 1.96 * sqrt(lamda/n)
upper <- lamda + 1.96 * sqrt(lamda/n)

lower 
[1] 46
upper 
[1] 49

With Exact method, we first need to calculate x (# of events):

lamda <-   47.18182
n <- 88
x = lamda * n 
alph <- 0.05
lower <- qchisq(alph/2,2*x)/2
upper <-  qchisq(1-alph/2,2*(x+1))/2

lower
[1] 4027
upper
[1] 4280

The 95% confidence interval for mean (\(\lambda\)) is therefore:

lower_bound <- lower/n
upper_bound <- upper/n

lower_bound
[1] 46
upper_bound
[1] 49

Using R

  1. Generate 1000 random number with (\(\lambda\)) = 50
  2. choose sample of size n = 40
  3. calculate \(\bar{x}\)
  4. compute the 95% confidence interval
population_size <- 1000
sample_size_n <- 40
population_lamda <- 50


#step 1
population <- rpois(population_size,population_lamda)

#step 2
sample <- sample(population , sample_size_n ,FALSE )

#step 3
x_bar <- mean(sample)

#step 4
# confidence interval using Normal Approximation
lamda_hat <-   x_bar
lower_95 <- lamda_hat - 1.96 * sqrt(lamda_hat/sample_size_n)
upper_95 <- lamda_hat + 1.96 * sqrt(lamda_hat/sample_size_n)

x_bar
[1] 50
lower_95 
[1] 48
upper_95 
[1] 52
 

by using previous example but with 99% confidence interval

sample_size_n <- 40

#step 3
# confidence interval using Normal Approximation
lamda_hat <-   x_bar
lower_99 <- lamda_hat - 2.58 * sqrt(lamda_hat/sample_size_n)
upper_99 <- lamda_hat + 2.58 * sqrt(lamda_hat/sample_size_n)

x_bar
[1] 50
lower_99 
[1] 47
upper_99
[1] 53

by using previous example but with large sample size n=600

sample_size_n <- 600
#step 2
sample <- sample(population , sample_size_n ,FALSE )

#step 3
x_bar <- mean(sample)

#step 3
# confidence interval using Normal Approximation
lamda_hat <-   x_bar
lower <- lamda_hat - 1.96 * sqrt(lamda_hat/sample_size_n)
upper <- lamda_hat + 1.96 * sqrt(lamda_hat/sample_size_n)

x_bar
[1] 50
lower 
[1] 49
upper 
[1] 50

Sampling Distribution for

\[\bar{x}\]

Calculate x bar for 1000 different sample from same population and check if these x bar belong to interval [lower,upper]

1. With Confidence 95%

2. With Confidence 99%

 results = NULL

for(i in 1:1000){
  sample_size_n <- 40
  sample <- sample(population , sample_size_n ,FALSE )
  x_bar <- mean(sample)
  results = rbind(results, data.frame(i,x_bar))
}

# plot sample distribution for X bar
library(dplyr)
results %>% ggplot(mapping = aes(x = x_bar)) + 
  geom_histogram(aes(y=..density..) ,  colour="black", fill="white")+
 geom_density(alpha=.2, fill="#FF6666") +
geom_vline(aes(xintercept = upper_95), colour="red") +
geom_vline(aes(xintercept = lower_95), colour="red") +
  geom_vline(aes(xintercept = upper_99), colour="blue" ,  linetype="dashed", size=1) +
geom_vline(aes(xintercept = lower_99), colour="blue") +
      labs(title = "X Bar Sample Distribution" , subtitle = "With 95% and 99% Confidance Intervals ") + 
  xlab("X Bar") + ylab("count")
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.

NA
NA

simulationResult_95 <- mean(lower_95<results$x_bar &  results$x_bar<upper_95)
simulationResult_99 <- mean(lower_99<results$x_bar &  results$x_bar<upper_99)

simulationResult_95
[1] 0.96
simulationResult_99
[1] 0.99

the result after this simulation show us that about 95% of samples has x bar between the lower and upper calculated values when confidence level equal 95% , also about 99% of samples has x bar between the lower and upper calculated values when confidence level equal 99%

LS0tDQp0aXRsZTogIlRoZSBQb2lzc29uIERpc3RyaWJ1dGlvbiINCmF1dGhvcjogIkl5YWQgQWxrcnVueiINCm91dHB1dDoNCiAgaHRtbF9ub3RlYm9vazogZGVmYXVsdA0KICB3b3JkX2RvY3VtZW50OiBkZWZhdWx0DQotLS0NCg0KIyBSIEZ1bmN0aW9ucw0KDQoxLiAgKipkcG9pcyoqDQoyLiAgKipwcG9pcyoqDQozLiAgKipycG9pcyoqDQoNClJhbmRvbSB2YXJpYWJsZSBYIGlzIGRpc3RyaWJ1dGVkICRYIFxzaW0gUChcbGFtYmRhKSQgd2l0aCBtZWFuICRcbXUgPSBcbGFtYmRhJCBhbmQgdmFyaWFuY2UgJFxzaWdtYV4yID0gXGxhbWJkYSQgLCBpZiBYPXggaXMgdGhlIG51bWJlciBvZiBzdWNjZXNzZXMgaW4gbiAobWFueSkgdHJpYWxzIHdoZW4gdGhlIHByb2JhYmlsaXR5IG9mIHN1Y2Nlc3MgJFxsYW1iZGEvbiQgaXMgc21hbGwuIFRoZSBwcm9iYWJpbGl0eSBvZiBYPWsgc3VjY2Vzc2VzIGlzICRQKFg9aykgPSBcZnJhYyB7KGVee1xsYW1iZGF9ICogXGxhbWJkYV5rKX0ge2shfSQgLg0KDQoxLiAgUiBmdW5jdGlvbiBgZHBvaXMoeCwgbGFtYmRhKWAgaXMgdGhlIHByb2JhYmlsaXR5IG9mIHggc3VjY2Vzc2VzIGluIGEgcGVyaW9kIHdoZW4gdGhlIGV4cGVjdGVkIG51bWJlciBvZiBldmVudHMgaXMgbGFtYmRhLg0KMi4gIFIgZnVuY3Rpb24gYHBwb2lzKHEsIGxhbWJkYSwgbG93ZXIudGFpbClgIGlzIHRoZSBjdW11bGF0aXZlIHByb2JhYmlsaXR5IG9mIGxlc3MgdGhhbiBvciBlcXVhbCB0byBxIHN1Y2Nlc3Nlcy4NCjMuICBSIGZ1bmN0aW9uIGBycG9pcyhuLCBsYW1iZGEpYCByZXR1cm5zIG4gcmFuZG9tIG51bWJlcnMgZnJvbSB0aGUgUG9pc3NvbiBkaXN0cmlidXRpb24gYHggfiBQKGxhbWJkYSlgDQoNCg0KIyMgRXhhbXBsZXMNCg0KKipFeGFtcGxlIDEqKg0KDQpXaGF0IGlzIHRoZSBwcm9iYWJpbGl0eSBvZiBtYWtpbmcgMiB0byA0IHNhbGVzIGluIGEgd2VlayBpZiB0aGUgYXZlcmFnZSBzYWxlcyByYXRlIGlzIDMgcGVyIHdlZWs/DQoNCmBgYHtyfQ0KIyBVc2luZyBjdW11bGF0aXZlIHByb2JhYmlsaXR5DQpwcG9pcyhxID0gNCwgbGFtYmRhID0gMywgbG93ZXIudGFpbCA9IFRSVUUpIC0gDQogIHBwb2lzKHEgPSAxLCBsYW1iZGEgPSAzLCBsb3dlci50YWlsID0gVFJVRSkNCmBgYA0KDQpgYGB7cn0NCiMgVXNpbmcgZXhhY3QgcHJvYmFiaWxpdHkNCmRwb2lzKHggPSAyLCBsYW1iZGEgPSAzKSArDQogIGRwb2lzKHggPSAzLCBsYW1iZGEgPSAzKSArDQogIGRwb2lzKHggPSA0LCBsYW1iZGEgPSA0KQ0KDQpgYGANCg0KYGBge3J9DQojIGV4cGVjdGVkIG51bWJlciBvZiBzYWxlcyA9IGxhbWJkYSA9IDMNCg0KIyB2YXJpYW5jZSA9IGxhbWJkYSA9IDMNCg0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShkcGx5cikNCm9wdGlvbnMoc2NpcGVuID0gOTk5LCBkaWdpdHMgPSAyKSAjIHNpZyBkaWdpdHMNCg0KZXZlbnRzIDwtIDA6MTANCmRlbnNpdHkgPC0gZHBvaXMoeCA9IGV2ZW50cywgbGFtYmRhID0gMykNCnByb2IgPC0gcHBvaXMocSA9IGV2ZW50cywgbGFtYmRhID0gMywgbG93ZXIudGFpbCA9IFRSVUUpDQpkZiA8LSBkYXRhLmZyYW1lKGV2ZW50cywgZGVuc2l0eSwgcHJvYikNCmRmICU+JSBnZ3Bsb3QoIGFlcyh4ID0gZmFjdG9yKGV2ZW50cyksIHkgPSBkZW5zaXR5KSkgKw0KICBnZW9tX2NvbCgpICsNCiAgZ2VvbV90ZXh0KA0KICAgIGFlcyhsYWJlbCA9IHJvdW5kKGRlbnNpdHksMiksIHkgPSBkZW5zaXR5ICsgMC4wMSksDQogICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgwLjkpLA0KICAgIHNpemUgPSAzLA0KICAgIHZqdXN0ID0gMA0KICApICsNCiAgbGFicyh0aXRsZSA9ICJQTUYgYW5kIENERiBvZiBQb2lzc29uIERpc3RyaWJ1dGlvbiIsDQogICAgICAgc3VidGl0bGUgPSAiUCgzKS4iLA0KICAgICAgIHggPSAiRXZlbnRzICh4KSIsDQogICAgICAgeSA9ICJEZW5zaXR5IikgKw0KICBnZW9tX2xpbmUoYWVzKHggPSBldmVudHMsIHkgPSBwcm9iKSkNCmBgYA0KDQoqKkV4YW1wbGUgMioqIFN1cHBvc2UgYSBiYXNlYmFsbCBwbGF5ZXIgaGFzIGEgcD0uMyBiYXR0aW5nIGF2ZXJhZ2UuIFdoYXQgaXMgdGhlIHByb2JhYmlsaXR5IG9mIFhcPD0xNTAgaGl0cyBpbiBuPTUwMCBhdCBiYXRzPyBYPTE1MD8gWFw+MTUwPw0KDQpgYGB7cn0NCiMgcHJvYmFiaWxpdHkgb2YgeCA8PSAxNTANCnBwb2lzKHEgPSAxNTAsIGxhbWJkYSA9IC4zICogNTAwLCBsb3dlci50YWlsID0gVFJVRSkNCmBgYA0KDQpgYGB7cn0NCiMgcHJvYmFiaWxpdHkgb2YgeCA9IDE1MA0KZHBvaXMoeCA9IDE1MCwgbGFtYmRhID0gLjMwMCAqIDUwMCkNCmBgYA0KDQpgYGB7cn0NCiMgcHJvYmFiaWxpdHkgb2YgeCA+IDE1MA0KcHBvaXMocSA9IDE1MCwgbGFtYmRhID0gLjMgKiA1MDAsIGxvd2VyLnRhaWwgPSAgRkFMU0UpIA0KYGBgDQoNCmBgYHtyfQ0KDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KGRwbHlyKQ0Kb3B0aW9ucyhzY2lwZW4gPSA5OTksIGRpZ2l0cyA9IDIpICMgc2lnIGRpZ2l0cw0KDQpoaXRzIDwtIDA6MzAwICANCmRlbnNpdHkgPC0gZHBvaXMoeCA9IGhpdHMsIGxhbWJkYSA9IC4zMDAgKiA1MDApDQpwcm9iIDwtIHBwb2lzKHEgPSBoaXRzLCBsYW1iZGEgPSAuMzAwICogNTAwLCBsb3dlci50YWlsID0gVFJVRSkNCmRmIDwtIGRhdGEuZnJhbWUoaGl0cywgZGVuc2l0eSwgcHJvYikNCmdncGxvdChkZiwgYWVzKHggPSBoaXRzLCB5ID0gZGVuc2l0eSkpICsNCiAgZ2VvbV9jb2woKSArDQogIGxhYnModGl0bGUgPSAiUG9pc3NvbigxNTApIiwNCiAgICAgICBzdWJ0aXRsZSA9ICJQTUYgYW5kIENERiBvZiBQb2lzc29uKDE1MCkgZGlzdHJpYnV0aW9uLiIsDQogICAgICAgeCA9ICJIaXRzICh4KSIsDQogICAgICAgeSA9ICJEZW5zaXR5IikgKw0KICBnZW9tX2xpbmUoZGF0YSA9IGRmLCBhZXMoeCA9IGhpdHMsIHkgPSBwcm9iKSkNCg0KDQpgYGANCg0KKipFeGFtcGxlIDMqKiBJZiBlbGVjdHJpY2l0eSBwb3dlciBmYWlsdXJlcyBvY2N1ciBhY2NvcmRpbmcgdG8gYSBQb2lzc29uIGRpc3RyaWJ1dGlvbiB3aXRoIGFuIGF2ZXJhZ2Ugb2YgMyBmYWlsdXJlcyBldmVyeSB0d2VudHkgd2Vla3MsIGNhbGN1bGF0ZSB0aGUgcHJvYmFiaWxpdHkgdGhhdCB0aGVyZSB3aWxsIG5vdCBiZSBtb3JlIHRoYW4gb25lIGZhaWx1cmUgZHVyaW5nIGEgcGFydGljdWxhciB3ZWVrLg0KDQpgYGB7cn0NCiMiTm90IG1vcmUgdGhhbiBvbmUgZmFpbHVyZSIgbWVhbnMgd2UgbmVlZCB0byBpbmNsdWRlIHRoZSBwcm9iYWJpbGl0aWVzDQojZm9yICIwIGZhaWx1cmVzIiBwbHVzICIxIGZhaWx1cmUiLg0KDQpsYW1kYSA8LSAzLzIwICNwZXIgd2Vlaw0KcHBvaXMoNSxsYW1kYSAsIGxvd2VyLnRhaWwgPSBUUlVFKQ0KDQpgYGANCg0KYGBge3J9DQpsYW1kYSA8LSAzLzIwICNwZXIgd2Vlaw0KaGl0cyA8LSAwOjEwICANCmRlbnNpdHkgPC0gZHBvaXMoeCA9IGhpdHMsIGxhbWJkYSA9bGFtZGEpDQpwcm9iIDwtIHBwb2lzKHEgPSBoaXRzLCBsYW1iZGEgPSBsYW1kYSwgbG93ZXIudGFpbCA9IFRSVUUpDQpkZiA8LSBkYXRhLmZyYW1lKGhpdHMsIGRlbnNpdHksIHByb2IpDQpnZ3Bsb3QoZGYsIGFlcyh4ID0gaGl0cywgeSA9IGRlbnNpdHkpKSArDQogIGdlb21fY29sKCkgKw0KICBsYWJzKHRpdGxlID0gIlBvaXNzb24oMy8yMCkiLA0KICAgICAgIHN1YnRpdGxlID0gIlBNRiBhbmQgQ0RGIG9mIFBvaXNzb24oMy8yMCkgZGlzdHJpYnV0aW9uLiIsDQogICAgICAgeCA9ICJIaXRzICh4KSIsDQogICAgICAgeSA9ICJEZW5zaXR5IikgKw0KICAgZ2VvbV90ZXh0KA0KICAgIGFlcyhsYWJlbCA9IHJvdW5kKGRlbnNpdHksMiksIHkgPSBkZW5zaXR5ICsgMC4wMSksDQogICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgwLjkpLA0KICAgIHNpemUgPSAzLA0KICAgIHZqdXN0ID0gMA0KICApICsNCiAgZ2VvbV9saW5lKGRhdGEgPSBkZiwgYWVzKHggPSBoaXRzLCB5ID0gcHJvYikpDQpgYGANCg0KKipFeGFtcGxlIDQqKiBTdXBwb3NlIGEgYmFuayBrbm93cyB0aGF0IG9uIGF2ZXJhZ2UgNjAgY3VzdG9tZXJzIGFycml2ZSBiZXR3ZWVuIDEwIEEuTS4gYW5kIDExIEEuTS4gZGFpbHkuIFRodXMgMSBjdXN0b21lciBhcnJpdmVzIHBlciBtaW51dGUuIEZpbmQgdGhlIHByb2JhYmlsaXR5IHRoYXQgZXhhY3RseSB0d28gY3VzdG9tZXJzIGFycml2ZSBpbiBhIGdpdmVuIG9uZSBtaW51dGUgdGltZSBpbnRlcnZhbCBiZXR3ZWVuIDEwIGFuZCAxMSBBLk0uDQoNCmBgYHtyfQ0KZHBvaXMoMiAsIGxhbWJkYSA9IDEgKQ0KYGBgDQoNCmBgYHtyfQ0KbGFtZGEgPC0gMSAgI3BlciBtaW51dGUgDQpoaXRzIDwtIDA6NSAgDQpkZW5zaXR5IDwtIGRwb2lzKHggPSBoaXRzLCBsYW1iZGEgPWxhbWRhKQ0KcHJvYiA8LSBwcG9pcyhxID0gaGl0cywgbGFtYmRhID0gbGFtZGEsIGxvd2VyLnRhaWwgPSBUUlVFKQ0KZGYgPC0gZGF0YS5mcmFtZShoaXRzLCBkZW5zaXR5LCBwcm9iKQ0KZ2dwbG90KGRmLCBhZXMoeCA9IGhpdHMsIHkgPSBkZW5zaXR5KSkgKw0KICBnZW9tX2NvbChhZXMoZmlsbCA9IGRlbnNpdHkpKSArDQogIGxhYnModGl0bGUgPSAiUG9pc3NvbigxKSIsDQogICAgICAgc3VidGl0bGUgPSAiUE1GIGFuZCBDREYgb2YgUG9pc3NvbigxKSBkaXN0cmlidXRpb24uIiwNCiAgICAgICB4ID0gIkhpdHMgKHgpIiwNCiAgICAgICB5ID0gIkRlbnNpdHkiKSArDQogICBnZW9tX3RleHQoDQogICAgYWVzKGxhYmVsID0gcm91bmQoZGVuc2l0eSwyKSwgeSA9IGRlbnNpdHkgKyAwLjAxKSwNCiAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKDAuOSksDQogICAgc2l6ZSA9IDMsDQogICAgdmp1c3QgPSAwDQogICkgKw0KICBnZW9tX2xpbmUoZGF0YSA9IGRmLCBhZXMoeCA9IGhpdHMsIHkgPSBwcm9iICkgKQ0KYGBgDQpccGFnZWJyZWFrDQoNCiMgRmluZCB0aGUgRXN0aW1hdG9yDQoNCiMjIFVzaW5nIFRoZSBNb21lbnRzIEVzdGltYXRpb24NCg0KKipUaGUgTWV0aG9kIG9mIG1vbWVudHMqKg0KDQoqKlBvcHVsYXRpb24gbW9tZW50cyoqICRNX3IgPSBFKHhecikkDQoNCjEuICAkTV8wID0gRSh4XjApID0gRSgxKSA9IDEkXA0KMi4gICRNXzEgPSBFKHheMSkgPSBFKHgpID0gXG11JCBQb3B1bGF0aW9uIG1lYW4NCjMuICAkTV8yID0gRSh4XjIpJFwNCiAgICAkXHNpZ21hXjIgPSBNXzIgLSBNXzFeMiQgUG9wdWxhdGlvbiBWYXJpYW5jZQ0KDQoqKlNhbXBsZSBNb21lbnQqKg0KDQokbV9yID0gXGZyYWN7MX17bn0gXHN1bV97aSA9IDF9XntufXt4X2lecn0kDQoNCjEuICAkbV8wID0gXGZyYWN7MX17bn0gXHN1bV97aSA9IDF9XntufXt4X2leMH0gPSBcZnJhY3sxfXtufSAqbiA9IDEkDQoyLiAgJG1fMSA9IFxmcmFjezF9e259IFxzdW1fe2kgPSAxfV57bn17eF9pfSA9IFxiYXJ7eH0kDQozLiAgJG1fMiA9IFxmcmFjezF9e259IFxzdW1fe2kgPSAxfV57bn17eF9pXjJ9JFwNCiAgICAkc14yID0gbV8yIC0gbV8xXjIkIHNhbXBsZSBWYXJpYW5jZQ0KDQoNCg0KTGV0ICRYIFxzaW0gUChcbGFtYmRhKSQgLCBGaW5kIE1NRSBvZiAkXGxhbWJkYSQNCg0KUG9wdWxhdGlvbiA+IEVxdWF0aW9uIDE6DQokTV8xID0gRSh4XjEpID0gRSh4KSA9IFxtdSA9IFxsYW1iZGEgJA0KDQpTYW1wbGUgPiBFcXVhdGlvbiAyIDoNCiRtXzEgPSBcZnJhY3sxfXtufSBcc3VtX3tpID0gMX1ee259e3hfaX0gPSBcYmFye3h9JA0KDQpmcm9tIGVxdWF0aW9uKDEpIGFuZCBlcXVhdGlvbigyKSAgDQoNCiRNXzE9bV8xJCB0aGVuICRcbGFtYmRhID0gXGJhcnt4fSQNCg0KKipUaHVzLCB0aGUgTU1FIGVxdWFsOioqDQoNCiRcbGFtYmRhID0gXGJhcnt4fSQNCg0KIyMgTWF4aW11bSBsaWtlbGlob29kIEVzdGltYXRpb24NCg0KKipGaW5kIE1MRSBQb2lzc29uIERpc3RyaWJ1dGlvbioqDQoNCioqU3RlcCAxOiBXcml0ZSB0aGUgUERGLioqDQokZih4LFxsYW1iZGEpID0gXGZyYWMgeyhlXnstXGxhbWJkYX0gXGxhbWJkYV54KX0ge3ghfSQNCg0KKipTdGVwIDI6IFdyaXRlIHRoZSBsaWtlbGlob29kIGZ1bmN0aW9uLioqDQokTChcbGFtYmRhICwgeF8xLHhfMiwuLi4seF9uKSA9IFxwcm9kX3t4ID0gMX1ee259IGYoeCxcbGFtYmRhKSQNCg0KKipTdGVwIDM6IFdyaXRlIHRoZSBuYXR1cmFsIGxvZyBsaWtlbGlob29kIGZ1bmN0aW9uLioqDQokTChcbGFtYmRhICwgeF8xLHhfMiwuLi4seF9uKSA9IGxuKFxwcm9kX3t4ID0gMX1ee259IGYoeCxcbGFtYmRhKSkkDQoNCiRMKFxsYW1iZGEsIHhfMSx4XzIsLi4uLHhfbikgPSBcc3VtX3t4ID0gMX1ee259IGxuKGYoeCxcbGFtYmRhKSkkDQoNCiRMKFxsYW1iZGEgLCB4XzEseF8yLC4uLix4X24pID0gbG4oZihcbGFtYmRhLHhfMSkpICsgbG4oZihcbGFtYmRhLHhfMikpICsgLi4uLi4gKyBsbihmKFxsYW1iZGEseF9uKSkkDQoNCiRMKFxsYW1iZGEsIHhfMSx4XzIsLi4uLHhfbikgPSBsbihcZnJhYyB7KGVeey1cbGFtYmRhfSBcbGFtYmRhXnt4XzF9KX0ge3hfMSF9KSArIGxuKFxmcmFjIHsoZV57LVxsYW1iZGF9IFxsYW1iZGFee3hfMn0pfSB7eF8yIX0pICsgLi4uLi4gKyBsbihcZnJhYyB7KGVee1xsYW1iZGF9IFxsYW1iZGFee3hfbn0pfSB7eF9uIX0pJA0KDQokTChcbGFtYmRhICwgeF8xLHhfMiwuLi4seF9uKSA9ICgtXGxhbWJkYSArIHhfMWxuKFxsYW1iZGEpIC1sb2coeF8xISkpICsgKC1cbGFtYmRhICsgeF8ybG4oXGxhbWJkYSkgLWxvZyh4XzIhKSkgKyAuLi4uICsgKC1cbGFtYmRhICsgeF9ubG4oXGxhbWJkYSkgLWxvZyh4X24hKSkkDQoNCiRMKFxsYW1iZGEgLCB4XzEseF8yLC4uLix4X24pID0gLW5cbGFtYmRhICsgXHN1bV97aSA9IDF9XntufXt4X2kgbG4oXGxhbWJkYSl9IC0gXHN1bV97aSA9IDF9XntufXt4X2khfSQNCg0KKipTdGVwIDQ6IENhbGN1bGF0ZSB0aGUgZGVyaXZhdGl2ZSBvZiB0aGUgbmF0dXJhbCBsb2cgbGlrZWxpaG9vZCBmdW5jdGlvbiB3aXRoIHJlc3BlY3QgdG8gzrsuKioNCg0KJFxmcmFjIHtkTH17ZFxsYW1iZGF9ID0gLW4gKyBcc3VtX3tpID0gMX1ee259e3hfaX0gKiBcZnJhY3sxfXtcbGFtYmRhfSAtIDAkDQoNCioqU3RlcCA1OiBTZXQgdGhlIGRlcml2YXRpdmUgZXF1YWwgdG8gemVybyBhbmQgc29sdmUgZm9yIM67LioqDQokXGZyYWMge2RMfXtkXGxhbWJkYX0gPSAwJA0KDQokLW4gKyBcc3VtX3tpID0gMX1ee259e3hfaX0gKiBcZnJhY3sxfXtcbGFtYmRhfSA9IDAkDQoNCiRuID0gXGZyYWN7IFxzdW1fe2kgPSAxfV57bn17eF9pfX17XGxhbWJkYX0kDQoNCioqVGh1cywgdGhlIE1MRSBlcXVhbDoqKg0KJFxsYW1iZGEgPSBcZnJhY3sgXHN1bV97aSA9IDF9XntufXt4X2l9fXtufSQNCg0KJFxsYW1iZGEgPSBcYmFye3h9JA0KDQoNClxuZXdwYWdlDQoNCg0KIyBTT01FIFBST1BFUlRJRVMgT0YgRVNUSU1BVE9SUw0KDQojIyBVbmJpYXNlZCBFc3RpbWF0b3IgKFVFKTogDQoNCkFuIGVzdGltYXRvciAkXGhhdFx0aGV0YSQgaXMgYW4gVUUgb2YgdGhlIHVua25vd24gcGFyYW1ldGVyICRcdGhldGEkICxpZg0KDQokRVtcaGF0XHRoZXRhXT1cdGhldGEkICBmb3IgYWxsICAkXHRoZXRhIFxpbiBcT21lZ2EkDQoNCk90aGVyd2lzZSwgaXQgaXMgYSBCaWFzZWQgRXN0aW1hdG9yIG9mICRcdGhldGEkLg0KDQpDaGVjayBpZiAkXGJhcnt4fSQgaXMgVW5iaWFzZWQgRXN0aW1hdG9yDQoNCiRFKFxsYW1iZGEpID0gXGxhbWJkYSQNCg0KJEUoXGJhcnt4fSkgPSBFKFxmcmFjeyBcc3VtX3tpID0gMX1ee259e3hfaX19e259KSQNCg0KJD0gXGZyYWN7MX17bn0gRSAoXHN1bV97aSA9IDF9XntufXt4X2l9KSQNCg0KJD1cZnJhY3sxfXtufSAgXGxhbWJkYSBuJA0KDQokPVxsYW1iZGEkDQoNCiRFKFxiYXJ7eH0pID0gRShcbGFtYmRhKSA9IFxsYW1iZGEkDQoNCnRoZW4gJFxiYXJ7eH0kIGlzIFVuYmlhc2VkIEVzdGltYXRvcg0KDQpccGFnZWJyZWFrDQoNCiMjIENvbnNpc3RlbnQgRXN0aW1hdG9yIChDRSk6IA0KDQppZiBlc3RpbWF0b3IgJFxoYXRcdGhldGEkIGlzIGFuIFVuYmlhc2VkIEVzdGltYXRvciBvZiB0aGUgdW5rbm93biBwYXJhbWV0ZXIgJFx0aGV0YSQNCmFuZCAkXGxpbV97eCBcdG8gXGluZnR5fSB2YXIoXGhhdFx0aGV0YSkgPSAwJCAgdGhlbiAgJFxoYXRcdGhldGEkIGlzIENvbnNpc3RlbnQgRXN0aW1hdG9yIG9mICAkXHRoZXRhJCANCg0KQ2hlY2sgaWYgJFxiYXJ7eH0kIGlzIENvbnNpc3RlbnQgRXN0aW1hdG9yDQoNCiRcbGltX3t4IFx0byBcaW5mdHl9IHZhcihcYmFye3h9KSQNCg0KJGxpbV97eCBcdG8gXGluZnR5fSB2YXIoXGZyYWN7XHN1bV97aSA9IDF9XntufXt4X2l9fXtufSkkDQoNCiRsaW1fe3ggXHRvIFxpbmZ0eX0gXGZyYWN7MX17bl4yfSB2YXIoXHN1bV97aSA9IDF9XntufXt4X2l9KSQNCg0KJGxpbV97eCBcdG8gXGluZnR5fSBcZnJhY3sxfXtuXjJ9IG5cbGFtYmRhJA0KDQokbGltX3t4IFx0byBcaW5mdHl9IFxmcmFje1xsYW1iZGF9e259JA0KDQokPSAwJA0KDQp0aGVuICRcYmFye3h9JCBpcyBDb25zaXN0ZW50IEVzdGltYXRvcg0KDQoNCiMgQ29tcHV0aW5nIENvbmZpZGVuY2UgSW50ZXJ2YWwgZm9yIFBvaXNzb24gTWVhbg0KDQoqKkZvciBQb2lzc29uIGRpc3RyaWJ1dGlvbiwgdGhlcmUgYXJlIG1hbnkgZGlmZmVyZW50IHdheXMgZm9yIGNhbGN1bGF0aW5nIHRoZSBjb25maWRlbmNlIGludGVydmFsLiAqKg0KDQpUaGUgbW9zdCBjb21tb25seSB1c2VkIG1ldGhvZCBpcyANCg0KMS4gVGhlIG5vcm1hbCBhcHByb3hpbWF0aW9uIChmb3IgbGFyZ2Ugc2FtcGxlIHNpemUpIA0KDQoyLiBUaGUgZXhhY3QgbWV0aG9kIChmb3Igc21hbGwgc2FtcGxlIHNpemUpDQoNCg0KDQojIyBOb3JtYWwgQXBwcm94aW1hdGlvbjoNCg0KRm9yIFBvaXNzb24sIHRoZSBtZWFuIGFuZCB0aGUgdmFyaWFuY2UgYXJlIGJvdGggbGFtYmRhICgkXGxhbWJkYSQpLg0KDQpUaGUgc3RhbmRhcmQgZXJyb3IgaXMgY2FsY3VsYXRlZCBhczokc3FydChcbGFtYmRhICAvbikkIHdoZXJlICRcbGFtYmRhJCBpcyBQb2lzc29uIG1lYW4gYW5kICRuJCBpcyBzYW1wbGUgc2l6ZSAgDQoNClRoZSBjb25maWRlbmNlIGludGVydmFsIGNhbiBiZSBjYWxjdWxhdGVkIGFzOiAkXGxhbWJkYSAtIHooXGFscGhhLzIpKnNxcnQoXGxhbWJkYSAvbikgPCBcaGF0e1xsYW1iZGF9IDwgXGxhbWJkYSArIHooXGFscGhhLzIpKnNxcnQoXGxhbWJkYSAvbikkDQoNClRoZSA5NS1wZXJjZW50IGNvbmZpZGVuY2UgaW50ZXJ2YWwgaXMgY2FsY3VsYXRlZCBhczogJFxsYW1iZGEgIC0gMS45NipzcXJ0KFxsYW1iZGEgL24pIDwgXGhhdHtcbGFtYmRhfSA8ICBcbGFtYmRhICArIDEuOTYqc3FydChcbGFtYmRhIC9uKSAkDQoNClRoZSA5OS1wZXJjZW50IGNvbmZpZGVuY2UgaW50ZXJ2YWwgaXMgY2FsY3VsYXRlZCBhczogJFxsYW1iZGEgIC0gMi41OCpzcXJ0KFxsYW1iZGEgL24pICA8IFxoYXR7XGxhbWJkYX0gPCAgXGxhbWJkYSAgKyAyLjU4KnNxcnQoXGxhbWJkYSAvbikkDQoNCg0KIyMgRVhBQ1QgbWV0aG9kOg0KDQpUaGUgY29uZmlkZW5jZSBpbnRlcnZhbCBmb3IgZXZlbnQgWCBpcyBjYWxjdWxhdGVkIGFzOiANCg0KJChxY2hpc3EoXGFscGhhLzIsIDIqeCkvMiwgcWNoaXNxKDEtXGFscGhhLzIsIDIqKHgrMSkpLzIgKSQNCg0KV2hlcmUgeCBpcyB0aGUgbnVtYmVyIG9mIGV2ZW50cyBvY2N1cnJlZCB1bmRlciBQb2lzc29uIGRpc3RyaWJ1dGlvbi4NCg0KSW4gb3JkZXIgdG8gY2FsY3VsYXRlIHRoZSBleGFjdCBjb25maWRlbmNlIGludGVydmFsIGZvciBQb2lzc29uIG1lYW4sDQp0aGUgb2J0YWluZWQgY29uZmlkZW5jZSBpbnRlcnZhbCBmb3IgdGhlIG51bWJlciBvZiBldmVudHMgbmVlZCB0byBiZSBjb252ZXJ0ZWQgdG8gdGhlIGNvbmZpZGVuY2UgaW50ZXJ2YWwgZm9yIFBvaXNzb24gbWVhbi4NCg0KDQojIyBFeGFtcGxlIDE6DQoNCkZpbmQgdXBwZXIgYW5kIGxvd2VyIGNvbmZpZGVuY2UgbGV2ZWxzIGZvciBhIFBvaXNzb24gZGlzdHJpYnV0aW9uDQpPYnNlcnZhdGlvbnMgKCRuJCkgPSA4OA0KU2FtcGxlIG1lYW4gKCRcbGFtYmRhJCkgPSA0Ny4xODE4Mg0Kd2hhdCB3b3VsZCB0aGUgOTUlIGNvbmZpZGVuY2UgbG9vayBsaWtlIGZvciB0aGlzPw0KDQpXaXRoIE5vcm1hbCBBcHByb3hpbWF0aW9uLCB0aGUgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWwgaXMgY2FsY3VsYXRlZCBhczoNCg0KYGBge3J9DQpsYW1kYSA8LSAgIDQ3LjE4MTgyDQpuIDwtIDg4DQoNCmxvd2VyIDwtIGxhbWRhIC0gMS45NiAqIHNxcnQobGFtZGEvbikNCnVwcGVyIDwtIGxhbWRhICsgMS45NiAqIHNxcnQobGFtZGEvbikNCg0KbG93ZXIgDQp1cHBlciANCg0KDQpgYGANCldpdGggRXhhY3QgbWV0aG9kLCB3ZSBmaXJzdCBuZWVkIHRvIGNhbGN1bGF0ZSB4ICgjIG9mIGV2ZW50cyk6DQpgYGB7cn0NCmxhbWRhIDwtICAgNDcuMTgxODINCm4gPC0gODgNCnggPSBsYW1kYSAqIG4gDQphbHBoIDwtIDAuMDUNCmxvd2VyIDwtIHFjaGlzcShhbHBoLzIsMip4KS8yDQp1cHBlciA8LSAgcWNoaXNxKDEtYWxwaC8yLDIqKHgrMSkpLzINCg0KbG93ZXINCnVwcGVyDQpgYGANClRoZSA5NSUgY29uZmlkZW5jZSBpbnRlcnZhbCBmb3IgbWVhbiAoJFxsYW1iZGEkKSBpcyB0aGVyZWZvcmU6DQpgYGB7cn0NCmxvd2VyX2JvdW5kIDwtIGxvd2VyL24NCnVwcGVyX2JvdW5kIDwtIHVwcGVyL24NCg0KbG93ZXJfYm91bmQNCnVwcGVyX2JvdW5kDQpgYGANCg0KIyMgVXNpbmcgUiANCg0KMS4gR2VuZXJhdGUgMTAwMCByYW5kb20gbnVtYmVyIHdpdGggICAoJFxsYW1iZGEkKSA9IDUwDQoyLiBjaG9vc2Ugc2FtcGxlIG9mIHNpemUgbiA9IDQwDQozLiBjYWxjdWxhdGUgJFxiYXJ7eH0kDQo0LiBjb21wdXRlIHRoZSA5NSUgY29uZmlkZW5jZSBpbnRlcnZhbA0KIA0KYGBge3J9DQpwb3B1bGF0aW9uX3NpemUgPC0gMTAwMA0Kc2FtcGxlX3NpemVfbiA8LSA0MA0KcG9wdWxhdGlvbl9sYW1kYSA8LSA1MA0KDQoNCiNzdGVwIDENCnBvcHVsYXRpb24gPC0gcnBvaXMocG9wdWxhdGlvbl9zaXplLHBvcHVsYXRpb25fbGFtZGEpDQoNCiNzdGVwIDINCnNhbXBsZSA8LSBzYW1wbGUocG9wdWxhdGlvbiAsIHNhbXBsZV9zaXplX24gLEZBTFNFICkNCg0KI3N0ZXAgMw0KeF9iYXIgPC0gbWVhbihzYW1wbGUpDQoNCiNzdGVwIDQNCiMgY29uZmlkZW5jZSBpbnRlcnZhbCB1c2luZyBOb3JtYWwgQXBwcm94aW1hdGlvbg0KbGFtZGFfaGF0IDwtICAgeF9iYXINCmxvd2VyXzk1IDwtIGxhbWRhX2hhdCAtIDEuOTYgKiBzcXJ0KGxhbWRhX2hhdC9zYW1wbGVfc2l6ZV9uKQ0KdXBwZXJfOTUgPC0gbGFtZGFfaGF0ICsgMS45NiAqIHNxcnQobGFtZGFfaGF0L3NhbXBsZV9zaXplX24pDQoNCnhfYmFyDQpsb3dlcl85NSANCnVwcGVyXzk1IA0KDQogDQpgYGANCg0KDQpieSB1c2luZyBwcmV2aW91cyBleGFtcGxlIGJ1dCB3aXRoIDk5JSBjb25maWRlbmNlIGludGVydmFsDQpgYGB7cn0NCnNhbXBsZV9zaXplX24gPC0gNDANCg0KI3N0ZXAgMw0KIyBjb25maWRlbmNlIGludGVydmFsIHVzaW5nIE5vcm1hbCBBcHByb3hpbWF0aW9uDQpsYW1kYV9oYXQgPC0gICB4X2Jhcg0KbG93ZXJfOTkgPC0gbGFtZGFfaGF0IC0gMi41OCAqIHNxcnQobGFtZGFfaGF0L3NhbXBsZV9zaXplX24pDQp1cHBlcl85OSA8LSBsYW1kYV9oYXQgKyAyLjU4ICogc3FydChsYW1kYV9oYXQvc2FtcGxlX3NpemVfbikNCg0KeF9iYXINCmxvd2VyXzk5IA0KdXBwZXJfOTkNCmBgYA0KDQoNCg0KYnkgdXNpbmcgcHJldmlvdXMgZXhhbXBsZSBidXQgd2l0aCBsYXJnZSBzYW1wbGUgc2l6ZSBuPTYwMA0KYGBge3J9DQpzYW1wbGVfc2l6ZV9uIDwtIDYwMA0KI3N0ZXAgMg0Kc2FtcGxlIDwtIHNhbXBsZShwb3B1bGF0aW9uICwgc2FtcGxlX3NpemVfbiAsRkFMU0UgKQ0KDQojc3RlcCAzDQp4X2JhciA8LSBtZWFuKHNhbXBsZSkNCg0KI3N0ZXAgMw0KIyBjb25maWRlbmNlIGludGVydmFsIHVzaW5nIE5vcm1hbCBBcHByb3hpbWF0aW9uDQpsYW1kYV9oYXQgPC0gICB4X2Jhcg0KbG93ZXIgPC0gbGFtZGFfaGF0IC0gMS45NiAqIHNxcnQobGFtZGFfaGF0L3NhbXBsZV9zaXplX24pDQp1cHBlciA8LSBsYW1kYV9oYXQgKyAxLjk2ICogc3FydChsYW1kYV9oYXQvc2FtcGxlX3NpemVfbikNCg0KeF9iYXINCmxvd2VyIA0KdXBwZXIgDQpgYGANCg0KDQojIyBTYW1wbGluZyBEaXN0cmlidXRpb24gZm9yIA0KICAkJFxiYXJ7eH0kJA0KDQpDYWxjdWxhdGUgeCBiYXIgZm9yIDEwMDAgZGlmZmVyZW50IHNhbXBsZSBmcm9tIHNhbWUgcG9wdWxhdGlvbiBhbmQgY2hlY2sgaWYgdGhlc2UgeCBiYXIgYmVsb25nIHRvICBpbnRlcnZhbCBbbG93ZXIsdXBwZXJdDQoNCioqMS4gV2l0aCBDb25maWRlbmNlIDk1JSoqDQoNCioqMi4gV2l0aCBDb25maWRlbmNlIDk5JSoqDQoNCg0KYGBge3J9DQogcmVzdWx0cyA9IE5VTEwNCg0KZm9yKGkgaW4gMToxMDAwKXsNCiAgc2FtcGxlX3NpemVfbiA8LSA0MA0KICBzYW1wbGUgPC0gc2FtcGxlKHBvcHVsYXRpb24gLCBzYW1wbGVfc2l6ZV9uICxGQUxTRSApDQogIHhfYmFyIDwtIG1lYW4oc2FtcGxlKQ0KICByZXN1bHRzID0gcmJpbmQocmVzdWx0cywgZGF0YS5mcmFtZShpLHhfYmFyKSkNCn0NCg0KIyBwbG90IHNhbXBsZSBkaXN0cmlidXRpb24gZm9yIFggYmFyDQpsaWJyYXJ5KGRwbHlyKQ0KcmVzdWx0cyAlPiUgZ2dwbG90KG1hcHBpbmcgPSBhZXMoeCA9IHhfYmFyKSkgKyANCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKHk9Li5kZW5zaXR5Li4pICwgIGNvbG91cj0iYmxhY2siLCBmaWxsPSJ3aGl0ZSIpKw0KIGdlb21fZGVuc2l0eShhbHBoYT0uMiwgZmlsbD0iI0ZGNjY2NiIpICsNCmdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQgPSB1cHBlcl85NSksIGNvbG91cj0icmVkIikgKw0KZ2VvbV92bGluZShhZXMoeGludGVyY2VwdCA9IGxvd2VyXzk1KSwgY29sb3VyPSJyZWQiKSArDQogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQgPSB1cHBlcl85OSksIGNvbG91cj0iYmx1ZSIgLCAgbGluZXR5cGU9ImRhc2hlZCIsIHNpemU9MSkgKw0KZ2VvbV92bGluZShhZXMoeGludGVyY2VwdCA9IGxvd2VyXzk5KSwgY29sb3VyPSJibHVlIikgKw0KICAgICAgbGFicyh0aXRsZSA9ICJYIEJhciBTYW1wbGUgRGlzdHJpYnV0aW9uIiAsIHN1YnRpdGxlID0gIldpdGggOTUlIGFuZCA5OSUgQ29uZmlkYW5jZSBJbnRlcnZhbHMgIikgKyANCiAgeGxhYigiWCBCYXIiKSArIHlsYWIoImNvdW50IikNCiANCg0KYGBgDQoNCg0KYGBge3J9DQoNCnNpbXVsYXRpb25SZXN1bHRfOTUgPC0gbWVhbihsb3dlcl85NTxyZXN1bHRzJHhfYmFyICYgIHJlc3VsdHMkeF9iYXI8dXBwZXJfOTUpDQpzaW11bGF0aW9uUmVzdWx0Xzk5IDwtIG1lYW4obG93ZXJfOTk8cmVzdWx0cyR4X2JhciAmICByZXN1bHRzJHhfYmFyPHVwcGVyXzk5KQ0KDQpzaW11bGF0aW9uUmVzdWx0Xzk1DQpzaW11bGF0aW9uUmVzdWx0Xzk5DQoNCg0KYGBgDQoNCnRoZSByZXN1bHQgYWZ0ZXIgdGhpcyBzaW11bGF0aW9uIHNob3cgdXMgdGhhdCBhYm91dCA5NSUgb2Ygc2FtcGxlcyBoYXMgeCBiYXIgYmV0d2VlbiB0aGUgbG93ZXIgYW5kIHVwcGVyIGNhbGN1bGF0ZWQgdmFsdWVzIHdoZW4gY29uZmlkZW5jZSBsZXZlbCBlcXVhbCA5NSUgLCBhbHNvICBhYm91dCA5OSUgb2Ygc2FtcGxlcyBoYXMgeCBiYXIgYmV0d2VlbiB0aGUgbG93ZXIgYW5kIHVwcGVyIGNhbGN1bGF0ZWQgdmFsdWVzIHdoZW4gY29uZmlkZW5jZSBsZXZlbCBlcXVhbCA5OSUNCg0K