Using recurrence networks to summarise time series of MS users in APPS MS
Read in necessary libraries, functions and look up tables
library(igraph)
library(qgraph)
library(casnet)
library(plyr)
library(dplyr)
library(tidyr)
library(caret)
library(psych)
library(lme4)
library(reshape2)
library(lubridate)
library(parallel)
library(wesanderson)
library(stringr)
library(matrixStats)
library(ggthemes)
library(gridExtra)
library(cowplot)
library(DataExplorer)
# save the original plotting space parameters
og_par <- par()
Read in data
plot_intro(dai_df)

plot_bar(dai_df)
3 columns ignored with more than 50 categories.
User: 102 categories
date: 125 categories
strategies: 1035 categories

plot_correlation(dai_df)
4 features with more than 20 categories ignored!
User: 102 categories
date: 125 categories
howami_participation_started: 37 categories
strategies: 1035 categories

[1] "absorption" "amotivation" "autonomy" "competence" "dedication" "emotional_drain" "enjoyment" "external.pressure"
[9] "importance" "interest" "internal.pressure" "productivity_work" "relatedness" "satisfaction_work" "time_pressure" "vigor"
Split the keystroke df into a list of dfs based on User
# head(dai_df)
# dai_df %>% group_by(User) %>% summarize(count = n())
df_list <- split(dai_df[c("User", vars)], dai_df["User"])
Define the functions which will be applied to each user individually
Select users with long enough time series
user_row_lengths_list <- lapply(df_list, function(x) length(rownames(x)))
user_row_lengths_df <- t(data.frame(user_row_lengths_list))
user_row_lengths_df <- data.frame(cbind(user_row_lengths_df, unique(dai_df$User)))
user_row_lengths_df$X1 <- as.numeric(user_row_lengths_df$X1)
# User_list <- user_row_lengths_df[user_row_lengths_df["X1"] > 30, "X2"]
# User_list <- unique(dai_df$User)
# User_list <- c('Moti148', 'Moti143', 'Moti140', 'Moti156', 'Moti151')
User_list <- c(
# 'Moti114',
'Moti147',
'Moti149',
'Moti164',
'Moti106',
'Moti121',
'Moti137',
'Moti138',
'Moti150',
'Moti157',
'Moti148',
'Moti143',
'Moti140',
'Moti156',
'Moti151')
df_list <- df_list[names(df_list) %in% User_list]
# df_list_imp_scal <- df_list_imp_scal[names(df_list_imp_scal) %in% User_list]
Prepare the data (impute and min max scale) and plot an example feature
df_list_imp <- lapply(df_list, apply_imputation, vars)
Number of logged events: 60replacement element 1 has 125 rows to replace 60 rowsNumber of logged events: 35replacement element 1 has 125 rows to replace 60 rowsreplacement element 1 has 125 rows to replace 60 rowsreplacement element 1 has 125 rows to replace 60 rowsreplacement element 1 has 125 rows to replace 60 rowsreplacement element 1 has 125 rows to replace 60 rowsreplacement element 1 has 125 rows to replace 60 rowsreplacement element 1 has 125 rows to replace 60 rowsreplacement element 1 has 125 rows to replace 60 rowsreplacement element 1 has 125 rows to replace 60 rowsreplacement element 1 has 125 rows to replace 60 rowsreplacement element 1 has 125 rows to replace 60 rowsreplacement element 1 has 125 rows to replace 60 rowsreplacement element 1 has 125 rows to replace 60 rows
df_list_imp_scal <- lapply(df_list_imp, apply_scaling, vars)
df_list_imp[example_user]
$Moti143
df_list_imp_scal[example_user]
$Moti143
NA
Remove users from the imputed and scaled dfs list that had too many missing values
user_drop_list <- c()
for (User in User_list) {
missing_amount <- sum(sapply(df_list_imp_scal[[as.character(User)]], function(x) sum(is.na(x))))
# print(User)
# print(missing_amount)
if (missing_amount > 0) {
print(User)
print(missing_amount)
user_drop_list <- c(user_drop_list, as.character(User))
}
}
df_list_imp_scal <- df_list_imp_scal[!names(df_list_imp_scal) %in% user_drop_list]
# for (User in unique(dai_df$User)) {
# print(User)
# apply_RP_measures(df_list_imp_scal[as.character(User)], vars, emLag, emDim)
# }
Identify the feature with the most variable Determinism (variance within users) and assign this the feature of interest for the rest of the analysis.
all_RP_measures_df <- reshape::merge_all(RP_measures_list)
rqa_feature <- "DET" #TT_vl
all_RP_measures_df_long <- melt(all_RP_measures_df[, c("feature", rqa_feature)], id.vars = "feature")
g <- ggplot(all_RP_measures_df_long, aes(x=feature, y=value)) +
geom_boxplot(outlier.colour="#e58038", outlier.shape=8,
outlier.size=4) +
theme(axis.text.x = element_text(angle = 90))
print(g)

agg_RP_measures_df <- aggregate(all_RP_measures_df[, c(rqa_feature)], list(all_RP_measures_df$feature), var, na.rm=TRUE)
colnames(agg_RP_measures_df) <- c("feature", rqa_feature)
feature_of_interest <- agg_RP_measures_df[which(agg_RP_measures_df[rqa_feature]==max(agg_RP_measures_df[rqa_feature])), "feature"][1]
print("New feature of interest:")
[1] "New feature of interest:"
feature_of_interest
[1] "enjoyment"
Spiral graphs of the feature of interest per user with embedding lag and embedding dimension the same across all users














plot.ts(x=df_list_imp_scal[["Moti156"]]$enjoyment)

plot.ts(x=df_list[["Moti156"]]$enjoyment)

feature_of_interest_RN_measures_df <- reshape::merge_all(RN_measures_list)
# write.csv(feature_of_interest_RN_measures_df,
# file=paste("data/", feature_of_interest, "_RN_measures.csv", sep = ""))
LS0tCnRpdGxlOiAiUmVjdXJyZW5jZSBOZXR3b3JrcyBvZiBEYWlseSBxdWVzdGlvbm5haXJlcyBvbiB3b3JrIG1vdGl2YXRpb24iCnN1YnRpdGxlOiAiICIKYXV0aG9yOiAKLSAiSmFtZXMgVHdvc2UiCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgY29kZV9mb2xkaW5nOiBoaWRlCi0tLQoKIyMgVXNpbmcgcmVjdXJyZW5jZSBuZXR3b3JrcyB0byBzdW1tYXJpc2UgdGltZSBzZXJpZXMgb2YgTVMgdXNlcnMgaW4gQVBQUyBNUwoKIyMjIyBSZWFkIGluIG5lY2Vzc2FyeSBsaWJyYXJpZXMsIGZ1bmN0aW9ucyBhbmQgbG9vayB1cCB0YWJsZXMKCmBgYHtyIGVjaG89VFJVRSwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KbGlicmFyeShpZ3JhcGgpCmxpYnJhcnkocWdyYXBoKQpsaWJyYXJ5KGNhc25ldCkKbGlicmFyeShwbHlyKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHRpZHlyKQpsaWJyYXJ5KGNhcmV0KQpsaWJyYXJ5KHBzeWNoKQpsaWJyYXJ5KGxtZTQpCmxpYnJhcnkocmVzaGFwZTIpCmxpYnJhcnkobHVicmlkYXRlKQpsaWJyYXJ5KHBhcmFsbGVsKQpsaWJyYXJ5KHdlc2FuZGVyc29uKQpsaWJyYXJ5KHN0cmluZ3IpCmxpYnJhcnkobWF0cml4U3RhdHMpCmxpYnJhcnkoZ2d0aGVtZXMpCmxpYnJhcnkoZ3JpZEV4dHJhKQpsaWJyYXJ5KGNvd3Bsb3QpCmxpYnJhcnkoRGF0YUV4cGxvcmVyKQoKCiMgc2F2ZSB0aGUgb3JpZ2luYWwgcGxvdHRpbmcgc3BhY2UgcGFyYW1ldGVycwpvZ19wYXIgPC0gcGFyKCkKYGBgCgojIyMjIyBTaG93IHRoZSBzZXNzaW9uIGluZm9ybWF0aW9uCmBgYHtyfQpkZXZ0b29sczo6c2Vzc2lvbl9pbmZvKCkKYGBgCgojIyMjIFJlYWQgaW4gZGF0YQoKYGBge3IsIGVjaG89RkFMU0UsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9CiMgZGFpX2RmIDwtIHJlYWQuY3N2KCJkYXRhL3JlbGFwc2Vfd19tYXRjaGVkX3VzZXJzX2tleV9jbHVzdGVycy5jc3YiLCByb3cubmFtZXMgPSAiWCIpCmRhaV9kZiA8LSByZWFkLmNzdigiZGF0YS9tb3RpX2ZlYXNpYmlsaXR5X2phbWVzX2RhaWx5X3Bpdm90LmNzdiIsIHJvdy5uYW1lcyA9ICJYIikKZmVhdHVyZV9vZl9pbnRlcmVzdCA8LSAiZGVkaWNhdGlvbiIKYGBgCgpgYGB7cn0KcGxvdF9pbnRybyhkYWlfZGYpCnBsb3RfYmFyKGRhaV9kZikKcGxvdF9jb3JyZWxhdGlvbihkYWlfZGYpCmBgYAoKCmBgYHtyLCBlY2hvPVRydWUsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9CmV4YW1wbGVfdXNlciA8LSAiTW90aTE0MyIKZGYgPC0gZGFpX2RmW2RhaV9kZlsiVXNlciJdID09IGV4YW1wbGVfdXNlciwgXQojIHZhcnMgPC0gY29sbmFtZXMoZGFpX2RmKVs1OjhdI1szOjYwXQp2YXJzIDwtIGMoImFic29ycHRpb24iLCAiYW1vdGl2YXRpb24iLCAiYXV0b25vbXkiLCAiY29tcGV0ZW5jZSIsICJkZWRpY2F0aW9uIiwgImVtb3Rpb25hbF9kcmFpbiIsICJlbmpveW1lbnQiLCAKICAgICAgICAgICJleHRlcm5hbC5wcmVzc3VyZSIsICJpbXBvcnRhbmNlIiwgImludGVyZXN0IiwgImludGVybmFsLnByZXNzdXJlIiwgInByb2R1Y3Rpdml0eV93b3JrIiwgInJlbGF0ZWRuZXNzIiwgInNhdGlzZmFjdGlvbl93b3JrIiwgInRpbWVfcHJlc3N1cmUiLCAidmlnb3IiKQp2YXJzCmBgYAoKIyMjIFNwbGl0IHRoZSBrZXlzdHJva2UgZGYgaW50byBhIGxpc3Qgb2YgZGZzIGJhc2VkIG9uIFVzZXIKCmBgYHtyfQojIGhlYWQoZGFpX2RmKQojIGRhaV9kZiAlPiUgZ3JvdXBfYnkoVXNlcikgJT4lIHN1bW1hcml6ZShjb3VudCA9IG4oKSkKCmRmX2xpc3QgPC0gc3BsaXQoZGFpX2RmW2MoIlVzZXIiLCB2YXJzKV0sIGRhaV9kZlsiVXNlciJdKQpgYGAKCiMjIyBEZWZpbmUgdGhlIGZ1bmN0aW9ucyB3aGljaCB3aWxsIGJlIGFwcGxpZWQgdG8gZWFjaCB1c2VyIGluZGl2aWR1YWxseQoKYGBge3IsIGVjaG89RkFMU0UsIHdhcm5pbmc9RkFMU0UsIG1lc3NhZ2U9RkFMU0V9CiMgSW1wdXRlIG1pc3NpbmcgdmFsdWVzIHdpdGggQ2xhc3NpZmljYXRpb24gQW5kIFJlZ3Jlc3Npb24gVHJlZXMgLyBSYW5kb20gRm9yZXN0cwojIFJGIGFuZCBDQVJUIHJldHVybiAoaWRlbnRpY2FsKSBkaXNjcmV0ZSBudW1iZXJzCiMgaW1wLmNhcnQgIDwtIG1pY2U6Om1pY2UoZGZbdmFyc10sIG1ldGhvZCA9ICdjYXJ0JywgcmVtb3ZlLmNvbnN0YW50ID0gVFJVRSwgcmVtb3ZlLmNvbGxpbmVhciA9IFRSVUUsIHByaW50RmxhZyA9IEZBTFNFKQojIGRmX2ltcCAgPC0gbWljZTo6Y29tcGxldGUoaW1wLmNhcnQpCgpxdWlldCA8LSBmdW5jdGlvbih4KSB7IAogIHNpbmsodGVtcGZpbGUoKSkgCiAgb24uZXhpdChzaW5rKCkpIAogIGludmlzaWJsZShmb3JjZSh4KSkgCn0gCgphcHBseV9pbXB1dGF0aW9uIDwtIGZ1bmN0aW9uKGRmLCB2YXJzKXsKICBpbXAuY2FydCAgPC0gbWljZTo6bWljZShkZlsxOjYwLCB2YXJzXSwgbWV0aG9kID0gJ2NhcnQnLCByZW1vdmUuY29uc3RhbnQgPSBUUlVFLCByZW1vdmUuY29sbGluZWFyID0gVFJVRSwgcHJpbnRGbGFnID0gRkFMU0UpCiAgIyBpbXAuY2FydCAgPC0gbWljZTo6bWljZShkZlt2YXJzXSwgbWV0aG9kID0gJ2NhcnQnLCByZW1vdmUuY29uc3RhbnQgPSBUUlVFLCByZW1vdmUuY29sbGluZWFyID0gVFJVRSwgcHJpbnRGbGFnID0gRkFMU0UpCiAgZGZfaW1wICA8LSBtaWNlOjpjb21wbGV0ZShpbXAuY2FydCkKICBkZl9pbXBbIlVzZXIiXSA8LSBkZlsiVXNlciJdCiAgcmV0dXJuKGRmX2ltcCkKfQoKCmFwcGx5X3NjYWxpbmcgPC0gZnVuY3Rpb24oZGYsIHZhcnMpIHsKICBkZl9zY2FsIDwtIGRhdGEuZnJhbWUoYXBwbHkoZGZbdmFyc10sIDIsIGVsYXNjZXIpKQogIGRmX3NjYWxbIlVzZXIiXSA8LSBkZlsiVXNlciJdCiAgcmV0dXJuKGRmX3NjYWwpCn0KCmFwcGx5X1JQX21lYXN1cmVzIDwtIGZ1bmN0aW9uKGRmLCB2YXJzLCBlbURpbSwgZW1MYWcpIHsKCiAgUlBzIDwtIHBseXI6OmxscGx5KDE6bGVuZ3RoKHZhcnMpLCBmdW5jdGlvbihyKSBycCh5MSA9IGRmWzE6NjAsIHJdLCBlbURpbSA9IGVtRGltLCBlbUxhZyA9IGVtTGFnLCBlbVJhZCA9IE5BLCB0YXJnZXRWYWx1ZSA9IDAuMDUpKQogICMgUlBzIDwtIHBseXI6OmxscGx5KDE6bGVuZ3RoKHZhcnMpLCBmdW5jdGlvbihyKSBycCh5MSA9IGRmWywgcl0sIGVtRGltID0gZW1EaW0sIGVtTGFnID0gZW1MYWcsIGVtUmFkID0gTkEsIHRhcmdldFZhbHVlID0gMC4wNSkpCiAgcHJpbnQoZGZbMSwgIlVzZXIiXSkKICBSUF9tZWFzdXJlc19saXN0IDwtIHBseXI6OmxscGx5KFJQcywgZnVuY3Rpb24ocikgcnBfbWVhc3VyZXMoUk09ciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVtUmFkID0gMC4wNSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIERMbWluID0gMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFZMbWluID0gMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIEhMbWluID0gMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpbGVudCA9IFRSVUUpKQogIAogIHVzZXJfcnBfbWVhc3VyZXNfZGYgPC0gcmVzaGFwZTo6bWVyZ2VfYWxsKFJQX21lYXN1cmVzX2xpc3QpIAogIHVzZXJfcnBfbWVhc3VyZXNfZGYgPC0gdXNlcl9ycF9tZWFzdXJlc19kZltvcmRlcihhcy5udW1lcmljKHJvd25hbWVzKHVzZXJfcnBfbWVhc3VyZXNfZGYpKSksIF0KICB1c2VyX3JwX21lYXN1cmVzX2RmWyJmZWF0dXJlIl0gPC0gdmFycwogIHVzZXJfcnBfbWVhc3VyZXNfZGZbIlVzZXIiXSA8LSBkZlsiVXNlciJdCiAgcmV0dXJuKHVzZXJfcnBfbWVhc3VyZXNfZGYpCn0KCgphcHBseV9STl9wbG90cyA8LSBmdW5jdGlvbihkZiwgZmVhdHVyZV9vZl9pbnRlcmVzdCwgZW1EaW0sIGVtTGFnKSB7CiAgUk4gPC0gcm4oeTEgPSBkZlsxOjYwLCBmZWF0dXJlX29mX2ludGVyZXN0XSwgZW1EaW0gPSBlbURpbSwgZW1MYWcgPSBlbUxhZywgZW1SYWQgPSBOQSwgdGFyZ2V0VmFsdWUgPSAwLjA1KQogICMgUk4gPC0gcm4oeTEgPSBkZlssIGZlYXR1cmVfb2ZfaW50ZXJlc3RdLCBlbURpbSA9IGVtRGltLCBlbUxhZyA9IGVtTGFnLCBlbVJhZCA9IE5BLCB0YXJnZXRWYWx1ZSA9IDAuMDUpCiAgCiAgYXJjcyA8LSA2CiAgVXNlciA8LSBkZlsxLCAiVXNlciJdCgogIGcxIDwtIGlncmFwaDo6Z3JhcGhfZnJvbV9hZGphY2VuY3lfbWF0cml4KFJOLCBtb2RlPSJ1bmRpcmVjdGVkIiwgZGlhZyA9IEZBTFNFKQogIGlncmFwaDo6VihnMSkkc2l6ZSA8LSBpZ3JhcGg6OmRlZ3JlZShnMSkKICBnMXIgPC0gY2FzbmV0OjptYWtlX3NwaXJhbF9ncmFwaChnMSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgdHlwZSA9ICJFdWxlciIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXJjcyA9IGFyY3MsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZXBvY2hDb2xvdXJzID0gZ2V0Q29sb3VycyhhcmNzKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aXRsZSA9IHBhc3RlKCJVc2VyID09IiwgVXNlciksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFya1RpbWVCeSA9IFRSVUUpCiAgZ2dzYXZlKHBhc3RlMCgiaW1hZ2VzL3NwaXJhbF9ncmFwaF9zaG9ydCIsIFVzZXIsICIucG5nIikpCiAgcmV0dXJuKGcxcikKfQoKYXBwbHlfUk5fbWVhc3VyZXMgPC0gZnVuY3Rpb24oZGYsIGZlYXR1cmVfb2ZfaW50ZXJlc3QsIGVtRGltLCBlbUxhZykgewogIFJOIDwtIHJuKHkxID0gZGZbMTo2MCwgZmVhdHVyZV9vZl9pbnRlcmVzdF0sIGVtRGltID0gZW1EaW0sIGVtTGFnID0gZW1MYWcsIGVtUmFkID0gTkEsIHRhcmdldFZhbHVlID0gMC4wNSkKICAjIFJOIDwtIHJuKHkxID0gZGZbLCBmZWF0dXJlX29mX2ludGVyZXN0XSwgZW1EaW0gPSBlbURpbSwgZW1MYWcgPSBlbUxhZywgZW1SYWQgPSBOQSwgdGFyZ2V0VmFsdWUgPSAwLjA1KQogIAogIGFyY3MgPC0gNgogIFVzZXIgPC0gZGZbMSwgIlVzZXIiXQoKICBnMSA8LSBpZ3JhcGg6OmdyYXBoX2Zyb21fYWRqYWNlbmN5X21hdHJpeChSTiwgbW9kZT0idW5kaXJlY3RlZCIsIGRpYWcgPSBGQUxTRSkKICBuZXR3b3JrX21lYXN1cmVzIDwtIHJuX21lYXN1cmVzKGcxLCBzaWxlbnQgPSBUUlVFKQogIGdyYXBoX21lYXN1cmVzX2RmIDwtIG5ldHdvcmtfbWVhc3VyZXMkZ3JhcGhfbWVhc3VyZXMKICBncmFwaF9tZWFzdXJlc19kZlsiVXNlciJdIDwtIGRmWyJVc2VyIl0KCiAgcmV0dXJuKGdyYXBoX21lYXN1cmVzX2RmKQp9CgpgYGAKCiMjIyBTZWxlY3QgdXNlcnMgd2l0aCBsb25nIGVub3VnaCB0aW1lIHNlcmllcwpgYGB7cn0KdXNlcl9yb3dfbGVuZ3Roc19saXN0IDwtIGxhcHBseShkZl9saXN0LCBmdW5jdGlvbih4KSBsZW5ndGgocm93bmFtZXMoeCkpKQp1c2VyX3Jvd19sZW5ndGhzX2RmIDwtIHQoZGF0YS5mcmFtZSh1c2VyX3Jvd19sZW5ndGhzX2xpc3QpKQp1c2VyX3Jvd19sZW5ndGhzX2RmIDwtIGRhdGEuZnJhbWUoY2JpbmQodXNlcl9yb3dfbGVuZ3Roc19kZiwgdW5pcXVlKGRhaV9kZiRVc2VyKSkpCgp1c2VyX3Jvd19sZW5ndGhzX2RmJFgxIDwtIGFzLm51bWVyaWModXNlcl9yb3dfbGVuZ3Roc19kZiRYMSkKCiMgVXNlcl9saXN0IDwtIHVzZXJfcm93X2xlbmd0aHNfZGZbdXNlcl9yb3dfbGVuZ3Roc19kZlsiWDEiXSA+IDMwLCAiWDIiXQojIFVzZXJfbGlzdCA8LSB1bmlxdWUoZGFpX2RmJFVzZXIpCiMgVXNlcl9saXN0IDwtIGMoJ01vdGkxNDgnLCAnTW90aTE0MycsICdNb3RpMTQwJywgJ01vdGkxNTYnLCAnTW90aTE1MScpClVzZXJfbGlzdCA8LSBjKAogICMgJ01vdGkxMTQnLAogJ01vdGkxNDcnLAogJ01vdGkxNDknLAogJ01vdGkxNjQnLAogJ01vdGkxMDYnLAogJ01vdGkxMjEnLAogJ01vdGkxMzcnLAogJ01vdGkxMzgnLAogJ01vdGkxNTAnLAogJ01vdGkxNTcnLAogJ01vdGkxNDgnLAogJ01vdGkxNDMnLAogJ01vdGkxNDAnLAogJ01vdGkxNTYnLAogJ01vdGkxNTEnKQoKZGZfbGlzdCA8LSBkZl9saXN0W25hbWVzKGRmX2xpc3QpICVpbiUgVXNlcl9saXN0XQojIGRmX2xpc3RfaW1wX3NjYWwgPC0gZGZfbGlzdF9pbXBfc2NhbFtuYW1lcyhkZl9saXN0X2ltcF9zY2FsKSAlaW4lIFVzZXJfbGlzdF0KYGBgCgojIyMgUHJlcGFyZSB0aGUgZGF0YSAoaW1wdXRlIGFuZCBtaW4gbWF4IHNjYWxlKSBhbmQgcGxvdCBhbiBleGFtcGxlIGZlYXR1cmUKCmBgYHtyfQpkZl9saXN0X2ltcCA8LSBsYXBwbHkoZGZfbGlzdCwgYXBwbHlfaW1wdXRhdGlvbiwgdmFycykKZGZfbGlzdF9pbXBfc2NhbCA8LSBsYXBwbHkoZGZfbGlzdF9pbXAsIGFwcGx5X3NjYWxpbmcsIHZhcnMpCmRmX2xpc3RfaW1wW2V4YW1wbGVfdXNlcl0KZGZfbGlzdF9pbXBfc2NhbFtleGFtcGxlX3VzZXJdCmBgYAoKIyMjIFJlbW92ZSB1c2VycyBmcm9tIHRoZSBpbXB1dGVkIGFuZCBzY2FsZWQgZGZzIGxpc3QgdGhhdCBoYWQgdG9vIG1hbnkgbWlzc2luZyB2YWx1ZXMKCmBgYHtyfQp1c2VyX2Ryb3BfbGlzdCA8LSBjKCkKZm9yIChVc2VyIGluIFVzZXJfbGlzdCkgewogIG1pc3NpbmdfYW1vdW50IDwtIHN1bShzYXBwbHkoZGZfbGlzdF9pbXBfc2NhbFtbYXMuY2hhcmFjdGVyKFVzZXIpXV0sIGZ1bmN0aW9uKHgpIHN1bShpcy5uYSh4KSkpKQogICMgcHJpbnQoVXNlcikKICAjIHByaW50KG1pc3NpbmdfYW1vdW50KQogIGlmIChtaXNzaW5nX2Ftb3VudCA+IDApIHsKICAgIHByaW50KFVzZXIpCiAgICBwcmludChtaXNzaW5nX2Ftb3VudCkKICAgIHVzZXJfZHJvcF9saXN0IDwtIGModXNlcl9kcm9wX2xpc3QsIGFzLmNoYXJhY3RlcihVc2VyKSkKICB9Cn0KCmRmX2xpc3RfaW1wX3NjYWwgPC0gZGZfbGlzdF9pbXBfc2NhbFshbmFtZXMoZGZfbGlzdF9pbXBfc2NhbCkgJWluJSB1c2VyX2Ryb3BfbGlzdF0KCmBgYAoKYGBge3IsIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHJlc3VsdHM9J2hpZGUnfQplbUxhZyA8LSAyCmVtRGltIDwtIDIKClJQX21lYXN1cmVzX2xpc3QgPC0gcXVpZXQobGFwcGx5KGRmX2xpc3RfaW1wX3NjYWwsIGFwcGx5X1JQX21lYXN1cmVzLCB2YXJzLCBlbUxhZywgZW1EaW0pKQoKYGBgCgpgYGB7cn0KIyBmb3IgKFVzZXIgaW4gdW5pcXVlKGRhaV9kZiRVc2VyKSkgewojICAgcHJpbnQoVXNlcikKIyAgIGFwcGx5X1JQX21lYXN1cmVzKGRmX2xpc3RfaW1wX3NjYWxbYXMuY2hhcmFjdGVyKFVzZXIpXSwgdmFycywgZW1MYWcsIGVtRGltKQojIH0KCmBgYAoKCiMjIyBJZGVudGlmeSB0aGUgZmVhdHVyZSB3aXRoIHRoZSBtb3N0IHZhcmlhYmxlIERldGVybWluaXNtICh2YXJpYW5jZSB3aXRoaW4gdXNlcnMpIGFuZCBhc3NpZ24gdGhpcyB0aGUgZmVhdHVyZSBvZiBpbnRlcmVzdCBmb3IgdGhlIHJlc3Qgb2YgdGhlIGFuYWx5c2lzLgoKYGBge3IsIGZpZy53aWR0aD0xNSwgZmlnLmhlaWdodD03fQphbGxfUlBfbWVhc3VyZXNfZGYgPC0gcmVzaGFwZTo6bWVyZ2VfYWxsKFJQX21lYXN1cmVzX2xpc3QpCgpycWFfZmVhdHVyZSA8LSAiREVUIiAjVFRfdmwKCmFsbF9SUF9tZWFzdXJlc19kZl9sb25nIDwtIG1lbHQoYWxsX1JQX21lYXN1cmVzX2RmWywgYygiZmVhdHVyZSIsIHJxYV9mZWF0dXJlKV0sIGlkLnZhcnMgPSAiZmVhdHVyZSIpCgpnIDwtIGdncGxvdChhbGxfUlBfbWVhc3VyZXNfZGZfbG9uZywgYWVzKHg9ZmVhdHVyZSwgeT12YWx1ZSkpICsKICAgIGdlb21fYm94cGxvdChvdXRsaWVyLmNvbG91cj0iI2U1ODAzOCIsIG91dGxpZXIuc2hhcGU9OCwKICAgICAgICAgICAgICAgIG91dGxpZXIuc2l6ZT00KSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCkpCnByaW50KGcpCgphZ2dfUlBfbWVhc3VyZXNfZGYgPC0gYWdncmVnYXRlKGFsbF9SUF9tZWFzdXJlc19kZlssIGMocnFhX2ZlYXR1cmUpXSwgbGlzdChhbGxfUlBfbWVhc3VyZXNfZGYkZmVhdHVyZSksIHZhciwgbmEucm09VFJVRSkKY29sbmFtZXMoYWdnX1JQX21lYXN1cmVzX2RmKSA8LSBjKCJmZWF0dXJlIiwgcnFhX2ZlYXR1cmUpCgpmZWF0dXJlX29mX2ludGVyZXN0IDwtIGFnZ19SUF9tZWFzdXJlc19kZlt3aGljaChhZ2dfUlBfbWVhc3VyZXNfZGZbcnFhX2ZlYXR1cmVdPT1tYXgoYWdnX1JQX21lYXN1cmVzX2RmW3JxYV9mZWF0dXJlXSkpLCAiZmVhdHVyZSJdWzFdCgpwcmludCgiTmV3IGZlYXR1cmUgb2YgaW50ZXJlc3Q6IikKZmVhdHVyZV9vZl9pbnRlcmVzdAoKYGBgCgojIyMgU3BpcmFsIGdyYXBocyBvZiB0aGUgZmVhdHVyZSBvZiBpbnRlcmVzdCBwZXIgdXNlciB3aXRoIGVtYmVkZGluZyBsYWcgYW5kIGVtYmVkZGluZyBkaW1lbnNpb24gdGhlIHNhbWUgYWNyb3NzIGFsbCB1c2VycwoKYGBge3IsIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHJlc3VsdHM9J2hpZGUnfQojIGxhcHBseShYPWRmX2xpc3RfaW1wX3NjYWwsIEZVTj1ucm93KQpmZWF0dXJlX29mX2ludGVyZXN0CiMgUk5zX2xpc3QgPC0gbGFwcGx5KGRmX2xpc3RfaW1wX3NjYWwsIGFwcGx5X1JOcywgZmVhdHVyZV9vZl9pbnRlcmVzdCwgZW1MYWcsIGVtRGltKQpSTl9wbG90c19saXN0IDwtIGxhcHBseShkZl9saXN0X2ltcF9zY2FsLCBhcHBseV9STl9wbG90cywgZmVhdHVyZV9vZl9pbnRlcmVzdCwgZW1MYWcsIGVtRGltKQpSTl9tZWFzdXJlc19saXN0IDwtIGxhcHBseShkZl9saXN0X2ltcF9zY2FsLCBhcHBseV9STl9tZWFzdXJlcywgZmVhdHVyZV9vZl9pbnRlcmVzdCwgZW1MYWcsIGVtRGltKQoKYGBgCmBgYHtyfQpwbG90LnRzKHg9ZGZfbGlzdF9pbXBfc2NhbFtbIk1vdGkxNTYiXV0kZW5qb3ltZW50KQpwbG90LnRzKHg9ZGZfbGlzdFtbIk1vdGkxNTYiXV0kZW5qb3ltZW50KQpgYGAKCgpgYGB7cn0KZmVhdHVyZV9vZl9pbnRlcmVzdF9STl9tZWFzdXJlc19kZiA8LSByZXNoYXBlOjptZXJnZV9hbGwoUk5fbWVhc3VyZXNfbGlzdCkKYGBgCgpgYGB7cn0KIyB3cml0ZS5jc3YoZmVhdHVyZV9vZl9pbnRlcmVzdF9STl9tZWFzdXJlc19kZiwgCiMgICAgICAgICAgIGZpbGU9cGFzdGUoImRhdGEvIiwgZmVhdHVyZV9vZl9pbnRlcmVzdCwgIl9STl9tZWFzdXJlcy5jc3YiLCBzZXAgPSAiIikpCmBgYAo=