Julius Schmid
Factors form the basis for many of R’s powerful operations, including
many of those performed on tabular data. The motivation for factors
comes from the notion of nominal, or categorical, variables in
statistics. These values are nonnumerical in nature, corresponding to
categories such as Democrat, Republican, and Unaffiliated, although they
may be coded using numbers.
Factors and Levels An R factor might be viewed
simply as a vector with a bit more information added (though, as seen
below, it’s different from this internally). That extra information
consists of a record of the distinct values in that vector, called
levels. Here’s an example:
x <- c(3,27,3,16,16,25)
xf <- factor(x)
xf
[1] 3 27 3 16 16 25
Levels: 3 16 25 27
The distinct values in xf — 3, 16, 25 and 27 — are the levels here.
Let’s take a look inside. For this, we use the structure function str().
If xf were a data frame, str() would return the number of rows and
columns, as well as the data type for each column. For a factor input,
on the other hand, str() returns the number of different levels and the
level names.
str(xf)
Factor w/ 4 levels "3","16","25",..: 1 4 1 2 2 3
In our case, we have 4 different levels: 3, 16, 25, and 27. The
numbers behind the levels indicate which to what level each component
belongs. Here, 1 belongs to level “3”, 2 belongs to “16”, 3 belongs to
“25”, and 4 belongs to “27”.
We get a similar output by applying the unclass() function. In fact,
for the factor xf str() and unclass() return the same values but in a
different order.
unclass(xf)
[1] 1 4 1 2 2 3
attr(,"levels")
[1] "3" "16" "25" "27"
Now let us return the length of xf. We might expect the length to be
4 since we have 4 factor levels.
length(xf)
[1] 6
The output is different from our expectation! The length is 6, which
means that duplicates are counted.
We can anticipate new future levels, as seen here:
x <- c(3,27,3,16,16,25)
xff <- factor(x,levels=c(3,16,25,27,59))
xff
[1] 3 27 3 16 16 25
Levels: 3 16 25 27 59
Here, we just added a new level namely 59. Even though 59 does not
appear as a component of x, we can still express that x may have
contained 59 because it is one of the possible levels.
Another possibility to add the level 59 is by setting the second
value in the factor xff to 59. The new level is added automatically.
This is done in the following code.
xff[2] <- 59
xff
[1] 3 59 3 16 16 25
Levels: 3 16 25 27 59
Originally, xff did not contain the value 59, but in defining it, we
allowed for that future possibility. Later, we did indeed add the
value.
Common Functions Used with Factors
With factors, we have yet another member of the family of apply
functions, tapply. We’ll look at that function, as well as two other
functions commonly used with factors: split() and by().
The operation performed by tapply() is to (temporarily) split x into
groups, each group corresponding to a level of the factor (or a
combination of levels of the factors in the case of multiple factors),
and then apply g() to the resulting subvectors of x. Here’s a little
example:
ages <- c(12,16,15,27,21,42,55)
affils <- c("U","D","U","R","R","D","D")
tapply(ages,affils,mean)
D R U
37.66667 24.00000 13.50000
Let’s look at what happened. The function tapply() treated the vector
(“U”,“D”,“U”,“R”,“R”,“D”) as a factor with levels “D”, “R”, and “U”. It
noted that “D” occurred in indices 2, 6, and 7; “R” occurred in indices
4 and 5; and “U” occurred in indices 1 and 3. For convenience, let’s
refer to the three index vectors (2,6,7), (4,5), and (1,3) as x, y, and
z, respectively. Then tapply() computed mean(u[x]), mean(u[y]), and
mean(u[z]) and returned those means in a three-element vector. And that
vector’s element names are “D”, “R”, and “U”, reflecting the factor
levels that were used by tapply().
What if we have two or more factors? Then each factor yields a set of
groups, as in the preceding example, and the groups are ANDed together.
As an example, suppose that we have an economic data set that includes
variables for gender, age, and income. Here, the call tapply(x,f,g)
might have x as income and f as a pair of factors: one for gender and
the other coding whether the person is older or younger than 25. We may
be interested in finding mean income, broken down by gender and age. If
we set g() to be mean(), tapply() will return the mean incomes in each
of four subgroups:
• Male and under 25 years old • Female and under 25 years old • Male
and over 25 years old • Female and over 25 years old
Let us create a data frame, containing dummy data with the variables
gender, age, and income.
d <- data.frame(list(gender=c("M","F","F","M","F","M"),age=c(47,32,21,32,48,24),income=c(55000,88000,32450,33000,123000,45650)))
Let us see what d looks like
d
We observe 6 rows, each containing data for gender, age, and income
for an individual person. In the next step, we create a fourth column
over25, which is boolean and returns 1 if the person is older than 25,
and 0 if not.
d$over25 <- ifelse(d$age > 25,1,0)
d
Only one woman (row 3) and one man (row 6) are not older than 25.
As mentioned above, we apply the tapply function to this data frame,
calculating the mean income for each of the four combinations that we
listed above (Male and under 25 years old, Female and under 25 years
old, Male and over 25 years old, Female and over 25 years old). That
means, that we calculate four different means:
tapply(d$income,list(d$gender,d$over25),mean)
0 1
F 32450 105500
M 45650 44000
Since there is only one row each for Fx0 and Mx0, these are just the
income values for row 3 and 6, respectively. Fx1 and Mx1 each calculate
the income mean of two individuals (rows 2 and 5 in the first case, and
rows 1 and 4 in the second case)
We specified two factors, gender and indicator variable for age over
or under 25. Since each of these factors has two levels, tapply()
partitioned the income data into four groups, one for each combination
of gender and age, and then applied to mean() function to each
group.
The split() Function
In contrast to tapply(), which splits a vector into groups and then
applies a specified function on each group, split() stops at that first
stage, just forming the groups. The basic form, without bells and
whistles, is split(x,f), with x and f playing roles similar to those in
the call tapply(x,f,g); that is, x being a vector or data frame and f
being a factor or a list of factors. The action is to split x into
groups, which are returned in a list. (Note that x is allowed to be a
data frame with split() but not with tapply().
Let’s try it out with our earlier example.
split(d$income,list(d$gender,d$over25))
$F.0
[1] 32450
$M.0
[1] 45650
$F.1
[1] 88000 123000
$M.1
[1] 55000 33000
The output of split() is a list, and recall that list components are
denoted by dollar signs. So the last vector, for example, was named
“M.1” to indicate that it was the result of combining “M” in the first
factor and 1 in the second.
As another illustration, consider our abalone example from previous
in class activitities (2.9.2). We wanted to determine the indices of the
vector elements corresponding to male, female, and infant. The data in
that little example consisted of the seven-observation vector
(“M”,“F”,“F”,“I”,“M”,“M”,“F”), assigned to g. We can do this in a flash
with split().
g <- c("M","F","F","I","M","M","F")
split(1:7,g)
$F
[1] 2 3 7
$I
[1] 4
$M
[1] 1 5 6
Let’s dissect this step-by-step. The vector g, taken as a factor, has
three levels: “M”, “F”, and “I”. The indices corresponding to the first
level are 1, 5, and 6, which means that g[1], g[5], and g[6] all have
the value “M”. So, R sets the M component of the output to elements 1,
5, and 6 of 1:7, which is the vector (1,5,6).
Working with Tables
To begin exploring R tables, consider this example:
u <- c(22,8,33,6,8,29,-2)
fl <- list(c(5,12,13,12,13,5,13),c("a","bc","a","a","bc","a","a"))
tapply(u,fl,length)
a bc
5 2 NA
12 1 1
13 2 1
Here, tapply() again temporarily breaks u into subvectors, as you saw
earlier,and then applies the length() function to each subvector. (Note
that this is independent of what’s in u. Our focus now is purely on the
factors.) Those subvector lengths are the counts of the occurrences of
each of the 3 × 2 = 6 combinations of the two factors. For instance, 5
occurred twice with “a” and not at all with “bc”; hence the entries 2
and NA in the first row of the output.In statistics, this is called a
contingency table.
There is one problem in this example: the NA value. It really should
be 0, meaning that in no cases did the first factor have level 5 and the
second have level “bc”. The table() function creates contingency tables
correctly.
table(fl)
fl.2
fl.1 a bc
5 2 0
12 1 1
13 2 1
The first argument in a call to table() is either a factor or a list
of factors. The two factors here were (5,12,13,12,13,5,13) and
(“a”,“bc”,“a”,“a”,“bc”,“a”,“a”). In this case, an object that is
interpretable as a factor is counted as one.
LS0tCnRpdGxlOiAiUiBGYWN0b3JzIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpKdWxpdXMgU2NobWlkCgpGYWN0b3JzIGZvcm0gdGhlIGJhc2lzIGZvciBtYW55IG9mIFLigJlzIHBvd2VyZnVsIG9wZXJhdGlvbnMsIGluY2x1ZGluZyBtYW55IG9mIHRob3NlIHBlcmZvcm1lZCBvbiB0YWJ1bGFyIGRhdGEuIFRoZSBtb3RpdmF0aW9uIGZvciBmYWN0b3JzIGNvbWVzIGZyb20gdGhlIG5vdGlvbiBvZiBub21pbmFsLCBvciBjYXRlZ29yaWNhbCwgdmFyaWFibGVzIGluIHN0YXRpc3RpY3MuIFRoZXNlIHZhbHVlcyBhcmUgbm9ubnVtZXJpY2FsIGluIG5hdHVyZSwgY29ycmVzcG9uZGluZyB0byBjYXRlZ29yaWVzIHN1Y2ggYXMgRGVtb2NyYXQsIFJlcHVibGljYW4sIGFuZCBVbmFmZmlsaWF0ZWQsIGFsdGhvdWdoIHRoZXkgbWF5IGJlIGNvZGVkIHVzaW5nIG51bWJlcnMuCgoKKipGYWN0b3JzIGFuZCBMZXZlbHMqKgpBbiBSIGZhY3RvciBtaWdodCBiZSB2aWV3ZWQgc2ltcGx5IGFzIGEgdmVjdG9yIHdpdGggYSBiaXQgbW9yZSBpbmZvcm1hdGlvbiBhZGRlZCAodGhvdWdoLCBhcyBzZWVuIGJlbG93LCBpdOKAmXMgZGlmZmVyZW50IGZyb20gdGhpcyBpbnRlcm5hbGx5KS4gVGhhdCBleHRyYSBpbmZvcm1hdGlvbiBjb25zaXN0cyBvZiBhIHJlY29yZCBvZiB0aGUgZGlzdGluY3QgdmFsdWVzIGluIHRoYXQgdmVjdG9yLCBjYWxsZWQgbGV2ZWxzLiBIZXJl4oCZcyBhbiBleGFtcGxlOgoKCmBgYHtyfQp4IDwtIGMoMywyNywzLDE2LDE2LDI1KQp4ZiA8LSBmYWN0b3IoeCkKeGYKYGBgClRoZSBkaXN0aW5jdCB2YWx1ZXMgaW4geGYg4oCUIDMsIDE2LCAyNSBhbmQgMjcg4oCUIGFyZSB0aGUgbGV2ZWxzIGhlcmUuIExldOKAmXMgdGFrZSBhIGxvb2sgaW5zaWRlLiBGb3IgdGhpcywgd2UgdXNlIHRoZSBzdHJ1Y3R1cmUgZnVuY3Rpb24gc3RyKCkuIElmIHhmIHdlcmUgYSBkYXRhIGZyYW1lLCBzdHIoKSB3b3VsZCByZXR1cm4gdGhlIG51bWJlciBvZiByb3dzIGFuZCBjb2x1bW5zLCBhcyB3ZWxsIGFzIHRoZSBkYXRhIHR5cGUgZm9yIGVhY2ggY29sdW1uLiBGb3IgYSBmYWN0b3IgaW5wdXQsIG9uIHRoZSBvdGhlciBoYW5kLCBzdHIoKSByZXR1cm5zIHRoZSBudW1iZXIgb2YgZGlmZmVyZW50IGxldmVscyBhbmQgdGhlIGxldmVsIG5hbWVzLgoKYGBge3J9CnN0cih4ZikKYGBgCkluIG91ciBjYXNlLCB3ZSBoYXZlIDQgZGlmZmVyZW50IGxldmVsczogMywgMTYsIDI1LCBhbmQgMjcuIFRoZSBudW1iZXJzIGJlaGluZCB0aGUgbGV2ZWxzIGluZGljYXRlIHdoaWNoICB0byB3aGF0IGxldmVsIGVhY2ggY29tcG9uZW50IGJlbG9uZ3MuIEhlcmUsIDEgYmVsb25ncyB0byBsZXZlbCAiMyIsIDIgYmVsb25ncyB0byAiMTYiLCAzIGJlbG9uZ3MgdG8gIjI1IiwgYW5kIDQgYmVsb25ncyB0byAiMjciLiAgCgoKV2UgZ2V0IGEgc2ltaWxhciBvdXRwdXQgYnkgYXBwbHlpbmcgdGhlIHVuY2xhc3MoKSBmdW5jdGlvbi4gSW4gZmFjdCwgZm9yIHRoZSBmYWN0b3IgeGYgc3RyKCkgYW5kIHVuY2xhc3MoKSByZXR1cm4gdGhlIHNhbWUgdmFsdWVzIGJ1dCBpbiBhIGRpZmZlcmVudCBvcmRlci4gCmBgYHtyfQp1bmNsYXNzKHhmKQpgYGAKCk5vdyBsZXQgdXMgcmV0dXJuIHRoZSBsZW5ndGggb2YgeGYuIFdlIG1pZ2h0IGV4cGVjdCB0aGUgbGVuZ3RoIHRvIGJlIDQgc2luY2Ugd2UgaGF2ZSA0IGZhY3RvciBsZXZlbHMuCmBgYHtyfQpsZW5ndGgoeGYpCmBgYApUaGUgb3V0cHV0IGlzIGRpZmZlcmVudCBmcm9tIG91ciBleHBlY3RhdGlvbiEgVGhlIGxlbmd0aCBpcyA2LCB3aGljaCBtZWFucyB0aGF0IGR1cGxpY2F0ZXMgYXJlIGNvdW50ZWQuIAoKV2UgY2FuIGFudGljaXBhdGUgbmV3IGZ1dHVyZSBsZXZlbHMsIGFzIHNlZW4gaGVyZToKCmBgYHtyfQp4IDwtIGMoMywyNywzLDE2LDE2LDI1KQp4ZmYgPC0gZmFjdG9yKHgsbGV2ZWxzPWMoMywxNiwyNSwyNyw1OSkpCnhmZgpgYGAKSGVyZSwgd2UganVzdCBhZGRlZCBhIG5ldyBsZXZlbCBuYW1lbHkgNTkuIEV2ZW4gdGhvdWdoIDU5IGRvZXMgbm90IGFwcGVhciBhcyBhIGNvbXBvbmVudCBvZiB4LCB3ZSBjYW4gc3RpbGwgZXhwcmVzcyB0aGF0IHggbWF5IGhhdmUgY29udGFpbmVkIDU5IGJlY2F1c2UgaXQgaXMgb25lIG9mIHRoZSBwb3NzaWJsZSBsZXZlbHMuIAoKQW5vdGhlciBwb3NzaWJpbGl0eSB0byBhZGQgdGhlIGxldmVsIDU5IGlzIGJ5IHNldHRpbmcgdGhlIHNlY29uZCB2YWx1ZSBpbiB0aGUgZmFjdG9yIHhmZiB0byA1OS4gVGhlIG5ldyBsZXZlbCBpcyBhZGRlZCBhdXRvbWF0aWNhbGx5LiBUaGlzIGlzIGRvbmUgaW4gdGhlIGZvbGxvd2luZyBjb2RlLiAKYGBge3J9CnhmZlsyXSA8LSA1OQp4ZmYKYGBgCgpPcmlnaW5hbGx5LCB4ZmYgZGlkIG5vdCBjb250YWluIHRoZSB2YWx1ZSA1OSwgYnV0IGluIGRlZmluaW5nIGl0LCB3ZSBhbGxvd2VkIGZvciB0aGF0IGZ1dHVyZSBwb3NzaWJpbGl0eS4gTGF0ZXIsIHdlIGRpZCBpbmRlZWQgYWRkIHRoZSB2YWx1ZS4KCioqQ29tbW9uIEZ1bmN0aW9ucyBVc2VkIHdpdGggRmFjdG9ycyAqKgoKV2l0aCBmYWN0b3JzLCB3ZSBoYXZlIHlldCBhbm90aGVyIG1lbWJlciBvZiB0aGUgZmFtaWx5IG9mIGFwcGx5IGZ1bmN0aW9ucywgdGFwcGx5LiBXZeKAmWxsIGxvb2sgYXQgdGhhdCBmdW5jdGlvbiwgYXMgd2VsbCBhcyB0d28gb3RoZXIgZnVuY3Rpb25zIGNvbW1vbmx5IHVzZWQgd2l0aCBmYWN0b3JzOiBzcGxpdCgpIGFuZCBieSgpLgoKVGhlIG9wZXJhdGlvbiBwZXJmb3JtZWQgYnkgdGFwcGx5KCkgaXMgdG8gKHRlbXBvcmFyaWx5KSBzcGxpdCB4IGludG8gZ3JvdXBzLCBlYWNoIGdyb3VwIGNvcnJlc3BvbmRpbmcgdG8gYSBsZXZlbCBvZiB0aGUgZmFjdG9yIChvciBhIGNvbWJpbmF0aW9uIG9mIGxldmVscyBvZiB0aGUgZmFjdG9ycyBpbiB0aGUgY2FzZSBvZiBtdWx0aXBsZSBmYWN0b3JzKSwgYW5kIHRoZW4gYXBwbHkgZygpIHRvIHRoZSByZXN1bHRpbmcgc3VidmVjdG9ycyBvZiB4LiBIZXJl4oCZcyBhIGxpdHRsZSBleGFtcGxlOgoKYGBge3J9CmFnZXMgPC0gYygxMiwxNiwxNSwyNywyMSw0Miw1NSkKYWZmaWxzIDwtIGMoIlUiLCJEIiwiVSIsIlIiLCJSIiwiRCIsIkQiKQp0YXBwbHkoYWdlcyxhZmZpbHMsbWVhbikKYGBgCgpMZXTigJlzIGxvb2sgYXQgd2hhdCBoYXBwZW5lZC4gVGhlIGZ1bmN0aW9uIHRhcHBseSgpIHRyZWF0ZWQgdGhlIHZlY3RvciAoIlUiLCJEIiwiVSIsIlIiLCJSIiwiRCIpIGFzIGEgZmFjdG9yIHdpdGggbGV2ZWxzICJEIiwgIlIiLCBhbmQgIlUiLiBJdCBub3RlZCB0aGF0ICJEIiBvY2N1cnJlZCBpbiBpbmRpY2VzIDIsIDYsIGFuZCA3OyAiUiIgb2NjdXJyZWQgaW4gaW5kaWNlcyA0IGFuZCA1OyBhbmQgIlUiIG9jY3VycmVkIGluIGluZGljZXMgMSBhbmQgMy4gRm9yIGNvbnZlbmllbmNlLCBsZXTigJlzIHJlZmVyIHRvIHRoZSB0aHJlZSBpbmRleCB2ZWN0b3JzICgyLDYsNyksICg0LDUpLCBhbmQgKDEsMykgYXMgeCwgeSwgYW5kIHosIHJlc3BlY3RpdmVseS4gVGhlbiB0YXBwbHkoKSBjb21wdXRlZCBtZWFuKHVbeF0pLCBtZWFuKHVbeV0pLCBhbmQgbWVhbih1W3pdKSBhbmQgcmV0dXJuZWQgdGhvc2UgbWVhbnMgaW4gYSB0aHJlZS1lbGVtZW50IHZlY3Rvci4gQW5kIHRoYXQgdmVjdG9y4oCZcyBlbGVtZW50IG5hbWVzIGFyZSAiRCIsICJSIiwgYW5kICJVIiwgcmVmbGVjdGluZyB0aGUgZmFjdG9yIGxldmVscyB0aGF0IHdlcmUgdXNlZCBieSB0YXBwbHkoKS4KCldoYXQgaWYgd2UgaGF2ZSB0d28gb3IgbW9yZSBmYWN0b3JzPyBUaGVuIGVhY2ggZmFjdG9yIHlpZWxkcyBhIHNldCBvZiBncm91cHMsIGFzIGluIHRoZSBwcmVjZWRpbmcgZXhhbXBsZSwgYW5kIHRoZSBncm91cHMgYXJlIEFORGVkIHRvZ2V0aGVyLiBBcyBhbiBleGFtcGxlLCBzdXBwb3NlIHRoYXQgd2UgaGF2ZSBhbiBlY29ub21pYyBkYXRhIHNldCB0aGF0IGluY2x1ZGVzIHZhcmlhYmxlcyBmb3IgZ2VuZGVyLCBhZ2UsIGFuZCBpbmNvbWUuIEhlcmUsIHRoZSBjYWxsIHRhcHBseSh4LGYsZykgbWlnaHQgaGF2ZSB4IGFzIGluY29tZSBhbmQgZiBhcyBhIHBhaXIgb2YgZmFjdG9yczogb25lIGZvciBnZW5kZXIgYW5kIHRoZSBvdGhlciBjb2Rpbmcgd2hldGhlciB0aGUgcGVyc29uIGlzIG9sZGVyIG9yIHlvdW5nZXIgdGhhbiAyNS4gV2UgbWF5IGJlIGludGVyZXN0ZWQgaW4gZmluZGluZyBtZWFuIGluY29tZSwgYnJva2VuIGRvd24gYnkgZ2VuZGVyIGFuZCBhZ2UuIElmIHdlIHNldCBnKCkgdG8gYmUgbWVhbigpLCB0YXBwbHkoKSB3aWxsIHJldHVybiB0aGUgbWVhbiBpbmNvbWVzIGluIGVhY2ggb2YgZm91ciBzdWJncm91cHM6CgrigKIgTWFsZSBhbmQgdW5kZXIgMjUgeWVhcnMgb2xkCuKAoiBGZW1hbGUgYW5kIHVuZGVyIDI1IHllYXJzIG9sZArigKIgTWFsZSBhbmQgb3ZlciAyNSB5ZWFycyBvbGQK4oCiIEZlbWFsZSBhbmQgb3ZlciAyNSB5ZWFycyBvbGQKCgpMZXQgdXMgY3JlYXRlIGEgZGF0YSBmcmFtZSwgY29udGFpbmluZyBkdW1teSBkYXRhIHdpdGggdGhlIHZhcmlhYmxlcyBnZW5kZXIsIGFnZSwgYW5kIGluY29tZS4KYGBge3J9CmQgPC0gZGF0YS5mcmFtZShsaXN0KGdlbmRlcj1jKCJNIiwiRiIsIkYiLCJNIiwiRiIsIk0iKSxhZ2U9Yyg0NywzMiwyMSwzMiw0OCwyNCksaW5jb21lPWMoNTUwMDAsODgwMDAsMzI0NTAsMzMwMDAsMTIzMDAwLDQ1NjUwKSkpCmBgYAoKTGV0IHVzIHNlZSB3aGF0IGQgbG9va3MgbGlrZQpgYGB7cn0KZApgYGAKV2Ugb2JzZXJ2ZSA2IHJvd3MsIGVhY2ggY29udGFpbmluZyBkYXRhIGZvciBnZW5kZXIsIGFnZSwgYW5kIGluY29tZSBmb3IgYW4gaW5kaXZpZHVhbCBwZXJzb24uIEluIHRoZSBuZXh0IHN0ZXAsIHdlIGNyZWF0ZSBhIGZvdXJ0aCBjb2x1bW4gb3ZlcjI1LCB3aGljaCBpcyBib29sZWFuIGFuZCByZXR1cm5zIDEgaWYgdGhlIHBlcnNvbiBpcyBvbGRlciB0aGFuIDI1LCBhbmQgMCBpZiBub3QuCmBgYHtyfQpkJG92ZXIyNSA8LSBpZmVsc2UoZCRhZ2UgPiAyNSwxLDApCmQKYGBgCk9ubHkgb25lIHdvbWFuIChyb3cgMykgYW5kIG9uZSBtYW4gKHJvdyA2KSBhcmUgbm90IG9sZGVyIHRoYW4gMjUuCgpBcyBtZW50aW9uZWQgYWJvdmUsIHdlIGFwcGx5IHRoZSB0YXBwbHkgZnVuY3Rpb24gdG8gdGhpcyBkYXRhIGZyYW1lLCBjYWxjdWxhdGluZyB0aGUgbWVhbiBpbmNvbWUgZm9yIGVhY2ggb2YgdGhlIGZvdXIgY29tYmluYXRpb25zIHRoYXQgd2UgbGlzdGVkIGFib3ZlIChNYWxlIGFuZCB1bmRlciAyNSB5ZWFycyBvbGQsIEZlbWFsZSBhbmQgdW5kZXIgMjUgeWVhcnMgb2xkLCBNYWxlIGFuZCBvdmVyIDI1IHllYXJzIG9sZCwgRmVtYWxlIGFuZCBvdmVyIDI1IHllYXJzIG9sZCkuIFRoYXQgbWVhbnMsIHRoYXQgd2UgY2FsY3VsYXRlIGZvdXIgZGlmZmVyZW50IG1lYW5zOgpgYGB7cn0KdGFwcGx5KGQkaW5jb21lLGxpc3QoZCRnZW5kZXIsZCRvdmVyMjUpLG1lYW4pCmBgYApTaW5jZSB0aGVyZSBpcyBvbmx5IG9uZSByb3cgZWFjaCBmb3IgRngwIGFuZCBNeDAsIHRoZXNlIGFyZSBqdXN0IHRoZSBpbmNvbWUgdmFsdWVzIGZvciByb3cgMyBhbmQgNiwgcmVzcGVjdGl2ZWx5LiBGeDEgYW5kIE14MSBlYWNoIGNhbGN1bGF0ZSB0aGUgaW5jb21lIG1lYW4gb2YgdHdvIGluZGl2aWR1YWxzIChyb3dzIDIgYW5kIDUgaW4gdGhlIGZpcnN0IGNhc2UsIGFuZCByb3dzIDEgYW5kIDQgaW4gdGhlIHNlY29uZCBjYXNlKSAKCldlIHNwZWNpZmllZCB0d28gZmFjdG9ycywgZ2VuZGVyIGFuZCBpbmRpY2F0b3IgdmFyaWFibGUgZm9yIGFnZSBvdmVyIG9yIHVuZGVyIDI1LiBTaW5jZSBlYWNoIG9mIHRoZXNlIGZhY3RvcnMgaGFzIHR3byBsZXZlbHMsIHRhcHBseSgpIHBhcnRpdGlvbmVkIHRoZSBpbmNvbWUgZGF0YSBpbnRvIGZvdXIgZ3JvdXBzLCBvbmUgZm9yIGVhY2ggY29tYmluYXRpb24gb2YgZ2VuZGVyIGFuZCBhZ2UsIGFuZCB0aGVuIGFwcGxpZWQgdG8gbWVhbigpIGZ1bmN0aW9uIHRvIGVhY2ggZ3JvdXAuCgoKKipUaGUgc3BsaXQoKSBGdW5jdGlvbioqCgpJbiBjb250cmFzdCB0byB0YXBwbHkoKSwgd2hpY2ggc3BsaXRzIGEgdmVjdG9yIGludG8gZ3JvdXBzIGFuZCB0aGVuIGFwcGxpZXMgYSBzcGVjaWZpZWQgZnVuY3Rpb24gb24gZWFjaCBncm91cCwgc3BsaXQoKSBzdG9wcyBhdCB0aGF0IGZpcnN0IHN0YWdlLCBqdXN0IGZvcm1pbmcgdGhlIGdyb3Vwcy4gVGhlIGJhc2ljIGZvcm0sIHdpdGhvdXQgYmVsbHMgYW5kIHdoaXN0bGVzLCBpcyBzcGxpdCh4LGYpLCB3aXRoIHggYW5kIGYgcGxheWluZyByb2xlcyBzaW1pbGFyIHRvIHRob3NlIGluIHRoZSBjYWxsIHRhcHBseSh4LGYsZyk7IHRoYXQgaXMsIHggYmVpbmcgYSB2ZWN0b3Igb3IgZGF0YSBmcmFtZSBhbmQgZiBiZWluZyBhIGZhY3RvciBvciBhIGxpc3Qgb2YgZmFjdG9ycy4gVGhlIGFjdGlvbiBpcyB0byBzcGxpdCB4IGludG8gZ3JvdXBzLCB3aGljaCBhcmUgcmV0dXJuZWQgaW4gYSBsaXN0LiAoTm90ZSB0aGF0IHggaXMgYWxsb3dlZCB0byBiZSBhIGRhdGEgZnJhbWUgd2l0aCBzcGxpdCgpIGJ1dCBub3Qgd2l0aCB0YXBwbHkoKS4KCkxldOKAmXMgdHJ5IGl0IG91dCB3aXRoIG91ciBlYXJsaWVyIGV4YW1wbGUuCmBgYHtyfQpzcGxpdChkJGluY29tZSxsaXN0KGQkZ2VuZGVyLGQkb3ZlcjI1KSkKYGBgCgpUaGUgb3V0cHV0IG9mIHNwbGl0KCkgaXMgYSBsaXN0LCBhbmQgcmVjYWxsIHRoYXQgbGlzdCBjb21wb25lbnRzIGFyZSBkZW5vdGVkIGJ5IGRvbGxhciBzaWducy4gU28gdGhlIGxhc3QgdmVjdG9yLCBmb3IgZXhhbXBsZSwgd2FzIG5hbWVkICJNLjEiIHRvIGluZGljYXRlIHRoYXQgaXQgd2FzIHRoZSByZXN1bHQgb2YgY29tYmluaW5nICJNIiBpbiB0aGUgZmlyc3QgZmFjdG9yIGFuZCAxIGluIHRoZSBzZWNvbmQuIAoKQXMgYW5vdGhlciBpbGx1c3RyYXRpb24sIGNvbnNpZGVyIG91ciBhYmFsb25lIGV4YW1wbGUgZnJvbSBwcmV2aW91cyBpbiBjbGFzcyBhY3Rpdml0aXRpZXMgKDIuOS4yKS4gIFdlIHdhbnRlZCB0byBkZXRlcm1pbmUgdGhlIGluZGljZXMgb2YgdGhlIHZlY3RvciBlbGVtZW50cyBjb3JyZXNwb25kaW5nIHRvIG1hbGUsIGZlbWFsZSwgYW5kIGluZmFudC4gVGhlIGRhdGEgaW4gdGhhdCBsaXR0bGUgZXhhbXBsZSBjb25zaXN0ZWQgb2YgdGhlIHNldmVuLW9ic2VydmF0aW9uIHZlY3RvciAoIk0iLCJGIiwiRiIsIkkiLCJNIiwiTSIsIkYiKSwgYXNzaWduZWQgdG8gZy4gV2UgY2FuIGRvIHRoaXMgaW4gYSBmbGFzaCB3aXRoIHNwbGl0KCkuCgoKYGBge3J9CmcgPC0gYygiTSIsIkYiLCJGIiwiSSIsIk0iLCJNIiwiRiIpCnNwbGl0KDE6NyxnKQpgYGAKCkxldOKAmXMgZGlzc2VjdCB0aGlzIHN0ZXAtYnktc3RlcC4gVGhlIHZlY3RvciBnLCB0YWtlbiBhcyBhIGZhY3RvciwgaGFzIHRocmVlIGxldmVsczogIk0iLCAiRiIsIGFuZCAiSSIuIFRoZSBpbmRpY2VzIGNvcnJlc3BvbmRpbmcgdG8gdGhlIGZpcnN0IGxldmVsIGFyZSAxLCA1LCBhbmQgNiwgd2hpY2ggbWVhbnMgdGhhdCBnWzFdLCBnWzVdLCBhbmQgZ1s2XSBhbGwgaGF2ZSB0aGUgdmFsdWUgIk0iLiBTbywgUiBzZXRzCnRoZSBNIGNvbXBvbmVudCBvZiB0aGUgb3V0cHV0IHRvIGVsZW1lbnRzIDEsIDUsIGFuZCA2IG9mIDE6Nywgd2hpY2ggaXMgdGhlIHZlY3RvciAoMSw1LDYpLgoKKipXb3JraW5nIHdpdGggVGFibGVzKioKClRvIGJlZ2luIGV4cGxvcmluZyBSIHRhYmxlcywgY29uc2lkZXIgdGhpcyBleGFtcGxlOgpgYGB7cn0KdSA8LSBjKDIyLDgsMzMsNiw4LDI5LC0yKQpmbCA8LSBsaXN0KGMoNSwxMiwxMywxMiwxMyw1LDEzKSxjKCJhIiwiYmMiLCJhIiwiYSIsImJjIiwiYSIsImEiKSkKdGFwcGx5KHUsZmwsbGVuZ3RoKQpgYGAKCkhlcmUsIHRhcHBseSgpIGFnYWluIHRlbXBvcmFyaWx5IGJyZWFrcyB1IGludG8gc3VidmVjdG9ycywgYXMgeW91IHNhdyBlYXJsaWVyLGFuZCB0aGVuIGFwcGxpZXMgdGhlIGxlbmd0aCgpIGZ1bmN0aW9uIHRvIGVhY2ggc3VidmVjdG9yLiAoTm90ZSB0aGF0IHRoaXMgaXMgaW5kZXBlbmRlbnQgb2Ygd2hhdOKAmXMgaW4gdS4gT3VyIGZvY3VzIG5vdyBpcyBwdXJlbHkgb24gdGhlIGZhY3RvcnMuKSBUaG9zZSBzdWJ2ZWN0b3IgbGVuZ3RocyBhcmUgdGhlIGNvdW50cyBvZiB0aGUgb2NjdXJyZW5jZXMgb2YgZWFjaCBvZiB0aGUgMyDDlyAyID0gNiBjb21iaW5hdGlvbnMgb2YgdGhlIHR3byBmYWN0b3JzLiBGb3IgaW5zdGFuY2UsIDUgb2NjdXJyZWQgdHdpY2Ugd2l0aCAiYSIgYW5kIG5vdCBhdCBhbGwgd2l0aCAiYmMiOyBoZW5jZSB0aGUgZW50cmllcyAyIGFuZCBOQSBpbiB0aGUgZmlyc3Qgcm93IG9mIHRoZSBvdXRwdXQuSW4gc3RhdGlzdGljcywgdGhpcyBpcyBjYWxsZWQgYSBjb250aW5nZW5jeSB0YWJsZS4KClRoZXJlIGlzIG9uZSBwcm9ibGVtIGluIHRoaXMgZXhhbXBsZTogdGhlIE5BIHZhbHVlLiBJdCByZWFsbHkgc2hvdWxkIGJlIDAsIG1lYW5pbmcgdGhhdCBpbiBubyBjYXNlcyBkaWQgdGhlIGZpcnN0IGZhY3RvciBoYXZlIGxldmVsIDUgYW5kIHRoZSBzZWNvbmQgaGF2ZSBsZXZlbCAiYmMiLiBUaGUgdGFibGUoKSBmdW5jdGlvbiBjcmVhdGVzIGNvbnRpbmdlbmN5IHRhYmxlcyBjb3JyZWN0bHkuCgpgYGB7cn0KdGFibGUoZmwpCmBgYApUaGUgZmlyc3QgYXJndW1lbnQgaW4gYSBjYWxsIHRvIHRhYmxlKCkgaXMgZWl0aGVyIGEgZmFjdG9yIG9yIGEgbGlzdCBvZiBmYWN0b3JzLiBUaGUgdHdvIGZhY3RvcnMgaGVyZSB3ZXJlICg1LDEyLDEzLDEyLDEzLDUsMTMpIGFuZCAoImEiLCJiYyIsImEiLCJhIiwiYmMiLCJhIiwiYSIpLiBJbiB0aGlzIGNhc2UsIGFuIG9iamVjdCB0aGF0IGlzIGludGVycHJldGFibGUgYXMgYSBmYWN0b3IgaXMgY291bnRlZCBhcyBvbmUuCgo=