suppressPackageStartupMessages(library("tidyverse"))
package 㤼㸱tidyverse㤼㸲 was built under R version 3.6.3
1. Describe the difference between is.finite(x)
and !is.infinite(x)
.
To find out, try the functions on a numeric vector that includes at least one number and the four special values (NA
, NaN
, Inf
, -Inf
).
x <- c(0, NA, NaN, Inf, -Inf)
is.finite(x)
[1] TRUE FALSE FALSE FALSE FALSE
!is.infinite(x)
[1] TRUE TRUE TRUE FALSE FALSE
The is.finite()
function considers non-missing numeric values to be finite, and missing (NA
), not a number (NaN
), and positive (Inf
) and negative infinity (-Inf
) to not be finite. The is.infinite()
behaves slightly differently. It considers Inf
and -Inf
to be infinite, and everything else, including non-missing numbers, NA
, and NaN
to not be infinite.
Results of is.finite()
and is.infinite()
for numeric and special values.
1 |
TRUE |
FALSE |
NA |
FALSE |
FALSE |
NaN |
FALSE |
FALSE |
Inf |
FALSE |
TRUE |
2. Read the source code for dplyr::near()
(Hint: to see the source code, drop the ()). How does it work?
The source for dplyr::near
is:
dplyr::near
function (x, y, tol = .Machine$double.eps^0.5)
{
abs(x - y) < tol
}
<bytecode: 0x000001ef57999068>
<environment: namespace:dplyr>
Instead of checking for exact equality, it checks that two numbers are within a certain tolerance, tol
. By default the tolerance is set to the square root of .Machine$double.eps
, which is the smallest floating point number that the computer can represent.
3. A logical vector can take 3 possible values. How many possible values can an integer vector take? How many possible values can a double take? Use Google to do some research.
For integers vectors, R uses a 32-bit representation. This means that it can represent up to
\(2^{32}\) different values with integers. One of these values is set aside for NA_integer_
. From the help for integer.
Note that current implementations of R use 32-bit integers for integer vectors, so the range of representable integers is restricted to about +/-2*10^9: doubles can hold much larger integers exactly.
The range of integers values that R can represent in an integer vector is \(\pm 2^{31}-1\)
.Machine$integer.max
[1] 2147483647
#> [1] 2147483647
The maximum integer is \(2^{31}-1\) rather than \(2^{32}\) because 1 bit is used to represent the sign (\(+\),\(−\)) and one value is used to represent NA_integer_
.
If you try to represent an integer greater than that value, R will return NA
values.
.Machine$integer.max + 1L
NAs produced by integer overflow
[1] NA
However, you can represent that value (exactly) with a numeric vector at the cost of about two times the memory.
as.numeric(.Machine$integer.max) + 1
[1] 2147483648
The same is true for the negative of the integer max.
-.Machine$integer.max - 1L
NAs produced by integer overflow
[1] NA
For double vectors, R uses a 64-bit representation. This means that they can hold up to \(2^{64}\) values exactly. However, some of those values are allocated to special values such as -Inf
, Inf
, NA_real_
, and NaN
. From the help for double:
All R platforms are required to work with values conforming to the IEC 60559 (also known as IEEE 754) standard. This basically works with a precision of 53 bits, and represents to that precision a range of absolute values from about 2e-308 to 2e+308. It also has special values NaN (many of them), plus and minus infinity and plus and minus zero (although R acts as if these are the same). There are also denormal(ized) (or subnormal) numbers with absolute values above or below the range given above but represented to less precision.
The details of floating point representation and arithmetic are complicated, beyond the scope of this question, and better discussed in the references provided below. The double can represent numbers in the range of about \(\pm 2\times10^{308}\) , which is provided in
.Machine$double.xmax
[1] 1.797693e+308
Many other details for the implementation of the double vectors are given in the .Machine
variable (and its documentation). These include the base (radix) of doubles,
.Machine$double.base
[1] 2
the number of bits used for the significand (mantissa),
.Machine$double.digits
[1] 53
the number of bits used in the exponent,
.Machine$double.exponent
[1] 11
and the smallest positive and negative numbers not equal to zero,
.Machine$double.eps
[1] 2.220446e-16
.Machine$double.neg.eps
[1] 1.110223e-16
- Computerphile, “Floating Point Numbers”
- https://en.wikipedia.org/wiki/IEEE_754
- https://en.wikipedia.org/wiki/Double-precision_floating-point_format
- “Floating Point Numbers Why floating point numbers are needed”
- Fabien Sanglard, “Floating Point Numbers: Visually Explained”
- James Howard, “How Many Floating Point Numbers are There?”
- GeeksforGeeks, “Floating Point Representation Basics”
- Chris Hecker, “Lets Go to the (Floating) Point”, Game Developer
- Chua Hock-Chuan, A Tutorial on Data Representation Integers, Floating-point Numbers, and Characters
- John D. Cook, “Anatomy of a floating point number”
- John D. Cook, “Five Tips for Floating Point Programming”
4. Brainstorm at least four functions that allow you to convert a double to an integer. How do they differ? Be precise.
The difference between to convert a double to an integer differ in how they deal with the fractional part of the double. There are are a variety of rules that could be used to do this.
- Round down, towards \(-\infty\). This is also called taking the
floor
of a number. This is the method the floor()
function uses.
- Round up, towards \(+\infty\). This is also called taking the
ceiling
. This is the method the ceiling()
function uses.
- Round towards zero. This is the method that the
trunc()
and as.integer()
functions use.
- Round away from zero.
- Round to the nearest integer. There several different methods for handling ties, which are numbers with a fractional part of 0.5.
- Round half down, towards \(-\infty\).
- Round half up, towards \(+\infty\).
- Round half towards zero
- Round half away from zero
- Round half towards the even integer. This is the method that the
round()
function uses.
- Round half towards the odd integer.
function(x, method) {
if (method == "round down") {
floor(x)
} else if (method == "round up") {
ceiling(x)
} else if (method == "round towards zero") {
trunc(x)
} else if (method == "round away from zero") {
sign(x) * ceiling(abs(x))
} else if (method == "nearest, round half up") {
floor(x + 0.5)
} else if (method == "nearest, round half down") {
ceiling(x - 0.5)
} else if (method == "nearest, round half towards zero") {
sign(x) * ceiling(abs(x) - 0.5)
} else if (method == "nearest, round half away from zero") {
sign(x) * floor(abs(x) + 0.5)
} else if (method == "nearest, round half to even") {
round(x, digits = 0)
} else if (method == "nearest, round half to odd") {
case_when(
# smaller integer is odd - round half down
floor(x) %% 2 ~ ceiling(x - 0.5),
# otherwise, round half up
TRUE ~ floor(x + 0.5)
)
} else if (method == "nearest, round half randomly") {
round_half_up <- sample(c(TRUE, FALSE), length(x), replace = TRUE)
y <- x
y[round_half_up] <- ceiling(x[round_half_up] - 0.5)
y[!round_half_up] <- floor(x[!round_half_up] + 0.5)
y
}
}
function(x, method) {
if (method == "round down") {
floor(x)
} else if (method == "round up") {
ceiling(x)
} else if (method == "round towards zero") {
trunc(x)
} else if (method == "round away from zero") {
sign(x) * ceiling(abs(x))
} else if (method == "nearest, round half up") {
floor(x + 0.5)
} else if (method == "nearest, round half down") {
ceiling(x - 0.5)
} else if (method == "nearest, round half towards zero") {
sign(x) * ceiling(abs(x) - 0.5)
} else if (method == "nearest, round half away from zero") {
sign(x) * floor(abs(x) + 0.5)
} else if (method == "nearest, round half to even") {
round(x, digits = 0)
} else if (method == "nearest, round half to odd") {
case_when(
# smaller integer is odd - round half down
floor(x) %% 2 ~ ceiling(x - 0.5),
# otherwise, round half up
TRUE ~ floor(x + 0.5)
)
} else if (method == "nearest, round half randomly") {
round_half_up <- sample(c(TRUE, FALSE), length(x), replace = TRUE)
y <- x
y[round_half_up] <- ceiling(x[round_half_up] - 0.5)
y[!round_half_up] <- floor(x[!round_half_up] + 0.5)
y
}
}
tibble(
x = c(
1.8, 1.5, 1.2, 0.8, 0.5, 0.2,
-0.2, -0.5, -0.8, -1.2, -1.5, -1.8
),
`Round down` = floor(x),
`Round up` = ceiling(x),
`Round towards zero` = trunc(x),
`Nearest, round half to even` = round(x)
)
See the Wikipedia articles, Rounding and IEEE floating point for more discussion of these rounding rules.
For rounding, R and many programming languages use the IEEE standard. This method is called “round to nearest, ties to even.” (See the documentation for .Machine$double.rounding
) This rule rounds ties, numbers with a remainder of 0.5, to the nearest even number. In this rule, half the ties are rounded up, and half are rounded down. The following function, round2()
, manually implements the “round to nearest, ties to even” method.
x <- seq(-10, 10, by = 0.5)
round2 <- function(x, to_even = TRUE) {
q <- x %/% 1
r <- x %% 1
q + (r >= 0.5)
}
x <- c(-12.5, -11.5, 11.5, 12.5)
round(x)
[1] -12 -12 12 12
round2(x, to_even = FALSE)
[1] -12 -11 12 13
This rounding method may be different than the one you learned in grade school, which is, at least for me, was to always round ties upwards, or, alternatively away from zero. This rule is called the “round half up” rule. The problem with the “round half up” rule is that it is biased upwards for positive numbers. Rounding to nearest with ties towards even is not. Consider this sequence which sums to zero.
x <- seq(-100.5, 100.5, by = 1)
x
[1] -100.5 -99.5 -98.5 -97.5 -96.5 -95.5 -94.5 -93.5 -92.5 -91.5 -90.5 -89.5
[13] -88.5 -87.5 -86.5 -85.5 -84.5 -83.5 -82.5 -81.5 -80.5 -79.5 -78.5 -77.5
[25] -76.5 -75.5 -74.5 -73.5 -72.5 -71.5 -70.5 -69.5 -68.5 -67.5 -66.5 -65.5
[37] -64.5 -63.5 -62.5 -61.5 -60.5 -59.5 -58.5 -57.5 -56.5 -55.5 -54.5 -53.5
[49] -52.5 -51.5 -50.5 -49.5 -48.5 -47.5 -46.5 -45.5 -44.5 -43.5 -42.5 -41.5
[61] -40.5 -39.5 -38.5 -37.5 -36.5 -35.5 -34.5 -33.5 -32.5 -31.5 -30.5 -29.5
[73] -28.5 -27.5 -26.5 -25.5 -24.5 -23.5 -22.5 -21.5 -20.5 -19.5 -18.5 -17.5
[85] -16.5 -15.5 -14.5 -13.5 -12.5 -11.5 -10.5 -9.5 -8.5 -7.5 -6.5 -5.5
[97] -4.5 -3.5 -2.5 -1.5 -0.5 0.5 1.5 2.5 3.5 4.5 5.5 6.5
[109] 7.5 8.5 9.5 10.5 11.5 12.5 13.5 14.5 15.5 16.5 17.5 18.5
[121] 19.5 20.5 21.5 22.5 23.5 24.5 25.5 26.5 27.5 28.5 29.5 30.5
[133] 31.5 32.5 33.5 34.5 35.5 36.5 37.5 38.5 39.5 40.5 41.5 42.5
[145] 43.5 44.5 45.5 46.5 47.5 48.5 49.5 50.5 51.5 52.5 53.5 54.5
[157] 55.5 56.5 57.5 58.5 59.5 60.5 61.5 62.5 63.5 64.5 65.5 66.5
[169] 67.5 68.5 69.5 70.5 71.5 72.5 73.5 74.5 75.5 76.5 77.5 78.5
[181] 79.5 80.5 81.5 82.5 83.5 84.5 85.5 86.5 87.5 88.5 89.5 90.5
[193] 91.5 92.5 93.5 94.5 95.5 96.5 97.5 98.5 99.5 100.5
sum(x)
[1] 0
A nice property of rounding preserved that sum. Using the “ties towards even”, the sum is still zero. However, the “ties towards \(+\infty\)” produces a non-zero number.
sum(x)
[1] 0
sum(round(x))
[1] 0
sum(round2(x))
[1] 101
Rounding rules can have real world impacts. One notable example was that in 1983, the Vancouver stock exchange adjusted its index from 524.811 to 1098.892 to correct for accumulated error due to rounding to three decimal points (see Vancouver Stock Exchange). This site lists several more examples of the dangers of rounding rules.
5. What functions from the readr
package allow you to turn a string into logical, integer, and double vector?
The function parse_logical()
parses logical values, which can appear as variations of TRUE/FALSE or 1/0.
parse_logical(c("TRUE", "FALSE", "1", "0", "true", "t", "NA"))
[1] TRUE FALSE TRUE FALSE TRUE TRUE NA
The function parse_integer()
parses integer values.
parse_integer(c("1235", "0134", "NA"))
[1] 1235 134 NA
However, if there are any non-numeric characters in the string, including currency symbols, commas, and decimals, parse_integer()
will raise an error.
parse_integer(c("1000", "$1,000", "10.00"))
2 parsing failures.
row col expected actual
2 -- an integer $1,000
3 -- no trailing characters .00
[1] 1000 NA NA
attr(,"problems")
The function parse_number()
parses integer values.
parse_number(c("1.0", "3.5", "$1,000.00", "NA"))
[1] 1.0 3.5 1000.0 NA
Unlike parse_integer()
, the function parse_number()
is very forgiving about the format of the numbers. It ignores all non-numeric characters, as with “$1,000.00” in the example. This allows it to easily parse numeric fields that include currency symbols and comma separators in number strings without any intervention by the user.
LS0tDQp0aXRsZTogIkltcG9ydGFudCB0eXBlcyBvZiBhdG9taWMgdmVjdG9yIg0Kb3V0cHV0OiANCiAgaHRtbF9ub3RlYm9vazoNCiAgICB0b2M6IHRydWUNCiAgICB0b2NfZmxvYXQ6IHRydWUNCi0tLQ0KDQpgYGB7cn0NCnN1cHByZXNzUGFja2FnZVN0YXJ0dXBNZXNzYWdlcyhsaWJyYXJ5KCJ0aWR5dmVyc2UiKSkNCmBgYA0KDQojIyMgMS4gRGVzY3JpYmUgdGhlIGRpZmZlcmVuY2UgYmV0d2VlbiBgaXMuZmluaXRlKHgpYCBhbmQgYCFpcy5pbmZpbml0ZSh4KWAuDQoNClRvIGZpbmQgb3V0LCB0cnkgdGhlIGZ1bmN0aW9ucyBvbiBhIG51bWVyaWMgdmVjdG9yIHRoYXQgaW5jbHVkZXMgYXQgbGVhc3Qgb25lIG51bWJlciBhbmQgdGhlIGZvdXIgc3BlY2lhbCB2YWx1ZXMgKGBOQWAsIGBOYU5gLCBgSW5mYCwgYC1JbmZgKS4NCg0KYGBge3J9DQp4IDwtIGMoMCwgTkEsIE5hTiwgSW5mLCAtSW5mKQ0KaXMuZmluaXRlKHgpDQohaXMuaW5maW5pdGUoeCkNCmBgYA0KDQpUaGUgYGlzLmZpbml0ZSgpYCBmdW5jdGlvbiBjb25zaWRlcnMgbm9uLW1pc3NpbmcgbnVtZXJpYyB2YWx1ZXMgdG8gYmUgZmluaXRlLCBhbmQgbWlzc2luZyAoYE5BYCksIG5vdCBhIG51bWJlciAoYE5hTmApLCBhbmQgcG9zaXRpdmUgKGBJbmZgKSBhbmQgbmVnYXRpdmUgaW5maW5pdHkgKGAtSW5mYCkgdG8gbm90IGJlIGZpbml0ZS4gVGhlIGBpcy5pbmZpbml0ZSgpYCBiZWhhdmVzIHNsaWdodGx5IGRpZmZlcmVudGx5LiBJdCBjb25zaWRlcnMgYEluZmAgYW5kIGAtSW5mYCB0byBiZSBpbmZpbml0ZSwgYW5kIGV2ZXJ5dGhpbmcgZWxzZSwgaW5jbHVkaW5nIG5vbi1taXNzaW5nIG51bWJlcnMsIGBOQWAsIGFuZCBgTmFOYCB0byBub3QgYmUgaW5maW5pdGUuIA0KDQoqKlJlc3VsdHMgb2YgYGlzLmZpbml0ZSgpYCBhbmQgYGlzLmluZmluaXRlKClgIGZvciBudW1lcmljIGFuZCBzcGVjaWFsIHZhbHVlcy4qKg0KDQp8ICAgICB8IGBpcy5maW5pdGUoKWAgfCBgaXMuaW5maW5pdGUoKWAgfA0KfC0tLS0tfC0tLS0tLS0tLS0tLS18LS0tLS0tLS0tLS0tLS0tfA0KfCBgMWAgICB8IGBUUlVFYCAgICAgICB8IGBGQUxTRWAgICAgICAgIHwNCnwgYE5BYCB8IGBGQUxTRWAgICAgICAgfCBgRkFMU0VgICAgICAgICB8DQp8IGBOYU5gIHwgYEZBTFNFYCAgICAgICB8IGBGQUxTRWAgICAgICAgICB8DQp8IGBJbmZgIHwgYEZBTFNFYCAgICAgICB8IGBUUlVFYCAgICAgICAgICB8DQoNCiMjIyAyLiBSZWFkIHRoZSBzb3VyY2UgY29kZSBmb3IgYGRwbHlyOjpuZWFyKClgIChIaW50OiB0byBzZWUgdGhlIHNvdXJjZSBjb2RlLCBkcm9wIHRoZSAoKSkuIEhvdyBkb2VzIGl0IHdvcms/DQoNClRoZSBzb3VyY2UgZm9yIGBkcGx5cjo6bmVhcmAgaXM6DQoNCmBgYHtyfQ0KZHBseXI6Om5lYXINCmBgYA0KDQpJbnN0ZWFkIG9mIGNoZWNraW5nIGZvciBleGFjdCBlcXVhbGl0eSwgaXQgY2hlY2tzIHRoYXQgdHdvIG51bWJlcnMgYXJlIHdpdGhpbiBhIGNlcnRhaW4gdG9sZXJhbmNlLCBgdG9sYC4gQnkgZGVmYXVsdCB0aGUgdG9sZXJhbmNlIGlzIHNldCB0byB0aGUgc3F1YXJlIHJvb3Qgb2YgYC5NYWNoaW5lJGRvdWJsZS5lcHNgLCB3aGljaCBpcyB0aGUgc21hbGxlc3QgZmxvYXRpbmcgcG9pbnQgbnVtYmVyIHRoYXQgdGhlIGNvbXB1dGVyIGNhbiByZXByZXNlbnQuDQoNCiMjIyAzLiBBIGxvZ2ljYWwgdmVjdG9yIGNhbiB0YWtlIDMgcG9zc2libGUgdmFsdWVzLiBIb3cgbWFueSBwb3NzaWJsZSB2YWx1ZXMgY2FuIGFuIGludGVnZXIgdmVjdG9yIHRha2U/IEhvdyBtYW55IHBvc3NpYmxlIHZhbHVlcyBjYW4gYSBkb3VibGUgdGFrZT8gVXNlIEdvb2dsZSB0byBkbyBzb21lIHJlc2VhcmNoLg0KDQpGb3IgaW50ZWdlcnMgdmVjdG9ycywgUiB1c2VzIGEgMzItYml0IHJlcHJlc2VudGF0aW9uLiBUaGlzIG1lYW5zIHRoYXQgaXQgY2FuIHJlcHJlc2VudCB1cCB0byAgDQokMl57MzJ9JCAgZGlmZmVyZW50IHZhbHVlcyB3aXRoIGludGVnZXJzLiBPbmUgb2YgdGhlc2UgdmFsdWVzIGlzIHNldCBhc2lkZSBmb3IgYE5BX2ludGVnZXJfYC4gRnJvbSB0aGUgaGVscCBmb3IgaW50ZWdlci4NCg0KPiBOb3RlIHRoYXQgY3VycmVudCBpbXBsZW1lbnRhdGlvbnMgb2YgUiB1c2UgMzItYml0IGludGVnZXJzIGZvciBpbnRlZ2VyIHZlY3RvcnMsIHNvIHRoZSByYW5nZSBvZiByZXByZXNlbnRhYmxlIGludGVnZXJzIGlzIHJlc3RyaWN0ZWQgdG8gYWJvdXQgKy8tMioxMF45OiBkb3VibGVzIGNhbiBob2xkIG11Y2ggbGFyZ2VyIGludGVnZXJzIGV4YWN0bHkuDQoNClRoZSByYW5nZSBvZiBpbnRlZ2VycyB2YWx1ZXMgdGhhdCBSIGNhbiByZXByZXNlbnQgaW4gYW4gaW50ZWdlciB2ZWN0b3IgaXMgJFxwbSAyXnszMX0tMSQgDQoNCmBgYHtyfQ0KLk1hY2hpbmUkaW50ZWdlci5tYXgNCiM+IFsxXSAyMTQ3NDgzNjQ3DQpgYGANCg0KVGhlIG1heGltdW0gaW50ZWdlciBpcyAkMl57MzF9LTEkIHJhdGhlciB0aGFuICQyXnszMn0kICBiZWNhdXNlIDEgYml0IGlzIHVzZWQgdG8gcmVwcmVzZW50IHRoZSBzaWduICgkKyQsJOKIkiQpIGFuZCBvbmUgdmFsdWUgaXMgdXNlZCB0byByZXByZXNlbnQgYE5BX2ludGVnZXJfYC4NCg0KSWYgeW91IHRyeSB0byByZXByZXNlbnQgYW4gaW50ZWdlciBncmVhdGVyIHRoYW4gdGhhdCB2YWx1ZSwgUiB3aWxsIHJldHVybiBgTkFgIHZhbHVlcy4NCg0KYGBge3J9DQouTWFjaGluZSRpbnRlZ2VyLm1heCArIDFMDQpgYGANCg0KSG93ZXZlciwgeW91IGNhbiByZXByZXNlbnQgdGhhdCB2YWx1ZSAoZXhhY3RseSkgd2l0aCBhIG51bWVyaWMgdmVjdG9yIGF0IHRoZSBjb3N0IG9mIGFib3V0IHR3byB0aW1lcyB0aGUgbWVtb3J5Lg0KDQpgYGB7cn0NCmFzLm51bWVyaWMoLk1hY2hpbmUkaW50ZWdlci5tYXgpICsgMQ0KYGBgDQoNClRoZSBzYW1lIGlzIHRydWUgZm9yIHRoZSBuZWdhdGl2ZSBvZiB0aGUgaW50ZWdlciBtYXguDQoNCmBgYHtyfQ0KLS5NYWNoaW5lJGludGVnZXIubWF4IC0gMUwNCmBgYA0KDQpGb3IgZG91YmxlIHZlY3RvcnMsIFIgdXNlcyBhIDY0LWJpdCByZXByZXNlbnRhdGlvbi4gVGhpcyBtZWFucyB0aGF0IHRoZXkgY2FuIGhvbGQgdXAgdG8gJDJeezY0fSQgdmFsdWVzIGV4YWN0bHkuIEhvd2V2ZXIsIHNvbWUgb2YgdGhvc2UgdmFsdWVzIGFyZSBhbGxvY2F0ZWQgdG8gc3BlY2lhbCB2YWx1ZXMgc3VjaCBhcyBgLUluZmAsIGBJbmZgLCBgTkFfcmVhbF9gLCBhbmQgYE5hTmAuIEZyb20gdGhlIGhlbHAgZm9yIGRvdWJsZToNCg0KPiBBbGwgUiBwbGF0Zm9ybXMgYXJlIHJlcXVpcmVkIHRvIHdvcmsgd2l0aCB2YWx1ZXMgY29uZm9ybWluZyB0byB0aGUgSUVDIDYwNTU5IChhbHNvIGtub3duIGFzIElFRUUgNzU0KSBzdGFuZGFyZC4gVGhpcyBiYXNpY2FsbHkgd29ya3Mgd2l0aCBhIHByZWNpc2lvbiBvZiA1MyBiaXRzLCBhbmQgcmVwcmVzZW50cyB0byB0aGF0IHByZWNpc2lvbiBhIHJhbmdlIG9mIGFic29sdXRlIHZhbHVlcyBmcm9tIGFib3V0IDJlLTMwOCB0byAyZSszMDguIEl0IGFsc28gaGFzIHNwZWNpYWwgdmFsdWVzIE5hTiAobWFueSBvZiB0aGVtKSwgcGx1cyBhbmQgbWludXMgaW5maW5pdHkgYW5kIHBsdXMgYW5kIG1pbnVzIHplcm8gKGFsdGhvdWdoIFIgYWN0cyBhcyBpZiB0aGVzZSBhcmUgdGhlIHNhbWUpLiBUaGVyZSBhcmUgYWxzbyBkZW5vcm1hbChpemVkKSAob3Igc3Vibm9ybWFsKSBudW1iZXJzIHdpdGggYWJzb2x1dGUgdmFsdWVzIGFib3ZlIG9yIGJlbG93IHRoZSByYW5nZSBnaXZlbiBhYm92ZSBidXQgcmVwcmVzZW50ZWQgdG8gbGVzcyBwcmVjaXNpb24uDQoNClRoZSBkZXRhaWxzIG9mIGZsb2F0aW5nIHBvaW50IHJlcHJlc2VudGF0aW9uIGFuZCBhcml0aG1ldGljIGFyZSBjb21wbGljYXRlZCwgYmV5b25kIHRoZSBzY29wZSBvZiB0aGlzIHF1ZXN0aW9uLCBhbmQgYmV0dGVyIGRpc2N1c3NlZCBpbiB0aGUgcmVmZXJlbmNlcyBwcm92aWRlZCBiZWxvdy4gVGhlIGRvdWJsZSBjYW4gcmVwcmVzZW50IG51bWJlcnMgaW4gdGhlIHJhbmdlIG9mIGFib3V0ICRccG0gMlx0aW1lczEwXnszMDh9JCAsIHdoaWNoIGlzIHByb3ZpZGVkIGluDQoNCmBgYHtyfQ0KLk1hY2hpbmUkZG91YmxlLnhtYXgNCmBgYA0KDQpNYW55IG90aGVyIGRldGFpbHMgZm9yIHRoZSBpbXBsZW1lbnRhdGlvbiBvZiB0aGUgZG91YmxlIHZlY3RvcnMgYXJlIGdpdmVuIGluIHRoZSBgLk1hY2hpbmVgIHZhcmlhYmxlIChhbmQgaXRzIGRvY3VtZW50YXRpb24pLiBUaGVzZSBpbmNsdWRlIHRoZSBiYXNlIChyYWRpeCkgb2YgZG91YmxlcywNCg0KYGBge3J9DQouTWFjaGluZSRkb3VibGUuYmFzZQ0KYGBgDQoNCnRoZSBudW1iZXIgb2YgYml0cyB1c2VkIGZvciB0aGUgc2lnbmlmaWNhbmQgKG1hbnRpc3NhKSwNCg0KYGBge3J9DQouTWFjaGluZSRkb3VibGUuZGlnaXRzDQpgYGANCg0KdGhlIG51bWJlciBvZiBiaXRzIHVzZWQgaW4gdGhlIGV4cG9uZW50LA0KDQpgYGB7cn0NCi5NYWNoaW5lJGRvdWJsZS5leHBvbmVudA0KYGBgDQoNCmFuZCB0aGUgc21hbGxlc3QgcG9zaXRpdmUgYW5kIG5lZ2F0aXZlIG51bWJlcnMgbm90IGVxdWFsIHRvIHplcm8sDQoNCmBgYHtyfQ0KLk1hY2hpbmUkZG91YmxlLmVwcw0KLk1hY2hpbmUkZG91YmxlLm5lZy5lcHMNCmBgYA0KDQogLSBDb21wdXRlcnBoaWxlLCBb4oCcRmxvYXRpbmcgUG9pbnQgTnVtYmVyc+KAnV0oaHR0cHM6Ly93d3cueW91dHViZS5jb20vd2F0Y2g/dj1QWlJJMUlmU3RZMCkNCiAtIDxodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9JRUVFXzc1ND4NCiAtIDxodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9Eb3VibGUtcHJlY2lzaW9uX2Zsb2F0aW5nLXBvaW50X2Zvcm1hdD4NCiAtIFvigJxGbG9hdGluZyBQb2ludCBOdW1iZXJzIFdoeSBmbG9hdGluZyBwb2ludCBudW1iZXJzIGFyZSBuZWVkZWTigJ1dKGh0dHBzOi8vZmxvYXRpbmctcG9pbnQtZ3VpLmRlL2Zvcm1hdHMvZnAvKQ0KIC0gRmFiaWVuIFNhbmdsYXJkLCBb4oCcRmxvYXRpbmcgUG9pbnQgTnVtYmVyczogVmlzdWFsbHkgRXhwbGFpbmVk4oCdXShodHRwOi8vZmFiaWVuc2FuZ2xhcmQubmV0L2Zsb2F0aW5nX3BvaW50X3Zpc3VhbGx5X2V4cGxhaW5lZC8pDQogLSBKYW1lcyBIb3dhcmQsIFvigJxIb3cgTWFueSBGbG9hdGluZyBQb2ludCBOdW1iZXJzIGFyZSBUaGVyZT/igJ1dKGh0dHBzOi8vamFtZXNob3dhcmQudXMvMjAxNS8wOS8wOS9ob3ctbWFueS1mbG9hdGluZy1wb2ludC1udW1iZXJzLWFyZS10aGVyZS8pDQogLSBHZWVrc2ZvckdlZWtzLCBb4oCcRmxvYXRpbmcgUG9pbnQgUmVwcmVzZW50YXRpb24gQmFzaWNz4oCdXShodHRwczovL3d3dy5nZWVrc2ZvcmdlZWtzLm9yZy9mbG9hdGluZy1wb2ludC1yZXByZXNlbnRhdGlvbi1iYXNpY3MvKQ0KIC0gQ2hyaXMgSGVja2VyLCBb4oCcTGV0cyBHbyB0byB0aGUgKEZsb2F0aW5nKSBQb2ludOKAnV0oaHR0cDovL2NocmlzaGVja2VyLmNvbS9pbWFnZXMvZi9mYi9HZG1mcC5wZGYpLCAqR2FtZSBEZXZlbG9wZXIqDQogLSBDaHVhIEhvY2stQ2h1YW4sIFtBIFR1dG9yaWFsIG9uIERhdGEgUmVwcmVzZW50YXRpb24gSW50ZWdlcnMsIEZsb2F0aW5nLXBvaW50IE51bWJlcnMsIGFuZCBDaGFyYWN0ZXJzXShodHRwOi8vd3d3Lm50dS5lZHUuc2cvaG9tZS9laGNodWEvcHJvZ3JhbW1pbmcvamF2YS9kYXRhcmVwcmVzZW50YXRpb24uaHRtbCkNCiAtIEpvaG4gRC4gQ29vaywgW+KAnEFuYXRvbXkgb2YgYSBmbG9hdGluZyBwb2ludCBudW1iZXLigJ1dKGh0dHBzOi8vd3d3LmpvaG5kY29vay5jb20vYmxvZy8yMDA5LzA0LzA2L2FuYXRvbXktb2YtYS1mbG9hdGluZy1wb2ludC1udW1iZXIvKQ0KIC0gSm9obiBELiBDb29rLCBb4oCcRml2ZSBUaXBzIGZvciBGbG9hdGluZyBQb2ludCBQcm9ncmFtbWluZ+KAnV0oaHR0cHM6Ly93d3cuY29kZXByb2plY3QuY29tL0FydGljbGVzLzI5NjM3L0ZpdmUtVGlwcy1mb3ItRmxvYXRpbmctUG9pbnQtUHJvZ3JhbW1pbmcpDQoNCiMjIyA0LiBCcmFpbnN0b3JtIGF0IGxlYXN0IGZvdXIgZnVuY3Rpb25zIHRoYXQgYWxsb3cgeW91IHRvIGNvbnZlcnQgYSBkb3VibGUgdG8gYW4gaW50ZWdlci4gSG93IGRvIHRoZXkgZGlmZmVyPyBCZSBwcmVjaXNlLg0KDQpUaGUgZGlmZmVyZW5jZSBiZXR3ZWVuIHRvIGNvbnZlcnQgYSBkb3VibGUgdG8gYW4gaW50ZWdlciBkaWZmZXIgaW4gaG93IHRoZXkgZGVhbCB3aXRoIHRoZSBmcmFjdGlvbmFsIHBhcnQgb2YgdGhlIGRvdWJsZS4gVGhlcmUgYXJlIGFyZSBhIHZhcmlldHkgb2YgcnVsZXMgdGhhdCBjb3VsZCBiZSB1c2VkIHRvIGRvIHRoaXMuDQoNCiAtIFJvdW5kIGRvd24sIHRvd2FyZHMgJC1caW5mdHkkLiBUaGlzIGlzIGFsc28gY2FsbGVkIHRha2luZyB0aGUgYGZsb29yYCBvZiBhIG51bWJlci4gVGhpcyBpcyB0aGUgbWV0aG9kIHRoZSBgZmxvb3IoKWAgZnVuY3Rpb24gdXNlcy4NCiAtIFJvdW5kIHVwLCB0b3dhcmRzICQrXGluZnR5JC4gVGhpcyBpcyBhbHNvIGNhbGxlZCB0YWtpbmcgdGhlIGBjZWlsaW5nYC4gVGhpcyBpcyB0aGUgbWV0aG9kIHRoZSBgY2VpbGluZygpYCBmdW5jdGlvbiB1c2VzLg0KIC0gUm91bmQgdG93YXJkcyB6ZXJvLiBUaGlzIGlzIHRoZSBtZXRob2QgdGhhdCB0aGUgYHRydW5jKClgIGFuZCBgYXMuaW50ZWdlcigpYCBmdW5jdGlvbnMgdXNlLg0KIC0gUm91bmQgYXdheSBmcm9tIHplcm8uDQogLSBSb3VuZCB0byB0aGUgbmVhcmVzdCBpbnRlZ2VyLiBUaGVyZSBzZXZlcmFsIGRpZmZlcmVudCBtZXRob2RzIGZvciBoYW5kbGluZyB0aWVzLCB3aGljaCBhcmUgbnVtYmVycyB3aXRoIGEgZnJhY3Rpb25hbCBwYXJ0IG9mIDAuNS4NCiAgIC0gUm91bmQgaGFsZiBkb3duLCB0b3dhcmRzICQtXGluZnR5JC4NCiAgIC0gUm91bmQgaGFsZiB1cCwgdG93YXJkcyAkK1xpbmZ0eSQuDQogICAtIFJvdW5kIGhhbGYgdG93YXJkcyB6ZXJvDQogICAtIFJvdW5kIGhhbGYgYXdheSBmcm9tIHplcm8NCiAgIC0gUm91bmQgaGFsZiB0b3dhcmRzIHRoZSBldmVuIGludGVnZXIuIFRoaXMgaXMgdGhlIG1ldGhvZCB0aGF0IHRoZSBgcm91bmQoKWAgZnVuY3Rpb24gdXNlcy4NCiAgIC0gUm91bmQgaGFsZiB0b3dhcmRzIHRoZSBvZGQgaW50ZWdlci4NCg0KYGBge3J9DQpmdW5jdGlvbih4LCBtZXRob2QpIHsNCiAgaWYgKG1ldGhvZCA9PSAicm91bmQgZG93biIpIHsNCiAgICBmbG9vcih4KQ0KICB9IGVsc2UgaWYgKG1ldGhvZCA9PSAicm91bmQgdXAiKSB7DQogICAgY2VpbGluZyh4KQ0KICB9IGVsc2UgaWYgKG1ldGhvZCA9PSAicm91bmQgdG93YXJkcyB6ZXJvIikgew0KICAgIHRydW5jKHgpDQogIH0gZWxzZSBpZiAobWV0aG9kID09ICJyb3VuZCBhd2F5IGZyb20gemVybyIpIHsNCiAgICBzaWduKHgpICogY2VpbGluZyhhYnMoeCkpDQogIH0gZWxzZSBpZiAobWV0aG9kID09ICJuZWFyZXN0LCByb3VuZCBoYWxmIHVwIikgew0KICAgIGZsb29yKHggKyAwLjUpDQogIH0gZWxzZSBpZiAobWV0aG9kID09ICJuZWFyZXN0LCByb3VuZCBoYWxmIGRvd24iKSB7DQogICAgY2VpbGluZyh4IC0gMC41KQ0KICB9IGVsc2UgaWYgKG1ldGhvZCA9PSAibmVhcmVzdCwgcm91bmQgaGFsZiB0b3dhcmRzIHplcm8iKSB7DQogICAgc2lnbih4KSAqIGNlaWxpbmcoYWJzKHgpIC0gMC41KQ0KICB9IGVsc2UgaWYgKG1ldGhvZCA9PSAibmVhcmVzdCwgcm91bmQgaGFsZiBhd2F5IGZyb20gemVybyIpIHsNCiAgICBzaWduKHgpICogZmxvb3IoYWJzKHgpICsgMC41KQ0KICB9IGVsc2UgaWYgKG1ldGhvZCA9PSAibmVhcmVzdCwgcm91bmQgaGFsZiB0byBldmVuIikgew0KICAgIHJvdW5kKHgsIGRpZ2l0cyA9IDApDQogIH0gZWxzZSBpZiAobWV0aG9kID09ICJuZWFyZXN0LCByb3VuZCBoYWxmIHRvIG9kZCIpIHsNCiAgICBjYXNlX3doZW4oDQogICAgICAjIHNtYWxsZXIgaW50ZWdlciBpcyBvZGQgLSByb3VuZCBoYWxmIGRvd24NCiAgICAgIGZsb29yKHgpICUlIDIgfiBjZWlsaW5nKHggLSAwLjUpLA0KICAgICAgIyBvdGhlcndpc2UsIHJvdW5kIGhhbGYgdXANCiAgICAgIFRSVUUgfiBmbG9vcih4ICsgMC41KQ0KICAgICkNCiAgfSBlbHNlIGlmIChtZXRob2QgPT0gIm5lYXJlc3QsIHJvdW5kIGhhbGYgcmFuZG9tbHkiKSB7DQogICAgcm91bmRfaGFsZl91cCA8LSBzYW1wbGUoYyhUUlVFLCBGQUxTRSksIGxlbmd0aCh4KSwgcmVwbGFjZSA9IFRSVUUpDQogICAgeSA8LSB4DQogICAgeVtyb3VuZF9oYWxmX3VwXSA8LSBjZWlsaW5nKHhbcm91bmRfaGFsZl91cF0gLSAwLjUpDQogICAgeVshcm91bmRfaGFsZl91cF0gPC0gZmxvb3IoeFshcm91bmRfaGFsZl91cF0gKyAwLjUpDQogICAgeQ0KICB9DQp9DQp0aWJibGUoDQogIHggPSBjKA0KICAgIDEuOCwgMS41LCAxLjIsIDAuOCwgMC41LCAwLjIsDQogICAgLTAuMiwgLTAuNSwgLTAuOCwgLTEuMiwgLTEuNSwgLTEuOA0KICApLA0KICBgUm91bmQgZG93bmAgPSBmbG9vcih4KSwNCiAgYFJvdW5kIHVwYCA9IGNlaWxpbmcoeCksDQogIGBSb3VuZCB0b3dhcmRzIHplcm9gID0gdHJ1bmMoeCksDQogIGBOZWFyZXN0LCByb3VuZCBoYWxmIHRvIGV2ZW5gID0gcm91bmQoeCkNCikNCmBgYA0KDQpTZWUgdGhlIFdpa2lwZWRpYSBhcnRpY2xlcywgW1JvdW5kaW5nXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9Sb3VuZGluZykgYW5kIFtJRUVFIGZsb2F0aW5nIHBvaW50XShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9JRUVFX2Zsb2F0aW5nX3BvaW50KSBmb3IgbW9yZSBkaXNjdXNzaW9uIG9mIHRoZXNlIHJvdW5kaW5nIHJ1bGVzLg0KDQpGb3Igcm91bmRpbmcsIFIgYW5kIG1hbnkgcHJvZ3JhbW1pbmcgbGFuZ3VhZ2VzIHVzZSB0aGUgSUVFRSBzdGFuZGFyZC4gVGhpcyBtZXRob2QgaXMgY2FsbGVkIOKAnHJvdW5kIHRvIG5lYXJlc3QsIHRpZXMgdG8gZXZlbi7igJ0gKFNlZSB0aGUgZG9jdW1lbnRhdGlvbiBmb3IgYC5NYWNoaW5lJGRvdWJsZS5yb3VuZGluZ2ApIFRoaXMgcnVsZSByb3VuZHMgdGllcywgbnVtYmVycyB3aXRoIGEgcmVtYWluZGVyIG9mIDAuNSwgdG8gdGhlIG5lYXJlc3QgZXZlbiBudW1iZXIuIEluIHRoaXMgcnVsZSwgaGFsZiB0aGUgdGllcyBhcmUgcm91bmRlZCB1cCwgYW5kIGhhbGYgYXJlIHJvdW5kZWQgZG93bi4gVGhlIGZvbGxvd2luZyBmdW5jdGlvbiwgYHJvdW5kMigpYCwgbWFudWFsbHkgaW1wbGVtZW50cyB0aGUg4oCccm91bmQgdG8gbmVhcmVzdCwgdGllcyB0byBldmVu4oCdIG1ldGhvZC4NCg0KYGBge3J9DQp4IDwtIHNlcSgtMTAsIDEwLCBieSA9IDAuNSkNCg0Kcm91bmQyIDwtIGZ1bmN0aW9uKHgsIHRvX2V2ZW4gPSBUUlVFKSB7DQogIHEgPC0geCAlLyUgMQ0KICByIDwtIHggJSUgMQ0KICBxICsgKHIgPj0gMC41KQ0KfQ0KeCA8LSBjKC0xMi41LCAtMTEuNSwgMTEuNSwgMTIuNSkNCnJvdW5kKHgpDQpyb3VuZDIoeCwgdG9fZXZlbiA9IEZBTFNFKQ0KYGBgDQoNClRoaXMgcm91bmRpbmcgbWV0aG9kIG1heSBiZSBkaWZmZXJlbnQgdGhhbiB0aGUgb25lIHlvdSBsZWFybmVkIGluIGdyYWRlIHNjaG9vbCwgd2hpY2ggaXMsIGF0IGxlYXN0IGZvciBtZSwgd2FzIHRvIGFsd2F5cyByb3VuZCB0aWVzIHVwd2FyZHMsIG9yLCBhbHRlcm5hdGl2ZWx5IGF3YXkgZnJvbSB6ZXJvLiBUaGlzIHJ1bGUgaXMgY2FsbGVkIHRoZSDigJxyb3VuZCBoYWxmIHVw4oCdIHJ1bGUuIFRoZSBwcm9ibGVtIHdpdGggdGhlIOKAnHJvdW5kIGhhbGYgdXDigJ0gcnVsZSBpcyB0aGF0IGl0IGlzIGJpYXNlZCB1cHdhcmRzIGZvciBwb3NpdGl2ZSBudW1iZXJzLiBSb3VuZGluZyB0byBuZWFyZXN0IHdpdGggdGllcyB0b3dhcmRzIGV2ZW4gaXMgbm90LiBDb25zaWRlciB0aGlzIHNlcXVlbmNlIHdoaWNoIHN1bXMgdG8gemVyby4NCg0KYGBge3J9DQp4IDwtIHNlcSgtMTAwLjUsIDEwMC41LCBieSA9IDEpDQp4DQpzdW0oeCkNCmBgYA0KDQpBIG5pY2UgcHJvcGVydHkgb2Ygcm91bmRpbmcgcHJlc2VydmVkIHRoYXQgc3VtLiBVc2luZyB0aGUg4oCcdGllcyB0b3dhcmRzIGV2ZW7igJ0sIHRoZSBzdW0gaXMgc3RpbGwgemVyby4gSG93ZXZlciwgdGhlIOKAnHRpZXMgdG93YXJkcyAkK1xpbmZ0eSTigJ0gcHJvZHVjZXMgYSBub24temVybyBudW1iZXIuDQoNCmBgYHtyfQ0Kc3VtKHgpDQpzdW0ocm91bmQoeCkpDQpzdW0ocm91bmQyKHgpKQ0KYGBgDQoNClJvdW5kaW5nIHJ1bGVzIGNhbiBoYXZlIHJlYWwgd29ybGQgaW1wYWN0cy4gT25lIG5vdGFibGUgZXhhbXBsZSB3YXMgdGhhdCBpbiAxOTgzLCB0aGUgVmFuY291dmVyIHN0b2NrIGV4Y2hhbmdlIGFkanVzdGVkIGl0cyBpbmRleCBmcm9tIDUyNC44MTEgdG8gMTA5OC44OTIgdG8gY29ycmVjdCBmb3IgYWNjdW11bGF0ZWQgZXJyb3IgZHVlIHRvIHJvdW5kaW5nIHRvIHRocmVlIGRlY2ltYWwgcG9pbnRzIChzZWUgW1ZhbmNvdXZlciBTdG9jayBFeGNoYW5nZV0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvVmFuY291dmVyX1N0b2NrX0V4Y2hhbmdlKSkuIFRoaXMgc2l0ZSBsaXN0cyBzZXZlcmFsIG1vcmUgZXhhbXBsZXMgb2YgdGhlIGRhbmdlcnMgb2Ygcm91bmRpbmcgcnVsZXMuDQoNCiMjIyA1LiBXaGF0IGZ1bmN0aW9ucyBmcm9tIHRoZSBgcmVhZHJgIHBhY2thZ2UgYWxsb3cgeW91IHRvIHR1cm4gYSBzdHJpbmcgaW50byBsb2dpY2FsLCBpbnRlZ2VyLCBhbmQgZG91YmxlIHZlY3Rvcj8NCg0KVGhlIGZ1bmN0aW9uIGBwYXJzZV9sb2dpY2FsKClgIHBhcnNlcyBsb2dpY2FsIHZhbHVlcywgd2hpY2ggY2FuIGFwcGVhciBhcyB2YXJpYXRpb25zIG9mIFRSVUUvRkFMU0Ugb3IgMS8wLg0KDQpgYGB7cn0NCnBhcnNlX2xvZ2ljYWwoYygiVFJVRSIsICJGQUxTRSIsICIxIiwgIjAiLCAidHJ1ZSIsICJ0IiwgIk5BIikpDQpgYGANCg0KVGhlIGZ1bmN0aW9uIGBwYXJzZV9pbnRlZ2VyKClgIHBhcnNlcyBpbnRlZ2VyIHZhbHVlcy4NCg0KYGBge3J9DQpwYXJzZV9pbnRlZ2VyKGMoIjEyMzUiLCAiMDEzNCIsICJOQSIpKQ0KYGBgDQoNCkhvd2V2ZXIsIGlmIHRoZXJlIGFyZSBhbnkgbm9uLW51bWVyaWMgY2hhcmFjdGVycyBpbiB0aGUgc3RyaW5nLCBpbmNsdWRpbmcgY3VycmVuY3kgc3ltYm9scywgY29tbWFzLCBhbmQgZGVjaW1hbHMsIGBwYXJzZV9pbnRlZ2VyKClgIHdpbGwgcmFpc2UgYW4gZXJyb3IuDQoNCmBgYHtyfQ0KcGFyc2VfaW50ZWdlcihjKCIxMDAwIiwgIiQxLDAwMCIsICIxMC4wMCIpKQ0KYGBgDQoNClRoZSBmdW5jdGlvbiBgcGFyc2VfbnVtYmVyKClgIHBhcnNlcyBpbnRlZ2VyIHZhbHVlcy4NCg0KYGBge3J9DQpwYXJzZV9udW1iZXIoYygiMS4wIiwgIjMuNSIsICIkMSwwMDAuMDAiLCAiTkEiKSkNCmBgYA0KDQpVbmxpa2UgYHBhcnNlX2ludGVnZXIoKWAsIHRoZSBmdW5jdGlvbiBgcGFyc2VfbnVtYmVyKClgIGlzIHZlcnkgZm9yZ2l2aW5nIGFib3V0IHRoZSBmb3JtYXQgb2YgdGhlIG51bWJlcnMuIEl0IGlnbm9yZXMgYWxsIG5vbi1udW1lcmljIGNoYXJhY3RlcnMsIGFzIHdpdGggIiQxLDAwMC4wMCIgaW4gdGhlIGV4YW1wbGUuIFRoaXMgYWxsb3dzIGl0IHRvIGVhc2lseSBwYXJzZSBudW1lcmljIGZpZWxkcyB0aGF0IGluY2x1ZGUgY3VycmVuY3kgc3ltYm9scyBhbmQgY29tbWEgc2VwYXJhdG9ycyBpbiBudW1iZXIgc3RyaW5ncyB3aXRob3V0IGFueSBpbnRlcnZlbnRpb24gYnkgdGhlIHVzZXIu