Primera Parte

Importamos CTU19

ctu19 <- ctu19 %>% select(-X1)
Error: Can't subset columns that don't exist.
x Column `X1` doesn't exist.

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]'))
  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()
foreach(i = 1:10) %do% {ctu19Puro_CM <- ctu19Puro_CM %>% cbind(test_model(ctu19))}
promedio_Puro <- c()
promedio_Puro <- rowMeans(ctu19Puro_CM)
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()
foreach(i = 1:10) %do% {ctu19Down_CM <- ctu19Down_CM %>% cbind(test_model_down(ctu19))}
promedio_Down <- c()
promedio_Down <- rowMeans(ctu19Down_CM)
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()
foreach(i = 1:10) %do% {ctu19Up_CM <- ctu19Up_CM %>% cbind(test_model_up(ctu19))}
promedio_Up <- c()
promedio_Up <- rowMeans(ctu19Up_CM)
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 %>% filter(nchar(State) > 9)
ctu19_10$State <- ctu19_10$State %>% substr(1,10)
ctu19_10

Tamaño 20

ctu19_20 <- ctu19 %>% filter(nchar(State) > 19)
ctu19_20$State <- ctu19_20$State %>% substr(1,20)

Tamaño 40

ctu19_40 <- ctu19 %>% filter(nchar(State) > 39)
ctu19_40$State <- ctu19_40$State %>% substr(1,40)

Tamaño 80

ctu19_80 <- ctu19 %>% filter(nchar(State) > 79)
ctu19_80$State <- ctu19_80$State %>% substr(1,80)

Tamaño 100

ctu19_100 <- ctu19 %>% filter(nchar(State) > 99)
ctu19_100$State <- ctu19_100$State %>% substr(1,100)

Tamaño 200

ctu19_200 <- ctu19 %>% filter(nchar(State) > 199)
ctu19_200$State <- ctu19_200$State %>% substr(1,200)

Tamaño 400

ctu19_400 <- ctu19 %>% filter(nchar(State) > 399)
ctu19_400$State <- ctu19_400$State %>% substr(1,400)

Tamaño 800

ctu19_800 <- ctu19 %>% filter(nchar(State) > 799)
ctu19_800$State <- ctu19_800$State %>% substr(1,800)

Tamaño 1000

ctu19_1000 <- ctu19 %>% filter(nchar(State) > 999)
ctu19_1000$State <- ctu19_1000$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()
  foreach(i = 1:10) %do% {ctu19Puro_DS <- ctu19Puro_DS %>% cbind(test_model(as.data.frame(x)))}
  return(ctu19Puro_DS)
})
promedio_Puro_DS <- lapply(ctu19_puro_DS, function(x){
  resp <- c()
  resp <- rowMeans(x)
  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()
  foreach(i = 1:10) %do% {resp <- resp %>% cbind(test_model_down(as.data.frame(x)))}
  return(resp)
})
promedio_Down_DS <- lapply(ctu19_Down_DS, function(x){
  resp <- c()
  resp <- rowMeans(x)
  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()
  foreach(i = 1:10) %do% {resp <- resp %>% cbind(test_model_up(as.data.frame(x)))}
  return(resp)
})
promedio_Up_DS <- lapply(ctu19_Up_DS, function(x){
  resp <- c()
  resp <- rowMeans(x)
  return(resp)
})
lapply(promedio_Up_DS, function(x) x %>% as.data.frame())
[[1]]

[[2]]

[[3]]

[[4]]

[[5]]

[[6]]

[[7]]

[[8]]

[[9]]
NA
LS0tDQp0aXRsZTogIkJvdG5ldHNfQ1RVMTlfMSINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCmBgYHtyIGluY2x1ZGU9RkFMU0V9DQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShsYXR0aWNlKQ0KbGlicmFyeSh0aWR5cikNCmxpYnJhcnkoY2FyZXQpDQpsaWJyYXJ5KHJhbmRvbUZvcmVzdCkNCmxpYnJhcnkoZG9QYXJhbGxlbCkNCmxpYnJhcnkoc3RyaW5ncikNCmBgYA0KDQojIFByaW1lcmEgUGFydGUNCg0KYGBge3IgaW5jbHVkZT1GQUxTRX0NCmN0dTE5ID0gcmVhZHI6OnJlYWRfZGVsaW0oZmlsZT0iQzovVXNlcnMvRHV6ekxvZ2ljL0dvb2dsZSBEcml2ZS9Db3Nhcy9MQUJTSU4vQm90bmV0cy9jdHUvY3R1MTkuY3N2IixkZWxpbSA9ICcsJykNCmBgYA0KDQojIyBJbXBvcnRhbW9zIENUVTE5DQoNCmBgYHtyfQ0KY3R1MTkgPC0gY3R1MTkgJT4lIHNlbGVjdCgtWDEpDQpjdHUxOSAlPiUgaGVhZCg1MCkNCmBgYA0KDQoNClNhY2Ftb3MgbG9zIHNpbWJvbG9zIGRlIHRpZW1wby4NCg0KYGBge3J9DQp0aW1lX3NpbWJvbF9wYXR0ZXJuIDwtICcoXFwuKSooXFwsKSooXFwrKSooXFwqKSooMCkqJw0KDQpjdHUxOSRTdGF0ZSA8LSBjdHUxOSRTdGF0ZSAlPiUgc3RyX3JlcGxhY2VfYWxsKHRpbWVfc2ltYm9sX3BhdHRlcm4sIiIpDQpgYGANCg0KDQpFbGltaW5hbW9zIGxvcyBwcmltZXJvcyA0IHNpbWJvbG9zLiBPYnZpYW1lbnRlLCBsYXMgc2VjdWVuY2lhcyBkZSBzb2xvIDQgc2ltYm9sb3Mgc29uIGVsaW1pbmFkYXMuDQoNCmBgYHtyIGVjaG89VFJVRX0NCmN0dTE5IDwtIGN0dTE5ICU+JSBmaWx0ZXIobmNoYXIoU3RhdGUpID4gNCkNCmN0dTE5JFN0YXRlIDwtIGN0dTE5JFN0YXRlICU+JSBzdWJzdHIoNCxuY2hhcihjdHUxOSRTdGF0ZSkpDQpgYGANCg0KYGBge3J9DQpjdHUxOSAlPiUgaGVhZCg1MCkNCmBgYA0KDQojIyBGZWF0dXJlIFZlY3Rvcg0KDQpgYGB7ciBlY2hvPVRSVUV9DQpmZWF0dXJlX3ZlY3RvciA8LSBmdW5jdGlvbihkYXRhc2V0KXsNCiAgI1NpemUNCiAgZGF0YXNldCA8LSBkYXRhc2V0ICU+JSBtdXRhdGUoc21hbGxfcyA9IHN0cl9jb3VudChTdGF0ZSwgJ1thLWNdJykgKyBzdHJfY291bnQoU3RhdGUsICdbQS1DXScpICsgc3RyX2NvdW50KFN0YXRlLCAnW3ItdF0nKSArIHN0cl9jb3VudChTdGF0ZSwgJ1tSLVRdJykgKyBzdHJfY291bnQoU3RhdGUsICdbMS0zXScpKQ0KICBkYXRhc2V0IDwtIGRhdGFzZXQgJT4lIG11dGF0ZShtZWRpdW1fcyA9IHN0cl9jb3VudChTdGF0ZSwgJ1tkLWZdJykgKyBzdHJfY291bnQoU3RhdGUsICdbRC1GXScpICsgc3RyX2NvdW50KFN0YXRlLCAnW3Utd10nKSArIHN0cl9jb3VudChTdGF0ZSwgJ1tVLVddJykgKyBzdHJfY291bnQoU3RhdGUsICdbNC02XScpKQ0KICBkYXRhc2V0IDwtIGRhdGFzZXQgJT4lIG11dGF0ZShsYXJnZV9zID0gc3RyX2NvdW50KFN0YXRlLCAnW2ctaV0nKSArIHN0cl9jb3VudChTdGF0ZSwgJ1tHLUldJykgKyBzdHJfY291bnQoU3RhdGUsICdbeC16XScpICsgc3RyX2NvdW50KFN0YXRlLCAnW1gtWl0nKSArIHN0cl9jb3VudChTdGF0ZSwgJ1s3LTldJykpDQogIA0KICAjUGVyaW9kaWNpdHkNCiAgZGF0YXNldCA8LSBkYXRhc2V0ICU+JSBtdXRhdGUoc3Ryb25nX3AgPSBzdHJfY291bnQoU3RhdGUsICdbYS1pXScpKQ0KICBkYXRhc2V0IDwtIGRhdGFzZXQgJT4lIG11dGF0ZSh3ZWFrX3AgPSBzdHJfY291bnQoU3RhdGUsICdbQS1JXScpKQ0KICBkYXRhc2V0IDwtIGRhdGFzZXQgJT4lIG11dGF0ZSh3ZWFrX25wID0gc3RyX2NvdW50KFN0YXRlLCAnW3Itel0nKSkNCiAgZGF0YXNldCA8LSBkYXRhc2V0ICU+JSBtdXRhdGUoc3Ryb25nX25wID0gc3RyX2NvdW50KFN0YXRlLCAnW1ItWl0nKSkNCiAgDQogICNEdXJhdGlvbg0KICBkYXRhc2V0IDwtIGRhdGFzZXQgJT4lIG11dGF0ZShzaG9ydF9kID0gc3RyX2NvdW50KFN0YXRlLCAnW2F8QXxyfFJ8MXxkfER8dXxVfDR8Z3xHfHh8WHw3XScpKQ0KICBkYXRhc2V0IDwtIGRhdGFzZXQgJT4lIG11dGF0ZShtZWRpdW1fZCA9IHN0cl9jb3VudChTdGF0ZSwgJ1tifEJ8c3xTfDJ8ZXxFfHZ8Vnw1fGh8SHx5fFl8OF0nKSkNCiAgZGF0YXNldCA8LSBkYXRhc2V0ICU+JSBtdXRhdGUobG9uZ19kID0gc3RyX2NvdW50KFN0YXRlLCAnW2N8Q3x0fFR8M3xmfEZ8d3xXfDZ8aXxJfHp8Wnw5XScpKQ0KICANCn0NCg0KYGBgDQoNCmBgYHtyfQ0KY3R1MTkgPC0gZmVhdHVyZV92ZWN0b3IoY3R1MTkpDQpgYGANCg0KYGBge3J9DQpjdHUxOSAlPiUgaGVhZCg1MCkNCmBgYA0KDQpEZWphbW9zIHNvbG8gbGFzIGNvbHVtbmFzIHF1ZSBub3MgaW50ZXJlc2FuDQoNCmBgYHtyfQ0KY3R1MTkgPC0gY3R1MTkgJT4lIHNlbGVjdCgtSW5pdGlhbElwLC1FbmRJUCwtUHJvdG8sLVN0YXRlLC1Qb3J0KQ0KY3R1MTkkTGFiZWxOYW1lIDwtIGFzLmZhY3RvcihjdHUxOSRMYWJlbE5hbWUpDQpjdHUxOSAlPiUgaGVhZCg1MCkNCmBgYA0KDQojIyBSYW5kb20gRm9yZXN0DQoNCmBgYHtyIGVjaG89VFJVRX0NCnRlc3RfbW9kZWwgPC0gZnVuY3Rpb24oY3R1MTkpew0KICAjVHJhaW4gNzAlIHkgMzAlDQogIHRyYWluX2RhdGFfaW5kIDwtIGNyZWF0ZURhdGFQYXJ0aXRpb24oY3R1MTkkTGFiZWxOYW1lLCBwID0gMC43LGxpc3QgPSBGQUxTRSkNCiAgdHJhaW5fZGF0YSA8LSBjdHUxOVt0cmFpbl9kYXRhX2luZCxdDQogIHRlc3RfZGF0YSA8LSBjdHUxOVstdHJhaW5fZGF0YV9pbmQsXQ0KICANCiAgc2V0LnNlZWQoMTIzKQ0KICBtb2RlbG9fcmFuZG9tZm9yZXN0IDwtIHJhbmRvbUZvcmVzdChMYWJlbE5hbWV+LiwgZGF0YT10cmFpbl9kYXRhLG5hLmFjdGlvbiA9IG5hLm9taXQpDQogIA0KICBwcmVkaWN0aW9uIDwtIHByZWRpY3QobW9kZWxvX3JhbmRvbWZvcmVzdCx0ZXN0X2RhdGEpDQogIGNvbmZfTUF0IDwtIGNvbmZ1c2lvbk1hdHJpeChwcmVkaWN0aW9uLCB0ZXN0X2RhdGEkTGFiZWxOYW1lKQ0KICByZXR1cm4oY29uZl9NQXQkYnlDbGFzcykNCn0NCmBgYA0KDQoNCiMjIyBDVFUxOSBwdXJvDQoNCmBgYHtyIGVjaG89VFJVRX0NCmN0dTE5UHVyb19DTSA8LSBjKCkNCmZvcmVhY2goaSA9IDE6MTApICVkbyUge2N0dTE5UHVyb19DTSA8LSBjdHUxOVB1cm9fQ00gJT4lIGNiaW5kKHRlc3RfbW9kZWwoY3R1MTkpKX0NCmBgYA0KDQpgYGB7cn0NCnByb21lZGlvX1B1cm8gPC0gYygpDQpwcm9tZWRpb19QdXJvIDwtIHJvd01lYW5zKGN0dTE5UHVyb19DTSkNCnByb21lZGlvX1B1cm8gJT4lIGFzLmRhdGEuZnJhbWUoKQ0KYGBgDQoNCiMjIyBDVFUxOSBjb24gRG93blNhbXBsaW5nDQoNCmBgYHtyIGVjaG89VFJVRX0NCnRlc3RfbW9kZWxfZG93biA8LSBmdW5jdGlvbihjdHUxOSl7DQogICNUcmFpbiA3MCUgeSAzMCUNCiAgdHJhaW5fZGF0YV9pbmQgPC0gY3JlYXRlRGF0YVBhcnRpdGlvbihjdHUxOSRMYWJlbE5hbWUsIHAgPSAwLjcsbGlzdCA9IEZBTFNFKQ0KICB0cmFpbl9kYXRhIDwtIGN0dTE5W3RyYWluX2RhdGFfaW5kLF0NCiAgdGVzdF9kYXRhIDwtIGN0dTE5Wy10cmFpbl9kYXRhX2luZCxdDQogIA0KICBkb3duX3RyYWluX2RhdGEgPC0gZG93blNhbXBsZSh0cmFpbl9kYXRhLHRyYWluX2RhdGEkTGFiZWxOYW1lLCBsaXN0PUZBTFNFKQ0KICBkb3duX3RyYWluX2RhdGEgPC0gZG93bl90cmFpbl9kYXRhICU+JSBzZWxlY3QoLUNsYXNzKQ0KICANCiAgc2V0LnNlZWQoMTIzKQ0KICBtb2RlbG9fcmFuZG9tZm9yZXN0IDwtIHJhbmRvbUZvcmVzdChMYWJlbE5hbWV+LiwgZGF0YT1kb3duX3RyYWluX2RhdGEgLG5hLmFjdGlvbiA9IG5hLm9taXQpDQogIA0KICBwcmVkaWN0aW9uIDwtIHByZWRpY3QobW9kZWxvX3JhbmRvbWZvcmVzdCx0ZXN0X2RhdGEpDQogIGNvbmZfTUF0IDwtIGNvbmZ1c2lvbk1hdHJpeChwcmVkaWN0aW9uLCB0ZXN0X2RhdGEkTGFiZWxOYW1lKQ0KICByZXR1cm4oY29uZl9NQXQkYnlDbGFzcykNCn0NCmBgYA0KDQpgYGB7ciBlY2hvPVRSVUV9DQpjdHUxOURvd25fQ00gPC0gYygpDQpmb3JlYWNoKGkgPSAxOjEwKSAlZG8lIHtjdHUxOURvd25fQ00gPC0gY3R1MTlEb3duX0NNICU+JSBjYmluZCh0ZXN0X21vZGVsX2Rvd24oY3R1MTkpKX0NCmBgYA0KDQpgYGB7cn0NCnByb21lZGlvX0Rvd24gPC0gYygpDQpwcm9tZWRpb19Eb3duIDwtIHJvd01lYW5zKGN0dTE5RG93bl9DTSkNCnByb21lZGlvX0Rvd24gJT4lIGFzLmRhdGEuZnJhbWUoKQ0KYGBgDQoNCiMjIyBDVFUxOSBjb24gVXBTYW1wbGluZw0KDQpgYGB7ciBlY2hvPVRSVUV9DQp0ZXN0X21vZGVsX3VwIDwtIGZ1bmN0aW9uKGN0dTE5KXsNCiAgI1RyYWluIDcwJSB5IDMwJQ0KICB0cmFpbl9kYXRhX2luZCA8LSBjcmVhdGVEYXRhUGFydGl0aW9uKGN0dTE5JExhYmVsTmFtZSwgcCA9IDAuNyxsaXN0ID0gRkFMU0UpDQogIHRyYWluX2RhdGEgPC0gY3R1MTlbdHJhaW5fZGF0YV9pbmQsXQ0KICB0ZXN0X2RhdGEgPC0gY3R1MTlbLXRyYWluX2RhdGFfaW5kLF0NCiAgDQogIHVwX3RyYWluX2RhdGEgPC0gdXBTYW1wbGUodHJhaW5fZGF0YSx0cmFpbl9kYXRhJExhYmVsTmFtZSwgbGlzdD1GQUxTRSkNCiAgdXBfdHJhaW5fZGF0YSA8LSB1cF90cmFpbl9kYXRhICU+JSBzZWxlY3QoLUNsYXNzKQ0KICANCiAgc2V0LnNlZWQoMTIzKQ0KICBtb2RlbG9fcmFuZG9tZm9yZXN0IDwtIHJhbmRvbUZvcmVzdChMYWJlbE5hbWV+LiwgZGF0YT11cF90cmFpbl9kYXRhICxuYS5hY3Rpb24gPSBuYS5vbWl0KQ0KICANCiAgcHJlZGljdGlvbiA8LSBwcmVkaWN0KG1vZGVsb19yYW5kb21mb3Jlc3QsdGVzdF9kYXRhKQ0KICBjb25mX01BdCA8LSBjb25mdXNpb25NYXRyaXgocHJlZGljdGlvbiwgdGVzdF9kYXRhJExhYmVsTmFtZSkNCiAgcmV0dXJuKGNvbmZfTUF0JGJ5Q2xhc3MpDQp9DQpgYGANCg0KYGBge3IgZWNobz1UUlVFfQ0KY3R1MTlVcF9DTSA8LSBjKCkNCmZvcmVhY2goaSA9IDE6MTApICVkbyUge2N0dTE5VXBfQ00gPC0gY3R1MTlVcF9DTSAlPiUgY2JpbmQodGVzdF9tb2RlbF91cChjdHUxOSkpfQ0KYGBgDQoNCmBgYHtyfQ0KcHJvbWVkaW9fVXAgPC0gYygpDQpwcm9tZWRpb19VcCA8LSByb3dNZWFucyhjdHUxOVVwX0NNKQ0KcHJvbWVkaW9fVXAgJT4lIGFzLmRhdGEuZnJhbWUoKSANCmBgYA0KDQojIFNlZ3VuZGEgUGFydGUNCg0KYGBge3IgaW5jbHVkZT1GQUxTRX0NCmN0dTE5ID0gcmVhZHI6OnJlYWRfZGVsaW0oZmlsZT0iQzovVXNlcnMvRHV6ekxvZ2ljL0dvb2dsZSBEcml2ZS9Db3Nhcy9MQUJTSU4vQm90bmV0cy9jdHUvY3R1MTkuY3N2IixkZWxpbSA9ICcsJykNCmBgYA0KDQpgYGB7cn0NCmN0dTE5IDwtIGN0dTE5ICU+JSBzZWxlY3QoLVgxKQ0KY3R1MTkgJT4lIGhlYWQoNTApDQpgYGANCg0KDQpTYWNhbW9zIGxvcyBzaW1ib2xvcyBkZSB0aWVtcG8uDQoNCmBgYHtyfQ0KdGltZV9zaW1ib2xfcGF0dGVybiA8LSAnKFxcLikqKFxcLCkqKFxcKykqKFxcKikqKDApKicNCg0KY3R1MTkkU3RhdGUgPC0gY3R1MTkkU3RhdGUgJT4lIHN0cl9yZXBsYWNlX2FsbCh0aW1lX3NpbWJvbF9wYXR0ZXJuLCIiKQ0KYGBgDQoNCg0KRWxpbWluYW1vcyBsb3MgcHJpbWVyb3MgNCBzaW1ib2xvcy4gT2J2aWFtZW50ZSwgbGFzIHNlY3VlbmNpYXMgZGUgc29sbyA0IHNpbWJvbG9zIHNvbiBlbGltaW5hZGFzLg0KDQpgYGB7ciBlY2hvPVRSVUV9DQpjdHUxOSA8LSBjdHUxOSAlPiUgZmlsdGVyKG5jaGFyKFN0YXRlKSA+IDQpDQpjdHUxOSRTdGF0ZSA8LSBjdHUxOSRTdGF0ZSAlPiUgc3Vic3RyKDQsbmNoYXIoY3R1MTkkU3RhdGUpKQ0KYGBgDQoNCmBgYHtyfQ0KY3R1MTkgJT4lIGhlYWQoNTApDQpgYGANCg0KIyMgQXJtYW1vcyBsb3MgZGF0YXNldCBkZSB0YW1hw7FvIE4NCg0KIyMjIFRhbWHDsW8gMTANCg0KYGBge3J9DQpjdHUxOV8xMCA8LSBjdHUxOSAlPiUgZmlsdGVyKG5jaGFyKFN0YXRlKSA+IDkpDQpjdHUxOV8xMCRTdGF0ZSA8LSBjdHUxOV8xMCRTdGF0ZSAlPiUgc3Vic3RyKDEsMTApDQpgYGANCg0KDQojIyMgVGFtYcOxbyAyMA0KDQpgYGB7cn0NCmN0dTE5XzIwIDwtIGN0dTE5ICU+JSBmaWx0ZXIobmNoYXIoU3RhdGUpID4gMTkpDQpjdHUxOV8yMCRTdGF0ZSA8LSBjdHUxOV8yMCRTdGF0ZSAlPiUgc3Vic3RyKDEsMjApDQpgYGANCg0KDQojIyMgVGFtYcOxbyA0MA0KDQpgYGB7cn0NCmN0dTE5XzQwIDwtIGN0dTE5ICU+JSBmaWx0ZXIobmNoYXIoU3RhdGUpID4gMzkpDQpjdHUxOV80MCRTdGF0ZSA8LSBjdHUxOV80MCRTdGF0ZSAlPiUgc3Vic3RyKDEsNDApDQpgYGANCg0KDQojIyMgVGFtYcOxbyA4MA0KDQpgYGB7cn0NCmN0dTE5XzgwIDwtIGN0dTE5ICU+JSBmaWx0ZXIobmNoYXIoU3RhdGUpID4gNzkpDQpjdHUxOV84MCRTdGF0ZSA8LSBjdHUxOV84MCRTdGF0ZSAlPiUgc3Vic3RyKDEsODApDQpgYGANCg0KDQojIyMgVGFtYcOxbyAxMDANCg0KYGBge3J9DQpjdHUxOV8xMDAgPC0gY3R1MTkgJT4lIGZpbHRlcihuY2hhcihTdGF0ZSkgPiA5OSkNCmN0dTE5XzEwMCRTdGF0ZSA8LSBjdHUxOV8xMDAkU3RhdGUgJT4lIHN1YnN0cigxLDEwMCkNCmBgYA0KDQoNCiMjIyBUYW1hw7FvIDIwMA0KDQpgYGB7cn0NCmN0dTE5XzIwMCA8LSBjdHUxOSAlPiUgZmlsdGVyKG5jaGFyKFN0YXRlKSA+IDE5OSkNCmN0dTE5XzIwMCRTdGF0ZSA8LSBjdHUxOV8yMDAkU3RhdGUgJT4lIHN1YnN0cigxLDIwMCkNCmBgYA0KDQoNCiMjIyBUYW1hw7FvIDQwMA0KDQpgYGB7cn0NCmN0dTE5XzQwMCA8LSBjdHUxOSAlPiUgZmlsdGVyKG5jaGFyKFN0YXRlKSA+IDM5OSkNCmN0dTE5XzQwMCRTdGF0ZSA8LSBjdHUxOV80MDAkU3RhdGUgJT4lIHN1YnN0cigxLDQwMCkNCmBgYA0KDQoNCiMjIyBUYW1hw7FvIDgwMA0KDQpgYGB7cn0NCmN0dTE5XzgwMCA8LSBjdHUxOSAlPiUgZmlsdGVyKG5jaGFyKFN0YXRlKSA+IDc5OSkNCmN0dTE5XzgwMCRTdGF0ZSA8LSBjdHUxOV84MDAkU3RhdGUgJT4lIHN1YnN0cigxLDgwMCkNCmBgYA0KDQoNCiMjIyBUYW1hw7FvIDEwMDANCg0KYGBge3J9DQpjdHUxOV8xMDAwIDwtIGN0dTE5ICU+JSBmaWx0ZXIobmNoYXIoU3RhdGUpID4gOTk5KQ0KY3R1MTlfMTAwMCRTdGF0ZSA8LSBjdHUxOV8xMDAwJFN0YXRlICU+JSBzdWJzdHIoMSwxMDAwKQ0KYGBgDQoNCiMjIFZlY3RvciBkZSBEYXRhU2V0cw0KDQpgYGB7cn0NCmRhdGFTZXRzIDwtIGxpc3QoY3R1MTlfMTAsY3R1MTlfMjAsY3R1MTlfNDAsY3R1MTlfODAsY3R1MTlfMTAwLGN0dTE5XzIwMCxjdHUxOV80MDAsY3R1MTlfODAwLGN0dTE5XzEwMDApDQpgYGANCg0KDQojIyBGZWF0dXJlIFZlY3Rvcg0KDQpgYGB7cn0NCmRhdGFTZXRzIDwtIGxhcHBseShkYXRhU2V0cywgZnVuY3Rpb24oeCkgeCA8LSBmZWF0dXJlX3ZlY3Rvcihhcy5kYXRhLmZyYW1lKHgpKSkNCmBgYA0KDQoNCiMjIExpbXBpZXphDQoNCkRlamFtb3Mgc29sbyBsYXMgY29sdW1uYXMgcXVlIG5vcyBpbnRlcmVzYW4NCg0KYGBge3J9DQpsaW1waWV6YSA8LSBmdW5jdGlvbih4KXsNCiAgeCA8LSB4ICU+JSBzZWxlY3QoLUluaXRpYWxJcCwtRW5kSVAsLVByb3RvLC1TdGF0ZSwtUG9ydCkNCiAgeCRMYWJlbE5hbWUgPC0gYXMuZmFjdG9yKHgkTGFiZWxOYW1lKQ0KICByZXR1cm4oeCkNCn0NCmBgYA0KDQpgYGB7cn0NCmRhdGFTZXRzIDwtIGxhcHBseShkYXRhU2V0cywgZnVuY3Rpb24oeCkgeCA8LSBsaW1waWV6YSh4KSkNCmBgYA0KDQpgYGB7cn0NCmxhcHBseShkYXRhU2V0cywgZnVuY3Rpb24oeCkgYXMuZGF0YS5mcmFtZSh4KSAlPiUgaGVhZCg1MCkpDQpgYGANCg0KDQojIyBSYW5kb20gRm9yZXN0DQoNCiMjIyBDVFUxOSBwdXJvDQoNCmBgYHtyfQ0KY3R1MTlfcHVyb19EUyA8LSBsYXBwbHkoZGF0YVNldHMsIGZ1bmN0aW9uKHgpIHsNCiAgY3R1MTlQdXJvX0RTIDwtIGMoKQ0KICBmb3JlYWNoKGkgPSAxOjEwKSAlZG8lIHtjdHUxOVB1cm9fRFMgPC0gY3R1MTlQdXJvX0RTICU+JSBjYmluZCh0ZXN0X21vZGVsKGFzLmRhdGEuZnJhbWUoeCkpKX0NCiAgcmV0dXJuKGN0dTE5UHVyb19EUykNCn0pDQpgYGANCg0KYGBge3J9DQpwcm9tZWRpb19QdXJvX0RTIDwtIGxhcHBseShjdHUxOV9wdXJvX0RTLCBmdW5jdGlvbih4KXsNCiAgcmVzcCA8LSBjKCkNCiAgcmVzcCA8LSByb3dNZWFucyh4KQ0KICByZXR1cm4ocmVzcCkNCn0pDQpgYGANCg0KYGBge3J9DQpsYXBwbHkocHJvbWVkaW9fUHVyb19EUywgZnVuY3Rpb24oeCkgeCAlPiUgYXMuZGF0YS5mcmFtZSgpKQ0KYGBgDQoNCg0KIyMjIENUVTE5IERvd24NCmBgYHtyfQ0KY3R1MTlfRG93bl9EUyA8LSBsYXBwbHkoZGF0YVNldHMsIGZ1bmN0aW9uKHgpIHsNCiAgcmVzcCA8LSBjKCkNCiAgZm9yZWFjaChpID0gMToxMCkgJWRvJSB7cmVzcCA8LSByZXNwICU+JSBjYmluZCh0ZXN0X21vZGVsX2Rvd24oYXMuZGF0YS5mcmFtZSh4KSkpfQ0KICByZXR1cm4ocmVzcCkNCn0pDQpgYGANCg0KYGBge3J9DQpwcm9tZWRpb19Eb3duX0RTIDwtIGxhcHBseShjdHUxOV9Eb3duX0RTLCBmdW5jdGlvbih4KXsNCiAgcmVzcCA8LSBjKCkNCiAgcmVzcCA8LSByb3dNZWFucyh4KQ0KICByZXR1cm4ocmVzcCkNCn0pDQpgYGANCg0KYGBge3J9DQpsYXBwbHkocHJvbWVkaW9fRG93bl9EUywgZnVuY3Rpb24oeCkgeCAlPiUgYXMuZGF0YS5mcmFtZSgpKQ0KYGBgDQoNCg0KIyMjIENUVTE5IFVwDQoNCmBgYHtyfQ0KY3R1MTlfVXBfRFMgPC0gbGFwcGx5KGRhdGFTZXRzLCBmdW5jdGlvbih4KSB7DQogIHJlc3AgPC0gYygpDQogIGZvcmVhY2goaSA9IDE6MTApICVkbyUge3Jlc3AgPC0gcmVzcCAlPiUgY2JpbmQodGVzdF9tb2RlbF91cChhcy5kYXRhLmZyYW1lKHgpKSl9DQogIHJldHVybihyZXNwKQ0KfSkNCmBgYA0KDQpgYGB7cn0NCnByb21lZGlvX1VwX0RTIDwtIGxhcHBseShjdHUxOV9VcF9EUywgZnVuY3Rpb24oeCl7DQogIHJlc3AgPC0gYygpDQogIHJlc3AgPC0gcm93TWVhbnMoeCkNCiAgcmV0dXJuKHJlc3ApDQp9KQ0KYGBgDQoNCmBgYHtyfQ0KbGFwcGx5KHByb21lZGlvX1VwX0RTLCBmdW5jdGlvbih4KSB4ICU+JSBhcy5kYXRhLmZyYW1lKCkpDQpgYGANCg0K