Whether you’re guessing if it’s going to rain tomorrow, betting on a sports team to win an away match, or framing a policy for an insurance company, probability and distributions come into action in all aspects of life to determine the likelihood of events. But before we jump into probabilities, let’s remind ourselves with the types of data.

Fig. 1: Examples of discrete vs continuous data. Image source: datasciencedojo
Fig. 1: Examples of discrete vs continuous data. Image source: datasciencedojo

Test: Volume of water in a tank represents what type of data?

Volume often represents continuous data

Note that the distinction between discrete and continuous data is not always clear-cut. Sometimes it is convenient to treat data as if they were continuous, even though strictly speaking they are not continuous.

To bring one such example, we will look into the ‘Lengths of Major North American Rivers’ dataset

print(rivers)
  [1]  735  320  325  392  524  450 1459  135  465  600  330  336  280  315
 [15]  870  906  202  329  290 1000  600  505 1450  840 1243  890  350  407
 [29]  286  280  525  720  390  250  327  230  265  850  210  630  260  230
 [43]  360  730  600  306  390  420  291  710  340  217  281  352  259  250
 [57]  470  680  570  350  300  560  900  625  332 2348 1171 3710 2315 2533
 [71]  780  280  410  460  260  255  431  350  760  618  338  981 1306  500
 [85]  696  605  250  411 1054  735  233  435  490  310  460  383  375 1270
 [99]  545  445 1885  380  300  380  377  425  276  210  800  420  350  360
[113]  538 1100 1205  314  237  610  360  540 1038  424  310  300  444  301
[127]  268  620  215  652  900  525  246  360  529  500  720  270  430  671
[141] 1770
str(rivers)
 num [1:141] 735 320 325 392 524 ...

The output says that rivers is a numeric vector of length 141, and the first few values are 735, 320, 325, etc. These data are definitely quantitative and it appears that the measurements have been rounded to the nearest mile. Thus, strictly speaking, these are discrete data. But we will find it convenient later to take data like these to be continuous for some of our statistical procedures.

Differentiating between discrete and continuous data is important as probability distributions are grouped into two categories, discrete distributions for discrete data (finite outcomes) and continuous distributions for continuous data (infinite outcomes).

What is a probability distribution?

In probability theory and statistics, a probability distribution is the mathematical function that gives the probabilities of occurrence of different possible outcomes for an experiment. It is a mathematical description of a random phenomenon in terms of its sample space and the probabilities of events (subsets of the sample space).

A probability density function is a mathematical function that describes a continuous probability distribution. It provides the probability density of each value of a variable, which can be greater than one.

A probability density function can be represented as an equation or as a graph.

In graph form, a probability density function is a curve. You can determine the probability that a value will fall within a certain interval by calculating the area under the curve within that interval. You can use reference tables or software to calculate the area.

The area under the whole curve is always exactly one because it’s certain (i.e., a probability of one) that an observation will fall somewhere in the variable’s range.

A cumulative distribution function is another type of function that describes a continuous probability distribution.

Types of probability distributions

There are many types of probability distributions depending on the type of data used. A few of the common ones are shown in Fig. 2 below. For a more comprehensive list, you can see here. Note that you don’t need to memorize all these

Fig. 2: Common types of probability distributions. Image source: datasciencedojo
Fig. 2: Common types of probability distributions. Image source: datasciencedojo

Discrete distributions

Discrete uniform distribution:

All outcomes are equally likely

In statistics, uniform distribution refers to a statistical distribution in which all outcomes are equally likely. Consider rolling a six-sided die. You have an equal probability of obtaining all six numbers on your next roll, i.e., obtaining precisely one of 1, 2, 3, 4, 5, or 6, equaling a probability of 1/6, hence an example of a discrete uniform distribution.

As a result, the uniform distribution graph contains bars of equal height representing each outcome. In our example, the height is a probability of 1/6 (0.166667).

[Fig. 3: Uniform distribution of the outcomes of throwing a dice event. Image source: datasciencedojo] (https://datasciencedojo.com/wp-content/uploads/fair-dice-uniform-distribution.webp)

To recreate this in R, we can use the sample command:

sample(1:6, 1)
[1] 1

1:6 indicate the possible outcomes are 1,2,3,4,5,6 (for the numbers on the dice) and 1 after the comma indicates how many times we threw the dice. If you run the above chunk again, there’s a good chance you will get a different outcome. However, all outcomes have equal probability of showing up, just like when you throw a dice.

To try multiple dice throws:

sample(1:6, 3, replace = T)
[1] 5 3 2

In the above example, we threw the dice three times. We used the replace command so that the number that comes up can reappear again, thereby keeping equal probability for all outcomes. This is called an independent event if one experiment’s outcome does not affect the other event’s probabilities.

A contrasting example to this would be if you are selecting out candidates. e.g. giving away gifts and you don’t want the same person to receive 2 or more gifts. So once their name comes out, they are taken out of the lottery pool. In that case, you can select replace = F.

For example:

sample(1:6, 5, replace = F)
[1] 6 5 3 4 2

None of the numbers show up again after throwing the dice 5 times.

Now let’s roll a thousand times and save the output vector to an object that we can do something with:

rolls = sample(1:6, 1000, replace = TRUE)
table(rolls)
rolls
  1   2   3   4   5   6 
154 162 156 156 195 177 
dice_data = data.frame(outcome=rolls)
dice_data

The table output above shows how many times each number came up after rolling the dice 1000 times. Let’s create a histogram of the above to visualize it.

library(ggplot2)
Use suppressPackageStartupMessages() to eliminate package startup
messages
ggplot(dice_data, aes(x = outcome)) +
  geom_histogram(binwidth = 1, fill = "grey", color = "black") +
  labs(title = "Histogram of Dice Roll Outcomes",
       x = "Dice Roll Outcome",
       y = "Frequency")+
  theme_bw()

So although each number had the same exact probability to show up (1/6 = 0.1666667), the results still show a slight variability in the final outcomes.

To demonstrate this in a clearer way:

table(rolls) / 1000
rolls
    1     2     3     4     5     6 
0.154 0.162 0.156 0.156 0.195 0.177 

Note: the higher the sample size (n), the closer these numbers will get to achieving 1/6 probability.

Let’s do a few exercises:

What is the probability of throwing a dice once and getting a 4 or higher?

(1/6)+(1/6)+(1/6)
[1] 0.5

Under a uniform distribution, the probability of each outcome is 1/6 = 0.1666667, so to get 4, 5, or 6, we have 3/6 = 50%

What is the probability of getting 1 or 5 when a fair six-sided die is rolled?

(2/6)
[1] 0.3333333

What is the probability of throwing a dice twice and getting at least one 6?

(1/6)+(1/6)
[1] 0.3333333

What is the probability of throwing a dice twice and getting two 6?

(1/6)*(1/6)
[1] 0.02777778

As in the latter case it is a must to get a “6” both times, we multiply the probability of each throw instead of adding. The result then is only 2.8% chance.

When two dice are thrown simultaneously, the number of events is \(6^2 = 36\) because each die has 1 to 6 number on its faces. The possible outcomes are shown in the below table.

Fig. 3: Outcomes for throwing a dice twice.
Fig. 3: Outcomes for throwing a dice twice.

As you can see, our outcome is only 1/36 possible outcomes, hence = 2.8%.

What is the probability of throwing a dice twice and getting sum ≤ 4.

Looking at the table, we can see there are 6/36 possible outcomes that result in a sum 4 or lower. Therefore:

(6/36)
[1] 0.1666667

If we want to write the above as a formula:

((1/6)*(3/6)+(1/6)*(2/6)+(1/6)*(1/6))
[1] 0.1666667

What is the probability of throwing a dice twice and getting 2 even numbers?

(3/6)*(3/6)
[1] 0.25

**Important to remember: When you read or you use addition (+), when you read and, you use multiplication (*).**

Bernoulli Distribution:

Single-trial with two possible outcomes

The Bernoulli distribution is one of the easiest distributions to understand. It can be used as a starting point to derive more complex distributions. Any event with a single trial and only two outcomes follows a Bernoulli distribution. Flipping a coin or choosing between True and False in a quiz are examples of a Bernoulli distribution.

They have a single trial and only two outcomes. Let’s assume you flip a coin once; this is a single trail. The only two outcomes are either heads or tails. This is an example of a Bernoulli distribution.

Usually, when following a Bernoulli distribution, we have the probability of one of the outcomes (p). From (p), we can deduce the probability of the other outcome by subtracting it from the total probability (1), represented as (1-p).

Binomial Distribution:

A sequence of Bernoulli events

The Binomial Distribution can be thought of as the sum of outcomes of an event following a Bernoulli distribution. Therefore, Binomial Distribution is used in binary outcome events, and the probability of success and failure is the same in all successive trials. An example of a binomial event would be flipping a coin multiple times to count the number of heads and tails.

Binomial vs Bernoulli distribution:

The difference between these distributions can be explained through an example. Consider you’re attempting a quiz that contains 10 True/False questions. Trying a single T/F question would be considered a Bernoulli trial, whereas attempting the entire quiz of 10 T/F questions would be categorized as a Binomial trial.

The main characteristics of Binomial Distribution are:

  • In multiple trials, each trial is independent of the other. That is, the outcome of one trial doesn’t affect another one. Each trial can lead to just two possible results (e.g., winning or losing), with probabilities p and (1 – p).

  • A binomial distribution is represented by B (n, p), where n is the number of trials and p is the probability of success in a single trial. A Bernoulli distribution can be shaped as a binomial trial as B (1, p) since it has only one trial.

In R, there are a number of commands you can use for binomial distributions. The 3 most commonly used ones are dbinom, pbinom, rbinom.

  1. dbinom function finds the probability of getting a certain number of successes (x) from a certain number of trials (size) where the probability of success on each trial is fixed (prob). You can write it as follows:

dbinom (x, size, prob)

  1. The function pbinom returns the value of the cumulative density function of the binomial distribution given a certain random variable q, number of trials (size) and probability of success on each trial (prob).

The syntax for using pbinom is as follows:

pbinom(q, size, prob)

Put simply, pbinom returns the area to the left of a given value q in the binomial distribution. If you’re interested in the area to the right of a given value q, you can simply add the argument lower.tail = FALSE. Here’s an example:

pbinom(q, size, prob, lower.tail = FALSE)

  1. The function rbinom generates a vector of binomial distributed random variables given a vector length n, number of trials (size) and probability of success on each trial (prob). The syntax for using rbinom is as follows:

rbinom(n, size, prob)

Let’s test these with a few exercises:

According to ESPN, Lebron James is a career 73.5% Free Throw shooter. In his last game, James attempted 8 FTs. What is the probability that he scored exactly 6 of them?

dbinom(6,8, 0.735)
[1] 0.3100087

According to the same source, James is currently having his second-best year in 3-pt% of his career, scoring 40.1% of all attempts from beyond the arc. If he attempts 7 such shots in the next game, what’s the probability that he will score 4 times or less?

Since this is a cumulative probability (indicating he will score 0, 1, 2, 3, or 4 attempts out of 7), we use the pbinom command:

pbinom(4,7, 0.401)
[1] 0.9027731

Same as the previous question, what’s the probability that he will miss at least 3 times?

Trick question: exactly the same as the one before it.

Same as the last 2 questions, what’s the probability that he will score 3 times or more?

pbinom(3,7, 0.401, lower.tail = FALSE)
[1] 0.2917298

Poisson Distribution:

The probability that an event may or may not occur

The Poisson distribution deals with the frequency with which an event occurs within a specific interval. Instead of the probability of an event, Poisson distribution requires knowing how often it happens in a particular period or distance. For example, a cricket chirps two times in 7 seconds on average. We can use the Poisson distribution to determine the likelihood of it chirping five times in 15 seconds.

A Poisson process is represented with the notation Po(λ), where λ represents the expected number of events that can take place in a period. X represents the discrete random variable.

The main characteristics which describe the Poisson processes are:

  • The events are independent of each other.
  • An event can occur any number of times (within the defined period).
  • Two events can’t take place simultaneously.

Fig. 4: Poisson distribution plot of the number of instances an event occurs in the standard interval of time and the probability of each one. Source: datasciencedojo In R, the syntax used for a Poisson distribution is similar to that of the binomial distribution but with pois being used instead of binom (see Fig. 5 below).

Fig. 5: Poisson distribution syntax in R
Fig. 5: Poisson distribution syntax in R

On average, I receive 35 emails per day. What is the probability that I receive more than more than 40 emails today?

Since we are looking for a cumulative distribution (>41 emails), we’ll use the ppois command. Moreover, since we are looking for the area below the right tail, we’ll add lower.tail=F to our syntax.

ppois(40, 35, lower.tail = FALSE)
[1] 0.1750619

Continuous distributions

Normal Distribution:

Symmetric distribution of values around the mean

Normal distribution is the most used distribution in data science. In a normal distribution graph, data is symmetrically distributed with no skew. When plotted, the data follows a bell shape, with most values clustering around a central region and tapering off as they go further away from the center.

The normal distribution frequently appears in nature and life in various forms. For example, the scores of a quiz follow a normal distribution. Many of the students scored between 60 and 80 as illustrated in the graph below. Of course, students with scores that fall outside this range are deviating from the center.

Fig. 6: Normal distribution graph
Fig. 6: Normal distribution graph

Here, you can witness the “bell-shaped” curve around the central region, indicating that most data points exist there. The normal distribution is represented as N(µ, σ2) here, µ represents the mean, and σ2 represents the variance, one of which is mostly provided. The expected value of a normal distribution is equal to its mean. Some of the characteristics which can help us to recognize a normal distribution are:

  • The curve is symmetric at the center. Therefore mean, mode, and median are equal to the same value, distributing all the values symmetrically around the mean.
  • The area under the distribution curve equals 1 (all the probabilities must sum up to 1).

While plotting a graph for a normal distribution, 68% of all values lie within one standard deviation from the mean. In the example above, if the mean is 70 and the standard deviation is 10, 68% of the values will lie between 60 and 80. Similarly, 95% of the values lie within two standard deviations from the mean, and 99.7% lie within three standard deviations from the mean. This last interval captures almost all matters. If a data point is not included, it is most likely an outlier.

In R, the syntax for normal distributions follows the same logic as those of binomial and poisson distributions, replacing binom and pois, respectively with norm. Thus, the functions are as follows:

Fig. 7: Normal distribution syntax in R
Fig. 7: Normal distribution syntax in R

Suppose the scores on a test follow a normal distribution with a mean of 70 and a standard deviation of 10. Calculate the probability that a randomly selected student scores between 60 and 80.

r1 = pnorm(80, 70, 10) - pnorm(60, 70, 10)
r1
[1] 0.6826895

Same sample as above, calculate the score below which 90% of the students fall.

qnorm(0.9, mean = 70, sd = 10)
[1] 82.81552

Student t-Test Distribution:

Small sample size approximation of a normal distribution

The student’s t-distribution, also known as the t distribution, is a type of statistical distribution similar to the normal distribution with its bell shape but has heavier tails. The t distribution is used instead of the normal distribution when you have small sample sizes.

For example, suppose we deal with the total apples sold by a shopkeeper in a month. In that case, we will use the normal distribution. Whereas, if we are dealing with the total amount of apples sold in a day, i.e., a smaller sample, we can use the t distribution.

Another critical difference between the students’ t distribution and the Normal one is that apart from the mean and variance, we must also define the degrees of freedom for the distribution. In statistics, the number of degrees of freedom is the number of values in the final calculation of a statistic that are free to vary. A Student’s t distribution is represented as t(k), where k represents the number of degrees of freedom. For k=2, i.e., 2 degrees of freedom, the expected value is the same as the mean.

Exponential distribution:

Exponential distribution is one of the widely used continuous distributions. It is used to model the time taken between different events. For example, in physics, it is often used to measure radioactive decay; in engineering, to measure the time associated with receiving a defective part on an assembly line; and in finance, to measure the likelihood of the next default for a portfolio of financial assets. Another common application of Exponential distributions in survival analysis (e.g., expected life of a device/machine).

The exponential distribution is commonly represented as Exp(λ), where λ is the distribution parameter, often called the rate parameter. We can find the value of λ by the formula = 1/μ, where μ is the mean. Here standard deviation is the same as the mean. Var (x) gives the variance = 1/λ2

Fig. 6: Exponential distribution curve
Fig. 6: Exponential distribution curve

An exponential graph is a curved line representing how the probability changes exponentially. Exponential distributions are commonly used in calculations of product reliability or the length of time a product lasts.

LS0tCnRpdGxlOiAiUHJvYmFiaWxpdHkgRGlzdHJpYnV0aW9ucyIKc3VidGl0bGU6ICJBbWVyaWNhbiBVbml2ZXJzaXR5IG9mIEFybWVuaWEiCmF1dGhvcjogIkVTUyAxMDMgLSBTcHJpbmcgMjAyNCIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKV2hldGhlciB5b3XigJlyZSBndWVzc2luZyBpZiBpdOKAmXMgZ29pbmcgdG8gcmFpbiB0b21vcnJvdywgYmV0dGluZyBvbiBhIHNwb3J0cyB0ZWFtIHRvIHdpbiBhbiBhd2F5IG1hdGNoLCBvciBmcmFtaW5nIGEgcG9saWN5IGZvciBhbiBpbnN1cmFuY2UgY29tcGFueSwgKipwcm9iYWJpbGl0eSoqIGFuZCAqKmRpc3RyaWJ1dGlvbnMqKiBjb21lIGludG8gYWN0aW9uIGluIGFsbCBhc3BlY3RzIG9mIGxpZmUgdG8gZGV0ZXJtaW5lIHRoZSBsaWtlbGlob29kIG9mIGV2ZW50cy4gQnV0IGJlZm9yZSB3ZSBqdW1wIGludG8gcHJvYmFiaWxpdGllcywgbGV0J3MgcmVtaW5kIG91cnNlbHZlcyB3aXRoIHRoZSB0eXBlcyBvZiBkYXRhLgoKLSAqKkRpc2NyZXRlKiogZGF0YSBoYXZlIGEgbGltaXRlZCBudW1iZXIgb2Ygb3V0Y29tZXMgcG9zc2libGUuIEV4YW1wbGVzIGluY2x1ZGU6IGNvdW50cywgbnVtYmVyIG9mIGFycml2YWxzLCBvciBudW1iZXIgb2Ygc3VjY2Vzc2VzLiBUaGV5IGFyZSBvZnRlbiByZXByZXNlbnRlZCBieSBpbnRlZ2Vycywgc2F5LCAwLCAxLCAyLCAqZXRjKi4gKmUuZy4qIFRoZSBudW1iZXIgb2Ygc3R1ZGVudHMgaW4gY2xhc3MuCi0gKipDb250aW51b3VzKiogZGF0YSBoYXZlIGluZmluaXRlIG9yIGNvbnRpbnVvdXMgb3V0Y29tZXMuIFRoZXNlIGFyZSBhbHNvIGtub3duIGFzIHNjYWxlIGRhdGEsIGludGVydmFsIGRhdGEsIG9yIG1lYXN1cmVtZW50IGRhdGEuIEV4YW1wbGVzIGluY2x1ZGU6IGhlaWdodCwgd2VpZ2h0LCBsZW5ndGgsIHRpbWUsICpldGMuKiBDb250aW51b3VzIGRhdGEgYXJlIG9mdGVuIGNoYXJhY3Rlcml6ZWQgYnkgZnJhY3Rpb25zIG9yIGRlY2ltYWxzOiAzLjgyLCA3LjAwMDEsICpldGMqLiAKCiFbRmlnLiAxOiBFeGFtcGxlcyBvZiBkaXNjcmV0ZSB2cyBjb250aW51b3VzIGRhdGEuIEltYWdlIHNvdXJjZTogZGF0YXNjaWVuY2Vkb2pvXShodHRwczovL2RhdGFzY2llbmNlZG9qby5jb20vd3AtY29udGVudC91cGxvYWRzL2Rpc2NyZXRlLXZzLWNvbnRpbnVvdXMtZGF0YS1lMTY2MDE0ODYwNDQwNi53ZWJwKQoKCjxzcGFuIHN0eWxlPSJjb2xvcjpyZWQiPiAqKlRlc3Q6IFZvbHVtZSBvZiB3YXRlciBpbiBhIHRhbmsgcmVwcmVzZW50cyB3aGF0IHR5cGUgb2YgZGF0YT8qKiA8L3NwYW4+Cgo+IFZvbHVtZSBvZnRlbiByZXByZXNlbnRzIGNvbnRpbnVvdXMgZGF0YQoKTm90ZSB0aGF0IHRoZSBkaXN0aW5jdGlvbiBiZXR3ZWVuIGRpc2NyZXRlIGFuZCBjb250aW51b3VzIGRhdGEgaXMgbm90IGFsd2F5cyBjbGVhci1jdXQuIFNvbWV0aW1lcyBpdCBpcyBjb252ZW5pZW50IHRvIHRyZWF0IGRhdGEgYXMgaWYgdGhleSB3ZXJlIGNvbnRpbnVvdXMsIGV2ZW4gdGhvdWdoIHN0cmljdGx5IHNwZWFraW5nIHRoZXkgYXJlIG5vdCBjb250aW51b3VzLiAKClRvIGJyaW5nIG9uZSBzdWNoIGV4YW1wbGUsIHdlIHdpbGwgbG9vayBpbnRvIHRoZSAqJ0xlbmd0aHMgb2YgTWFqb3IgTm9ydGggQW1lcmljYW4gUml2ZXJzJyogZGF0YXNldApgYGB7cn0KcHJpbnQocml2ZXJzKQpzdHIocml2ZXJzKQpgYGAKVGhlIG91dHB1dCBzYXlzIHRoYXQgcml2ZXJzIGlzIGEgbnVtZXJpYyB2ZWN0b3Igb2YgbGVuZ3RoIDE0MSwgYW5kIHRoZSBmaXJzdCBmZXcgdmFsdWVzIGFyZSA3MzUsIDMyMCwgMzI1LCAqZXRjLiogVGhlc2UgZGF0YSBhcmUgZGVmaW5pdGVseSBxdWFudGl0YXRpdmUgYW5kIGl0IGFwcGVhcnMgdGhhdCB0aGUgbWVhc3VyZW1lbnRzIGhhdmUgYmVlbiByb3VuZGVkIHRvIHRoZSBuZWFyZXN0IG1pbGUuIFRodXMsIHN0cmljdGx5IHNwZWFraW5nLCB0aGVzZSBhcmUgZGlzY3JldGUgZGF0YS4gQnV0IHdlIHdpbGwgZmluZCBpdCBjb252ZW5pZW50IGxhdGVyIHRvIHRha2UgZGF0YSBsaWtlIHRoZXNlIHRvIGJlIGNvbnRpbnVvdXMgZm9yIHNvbWUgb2Ygb3VyIHN0YXRpc3RpY2FsIHByb2NlZHVyZXMuCgpEaWZmZXJlbnRpYXRpbmcgYmV0d2VlbiBkaXNjcmV0ZSBhbmQgY29udGludW91cyBkYXRhIGlzIGltcG9ydGFudCBhcyBwcm9iYWJpbGl0eSBkaXN0cmlidXRpb25zIGFyZSBncm91cGVkIGludG8gdHdvIGNhdGVnb3JpZXMsIGRpc2NyZXRlIGRpc3RyaWJ1dGlvbnMgZm9yIGRpc2NyZXRlIGRhdGEgKGZpbml0ZSBvdXRjb21lcykgYW5kIGNvbnRpbnVvdXMgZGlzdHJpYnV0aW9ucyBmb3IgY29udGludW91cyBkYXRhIChpbmZpbml0ZSBvdXRjb21lcykuCgojIyBXaGF0IGlzIGEgcHJvYmFiaWxpdHkgZGlzdHJpYnV0aW9uPwoKSW4gcHJvYmFiaWxpdHkgdGhlb3J5IGFuZCBzdGF0aXN0aWNzLCBhIHByb2JhYmlsaXR5IGRpc3RyaWJ1dGlvbiBpcyB0aGUgbWF0aGVtYXRpY2FsIGZ1bmN0aW9uIHRoYXQgZ2l2ZXMgdGhlIHByb2JhYmlsaXRpZXMgb2Ygb2NjdXJyZW5jZSBvZiBkaWZmZXJlbnQgcG9zc2libGUgb3V0Y29tZXMgZm9yIGFuIGV4cGVyaW1lbnQuIEl0IGlzIGEgbWF0aGVtYXRpY2FsIGRlc2NyaXB0aW9uIG9mIGEgcmFuZG9tIHBoZW5vbWVub24gaW4gdGVybXMgb2YgaXRzIHNhbXBsZSBzcGFjZSBhbmQgdGhlIHByb2JhYmlsaXRpZXMgb2YgZXZlbnRzIChzdWJzZXRzIG9mIHRoZSBzYW1wbGUgc3BhY2UpLgoKQSAqKnByb2JhYmlsaXR5IGRlbnNpdHkgZnVuY3Rpb24qKiBpcyBhIG1hdGhlbWF0aWNhbCBmdW5jdGlvbiB0aGF0IGRlc2NyaWJlcyBhIGNvbnRpbnVvdXMgcHJvYmFiaWxpdHkgZGlzdHJpYnV0aW9uLiBJdCBwcm92aWRlcyB0aGUgcHJvYmFiaWxpdHkgZGVuc2l0eSBvZiBlYWNoIHZhbHVlIG9mIGEgdmFyaWFibGUsIHdoaWNoIGNhbiBiZSBncmVhdGVyIHRoYW4gb25lLgoKQSBwcm9iYWJpbGl0eSBkZW5zaXR5IGZ1bmN0aW9uIGNhbiBiZSByZXByZXNlbnRlZCBhcyBhbiBlcXVhdGlvbiBvciBhcyBhIGdyYXBoLgoKSW4gZ3JhcGggZm9ybSwgYSBwcm9iYWJpbGl0eSBkZW5zaXR5IGZ1bmN0aW9uIGlzIGEgY3VydmUuIFlvdSBjYW4gZGV0ZXJtaW5lIHRoZSBwcm9iYWJpbGl0eSB0aGF0IGEgdmFsdWUgd2lsbCBmYWxsIHdpdGhpbiBhIGNlcnRhaW4gaW50ZXJ2YWwgYnkgY2FsY3VsYXRpbmcgdGhlIGFyZWEgdW5kZXIgdGhlIGN1cnZlIHdpdGhpbiB0aGF0IGludGVydmFsLiBZb3UgY2FuIHVzZSByZWZlcmVuY2UgdGFibGVzIG9yIHNvZnR3YXJlIHRvIGNhbGN1bGF0ZSB0aGUgYXJlYS4KClRoZSBhcmVhIHVuZGVyIHRoZSB3aG9sZSBjdXJ2ZSBpcyBhbHdheXMgZXhhY3RseSBvbmUgYmVjYXVzZSBpdOKAmXMgY2VydGFpbiAoaS5lLiwgYSBwcm9iYWJpbGl0eSBvZiBvbmUpIHRoYXQgYW4gb2JzZXJ2YXRpb24gd2lsbCBmYWxsIHNvbWV3aGVyZSBpbiB0aGUgdmFyaWFibGXigJlzIHJhbmdlLgoKQSBjdW11bGF0aXZlIGRpc3RyaWJ1dGlvbiBmdW5jdGlvbiBpcyBhbm90aGVyIHR5cGUgb2YgZnVuY3Rpb24gdGhhdCBkZXNjcmliZXMgYSBjb250aW51b3VzIHByb2JhYmlsaXR5IGRpc3RyaWJ1dGlvbi4KCiMjIFR5cGVzIG9mIHByb2JhYmlsaXR5IGRpc3RyaWJ1dGlvbnMKClRoZXJlIGFyZSBtYW55IHR5cGVzIG9mIHByb2JhYmlsaXR5IGRpc3RyaWJ1dGlvbnMgZGVwZW5kaW5nIG9uIHRoZSB0eXBlIG9mIGRhdGEgdXNlZC4gQSBmZXcgb2YgdGhlIGNvbW1vbiBvbmVzIGFyZSBzaG93biBpbiBGaWcuIDIgYmVsb3cuIEZvciBhIG1vcmUgY29tcHJlaGVuc2l2ZSBsaXN0LCB5b3UgY2FuIHNlZSBbaGVyZV0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvTGlzdF9vZl9wcm9iYWJpbGl0eV9kaXN0cmlidXRpb25zKS4gKk5vdGUgdGhhdCB5b3UgZG9uJ3QgbmVlZCB0byBtZW1vcml6ZSBhbGwgdGhlc2UqCgohW0ZpZy4gMjogQ29tbW9uIHR5cGVzIG9mIHByb2JhYmlsaXR5IGRpc3RyaWJ1dGlvbnMuIEltYWdlIHNvdXJjZTogZGF0YXNjaWVuY2Vkb2pvXShodHRwczovL2RhdGFzY2llbmNlZG9qby5jb20vd3AtY29udGVudC91cGxvYWRzL3Byb2JhYmlpdHktZGlzdHJpYnV0aW9ucy0xMDMweDEwMzAucG5nKQoKIyMgRGlzY3JldGUgZGlzdHJpYnV0aW9ucwoKIyMjIERpc2NyZXRlIHVuaWZvcm0gZGlzdHJpYnV0aW9uOiAKIyMjIyBBbGwgb3V0Y29tZXMgYXJlIGVxdWFsbHkgbGlrZWx5CgpJbiBzdGF0aXN0aWNzLCB1bmlmb3JtIGRpc3RyaWJ1dGlvbiByZWZlcnMgdG8gYSBzdGF0aXN0aWNhbCBkaXN0cmlidXRpb24gaW4gd2hpY2ggYWxsIG91dGNvbWVzIGFyZSBlcXVhbGx5IGxpa2VseS4gQ29uc2lkZXIgcm9sbGluZyBhIHNpeC1zaWRlZCBkaWUuIFlvdSBoYXZlIGFuIGVxdWFsIHByb2JhYmlsaXR5IG9mIG9idGFpbmluZyBhbGwgc2l4IG51bWJlcnMgb24geW91ciBuZXh0IHJvbGwsIGkuZS4sIG9idGFpbmluZyBwcmVjaXNlbHkgb25lIG9mIDEsIDIsIDMsIDQsIDUsIG9yIDYsIGVxdWFsaW5nIGEgcHJvYmFiaWxpdHkgb2YgMS82LCBoZW5jZSBhbiBleGFtcGxlIG9mIGEgZGlzY3JldGUgdW5pZm9ybSBkaXN0cmlidXRpb24uCgpBcyBhIHJlc3VsdCwgdGhlIHVuaWZvcm0gZGlzdHJpYnV0aW9uIGdyYXBoIGNvbnRhaW5zIGJhcnMgb2YgZXF1YWwgaGVpZ2h0IHJlcHJlc2VudGluZyBlYWNoIG91dGNvbWUuIEluIG91ciBleGFtcGxlLCB0aGUgaGVpZ2h0IGlzIGEgcHJvYmFiaWxpdHkgb2YgMS82ICgwLjE2NjY2NykuCgohW0ZpZy4gMzogVW5pZm9ybSBkaXN0cmlidXRpb24gb2YgdGhlIG91dGNvbWVzIG9mIHRocm93aW5nIGEgZGljZSBldmVudC4gSW1hZ2Ugc291cmNlOiBkYXRhc2NpZW5jZWRvam9dIChodHRwczovL2RhdGFzY2llbmNlZG9qby5jb20vd3AtY29udGVudC91cGxvYWRzL2ZhaXItZGljZS11bmlmb3JtLWRpc3RyaWJ1dGlvbi53ZWJwKQoKVG8gcmVjcmVhdGUgdGhpcyBpbiBSLCB3ZSBjYW4gdXNlIHRoZSAqc2FtcGxlKiBjb21tYW5kOgpgYGB7cn0Kc2FtcGxlKDE6NiwgMSkKYGBgCgoxOjYgaW5kaWNhdGUgdGhlIHBvc3NpYmxlIG91dGNvbWVzIGFyZSAqMSwyLDMsNCw1LDYqIChmb3IgdGhlIG51bWJlcnMgb24gdGhlIGRpY2UpIGFuZCAxIGFmdGVyIHRoZSBjb21tYSBpbmRpY2F0ZXMgaG93IG1hbnkgdGltZXMgd2UgdGhyZXcgdGhlIGRpY2UuIElmIHlvdSBydW4gdGhlIGFib3ZlIGNodW5rIGFnYWluLCB0aGVyZSdzIGEgZ29vZCBjaGFuY2UgeW91IHdpbGwgZ2V0IGEgZGlmZmVyZW50IG91dGNvbWUuIEhvd2V2ZXIsIGFsbCBvdXRjb21lcyBoYXZlIGVxdWFsIHByb2JhYmlsaXR5IG9mIHNob3dpbmcgdXAsIGp1c3QgbGlrZSB3aGVuIHlvdSB0aHJvdyBhIGRpY2UuCgpUbyB0cnkgbXVsdGlwbGUgZGljZSB0aHJvd3M6CmBgYHtyfQpzYW1wbGUoMTo2LCAzLCByZXBsYWNlID0gVCkKYGBgCgpJbiB0aGUgYWJvdmUgZXhhbXBsZSwgd2UgdGhyZXcgdGhlIGRpY2UgdGhyZWUgdGltZXMuIFdlIHVzZWQgdGhlICpyZXBsYWNlKiBjb21tYW5kIHNvIHRoYXQgdGhlIG51bWJlciB0aGF0IGNvbWVzIHVwIGNhbiByZWFwcGVhciBhZ2FpbiwgdGhlcmVieSBrZWVwaW5nIGVxdWFsIHByb2JhYmlsaXR5IGZvciBhbGwgb3V0Y29tZXMuIFRoaXMgaXMgY2FsbGVkIGFuICoqaW5kZXBlbmRlbnQgZXZlbnQqKiBpZiBvbmUgZXhwZXJpbWVudOKAmXMgb3V0Y29tZSBkb2VzIG5vdCBhZmZlY3QgdGhlIG90aGVyIGV2ZW504oCZcyBwcm9iYWJpbGl0aWVzLgoKQSBjb250cmFzdGluZyBleGFtcGxlIHRvIHRoaXMgd291bGQgYmUgaWYgeW91IGFyZSBzZWxlY3Rpbmcgb3V0IGNhbmRpZGF0ZXMuICplLmcuKiBnaXZpbmcgYXdheSBnaWZ0cyBhbmQgeW91IGRvbid0IHdhbnQgdGhlIHNhbWUgcGVyc29uIHRvIHJlY2VpdmUgMiBvciBtb3JlIGdpZnRzLiBTbyBvbmNlIHRoZWlyIG5hbWUgY29tZXMgb3V0LCB0aGV5IGFyZSB0YWtlbiBvdXQgb2YgdGhlIGxvdHRlcnkgcG9vbC4gSW4gdGhhdCBjYXNlLCB5b3UgY2FuIHNlbGVjdCAqcmVwbGFjZSA9IEYqLiAKCkZvciBleGFtcGxlOiAKYGBge3J9CnNhbXBsZSgxOjYsIDUsIHJlcGxhY2UgPSBGKQpgYGAKTm9uZSBvZiB0aGUgbnVtYmVycyBzaG93IHVwIGFnYWluIGFmdGVyIHRocm93aW5nIHRoZSBkaWNlIDUgdGltZXMuCgpOb3cgbGV0J3Mgcm9sbCBhIHRob3VzYW5kIHRpbWVzIGFuZCBzYXZlIHRoZSBvdXRwdXQgdmVjdG9yIHRvIGFuIG9iamVjdCB0aGF0IHdlIGNhbiBkbyBzb21ldGhpbmcgd2l0aDoKYGBge3J9CnJvbGxzID0gc2FtcGxlKDE6NiwgMTAwMCwgcmVwbGFjZSA9IFRSVUUpCnRhYmxlKHJvbGxzKQoKZGljZV9kYXRhID0gZGF0YS5mcmFtZShvdXRjb21lPXJvbGxzKQpkaWNlX2RhdGEKYGBgCgpUaGUgdGFibGUgb3V0cHV0IGFib3ZlIHNob3dzIGhvdyBtYW55IHRpbWVzIGVhY2ggbnVtYmVyIGNhbWUgdXAgYWZ0ZXIgcm9sbGluZyB0aGUgZGljZSAxMDAwIHRpbWVzLiBMZXQncyBjcmVhdGUgYSBoaXN0b2dyYW0gb2YgdGhlIGFib3ZlIHRvIHZpc3VhbGl6ZSBpdC4KCmBgYHtyfQpsaWJyYXJ5KGdncGxvdDIpCmdncGxvdChkaWNlX2RhdGEsIGFlcyh4ID0gb3V0Y29tZSkpICsKICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDEsIGZpbGwgPSAiZ3JleSIsIGNvbG9yID0gImJsYWNrIikgKwogIGxhYnModGl0bGUgPSAiSGlzdG9ncmFtIG9mIERpY2UgUm9sbCBPdXRjb21lcyIsCiAgICAgICB4ID0gIkRpY2UgUm9sbCBPdXRjb21lIiwKICAgICAgIHkgPSAiRnJlcXVlbmN5IikrCiAgdGhlbWVfYncoKQpgYGAKU28gYWx0aG91Z2ggZWFjaCBudW1iZXIgaGFkIHRoZSBzYW1lIGV4YWN0IHByb2JhYmlsaXR5IHRvIHNob3cgdXAgKDEvNiA9ICAwLjE2NjY2NjcpLCB0aGUgcmVzdWx0cyBzdGlsbCBzaG93IGEgc2xpZ2h0IHZhcmlhYmlsaXR5IGluIHRoZSBmaW5hbCBvdXRjb21lcy4gCgpUbyBkZW1vbnN0cmF0ZSB0aGlzIGluIGEgY2xlYXJlciB3YXk6CgpgYGB7cn0KdGFibGUocm9sbHMpIC8gMTAwMApgYGAKCk5vdGU6IHRoZSBoaWdoZXIgdGhlIHNhbXBsZSBzaXplIChuKSwgdGhlIGNsb3NlciB0aGVzZSBudW1iZXJzIHdpbGwgZ2V0IHRvIGFjaGlldmluZyAxLzYgcHJvYmFiaWxpdHkuCgoqTGV0J3MgZG8gYSBmZXcgZXhlcmNpc2VzKjoKCjxzcGFuIHN0eWxlPSJjb2xvcjpyZWQiPiAqKldoYXQgaXMgdGhlIHByb2JhYmlsaXR5IG9mIHRocm93aW5nIGEgZGljZSBvbmNlIGFuZCBnZXR0aW5nIGEgNCBvciBoaWdoZXI/KiogPC9zcGFuPgoKYGBge3J9CigxLzYpKygxLzYpKygxLzYpCmBgYApVbmRlciBhIHVuaWZvcm0gZGlzdHJpYnV0aW9uLCB0aGUgcHJvYmFiaWxpdHkgb2YgZWFjaCBvdXRjb21lIGlzIDEvNiA9IDAuMTY2NjY2Nywgc28gdG8gZ2V0IDQsIDUsIG9yIDYsIHdlIGhhdmUgMy82ID0gNTAlCgo8c3BhbiBzdHlsZT0iY29sb3I6cmVkIj4gKipXaGF0IGlzIHRoZSBwcm9iYWJpbGl0eSBvZiBnZXR0aW5nIDEgb3IgNSB3aGVuIGEgZmFpciBzaXgtc2lkZWQgZGllIGlzIHJvbGxlZD8qKiA8L3NwYW4+CmBgYHtyfQooMi82KQpgYGAKCgo8c3BhbiBzdHlsZT0iY29sb3I6cmVkIj4gKipXaGF0IGlzIHRoZSBwcm9iYWJpbGl0eSBvZiB0aHJvd2luZyBhIGRpY2UgdHdpY2UgYW5kIGdldHRpbmcgYXQgbGVhc3Qgb25lIDY/KiogPC9zcGFuPgoKYGBge3J9CigxLzYpKygxLzYpCmBgYAoKPHNwYW4gc3R5bGU9ImNvbG9yOnJlZCI+ICoqV2hhdCBpcyB0aGUgcHJvYmFiaWxpdHkgb2YgdGhyb3dpbmcgYSBkaWNlIHR3aWNlIGFuZCBnZXR0aW5nIHR3byA2PyoqIDwvc3Bhbj4KCmBgYHtyfQooMS82KSooMS82KQpgYGAKQXMgaW4gdGhlIGxhdHRlciBjYXNlIGl0IGlzIGEgbXVzdCB0byBnZXQgYSAiNiIgYm90aCB0aW1lcywgd2UgbXVsdGlwbHkgdGhlIHByb2JhYmlsaXR5IG9mIGVhY2ggdGhyb3cgaW5zdGVhZCBvZiBhZGRpbmcuIFRoZSByZXN1bHQgdGhlbiBpcyBvbmx5IDIuOCUgY2hhbmNlLgoKV2hlbiB0d28gZGljZSBhcmUgdGhyb3duIHNpbXVsdGFuZW91c2x5LCB0aGUgbnVtYmVyIG9mIGV2ZW50cyBpcyAkNl4yID0gMzYkIGJlY2F1c2UgZWFjaCBkaWUgaGFzIDEgdG8gNiBudW1iZXIgb24gaXRzIGZhY2VzLiBUaGUgcG9zc2libGUgb3V0Y29tZXMgYXJlIHNob3duIGluIHRoZSBiZWxvdyB0YWJsZS4gCgohW0ZpZy4gMzogT3V0Y29tZXMgZm9yIHRocm93aW5nIGEgZGljZSB0d2ljZS5dKGh0dHBzOi8vd3d3Lm1hdGgtb25seS1tYXRoLmNvbS9pbWFnZXMveHByb2JhYmlsaXR5LWZvci1yb2xsaW5nLXR3by1kaWNlLmpwZy5wYWdlc3BlZWQuaWMuYzJ5cTYxNC1LVC53ZWJwKQoKQXMgeW91IGNhbiBzZWUsIG91ciBvdXRjb21lIGlzIG9ubHkgMS8zNiBwb3NzaWJsZSBvdXRjb21lcywgaGVuY2UgPSAyLjglLgoKPHNwYW4gc3R5bGU9ImNvbG9yOnJlZCI+ICoqV2hhdCBpcyB0aGUgcHJvYmFiaWxpdHkgb2YgdGhyb3dpbmcgYSBkaWNlIHR3aWNlIGFuZCBnZXR0aW5nIHN1bSDiiaQgNC4qKiA8L3NwYW4+CgpMb29raW5nIGF0IHRoZSB0YWJsZSwgd2UgY2FuIHNlZSB0aGVyZSBhcmUgNi8zNiBwb3NzaWJsZSBvdXRjb21lcyB0aGF0IHJlc3VsdCBpbiBhIHN1bSA0IG9yIGxvd2VyLiBUaGVyZWZvcmU6CmBgYHtyfQooNi8zNikKYGBgCgpJZiB3ZSB3YW50IHRvIHdyaXRlIHRoZSBhYm92ZSBhcyBhIGZvcm11bGE6CmBgYHtyfQooKDEvNikqKDMvNikrKDEvNikqKDIvNikrKDEvNikqKDEvNikpCmBgYAoKPHNwYW4gc3R5bGU9ImNvbG9yOnJlZCI+ICAqKldoYXQgaXMgdGhlIHByb2JhYmlsaXR5IG9mIHRocm93aW5nIGEgZGljZSB0d2ljZSBhbmQgZ2V0dGluZyAyIGV2ZW4gbnVtYmVycz8qKiA8L3NwYW4+CgpgYGB7cn0KKDMvNikqKDMvNikKYGBgCgoqKkltcG9ydGFudCB0byByZW1lbWJlcjogV2hlbiB5b3UgcmVhZCAqb3IqIHlvdSB1c2UgYWRkaXRpb24gKCspLCB3aGVuIHlvdSByZWFkICphbmQqLCB5b3UgdXNlIG11bHRpcGxpY2F0aW9uICgqKS4qKgoKIyMjIEJlcm5vdWxsaSBEaXN0cmlidXRpb246CiMjIyMgU2luZ2xlLXRyaWFsIHdpdGggdHdvIHBvc3NpYmxlIG91dGNvbWVzCgpUaGUgQmVybm91bGxpIGRpc3RyaWJ1dGlvbiBpcyBvbmUgb2YgdGhlIGVhc2llc3QgZGlzdHJpYnV0aW9ucyB0byB1bmRlcnN0YW5kLiBJdCBjYW4gYmUgdXNlZCBhcyBhIHN0YXJ0aW5nIHBvaW50IHRvIGRlcml2ZSBtb3JlIGNvbXBsZXggZGlzdHJpYnV0aW9ucy4gQW55IGV2ZW50IHdpdGggYSBzaW5nbGUgdHJpYWwgYW5kIG9ubHkgdHdvIG91dGNvbWVzIGZvbGxvd3MgYSBCZXJub3VsbGkgZGlzdHJpYnV0aW9uLiBGbGlwcGluZyBhIGNvaW4gb3IgY2hvb3NpbmcgYmV0d2VlbiBUcnVlIGFuZCBGYWxzZSBpbiBhIHF1aXogYXJlIGV4YW1wbGVzIG9mIGEgQmVybm91bGxpIGRpc3RyaWJ1dGlvbi4KClRoZXkgaGF2ZSBhIHNpbmdsZSB0cmlhbCBhbmQgb25seSB0d28gb3V0Y29tZXMuIExldOKAmXMgYXNzdW1lIHlvdSBmbGlwIGEgY29pbiBvbmNlOyB0aGlzIGlzIGEgc2luZ2xlIHRyYWlsLiBUaGUgb25seSB0d28gb3V0Y29tZXMgYXJlIGVpdGhlciBoZWFkcyBvciB0YWlscy4gVGhpcyBpcyBhbiBleGFtcGxlIG9mIGEgQmVybm91bGxpIGRpc3RyaWJ1dGlvbi4KClVzdWFsbHksIHdoZW4gZm9sbG93aW5nIGEgQmVybm91bGxpIGRpc3RyaWJ1dGlvbiwgd2UgaGF2ZSB0aGUgcHJvYmFiaWxpdHkgb2Ygb25lIG9mIHRoZSBvdXRjb21lcyAocCkuIEZyb20gKHApLCB3ZSBjYW4gZGVkdWNlIHRoZSBwcm9iYWJpbGl0eSBvZiB0aGUgb3RoZXIgb3V0Y29tZSBieSBzdWJ0cmFjdGluZyBpdCBmcm9tIHRoZSB0b3RhbCBwcm9iYWJpbGl0eSAoMSksIHJlcHJlc2VudGVkIGFzICgxLXApLgoKCiMjIyBCaW5vbWlhbCBEaXN0cmlidXRpb246IAojIyMjIEEgc2VxdWVuY2Ugb2YgQmVybm91bGxpIGV2ZW50cwoKVGhlIEJpbm9taWFsIERpc3RyaWJ1dGlvbiBjYW4gYmUgdGhvdWdodCBvZiBhcyB0aGUgc3VtIG9mIG91dGNvbWVzIG9mIGFuIGV2ZW50IGZvbGxvd2luZyBhIEJlcm5vdWxsaSBkaXN0cmlidXRpb24uIFRoZXJlZm9yZSwgQmlub21pYWwgRGlzdHJpYnV0aW9uIGlzIHVzZWQgaW4gYmluYXJ5IG91dGNvbWUgZXZlbnRzLCBhbmQgdGhlIHByb2JhYmlsaXR5IG9mIHN1Y2Nlc3MgYW5kIGZhaWx1cmUgaXMgdGhlIHNhbWUgaW4gYWxsIHN1Y2Nlc3NpdmUgdHJpYWxzLiBBbiBleGFtcGxlIG9mIGEgYmlub21pYWwgZXZlbnQgd291bGQgYmUgZmxpcHBpbmcgYSBjb2luIG11bHRpcGxlIHRpbWVzIHRvIGNvdW50IHRoZSBudW1iZXIgb2YgaGVhZHMgYW5kIHRhaWxzLgoKKkJpbm9taWFsIHZzIEJlcm5vdWxsaSBkaXN0cmlidXRpb24qOgoKVGhlIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGVzZSBkaXN0cmlidXRpb25zIGNhbiBiZSBleHBsYWluZWQgdGhyb3VnaCBhbiBleGFtcGxlLiBDb25zaWRlciB5b3XigJlyZSBhdHRlbXB0aW5nIGEgcXVpeiB0aGF0IGNvbnRhaW5zIDEwIFRydWUvRmFsc2UgcXVlc3Rpb25zLiBUcnlpbmcgYSBzaW5nbGUgVC9GIHF1ZXN0aW9uIHdvdWxkIGJlIGNvbnNpZGVyZWQgYSBCZXJub3VsbGkgdHJpYWwsIHdoZXJlYXMgYXR0ZW1wdGluZyB0aGUgZW50aXJlIHF1aXogb2YgMTAgVC9GIHF1ZXN0aW9ucyB3b3VsZCBiZSBjYXRlZ29yaXplZCBhcyBhIEJpbm9taWFsIHRyaWFsLiAKClRoZSBtYWluIGNoYXJhY3RlcmlzdGljcyBvZiBCaW5vbWlhbCBEaXN0cmlidXRpb24gYXJlOgoKLSBJbiBtdWx0aXBsZSB0cmlhbHMsIGVhY2ggdHJpYWwgaXMgaW5kZXBlbmRlbnQgb2YgdGhlIG90aGVyLiBUaGF0IGlzLCB0aGUgb3V0Y29tZSBvZiBvbmUgdHJpYWwgZG9lc27igJl0IGFmZmVjdCBhbm90aGVyIG9uZS4gRWFjaCB0cmlhbCBjYW4gbGVhZCB0byBqdXN0IHR3byBwb3NzaWJsZSByZXN1bHRzIChlLmcuLCB3aW5uaW5nIG9yIGxvc2luZyksIHdpdGggcHJvYmFiaWxpdGllcyBwIGFuZCAoMSDigJMgcCkuCgotIEEgYmlub21pYWwgZGlzdHJpYnV0aW9uIGlzIHJlcHJlc2VudGVkIGJ5IEIgKG4sIHApLCB3aGVyZSBuIGlzIHRoZSBudW1iZXIgb2YgdHJpYWxzIGFuZCBwIGlzIHRoZSBwcm9iYWJpbGl0eSBvZiBzdWNjZXNzIGluIGEgc2luZ2xlIHRyaWFsLiBBIEJlcm5vdWxsaSBkaXN0cmlidXRpb24gY2FuIGJlIHNoYXBlZCBhcyBhIGJpbm9taWFsIHRyaWFsIGFzIEIgKDEsIHApIHNpbmNlIGl0IGhhcyBvbmx5IG9uZSB0cmlhbC4KCkluIFIsIHRoZXJlIGFyZSBhIG51bWJlciBvZiBjb21tYW5kcyB5b3UgY2FuIHVzZSBmb3IgYmlub21pYWwgZGlzdHJpYnV0aW9ucy4gVGhlIDMgbW9zdCBjb21tb25seSB1c2VkIG9uZXMgYXJlICoqZGJpbm9tKiosICoqcGJpbm9tKiosICoqcmJpbm9tKiouCgoxLiAqKmRiaW5vbSoqIGZ1bmN0aW9uIGZpbmRzIHRoZSBwcm9iYWJpbGl0eSBvZiBnZXR0aW5nIGEgY2VydGFpbiBudW1iZXIgb2Ygc3VjY2Vzc2VzICh4KSBmcm9tIGEgY2VydGFpbiBudW1iZXIgb2YgdHJpYWxzIChzaXplKSB3aGVyZSB0aGUgcHJvYmFiaWxpdHkgb2Ygc3VjY2VzcyBvbiBlYWNoIHRyaWFsIGlzIGZpeGVkIChwcm9iKS4gWW91IGNhbiB3cml0ZSBpdCBhcyBmb2xsb3dzOgoKPiBkYmlub20gKHgsIHNpemUsIHByb2IpIAoKMi4gIFRoZSBmdW5jdGlvbiAqKnBiaW5vbSoqIHJldHVybnMgdGhlIHZhbHVlIG9mIHRoZSBjdW11bGF0aXZlIGRlbnNpdHkgZnVuY3Rpb24gb2YgdGhlIGJpbm9taWFsIGRpc3RyaWJ1dGlvbiBnaXZlbiBhIGNlcnRhaW4gcmFuZG9tIHZhcmlhYmxlIHEsIG51bWJlciBvZiB0cmlhbHMgKHNpemUpIGFuZCBwcm9iYWJpbGl0eSBvZiBzdWNjZXNzIG9uIGVhY2ggdHJpYWwgKHByb2IpLgoKVGhlIHN5bnRheCBmb3IgdXNpbmcgcGJpbm9tIGlzIGFzIGZvbGxvd3M6Cgo+IHBiaW5vbShxLCBzaXplLCBwcm9iKSAKClB1dCBzaW1wbHksIHBiaW5vbSByZXR1cm5zIHRoZSBhcmVhIHRvIHRoZSBsZWZ0IG9mIGEgZ2l2ZW4gdmFsdWUgcSBpbiB0aGUgYmlub21pYWwgZGlzdHJpYnV0aW9uLiBJZiB5b3XigJlyZSBpbnRlcmVzdGVkIGluIHRoZSBhcmVhIHRvIHRoZSByaWdodCBvZiBhIGdpdmVuIHZhbHVlIHEsIHlvdSBjYW4gc2ltcGx5IGFkZCB0aGUgYXJndW1lbnQgbG93ZXIudGFpbCA9IEZBTFNFLiBIZXJlJ3MgYW4gZXhhbXBsZToKCj4gcGJpbm9tKHEsIHNpemUsIHByb2IsIGxvd2VyLnRhaWwgPSBGQUxTRSkgCgozLiBUaGUgZnVuY3Rpb24gKipyYmlub20qKiBnZW5lcmF0ZXMgYSB2ZWN0b3Igb2YgYmlub21pYWwgZGlzdHJpYnV0ZWQgcmFuZG9tIHZhcmlhYmxlcyBnaXZlbiBhIHZlY3RvciBsZW5ndGggbiwgbnVtYmVyIG9mIHRyaWFscyAoc2l6ZSkgYW5kIHByb2JhYmlsaXR5IG9mIHN1Y2Nlc3Mgb24gZWFjaCB0cmlhbCAocHJvYikuClRoZSBzeW50YXggZm9yIHVzaW5nIHJiaW5vbSBpcyBhcyBmb2xsb3dzOgoKPnJiaW5vbShuLCBzaXplLCBwcm9iKSAKCipMZXQncyB0ZXN0IHRoZXNlIHdpdGggYSBmZXcgZXhlcmNpc2VzKjoKCjxzcGFuIHN0eWxlPSJjb2xvcjpyZWQiPiAgKipBY2NvcmRpbmcgdG8gW0VTUE5dKGh0dHBzOi8vd3d3LmVzcG4uY29tL25iYS9wbGF5ZXIvc3RhdHMvXy9pZC8xOTY2L2xlYnJvbi1qYW1lcyksIExlYnJvbiBKYW1lcyBpcyBhIGNhcmVlciA3My41JSBGcmVlIFRocm93IHNob290ZXIuIEluIGhpcyBsYXN0IGdhbWUsIEphbWVzIGF0dGVtcHRlZCA4IEZUcy4gV2hhdCBpcyB0aGUgcHJvYmFiaWxpdHkgdGhhdCBoZSBzY29yZWQgZXhhY3RseSA2IG9mIHRoZW0/KiogPC9zcGFuPgoKYGBge3J9CmRiaW5vbSg2LDgsIDAuNzM1KQpgYGAKCjxzcGFuIHN0eWxlPSJjb2xvcjpyZWQiPiAgKipBY2NvcmRpbmcgdG8gdGhlIHNhbWUgc291cmNlLCBKYW1lcyBpcyBjdXJyZW50bHkgaGF2aW5nIGhpcyBzZWNvbmQtYmVzdCB5ZWFyIGluIDMtcHQlIG9mIGhpcyBjYXJlZXIsIHNjb3JpbmcgNDAuMSUgb2YgYWxsIGF0dGVtcHRzIGZyb20gYmV5b25kIHRoZSBhcmMuIElmIGhlIGF0dGVtcHRzIDcgc3VjaCBzaG90cyBpbiB0aGUgbmV4dCBnYW1lLCB3aGF0J3MgdGhlIHByb2JhYmlsaXR5IHRoYXQgaGUgd2lsbCBzY29yZSA0IHRpbWVzIG9yIGxlc3M/KiogPC9zcGFuPgoKU2luY2UgdGhpcyBpcyBhIGN1bXVsYXRpdmUgcHJvYmFiaWxpdHkgKGluZGljYXRpbmcgaGUgd2lsbCBzY29yZSAwLCAxLCAyLCAzLCBvciA0IGF0dGVtcHRzIG91dCBvZiA3KSwgd2UgdXNlIHRoZSAqcGJpbm9tKiBjb21tYW5kOgpgYGB7cn0KcGJpbm9tKDQsNywgMC40MDEpCmBgYAoKPHNwYW4gc3R5bGU9ImNvbG9yOnJlZCI+ICAqKlNhbWUgYXMgdGhlIHByZXZpb3VzIHF1ZXN0aW9uLCB3aGF0J3MgdGhlIHByb2JhYmlsaXR5IHRoYXQgaGUgd2lsbCBtaXNzIGF0IGxlYXN0IDMgdGltZXM/KiogPC9zcGFuPgoKPiBUcmljayBxdWVzdGlvbjogZXhhY3RseSB0aGUgc2FtZSBhcyB0aGUgb25lIGJlZm9yZSBpdC4KCjxzcGFuIHN0eWxlPSJjb2xvcjpyZWQiPiAgKipTYW1lIGFzIHRoZSBsYXN0IDIgcXVlc3Rpb25zLCB3aGF0J3MgdGhlIHByb2JhYmlsaXR5IHRoYXQgaGUgd2lsbCBzY29yZSAzIHRpbWVzIG9yIG1vcmU/KiogPC9zcGFuPgoKYGBge3J9CnBiaW5vbSgzLDcsIDAuNDAxLCBsb3dlci50YWlsID0gRkFMU0UpCmBgYAoKIyMjIFBvaXNzb24gRGlzdHJpYnV0aW9uOiAKIyMjIyBUaGUgcHJvYmFiaWxpdHkgdGhhdCBhbiBldmVudCBtYXkgb3IgbWF5IG5vdCBvY2N1cgoKKipUaGUgUG9pc3NvbiBkaXN0cmlidXRpb24qKiBkZWFscyB3aXRoIHRoZSBmcmVxdWVuY3kgd2l0aCB3aGljaCBhbiBldmVudCBvY2N1cnMgd2l0aGluIGEgc3BlY2lmaWMgaW50ZXJ2YWwuIEluc3RlYWQgb2YgdGhlIHByb2JhYmlsaXR5IG9mIGFuIGV2ZW50LCBQb2lzc29uIGRpc3RyaWJ1dGlvbiByZXF1aXJlcyBrbm93aW5nIGhvdyBvZnRlbiBpdCBoYXBwZW5zIGluIGEgcGFydGljdWxhciBwZXJpb2Qgb3IgZGlzdGFuY2UuIEZvciBleGFtcGxlLCBhIGNyaWNrZXQgY2hpcnBzIHR3byB0aW1lcyBpbiA3IHNlY29uZHMgb24gYXZlcmFnZS4gV2UgY2FuIHVzZSB0aGUgUG9pc3NvbiBkaXN0cmlidXRpb24gdG8gZGV0ZXJtaW5lIHRoZSBsaWtlbGlob29kIG9mIGl0IGNoaXJwaW5nIGZpdmUgdGltZXMgaW4gMTUgc2Vjb25kcy4KCkEgUG9pc3NvbiBwcm9jZXNzIGlzIHJlcHJlc2VudGVkIHdpdGggdGhlIG5vdGF0aW9uIFBvKM67KSwgd2hlcmUgzrsgcmVwcmVzZW50cyB0aGUgZXhwZWN0ZWQgbnVtYmVyIG9mIGV2ZW50cyB0aGF0IGNhbiB0YWtlIHBsYWNlIGluIGEgcGVyaW9kLiBYIHJlcHJlc2VudHMgdGhlIGRpc2NyZXRlIHJhbmRvbSB2YXJpYWJsZS4gCgpUaGUgbWFpbiBjaGFyYWN0ZXJpc3RpY3Mgd2hpY2ggZGVzY3JpYmUgdGhlIFBvaXNzb24gcHJvY2Vzc2VzIGFyZToKCi0gVGhlIGV2ZW50cyBhcmUgaW5kZXBlbmRlbnQgb2YgZWFjaCBvdGhlci4KLSBBbiBldmVudCBjYW4gb2NjdXIgYW55IG51bWJlciBvZiB0aW1lcyAod2l0aGluIHRoZSBkZWZpbmVkIHBlcmlvZCkuCi0gVHdvIGV2ZW50cyBjYW7igJl0IHRha2UgcGxhY2Ugc2ltdWx0YW5lb3VzbHkuCgohW0ZpZy4gNDogUG9pc3NvbiBkaXN0cmlidXRpb24gcGxvdCBvZiB0aGUgbnVtYmVyIG9mIGluc3RhbmNlcyBhbiBldmVudCBvY2N1cnMgaW4gdGhlIHN0YW5kYXJkIGludGVydmFsIG9mIHRpbWUgYW5kIHRoZSBwcm9iYWJpbGl0eSBvZiBlYWNoIG9uZS4gU291cmNlOiBkYXRhc2NpZW5jZWRvam9dKGh0dHBzOi8vZGF0YXNjaWVuY2Vkb2pvLmNvbS93cC1jb250ZW50L3VwbG9hZHMvcG9pc3Nvbi1kaXN0cmlidXRpb24tZ3JhcGgud2VicCkKSW4gUiwgdGhlIHN5bnRheCB1c2VkIGZvciBhIFBvaXNzb24gZGlzdHJpYnV0aW9uIGlzIHNpbWlsYXIgdG8gdGhhdCBvZiB0aGUgYmlub21pYWwgZGlzdHJpYnV0aW9uIGJ1dCB3aXRoICpwb2lzKiBiZWluZyB1c2VkIGluc3RlYWQgb2YgKmJpbm9tKiAoc2VlIEZpZy4gNSBiZWxvdykuCgohW0ZpZy4gNTogUG9pc3NvbiBkaXN0cmlidXRpb24gc3ludGF4IGluIFJdKGh0dHBzOi8vaS5pbWd1ci5jb20vWFFKRWkyeC5wbmcpCgo8c3BhbiBzdHlsZT0iY29sb3I6cmVkIj4gICoqT24gYXZlcmFnZSwgSSByZWNlaXZlIDM1IGVtYWlscyBwZXIgZGF5LiBXaGF0IGlzIHRoZSBwcm9iYWJpbGl0eSB0aGF0IEkgcmVjZWl2ZSBtb3JlIHRoYW4gbW9yZSB0aGFuIDQwIGVtYWlscyB0b2RheT8qKiA8L3NwYW4+CgpTaW5jZSB3ZSBhcmUgbG9va2luZyBmb3IgYSBjdW11bGF0aXZlIGRpc3RyaWJ1dGlvbiAoPjQxIGVtYWlscyksIHdlJ2xsIHVzZSB0aGUgcHBvaXMgY29tbWFuZC4gTW9yZW92ZXIsIHNpbmNlIHdlIGFyZSBsb29raW5nIGZvciB0aGUgYXJlYSBiZWxvdyB0aGUgcmlnaHQgdGFpbCwgd2UnbGwgYWRkICpsb3dlci50YWlsPUYqIHRvIG91ciBzeW50YXguCmBgYHtyfQpwcG9pcyg0MCwgMzUsIGxvd2VyLnRhaWwgPSBGQUxTRSkKYGBgCgojIyBDb250aW51b3VzIGRpc3RyaWJ1dGlvbnMKIyMjIE5vcm1hbCBEaXN0cmlidXRpb246IAojIyMjIFN5bW1ldHJpYyBkaXN0cmlidXRpb24gb2YgdmFsdWVzIGFyb3VuZCB0aGUgbWVhbgoKTm9ybWFsIGRpc3RyaWJ1dGlvbiBpcyB0aGUgbW9zdCB1c2VkIGRpc3RyaWJ1dGlvbiBpbiBkYXRhIHNjaWVuY2UuIEluIGEgbm9ybWFsIGRpc3RyaWJ1dGlvbiBncmFwaCwgZGF0YSBpcyBzeW1tZXRyaWNhbGx5IGRpc3RyaWJ1dGVkIHdpdGggbm8gc2tldy4gV2hlbiBwbG90dGVkLCB0aGUgZGF0YSBmb2xsb3dzIGEgYmVsbCBzaGFwZSwgd2l0aCBtb3N0IHZhbHVlcyBjbHVzdGVyaW5nIGFyb3VuZCBhIGNlbnRyYWwgcmVnaW9uIGFuZCB0YXBlcmluZyBvZmYgYXMgdGhleSBnbyBmdXJ0aGVyIGF3YXkgZnJvbSB0aGUgY2VudGVyLgoKVGhlIG5vcm1hbCBkaXN0cmlidXRpb24gZnJlcXVlbnRseSBhcHBlYXJzIGluIG5hdHVyZSBhbmQgbGlmZSBpbiB2YXJpb3VzIGZvcm1zLiBGb3IgZXhhbXBsZSwgdGhlIHNjb3JlcyBvZiBhIHF1aXogZm9sbG93IGEgbm9ybWFsIGRpc3RyaWJ1dGlvbi4gTWFueSBvZiB0aGUgc3R1ZGVudHMgc2NvcmVkIGJldHdlZW4gNjAgYW5kIDgwIGFzIGlsbHVzdHJhdGVkIGluIHRoZSBncmFwaCBiZWxvdy4gT2YgY291cnNlLCBzdHVkZW50cyB3aXRoIHNjb3JlcyB0aGF0IGZhbGwgb3V0c2lkZSB0aGlzIHJhbmdlIGFyZSBkZXZpYXRpbmcgZnJvbSB0aGUgY2VudGVyLgoKIVtGaWcuIDY6IE5vcm1hbCBkaXN0cmlidXRpb24gZ3JhcGhdKGh0dHBzOi8vZGF0YXNjaWVuY2Vkb2pvLmNvbS93cC1jb250ZW50L3VwbG9hZHMvNjgtOTUtOTkuNy1SdWxlLndlYnApIAoKSGVyZSwgeW91IGNhbiB3aXRuZXNzIHRoZSDigJxiZWxsLXNoYXBlZOKAnSBjdXJ2ZSBhcm91bmQgdGhlIGNlbnRyYWwgcmVnaW9uLCBpbmRpY2F0aW5nIHRoYXQgbW9zdCBkYXRhIHBvaW50cyBleGlzdCB0aGVyZS4gVGhlIG5vcm1hbCBkaXN0cmlidXRpb24gaXMgcmVwcmVzZW50ZWQgYXMgTijCtSwgz4MyKSBoZXJlLCDCtSByZXByZXNlbnRzIHRoZSBtZWFuLCBhbmQgz4MyIHJlcHJlc2VudHMgdGhlIHZhcmlhbmNlLCBvbmUgb2Ygd2hpY2ggaXMgbW9zdGx5IHByb3ZpZGVkLiBUaGUgZXhwZWN0ZWQgdmFsdWUgb2YgYSBub3JtYWwgZGlzdHJpYnV0aW9uIGlzIGVxdWFsIHRvIGl0cyBtZWFuLiBTb21lIG9mIHRoZSBjaGFyYWN0ZXJpc3RpY3Mgd2hpY2ggY2FuIGhlbHAgdXMgdG8gcmVjb2duaXplIGEgbm9ybWFsIGRpc3RyaWJ1dGlvbiBhcmU6CgotIFRoZSBjdXJ2ZSBpcyBzeW1tZXRyaWMgYXQgdGhlIGNlbnRlci4gVGhlcmVmb3JlIG1lYW4sIG1vZGUsIGFuZCBtZWRpYW4gYXJlIGVxdWFsIHRvIHRoZSBzYW1lIHZhbHVlLCBkaXN0cmlidXRpbmcgYWxsIHRoZSB2YWx1ZXMgc3ltbWV0cmljYWxseSBhcm91bmQgdGhlIG1lYW4uCi0gVGhlIGFyZWEgdW5kZXIgdGhlIGRpc3RyaWJ1dGlvbiBjdXJ2ZSBlcXVhbHMgMSAoYWxsIHRoZSBwcm9iYWJpbGl0aWVzIG11c3Qgc3VtIHVwIHRvIDEpLgoKV2hpbGUgcGxvdHRpbmcgYSBncmFwaCBmb3IgYSBub3JtYWwgZGlzdHJpYnV0aW9uLCA2OCUgb2YgYWxsIHZhbHVlcyBsaWUgd2l0aGluIG9uZSBzdGFuZGFyZCBkZXZpYXRpb24gZnJvbSB0aGUgbWVhbi4gSW4gdGhlIGV4YW1wbGUgYWJvdmUsIGlmIHRoZSBtZWFuIGlzIDcwIGFuZCB0aGUgc3RhbmRhcmQgZGV2aWF0aW9uIGlzIDEwLCA2OCUgb2YgdGhlIHZhbHVlcyB3aWxsIGxpZSBiZXR3ZWVuIDYwIGFuZCA4MC4gU2ltaWxhcmx5LCA5NSUgb2YgdGhlIHZhbHVlcyBsaWUgd2l0aGluIHR3byBzdGFuZGFyZCBkZXZpYXRpb25zIGZyb20gdGhlIG1lYW4sIGFuZCA5OS43JSBsaWUgd2l0aGluIHRocmVlIHN0YW5kYXJkIGRldmlhdGlvbnMgZnJvbSB0aGUgbWVhbi4gVGhpcyBsYXN0IGludGVydmFsIGNhcHR1cmVzIGFsbW9zdCBhbGwgbWF0dGVycy4gSWYgYSBkYXRhIHBvaW50IGlzIG5vdCBpbmNsdWRlZCwgaXQgaXMgbW9zdCBsaWtlbHkgYW4gKm91dGxpZXIqLgoKSW4gUiwgdGhlIHN5bnRheCBmb3Igbm9ybWFsIGRpc3RyaWJ1dGlvbnMgZm9sbG93cyB0aGUgc2FtZSBsb2dpYyBhcyB0aG9zZSBvZiBiaW5vbWlhbCBhbmQgcG9pc3NvbiBkaXN0cmlidXRpb25zLCByZXBsYWNpbmcgKmJpbm9tKiBhbmQgKnBvaXMqLCByZXNwZWN0aXZlbHkgd2l0aCAqbm9ybSouIFRodXMsIHRoZSBmdW5jdGlvbnMgYXJlIGFzIGZvbGxvd3M6CgohW0ZpZy4gNzogTm9ybWFsIGRpc3RyaWJ1dGlvbiBzeW50YXggaW4gUl0oaHR0cHM6Ly9pLmltZ3VyLmNvbS9LTlNKR2JpLnBuZykKCgo8c3BhbiBzdHlsZT0iY29sb3I6cmVkIj4gICoqU3VwcG9zZSB0aGUgc2NvcmVzIG9uIGEgdGVzdCBmb2xsb3cgYSBub3JtYWwgZGlzdHJpYnV0aW9uIHdpdGggYSBtZWFuIG9mIDcwIGFuZCBhIHN0YW5kYXJkIGRldmlhdGlvbiBvZiAxMC4gQ2FsY3VsYXRlIHRoZSBwcm9iYWJpbGl0eSB0aGF0IGEgcmFuZG9tbHkgc2VsZWN0ZWQgc3R1ZGVudCBzY29yZXMgYmV0d2VlbiA2MCBhbmQgODAuKiogPC9zcGFuPgoKYGBge3J9CnIxID0gcG5vcm0oODAsIDcwLCAxMCkgLSBwbm9ybSg2MCwgNzAsIDEwKQpyMQpgYGAKCjxzcGFuIHN0eWxlPSJjb2xvcjpyZWQiPiAgKipTYW1lIHNhbXBsZSBhcyBhYm92ZSwgY2FsY3VsYXRlIHRoZSBzY29yZSBiZWxvdyB3aGljaCA5MCUgb2YgdGhlIHN0dWRlbnRzIGZhbGwuKio8L3NwYW4+CgpgYGB7cn0KcW5vcm0oMC45LCBtZWFuID0gNzAsIHNkID0gMTApCmBgYAoKCiMjIyBTdHVkZW50IHQtVGVzdCBEaXN0cmlidXRpb246CiMjIyMgU21hbGwgc2FtcGxlIHNpemUgYXBwcm94aW1hdGlvbiBvZiBhIG5vcm1hbCBkaXN0cmlidXRpb24KClRoZSBzdHVkZW504oCZcyB0LWRpc3RyaWJ1dGlvbiwgYWxzbyBrbm93biBhcyB0aGUgdCBkaXN0cmlidXRpb24sIGlzIGEgdHlwZSBvZiBzdGF0aXN0aWNhbCBkaXN0cmlidXRpb24gc2ltaWxhciB0byB0aGUgbm9ybWFsIGRpc3RyaWJ1dGlvbiB3aXRoIGl0cyBiZWxsIHNoYXBlIGJ1dCBoYXMgaGVhdmllciB0YWlscy4gVGhlIHQgZGlzdHJpYnV0aW9uIGlzIHVzZWQgaW5zdGVhZCBvZiB0aGUgbm9ybWFsIGRpc3RyaWJ1dGlvbiB3aGVuIHlvdSBoYXZlIHNtYWxsIHNhbXBsZSBzaXplcy4gCgpGb3IgZXhhbXBsZSwgc3VwcG9zZSB3ZSBkZWFsIHdpdGggdGhlIHRvdGFsIGFwcGxlcyBzb2xkIGJ5IGEgc2hvcGtlZXBlciBpbiBhIG1vbnRoLiBJbiB0aGF0IGNhc2UsIHdlIHdpbGwgdXNlIHRoZSBub3JtYWwgZGlzdHJpYnV0aW9uLiBXaGVyZWFzLCBpZiB3ZSBhcmUgZGVhbGluZyB3aXRoIHRoZSB0b3RhbCBhbW91bnQgb2YgYXBwbGVzIHNvbGQgaW4gYSBkYXksIGkuZS4sIGEgc21hbGxlciBzYW1wbGUsIHdlIGNhbiB1c2UgdGhlIHQgZGlzdHJpYnV0aW9uLgoKQW5vdGhlciBjcml0aWNhbCBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIHN0dWRlbnRz4oCZIHQgZGlzdHJpYnV0aW9uIGFuZCB0aGUgTm9ybWFsIG9uZSBpcyB0aGF0IGFwYXJ0IGZyb20gdGhlIG1lYW4gYW5kIHZhcmlhbmNlLCB3ZSBtdXN0IGFsc28gZGVmaW5lIHRoZSBkZWdyZWVzIG9mIGZyZWVkb20gZm9yIHRoZSBkaXN0cmlidXRpb24uIEluIHN0YXRpc3RpY3MsIHRoZSBudW1iZXIgb2YgZGVncmVlcyBvZiBmcmVlZG9tIGlzIHRoZSBudW1iZXIgb2YgdmFsdWVzIGluIHRoZSBmaW5hbCBjYWxjdWxhdGlvbiBvZiBhIHN0YXRpc3RpYyB0aGF0IGFyZSBmcmVlIHRvIHZhcnkuIEEgU3R1ZGVudOKAmXMgdCBkaXN0cmlidXRpb24gaXMgcmVwcmVzZW50ZWQgYXMgdChrKSwgd2hlcmUgayByZXByZXNlbnRzIHRoZSBudW1iZXIgb2YgZGVncmVlcyBvZiBmcmVlZG9tLiBGb3Igaz0yLCBpLmUuLCAyIGRlZ3JlZXMgb2YgZnJlZWRvbSwgdGhlIGV4cGVjdGVkIHZhbHVlIGlzIHRoZSBzYW1lIGFzIHRoZSBtZWFuLgoKIyMjIEV4cG9uZW50aWFsIGRpc3RyaWJ1dGlvbjogCgpFeHBvbmVudGlhbCBkaXN0cmlidXRpb24gaXMgb25lIG9mIHRoZSB3aWRlbHkgdXNlZCBjb250aW51b3VzIGRpc3RyaWJ1dGlvbnMuIEl0IGlzIHVzZWQgdG8gbW9kZWwgdGhlIHRpbWUgdGFrZW4gYmV0d2VlbiBkaWZmZXJlbnQgZXZlbnRzLiBGb3IgZXhhbXBsZSwgaW4gcGh5c2ljcywgaXQgaXMgb2Z0ZW4gdXNlZCB0byBtZWFzdXJlIHJhZGlvYWN0aXZlIGRlY2F5OyBpbiBlbmdpbmVlcmluZywgdG8gbWVhc3VyZSB0aGUgdGltZSBhc3NvY2lhdGVkIHdpdGggcmVjZWl2aW5nIGEgZGVmZWN0aXZlIHBhcnQgb24gYW4gYXNzZW1ibHkgbGluZTsgYW5kIGluIGZpbmFuY2UsIHRvIG1lYXN1cmUgdGhlIGxpa2VsaWhvb2Qgb2YgdGhlIG5leHQgZGVmYXVsdCBmb3IgYSBwb3J0Zm9saW8gb2YgZmluYW5jaWFsIGFzc2V0cy4gQW5vdGhlciBjb21tb24gYXBwbGljYXRpb24gb2YgRXhwb25lbnRpYWwgZGlzdHJpYnV0aW9ucyBpbiBzdXJ2aXZhbCBhbmFseXNpcyAoZS5nLiwgZXhwZWN0ZWQgbGlmZSBvZiBhIGRldmljZS9tYWNoaW5lKS4KClRoZSBleHBvbmVudGlhbCBkaXN0cmlidXRpb24gaXMgY29tbW9ubHkgcmVwcmVzZW50ZWQgYXMgRXhwKM67KSwgd2hlcmUgzrsgaXMgdGhlIGRpc3RyaWJ1dGlvbiBwYXJhbWV0ZXIsIG9mdGVuIGNhbGxlZCB0aGUgcmF0ZSBwYXJhbWV0ZXIuIFdlIGNhbiBmaW5kIHRoZSB2YWx1ZSBvZiDOuyBieSB0aGUgZm9ybXVsYSA9IDEvzrwsIHdoZXJlIM68IGlzIHRoZSBtZWFuLiBIZXJlIHN0YW5kYXJkIGRldmlhdGlvbiBpcyB0aGUgc2FtZSBhcyB0aGUgbWVhbi4gVmFyICh4KSBnaXZlcyB0aGUgdmFyaWFuY2UgPSAxL867MgoKIVtGaWcuIDY6IEV4cG9uZW50aWFsIGRpc3RyaWJ1dGlvbiBjdXJ2ZV0oaHR0cHM6Ly9kYXRhc2NpZW5jZWRvam8uY29tL3dwLWNvbnRlbnQvdXBsb2Fkcy9leHBvbmVudGlhbC1kaXN0cmlidXRpb24tY3VydmUuanBnKQoKQW4gZXhwb25lbnRpYWwgZ3JhcGggaXMgYSBjdXJ2ZWQgbGluZSByZXByZXNlbnRpbmcgaG93IHRoZSBwcm9iYWJpbGl0eSBjaGFuZ2VzIGV4cG9uZW50aWFsbHkuIEV4cG9uZW50aWFsIGRpc3RyaWJ1dGlvbnMgYXJlIGNvbW1vbmx5IHVzZWQgaW4gY2FsY3VsYXRpb25zIG9mIHByb2R1Y3QgcmVsaWFiaWxpdHkgb3IgdGhlIGxlbmd0aCBvZiB0aW1lIGEgcHJvZHVjdCBsYXN0cy4KCgoKCgoKCgoKCgoK