Julius Schmid

R contains built-in functions for your favorite math operations and, of course, for statistical distributions.

For example, we can create a scatterplot for the built-in cars data set just by calling plot(cars):

plot(cars)

Since the cars data set has only two variables speed and dist, we do not need to specify which columns we use to create the scatterplot. There is no other possibility to create a scatterplot with the cars data at hand (apart from switching the axes).

Extended Example: Calculating a Probability

As our first example, we’ll work through calculating a probability using the prod() function. Suppose we have n independent events, and the i-th event has the probability p(i) of occurring. What is the probability of exactly one of these events occurring? Suppose first that n = 3 and our events are named A, B, and C. Then we break down the computation as follows:

P(exactly one event occurs) = P(A and not B and not C) + P(not A and B and not C) + P(not A and not B and C)

Here’s code to compute this, with our probabilities p(i) contained in the vector p:

exactlyone <- function(p) {
notp <- 1 - p
tot <- 0.0
for (i in 1:length(p))
tot <- tot + p[i] * prod(notp[-i])
return(tot)
}

How does it work? Well, the assignment notp <- 1 - p creates a vector of all the “not occur” probabilities 1 − p , using recycling. The expression notp[-i] computes the product of all the elements of notp, except the ith—exactly what we need.

Cumulative Sums and Products

As mentioned, the functions cumsum() and cumprod() return cumulative sums and products.

x <- c(2,7,13,4)
cumsum(x)
[1]  2  9 22 26

In x, the sum of the first element is 2, the sum of the first two elements is 9, the sum of the first three elements is 22, and the sum of the first four elements (all elements) is 26.

Now, apply the cumprod() function:

cumprod(x)
[1]   2  14 182 728

The function cumprod() works the same way as cumsum(), but with the product instead of the sum. The output is a four-dimensional vector. The first entry of the output vector is just the first entry of x (which is 2). The product of the first two numbers 14. the product of the first three numbers is 182, and the product of the first four numbers (all numbers) is 728.

Minima and Maxima


There is quite a difference between min() and pmin(). The former simply combines all its arguments into one long vector and returns the minimum value in that vector. In contrast, if pmin() is applied to two or more vectors, it returns a vector of the pair-wise minima, hence the name pmin.

Here’s an example:

z <- matrix(c(3,4,6,7,3,2), nrow = 2)
z
     [,1] [,2] [,3]
[1,]    3    6    3
[2,]    4    7    2

When applying the min() function, we determine the global minimum over all matrix entries:

min(z[,1],z[,2],z[,3])
[1] 2

The minimum value is 2 which belongs to the entry z[3,2].

Now, let us return the pairwise minima for each row which we get by applying the pmin() function:

pmin(z[,1],z[,2],z[,3])
[1] 3 2

The minimum in the first row is 3 (in z[1,1]), and the minimum value in the second row is 2 (belonging to z[3,2]).

In the first case, min() computed the smallest value in (3,4,6,7,3,2). But the call to pmin() computed the smaller of 3, 6, and 3, yielding 3; and then the smaller of 4, 7, and 2, which is 2. Thus, the call returned the vector (3,2).

The max() and pmax() functions act analogously to min() and pmin(). Function minimization/maximization can be done via nlm() and optim(). For example, let’s find the smallest value of f(x) = x^2 − sin(x).

Let us use the nlm() function to solve this where nlm is an abbreviation for nonlinear minimization. nlm() takes the function x^2 - sin(x) as an input together with 8 as a starting parameter for the optimization:

nlm(function(x) return(x^2-sin(x)),8)
$minimum
[1] -0.2324656

$estimate
[1] 0.4501831

$gradient
[1] 4.024558e-09

$code
[1] 1

$iterations
[1] 5

nlm() then returns the outputs minimum (y-value), estimate (argmin, x-value), a gradient (which is 0 for a minimum), a code value and the number of iterations in order to reach the minimum. In this case, it took the algorithm only 5 iteration steps to get to the result.

The minimum value was found to be approximately −0.23, occurring at x = 0.45. A Newton-Raphson method (a technique from numerical analysis for approximating roots) is used, running five iterations in this case. The second argument specifies the initial guess, which we set to be 8. (This second argument was picked pretty arbitrarily here, but in some problems, you may need to experiment to find a value that will lead to convergence.)

Recreate a similar case scenario shown above but this time using the function f(x) = 3x^2 − cos(x)

Again, we use the nlm() function in order to find the minimum. Information about the nlm() function can be found in the comments above. This time, our first input is the function 3x^2 - cos(x), and our second input is the starting value 3.

#Enter Answer Here
nlm(function(x) return(3*x^2-cos(x)),3)
$minimum
[1] -1

$estimate
[1] -5.132311e-07

$gradient
[1] -9.25926e-08

$code
[1] 1

$iterations
[1] 3

The minimum value was found to be − 1, occurring at x = 0. A Newton-Raphson method (a technique from numerical analysis for approximating roots) is used, running three iterations in this case. The gradient is 0 (nlm() returns almost 0 because of floating-point error) which is just what we would expect for an extreme point of a function.

Calculus


R also has some calculus capabilities, including symbolic differentiation and numerical integration, as you can see in the following example.

In order to calculate the first derivative of a function, we apply the D() function in R, where we need to state the function as well as the variable that we want to derive.

D(expression(exp(x^2)),"x") # derivative
exp(x^2) * (2 * x)

We find that the derivative for x of exp(x^2)) is given by exp(x^2) * (2x).

Find the derivative of exp(x^3)+x

We proceed the same way as we did above, applying the D() function, and setting the function and the variable that we want to derive:

#Enter Answer Here
D(expression(exp(x^3) + x),"x")
exp(x^3) * (3 * x^2) + 1

We find that the derivative for x of exp(x^3) + x is given by exp(x^3) * (3x^2) + 1.

We can also integrate functions, calling integrate() in R. Here, we need to sepcify the function, as well as the lower and upper bounds for the integral. For example, if we want to integrate x^2 between 0 and 1, we enter the following code:

integrate(function(x) x^2,0,1)
0.3333333 with absolute error < 3.7e-15

The integral of x^2 within the boundaries 0 and 1 is evaluated to 1/3.

Next, let us integrate 2sin(x) + 3 between 0 and pi, we enter the following code:

#Enter Answer Here
integrate(function(x) 2 * sin(x) + 3 ,0,pi)
13.42478 with absolute error < 1.5e-13

The integral of 2sin(x) + 3 within the boundaries 0 and pi is evaluated to be approx. 13.42.

Set Operations


R includes some handy set operations, including these: • union(x,y): Union of the sets x and y • intersect(x,y): Intersection of the sets x and y • setdiff(x,y): Set difference between x and y, consisting of all elements of x that are not in y • setequal(x,y): Test for equality between x and y • c %in% y: Membership, testing whether c is an element of the set y • choose(n,k): Number of possible subsets of size k chosen from a set of size n

Let us create two variables x and y to which we can apply the set functions. Note that x and y are not interpreted as vectors, but rather as sets when we apply the functions above to them.

x <- c(1,2,5)
y <- c(5,1,8,9)

First, we build the union of the sets x and y.

union(x,y)
[1] 1 2 5 8 9

We get a set that collects all values of both sets x and y, without duplicates.

Next, we want to see if x and y have values in common. Therefore, we use the intersect() function:

intersect(x,y)
[1] 1 5

The numbers 1 and 5 are contained in both sets x and y.

Now we want to evaluate the mathematical expression x/y, returning all values in x that are not contained in y:

setdiff(x,y)
[1] 2

Only the number 2 is part of x and not contained in y.

We do this the other way around, returning all numbers y that are not contained in x: (y/x)

setdiff(y,x)
[1] 8 9

We get two numbers 8 and 9, that are part of the set y and not part of x.

Create two vectors and x1 and y1 and simulate a similar case scenario.

x1 includes every second number up to 12, and y1 includes every third number up to 12.

#Enter Answer Here
x1 <- c(2,4,6,8,10,12)
y1 <- c(3,6,9,12)

First, we build the union of the sets x1 and y1.

union(x1,y1)
[1]  2  4  6  8 10 12  3  9

We get a set that collects all values of both sets x1 and y1, without duplicates. These are all values that are divisible by two or three, up to twelve.

Next, we want to see if x1 and y1 have values in common. Therefore, we use the intersect() function:

intersect(x1,y1)
[1]  6 12

The numbers 6 and 12 are contained in both sets x1 and y1. They are divisible by both 2 and 3.

Now we want to evaluate the mathematical expression x1/y1, returning all values in x1 that are not contained in y1:

setdiff(x1,y1)
[1]  2  4  8 10

The numbers 2, 4, 8, and 10 are divisible by 2, but not by 3.

We do this the other way around, returning all numbers y1 that are not contained in x1: (y1/x1)

setdiff(y1,x1)
[1] 3 9

The numbers 3 and 9 are divisible by 3, but not by 2. We conclude that half of the set y1 is intersected with x1 (6 and 12), the other half is not (3 and 9).

LS0tCnRpdGxlOiAiTUFUSCBBTkQgU0lNVUxBVElPTlMgSU4gUiIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKSnVsaXVzIFNjaG1pZAoKUiBjb250YWlucyBidWlsdC1pbiBmdW5jdGlvbnMgZm9yIHlvdXIgZmF2b3JpdGUgbWF0aCBvcGVyYXRpb25zIGFuZCwgb2YgY291cnNlLCBmb3Igc3RhdGlzdGljYWwgZGlzdHJpYnV0aW9ucy4KCkZvciBleGFtcGxlLCB3ZSBjYW4gY3JlYXRlIGEgc2NhdHRlcnBsb3QgZm9yIHRoZSBidWlsdC1pbiBjYXJzIGRhdGEgc2V0IGp1c3QgYnkgY2FsbGluZyBwbG90KGNhcnMpOgpgYGB7cn0KcGxvdChjYXJzKQpgYGAKU2luY2UgdGhlIGNhcnMgZGF0YSBzZXQgaGFzIG9ubHkgdHdvIHZhcmlhYmxlcyBzcGVlZCBhbmQgZGlzdCwgd2UgZG8gbm90IG5lZWQgdG8gc3BlY2lmeSB3aGljaCBjb2x1bW5zIHdlIHVzZSB0byBjcmVhdGUgdGhlIHNjYXR0ZXJwbG90LiBUaGVyZSBpcyBubyBvdGhlciBwb3NzaWJpbGl0eSB0byBjcmVhdGUgYSBzY2F0dGVycGxvdCB3aXRoIHRoZSBjYXJzIGRhdGEgYXQgaGFuZCAoYXBhcnQgZnJvbSBzd2l0Y2hpbmcgdGhlIGF4ZXMpLgoKCioqRXh0ZW5kZWQgRXhhbXBsZTogQ2FsY3VsYXRpbmcgYSBQcm9iYWJpbGl0eSoqCgpBcyBvdXIgZmlyc3QgZXhhbXBsZSwgd2XigJlsbCB3b3JrIHRocm91Z2ggY2FsY3VsYXRpbmcgYSBwcm9iYWJpbGl0eSB1c2luZyB0aGUgcHJvZCgpIGZ1bmN0aW9uLiBTdXBwb3NlIHdlIGhhdmUgbiBpbmRlcGVuZGVudCBldmVudHMsIGFuZCB0aGUgaS10aCBldmVudCBoYXMgdGhlIHByb2JhYmlsaXR5IHAoaSkgb2Ygb2NjdXJyaW5nLiBXaGF0IGlzIHRoZSBwcm9iYWJpbGl0eSBvZiBleGFjdGx5IG9uZSBvZiB0aGVzZSBldmVudHMgb2NjdXJyaW5nPyBTdXBwb3NlIGZpcnN0IHRoYXQgbiA9IDMgYW5kIG91ciBldmVudHMgYXJlIG5hbWVkIEEsIEIsIGFuZCBDLiBUaGVuIHdlIGJyZWFrIGRvd24gdGhlIGNvbXB1dGF0aW9uIGFzIGZvbGxvd3M6CgpQKGV4YWN0bHkgb25lIGV2ZW50IG9jY3VycykgPSBQKEEgYW5kIG5vdCBCIGFuZCBub3QgQykgKyBQKG5vdCBBIGFuZCBCIGFuZCBub3QgQykgKyBQKG5vdCBBIGFuZCBub3QgQiBhbmQgQykKCkhlcmXigJlzIGNvZGUgdG8gY29tcHV0ZSB0aGlzLCB3aXRoIG91ciBwcm9iYWJpbGl0aWVzIHAoaSkgY29udGFpbmVkIGluIHRoZSB2ZWN0b3IgcDoKCmBgYHtyfQpleGFjdGx5b25lIDwtIGZ1bmN0aW9uKHApIHsKbm90cCA8LSAxIC0gcAp0b3QgPC0gMC4wCmZvciAoaSBpbiAxOmxlbmd0aChwKSkKdG90IDwtIHRvdCArIHBbaV0gKiBwcm9kKG5vdHBbLWldKQpyZXR1cm4odG90KQp9CmBgYApIb3cgZG9lcyBpdCB3b3JrPyBXZWxsLCB0aGUgYXNzaWdubWVudCBub3RwIDwtIDEgLSBwIGNyZWF0ZXMgYSB2ZWN0b3Igb2YgYWxsIHRoZSDigJxub3Qgb2NjdXLigJ0gcHJvYmFiaWxpdGllcyAxIOKIkiBwICwgdXNpbmcgcmVjeWNsaW5nLiBUaGUgZXhwcmVzc2lvbiBub3RwWy1pXSBjb21wdXRlcyB0aGUgcHJvZHVjdCBvZiBhbGwgdGhlIGVsZW1lbnRzIG9mIG5vdHAsIGV4Y2VwdCB0aGUgaXRo4oCUZXhhY3RseSB3aGF0IHdlIG5lZWQuCgoKKipDdW11bGF0aXZlIFN1bXMgYW5kIFByb2R1Y3RzKioKLS0tCkFzIG1lbnRpb25lZCwgdGhlIGZ1bmN0aW9ucyBjdW1zdW0oKSBhbmQgY3VtcHJvZCgpIHJldHVybiBjdW11bGF0aXZlIHN1bXMgYW5kIHByb2R1Y3RzLgpgYGB7cn0KeCA8LSBjKDIsNywxMyw0KQpjdW1zdW0oeCkKYGBgCkluIHgsIHRoZSBzdW0gb2YgdGhlIGZpcnN0IGVsZW1lbnQgaXMgMiwgdGhlIHN1bSBvZiB0aGUgZmlyc3QgdHdvIGVsZW1lbnRzIGlzIDksIHRoZSBzdW0gb2YgdGhlIGZpcnN0IHRocmVlIGVsZW1lbnRzIGlzIDIyLCBhbmQgdGhlIHN1bSBvZiB0aGUgZmlyc3QgZm91ciBlbGVtZW50cyAoYWxsIGVsZW1lbnRzKSBpcyAyNi4gIAoKTm93LCBhcHBseSB0aGUgY3VtcHJvZCgpIGZ1bmN0aW9uOgpgYGB7cn0KY3VtcHJvZCh4KQpgYGAKVGhlIGZ1bmN0aW9uIGN1bXByb2QoKSB3b3JrcyB0aGUgc2FtZSB3YXkgYXMgY3Vtc3VtKCksIGJ1dCB3aXRoIHRoZSBwcm9kdWN0IGluc3RlYWQgb2YgdGhlIHN1bS4gVGhlIG91dHB1dCBpcyBhIGZvdXItZGltZW5zaW9uYWwgdmVjdG9yLiBUaGUgZmlyc3QgZW50cnkgb2YgdGhlIG91dHB1dCB2ZWN0b3IgaXMganVzdCB0aGUgZmlyc3QgZW50cnkgb2YgeCAod2hpY2ggaXMgMikuIFRoZSBwcm9kdWN0IG9mIHRoZSBmaXJzdCB0d28gbnVtYmVycyAxNC4gdGhlIHByb2R1Y3Qgb2YgdGhlIGZpcnN0IHRocmVlIG51bWJlcnMgaXMgMTgyLCBhbmQgdGhlIHByb2R1Y3Qgb2YgdGhlIGZpcnN0IGZvdXIgbnVtYmVycyAoYWxsIG51bWJlcnMpIGlzIDcyOC4KCgoKKipNaW5pbWEgYW5kIE1heGltYSoqCgotLS0KClRoZXJlIGlzIHF1aXRlIGEgZGlmZmVyZW5jZSBiZXR3ZWVuIG1pbigpIGFuZCBwbWluKCkuIFRoZSBmb3JtZXIgc2ltcGx5IGNvbWJpbmVzIGFsbCBpdHMgYXJndW1lbnRzIGludG8gb25lIGxvbmcgdmVjdG9yIGFuZCByZXR1cm5zIHRoZSBtaW5pbXVtIHZhbHVlIGluIHRoYXQgdmVjdG9yLiBJbiBjb250cmFzdCwgaWYgcG1pbigpIGlzIGFwcGxpZWQgdG8gdHdvIG9yIG1vcmUgdmVjdG9ycywgaXQgcmV0dXJucyBhIHZlY3RvciBvZiB0aGUgcGFpci13aXNlIG1pbmltYSwgaGVuY2UgdGhlIG5hbWUgcG1pbi4KCgpIZXJl4oCZcyBhbiBleGFtcGxlOgpgYGB7cn0KeiA8LSBtYXRyaXgoYygzLDQsNiw3LDMsMiksIG5yb3cgPSAyKQp6CmBgYApXaGVuIGFwcGx5aW5nIHRoZSBtaW4oKSBmdW5jdGlvbiwgd2UgZGV0ZXJtaW5lIHRoZSBnbG9iYWwgbWluaW11bSBvdmVyIGFsbCBtYXRyaXggZW50cmllczoKYGBge3J9Cm1pbih6WywxXSx6WywyXSx6WywzXSkKYGBgClRoZSBtaW5pbXVtIHZhbHVlIGlzIDIgd2hpY2ggYmVsb25ncyB0byB0aGUgZW50cnkgelszLDJdLgoKTm93LCBsZXQgdXMgcmV0dXJuIHRoZSBwYWlyd2lzZSBtaW5pbWEgZm9yIGVhY2ggcm93IHdoaWNoIHdlIGdldCBieSBhcHBseWluZyB0aGUgcG1pbigpIGZ1bmN0aW9uOgpgYGB7cn0KcG1pbih6WywxXSx6WywyXSx6WywzXSkKYGBgClRoZSBtaW5pbXVtIGluIHRoZSBmaXJzdCByb3cgaXMgMyAoaW4gelsxLDFdKSwgYW5kIHRoZSBtaW5pbXVtIHZhbHVlIGluIHRoZSBzZWNvbmQgcm93IGlzIDIgKGJlbG9uZ2luZyB0byB6WzMsMl0pLgoKCkluIHRoZSBmaXJzdCBjYXNlLCBtaW4oKSBjb21wdXRlZCB0aGUgc21hbGxlc3QgdmFsdWUgaW4gKDMsNCw2LDcsMywyKS4gQnV0IHRoZSBjYWxsIHRvIHBtaW4oKSBjb21wdXRlZCB0aGUgc21hbGxlciBvZiAzLCA2LCBhbmQgMywgeWllbGRpbmcgMzsgYW5kIHRoZW4gdGhlIHNtYWxsZXIgb2YgNCwgNywgYW5kIDIsIHdoaWNoIGlzIDIuIFRodXMsIHRoZSBjYWxsIHJldHVybmVkIHRoZSB2ZWN0b3IgKDMsMikuCgoKVGhlIG1heCgpIGFuZCBwbWF4KCkgZnVuY3Rpb25zIGFjdCBhbmFsb2dvdXNseSB0byBtaW4oKSBhbmQgcG1pbigpLiBGdW5jdGlvbiBtaW5pbWl6YXRpb24vbWF4aW1pemF0aW9uIGNhbiBiZSBkb25lIHZpYSBubG0oKSBhbmQgb3B0aW0oKS4gRm9yIGV4YW1wbGUsIGxldOKAmXMgZmluZCB0aGUgc21hbGxlc3QgdmFsdWUgb2YgZih4KSA9IHheMiDiiJIgc2luKHgpLgoKTGV0IHVzIHVzZSB0aGUgbmxtKCkgZnVuY3Rpb24gdG8gc29sdmUgdGhpcyB3aGVyZSBubG0gaXMgYW4gYWJicmV2aWF0aW9uIGZvciBub25saW5lYXIgbWluaW1pemF0aW9uLiBubG0oKSB0YWtlcyB0aGUgZnVuY3Rpb24geF4yIC0gc2luKHgpIGFzIGFuIGlucHV0IHRvZ2V0aGVyIHdpdGggOCBhcyBhIHN0YXJ0aW5nIHBhcmFtZXRlciBmb3IgdGhlIG9wdGltaXphdGlvbjoKYGBge3J9Cm5sbShmdW5jdGlvbih4KSByZXR1cm4oeF4yLXNpbih4KSksOCkKYGBgCm5sbSgpIHRoZW4gcmV0dXJucyB0aGUgb3V0cHV0cyBtaW5pbXVtICh5LXZhbHVlKSwgZXN0aW1hdGUgKGFyZ21pbiwgeC12YWx1ZSksIGEgZ3JhZGllbnQgKHdoaWNoIGlzIDAgZm9yIGEgbWluaW11bSksIGEgY29kZSB2YWx1ZSBhbmQgdGhlIG51bWJlciBvZiBpdGVyYXRpb25zIGluIG9yZGVyIHRvIHJlYWNoIHRoZSBtaW5pbXVtLiBJbiB0aGlzIGNhc2UsIGl0IHRvb2sgdGhlIGFsZ29yaXRobSBvbmx5IDUgaXRlcmF0aW9uIHN0ZXBzIHRvIGdldCB0byB0aGUgcmVzdWx0LgoKVGhlIG1pbmltdW0gdmFsdWUgd2FzIGZvdW5kIHRvIGJlIGFwcHJveGltYXRlbHkg4oiSMC4yMywgb2NjdXJyaW5nIGF0IHggPSAwLjQ1LiBBIE5ld3Rvbi1SYXBoc29uIG1ldGhvZCAoYSB0ZWNobmlxdWUgZnJvbSBudW1lcmljYWwgYW5hbHlzaXMgZm9yIGFwcHJveGltYXRpbmcgcm9vdHMpIGlzIHVzZWQsIHJ1bm5pbmcgZml2ZSBpdGVyYXRpb25zIGluIHRoaXMgY2FzZS4gVGhlIHNlY29uZCBhcmd1bWVudCBzcGVjaWZpZXMgdGhlIGluaXRpYWwgZ3Vlc3MsIHdoaWNoIHdlIHNldCB0byBiZSA4LiAoVGhpcyBzZWNvbmQgYXJndW1lbnQgd2FzIHBpY2tlZCBwcmV0dHkgYXJiaXRyYXJpbHkgaGVyZSwgYnV0IGluIHNvbWUgcHJvYmxlbXMsIHlvdSBtYXkgbmVlZCB0byBleHBlcmltZW50IHRvIGZpbmQgYSB2YWx1ZSB0aGF0IHdpbGwgbGVhZCB0byBjb252ZXJnZW5jZS4pCgoKUmVjcmVhdGUgYSBzaW1pbGFyIGNhc2Ugc2NlbmFyaW8gc2hvd24gYWJvdmUgYnV0IHRoaXMgdGltZSB1c2luZyB0aGUgZnVuY3Rpb24gKipmKHgpID0gM3heMiDiiJIgY29zKHgpKioKCkFnYWluLCB3ZSB1c2UgdGhlIG5sbSgpIGZ1bmN0aW9uIGluIG9yZGVyIHRvIGZpbmQgdGhlIG1pbmltdW0uIEluZm9ybWF0aW9uIGFib3V0IHRoZSBubG0oKSBmdW5jdGlvbiBjYW4gYmUgZm91bmQgaW4gdGhlIGNvbW1lbnRzIGFib3ZlLiBUaGlzIHRpbWUsIG91ciBmaXJzdCBpbnB1dCBpcyB0aGUgZnVuY3Rpb24gM3heMiAtIGNvcyh4KSwgYW5kIG91ciBzZWNvbmQgaW5wdXQgaXMgdGhlIHN0YXJ0aW5nIHZhbHVlIDMuCmBgYHtyfQojRW50ZXIgQW5zd2VyIEhlcmUKbmxtKGZ1bmN0aW9uKHgpIHJldHVybigzKnheMi1jb3MoeCkpLDMpCmBgYApUaGUgbWluaW11bSB2YWx1ZSB3YXMgZm91bmQgdG8gYmUg4oiSIDEsIG9jY3VycmluZyBhdCB4ID0gMC4gQSBOZXd0b24tUmFwaHNvbiBtZXRob2QgKGEgdGVjaG5pcXVlIGZyb20gbnVtZXJpY2FsIGFuYWx5c2lzIGZvciBhcHByb3hpbWF0aW5nIHJvb3RzKSBpcyB1c2VkLCBydW5uaW5nIHRocmVlIGl0ZXJhdGlvbnMgaW4gdGhpcyBjYXNlLiBUaGUgZ3JhZGllbnQgaXMgMCAobmxtKCkgcmV0dXJucyBhbG1vc3QgMCBiZWNhdXNlIG9mIGZsb2F0aW5nLXBvaW50IGVycm9yKSB3aGljaCBpcyBqdXN0IHdoYXQgd2Ugd291bGQgZXhwZWN0IGZvciBhbiBleHRyZW1lIHBvaW50IG9mIGEgZnVuY3Rpb24uCgoKCioqQ2FsY3VsdXMqKgoKLS0tCgpSIGFsc28gaGFzIHNvbWUgY2FsY3VsdXMgY2FwYWJpbGl0aWVzLCBpbmNsdWRpbmcgc3ltYm9saWMgZGlmZmVyZW50aWF0aW9uIGFuZCBudW1lcmljYWwgaW50ZWdyYXRpb24sIGFzIHlvdSBjYW4gc2VlIGluIHRoZSBmb2xsb3dpbmcgZXhhbXBsZS4KCkluIG9yZGVyIHRvIGNhbGN1bGF0ZSB0aGUgZmlyc3QgZGVyaXZhdGl2ZSBvZiBhIGZ1bmN0aW9uLCB3ZSBhcHBseSB0aGUgRCgpIGZ1bmN0aW9uIGluIFIsIHdoZXJlIHdlIG5lZWQgdG8gc3RhdGUgdGhlIGZ1bmN0aW9uIGFzIHdlbGwgYXMgdGhlIHZhcmlhYmxlIHRoYXQgd2Ugd2FudCB0byBkZXJpdmUuCmBgYHtyfQpEKGV4cHJlc3Npb24oZXhwKHheMikpLCJ4IikgIyBkZXJpdmF0aXZlCmBgYApXZSBmaW5kIHRoYXQgdGhlIGRlcml2YXRpdmUgZm9yIHggb2YgZXhwKHheMikpIGlzIGdpdmVuIGJ5IGV4cCh4XjIpICogKDJ4KS4gCgoKRmluZCB0aGUgZGVyaXZhdGl2ZSBvZiBleHAoeF4zKSt4CgpXZSBwcm9jZWVkIHRoZSBzYW1lIHdheSBhcyB3ZSBkaWQgYWJvdmUsIGFwcGx5aW5nIHRoZSBEKCkgZnVuY3Rpb24sIGFuZCBzZXR0aW5nIHRoZSBmdW5jdGlvbiBhbmQgdGhlIHZhcmlhYmxlIHRoYXQgd2Ugd2FudCB0byBkZXJpdmU6CmBgYHtyfQojRW50ZXIgQW5zd2VyIEhlcmUKRChleHByZXNzaW9uKGV4cCh4XjMpICsgeCksIngiKQpgYGAKV2UgZmluZCB0aGF0IHRoZSBkZXJpdmF0aXZlIGZvciB4IG9mIGV4cCh4XjMpICsgeCBpcyBnaXZlbiBieSBleHAoeF4zKSAqICgzeF4yKSArIDEuCgpXZSBjYW4gYWxzbyBpbnRlZ3JhdGUgZnVuY3Rpb25zLCBjYWxsaW5nIGludGVncmF0ZSgpIGluIFIuIEhlcmUsIHdlIG5lZWQgdG8gc2VwY2lmeSB0aGUgZnVuY3Rpb24sIGFzIHdlbGwgYXMgdGhlIGxvd2VyIGFuZCB1cHBlciBib3VuZHMgZm9yIHRoZSBpbnRlZ3JhbC4gRm9yIGV4YW1wbGUsIGlmIHdlIHdhbnQgdG8gaW50ZWdyYXRlIHheMiBiZXR3ZWVuIDAgYW5kIDEsIHdlIGVudGVyIHRoZSBmb2xsb3dpbmcgY29kZToKYGBge3J9CmludGVncmF0ZShmdW5jdGlvbih4KSB4XjIsMCwxKQpgYGAKVGhlIGludGVncmFsIG9mIHheMiB3aXRoaW4gdGhlIGJvdW5kYXJpZXMgMCBhbmQgMSBpcyBldmFsdWF0ZWQgdG8gMS8zLgoKTmV4dCwgbGV0IHVzIGludGVncmF0ZSAyc2luKHgpICsgMyBiZXR3ZWVuIDAgYW5kIHBpLCB3ZSBlbnRlciB0aGUgZm9sbG93aW5nIGNvZGU6CmBgYHtyfQojRW50ZXIgQW5zd2VyIEhlcmUKaW50ZWdyYXRlKGZ1bmN0aW9uKHgpIDIgKiBzaW4oeCkgKyAzICwwLHBpKQpgYGAKVGhlIGludGVncmFsIG9mIDJzaW4oeCkgKyAzIHdpdGhpbiB0aGUgYm91bmRhcmllcyAwIGFuZCBwaSBpcyBldmFsdWF0ZWQgdG8gYmUgYXBwcm94LiAxMy40Mi4KCioqU2V0IE9wZXJhdGlvbnMqKgoKLS0tCgpSIGluY2x1ZGVzIHNvbWUgaGFuZHkgc2V0IG9wZXJhdGlvbnMsIGluY2x1ZGluZyB0aGVzZToK4oCiIHVuaW9uKHgseSk6IFVuaW9uIG9mIHRoZSBzZXRzIHggYW5kIHkK4oCiIGludGVyc2VjdCh4LHkpOiBJbnRlcnNlY3Rpb24gb2YgdGhlIHNldHMgeCBhbmQgeQrigKIgc2V0ZGlmZih4LHkpOiBTZXQgZGlmZmVyZW5jZSBiZXR3ZWVuIHggYW5kIHksIGNvbnNpc3Rpbmcgb2YgYWxsIGVsZW1lbnRzIG9mIHggdGhhdCBhcmUgbm90IGluIHkK4oCiIHNldGVxdWFsKHgseSk6IFRlc3QgZm9yIGVxdWFsaXR5IGJldHdlZW4geCBhbmQgeQrigKIgYyAlaW4lIHk6IE1lbWJlcnNoaXAsIHRlc3Rpbmcgd2hldGhlciBjIGlzIGFuIGVsZW1lbnQgb2YgdGhlIHNldCB5CuKAoiBjaG9vc2UobixrKTogTnVtYmVyIG9mIHBvc3NpYmxlIHN1YnNldHMgb2Ygc2l6ZSBrIGNob3NlbiBmcm9tIGEgc2V0IG9mIHNpemUgbgoKTGV0IHVzIGNyZWF0ZSB0d28gdmFyaWFibGVzIHggYW5kIHkgdG8gd2hpY2ggd2UgY2FuIGFwcGx5IHRoZSBzZXQgZnVuY3Rpb25zLiBOb3RlIHRoYXQgeCBhbmQgeSBhcmUgbm90IGludGVycHJldGVkIGFzIHZlY3RvcnMsIGJ1dCByYXRoZXIgYXMgc2V0cyB3aGVuIHdlIGFwcGx5IHRoZSBmdW5jdGlvbnMgYWJvdmUgdG8gdGhlbS4KYGBge3J9CnggPC0gYygxLDIsNSkKeSA8LSBjKDUsMSw4LDkpCmBgYAoKRmlyc3QsIHdlIGJ1aWxkIHRoZSB1bmlvbiBvZiB0aGUgc2V0cyB4IGFuZCB5LgpgYGB7cn0KdW5pb24oeCx5KQpgYGAKV2UgZ2V0IGEgc2V0IHRoYXQgY29sbGVjdHMgYWxsIHZhbHVlcyBvZiBib3RoIHNldHMgeCBhbmQgeSwgd2l0aG91dCBkdXBsaWNhdGVzLgoKTmV4dCwgd2Ugd2FudCB0byBzZWUgaWYgeCBhbmQgeSBoYXZlIHZhbHVlcyBpbiBjb21tb24uIFRoZXJlZm9yZSwgd2UgdXNlIHRoZSBpbnRlcnNlY3QoKSBmdW5jdGlvbjoKYGBge3J9CmludGVyc2VjdCh4LHkpCmBgYApUaGUgbnVtYmVycyAxIGFuZCA1IGFyZSBjb250YWluZWQgaW4gYm90aCBzZXRzIHggYW5kIHkuCgpOb3cgd2Ugd2FudCB0byBldmFsdWF0ZSB0aGUgbWF0aGVtYXRpY2FsIGV4cHJlc3Npb24geC95LCByZXR1cm5pbmcgYWxsIHZhbHVlcyBpbiB4IHRoYXQgYXJlIG5vdCBjb250YWluZWQgaW4geToKYGBge3J9CnNldGRpZmYoeCx5KQpgYGAKT25seSB0aGUgbnVtYmVyIDIgaXMgcGFydCBvZiB4IGFuZCBub3QgY29udGFpbmVkIGluIHkuCgpXZSBkbyB0aGlzIHRoZSBvdGhlciB3YXkgYXJvdW5kLCByZXR1cm5pbmcgYWxsIG51bWJlcnMgeSB0aGF0IGFyZSBub3QgY29udGFpbmVkIGluIHg6ICh5L3gpCmBgYHtyfQpzZXRkaWZmKHkseCkKYGBgCldlIGdldCB0d28gbnVtYmVycyA4IGFuZCA5LCB0aGF0IGFyZSBwYXJ0IG9mIHRoZSBzZXQgeSBhbmQgbm90IHBhcnQgb2YgeC4KCkNyZWF0ZSB0d28gdmVjdG9ycyBhbmQgeDEgYW5kIHkxIGFuZCBzaW11bGF0ZSBhIHNpbWlsYXIgY2FzZSBzY2VuYXJpby4gCgp4MSBpbmNsdWRlcyBldmVyeSBzZWNvbmQgbnVtYmVyIHVwIHRvIDEyLCBhbmQgeTEgaW5jbHVkZXMgZXZlcnkgdGhpcmQgbnVtYmVyIHVwIHRvIDEyLgpgYGB7cn0KI0VudGVyIEFuc3dlciBIZXJlCngxIDwtIGMoMiw0LDYsOCwxMCwxMikKeTEgPC0gYygzLDYsOSwxMikKYGBgCgpGaXJzdCwgd2UgYnVpbGQgdGhlIHVuaW9uIG9mIHRoZSBzZXRzIHgxIGFuZCB5MS4KYGBge3J9CnVuaW9uKHgxLHkxKQpgYGAKV2UgZ2V0IGEgc2V0IHRoYXQgY29sbGVjdHMgYWxsIHZhbHVlcyBvZiBib3RoIHNldHMgeDEgYW5kIHkxLCB3aXRob3V0IGR1cGxpY2F0ZXMuIFRoZXNlIGFyZSBhbGwgdmFsdWVzIHRoYXQgYXJlIGRpdmlzaWJsZSBieSB0d28gb3IgdGhyZWUsIHVwIHRvIHR3ZWx2ZS4KCk5leHQsIHdlIHdhbnQgdG8gc2VlIGlmIHgxIGFuZCB5MSBoYXZlIHZhbHVlcyBpbiBjb21tb24uIFRoZXJlZm9yZSwgd2UgdXNlIHRoZSBpbnRlcnNlY3QoKSBmdW5jdGlvbjoKYGBge3J9CmludGVyc2VjdCh4MSx5MSkKYGBgClRoZSBudW1iZXJzIDYgYW5kIDEyIGFyZSBjb250YWluZWQgaW4gYm90aCBzZXRzIHgxIGFuZCB5MS4gVGhleSBhcmUgZGl2aXNpYmxlIGJ5IGJvdGggMiBhbmQgMy4gCgpOb3cgd2Ugd2FudCB0byBldmFsdWF0ZSB0aGUgbWF0aGVtYXRpY2FsIGV4cHJlc3Npb24geDEveTEsIHJldHVybmluZyBhbGwgdmFsdWVzIGluIHgxIHRoYXQgYXJlIG5vdCBjb250YWluZWQgaW4geTE6CmBgYHtyfQpzZXRkaWZmKHgxLHkxKQpgYGAKVGhlIG51bWJlcnMgMiwgNCwgOCwgYW5kIDEwIGFyZSBkaXZpc2libGUgYnkgMiwgYnV0IG5vdCBieSAzLgoKV2UgZG8gdGhpcyB0aGUgb3RoZXIgd2F5IGFyb3VuZCwgcmV0dXJuaW5nIGFsbCBudW1iZXJzIHkxIHRoYXQgYXJlIG5vdCBjb250YWluZWQgaW4geDE6ICh5MS94MSkKYGBge3J9CnNldGRpZmYoeTEseDEpCmBgYApUaGUgbnVtYmVycyAzIGFuZCA5IGFyZSBkaXZpc2libGUgYnkgMywgYnV0IG5vdCBieSAyLiBXZSBjb25jbHVkZSB0aGF0IGhhbGYgb2YgdGhlIHNldCB5MSBpcyBpbnRlcnNlY3RlZCB3aXRoIHgxICg2IGFuZCAxMiksIHRoZSBvdGhlciBoYWxmIGlzIG5vdCAoMyBhbmQgOSkuIAoK