0. Installing the libraries

library(dplyr)
library(invgamma)
library(truncnorm)
library(matlib)
library(MASS)
library(wordspace)

1. Getting the data

We obtain the data and divide it into test and training set. The training set is further divided for 5-fold cross validation. The data looks as follows: the first column is the unique identifier for each observation (patient), the second column is the binary response (1 stands for dead and 0 stands for not dead) followed by four feature variables suitably scaled.

dataset = read.delim("traumadata.txt")

dataset <- cbind(dataset[,1:2], scale(dataset[,-(1:2)], center = TRUE, scale = TRUE))
#dataset <- cbind(dataset[,1:2], normalize.cols(scale(df[,-(1:2)], center = TRUE, scale = FALSE), method = "euclidean", p = 2))
head(dataset)
pos <- dataset[dataset$death==1,]
neg <- dataset[dataset$death==0,]

set.seed(123)
testpos <- sample(pos$ID, 2)

pos %>% filter(!(ID %in% testpos)) -> train_pos
pos %>% filter((ID %in% testpos)) -> test_pos

testneg <- sample(neg$ID, 48)

neg %>% filter(!(ID %in% testneg)) -> train_neg
neg %>% filter(ID %in% testneg) -> test_neg

test_set <- rbind(test_pos, test_neg)

set.seed(123)
temp <- sample(train_pos$ID)

foldpos1 <- temp[1:4]
foldpos2 <- temp[5:8]
foldpos3 <- temp[9:12]
foldpos4 <- temp[13:16]
foldpos5 <- temp[17:20]

fold_pos_1 <- train_pos %>% filter(ID %in% foldpos1)
fold_pos_2 <- train_pos %>% filter(ID %in% foldpos2)
fold_pos_3 <- train_pos %>% filter(ID %in% foldpos3)
fold_pos_4 <- train_pos %>% filter(ID %in% foldpos4)
fold_pos_5 <- train_pos %>% filter(ID %in% foldpos5)

set.seed(123)
temp <- sample(train_neg$ID)

fold_neg_1 <- train_neg %>% filter(ID %in% temp[1:46])
fold_neg_2 <- train_neg %>% filter(ID %in% temp[(1+46):(46*2)])
fold_neg_3 <- train_neg %>% filter(ID %in% temp[(1+46*2):(46*3)])
fold_neg_4 <- train_neg %>% filter(ID %in% temp[(1+46*3):(46*4)])
fold_neg_5 <- train_neg %>% filter(ID %in% temp[(1+46*4):(46*5)])

fold_1 <- rbind(fold_pos_1, fold_neg_1)
fold_2 <- rbind(fold_pos_2, fold_neg_2)
fold_3 <- rbind(fold_pos_3, fold_neg_3)
fold_4 <- rbind(fold_pos_4, fold_neg_4)
fold_5 <- rbind(fold_pos_5, fold_neg_5)

2. Model selection

For model selection we are selecting from the four variables and the intercept i.e a total of five variables. The model selection Gibbs Sampler selects the intercept and just one of the features when applied on the five folds i.e is suggests us to do a Simple Linear Regression. The best test set precision is obtained in the second fold which suggests us to select the intercept and the third variable i.e. “RTS”.

dataset <- rbind(fold_1, fold_2, fold_3, fold_5)

b <- rep(0, 5)
B=diag(1000,5,5)
X=as.matrix(dataset[,-c(1,2)])
X=cbind(1,X)
#head(X)
#dim(X)
#length(y)


p=rep(0.5, 5)
b_0=1
b_1=1
b_2=1
b_3=1
b_4=1

gamma=c(1,0,1,0,1)
sigmasq=1
b_new=data.frame(b_0,b_1,b_2,b_3,b_4)
#b_new
gamma_new=t(data.frame(gamma))
#gamma_new


set.seed(123)

z=data.frame()

for(i in 1:10000){
  X_star = matrix(NA,nrow=200,ncol=5)
  for(k in 1:5){
    X_star[,k]=gamma_new[i,k]*X[,k]
  }
  for (j in 1:200){
    if (dataset[j,2]==1){
      z[i,j]= rtruncnorm(n=1,a=0,b=Inf,mean=sum(X_star[j,]*b_new[i,]),sd=sigmasq)
    }
    else{
      z[i,j]=rtruncnorm(n=1,a=-Inf,b=0,mean=sum(X_star[j,]*b_new[i,]),sd=sigmasq)
    }
    
  }
  intermediate_value<-inv(inv(B)+(t(X_star)%*%X_star))
  
  temp=mvrnorm(n=1,mu=intermediate_value%*%(inv(B)%*%as.matrix(b,byrow=TRUE)+(t(X_star)%*%t(as.matrix(z[i,])))),Sigma=intermediate_value)
  b_new <- rbind(b_new, temp)
  
  
  u=c(0,0,0,0,0)
  for (q in 1:5){
    
    v_q_star<-gamma_new[i,]*b_new[i,]
    v_q_star[q]<-b_new[i,q]
    v_q_star<-t(v_q_star)
    v_q_ss<-gamma_new[i,]*b_new[i,]
    v_q_ss[q]<-0
    v_q_ss<-t(v_q_ss)
    log=-0.5*((t(t(as.matrix(z[i,]))-X%*%v_q_ss)%*%(t(as.matrix(z[i,]))-X%*%v_q_ss)-(t(t(as.matrix(z[i,]))-X%*%v_q_star)%*%(t(as.matrix(z[i,]))-X%*%v_q_star))))
    ratio<- exp(log)+1
    u[q]<-rbinom(1,1,1/ratio)
    
  }
  gamma_new<-rbind(gamma_new,u)
}
th <- gamma_new

myfun <- function(a) { paste(a, collapse="")}

ou <- apply(th[3002:10001,], 1, FUN = myfun)

table(ou)
ou
10000 10001 10010 10011 10110 10111 11000 11001 11010 11011 11100 11101 11110 11111 
  143    62  2091   698   177    84  1967   945    37    31    99   621    42     3 

Above we tabulate the frequencies of the various models that the Gibbs Sampler selects and see that the Simple Linear Regression model containing intercept and RTS is most frequent. Below we obtain estimates for the coefficients using Gibbs Sampler and check its precision on the test set.

3. Estimation and Prediction

Here is the design matrix X for the estimation part.

dataset <- rbind(fold_1, fold_2, fold_3, fold_4, fold_5)


b=c(0,0)
B=diag(1000,2,2)
X=as.matrix(dataset[,5])
X=cbind(1,X)
head(X)
     [,1]       [,2]
[1,]    1  0.4415385
[2,]    1 -1.0519002
[3,]    1 -2.2622105
[4,]    1 -0.9581618
[5,]    1  0.4415385
[6,]    1  0.4415385
intermediate_value=solve(solve(B)+t(X)%*%X)
burn=2500

b_0=1
b_3=5

b_new=data.frame(b_0, b_3)
#b_new
# In the next step, we generate z_i
z=data.frame()
set.seed(123)
for(i in 1:10000){
  for (j in 1:250){
    if (dataset[j,2]==1){
      z[i,j]= rtruncnorm(n=1,a=0,b=Inf,mean=sum(X[j,]*b_new[i,]),sd=1)
    }
    else{
      z[i,j]=rtruncnorm(n=1,a=-Inf,b=0,mean=sum(X[j,]*b_new[i,]),sd=1)
    }
    
  }
  temp=mvrnorm(n=1,mu=intermediate_value%*%(solve(B)%*%as.matrix(b)+t(X)%*%t(as.matrix(z[i,]))),Sigma=intermediate_value)
  b_new<- rbind(b_new, temp)
}
th1 <- b_new

cf <- apply(th1[3002:10001,] , 2, mean)

z123 <- cbind(1, as.matrix(test_set[,5]))%*%(as.matrix(cf))

y123pred <- ifelse(z123 >= 0, 1, 0)

y123true <- test_set[,2]

The estimated coefficients for the intercept and the third feature i.e. RTS are:

cf
       b_0        b_3 
-1.5836733 -0.4891487 

The predicted values are:

y123pred %>% as.vector %>% cat
0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

The true values are:

y123true %>% cat
1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

We can see that our model predicts one out of the two deaths correctly and does not incorrectly predict any death.

The End

LS0tDQp0aXRsZTogIlByb2plY3Qgb24gdHJhdW1hIGRhdGEiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQojIyMgMC4gSW5zdGFsbGluZyB0aGUgbGlicmFyaWVzDQoNCmBgYHtyICBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkoaW52Z2FtbWEpDQpsaWJyYXJ5KHRydW5jbm9ybSkNCmxpYnJhcnkobWF0bGliKQ0KbGlicmFyeShNQVNTKQ0KbGlicmFyeSh3b3Jkc3BhY2UpDQpgYGANCg0KIyMjIDEuIEdldHRpbmcgdGhlIGRhdGENCg0KV2Ugb2J0YWluIHRoZSBkYXRhIGFuZCBkaXZpZGUgaXQgaW50byB0ZXN0IGFuZCB0cmFpbmluZyBzZXQuIFRoZSB0cmFpbmluZyBzZXQgaXMgZnVydGhlciBkaXZpZGVkIGZvciA1LWZvbGQgY3Jvc3MgdmFsaWRhdGlvbi4gVGhlIGRhdGEgbG9va3MgYXMgZm9sbG93czogdGhlIGZpcnN0IGNvbHVtbiBpcyB0aGUgdW5pcXVlIGlkZW50aWZpZXIgZm9yIGVhY2ggb2JzZXJ2YXRpb24gKHBhdGllbnQpLCB0aGUgc2Vjb25kIGNvbHVtbiBpcyB0aGUgYmluYXJ5IHJlc3BvbnNlICgxIHN0YW5kcyBmb3IgZGVhZCBhbmQgMCBzdGFuZHMgZm9yIG5vdCBkZWFkKSBmb2xsb3dlZCBieSBmb3VyIGZlYXR1cmUgdmFyaWFibGVzIHN1aXRhYmx5IHNjYWxlZC4NCg0KDQpgYGB7cn0NCmRhdGFzZXQgPSByZWFkLmRlbGltKCJ0cmF1bWFkYXRhLnR4dCIpDQoNCmRhdGFzZXQgPC0gY2JpbmQoZGF0YXNldFssMToyXSwgc2NhbGUoZGF0YXNldFssLSgxOjIpXSwgY2VudGVyID0gVFJVRSwgc2NhbGUgPSBUUlVFKSkNCiNkYXRhc2V0IDwtIGNiaW5kKGRhdGFzZXRbLDE6Ml0sIG5vcm1hbGl6ZS5jb2xzKHNjYWxlKGRmWywtKDE6MildLCBjZW50ZXIgPSBUUlVFLCBzY2FsZSA9IEZBTFNFKSwgbWV0aG9kID0gImV1Y2xpZGVhbiIsIHAgPSAyKSkNCmhlYWQoZGF0YXNldCkNCnBvcyA8LSBkYXRhc2V0W2RhdGFzZXQkZGVhdGg9PTEsXQ0KbmVnIDwtIGRhdGFzZXRbZGF0YXNldCRkZWF0aD09MCxdDQoNCnNldC5zZWVkKDEyMykNCnRlc3Rwb3MgPC0gc2FtcGxlKHBvcyRJRCwgMikNCg0KcG9zICU+JSBmaWx0ZXIoIShJRCAlaW4lIHRlc3Rwb3MpKSAtPiB0cmFpbl9wb3MNCnBvcyAlPiUgZmlsdGVyKChJRCAlaW4lIHRlc3Rwb3MpKSAtPiB0ZXN0X3Bvcw0KDQp0ZXN0bmVnIDwtIHNhbXBsZShuZWckSUQsIDQ4KQ0KDQpuZWcgJT4lIGZpbHRlcighKElEICVpbiUgdGVzdG5lZykpIC0+IHRyYWluX25lZw0KbmVnICU+JSBmaWx0ZXIoSUQgJWluJSB0ZXN0bmVnKSAtPiB0ZXN0X25lZw0KDQp0ZXN0X3NldCA8LSByYmluZCh0ZXN0X3BvcywgdGVzdF9uZWcpDQoNCnNldC5zZWVkKDEyMykNCnRlbXAgPC0gc2FtcGxlKHRyYWluX3BvcyRJRCkNCg0KZm9sZHBvczEgPC0gdGVtcFsxOjRdDQpmb2xkcG9zMiA8LSB0ZW1wWzU6OF0NCmZvbGRwb3MzIDwtIHRlbXBbOToxMl0NCmZvbGRwb3M0IDwtIHRlbXBbMTM6MTZdDQpmb2xkcG9zNSA8LSB0ZW1wWzE3OjIwXQ0KDQpmb2xkX3Bvc18xIDwtIHRyYWluX3BvcyAlPiUgZmlsdGVyKElEICVpbiUgZm9sZHBvczEpDQpmb2xkX3Bvc18yIDwtIHRyYWluX3BvcyAlPiUgZmlsdGVyKElEICVpbiUgZm9sZHBvczIpDQpmb2xkX3Bvc18zIDwtIHRyYWluX3BvcyAlPiUgZmlsdGVyKElEICVpbiUgZm9sZHBvczMpDQpmb2xkX3Bvc180IDwtIHRyYWluX3BvcyAlPiUgZmlsdGVyKElEICVpbiUgZm9sZHBvczQpDQpmb2xkX3Bvc181IDwtIHRyYWluX3BvcyAlPiUgZmlsdGVyKElEICVpbiUgZm9sZHBvczUpDQoNCnNldC5zZWVkKDEyMykNCnRlbXAgPC0gc2FtcGxlKHRyYWluX25lZyRJRCkNCg0KZm9sZF9uZWdfMSA8LSB0cmFpbl9uZWcgJT4lIGZpbHRlcihJRCAlaW4lIHRlbXBbMTo0Nl0pDQpmb2xkX25lZ18yIDwtIHRyYWluX25lZyAlPiUgZmlsdGVyKElEICVpbiUgdGVtcFsoMSs0Nik6KDQ2KjIpXSkNCmZvbGRfbmVnXzMgPC0gdHJhaW5fbmVnICU+JSBmaWx0ZXIoSUQgJWluJSB0ZW1wWygxKzQ2KjIpOig0NiozKV0pDQpmb2xkX25lZ180IDwtIHRyYWluX25lZyAlPiUgZmlsdGVyKElEICVpbiUgdGVtcFsoMSs0NiozKTooNDYqNCldKQ0KZm9sZF9uZWdfNSA8LSB0cmFpbl9uZWcgJT4lIGZpbHRlcihJRCAlaW4lIHRlbXBbKDErNDYqNCk6KDQ2KjUpXSkNCg0KZm9sZF8xIDwtIHJiaW5kKGZvbGRfcG9zXzEsIGZvbGRfbmVnXzEpDQpmb2xkXzIgPC0gcmJpbmQoZm9sZF9wb3NfMiwgZm9sZF9uZWdfMikNCmZvbGRfMyA8LSByYmluZChmb2xkX3Bvc18zLCBmb2xkX25lZ18zKQ0KZm9sZF80IDwtIHJiaW5kKGZvbGRfcG9zXzQsIGZvbGRfbmVnXzQpDQpmb2xkXzUgPC0gcmJpbmQoZm9sZF9wb3NfNSwgZm9sZF9uZWdfNSkNCg0KYGBgDQoNCiMjIyAyLiBNb2RlbCBzZWxlY3Rpb24NCg0KRm9yIG1vZGVsIHNlbGVjdGlvbiB3ZSBhcmUgc2VsZWN0aW5nIGZyb20gdGhlIGZvdXIgdmFyaWFibGVzIGFuZCB0aGUgaW50ZXJjZXB0IGkuZSBhIHRvdGFsIG9mIGZpdmUgdmFyaWFibGVzLiBUaGUgbW9kZWwgc2VsZWN0aW9uIEdpYmJzIFNhbXBsZXIgc2VsZWN0cyB0aGUgaW50ZXJjZXB0IGFuZCBqdXN0IG9uZSBvZiB0aGUgZmVhdHVyZXMgd2hlbiBhcHBsaWVkIG9uIHRoZSBmaXZlIGZvbGRzIGkuZSBpcyBzdWdnZXN0cyB1cyB0byBkbyBhIFNpbXBsZSBMaW5lYXIgUmVncmVzc2lvbi4gVGhlIGJlc3QgdGVzdCBzZXQgcHJlY2lzaW9uIGlzIG9idGFpbmVkIGluIHRoZSBzZWNvbmQgZm9sZCB3aGljaCBzdWdnZXN0cyB1cyB0byBzZWxlY3QgdGhlIGludGVyY2VwdCBhbmQgdGhlIHRoaXJkIHZhcmlhYmxlIGkuZS4gIlJUUyIuDQoNCg0KYGBge3J9DQpkYXRhc2V0IDwtIHJiaW5kKGZvbGRfMSwgZm9sZF8yLCBmb2xkXzMsIGZvbGRfNSkNCg0KYiA8LSByZXAoMCwgNSkNCkI9ZGlhZygxMDAwLDUsNSkNClg9YXMubWF0cml4KGRhdGFzZXRbLC1jKDEsMildKQ0KWD1jYmluZCgxLFgpDQojaGVhZChYKQ0KI2RpbShYKQ0KI2xlbmd0aCh5KQ0KDQoNCnA9cmVwKDAuNSwgNSkNCmJfMD0xDQpiXzE9MQ0KYl8yPTENCmJfMz0xDQpiXzQ9MQ0KDQpnYW1tYT1jKDEsMCwxLDAsMSkNCnNpZ21hc3E9MQ0KYl9uZXc9ZGF0YS5mcmFtZShiXzAsYl8xLGJfMixiXzMsYl80KQ0KI2JfbmV3DQpnYW1tYV9uZXc9dChkYXRhLmZyYW1lKGdhbW1hKSkNCiNnYW1tYV9uZXcNCg0KDQpzZXQuc2VlZCgxMjMpDQoNCno9ZGF0YS5mcmFtZSgpDQoNCmZvcihpIGluIDE6MTAwMDApew0KICBYX3N0YXIgPSBtYXRyaXgoTkEsbnJvdz0yMDAsbmNvbD01KQ0KICBmb3IoayBpbiAxOjUpew0KICAgIFhfc3Rhclssa109Z2FtbWFfbmV3W2ksa10qWFssa10NCiAgfQ0KICBmb3IgKGogaW4gMToyMDApew0KICAgIGlmIChkYXRhc2V0W2osMl09PTEpew0KICAgICAgeltpLGpdPSBydHJ1bmNub3JtKG49MSxhPTAsYj1JbmYsbWVhbj1zdW0oWF9zdGFyW2osXSpiX25ld1tpLF0pLHNkPXNpZ21hc3EpDQogICAgfQ0KICAgIGVsc2V7DQogICAgICB6W2ksal09cnRydW5jbm9ybShuPTEsYT0tSW5mLGI9MCxtZWFuPXN1bShYX3N0YXJbaixdKmJfbmV3W2ksXSksc2Q9c2lnbWFzcSkNCiAgICB9DQogICAgDQogIH0NCiAgaW50ZXJtZWRpYXRlX3ZhbHVlPC1pbnYoaW52KEIpKyh0KFhfc3RhciklKiVYX3N0YXIpKQ0KICANCiAgdGVtcD1tdnJub3JtKG49MSxtdT1pbnRlcm1lZGlhdGVfdmFsdWUlKiUoaW52KEIpJSolYXMubWF0cml4KGIsYnlyb3c9VFJVRSkrKHQoWF9zdGFyKSUqJXQoYXMubWF0cml4KHpbaSxdKSkpKSxTaWdtYT1pbnRlcm1lZGlhdGVfdmFsdWUpDQogIGJfbmV3IDwtIHJiaW5kKGJfbmV3LCB0ZW1wKQ0KICANCiAgDQogIHU9YygwLDAsMCwwLDApDQogIGZvciAocSBpbiAxOjUpew0KICAgIA0KICAgIHZfcV9zdGFyPC1nYW1tYV9uZXdbaSxdKmJfbmV3W2ksXQ0KICAgIHZfcV9zdGFyW3FdPC1iX25ld1tpLHFdDQogICAgdl9xX3N0YXI8LXQodl9xX3N0YXIpDQogICAgdl9xX3NzPC1nYW1tYV9uZXdbaSxdKmJfbmV3W2ksXQ0KICAgIHZfcV9zc1txXTwtMA0KICAgIHZfcV9zczwtdCh2X3Ffc3MpDQogICAgbG9nPS0wLjUqKCh0KHQoYXMubWF0cml4KHpbaSxdKSktWCUqJXZfcV9zcyklKiUodChhcy5tYXRyaXgoeltpLF0pKS1YJSoldl9xX3NzKS0odCh0KGFzLm1hdHJpeCh6W2ksXSkpLVglKiV2X3Ffc3RhciklKiUodChhcy5tYXRyaXgoeltpLF0pKS1YJSoldl9xX3N0YXIpKSkpDQogICAgcmF0aW88LSBleHAobG9nKSsxDQogICAgdVtxXTwtcmJpbm9tKDEsMSwxL3JhdGlvKQ0KICAgIA0KICB9DQogIGdhbW1hX25ldzwtcmJpbmQoZ2FtbWFfbmV3LHUpDQp9DQoNCmBgYA0KDQpgYGB7cn0NCnRoIDwtIGdhbW1hX25ldw0KDQpteWZ1biA8LSBmdW5jdGlvbihhKSB7IHBhc3RlKGEsIGNvbGxhcHNlPSIiKX0NCg0Kb3UgPC0gYXBwbHkodGhbMzAwMjoxMDAwMSxdLCAxLCBGVU4gPSBteWZ1bikNCg0KdGFibGUob3UpDQpgYGANCg0KQWJvdmUgd2UgdGFidWxhdGUgdGhlIGZyZXF1ZW5jaWVzIG9mIHRoZSB2YXJpb3VzIG1vZGVscyB0aGF0IHRoZSBHaWJicyBTYW1wbGVyIHNlbGVjdHMgYW5kIHNlZSB0aGF0IHRoZSBTaW1wbGUgTGluZWFyIFJlZ3Jlc3Npb24gbW9kZWwgY29udGFpbmluZyBpbnRlcmNlcHQgYW5kIFJUUyBpcyBtb3N0IGZyZXF1ZW50LiBCZWxvdyB3ZSBvYnRhaW4gZXN0aW1hdGVzIGZvciAgdGhlIGNvZWZmaWNpZW50cyB1c2luZyBHaWJicyBTYW1wbGVyIGFuZCBjaGVjayBpdHMgcHJlY2lzaW9uIG9uIHRoZSB0ZXN0IHNldC4NCg0KDQojIyMgMy4gRXN0aW1hdGlvbiBhbmQgUHJlZGljdGlvbg0KDQpIZXJlIGlzIHRoZSBkZXNpZ24gbWF0cml4IFggZm9yIHRoZSBlc3RpbWF0aW9uIHBhcnQuDQoNCmBgYHtyfQ0KZGF0YXNldCA8LSByYmluZChmb2xkXzEsIGZvbGRfMiwgZm9sZF8zLCBmb2xkXzQsIGZvbGRfNSkNCg0KDQpiPWMoMCwwKQ0KQj1kaWFnKDEwMDAsMiwyKQ0KWD1hcy5tYXRyaXgoZGF0YXNldFssNV0pDQpYPWNiaW5kKDEsWCkNCiNoZWFkKFgpDQppbnRlcm1lZGlhdGVfdmFsdWU9c29sdmUoc29sdmUoQikrdChYKSUqJVgpDQpidXJuPTI1MDANCg0KYl8wPTENCmJfMz01DQoNCmJfbmV3PWRhdGEuZnJhbWUoYl8wLCBiXzMpDQojYl9uZXcNCiMgSW4gdGhlIG5leHQgc3RlcCwgd2UgZ2VuZXJhdGUgel9pDQp6PWRhdGEuZnJhbWUoKQ0Kc2V0LnNlZWQoMTIzKQ0KZm9yKGkgaW4gMToxMDAwMCl7DQogIGZvciAoaiBpbiAxOjI1MCl7DQogICAgaWYgKGRhdGFzZXRbaiwyXT09MSl7DQogICAgICB6W2ksal09IHJ0cnVuY25vcm0obj0xLGE9MCxiPUluZixtZWFuPXN1bShYW2osXSpiX25ld1tpLF0pLHNkPTEpDQogICAgfQ0KICAgIGVsc2V7DQogICAgICB6W2ksal09cnRydW5jbm9ybShuPTEsYT0tSW5mLGI9MCxtZWFuPXN1bShYW2osXSpiX25ld1tpLF0pLHNkPTEpDQogICAgfQ0KICAgIA0KICB9DQogIHRlbXA9bXZybm9ybShuPTEsbXU9aW50ZXJtZWRpYXRlX3ZhbHVlJSolKHNvbHZlKEIpJSolYXMubWF0cml4KGIpK3QoWCklKiV0KGFzLm1hdHJpeCh6W2ksXSkpKSxTaWdtYT1pbnRlcm1lZGlhdGVfdmFsdWUpDQogIGJfbmV3PC0gcmJpbmQoYl9uZXcsIHRlbXApDQp9DQoNCmBgYA0KDQpgYGB7cn0NCnRoMSA8LSBiX25ldw0KDQpjZiA8LSBhcHBseSh0aDFbMzAwMjoxMDAwMSxdICwgMiwgbWVhbikNCg0KejEyMyA8LSBjYmluZCgxLCBhcy5tYXRyaXgodGVzdF9zZXRbLDVdKSklKiUoYXMubWF0cml4KGNmKSkNCg0KeTEyM3ByZWQgPC0gaWZlbHNlKHoxMjMgPj0gMCwgMSwgMCkNCg0KeTEyM3RydWUgPC0gdGVzdF9zZXRbLDJdDQpgYGANCg0KVGhlIGVzdGltYXRlZCBjb2VmZmljaWVudHMgZm9yIHRoZSBpbnRlcmNlcHQgYW5kIHRoZSB0aGlyZCBmZWF0dXJlIGkuZS4gUlRTIGFyZToNCg0KYGBge3J9DQpjZg0KYGBgDQoNCg0KVGhlIHByZWRpY3RlZCB2YWx1ZXMgYXJlOg0KDQpgYGB7cn0NCnkxMjNwcmVkICU+JSBhcy52ZWN0b3IgJT4lIGNhdA0KYGBgDQoNClRoZSB0cnVlIHZhbHVlcyBhcmU6DQoNCmBgYHtyfQ0KeTEyM3RydWUgJT4lIGNhdA0KYGBgDQoNCldlIGNhbiBzZWUgdGhhdCBvdXIgbW9kZWwgcHJlZGljdHMgb25lIG91dCBvZiB0aGUgdHdvIGRlYXRocyBjb3JyZWN0bHkgYW5kIGRvZXMgbm90IGluY29ycmVjdGx5IHByZWRpY3QgYW55IGRlYXRoLg0KDQoNCiMjIyBUaGUgRW5kDQo=