This notebook accompanies the manuscript:

Fink, Fiehn & Wald-Fuhrmann (2024). The role of audiovisual congruence in aesthetic appreciation of contemporary music and visual art. Scientific Reports, 71399. DOI: https://doi.org/10.1038/s41598-024-71399-y

Pre-print available at: osf.io/hjgc5/

If using any code or data from this notebook, please cite the paper.

Additional code and information accompanying this R notebook are available in the associated GitHub repository: https://github.com/lkfink/Kentler_MIM_Behavior

Load and preprocess data

Turn off warnings for cleaner submission file. N.B. users of this file should turn warnings on for troubleshooting

Install required packages, if not already installed

list.of.packages <- c("tidyverse", "ggpubr", "ez", "corrplot", "car", "stats","PerformanceAnalytics", "afex", "emmeans", "mlma", "ggplot2", "ggExtra", "psych", "ggpubr", "here", "gridExtra", "ggridges")
new.packages <- list.of.packages[!(list.of.packages %in% installed.packages()[,"Package"])]
if(length(new.packages)) install.packages(new.packages) 

Load packages and data

We use the here package so that all file paths are relative. Users should be sure not to change the directory structure of the repository. By default, figures will be plotted in line. If you want to save the figures to a folder on your local machine, set op = 1.

here::i_am("Fink_Kentler_analyses.Rmd")
library(here)
source(here("dependencies.R"))
data <- read.csv(here("data.csv")) 
fig_path <- here("figures/") # path to save generated figures to
op = 0 # flag if want to save output plots to files (1) or plot inline (0)

Pre-process the data

Clean up variable names, add combined columns of interest, drop unnecessary columns

# remove variables we don't need (Labvanced still outputting old vars from earlier exp. version)
data_new <- subset(data, select = - c(Block_Name, Task_Nr, aud_tend_unix, aud_ts, aud_ts_unix, condi3, copy_of_condi2, copy_of_condi, frame_end_unix, frame_rt, Name.Audio._copy_4b49, Name.Audio._copy_93a7, Name.Audio._copy_bd6f, Name.Audio._copy_c958, Name.Audio._copy_c96c, Name.Audio., subj_counter_global, subj_counter_per_group, time_delay_offset, time_measure_std, pixelDensityPerMM,unlocked))

# filter out people who have seen/heard stimuli before (some of our pilots) or who don't have normal hearing / vision
exposed = table(data$prev_exposure)
data_new <- data_new[-c(which(data_new$prev_exposure == "option_0")), ]
normSenses = table(data$Normal.Vision.) # no one without
data_new <- data_new[-c(which(data_new$completed == "no")), ] # remove incompletes
data = data_new # overwrite old data so can't accidentally use it

#create a dataframe just with the task block (for further analysis )
data_task <- data_new %>% 
  select(Trial_Nr, Trial_Id, correspondence_, enjoy_, Frame.Time., interestingness_, mood.congruency_, move_, subject_code, Block_Nr, group_name, exp_subject_id)

data_task <- data_task[, c("exp_subject_id", "Block_Nr", "Trial_Nr", "Trial_Id","group_name", "Frame.Time.", "correspondence_", "enjoy_", "interestingness_", "mood.congruency_", "move_" )]

# put time spent in secs (instead of ms)
data_task$Frame.Time. = data_task$Frame.Time. / 1000

# Add column for condition 
# Trial_Id tells which condition it is (1 - 4 = A; 5 - 8 = V; 9 - 12 = AVI; 13 - 16 = AVR)
# with Trial_Id and the group number we can look which specific stimuli are used 
data_task$Trial_Id = as.numeric(data_task$Trial_Id)
data_task$condition = NA
data_task$condition[data_task$Trial_Id <= 4] = 'Audio' 
data_task$condition[data_task$Trial_Id >= 5 & data_task$Trial_Id <= 8] = 'Visual' 
data_task$condition[data_task$Trial_Id >= 9 & data_task$Trial_Id <= 12] = 'AV-Intended' 
data_task$condition[data_task$Trial_Id >= 13] = 'AV-Random' 

# create subset data frame of task data
#just keep Block Number = 2 (these are the experimental trials)
data_task <- data_task %>%
  filter(Block_Nr == 2)

# create subset data frame with just participant info
data_participant <- data_new %>%
  select(exp_subject_id, group_name, age_input, gender, country_current, country_home, Modality_Preference, Ollen, overall_enjoy, "prev_exposure", realWorldLikelihood)

data_participant = na.omit(data_participant)

# calculate area scores for each participant and add to participant data
# AReA scale scoring
#Aesthetic Appreciation: Items 1, 2, 3, 4, 6, 9, 13, 14
#Intense Aesthetic Experience: Items 8, 11, 12, 13
#Creative Behavior: Items 5, 7, 10
area_data = data[data$Task_Name == 'AReA',]
area_data$area_aes_apprec = area_data$area_01 + area_data$area_02 + area_data$area_03 + area_data$area_04 + area_data$area_06 + area_data$area_09 + area_data$area_13 + area_data$area_14
area_data$area_aes_apprec = area_data$area_aes_apprec / 8 # divide by num of items
area_data$area_intense_aes_exp = area_data$area_08 + area_data$area_11 + area_data$area_12 + area_data$area_13
area_data$area_intense_aes_exp = area_data$area_intense_aes_exp / 4
area_data$area_creative_beh = area_data$area_05 + area_data$area_07 + area_data$area_10
area_data$area_creative_beh = area_data$area_creative_beh / 3
area_data$area_composite = (area_data$area_aes_apprec + area_data$area_intense_aes_exp + area_data$area_creative_beh) / 3

# add area scores to mean table (join based on exp_subj_id)
area_data = area_data[,c("exp_subject_id", "area_aes_apprec", "area_intense_aes_exp", "area_creative_beh", "area_composite")]

# merge area with participant df
data_participant = merge(x=data_participant,y=area_data, 
                         by="exp_subject_id", all=TRUE)

# clean up modality pref data to have meaningful labels
temp = data_participant$Modality_Preference
temp = gsub("option_0", "prefer_audio", temp)
temp = gsub("option_1", "prefer_visual", temp)
temp = gsub("option_2", "prefer_audiovisual", temp)
temp = gsub("option_3", "no_preference", temp)
data_participant$Modality_Preference_cat = temp

# join participant info with trial level data for final full data frame
full_data = merge(x=data_task,y=data_participant, 
                  by="exp_subject_id", all=TRUE)

Check participant number discrepencies between task data and demo data

# something wrong! only 195 obs for people who saw endQs ?! (these were required questions. not sure how labvanced let that through)
# table(data_new$Task_Name)

# check what going on with 6 subs
check = subset(full_data, is.na(full_data$Ollen))
check2 = subset(data, is.na(full_data$Ollen))

nsubs = length(unique(full_data$exp_subject_id))
nsubs_missingDemo = length(unique(check$exp_subject_id))

It seems 6 participants never got the ending questions. We can include them for all trial analyses but they will be excluded from person-level analyses

Person-level analyses

Explore demographic data

gender_dist = table(data_participant$gender)
age_mean = mean(data_participant$age_input, na.rm = TRUE)
age_std = sd(data_participant$age_input, na.rm = TRUE)
ncountries = length(unique(data_participant$country_current))
countries = table(data_participant$country_current)
modality_pref = table(data_participant$Modality_Preference_cat) 

print("Gender: man, woman, non-binary, prefer not to say")
[1] "Gender: man, woman, non-binary, prefer not to say"
print(gender_dist)

  0   1   2   3 
117  73   4   1 
print("Age (mean, sd, min, max)")
[1] "Age (mean, sd, min, max)"
print(age_mean)
[1] 31.01538
print(age_std)
[1] 11.81973
print(min(data_participant$age_input, na.rm = TRUE))
[1] 18
print(max(data_participant$age_input, na.rm = TRUE))
[1] 68
print("Unique countries:")
[1] "Unique countries:"
print(ncountries)
[1] 23
print(countries)

     Australia        Belgium         Canada          Chile Czech Republic        Ecuador 
             2              1              3              1              2              1 
       Germany         Greece        Hungary          India        Ireland          Italy 
             1              9              4              1              2             11 
        Mexico        Nigeria         Poland       Portugal   South Africa          Spain 
            12              2             23             34             15              9 
   Switzerland        Ukraine United Kingdom  United States 
             2              1             47             12 
print("AReA (mean, sd, min, max):")
[1] "AReA (mean, sd, min, max):"
print(mean(data_participant$area_composite))
[1] 2.62576
print(sd(data_participant$area_composite))
[1] 0.7410346
print(min(data_participant$area_composite))
[1] 1.125
print(max(data_participant$area_composite))
[1] 4.763889
print("AReA AA (mean, sd, min, max):")
[1] "AReA AA (mean, sd, min, max):"
print(mean(data_participant$area_aes_apprec))
[1] 3.439055
print(sd(data_participant$area_aes_apprec))
[1] 0.69193
print(min(data_participant$area_aes_apprec))
[1] 1.125
print(max(data_participant$area_aes_apprec))
[1] 5
print("AReA IAE (mean, sd, min, max):")
[1] "AReA IAE (mean, sd, min, max):"
print(mean(data_participant$area_intense_aes_exp))
[1] 2.461443
print(sd(data_participant$area_intense_aes_exp))
[1] 0.9202953
print(min(data_participant$area_intense_aes_exp))
[1] 1
print(max(data_participant$area_intense_aes_exp))
[1] 5
print("AReA CB (mean, sd, min, max):")
[1] "AReA CB (mean, sd, min, max):"
print(mean(data_participant$area_creative_beh))
[1] 1.976783
print(sd(data_participant$area_creative_beh))
[1] 0.9174315
print(min(data_participant$area_creative_beh))
[1] 1
print(max(data_participant$area_creative_beh))
[1] 5

Plot relationship between all person-level vars

# create data frame for correlation
# need to convert categorical to numeric 
corrdf = data_participant[ , which(names(data_participant) %in% c("Ollen", "Modality_Preference", "overall_enjoy", "realWorldLikelihood", "area_aes_apprec", "area_intense_aes_exp", "area_creative_beh", "area_composite"))] 

corrdf$Modality_Preference = as.numeric(as.factor(corrdf$Modality_Preference))
corrdf$Ollen = as.numeric(as.factor(corrdf$Ollen))

chart.Correlation(corrdf, histogram=TRUE, pch=25, text.panel=labs)

Condition-level analyses

Create tables of means

Z-score ratings data within scale, participant
Calculate table of means for all participants / conditions - do this for both z-scored and raw data in case we want to compare

# create zscore function
zscore <- function(input){
  out = (input - mean(input))/sd(input)
}

# zscore data
zscored = data_task %>%
  group_by(exp_subject_id) %>%
  mutate(z_enjoy = zscore(enjoy_), z_interesting = zscore(interestingness_), z_mood_cong = zscore(mood.congruency_), z_moved = zscore(move_))
# NOTE zscoring correspondence needs to be done only for AV conditions

# get means of zscored data
z_means = zscored %>%
  group_by(exp_subject_id, condition) %>%
  summarise(mean_timespent = mean(Frame.Time.), mean_enjoy = mean(z_enjoy), mean_interesting = mean(z_interesting), mean_mood_cong = mean(z_mood_cong), mean_moved = mean(z_moved))


# get means of zscored data
# z_means_participant = z_means %>%
#   group_by(exp_subject_id) %>%
#   summarise(mean_timespent = mean(mean_timespent), mean_enjoy = mean(mean_enjoy), mean_interesting = mean(mean_interesting), mean_mood_cong = mean(mean_mood_cong), mean_moved = mean(mean_moved))
# 

# get raw means in case want to compare to zscored data
means = data_task %>%
  group_by(exp_subject_id, condition) %>%
  summarise(mean_timespent = mean(Frame.Time.), mean_enjoy = mean(enjoy_), mean_interesting = mean(interestingness_), mean_mood_cong = mean(mood.congruency_), mean_moved = mean(move_), mean_corresp = mean(correspondence_))

# get raw sds in case want to compare to zscored data
sds = data_task %>%
  group_by(exp_subject_id, condition) %>%
  summarise(mean_timespent = sd(Frame.Time.), mean_enjoy = sd(enjoy_), mean_interesting = sd(interestingness_), mean_mood_cong = sd(mood.congruency_), mean_moved = sd(move_), mean_corresp = sd(correspondence_))

Create custom functions for analysis and plotting

We have multiple DVs on which we want to run the same type of analysis

# Function to plot violins for each condition
# Input: dataframe, variable to plot, title for plot
plotViolin = function(data, groupvar, var, titstr, xlab, ylab){
  
  # define colors
  AVR = '#8c1aff'
  AVI = '#cc99ff'
  V = '#ff4d4d'
  A = '#6699ff'
  ourcolors = c(A, AVI, AVR, V)
  
  # only AV conditions relevant
  if (var == "z_corresp"){
    ourcolors = c(AVI, AVR) 
  }
  
  # Plot
  var = sym(var)
  groupvar = sym(groupvar)

  pl = data %>%
    ggplot(aes(x=!!groupvar, y=!!var, fill=!!groupvar)) +
    geom_violin(legend = FALSE, trim = FALSE, adjust = 1, draw_quantiles = c(0.25, 0.75), size=.5, linetype = "dashed", color="black") + #.8 
    geom_violin(legend = FALSE, trim = FALSE, adjust = 1, draw_quantiles = 0.5, fill="transparent", size=.85, color="black") + #1.2
    
    geom_jitter(size=0.4, alpha=0.6, color="gray") +
    scale_fill_manual(values=ourcolors) +
    #theme_classic() +
    theme_ridges() +
    theme(
      legend.position="none",
      plot.title = element_text(size=11)
    ) +
    ggtitle(titstr) +
    xlab(xlab) +
    ylab(ylab)
  
  return(pl)
  
}



# Function to create density ridge plots for each condition
# Input: dataframe, variable to plot, title for plot
plotRidges = function(data, groupvar, var, titstr, xlab, ylab){
  
  # define colors
  AVR = '#CCBB44'
  AVI = '#228833'
  V = '#CC6677'
  A = '#88CCEE'
  ourcolors = c(A, AVI, AVR, V)
  
  # only AV conditions relevant
  if (var == "z_corresp"){
    ourcolors = c(AVI, AVR) 
  }
  
  # Plot
  var = sym(var)
  groupvar = sym(groupvar)

  pl = data %>%
    ggplot(aes(x=!!var, y=!!groupvar, fill=!!groupvar)) +
    
   # stat_density_ridges(quantile_lines=TRUE, quantiles = c(0.025, 0.975), color="black", alpha = 1) +
    
    geom_density_ridges(inherit.aes = TRUE, jittered_points = TRUE, stat ="density_ridges",
      position = position_points_jitter(width = 0.05, height = 0),
      point_shape = '|', point_size = 3, point_alpha = .9, alpha = 0.7) +
    
    geom_density_ridges(alpha = 0.85, quantile_lines=TRUE,
                        color="white", quantile_fun=function(var,...)mean(var)) +
    
    scale_fill_manual(values=ourcolors) +
    xlab(ylab) +
    theme_ridges() + theme(legend.position = "none") +
    theme(axis.title.x = element_text(hjust = 0.5)) + 
          theme(axis.title.y=element_blank())
  
  return(pl)
  
}


# Function to run rm anova and output stats
runaov = function(id, dv, data, w){
  fit = aov_ez(id,dv,data,within=w)
  print(fit)
  fit2 <- lsmeans(fit,specs = c(w))
  contrast(fit2,method="pairwise",adjust="holm")
}

# Conditions to compare after ANOVAs
my_comparisons <- list( c("Audio", "AV-Intended"), c("Audio", "AV-Random"), c("Audio", "Visual"), c("AV-Intended", "AV-Random"),  c("AV-Intended", "Visual"), c("AV-Random", "Visual"))
my_comparisons = rev(my_comparisons) # reverse order so more readable on plots

# Choose plotting style (violin or ridge) for future plots
customplot = plotRidges
hide_ns = FALSE

Time spent

How much time did participants spend experiencing the pieces in the different conditions? Did they spend more time in one condition vs. another?

z_means$logtime = log(z_means$mean_timespent)
p = customplot(z_means, "condition", "mean_timespent", "", "Condition", "Mean Time Spent (secs)")
plotTimeSecs = p + stat_compare_means(comparisons = my_comparisons, label = "p.signif", method = "t.test", paired = "true", na.rm=TRUE, hide.ns=hide_ns)

p = customplot(z_means, "condition", "logtime", "", "", "Mean Time Spent (log secs)")
plotTimeLog = p + stat_compare_means(comparisons = my_comparisons, label = "p.signif", method = "t.test", paired = "true", na.rm=TRUE, hide.ns=hide_ns)
z_means$exp_subject_id = as.factor(z_means$exp_subject_id)

runaov("exp_subject_id","mean_timespent", z_means, "condition")
Anova Table (Type 3 tests)

Response: mean_timespent
     Effect           df    MSE         F  ges p.value
1 condition 2.00, 400.21 237.00 96.93 *** .100   <.001
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘+’ 0.1 ‘ ’ 1

Sphericity correction method: GG 
 contrast                estimate    SE  df t.ratio p.value
 AV.Intended - AV.Random   -0.616 0.948 200  -0.650  0.5165
 AV.Intended - Audio       -4.908 0.800 200  -6.134  <.0001
 AV.Intended - Visual      15.067 1.469 200  10.256  <.0001
 AV.Random - Audio         -4.292 0.942 200  -4.554  <.0001
 AV.Random - Visual        15.683 1.514 200  10.361  <.0001
 Audio - Visual            19.975 1.600 200  12.481  <.0001

P value adjustment: holm method for 6 tests 
# print means and sds
cond_means = z_means %>%
  group_by(condition) %>%
  summarise(mean_timespent = mean(mean_timespent, na.rm=T))   

cond_sds = z_means %>%
  group_by(condition) %>%
  summarise(sd_timespent = sd(mean_timespent, na.rm=T))

print(cond_means)
print(cond_sds)

plotTimeSecs

plotTimeLog


plotTimeSecs = plotTimeSecs + labs(title = "Time Spent", tag = "A") + theme(plot.title = element_text(hjust = 0.5, face='bold'), plot.tag = element_text(face='bold'))

We find a main effect of condition. Post-hoc tests show significant differences between all conditions, except AVI and AVR. Results do not change whether we use raw mean time spent or log of it.

Enjoyment

Did enjoyment differ by condition? (Q to participants: I enjoyed the piece (0-100))

p = customplot(z_means, "condition", "mean_enjoy", "", "Condition", "Mean Enjoyment (z-score)")
plotEnjoy = p + stat_compare_means(comparisons = my_comparisons, label = "p.signif", method = "t.test", paired = "true", na.rm=TRUE, hide.ns=hide_ns)
runaov("exp_subject_id","mean_enjoy", z_means, "condition")
Anova Table (Type 3 tests)

Response: mean_enjoy
     Effect           df  MSE         F  ges p.value
1 condition 2.76, 552.98 0.33 13.83 *** .065   <.001
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘+’ 0.1 ‘ ’ 1

Sphericity correction method: GG 
 contrast                estimate     SE  df t.ratio p.value
 AV.Intended - AV.Random -0.01486 0.0484 200  -0.307  1.0000
 AV.Intended - Audio      0.28382 0.0524 200   5.416  <.0001
 AV.Intended - Visual    -0.00333 0.0544 200  -0.061  1.0000
 AV.Random - Audio        0.29869 0.0546 200   5.475  <.0001
 AV.Random - Visual       0.01154 0.0544 200   0.212  1.0000
 Audio - Visual          -0.28715 0.0654 200  -4.388  0.0001

P value adjustment: holm method for 6 tests 
plotEnjoy

plotEnjoy = plotEnjoy + labs(title = "Enjoyment", tag = "C") + theme(plot.title = element_text(hjust = 0.5, face='bold'), plot.tag = element_text(face='bold'))

There is a significant main effect of condition on Enjoyment. Post-hoc contrasts show that AVI and AVR are higher in enjoyment than A, but not V, or each other. (V is also higher than A) So, even though people spent more time with audio, they enjoy more with visual.

Interestingness

Did interestingness differ by condition? (Q to participants: I found the piece interesting (0-100))

p = customplot(z_means, "condition", "mean_interesting", "", "Condition", "Mean Interestingness (z-score)")
plotInterest = p + stat_compare_means(comparisons = my_comparisons, label = "p.signif", method = "t.test", paired = "true", na.rm=TRUE, hide.ns=hide_ns)
runaov("exp_subject_id","mean_interesting", z_means, "condition")
Anova Table (Type 3 tests)

Response: mean_interesting
     Effect           df  MSE         F  ges p.value
1 condition 2.65, 526.68 0.35 13.06 *** .062   <.001
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘+’ 0.1 ‘ ’ 1

Sphericity correction method: GG 
 contrast                estimate     SE  df t.ratio p.value
 AV.Intended - AV.Random  -0.0412 0.0460 199  -0.897  0.5345
 AV.Intended - Audio       0.2781 0.0530 199   5.249  <.0001
 AV.Intended - Visual      0.0637 0.0573 199   1.112  0.5345
 AV.Random - Audio         0.3193 0.0537 199   5.943  <.0001
 AV.Random - Visual        0.1050 0.0532 199   1.973  0.1496
 Audio - Visual           -0.2144 0.0680 199  -3.154  0.0075

P value adjustment: holm method for 6 tests 
plotInterest

plotInterest = plotInterest + labs(title = "Interestingness", tag = "D") + theme(plot.title = element_text(hjust = 0.5, face='bold'), plot.tag = element_text(face='bold'))

These interestingness results are basically identical to the ones above for enjoyment.

Mood Congruency

Did participants feel the piece matched their current mood more in certain conditions? (Q to participants: The piece matched my current mood (0-100))

p = customplot(z_means, "condition", "mean_mood_cong", "", "Condition", "Mean Mood Congruency (z-score)")
plotMood = p + stat_compare_means(comparisons = my_comparisons, label = "p.signif", method = "t.test", paired = "true", na.rm=TRUE, hide.ns=hide_ns)
runaov("exp_subject_id","mean_mood_cong", z_means, "condition")
Anova Table (Type 3 tests)

Response: mean_mood_cong
     Effect           df  MSE      F  ges p.value
1 condition 2.84, 564.37 0.30 3.61 * .018    .015
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘+’ 0.1 ‘ ’ 1

Sphericity correction method: GG 
 contrast                estimate     SE  df t.ratio p.value
 AV.Intended - AV.Random  -0.0256 0.0454 199  -0.563  0.5910
 AV.Intended - Audio       0.0896 0.0526 199   1.703  0.3607
 AV.Intended - Visual     -0.0827 0.0540 199  -1.533  0.3809
 AV.Random - Audio         0.1152 0.0519 199   2.219  0.1380
 AV.Random - Visual       -0.0571 0.0545 199  -1.049  0.5910
 Audio - Visual           -0.1723 0.0609 199  -2.831  0.0307

P value adjustment: holm method for 6 tests 
plotMood

plotMood = plotMood + labs(title = "Mood Congruency", tag = "E") + theme(plot.title = element_text(hjust = 0.5, face='bold'), plot.tag = element_text(face='bold'))

There is a significant main effect of condition with repect to whether people think the piece matches their current mood. Post-hoc contrasts show that people are significantly more likely to say the piece matches their mood in V vs. A conditions. But no other post-hoc contrasts were significant.

Feeling moved

Did participants feel moved by the piece more in certain conditions? (Q to participants: The piece moved me (0-100))

p = customplot(z_means, "condition", "mean_moved", "", "Condition", "Mean Feeling Moved (z-score)")
runaov("exp_subject_id","mean_moved", z_means, "condition")
Anova Table (Type 3 tests)

Response: mean_moved
     Effect           df  MSE        F  ges p.value
1 condition 2.83, 561.24 0.30 9.12 *** .044   <.001
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘+’ 0.1 ‘ ’ 1

Sphericity correction method: GG 
 contrast                estimate     SE  df t.ratio p.value
 AV.Intended - AV.Random  -0.0265 0.0453 198  -0.584  1.0000
 AV.Intended - Audio       0.1667 0.0539 198   3.092  0.0068
 AV.Intended - Visual      0.1987 0.0544 198   3.651  0.0013
 AV.Random - Audio         0.1932 0.0520 198   3.714  0.0013
 AV.Random - Visual        0.2252 0.0535 198   4.209  0.0002
 Audio - Visual            0.0320 0.0611 198   0.523  1.0000

P value adjustment: holm method for 6 tests 
plotMoved = p + stat_compare_means(comparisons = my_comparisons, label = "p.signif", method = "t.test", paired = "true", na.rm=TRUE, hide.ns=hide_ns)
plotMoved

plotMoved = plotMoved + labs(title = "Feeling Moved", tag = "F") + theme(plot.title = element_text(hjust = 0.5, face='bold'), plot.tag = element_text(face='bold'))

Significant main effect of condition on feeling moved. Post-hoc tests shows no significant differences in feeling moved between A vs. V or between AVI vs. AVR, but all other contrasts were significant. This is interesting and potentially a “load” effect (i.e., bimodal is generally more moving than uni-modal)

Audio-visual correspondence

Could participants tell above chance whether the audio and visual materials corresponded to one another? (Q to participants: To what degree did you feel there was a correspondence between the audio and visual sensations you were experiencing?)

# only zscore within relevant AV conditions
correspdata = data_task[data_task$condition == "AV-Intended" | data_task$condition == "AV-Random", ]
zscored_corresp = correspdata %>%
  group_by(exp_subject_id) %>%
  mutate(z_corresp = zscore(correspondence_)) 

mean_z_corresp = zscored_corresp %>%
  group_by(exp_subject_id, condition) %>%
  summarise(z_corresp = mean(z_corresp))

# plot and calculate stats
p <- customplot(mean_z_corresp, "condition", "z_corresp", "", "Condition", "Mean Correspondence (z-score)")
plotAVcorresp = p + stat_compare_means(comparisons = list(c("AV-Intended", "AV-Random")), label = "p.signif", method = "t.test", paired="true", label.x.npc=.5)
compare_means(z_corresp ~ condition,  data = mean_z_corresp, method = "t.test", hide.ns=hide_ns)
plotAVcorresp

plotAVcorresp = plotAVcorresp + labs(title = "Audiovisual Correspondence", tag = "B") + theme(plot.title = element_text(hjust = 0.5, face='bold'), plot.tag = element_text(face='bold'))
 

There is a significant difference between AVI and AVR conditions in terms of felt correspendence (i.e., particpants felt that the intentional pairings showed greater A-V correspondence than the random pairings). It is quite interesting then, that even though they could tell the difference in correspondence, there were no differences in terms of enjoyment, interestingness, etc. (see all prior plots and stats).

Figure 1 for paper

Now create one figure which tiles all of our previous figures

if (op) {tiff(paste(fig_path, "combined_DVs_ridge_r1.tiff", sep=""), units="in", width=9, height=11, res=300)}
plotAll = grid.arrange(plotTimeSecs, plotAVcorresp, plotEnjoy, plotInterest, plotMood, plotMoved, ncol = 2)

plotAll
TableGrob (3 x 2) "arrange": 6 grobs
ggsave("combined_DVs_ridge_r1.svg", plotAll, width=9, height=11, units = "in")

NOTE: In final, publication-ready figure, I manually removed non-significant comparison brackets, as well as brackets with p values that did not withstand multiple comparisons.

Supplementary Analysis (not included in the paper)

How do our different measures correlate with one another?

Note, 4 observations per condition for every participant. Can avg by participant. Construct 4 separate correlation matrices and see if differences in structure based on modality?

Overall correlation with all conditions included

# remove ratio diff and other columns we don't need 
ratings = z_means[ , -which(names(z_means) %in% c("exp_subject_id","condition", "mean_corresp", "logtime"))] # drop label columns and ones not using
ratings$mean_timespent = log(ratings$mean_timespent) # TODO check if want to do this or not

# Capture the plot so we can use it again later
chart.Correlation(ratings, histogram=TRUE, pch=25, text.panel=labs)

Correlations by condition

Audio

# remove ratio diff and other columns we don't need 
ratings = subset(z_means, condition == 'Audio')
ratings = ratings[ , -which(names(ratings) %in% c("exp_subject_id","condition", "mean_corresp", "logtime"))] # drop label columns and ones not using
ratings$mean_timespent = log(ratings$mean_timespent)

chart.Correlation(ratings, histogram=TRUE, pch=25, text.panel=labs)

Visual

# remove ratio diff and other columns we don't need 
ratings = subset(z_means, condition == 'Visual')
ratings = ratings[ , -which(names(ratings) %in% c("exp_subject_id","condition", "mean_corresp", "logtime"))] # drop label columns and ones not using
ratings$mean_timespent = log(ratings$mean_timespent)

chart.Correlation(ratings, histogram=TRUE, pch=25, text.panel=labs)

AV-Intended

# remove ratio diff and other columns we don't need 
ratings = subset(z_means, condition == 'AV-Intended')
corresp = subset(mean_z_corresp, condition == 'AV-Intended')
#ratings$mean_corresp = mean_z_corresp
ratings <- merge(x=ratings,y=corresp, 
                by="exp_subject_id")
ratings <- ratings %>% # rename
  rename(mean_corresp = z_corresp)
ratings = ratings[ , -which(names(ratings) %in% c("exp_subject_id","condition", "condition.x", "condition.y", "logtime"))] 
ratings$mean_timespent = log(ratings$mean_timespent)

chart.Correlation(ratings, histogram=TRUE, pch=25, text.panel=labs)

AV-random

# remove ratio diff and other columns we don't need 
ratings = subset(z_means, condition == 'AV-Random')
corresp = subset(mean_z_corresp, condition == 'AV-Random')
ratings <- merge(x=ratings,y=corresp, 
                by="exp_subject_id")
ratings <- ratings %>% # rename
  rename(mean_corresp = z_corresp)
ratings = ratings[ , -which(names(ratings) %in% c("exp_subject_id","condition", "condition.x", "condition.y", "logtime"))] 
ratings$mean_timespent = log(ratings$mean_timespent)


chart.Correlation(ratings, histogram=TRUE, pch=25, text.panel=labs)

It seems our ratings scales and time spent measure show different relationships with each other, dependent on the condition. On the one hand this speaks against something like factor analysis to reduce dimensionality without taking condition into account. On the other hand, the rating scales consistently correlate with each other across conditions. Therefore, we could probably reduce the ratings, as we suggested in our pre-registration. Note that the relationship of the ratings with time spent does not change when using log time spent.

Factor analysis on ratings data

Organize all data we want into one table

# merge participants means and demo data
pall = merge(data_participant, z_means, by="exp_subject_id")

# remove columns we don't need 
pall = pall[ , -which(names(pall) %in% c("country_current", "country_home","prev_exposure","area_intense_aes_exp","Modality_Preference_cat", "area_creative_beh","area_aes_apprec"))]  
# "gender","Modality_Preference","Ollen",, "exp_subject_id","group_name",
pall$mean_timespent = log(pall$mean_timespent)

# make sure variable right type
# Remove the 'option_' prefix and keep only the numbers for the ordered categorical columns
data$Modality_Preference <- gsub('option_', '', data$Modality_Preference)
# Convert the column to numeric
data$Modality_Preference <- as.numeric(data$Modality_Preference)
# Convert to ordered factor
pall$Modality_Preference = factor(pall$Modality_Preference)

# Do same for ollen scale
data$Ollen <- gsub('option_', '', data$Ollen)
data$Ollen <- as.numeric(data$Ollen)
pall$Ollen = factor(pall$Ollen)

# gender is unordered
pall$gender = factor(pall$gender, ordered = F)

#chart.Correlation(pall, histogram=TRUE, pch=25, text.panel=labs)

Check for suitability of FA

# organize data
forfa = z_means[ , -which(names(z_means) %in% c("mean_timespent","logtime", "condition","exp_subject_id", "factor_score"))] 

# check for missing values
nna = sum(is.na(forfa)) # 16 nas in the df
# N.B. NAs have been introduced by z-scoring, due to dividing by zero (no variance)
# Since the true mean was zero, it is fair to impute with zero 
forfa$mean_enjoy[is.na(forfa$mean_enjoy)] <- 0
forfa$mean_mood_cong[is.na(forfa$mean_mood_cong)] <- 0
forfa$mean_moved[is.na(forfa$mean_moved)] <- 0
forfa$mean_interesting[is.na(forfa$mean_interesting)] <- 0

# Do tests to determine suitability for FA
print("KMO")
[1] "KMO"
KMO(r=cor(forfa))
Kaiser-Meyer-Olkin factor adequacy
Call: KMO(r = cor(forfa))
Overall MSA =  0.8
MSA for each item = 
      mean_enjoy mean_interesting   mean_mood_cong       mean_moved 
            0.73             0.75             0.88             0.90 
print("Bartlett")
[1] "Bartlett"
cortest.bartlett(forfa)
$chisq
[1] 2127.938

$p.value
[1] 0

$df
[1] 6
print("Determinant")
[1] "Determinant"
det(cor(forfa))
[1] 0.07014754

Kaiser’s (1974) guidelines, suggest cutoff of KMO ≥ 60 for determining the factorability of the sample data. Here was are well above, suggesting suitability for FA. P value for Bartlett’s test is significant. Determinant is positive, indicating FA will likely run.

Determine number of factors

fafitfree <- fa(forfa, nfactors = ncol(forfa), rotate = "none")
n_factors <- length(fafitfree$e.values)
scree     <- data.frame(
  Factor_n =  as.factor(1:n_factors), 
  Eigenvalue = fafitfree$e.values)
ggplot(scree, aes(x = Factor_n, y = Eigenvalue, group = 1)) + 
  geom_point() + geom_line() +
  xlab("Number of factors") +
  ylab("Initial eigenvalue") +
  labs( title = "Scree Plot", 
        subtitle = "(Based on the unreduced correlation matrix)")

fa.none <- fa(r=forfa, 
              nfactors = 1, 
              fm="pa", # type of factor analysis we want to use (“pa” is principal axis factoring)
              max.iter=100,
              rotate="varimax") # none rotation
print(fa.none)
Factor Analysis using method =  pa
Call: fa(r = forfa, nfactors = 1, rotate = "varimax", max.iter = 100, 
    fm = "pa")
Standardized loadings (pattern matrix) based upon correlation matrix

                PA1
SS loadings    2.75
Proportion Var 0.69

Mean item complexity =  1
Test of the hypothesis that 1 factor is sufficient.

df null model =  6  with the objective function =  2.66 with Chi Square =  2127.94
df of  the model are 2  and the objective function was  0.07 

The root mean square of the residuals (RMSR) is  0.03 
The df corrected root mean square of the residuals is  0.05 

The harmonic n.obs is  804 with the empirical chi square  9.47  with prob <  0.0088 
The total n.obs was  804  with Likelihood Chi Square =  53.1  with prob <  2.9e-12 

Tucker Lewis Index of factoring reliability =  0.928
RMSEA index =  0.178  and the 90 % confidence intervals are  0.139 0.221
BIC =  39.72
Fit based upon off diagonal values = 1
Measures of factor score adequacy             
                                                   PA1
Correlation of (regression) scores with factors   0.96
Multiple R square of scores with factors          0.93
Minimum correlation of possible factor scores     0.85

Concatenate scores with other data

z_means['factor_score'] <- fa.none$scores

Run same anova analyses as above but on factor score

p = plotRidges(z_means, "condition", "factor_score", "", "Condition", "Mean Factor Score")
runaov("exp_subject_id","factor_score", z_means, "condition") 
Anova Table (Type 3 tests)

Response: factor_score
     Effect           df  MSE         F  ges p.value
1 condition 2.72, 543.46 1.29 11.85 *** .056   <.001
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘+’ 0.1 ‘ ’ 1

Sphericity correction method: GG 
 contrast                estimate     SE  df t.ratio p.value
 AV.Intended - AV.Random  -0.0506 0.0916 200  -0.552  0.9428
 AV.Intended - Audio       0.5237 0.1047 200   5.001  <.0001
 AV.Intended - Visual      0.0774 0.1073 200   0.722  0.9428
 AV.Random - Audio         0.5743 0.1058 200   5.429  <.0001
 AV.Random - Visual        0.1280 0.1047 200   1.222  0.6691
 Audio - Visual           -0.4463 0.1300 200  -3.434  0.0029

P value adjustment: holm method for 6 tests 
factorPlot = p + stat_compare_means(comparisons = my_comparisons, label = "p.signif", method = "t.test", paired="True", na.rm=TRUE)
factorPlot = factorPlot + labs(y = "Mean Factor Score (Aesthetic Experience)")
factorPlot

It basically mimics enjoyment results, as that item has highest factor loading. But there was clearly something more interesting going on with all of the small differences in the ANOVAs reported above

ratings = z_means[ , -which(names(z_means) %in% c("exp_subject_id","condition", "mean_corresp"))] # drop label columns and ones not using
ratings$mean_timespent = log(ratings$mean_timespent)

par(mfrow = c(3,1))
chart.Correlation(ratings, histogram=TRUE, pch=25, text.panel=labs)

fa.diagram(fa.none, digits=2, cut = .3, simple=TRUE)

#factorPlot

Exploratory analysis

Relationship between personal variables and time spent / feeling moved (all conditions)

# merge mean table and participant level table
df = pall

# plot relation between area and feeling moved
p <- ggplot(df, aes(x=area_composite, y=mean_moved)) +
  geom_point() + geom_smooth(method=lm , color="black", fill="gray", se=TRUE) +
  theme(legend.position="none") + theme_classic()

# Custom marginal plots:
p2 <- ggMarginal(p, type="densigram", fill = "gray") 
p2 



# plot relation between area and timespent
p <- ggplot(df, aes(x=area_composite, y=mean_timespent)) +
  geom_point() + geom_smooth(method=lm , color="black", fill="gray", se=TRUE) +
  theme(legend.position="none") + theme_classic()

# Custom marginal plots:
p2 <- ggMarginal(p, type="densigram", fill = "gray") 
p2 

I would have expected a relationship between AReA and some of the aesthetic measures. Perhaps AReA more relevant for visual modality. Break out by modality?

Visual-only data

# merge mean table and participant level table
# pvis = pall[, pall$condition == 'Visual']
# df = pvis


pvis <- pall %>%
  filter(condition == "Visual")

df = pvis

# plot relation between area and feeling moved
p <- ggplot(df, aes(x=area_composite, y=mean_moved)) +
  geom_point() + geom_smooth(method=lm , color="black", fill="gray", se=TRUE) +
  theme(legend.position="none") + theme_classic()

# Custom marginal plots:
p2 <- ggMarginal(p, type="densigram", fill = "gray") 
p2 



# plot relation between area and timespent
p <- ggplot(df, aes(x=area_composite, y=mean_timespent)) +
  geom_point() + geom_smooth(method=lm , color="black", fill="gray", se=TRUE) +
  theme(legend.position="none") + theme_classic()

# Custom marginal plots:
p2 <- ggMarginal(p, type="densigram", fill = "gray") 
p2 

LS0tCnRpdGxlOiAiUiBOb3RlYm9vayBmb3IgRmluaywgRmllaG4sIFdhbGQtRnVocm1hbm4gKDIwMjQpIGFuYWx5c2VzIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKYXV0aG9yczogTGF1cmVuIEZpbmsgJiBIYW5uYWggRmllaG4KY29udGFjdDogZmlua2wxQG1jbWFzdGVyLmNhCi0tLQoKVGhpcyBub3RlYm9vayBhY2NvbXBhbmllcyB0aGUgbWFudXNjcmlwdDoKCkZpbmssIEZpZWhuICYgV2FsZC1GdWhybWFubiAoMjAyNCkuIFRoZSByb2xlIG9mIGF1ZGlvdmlzdWFsIGNvbmdydWVuY2UgaW4gYWVzdGhldGljIGFwcHJlY2lhdGlvbiBvZiBjb250ZW1wb3JhcnkgbXVzaWMgYW5kIHZpc3VhbCBhcnQuICpTY2llbnRpZmljIFJlcG9ydHMqLCA3MTM5OS4gRE9JOiBbaHR0cHM6Ly9kb2kub3JnLzEwLjEwMzgvczQxNTk4LTAyNC03MTM5OS15XShodHRwczovL2RvaS5vcmcvMTAuMTAzOC9zNDE1OTgtMDI0LTcxMzk5LXkpCgoqUHJlLXByaW50IGF2YWlsYWJsZSBhdDoqIFtvc2YuaW8vaGpnYzUvXShvc2YuaW8vaGpnYzUvKQoKSWYgdXNpbmcgYW55IGNvZGUgb3IgZGF0YSBmcm9tIHRoaXMgbm90ZWJvb2ssIHBsZWFzZSBjaXRlIHRoZSBwYXBlci4gCgpBZGRpdGlvbmFsIGNvZGUgYW5kIGluZm9ybWF0aW9uIGFjY29tcGFueWluZyB0aGlzIFIgbm90ZWJvb2sgYXJlIGF2YWlsYWJsZSBpbiB0aGUgYXNzb2NpYXRlZCBHaXRIdWIgcmVwb3NpdG9yeTogW2h0dHBzOi8vZ2l0aHViLmNvbS9sa2ZpbmsvS2VudGxlcl9NSU1fQmVoYXZpb3JdKGh0dHBzOi8vZ2l0aHViLmNvbS9sa2ZpbmsvS2VudGxlcl9NSU1fQmVoYXZpb3IpCgojIExvYWQgYW5kIHByZXByb2Nlc3MgZGF0YQpUdXJuIG9mZiB3YXJuaW5ncyBmb3IgY2xlYW5lciBzdWJtaXNzaW9uIGZpbGUuIE4uQi4gdXNlcnMgb2YgdGhpcyBmaWxlIHNob3VsZCB0dXJuIHdhcm5pbmdzIG9uIGZvciB0cm91Ymxlc2hvb3RpbmcKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9IAprbml0cjo6b3B0c19jaHVuayRzZXQod2FybmluZyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0UpIApgYGAKCiMjIyBJbnN0YWxsIHJlcXVpcmVkIHBhY2thZ2VzLCBpZiBub3QgYWxyZWFkeSBpbnN0YWxsZWQKYGBge3J9Cmxpc3Qub2YucGFja2FnZXMgPC0gYygidGlkeXZlcnNlIiwgImdncHViciIsICJleiIsICJjb3JycGxvdCIsICJjYXIiLCAic3RhdHMiLCJQZXJmb3JtYW5jZUFuYWx5dGljcyIsICJhZmV4IiwgImVtbWVhbnMiLCAibWxtYSIsICJnZ3Bsb3QyIiwgImdnRXh0cmEiLCAicHN5Y2giLCAiZ2dwdWJyIiwgImhlcmUiLCAiZ3JpZEV4dHJhIiwgImdncmlkZ2VzIikKbmV3LnBhY2thZ2VzIDwtIGxpc3Qub2YucGFja2FnZXNbIShsaXN0Lm9mLnBhY2thZ2VzICVpbiUgaW5zdGFsbGVkLnBhY2thZ2VzKClbLCJQYWNrYWdlIl0pXQppZihsZW5ndGgobmV3LnBhY2thZ2VzKSkgaW5zdGFsbC5wYWNrYWdlcyhuZXcucGFja2FnZXMpIApgYGAKCiMjIyBMb2FkIHBhY2thZ2VzIGFuZCBkYXRhCldlIHVzZSB0aGUgKmhlcmUqIHBhY2thZ2Ugc28gdGhhdCBhbGwgZmlsZSBwYXRocyBhcmUgcmVsYXRpdmUuIFVzZXJzIHNob3VsZCBiZSBzdXJlIG5vdCB0byBjaGFuZ2UgdGhlIGRpcmVjdG9yeSBzdHJ1Y3R1cmUgb2YgdGhlIHJlcG9zaXRvcnkuIApCeSBkZWZhdWx0LCBmaWd1cmVzIHdpbGwgYmUgcGxvdHRlZCBpbiBsaW5lLiBJZiB5b3Ugd2FudCB0byBzYXZlIHRoZSBmaWd1cmVzIHRvIGEgZm9sZGVyIG9uIHlvdXIgbG9jYWwgbWFjaGluZSwgc2V0IG9wID0gMS4gCmBgYHtyfQpoZXJlOjppX2FtKCJGaW5rX0tlbnRsZXJfYW5hbHlzZXMuUm1kIikKbGlicmFyeShoZXJlKQpzb3VyY2UoaGVyZSgiZGVwZW5kZW5jaWVzLlIiKSkKZGF0YSA8LSByZWFkLmNzdihoZXJlKCJkYXRhLmNzdiIpKSAKZmlnX3BhdGggPC0gaGVyZSgiZmlndXJlcy8iKSAjIHBhdGggdG8gc2F2ZSBnZW5lcmF0ZWQgZmlndXJlcyB0bwpvcCA9IDAgIyBmbGFnIGlmIHdhbnQgdG8gc2F2ZSBvdXRwdXQgcGxvdHMgdG8gZmlsZXMgKDEpIG9yIHBsb3QgaW5saW5lICgwKQpgYGAKCiMjIyBQcmUtcHJvY2VzcyB0aGUgZGF0YQpDbGVhbiB1cCB2YXJpYWJsZSBuYW1lcywgYWRkIGNvbWJpbmVkIGNvbHVtbnMgb2YgaW50ZXJlc3QsIGRyb3AgdW5uZWNlc3NhcnkgY29sdW1ucwpgYGB7cn0KIyByZW1vdmUgdmFyaWFibGVzIHdlIGRvbid0IG5lZWQgKExhYnZhbmNlZCBzdGlsbCBvdXRwdXR0aW5nIG9sZCB2YXJzIGZyb20gZWFybGllciBleHAuIHZlcnNpb24pCmRhdGFfbmV3IDwtIHN1YnNldChkYXRhLCBzZWxlY3QgPSAtIGMoQmxvY2tfTmFtZSwgVGFza19OciwgYXVkX3RlbmRfdW5peCwgYXVkX3RzLCBhdWRfdHNfdW5peCwgY29uZGkzLCBjb3B5X29mX2NvbmRpMiwgY29weV9vZl9jb25kaSwgZnJhbWVfZW5kX3VuaXgsIGZyYW1lX3J0LCBOYW1lLkF1ZGlvLl9jb3B5XzRiNDksIE5hbWUuQXVkaW8uX2NvcHlfOTNhNywgTmFtZS5BdWRpby5fY29weV9iZDZmLCBOYW1lLkF1ZGlvLl9jb3B5X2M5NTgsIE5hbWUuQXVkaW8uX2NvcHlfYzk2YywgTmFtZS5BdWRpby4sIHN1YmpfY291bnRlcl9nbG9iYWwsIHN1YmpfY291bnRlcl9wZXJfZ3JvdXAsIHRpbWVfZGVsYXlfb2Zmc2V0LCB0aW1lX21lYXN1cmVfc3RkLCBwaXhlbERlbnNpdHlQZXJNTSx1bmxvY2tlZCkpCgojIGZpbHRlciBvdXQgcGVvcGxlIHdobyBoYXZlIHNlZW4vaGVhcmQgc3RpbXVsaSBiZWZvcmUgKHNvbWUgb2Ygb3VyIHBpbG90cykgb3Igd2hvIGRvbid0IGhhdmUgbm9ybWFsIGhlYXJpbmcgLyB2aXNpb24KZXhwb3NlZCA9IHRhYmxlKGRhdGEkcHJldl9leHBvc3VyZSkKZGF0YV9uZXcgPC0gZGF0YV9uZXdbLWMod2hpY2goZGF0YV9uZXckcHJldl9leHBvc3VyZSA9PSAib3B0aW9uXzAiKSksIF0Kbm9ybVNlbnNlcyA9IHRhYmxlKGRhdGEkTm9ybWFsLlZpc2lvbi4pICMgbm8gb25lIHdpdGhvdXQKZGF0YV9uZXcgPC0gZGF0YV9uZXdbLWMod2hpY2goZGF0YV9uZXckY29tcGxldGVkID09ICJubyIpKSwgXSAjIHJlbW92ZSBpbmNvbXBsZXRlcwpkYXRhID0gZGF0YV9uZXcgIyBvdmVyd3JpdGUgb2xkIGRhdGEgc28gY2FuJ3QgYWNjaWRlbnRhbGx5IHVzZSBpdAoKI2NyZWF0ZSBhIGRhdGFmcmFtZSBqdXN0IHdpdGggdGhlIHRhc2sgYmxvY2sgKGZvciBmdXJ0aGVyIGFuYWx5c2lzICkKZGF0YV90YXNrIDwtIGRhdGFfbmV3ICU+JSAKICBzZWxlY3QoVHJpYWxfTnIsIFRyaWFsX0lkLCBjb3JyZXNwb25kZW5jZV8sIGVuam95XywgRnJhbWUuVGltZS4sIGludGVyZXN0aW5nbmVzc18sIG1vb2QuY29uZ3J1ZW5jeV8sIG1vdmVfLCBzdWJqZWN0X2NvZGUsIEJsb2NrX05yLCBncm91cF9uYW1lLCBleHBfc3ViamVjdF9pZCkKCmRhdGFfdGFzayA8LSBkYXRhX3Rhc2tbLCBjKCJleHBfc3ViamVjdF9pZCIsICJCbG9ja19OciIsICJUcmlhbF9OciIsICJUcmlhbF9JZCIsImdyb3VwX25hbWUiLCAiRnJhbWUuVGltZS4iLCAiY29ycmVzcG9uZGVuY2VfIiwgImVuam95XyIsICJpbnRlcmVzdGluZ25lc3NfIiwgIm1vb2QuY29uZ3J1ZW5jeV8iLCAibW92ZV8iICldCgojIHB1dCB0aW1lIHNwZW50IGluIHNlY3MgKGluc3RlYWQgb2YgbXMpCmRhdGFfdGFzayRGcmFtZS5UaW1lLiA9IGRhdGFfdGFzayRGcmFtZS5UaW1lLiAvIDEwMDAKCiMgQWRkIGNvbHVtbiBmb3IgY29uZGl0aW9uIAojIFRyaWFsX0lkIHRlbGxzIHdoaWNoIGNvbmRpdGlvbiBpdCBpcyAoMSAtIDQgPSBBOyA1IC0gOCA9IFY7IDkgLSAxMiA9IEFWSTsgMTMgLSAxNiA9IEFWUikKIyB3aXRoIFRyaWFsX0lkIGFuZCB0aGUgZ3JvdXAgbnVtYmVyIHdlIGNhbiBsb29rIHdoaWNoIHNwZWNpZmljIHN0aW11bGkgYXJlIHVzZWQgCmRhdGFfdGFzayRUcmlhbF9JZCA9IGFzLm51bWVyaWMoZGF0YV90YXNrJFRyaWFsX0lkKQpkYXRhX3Rhc2skY29uZGl0aW9uID0gTkEKZGF0YV90YXNrJGNvbmRpdGlvbltkYXRhX3Rhc2skVHJpYWxfSWQgPD0gNF0gPSAnQXVkaW8nIApkYXRhX3Rhc2skY29uZGl0aW9uW2RhdGFfdGFzayRUcmlhbF9JZCA+PSA1ICYgZGF0YV90YXNrJFRyaWFsX0lkIDw9IDhdID0gJ1Zpc3VhbCcgCmRhdGFfdGFzayRjb25kaXRpb25bZGF0YV90YXNrJFRyaWFsX0lkID49IDkgJiBkYXRhX3Rhc2skVHJpYWxfSWQgPD0gMTJdID0gJ0FWLUludGVuZGVkJyAKZGF0YV90YXNrJGNvbmRpdGlvbltkYXRhX3Rhc2skVHJpYWxfSWQgPj0gMTNdID0gJ0FWLVJhbmRvbScgCgojIGNyZWF0ZSBzdWJzZXQgZGF0YSBmcmFtZSBvZiB0YXNrIGRhdGEKI2p1c3Qga2VlcCBCbG9jayBOdW1iZXIgPSAyICh0aGVzZSBhcmUgdGhlIGV4cGVyaW1lbnRhbCB0cmlhbHMpCmRhdGFfdGFzayA8LSBkYXRhX3Rhc2sgJT4lCiAgZmlsdGVyKEJsb2NrX05yID09IDIpCgojIGNyZWF0ZSBzdWJzZXQgZGF0YSBmcmFtZSB3aXRoIGp1c3QgcGFydGljaXBhbnQgaW5mbwpkYXRhX3BhcnRpY2lwYW50IDwtIGRhdGFfbmV3ICU+JQogIHNlbGVjdChleHBfc3ViamVjdF9pZCwgZ3JvdXBfbmFtZSwgYWdlX2lucHV0LCBnZW5kZXIsIGNvdW50cnlfY3VycmVudCwgY291bnRyeV9ob21lLCBNb2RhbGl0eV9QcmVmZXJlbmNlLCBPbGxlbiwgb3ZlcmFsbF9lbmpveSwgInByZXZfZXhwb3N1cmUiLCByZWFsV29ybGRMaWtlbGlob29kKQoKZGF0YV9wYXJ0aWNpcGFudCA9IG5hLm9taXQoZGF0YV9wYXJ0aWNpcGFudCkKCiMgY2FsY3VsYXRlIGFyZWEgc2NvcmVzIGZvciBlYWNoIHBhcnRpY2lwYW50IGFuZCBhZGQgdG8gcGFydGljaXBhbnQgZGF0YQojIEFSZUEgc2NhbGUgc2NvcmluZwojQWVzdGhldGljIEFwcHJlY2lhdGlvbjogSXRlbXMgMSwgMiwgMywgNCwgNiwgOSwgMTMsIDE0CiNJbnRlbnNlIEFlc3RoZXRpYyBFeHBlcmllbmNlOiBJdGVtcyA4LCAxMSwgMTIsIDEzCiNDcmVhdGl2ZSBCZWhhdmlvcjogSXRlbXMgNSwgNywgMTAKYXJlYV9kYXRhID0gZGF0YVtkYXRhJFRhc2tfTmFtZSA9PSAnQVJlQScsXQphcmVhX2RhdGEkYXJlYV9hZXNfYXBwcmVjID0gYXJlYV9kYXRhJGFyZWFfMDEgKyBhcmVhX2RhdGEkYXJlYV8wMiArIGFyZWFfZGF0YSRhcmVhXzAzICsgYXJlYV9kYXRhJGFyZWFfMDQgKyBhcmVhX2RhdGEkYXJlYV8wNiArIGFyZWFfZGF0YSRhcmVhXzA5ICsgYXJlYV9kYXRhJGFyZWFfMTMgKyBhcmVhX2RhdGEkYXJlYV8xNAphcmVhX2RhdGEkYXJlYV9hZXNfYXBwcmVjID0gYXJlYV9kYXRhJGFyZWFfYWVzX2FwcHJlYyAvIDggIyBkaXZpZGUgYnkgbnVtIG9mIGl0ZW1zCmFyZWFfZGF0YSRhcmVhX2ludGVuc2VfYWVzX2V4cCA9IGFyZWFfZGF0YSRhcmVhXzA4ICsgYXJlYV9kYXRhJGFyZWFfMTEgKyBhcmVhX2RhdGEkYXJlYV8xMiArIGFyZWFfZGF0YSRhcmVhXzEzCmFyZWFfZGF0YSRhcmVhX2ludGVuc2VfYWVzX2V4cCA9IGFyZWFfZGF0YSRhcmVhX2ludGVuc2VfYWVzX2V4cCAvIDQKYXJlYV9kYXRhJGFyZWFfY3JlYXRpdmVfYmVoID0gYXJlYV9kYXRhJGFyZWFfMDUgKyBhcmVhX2RhdGEkYXJlYV8wNyArIGFyZWFfZGF0YSRhcmVhXzEwCmFyZWFfZGF0YSRhcmVhX2NyZWF0aXZlX2JlaCA9IGFyZWFfZGF0YSRhcmVhX2NyZWF0aXZlX2JlaCAvIDMKYXJlYV9kYXRhJGFyZWFfY29tcG9zaXRlID0gKGFyZWFfZGF0YSRhcmVhX2Flc19hcHByZWMgKyBhcmVhX2RhdGEkYXJlYV9pbnRlbnNlX2Flc19leHAgKyBhcmVhX2RhdGEkYXJlYV9jcmVhdGl2ZV9iZWgpIC8gMwoKIyBhZGQgYXJlYSBzY29yZXMgdG8gbWVhbiB0YWJsZSAoam9pbiBiYXNlZCBvbiBleHBfc3Vial9pZCkKYXJlYV9kYXRhID0gYXJlYV9kYXRhWyxjKCJleHBfc3ViamVjdF9pZCIsICJhcmVhX2Flc19hcHByZWMiLCAiYXJlYV9pbnRlbnNlX2Flc19leHAiLCAiYXJlYV9jcmVhdGl2ZV9iZWgiLCAiYXJlYV9jb21wb3NpdGUiKV0KCiMgbWVyZ2UgYXJlYSB3aXRoIHBhcnRpY2lwYW50IGRmCmRhdGFfcGFydGljaXBhbnQgPSBtZXJnZSh4PWRhdGFfcGFydGljaXBhbnQseT1hcmVhX2RhdGEsIAogICAgICAgICAgICAgICAgICAgICAgICAgYnk9ImV4cF9zdWJqZWN0X2lkIiwgYWxsPVRSVUUpCgojIGNsZWFuIHVwIG1vZGFsaXR5IHByZWYgZGF0YSB0byBoYXZlIG1lYW5pbmdmdWwgbGFiZWxzCnRlbXAgPSBkYXRhX3BhcnRpY2lwYW50JE1vZGFsaXR5X1ByZWZlcmVuY2UKdGVtcCA9IGdzdWIoIm9wdGlvbl8wIiwgInByZWZlcl9hdWRpbyIsIHRlbXApCnRlbXAgPSBnc3ViKCJvcHRpb25fMSIsICJwcmVmZXJfdmlzdWFsIiwgdGVtcCkKdGVtcCA9IGdzdWIoIm9wdGlvbl8yIiwgInByZWZlcl9hdWRpb3Zpc3VhbCIsIHRlbXApCnRlbXAgPSBnc3ViKCJvcHRpb25fMyIsICJub19wcmVmZXJlbmNlIiwgdGVtcCkKZGF0YV9wYXJ0aWNpcGFudCRNb2RhbGl0eV9QcmVmZXJlbmNlX2NhdCA9IHRlbXAKCiMgam9pbiBwYXJ0aWNpcGFudCBpbmZvIHdpdGggdHJpYWwgbGV2ZWwgZGF0YSBmb3IgZmluYWwgZnVsbCBkYXRhIGZyYW1lCmZ1bGxfZGF0YSA9IG1lcmdlKHg9ZGF0YV90YXNrLHk9ZGF0YV9wYXJ0aWNpcGFudCwgCiAgICAgICAgICAgICAgICAgIGJ5PSJleHBfc3ViamVjdF9pZCIsIGFsbD1UUlVFKQpgYGAKCkNoZWNrIHBhcnRpY2lwYW50IG51bWJlciBkaXNjcmVwZW5jaWVzIGJldHdlZW4gdGFzayBkYXRhIGFuZCBkZW1vIGRhdGEKYGBge3J9CiMgc29tZXRoaW5nIHdyb25nISBvbmx5IDE5NSBvYnMgZm9yIHBlb3BsZSB3aG8gc2F3IGVuZFFzID8hICh0aGVzZSB3ZXJlIHJlcXVpcmVkIHF1ZXN0aW9ucy4gbm90IHN1cmUgaG93IGxhYnZhbmNlZCBsZXQgdGhhdCB0aHJvdWdoKQojIHRhYmxlKGRhdGFfbmV3JFRhc2tfTmFtZSkKCiMgY2hlY2sgd2hhdCBnb2luZyBvbiB3aXRoIDYgc3VicwpjaGVjayA9IHN1YnNldChmdWxsX2RhdGEsIGlzLm5hKGZ1bGxfZGF0YSRPbGxlbikpCmNoZWNrMiA9IHN1YnNldChkYXRhLCBpcy5uYShmdWxsX2RhdGEkT2xsZW4pKQoKbnN1YnMgPSBsZW5ndGgodW5pcXVlKGZ1bGxfZGF0YSRleHBfc3ViamVjdF9pZCkpCm5zdWJzX21pc3NpbmdEZW1vID0gbGVuZ3RoKHVuaXF1ZShjaGVjayRleHBfc3ViamVjdF9pZCkpCmBgYApJdCBzZWVtcyA2IHBhcnRpY2lwYW50cyBuZXZlciBnb3QgdGhlIGVuZGluZyBxdWVzdGlvbnMuIFdlIGNhbiBpbmNsdWRlIHRoZW0gZm9yIGFsbCB0cmlhbCBhbmFseXNlcyBidXQgdGhleSB3aWxsIGJlIGV4Y2x1ZGVkIGZyb20gcGVyc29uLWxldmVsIGFuYWx5c2VzCgojIFBlcnNvbi1sZXZlbCBhbmFseXNlcwoKIyMjIEV4cGxvcmUgZGVtb2dyYXBoaWMgZGF0YQpgYGB7cn0KZ2VuZGVyX2Rpc3QgPSB0YWJsZShkYXRhX3BhcnRpY2lwYW50JGdlbmRlcikKYWdlX21lYW4gPSBtZWFuKGRhdGFfcGFydGljaXBhbnQkYWdlX2lucHV0LCBuYS5ybSA9IFRSVUUpCmFnZV9zdGQgPSBzZChkYXRhX3BhcnRpY2lwYW50JGFnZV9pbnB1dCwgbmEucm0gPSBUUlVFKQpuY291bnRyaWVzID0gbGVuZ3RoKHVuaXF1ZShkYXRhX3BhcnRpY2lwYW50JGNvdW50cnlfY3VycmVudCkpCmNvdW50cmllcyA9IHRhYmxlKGRhdGFfcGFydGljaXBhbnQkY291bnRyeV9jdXJyZW50KQptb2RhbGl0eV9wcmVmID0gdGFibGUoZGF0YV9wYXJ0aWNpcGFudCRNb2RhbGl0eV9QcmVmZXJlbmNlX2NhdCkgCgpwcmludCgiR2VuZGVyOiBtYW4sIHdvbWFuLCBub24tYmluYXJ5LCBwcmVmZXIgbm90IHRvIHNheSIpCnByaW50KGdlbmRlcl9kaXN0KQoKcHJpbnQoIkFnZSAobWVhbiwgc2QsIG1pbiwgbWF4KSIpCnByaW50KGFnZV9tZWFuKQpwcmludChhZ2Vfc3RkKQpwcmludChtaW4oZGF0YV9wYXJ0aWNpcGFudCRhZ2VfaW5wdXQsIG5hLnJtID0gVFJVRSkpCnByaW50KG1heChkYXRhX3BhcnRpY2lwYW50JGFnZV9pbnB1dCwgbmEucm0gPSBUUlVFKSkKCnByaW50KCJVbmlxdWUgY291bnRyaWVzOiIpCnByaW50KG5jb3VudHJpZXMpCnByaW50KGNvdW50cmllcykKCnByaW50KCJBUmVBIChtZWFuLCBzZCwgbWluLCBtYXgpOiIpCnByaW50KG1lYW4oZGF0YV9wYXJ0aWNpcGFudCRhcmVhX2NvbXBvc2l0ZSkpCnByaW50KHNkKGRhdGFfcGFydGljaXBhbnQkYXJlYV9jb21wb3NpdGUpKQpwcmludChtaW4oZGF0YV9wYXJ0aWNpcGFudCRhcmVhX2NvbXBvc2l0ZSkpCnByaW50KG1heChkYXRhX3BhcnRpY2lwYW50JGFyZWFfY29tcG9zaXRlKSkKCnByaW50KCJBUmVBIEFBIChtZWFuLCBzZCwgbWluLCBtYXgpOiIpCnByaW50KG1lYW4oZGF0YV9wYXJ0aWNpcGFudCRhcmVhX2Flc19hcHByZWMpKQpwcmludChzZChkYXRhX3BhcnRpY2lwYW50JGFyZWFfYWVzX2FwcHJlYykpCnByaW50KG1pbihkYXRhX3BhcnRpY2lwYW50JGFyZWFfYWVzX2FwcHJlYykpCnByaW50KG1heChkYXRhX3BhcnRpY2lwYW50JGFyZWFfYWVzX2FwcHJlYykpCgpwcmludCgiQVJlQSBJQUUgKG1lYW4sIHNkLCBtaW4sIG1heCk6IikKcHJpbnQobWVhbihkYXRhX3BhcnRpY2lwYW50JGFyZWFfaW50ZW5zZV9hZXNfZXhwKSkKcHJpbnQoc2QoZGF0YV9wYXJ0aWNpcGFudCRhcmVhX2ludGVuc2VfYWVzX2V4cCkpCnByaW50KG1pbihkYXRhX3BhcnRpY2lwYW50JGFyZWFfaW50ZW5zZV9hZXNfZXhwKSkKcHJpbnQobWF4KGRhdGFfcGFydGljaXBhbnQkYXJlYV9pbnRlbnNlX2Flc19leHApKQoKcHJpbnQoIkFSZUEgQ0IgKG1lYW4sIHNkLCBtaW4sIG1heCk6IikKcHJpbnQobWVhbihkYXRhX3BhcnRpY2lwYW50JGFyZWFfY3JlYXRpdmVfYmVoKSkKcHJpbnQoc2QoZGF0YV9wYXJ0aWNpcGFudCRhcmVhX2NyZWF0aXZlX2JlaCkpCnByaW50KG1pbihkYXRhX3BhcnRpY2lwYW50JGFyZWFfY3JlYXRpdmVfYmVoKSkKcHJpbnQobWF4KGRhdGFfcGFydGljaXBhbnQkYXJlYV9jcmVhdGl2ZV9iZWgpKQpgYGAKCiMjIyBQbG90IGV4cGVyaW1lbnQtcmVsYXRlZCBwZXJzb24tbGV2ZWwgdmFyaWFibGVzCmBgYHtyfQojIGNsZWFuIHVwIGFuZCBwbG90IG9sbGVuIGRhdGEKb2xsZW5TY2FsZSA9IGMoIm5vbi1tdXNpY2lhbiIsICJtdXNpYy1sb3Zpbmcgbm9uLW11c2ljaWFuIiwgImFtYXRldXIgbXVzaWNpYW4iLCAic2VyaW91cyBhbWF0ZXVyIG11c2ljaWFuIiwgInNlbWktcHJvZmVzc2lvbmFsIG11c2ljaWFuIiwgInByb2Zlc3Npb25hbCBtdXNpY2lhbiIpCgpvbGxlbiA9IHRhYmxlKGRhdGFfcGFydGljaXBhbnQkT2xsZW4pCm9sbGVuID0gZGF0YS5mcmFtZShvbGxlbikKbmFtZXMob2xsZW4pID0gYygiUmVzcG9uc2UiLCJQYXJ0aWNpcGFudHMiKQpvbGxlbiRSZXNwb25zZSA9IG9sbGVuU2NhbGVbMTo1XSAjIG5vYm9keSBjaG9zZSBwcm9mZXNzaW9uYWwhCgpwcmludChvbGxlbikKZGVzY3JpYmUob2xsZW4kUGFydGljaXBhbnRzKQoKIyBvcmRlciBPbGxlbiBwcm9wZXJseQpvbGxlbiA8LSB3aXRoaW4ob2xsZW4sIFJlc3BvbnNlIDwtIGZhY3RvcihSZXNwb25zZSwgbGV2ZWxzPW9sbGVuU2NhbGUpKQoKIyBjcmVhdGUgYmFycGxvdAojIHBuZygiS2VudGxlcl9vbGxlbi5wbmciLCB1bml0cz0iaW4iLCB3aWR0aD04LCBoZWlnaHQ9NSwgcmVzPTMwMCkKZ2dwbG90KG9sbGVuLCBhZXMoeD1SZXNwb25zZSwgeT1QYXJ0aWNpcGFudHMpKSArIAogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArIGNvb3JkX2ZsaXAoKSArIHRoZW1lX2NsYXNzaWMoKSArIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwKSkKCiMgUGxvdCBhcmVhIGRhdGEKZ2dwbG90KGRhdGFfcGFydGljaXBhbnQsIGFlcyh4PWFyZWFfY29tcG9zaXRlKSkgKyAKICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gMjApICsgZ2d0aXRsZSgiQVJlQSBjb21wb3NpdGUgc2NvcmUiKQoKCiMgUGxvdCBlbmpveW1lbnQgZGF0YQpnZ3Bsb3QoZGF0YV9wYXJ0aWNpcGFudCwgYWVzKHg9b3ZlcmFsbF9lbmpveSkpICsgCiAgZ2VvbV9oaXN0b2dyYW0oYmlucyA9IDI1KSArIGdndGl0bGUoIk92ZXJhbGwgZW5qb3ltZW50IG9mIHRoZSBleHBlcmltZW50IikKCmdncGxvdChkYXRhX3BhcnRpY2lwYW50LCBhZXMoeD1yZWFsV29ybGRMaWtlbGlob29kKSkgKyAKICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gMjUpICsgZ2d0aXRsZSgiTGlrZWxpaG9vZCBvZiBzZWVraW5nIHNpbWlsYXIgcGllY2VzIGluIHJlYWwgd29ybGQiKQoKcHJpbnQoIkVuam95bWVudCAobWVhbiwgc2QpIikKcHJpbnQobWVhbihkYXRhX3BhcnRpY2lwYW50JG92ZXJhbGxfZW5qb3ksIG5hLnJtPVQpKQpwcmludChzZChkYXRhX3BhcnRpY2lwYW50JG92ZXJhbGxfZW5qb3ksIG5hLnJtPVQpKQoKcHJpbnQoIkxpa2VsaWhvb2QgKG1lYW4sIHNkKSIpCnByaW50KG1lYW4oZGF0YV9wYXJ0aWNpcGFudCRyZWFsV29ybGRMaWtlbGlob29kLCBuYS5ybT1UKSkKcHJpbnQoc2QoZGF0YV9wYXJ0aWNpcGFudCRyZWFsV29ybGRMaWtlbGlob29kLCBuYS5ybT1UKSkKCiMgcGxvdCByZWxhdGlvbiBiZXR3ZWVuIGVuam95bWVudCBhbmQgbGlrZWxpaG9vZApwIDwtIGdncGxvdChkYXRhX3BhcnRpY2lwYW50LCBhZXMoeD1vdmVyYWxsX2Vuam95LCB5PXJlYWxXb3JsZExpa2VsaWhvb2QpKSArCiAgZ2VvbV9wb2ludCgpICsgZ2VvbV9zbW9vdGgobWV0aG9kPWxtICwgY29sb3I9ImJsYWNrIiwgZmlsbD0iZ3JheSIsIHNlPVRSVUUpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSArIHRoZW1lX2NsYXNzaWMoKQoKIyBDdXN0b20gbWFyZ2luYWwgcGxvdHM6CnAyIDwtIGdnTWFyZ2luYWwocCwgdHlwZT0iZGVuc2lncmFtIiwgZmlsbCA9ICJncmF5IikgCnAyIAoKIyBTZWxmLXJlcG9ydGVkIG1vZGFsaXR5IHByZWZzCiMgY3JlYXRlIGJhcnBsb3Qgb2YgbW9kYWxpdHkgcHJlZmVyZW5jZXMKbXByZWYgPSBkYXRhLmZyYW1lKG1vZGFsaXR5X3ByZWYpCm5hbWVzKG1wcmVmKSA9IGMoIlJlc3BvbnNlIiwiUGFydGljaXBhbnRzIikKbXByZWYkcGVyY2VudCA9IG1wcmVmJFBhcnRpY2lwYW50cyAvIHN1bShtcHJlZiRQYXJ0aWNpcGFudHMpCgoKIyBwbmcoIktlbnRsZXJfcHJlZmVyZW5jZS5wbmciLCB1bml0cz0iaW4iLCB3aWR0aD04LCBoZWlnaHQ9NSwgcmVzPTMwMCkgCmdncGxvdChtcHJlZiwgYWVzKHg9UmVzcG9uc2UsIHk9UGFydGljaXBhbnRzKSkgKyAKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKyBjb29yZF9mbGlwKCkgKyB0aGVtZV9jbGFzc2ljKCkgKyB0aGVtZSh0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMCkpCmBgYAojIyMgUGxvdCByZWxhdGlvbnNoaXAgYmV0d2VlbiBhbGwgcGVyc29uLWxldmVsIHZhcnMKYGBge3J9CiMgY3JlYXRlIGRhdGEgZnJhbWUgZm9yIGNvcnJlbGF0aW9uCiMgbmVlZCB0byBjb252ZXJ0IGNhdGVnb3JpY2FsIHRvIG51bWVyaWMgCmNvcnJkZiA9IGRhdGFfcGFydGljaXBhbnRbICwgd2hpY2gobmFtZXMoZGF0YV9wYXJ0aWNpcGFudCkgJWluJSBjKCJPbGxlbiIsICJNb2RhbGl0eV9QcmVmZXJlbmNlIiwgIm92ZXJhbGxfZW5qb3kiLCAicmVhbFdvcmxkTGlrZWxpaG9vZCIsICJhcmVhX2Flc19hcHByZWMiLCAiYXJlYV9pbnRlbnNlX2Flc19leHAiLCAiYXJlYV9jcmVhdGl2ZV9iZWgiLCAiYXJlYV9jb21wb3NpdGUiKSldIAoKY29ycmRmJE1vZGFsaXR5X1ByZWZlcmVuY2UgPSBhcy5udW1lcmljKGFzLmZhY3Rvcihjb3JyZGYkTW9kYWxpdHlfUHJlZmVyZW5jZSkpCmNvcnJkZiRPbGxlbiA9IGFzLm51bWVyaWMoYXMuZmFjdG9yKGNvcnJkZiRPbGxlbikpCgpjaGFydC5Db3JyZWxhdGlvbihjb3JyZGYsIGhpc3RvZ3JhbT1UUlVFLCBwY2g9MjUsIHRleHQucGFuZWw9bGFicykKYGBgCgojIENvbmRpdGlvbi1sZXZlbCBhbmFseXNlcwoKIyMjIENyZWF0ZSB0YWJsZXMgb2YgbWVhbnMKWi1zY29yZSByYXRpbmdzIGRhdGEgd2l0aGluIHNjYWxlLCBwYXJ0aWNpcGFudCAgCkNhbGN1bGF0ZSB0YWJsZSBvZiBtZWFucyBmb3IgYWxsIHBhcnRpY2lwYW50cyAvIGNvbmRpdGlvbnMKLSBkbyB0aGlzIGZvciBib3RoIHotc2NvcmVkIGFuZCByYXcgZGF0YSBpbiBjYXNlIHdlIHdhbnQgdG8gY29tcGFyZQpgYGB7cn0KIyBjcmVhdGUgenNjb3JlIGZ1bmN0aW9uCnpzY29yZSA8LSBmdW5jdGlvbihpbnB1dCl7CiAgb3V0ID0gKGlucHV0IC0gbWVhbihpbnB1dCkpL3NkKGlucHV0KQp9CgojIHpzY29yZSBkYXRhCnpzY29yZWQgPSBkYXRhX3Rhc2sgJT4lCiAgZ3JvdXBfYnkoZXhwX3N1YmplY3RfaWQpICU+JQogIG11dGF0ZSh6X2Vuam95ID0genNjb3JlKGVuam95XyksIHpfaW50ZXJlc3RpbmcgPSB6c2NvcmUoaW50ZXJlc3RpbmduZXNzXyksIHpfbW9vZF9jb25nID0genNjb3JlKG1vb2QuY29uZ3J1ZW5jeV8pLCB6X21vdmVkID0genNjb3JlKG1vdmVfKSkKIyBOT1RFIHpzY29yaW5nIGNvcnJlc3BvbmRlbmNlIG5lZWRzIHRvIGJlIGRvbmUgb25seSBmb3IgQVYgY29uZGl0aW9ucwoKIyBnZXQgbWVhbnMgb2YgenNjb3JlZCBkYXRhCnpfbWVhbnMgPSB6c2NvcmVkICU+JQogIGdyb3VwX2J5KGV4cF9zdWJqZWN0X2lkLCBjb25kaXRpb24pICU+JQogIHN1bW1hcmlzZShtZWFuX3RpbWVzcGVudCA9IG1lYW4oRnJhbWUuVGltZS4pLCBtZWFuX2Vuam95ID0gbWVhbih6X2Vuam95KSwgbWVhbl9pbnRlcmVzdGluZyA9IG1lYW4oel9pbnRlcmVzdGluZyksIG1lYW5fbW9vZF9jb25nID0gbWVhbih6X21vb2RfY29uZyksIG1lYW5fbW92ZWQgPSBtZWFuKHpfbW92ZWQpKQoKCiMgZ2V0IG1lYW5zIG9mIHpzY29yZWQgZGF0YQojIHpfbWVhbnNfcGFydGljaXBhbnQgPSB6X21lYW5zICU+JQojICAgZ3JvdXBfYnkoZXhwX3N1YmplY3RfaWQpICU+JQojICAgc3VtbWFyaXNlKG1lYW5fdGltZXNwZW50ID0gbWVhbihtZWFuX3RpbWVzcGVudCksIG1lYW5fZW5qb3kgPSBtZWFuKG1lYW5fZW5qb3kpLCBtZWFuX2ludGVyZXN0aW5nID0gbWVhbihtZWFuX2ludGVyZXN0aW5nKSwgbWVhbl9tb29kX2NvbmcgPSBtZWFuKG1lYW5fbW9vZF9jb25nKSwgbWVhbl9tb3ZlZCA9IG1lYW4obWVhbl9tb3ZlZCkpCiMgCgojIGdldCByYXcgbWVhbnMgaW4gY2FzZSB3YW50IHRvIGNvbXBhcmUgdG8genNjb3JlZCBkYXRhCm1lYW5zID0gZGF0YV90YXNrICU+JQogIGdyb3VwX2J5KGV4cF9zdWJqZWN0X2lkLCBjb25kaXRpb24pICU+JQogIHN1bW1hcmlzZShtZWFuX3RpbWVzcGVudCA9IG1lYW4oRnJhbWUuVGltZS4pLCBtZWFuX2Vuam95ID0gbWVhbihlbmpveV8pLCBtZWFuX2ludGVyZXN0aW5nID0gbWVhbihpbnRlcmVzdGluZ25lc3NfKSwgbWVhbl9tb29kX2NvbmcgPSBtZWFuKG1vb2QuY29uZ3J1ZW5jeV8pLCBtZWFuX21vdmVkID0gbWVhbihtb3ZlXyksIG1lYW5fY29ycmVzcCA9IG1lYW4oY29ycmVzcG9uZGVuY2VfKSkKCiMgZ2V0IHJhdyBzZHMgaW4gY2FzZSB3YW50IHRvIGNvbXBhcmUgdG8genNjb3JlZCBkYXRhCnNkcyA9IGRhdGFfdGFzayAlPiUKICBncm91cF9ieShleHBfc3ViamVjdF9pZCwgY29uZGl0aW9uKSAlPiUKICBzdW1tYXJpc2UobWVhbl90aW1lc3BlbnQgPSBzZChGcmFtZS5UaW1lLiksIG1lYW5fZW5qb3kgPSBzZChlbmpveV8pLCBtZWFuX2ludGVyZXN0aW5nID0gc2QoaW50ZXJlc3RpbmduZXNzXyksIG1lYW5fbW9vZF9jb25nID0gc2QobW9vZC5jb25ncnVlbmN5XyksIG1lYW5fbW92ZWQgPSBzZChtb3ZlXyksIG1lYW5fY29ycmVzcCA9IHNkKGNvcnJlc3BvbmRlbmNlXykpCgpgYGAKCgojIyMgQ3JlYXRlIGN1c3RvbSBmdW5jdGlvbnMgZm9yIGFuYWx5c2lzIGFuZCBwbG90dGluZwpXZSBoYXZlIG11bHRpcGxlIERWcyBvbiB3aGljaCB3ZSB3YW50IHRvIHJ1biB0aGUgc2FtZSB0eXBlIG9mIGFuYWx5c2lzCmBgYHtyfQojIEZ1bmN0aW9uIHRvIHBsb3QgdmlvbGlucyBmb3IgZWFjaCBjb25kaXRpb24KIyBJbnB1dDogZGF0YWZyYW1lLCB2YXJpYWJsZSB0byBwbG90LCB0aXRsZSBmb3IgcGxvdApwbG90VmlvbGluID0gZnVuY3Rpb24oZGF0YSwgZ3JvdXB2YXIsIHZhciwgdGl0c3RyLCB4bGFiLCB5bGFiKXsKICAKICAjIGRlZmluZSBjb2xvcnMKICBBVlIgPSAnIzhjMWFmZicKICBBVkkgPSAnI2NjOTlmZicKICBWID0gJyNmZjRkNGQnCiAgQSA9ICcjNjY5OWZmJwogIG91cmNvbG9ycyA9IGMoQSwgQVZJLCBBVlIsIFYpCiAgCiAgIyBvbmx5IEFWIGNvbmRpdGlvbnMgcmVsZXZhbnQKICBpZiAodmFyID09ICJ6X2NvcnJlc3AiKXsKICAgIG91cmNvbG9ycyA9IGMoQVZJLCBBVlIpIAogIH0KICAKICAjIFBsb3QKICB2YXIgPSBzeW0odmFyKQogIGdyb3VwdmFyID0gc3ltKGdyb3VwdmFyKQoKICBwbCA9IGRhdGEgJT4lCiAgICBnZ3Bsb3QoYWVzKHg9ISFncm91cHZhciwgeT0hIXZhciwgZmlsbD0hIWdyb3VwdmFyKSkgKwogICAgZ2VvbV92aW9saW4obGVnZW5kID0gRkFMU0UsIHRyaW0gPSBGQUxTRSwgYWRqdXN0ID0gMSwgZHJhd19xdWFudGlsZXMgPSBjKDAuMjUsIDAuNzUpLCBzaXplPS41LCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvcj0iYmxhY2siKSArICMuOCAKICAgIGdlb21fdmlvbGluKGxlZ2VuZCA9IEZBTFNFLCB0cmltID0gRkFMU0UsIGFkanVzdCA9IDEsIGRyYXdfcXVhbnRpbGVzID0gMC41LCBmaWxsPSJ0cmFuc3BhcmVudCIsIHNpemU9Ljg1LCBjb2xvcj0iYmxhY2siKSArICMxLjIKICAgIAogICAgZ2VvbV9qaXR0ZXIoc2l6ZT0wLjQsIGFscGhhPTAuNiwgY29sb3I9ImdyYXkiKSArCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9b3VyY29sb3JzKSArCiAgICAjdGhlbWVfY2xhc3NpYygpICsKICAgIHRoZW1lX3JpZGdlcygpICsKICAgIHRoZW1lKAogICAgICBsZWdlbmQucG9zaXRpb249Im5vbmUiLAogICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MTEpCiAgICApICsKICAgIGdndGl0bGUodGl0c3RyKSArCiAgICB4bGFiKHhsYWIpICsKICAgIHlsYWIoeWxhYikKICAKICByZXR1cm4ocGwpCiAgCn0KCgoKIyBGdW5jdGlvbiB0byBjcmVhdGUgZGVuc2l0eSByaWRnZSBwbG90cyBmb3IgZWFjaCBjb25kaXRpb24KIyBJbnB1dDogZGF0YWZyYW1lLCB2YXJpYWJsZSB0byBwbG90LCB0aXRsZSBmb3IgcGxvdApwbG90UmlkZ2VzID0gZnVuY3Rpb24oZGF0YSwgZ3JvdXB2YXIsIHZhciwgdGl0c3RyLCB4bGFiLCB5bGFiKXsKICAKICAjIGRlZmluZSBjb2xvcnMKICBBVlIgPSAnI0NDQkI0NCcKICBBVkkgPSAnIzIyODgzMycKICBWID0gJyNDQzY2NzcnCiAgQSA9ICcjODhDQ0VFJwogIG91cmNvbG9ycyA9IGMoQSwgQVZJLCBBVlIsIFYpCiAgCiAgIyBvbmx5IEFWIGNvbmRpdGlvbnMgcmVsZXZhbnQKICBpZiAodmFyID09ICJ6X2NvcnJlc3AiKXsKICAgIG91cmNvbG9ycyA9IGMoQVZJLCBBVlIpIAogIH0KICAKICAjIFBsb3QKICB2YXIgPSBzeW0odmFyKQogIGdyb3VwdmFyID0gc3ltKGdyb3VwdmFyKQoKICBwbCA9IGRhdGEgJT4lCiAgICBnZ3Bsb3QoYWVzKHg9ISF2YXIsIHk9ISFncm91cHZhciwgZmlsbD0hIWdyb3VwdmFyKSkgKwogICAgCiAgICMgc3RhdF9kZW5zaXR5X3JpZGdlcyhxdWFudGlsZV9saW5lcz1UUlVFLCBxdWFudGlsZXMgPSBjKDAuMDI1LCAwLjk3NSksIGNvbG9yPSJibGFjayIsIGFscGhhID0gMSkgKwogICAgCiAgICBnZW9tX2RlbnNpdHlfcmlkZ2VzKGluaGVyaXQuYWVzID0gVFJVRSwgaml0dGVyZWRfcG9pbnRzID0gVFJVRSwgc3RhdCA9ImRlbnNpdHlfcmlkZ2VzIiwKICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9wb2ludHNfaml0dGVyKHdpZHRoID0gMC4wNSwgaGVpZ2h0ID0gMCksCiAgICAgIHBvaW50X3NoYXBlID0gJ3wnLCBwb2ludF9zaXplID0gMywgcG9pbnRfYWxwaGEgPSAuOSwgYWxwaGEgPSAwLjcpICsKICAgIAogICAgZ2VvbV9kZW5zaXR5X3JpZGdlcyhhbHBoYSA9IDAuODUsIHF1YW50aWxlX2xpbmVzPVRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yPSJ3aGl0ZSIsIHF1YW50aWxlX2Z1bj1mdW5jdGlvbih2YXIsLi4uKW1lYW4odmFyKSkgKwogICAgCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9b3VyY29sb3JzKSArCiAgICB4bGFiKHlsYWIpICsKICAgIHRoZW1lX3JpZGdlcygpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiAgICB0aGVtZShheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKSArIAogICAgICAgICAgdGhlbWUoYXhpcy50aXRsZS55PWVsZW1lbnRfYmxhbmsoKSkKICAKICByZXR1cm4ocGwpCiAgCn0KCgojIEZ1bmN0aW9uIHRvIHJ1biBybSBhbm92YSBhbmQgb3V0cHV0IHN0YXRzCnJ1bmFvdiA9IGZ1bmN0aW9uKGlkLCBkdiwgZGF0YSwgdyl7CiAgZml0ID0gYW92X2V6KGlkLGR2LGRhdGEsd2l0aGluPXcpCiAgcHJpbnQoZml0KQogIGZpdDIgPC0gbHNtZWFucyhmaXQsc3BlY3MgPSBjKHcpKQogIGNvbnRyYXN0KGZpdDIsbWV0aG9kPSJwYWlyd2lzZSIsYWRqdXN0PSJob2xtIikKfQoKIyBDb25kaXRpb25zIHRvIGNvbXBhcmUgYWZ0ZXIgQU5PVkFzCm15X2NvbXBhcmlzb25zIDwtIGxpc3QoIGMoIkF1ZGlvIiwgIkFWLUludGVuZGVkIiksIGMoIkF1ZGlvIiwgIkFWLVJhbmRvbSIpLCBjKCJBdWRpbyIsICJWaXN1YWwiKSwgYygiQVYtSW50ZW5kZWQiLCAiQVYtUmFuZG9tIiksICBjKCJBVi1JbnRlbmRlZCIsICJWaXN1YWwiKSwgYygiQVYtUmFuZG9tIiwgIlZpc3VhbCIpKQpteV9jb21wYXJpc29ucyA9IHJldihteV9jb21wYXJpc29ucykgIyByZXZlcnNlIG9yZGVyIHNvIG1vcmUgcmVhZGFibGUgb24gcGxvdHMKCiMgQ2hvb3NlIHBsb3R0aW5nIHN0eWxlICh2aW9saW4gb3IgcmlkZ2UpIGZvciBmdXR1cmUgcGxvdHMKY3VzdG9tcGxvdCA9IHBsb3RSaWRnZXMKaGlkZV9ucyA9IEZBTFNFCmBgYAoKIyMgVGltZSBzcGVudApIb3cgbXVjaCB0aW1lIGRpZCBwYXJ0aWNpcGFudHMgc3BlbmQgZXhwZXJpZW5jaW5nIHRoZSBwaWVjZXMgaW4gdGhlIGRpZmZlcmVudCBjb25kaXRpb25zPyBEaWQgdGhleSBzcGVuZCBtb3JlIHRpbWUgaW4gb25lIGNvbmRpdGlvbiB2cy4gYW5vdGhlcj8KYGBge3J9CnpfbWVhbnMkbG9ndGltZSA9IGxvZyh6X21lYW5zJG1lYW5fdGltZXNwZW50KQpwID0gY3VzdG9tcGxvdCh6X21lYW5zLCAiY29uZGl0aW9uIiwgIm1lYW5fdGltZXNwZW50IiwgIiIsICJDb25kaXRpb24iLCAiTWVhbiBUaW1lIFNwZW50IChzZWNzKSIpCnBsb3RUaW1lU2VjcyA9IHAgKyBzdGF0X2NvbXBhcmVfbWVhbnMoY29tcGFyaXNvbnMgPSBteV9jb21wYXJpc29ucywgbGFiZWwgPSAicC5zaWduaWYiLCBtZXRob2QgPSAidC50ZXN0IiwgcGFpcmVkID0gInRydWUiLCBuYS5ybT1UUlVFLCBoaWRlLm5zPWhpZGVfbnMpCgpwID0gY3VzdG9tcGxvdCh6X21lYW5zLCAiY29uZGl0aW9uIiwgImxvZ3RpbWUiLCAiIiwgIiIsICJNZWFuIFRpbWUgU3BlbnQgKGxvZyBzZWNzKSIpCnBsb3RUaW1lTG9nID0gcCArIHN0YXRfY29tcGFyZV9tZWFucyhjb21wYXJpc29ucyA9IG15X2NvbXBhcmlzb25zLCBsYWJlbCA9ICJwLnNpZ25pZiIsIG1ldGhvZCA9ICJ0LnRlc3QiLCBwYWlyZWQgPSAidHJ1ZSIsIG5hLnJtPVRSVUUsIGhpZGUubnM9aGlkZV9ucykKel9tZWFucyRleHBfc3ViamVjdF9pZCA9IGFzLmZhY3Rvcih6X21lYW5zJGV4cF9zdWJqZWN0X2lkKQoKcnVuYW92KCJleHBfc3ViamVjdF9pZCIsIm1lYW5fdGltZXNwZW50Iiwgel9tZWFucywgImNvbmRpdGlvbiIpCgojIHByaW50IG1lYW5zIGFuZCBzZHMKY29uZF9tZWFucyA9IHpfbWVhbnMgJT4lCiAgZ3JvdXBfYnkoY29uZGl0aW9uKSAlPiUKICBzdW1tYXJpc2UobWVhbl90aW1lc3BlbnQgPSBtZWFuKG1lYW5fdGltZXNwZW50LCBuYS5ybT1UKSkgICAKCmNvbmRfc2RzID0gel9tZWFucyAlPiUKICBncm91cF9ieShjb25kaXRpb24pICU+JQogIHN1bW1hcmlzZShzZF90aW1lc3BlbnQgPSBzZChtZWFuX3RpbWVzcGVudCwgbmEucm09VCkpCgpwcmludChjb25kX21lYW5zKQpwcmludChjb25kX3NkcykKCnBsb3RUaW1lU2VjcwpwbG90VGltZUxvZwoKcGxvdFRpbWVTZWNzID0gcGxvdFRpbWVTZWNzICsgbGFicyh0aXRsZSA9ICJUaW1lIFNwZW50IiwgdGFnID0gIkEiKSArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2U9J2JvbGQnKSwgcGxvdC50YWcgPSBlbGVtZW50X3RleHQoZmFjZT0nYm9sZCcpKQpgYGAKCldlIGZpbmQgYSBtYWluIGVmZmVjdCBvZiBjb25kaXRpb24uIFBvc3QtaG9jIHRlc3RzIHNob3cgc2lnbmlmaWNhbnQgZGlmZmVyZW5jZXMgYmV0d2VlbiBhbGwgY29uZGl0aW9ucywgZXhjZXB0IEFWSSBhbmQgQVZSLiBSZXN1bHRzIGRvIG5vdCBjaGFuZ2Ugd2hldGhlciB3ZSB1c2UgcmF3IG1lYW4gdGltZSBzcGVudCBvciBsb2cgb2YgaXQuIAoKCgojIyBFbmpveW1lbnQKRGlkIGVuam95bWVudCBkaWZmZXIgYnkgY29uZGl0aW9uPyAoUSB0byBwYXJ0aWNpcGFudHM6IEkgZW5qb3llZCB0aGUgcGllY2UgKDAtMTAwKSkKYGBge3J9CnAgPSBjdXN0b21wbG90KHpfbWVhbnMsICJjb25kaXRpb24iLCAibWVhbl9lbmpveSIsICIiLCAiQ29uZGl0aW9uIiwgIk1lYW4gRW5qb3ltZW50ICh6LXNjb3JlKSIpCnBsb3RFbmpveSA9IHAgKyBzdGF0X2NvbXBhcmVfbWVhbnMoY29tcGFyaXNvbnMgPSBteV9jb21wYXJpc29ucywgbGFiZWwgPSAicC5zaWduaWYiLCBtZXRob2QgPSAidC50ZXN0IiwgcGFpcmVkID0gInRydWUiLCBuYS5ybT1UUlVFLCBoaWRlLm5zPWhpZGVfbnMpCnJ1bmFvdigiZXhwX3N1YmplY3RfaWQiLCJtZWFuX2Vuam95Iiwgel9tZWFucywgImNvbmRpdGlvbiIpCnBsb3RFbmpveQpwbG90RW5qb3kgPSBwbG90RW5qb3kgKyBsYWJzKHRpdGxlID0gIkVuam95bWVudCIsIHRhZyA9ICJDIikgKyB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlPSdib2xkJyksIHBsb3QudGFnID0gZWxlbWVudF90ZXh0KGZhY2U9J2JvbGQnKSkKYGBgCgpUaGVyZSBpcyBhIHNpZ25pZmljYW50IG1haW4gZWZmZWN0IG9mIGNvbmRpdGlvbiBvbiBFbmpveW1lbnQuIFBvc3QtaG9jIGNvbnRyYXN0cyBzaG93IHRoYXQgQVZJIGFuZCBBVlIgYXJlIGhpZ2hlciBpbiBlbmpveW1lbnQgdGhhbiBBLCBidXQgbm90IFYsIG9yIGVhY2ggb3RoZXIuIChWIGlzIGFsc28gaGlnaGVyIHRoYW4gQSkKU28sIGV2ZW4gdGhvdWdoIHBlb3BsZSBzcGVudCBtb3JlIHRpbWUgd2l0aCBhdWRpbywgdGhleSBlbmpveSBtb3JlIHdpdGggdmlzdWFsLiAKCiMjIEludGVyZXN0aW5nbmVzcwpEaWQgaW50ZXJlc3RpbmduZXNzIGRpZmZlciBieSBjb25kaXRpb24/IChRIHRvIHBhcnRpY2lwYW50czogSSBmb3VuZCB0aGUgcGllY2UgaW50ZXJlc3RpbmcgKDAtMTAwKSkKYGBge3J9CnAgPSBjdXN0b21wbG90KHpfbWVhbnMsICJjb25kaXRpb24iLCAibWVhbl9pbnRlcmVzdGluZyIsICIiLCAiQ29uZGl0aW9uIiwgIk1lYW4gSW50ZXJlc3RpbmduZXNzICh6LXNjb3JlKSIpCnBsb3RJbnRlcmVzdCA9IHAgKyBzdGF0X2NvbXBhcmVfbWVhbnMoY29tcGFyaXNvbnMgPSBteV9jb21wYXJpc29ucywgbGFiZWwgPSAicC5zaWduaWYiLCBtZXRob2QgPSAidC50ZXN0IiwgcGFpcmVkID0gInRydWUiLCBuYS5ybT1UUlVFLCBoaWRlLm5zPWhpZGVfbnMpCnJ1bmFvdigiZXhwX3N1YmplY3RfaWQiLCJtZWFuX2ludGVyZXN0aW5nIiwgel9tZWFucywgImNvbmRpdGlvbiIpCnBsb3RJbnRlcmVzdApwbG90SW50ZXJlc3QgPSBwbG90SW50ZXJlc3QgKyBsYWJzKHRpdGxlID0gIkludGVyZXN0aW5nbmVzcyIsIHRhZyA9ICJEIikgKyB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBmYWNlPSdib2xkJyksIHBsb3QudGFnID0gZWxlbWVudF90ZXh0KGZhY2U9J2JvbGQnKSkKCmBgYAoKVGhlc2UgaW50ZXJlc3RpbmduZXNzIHJlc3VsdHMgYXJlIGJhc2ljYWxseSBpZGVudGljYWwgdG8gdGhlIG9uZXMgYWJvdmUgZm9yIGVuam95bWVudC4gCgojIyBNb29kIENvbmdydWVuY3kKRGlkIHBhcnRpY2lwYW50cyBmZWVsIHRoZSBwaWVjZSBtYXRjaGVkIHRoZWlyIGN1cnJlbnQgbW9vZCBtb3JlIGluIGNlcnRhaW4gY29uZGl0aW9ucz8gKFEgdG8gcGFydGljaXBhbnRzOiBUaGUgcGllY2UgbWF0Y2hlZCBteSBjdXJyZW50IG1vb2QgKDAtMTAwKSkKYGBge3J9CnAgPSBjdXN0b21wbG90KHpfbWVhbnMsICJjb25kaXRpb24iLCAibWVhbl9tb29kX2NvbmciLCAiIiwgIkNvbmRpdGlvbiIsICJNZWFuIE1vb2QgQ29uZ3J1ZW5jeSAoei1zY29yZSkiKQpwbG90TW9vZCA9IHAgKyBzdGF0X2NvbXBhcmVfbWVhbnMoY29tcGFyaXNvbnMgPSBteV9jb21wYXJpc29ucywgbGFiZWwgPSAicC5zaWduaWYiLCBtZXRob2QgPSAidC50ZXN0IiwgcGFpcmVkID0gInRydWUiLCBuYS5ybT1UUlVFLCBoaWRlLm5zPWhpZGVfbnMpCnJ1bmFvdigiZXhwX3N1YmplY3RfaWQiLCJtZWFuX21vb2RfY29uZyIsIHpfbWVhbnMsICJjb25kaXRpb24iKQpwbG90TW9vZApwbG90TW9vZCA9IHBsb3RNb29kICsgbGFicyh0aXRsZSA9ICJNb29kIENvbmdydWVuY3kiLCB0YWcgPSAiRSIpICsgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZT0nYm9sZCcpLCBwbG90LnRhZyA9IGVsZW1lbnRfdGV4dChmYWNlPSdib2xkJykpCmBgYAoKVGhlcmUgaXMgYSBzaWduaWZpY2FudCBtYWluIGVmZmVjdCBvZiBjb25kaXRpb24gd2l0aCByZXBlY3QgdG8gd2hldGhlciBwZW9wbGUgdGhpbmsgdGhlIHBpZWNlIG1hdGNoZXMgdGhlaXIgY3VycmVudCBtb29kLiBQb3N0LWhvYyBjb250cmFzdHMgc2hvdyB0aGF0IHBlb3BsZSBhcmUgc2lnbmlmaWNhbnRseSBtb3JlIGxpa2VseSB0byBzYXkgdGhlIHBpZWNlIG1hdGNoZXMgdGhlaXIgbW9vZCBpbiBWIHZzLiBBIGNvbmRpdGlvbnMuIEJ1dCBubyBvdGhlciBwb3N0LWhvYyBjb250cmFzdHMgd2VyZSBzaWduaWZpY2FudC4KCiMjIEZlZWxpbmcgbW92ZWQKRGlkIHBhcnRpY2lwYW50cyBmZWVsIG1vdmVkIGJ5IHRoZSBwaWVjZSBtb3JlIGluIGNlcnRhaW4gY29uZGl0aW9ucz8gKFEgdG8gcGFydGljaXBhbnRzOiBUaGUgcGllY2UgbW92ZWQgbWUgKDAtMTAwKSkKYGBge3J9CnAgPSBjdXN0b21wbG90KHpfbWVhbnMsICJjb25kaXRpb24iLCAibWVhbl9tb3ZlZCIsICIiLCAiQ29uZGl0aW9uIiwgIk1lYW4gRmVlbGluZyBNb3ZlZCAoei1zY29yZSkiKQpydW5hb3YoImV4cF9zdWJqZWN0X2lkIiwibWVhbl9tb3ZlZCIsIHpfbWVhbnMsICJjb25kaXRpb24iKQpwbG90TW92ZWQgPSBwICsgc3RhdF9jb21wYXJlX21lYW5zKGNvbXBhcmlzb25zID0gbXlfY29tcGFyaXNvbnMsIGxhYmVsID0gInAuc2lnbmlmIiwgbWV0aG9kID0gInQudGVzdCIsIHBhaXJlZCA9ICJ0cnVlIiwgbmEucm09VFJVRSwgaGlkZS5ucz1oaWRlX25zKQpwbG90TW92ZWQKcGxvdE1vdmVkID0gcGxvdE1vdmVkICsgbGFicyh0aXRsZSA9ICJGZWVsaW5nIE1vdmVkIiwgdGFnID0gIkYiKSArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2U9J2JvbGQnKSwgcGxvdC50YWcgPSBlbGVtZW50X3RleHQoZmFjZT0nYm9sZCcpKQpgYGAKClNpZ25pZmljYW50IG1haW4gZWZmZWN0IG9mIGNvbmRpdGlvbiBvbiBmZWVsaW5nIG1vdmVkLiBQb3N0LWhvYyB0ZXN0cyBzaG93cyBubyBzaWduaWZpY2FudCBkaWZmZXJlbmNlcyBpbiBmZWVsaW5nIG1vdmVkIGJldHdlZW4gQSB2cy4gViBvciBiZXR3ZWVuIEFWSSB2cy4gQVZSLCBidXQgYWxsIG90aGVyIGNvbnRyYXN0cyB3ZXJlIHNpZ25pZmljYW50LiBUaGlzIGlzIGludGVyZXN0aW5nIGFuZCBwb3RlbnRpYWxseSBhICJsb2FkIiBlZmZlY3QgKGkuZS4sIGJpbW9kYWwgaXMgZ2VuZXJhbGx5IG1vcmUgbW92aW5nIHRoYW4gdW5pLW1vZGFsKQoKIyMgQXVkaW8tdmlzdWFsIGNvcnJlc3BvbmRlbmNlCkNvdWxkIHBhcnRpY2lwYW50cyB0ZWxsIGFib3ZlIGNoYW5jZSB3aGV0aGVyIHRoZSBhdWRpbyBhbmQgdmlzdWFsIG1hdGVyaWFscyBjb3JyZXNwb25kZWQgdG8gb25lIGFub3RoZXI/IChRIHRvIHBhcnRpY2lwYW50czogVG8gd2hhdCBkZWdyZWUgZGlkIHlvdSBmZWVsIHRoZXJlIHdhcyBhIGNvcnJlc3BvbmRlbmNlIGJldHdlZW4gdGhlIGF1ZGlvIGFuZCB2aXN1YWwgc2Vuc2F0aW9ucyB5b3Ugd2VyZSBleHBlcmllbmNpbmc/KQpgYGB7cn0KIyBvbmx5IHpzY29yZSB3aXRoaW4gcmVsZXZhbnQgQVYgY29uZGl0aW9ucwpjb3JyZXNwZGF0YSA9IGRhdGFfdGFza1tkYXRhX3Rhc2skY29uZGl0aW9uID09ICJBVi1JbnRlbmRlZCIgfCBkYXRhX3Rhc2skY29uZGl0aW9uID09ICJBVi1SYW5kb20iLCBdCnpzY29yZWRfY29ycmVzcCA9IGNvcnJlc3BkYXRhICU+JQogIGdyb3VwX2J5KGV4cF9zdWJqZWN0X2lkKSAlPiUKICBtdXRhdGUoel9jb3JyZXNwID0genNjb3JlKGNvcnJlc3BvbmRlbmNlXykpIAoKbWVhbl96X2NvcnJlc3AgPSB6c2NvcmVkX2NvcnJlc3AgJT4lCiAgZ3JvdXBfYnkoZXhwX3N1YmplY3RfaWQsIGNvbmRpdGlvbikgJT4lCiAgc3VtbWFyaXNlKHpfY29ycmVzcCA9IG1lYW4oel9jb3JyZXNwKSkKCiMgcGxvdCBhbmQgY2FsY3VsYXRlIHN0YXRzCnAgPC0gY3VzdG9tcGxvdChtZWFuX3pfY29ycmVzcCwgImNvbmRpdGlvbiIsICJ6X2NvcnJlc3AiLCAiIiwgIkNvbmRpdGlvbiIsICJNZWFuIENvcnJlc3BvbmRlbmNlICh6LXNjb3JlKSIpCnBsb3RBVmNvcnJlc3AgPSBwICsgc3RhdF9jb21wYXJlX21lYW5zKGNvbXBhcmlzb25zID0gbGlzdChjKCJBVi1JbnRlbmRlZCIsICJBVi1SYW5kb20iKSksIGxhYmVsID0gInAuc2lnbmlmIiwgbWV0aG9kID0gInQudGVzdCIsIHBhaXJlZD0idHJ1ZSIsIGxhYmVsLngubnBjPS41KQpjb21wYXJlX21lYW5zKHpfY29ycmVzcCB+IGNvbmRpdGlvbiwgIGRhdGEgPSBtZWFuX3pfY29ycmVzcCwgbWV0aG9kID0gInQudGVzdCIsIGhpZGUubnM9aGlkZV9ucykKcGxvdEFWY29ycmVzcApwbG90QVZjb3JyZXNwID0gcGxvdEFWY29ycmVzcCArIGxhYnModGl0bGUgPSAiQXVkaW92aXN1YWwgQ29ycmVzcG9uZGVuY2UiLCB0YWcgPSAiQiIpICsgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgZmFjZT0nYm9sZCcpLCBwbG90LnRhZyA9IGVsZW1lbnRfdGV4dChmYWNlPSdib2xkJykpCiAKYGBgCgpUaGVyZSBpcyBhIHNpZ25pZmljYW50IGRpZmZlcmVuY2UgYmV0d2VlbiBBVkkgYW5kIEFWUiBjb25kaXRpb25zIGluIHRlcm1zIG9mIGZlbHQgY29ycmVzcGVuZGVuY2UgKGkuZS4sIHBhcnRpY3BhbnRzIGZlbHQgdGhhdCB0aGUgaW50ZW50aW9uYWwgcGFpcmluZ3Mgc2hvd2VkIGdyZWF0ZXIgQS1WIGNvcnJlc3BvbmRlbmNlIHRoYW4gdGhlIHJhbmRvbSBwYWlyaW5ncykuIEl0IGlzIHF1aXRlIGludGVyZXN0aW5nIHRoZW4sIHRoYXQgZXZlbiB0aG91Z2ggdGhleSBjb3VsZCB0ZWxsIHRoZSBkaWZmZXJlbmNlIGluIGNvcnJlc3BvbmRlbmNlLCB0aGVyZSB3ZXJlIG5vIGRpZmZlcmVuY2VzIGluIHRlcm1zIG9mIGVuam95bWVudCwgaW50ZXJlc3RpbmduZXNzLCBldGMuIChzZWUgYWxsIHByaW9yIHBsb3RzIGFuZCBzdGF0cykuCgoKIyBGaWd1cmUgMSBmb3IgcGFwZXIKTm93IGNyZWF0ZSBvbmUgZmlndXJlIHdoaWNoIHRpbGVzIGFsbCBvZiBvdXIgcHJldmlvdXMgZmlndXJlcwpgYGB7cn0KaWYgKG9wKSB7dGlmZihwYXN0ZShmaWdfcGF0aCwgImNvbWJpbmVkX0RWc19yaWRnZV9yMS50aWZmIiwgc2VwPSIiKSwgdW5pdHM9ImluIiwgd2lkdGg9OSwgaGVpZ2h0PTExLCByZXM9MzAwKX0KcGxvdEFsbCA9IGdyaWQuYXJyYW5nZShwbG90VGltZVNlY3MsIHBsb3RBVmNvcnJlc3AsIHBsb3RFbmpveSwgcGxvdEludGVyZXN0LCBwbG90TW9vZCwgcGxvdE1vdmVkLCBuY29sID0gMikKcGxvdEFsbAoKZ2dzYXZlKCJjb21iaW5lZF9EVnNfcmlkZ2VfcjEuc3ZnIiwgcGxvdEFsbCwgd2lkdGg9OSwgaGVpZ2h0PTExLCB1bml0cyA9ICJpbiIpCgpgYGAKCk5PVEU6IEluIGZpbmFsLCBwdWJsaWNhdGlvbi1yZWFkeSBmaWd1cmUsIEkgbWFudWFsbHkgcmVtb3ZlZCBub24tc2lnbmlmaWNhbnQgY29tcGFyaXNvbiBicmFja2V0cywgYXMgd2VsbCBhcyBicmFja2V0cyB3aXRoIHAgdmFsdWVzIHRoYXQgZGlkIG5vdCB3aXRoc3RhbmQgbXVsdGlwbGUgY29tcGFyaXNvbnMuIAoKCgoKCgojIFN1cHBsZW1lbnRhcnkgQW5hbHlzaXMgKG5vdCBpbmNsdWRlZCBpbiB0aGUgcGFwZXIpCgojIyBIb3cgZG8gb3VyIGRpZmZlcmVudCBtZWFzdXJlcyBjb3JyZWxhdGUgd2l0aCBvbmUgYW5vdGhlcj8KTm90ZSwgNCBvYnNlcnZhdGlvbnMgcGVyIGNvbmRpdGlvbiBmb3IgZXZlcnkgcGFydGljaXBhbnQuIENhbiBhdmcgYnkgcGFydGljaXBhbnQuCkNvbnN0cnVjdCA0IHNlcGFyYXRlIGNvcnJlbGF0aW9uIG1hdHJpY2VzIGFuZCBzZWUgaWYgZGlmZmVyZW5jZXMgaW4gc3RydWN0dXJlIGJhc2VkIG9uIG1vZGFsaXR5PwoKIyMjIE92ZXJhbGwgY29ycmVsYXRpb24gd2l0aCBhbGwgY29uZGl0aW9ucyBpbmNsdWRlZApgYGB7cn0KIyByZW1vdmUgcmF0aW8gZGlmZiBhbmQgb3RoZXIgY29sdW1ucyB3ZSBkb24ndCBuZWVkIApyYXRpbmdzID0gel9tZWFuc1sgLCAtd2hpY2gobmFtZXMoel9tZWFucykgJWluJSBjKCJleHBfc3ViamVjdF9pZCIsImNvbmRpdGlvbiIsICJtZWFuX2NvcnJlc3AiLCAibG9ndGltZSIpKV0gIyBkcm9wIGxhYmVsIGNvbHVtbnMgYW5kIG9uZXMgbm90IHVzaW5nCnJhdGluZ3MkbWVhbl90aW1lc3BlbnQgPSBsb2cocmF0aW5ncyRtZWFuX3RpbWVzcGVudCkgIyBUT0RPIGNoZWNrIGlmIHdhbnQgdG8gZG8gdGhpcyBvciBub3QKCiMgQ2FwdHVyZSB0aGUgcGxvdCBzbyB3ZSBjYW4gdXNlIGl0IGFnYWluIGxhdGVyCmNoYXJ0LkNvcnJlbGF0aW9uKHJhdGluZ3MsIGhpc3RvZ3JhbT1UUlVFLCBwY2g9MjUsIHRleHQucGFuZWw9bGFicykKYGBgCgojIyMgQ29ycmVsYXRpb25zIGJ5IGNvbmRpdGlvbgojIyMjIEF1ZGlvCmBgYHtyfQojIHJlbW92ZSByYXRpbyBkaWZmIGFuZCBvdGhlciBjb2x1bW5zIHdlIGRvbid0IG5lZWQgCnJhdGluZ3MgPSBzdWJzZXQoel9tZWFucywgY29uZGl0aW9uID09ICdBdWRpbycpCnJhdGluZ3MgPSByYXRpbmdzWyAsIC13aGljaChuYW1lcyhyYXRpbmdzKSAlaW4lIGMoImV4cF9zdWJqZWN0X2lkIiwiY29uZGl0aW9uIiwgIm1lYW5fY29ycmVzcCIsICJsb2d0aW1lIikpXSAjIGRyb3AgbGFiZWwgY29sdW1ucyBhbmQgb25lcyBub3QgdXNpbmcKcmF0aW5ncyRtZWFuX3RpbWVzcGVudCA9IGxvZyhyYXRpbmdzJG1lYW5fdGltZXNwZW50KQoKY2hhcnQuQ29ycmVsYXRpb24ocmF0aW5ncywgaGlzdG9ncmFtPVRSVUUsIHBjaD0yNSwgdGV4dC5wYW5lbD1sYWJzKQpgYGAKCiMjIyMgVmlzdWFsCmBgYHtyfQojIHJlbW92ZSByYXRpbyBkaWZmIGFuZCBvdGhlciBjb2x1bW5zIHdlIGRvbid0IG5lZWQgCnJhdGluZ3MgPSBzdWJzZXQoel9tZWFucywgY29uZGl0aW9uID09ICdWaXN1YWwnKQpyYXRpbmdzID0gcmF0aW5nc1sgLCAtd2hpY2gobmFtZXMocmF0aW5ncykgJWluJSBjKCJleHBfc3ViamVjdF9pZCIsImNvbmRpdGlvbiIsICJtZWFuX2NvcnJlc3AiLCAibG9ndGltZSIpKV0gIyBkcm9wIGxhYmVsIGNvbHVtbnMgYW5kIG9uZXMgbm90IHVzaW5nCnJhdGluZ3MkbWVhbl90aW1lc3BlbnQgPSBsb2cocmF0aW5ncyRtZWFuX3RpbWVzcGVudCkKCmNoYXJ0LkNvcnJlbGF0aW9uKHJhdGluZ3MsIGhpc3RvZ3JhbT1UUlVFLCBwY2g9MjUsIHRleHQucGFuZWw9bGFicykKYGBgCgojIyMjIEFWLUludGVuZGVkCmBgYHtyfQojIHJlbW92ZSByYXRpbyBkaWZmIGFuZCBvdGhlciBjb2x1bW5zIHdlIGRvbid0IG5lZWQgCnJhdGluZ3MgPSBzdWJzZXQoel9tZWFucywgY29uZGl0aW9uID09ICdBVi1JbnRlbmRlZCcpCmNvcnJlc3AgPSBzdWJzZXQobWVhbl96X2NvcnJlc3AsIGNvbmRpdGlvbiA9PSAnQVYtSW50ZW5kZWQnKQojcmF0aW5ncyRtZWFuX2NvcnJlc3AgPSBtZWFuX3pfY29ycmVzcApyYXRpbmdzIDwtIG1lcmdlKHg9cmF0aW5ncyx5PWNvcnJlc3AsIAogICAgICAgICAgICAgICAgYnk9ImV4cF9zdWJqZWN0X2lkIikKcmF0aW5ncyA8LSByYXRpbmdzICU+JSAjIHJlbmFtZQogIHJlbmFtZShtZWFuX2NvcnJlc3AgPSB6X2NvcnJlc3ApCnJhdGluZ3MgPSByYXRpbmdzWyAsIC13aGljaChuYW1lcyhyYXRpbmdzKSAlaW4lIGMoImV4cF9zdWJqZWN0X2lkIiwiY29uZGl0aW9uIiwgImNvbmRpdGlvbi54IiwgImNvbmRpdGlvbi55IiwgImxvZ3RpbWUiKSldIApyYXRpbmdzJG1lYW5fdGltZXNwZW50ID0gbG9nKHJhdGluZ3MkbWVhbl90aW1lc3BlbnQpCgpjaGFydC5Db3JyZWxhdGlvbihyYXRpbmdzLCBoaXN0b2dyYW09VFJVRSwgcGNoPTI1LCB0ZXh0LnBhbmVsPWxhYnMpCmBgYAoKCiMjIyMgQVYtcmFuZG9tCmBgYHtyfQojIHJlbW92ZSByYXRpbyBkaWZmIGFuZCBvdGhlciBjb2x1bW5zIHdlIGRvbid0IG5lZWQgCnJhdGluZ3MgPSBzdWJzZXQoel9tZWFucywgY29uZGl0aW9uID09ICdBVi1SYW5kb20nKQpjb3JyZXNwID0gc3Vic2V0KG1lYW5fel9jb3JyZXNwLCBjb25kaXRpb24gPT0gJ0FWLVJhbmRvbScpCnJhdGluZ3MgPC0gbWVyZ2UoeD1yYXRpbmdzLHk9Y29ycmVzcCwgCiAgICAgICAgICAgICAgICBieT0iZXhwX3N1YmplY3RfaWQiKQpyYXRpbmdzIDwtIHJhdGluZ3MgJT4lICMgcmVuYW1lCiAgcmVuYW1lKG1lYW5fY29ycmVzcCA9IHpfY29ycmVzcCkKcmF0aW5ncyA9IHJhdGluZ3NbICwgLXdoaWNoKG5hbWVzKHJhdGluZ3MpICVpbiUgYygiZXhwX3N1YmplY3RfaWQiLCJjb25kaXRpb24iLCAiY29uZGl0aW9uLngiLCAiY29uZGl0aW9uLnkiLCAibG9ndGltZSIpKV0gCnJhdGluZ3MkbWVhbl90aW1lc3BlbnQgPSBsb2cocmF0aW5ncyRtZWFuX3RpbWVzcGVudCkKCgpjaGFydC5Db3JyZWxhdGlvbihyYXRpbmdzLCBoaXN0b2dyYW09VFJVRSwgcGNoPTI1LCB0ZXh0LnBhbmVsPWxhYnMpCmBgYApJdCBzZWVtcyBvdXIgcmF0aW5ncyBzY2FsZXMgYW5kIHRpbWUgc3BlbnQgbWVhc3VyZSBzaG93IGRpZmZlcmVudCByZWxhdGlvbnNoaXBzIHdpdGggZWFjaCBvdGhlciwgZGVwZW5kZW50IG9uIHRoZSBjb25kaXRpb24uIE9uIHRoZSBvbmUgaGFuZCB0aGlzIHNwZWFrcyBhZ2FpbnN0IHNvbWV0aGluZyBsaWtlIGZhY3RvciBhbmFseXNpcyB0byByZWR1Y2UgZGltZW5zaW9uYWxpdHkgd2l0aG91dCB0YWtpbmcgY29uZGl0aW9uIGludG8gYWNjb3VudC4gT24gdGhlIG90aGVyIGhhbmQsIHRoZSByYXRpbmcgc2NhbGVzIGNvbnNpc3RlbnRseSBjb3JyZWxhdGUgd2l0aCBlYWNoIG90aGVyIGFjcm9zcyBjb25kaXRpb25zLiBUaGVyZWZvcmUsIHdlIGNvdWxkIHByb2JhYmx5IHJlZHVjZSB0aGUgcmF0aW5ncywgYXMgd2Ugc3VnZ2VzdGVkIGluIG91ciBwcmUtcmVnaXN0cmF0aW9uLiBOb3RlIHRoYXQgdGhlIHJlbGF0aW9uc2hpcCBvZiB0aGUgcmF0aW5ncyB3aXRoIHRpbWUgc3BlbnQgZG9lcyBub3QgY2hhbmdlIHdoZW4gdXNpbmcgbG9nIHRpbWUgc3BlbnQuIAoKCgojIEZhY3RvciBhbmFseXNpcyBvbiByYXRpbmdzIGRhdGEKCiMjIE9yZ2FuaXplIGFsbCBkYXRhIHdlIHdhbnQgaW50byBvbmUgdGFibGUKYGBge3J9CiMgbWVyZ2UgcGFydGljaXBhbnRzIG1lYW5zIGFuZCBkZW1vIGRhdGEKcGFsbCA9IG1lcmdlKGRhdGFfcGFydGljaXBhbnQsIHpfbWVhbnMsIGJ5PSJleHBfc3ViamVjdF9pZCIpCgojIHJlbW92ZSBjb2x1bW5zIHdlIGRvbid0IG5lZWQgCnBhbGwgPSBwYWxsWyAsIC13aGljaChuYW1lcyhwYWxsKSAlaW4lIGMoImNvdW50cnlfY3VycmVudCIsICJjb3VudHJ5X2hvbWUiLCJwcmV2X2V4cG9zdXJlIiwiYXJlYV9pbnRlbnNlX2Flc19leHAiLCJNb2RhbGl0eV9QcmVmZXJlbmNlX2NhdCIsICJhcmVhX2NyZWF0aXZlX2JlaCIsImFyZWFfYWVzX2FwcHJlYyIpKV0gIAojICJnZW5kZXIiLCJNb2RhbGl0eV9QcmVmZXJlbmNlIiwiT2xsZW4iLCwgImV4cF9zdWJqZWN0X2lkIiwiZ3JvdXBfbmFtZSIsCnBhbGwkbWVhbl90aW1lc3BlbnQgPSBsb2cocGFsbCRtZWFuX3RpbWVzcGVudCkKCiMgbWFrZSBzdXJlIHZhcmlhYmxlIHJpZ2h0IHR5cGUKIyBSZW1vdmUgdGhlICdvcHRpb25fJyBwcmVmaXggYW5kIGtlZXAgb25seSB0aGUgbnVtYmVycyBmb3IgdGhlIG9yZGVyZWQgY2F0ZWdvcmljYWwgY29sdW1ucwpkYXRhJE1vZGFsaXR5X1ByZWZlcmVuY2UgPC0gZ3N1Yignb3B0aW9uXycsICcnLCBkYXRhJE1vZGFsaXR5X1ByZWZlcmVuY2UpCiMgQ29udmVydCB0aGUgY29sdW1uIHRvIG51bWVyaWMKZGF0YSRNb2RhbGl0eV9QcmVmZXJlbmNlIDwtIGFzLm51bWVyaWMoZGF0YSRNb2RhbGl0eV9QcmVmZXJlbmNlKQojIENvbnZlcnQgdG8gb3JkZXJlZCBmYWN0b3IKcGFsbCRNb2RhbGl0eV9QcmVmZXJlbmNlID0gZmFjdG9yKHBhbGwkTW9kYWxpdHlfUHJlZmVyZW5jZSkKCiMgRG8gc2FtZSBmb3Igb2xsZW4gc2NhbGUKZGF0YSRPbGxlbiA8LSBnc3ViKCdvcHRpb25fJywgJycsIGRhdGEkT2xsZW4pCmRhdGEkT2xsZW4gPC0gYXMubnVtZXJpYyhkYXRhJE9sbGVuKQpwYWxsJE9sbGVuID0gZmFjdG9yKHBhbGwkT2xsZW4pCgojIGdlbmRlciBpcyB1bm9yZGVyZWQKcGFsbCRnZW5kZXIgPSBmYWN0b3IocGFsbCRnZW5kZXIsIG9yZGVyZWQgPSBGKQoKI2NoYXJ0LkNvcnJlbGF0aW9uKHBhbGwsIGhpc3RvZ3JhbT1UUlVFLCBwY2g9MjUsIHRleHQucGFuZWw9bGFicykKYGBgCgoKCiMjIENoZWNrIGZvciBzdWl0YWJpbGl0eSBvZiBGQQpgYGB7cn0KIyBvcmdhbml6ZSBkYXRhCmZvcmZhID0gel9tZWFuc1sgLCAtd2hpY2gobmFtZXMoel9tZWFucykgJWluJSBjKCJtZWFuX3RpbWVzcGVudCIsImxvZ3RpbWUiLCAiY29uZGl0aW9uIiwiZXhwX3N1YmplY3RfaWQiLCAiZmFjdG9yX3Njb3JlIikpXSAKCiMgY2hlY2sgZm9yIG1pc3NpbmcgdmFsdWVzCm5uYSA9IHN1bShpcy5uYShmb3JmYSkpICMgMTYgbmFzIGluIHRoZSBkZgojIE4uQi4gTkFzIGhhdmUgYmVlbiBpbnRyb2R1Y2VkIGJ5IHotc2NvcmluZywgZHVlIHRvIGRpdmlkaW5nIGJ5IHplcm8gKG5vIHZhcmlhbmNlKQojIFNpbmNlIHRoZSB0cnVlIG1lYW4gd2FzIHplcm8sIGl0IGlzIGZhaXIgdG8gaW1wdXRlIHdpdGggemVybyAKZm9yZmEkbWVhbl9lbmpveVtpcy5uYShmb3JmYSRtZWFuX2Vuam95KV0gPC0gMApmb3JmYSRtZWFuX21vb2RfY29uZ1tpcy5uYShmb3JmYSRtZWFuX21vb2RfY29uZyldIDwtIDAKZm9yZmEkbWVhbl9tb3ZlZFtpcy5uYShmb3JmYSRtZWFuX21vdmVkKV0gPC0gMApmb3JmYSRtZWFuX2ludGVyZXN0aW5nW2lzLm5hKGZvcmZhJG1lYW5faW50ZXJlc3RpbmcpXSA8LSAwCgojIERvIHRlc3RzIHRvIGRldGVybWluZSBzdWl0YWJpbGl0eSBmb3IgRkEKcHJpbnQoIktNTyIpCktNTyhyPWNvcihmb3JmYSkpCnByaW50KCJCYXJ0bGV0dCIpCmNvcnRlc3QuYmFydGxldHQoZm9yZmEpCnByaW50KCJEZXRlcm1pbmFudCIpCmRldChjb3IoZm9yZmEpKQpgYGAKS2Fpc2Vy4oCZcyAoMTk3NCkgZ3VpZGVsaW5lcywgc3VnZ2VzdCBjdXRvZmYgb2YgS01PIOKJpSA2MCBmb3IgZGV0ZXJtaW5pbmcgdGhlIGZhY3RvcmFiaWxpdHkgb2YgdGhlIHNhbXBsZSBkYXRhLiBIZXJlIHdhcyBhcmUgd2VsbCBhYm92ZSwgc3VnZ2VzdGluZyBzdWl0YWJpbGl0eSBmb3IgRkEuIApQIHZhbHVlIGZvciBCYXJ0bGV0dCdzIHRlc3QgaXMgc2lnbmlmaWNhbnQuIERldGVybWluYW50IGlzIHBvc2l0aXZlLCBpbmRpY2F0aW5nIEZBIHdpbGwgbGlrZWx5IHJ1bi4KCiMjIERldGVybWluZSBudW1iZXIgb2YgZmFjdG9ycwpgYGB7cn0KZmFmaXRmcmVlIDwtIGZhKGZvcmZhLCBuZmFjdG9ycyA9IG5jb2woZm9yZmEpLCByb3RhdGUgPSAibm9uZSIpCm5fZmFjdG9ycyA8LSBsZW5ndGgoZmFmaXRmcmVlJGUudmFsdWVzKQpzY3JlZSAgICAgPC0gZGF0YS5mcmFtZSgKICBGYWN0b3JfbiA9ICBhcy5mYWN0b3IoMTpuX2ZhY3RvcnMpLCAKICBFaWdlbnZhbHVlID0gZmFmaXRmcmVlJGUudmFsdWVzKQpnZ3Bsb3Qoc2NyZWUsIGFlcyh4ID0gRmFjdG9yX24sIHkgPSBFaWdlbnZhbHVlLCBncm91cCA9IDEpKSArIAogIGdlb21fcG9pbnQoKSArIGdlb21fbGluZSgpICsKICB4bGFiKCJOdW1iZXIgb2YgZmFjdG9ycyIpICsKICB5bGFiKCJJbml0aWFsIGVpZ2VudmFsdWUiKSArCiAgbGFicyggdGl0bGUgPSAiU2NyZWUgUGxvdCIsIAogICAgICAgIHN1YnRpdGxlID0gIihCYXNlZCBvbiB0aGUgdW5yZWR1Y2VkIGNvcnJlbGF0aW9uIG1hdHJpeCkiKQpgYGAKCgpgYGB7cn0KZmEubm9uZSA8LSBmYShyPWZvcmZhLCAKICAgICAgICAgICAgICBuZmFjdG9ycyA9IDEsIAogICAgICAgICAgICAgIGZtPSJwYSIsICMgdHlwZSBvZiBmYWN0b3IgYW5hbHlzaXMgd2Ugd2FudCB0byB1c2UgKOKAnHBh4oCdIGlzIHByaW5jaXBhbCBheGlzIGZhY3RvcmluZykKICAgICAgICAgICAgICBtYXguaXRlcj0xMDAsCiAgICAgICAgICAgICAgcm90YXRlPSJ2YXJpbWF4IikgIyBub25lIHJvdGF0aW9uCnByaW50KGZhLm5vbmUpCmBgYAoKIyMgQ29uY2F0ZW5hdGUgc2NvcmVzIHdpdGggb3RoZXIgZGF0YQpgYGB7cn0Kel9tZWFuc1snZmFjdG9yX3Njb3JlJ10gPC0gZmEubm9uZSRzY29yZXMKYGBgCgojIyBSdW4gc2FtZSBhbm92YSBhbmFseXNlcyBhcyBhYm92ZSBidXQgb24gZmFjdG9yIHNjb3JlCmBgYHtyfQpwID0gcGxvdFJpZGdlcyh6X21lYW5zLCAiY29uZGl0aW9uIiwgImZhY3Rvcl9zY29yZSIsICIiLCAiQ29uZGl0aW9uIiwgIk1lYW4gRmFjdG9yIFNjb3JlIikKcnVuYW92KCJleHBfc3ViamVjdF9pZCIsImZhY3Rvcl9zY29yZSIsIHpfbWVhbnMsICJjb25kaXRpb24iKSAKZmFjdG9yUGxvdCA9IHAgKyBzdGF0X2NvbXBhcmVfbWVhbnMoY29tcGFyaXNvbnMgPSBteV9jb21wYXJpc29ucywgbGFiZWwgPSAicC5zaWduaWYiLCBtZXRob2QgPSAidC50ZXN0IiwgcGFpcmVkPSJUcnVlIiwgbmEucm09VFJVRSkKZmFjdG9yUGxvdCA9IGZhY3RvclBsb3QgKyBsYWJzKHkgPSAiTWVhbiBGYWN0b3IgU2NvcmUgKEFlc3RoZXRpYyBFeHBlcmllbmNlKSIpCmZhY3RvclBsb3QKYGBgCkl0IGJhc2ljYWxseSBtaW1pY3MgZW5qb3ltZW50IHJlc3VsdHMsIGFzIHRoYXQgaXRlbSBoYXMgaGlnaGVzdCBmYWN0b3IgbG9hZGluZy4gQnV0IHRoZXJlIHdhcyBjbGVhcmx5IHNvbWV0aGluZyBtb3JlIGludGVyZXN0aW5nIGdvaW5nIG9uIHdpdGggYWxsIG9mIHRoZSBzbWFsbCBkaWZmZXJlbmNlcyBpbiB0aGUgQU5PVkFzIHJlcG9ydGVkIGFib3ZlCgoKYGBge3J9CnJhdGluZ3MgPSB6X21lYW5zWyAsIC13aGljaChuYW1lcyh6X21lYW5zKSAlaW4lIGMoImV4cF9zdWJqZWN0X2lkIiwiY29uZGl0aW9uIiwgIm1lYW5fY29ycmVzcCIpKV0gIyBkcm9wIGxhYmVsIGNvbHVtbnMgYW5kIG9uZXMgbm90IHVzaW5nCnJhdGluZ3MkbWVhbl90aW1lc3BlbnQgPSBsb2cocmF0aW5ncyRtZWFuX3RpbWVzcGVudCkKCnBhcihtZnJvdyA9IGMoMywxKSkKY2hhcnQuQ29ycmVsYXRpb24ocmF0aW5ncywgaGlzdG9ncmFtPVRSVUUsIHBjaD0yNSwgdGV4dC5wYW5lbD1sYWJzKQpmYS5kaWFncmFtKGZhLm5vbmUsIGRpZ2l0cz0yLCBjdXQgPSAuMywgc2ltcGxlPVRSVUUpCiNmYWN0b3JQbG90CmBgYAoKCiMgRXhwbG9yYXRvcnkgYW5hbHlzaXMKCiMjIyBSZWxhdGlvbnNoaXAgYmV0d2VlbiBwZXJzb25hbCB2YXJpYWJsZXMgYW5kIHRpbWUgc3BlbnQgLyBmZWVsaW5nIG1vdmVkIChhbGwgY29uZGl0aW9ucykKYGBge3J9CiMgbWVyZ2UgbWVhbiB0YWJsZSBhbmQgcGFydGljaXBhbnQgbGV2ZWwgdGFibGUKZGYgPSBwYWxsCgojIHBsb3QgcmVsYXRpb24gYmV0d2VlbiBhcmVhIGFuZCBmZWVsaW5nIG1vdmVkCnAgPC0gZ2dwbG90KGRmLCBhZXMoeD1hcmVhX2NvbXBvc2l0ZSwgeT1tZWFuX21vdmVkKSkgKwogIGdlb21fcG9pbnQoKSArIGdlb21fc21vb3RoKG1ldGhvZD1sbSAsIGNvbG9yPSJibGFjayIsIGZpbGw9ImdyYXkiLCBzZT1UUlVFKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikgKyB0aGVtZV9jbGFzc2ljKCkKCiMgQ3VzdG9tIG1hcmdpbmFsIHBsb3RzOgpwMiA8LSBnZ01hcmdpbmFsKHAsIHR5cGU9ImRlbnNpZ3JhbSIsIGZpbGwgPSAiZ3JheSIpIApwMiAKCgojIHBsb3QgcmVsYXRpb24gYmV0d2VlbiBhcmVhIGFuZCB0aW1lc3BlbnQKcCA8LSBnZ3Bsb3QoZGYsIGFlcyh4PWFyZWFfY29tcG9zaXRlLCB5PW1lYW5fdGltZXNwZW50KSkgKwogIGdlb21fcG9pbnQoKSArIGdlb21fc21vb3RoKG1ldGhvZD1sbSAsIGNvbG9yPSJibGFjayIsIGZpbGw9ImdyYXkiLCBzZT1UUlVFKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikgKyB0aGVtZV9jbGFzc2ljKCkKCiMgQ3VzdG9tIG1hcmdpbmFsIHBsb3RzOgpwMiA8LSBnZ01hcmdpbmFsKHAsIHR5cGU9ImRlbnNpZ3JhbSIsIGZpbGwgPSAiZ3JheSIpIApwMiAKCmBgYApJIHdvdWxkIGhhdmUgZXhwZWN0ZWQgYSByZWxhdGlvbnNoaXAgYmV0d2VlbiBBUmVBIGFuZCBzb21lIG9mIHRoZSBhZXN0aGV0aWMgbWVhc3VyZXMuIApQZXJoYXBzIEFSZUEgbW9yZSByZWxldmFudCBmb3IgdmlzdWFsIG1vZGFsaXR5LiBCcmVhayBvdXQgYnkgbW9kYWxpdHk/IAoKIyMjIFZpc3VhbC1vbmx5IGRhdGEKYGBge3J9CiMgbWVyZ2UgbWVhbiB0YWJsZSBhbmQgcGFydGljaXBhbnQgbGV2ZWwgdGFibGUKIyBwdmlzID0gcGFsbFssIHBhbGwkY29uZGl0aW9uID09ICdWaXN1YWwnXQojIGRmID0gcHZpcwoKCnB2aXMgPC0gcGFsbCAlPiUKICBmaWx0ZXIoY29uZGl0aW9uID09ICJWaXN1YWwiKQoKZGYgPSBwdmlzCgojIHBsb3QgcmVsYXRpb24gYmV0d2VlbiBhcmVhIGFuZCBmZWVsaW5nIG1vdmVkCnAgPC0gZ2dwbG90KGRmLCBhZXMoeD1hcmVhX2NvbXBvc2l0ZSwgeT1tZWFuX21vdmVkKSkgKwogIGdlb21fcG9pbnQoKSArIGdlb21fc21vb3RoKG1ldGhvZD1sbSAsIGNvbG9yPSJibGFjayIsIGZpbGw9ImdyYXkiLCBzZT1UUlVFKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikgKyB0aGVtZV9jbGFzc2ljKCkKCiMgQ3VzdG9tIG1hcmdpbmFsIHBsb3RzOgpwMiA8LSBnZ01hcmdpbmFsKHAsIHR5cGU9ImRlbnNpZ3JhbSIsIGZpbGwgPSAiZ3JheSIpIApwMiAKCgojIHBsb3QgcmVsYXRpb24gYmV0d2VlbiBhcmVhIGFuZCB0aW1lc3BlbnQKcCA8LSBnZ3Bsb3QoZGYsIGFlcyh4PWFyZWFfY29tcG9zaXRlLCB5PW1lYW5fdGltZXNwZW50KSkgKwogIGdlb21fcG9pbnQoKSArIGdlb21fc21vb3RoKG1ldGhvZD1sbSAsIGNvbG9yPSJibGFjayIsIGZpbGw9ImdyYXkiLCBzZT1UUlVFKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikgKyB0aGVtZV9jbGFzc2ljKCkKCiMgQ3VzdG9tIG1hcmdpbmFsIHBsb3RzOgpwMiA8LSBnZ01hcmdpbmFsKHAsIHR5cGU9ImRlbnNpZ3JhbSIsIGZpbGwgPSAiZ3JheSIpIApwMiAKCmBgYAoKCgoKCgoK