1 Run demoimitMetrics_cleantable script

folder <- "C:/Users/Mihai/Desktop/R Notebooks/notebooks/STAD-demoimitMetrics"
setwd(folder)


########################################################

# Read clean table
sessions_clean_data <- readRDS("sessions_clean2batrani.RDS")

# Define function
list_to_nested <- function(list, group_var){
  list %>%
    do.call(dplyr::bind_rows, .) %>%
    dplyr::group_by( {{ group_var }} ) %>%
    tidyr::nest()
}

# Lists of recordings to nested data frames
sessions_clean_data_df <- list_to_nested(sessions_clean_data, file)

sessions_clean_data_df <-
  sessions_clean_data_df %>%
  dplyr::ungroup() %>%       # careful, the df is already grouped
  dplyr::mutate(id = dplyr::row_number())

full_data_output <- sessions_clean_data_df %>%
  dplyr::relocate(id) %>%
  tidyr::unnest(data)


# Some additional tidying
vars_exclude <- c(
  # General    
  "InputY", "InputX", "xPos", "yPos", "zPos", "xRot", "yRot", "zRot", "wRot", "markerX", "markerY", "markerZ",
  # Demo
  "demoMetrics_playerPosition_x", "demoMetrics_playerPosition_y", "demoMetrics_playerPosition_z", "demoMetrics_markerPosition_x",  
  "demoMetrics_markerPosition_y", "demoMetrics_markerPosition_z", "demoMetrics_distanceFromMarker", 
  # Imit
  "imitMetrics_playerPosition_x", "imitMetrics_playerPosition_y", "imitMetrics_playerPosition_z", "imitMetrics_markerPosition_x", 
  "imitMetrics_markerPosition_y", "imitMetrics_markerPosition_z", "imitMetrics_distanceFromMarker", 
  # syncKey
  "syncKey"
)

full_data_output_clean <- 
  full_data_output %>%
  dplyr::select(-any_of(vars_exclude))


full_data_output_clean <- 
  full_data_output_clean %>%
  dplyr::mutate(demoimitState = dplyr::case_when(newGameState_f %in% 5:11 ~ "Demo",
                                                 newGameState_f %in% 12:20 ~ "Imit",
                                                 TRUE ~ NA_character_)) %>%
  dplyr::mutate(timeStamp_demoimit = dplyr::coalesce(timeStamp_demo, timeStamp_imit), 
                playerType = dplyr::coalesce(demoMetrics_playerType, imitMetrics_playerType),
                markerType = dplyr::coalesce(demoMetrics_markerType, imitMetrics_markerType),
                score = dplyr::coalesce(demoMetrics_score, imitMetrics_score)) %>% 
  dplyr::mutate(who = dplyr::case_when(stringr::str_detect(file, "PLAYER_1") ~ 1L,     # changes output_file_clean to file
                                       stringr::str_detect(file, "PLAYER_2") ~ 2L,   
                                       TRUE ~ NA_integer_)) %>%
  dplyr::select(-c(demoMetrics_playerType, imitMetrics_playerType, demoMetrics_markerType, imitMetrics_markerType, demoMetrics_score, imitMetrics_score,
                   timeStamp_demo, timeStamp_imit))


# Keep only data from the actual player (where playerType == who)
full_data_output_clean <-
  full_data_output_clean %>%
  dplyr::filter(playerType == who)


# Exclude multiple timpeStamp_demoimit per timeStamp match (only adjusting tolerance will lose data as matches are not exact)
full_data_output_clean <-
  full_data_output_clean %>%
  dplyr::mutate(timeStamp_diff = abs(timeStamp - timeStamp_demoimit)) %>%
  dplyr::group_by(id, timeStamp_demoimit) %>%
  dplyr::slice_min(timeStamp_diff) %>%
  dplyr::ungroup() %>%
  dplyr::group_by(id, timeStamp) %>%
  dplyr::slice_min(timeStamp_diff) %>%
  dplyr::ungroup()

# Make newGameState_clean --- a bit hacky 
full_data_output_clean <-
  full_data_output_clean %>%
  dplyr::mutate(
    newGameState_clean = 
      dplyr::case_when(newGameState_f == "9" ~ 10L,             # is 9 or 14 when it should be 10 or 15
                       newGameState_f == "14" ~ 15L,
                       newGameState_f %in% as.character(c(10, 15:19)) ~ as.integer(newGameState_f),
                       TRUE ~ NA_integer_
      ),
    newGameState_clean =                                 # some matched the previous frame so GameStates repeat
      dplyr::if_else(newGameState_clean == dplyr::lag(newGameState_clean) & !is.na(dplyr::lag(newGameState_clean)), 
                     newGameState_clean + 1L, 
                     newGameState_clean
     ),
    newGameState_clean =                                 # GameState 10 following another 10 now became 11
      dplyr::if_else(newGameState_clean == 11L, 10L, newGameState_clean)
  ) %>%                                          # !CAREFUL columns computed based on newGameState_f like demoimitState now may be wrong
  dplyr::mutate(demoimitState_clean = dplyr::case_when(newGameState_clean %in% 5:11 ~ "Demo",
                                                       newGameState_clean %in% 12:20 ~ "Imit",
                                                       TRUE ~ NA_character_))

# Check GameStates
check_df <-
  full_data_output_clean %>%
  dplyr::group_by(id) %>%
  dplyr::mutate(grp = as.integer(gl(n(), 6, n()))) %>%    # group every 6 rows
  dplyr::group_by(id, grp) %>%
  dplyr::summarise(pattern = paste0(newGameState_f, collapse = " "),
                   pattern_clean = paste0(newGameState_clean, collapse = " "))

1.1 Check GamesStates

check_df

2 Data

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, gamestate, time_lim = 20) {
  data %>%
  dplyr::filter(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("Game state: ", gamestate))
}


plot_growth_state_loess <- function(data, gamestate, time_lim = 20) {
  data %>%
  dplyr::filter(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 = NA) +
    # 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) +
    # tidyquant::geom_ma(ma_fun = SMA, n = 1, color = "black") +
    stat_summary(fun = mean, geom = "line", colour = "black", lty = "dashed") +
    ylim(0, 100) +
    scale_x_continuous(breaks = 1:14) +
    ggtitle(paste0("Game state: ", gamestate)) +
    labs(color = "id")  
}

3.1 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, "10")


plot_growth_state_id(full_data_output_clean, "15")

plot_growth_state_id(full_data_output_clean, "16")

plot_growth_state_id(full_data_output_clean, "17")

plot_growth_state_id(full_data_output_clean, "18")

plot_growth_state_id(full_data_output_clean, "19")

3.2 Individual growth (object not considered)

Red = Loess Black dashed = Simple Mean

plot_growth_state_loess(full_data_output_clean, "10") + theme(legend.position = "none")


plot_growth_state_loess(full_data_output_clean, "15") + theme(legend.position = "none")

plot_growth_state_loess(full_data_output_clean, "16") + theme(legend.position = "none")

plot_growth_state_loess(full_data_output_clean, "17") + theme(legend.position = "none")

plot_growth_state_loess(full_data_output_clean, "18") + theme(legend.position = "none")

plot_growth_state_loess(full_data_output_clean, "19") + theme(legend.position = "none")

3.3 Alternating GameStates 10 and 17 for each participant by condition

full_data_output_clean %>%
  dplyr::filter(newGameState_clean %in% c("10", "17")) %>%
  dplyr::mutate(newGameState_clean = as.factor(newGameState_clean)) %>%  
  dplyr::group_by(id) %>%
  dplyr::mutate(time = dplyr::row_number()) %>%
    ggplot(aes(x = time, y = score)) +
    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")


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 LC_NUMERIC=C                     
[5] 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 rstatix_0.7.0     
 [8] broom_0.7.11       psych_2.1.9        forcats_0.5.1      stringr_1.4.0      dplyr_1.0.9        purrr_0.3.4        readr_2.0.1       
[15] tidyr_1.1.3        tibble_3.1.7       ggplot2_3.3.5      tidyverse_1.3.1    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                 tcltk_4.1.0              
 [31] crayon_1.5.1              jsonlite_1.8.0            zeallot_0.1.0             survival_3.2-13           zoo_1.8-9                
 [36] glue_1.6.2                gtable_0.3.0              emmeans_1.6.3             MatrixModels_0.5-0        statsExpressions_1.1.0   
 [41] car_3.0-11                Rmpfr_0.8-4               abind_1.4-5               rapportools_1.0           mvtnorm_1.1-2            
 [46] DBI_1.1.1                 PMCMRplus_1.9.0           Rcpp_1.0.7                xtable_1.8-4              performance_0.7.3        
 [51] tmvnsim_1.0-2             foreign_0.8-81            DT_0.19                   htmlwidgets_1.5.3         datawizard_0.2.0.1       
 [56] httr_1.4.3                ellipsis_0.3.2            farver_2.1.0              pkgconfig_2.0.3           reshape_0.8.8            
 [61] sass_0.4.1                multcompView_0.1-8        dbplyr_2.1.1              utf8_1.2.2                labeling_0.4.2           
 [66] effectsize_0.4.5          tidyselect_1.1.2          rlang_1.0.2               munsell_0.5.0             cellranger_1.1.0         
 [71] tools_4.1.0               cachem_1.0.6              cli_3.0.1                 generics_0.1.2            fastmap_1.1.0            
 [76] yaml_2.3.5                BWStest_0.2.2             rematch2_2.1.2            knitr_1.39                fs_1.5.2                 
 [81] zip_2.2.0                 pander_0.6.5              WRS2_1.1-3                pbapply_1.4-3             nlme_3.1-152             
 [86] xml2_1.3.3                correlation_0.7.0         compiler_4.1.0            rstudioapi_0.13           curl_4.3.2               
 [91] ggsignif_0.6.2            reprex_2.0.1              bslib_0.3.1               stringi_1.7.4             parameters_0.14.0        
 [96] lattice_0.20-44           Matrix_1.3-4              vctrs_0.4.1               pillar_1.7.0              lifecycle_1.0.1          
[101] mc2d_0.1-21               jquerylib_0.1.4           estimability_1.3          data.table_1.14.0         insight_0.14.4           
[106] patchwork_1.1.1           R6_2.5.1                  BayesFactor_0.9.12-4.2    codetools_0.2-18          MASS_7.3-54              
[111] gtools_3.9.2              assertthat_0.2.1          withr_2.5.0               mnormt_2.0.2              multcomp_1.4-17          
[116] mgcv_1.8-36               bayestestR_0.11.0         parallel_4.1.0            hms_1.1.1                 grid_4.1.0               
[121] coda_0.19-4               carData_3.0-4             lubridate_1.7.10          base64enc_0.1-3          

 


A work by Claudiu Papasteri

 

LS0tDQp0aXRsZTogIjxicj4gU1RBRCAtIERlbW8gYW5kIEltaXRhdGlvbiBNZXRyaWNzIiANCnN1YnRpdGxlOiAiVGVzdCBUd28gRWxkZXJseSINCmF1dGhvcjogIjxicj4gQ2xhdWRpdSBQYXBhc3RlcmkiDQpkYXRlOiAiYHIgZm9ybWF0KFN5cy50aW1lKCksICclZCAlbSAlWScpYCINCm91dHB1dDogDQogICAgaHRtbF9ub3RlYm9vazoNCiAgICAgICAgICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgICAgICAgICAgdG9jOiB0cnVlDQogICAgICAgICAgICB0b2NfZGVwdGg6IDINCiAgICAgICAgICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQ0KICAgICAgICAgICAgdGhlbWU6IHNwYWNlbGFiDQogICAgICAgICAgICBoaWdobGlnaHQ6IHRhbmdvDQogICAgICAgICAgICBmb250LWZhbWlseTogQXJpYWwNCiAgICAgICAgICAgIGZpZ193aWR0aDogMTANCiAgICAgICAgICAgIGZpZ19oZWlnaHQ6IDkNCiAgICAjIHBkZl9kb2N1bWVudDogDQogICAgICAgICAgICAjIHRvYzogdHJ1ZQ0KICAgICAgICAgICAgIyAgdG9jX2RlcHRoOiAyDQogICAgICAgICAgICAjICBudW1iZXJfc2VjdGlvbnM6IHRydWUNCiAgICAgICAgICAgICMgZm9udHNpemU6IDExcHQNCiAgICAgICAgICAgICMgZ2VvbWV0cnk6IG1hcmdpbj0xaW4NCiAgICAgICAgICAgICMgZmlnX3dpZHRoOiA3DQogICAgICAgICAgICAjIGZpZ19oZWlnaHQ6IDYNCiAgICAgICAgICAgICMgZmlnX2NhcHRpb246IHRydWUNCiAgICAjIGdpdGh1Yl9kb2N1bWVudDogDQogICAgICAgICAgICAjIHRvYzogdHJ1ZQ0KICAgICAgICAgICAgIyB0b2NfZGVwdGg6IDINCiAgICAgICAgICAgICMgaHRtbF9wcmV2aWV3OiBmYWxzZQ0KICAgICAgICAgICAgIyBmaWdfd2lkdGg6IDUNCiAgICAgICAgICAgICMgZmlnX2hlaWdodDogNQ0KICAgICAgICAgICAgIyBkZXY6IGpwZWcNCi0tLQ0KDQo8IS0tIFNldHVwIC0tPg0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCiMga2ludHIgb3B0aW9ucw0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KA0KICBjb21tZW50ID0gIiMiLA0KICBjb2xsYXBzZSA9IFRSVUUsDQogIGVjaG8gPSBUUlVFLCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2UgPSBUUlVFLCBjYWNoZSA9IFRSVUUgICAgICAgIyBlY2hvID0gRmFsc2UgZm9yIGdpdGh1Yl9kb2N1bWVudCwgYnV0IHdpbGwgYmUgZm9sZGVkIGluIGh0bWxfbm90ZWJvb2sNCikNCg0Kb3B0aW9ucyhkcGx5ci5zdW1tYXJpc2UuaW5mb3JtID0gRkFMU0UpICAgIyBhbm5veWluZyBzdW1tYXJpemUgbWVzc2FnZXMgcGFzcyB0aHJvdWdodCBtZXNzYWdlPUZBTFNFDQoNCiMgR2VuZXJhbCBSIG9wdGlvbnMgYW5kIGluZm8NClN5cy5zZXRlbnYoYF9SX1MzX01FVEhPRF9SRUdJU1RSQVRJT05fTk9URV9PVkVSV1JJVEVTX2AgPSAiZmFsc2UiKSAjIHN1cHByZXNzICJTMyBtZXRob2Qgb3ZlcndyaXR0ZW4iIGJlZm9yZSBsb2FkaW5nIHBhY2thZ2VzDQpzZXQuc2VlZCgxMTEpICAgICAgICAgICAgICAgIyBpbiBjYXNlIHdlIHVzZSByYW5kb21pemVkIHByb2NlZHVyZXMgICAgICAgDQpvcHRpb25zKHNjaXBlbiA9IDk5OSkgICAgICAgIyBwb3NpdGl2ZSB2YWx1ZXMgYmlhcyB0b3dhcmRzIGZpeGVkIGFuZCBuZWdhdGl2ZSB0b3dhcmRzIHNjaWVudGlmaWMgbm90YXRpb24NCg0KIyBMb2FkIHBhY2thZ2VzDQppZiAoIXJlcXVpcmUoInBhY21hbiIpKSBpbnN0YWxsLnBhY2thZ2VzKCJwYWNtYW4iKQ0KcGFja2FnZXMgPC0gYygNCiAgInBhcGFqYSIsDQogICJ0aWR5dmVyc2UiLCAgICAgIA0KICAicHN5Y2giLCAgICAgICAgICANCiAgImJyb29tIiwgInJzdGF0aXgiLA0KICAic3VtbWFyeXRvb2xzIiwgICAgICAgICAgICANCiAgImdncGxvdDIiLCAiZ2dwdWJyIiwgInNjYWxlcyIsICJzcGxpbmVzIiwgImNvd3Bsb3QiLCAiZ2dzdGF0c3Bsb3QiLCAgICAgICAgDQogICJyaW8iDQogICMgLCAuLi4NCikNCmlmICghcmVxdWlyZSgicGFjbWFuIikpIGluc3RhbGwucGFja2FnZXMoInBhY21hbiIpDQpwYWNtYW46OnBfbG9hZChjaGFyID0gcGFja2FnZXMpDQoNCiMgVGhlbWVzIGZvciBnZ3Bsb3QyIHBsb3RpbmcgKGhlcmUgdXNlZCBBUEEgc3R5bGUpDQp0aGVtZV9zZXQodGhlbWVfYXBhKCkpDQpgYGANCg0KPCEtLSBSZXBvcnQgLS0+DQoNCiMgUnVuIGRlbW9pbWl0TWV0cmljc19jbGVhbnRhYmxlIHNjcmlwdA0KDQpgYGB7ciwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmZvbGRlciA8LSAiQzovVXNlcnMvTWloYWkvRGVza3RvcC9SIE5vdGVib29rcy9ub3RlYm9va3MvU1RBRC1kZW1vaW1pdE1ldHJpY3MiDQpzZXR3ZChmb2xkZXIpDQoNCg0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCg0KIyBSZWFkIGNsZWFuIHRhYmxlDQpzZXNzaW9uc19jbGVhbl9kYXRhIDwtIHJlYWRSRFMoInNlc3Npb25zX2NsZWFuMmJhdHJhbmkuUkRTIikNCg0KIyBEZWZpbmUgZnVuY3Rpb24NCmxpc3RfdG9fbmVzdGVkIDwtIGZ1bmN0aW9uKGxpc3QsIGdyb3VwX3Zhcil7DQogIGxpc3QgJT4lDQogICAgZG8uY2FsbChkcGx5cjo6YmluZF9yb3dzLCAuKSAlPiUNCiAgICBkcGx5cjo6Z3JvdXBfYnkoIHt7IGdyb3VwX3ZhciB9fSApICU+JQ0KICAgIHRpZHlyOjpuZXN0KCkNCn0NCg0KIyBMaXN0cyBvZiByZWNvcmRpbmdzIHRvIG5lc3RlZCBkYXRhIGZyYW1lcw0Kc2Vzc2lvbnNfY2xlYW5fZGF0YV9kZiA8LSBsaXN0X3RvX25lc3RlZChzZXNzaW9uc19jbGVhbl9kYXRhLCBmaWxlKQ0KDQpzZXNzaW9uc19jbGVhbl9kYXRhX2RmIDwtDQogIHNlc3Npb25zX2NsZWFuX2RhdGFfZGYgJT4lDQogIGRwbHlyOjp1bmdyb3VwKCkgJT4lICAgICAgICMgY2FyZWZ1bCwgdGhlIGRmIGlzIGFscmVhZHkgZ3JvdXBlZA0KICBkcGx5cjo6bXV0YXRlKGlkID0gZHBseXI6OnJvd19udW1iZXIoKSkNCg0KZnVsbF9kYXRhX291dHB1dCA8LSBzZXNzaW9uc19jbGVhbl9kYXRhX2RmICU+JQ0KICBkcGx5cjo6cmVsb2NhdGUoaWQpICU+JQ0KICB0aWR5cjo6dW5uZXN0KGRhdGEpDQoNCg0KIyBTb21lIGFkZGl0aW9uYWwgdGlkeWluZw0KdmFyc19leGNsdWRlIDwtIGMoDQogICMgR2VuZXJhbCAgICANCiAgIklucHV0WSIsICJJbnB1dFgiLCAieFBvcyIsICJ5UG9zIiwgInpQb3MiLCAieFJvdCIsICJ5Um90IiwgInpSb3QiLCAid1JvdCIsICJtYXJrZXJYIiwgIm1hcmtlclkiLCAibWFya2VyWiIsDQogICMgRGVtbw0KICAiZGVtb01ldHJpY3NfcGxheWVyUG9zaXRpb25feCIsICJkZW1vTWV0cmljc19wbGF5ZXJQb3NpdGlvbl95IiwgImRlbW9NZXRyaWNzX3BsYXllclBvc2l0aW9uX3oiLCAiZGVtb01ldHJpY3NfbWFya2VyUG9zaXRpb25feCIsICANCiAgImRlbW9NZXRyaWNzX21hcmtlclBvc2l0aW9uX3kiLCAiZGVtb01ldHJpY3NfbWFya2VyUG9zaXRpb25feiIsICJkZW1vTWV0cmljc19kaXN0YW5jZUZyb21NYXJrZXIiLCANCiAgIyBJbWl0DQogICJpbWl0TWV0cmljc19wbGF5ZXJQb3NpdGlvbl94IiwgImltaXRNZXRyaWNzX3BsYXllclBvc2l0aW9uX3kiLCAiaW1pdE1ldHJpY3NfcGxheWVyUG9zaXRpb25feiIsICJpbWl0TWV0cmljc19tYXJrZXJQb3NpdGlvbl94IiwgDQogICJpbWl0TWV0cmljc19tYXJrZXJQb3NpdGlvbl95IiwgImltaXRNZXRyaWNzX21hcmtlclBvc2l0aW9uX3oiLCAiaW1pdE1ldHJpY3NfZGlzdGFuY2VGcm9tTWFya2VyIiwgDQogICMgc3luY0tleQ0KICAic3luY0tleSINCikNCg0KZnVsbF9kYXRhX291dHB1dF9jbGVhbiA8LSANCiAgZnVsbF9kYXRhX291dHB1dCAlPiUNCiAgZHBseXI6OnNlbGVjdCgtYW55X29mKHZhcnNfZXhjbHVkZSkpDQoNCg0KZnVsbF9kYXRhX291dHB1dF9jbGVhbiA8LSANCiAgZnVsbF9kYXRhX291dHB1dF9jbGVhbiAlPiUNCiAgZHBseXI6Om11dGF0ZShkZW1vaW1pdFN0YXRlID0gZHBseXI6OmNhc2Vfd2hlbihuZXdHYW1lU3RhdGVfZiAlaW4lIDU6MTEgfiAiRGVtbyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmV3R2FtZVN0YXRlX2YgJWluJSAxMjoyMCB+ICJJbWl0IiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gTkFfY2hhcmFjdGVyXykpICU+JQ0KICBkcGx5cjo6bXV0YXRlKHRpbWVTdGFtcF9kZW1vaW1pdCA9IGRwbHlyOjpjb2FsZXNjZSh0aW1lU3RhbXBfZGVtbywgdGltZVN0YW1wX2ltaXQpLCANCiAgICAgICAgICAgICAgICBwbGF5ZXJUeXBlID0gZHBseXI6OmNvYWxlc2NlKGRlbW9NZXRyaWNzX3BsYXllclR5cGUsIGltaXRNZXRyaWNzX3BsYXllclR5cGUpLA0KICAgICAgICAgICAgICAgIG1hcmtlclR5cGUgPSBkcGx5cjo6Y29hbGVzY2UoZGVtb01ldHJpY3NfbWFya2VyVHlwZSwgaW1pdE1ldHJpY3NfbWFya2VyVHlwZSksDQogICAgICAgICAgICAgICAgc2NvcmUgPSBkcGx5cjo6Y29hbGVzY2UoZGVtb01ldHJpY3Nfc2NvcmUsIGltaXRNZXRyaWNzX3Njb3JlKSkgJT4lIA0KICBkcGx5cjo6bXV0YXRlKHdobyA9IGRwbHlyOjpjYXNlX3doZW4oc3RyaW5ncjo6c3RyX2RldGVjdChmaWxlLCAiUExBWUVSXzEiKSB+IDFMLCAgICAgIyBjaGFuZ2VzIG91dHB1dF9maWxlX2NsZWFuIHRvIGZpbGUNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0cmluZ3I6OnN0cl9kZXRlY3QoZmlsZSwgIlBMQVlFUl8yIikgfiAyTCwgICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiBOQV9pbnRlZ2VyXykpICU+JQ0KICBkcGx5cjo6c2VsZWN0KC1jKGRlbW9NZXRyaWNzX3BsYXllclR5cGUsIGltaXRNZXRyaWNzX3BsYXllclR5cGUsIGRlbW9NZXRyaWNzX21hcmtlclR5cGUsIGltaXRNZXRyaWNzX21hcmtlclR5cGUsIGRlbW9NZXRyaWNzX3Njb3JlLCBpbWl0TWV0cmljc19zY29yZSwNCiAgICAgICAgICAgICAgICAgICB0aW1lU3RhbXBfZGVtbywgdGltZVN0YW1wX2ltaXQpKQ0KDQoNCiMgS2VlcCBvbmx5IGRhdGEgZnJvbSB0aGUgYWN0dWFsIHBsYXllciAod2hlcmUgcGxheWVyVHlwZSA9PSB3aG8pDQpmdWxsX2RhdGFfb3V0cHV0X2NsZWFuIDwtDQogIGZ1bGxfZGF0YV9vdXRwdXRfY2xlYW4gJT4lDQogIGRwbHlyOjpmaWx0ZXIocGxheWVyVHlwZSA9PSB3aG8pDQoNCg0KIyBFeGNsdWRlIG11bHRpcGxlIHRpbXBlU3RhbXBfZGVtb2ltaXQgcGVyIHRpbWVTdGFtcCBtYXRjaCAob25seSBhZGp1c3RpbmcgdG9sZXJhbmNlIHdpbGwgbG9zZSBkYXRhIGFzIG1hdGNoZXMgYXJlIG5vdCBleGFjdCkNCmZ1bGxfZGF0YV9vdXRwdXRfY2xlYW4gPC0NCiAgZnVsbF9kYXRhX291dHB1dF9jbGVhbiAlPiUNCiAgZHBseXI6Om11dGF0ZSh0aW1lU3RhbXBfZGlmZiA9IGFicyh0aW1lU3RhbXAgLSB0aW1lU3RhbXBfZGVtb2ltaXQpKSAlPiUNCiAgZHBseXI6Omdyb3VwX2J5KGlkLCB0aW1lU3RhbXBfZGVtb2ltaXQpICU+JQ0KICBkcGx5cjo6c2xpY2VfbWluKHRpbWVTdGFtcF9kaWZmKSAlPiUNCiAgZHBseXI6OnVuZ3JvdXAoKSAlPiUNCiAgZHBseXI6Omdyb3VwX2J5KGlkLCB0aW1lU3RhbXApICU+JQ0KICBkcGx5cjo6c2xpY2VfbWluKHRpbWVTdGFtcF9kaWZmKSAlPiUNCiAgZHBseXI6OnVuZ3JvdXAoKQ0KDQojIE1ha2UgbmV3R2FtZVN0YXRlX2NsZWFuIC0tLSBhIGJpdCBoYWNreSANCmZ1bGxfZGF0YV9vdXRwdXRfY2xlYW4gPC0NCiAgZnVsbF9kYXRhX291dHB1dF9jbGVhbiAlPiUNCiAgZHBseXI6Om11dGF0ZSgNCiAgICBuZXdHYW1lU3RhdGVfY2xlYW4gPSANCiAgICAgIGRwbHlyOjpjYXNlX3doZW4obmV3R2FtZVN0YXRlX2YgPT0gIjkiIH4gMTBMLCAgICAgICAgICAgICAjIGlzIDkgb3IgMTQgd2hlbiBpdCBzaG91bGQgYmUgMTAgb3IgMTUNCiAgICAgICAgICAgICAgICAgICAgICAgbmV3R2FtZVN0YXRlX2YgPT0gIjE0IiB+IDE1TCwNCiAgICAgICAgICAgICAgICAgICAgICAgbmV3R2FtZVN0YXRlX2YgJWluJSBhcy5jaGFyYWN0ZXIoYygxMCwgMTU6MTkpKSB+IGFzLmludGVnZXIobmV3R2FtZVN0YXRlX2YpLA0KICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gTkFfaW50ZWdlcl8NCiAgICAgICksDQogICAgbmV3R2FtZVN0YXRlX2NsZWFuID0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHNvbWUgbWF0Y2hlZCB0aGUgcHJldmlvdXMgZnJhbWUgc28gR2FtZVN0YXRlcyByZXBlYXQNCiAgICAgIGRwbHlyOjppZl9lbHNlKG5ld0dhbWVTdGF0ZV9jbGVhbiA9PSBkcGx5cjo6bGFnKG5ld0dhbWVTdGF0ZV9jbGVhbikgJiAhaXMubmEoZHBseXI6OmxhZyhuZXdHYW1lU3RhdGVfY2xlYW4pKSwgDQogICAgICAgICAgICAgICAgICAgICBuZXdHYW1lU3RhdGVfY2xlYW4gKyAxTCwgDQogICAgICAgICAgICAgICAgICAgICBuZXdHYW1lU3RhdGVfY2xlYW4NCiAgICAgKSwNCiAgICBuZXdHYW1lU3RhdGVfY2xlYW4gPSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgR2FtZVN0YXRlIDEwIGZvbGxvd2luZyBhbm90aGVyIDEwIG5vdyBiZWNhbWUgMTENCiAgICAgIGRwbHlyOjppZl9lbHNlKG5ld0dhbWVTdGF0ZV9jbGVhbiA9PSAxMUwsIDEwTCwgbmV3R2FtZVN0YXRlX2NsZWFuKQ0KICApICU+JSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgIUNBUkVGVUwgY29sdW1ucyBjb21wdXRlZCBiYXNlZCBvbiBuZXdHYW1lU3RhdGVfZiBsaWtlIGRlbW9pbWl0U3RhdGUgbm93IG1heSBiZSB3cm9uZw0KICBkcGx5cjo6bXV0YXRlKGRlbW9pbWl0U3RhdGVfY2xlYW4gPSBkcGx5cjo6Y2FzZV93aGVuKG5ld0dhbWVTdGF0ZV9jbGVhbiAlaW4lIDU6MTEgfiAiRGVtbyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmV3R2FtZVN0YXRlX2NsZWFuICVpbiUgMTI6MjAgfiAiSW1pdCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+IE5BX2NoYXJhY3Rlcl8pKQ0KDQojIENoZWNrIEdhbWVTdGF0ZXMNCmNoZWNrX2RmIDwtDQogIGZ1bGxfZGF0YV9vdXRwdXRfY2xlYW4gJT4lDQogIGRwbHlyOjpncm91cF9ieShpZCkgJT4lDQogIGRwbHlyOjptdXRhdGUoZ3JwID0gYXMuaW50ZWdlcihnbChuKCksIDYsIG4oKSkpKSAlPiUgICAgIyBncm91cCBldmVyeSA2IHJvd3MNCiAgZHBseXI6Omdyb3VwX2J5KGlkLCBncnApICU+JQ0KICBkcGx5cjo6c3VtbWFyaXNlKHBhdHRlcm4gPSBwYXN0ZTAobmV3R2FtZVN0YXRlX2YsIGNvbGxhcHNlID0gIiAiKSwNCiAgICAgICAgICAgICAgICAgICBwYXR0ZXJuX2NsZWFuID0gcGFzdGUwKG5ld0dhbWVTdGF0ZV9jbGVhbiwgY29sbGFwc2UgPSAiICIpKQ0KYGBgDQoNCiMjIENoZWNrIEdhbWVzU3RhdGVzDQoNCmBgYHtyfQ0KY2hlY2tfZGYNCmBgYA0KDQoNCiMgRGF0YQ0KDQpgYGB7cn0NCmZ1bGxfZGF0YV9vdXRwdXRfY2xlYW4gJT4lDQogIERUOjpkYXRhdGFibGUoICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgZXhjZWwgZG93bmxvYWRhYmxlICBEVCB0YWJsZQ0KICBleHRlbnNpb25zID0gJ0J1dHRvbnMnLA0KICBvcHRpb25zID0gbGlzdChwYWdlTGVuZ3RoID0gNSwNCiAgICAgICAgICAgICAgICAgc2Nyb2xsWCA9ICc1MDBweCcsIA0KICAgICAgICAgICAgICAgICBkb20gPSAnQmZydGlwJywgDQogICAgICAgICAgICAgICAgIGJ1dHRvbnMgPSBjKCdleGNlbCcsICJjc3YiKSkpICU+JQ0KICBEVDo6Zm9ybWF0U3R5bGUobmFtZXMoZnVsbF9kYXRhX291dHB1dF9jbGVhbiksbGluZUhlaWdodCA9ICI2MCUiKSAgICAjIHNsaW1tZXIgcm93cw0KYGBgDQoNCiMgUHJlbGltaW5hcnkgQW5hbHlzZXMNCg0KIyMjIEZ1bmN0aW9ucw0KDQpgYGB7cn0NCnBsb3RfZ3Jvd3RoX3N0YXRlX2lkIDwtIGZ1bmN0aW9uKGRhdGEsIGdhbWVzdGF0ZSwgdGltZV9saW0gPSAyMCkgew0KICBkYXRhICU+JQ0KICBkcGx5cjo6ZmlsdGVyKG5ld0dhbWVTdGF0ZV9jbGVhbiA9PSBnYW1lc3RhdGUpICU+JQ0KICBncm91cF9ieShpZCkgJT4lDQogIGRwbHlyOjptdXRhdGUodGltZSA9IGRwbHlyOjpyb3dfbnVtYmVyKCkpICU+JQ0KICBkcGx5cjo6ZmlsdGVyKHRpbWUgPCB0aW1lX2xpbSkgJT4lICANCiAgICBnZ3Bsb3QoYWVzKHggPSB0aW1lLCB5ID0gc2NvcmUpKSArDQogICAgZ2VvbV9saW5lKCkgKw0KICAgIGZhY2V0X3dyYXAofmlkKSArDQogICAgeWxpbSgwLCAxMDApICsNCiAgICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gMToxNCkgKw0KICAgIGdndGl0bGUocGFzdGUwKCJHYW1lIHN0YXRlOiAiLCBnYW1lc3RhdGUpKQ0KfQ0KDQoNCnBsb3RfZ3Jvd3RoX3N0YXRlX2xvZXNzIDwtIGZ1bmN0aW9uKGRhdGEsIGdhbWVzdGF0ZSwgdGltZV9saW0gPSAyMCkgew0KICBkYXRhICU+JQ0KICBkcGx5cjo6ZmlsdGVyKG5ld0dhbWVTdGF0ZV9jbGVhbiA9PSBnYW1lc3RhdGUpICU+JQ0KICBncm91cF9ieShpZCkgJT4lDQogIGRwbHlyOjptdXRhdGUodGltZSA9IGRwbHlyOjpyb3dfbnVtYmVyKCkpICU+JQ0KICBkcGx5cjo6ZmlsdGVyKHRpbWUgPCB0aW1lX2xpbSkgJT4lICAgDQogICAgZ2dwbG90KGFlcyh4ID0gdGltZSwgeSA9IHNjb3JlKSkgKw0KICAgIGdlb21fbGluZShhZXMoY29sb3IgPSBhcy5mYWN0b3IoaWQpKSwgYWxwaGEgPSAuNSkgKw0KICAgIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsb2VzcyIsIGZvcm11bGEgPSAieSB+IHgiLCBjb2xvciA9ICJyZWQiLCBmaWxsID0gTkEpICsNCiAgICAjIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIGZvcm11bGEgPSB5IH4gc3BsaW5lczo6YnMoeCwga25vdHMgPSBzZXEoMiAsIDE2LCBieSA9IDIpLCBkZWdyZWUgPSAxKSwgDQogICAgIyAgICAgICAgICAgICBzZSA9IEZBTFNFLCBjb2xvciA9ICJibGFjayIsIGZpbGwgPSAiZ3JheSIsIGFscGhhID0gMC44KSArDQogICAgIyB0aWR5cXVhbnQ6Omdlb21fbWEobWFfZnVuID0gU01BLCBuID0gMSwgY29sb3IgPSAiYmxhY2siKSArDQogICAgc3RhdF9zdW1tYXJ5KGZ1biA9IG1lYW4sIGdlb20gPSAibGluZSIsIGNvbG91ciA9ICJibGFjayIsIGx0eSA9ICJkYXNoZWQiKSArDQogICAgeWxpbSgwLCAxMDApICsNCiAgICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gMToxNCkgKw0KICAgIGdndGl0bGUocGFzdGUwKCJHYW1lIHN0YXRlOiAiLCBnYW1lc3RhdGUpKSArDQogICAgbGFicyhjb2xvciA9ICJpZCIpICANCn0NCg0KYGBgDQoNCg0KIyMgSW5kaXZpZHVhbCBncm93dGggKG9iamVjdCBub3QgY29uc2lkZXJlZCkNCg0KTm90ZXM6DQoNCjEuICBWYXJpYWJpbGl0eSBpcyB0aGUgbm9ybQ0KDQoyLiAgVHJlbmQgaXMgbm90IGVhc2lseSBkaXNjZXJuaWJsZQ0KDQpgYGB7ciwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9OH0NCnBsb3RfZ3Jvd3RoX3N0YXRlX2lkKGZ1bGxfZGF0YV9vdXRwdXRfY2xlYW4sICIxMCIpDQoNCnBsb3RfZ3Jvd3RoX3N0YXRlX2lkKGZ1bGxfZGF0YV9vdXRwdXRfY2xlYW4sICIxNSIpDQpwbG90X2dyb3d0aF9zdGF0ZV9pZChmdWxsX2RhdGFfb3V0cHV0X2NsZWFuLCAiMTYiKQ0KcGxvdF9ncm93dGhfc3RhdGVfaWQoZnVsbF9kYXRhX291dHB1dF9jbGVhbiwgIjE3IikNCnBsb3RfZ3Jvd3RoX3N0YXRlX2lkKGZ1bGxfZGF0YV9vdXRwdXRfY2xlYW4sICIxOCIpDQpwbG90X2dyb3d0aF9zdGF0ZV9pZChmdWxsX2RhdGFfb3V0cHV0X2NsZWFuLCAiMTkiKQ0KYGBgDQoNCiMjIEluZGl2aWR1YWwgZ3Jvd3RoIChvYmplY3Qgbm90IGNvbnNpZGVyZWQpDQoNClJlZCA9IExvZXNzDQpCbGFjayBkYXNoZWQgPSBTaW1wbGUgTWVhbg0KDQpgYGB7ciwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9N30NCnBsb3RfZ3Jvd3RoX3N0YXRlX2xvZXNzKGZ1bGxfZGF0YV9vdXRwdXRfY2xlYW4sICIxMCIpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KDQpwbG90X2dyb3d0aF9zdGF0ZV9sb2VzcyhmdWxsX2RhdGFfb3V0cHV0X2NsZWFuLCAiMTUiKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikNCnBsb3RfZ3Jvd3RoX3N0YXRlX2xvZXNzKGZ1bGxfZGF0YV9vdXRwdXRfY2xlYW4sICIxNiIpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KcGxvdF9ncm93dGhfc3RhdGVfbG9lc3MoZnVsbF9kYXRhX291dHB1dF9jbGVhbiwgIjE3IikgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpDQpwbG90X2dyb3d0aF9zdGF0ZV9sb2VzcyhmdWxsX2RhdGFfb3V0cHV0X2NsZWFuLCAiMTgiKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikNCnBsb3RfZ3Jvd3RoX3N0YXRlX2xvZXNzKGZ1bGxfZGF0YV9vdXRwdXRfY2xlYW4sICIxOSIpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KYGBgDQoNCg0KIyMgQWx0ZXJuYXRpbmcgR2FtZVN0YXRlcyAxMCBhbmQgMTcgZm9yIGVhY2ggcGFydGljaXBhbnQgYnkgY29uZGl0aW9uDQoNCg0KYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEwfQ0KZnVsbF9kYXRhX291dHB1dF9jbGVhbiAlPiUNCiAgZHBseXI6OmZpbHRlcihuZXdHYW1lU3RhdGVfY2xlYW4gJWluJSBjKCIxMCIsICIxNyIpKSAlPiUNCiAgZHBseXI6Om11dGF0ZShuZXdHYW1lU3RhdGVfY2xlYW4gPSBhcy5mYWN0b3IobmV3R2FtZVN0YXRlX2NsZWFuKSkgJT4lICANCiAgZHBseXI6Omdyb3VwX2J5KGlkKSAlPiUNCiAgZHBseXI6Om11dGF0ZSh0aW1lID0gZHBseXI6OnJvd19udW1iZXIoKSkgJT4lDQogICAgZ2dwbG90KGFlcyh4ID0gdGltZSwgeSA9IHNjb3JlKSkgKw0KICAgIGdlb21fbGluZSgpICsNCiAgICBnZW9tX3BvaW50KGFlcyhzaGFwZSA9IG5ld0dhbWVTdGF0ZV9jbGVhbikpICsNCiAgICBmYWNldF93cmFwKH5pZCkgKw0KICAgIHlsaW0oMCwgMTAwKSArDQogICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IDE6MTQpICsNCiAgICBnZ3RpdGxlKCJBbHRlcm5hdGluZyBHYW1lU3RhdGUgMTAgYW5kIDE3IikgKyANCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiKQ0KYGBgDQoNCg0KDQoNCg0KDQoNCjwhLS0gU2Vzc2lvbiBJbmZvIGFuZCBMaWNlbnNlIC0tPg0KDQo8YnI+DQoNCiMgU2Vzc2lvbiBJbmZvDQoNCmBgYHtyIHNlc3Npb25faW5mbywgZWNobyA9IEZBTFNFLCByZXN1bHRzID0gJ21hcmt1cCd9DQpzZXNzaW9uSW5mbygpICAgIA0KYGBgDQoNCjwhLS0gRm9vdGVyIC0tPg0KDQrCoA0KDQo8aHIgLz4NCg0KPHAgc3R5bGU9InRleHQtYWxpZ246IGNlbnRlcjsiPg0KDQpBIHdvcmsgYnkgPGEgaHJlZj0iaHR0cHM6Ly9naXRodWIuY29tL0NsYXVkaXVQYXBhc3RlcmkvIj5DbGF1ZGl1IFBhcGFzdGVyaTwvYT4NCg0KPC9wPg0KDQo8cCBzdHlsZT0idGV4dC1hbGlnbjogY2VudGVyOyI+DQoNCjxlbT5bY2xhdWRpdS5wYXBhc3RlcmlcQGdtYWlsLmNvbV0obWFpbHRvOmNsYXVkaXUucGFwYXN0ZXJpQGdtYWlsLmNvbSl7LmVtYWlsfTwvZW0+DQoNCjwvcD4NCg0KwqANCg==