Filtered ML fit and the GDSTM with FRESA.CAD

Here we make use of the FRESA.CAD::filteredfit() function to train ML models with and without GDSTM.

Naive-Bayes (NB) and LASSO models are used in this demo.

This scrip uses FRESA.CAD and mlbench R packages:

knitr::opts_chunk$set(collapse = TRUE, warning = FALSE, message = FALSE,comment = "#>")

library("FRESA.CAD")
Loading required package: Rcpp
Loading required package: stringr
Loading required package: miscTools
Loading required package: Hmisc
Loading required package: lattice
Loading required package: survival
Loading required package: Formula
Loading required package: ggplot2
Registered S3 methods overwritten by 'htmltools':
  method               from         
  print.html           tools:rstudio
  print.shiny.tag      tools:rstudio
  print.shiny.tag.list tools:rstudio
Registered S3 method overwritten by 'htmlwidgets':
  method           from         
  print.htmlwidget tools:rstudio
Registered S3 method overwritten by 'data.table':
  method           from
  print.data.table     

Attaching package: ‘Hmisc’

The following objects are masked from ‘package:base’:

    format.pval, units

Loading required package: pROC
Type 'citation("pROC")' for a citation.

Attaching package: ‘pROC’

The following objects are masked from ‘package:stats’:

    cov, smooth, var
library(mlbench)

op <- par(no.readonly = TRUE)

I’ll load the Sonar data set

data("Sonar", package = "mlbench")
print(table(Sonar$Class))

  M   R 
111  97 

Setting some variables for downstream analysis

studyName = "Sonar"
datasetframe <- Sonar
Outcome <- "Class"

# 50% of subjects for training

trainFraction = 0.5

Setting the Training and Testing sets


tb <- table(datasetframe[,Outcome])
classNames <- unique(datasetframe[,Outcome])

allrowClass <- datasetframe[,Outcome]
names(allrowClass) <- rownames(datasetframe)

trainsize <- trainFraction*min(tb);
trainSamples <- NULL;
for (theClass in classNames)
{
  classSample <- allrowClass[allrowClass == theClass]
  trainSamples <- c(trainSamples,names(classSample[sample(length(classSample),trainsize)]))
}


datasetframe_train <- datasetframe[trainSamples,]
testSamples <- !(rownames(datasetframe) %in% trainSamples)
datasetframe_test <- datasetframe[testSamples,]

outcomes <- datasetframe_train[,Outcome]

pander::pander(table(datasetframe[,Outcome]),caption="All")
All
M R
111 97
pander::pander(table(datasetframe_train[,Outcome]),caption="Training")
Training
M R
48 48
pander::pander(table(datasetframe_test[,Outcome]),caption="Testing")
Testing
M R
63 49

Machine Learning with the filteredFit() function

Train a simple NB and LASSO model on the datasets

In FRESA.CAD all Binary classification task assume that the outcome is 0 and 1.


datasetframe_train[,Outcome] <- 1*(datasetframe_train[,Outcome] == classNames[2])
datasetframe_test[,Outcome] <- 1*(datasetframe_test[,Outcome] == classNames[2])

mNBRaw <- filteredFit(paste(Outcome,"~."),
                   datasetframe_train,
                   fitmethod=NAIVE_BAYES,
                     filtermethod=univariate_KS,
                     filtermethod.control=list(pvalue=0.01,limit= 0),
                     pca=FALSE
                   )

mLASSORaw <- filteredFit(paste(Outcome,"~."),
                   datasetframe_train,
                   fitmethod=LASSO_MIN,
                     filtermethod=univariate_KS,
                     filtermethod.control=list(pvalue=0.20,limit= -1),
                    family = "binomial"
                   )

With PCA

# With PCA
mNBPCA <- filteredFit(paste(Outcome,"~."),
                   datasetframe_train,
                   fitmethod=NAIVE_BAYES,
                     filtermethod=univariate_KS,
                     filtermethod.control=list(pvalue=0.01,limit= 0),
                     pca=TRUE
                   )


mLASSOPCA <- filteredFit(paste(Outcome,"~."),
                   datasetframe_train,
                   fitmethod=LASSO_MIN,
                     filtermethod=univariate_KS,
                     filtermethod.control=list(pvalue=0.20,limit= -1),
                     PCA = TRUE,
                    family = "binomial"
                   )

Now we run filteredFit with the decorrelation set to true and default parameters


mNBDecor <- filteredFit(paste(Outcome,"~."),
                   datasetframe_train,
                    fitmethod=NAIVE_BAYES,
                     filtermethod=univariate_KS,
                     filtermethod.control=list(pvalue=0.01,limit= 0),
                     DECOR = TRUE,
                     pca=FALSE
                   )

mLASSODecor <- filteredFit(paste(Outcome,"~."),
                   datasetframe_train,
                    fitmethod=LASSO_MIN,
                     filtermethod=univariate_KS,
                     filtermethod.control=list(pvalue=0.20,limit= -1),
                     DECOR = TRUE,
                    family = "binomial"
                   )

Decorrelation with parameters: Spearman correlation and Robust Fit.

mNBDecor2 <- filteredFit(paste(Outcome,"~."),
                   datasetframe_train,
                    fitmethod=NAIVE_BAYES,
                     filtermethod=univariate_KS,
                     filtermethod.control=list(pvalue=0.01,limit= 0),
                     DECOR = TRUE,
                     DECOR.control=list(method="spearman",type="RLM"),
                     pca=FALSE
                   )
mLASSODecor2 <- filteredFit(paste(Outcome,"~."),
                   datasetframe_train,
                    fitmethod=LASSO_MIN,
                     filtermethod=univariate_KS,
                     filtermethod.control=list(pvalue=0.20,limit= -1),
                     DECOR = TRUE,
                     DECOR.control=list(method="spearman",type="RLM"),
                    family = "binomial"
                   )

Once we have the transformed testing dataset we can make a side by side comparison of predictions


# Predict the raw testing set
prRAW <- predict(mNBRaw,datasetframe_test)

# Predict with PCA
prPCA <- predict(mNBPCA,datasetframe_test)

# Predict the transformed dataset
prDecor <- predict(mNBDecor,datasetframe_test)

# Predict the transformed dataset spearman
prDecor2 <- predict(mNBDecor2,datasetframe_test)

par(mfrow=c(2,2))
AllRocAUC <- NULL;

classoutcomes <- datasetframe_test[,Outcome]
psRaw <- predictionStats_binary(cbind(classoutcomes,prRAW),
                                "NB Raw",cex=0.75)

NB Raw

pander::pander(psRaw$aucs)
est lower upper
0.8578 0.7881 0.9275
AllRocAUC <- rbind(AllRocAUC,psRaw$aucs)

psPCA <- predictionStats_binary(cbind(classoutcomes,prPCA),
                                "NB PCA",cex=0.75)

NB PCA

pander::pander(psPCA$aucs)
est lower upper
0.8202 0.7397 0.9008
AllRocAUC <- rbind(AllRocAUC,psPCA$aucs)

psDecor <- predictionStats_binary(cbind(classoutcomes,prDecor),
                                "NB GDSTM",cex=0.75)

NB GDSTM

pander::pander(psDecor$aucs)
est lower upper
0.8614 0.7946 0.9281
AllRocAUC <- rbind(AllRocAUC,psDecor$aucs);


psDecor2 <- predictionStats_binary(cbind(classoutcomes,prDecor2),
                                "NB GDSTM Spearman",cex=0.75)

NB GDSTM Spearman

pander::pander(psDecor2$aucs)
est lower upper
0.8915 0.83 0.953
AllRocAUC <- rbind(AllRocAUC,psDecor2$aucs);


psRaw <- predictionStats_binary(cbind(classoutcomes,
                                      predict(mLASSORaw,datasetframe_test)),
                                "LASSO Raw",cex=0.75)

LASSO Raw

pander::pander(psRaw$aucs)
est lower upper
0.803 0.7215 0.8846
AllRocAUC <- rbind(AllRocAUC,psRaw$aucs)

psPCA <- predictionStats_binary(cbind(classoutcomes,
                                      predict(mLASSOPCA,datasetframe_test)),
                                "LASSO PCA",cex=0.75)

LASSO PCA

pander::pander(psPCA$aucs)
est lower upper
0.8335 0.7579 0.9091
AllRocAUC <- rbind(AllRocAUC,psPCA$aucs)

psDecor <- predictionStats_binary(cbind(classoutcomes,
                                        predict(mLASSODecor,datasetframe_test)),
                                "LASSO GDSTM",cex=0.75)

LASSO GDSTM

pander::pander(psDecor$aucs)
est lower upper
0.7849 0.6992 0.8706
AllRocAUC <- rbind(AllRocAUC,psDecor$aucs);


psDecor2 <- predictionStats_binary(cbind(classoutcomes,
                                         predict(mLASSODecor2,datasetframe_test)),
                                "LASSO GDSTM Spearman",cex=0.75)

LASSO GDSTM Spearman

pander::pander(psDecor2$aucs)
est lower upper
0.8115 0.7313 0.8916
AllRocAUC <- rbind(AllRocAUC,psDecor2$aucs);

Comparing ROCAUC


rownames(AllRocAUC) <- c("NB:Raw","NB:PCA","NB:GDSTM_P","NB:GDSTM_S",
                         "LASSO:Raw","LASSO:PCA","LASSO:GDSTM_P","LASSO:GDSTM_S")
pander::pander(AllRocAUC)
  est lower upper
NB:Raw 0.8578 0.7881 0.9275
NB:PCA 0.8202 0.7397 0.9008
NB:GDSTM_P 0.8614 0.7946 0.9281
NB:GDSTM_S 0.8915 0.83 0.953
LASSO:Raw 0.803 0.7215 0.8846
LASSO:PCA 0.8335 0.7579 0.9091
LASSO:GDSTM_P 0.7849 0.6992 0.8706
LASSO:GDSTM_S 0.8115 0.7313 0.8916
bpROCAUC <- barPlotCiError(as.matrix(AllRocAUC),
                          metricname = "ROCAUC",
                          thesets = "ROC AUC",
                          themethod = rownames(AllRocAUC),
                          main = "ROC AUC",
                          offsets = c(0.5,1),
                          scoreDirection = ">",
                          ho=0.5,
                          args.legend = list(bg = "white",x="bottomright",inset=c(0.0,0),cex=0.75),
                          col = terrain.colors(nrow(AllRocAUC))
                          )

Visualization of GDSTM

The GDSTM is stored in the filteredFit() object. Hence, we can analyze and display the matrix.


gplots::heatmap.2(mNBDecor$GDSTM,
                  trace = "none",
                  mar = c(10,10),
                  col=rev(heat.colors(7)),
                  main = paste("GDSTM Matrix (Pearson, LM):",studyName),
                  cexRow = 0.7,
                  cexCol = 0.7,
                  key.title=NA,
                  key.xlab="beta",
                  xlab="GDSTM Feature", ylab="Input Feature")


gplots::heatmap.2(mNBDecor2$GDSTM,
                  trace = "none",
                  mar = c(10,10),
                  col=rev(heat.colors(7)),
                  main = paste("GDSTM Matrix (Spearman, RLM):",studyName),
                  cexRow = 0.7,
                  cexCol = 0.7,
                  key.title=NA,
                  key.xlab="beta",
                  xlab="GDSTM Feature", ylab="Input Feature")

Repeated Holdout Cross-Validation




dataCV <- datasetframe
dataCV[,Outcome] <- 1*(dataCV[,Outcome] == classNames[2])


cvNBRaw <- randomCV(dataCV,
                Outcome,
                fittingFunction= filteredFit,
                classSamplingType = "Ba",
                trainFraction = 0.80,
                repetitions = 100,
                fitmethod=NAIVE_BAYES,
                filtermethod=univariate_KS,
                filtermethod.control=list(pvalue=0.01,limit= 0),
                pca = FALSE
            )

……….10 Tested: 193 Avg. Selected: 17.5 Min Tests: 1 Max Tests: 6 Mean Tests: 2.797927 . MAD: 0.2518187 ……….20 Tested: 205 Avg. Selected: 17 Min Tests: 1 Max Tests: 14 Mean Tests: 5.268293 . MAD: 0.2423145 ……….30 Tested: 208 Avg. Selected: 17.93333 Min Tests: 1 Max Tests: 19 Mean Tests: 7.788462 . MAD: 0.2534458 ……….40 Tested: 208 Avg. Selected: 17.8 Min Tests: 2 Max Tests: 21 Mean Tests: 10.38462 . MAD: 0.2568665 ……….50 Tested: 208 Avg. Selected: 17.54 Min Tests: 3 Max Tests: 24 Mean Tests: 12.98077 . MAD: 0.2585082 ……….60 Tested: 208 Avg. Selected: 17.35 Min Tests: 3 Max Tests: 27 Mean Tests: 15.57692 . MAD: 0.2587307 ……….70 Tested: 208 Avg. Selected: 17.18571 Min Tests: 5 Max Tests: 31 Mean Tests: 18.17308 . MAD: 0.2573407 ……….80 Tested: 208 Avg. Selected: 17.25 Min Tests: 8 Max Tests: 36 Mean Tests: 20.76923 . MAD: 0.258488 ……….90 Tested: 208 Avg. Selected: 17.36667 Min Tests: 8 Max Tests: 40 Mean Tests: 23.36538 . MAD: 0.2601201 ……….100 Tested: 208 Avg. Selected: 17.37 Min Tests: 9 Max Tests: 44 Mean Tests: 25.96154 . MAD: 0.2596599

cvNBPCA <- randomCV(dataCV,
                Outcome,
                trainSampleSets= cvNBRaw$trainSamplesSets,
                fittingFunction= filteredFit,
                fitmethod=NAIVE_BAYES,
                filtermethod=univariate_KS,
                filtermethod.control=list(pvalue=0.01,limit= 0),
                pca = TRUE
            )

……….10 Tested: 193 Avg. Selected: 17.5 Min Tests: 1 Max Tests: 6 Mean Tests: 2.797927 . MAD: 0.296886 ……….20 Tested: 205 Avg. Selected: 17 Min Tests: 1 Max Tests: 14 Mean Tests: 5.268293 . MAD: 0.281058 ……….30 Tested: 208 Avg. Selected: 17.93333 Min Tests: 1 Max Tests: 19 Mean Tests: 7.788462 . MAD: 0.2931561 ……….40 Tested: 208 Avg. Selected: 17.8 Min Tests: 2 Max Tests: 21 Mean Tests: 10.38462 . MAD: 0.2915794 ……….50 Tested: 208 Avg. Selected: 17.54 Min Tests: 3 Max Tests: 24 Mean Tests: 12.98077 . MAD: 0.2927341 ……….60 Tested: 208 Avg. Selected: 17.35 Min Tests: 3 Max Tests: 27 Mean Tests: 15.57692 . MAD: 0.2891591 ……….70 Tested: 208 Avg. Selected: 17.18571 Min Tests: 5 Max Tests: 31 Mean Tests: 18.17308 . MAD: 0.2891342 ……….80 Tested: 208 Avg. Selected: 17.25 Min Tests: 8 Max Tests: 36 Mean Tests: 20.76923 . MAD: 0.2840093 ……….90 Tested: 208 Avg. Selected: 17.36667 Min Tests: 8 Max Tests: 40 Mean Tests: 23.36538 . MAD: 0.2848521 ……….100 Tested: 208 Avg. Selected: 17.37 Min Tests: 9 Max Tests: 44 Mean Tests: 25.96154 . MAD: 0.2819397

cvNBDecor <- randomCV(dataCV,
                Outcome,
                trainSampleSets= cvNBRaw$trainSamplesSets,
                fittingFunction= filteredFit,
                fitmethod=NAIVE_BAYES,
                filtermethod=univariate_KS,
                filtermethod.control=list(pvalue=0.01,limit= 0),
                DECOR = TRUE,
                pca = FALSE
            )

……….10 Tested: 193 Avg. Selected: 11.1 Min Tests: 1 Max Tests: 6 Mean Tests: 2.797927 . MAD: 0.2629977 ……….20 Tested: 205 Avg. Selected: 10.55 Min Tests: 1 Max Tests: 14 Mean Tests: 5.268293 . MAD: 0.2479953 ……..no Fast..[ 1 ][ 1 ]….30 Tested: 208 Avg. Selected: 10.56667 Min Tests: 1 Max Tests: 19 Mean Tests: 7.788462 . MAD: 0.2530434 ……….40 Tested: 208 Avg. Selected: 10.725 Min Tests: 2 Max Tests: 21 Mean Tests: 10.38462 . MAD: 0.2596764 ………..no Fast..[ 1 ][ 1 ]…no Fast..[ 1 ][ 1 ]50 Tested: 208 Avg. Selected: 10.68 Min Tests: 3 Max Tests: 24 Mean Tests: 12.98077 . MAD: 0.2616769 ….no Fast..[ 1 ][ 1 ]….no Fast..[ 1 ][ 1 ]…..no Fast..[ 1 ][ 1 ]….no Fast..[ 1 ][ 1 ].60 Tested: 208 Avg. Selected: 10.61667 Min Tests: 3 Max Tests: 27 Mean Tests: 15.57692 . MAD: 0.2612051 …….no Fast..[ 1 ][ 1 ]…..70 Tested: 208 Avg. Selected: 10.55714 Min Tests: 5 Max Tests: 31 Mean Tests: 18.17308 . MAD: 0.2580412 ……….80 Tested: 208 Avg. Selected: 10.5 Min Tests: 8 Max Tests: 36 Mean Tests: 20.76923 . MAD: 0.2561888 ……….90 Tested: 208 Avg. Selected: 10.43333 Min Tests: 8 Max Tests: 40 Mean Tests: 23.36538 . MAD: 0.2576202 ……..no Fast..[ 1 ][ 1 ]….100 Tested: 208 Avg. Selected: 10.5 Min Tests: 9 Max Tests: 44 Mean Tests: 25.96154 . MAD: 0.2570722

The Aggregated Test Results


par(mfrow=c(1,3))
bpraw <- predictionStats_binary(cvNBRaw$testPredictions,"NB RAW",cex=0.75)

NB RAW

bpPCA <- predictionStats_binary(cvNBPCA$testPredictions,"NB PCA",cex=0.75)

NB PCA

bpdecor <- predictionStats_binary(cvNBDecor$testPredictions,"NB GDSTM",cex=0.75)

NB GDSTM

pander::pander(bpraw$aucs)
est lower upper
0.825 0.7671 0.8829
pander::pander(bpPCA$aucs)
est lower upper
0.8649 0.8151 0.9146
pander::pander(bpdecor$aucs)
est lower upper
0.8444 0.7907 0.8982

Using Feature Interactions.


signedsqrt <- function(x) { return (sign(x)*sqrt(abs(x)))}
data("Sonar", package = "mlbench")
sclass <- Sonar$Class


Sonar <- as.data.frame(model.matrix(Class ~ .*.,Sonar))
Sonar$`(Intercept)` <- NULL
Sonar[,1:ncol(Sonar)] <- sapply(Sonar,as.numeric)

fnames <- colnames(Sonar)
fnames <- str_replace_all(fnames," ","_")
fnames <- str_replace_all(fnames,"/","_")
fnames <- str_replace_all(fnames,":","_x_")
colnames(Sonar) <- fnames
squaredfeatures <- str_detect(fnames,"_x_")

Sonar[,squaredfeatures] <- as.data.frame(apply(Sonar[,squaredfeatures],2,signedsqrt));
Sonar$Class <- sclass

datasetframe <- Sonar

Setting the Training and Testing sets



datasetframe_train <- datasetframe[trainSamples,]
datasetframe_test <- datasetframe[testSamples,]

FI: Machine Learning with the filteredFit() function

Train a simple NB and LASSO model on the datasets

In FRESA.CAD all Binary classification task assume that the outcome is 0 and 1.


datasetframe_train[,Outcome] <- 1*(datasetframe_train[,Outcome] == classNames[2])
datasetframe_test[,Outcome] <- 1*(datasetframe_test[,Outcome] == classNames[2])

mNBRaw <- filteredFit(paste(Outcome,"~."),
                   datasetframe_train,
                   fitmethod=NAIVE_BAYES,
                     filtermethod=univariate_KS,
                     filtermethod.control=list(pvalue=0.01,limit= 0),
                     pca=FALSE
                   )

mLASSORaw <- filteredFit(paste(Outcome,"~."),
                   datasetframe_train,
                   fitmethod=LASSO_MIN,
                     filtermethod=univariate_KS,
                     filtermethod.control=list(pvalue=0.20,limit= -1),
                    family = "binomial"
                   )

With PCA

# With PCA
mNBPCA <- filteredFit(paste(Outcome,"~."),
                   datasetframe_train,
                   fitmethod=NAIVE_BAYES,
                     filtermethod=univariate_KS,
                     filtermethod.control=list(pvalue=0.01,limit= 0),
                     pca=TRUE
                   )


mLASSOPCA <- filteredFit(paste(Outcome,"~."),
                   datasetframe_train,
                   fitmethod=LASSO_MIN,
                     filtermethod=univariate_KS,
                     filtermethod.control=list(pvalue=0.20,limit= -1),
                     PCA = TRUE,
                    family = "binomial"
                   )

Now we run filteredFit with the decorrelation set to true and default parameters


mNBDecor <- filteredFit(paste(Outcome,"~."),
                   datasetframe_train,
                    fitmethod=NAIVE_BAYES,
                     filtermethod=univariate_KS,
                     filtermethod.control=list(pvalue=0.01,limit= 0),
                     DECOR = TRUE,
                     pca=FALSE
                   )

mLASSODecor <- filteredFit(paste(Outcome,"~."),
                   datasetframe_train,
                    fitmethod=LASSO_MIN,
                     filtermethod=univariate_KS,
                     filtermethod.control=list(pvalue=0.20,limit= -1),
                     DECOR = TRUE,
                    family = "binomial"
                   )

Decorrelation with parameters: Spearman correlation and Robust Fit.

mNBDecor2 <- filteredFit(paste(Outcome,"~."),
                   datasetframe_train,
                    fitmethod=NAIVE_BAYES,
                     filtermethod=univariate_KS,
                     filtermethod.control=list(pvalue=0.01,limit= 0),
                     DECOR = TRUE,
                     DECOR.control=list(method="spearman",type="RLM"),
                     pca=FALSE
                   )
mLASSODecor2 <- filteredFit(paste(Outcome,"~."),
                   datasetframe_train,
                    fitmethod=LASSO_MIN,
                     filtermethod=univariate_KS,
                     filtermethod.control=list(pvalue=0.20,limit= -1),
                     DECOR = TRUE,
                     DECOR.control=list(method="spearman",type="RLM"),
                    family = "binomial"
                   )

Once we have the transformed testing dataset we can make a side by side comparison of predictions


# Predict the raw testing set
prRAW <- predict(mNBRaw,datasetframe_test)

# Predict with PCA
prPCA <- predict(mNBPCA,datasetframe_test)

# Predict the transformed dataset
prDecor <- predict(mNBDecor,datasetframe_test)

# Predict the transformed dataset spearman
prDecor2 <- predict(mNBDecor2,datasetframe_test)

par(mfrow=c(2,2))
AllRocAUC <- NULL;

classoutcomes <- datasetframe_test[,Outcome]
psRaw <- predictionStats_binary(cbind(classoutcomes,prRAW),
                                "NB Raw",cex=0.75)

NB Raw

pander::pander(psRaw$aucs)
est lower upper
0.8264 0.7507 0.902
AllRocAUC <- rbind(AllRocAUC,psRaw$aucs)

psPCA <- predictionStats_binary(cbind(classoutcomes,prPCA),
                                "NB PCA",cex=0.75)

NB PCA

pander::pander(psPCA$aucs)
est lower upper
0.6276 0.5204 0.7349
AllRocAUC <- rbind(AllRocAUC,psPCA$aucs)

psDecor <- predictionStats_binary(cbind(classoutcomes,prDecor),
                                "NB GDSTM",cex=0.75)

NB GDSTM

pander::pander(psDecor$aucs)
est lower upper
0.8657 0.797 0.9344
AllRocAUC <- rbind(AllRocAUC,psDecor$aucs);


psDecor2 <- predictionStats_binary(cbind(classoutcomes,prDecor2),
                                "NB GDSTM Spearman",cex=0.75)

NB GDSTM Spearman

pander::pander(psDecor2$aucs)
est lower upper
0.856 0.7838 0.9282
AllRocAUC <- rbind(AllRocAUC,psDecor2$aucs);


psRaw <- predictionStats_binary(cbind(classoutcomes,
                                      predict(mLASSORaw,datasetframe_test)),
                                "LASSO Raw",cex=0.75)

LASSO Raw

pander::pander(psRaw$aucs)
est lower upper
0.8503 0.7756 0.9251
AllRocAUC <- rbind(AllRocAUC,psRaw$aucs)

psPCA <- predictionStats_binary(cbind(classoutcomes,
                                      predict(mLASSOPCA,datasetframe_test)),
                                "LASSO PCA",cex=0.75)

LASSO PCA

pander::pander(psPCA$aucs)
est lower upper
0.84 0.7645 0.9155
AllRocAUC <- rbind(AllRocAUC,psPCA$aucs)

psDecor <- predictionStats_binary(cbind(classoutcomes,
                                        predict(mLASSODecor,datasetframe_test)),
                                "LASSO GDSTM",cex=0.75)

LASSO GDSTM

pander::pander(psDecor$aucs)
est lower upper
0.8623 0.7931 0.9315
AllRocAUC <- rbind(AllRocAUC,psDecor$aucs);


psDecor2 <- predictionStats_binary(cbind(classoutcomes,
                                         predict(mLASSODecor2,datasetframe_test)),
                                "LASSO GDSTM Spearman",cex=0.75)

LASSO GDSTM Spearman

pander::pander(psDecor2$aucs)
est lower upper
0.8465 0.776 0.9169
AllRocAUC <- rbind(AllRocAUC,psDecor2$aucs);

FI: Comparing ROCAUC


rownames(AllRocAUC) <- c("NB:Raw","NB:PCA","NB:GDSTM_P","NB:GDSTM_S",
                         "LASSO:Raw","LASSO:PCA","LASSO:GDSTM_P","LASSO:GDSTM_S")
pander::pander(AllRocAUC)
  est lower upper
NB:Raw 0.8264 0.7507 0.902
NB:PCA 0.6276 0.5204 0.7349
NB:GDSTM_P 0.8657 0.797 0.9344
NB:GDSTM_S 0.856 0.7838 0.9282
LASSO:Raw 0.8503 0.7756 0.9251
LASSO:PCA 0.84 0.7645 0.9155
LASSO:GDSTM_P 0.8623 0.7931 0.9315
LASSO:GDSTM_S 0.8465 0.776 0.9169
bpROCAUC <- barPlotCiError(as.matrix(AllRocAUC),
                          metricname = "ROCAUC",
                          thesets = "ROC AUC",
                          themethod = rownames(AllRocAUC),
                          main = "ROC AUC",
                          offsets = c(0.5,1),
                          scoreDirection = ">",
                          ho=0.5,
                          args.legend = list(bg = "white",x="bottomright",inset=c(0.0,0),cex=0.75),
                          col = terrain.colors(nrow(AllRocAUC))
                          )

LS0tDQp0aXRsZTogIkZDQSBhbmQgdGhlIEdEU1RNIg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KIyMgRmlsdGVyZWQgTUwgZml0IGFuZCB0aGUgR0RTVE0gd2l0aCBGUkVTQS5DQUQNCg0KSGVyZSB3ZSBtYWtlIHVzZSBvZiB0aGUgKipGUkVTQS5DQUQ6OmZpbHRlcmVkZml0KCkqKiBmdW5jdGlvbiB0byB0cmFpbiBNTCBtb2RlbHMgd2l0aCBhbmQgd2l0aG91dCBHRFNUTS4NCg0KTmFpdmUtQmF5ZXMgKE5CKSBhbmQgTEFTU08gbW9kZWxzIGFyZSB1c2VkIGluIHRoaXMgZGVtby4NCg0KVGhpcyBzY3JpcCB1c2VzIEZSRVNBLkNBRCBhbmQgbWxiZW5jaCBSIHBhY2thZ2VzOg0KDQpgYGB7ciBmdW5jdGlvbnMsZWNobyA9IFRSVUUgfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGNvbGxhcHNlID0gVFJVRSwgd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0UsY29tbWVudCA9ICIjPiIpDQoNCmxpYnJhcnkoIkZSRVNBLkNBRCIpDQpsaWJyYXJ5KG1sYmVuY2gpDQoNCm9wIDwtIHBhcihuby5yZWFkb25seSA9IFRSVUUpDQoNCmBgYA0KDQpJJ2xsIGxvYWQgdGhlIFNvbmFyIGRhdGEgc2V0DQoNCmBgYHtyfQ0KZGF0YSgiU29uYXIiLCBwYWNrYWdlID0gIm1sYmVuY2giKQ0KcHJpbnQodGFibGUoU29uYXIkQ2xhc3MpKQ0KDQoNCg0KYGBgDQoNClNldHRpbmcgc29tZSB2YXJpYWJsZXMgZm9yIGRvd25zdHJlYW0gYW5hbHlzaXMNCg0KYGBge3J9DQpzdHVkeU5hbWUgPSAiU29uYXIiDQpkYXRhc2V0ZnJhbWUgPC0gU29uYXINCk91dGNvbWUgPC0gIkNsYXNzIg0KDQojIDUwJSBvZiBzdWJqZWN0cyBmb3IgdHJhaW5pbmcNCg0KdHJhaW5GcmFjdGlvbiA9IDAuNQ0KDQpgYGANCg0KU2V0dGluZyB0aGUgVHJhaW5pbmcgYW5kIFRlc3Rpbmcgc2V0cw0KDQpgYGB7ciwgcmVzdWx0cyA9ICJhc2lzIiwgd2FybmluZyA9IEZBTFNFLCBkcGk9NjAwLCBmaWcuaGVpZ2h0PSA2LjAsIGZpZy53aWR0aD0gOC4wfQ0KDQp0YiA8LSB0YWJsZShkYXRhc2V0ZnJhbWVbLE91dGNvbWVdKQ0KY2xhc3NOYW1lcyA8LSB1bmlxdWUoZGF0YXNldGZyYW1lWyxPdXRjb21lXSkNCg0KYWxscm93Q2xhc3MgPC0gZGF0YXNldGZyYW1lWyxPdXRjb21lXQ0KbmFtZXMoYWxscm93Q2xhc3MpIDwtIHJvd25hbWVzKGRhdGFzZXRmcmFtZSkNCg0KdHJhaW5zaXplIDwtIHRyYWluRnJhY3Rpb24qbWluKHRiKTsNCnRyYWluU2FtcGxlcyA8LSBOVUxMOw0KZm9yICh0aGVDbGFzcyBpbiBjbGFzc05hbWVzKQ0Kew0KICBjbGFzc1NhbXBsZSA8LSBhbGxyb3dDbGFzc1thbGxyb3dDbGFzcyA9PSB0aGVDbGFzc10NCiAgdHJhaW5TYW1wbGVzIDwtIGModHJhaW5TYW1wbGVzLG5hbWVzKGNsYXNzU2FtcGxlW3NhbXBsZShsZW5ndGgoY2xhc3NTYW1wbGUpLHRyYWluc2l6ZSldKSkNCn0NCg0KDQpkYXRhc2V0ZnJhbWVfdHJhaW4gPC0gZGF0YXNldGZyYW1lW3RyYWluU2FtcGxlcyxdDQp0ZXN0U2FtcGxlcyA8LSAhKHJvd25hbWVzKGRhdGFzZXRmcmFtZSkgJWluJSB0cmFpblNhbXBsZXMpDQpkYXRhc2V0ZnJhbWVfdGVzdCA8LSBkYXRhc2V0ZnJhbWVbdGVzdFNhbXBsZXMsXQ0KDQpvdXRjb21lcyA8LSBkYXRhc2V0ZnJhbWVfdHJhaW5bLE91dGNvbWVdDQoNCnBhbmRlcjo6cGFuZGVyKHRhYmxlKGRhdGFzZXRmcmFtZVssT3V0Y29tZV0pLGNhcHRpb249IkFsbCIpDQpwYW5kZXI6OnBhbmRlcih0YWJsZShkYXRhc2V0ZnJhbWVfdHJhaW5bLE91dGNvbWVdKSxjYXB0aW9uPSJUcmFpbmluZyIpDQpwYW5kZXI6OnBhbmRlcih0YWJsZShkYXRhc2V0ZnJhbWVfdGVzdFssT3V0Y29tZV0pLGNhcHRpb249IlRlc3RpbmciKQ0KDQoNCmBgYA0KDQojIyBNYWNoaW5lIExlYXJuaW5nIHdpdGggdGhlIGZpbHRlcmVkRml0KCkgZnVuY3Rpb24NCg0KVHJhaW4gYSBzaW1wbGUgTkIgYW5kIExBU1NPIG1vZGVsIG9uIHRoZSBkYXRhc2V0cw0KDQpJbiBGUkVTQS5DQUQgYWxsIEJpbmFyeSBjbGFzc2lmaWNhdGlvbiB0YXNrIGFzc3VtZSB0aGF0IHRoZSBvdXRjb21lIGlzIDAgYW5kIDEuDQoNCmBgYHtyIHJlc3VsdHMgPSAiYXNpcyIsIHdhcm5pbmcgPSBGQUxTRSwgZHBpPTYwMCwgZmlnLmhlaWdodD0gNi4wLCBmaWcud2lkdGg9IDguMH0NCg0KZGF0YXNldGZyYW1lX3RyYWluWyxPdXRjb21lXSA8LSAxKihkYXRhc2V0ZnJhbWVfdHJhaW5bLE91dGNvbWVdID09IGNsYXNzTmFtZXNbMl0pDQpkYXRhc2V0ZnJhbWVfdGVzdFssT3V0Y29tZV0gPC0gMSooZGF0YXNldGZyYW1lX3Rlc3RbLE91dGNvbWVdID09IGNsYXNzTmFtZXNbMl0pDQoNCm1OQlJhdyA8LSBmaWx0ZXJlZEZpdChwYXN0ZShPdXRjb21lLCJ+LiIpLA0KICAgICAgICAgICAgICAgICAgIGRhdGFzZXRmcmFtZV90cmFpbiwNCiAgICAgICAgICAgICAgICAgICBmaXRtZXRob2Q9TkFJVkVfQkFZRVMsDQogICAgICAgICAgICAgICAgICAgICBmaWx0ZXJtZXRob2Q9dW5pdmFyaWF0ZV9LUywNCiAgICAgICAgICAgICAgICAgICAgIGZpbHRlcm1ldGhvZC5jb250cm9sPWxpc3QocHZhbHVlPTAuMDEsbGltaXQ9IDApLA0KICAgICAgICAgICAgICAgICAgICAgcGNhPUZBTFNFDQogICAgICAgICAgICAgICAgICAgKQ0KDQptTEFTU09SYXcgPC0gZmlsdGVyZWRGaXQocGFzdGUoT3V0Y29tZSwifi4iKSwNCiAgICAgICAgICAgICAgICAgICBkYXRhc2V0ZnJhbWVfdHJhaW4sDQogICAgICAgICAgICAgICAgICAgZml0bWV0aG9kPUxBU1NPX01JTiwNCiAgICAgICAgICAgICAgICAgICAgIGZpbHRlcm1ldGhvZD11bml2YXJpYXRlX0tTLA0KICAgICAgICAgICAgICAgICAgICAgZmlsdGVybWV0aG9kLmNvbnRyb2w9bGlzdChwdmFsdWU9MC4yMCxsaW1pdD0gLTEpLA0KICAgICAgICAgICAgICAgICAgICBmYW1pbHkgPSAiYmlub21pYWwiDQogICAgICAgICAgICAgICAgICAgKQ0KDQoNCmBgYA0KDQpXaXRoIFBDQQ0KDQpgYGB7ciByZXN1bHRzID0gImFzaXMiLCB3YXJuaW5nID0gRkFMU0UsIGRwaT02MDAsIGZpZy5oZWlnaHQ9IDYuMCwgZmlnLndpZHRoPSA4LjB9DQojIFdpdGggUENBDQptTkJQQ0EgPC0gZmlsdGVyZWRGaXQocGFzdGUoT3V0Y29tZSwifi4iKSwNCiAgICAgICAgICAgICAgICAgICBkYXRhc2V0ZnJhbWVfdHJhaW4sDQogICAgICAgICAgICAgICAgICAgZml0bWV0aG9kPU5BSVZFX0JBWUVTLA0KICAgICAgICAgICAgICAgICAgICAgZmlsdGVybWV0aG9kPXVuaXZhcmlhdGVfS1MsDQogICAgICAgICAgICAgICAgICAgICBmaWx0ZXJtZXRob2QuY29udHJvbD1saXN0KHB2YWx1ZT0wLjAxLGxpbWl0PSAwKSwNCiAgICAgICAgICAgICAgICAgICAgIHBjYT1UUlVFDQogICAgICAgICAgICAgICAgICAgKQ0KDQoNCm1MQVNTT1BDQSA8LSBmaWx0ZXJlZEZpdChwYXN0ZShPdXRjb21lLCJ+LiIpLA0KICAgICAgICAgICAgICAgICAgIGRhdGFzZXRmcmFtZV90cmFpbiwNCiAgICAgICAgICAgICAgICAgICBmaXRtZXRob2Q9TEFTU09fTUlOLA0KICAgICAgICAgICAgICAgICAgICAgZmlsdGVybWV0aG9kPXVuaXZhcmlhdGVfS1MsDQogICAgICAgICAgICAgICAgICAgICBmaWx0ZXJtZXRob2QuY29udHJvbD1saXN0KHB2YWx1ZT0wLjIwLGxpbWl0PSAtMSksDQogICAgICAgICAgICAgICAgICAgICBQQ0EgPSBUUlVFLA0KICAgICAgICAgICAgICAgICAgICBmYW1pbHkgPSAiYmlub21pYWwiDQogICAgICAgICAgICAgICAgICAgKQ0KYGBgDQoNCk5vdyB3ZSBydW4gZmlsdGVyZWRGaXQgd2l0aCB0aGUgZGVjb3JyZWxhdGlvbiBzZXQgdG8gdHJ1ZSBhbmQgZGVmYXVsdCBwYXJhbWV0ZXJzDQoNCmBgYHtyIHJlc3VsdHMgPSAiYXNpcyIsIHdhcm5pbmcgPSBGQUxTRSwgZHBpPTYwMCwgZmlnLmhlaWdodD0gNi4wLCBmaWcud2lkdGg9IDguMH0NCg0KbU5CRGVjb3IgPC0gZmlsdGVyZWRGaXQocGFzdGUoT3V0Y29tZSwifi4iKSwNCiAgICAgICAgICAgICAgICAgICBkYXRhc2V0ZnJhbWVfdHJhaW4sDQogICAgICAgICAgICAgICAgICAgIGZpdG1ldGhvZD1OQUlWRV9CQVlFUywNCiAgICAgICAgICAgICAgICAgICAgIGZpbHRlcm1ldGhvZD11bml2YXJpYXRlX0tTLA0KICAgICAgICAgICAgICAgICAgICAgZmlsdGVybWV0aG9kLmNvbnRyb2w9bGlzdChwdmFsdWU9MC4wMSxsaW1pdD0gMCksDQogICAgICAgICAgICAgICAgICAgICBERUNPUiA9IFRSVUUsDQogICAgICAgICAgICAgICAgICAgICBwY2E9RkFMU0UNCiAgICAgICAgICAgICAgICAgICApDQoNCm1MQVNTT0RlY29yIDwtIGZpbHRlcmVkRml0KHBhc3RlKE91dGNvbWUsIn4uIiksDQogICAgICAgICAgICAgICAgICAgZGF0YXNldGZyYW1lX3RyYWluLA0KICAgICAgICAgICAgICAgICAgICBmaXRtZXRob2Q9TEFTU09fTUlOLA0KICAgICAgICAgICAgICAgICAgICAgZmlsdGVybWV0aG9kPXVuaXZhcmlhdGVfS1MsDQogICAgICAgICAgICAgICAgICAgICBmaWx0ZXJtZXRob2QuY29udHJvbD1saXN0KHB2YWx1ZT0wLjIwLGxpbWl0PSAtMSksDQogICAgICAgICAgICAgICAgICAgICBERUNPUiA9IFRSVUUsDQogICAgICAgICAgICAgICAgICAgIGZhbWlseSA9ICJiaW5vbWlhbCINCiAgICAgICAgICAgICAgICAgICApDQoNCg0KYGBgDQoNCkRlY29ycmVsYXRpb24gd2l0aCBwYXJhbWV0ZXJzOiBTcGVhcm1hbiBjb3JyZWxhdGlvbiBhbmQgUm9idXN0IEZpdC4NCg0KYGBge3IgcmVzdWx0cyA9ICJhc2lzIiwgd2FybmluZyA9IEZBTFNFLCBkcGk9NjAwLCBmaWcuaGVpZ2h0PSA2LjAsIGZpZy53aWR0aD0gOC4wfQ0KbU5CRGVjb3IyIDwtIGZpbHRlcmVkRml0KHBhc3RlKE91dGNvbWUsIn4uIiksDQogICAgICAgICAgICAgICAgICAgZGF0YXNldGZyYW1lX3RyYWluLA0KICAgICAgICAgICAgICAgICAgICBmaXRtZXRob2Q9TkFJVkVfQkFZRVMsDQogICAgICAgICAgICAgICAgICAgICBmaWx0ZXJtZXRob2Q9dW5pdmFyaWF0ZV9LUywNCiAgICAgICAgICAgICAgICAgICAgIGZpbHRlcm1ldGhvZC5jb250cm9sPWxpc3QocHZhbHVlPTAuMDEsbGltaXQ9IDApLA0KICAgICAgICAgICAgICAgICAgICAgREVDT1IgPSBUUlVFLA0KICAgICAgICAgICAgICAgICAgICAgREVDT1IuY29udHJvbD1saXN0KG1ldGhvZD0ic3BlYXJtYW4iLHR5cGU9IlJMTSIpLA0KICAgICAgICAgICAgICAgICAgICAgcGNhPUZBTFNFDQogICAgICAgICAgICAgICAgICAgKQ0KbUxBU1NPRGVjb3IyIDwtIGZpbHRlcmVkRml0KHBhc3RlKE91dGNvbWUsIn4uIiksDQogICAgICAgICAgICAgICAgICAgZGF0YXNldGZyYW1lX3RyYWluLA0KICAgICAgICAgICAgICAgICAgICBmaXRtZXRob2Q9TEFTU09fTUlOLA0KICAgICAgICAgICAgICAgICAgICAgZmlsdGVybWV0aG9kPXVuaXZhcmlhdGVfS1MsDQogICAgICAgICAgICAgICAgICAgICBmaWx0ZXJtZXRob2QuY29udHJvbD1saXN0KHB2YWx1ZT0wLjIwLGxpbWl0PSAtMSksDQogICAgICAgICAgICAgICAgICAgICBERUNPUiA9IFRSVUUsDQogICAgICAgICAgICAgICAgICAgICBERUNPUi5jb250cm9sPWxpc3QobWV0aG9kPSJzcGVhcm1hbiIsdHlwZT0iUkxNIiksDQogICAgICAgICAgICAgICAgICAgIGZhbWlseSA9ICJiaW5vbWlhbCINCiAgICAgICAgICAgICAgICAgICApDQoNCg0KYGBgDQoNCk9uY2Ugd2UgaGF2ZSB0aGUgdHJhbnNmb3JtZWQgdGVzdGluZyBkYXRhc2V0IHdlIGNhbiBtYWtlIGEgc2lkZSBieSBzaWRlIGNvbXBhcmlzb24gb2YgcHJlZGljdGlvbnMNCg0KYGBge3IgcmVzdWx0cyA9ICJhc2lzIiwgd2FybmluZyA9IEZBTFNFLCBkcGk9NjAwLCBmaWcuaGVpZ2h0PSA2LjAsIGZpZy53aWR0aD0gOC4wfQ0KDQojIFByZWRpY3QgdGhlIHJhdyB0ZXN0aW5nIHNldA0KcHJSQVcgPC0gcHJlZGljdChtTkJSYXcsZGF0YXNldGZyYW1lX3Rlc3QpDQoNCiMgUHJlZGljdCB3aXRoIFBDQQ0KcHJQQ0EgPC0gcHJlZGljdChtTkJQQ0EsZGF0YXNldGZyYW1lX3Rlc3QpDQoNCiMgUHJlZGljdCB0aGUgdHJhbnNmb3JtZWQgZGF0YXNldA0KcHJEZWNvciA8LSBwcmVkaWN0KG1OQkRlY29yLGRhdGFzZXRmcmFtZV90ZXN0KQ0KDQojIFByZWRpY3QgdGhlIHRyYW5zZm9ybWVkIGRhdGFzZXQgc3BlYXJtYW4NCnByRGVjb3IyIDwtIHByZWRpY3QobU5CRGVjb3IyLGRhdGFzZXRmcmFtZV90ZXN0KQ0KDQpwYXIobWZyb3c9YygyLDIpKQ0KQWxsUm9jQVVDIDwtIE5VTEw7DQoNCmNsYXNzb3V0Y29tZXMgPC0gZGF0YXNldGZyYW1lX3Rlc3RbLE91dGNvbWVdDQpwc1JhdyA8LSBwcmVkaWN0aW9uU3RhdHNfYmluYXJ5KGNiaW5kKGNsYXNzb3V0Y29tZXMscHJSQVcpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTkIgUmF3IixjZXg9MC43NSkNCnBhbmRlcjo6cGFuZGVyKHBzUmF3JGF1Y3MpDQpBbGxSb2NBVUMgPC0gcmJpbmQoQWxsUm9jQVVDLHBzUmF3JGF1Y3MpDQoNCnBzUENBIDwtIHByZWRpY3Rpb25TdGF0c19iaW5hcnkoY2JpbmQoY2xhc3NvdXRjb21lcyxwclBDQSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOQiBQQ0EiLGNleD0wLjc1KQ0KcGFuZGVyOjpwYW5kZXIocHNQQ0EkYXVjcykNCkFsbFJvY0FVQyA8LSByYmluZChBbGxSb2NBVUMscHNQQ0EkYXVjcykNCg0KcHNEZWNvciA8LSBwcmVkaWN0aW9uU3RhdHNfYmluYXJ5KGNiaW5kKGNsYXNzb3V0Y29tZXMscHJEZWNvciksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOQiBHRFNUTSIsY2V4PTAuNzUpDQpwYW5kZXI6OnBhbmRlcihwc0RlY29yJGF1Y3MpDQpBbGxSb2NBVUMgPC0gcmJpbmQoQWxsUm9jQVVDLHBzRGVjb3IkYXVjcyk7DQoNCg0KcHNEZWNvcjIgPC0gcHJlZGljdGlvblN0YXRzX2JpbmFyeShjYmluZChjbGFzc291dGNvbWVzLHByRGVjb3IyKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk5CIEdEU1RNIFNwZWFybWFuIixjZXg9MC43NSkNCnBhbmRlcjo6cGFuZGVyKHBzRGVjb3IyJGF1Y3MpDQpBbGxSb2NBVUMgPC0gcmJpbmQoQWxsUm9jQVVDLHBzRGVjb3IyJGF1Y3MpOw0KDQoNCnBzUmF3IDwtIHByZWRpY3Rpb25TdGF0c19iaW5hcnkoY2JpbmQoY2xhc3NvdXRjb21lcywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJlZGljdChtTEFTU09SYXcsZGF0YXNldGZyYW1lX3Rlc3QpKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkxBU1NPIFJhdyIsY2V4PTAuNzUpDQpwYW5kZXI6OnBhbmRlcihwc1JhdyRhdWNzKQ0KQWxsUm9jQVVDIDwtIHJiaW5kKEFsbFJvY0FVQyxwc1JhdyRhdWNzKQ0KDQpwc1BDQSA8LSBwcmVkaWN0aW9uU3RhdHNfYmluYXJ5KGNiaW5kKGNsYXNzb3V0Y29tZXMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByZWRpY3QobUxBU1NPUENBLGRhdGFzZXRmcmFtZV90ZXN0KSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJMQVNTTyBQQ0EiLGNleD0wLjc1KQ0KcGFuZGVyOjpwYW5kZXIocHNQQ0EkYXVjcykNCkFsbFJvY0FVQyA8LSByYmluZChBbGxSb2NBVUMscHNQQ0EkYXVjcykNCg0KcHNEZWNvciA8LSBwcmVkaWN0aW9uU3RhdHNfYmluYXJ5KGNiaW5kKGNsYXNzb3V0Y29tZXMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJlZGljdChtTEFTU09EZWNvcixkYXRhc2V0ZnJhbWVfdGVzdCkpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTEFTU08gR0RTVE0iLGNleD0wLjc1KQ0KcGFuZGVyOjpwYW5kZXIocHNEZWNvciRhdWNzKQ0KQWxsUm9jQVVDIDwtIHJiaW5kKEFsbFJvY0FVQyxwc0RlY29yJGF1Y3MpOw0KDQoNCnBzRGVjb3IyIDwtIHByZWRpY3Rpb25TdGF0c19iaW5hcnkoY2JpbmQoY2xhc3NvdXRjb21lcywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJlZGljdChtTEFTU09EZWNvcjIsZGF0YXNldGZyYW1lX3Rlc3QpKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkxBU1NPIEdEU1RNIFNwZWFybWFuIixjZXg9MC43NSkNCnBhbmRlcjo6cGFuZGVyKHBzRGVjb3IyJGF1Y3MpDQpBbGxSb2NBVUMgPC0gcmJpbmQoQWxsUm9jQVVDLHBzRGVjb3IyJGF1Y3MpOw0KDQpgYGANCg0KIyMgQ29tcGFyaW5nIFJPQ0FVQw0KDQpgYGB7ciByZXN1bHRzID0gImFzaXMiLCB3YXJuaW5nID0gRkFMU0UsIGRwaT02MDAsIGZpZy5oZWlnaHQ9IDYuMCwgZmlnLndpZHRoPSA4LjB9DQoNCnJvd25hbWVzKEFsbFJvY0FVQykgPC0gYygiTkI6UmF3IiwiTkI6UENBIiwiTkI6R0RTVE1fUCIsIk5COkdEU1RNX1MiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICJMQVNTTzpSYXciLCJMQVNTTzpQQ0EiLCJMQVNTTzpHRFNUTV9QIiwiTEFTU086R0RTVE1fUyIpDQpwYW5kZXI6OnBhbmRlcihBbGxSb2NBVUMpDQpicFJPQ0FVQyA8LSBiYXJQbG90Q2lFcnJvcihhcy5tYXRyaXgoQWxsUm9jQVVDKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgbWV0cmljbmFtZSA9ICJST0NBVUMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVzZXRzID0gIlJPQyBBVUMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICB0aGVtZXRob2QgPSByb3duYW1lcyhBbGxSb2NBVUMpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBtYWluID0gIlJPQyBBVUMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBvZmZzZXRzID0gYygwLjUsMSksDQogICAgICAgICAgICAgICAgICAgICAgICAgIHNjb3JlRGlyZWN0aW9uID0gIj4iLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBobz0wLjUsDQogICAgICAgICAgICAgICAgICAgICAgICAgIGFyZ3MubGVnZW5kID0gbGlzdChiZyA9ICJ3aGl0ZSIseD0iYm90dG9tcmlnaHQiLGluc2V0PWMoMC4wLDApLGNleD0wLjc1KSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgY29sID0gdGVycmFpbi5jb2xvcnMobnJvdyhBbGxSb2NBVUMpKQ0KICAgICAgICAgICAgICAgICAgICAgICAgICApDQoNCmBgYA0KDQojIyBWaXN1YWxpemF0aW9uIG9mIEdEU1RNDQoNClRoZSBHRFNUTSBpcyBzdG9yZWQgaW4gdGhlIGZpbHRlcmVkRml0KCkgb2JqZWN0LiBIZW5jZSwgd2UgY2FuIGFuYWx5emUgYW5kIGRpc3BsYXkgdGhlIG1hdHJpeC4NCg0KYGBge3IgcmVzdWx0cyA9ICJhc2lzIiwgd2FybmluZyA9IEZBTFNFLCBkcGk9NjAwLCBmaWcuaGVpZ2h0PSA2LjAsIGZpZy53aWR0aD0gOC4wfQ0KDQpncGxvdHM6OmhlYXRtYXAuMihtTkJEZWNvciRHRFNUTSwNCiAgICAgICAgICAgICAgICAgIHRyYWNlID0gIm5vbmUiLA0KICAgICAgICAgICAgICAgICAgbWFyID0gYygxMCwxMCksDQogICAgICAgICAgICAgICAgICBjb2w9cmV2KGhlYXQuY29sb3JzKDcpKSwNCiAgICAgICAgICAgICAgICAgIG1haW4gPSBwYXN0ZSgiR0RTVE0gTWF0cml4IChQZWFyc29uLCBMTSk6IixzdHVkeU5hbWUpLA0KICAgICAgICAgICAgICAgICAgY2V4Um93ID0gMC43LA0KICAgICAgICAgICAgICAgICAgY2V4Q29sID0gMC43LA0KICAgICAgICAgICAgICAgICAga2V5LnRpdGxlPU5BLA0KICAgICAgICAgICAgICAgICAga2V5LnhsYWI9ImJldGEiLA0KICAgICAgICAgICAgICAgICAgeGxhYj0iR0RTVE0gRmVhdHVyZSIsIHlsYWI9IklucHV0IEZlYXR1cmUiKQ0KDQpncGxvdHM6OmhlYXRtYXAuMihtTkJEZWNvcjIkR0RTVE0sDQogICAgICAgICAgICAgICAgICB0cmFjZSA9ICJub25lIiwNCiAgICAgICAgICAgICAgICAgIG1hciA9IGMoMTAsMTApLA0KICAgICAgICAgICAgICAgICAgY29sPXJldihoZWF0LmNvbG9ycyg3KSksDQogICAgICAgICAgICAgICAgICBtYWluID0gcGFzdGUoIkdEU1RNIE1hdHJpeCAoU3BlYXJtYW4sIFJMTSk6IixzdHVkeU5hbWUpLA0KICAgICAgICAgICAgICAgICAgY2V4Um93ID0gMC43LA0KICAgICAgICAgICAgICAgICAgY2V4Q29sID0gMC43LA0KICAgICAgICAgICAgICAgICAga2V5LnRpdGxlPU5BLA0KICAgICAgICAgICAgICAgICAga2V5LnhsYWI9ImJldGEiLA0KICAgICAgICAgICAgICAgICAgeGxhYj0iR0RTVE0gRmVhdHVyZSIsIHlsYWI9IklucHV0IEZlYXR1cmUiKQ0KYGBgDQoNCiMjIFJlcGVhdGVkIEhvbGRvdXQgQ3Jvc3MtVmFsaWRhdGlvbg0KDQpgYGB7ciByZXN1bHRzID0gImFzaXMiLCB3YXJuaW5nID0gRkFMU0UsIGRwaT02MDAsIGZpZy5oZWlnaHQ9IDYuMCwgZmlnLndpZHRoPSA4LjB9DQoNCg0KDQpkYXRhQ1YgPC0gZGF0YXNldGZyYW1lDQpkYXRhQ1ZbLE91dGNvbWVdIDwtIDEqKGRhdGFDVlssT3V0Y29tZV0gPT0gY2xhc3NOYW1lc1syXSkNCg0KDQpjdk5CUmF3IDwtIHJhbmRvbUNWKGRhdGFDViwNCiAgICAgICAgICAgICAgICBPdXRjb21lLA0KICAgICAgICAgICAgICAgIGZpdHRpbmdGdW5jdGlvbj0gZmlsdGVyZWRGaXQsDQogICAgICAgICAgICAgICAgY2xhc3NTYW1wbGluZ1R5cGUgPSAiQmEiLA0KICAgICAgICAgICAgICAgIHRyYWluRnJhY3Rpb24gPSAwLjgwLA0KICAgICAgICAgICAgICAgIHJlcGV0aXRpb25zID0gMTAwLA0KICAgICAgICAgICAgICAgIGZpdG1ldGhvZD1OQUlWRV9CQVlFUywNCiAgICAgICAgICAgICAgICBmaWx0ZXJtZXRob2Q9dW5pdmFyaWF0ZV9LUywNCiAgICAgICAgICAgICAgICBmaWx0ZXJtZXRob2QuY29udHJvbD1saXN0KHB2YWx1ZT0wLjAxLGxpbWl0PSAwKSwNCiAgICAgICAgICAgICAgICBwY2EgPSBGQUxTRQ0KICAgICAgICAgICAgKQ0KDQpjdk5CUENBIDwtIHJhbmRvbUNWKGRhdGFDViwNCiAgICAgICAgICAgICAgICBPdXRjb21lLA0KICAgICAgICAgICAgICAgIHRyYWluU2FtcGxlU2V0cz0gY3ZOQlJhdyR0cmFpblNhbXBsZXNTZXRzLA0KICAgICAgICAgICAgICAgIGZpdHRpbmdGdW5jdGlvbj0gZmlsdGVyZWRGaXQsDQogICAgICAgICAgICAgICAgZml0bWV0aG9kPU5BSVZFX0JBWUVTLA0KICAgICAgICAgICAgICAgIGZpbHRlcm1ldGhvZD11bml2YXJpYXRlX0tTLA0KICAgICAgICAgICAgICAgIGZpbHRlcm1ldGhvZC5jb250cm9sPWxpc3QocHZhbHVlPTAuMDEsbGltaXQ9IDApLA0KICAgICAgICAgICAgICAgIHBjYSA9IFRSVUUNCiAgICAgICAgICAgICkNCg0KY3ZOQkRlY29yIDwtIHJhbmRvbUNWKGRhdGFDViwNCiAgICAgICAgICAgICAgICBPdXRjb21lLA0KICAgICAgICAgICAgICAgIHRyYWluU2FtcGxlU2V0cz0gY3ZOQlJhdyR0cmFpblNhbXBsZXNTZXRzLA0KICAgICAgICAgICAgICAgIGZpdHRpbmdGdW5jdGlvbj0gZmlsdGVyZWRGaXQsDQogICAgICAgICAgICAgICAgZml0bWV0aG9kPU5BSVZFX0JBWUVTLA0KICAgICAgICAgICAgICAgIGZpbHRlcm1ldGhvZD11bml2YXJpYXRlX0tTLA0KICAgICAgICAgICAgICAgIGZpbHRlcm1ldGhvZC5jb250cm9sPWxpc3QocHZhbHVlPTAuMDEsbGltaXQ9IDApLA0KICAgICAgICAgICAgICAgIERFQ09SID0gVFJVRSwNCiAgICAgICAgICAgICAgICBwY2EgPSBGQUxTRQ0KICAgICAgICAgICAgKQ0KDQoNCg0KYGBgDQoNClRoZSBBZ2dyZWdhdGVkIFRlc3QgUmVzdWx0cw0KDQpgYGB7ciByZXN1bHRzID0gImFzaXMiLCB3YXJuaW5nID0gRkFMU0UsIGRwaT02MDAsIGZpZy5oZWlnaHQ9IDQuMCwgZmlnLndpZHRoPSA4LjB9DQoNCnBhcihtZnJvdz1jKDEsMykpDQpicHJhdyA8LSBwcmVkaWN0aW9uU3RhdHNfYmluYXJ5KGN2TkJSYXckdGVzdFByZWRpY3Rpb25zLCJOQiBSQVciLGNleD0wLjc1KQ0KYnBQQ0EgPC0gcHJlZGljdGlvblN0YXRzX2JpbmFyeShjdk5CUENBJHRlc3RQcmVkaWN0aW9ucywiTkIgUENBIixjZXg9MC43NSkNCmJwZGVjb3IgPC0gcHJlZGljdGlvblN0YXRzX2JpbmFyeShjdk5CRGVjb3IkdGVzdFByZWRpY3Rpb25zLCJOQiBHRFNUTSIsY2V4PTAuNzUpDQoNCnBhbmRlcjo6cGFuZGVyKGJwcmF3JGF1Y3MpDQpwYW5kZXI6OnBhbmRlcihicFBDQSRhdWNzKQ0KcGFuZGVyOjpwYW5kZXIoYnBkZWNvciRhdWNzKQ0KYGBgDQoNCiMjIFVzaW5nIEZlYXR1cmUgSW50ZXJhY3Rpb25zLg0KDQpgYGB7cn0NCg0Kc2lnbmVkc3FydCA8LSBmdW5jdGlvbih4KSB7IHJldHVybiAoc2lnbih4KSpzcXJ0KGFicyh4KSkpfQ0KZGF0YSgiU29uYXIiLCBwYWNrYWdlID0gIm1sYmVuY2giKQ0Kc2NsYXNzIDwtIFNvbmFyJENsYXNzDQoNCg0KU29uYXIgPC0gYXMuZGF0YS5mcmFtZShtb2RlbC5tYXRyaXgoQ2xhc3MgfiAuKi4sU29uYXIpKQ0KU29uYXIkYChJbnRlcmNlcHQpYCA8LSBOVUxMDQpTb25hclssMTpuY29sKFNvbmFyKV0gPC0gc2FwcGx5KFNvbmFyLGFzLm51bWVyaWMpDQoNCmZuYW1lcyA8LSBjb2xuYW1lcyhTb25hcikNCmZuYW1lcyA8LSBzdHJfcmVwbGFjZV9hbGwoZm5hbWVzLCIgIiwiXyIpDQpmbmFtZXMgPC0gc3RyX3JlcGxhY2VfYWxsKGZuYW1lcywiLyIsIl8iKQ0KZm5hbWVzIDwtIHN0cl9yZXBsYWNlX2FsbChmbmFtZXMsIjoiLCJfeF8iKQ0KY29sbmFtZXMoU29uYXIpIDwtIGZuYW1lcw0Kc3F1YXJlZGZlYXR1cmVzIDwtIHN0cl9kZXRlY3QoZm5hbWVzLCJfeF8iKQ0KDQpTb25hclssc3F1YXJlZGZlYXR1cmVzXSA8LSBhcy5kYXRhLmZyYW1lKGFwcGx5KFNvbmFyWyxzcXVhcmVkZmVhdHVyZXNdLDIsc2lnbmVkc3FydCkpOw0KU29uYXIkQ2xhc3MgPC0gc2NsYXNzDQoNCmRhdGFzZXRmcmFtZSA8LSBTb25hcg0KDQpgYGANCg0KU2V0dGluZyB0aGUgVHJhaW5pbmcgYW5kIFRlc3Rpbmcgc2V0cw0KDQpgYGB7ciwgcmVzdWx0cyA9ICJhc2lzIiwgd2FybmluZyA9IEZBTFNFLCBkcGk9NjAwLCBmaWcuaGVpZ2h0PSA2LjAsIGZpZy53aWR0aD0gOC4wfQ0KDQoNCmRhdGFzZXRmcmFtZV90cmFpbiA8LSBkYXRhc2V0ZnJhbWVbdHJhaW5TYW1wbGVzLF0NCmRhdGFzZXRmcmFtZV90ZXN0IDwtIGRhdGFzZXRmcmFtZVt0ZXN0U2FtcGxlcyxdDQoNCg0KDQpgYGANCg0KIyMjIEZJOiBNYWNoaW5lIExlYXJuaW5nIHdpdGggdGhlIGZpbHRlcmVkRml0KCkgZnVuY3Rpb24NCg0KVHJhaW4gYSBzaW1wbGUgTkIgYW5kIExBU1NPIG1vZGVsIG9uIHRoZSBkYXRhc2V0cw0KDQpJbiBGUkVTQS5DQUQgYWxsIEJpbmFyeSBjbGFzc2lmaWNhdGlvbiB0YXNrIGFzc3VtZSB0aGF0IHRoZSBvdXRjb21lIGlzIDAgYW5kIDEuDQoNCmBgYHtyIHJlc3VsdHMgPSAiYXNpcyIsIHdhcm5pbmcgPSBGQUxTRSwgZHBpPTYwMCwgZmlnLmhlaWdodD0gNi4wLCBmaWcud2lkdGg9IDguMH0NCg0KZGF0YXNldGZyYW1lX3RyYWluWyxPdXRjb21lXSA8LSAxKihkYXRhc2V0ZnJhbWVfdHJhaW5bLE91dGNvbWVdID09IGNsYXNzTmFtZXNbMl0pDQpkYXRhc2V0ZnJhbWVfdGVzdFssT3V0Y29tZV0gPC0gMSooZGF0YXNldGZyYW1lX3Rlc3RbLE91dGNvbWVdID09IGNsYXNzTmFtZXNbMl0pDQoNCm1OQlJhdyA8LSBmaWx0ZXJlZEZpdChwYXN0ZShPdXRjb21lLCJ+LiIpLA0KICAgICAgICAgICAgICAgICAgIGRhdGFzZXRmcmFtZV90cmFpbiwNCiAgICAgICAgICAgICAgICAgICBmaXRtZXRob2Q9TkFJVkVfQkFZRVMsDQogICAgICAgICAgICAgICAgICAgICBmaWx0ZXJtZXRob2Q9dW5pdmFyaWF0ZV9LUywNCiAgICAgICAgICAgICAgICAgICAgIGZpbHRlcm1ldGhvZC5jb250cm9sPWxpc3QocHZhbHVlPTAuMDEsbGltaXQ9IDApLA0KICAgICAgICAgICAgICAgICAgICAgcGNhPUZBTFNFDQogICAgICAgICAgICAgICAgICAgKQ0KDQptTEFTU09SYXcgPC0gZmlsdGVyZWRGaXQocGFzdGUoT3V0Y29tZSwifi4iKSwNCiAgICAgICAgICAgICAgICAgICBkYXRhc2V0ZnJhbWVfdHJhaW4sDQogICAgICAgICAgICAgICAgICAgZml0bWV0aG9kPUxBU1NPX01JTiwNCiAgICAgICAgICAgICAgICAgICAgIGZpbHRlcm1ldGhvZD11bml2YXJpYXRlX0tTLA0KICAgICAgICAgICAgICAgICAgICAgZmlsdGVybWV0aG9kLmNvbnRyb2w9bGlzdChwdmFsdWU9MC4yMCxsaW1pdD0gLTEpLA0KICAgICAgICAgICAgICAgICAgICBmYW1pbHkgPSAiYmlub21pYWwiDQogICAgICAgICAgICAgICAgICAgKQ0KDQoNCmBgYA0KDQpXaXRoIFBDQQ0KDQpgYGB7ciByZXN1bHRzID0gImFzaXMiLCB3YXJuaW5nID0gRkFMU0UsIGRwaT02MDAsIGZpZy5oZWlnaHQ9IDYuMCwgZmlnLndpZHRoPSA4LjB9DQojIFdpdGggUENBDQptTkJQQ0EgPC0gZmlsdGVyZWRGaXQocGFzdGUoT3V0Y29tZSwifi4iKSwNCiAgICAgICAgICAgICAgICAgICBkYXRhc2V0ZnJhbWVfdHJhaW4sDQogICAgICAgICAgICAgICAgICAgZml0bWV0aG9kPU5BSVZFX0JBWUVTLA0KICAgICAgICAgICAgICAgICAgICAgZmlsdGVybWV0aG9kPXVuaXZhcmlhdGVfS1MsDQogICAgICAgICAgICAgICAgICAgICBmaWx0ZXJtZXRob2QuY29udHJvbD1saXN0KHB2YWx1ZT0wLjAxLGxpbWl0PSAwKSwNCiAgICAgICAgICAgICAgICAgICAgIHBjYT1UUlVFDQogICAgICAgICAgICAgICAgICAgKQ0KDQoNCm1MQVNTT1BDQSA8LSBmaWx0ZXJlZEZpdChwYXN0ZShPdXRjb21lLCJ+LiIpLA0KICAgICAgICAgICAgICAgICAgIGRhdGFzZXRmcmFtZV90cmFpbiwNCiAgICAgICAgICAgICAgICAgICBmaXRtZXRob2Q9TEFTU09fTUlOLA0KICAgICAgICAgICAgICAgICAgICAgZmlsdGVybWV0aG9kPXVuaXZhcmlhdGVfS1MsDQogICAgICAgICAgICAgICAgICAgICBmaWx0ZXJtZXRob2QuY29udHJvbD1saXN0KHB2YWx1ZT0wLjIwLGxpbWl0PSAtMSksDQogICAgICAgICAgICAgICAgICAgICBQQ0EgPSBUUlVFLA0KICAgICAgICAgICAgICAgICAgICBmYW1pbHkgPSAiYmlub21pYWwiDQogICAgICAgICAgICAgICAgICAgKQ0KYGBgDQoNCk5vdyB3ZSBydW4gZmlsdGVyZWRGaXQgd2l0aCB0aGUgZGVjb3JyZWxhdGlvbiBzZXQgdG8gdHJ1ZSBhbmQgZGVmYXVsdCBwYXJhbWV0ZXJzDQoNCmBgYHtyIHJlc3VsdHMgPSAiYXNpcyIsIHdhcm5pbmcgPSBGQUxTRSwgZHBpPTYwMCwgZmlnLmhlaWdodD0gNi4wLCBmaWcud2lkdGg9IDguMH0NCg0KbU5CRGVjb3IgPC0gZmlsdGVyZWRGaXQocGFzdGUoT3V0Y29tZSwifi4iKSwNCiAgICAgICAgICAgICAgICAgICBkYXRhc2V0ZnJhbWVfdHJhaW4sDQogICAgICAgICAgICAgICAgICAgIGZpdG1ldGhvZD1OQUlWRV9CQVlFUywNCiAgICAgICAgICAgICAgICAgICAgIGZpbHRlcm1ldGhvZD11bml2YXJpYXRlX0tTLA0KICAgICAgICAgICAgICAgICAgICAgZmlsdGVybWV0aG9kLmNvbnRyb2w9bGlzdChwdmFsdWU9MC4wMSxsaW1pdD0gMCksDQogICAgICAgICAgICAgICAgICAgICBERUNPUiA9IFRSVUUsDQogICAgICAgICAgICAgICAgICAgICBwY2E9RkFMU0UNCiAgICAgICAgICAgICAgICAgICApDQoNCm1MQVNTT0RlY29yIDwtIGZpbHRlcmVkRml0KHBhc3RlKE91dGNvbWUsIn4uIiksDQogICAgICAgICAgICAgICAgICAgZGF0YXNldGZyYW1lX3RyYWluLA0KICAgICAgICAgICAgICAgICAgICBmaXRtZXRob2Q9TEFTU09fTUlOLA0KICAgICAgICAgICAgICAgICAgICAgZmlsdGVybWV0aG9kPXVuaXZhcmlhdGVfS1MsDQogICAgICAgICAgICAgICAgICAgICBmaWx0ZXJtZXRob2QuY29udHJvbD1saXN0KHB2YWx1ZT0wLjIwLGxpbWl0PSAtMSksDQogICAgICAgICAgICAgICAgICAgICBERUNPUiA9IFRSVUUsDQogICAgICAgICAgICAgICAgICAgIGZhbWlseSA9ICJiaW5vbWlhbCINCiAgICAgICAgICAgICAgICAgICApDQoNCg0KYGBgDQoNCkRlY29ycmVsYXRpb24gd2l0aCBwYXJhbWV0ZXJzOiBTcGVhcm1hbiBjb3JyZWxhdGlvbiBhbmQgUm9idXN0IEZpdC4NCg0KYGBge3IgcmVzdWx0cyA9ICJhc2lzIiwgd2FybmluZyA9IEZBTFNFLCBkcGk9NjAwLCBmaWcuaGVpZ2h0PSA2LjAsIGZpZy53aWR0aD0gOC4wfQ0KbU5CRGVjb3IyIDwtIGZpbHRlcmVkRml0KHBhc3RlKE91dGNvbWUsIn4uIiksDQogICAgICAgICAgICAgICAgICAgZGF0YXNldGZyYW1lX3RyYWluLA0KICAgICAgICAgICAgICAgICAgICBmaXRtZXRob2Q9TkFJVkVfQkFZRVMsDQogICAgICAgICAgICAgICAgICAgICBmaWx0ZXJtZXRob2Q9dW5pdmFyaWF0ZV9LUywNCiAgICAgICAgICAgICAgICAgICAgIGZpbHRlcm1ldGhvZC5jb250cm9sPWxpc3QocHZhbHVlPTAuMDEsbGltaXQ9IDApLA0KICAgICAgICAgICAgICAgICAgICAgREVDT1IgPSBUUlVFLA0KICAgICAgICAgICAgICAgICAgICAgREVDT1IuY29udHJvbD1saXN0KG1ldGhvZD0ic3BlYXJtYW4iLHR5cGU9IlJMTSIpLA0KICAgICAgICAgICAgICAgICAgICAgcGNhPUZBTFNFDQogICAgICAgICAgICAgICAgICAgKQ0KbUxBU1NPRGVjb3IyIDwtIGZpbHRlcmVkRml0KHBhc3RlKE91dGNvbWUsIn4uIiksDQogICAgICAgICAgICAgICAgICAgZGF0YXNldGZyYW1lX3RyYWluLA0KICAgICAgICAgICAgICAgICAgICBmaXRtZXRob2Q9TEFTU09fTUlOLA0KICAgICAgICAgICAgICAgICAgICAgZmlsdGVybWV0aG9kPXVuaXZhcmlhdGVfS1MsDQogICAgICAgICAgICAgICAgICAgICBmaWx0ZXJtZXRob2QuY29udHJvbD1saXN0KHB2YWx1ZT0wLjIwLGxpbWl0PSAtMSksDQogICAgICAgICAgICAgICAgICAgICBERUNPUiA9IFRSVUUsDQogICAgICAgICAgICAgICAgICAgICBERUNPUi5jb250cm9sPWxpc3QobWV0aG9kPSJzcGVhcm1hbiIsdHlwZT0iUkxNIiksDQogICAgICAgICAgICAgICAgICAgIGZhbWlseSA9ICJiaW5vbWlhbCINCiAgICAgICAgICAgICAgICAgICApDQoNCg0KYGBgDQoNCk9uY2Ugd2UgaGF2ZSB0aGUgdHJhbnNmb3JtZWQgdGVzdGluZyBkYXRhc2V0IHdlIGNhbiBtYWtlIGEgc2lkZSBieSBzaWRlIGNvbXBhcmlzb24gb2YgcHJlZGljdGlvbnMNCg0KYGBge3IgcmVzdWx0cyA9ICJhc2lzIiwgd2FybmluZyA9IEZBTFNFLCBkcGk9NjAwLCBmaWcuaGVpZ2h0PSA2LjAsIGZpZy53aWR0aD0gOC4wfQ0KDQojIFByZWRpY3QgdGhlIHJhdyB0ZXN0aW5nIHNldA0KcHJSQVcgPC0gcHJlZGljdChtTkJSYXcsZGF0YXNldGZyYW1lX3Rlc3QpDQoNCiMgUHJlZGljdCB3aXRoIFBDQQ0KcHJQQ0EgPC0gcHJlZGljdChtTkJQQ0EsZGF0YXNldGZyYW1lX3Rlc3QpDQoNCiMgUHJlZGljdCB0aGUgdHJhbnNmb3JtZWQgZGF0YXNldA0KcHJEZWNvciA8LSBwcmVkaWN0KG1OQkRlY29yLGRhdGFzZXRmcmFtZV90ZXN0KQ0KDQojIFByZWRpY3QgdGhlIHRyYW5zZm9ybWVkIGRhdGFzZXQgc3BlYXJtYW4NCnByRGVjb3IyIDwtIHByZWRpY3QobU5CRGVjb3IyLGRhdGFzZXRmcmFtZV90ZXN0KQ0KDQpwYXIobWZyb3c9YygyLDIpKQ0KQWxsUm9jQVVDIDwtIE5VTEw7DQoNCmNsYXNzb3V0Y29tZXMgPC0gZGF0YXNldGZyYW1lX3Rlc3RbLE91dGNvbWVdDQpwc1JhdyA8LSBwcmVkaWN0aW9uU3RhdHNfYmluYXJ5KGNiaW5kKGNsYXNzb3V0Y29tZXMscHJSQVcpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTkIgUmF3IixjZXg9MC43NSkNCnBhbmRlcjo6cGFuZGVyKHBzUmF3JGF1Y3MpDQpBbGxSb2NBVUMgPC0gcmJpbmQoQWxsUm9jQVVDLHBzUmF3JGF1Y3MpDQoNCnBzUENBIDwtIHByZWRpY3Rpb25TdGF0c19iaW5hcnkoY2JpbmQoY2xhc3NvdXRjb21lcyxwclBDQSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOQiBQQ0EiLGNleD0wLjc1KQ0KcGFuZGVyOjpwYW5kZXIocHNQQ0EkYXVjcykNCkFsbFJvY0FVQyA8LSByYmluZChBbGxSb2NBVUMscHNQQ0EkYXVjcykNCg0KcHNEZWNvciA8LSBwcmVkaWN0aW9uU3RhdHNfYmluYXJ5KGNiaW5kKGNsYXNzb3V0Y29tZXMscHJEZWNvciksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJOQiBHRFNUTSIsY2V4PTAuNzUpDQpwYW5kZXI6OnBhbmRlcihwc0RlY29yJGF1Y3MpDQpBbGxSb2NBVUMgPC0gcmJpbmQoQWxsUm9jQVVDLHBzRGVjb3IkYXVjcyk7DQoNCg0KcHNEZWNvcjIgPC0gcHJlZGljdGlvblN0YXRzX2JpbmFyeShjYmluZChjbGFzc291dGNvbWVzLHByRGVjb3IyKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk5CIEdEU1RNIFNwZWFybWFuIixjZXg9MC43NSkNCnBhbmRlcjo6cGFuZGVyKHBzRGVjb3IyJGF1Y3MpDQpBbGxSb2NBVUMgPC0gcmJpbmQoQWxsUm9jQVVDLHBzRGVjb3IyJGF1Y3MpOw0KDQoNCnBzUmF3IDwtIHByZWRpY3Rpb25TdGF0c19iaW5hcnkoY2JpbmQoY2xhc3NvdXRjb21lcywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJlZGljdChtTEFTU09SYXcsZGF0YXNldGZyYW1lX3Rlc3QpKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkxBU1NPIFJhdyIsY2V4PTAuNzUpDQpwYW5kZXI6OnBhbmRlcihwc1JhdyRhdWNzKQ0KQWxsUm9jQVVDIDwtIHJiaW5kKEFsbFJvY0FVQyxwc1JhdyRhdWNzKQ0KDQpwc1BDQSA8LSBwcmVkaWN0aW9uU3RhdHNfYmluYXJ5KGNiaW5kKGNsYXNzb3V0Y29tZXMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByZWRpY3QobUxBU1NPUENBLGRhdGFzZXRmcmFtZV90ZXN0KSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJMQVNTTyBQQ0EiLGNleD0wLjc1KQ0KcGFuZGVyOjpwYW5kZXIocHNQQ0EkYXVjcykNCkFsbFJvY0FVQyA8LSByYmluZChBbGxSb2NBVUMscHNQQ0EkYXVjcykNCg0KcHNEZWNvciA8LSBwcmVkaWN0aW9uU3RhdHNfYmluYXJ5KGNiaW5kKGNsYXNzb3V0Y29tZXMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJlZGljdChtTEFTU09EZWNvcixkYXRhc2V0ZnJhbWVfdGVzdCkpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiTEFTU08gR0RTVE0iLGNleD0wLjc1KQ0KcGFuZGVyOjpwYW5kZXIocHNEZWNvciRhdWNzKQ0KQWxsUm9jQVVDIDwtIHJiaW5kKEFsbFJvY0FVQyxwc0RlY29yJGF1Y3MpOw0KDQoNCnBzRGVjb3IyIDwtIHByZWRpY3Rpb25TdGF0c19iaW5hcnkoY2JpbmQoY2xhc3NvdXRjb21lcywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJlZGljdChtTEFTU09EZWNvcjIsZGF0YXNldGZyYW1lX3Rlc3QpKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkxBU1NPIEdEU1RNIFNwZWFybWFuIixjZXg9MC43NSkNCnBhbmRlcjo6cGFuZGVyKHBzRGVjb3IyJGF1Y3MpDQpBbGxSb2NBVUMgPC0gcmJpbmQoQWxsUm9jQVVDLHBzRGVjb3IyJGF1Y3MpOw0KDQpgYGANCg0KIyMgRkk6IENvbXBhcmluZyBST0NBVUMNCg0KYGBge3IgcmVzdWx0cyA9ICJhc2lzIiwgd2FybmluZyA9IEZBTFNFLCBkcGk9NjAwLCBmaWcuaGVpZ2h0PSA2LjAsIGZpZy53aWR0aD0gOC4wfQ0KDQpyb3duYW1lcyhBbGxSb2NBVUMpIDwtIGMoIk5COlJhdyIsIk5COlBDQSIsIk5COkdEU1RNX1AiLCJOQjpHRFNUTV9TIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAiTEFTU086UmF3IiwiTEFTU086UENBIiwiTEFTU086R0RTVE1fUCIsIkxBU1NPOkdEU1RNX1MiKQ0KcGFuZGVyOjpwYW5kZXIoQWxsUm9jQVVDKQ0KYnBST0NBVUMgPC0gYmFyUGxvdENpRXJyb3IoYXMubWF0cml4KEFsbFJvY0FVQyksDQogICAgICAgICAgICAgICAgICAgICAgICAgIG1ldHJpY25hbWUgPSAiUk9DQVVDIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlc2V0cyA9ICJST0MgQVVDIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgdGhlbWV0aG9kID0gcm93bmFtZXMoQWxsUm9jQVVDKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgbWFpbiA9ICJST0MgQVVDIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgb2Zmc2V0cyA9IGMoMC41LDEpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICBzY29yZURpcmVjdGlvbiA9ICI+IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgaG89MC41LA0KICAgICAgICAgICAgICAgICAgICAgICAgICBhcmdzLmxlZ2VuZCA9IGxpc3QoYmcgPSAid2hpdGUiLHg9ImJvdHRvbXJpZ2h0IixpbnNldD1jKDAuMCwwKSxjZXg9MC43NSksDQogICAgICAgICAgICAgICAgICAgICAgICAgIGNvbCA9IHRlcnJhaW4uY29sb3JzKG5yb3coQWxsUm9jQVVDKSkNCiAgICAgICAgICAgICAgICAgICAgICAgICAgKQ0KDQpgYGANCg0KIyMgDQo=