Go back to main

library(pander)
library(ez)
library(ARTool)
library(MASS) # for boxplot
library(emmeans)
library(scales) # for percent scale
library(patchwork)
source("./keytime-setup.R")

H_GRAPH_MARGIN = 10
PANEL_MARGIN = unit(4, "mm")

normalCheck <- function(model) {
  res = residuals(model)
  qqnorm((res - mean(res)) / sd(res))
  abline(0, 1)
  print (shapiro.test(res))
}

all_trials <- read_keytime_trials(measured_only = FALSE)
measured_test_trials <- read_keytime_trials(measured_only = TRUE) |>
  mutate(
  suggestions_type = suggestions_type |> fct_relevel(BAR_SUGGESTION_TYPE, INLINE_SUGGESTION_TYPE),
  suggestions_label = fct_recode(
    suggestions_type,
    `Suggestion Bar (Exp. 2)` = BAR_SUGGESTION_TYPE,
    `Inline Suggestions (Exp. 3)` = INLINE_SUGGESTION_TYPE
  )
)
measured_runs <- read_keytime_runs(measured_only = TRUE)

1 Trials

all_trials |>
  filter(!is_practice & is_run_measured) |>
  count(suggestions_type, is_trial_measured, was_trial_blurred)

2 Suggestions Reliance

p_data_usage <- measured_test_trials |>
  group_by(
    participant,
    accuracy,
    keytime,
    accuracy_numeric,
    keytime_numeric,
    suggestions_type
  ) |>
  summarize(mean_suggestion_use = mean(total_suggestion_used),
            .groups = "drop")

plot_reliance <- function(filtered_p_data_usage) {
  summary_usage <- filtered_p_data_usage |>
    group_by(accuracy_numeric, keytime_numeric) |>
    summarize(
      err_mean_tibble(mean_suggestion_use, min_min = 0),
      .groups = "drop"
    )
  
  pd <- position_dodge(0.025)
  ggplot(
    data = summary_usage,
    aes(
      x = accuracy_numeric,
      y = data_mean,
      ymin = data_min,
      ymax = data_max,
      color = keytime_numeric,
      group = keytime_numeric
    )
  ) +
    SCALE_COLOR_KEY_STROKE +
    SCALE_X_ACCURACY +
    scale_y_continuous("Suggestions Use per Trials", breaks = seq(0, 6, 1)) +
    expand_limits(y = c(0)) +
    custom_line(position = pd) +
    custom_pointrange(position = pd) +
    theme(legend.position = "none",
          panel.spacing = PANEL_MARGIN)
}

2.1 Summaries

2.1.1 Global

p_data_usage |>
  group_by(suggestions_type) |>
  summarize(
    sd_suggestion_use = sd(mean_suggestion_use),
    mean_suggestion_use = mean(mean_suggestion_use),
    .groups = "drop"
  )

2.1.2 Per conditions

p_data_usage |>
  group_by(suggestions_type, accuracy, keytime) |>
  summarize(
    sd_suggestion_use = sd(mean_suggestion_use),
    mean_suggestion_use = mean(mean_suggestion_use),
    .groups = "drop"
  )

2.1.3 Per keytime

p_data_usage |>
  group_by(suggestions_type, keytime) |>
  summarize(
    sd_suggestion_use = sd(mean_suggestion_use),
    mean_suggestion_use = mean(mean_suggestion_use),
    .groups = "drop"
  )

2.1.4 Per accuray

p_data_usage |>
  group_by(suggestions_type, accuracy) |>
  summarize(
    sd_suggestion_use = sd(mean_suggestion_use),
    mean_suggestion_use = mean(mean_suggestion_use),
    .groups = "drop"
  )

2.2 Inline suggestions

p_data_usage_inline <-
  p_data_usage |> filter(suggestions_type == INLINE_SUGGESTION_TYPE)

inline_reliance_plot <- plot_reliance(p_data_usage_inline)

ggsave(
  graph_path("suggestions-usage-inline.pdf"),
  plot = inline_reliance_plot,
  units = "mm",
  width = (FULL_WIDTH - H_GRAPH_MARGIN) / 4 - 2,
  height = (FULL_WIDTH - H_GRAPH_MARGIN) / 4,
  device = cairo_pdf
)

inline_reliance_plot

2.2.1 Histograms

ggplot(p_data_usage_inline, aes(x = mean_suggestion_use)) +
  geom_histogram(binwidth = .5) +
  facet_grid(rows=vars(accuracy), cols = vars(keytime))

2.2.2 ANOVA assumptions

model_usage <- ezANOVA(
  data = measured_test_trials |> filter(suggestions_type == INLINE_SUGGESTION_TYPE),
  wid = c("participant"),
  dv = total_suggestion_used,
  between = c("keytime", "accuracy"),
  return_aov = TRUE
)
Warning: You have removed one or more Ss from the analysis. Refactoring "participant" for ANOVA.
Warning: Data is unbalanced (unequal N per group). Make sure you specified a well-considered value for the type argument to ezANOVA().
Warning: Collapsing data to cell means. *IF* the requested effects are a subset of the full design, you must use the "within_full"
argument, else results may be inaccurate.
Coefficient covariances computed by hccm()
qqnorm(model_usage$aov$residuals);qqline(model_usage$aov$residuals)

model_usage
$ANOVA
            Effect DFn DFd         F             p p<.05       ges
1          keytime   3 587 109.90919  1.753218e-56     * 0.3596789
2         accuracy   4 587 327.74936 5.303566e-148     * 0.6907267
3 keytime:accuracy  12 587  11.29028  1.614947e-20     * 0.1875246

$`Levene's Test for Homogeneity of Variance`
  DFn DFd      SSn      SSd        F            p p<.05
1  19 587 118.6575 274.5834 13.35074 6.059843e-35     *

$aov
Call:
   aov(formula = formula(aov_formula), data = data)

Terms:
                  keytime  accuracy keytime:accuracy Residuals
Sum of Squares   374.7243 1438.9419         148.7057  644.2872
Deg. of Freedom         3         4               12       587

Residual standard error: 1.047661
Estimated effects may be unbalanced

2.2.3 ART

art_m_usage_inline = art(mean_suggestion_use ~ keytime * accuracy,
                  data=p_data_usage_inline)
anova(art_m_usage_inline, type = 2)
emmeans(artlm(art_m_usage_inline, "keytime"), pairwise ~ keytime)
NOTE: Results may be misleading due to involvement in interactions
$emmeans
 keytime emmean   SE  df lower.CL upper.CL
 0          171 11.2 587      149      193
 50         230 11.0 587      208      251
 100        358 11.2 587      336      380
 200        455 11.0 587      433      477

Results are averaged over the levels of: accuracy 
Confidence level used: 0.95 

$contrasts
 contrast                estimate   SE  df t.ratio p.value
 keytime0 - keytime50       -59.0 15.7 587  -3.759  0.0011
 keytime0 - keytime100     -187.3 15.8 587 -11.875  <.0001
 keytime0 - keytime200     -284.4 15.7 587 -18.141  <.0001
 keytime50 - keytime100    -128.3 15.7 587  -8.174  <.0001
 keytime50 - keytime200    -225.4 15.6 587 -14.449  <.0001
 keytime100 - keytime200    -97.1 15.7 587  -6.196  <.0001

Results are averaged over the levels of: accuracy 
P value adjustment: tukey method for comparing a family of 4 estimates 
emmeans(artlm(art_m_usage_inline, "accuracy"), pairwise ~ accuracy)
NOTE: Results may be misleading due to involvement in interactions
$emmeans
 accuracy emmean   SE  df lower.CL upper.CL
 0.1        89.6 8.59 587     72.7      106
 0.3       201.2 8.59 587    184.3      218
 0.5       298.5 8.63 587    281.6      315
 0.7       429.2 8.46 587    412.6      446
 0.9       498.8 8.63 587    481.9      516

Results are averaged over the levels of: keytime 
Confidence level used: 0.95 

$contrasts
 contrast                  estimate   SE  df t.ratio p.value
 accuracy0.1 - accuracy0.3   -111.6 12.2 587  -9.183  <.0001
 accuracy0.1 - accuracy0.5   -208.9 12.2 587 -17.161  <.0001
 accuracy0.1 - accuracy0.7   -339.6 12.1 587 -28.159  <.0001
 accuracy0.1 - accuracy0.9   -409.2 12.2 587 -33.612  <.0001
 accuracy0.3 - accuracy0.5    -97.4 12.2 587  -7.997  <.0001
 accuracy0.3 - accuracy0.7   -228.0 12.1 587 -18.907  <.0001
 accuracy0.3 - accuracy0.9   -297.6 12.2 587 -24.448  <.0001
 accuracy0.5 - accuracy0.7   -130.7 12.1 587 -10.812  <.0001
 accuracy0.5 - accuracy0.9   -200.3 12.2 587 -16.417  <.0001
 accuracy0.7 - accuracy0.9    -69.6 12.1 587  -5.762  <.0001

Results are averaged over the levels of: keytime 
P value adjustment: tukey method for comparing a family of 5 estimates 

2.3 Bar suggestions

p_data_usage_bar <- p_data_usage |>
  filter(suggestions_type == BAR_SUGGESTION_TYPE)
p_data_usage_bar_common_factors <- p_data_usage_bar

bar_reliance_plot <- plot_reliance(p_data_usage_bar)

ggsave(
  graph_path("suggestions-usage-bar.pdf"),
  plot = bar_reliance_plot,
  units = "mm",
  width = (FULL_WIDTH - H_GRAPH_MARGIN) / 4 - 2,
  height = (FULL_WIDTH - H_GRAPH_MARGIN) / 4,
  device = cairo_pdf
)

bar_reliance_plot

2.3.1 Histograms

ggplot(p_data_usage_bar, aes(x = mean_suggestion_use)) +
  geom_histogram(binwidth = .5) +
  facet_grid(rows=vars(accuracy), cols = vars(keytime))

2.3.2 ANOVA assumptions

model_usage <- ezANOVA(
  data = measured_test_trials |>
    filter(suggestions_type == BAR_SUGGESTION_TYPE & accuracy %in% c(0.1, 0.5, 0.9)),
  wid = c("participant"),
  dv = total_suggestion_used,
  between = c("keytime", "accuracy"),
  return_aov = TRUE
)
Warning: You have removed one or more Ss from the analysis. Refactoring "participant" for ANOVA.
Warning: You have removed one or more levels from variable "accuracy". Refactoring for ANOVA.
Warning: Collapsing data to cell means. *IF* the requested effects are a subset of the full design, you must use the "within_full"
argument, else results may be inaccurate.
Coefficient covariances computed by hccm()
qqnorm(model_usage$aov$residuals);qqline(model_usage$aov$residuals)

model_usage
$ANOVA
            Effect DFn DFd         F            p p<.05       ges
1          keytime   3 348  60.81269 1.237671e-31     * 0.3439385
2         accuracy   2 348 297.02066 5.579782e-76     * 0.6305894
3 keytime:accuracy   6 348  14.22432 1.667218e-14     * 0.1969464

$`Levene's Test for Homogeneity of Variance`
  DFn DFd      SSn      SSd       F            p p<.05
1  11 348 124.8144 250.0284 15.7929 4.657556e-25     *

$aov
Call:
   aov(formula = formula(aov_formula), data = data)

Terms:
                 keytime accuracy keytime:accuracy Residuals
Sum of Squares  262.8508 855.8752         122.9636  501.3870
Deg. of Freedom        3        2                6       348

Residual standard error: 1.20032
Estimated effects are balanced

2.3.3 ART

art_m_usage_bar = art(mean_suggestion_use ~ keytime * accuracy,
                      data = p_data_usage_bar_common_factors)
anova(art_m_usage_bar, type = 2)
emmeans(artlm(art_m_usage_bar, "keytime"), pairwise ~ keytime)
NOTE: Results may be misleading due to involvement in interactions
$emmeans
 keytime emmean   SE  df lower.CL upper.CL
 0          164 11.2 580      142      186
 50         232 11.2 580      210      254
 100        372 11.2 580      350      394
 200        434 11.2 580      412      456

Results are averaged over the levels of: accuracy 
Confidence level used: 0.95 

$contrasts
 contrast                estimate   SE  df t.ratio p.value
 keytime0 - keytime50       -68.6 15.8 580  -4.332  0.0001
 keytime0 - keytime100     -207.8 15.8 580 -13.118  <.0001
 keytime0 - keytime200     -270.3 15.8 580 -17.059  <.0001
 keytime50 - keytime100    -139.2 15.8 580  -8.786  <.0001
 keytime50 - keytime200    -201.6 15.8 580 -12.727  <.0001
 keytime100 - keytime200    -62.4 15.8 580  -3.941  0.0005

Results are averaged over the levels of: accuracy 
P value adjustment: tukey method for comparing a family of 4 estimates 
emmeans(artlm(art_m_usage_bar, "accuracy"), pairwise ~ accuracy)
NOTE: Results may be misleading due to involvement in interactions
$emmeans
 accuracy emmean   SE  df lower.CL upper.CL
 0.1        94.2 9.95 580     74.6      114
 0.3       215.8 9.95 580    196.2      235
 0.5       312.5 9.95 580    293.0      332
 0.7       398.7 9.95 580    379.1      418
 0.9       481.4 9.95 580    461.8      501

Results are averaged over the levels of: keytime 
Confidence level used: 0.95 

$contrasts
 contrast                  estimate   SE  df t.ratio p.value
 accuracy0.1 - accuracy0.3   -121.6 14.1 580  -8.646  <.0001
 accuracy0.1 - accuracy0.5   -218.4 14.1 580 -15.525  <.0001
 accuracy0.1 - accuracy0.7   -304.5 14.1 580 -21.647  <.0001
 accuracy0.1 - accuracy0.9   -387.2 14.1 580 -27.526  <.0001
 accuracy0.3 - accuracy0.5    -96.8 14.1 580  -6.879  <.0001
 accuracy0.3 - accuracy0.7   -182.9 14.1 580 -13.002  <.0001
 accuracy0.3 - accuracy0.9   -265.6 14.1 580 -18.880  <.0001
 accuracy0.5 - accuracy0.7    -86.1 14.1 580  -6.123  <.0001
 accuracy0.5 - accuracy0.9   -168.8 14.1 580 -12.001  <.0001
 accuracy0.7 - accuracy0.9    -82.7 14.1 580  -5.879  <.0001

Results are averaged over the levels of: keytime 
P value adjustment: tukey method for comparing a family of 5 estimates 

3 Saved Key Strokes

p_data_sks <- measured_test_trials |>
  group_by(participant, accuracy, keytime, accuracy_numeric, keytime_numeric, suggestions_type) |>
  summarize(
    p_mean_sks = mean(actual_sks),
    .groups = "drop"
  ) 

summary_sks <- p_data_sks |>
  group_by(accuracy_numeric, keytime_numeric, suggestions_type) |>
  summarize(
    error_sks = t_error(p_mean_sks),
    mean_sks = mean(p_mean_sks),
    min_sks = mean_sks - error_sks,
    max_sks = mean_sks + error_sks,
    .groups = "drop"
  )

theoretical_sks <- measured_test_trials |>
  group_by(participant, accuracy_numeric, suggestions_type) |>
  summarize(p_mean_sks = mean(theoretical_sks), .groups = "drop") |>
  group_by(accuracy_numeric) |>
  summarize(
    error_sks = t_error(p_mean_sks),
    mean_sks = mean(p_mean_sks),
    min_sks = mean_sks - error_sks,
    max_sks = mean_sks + error_sks,
    .groups = "drop"
  )
pd <- position_dodge(0.025)
plot_sks <- ggplot(summary_sks, aes(
    x = accuracy_numeric,
    y = mean_sks,
    ymin = min_sks,
    ymax = max_sks,
    color = keytime_numeric,
    group = keytime_numeric
  )) +
  geom_line(data=theoretical_sks, color="red", group="red") +
  geom_pointrange(data=theoretical_sks, color="red", group="red") +
  scale_color_continuous(breaks=c(0, 50, 100, 200)) +
  scale_x_continuous(breaks=c(0, 0.1, 0.3, 0.5, 0.7, 0.9, 1)) +
  geom_line(position=pd) +
  geom_pointrange(position=pd) +
  facet_grid(rows=vars(suggestions_type)) +
  theme(
    legend.position = "none",
    panel.spacing = PANEL_MARGIN,
  ) +
  labs(x="Accuracy", y="Saved Keystrokes", color="Key Stroke Delay")

plot_sks

4 Keystroke Saving

p_data_ks <- measured_test_trials |>
  group_by(
    participant,
    accuracy,
    keytime,
    accuracy_numeric,
    keytime_numeric,
    suggestions_type
  ) |>
  summarize(
    p_mean_actual_ks = mean(actual_key_saving_no_editing),
    p_mean_theoretical_ks = mean(theoretical_key_saving),
    .groups = "drop"
  ) |>
  group_by(accuracy, keytime) |>
  mutate(is_outlier = is_outlier(p_mean_actual_ks)) |>
  ungroup()

plot_keystroke_saving <- function(filtered_p_data_ks) {
  actual_ks_summary <- filtered_p_data_ks |>
    group_by(accuracy_numeric,
             keytime_numeric) |>
    summarize(
      error_ks = t_error(p_mean_actual_ks),
      mean_ks = mean(p_mean_actual_ks),
      min_ks = max(0, mean_ks - error_ks),
      max_ks = min(1, mean_ks + error_ks),
      ks_type = "actual",
      .groups = "drop"
    )
  
  theoretical_ks_summary <- filtered_p_data_ks |>
    group_by(accuracy_numeric) |>
    summarize(
      error_ks = t_error(p_mean_theoretical_ks),
      mean_ks = mean(p_mean_theoretical_ks),
      min_ks = max(0, mean_ks - error_ks),
      max_ks = min(1, mean_ks + error_ks),
      ks_type = "theoretical",
      keytime_numeric = NA,
      .groups = "drop"
    )
  
  ks_summary <- union_all(theoretical_ks_summary, actual_ks_summary)
  
  pd <- position_dodge(0.025)
  plot_keystroke_saving <- ggplot(
    ks_summary,
    aes(
      x = accuracy_numeric,
      y = mean_ks,
      ymin = min_ks,
      ymax = max_ks,
      color = keytime_numeric,
      group = keytime_numeric
    )
  ) +
    custom_line(data = theoretical_ks_summary,
                color = THEORETICAL_COLOR,
                group = "theoretical") +
    custom_pointrange(
      data = theoretical_ks_summary,
      color = THEORETICAL_COLOR,
      group = "theoretical",
      shape = 17
    ) +
    custom_line(data = actual_ks_summary, position = pd) +
    custom_pointrange(data = actual_ks_summary, position = pd) +
    SCALE_COLOR_KEY_STROKE +
    SCALE_X_ACCURACY +
    scale_y_continuous("Keystroke Saving",
                       limits = c(0, 1),
                       labels = percent) +
    theme(legend.position = "none",
          panel.spacing = PANEL_MARGIN)
}

4.1 Summaries

4.1.1 Global

p_data_ks |>
  group_by(suggestions_type) |>
  summarize(
    sd_ks = sd(p_mean_actual_ks),
    mean_ks = mean(p_mean_actual_ks),
    .groups = "drop"
  )

4.1.2 Per conditions

p_data_ks |>
  group_by(suggestions_type, accuracy, keytime) |>
  summarize(
    sd_ks = sd(p_mean_actual_ks),
    mean_ks = mean(p_mean_actual_ks),
    .groups = "drop"
  )

4.1.3 Per keytime

p_data_ks |>
  group_by(suggestions_type, keytime) |>
  summarize(
    sd_ks = sd(p_mean_actual_ks),
    mean_ks = mean(p_mean_actual_ks),
    .groups = "drop"
  )

4.1.4 Per accuray

p_data_ks |>
  group_by(suggestions_type, accuracy) |>
  summarize(
    sd_ks = sd(p_mean_actual_ks),
    mean_ks = mean(p_mean_actual_ks),
    .groups = "drop"
  )

4.2 Inline suggestions

p_data_ks_inline <- p_data_ks |> filter(suggestions_type == INLINE_SUGGESTION_TYPE)

inline_ks_plot <- plot_keystroke_saving(p_data_ks_inline)

ggsave(
  graph_path("keystroke-saving-inline.pdf"),
  plot=inline_ks_plot,
  units="mm",
  width=(FULL_WIDTH - H_GRAPH_MARGIN) / 4,
  height=(FULL_WIDTH - H_GRAPH_MARGIN) / 4,
  device=cairo_pdf
)

inline_ks_plot

4.2.1 Normality and Homogeneity

ggplot(p_data_ks_inline, aes(x = p_mean_actual_ks)) +
  geom_histogram(binwidth = .05) +
  facet_grid(rows=vars(accuracy), cols = vars(keytime))

m <- aov(p_mean_actual_ks ~ keytime*accuracy, data=p_data_ks_inline)
pander(normalCheck(m))

Shapiro-Wilk normality test

data: res W = 0.90538, p-value < 2.2e-16

Shapiro-Wilk normality test: res
Test statistic P value
0.9054 6.001e-19 * * *
remove(m)

Not normal.

4.2.2 Determine boxcox transform lambda

boxcox((p_mean_actual_ks + 0.5)~keytime*accuracy, data=p_data_ks_inline)

lambda <- 0.5
m <- aov((p_mean_actual_ks + 0.5) ^ -0.3 ~ keytime*accuracy, data=p_data_ks_inline)
pander(normalCheck(m))

Shapiro-Wilk normality test

data: res W = 0.92199, p-value < 2.2e-16

Shapiro-Wilk normality test: res
Test statistic P value
0.922 3.512e-17 * * *
remove(m)
ezANOVA(
  p_data_ks_inline |> mutate(final_ks = (p_mean_actual_ks + 0.5) ^ -0.3),
  dv=final_ks, wid=c(participant),
  between=c(keytime, accuracy),
  detailed=TRUE
)
Warning: You have removed one or more Ss from the analysis. Refactoring "participant" for ANOVA.
Warning: Data is unbalanced (unequal N per group). Make sure you specified a well-considered value for the type argument to ezANOVA().
Coefficient covariances computed by hccm()
$ANOVA
            Effect DFn DFd       SSn      SSd          F             p p<.05       ges
1          keytime   3 587 0.7855189 1.395994 110.100646  1.459609e-56     * 0.3600798
2         accuracy   4 587 6.0451693 1.395994 635.481539 1.191109e-211     * 0.8123957
3 keytime:accuracy  12 587 0.2848055 1.395994   9.979795  6.273666e-18     * 0.1694464

$`Levene's Test for Homogeneity of Variance`
  DFn DFd       SSn       SSd        F           p p<.05
1  19 587 0.2777115 0.6856414 12.51357 1.12417e-32     *

Still not normal, and also not homogenic, switching to art

4.2.3 ART

m_ks_inline = art(p_mean_actual_ks ~ keytime * accuracy, data=p_data_ks_inline)
anova(m_ks_inline, type = 2)
emmeans(artlm(m_ks_inline, "keytime"), pairwise ~ keytime)
NOTE: Results may be misleading due to involvement in interactions
$emmeans
 keytime emmean   SE  df lower.CL upper.CL
 0          170 10.8 587      149      191
 50         225 10.7 587      204      246
 100        357 10.8 587      335      378
 200        461 10.7 587      440      482

Results are averaged over the levels of: accuracy 
Confidence level used: 0.95 

$contrasts
 contrast                estimate   SE  df t.ratio p.value
 keytime0 - keytime50       -55.2 15.2 587  -3.632  0.0017
 keytime0 - keytime100     -186.4 15.3 587 -12.217  <.0001
 keytime0 - keytime200     -291.2 15.2 587 -19.197  <.0001
 keytime50 - keytime100    -131.3 15.2 587  -8.644  <.0001
 keytime50 - keytime200    -236.0 15.1 587 -15.637  <.0001
 keytime100 - keytime200   -104.8 15.2 587  -6.907  <.0001

Results are averaged over the levels of: accuracy 
P value adjustment: tukey method for comparing a family of 4 estimates 
emmeans(artlm(m_ks_inline, "accuracy"), pairwise ~ accuracy)
NOTE: Results may be misleading due to involvement in interactions
$emmeans
 accuracy emmean   SE  df lower.CL upper.CL
 0.1        83.7 6.74 587     70.4     96.9
 0.3       191.4 6.74 587    178.2    204.7
 0.5       288.4 6.77 587    275.1    301.7
 0.7       424.0 6.64 587    411.0    437.1
 0.9       530.2 6.77 587    516.9    543.5

Results are averaged over the levels of: keytime 
Confidence level used: 0.95 

$contrasts
 contrast                  estimate   SE  df t.ratio p.value
 accuracy0.1 - accuracy0.3   -107.8 9.54 587 -11.300  <.0001
 accuracy0.1 - accuracy0.5   -204.7 9.55 587 -21.424  <.0001
 accuracy0.1 - accuracy0.7   -340.4 9.46 587 -35.962  <.0001
 accuracy0.1 - accuracy0.9   -446.5 9.55 587 -46.729  <.0001
 accuracy0.3 - accuracy0.5    -96.9 9.55 587 -10.146  <.0001
 accuracy0.3 - accuracy0.7   -232.6 9.46 587 -24.577  <.0001
 accuracy0.3 - accuracy0.9   -338.7 9.55 587 -35.452  <.0001
 accuracy0.5 - accuracy0.7   -135.7 9.48 587 -14.304  <.0001
 accuracy0.5 - accuracy0.9   -241.8 9.57 587 -25.255  <.0001
 accuracy0.7 - accuracy0.9   -106.1 9.48 587 -11.190  <.0001

Results are averaged over the levels of: keytime 
P value adjustment: tukey method for comparing a family of 5 estimates 

4.3 Bar suggestions

p_data_ks_bar <- p_data_ks |> filter(suggestions_type == BAR_SUGGESTION_TYPE)
p_data_ks_bar_common_factors <- p_data_ks_bar

bar_ks_plot <- plot_keystroke_saving(p_data_ks_bar)

ggsave(
  graph_path("keystroke-saving-bar.pdf"),
  plot=bar_ks_plot,
  units="mm",
  width=(FULL_WIDTH - H_GRAPH_MARGIN) / 4,
  height=(FULL_WIDTH - H_GRAPH_MARGIN) / 4,
  device=cairo_pdf
)

bar_ks_plot

4.4 Inline vs bar

p_data_ks |>
  group_by(suggestions_type) |>
  summarize(
    error = t_error(p_mean_actual_ks),
    mean = mean(p_mean_actual_ks))
m_ks_both = art(p_mean_actual_ks ~ keytime * accuracy * suggestions_type, data=p_data_ks)
anova(m_ks_both, type = 2)
emmeans(artlm(m_ks_both, "suggestions_type"), pairwise ~ suggestions_type)
NOTE: Results may be misleading due to involvement in interactions
$emmeans
 suggestions_type emmean   SE   df lower.CL upper.CL
 BAR                 525 13.7 1167      499      552
 INLINE              681 13.6 1167      655      708

Results are averaged over the levels of: keytime, accuracy 
Confidence level used: 0.95 

$contrasts
 contrast     estimate   SE   df t.ratio p.value
 BAR - INLINE     -156 19.3 1167  -8.066  <.0001

Results are averaged over the levels of: keytime, accuracy 

4.4.1 Normality and Homogeneity

ggplot(p_data_ks_bar, aes(x = p_mean_actual_ks)) +
  geom_histogram(binwidth = .05) +
  facet_grid(rows=vars(accuracy), cols = vars(keytime))

m <- aov(p_mean_actual_ks ~ keytime*accuracy, data=p_data_ks_bar_common_factors)
pander(normalCheck(m))

Shapiro-Wilk normality test

data: res W = 0.89279, p-value < 2.2e-16

Shapiro-Wilk normality test: res
Test statistic P value
0.8928 5.069e-20 * * *
remove(m)

Not normal.

4.4.2 ART

C.f. http://faculty.washington.edu/wobbrock/pubs/chi-11.06.pdf

m_ks_bar = art(p_mean_actual_ks ~ keytime * accuracy, data=p_data_ks_bar_common_factors)
anova(m_ks_bar, type = 2)
emmeans(artlm(m_ks_bar, "keytime"), pairwise ~ keytime)
NOTE: Results may be misleading due to involvement in interactions
$emmeans
 keytime emmean   SE  df lower.CL upper.CL
 0          160 11.1 580      138      182
 50         242 11.1 580      220      264
 100        369 11.1 580      348      391
 200        431 11.1 580      409      452

Results are averaged over the levels of: accuracy 
Confidence level used: 0.95 

$contrasts
 contrast                estimate   SE  df t.ratio p.value
 keytime0 - keytime50       -82.3 15.8 580  -5.220  <.0001
 keytime0 - keytime100     -209.7 15.8 580 -13.306  <.0001
 keytime0 - keytime200     -270.8 15.8 580 -17.185  <.0001
 keytime50 - keytime100    -127.4 15.8 580  -8.086  <.0001
 keytime50 - keytime200    -188.5 15.8 580 -11.965  <.0001
 keytime100 - keytime200    -61.1 15.8 580  -3.879  0.0007

Results are averaged over the levels of: accuracy 
P value adjustment: tukey method for comparing a family of 4 estimates 
emmeans(artlm(m_ks_bar, "accuracy"), pairwise ~ accuracy)
NOTE: Results may be misleading due to involvement in interactions
$emmeans
 accuracy emmean   SE  df lower.CL upper.CL
 0.1        91.1 8.54 580     74.4      108
 0.3       205.2 8.54 580    188.5      222
 0.5       293.1 8.54 580    276.3      310
 0.7       403.0 8.54 580    386.3      420
 0.9       510.1 8.54 580    493.3      527

Results are averaged over the levels of: keytime 
Confidence level used: 0.95 

$contrasts
 contrast                  estimate   SE  df t.ratio p.value
 accuracy0.1 - accuracy0.3   -114.1 12.1 580  -9.451  <.0001
 accuracy0.1 - accuracy0.5   -201.9 12.1 580 -16.729  <.0001
 accuracy0.1 - accuracy0.7   -311.9 12.1 580 -25.838  <.0001
 accuracy0.1 - accuracy0.9   -418.9 12.1 580 -34.704  <.0001
 accuracy0.3 - accuracy0.5    -87.9 12.1 580  -7.278  <.0001
 accuracy0.3 - accuracy0.7   -197.8 12.1 580 -16.387  <.0001
 accuracy0.3 - accuracy0.9   -304.8 12.1 580 -25.253  <.0001
 accuracy0.5 - accuracy0.7   -110.0 12.1 580  -9.108  <.0001
 accuracy0.5 - accuracy0.9   -217.0 12.1 580 -17.975  <.0001
 accuracy0.7 - accuracy0.9   -107.0 12.1 580  -8.866  <.0001

Results are averaged over the levels of: keytime 
P value adjustment: tukey method for comparing a family of 5 estimates 

5 Keystroke Saving Ratio

p_data_tsku <- measured_test_trials |>
  group_by(participant,
           accuracy_numeric,
           keytime_numeric,
           suggestions_type) |>
  summarize(
    p_mean_ks = mean((total_final_suggestion_chars / total_chars) / theoretical_key_saving
  ),
  .groups = "drop")


plot_keystroke_saving_ratio <- function(filtered_p_data_tsku) {
  actual_tsku_data <- filtered_p_data_tsku |>
    group_by(accuracy_numeric,
             keytime_numeric) |>
    summarize(
      error_ks = t_error(p_mean_ks),
      mean_ks = mean(p_mean_ks),
      min_ks = max(0, mean_ks - error_ks),
      max_ks = min(1, mean_ks + error_ks),
      .groups = "drop"
    )
  theoretical_tsku_data <- tibble(
    accuracy_numeric = ACCURACY_LEVELS_NUM,
    keytime_numeric = NA,
    mean_ks = 1.0,
    min_ks = 1.0,
    max_ks = 1.0
  )
  pd <- position_dodge(0.025)
  plot_keystroke_saving_ratio <- ggplot(
    actual_tsku_data,
    aes(
      x = accuracy_numeric,
      y = mean_ks,
      ymin = min_ks,
      ymax = max_ks,
      color = keytime_numeric,
      group = keytime_numeric
    )
  ) +
    custom_line(data = theoretical_tsku_data,
                color = THEORETICAL_COLOR,
                group = "theoretical") +
    custom_pointrange(
      data = theoretical_tsku_data,
      color = THEORETICAL_COLOR,
      group = "theoretical",
      shape = 17
    ) +
    custom_line(position = pd) +
    custom_pointrange(position = pd) +
    SCALE_COLOR_KEY_STROKE +
    SCALE_X_ACCURACY +
    scale_y_continuous("Keystroke Saving Ratio",
                       limits = c(0, 1),
                       labels = percent) +
    theme(legend.position = "none",
          panel.spacing = PANEL_MARGIN, )
}

5.1 Inline suggestions

inline_ks_ratio_plot <-
  plot_keystroke_saving_ratio(p_data_tsku |> filter(suggestions_type == INLINE_SUGGESTION_TYPE))

ggsave(
  graph_path("keystroke-saving-ratio-inline.pdf"),
  plot = inline_ks_ratio_plot,
  units = "mm",
  width = (FULL_WIDTH - H_GRAPH_MARGIN) / 4,
  height = (FULL_WIDTH - H_GRAPH_MARGIN) / 4,
  device = cairo_pdf
)

inline_ks_ratio_plot

5.2 Bar suggestions

bar_ks_ratio_plot <-
  plot_keystroke_saving_ratio(p_data_tsku |> filter(suggestions_type == BAR_SUGGESTION_TYPE))

ggsave(
  graph_path("keystroke-saving-ratio-bar.pdf"),
  plot = bar_ks_ratio_plot,
  units = "mm",
  width = (FULL_WIDTH - H_GRAPH_MARGIN) / 4,
  height = (FULL_WIDTH - H_GRAPH_MARGIN) / 4,
  device = cairo_pdf
)

bar_ks_ratio_plot

6 Trial Duration

actual_graph_data <- measured_test_trials |>
  group_by(participant, accuracy_numeric, keytime_numeric, suggestions_type) |>
  summarize(
    value = mean(duration),
    .groups = "drop"
  ) |>
  group_by(accuracy_numeric, keytime_numeric, suggestions_type) |>
  summarize(
    error_value = t_error(value),
    mean_value = mean(value),
    min_value = max(0, mean_value - error_value),
    max_value = mean_value + error_value,
    .groups = "drop"
  )
pd <- position_dodge(0.025)
ggplot(actual_graph_data, aes(
    x = accuracy_numeric,
    y = mean_value,
    ymin = min_value,
    ymax = max_value,
    color = keytime_numeric,
    group = keytime_numeric
  )) +
  scale_x_continuous(breaks=c(0, 0.1, 0.3, 0.5, 0.7, 0.9, 1)) +
  scale_color_continuous(breaks=c(0, 50, 100, 200)) +
  expand_limits(y = c(0)) +
  geom_line(position=pd) +
  geom_pointrange(position=pd) +
  facet_wrap(vars(suggestions_type)) +
  labs(x="Suggestions Accuracy", y="Trial Duration (seconds)", color="Key Stroke Delay")

7 Entry Speed

p_data_ts <- measured_test_trials |>
  group_by(
    participant,
    accuracy,
    keytime,
    accuracy_numeric,
    keytime_numeric,
    suggestions_label,
    suggestions_type
  ) |>
  summarize(speed = mean(cps * 60 / 5), .groups = "drop") |>
  group_by(accuracy, keytime)

plot_entry_speed <- function(filtered_p_data_ts) {
  summary_ts <- filtered_p_data_ts |>
    group_by(accuracy_numeric,
             keytime_numeric,
             suggestions_label) |>
    summarize(
      error_value = t_error(speed),
      mean_value = mean(speed),
      min_value = max(0, mean_value - error_value),
      max_value = mean_value + error_value,
      .groups = "drop"
    )
  
  pd <- position_dodge(0.025)
  plot_entry_speed <- ggplot(
    summary_ts,
    aes(
      x = accuracy_numeric,
      y = mean_value,
      ymin = min_value,
      ymax = max_value,
      color = keytime_numeric,
      group = keytime_numeric
    )
  ) +
    SCALE_X_ACCURACY +
    SCALE_COLOR_KEY_STROKE +
    expand_limits(y = c(0)) +
    scale_y_continuous(breaks = seq(0, 80, 10), labels = paste(seq(0, 80, 10), "wpm")) +
    custom_line(position = pd) +
    custom_pointrange(position = pd) +
    labs(y = "Entry Speed") +
    guides(color = guide_legend(override.aes = list(linetype = 0))) +
    theme(legend.position = "none",
          panel.spacing = PANEL_MARGIN)
}

7.1 Summaries

7.1.1 Global

p_data_ts |>
  group_by(suggestions_type) |>
  summarize(
    sd_speed = sd(speed),
    mean_speed = mean(speed),
    .groups = "drop"
  )

7.1.2 Per conditions

p_data_ts |>
  group_by(suggestions_type, accuracy, keytime) |>
  summarize(
    sd_speed = sd(speed),
    mean_speed = mean(speed),
    .groups = "drop"
  )

7.1.3 Per keytime

p_data_ts |>
  group_by(suggestions_type, keytime) |>
  summarize(
    sd_speed = sd(speed),
    mean_speed = mean(speed),
    .groups = "drop"
  )

7.1.4 Per accuray

p_data_ts |>
  group_by(suggestions_type, accuracy) |>
  summarize(
    sd_speed = sd(speed),
    mean_speed = mean(speed),
    .groups = "drop"
  )

7.2 Inline Suggestions

p_data_ts_inline <- p_data_ts |> filter(suggestions_type == INLINE_SUGGESTION_TYPE)


inline_entry_speed_plot <- plot_entry_speed(p_data_ts_inline)

ggsave(
  graph_path("entry-speed-inline.pdf"),
  plot = inline_entry_speed_plot,
  units = "mm",
  width = (FULL_WIDTH - H_GRAPH_MARGIN) / 4 + 1,
  height = (FULL_WIDTH - H_GRAPH_MARGIN) / 4,
  device = cairo_pdf
)

inline_entry_speed_plot

7.2.1 Normality and Homogeneity

ggplot(p_data_ts_inline, aes(x = speed)) +
  geom_histogram(binwidth = 2) +
  facet_grid(rows=vars(accuracy), cols = vars(keytime))

m <- aov(speed ~ keytime*accuracy, data=p_data_ts_inline)
pander(normalCheck(m))

Shapiro-Wilk normality test

data: res W = 0.9444, p-value = 2.623e-14

Shapiro-Wilk normality test: res
Test statistic P value
0.9444 2.623e-14 * * *
remove(m)

Not normal.

7.2.2 Determine boxcox transform lambda

boxcox(speed~keytime*accuracy, data=p_data_ts_inline)

lambda <- 0.15
m <- aov(speed ^lambda  ~ keytime*accuracy, data=p_data_ts_inline)
pander(normalCheck(m))

Shapiro-Wilk normality test

data: res W = 0.97699, p-value = 3.596e-08

Shapiro-Wilk normality test: res
Test statistic P value
0.977 3.596e-08 * * *
remove(m)

Could not normalize it. Switch to ART.

7.2.3 ART

m_ts = art(speed ~ keytime * accuracy, data=p_data_ts_inline)
anova(m_ts, type = 2)
emmeans(artlm(m_ts, "keytime"), pairwise ~ keytime)
NOTE: Results may be misleading due to involvement in interactions
$emmeans
 keytime emmean   SE  df lower.CL upper.CL
 0          456 10.4 587      435      476
 50         379 10.3 587      359      399
 100        247 10.4 587      226      267
 200        137 10.2 587      117      157

Results are averaged over the levels of: accuracy 
Confidence level used: 0.95 

$contrasts
 contrast                estimate   SE  df t.ratio p.value
 keytime0 - keytime50        76.6 14.6 587   5.252  <.0001
 keytime0 - keytime100      209.1 14.7 587  14.261  <.0001
 keytime0 - keytime200      318.5 14.6 587  21.846  <.0001
 keytime50 - keytime100     132.5 14.6 587   9.079  <.0001
 keytime50 - keytime200     241.8 14.5 587  16.670  <.0001
 keytime100 - keytime200    109.3 14.6 587   7.500  <.0001

Results are averaged over the levels of: accuracy 
P value adjustment: tukey method for comparing a family of 4 estimates 
emmeans(artlm(m_ts, "accuracy"), pairwise ~ accuracy)
NOTE: Results may be misleading due to involvement in interactions
$emmeans
 accuracy emmean   SE  df lower.CL upper.CL
 0.1         263 14.7 587      234      292
 0.3         237 14.7 587      208      266
 0.5         290 14.7 587      261      319
 0.7         286 14.4 587      257      314
 0.9         446 14.7 587      417      475

Results are averaged over the levels of: keytime 
Confidence level used: 0.95 

$contrasts
 contrast                  estimate   SE  df t.ratio p.value
 accuracy0.1 - accuracy0.3    26.03 20.7 587   1.255  0.7191
 accuracy0.1 - accuracy0.5   -27.14 20.8 587  -1.306  0.6877
 accuracy0.1 - accuracy0.7   -22.69 20.6 587  -1.102  0.8056
 accuracy0.1 - accuracy0.9  -182.83 20.8 587  -8.796  <.0001
 accuracy0.3 - accuracy0.5   -53.17 20.8 587  -2.558  0.0797
 accuracy0.3 - accuracy0.7   -48.71 20.6 587  -2.366  0.1262
 accuracy0.3 - accuracy0.9  -208.86 20.8 587 -10.048  <.0001
 accuracy0.5 - accuracy0.7     4.46 20.6 587   0.216  0.9995
 accuracy0.5 - accuracy0.9  -155.69 20.8 587  -7.475  <.0001
 accuracy0.7 - accuracy0.9  -160.15 20.6 587  -7.762  <.0001

Results are averaged over the levels of: keytime 
P value adjustment: tukey method for comparing a family of 5 estimates 

7.3 Bar Suggestions

p_data_ts_bar <- p_data_ts |> filter(suggestions_type == BAR_SUGGESTION_TYPE)
p_data_ts_bar_common_factors <- p_data_ts_bar


bar_entry_speed_plot <- plot_entry_speed(p_data_ts_bar)

ggsave(
  graph_path("entry-speed-bar.pdf"),
  plot = bar_entry_speed_plot,
  units = "mm",
  width = (FULL_WIDTH - H_GRAPH_MARGIN) / 4 + 1,
  height = (FULL_WIDTH - H_GRAPH_MARGIN) / 4,
  device = cairo_pdf
)

bar_entry_speed_plot

7.3.1 Normality and Homogeneity

ggplot(p_data_ts_bar_common_factors, aes(x = speed)) +
  geom_histogram(binwidth = 2) +
  facet_grid(rows=vars(accuracy), cols = vars(keytime))

m <- aov(speed ~ keytime*accuracy, data=p_data_ts_bar_common_factors)
pander(normalCheck(m))

Shapiro-Wilk normality test

data: res W = 0.96035, p-value = 1.218e-11

Shapiro-Wilk normality test: res
Test statistic P value
0.9603 1.218e-11 * * *
remove(m)

Not normal.

7.3.2 ART

m_ts_bar = art(speed ~ keytime * accuracy, data=p_data_ts_bar_common_factors)
anova(m_ts_bar, type = 2)
emmeans(artlm(m_ts_bar, "keytime"), pairwise ~ keytime)
NOTE: Results may be misleading due to involvement in interactions
$emmeans
 keytime emmean   SE  df lower.CL upper.CL
 0          451 10.8 580      430      472
 50         361 10.8 580      340      382
 100        239 10.8 580      217      260
 200        151 10.8 580      130      173

Results are averaged over the levels of: accuracy 
Confidence level used: 0.95 

$contrasts
 contrast                estimate   SE  df t.ratio p.value
 keytime0 - keytime50        89.6 15.2 580   5.876  <.0001
 keytime0 - keytime100      212.2 15.2 580  13.925  <.0001
 keytime0 - keytime200      299.5 15.2 580  19.651  <.0001
 keytime50 - keytime100     122.7 15.2 580   8.049  <.0001
 keytime50 - keytime200     209.9 15.2 580  13.774  <.0001
 keytime100 - keytime200     87.2 15.2 580   5.725  <.0001

Results are averaged over the levels of: accuracy 
P value adjustment: tukey method for comparing a family of 4 estimates 
emmeans(artlm(m_ts_bar, "accuracy"), pairwise ~ accuracy)
NOTE: Results may be misleading due to involvement in interactions
$emmeans
 accuracy emmean   SE  df lower.CL upper.CL
 0.1         280 14.4 580      251      308
 0.3         237 14.4 580      209      265
 0.5         277 14.4 580      248      305
 0.7         261 14.4 580      233      290
 0.9         448 14.4 580      419      476

Results are averaged over the levels of: keytime 
Confidence level used: 0.95 

$contrasts
 contrast                  estimate   SE  df t.ratio p.value
 accuracy0.1 - accuracy0.3    42.65 20.4 580   2.092  0.2247
 accuracy0.1 - accuracy0.5     2.98 20.4 580   0.146  0.9999
 accuracy0.1 - accuracy0.7    18.17 20.4 580   0.891  0.9001
 accuracy0.1 - accuracy0.9  -168.00 20.4 580  -8.242  <.0001
 accuracy0.3 - accuracy0.5   -39.67 20.4 580  -1.946  0.2940
 accuracy0.3 - accuracy0.7   -24.48 20.4 580  -1.201  0.7507
 accuracy0.3 - accuracy0.9  -210.65 20.4 580 -10.335  <.0001
 accuracy0.5 - accuracy0.7    15.19 20.4 580   0.745  0.9457
 accuracy0.5 - accuracy0.9  -170.97 20.4 580  -8.388  <.0001
 accuracy0.7 - accuracy0.9  -186.17 20.4 580  -9.134  <.0001

Results are averaged over the levels of: keytime 
P value adjustment: tukey method for comparing a family of 5 estimates 

7.4 Inline vs Bar

p_data_ts |>
  group_by(suggestions_type) |>
  summarize(
    error = t_error(speed),
    mean = mean(speed))
m_ts_both = art(speed ~ keytime * accuracy * suggestions_type, data=p_data_ts)
anova(m_ts_both, type = 2)
emmeans(artlm(m_ts_both, "suggestions_type"), pairwise ~ suggestions_type)
NOTE: Results may be misleading due to involvement in interactions
$emmeans
 suggestions_type emmean   SE   df lower.CL upper.CL
 BAR                 572 14.4 1167      544      601
 INLINE              635 14.3 1167      607      663

Results are averaged over the levels of: keytime, accuracy 
Confidence level used: 0.95 

$contrasts
 contrast     estimate   SE   df t.ratio p.value
 BAR - INLINE    -62.7 20.2 1167  -3.100  0.0020

Results are averaged over the levels of: keytime, accuracy 

8 Total Run duration

line_graph <-
  function(completed_trials,
           measure,
           min_value = NA,
           max_value = NA) {
    graph_data <- completed_trials |>
      rename(value = measure) |>
      group_by(participant, accuracy_numeric, keytime_numeric, suggestions_type) |>
      summarize(p_value = mean(value), .groups="drop") |>
      group_by(accuracy_numeric, keytime_numeric, suggestions_type) |>
      summarize(
        error_value = t_error(p_value),
        mean_value = mean(p_value),
        ci_min = if_else(
          is.na(min_value),
          mean_value - error_value,
          max(min_value, mean_value - error_value)
        ),
        ci_max = if_else(
          is.na(max_value),
          mean_value + error_value,
          min(max_value, mean_value + error_value)
        ),
        .groups = "drop"
      )
    ggplot(
      graph_data,
      aes(
        x = accuracy_numeric,
        y = mean_value,
        ymin = ci_min,
        ymax = ci_max,
        color = keytime_numeric,
        group = keytime_numeric
      )
    ) +
      scale_x_continuous(breaks = ACCURACY_LEVELS_NUM) +
      scale_color_continuous(breaks = keytime_LEVELS_NUM) +
      geom_line() +
      geom_pointrange()
  }

line_graph(measured_runs |> mutate(minutes = duration / 60) |>
             filter(minutes <= 120), "minutes") +
  facet_wrap(vars(suggestions_type)) +
  ylab("Duration (minutes)")

9 Learning

p_data_ks <- measured_test_trials |>
  group_by(participant, accuracy, keytime, accuracy_numeric, keytime_numeric, suggestions_type, trial_number) |>
  summarize(
    p_mean_actual_ks = mean(actual_key_saving_no_editing),
    p_mean_theoretical_ks = mean(theoretical_key_saving),
    .groups = "drop"
  ) |>
  group_by(accuracy, keytime, trial_number) |>
  mutate(
    is_outlier = is_outlier(p_mean_actual_ks)
  ) |>
  ungroup()

actual_ks_summary <- p_data_ks |>
  group_by(accuracy_numeric, keytime_numeric, suggestions_type, trial_number) |>
  summarize(
    error_ks = t_error(p_mean_actual_ks),
    mean_ks = mean(p_mean_actual_ks),
    min_ks = max(0, mean_ks - error_ks),
    max_ks = min(1, mean_ks + error_ks),
    ks_type = "actual",
    .groups = "drop"
  )

theoretical_ks_summary <- p_data_ks |>
  group_by(accuracy_numeric, suggestions_type, trial_number) |>
  summarize(
    error_ks = t_error(p_mean_theoretical_ks),
    mean_ks = mean(p_mean_theoretical_ks),
    min_ks = max(0, mean_ks - error_ks),
    max_ks = min(1, mean_ks + error_ks),
    ks_type = "theoretical",
    keytime_numeric = NA,
    .groups = "drop"
  )
  
ks_summary <- union_all(theoretical_ks_summary, actual_ks_summary)

pd <- position_dodge(0.025)
plot_learning <- ggplot(ks_summary, aes(
    x = trial_number,
    y = mean_ks,
    ymin = min_ks,
    ymax = max_ks,
    color = keytime_numeric,
    group = keytime_numeric
  )) +
  custom_line(
    data=theoretical_ks_summary,
    color=THEORETICAL_COLOR,
    group="theoretical"
  ) +
  custom_pointrange(
    data=theoretical_ks_summary,
    color=THEORETICAL_COLOR,
    group="theoretical",
    shape=17
  ) +
  custom_line(data=actual_ks_summary, position=pd) +
  custom_pointrange(data=actual_ks_summary, position=pd) +
  SCALE_COLOR_KEY_STROKE +
  scale_y_continuous("Keystroke Saving", limits = c(0, 1), labels = percent) + 
  facet_grid(rows=vars(suggestions_type), cols=vars(accuracy_numeric)) +
  theme(
    legend.position = "none",
    panel.spacing = PANEL_MARGIN
    # strip.text.y = element_blank(),
    # strip.background.y = element_blank(),
    # axis.title.x = element_blank()
  )

ggsave(
  graph_path("amt-learning-keystroke-saving.pdf"),
  plot = plot_learning,
  units="mm",
  width=150,
  height=150,
  device=cairo_pdf
)

plot_learning

10 Exports

theme_margin <- theme(plot.margin = margin(r = 2, b = 2, unit = "mm"))

inline_plot <-
  (inline_reliance_plot + theme_margin) + inline_entry_speed_plot + inline_ks_plot  + inline_ks_ratio_plot 


ggsave(
  graph_path("objective_inline.pdf"),
  plot = inline_plot,
  units = "mm",
  width = FULL_WIDTH,
  height =  FULL_WIDTH /  GOLDEN_RATIO,
  device = cairo_pdf
)

inline_plot

bar_plot <-
  (bar_reliance_plot + theme_margin) + bar_entry_speed_plot + bar_ks_plot  + bar_ks_ratio_plot 


ggsave(
  graph_path("objective_bar.pdf"),
  plot = bar_plot,
  units = "mm",
  width = FULL_WIDTH,
  height =  FULL_WIDTH /  GOLDEN_RATIO,
  device = cairo_pdf
)

bar_plot

Go back to main

LS0tCnRpdGxlOiAiV29yZC1TdWdnZXN0aW9uczogS2V5dGltZSBPYmplY3RpdmUgUmVzdWx0cyIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgdGhlbWU6IGx1bWVuCiAgICBoaWdobGlnaHQ6IGRlZmF1bHQKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgbnVtYmVyX3NlY3Rpb25zOiBUUlVFCi0tLQoKCltHbyBiYWNrIHRvIG1haW5dKC4vbWFpbi5uYi5odG1sKQoKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmxpYnJhcnkocGFuZGVyKQpsaWJyYXJ5KGV6KQpsaWJyYXJ5KEFSVG9vbCkKbGlicmFyeShNQVNTKSAjIGZvciBib3hwbG90CmxpYnJhcnkoZW1tZWFucykKbGlicmFyeShzY2FsZXMpICMgZm9yIHBlcmNlbnQgc2NhbGUKbGlicmFyeShwYXRjaHdvcmspCnNvdXJjZSgiLi9rZXl0aW1lLXNldHVwLlIiKQoKSF9HUkFQSF9NQVJHSU4gPSAxMApQQU5FTF9NQVJHSU4gPSB1bml0KDQsICJtbSIpCgpub3JtYWxDaGVjayA8LSBmdW5jdGlvbihtb2RlbCkgewogIHJlcyA9IHJlc2lkdWFscyhtb2RlbCkKICBxcW5vcm0oKHJlcyAtIG1lYW4ocmVzKSkgLyBzZChyZXMpKQogIGFibGluZSgwLCAxKQogIHByaW50IChzaGFwaXJvLnRlc3QocmVzKSkKfQoKYWxsX3RyaWFscyA8LSByZWFkX2tleXRpbWVfdHJpYWxzKG1lYXN1cmVkX29ubHkgPSBGQUxTRSkKbWVhc3VyZWRfdGVzdF90cmlhbHMgPC0gcmVhZF9rZXl0aW1lX3RyaWFscyhtZWFzdXJlZF9vbmx5ID0gVFJVRSkgfD4KICBtdXRhdGUoCiAgc3VnZ2VzdGlvbnNfdHlwZSA9IHN1Z2dlc3Rpb25zX3R5cGUgfD4gZmN0X3JlbGV2ZWwoQkFSX1NVR0dFU1RJT05fVFlQRSwgSU5MSU5FX1NVR0dFU1RJT05fVFlQRSksCiAgc3VnZ2VzdGlvbnNfbGFiZWwgPSBmY3RfcmVjb2RlKAogICAgc3VnZ2VzdGlvbnNfdHlwZSwKICAgIGBTdWdnZXN0aW9uIEJhciAoRXhwLiAyKWAgPSBCQVJfU1VHR0VTVElPTl9UWVBFLAogICAgYElubGluZSBTdWdnZXN0aW9ucyAoRXhwLiAzKWAgPSBJTkxJTkVfU1VHR0VTVElPTl9UWVBFCiAgKQopCm1lYXN1cmVkX3J1bnMgPC0gcmVhZF9rZXl0aW1lX3J1bnMobWVhc3VyZWRfb25seSA9IFRSVUUpCmBgYAoKIyBUcmlhbHMKCmBgYHtyfQphbGxfdHJpYWxzIHw+CiAgZmlsdGVyKCFpc19wcmFjdGljZSAmIGlzX3J1bl9tZWFzdXJlZCkgfD4KICBjb3VudChzdWdnZXN0aW9uc190eXBlLCBpc190cmlhbF9tZWFzdXJlZCwgd2FzX3RyaWFsX2JsdXJyZWQpCmBgYAoKCiMgU3VnZ2VzdGlvbnMgUmVsaWFuY2UKCmBgYHtyLCBkZXY9InN2Z2xpdGUifQpwX2RhdGFfdXNhZ2UgPC0gbWVhc3VyZWRfdGVzdF90cmlhbHMgfD4KICBncm91cF9ieSgKICAgIHBhcnRpY2lwYW50LAogICAgYWNjdXJhY3ksCiAgICBrZXl0aW1lLAogICAgYWNjdXJhY3lfbnVtZXJpYywKICAgIGtleXRpbWVfbnVtZXJpYywKICAgIHN1Z2dlc3Rpb25zX3R5cGUKICApIHw+CiAgc3VtbWFyaXplKG1lYW5fc3VnZ2VzdGlvbl91c2UgPSBtZWFuKHRvdGFsX3N1Z2dlc3Rpb25fdXNlZCksCiAgICAgICAgICAgIC5ncm91cHMgPSAiZHJvcCIpCgpwbG90X3JlbGlhbmNlIDwtIGZ1bmN0aW9uKGZpbHRlcmVkX3BfZGF0YV91c2FnZSkgewogIHN1bW1hcnlfdXNhZ2UgPC0gZmlsdGVyZWRfcF9kYXRhX3VzYWdlIHw+CiAgICBncm91cF9ieShhY2N1cmFjeV9udW1lcmljLCBrZXl0aW1lX251bWVyaWMpIHw+CiAgICBzdW1tYXJpemUoCiAgICAgIGVycl9tZWFuX3RpYmJsZShtZWFuX3N1Z2dlc3Rpb25fdXNlLCBtaW5fbWluID0gMCksCiAgICAgIC5ncm91cHMgPSAiZHJvcCIKICAgICkKICAKICBwZCA8LSBwb3NpdGlvbl9kb2RnZSgwLjAyNSkKICBnZ3Bsb3QoCiAgICBkYXRhID0gc3VtbWFyeV91c2FnZSwKICAgIGFlcygKICAgICAgeCA9IGFjY3VyYWN5X251bWVyaWMsCiAgICAgIHkgPSBkYXRhX21lYW4sCiAgICAgIHltaW4gPSBkYXRhX21pbiwKICAgICAgeW1heCA9IGRhdGFfbWF4LAogICAgICBjb2xvciA9IGtleXRpbWVfbnVtZXJpYywKICAgICAgZ3JvdXAgPSBrZXl0aW1lX251bWVyaWMKICAgICkKICApICsKICAgIFNDQUxFX0NPTE9SX0tFWV9TVFJPS0UgKwogICAgU0NBTEVfWF9BQ0NVUkFDWSArCiAgICBzY2FsZV95X2NvbnRpbnVvdXMoIlN1Z2dlc3Rpb25zIFVzZSBwZXIgVHJpYWxzIiwgYnJlYWtzID0gc2VxKDAsIDYsIDEpKSArCiAgICBleHBhbmRfbGltaXRzKHkgPSBjKDApKSArCiAgICBjdXN0b21fbGluZShwb3NpdGlvbiA9IHBkKSArCiAgICBjdXN0b21fcG9pbnRyYW5nZShwb3NpdGlvbiA9IHBkKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgICBwYW5lbC5zcGFjaW5nID0gUEFORUxfTUFSR0lOKQp9CmBgYAoKCiMjIFN1bW1hcmllcwoKIyMjIEdsb2JhbAoKYGBge3J9CnBfZGF0YV91c2FnZSB8PgogIGdyb3VwX2J5KHN1Z2dlc3Rpb25zX3R5cGUpIHw+CiAgc3VtbWFyaXplKAogICAgc2Rfc3VnZ2VzdGlvbl91c2UgPSBzZChtZWFuX3N1Z2dlc3Rpb25fdXNlKSwKICAgIG1lYW5fc3VnZ2VzdGlvbl91c2UgPSBtZWFuKG1lYW5fc3VnZ2VzdGlvbl91c2UpLAogICAgLmdyb3VwcyA9ICJkcm9wIgogICkKYGBgCiMjIyBQZXIgY29uZGl0aW9ucwoKYGBge3J9CnBfZGF0YV91c2FnZSB8PgogIGdyb3VwX2J5KHN1Z2dlc3Rpb25zX3R5cGUsIGFjY3VyYWN5LCBrZXl0aW1lKSB8PgogIHN1bW1hcml6ZSgKICAgIHNkX3N1Z2dlc3Rpb25fdXNlID0gc2QobWVhbl9zdWdnZXN0aW9uX3VzZSksCiAgICBtZWFuX3N1Z2dlc3Rpb25fdXNlID0gbWVhbihtZWFuX3N1Z2dlc3Rpb25fdXNlKSwKICAgIC5ncm91cHMgPSAiZHJvcCIKICApCmBgYAojIyMgUGVyIGtleXRpbWUKCmBgYHtyfQpwX2RhdGFfdXNhZ2UgfD4KICBncm91cF9ieShzdWdnZXN0aW9uc190eXBlLCBrZXl0aW1lKSB8PgogIHN1bW1hcml6ZSgKICAgIHNkX3N1Z2dlc3Rpb25fdXNlID0gc2QobWVhbl9zdWdnZXN0aW9uX3VzZSksCiAgICBtZWFuX3N1Z2dlc3Rpb25fdXNlID0gbWVhbihtZWFuX3N1Z2dlc3Rpb25fdXNlKSwKICAgIC5ncm91cHMgPSAiZHJvcCIKICApCmBgYAoKIyMjIFBlciBhY2N1cmF5CgpgYGB7cn0KcF9kYXRhX3VzYWdlIHw+CiAgZ3JvdXBfYnkoc3VnZ2VzdGlvbnNfdHlwZSwgYWNjdXJhY3kpIHw+CiAgc3VtbWFyaXplKAogICAgc2Rfc3VnZ2VzdGlvbl91c2UgPSBzZChtZWFuX3N1Z2dlc3Rpb25fdXNlKSwKICAgIG1lYW5fc3VnZ2VzdGlvbl91c2UgPSBtZWFuKG1lYW5fc3VnZ2VzdGlvbl91c2UpLAogICAgLmdyb3VwcyA9ICJkcm9wIgogICkKYGBgCgoKIyMgSW5saW5lIHN1Z2dlc3Rpb25zCgpgYGB7ciwgZGV2PSJzdmdsaXRlIn0KcF9kYXRhX3VzYWdlX2lubGluZSA8LQogIHBfZGF0YV91c2FnZSB8PiBmaWx0ZXIoc3VnZ2VzdGlvbnNfdHlwZSA9PSBJTkxJTkVfU1VHR0VTVElPTl9UWVBFKQoKaW5saW5lX3JlbGlhbmNlX3Bsb3QgPC0gcGxvdF9yZWxpYW5jZShwX2RhdGFfdXNhZ2VfaW5saW5lKQoKZ2dzYXZlKAogIGdyYXBoX3BhdGgoInN1Z2dlc3Rpb25zLXVzYWdlLWlubGluZS5wZGYiKSwKICBwbG90ID0gaW5saW5lX3JlbGlhbmNlX3Bsb3QsCiAgdW5pdHMgPSAibW0iLAogIHdpZHRoID0gKEZVTExfV0lEVEggLSBIX0dSQVBIX01BUkdJTikgLyA0IC0gMiwKICBoZWlnaHQgPSAoRlVMTF9XSURUSCAtIEhfR1JBUEhfTUFSR0lOKSAvIDQsCiAgZGV2aWNlID0gY2Fpcm9fcGRmCikKCmlubGluZV9yZWxpYW5jZV9wbG90CmBgYAoKIyMjIEhpc3RvZ3JhbXMKCmBgYHtyLCBkZXY9InN2Z2xpdGUifQpnZ3Bsb3QocF9kYXRhX3VzYWdlX2lubGluZSwgYWVzKHggPSBtZWFuX3N1Z2dlc3Rpb25fdXNlKSkgKwogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gLjUpICsKICBmYWNldF9ncmlkKHJvd3M9dmFycyhhY2N1cmFjeSksIGNvbHMgPSB2YXJzKGtleXRpbWUpKQpgYGAKCiMjIyBBTk9WQSBhc3N1bXB0aW9ucwoKYGBge3IsIGRldj0ic3ZnbGl0ZSJ9Cm1vZGVsX3VzYWdlIDwtIGV6QU5PVkEoCiAgZGF0YSA9IG1lYXN1cmVkX3Rlc3RfdHJpYWxzIHw+IGZpbHRlcihzdWdnZXN0aW9uc190eXBlID09IElOTElORV9TVUdHRVNUSU9OX1RZUEUpLAogIHdpZCA9IGMoInBhcnRpY2lwYW50IiksCiAgZHYgPSB0b3RhbF9zdWdnZXN0aW9uX3VzZWQsCiAgYmV0d2VlbiA9IGMoImtleXRpbWUiLCAiYWNjdXJhY3kiKSwKICByZXR1cm5fYW92ID0gVFJVRQopCnFxbm9ybShtb2RlbF91c2FnZSRhb3YkcmVzaWR1YWxzKTtxcWxpbmUobW9kZWxfdXNhZ2UkYW92JHJlc2lkdWFscykKbW9kZWxfdXNhZ2UKYGBgCgojIyMgQVJUCgpgYGB7ciwgZGV2PSJzdmdsaXRlIn0KYXJ0X21fdXNhZ2VfaW5saW5lID0gYXJ0KG1lYW5fc3VnZ2VzdGlvbl91c2UgfiBrZXl0aW1lICogYWNjdXJhY3ksCiAgICAgICAgICAgICAgICAgIGRhdGE9cF9kYXRhX3VzYWdlX2lubGluZSkKYW5vdmEoYXJ0X21fdXNhZ2VfaW5saW5lLCB0eXBlID0gMikKYGBgCgpgYGB7ciwgZGV2PSJzdmdsaXRlIn0KZW1tZWFucyhhcnRsbShhcnRfbV91c2FnZV9pbmxpbmUsICJrZXl0aW1lIiksIHBhaXJ3aXNlIH4ga2V5dGltZSkKYGBgCgpgYGB7ciwgZGV2PSJzdmdsaXRlIn0KZW1tZWFucyhhcnRsbShhcnRfbV91c2FnZV9pbmxpbmUsICJhY2N1cmFjeSIpLCBwYWlyd2lzZSB+IGFjY3VyYWN5KQpgYGAKCgojIyBCYXIgc3VnZ2VzdGlvbnMKCmBgYHtyLCBkZXY9InN2Z2xpdGUifQpwX2RhdGFfdXNhZ2VfYmFyIDwtIHBfZGF0YV91c2FnZSB8PgogIGZpbHRlcihzdWdnZXN0aW9uc190eXBlID09IEJBUl9TVUdHRVNUSU9OX1RZUEUpCnBfZGF0YV91c2FnZV9iYXJfY29tbW9uX2ZhY3RvcnMgPC0gcF9kYXRhX3VzYWdlX2JhcgoKYmFyX3JlbGlhbmNlX3Bsb3QgPC0gcGxvdF9yZWxpYW5jZShwX2RhdGFfdXNhZ2VfYmFyKQoKZ2dzYXZlKAogIGdyYXBoX3BhdGgoInN1Z2dlc3Rpb25zLXVzYWdlLWJhci5wZGYiKSwKICBwbG90ID0gYmFyX3JlbGlhbmNlX3Bsb3QsCiAgdW5pdHMgPSAibW0iLAogIHdpZHRoID0gKEZVTExfV0lEVEggLSBIX0dSQVBIX01BUkdJTikgLyA0IC0gMiwKICBoZWlnaHQgPSAoRlVMTF9XSURUSCAtIEhfR1JBUEhfTUFSR0lOKSAvIDQsCiAgZGV2aWNlID0gY2Fpcm9fcGRmCikKCmJhcl9yZWxpYW5jZV9wbG90CmBgYAoKIyMjIEhpc3RvZ3JhbXMKCmBgYHtyLCBkZXY9InN2Z2xpdGUifQpnZ3Bsb3QocF9kYXRhX3VzYWdlX2JhciwgYWVzKHggPSBtZWFuX3N1Z2dlc3Rpb25fdXNlKSkgKwogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gLjUpICsKICBmYWNldF9ncmlkKHJvd3M9dmFycyhhY2N1cmFjeSksIGNvbHMgPSB2YXJzKGtleXRpbWUpKQpgYGAKCiMjIyBBTk9WQSBhc3N1bXB0aW9ucwoKYGBge3IsIGRldj0ic3ZnbGl0ZSJ9Cm1vZGVsX3VzYWdlIDwtIGV6QU5PVkEoCiAgZGF0YSA9IG1lYXN1cmVkX3Rlc3RfdHJpYWxzIHw+CiAgICBmaWx0ZXIoc3VnZ2VzdGlvbnNfdHlwZSA9PSBCQVJfU1VHR0VTVElPTl9UWVBFICYgYWNjdXJhY3kgJWluJSBjKDAuMSwgMC41LCAwLjkpKSwKICB3aWQgPSBjKCJwYXJ0aWNpcGFudCIpLAogIGR2ID0gdG90YWxfc3VnZ2VzdGlvbl91c2VkLAogIGJldHdlZW4gPSBjKCJrZXl0aW1lIiwgImFjY3VyYWN5IiksCiAgcmV0dXJuX2FvdiA9IFRSVUUKKQpxcW5vcm0obW9kZWxfdXNhZ2UkYW92JHJlc2lkdWFscyk7cXFsaW5lKG1vZGVsX3VzYWdlJGFvdiRyZXNpZHVhbHMpCm1vZGVsX3VzYWdlCmBgYAoKIyMjIEFSVAoKYGBge3IsIGRldj0ic3ZnbGl0ZSJ9CmFydF9tX3VzYWdlX2JhciA9IGFydChtZWFuX3N1Z2dlc3Rpb25fdXNlIH4ga2V5dGltZSAqIGFjY3VyYWN5LAogICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IHBfZGF0YV91c2FnZV9iYXJfY29tbW9uX2ZhY3RvcnMpCmFub3ZhKGFydF9tX3VzYWdlX2JhciwgdHlwZSA9IDIpCmBgYAoKYGBge3IsIGRldj0ic3ZnbGl0ZSJ9CmVtbWVhbnMoYXJ0bG0oYXJ0X21fdXNhZ2VfYmFyLCAia2V5dGltZSIpLCBwYWlyd2lzZSB+IGtleXRpbWUpCmBgYAoKYGBge3IsIGRldj0ic3ZnbGl0ZSJ9CmVtbWVhbnMoYXJ0bG0oYXJ0X21fdXNhZ2VfYmFyLCAiYWNjdXJhY3kiKSwgcGFpcndpc2UgfiBhY2N1cmFjeSkKYGBgCgoKCgojIFNhdmVkIEtleSBTdHJva2VzCgoKYGBge3IsIGRldj0ic3ZnbGl0ZSJ9CnBfZGF0YV9za3MgPC0gbWVhc3VyZWRfdGVzdF90cmlhbHMgfD4KICBncm91cF9ieShwYXJ0aWNpcGFudCwgYWNjdXJhY3ksIGtleXRpbWUsIGFjY3VyYWN5X251bWVyaWMsIGtleXRpbWVfbnVtZXJpYywgc3VnZ2VzdGlvbnNfdHlwZSkgfD4KICBzdW1tYXJpemUoCiAgICBwX21lYW5fc2tzID0gbWVhbihhY3R1YWxfc2tzKSwKICAgIC5ncm91cHMgPSAiZHJvcCIKICApIAoKc3VtbWFyeV9za3MgPC0gcF9kYXRhX3NrcyB8PgogIGdyb3VwX2J5KGFjY3VyYWN5X251bWVyaWMsIGtleXRpbWVfbnVtZXJpYywgc3VnZ2VzdGlvbnNfdHlwZSkgfD4KICBzdW1tYXJpemUoCiAgICBlcnJvcl9za3MgPSB0X2Vycm9yKHBfbWVhbl9za3MpLAogICAgbWVhbl9za3MgPSBtZWFuKHBfbWVhbl9za3MpLAogICAgbWluX3NrcyA9IG1lYW5fc2tzIC0gZXJyb3Jfc2tzLAogICAgbWF4X3NrcyA9IG1lYW5fc2tzICsgZXJyb3Jfc2tzLAogICAgLmdyb3VwcyA9ICJkcm9wIgogICkKCnRoZW9yZXRpY2FsX3NrcyA8LSBtZWFzdXJlZF90ZXN0X3RyaWFscyB8PgogIGdyb3VwX2J5KHBhcnRpY2lwYW50LCBhY2N1cmFjeV9udW1lcmljLCBzdWdnZXN0aW9uc190eXBlKSB8PgogIHN1bW1hcml6ZShwX21lYW5fc2tzID0gbWVhbih0aGVvcmV0aWNhbF9za3MpLCAuZ3JvdXBzID0gImRyb3AiKSB8PgogIGdyb3VwX2J5KGFjY3VyYWN5X251bWVyaWMpIHw+CiAgc3VtbWFyaXplKAogICAgZXJyb3Jfc2tzID0gdF9lcnJvcihwX21lYW5fc2tzKSwKICAgIG1lYW5fc2tzID0gbWVhbihwX21lYW5fc2tzKSwKICAgIG1pbl9za3MgPSBtZWFuX3NrcyAtIGVycm9yX3NrcywKICAgIG1heF9za3MgPSBtZWFuX3NrcyArIGVycm9yX3NrcywKICAgIC5ncm91cHMgPSAiZHJvcCIKICApCnBkIDwtIHBvc2l0aW9uX2RvZGdlKDAuMDI1KQpwbG90X3NrcyA8LSBnZ3Bsb3Qoc3VtbWFyeV9za3MsIGFlcygKICAgIHggPSBhY2N1cmFjeV9udW1lcmljLAogICAgeSA9IG1lYW5fc2tzLAogICAgeW1pbiA9IG1pbl9za3MsCiAgICB5bWF4ID0gbWF4X3NrcywKICAgIGNvbG9yID0ga2V5dGltZV9udW1lcmljLAogICAgZ3JvdXAgPSBrZXl0aW1lX251bWVyaWMKICApKSArCiAgZ2VvbV9saW5lKGRhdGE9dGhlb3JldGljYWxfc2tzLCBjb2xvcj0icmVkIiwgZ3JvdXA9InJlZCIpICsKICBnZW9tX3BvaW50cmFuZ2UoZGF0YT10aGVvcmV0aWNhbF9za3MsIGNvbG9yPSJyZWQiLCBncm91cD0icmVkIikgKwogIHNjYWxlX2NvbG9yX2NvbnRpbnVvdXMoYnJlYWtzPWMoMCwgNTAsIDEwMCwgMjAwKSkgKwogIHNjYWxlX3hfY29udGludW91cyhicmVha3M9YygwLCAwLjEsIDAuMywgMC41LCAwLjcsIDAuOSwgMSkpICsKICBnZW9tX2xpbmUocG9zaXRpb249cGQpICsKICBnZW9tX3BvaW50cmFuZ2UocG9zaXRpb249cGQpICsKICBmYWNldF9ncmlkKHJvd3M9dmFycyhzdWdnZXN0aW9uc190eXBlKSkgKwogIHRoZW1lKAogICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgcGFuZWwuc3BhY2luZyA9IFBBTkVMX01BUkdJTiwKICApICsKICBsYWJzKHg9IkFjY3VyYWN5IiwgeT0iU2F2ZWQgS2V5c3Ryb2tlcyIsIGNvbG9yPSJLZXkgU3Ryb2tlIERlbGF5IikKCnBsb3Rfc2tzCmBgYAoKCgoKIyBLZXlzdHJva2UgU2F2aW5nCgoKYGBge3IsIGRldj0ic3ZnbGl0ZSJ9CnBfZGF0YV9rcyA8LSBtZWFzdXJlZF90ZXN0X3RyaWFscyB8PgogIGdyb3VwX2J5KAogICAgcGFydGljaXBhbnQsCiAgICBhY2N1cmFjeSwKICAgIGtleXRpbWUsCiAgICBhY2N1cmFjeV9udW1lcmljLAogICAga2V5dGltZV9udW1lcmljLAogICAgc3VnZ2VzdGlvbnNfdHlwZQogICkgfD4KICBzdW1tYXJpemUoCiAgICBwX21lYW5fYWN0dWFsX2tzID0gbWVhbihhY3R1YWxfa2V5X3NhdmluZ19ub19lZGl0aW5nKSwKICAgIHBfbWVhbl90aGVvcmV0aWNhbF9rcyA9IG1lYW4odGhlb3JldGljYWxfa2V5X3NhdmluZyksCiAgICAuZ3JvdXBzID0gImRyb3AiCiAgKSB8PgogIGdyb3VwX2J5KGFjY3VyYWN5LCBrZXl0aW1lKSB8PgogIG11dGF0ZShpc19vdXRsaWVyID0gaXNfb3V0bGllcihwX21lYW5fYWN0dWFsX2tzKSkgfD4KICB1bmdyb3VwKCkKCnBsb3Rfa2V5c3Ryb2tlX3NhdmluZyA8LSBmdW5jdGlvbihmaWx0ZXJlZF9wX2RhdGFfa3MpIHsKICBhY3R1YWxfa3Nfc3VtbWFyeSA8LSBmaWx0ZXJlZF9wX2RhdGFfa3MgfD4KICAgIGdyb3VwX2J5KGFjY3VyYWN5X251bWVyaWMsCiAgICAgICAgICAgICBrZXl0aW1lX251bWVyaWMpIHw+CiAgICBzdW1tYXJpemUoCiAgICAgIGVycm9yX2tzID0gdF9lcnJvcihwX21lYW5fYWN0dWFsX2tzKSwKICAgICAgbWVhbl9rcyA9IG1lYW4ocF9tZWFuX2FjdHVhbF9rcyksCiAgICAgIG1pbl9rcyA9IG1heCgwLCBtZWFuX2tzIC0gZXJyb3Jfa3MpLAogICAgICBtYXhfa3MgPSBtaW4oMSwgbWVhbl9rcyArIGVycm9yX2tzKSwKICAgICAga3NfdHlwZSA9ICJhY3R1YWwiLAogICAgICAuZ3JvdXBzID0gImRyb3AiCiAgICApCiAgCiAgdGhlb3JldGljYWxfa3Nfc3VtbWFyeSA8LSBmaWx0ZXJlZF9wX2RhdGFfa3MgfD4KICAgIGdyb3VwX2J5KGFjY3VyYWN5X251bWVyaWMpIHw+CiAgICBzdW1tYXJpemUoCiAgICAgIGVycm9yX2tzID0gdF9lcnJvcihwX21lYW5fdGhlb3JldGljYWxfa3MpLAogICAgICBtZWFuX2tzID0gbWVhbihwX21lYW5fdGhlb3JldGljYWxfa3MpLAogICAgICBtaW5fa3MgPSBtYXgoMCwgbWVhbl9rcyAtIGVycm9yX2tzKSwKICAgICAgbWF4X2tzID0gbWluKDEsIG1lYW5fa3MgKyBlcnJvcl9rcyksCiAgICAgIGtzX3R5cGUgPSAidGhlb3JldGljYWwiLAogICAgICBrZXl0aW1lX251bWVyaWMgPSBOQSwKICAgICAgLmdyb3VwcyA9ICJkcm9wIgogICAgKQogIAogIGtzX3N1bW1hcnkgPC0gdW5pb25fYWxsKHRoZW9yZXRpY2FsX2tzX3N1bW1hcnksIGFjdHVhbF9rc19zdW1tYXJ5KQogIAogIHBkIDwtIHBvc2l0aW9uX2RvZGdlKDAuMDI1KQogIHBsb3Rfa2V5c3Ryb2tlX3NhdmluZyA8LSBnZ3Bsb3QoCiAgICBrc19zdW1tYXJ5LAogICAgYWVzKAogICAgICB4ID0gYWNjdXJhY3lfbnVtZXJpYywKICAgICAgeSA9IG1lYW5fa3MsCiAgICAgIHltaW4gPSBtaW5fa3MsCiAgICAgIHltYXggPSBtYXhfa3MsCiAgICAgIGNvbG9yID0ga2V5dGltZV9udW1lcmljLAogICAgICBncm91cCA9IGtleXRpbWVfbnVtZXJpYwogICAgKQogICkgKwogICAgY3VzdG9tX2xpbmUoZGF0YSA9IHRoZW9yZXRpY2FsX2tzX3N1bW1hcnksCiAgICAgICAgICAgICAgICBjb2xvciA9IFRIRU9SRVRJQ0FMX0NPTE9SLAogICAgICAgICAgICAgICAgZ3JvdXAgPSAidGhlb3JldGljYWwiKSArCiAgICBjdXN0b21fcG9pbnRyYW5nZSgKICAgICAgZGF0YSA9IHRoZW9yZXRpY2FsX2tzX3N1bW1hcnksCiAgICAgIGNvbG9yID0gVEhFT1JFVElDQUxfQ09MT1IsCiAgICAgIGdyb3VwID0gInRoZW9yZXRpY2FsIiwKICAgICAgc2hhcGUgPSAxNwogICAgKSArCiAgICBjdXN0b21fbGluZShkYXRhID0gYWN0dWFsX2tzX3N1bW1hcnksIHBvc2l0aW9uID0gcGQpICsKICAgIGN1c3RvbV9wb2ludHJhbmdlKGRhdGEgPSBhY3R1YWxfa3Nfc3VtbWFyeSwgcG9zaXRpb24gPSBwZCkgKwogICAgU0NBTEVfQ09MT1JfS0VZX1NUUk9LRSArCiAgICBTQ0FMRV9YX0FDQ1VSQUNZICsKICAgIHNjYWxlX3lfY29udGludW91cygiS2V5c3Ryb2tlIFNhdmluZyIsCiAgICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygwLCAxKSwKICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBwZXJjZW50KSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgICBwYW5lbC5zcGFjaW5nID0gUEFORUxfTUFSR0lOKQp9CmBgYAoKCiMjIFN1bW1hcmllcwoKIyMjIEdsb2JhbAoKYGBge3J9CnBfZGF0YV9rcyB8PgogIGdyb3VwX2J5KHN1Z2dlc3Rpb25zX3R5cGUpIHw+CiAgc3VtbWFyaXplKAogICAgc2Rfa3MgPSBzZChwX21lYW5fYWN0dWFsX2tzKSwKICAgIG1lYW5fa3MgPSBtZWFuKHBfbWVhbl9hY3R1YWxfa3MpLAogICAgLmdyb3VwcyA9ICJkcm9wIgogICkKYGBgCiMjIyBQZXIgY29uZGl0aW9ucwoKYGBge3J9CnBfZGF0YV9rcyB8PgogIGdyb3VwX2J5KHN1Z2dlc3Rpb25zX3R5cGUsIGFjY3VyYWN5LCBrZXl0aW1lKSB8PgogIHN1bW1hcml6ZSgKICAgIHNkX2tzID0gc2QocF9tZWFuX2FjdHVhbF9rcyksCiAgICBtZWFuX2tzID0gbWVhbihwX21lYW5fYWN0dWFsX2tzKSwKICAgIC5ncm91cHMgPSAiZHJvcCIKICApCmBgYAojIyMgUGVyIGtleXRpbWUKCmBgYHtyfQpwX2RhdGFfa3MgfD4KICBncm91cF9ieShzdWdnZXN0aW9uc190eXBlLCBrZXl0aW1lKSB8PgogIHN1bW1hcml6ZSgKICAgIHNkX2tzID0gc2QocF9tZWFuX2FjdHVhbF9rcyksCiAgICBtZWFuX2tzID0gbWVhbihwX21lYW5fYWN0dWFsX2tzKSwKICAgIC5ncm91cHMgPSAiZHJvcCIKICApCmBgYAoKIyMjIFBlciBhY2N1cmF5CgpgYGB7cn0KcF9kYXRhX2tzIHw+CiAgZ3JvdXBfYnkoc3VnZ2VzdGlvbnNfdHlwZSwgYWNjdXJhY3kpIHw+CiAgc3VtbWFyaXplKAogICAgc2Rfa3MgPSBzZChwX21lYW5fYWN0dWFsX2tzKSwKICAgIG1lYW5fa3MgPSBtZWFuKHBfbWVhbl9hY3R1YWxfa3MpLAogICAgLmdyb3VwcyA9ICJkcm9wIgogICkKYGBgCgoKCiMjIElubGluZSBzdWdnZXN0aW9ucwoKYGBge3IsIGRldj0ic3ZnbGl0ZSJ9CnBfZGF0YV9rc19pbmxpbmUgPC0gcF9kYXRhX2tzIHw+IGZpbHRlcihzdWdnZXN0aW9uc190eXBlID09IElOTElORV9TVUdHRVNUSU9OX1RZUEUpCgppbmxpbmVfa3NfcGxvdCA8LSBwbG90X2tleXN0cm9rZV9zYXZpbmcocF9kYXRhX2tzX2lubGluZSkKCmdnc2F2ZSgKICBncmFwaF9wYXRoKCJrZXlzdHJva2Utc2F2aW5nLWlubGluZS5wZGYiKSwKICBwbG90PWlubGluZV9rc19wbG90LAogIHVuaXRzPSJtbSIsCiAgd2lkdGg9KEZVTExfV0lEVEggLSBIX0dSQVBIX01BUkdJTikgLyA0LAogIGhlaWdodD0oRlVMTF9XSURUSCAtIEhfR1JBUEhfTUFSR0lOKSAvIDQsCiAgZGV2aWNlPWNhaXJvX3BkZgopCgppbmxpbmVfa3NfcGxvdApgYGAKCiMjIyBOb3JtYWxpdHkgYW5kIEhvbW9nZW5laXR5CgpgYGB7ciwgZGV2PSJzdmdsaXRlIn0KZ2dwbG90KHBfZGF0YV9rc19pbmxpbmUsIGFlcyh4ID0gcF9tZWFuX2FjdHVhbF9rcykpICsKICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IC4wNSkgKwogIGZhY2V0X2dyaWQocm93cz12YXJzKGFjY3VyYWN5KSwgY29scyA9IHZhcnMoa2V5dGltZSkpCmBgYAoKYGBge3IsIGRldj0ic3ZnbGl0ZSJ9Cm0gPC0gYW92KHBfbWVhbl9hY3R1YWxfa3MgfiBrZXl0aW1lKmFjY3VyYWN5LCBkYXRhPXBfZGF0YV9rc19pbmxpbmUpCnBhbmRlcihub3JtYWxDaGVjayhtKSkKcmVtb3ZlKG0pCmBgYAoKTm90IG5vcm1hbC4KCiMjIyBEZXRlcm1pbmUgYm94Y294IHRyYW5zZm9ybSBsYW1iZGEKCmBgYHtyLCBkZXY9InN2Z2xpdGUifQpib3hjb3goKHBfbWVhbl9hY3R1YWxfa3MgKyAwLjUpfmtleXRpbWUqYWNjdXJhY3ksIGRhdGE9cF9kYXRhX2tzX2lubGluZSkKYGBgCgoKYGBge3IsIGRldj0ic3ZnbGl0ZSJ9CmxhbWJkYSA8LSAwLjUKbSA8LSBhb3YoKHBfbWVhbl9hY3R1YWxfa3MgKyAwLjUpIF4gLTAuMyB+IGtleXRpbWUqYWNjdXJhY3ksIGRhdGE9cF9kYXRhX2tzX2lubGluZSkKcGFuZGVyKG5vcm1hbENoZWNrKG0pKQpyZW1vdmUobSkKYGBgCgpgYGB7ciwgZGV2PSJzdmdsaXRlIn0KZXpBTk9WQSgKICBwX2RhdGFfa3NfaW5saW5lIHw+IG11dGF0ZShmaW5hbF9rcyA9IChwX21lYW5fYWN0dWFsX2tzICsgMC41KSBeIC0wLjMpLAogIGR2PWZpbmFsX2tzLCB3aWQ9YyhwYXJ0aWNpcGFudCksCiAgYmV0d2Vlbj1jKGtleXRpbWUsIGFjY3VyYWN5KSwKICBkZXRhaWxlZD1UUlVFCikKYGBgCgpTdGlsbCBub3Qgbm9ybWFsLCBhbmQgYWxzbyBub3QgaG9tb2dlbmljLCBzd2l0Y2hpbmcgdG8gYXJ0CgojIyMgQVJUCgpgYGB7ciwgZGV2PSJzdmdsaXRlIn0KbV9rc19pbmxpbmUgPSBhcnQocF9tZWFuX2FjdHVhbF9rcyB+IGtleXRpbWUgKiBhY2N1cmFjeSwgZGF0YT1wX2RhdGFfa3NfaW5saW5lKQphbm92YShtX2tzX2lubGluZSwgdHlwZSA9IDIpCmBgYAoKYGBge3IsIGRldj0ic3ZnbGl0ZSJ9CmVtbWVhbnMoYXJ0bG0obV9rc19pbmxpbmUsICJrZXl0aW1lIiksIHBhaXJ3aXNlIH4ga2V5dGltZSkKYGBgCgpgYGB7ciwgZGV2PSJzdmdsaXRlIn0KZW1tZWFucyhhcnRsbShtX2tzX2lubGluZSwgImFjY3VyYWN5IiksIHBhaXJ3aXNlIH4gYWNjdXJhY3kpCmBgYAoKCiMjIEJhciBzdWdnZXN0aW9ucwoKYGBge3IsIGRldj0ic3ZnbGl0ZSJ9CnBfZGF0YV9rc19iYXIgPC0gcF9kYXRhX2tzIHw+IGZpbHRlcihzdWdnZXN0aW9uc190eXBlID09IEJBUl9TVUdHRVNUSU9OX1RZUEUpCnBfZGF0YV9rc19iYXJfY29tbW9uX2ZhY3RvcnMgPC0gcF9kYXRhX2tzX2JhcgoKYmFyX2tzX3Bsb3QgPC0gcGxvdF9rZXlzdHJva2Vfc2F2aW5nKHBfZGF0YV9rc19iYXIpCgpnZ3NhdmUoCiAgZ3JhcGhfcGF0aCgia2V5c3Ryb2tlLXNhdmluZy1iYXIucGRmIiksCiAgcGxvdD1iYXJfa3NfcGxvdCwKICB1bml0cz0ibW0iLAogIHdpZHRoPShGVUxMX1dJRFRIIC0gSF9HUkFQSF9NQVJHSU4pIC8gNCwKICBoZWlnaHQ9KEZVTExfV0lEVEggLSBIX0dSQVBIX01BUkdJTikgLyA0LAogIGRldmljZT1jYWlyb19wZGYKKQoKYmFyX2tzX3Bsb3QKYGBgCgoKIyMgSW5saW5lIHZzIGJhcgoKYGBge3J9CnBfZGF0YV9rcyB8PgogIGdyb3VwX2J5KHN1Z2dlc3Rpb25zX3R5cGUpIHw+CiAgc3VtbWFyaXplKAogICAgZXJyb3IgPSB0X2Vycm9yKHBfbWVhbl9hY3R1YWxfa3MpLAogICAgbWVhbiA9IG1lYW4ocF9tZWFuX2FjdHVhbF9rcykpCmBgYAoKCmBgYHtyfQptX2tzX2JvdGggPSBhcnQocF9tZWFuX2FjdHVhbF9rcyB+IGtleXRpbWUgKiBhY2N1cmFjeSAqIHN1Z2dlc3Rpb25zX3R5cGUsIGRhdGE9cF9kYXRhX2tzKQphbm92YShtX2tzX2JvdGgsIHR5cGUgPSAyKQpgYGAKCmBgYHtyfQplbW1lYW5zKGFydGxtKG1fa3NfYm90aCwgInN1Z2dlc3Rpb25zX3R5cGUiKSwgcGFpcndpc2UgfiBzdWdnZXN0aW9uc190eXBlKQpgYGAKCgoKIyMjIE5vcm1hbGl0eSBhbmQgSG9tb2dlbmVpdHkKCmBgYHtyLCBkZXY9InN2Z2xpdGUifQpnZ3Bsb3QocF9kYXRhX2tzX2JhciwgYWVzKHggPSBwX21lYW5fYWN0dWFsX2tzKSkgKwogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gLjA1KSArCiAgZmFjZXRfZ3JpZChyb3dzPXZhcnMoYWNjdXJhY3kpLCBjb2xzID0gdmFycyhrZXl0aW1lKSkKYGBgCgpgYGB7ciwgZGV2PSJzdmdsaXRlIn0KbSA8LSBhb3YocF9tZWFuX2FjdHVhbF9rcyB+IGtleXRpbWUqYWNjdXJhY3ksIGRhdGE9cF9kYXRhX2tzX2Jhcl9jb21tb25fZmFjdG9ycykKcGFuZGVyKG5vcm1hbENoZWNrKG0pKQpyZW1vdmUobSkKYGBgCgpOb3Qgbm9ybWFsLgoKIyMjIEFSVAoKQy5mLiBodHRwOi8vZmFjdWx0eS53YXNoaW5ndG9uLmVkdS93b2Jicm9jay9wdWJzL2NoaS0xMS4wNi5wZGYKCmBgYHtyLCBkZXY9InN2Z2xpdGUifQptX2tzX2JhciA9IGFydChwX21lYW5fYWN0dWFsX2tzIH4ga2V5dGltZSAqIGFjY3VyYWN5LCBkYXRhPXBfZGF0YV9rc19iYXJfY29tbW9uX2ZhY3RvcnMpCmFub3ZhKG1fa3NfYmFyLCB0eXBlID0gMikKYGBgCgpgYGB7ciwgZGV2PSJzdmdsaXRlIn0KZW1tZWFucyhhcnRsbShtX2tzX2JhciwgImtleXRpbWUiKSwgcGFpcndpc2UgfiBrZXl0aW1lKQpgYGAKCmBgYHtyLCBkZXY9InN2Z2xpdGUifQplbW1lYW5zKGFydGxtKG1fa3NfYmFyLCAiYWNjdXJhY3kiKSwgcGFpcndpc2UgfiBhY2N1cmFjeSkKYGBgCgoKCiMgS2V5c3Ryb2tlIFNhdmluZyBSYXRpbwoKYGBge3IsIGRldj0ic3ZnbGl0ZSJ9CnBfZGF0YV90c2t1IDwtIG1lYXN1cmVkX3Rlc3RfdHJpYWxzIHw+CiAgZ3JvdXBfYnkocGFydGljaXBhbnQsCiAgICAgICAgICAgYWNjdXJhY3lfbnVtZXJpYywKICAgICAgICAgICBrZXl0aW1lX251bWVyaWMsCiAgICAgICAgICAgc3VnZ2VzdGlvbnNfdHlwZSkgfD4KICBzdW1tYXJpemUoCiAgICBwX21lYW5fa3MgPSBtZWFuKCh0b3RhbF9maW5hbF9zdWdnZXN0aW9uX2NoYXJzIC8gdG90YWxfY2hhcnMpIC8gdGhlb3JldGljYWxfa2V5X3NhdmluZwogICksCiAgLmdyb3VwcyA9ICJkcm9wIikKCgpwbG90X2tleXN0cm9rZV9zYXZpbmdfcmF0aW8gPC0gZnVuY3Rpb24oZmlsdGVyZWRfcF9kYXRhX3Rza3UpIHsKICBhY3R1YWxfdHNrdV9kYXRhIDwtIGZpbHRlcmVkX3BfZGF0YV90c2t1IHw+CiAgICBncm91cF9ieShhY2N1cmFjeV9udW1lcmljLAogICAgICAgICAgICAga2V5dGltZV9udW1lcmljKSB8PgogICAgc3VtbWFyaXplKAogICAgICBlcnJvcl9rcyA9IHRfZXJyb3IocF9tZWFuX2tzKSwKICAgICAgbWVhbl9rcyA9IG1lYW4ocF9tZWFuX2tzKSwKICAgICAgbWluX2tzID0gbWF4KDAsIG1lYW5fa3MgLSBlcnJvcl9rcyksCiAgICAgIG1heF9rcyA9IG1pbigxLCBtZWFuX2tzICsgZXJyb3Jfa3MpLAogICAgICAuZ3JvdXBzID0gImRyb3AiCiAgICApCiAgdGhlb3JldGljYWxfdHNrdV9kYXRhIDwtIHRpYmJsZSgKICAgIGFjY3VyYWN5X251bWVyaWMgPSBBQ0NVUkFDWV9MRVZFTFNfTlVNLAogICAga2V5dGltZV9udW1lcmljID0gTkEsCiAgICBtZWFuX2tzID0gMS4wLAogICAgbWluX2tzID0gMS4wLAogICAgbWF4X2tzID0gMS4wCiAgKQogIHBkIDwtIHBvc2l0aW9uX2RvZGdlKDAuMDI1KQogIHBsb3Rfa2V5c3Ryb2tlX3NhdmluZ19yYXRpbyA8LSBnZ3Bsb3QoCiAgICBhY3R1YWxfdHNrdV9kYXRhLAogICAgYWVzKAogICAgICB4ID0gYWNjdXJhY3lfbnVtZXJpYywKICAgICAgeSA9IG1lYW5fa3MsCiAgICAgIHltaW4gPSBtaW5fa3MsCiAgICAgIHltYXggPSBtYXhfa3MsCiAgICAgIGNvbG9yID0ga2V5dGltZV9udW1lcmljLAogICAgICBncm91cCA9IGtleXRpbWVfbnVtZXJpYwogICAgKQogICkgKwogICAgY3VzdG9tX2xpbmUoZGF0YSA9IHRoZW9yZXRpY2FsX3Rza3VfZGF0YSwKICAgICAgICAgICAgICAgIGNvbG9yID0gVEhFT1JFVElDQUxfQ09MT1IsCiAgICAgICAgICAgICAgICBncm91cCA9ICJ0aGVvcmV0aWNhbCIpICsKICAgIGN1c3RvbV9wb2ludHJhbmdlKAogICAgICBkYXRhID0gdGhlb3JldGljYWxfdHNrdV9kYXRhLAogICAgICBjb2xvciA9IFRIRU9SRVRJQ0FMX0NPTE9SLAogICAgICBncm91cCA9ICJ0aGVvcmV0aWNhbCIsCiAgICAgIHNoYXBlID0gMTcKICAgICkgKwogICAgY3VzdG9tX2xpbmUocG9zaXRpb24gPSBwZCkgKwogICAgY3VzdG9tX3BvaW50cmFuZ2UocG9zaXRpb24gPSBwZCkgKwogICAgU0NBTEVfQ09MT1JfS0VZX1NUUk9LRSArCiAgICBTQ0FMRV9YX0FDQ1VSQUNZICsKICAgIHNjYWxlX3lfY29udGludW91cygiS2V5c3Ryb2tlIFNhdmluZyBSYXRpbyIsCiAgICAgICAgICAgICAgICAgICAgICAgbGltaXRzID0gYygwLCAxKSwKICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHMgPSBwZXJjZW50KSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgICBwYW5lbC5zcGFjaW5nID0gUEFORUxfTUFSR0lOLCApCn0KYGBgCgojIyBJbmxpbmUgc3VnZ2VzdGlvbnMKCmBgYHtyLCBkZXY9InN2Z2xpdGUifQppbmxpbmVfa3NfcmF0aW9fcGxvdCA8LQogIHBsb3Rfa2V5c3Ryb2tlX3NhdmluZ19yYXRpbyhwX2RhdGFfdHNrdSB8PiBmaWx0ZXIoc3VnZ2VzdGlvbnNfdHlwZSA9PSBJTkxJTkVfU1VHR0VTVElPTl9UWVBFKSkKCmdnc2F2ZSgKICBncmFwaF9wYXRoKCJrZXlzdHJva2Utc2F2aW5nLXJhdGlvLWlubGluZS5wZGYiKSwKICBwbG90ID0gaW5saW5lX2tzX3JhdGlvX3Bsb3QsCiAgdW5pdHMgPSAibW0iLAogIHdpZHRoID0gKEZVTExfV0lEVEggLSBIX0dSQVBIX01BUkdJTikgLyA0LAogIGhlaWdodCA9IChGVUxMX1dJRFRIIC0gSF9HUkFQSF9NQVJHSU4pIC8gNCwKICBkZXZpY2UgPSBjYWlyb19wZGYKKQoKaW5saW5lX2tzX3JhdGlvX3Bsb3QKYGBgCgojIyBCYXIgc3VnZ2VzdGlvbnMKCmBgYHtyLCBkZXY9InN2Z2xpdGUifQpiYXJfa3NfcmF0aW9fcGxvdCA8LQogIHBsb3Rfa2V5c3Ryb2tlX3NhdmluZ19yYXRpbyhwX2RhdGFfdHNrdSB8PiBmaWx0ZXIoc3VnZ2VzdGlvbnNfdHlwZSA9PSBCQVJfU1VHR0VTVElPTl9UWVBFKSkKCmdnc2F2ZSgKICBncmFwaF9wYXRoKCJrZXlzdHJva2Utc2F2aW5nLXJhdGlvLWJhci5wZGYiKSwKICBwbG90ID0gYmFyX2tzX3JhdGlvX3Bsb3QsCiAgdW5pdHMgPSAibW0iLAogIHdpZHRoID0gKEZVTExfV0lEVEggLSBIX0dSQVBIX01BUkdJTikgLyA0LAogIGhlaWdodCA9IChGVUxMX1dJRFRIIC0gSF9HUkFQSF9NQVJHSU4pIC8gNCwKICBkZXZpY2UgPSBjYWlyb19wZGYKKQoKYmFyX2tzX3JhdGlvX3Bsb3QKYGBgCgoKIyBUcmlhbCBEdXJhdGlvbgoKYGBge3IsIGRldj0ic3ZnbGl0ZSJ9CmFjdHVhbF9ncmFwaF9kYXRhIDwtIG1lYXN1cmVkX3Rlc3RfdHJpYWxzIHw+CiAgZ3JvdXBfYnkocGFydGljaXBhbnQsIGFjY3VyYWN5X251bWVyaWMsIGtleXRpbWVfbnVtZXJpYywgc3VnZ2VzdGlvbnNfdHlwZSkgfD4KICBzdW1tYXJpemUoCiAgICB2YWx1ZSA9IG1lYW4oZHVyYXRpb24pLAogICAgLmdyb3VwcyA9ICJkcm9wIgogICkgfD4KICBncm91cF9ieShhY2N1cmFjeV9udW1lcmljLCBrZXl0aW1lX251bWVyaWMsIHN1Z2dlc3Rpb25zX3R5cGUpIHw+CiAgc3VtbWFyaXplKAogICAgZXJyb3JfdmFsdWUgPSB0X2Vycm9yKHZhbHVlKSwKICAgIG1lYW5fdmFsdWUgPSBtZWFuKHZhbHVlKSwKICAgIG1pbl92YWx1ZSA9IG1heCgwLCBtZWFuX3ZhbHVlIC0gZXJyb3JfdmFsdWUpLAogICAgbWF4X3ZhbHVlID0gbWVhbl92YWx1ZSArIGVycm9yX3ZhbHVlLAogICAgLmdyb3VwcyA9ICJkcm9wIgogICkKcGQgPC0gcG9zaXRpb25fZG9kZ2UoMC4wMjUpCmdncGxvdChhY3R1YWxfZ3JhcGhfZGF0YSwgYWVzKAogICAgeCA9IGFjY3VyYWN5X251bWVyaWMsCiAgICB5ID0gbWVhbl92YWx1ZSwKICAgIHltaW4gPSBtaW5fdmFsdWUsCiAgICB5bWF4ID0gbWF4X3ZhbHVlLAogICAgY29sb3IgPSBrZXl0aW1lX251bWVyaWMsCiAgICBncm91cCA9IGtleXRpbWVfbnVtZXJpYwogICkpICsKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPWMoMCwgMC4xLCAwLjMsIDAuNSwgMC43LCAwLjksIDEpKSArCiAgc2NhbGVfY29sb3JfY29udGludW91cyhicmVha3M9YygwLCA1MCwgMTAwLCAyMDApKSArCiAgZXhwYW5kX2xpbWl0cyh5ID0gYygwKSkgKwogIGdlb21fbGluZShwb3NpdGlvbj1wZCkgKwogIGdlb21fcG9pbnRyYW5nZShwb3NpdGlvbj1wZCkgKwogIGZhY2V0X3dyYXAodmFycyhzdWdnZXN0aW9uc190eXBlKSkgKwogIGxhYnMoeD0iU3VnZ2VzdGlvbnMgQWNjdXJhY3kiLCB5PSJUcmlhbCBEdXJhdGlvbiAoc2Vjb25kcykiLCBjb2xvcj0iS2V5IFN0cm9rZSBEZWxheSIpCmBgYAoKCiMgRW50cnkgU3BlZWQKCmBgYHtyLCBkZXY9InN2Z2xpdGUifQpwX2RhdGFfdHMgPC0gbWVhc3VyZWRfdGVzdF90cmlhbHMgfD4KICBncm91cF9ieSgKICAgIHBhcnRpY2lwYW50LAogICAgYWNjdXJhY3ksCiAgICBrZXl0aW1lLAogICAgYWNjdXJhY3lfbnVtZXJpYywKICAgIGtleXRpbWVfbnVtZXJpYywKICAgIHN1Z2dlc3Rpb25zX2xhYmVsLAogICAgc3VnZ2VzdGlvbnNfdHlwZQogICkgfD4KICBzdW1tYXJpemUoc3BlZWQgPSBtZWFuKGNwcyAqIDYwIC8gNSksIC5ncm91cHMgPSAiZHJvcCIpIHw+CiAgZ3JvdXBfYnkoYWNjdXJhY3ksIGtleXRpbWUpCgpwbG90X2VudHJ5X3NwZWVkIDwtIGZ1bmN0aW9uKGZpbHRlcmVkX3BfZGF0YV90cykgewogIHN1bW1hcnlfdHMgPC0gZmlsdGVyZWRfcF9kYXRhX3RzIHw+CiAgICBncm91cF9ieShhY2N1cmFjeV9udW1lcmljLAogICAgICAgICAgICAga2V5dGltZV9udW1lcmljLAogICAgICAgICAgICAgc3VnZ2VzdGlvbnNfbGFiZWwpIHw+CiAgICBzdW1tYXJpemUoCiAgICAgIGVycm9yX3ZhbHVlID0gdF9lcnJvcihzcGVlZCksCiAgICAgIG1lYW5fdmFsdWUgPSBtZWFuKHNwZWVkKSwKICAgICAgbWluX3ZhbHVlID0gbWF4KDAsIG1lYW5fdmFsdWUgLSBlcnJvcl92YWx1ZSksCiAgICAgIG1heF92YWx1ZSA9IG1lYW5fdmFsdWUgKyBlcnJvcl92YWx1ZSwKICAgICAgLmdyb3VwcyA9ICJkcm9wIgogICAgKQogIAogIHBkIDwtIHBvc2l0aW9uX2RvZGdlKDAuMDI1KQogIHBsb3RfZW50cnlfc3BlZWQgPC0gZ2dwbG90KAogICAgc3VtbWFyeV90cywKICAgIGFlcygKICAgICAgeCA9IGFjY3VyYWN5X251bWVyaWMsCiAgICAgIHkgPSBtZWFuX3ZhbHVlLAogICAgICB5bWluID0gbWluX3ZhbHVlLAogICAgICB5bWF4ID0gbWF4X3ZhbHVlLAogICAgICBjb2xvciA9IGtleXRpbWVfbnVtZXJpYywKICAgICAgZ3JvdXAgPSBrZXl0aW1lX251bWVyaWMKICAgICkKICApICsKICAgIFNDQUxFX1hfQUNDVVJBQ1kgKwogICAgU0NBTEVfQ09MT1JfS0VZX1NUUk9LRSArCiAgICBleHBhbmRfbGltaXRzKHkgPSBjKDApKSArCiAgICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzID0gc2VxKDAsIDgwLCAxMCksIGxhYmVscyA9IHBhc3RlKHNlcSgwLCA4MCwgMTApLCAid3BtIikpICsKICAgIGN1c3RvbV9saW5lKHBvc2l0aW9uID0gcGQpICsKICAgIGN1c3RvbV9wb2ludHJhbmdlKHBvc2l0aW9uID0gcGQpICsKICAgIGxhYnMoeSA9ICJFbnRyeSBTcGVlZCIpICsKICAgIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPSBsaXN0KGxpbmV0eXBlID0gMCkpKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgICBwYW5lbC5zcGFjaW5nID0gUEFORUxfTUFSR0lOKQp9CmBgYAoKCiMjIFN1bW1hcmllcwoKIyMjIEdsb2JhbAoKYGBge3J9CnBfZGF0YV90cyB8PgogIGdyb3VwX2J5KHN1Z2dlc3Rpb25zX3R5cGUpIHw+CiAgc3VtbWFyaXplKAogICAgc2Rfc3BlZWQgPSBzZChzcGVlZCksCiAgICBtZWFuX3NwZWVkID0gbWVhbihzcGVlZCksCiAgICAuZ3JvdXBzID0gImRyb3AiCiAgKQpgYGAKIyMjIFBlciBjb25kaXRpb25zCgpgYGB7cn0KcF9kYXRhX3RzIHw+CiAgZ3JvdXBfYnkoc3VnZ2VzdGlvbnNfdHlwZSwgYWNjdXJhY3ksIGtleXRpbWUpIHw+CiAgc3VtbWFyaXplKAogICAgc2Rfc3BlZWQgPSBzZChzcGVlZCksCiAgICBtZWFuX3NwZWVkID0gbWVhbihzcGVlZCksCiAgICAuZ3JvdXBzID0gImRyb3AiCiAgKQpgYGAKIyMjIFBlciBrZXl0aW1lCgpgYGB7cn0KcF9kYXRhX3RzIHw+CiAgZ3JvdXBfYnkoc3VnZ2VzdGlvbnNfdHlwZSwga2V5dGltZSkgfD4KICBzdW1tYXJpemUoCiAgICBzZF9zcGVlZCA9IHNkKHNwZWVkKSwKICAgIG1lYW5fc3BlZWQgPSBtZWFuKHNwZWVkKSwKICAgIC5ncm91cHMgPSAiZHJvcCIKICApCmBgYAoKIyMjIFBlciBhY2N1cmF5CgpgYGB7cn0KcF9kYXRhX3RzIHw+CiAgZ3JvdXBfYnkoc3VnZ2VzdGlvbnNfdHlwZSwgYWNjdXJhY3kpIHw+CiAgc3VtbWFyaXplKAogICAgc2Rfc3BlZWQgPSBzZChzcGVlZCksCiAgICBtZWFuX3NwZWVkID0gbWVhbihzcGVlZCksCiAgICAuZ3JvdXBzID0gImRyb3AiCiAgKQpgYGAKCgojIyBJbmxpbmUgU3VnZ2VzdGlvbnMKCmBgYHtyLCBkZXY9InN2Z2xpdGUifQpwX2RhdGFfdHNfaW5saW5lIDwtIHBfZGF0YV90cyB8PiBmaWx0ZXIoc3VnZ2VzdGlvbnNfdHlwZSA9PSBJTkxJTkVfU1VHR0VTVElPTl9UWVBFKQoKCmlubGluZV9lbnRyeV9zcGVlZF9wbG90IDwtIHBsb3RfZW50cnlfc3BlZWQocF9kYXRhX3RzX2lubGluZSkKCmdnc2F2ZSgKICBncmFwaF9wYXRoKCJlbnRyeS1zcGVlZC1pbmxpbmUucGRmIiksCiAgcGxvdCA9IGlubGluZV9lbnRyeV9zcGVlZF9wbG90LAogIHVuaXRzID0gIm1tIiwKICB3aWR0aCA9IChGVUxMX1dJRFRIIC0gSF9HUkFQSF9NQVJHSU4pIC8gNCArIDEsCiAgaGVpZ2h0ID0gKEZVTExfV0lEVEggLSBIX0dSQVBIX01BUkdJTikgLyA0LAogIGRldmljZSA9IGNhaXJvX3BkZgopCgppbmxpbmVfZW50cnlfc3BlZWRfcGxvdApgYGAKCiMjIyBOb3JtYWxpdHkgYW5kIEhvbW9nZW5laXR5CgpgYGB7ciwgZGV2PSJzdmdsaXRlIn0KZ2dwbG90KHBfZGF0YV90c19pbmxpbmUsIGFlcyh4ID0gc3BlZWQpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAyKSArCiAgZmFjZXRfZ3JpZChyb3dzPXZhcnMoYWNjdXJhY3kpLCBjb2xzID0gdmFycyhrZXl0aW1lKSkKYGBgCgpgYGB7ciwgZGV2PSJzdmdsaXRlIn0KbSA8LSBhb3Yoc3BlZWQgfiBrZXl0aW1lKmFjY3VyYWN5LCBkYXRhPXBfZGF0YV90c19pbmxpbmUpCnBhbmRlcihub3JtYWxDaGVjayhtKSkKcmVtb3ZlKG0pCmBgYAoKTm90IG5vcm1hbC4KCiMjIyBEZXRlcm1pbmUgYm94Y294IHRyYW5zZm9ybSBsYW1iZGEKCmBgYHtyLCBkZXY9InN2Z2xpdGUifQpib3hjb3goc3BlZWR+a2V5dGltZSphY2N1cmFjeSwgZGF0YT1wX2RhdGFfdHNfaW5saW5lKQpgYGAKCgpgYGB7ciwgZGV2PSJzdmdsaXRlIn0KbGFtYmRhIDwtIDAuMTUKbSA8LSBhb3Yoc3BlZWQgXmxhbWJkYSAgfiBrZXl0aW1lKmFjY3VyYWN5LCBkYXRhPXBfZGF0YV90c19pbmxpbmUpCnBhbmRlcihub3JtYWxDaGVjayhtKSkKcmVtb3ZlKG0pCmBgYAoKQ291bGQgbm90IG5vcm1hbGl6ZSBpdC4gU3dpdGNoIHRvIEFSVC4KCgojIyMgQVJUCgpgYGB7ciwgZGV2PSJzdmdsaXRlIn0KbV90cyA9IGFydChzcGVlZCB+IGtleXRpbWUgKiBhY2N1cmFjeSwgZGF0YT1wX2RhdGFfdHNfaW5saW5lKQphbm92YShtX3RzLCB0eXBlID0gMikKYGBgCgpgYGB7ciwgZGV2PSJzdmdsaXRlIn0KZW1tZWFucyhhcnRsbShtX3RzLCAia2V5dGltZSIpLCBwYWlyd2lzZSB+IGtleXRpbWUpCmBgYAoKYGBge3IsIGRldj0ic3ZnbGl0ZSJ9CmVtbWVhbnMoYXJ0bG0obV90cywgImFjY3VyYWN5IiksIHBhaXJ3aXNlIH4gYWNjdXJhY3kpCmBgYAoKCiMjIEJhciBTdWdnZXN0aW9ucwoKYGBge3IsIGRldj0ic3ZnbGl0ZSJ9CnBfZGF0YV90c19iYXIgPC0gcF9kYXRhX3RzIHw+IGZpbHRlcihzdWdnZXN0aW9uc190eXBlID09IEJBUl9TVUdHRVNUSU9OX1RZUEUpCnBfZGF0YV90c19iYXJfY29tbW9uX2ZhY3RvcnMgPC0gcF9kYXRhX3RzX2JhcgoKCmJhcl9lbnRyeV9zcGVlZF9wbG90IDwtIHBsb3RfZW50cnlfc3BlZWQocF9kYXRhX3RzX2JhcikKCmdnc2F2ZSgKICBncmFwaF9wYXRoKCJlbnRyeS1zcGVlZC1iYXIucGRmIiksCiAgcGxvdCA9IGJhcl9lbnRyeV9zcGVlZF9wbG90LAogIHVuaXRzID0gIm1tIiwKICB3aWR0aCA9IChGVUxMX1dJRFRIIC0gSF9HUkFQSF9NQVJHSU4pIC8gNCArIDEsCiAgaGVpZ2h0ID0gKEZVTExfV0lEVEggLSBIX0dSQVBIX01BUkdJTikgLyA0LAogIGRldmljZSA9IGNhaXJvX3BkZgopCgpiYXJfZW50cnlfc3BlZWRfcGxvdApgYGAKCiMjIyBOb3JtYWxpdHkgYW5kIEhvbW9nZW5laXR5CgpgYGB7ciwgZGV2PSJzdmdsaXRlIn0KZ2dwbG90KHBfZGF0YV90c19iYXJfY29tbW9uX2ZhY3RvcnMsIGFlcyh4ID0gc3BlZWQpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAyKSArCiAgZmFjZXRfZ3JpZChyb3dzPXZhcnMoYWNjdXJhY3kpLCBjb2xzID0gdmFycyhrZXl0aW1lKSkKYGBgCgpgYGB7ciwgZGV2PSJzdmdsaXRlIn0KbSA8LSBhb3Yoc3BlZWQgfiBrZXl0aW1lKmFjY3VyYWN5LCBkYXRhPXBfZGF0YV90c19iYXJfY29tbW9uX2ZhY3RvcnMpCnBhbmRlcihub3JtYWxDaGVjayhtKSkKcmVtb3ZlKG0pCmBgYAoKTm90IG5vcm1hbC4KCiMjIyBBUlQKCmBgYHtyLCBkZXY9InN2Z2xpdGUifQptX3RzX2JhciA9IGFydChzcGVlZCB+IGtleXRpbWUgKiBhY2N1cmFjeSwgZGF0YT1wX2RhdGFfdHNfYmFyX2NvbW1vbl9mYWN0b3JzKQphbm92YShtX3RzX2JhciwgdHlwZSA9IDIpCmBgYAoKYGBge3IsIGRldj0ic3ZnbGl0ZSJ9CmVtbWVhbnMoYXJ0bG0obV90c19iYXIsICJrZXl0aW1lIiksIHBhaXJ3aXNlIH4ga2V5dGltZSkKYGBgCgpgYGB7ciwgZGV2PSJzdmdsaXRlIn0KZW1tZWFucyhhcnRsbShtX3RzX2JhciwgImFjY3VyYWN5IiksIHBhaXJ3aXNlIH4gYWNjdXJhY3kpCmBgYAoKCiMjIElubGluZSB2cyBCYXIKCmBgYHtyfQpwX2RhdGFfdHMgfD4KICBncm91cF9ieShzdWdnZXN0aW9uc190eXBlKSB8PgogIHN1bW1hcml6ZSgKICAgIGVycm9yID0gdF9lcnJvcihzcGVlZCksCiAgICBtZWFuID0gbWVhbihzcGVlZCkpCmBgYAoKYGBge3J9Cm1fdHNfYm90aCA9IGFydChzcGVlZCB+IGtleXRpbWUgKiBhY2N1cmFjeSAqIHN1Z2dlc3Rpb25zX3R5cGUsIGRhdGE9cF9kYXRhX3RzKQphbm92YShtX3RzX2JvdGgsIHR5cGUgPSAyKQpgYGAKCmBgYHtyfQplbW1lYW5zKGFydGxtKG1fdHNfYm90aCwgInN1Z2dlc3Rpb25zX3R5cGUiKSwgcGFpcndpc2UgfiBzdWdnZXN0aW9uc190eXBlKQpgYGAKCiMgVG90YWwgUnVuIGR1cmF0aW9uCgoKYGBge3IsIGRldj0ic3ZnbGl0ZSJ9CmxpbmVfZ3JhcGggPC0KICBmdW5jdGlvbihjb21wbGV0ZWRfdHJpYWxzLAogICAgICAgICAgIG1lYXN1cmUsCiAgICAgICAgICAgbWluX3ZhbHVlID0gTkEsCiAgICAgICAgICAgbWF4X3ZhbHVlID0gTkEpIHsKICAgIGdyYXBoX2RhdGEgPC0gY29tcGxldGVkX3RyaWFscyB8PgogICAgICByZW5hbWUodmFsdWUgPSBtZWFzdXJlKSB8PgogICAgICBncm91cF9ieShwYXJ0aWNpcGFudCwgYWNjdXJhY3lfbnVtZXJpYywga2V5dGltZV9udW1lcmljLCBzdWdnZXN0aW9uc190eXBlKSB8PgogICAgICBzdW1tYXJpemUocF92YWx1ZSA9IG1lYW4odmFsdWUpLCAuZ3JvdXBzPSJkcm9wIikgfD4KICAgICAgZ3JvdXBfYnkoYWNjdXJhY3lfbnVtZXJpYywga2V5dGltZV9udW1lcmljLCBzdWdnZXN0aW9uc190eXBlKSB8PgogICAgICBzdW1tYXJpemUoCiAgICAgICAgZXJyb3JfdmFsdWUgPSB0X2Vycm9yKHBfdmFsdWUpLAogICAgICAgIG1lYW5fdmFsdWUgPSBtZWFuKHBfdmFsdWUpLAogICAgICAgIGNpX21pbiA9IGlmX2Vsc2UoCiAgICAgICAgICBpcy5uYShtaW5fdmFsdWUpLAogICAgICAgICAgbWVhbl92YWx1ZSAtIGVycm9yX3ZhbHVlLAogICAgICAgICAgbWF4KG1pbl92YWx1ZSwgbWVhbl92YWx1ZSAtIGVycm9yX3ZhbHVlKQogICAgICAgICksCiAgICAgICAgY2lfbWF4ID0gaWZfZWxzZSgKICAgICAgICAgIGlzLm5hKG1heF92YWx1ZSksCiAgICAgICAgICBtZWFuX3ZhbHVlICsgZXJyb3JfdmFsdWUsCiAgICAgICAgICBtaW4obWF4X3ZhbHVlLCBtZWFuX3ZhbHVlICsgZXJyb3JfdmFsdWUpCiAgICAgICAgKSwKICAgICAgICAuZ3JvdXBzID0gImRyb3AiCiAgICAgICkKICAgIGdncGxvdCgKICAgICAgZ3JhcGhfZGF0YSwKICAgICAgYWVzKAogICAgICAgIHggPSBhY2N1cmFjeV9udW1lcmljLAogICAgICAgIHkgPSBtZWFuX3ZhbHVlLAogICAgICAgIHltaW4gPSBjaV9taW4sCiAgICAgICAgeW1heCA9IGNpX21heCwKICAgICAgICBjb2xvciA9IGtleXRpbWVfbnVtZXJpYywKICAgICAgICBncm91cCA9IGtleXRpbWVfbnVtZXJpYwogICAgICApCiAgICApICsKICAgICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IEFDQ1VSQUNZX0xFVkVMU19OVU0pICsKICAgICAgc2NhbGVfY29sb3JfY29udGludW91cyhicmVha3MgPSBrZXl0aW1lX0xFVkVMU19OVU0pICsKICAgICAgZ2VvbV9saW5lKCkgKwogICAgICBnZW9tX3BvaW50cmFuZ2UoKQogIH0KCmxpbmVfZ3JhcGgobWVhc3VyZWRfcnVucyB8PiBtdXRhdGUobWludXRlcyA9IGR1cmF0aW9uIC8gNjApIHw+CiAgICAgICAgICAgICBmaWx0ZXIobWludXRlcyA8PSAxMjApLCAibWludXRlcyIpICsKICBmYWNldF93cmFwKHZhcnMoc3VnZ2VzdGlvbnNfdHlwZSkpICsKICB5bGFiKCJEdXJhdGlvbiAobWludXRlcykiKQpgYGAKCgojIExlYXJuaW5nCgoKYGBge3IsIGRldj0ic3ZnbGl0ZSJ9CnBfZGF0YV9rcyA8LSBtZWFzdXJlZF90ZXN0X3RyaWFscyB8PgogIGdyb3VwX2J5KHBhcnRpY2lwYW50LCBhY2N1cmFjeSwga2V5dGltZSwgYWNjdXJhY3lfbnVtZXJpYywga2V5dGltZV9udW1lcmljLCBzdWdnZXN0aW9uc190eXBlLCB0cmlhbF9udW1iZXIpIHw+CiAgc3VtbWFyaXplKAogICAgcF9tZWFuX2FjdHVhbF9rcyA9IG1lYW4oYWN0dWFsX2tleV9zYXZpbmdfbm9fZWRpdGluZyksCiAgICBwX21lYW5fdGhlb3JldGljYWxfa3MgPSBtZWFuKHRoZW9yZXRpY2FsX2tleV9zYXZpbmcpLAogICAgLmdyb3VwcyA9ICJkcm9wIgogICkgfD4KICBncm91cF9ieShhY2N1cmFjeSwga2V5dGltZSwgdHJpYWxfbnVtYmVyKSB8PgogIG11dGF0ZSgKICAgIGlzX291dGxpZXIgPSBpc19vdXRsaWVyKHBfbWVhbl9hY3R1YWxfa3MpCiAgKSB8PgogIHVuZ3JvdXAoKQoKYWN0dWFsX2tzX3N1bW1hcnkgPC0gcF9kYXRhX2tzIHw+CiAgZ3JvdXBfYnkoYWNjdXJhY3lfbnVtZXJpYywga2V5dGltZV9udW1lcmljLCBzdWdnZXN0aW9uc190eXBlLCB0cmlhbF9udW1iZXIpIHw+CiAgc3VtbWFyaXplKAogICAgZXJyb3Jfa3MgPSB0X2Vycm9yKHBfbWVhbl9hY3R1YWxfa3MpLAogICAgbWVhbl9rcyA9IG1lYW4ocF9tZWFuX2FjdHVhbF9rcyksCiAgICBtaW5fa3MgPSBtYXgoMCwgbWVhbl9rcyAtIGVycm9yX2tzKSwKICAgIG1heF9rcyA9IG1pbigxLCBtZWFuX2tzICsgZXJyb3Jfa3MpLAogICAga3NfdHlwZSA9ICJhY3R1YWwiLAogICAgLmdyb3VwcyA9ICJkcm9wIgogICkKCnRoZW9yZXRpY2FsX2tzX3N1bW1hcnkgPC0gcF9kYXRhX2tzIHw+CiAgZ3JvdXBfYnkoYWNjdXJhY3lfbnVtZXJpYywgc3VnZ2VzdGlvbnNfdHlwZSwgdHJpYWxfbnVtYmVyKSB8PgogIHN1bW1hcml6ZSgKICAgIGVycm9yX2tzID0gdF9lcnJvcihwX21lYW5fdGhlb3JldGljYWxfa3MpLAogICAgbWVhbl9rcyA9IG1lYW4ocF9tZWFuX3RoZW9yZXRpY2FsX2tzKSwKICAgIG1pbl9rcyA9IG1heCgwLCBtZWFuX2tzIC0gZXJyb3Jfa3MpLAogICAgbWF4X2tzID0gbWluKDEsIG1lYW5fa3MgKyBlcnJvcl9rcyksCiAgICBrc190eXBlID0gInRoZW9yZXRpY2FsIiwKICAgIGtleXRpbWVfbnVtZXJpYyA9IE5BLAogICAgLmdyb3VwcyA9ICJkcm9wIgogICkKICAKa3Nfc3VtbWFyeSA8LSB1bmlvbl9hbGwodGhlb3JldGljYWxfa3Nfc3VtbWFyeSwgYWN0dWFsX2tzX3N1bW1hcnkpCgpwZCA8LSBwb3NpdGlvbl9kb2RnZSgwLjAyNSkKcGxvdF9sZWFybmluZyA8LSBnZ3Bsb3Qoa3Nfc3VtbWFyeSwgYWVzKAogICAgeCA9IHRyaWFsX251bWJlciwKICAgIHkgPSBtZWFuX2tzLAogICAgeW1pbiA9IG1pbl9rcywKICAgIHltYXggPSBtYXhfa3MsCiAgICBjb2xvciA9IGtleXRpbWVfbnVtZXJpYywKICAgIGdyb3VwID0ga2V5dGltZV9udW1lcmljCiAgKSkgKwogIGN1c3RvbV9saW5lKAogICAgZGF0YT10aGVvcmV0aWNhbF9rc19zdW1tYXJ5LAogICAgY29sb3I9VEhFT1JFVElDQUxfQ09MT1IsCiAgICBncm91cD0idGhlb3JldGljYWwiCiAgKSArCiAgY3VzdG9tX3BvaW50cmFuZ2UoCiAgICBkYXRhPXRoZW9yZXRpY2FsX2tzX3N1bW1hcnksCiAgICBjb2xvcj1USEVPUkVUSUNBTF9DT0xPUiwKICAgIGdyb3VwPSJ0aGVvcmV0aWNhbCIsCiAgICBzaGFwZT0xNwogICkgKwogIGN1c3RvbV9saW5lKGRhdGE9YWN0dWFsX2tzX3N1bW1hcnksIHBvc2l0aW9uPXBkKSArCiAgY3VzdG9tX3BvaW50cmFuZ2UoZGF0YT1hY3R1YWxfa3Nfc3VtbWFyeSwgcG9zaXRpb249cGQpICsKICBTQ0FMRV9DT0xPUl9LRVlfU1RST0tFICsKICBzY2FsZV95X2NvbnRpbnVvdXMoIktleXN0cm9rZSBTYXZpbmciLCBsaW1pdHMgPSBjKDAsIDEpLCBsYWJlbHMgPSBwZXJjZW50KSArIAogIGZhY2V0X2dyaWQocm93cz12YXJzKHN1Z2dlc3Rpb25zX3R5cGUpLCBjb2xzPXZhcnMoYWNjdXJhY3lfbnVtZXJpYykpICsKICB0aGVtZSgKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgIHBhbmVsLnNwYWNpbmcgPSBQQU5FTF9NQVJHSU4KICAgICMgc3RyaXAudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLAogICAgIyBzdHJpcC5iYWNrZ3JvdW5kLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAjIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKQogICkKCmdnc2F2ZSgKICBncmFwaF9wYXRoKCJhbXQtbGVhcm5pbmcta2V5c3Ryb2tlLXNhdmluZy5wZGYiKSwKICBwbG90ID0gcGxvdF9sZWFybmluZywKICB1bml0cz0ibW0iLAogIHdpZHRoPTE1MCwKICBoZWlnaHQ9MTUwLAogIGRldmljZT1jYWlyb19wZGYKKQoKcGxvdF9sZWFybmluZwpgYGAKCgojIEV4cG9ydHMKCmBgYHtyLCBkZXY9InN2Z2xpdGUifQp0aGVtZV9tYXJnaW4gPC0gdGhlbWUocGxvdC5tYXJnaW4gPSBtYXJnaW4ociA9IDIsIGIgPSAyLCB1bml0ID0gIm1tIikpCgppbmxpbmVfcGxvdCA8LQogIChpbmxpbmVfcmVsaWFuY2VfcGxvdCArIHRoZW1lX21hcmdpbikgKyBpbmxpbmVfZW50cnlfc3BlZWRfcGxvdCArIGlubGluZV9rc19wbG90ICArIGlubGluZV9rc19yYXRpb19wbG90IAoKCmdnc2F2ZSgKICBncmFwaF9wYXRoKCJvYmplY3RpdmVfaW5saW5lLnBkZiIpLAogIHBsb3QgPSBpbmxpbmVfcGxvdCwKICB1bml0cyA9ICJtbSIsCiAgd2lkdGggPSBGVUxMX1dJRFRILAogIGhlaWdodCA9ICBGVUxMX1dJRFRIIC8gIEdPTERFTl9SQVRJTywKICBkZXZpY2UgPSBjYWlyb19wZGYKKQoKaW5saW5lX3Bsb3QKYGBgCmBgYHtyLCBkZXY9InN2Z2xpdGUifQpiYXJfcGxvdCA8LQogIChiYXJfcmVsaWFuY2VfcGxvdCArIHRoZW1lX21hcmdpbikgKyBiYXJfZW50cnlfc3BlZWRfcGxvdCArIGJhcl9rc19wbG90ICArIGJhcl9rc19yYXRpb19wbG90IAoKCmdnc2F2ZSgKICBncmFwaF9wYXRoKCJvYmplY3RpdmVfYmFyLnBkZiIpLAogIHBsb3QgPSBiYXJfcGxvdCwKICB1bml0cyA9ICJtbSIsCiAgd2lkdGggPSBGVUxMX1dJRFRILAogIGhlaWdodCA9ICBGVUxMX1dJRFRIIC8gIEdPTERFTl9SQVRJTywKICBkZXZpY2UgPSBjYWlyb19wZGYKKQoKYmFyX3Bsb3QKYGBgCgpbR28gYmFjayB0byBtYWluXSguL21haW4ubmIuaHRtbCkK