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):
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).
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:
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