Introduction

When building linear regression models in R, it can be possible to specify a predictor as either numeric or as a “factor”. In R, factor variables are typically used when a given predictor contains data from a discrete set of values, that does not have an implied order. Some examples of factor variables can include gender, and color(“red”, “green”, “blue”, etc.). In some cases, the values can become difficult to decipher. Consider, for example, if you build a model and one of the parameters is “number_of_bedrooms”, and the dataset only contains values from 0-8. Should “number_of_bedrooms” be a numeric value, or should it be a factor?

The purpose of this document is to compare what happens when a simple model with one numeric predictor is built using numeric vs factor types.

The Data

The data in this example will come from the Abalone dataset from the University of California, Irvine machine learning repository. In this exploration we will use just one response variable, rings, and the predictor will be weight.whole. In Abalone, rings are found in the crossections of the animal’s shell. The number of rings plus 1.5 indicates the number years of growth for the animal.

The following cell will load the data from the UCI repository:

rm(list=ls())
library(tidyverse)

# read the dataset into a data frame
abalone <- read.csv("http://archive.ics.uci.edu/ml/machine-learning-databases/abalone/abalone.data", header=FALSE)

The code below will pull out the specific columns of interest. The code also limits the number of rings in the dataset to less than 16. The reason for this will be discussed later in the document.

# add column names
names(abalone) <- c("sex", "length", "diameter", "height", "weight.whole",
    "weight.shucked", "weight.viscera", "weight.shell", "rings")

abalone <- abalone %>% select(weight.whole, rings)
abalone <- abalone %>% filter(rings<=15) %>% filter(rings>2)

For the purposes of comparison, we will create a training and testing datasets. First, we will create two copies of the original data. In the first case, we will leave the “rings” variable as a numeric data type. In the second set, we will convert the data to a factor variable. The training datasets will consists of 75% of the data, and the test sets will be the remainder.


## 75% of the sample size
smp_size <- floor(0.75 * nrow(abalone))

## set the seed to make your partition reproducible
set.seed(8888)

abalone_factor <- abalone

abalone_factor$rings <- as.factor(abalone_factor$rings)

train_ind <- sample(seq_len(nrow(abalone)), size = smp_size)

num_train <- abalone[train_ind, ]
num_test <- abalone[-train_ind, ]
factor_train <- abalone_factor[train_ind,]
factor_test <- abalone_factor[-train_ind,]

If we compare the first few records of the training and testing sets, they appear to be identical, except for the type used for the data ring variable.

head(num_train)
head(factor_train)

The contrast command in R helps to visualize how factor variables are actually encoded in the data. In this case, “dummy” variables are used to store the value of the predictor.

contrasts(factor_train$rings)[1:10,]
   4 5 6 7 8 9 10 11 12 13 14 15
3  0 0 0 0 0 0  0  0  0  0  0  0
4  1 0 0 0 0 0  0  0  0  0  0  0
5  0 1 0 0 0 0  0  0  0  0  0  0
6  0 0 1 0 0 0  0  0  0  0  0  0
7  0 0 0 1 0 0  0  0  0  0  0  0
8  0 0 0 0 1 0  0  0  0  0  0  0
9  0 0 0 0 0 1  0  0  0  0  0  0
10 0 0 0 0 0 0  1  0  0  0  0  0
11 0 0 0 0 0 0  0  1  0  0  0  0
12 0 0 0 0 0 0  0  0  1  0  0  0

The graph above gives us an indication of how the rings will be encoded as dummy variables. In this example, what we are looking at is a portion of the possible combinations of dummy variables for the different values of “ring”. It is important to note that this matrix is just showing us the different possiblities and how they are encoded. The matrix is not actual observed data.

In the above graph, the first row is considered the “base” case. In this example, an Abalone that has 1 ring would have 0 for all of its dummy variables. Data of the structure in the second row would used to indicate if an Abalone has 2 rings. In this case, the value 2 would be 1, and the remaining dummy variables would be 0. When we display the dataframe or tibble in R, we don’t see this encoding scheme… but it is there and will be used as part of the linear regression model.

For a model that uses a numeric data type (and not a factor), no dummy variables are created. As a result, a model with this structure will have just one coefficient and an intercept. However, if rings is used as a factor, the model has 12 coefficients and an intercept.

The following code builds a model for the numeric and the factor variations.

mdl1 <- lm(weight.whole~rings, data=num_train)
mdl2 <- lm(weight.whole~rings, data=factor_train)

The following is a summary of model 1. Note that this model, which uses a numeric data type for the single predictor has only 1 coefficient and an intercept.

summary(mdl1)

Call:
lm(formula = weight.whole ~ rings, data = num_train)

Residuals:
     Min       1Q   Median       3Q      Max 
-1.17329 -0.26012 -0.05797  0.23882  1.66992 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept) -0.299261   0.029356  -10.19   <2e-16 ***
rings        0.117404   0.003035   38.69   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.3957 on 2933 degrees of freedom
Multiple R-squared:  0.3379,    Adjusted R-squared:  0.3376 
F-statistic:  1497 on 1 and 2933 DF,  p-value: < 2.2e-16

Let’s compare that to model 2:

summary(mdl2)

Call:
lm(formula = weight.whole ~ rings, data = factor_train)

Residuals:
     Min       1Q   Median       3Q      Max 
-1.03635 -0.22405 -0.02097  0.20128  1.66767 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)  0.02891    0.11196   0.258  0.79627    
rings4       0.03181    0.12490   0.255  0.79896    
rings5       0.09744    0.11861   0.821  0.41143    
rings6       0.24847    0.11519   2.157  0.03108 *  
rings7       0.36871    0.11402   3.234  0.00124 ** 
rings8       0.60356    0.11337   5.324 1.09e-07 ***
rings9       0.82116    0.11317   7.256 5.07e-13 ***
rings10      0.96602    0.11324   8.531  < 2e-16 ***
rings11      1.12744    0.11368   9.917  < 2e-16 ***
rings12      1.08292    0.11478   9.435  < 2e-16 ***
rings13      1.04442    0.11599   9.004  < 2e-16 ***
rings14      1.06209    0.11891   8.932  < 2e-16 ***
rings15      0.97661    0.11979   8.153 5.23e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.3713 on 2922 degrees of freedom
Multiple R-squared:  0.4191,    Adjusted R-squared:  0.4167 
F-statistic: 175.7 on 12 and 2922 DF,  p-value: < 2.2e-16

There are several interesting things to note in the above. First, only coefficient for model1 is statistically significant at the 95% level. In the case of model 2, a number of coefficients are not statistically significant. The other thing to notice between these two models is that the F test does indicate that there is some predictive power (not all of the coefficients are 0).

So, how accurate are these models? The following code will compute the mean squared error for our models on the holdout test set that we used initially.


p1 <- predict(mdl1, newdata=num_test, type="response")
p2 <- predict(mdl2, newdata=factor_test, type="response")

msp1 <- mean((num_test$weight.whole - p1) ^ 2)
msp2 <- mean((factor_test$weight.whole - p2) ^ 2)


cat(paste("\nModel 1 (numeric) Adj R Squared:", summary(mdl1)$adj.r.squared))

Model 1 (numeric) Adj R Squared: 0.337628397989203
cat(paste("\nMSE Model 1:", msp1))

MSE Model 1: 0.149382512820635
cat(paste("\n\nModel 2 (factor) Adj R Squared:", summary(mdl2)$adj.r.squared))


Model 2 (factor) Adj R Squared: 0.416709755376824
cat(paste("\nMSE Model 2:", msp2))

MSE Model 2: 0.131112595156082
x = seq(3,15)
y = predict(mdl2, data.frame(rings=as.factor(x)))
plot(abalone$rings,abalone$weight.whole)
abline(coef=mdl1$coefficients)
lines(x,y, col="red")

At first glance, model 2 (in red) looks great… however there is a danger. In the above case, our model fits the data but only the data that it has been trained on. In fact, it has been “overfit” to the extreme. Consider if we try to predict the weight of an Abalone that has 20 rings, or one that has only 2. Model 1 will work fine in both cases. Model 2, however “blows up”. The model does not contain a dummy variable for the case of less than 3 rings, or greater than 15.

Conclusion

In many cases, coding factor variables for numeric types can provide better fit. However, doing so limits the model to only being able to predict data that has the corresponding dummy variables.

This concludes this writeup on converting numeric types to factor variables.

LS0tCnRpdGxlOiAiTGluZWFyIFJlZ3Jlc3Npb24gYW5kIENvbnZlcnRpbmcgTnVtZXJpYyBQcmVkaWN0b3JzIHRvIEZhY3RvcnMiCmF1dGhvcjogIE1pbGVzIFBvcnRlcgpkYXRlOiBNYXkgMjcsIDIwMjAKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyBJbnRyb2R1Y3Rpb24KCldoZW4gYnVpbGRpbmcgbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWxzIGluIFIsIGl0IGNhbiBiZSBwb3NzaWJsZSB0byBzcGVjaWZ5IGEgcHJlZGljdG9yIGFzIGVpdGhlciBudW1lcmljIG9yIGFzIGEgImZhY3RvciIuICBJbiBSLCBmYWN0b3IgdmFyaWFibGVzIGFyZSB0eXBpY2FsbHkgdXNlZCB3aGVuIGEgZ2l2ZW4gcHJlZGljdG9yIGNvbnRhaW5zIGRhdGEgZnJvbSBhIGRpc2NyZXRlIHNldCBvZiB2YWx1ZXMsIHRoYXQgZG9lcyBub3QgaGF2ZSBhbiBpbXBsaWVkIG9yZGVyLiAgU29tZSBleGFtcGxlcyBvZiBmYWN0b3IgdmFyaWFibGVzIGNhbiBpbmNsdWRlIGdlbmRlciwgYW5kIGNvbG9yKCJyZWQiLCAiZ3JlZW4iLCAiYmx1ZSIsIGV0Yy4pLiAgSW4gc29tZSBjYXNlcywgdGhlIHZhbHVlcyBjYW4gYmVjb21lIGRpZmZpY3VsdCB0byBkZWNpcGhlci4gIENvbnNpZGVyLCBmb3IgZXhhbXBsZSwgaWYgeW91IGJ1aWxkIGEgbW9kZWwgYW5kIG9uZSBvZiB0aGUgcGFyYW1ldGVycyBpcyAibnVtYmVyX29mX2JlZHJvb21zIiwgYW5kIHRoZSBkYXRhc2V0IG9ubHkgY29udGFpbnMgdmFsdWVzIGZyb20gMC04LiAgU2hvdWxkICJudW1iZXJfb2ZfYmVkcm9vbXMiIGJlIGEgbnVtZXJpYyB2YWx1ZSwgb3Igc2hvdWxkIGl0IGJlIGEgZmFjdG9yPwoKVGhlIHB1cnBvc2Ugb2YgdGhpcyBkb2N1bWVudCBpcyB0byBjb21wYXJlIHdoYXQgaGFwcGVucyB3aGVuIGEgc2ltcGxlIG1vZGVsIHdpdGggb25lIG51bWVyaWMgcHJlZGljdG9yIGlzIGJ1aWx0IHVzaW5nIG51bWVyaWMgdnMgZmFjdG9yIHR5cGVzLgoKIyMgIFRoZSBEYXRhCgpUaGUgZGF0YSBpbiB0aGlzIGV4YW1wbGUgd2lsbCBjb21lIGZyb20gdGhlIEFiYWxvbmUgZGF0YXNldCBmcm9tIHRoZSBbVW5pdmVyc2l0eSBvZiBDYWxpZm9ybmlhLCBJcnZpbmUgbWFjaGluZSBsZWFybmluZyByZXBvc2l0b3J5XShodHRwczovL2FyY2hpdmUuaWNzLnVjaS5lZHUvbWwvaW5kZXgucGhwKS4gIEluIHRoaXMgZXhwbG9yYXRpb24gd2Ugd2lsbCB1c2UganVzdCBvbmUgcmVzcG9uc2UgdmFyaWFibGUsIHJpbmdzLCBhbmQgdGhlIHByZWRpY3RvciB3aWxsIGJlIHdlaWdodC53aG9sZS4gIEluIEFiYWxvbmUsIHJpbmdzIGFyZSBmb3VuZCBpbiB0aGUgY3Jvc3NlY3Rpb25zIG9mIHRoZSBhbmltYWwncyBzaGVsbC4gIFRoZSBudW1iZXIgb2YgcmluZ3MgcGx1cyAxLjUgaW5kaWNhdGVzIHRoZSBudW1iZXIgeWVhcnMgb2YgZ3Jvd3RoIGZvciB0aGUgYW5pbWFsLgoKVGhlIGZvbGxvd2luZyBjZWxsIHdpbGwgbG9hZCB0aGUgZGF0YSBmcm9tIHRoZSBVQ0kgcmVwb3NpdG9yeToKCmBgYHtyfQpybShsaXN0PWxzKCkpCmxpYnJhcnkodGlkeXZlcnNlKQoKIyByZWFkIHRoZSBkYXRhc2V0IGludG8gYSBkYXRhIGZyYW1lCmFiYWxvbmUgPC0gcmVhZC5jc3YoImh0dHA6Ly9hcmNoaXZlLmljcy51Y2kuZWR1L21sL21hY2hpbmUtbGVhcm5pbmctZGF0YWJhc2VzL2FiYWxvbmUvYWJhbG9uZS5kYXRhIiwgaGVhZGVyPUZBTFNFKQoKCmBgYAoKVGhlIGNvZGUgYmVsb3cgd2lsbCBwdWxsIG91dCB0aGUgc3BlY2lmaWMgY29sdW1ucyBvZiBpbnRlcmVzdC4gIFRoZSBjb2RlIGFsc28gbGltaXRzIHRoZSBudW1iZXIgb2YgcmluZ3MgaW4gdGhlIGRhdGFzZXQgdG8gbGVzcyB0aGFuIDE2LiAgVGhlIHJlYXNvbiBmb3IgdGhpcyB3aWxsIGJlIGRpc2N1c3NlZCBsYXRlciBpbiB0aGUgZG9jdW1lbnQuCgpgYGB7Un0KIyBhZGQgY29sdW1uIG5hbWVzCm5hbWVzKGFiYWxvbmUpIDwtIGMoInNleCIsICJsZW5ndGgiLCAiZGlhbWV0ZXIiLCAiaGVpZ2h0IiwgIndlaWdodC53aG9sZSIsCiAgICAid2VpZ2h0LnNodWNrZWQiLCAid2VpZ2h0LnZpc2NlcmEiLCAid2VpZ2h0LnNoZWxsIiwgInJpbmdzIikKCmFiYWxvbmUgPC0gYWJhbG9uZSAlPiUgc2VsZWN0KHdlaWdodC53aG9sZSwgcmluZ3MpCmFiYWxvbmUgPC0gYWJhbG9uZSAlPiUgZmlsdGVyKHJpbmdzPD0xNSkgJT4lIGZpbHRlcihyaW5ncz4yKQoKYGBgCgpGb3IgdGhlIHB1cnBvc2VzIG9mIGNvbXBhcmlzb24sIHdlIHdpbGwgY3JlYXRlIGEgdHJhaW5pbmcgYW5kIHRlc3RpbmcgZGF0YXNldHMuICBGaXJzdCwgd2Ugd2lsbCBjcmVhdGUgdHdvIGNvcGllcyBvZiB0aGUgb3JpZ2luYWwgZGF0YS4gIEluIHRoZSBmaXJzdCBjYXNlLCB3ZSB3aWxsIGxlYXZlIHRoZSAicmluZ3MiIHZhcmlhYmxlIGFzIGEgbnVtZXJpYyBkYXRhIHR5cGUuICBJbiB0aGUgc2Vjb25kIHNldCwgd2Ugd2lsbCBjb252ZXJ0IHRoZSBkYXRhIHRvIGEgZmFjdG9yIHZhcmlhYmxlLiAgVGhlIHRyYWluaW5nIGRhdGFzZXRzIHdpbGwgY29uc2lzdHMgb2YgNzUlIG9mIHRoZSBkYXRhLCBhbmQgdGhlIHRlc3Qgc2V0cyB3aWxsIGJlIHRoZSByZW1haW5kZXIuCgpgYGB7cn0KCiMjIDc1JSBvZiB0aGUgc2FtcGxlIHNpemUKc21wX3NpemUgPC0gZmxvb3IoMC43NSAqIG5yb3coYWJhbG9uZSkpCgojIyBzZXQgdGhlIHNlZWQgdG8gbWFrZSB5b3VyIHBhcnRpdGlvbiByZXByb2R1Y2libGUKc2V0LnNlZWQoODg4OCkKCmFiYWxvbmVfZmFjdG9yIDwtIGFiYWxvbmUKCmFiYWxvbmVfZmFjdG9yJHJpbmdzIDwtIGFzLmZhY3RvcihhYmFsb25lX2ZhY3RvciRyaW5ncykKCnRyYWluX2luZCA8LSBzYW1wbGUoc2VxX2xlbihucm93KGFiYWxvbmUpKSwgc2l6ZSA9IHNtcF9zaXplKQoKbnVtX3RyYWluIDwtIGFiYWxvbmVbdHJhaW5faW5kLCBdCm51bV90ZXN0IDwtIGFiYWxvbmVbLXRyYWluX2luZCwgXQpmYWN0b3JfdHJhaW4gPC0gYWJhbG9uZV9mYWN0b3JbdHJhaW5faW5kLF0KZmFjdG9yX3Rlc3QgPC0gYWJhbG9uZV9mYWN0b3JbLXRyYWluX2luZCxdCmBgYAoKSWYgd2UgY29tcGFyZSB0aGUgZmlyc3QgZmV3IHJlY29yZHMgb2YgdGhlIHRyYWluaW5nIGFuZCB0ZXN0aW5nIHNldHMsIHRoZXkgYXBwZWFyIHRvIGJlIGlkZW50aWNhbCwgZXhjZXB0IGZvciB0aGUgdHlwZSB1c2VkIGZvciB0aGUgZGF0YSByaW5nIHZhcmlhYmxlLgoKYGBge3J9CmhlYWQobnVtX3RyYWluKQpoZWFkKGZhY3Rvcl90cmFpbikKYGBgCgpUaGUgY29udHJhc3QgY29tbWFuZCBpbiBSIGhlbHBzIHRvIHZpc3VhbGl6ZSBob3cgZmFjdG9yIHZhcmlhYmxlcyBhcmUgYWN0dWFsbHkgZW5jb2RlZCBpbiB0aGUgZGF0YS4gIEluIHRoaXMgY2FzZSwgImR1bW15IiB2YXJpYWJsZXMgYXJlIHVzZWQgdG8gc3RvcmUgdGhlIHZhbHVlIG9mIHRoZSBwcmVkaWN0b3IuCgpgYGB7cn0KY29udHJhc3RzKGZhY3Rvcl90cmFpbiRyaW5ncylbMToxMCxdCmBgYAoKVGhlIGdyYXBoIGFib3ZlIGdpdmVzIHVzIGFuIGluZGljYXRpb24gb2YgaG93IHRoZSByaW5ncyB3aWxsIGJlIGVuY29kZWQgYXMgZHVtbXkgdmFyaWFibGVzLiAgSW4gdGhpcyBleGFtcGxlLCB3aGF0IHdlIGFyZSBsb29raW5nIGF0IGlzIGEgcG9ydGlvbiBvZiB0aGUgcG9zc2libGUgY29tYmluYXRpb25zIG9mIGR1bW15IHZhcmlhYmxlcyBmb3IgdGhlIGRpZmZlcmVudCB2YWx1ZXMgb2YgInJpbmciLiAgSXQgaXMgaW1wb3J0YW50IHRvIG5vdGUgdGhhdCB0aGlzIG1hdHJpeCBpcyBqdXN0IHNob3dpbmcgdXMgdGhlIGRpZmZlcmVudCBwb3NzaWJsaXRpZXMgYW5kIGhvdyB0aGV5IGFyZSBlbmNvZGVkLiAgVGhlIG1hdHJpeCBpcyBub3QgYWN0dWFsIG9ic2VydmVkIGRhdGEuCgpJbiB0aGUgYWJvdmUgZ3JhcGgsIHRoZSBmaXJzdCByb3cgaXMgY29uc2lkZXJlZCB0aGUgImJhc2UiIGNhc2UuICBJbiB0aGlzIGV4YW1wbGUsIGFuIEFiYWxvbmUgdGhhdCBoYXMgMSByaW5nIHdvdWxkIGhhdmUgMCBmb3IgYWxsIG9mIGl0cyBkdW1teSB2YXJpYWJsZXMuICBEYXRhIG9mIHRoZSBzdHJ1Y3R1cmUgaW4gdGhlIHNlY29uZCByb3cgd291bGQgdXNlZCB0byBpbmRpY2F0ZSBpZiBhbiBBYmFsb25lIGhhcyAyIHJpbmdzLiAgSW4gdGhpcyBjYXNlLCB0aGUgdmFsdWUgMiB3b3VsZCBiZSAxLCBhbmQgdGhlIHJlbWFpbmluZyBkdW1teSB2YXJpYWJsZXMgd291bGQgYmUgMC4gIFdoZW4gd2UgZGlzcGxheSB0aGUgZGF0YWZyYW1lIG9yIHRpYmJsZSBpbiBSLCB3ZSBkb24ndCBzZWUgdGhpcyBlbmNvZGluZyBzY2hlbWUuLi4gIGJ1dCBpdCBpcyB0aGVyZSBhbmQgd2lsbCBiZSB1c2VkIGFzIHBhcnQgb2YgdGhlIGxpbmVhciByZWdyZXNzaW9uIG1vZGVsLgoKRm9yIGEgbW9kZWwgdGhhdCB1c2VzIGEgbnVtZXJpYyBkYXRhIHR5cGUgKGFuZCBub3QgYSBmYWN0b3IpLCBubyBkdW1teSB2YXJpYWJsZXMgYXJlIGNyZWF0ZWQuICBBcyBhIHJlc3VsdCwgYSBtb2RlbCB3aXRoIHRoaXMgc3RydWN0dXJlIHdpbGwgaGF2ZSBqdXN0IG9uZSBjb2VmZmljaWVudCBhbmQgYW4gaW50ZXJjZXB0LiAgSG93ZXZlciwgaWYgcmluZ3MgaXMgdXNlZCBhcyBhIGZhY3RvciwgdGhlIG1vZGVsIGhhcyAxMiBjb2VmZmljaWVudHMgYW5kIGFuIGludGVyY2VwdC4KClRoZSBmb2xsb3dpbmcgY29kZSBidWlsZHMgYSBtb2RlbCBmb3IgdGhlIG51bWVyaWMgYW5kIHRoZSBmYWN0b3IgdmFyaWF0aW9ucy4KCmBgYHtyfQptZGwxIDwtIGxtKHdlaWdodC53aG9sZX5yaW5ncywgZGF0YT1udW1fdHJhaW4pCm1kbDIgPC0gbG0od2VpZ2h0Lndob2xlfnJpbmdzLCBkYXRhPWZhY3Rvcl90cmFpbikKYGBgCgpUaGUgZm9sbG93aW5nIGlzIGEgc3VtbWFyeSBvZiBtb2RlbCAxLiAgTm90ZSB0aGF0IHRoaXMgbW9kZWwsIHdoaWNoIHVzZXMgYSBudW1lcmljIGRhdGEgdHlwZSBmb3IgdGhlIHNpbmdsZSBwcmVkaWN0b3IgaGFzIG9ubHkgMSBjb2VmZmljaWVudCBhbmQgYW4gaW50ZXJjZXB0LgoKYGBge3J9CnN1bW1hcnkobWRsMSkKYGBgCgpMZXQncyBjb21wYXJlIHRoYXQgdG8gbW9kZWwgMjoKCmBgYHtyfQpzdW1tYXJ5KG1kbDIpCmBgYAoKVGhlcmUgYXJlIHNldmVyYWwgaW50ZXJlc3RpbmcgdGhpbmdzIHRvIG5vdGUgaW4gdGhlIGFib3ZlLiAgRmlyc3QsIG9ubHkgY29lZmZpY2llbnQgZm9yIG1vZGVsMSBpcyBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50IGF0IHRoZSA5NSUgbGV2ZWwuICBJbiB0aGUgY2FzZSBvZiBtb2RlbCAyLCBhIG51bWJlciBvZiBjb2VmZmljaWVudHMgYXJlIG5vdCBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50LiAgVGhlIG90aGVyIHRoaW5nIHRvIG5vdGljZSBiZXR3ZWVuIHRoZXNlIHR3byBtb2RlbHMgaXMgdGhhdCB0aGUgRiB0ZXN0IGRvZXMgaW5kaWNhdGUgdGhhdCB0aGVyZSBpcyBzb21lIHByZWRpY3RpdmUgcG93ZXIgKG5vdCBhbGwgb2YgdGhlIGNvZWZmaWNpZW50cyBhcmUgMCkuCgpTbywgaG93IGFjY3VyYXRlIGFyZSB0aGVzZSBtb2RlbHM/ICBUaGUgZm9sbG93aW5nIGNvZGUgd2lsbCBjb21wdXRlIHRoZSBtZWFuIHNxdWFyZWQgZXJyb3IgZm9yIG91ciBtb2RlbHMgb24gdGhlIGhvbGRvdXQgdGVzdCBzZXQgdGhhdCB3ZSB1c2VkIGluaXRpYWxseS4KCmBgYHtyfQoKcDEgPC0gcHJlZGljdChtZGwxLCBuZXdkYXRhPW51bV90ZXN0LCB0eXBlPSJyZXNwb25zZSIpCnAyIDwtIHByZWRpY3QobWRsMiwgbmV3ZGF0YT1mYWN0b3JfdGVzdCwgdHlwZT0icmVzcG9uc2UiKQoKbXNwMSA8LSBtZWFuKChudW1fdGVzdCR3ZWlnaHQud2hvbGUgLSBwMSkgXiAyKQptc3AyIDwtIG1lYW4oKGZhY3Rvcl90ZXN0JHdlaWdodC53aG9sZSAtIHAyKSBeIDIpCgoKY2F0KHBhc3RlKCJcbk1vZGVsIDEgKG51bWVyaWMpIEFkaiBSIFNxdWFyZWQ6Iiwgc3VtbWFyeShtZGwxKSRhZGouci5zcXVhcmVkKSkKY2F0KHBhc3RlKCJcbk1TRSBNb2RlbCAxOiIsIG1zcDEpKQoKY2F0KHBhc3RlKCJcblxuTW9kZWwgMiAoZmFjdG9yKSBBZGogUiBTcXVhcmVkOiIsIHN1bW1hcnkobWRsMikkYWRqLnIuc3F1YXJlZCkpCmNhdChwYXN0ZSgiXG5NU0UgTW9kZWwgMjoiLCBtc3AyKSkKYGBgCgpgYGB7cn0KeCA9IHNlcSgzLDE1KQp5ID0gcHJlZGljdChtZGwyLCBkYXRhLmZyYW1lKHJpbmdzPWFzLmZhY3Rvcih4KSkpCnBsb3QoYWJhbG9uZSRyaW5ncyxhYmFsb25lJHdlaWdodC53aG9sZSkKYWJsaW5lKGNvZWY9bWRsMSRjb2VmZmljaWVudHMpCmxpbmVzKHgseSwgY29sPSJyZWQiKQpgYGAKCkF0IGZpcnN0IGdsYW5jZSwgbW9kZWwgMiAoaW4gcmVkKSBsb29rcyBncmVhdC4uLiAgaG93ZXZlciB0aGVyZSBpcyBhIGRhbmdlci4gIEluIHRoZSBhYm92ZSBjYXNlLCBvdXIgbW9kZWwgZml0cyB0aGUgZGF0YSBidXQgb25seSB0aGUgZGF0YSB0aGF0IGl0IGhhcyBiZWVuIHRyYWluZWQgb24uICBJbiBmYWN0LCBpdCBoYXMgYmVlbiAib3ZlcmZpdCIgdG8gdGhlIGV4dHJlbWUuICBDb25zaWRlciBpZiB3ZSB0cnkgdG8gcHJlZGljdCB0aGUgd2VpZ2h0IG9mIGFuIEFiYWxvbmUgdGhhdCBoYXMgMjAgcmluZ3MsIG9yIG9uZSB0aGF0IGhhcyBvbmx5IDIuICBNb2RlbCAxIHdpbGwgd29yayBmaW5lIGluIGJvdGggY2FzZXMuICBNb2RlbCAyLCBob3dldmVyICJibG93cyB1cCIuICBUaGUgbW9kZWwgZG9lcyBub3QgY29udGFpbiBhIGR1bW15IHZhcmlhYmxlIGZvciB0aGUgY2FzZSBvZiBsZXNzIHRoYW4gMyByaW5ncywgb3IgZ3JlYXRlciB0aGFuIDE1LiAgCgojIENvbmNsdXNpb24KCkluIG1hbnkgY2FzZXMsIGNvZGluZyBmYWN0b3IgdmFyaWFibGVzIGZvciBudW1lcmljIHR5cGVzIGNhbiBwcm92aWRlIGJldHRlciBmaXQuICBIb3dldmVyLCBkb2luZyBzbyBsaW1pdHMgdGhlIG1vZGVsIHRvIG9ubHkgYmVpbmcgYWJsZSB0byBwcmVkaWN0IGRhdGEgdGhhdCBoYXMgdGhlIGNvcnJlc3BvbmRpbmcgZHVtbXkgdmFyaWFibGVzLgoKVGhpcyBjb25jbHVkZXMgdGhpcyB3cml0ZXVwIG9uIGNvbnZlcnRpbmcgbnVtZXJpYyB0eXBlcyB0byBmYWN0b3IgdmFyaWFibGVzLgo=