1 Define functions

## Define function that recodes to numeric, but watches out to coercion to not introduce NAs
colstonumeric <- function(df){
  tryCatch({
    df_num <- as.data.frame(
      lapply(df,
             function(x) { as.numeric(as.character(x))})) 
  },warning = function(stop_on_warning) {
    message("Stoped the execution of numeric conversion: ", conditionMessage(stop_on_warning))
  }) 
}
##
## Define function that reverse codes items
ReverseCode <- function(df, tonumeric = FALSE, min = NULL, max = NULL) {
  if(tonumeric) df <- colstonumeric(df)
  df <- (max + min) - df
}
##
## Define function that scores only rows with less than 10% NAs (returns NA if all or above threshold percentage of rows are NA); can reverse code if vector of column indexes and min, max are provided.
ScoreLikert <- function(df, napercent = .1, tonumeric = FALSE, reversecols = NULL, min = NULL, max = NULL) {
  reverse_list <- list(reversecols = reversecols, min = min, max = max)
  reverse_check <- !sapply(reverse_list, is.null)
  
  # Recode to numeric, but watch out to coercion to not introduce NAs
  colstonumeric <- function(df){
    tryCatch({
      df_num <- as.data.frame(
        lapply(df,
               function(x) { as.numeric(as.character(x))})) 
    },warning = function(stop_on_warning) {
      message("Stoped the execution of numeric conversion: ", conditionMessage(stop_on_warning))
    }) 
  }
  
  if(tonumeric) df <- colstonumeric(df)
  
  if(all(reverse_check)){
    df[ ,reversecols] <- (max + min) - df[ ,reversecols]
  }else if(any(reverse_check)){
    stop("Insuficient info for reversing. Please provide: ", paste(names(reverse_list)[!reverse_check], collapse = ", "))
  }
  
  ifelse(rowSums(is.na(df)) > ncol(df) * napercent,
         NA,
         rowSums(df, na.rm = TRUE) * NA ^ (rowSums(!is.na(df)) == 0)
  )
}
##
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

id_df <- rio::import(file.path(folder, file),
                               skip = -1, which = "Iduri")

2.1 Score APS

2.2 APS

data %>%
  dplyr::filter(Cond == "experimental") %>%
  dplyr::filter(PrePost %in% c("Pre", "Post")) %>%
  my_ggwithinstats2(x = PrePost, y = APS_Total, outlier.label = id, type = "np",  
                    xlab = "", ylab = "APS",
                    title = "Experimental")
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the existing scale.

data %>%
  dplyr::filter(Cond == "ctrl") %>%
  dplyr::filter(PrePost %in% c("Pre", "Post")) %>%
  my_ggwithinstats2(x = PrePost, y = APS_Total, outlier.label = id, type = "np",
                    xlab = "", ylab = "APS",
                    title = "Control")
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the existing scale.

data %>%
  dplyr::filter(Cond == "experimental") %>%
  group_by(id) %>%
  dplyr::filter(!n() < 3) %>%                     # filter out those without F_up
  my_ggwithinstats2(x = PrePost, y = APS_Total, outlier.label = id, type = "np",  
                    xlab = "", ylab = "APS",
                    title = "Experimental")
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the existing scale.

data %>%
  dplyr::filter(Cond == "ctrl") %>%
  group_by(id) %>%
  dplyr::filter(!n() < 3) %>%                     # filter out those without F_up
  my_ggwithinstats2(x = PrePost, y = APS_Total, outlier.label = id, type = "np",
                    xlab = "", ylab = "APS",
                    title = "Control")
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the existing scale.


3 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.27        scales_1.1.1      ggpubr_0.4.0      rstatix_0.7.0     broom_0.7.9       forcats_0.5.1     stringr_1.4.0    
 [9] purrr_0.3.4       readr_2.0.1       tidyr_1.1.3       tibble_3.1.4      ggplot2_3.3.5     tidyverse_1.3.1   papaja_0.1.0.9997 pacman_0.5.1     
[17] dplyr_1.0.7      

loaded via a namespace (and not attached):
  [1] estimability_1.3          ggprism_1.0.3             GGally_2.1.2              lavaan_0.6-9              coda_0.19-4              
  [6] knitr_1.33                multcomp_1.4-17           data.table_1.14.0         rpart_4.1-15              hardhat_0.1.6            
 [11] generics_0.1.0            GPfit_1.0-8               TH.data_1.0-10            future_1.22.1             correlation_0.7.0        
 [16] tzdb_0.1.2                xml2_1.3.2                lubridate_1.7.10          assertthat_0.2.1          gower_0.2.2              
 [21] WRS2_1.1-3                xfun_0.25                 hms_1.1.0                 jquerylib_0.1.4           evaluate_0.14            
 [26] fansi_0.5.0               dbplyr_2.1.1              readxl_1.3.1              igraph_1.2.6              DBI_1.1.1                
 [31] tmvnsim_1.0-2             Rsolnp_1.16               htmlwidgets_1.5.3         reshape_0.8.8             kSamples_1.2-9           
 [36] stats4_4.1.0              Rmpfr_0.8-4               paletteer_1.4.0           ellipsis_0.3.2            backports_1.2.1          
 [41] pbivnorm_0.6.0            insight_0.14.4            RcppParallel_5.1.4        pwr_1.3-0                 vctrs_0.3.8              
 [46] abind_1.4-5               cachem_1.0.6              withr_2.4.2               checkmate_2.0.0           emmeans_1.6.3            
 [51] fdrtool_1.2.16            parsnip_0.1.7             mnormt_2.0.2              cluster_2.1.2             mi_1.0                   
 [56] crayon_1.4.1              labeling_0.4.2            recipes_0.1.16            pkgconfig_2.0.3           SuppDists_1.1-9.5        
 [61] nlme_3.1-152              statsExpressions_1.1.0    nnet_7.3-16               rlang_0.4.11              globals_0.14.0           
 [66] lifecycle_1.0.1           MatrixModels_0.5-0        sandwich_3.0-1            kutils_1.70               modelr_0.1.8             
 [71] cellranger_1.1.0          datawizard_0.2.0.1        Matrix_1.3-4              yardstick_0.0.8           regsem_1.8.0             
 [76] mc2d_0.1-21               carData_3.0-4             boot_1.3-28               zoo_1.8-9                 reprex_2.0.1             
 [81] base64enc_0.1-3           png_0.1-7                 PMCMRplus_1.9.0           parameters_0.14.0         pROC_1.18.0              
 [86] afex_1.0-1                tune_0.1.6                workflows_0.2.3           multcompView_0.1-8        arm_1.11-2               
 [91] parallelly_1.27.0         jpeg_0.1-9                rockchalk_1.8.144         ggsignif_0.6.2            memoise_2.0.0            
 [96] magrittr_2.0.1            plyr_1.8.6                compiler_4.1.0            RColorBrewer_1.1-2        lme4_1.1-27.1            
[101] snakecase_0.11.0          cli_3.0.1                 lmerTest_3.1-3            DiceDesign_1.9            listenv_0.8.0            
[106] patchwork_1.1.1           pbapply_1.4-3             htmlTable_2.2.1           Formula_1.2-4             MASS_7.3-54              
[111] tidyselect_1.1.1          stringi_1.7.4             lisrelToR_0.1.4           sem_3.1-11                yaml_2.2.1               
[116] OpenMx_2.19.6             latticeExtra_0.6-29       ggrepel_0.9.1             semTools_0.5-5            grid_4.1.0               
[121] sass_0.4.0                tools_4.1.0               future.apply_1.8.1        parallel_4.1.0            matrixcalc_1.0-5         
[126] rstudioapi_0.13           foreach_1.5.1             foreign_0.8-81            janitor_2.1.0             gridExtra_2.3            
[131] ipmisc_6.0.2              prodlim_2019.11.13        pairwiseComparisons_3.1.6 farver_2.1.0              digest_0.6.28            
[136] lava_1.6.10               BWStest_0.2.2             Rcpp_1.0.7                car_3.0-11                BayesFactor_0.9.12-4.2   
[141] performance_0.7.3         httr_1.4.2                psych_2.1.6               effectsize_0.4.5          poLCA_1.4.1              
[146] colorspace_2.0-2          rvest_1.0.1               fs_1.5.0                  XML_3.99-0.7              truncnorm_1.0-8          
[151] splines_4.1.0             rematch2_2.1.2            xtable_1.8-4              gmp_0.6-2                 jsonlite_1.7.2           
[156] nloptr_1.2.2.2            corpcor_1.6.9             timeDate_3043.102         glasso_1.11               zeallot_0.1.0            
[161] ipred_0.9-11              R6_2.5.1                  Hmisc_4.5-0               lhs_1.1.1                 pillar_1.6.3             
[166] htmltools_0.5.2           glue_1.4.2                fastmap_1.1.0             minqa_1.2.4               class_7.3-19             
[171] codetools_0.2-18          mvtnorm_1.1-2             furrr_0.2.3               utf8_1.2.2                lattice_0.20-44          
[176] bslib_0.3.0               dials_0.0.9               numDeriv_2016.8-1.1       curl_4.3.2                gtools_3.9.2             
[181] zip_2.2.0                 openxlsx_4.2.4            survival_3.2-13           rmarkdown_2.10            qgraph_1.6.9             
[186] munsell_0.5.0             semPlot_1.1.2             rsample_0.1.0             iterators_1.0.13          haven_2.4.3              
[191] reshape2_1.4.4            gtable_0.3.0              bayestestR_0.11.0        
 

A work by Claudiu Papasteri

 

LS0tDQp0aXRsZTogIjxicj4gQTEwIiANCnN1YnRpdGxlOiAiUmVwb3J0Ig0KYXV0aG9yOiAiPGJyPiBDbGF1ZGl1IFBhcGFzdGVyaSINCmRhdGU6ICJgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVkICVtICVZJylgIg0Kb3V0cHV0OiANCiAgICBodG1sX25vdGVib29rOg0KICAgICAgICAgICAgY29kZV9mb2xkaW5nOiBoaWRlDQogICAgICAgICAgICB0b2M6IHRydWUNCiAgICAgICAgICAgIHRvY19kZXB0aDogMg0KICAgICAgICAgICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlDQogICAgICAgICAgICB0aGVtZTogc3BhY2VsYWINCiAgICAgICAgICAgIGhpZ2hsaWdodDogdGFuZ28NCiAgICAgICAgICAgIGZvbnQtZmFtaWx5OiBBcmlhbA0KICAgICAgICAgICAgZmlnX3dpZHRoOiAxMA0KICAgICAgICAgICAgZmlnX2hlaWdodDogOQ0KICAgICMgcGRmX2RvY3VtZW50OiANCiAgICAgICAgICAgICMgdG9jOiB0cnVlDQogICAgICAgICAgICAjICB0b2NfZGVwdGg6IDINCiAgICAgICAgICAgICMgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQ0KICAgICAgICAgICAgIyBmb250c2l6ZTogMTFwdA0KICAgICAgICAgICAgIyBnZW9tZXRyeTogbWFyZ2luPTFpbg0KICAgICAgICAgICAgIyBmaWdfd2lkdGg6IDcNCiAgICAgICAgICAgICMgZmlnX2hlaWdodDogNg0KICAgICAgICAgICAgIyBmaWdfY2FwdGlvbjogdHJ1ZQ0KICAgICMgZ2l0aHViX2RvY3VtZW50OiANCiAgICAgICAgICAgICMgdG9jOiB0cnVlDQogICAgICAgICAgICAjIHRvY19kZXB0aDogMg0KICAgICAgICAgICAgIyBodG1sX3ByZXZpZXc6IGZhbHNlDQogICAgICAgICAgICAjIGZpZ193aWR0aDogNQ0KICAgICAgICAgICAgIyBmaWdfaGVpZ2h0OiA1DQogICAgICAgICAgICAjIGRldjoganBlZw0KLS0tDQoNCg0KPCEtLSBTZXR1cCAtLT4NCg0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCiMga2ludHIgb3B0aW9ucw0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KA0KICBjb21tZW50ID0gIiMiLA0KICBjb2xsYXBzZSA9IFRSVUUsDQogIGVycm9yID0gVFJVRSwNCiAgZWNobyA9IFRSVUUsIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFLCBjYWNoZSA9IFRSVUUgICAgICAgIyBlY2hvID0gRmFsc2UgZm9yIGdpdGh1Yl9kb2N1bWVudCwgYnV0IHdpbGwgYmUgZm9sZGVkIGluIGh0bWxfbm90ZWJvb2sNCikNCg0KIyBHZW5lcmFsIFIgb3B0aW9ucyBhbmQgaW5mbw0Kc2V0LnNlZWQoMTExKSAgICAgICAgICAgICAgICMgaW4gY2FzZSB3ZSB1c2UgcmFuZG9taXplZCBwcm9jZWR1cmVzICAgICAgIA0Kb3B0aW9ucyhzY2lwZW4gPSA5OTkpICAgICAgICMgcG9zaXRpdmUgdmFsdWVzIGJpYXMgdG93YXJkcyBmaXhlZCBhbmQgbmVnYXRpdmUgdG93YXJkcyBzY2llbnRpZmljIG5vdGF0aW9uDQoNCiMgTG9hZCBwYWNrYWdlcw0KaWYgKCFyZXF1aXJlKCJwYWNtYW4iKSkgaW5zdGFsbC5wYWNrYWdlcygicGFjbWFuIikNCnBhY2thZ2VzIDwtIGMoDQogICJwYXBhamEiLA0KICAidGlkeXZlcnNlIiwgICAgICAgDQogICJicm9vbSIsICJyc3RhdGl4IiwNCiAgImdncGxvdDIiLCAiZ2dwdWJyIiwgInNjYWxlcyIsICAgICAgICANCiAgInJpbyIsDQogICJnZ3N0YXRzcGxvdCINCiAgIyAsIC4uLg0KKQ0KaWYgKCFyZXF1aXJlKCJwYWNtYW4iKSkgaW5zdGFsbC5wYWNrYWdlcygicGFjbWFuIikNCnBhY21hbjo6cF9sb2FkKGNoYXIgPSBwYWNrYWdlcykNCg0KIyBUaGVtZXMgZm9yIGdncGxvdDIgcGxvdGluZyAoaGVyZSB1c2VkIEFQQSBzdHlsZSkNCnRoZW1lX3NldCh0aGVtZV9hcGEoKSkNCmBgYA0KDQoNCg0KDQoNCjwhLS0gUmVwb3J0IC0tPg0KDQojIERlZmluZSBmdW5jdGlvbnMNCg0KYGBge3IgZGVmX2Z1bmN9DQojIyBEZWZpbmUgZnVuY3Rpb24gdGhhdCByZWNvZGVzIHRvIG51bWVyaWMsIGJ1dCB3YXRjaGVzIG91dCB0byBjb2VyY2lvbiB0byBub3QgaW50cm9kdWNlIE5Bcw0KY29sc3RvbnVtZXJpYyA8LSBmdW5jdGlvbihkZil7DQogIHRyeUNhdGNoKHsNCiAgICBkZl9udW0gPC0gYXMuZGF0YS5mcmFtZSgNCiAgICAgIGxhcHBseShkZiwNCiAgICAgICAgICAgICBmdW5jdGlvbih4KSB7IGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKHgpKX0pKSANCiAgfSx3YXJuaW5nID0gZnVuY3Rpb24oc3RvcF9vbl93YXJuaW5nKSB7DQogICAgbWVzc2FnZSgiU3RvcGVkIHRoZSBleGVjdXRpb24gb2YgbnVtZXJpYyBjb252ZXJzaW9uOiAiLCBjb25kaXRpb25NZXNzYWdlKHN0b3Bfb25fd2FybmluZykpDQogIH0pIA0KfQ0KIyMNCiMjIERlZmluZSBmdW5jdGlvbiB0aGF0IHJldmVyc2UgY29kZXMgaXRlbXMNClJldmVyc2VDb2RlIDwtIGZ1bmN0aW9uKGRmLCB0b251bWVyaWMgPSBGQUxTRSwgbWluID0gTlVMTCwgbWF4ID0gTlVMTCkgew0KICBpZih0b251bWVyaWMpIGRmIDwtIGNvbHN0b251bWVyaWMoZGYpDQogIGRmIDwtIChtYXggKyBtaW4pIC0gZGYNCn0NCiMjDQojIyBEZWZpbmUgZnVuY3Rpb24gdGhhdCBzY29yZXMgb25seSByb3dzIHdpdGggbGVzcyB0aGFuIDEwJSBOQXMgKHJldHVybnMgTkEgaWYgYWxsIG9yIGFib3ZlIHRocmVzaG9sZCBwZXJjZW50YWdlIG9mIHJvd3MgYXJlIE5BKTsgY2FuIHJldmVyc2UgY29kZSBpZiB2ZWN0b3Igb2YgY29sdW1uIGluZGV4ZXMgYW5kIG1pbiwgbWF4IGFyZSBwcm92aWRlZC4NClNjb3JlTGlrZXJ0IDwtIGZ1bmN0aW9uKGRmLCBuYXBlcmNlbnQgPSAuMSwgdG9udW1lcmljID0gRkFMU0UsIHJldmVyc2Vjb2xzID0gTlVMTCwgbWluID0gTlVMTCwgbWF4ID0gTlVMTCkgew0KICByZXZlcnNlX2xpc3QgPC0gbGlzdChyZXZlcnNlY29scyA9IHJldmVyc2Vjb2xzLCBtaW4gPSBtaW4sIG1heCA9IG1heCkNCiAgcmV2ZXJzZV9jaGVjayA8LSAhc2FwcGx5KHJldmVyc2VfbGlzdCwgaXMubnVsbCkNCiAgDQogICMgUmVjb2RlIHRvIG51bWVyaWMsIGJ1dCB3YXRjaCBvdXQgdG8gY29lcmNpb24gdG8gbm90IGludHJvZHVjZSBOQXMNCiAgY29sc3RvbnVtZXJpYyA8LSBmdW5jdGlvbihkZil7DQogICAgdHJ5Q2F0Y2goew0KICAgICAgZGZfbnVtIDwtIGFzLmRhdGEuZnJhbWUoDQogICAgICAgIGxhcHBseShkZiwNCiAgICAgICAgICAgICAgIGZ1bmN0aW9uKHgpIHsgYXMubnVtZXJpYyhhcy5jaGFyYWN0ZXIoeCkpfSkpIA0KICAgIH0sd2FybmluZyA9IGZ1bmN0aW9uKHN0b3Bfb25fd2FybmluZykgew0KICAgICAgbWVzc2FnZSgiU3RvcGVkIHRoZSBleGVjdXRpb24gb2YgbnVtZXJpYyBjb252ZXJzaW9uOiAiLCBjb25kaXRpb25NZXNzYWdlKHN0b3Bfb25fd2FybmluZykpDQogICAgfSkgDQogIH0NCiAgDQogIGlmKHRvbnVtZXJpYykgZGYgPC0gY29sc3RvbnVtZXJpYyhkZikNCiAgDQogIGlmKGFsbChyZXZlcnNlX2NoZWNrKSl7DQogICAgZGZbICxyZXZlcnNlY29sc10gPC0gKG1heCArIG1pbikgLSBkZlsgLHJldmVyc2Vjb2xzXQ0KICB9ZWxzZSBpZihhbnkocmV2ZXJzZV9jaGVjaykpew0KICAgIHN0b3AoIkluc3VmaWNpZW50IGluZm8gZm9yIHJldmVyc2luZy4gUGxlYXNlIHByb3ZpZGU6ICIsIHBhc3RlKG5hbWVzKHJldmVyc2VfbGlzdClbIXJldmVyc2VfY2hlY2tdLCBjb2xsYXBzZSA9ICIsICIpKQ0KICB9DQogIA0KICBpZmVsc2Uocm93U3Vtcyhpcy5uYShkZikpID4gbmNvbChkZikgKiBuYXBlcmNlbnQsDQogICAgICAgICBOQSwNCiAgICAgICAgIHJvd1N1bXMoZGYsIG5hLnJtID0gVFJVRSkgKiBOQSBeIChyb3dTdW1zKCFpcy5uYShkZikpID09IDApDQogICkNCn0NCiMjDQpgYGANCg0KDQpgYGB7cn0NCm15X2dnd2l0aGluc3RhdHMgPC0gZnVuY3Rpb24oZGF0YSwgdGl0bGUsIHgsIHksIG91dGxpZXIubGFiZWwsIHhsYWIsIHlsYWIpIHsNCiAgeCA8LSBybGFuZzo6ZW5xdW8oeCkNCiAgeSA8LSBybGFuZzo6ZW5xdW8oeSkNCiAgb3V0bGllci5sYWJlbCA8LSBybGFuZzo6ZW5xdW8ob3V0bGllci5sYWJlbCkNCiAgDQogIGRhdGEgJT4lDQogICAgZ2dzdGF0c3Bsb3Q6Omdnd2l0aGluc3RhdHMoDQogICAgICB4ID0gISF4LA0KICAgICAgeSA9ICEheSwNCiAgICAgIHRpdGxlID0gdGl0bGUsDQogICAgICB4bGFiID0geGxhYiwNCiAgICAgIHlsYWIgPSB5bGFiLA0KICAgICAgb3V0bGllci50YWdnaW5nID0gVFJVRSwgICAgICAgICAgICAjIHdoZXRoZXIgb3V0bGllcnMgbmVlZCB0byBiZSB0YWdnZWQNCiAgICAgIG91dGxpZXIubGFiZWwgPSAhIW91dGxpZXIubGFiZWwsICAgIyB2YXJpYWJsZSB0byBiZSB1c2VkIGZvciB0YWdnaW5nIG91dGxpZXJzDQogICAgICBvdXRsaWVyLmNvZWYgPSAyLA0KICAgICAgcGFpcndpc2UuY29tcGFyaXNvbnMgPSBUUlVFLA0KICAgICAgcGFpcndpc2UuZGlzcGxheSA9ICJzaWduaWZpY2FudCIsDQogICAgICByZXN1bHRzLnN1YnRpdGxlID0gVFJVRSwNCiAgICAgIHR5cGUgPSAicGFyYW1ldHJpYyIsDQogICAgICBiZi5tZXNzYWdlID0gRkFMU0UsIA0KICAgICAgcC5hZGp1c3QubWV0aG9kID0gIm5vbmUiLA0KICAgICAgcG9pbnQucGF0aCA9IFRSVUUsDQogICAgICBnZ3RoZW1lID0gZ2dwcmlzbTo6dGhlbWVfcHJpc20oKSwNCiAgICAgICMgcGFja2FnZSA9ICJSQ29sb3JCcmV3ZXIiLCAgIyAiZ2dzY2kiLA0KICAgICAgIyBwYWxldHRlID0gIkRhcmsiLCAgICAgICAgICMgImRlZmF1bHRfamNvIiwNCiAgICAgIHZpb2xpbi5hcmdzID0gbGlzdCh3aWR0aCA9IDAuOSwgYWxwaGEgPSAwLjIsIHNpemUgPSAxLCBjb2xvciA9ICJibGFjayIpLA0KICAgICAgY2VudHJhbGl0eS5wb2ludC5hcmdzID0gbGlzdChzaXplID0gNSwgY29sb3IgPSAiZGFya3JlZCIpLA0KICAgICAgY2VudHJhbGl0eS5sYWJlbC5hcmdzID0gbGlzdChzaXplID0gMywgbnVkZ2VfeCA9IDAuMiwgc2VnbWVudC5saW5ldHlwZSA9IDUsIGZpbGwgPSAiI0ZGRjhFNyIpLCANCiAgICAgIGdncGxvdC5jb21wb25lbnQgPSBsaXN0KA0KICAgICAgICB0aGVtZSgNCiAgICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMCwgc2l6ZSA9IDE2KSwNCiAgICAgICAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMCwgc2l6ZSA9IDEyKSwgDQogICAgICAgICAgcGxvdC5jYXB0aW9uID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMCwgc2l6ZSA9IDEyKSwgDQogICAgICAgICAgdGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQpDQogICAgICApKQ0KICAgICkgKyBzY2FsZV9jb2xvdXJfZ3JleShzdGFydCA9IDAuMiwgZW5kID0gMC4yKSAgICMgaGFja3kgd2F5IHRvIGNoYW5nZSBwb2ludCBjb2xvcg0KfQ0KDQojIEZvciBwdWJsaWNhdGlvbg0KbXlfZ2d3aXRoaW5zdGF0czIgPC0gZnVuY3Rpb24oZGF0YSwgdGl0bGUsIHgsIHksIG91dGxpZXIubGFiZWwsIHhsYWIsIHlsYWIsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3V0bGllci50YWdnaW5nID0gRkFMU0UsIHJlc3VsdHMuc3VidGl0bGUgPSBUUlVFLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNlbnRyYWxpdHkubGFiZWwuYXJncyA9IFRSVUUsIHBvaW50LnBhdGggPSBUUlVFLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdHlwZSA9ICJwYXJhbWV0cmljIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuLi4pIHsgICMgLi4uIGZvciBsaW1pdHMgYW5kIGJyZWFrcw0KICB4IDwtIHJsYW5nOjplbnF1byh4KQ0KICB5IDwtIHJsYW5nOjplbnF1byh5KQ0KICBvdXRsaWVyLmxhYmVsIDwtIHJsYW5nOjplbnF1byhvdXRsaWVyLmxhYmVsKQ0KICANCiAgaWYoY2VudHJhbGl0eS5sYWJlbC5hcmdzKXsNCiAgICBjZW50cmFsaXR5LmxhYmVsLmFyZ3MgPC0gbGlzdChzaXplID0gMywgbnVkZ2VfeCA9IDAuMiwgc2VnbWVudC5saW5ldHlwZSA9IDUsIGZpbGwgPSAiI0ZGRjhFNyIpDQogIH1lbHNlew0KICAgIGNlbnRyYWxpdHkubGFiZWwuYXJncyA8LSBsaXN0KHNpemUgPSAwLCBudWRnZV94ID0gMTAsIHNlZ21lbnQubGluZXR5cGUgPSAwLCBhbHBoYSA9IDApICMgdmVyeSBoYWNreSB3YXkgb2Ygbm90IHNob3dpbmcgbGFiZWwNCiAgfQ0KICANCiAgZGF0YSAlPiUNCiAgICBnZ3N0YXRzcGxvdDo6Z2d3aXRoaW5zdGF0cygNCiAgICAgIHggPSAhIXgsDQogICAgICB5ID0gISF5LA0KICAgICAgdGl0bGUgPSB0aXRsZSwNCiAgICAgIHhsYWIgPSB4bGFiLA0KICAgICAgeWxhYiA9IHlsYWIsDQogICAgICBvdXRsaWVyLnRhZ2dpbmcgPSBvdXRsaWVyLnRhZ2dpbmcsICAgICAgICAgICAgICAgICAgICAjIHdoZXRoZXIgb3V0bGluZXMgbmVlZCB0byBiZSB0YWdnZWQNCiAgICAgIG91dGxpZXIubGFiZWwgPSAhIW91dGxpZXIubGFiZWwsICAgICAgICAgICAgICAgICAgICAgICMgdmFyaWFibGUgdG8gYmUgdXNlZCBmb3IgdGFnZ2luZyBvdXRsaWVycw0KICAgICAgb3V0bGllci5jb2VmID0gMiwNCiAgICAgIHBhaXJ3aXNlLmNvbXBhcmlzb25zID0gVFJVRSwNCiAgICAgIHBhaXJ3aXNlLmRpc3BsYXkgPSAiYWxsIiwNCiAgICAgIHJlc3VsdHMuc3VidGl0bGUgPSByZXN1bHRzLnN1YnRpdGxlLA0KICAgICAgdHlwZSA9IHR5cGUsDQogICAgICBiZi5tZXNzYWdlID0gRkFMU0UsIA0KICAgICAgcC5hZGp1c3QubWV0aG9kID0gIm5vbmUiLA0KICAgICAgcG9pbnQucGF0aCA9IHBvaW50LnBhdGgsDQogICAgICBnZ3RoZW1lID0gZ2dwcmlzbTo6dGhlbWVfcHJpc20oKSwNCiAgICAgICMgcGFja2FnZSA9ICJSQ29sb3JCcmV3ZXIiLCAgIyAiZ2dzY2kiLA0KICAgICAgIyBwYWxldHRlID0gIkRhcmsiLCAgICAgICAgICMgImRlZmF1bHRfamNvIiwNCiAgICAgIHZpb2xpbi5hcmdzID0gbGlzdCh3aWR0aCA9IDAuOSwgYWxwaGEgPSAwLjIsIHNpemUgPSAxLCBjb2xvciA9ICJibGFjayIpLA0KICAgICAgY2VudHJhbGl0eS5wbG90dGluZyA9IFRSVUUsDQogICAgICBjZW50cmFsaXR5LnR5cGUgPSAicGFyYW1ldGVyaWMiLA0KICAgICAgY2VudHJhbGl0eS5wb2ludC5hcmdzID0gbGlzdChzaXplID0gNSwgY29sb3IgPSAiZGFya3JlZCIpLA0KICAgICAgY2VudHJhbGl0eS5sYWJlbC5hcmdzID0gY2VudHJhbGl0eS5sYWJlbC5hcmdzLA0KICAgICAgZ2dwbG90LmNvbXBvbmVudCA9IGxpc3QoDQogICAgICAgIHRoZW1lKA0KICAgICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLCBzaXplID0gMTYpLA0KICAgICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLCBzaXplID0gMTIpLCANCiAgICAgICAgICBwbG90LmNhcHRpb24gPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLCBzaXplID0gMTIpLCANCiAgICAgICAgICB0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNCkNCiAgICAgICkpDQogICAgKSArIHNjYWxlX2NvbG91cl9ncmV5KHN0YXJ0ID0gMC4yLCBlbmQgPSAwLjIpICsgICMgaGFja3kgd2F5IHRvIGNoYW5nZSBwb2ludCBjb2xvcg0KICAgIHNjYWxlX3lfY29udGludW91cyguLi4pDQp9DQoNCiMgRmFzdCBnZ3NhdmUgLSBzYXZlcyBwbG90IHdpdGggZmlsZW5hbWUgb2YgUiBwbG90IG9iamVjdA0KZmFzdF9nZ3NhdmUgPC0gZnVuY3Rpb24ocGxvdCwgZGV2aWNlID0gInBuZyIsIHBhdGggPSBOVUxMLA0KICAgICAgICAgICAgICAgICAgICAgICAgdW5pdHMgPSAiaW4iLCBkcGkgPSAzMDAsIHdpZHRoID0gNSwgaGVpZ2h0ID0gNSwgLi4uKXsgDQogIHBsb3RfbmFtZSA8LSBkZXBhcnNlKHN1YnN0aXR1dGUocGxvdCkpDQogIGdncGxvdDI6Omdnc2F2ZShmaWxlbmFtZSA9IHBhc3RlMChwbG90X25hbWUsICIuIiwgZGV2aWNlKSwgcGxvdCA9IHBsb3QsDQogICAgICAgICAgICAgICAgICBkZXZpY2UgPSBkZXZpY2UsIHBhdGggPSBwYXRoLA0KICAgICAgICAgICAgICAgICAgdW5pdHMgPSB1bml0cywgZHBpID0gZHBpLA0KICAgICAgICAgICAgICAgICAgd2lkdGggPSB3aWR0aCwgaGVpZ2h0ID0gaGVpZ2h0LA0KICAgICAgICAgICAgICAgICAgLi4uDQogICkNCiAgDQp9ICMgdXNlOiBmYXN0X2dnc2F2ZShqcmFkX294X3AsIHBhdGggPSBzYXZlZm9sZGVyKQ0KYGBgDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KIyBSZWFkLCBDbGVhbiwgUmVjb2RlDQoNCmBgYHtyIHJlZF9jbGVhbl9yZWNvZGVfbWVyZ2UsIHJlc3VsdHM9J2hpZGUnLCBtZXNzYWdlPUZBTFNFfQ0KI35+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+fn4NCiMgUmVhZCwgQ2xlYW4sIFJlY29kZSwgVW5pdGUNCiN+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+DQoNCiMjIFJlYWQgZmlsZXMNCmZvbGRlciA8LSAiQzovVXNlcnMvTWloYWkvRGVza3RvcC9SIE5vdGVib29rcy9ub3RlYm9va3MvcGlsb3RBMTAiDQpmaWxlIDwtICJBUFMgQTEwLnhsc3giDQoNCnNldHdkKGZvbGRlcikNCg0KIyBSZWFkIGRhdGENCmRhdGEgPC0gcmlvOjppbXBvcnQoZmlsZS5wYXRoKGZvbGRlciwgZmlsZSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2tpcCA9IDAsIHdoaWNoID0gIkFQUyIpDQoNCmRhdGEgPC0gDQogIGRhdGEgJT4lDQogIGRwbHlyOjpyZW5hbWVfd2l0aCguY29sID0gMTM6MjksIH4gYyhzcHJpbnRmKCJBUFNfJWQiLCAxOjE2KSwgImlkIikpICU+JQ0KICAgIGRwbHlyOjptdXRhdGUoaWQgPSBzdHJpbmdyOjpzdHJfcmVtb3ZlKGlkLCAiXjArIiksICAgICAgICAgICAgICAgICAgICAjIHJlbW92ZSBsZWFkaW5nIHplcm9zDQogICAgICAgICAgICAgICAgaWQgPSBzdHJpbmdyOjpzdHJfcmVtb3ZlX2FsbChpZCwgIltbOmJsYW5rOl1dIiksICAgICAgICAgICMgcmVtb3ZlIGFueSB3aGl0ZSBzcGFjZQ0KICAgICAgICAgICAgICAgIGlkID0gIHRvdXBwZXIoaWQpKSAlPiUgDQogIGRwbHlyOjpzZWxlY3QoMTM6MjkpICU+JQ0KICBkcGx5cjo6ZmlsdGVyKGFjcm9zcyhhbGxfb2YoYygiQVBTXzEiLCAiQVBTXzIiLCAiQVBTXzMiKSksIH4gIWlzLm5hKC54KSkpICAgICMgaWYgbWlzc2luZyBhbGwgMyBpdGVtcyB0aGVuIGRyb3Agcm93IChub25zZW5zZSBpbmZvKQ0KDQojIEFkZCBQcmVQb3N0IENvbHVtbg0KZGF0YSA8LSANCiAgZGF0YSAlPiUNCiAgZHBseXI6Omdyb3VwX2J5KGlkKSAlPiUgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGNhbiBkbyBhcnJhbmdlIG9uIERhdGVzIGNvbHVtbiBpZiByb3dzIGFyZSBub3QgaW4gb3JkZXIsIGJ1dCBoZXJlIHRoZXkgYXJlDQogIGRwbHlyOjptdXRhdGUobnVtYmVyaW5nID0gcm93X251bWJlcigpKSAlPiUNCiAgZHBseXI6Om11dGF0ZShQcmVQb3N0ID0gZHBseXI6OmNhc2Vfd2hlbihudW1iZXJpbmcgPT0gMSB+ICJQcmUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG51bWJlcmluZyA9PSAyIH4gIlBvc3QiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG51bWJlcmluZyA9PSAzIH4gIkZfdXAiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiAiT3RoZXIiKSkgJT4lIA0KICBkcGx5cjo6dW5ncm91cCgpICU+JQ0KICBkcGx5cjo6bXV0YXRlKFByZVBvc3QgPSBmYWN0b3IoUHJlUG9zdCwgbGV2ZWxzID0gYygiUHJlIiwgIlBvc3QiLCAiRl91cCIpKSkNCg0KdGFibGUoZGF0YSRpZCwgZGF0YSRQcmVQb3N0KSAgICMgY2hlY2sgLS0gIFNvZmk6IEYtdXAgbWlzc2luZyBmb3IgaWQgNiw3LDEzLDE4LDE5LDIxDQoNCiMgQWRkIENvbmQNCmlkX2RmIDwtIHJpbzo6aW1wb3J0KGZpbGUucGF0aChmb2xkZXIsIGZpbGUpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNraXAgPSAwLCB3aGljaCA9ICJJZHVyaSIpDQoNCmlkX2RmIDwtIA0KICBpZF9kZiAlPiUNCiAgZHBseXI6OnJlbmFtZV93aXRoKC5jb2wgPSBldmVyeXRoaW5nKCksIH4gYygiQ29uZCIsICJpZCIsICJlbWFpbCIpKSAlPiUNCiAgICBkcGx5cjo6bXV0YXRlKGlkID0gc3RyaW5ncjo6c3RyX3JlbW92ZShpZCwgIklEIikpICU+JQ0KICAgIGRwbHlyOjptdXRhdGUoaWQgPSBzdHJpbmdyOjpzdHJfcmVtb3ZlX2FsbChpZCwgIltbOmJsYW5rOl1dIiksICAgICAgICAgICMgcmVtb3ZlIGFueSB3aGl0ZSBzcGFjZQ0KICAgICAgICAgICAgICAgICAgaWQgPSBzdHJpbmdyOjpzdHJfcmVtb3ZlKGlkLCAiXjArIiksICAgICAgICAgICAgICAgICAgICAgIyByZW1vdmUgbGVhZGluZyB6ZXJvcw0KICAgICAgICAgICAgICAgICAgaWQgPSAgdG91cHBlcihpZCkpICANCg0KZGF0YSA8LSBkcGx5cjo6bGVmdF9qb2luKGRhdGEsIGlkX2RmLCBieSA9ICJpZCIpDQpgYGANCg0KDQoNCiMjIFNjb3JlIEFQUw0KYGBge3J9DQojIFJlY29kZQ0KIyBkYXRhIDwtDQojICAgZGF0YSAlPiUNCiMgICBkcGx5cjo6bXV0YXRlX2F0KHZhcnMoc3ByaW50ZigiQVBTXyVkIiwgMToxNikpLCB+Y2FzZV93aGVuKC4gPT0gIm5pY2lvZGF0xIMgLyBhcHJvYXBlIG5pY2lvZGF0xIMgYWRldsSDcmF0IiB+IDEsDQojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuID09ICJvY2F6aW9uYWwgYWRldsSDcmF0IiB+IDIsDQojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuID09ICJjw6J0ZW9kYXTEgyBhZGV2xINyYXQiIH4gMywNCiMgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC4gPT0gImRlc2VvcmkgYWRldsSDcmF0IiB+IDQsDQojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuID09ICJhcHJvYXBlIMOubnRvdGRlYXVuYS/Drm50b3RkZWF1bmEgYWRldsSDcmF0IiB+IDUsDQojICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gTkFfcmVhbF8pKQ0KDQoNCiMgVXBkYXRlZCBiZWNhdXNlIHNwZWNpYWwgY2hhcmFjdGVycyB3ZXJlIG5vdCByZWNvZ25pemVkIC0tIHJlcGxhY2VkIGFzIHdpbGQgY2FyZHMgaW4gcmVnZXgNCmRhdGFbLCBzcHJpbnRmKCJBUFNfJWQiLCAxOjE2KV0gPC0NCiAgZGF0YVssIHNwcmludGYoIkFQU18lZCIsIDE6MTYpXSAlPiUNCiAgZHBseXI6Om11dGF0ZV9hbGwofmNhc2Vfd2hlbihzdHJpbmdyOjpzdHJfZGV0ZWN0KC4sICJuaWNpb2RhdCoiKSB+IDEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyaW5ncjo6c3RyX2RldGVjdCguLCAib2NhemlvbmFsKiIpIH4gMiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdHJpbmdyOjpzdHJfZGV0ZWN0KC4sICJjP3Rlb2RhdCoiKSB+IDMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyaW5ncjo6c3RyX2RldGVjdCguLCAiZGVzZW9yaSoiKSB+IDQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3RyaW5ncjo6c3RyX2RldGVjdCguLCAibnRvdGRlYXVuYSIpIH4gNSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiBOQV9yZWFsXykpDQoNCiMgU2NvcmUNCmRhdGEkQVBTX1RvdGFsIDwtIFNjb3JlTGlrZXJ0KGRhdGFbLCBzcHJpbnRmKCJBUFNfJWQiLCAxOjE2KV0sIG5hcGVyY2VudCA9IC4xMykNCmBgYA0KDQoNCg0KDQojIyBBUFMNCg0KYGBge3IgcHJlcG9zdH0NCmRhdGEgJT4lDQogIGRwbHlyOjpmaWx0ZXIoQ29uZCA9PSAiZXhwZXJpbWVudGFsIikgJT4lDQogIGRwbHlyOjpmaWx0ZXIoUHJlUG9zdCAlaW4lIGMoIlByZSIsICJQb3N0IikpICU+JQ0KICBteV9nZ3dpdGhpbnN0YXRzMih4ID0gUHJlUG9zdCwgeSA9IEFQU19Ub3RhbCwgb3V0bGllci5sYWJlbCA9IGlkLCB0eXBlID0gIm5wIiwgIA0KICAgICAgICAgICAgICAgICAgICB4bGFiID0gIiIsIHlsYWIgPSAiQVBTIiwNCiAgICAgICAgICAgICAgICAgICAgdGl0bGUgPSAiRXhwZXJpbWVudGFsIikNCg0KZGF0YSAlPiUNCiAgZHBseXI6OmZpbHRlcihDb25kID09ICJjdHJsIikgJT4lDQogIGRwbHlyOjpmaWx0ZXIoUHJlUG9zdCAlaW4lIGMoIlByZSIsICJQb3N0IikpICU+JQ0KICBteV9nZ3dpdGhpbnN0YXRzMih4ID0gUHJlUG9zdCwgeSA9IEFQU19Ub3RhbCwgb3V0bGllci5sYWJlbCA9IGlkLCB0eXBlID0gIm5wIiwNCiAgICAgICAgICAgICAgICAgICAgeGxhYiA9ICIiLCB5bGFiID0gIkFQUyIsDQogICAgICAgICAgICAgICAgICAgIHRpdGxlID0gIkNvbnRyb2wiKQ0KYGBgDQoNCmBgYHtyIHByZXBvc3RmdXAsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTh9DQpkYXRhICU+JQ0KICBkcGx5cjo6ZmlsdGVyKENvbmQgPT0gImV4cGVyaW1lbnRhbCIpICU+JQ0KICBncm91cF9ieShpZCkgJT4lDQogIGRwbHlyOjpmaWx0ZXIoIW4oKSA8IDMpICU+JSAgICAgICAgICAgICAgICAgICAgICMgZmlsdGVyIG91dCB0aG9zZSB3aXRob3V0IEZfdXANCiAgbXlfZ2d3aXRoaW5zdGF0czIoeCA9IFByZVBvc3QsIHkgPSBBUFNfVG90YWwsIG91dGxpZXIubGFiZWwgPSBpZCwgdHlwZSA9ICJucCIsICANCiAgICAgICAgICAgICAgICAgICAgeGxhYiA9ICIiLCB5bGFiID0gIkFQUyIsDQogICAgICAgICAgICAgICAgICAgIHRpdGxlID0gIkV4cGVyaW1lbnRhbCIpDQoNCmRhdGEgJT4lDQogIGRwbHlyOjpmaWx0ZXIoQ29uZCA9PSAiY3RybCIpICU+JQ0KICBncm91cF9ieShpZCkgJT4lDQogIGRwbHlyOjpmaWx0ZXIoIW4oKSA8IDMpICU+JSAgICAgICAgICAgICAgICAgICAgICMgZmlsdGVyIG91dCB0aG9zZSB3aXRob3V0IEZfdXANCiAgbXlfZ2d3aXRoaW5zdGF0czIoeCA9IFByZVBvc3QsIHkgPSBBUFNfVG90YWwsIG91dGxpZXIubGFiZWwgPSBpZCwgdHlwZSA9ICJucCIsDQogICAgICAgICAgICAgICAgICAgIHhsYWIgPSAiIiwgeWxhYiA9ICJBUFMiLA0KICAgICAgICAgICAgICAgICAgICB0aXRsZSA9ICJDb250cm9sIikNCmBgYA0KDQoNCg0KDQoNCg0KPCEtLSBTZXNzaW9uIEluZm8gYW5kIExpY2Vuc2UgLS0+DQoNCjxicj4NCg0KIyBTZXNzaW9uIEluZm8NCmBgYHtyIHNlc3Npb25faW5mbywgZWNobyA9IEZBTFNFLCByZXN1bHRzID0gJ21hcmt1cCd9DQpzZXNzaW9uSW5mbygpICAgIA0KYGBgDQoNCjwhLS0gRm9vdGVyIC0tPg0KJm5ic3A7DQo8aHIgLz4NCjxwIHN0eWxlPSJ0ZXh0LWFsaWduOiBjZW50ZXI7Ij5BIHdvcmsgYnkgPGEgaHJlZj0iaHR0cHM6Ly9naXRodWIuY29tL0NsYXVkaXVQYXBhc3RlcmkvIj5DbGF1ZGl1IFBhcGFzdGVyaTwvYT48L3A+DQo8cCBzdHlsZT0idGV4dC1hbGlnbjogY2VudGVyOyI+PHNwYW4gc3R5bGU9ImNvbG9yOiAjODA4MDgwOyI+PGVtPmNsYXVkaXUucGFwYXN0ZXJpQGdtYWlsLmNvbTwvZW0+PC9zcGFuPjwvcD4NCiZuYnNwOw0K