1 Arrange folders, sort files, read and merge

1.1 Create folders by conditions, copy files to them

# !!!!EVAL = FALSE
##################### Read file names ##################################################################################
file_names <- dir(pattern = "\\.xls$")
## if above isn't good enough try the following:
# file_names <- list.files(wd)
# file_names <- sop_files[!file.info(sop_files)$isdir]   # exclude directories
# file_names <- sop_files[grep(".xls", sop_files, fixed = TRUE)]


##################### Create folders with Condition names ###############################################################
# this part of script may be re-run if files from wd are updated
dir_names <- c("Unic_CTRL_Instr", "Unic_CTRL_Solo", "Unic_OGL_Instr", "Unic_OGL_Solo",
              "Repetat_CTRL_Instr", "Repetat_CTRL_Solo", "Repetat_OGL_Instr", "Repetat_OGL_Solo")
             
for(dir in dir_names){
  if(!dir.exists(file.path(wd, dir)))
  dir.create(file.path(wd, dir), showWarnings = FALSE)
}


##################### Use file names to sort them to folders ############################################################
sort_files_to_dirs <- function(wd, pattern, dir) {
  check_pattern <- outer(file_names, pattern, stringr::str_detect)               # if all TRUE bye row then it has full pattern
  index <- which(apply(check_pattern, 1, function(x) all(x==TRUE)))              # get index of file_names where all are TRUE
  sorted_files <- file_names[index]                                              # get names of files from indexes
  
  for(files in sorted_files) {                                                   # copy the files to corresponding folder
    file.copy(from = file.path(wd, files), to = file.path(wd, dir))
  }  
}

sort_files_to_dirs(wd = wd, pattern = c("unic", "ecran", "instructor"), dir = "Unic_CTRL_Instr")
sort_files_to_dirs(wd = wd, pattern = c("unic", "ecran", "solo"), dir = "Unic_CTRL_Solo")
sort_files_to_dirs(wd = wd, pattern = c("unic", "oglinda", "instructor"), dir = "Unic_OGL_Instr")
sort_files_to_dirs(wd = wd, pattern = c("unic", "oglinda", "solo"), dir = "Unic_OGL_Solo")

1.2 Reading the data

############ Read in all the .xls from folders and merge them in datasets named after corresponding folder ##############
# this part of script may be re-run if files from wd are updated
# RE-RUN FROM HERE IF FOLDERS AND SORTING WAS ALREADY DONE
wd <- "C:/Users/Mihai/Desktop/EEG_O.4c_1/O.4c - Poster/Date Studiu"
setwd(wd)
The working directory was changed to C:/Users/Mihai/Desktop/EEG_O.4c_1/O.4c - Poster/Date Studiu inside a notebook chunk. The working directory will be reset when the chunk is finished running. Use the knitr root.dir option in the setup chunk to change the working directory for notebook chunks.
folders <- list.files(wd)
folders <- folders[file.info(folders)$isdir]   # luam doar folderele
datasetnames <- NULL
for (i in 1:length(folders)) {
  datasetname <- folders[i]
  datasetnames <- c(datasetnames, datasetname)
  current_dir <- setwd(file.path(wd, folders[i]))
  print(paste0("current_dir: ", current_dir))
  
  paths <- dir(pattern = "\\.xls$")
  names(paths) <- basename(paths)
  assign( paste(datasetname), plyr::ldply(paths, rio::import) )
}
[1] "current_dir: C:/Users/Mihai/Desktop/EEG_O.4c_1/O.4c - Poster/Date Studiu"
[1] "current_dir: C:/Users/Mihai/Desktop/EEG_O.4c_1/O.4c - Poster/Date Studiu/Unic_CTRL_Instr"
[1] "current_dir: C:/Users/Mihai/Desktop/EEG_O.4c_1/O.4c - Poster/Date Studiu/Unic_CTRL_Solo"
[1] "current_dir: C:/Users/Mihai/Desktop/EEG_O.4c_1/O.4c - Poster/Date Studiu/Unic_OGL_Instr"
setwd(wd)
# detach("package:plyr", unload=TRUE)                                                   # detach plyr because of conflicts with dplyr

1.3 Cleaning the data

#################################### Data Cleaning #####################################################################
# Check if ids have > 1 row of data (empty .xls have only 1 row)
# Careful! This function modfies the datasets in the global envinronment
delete_empty_id <- function(df){
  list_empty_id <- 
    df %>%
    dplyr::group_by(.id) %>%
    dplyr::summarise(row_count = n()) %>%
    dplyr::rename("empty_id" = .id) %>%
    mutate(delete_id = if_else(row_count < 3, TRUE, FALSE)) %>%
    filter(delete_id == TRUE)
  
  df_modif <- 
    df %>%
    filter(!.id %in% list_empty_id$empty_id)
  
  if(!identical(df, df_modif)){
    df <- deparse(substitute(df))
    cat("Deleting from ", print(as.name(df))); print(list_empty_id)                    # print out which ids are deleted from which dataset
    assign(df, df_modif, envir = globalenv())                                          # assign modified df to original dataset from Global
  }else cat("No empty datasets. Nothing to delete")
}
# Apply function to all datasets (tricky to do in for loop because of super assignment)
delete_empty_id(Unic_CTRL_Instr)
No empty datasets. Nothing to delete
delete_empty_id(Unic_CTRL_Solo)
No empty datasets. Nothing to delete
delete_empty_id(Unic_OGL_Instr)
No empty datasets. Nothing to delete
delete_empty_id(Unic_OGL_Solo)
No empty datasets. Nothing to delete

1.4 Exclude SAM_resp based on RT outliers

# !!!!EVAL = FALSE
############################### Exclude Outliers based on RT (by subject and stimulus type) #######################################
## DONT RUN (unless it is needed) ----> eval=FALSE
# Exclude RT outliers (=- 2SD) - instead of simple filter, makeing them NA  is better for paired comparison
remove_outliers <- function(df) {
  df_modif <-
    df %>%
    dplyr::group_by(.id, `Stimulus type`) %>%                  # we could have done before:  dplyr::rename("Stim_type" = `Stimulus type`) 
    mutate(SAM_Resp = if_else(abs(SAM_RT - mean(SAM_RT, na.rm=TRUE)) > 2*sd(SAM_RT, na.rm=TRUE), as.numeric(NA), SAM_Resp))
  
  if(!identical(df, df_modif)){
    df <- deparse(substitute(df))
    cat("Deleting outliers from ", print(as.name(df)));                               # print out datasets which have been modified
    assign(df, df_modif, envir = globalenv())                                          # assign modified df to original dataset from Global
  }else cat("No outlier")
}

remove_outliers(Unic_CTRL_Instr)
remove_outliers(Unic_CTRL_Solo)
remove_outliers(Unic_OGL_Instr)
remove_outliers(Unic_OGL_Solo)

1.5 Test if datasets have same columns

unic_df_obj <- mget(c("Unic_CTRL_Instr", "Unic_CTRL_Solo", "Unic_OGL_Instr", "Unic_OGL_Solo"))
unic_df_obj <-lapply(unic_df_obj, colnames)
outer(unic_df_obj, unic_df_obj, Vectorize(identical))                           # if all are TRUE, all df have same columns
                Unic_CTRL_Instr Unic_CTRL_Solo Unic_OGL_Instr Unic_OGL_Solo
Unic_CTRL_Instr            TRUE           TRUE           TRUE          TRUE
Unic_CTRL_Solo             TRUE           TRUE           TRUE          TRUE
Unic_OGL_Instr             TRUE           TRUE           TRUE          TRUE
Unic_OGL_Solo              TRUE           TRUE           TRUE          TRUE



2 Analysis - UNICE

2.1 Descriptives

##########################################################################################################################
#################################### Analyses - UNICE ####################################################################
## Descriptives by condition dataset
descriptive_func <- function(df, Stim_type, By_ID = FALSE){
  df_name <- deparse(substitute(df))
  suppressWarnings({                                                                # if all NAs in SAM_Resp, NaNs and Infs will be produced
    df_modif <- 
      df %>%
      dplyr::rename("ID" = .id) %>%
      select_all(~gsub("\\s+|\\.", "_", .)) %>%                                     # replaces blancks with "_" in colnames 
      filter(Stimulus_type == Stim_type)                                            # filter by stimulus type
      
    if(isTRUE(By_ID)){                                                              # if true group by id, if not return descriptives for all ids
      by_id_text <- " by subject"
      df_modif %>%
      dplyr::group_by(ID) %>%
      tidystats::describe_data(SAM_Resp, SAM_RT, na.rm = TRUE) %>%
        knitr::kable(caption = paste(as.name(df_name), " ", Stim_type, by_id_text), format = "pandoc", digits = 2)
    }else{ 
      by_id_text <- " all subjects"
      df_modif %>%
      ungroup() %>%  
      tidystats::describe_data(SAM_Resp, SAM_RT, na.rm = TRUE) %>%
        knitr::kable(caption = paste(as.name(df_name), " ", Stim_type, by_id_text), format = "pandoc", digits = 2)
    }
  })
}  
descriptive_func(df = Unic_CTRL_Instr, Stim_type = "negativ", By_ID = FALSE)           # Negative - General

Unic_CTRL_Instr negativ all subjects
var missing n M SD SE min max range median mode skew kurtosis
SAM_Resp 0 105 2.80 1.50 0.15 1 8.00 7.00 3.00 2.00 0.83 3.49
SAM_RT 0 105 1.89 0.88 0.09 1 4.38 3.38 1.56 2.51 0.99 2.94

descriptive_func(df = Unic_CTRL_Solo, Stim_type = "negativ", By_ID = FALSE)

Unic_CTRL_Solo negativ all subjects
var missing n M SD SE min max range median mode skew kurtosis
SAM_Resp 0 105 3.33 1.75 0.17 1 8.00 7.00 3.00 2.00 0.62 2.56
SAM_RT 0 105 2.53 1.66 0.16 1 10.12 9.12 2.05 1.59 2.25 9.40

descriptive_func(df = Unic_OGL_Instr, Stim_type = "negativ", By_ID = FALSE)

Unic_OGL_Instr negativ all subjects
var missing n M SD SE min max range median mode skew kurtosis
SAM_Resp 0 105 2.80 1.83 0.18 1 8.00 7.00 2.00 2.00 1.11 3.5
SAM_RT 0 105 1.91 0.80 0.08 1 4.54 3.54 1.75 1.42 0.88 3.2

descriptive_func(df = Unic_OGL_Solo, Stim_type = "negativ", By_ID = FALSE)

Unic_OGL_Solo negativ all subjects
var missing n M SD SE min max range median mode skew kurtosis
SAM_Resp 0 105 2.66 1.60 0.16 1 8.00 7.00 2.00 1 1.00 3.60
SAM_RT 0 105 1.91 0.83 0.08 1 5.27 4.27 1.73 1 1.28 5.01

descriptive_func(df = Unic_CTRL_Instr, Stim_type = "negativ", By_ID = TRUE)            # Negative - by id

Unic_CTRL_Instr negativ by subject
var ID missing n M SD SE min max range median mode skew kurtosis
SAM_Resp O4c_2_ID17ecraninstructorunic .xls 0 35 2.23 0.91 0.15 1 4.00 3.00 2.00 2.00 0.25 2.26
SAM_Resp O4c_Run2_ID12ecraninstructorunic .xls 0 35 3.14 1.42 0.24 1 5.00 4.00 3.00 5.00 0.00 1.72
SAM_Resp O4c_Run4_ID10ecraninstructorunic .xls 0 35 3.03 1.87 0.32 1 8.00 7.00 3.00 1.00 0.83 3.03
SAM_RT O4c_2_ID17ecraninstructorunic .xls 0 35 2.84 0.75 0.13 1 4.38 3.38 2.65 2.51 0.04 2.81
SAM_RT O4c_Run2_ID12ecraninstructorunic .xls 0 35 1.43 0.32 0.05 1 2.26 1.26 1.37 1.00 0.69 2.88
SAM_RT O4c_Run4_ID10ecraninstructorunic .xls 0 35 1.40 0.57 0.10 1 3.26 2.26 1.23 1.22 2.15 6.83

descriptive_func(df = Unic_CTRL_Solo, Stim_type = "negativ", By_ID = TRUE)

Unic_CTRL_Solo negativ by subject
var ID missing n M SD SE min max range median mode skew kurtosis
SAM_Resp O4c_Run1_ID12ecransolo unic .xls 0 35 3.69 1.59 0.27 1.00 6.00 5.00 4.00 5.00 -0.19 1.75
SAM_Resp O4c_Run1_ID17ecransolo unic .xls 0 35 3.14 1.68 0.28 1.00 7.00 6.00 3.00 2.00 0.75 2.60
SAM_Resp O4c_Run3_ID10ecransolo unic .xls 0 35 3.17 1.95 0.33 1.00 8.00 7.00 3.00 2.00 1.11 3.36
SAM_RT O4c_Run1_ID12ecransolo unic .xls 0 35 1.79 0.69 0.12 1.00 4.23 3.23 1.56 1.59 1.47 5.65
SAM_RT O4c_Run1_ID17ecransolo unic .xls 0 35 3.48 1.71 0.29 1.18 10.12 8.94 3.24 1.18 1.91 8.09
SAM_RT O4c_Run3_ID10ecransolo unic .xls 0 35 2.31 1.88 0.32 1.00 9.63 8.63 1.65 1.28 2.47 9.08

descriptive_func(df = Unic_OGL_Instr, Stim_type = "negativ", By_ID = TRUE)

Unic_OGL_Instr negativ by subject
var ID missing n M SD SE min max range median mode skew kurtosis
SAM_Resp O4c_3_ID12oglindainstructorunic X.xls 0 35 2.77 1.46 0.25 1.00 5.00 4.00 3.00 1.00 0.23 1.70
SAM_Resp O4c_Run1_ID10oglindainstructorunic .xls 0 35 3.86 2.30 0.39 1.00 8.00 7.00 3.00 2.00 0.38 1.82
SAM_Resp O4c_RunN(modifica N!)_ID1717oglindainstructorunic .xls 0 35 1.77 0.73 0.12 1.00 3.00 2.00 2.00 2.00 0.37 1.98
SAM_RT O4c_3_ID12oglindainstructorunic X.xls 0 35 1.28 0.24 0.04 1.00 1.79 0.79 1.22 1.42 0.89 2.80
SAM_RT O4c_Run1_ID10oglindainstructorunic .xls 0 35 2.00 0.89 0.15 1.00 4.04 3.04 1.78 3.11 0.71 2.47
SAM_RT O4c_RunN(modifica N!)_ID1717oglindainstructorunic .xls 0 35 2.45 0.63 0.11 1.38 4.54 3.17 2.40 2.26 0.91 4.88

descriptive_func(df = Unic_OGL_Solo, Stim_type = "negativ", By_ID = TRUE)

Unic_OGL_Solo negativ by subject
var ID missing n M SD SE min max range median mode skew kurtosis
SAM_Resp O4c_4_ID12oglindasolo unic .xls 0 35 2.91 1.46 0.25 1.00 5.00 4.00 3.00 1.00 -0.02 1.65
SAM_Resp O4c_Run2_ID10oglindasolo unic .xls 0 35 3.34 1.94 0.33 1.00 8.00 7.00 3.00 3.00 0.66 2.62
SAM_Resp O4c_RunN(modifica N!)_ID1717oglindasolo unic .xls 0 35 1.71 0.67 0.11 1.00 3.00 2.00 2.00 2.00 0.38 2.24
SAM_RT O4c_4_ID12oglindasolo unic .xls 0 35 1.35 0.33 0.05 1.00 2.30 1.30 1.28 1.00 1.23 3.79
SAM_RT O4c_Run2_ID10oglindasolo unic .xls 0 35 2.01 1.05 0.18 1.00 5.27 4.27 1.73 1.24 1.42 4.56
SAM_RT O4c_RunN(modifica N!)_ID1717oglindasolo unic .xls 0 35 2.38 0.57 0.10 1.46 3.74 2.28 2.30 3.04 0.19 2.37

descriptive_func(df = Unic_CTRL_Instr, Stim_type = "pozitiv", By_ID = FALSE)           # Positive - General

Unic_CTRL_Instr pozitiv all subjects
var missing n M SD SE min max range median mode skew kurtosis
SAM_Resp 0 105 1.73 0.96 0.09 1 5.00 4.00 1.00 1.00 1.20 3.66
SAM_RT 0 105 1.69 0.70 0.07 1 4.08 3.08 1.39 2.33 1.12 3.51

descriptive_func(df = Unic_CTRL_Solo, Stim_type = "pozitiv", By_ID = FALSE)

Unic_CTRL_Solo pozitiv all subjects
var missing n M SD SE min max range median mode skew kurtosis
SAM_Resp 0 105 2.01 1.27 0.12 1 6.00 5.00 2.00 1.00 1.21 3.71
SAM_RT 0 105 2.13 1.29 0.13 1 9.16 8.16 1.78 1.21 2.52 12.52

descriptive_func(df = Unic_OGL_Instr, Stim_type = "pozitiv", By_ID = FALSE)

Unic_OGL_Instr pozitiv all subjects
var missing n M SD SE min max range median mode skew kurtosis
SAM_Resp 0 105 2.15 1.57 0.15 1 8.00 7.00 2.00 1 1.46 4.49
SAM_RT 0 105 1.85 0.82 0.08 1 5.14 4.14 1.59 1 1.64 6.04

descriptive_func(df = Unic_OGL_Solo, Stim_type = "pozitiv", By_ID = FALSE)

Unic_OGL_Solo pozitiv all subjects
var missing n M SD SE min max range median mode skew kurtosis
SAM_Resp 0 105 2.02 1.26 0.12 1 7.00 6.00 2.00 1.00 1.57 5.56
SAM_RT 0 105 1.84 1.03 0.10 1 6.72 5.71 1.47 1.42 2.25 9.10

descriptive_func(df = Unic_CTRL_Instr, Stim_type = "pozitiv", By_ID = TRUE)            # Positive - by id

Unic_CTRL_Instr pozitiv by subject
var ID missing n M SD SE min max range median mode skew kurtosis
SAM_Resp O4c_2_ID17ecraninstructorunic .xls 0 35 1.69 0.76 0.13 1.00 3.00 2.00 2.00 1.00 0.58 2.00
SAM_Resp O4c_Run2_ID12ecraninstructorunic .xls 0 35 1.00 0.00 0.00 1.00 1.00 0.00 1.00 1.00 NaN NaN
SAM_Resp O4c_Run4_ID10ecraninstructorunic .xls 0 35 2.51 1.04 0.18 1.00 5.00 4.00 2.00 2.00 0.44 2.47
SAM_RT O4c_2_ID17ecraninstructorunic .xls 0 35 2.41 0.59 0.10 1.39 4.08 2.69 2.41 2.33 0.40 3.21
SAM_RT O4c_Run2_ID12ecraninstructorunic .xls 0 35 1.25 0.29 0.05 1.00 2.50 1.50 1.18 1.14 2.48 10.70
SAM_RT O4c_Run4_ID10ecraninstructorunic .xls 0 35 1.41 0.49 0.08 1.00 3.55 2.54 1.27 1.76 2.59 11.43

descriptive_func(df = Unic_CTRL_Solo, Stim_type = "pozitiv", By_ID = TRUE)

Unic_CTRL_Solo pozitiv by subject
var ID missing n M SD SE min max range median mode skew kurtosis
SAM_Resp O4c_Run1_ID12ecransolo unic .xls 0 35 1.00 0.00 0.00 1.00 1.00 0.00 1.00 1.00 NaN NaN
SAM_Resp O4c_Run1_ID17ecransolo unic .xls 0 35 1.94 0.84 0.14 1.00 4.00 3.00 2.00 2.00 0.41 2.29
SAM_Resp O4c_Run3_ID10ecransolo unic .xls 0 35 3.09 1.40 0.24 1.00 6.00 5.00 3.00 2.00 0.30 2.22
SAM_RT O4c_Run1_ID12ecransolo unic .xls 0 35 1.39 0.42 0.07 1.00 2.91 1.91 1.27 1.21 1.83 6.56
SAM_RT O4c_Run1_ID17ecransolo unic .xls 0 35 2.89 0.68 0.12 1.23 4.85 3.61 2.84 2.81 0.71 4.47
SAM_RT O4c_Run3_ID10ecransolo unic .xls 0 35 2.11 1.81 0.31 1.00 9.16 8.16 1.40 2.99 2.67 9.78

descriptive_func(df = Unic_OGL_Instr, Stim_type = "pozitiv", By_ID = TRUE)

Unic_OGL_Instr pozitiv by subject
var ID missing n M SD SE min max range median mode skew kurtosis
SAM_Resp O4c_3_ID12oglindainstructorunic X.xls 0 35 1.29 0.52 0.09 1.00 3.00 2.00 1.00 1.00 1.57 4.56
SAM_Resp O4c_Run1_ID10oglindainstructorunic .xls 0 35 3.86 1.59 0.27 1.00 8.00 7.00 4.00 4.00 0.33 2.85
SAM_Resp O4c_RunN(modifica N!)_ID1717oglindainstructorunic .xls 0 35 1.31 0.47 0.08 1.00 2.00 1.00 1.00 1.00 0.80 1.64
SAM_RT O4c_3_ID12oglindainstructorunic X.xls 0 35 1.29 0.24 0.04 1.00 1.84 0.84 1.20 1.00 0.68 2.48
SAM_RT O4c_Run1_ID10oglindainstructorunic .xls 0 35 2.09 1.07 0.18 1.01 5.14 4.13 1.68 2.79 1.37 4.13
SAM_RT O4c_RunN(modifica N!)_ID1717oglindainstructorunic .xls 0 35 2.17 0.59 0.10 1.27 3.66 2.38 2.11 3.66 0.65 2.83

descriptive_func(df = Unic_OGL_Solo, Stim_type = "pozitiv", By_ID = TRUE)

Unic_OGL_Solo pozitiv by subject
var ID missing n M SD SE min max range median mode skew kurtosis
SAM_Resp O4c_4_ID12oglindasolo unic .xls 0 35 1.34 0.48 0.08 1 2.00 1.00 1.00 1.00 0.66 1.44
SAM_Resp O4c_Run2_ID10oglindasolo unic .xls 0 35 3.23 1.44 0.24 1 7.00 6.00 3.00 4.00 0.50 3.19
SAM_Resp O4c_RunN(modifica N!)_ID1717oglindasolo unic .xls 0 35 1.49 0.51 0.09 1 2.00 1.00 1.00 1.00 0.06 1.00
SAM_RT O4c_4_ID12oglindasolo unic .xls 0 35 1.24 0.43 0.07 1 3.48 2.48 1.14 1.42 4.27 22.86
SAM_RT O4c_Run2_ID10oglindasolo unic .xls 0 35 2.12 1.35 0.23 1 6.72 5.71 1.59 1.21 2.06 6.70
SAM_RT O4c_RunN(modifica N!)_ID1717oglindasolo unic .xls 0 35 2.16 0.83 0.14 1 4.54 3.53 1.98 1.79 0.87 3.30

descriptive_func(df = Unic_CTRL_Instr, Stim_type = "neutru", By_ID = FALSE)           # Neutral - General

Unic_CTRL_Instr neutru all subjects
var missing n M SD SE min max range median mode skew kurtosis
SAM_Resp 0 105 1.43 0.95 0.09 1 5.00 4.00 1.00 1.00 2.51 8.86
SAM_RT 0 105 1.57 0.58 0.06 1 3.47 2.47 1.42 2.12 1.08 3.82

descriptive_func(df = Unic_CTRL_Solo, Stim_type = "neutru", By_ID = FALSE)

Unic_CTRL_Solo neutru all subjects
var missing n M SD SE min max range median mode skew kurtosis
SAM_Resp 0 105 1.54 1.05 0.1 1 5.0 4.0 1.00 1.00 2.01 6.14
SAM_RT 0 105 1.88 0.98 0.1 1 5.9 4.9 1.51 1.61 1.62 5.84

descriptive_func(df = Unic_OGL_Instr, Stim_type = "neutru", By_ID = FALSE)

Unic_OGL_Instr neutru all subjects
var missing n M SD SE min max range median mode skew kurtosis
SAM_Resp 0 105 1.37 0.90 0.09 1 6.00 5.00 1.00 1.00 3.16 13.51
SAM_RT 0 105 1.67 0.62 0.06 1 3.98 2.98 1.57 1.21 1.36 5.02

descriptive_func(df = Unic_OGL_Solo, Stim_type = "neutru", By_ID = FALSE)

Unic_OGL_Solo neutru all subjects
var missing n M SD SE min max range median mode skew kurtosis
SAM_Resp 0 105 1.43 0.91 0.09 1 5.00 4.00 1.00 1.00 2.46 8.81
SAM_RT 0 105 1.56 0.60 0.06 1 3.73 2.73 1.37 1.55 1.33 4.12

descriptive_func(df = Unic_CTRL_Instr, Stim_type = "neutru", By_ID = TRUE)            # Neutral - by id

Unic_CTRL_Instr neutru by subject
var ID missing n M SD SE min max range median mode skew kurtosis
SAM_Resp O4c_2_ID17ecraninstructorunic .xls 0 35 1.23 0.60 0.10 1.0 3.00 2.00 1.00 1.00 2.40 7.17
SAM_Resp O4c_Run2_ID12ecraninstructorunic .xls 0 35 1.03 0.17 0.03 1.0 2.00 1.00 1.00 1.00 5.66 33.03
SAM_Resp O4c_Run4_ID10ecraninstructorunic .xls 0 35 2.03 1.34 0.23 1.0 5.00 4.00 2.00 1.00 1.21 3.29
SAM_RT O4c_2_ID17ecraninstructorunic .xls 0 35 2.17 0.51 0.09 1.3 3.47 2.16 2.13 2.12 0.84 3.42
SAM_RT O4c_Run2_ID12ecraninstructorunic .xls 0 35 1.33 0.35 0.06 1.0 2.09 1.09 1.22 2.09 0.74 2.23
SAM_RT O4c_Run4_ID10ecraninstructorunic .xls 0 35 1.20 0.26 0.04 1.0 1.87 0.87 1.09 1.00 1.47 3.91

descriptive_func(df = Unic_CTRL_Solo, Stim_type = "neutru", By_ID = TRUE)

Unic_CTRL_Solo neutru by subject
var ID missing n M SD SE min max range median mode skew kurtosis
SAM_Resp O4c_Run1_ID12ecransolo unic .xls 0 35 1.09 0.51 0.09 1.00 4.00 3.00 1.00 1.00 5.66 33.03
SAM_Resp O4c_Run1_ID17ecransolo unic .xls 0 35 1.49 0.98 0.17 1.00 5.00 4.00 1.00 1.00 2.12 6.86
SAM_Resp O4c_Run3_ID10ecransolo unic .xls 0 35 2.06 1.28 0.22 1.00 5.00 4.00 2.00 1.00 1.08 3.11
SAM_RT O4c_Run1_ID12ecransolo unic .xls 0 35 1.36 0.55 0.09 1.00 3.53 2.53 1.18 1.61 2.47 9.05
SAM_RT O4c_Run1_ID17ecransolo unic .xls 0 35 2.54 0.90 0.15 1.46 5.03 3.57 2.34 2.71 1.30 4.16
SAM_RT O4c_Run3_ID10ecransolo unic .xls 0 35 1.75 1.05 0.18 1.00 5.90 4.90 1.35 1.45 2.22 8.35

descriptive_func(df = Unic_OGL_Instr, Stim_type = "neutru", By_ID = TRUE)

Unic_OGL_Instr neutru by subject
var ID missing n M SD SE min max range median mode skew kurtosis
SAM_Resp O4c_3_ID12oglindainstructorunic X.xls 0 35 1.17 0.57 0.10 1.00 4.00 3.00 1.00 1.00 3.94 19.03
SAM_Resp O4c_Run1_ID10oglindainstructorunic .xls 0 35 1.80 1.32 0.22 1.00 6.00 5.00 1.00 1.00 1.84 5.49
SAM_Resp O4c_RunN(modifica N!)_ID1717oglindainstructorunic .xls 0 35 1.14 0.36 0.06 1.00 2.00 1.00 1.00 1.00 2.04 5.17
SAM_RT O4c_3_ID12oglindainstructorunic X.xls 0 35 1.25 0.23 0.04 1.00 1.83 0.83 1.22 1.21 0.80 2.74
SAM_RT O4c_Run1_ID10oglindainstructorunic .xls 0 35 1.90 0.73 0.12 1.00 3.98 2.98 1.71 3.98 0.93 3.43
SAM_RT O4c_RunN(modifica N!)_ID1717oglindainstructorunic .xls 0 35 1.86 0.56 0.09 1.05 3.75 2.70 1.84 2.87 1.09 5.12

descriptive_func(df = Unic_OGL_Solo, Stim_type = "neutru", By_ID = TRUE)
Unic_OGL_Solo neutru by subject
var ID missing n M SD SE min max range median mode skew kurtosis
SAM_Resp O4c_4_ID12oglindasolo unic .xls 0 35 1.20 0.41 0.07 1.00 2.00 1.00 1.00 1.00 1.50 3.25
SAM_Resp O4c_Run2_ID10oglindasolo unic .xls 0 35 1.94 1.33 0.22 1.00 5.00 4.00 1.00 1.00 1.18 3.12
SAM_Resp O4c_RunN(modifica N!)_ID1717oglindasolo unic .xls 0 35 1.14 0.43 0.07 1.00 3.00 2.00 1.00 1.00 3.08 11.98
SAM_RT O4c_4_ID12oglindasolo unic .xls 0 35 1.20 0.20 0.03 1.00 1.57 0.56 1.15 1.55 0.64 1.91
SAM_RT O4c_Run2_ID10oglindasolo unic .xls 0 35 1.77 0.78 0.13 1.00 3.73 2.73 1.38 1.95 0.82 2.43
SAM_RT O4c_RunN(modifica N!)_ID1717oglindasolo unic .xls 0 35 1.71 0.52 0.09 1.04 2.83 1.80 1.68 1.22 0.55 2.39

2.2 Merge

############################## Merge condition dataset ############################################################
# Must first rename .id to ID in oder to have .id for df names
ID_rename <- function(df){
  if(".id" %in% colnames(df)) {
    df_modif <- 
      df %>%
      dplyr::rename("ID" = .id)
    df <- deparse(substitute(df))
    cat("Changed .id to ID for: ", as.name(df))
    assign(df, df_modif, envir = globalenv())
  }  
}
ID_rename(Unic_CTRL_Instr)
Changed .id to ID for:  Unic_CTRL_Instr
ID_rename(Unic_CTRL_Solo)
Changed .id to ID for:  Unic_CTRL_Solo
ID_rename(Unic_OGL_Instr)
Changed .id to ID for:  Unic_OGL_Instr
ID_rename(Unic_OGL_Solo)
Changed .id to ID for:  Unic_OGL_Solo
# Merge into one df
list_df_merge <- list(Unic_CTRL_Instr, Unic_CTRL_Solo, Unic_OGL_Instr, Unic_OGL_Solo)
names(list_df_merge) <- c("Unic_CTRL_Instr", "Unic_CTRL_Solo", "Unic_OGL_Instr", "Unic_OGL_Solo")
Unic_merged <- plyr::ldply(list_df_merge, data.frame)                    # also works for this job bind_rows(list_df_merge, .id = "column_label")

2.3 Analyses on merged (Anova & post-hoc)

############################## Analyses on Merged ################################################################
## Just a Test 
  # Unic_merged_spread_Neg <- 
  #   Unic_merged %>%
  #   filter(!is.na(SAM_Resp)) %>%                                           # some files had only NA on SAM_Resp and SAM_RT
  #   select(.id, ID, Subj_id, 
  #          Stimuli.order, MarkerStimuli, Stimulus.type, 
  #          SAM_Resp, SAM_RT) %>%
  #   filter(Stimulus.type == "negativ") %>%                                 # dont forget to pick stymulus type
  #   spread(.id, SAM_Resp)
  # 
  # t.test(Unic_merged_spread_Neg$Unic_CTRL_Instr, Unic_merged_spread_Neg$Unic_CTRL_Solo, na.rm = TRUE)
  # t.test(Unic_merged_spread_Neg$Unic_OGL_Instr, Unic_merged_spread_Neg$Unic_OGL_Solo, na.rm = TRUE)
  # t.test(Unic_merged_spread_Neg$Unic_OGL_Instr, Unic_merged_spread_Neg$Unic_CTRL_Instr, na.rm = TRUE)
  # t.test(Unic_merged_spread_Neg$Unic_OGL_Solo, Unic_merged_spread_Neg$Unic_CTRL_Solo, na.rm = TRUE)
## Function prepair data for analyses
prepaire_merged_func <- function(Stim_type){
  Unic_merged %>%
    filter(!is.na(SAM_Resp)) %>%                                           # some files had only NA on SAM_Resp and SAM_RT
    select(.id, ID, Subj_id, 
           Stimuli.order, MarkerStimuli, Stimulus.type, 
           SAM_Resp, SAM_RT) %>%
    dplyr::rename(Cond = .id) %>% 
    filter(Stimulus.type == Stim_type) %>%                                 # dont forget to pick stymulus type
    mutate(Cond = as.factor(Cond))                                         # tunr to factor for aov family functions
}
Unic_merged_Neg <- prepaire_merged_func("negativ")
Unic_merged_Neu <- prepaire_merged_func("neutru")
Unic_merged_Poz <- prepaire_merged_func("pozitiv")
## Anova and Post-Hoc  - NEGATIV
# Stimulus type
cat("### Negativ")

2.3.1 Negativ

# Normality
cat("#### Normality Test")

2.3.1.1 Normality Test

Unic_merged_Neg %>%
  select(SAM_Resp) %>%                                                     # must select variables outside function 
  tadaatoolbox::tadaa_normtest(method = "shapiro")                         # , print = "markdown"  for Notebook
# Levene Test (p>.05 = homogeneity of variances)
cat("#### Levene Test")

2.3.1.2 Levene Test

Unic_merged_Neg %>%
  tadaatoolbox::tadaa_levene(data = ., SAM_Resp ~ Cond)                    # , print = "markdown"  for Notebook
# Anova
cat("#### Anova")

2.3.1.3 Anova

Unic_merged_Neg %>%
  #do(broom::glance(aov(.$SAM_Resp ~ .$Cond)))                             # regular anova do(broom::tidy(aov(.$SAM_Resp ~ .$Cond)))
  tadaatoolbox::tadaa_aov(data = ., SAM_Resp ~ Cond, type = 1)             # , print = "markdown"  for Notebook
# Post-Hoc 
cat("#### Post-Hoc Games Howell")

2.3.1.4 Post-Hoc Games Howell

Unic_merged_Neg %>%
  # Tukey for equal variance 
  tadaatoolbox::tadaa_pairwise_tukey(data = ., SAM_Resp, Cond)             # , print = "markdown"  for Notebook
  # Games Howell does not assume equal variances
  #tadaatoolbox::tadaa_pairwise_gh(data = ., SAM_Resp, Cond)                # , print = "markdown"  for Notebook
## Anova and Post-Hoc  - NEUTRU
# Stimulus type
cat("### Neutru")

2.3.2 Neutru

# Normality
cat("#### Normality Test")

2.3.2.1 Normality Test

Unic_merged_Neu %>%
  select(SAM_Resp) %>%                                                     # must select variables outside function 
  tadaatoolbox::tadaa_normtest(method = "shapiro")                         # , print = "markdown"  for Notebook
# Levene Test (p>.05 = homogeneity of variances)
cat("#### Levene Test")

2.3.2.2 Levene Test

Unic_merged_Neu %>%
  tadaatoolbox::tadaa_levene(data = ., SAM_Resp ~ Cond)                    # , print = "markdown"  for Notebook
# Anova
cat("#### Anova")

2.3.2.3 Anova

Unic_merged_Neu %>%
  #do(broom::glance(aov(.$SAM_Resp ~ .$Cond)))                             # regular anova do(broom::tidy(aov(.$SAM_Resp ~ .$Cond)))
  tadaatoolbox::tadaa_aov(data = ., SAM_Resp ~ Cond, type = 1)             # , print = "markdown"  for Notebook
# Post-Hoc 
cat("#### Post-Hoc Games Howell")

2.3.2.4 Post-Hoc Games Howell

Unic_merged_Neu %>%
  # Tukey for equal variance 
  tadaatoolbox::tadaa_pairwise_tukey(data = ., SAM_Resp, Cond)             # , print = "markdown"  for Notebook
  # Games Howell does not assume equal variances
  #tadaatoolbox::tadaa_pairwise_gh(data = ., SAM_Resp, Cond)                # , print = "markdown"  for Notebook
## Anova and Post-Hoc  - POZITIV
# Stimulus type
cat("### Pozitiv")

2.3.3 Pozitiv

# Normality
cat("#### Normality Test")

2.3.3.1 Normality Test

Unic_merged_Poz %>%
  select(SAM_Resp) %>%                                                     # must select variables outside function 
  tadaatoolbox::tadaa_normtest(method = "shapiro")                         # , print = "markdown"  for Notebook
# Levene Test (p>.05 = homogeneity of variances)
cat("#### Levene Test")

2.3.3.2 Levene Test

Unic_merged_Poz %>%
  tadaatoolbox::tadaa_levene(data = ., SAM_Resp ~ Cond)                    # , print = "markdown"  for Notebook
# Anova
cat("#### Anova")

2.3.3.3 Anova

Unic_merged_Poz %>%
  #do(broom::glance(aov(.$SAM_Resp ~ .$Cond)))                             # regular anova do(broom::tidy(aov(.$SAM_Resp ~ .$Cond)))
  tadaatoolbox::tadaa_aov(data = ., SAM_Resp ~ Cond, type = 1)             # , print = "markdown"  for Notebook
# Post-Hoc 
cat("#### Post-Hoc Games Howell")

2.3.3.4 Post-Hoc Games Howell

Unic_merged_Poz %>%
  # Tukey for equal variance 
  tadaatoolbox::tadaa_pairwise_tukey(data = ., SAM_Resp, Cond)             # , print = "markdown"  for Notebook
  # Games Howell does not assume equal variances
  #tadaatoolbox::tadaa_pairwise_gh(data = ., SAM_Resp, Cond)                # , print = "markdown"  for Notebook

2.4 Plots with p values

# by dataset
ggplot(Unic_merged, aes(x = Stimulus.type, y = SAM_Resp)) +
  geom_boxplot() +
  stat_summary(fun.data = mean_se,  colour = "darkred") +
  xlab("") +
  facet_wrap(~.id) +
  ggpubr::stat_compare_means(method = "t.test", 
                             label = "p.signif",                                         # to avoid scientific notation of very small p-values
                             #paired = TRUE, 
                             comparisons = list(c("negativ", "neutru"),
                                                c("neutru", "pozitiv"),
                                                c("negativ", "pozitiv")))  

# by Stimulus type
ggplot(Unic_merged, aes(x = .id, y = SAM_Resp)) +
  geom_boxplot() +
  stat_summary(fun.data = mean_se,  colour = "darkred") +
  xlab("") +
  theme(axis.text.x = element_text(angle = 90, hjust = 1)) +
  facet_wrap(~Stimulus.type) +
  ggpubr::stat_compare_means(method = "t.test",
                             label = "p.format",                                         # formated p-values
                             #paired = TRUE, 
                             comparisons = list(c("Unic_CTRL_Instr", "Unic_CTRL_Solo"),
                                                c("Unic_CTRL_Instr", "Unic_OGL_Instr"),
                                                c("Unic_CTRL_Solo", "Unic_OGL_Instr"),
                                                c("Unic_CTRL_Solo", "Unic_OGL_Solo"),
                                                c("Unic_OGL_Instr", "Unic_OGL_Solo"),
                                                c("Unic_CTRL_Instr", "Unic_OGL_Solo"))) 

# drop to CTRL vs OGL - by Stimulus type
Unic_merged %>%
  mutate(.id = case_when(.id %in% c("Unic_CTRL_Instr", "Unic_CTRL_Solo") ~ "Unic_CTRL",
                         .id %in% c("Unic_OGL_Instr", "Unic_OGL_Solo") ~ "Unic_OGL",
                         TRUE ~ as.character(.id))) %>%
    ggplot(aes(x = .id, y = SAM_Resp)) +
    geom_boxplot() +
    stat_summary(fun.data = mean_se,  colour = "darkred") +
    xlab("") +
    theme(axis.text.x = element_text(angle = 90, hjust = 1)) +
    facet_wrap(~Stimulus.type) +
    ggpubr::stat_compare_means(method = "t.test",
                               label = "p.format",                                         # formated p-values
                               #paired = TRUE, 
                               comparisons = list(c("Unic_CTRL", "Unic_OGL")))          

# drop to Instr vs Solo - by Stimulus type
Unic_merged %>%
  mutate(.id = case_when(.id %in% c("Unic_CTRL_Instr", "Unic_OGL_Instr") ~ "Unic_Instr",
                         .id %in% c("Unic_CTRL_Solo", "Unic_OGL_Solo") ~ "Unic_Solo",
                         TRUE ~ as.character(.id))) %>%
    ggplot(aes(x = .id, y = SAM_Resp)) +
    geom_boxplot() +
    stat_summary(fun.data = mean_se,  colour = "darkred") +
    xlab("") +
    theme(axis.text.x = element_text(angle = 90, hjust = 1)) +
    facet_wrap(~Stimulus.type) +
    ggpubr::stat_compare_means(method = "t.test",
                               label = "p.format",                                         # formated p-values
                               #paired = TRUE, 
                               comparisons = list(c("Unic_Instr", "Unic_Solo"))) 

3 Download Data

Unic_merged %>% 
    select(-c(3:10)) %>%
    DT::datatable(                                  # excel downloadable  DT table
      extensions = 'Buttons',
      options = list(pageLength = 20,
                     scrollX='500px', 
                     dom = 'Bfrtip', 
                     buttons = c('excel', "csv")))


4 Session Info

R version 3.5.2 (2018-12-20)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows >= 8 x64 (build 9200)

Matrix products: default

locale:
[1] LC_COLLATE=Romanian_Romania.1250  LC_CTYPE=Romanian_Romania.1250    LC_MONETARY=Romanian_Romania.1250 LC_NUMERIC=C                     
[5] LC_TIME=Romanian_Romania.1250    

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] bindrcpp_0.2.2     plyr_1.8.4         summarytools_0.9.3 DT_0.5             ggpubr_0.2         magrittr_1.5       broom_0.5.1       
 [8] papaja_0.1.0.9842  psych_1.8.10       forcats_0.3.0      stringr_1.3.1      dplyr_0.7.8        purrr_0.2.5        readr_1.3.0       
[15] tidyr_0.8.2        tibble_1.4.2       ggplot2_3.1.0      tidyverse_1.2.1    pacman_0.5.0      

loaded via a namespace (and not attached):
 [1] nlme_3.1-137        matrixStats_0.54.0  bitops_1.0-6        lubridate_1.7.4     httr_1.4.0          tools_3.5.2         backports_1.1.3    
 [8] tidystats_0.3       R6_2.3.0            nortest_1.0-4       lazyeval_0.2.1      colorspace_1.3-2    withr_2.1.2         tidyselect_0.2.5   
[15] gridExtra_2.3       mnormt_1.5-5        pixiedust_0.8.6     curl_3.2            compiler_3.5.2      tadaatoolbox_0.16.1 cli_1.0.1          
[22] rvest_0.3.2         expm_0.999-3        xml2_1.2.0          labeling_0.3        checkmate_1.8.5     scales_1.0.0        mvtnorm_1.0-10     
[29] digest_0.6.18       foreign_0.8-71      rmarkdown_1.11      rio_0.5.16          base64enc_0.1-3     pkgconfig_2.0.2     htmltools_0.3.6    
[36] manipulate_1.0.1    highr_0.7           pwr_1.2-2           htmlwidgets_1.3     rlang_0.3.1         readxl_1.1.0        pryr_0.1.4         
[43] rstudioapi_0.8      shiny_1.2.0         bindr_0.1.1         generics_0.0.2      jsonlite_1.6        crosstalk_1.0.0     zip_1.0.0          
[50] car_3.0-2           RCurl_1.95-4.11     rapportools_1.0     Matrix_1.2-15       Rcpp_1.0.0          DescTools_0.99.27   munsell_0.5.0      
[57] abind_1.4-5         viridis_0.5.1       stringi_1.2.4       yaml_2.2.0          carData_3.0-2       MASS_7.3-51.1       grid_3.5.2         
[64] parallel_3.5.2      promises_1.0.1      crayon_1.3.4        lattice_0.20-38     haven_2.1.0         pander_0.6.3        hms_0.4.2          
[71] magick_2.0          knitr_1.21          pillar_1.3.1        tcltk_3.5.2         boot_1.3-20         ggsignif_0.4.0      codetools_0.2-15   
[78] glue_1.3.0          evaluate_0.12       data.table_1.12.2   modelr_0.1.2        httpuv_1.4.5        cellranger_1.1.0    gtable_0.2.0       
[85] assertthat_0.2.0    xfun_0.4            openxlsx_4.1.0      mime_0.6            xtable_1.8-3        later_0.7.5         viridisLite_0.3.0  
 

A work by Claudiu Papasteri

claudiu.papasteri@gmail.com

 

LS0tDQp0aXRsZTogIjxicj4gTy40IC0gVUNMIFBvc3RlciIgDQpzdWJ0aXRsZTogIlByZWxpbWluYXJ5IFJlcG9ydCBmb3IgVW5pY2UgLSAzIFN0dWR5IFBhcnRpY2lwYW50cyINCmF1dGhvcjogIjxicj4gQ2xhdWRpdSBQYXBhc3RlcmkiDQpkYXRlOiAiYHIgZm9ybWF0KFN5cy50aW1lKCksICclZCAlbSAlWScpYCINCm91dHB1dDogDQogICAgaHRtbF9ub3RlYm9vazoNCiAgICAgICAgICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgICAgICAgICAgdG9jOiB0cnVlDQogICAgICAgICAgICB0b2NfZGVwdGg6IDINCiAgICAgICAgICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQ0KICAgICAgICAgICAgdGhlbWU6IHNwYWNlbGFiDQogICAgICAgICAgICBoaWdobGlnaHQ6IHRhbmdvDQogICAgICAgICAgICBmb250LWZhbWlseTogQXJpYWwNCiAgICAgICAgICAgIGZpZ193aWR0aDogMTANCiAgICAgICAgICAgIGZpZ19oZWlnaHQ6IDkNCiAgICBwZGZfZG9jdW1lbnQ6IA0KICAgICAgICAgICAgdG9jOiB0cnVlDQogICAgICAgICAgICB0b2NfZGVwdGg6IDINCiAgICAgICAgICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQ0KICAgICAgICAgICAgIyBmb250c2l6ZTogMTFwdA0KICAgICAgICAgICAgIyBnZW9tZXRyeTogbWFyZ2luPTFpbg0KICAgICAgICAgICAgIyBmaWdfd2lkdGg6IDcNCiAgICAgICAgICAgICMgZmlnX2hlaWdodDogNg0KICAgICAgICAgICAgIyBmaWdfY2FwdGlvbjogdHJ1ZQ0KICAgICMgZ2l0aHViX2RvY3VtZW50OiANCiAgICAgICAgICAgICMgdG9jOiB0cnVlDQogICAgICAgICAgICAjIHRvY19kZXB0aDogMg0KICAgICAgICAgICAgIyBodG1sX3ByZXZpZXc6IGZhbHNlDQogICAgICAgICAgICAjIGZpZ193aWR0aDogNQ0KICAgICAgICAgICAgIyBmaWdfaGVpZ2h0OiA1DQogICAgICAgICAgICAjIGRldjoganBlZw0KLS0tDQoNCg0KPCEtLSBTZXR1cCAtLT4NCg0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCiMga2ludHIgb3B0aW9ucw0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KA0KICBjb21tZW50ID0gIiMiLA0KICBjb2xsYXBzZSA9IFRSVUUsDQogIGVjaG8gPSBUUlVFLCB3YXJuaW5nID0gVFJVRSwgbWVzc2FnZSA9IFRSVUUsIGNhY2hlID0gVFJVRSAgICAgICAjIGVjaG8gPSBGYWxzZSBmb3IgZ2l0aHViX2RvY3VtZW50LCBidXQgd2lsbCBiZSBmb2xkZWQgaW4gaHRtbF9ub3RlYm9vaw0KKQ0KDQojIEdlbmVyYWwgUiBvcHRpb25zIGFuZCBpbmZvDQpzZXQuc2VlZCgxMTEpICAgICAgICAgICAgICAgIyBpbiBjYXNlIHdlIHVzZSByYW5kb21pemVkIHByb2NlZHVyZXMgICAgICAgDQpvcHRpb25zKHNjaXBlbiA9IDk5OSkgICAgICAgIyBwb3NpdGl2ZSB2YWx1ZXMgYmlhcyB0b3dhcmRzIGZpeGVkIGFuZCBuZWdhdGl2ZSB0b3dhcmRzIHNjaWVudGlmaWMgbm90YXRpb24NCg0KIyBMb2FkIHBhY2thZ2VzDQppZiAoIXJlcXVpcmUoInBhY21hbiIpKSBpbnN0YWxsLnBhY2thZ2VzKCJwYWNtYW4iKQ0KcGFja2FnZXMgPC0gYygNCiAgInRpZHl2ZXJzZSIsICAgICAgIyBiZXN0IHRoaW5nIHRoYXQgaGFwcGVuZCB0byBtZQ0KICAicHN5Y2giLCAgICAgICAgICAjIGdlbmVyYWwgcHVycG9zZSB0b29sYm94IGZvciBwZXJzb25hbGl0eSwgcHN5Y2hvbWV0cmljIHRoZW9yeSBhbmQgZXhwZXJpbWVudGFsIHBzeWNob2xvZ3kNCiAgInBhcGFqYSIsICAgICAgICAgIyBmb3IgQVBBIHN0eWxlDQogICJicm9vbSIsICAgICAgICAgICMgZm9yIHRpZHkgbW9kZWxsaW5nDQogICJnZ3Bsb3QyIiwgICAgICAgICMgYmVzdCBwbG90cw0KICAiZ2dwdWJyIiwgICAgICAgICAjIGdncGxvdDIgdG8gcHVibGljYXRpb24gcXVhbGl0eQ0KICAiRFQiLCAgICAgICAgICAgICAjIG5pY2Ugc2VhcmNoYWJsZSBhbmQgZG93bmxvYWRhYmxlIHRhYmxlcw0KICAic3VtbWFyeXRvb2xzIiwNCiAgInBseXIiLCANCiAgInN0cmluZ3IiDQogICMgLCAuLi4NCikNCmlmICghcmVxdWlyZSgicGFjbWFuIikpIGluc3RhbGwucGFja2FnZXMoInBhY21hbiIpDQpwYWNtYW46OnBfbG9hZChjaGFyID0gcGFja2FnZXMpDQoNCiMgVGhlbWVzIGZvciBnZ3Bsb3QyIHBsb3RpbmcgKGhlcmUgdXNlZCBBUEEgc3R5bGUpDQp0aGVtZV9zZXQodGhlbWVfYXBhKCkpDQpgYGANCg0KYGBge3Igd29ya2luZ19kaXJlY3RvcnksIGluY2x1ZGUgPSBGQUxTRX0NCiMjIyBPLjQgUiBjb2RlIC0gVW5pY2UgYW5kIFJldGF0YXRlDQojIyMgUiBjb2RlIGZvciBzb3J0aW5nLCBpbnRlZ3JhdGluZyBhbmQgYW5hbHlzZXMgDQojIFRhc2sgb3V0cHV0IGZpbGVzOiANCiMgSUQsIGV4cGVyaW1lbnRhbCBjb25kaXRpb24gKCJvZ2xpbmRhIiAvICJlY3JhbiIpLCBjb25kaXRpb24gKCJpbnN0cnVjdG9yIiwgInNvbG8iKSwgdHlwZSBvZiB0YXNrICgidW5pYyIsICJyZXBldGF0IikNCndkIDwtICJDOi9Vc2Vycy9NaWhhaS9EZXNrdG9wL0VFR19PLjRjXzEvTy40YyAtIFBvc3RlciINCnNldHdkKHdkKQ0KYGBgDQoNCg0KPCEtLSBSZXBvcnQgLS0+DQoNCg0KIyBBcnJhbmdlIGZvbGRlcnMsIHNvcnQgZmlsZXMsIHJlYWQgYW5kIG1lcmdlDQoNCiMjIENyZWF0ZSBmb2xkZXJzIGJ5IGNvbmRpdGlvbnMsIGNvcHkgZmlsZXMgdG8gdGhlbQ0KDQpgYGB7ciBtYWtlZGlyX3NvcnRmaWxlcywgZXZhbD1GQUxTRX0NCiMgISEhIUVWQUwgPSBGQUxTRQ0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIFJlYWQgZmlsZSBuYW1lcyAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQpmaWxlX25hbWVzIDwtIGRpcihwYXR0ZXJuID0gIlxcLnhscyQiKQ0KIyMgaWYgYWJvdmUgaXNuJ3QgZ29vZCBlbm91Z2ggdHJ5IHRoZSBmb2xsb3dpbmc6DQojIGZpbGVfbmFtZXMgPC0gbGlzdC5maWxlcyh3ZCkNCiMgZmlsZV9uYW1lcyA8LSBzb3BfZmlsZXNbIWZpbGUuaW5mbyhzb3BfZmlsZXMpJGlzZGlyXSAgICMgZXhjbHVkZSBkaXJlY3Rvcmllcw0KIyBmaWxlX25hbWVzIDwtIHNvcF9maWxlc1tncmVwKCIueGxzIiwgc29wX2ZpbGVzLCBmaXhlZCA9IFRSVUUpXQ0KDQoNCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyBDcmVhdGUgZm9sZGVycyB3aXRoIENvbmRpdGlvbiBuYW1lcyAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCiMgdGhpcyBwYXJ0IG9mIHNjcmlwdCBtYXkgYmUgcmUtcnVuIGlmIGZpbGVzIGZyb20gd2QgYXJlIHVwZGF0ZWQNCmRpcl9uYW1lcyA8LSBjKCJVbmljX0NUUkxfSW5zdHIiLCAiVW5pY19DVFJMX1NvbG8iLCAiVW5pY19PR0xfSW5zdHIiLCAiVW5pY19PR0xfU29sbyIsDQogICAgICAgICAgICAgICJSZXBldGF0X0NUUkxfSW5zdHIiLCAiUmVwZXRhdF9DVFJMX1NvbG8iLCAiUmVwZXRhdF9PR0xfSW5zdHIiLCAiUmVwZXRhdF9PR0xfU29sbyIpDQogICAgICAgICAgICAgDQpmb3IoZGlyIGluIGRpcl9uYW1lcyl7DQogIGlmKCFkaXIuZXhpc3RzKGZpbGUucGF0aCh3ZCwgZGlyKSkpDQogIGRpci5jcmVhdGUoZmlsZS5wYXRoKHdkLCBkaXIpLCBzaG93V2FybmluZ3MgPSBGQUxTRSkNCn0NCg0KDQojIyMjIyMjIyMjIyMjIyMjIyMjIyMgVXNlIGZpbGUgbmFtZXMgdG8gc29ydCB0aGVtIHRvIGZvbGRlcnMgIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQpzb3J0X2ZpbGVzX3RvX2RpcnMgPC0gZnVuY3Rpb24od2QsIHBhdHRlcm4sIGRpcikgew0KICBjaGVja19wYXR0ZXJuIDwtIG91dGVyKGZpbGVfbmFtZXMsIHBhdHRlcm4sIHN0cmluZ3I6OnN0cl9kZXRlY3QpICAgICAgICAgICAgICAgIyBpZiBhbGwgVFJVRSBieWUgcm93IHRoZW4gaXQgaGFzIGZ1bGwgcGF0dGVybg0KICBpbmRleCA8LSB3aGljaChhcHBseShjaGVja19wYXR0ZXJuLCAxLCBmdW5jdGlvbih4KSBhbGwoeD09VFJVRSkpKSAgICAgICAgICAgICAgIyBnZXQgaW5kZXggb2YgZmlsZV9uYW1lcyB3aGVyZSBhbGwgYXJlIFRSVUUNCiAgc29ydGVkX2ZpbGVzIDwtIGZpbGVfbmFtZXNbaW5kZXhdICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgZ2V0IG5hbWVzIG9mIGZpbGVzIGZyb20gaW5kZXhlcw0KICANCiAgZm9yKGZpbGVzIGluIHNvcnRlZF9maWxlcykgeyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgY29weSB0aGUgZmlsZXMgdG8gY29ycmVzcG9uZGluZyBmb2xkZXINCiAgICBmaWxlLmNvcHkoZnJvbSA9IGZpbGUucGF0aCh3ZCwgZmlsZXMpLCB0byA9IGZpbGUucGF0aCh3ZCwgZGlyKSkNCiAgfSAgDQp9DQoNCnNvcnRfZmlsZXNfdG9fZGlycyh3ZCA9IHdkLCBwYXR0ZXJuID0gYygidW5pYyIsICJlY3JhbiIsICJpbnN0cnVjdG9yIiksIGRpciA9ICJVbmljX0NUUkxfSW5zdHIiKQ0Kc29ydF9maWxlc190b19kaXJzKHdkID0gd2QsIHBhdHRlcm4gPSBjKCJ1bmljIiwgImVjcmFuIiwgInNvbG8iKSwgZGlyID0gIlVuaWNfQ1RSTF9Tb2xvIikNCnNvcnRfZmlsZXNfdG9fZGlycyh3ZCA9IHdkLCBwYXR0ZXJuID0gYygidW5pYyIsICJvZ2xpbmRhIiwgImluc3RydWN0b3IiKSwgZGlyID0gIlVuaWNfT0dMX0luc3RyIikNCnNvcnRfZmlsZXNfdG9fZGlycyh3ZCA9IHdkLCBwYXR0ZXJuID0gYygidW5pYyIsICJvZ2xpbmRhIiwgInNvbG8iKSwgZGlyID0gIlVuaWNfT0dMX1NvbG8iKQ0KYGBgDQoNCg0KIyMgUmVhZGluZyB0aGUgZGF0YQ0KDQpgYGB7ciByYXdfcmVhZCwgaGlkZT1UUlVFfQ0KIyMjIyMjIyMjIyMjIFJlYWQgaW4gYWxsIHRoZSAueGxzIGZyb20gZm9sZGVycyBhbmQgbWVyZ2UgdGhlbSBpbiBkYXRhc2V0cyBuYW1lZCBhZnRlciBjb3JyZXNwb25kaW5nIGZvbGRlciAjIyMjIyMjIyMjIyMjIw0KIyB0aGlzIHBhcnQgb2Ygc2NyaXB0IG1heSBiZSByZS1ydW4gaWYgZmlsZXMgZnJvbSB3ZCBhcmUgdXBkYXRlZA0KIyBSRS1SVU4gRlJPTSBIRVJFIElGIEZPTERFUlMgQU5EIFNPUlRJTkcgV0FTIEFMUkVBRFkgRE9ORQ0Kd2QgPC0gIkM6L1VzZXJzL01paGFpL0Rlc2t0b3AvRUVHX08uNGNfMS9PLjRjIC0gUG9zdGVyL0RhdGUgU3R1ZGl1Ig0Kc2V0d2Qod2QpDQpmb2xkZXJzIDwtIGxpc3QuZmlsZXMod2QpDQpmb2xkZXJzIDwtIGZvbGRlcnNbZmlsZS5pbmZvKGZvbGRlcnMpJGlzZGlyXSAgICMgbHVhbSBkb2FyIGZvbGRlcmVsZQ0KZGF0YXNldG5hbWVzIDwtIE5VTEwNCg0KZm9yIChpIGluIDE6bGVuZ3RoKGZvbGRlcnMpKSB7DQogIGRhdGFzZXRuYW1lIDwtIGZvbGRlcnNbaV0NCiAgZGF0YXNldG5hbWVzIDwtIGMoZGF0YXNldG5hbWVzLCBkYXRhc2V0bmFtZSkNCiAgY3VycmVudF9kaXIgPC0gc2V0d2QoZmlsZS5wYXRoKHdkLCBmb2xkZXJzW2ldKSkNCiAgcHJpbnQocGFzdGUwKCJjdXJyZW50X2RpcjogIiwgY3VycmVudF9kaXIpKQ0KICANCiAgcGF0aHMgPC0gZGlyKHBhdHRlcm4gPSAiXFwueGxzJCIpDQogIG5hbWVzKHBhdGhzKSA8LSBiYXNlbmFtZShwYXRocykNCg0KICBhc3NpZ24oIHBhc3RlKGRhdGFzZXRuYW1lKSwgcGx5cjo6bGRwbHkocGF0aHMsIHJpbzo6aW1wb3J0KSApDQp9DQoNCnNldHdkKHdkKQ0KIyBkZXRhY2goInBhY2thZ2U6cGx5ciIsIHVubG9hZD1UUlVFKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgZGV0YWNoIHBseXIgYmVjYXVzZSBvZiBjb25mbGljdHMgd2l0aCBkcGx5cg0KYGBgDQoNCg0KIyMgQ2xlYW5pbmcgdGhlIGRhdGENCg0KYGBge3IgY2xlYW5fZGF0YSwgaGlkZT1UUlVFfQ0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIERhdGEgQ2xlYW5pbmcgIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQojIENoZWNrIGlmIGlkcyBoYXZlID4gMSByb3cgb2YgZGF0YSAoZW1wdHkgLnhscyBoYXZlIG9ubHkgMSByb3cpDQojIENhcmVmdWwhIFRoaXMgZnVuY3Rpb24gbW9kZmllcyB0aGUgZGF0YXNldHMgaW4gdGhlIGdsb2JhbCBlbnZpbnJvbm1lbnQNCmRlbGV0ZV9lbXB0eV9pZCA8LSBmdW5jdGlvbihkZil7DQogIGxpc3RfZW1wdHlfaWQgPC0gDQogICAgZGYgJT4lDQogICAgZHBseXI6Omdyb3VwX2J5KC5pZCkgJT4lDQogICAgZHBseXI6OnN1bW1hcmlzZShyb3dfY291bnQgPSBuKCkpICU+JQ0KICAgIGRwbHlyOjpyZW5hbWUoImVtcHR5X2lkIiA9IC5pZCkgJT4lDQogICAgbXV0YXRlKGRlbGV0ZV9pZCA9IGlmX2Vsc2Uocm93X2NvdW50IDwgMywgVFJVRSwgRkFMU0UpKSAlPiUNCiAgICBmaWx0ZXIoZGVsZXRlX2lkID09IFRSVUUpDQogIA0KICBkZl9tb2RpZiA8LSANCiAgICBkZiAlPiUNCiAgICBmaWx0ZXIoIS5pZCAlaW4lIGxpc3RfZW1wdHlfaWQkZW1wdHlfaWQpDQogIA0KICBpZighaWRlbnRpY2FsKGRmLCBkZl9tb2RpZikpew0KICAgIGRmIDwtIGRlcGFyc2Uoc3Vic3RpdHV0ZShkZikpDQogICAgY2F0KCJEZWxldGluZyBmcm9tICIsIHByaW50KGFzLm5hbWUoZGYpKSk7IHByaW50KGxpc3RfZW1wdHlfaWQpICAgICAgICAgICAgICAgICAgICAjIHByaW50IG91dCB3aGljaCBpZHMgYXJlIGRlbGV0ZWQgZnJvbSB3aGljaCBkYXRhc2V0DQogICAgYXNzaWduKGRmLCBkZl9tb2RpZiwgZW52aXIgPSBnbG9iYWxlbnYoKSkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGFzc2lnbiBtb2RpZmllZCBkZiB0byBvcmlnaW5hbCBkYXRhc2V0IGZyb20gR2xvYmFsDQogIH1lbHNlIGNhdCgiTm8gZW1wdHkgZGF0YXNldHMuIE5vdGhpbmcgdG8gZGVsZXRlIikNCn0NCg0KIyBBcHBseSBmdW5jdGlvbiB0byBhbGwgZGF0YXNldHMgKHRyaWNreSB0byBkbyBpbiBmb3IgbG9vcCBiZWNhdXNlIG9mIHN1cGVyIGFzc2lnbm1lbnQpDQpkZWxldGVfZW1wdHlfaWQoVW5pY19DVFJMX0luc3RyKQ0KZGVsZXRlX2VtcHR5X2lkKFVuaWNfQ1RSTF9Tb2xvKQ0KZGVsZXRlX2VtcHR5X2lkKFVuaWNfT0dMX0luc3RyKQ0KZGVsZXRlX2VtcHR5X2lkKFVuaWNfT0dMX1NvbG8pDQpgYGANCg0KDQojIyBFeGNsdWRlIFNBTV9yZXNwIGJhc2VkIG9uIFJUIG91dGxpZXJzDQoNCmBgYHtyIG5vb3V0bGllcl9kYXRhLCBldmFsPUZBTFNFfQ0KIyAhISEhRVZBTCA9IEZBTFNFDQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIEV4Y2x1ZGUgT3V0bGllcnMgYmFzZWQgb24gUlQgKGJ5IHN1YmplY3QgYW5kIHN0aW11bHVzIHR5cGUpICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KIyMgRE9OVCBSVU4gKHVubGVzcyBpdCBpcyBuZWVkZWQpIC0tLS0+IGV2YWw9RkFMU0UNCiMgRXhjbHVkZSBSVCBvdXRsaWVycyAoPS0gMlNEKSAtIGluc3RlYWQgb2Ygc2ltcGxlIGZpbHRlciwgbWFrZWluZyB0aGVtIE5BICBpcyBiZXR0ZXIgZm9yIHBhaXJlZCBjb21wYXJpc29uDQpyZW1vdmVfb3V0bGllcnMgPC0gZnVuY3Rpb24oZGYpIHsNCiAgZGZfbW9kaWYgPC0NCiAgICBkZiAlPiUNCiAgICBkcGx5cjo6Z3JvdXBfYnkoLmlkLCBgU3RpbXVsdXMgdHlwZWApICU+JSAgICAgICAgICAgICAgICAgICMgd2UgY291bGQgaGF2ZSBkb25lIGJlZm9yZTogIGRwbHlyOjpyZW5hbWUoIlN0aW1fdHlwZSIgPSBgU3RpbXVsdXMgdHlwZWApIA0KICAgIG11dGF0ZShTQU1fUmVzcCA9IGlmX2Vsc2UoYWJzKFNBTV9SVCAtIG1lYW4oU0FNX1JULCBuYS5ybT1UUlVFKSkgPiAyKnNkKFNBTV9SVCwgbmEucm09VFJVRSksIGFzLm51bWVyaWMoTkEpLCBTQU1fUmVzcCkpDQogIA0KICBpZighaWRlbnRpY2FsKGRmLCBkZl9tb2RpZikpew0KICAgIGRmIDwtIGRlcGFyc2Uoc3Vic3RpdHV0ZShkZikpDQogICAgY2F0KCJEZWxldGluZyBvdXRsaWVycyBmcm9tICIsIHByaW50KGFzLm5hbWUoZGYpKSk7ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgcHJpbnQgb3V0IGRhdGFzZXRzIHdoaWNoIGhhdmUgYmVlbiBtb2RpZmllZA0KICAgIGFzc2lnbihkZiwgZGZfbW9kaWYsIGVudmlyID0gZ2xvYmFsZW52KCkpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBhc3NpZ24gbW9kaWZpZWQgZGYgdG8gb3JpZ2luYWwgZGF0YXNldCBmcm9tIEdsb2JhbA0KICB9ZWxzZSBjYXQoIk5vIG91dGxpZXIiKQ0KfQ0KDQpyZW1vdmVfb3V0bGllcnMoVW5pY19DVFJMX0luc3RyKQ0KcmVtb3ZlX291dGxpZXJzKFVuaWNfQ1RSTF9Tb2xvKQ0KcmVtb3ZlX291dGxpZXJzKFVuaWNfT0dMX0luc3RyKQ0KcmVtb3ZlX291dGxpZXJzKFVuaWNfT0dMX1NvbG8pDQpgYGANCg0KDQojIyBUZXN0IGlmIGRhdGFzZXRzIGhhdmUgc2FtZSBjb2x1bW5zDQoNCmBgYHtyIHRlc3RfY29sc30NCnVuaWNfZGZfb2JqIDwtIG1nZXQoYygiVW5pY19DVFJMX0luc3RyIiwgIlVuaWNfQ1RSTF9Tb2xvIiwgIlVuaWNfT0dMX0luc3RyIiwgIlVuaWNfT0dMX1NvbG8iKSkNCnVuaWNfZGZfb2JqIDwtbGFwcGx5KHVuaWNfZGZfb2JqLCBjb2xuYW1lcykNCm91dGVyKHVuaWNfZGZfb2JqLCB1bmljX2RmX29iaiwgVmVjdG9yaXplKGlkZW50aWNhbCkpICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBpZiBhbGwgYXJlIFRSVUUsIGFsbCBkZiBoYXZlIHNhbWUgY29sdW1ucw0KYGBgDQoNCjxicj4NCjxicj4NCg0KDQojIEFuYWx5c2lzIC0gVU5JQ0UNCg0KIyMgRGVzY3JpcHRpdmVzDQoNCmBgYHtyIGRlc2NfdW5pY2V9DQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIEFuYWx5c2VzIC0gVU5JQ0UgIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCiMjIERlc2NyaXB0aXZlcyBieSBjb25kaXRpb24gZGF0YXNldA0KZGVzY3JpcHRpdmVfZnVuYyA8LSBmdW5jdGlvbihkZiwgU3RpbV90eXBlLCBCeV9JRCA9IEZBTFNFKXsNCiAgZGZfbmFtZSA8LSBkZXBhcnNlKHN1YnN0aXR1dGUoZGYpKQ0KICBzdXBwcmVzc1dhcm5pbmdzKHsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBpZiBhbGwgTkFzIGluIFNBTV9SZXNwLCBOYU5zIGFuZCBJbmZzIHdpbGwgYmUgcHJvZHVjZWQNCiAgICBkZl9tb2RpZiA8LSANCiAgICAgIGRmICU+JQ0KICAgICAgZHBseXI6OnJlbmFtZSgiSUQiID0gLmlkKSAlPiUNCiAgICAgIHNlbGVjdF9hbGwofmdzdWIoIlxccyt8XFwuIiwgIl8iLCAuKSkgJT4lICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgcmVwbGFjZXMgYmxhbmNrcyB3aXRoICJfIiBpbiBjb2xuYW1lcyANCiAgICAgIGZpbHRlcihTdGltdWx1c190eXBlID09IFN0aW1fdHlwZSkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgZmlsdGVyIGJ5IHN0aW11bHVzIHR5cGUNCiAgICAgIA0KICAgIGlmKGlzVFJVRShCeV9JRCkpeyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBpZiB0cnVlIGdyb3VwIGJ5IGlkLCBpZiBub3QgcmV0dXJuIGRlc2NyaXB0aXZlcyBmb3IgYWxsIGlkcw0KICAgICAgYnlfaWRfdGV4dCA8LSAiIGJ5IHN1YmplY3QiDQogICAgICBkZl9tb2RpZiAlPiUNCiAgICAgIGRwbHlyOjpncm91cF9ieShJRCkgJT4lDQogICAgICB0aWR5c3RhdHM6OmRlc2NyaWJlX2RhdGEoU0FNX1Jlc3AsIFNBTV9SVCwgbmEucm0gPSBUUlVFKSAlPiUNCiAgICAgICAga25pdHI6OmthYmxlKGNhcHRpb24gPSBwYXN0ZShhcy5uYW1lKGRmX25hbWUpLCAiICIsIFN0aW1fdHlwZSwgYnlfaWRfdGV4dCksIGZvcm1hdCA9ICJwYW5kb2MiLCBkaWdpdHMgPSAyKQ0KICAgIH1lbHNleyANCiAgICAgIGJ5X2lkX3RleHQgPC0gIiBhbGwgc3ViamVjdHMiDQogICAgICBkZl9tb2RpZiAlPiUNCiAgICAgIHVuZ3JvdXAoKSAlPiUgIA0KICAgICAgdGlkeXN0YXRzOjpkZXNjcmliZV9kYXRhKFNBTV9SZXNwLCBTQU1fUlQsIG5hLnJtID0gVFJVRSkgJT4lDQogICAgICAgIGtuaXRyOjprYWJsZShjYXB0aW9uID0gcGFzdGUoYXMubmFtZShkZl9uYW1lKSwgIiAiLCBTdGltX3R5cGUsIGJ5X2lkX3RleHQpLCBmb3JtYXQgPSAicGFuZG9jIiwgZGlnaXRzID0gMikNCiAgICB9DQogIH0pDQp9ICANCg0KDQpkZXNjcmlwdGl2ZV9mdW5jKGRmID0gVW5pY19DVFJMX0luc3RyLCBTdGltX3R5cGUgPSAibmVnYXRpdiIsIEJ5X0lEID0gRkFMU0UpICAgICAgICAgICAjIE5lZ2F0aXZlIC0gR2VuZXJhbA0KZGVzY3JpcHRpdmVfZnVuYyhkZiA9IFVuaWNfQ1RSTF9Tb2xvLCBTdGltX3R5cGUgPSAibmVnYXRpdiIsIEJ5X0lEID0gRkFMU0UpDQpkZXNjcmlwdGl2ZV9mdW5jKGRmID0gVW5pY19PR0xfSW5zdHIsIFN0aW1fdHlwZSA9ICJuZWdhdGl2IiwgQnlfSUQgPSBGQUxTRSkNCmRlc2NyaXB0aXZlX2Z1bmMoZGYgPSBVbmljX09HTF9Tb2xvLCBTdGltX3R5cGUgPSAibmVnYXRpdiIsIEJ5X0lEID0gRkFMU0UpDQoNCmRlc2NyaXB0aXZlX2Z1bmMoZGYgPSBVbmljX0NUUkxfSW5zdHIsIFN0aW1fdHlwZSA9ICJuZWdhdGl2IiwgQnlfSUQgPSBUUlVFKSAgICAgICAgICAgICMgTmVnYXRpdmUgLSBieSBpZA0KZGVzY3JpcHRpdmVfZnVuYyhkZiA9IFVuaWNfQ1RSTF9Tb2xvLCBTdGltX3R5cGUgPSAibmVnYXRpdiIsIEJ5X0lEID0gVFJVRSkNCmRlc2NyaXB0aXZlX2Z1bmMoZGYgPSBVbmljX09HTF9JbnN0ciwgU3RpbV90eXBlID0gIm5lZ2F0aXYiLCBCeV9JRCA9IFRSVUUpDQpkZXNjcmlwdGl2ZV9mdW5jKGRmID0gVW5pY19PR0xfU29sbywgU3RpbV90eXBlID0gIm5lZ2F0aXYiLCBCeV9JRCA9IFRSVUUpDQoNCmRlc2NyaXB0aXZlX2Z1bmMoZGYgPSBVbmljX0NUUkxfSW5zdHIsIFN0aW1fdHlwZSA9ICJwb3ppdGl2IiwgQnlfSUQgPSBGQUxTRSkgICAgICAgICAgICMgUG9zaXRpdmUgLSBHZW5lcmFsDQpkZXNjcmlwdGl2ZV9mdW5jKGRmID0gVW5pY19DVFJMX1NvbG8sIFN0aW1fdHlwZSA9ICJwb3ppdGl2IiwgQnlfSUQgPSBGQUxTRSkNCmRlc2NyaXB0aXZlX2Z1bmMoZGYgPSBVbmljX09HTF9JbnN0ciwgU3RpbV90eXBlID0gInBveml0aXYiLCBCeV9JRCA9IEZBTFNFKQ0KZGVzY3JpcHRpdmVfZnVuYyhkZiA9IFVuaWNfT0dMX1NvbG8sIFN0aW1fdHlwZSA9ICJwb3ppdGl2IiwgQnlfSUQgPSBGQUxTRSkNCg0KZGVzY3JpcHRpdmVfZnVuYyhkZiA9IFVuaWNfQ1RSTF9JbnN0ciwgU3RpbV90eXBlID0gInBveml0aXYiLCBCeV9JRCA9IFRSVUUpICAgICAgICAgICAgIyBQb3NpdGl2ZSAtIGJ5IGlkDQpkZXNjcmlwdGl2ZV9mdW5jKGRmID0gVW5pY19DVFJMX1NvbG8sIFN0aW1fdHlwZSA9ICJwb3ppdGl2IiwgQnlfSUQgPSBUUlVFKQ0KZGVzY3JpcHRpdmVfZnVuYyhkZiA9IFVuaWNfT0dMX0luc3RyLCBTdGltX3R5cGUgPSAicG96aXRpdiIsIEJ5X0lEID0gVFJVRSkNCmRlc2NyaXB0aXZlX2Z1bmMoZGYgPSBVbmljX09HTF9Tb2xvLCBTdGltX3R5cGUgPSAicG96aXRpdiIsIEJ5X0lEID0gVFJVRSkNCg0KZGVzY3JpcHRpdmVfZnVuYyhkZiA9IFVuaWNfQ1RSTF9JbnN0ciwgU3RpbV90eXBlID0gIm5ldXRydSIsIEJ5X0lEID0gRkFMU0UpICAgICAgICAgICAjIE5ldXRyYWwgLSBHZW5lcmFsDQpkZXNjcmlwdGl2ZV9mdW5jKGRmID0gVW5pY19DVFJMX1NvbG8sIFN0aW1fdHlwZSA9ICJuZXV0cnUiLCBCeV9JRCA9IEZBTFNFKQ0KZGVzY3JpcHRpdmVfZnVuYyhkZiA9IFVuaWNfT0dMX0luc3RyLCBTdGltX3R5cGUgPSAibmV1dHJ1IiwgQnlfSUQgPSBGQUxTRSkNCmRlc2NyaXB0aXZlX2Z1bmMoZGYgPSBVbmljX09HTF9Tb2xvLCBTdGltX3R5cGUgPSAibmV1dHJ1IiwgQnlfSUQgPSBGQUxTRSkNCg0KZGVzY3JpcHRpdmVfZnVuYyhkZiA9IFVuaWNfQ1RSTF9JbnN0ciwgU3RpbV90eXBlID0gIm5ldXRydSIsIEJ5X0lEID0gVFJVRSkgICAgICAgICAgICAjIE5ldXRyYWwgLSBieSBpZA0KZGVzY3JpcHRpdmVfZnVuYyhkZiA9IFVuaWNfQ1RSTF9Tb2xvLCBTdGltX3R5cGUgPSAibmV1dHJ1IiwgQnlfSUQgPSBUUlVFKQ0KZGVzY3JpcHRpdmVfZnVuYyhkZiA9IFVuaWNfT0dMX0luc3RyLCBTdGltX3R5cGUgPSAibmV1dHJ1IiwgQnlfSUQgPSBUUlVFKQ0KZGVzY3JpcHRpdmVfZnVuYyhkZiA9IFVuaWNfT0dMX1NvbG8sIFN0aW1fdHlwZSA9ICJuZXV0cnUiLCBCeV9JRCA9IFRSVUUpDQpgYGANCg0KDQojIyBNZXJnZQ0KDQpgYGB7ciBtZXJnZWRfdW5pY2VfZGF0YSwgaGlkZT1UUlVFfQ0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIE1lcmdlIGNvbmRpdGlvbiBkYXRhc2V0ICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KIyBNdXN0IGZpcnN0IHJlbmFtZSAuaWQgdG8gSUQgaW4gb2RlciB0byBoYXZlIC5pZCBmb3IgZGYgbmFtZXMNCklEX3JlbmFtZSA8LSBmdW5jdGlvbihkZil7DQogIGlmKCIuaWQiICVpbiUgY29sbmFtZXMoZGYpKSB7DQogICAgZGZfbW9kaWYgPC0gDQogICAgICBkZiAlPiUNCiAgICAgIGRwbHlyOjpyZW5hbWUoIklEIiA9IC5pZCkNCiAgICBkZiA8LSBkZXBhcnNlKHN1YnN0aXR1dGUoZGYpKQ0KICAgIGNhdCgiQ2hhbmdlZCAuaWQgdG8gSUQgZm9yOiAiLCBhcy5uYW1lKGRmKSkNCiAgICBhc3NpZ24oZGYsIGRmX21vZGlmLCBlbnZpciA9IGdsb2JhbGVudigpKQ0KICB9ICANCn0NCg0KSURfcmVuYW1lKFVuaWNfQ1RSTF9JbnN0cikNCklEX3JlbmFtZShVbmljX0NUUkxfU29sbykNCklEX3JlbmFtZShVbmljX09HTF9JbnN0cikNCklEX3JlbmFtZShVbmljX09HTF9Tb2xvKQ0KDQojIE1lcmdlIGludG8gb25lIGRmDQpsaXN0X2RmX21lcmdlIDwtIGxpc3QoVW5pY19DVFJMX0luc3RyLCBVbmljX0NUUkxfU29sbywgVW5pY19PR0xfSW5zdHIsIFVuaWNfT0dMX1NvbG8pDQpuYW1lcyhsaXN0X2RmX21lcmdlKSA8LSBjKCJVbmljX0NUUkxfSW5zdHIiLCAiVW5pY19DVFJMX1NvbG8iLCAiVW5pY19PR0xfSW5zdHIiLCAiVW5pY19PR0xfU29sbyIpDQpVbmljX21lcmdlZCA8LSBwbHlyOjpsZHBseShsaXN0X2RmX21lcmdlLCBkYXRhLmZyYW1lKSAgICAgICAgICAgICAgICAgICAgIyBhbHNvIHdvcmtzIGZvciB0aGlzIGpvYiBiaW5kX3Jvd3MobGlzdF9kZl9tZXJnZSwgLmlkID0gImNvbHVtbl9sYWJlbCIpDQpgYGANCg0KDQojIyBBbmFseXNlcyBvbiBtZXJnZWQgKEFub3ZhICYgcG9zdC1ob2MpDQoNCmBgYHtyIGFub3ZhX3VuaWNlLCByZXN1bHRzPSdhc2lzJ30NCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyBBbmFseXNlcyBvbiBNZXJnZWQgIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KIyMgSnVzdCBhIFRlc3QgDQogICMgVW5pY19tZXJnZWRfc3ByZWFkX05lZyA8LSANCiAgIyAgIFVuaWNfbWVyZ2VkICU+JQ0KICAjICAgZmlsdGVyKCFpcy5uYShTQU1fUmVzcCkpICU+JSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHNvbWUgZmlsZXMgaGFkIG9ubHkgTkEgb24gU0FNX1Jlc3AgYW5kIFNBTV9SVA0KICAjICAgc2VsZWN0KC5pZCwgSUQsIFN1YmpfaWQsIA0KICAjICAgICAgICAgIFN0aW11bGkub3JkZXIsIE1hcmtlclN0aW11bGksIFN0aW11bHVzLnR5cGUsIA0KICAjICAgICAgICAgIFNBTV9SZXNwLCBTQU1fUlQpICU+JQ0KICAjICAgZmlsdGVyKFN0aW11bHVzLnR5cGUgPT0gIm5lZ2F0aXYiKSAlPiUgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGRvbnQgZm9yZ2V0IHRvIHBpY2sgc3R5bXVsdXMgdHlwZQ0KICAjICAgc3ByZWFkKC5pZCwgU0FNX1Jlc3ApDQogICMgDQogICMgdC50ZXN0KFVuaWNfbWVyZ2VkX3NwcmVhZF9OZWckVW5pY19DVFJMX0luc3RyLCBVbmljX21lcmdlZF9zcHJlYWRfTmVnJFVuaWNfQ1RSTF9Tb2xvLCBuYS5ybSA9IFRSVUUpDQogICMgdC50ZXN0KFVuaWNfbWVyZ2VkX3NwcmVhZF9OZWckVW5pY19PR0xfSW5zdHIsIFVuaWNfbWVyZ2VkX3NwcmVhZF9OZWckVW5pY19PR0xfU29sbywgbmEucm0gPSBUUlVFKQ0KICAjIHQudGVzdChVbmljX21lcmdlZF9zcHJlYWRfTmVnJFVuaWNfT0dMX0luc3RyLCBVbmljX21lcmdlZF9zcHJlYWRfTmVnJFVuaWNfQ1RSTF9JbnN0ciwgbmEucm0gPSBUUlVFKQ0KICAjIHQudGVzdChVbmljX21lcmdlZF9zcHJlYWRfTmVnJFVuaWNfT0dMX1NvbG8sIFVuaWNfbWVyZ2VkX3NwcmVhZF9OZWckVW5pY19DVFJMX1NvbG8sIG5hLnJtID0gVFJVRSkNCg0KIyMgRnVuY3Rpb24gcHJlcGFpciBkYXRhIGZvciBhbmFseXNlcw0KcHJlcGFpcmVfbWVyZ2VkX2Z1bmMgPC0gZnVuY3Rpb24oU3RpbV90eXBlKXsNCiAgVW5pY19tZXJnZWQgJT4lDQogICAgZmlsdGVyKCFpcy5uYShTQU1fUmVzcCkpICU+JSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHNvbWUgZmlsZXMgaGFkIG9ubHkgTkEgb24gU0FNX1Jlc3AgYW5kIFNBTV9SVA0KICAgIHNlbGVjdCguaWQsIElELCBTdWJqX2lkLCANCiAgICAgICAgICAgU3RpbXVsaS5vcmRlciwgTWFya2VyU3RpbXVsaSwgU3RpbXVsdXMudHlwZSwgDQogICAgICAgICAgIFNBTV9SZXNwLCBTQU1fUlQpICU+JQ0KICAgIGRwbHlyOjpyZW5hbWUoQ29uZCA9IC5pZCkgJT4lIA0KICAgIGZpbHRlcihTdGltdWx1cy50eXBlID09IFN0aW1fdHlwZSkgJT4lICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBkb250IGZvcmdldCB0byBwaWNrIHN0eW11bHVzIHR5cGUNCiAgICBtdXRhdGUoQ29uZCA9IGFzLmZhY3RvcihDb25kKSkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgdHVuciB0byBmYWN0b3IgZm9yIGFvdiBmYW1pbHkgZnVuY3Rpb25zDQp9DQoNClVuaWNfbWVyZ2VkX05lZyA8LSBwcmVwYWlyZV9tZXJnZWRfZnVuYygibmVnYXRpdiIpDQpVbmljX21lcmdlZF9OZXUgPC0gcHJlcGFpcmVfbWVyZ2VkX2Z1bmMoIm5ldXRydSIpDQpVbmljX21lcmdlZF9Qb3ogPC0gcHJlcGFpcmVfbWVyZ2VkX2Z1bmMoInBveml0aXYiKQ0KDQoNCiMjIEFub3ZhIGFuZCBQb3N0LUhvYyAgLSBORUdBVElWDQojIFN0aW11bHVzIHR5cGUNCmNhdCgiIyMjIE5lZ2F0aXYiKQ0KDQojIE5vcm1hbGl0eQ0KY2F0KCIjIyMjIE5vcm1hbGl0eSBUZXN0IikNClVuaWNfbWVyZ2VkX05lZyAlPiUNCiAgc2VsZWN0KFNBTV9SZXNwKSAlPiUgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgbXVzdCBzZWxlY3QgdmFyaWFibGVzIG91dHNpZGUgZnVuY3Rpb24gDQogIHRhZGFhdG9vbGJveDo6dGFkYWFfbm9ybXRlc3QobWV0aG9kID0gInNoYXBpcm8iKSAgICAgICAgICAgICAgICAgICAgICAgICAjICwgcHJpbnQgPSAibWFya2Rvd24iICBmb3IgTm90ZWJvb2sNCg0KIyBMZXZlbmUgVGVzdCAocD4uMDUgPSBob21vZ2VuZWl0eSBvZiB2YXJpYW5jZXMpDQpjYXQoIiMjIyMgTGV2ZW5lIFRlc3QiKQ0KVW5pY19tZXJnZWRfTmVnICU+JQ0KICB0YWRhYXRvb2xib3g6OnRhZGFhX2xldmVuZShkYXRhID0gLiwgU0FNX1Jlc3AgfiBDb25kKSAgICAgICAgICAgICAgICAgICAgIyAsIHByaW50ID0gIm1hcmtkb3duIiAgZm9yIE5vdGVib29rDQoNCiMgQW5vdmENCmNhdCgiIyMjIyBBbm92YSIpDQpVbmljX21lcmdlZF9OZWcgJT4lDQogICNkbyhicm9vbTo6Z2xhbmNlKGFvdiguJFNBTV9SZXNwIH4gLiRDb25kKSkpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHJlZ3VsYXIgYW5vdmEgZG8oYnJvb206OnRpZHkoYW92KC4kU0FNX1Jlc3AgfiAuJENvbmQpKSkNCiAgdGFkYWF0b29sYm94Ojp0YWRhYV9hb3YoZGF0YSA9IC4sIFNBTV9SZXNwIH4gQ29uZCwgdHlwZSA9IDEpICAgICAgICAgICAgICMgLCBwcmludCA9ICJtYXJrZG93biIgIGZvciBOb3RlYm9vaw0KDQojIFBvc3QtSG9jIA0KY2F0KCIjIyMjIFBvc3QtSG9jIEdhbWVzIEhvd2VsbCIpDQpVbmljX21lcmdlZF9OZWcgJT4lDQogICMgVHVrZXkgZm9yIGVxdWFsIHZhcmlhbmNlIA0KICB0YWRhYXRvb2xib3g6OnRhZGFhX3BhaXJ3aXNlX3R1a2V5KGRhdGEgPSAuLCBTQU1fUmVzcCwgQ29uZCkgICAgICAgICAgICAgIyAsIHByaW50ID0gIm1hcmtkb3duIiAgZm9yIE5vdGVib29rDQogICMgR2FtZXMgSG93ZWxsIGRvZXMgbm90IGFzc3VtZSBlcXVhbCB2YXJpYW5jZXMNCiAgI3RhZGFhdG9vbGJveDo6dGFkYWFfcGFpcndpc2VfZ2goZGF0YSA9IC4sIFNBTV9SZXNwLCBDb25kKSAgICAgICAgICAgICAgICAjICwgcHJpbnQgPSAibWFya2Rvd24iICBmb3IgTm90ZWJvb2sNCg0KDQojIyBBbm92YSBhbmQgUG9zdC1Ib2MgIC0gTkVVVFJVDQojIFN0aW11bHVzIHR5cGUNCmNhdCgiIyMjIE5ldXRydSIpDQoNCiMgTm9ybWFsaXR5DQpjYXQoIiMjIyMgTm9ybWFsaXR5IFRlc3QiKQ0KVW5pY19tZXJnZWRfTmV1ICU+JQ0KICBzZWxlY3QoU0FNX1Jlc3ApICU+JSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBtdXN0IHNlbGVjdCB2YXJpYWJsZXMgb3V0c2lkZSBmdW5jdGlvbiANCiAgdGFkYWF0b29sYm94Ojp0YWRhYV9ub3JtdGVzdChtZXRob2QgPSAic2hhcGlybyIpICAgICAgICAgICAgICAgICAgICAgICAgICMgLCBwcmludCA9ICJtYXJrZG93biIgIGZvciBOb3RlYm9vaw0KDQojIExldmVuZSBUZXN0IChwPi4wNSA9IGhvbW9nZW5laXR5IG9mIHZhcmlhbmNlcykNCmNhdCgiIyMjIyBMZXZlbmUgVGVzdCIpDQpVbmljX21lcmdlZF9OZXUgJT4lDQogIHRhZGFhdG9vbGJveDo6dGFkYWFfbGV2ZW5lKGRhdGEgPSAuLCBTQU1fUmVzcCB+IENvbmQpICAgICAgICAgICAgICAgICAgICAjICwgcHJpbnQgPSAibWFya2Rvd24iICBmb3IgTm90ZWJvb2sNCg0KIyBBbm92YQ0KY2F0KCIjIyMjIEFub3ZhIikNClVuaWNfbWVyZ2VkX05ldSAlPiUNCiAgI2RvKGJyb29tOjpnbGFuY2UoYW92KC4kU0FNX1Jlc3AgfiAuJENvbmQpKSkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgcmVndWxhciBhbm92YSBkbyhicm9vbTo6dGlkeShhb3YoLiRTQU1fUmVzcCB+IC4kQ29uZCkpKQ0KICB0YWRhYXRvb2xib3g6OnRhZGFhX2FvdihkYXRhID0gLiwgU0FNX1Jlc3AgfiBDb25kLCB0eXBlID0gMSkgICAgICAgICAgICAgIyAsIHByaW50ID0gIm1hcmtkb3duIiAgZm9yIE5vdGVib29rDQoNCiMgUG9zdC1Ib2MgDQpjYXQoIiMjIyMgUG9zdC1Ib2MgR2FtZXMgSG93ZWxsIikNClVuaWNfbWVyZ2VkX05ldSAlPiUNCiAgIyBUdWtleSBmb3IgZXF1YWwgdmFyaWFuY2UgDQogIHRhZGFhdG9vbGJveDo6dGFkYWFfcGFpcndpc2VfdHVrZXkoZGF0YSA9IC4sIFNBTV9SZXNwLCBDb25kKSAgICAgICAgICAgICAjICwgcHJpbnQgPSAibWFya2Rvd24iICBmb3IgTm90ZWJvb2sNCiAgIyBHYW1lcyBIb3dlbGwgZG9lcyBub3QgYXNzdW1lIGVxdWFsIHZhcmlhbmNlcw0KICAjdGFkYWF0b29sYm94Ojp0YWRhYV9wYWlyd2lzZV9naChkYXRhID0gLiwgU0FNX1Jlc3AsIENvbmQpICAgICAgICAgICAgICAgICMgLCBwcmludCA9ICJtYXJrZG93biIgIGZvciBOb3RlYm9vaw0KDQoNCiMjIEFub3ZhIGFuZCBQb3N0LUhvYyAgLSBQT1pJVElWDQojIFN0aW11bHVzIHR5cGUNCmNhdCgiIyMjIFBveml0aXYiKQ0KDQojIE5vcm1hbGl0eQ0KY2F0KCIjIyMjIE5vcm1hbGl0eSBUZXN0IikNClVuaWNfbWVyZ2VkX1BveiAlPiUNCiAgc2VsZWN0KFNBTV9SZXNwKSAlPiUgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgbXVzdCBzZWxlY3QgdmFyaWFibGVzIG91dHNpZGUgZnVuY3Rpb24gDQogIHRhZGFhdG9vbGJveDo6dGFkYWFfbm9ybXRlc3QobWV0aG9kID0gInNoYXBpcm8iKSAgICAgICAgICAgICAgICAgICAgICAgICAjICwgcHJpbnQgPSAibWFya2Rvd24iICBmb3IgTm90ZWJvb2sNCg0KIyBMZXZlbmUgVGVzdCAocD4uMDUgPSBob21vZ2VuZWl0eSBvZiB2YXJpYW5jZXMpDQpjYXQoIiMjIyMgTGV2ZW5lIFRlc3QiKQ0KVW5pY19tZXJnZWRfUG96ICU+JQ0KICB0YWRhYXRvb2xib3g6OnRhZGFhX2xldmVuZShkYXRhID0gLiwgU0FNX1Jlc3AgfiBDb25kKSAgICAgICAgICAgICAgICAgICAgIyAsIHByaW50ID0gIm1hcmtkb3duIiAgZm9yIE5vdGVib29rDQoNCiMgQW5vdmENCmNhdCgiIyMjIyBBbm92YSIpDQpVbmljX21lcmdlZF9Qb3ogJT4lDQogICNkbyhicm9vbTo6Z2xhbmNlKGFvdiguJFNBTV9SZXNwIH4gLiRDb25kKSkpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHJlZ3VsYXIgYW5vdmEgZG8oYnJvb206OnRpZHkoYW92KC4kU0FNX1Jlc3AgfiAuJENvbmQpKSkNCiAgdGFkYWF0b29sYm94Ojp0YWRhYV9hb3YoZGF0YSA9IC4sIFNBTV9SZXNwIH4gQ29uZCwgdHlwZSA9IDEpICAgICAgICAgICAgICMgLCBwcmludCA9ICJtYXJrZG93biIgIGZvciBOb3RlYm9vaw0KDQojIFBvc3QtSG9jIA0KY2F0KCIjIyMjIFBvc3QtSG9jIEdhbWVzIEhvd2VsbCIpDQpVbmljX21lcmdlZF9Qb3ogJT4lDQogICMgVHVrZXkgZm9yIGVxdWFsIHZhcmlhbmNlIA0KICB0YWRhYXRvb2xib3g6OnRhZGFhX3BhaXJ3aXNlX3R1a2V5KGRhdGEgPSAuLCBTQU1fUmVzcCwgQ29uZCkgICAgICAgICAgICAgIyAsIHByaW50ID0gIm1hcmtkb3duIiAgZm9yIE5vdGVib29rDQogICMgR2FtZXMgSG93ZWxsIGRvZXMgbm90IGFzc3VtZSBlcXVhbCB2YXJpYW5jZXMNCiAgI3RhZGFhdG9vbGJveDo6dGFkYWFfcGFpcndpc2VfZ2goZGF0YSA9IC4sIFNBTV9SZXNwLCBDb25kKSAgICAgICAgICAgICAgICAjICwgcHJpbnQgPSAibWFya2Rvd24iICBmb3IgTm90ZWJvb2sNCmBgYA0KDQoNCiMjIFBsb3RzIHdpdGggcCB2YWx1ZXMNCmBgYHtyIHBsb3RfdW5pY2UsIGZpZy5oZWlnaHQ9N30NCiMgYnkgZGF0YXNldA0KZ2dwbG90KFVuaWNfbWVyZ2VkLCBhZXMoeCA9IFN0aW11bHVzLnR5cGUsIHkgPSBTQU1fUmVzcCkpICsNCiAgZ2VvbV9ib3hwbG90KCkgKw0KICBzdGF0X3N1bW1hcnkoZnVuLmRhdGEgPSBtZWFuX3NlLCAgY29sb3VyID0gImRhcmtyZWQiKSArDQogIHhsYWIoIiIpICsNCiAgZmFjZXRfd3JhcCh+LmlkKSArDQogIGdncHVicjo6c3RhdF9jb21wYXJlX21lYW5zKG1ldGhvZCA9ICJ0LnRlc3QiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSAicC5zaWduaWYiLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyB0byBhdm9pZCBzY2llbnRpZmljIG5vdGF0aW9uIG9mIHZlcnkgc21hbGwgcC12YWx1ZXMNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI3BhaXJlZCA9IFRSVUUsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb21wYXJpc29ucyA9IGxpc3QoYygibmVnYXRpdiIsICJuZXV0cnUiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGMoIm5ldXRydSIsICJwb3ppdGl2IiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjKCJuZWdhdGl2IiwgInBveml0aXYiKSkpICANCg0KIyBieSBTdGltdWx1cyB0eXBlDQpnZ3Bsb3QoVW5pY19tZXJnZWQsIGFlcyh4ID0gLmlkLCB5ID0gU0FNX1Jlc3ApKSArDQogIGdlb21fYm94cGxvdCgpICsNCiAgc3RhdF9zdW1tYXJ5KGZ1bi5kYXRhID0gbWVhbl9zZSwgIGNvbG91ciA9ICJkYXJrcmVkIikgKw0KICB4bGFiKCIiKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSkpICsNCiAgZmFjZXRfd3JhcCh+U3RpbXVsdXMudHlwZSkgKw0KICBnZ3B1YnI6OnN0YXRfY29tcGFyZV9tZWFucyhtZXRob2QgPSAidC50ZXN0IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSAicC5mb3JtYXQiLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBmb3JtYXRlZCBwLXZhbHVlcw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjcGFpcmVkID0gVFJVRSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbXBhcmlzb25zID0gbGlzdChjKCJVbmljX0NUUkxfSW5zdHIiLCAiVW5pY19DVFJMX1NvbG8iKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGMoIlVuaWNfQ1RSTF9JbnN0ciIsICJVbmljX09HTF9JbnN0ciIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYygiVW5pY19DVFJMX1NvbG8iLCAiVW5pY19PR0xfSW5zdHIiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGMoIlVuaWNfQ1RSTF9Tb2xvIiwgIlVuaWNfT0dMX1NvbG8iKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGMoIlVuaWNfT0dMX0luc3RyIiwgIlVuaWNfT0dMX1NvbG8iKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGMoIlVuaWNfQ1RSTF9JbnN0ciIsICJVbmljX09HTF9Tb2xvIikpKSANCg0KDQojIGRyb3AgdG8gQ1RSTCB2cyBPR0wgLSBieSBTdGltdWx1cyB0eXBlDQpVbmljX21lcmdlZCAlPiUNCiAgbXV0YXRlKC5pZCA9IGNhc2Vfd2hlbiguaWQgJWluJSBjKCJVbmljX0NUUkxfSW5zdHIiLCAiVW5pY19DVFJMX1NvbG8iKSB+ICJVbmljX0NUUkwiLA0KICAgICAgICAgICAgICAgICAgICAgICAgIC5pZCAlaW4lIGMoIlVuaWNfT0dMX0luc3RyIiwgIlVuaWNfT0dMX1NvbG8iKSB+ICJVbmljX09HTCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+IGFzLmNoYXJhY3RlciguaWQpKSkgJT4lDQogICAgZ2dwbG90KGFlcyh4ID0gLmlkLCB5ID0gU0FNX1Jlc3ApKSArDQogICAgZ2VvbV9ib3hwbG90KCkgKw0KICAgIHN0YXRfc3VtbWFyeShmdW4uZGF0YSA9IG1lYW5fc2UsICBjb2xvdXIgPSAiZGFya3JlZCIpICsNCiAgICB4bGFiKCIiKSArDQogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxKSkgKw0KICAgIGZhY2V0X3dyYXAoflN0aW11bHVzLnR5cGUpICsNCiAgICBnZ3B1YnI6OnN0YXRfY29tcGFyZV9tZWFucyhtZXRob2QgPSAidC50ZXN0IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYWJlbCA9ICJwLmZvcm1hdCIsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGZvcm1hdGVkIHAtdmFsdWVzDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgI3BhaXJlZCA9IFRSVUUsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbXBhcmlzb25zID0gbGlzdChjKCJVbmljX0NUUkwiLCAiVW5pY19PR0wiKSkpICAgICAgICAgIA0KDQojIGRyb3AgdG8gSW5zdHIgdnMgU29sbyAtIGJ5IFN0aW11bHVzIHR5cGUNClVuaWNfbWVyZ2VkICU+JQ0KICBtdXRhdGUoLmlkID0gY2FzZV93aGVuKC5pZCAlaW4lIGMoIlVuaWNfQ1RSTF9JbnN0ciIsICJVbmljX09HTF9JbnN0ciIpIH4gIlVuaWNfSW5zdHIiLA0KICAgICAgICAgICAgICAgICAgICAgICAgIC5pZCAlaW4lIGMoIlVuaWNfQ1RSTF9Tb2xvIiwgIlVuaWNfT0dMX1NvbG8iKSB+ICJVbmljX1NvbG8iLA0KICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiBhcy5jaGFyYWN0ZXIoLmlkKSkpICU+JQ0KICAgIGdncGxvdChhZXMoeCA9IC5pZCwgeSA9IFNBTV9SZXNwKSkgKw0KICAgIGdlb21fYm94cGxvdCgpICsNCiAgICBzdGF0X3N1bW1hcnkoZnVuLmRhdGEgPSBtZWFuX3NlLCAgY29sb3VyID0gImRhcmtyZWQiKSArDQogICAgeGxhYigiIikgKw0KICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSkpICsNCiAgICBmYWNldF93cmFwKH5TdGltdWx1cy50eXBlKSArDQogICAgZ2dwdWJyOjpzdGF0X2NvbXBhcmVfbWVhbnMobWV0aG9kID0gInQudGVzdCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSAicC5mb3JtYXQiLCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBmb3JtYXRlZCBwLXZhbHVlcw0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICNwYWlyZWQgPSBUUlVFLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb21wYXJpc29ucyA9IGxpc3QoYygiVW5pY19JbnN0ciIsICJVbmljX1NvbG8iKSkpIA0KYGBgDQoNCg0KIyBEb3dubG9hZCBEYXRhDQoNCmBgYHtyIGRvd25sb2FkX2RhdGF9DQpVbmljX21lcmdlZCAlPiUgDQogICAgc2VsZWN0KC1jKDM6MTApKSAlPiUNCiAgICBEVDo6ZGF0YXRhYmxlKCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGV4Y2VsIGRvd25sb2FkYWJsZSAgRFQgdGFibGUNCiAgICAgIGV4dGVuc2lvbnMgPSAnQnV0dG9ucycsDQogICAgICBvcHRpb25zID0gbGlzdChwYWdlTGVuZ3RoID0gMjAsDQogICAgICAgICAgICAgICAgICAgICBzY3JvbGxYPSc1MDBweCcsIA0KICAgICAgICAgICAgICAgICAgICAgZG9tID0gJ0JmcnRpcCcsIA0KICAgICAgICAgICAgICAgICAgICAgYnV0dG9ucyA9IGMoJ2V4Y2VsJywgImNzdiIpKSkNCmBgYA0KDQoNCg0KDQo8IS0tIFNlc3Npb24gSW5mbyBhbmQgTGljZW5zZSAtLT4NCg0KPGJyPg0KDQojIFNlc3Npb24gSW5mbw0KYGBge3Igc2Vzc2lvbl9pbmZvLCBlY2hvID0gRkFMU0UsIHJlc3VsdHMgPSAnbWFya3VwJ30NCnNlc3Npb25JbmZvKCkgICAgDQpgYGANCg0KPCEtLSBGb290ZXIgLS0+DQombmJzcDsNCjxociAvPg0KPHAgc3R5bGU9InRleHQtYWxpZ246IGNlbnRlcjsiPkEgd29yayBieSA8YSBocmVmPSJodHRwczovL2dpdGh1Yi5jb20vQ2xhdWRpdVBhcGFzdGVyaS8iPkNsYXVkaXUgUGFwYXN0ZXJpPC9hPjwvcD4NCjxwIHN0eWxlPSJ0ZXh0LWFsaWduOiBjZW50ZXI7Ij48c3BhbiBzdHlsZT0iY29sb3I6ICM4MDgwODA7Ij48ZW0+Y2xhdWRpdS5wYXBhc3RlcmlAZ21haWwuY29tPC9lbT48L3NwYW4+PC9wPg0KJm5ic3A7DQo=