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,"")
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]'))/nchar(State))
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]'))/nchar(State))
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]'))/nchar(State))
#Periodicity
dataset <- dataset %>% mutate(strong_p = (str_count(State, '[a-i]'))/nchar(State))
dataset <- dataset %>% mutate(weak_p = (str_count(State, '[A-I]'))/nchar(State))
dataset <- dataset %>% mutate(weak_np = (str_count(State, '[r-z]'))/nchar(State))
dataset <- dataset %>% mutate(strong_np = (str_count(State, '[R-Z]'))/nchar(State))
#Duration
dataset <- dataset %>% mutate(short_d = (str_count(State, '[a|A|r|R|1|d|D|u|U|4|g|G|x|X|7]'))/nchar(State))
dataset <- dataset %>% mutate(medium_d = (str_count(State, '[b|B|s|S|2|e|E|v|V|5|h|H|y|Y|8]'))/nchar(State))
dataset <- dataset %>% mutate(long_d = (str_count(State, '[c|C|t|T|3|f|F|w|W|6|i|I|z|Z|9]'))/nchar(State))
}
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
LS0tDQp0aXRsZTogIkJvdG5ldHNfQ1RVMTlfTi9ITiINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCmBgYHtyIGluY2x1ZGU9RkFMU0V9DQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShsYXR0aWNlKQ0KbGlicmFyeSh0aWR5cikNCmxpYnJhcnkoY2FyZXQpDQpsaWJyYXJ5KHJhbmRvbUZvcmVzdCkNCmxpYnJhcnkoZG9QYXJhbGxlbCkNCmxpYnJhcnkoc3RyaW5ncikNCmxpYnJhcnkobWF0cml4U3RhdHMpDQpgYGANCg0KYGBge3J9DQpjbCA8LSBtYWtlQ2x1c3Rlcig0KQ0KcmVnaXN0ZXJEb1BhcmFsbGVsKGNsKQ0KYGBgDQoNCg0KYGBge3J9DQpyZXFwa2dzIDwtIGMoInJhbmRvbUZvcmVzdCIsImNhcmV0IiwidGlkeXIiLCJkcGx5ciIpIA0KYGBgDQoNCiMgUHJpbWVyYSBQYXJ0ZQ0KDQpTaW4gbm9ybWFsaXphciB5IGhhY2llbmRvIGxhIHNlZ3VuZGEgcGFydGUgY29uIHNlY3VlbmNpYXMgZGUgTiBjYXJhY3RlcmVzLiANCg0KYGBge3IgaW5jbHVkZT1GQUxTRX0NCmN0dTE5ID0gcmVhZHI6OnJlYWRfZGVsaW0oZmlsZT0iQzovVXNlcnMvRHV6ekxvZ2ljL0dvb2dsZSBEcml2ZS9Db3Nhcy9MQUJTSU4vQm90bmV0cy9jdHUvY3R1MTkuY3N2IixkZWxpbSA9ICcsJykNCmBgYA0KDQojIyBJbXBvcnRhbW9zIENUVTE5DQoNCmBgYHtyfQ0KY3R1MTkgPC0gY3R1MTkgJT4lIHNlbGVjdCgtWDEpDQpjdHUxOSAlPiUgaGVhZCg1MCkNCmBgYA0KDQoNClNhY2Ftb3MgbG9zIHNpbWJvbG9zIGRlIHRpZW1wby4NCg0KYGBge3J9DQp0aW1lX3NpbWJvbF9wYXR0ZXJuIDwtICcoXFwuKSooXFwsKSooXFwrKSooXFwqKSooMCkqJw0KDQpjdHUxOSRTdGF0ZSA8LSBjdHUxOSRTdGF0ZSAlPiUgc3RyX3JlcGxhY2VfYWxsKHRpbWVfc2ltYm9sX3BhdHRlcm4sIiIpDQpgYGANCg0KDQpFbGltaW5hbW9zIGxvcyBwcmltZXJvcyA0IHNpbWJvbG9zLiBPYnZpYW1lbnRlLCBsYXMgc2VjdWVuY2lhcyBkZSBzb2xvIDQgc2ltYm9sb3Mgc29uIGVsaW1pbmFkYXMuDQoNCmBgYHtyIGVjaG89VFJVRX0NCmN0dTE5IDwtIGN0dTE5ICU+JSBmaWx0ZXIobmNoYXIoU3RhdGUpID4gNCkNCmN0dTE5JFN0YXRlIDwtIGN0dTE5JFN0YXRlICU+JSBzdWJzdHIoNCxuY2hhcihjdHUxOSRTdGF0ZSkpDQpgYGANCg0KYGBge3J9DQpjdHUxOSAlPiUgaGVhZCg1MCkNCmBgYA0KDQojIyBGZWF0dXJlIFZlY3Rvcg0KDQpgYGB7ciBlY2hvPVRSVUV9DQpmZWF0dXJlX3ZlY3RvciA8LSBmdW5jdGlvbihkYXRhc2V0KXsNCiAgI1NpemUNCiAgZGF0YXNldCA8LSBkYXRhc2V0ICU+JSBtdXRhdGUoc21hbGxfcyA9IChzdHJfY291bnQoU3RhdGUsICdbYS1jXScpICsgc3RyX2NvdW50KFN0YXRlLCAnW0EtQ10nKSArIHN0cl9jb3VudChTdGF0ZSwgJ1tyLXRdJykgKyBzdHJfY291bnQoU3RhdGUsICdbUi1UXScpICsgc3RyX2NvdW50KFN0YXRlLCAnWzEtM10nKSkvbmNoYXIoU3RhdGUpKQ0KICBkYXRhc2V0IDwtIGRhdGFzZXQgJT4lIG11dGF0ZShtZWRpdW1fcyA9IChzdHJfY291bnQoU3RhdGUsICdbZC1mXScpICsgc3RyX2NvdW50KFN0YXRlLCAnW0QtRl0nKSArIHN0cl9jb3VudChTdGF0ZSwgJ1t1LXddJykgKyBzdHJfY291bnQoU3RhdGUsICdbVS1XXScpICsgc3RyX2NvdW50KFN0YXRlLCAnWzQtNl0nKSkvbmNoYXIoU3RhdGUpKQ0KICBkYXRhc2V0IDwtIGRhdGFzZXQgJT4lIG11dGF0ZShsYXJnZV9zID0gKHN0cl9jb3VudChTdGF0ZSwgJ1tnLWldJykgKyBzdHJfY291bnQoU3RhdGUsICdbRy1JXScpICsgc3RyX2NvdW50KFN0YXRlLCAnW3gtel0nKSArIHN0cl9jb3VudChTdGF0ZSwgJ1tYLVpdJykgKyBzdHJfY291bnQoU3RhdGUsICdbNy05XScpKS9uY2hhcihTdGF0ZSkpDQogIA0KICAjUGVyaW9kaWNpdHkNCiAgZGF0YXNldCA8LSBkYXRhc2V0ICU+JSBtdXRhdGUoc3Ryb25nX3AgPSAoc3RyX2NvdW50KFN0YXRlLCAnW2EtaV0nKSkvbmNoYXIoU3RhdGUpKQ0KICBkYXRhc2V0IDwtIGRhdGFzZXQgJT4lIG11dGF0ZSh3ZWFrX3AgPSAoc3RyX2NvdW50KFN0YXRlLCAnW0EtSV0nKSkvbmNoYXIoU3RhdGUpKQ0KICBkYXRhc2V0IDwtIGRhdGFzZXQgJT4lIG11dGF0ZSh3ZWFrX25wID0gKHN0cl9jb3VudChTdGF0ZSwgJ1tyLXpdJykpL25jaGFyKFN0YXRlKSkNCiAgZGF0YXNldCA8LSBkYXRhc2V0ICU+JSBtdXRhdGUoc3Ryb25nX25wID0gKHN0cl9jb3VudChTdGF0ZSwgJ1tSLVpdJykpL25jaGFyKFN0YXRlKSkNCiAgDQogICNEdXJhdGlvbg0KICBkYXRhc2V0IDwtIGRhdGFzZXQgJT4lIG11dGF0ZShzaG9ydF9kID0gKHN0cl9jb3VudChTdGF0ZSwgJ1thfEF8cnxSfDF8ZHxEfHV8VXw0fGd8R3x4fFh8N10nKSkvbmNoYXIoU3RhdGUpKQ0KICBkYXRhc2V0IDwtIGRhdGFzZXQgJT4lIG11dGF0ZShtZWRpdW1fZCA9IChzdHJfY291bnQoU3RhdGUsICdbYnxCfHN8U3wyfGV8RXx2fFZ8NXxofEh8eXxZfDhdJykpL25jaGFyKFN0YXRlKSkNCiAgZGF0YXNldCA8LSBkYXRhc2V0ICU+JSBtdXRhdGUobG9uZ19kID0gKHN0cl9jb3VudChTdGF0ZSwgJ1tjfEN8dHxUfDN8ZnxGfHd8V3w2fGl8SXx6fFp8OV0nKSkvbmNoYXIoU3RhdGUpKQ0KICANCn0NCg0KYGBgDQoNCmBgYHtyfQ0KY3R1MTkgPC0gZmVhdHVyZV92ZWN0b3IoY3R1MTkpDQpgYGANCg0KYGBge3J9DQpjdHUxOSAlPiUgaGVhZCg1MCkNCmBgYA0KDQpEZWphbW9zIHNvbG8gbGFzIGNvbHVtbmFzIHF1ZSBub3MgaW50ZXJlc2FuDQoNCmBgYHtyfQ0KY3R1MTkgPC0gY3R1MTkgJT4lIHNlbGVjdCgtSW5pdGlhbElwLC1FbmRJUCwtUHJvdG8sLVN0YXRlLC1Qb3J0KQ0KY3R1MTkkTGFiZWxOYW1lIDwtIGFzLmZhY3RvcihjdHUxOSRMYWJlbE5hbWUpDQpjdHUxOSAlPiUgaGVhZCg1MCkNCmBgYA0KDQojIyBSYW5kb20gRm9yZXN0DQoNCmBgYHtyIGVjaG89VFJVRX0NCnRlc3RfbW9kZWwgPC0gZnVuY3Rpb24oY3R1MTkpew0KICAjVHJhaW4gNzAlIHkgMzAlDQogIHRyYWluX2RhdGFfaW5kIDwtIGNyZWF0ZURhdGFQYXJ0aXRpb24oY3R1MTkkTGFiZWxOYW1lLCBwID0gMC43LGxpc3QgPSBGQUxTRSkNCiAgdHJhaW5fZGF0YSA8LSBjdHUxOVt0cmFpbl9kYXRhX2luZCxdDQogIHRlc3RfZGF0YSA8LSBjdHUxOVstdHJhaW5fZGF0YV9pbmQsXQ0KICANCiAgc2V0LnNlZWQoMTIzKQ0KICBtb2RlbG9fcmFuZG9tZm9yZXN0IDwtIHJhbmRvbUZvcmVzdChMYWJlbE5hbWV+LiwgZGF0YT10cmFpbl9kYXRhLG5hLmFjdGlvbiA9IG5hLm9taXQpDQogIA0KICBwcmVkaWN0aW9uIDwtIHByZWRpY3QobW9kZWxvX3JhbmRvbWZvcmVzdCx0ZXN0X2RhdGEpDQogIGNvbmZfTUF0IDwtIGNvbmZ1c2lvbk1hdHJpeChwcmVkaWN0aW9uLCB0ZXN0X2RhdGEkTGFiZWxOYW1lKQ0KICByZXR1cm4oY29uZl9NQXQkYnlDbGFzcykNCn0NCmBgYA0KDQoNCiMjIyBDVFUxOSBwdXJvDQoNCmBgYHtyIGVjaG89VFJVRX0NCmN0dTE5UHVyb19DTSA8LSBjKCkNCmN0dTE5UHVyb19DTSA8LSBmb3JlYWNoOjpmb3JlYWNoKGkgPSAxOjEwLA0KICAgICAgICAgICAgICAgICAucGFja2FnZXMgPSByZXFwa2dzLA0KICAgICAgICAgICAgICAgICAuY29tYmluZSA9IGNiaW5kDQopICVkb3BhciUgew0KICAgICAgICAgICAgICAgICAgdGVzdF9tb2RlbChjdHUxOSkgDQogICAgICAgICAgICAgICAgIH0NCmBgYA0KDQpgYGB7cn0NCnByb21lZGlvX1B1cm8gPC0gYygpDQpwcm9tIDwtIHJvd01lYW5zKGN0dTE5UHVyb19DTSkNCnN0YW5kYXJkX2RldmlhdGlvbiA8LSByb3dTZHMoY3R1MTlQdXJvX0NNKQ0KcHJvbWVkaW9fUHVybyA8LSBwcm9tZWRpb19QdXJvICU+JSBjYmluZChwcm9tKSAlPiUgY2JpbmQoc3RhbmRhcmRfZGV2aWF0aW9uKQ0KcHJvbWVkaW9fUHVybyAlPiUgYXMuZGF0YS5mcmFtZSgpDQpgYGANCg0KIyMjIENUVTE5IGNvbiBEb3duU2FtcGxpbmcNCg0KYGBge3IgZWNobz1UUlVFfQ0KdGVzdF9tb2RlbF9kb3duIDwtIGZ1bmN0aW9uKGN0dTE5KXsNCiAgI1RyYWluIDcwJSB5IDMwJQ0KICB0cmFpbl9kYXRhX2luZCA8LSBjcmVhdGVEYXRhUGFydGl0aW9uKGN0dTE5JExhYmVsTmFtZSwgcCA9IDAuNyxsaXN0ID0gRkFMU0UpDQogIHRyYWluX2RhdGEgPC0gY3R1MTlbdHJhaW5fZGF0YV9pbmQsXQ0KICB0ZXN0X2RhdGEgPC0gY3R1MTlbLXRyYWluX2RhdGFfaW5kLF0NCiAgDQogIGRvd25fdHJhaW5fZGF0YSA8LSBkb3duU2FtcGxlKHRyYWluX2RhdGEsdHJhaW5fZGF0YSRMYWJlbE5hbWUsIGxpc3Q9RkFMU0UpDQogIGRvd25fdHJhaW5fZGF0YSA8LSBkb3duX3RyYWluX2RhdGEgJT4lIHNlbGVjdCgtQ2xhc3MpDQogIA0KICBzZXQuc2VlZCgxMjMpDQogIG1vZGVsb19yYW5kb21mb3Jlc3QgPC0gcmFuZG9tRm9yZXN0KExhYmVsTmFtZX4uLCBkYXRhPWRvd25fdHJhaW5fZGF0YSAsbmEuYWN0aW9uID0gbmEub21pdCkNCiAgDQogIHByZWRpY3Rpb24gPC0gcHJlZGljdChtb2RlbG9fcmFuZG9tZm9yZXN0LHRlc3RfZGF0YSkNCiAgY29uZl9NQXQgPC0gY29uZnVzaW9uTWF0cml4KHByZWRpY3Rpb24sIHRlc3RfZGF0YSRMYWJlbE5hbWUpDQogIHJldHVybihjb25mX01BdCRieUNsYXNzKQ0KfQ0KYGBgDQoNCmBgYHtyIGVjaG89VFJVRX0NCmN0dTE5RG93bl9DTSA8LSBjKCkNCmN0dTE5RG93bl9DTSA8LSBmb3JlYWNoOjpmb3JlYWNoKGkgPSAxOjEwLA0KICAgICAgICAgICAgICAgICAucGFja2FnZXMgPSByZXFwa2dzLA0KICAgICAgICAgICAgICAgICAuY29tYmluZSA9IGNiaW5kDQopICVkb3BhciUgew0KICAgICAgICAgICAgICAgICAgdGVzdF9tb2RlbF9kb3duKGN0dTE5KSANCiAgICAgICAgICAgICAgICAgfQ0KYGBgDQoNCmBgYHtyfQ0KcHJvbWVkaW9fRG93biA8LSBjKCkNCnByb20gPC0gcm93TWVhbnMoY3R1MTlEb3duX0NNKQ0Kc3RhbmRhcmRfZGV2aWF0aW9uIDwtIHJvd1NkcyhjdHUxOURvd25fQ00pDQpwcm9tZWRpb19Eb3duIDwtIHByb21lZGlvX0Rvd24gJT4lIGNiaW5kKHByb20pICU+JSBjYmluZChzdGFuZGFyZF9kZXZpYXRpb24pDQpwcm9tZWRpb19Eb3duICU+JSBhcy5kYXRhLmZyYW1lKCkNCmBgYA0KDQojIyMgQ1RVMTkgY29uIFVwU2FtcGxpbmcNCg0KYGBge3IgZWNobz1UUlVFfQ0KdGVzdF9tb2RlbF91cCA8LSBmdW5jdGlvbihjdHUxOSl7DQogICNUcmFpbiA3MCUgeSAzMCUNCiAgdHJhaW5fZGF0YV9pbmQgPC0gY3JlYXRlRGF0YVBhcnRpdGlvbihjdHUxOSRMYWJlbE5hbWUsIHAgPSAwLjcsbGlzdCA9IEZBTFNFKQ0KICB0cmFpbl9kYXRhIDwtIGN0dTE5W3RyYWluX2RhdGFfaW5kLF0NCiAgdGVzdF9kYXRhIDwtIGN0dTE5Wy10cmFpbl9kYXRhX2luZCxdDQogIA0KICB1cF90cmFpbl9kYXRhIDwtIHVwU2FtcGxlKHRyYWluX2RhdGEsdHJhaW5fZGF0YSRMYWJlbE5hbWUsIGxpc3Q9RkFMU0UpDQogIHVwX3RyYWluX2RhdGEgPC0gdXBfdHJhaW5fZGF0YSAlPiUgc2VsZWN0KC1DbGFzcykNCiAgDQogIHNldC5zZWVkKDEyMykNCiAgbW9kZWxvX3JhbmRvbWZvcmVzdCA8LSByYW5kb21Gb3Jlc3QoTGFiZWxOYW1lfi4sIGRhdGE9dXBfdHJhaW5fZGF0YSAsbmEuYWN0aW9uID0gbmEub21pdCkNCiAgDQogIHByZWRpY3Rpb24gPC0gcHJlZGljdChtb2RlbG9fcmFuZG9tZm9yZXN0LHRlc3RfZGF0YSkNCiAgY29uZl9NQXQgPC0gY29uZnVzaW9uTWF0cml4KHByZWRpY3Rpb24sIHRlc3RfZGF0YSRMYWJlbE5hbWUpDQogIHJldHVybihjb25mX01BdCRieUNsYXNzKQ0KfQ0KYGBgDQoNCmBgYHtyIGVjaG89VFJVRX0NCmN0dTE5VXBfQ00gPC0gYygpDQpjdHUxOVVwX0NNIDwtIGZvcmVhY2g6OmZvcmVhY2goaSA9IDE6MTAsDQogICAgICAgICAgICAgICAgIC5wYWNrYWdlcyA9IHJlcXBrZ3MsDQogICAgICAgICAgICAgICAgIC5jb21iaW5lID0gY2JpbmQNCikgJWRvcGFyJSB7DQogICAgICAgICAgICAgICAgICB0ZXN0X21vZGVsX3VwKGN0dTE5KSANCiAgICAgICAgICAgICAgICAgfQ0KYGBgDQoNCmBgYHtyfQ0KcHJvbWVkaW9fVXAgPC0gYygpDQpwcm9tIDwtIHJvd01lYW5zKGN0dTE5VXBfQ00pDQpzdGFuZGFyZF9kZXZpYXRpb24gPC0gcm93U2RzKGN0dTE5VXBfQ00pDQpwcm9tZWRpb19VcCA8LSBwcm9tZWRpb19VcCAlPiUgY2JpbmQocHJvbSkgJT4lIGNiaW5kKHN0YW5kYXJkX2RldmlhdGlvbikNCnByb21lZGlvX1VwICU+JSBhcy5kYXRhLmZyYW1lKCkgDQpgYGANCg0KIyBTZWd1bmRhIFBhcnRlDQoNCmBgYHtyIGluY2x1ZGU9RkFMU0V9DQpjdHUxOSA9IHJlYWRyOjpyZWFkX2RlbGltKGZpbGU9IkM6L1VzZXJzL0R1enpMb2dpYy9Hb29nbGUgRHJpdmUvQ29zYXMvTEFCU0lOL0JvdG5ldHMvY3R1L2N0dTE5LmNzdiIsZGVsaW0gPSAnLCcpDQpgYGANCg0KYGBge3J9DQpjdHUxOSA8LSBjdHUxOSAlPiUgc2VsZWN0KC1YMSkNCmN0dTE5ICU+JSBoZWFkKDUwKQ0KYGBgDQoNCg0KU2FjYW1vcyBsb3Mgc2ltYm9sb3MgZGUgdGllbXBvLg0KDQpgYGB7cn0NCnRpbWVfc2ltYm9sX3BhdHRlcm4gPC0gJyhcXC4pKihcXCwpKihcXCspKihcXCopKigwKSonDQoNCmN0dTE5JFN0YXRlIDwtIGN0dTE5JFN0YXRlICU+JSBzdHJfcmVwbGFjZV9hbGwodGltZV9zaW1ib2xfcGF0dGVybiwiIikNCmBgYA0KDQoNCkVsaW1pbmFtb3MgbG9zIHByaW1lcm9zIDQgc2ltYm9sb3MuIE9idmlhbWVudGUsIGxhcyBzZWN1ZW5jaWFzIGRlIHNvbG8gNCBzaW1ib2xvcyBzb24gZWxpbWluYWRhcy4NCg0KYGBge3IgZWNobz1UUlVFfQ0KY3R1MTkgPC0gY3R1MTkgJT4lIGZpbHRlcihuY2hhcihTdGF0ZSkgPiA0KQ0KY3R1MTkkU3RhdGUgPC0gY3R1MTkkU3RhdGUgJT4lIHN1YnN0cig0LG5jaGFyKGN0dTE5JFN0YXRlKSkNCmBgYA0KDQpgYGB7cn0NCmN0dTE5ICU+JSBoZWFkKDUwKQ0KYGBgDQoNCiMjIEFybWFtb3MgbG9zIGRhdGFzZXQgZGUgdGFtYcOxbyBODQoNCiMjIyBUYW1hw7FvIDEwDQoNCmBgYHtyfQ0KY3R1MTlfMTAgPC0gY3R1MTkNCmN0dTE5XzEwJFN0YXRlIDwtIGN0dTE5JFN0YXRlICU+JSBzdWJzdHIoMSwxMCkNCmBgYA0KDQoNCiMjIyBUYW1hw7FvIDIwDQoNCmBgYHtyfQ0KY3R1MTlfMjAgPC0gY3R1MTkNCmN0dTE5XzIwJFN0YXRlIDwtIGN0dTE5JFN0YXRlICU+JSBzdWJzdHIoMSwyMCkNCmBgYA0KDQoNCiMjIyBUYW1hw7FvIDQwDQoNCmBgYHtyfQ0KY3R1MTlfNDAgPC0gY3R1MTkNCmN0dTE5XzQwJFN0YXRlIDwtIGN0dTE5JFN0YXRlICU+JSBzdWJzdHIoMSw0MCkNCmBgYA0KDQoNCiMjIyBUYW1hw7FvIDgwDQoNCmBgYHtyfQ0KY3R1MTlfODAgPC0gY3R1MTkNCmN0dTE5XzgwJFN0YXRlIDwtIGN0dTE5JFN0YXRlICU+JSBzdWJzdHIoMSw4MCkNCmBgYA0KDQoNCiMjIyBUYW1hw7FvIDEwMA0KDQpgYGB7cn0NCmN0dTE5XzEwMCA8LSBjdHUxOQ0KY3R1MTlfMTAwJFN0YXRlIDwtIGN0dTE5JFN0YXRlICU+JSBzdWJzdHIoMSwxMDApDQpgYGANCg0KDQojIyMgVGFtYcOxbyAyMDANCg0KYGBge3J9DQpjdHUxOV8yMDAgPC0gY3R1MTkNCmN0dTE5XzIwMCRTdGF0ZSA8LSBjdHUxOSRTdGF0ZSAlPiUgc3Vic3RyKDEsMjAwKQ0KYGBgDQoNCg0KIyMjIFRhbWHDsW8gNDAwDQoNCmBgYHtyfQ0KY3R1MTlfNDAwIDwtIGN0dTE5DQpjdHUxOV80MDAkU3RhdGUgPC0gY3R1MTkkU3RhdGUgJT4lIHN1YnN0cigxLDQwMCkNCmBgYA0KDQoNCiMjIyBUYW1hw7FvIDgwMA0KDQpgYGB7cn0NCmN0dTE5XzgwMCA8LSBjdHUxOQ0KY3R1MTlfODAwJFN0YXRlIDwtIGN0dTE5JFN0YXRlICU+JSBzdWJzdHIoMSw4MDApDQpgYGANCg0KDQojIyMgVGFtYcOxbyAxMDAwDQoNCmBgYHtyfQ0KY3R1MTlfMTAwMCA8LSBjdHUxOQ0KY3R1MTlfMTAwMCRTdGF0ZSA8LSBjdHUxOSRTdGF0ZSAlPiUgc3Vic3RyKDEsMTAwMCkNCmBgYA0KDQojIyBWZWN0b3IgZGUgRGF0YVNldHMNCg0KYGBge3J9DQpkYXRhU2V0cyA8LSBsaXN0KGN0dTE5XzEwLGN0dTE5XzIwLGN0dTE5XzQwLGN0dTE5XzgwLGN0dTE5XzEwMCxjdHUxOV8yMDAsY3R1MTlfNDAwLGN0dTE5XzgwMCxjdHUxOV8xMDAwKQ0KYGBgDQoNCg0KIyMgRmVhdHVyZSBWZWN0b3INCg0KYGBge3J9DQpkYXRhU2V0cyA8LSBsYXBwbHkoZGF0YVNldHMsIGZ1bmN0aW9uKHgpIHggPC0gZmVhdHVyZV92ZWN0b3IoYXMuZGF0YS5mcmFtZSh4KSkpDQpgYGANCg0KDQojIyBMaW1waWV6YQ0KDQpEZWphbW9zIHNvbG8gbGFzIGNvbHVtbmFzIHF1ZSBub3MgaW50ZXJlc2FuDQoNCmBgYHtyfQ0KbGltcGllemEgPC0gZnVuY3Rpb24oeCl7DQogIHggPC0geCAlPiUgc2VsZWN0KC1Jbml0aWFsSXAsLUVuZElQLC1Qcm90bywtU3RhdGUsLVBvcnQpDQogIHgkTGFiZWxOYW1lIDwtIGFzLmZhY3Rvcih4JExhYmVsTmFtZSkNCiAgcmV0dXJuKHgpDQp9DQpgYGANCg0KYGBge3J9DQpkYXRhU2V0cyA8LSBsYXBwbHkoZGF0YVNldHMsIGZ1bmN0aW9uKHgpIHggPC0gbGltcGllemEoeCkpDQpgYGANCg0KYGBge3J9DQpsYXBwbHkoZGF0YVNldHMsIGZ1bmN0aW9uKHgpIGFzLmRhdGEuZnJhbWUoeCkgJT4lIGhlYWQoNTApKQ0KYGBgDQoNCg0KIyMgUmFuZG9tIEZvcmVzdA0KDQojIyMgQ1RVMTkgcHVybw0KDQpgYGB7cn0NCmN0dTE5X3B1cm9fRFMgPC0gbGFwcGx5KGRhdGFTZXRzLCBmdW5jdGlvbih4KSB7DQogIGN0dTE5UHVyb19EUyA8LSBjKCkNCiAgY3R1MTlQdXJvX0RTIDwtIGZvcmVhY2g6OmZvcmVhY2goaSA9IDE6MTAsDQogICAgICAgICAgICAgICAgIC5wYWNrYWdlcyA9IHJlcXBrZ3MsDQogICAgICAgICAgICAgICAgIC5jb21iaW5lID0gY2JpbmQsDQogICAgICAgICAgICAgICAgIC5leHBvcnQgPSBjKCJ0ZXN0X21vZGVsIikNCiAgKSAlZG9wYXIlIHsNCiAgICAgICAgICAgICAgICB0ZXN0X21vZGVsKGFzLmRhdGEuZnJhbWUoeCkpIA0KICAgICAgICAgICAgICAgICB9DQogIHJldHVybihjdHUxOVB1cm9fRFMpDQp9KQ0KYGBgDQoNCmBgYHtyfQ0KcHJvbWVkaW9fUHVyb19EUyA8LSBsYXBwbHkoY3R1MTlfcHVyb19EUywgZnVuY3Rpb24oeCl7DQogIHJlc3AgPC0gYygpDQogIHByb20gPC0gcm93TWVhbnMoeCkNCiAgc3RhbmRhcmRfZGV2aWF0aW9uIDwtIHJvd1Nkcyh4KQ0KICByZXNwIDwtIHJlc3AgJT4lIGNiaW5kKHByb20pICU+JSBjYmluZChzdGFuZGFyZF9kZXZpYXRpb24pDQogIHJldHVybihyZXNwKQ0KfSkNCmBgYA0KDQpgYGB7cn0NCmxhcHBseShwcm9tZWRpb19QdXJvX0RTLCBmdW5jdGlvbih4KSB4ICU+JSBhcy5kYXRhLmZyYW1lKCkpDQpgYGANCg0KDQojIyMgQ1RVMTkgRG93bg0KYGBge3J9DQpjdHUxOV9Eb3duX0RTIDwtIGxhcHBseShkYXRhU2V0cywgZnVuY3Rpb24oeCkgew0KICByZXNwIDwtIGMoKQ0KICByZXNwIDwtIGZvcmVhY2g6OmZvcmVhY2goaSA9IDE6MTAsDQogICAgICAgICAgICAgICAgIC5wYWNrYWdlcyA9IHJlcXBrZ3MsDQogICAgICAgICAgICAgICAgIC5jb21iaW5lID0gY2JpbmQsDQogICAgICAgICAgICAgICAgIC5leHBvcnQgPSBjKCJ0ZXN0X21vZGVsX2Rvd24iKQ0KICApICVkb3BhciUgew0KICAgICAgICAgICAgICAgIHRlc3RfbW9kZWxfZG93bihhcy5kYXRhLmZyYW1lKHgpKSANCiAgICAgICAgICAgICAgICAgfQ0KICByZXR1cm4ocmVzcCkNCn0pDQpgYGANCg0KYGBge3J9DQpwcm9tZWRpb19Eb3duX0RTIDwtIGxhcHBseShjdHUxOV9Eb3duX0RTLCBmdW5jdGlvbih4KXsNCiAgcmVzcCA8LSBjKCkNCiAgcHJvbSA8LSByb3dNZWFucyh4KQ0KICBzdGFuZGFyZF9kZXZpYXRpb24gPC0gcm93U2RzKHgpDQogIHJlc3AgPC0gcmVzcCAlPiUgY2JpbmQocHJvbSkgJT4lIGNiaW5kKHN0YW5kYXJkX2RldmlhdGlvbikNCiAgcmV0dXJuKHJlc3ApDQp9KQ0KYGBgDQoNCmBgYHtyfQ0KbGFwcGx5KHByb21lZGlvX0Rvd25fRFMsIGZ1bmN0aW9uKHgpIHggJT4lIGFzLmRhdGEuZnJhbWUoKSkNCmBgYA0KDQoNCiMjIyBDVFUxOSBVcA0KDQpgYGB7cn0NCmN0dTE5X1VwX0RTIDwtIGxhcHBseShkYXRhU2V0cywgZnVuY3Rpb24oeCkgew0KICByZXNwIDwtIGMoKQ0KICByZXNwIDwtIGZvcmVhY2g6OmZvcmVhY2goaSA9IDE6MTAsDQogICAgICAgICAgICAgICAgIC5wYWNrYWdlcyA9IHJlcXBrZ3MsDQogICAgICAgICAgICAgICAgIC5jb21iaW5lID0gY2JpbmQsDQogICAgICAgICAgICAgICAgIC5leHBvcnQgPSBjKCJ0ZXN0X21vZGVsX3VwIikNCiAgKSAlZG9wYXIlIHsNCiAgICAgICAgICAgICAgICB0ZXN0X21vZGVsX3VwKGFzLmRhdGEuZnJhbWUoeCkpIA0KICAgICAgICAgICAgICAgICB9DQogIHJldHVybihyZXNwKQ0KfSkNCmBgYA0KDQpgYGB7cn0NCnByb21lZGlvX1VwX0RTIDwtIGxhcHBseShjdHUxOV9VcF9EUywgZnVuY3Rpb24oeCl7DQogIHJlc3AgPC0gYygpDQogIHByb20gPC0gcm93TWVhbnMoeCkNCiAgc3RhbmRhcmRfZGV2aWF0aW9uIDwtIHJvd1Nkcyh4KQ0KICByZXNwIDwtIHJlc3AgJT4lIGNiaW5kKHByb20pICU+JSBjYmluZChzdGFuZGFyZF9kZXZpYXRpb24pDQogIHJldHVybihyZXNwKQ0KfSkNCmBgYA0KDQpgYGB7cn0NCmxhcHBseShwcm9tZWRpb19VcF9EUywgZnVuY3Rpb24oeCkgeCAlPiUgYXMuZGF0YS5mcmFtZSgpKQ0KYGBgDQoNCg0KDQoNCg0KDQoNCg==