#Libraries and Packages

library(ggplot2)
library(dplyr)
library(stringr)
library(tidyr)
library(forcats)
library(nlme)
library(ggalluvial)
library(ordinal)
library(ggeffects)
library(ggplot2)
data=read.csv("deident_final_merged_data.csv")
data <- subset(data, !is.na(Treatment))

Did humor effect overall exam performance?

#Average score between Treatments, including Child.Course.ID as a random effect 
#Control group is the reference by default


model <- lme(
  Exam.Score ~ Treatment,
  random = ~1 | Child.Course.ID,
  data = data,
  na.action = na.omit
)

anova(model)
summary(model)
Linear mixed-effects model fit by REML
  Data: data 

Random effects:
 Formula: ~1 | Child.Course.ID
         (Intercept) Residual
StdDev: 0.0003621712 10.50213

Fixed effects:  Exam.Score ~ Treatment 
 Correlation: 
                            (Intr) TrtmNA TrtmnQ
TreatmentNonsensical Answer -0.715              
TreatmentQuestion           -0.719  0.515       
TreatmentValid Answer       -0.711  0.509  0.512

Standardized Within-Group Residuals:
       Min         Q1        Med         Q3        Max 
-4.0545487 -0.6853066  0.1350778  0.8014248  1.5770611 

Number of Observations: 170
Number of Groups: 4 

Did STAI score change in response to humor on exam?


stai <- lme(
  Post.STAI.score ~ Treatment,
  random = ~1 | Pre.STAI.score,
  data = data,
  na.action = na.omit
)

anova(stai)
summary(stai)
Linear mixed-effects model fit by REML
  Data: data 

Random effects:
 Formula: ~1 | Pre.STAI.score
        (Intercept) Residual
StdDev:    9.405543  14.0588

Fixed effects:  Post.STAI.score ~ Treatment 
 Correlation: 
                            (Intr) TrtmNA TrtmnQ
TreatmentNonsensical Answer -0.572              
TreatmentQuestion           -0.551  0.542       
TreatmentValid Answer       -0.575  0.541  0.545

Standardized Within-Group Residuals:
        Min          Q1         Med          Q3         Max 
-3.18541483 -0.50046122  0.03709113  0.68856269  1.99818647 

Number of Observations: 126
Number of Groups: 18 

Look for visual changes in anxiety. Pre.STAI.Cat –> Post.STAI.Cat


clean_data <- data %>%
  filter(
    !is.na(Pre.STAI.Cat),
    !is.na(Post.STAI.Cat),
    trimws(Pre.STAI.Cat) != "",
    trimws(Post.STAI.Cat) != "",
    !grepl("^[0-9]+$", Pre.STAI.Cat),
    !grepl("^[0-9]+$", Post.STAI.Cat)
  )

flow_data <- clean_data %>%
  count(Pre.STAI.Cat, Post.STAI.Cat) %>%
  group_by(Pre.STAI.Cat) %>%
  mutate(prop = n / sum(n))

ggplot(flow_data,
       aes(axis1 = Pre.STAI.Cat,
           axis2 = Post.STAI.Cat,
           y = n)) +
  geom_alluvium(aes(fill = Pre.STAI.Cat), width = 0.2) +
  geom_stratum(width = 0.2, fill = "grey80", color = "black") +
  geom_text(stat = "stratum", aes(label = after_stat(stratum))) +
  scale_x_discrete(limits = c("Pre", "Post"), expand = c(.1, .1)) +
    scale_fill_brewer(palette = "Set2") +
  labs(title = "Change in STAI Categories",
       y = "Count") +
  theme_minimal()



#give the proportion within each pre-category that is allocated to the post-category. So if the proportion is 0.70, then 70% went from high anxiety to high anxiety. And 18% went from high to moderate anxiety. 

flow_data


#run an ordinal linear regression, just in case


# Make ordered factors (IMPORTANT)
data$Pre.STAI.Cat  <- factor(data$Pre.STAI.Cat, ordered = TRUE)
data$Post.STAI.Cat <- factor(data$Post.STAI.Cat, ordered = TRUE)

model <- clmm(
  Post.STAI.Cat ~ Treatment  + (1 | Pre.STAI.Cat),
  data = data
)

summary(model)
Cumulative Link Mixed Model fitted with the Laplace approximation

formula: Post.STAI.Cat ~ Treatment + (1 | Pre.STAI.Cat)
data:    data

Random effects:
 Groups       Name        Variance  Std.Dev. 
 Pre.STAI.Cat (Intercept) 3.334e-09 5.774e-05
Number of groups:  Pre.STAI.Cat 4 

Coefficients:
                            Estimate Std. Error z value Pr(>|z|)
TreatmentNonsensical Answer   0.1150     0.4462   0.258    0.797
TreatmentQuestion            -0.4181     0.4607  -0.908    0.364
TreatmentValid Answer         0.2991     0.4576   0.654    0.513

Threshold coefficients:
                                   Estimate Std. Error z value
|2                                  -2.2369     0.4001  -5.590
2|High Anxiety                      -2.1647     0.3950  -5.481
High Anxiety|Moderate Anxiety        0.7114     0.3430   2.074
Moderate Anxiety|No or Low Anxiety   1.7379     0.3736   4.652
(19 observations deleted due to missingness)



model <- lme(
  Post.STAI.score ~ Treatment * Exam.Score,
  random = list(
    Pre.STAI.Cat = ~1,
    Child.Course.ID = ~1
  ),
  data = data,
  na.action = na.omit
)

anova(model)
summary(model)
Linear mixed-effects model fit by REML
  Data: data 

Random effects:
 Formula: ~1 | Pre.STAI.Cat
        (Intercept)
StdDev:    3.701099

 Formula: ~1 | Child.Course.ID %in% Pre.STAI.Cat
        (Intercept) Residual
StdDev:      1.6521 15.00977

Fixed effects:  Post.STAI.score ~ Treatment * Exam.Score 
 Correlation: 
                                       (Intr) TrtmNA TrtmnQ TrtmVA Exm.Sc TNA:E. TQ:E.S
TreatmentNonsensical Answer            -0.777                                          
TreatmentQuestion                      -0.707  0.566                                   
TreatmentValid Answer                  -0.703  0.562  0.510                            
Exam.Score                             -0.964  0.770  0.703  0.697                     
TreatmentNonsensical Answer:Exam.Score  0.769 -0.974 -0.562 -0.557 -0.799              
TreatmentQuestion:Exam.Score            0.695 -0.558 -0.978 -0.501 -0.723  0.579       
TreatmentValid Answer:Exam.Score        0.688 -0.553 -0.501 -0.977 -0.715  0.574  0.516

Standardized Within-Group Residuals:
        Min          Q1         Med          Q3         Max 
-3.30294310 -0.55813099 -0.04116798  0.66455128  2.08483132 

Number of Observations: 139
Number of Groups: 
                     Pre.STAI.Cat Child.Course.ID %in% Pre.STAI.Cat 
                                4                                16 
pred <- ggpredict(model, terms = c("Exam.Score", "Treatment"))

ggplot(pred, aes(x = x, y = predicted, color = group, fill = group)) +
  geom_line(linewidth = 1.2) +
  geom_ribbon(aes(ymin = conf.low, ymax = conf.high), alpha = 0.2, color = NA) +
  labs(
    x = "Exam Score",
    y = "Predicted Post STAI Score",
    color = "Treatment",
    fill = "Treatment"
  ) +
  theme_classic()



library(tidyr)
library(dplyr)


pre <- data %>%
  filter(
    !is.na(Treatment),
    !is.na(Pre.STAI.Cat),
    trimws(Treatment) != "",
    trimws(Pre.STAI.Cat) != "",
    tolower(trimws(Pre.STAI.Cat)) != "missing",
    !grepl("^\\d+$", trimws(Pre.STAI.Cat))   # removes numeric-only categories
  ) %>%
  count(Treatment, Category = Pre.STAI.Cat) %>%
  mutate(Time = "Pre")

post <- data %>%
  filter(
    !is.na(Treatment),
    !is.na(Post.STAI.Cat),
    trimws(Treatment) != "",
    trimws(Post.STAI.Cat) != "",
    tolower(trimws(Post.STAI.Cat)) != "missing",
    !grepl("^\\d+$", trimws(Post.STAI.Cat))  # removes numeric-only categories
  ) %>%
  count(Treatment, Category = Post.STAI.Cat) %>%
  mutate(Time = "Post")




ggplot(data, aes(x = Exam.Score)) +
  geom_histogram() +
  theme_classic() +
  labs(x = "Exam Score", y = "Count")

Less.Anxious Distracted Easy.to.understand Notice Less.stress.intim Interfered.Seriousness


allowed_levels <- c(
  "Strongly disagree",
  "Somewhat disagree",
  "Neither agree nor disagree",
  "Somewhat agree",
  "Strongly agree"
)

likert_cols <- c("Less.Anxious",
                 "Distracted",
                 "Easy.to.understand",
                 "Notice",
                 "Less.stress.intim",
                 "Interfered.Seriousness")

long_data <- data %>%
  select(all_of(c("Treatment", likert_cols))) %>%
  pivot_longer(
    cols = all_of(likert_cols),
    names_to = "Question",
    values_to = "Response"
  )


long_data <- long_data %>%
  mutate(
    Response = factor(Response, levels = allowed_levels, ordered = TRUE),
    Treatment = factor(Treatment)
  )


summary_data <- long_data %>%
  group_by(Question, Treatment, Response) %>%
  summarise(n = n(), .groups = "drop") %>%
  group_by(Question, Treatment) %>%
  mutate(prop = n / sum(n))



ggplot(summary_data, aes(x = Treatment, y = prop, fill = Response)) +
  geom_col(position = "fill", color = "black", size = 0.2) +   # stacked proportional bars
  facet_wrap(~ Question, ncol = 2) +
  scale_y_continuous(labels = scales::percent_format()) +
  scale_fill_brewer(palette = "RdYlBu", direction = -1) +      # reversed for agreement going blue
  labs(x = "Treatment", y = "Percentage", fill = "Likert Response",
       title = "Likert Responses by Treatment and Question") +
  theme_minimal(base_size = 14) +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1),
    legend.position = "bottom"
  )

NA
NA



# Step 1: Define Likert levels and question columns
allowed_levels <- c(
  "Strongly disagree",
  "Somewhat disagree",
  "Neither agree nor disagree",
  "Somewhat agree",
  "Strongly agree"
)

likert_cols <- c(
  "Less.Anxious",
  "Distracted",
  "Easy.to.understand",
  "Notice",
  "Less.stress.intim",
  "Interfered.Seriousness"
)

# Step 2: Filter invalid responses
clean_data <- data %>%
  filter(
    if_all(all_of(likert_cols), ~ .x %in% allowed_levels),
    !is.na(Treatment),
    Treatment != "Control"   # Remove Control treatment
  )

# Step 3: Reshape to long format
long_data <- clean_data %>%
  select(Treatment, all_of(likert_cols)) %>%
  pivot_longer(
    cols = all_of(likert_cols),
    names_to = "Question",
    values_to = "Response"
  )

# Step 4: Factor levels
long_data <- long_data %>%
  mutate(
    Response = factor(Response, levels = allowed_levels, ordered = TRUE),
    Treatment = factor(Treatment)
  )

# Step 5: Calculate proportions
summary_data <- long_data %>%
  group_by(Question, Treatment, Response) %>%
  summarise(n = n(), .groups = "drop") %>%
  group_by(Question, Treatment) %>%
  mutate(prop = n / sum(n))

# Step 6: Plot with labels inside bars
ggplot(summary_data, aes(x = Treatment, y = prop, fill = Response)) +
  geom_col(position = "fill", color = "black", size = 0.2) +
  
  # Add percentage labels only if >5% to avoid clutter
  geom_text(
    aes(label = ifelse(prop > 0.05, scales::percent(prop, accuracy = 1), "")),
    position = position_fill(vjust = 0.5),
    size = 3,
    color = "black"
  ) +
  
  facet_wrap(~ Question, ncol = 2) +
  scale_y_continuous(labels = scales::percent_format()) +
  scale_fill_brewer(palette = "RdYlBu", direction = -1) +
  labs(
    title = "Likert Responses by Treatment and Question",
    x = "Treatment",
    y = "Percentage",
    fill = "Likert Response"
  ) +
  theme_minimal(base_size = 14) +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1),
    legend.position = "bottom"
  )


question_labels <- c(
  "Less.Anxious" = "The humorous items helped me feel less anxious during the exam.",
  "Distracted" = "The humorous items distracted me from concentrating on the questions.",
  "Easy.to.understand" = "I found the humor in the test items easy to understand and appropriate for the class.",
  "Notice" = "I noticed that some questions had humorous wording or answer choices.",
  "Less.stress.intim" = "The humorous items made the exam feel less intimidating or stressful.",
  "Interfered.Seriousness" = "I felt that the humor interfered with how seriously I approached the test."
)
ggplot(summary_data, aes(x = Treatment, y = prop, fill = Response)) +
  geom_col(position = "fill", color = "black", size = 0.2) +
  geom_text(
    aes(label = ifelse(prop > 0.05, scales::percent(prop, accuracy = 1), "")),
    position = position_fill(vjust = 0.5),
    size = 3,
    color = "black"
  ) +
  facet_wrap(~ Question, ncol = 2, labeller = labeller(Question = question_labels)) +
  scale_y_continuous(labels = scales::percent_format()) +
  scale_fill_brewer(palette = "RdYlBu", direction = -1) +
  labs(
    title = "Likert Responses by Treatment and Question",
    x = "Treatment",
    y = "Percentage",
    fill = "Likert Response"
  ) +
  theme_minimal(base_size = 14) +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1),
    legend.position = "bottom"
  )

NA
NA
LS0tCnRpdGxlOiAiSHVtb3IgRGF0YSBBbmFseXNpcyIKYXV0aG9yOiAiQWJieSBCZWF0dHkiCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKCgojTGlicmFyaWVzIGFuZCBQYWNrYWdlcwpgYGB7ciwgbWVzc2FnZT1GLCB3YXJuaW5nPUZ9CmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShkcGx5cikKbGlicmFyeShzdHJpbmdyKQpsaWJyYXJ5KHRpZHlyKQpsaWJyYXJ5KGZvcmNhdHMpCmxpYnJhcnkobmxtZSkKbGlicmFyeShnZ2FsbHV2aWFsKQpsaWJyYXJ5KG9yZGluYWwpCmxpYnJhcnkoZ2dlZmZlY3RzKQpsaWJyYXJ5KGdncGxvdDIpCmBgYAoKCmBgYHtyLCBtZXNzYWdlPUYsIHdhcm5pbmc9Rn0KZGF0YT1yZWFkLmNzdigiZGVpZGVudF9maW5hbF9tZXJnZWRfZGF0YS5jc3YiKQpkYXRhIDwtIHN1YnNldChkYXRhLCAhaXMubmEoVHJlYXRtZW50KSkKYGBgCgojIyMgRGlkIGh1bW9yIGVmZmVjdCBvdmVyYWxsIGV4YW0gcGVyZm9ybWFuY2U/CmBgYHtyLCBtZXNzYWdlPUYsIHdhcm5pbmc9Rn0KI0F2ZXJhZ2Ugc2NvcmUgYmV0d2VlbiBUcmVhdG1lbnRzLCBpbmNsdWRpbmcgQ2hpbGQuQ291cnNlLklEIGFzIGEgcmFuZG9tIGVmZmVjdCAKI0NvbnRyb2wgZ3JvdXAgaXMgdGhlIHJlZmVyZW5jZSBieSBkZWZhdWx0CgoKbW9kZWwgPC0gbG1lKAogIEV4YW0uU2NvcmUgfiBUcmVhdG1lbnQsCiAgcmFuZG9tID0gfjEgfCBDaGlsZC5Db3Vyc2UuSUQsCiAgZGF0YSA9IGRhdGEsCiAgbmEuYWN0aW9uID0gbmEub21pdAopCgphbm92YShtb2RlbCkKc3VtbWFyeShtb2RlbCkKCmBgYAoKIyMjIERpZCBTVEFJIHNjb3JlIGNoYW5nZSBpbiByZXNwb25zZSB0byBodW1vciBvbiBleGFtPwoKYGBge3IsIG1lc3NhZ2U9Riwgd2FybmluZz1GfQoKc3RhaSA8LSBsbWUoCiAgUG9zdC5TVEFJLnNjb3JlIH4gVHJlYXRtZW50LAogIHJhbmRvbSA9IH4xIHwgUHJlLlNUQUkuc2NvcmUsCiAgZGF0YSA9IGRhdGEsCiAgbmEuYWN0aW9uID0gbmEub21pdAopCgphbm92YShzdGFpKQpzdW1tYXJ5KHN0YWkpCgoKCmBgYAojIyMgTG9vayBmb3IgdmlzdWFsIGNoYW5nZXMgaW4gYW54aWV0eS4gUHJlLlNUQUkuQ2F0IC0tPiBQb3N0LlNUQUkuQ2F0CgoKYGBge3IsIG1lc3NhZ2U9Riwgd2FybmluZz1GfQoKY2xlYW5fZGF0YSA8LSBkYXRhICU+JQogIGZpbHRlcigKICAgICFpcy5uYShQcmUuU1RBSS5DYXQpLAogICAgIWlzLm5hKFBvc3QuU1RBSS5DYXQpLAogICAgdHJpbXdzKFByZS5TVEFJLkNhdCkgIT0gIiIsCiAgICB0cmltd3MoUG9zdC5TVEFJLkNhdCkgIT0gIiIsCiAgICAhZ3JlcGwoIl5bMC05XSskIiwgUHJlLlNUQUkuQ2F0KSwKICAgICFncmVwbCgiXlswLTldKyQiLCBQb3N0LlNUQUkuQ2F0KQogICkKCmZsb3dfZGF0YSA8LSBjbGVhbl9kYXRhICU+JQogIGNvdW50KFByZS5TVEFJLkNhdCwgUG9zdC5TVEFJLkNhdCkgJT4lCiAgZ3JvdXBfYnkoUHJlLlNUQUkuQ2F0KSAlPiUKICBtdXRhdGUocHJvcCA9IG4gLyBzdW0obikpCgpnZ3Bsb3QoZmxvd19kYXRhLAogICAgICAgYWVzKGF4aXMxID0gUHJlLlNUQUkuQ2F0LAogICAgICAgICAgIGF4aXMyID0gUG9zdC5TVEFJLkNhdCwKICAgICAgICAgICB5ID0gbikpICsKICBnZW9tX2FsbHV2aXVtKGFlcyhmaWxsID0gUHJlLlNUQUkuQ2F0KSwgd2lkdGggPSAwLjIpICsKICBnZW9tX3N0cmF0dW0od2lkdGggPSAwLjIsIGZpbGwgPSAiZ3JleTgwIiwgY29sb3IgPSAiYmxhY2siKSArCiAgZ2VvbV90ZXh0KHN0YXQgPSAic3RyYXR1bSIsIGFlcyhsYWJlbCA9IGFmdGVyX3N0YXQoc3RyYXR1bSkpKSArCiAgc2NhbGVfeF9kaXNjcmV0ZShsaW1pdHMgPSBjKCJQcmUiLCAiUG9zdCIpLCBleHBhbmQgPSBjKC4xLCAuMSkpICsKICAgIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiU2V0MiIpICsKICBsYWJzKHRpdGxlID0gIkNoYW5nZSBpbiBTVEFJIENhdGVnb3JpZXMiLAogICAgICAgeSA9ICJDb3VudCIpICsKICB0aGVtZV9taW5pbWFsKCkKCgojZ2l2ZSB0aGUgcHJvcG9ydGlvbiB3aXRoaW4gZWFjaCBwcmUtY2F0ZWdvcnkgdGhhdCBpcyBhbGxvY2F0ZWQgdG8gdGhlIHBvc3QtY2F0ZWdvcnkuIFNvIGlmIHRoZSBwcm9wb3J0aW9uIGlzIDAuNzAsIHRoZW4gNzAlIHdlbnQgZnJvbSBoaWdoIGFueGlldHkgdG8gaGlnaCBhbnhpZXR5LiBBbmQgMTglIHdlbnQgZnJvbSBoaWdoIHRvIG1vZGVyYXRlIGFueGlldHkuIAoKZmxvd19kYXRhCgoKI3J1biBhbiBvcmRpbmFsIGxpbmVhciByZWdyZXNzaW9uLCBqdXN0IGluIGNhc2UKCgojIE1ha2Ugb3JkZXJlZCBmYWN0b3JzIChJTVBPUlRBTlQpCmRhdGEkUHJlLlNUQUkuQ2F0ICA8LSBmYWN0b3IoZGF0YSRQcmUuU1RBSS5DYXQsIG9yZGVyZWQgPSBUUlVFKQpkYXRhJFBvc3QuU1RBSS5DYXQgPC0gZmFjdG9yKGRhdGEkUG9zdC5TVEFJLkNhdCwgb3JkZXJlZCA9IFRSVUUpCgptb2RlbCA8LSBjbG1tKAogIFBvc3QuU1RBSS5DYXQgfiBUcmVhdG1lbnQgICsgKDEgfCBQcmUuU1RBSS5DYXQpLAogIGRhdGEgPSBkYXRhCikKCnN1bW1hcnkobW9kZWwpCmBgYAoKCmBgYHtyfQoKCgptb2RlbCA8LSBsbWUoCiAgUG9zdC5TVEFJLnNjb3JlIH4gVHJlYXRtZW50ICogRXhhbS5TY29yZSwKICByYW5kb20gPSBsaXN0KAogICAgUHJlLlNUQUkuQ2F0ID0gfjEsCiAgICBDaGlsZC5Db3Vyc2UuSUQgPSB+MQogICksCiAgZGF0YSA9IGRhdGEsCiAgbmEuYWN0aW9uID0gbmEub21pdAopCgphbm92YShtb2RlbCkKc3VtbWFyeShtb2RlbCkKCgpwcmVkIDwtIGdncHJlZGljdChtb2RlbCwgdGVybXMgPSBjKCJFeGFtLlNjb3JlIiwgIlRyZWF0bWVudCIpKQoKZ2dwbG90KHByZWQsIGFlcyh4ID0geCwgeSA9IHByZWRpY3RlZCwgY29sb3IgPSBncm91cCwgZmlsbCA9IGdyb3VwKSkgKwogIGdlb21fbGluZShsaW5ld2lkdGggPSAxLjIpICsKICBnZW9tX3JpYmJvbihhZXMoeW1pbiA9IGNvbmYubG93LCB5bWF4ID0gY29uZi5oaWdoKSwgYWxwaGEgPSAwLjIsIGNvbG9yID0gTkEpICsKICBsYWJzKAogICAgeCA9ICJFeGFtIFNjb3JlIiwKICAgIHkgPSAiUHJlZGljdGVkIFBvc3QgU1RBSSBTY29yZSIsCiAgICBjb2xvciA9ICJUcmVhdG1lbnQiLAogICAgZmlsbCA9ICJUcmVhdG1lbnQiCiAgKSArCiAgdGhlbWVfY2xhc3NpYygpCgoKbGlicmFyeSh0aWR5cikKbGlicmFyeShkcGx5cikKCgpwcmUgPC0gZGF0YSAlPiUKICBmaWx0ZXIoCiAgICAhaXMubmEoVHJlYXRtZW50KSwKICAgICFpcy5uYShQcmUuU1RBSS5DYXQpLAogICAgdHJpbXdzKFRyZWF0bWVudCkgIT0gIiIsCiAgICB0cmltd3MoUHJlLlNUQUkuQ2F0KSAhPSAiIiwKICAgIHRvbG93ZXIodHJpbXdzKFByZS5TVEFJLkNhdCkpICE9ICJtaXNzaW5nIiwKICAgICFncmVwbCgiXlxcZCskIiwgdHJpbXdzKFByZS5TVEFJLkNhdCkpICAgIyByZW1vdmVzIG51bWVyaWMtb25seSBjYXRlZ29yaWVzCiAgKSAlPiUKICBjb3VudChUcmVhdG1lbnQsIENhdGVnb3J5ID0gUHJlLlNUQUkuQ2F0KSAlPiUKICBtdXRhdGUoVGltZSA9ICJQcmUiKQoKcG9zdCA8LSBkYXRhICU+JQogIGZpbHRlcigKICAgICFpcy5uYShUcmVhdG1lbnQpLAogICAgIWlzLm5hKFBvc3QuU1RBSS5DYXQpLAogICAgdHJpbXdzKFRyZWF0bWVudCkgIT0gIiIsCiAgICB0cmltd3MoUG9zdC5TVEFJLkNhdCkgIT0gIiIsCiAgICB0b2xvd2VyKHRyaW13cyhQb3N0LlNUQUkuQ2F0KSkgIT0gIm1pc3NpbmciLAogICAgIWdyZXBsKCJeXFxkKyQiLCB0cmltd3MoUG9zdC5TVEFJLkNhdCkpICAjIHJlbW92ZXMgbnVtZXJpYy1vbmx5IGNhdGVnb3JpZXMKICApICU+JQogIGNvdW50KFRyZWF0bWVudCwgQ2F0ZWdvcnkgPSBQb3N0LlNUQUkuQ2F0KSAlPiUKICBtdXRhdGUoVGltZSA9ICJQb3N0IikKCgoKCmdncGxvdChkYXRhLCBhZXMoeCA9IEV4YW0uU2NvcmUpKSArCiAgZ2VvbV9oaXN0b2dyYW0oKSArCiAgdGhlbWVfY2xhc3NpYygpICsKICBsYWJzKHggPSAiRXhhbSBTY29yZSIsIHkgPSAiQ291bnQiKQpgYGAKCgoKTGVzcy5Bbnhpb3VzCkRpc3RyYWN0ZWQKRWFzeS50by51bmRlcnN0YW5kCk5vdGljZQpMZXNzLnN0cmVzcy5pbnRpbQpJbnRlcmZlcmVkLlNlcmlvdXNuZXNzCgoKYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGVjaG89VCwgZmlnLnNob3c9J2hpZGUnfQoKYWxsb3dlZF9sZXZlbHMgPC0gYygKICAiU3Ryb25nbHkgZGlzYWdyZWUiLAogICJTb21ld2hhdCBkaXNhZ3JlZSIsCiAgIk5laXRoZXIgYWdyZWUgbm9yIGRpc2FncmVlIiwKICAiU29tZXdoYXQgYWdyZWUiLAogICJTdHJvbmdseSBhZ3JlZSIKKQoKbGlrZXJ0X2NvbHMgPC0gYygiTGVzcy5Bbnhpb3VzIiwKICAgICAgICAgICAgICAgICAiRGlzdHJhY3RlZCIsCiAgICAgICAgICAgICAgICAgIkVhc3kudG8udW5kZXJzdGFuZCIsCiAgICAgICAgICAgICAgICAgIk5vdGljZSIsCiAgICAgICAgICAgICAgICAgIkxlc3Muc3RyZXNzLmludGltIiwKICAgICAgICAgICAgICAgICAiSW50ZXJmZXJlZC5TZXJpb3VzbmVzcyIpCgpsb25nX2RhdGEgPC0gZGF0YSAlPiUKICBzZWxlY3QoYWxsX29mKGMoIlRyZWF0bWVudCIsIGxpa2VydF9jb2xzKSkpICU+JQogIHBpdm90X2xvbmdlcigKICAgIGNvbHMgPSBhbGxfb2YobGlrZXJ0X2NvbHMpLAogICAgbmFtZXNfdG8gPSAiUXVlc3Rpb24iLAogICAgdmFsdWVzX3RvID0gIlJlc3BvbnNlIgogICkKCgpsb25nX2RhdGEgPC0gbG9uZ19kYXRhICU+JQogIG11dGF0ZSgKICAgIFJlc3BvbnNlID0gZmFjdG9yKFJlc3BvbnNlLCBsZXZlbHMgPSBhbGxvd2VkX2xldmVscywgb3JkZXJlZCA9IFRSVUUpLAogICAgVHJlYXRtZW50ID0gZmFjdG9yKFRyZWF0bWVudCkKICApCgoKc3VtbWFyeV9kYXRhIDwtIGxvbmdfZGF0YSAlPiUKICBncm91cF9ieShRdWVzdGlvbiwgVHJlYXRtZW50LCBSZXNwb25zZSkgJT4lCiAgc3VtbWFyaXNlKG4gPSBuKCksIC5ncm91cHMgPSAiZHJvcCIpICU+JQogIGdyb3VwX2J5KFF1ZXN0aW9uLCBUcmVhdG1lbnQpICU+JQogIG11dGF0ZShwcm9wID0gbiAvIHN1bShuKSkKCgoKZ2dwbG90KHN1bW1hcnlfZGF0YSwgYWVzKHggPSBUcmVhdG1lbnQsIHkgPSBwcm9wLCBmaWxsID0gUmVzcG9uc2UpKSArCiAgZ2VvbV9jb2wocG9zaXRpb24gPSAiZmlsbCIsIGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IDAuMikgKyAgICMgc3RhY2tlZCBwcm9wb3J0aW9uYWwgYmFycwogIGZhY2V0X3dyYXAofiBRdWVzdGlvbiwgbmNvbCA9IDIpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50X2Zvcm1hdCgpKSArCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJSZFlsQnUiLCBkaXJlY3Rpb24gPSAtMSkgKyAgICAgICMgcmV2ZXJzZWQgZm9yIGFncmVlbWVudCBnb2luZyBibHVlCiAgbGFicyh4ID0gIlRyZWF0bWVudCIsIHkgPSAiUGVyY2VudGFnZSIsIGZpbGwgPSAiTGlrZXJ0IFJlc3BvbnNlIiwKICAgICAgIHRpdGxlID0gIkxpa2VydCBSZXNwb25zZXMgYnkgVHJlYXRtZW50IGFuZCBRdWVzdGlvbiIpICsKICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDE0KSArCiAgdGhlbWUoCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpLAogICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIKICApCgoKYGBgCgoKYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGZpZy5zaG93PSdoaWRlJ30KCgoKIyBTdGVwIDE6IERlZmluZSBMaWtlcnQgbGV2ZWxzIGFuZCBxdWVzdGlvbiBjb2x1bW5zCmFsbG93ZWRfbGV2ZWxzIDwtIGMoCiAgIlN0cm9uZ2x5IGRpc2FncmVlIiwKICAiU29tZXdoYXQgZGlzYWdyZWUiLAogICJOZWl0aGVyIGFncmVlIG5vciBkaXNhZ3JlZSIsCiAgIlNvbWV3aGF0IGFncmVlIiwKICAiU3Ryb25nbHkgYWdyZWUiCikKCmxpa2VydF9jb2xzIDwtIGMoCiAgIkxlc3MuQW54aW91cyIsCiAgIkRpc3RyYWN0ZWQiLAogICJFYXN5LnRvLnVuZGVyc3RhbmQiLAogICJOb3RpY2UiLAogICJMZXNzLnN0cmVzcy5pbnRpbSIsCiAgIkludGVyZmVyZWQuU2VyaW91c25lc3MiCikKCiMgU3RlcCAyOiBGaWx0ZXIgaW52YWxpZCByZXNwb25zZXMKY2xlYW5fZGF0YSA8LSBkYXRhICU+JQogIGZpbHRlcigKICAgIGlmX2FsbChhbGxfb2YobGlrZXJ0X2NvbHMpLCB+IC54ICVpbiUgYWxsb3dlZF9sZXZlbHMpLAogICAgIWlzLm5hKFRyZWF0bWVudCksCiAgICBUcmVhdG1lbnQgIT0gIkNvbnRyb2wiICAgIyBSZW1vdmUgQ29udHJvbCB0cmVhdG1lbnQKICApCgojIFN0ZXAgMzogUmVzaGFwZSB0byBsb25nIGZvcm1hdApsb25nX2RhdGEgPC0gY2xlYW5fZGF0YSAlPiUKICBzZWxlY3QoVHJlYXRtZW50LCBhbGxfb2YobGlrZXJ0X2NvbHMpKSAlPiUKICBwaXZvdF9sb25nZXIoCiAgICBjb2xzID0gYWxsX29mKGxpa2VydF9jb2xzKSwKICAgIG5hbWVzX3RvID0gIlF1ZXN0aW9uIiwKICAgIHZhbHVlc190byA9ICJSZXNwb25zZSIKICApCgojIFN0ZXAgNDogRmFjdG9yIGxldmVscwpsb25nX2RhdGEgPC0gbG9uZ19kYXRhICU+JQogIG11dGF0ZSgKICAgIFJlc3BvbnNlID0gZmFjdG9yKFJlc3BvbnNlLCBsZXZlbHMgPSBhbGxvd2VkX2xldmVscywgb3JkZXJlZCA9IFRSVUUpLAogICAgVHJlYXRtZW50ID0gZmFjdG9yKFRyZWF0bWVudCkKICApCgojIFN0ZXAgNTogQ2FsY3VsYXRlIHByb3BvcnRpb25zCnN1bW1hcnlfZGF0YSA8LSBsb25nX2RhdGEgJT4lCiAgZ3JvdXBfYnkoUXVlc3Rpb24sIFRyZWF0bWVudCwgUmVzcG9uc2UpICU+JQogIHN1bW1hcmlzZShuID0gbigpLCAuZ3JvdXBzID0gImRyb3AiKSAlPiUKICBncm91cF9ieShRdWVzdGlvbiwgVHJlYXRtZW50KSAlPiUKICBtdXRhdGUocHJvcCA9IG4gLyBzdW0obikpCgojIFN0ZXAgNjogUGxvdCB3aXRoIGxhYmVscyBpbnNpZGUgYmFycwpnZ3Bsb3Qoc3VtbWFyeV9kYXRhLCBhZXMoeCA9IFRyZWF0bWVudCwgeSA9IHByb3AsIGZpbGwgPSBSZXNwb25zZSkpICsKICBnZW9tX2NvbChwb3NpdGlvbiA9ICJmaWxsIiwgY29sb3IgPSAiYmxhY2siLCBzaXplID0gMC4yKSArCiAgCiAgIyBBZGQgcGVyY2VudGFnZSBsYWJlbHMgb25seSBpZiA+NSUgdG8gYXZvaWQgY2x1dHRlcgogIGdlb21fdGV4dCgKICAgIGFlcyhsYWJlbCA9IGlmZWxzZShwcm9wID4gMC4wNSwgc2NhbGVzOjpwZXJjZW50KHByb3AsIGFjY3VyYWN5ID0gMSksICIiKSksCiAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2ZpbGwodmp1c3QgPSAwLjUpLAogICAgc2l6ZSA9IDMsCiAgICBjb2xvciA9ICJibGFjayIKICApICsKICAKICBmYWNldF93cmFwKH4gUXVlc3Rpb24sIG5jb2wgPSAyKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudF9mb3JtYXQoKSkgKwogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiUmRZbEJ1IiwgZGlyZWN0aW9uID0gLTEpICsKICBsYWJzKAogICAgdGl0bGUgPSAiTGlrZXJ0IFJlc3BvbnNlcyBieSBUcmVhdG1lbnQgYW5kIFF1ZXN0aW9uIiwKICAgIHggPSAiVHJlYXRtZW50IiwKICAgIHkgPSAiUGVyY2VudGFnZSIsCiAgICBmaWxsID0gIkxpa2VydCBSZXNwb25zZSIKICApICsKICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDE0KSArCiAgdGhlbWUoCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpLAogICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIKICApCgpxdWVzdGlvbl9sYWJlbHMgPC0gYygKICAiTGVzcy5Bbnhpb3VzIiA9ICJUaGUgaHVtb3JvdXMgaXRlbXMgaGVscGVkIG1lIGZlZWwgbGVzcyBhbnhpb3VzIGR1cmluZyB0aGUgZXhhbS4iLAogICJEaXN0cmFjdGVkIiA9ICJUaGUgaHVtb3JvdXMgaXRlbXMgZGlzdHJhY3RlZCBtZSBmcm9tIGNvbmNlbnRyYXRpbmcgb24gdGhlIHF1ZXN0aW9ucy4iLAogICJFYXN5LnRvLnVuZGVyc3RhbmQiID0gIkkgZm91bmQgdGhlIGh1bW9yIGluIHRoZSB0ZXN0IGl0ZW1zIGVhc3kgdG8gdW5kZXJzdGFuZCBhbmQgYXBwcm9wcmlhdGUgZm9yIHRoZSBjbGFzcy4iLAogICJOb3RpY2UiID0gIkkgbm90aWNlZCB0aGF0IHNvbWUgcXVlc3Rpb25zIGhhZCBodW1vcm91cyB3b3JkaW5nIG9yIGFuc3dlciBjaG9pY2VzLiIsCiAgIkxlc3Muc3RyZXNzLmludGltIiA9ICJUaGUgaHVtb3JvdXMgaXRlbXMgbWFkZSB0aGUgZXhhbSBmZWVsIGxlc3MgaW50aW1pZGF0aW5nIG9yIHN0cmVzc2Z1bC4iLAogICJJbnRlcmZlcmVkLlNlcmlvdXNuZXNzIiA9ICJJIGZlbHQgdGhhdCB0aGUgaHVtb3IgaW50ZXJmZXJlZCB3aXRoIGhvdyBzZXJpb3VzbHkgSSBhcHByb2FjaGVkIHRoZSB0ZXN0LiIKKQoKYGBgCgoKYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGZpZy53aWR0aD0xNCwgZmlnLmhlaWdodD0xNn0KZ2dwbG90KHN1bW1hcnlfZGF0YSwgYWVzKHggPSBUcmVhdG1lbnQsIHkgPSBwcm9wLCBmaWxsID0gUmVzcG9uc2UpKSArCiAgZ2VvbV9jb2wocG9zaXRpb24gPSAiZmlsbCIsIGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IDAuMikgKwogIGdlb21fdGV4dCgKICAgIGFlcyhsYWJlbCA9IGlmZWxzZShwcm9wID4gMC4wNSwgc2NhbGVzOjpwZXJjZW50KHByb3AsIGFjY3VyYWN5ID0gMSksICIiKSksCiAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2ZpbGwodmp1c3QgPSAwLjUpLAogICAgc2l6ZSA9IDMsCiAgICBjb2xvciA9ICJibGFjayIKICApICsKICBmYWNldF93cmFwKH4gUXVlc3Rpb24sIG5jb2wgPSAyLCBsYWJlbGxlciA9IGxhYmVsbGVyKFF1ZXN0aW9uID0gcXVlc3Rpb25fbGFiZWxzKSkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnRfZm9ybWF0KCkpICsKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlJkWWxCdSIsIGRpcmVjdGlvbiA9IC0xKSArCiAgbGFicygKICAgIHRpdGxlID0gIkxpa2VydCBSZXNwb25zZXMgYnkgVHJlYXRtZW50IGFuZCBRdWVzdGlvbiIsCiAgICB4ID0gIlRyZWF0bWVudCIsCiAgICB5ID0gIlBlcmNlbnRhZ2UiLAogICAgZmlsbCA9ICJMaWtlcnQgUmVzcG9uc2UiCiAgKSArCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxNCkgKwogIHRoZW1lKAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSwKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iCiAgKQoKCmBgYAo=