library(ggplot2)
library(MASS)
library(PASWR2)

Objectives

Motivation:

Discrete distributions can be used to model the number of failures until a successful rocket launch, the number of passing students in a class, or the number of taxis that pass a street corner, as well as many other phenomena with countable outcomes. Continuous distributions are used to model measurement variables such as weight, height, and time.

Motivational Problem (Pr. 20 / page 309 in text)

The weekly production of a banana plantation can be modeled with a normal random variable that has a mean of 5 tons and a standard deviation of 2 tons.

  1. Find the probability that, in at most 1 out of the 8 randomly chosen weeks, the production has been less than 3 tons.
  2. Find the probability that at least 3 weeks are needed to obtain a production greater than 10 tons.

Discrete Univariate Distributions

4.2.1 Discrete Uniform Distribution

The random variable X is said to follow a discrete uniform distribution with parameter n (where \(n ∈ ℕ)\) if the probability X takes on the value x is the same for all x, where \(x = x_1, x_2, …, x_n\).

For Discrete Uniform Distribution one has:

  1. \[P(X=x_i|n)= \frac{1}{n}\] for \(i=1,2,...,n\)
  1. \[E[X]=\frac{1}{n} \sum_{i=1}^n x_i\]
  1. \[Var[X]=\frac{1}{n} \sum_{i=1}^n (x_i-E[X])^2\]

Exercise: When \(x_i = i\) for \(i = 1, …, n\), it can be shown that \(E[X] = \frac{n+1}{2}\) and that \(Var[X] = \frac{n^2−1}{12}\), respectively.

Example 4.1

One light bulb is randomly selected from a box that contains a 40-watt light bulb, a 60-watt light bulb, a 75-watt light bulb, a 100-watt light bulb, and a 120-watt light bulb. Write the probability function for the random variable that represents the wattage of the randomly selected light bulb, and determine the mean and variance of that random variable.

Solution: The random variable X can assume the set of values \(Ω = {40, 60, 75, 100, 120}\). The probability density function for the random variable X is

\(P(X=x|n=5)=\frac{1}{5}\) for \(x=40, 60, 75, 100, 120\)

Try the code


Watts <- c(40, 60, 75, 100, 120)
n <- length(Watts)
meanWatts <- (1/n)*sum(Watts)
varWatts<- (1/n)*sum((Watts - meanWatts)^2)
ans <- c(meanWatts, varWatts)
ans

4.2.2 Bernoulli and Binomial Distributions

A Bernoulli trial is a random experiment with only two possible outcomes. The outcomes are mutually exclusive and exhaustive;e.g., success or failure, true or false, alive or dead, male or female, etc. A Bernoulli random variable, X, can take on two values, where X(success) = 1 and X(failure) = 0. The probability that X is a success is \(\pi\), and the probability that X is a failure is \(1-\pi\).

For Bernoulli distribution pdf, mean, and variance of a Bernoulli random variable are:

\[X \sim Bernoulli(\pi)\]

  1. \[P(X=x|\pi)= \pi^x(1-\pi)^{1-x}\] for \(x=0,1\)
  1. \[E[X]=\pi\]
  1. \[Var[X]=\pi(1-\pi)\]

When a sequence of Bernoulli trials conforms to the following list of requirements, it is called a binomial experiment:

  1. The experiment consists of a fixed number (n) of Bernoulli trials.
  2. The probability of success for each trial, denoted by \(\pi\), is constant from trial to trial. The probability of failure is \(\rho = 1-\pi\)
  3. The trials are independent.
  4. The random variable of interest, X, is the number of observed successes during the n trials.

For Binomial distribution pdf, mean, and variance of a binomial random variable are:

\[X \sim Bin(n, \pi) \]

  1. \[P(X=x|n, \pi)= {n \choose x} \pi^x(1-\pi)^{n-x}\] for \(x=0,1, ..., n\)
  1. \[E[X]=n \pi\]
  1. \[Var[X]=n \pi(1-\pi)\]

Exercise (optional): Prove 1,2 and 3 above.

Code below is used to create graphs that represent the probability density function and the cumulative distribution function for a Bin(8, 0.3) random variable:

Try it!

opar <- par(no.readonly = TRUE)
par(mfrow=c(1, 2), pty = "s")
x <- 0:8
px <- dbinom(x = x, size = 8,prob =  0.3)

# plot probability vs corresponding x-values
plot(x, px, type = "h", xlab = "x", ylab="P(X = x)",
    main = "PDF of X~Bin(8, 0.3)")
xs <- rep(0:8, round(dbinom(0:8, 8, .3)*100000, 0)) # creates vector of 0s, 1s, ...8s, according to the expected number of each one out of 10,000 trials

# plot the empirical cdf
plot(ecdf(xs), main = "CDF of X~Bin(8, 0.3)",
    ylab = expression(P(X<=x)), xlab = "x")
par(opar)

Q: Change the probability, \(\pi\) parameter to value close to zero. What do you observe? How does it skew the distribution. Now, increase `n’ to bigger value, even bigger. Do you notice correction of the skewness?

Exercise: Graph the pdf and cdf for \(X \sim Bin(10,\frac{1}{2})\) (# of heads of tossing a fair coin 10 times experiment) it is part of the weekly programming exercises Rmd file.

R functions for Binomial Distribution Calculations

Description

Density, distribution function, quantile function and random generation for the binomial distribution with parameters size and prob.

This is conventionally interpreted as the number of ‘successes’ in size trials.

Usage

dbinom(x, size, prob, log = FALSE) this computes the pdf values

pbinom(q, size, prob, lower.tail = TRUE, log.p = FALSE) this gives \(P(X \le x)\) the pdf values

qbinom(p, size, prob, lower.tail = TRUE, log.p = FALSE) this gives the quantiles \(P(X \le k) \ge p\)

rbinom(n, size, prob)

Arguments

x, q - vector of quantiles. p - vector of probabilities. n - number of observations. size - number of trials (zero or more). prob - probability of success on each trial.

Example: Using the function rbinom(), one can generate 1000 samples of a \(Bin(n = 5, \pi = 0.5)\) as shown below:


set.seed(123)
x <- rbinom(1000, 5, .5)
table(x)/1000 # The empirical distribution

Example 4.3

Binomial Calculation Consider the problem of calculating the probability of obtaining 6 or more heads in 10 tosses of a weighted coin (not fair), where the probability of obtaining a head in any given trial is 0.33.

# adding probabilities 
sum(dbinom(x = 6:10, size = 10, prob = 0.33))          # P(X >= 6)=P(6)+P(7)+P(8)+P(9)+P(10)

# or
1 - pbinom(5, 10, 0.33)              # 1 - P(X <= 5)
#or 
pbinom(5, 10, 0.33, lower = FALSE)   # P(X >= 6)
# or 
1 - sum(dbinom(5:0, 10, 0.33)) # 1 - P(X <= 5)

4.2.3 Poisson Distribution

The Poisson distribution is very popular for modeling the number of times particular events occur in given times or on defined spaces, or in general unit interval of time (units of time may vary).

E.g.

  • number of phone calls to 911 between 1 a.m. and 2 a.m.

  • number of accidents at a busy street corner during a 24-hour period

  • number of typographical errors on a single page of this book

See definition of Poisson Process in the text, page 256.

Suppose there is an experiment that satisfies the three criteria for an approximate Poisson process with parameter \(\lambda\), \(\lambda\) mean number of occurrences on a unit interval of time.

Let X represent the number of outcomes in an interval of length 1 (t = 1).

Then one has:

Poisson Distribution mean, and variance of a binomial random variable are:

\[X \sim Pois(\lambda)\]

  1. \[P(X=x|\lambda)=\frac{\lambda^xe^{-\lambda}}{x!}\] for \(x=0,1,2,...\)
  1. \[E[X]=\lambda\]
  1. \[Var[X]=\lambda\]

Review the code to see how to represent a pdf and cdf for a Pois(λ = 1) random variable. Although the values x can take on with the Poisson distribution are $0, 1, 2,…, $ the probability a Poisson random variable has a value of eight or greater when λ = 1 is extremely small (< 0). Consequently, the pdf, and cdf do not extend beyond eight.

opar <- par(no.readonly = TRUE)
par(mfrow=c(1, 2), pty = "s")

x <- 0:8
px <- dpois(x,lambda = 1) # computes the pdf at the points x

# plot probability vs x-values
plot(x, px, type = "h", xlab = "x", ylab="P(X = x)",
    main = "PDF of X ~ Pois(1)")

xs <- rep(0:8, round(dpois(0:8, 1)*100000, 0)) # create vector of 100,000 values according to the expected number of occurrences of 0s,1s, 2s, ...and we cut at 8s other values can be ignored
# plot the empirical cdf
plot(ecdf(xs), main = "CDF of X ~ Pois(1)",
    ylab = expression(P(X <=x)), xlab = "x")

par(opar)

Note: The Poisson distribution is particularly appropriate for modeling “rare” phenomena or outcomes where the probability of success is small.

Given n independent Poisson random variables \(X_1, X_2,…, X_n\) with parameters \(λ_1, λ_2,…, λ_n\) respectively, \(Y= \sum_{i=1}^n X_i \sim Pois(\sum_{i=1}^n \lambda_i=\lambda)\)

Example 4.6 More accidents are registered in auto body repair shops during the months of May and June than in the rest of the year. Suppose a particular auto body repair shop has an average of four accidents per month. What is the probability there will be more than seven accidents in this auto body shop during the month of May? What is the probability no more than three accidents will occur during the months of May and June?

Solution: Assuming accidents in the auto body shop follow an approximate Poisson process, the probability of x accidents in one month is

\[P(X=x|4)=\frac{4^xe^{-4}}{x!}\] for \(x=0,1,2,...\)

Using R:

# lower parameter TRUE - computes probabilities up to the point, FALSE to the right of the point
1 - ppois(q = 7, lambda = 4, lower = TRUE)               # P(X > 7|4) = 1 - P(X<=7|4)

ppois(q = 7, lambda = 4, lower = FALSE)    # P(X > 7|4) notice lower = FALSE

ppois(q = 3, lambda = 8) # P(X <= 3|8)

R functions for the Poisson Distribution Calculations

Description

Density, distribution function, quantile function and random generation for the Poisson distribution with parameter lambda.

Usage

dpois(x, lambda, log = FALSE)

ppois(q, lambda, lower.tail = TRUE, log.p = FALSE)

qpois(p, lambda, lower.tail = TRUE, log.p = FALSE)

rpois(n, lambda)

Arguments

x - vector of (non-negative integer) quantiles. q - vector of quantiles. p - vector of probabilities. n - number of random values to return. lambda - vector of (non-negative) means.

4.2.4 Geometric Distribution

A random variable X that counts the number of Bernoulli trials that result in failure before the first success is called a geometric random variable. Clearly, the probability of a success after r failures is \(π × (1 − π)^r\), which leads to the geometric probability distribution function where \(\rho = 1 − π\) is the probability of failure.

The pdf, mean, and variance for a geometric random variable are shown below:

\[X \sim Geo(\pi)\] \[P(X=x|\pi)=\pi\rho^x\] for \(x=0,1,2 ...\)

\[E[X]=\frac{\rho}{\pi}\] \[Var[X]=\frac{\rho}{\pi^2}\]

The code below can be used to create graphs that represent the probability density function and the cumulative distribution function for a \(Geo(π = 0.3)\) random variable.


opar <- par(no.readonly = TRUE)
par(mfrow=c(1, 2), pty = "s")
x <- 0:15
px <- dgeom(x = x, prob = .3)

plot(x, px, type = "h", xlab = "x", ylab="P(X = x)",
     main = "PDF of X ~ Geom(0.3)")
xs <- rep(0:15, round(dgeom(0:15, 0.3)*100000, 0))
plot(ecdf(xs), main = "CDF of X ~ Geom(0.3)",
     ylab = expression(P(X <=x)), xlab = "x")
par(opar)

Pr. 18 / page 308 in text Suppose the percentage of drinks sold from a vending machine are 80% and 20% for soft drinks and bottled water, respectively.

  1. What is the probability that on a randomly selected day, the first soft drink is the fourth drink sold?
  2. Find the probability that exactly 1 out of 10 drinks sold is a soft drink.

Solution: Let X = number of waters (failures) purchased before the first soft drink is purchased. Then, \(X \sim Geo(0.80)\).


dgeom(x = 3, prob = 0.80) # P(X = 3)
  1. Let X = number of soft drinks sold. Then, \(X \sim Bin(10, 0.80)\) and \(P(X = 1) = 0\) since one has:
pbinom(q = 1, size = 10, prob = 0.8) # P(X = 1)

Optional to review: 4.2.5 Negative Binomial Distribution & 4.2.6 Hypergeometric Distribution

4.3 Continuous Univariate Distributions

4.3.1 Uniform Distribution (Continuous)

The continuous uniform distribution has a pdf that is constant over a closed interval.

An important application of the uniform distribution includes random number generation.

Uniform Distribution

\[X \sim Unif(a,b)\]

  1. \[f(x|a,b)=\frac{1}{b-a}\] for \(a \le x \le b\)
  1. \[E[X]=\frac{b+a}{2}\]
  1. \[Var[X]=\frac{(b-a)^2}{12}\]

Generating Pseudo Random Numbers using R command rdist where dist is distribution name. Use runif for the next example.

Example:

For \(X \sim Unif(2,6)\) one has \(E[X]=4\) and \(Var[X]=\frac{16}{12}=\frac{4}{3}\)

Estimate \(E[X]\) and \(Var[X]\) by using a large number of values drawn at random from a Unif(2, 6).

set.seed(13)
TM <- 4 # true mean
TV <- 4/3 # true variance

x <- runif(n = 10000,min = 2,max = 6)
Ex <- mean(x)
Ex

Vx <- mean((x-Ex)^2)
Vx

PE <- c(PercentErrorMean  = abs(Ex - TM)/TM*100, 
        PercentErrorVariance = abs(Vx - TV)/TV*100) # percent error of the estimate from the true mean and var
ANS <- c(SimMean = Ex, TheMean = TM, SimVar = Vx, TheVar = TV)
ANS

4.3.2 Exponential Distribution

If W is the waiting time until the first outcome of a Poisson process with mean \(\lambda > 0\) (# occurrences over unit interval), then the pdf, mean, and variance for W are shown below:

  1. \[f(x| \lambda)=\lambda e^{-\lambda x}\] for \(x \ge 0\), and 0 otherwise
  1. \[E[X]=\frac{1}{\lambda}\]
  1. \[Var[X]=\frac{1}{\lambda^2}\]

Consequently, when \(w > 0\), the pdf of W is \(F'(w) = f(w) = λe^{−λw}\).

The exponential distribution is characterized by a lack of memory property and is often used to model lifetimes of electronic components as well as waiting times for Poisson processes.

A random variable is said to be memoryless if

\[P(X > t_2 + t_1 |X > t_1) = P(X > t_2)\] for all \(t_1, t_2\)

Exercise: Try to show that above is equivalent to

\[P(X > t_2 + t_1)=P(X > t_1) P(X > t_2)\] for all \(t_1, t_2\)

R functions for the Exponential Distribution

Description

Density, distribution function, quantile function and random generation for the exponential distribution with rate rate (i.e., mean 1/rate).

Usage

dexp(x, rate = 1, log = FALSE)

pexp(q, rate = 1, lower.tail = TRUE, log.p = FALSE)

qexp(p, rate = 1, lower.tail = TRUE, log.p = FALSE)

rexp(n, rate = 1)

Arguments

x, q - vector of quantiles. p - vector of probabilities. n- number of observations. If length(n) > 1, the length is taken to be the number required. rate - vector of rates. log, log.p - logical; if TRUE, probabilities p are given as log(p). lower.tail - logical; if TRUE (default), probabilities are P[X ≤ x], otherwise, P[X > x].

Example 4.17, page 279 in text

Exponential Distribution: Light Bulbs If the life of a certain type of light bulb has an exponential distribution with a mean of 8 months, find

  1. The probability that a randomly selected light bulb lasts between 3 and 12 months.
  2. The 95th percentile of the distribution.
  3. The probability that a light bulb that has lasted for 10 months will last more than 25 months.

Solution:

YOUR CODE HERE:

# uncomment the code below to see solution - explain why
pexp(q = 12, rate = 1/8) - pexp(q = 3, rate = 1/8)

f1 <- function(x){(1/8) * exp(-x/8)}        # define f1
(integrate(f1, lower = 3, upper = 12)$value)   # integrate f1

# the 95 quantile/percentile
qexp(0.95, 1/8) 

pexp(25, 1/8, lower = FALSE)/pexp(10, 1/8, lower = FALSE)
# or
1 - pexp(15, 1/8)
# or
pexp(15, 1/8, lower = FALSE)

4.3.7 Normal (Gaussian) Distribution

most important distribution in statistical applications

many numerical populations have distributions that can be approximated with the normal distribution.

The pdf, mean, and variance for a normal random variable X with mean μ and variance \(\sigma^2\) are provided: \[X \sim N(\mu, \sigma^2)\] \[ f(x|\mu,\sigma) = \frac{1}{\sqrt{2\pi\sigma^2}} e^{-\frac{(x-\mu)^2}{2\sigma^2}}\] for \(-\infty < x <\infty\)

\[E[X]=\mu\]

\[Var[X]=\sigma^2\]

R functions for the Normal Distribution

Description

Density, distribution function, quantile function and random generation for the normal distribution with mean equal to mean and standard deviation equal to sd.

Usage

dnorm(x, mean = 0, sd = 1, log = FALSE)

pnorm(q, mean = 0, sd = 1, lower.tail = TRUE, log.p = FALSE)

qnorm(p, mean = 0, sd = 1, lower.tail = TRUE, log.p = FALSE)

rnorm(n, mean = 0, sd = 1)

Arguments

x, q - vector of quantiles. p - vector of probabilities. n - number of observations. If length(n) > 1, the length is taken to be the number required. mean - vector of means. sd - vector of standard deviations.

Example 4.25

Scores on a particular standardized test follow a normal distribution with a mean of 100 and standard deviation of 10.

  1. What is the probability that a randomly selected individual will score between 90 and 115?
  2. What score does one need to be in the top 10%?
  3. Find the constant c such that \(P(105 \le X \le c) = 0.10\).

# (a)
pnorm(q = 115,mean =  100, sd = 10) - pnorm(q = 90, mean = 100, sd = 10) # see why
# (b) 
qnorm(p = .90, mean = 100, sd = 10) # check why
# (c) 
qnorm(0.10 + pnorm(105, 100, 10), 100, 10) # see the text page 299.

Motivational Problem (Pr. 20 / page 309 in text)

The weekly production of a banana plantation can be modeled with a normal random variable that has a mean of 5 tons and a standard deviation of 2 tons.

  1. Find the probability that, in at most 1 out of the 8 randomly chosen weeks, the production has been less than 3 tons.
  2. Find the probability that at least 3 weeks are needed to obtain a production greater than 10 tons.

Solution:

  1. Let X = number of weeks where production is less than 3 tons. Then, \(X \sim Bin(8, 0.1587)\). Let W = production, \(W \sim N(5, 2)\) and \(P(W \le 3) = 0.1587\). So, P(X ) = 0.6298. Check the code below!

p <- pnorm(3, 5, 2) # P(W < 3)
pbinom(1, 8, p)
  1. Let \(X_n\) = number of weeks where production is less than 10 tons before the first week with production over 10 tons. \(X_n \sim Geo(\pi = P(W \ge 10) = 0.0062)\), and \(P(X_n \ge 2) = 1 − P(Xn \le 1) = 0.9876\).
PI <- 1 - pnorm(q = 10,mean =  5, sd = 2) # P(W >= 10)
PI

1 - pgeom(1, PI)
0.9876192

Quantile-Quantile Plots for Normal Distributions (Q-Q Plots)

Many of the techniques and testing assume the underlying distribution is normal.

One of the more useful graphical procedures for assessing distributions is the quantile-quantile plot. (Recall from Section 2.7.3 that this graph is also called a Q-Q plot.)

R function qqnorm() helps determine whether the underlying distribution is normal.

** Example** Consider the values stored in the variable scores of the data frame SCORE (in the PASWR2 package) and shown below which are the scores a random sample of 20 college freshmen received on a standardized test.

119 107 96 107 97 103 94 106 87 112 99 99 90 106 110 99 105 100 100 94

To compute the pairs of values plotted in an R quantile-quantile plot for the variable scores of the data frame SCORE inspect the code below:

n <- length(SCORE$scores) # number of observations

X <- (1:n - 1/2)/n # 100% split into n=20 equal intervals
Xs <- qnorm(X) # quantiles of X
Ys <- sort(SCORE$scores) # sorted scores
plot(Xs, Ys) # plot Ys vs Xs
quantile(Xs, c(0.25, 0.75)) 
quantile(Ys, c(0.25, 0.75))

qqnorm(SCORE$scores) #using qqnorm
qqline(SCORE$scores) #adding line through 1st and 3rd quantile

You can do this using ggplot2 much nicer:

ggplot(data = SCORE, aes(sample = scores)) + stat_qq()

REMINDER: DO NOT MISS TO REVIEW THE PROGRAMMING EXERCISES before you attempt the quiz for the week!

LS0tCnRpdGxlOiBXZWVrIDUgLSBVbml2YXJpYXRlIFByb2JhYmlsaXR5IERpc3RyaWJ1dGlvbnMKZGF0ZTogJ2ByIFN5cy5EYXRlKClgJwpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKZWRpdG9yX29wdGlvbnM6IAogIG1hcmtkb3duOiAKICAgIHdyYXA6IHNlbnRlbmNlCi0tLQoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSkKYGBgCgpgYGB7ciBwYWNrYWdlcywgd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlID0gIEZBTFNFfQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoTUFTUykKbGlicmFyeShQQVNXUjIpCgpgYGAKCiMjIE9iamVjdGl2ZXMKCi0gICBDb21wdXRlIHByb2JhYmlsaXRpZXMgcmVsYXRlZCB0byBkaXNjcmV0ZSBhbmQgY29udGludW91cyByYW5kb20gdmFyaWFibGVzCi0gICBVc2UgZXhwZXJpbWVudGFsIGFuZCB0aGVvcmV0aWNhbCBwcm9iYWJpbGl0aWVzIHRvIGZvcm11bGF0ZSBhbmQgc29sdmUgYXBwbGllZCBwcm9ibGVtcwoKPiBNb3RpdmF0aW9uOgoKRGlzY3JldGUgZGlzdHJpYnV0aW9ucyBjYW4gYmUgdXNlZCB0byBtb2RlbCB0aGUgbnVtYmVyIG9mIGZhaWx1cmVzIHVudGlsIGEgc3VjY2Vzc2Z1bCByb2NrZXQgbGF1bmNoLCB0aGUgbnVtYmVyIG9mIHBhc3Npbmcgc3R1ZGVudHMgaW4gYSBjbGFzcywgb3IgdGhlIG51bWJlciBvZiB0YXhpcyB0aGF0IHBhc3MgYSBzdHJlZXQgY29ybmVyLCBhcyB3ZWxsIGFzIG1hbnkgb3RoZXIgcGhlbm9tZW5hIHdpdGggY291bnRhYmxlIG91dGNvbWVzLgpDb250aW51b3VzIGRpc3RyaWJ1dGlvbnMgYXJlIHVzZWQgdG8gbW9kZWwgbWVhc3VyZW1lbnQgdmFyaWFibGVzIHN1Y2ggYXMgd2VpZ2h0LCBoZWlnaHQsIGFuZCB0aW1lLgoKPiAqKk1vdGl2YXRpb25hbCBQcm9ibGVtIChQci4gMjAgLyBwYWdlIDMwOSBpbiB0ZXh0KSoqCgpUaGUgd2Vla2x5IHByb2R1Y3Rpb24gb2YgYSBiYW5hbmEgcGxhbnRhdGlvbiBjYW4gYmUgbW9kZWxlZCB3aXRoIGEgbm9ybWFsIHJhbmRvbSB2YXJpYWJsZSB0aGF0IGhhcyBhIG1lYW4gb2YgNSB0b25zIGFuZCBhIHN0YW5kYXJkIGRldmlhdGlvbiBvZiAyIHRvbnMuCgooYSkgRmluZCB0aGUgcHJvYmFiaWxpdHkgdGhhdCwgaW4gYXQgbW9zdCAxIG91dCBvZiB0aGUgOCByYW5kb21seSBjaG9zZW4gd2Vla3MsIHRoZSBwcm9kdWN0aW9uIGhhcyBiZWVuIGxlc3MgdGhhbiAzIHRvbnMuCihiKSBGaW5kIHRoZSBwcm9iYWJpbGl0eSB0aGF0IGF0IGxlYXN0IDMgd2Vla3MgYXJlIG5lZWRlZCB0byBvYnRhaW4gYSBwcm9kdWN0aW9uIGdyZWF0ZXIgdGhhbiAxMCB0b25zLgoKLSAgIFNvbHV0aW9uIHRvd2FyZHMgdGhlIGVuZCBvZiB0aGUgbm90ZXMhCgojIyBEaXNjcmV0ZSBVbml2YXJpYXRlIERpc3RyaWJ1dGlvbnMKCiMjIyA0LjIuMSBEaXNjcmV0ZSBVbmlmb3JtIERpc3RyaWJ1dGlvbgoKVGhlIHJhbmRvbSB2YXJpYWJsZSBgWGAgaXMgc2FpZCB0byBmb2xsb3cgYSBkaXNjcmV0ZSB1bmlmb3JtIGRpc3RyaWJ1dGlvbiB3aXRoIHBhcmFtZXRlciBgbmAgKHdoZXJlICRuIOKIiCDihJUpJCBpZiB0aGUgcHJvYmFiaWxpdHkgYFhgIHRha2VzIG9uIHRoZSB2YWx1ZSBgeGAgaXMgdGhlICoqc2FtZSoqIGZvciBhbGwgYHhgLCB3aGVyZSAkeCA9IHhfMSwgeF8yLCDigKYsIHhfbiQuCgpGb3IgKipEaXNjcmV0ZSBVbmlmb3JtIERpc3RyaWJ1dGlvbioqIG9uZSBoYXM6Cgo+IDEuICAkJFAoWD14X2l8bik9IFxmcmFjezF9e259JCQgZm9yICRpPTEsMiwuLi4sbiQKCj4gMi4gICQkRVtYXT1cZnJhY3sxfXtufSBcc3VtX3tpPTF9Xm4geF9pJCQKCj4gMy4gICQkVmFyW1hdPVxmcmFjezF9e259IFxzdW1fe2k9MX1ebiAoeF9pLUVbWF0pXjIkJAoKKipFeGVyY2lzZToqKiBXaGVuICR4X2kgPSBpJCBmb3IgJGkgPSAxLCDigKYsIG4kLCBpdCBjYW4gYmUgc2hvd24gdGhhdCAkRVtYXSA9IFxmcmFje24rMX17Mn0kIGFuZCB0aGF0ICRWYXJbWF0gPSBcZnJhY3tuXjLiiJIxfXsxMn0kLCByZXNwZWN0aXZlbHkuCgoqKkV4YW1wbGUgNC4xKioKCk9uZSBsaWdodCBidWxiIGlzIHJhbmRvbWx5IHNlbGVjdGVkIGZyb20gYSBib3ggdGhhdCBjb250YWlucyBhIDQwLXdhdHQgbGlnaHQgYnVsYiwgYSA2MC13YXR0IGxpZ2h0IGJ1bGIsIGEgNzUtd2F0dCBsaWdodCBidWxiLCBhIDEwMC13YXR0IGxpZ2h0IGJ1bGIsIGFuZCBhIDEyMC13YXR0IGxpZ2h0IGJ1bGIuCldyaXRlIHRoZSBwcm9iYWJpbGl0eSBmdW5jdGlvbiBmb3IgdGhlIHJhbmRvbSB2YXJpYWJsZSB0aGF0IHJlcHJlc2VudHMgdGhlIHdhdHRhZ2Ugb2YgdGhlIHJhbmRvbWx5IHNlbGVjdGVkIGxpZ2h0IGJ1bGIsIGFuZCBkZXRlcm1pbmUgdGhlIG1lYW4gYW5kIHZhcmlhbmNlIG9mIHRoYXQgcmFuZG9tIHZhcmlhYmxlLgoKKipTb2x1dGlvbjoqKiBUaGUgcmFuZG9tIHZhcmlhYmxlIGBYYCBjYW4gYXNzdW1lIHRoZSBzZXQgb2YgdmFsdWVzICTOqSA9IHs0MCwgNjAsIDc1LCAxMDAsIDEyMH0kLgpUaGUgcHJvYmFiaWxpdHkgZGVuc2l0eSBmdW5jdGlvbiBmb3IgdGhlIHJhbmRvbSB2YXJpYWJsZSBgWGAgaXMKCiRQKFg9eHxuPTUpPVxmcmFjezF9ezV9JCBmb3IgJHg9NDAsIDYwLCA3NSwgMTAwLCAxMjAkCgpUcnkgdGhlIGNvZGUKCmBgYHtyIGV4LiA0LjF9CgpXYXR0cyA8LSBjKDQwLCA2MCwgNzUsIDEwMCwgMTIwKQpuIDwtIGxlbmd0aChXYXR0cykKbWVhbldhdHRzIDwtICgxL24pKnN1bShXYXR0cykKdmFyV2F0dHM8LSAoMS9uKSpzdW0oKFdhdHRzIC0gbWVhbldhdHRzKV4yKQphbnMgPC0gYyhtZWFuV2F0dHMsIHZhcldhdHRzKQphbnMKYGBgCgojIyMgNC4yLjIgQmVybm91bGxpIGFuZCBCaW5vbWlhbCBEaXN0cmlidXRpb25zCgpBICoqQmVybm91bGxpIHRyaWFsKiogaXMgYSByYW5kb20gZXhwZXJpbWVudCB3aXRoIG9ubHkgKip0d28gcG9zc2libGUgb3V0Y29tZXMqKi4KVGhlIG91dGNvbWVzIGFyZSAqKm11dHVhbGx5IGV4Y2x1c2l2ZSBhbmQgZXhoYXVzdGl2ZSoqO2UuZy4sIHN1Y2Nlc3Mgb3IgZmFpbHVyZSwgdHJ1ZSBvciBmYWxzZSwgYWxpdmUgb3IgZGVhZCwgbWFsZSBvciBmZW1hbGUsIGV0Yy4KQSBCZXJub3VsbGkgcmFuZG9tIHZhcmlhYmxlLCBgWGAsIGNhbiB0YWtlIG9uIHR3byB2YWx1ZXMsIHdoZXJlIFgoc3VjY2VzcykgPSAxIGFuZCBYKGZhaWx1cmUpID0gMC4KVGhlIHByb2JhYmlsaXR5IHRoYXQgYFhgIGlzIGEgc3VjY2VzcyBpcyAkXHBpJCwgYW5kIHRoZSBwcm9iYWJpbGl0eSB0aGF0IGBYYCBpcyBhIGZhaWx1cmUgaXMgJDEtXHBpJC4KCkZvciAqKkJlcm5vdWxsaSBkaXN0cmlidXRpb24qKiAqKnBkZioqLCBtZWFuLCBhbmQgdmFyaWFuY2Ugb2YgYSBCZXJub3VsbGkgcmFuZG9tIHZhcmlhYmxlIGFyZToKCiQkWCBcc2ltIEJlcm5vdWxsaShccGkpJCQKCj4gMS4gICQkUChYPXh8XHBpKT0gXHBpXngoMS1ccGkpXnsxLXh9JCQgZm9yICR4PTAsMSQKCj4gMi4gICQkRVtYXT1ccGkkJAoKPiAzLiAgJCRWYXJbWF09XHBpKDEtXHBpKSQkCgpXaGVuIGEgc2VxdWVuY2Ugb2YgQmVybm91bGxpIHRyaWFscyBjb25mb3JtcyB0byB0aGUgZm9sbG93aW5nIGxpc3Qgb2YgcmVxdWlyZW1lbnRzLCBpdCBpcyBjYWxsZWQgYSAqKmJpbm9taWFsIGV4cGVyaW1lbnQqKjoKCj4gMS4gIFRoZSBleHBlcmltZW50IGNvbnNpc3RzIG9mIGEgZml4ZWQgbnVtYmVyIChgbmApIG9mIEJlcm5vdWxsaSB0cmlhbHMuCj4gMi4gIFRoZSBwcm9iYWJpbGl0eSBvZiBzdWNjZXNzIGZvciBlYWNoIHRyaWFsLCBkZW5vdGVkIGJ5ICRccGkkLCBpcyBjb25zdGFudCBmcm9tIHRyaWFsIHRvIHRyaWFsLiBUaGUgcHJvYmFiaWxpdHkgb2YgZmFpbHVyZSBpcyAkXHJobyA9IDEtXHBpJAo+IDMuICBUaGUgdHJpYWxzIGFyZSBpbmRlcGVuZGVudC4KPiA0LiAgVGhlIHJhbmRvbSB2YXJpYWJsZSBvZiBpbnRlcmVzdCwgWCwgaXMgdGhlIG51bWJlciBvZiBvYnNlcnZlZCBzdWNjZXNzZXMgZHVyaW5nIHRoZSBuIHRyaWFscy4KCkZvciAqKkJpbm9taWFsIGRpc3RyaWJ1dGlvbioqICoqcGRmKiosIG1lYW4sIGFuZCB2YXJpYW5jZSBvZiBhIGJpbm9taWFsIHJhbmRvbSB2YXJpYWJsZSBhcmU6CgokJFggXHNpbSBCaW4obiwgXHBpKSAkJAoKPiAxLiAgJCRQKFg9eHxuLCBccGkpPSB7biBcY2hvb3NlIHh9IFxwaV54KDEtXHBpKV57bi14fSQkIGZvciAkeD0wLDEsIC4uLiwgbiQKCj4gMi4gICQkRVtYXT1uIFxwaSQkCgo+IDMuICAkJFZhcltYXT1uIFxwaSgxLVxwaSkkJAoKKipFeGVyY2lzZSAob3B0aW9uYWwpKio6IFByb3ZlIDEsMiBhbmQgMyBhYm92ZS4KCkNvZGUgYmVsb3cgaXMgdXNlZCB0byBjcmVhdGUgZ3JhcGhzIHRoYXQgcmVwcmVzZW50IHRoZSBwcm9iYWJpbGl0eSBkZW5zaXR5IGZ1bmN0aW9uIGFuZCB0aGUgY3VtdWxhdGl2ZSBkaXN0cmlidXRpb24gZnVuY3Rpb24gZm9yIGEgQmluKDgsIDAuMykgcmFuZG9tIHZhcmlhYmxlOgoKVHJ5IGl0IQoKYGBge3IgQmlufQpvcGFyIDwtIHBhcihuby5yZWFkb25seSA9IFRSVUUpCnBhcihtZnJvdz1jKDEsIDIpLCBwdHkgPSAicyIpCnggPC0gMDo4CnB4IDwtIGRiaW5vbSh4ID0geCwgc2l6ZSA9IDgscHJvYiA9ICAwLjMpCgojIHBsb3QgcHJvYmFiaWxpdHkgdnMgY29ycmVzcG9uZGluZyB4LXZhbHVlcwpwbG90KHgsIHB4LCB0eXBlID0gImgiLCB4bGFiID0gIngiLCB5bGFiPSJQKFggPSB4KSIsCiAgICBtYWluID0gIlBERiBvZiBYfkJpbig4LCAwLjMpIikKeHMgPC0gcmVwKDA6OCwgcm91bmQoZGJpbm9tKDA6OCwgOCwgLjMpKjEwMDAwMCwgMCkpICMgY3JlYXRlcyB2ZWN0b3Igb2YgMHMsIDFzLCAuLi44cywgYWNjb3JkaW5nIHRvIHRoZSBleHBlY3RlZCBudW1iZXIgb2YgZWFjaCBvbmUgb3V0IG9mIDEwLDAwMCB0cmlhbHMKCiMgcGxvdCB0aGUgZW1waXJpY2FsIGNkZgpwbG90KGVjZGYoeHMpLCBtYWluID0gIkNERiBvZiBYfkJpbig4LCAwLjMpIiwKICAgIHlsYWIgPSBleHByZXNzaW9uKFAoWDw9eCkpLCB4bGFiID0gIngiKQpwYXIob3BhcikKYGBgCgoqKlE6KiogQ2hhbmdlIHRoZSBwcm9iYWJpbGl0eSwgJFxwaSQgcGFyYW1ldGVyIHRvIHZhbHVlIGNsb3NlIHRvIHplcm8uCldoYXQgZG8geW91IG9ic2VydmU/CkhvdyBkb2VzIGl0IHNrZXcgdGhlIGRpc3RyaWJ1dGlvbi4KTm93LCBpbmNyZWFzZSBcYG4nIHRvIGJpZ2dlciB2YWx1ZSwgZXZlbiBiaWdnZXIuCkRvIHlvdSBub3RpY2UgY29ycmVjdGlvbiBvZiB0aGUgc2tld25lc3M/CgoqKkV4ZXJjaXNlOioqIEdyYXBoIHRoZSAqKnBkZioqIGFuZCAqKmNkZioqIGZvciAkWCBcc2ltIEJpbigxMCxcZnJhY3sxfXsyfSkkIChcIyBvZiBoZWFkcyBvZiB0b3NzaW5nIGEgZmFpciBjb2luIDEwIHRpbWVzIGV4cGVyaW1lbnQpIGl0IGlzIHBhcnQgb2YgdGhlIHdlZWtseSBwcm9ncmFtbWluZyBleGVyY2lzZXMgUm1kIGZpbGUuCgojIyMjIFIgZnVuY3Rpb25zIGZvciBCaW5vbWlhbCBEaXN0cmlidXRpb24gQ2FsY3VsYXRpb25zCgoqKkRlc2NyaXB0aW9uKioKCkRlbnNpdHksIGRpc3RyaWJ1dGlvbiBmdW5jdGlvbiwgcXVhbnRpbGUgZnVuY3Rpb24gYW5kIHJhbmRvbSBnZW5lcmF0aW9uIGZvciB0aGUgYmlub21pYWwgZGlzdHJpYnV0aW9uIHdpdGggcGFyYW1ldGVycyBzaXplIGFuZCBwcm9iLgoKVGhpcyBpcyBjb252ZW50aW9uYWxseSBpbnRlcnByZXRlZCBhcyB0aGUgbnVtYmVyIG9mICdzdWNjZXNzZXMnIGluIHNpemUgdHJpYWxzLgoKVXNhZ2UKCmBkYmlub20oeCwgc2l6ZSwgcHJvYiwgbG9nID0gRkFMU0UpYCB0aGlzIGNvbXB1dGVzIHRoZSAqKnBkZioqIHZhbHVlcwoKYHBiaW5vbShxLCBzaXplLCBwcm9iLCBsb3dlci50YWlsID0gVFJVRSwgbG9nLnAgPSBGQUxTRSlgIHRoaXMgZ2l2ZXMgJFAoWCBcbGUgeCkkIHRoZSAqKnBkZioqIHZhbHVlcwoKYHFiaW5vbShwLCBzaXplLCBwcm9iLCBsb3dlci50YWlsID0gVFJVRSwgbG9nLnAgPSBGQUxTRSlgIHRoaXMgZ2l2ZXMgdGhlIHF1YW50aWxlcyAkUChYIFxsZSBrKSBcZ2UgcCQKCmByYmlub20obiwgc2l6ZSwgcHJvYilgCgpBcmd1bWVudHMKCmB4LCBxYCAtIHZlY3RvciBvZiBxdWFudGlsZXMuCmBwYCAtIHZlY3RvciBvZiBwcm9iYWJpbGl0aWVzLgpgbmAgLSBudW1iZXIgb2Ygb2JzZXJ2YXRpb25zLgpgc2l6ZWAgLSBudW1iZXIgb2YgdHJpYWxzICh6ZXJvIG9yIG1vcmUpLgpgcHJvYmAgLSBwcm9iYWJpbGl0eSBvZiBzdWNjZXNzIG9uIGVhY2ggdHJpYWwuCgoqKkV4YW1wbGU6KiogVXNpbmcgdGhlIGZ1bmN0aW9uIGByYmlub20oKWAsIG9uZSBjYW4gZ2VuZXJhdGUgMTAwMCBzYW1wbGVzIG9mIGEgJEJpbihuID0gNSwgXHBpID0gMC41KSQgYXMgc2hvd24gYmVsb3c6CgpgYGB7ciByYmlub219CgpzZXQuc2VlZCgxMjMpCnggPC0gcmJpbm9tKDEwMDAsIDUsIC41KQp0YWJsZSh4KS8xMDAwICMgVGhlIGVtcGlyaWNhbCBkaXN0cmlidXRpb24KCmBgYAoKKipFeGFtcGxlIDQuMyoqCgoqKkJpbm9taWFsIENhbGN1bGF0aW9uKiogQ29uc2lkZXIgdGhlIHByb2JsZW0gb2YgY2FsY3VsYXRpbmcgdGhlIHByb2JhYmlsaXR5IG9mIG9idGFpbmluZyBgNmAgb3IgbW9yZSBoZWFkcyBpbiBgMTBgIHRvc3NlcyBvZiBhICoqd2VpZ2h0ZWQqKiBjb2luIChub3QgZmFpciksIHdoZXJlIHRoZSBwcm9iYWJpbGl0eSBvZiBvYnRhaW5pbmcgYSBoZWFkIGluIGFueSBnaXZlbiB0cmlhbCBpcyBgMC4zM2AuCgpgYGB7cn0KIyBhZGRpbmcgcHJvYmFiaWxpdGllcyAKc3VtKGRiaW5vbSh4ID0gNjoxMCwgc2l6ZSA9IDEwLCBwcm9iID0gMC4zMykpICAgICAgICAgICMgUChYID49IDYpPVAoNikrUCg3KStQKDgpK1AoOSkrUCgxMCkKCiMgb3IKMSAtIHBiaW5vbSg1LCAxMCwgMC4zMykgICAgICAgICAgICAgICMgMSAtIFAoWCA8PSA1KQojb3IgCnBiaW5vbSg1LCAxMCwgMC4zMywgbG93ZXIgPSBGQUxTRSkgICAjIFAoWCA+PSA2KQojIG9yIAoxIC0gc3VtKGRiaW5vbSg1OjAsIDEwLCAwLjMzKSkgIyAxIC0gUChYIDw9IDUpCgpgYGAKCiMjIyA0LjIuMyBQb2lzc29uIERpc3RyaWJ1dGlvbgoKVGhlIFBvaXNzb24gZGlzdHJpYnV0aW9uIGlzIHZlcnkgcG9wdWxhciBmb3IgbW9kZWxpbmcgdGhlIG51bWJlciBvZiB0aW1lcyBwYXJ0aWN1bGFyIGV2ZW50cyBvY2N1ciBpbiBnaXZlbiB0aW1lcyBvciBvbiBkZWZpbmVkIHNwYWNlcywgb3IgaW4gZ2VuZXJhbCAqKnVuaXQqKiBpbnRlcnZhbCBvZiB0aW1lICh1bml0cyBvZiB0aW1lIG1heSB2YXJ5KS4KCkUuZy4KCi0gICBudW1iZXIgb2YgcGhvbmUgY2FsbHMgdG8gOTExIGJldHdlZW4gMSBhLm0uCiAgICBhbmQgMiBhLm0uCgotICAgbnVtYmVyIG9mIGFjY2lkZW50cyBhdCBhIGJ1c3kgc3RyZWV0IGNvcm5lciBkdXJpbmcgYSAyNC1ob3VyIHBlcmlvZAoKLSAgIG51bWJlciBvZiB0eXBvZ3JhcGhpY2FsIGVycm9ycyBvbiBhIHNpbmdsZSBwYWdlIG9mIHRoaXMgYm9vawoKU2VlIGRlZmluaXRpb24gb2YgKipQb2lzc29uIFByb2Nlc3MqKiBpbiB0aGUgdGV4dCwgcGFnZSAyNTYuCgpTdXBwb3NlIHRoZXJlIGlzIGFuIGV4cGVyaW1lbnQgdGhhdCBzYXRpc2ZpZXMgdGhlIHRocmVlIGNyaXRlcmlhIGZvciBhbiBhcHByb3hpbWF0ZSBQb2lzc29uIHByb2Nlc3Mgd2l0aCBwYXJhbWV0ZXIgJFxsYW1iZGEkLCAkXGxhbWJkYSQgbWVhbiBudW1iZXIgb2Ygb2NjdXJyZW5jZXMgb24gYSB1bml0IGludGVydmFsIG9mIHRpbWUuCgpMZXQgYFhgIHJlcHJlc2VudCB0aGUgbnVtYmVyIG9mIG91dGNvbWVzIGluIGFuIGludGVydmFsIG9mIGxlbmd0aCAxICh0ID0gMSkuCgpUaGVuIG9uZSBoYXM6CgoqKlBvaXNzb24gRGlzdHJpYnV0aW9uKiogbWVhbiwgYW5kIHZhcmlhbmNlIG9mIGEgYmlub21pYWwgcmFuZG9tIHZhcmlhYmxlIGFyZToKCiQkWCBcc2ltIFBvaXMoXGxhbWJkYSkkJAoKPiAxLiAgJCRQKFg9eHxcbGFtYmRhKT1cZnJhY3tcbGFtYmRhXnhlXnstXGxhbWJkYX19e3ghfSQkIGZvciAkeD0wLDEsMiwuLi4kCgo+IDIuICAkJEVbWF09XGxhbWJkYSQkCgo+IDMuICAkJFZhcltYXT1cbGFtYmRhJCQKCioqUmV2aWV3IHRoZSBjb2RlKiogdG8gc2VlIGhvdyB0byByZXByZXNlbnQgYSAqKnBkZioqIGFuZCAqKmNkZioqIGZvciBhIGBQb2lzKM67ID0gMSlgIHJhbmRvbSB2YXJpYWJsZS4KQWx0aG91Z2ggdGhlIHZhbHVlcyBgeGAgY2FuIHRha2Ugb24gd2l0aCB0aGUgUG9pc3NvbiBkaXN0cmlidXRpb24gYXJlIFwkMCwgMSwgMiwuLi4sIFwkIHRoZSBwcm9iYWJpbGl0eSBhIFBvaXNzb24gcmFuZG9tIHZhcmlhYmxlIGhhcyBhIHZhbHVlIG9mIGVpZ2h0IG9yIGdyZWF0ZXIgd2hlbiDOuyA9IDEgaXMgZXh0cmVtZWx5IHNtYWxsIChcPCAwKS4KQ29uc2VxdWVudGx5LCB0aGUgcGRmLCBhbmQgY2RmIGRvIG5vdCBleHRlbmQgYmV5b25kIGVpZ2h0LgoKYGBge3IgcGRmIGFuZCBjZGYgUG9pc30Kb3BhciA8LSBwYXIobm8ucmVhZG9ubHkgPSBUUlVFKQpwYXIobWZyb3c9YygxLCAyKSwgcHR5ID0gInMiKQoKeCA8LSAwOjgKcHggPC0gZHBvaXMoeCxsYW1iZGEgPSAxKSAjIGNvbXB1dGVzIHRoZSBwZGYgYXQgdGhlIHBvaW50cyB4CgojIHBsb3QgcHJvYmFiaWxpdHkgdnMgeC12YWx1ZXMKcGxvdCh4LCBweCwgdHlwZSA9ICJoIiwgeGxhYiA9ICJ4IiwgeWxhYj0iUChYID0geCkiLAogICAgbWFpbiA9ICJQREYgb2YgWCB+IFBvaXMoMSkiKQoKeHMgPC0gcmVwKDA6OCwgcm91bmQoZHBvaXMoMDo4LCAxKSoxMDAwMDAsIDApKSAjIGNyZWF0ZSB2ZWN0b3Igb2YgMTAwLDAwMCB2YWx1ZXMgYWNjb3JkaW5nIHRvIHRoZSBleHBlY3RlZCBudW1iZXIgb2Ygb2NjdXJyZW5jZXMgb2YgMHMsMXMsIDJzLCAuLi5hbmQgd2UgY3V0IGF0IDhzIG90aGVyIHZhbHVlcyBjYW4gYmUgaWdub3JlZAojIHBsb3QgdGhlIGVtcGlyaWNhbCBjZGYKcGxvdChlY2RmKHhzKSwgbWFpbiA9ICJDREYgb2YgWCB+IFBvaXMoMSkiLAogICAgeWxhYiA9IGV4cHJlc3Npb24oUChYIDw9eCkpLCB4bGFiID0gIngiKQoKcGFyKG9wYXIpCgpgYGAKCioqTm90ZToqKiBUaGUgUG9pc3NvbiBkaXN0cmlidXRpb24gaXMgcGFydGljdWxhcmx5IGFwcHJvcHJpYXRlIGZvciBtb2RlbGluZyAqKiJyYXJlIioqIHBoZW5vbWVuYSBvciBvdXRjb21lcyB3aGVyZSB0aGUgcHJvYmFiaWxpdHkgb2Ygc3VjY2VzcyBpcyBzbWFsbC4KCkdpdmVuIGBuYCAqKmluZGVwZW5kZW50KiogUG9pc3NvbiByYW5kb20gdmFyaWFibGVzICRYXzEsIFhfMizigKYsIFhfbiQgd2l0aCBwYXJhbWV0ZXJzICTOu18xLCDOu18yLOKApiwgzrtfbiQgcmVzcGVjdGl2ZWx5LCAkWT0gXHN1bV97aT0xfV5uIFhfaSBcc2ltIFBvaXMoXHN1bV97aT0xfV5uIFxsYW1iZGFfaT1cbGFtYmRhKSQKCioqRXhhbXBsZSA0LjYqKiBNb3JlIGFjY2lkZW50cyBhcmUgcmVnaXN0ZXJlZCBpbiBhdXRvIGJvZHkgcmVwYWlyIHNob3BzIGR1cmluZyB0aGUgbW9udGhzIG9mIE1heSBhbmQgSnVuZSB0aGFuIGluIHRoZSByZXN0IG9mIHRoZSB5ZWFyLgpTdXBwb3NlIGEgcGFydGljdWxhciBhdXRvIGJvZHkgcmVwYWlyIHNob3AgaGFzIGFuIGF2ZXJhZ2Ugb2YgZm91ciBhY2NpZGVudHMgcGVyIG1vbnRoLgpXaGF0IGlzIHRoZSBwcm9iYWJpbGl0eSB0aGVyZSB3aWxsIGJlIG1vcmUgdGhhbiBzZXZlbiBhY2NpZGVudHMgaW4gdGhpcyBhdXRvIGJvZHkgc2hvcCBkdXJpbmcgdGhlIG1vbnRoIG9mIE1heT8KV2hhdCBpcyB0aGUgcHJvYmFiaWxpdHkgbm8gbW9yZSB0aGFuIHRocmVlIGFjY2lkZW50cyB3aWxsIG9jY3VyIGR1cmluZyB0aGUgbW9udGhzIG9mIE1heSBhbmQgSnVuZT8KCioqU29sdXRpb246KiogQXNzdW1pbmcgYWNjaWRlbnRzIGluIHRoZSBhdXRvIGJvZHkgc2hvcCBmb2xsb3cgYW4gYXBwcm94aW1hdGUgUG9pc3NvbiBwcm9jZXNzLCB0aGUgcHJvYmFiaWxpdHkgb2YgYHhgIGFjY2lkZW50cyBpbiBvbmUgbW9udGggaXMKCiQkUChYPXh8NCk9XGZyYWN7NF54ZV57LTR9fXt4IX0kJCBmb3IgJHg9MCwxLDIsLi4uJAoKVXNpbmcgYFJgOgoKYGBge3J9CiMgbG93ZXIgcGFyYW1ldGVyIFRSVUUgLSBjb21wdXRlcyBwcm9iYWJpbGl0aWVzIHVwIHRvIHRoZSBwb2ludCwgRkFMU0UgdG8gdGhlIHJpZ2h0IG9mIHRoZSBwb2ludAoxIC0gcHBvaXMocSA9IDcsIGxhbWJkYSA9IDQsIGxvd2VyID0gVFJVRSkgICAgICAgICAgICAgICAjIFAoWCA+IDd8NCkgPSAxIC0gUChYPD03fDQpCgpwcG9pcyhxID0gNywgbGFtYmRhID0gNCwgbG93ZXIgPSBGQUxTRSkgICAgIyBQKFggPiA3fDQpIG5vdGljZSBsb3dlciA9IEZBTFNFCgpwcG9pcyhxID0gMywgbGFtYmRhID0gOCkgIyBQKFggPD0gM3w4KQoKYGBgCgojIyMjIFIgZnVuY3Rpb25zIGZvciB0aGUgUG9pc3NvbiBEaXN0cmlidXRpb24gQ2FsY3VsYXRpb25zCgoqKkRlc2NyaXB0aW9uKioKCkRlbnNpdHksIGRpc3RyaWJ1dGlvbiBmdW5jdGlvbiwgcXVhbnRpbGUgZnVuY3Rpb24gYW5kIHJhbmRvbSBnZW5lcmF0aW9uIGZvciB0aGUgUG9pc3NvbiBkaXN0cmlidXRpb24gd2l0aCBwYXJhbWV0ZXIgbGFtYmRhLgoKVXNhZ2UKCmBkcG9pcyh4LCBsYW1iZGEsIGxvZyA9IEZBTFNFKWAKCmBwcG9pcyhxLCBsYW1iZGEsIGxvd2VyLnRhaWwgPSBUUlVFLCBsb2cucCA9IEZBTFNFKWAKCmBxcG9pcyhwLCBsYW1iZGEsIGxvd2VyLnRhaWwgPSBUUlVFLCBsb2cucCA9IEZBTFNFKWAKCmBycG9pcyhuLCBsYW1iZGEpYAoKQXJndW1lbnRzCgpgeGAgLSB2ZWN0b3Igb2YgKG5vbi1uZWdhdGl2ZSBpbnRlZ2VyKSBxdWFudGlsZXMuCmBxYCAtIHZlY3RvciBvZiBxdWFudGlsZXMuCmBwYCAtIHZlY3RvciBvZiBwcm9iYWJpbGl0aWVzLgpgbmAgLSBudW1iZXIgb2YgcmFuZG9tIHZhbHVlcyB0byByZXR1cm4uCmBsYW1iZGFgIC0gdmVjdG9yIG9mIChub24tbmVnYXRpdmUpIG1lYW5zLgoKIyMjIDQuMi40IEdlb21ldHJpYyBEaXN0cmlidXRpb24KCkEgcmFuZG9tIHZhcmlhYmxlIGBYYCB0aGF0IGNvdW50cyB0aGUgbnVtYmVyIG9mIEJlcm5vdWxsaSB0cmlhbHMgdGhhdCByZXN1bHQgaW4gZmFpbHVyZSBiZWZvcmUgdGhlIGZpcnN0IHN1Y2Nlc3MgaXMgY2FsbGVkIGEgKipnZW9tZXRyaWMqKiByYW5kb20gdmFyaWFibGUuCkNsZWFybHksIHRoZSBwcm9iYWJpbGl0eSBvZiBhIHN1Y2Nlc3MgYWZ0ZXIgYHJgIGZhaWx1cmVzIGlzICTPgCDDlyAoMSDiiJIgz4ApXnIkLCB3aGljaCBsZWFkcyB0byB0aGUgZ2VvbWV0cmljIHByb2JhYmlsaXR5IGRpc3RyaWJ1dGlvbiBmdW5jdGlvbiB3aGVyZSAkXHJobyA9IDEg4oiSIM+AJCBpcyB0aGUgcHJvYmFiaWxpdHkgb2YgZmFpbHVyZS4KClRoZSAqKnBkZioqLCBtZWFuLCBhbmQgdmFyaWFuY2UgZm9yIGEgZ2VvbWV0cmljIHJhbmRvbSB2YXJpYWJsZSBhcmUgc2hvd24gYmVsb3c6CgokJFggXHNpbSBHZW8oXHBpKSQkICQkUChYPXh8XHBpKT1ccGlccmhvXngkJCBmb3IgJHg9MCwxLDIgLi4uJAoKJCRFW1hdPVxmcmFje1xyaG99e1xwaX0kJCAkJFZhcltYXT1cZnJhY3tccmhvfXtccGleMn0kJAoKVGhlIGNvZGUgYmVsb3cgY2FuIGJlIHVzZWQgdG8gY3JlYXRlIGdyYXBocyB0aGF0IHJlcHJlc2VudCB0aGUgcHJvYmFiaWxpdHkgZGVuc2l0eSBmdW5jdGlvbiBhbmQgdGhlIGN1bXVsYXRpdmUgZGlzdHJpYnV0aW9uIGZ1bmN0aW9uIGZvciBhICRHZW8oz4AgPSAwLjMpJCByYW5kb20gdmFyaWFibGUuCgpgYGB7ciBHZW99CgpvcGFyIDwtIHBhcihuby5yZWFkb25seSA9IFRSVUUpCnBhcihtZnJvdz1jKDEsIDIpLCBwdHkgPSAicyIpCnggPC0gMDoxNQpweCA8LSBkZ2VvbSh4ID0geCwgcHJvYiA9IC4zKQoKcGxvdCh4LCBweCwgdHlwZSA9ICJoIiwgeGxhYiA9ICJ4IiwgeWxhYj0iUChYID0geCkiLAogICAgIG1haW4gPSAiUERGIG9mIFggfiBHZW9tKDAuMykiKQp4cyA8LSByZXAoMDoxNSwgcm91bmQoZGdlb20oMDoxNSwgMC4zKSoxMDAwMDAsIDApKQpwbG90KGVjZGYoeHMpLCBtYWluID0gIkNERiBvZiBYIH4gR2VvbSgwLjMpIiwKICAgICB5bGFiID0gZXhwcmVzc2lvbihQKFggPD14KSksIHhsYWIgPSAieCIpCnBhcihvcGFyKQpgYGAKCioqUHIuIDE4IC8gcGFnZSAzMDggaW4gdGV4dCoqIFN1cHBvc2UgdGhlIHBlcmNlbnRhZ2Ugb2YgZHJpbmtzIHNvbGQgZnJvbSBhIHZlbmRpbmcgbWFjaGluZSBhcmUgODAlIGFuZCAyMCUgZm9yIHNvZnQgZHJpbmtzIGFuZCBib3R0bGVkIHdhdGVyLCByZXNwZWN0aXZlbHkuCgooYSkgV2hhdCBpcyB0aGUgcHJvYmFiaWxpdHkgdGhhdCBvbiBhIHJhbmRvbWx5IHNlbGVjdGVkIGRheSwgdGhlIGZpcnN0IHNvZnQgZHJpbmsgaXMgdGhlIGZvdXJ0aCBkcmluayBzb2xkPwooYikgRmluZCB0aGUgcHJvYmFiaWxpdHkgdGhhdCBleGFjdGx5IDEgb3V0IG9mIDEwIGRyaW5rcyBzb2xkIGlzIGEgc29mdCBkcmluay4KCioqU29sdXRpb246KiogTGV0IGBYYCA9IG51bWJlciBvZiB3YXRlcnMgKGZhaWx1cmVzKSBwdXJjaGFzZWQgYmVmb3JlIHRoZSBmaXJzdCBzb2Z0IGRyaW5rIGlzIHB1cmNoYXNlZC4KVGhlbiwgJFggXHNpbSBHZW8oMC44MCkkLgoKKGEpIAoKYGBge3IgcHIuIDE4YX0KCmRnZW9tKHggPSAzLCBwcm9iID0gMC44MCkgIyBQKFggPSAzKQoKYGBgCgooYikgTGV0IGBYYCA9IG51bWJlciBvZiBzb2Z0IGRyaW5rcyBzb2xkLiBUaGVuLCAkWCBcc2ltIEJpbigxMCwgMC44MCkkIGFuZCAkUChYID0gMSkgPSAwJCBzaW5jZSBvbmUgaGFzOgoKYGBge3IgcHIuIDE4Yn0KcGJpbm9tKHEgPSAxLCBzaXplID0gMTAsIHByb2IgPSAwLjgpICMgUChYID0gMSkKYGBgCgoqKk9wdGlvbmFsIHRvIHJldmlldzoqKiA0LjIuNSBOZWdhdGl2ZSBCaW5vbWlhbCBEaXN0cmlidXRpb24gJiA0LjIuNiBIeXBlcmdlb21ldHJpYyBEaXN0cmlidXRpb24KCiMjIDQuMyBDb250aW51b3VzIFVuaXZhcmlhdGUgRGlzdHJpYnV0aW9ucwoKIyMjIDQuMy4xIFVuaWZvcm0gRGlzdHJpYnV0aW9uIChDb250aW51b3VzKQoKPiBUaGUgY29udGludW91cyB1bmlmb3JtIGRpc3RyaWJ1dGlvbiBoYXMgYSAqKnBkZioqIHRoYXQgaXMgY29uc3RhbnQgb3ZlciBhIGNsb3NlZCBpbnRlcnZhbC4KCj4gQW4gaW1wb3J0YW50IGFwcGxpY2F0aW9uIG9mIHRoZSB1bmlmb3JtIGRpc3RyaWJ1dGlvbiBpbmNsdWRlcyByYW5kb20gbnVtYmVyIGdlbmVyYXRpb24uCgoqKlVuaWZvcm0gRGlzdHJpYnV0aW9uKioKCiQkWCBcc2ltIFVuaWYoYSxiKSQkCgo+IDEuICAkJGYoeHxhLGIpPVxmcmFjezF9e2ItYX0kJCBmb3IgJGEgXGxlIHggXGxlIGIkCgo+IDIuICAkJEVbWF09XGZyYWN7YithfXsyfSQkCgo+IDMuICAkJFZhcltYXT1cZnJhY3soYi1hKV4yfXsxMn0kJAoKR2VuZXJhdGluZyBQc2V1ZG8gUmFuZG9tIE51bWJlcnMgdXNpbmcgYFJgIGNvbW1hbmQgKnJkaXN0KiB3aGVyZSAqZGlzdCogaXMgZGlzdHJpYnV0aW9uIG5hbWUuClVzZSBgcnVuaWZgIGZvciB0aGUgbmV4dCBleGFtcGxlLgoKKipFeGFtcGxlOioqCgpGb3IgJFggXHNpbSBVbmlmKDIsNikkIG9uZSBoYXMgJEVbWF09NCQgYW5kICRWYXJbWF09XGZyYWN7MTZ9ezEyfT1cZnJhY3s0fXszfSQKCkVzdGltYXRlICRFW1hdJCBhbmQgJFZhcltYXSQgYnkgdXNpbmcgYSBsYXJnZSBudW1iZXIgb2YgdmFsdWVzIGRyYXduIGF0IHJhbmRvbSBmcm9tIGEgYFVuaWYoMiwgNilgLgoKYGBge3J9CnNldC5zZWVkKDEzKQpUTSA8LSA0ICMgdHJ1ZSBtZWFuClRWIDwtIDQvMyAjIHRydWUgdmFyaWFuY2UKCnggPC0gcnVuaWYobiA9IDEwMDAwLG1pbiA9IDIsbWF4ID0gNikKRXggPC0gbWVhbih4KQpFeAoKVnggPC0gbWVhbigoeC1FeCleMikKVngKClBFIDwtIGMoUGVyY2VudEVycm9yTWVhbiAgPSBhYnMoRXggLSBUTSkvVE0qMTAwLCAKICAgICAgICBQZXJjZW50RXJyb3JWYXJpYW5jZSA9IGFicyhWeCAtIFRWKS9UVioxMDApICMgcGVyY2VudCBlcnJvciBvZiB0aGUgZXN0aW1hdGUgZnJvbSB0aGUgdHJ1ZSBtZWFuIGFuZCB2YXIKQU5TIDwtIGMoU2ltTWVhbiA9IEV4LCBUaGVNZWFuID0gVE0sIFNpbVZhciA9IFZ4LCBUaGVWYXIgPSBUVikKQU5TCmBgYAoKIyMjIDQuMy4yIEV4cG9uZW50aWFsIERpc3RyaWJ1dGlvbgoKSWYgYFdgIGlzIHRoZSB3YWl0aW5nIHRpbWUgdW50aWwgdGhlIGZpcnN0IG91dGNvbWUgb2YgYSBgUG9pc3NvbmAgcHJvY2VzcyB3aXRoIG1lYW4gJFxsYW1iZGEgPiAwJCAoXCMgb2NjdXJyZW5jZXMgb3ZlciB1bml0IGludGVydmFsKSwgdGhlbiB0aGUgKipwZGYqKiwgbWVhbiwgYW5kIHZhcmlhbmNlIGZvciBgV2AgYXJlIHNob3duIGJlbG93OgoKPiAxLiAgJCRmKHh8IFxsYW1iZGEpPVxsYW1iZGEgZV57LVxsYW1iZGEgeH0kJCBmb3IgJHggXGdlIDAkLCBhbmQgMCBvdGhlcndpc2UKCj4gMi4gICQkRVtYXT1cZnJhY3sxfXtcbGFtYmRhfSQkCgo+IDMuICAkJFZhcltYXT1cZnJhY3sxfXtcbGFtYmRhXjJ9JCQKCkNvbnNlcXVlbnRseSwgd2hlbiAkdyA+IDAkLCB0aGUgKipwZGYqKiBvZiBgV2AgaXMgJEYnKHcpID0gZih3KSA9IM67ZV574oiSzrt3fSQuCgpUaGUgZXhwb25lbnRpYWwgZGlzdHJpYnV0aW9uIGlzIGNoYXJhY3Rlcml6ZWQgYnkgYSBsYWNrIG9mIG1lbW9yeSBwcm9wZXJ0eSBhbmQgaXMgb2Z0ZW4gdXNlZCB0byBtb2RlbCBsaWZldGltZXMgb2YgZWxlY3Ryb25pYyBjb21wb25lbnRzIGFzIHdlbGwgYXMgd2FpdGluZyB0aW1lcyBmb3IgUG9pc3NvbiBwcm9jZXNzZXMuCgpBIHJhbmRvbSB2YXJpYWJsZSBpcyBzYWlkIHRvIGJlICoqbWVtb3J5bGVzcyoqIGlmCgokJFAoWCA+IHRfMiArIHRfMSB8WCA+IHRfMSkgPSBQKFggPiB0XzIpJCQgZm9yIGFsbCAkdF8xLCB0XzIkCgoqKkV4ZXJjaXNlOioqIFRyeSB0byBzaG93IHRoYXQgYWJvdmUgaXMgZXF1aXZhbGVudCB0bwoKJCRQKFggPiB0XzIgKyB0XzEpPVAoWCA+IHRfMSkgUChYID4gdF8yKSQkIGZvciBhbGwgJHRfMSwgdF8yJAoKIyMjIyBSIGZ1bmN0aW9ucyBmb3IgdGhlIEV4cG9uZW50aWFsIERpc3RyaWJ1dGlvbgoKKipEZXNjcmlwdGlvbioqCgpEZW5zaXR5LCBkaXN0cmlidXRpb24gZnVuY3Rpb24sIHF1YW50aWxlIGZ1bmN0aW9uIGFuZCByYW5kb20gZ2VuZXJhdGlvbiBmb3IgdGhlIGV4cG9uZW50aWFsIGRpc3RyaWJ1dGlvbiB3aXRoIHJhdGUgcmF0ZSAoaS5lLiwgbWVhbiAxL3JhdGUpLgoKVXNhZ2UKCmBkZXhwKHgsIHJhdGUgPSAxLCBsb2cgPSBGQUxTRSlgCgpgcGV4cChxLCByYXRlID0gMSwgbG93ZXIudGFpbCA9IFRSVUUsIGxvZy5wID0gRkFMU0UpYAoKYHFleHAocCwgcmF0ZSA9IDEsIGxvd2VyLnRhaWwgPSBUUlVFLCBsb2cucCA9IEZBTFNFKWAKCmByZXhwKG4sIHJhdGUgPSAxKWAKCkFyZ3VtZW50cwoKYHgsIHFgIC0gdmVjdG9yIG9mIHF1YW50aWxlcy4KYHBgIC0gdmVjdG9yIG9mIHByb2JhYmlsaXRpZXMuCmBuYC0gbnVtYmVyIG9mIG9ic2VydmF0aW9ucy4KSWYgbGVuZ3RoKG4pIFw+IDEsIHRoZSBsZW5ndGggaXMgdGFrZW4gdG8gYmUgdGhlIG51bWJlciByZXF1aXJlZC4KYHJhdGVgIC0gdmVjdG9yIG9mIHJhdGVzLgpgbG9nLCBsb2cucGAgLSBsb2dpY2FsOyBpZiBUUlVFLCBwcm9iYWJpbGl0aWVzIHAgYXJlIGdpdmVuIGFzIGxvZyhwKS4KYGxvd2VyLnRhaWxgIC0gbG9naWNhbDsgaWYgVFJVRSAoZGVmYXVsdCksIHByb2JhYmlsaXRpZXMgYXJlIFBbWCDiiaQgeF0sIG90aGVyd2lzZSwgUFtYIFw+IHhdLgoKKipFeGFtcGxlIDQuMTcsIHBhZ2UgMjc5IGluIHRleHQqKgoKKipFeHBvbmVudGlhbCBEaXN0cmlidXRpb246IExpZ2h0IEJ1bGJzKiogSWYgdGhlIGxpZmUgb2YgYSBjZXJ0YWluIHR5cGUgb2YgbGlnaHQgYnVsYiBoYXMgYW4gZXhwb25lbnRpYWwgZGlzdHJpYnV0aW9uIHdpdGggYSBtZWFuIG9mIDggbW9udGhzLCBmaW5kCgooYSkgVGhlIHByb2JhYmlsaXR5IHRoYXQgYSByYW5kb21seSBzZWxlY3RlZCBsaWdodCBidWxiIGxhc3RzIGJldHdlZW4gMyBhbmQgMTIgbW9udGhzLgooYikgVGhlIDk1dGggcGVyY2VudGlsZSBvZiB0aGUgZGlzdHJpYnV0aW9uLgooYykgVGhlIHByb2JhYmlsaXR5IHRoYXQgYSBsaWdodCBidWxiIHRoYXQgaGFzIGxhc3RlZCBmb3IgMTAgbW9udGhzIHdpbGwgbGFzdCBtb3JlIHRoYW4gMjUgbW9udGhzLgoKKipTb2x1dGlvbjoqKgoKWU9VUiBDT0RFIEhFUkU6CgpgYGB7ciBFeC4gNC4xN30KIyB1bmNvbW1lbnQgdGhlIGNvZGUgYmVsb3cgdG8gc2VlIHNvbHV0aW9uIC0gZXhwbGFpbiB3aHkKcGV4cChxID0gMTIsIHJhdGUgPSAxLzgpIC0gcGV4cChxID0gMywgcmF0ZSA9IDEvOCkKCmYxIDwtIGZ1bmN0aW9uKHgpeygxLzgpICogZXhwKC14LzgpfSAgICAgICAgIyBkZWZpbmUgZjEKKGludGVncmF0ZShmMSwgbG93ZXIgPSAzLCB1cHBlciA9IDEyKSR2YWx1ZSkgICAjIGludGVncmF0ZSBmMQoKIyB0aGUgOTUgcXVhbnRpbGUvcGVyY2VudGlsZQpxZXhwKDAuOTUsIDEvOCkgCgpwZXhwKDI1LCAxLzgsIGxvd2VyID0gRkFMU0UpL3BleHAoMTAsIDEvOCwgbG93ZXIgPSBGQUxTRSkKIyBvcgoxIC0gcGV4cCgxNSwgMS84KQojIG9yCnBleHAoMTUsIDEvOCwgbG93ZXIgPSBGQUxTRSkKCmBgYAoKIyMjIDQuMy43IE5vcm1hbCAoR2F1c3NpYW4pIERpc3RyaWJ1dGlvbgoKPiBtb3N0IGltcG9ydGFudCBkaXN0cmlidXRpb24gaW4gc3RhdGlzdGljYWwgYXBwbGljYXRpb25zCgo+IG1hbnkgbnVtZXJpY2FsIHBvcHVsYXRpb25zIGhhdmUgZGlzdHJpYnV0aW9ucyB0aGF0IGNhbiBiZSBhcHByb3hpbWF0ZWQgd2l0aCB0aGUgbm9ybWFsIGRpc3RyaWJ1dGlvbi4KClRoZSAqKnBkZioqLCBtZWFuLCBhbmQgdmFyaWFuY2UgZm9yIGEgbm9ybWFsIHJhbmRvbSB2YXJpYWJsZSBYIHdpdGggbWVhbiDOvCBhbmQgdmFyaWFuY2UgJFxzaWdtYV4yJCBhcmUgcHJvdmlkZWQ6ICQkWCBcc2ltIE4oXG11LCBcc2lnbWFeMikkJCAkJCBmKHh8XG11LFxzaWdtYSkgPSBcZnJhY3sxfXtcc3FydHsyXHBpXHNpZ21hXjJ9fSBlXnstXGZyYWN7KHgtXG11KV4yfXsyXHNpZ21hXjJ9fSQkIGZvciAkLVxpbmZ0eSA8IHggPFxpbmZ0eSQKCiQkRVtYXT1cbXUkJAoKJCRWYXJbWF09XHNpZ21hXjIkJAoKIyMjIyBSIGZ1bmN0aW9ucyBmb3IgdGhlIE5vcm1hbCBEaXN0cmlidXRpb24KCioqRGVzY3JpcHRpb24qKgoKRGVuc2l0eSwgZGlzdHJpYnV0aW9uIGZ1bmN0aW9uLCBxdWFudGlsZSBmdW5jdGlvbiBhbmQgcmFuZG9tIGdlbmVyYXRpb24gZm9yIHRoZSBub3JtYWwgZGlzdHJpYnV0aW9uIHdpdGggbWVhbiBlcXVhbCB0byBtZWFuIGFuZCBzdGFuZGFyZCBkZXZpYXRpb24gZXF1YWwgdG8gc2QuCgpVc2FnZQoKYGRub3JtKHgsIG1lYW4gPSAwLCBzZCA9IDEsIGxvZyA9IEZBTFNFKWAKCmBwbm9ybShxLCBtZWFuID0gMCwgc2QgPSAxLCBsb3dlci50YWlsID0gVFJVRSwgbG9nLnAgPSBGQUxTRSlgCgpgcW5vcm0ocCwgbWVhbiA9IDAsIHNkID0gMSwgbG93ZXIudGFpbCA9IFRSVUUsIGxvZy5wID0gRkFMU0UpYAoKYHJub3JtKG4sIG1lYW4gPSAwLCBzZCA9IDEpYAoKQXJndW1lbnRzCgpgeCwgcWAgLSB2ZWN0b3Igb2YgcXVhbnRpbGVzLgpgcGAgLSB2ZWN0b3Igb2YgcHJvYmFiaWxpdGllcy4KYG5gIC0gbnVtYmVyIG9mIG9ic2VydmF0aW9ucy4KSWYgbGVuZ3RoKG4pIFw+IDEsIHRoZSBsZW5ndGggaXMgdGFrZW4gdG8gYmUgdGhlIG51bWJlciByZXF1aXJlZC4KYG1lYW5gIC0gdmVjdG9yIG9mIG1lYW5zLgpgc2RgIC0gdmVjdG9yIG9mIHN0YW5kYXJkIGRldmlhdGlvbnMuCgoqKkV4YW1wbGUgNC4yNSoqCgpTY29yZXMgb24gYSBwYXJ0aWN1bGFyIHN0YW5kYXJkaXplZCB0ZXN0IGZvbGxvdyBhIG5vcm1hbCBkaXN0cmlidXRpb24gd2l0aCBhIG1lYW4gb2YgMTAwIGFuZCBzdGFuZGFyZCBkZXZpYXRpb24gb2YgMTAuCgooYSkgV2hhdCBpcyB0aGUgcHJvYmFiaWxpdHkgdGhhdCBhIHJhbmRvbWx5IHNlbGVjdGVkIGluZGl2aWR1YWwgd2lsbCBzY29yZSBiZXR3ZWVuIDkwIGFuZCAxMTU/CihiKSBXaGF0IHNjb3JlIGRvZXMgb25lIG5lZWQgdG8gYmUgaW4gdGhlIHRvcCAxMCU/CihjKSBGaW5kIHRoZSBjb25zdGFudCBjIHN1Y2ggdGhhdCAkUCgxMDUgXGxlIFggXGxlIGMpID0gMC4xMCQuCgpgYGB7ciBub3JtfQoKIyAoYSkKcG5vcm0ocSA9IDExNSxtZWFuID0gIDEwMCwgc2QgPSAxMCkgLSBwbm9ybShxID0gOTAsIG1lYW4gPSAxMDAsIHNkID0gMTApICMgc2VlIHdoeQojIChiKSAKcW5vcm0ocCA9IC45MCwgbWVhbiA9IDEwMCwgc2QgPSAxMCkgIyBjaGVjayB3aHkKIyAoYykgCnFub3JtKDAuMTAgKyBwbm9ybSgxMDUsIDEwMCwgMTApLCAxMDAsIDEwKSAjIHNlZSB0aGUgdGV4dCBwYWdlIDI5OS4KYGBgCgoqKk1vdGl2YXRpb25hbCBQcm9ibGVtIChQci4gMjAgLyBwYWdlIDMwOSBpbiB0ZXh0KSoqCgpUaGUgd2Vla2x5IHByb2R1Y3Rpb24gb2YgYSBiYW5hbmEgcGxhbnRhdGlvbiBjYW4gYmUgbW9kZWxlZCB3aXRoIGEgbm9ybWFsIHJhbmRvbSB2YXJpYWJsZSB0aGF0IGhhcyBhIG1lYW4gb2YgNSB0b25zIGFuZCBhIHN0YW5kYXJkIGRldmlhdGlvbiBvZiAyIHRvbnMuCgooYSkgRmluZCB0aGUgcHJvYmFiaWxpdHkgdGhhdCwgaW4gYXQgbW9zdCAxIG91dCBvZiB0aGUgOCByYW5kb21seSBjaG9zZW4gd2Vla3MsIHRoZSBwcm9kdWN0aW9uIGhhcyBiZWVuIGxlc3MgdGhhbiAzIHRvbnMuCihiKSBGaW5kIHRoZSBwcm9iYWJpbGl0eSB0aGF0IGF0IGxlYXN0IDMgd2Vla3MgYXJlIG5lZWRlZCB0byBvYnRhaW4gYSBwcm9kdWN0aW9uIGdyZWF0ZXIgdGhhbiAxMCB0b25zLgoKKipTb2x1dGlvbjoqKgoKPiAoYSkgTGV0IFggPSBudW1iZXIgb2Ygd2Vla3Mgd2hlcmUgcHJvZHVjdGlvbiBpcyBsZXNzIHRoYW4gMyB0b25zLiBUaGVuLCAkWCBcc2ltIEJpbig4LCAwLjE1ODcpJC4gTGV0IFcgPSBwcm9kdWN0aW9uLCAkVyBcc2ltIE4oNSwgMikkIGFuZCAkUChXIFxsZSAzKSA9IDAuMTU4NyQuIFNvLCBQKFggXGxlIDEpID0gMC42Mjk4LiBDaGVjayB0aGUgY29kZSBiZWxvdyEKCmBgYHtyfQoKcCA8LSBwbm9ybSgzLCA1LCAyKSAjIFAoVyA8IDMpCnBiaW5vbSgxLCA4LCBwKQoKYGBgCgooYikgTGV0ICRYX24kID0gbnVtYmVyIG9mIHdlZWtzIHdoZXJlIHByb2R1Y3Rpb24gaXMgbGVzcyB0aGFuIDEwIHRvbnMgYmVmb3JlIHRoZSBmaXJzdCB3ZWVrIHdpdGggcHJvZHVjdGlvbiBvdmVyIDEwIHRvbnMuICRYX24gXHNpbSBHZW8oXHBpID0gUChXIFxnZSAxMCkgPSAwLjAwNjIpJCwgYW5kICRQKFhfbiBcZ2UgMikgPSAxIOKIkiBQKFhuIFxsZSAxKSA9IDAuOTg3NiQuCgpgYGB7cn0KUEkgPC0gMSAtIHBub3JtKHEgPSAxMCxtZWFuID0gIDUsIHNkID0gMikgIyBQKFcgPj0gMTApClBJCgoxIC0gcGdlb20oMSwgUEkpCjAuOTg3NjE5MgoKYGBgCgojIyMjIFF1YW50aWxlLVF1YW50aWxlIFBsb3RzIGZvciBOb3JtYWwgRGlzdHJpYnV0aW9ucyAoUS1RIFBsb3RzKQoKPiBNYW55IG9mIHRoZSB0ZWNobmlxdWVzIGFuZCB0ZXN0aW5nIGFzc3VtZSB0aGUgdW5kZXJseWluZyBkaXN0cmlidXRpb24gaXMgbm9ybWFsLgoKPiBPbmUgb2YgdGhlIG1vcmUgdXNlZnVsIGdyYXBoaWNhbCBwcm9jZWR1cmVzIGZvciBhc3Nlc3NpbmcgZGlzdHJpYnV0aW9ucyBpcyB0aGUgcXVhbnRpbGUtcXVhbnRpbGUgcGxvdC4KPiAoUmVjYWxsIGZyb20gU2VjdGlvbiAyLjcuMyB0aGF0IHRoaXMgZ3JhcGggaXMgYWxzbyBjYWxsZWQgYSBRLVEgcGxvdC4pCgo+IFIgZnVuY3Rpb24gYHFxbm9ybSgpYCBoZWxwcyBkZXRlcm1pbmUgd2hldGhlciB0aGUgdW5kZXJseWluZyBkaXN0cmlidXRpb24gaXMgbm9ybWFsLgoKXCpcKiBFeGFtcGxlXCpcKiBDb25zaWRlciB0aGUgdmFsdWVzIHN0b3JlZCBpbiB0aGUgdmFyaWFibGUgc2NvcmVzIG9mIHRoZSBkYXRhIGZyYW1lIGBTQ09SRWAgKGluIHRoZSBgUEFTV1IyYCBwYWNrYWdlKSBhbmQgc2hvd24gYmVsb3cgd2hpY2ggYXJlIHRoZSBzY29yZXMgYSByYW5kb20gc2FtcGxlIG9mIDIwIGNvbGxlZ2UgZnJlc2htZW4gcmVjZWl2ZWQgb24gYSBzdGFuZGFyZGl6ZWQgdGVzdC4KCj4gMTE5IDEwNyA5NiAxMDcgOTcgMTAzIDk0IDEwNiA4NyAxMTIgOTkgOTkgOTAgMTA2IDExMCA5OSAxMDUgMTAwIDEwMCA5NAoKVG8gY29tcHV0ZSB0aGUgcGFpcnMgb2YgdmFsdWVzIHBsb3R0ZWQgaW4gYW4gYFIgcXVhbnRpbGUtcXVhbnRpbGUgcGxvdGAgZm9yIHRoZSB2YXJpYWJsZSBzY29yZXMgb2YgdGhlIGRhdGEgZnJhbWUgU0NPUkUgaW5zcGVjdCB0aGUgY29kZSBiZWxvdzoKCmBgYHtyfQpuIDwtIGxlbmd0aChTQ09SRSRzY29yZXMpICMgbnVtYmVyIG9mIG9ic2VydmF0aW9ucwoKWCA8LSAoMTpuIC0gMS8yKS9uICMgMTAwJSBzcGxpdCBpbnRvIG49MjAgZXF1YWwgaW50ZXJ2YWxzClhzIDwtIHFub3JtKFgpICMgcXVhbnRpbGVzIG9mIFgKWXMgPC0gc29ydChTQ09SRSRzY29yZXMpICMgc29ydGVkIHNjb3JlcwpwbG90KFhzLCBZcykgIyBwbG90IFlzIHZzIFhzCnF1YW50aWxlKFhzLCBjKDAuMjUsIDAuNzUpKSAKcXVhbnRpbGUoWXMsIGMoMC4yNSwgMC43NSkpCgpxcW5vcm0oU0NPUkUkc2NvcmVzKSAjdXNpbmcgcXFub3JtCnFxbGluZShTQ09SRSRzY29yZXMpICNhZGRpbmcgbGluZSB0aHJvdWdoIDFzdCBhbmQgM3JkIHF1YW50aWxlCmBgYAoKWW91IGNhbiBkbyB0aGlzIHVzaW5nIGBnZ3Bsb3QyYCBtdWNoIG5pY2VyOgoKYGBge3J9CmdncGxvdChkYXRhID0gU0NPUkUsIGFlcyhzYW1wbGUgPSBzY29yZXMpKSArIHN0YXRfcXEoKQpgYGAKCioqUkVNSU5ERVI6IERPIE5PVCBNSVNTIFRPIFJFVklFVyBUSEUgUFJPR1JBTU1JTkcgRVhFUkNJU0VTIGJlZm9yZSB5b3UgYXR0ZW1wdCB0aGUgcXVpeiBmb3IgdGhlIHdlZWshKioK