library(lubridate)
library(tidyverse)
library(pROC)
library(plotROC)
library(caret)
library(doMC)
registerDoMC(cores=8)

Dataset generation

The same datasets used in Paula’s thesis

data %>% group_by(eng_season) %>% summarise(total=n())

FNL lags

Creating FNL lags for 6, 12, 18 and 24 hs before the target_day

lags<- data %>% select(-eng_season, -target_timestamp, -target_year, -target_day, -target_hour,-eng_cyclic_day, -eng_nino_year, -eng_nino_month, -eng_zonda,-target_month, -precip_3hr_sum) %>% imap_dfc(~set_names(map(1:4, lag, x = .x), 
                        paste(.y, 'lag', c("6","12","18","24"), sep = '_')))
trainset<-lags %>% bind_cols(data %>% select(eng_season, target_timestamp, target_year, target_day, eng_cyclic_day, eng_nino_year, eng_nino_month, eng_zonda,target_month), .) %>% slice(7:nrow(data)) 
# considering only timestamp at 00 hour
trainset<-trainset[seq(1,nrow(trainset),4),]
# Removing the hours from timestamp
trainset<-trainset %>% mutate(target_timestamp=as.integer(target_timestamp/100))
head(trainset)

The cmorph daily file contains the 4 closestgeo-points to Mendoza Aerodrome station. Taken from From ./2.selected/cmorph_mza_daily/cmorph_paste_mza_dly

Merging with cmorph_daily

Merging Cmoprh daily with previous trainset

trainset_merged <- inner_join(trainset,cmorph_daily %>% mutate(target_timestamp=as.integer(target_timestamp/100)),by="target_timestamp")

Comparison with wmo

Georefence of the 4 CMORPH selected point and the MZA Aerodrome meteo station.

The two closest point to MWO are cmorph1 and cmorph3

A comparison between MWO precipitation days and cmorph3

Creating precip class with threshold=0.0

The point corresponding to CMORPH3 5_6 was chosen as the target precipitation volume

threshold=0.0
trainset_labeled <- trainset_merged %>% 
  mutate(precip_reg=cmorph3,precip=ifelse(precip_reg>threshold,'yes','no'),eng_season_num=ifelse(eng_season=="summer",1,0)) %>%
  select(-cmorph1, -cmorph2, -cmorph3, -cmorph4, -eng_season)

Day of rainfall distribution

trainset_labeled %>% group_by(eng_season_num,precip) %>% summarise(total=n()) %>% ggplot()+
  geom_col(aes(x=as.factor(eng_season_num),y=total,fill=precip))+
  theme_bw()

Removing lags and some features

trainset_labeled<-trainset_labeled %>% 
  select( -contains("lag_24") ) %>% 
  #select( -contains("lag_18") ) %>%
  #select( -contains("lag_12") ) %>%
  select(-target_year, -target_timestamp ,-eng_zonda) 
#%>% 
  #filter(eng_season_num==1) %>% 
  #select(-eng_season_num)

names(trainset_labeled)

Removing Highly correlated features

trainset_cor<-cor(trainset_labeled %>% select(-precip,-precip_reg))
trainsetid<-findCorrelation(trainset_cor, cutoff = .9)
trainset_labeled_selected<-trainset_labeled[,-trainsetid]#,precip=trainset_labeled$precip)
length(names(trainset_labeled_selected))

Listing the final set of features

names(trainset_labeled_selected)
  [1] "target_day"                          "eng_nino_year"                       "eng_nino_month"                     
  [4] "target_month"                        "fnl_absvorticity_500_1__1_t0_lag_6"  "fnl_absvorticity_500_1__1_t0_lag_12"
  [7] "fnl_absvorticity_500_1__1_t0_lag_18" "fnl_absvorticity_500_2__1_t0_lag_6"  "fnl_absvorticity_500_2__1_t0_lag_12"
 [10] "fnl_absvorticity_500_2__1_t0_lag_18" "fnl_absvorticity_500_3__1_t0_lag_6"  "fnl_absvorticity_500_3__1_t0_lag_12"
 [13] "fnl_absvorticity_500_3__1_t0_lag_18" "fnl_absvorticity_500_1__2_t0_lag_6"  "fnl_absvorticity_500_1__2_t0_lag_12"
 [16] "fnl_absvorticity_500_1__2_t0_lag_18" "fnl_absvorticity_500_2__2_t0_lag_6"  "fnl_absvorticity_500_2__2_t0_lag_12"
 [19] "fnl_absvorticity_500_2__2_t0_lag_18" "fnl_absvorticity_500_3__2_t0_lag_6"  "fnl_absvorticity_500_3__2_t0_lag_12"
 [22] "fnl_absvorticity_500_3__2_t0_lag_18" "fnl_absvorticity_500_1__3_t0_lag_6"  "fnl_absvorticity_500_1__3_t0_lag_12"
 [25] "fnl_absvorticity_500_1__3_t0_lag_18" "fnl_absvorticity_500_2__3_t0_lag_6"  "fnl_absvorticity_500_2__3_t0_lag_12"
 [28] "fnl_absvorticity_500_2__3_t0_lag_18" "fnl_absvorticity_500_3__3_t0_lag_6"  "fnl_absvorticity_500_3__3_t0_lag_12"
 [31] "fnl_absvorticity_500_3__3_t0_lag_18" "fnl_temperature_500_1__3_t0_lag_6"   "fnl_uwind_850_1__1_t0_lag_6"        
 [34] "fnl_uwind_850_2__1_t0_lag_6"         "fnl_uwind_850_2__1_t0_lag_12"        "fnl_uwind_850_3__1_t0_lag_6"        
 [37] "fnl_uwind_850_3__1_t0_lag_12"        "fnl_uwind_850_2__2_t0_lag_18"        "fnl_uwind_850_3__2_t0_lag_6"        
 [40] "fnl_uwind_850_3__2_t0_lag_12"        "fnl_uwind_850_3__2_t0_lag_18"        "fnl_uwind_850_1__3_t0_lag_6"        
 [43] "fnl_uwind_850_1__3_t0_lag_12"        "fnl_uwind_850_1__3_t0_lag_18"        "fnl_uwind_850_2__3_t0_lag_6"        
 [46] "fnl_uwind_850_2__3_t0_lag_12"        "fnl_uwind_850_2__3_t0_lag_18"        "fnl_uwind_850_3__3_t0_lag_6"        
 [49] "fnl_uwind_850_3__3_t0_lag_12"        "fnl_uwind_850_3__3_t0_lag_18"        "fnl_vwind_850_1__1_t0_lag_6"        
 [52] "fnl_vwind_850_1__1_t0_lag_12"        "fnl_vwind_850_1__1_t0_lag_18"        "fnl_vwind_850_2__1_t0_lag_6"        
 [55] "fnl_vwind_850_2__1_t0_lag_12"        "fnl_vwind_850_2__1_t0_lag_18"        "fnl_vwind_850_3__1_t0_lag_6"        
 [58] "fnl_vwind_850_3__1_t0_lag_12"        "fnl_vwind_850_1__2_t0_lag_6"         "fnl_vwind_850_1__2_t0_lag_12"       
 [61] "fnl_vwind_850_2__2_t0_lag_6"         "fnl_vwind_850_2__2_t0_lag_12"        "fnl_vwind_850_2__2_t0_lag_18"       
 [64] "fnl_vwind_850_3__2_t0_lag_6"         "fnl_vwind_850_3__2_t0_lag_12"        "fnl_vwind_850_3__2_t0_lag_18"       
 [67] "fnl_vwind_850_1__3_t0_lag_6"         "fnl_vwind_850_1__3_t0_lag_12"        "fnl_vwind_850_2__3_t0_lag_6"        
 [70] "fnl_vwind_850_2__3_t0_lag_12"        "fnl_vwind_850_2__3_t0_lag_18"        "fnl_vwind_850_3__3_t0_lag_6"        
 [73] "fnl_vwind_850_3__3_t0_lag_12"        "fnl_vwind_850_3__3_t0_lag_18"        "fnl_cape_1__1_t0_lag_6"             
 [76] "fnl_cape_1__1_t0_lag_12"             "fnl_cape_1__1_t0_lag_18"             "fnl_cape_2__1_t0_lag_6"             
 [79] "fnl_cape_2__1_t0_lag_12"             "fnl_cape_2__1_t0_lag_18"             "fnl_cape_3__1_t0_lag_6"             
 [82] "fnl_cape_3__1_t0_lag_12"             "fnl_cape_3__1_t0_lag_18"             "fnl_cape_1__2_t0_lag_6"             
 [85] "fnl_cape_1__2_t0_lag_12"             "fnl_cape_1__2_t0_lag_18"             "fnl_cape_2__2_t0_lag_6"             
 [88] "fnl_cape_2__2_t0_lag_12"             "fnl_cape_2__2_t0_lag_18"             "fnl_cape_3__2_t0_lag_6"             
 [91] "fnl_cape_3__2_t0_lag_12"             "fnl_cape_3__2_t0_lag_18"             "fnl_cape_1__3_t0_lag_6"             
 [94] "fnl_cape_1__3_t0_lag_12"             "fnl_cape_1__3_t0_lag_18"             "fnl_cape_2__3_t0_lag_6"             
 [97] "fnl_cape_2__3_t0_lag_12"             "fnl_cape_2__3_t0_lag_18"             "fnl_cape_3__3_t0_lag_6"             
[100] "fnl_cape_3__3_t0_lag_12"             "fnl_cape_3__3_t0_lag_18"             "fnl_sealevelpress_1__1_t0_lag_18"   
[103] "fnl_sealevelpress_3__1_t0_lag_18"    "fnl_sealevelpress_1__3_t0_lag_6"     "fnl_sealevelpress_3__3_t0_lag_6"    
[106] "fnl_relhum_850_1__1_t0_lag_18"       "fnl_relhum_850_2__1_t0_lag_6"        "fnl_cin_1__1_t0_lag_6"              
[109] "fnl_cin_1__1_t0_lag_12"              "fnl_cin_1__1_t0_lag_18"              "fnl_cin_2__1_t0_lag_6"              
[112] "fnl_cin_2__1_t0_lag_12"              "fnl_cin_2__1_t0_lag_18"              "fnl_cin_3__1_t0_lag_6"              
[115] "fnl_cin_3__1_t0_lag_12"              "fnl_cin_3__1_t0_lag_18"              "fnl_cin_1__2_t0_lag_6"              
[118] "fnl_cin_1__2_t0_lag_12"              "fnl_cin_1__2_t0_lag_18"              "fnl_cin_2__2_t0_lag_6"              
[121] "fnl_cin_2__2_t0_lag_12"              "fnl_cin_2__2_t0_lag_18"              "fnl_cin_3__2_t0_lag_6"              
[124] "fnl_cin_3__2_t0_lag_12"              "fnl_cin_3__2_t0_lag_18"              "fnl_cin_1__3_t0_lag_6"              
[127] "fnl_cin_1__3_t0_lag_12"              "fnl_cin_1__3_t0_lag_18"              "fnl_cin_2__3_t0_lag_6"              
[130] "fnl_cin_2__3_t0_lag_12"              "fnl_cin_2__3_t0_lag_18"              "fnl_cin_3__3_t0_lag_6"              
[133] "fnl_cin_3__3_t0_lag_12"              "fnl_cin_3__3_t0_lag_18"              "fnl_divergence_200_1__1_t0_lag_6"   
[136] "fnl_divergence_200_1__1_t0_lag_12"   "fnl_divergence_200_1__1_t0_lag_18"   "fnl_divergence_200_2__1_t0_lag_6"   
[139] "fnl_divergence_200_2__1_t0_lag_12"   "fnl_divergence_200_2__1_t0_lag_18"   "fnl_divergence_200_3__1_t0_lag_6"   
[142] "fnl_divergence_200_3__1_t0_lag_12"   "fnl_divergence_200_3__1_t0_lag_18"   "fnl_divergence_200_1__2_t0_lag_6"   
[145] "fnl_divergence_200_1__2_t0_lag_12"   "fnl_divergence_200_1__2_t0_lag_18"   "fnl_divergence_200_2__2_t0_lag_6"   
[148] "fnl_divergence_200_2__2_t0_lag_12"   "fnl_divergence_200_2__2_t0_lag_18"   "fnl_divergence_200_3__2_t0_lag_6"   
[151] "fnl_divergence_200_3__2_t0_lag_12"   "fnl_divergence_200_3__2_t0_lag_18"   "fnl_divergence_200_1__3_t0_lag_6"   
[154] "fnl_divergence_200_1__3_t0_lag_12"   "fnl_divergence_200_1__3_t0_lag_18"   "fnl_divergence_200_2__3_t0_lag_6"   
[157] "fnl_divergence_200_2__3_t0_lag_12"   "fnl_divergence_200_2__3_t0_lag_18"   "fnl_divergence_200_3__3_t0_lag_6"   
[160] "fnl_divergence_200_3__3_t0_lag_12"   "fnl_divergence_200_3__3_t0_lag_18"   "precip_reg"                         
[163] "precip"                              "eng_season_num"                     

Creating Train and Test sets

set.seed(12121)
trainset_labeled_selected$precip<-as.factor(trainset_labeled_selected$precip)
train_index <- createDataPartition(trainset_labeled_selected$precip , p=0.80, list=FALSE)
data_train <- trainset_labeled_selected[ train_index,]
data_test <-  trainset_labeled_selected[-train_index,]
data_train <- data_train %>% select(-precip_reg)

#data_reg <- data_reg %>% slice(1:nrow(data_reg)) # check here for lag
# add precipitation numerical value to test
#data_test$precip_reg <- trainset_merged[-train_index,]$cmorph1
train_formula<-formula(precip ~ .) 
names(data_train)
nrow(data_train)

Model evaluation

Model fine tuning on Training set

ctrl_fast <- trainControl(method="repeatedcv", 
                     repeats=1,
                     number=5, 
                     summaryFunction=twoClassSummary,
                     verboseIter=F,
                     #preProcOptions = list(pcaComp = 10),
                     classProbs=TRUE,
                     allowParallel = T)  

nnGrid <-  expand.grid(decay = c(0), size=c(10,20,50,100,200,300)) 
svmGrid <-  expand.grid(sigma = c(0.001,0.00001), C=c(0.1,0.001,0.5)) 

kerasGrid <- expand.grid(
  size=c(20,50,2000,5000),
  lambda=c(0),
  batch_size=c(1024),
  decay=c(0),
  activation=c('tanh','sigmoid','relu'),
  lr=c(0.001), rho=c(0.9)
)

ctrl_fast$sampling<-"smote"
rfFit <- caret::train(train_formula,
               data = data_train,
               #metric="ROC",
               #preProcess=c("pca"),
               
               #method = "mlpWeightDecay",
               #method = "svmRadial",
               #method ="mlpKerasDecay",
               method = "rf",
               #tuneGrid=kerasGrid,
               tuneLength=11,
               verbose=0,
               #epochs=100,
               trControl = ctrl_fast)

Resulting models

rfFit
Random Forest 

2171 samples
 162 predictors
   2 classes: 'no', 'yes' 

No pre-processing
Resampling: Cross-Validated (5 fold, repeated 1 times) 
Summary of sample sizes: 1737, 1736, 1737, 1737, 1737 
Addtional sampling using SMOTE

Resampling results across tuning parameters:

  mtry  ROC        Sens       Spec     
    2   0.7373925  0.8069821  0.4784894
   18   0.7341498  0.8230763  0.4131433
   34   0.7272402  0.8225162  0.4238430
   50   0.7319841  0.8302847  0.3967049
   66   0.7351522  0.8352816  0.4156238
   82   0.7313635  0.8203001  0.4345428
   98   0.7215759  0.8114204  0.4129582
  114   0.7249941  0.8308464  0.4264347
  130   0.7242694  0.8253001  0.4102184
  146   0.7191343  0.8158757  0.4263976
  162   0.7250953  0.8247276  0.4184006

ROC was used to select the optimal model using the largest value.
The final value used for the model was mtry = 2.
ggplot(rfFit)+theme_bw()

Most relevant features for RF

THe list of the most relevant features used by the RandomForest Classifier

varImp(rfFit, scale = F)
rf variable importance

  only 20 most important variables shown (out of 162)

                                  Overall
fnl_sealevelpress_1__3_t0_lag_6    12.885
fnl_sealevelpress_3__1_t0_lag_18   11.787
fnl_sealevelpress_1__1_t0_lag_18   11.400
fnl_sealevelpress_3__3_t0_lag_6    11.377
fnl_temperature_500_1__3_t0_lag_6  11.305
fnl_vwind_850_1__2_t0_lag_12       11.081
fnl_cape_3__3_t0_lag_12            10.328
fnl_vwind_850_1__3_t0_lag_6        10.325
fnl_cape_3__2_t0_lag_12            10.241
fnl_cin_3__1_t0_lag_18             10.179
fnl_cape_3__3_t0_lag_18            10.136
fnl_vwind_850_1__3_t0_lag_12       10.133
fnl_cape_3__2_t0_lag_18            10.101
fnl_uwind_850_3__1_t0_lag_12        9.882
fnl_vwind_850_1__2_t0_lag_6         9.813
fnl_vwind_850_1__1_t0_lag_18        9.708
fnl_uwind_850_3__3_t0_lag_12        9.672
fnl_cin_3__2_t0_lag_12              9.621
fnl_cin_2__3_t0_lag_12              9.557
fnl_uwind_850_2__1_t0_lag_12        9.506

Evaluation on test set

Confusion Matrix

cm
Confusion Matrix and Statistics

          Reference
Prediction  no yes
       no  290  22
       yes 160  69
                                         
               Accuracy : 0.6636         
                 95% CI : (0.622, 0.7033)
    No Information Rate : 0.8318         
    P-Value [Acc > NIR] : 1              
                                         
                  Kappa : 0.2509         
 Mcnemar's Test P-Value : <2e-16         
                                         
            Sensitivity : 0.7582         
            Specificity : 0.6444         
         Pos Pred Value : 0.3013         
         Neg Pred Value : 0.9295         
             Prevalence : 0.1682         
         Detection Rate : 0.1275         
   Detection Prevalence : 0.4233         
      Balanced Accuracy : 0.7013         
                                         
       'Positive' Class : yes            
                                         

ROC Curve

#plot(roc(data_test$profile,predsrprofilerobsamp$Malicious))
ggplot(cbind(predsrprofilerobsamp,class=data_test$precip), 
       aes(m = yes, d = factor(class, labels=c("no","yes"),levels = c("no", "yes")))) + 
    geom_roc(hjust = -0.4, vjust = 1.5,colour='orange') + 
    geom_abline(intercept = 0, slope = 1,colour='red')+
  theme_bw()

LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQpgYGB7cn0KbGlicmFyeShsdWJyaWRhdGUpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHBST0MpCmxpYnJhcnkocGxvdFJPQykKbGlicmFyeShjYXJldCkKbGlicmFyeShkb01DKQpyZWdpc3RlckRvTUMoY29yZXM9OCkKYGBgCgpgYGB7ciBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQpzdGF0aW9uX3ZzX2Ntb3JwaF9temE9cmVhZC5jc3YoCiAgZmlsZT0iZGF0YS9zdGF0aW9uLXZzLWNtb3JwaC1temEtZGFpbHkuY3N2IixzZXA9JywnLGhlYWRlcj1GKQpzdGF0aW9uX3ZzX2Ntb3JwaF9temE9Y2JpbmQocmVwKCJtemEiKSxzdGF0aW9uX3ZzX2Ntb3JwaF9temEpCm5hbWVzKHN0YXRpb25fdnNfY21vcnBoX216YSk8LWMoImNpdHkiLCJ0cyIsInN0YXRpb24iLCJjbW9ycGgiKQoKbW9udGg9bW9udGgoYXMuRGF0ZShhcy5jaGFyYWN0ZXIoc3RhdGlvbl92c19jbW9ycGhfbXphJHRzKSwiJVklbSVkIikpCnllYXI9eWVhcihhcy5EYXRlKGFzLmNoYXJhY3RlcihzdGF0aW9uX3ZzX2Ntb3JwaF9temEkdHMpLCIlWSVtJWQiKSkKZGF5PWRheShhcy5EYXRlKGFzLmNoYXJhY3RlcihzdGF0aW9uX3ZzX2Ntb3JwaF9temEkdHMpLCIlWSVtJWQiKSkKc3RhdGlvbl92c19jbW9ycGg9Y2JpbmQoc3RhdGlvbl92c19jbW9ycGhfbXphLHllYXIsbW9udGgsZGF5KQoKCmBgYApgYGB7ciBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQp3bW9fZGF0YTwtc3RhdGlvbl92c19jbW9ycGggJT4lIGdyb3VwX2J5KHllYXIpICU+JSBzdW1tYXJpc2UodG90YWw9bigpLHN0YXRpb249c3VtKGlmZWxzZShzdGF0aW9uPjAsMSwwKSksY21vcnBoPXN1bShpZmVsc2UoY21vcnBoPjAsMSwwKSkpCndtb19kYXRhX21lbHRlZDwtbWVsdCh3bW9fZGF0YSxpZD1jKCJ5ZWFyIikpCndtb19kYXRhX3Bsb3Q8LWdncGxvdCh3bW9fZGF0YSkrCiAjIGdlb21fY29sKGFlcyh4PWFzLmZhY3Rvcih5ZWFyKSx5PXZhbHVlLGZpbGw9dmFyaWFibGUpLHBvc2l0aW9uPSdkb2RnZScpKwogIGdlb21fY29sKGFlcyh4PWFzLmZhY3Rvcih5ZWFyKSx5PXRvdGFsLGZpbGw9J3JlZCcpKSsKICBnZW9tX2NvbChhZXMoeD1hcy5mYWN0b3IoeWVhcikseT1jbW9ycGgsZmlsbD0nZ3JlZW4nKSkrCiAgZ2VvbV9jb2woYWVzKHg9YXMuZmFjdG9yKHllYXIpLHk9c3RhdGlvbixmaWxsPSdibHVlJykpKwogIHNjYWxlX2ZpbGxfbWFudWFsKCJEYXlzIHdpdGggbWVhc3VyZXMiLHZhbHVlcyA9YygncmVkJz0ncGluaycsJ2JsdWUnPSdza3libHVlJywnZ3JlZW4nPSdsaWdodGdyZWVuJyksIGxhYmVscyA9IGMoJ3N0YXRpb24nLCdjbW9ycGgnLCd0b3RhbCcpKSsKICB5bGFiKCJkYXlzIikreGxhYigieWVhciIpKwogIHRoZW1lX2J3KCkrCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkrCiAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0iYm90dG9tIikKd21vX2RhdGFfcGxvdAp3bW9fZGF0YQpnZ3NhdmUod21vX2RhdGFfcGxvdCxmaWxlbmFtZSA9ICJwcmVjaXBpdGF0aW9uLWRheXMucGRmIiwgd2lkdGggPSA4LGhlaWdodCA9IDQsZGV2aWNlID0gInBkZiIpCmBgYAoKYGBge3IgZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0Kd21vX2RhdGFfZml4ZWQ8LXN0YXRpb25fdnNfY21vcnBoICU+JSBncm91cF9ieSh5ZWFyKSAlPiUgc3VtbWFyaXNlKHRvdGFsPW4oKSxzdGF0aW9uPXN1bShpZmVsc2Uoc3RhdGlvbj4wLDEsMCkpLGNtb3JwaD1zdW0oaWZlbHNlKGNtb3JwaD4wLjEsMSwwKSkpCndtb19kYXRhX2ZpeGVkX21lbHRlZDwtbWVsdCh3bW9fZGF0YV9maXhlZCxpZD1jKCJ5ZWFyIikpCndtb19kYXRhX2ZpeGVkX3Bsb3Q8LWdncGxvdCh3bW9fZGF0YV9maXhlZCkrCiAjIGdlb21fY29sKGFlcyh4PWFzLmZhY3Rvcih5ZWFyKSx5PXZhbHVlLGZpbGw9dmFyaWFibGUpLHBvc2l0aW9uPSdkb2RnZScpKwogICNnZW9tX2NvbChhZXMoeD1hcy5mYWN0b3IoeWVhcikseT10b3RhbCxmaWxsPSdyZWQnKSkrCiAgCmdlb21fY29sKGFlcyh4PWFzLmZhY3Rvcih5ZWFyKSx5PWNtb3JwaCxmaWxsPSdncmVlbicpLGFscGhhPTAuNykrCiAgZ2VvbV9jb2woYWVzKHg9YXMuZmFjdG9yKHllYXIpLHk9c3RhdGlvbixmaWxsPSdibHVlJyksYWxwaGE9MSkrCiAgICBzY2FsZV9maWxsX21hbnVhbCgiIix2YWx1ZXMgPWMoJ3JlZCc9J3BpbmsnLCdibHVlJz0nc2t5Ymx1ZScsJ2dyZWVuJz0nbGlnaHRncmVlbicpLCBsYWJlbHMgPSBjKCdzdGF0aW9uJywnY21vcnBoJywndG90YWwnKSkrCiAgeWxhYigiZGF5cyIpK3hsYWIoInllYXIiKSsKICB0aGVtZV9idygpKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpKwogICB0aGVtZShsZWdlbmQucG9zaXRpb249ImJvdHRvbSIpCndtb19kYXRhX2ZpeGVkX3Bsb3QKZ2dzYXZlKHdtb19kYXRhX2ZpeGVkX3Bsb3QsZmlsZW5hbWUgPSAicHJlY2lwaXRhdGlvbi1jbW9ycGgtc3RhdGlvbi1maXhlZC0wMS5wZGYiLCB3aWR0aCA9IDgsaGVpZ2h0ID0gNCxkZXZpY2UgPSAicGRmIikKYGBgCgojIERhdGFzZXQgZ2VuZXJhdGlvbgojIyBUaGUgc2FtZSBkYXRhc2V0cyB1c2VkIGluIFBhdWxhJ3MgdGhlc2lzCmBgYHtyfQpyZWdpc3RlckRvTUMoY29yZXM9OCkKbXphX3dpbnRlcjwtcmVhZF9jc3YoIi9ob21lL2hhcnBvL0Ryb3Bib3gvb25nb2luZy13b3JrL2dpdC1yZXBvcy9tZXRlby1tbC9kYXRhL2pvdXJuYWwtcGF1bGEvNS5jbHMtbXphLXdpbnRlci1zMS1wNi5jc3YiKQptemFfd2ludGVyX3JlZzwtcmVhZF9jc3YoIi9ob21lL2hhcnBvL0Ryb3Bib3gvb25nb2luZy13b3JrL2dpdC1yZXBvcy9tZXRlby1tbC9kYXRhL2pvdXJuYWwtcGF1bGEvNS5yZWctbXphLXdpbnRlci1zMS1wNi5jc3YiKQptemFfc3VtbWVyPC1yZWFkX2NzdigiL2hvbWUvaGFycG8vRHJvcGJveC9vbmdvaW5nLXdvcmsvZ2l0LXJlcG9zL21ldGVvLW1sL2RhdGEvam91cm5hbC1wYXVsYS81LmNscy1temEtc3VtbWVyLXMxLXA2LmNzdiIpCm16YV9zdW1tZXJfcmVnPC1yZWFkX2NzdigiL2hvbWUvaGFycG8vRHJvcGJveC9vbmdvaW5nLXdvcmsvZ2l0LXJlcG9zL21ldGVvLW1sL2RhdGEvam91cm5hbC1wYXVsYS81LnJlZy1temEtc3VtbWVyLXMxLXA2LmNzdiIpCmRhdGE8LXJiaW5kKG16YV9zdW1tZXJfcmVnLG16YV93aW50ZXJfcmVnKQpucm93KGRhdGEpCmhlYWQoZGF0YSkKYGBgCmBgYHtyfQpkYXRhICU+JSBncm91cF9ieShlbmdfc2Vhc29uKSAlPiUgc3VtbWFyaXNlKHRvdGFsPW4oKSkKYGBgCgoKIyMgRk5MIGxhZ3MgCkNyZWF0aW5nIEZOTCBsYWdzIGZvciA2LCAxMiwgMTggYW5kIDI0IGhzIGJlZm9yZSB0aGUgKip0YXJnZXRfZGF5KioKYGBge3IgZGF0YXNldCBnZW5lcmF0aW9ufQoKbGFnczwtIGRhdGEgJT4lIHNlbGVjdCgtZW5nX3NlYXNvbiwgLXRhcmdldF90aW1lc3RhbXAsIC10YXJnZXRfeWVhciwgLXRhcmdldF9kYXksIC10YXJnZXRfaG91ciwtZW5nX2N5Y2xpY19kYXksIC1lbmdfbmlub195ZWFyLCAtZW5nX25pbm9fbW9udGgsIC1lbmdfem9uZGEsLXRhcmdldF9tb250aCwgLXByZWNpcF8zaHJfc3VtKSAlPiUgaW1hcF9kZmMofnNldF9uYW1lcyhtYXAoMTo0LCBsYWcsIHggPSAueCksIAogICAgICAgICAgICAgICAgICAgICAgICBwYXN0ZSgueSwgJ2xhZycsIGMoIjYiLCIxMiIsIjE4IiwiMjQiKSwgc2VwID0gJ18nKSkpCgp0cmFpbnNldDwtbGFncyAlPiUgYmluZF9jb2xzKGRhdGEgJT4lIHNlbGVjdChlbmdfc2Vhc29uLCB0YXJnZXRfdGltZXN0YW1wLCB0YXJnZXRfeWVhciwgdGFyZ2V0X2RheSwgZW5nX2N5Y2xpY19kYXksIGVuZ19uaW5vX3llYXIsIGVuZ19uaW5vX21vbnRoLCBlbmdfem9uZGEsdGFyZ2V0X21vbnRoKSwgLikgJT4lIHNsaWNlKDc6bnJvdyhkYXRhKSkgCgojIGNvbnNpZGVyaW5nIG9ubHkgdGltZXN0YW1wIGF0IDAwIGhvdXIKdHJhaW5zZXQ8LXRyYWluc2V0W3NlcSgxLG5yb3codHJhaW5zZXQpLDQpLF0KCiMgUmVtb3ZpbmcgdGhlIGhvdXJzIGZyb20gdGltZXN0YW1wCnRyYWluc2V0PC10cmFpbnNldCAlPiUgbXV0YXRlKHRhcmdldF90aW1lc3RhbXA9YXMuaW50ZWdlcih0YXJnZXRfdGltZXN0YW1wLzEwMCkpCmhlYWQodHJhaW5zZXQpCmBgYAoKVGhlIGNtb3JwaCBkYWlseSBmaWxlIGNvbnRhaW5zIHRoZSA0IGNsb3Nlc3RnZW8tcG9pbnRzIHRvIE1lbmRvemEgQWVyb2Ryb21lIHN0YXRpb24uClRha2VuIGZyb20gRnJvbSBgYGAuLzIuc2VsZWN0ZWQvY21vcnBoX216YV9kYWlseS9jbW9ycGhfcGFzdGVfbXphX2RseWBgYAoKYGBge3J9CgpjbW9ycGhfZGFpbHk8LXJlYWRfZGVsaW0oImRhdGEvY21vcnBoX216YV9kbHkiLGRlbGltID0iICIpCm5hbWVzKGNtb3JwaF9kYWlseSk8LWMoInRhcmdldF90aW1lc3RhbXAiLCJjbW9ycGgxIiwiY21vcnBoMiIsImNtb3JwaDMiLCJjbW9ycGg0IikKaGVhZChjbW9ycGhfZGFpbHkpCmBgYAoKIyMgIE1lcmdpbmcgd2l0aCBjbW9ycGhfZGFpbHkKTWVyZ2luZyBDbW9wcmggZGFpbHkgd2l0aCAgcHJldmlvdXMgdHJhaW5zZXQgCgpgYGB7cn0KCnRyYWluc2V0X21lcmdlZCA8LSBpbm5lcl9qb2luKHRyYWluc2V0LGNtb3JwaF9kYWlseSAlPiUgbXV0YXRlKHRhcmdldF90aW1lc3RhbXA9YXMuaW50ZWdlcih0YXJnZXRfdGltZXN0YW1wLzEwMCkpLGJ5PSJ0YXJnZXRfdGltZXN0YW1wIikKCmBgYAoKIyMgQ29tcGFyaXNvbiB3aXRoIHdtbwoKIyMjIEdlb3JlZmVuY2Ugb2YgdGhlIDQgQ01PUlBIIHNlbGVjdGVkIHBvaW50IGFuZCB0aGUgTVpBIEFlcm9kcm9tZSBtZXRlbyBzdGF0aW9uLiAKClRoZSB0d28gY2xvc2VzdCBwb2ludCB0byBNV08gYXJlICpjbW9ycGgxKiBhbmQgKmNtb3JwaDMqCmBgYHtyfQpsaWJyYXJ5KGdnbWFwKQpsaWJyYXJ5KHNwKQptemFfbWFwIDwtIGdldF9tYXAobG9jYXRpb24gPSAibWVuZG96YSIsIHpvb20gPSAxMCxtYXB0eXBlID0gInJvYWRtYXAiLGNvbG9yID0gImJ3IikKbXphX2Ntb3JwaF9nZW9fZGF0YT1yZWFkLmNzdigiL2hvbWUvaGFycG8vRHJvcGJveC9vbmdvaW5nLXdvcmsvbWV0ZW8vc2NyaXB0cy9SL2Ntb3JwaF9temFfZGF0YV9nZW8uY3N2IixoZWFkZXI9VCxzZXA9IiwiKQpzZWxlY3RlZF9temFfY21vcnBoX2dlb19kYXRhPC1temFfY21vcnBoX2dlb19kYXRhICU+JSAKICAgICAgICAgICAgICAgIGZpbHRlcihjdWFkcmFudGU9PSI1XzUiIHwgY3VhZHJhbnRlPT0iNV82IiB8IGN1YWRyYW50ZT09IjZfNiIgfCBjdWFkcmFudGU9PSI2XzUiICkKCnNlbGVjdGVkX216YV9jbW9ycGhfZ2VvX2RhdGE8LWNiaW5kKG5vbWJyZT1jKCJjbW9ycGgxIiwiY21vcnBoMiIsImNtb3JwaDMiLCJjbW9ycGg0Iiksc2VsZWN0ZWRfbXphX2Ntb3JwaF9nZW9fZGF0YSkKCmdnPC1nZ21hcChtemFfbWFwKSsgCiAgIGdlb21fcG9pbnQoYWVzKHg9bG9uIC0gMzYwICx5PWxhdCksZGF0YT1zZWxlY3RlZF9temFfY21vcnBoX2dlb19kYXRhLGNvbG9yPSdyZWQnKSsKICAgZ2VvbV90ZXh0KGFlcyh4PWxvbiAtIDM2MC4wMyAseT1sYXQrMC4wMixsYWJlbD1jdWFkcmFudGUpLHNpemU9MyxkYXRhPXNlbGVjdGVkX216YV9jbW9ycGhfZ2VvX2RhdGEsY29sb3I9J3JlZCcpKwogICBnZW9tX3RleHQoYWVzKHg9bG9uIC0gMzYwLjAzICx5PWxhdCswLjA0LGxhYmVsPW5vbWJyZSksc2l6ZT0zLGRhdGE9c2VsZWN0ZWRfbXphX2Ntb3JwaF9nZW9fZGF0YSxjb2xvcj0ncmVkJykrCiAgIGdlb21fcG9pbnQoeT0tMzIuODMzMSx4PS02OC43NzE1LHNpemU9Myxjb2xvcj0nYmx1ZScpCiAgCgpnZwoKYGBgCgojIyMgQSBjb21wYXJpc29uIGJldHdlZW4gTVdPIHByZWNpcGl0YXRpb24gZGF5cyBhbmQgY21vcnBoMwoKYGBge3IgZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KYSA8LXRyYWluc2V0X21lcmdlZCAlPiUgaW5uZXJfam9pbihzdGF0aW9uX3ZzX2Ntb3JwaF9temEsIGJ5PWMoInRhcmdldF90aW1lc3RhbXAiID0gInRzIikpICAlPiUgCiAgbXV0YXRlKGNtb3JwaD1pZmVsc2UoY21vcnBoMz4wLCd5ZXMnLCdubycpLHN0YXRpb249aWZlbHNlKHN0YXRpb24+MSwneWVzJywnbm8nKSkKCgoKYSAlPiUgZ3JvdXBfYnkodGFyZ2V0X3llYXIpICU+JSBzdW1tYXJpc2UoY21vcnBoPXN1bShjbW9ycGg9PSd5ZXMnKSxzdGF0aW9uPXN1bShzdGF0aW9uPT0neWVzJyksdG90YWw9bigpKSAlPiUKICBnZ3Bsb3QoYWVzKGFscGhhPTAuNSkpICsKICBnZW9tX2NvbChhZXMoeD1hcy5mYWN0b3IodGFyZ2V0X3llYXIpLHk9dG90YWwpLGZpbGw9J3JlZCcpKwogIGdlb21fY29sKGFlcyh4PWFzLmZhY3Rvcih0YXJnZXRfeWVhcikseT1jbW9ycGgpLGZpbGw9J2JsdWUnKSsKICBnZW9tX2NvbChhZXMoeD1hcy5mYWN0b3IodGFyZ2V0X3llYXIpLHk9c3RhdGlvbiksZmlsbD0nZ3JlZW4nKSsKICB0aGVtZV9idygpCgojY29uZnVzaW9uTWF0cml4KGFzLmZhY3RvcihhJGNtb3JwaDEpLGFzLmZhY3RvcihhJHN0YXRpb24pKQpgYGAKCiMjIENyZWF0aW5nIHByZWNpcCBjbGFzcyB3aXRoIGBgYHRocmVzaG9sZD0wLjBgYGAKClRoZSAgcG9pbnQgY29ycmVzcG9uZGluZyB0byBDTU9SUEgzIDVfNiB3YXMgY2hvc2VuIGFzIHRoZSB0YXJnZXQgcHJlY2lwaXRhdGlvbiB2b2x1bWUKCmBgYHtyfQp0aHJlc2hvbGQ9MC4wCnRyYWluc2V0X2xhYmVsZWQgPC0gdHJhaW5zZXRfbWVyZ2VkICU+JSAKICBtdXRhdGUocHJlY2lwX3JlZz1jbW9ycGgzLHByZWNpcD1pZmVsc2UocHJlY2lwX3JlZz50aHJlc2hvbGQsJ3llcycsJ25vJyksZW5nX3NlYXNvbl9udW09aWZlbHNlKGVuZ19zZWFzb249PSJzdW1tZXIiLDEsMCkpICU+JQogIHNlbGVjdCgtY21vcnBoMSwgLWNtb3JwaDIsIC1jbW9ycGgzLCAtY21vcnBoNCwgLWVuZ19zZWFzb24pCmBgYAoKIyMjIERheSBvZiByYWluZmFsbCBkaXN0cmlidXRpb24KYGBge3J9CnRyYWluc2V0X2xhYmVsZWQgJT4lIGdyb3VwX2J5KGVuZ19zZWFzb25fbnVtLHByZWNpcCkgJT4lIHN1bW1hcmlzZSh0b3RhbD1uKCkpICU+JSBnZ3Bsb3QoKSsKICBnZW9tX2NvbChhZXMoeD1hcy5mYWN0b3IoZW5nX3NlYXNvbl9udW0pLHk9dG90YWwsZmlsbD1wcmVjaXApKSsKICB0aGVtZV9idygpCmBgYAoKIyMgUmVtb3ZpbmcgbGFncyBhbmQgc29tZSBmZWF0dXJlcwpgYGB7cn0KdHJhaW5zZXRfbGFiZWxlZDwtdHJhaW5zZXRfbGFiZWxlZCAlPiUgCiAgc2VsZWN0KCAtY29udGFpbnMoImxhZ18yNCIpICkgJT4lIAogICNzZWxlY3QoIC1jb250YWlucygibGFnXzE4IikgKSAlPiUKICAjc2VsZWN0KCAtY29udGFpbnMoImxhZ18xMiIpICkgJT4lCiAgc2VsZWN0KC10YXJnZXRfeWVhciwgLXRhcmdldF90aW1lc3RhbXAgLC1lbmdfem9uZGEpIAojJT4lIAogICNmaWx0ZXIoZW5nX3NlYXNvbl9udW09PTEpICU+JSAKICAjc2VsZWN0KC1lbmdfc2Vhc29uX251bSkKCm5hbWVzKHRyYWluc2V0X2xhYmVsZWQpCmBgYAoKIyMgUmVtb3ZpbmcgSGlnaGx5IGNvcnJlbGF0ZWQgZmVhdHVyZXMKYGBge3IgcmVtb3ZlIGNvcnJlbGF0ZWR9CnRyYWluc2V0X2NvcjwtY29yKHRyYWluc2V0X2xhYmVsZWQgJT4lIHNlbGVjdCgtcHJlY2lwLC1wcmVjaXBfcmVnKSkKdHJhaW5zZXRpZDwtZmluZENvcnJlbGF0aW9uKHRyYWluc2V0X2NvciwgY3V0b2ZmID0gLjkpCnRyYWluc2V0X2xhYmVsZWRfc2VsZWN0ZWQ8LXRyYWluc2V0X2xhYmVsZWRbLC10cmFpbnNldGlkXSMscHJlY2lwPXRyYWluc2V0X2xhYmVsZWQkcHJlY2lwKQpsZW5ndGgobmFtZXModHJhaW5zZXRfbGFiZWxlZF9zZWxlY3RlZCkpCmBgYAoKIyMgTGlzdGluZyB0aGUgZmluYWwgc2V0IG9mIGZlYXR1cmVzCmBgYHtyfQpuYW1lcyh0cmFpbnNldF9sYWJlbGVkX3NlbGVjdGVkKQpgYGAKIyBDcmVhdGluZyBUcmFpbiBhbmQgVGVzdCBzZXRzCgpgYGB7ciB0cmFpbmluZyBhbmQgdGVzdGluZ30Kc2V0LnNlZWQoMTIxMjEpCnRyYWluc2V0X2xhYmVsZWRfc2VsZWN0ZWQkcHJlY2lwPC1hcy5mYWN0b3IodHJhaW5zZXRfbGFiZWxlZF9zZWxlY3RlZCRwcmVjaXApCnRyYWluX2luZGV4IDwtIGNyZWF0ZURhdGFQYXJ0aXRpb24odHJhaW5zZXRfbGFiZWxlZF9zZWxlY3RlZCRwcmVjaXAgLCBwPTAuODAsIGxpc3Q9RkFMU0UpCmRhdGFfdHJhaW4gPC0gdHJhaW5zZXRfbGFiZWxlZF9zZWxlY3RlZFsgdHJhaW5faW5kZXgsXQpkYXRhX3Rlc3QgPC0gIHRyYWluc2V0X2xhYmVsZWRfc2VsZWN0ZWRbLXRyYWluX2luZGV4LF0KZGF0YV90cmFpbiA8LSBkYXRhX3RyYWluICU+JSBzZWxlY3QoLXByZWNpcF9yZWcpCgojZGF0YV9yZWcgPC0gZGF0YV9yZWcgJT4lIHNsaWNlKDE6bnJvdyhkYXRhX3JlZykpICMgY2hlY2sgaGVyZSBmb3IgbGFnCiMgYWRkIHByZWNpcGl0YXRpb24gbnVtZXJpY2FsIHZhbHVlIHRvIHRlc3QKI2RhdGFfdGVzdCRwcmVjaXBfcmVnIDwtIHRyYWluc2V0X21lcmdlZFstdHJhaW5faW5kZXgsXSRjbW9ycGgxCnRyYWluX2Zvcm11bGE8LWZvcm11bGEocHJlY2lwIH4gLikgCm5hbWVzKGRhdGFfdHJhaW4pCm5yb3coZGF0YV90cmFpbikKYGBgCgojIE1vZGVsIGV2YWx1YXRpb24KIyMgTW9kZWwgZmluZSB0dW5pbmcgb24gVHJhaW5pbmcgc2V0CmBgYHtyIHRyYWluaW5nfQpjdHJsX2Zhc3QgPC0gdHJhaW5Db250cm9sKG1ldGhvZD0icmVwZWF0ZWRjdiIsIAogICAgICAgICAgICAgICAgICAgICByZXBlYXRzPTEsCiAgICAgICAgICAgICAgICAgICAgIG51bWJlcj01LCAKICAgICAgICAgICAgICAgICAgICAgc3VtbWFyeUZ1bmN0aW9uPXR3b0NsYXNzU3VtbWFyeSwKICAgICAgICAgICAgICAgICAgICAgdmVyYm9zZUl0ZXI9RiwKICAgICAgICAgICAgICAgICAgICAgI3ByZVByb2NPcHRpb25zID0gbGlzdChwY2FDb21wID0gMTApLAogICAgICAgICAgICAgICAgICAgICBjbGFzc1Byb2JzPVRSVUUsCiAgICAgICAgICAgICAgICAgICAgIGFsbG93UGFyYWxsZWwgPSBUKSAgCgpubkdyaWQgPC0gIGV4cGFuZC5ncmlkKGRlY2F5ID0gYygwKSwgc2l6ZT1jKDEwLDIwLDUwLDEwMCwyMDAsMzAwKSkgCnN2bUdyaWQgPC0gIGV4cGFuZC5ncmlkKHNpZ21hID0gYygwLjAwMSwwLjAwMDAxKSwgQz1jKDAuMSwwLjAwMSwwLjUpKSAKCmtlcmFzR3JpZCA8LSBleHBhbmQuZ3JpZCgKICBzaXplPWMoMjAsNTAsMjAwMCw1MDAwKSwKICBsYW1iZGE9YygwKSwKICBiYXRjaF9zaXplPWMoMTAyNCksCiAgZGVjYXk9YygwKSwKICBhY3RpdmF0aW9uPWMoJ3RhbmgnLCdzaWdtb2lkJywncmVsdScpLAogIGxyPWMoMC4wMDEpLCByaG89YygwLjkpCikKCmN0cmxfZmFzdCRzYW1wbGluZzwtInNtb3RlIgpyZkZpdCA8LSBjYXJldDo6dHJhaW4odHJhaW5fZm9ybXVsYSwKICAgICAgICAgICAgICAgZGF0YSA9IGRhdGFfdHJhaW4sCiAgICAgICAgICAgICAgICNtZXRyaWM9IlJPQyIsCiAgICAgICAgICAgICAgICNwcmVQcm9jZXNzPWMoInBjYSIpLAogICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgI21ldGhvZCA9ICJtbHBXZWlnaHREZWNheSIsCiAgICAgICAgICAgICAgICNtZXRob2QgPSAic3ZtUmFkaWFsIiwKICAgICAgICAgICAgICAgI21ldGhvZCA9Im1scEtlcmFzRGVjYXkiLAogICAgICAgICAgICAgICBtZXRob2QgPSAicmYiLAogICAgICAgICAgICAgICAjdHVuZUdyaWQ9a2VyYXNHcmlkLAogICAgICAgICAgICAgICB0dW5lTGVuZ3RoPTExLAogICAgICAgICAgICAgICB2ZXJib3NlPTAsCiAgICAgICAgICAgICAgICNlcG9jaHM9MTAwLAogICAgICAgICAgICAgICB0ckNvbnRyb2wgPSBjdHJsX2Zhc3QpCmBgYAojIyBSZXN1bHRpbmcgbW9kZWxzCgpgYGB7ciBmaW5hbCBtb2RlbH0KcmZGaXQKZ2dwbG90KHJmRml0KSt0aGVtZV9idygpCmBgYAoKCgojIyBNb3N0IHJlbGV2YW50IGZlYXR1cmVzIGZvciBSRgpUSGUgbGlzdCBvZiB0aGUgbW9zdCByZWxldmFudCBmZWF0dXJlcyB1c2VkIGJ5IHRoZSBSYW5kb21Gb3Jlc3QgQ2xhc3NpZmllcgpgYGB7ciB2YXJpYWJsZSBpbXBvcnRhbmNlfQp2YXJJbXAocmZGaXQsIHNjYWxlID0gRikKYGBgCiMgRXZhbHVhdGlvbiBvbiB0ZXN0IHNldAoKIyMgQ29uZnVzaW9uIE1hdHJpeApgYGB7ciB0ZXN0aW5nfQpwcmVkc3Jwcm9maWxlcm9ic2FtcD1wcmVkaWN0KHJmRml0LGRhdGFfdGVzdCx0eXBlPSdwcm9iJykKcHJlZHNyZnNhbXA9aWZlbHNlKHByZWRzcnByb2ZpbGVyb2JzYW1wJHllcyA+PTAuNCwneWVzJywnbm8nKQpyZXN1bHRzPC1kYXRhLmZyYW1lKHJlZj1kYXRhX3Rlc3QkcHJlY2lwLHByZWQ9cHJlZHNyZnNhbXApCgoKY208LWNhcmV0Ojpjb25mdXNpb25NYXRyaXgoYXMuZmFjdG9yKHByZWRzcmZzYW1wKSxkYXRhX3Rlc3QkcHJlY2lwLHBvc2l0aXZlPSJ5ZXMiKQpjbQpgYGAKIyMgUk9DIEN1cnZlCmBgYHtyIHJvYyBjdXJ2ZX0KI3Bsb3Qocm9jKGRhdGFfdGVzdCRwcm9maWxlLHByZWRzcnByb2ZpbGVyb2JzYW1wJE1hbGljaW91cykpCmdncGxvdChjYmluZChwcmVkc3Jwcm9maWxlcm9ic2FtcCxjbGFzcz1kYXRhX3Rlc3QkcHJlY2lwKSwgCiAgICAgICBhZXMobSA9IHllcywgZCA9IGZhY3RvcihjbGFzcywgbGFiZWxzPWMoIm5vIiwieWVzIiksbGV2ZWxzID0gYygibm8iLCAieWVzIikpKSkgKyAKICAgIGdlb21fcm9jKGhqdXN0ID0gLTAuNCwgdmp1c3QgPSAxLjUsY29sb3VyPSdvcmFuZ2UnKSArIAogICAgZ2VvbV9hYmxpbmUoaW50ZXJjZXB0ID0gMCwgc2xvcGUgPSAxLGNvbG91cj0ncmVkJykrCiAgdGhlbWVfYncoKQoKYGBgCgo=