1 Define functions

my_ggwithinstats <- function(data, title, x, y, outlier.label, xlab, ylab) {
  x <- rlang::enquo(x)
  y <- rlang::enquo(y)
  outlier.label <- rlang::enquo(outlier.label)
  
  data %>%
    ggstatsplot::ggwithinstats(
      x = !!x,
      y = !!y,
      title = title,
      xlab = xlab,
      ylab = ylab,
      outlier.tagging = TRUE,            # whether outliers need to be tagged
      outlier.label = !!outlier.label,   # variable to be used for tagging outliers
      outlier.coef = 2,
      pairwise.comparisons = TRUE,
      pairwise.display = "significant",
      results.subtitle = TRUE,
      type = "parametric",
      bf.message = FALSE, 
      p.adjust.method = "none",
      point.path = TRUE,
      ggtheme = ggprism::theme_prism(),
      # package = "RColorBrewer",  # "ggsci",
      # palette = "Dark",         # "default_jco",
      violin.args = list(width = 0.9, alpha = 0.2, size = 1, color = "black"),
      centrality.point.args = list(size = 5, color = "darkred"),
      centrality.label.args = list(size = 3, nudge_x = 0.2, segment.linetype = 5, fill = "#FFF8E7"), 
      ggplot.component = list(
        theme(
          plot.title = element_text(hjust = 0, size = 16),
          plot.subtitle = element_text(hjust = 0, size = 12), 
          plot.caption = element_text(hjust = 0, size = 12), 
          text = element_text(size = 14)
      ))
    ) + scale_colour_grey(start = 0.2, end = 0.2)   # hacky way to change point color
}

# For publication
my_ggwithinstats2 <- function(data, title, x, y, outlier.label, xlab, ylab, 
                              outlier.tagging = FALSE, results.subtitle = TRUE, 
                              centrality.label.args = TRUE, point.path = TRUE,
                              type = "parametric", 
                              ...) {  # ... for limits and breaks
  x <- rlang::enquo(x)
  y <- rlang::enquo(y)
  outlier.label <- rlang::enquo(outlier.label)
  
  if(centrality.label.args){
    centrality.label.args <- list(size = 3, nudge_x = 0.2, segment.linetype = 5, fill = "#FFF8E7")
  }else{
    centrality.label.args <- list(size = 0, nudge_x = 10, segment.linetype = 0, alpha = 0) # very hacky way of not showing label
  }
  
  data %>%
    ggstatsplot::ggwithinstats(
      x = !!x,
      y = !!y,
      title = title,
      xlab = xlab,
      ylab = ylab,
      outlier.tagging = outlier.tagging,                    # whether outlines need to be tagged
      outlier.label = !!outlier.label,                      # variable to be used for tagging outliers
      outlier.coef = 2,
      pairwise.comparisons = TRUE,
      pairwise.display = "all",
      results.subtitle = results.subtitle,
      type = type,
      bf.message = FALSE, 
      p.adjust.method = "none",
      point.path = point.path,
      ggtheme = ggprism::theme_prism(),
      # package = "RColorBrewer",  # "ggsci",
      # palette = "Dark",         # "default_jco",
      violin.args = list(width = 0.9, alpha = 0.2, size = 1, color = "black"),
      centrality.plotting = TRUE,
      centrality.type = "parameteric",
      centrality.point.args = list(size = 5, color = "darkred"),
      centrality.label.args = centrality.label.args,
      ggplot.component = list(
        theme(
          plot.title = element_text(hjust = 0, size = 16),
          plot.subtitle = element_text(hjust = 0, size = 12), 
          plot.caption = element_text(hjust = 0, size = 12), 
          text = element_text(size = 14)
      ))
    ) + scale_colour_grey(start = 0.2, end = 0.2) +  # hacky way to change point color
    scale_y_continuous(...)
}

# Fast ggsave - saves plot with filename of R plot object
fast_ggsave <- function(plot, device = "png", path = NULL,
                        units = "in", dpi = 300, width = 5, height = 5, ...){ 
  plot_name <- deparse(substitute(plot))
  ggplot2::ggsave(filename = paste0(plot_name, ".", device), plot = plot,
                  device = device, path = path,
                  units = units, dpi = dpi,
                  width = width, height = height,
                  ...
  )
  
} # use: fast_ggsave(jrad_ox_p, path = savefolder)

2 Read, Clean, Recode

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Read, Clean, Recode, Unite
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

# Read ID data
folder <- "C:/Users/Mihai/Desktop/R Notebooks/notebooks/PA4-full-report"
file <- "Scale complete triate Sofi pa4.xlsx"
setwd(folder)

id_df <- xlsx::read.xlsx2(file.path(folder, file),
                          startRow = 1, header = FALSE, sheetName = "incadrari")

id_df <- id_df[, 1:8]
colnames(id_df) <- c("Grup", "Cond", "id", "email", "gen", "dir1", "dir2", "dir3")



id_df <- 
  id_df %>%
  dplyr::na_if("") %>%
  janitor::remove_empty("rows") %>% 
  dplyr::mutate(id = stringr::str_remove(id, "^0+"),              # remove leading zeros
                id = stringr::str_remove_all(id, "[[:blank:]]"),  # remove any white space
                id =  toupper(id)) %>%
  dplyr::mutate(Cond = stringr::str_replace(Cond, "12CONTROL", "CONTROL"),   # fix typo
                Grup = stringr::str_replace(Grup, "burnout", "Burnout"),
                Grup = stringr::str_replace(Grup, "pop generala", "pop gen"),
                Grup = stringr::str_replace(Grup, "old", "pop gen")) %>%
  dplyr::mutate(Grup = dplyr::if_else(is.na(Grup), "pop gen", Grup))

id_df <- 
  id_df %>%
  tidyr::separate(id, 
                  into = c("id_num", "Exp_type"), 
                  sep = "(?<=[0-9])(?=[A-Za-z])",     # ?<= is "look behind"
                  remove = FALSE
  ) %>%
  dplyr::select(-id_num) %>%
  dplyr::mutate(Exp_type = dplyr::if_else(Exp_type %in% c("A", "B", "C", "D", "E", "R", "X"), "online", Exp_type)) %>% 
  dplyr::mutate(email = tolower(email),
                email = stringr::str_remove_all(email, "[[:blank:]]"))

id_df <- 
  id_df %>%
  dplyr::mutate(across(starts_with("dir"),  as.numeric)) %>%
  dplyr::filter(id != "9RMN")


# check if info in dir colums is correct
check_ordered <- sort(c(id_df$dir1, id_df$dir2, id_df$dir3))  # 8.9,10 from 1GSR/9RMN
check_ordered <- unique(check_ordered)

hrv_all <- c(5:228, 230:257)    # 229 was skipped

all.equal(check_ordered, hrv_all)  # GOOD
# Read HRV data
root_folder <- "E:/CINETIC diverse/PA4 HRV"
temp_folder <- "temp_PPG"
dir1_path <- file.path(root_folder, "dir1", temp_folder)
# dir2_path <- file.path(root_folder, "dir2", temp_folder)
dir3_path <- file.path(root_folder, "dir3", temp_folder)

dir1_file <- paste0("IBI_", "dir1", ".csv")
# dir2_file <- paste0("IBI_", "dir2", ".csv")
dir3_file <- paste0("IBI_", "dir3", ".csv")


dir1_df <- read.csv(file.path(dir1_path, dir1_file))
names(dir1_df) <- c("rec", "base", "b_first5", "b_last5")
dir1_df <- 
  dir1_df %>%
  mutate_all(~ifelse(is.nan(.), NA, .)) %>%
  mutate(rec = stringr::str_remove(rec, "BUN_M2_Session"),
         rec = stringr::str_remove(rec, "_idCD5C_Calibrated_PC.csv"),
         rec = as.numeric(rec))


dir3_df <- read.csv(file.path(dir3_path, dir3_file))
names(dir3_df) <- c("rec", "whole", "first5", "last5")
dir3_df <- 
  dir3_df %>%
  mutate_all(~ifelse(is.nan(.), NA, .)) %>%
  mutate(rec = stringr::str_remove(rec, "BUN_M2_Session"),
         rec = stringr::str_remove(rec, "_idCD5C_Calibrated_PC.csv"),
         rec = as.numeric(rec))


# Make merged dataframe
dir_merge <- dplyr::left_join(id_df, dir1_df, by = c("dir1" = "rec"))
dir_merge <- dplyr::left_join(dir_merge, dir3_df, by = c("dir3" = "rec"))

dir_merge <-
  dir_merge %>%
  tidyr::drop_na(base, first5, last5)

dir_merge_long <-
  dir_merge %>%
  dplyr::select(-c(b_first5, b_last5, whole)) %>%
  tidyr::pivot_longer(cols = c(base, first5, last5), names_to = "Time", values_to = "HRV" )

3 Whole sample

dir_merge_long %>%
  dplyr::filter(Cond == "CONTROL") %>%
  my_ggwithinstats2(x = Time, y = HRV, outlier.label = id, 
                    xlab = "", ylab = "HRV",
                    title = "CONTROL")
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the existing scale.

dir_merge_long %>%
  dplyr::filter(Cond == "EXPERIMENTAL") %>%
  my_ggwithinstats2(x = Time, y = HRV, outlier.label = id, 
                    xlab = "", ylab = "HRV",
                    title = "EXPERIMENTAL")
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the existing scale.

4 By group

4.1 Normal Pop

dir_merge_long %>%
  dplyr::filter(Cond == "CONTROL", Grup == "pop gen") %>%
  my_ggwithinstats2(x = Time, y = HRV, outlier.label = id, 
                    xlab = "", ylab = "HRV",
                    title = "CONTROL")
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the existing scale.

dir_merge_long %>%
  dplyr::filter(Cond == "EXPERIMENTAL", Grup == "pop gen") %>%
  my_ggwithinstats2(x = Time, y = HRV, outlier.label = id, 
                    xlab = "", ylab = "HRV",
                    title = "EXPERIMENTAL")
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the existing scale.

4.2 PTSD

  • only 1 CONTROL with PTSD had HRV data
# dir_merge_long %>%
#   dplyr::filter(Cond == "CONTROL", Grup == "PTSD") %>%
#   my_ggwithinstats2(x = Time, y = HRV, outlier.label = id, 
#                     xlab = "", ylab = "HRV",
#                     title = "CONTROL")

dir_merge_long %>%
  dplyr::filter(Cond == "EXPERIMENTAL", Grup == "PTSD") %>%
  my_ggwithinstats2(x = Time, y = HRV, outlier.label = id, type = "np",
                    xlab = "", ylab = "HRV",
                    title = "EXPERIMENTAL")
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the existing scale.

4.3 Burnout

dir_merge_long %>%
  dplyr::filter(Cond == "CONTROL", Grup == "Burnout") %>%
  my_ggwithinstats2(x = Time, y = HRV, outlier.label = id, 
                    xlab = "", ylab = "HRV",
                    title = "CONTROL")
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the existing scale.

dir_merge_long %>%
  dplyr::filter(Cond == "EXPERIMENTAL", Grup == "Burnout") %>%
  my_ggwithinstats2(x = Time, y = HRV, outlier.label = id, type = "np",
                    xlab = "", ylab = "HRV",
                    title = "EXPERIMENTAL")
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the existing scale.


5 Session Info

R version 4.1.0 (2021-05-18)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 8.1 x64 (build 9600)

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    
system code page: 1252

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

other attached packages:
 [1] ggstatsplot_0.8.0          rio_0.5.29                 scales_1.1.1               ggpubr_0.4.0               rstatix_0.7.0             
 [6] broom_0.7.11               PerformanceAnalytics_2.0.4 xts_0.12.1                 zoo_1.8-9                  psych_2.1.6               
[11] forcats_0.5.1              stringr_1.4.0              dplyr_1.0.7                purrr_0.3.4                readr_2.0.1               
[16] tidyr_1.1.3                tibble_3.1.4               ggplot2_3.3.5              tidyverse_1.3.1            papaja_0.1.0.9997         
[21] pacman_0.5.1              

loaded via a namespace (and not attached):
  [1] readxl_1.3.1              pairwiseComparisons_3.1.6 backports_1.2.1           plyr_1.8.6                splines_4.1.0            
  [6] gmp_0.6-2                 kSamples_1.2-9            ipmisc_6.0.2              TH.data_1.0-10            digest_0.6.28            
 [11] SuppDists_1.1-9.5         lmerTest_3.1-3            fansi_0.5.0               magrittr_2.0.1            memoise_2.0.0            
 [16] xlsx_0.6.5                paletteer_1.4.0           tzdb_0.1.2                openxlsx_4.2.4            modelr_0.1.8             
 [21] sandwich_3.0-1            colorspace_2.0-2          rvest_1.0.1               ggrepel_0.9.1             haven_2.4.3              
 [26] xfun_0.25                 crayon_1.4.1              jsonlite_1.7.2            lme4_1.1-27.1             zeallot_0.1.0            
 [31] survival_3.2-13           glue_1.4.2                gtable_0.3.0              emmeans_1.6.3             MatrixModels_0.5-0       
 [36] statsExpressions_1.1.0    car_3.0-11                Rmpfr_0.8-4               abind_1.4-5               mvtnorm_1.1-2            
 [41] DBI_1.1.1                 PMCMRplus_1.9.0           Rcpp_1.0.7                xtable_1.8-4              performance_0.7.3        
 [46] tmvnsim_1.0-2             foreign_0.8-81            datawizard_0.2.0.1        httr_1.4.2                ellipsis_0.3.2           
 [51] farver_2.1.0              pkgconfig_2.0.3           reshape_0.8.8             rJava_1.0-4               multcompView_0.1-8       
 [56] dbplyr_2.1.1              utf8_1.2.2                janitor_2.1.0             labeling_0.4.2            reshape2_1.4.4           
 [61] tidyselect_1.1.1          rlang_0.4.11              effectsize_0.4.5          munsell_0.5.0             cellranger_1.1.0         
 [66] tools_4.1.0               cachem_1.0.6              ggprism_1.0.3             cli_3.0.1                 generics_0.1.0           
 [71] fastmap_1.1.0             BWStest_0.2.2             rematch2_2.1.2            knitr_1.33                fs_1.5.0                 
 [76] zip_2.2.0                 WRS2_1.1-3                pbapply_1.4-3             nlme_3.1-152              xml2_1.3.2               
 [81] correlation_0.7.0         compiler_4.1.0            rstudioapi_0.13           curl_4.3.2                ggsignif_0.6.2           
 [86] reprex_2.0.1              afex_1.0-1                stringi_1.7.4             parameters_0.14.0         lattice_0.20-44          
 [91] Matrix_1.3-4              nloptr_1.2.2.2            vctrs_0.3.8               pillar_1.6.3              lifecycle_1.0.1          
 [96] mc2d_0.1-21               estimability_1.3          data.table_1.14.0         insight_0.14.4            patchwork_1.1.1          
[101] R6_2.5.1                  BayesFactor_0.9.12-4.2    codetools_0.2-18          boot_1.3-28               MASS_7.3-54              
[106] gtools_3.9.2              assertthat_0.2.1          xlsxjars_0.6.1            withr_2.4.2               mnormt_2.0.2             
[111] multcomp_1.4-17           bayestestR_0.11.0         parallel_4.1.0            hms_1.1.0                 quadprog_1.5-8           
[116] grid_4.1.0                minqa_1.2.4               coda_0.19-4               snakecase_0.11.0          carData_3.0-4            
[121] numDeriv_2016.8-1.1       lubridate_1.7.10         
 

A work by Claudiu Papasteri

 

LS0tDQp0aXRsZTogIjxicj4gUEE0IC0gSFJWIiANCnN1YnRpdGxlOiAiUmVwb3J0Ig0KYXV0aG9yOiAiPGJyPiBDbGF1ZGl1IFBhcGFzdGVyaSINCmRhdGU6ICJgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVkICVtICVZJylgIg0Kb3V0cHV0OiANCiAgICBodG1sX25vdGVib29rOg0KICAgICAgICAgICAgY29kZV9mb2xkaW5nOiBoaWRlDQogICAgICAgICAgICB0b2M6IHRydWUNCiAgICAgICAgICAgIHRvY19kZXB0aDogMg0KICAgICAgICAgICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlDQogICAgICAgICAgICB0aGVtZTogc3BhY2VsYWINCiAgICAgICAgICAgIGhpZ2hsaWdodDogdGFuZ28NCiAgICAgICAgICAgIGZvbnQtZmFtaWx5OiBBcmlhbA0KICAgICAgICAgICAgZmlnX3dpZHRoOiAxMA0KICAgICAgICAgICAgZmlnX2hlaWdodDogOQ0KICAgICMgcGRmX2RvY3VtZW50OiANCiAgICAgICAgICAgICMgdG9jOiB0cnVlDQogICAgICAgICAgICAjICB0b2NfZGVwdGg6IDINCiAgICAgICAgICAgICMgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQ0KICAgICAgICAgICAgIyBmb250c2l6ZTogMTFwdA0KICAgICAgICAgICAgIyBnZW9tZXRyeTogbWFyZ2luPTFpbg0KICAgICAgICAgICAgIyBmaWdfd2lkdGg6IDcNCiAgICAgICAgICAgICMgZmlnX2hlaWdodDogNg0KICAgICAgICAgICAgIyBmaWdfY2FwdGlvbjogdHJ1ZQ0KICAgICMgZ2l0aHViX2RvY3VtZW50OiANCiAgICAgICAgICAgICMgdG9jOiB0cnVlDQogICAgICAgICAgICAjIHRvY19kZXB0aDogMg0KICAgICAgICAgICAgIyBodG1sX3ByZXZpZXc6IGZhbHNlDQogICAgICAgICAgICAjIGZpZ193aWR0aDogNQ0KICAgICAgICAgICAgIyBmaWdfaGVpZ2h0OiA1DQogICAgICAgICAgICAjIGRldjoganBlZw0KLS0tDQoNCg0KPCEtLSBTZXR1cCAtLT4NCg0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCiMga2ludHIgb3B0aW9ucw0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KA0KICBjb21tZW50ID0gIiMiLA0KICBjb2xsYXBzZSA9IFRSVUUsDQogIGVycm9yID0gVFJVRSwNCiAgZWNobyA9IFRSVUUsIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFLCBjYWNoZSA9IFRSVUUgICAgICAgIyBlY2hvID0gRmFsc2UgZm9yIGdpdGh1Yl9kb2N1bWVudCwgYnV0IHdpbGwgYmUgZm9sZGVkIGluIGh0bWxfbm90ZWJvb2sNCikNCg0KIyBHZW5lcmFsIFIgb3B0aW9ucyBhbmQgaW5mbw0Kc2V0LnNlZWQoMTExKSAgICAgICAgICAgICAgICMgaW4gY2FzZSB3ZSB1c2UgcmFuZG9taXplZCBwcm9jZWR1cmVzICAgICAgIA0Kb3B0aW9ucyhzY2lwZW4gPSA5OTkpICAgICAgICMgcG9zaXRpdmUgdmFsdWVzIGJpYXMgdG93YXJkcyBmaXhlZCBhbmQgbmVnYXRpdmUgdG93YXJkcyBzY2llbnRpZmljIG5vdGF0aW9uDQoNCiMgTG9hZCBwYWNrYWdlcw0KaWYgKCFyZXF1aXJlKCJwYWNtYW4iKSkgaW5zdGFsbC5wYWNrYWdlcygicGFjbWFuIikNCnBhY2thZ2VzIDwtIGMoDQogICJwYXBhamEiLA0KICAidGlkeXZlcnNlIiwgICAgICAgDQogICJwc3ljaCIsICJQZXJmb3JtYW5jZUFuYWx5dGljcyIsICAgICAgICAgIA0KICAiYnJvb20iLCAicnN0YXRpeCIsDQogICJnZ3B1YnIiLCAic2NhbGVzIiwgICAgICAgIA0KICAicmlvIiwgImdnc3RhdHNwbG90Ig0KICAjICwgLi4uDQopDQppZiAoIXJlcXVpcmUoInBhY21hbiIpKSBpbnN0YWxsLnBhY2thZ2VzKCJwYWNtYW4iKQ0KcGFjbWFuOjpwX2xvYWQoY2hhciA9IHBhY2thZ2VzKQ0KDQojIFRoZW1lcyBmb3IgZ2dwbG90MiBwbG90aW5nIChoZXJlIHVzZWQgQVBBIHN0eWxlKQ0KdGhlbWVfc2V0KHRoZW1lX2FwYSgpKQ0KYGBgDQoNCg0KPCEtLSBSZXBvcnQgLS0+DQoNCiMgRGVmaW5lIGZ1bmN0aW9ucw0KDQpgYGB7cn0NCm15X2dnd2l0aGluc3RhdHMgPC0gZnVuY3Rpb24oZGF0YSwgdGl0bGUsIHgsIHksIG91dGxpZXIubGFiZWwsIHhsYWIsIHlsYWIpIHsNCiAgeCA8LSBybGFuZzo6ZW5xdW8oeCkNCiAgeSA8LSBybGFuZzo6ZW5xdW8oeSkNCiAgb3V0bGllci5sYWJlbCA8LSBybGFuZzo6ZW5xdW8ob3V0bGllci5sYWJlbCkNCiAgDQogIGRhdGEgJT4lDQogICAgZ2dzdGF0c3Bsb3Q6Omdnd2l0aGluc3RhdHMoDQogICAgICB4ID0gISF4LA0KICAgICAgeSA9ICEheSwNCiAgICAgIHRpdGxlID0gdGl0bGUsDQogICAgICB4bGFiID0geGxhYiwNCiAgICAgIHlsYWIgPSB5bGFiLA0KICAgICAgb3V0bGllci50YWdnaW5nID0gVFJVRSwgICAgICAgICAgICAjIHdoZXRoZXIgb3V0bGllcnMgbmVlZCB0byBiZSB0YWdnZWQNCiAgICAgIG91dGxpZXIubGFiZWwgPSAhIW91dGxpZXIubGFiZWwsICAgIyB2YXJpYWJsZSB0byBiZSB1c2VkIGZvciB0YWdnaW5nIG91dGxpZXJzDQogICAgICBvdXRsaWVyLmNvZWYgPSAyLA0KICAgICAgcGFpcndpc2UuY29tcGFyaXNvbnMgPSBUUlVFLA0KICAgICAgcGFpcndpc2UuZGlzcGxheSA9ICJzaWduaWZpY2FudCIsDQogICAgICByZXN1bHRzLnN1YnRpdGxlID0gVFJVRSwNCiAgICAgIHR5cGUgPSAicGFyYW1ldHJpYyIsDQogICAgICBiZi5tZXNzYWdlID0gRkFMU0UsIA0KICAgICAgcC5hZGp1c3QubWV0aG9kID0gIm5vbmUiLA0KICAgICAgcG9pbnQucGF0aCA9IFRSVUUsDQogICAgICBnZ3RoZW1lID0gZ2dwcmlzbTo6dGhlbWVfcHJpc20oKSwNCiAgICAgICMgcGFja2FnZSA9ICJSQ29sb3JCcmV3ZXIiLCAgIyAiZ2dzY2kiLA0KICAgICAgIyBwYWxldHRlID0gIkRhcmsiLCAgICAgICAgICMgImRlZmF1bHRfamNvIiwNCiAgICAgIHZpb2xpbi5hcmdzID0gbGlzdCh3aWR0aCA9IDAuOSwgYWxwaGEgPSAwLjIsIHNpemUgPSAxLCBjb2xvciA9ICJibGFjayIpLA0KICAgICAgY2VudHJhbGl0eS5wb2ludC5hcmdzID0gbGlzdChzaXplID0gNSwgY29sb3IgPSAiZGFya3JlZCIpLA0KICAgICAgY2VudHJhbGl0eS5sYWJlbC5hcmdzID0gbGlzdChzaXplID0gMywgbnVkZ2VfeCA9IDAuMiwgc2VnbWVudC5saW5ldHlwZSA9IDUsIGZpbGwgPSAiI0ZGRjhFNyIpLCANCiAgICAgIGdncGxvdC5jb21wb25lbnQgPSBsaXN0KA0KICAgICAgICB0aGVtZSgNCiAgICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMCwgc2l6ZSA9IDE2KSwNCiAgICAgICAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMCwgc2l6ZSA9IDEyKSwgDQogICAgICAgICAgcGxvdC5jYXB0aW9uID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMCwgc2l6ZSA9IDEyKSwgDQogICAgICAgICAgdGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQpDQogICAgICApKQ0KICAgICkgKyBzY2FsZV9jb2xvdXJfZ3JleShzdGFydCA9IDAuMiwgZW5kID0gMC4yKSAgICMgaGFja3kgd2F5IHRvIGNoYW5nZSBwb2ludCBjb2xvcg0KfQ0KDQojIEZvciBwdWJsaWNhdGlvbg0KbXlfZ2d3aXRoaW5zdGF0czIgPC0gZnVuY3Rpb24oZGF0YSwgdGl0bGUsIHgsIHksIG91dGxpZXIubGFiZWwsIHhsYWIsIHlsYWIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3V0bGllci50YWdnaW5nID0gRkFMU0UsIHJlc3VsdHMuc3VidGl0bGUgPSBUUlVFLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNlbnRyYWxpdHkubGFiZWwuYXJncyA9IFRSVUUsIHBvaW50LnBhdGggPSBUUlVFLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZSA9ICJwYXJhbWV0cmljIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuLi4pIHsgICMgLi4uIGZvciBsaW1pdHMgYW5kIGJyZWFrcw0KICB4IDwtIHJsYW5nOjplbnF1byh4KQ0KICB5IDwtIHJsYW5nOjplbnF1byh5KQ0KICBvdXRsaWVyLmxhYmVsIDwtIHJsYW5nOjplbnF1byhvdXRsaWVyLmxhYmVsKQ0KICANCiAgaWYoY2VudHJhbGl0eS5sYWJlbC5hcmdzKXsNCiAgICBjZW50cmFsaXR5LmxhYmVsLmFyZ3MgPC0gbGlzdChzaXplID0gMywgbnVkZ2VfeCA9IDAuMiwgc2VnbWVudC5saW5ldHlwZSA9IDUsIGZpbGwgPSAiI0ZGRjhFNyIpDQogIH1lbHNlew0KICAgIGNlbnRyYWxpdHkubGFiZWwuYXJncyA8LSBsaXN0KHNpemUgPSAwLCBudWRnZV94ID0gMTAsIHNlZ21lbnQubGluZXR5cGUgPSAwLCBhbHBoYSA9IDApICMgdmVyeSBoYWNreSB3YXkgb2Ygbm90IHNob3dpbmcgbGFiZWwNCiAgfQ0KICANCiAgZGF0YSAlPiUNCiAgICBnZ3N0YXRzcGxvdDo6Z2d3aXRoaW5zdGF0cygNCiAgICAgIHggPSAhIXgsDQogICAgICB5ID0gISF5LA0KICAgICAgdGl0bGUgPSB0aXRsZSwNCiAgICAgIHhsYWIgPSB4bGFiLA0KICAgICAgeWxhYiA9IHlsYWIsDQogICAgICBvdXRsaWVyLnRhZ2dpbmcgPSBvdXRsaWVyLnRhZ2dpbmcsICAgICAgICAgICAgICAgICAgICAjIHdoZXRoZXIgb3V0bGluZXMgbmVlZCB0byBiZSB0YWdnZWQNCiAgICAgIG91dGxpZXIubGFiZWwgPSAhIW91dGxpZXIubGFiZWwsICAgICAgICAgICAgICAgICAgICAgICMgdmFyaWFibGUgdG8gYmUgdXNlZCBmb3IgdGFnZ2luZyBvdXRsaWVycw0KICAgICAgb3V0bGllci5jb2VmID0gMiwNCiAgICAgIHBhaXJ3aXNlLmNvbXBhcmlzb25zID0gVFJVRSwNCiAgICAgIHBhaXJ3aXNlLmRpc3BsYXkgPSAiYWxsIiwNCiAgICAgIHJlc3VsdHMuc3VidGl0bGUgPSByZXN1bHRzLnN1YnRpdGxlLA0KICAgICAgdHlwZSA9IHR5cGUsDQogICAgICBiZi5tZXNzYWdlID0gRkFMU0UsIA0KICAgICAgcC5hZGp1c3QubWV0aG9kID0gIm5vbmUiLA0KICAgICAgcG9pbnQucGF0aCA9IHBvaW50LnBhdGgsDQogICAgICBnZ3RoZW1lID0gZ2dwcmlzbTo6dGhlbWVfcHJpc20oKSwNCiAgICAgICMgcGFja2FnZSA9ICJSQ29sb3JCcmV3ZXIiLCAgIyAiZ2dzY2kiLA0KICAgICAgIyBwYWxldHRlID0gIkRhcmsiLCAgICAgICAgICMgImRlZmF1bHRfamNvIiwNCiAgICAgIHZpb2xpbi5hcmdzID0gbGlzdCh3aWR0aCA9IDAuOSwgYWxwaGEgPSAwLjIsIHNpemUgPSAxLCBjb2xvciA9ICJibGFjayIpLA0KICAgICAgY2VudHJhbGl0eS5wbG90dGluZyA9IFRSVUUsDQogICAgICBjZW50cmFsaXR5LnR5cGUgPSAicGFyYW1ldGVyaWMiLA0KICAgICAgY2VudHJhbGl0eS5wb2ludC5hcmdzID0gbGlzdChzaXplID0gNSwgY29sb3IgPSAiZGFya3JlZCIpLA0KICAgICAgY2VudHJhbGl0eS5sYWJlbC5hcmdzID0gY2VudHJhbGl0eS5sYWJlbC5hcmdzLA0KICAgICAgZ2dwbG90LmNvbXBvbmVudCA9IGxpc3QoDQogICAgICAgIHRoZW1lKA0KICAgICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLCBzaXplID0gMTYpLA0KICAgICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLCBzaXplID0gMTIpLCANCiAgICAgICAgICBwbG90LmNhcHRpb24gPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLCBzaXplID0gMTIpLCANCiAgICAgICAgICB0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCkNCiAgICAgICkpDQogICAgKSArIHNjYWxlX2NvbG91cl9ncmV5KHN0YXJ0ID0gMC4yLCBlbmQgPSAwLjIpICsgICMgaGFja3kgd2F5IHRvIGNoYW5nZSBwb2ludCBjb2xvcg0KICAgIHNjYWxlX3lfY29udGludW91cyguLi4pDQp9DQoNCiMgRmFzdCBnZ3NhdmUgLSBzYXZlcyBwbG90IHdpdGggZmlsZW5hbWUgb2YgUiBwbG90IG9iamVjdA0KZmFzdF9nZ3NhdmUgPC0gZnVuY3Rpb24ocGxvdCwgZGV2aWNlID0gInBuZyIsIHBhdGggPSBOVUxMLA0KICAgICAgICAgICAgICAgICAgICAgICAgdW5pdHMgPSAiaW4iLCBkcGkgPSAzMDAsIHdpZHRoID0gNSwgaGVpZ2h0ID0gNSwgLi4uKXsgDQogIHBsb3RfbmFtZSA8LSBkZXBhcnNlKHN1YnN0aXR1dGUocGxvdCkpDQogIGdncGxvdDI6Omdnc2F2ZShmaWxlbmFtZSA9IHBhc3RlMChwbG90X25hbWUsICIuIiwgZGV2aWNlKSwgcGxvdCA9IHBsb3QsDQogICAgICAgICAgICAgICAgICBkZXZpY2UgPSBkZXZpY2UsIHBhdGggPSBwYXRoLA0KICAgICAgICAgICAgICAgICAgdW5pdHMgPSB1bml0cywgZHBpID0gZHBpLA0KICAgICAgICAgICAgICAgICAgd2lkdGggPSB3aWR0aCwgaGVpZ2h0ID0gaGVpZ2h0LA0KICAgICAgICAgICAgICAgICAgLi4uDQogICkNCiAgDQp9ICMgdXNlOiBmYXN0X2dnc2F2ZShqcmFkX294X3AsIHBhdGggPSBzYXZlZm9sZGVyKQ0KYGBgDQoNCg0KDQoNCiMgUmVhZCwgQ2xlYW4sIFJlY29kZQ0KDQpgYGB7ciByZWRfY2xlYW5fcmVjb2RlX21lcmdlLCByZXN1bHRzPSdoaWRlJywgbWVzc2FnZT1GQUxTRX0NCiN+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+DQojIFJlYWQsIENsZWFuLCBSZWNvZGUsIFVuaXRlDQojfn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fg0KDQojIFJlYWQgSUQgZGF0YQ0KZm9sZGVyIDwtICJDOi9Vc2Vycy9NaWhhaS9EZXNrdG9wL1IgTm90ZWJvb2tzL25vdGVib29rcy9QQTQtZnVsbC1yZXBvcnQiDQpmaWxlIDwtICJTY2FsZSBjb21wbGV0ZSB0cmlhdGUgU29maSBwYTQueGxzeCINCnNldHdkKGZvbGRlcikNCg0KaWRfZGYgPC0geGxzeDo6cmVhZC54bHN4MihmaWxlLnBhdGgoZm9sZGVyLCBmaWxlKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgc3RhcnRSb3cgPSAxLCBoZWFkZXIgPSBGQUxTRSwgc2hlZXROYW1lID0gImluY2FkcmFyaSIpDQoNCmlkX2RmIDwtIGlkX2RmWywgMTo4XQ0KY29sbmFtZXMoaWRfZGYpIDwtIGMoIkdydXAiLCAiQ29uZCIsICJpZCIsICJlbWFpbCIsICJnZW4iLCAiZGlyMSIsICJkaXIyIiwgImRpcjMiKQ0KDQoNCg0KaWRfZGYgPC0gDQogIGlkX2RmICU+JQ0KICBkcGx5cjo6bmFfaWYoIiIpICU+JQ0KICBqYW5pdG9yOjpyZW1vdmVfZW1wdHkoInJvd3MiKSAlPiUgDQogIGRwbHlyOjptdXRhdGUoaWQgPSBzdHJpbmdyOjpzdHJfcmVtb3ZlKGlkLCAiXjArIiksICAgICAgICAgICAgICAjIHJlbW92ZSBsZWFkaW5nIHplcm9zDQogICAgICAgICAgICAgICAgaWQgPSBzdHJpbmdyOjpzdHJfcmVtb3ZlX2FsbChpZCwgIltbOmJsYW5rOl1dIiksICAjIHJlbW92ZSBhbnkgd2hpdGUgc3BhY2UNCiAgICAgICAgICAgICAgICBpZCA9ICB0b3VwcGVyKGlkKSkgJT4lDQogIGRwbHlyOjptdXRhdGUoQ29uZCA9IHN0cmluZ3I6OnN0cl9yZXBsYWNlKENvbmQsICIxMkNPTlRST0wiLCAiQ09OVFJPTCIpLCAgICMgZml4IHR5cG8NCiAgICAgICAgICAgICAgICBHcnVwID0gc3RyaW5ncjo6c3RyX3JlcGxhY2UoR3J1cCwgImJ1cm5vdXQiLCAiQnVybm91dCIpLA0KICAgICAgICAgICAgICAgIEdydXAgPSBzdHJpbmdyOjpzdHJfcmVwbGFjZShHcnVwLCAicG9wIGdlbmVyYWxhIiwgInBvcCBnZW4iKSwNCiAgICAgICAgICAgICAgICBHcnVwID0gc3RyaW5ncjo6c3RyX3JlcGxhY2UoR3J1cCwgIm9sZCIsICJwb3AgZ2VuIikpICU+JQ0KICBkcGx5cjo6bXV0YXRlKEdydXAgPSBkcGx5cjo6aWZfZWxzZShpcy5uYShHcnVwKSwgInBvcCBnZW4iLCBHcnVwKSkNCg0KaWRfZGYgPC0gDQogIGlkX2RmICU+JQ0KICB0aWR5cjo6c2VwYXJhdGUoaWQsIA0KICAgICAgICAgICAgICAgICAgaW50byA9IGMoImlkX251bSIsICJFeHBfdHlwZSIpLCANCiAgICAgICAgICAgICAgICAgIHNlcCA9ICIoPzw9WzAtOV0pKD89W0EtWmEtel0pIiwgICAgICMgPzw9IGlzICJsb29rIGJlaGluZCINCiAgICAgICAgICAgICAgICAgIHJlbW92ZSA9IEZBTFNFDQogICkgJT4lDQogIGRwbHlyOjpzZWxlY3QoLWlkX251bSkgJT4lDQogIGRwbHlyOjptdXRhdGUoRXhwX3R5cGUgPSBkcGx5cjo6aWZfZWxzZShFeHBfdHlwZSAlaW4lIGMoIkEiLCAiQiIsICJDIiwgIkQiLCAiRSIsICJSIiwgIlgiKSwgIm9ubGluZSIsIEV4cF90eXBlKSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKGVtYWlsID0gdG9sb3dlcihlbWFpbCksDQogICAgICAgICAgICAgICAgZW1haWwgPSBzdHJpbmdyOjpzdHJfcmVtb3ZlX2FsbChlbWFpbCwgIltbOmJsYW5rOl1dIikpDQoNCmlkX2RmIDwtIA0KICBpZF9kZiAlPiUNCiAgZHBseXI6Om11dGF0ZShhY3Jvc3Moc3RhcnRzX3dpdGgoImRpciIpLCAgYXMubnVtZXJpYykpICU+JQ0KICBkcGx5cjo6ZmlsdGVyKGlkICE9ICI5Uk1OIikNCg0KDQojIGNoZWNrIGlmIGluZm8gaW4gZGlyIGNvbHVtcyBpcyBjb3JyZWN0DQpjaGVja19vcmRlcmVkIDwtIHNvcnQoYyhpZF9kZiRkaXIxLCBpZF9kZiRkaXIyLCBpZF9kZiRkaXIzKSkgICMgOC45LDEwIGZyb20gMUdTUi85Uk1ODQpjaGVja19vcmRlcmVkIDwtIHVuaXF1ZShjaGVja19vcmRlcmVkKQ0KDQpocnZfYWxsIDwtIGMoNToyMjgsIDIzMDoyNTcpICAgICMgMjI5IHdhcyBza2lwcGVkDQoNCmFsbC5lcXVhbChjaGVja19vcmRlcmVkLCBocnZfYWxsKSAgIyBHT09EDQoNCg0KIyBSZWFkIEhSViBkYXRhDQpyb290X2ZvbGRlciA8LSAiRTovQ0lORVRJQyBkaXZlcnNlL1BBNCBIUlYiDQp0ZW1wX2ZvbGRlciA8LSAidGVtcF9QUEciDQpkaXIxX3BhdGggPC0gZmlsZS5wYXRoKHJvb3RfZm9sZGVyLCAiZGlyMSIsIHRlbXBfZm9sZGVyKQ0KIyBkaXIyX3BhdGggPC0gZmlsZS5wYXRoKHJvb3RfZm9sZGVyLCAiZGlyMiIsIHRlbXBfZm9sZGVyKQ0KZGlyM19wYXRoIDwtIGZpbGUucGF0aChyb290X2ZvbGRlciwgImRpcjMiLCB0ZW1wX2ZvbGRlcikNCg0KZGlyMV9maWxlIDwtIHBhc3RlMCgiSUJJXyIsICJkaXIxIiwgIi5jc3YiKQ0KIyBkaXIyX2ZpbGUgPC0gcGFzdGUwKCJJQklfIiwgImRpcjIiLCAiLmNzdiIpDQpkaXIzX2ZpbGUgPC0gcGFzdGUwKCJJQklfIiwgImRpcjMiLCAiLmNzdiIpDQoNCg0KZGlyMV9kZiA8LSByZWFkLmNzdihmaWxlLnBhdGgoZGlyMV9wYXRoLCBkaXIxX2ZpbGUpKQ0KbmFtZXMoZGlyMV9kZikgPC0gYygicmVjIiwgImJhc2UiLCAiYl9maXJzdDUiLCAiYl9sYXN0NSIpDQpkaXIxX2RmIDwtIA0KICBkaXIxX2RmICU+JQ0KICBtdXRhdGVfYWxsKH5pZmVsc2UoaXMubmFuKC4pLCBOQSwgLikpICU+JQ0KICBtdXRhdGUocmVjID0gc3RyaW5ncjo6c3RyX3JlbW92ZShyZWMsICJCVU5fTTJfU2Vzc2lvbiIpLA0KICAgICAgICAgcmVjID0gc3RyaW5ncjo6c3RyX3JlbW92ZShyZWMsICJfaWRDRDVDX0NhbGlicmF0ZWRfUEMuY3N2IiksDQogICAgICAgICByZWMgPSBhcy5udW1lcmljKHJlYykpDQoNCg0KZGlyM19kZiA8LSByZWFkLmNzdihmaWxlLnBhdGgoZGlyM19wYXRoLCBkaXIzX2ZpbGUpKQ0KbmFtZXMoZGlyM19kZikgPC0gYygicmVjIiwgIndob2xlIiwgImZpcnN0NSIsICJsYXN0NSIpDQpkaXIzX2RmIDwtIA0KICBkaXIzX2RmICU+JQ0KICBtdXRhdGVfYWxsKH5pZmVsc2UoaXMubmFuKC4pLCBOQSwgLikpICU+JQ0KICBtdXRhdGUocmVjID0gc3RyaW5ncjo6c3RyX3JlbW92ZShyZWMsICJCVU5fTTJfU2Vzc2lvbiIpLA0KICAgICAgICAgcmVjID0gc3RyaW5ncjo6c3RyX3JlbW92ZShyZWMsICJfaWRDRDVDX0NhbGlicmF0ZWRfUEMuY3N2IiksDQogICAgICAgICByZWMgPSBhcy5udW1lcmljKHJlYykpDQoNCg0KIyBNYWtlIG1lcmdlZCBkYXRhZnJhbWUNCmRpcl9tZXJnZSA8LSBkcGx5cjo6bGVmdF9qb2luKGlkX2RmLCBkaXIxX2RmLCBieSA9IGMoImRpcjEiID0gInJlYyIpKQ0KZGlyX21lcmdlIDwtIGRwbHlyOjpsZWZ0X2pvaW4oZGlyX21lcmdlLCBkaXIzX2RmLCBieSA9IGMoImRpcjMiID0gInJlYyIpKQ0KDQpkaXJfbWVyZ2UgPC0NCiAgZGlyX21lcmdlICU+JQ0KICB0aWR5cjo6ZHJvcF9uYShiYXNlLCBmaXJzdDUsIGxhc3Q1KQ0KDQpkaXJfbWVyZ2VfbG9uZyA8LQ0KICBkaXJfbWVyZ2UgJT4lDQogIGRwbHlyOjpzZWxlY3QoLWMoYl9maXJzdDUsIGJfbGFzdDUsIHdob2xlKSkgJT4lDQogIHRpZHlyOjpwaXZvdF9sb25nZXIoY29scyA9IGMoYmFzZSwgZmlyc3Q1LCBsYXN0NSksIG5hbWVzX3RvID0gIlRpbWUiLCB2YWx1ZXNfdG8gPSAiSFJWIiApDQoNCmBgYA0KDQoNCiMgV2hvbGUgc2FtcGxlDQoNCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD04fQ0KZGlyX21lcmdlX2xvbmcgJT4lDQogIGRwbHlyOjpmaWx0ZXIoQ29uZCA9PSAiQ09OVFJPTCIpICU+JQ0KICBteV9nZ3dpdGhpbnN0YXRzMih4ID0gVGltZSwgeSA9IEhSViwgb3V0bGllci5sYWJlbCA9IGlkLCANCiAgICAgICAgICAgICAgICAgICAgeGxhYiA9ICIiLCB5bGFiID0gIkhSViIsDQogICAgICAgICAgICAgICAgICAgIHRpdGxlID0gIkNPTlRST0wiKQ0KDQpkaXJfbWVyZ2VfbG9uZyAlPiUNCiAgZHBseXI6OmZpbHRlcihDb25kID09ICJFWFBFUklNRU5UQUwiKSAlPiUNCiAgbXlfZ2d3aXRoaW5zdGF0czIoeCA9IFRpbWUsIHkgPSBIUlYsIG91dGxpZXIubGFiZWwgPSBpZCwgDQogICAgICAgICAgICAgICAgICAgIHhsYWIgPSAiIiwgeWxhYiA9ICJIUlYiLA0KICAgICAgICAgICAgICAgICAgICB0aXRsZSA9ICJFWFBFUklNRU5UQUwiKQ0KYGBgDQoNCg0KIyBCeSBncm91cA0KDQojIyBOb3JtYWwgUG9wDQoNCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD04fQ0KZGlyX21lcmdlX2xvbmcgJT4lDQogIGRwbHlyOjpmaWx0ZXIoQ29uZCA9PSAiQ09OVFJPTCIsIEdydXAgPT0gInBvcCBnZW4iKSAlPiUNCiAgbXlfZ2d3aXRoaW5zdGF0czIoeCA9IFRpbWUsIHkgPSBIUlYsIG91dGxpZXIubGFiZWwgPSBpZCwgDQogICAgICAgICAgICAgICAgICAgIHhsYWIgPSAiIiwgeWxhYiA9ICJIUlYiLA0KICAgICAgICAgICAgICAgICAgICB0aXRsZSA9ICJDT05UUk9MIikNCg0KZGlyX21lcmdlX2xvbmcgJT4lDQogIGRwbHlyOjpmaWx0ZXIoQ29uZCA9PSAiRVhQRVJJTUVOVEFMIiwgR3J1cCA9PSAicG9wIGdlbiIpICU+JQ0KICBteV9nZ3dpdGhpbnN0YXRzMih4ID0gVGltZSwgeSA9IEhSViwgb3V0bGllci5sYWJlbCA9IGlkLCANCiAgICAgICAgICAgICAgICAgICAgeGxhYiA9ICIiLCB5bGFiID0gIkhSViIsDQogICAgICAgICAgICAgICAgICAgIHRpdGxlID0gIkVYUEVSSU1FTlRBTCIpDQpgYGANCg0KIyMgUFRTRCANCg0KLSBvbmx5IDEgQ09OVFJPTCB3aXRoIFBUU0QgaGFkIEhSViBkYXRhDQoNCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD04fQ0KIyBkaXJfbWVyZ2VfbG9uZyAlPiUNCiMgICBkcGx5cjo6ZmlsdGVyKENvbmQgPT0gIkNPTlRST0wiLCBHcnVwID09ICJQVFNEIikgJT4lDQojICAgbXlfZ2d3aXRoaW5zdGF0czIoeCA9IFRpbWUsIHkgPSBIUlYsIG91dGxpZXIubGFiZWwgPSBpZCwgDQojICAgICAgICAgICAgICAgICAgICAgeGxhYiA9ICIiLCB5bGFiID0gIkhSViIsDQojICAgICAgICAgICAgICAgICAgICAgdGl0bGUgPSAiQ09OVFJPTCIpDQoNCmRpcl9tZXJnZV9sb25nICU+JQ0KICBkcGx5cjo6ZmlsdGVyKENvbmQgPT0gIkVYUEVSSU1FTlRBTCIsIEdydXAgPT0gIlBUU0QiKSAlPiUNCiAgbXlfZ2d3aXRoaW5zdGF0czIoeCA9IFRpbWUsIHkgPSBIUlYsIG91dGxpZXIubGFiZWwgPSBpZCwgdHlwZSA9ICJucCIsDQogICAgICAgICAgICAgICAgICAgIHhsYWIgPSAiIiwgeWxhYiA9ICJIUlYiLA0KICAgICAgICAgICAgICAgICAgICB0aXRsZSA9ICJFWFBFUklNRU5UQUwiKQ0KYGBgDQoNCiMjIEJ1cm5vdXQNCg0KDQpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9OH0NCmRpcl9tZXJnZV9sb25nICU+JQ0KICBkcGx5cjo6ZmlsdGVyKENvbmQgPT0gIkNPTlRST0wiLCBHcnVwID09ICJCdXJub3V0IikgJT4lDQogIG15X2dnd2l0aGluc3RhdHMyKHggPSBUaW1lLCB5ID0gSFJWLCBvdXRsaWVyLmxhYmVsID0gaWQsIA0KICAgICAgICAgICAgICAgICAgICB4bGFiID0gIiIsIHlsYWIgPSAiSFJWIiwNCiAgICAgICAgICAgICAgICAgICAgdGl0bGUgPSAiQ09OVFJPTCIpDQoNCmRpcl9tZXJnZV9sb25nICU+JQ0KICBkcGx5cjo6ZmlsdGVyKENvbmQgPT0gIkVYUEVSSU1FTlRBTCIsIEdydXAgPT0gIkJ1cm5vdXQiKSAlPiUNCiAgbXlfZ2d3aXRoaW5zdGF0czIoeCA9IFRpbWUsIHkgPSBIUlYsIG91dGxpZXIubGFiZWwgPSBpZCwgdHlwZSA9ICJucCIsDQogICAgICAgICAgICAgICAgICAgIHhsYWIgPSAiIiwgeWxhYiA9ICJIUlYiLA0KICAgICAgICAgICAgICAgICAgICB0aXRsZSA9ICJFWFBFUklNRU5UQUwiKQ0KYGBgDQoNCg0KDQoNCg0KDQoNCjwhLS0gU2Vzc2lvbiBJbmZvIGFuZCBMaWNlbnNlIC0tPg0KDQo8YnI+DQoNCiMgU2Vzc2lvbiBJbmZvDQpgYGB7ciBzZXNzaW9uX2luZm8sIGVjaG8gPSBGQUxTRSwgcmVzdWx0cyA9ICdtYXJrdXAnfQ0Kc2Vzc2lvbkluZm8oKSAgICANCmBgYA0KDQo8IS0tIEZvb3RlciAtLT4NCiZuYnNwOw0KPGhyIC8+DQo8cCBzdHlsZT0idGV4dC1hbGlnbjogY2VudGVyOyI+QSB3b3JrIGJ5IDxhIGhyZWY9Imh0dHBzOi8vZ2l0aHViLmNvbS9DbGF1ZGl1UGFwYXN0ZXJpLyI+Q2xhdWRpdSBQYXBhc3Rlcmk8L2E+PC9wPg0KPHAgc3R5bGU9InRleHQtYWxpZ246IGNlbnRlcjsiPjxzcGFuIHN0eWxlPSJjb2xvcjogIzgwODA4MDsiPjxlbT5jbGF1ZGl1LnBhcGFzdGVyaUBnbWFpbC5jb208L2VtPjwvc3Bhbj48L3A+DQombmJzcDsNCg==