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 vector has been created then vector X has been transformed into a factor named xf.

x <- c(7,23,7,15,7)
xf <- factor(x)
xf
[1] 7  23 7  15 7 
Levels: 7 15 23

As could be seen above there are 3 levels which are the factors, in this case 7,15 and 23. Value 7 is repeated 3 times.

str(xf)
 Factor w/ 3 levels "7","15","23": 1 3 1 2 1

unclass() function returns its argument with its class attribute removed

unclass(xf)
[1] 1 3 1 2 1
attr(,"levels")
[1] "7"  "15" "23"

The factor has 5 elements

length(xf)
[1] 5

New levels can be added to the factor even if the vector does not have this variable yet. In this case factor has level 67 but vetor does not.

x <- c(7,23,7,15,7)
xff <- factor(x,levels=c(7,23,15,67))
xff
[1] 7  23 7  15 7 
Levels: 7 23 15 67

Adding variable 67 to the vector

xff[3] <- 67
x
[1]  7 23  7 15  7

Originally, xff did not contain the value 67, 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(30,77,12,15,24,39)
affils <- c("J","A","J","A","J","P")
tapply(ages,affils,mean)
 A  J  P 
46 22 39 

Tapply() function uses affils vector as a factor with levels “J”, “A” and “P”. Then, numerical values of vector ages has been attributed to it corresponding level of factor affils.In this example “J” occurred in indices 1, 3 and 5; “A” occurred in indices 2 and 4 and “P” in 6.

I three index vectors are refereed as (2,3,6), (1,4), and (5) 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 “J”, “A”, and “P”, 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

d <- data.frame(list(gender=c("M","M","F","M","F","F"),age=c(47,59,21,32,33,24),income=c(55000,88000,32450,76500,123000,45650)))
d
d$over25 <- ifelse(d$age > 25,1,0)
d
tapply(d$income,list(d$gender,d$over25),mean)
      0         1
F 39050 123000.00
M    NA  73166.67

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.

My Example

My example with more than 2 factors. In this case variables are going to be size, color and prices of T-shirts in a store. Here, the call tapply(x,f,g) might have x as income and f as a pair of factors: one for size and the other coding whether the T-shirt is cheaper or more expensive than 50$. We may be interested in finding mean price, broken down by size and color. If we set g() to be mean(), tapply() will return the mean incomes in each of four subgroups:

• Size L and under 50$ • Size M and under 50$ • Size L and over 50$ • SIze M and over 50$

tshirt <- data.frame(list(size=c("M","L","L","L","S","M"),coolor=c("red","red","blue","purple","purple","purple"),price=c(55,86,33,45,78,20)))

Data frame as been created with color size and price of tshirts in a shop.

tshirt

Lets show the t shirts that costs less than 50$

tshirt$lower50 <- ifelse(d$price < 50,1,0)
Error in `$<-.data.frame`(`*tmp*`, lower50, value = logical(0)) : 
  replacement has 0 rows, data has 6
tapply(tshirt$price,list(tshirt$coolor,tshirt$lower50),mean)
          0    1
blue     NA 33.0
purple 78.0 32.5
red    70.5   NA

Mean values of prices for blue, purple and red t shirts. 0 correspond to the shirts which values is grater than 50dollars while 1 correspond to the shirt which values is lower than 50dollars

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 45650

$M.0
numeric(0)

$F.1
[1] 123000

$M.1
[1] 55000 88000 76500

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.

Indices of the vector elements corresponding to male, female, and infant wanted to be determined. In this example “Female” occurred in indices 2, 3 and 7; “Male” occurred in indices 1, 5 and 6 and “Infant” in 4.

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

My Example, split() function

Function split() outputs the price of each kind of shirt with the condition of being cheaper or more expensive than 50 dollars. For example there is no blue shirt that costs more than 50dollars but there is one which price is 33dollars.

split(tshirt$price,list(tshirt$coolor,tshirt$lower50))
$blue.0
numeric(0)

$purple.0
[1] 78

$red.0
[1] 55 86

$blue.1
[1] 33

$purple.1
[1] 45 20

$red.1
numeric(0)

Working with Tables

To begin exploring R tables, consider this example:

p <- c(66,90,3,56,0,9,-6)
fl <- list(c(7,14,33,33,7,14,33),c("k","j","j","j","k","j","j"))
tapply(p,fl,length)
    j  k
7  NA  2
14  2 NA
33  3 NA

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 p. 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, 7 occurred twice with “k” and not at all with “j”; 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 “j”. The table() function creates contingency tables correctly.

table(fl)
    fl.2
fl.1 j k
  7  0 2
  14 2 0
  33 3 0

The first argument in a call to table() is either a factor or a list of factors. The two factors here were (7,14,33,33,7,14,33) and (“k”,“j”,“j”,“j”,“k”,“j”,“j”). In this case, an object that is interpretable as a factor is counted as one.

LS0tDQp0aXRsZTogIlIgRmFjdG9ycyINCmF1dGhvcjogIlJhdWwgUm9jZXMiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQoNCkZhY3RvcnMgZm9ybSB0aGUgYmFzaXMgZm9yIG1hbnkgb2YgUuKAmXMgcG93ZXJmdWwgb3BlcmF0aW9ucywgaW5jbHVkaW5nIG1hbnkgb2YgdGhvc2UgcGVyZm9ybWVkIG9uIHRhYnVsYXIgZGF0YS4gVGhlIG1vdGl2YXRpb24gZm9yIGZhY3RvcnMgY29tZXMgZnJvbSB0aGUgbm90aW9uIG9mIG5vbWluYWwsIG9yIGNhdGVnb3JpY2FsLCB2YXJpYWJsZXMgaW4gc3RhdGlzdGljcy4gVGhlc2UgdmFsdWVzIGFyZSBub25udW1lcmljYWwgaW4gbmF0dXJlLCBjb3JyZXNwb25kaW5nIHRvIGNhdGVnb3JpZXMgc3VjaCBhcyBEZW1vY3JhdCwgUmVwdWJsaWNhbiwgYW5kIFVuYWZmaWxpYXRlZCwgYWx0aG91Z2ggdGhleSBtYXkgYmUgY29kZWQgdXNpbmcgbnVtYmVycy4NCg0KDQoqKkZhY3RvcnMgYW5kIExldmVscyoqDQpBbiBSIGZhY3RvciBtaWdodCBiZSB2aWV3ZWQgc2ltcGx5IGFzIGEgdmVjdG9yIHdpdGggYSBiaXQgbW9yZSBpbmZvcm1hdGlvbiBhZGRlZCAodGhvdWdoLCBhcyBzZWVuIGJlbG93LCBpdOKAmXMgZGlmZmVyZW50IGZyb20gdGhpcyBpbnRlcm5hbGx5KS4gVGhhdCBleHRyYSBpbmZvcm1hdGlvbiBjb25zaXN0cyBvZiBhIHJlY29yZCBvZiB0aGUgZGlzdGluY3QgdmFsdWVzIGluIHRoYXQgdmVjdG9yLCBjYWxsZWQgbGV2ZWxzLiBIZXJl4oCZcyBhbiBleGFtcGxlOg0KDQpYIHZlY3RvciBoYXMgYmVlbiBjcmVhdGVkIHRoZW4gdmVjdG9yIFggaGFzIGJlZW4gdHJhbnNmb3JtZWQgaW50byBhIGZhY3RvciBuYW1lZCB4Zi4gDQpgYGB7cn0NCnggPC0gYyg3LDIzLDcsMTUsNykNCnhmIDwtIGZhY3Rvcih4KQ0KeGYNCmBgYA0KQXMgY291bGQgYmUgc2VlbiBhYm92ZSB0aGVyZSBhcmUgMyBsZXZlbHMgd2hpY2ggYXJlIHRoZSBmYWN0b3JzLCBpbiB0aGlzIGNhc2UgNywxNSBhbmQgMjMuIFZhbHVlIDcgaXMgcmVwZWF0ZWQgMyB0aW1lcy4NCg0KYGBge3J9DQpzdHIoeGYpDQpgYGANCg0KDQp1bmNsYXNzKCkgZnVuY3Rpb24gcmV0dXJucyBpdHMgYXJndW1lbnQgd2l0aCBpdHMgY2xhc3MgYXR0cmlidXRlIHJlbW92ZWQNCmBgYHtyfQ0KdW5jbGFzcyh4ZikNCmBgYA0KDQoNClRoZSBmYWN0b3IgaGFzIDUgZWxlbWVudHMNCmBgYHtyfQ0KbGVuZ3RoKHhmKQ0KYGBgDQoNCk5ldyBsZXZlbHMgY2FuIGJlIGFkZGVkIHRvIHRoZSBmYWN0b3IgZXZlbiBpZiB0aGUgdmVjdG9yIGRvZXMgbm90IGhhdmUgdGhpcyB2YXJpYWJsZSB5ZXQuDQpJbiB0aGlzIGNhc2UgZmFjdG9yIGhhcyBsZXZlbCA2NyBidXQgdmV0b3IgZG9lcyBub3QuDQpgYGB7cn0NCnggPC0gYyg3LDIzLDcsMTUsNykNCnhmZiA8LSBmYWN0b3IoeCxsZXZlbHM9Yyg3LDIzLDE1LDY3KSkNCnhmZg0KYGBgDQoNCg0KQWRkaW5nIHZhcmlhYmxlIDY3IHRvIHRoZSB2ZWN0b3INCmBgYHtyfQ0KeGZmWzNdIDwtIDY3DQp4DQpgYGANCk9yaWdpbmFsbHksIHhmZiBkaWQgbm90IGNvbnRhaW4gdGhlIHZhbHVlIDY3LCBidXQgaW4gZGVmaW5pbmcgaXQsIHdlIGFsbG93ZWQgZm9yIHRoYXQgZnV0dXJlIHBvc3NpYmlsaXR5LiBMYXRlciwgd2UgZGlkIGluZGVlZCBhZGQgdGhlIHZhbHVlLg0KDQoqKkNvbW1vbiBGdW5jdGlvbnMgVXNlZCB3aXRoIEZhY3RvcnMgKioNCg0KV2l0aCBmYWN0b3JzLCB3ZSBoYXZlIHlldCBhbm90aGVyIG1lbWJlciBvZiB0aGUgZmFtaWx5IG9mIGFwcGx5IGZ1bmN0aW9ucywgdGFwcGx5LiBXZeKAmWxsIGxvb2sgYXQgdGhhdCBmdW5jdGlvbiwgYXMgd2VsbCBhcyB0d28gb3RoZXIgZnVuY3Rpb25zIGNvbW1vbmx5IHVzZWQgd2l0aCBmYWN0b3JzOiBzcGxpdCgpIGFuZCBieSgpLg0KDQpUaGUgb3BlcmF0aW9uIHBlcmZvcm1lZCBieSB0YXBwbHkoKSBpcyB0byAodGVtcG9yYXJpbHkpIHNwbGl0IHggaW50byBncm91cHMsIGVhY2ggZ3JvdXAgY29ycmVzcG9uZGluZyB0byBhIGxldmVsIG9mIHRoZSBmYWN0b3IgKG9yIGEgY29tYmluYXRpb24gb2YgbGV2ZWxzIG9mIHRoZSBmYWN0b3JzIGluIHRoZSBjYXNlIG9mIG11bHRpcGxlIGZhY3RvcnMpLCBhbmQgdGhlbiBhcHBseSBnKCkgdG8gdGhlIHJlc3VsdGluZyBzdWJ2ZWN0b3JzIG9mIHguIEhlcmXigJlzIGEgbGl0dGxlIGV4YW1wbGU6DQoNCmBgYHtyfQ0KYWdlcyA8LSBjKDMwLDc3LDEyLDE1LDI0LDM5KQ0KYWZmaWxzIDwtIGMoIkoiLCJBIiwiSiIsIkEiLCJKIiwiUCIpDQp0YXBwbHkoYWdlcyxhZmZpbHMsbWVhbikNCmBgYA0KVGFwcGx5KCkgZnVuY3Rpb24gdXNlcyBhZmZpbHMgdmVjdG9yIGFzIGEgZmFjdG9yIHdpdGggbGV2ZWxzICJKIiwgIkEiIGFuZCAiUCIuIFRoZW4sIG51bWVyaWNhbCB2YWx1ZXMgb2YgdmVjdG9yIGFnZXMgaGFzIGJlZW4gYXR0cmlidXRlZCB0byBpdCBjb3JyZXNwb25kaW5nIGxldmVsIG9mIGZhY3RvciBhZmZpbHMuSW4gdGhpcyBleGFtcGxlICJKIiBvY2N1cnJlZCBpbiBpbmRpY2VzIDEsIDMgYW5kIDU7ICJBIiBvY2N1cnJlZCBpbiBpbmRpY2VzIDIgYW5kIDQgYW5kICJQIiBpbiA2Lg0KDQpJIHRocmVlIGluZGV4IHZlY3RvcnMgYXJlIHJlZmVyZWVkIGFzICgyLDMsNiksICgxLDQpLCBhbmQgKDUpIGFzIHgsIHksIGFuZCB6LCByZXNwZWN0aXZlbHkuIFRoZW4gdGFwcGx5KCkgY29tcHV0ZWQgbWVhbih1W3hdKSwgbWVhbih1W3ldKSwgYW5kIG1lYW4odVt6XSkgYW5kIHJldHVybmVkIHRob3NlIG1lYW5zIGluIGEgdGhyZWUtZWxlbWVudCB2ZWN0b3IuIEFuZCB0aGF0IHZlY3RvcuKAmXMgZWxlbWVudCBuYW1lcyBhcmUgIkoiLCAiQSIsIGFuZCAiUCIsIHJlZmxlY3RpbmcgdGhlIGZhY3RvciBsZXZlbHMgdGhhdCB3ZXJlIHVzZWQgYnkgdGFwcGx5KCkuDQoNCldoYXQgaWYgd2UgaGF2ZSB0d28gb3IgbW9yZSBmYWN0b3JzPyBUaGVuIGVhY2ggZmFjdG9yIHlpZWxkcyBhIHNldCBvZiBncm91cHMsIGFzIGluIHRoZSBwcmVjZWRpbmcgZXhhbXBsZSwgYW5kIHRoZSBncm91cHMgYXJlIEFORGVkIHRvZ2V0aGVyLiBBcyBhbiBleGFtcGxlLCBzdXBwb3NlIHRoYXQgd2UgaGF2ZSBhbiBlY29ub21pYyBkYXRhIHNldCB0aGF0IGluY2x1ZGVzIHZhcmlhYmxlcyBmb3IgZ2VuZGVyLCBhZ2UsIGFuZCBpbmNvbWUuIEhlcmUsIHRoZSBjYWxsIHRhcHBseSh4LGYsZykgbWlnaHQgaGF2ZSB4IGFzIGluY29tZSBhbmQgZiBhcyBhIHBhaXIgb2YgZmFjdG9yczogb25lIGZvciBnZW5kZXIgYW5kIHRoZSBvdGhlciBjb2Rpbmcgd2hldGhlciB0aGUgcGVyc29uIGlzIG9sZGVyIG9yIHlvdW5nZXIgdGhhbiAyNS4gV2UgbWF5IGJlIGludGVyZXN0ZWQgaW4gZmluZGluZyBtZWFuIGluY29tZSwgYnJva2VuIGRvd24gYnkgZ2VuZGVyIGFuZCBhZ2UuIElmIHdlIHNldCBnKCkgdG8gYmUgbWVhbigpLCB0YXBwbHkoKSB3aWxsIHJldHVybiB0aGUgbWVhbiBpbmNvbWVzIGluIGVhY2ggb2YgZm91ciBzdWJncm91cHM6DQoNCuKAoiBNYWxlIGFuZCB1bmRlciAyNSB5ZWFycyBvbGQNCuKAoiBGZW1hbGUgYW5kIHVuZGVyIDI1IHllYXJzIG9sZA0K4oCiIE1hbGUgYW5kIG92ZXIgMjUgeWVhcnMgb2xkDQrigKIgRmVtYWxlIGFuZCBvdmVyIDI1IHllYXJzIG9sZA0KDQoNCg0KYGBge3J9DQpkIDwtIGRhdGEuZnJhbWUobGlzdChnZW5kZXI9YygiTSIsIk0iLCJGIiwiTSIsIkYiLCJGIiksYWdlPWMoNDcsNTksMjEsMzIsMzMsMjQpLGluY29tZT1jKDU1MDAwLDg4MDAwLDMyNDUwLDc2NTAwLDEyMzAwMCw0NTY1MCkpKQ0KYGBgDQoNCg0KYGBge3J9DQpkDQpgYGANCg0KDQoNCmBgYHtyfQ0KZCRvdmVyMjUgPC0gaWZlbHNlKGQkYWdlID4gMjUsMSwwKQ0KYGBgDQoNCg0KDQpgYGB7cn0NCmQNCmBgYA0KDQoNCg0KYGBge3J9DQp0YXBwbHkoZCRpbmNvbWUsbGlzdChkJGdlbmRlcixkJG92ZXIyNSksbWVhbikNCmBgYA0KDQpXZSBzcGVjaWZpZWQgdHdvIGZhY3RvcnMsIGdlbmRlciBhbmQgaW5kaWNhdG9yIHZhcmlhYmxlIGZvciBhZ2Ugb3ZlciBvciB1bmRlciAyNS4gU2luY2UgZWFjaCBvZiB0aGVzZSBmYWN0b3JzIGhhcyB0d28gbGV2ZWxzLCB0YXBwbHkoKSBwYXJ0aXRpb25lZCB0aGUgaW5jb21lIGRhdGEgaW50byBmb3VyIGdyb3Vwcywgb25lIGZvciBlYWNoIGNvbWJpbmF0aW9uIG9mIGdlbmRlciBhbmQgYWdlLCBhbmQgdGhlbiBhcHBsaWVkIHRvIG1lYW4oKSBmdW5jdGlvbiB0byBlYWNoIGdyb3VwLg0KDQoNCiMjIyMjICoqTXkgRXhhbXBsZSoqDQoNCk15IGV4YW1wbGUgd2l0aCBtb3JlIHRoYW4gMiBmYWN0b3JzLiBJbiB0aGlzIGNhc2UgdmFyaWFibGVzIGFyZSBnb2luZyB0byBiZSBzaXplLCBjb2xvciBhbmQgcHJpY2VzIG9mIFQtc2hpcnRzIGluIGEgc3RvcmUuIEhlcmUsIHRoZSBjYWxsIHRhcHBseSh4LGYsZykgbWlnaHQgaGF2ZSB4IGFzIGluY29tZSBhbmQgZiBhcyBhIHBhaXIgb2YgZmFjdG9yczogb25lIGZvciBzaXplIGFuZCB0aGUgb3RoZXIgY29kaW5nIHdoZXRoZXIgdGhlIFQtc2hpcnQgaXMgY2hlYXBlciBvciBtb3JlIGV4cGVuc2l2ZSB0aGFuIDUwJC4gV2UgbWF5IGJlIGludGVyZXN0ZWQgaW4gZmluZGluZyBtZWFuIHByaWNlLCBicm9rZW4gZG93biBieSBzaXplIGFuZCBjb2xvci4gSWYgd2Ugc2V0IGcoKSB0byBiZSBtZWFuKCksIHRhcHBseSgpIHdpbGwgcmV0dXJuIHRoZSBtZWFuIGluY29tZXMgaW4gZWFjaCBvZiBmb3VyIHN1Ymdyb3VwczoNCg0K4oCiIFNpemUgTCBhbmQgdW5kZXIgNTAkIA0K4oCiIFNpemUgTSBhbmQgdW5kZXIgNTAkIA0K4oCiIFNpemUgTCBhbmQgb3ZlciA1MCQNCuKAoiBTSXplIE0gYW5kIG92ZXIgNTAkDQoNCmBgYHtyfQ0KdHNoaXJ0IDwtIGRhdGEuZnJhbWUobGlzdChzaXplPWMoIk0iLCJMIiwiTCIsIkwiLCJTIiwiTSIpLGNvb2xvcj1jKCJyZWQiLCJyZWQiLCJibHVlIiwicHVycGxlIiwicHVycGxlIiwicHVycGxlIikscHJpY2U9Yyg1NSw4NiwzMyw0NSw3OCwyMCkpKQ0KYGBgDQoNCkRhdGEgZnJhbWUgYXMgYmVlbiBjcmVhdGVkIHdpdGggY29sb3Igc2l6ZSBhbmQgcHJpY2Ugb2YgdHNoaXJ0cyBpbiBhIHNob3AuDQpgYGB7cn0NCnRzaGlydA0KYGBgDQpMZXRzIHNob3cgdGhlIHQgc2hpcnRzIHRoYXQgY29zdHMgbGVzcyB0aGFuIDUwJA0KYGBge3J9DQp0c2hpcnQkbG93ZXI1MCA8LSBpZmVsc2UodHNoaXJ0JHByaWNlIDwgNTAsMSwwKQ0KYGBgDQoNCg0KYGBge3J9DQp0c2hpcnQNCmBgYA0KDQoNCmBgYHtyfQ0KdGFwcGx5KHRzaGlydCRwcmljZSxsaXN0KHRzaGlydCRjb29sb3IsdHNoaXJ0JGxvd2VyNTApLG1lYW4pDQpgYGANCk1lYW4gdmFsdWVzIG9mIHByaWNlcyBmb3IgYmx1ZSwgcHVycGxlIGFuZCByZWQgdCBzaGlydHMuIDAgY29ycmVzcG9uZCB0byB0aGUgc2hpcnRzIHdoaWNoIHZhbHVlcyBpcyBncmF0ZXIgdGhhbiA1MGRvbGxhcnMgd2hpbGUgMSBjb3JyZXNwb25kIHRvIHRoZSBzaGlydCB3aGljaCB2YWx1ZXMgaXMgbG93ZXIgdGhhbiA1MGRvbGxhcnMNCg0KDQoNCg0KDQoqKlRoZSBzcGxpdCgpIEZ1bmN0aW9uKioNCg0KSW4gY29udHJhc3QgdG8gdGFwcGx5KCksIHdoaWNoIHNwbGl0cyBhIHZlY3RvciBpbnRvIGdyb3VwcyBhbmQgdGhlbiBhcHBsaWVzIGEgc3BlY2lmaWVkIGZ1bmN0aW9uIG9uIGVhY2ggZ3JvdXAsIHNwbGl0KCkgc3RvcHMgYXQgdGhhdCBmaXJzdCBzdGFnZSwganVzdCBmb3JtaW5nIHRoZSBncm91cHMuIFRoZSBiYXNpYyBmb3JtLCB3aXRob3V0IGJlbGxzIGFuZCB3aGlzdGxlcywgaXMgc3BsaXQoeCxmKSwgd2l0aCB4IGFuZCBmIHBsYXlpbmcgcm9sZXMgc2ltaWxhciB0byB0aG9zZSBpbiB0aGUgY2FsbCB0YXBwbHkoeCxmLGcpOyB0aGF0IGlzLCB4IGJlaW5nIGEgdmVjdG9yIG9yIGRhdGEgZnJhbWUgYW5kIGYgYmVpbmcgYSBmYWN0b3Igb3IgYSBsaXN0IG9mIGZhY3RvcnMuIFRoZSBhY3Rpb24gaXMgdG8gc3BsaXQgeCBpbnRvIGdyb3Vwcywgd2hpY2ggYXJlIHJldHVybmVkIGluIGEgbGlzdC4gKE5vdGUgdGhhdCB4IGlzIGFsbG93ZWQgdG8gYmUgYSBkYXRhIGZyYW1lIHdpdGggc3BsaXQoKSBidXQgbm90IHdpdGggdGFwcGx5KCkuDQoNCkxldOKAmXMgdHJ5IGl0IG91dCB3aXRoIG91ciBlYXJsaWVyIGV4YW1wbGUuDQoNCg0KYGBge3J9DQpzcGxpdChkJGluY29tZSxsaXN0KGQkZ2VuZGVyLGQkb3ZlcjI1KSkNCmBgYA0KDQpUaGUgb3V0cHV0IG9mIHNwbGl0KCkgaXMgYSBsaXN0LCBhbmQgcmVjYWxsIHRoYXQgbGlzdCBjb21wb25lbnRzIGFyZSBkZW5vdGVkIGJ5IGRvbGxhciBzaWducy4gU28gdGhlIGxhc3QgdmVjdG9yLCBmb3IgZXhhbXBsZSwgd2FzIG5hbWVkICJNLjEiIHRvIGluZGljYXRlIHRoYXQgaXQgd2FzIHRoZSByZXN1bHQgb2YgY29tYmluaW5nICJNIiBpbiB0aGUgZmlyc3QgZmFjdG9yIGFuZCAxIGluIHRoZSBzZWNvbmQuIA0KDQoNCkluZGljZXMgb2YgdGhlIHZlY3RvciBlbGVtZW50cyBjb3JyZXNwb25kaW5nIHRvIG1hbGUsIGZlbWFsZSwgYW5kIGluZmFudCB3YW50ZWQgdG8gYmUgZGV0ZXJtaW5lZC4gSW4gdGhpcyBleGFtcGxlICJGZW1hbGUiIG9jY3VycmVkIGluIGluZGljZXMgMiwgMyBhbmQgNzsgIk1hbGUiIG9jY3VycmVkIGluIGluZGljZXMgMSwgNSBhbmQgNiBhbmQgIkluZmFudCIgaW4gNC4NCmBgYHtyfQ0KZyA8LSBjKCJNIiwiRiIsIkYiLCJJIiwiTSIsIk0iLCJGIikNCnNwbGl0KDE6NyxnKQ0KYGBgDQoNCkxldOKAmXMgZGlzc2VjdCB0aGlzIHN0ZXAtYnktc3RlcC4gVGhlIHZlY3RvciBnLCB0YWtlbiBhcyBhIGZhY3RvciwgaGFzIHRocmVlIGxldmVsczogIk0iLCAiRiIsIGFuZCAiSSIuIFRoZSBpbmRpY2VzIGNvcnJlc3BvbmRpbmcgdG8gdGhlIGZpcnN0IGxldmVsIGFyZSAxLCA1LCBhbmQgNiwgd2hpY2ggbWVhbnMgdGhhdCBnWzFdLCBnWzVdLCBhbmQgZ1s2XSBhbGwgaGF2ZSB0aGUgdmFsdWUgIk0iLiBTbywgUiBzZXRzDQp0aGUgTSBjb21wb25lbnQgb2YgdGhlIG91dHB1dCB0byBlbGVtZW50cyAxLCA1LCBhbmQgNiBvZiAxOjcsIHdoaWNoIGlzIHRoZSB2ZWN0b3IgKDEsNSw2KS4NCg0KIyMjIyMgKipNeSBFeGFtcGxlLCBzcGxpdCgpIGZ1bmN0aW9uKioNCg0KRnVuY3Rpb24gc3BsaXQoKSBvdXRwdXRzIHRoZSBwcmljZSBvZiBlYWNoIGtpbmQgb2Ygc2hpcnQgd2l0aCB0aGUgY29uZGl0aW9uIG9mIGJlaW5nIGNoZWFwZXIgb3IgbW9yZSBleHBlbnNpdmUgdGhhbiA1MCBkb2xsYXJzLg0KRm9yIGV4YW1wbGUgdGhlcmUgaXMgbm8gYmx1ZSBzaGlydCB0aGF0IGNvc3RzIG1vcmUgdGhhbiA1MGRvbGxhcnMgYnV0IHRoZXJlIGlzIG9uZSB3aGljaCBwcmljZSBpcyAzM2RvbGxhcnMuIA0KYGBge3J9DQpzcGxpdCh0c2hpcnQkcHJpY2UsbGlzdCh0c2hpcnQkY29vbG9yLHRzaGlydCRsb3dlcjUwKSkNCmBgYA0KDQoNCioqV29ya2luZyB3aXRoIFRhYmxlcyoqDQoNClRvIGJlZ2luIGV4cGxvcmluZyBSIHRhYmxlcywgY29uc2lkZXIgdGhpcyBleGFtcGxlOg0KDQoNCmBgYHtyfQ0KcCA8LSBjKDY2LDkwLDMsNTYsMCw5LC02KQ0KZmwgPC0gbGlzdChjKDcsMTQsMzMsMzMsNywxNCwzMyksYygiayIsImoiLCJqIiwiaiIsImsiLCJqIiwiaiIpKQ0KdGFwcGx5KHAsZmwsbGVuZ3RoKQ0KYGBgDQoNCkhlcmUsIHRhcHBseSgpIGFnYWluIHRlbXBvcmFyaWx5IGJyZWFrcyB1IGludG8gc3VidmVjdG9ycywgYXMgeW91IHNhdyBlYXJsaWVyLGFuZCB0aGVuIGFwcGxpZXMgdGhlIGxlbmd0aCgpIGZ1bmN0aW9uIHRvIGVhY2ggc3VidmVjdG9yLiAoTm90ZSB0aGF0IHRoaXMgaXMgaW5kZXBlbmRlbnQgb2Ygd2hhdOKAmXMgaW4gcC4gT3VyIGZvY3VzIG5vdyBpcyBwdXJlbHkgb24gdGhlIGZhY3RvcnMuKSBUaG9zZSBzdWJ2ZWN0b3IgbGVuZ3RocyBhcmUgdGhlIGNvdW50cyBvZiB0aGUgb2NjdXJyZW5jZXMgb2YgZWFjaCBvZiB0aGUgMyDDlyAyID0gNiBjb21iaW5hdGlvbnMgb2YgdGhlIHR3byBmYWN0b3JzLiBGb3IgaW5zdGFuY2UsIDcgb2NjdXJyZWQgdHdpY2Ugd2l0aCAiayIgYW5kIG5vdCBhdCBhbGwgd2l0aCAiaiI7IGhlbmNlIHRoZSBlbnRyaWVzIDIgYW5kIE5BIGluIHRoZSBmaXJzdCByb3cgb2YgdGhlIG91dHB1dC5JbiBzdGF0aXN0aWNzLCB0aGlzIGlzIGNhbGxlZCBhIGNvbnRpbmdlbmN5IHRhYmxlLg0KDQpUaGVyZSBpcyBvbmUgcHJvYmxlbSBpbiB0aGlzIGV4YW1wbGU6IHRoZSBOQSB2YWx1ZS4gSXQgcmVhbGx5IHNob3VsZCBiZSAwLCBtZWFuaW5nIHRoYXQgaW4gbm8gY2FzZXMgZGlkIHRoZSBmaXJzdCBmYWN0b3IgaGF2ZSBsZXZlbCA1IGFuZCB0aGUgc2Vjb25kIGhhdmUgbGV2ZWwgImoiLiBUaGUgdGFibGUoKSBmdW5jdGlvbiBjcmVhdGVzIGNvbnRpbmdlbmN5IHRhYmxlcyBjb3JyZWN0bHkuDQoNCg0KYGBge3J9DQp0YWJsZShmbCkNCmBgYA0KVGhlIGZpcnN0IGFyZ3VtZW50IGluIGEgY2FsbCB0byB0YWJsZSgpIGlzIGVpdGhlciBhIGZhY3RvciBvciBhIGxpc3Qgb2YgZmFjdG9ycy4gVGhlIHR3byBmYWN0b3JzIGhlcmUgd2VyZSAoNywxNCwzMywzMyw3LDE0LDMzKSBhbmQgKCJrIiwiaiIsImoiLCJqIiwiayIsImoiLCJqIikuIEluIHRoaXMgY2FzZSwgYW4gb2JqZWN0IHRoYXQgaXMgaW50ZXJwcmV0YWJsZSBhcyBhIGZhY3RvciBpcyBjb3VudGVkIGFzIG9uZS4NCg0KDQo=