1 Run demoimitMetrics_cleantable script

script_folder <- "C:/Users/Mihai/Desktop/R Notebooks/notebooks/STAD-demoimitMetrics/Scripts" 
script_name <- "demoimitMetrics_to_cleantable.R"
source(file.path(script_folder, script_name))

2 Data

2.1 Info:

  • Demo scores

    • object response by navigator (individual score) (GameState 9 => newGameState 10)
  • Imitation scores

    • 1st row for start (GameState 14 => newGameState 15)
    • 2nd row for flag (GameState 15 => newGameState 16)
    • 3rd row = first object response by navigator (individual score) (GameState 16 => newGameState 17)
    • 4th row = suggestion marker by observer (observer score) (GameState 17 => newGameState 18)
    • 5th row = 2nd object response by navigator (collaborative score) (GameState 18 => newGameState 19)
  • Variables:

    • id categorical - unique identifier
    • condition categorical - “social” or “bot”
    • order categorical - 1 or 2 the order of conditions
    • who catergorical - 1 or 2 codes for who’s recording it is (data only for current id is when: who == playerType)
    • newGameState_clean categorical - codes for GameStates (5-11 are Demo, 12-20 are Imit)
    • demoimitState_clean categorical - “Demo” or “Imit” depending on state
    • playerType categorical - 1 or 2 depending on GameState (should be used together with var who)
    • markerType categorical - codes for the object (see documentation), but it actually follows the the above Info (dependes on GameState)
    • score continuous - follows the the above Info (depends on GameState)
full_data_output_clean %>%
  DT::datatable(                                  # excel downloadable  DT table
  extensions = 'Buttons',
  options = list(pageLength = 5,
                 scrollX = '500px', 
                 dom = 'Bfrtip', 
                 buttons = c('excel', "csv"))) %>%
  DT::formatStyle(names(full_data_output_clean),lineHeight = "60%")    # slimmer rows

3 Preliminary Analyses

3.0.1 Functions

plot_growth_state_id <- function(data, cond, gamestate, time_lim = 20) {
  data %>%
  dplyr::filter(condition == cond, newGameState_clean == gamestate) %>%
  group_by(id) %>%
  dplyr::mutate(time = dplyr::row_number()) %>%
  dplyr::filter(time < time_lim) %>%  
    ggplot(aes(x = time, y = score)) +
    geom_line() +
    facet_wrap(~id) +
    ylim(0, 100) +
    scale_x_continuous(breaks = 1:14) +
    ggtitle(paste0("Condition: ", cond, ", ", "Game state: ", gamestate))
}

# e.g.
# full_data_output_clean %>%
#   dplyr::filter(condition == "bot", newGameState_clean == "10") %>%
#   group_by(id) %>%
#   dplyr::mutate(time = dplyr::row_number()) %>%
#   ggplot(aes(x = time, y = score)) +
#   geom_line() +
#   facet_wrap(~id)

plot_growth_state_loess <- function(data, cond, gamestate, time_lim = 20) {
  data %>%
  dplyr::filter(condition == cond, newGameState_clean == gamestate) %>%
  group_by(id) %>%
  dplyr::mutate(time = dplyr::row_number()) %>%
  dplyr::filter(time < time_lim) %>%   
    ggplot(aes(x = time, y = score)) +
    geom_line(aes(color = as.factor(id)), alpha = .5) +
    geom_smooth(method = "loess", formula = "y ~ x", color = "red", fill = "red") +
    geom_smooth(method = "lm", formula = y ~ splines::bs(x, knots = seq(2 , 16, by = 2), degree = 1), 
                se = FALSE, color = "black", fill = "gray", alpha = 0.8) +
    ylim(0, 100) +
    scale_x_continuous(breaks = 1:14) +
    ggtitle(paste0("Condition: ", cond, ", ", "Game state: ", gamestate)) +
    labs(color = "id")  
}
  
# e.e.
# full_data_output_clean %>%
# dplyr::filter(condition == "bot", newGameState_clean == "10") %>%
# group_by(id) %>%
# dplyr::mutate(time = dplyr::row_number()) %>%
# ggplot(aes(x = time, y = score)) +
# geom_line(aes(color = as.factor(id)), alpha = .5) +
# geom_smooth(method = "loess", formula = "y ~ x")

plot_growth_state1017_id <- function(data, conds = c("social", "bot"), time_lim = 20) {
  data %>%
  dplyr::filter(condition %in% conds, newGameState_clean %in% c("10", "17")) %>%
  dplyr::mutate(newGameState_clean = as.factor(newGameState_clean)) %>%  
  dplyr::group_by(id, condition) %>%
  dplyr::mutate(time = dplyr::row_number()) %>%
  dplyr::filter(time < time_lim) %>% 
    ggplot(aes(x = time, y = score, color = condition)) +
    geom_line() +
    geom_point(aes(shape = newGameState_clean)) +
    facet_wrap(~id) +
    ylim(0, 100) +
    scale_x_continuous(breaks = 1:14) +
    ggtitle("Alternating GameState 10 and 17") + 
    theme(legend.position = "right")
}



my_ggwithinstats2 <- function(data, title = NULL, x, y, gamestate, time_lim = 20, 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(is.null(title)) {
    title <- paste0("Game state: ", gamestate)
  }
  
  data <-
    data %>%
    dplyr::select(!!outlier.label, !!x, !!y, newGameState_clean) %>%      # newGameState_clean is hardcoded here
    dplyr::filter(newGameState_clean == gamestate) %>%
    group_by(!!outlier.label, !!x) %>%
    dplyr::mutate(time = dplyr::row_number()) %>%
    dplyr::filter(time < time_lim) %>%   
    dplyr::summarise(mean_score = mean(!!y, na.rm = TRUE))
    
  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 = mean_score,              # here we have the mean score for id, not !!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
    ylim(0, 100) +
    scale_y_continuous(...)
}

# e.g.
# my_ggwithinstats2(full_data_output_clean, x = condition, y = score, outlier.label = id, gamestate = 10,
#                   time_lim = 20, xlab = "Condition", ylab = "score")
                   

3.1 Check balance

3.1.1 All participants

counts_id_condord <-
  full_data_output_clean %>%
  dplyr::count(id, condition, order)

counts_id_condord %>%      # Participant 41 has 2 bot conditions: order = 1 and 1bis
  print(n = Inf)

counts_id_condord %>%
  dplyr::select(condition, order) %>%
  table() %>%
  knitr::kable(caption = "Order")
Order
1.0 1bis 2.0
bot 15 1 21
social 28 0 8

3.1.2 Participants with both conditions

# Participant 41 has 2 bot conditions: order = 1 and 1bis
ids_full_subj <-
  full_data_output_clean %>%
  dplyr::filter(order != "1bis") %>%   # exclude subj 41
  group_by(id, condition) %>%
  summarise(count = n()) %>%
  dplyr::filter(n() > 1) %>%
  dplyr::pull(id) %>%
  unique()

full_data_output_clean %>%
  dplyr::filter(id %in% ids_full_subj) %>%
  dplyr::count(id, condition, order) %>%
  dplyr::select(condition, order) %>%
  table() %>%
  knitr::kable(caption = "Order")
Order
1.0 2.0
bot 8 21
social 21 8

3.2 Individual growth (object not considered)

Notes:

  1. Variability is the norm

  2. Trend is not easily discernible

plot_growth_state_id(full_data_output_clean, "bot", "10")

plot_growth_state_id(full_data_output_clean, "social", "10")


plot_growth_state_id(full_data_output_clean, "bot", "15")

plot_growth_state_id(full_data_output_clean, "social", "15")


plot_growth_state_id(full_data_output_clean, "bot", "16")

plot_growth_state_id(full_data_output_clean, "social", "16")


plot_growth_state_id(full_data_output_clean, "bot", "17")

plot_growth_state_id(full_data_output_clean, "social", "17")


plot_growth_state_id(full_data_output_clean, "bot", "18")

plot_growth_state_id(full_data_output_clean, "social", "18")


plot_growth_state_id(full_data_output_clean, "bot", "19")

plot_growth_state_id(full_data_output_clean, "social", "19")

3.3 Individual growth (object not considered)

Red = Loess

Black = Spline regression (1st degree polynomial), knots = every second time point

Notes:

  1. Some participants have more trials than others

  2. There is a large dip in performance after a somewhat consistent number of trials

cowplot::plot_grid(
  plot_growth_state_loess(full_data_output_clean, "bot", "10") + theme(legend.position="none"),
  plot_growth_state_loess(full_data_output_clean, "social", "10") + theme(legend.position="none"),
  nrow = 2
)


cowplot::plot_grid(
  plot_growth_state_loess(full_data_output_clean, "bot", "15") + theme(legend.position="none"),
  plot_growth_state_loess(full_data_output_clean, "social", "15") + theme(legend.position="none"),  
  nrow = 2
)


cowplot::plot_grid(
  plot_growth_state_loess(full_data_output_clean, "bot", "16") + theme(legend.position="none"),
  plot_growth_state_loess(full_data_output_clean, "social", "16") + theme(legend.position="none"),  
  nrow = 2
)


cowplot::plot_grid(
  plot_growth_state_loess(full_data_output_clean, "bot", "17") + theme(legend.position="none"),
  plot_growth_state_loess(full_data_output_clean, "social", "17") + theme(legend.position="none"),  
  nrow = 2
)


cowplot::plot_grid(
  plot_growth_state_loess(full_data_output_clean, "bot", "18") + theme(legend.position="none"),
  plot_growth_state_loess(full_data_output_clean, "social", "18") + theme(legend.position="none"), 
  nrow = 2
)

  
cowplot::plot_grid(
  plot_growth_state_loess(full_data_output_clean, "bot", "19") + theme(legend.position="none"),
  plot_growth_state_loess(full_data_output_clean, "social", "19") + theme(legend.position="none"), 
  nrow = 2
)

3.4 Alternating GameStates 10 and 17 for each participant by condition

3.4.1 All participans

plot_growth_state1017_id(full_data_output_clean)

3.4.2 Partcipants with both conditions

full_data_output_clean %>%
  dplyr::filter(id %in% ids_full_subj) %>%
  plot_growth_state1017_id()

3.5 Individual average scores (mean)

Notes:

  1. These are trial-limited (limit is set at 5 trials)

  2. But: do not take condition order or markerType into consideration. Also, n refers to gamestate observations not ids.


my_ggwithinstats2(full_data_output_clean, x = condition, y = score, outlier.label = id, gamestate = 10,
                  time_lim = 5, xlab = "Condition", ylab = "score") %>%
  suppressMessages()


my_ggwithinstats2(full_data_output_clean, x = condition, y = score, outlier.label = id, gamestate = 15,
                  time_lim = 5, xlab = "Condition", ylab = "score") %>%
  suppressMessages()


my_ggwithinstats2(full_data_output_clean, x = condition, y = score, outlier.label = id, gamestate = 16,
                  time_lim = 5, xlab = "Condition", ylab = "score") %>%
  suppressMessages()


my_ggwithinstats2(full_data_output_clean, x = condition, y = score, outlier.label = id, gamestate = 17,
                  time_lim = 5, xlab = "Condition", ylab = "score") %>%
  suppressMessages()


my_ggwithinstats2(full_data_output_clean, x = condition, y = score, outlier.label = id, gamestate = 18,
                  time_lim = 5, xlab = "Condition", ylab = "score") %>%
  suppressMessages()


my_ggwithinstats2(full_data_output_clean, x = condition, y = score, outlier.label = id, gamestate = 19,
                  time_lim = 5, xlab = "Condition", ylab = "score") %>%
  suppressMessages()

3.5.1 GameState 19, only first object, individual level average

Order is not accounted for

plot_gs19_fisrt <- 
  full_data_output_clean %>%
  dplyr::select(id, condition, score, newGameState_clean, markerType) %>%      
  dplyr::filter(newGameState_clean == "19") %>%
  dplyr::group_by(id, condition) %>%  
  dplyr::mutate(first_marker = dplyr::if_else(markerType == dplyr::first(markerType), "yes", "no")) %>%  
  dplyr::filter(first_marker == "yes") %>%
  dplyr::mutate(time = dplyr::row_number()) %>%
    ggplot(aes(x = time, y = score)) +
    geom_line() +
    # facet_wrap(score ~ condition, strip.position = "top") +
    # facet_grid(condition ~ id) +    
    facet_grid(rows = vars(id), cols = vars(condition)) + 
    ylim(0, 100) +
    scale_x_continuous(breaks = 1:16) +
    ggtitle(paste0("Game state: ", "19")) +
    theme_bw() 

suppressMessages(print(plot_gs19_fisrt))

full_data_output_clean %>%
dplyr::select(id, condition, score, newGameState_clean, markerType) %>%      
dplyr::filter(newGameState_clean == "19") %>%
dplyr::group_by(id, condition) %>%  
dplyr::mutate(first_marker = dplyr::if_else(markerType == dplyr::first(markerType), "yes", "no")) %>%  
dplyr::filter(first_marker == "yes") %>%
dplyr::summarise(mean_score = mean(score, na.rm = TRUE)) %>%
  ggstatsplot::ggwithinstats(
    x = condition,
    y = mean_score,
    outlier.tagging = TRUE,                   
    outlier.label = id, 
    title = "GameState: 19"
  )


4 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
[4] LC_NUMERIC=C                      LC_TIME=Romanian_Romania.1250    
system code page: 1252

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

other attached packages:
 [1] rio_0.5.29         ggstatsplot_0.8.0  cowplot_1.1.1      scales_1.2.0       ggpubr_0.4.0       summarytools_1.0.0
 [7] rstatix_0.7.0      broom_0.7.11       psych_2.1.9        forcats_0.5.1      stringr_1.4.0      dplyr_1.0.9       
[13] purrr_0.3.4        readr_2.0.1        tidyr_1.1.3        tibble_3.1.7       ggplot2_3.3.5      tidyverse_1.3.1   
[19] papaja_0.1.0.9997  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                gmp_0.6-2                
  [6] crosstalk_1.1.1           kSamples_1.2-9            ipmisc_6.0.2              TH.data_1.0-10            pryr_0.1.5               
 [11] digest_0.6.28             SuppDists_1.1-9.7         htmltools_0.5.2           magick_2.7.3              fansi_0.5.0              
 [16] magrittr_2.0.1            checkmate_2.0.0           memoise_2.0.0             paletteer_1.4.0           tzdb_0.1.2               
 [21] openxlsx_4.2.4            modelr_0.1.8              matrixStats_0.60.1        sandwich_3.0-1            colorspace_2.0-3         
 [26] rvest_1.0.2               ggrepel_0.9.1             haven_2.4.3               xfun_0.30                 prismatic_1.0.0          
 [31] tcltk_4.1.0               crayon_1.5.1              jsonlite_1.8.0            zeallot_0.1.0             survival_3.2-13          
 [36] zoo_1.8-9                 glue_1.6.2                gtable_0.3.0              emmeans_1.6.3             MatrixModels_0.5-0       
 [41] statsExpressions_1.1.0    car_3.0-11                Rmpfr_0.8-4               abind_1.4-5               rapportools_1.0          
 [46] mvtnorm_1.1-2             DBI_1.1.1                 PMCMRplus_1.9.0           Rcpp_1.0.7                xtable_1.8-4             
 [51] performance_0.7.3         tmvnsim_1.0-2             foreign_0.8-81            DT_0.19                   htmlwidgets_1.5.3        
 [56] datawizard_0.2.0.1        httr_1.4.3                ellipsis_0.3.2            farver_2.1.0              pkgconfig_2.0.3          
 [61] reshape_0.8.8             sass_0.4.1                multcompView_0.1-8        dbplyr_2.1.1              utf8_1.2.2               
 [66] labeling_0.4.2            effectsize_0.4.5          tidyselect_1.1.2          rlang_1.0.2               munsell_0.5.0            
 [71] cellranger_1.1.0          tools_4.1.0               cachem_1.0.6              ggprism_1.0.3             cli_3.0.1                
 [76] generics_0.1.2            evaluate_0.15             fastmap_1.1.0             yaml_2.3.5                BWStest_0.2.2            
 [81] rematch2_2.1.2            knitr_1.39                fs_1.5.2                  zip_2.2.0                 pander_0.6.5             
 [86] WRS2_1.1-3                pbapply_1.4-3             nlme_3.1-152              xml2_1.3.3                correlation_0.7.0        
 [91] compiler_4.1.0            rstudioapi_0.13           curl_4.3.2                ggsignif_0.6.2            reprex_2.0.1             
 [96] bslib_0.3.1               stringi_1.7.4             highr_0.9                 parameters_0.14.0         lattice_0.20-44          
[101] Matrix_1.3-4              vctrs_0.4.1               pillar_1.7.0              lifecycle_1.0.1           mc2d_0.1-21              
[106] jquerylib_0.1.4           estimability_1.3          data.table_1.14.0         insight_0.14.4            patchwork_1.1.1          
[111] R6_2.5.1                  BayesFactor_0.9.12-4.2    codetools_0.2-18          boot_1.3-28               MASS_7.3-54              
[116] gtools_3.9.2              assertthat_0.2.1          withr_2.5.0               mnormt_2.0.2              multcomp_1.4-17          
[121] mgcv_1.8-36               bayestestR_0.11.0         parallel_4.1.0            hms_1.1.1                 grid_4.1.0               
[126] coda_0.19-4               rmarkdown_2.14            carData_3.0-4             lubridate_1.7.10          base64enc_0.1-3          

 


A work by Claudiu Papasteri

 

LS0tDQp0aXRsZTogIjxicj4gU1RBRCAtIERlbW8gYW5kIEltaXRhdGlvbiBNZXRyaWNzIiANCnN1YnRpdGxlOiAiUHJlbGltaW5hcnkgQW5hbHlzaXMiDQphdXRob3I6ICI8YnI+IENsYXVkaXUgUGFwYXN0ZXJpIg0KZGF0ZTogImByIGZvcm1hdChTeXMudGltZSgpLCAnJWQgJW0gJVknKWAiDQpvdXRwdXQ6IA0KICAgIGh0bWxfbm90ZWJvb2s6DQogICAgICAgICAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICAgICAgICAgIHRvYzogdHJ1ZQ0KICAgICAgICAgICAgdG9jX2RlcHRoOiAyDQogICAgICAgICAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUNCiAgICAgICAgICAgIHRoZW1lOiBzcGFjZWxhYg0KICAgICAgICAgICAgaGlnaGxpZ2h0OiB0YW5nbw0KICAgICAgICAgICAgZm9udC1mYW1pbHk6IEFyaWFsDQogICAgICAgICAgICBmaWdfd2lkdGg6IDEwDQogICAgICAgICAgICBmaWdfaGVpZ2h0OiA5DQogICAgIyBwZGZfZG9jdW1lbnQ6IA0KICAgICAgICAgICAgIyB0b2M6IHRydWUNCiAgICAgICAgICAgICMgIHRvY19kZXB0aDogMg0KICAgICAgICAgICAgIyAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlDQogICAgICAgICAgICAjIGZvbnRzaXplOiAxMXB0DQogICAgICAgICAgICAjIGdlb21ldHJ5OiBtYXJnaW49MWluDQogICAgICAgICAgICAjIGZpZ193aWR0aDogNw0KICAgICAgICAgICAgIyBmaWdfaGVpZ2h0OiA2DQogICAgICAgICAgICAjIGZpZ19jYXB0aW9uOiB0cnVlDQogICAgIyBnaXRodWJfZG9jdW1lbnQ6IA0KICAgICAgICAgICAgIyB0b2M6IHRydWUNCiAgICAgICAgICAgICMgdG9jX2RlcHRoOiAyDQogICAgICAgICAgICAjIGh0bWxfcHJldmlldzogZmFsc2UNCiAgICAgICAgICAgICMgZmlnX3dpZHRoOiA1DQogICAgICAgICAgICAjIGZpZ19oZWlnaHQ6IDUNCiAgICAgICAgICAgICMgZGV2OiBqcGVnDQotLS0NCg0KPCEtLSBTZXR1cCAtLT4NCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQojIGtpbnRyIG9wdGlvbnMNCmtuaXRyOjpvcHRzX2NodW5rJHNldCgNCiAgY29tbWVudCA9ICIjIiwNCiAgY29sbGFwc2UgPSBUUlVFLA0KICBlY2hvID0gVFJVRSwgd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlID0gVFJVRSwgY2FjaGUgPSBUUlVFICAgICAgICMgZWNobyA9IEZhbHNlIGZvciBnaXRodWJfZG9jdW1lbnQsIGJ1dCB3aWxsIGJlIGZvbGRlZCBpbiBodG1sX25vdGVib29rDQopDQoNCm9wdGlvbnMoZHBseXIuc3VtbWFyaXNlLmluZm9ybSA9IEZBTFNFKSAgICMgYW5ub3lpbmcgc3VtbWFyaXplIG1lc3NhZ2VzIHBhc3MgdGhyb3VnaHQgbWVzc2FnZT1GQUxTRQ0KDQojIEdlbmVyYWwgUiBvcHRpb25zIGFuZCBpbmZvDQpTeXMuc2V0ZW52KGBfUl9TM19NRVRIT0RfUkVHSVNUUkFUSU9OX05PVEVfT1ZFUldSSVRFU19gID0gImZhbHNlIikgIyBzdXBwcmVzcyAiUzMgbWV0aG9kIG92ZXJ3cml0dGVuIiBiZWZvcmUgbG9hZGluZyBwYWNrYWdlcw0Kc2V0LnNlZWQoMTExKSAgICAgICAgICAgICAgICMgaW4gY2FzZSB3ZSB1c2UgcmFuZG9taXplZCBwcm9jZWR1cmVzICAgICAgIA0Kb3B0aW9ucyhzY2lwZW4gPSA5OTkpICAgICAgICMgcG9zaXRpdmUgdmFsdWVzIGJpYXMgdG93YXJkcyBmaXhlZCBhbmQgbmVnYXRpdmUgdG93YXJkcyBzY2llbnRpZmljIG5vdGF0aW9uDQoNCiMgTG9hZCBwYWNrYWdlcw0KaWYgKCFyZXF1aXJlKCJwYWNtYW4iKSkgaW5zdGFsbC5wYWNrYWdlcygicGFjbWFuIikNCnBhY2thZ2VzIDwtIGMoDQogICJwYXBhamEiLA0KICAidGlkeXZlcnNlIiwgICAgICANCiAgInBzeWNoIiwgICAgICAgICAgDQogICJicm9vbSIsICJyc3RhdGl4IiwNCiAgInN1bW1hcnl0b29scyIsICAgICAgICAgICAgDQogICJnZ3Bsb3QyIiwgImdncHViciIsICJzY2FsZXMiLCAic3BsaW5lcyIsICJjb3dwbG90IiwgImdnc3RhdHNwbG90IiwgICAgICAgIA0KICAicmlvIg0KICAjICwgLi4uDQopDQppZiAoIXJlcXVpcmUoInBhY21hbiIpKSBpbnN0YWxsLnBhY2thZ2VzKCJwYWNtYW4iKQ0KcGFjbWFuOjpwX2xvYWQoY2hhciA9IHBhY2thZ2VzKQ0KDQojIFRoZW1lcyBmb3IgZ2dwbG90MiBwbG90aW5nIChoZXJlIHVzZWQgQVBBIHN0eWxlKQ0KdGhlbWVfc2V0KHRoZW1lX2FwYSgpKQ0KYGBgDQoNCjwhLS0gUmVwb3J0IC0tPg0KDQojIFJ1biBkZW1vaW1pdE1ldHJpY3NfY2xlYW50YWJsZSBzY3JpcHQNCg0KYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpzY3JpcHRfZm9sZGVyIDwtICJDOi9Vc2Vycy9NaWhhaS9EZXNrdG9wL1IgTm90ZWJvb2tzL25vdGVib29rcy9TVEFELWRlbW9pbWl0TWV0cmljcy9TY3JpcHRzIiANCnNjcmlwdF9uYW1lIDwtICJkZW1vaW1pdE1ldHJpY3NfdG9fY2xlYW50YWJsZS5SIg0Kc291cmNlKGZpbGUucGF0aChzY3JpcHRfZm9sZGVyLCBzY3JpcHRfbmFtZSkpDQpgYGANCg0KIyBEYXRhDQoNCiMjIEluZm86DQoNCi0gICBEZW1vIHNjb3Jlcw0KDQogICAgLSAgIG9iamVjdCByZXNwb25zZSBieSBuYXZpZ2F0b3IgKGluZGl2aWR1YWwgc2NvcmUpIChHYW1lU3RhdGUgOSA9XD4gbmV3R2FtZVN0YXRlIDEwKQ0KDQotICAgSW1pdGF0aW9uIHNjb3Jlcw0KDQogICAgLSAgIDFzdCByb3cgZm9yIHN0YXJ0IChHYW1lU3RhdGUgMTQgPVw+IG5ld0dhbWVTdGF0ZSAxNSkNCiAgICAtICAgMm5kIHJvdyBmb3IgZmxhZyAoR2FtZVN0YXRlIDE1ID1cPiBuZXdHYW1lU3RhdGUgMTYpDQogICAgLSAgIDNyZCByb3cgPSBmaXJzdCBvYmplY3QgcmVzcG9uc2UgYnkgbmF2aWdhdG9yIChpbmRpdmlkdWFsIHNjb3JlKSAoR2FtZVN0YXRlIDE2ID1cPiBuZXdHYW1lU3RhdGUgMTcpDQogICAgLSAgIDR0aCByb3cgPSBzdWdnZXN0aW9uIG1hcmtlciBieSBvYnNlcnZlciAob2JzZXJ2ZXIgc2NvcmUpIChHYW1lU3RhdGUgMTcgPVw+IG5ld0dhbWVTdGF0ZSAxOCkNCiAgICAtICAgNXRoIHJvdyA9IDJuZCBvYmplY3QgcmVzcG9uc2UgYnkgbmF2aWdhdG9yIChjb2xsYWJvcmF0aXZlIHNjb3JlKSAoR2FtZVN0YXRlIDE4ID1cPiBuZXdHYW1lU3RhdGUgMTkpDQoNCi0gICBWYXJpYWJsZXM6DQoNCiAgICAtICAgaWQgY2F0ZWdvcmljYWwgLSB1bmlxdWUgaWRlbnRpZmllcg0KICAgIC0gICBjb25kaXRpb24gY2F0ZWdvcmljYWwgLSAic29jaWFsIiBvciAiYm90Ig0KICAgIC0gICBvcmRlciBjYXRlZ29yaWNhbCAtIDEgb3IgMiB0aGUgb3JkZXIgb2YgY29uZGl0aW9ucw0KICAgIC0gICB3aG8gY2F0ZXJnb3JpY2FsIC0gMSBvciAyIGNvZGVzIGZvciB3aG8ncyByZWNvcmRpbmcgaXQgaXMgKGRhdGEgb25seSBmb3IgY3VycmVudCBpZCBpcyB3aGVuOiAqd2hvID09IHBsYXllclR5cGUqKQ0KDQogICAgPCEtLSArIG5ld0dhbWVTdGF0ZV9mIGNhdGVnb3JpY2FsIC0gY29kZXMgZm9yIEdhbWVTdGF0ZXMgKDUtMTEgYXJlIERlbW8sIDEyLTIwIGFyZSBJbWl0KSAtLT4NCg0KICAgIDwhLS0gKyBkZW1vaW1pdFN0YXRlIGNhdGVnb3JpY2FsIC0gIkRlbW8iIG9yICJJbWl0IiBkZXBlbmRpbmcgb24gc3RhdGUgLS0+DQoNCiAgICAtICAgbmV3R2FtZVN0YXRlX2NsZWFuIGNhdGVnb3JpY2FsIC0gY29kZXMgZm9yIEdhbWVTdGF0ZXMgKDUtMTEgYXJlIERlbW8sIDEyLTIwIGFyZSBJbWl0KQ0KICAgIC0gICBkZW1vaW1pdFN0YXRlX2NsZWFuIGNhdGVnb3JpY2FsIC0gIkRlbW8iIG9yICJJbWl0IiBkZXBlbmRpbmcgb24gc3RhdGUNCiAgICAtICAgcGxheWVyVHlwZSBjYXRlZ29yaWNhbCAtIDEgb3IgMiBkZXBlbmRpbmcgb24gR2FtZVN0YXRlIChzaG91bGQgYmUgdXNlZCB0b2dldGhlciB3aXRoIHZhciAqd2hvKikNCiAgICAtICAgbWFya2VyVHlwZSBjYXRlZ29yaWNhbCAtIGNvZGVzIGZvciB0aGUgb2JqZWN0IChzZWUgZG9jdW1lbnRhdGlvbiksIGJ1dCBpdCBhY3R1YWxseSBmb2xsb3dzIHRoZSB0aGUgYWJvdmUgSW5mbyAoZGVwZW5kZXMgb24gR2FtZVN0YXRlKQ0KICAgIC0gICBzY29yZSBjb250aW51b3VzIC0gZm9sbG93cyB0aGUgdGhlIGFib3ZlIEluZm8gKGRlcGVuZHMgb24gR2FtZVN0YXRlKQ0KDQpgYGB7cn0NCmZ1bGxfZGF0YV9vdXRwdXRfY2xlYW4gJT4lDQogIERUOjpkYXRhdGFibGUoICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgZXhjZWwgZG93bmxvYWRhYmxlICBEVCB0YWJsZQ0KICBleHRlbnNpb25zID0gJ0J1dHRvbnMnLA0KICBvcHRpb25zID0gbGlzdChwYWdlTGVuZ3RoID0gNSwNCiAgICAgICAgICAgICAgICAgc2Nyb2xsWCA9ICc1MDBweCcsIA0KICAgICAgICAgICAgICAgICBkb20gPSAnQmZydGlwJywgDQogICAgICAgICAgICAgICAgIGJ1dHRvbnMgPSBjKCdleGNlbCcsICJjc3YiKSkpICU+JQ0KICBEVDo6Zm9ybWF0U3R5bGUobmFtZXMoZnVsbF9kYXRhX291dHB1dF9jbGVhbiksbGluZUhlaWdodCA9ICI2MCUiKSAgICAjIHNsaW1tZXIgcm93cw0KYGBgDQoNCiMgUHJlbGltaW5hcnkgQW5hbHlzZXMNCg0KIyMjIEZ1bmN0aW9ucw0KDQpgYGB7cn0NCnBsb3RfZ3Jvd3RoX3N0YXRlX2lkIDwtIGZ1bmN0aW9uKGRhdGEsIGNvbmQsIGdhbWVzdGF0ZSwgdGltZV9saW0gPSAyMCkgew0KICBkYXRhICU+JQ0KICBkcGx5cjo6ZmlsdGVyKGNvbmRpdGlvbiA9PSBjb25kLCBuZXdHYW1lU3RhdGVfY2xlYW4gPT0gZ2FtZXN0YXRlKSAlPiUNCiAgZ3JvdXBfYnkoaWQpICU+JQ0KICBkcGx5cjo6bXV0YXRlKHRpbWUgPSBkcGx5cjo6cm93X251bWJlcigpKSAlPiUNCiAgZHBseXI6OmZpbHRlcih0aW1lIDwgdGltZV9saW0pICU+JSAgDQogICAgZ2dwbG90KGFlcyh4ID0gdGltZSwgeSA9IHNjb3JlKSkgKw0KICAgIGdlb21fbGluZSgpICsNCiAgICBmYWNldF93cmFwKH5pZCkgKw0KICAgIHlsaW0oMCwgMTAwKSArDQogICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IDE6MTQpICsNCiAgICBnZ3RpdGxlKHBhc3RlMCgiQ29uZGl0aW9uOiAiLCBjb25kLCAiLCAiLCAiR2FtZSBzdGF0ZTogIiwgZ2FtZXN0YXRlKSkNCn0NCg0KIyBlLmcuDQojIGZ1bGxfZGF0YV9vdXRwdXRfY2xlYW4gJT4lDQojICAgZHBseXI6OmZpbHRlcihjb25kaXRpb24gPT0gImJvdCIsIG5ld0dhbWVTdGF0ZV9jbGVhbiA9PSAiMTAiKSAlPiUNCiMgICBncm91cF9ieShpZCkgJT4lDQojICAgZHBseXI6Om11dGF0ZSh0aW1lID0gZHBseXI6OnJvd19udW1iZXIoKSkgJT4lDQojICAgZ2dwbG90KGFlcyh4ID0gdGltZSwgeSA9IHNjb3JlKSkgKw0KIyAgIGdlb21fbGluZSgpICsNCiMgICBmYWNldF93cmFwKH5pZCkNCg0KcGxvdF9ncm93dGhfc3RhdGVfbG9lc3MgPC0gZnVuY3Rpb24oZGF0YSwgY29uZCwgZ2FtZXN0YXRlLCB0aW1lX2xpbSA9IDIwKSB7DQogIGRhdGEgJT4lDQogIGRwbHlyOjpmaWx0ZXIoY29uZGl0aW9uID09IGNvbmQsIG5ld0dhbWVTdGF0ZV9jbGVhbiA9PSBnYW1lc3RhdGUpICU+JQ0KICBncm91cF9ieShpZCkgJT4lDQogIGRwbHlyOjptdXRhdGUodGltZSA9IGRwbHlyOjpyb3dfbnVtYmVyKCkpICU+JQ0KICBkcGx5cjo6ZmlsdGVyKHRpbWUgPCB0aW1lX2xpbSkgJT4lICAgDQogICAgZ2dwbG90KGFlcyh4ID0gdGltZSwgeSA9IHNjb3JlKSkgKw0KICAgIGdlb21fbGluZShhZXMoY29sb3IgPSBhcy5mYWN0b3IoaWQpKSwgYWxwaGEgPSAuNSkgKw0KICAgIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsb2VzcyIsIGZvcm11bGEgPSAieSB+IHgiLCBjb2xvciA9ICJyZWQiLCBmaWxsID0gInJlZCIpICsNCiAgICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBmb3JtdWxhID0geSB+IHNwbGluZXM6OmJzKHgsIGtub3RzID0gc2VxKDIgLCAxNiwgYnkgPSAyKSwgZGVncmVlID0gMSksIA0KICAgICAgICAgICAgICAgIHNlID0gRkFMU0UsIGNvbG9yID0gImJsYWNrIiwgZmlsbCA9ICJncmF5IiwgYWxwaGEgPSAwLjgpICsNCiAgICB5bGltKDAsIDEwMCkgKw0KICAgIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSAxOjE0KSArDQogICAgZ2d0aXRsZShwYXN0ZTAoIkNvbmRpdGlvbjogIiwgY29uZCwgIiwgIiwgIkdhbWUgc3RhdGU6ICIsIGdhbWVzdGF0ZSkpICsNCiAgICBsYWJzKGNvbG9yID0gImlkIikgIA0KfQ0KICANCiMgZS5lLg0KIyBmdWxsX2RhdGFfb3V0cHV0X2NsZWFuICU+JQ0KIyBkcGx5cjo6ZmlsdGVyKGNvbmRpdGlvbiA9PSAiYm90IiwgbmV3R2FtZVN0YXRlX2NsZWFuID09ICIxMCIpICU+JQ0KIyBncm91cF9ieShpZCkgJT4lDQojIGRwbHlyOjptdXRhdGUodGltZSA9IGRwbHlyOjpyb3dfbnVtYmVyKCkpICU+JQ0KIyBnZ3Bsb3QoYWVzKHggPSB0aW1lLCB5ID0gc2NvcmUpKSArDQojIGdlb21fbGluZShhZXMoY29sb3IgPSBhcy5mYWN0b3IoaWQpKSwgYWxwaGEgPSAuNSkgKw0KIyBnZW9tX3Ntb290aChtZXRob2QgPSAibG9lc3MiLCBmb3JtdWxhID0gInkgfiB4IikNCg0KcGxvdF9ncm93dGhfc3RhdGUxMDE3X2lkIDwtIGZ1bmN0aW9uKGRhdGEsIGNvbmRzID0gYygic29jaWFsIiwgImJvdCIpLCB0aW1lX2xpbSA9IDIwKSB7DQogIGRhdGEgJT4lDQogIGRwbHlyOjpmaWx0ZXIoY29uZGl0aW9uICVpbiUgY29uZHMsIG5ld0dhbWVTdGF0ZV9jbGVhbiAlaW4lIGMoIjEwIiwgIjE3IikpICU+JQ0KICBkcGx5cjo6bXV0YXRlKG5ld0dhbWVTdGF0ZV9jbGVhbiA9IGFzLmZhY3RvcihuZXdHYW1lU3RhdGVfY2xlYW4pKSAlPiUgIA0KICBkcGx5cjo6Z3JvdXBfYnkoaWQsIGNvbmRpdGlvbikgJT4lDQogIGRwbHlyOjptdXRhdGUodGltZSA9IGRwbHlyOjpyb3dfbnVtYmVyKCkpICU+JQ0KICBkcGx5cjo6ZmlsdGVyKHRpbWUgPCB0aW1lX2xpbSkgJT4lIA0KICAgIGdncGxvdChhZXMoeCA9IHRpbWUsIHkgPSBzY29yZSwgY29sb3IgPSBjb25kaXRpb24pKSArDQogICAgZ2VvbV9saW5lKCkgKw0KICAgIGdlb21fcG9pbnQoYWVzKHNoYXBlID0gbmV3R2FtZVN0YXRlX2NsZWFuKSkgKw0KICAgIGZhY2V0X3dyYXAofmlkKSArDQogICAgeWxpbSgwLCAxMDApICsNCiAgICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gMToxNCkgKw0KICAgIGdndGl0bGUoIkFsdGVybmF0aW5nIEdhbWVTdGF0ZSAxMCBhbmQgMTciKSArIA0KICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJyaWdodCIpDQp9DQoNCg0KDQpteV9nZ3dpdGhpbnN0YXRzMiA8LSBmdW5jdGlvbihkYXRhLCB0aXRsZSA9IE5VTEwsIHgsIHksIGdhbWVzdGF0ZSwgdGltZV9saW0gPSAyMCwgb3V0bGllci5sYWJlbCwgeGxhYiwgeWxhYiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvdXRsaWVyLnRhZ2dpbmcgPSBGQUxTRSwgcmVzdWx0cy5zdWJ0aXRsZSA9IFRSVUUsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2VudHJhbGl0eS5sYWJlbC5hcmdzID0gVFJVRSwgcG9pbnQucGF0aCA9IFRSVUUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gInBhcmFtZXRyaWMiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC4uLikgeyAgIyAuLi4gZm9yIGxpbWl0cyBhbmQgYnJlYWtzDQogIHggPC0gcmxhbmc6OmVucXVvKHgpDQogIHkgPC0gcmxhbmc6OmVucXVvKHkpDQogIG91dGxpZXIubGFiZWwgPC0gcmxhbmc6OmVucXVvKG91dGxpZXIubGFiZWwpDQogIA0KICBpZihpcy5udWxsKHRpdGxlKSkgew0KICAgIHRpdGxlIDwtIHBhc3RlMCgiR2FtZSBzdGF0ZTogIiwgZ2FtZXN0YXRlKQ0KICB9DQogIA0KICBkYXRhIDwtDQogICAgZGF0YSAlPiUNCiAgICBkcGx5cjo6c2VsZWN0KCEhb3V0bGllci5sYWJlbCwgISF4LCAhIXksIG5ld0dhbWVTdGF0ZV9jbGVhbikgJT4lICAgICAgIyBuZXdHYW1lU3RhdGVfY2xlYW4gaXMgaGFyZGNvZGVkIGhlcmUNCiAgICBkcGx5cjo6ZmlsdGVyKG5ld0dhbWVTdGF0ZV9jbGVhbiA9PSBnYW1lc3RhdGUpICU+JQ0KICAgIGdyb3VwX2J5KCEhb3V0bGllci5sYWJlbCwgISF4KSAlPiUNCiAgICBkcGx5cjo6bXV0YXRlKHRpbWUgPSBkcGx5cjo6cm93X251bWJlcigpKSAlPiUNCiAgICBkcGx5cjo6ZmlsdGVyKHRpbWUgPCB0aW1lX2xpbSkgJT4lICAgDQogICAgZHBseXI6OnN1bW1hcmlzZShtZWFuX3Njb3JlID0gbWVhbighIXksIG5hLnJtID0gVFJVRSkpDQogICAgDQogIGlmKGNlbnRyYWxpdHkubGFiZWwuYXJncyl7DQogICAgY2VudHJhbGl0eS5sYWJlbC5hcmdzIDwtIGxpc3Qoc2l6ZSA9IDMsIG51ZGdlX3ggPSAwLjIsIHNlZ21lbnQubGluZXR5cGUgPSA1LCBmaWxsID0gIiNGRkY4RTciKQ0KICB9ZWxzZXsNCiAgICBjZW50cmFsaXR5LmxhYmVsLmFyZ3MgPC0gbGlzdChzaXplID0gMCwgbnVkZ2VfeCA9IDEwLCBzZWdtZW50LmxpbmV0eXBlID0gMCwgYWxwaGEgPSAwKSAjIHZlcnkgaGFja3kgd2F5IG9mIG5vdCBzaG93aW5nIGxhYmVsDQogIH0NCiAgDQogIGRhdGEgJT4lDQogICAgZ2dzdGF0c3Bsb3Q6Omdnd2l0aGluc3RhdHMoDQogICAgICB4ID0gISF4LA0KICAgICAgeSA9IG1lYW5fc2NvcmUsICAgICAgICAgICAgICAjIGhlcmUgd2UgaGF2ZSB0aGUgbWVhbiBzY29yZSBmb3IgaWQsIG5vdCAhIXkNCiAgICAgIHRpdGxlID0gdGl0bGUsDQogICAgICB4bGFiID0geGxhYiwNCiAgICAgIHlsYWIgPSB5bGFiLA0KICAgICAgb3V0bGllci50YWdnaW5nID0gb3V0bGllci50YWdnaW5nLCAgICAgICAgICAgICAgICAgICAgIyB3aGV0aGVyIG91dGxpbmVzIG5lZWQgdG8gYmUgdGFnZ2VkDQogICAgICBvdXRsaWVyLmxhYmVsID0gISFvdXRsaWVyLmxhYmVsLCAgICAgICAgICAgICAgICAgICAgICAjIHZhcmlhYmxlIHRvIGJlIHVzZWQgZm9yIHRhZ2dpbmcgb3V0bGllcnMNCiAgICAgIG91dGxpZXIuY29lZiA9IDIsDQogICAgICBwYWlyd2lzZS5jb21wYXJpc29ucyA9IFRSVUUsDQogICAgICBwYWlyd2lzZS5kaXNwbGF5ID0gImFsbCIsDQogICAgICByZXN1bHRzLnN1YnRpdGxlID0gcmVzdWx0cy5zdWJ0aXRsZSwNCiAgICAgIHR5cGUgPSB0eXBlLA0KICAgICAgYmYubWVzc2FnZSA9IEZBTFNFLCANCiAgICAgIHAuYWRqdXN0Lm1ldGhvZCA9ICJub25lIiwNCiAgICAgIHBvaW50LnBhdGggPSBwb2ludC5wYXRoLA0KICAgICAgZ2d0aGVtZSA9IGdncHJpc206OnRoZW1lX3ByaXNtKCksDQogICAgICAjIHBhY2thZ2UgPSAiUkNvbG9yQnJld2VyIiwgICMgImdnc2NpIiwNCiAgICAgICMgcGFsZXR0ZSA9ICJEYXJrIiwgICAgICAgICAjICJkZWZhdWx0X2pjbyIsDQogICAgICB2aW9saW4uYXJncyA9IGxpc3Qod2lkdGggPSAwLjksIGFscGhhID0gMC4yLCBzaXplID0gMSwgY29sb3IgPSAiYmxhY2siKSwNCiAgICAgIGNlbnRyYWxpdHkucGxvdHRpbmcgPSBUUlVFLA0KICAgICAgY2VudHJhbGl0eS50eXBlID0gInBhcmFtZXRlcmljIiwNCiAgICAgIGNlbnRyYWxpdHkucG9pbnQuYXJncyA9IGxpc3Qoc2l6ZSA9IDUsIGNvbG9yID0gImRhcmtyZWQiKSwNCiAgICAgIGNlbnRyYWxpdHkubGFiZWwuYXJncyA9IGNlbnRyYWxpdHkubGFiZWwuYXJncywNCiAgICAgIGdncGxvdC5jb21wb25lbnQgPSBsaXN0KA0KICAgICAgICB0aGVtZSgNCiAgICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMCwgc2l6ZSA9IDE2KSwNCiAgICAgICAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMCwgc2l6ZSA9IDEyKSwgDQogICAgICAgICAgcGxvdC5jYXB0aW9uID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMCwgc2l6ZSA9IDEyKSwgDQogICAgICAgICAgdGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQpDQogICAgICApKQ0KICAgICkgKyBzY2FsZV9jb2xvdXJfZ3JleShzdGFydCA9IDAuMiwgZW5kID0gMC4yKSArICAjIGhhY2t5IHdheSB0byBjaGFuZ2UgcG9pbnQgY29sb3INCiAgICB5bGltKDAsIDEwMCkgKw0KICAgIHNjYWxlX3lfY29udGludW91cyguLi4pDQp9DQoNCiMgZS5nLg0KIyBteV9nZ3dpdGhpbnN0YXRzMihmdWxsX2RhdGFfb3V0cHV0X2NsZWFuLCB4ID0gY29uZGl0aW9uLCB5ID0gc2NvcmUsIG91dGxpZXIubGFiZWwgPSBpZCwgZ2FtZXN0YXRlID0gMTAsDQojICAgICAgICAgICAgICAgICAgIHRpbWVfbGltID0gMjAsIHhsYWIgPSAiQ29uZGl0aW9uIiwgeWxhYiA9ICJzY29yZSIpDQogICAgICAgICAgICAgICAgICAgDQpgYGANCg0KIyMgQ2hlY2sgYmFsYW5jZQ0KDQojIyMgQWxsIHBhcnRpY2lwYW50cw0KDQpgYGB7cn0NCmNvdW50c19pZF9jb25kb3JkIDwtDQogIGZ1bGxfZGF0YV9vdXRwdXRfY2xlYW4gJT4lDQogIGRwbHlyOjpjb3VudChpZCwgY29uZGl0aW9uLCBvcmRlcikNCg0KY291bnRzX2lkX2NvbmRvcmQgJT4lICAgICAgIyBQYXJ0aWNpcGFudCA0MSBoYXMgMiBib3QgY29uZGl0aW9uczogb3JkZXIgPSAxIGFuZCAxYmlzDQogIHByaW50KG4gPSBJbmYpDQoNCmNvdW50c19pZF9jb25kb3JkICU+JQ0KICBkcGx5cjo6c2VsZWN0KGNvbmRpdGlvbiwgb3JkZXIpICU+JQ0KICB0YWJsZSgpICU+JQ0KICBrbml0cjo6a2FibGUoY2FwdGlvbiA9ICJPcmRlciIpDQpgYGANCg0KIyMjIFBhcnRpY2lwYW50cyB3aXRoIGJvdGggY29uZGl0aW9ucw0KDQpgYGB7cn0NCiMgUGFydGljaXBhbnQgNDEgaGFzIDIgYm90IGNvbmRpdGlvbnM6IG9yZGVyID0gMSBhbmQgMWJpcw0KaWRzX2Z1bGxfc3ViaiA8LQ0KICBmdWxsX2RhdGFfb3V0cHV0X2NsZWFuICU+JQ0KICBkcGx5cjo6ZmlsdGVyKG9yZGVyICE9ICIxYmlzIikgJT4lICAgIyBleGNsdWRlIHN1YmogNDENCiAgZ3JvdXBfYnkoaWQsIGNvbmRpdGlvbikgJT4lDQogIHN1bW1hcmlzZShjb3VudCA9IG4oKSkgJT4lDQogIGRwbHlyOjpmaWx0ZXIobigpID4gMSkgJT4lDQogIGRwbHlyOjpwdWxsKGlkKSAlPiUNCiAgdW5pcXVlKCkNCg0KZnVsbF9kYXRhX291dHB1dF9jbGVhbiAlPiUNCiAgZHBseXI6OmZpbHRlcihpZCAlaW4lIGlkc19mdWxsX3N1YmopICU+JQ0KICBkcGx5cjo6Y291bnQoaWQsIGNvbmRpdGlvbiwgb3JkZXIpICU+JQ0KICBkcGx5cjo6c2VsZWN0KGNvbmRpdGlvbiwgb3JkZXIpICU+JQ0KICB0YWJsZSgpICU+JQ0KICBrbml0cjo6a2FibGUoY2FwdGlvbiA9ICJPcmRlciIpDQpgYGANCg0KDQojIyBJbmRpdmlkdWFsIGdyb3d0aCAob2JqZWN0IG5vdCBjb25zaWRlcmVkKQ0KDQpOb3RlczoNCg0KMS4gIFZhcmlhYmlsaXR5IGlzIHRoZSBub3JtDQoNCjIuICBUcmVuZCBpcyBub3QgZWFzaWx5IGRpc2Nlcm5pYmxlDQoNCmBgYHtyLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD0xMH0NCnBsb3RfZ3Jvd3RoX3N0YXRlX2lkKGZ1bGxfZGF0YV9vdXRwdXRfY2xlYW4sICJib3QiLCAiMTAiKQ0KcGxvdF9ncm93dGhfc3RhdGVfaWQoZnVsbF9kYXRhX291dHB1dF9jbGVhbiwgInNvY2lhbCIsICIxMCIpDQoNCnBsb3RfZ3Jvd3RoX3N0YXRlX2lkKGZ1bGxfZGF0YV9vdXRwdXRfY2xlYW4sICJib3QiLCAiMTUiKQ0KcGxvdF9ncm93dGhfc3RhdGVfaWQoZnVsbF9kYXRhX291dHB1dF9jbGVhbiwgInNvY2lhbCIsICIxNSIpDQoNCnBsb3RfZ3Jvd3RoX3N0YXRlX2lkKGZ1bGxfZGF0YV9vdXRwdXRfY2xlYW4sICJib3QiLCAiMTYiKQ0KcGxvdF9ncm93dGhfc3RhdGVfaWQoZnVsbF9kYXRhX291dHB1dF9jbGVhbiwgInNvY2lhbCIsICIxNiIpDQoNCnBsb3RfZ3Jvd3RoX3N0YXRlX2lkKGZ1bGxfZGF0YV9vdXRwdXRfY2xlYW4sICJib3QiLCAiMTciKQ0KcGxvdF9ncm93dGhfc3RhdGVfaWQoZnVsbF9kYXRhX291dHB1dF9jbGVhbiwgInNvY2lhbCIsICIxNyIpDQoNCnBsb3RfZ3Jvd3RoX3N0YXRlX2lkKGZ1bGxfZGF0YV9vdXRwdXRfY2xlYW4sICJib3QiLCAiMTgiKQ0KcGxvdF9ncm93dGhfc3RhdGVfaWQoZnVsbF9kYXRhX291dHB1dF9jbGVhbiwgInNvY2lhbCIsICIxOCIpDQoNCnBsb3RfZ3Jvd3RoX3N0YXRlX2lkKGZ1bGxfZGF0YV9vdXRwdXRfY2xlYW4sICJib3QiLCAiMTkiKQ0KcGxvdF9ncm93dGhfc3RhdGVfaWQoZnVsbF9kYXRhX291dHB1dF9jbGVhbiwgInNvY2lhbCIsICIxOSIpDQpgYGANCg0KIyMgSW5kaXZpZHVhbCBncm93dGggKG9iamVjdCBub3QgY29uc2lkZXJlZCkNCg0KUmVkID0gTG9lc3MNCg0KQmxhY2sgPSBTcGxpbmUgcmVncmVzc2lvbiAoMXN0IGRlZ3JlZSBwb2x5bm9taWFsKSwga25vdHMgPSBldmVyeSBzZWNvbmQgdGltZSBwb2ludA0KDQpOb3RlczoNCg0KMS4gIFNvbWUgcGFydGljaXBhbnRzIGhhdmUgbW9yZSB0cmlhbHMgdGhhbiBvdGhlcnMNCg0KMi4gIFRoZXJlIGlzIGEgbGFyZ2UgZGlwIGluIHBlcmZvcm1hbmNlIGFmdGVyIGEgc29tZXdoYXQgY29uc2lzdGVudCBudW1iZXIgb2YgdHJpYWxzDQoNCmBgYHtyLCBmaWcuaGVpZ2h0PTgsIGZpZy53aWR0aD04fQ0KY293cGxvdDo6cGxvdF9ncmlkKA0KICBwbG90X2dyb3d0aF9zdGF0ZV9sb2VzcyhmdWxsX2RhdGFfb3V0cHV0X2NsZWFuLCAiYm90IiwgIjEwIikgKyB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSwNCiAgcGxvdF9ncm93dGhfc3RhdGVfbG9lc3MoZnVsbF9kYXRhX291dHB1dF9jbGVhbiwgInNvY2lhbCIsICIxMCIpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIiksDQogIG5yb3cgPSAyDQopDQoNCmNvd3Bsb3Q6OnBsb3RfZ3JpZCgNCiAgcGxvdF9ncm93dGhfc3RhdGVfbG9lc3MoZnVsbF9kYXRhX291dHB1dF9jbGVhbiwgImJvdCIsICIxNSIpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIiksDQogIHBsb3RfZ3Jvd3RoX3N0YXRlX2xvZXNzKGZ1bGxfZGF0YV9vdXRwdXRfY2xlYW4sICJzb2NpYWwiLCAiMTUiKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpLCAgDQogIG5yb3cgPSAyDQopDQoNCmNvd3Bsb3Q6OnBsb3RfZ3JpZCgNCiAgcGxvdF9ncm93dGhfc3RhdGVfbG9lc3MoZnVsbF9kYXRhX291dHB1dF9jbGVhbiwgImJvdCIsICIxNiIpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIiksDQogIHBsb3RfZ3Jvd3RoX3N0YXRlX2xvZXNzKGZ1bGxfZGF0YV9vdXRwdXRfY2xlYW4sICJzb2NpYWwiLCAiMTYiKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpLCAgDQogIG5yb3cgPSAyDQopDQoNCmNvd3Bsb3Q6OnBsb3RfZ3JpZCgNCiAgcGxvdF9ncm93dGhfc3RhdGVfbG9lc3MoZnVsbF9kYXRhX291dHB1dF9jbGVhbiwgImJvdCIsICIxNyIpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIiksDQogIHBsb3RfZ3Jvd3RoX3N0YXRlX2xvZXNzKGZ1bGxfZGF0YV9vdXRwdXRfY2xlYW4sICJzb2NpYWwiLCAiMTciKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpLCAgDQogIG5yb3cgPSAyDQopDQoNCmNvd3Bsb3Q6OnBsb3RfZ3JpZCgNCiAgcGxvdF9ncm93dGhfc3RhdGVfbG9lc3MoZnVsbF9kYXRhX291dHB1dF9jbGVhbiwgImJvdCIsICIxOCIpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIiksDQogIHBsb3RfZ3Jvd3RoX3N0YXRlX2xvZXNzKGZ1bGxfZGF0YV9vdXRwdXRfY2xlYW4sICJzb2NpYWwiLCAiMTgiKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpLCANCiAgbnJvdyA9IDINCikNCiAgDQpjb3dwbG90OjpwbG90X2dyaWQoDQogIHBsb3RfZ3Jvd3RoX3N0YXRlX2xvZXNzKGZ1bGxfZGF0YV9vdXRwdXRfY2xlYW4sICJib3QiLCAiMTkiKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpLA0KICBwbG90X2dyb3d0aF9zdGF0ZV9sb2VzcyhmdWxsX2RhdGFfb3V0cHV0X2NsZWFuLCAic29jaWFsIiwgIjE5IikgKyB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSwgDQogIG5yb3cgPSAyDQopDQpgYGANCg0KDQojIyBBbHRlcm5hdGluZyBHYW1lU3RhdGVzIDEwIGFuZCAxNyBmb3IgZWFjaCBwYXJ0aWNpcGFudCBieSBjb25kaXRpb24NCg0KIyMjIEFsbCBwYXJ0aWNpcGFucw0KDQpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZmlnLmhlaWdodD0xMiwgZmlnLndpZHRoPTEyfQ0KcGxvdF9ncm93dGhfc3RhdGUxMDE3X2lkKGZ1bGxfZGF0YV9vdXRwdXRfY2xlYW4pDQpgYGANCg0KIyMjIFBhcnRjaXBhbnRzIHdpdGggYm90aCBjb25kaXRpb25zDQoNCmBgYHtyLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBmaWcuaGVpZ2h0PTEwLCBmaWcud2lkdGg9MTF9DQpmdWxsX2RhdGFfb3V0cHV0X2NsZWFuICU+JQ0KICBkcGx5cjo6ZmlsdGVyKGlkICVpbiUgaWRzX2Z1bGxfc3ViaikgJT4lDQogIHBsb3RfZ3Jvd3RoX3N0YXRlMTAxN19pZCgpDQpgYGANCg0KDQojIyBJbmRpdmlkdWFsIGF2ZXJhZ2Ugc2NvcmVzIChtZWFuKQ0KDQpOb3RlczoNCg0KMS4gIFRoZXNlIGFyZSB0cmlhbC1saW1pdGVkIChsaW1pdCBpcyBzZXQgYXQgNSB0cmlhbHMpDQoNCjIuICBCdXQ6IGRvIG5vdCB0YWtlIGNvbmRpdGlvbiBvcmRlciBvciBtYXJrZXJUeXBlIGludG8gY29uc2lkZXJhdGlvbi4gQWxzbywgbiByZWZlcnMgdG8gZ2FtZXN0YXRlIG9ic2VydmF0aW9ucyBub3QgaWRzLg0KDQpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCg0KbXlfZ2d3aXRoaW5zdGF0czIoZnVsbF9kYXRhX291dHB1dF9jbGVhbiwgeCA9IGNvbmRpdGlvbiwgeSA9IHNjb3JlLCBvdXRsaWVyLmxhYmVsID0gaWQsIGdhbWVzdGF0ZSA9IDEwLA0KICAgICAgICAgICAgICAgICAgdGltZV9saW0gPSA1LCB4bGFiID0gIkNvbmRpdGlvbiIsIHlsYWIgPSAic2NvcmUiKSAlPiUNCiAgc3VwcHJlc3NNZXNzYWdlcygpDQoNCm15X2dnd2l0aGluc3RhdHMyKGZ1bGxfZGF0YV9vdXRwdXRfY2xlYW4sIHggPSBjb25kaXRpb24sIHkgPSBzY29yZSwgb3V0bGllci5sYWJlbCA9IGlkLCBnYW1lc3RhdGUgPSAxNSwNCiAgICAgICAgICAgICAgICAgIHRpbWVfbGltID0gNSwgeGxhYiA9ICJDb25kaXRpb24iLCB5bGFiID0gInNjb3JlIikgJT4lDQogIHN1cHByZXNzTWVzc2FnZXMoKQ0KDQpteV9nZ3dpdGhpbnN0YXRzMihmdWxsX2RhdGFfb3V0cHV0X2NsZWFuLCB4ID0gY29uZGl0aW9uLCB5ID0gc2NvcmUsIG91dGxpZXIubGFiZWwgPSBpZCwgZ2FtZXN0YXRlID0gMTYsDQogICAgICAgICAgICAgICAgICB0aW1lX2xpbSA9IDUsIHhsYWIgPSAiQ29uZGl0aW9uIiwgeWxhYiA9ICJzY29yZSIpICU+JQ0KICBzdXBwcmVzc01lc3NhZ2VzKCkNCg0KbXlfZ2d3aXRoaW5zdGF0czIoZnVsbF9kYXRhX291dHB1dF9jbGVhbiwgeCA9IGNvbmRpdGlvbiwgeSA9IHNjb3JlLCBvdXRsaWVyLmxhYmVsID0gaWQsIGdhbWVzdGF0ZSA9IDE3LA0KICAgICAgICAgICAgICAgICAgdGltZV9saW0gPSA1LCB4bGFiID0gIkNvbmRpdGlvbiIsIHlsYWIgPSAic2NvcmUiKSAlPiUNCiAgc3VwcHJlc3NNZXNzYWdlcygpDQoNCm15X2dnd2l0aGluc3RhdHMyKGZ1bGxfZGF0YV9vdXRwdXRfY2xlYW4sIHggPSBjb25kaXRpb24sIHkgPSBzY29yZSwgb3V0bGllci5sYWJlbCA9IGlkLCBnYW1lc3RhdGUgPSAxOCwNCiAgICAgICAgICAgICAgICAgIHRpbWVfbGltID0gNSwgeGxhYiA9ICJDb25kaXRpb24iLCB5bGFiID0gInNjb3JlIikgJT4lDQogIHN1cHByZXNzTWVzc2FnZXMoKQ0KDQpteV9nZ3dpdGhpbnN0YXRzMihmdWxsX2RhdGFfb3V0cHV0X2NsZWFuLCB4ID0gY29uZGl0aW9uLCB5ID0gc2NvcmUsIG91dGxpZXIubGFiZWwgPSBpZCwgZ2FtZXN0YXRlID0gMTksDQogICAgICAgICAgICAgICAgICB0aW1lX2xpbSA9IDUsIHhsYWIgPSAiQ29uZGl0aW9uIiwgeWxhYiA9ICJzY29yZSIpICU+JQ0KICBzdXBwcmVzc01lc3NhZ2VzKCkNCg0KYGBgDQoNCiMjIyBHYW1lU3RhdGUgMTksIG9ubHkgZmlyc3Qgb2JqZWN0LCBpbmRpdmlkdWFsIGxldmVsIGF2ZXJhZ2UNCg0KT3JkZXIgaXMgbm90IGFjY291bnRlZCBmb3INCg0KYGBge3IsIGZpZy5oZWlnaHQ9MTcsIGZpZy53aWR0aD03LCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KcGxvdF9nczE5X2Zpc3J0IDwtIA0KICBmdWxsX2RhdGFfb3V0cHV0X2NsZWFuICU+JQ0KICBkcGx5cjo6c2VsZWN0KGlkLCBjb25kaXRpb24sIHNjb3JlLCBuZXdHYW1lU3RhdGVfY2xlYW4sIG1hcmtlclR5cGUpICU+JSAgICAgIA0KICBkcGx5cjo6ZmlsdGVyKG5ld0dhbWVTdGF0ZV9jbGVhbiA9PSAiMTkiKSAlPiUNCiAgZHBseXI6Omdyb3VwX2J5KGlkLCBjb25kaXRpb24pICU+JSAgDQogIGRwbHlyOjptdXRhdGUoZmlyc3RfbWFya2VyID0gZHBseXI6OmlmX2Vsc2UobWFya2VyVHlwZSA9PSBkcGx5cjo6Zmlyc3QobWFya2VyVHlwZSksICJ5ZXMiLCAibm8iKSkgJT4lICANCiAgZHBseXI6OmZpbHRlcihmaXJzdF9tYXJrZXIgPT0gInllcyIpICU+JQ0KICBkcGx5cjo6bXV0YXRlKHRpbWUgPSBkcGx5cjo6cm93X251bWJlcigpKSAlPiUNCiAgICBnZ3Bsb3QoYWVzKHggPSB0aW1lLCB5ID0gc2NvcmUpKSArDQogICAgZ2VvbV9saW5lKCkgKw0KICAgICMgZmFjZXRfd3JhcChzY29yZSB+IGNvbmRpdGlvbiwgc3RyaXAucG9zaXRpb24gPSAidG9wIikgKw0KICAgICMgZmFjZXRfZ3JpZChjb25kaXRpb24gfiBpZCkgKyAgICANCiAgICBmYWNldF9ncmlkKHJvd3MgPSB2YXJzKGlkKSwgY29scyA9IHZhcnMoY29uZGl0aW9uKSkgKyANCiAgICB5bGltKDAsIDEwMCkgKw0KICAgIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSAxOjE2KSArDQogICAgZ2d0aXRsZShwYXN0ZTAoIkdhbWUgc3RhdGU6ICIsICIxOSIpKSArDQogICAgdGhlbWVfYncoKSANCg0Kc3VwcHJlc3NNZXNzYWdlcyhwcmludChwbG90X2dzMTlfZmlzcnQpKQ0KYGBgDQoNCmBgYHtyLCBmaWcuaGVpZ2h0PTcsIGZpZy53aWR0aD03fQ0KZnVsbF9kYXRhX291dHB1dF9jbGVhbiAlPiUNCmRwbHlyOjpzZWxlY3QoaWQsIGNvbmRpdGlvbiwgc2NvcmUsIG5ld0dhbWVTdGF0ZV9jbGVhbiwgbWFya2VyVHlwZSkgJT4lICAgICAgDQpkcGx5cjo6ZmlsdGVyKG5ld0dhbWVTdGF0ZV9jbGVhbiA9PSAiMTkiKSAlPiUNCmRwbHlyOjpncm91cF9ieShpZCwgY29uZGl0aW9uKSAlPiUgIA0KZHBseXI6Om11dGF0ZShmaXJzdF9tYXJrZXIgPSBkcGx5cjo6aWZfZWxzZShtYXJrZXJUeXBlID09IGRwbHlyOjpmaXJzdChtYXJrZXJUeXBlKSwgInllcyIsICJubyIpKSAlPiUgIA0KZHBseXI6OmZpbHRlcihmaXJzdF9tYXJrZXIgPT0gInllcyIpICU+JQ0KZHBseXI6OnN1bW1hcmlzZShtZWFuX3Njb3JlID0gbWVhbihzY29yZSwgbmEucm0gPSBUUlVFKSkgJT4lDQogIGdnc3RhdHNwbG90OjpnZ3dpdGhpbnN0YXRzKA0KICAgIHggPSBjb25kaXRpb24sDQogICAgeSA9IG1lYW5fc2NvcmUsDQogICAgb3V0bGllci50YWdnaW5nID0gVFJVRSwgICAgICAgICAgICAgICAgICAgDQogICAgb3V0bGllci5sYWJlbCA9IGlkLCANCiAgICB0aXRsZSA9ICJHYW1lU3RhdGU6IDE5Ig0KICApDQpgYGANCg0KDQoNCg0KPCEtLSBTZXNzaW9uIEluZm8gYW5kIExpY2Vuc2UgLS0+DQoNCjxicj4NCg0KIyBTZXNzaW9uIEluZm8NCg0KYGBge3Igc2Vzc2lvbl9pbmZvLCBlY2hvID0gRkFMU0UsIHJlc3VsdHMgPSAnbWFya3VwJ30NCnNlc3Npb25JbmZvKCkgICAgDQpgYGANCg0KPCEtLSBGb290ZXIgLS0+DQoNCsKgDQoNCjxociAvPg0KDQo8cCBzdHlsZT0idGV4dC1hbGlnbjogY2VudGVyOyI+DQoNCkEgd29yayBieSA8YSBocmVmPSJodHRwczovL2dpdGh1Yi5jb20vQ2xhdWRpdVBhcGFzdGVyaS8iPkNsYXVkaXUgUGFwYXN0ZXJpPC9hPg0KDQo8L3A+DQoNCjxwIHN0eWxlPSJ0ZXh0LWFsaWduOiBjZW50ZXI7Ij4NCg0KPGVtPltjbGF1ZGl1LnBhcGFzdGVyaVxAZ21haWwuY29tXShtYWlsdG86Y2xhdWRpdS5wYXBhc3RlcmlAZ21haWwuY29tKXsuZW1haWx9PC9lbT4NCg0KPC9wPg0KDQrCoA0K