cl <- makeCluster(4)
registerDoParallel(cl)
reqpkgs <- c("randomForest","caret","tidyr","dplyr")
Primera Parte
Sin normalizar y haciendo la segunda parte con secuencias de N caracteres.
Importamos CTU19
ctu19 <- ctu19 %>% select(-X1)
ctu19 %>% head(50)
Sacamos los simbolos de tiempo.
time_simbol_pattern <- '(\\.)*(\\,)*(\\+)*(\\*)*(0)*'
ctu19$State <- ctu19$State %>% str_replace_all(time_simbol_pattern,"")
Warning in for (name in names(hooks)) { :
cerrando la conenexion 7 (<-DESKTOP-D5ND1BA:11161) que no esta siendo utilizada
Warning in for (name in names(hooks)) { :
cerrando la conenexion 6 (<-DESKTOP-D5ND1BA:11161) que no esta siendo utilizada
Warning in for (name in names(hooks)) { :
cerrando la conenexion 5 (<-DESKTOP-D5ND1BA:11161) que no esta siendo utilizada
Warning in for (name in names(hooks)) { :
cerrando la conenexion 4 (<-DESKTOP-D5ND1BA:11161) que no esta siendo utilizada
Eliminamos los primeros 4 simbolos. Obviamente, las secuencias de solo 4 simbolos son eliminadas.
ctu19 <- ctu19 %>% filter(nchar(State) > 4)
ctu19$State <- ctu19$State %>% substr(4,nchar(ctu19$State))
ctu19 %>% head(50)
Feature Vector
feature_vector <- function(dataset){
#Size
dataset <- dataset %>% mutate(small_s = str_count(State, '[a-c]') + str_count(State, '[A-C]') + str_count(State, '[r-t]') + str_count(State, '[R-T]') + str_count(State, '[1-3]'))
dataset <- dataset %>% mutate(medium_s = str_count(State, '[d-f]') + str_count(State, '[D-F]') + str_count(State, '[u-w]') + str_count(State, '[U-W]') + str_count(State, '[4-6]'))
dataset <- dataset %>% mutate(large_s = str_count(State, '[g-i]') + str_count(State, '[G-I]') + str_count(State, '[x-z]') + str_count(State, '[X-Z]') + str_count(State, '[7-9]'))
#Periodicity
dataset <- dataset %>% mutate(strong_p = str_count(State, '[a-i]'))
dataset <- dataset %>% mutate(weak_p = str_count(State, '[A-I]'))
dataset <- dataset %>% mutate(weak_np = str_count(State, '[r-z]'))
dataset <- dataset %>% mutate(strong_np = str_count(State, '[R-Z]'))
#Duration
dataset <- dataset %>% mutate(short_d = str_count(State, '[a|A|r|R|1|d|D|u|U|4|g|G|x|X|7]'))
dataset <- dataset %>% mutate(medium_d = str_count(State, '[b|B|s|S|2|e|E|v|V|5|h|H|y|Y|8]'))
dataset <- dataset %>% mutate(long_d = str_count(State, '[c|C|t|T|3|f|F|w|W|6|i|I|z|Z|9]'))
}
ctu19 <- feature_vector(ctu19)
ctu19 %>% head(50)
Dejamos solo las columnas que nos interesan
ctu19 <- ctu19 %>% select(-InitialIp,-EndIP,-Proto,-State,-Port)
ctu19$LabelName <- as.factor(ctu19$LabelName)
ctu19 %>% head(50)
Random Forest
test_model <- function(ctu19){
#Train 70% y 30%
train_data_ind <- createDataPartition(ctu19$LabelName, p = 0.7,list = FALSE)
train_data <- ctu19[train_data_ind,]
test_data <- ctu19[-train_data_ind,]
set.seed(123)
modelo_randomforest <- randomForest(LabelName~., data=train_data,na.action = na.omit)
prediction <- predict(modelo_randomforest,test_data)
conf_MAt <- confusionMatrix(prediction, test_data$LabelName)
return(conf_MAt$byClass)
}
CTU19 puro
ctu19Puro_CM <- c()
ctu19Puro_CM <- foreach::foreach(i = 1:10,
.packages = reqpkgs,
.combine = cbind
) %dopar% {
test_model(ctu19)
}
promedio_Puro <- c()
prom <- rowMeans(ctu19Puro_CM)
standard_deviation <- rowSds(ctu19Puro_CM)
promedio_Puro <- promedio_Puro %>% cbind(prom) %>% cbind(standard_deviation)
promedio_Puro %>% as.data.frame()
CTU19 con DownSampling
test_model_down <- function(ctu19){
#Train 70% y 30%
train_data_ind <- createDataPartition(ctu19$LabelName, p = 0.7,list = FALSE)
train_data <- ctu19[train_data_ind,]
test_data <- ctu19[-train_data_ind,]
down_train_data <- downSample(train_data,train_data$LabelName, list=FALSE)
down_train_data <- down_train_data %>% select(-Class)
set.seed(123)
modelo_randomforest <- randomForest(LabelName~., data=down_train_data ,na.action = na.omit)
prediction <- predict(modelo_randomforest,test_data)
conf_MAt <- confusionMatrix(prediction, test_data$LabelName)
return(conf_MAt$byClass)
}
ctu19Down_CM <- c()
ctu19Down_CM <- foreach::foreach(i = 1:10,
.packages = reqpkgs,
.combine = cbind
) %dopar% {
test_model_down(ctu19)
}
promedio_Down <- c()
prom <- rowMeans(ctu19Down_CM)
standard_deviation <- rowSds(ctu19Down_CM)
promedio_Down <- promedio_Down %>% cbind(prom) %>% cbind(standard_deviation)
promedio_Down %>% as.data.frame()
CTU19 con UpSampling
test_model_up <- function(ctu19){
#Train 70% y 30%
train_data_ind <- createDataPartition(ctu19$LabelName, p = 0.7,list = FALSE)
train_data <- ctu19[train_data_ind,]
test_data <- ctu19[-train_data_ind,]
up_train_data <- upSample(train_data,train_data$LabelName, list=FALSE)
up_train_data <- up_train_data %>% select(-Class)
set.seed(123)
modelo_randomforest <- randomForest(LabelName~., data=up_train_data ,na.action = na.omit)
prediction <- predict(modelo_randomforest,test_data)
conf_MAt <- confusionMatrix(prediction, test_data$LabelName)
return(conf_MAt$byClass)
}
ctu19Up_CM <- c()
ctu19Up_CM <- foreach::foreach(i = 1:10,
.packages = reqpkgs,
.combine = cbind
) %dopar% {
test_model_up(ctu19)
}
promedio_Up <- c()
prom <- rowMeans(ctu19Up_CM)
standard_deviation <- rowSds(ctu19Up_CM)
promedio_Up <- promedio_Up %>% cbind(prom) %>% cbind(standard_deviation)
promedio_Up %>% as.data.frame()
Segunda Parte
ctu19 <- ctu19 %>% select(-X1)
ctu19 %>% head(50)
Sacamos los simbolos de tiempo.
time_simbol_pattern <- '(\\.)*(\\,)*(\\+)*(\\*)*(0)*'
ctu19$State <- ctu19$State %>% str_replace_all(time_simbol_pattern,"")
Eliminamos los primeros 4 simbolos. Obviamente, las secuencias de solo 4 simbolos son eliminadas.
ctu19 <- ctu19 %>% filter(nchar(State) > 4)
ctu19$State <- ctu19$State %>% substr(4,nchar(ctu19$State))
ctu19 %>% head(50)
Armamos los dataset de tamaño N
Tamaño 10
ctu19_10 <- ctu19
ctu19_10$State <- ctu19$State %>% substr(1,10)
Tamaño 20
ctu19_20 <- ctu19
ctu19_20$State <- ctu19$State %>% substr(1,20)
Tamaño 40
ctu19_40 <- ctu19
ctu19_40$State <- ctu19$State %>% substr(1,40)
Tamaño 80
ctu19_80 <- ctu19
ctu19_80$State <- ctu19$State %>% substr(1,80)
Tamaño 100
ctu19_100 <- ctu19
ctu19_100$State <- ctu19$State %>% substr(1,100)
Tamaño 200
ctu19_200 <- ctu19
ctu19_200$State <- ctu19$State %>% substr(1,200)
Tamaño 400
ctu19_400 <- ctu19
ctu19_400$State <- ctu19$State %>% substr(1,400)
Tamaño 800
ctu19_800 <- ctu19
ctu19_800$State <- ctu19$State %>% substr(1,800)
Tamaño 1000
ctu19_1000 <- ctu19
ctu19_1000$State <- ctu19$State %>% substr(1,1000)
Vector de DataSets
dataSets <- list(ctu19_10,ctu19_20,ctu19_40,ctu19_80,ctu19_100,ctu19_200,ctu19_400,ctu19_800,ctu19_1000)
Feature Vector
dataSets <- lapply(dataSets, function(x) x <- feature_vector(as.data.frame(x)))
Limpieza
Dejamos solo las columnas que nos interesan
limpieza <- function(x){
x <- x %>% select(-InitialIp,-EndIP,-Proto,-State,-Port)
x$LabelName <- as.factor(x$LabelName)
return(x)
}
dataSets <- lapply(dataSets, function(x) x <- limpieza(x))
lapply(dataSets, function(x) as.data.frame(x) %>% head(50))
[[1]]
[[2]]
[[3]]
[[4]]
[[5]]
[[6]]
[[7]]
[[8]]
[[9]]
NA
Random Forest
CTU19 puro
ctu19_puro_DS <- lapply(dataSets, function(x) {
ctu19Puro_DS <- c()
ctu19Puro_DS <- foreach::foreach(i = 1:10,
.packages = reqpkgs,
.combine = cbind,
.export = c("test_model")
) %dopar% {
test_model(as.data.frame(x))
}
return(ctu19Puro_DS)
})
promedio_Puro_DS <- lapply(ctu19_puro_DS, function(x){
resp <- c()
prom <- rowMeans(x)
standard_deviation <- rowSds(x)
resp <- resp %>% cbind(prom) %>% cbind(standard_deviation)
return(resp)
})
lapply(promedio_Puro_DS, function(x) x %>% as.data.frame())
[[1]]
[[2]]
[[3]]
[[4]]
[[5]]
[[6]]
[[7]]
[[8]]
[[9]]
NA
CTU19 Down
ctu19_Down_DS <- lapply(dataSets, function(x) {
resp <- c()
resp <- foreach::foreach(i = 1:10,
.packages = reqpkgs,
.combine = cbind,
.export = c("test_model_down")
) %dopar% {
test_model_down(as.data.frame(x))
}
return(resp)
})
promedio_Down_DS <- lapply(ctu19_Down_DS, function(x){
resp <- c()
prom <- rowMeans(x)
standard_deviation <- rowSds(x)
resp <- resp %>% cbind(prom) %>% cbind(standard_deviation)
return(resp)
})
lapply(promedio_Down_DS, function(x) x %>% as.data.frame())
[[1]]
[[2]]
[[3]]
[[4]]
[[5]]
[[6]]
[[7]]
[[8]]
[[9]]
NA
CTU19 Up
ctu19_Up_DS <- lapply(dataSets, function(x) {
resp <- c()
resp <- foreach::foreach(i = 1:10,
.packages = reqpkgs,
.combine = cbind,
.export = c("test_model_up")
) %dopar% {
test_model_up(as.data.frame(x))
}
return(resp)
})
promedio_Up_DS <- lapply(ctu19_Up_DS, function(x){
resp <- c()
prom <- rowMeans(x)
standard_deviation <- rowSds(x)
resp <- resp %>% cbind(prom) %>% cbind(standard_deviation)
return(resp)
})
lapply(promedio_Up_DS, function(x) x %>% as.data.frame())
[[1]]
[[2]]
[[3]]
[[4]]
[[5]]
[[6]]
[[7]]
[[8]]
[[9]]
NA
LS0tDQp0aXRsZTogIkJvdG5ldHNfQ1RVMTlfU04vSE4iDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQpgYGB7ciBpbmNsdWRlPUZBTFNFfQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkobGF0dGljZSkNCmxpYnJhcnkodGlkeXIpDQpsaWJyYXJ5KGNhcmV0KQ0KbGlicmFyeShyYW5kb21Gb3Jlc3QpDQpsaWJyYXJ5KGRvUGFyYWxsZWwpDQpsaWJyYXJ5KHN0cmluZ3IpDQpsaWJyYXJ5KG1hdHJpeFN0YXRzKQ0KYGBgDQoNCmBgYHtyfQ0KY2wgPC0gbWFrZUNsdXN0ZXIoNCkNCnJlZ2lzdGVyRG9QYXJhbGxlbChjbCkNCmBgYA0KDQoNCmBgYHtyfQ0KcmVxcGtncyA8LSBjKCJyYW5kb21Gb3Jlc3QiLCJjYXJldCIsInRpZHlyIiwiZHBseXIiKSANCmBgYA0KDQojIFByaW1lcmEgUGFydGUNCg0KU2luIG5vcm1hbGl6YXIgeSBoYWNpZW5kbyBsYSBzZWd1bmRhIHBhcnRlIGNvbiBzZWN1ZW5jaWFzIGRlIE4gY2FyYWN0ZXJlcy4gDQoNCmBgYHtyIGluY2x1ZGU9RkFMU0V9DQpjdHUxOSA9IHJlYWRyOjpyZWFkX2RlbGltKGZpbGU9IkM6L1VzZXJzL0R1enpMb2dpYy9Hb29nbGUgRHJpdmUvQ29zYXMvTEFCU0lOL0JvdG5ldHMvY3R1L2N0dTE5LmNzdiIsZGVsaW0gPSAnLCcpDQpgYGANCg0KIyMgSW1wb3J0YW1vcyBDVFUxOQ0KDQpgYGB7cn0NCmN0dTE5IDwtIGN0dTE5ICU+JSBzZWxlY3QoLVgxKQ0KY3R1MTkgJT4lIGhlYWQoNTApDQpgYGANCg0KDQpTYWNhbW9zIGxvcyBzaW1ib2xvcyBkZSB0aWVtcG8uDQoNCmBgYHtyfQ0KdGltZV9zaW1ib2xfcGF0dGVybiA8LSAnKFxcLikqKFxcLCkqKFxcKykqKFxcKikqKDApKicNCg0KY3R1MTkkU3RhdGUgPC0gY3R1MTkkU3RhdGUgJT4lIHN0cl9yZXBsYWNlX2FsbCh0aW1lX3NpbWJvbF9wYXR0ZXJuLCIiKQ0KYGBgDQoNCg0KRWxpbWluYW1vcyBsb3MgcHJpbWVyb3MgNCBzaW1ib2xvcy4gT2J2aWFtZW50ZSwgbGFzIHNlY3VlbmNpYXMgZGUgc29sbyA0IHNpbWJvbG9zIHNvbiBlbGltaW5hZGFzLg0KDQpgYGB7ciBlY2hvPVRSVUV9DQpjdHUxOSA8LSBjdHUxOSAlPiUgZmlsdGVyKG5jaGFyKFN0YXRlKSA+IDQpDQpjdHUxOSRTdGF0ZSA8LSBjdHUxOSRTdGF0ZSAlPiUgc3Vic3RyKDQsbmNoYXIoY3R1MTkkU3RhdGUpKQ0KYGBgDQoNCmBgYHtyfQ0KY3R1MTkgJT4lIGhlYWQoNTApDQpgYGANCg0KIyMgRmVhdHVyZSBWZWN0b3INCg0KYGBge3IgZWNobz1UUlVFfQ0KZmVhdHVyZV92ZWN0b3IgPC0gZnVuY3Rpb24oZGF0YXNldCl7DQogICNTaXplDQogIGRhdGFzZXQgPC0gZGF0YXNldCAlPiUgbXV0YXRlKHNtYWxsX3MgPSBzdHJfY291bnQoU3RhdGUsICdbYS1jXScpICsgc3RyX2NvdW50KFN0YXRlLCAnW0EtQ10nKSArIHN0cl9jb3VudChTdGF0ZSwgJ1tyLXRdJykgKyBzdHJfY291bnQoU3RhdGUsICdbUi1UXScpICsgc3RyX2NvdW50KFN0YXRlLCAnWzEtM10nKSkNCiAgZGF0YXNldCA8LSBkYXRhc2V0ICU+JSBtdXRhdGUobWVkaXVtX3MgPSBzdHJfY291bnQoU3RhdGUsICdbZC1mXScpICsgc3RyX2NvdW50KFN0YXRlLCAnW0QtRl0nKSArIHN0cl9jb3VudChTdGF0ZSwgJ1t1LXddJykgKyBzdHJfY291bnQoU3RhdGUsICdbVS1XXScpICsgc3RyX2NvdW50KFN0YXRlLCAnWzQtNl0nKSkNCiAgZGF0YXNldCA8LSBkYXRhc2V0ICU+JSBtdXRhdGUobGFyZ2VfcyA9IHN0cl9jb3VudChTdGF0ZSwgJ1tnLWldJykgKyBzdHJfY291bnQoU3RhdGUsICdbRy1JXScpICsgc3RyX2NvdW50KFN0YXRlLCAnW3gtel0nKSArIHN0cl9jb3VudChTdGF0ZSwgJ1tYLVpdJykgKyBzdHJfY291bnQoU3RhdGUsICdbNy05XScpKQ0KICANCiAgI1BlcmlvZGljaXR5DQogIGRhdGFzZXQgPC0gZGF0YXNldCAlPiUgbXV0YXRlKHN0cm9uZ19wID0gc3RyX2NvdW50KFN0YXRlLCAnW2EtaV0nKSkNCiAgZGF0YXNldCA8LSBkYXRhc2V0ICU+JSBtdXRhdGUod2Vha19wID0gc3RyX2NvdW50KFN0YXRlLCAnW0EtSV0nKSkNCiAgZGF0YXNldCA8LSBkYXRhc2V0ICU+JSBtdXRhdGUod2Vha19ucCA9IHN0cl9jb3VudChTdGF0ZSwgJ1tyLXpdJykpDQogIGRhdGFzZXQgPC0gZGF0YXNldCAlPiUgbXV0YXRlKHN0cm9uZ19ucCA9IHN0cl9jb3VudChTdGF0ZSwgJ1tSLVpdJykpDQogIA0KICAjRHVyYXRpb24NCiAgZGF0YXNldCA8LSBkYXRhc2V0ICU+JSBtdXRhdGUoc2hvcnRfZCA9IHN0cl9jb3VudChTdGF0ZSwgJ1thfEF8cnxSfDF8ZHxEfHV8VXw0fGd8R3x4fFh8N10nKSkNCiAgZGF0YXNldCA8LSBkYXRhc2V0ICU+JSBtdXRhdGUobWVkaXVtX2QgPSBzdHJfY291bnQoU3RhdGUsICdbYnxCfHN8U3wyfGV8RXx2fFZ8NXxofEh8eXxZfDhdJykpDQogIGRhdGFzZXQgPC0gZGF0YXNldCAlPiUgbXV0YXRlKGxvbmdfZCA9IHN0cl9jb3VudChTdGF0ZSwgJ1tjfEN8dHxUfDN8ZnxGfHd8V3w2fGl8SXx6fFp8OV0nKSkNCiAgDQp9DQoNCmBgYA0KDQpgYGB7cn0NCmN0dTE5IDwtIGZlYXR1cmVfdmVjdG9yKGN0dTE5KQ0KYGBgDQoNCmBgYHtyfQ0KY3R1MTkgJT4lIGhlYWQoNTApDQpgYGANCg0KRGVqYW1vcyBzb2xvIGxhcyBjb2x1bW5hcyBxdWUgbm9zIGludGVyZXNhbg0KDQpgYGB7cn0NCmN0dTE5IDwtIGN0dTE5ICU+JSBzZWxlY3QoLUluaXRpYWxJcCwtRW5kSVAsLVByb3RvLC1TdGF0ZSwtUG9ydCkNCmN0dTE5JExhYmVsTmFtZSA8LSBhcy5mYWN0b3IoY3R1MTkkTGFiZWxOYW1lKQ0KY3R1MTkgJT4lIGhlYWQoNTApDQpgYGANCg0KIyMgUmFuZG9tIEZvcmVzdA0KDQpgYGB7ciBlY2hvPVRSVUV9DQp0ZXN0X21vZGVsIDwtIGZ1bmN0aW9uKGN0dTE5KXsNCiAgI1RyYWluIDcwJSB5IDMwJQ0KICB0cmFpbl9kYXRhX2luZCA8LSBjcmVhdGVEYXRhUGFydGl0aW9uKGN0dTE5JExhYmVsTmFtZSwgcCA9IDAuNyxsaXN0ID0gRkFMU0UpDQogIHRyYWluX2RhdGEgPC0gY3R1MTlbdHJhaW5fZGF0YV9pbmQsXQ0KICB0ZXN0X2RhdGEgPC0gY3R1MTlbLXRyYWluX2RhdGFfaW5kLF0NCiAgDQogIHNldC5zZWVkKDEyMykNCiAgbW9kZWxvX3JhbmRvbWZvcmVzdCA8LSByYW5kb21Gb3Jlc3QoTGFiZWxOYW1lfi4sIGRhdGE9dHJhaW5fZGF0YSxuYS5hY3Rpb24gPSBuYS5vbWl0KQ0KICANCiAgcHJlZGljdGlvbiA8LSBwcmVkaWN0KG1vZGVsb19yYW5kb21mb3Jlc3QsdGVzdF9kYXRhKQ0KICBjb25mX01BdCA8LSBjb25mdXNpb25NYXRyaXgocHJlZGljdGlvbiwgdGVzdF9kYXRhJExhYmVsTmFtZSkNCiAgcmV0dXJuKGNvbmZfTUF0JGJ5Q2xhc3MpDQp9DQpgYGANCg0KDQojIyMgQ1RVMTkgcHVybw0KDQpgYGB7ciBlY2hvPVRSVUV9DQpjdHUxOVB1cm9fQ00gPC0gYygpDQpjdHUxOVB1cm9fQ00gPC0gZm9yZWFjaDo6Zm9yZWFjaChpID0gMToxMCwNCiAgICAgICAgICAgICAgICAgLnBhY2thZ2VzID0gcmVxcGtncywNCiAgICAgICAgICAgICAgICAgLmNvbWJpbmUgPSBjYmluZA0KKSAlZG9wYXIlIHsNCiAgICAgICAgICAgICAgICAgIHRlc3RfbW9kZWwoY3R1MTkpIA0KICAgICAgICAgICAgICAgICB9DQpgYGANCg0KYGBge3J9DQpwcm9tZWRpb19QdXJvIDwtIGMoKQ0KcHJvbSA8LSByb3dNZWFucyhjdHUxOVB1cm9fQ00pDQpzdGFuZGFyZF9kZXZpYXRpb24gPC0gcm93U2RzKGN0dTE5UHVyb19DTSkNCnByb21lZGlvX1B1cm8gPC0gcHJvbWVkaW9fUHVybyAlPiUgY2JpbmQocHJvbSkgJT4lIGNiaW5kKHN0YW5kYXJkX2RldmlhdGlvbikNCnByb21lZGlvX1B1cm8gJT4lIGFzLmRhdGEuZnJhbWUoKQ0KYGBgDQoNCiMjIyBDVFUxOSBjb24gRG93blNhbXBsaW5nDQoNCmBgYHtyIGVjaG89VFJVRX0NCnRlc3RfbW9kZWxfZG93biA8LSBmdW5jdGlvbihjdHUxOSl7DQogICNUcmFpbiA3MCUgeSAzMCUNCiAgdHJhaW5fZGF0YV9pbmQgPC0gY3JlYXRlRGF0YVBhcnRpdGlvbihjdHUxOSRMYWJlbE5hbWUsIHAgPSAwLjcsbGlzdCA9IEZBTFNFKQ0KICB0cmFpbl9kYXRhIDwtIGN0dTE5W3RyYWluX2RhdGFfaW5kLF0NCiAgdGVzdF9kYXRhIDwtIGN0dTE5Wy10cmFpbl9kYXRhX2luZCxdDQogIA0KICBkb3duX3RyYWluX2RhdGEgPC0gZG93blNhbXBsZSh0cmFpbl9kYXRhLHRyYWluX2RhdGEkTGFiZWxOYW1lLCBsaXN0PUZBTFNFKQ0KICBkb3duX3RyYWluX2RhdGEgPC0gZG93bl90cmFpbl9kYXRhICU+JSBzZWxlY3QoLUNsYXNzKQ0KICANCiAgc2V0LnNlZWQoMTIzKQ0KICBtb2RlbG9fcmFuZG9tZm9yZXN0IDwtIHJhbmRvbUZvcmVzdChMYWJlbE5hbWV+LiwgZGF0YT1kb3duX3RyYWluX2RhdGEgLG5hLmFjdGlvbiA9IG5hLm9taXQpDQogIA0KICBwcmVkaWN0aW9uIDwtIHByZWRpY3QobW9kZWxvX3JhbmRvbWZvcmVzdCx0ZXN0X2RhdGEpDQogIGNvbmZfTUF0IDwtIGNvbmZ1c2lvbk1hdHJpeChwcmVkaWN0aW9uLCB0ZXN0X2RhdGEkTGFiZWxOYW1lKQ0KICByZXR1cm4oY29uZl9NQXQkYnlDbGFzcykNCn0NCmBgYA0KDQpgYGB7ciBlY2hvPVRSVUV9DQpjdHUxOURvd25fQ00gPC0gYygpDQpjdHUxOURvd25fQ00gPC0gZm9yZWFjaDo6Zm9yZWFjaChpID0gMToxMCwNCiAgICAgICAgICAgICAgICAgLnBhY2thZ2VzID0gcmVxcGtncywNCiAgICAgICAgICAgICAgICAgLmNvbWJpbmUgPSBjYmluZA0KKSAlZG9wYXIlIHsNCiAgICAgICAgICAgICAgICAgIHRlc3RfbW9kZWxfZG93bihjdHUxOSkgDQogICAgICAgICAgICAgICAgIH0NCmBgYA0KDQpgYGB7cn0NCnByb21lZGlvX0Rvd24gPC0gYygpDQpwcm9tIDwtIHJvd01lYW5zKGN0dTE5RG93bl9DTSkNCnN0YW5kYXJkX2RldmlhdGlvbiA8LSByb3dTZHMoY3R1MTlEb3duX0NNKQ0KcHJvbWVkaW9fRG93biA8LSBwcm9tZWRpb19Eb3duICU+JSBjYmluZChwcm9tKSAlPiUgY2JpbmQoc3RhbmRhcmRfZGV2aWF0aW9uKQ0KcHJvbWVkaW9fRG93biAlPiUgYXMuZGF0YS5mcmFtZSgpDQpgYGANCg0KIyMjIENUVTE5IGNvbiBVcFNhbXBsaW5nDQoNCmBgYHtyIGVjaG89VFJVRX0NCnRlc3RfbW9kZWxfdXAgPC0gZnVuY3Rpb24oY3R1MTkpew0KICAjVHJhaW4gNzAlIHkgMzAlDQogIHRyYWluX2RhdGFfaW5kIDwtIGNyZWF0ZURhdGFQYXJ0aXRpb24oY3R1MTkkTGFiZWxOYW1lLCBwID0gMC43LGxpc3QgPSBGQUxTRSkNCiAgdHJhaW5fZGF0YSA8LSBjdHUxOVt0cmFpbl9kYXRhX2luZCxdDQogIHRlc3RfZGF0YSA8LSBjdHUxOVstdHJhaW5fZGF0YV9pbmQsXQ0KICANCiAgdXBfdHJhaW5fZGF0YSA8LSB1cFNhbXBsZSh0cmFpbl9kYXRhLHRyYWluX2RhdGEkTGFiZWxOYW1lLCBsaXN0PUZBTFNFKQ0KICB1cF90cmFpbl9kYXRhIDwtIHVwX3RyYWluX2RhdGEgJT4lIHNlbGVjdCgtQ2xhc3MpDQogIA0KICBzZXQuc2VlZCgxMjMpDQogIG1vZGVsb19yYW5kb21mb3Jlc3QgPC0gcmFuZG9tRm9yZXN0KExhYmVsTmFtZX4uLCBkYXRhPXVwX3RyYWluX2RhdGEgLG5hLmFjdGlvbiA9IG5hLm9taXQpDQogIA0KICBwcmVkaWN0aW9uIDwtIHByZWRpY3QobW9kZWxvX3JhbmRvbWZvcmVzdCx0ZXN0X2RhdGEpDQogIGNvbmZfTUF0IDwtIGNvbmZ1c2lvbk1hdHJpeChwcmVkaWN0aW9uLCB0ZXN0X2RhdGEkTGFiZWxOYW1lKQ0KICByZXR1cm4oY29uZl9NQXQkYnlDbGFzcykNCn0NCmBgYA0KDQpgYGB7ciBlY2hvPVRSVUV9DQpjdHUxOVVwX0NNIDwtIGMoKQ0KY3R1MTlVcF9DTSA8LSBmb3JlYWNoOjpmb3JlYWNoKGkgPSAxOjEwLA0KICAgICAgICAgICAgICAgICAucGFja2FnZXMgPSByZXFwa2dzLA0KICAgICAgICAgICAgICAgICAuY29tYmluZSA9IGNiaW5kDQopICVkb3BhciUgew0KICAgICAgICAgICAgICAgICAgdGVzdF9tb2RlbF91cChjdHUxOSkgDQogICAgICAgICAgICAgICAgIH0NCmBgYA0KDQpgYGB7cn0NCnByb21lZGlvX1VwIDwtIGMoKQ0KcHJvbSA8LSByb3dNZWFucyhjdHUxOVVwX0NNKQ0Kc3RhbmRhcmRfZGV2aWF0aW9uIDwtIHJvd1NkcyhjdHUxOVVwX0NNKQ0KcHJvbWVkaW9fVXAgPC0gcHJvbWVkaW9fVXAgJT4lIGNiaW5kKHByb20pICU+JSBjYmluZChzdGFuZGFyZF9kZXZpYXRpb24pDQpwcm9tZWRpb19VcCAlPiUgYXMuZGF0YS5mcmFtZSgpIA0KYGBgDQoNCiMgU2VndW5kYSBQYXJ0ZQ0KDQpgYGB7ciBpbmNsdWRlPUZBTFNFfQ0KY3R1MTkgPSByZWFkcjo6cmVhZF9kZWxpbShmaWxlPSJDOi9Vc2Vycy9EdXp6TG9naWMvR29vZ2xlIERyaXZlL0Nvc2FzL0xBQlNJTi9Cb3RuZXRzL2N0dS9jdHUxOS5jc3YiLGRlbGltID0gJywnKQ0KYGBgDQoNCmBgYHtyfQ0KY3R1MTkgPC0gY3R1MTkgJT4lIHNlbGVjdCgtWDEpDQpjdHUxOSAlPiUgaGVhZCg1MCkNCmBgYA0KDQoNClNhY2Ftb3MgbG9zIHNpbWJvbG9zIGRlIHRpZW1wby4NCg0KYGBge3J9DQp0aW1lX3NpbWJvbF9wYXR0ZXJuIDwtICcoXFwuKSooXFwsKSooXFwrKSooXFwqKSooMCkqJw0KDQpjdHUxOSRTdGF0ZSA8LSBjdHUxOSRTdGF0ZSAlPiUgc3RyX3JlcGxhY2VfYWxsKHRpbWVfc2ltYm9sX3BhdHRlcm4sIiIpDQpgYGANCg0KDQpFbGltaW5hbW9zIGxvcyBwcmltZXJvcyA0IHNpbWJvbG9zLiBPYnZpYW1lbnRlLCBsYXMgc2VjdWVuY2lhcyBkZSBzb2xvIDQgc2ltYm9sb3Mgc29uIGVsaW1pbmFkYXMuDQoNCmBgYHtyIGVjaG89VFJVRX0NCmN0dTE5IDwtIGN0dTE5ICU+JSBmaWx0ZXIobmNoYXIoU3RhdGUpID4gNCkNCmN0dTE5JFN0YXRlIDwtIGN0dTE5JFN0YXRlICU+JSBzdWJzdHIoNCxuY2hhcihjdHUxOSRTdGF0ZSkpDQpgYGANCg0KYGBge3J9DQpjdHUxOSAlPiUgaGVhZCg1MCkNCmBgYA0KDQojIyBBcm1hbW9zIGxvcyBkYXRhc2V0IGRlIHRhbWHDsW8gTg0KDQojIyMgVGFtYcOxbyAxMA0KDQpgYGB7cn0NCmN0dTE5XzEwIDwtIGN0dTE5DQpjdHUxOV8xMCRTdGF0ZSA8LSBjdHUxOSRTdGF0ZSAlPiUgc3Vic3RyKDEsMTApDQpgYGANCg0KDQojIyMgVGFtYcOxbyAyMA0KDQpgYGB7cn0NCmN0dTE5XzIwIDwtIGN0dTE5DQpjdHUxOV8yMCRTdGF0ZSA8LSBjdHUxOSRTdGF0ZSAlPiUgc3Vic3RyKDEsMjApDQpgYGANCg0KDQojIyMgVGFtYcOxbyA0MA0KDQpgYGB7cn0NCmN0dTE5XzQwIDwtIGN0dTE5DQpjdHUxOV80MCRTdGF0ZSA8LSBjdHUxOSRTdGF0ZSAlPiUgc3Vic3RyKDEsNDApDQpgYGANCg0KDQojIyMgVGFtYcOxbyA4MA0KDQpgYGB7cn0NCmN0dTE5XzgwIDwtIGN0dTE5DQpjdHUxOV84MCRTdGF0ZSA8LSBjdHUxOSRTdGF0ZSAlPiUgc3Vic3RyKDEsODApDQpgYGANCg0KDQojIyMgVGFtYcOxbyAxMDANCg0KYGBge3J9DQpjdHUxOV8xMDAgPC0gY3R1MTkNCmN0dTE5XzEwMCRTdGF0ZSA8LSBjdHUxOSRTdGF0ZSAlPiUgc3Vic3RyKDEsMTAwKQ0KYGBgDQoNCg0KIyMjIFRhbWHDsW8gMjAwDQoNCmBgYHtyfQ0KY3R1MTlfMjAwIDwtIGN0dTE5DQpjdHUxOV8yMDAkU3RhdGUgPC0gY3R1MTkkU3RhdGUgJT4lIHN1YnN0cigxLDIwMCkNCmBgYA0KDQoNCiMjIyBUYW1hw7FvIDQwMA0KDQpgYGB7cn0NCmN0dTE5XzQwMCA8LSBjdHUxOQ0KY3R1MTlfNDAwJFN0YXRlIDwtIGN0dTE5JFN0YXRlICU+JSBzdWJzdHIoMSw0MDApDQpgYGANCg0KDQojIyMgVGFtYcOxbyA4MDANCg0KYGBge3J9DQpjdHUxOV84MDAgPC0gY3R1MTkNCmN0dTE5XzgwMCRTdGF0ZSA8LSBjdHUxOSRTdGF0ZSAlPiUgc3Vic3RyKDEsODAwKQ0KYGBgDQoNCg0KIyMjIFRhbWHDsW8gMTAwMA0KDQpgYGB7cn0NCmN0dTE5XzEwMDAgPC0gY3R1MTkNCmN0dTE5XzEwMDAkU3RhdGUgPC0gY3R1MTkkU3RhdGUgJT4lIHN1YnN0cigxLDEwMDApDQpgYGANCg0KIyMgVmVjdG9yIGRlIERhdGFTZXRzDQoNCmBgYHtyfQ0KZGF0YVNldHMgPC0gbGlzdChjdHUxOV8xMCxjdHUxOV8yMCxjdHUxOV80MCxjdHUxOV84MCxjdHUxOV8xMDAsY3R1MTlfMjAwLGN0dTE5XzQwMCxjdHUxOV84MDAsY3R1MTlfMTAwMCkNCmBgYA0KDQoNCiMjIEZlYXR1cmUgVmVjdG9yDQoNCmBgYHtyfQ0KZGF0YVNldHMgPC0gbGFwcGx5KGRhdGFTZXRzLCBmdW5jdGlvbih4KSB4IDwtIGZlYXR1cmVfdmVjdG9yKGFzLmRhdGEuZnJhbWUoeCkpKQ0KYGBgDQoNCg0KIyMgTGltcGllemENCg0KRGVqYW1vcyBzb2xvIGxhcyBjb2x1bW5hcyBxdWUgbm9zIGludGVyZXNhbg0KDQpgYGB7cn0NCmxpbXBpZXphIDwtIGZ1bmN0aW9uKHgpew0KICB4IDwtIHggJT4lIHNlbGVjdCgtSW5pdGlhbElwLC1FbmRJUCwtUHJvdG8sLVN0YXRlLC1Qb3J0KQ0KICB4JExhYmVsTmFtZSA8LSBhcy5mYWN0b3IoeCRMYWJlbE5hbWUpDQogIHJldHVybih4KQ0KfQ0KYGBgDQoNCmBgYHtyfQ0KZGF0YVNldHMgPC0gbGFwcGx5KGRhdGFTZXRzLCBmdW5jdGlvbih4KSB4IDwtIGxpbXBpZXphKHgpKQ0KYGBgDQoNCmBgYHtyfQ0KbGFwcGx5KGRhdGFTZXRzLCBmdW5jdGlvbih4KSBhcy5kYXRhLmZyYW1lKHgpICU+JSBoZWFkKDUwKSkNCmBgYA0KDQoNCiMjIFJhbmRvbSBGb3Jlc3QNCg0KIyMjIENUVTE5IHB1cm8NCg0KYGBge3J9DQpjdHUxOV9wdXJvX0RTIDwtIGxhcHBseShkYXRhU2V0cywgZnVuY3Rpb24oeCkgew0KICBjdHUxOVB1cm9fRFMgPC0gYygpDQogIGN0dTE5UHVyb19EUyA8LSBmb3JlYWNoOjpmb3JlYWNoKGkgPSAxOjEwLA0KICAgICAgICAgICAgICAgICAucGFja2FnZXMgPSByZXFwa2dzLA0KICAgICAgICAgICAgICAgICAuY29tYmluZSA9IGNiaW5kLA0KICAgICAgICAgICAgICAgICAuZXhwb3J0ID0gYygidGVzdF9tb2RlbCIpDQogICkgJWRvcGFyJSB7DQogICAgICAgICAgICAgICAgdGVzdF9tb2RlbChhcy5kYXRhLmZyYW1lKHgpKSANCiAgICAgICAgICAgICAgICAgfQ0KICByZXR1cm4oY3R1MTlQdXJvX0RTKQ0KfSkNCmBgYA0KDQpgYGB7cn0NCnByb21lZGlvX1B1cm9fRFMgPC0gbGFwcGx5KGN0dTE5X3B1cm9fRFMsIGZ1bmN0aW9uKHgpew0KICByZXNwIDwtIGMoKQ0KICBwcm9tIDwtIHJvd01lYW5zKHgpDQogIHN0YW5kYXJkX2RldmlhdGlvbiA8LSByb3dTZHMoeCkNCiAgcmVzcCA8LSByZXNwICU+JSBjYmluZChwcm9tKSAlPiUgY2JpbmQoc3RhbmRhcmRfZGV2aWF0aW9uKQ0KICByZXR1cm4ocmVzcCkNCn0pDQpgYGANCg0KYGBge3J9DQpsYXBwbHkocHJvbWVkaW9fUHVyb19EUywgZnVuY3Rpb24oeCkgeCAlPiUgYXMuZGF0YS5mcmFtZSgpKQ0KYGBgDQoNCg0KIyMjIENUVTE5IERvd24NCmBgYHtyfQ0KY3R1MTlfRG93bl9EUyA8LSBsYXBwbHkoZGF0YVNldHMsIGZ1bmN0aW9uKHgpIHsNCiAgcmVzcCA8LSBjKCkNCiAgcmVzcCA8LSBmb3JlYWNoOjpmb3JlYWNoKGkgPSAxOjEwLA0KICAgICAgICAgICAgICAgICAucGFja2FnZXMgPSByZXFwa2dzLA0KICAgICAgICAgICAgICAgICAuY29tYmluZSA9IGNiaW5kLA0KICAgICAgICAgICAgICAgICAuZXhwb3J0ID0gYygidGVzdF9tb2RlbF9kb3duIikNCiAgKSAlZG9wYXIlIHsNCiAgICAgICAgICAgICAgICB0ZXN0X21vZGVsX2Rvd24oYXMuZGF0YS5mcmFtZSh4KSkgDQogICAgICAgICAgICAgICAgIH0NCiAgcmV0dXJuKHJlc3ApDQp9KQ0KYGBgDQoNCmBgYHtyfQ0KcHJvbWVkaW9fRG93bl9EUyA8LSBsYXBwbHkoY3R1MTlfRG93bl9EUywgZnVuY3Rpb24oeCl7DQogIHJlc3AgPC0gYygpDQogIHByb20gPC0gcm93TWVhbnMoeCkNCiAgc3RhbmRhcmRfZGV2aWF0aW9uIDwtIHJvd1Nkcyh4KQ0KICByZXNwIDwtIHJlc3AgJT4lIGNiaW5kKHByb20pICU+JSBjYmluZChzdGFuZGFyZF9kZXZpYXRpb24pDQogIHJldHVybihyZXNwKQ0KfSkNCmBgYA0KDQpgYGB7cn0NCmxhcHBseShwcm9tZWRpb19Eb3duX0RTLCBmdW5jdGlvbih4KSB4ICU+JSBhcy5kYXRhLmZyYW1lKCkpDQpgYGANCg0KDQojIyMgQ1RVMTkgVXANCg0KYGBge3J9DQpjdHUxOV9VcF9EUyA8LSBsYXBwbHkoZGF0YVNldHMsIGZ1bmN0aW9uKHgpIHsNCiAgcmVzcCA8LSBjKCkNCiAgcmVzcCA8LSBmb3JlYWNoOjpmb3JlYWNoKGkgPSAxOjEwLA0KICAgICAgICAgICAgICAgICAucGFja2FnZXMgPSByZXFwa2dzLA0KICAgICAgICAgICAgICAgICAuY29tYmluZSA9IGNiaW5kLA0KICAgICAgICAgICAgICAgICAuZXhwb3J0ID0gYygidGVzdF9tb2RlbF91cCIpDQogICkgJWRvcGFyJSB7DQogICAgICAgICAgICAgICAgdGVzdF9tb2RlbF91cChhcy5kYXRhLmZyYW1lKHgpKSANCiAgICAgICAgICAgICAgICAgfQ0KICByZXR1cm4ocmVzcCkNCn0pDQpgYGANCg0KYGBge3J9DQpwcm9tZWRpb19VcF9EUyA8LSBsYXBwbHkoY3R1MTlfVXBfRFMsIGZ1bmN0aW9uKHgpew0KICByZXNwIDwtIGMoKQ0KICBwcm9tIDwtIHJvd01lYW5zKHgpDQogIHN0YW5kYXJkX2RldmlhdGlvbiA8LSByb3dTZHMoeCkNCiAgcmVzcCA8LSByZXNwICU+JSBjYmluZChwcm9tKSAlPiUgY2JpbmQoc3RhbmRhcmRfZGV2aWF0aW9uKQ0KICByZXR1cm4ocmVzcCkNCn0pDQpgYGANCg0KYGBge3J9DQpsYXBwbHkocHJvbWVkaW9fVXBfRFMsIGZ1bmN0aW9uKHgpIHggJT4lIGFzLmRhdGEuZnJhbWUoKSkNCmBgYA==