Prompt:

Using Pima Indians diabetes data set. Partition the data set into training set and test set with 80:20 ratios.

We begin this exercise by reading the data into our project from the site. We are also sure to add appropriate names to the data frame.

library(dplyr)
package <U+393C><U+3E31>dplyr<U+393C><U+3E32> was built under R version 3.3.2
Attaching package: <U+393C><U+3E31>dplyr<U+393C><U+3E32>

The following object is masked from <U+393C><U+3E31>package:car<U+393C><U+3E32>:

    recode

The following objects are masked from <U+393C><U+3E31>package:stats<U+393C><U+3E32>:

    filter, lag

The following objects are masked from <U+393C><U+3E31>package:base<U+393C><U+3E32>:

    intersect, setdiff, setequal, union

The first thing the prompt has us execute, is splitting the data into a 80-20, test and train data set, which we execute below:

Now that we have our working data set, we can begin to explore some of the properites with basic charts and summaries.

summary(train)
    Pregnant        GlucoseCon      Diastolic        SkinThick        Insulin            BMI             Diab             Age            Class       
 Min.   : 0.000   Min.   :  0.0   Min.   :  0.00   Min.   : 0.00   Min.   :  0.00   Min.   : 0.00   Min.   :0.0780   Min.   :21.00   Min.   :0.0000  
 1st Qu.: 1.000   1st Qu.:100.0   1st Qu.: 62.00   1st Qu.: 0.00   1st Qu.:  0.00   1st Qu.:26.93   1st Qu.:0.2415   1st Qu.:24.00   1st Qu.:0.0000  
 Median : 3.000   Median :117.5   Median : 72.00   Median :23.00   Median : 24.00   Median :32.05   Median :0.3780   Median :29.00   Median :0.0000  
 Mean   : 3.907   Mean   :121.8   Mean   : 68.89   Mean   :20.68   Mean   : 78.86   Mean   :32.03   Mean   :0.4694   Mean   :33.43   Mean   :0.3502  
 3rd Qu.: 6.000   3rd Qu.:142.0   3rd Qu.: 80.00   3rd Qu.:32.00   3rd Qu.:128.75   3rd Qu.:36.60   3rd Qu.:0.6355   3rd Qu.:41.00   3rd Qu.:1.0000  
 Max.   :17.000   Max.   :199.0   Max.   :122.00   Max.   :99.00   Max.   :744.00   Max.   :67.10   Max.   :2.4200   Max.   :81.00   Max.   :1.0000  
str(train)
'data.frame':   614 obs. of  9 variables:
 $ Pregnant  : int  6 1 4 3 6 1 7 3 1 9 ...
 $ GlucoseCon: int  194 86 76 130 144 121 114 111 103 112 ...
 $ Diastolic : int  78 66 62 64 72 78 76 56 80 82 ...
 $ SkinThick : int  0 52 0 0 27 39 17 39 11 32 ...
 $ Insulin   : int  0 65 0 0 228 74 110 0 82 175 ...
 $ BMI       : num  23.5 41.3 34 23.1 33.9 39 23.8 30.1 19.4 34.2 ...
 $ Diab      : num  0.129 0.917 0.391 0.314 0.255 0.261 0.466 0.557 0.491 0.26 ...
 $ Age       : int  59 29 25 22 40 28 31 30 22 36 ...
 $ Class     : int  1 0 0 0 0 0 0 0 0 1 ...
plot(train)

ages<-train %>% group_by(as.factor(Age),as.factor(Class)) %>% summarise(Class = n())
names(ages)<-c("Age","Class","NumberOfPeople")
ggplot(ages,aes(Age,NumberOfPeople))+geom_bar(aes(fill = Class), position = "dodge", stat='identity')+ 
  scale_x_discrete(breaks=seq(21, 81, 2))+labs(title="Number of Diabeteics vs Non-Diabetics by Age")

pregs<-train %>% group_by(as.factor(Pregnant),as.factor(Class)) %>% summarise(Class = n())
names(pregs)<-c("TimesPregnant","Class","NumberOfPeople")
ggplot(pregs,aes(TimesPregnant,NumberOfPeople))+geom_bar(aes(fill = Class), position = "dodge", stat='identity')+ 
  scale_x_discrete(breaks=seq(0, 17, 2))+labs(title="Number of Diabeteics vs Non-Diabetics by Number of Times Pregnant")

Ins<-train %>% group_by(as.factor(Class)) %>% summarise(Insulin = mean(Insulin))
names(Ins)<-c("Class","AvgInsulinLevel")
ggplot(Ins,aes(Class,AvgInsulinLevel))+geom_bar(stat='identity')+ 
 labs(title="Avg Insulin Levels for Class")

It looks like there is a relationship between a few of the variables that we looked at, but nothing overwhelming stands out. In the general plots, there are several giant clusters that are hard to distinguish, but there could be something there. Let’s now begin with the “adabag” package as recommended in the prompt to try our hand in classifying this data.

table(baggingTrained$class,train$Class,dnn=c("Predicted Class","Observed Class"))
               Observed Class
Predicted Class   0   1
              0 363 193
              1  36  22

This did not perform very well on itself. Something to point out at this point is that there are far more 0 classification records than 1’s. This model appears to have voted heavily for class 0 when it should be class 1. The next step is to apply this model to the test set from before and get a few metrics to see how it does. We will evaluate this model based on the confusion matrix, accuracy, and average error.

baggingTest$confusion
               Observed Class
Predicted Class  0  1
              0 87 27
              1 14 26
baggingTest$error
[1] 0.2662338
accuracy<-1-(14+27)/154
accuracy
[1] 0.7337662

This package does not have a great way to look at accuacy, so I will do a few calculations manually.

Specificity: When there is no diabetes, how often do we predict no diabetes?

Precision: When we did predict diabetes, how often is it correct?

This number is particularly weak. The prompt would have us do 10-fold cross validation with our bagging model. Let’s see if that makes a difference for our precision.

table(baggingTrained10Fold$class,train$Class,dnn=c("Predicted Class","Observed Class"))
               Observed Class
Predicted Class   0   1
              0 368 198
              1  31  17
baggingTest10Fold<- predict.bagging(baggingTrained10Fold, newdata = test)
baggingTest10Fold$confusion
               Observed Class
Predicted Class  0  1
              0 89 27
              1 12 26
baggingTest10Fold$error
[1] 0.2532468
accuracy<-1-(12+27)/154
accuracy
[1] 0.7467532

Specificity: When there is no diabetes, how often do we predict no diabetes?

Precision: When we did predict diabetes, how often is it correct?

This performed slightly better with 2 fewer misclassifications, but does not yet perform well. Let’s move to boosting, continuing with the adabag package for consitency.

table(boostTrain$class,train$Class,dnn=c("Predicted Class","Observed Class"))
               Observed Class
Predicted Class   0   1
              0 383  20
              1  16 195
boostTest<- predict.boosting(boostTrain, newdata = test)
boostTest$confusion
               Observed Class
Predicted Class  0  1
              0 83 23
              1 18 30
boostTest$error
[1] 0.2662338
accuracy<-1-(18+23)/154
accuracy
[1] 0.7337662

Our boosting study appears to have about the same accuracy as our previous bagging models. One thing to point out is that when comparing the training model to the training classification, that confusion matrix appears that represent a higher accuracy that our bagging models represented when looking at the training data.

Specificity: When there is no diabetes, how often do we predict no diabetes?

Precision: When we did predict diabetes, how often is it correct?

One take away from these metrics is that this prediciton had more guesses for 1, a positive diabetes classification, though overall, it was less accurate in doing so. It could be the case that our model is over fitted based on our training set. As recommended in the prompt, we can try using 10-fold cross validation to account for this problem. Let’s see if it works for our diabetes classifications.

table(boostTrain10Fold$class,train$Class,dnn=c("Predicted Class","Observed Class"))
               Observed Class
Predicted Class   0   1
              0 386  16
              1  13 199
boostTest10Fold<- predict.boosting(boostTrain10Fold, newdata = test)
boostTest10Fold$confusion
               Observed Class
Predicted Class  0  1
              0 81 24
              1 20 29
boostTest10Fold$error
[1] 0.2857143
accuracy<-1-(20+24)/154
accuracy
[1] 0.7142857

Specificity: When there is no diabetes, how often do we predict no diabetes?

Precision: When we did predict diabetes, how often is it correct?

Interestingly, our first example had higher precision and specificity. That just goes to show why the 10-fold validation is important. OUr first model performed better than we should expect.

Lets compare the variable importance when looking at all 4 of the models to compare what they look at before evaluating them for performance

baggingTrained$importance
       Age        BMI       Diab  Diastolic GlucoseCon    Insulin   Pregnant  SkinThick 
  9.482231  17.778772   6.637635   4.093818  51.507081   2.937476   4.986332   2.576655 
baggingTrained10Fold$importance
       Age        BMI       Diab  Diastolic GlucoseCon    Insulin   Pregnant  SkinThick 
 10.736659  14.539231  10.203879   2.454334  50.122278   3.226829   4.299985   4.416806 
boostTrain$importance
       Age        BMI       Diab  Diastolic GlucoseCon    Insulin   Pregnant  SkinThick 
 11.246099  19.916713  13.336090   7.126663  27.145441   6.857899   8.141832   6.229262 
boostTrain10Fold$importance
       Age        BMI       Diab  Diastolic GlucoseCon    Insulin   Pregnant  SkinThick 
 12.644516  20.444870  15.080553   8.405236  21.370252   8.042423   6.450498   7.561652 
barplot(baggingTrained$imp[order(baggingTrained$imp, decreasing = TRUE)], ylim = c(0, 100), main = "Bagging Relative Importance", col = "lightblue")

barplot(baggingTrained10Fold$imp[order(baggingTrained10Fold$imp, decreasing = TRUE)], ylim = c(0, 100), main = "Bagging 10 Fold Cross Validated Relative Importance", col = "lightblue")

barplot(boostTrain$imp[order(boostTrain$imp, decreasing = TRUE)], ylim = c(0, 100), main = "Boosting Relative Importance", col = "lightblue")

barplot(boostTrain10Fold$imp[order(boostTrain10Fold$imp, decreasing = TRUE)], ylim = c(0, 100), main = "Boosting 10 Fold Cross Validated Relative Importance", col = "lightblue")

You can see that these algorithms vary in terms of much the value certain variables. In this case, boosting has much less variance in the weight of each different variable, where bagging shows that GlucoseCon is signifiacntly more important. Accuracy In review:

The highest performing was Baggin with the validation, but we can also evaluate based on Precision.

If we were to conclude our findings here, the best model to use would be Bagging with Validation once again. If we were to continue looking at new models. This first thing I would do is use a different package. The adabag package is very limited in its capabilities. In terms of modelling, the next steps would be to see if we can better predict diabetes if we remove some of the variables that are not found to be important. Another technique we could use, is to change the sample set from the beginning to make sure our sample is representative of the population. If we were to go more in depth, I would like to evaluate these models and further models with ROC curves to better determine their relational accuracy.

LS0tDQp0aXRsZTogIldlZWsgNCBQaW1hIEluZGlhbnMgRGlhYmV0ZXMiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCmF1dGhvcjogSm9obiBOZXZpbGxlDQotLS0NCg0KUHJvbXB0Og0KDQpVc2luZyBQaW1hIEluZGlhbnMgZGlhYmV0ZXMgZGF0YSBzZXQuIA0KUGFydGl0aW9uIHRoZSBkYXRhIHNldCBpbnRvIHRyYWluaW5nIHNldCBhbmQgdGVzdCBzZXQgd2l0aCA4MDoyMCByYXRpb3MuDQoNCisgR2V0IHRvIGtub3cgeW91ciBkYXRhLCBzdGFydCBvdXQgd2l0aCBkYXRhIGV4cGxvcmF0aW9uLiBTdW1tYXJpemUgeW91ciBmaW5kaW5ncy4NCisgVXNlIHRoZSBiYWdnaW5nIG1ldGhvZCAoZS5nLiBhZGFiYWcgIHBhY2thZ2Ugb3IgaXByZWQgcGFja2FnZSkgdG8gdHJhaW4gdGhlIHRyYWluaW5nIGRhdGEgc2V0LiBUaGVuLCBwcmVkaWN0IHRoZSBtb2RlbCBvbiB0aGUgdGVzdCBzZXQuIERpc3BsYXkgdGhlIGNvbmZ1c2lvbiBtYXRyaXgsIGl0cyBhY2N1cmFjeSwgYW5kIGF2ZXJhZ2UgZXJyb3IgZnJvbSB0aGUgcHJlZGljdGVkIHJlc3VsdHMuDQorIFBlcmZvcm0gMTAtZm9sZCBjcm9zcy12YWxpZGF0aW9uIHVzaW5nIGJhZ2dpbmcgYW5kIHJlcG9ydCB0aGUgcGVyZm9ybWFuY2UuIENvbXBhcmUgdGhlIHJlc3VsdCB3aXRoIDIpDQorIFVzZSB0aGUgYm9vc3RpbmcgbWV0aG9kIChlLmcuIGFkYWJhZyBwYWNrYWdlIG9yIGNhcmV0IHBhY2thZ2UpIHRvIHRyYWluIHRoZSB0cmFpbmluZyBkYXRhIHNldC4gVGhlbiwgcHJlZGljdCB0aGUgbW9kZWwgb24gdGhlIHRlc3Qgc2V0LiAgRGlzcGxheSB0aGUgY29uZnVzaW9uIG1hdHJpeCwgaXRzIGFjY3VyYWN5LCBhbmQgYXZlcmFnZSBlcnJvciBmcm9tIHByZWRpY3RlZCByZXN1bHRzLg0KKyBQZXJmb3JtIDEwLWZvbGQgY3Jvc3MtdmFsaWRhdGlvbiB3aXRoIHRoZSBib29zdGluZyBtZXRob2QgYW5kIHJlcG9ydCB0aGUgcGVyZm9ybWFuY2UuIENvbXBhcmUgdGhlIHJlc3VsdCB3aXRoIDQpDQorIENvbXBhcmUgYWxsIHRoZSByZXN1bHRzLiBDb25jbHVkZSBhbmQgZGlzY3VzcyB5b3VyIGZpbmRpbmcuDQorIENvbXBhcmUgdGhlc2UgdHdvIHRlY2huaXF1ZXMuIFdoYXQgaXMgeW91ciBjb25jbHVzaW9uPyBEaXNjdXNzIChpbmNsdWRlIGFueSB0YWJsZXMvZ3JhcGhzIHRoYXQgY29ycmVzcG9uZGluZyB0byB5b3VyIHJlYXNvbmluZykuDQorIEZyb20gdGhlIGFuYWx5c2lzIHJlc3VsdHMsIHdoYXQgYXJlIHlvdXIgcmVjb21tZW5kIGFjdGlvbnM/DQorIFBsZWFzZSBzdWJtaXQgeW91ciByZXBvcnQgYW5kIHNvdXJjZSBjb2RlICgucikgaW4gdGhlIGRyb3AgYm94IGJ5IEFwci4gOQ0KDQpXZSBiZWdpbiB0aGlzIGV4ZXJjaXNlIGJ5IHJlYWRpbmcgdGhlIGRhdGEgaW50byBvdXIgcHJvamVjdCBmcm9tIHRoZSBzaXRlLiAgV2UgYXJlIGFsc28gc3VyZSB0byBhZGQgYXBwcm9wcmlhdGUgbmFtZXMgdG8gdGhlIGRhdGEgZnJhbWUuDQoNCmBgYHtyfQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShkcGx5cikNCg0KZmlsZSA8LSAiaHR0cHM6Ly9hcmNoaXZlLmljcy51Y2kuZWR1L21sL21hY2hpbmUtbGVhcm5pbmctZGF0YWJhc2VzL3BpbWEtaW5kaWFucy1kaWFiZXRlcy9waW1hLWluZGlhbnMtZGlhYmV0ZXMuZGF0YSINCiANCnJhd19kYXRhIDwtIHJlYWQuY3N2KGZpbGUsIGhlYWRlcj1GKQ0KbmFtZXM8LWMoIlByZWduYW50IiwiR2x1Y29zZUNvbiIsIkRpYXN0b2xpYyIsIlNraW5UaGljayIsIkluc3VsaW4iLCJCTUkiLCJEaWFiIiwiQWdlIiwiQ2xhc3MiKQ0KDQpuYW1lcyhyYXdfZGF0YSk8LW5hbWVzDQoNCmBgYA0KDQpUaGUgZmlyc3QgdGhpbmcgdGhlIHByb21wdCBoYXMgdXMgZXhlY3V0ZSwgaXMgc3BsaXR0aW5nIHRoZSBkYXRhIGludG8gYSA4MC0yMCwgdGVzdCBhbmQgdHJhaW4gZGF0YSBzZXQsIHdoaWNoIHdlIGV4ZWN1dGUgYmVsb3c6DQogDQoNCmBgYHtyfQ0Kc2V0LnNlZWQoMjUpICAjIEZvciByZXByb2R1Y2liaWxpdHkNCnNtcGwgPC0gZmxvb3IoMC44MCAqIG5yb3cocmF3X2RhdGEpKSAjIFNwZWNpZnkgcmF0aW8gb2Ygc2FtcGxlIHNwbGl0DQp0cmFpbl9pbmQgPC0gc2FtcGxlKHNlcV9sZW4obnJvdyhyYXdfZGF0YSkpLCBzaXplID0gc21wbCkgIyBNYWtpbmcgdGhlIGluZGV4DQp0cmFpbiA8LSByYXdfZGF0YVt0cmFpbl9pbmQsIF0gIyBBc3NpZ24gdHJhaW5pbmcgZGF0YQ0KdGVzdCA8LSByYXdfZGF0YVstdHJhaW5faW5kLCBdICMgQXNzaWduIHRlc3RpbmcgZGF0YQ0KDQpgYGANCg0KTm93IHRoYXQgd2UgaGF2ZSBvdXIgd29ya2luZyBkYXRhIHNldCwgd2UgY2FuIGJlZ2luIHRvIGV4cGxvcmUgc29tZSBvZiB0aGUgcHJvcGVyaXRlcyB3aXRoIGJhc2ljIGNoYXJ0cyBhbmQgc3VtbWFyaWVzLg0KDQpgYGB7cn0NCnN1bW1hcnkodHJhaW4pDQpzdHIodHJhaW4pDQpwbG90KHRyYWluKQ0KDQphZ2VzPC10cmFpbiAlPiUgZ3JvdXBfYnkoYXMuZmFjdG9yKEFnZSksYXMuZmFjdG9yKENsYXNzKSkgJT4lIHN1bW1hcmlzZShDbGFzcyA9IG4oKSkNCm5hbWVzKGFnZXMpPC1jKCJBZ2UiLCJDbGFzcyIsIk51bWJlck9mUGVvcGxlIikNCmdncGxvdChhZ2VzLGFlcyhBZ2UsTnVtYmVyT2ZQZW9wbGUpKStnZW9tX2JhcihhZXMoZmlsbCA9IENsYXNzKSwgcG9zaXRpb24gPSAiZG9kZ2UiLCBzdGF0PSdpZGVudGl0eScpKyANCiAgc2NhbGVfeF9kaXNjcmV0ZShicmVha3M9c2VxKDIxLCA4MSwgMikpK2xhYnModGl0bGU9Ik51bWJlciBvZiBEaWFiZXRlaWNzIHZzIE5vbi1EaWFiZXRpY3MgYnkgQWdlIikNCg0KcHJlZ3M8LXRyYWluICU+JSBncm91cF9ieShhcy5mYWN0b3IoUHJlZ25hbnQpLGFzLmZhY3RvcihDbGFzcykpICU+JSBzdW1tYXJpc2UoQ2xhc3MgPSBuKCkpDQpuYW1lcyhwcmVncyk8LWMoIlRpbWVzUHJlZ25hbnQiLCJDbGFzcyIsIk51bWJlck9mUGVvcGxlIikNCmdncGxvdChwcmVncyxhZXMoVGltZXNQcmVnbmFudCxOdW1iZXJPZlBlb3BsZSkpK2dlb21fYmFyKGFlcyhmaWxsID0gQ2xhc3MpLCBwb3NpdGlvbiA9ICJkb2RnZSIsIHN0YXQ9J2lkZW50aXR5JykrIA0KICBzY2FsZV94X2Rpc2NyZXRlKGJyZWFrcz1zZXEoMCwgMTcsIDIpKStsYWJzKHRpdGxlPSJOdW1iZXIgb2YgRGlhYmV0ZWljcyB2cyBOb24tRGlhYmV0aWNzIGJ5IE51bWJlciBvZiBUaW1lcyBQcmVnbmFudCIpDQoNCkluczwtdHJhaW4gJT4lIGdyb3VwX2J5KGFzLmZhY3RvcihDbGFzcykpICU+JSBzdW1tYXJpc2UoSW5zdWxpbiA9IG1lYW4oSW5zdWxpbikpDQpuYW1lcyhJbnMpPC1jKCJDbGFzcyIsIkF2Z0luc3VsaW5MZXZlbCIpDQpnZ3Bsb3QoSW5zLGFlcyhDbGFzcyxBdmdJbnN1bGluTGV2ZWwpKStnZW9tX2JhcihzdGF0PSdpZGVudGl0eScpKyANCiBsYWJzKHRpdGxlPSJBdmcgSW5zdWxpbiBMZXZlbHMgZm9yIENsYXNzIikNCg0KYGBgDQoNCg0KSXQgbG9va3MgbGlrZSB0aGVyZSBpcyBhIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGEgZmV3IG9mIHRoZSB2YXJpYWJsZXMgdGhhdCB3ZSBsb29rZWQgYXQsIGJ1dCBub3RoaW5nIG92ZXJ3aGVsbWluZyBzdGFuZHMgb3V0LiAgSW4gdGhlIGdlbmVyYWwgcGxvdHMsIHRoZXJlIGFyZSBzZXZlcmFsIGdpYW50IGNsdXN0ZXJzIHRoYXQgYXJlIGhhcmQgdG8gZGlzdGluZ3Vpc2gsIGJ1dCB0aGVyZSBjb3VsZCBiZSBzb21ldGhpbmcgdGhlcmUuIExldCdzIG5vdyBiZWdpbiB3aXRoIHRoZSAiYWRhYmFnIiBwYWNrYWdlIGFzIHJlY29tbWVuZGVkIGluIHRoZSBwcm9tcHQgdG8gdHJ5IG91ciBoYW5kIGluIGNsYXNzaWZ5aW5nIHRoaXMgZGF0YS4NCmBgYHtyfQ0KbGlicmFyeSgnYWRhYmFnJykNCg0KdHJhaW4kQ2xhc3M8LWFzLmZhY3Rvcih0cmFpbiRDbGFzcykNCmJhZ2dpbmdUcmFpbmVkPC1iYWdnaW5nKENsYXNzfi4sZGF0YT10cmFpbixtZmluYWw9MTAsYm9vcz0gRkFMU0UpDQoNCnRhYmxlKGJhZ2dpbmdUcmFpbmVkJGNsYXNzLHRyYWluJENsYXNzLGRubj1jKCJQcmVkaWN0ZWQgQ2xhc3MiLCJPYnNlcnZlZCBDbGFzcyIpKQ0KDQpgYGANClRoaXMgZGlkIG5vdCBwZXJmb3JtIHZlcnkgd2VsbCBvbiBpdHNlbGYuICBTb21ldGhpbmcgdG8gcG9pbnQgb3V0IGF0IHRoaXMgcG9pbnQgaXMgdGhhdCB0aGVyZSBhcmUgZmFyIG1vcmUgMCBjbGFzc2lmaWNhdGlvbiByZWNvcmRzIHRoYW4gMSdzLiAgVGhpcyBtb2RlbCBhcHBlYXJzIHRvIGhhdmUgdm90ZWQgaGVhdmlseSBmb3IgY2xhc3MgMCB3aGVuIGl0IHNob3VsZCBiZSBjbGFzcyAxLiAgVGhlIG5leHQgc3RlcCBpcyB0byBhcHBseSB0aGlzIG1vZGVsIHRvIHRoZSB0ZXN0IHNldCBmcm9tIGJlZm9yZSBhbmQgZ2V0IGEgZmV3IG1ldHJpY3MgdG8gc2VlIGhvdyBpdCBkb2VzLiAgV2Ugd2lsbCBldmFsdWF0ZSB0aGlzIG1vZGVsIGJhc2VkIG9uIHRoZSBjb25mdXNpb24gbWF0cml4LCBhY2N1cmFjeSwgYW5kIGF2ZXJhZ2UgZXJyb3IuICANCg0KDQoNCg0KYGBge3J9DQpiYWdnaW5nVGVzdDwtIHByZWRpY3QuYmFnZ2luZyhiYWdnaW5nVHJhaW5lZCwgbmV3ZGF0YSA9IHRlc3QpDQpiYWdnaW5nVGVzdCRjb25mdXNpb24NCg0KYmFnZ2luZ1Rlc3QkZXJyb3INCg0KYWNjdXJhY3k8LTEtKDE0KzI3KS8xNTQNCg0KYWNjdXJhY3kNCg0KYGBgDQpUaGlzIHBhY2thZ2UgZG9lcyBub3QgaGF2ZSBhIGdyZWF0IHdheSB0byBsb29rIGF0IGFjY3VhY3ksIHNvIEkgd2lsbCBkbyBhIGZldyBjYWxjdWxhdGlvbnMgbWFudWFsbHkuDQoNClNwZWNpZmljaXR5OiBXaGVuIHRoZXJlIGlzIG5vIGRpYWJldGVzLCBob3cgb2Z0ZW4gZG8gd2UgcHJlZGljdCBubyBkaWFiZXRlcz8NCg0KKyA4Ny8xMDEgPSA4NiUNCg0KUHJlY2lzaW9uOiBXaGVuIHdlIGRpZCBwcmVkaWN0IGRpYWJldGVzLCBob3cgb2Z0ZW4gaXMgaXQgY29ycmVjdD8NCg0KKyAyNi80MCA9IDY1JQ0KDQpUaGlzIG51bWJlciBpcyBwYXJ0aWN1bGFybHkgd2Vhay4NClRoZSBwcm9tcHQgd291bGQgaGF2ZSB1cyBkbyAxMC1mb2xkIGNyb3NzIHZhbGlkYXRpb24gd2l0aCBvdXIgYmFnZ2luZyBtb2RlbC4gIExldCdzIHNlZSBpZiB0aGF0IG1ha2VzIGEgZGlmZmVyZW5jZSBmb3Igb3VyIHByZWNpc2lvbi4NCg0KYGBge3J9DQoNCmJhZ2dpbmdUcmFpbmVkMTBGb2xkPC1iYWdnaW5nKENsYXNzfi4sZGF0YT10cmFpbix2PTEwLG1maW5hbD0xMCxib29zPSBGQUxTRSkNCg0KdGFibGUoYmFnZ2luZ1RyYWluZWQxMEZvbGQkY2xhc3MsdHJhaW4kQ2xhc3MsZG5uPWMoIlByZWRpY3RlZCBDbGFzcyIsIk9ic2VydmVkIENsYXNzIikpDQpiYWdnaW5nVGVzdDEwRm9sZDwtIHByZWRpY3QuYmFnZ2luZyhiYWdnaW5nVHJhaW5lZDEwRm9sZCwgbmV3ZGF0YSA9IHRlc3QpDQpiYWdnaW5nVGVzdDEwRm9sZCRjb25mdXNpb24NCg0KYmFnZ2luZ1Rlc3QxMEZvbGQkZXJyb3INCg0KYWNjdXJhY3k8LTEtKDEyKzI3KS8xNTQNCg0KYWNjdXJhY3kNCmBgYA0KDQoNClNwZWNpZmljaXR5OiBXaGVuIHRoZXJlIGlzIG5vIGRpYWJldGVzLCBob3cgb2Z0ZW4gZG8gd2UgcHJlZGljdCAgbm8gZGlhYmV0ZXM/DQoNCisgODkvMTAxID0gODglDQoNClByZWNpc2lvbjogV2hlbiB3ZSBkaWQgcHJlZGljdCBkaWFiZXRlcywgaG93IG9mdGVuIGlzIGl0IGNvcnJlY3Q/DQoNCisgMjYvMzggPSA2OCUNCg0KVGhpcyBwZXJmb3JtZWQgc2xpZ2h0bHkgYmV0dGVyIHdpdGggMiBmZXdlciBtaXNjbGFzc2lmaWNhdGlvbnMsIGJ1dCBkb2VzIG5vdCB5ZXQgcGVyZm9ybSB3ZWxsLg0KTGV0J3MgbW92ZSB0byBib29zdGluZywgY29udGludWluZyB3aXRoIHRoZSBhZGFiYWcgcGFja2FnZSBmb3IgY29uc2l0ZW5jeS4NCg0KYGBge3J9DQpib29zdFRyYWluIDwtIGJvb3N0aW5nKENsYXNzIH4gLiwgZGF0YSA9IHRyYWluLCBtZmluYWwgPSAxMCkNCg0KdGFibGUoYm9vc3RUcmFpbiRjbGFzcyx0cmFpbiRDbGFzcyxkbm49YygiUHJlZGljdGVkIENsYXNzIiwiT2JzZXJ2ZWQgQ2xhc3MiKSkNCmJvb3N0VGVzdDwtIHByZWRpY3QuYm9vc3RpbmcoYm9vc3RUcmFpbiwgbmV3ZGF0YSA9IHRlc3QpDQpib29zdFRlc3QkY29uZnVzaW9uDQpib29zdFRlc3QkZXJyb3INCmFjY3VyYWN5PC0xLSgxOCsyMykvMTU0DQphY2N1cmFjeQ0KYGBgDQoNCk91ciBib29zdGluZyBzdHVkeSBhcHBlYXJzIHRvIGhhdmUgYWJvdXQgdGhlIHNhbWUgYWNjdXJhY3kgYXMgb3VyIHByZXZpb3VzIGJhZ2dpbmcgbW9kZWxzLg0KT25lIHRoaW5nIHRvIHBvaW50IG91dCBpcyB0aGF0IHdoZW4gY29tcGFyaW5nIHRoZSB0cmFpbmluZyBtb2RlbCB0byB0aGUgdHJhaW5pbmcgY2xhc3NpZmljYXRpb24sIHRoYXQgY29uZnVzaW9uIG1hdHJpeCBhcHBlYXJzIHRoYXQgcmVwcmVzZW50IGEgaGlnaGVyIGFjY3VyYWN5IHRoYXQgb3VyIGJhZ2dpbmcgbW9kZWxzIHJlcHJlc2VudGVkIHdoZW4gbG9va2luZyBhdCB0aGUgdHJhaW5pbmcgZGF0YS4NCg0KU3BlY2lmaWNpdHk6IFdoZW4gdGhlcmUgaXMgbm8gZGlhYmV0ZXMsIGhvdyBvZnRlbiBkbyB3ZSBwcmVkaWN0IG5vIGRpYWJldGVzPw0KDQorIDgzLzEwMSA9IDgyJQ0KDQpQcmVjaXNpb246IFdoZW4gd2UgZGlkIHByZWRpY3QgZGlhYmV0ZXMsIGhvdyBvZnRlbiBpcyBpdCBjb3JyZWN0Pw0KDQorIDMwLzQ4ID0gNjMlDQoNCk9uZSB0YWtlIGF3YXkgZnJvbSB0aGVzZSBtZXRyaWNzIGlzIHRoYXQgdGhpcyBwcmVkaWNpdG9uIGhhZCBtb3JlIGd1ZXNzZXMgZm9yIDEsIGEgcG9zaXRpdmUgZGlhYmV0ZXMgY2xhc3NpZmljYXRpb24sIHRob3VnaCBvdmVyYWxsLCBpdCB3YXMgbGVzcyBhY2N1cmF0ZSBpbiBkb2luZyBzby4gIEl0IGNvdWxkIGJlIHRoZSBjYXNlIHRoYXQgb3VyIG1vZGVsIGlzIG92ZXIgZml0dGVkIGJhc2VkIG9uIG91ciB0cmFpbmluZyBzZXQuICBBcyByZWNvbW1lbmRlZCBpbiB0aGUgcHJvbXB0LCB3ZSBjYW4gdHJ5IHVzaW5nIDEwLWZvbGQgY3Jvc3MgdmFsaWRhdGlvbiB0byBhY2NvdW50IGZvciB0aGlzIHByb2JsZW0uICBMZXQncyBzZWUgaWYgaXQgd29ya3MgZm9yIG91ciBkaWFiZXRlcyBjbGFzc2lmaWNhdGlvbnMuDQoNCmBgYHtyfQ0KYm9vc3RUcmFpbjEwRm9sZCA8LSBib29zdGluZyhDbGFzcyB+IC4sIGRhdGEgPSB0cmFpbix2PTEwLCBtZmluYWwgPSAxMCkNCg0KdGFibGUoYm9vc3RUcmFpbjEwRm9sZCRjbGFzcyx0cmFpbiRDbGFzcyxkbm49YygiUHJlZGljdGVkIENsYXNzIiwiT2JzZXJ2ZWQgQ2xhc3MiKSkNCmJvb3N0VGVzdDEwRm9sZDwtIHByZWRpY3QuYm9vc3RpbmcoYm9vc3RUcmFpbjEwRm9sZCwgbmV3ZGF0YSA9IHRlc3QpDQpib29zdFRlc3QxMEZvbGQkY29uZnVzaW9uDQpib29zdFRlc3QxMEZvbGQkZXJyb3INCmFjY3VyYWN5PC0xLSgyMCsyNCkvMTU0DQphY2N1cmFjeQ0KYGBgDQoNCg0KU3BlY2lmaWNpdHk6IFdoZW4gdGhlcmUgaXMgbm8gZGlhYmV0ZXMsIGhvdyBvZnRlbiBkbyB3ZSBwcmVkaWN0IG5vIGRpYWJldGVzPw0KDQorIDgxLzEwMSA9IDgwJQ0KDQpQcmVjaXNpb246IFdoZW4gd2UgZGlkIHByZWRpY3QgZGlhYmV0ZXMsIGhvdyBvZnRlbiBpcyBpdCBjb3JyZWN0Pw0KDQorIDI5LzQ5ID0gNTklDQoNCkludGVyZXN0aW5nbHksIG91ciBmaXJzdCBleGFtcGxlIGhhZCBoaWdoZXIgcHJlY2lzaW9uIGFuZCBzcGVjaWZpY2l0eS4gIFRoYXQganVzdCBnb2VzIHRvIHNob3cgd2h5IHRoZSAxMC1mb2xkIHZhbGlkYXRpb24gaXMgaW1wb3J0YW50LiAgT1VyIGZpcnN0IG1vZGVsIHBlcmZvcm1lZCBiZXR0ZXIgdGhhbiB3ZSBzaG91bGQgZXhwZWN0Lg0KDQpMZXRzIGNvbXBhcmUgdGhlIHZhcmlhYmxlIGltcG9ydGFuY2Ugd2hlbiBsb29raW5nIGF0IGFsbCA0IG9mIHRoZSBtb2RlbHMgdG8gY29tcGFyZSB3aGF0IHRoZXkgbG9vayBhdCBiZWZvcmUgZXZhbHVhdGluZyB0aGVtIGZvciBwZXJmb3JtYW5jZQ0KDQpgYGB7cn0NCmJhZ2dpbmdUcmFpbmVkJGltcG9ydGFuY2UNCmJhZ2dpbmdUcmFpbmVkMTBGb2xkJGltcG9ydGFuY2UNCmJvb3N0VHJhaW4kaW1wb3J0YW5jZQ0KYm9vc3RUcmFpbjEwRm9sZCRpbXBvcnRhbmNlDQoNCmJhcnBsb3QoYmFnZ2luZ1RyYWluZWQkaW1wW29yZGVyKGJhZ2dpbmdUcmFpbmVkJGltcCwgZGVjcmVhc2luZyA9IFRSVUUpXSwgeWxpbSA9IGMoMCwgMTAwKSwgbWFpbiA9ICJCYWdnaW5nIFJlbGF0aXZlIEltcG9ydGFuY2UiLCBjb2wgPSAibGlnaHRibHVlIikNCg0KYmFycGxvdChiYWdnaW5nVHJhaW5lZDEwRm9sZCRpbXBbb3JkZXIoYmFnZ2luZ1RyYWluZWQxMEZvbGQkaW1wLCBkZWNyZWFzaW5nID0gVFJVRSldLCB5bGltID0gYygwLCAxMDApLCBtYWluID0gIkJhZ2dpbmcgMTAgRm9sZCBDcm9zcyBWYWxpZGF0ZWQgUmVsYXRpdmUgSW1wb3J0YW5jZSIsIGNvbCA9ICJsaWdodGJsdWUiKQ0KDQpiYXJwbG90KGJvb3N0VHJhaW4kaW1wW29yZGVyKGJvb3N0VHJhaW4kaW1wLCBkZWNyZWFzaW5nID0gVFJVRSldLCB5bGltID0gYygwLCAxMDApLCBtYWluID0gIkJvb3N0aW5nIFJlbGF0aXZlIEltcG9ydGFuY2UiLCBjb2wgPSAibGlnaHRibHVlIikNCg0KDQpiYXJwbG90KGJvb3N0VHJhaW4xMEZvbGQkaW1wW29yZGVyKGJvb3N0VHJhaW4xMEZvbGQkaW1wLCBkZWNyZWFzaW5nID0gVFJVRSldLCB5bGltID0gYygwLCAxMDApLCBtYWluID0gIkJvb3N0aW5nIDEwIEZvbGQgQ3Jvc3MgVmFsaWRhdGVkIFJlbGF0aXZlIEltcG9ydGFuY2UiLCBjb2wgPSAibGlnaHRibHVlIikNCg0KYGBgDQoNCllvdSBjYW4gc2VlIHRoYXQgdGhlc2UgYWxnb3JpdGhtcyB2YXJ5IGluIHRlcm1zIG9mIG11Y2ggdGhlIHZhbHVlIGNlcnRhaW4gdmFyaWFibGVzLiAgSW4gdGhpcyBjYXNlLCBib29zdGluZyBoYXMgbXVjaCBsZXNzIHZhcmlhbmNlIGluIHRoZSB3ZWlnaHQgb2YgZWFjaCBkaWZmZXJlbnQgdmFyaWFibGUsIHdoZXJlIGJhZ2dpbmcgc2hvd3MgdGhhdCBHbHVjb3NlQ29uIGlzIHNpZ25pZmlhY250bHkgbW9yZSBpbXBvcnRhbnQuDQpBY2N1cmFjeSBJbiByZXZpZXc6DQoNCisgQmFnZ2luZzogIDczLjQlDQorIEJhZ2dpbmcgdyBWYWxpZGF0aW9uOiAgNzQuNyUNCisgQm9vc3Rpbmc6ICA3My40JQ0KKyBCb29zdGluZyB3IFZhbGlkYXRpb246ICA3MS40JQ0KDQpUaGUgaGlnaGVzdCBwZXJmb3JtaW5nIHdhcyBCYWdnaW4gd2l0aCB0aGUgdmFsaWRhdGlvbiwgYnV0IHdlIGNhbiBhbHNvIGV2YWx1YXRlIGJhc2VkIG9uIFByZWNpc2lvbi4NCg0KKyBCYWdnaW5nOiAgNjUlDQorIEJhZ2dpbmcgdyBWYWxpZGF0aW9uOiAgNjglDQorIEJvb3N0aW5nOiAgNjMlDQorIEJvb3N0aW5nIHcgVmFsaWRhdGlvbjogIDU5JQ0KDQpJZiB3ZSB3ZXJlIHRvIGNvbmNsdWRlIG91ciBmaW5kaW5ncyBoZXJlLCB0aGUgYmVzdCBtb2RlbCB0byB1c2Ugd291bGQgYmUgQmFnZ2luZyB3aXRoIFZhbGlkYXRpb24gb25jZSBhZ2Fpbi4gIElmIHdlIHdlcmUgdG8gY29udGludWUgbG9va2luZyBhdCBuZXcgbW9kZWxzLiAgVGhpcyBmaXJzdCB0aGluZyBJIHdvdWxkIGRvIGlzIHVzZSBhIGRpZmZlcmVudCBwYWNrYWdlLiAgVGhlIGFkYWJhZyBwYWNrYWdlIGlzIHZlcnkgbGltaXRlZCBpbiBpdHMgY2FwYWJpbGl0aWVzLg0KSW4gdGVybXMgb2YgbW9kZWxsaW5nLCB0aGUgbmV4dCBzdGVwcyB3b3VsZCBiZSB0byBzZWUgaWYgd2UgY2FuIGJldHRlciBwcmVkaWN0IGRpYWJldGVzIGlmIHdlIHJlbW92ZSBzb21lIG9mIHRoZSB2YXJpYWJsZXMgdGhhdCBhcmUgbm90IGZvdW5kIHRvIGJlIGltcG9ydGFudC4gIEFub3RoZXIgdGVjaG5pcXVlIHdlIGNvdWxkIHVzZSwgaXMgdG8gY2hhbmdlIHRoZSBzYW1wbGUgc2V0IGZyb20gdGhlIGJlZ2lubmluZyB0byBtYWtlIHN1cmUgb3VyIHNhbXBsZSBpcyByZXByZXNlbnRhdGl2ZSBvZiB0aGUgcG9wdWxhdGlvbi4NCklmIHdlIHdlcmUgdG8gZ28gbW9yZSBpbiBkZXB0aCwgSSB3b3VsZCBsaWtlIHRvIGV2YWx1YXRlIHRoZXNlIG1vZGVscyBhbmQgZnVydGhlciBtb2RlbHMgd2l0aCBST0MgY3VydmVzIHRvIGJldHRlciBkZXRlcm1pbmUgdGhlaXIgcmVsYXRpb25hbCBhY2N1cmFjeS4NCg0KDQo=