2 Simple manipulations; numbers and vectors
2.1 Vectors and assignment
R operates on named data structures. The simplest such structure is the numeric vector, which is a single entity consisting of an ordered collection of numbers. For example:
x = c(10.4, 5.6, 3.1,6.4,21.7)
x
[1] 10.4 5.6 3.1 6.4 21.7
This is an assignment statement using the function c() which in this context can take an arbitrary number of vector arguments and whose value is a vector got by concatenating its arguments end to end.
A number occuring by itself in an expression is taken as a vector of length one.
Assignment can also be made using the function assign.
For example:
assign("x",c(10.4,5.6,3.1,6.4,21.7))
x
[1] 10.4 5.6 3.1 6.4 21.7
Assignments can also be made in the other direction. For example:
c(10.4,5.6,3.1,6.4,21.7)->x
x
[1] 10.4 5.6 3.1 6.4 21.7
If an expression is used as a complete command, the value is printed and lost. So now if we were to use the command:
1/x
[1] 0.09615385 0.17857143 0.32258065 0.15625000 0.04608295
Shown above, the reciprocals of the five values of x are printed at the terminal (and the value of x, of course, unchanged).
The further assignment
y=c(x,0,x)
y
[1] 10.4 5.6 3.1 6.4 21.7 0.0 10.4 5.6 3.1 6.4 21.7
2.2 Vector arithmetic
Vectors can be used in arithmetic expressions, in which case the operations are performed element by element. Vectors occuring in the same expression need not all be of the same length. If they are not, the value of the expression is a vetor with the same length as the longest vector which occurs in the expression. Shorter vectors in the expression are recycled as often as need be (perhaps fractionally) until they match the length of the longest vector. In particular a constant is simply repeated. So with the above assignments the command
v=2*x+y+1
longer object length is not a multiple of shorter object length
v
[1] 32.2 17.8 10.3 20.2 66.1 21.8 22.6 12.8 16.9 50.8 43.5
2.3 Generating regular sequences
R has a number of facilities for generating commonly used sequences of numbers. For example; 1:30 is
c(1:30)
[1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
[29] 29 30
2*1:15
[1] 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30
n=10
n
[1] 10
1:n
[1] 1 2 3 4 5 6 7 8 9 10
1:n-1
[1] 0 1 2 3 4 5 6 7 8 9
1:(n-1)
[1] 1 2 3 4 5 6 7 8 9
The construction 30:1 may be used to generate a sequence backwards.
30:1
[1] 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3
[29] 2 1
The function seq() is a more general facility for generating sequences. It has five arguments, only some of which may be specified in any one call. The first two arguments, if given, specify the beginning and end of the sequence, and if these are the only two arguments given the result is the same as the colon operator. That is seq(2,10) is the same vector as 2:10.
seq(2,10)
[1] 2 3 4 5 6 7 8 9 10
2:10
[1] 2 3 4 5 6 7 8 9 10
Arguments to seq(), and to many other R functions, can also be given in named form, in which case the order in which they appear is irrelevant. The first two arguments may be named from=value and to=value; thus seq(1, 30), seq(from=1, to=30) and seq(to=30, from=1) are all the same as 1:30. The next two arguments to seq() may be named by=value and length=value, which specify a step size and a length for the sequence respectively. If neither of these is given, the default by=1 is assumed. For example the following two sequences generate identical vectors using differing rulesets.
s3 = seq(-5,5,by=.2)
s3
[1] -5.0 -4.8 -4.6 -4.4 -4.2 -4.0 -3.8 -3.6 -3.4 -3.2 -3.0 -2.8 -2.6 -2.4 -2.2 -2.0
[17] -1.8 -1.6 -1.4 -1.2 -1.0 -0.8 -0.6 -0.4 -0.2 0.0 0.2 0.4 0.6 0.8 1.0 1.2
[33] 1.4 1.6 1.8 2.0 2.2 2.4 2.6 2.8 3.0 3.2 3.4 3.6 3.8 4.0 4.2 4.4
[49] 4.6 4.8 5.0
s4 = seq(length=51,from=-5,by=.2)
s4
[1] -5.0 -4.8 -4.6 -4.4 -4.2 -4.0 -3.8 -3.6 -3.4 -3.2 -3.0 -2.8 -2.6 -2.4 -2.2 -2.0
[17] -1.8 -1.6 -1.4 -1.2 -1.0 -0.8 -0.6 -0.4 -0.2 0.0 0.2 0.4 0.6 0.8 1.0 1.2
[33] 1.4 1.6 1.8 2.0 2.2 2.4 2.6 2.8 3.0 3.2 3.4 3.6 3.8 4.0 4.2 4.4
[49] 4.6 4.8 5.0
The fifth argument may be named along=vector, which is normally used as the only argument to create the sequence 1, 2, …, length(vector), or the empty sequence if the vector is empty (as it can be).
A related function is rep() which can be used for replicating an object in various complicated ways. The simplest form is seen below. This places five copies of x end-to-end in s5.
s5 = rep(x,times=5)
s5
[1] 10.4 5.6 3.1 6.4 21.7 10.4 5.6 3.1 6.4 21.7 10.4 5.6 3.1 6.4 21.7 10.4
[17] 5.6 3.1 6.4 21.7 10.4 5.6 3.1 6.4 21.7
Another useful version, seen below, is. Which repeats each element of the vector x five times before moving on to the next.
s6 = rep(x, each=5)
s6
[1] 10.4 10.4 10.4 10.4 10.4 5.6 5.6 5.6 5.6 5.6 3.1 3.1 3.1 3.1 3.1 6.4
[17] 6.4 6.4 6.4 6.4 21.7 21.7 21.7 21.7 21.7
2.4 Logical vectors
As well as numerical vectors, R allows manipulation of logical quantities. The elements of a logical vector can have the values TRUE, FALSE, and NA (for “not available”). The first two are often abbreviated as T and F, respectively. Note however that T and F are just variables which are set to TRUE and FALSE by default, but are not reserved words and hence can be overwritten by the user. Hence, you should always use TRUE and FALSE.
Logical vectors are generated by conditions. For example
temp = x>13
temp
[1] FALSE FALSE FALSE FALSE TRUE
sets temp as a vector of the same length as x with values FALSE corresponding to elements of x where the condition is not met and TRUE where it is.
The logical operators are <, <=, >, >=, == for exact equality and != for inequality. In addition if c1 and c2 are logical expressions, then c1 & c2 is their intersection (“and”), c1 given c2 is their union (“or”), and !c1 is the negation of c1.
Logical vectors may be used in ordinary arithmetic, in which case they are coerced into numeric vectors, FALSE becoming 0 and TRUE becoming 1. However there are situations where logical vectors and their coerced numeric counterparts are not equivalent, for example see the next subsection.
2.5 Missing values
In some cases the components of a vector may not be completely known. When an element or value is “not available” or a “missing value” in the statistical sense, a place within a vector may be reserved for it by assigning it the special value NA. In general any operation on an NA becomes an NA. The motivation for this rule is simply that if the specification of an operation is incomplete, the result cannot be known and hence is not available.
The function is.na(x) gives a logical vector of the same size as x with value TRUE if and only if the corresponding element in x is NA.
z = c(1:3,NA)
z
[1] 1 2 3 NA
ind = is.na(z)
ind
[1] FALSE FALSE FALSE TRUE
There is a second kind of “missing” values which are produced by numerical computation, the so-called Not a Number, NaN, values. Examples are:
0/0
[1] NaN
or
Inf/Inf
[1] NaN
In summary, is.na(xx) is TRUE both for NA and NaN values. To differentiate these, is.nan(xx) is only TRUE for NaNs.
2.6 Character vectors
Character quantities and character vectors are used frequently in R, for example as plot lables. Where needed they are denoted by a sequence of characters delimited by the double quote character, e.g., “x-values”, “New iteration results”.
Character strings are entered using either matching double(“) or single (’) quotes, but are printed using double quotes (or sometimes without quotes). They use C-style escape sequences, using forward-slash as the escape character, so forward-slash is entered and printed as forward-slash forward-slash, and inside double quotes” is entered as forward-slash".
Other useful escape sequences are forward-slash n, newline, forward-slash t, tab and forward-slash b, backspace - see ?Quotes for a full list.
Character vectors may be concatenated into a vector by the c(); read on for examples.
The paste() function takes an arbitrary number of arguments and concatenates them one by one into character strings. Any numbers given among the arguments are coerced into character strings in the evident way, that is, in the same way they would be if they were printed. The arguments are by default separated in the result by a single blank character, but this can be changed by the named argument, sep=string, which changes it to string, possibly empty.
For example
labs = paste(c("X","Y"),1:10,sep="")
labs
[1] "X1" "Y2" "X3" "Y4" "X5" "Y6" "X7" "Y8" "X9" "Y10"
c("X1","Y2","X3","Y4","X5","Y6","X7","Y8","X9","Y10")
[1] "X1" "Y2" "X3" "Y4" "X5" "Y6" "X7" "Y8" "X9" "Y10"
2.7 Index Vectors; Selecting and Modifying Subsets of a Data Set
Subsets of the elements of a vector may be selected by appending to the name of the vector an index vector in square brackets. More generally any expression that evaluates to a vector may have subsets of its elements similarly selected by appending an index vector in square brackets immediately after the expression.
- A logical vector. In this case the index vector is recycled to the same length as the vector from which elements are to be selected. Values corresponding to TRUE in the index vector are selected and those corresponding to FALSE are omitted. For example
y = x[!is.na(x)]
y
[1] 10.4 5.6 3.1 6.4 21.7
creates (or re-creates) an object y which will contain the non-missing values of x, in the same order. Note that if x has missing values, y will be shorter than x. Also,
z = (x+1)[(!is.na(x)) & x>0]
z
[1] 11.4 6.6 4.1 7.4 22.7
creates an object z and places in it the values of the vector x + 1 for which the corresponding value in x was both non-missing and positive.
- A vector of positive integral quantitites. In this case the values in the index vector must lie in the set {1, 2, …, length(x)}. The corresponding elements of the vector are selected and concatenated, in that order, in the result. The index vector can be of any length and the result is of the same length as the index vector. For example x[6] is the sixth component of x and
\(> x[1:10]\)
selects the first 10 elements of x (assuming length(x) is not less than 10). Also
\(c("x","y")[rep(c(1,2,2,1),times=4]\)
x[6]
[1] NA
x[1:10]
[1] 10.4 5.6 3.1 6.4 21.7 NA NA NA NA NA
c("x","y")[rep(c(1,2,2,1),times=4)]
[1] "x" "y" "y" "x" "x" "y" "y" "x" "x" "y" "y" "x" "x" "y" "y" "x"
(an admittedly unlikely thing to do) produces a character vector of length 16 consisting of “x”, “y”, “y”, “x” repeated four times.
- A vector of negative integral quantities. Such an index vector specifies the values to be excluded rather than included. Thus
\(y = x[-(1:5)]\)
gives
y all but the first five elements of
x
y = x[-(1:5)]
y
numeric(0)
Since x only consists of five elements, nothing is produced.
- A vector of character strings. This possibility only applies where an object has a names attribute to identify its componenets. In this case a sub-vector of the names vector may be used in the same way as the positive integral labels in item 2 further above.
fruit = c(5,10,1,20)
names(fruit) = c("orange","banana","apple","peach")
lunch = fruit[c("apple","orange")]
The advantage is that alphanumeric names are often easier to remember than numeric indices This option is particularly useful in connection with data frames, as we shall see later.
An indexed expression can also appear on the receiving end of an assignment, in which case the assignment operation is performed only on those elements of the vector. The expression must be of the form vector[index_vector] as having an arbitrary expression in place of the vector name does not make much sense here.
For example
x[is.na(x)] = 0
x
[1] 10.4 5.6 3.1 6.4 21.7
replaces any missing values in x by zeros and
y[y<0] = -y[y<0]
y
[1] 10.4 5.6 3.1 6.4 21.7
has the same effect as
2.8 Other types of objects
Vectors are the most important type of object in R, but there are several others which we will meet more formally in later sections.
- matrices or more generally arrays are multi-dimensinal generalizations of vectors. In fact, they are vectors that can be indexed by two or more indices and will be printed in special ways.
- factors provide compact ways to handle categorical data.
- lists are a general form of vector in which the various elements need not be of the same type, and are often themselves vectors or lists. Lists provide a convenient way to return the results of a statistical computation.
- data frames are matrix-like structures, in which the columns can be of different types. Think of data frames as ‘data matrices’ with one row per observational unit but with (possibly) both numerical and categorical variables. Many experiments are best described by data frames: the treatments are categorical but the response is numeric. functions are themselves objects in R which can be stored in the project’s workspace. This provides a simple and convenient way to extend R.
LS0tCnRpdGxlOiAiQ2hhcHRlciAyIFNpbXBsZSBNYW5pcHVsYXRpb25zOyBOdW1iZXJzICYgVmVjdG9ycyIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyAyIFNpbXBsZSBtYW5pcHVsYXRpb25zOyBudW1iZXJzIGFuZCB2ZWN0b3JzIwoKIyMgMi4xIFZlY3RvcnMgYW5kIGFzc2lnbm1lbnQjIwoKUiBvcGVyYXRlcyBvbiBuYW1lZCAqZGF0YSBzdHJ1Y3R1cmVzKi4gVGhlIHNpbXBsZXN0IHN1Y2ggc3RydWN0dXJlIGlzIHRoZSBudW1lcmljICp2ZWN0b3IqLCB3aGljaCBpcyBhIHNpbmdsZSBlbnRpdHkgY29uc2lzdGluZyBvZiBhbiBvcmRlcmVkIGNvbGxlY3Rpb24gb2YgbnVtYmVycy4gRm9yIGV4YW1wbGU6CgpgYGB7cn0KeCA9IGMoMTAuNCwgNS42LCAzLjEsNi40LDIxLjcpCngKYGBgCgpUaGlzIGlzIGFuICphc3NpZ25tZW50KiBzdGF0ZW1lbnQgdXNpbmcgdGhlICpmdW5jdGlvbiogYygpIHdoaWNoIGluIHRoaXMgY29udGV4dCBjYW4gdGFrZSBhbiBhcmJpdHJhcnkgbnVtYmVyIG9mIHZlY3RvciAqYXJndW1lbnRzKiBhbmQgd2hvc2UgdmFsdWUgaXMgYSB2ZWN0b3IgZ290IGJ5IGNvbmNhdGVuYXRpbmcgaXRzIGFyZ3VtZW50cyBlbmQgdG8gZW5kLgoKQSBudW1iZXIgb2NjdXJpbmcgYnkgaXRzZWxmIGluIGFuIGV4cHJlc3Npb24gaXMgdGFrZW4gYXMgYSB2ZWN0b3Igb2YgbGVuZ3RoIG9uZS4KCkFzc2lnbm1lbnQgY2FuIGFsc28gYmUgbWFkZSB1c2luZyB0aGUgZnVuY3Rpb24gX19hc3NpZ25fXy4KCkZvciBleGFtcGxlOgoKYGBge3J9CmFzc2lnbigieCIsYygxMC40LDUuNiwzLjEsNi40LDIxLjcpKQp4CmBgYAoKQXNzaWdubWVudHMgY2FuIGFsc28gYmUgbWFkZSBpbiB0aGUgb3RoZXIgZGlyZWN0aW9uLiBGb3IgZXhhbXBsZToKCmBgYHtyfQpjKDEwLjQsNS42LDMuMSw2LjQsMjEuNyktPngKeApgYGAKCklmIGFuIGV4cHJlc3Npb24gaXMgdXNlZCBhcyBhIGNvbXBsZXRlIGNvbW1hbmQsIHRoZSB2YWx1ZSBpcyBwcmludGVkICphbmQgbG9zdCouIFNvIG5vdyBpZiB3ZSB3ZXJlIHRvIHVzZSB0aGUgY29tbWFuZDoKCmBgYHtyfQoxL3gKYGBgCgpTaG93biBhYm92ZSwgdGhlIHJlY2lwcm9jYWxzIG9mIHRoZSBmaXZlIHZhbHVlcyBvZiB4IGFyZSBwcmludGVkIGF0IHRoZSB0ZXJtaW5hbCAoYW5kIHRoZSB2YWx1ZSBvZiB4LCBvZiBjb3Vyc2UsIHVuY2hhbmdlZCkuCgpUaGUgZnVydGhlciBhc3NpZ25tZW50CgpgYGB7cn0KeT1jKHgsMCx4KQp5CmBgYAoKIyMgMi4yIFZlY3RvciBhcml0aG1ldGljICMjCgo+IFZlY3RvcnMgY2FuIGJlIHVzZWQgaW4gYXJpdGhtZXRpYyBleHByZXNzaW9ucywgaW4gd2hpY2ggY2FzZSB0aGUgb3BlcmF0aW9ucyBhcmUgcGVyZm9ybWVkIGVsZW1lbnQgYnkgZWxlbWVudC4gVmVjdG9ycyBvY2N1cmluZyBpbiB0aGUgc2FtZSBleHByZXNzaW9uIG5lZWQgbm90IGFsbCBiZSBvZiB0aGUgc2FtZSBsZW5ndGguIElmIHRoZXkgYXJlIG5vdCwgdGhlIHZhbHVlIG9mIHRoZSBleHByZXNzaW9uIGlzIGEgdmV0b3Igd2l0aCB0aGUgc2FtZSBsZW5ndGggYXMgdGhlIGxvbmdlc3QgdmVjdG9yIHdoaWNoIG9jY3VycyBpbiB0aGUgZXhwcmVzc2lvbi4gU2hvcnRlciB2ZWN0b3JzIGluIHRoZSBleHByZXNzaW9uIGFyZSAqcmVjeWNsZWQqIGFzIG9mdGVuIGFzIG5lZWQgYmUgKHBlcmhhcHMgZnJhY3Rpb25hbGx5KSB1bnRpbCB0aGV5IG1hdGNoIHRoZSBsZW5ndGggb2YgdGhlIGxvbmdlc3QgdmVjdG9yLiBJbiBwYXJ0aWN1bGFyIGEgY29uc3RhbnQgaXMgc2ltcGx5IHJlcGVhdGVkLiBTbyB3aXRoIHRoZSBhYm92ZSBhc3NpZ25tZW50cyB0aGUgY29tbWFuZAoKYGBge3J9CnY9Mip4K3krMQp2CmBgYAoKIyMgMi4zIEdlbmVyYXRpbmcgcmVndWxhciBzZXF1ZW5jZXMgIyMKClIgaGFzIGEgbnVtYmVyIG9mIGZhY2lsaXRpZXMgZm9yIGdlbmVyYXRpbmcgY29tbW9ubHkgdXNlZCBzZXF1ZW5jZXMgb2YgbnVtYmVycy4gRm9yIGV4YW1wbGU7IDE6MzAgaXMKCmBgYHtyfQpjKDE6MzApCmBgYAoKYGBge3J9CjIqMToxNQpgYGAKCmBgYHtyfQpuPTEwCm4KMTpuCjE6bi0xCjE6KG4tMSkKYGBgCgpUaGUgY29uc3RydWN0aW9uIDMwOjEgbWF5IGJlIHVzZWQgdG8gZ2VuZXJhdGUgYSBzZXF1ZW5jZSBiYWNrd2FyZHMuCgpgYGB7cn0KMzA6MQpgYGAKClRoZSBmdW5jdGlvbiAqc2VxKCkqIGlzIGEgbW9yZSBnZW5lcmFsIGZhY2lsaXR5IGZvciBnZW5lcmF0aW5nIHNlcXVlbmNlcy4gSXQgaGFzIGZpdmUgYXJndW1lbnRzLCBvbmx5IHNvbWUgb2Ygd2hpY2ggbWF5IGJlIHNwZWNpZmllZCBpbiBhbnkgb25lIGNhbGwuIFRoZSBmaXJzdCB0d28gYXJndW1lbnRzLCBpZiBnaXZlbiwgc3BlY2lmeSB0aGUgYmVnaW5uaW5nIGFuZCBlbmQgb2YgdGhlIHNlcXVlbmNlLCBhbmQgaWYgdGhlc2UgYXJlIHRoZSBvbmx5IHR3byBhcmd1bWVudHMgZ2l2ZW4gdGhlIHJlc3VsdCBpcyB0aGUgc2FtZSBhcyB0aGUgY29sb24gb3BlcmF0b3IuIFRoYXQgaXMgKnNlcSgyLDEwKSogaXMgdGhlIHNhbWUgdmVjdG9yIGFzIDI6MTAuCgpgYGB7cn0Kc2VxKDIsMTApCjI6MTAKYGBgCgo+IEFyZ3VtZW50cyB0byBzZXEoKSwgYW5kIHRvIG1hbnkgb3RoZXIgUiBmdW5jdGlvbnMsIGNhbiBhbHNvIGJlIGdpdmVuIGluIG5hbWVkIGZvcm0sIGluIHdoaWNoIGNhc2UgdGhlIG9yZGVyIGluIHdoaWNoIHRoZXkgYXBwZWFyIGlzIGlycmVsZXZhbnQuIFRoZSBmaXJzdCB0d28gYXJndW1lbnRzIG1heSBiZSBuYW1lZCAqZnJvbT12YWx1ZSogYW5kICp0bz12YWx1ZSo7IHRodXMgKipzZXEoMSwgMzApKiosICoqc2VxKGZyb209MSwgdG89MzApKiogYW5kICoqc2VxKHRvPTMwLCBmcm9tPTEpKiogYXJlIGFsbCB0aGUgc2FtZSBhcyAqKjE6MzAqKi4gVGhlIG5leHQgdHdvIGFyZ3VtZW50cyB0byBzZXEoKSBtYXkgYmUgbmFtZWQgYnk9KnZhbHVlKiBhbmQgbGVuZ3RoPSp2YWx1ZSosIHdoaWNoIHNwZWNpZnkgYSBzdGVwIHNpemUgYW5kIGEgbGVuZ3RoIGZvciB0aGUgc2VxdWVuY2UgcmVzcGVjdGl2ZWx5LiBJZiBuZWl0aGVyIG9mIHRoZXNlIGlzIGdpdmVuLCB0aGUgZGVmYXVsdCAqYnk9MSogaXMgYXNzdW1lZC4gRm9yIGV4YW1wbGUgdGhlIGZvbGxvd2luZyB0d28gc2VxdWVuY2VzIGdlbmVyYXRlIGlkZW50aWNhbCB2ZWN0b3JzIHVzaW5nIGRpZmZlcmluZyBydWxlc2V0cy4KCmBgYHtyfQpzMyA9IHNlcSgtNSw1LGJ5PS4yKQpzMwpzNCA9IHNlcShsZW5ndGg9NTEsZnJvbT0tNSxieT0uMikKczQKYGBgCgpUaGUgZmlmdGggYXJndW1lbnQgbWF5IGJlIG5hbWVkIGFsb25nPSp2ZWN0b3IqLCB3aGljaCBpcyBub3JtYWxseSB1c2VkIGFzIHRoZSBvbmx5IGFyZ3VtZW50IHRvIGNyZWF0ZSB0aGUgc2VxdWVuY2UgMSwgMiwgLi4uLCBsZW5ndGgoKnZlY3RvciopLCBvciB0aGUgZW1wdHkgc2VxdWVuY2UgaWYgdGhlIHZlY3RvciBpcyBlbXB0eSAoYXMgaXQgY2FuIGJlKS4KCkEgcmVsYXRlZCBmdW5jdGlvbiBpcyByZXAoKSB3aGljaCBjYW4gYmUgdXNlZCBmb3IgcmVwbGljYXRpbmcgYW4gb2JqZWN0IGluIHZhcmlvdXMgY29tcGxpY2F0ZWQgd2F5cy4gVGhlIHNpbXBsZXN0IGZvcm0gaXMgc2VlbiBiZWxvdy4gVGhpcyBwbGFjZXMgZml2ZSBjb3BpZXMgb2YgKngqIGVuZC10by1lbmQgaW4gczUuCgpgYGB7cn0KczUgPSByZXAoeCx0aW1lcz01KQpzNQpgYGAKCkFub3RoZXIgdXNlZnVsIHZlcnNpb24sIHNlZW4gYmVsb3csIGlzLiBXaGljaCByZXBlYXRzIGVhY2ggZWxlbWVudCBvZiB0aGUgdmVjdG9yICp4KiBmaXZlIHRpbWVzIGJlZm9yZSBtb3Zpbmcgb24gdG8gdGhlIG5leHQuCgpgYGB7cn0KczYgPSByZXAoeCwgZWFjaD01KQpzNgpgYGAKCiMjIDIuNCBMb2dpY2FsIHZlY3RvcnMgIyMKCkFzIHdlbGwgYXMgbnVtZXJpY2FsIHZlY3RvcnMsIFIgYWxsb3dzIG1hbmlwdWxhdGlvbiBvZiBsb2dpY2FsIHF1YW50aXRpZXMuIFRoZSBlbGVtZW50cyBvZiBhIGxvZ2ljYWwgdmVjdG9yIGNhbiBoYXZlIHRoZSB2YWx1ZXMgX19UUlVFX18sIF9fRkFMU0VfXywgYW5kIF9fTkFfXyAoZm9yICJub3QgYXZhaWxhYmxlIikuIFRoZSBmaXJzdCB0d28gYXJlIG9mdGVuIGFiYnJldmlhdGVkIGFzIF9fVF9fIGFuZCBfX0ZfXywgcmVzcGVjdGl2ZWx5LiBOb3RlIGhvd2V2ZXIgdGhhdCBfX1RfXyBhbmQgX19GX18gYXJlIGp1c3QgdmFyaWFibGVzIHdoaWNoIGFyZSBzZXQgdG8gX19UUlVFX18gYW5kIF9fRkFMU0VfXyBieSBkZWZhdWx0LCBidXQgYXJlIG5vdCByZXNlcnZlZCB3b3JkcyBhbmQgaGVuY2UgY2FuIGJlIG92ZXJ3cml0dGVuIGJ5IHRoZSB1c2VyLiBIZW5jZSwgeW91IHNob3VsZCBhbHdheXMgdXNlIF9fVFJVRV9fIGFuZCBfX0ZBTFNFX18uCgpMb2dpY2FsIHZlY3RvcnMgYXJlIGdlbmVyYXRlZCBieSAqY29uZGl0aW9ucyouIEZvciBleGFtcGxlCgpgYGB7cn0KdGVtcCA9IHg+MTMKdGVtcApgYGAKCnNldHMgX190ZW1wX18gYXMgYSB2ZWN0b3Igb2YgdGhlIHNhbWUgbGVuZ3RoIGFzICp4KiB3aXRoIHZhbHVlcyBfX0ZBTFNFX18gY29ycmVzcG9uZGluZyB0byBlbGVtZW50cyBvZiAqeCogd2hlcmUgdGhlIGNvbmRpdGlvbiBpcyAqbm90KiBtZXQgYW5kIF9fVFJVRV9fIHdoZXJlIGl0IGlzLgoKVGhlIGxvZ2ljYWwgb3BlcmF0b3JzIGFyZSA8LCA8PSwgPiwgPj0sID09IGZvciBleGFjdCBlcXVhbGl0eSBhbmQgIT0gZm9yIGluZXF1YWxpdHkuIEluIGFkZGl0aW9uIGlmIF9fYzFfXyBhbmQgX19jMl9fIGFyZSBsb2dpY2FsIGV4cHJlc3Npb25zLCB0aGVuIF9fYzFfXyAmIF9fYzJfXyBpcyB0aGVpciBpbnRlcnNlY3Rpb24gKCJhbmQiKSwgX19jMV9fICpnaXZlbiogX19jMl9fIGlzIHRoZWlyIHVuaW9uICgib3IiKSwgYW5kICFfX2MxX18gaXMgdGhlIG5lZ2F0aW9uIG9mIGMxLgoKTG9naWNhbCB2ZWN0b3JzIG1heSBiZSB1c2VkIGluIG9yZGluYXJ5IGFyaXRobWV0aWMsIGluIHdoaWNoIGNhc2UgdGhleSBhcmUgKmNvZXJjZWQqIGludG8gbnVtZXJpYyB2ZWN0b3JzLCBfX0ZBTFNFX18gYmVjb21pbmcgX18wX18gYW5kIF9fVFJVRV9fIGJlY29taW5nIF9fMV9fLiBIb3dldmVyIHRoZXJlIGFyZSBzaXR1YXRpb25zIHdoZXJlIGxvZ2ljYWwgdmVjdG9ycyBhbmQgdGhlaXIgY29lcmNlZCBudW1lcmljIGNvdW50ZXJwYXJ0cyBhcmUgbm90IGVxdWl2YWxlbnQsIGZvciBleGFtcGxlIHNlZSB0aGUgbmV4dCBzdWJzZWN0aW9uLiAKCiMjIDIuNSBNaXNzaW5nIHZhbHVlcyAjIwoKPiBJbiBzb21lIGNhc2VzIHRoZSBjb21wb25lbnRzIG9mIGEgdmVjdG9yIG1heSBub3QgYmUgY29tcGxldGVseSBrbm93bi4gV2hlbiBhbiBlbGVtZW50IG9yIHZhbHVlIGlzICJub3QgYXZhaWxhYmxlIiBvciBhICJtaXNzaW5nIHZhbHVlIiBpbiB0aGUgc3RhdGlzdGljYWwgc2Vuc2UsIGEgcGxhY2Ugd2l0aGluIGEgdmVjdG9yIG1heSBiZSByZXNlcnZlZCBmb3IgaXQgYnkgYXNzaWduaW5nIGl0IHRoZSBzcGVjaWFsIHZhbHVlIF9fTkFfXy4gSW4gZ2VuZXJhbCBhbnkgb3BlcmF0aW9uIG9uIGFuIF9fTkFfXyBiZWNvbWVzIGFuIF9fTkFfXy4gVGhlIG1vdGl2YXRpb24gZm9yIHRoaXMgcnVsZSBpcyBzaW1wbHkgdGhhdCBpZiB0aGUgc3BlY2lmaWNhdGlvbiBvZiBhbiBvcGVyYXRpb24gaXMgaW5jb21wbGV0ZSwgdGhlIHJlc3VsdCBjYW5ub3QgYmUga25vd24gYW5kIGhlbmNlIGlzIG5vdCBhdmFpbGFibGUuCgpUaGUgZnVuY3Rpb24gX19pcy5uYSh4KV9fIGdpdmVzIGEgbG9naWNhbCB2ZWN0b3Igb2YgdGhlIHNhbWUgc2l6ZSBhcyAqeCogd2l0aCB2YWx1ZSBfX1RSVUVfXyBpZiBhbmQgb25seSBpZiB0aGUgY29ycmVzcG9uZGluZyBlbGVtZW50IGluICp4KiBpcyBfX05BX18uIAoKYGBge3J9CnogPSBjKDE6MyxOQSkKegppbmQgPSBpcy5uYSh6KQppbmQKYGBgCgpUaGVyZSBpcyBhIHNlY29uZCBraW5kIG9mICJtaXNzaW5nIiB2YWx1ZXMgd2hpY2ggYXJlIHByb2R1Y2VkIGJ5IG51bWVyaWNhbCBjb21wdXRhdGlvbiwgdGhlIHNvLWNhbGxlZCAqTm90IGEgTnVtYmVyKiwgX19OYU5fXywgdmFsdWVzLiBFeGFtcGxlcyBhcmU6CgpgYGB7cn0KMC8wCmBgYAoKb3IKCmBgYHtyfQpJbmYvSW5mCmBgYAoKSW4gc3VtbWFyeSwgX19pcy5uYSh4eClfXyBpcyBfX1RSVUVfXyAqYm90aCogZm9yIF9fTkFfXyBhbmQgX19OYU5fXyB2YWx1ZXMuIFRvIGRpZmZlcmVudGlhdGUgdGhlc2UsIF9faXMubmFuKHh4KV9fIGlzIG9ubHkgX19UUlVFX18gZm9yIF9fTmFOc19fLgoKIyMgMi42IENoYXJhY3RlciB2ZWN0b3JzICMjCgpDaGFyYWN0ZXIgcXVhbnRpdGllcyBhbmQgY2hhcmFjdGVyIHZlY3RvcnMgYXJlIHVzZWQgZnJlcXVlbnRseSBpbiBSLCBmb3IgZXhhbXBsZSBhcyBwbG90IGxhYmxlcy4gV2hlcmUgbmVlZGVkIHRoZXkgYXJlIGRlbm90ZWQgYnkgYSBzZXF1ZW5jZSBvZiBjaGFyYWN0ZXJzIGRlbGltaXRlZCBieSB0aGUgZG91YmxlIHF1b3RlIGNoYXJhY3RlciwgZS5nLiwgX18ieC12YWx1ZXMiLCAiTmV3IGl0ZXJhdGlvbiByZXN1bHRzIl9fLgoKQ2hhcmFjdGVyIHN0cmluZ3MgYXJlIGVudGVyZWQgdXNpbmcgZWl0aGVyIG1hdGNoaW5nIGRvdWJsZSgiKSBvciBzaW5nbGUgKCcpIHF1b3RlcywgYnV0IGFyZSBwcmludGVkIHVzaW5nIGRvdWJsZSBxdW90ZXMgKG9yIHNvbWV0aW1lcyB3aXRob3V0IHF1b3RlcykuIFRoZXkgdXNlIEMtc3R5bGUgZXNjYXBlIHNlcXVlbmNlcywgdXNpbmcgX19mb3J3YXJkLXNsYXNoX18gYXMgdGhlIGVzY2FwZSBjaGFyYWN0ZXIsIHNvIF9fZm9yd2FyZC1zbGFzaF9fIGlzIGVudGVyZWQgYW5kIHByaW50ZWQgYXMgX19mb3J3YXJkLXNsYXNoIGZvcndhcmQtc2xhc2hfXywgYW5kIGluc2lkZSBkb3VibGUgcXVvdGVzICIgaXMgZW50ZXJlZCBhcyBfX2ZvcndhcmQtc2xhc2giX18uCgpPdGhlciB1c2VmdWwgZXNjYXBlIHNlcXVlbmNlcyBhcmUgX19mb3J3YXJkLXNsYXNoIG5fXywgbmV3bGluZSwgX19mb3J3YXJkLXNsYXNoIHRfXywgdGFiIGFuZCBfX2ZvcndhcmQtc2xhc2ggYl9fLCBiYWNrc3BhY2UgLSBzZWUgX18/UXVvdGVzX18gZm9yIGEgZnVsbCBsaXN0LgoKQ2hhcmFjdGVyIHZlY3RvcnMgbWF5IGJlIGNvbmNhdGVuYXRlZCBpbnRvIGEgdmVjdG9yIGJ5IHRoZSBjKCk7IHJlYWQgb24gZm9yIGV4YW1wbGVzLgoKPiBUaGUgX19wYXN0ZSgpX18gZnVuY3Rpb24gdGFrZXMgYW4gYXJiaXRyYXJ5IG51bWJlciBvZiBhcmd1bWVudHMgYW5kIGNvbmNhdGVuYXRlcyB0aGVtIG9uZSBieSBvbmUgaW50byBjaGFyYWN0ZXIgc3RyaW5ncy4gQW55IG51bWJlcnMgZ2l2ZW4gYW1vbmcgdGhlIGFyZ3VtZW50cyBhcmUgY29lcmNlZCBpbnRvIGNoYXJhY3RlciBzdHJpbmdzIGluIHRoZSBldmlkZW50IHdheSwgdGhhdCBpcywgaW4gdGhlIHNhbWUgd2F5IHRoZXkgd291bGQgYmUgaWYgdGhleSB3ZXJlIHByaW50ZWQuIFRoZSBhcmd1bWVudHMgYXJlIGJ5IGRlZmF1bHQgc2VwYXJhdGVkIGluIHRoZSByZXN1bHQgYnkgYSBzaW5nbGUgYmxhbmsgY2hhcmFjdGVyLCBidXQgdGhpcyBjYW4gYmUgY2hhbmdlZCBieSB0aGUgbmFtZWQgYXJndW1lbnQsIF9fKnNlcD1zdHJpbmcqX18sIHdoaWNoIGNoYW5nZXMgaXQgdG8gX18qc3RyaW5nKl9fLCBwb3NzaWJseSBlbXB0eS4KCkZvciBleGFtcGxlCgpgYGB7cn0KbGFicyA9IHBhc3RlKGMoIlgiLCJZIiksMToxMCxzZXA9IiIpCmxhYnMKYygiWDEiLCJZMiIsIlgzIiwiWTQiLCJYNSIsIlk2IiwiWDciLCJZOCIsIlg5IiwiWTEwIikKYGBgCgojIyAyLjcgSW5kZXggVmVjdG9yczsgU2VsZWN0aW5nIGFuZCBNb2RpZnlpbmcgU3Vic2V0cyBvZiBhIERhdGEgU2V0ICMjCgpTdWJzZXRzIG9mIHRoZSBlbGVtZW50cyBvZiBhIHZlY3RvciBtYXkgYmUgc2VsZWN0ZWQgYnkgYXBwZW5kaW5nIHRvIHRoZSBuYW1lIG9mIHRoZSB2ZWN0b3IgYW4gKmluZGV4IHZlY3RvciogaW4gc3F1YXJlIGJyYWNrZXRzLiBNb3JlIGdlbmVyYWxseSBhbnkgZXhwcmVzc2lvbiB0aGF0IGV2YWx1YXRlcyB0byBhIHZlY3RvciBtYXkgIGhhdmUgc3Vic2V0cyBvZiBpdHMgZWxlbWVudHMgc2ltaWxhcmx5IHNlbGVjdGVkIGJ5IGFwcGVuZGluZyBhbiBpbmRleCB2ZWN0b3IgaW4gc3F1YXJlIGJyYWNrZXRzIGltbWVkaWF0ZWx5IGFmdGVyIHRoZSBleHByZXNzaW9uLgoKPiAxLiBfX0EgbG9naWNhbCB2ZWN0b3JfXy4gSW4gdGhpcyBjYXNlIHRoZSBpbmRleCB2ZWN0b3IgaXMgcmVjeWNsZWQgdG8gdGhlIHNhbWUgbGVuZ3RoIGFzIHRoZSB2ZWN0b3IgZnJvbSB3aGljaCBlbGVtZW50cyBhcmUgdG8gYmUgc2VsZWN0ZWQuIFZhbHVlcyBjb3JyZXNwb25kaW5nIHRvIF9fVFJVRV9fIGluIHRoZSBpbmRleCB2ZWN0b3IgYXJlIHNlbGVjdGVkIGFuZCB0aG9zZSBjb3JyZXNwb25kaW5nIHRvIF9fRkFMU0VfXyBhcmUgb21pdHRlZC4gRm9yIGV4YW1wbGUKCmBgYHtyfQp5ID0geFshaXMubmEoeCldCnkKYGBgCgpjcmVhdGVzIChvciByZS1jcmVhdGVzKSBhbiBvYmplY3QgKnkqIHdoaWNoIHdpbGwgY29udGFpbiB0aGUgbm9uLW1pc3NpbmcgdmFsdWVzIG9mICp4KiwgaW4gdGhlIHNhbWUgb3JkZXIuIE5vdGUgdGhhdCBpZiAqeCogaGFzIG1pc3NpbmcgdmFsdWVzLCAqeSogd2lsbCBiZSBzaG9ydGVyIHRoYW4gKngqLiBBbHNvLAoKYGBge3J9CnogPSAoeCsxKVsoIWlzLm5hKHgpKSAmIHg+MF0KegpgYGAKCmNyZWF0ZXMgYW4gb2JqZWN0ICp6KiBhbmQgcGxhY2VzIGluIGl0IHRoZSB2YWx1ZXMgb2YgdGhlIHZlY3RvciAqeCArIDEqIGZvciB3aGljaCB0aGUgY29ycmVzcG9uZGluZyB2YWx1ZSBpbiAqeCogd2FzIGJvdGggX19ub24tbWlzc2luZ19fIGFuZCBfX3Bvc2l0aXZlX18uCgo+IDIuICBfX0EgdmVjdG9yIG9mIHBvc2l0aXZlIGludGVncmFsIHF1YW50aXRpdGVzX18uIEluIHRoaXMgY2FzZSB0aGUgdmFsdWVzIGluIHRoZSBpbmRleCB2ZWN0b3IgbXVzdCBsaWUgaW4gdGhlIHNldCB7MSwgMiwgLi4uLCBsZW5ndGgoeCl9LiBUaGUgY29ycmVzcG9uZGluZyBlbGVtZW50cyBvZiB0aGUgdmVjdG9yIGFyZSBzZWxlY3RlZCBhbmQgY29uY2F0ZW5hdGVkLCAqaW4gdGhhdCBvcmRlciosIGluIHRoZSByZXN1bHQuIFRoZSBpbmRleCB2ZWN0b3IgY2FuIGJlIG9mIGFueSBsZW5ndGggYW5kIHRoZSByZXN1bHQgaXMgb2YgdGhlIHNhbWUgbGVuZ3RoIGFzIHRoZSBpbmRleCB2ZWN0b3IuIEZvciBleGFtcGxlICoqeFs2XSoqIGlzIHRoZSBzaXh0aCBjb21wb25lbnQgb2YgKngqIGFuZAoKPGRpdiBhbGlnbj0iY2VudGVyIj4gJD4geFsxOjEwXSQKCjxkaXYgYWxpZ249ImxlZnQiPiBzZWxlY3RzIHRoZSBmaXJzdCAxMCBlbGVtZW50cyBvZiAqeCogKGFzc3VtaW5nIGxlbmd0aCh4KSBpcyBub3QgbGVzcyB0aGFuIDEwKS4gQWxzbwoKPGRpdiBhbGlnbj0iY2VudGVyIj4gJGMoIngiLCJ5IilbcmVwKGMoMSwyLDIsMSksdGltZXM9NF0kCjxkaXYgYWxpZ249ImxlZnQiPgpgYGB7cn0KeFs2XQp4WzE6MTBdCmMoIngiLCJ5IilbcmVwKGMoMSwyLDIsMSksdGltZXM9NCldCmBgYAoKKGFuIGFkbWl0dGVkbHkgdW5saWtlbHkgdGhpbmcgdG8gZG8pIHByb2R1Y2VzIGEgY2hhcmFjdGVyIHZlY3RvciBvZiBsZW5ndGggMTYgY29uc2lzdGluZyBvZiAieCIsICJ5IiwgInkiLCAieCIgcmVwZWF0ZWQgZm91ciB0aW1lcy4KCj4gMy4gX19BIHZlY3RvciBvZiBuZWdhdGl2ZSBpbnRlZ3JhbCBxdWFudGl0aWVzX18uIFN1Y2ggYW4gaW5kZXggdmVjdG9yIHNwZWNpZmllcyB0aGUgdmFsdWVzIHRvIGJlICpleGNsdWRlZCogcmF0aGVyIHRoYW4gaW5jbHVkZWQuIFRodXMKCjxkaXYgYWxpZ249ImNlbnRlciI+ICR5ID0geFstKDE6NSldJAoKZ2l2ZXMgKnkqIGFsbCBidXQgdGhlIGZpcnN0IGZpdmUgZWxlbWVudHMgb2YgKngqCjxkaXYgYWxpZ249ImxlZnQiPgpgYGB7cn0KeSA9IHhbLSgxOjUpXQp5CmBgYAoKU2luY2UgKngqIG9ubHkgY29uc2lzdHMgb2YgZml2ZSBlbGVtZW50cywgbm90aGluZyBpcyBwcm9kdWNlZC4KCj4gNC4gX19BIHZlY3RvciBvZiBjaGFyYWN0ZXIgc3RyaW5nc19fLiBUaGlzIHBvc3NpYmlsaXR5IG9ubHkgYXBwbGllcyB3aGVyZSBhbiBvYmplY3QgaGFzIGEgX19uYW1lc19fIGF0dHJpYnV0ZSB0byBpZGVudGlmeSBpdHMgY29tcG9uZW5ldHMuIEluIHRoaXMgY2FzZSBhIHN1Yi12ZWN0b3Igb2YgdGhlIG5hbWVzIHZlY3RvciBtYXkgYmUgdXNlZCBpbiB0aGUgc2FtZSB3YXkgYXMgdGhlIHBvc2l0aXZlIGludGVncmFsIGxhYmVscyBpbiBpdGVtIDIgZnVydGhlciBhYm92ZS4KCmBgYHtyfQpmcnVpdCA9IGMoNSwxMCwxLDIwKQpuYW1lcyhmcnVpdCkgPSBjKCJvcmFuZ2UiLCJiYW5hbmEiLCJhcHBsZSIsInBlYWNoIikKbHVuY2ggPSBmcnVpdFtjKCJhcHBsZSIsIm9yYW5nZSIpXQpgYGAKClRoZSBhZHZhbnRhZ2UgaXMgdGhhdCBhbHBoYW51bWVyaWMgKm5hbWVzKiBhcmUgb2Z0ZW4gZWFzaWVyIHRvIHJlbWVtYmVyIHRoYW4gKm51bWVyaWMgaW5kaWNlcyogVGhpcyBvcHRpb24gaXMgcGFydGljdWxhcmx5IHVzZWZ1bCBpbiBjb25uZWN0aW9uIHdpdGggZGF0YSBmcmFtZXMsIGFzIHdlIHNoYWxsIHNlZSBsYXRlci4KCj4gQW4gaW5kZXhlZCBleHByZXNzaW9uIGNhbiBhbHNvIGFwcGVhciBvbiB0aGUgcmVjZWl2aW5nIGVuZCBvZiBhbiBhc3NpZ25tZW50LCBpbiB3aGljaCBjYXNlIHRoZSBhc3NpZ25tZW50IG9wZXJhdGlvbiBpcyBwZXJmb3JtZWQgKm9ubHkgb24gdGhvc2UgZWxlbWVudHMgb2YgdGhlIHZlY3RvciouIFRoZSBleHByZXNzaW9uIG11c3QgYmUgb2YgdGhlIGZvcm0gX192ZWN0b3JbKmluZGV4X3ZlY3RvcipdX18gYXMgaGF2aW5nIGFuIGFyYml0cmFyeSBleHByZXNzaW9uIGluIHBsYWNlIG9mIHRoZSB2ZWN0b3IgbmFtZSBkb2VzIG5vdCBtYWtlIG11Y2ggc2Vuc2UgaGVyZS4KCkZvciBleGFtcGxlCgpgYGB7cn0KeFtpcy5uYSh4KV0gPSAwCngKYGBgCgpyZXBsYWNlcyBhbnkgbWlzc2luZyB2YWx1ZXMgaW4gKngqIGJ5IHplcm9zIGFuZAoKYGBge3J9CnlbeTwwXSA9IC15W3k8MF0KeQpgYGAKCmhhcyB0aGUgc2FtZSBlZmZlY3QgYXMKPGRpdiBhbGlnbj0iY2VudGVyIj4gJD55ID0gYWJzKHkpJCAKCiMjIDIuOCBPdGhlciB0eXBlcyBvZiBvYmplY3RzICMjCgpWZWN0b3JzIGFyZSB0aGUgbW9zdCBpbXBvcnRhbnQgdHlwZSBvZiBvYmplY3QgaW4gUiwgYnV0IHRoZXJlIGFyZSBzZXZlcmFsIG90aGVycyB3aGljaCB3ZSB3aWxsIG1lZXQgbW9yZSBmb3JtYWxseSBpbiBsYXRlciBzZWN0aW9ucy4KCiogKm1hdHJpY2VzKiBvciBtb3JlIGdlbmVyYWxseSAqYXJyYXlzKiBhcmUgbXVsdGktZGltZW5zaW5hbCBnZW5lcmFsaXphdGlvbnMgb2YgdmVjdG9ycy4gSW4gZmFjdCwgdGhleSAqYXJlKiB2ZWN0b3JzIHRoYXQgY2FuIGJlIGluZGV4ZWQgYnkgdHdvIG9yIG1vcmUgaW5kaWNlcyBhbmQgd2lsbCBiZSBwcmludGVkIGluIHNwZWNpYWwgd2F5cy4gCiogKmZhY3RvcnMqIHByb3ZpZGUgY29tcGFjdCB3YXlzIHRvIGhhbmRsZSBjYXRlZ29yaWNhbCBkYXRhLgoqICpsaXN0cyogYXJlIGEgZ2VuZXJhbCBmb3JtIG9mIHZlY3RvciBpbiB3aGljaCB0aGUgdmFyaW91cyBlbGVtZW50cyBuZWVkIG5vdCBiZSBvZiB0aGUgc2FtZSB0eXBlLCBhbmQgYXJlIG9mdGVuIHRoZW1zZWx2ZXMgdmVjdG9ycyBvciBsaXN0cy4gTGlzdHMgcHJvdmlkZSBhIGNvbnZlbmllbnQgd2F5IHRvIHJldHVybiB0aGUgcmVzdWx0cyBvZiBhIHN0YXRpc3RpY2FsIGNvbXB1dGF0aW9uLgoqICpkYXRhIGZyYW1lcyogYXJlIG1hdHJpeC1saWtlIHN0cnVjdHVyZXMsIGluIHdoaWNoIHRoZSBjb2x1bW5zIGNhbiBiZSBvZiBkaWZmZXJlbnQgdHlwZXMuIFRoaW5rIG9mIGRhdGEgZnJhbWVzIGFzICdkYXRhIG1hdHJpY2VzJyB3aXRoIG9uZSByb3cgcGVyIG9ic2VydmF0aW9uYWwgdW5pdCBidXQgd2l0aCAocG9zc2libHkpIGJvdGggbnVtZXJpY2FsIGFuZCBjYXRlZ29yaWNhbCB2YXJpYWJsZXMuIE1hbnkgZXhwZXJpbWVudHMgYXJlIGJlc3QgZGVzY3JpYmVkIGJ5IGRhdGEgZnJhbWVzOiB0aGUgdHJlYXRtZW50cyBhcmUgY2F0ZWdvcmljYWwgYnV0IHRoZSByZXNwb25zZSBpcyBudW1lcmljLgoqZnVuY3Rpb25zKiBhcmUgdGhlbXNlbHZlcyBvYmplY3RzIGluIFIgd2hpY2ggY2FuIGJlIHN0b3JlZCBpbiB0aGUgcHJvamVjdCdzIHdvcmtzcGFjZS4gVGhpcyBwcm92aWRlcyBhIHNpbXBsZSBhbmQgY29udmVuaWVudCB3YXkgdG8gZXh0ZW5kIFIuCgoKCgoKCgoKCgoK