1 ASD Group

2 Data processing

2.1 Packages

pacman::p_load(tidyverse, readxl, effsize, janitor, irr, dplyr, tidyr, ggplot2, openxlsx, RColorBrewer, car, semPlot,reshape2, mediation, afex, ez, lavaan, tidyLPA, compareGroups, car, emmeans, arsenal, Hmisc, factoextra, boot, lsr)

2.2 Data - ASD group

df_asd <- read_excel("C:/Users/louis/OneDrive/Área de Trabalho/Artigo 2 - Mestrado/df_asd.xlsx")

2.3 Check NA’s

variaveis <- c("go_no_go", "go_no_go_z", "stroop_a", "stroop_a_z", "stroop_a_errors", "stroop_a_errors_z", "stroop_b", "stroop_b_z",                "stroop_b_errors", "stroop_b_errors_z", "stroop_c", "stroop_c_z", "stroop_c_errors",
               "stroop_c_errors_z", "interference", "fdt_reading", "fdt_reading_z",
               "fdt_reading_errors", "fdt_reading_errors_z", "fdt_counting", "fdt_counting_z",
               "fdt_counting_errors", "fdt_counting_errors_z", "fdt_choosing", "fdt_choosing_z",
               "fdt_choosing_errors", "fdt_choosing_errors_z", "fdt_shifting", "fdt_shifting_z",
               "fdt_shifting_errors", "fdt_shifting_errors_z", "fdt_inhibition", "fdt_inhibition_z",
               "fdt_flexibility", "fdt_flexibility_z")


sapply(df_asd[variaveis], function(x) sum(is.na(x)))
             go_no_go            go_no_go_z              stroop_a            stroop_a_z       stroop_a_errors 
                    8                     8                     5                     8                     8 
    stroop_a_errors_z              stroop_b            stroop_b_z       stroop_b_errors     stroop_b_errors_z 
                    8                     8                    11                    11                    11 
             stroop_c            stroop_c_z       stroop_c_errors     stroop_c_errors_z          interference 
                    8                    11                    11                    11                     9 
          fdt_reading         fdt_reading_z    fdt_reading_errors  fdt_reading_errors_z          fdt_counting 
                   24                    24                    24                    24                    24 
       fdt_counting_z   fdt_counting_errors fdt_counting_errors_z          fdt_choosing        fdt_choosing_z 
                   24                    24                    24                    24                    24 
  fdt_choosing_errors fdt_choosing_errors_z          fdt_shifting        fdt_shifting_z   fdt_shifting_errors 
                   24                    24                    24                    24                    24 
fdt_shifting_errors_z        fdt_inhibition      fdt_inhibition_z       fdt_flexibility     fdt_flexibility_z 
                   24                    24                    24                    24                    24 

2.4 Imputation of missing values using the mean

df_asd[variaveis] <- lapply(df_asd[variaveis], function(x) {
  ifelse(is.na(x), mean(x, na.rm = TRUE), x)
})

2.5 Transform - Sociodemographic variables

df_asd <- df_asd %>%
  dplyr::mutate(
    sex = as.factor(sex),
    education_level = as.factor(education_level),
    comorbidities = as.factor(comorbidities),
    diagnosis = as.factor(diagnosis)
  )

2.6 Rename - Sex

df_asd <- df_asd %>%
  dplyr::mutate(
    sex = dplyr::recode_factor(sex, 
                               `1` = "Feminine", 
                               `2` = "Masculine")
  )

2.7 Transform in numeric

vars_to_convert <- c("go_no_go", "go_no_go_z", "stroop_a", "stroop_a_z", "stroop_a_errors", "stroop_a_errors_z",
                     "stroop_b", "stroop_b_z", "stroop_b_errors", "stroop_b_errors_z",
                     "stroop_c", "stroop_c_z", "stroop_c_errors", "stroop_c_errors_z",
                     "interference", "fdt_reading", "fdt_reading_z", "fdt_reading_errors",
                     "fdt_reading_errors_z", "fdt_counting", "fdt_counting_z", "fdt_counting_errors",
                     "fdt_counting_errors_z", "fdt_choosing", "fdt_choosing_z", "fdt_choosing_errors",
                     "fdt_choosing_errors_z", "fdt_shifting", "fdt_shifting_z", "fdt_shifting_errors",
                     "fdt_shifting_errors_z", "fdt_inhibition", "fdt_inhibition_z", "fdt_flexibility",
                     "fdt_flexibility_z")

df_asd <- df_asd %>%
  mutate(across(all_of(vars_to_convert), ~ round(as.numeric(.), 2)))

2.8 Creating medication subgroups

df_asd <- df_asd %>%
  dplyr::mutate(
    medication_class = case_when(
      !is.na(initial_medication) & initial_medication %in% c("Ritalina") ~ "Psychostimulants",
      !is.na(initial_medication) & initial_medication %in% c("Atentah") ~ "Non-stimulants (ADHD)",
      !is.na(initial_medication) & initial_medication %in% c("Risperdal", "Risperidona", "Risperidona e Escitalopram", 
                                                             "Risperidona e Quetiapina", "Neuleptil", "neuleptil", "Neozine") ~ "Antipsychotics",
      !is.na(initial_medication) & initial_medication %in% c("Fluoxetina", "Sertralina", "Daforin", "Escitalopram") ~ "Antidepressants",
      !is.na(initial_medication) & initial_medication %in% c("Topiramato") ~ "Mood stabilizers",
      !is.na(initial_medication) & initial_medication %in% c("without medication", "N-Miss") ~ "No medication",
      FALSE ~ "Others" 
    )
  )
df_asd <- df_asd %>%
  dplyr::mutate(
    sex = as.factor(sex),
    education_level = as.factor(education_level),
    comorbidities = as.factor(comorbidities),
    diagnosis = as.factor(diagnosis)
  )
df_asd <- df_asd %>%
  dplyr::mutate(
    psychomotor_agitation = as.factor(psychomotor_agitation),
    restlessness = as.factor(restlessness),
    impulsiveness = as.factor(impulsiveness),
    inattention = as.factor(inattention),
    verbal_aggressiveness = as.factor(verbal_aggressiveness),
    physical_aggressiveness = as.factor(physical_aggressiveness),
    difficulty_with_frustration = as.factor(difficulty_with_frustration),
    restricted_patterns = as.factor(restricted_patterns),
    behavioral_inflexibility = as.factor(behavioral_inflexibility),
    repetitive_patterns = as.factor(repetitive_patterns),
    social_difficulty = as.factor(social_difficulty),
    speech_delay = as.factor(speech_delay),
    depression_symptoms = as.factor(depression_symptoms),
    anxiety_symptoms = as.factor(anxiety_symptoms)
  )

3 Data Analysis

3.1 Check - participants characteristics

df_asd %>%
  dplyr::select(age, sex,education_level, comorbidities, diagnosis, iq, verbal_index, performance_index, go_no_go_z,stroop_a_z, stroop_b_z, stroop_c_z,fdt_inhibition_z, fdt_flexibility_z) %>%
  arsenal::tableby(~ ., digits = 2, data = .) %>% summary(text= T) %>% 
  as.data.frame()

3.2 How many participants has a IQ <70?

 df_asd %>%
  dplyr::filter(iq < 70) %>%
  dplyr::summarise(count = n()) # São 8, sendo que 8 tiveram o diagnóstico de TEA e DI

3.3 Select data

df_selected <- df_asd %>%
  dplyr::select("go_no_go_z", "stroop_a_z", "stroop_b_z", "stroop_c_z", "fdt_inhibition_z")

3.4 Clustering (traditional)

3.4.1 How many classes?

fviz_nbclust(df_selected, kmeans, method = "wss")+
  geom_vline(xintercept = 4, linetype = 2) # incialmente sugerem quatro 

set.seed(123)
km.res <- kmeans(df_selected, 3, nstart = 25)

palette <- c("#255293", "#db0a16", "#f8c72d")

# Visualize
library(factoextra)

fviz_cluster(km.res, data = df_selected,
             ellipse.type = "convex",
             #palette = palette,
             ggtheme = theme_minimal())


fviz_cluster(km.res, data=df_selected,
             palette = c("#2E9FDF", "#00AFBB", "#E7B800", "#FC4E07"),
             ellipse.type="euclid",
             star.plot=TRUE,
             repel=TRUE,
             ggtheme=theme_minimal()
             )

3.4.2 Final model

#set.seed(123)
#lpa_exploratory = estimate_profiles(df_selected,1:5, package = "MplusAutomation",
                     # variances = c("equal", "varying"),
                     # covariances = c("zero", "varying"))
#compare_solutions(lpa_exploratory,statistics = c("LogLik","AWE", "AIC", "BIC", "SABIC", "BLRT_val", "BLRT_p","Entropy"))

Now I’ll run this solution

mod_lap = estimate_profiles(df_selected, n_profiles = 3)
get_fit(mod_lap)
get_estimates(mod_lap)
df_cluster = get_data(mod_lap)
tabyl(df_cluster$Class)
 df_cluster$Class  n   percent
                1 28 0.5283019
                2 11 0.2075472
                3 14 0.2641509

3.4.3 Plot fit

prof_estimates <- get_estimates(mod_lap)
prof_estimates %>%
  filter(Category == "Means") %>%
  mutate(Class = str_replace_all(Class, "^", "Profile "),
         Parameter = str_remove_all(Parameter, "_centered")) %>%
  mutate(Parameter = str_remove_all(Parameter, "_zscore")) %>%
  mutate(Parameter = str_remove_all(Parameter, "(total)")) %>%
  mutate(Parameter = str_remove_all(Parameter, "\\(.*")) %>%
  ggplot(aes(x = Class, y = Estimate, group = Parameter, fill = Parameter)) +
  geom_bar(stat = "summary", position = "dodge") +
  theme_light() +
  theme(legend.position = "bottom") +
  scale_fill_grey(start = 0, end = .9) +
  scale_y_continuous(limits = c(NA, 2), breaks = scales::pretty_breaks(n = 5))

bind_cols(
  df_asd %>% dplyr::select("diagnosis"),
  df_cluster
)
 bind_cols(
  df_asd %>% dplyr::select(diagnosis),
  df_cluster
) %>% 
  tabyl(diagnosis, Class, show_na = FALSE) %>% 
  adorn_percentages("row") %>% 
  adorn_pct_formatting(digits = 1) %>% 
  adorn_ns()
 diagnosis          1         2          3
       ASD 60.5% (23) 13.2% (5) 26.3% (10)
  ASD+ADHD 40.0%  (2) 20.0% (1) 40.0%  (2)
   ASD+IDD 30.0%  (3) 50.0% (5) 20.0%  (2)

4 Predictors

df_asd <- bind_cols(
  df_asd,
  df_cluster %>% dplyr::select("Class")
)
rm(res)
Warning: objeto 'res' não encontrado
res<-compareGroups(Class ~ age + sex + iq + verbal_index + performance_index + fdt_flexibility_z + working_memory_index + processing_speed_index, data=df_asd)
createTable(res)

--------Summary descriptives table by 'Class'---------

_______________________________________________________________________ 
                            1            2            3       p.overall 
                           N=28         N=11         N=14               
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ 
age                    10.1 (2.73)  8.91 (1.87)  10.6 (2.28)    0.233   
sex:                                                            0.360   
    Feminine            7 (25.0%)    3 (27.3%)    1 (7.14%)             
    Masculine           21 (75.0%)   8 (72.7%)    13 (92.9%)            
iq                     89.1 (19.5)  83.0 (18.7)  83.3 (10.7)    0.479   
verbal_index           85.9 (21.0)  79.7 (19.2)  85.3 (12.1)    0.644   
performance_index      94.1 (17.4)  88.7 (18.6)  87.2 (12.2)    0.396   
fdt_flexibility_z      -1.02 (0.76) -1.75 (0.81) -0.81 (0.93)   0.016   
working_memory_index   85.6 (17.2)  79.9 (11.3)  86.3 (20.0)    0.640   
processing_speed_index 93.0 (14.8)  80.8 (15.1)  90.5 (12.2)    0.111   
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ 

4.1 Getting to Know the People in the Clusters

df_asd %>% 
  dplyr::select(age, sex,education_level, comorbidities, diagnosis, iq, verbal_index, performance_index, go_no_go_z,stroop_a_z, stroop_b_z, stroop_c_z,fdt_inhibition_z, fdt_flexibility_z, working_memory_index, processing_speed_index) %>%
  arsenal::tableby(df_asd $Class ~ .,  digits=2, data = .) %>% summary(text= T)%>% as.data.frame()

4.2 Medication use

df_asd %>% 
  dplyr::select(medication_class) %>%
  arsenal::tableby(df_asd $Class ~ .,  digits=2, data = .) %>% summary(text= T)%>% as.data.frame()

4.3 Plot - Medication use

df_pizza <- df_asd %>%
  filter(!is.na(medication_class) & medication_class != "Others") %>%  # Remove NAs e "Others"
  group_by(Class, medication_class) %>%
  summarise(count = n()) %>%
  mutate(percentage = count / sum(count) * 100)
`summarise()` has grouped output by 'Class'. You can override using the `.groups` argument.
ggplot(df_pizza, aes(x = "", y = percentage, fill = medication_class)) +
  geom_bar(stat = "identity", width = 1, color = "white") +
  coord_polar(theta = "y") +
  facet_wrap(~ Class, ncol = 3) +  # Coloca os gráficos lado a lado (3 colunas)
  labs(
    title = "Distribution of Medication Classes by Class",
    fill = "Medication Class",
    y = "",
    x = ""
  ) +
  geom_text(aes(label = paste0(round(percentage, 1), "%")), 
            position = position_stack(vjust = 0.5), 
            size = 4, color = "black") + # Rótulos de porcentagem no centro das fatias
  theme_minimal() +
  theme(
    plot.title = element_text(size = 16, face = "bold", hjust = 0.5), # Centraliza e aumenta o título
    strip.text = element_text(size = 14, face = "bold"), # Aumenta o texto das facetas
    axis.text = element_blank(),
    axis.ticks = element_blank(),
    panel.grid = element_blank(),
    legend.title = element_text(size = 12, face = "bold"), # Ajusta o tamanho do título da legenda
    legend.text = element_text(size = 10),
    legend.position = "bottom"  # Move a legenda para baixo
  ) +
  guides(fill = guide_legend(title.position = "top", title.hjust = 0.5)) # Centraliza o título da legenda

NA
NA

4.4 Behavioral information

df_asd %>%
  dplyr::select(
    psychomotor_agitation, restlessness, impulsiveness, inattention, verbal_aggressiveness, 
    physical_aggressiveness, difficulty_with_frustration, restricted_patterns, behavioral_inflexibility, 
    repetitive_patterns, social_difficulty, speech_delay, depression_symptoms, anxiety_symptoms
  ) %>%
  arsenal::tableby(df_asd$Class ~ ., digits = 2, data = .) %>%
  summary(text = TRUE) %>%
  as.data.frame()
df_pizza_2 <- df_asd %>%
  dplyr::select(
    psychomotor_agitation, restlessness, impulsiveness, inattention, verbal_aggressiveness, 
    physical_aggressiveness, difficulty_with_frustration, restricted_patterns, behavioral_inflexibility, 
    repetitive_patterns, social_difficulty, speech_delay, depression_symptoms, anxiety_symptoms, Class
  ) %>%
  gather(key = "behavior", value = "score", -Class) %>%
  mutate(score = as.numeric(score)) %>%  # Garantir que 'score' seja numérico
  group_by(Class, behavior) %>%
  summarise(total_score = sum(score, na.rm = TRUE)) %>%
  group_by(Class) %>%
  mutate(percentage = total_score / sum(total_score) * 100)
`summarise()` has grouped output by 'Class'. You can override using the `.groups` argument.
custom_colors <- c(
  "#66c2a5", "#fc8d62", "#8da0cb", "#e78ac3", "#a6d854",
  "#ffd92f", "#e5c494", "#b3b3b3", "#a6cee3", "#1f78b4",
  "#b2df8a", "#33a02c", "#fb9a99", "#e31a1c", "#fdbf6f"
)

options(repr.plot.width = 12, repr.plot.height = 8)

ggplot(df_pizza_2, aes(x = Class, y = percentage, fill = behavior)) +
  geom_bar(stat = "identity", position = "dodge", color = "gray80") +
  labs(
    title = "Distribution of Symptoms by Groups",
    fill = "Symptom",
    y = "Percentage",
    x = "Class"
  ) +
  geom_text(aes(label = paste0(round(percentage, 1), "%")), 
            position = position_dodge(width = 0.8), 
            size = 3.5, color = "black") +
  theme_minimal(base_size = 14) +
  theme(
    plot.title = element_text(size = 18, face = "bold", hjust = 0.5),
    axis.text.x = element_text(size = 12, face = "bold"),
    axis.text.y = element_text(size = 12),
    legend.title = element_text(size = 14, face = "bold"),
    legend.text = element_text(size = 12),
    legend.position = "bottom",
    legend.key.size = unit(0.8, "cm")
  ) +
  scale_fill_manual(values = custom_colors) + # Aplicando cores personalizadas
  guides(fill = guide_legend(nrow = 2, byrow = TRUE))

4.5 ANOVA - Stroop

anova_stroop_a <- aov(stroop_a_z ~ Class, data = df_asd)
anova_stroop_b <- aov(stroop_b_z ~ Class, data = df_asd)
anova_stroop_c <- aov(stroop_c_z ~ Class, data = df_asd)

# Resumo dos resultados
summary(anova_stroop_a)
            Df Sum Sq Mean Sq F value Pr(>F)  
Class        1  21.11  21.114   4.987   0.03 *
Residuals   51 215.95   4.234                 
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
summary(anova_stroop_b) # diferença significativa
            Df Sum Sq Mean Sq F value Pr(>F)  
Class        1   8.54   8.536   4.452 0.0398 *
Residuals   51  97.79   1.918                 
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
summary(anova_stroop_c) # diferença significativa 
            Df Sum Sq Mean Sq F value Pr(>F)  
Class        1  11.17  11.169   4.124 0.0475 *
Residuals   51 138.11   2.708                 
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
# Post-hoc usando Tukey HSD para uma das variáveis
posthoc_a <- emmeans(anova_stroop_a, pairwise ~ Class)
posthoc_a
$emmeans
 Class emmean    SE df lower.CL upper.CL
  1.74  -1.37 0.283 51    -1.94   -0.802

Confidence level used: 0.95 

$contrasts
 contrast  estimate SE df z.ratio p.value
 (nothing)   nonEst NA NA      NA      NA
# ANOVA para cada variável
anova_go_no_go <- aov(go_no_go_z ~ Class, data = df_asd)

# Resumo dos resultados
summary(anova_go_no_go)
            Df Sum Sq Mean Sq F value Pr(>F)
Class        1   19.1  19.091   2.754  0.103
Residuals   51  353.5   6.932               
# Post-hoc usando Tukey HSD para uma das variáveis
posthoc_go <- emmeans(anova_go_no_go, pairwise ~ Class)
posthoc_go
$emmeans
 Class emmean    SE df lower.CL upper.CL
  1.74  -1.45 0.362 51    -2.18   -0.729

Confidence level used: 0.95 

$contrasts
 contrast  estimate SE df z.ratio p.value
 (nothing)   nonEst NA NA      NA      NA
# ANOVA para cada variável
anova_fdt  <- aov(fdt_inhibition_z ~ Class, data = df_asd)

# Resumo dos resultados
summary(anova_fdt)
            Df Sum Sq Mean Sq F value Pr(>F)  
Class        1   4.83   4.835   3.729  0.059 .
Residuals   51  66.12   1.297                 
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
# Post-hoc usando Tukey HSD para uma das variáveis
posthoc_fdt <- emmeans(anova_fdt, pairwise ~ Class)
posthoc_fdt
$emmeans
 Class emmean    SE df lower.CL upper.CL
  1.74  -1.26 0.156 51    -1.58   -0.948

Confidence level used: 0.95 

$contrasts
 contrast  estimate SE df z.ratio p.value
 (nothing)   nonEst NA NA      NA      NA

4.6 Correlation

# Selecionar variáveis
correlation_data <- df_asd %>%
  dplyr::select(go_no_go_z, stroop_a_z, stroop_b_z, stroop_c_z, fdt_inhibition_z, 
                fdt_flexibility_z, performance_index, working_memory_index)

# Matriz de correlação
correlation_matrix <- cor(correlation_data, use = "pairwise.complete.obs", method = "pearson")

# Visualização da matriz
library(corrplot)
corrplot::corrplot(correlation_matrix, method = "color", type = "upper", addCoef.col = "black", tl.col = "black")

# Obter matriz de correlações e valores-p
cor_results <- Hmisc::rcorr(as.matrix(correlation_data), type = "pearson")

# Matriz de correlações
cor_matrix <- cor_results$r

# Matriz de valores-p
p_matrix <- cor_results$P

# Criar matriz combinada com correlação e valores-p
combined_matrix <- paste0(
  format(round(cor_matrix, 2), nsmall = 2),  # Coeficiente de correlação
  " (p=", format(round(p_matrix, 3), nsmall = 3), ")"  # Valor-p
)

# Reformatar em formato de matriz
dim(combined_matrix) <- dim(cor_matrix)
rownames(combined_matrix) <- rownames(cor_matrix)
colnames(combined_matrix) <- colnames(cor_matrix)

# Visualizar matriz combinada
print(combined_matrix, quote = FALSE)
                     go_no_go_z      stroop_a_z      stroop_b_z      stroop_c_z      fdt_inhibition_z fdt_flexibility_z
go_no_go_z            1.00 (p=   NA)  0.09 (p=0.501)  0.11 (p=0.449)  0.18 (p=0.187)  0.29 (p=0.036)   0.21 (p=0.123)  
stroop_a_z            0.09 (p=0.501)  1.00 (p=   NA)  0.49 (p=0.000)  0.46 (p=0.001)  0.22 (p=0.121)   0.09 (p=0.522)  
stroop_b_z            0.11 (p=0.449)  0.49 (p=0.000)  1.00 (p=   NA)  0.72 (p=0.000)  0.14 (p=0.302)   0.31 (p=0.026)  
stroop_c_z            0.18 (p=0.187)  0.46 (p=0.001)  0.72 (p=0.000)  1.00 (p=   NA)  0.14 (p=0.301)   0.29 (p=0.034)  
fdt_inhibition_z      0.29 (p=0.036)  0.22 (p=0.121)  0.14 (p=0.302)  0.14 (p=0.301)  1.00 (p=   NA)   0.40 (p=0.003)  
fdt_flexibility_z     0.21 (p=0.123)  0.09 (p=0.522)  0.31 (p=0.026)  0.29 (p=0.034)  0.40 (p=0.003)   1.00 (p=   NA)  
performance_index    -0.11 (p=0.430)  0.10 (p=0.483)  0.16 (p=0.260) -0.12 (p=0.420) -0.04 (p=0.800)  -0.14 (p=0.325)  
working_memory_index  0.21 (p=0.151)  0.09 (p=0.551)  0.24 (p=0.099)  0.18 (p=0.217) -0.03 (p=0.813)   0.02 (p=0.901)  
                     performance_index working_memory_index
go_no_go_z           -0.11 (p=0.430)    0.21 (p=0.151)     
stroop_a_z            0.10 (p=0.483)    0.09 (p=0.551)     
stroop_b_z            0.16 (p=0.260)    0.24 (p=0.099)     
stroop_c_z           -0.12 (p=0.420)    0.18 (p=0.217)     
fdt_inhibition_z     -0.04 (p=0.800)   -0.03 (p=0.813)     
fdt_flexibility_z    -0.14 (p=0.325)    0.02 (p=0.901)     
performance_index     1.00 (p=   NA)    0.51 (p=0.000)     
working_memory_index  0.51 (p=0.000)    1.00 (p=   NA)     

5 Non-Clinical Group

5.1 Data

df_non_clinical <- read_excel("C:/Users/louis/Downloads/Controle - escolinha (Louise).xlsx")

5.2 Check NA’s

variaveis <- c("go_no_go", "go_no_go_z", "stroop_a", "stroop_a_z", "stroop_a_errors", "stroop_a_errors_z", "stroop_b", "stroop_b_z",                "stroop_b_errors", "stroop_b_errors_z", "stroop_c", "stroop_c_z", "stroop_c_errors",
               "stroop_c_errors_z", "interference", "fdt_reading", "fdt_reading_z",
               "fdt_reading_errors", "fdt_reading_errors_z", "fdt_counting", "fdt_counting_z",
               "fdt_counting_errors", "fdt_counting_errors_z", "fdt_choosing", "fdt_choosing_z",
               "fdt_choosing_errors", "fdt_choosing_errors_z", "fdt_shifting", "fdt_shifting_z",
               "fdt_shifting_errors", "fdt_shifting_errors_z", "fdt_inhibition", "fdt_inhibition_z",
               "fdt_flexibility", "fdt_flexibility_z")


sapply(df_non_clinical[variaveis], function(x) sum(is.na(x)))
             go_no_go            go_no_go_z              stroop_a            stroop_a_z       stroop_a_errors 
                    2                     3                     1                     1                     1 
    stroop_a_errors_z              stroop_b            stroop_b_z       stroop_b_errors     stroop_b_errors_z 
                    1                     1                     1                     1                     1 
             stroop_c            stroop_c_z       stroop_c_errors     stroop_c_errors_z          interference 
                    1                     1                     1                     1                     1 
          fdt_reading         fdt_reading_z    fdt_reading_errors  fdt_reading_errors_z          fdt_counting 
                    0                     0                     0                     0                     0 
       fdt_counting_z   fdt_counting_errors fdt_counting_errors_z          fdt_choosing        fdt_choosing_z 
                    0                     0                     0                     0                     0 
  fdt_choosing_errors fdt_choosing_errors_z          fdt_shifting        fdt_shifting_z   fdt_shifting_errors 
                    0                     0                     1                     1                     1 
fdt_shifting_errors_z        fdt_inhibition      fdt_inhibition_z       fdt_flexibility     fdt_flexibility_z 
                    1                     0                     0                     1                     1 

5.3 Transform in numeric

vars_to_convert <- c("go_no_go", "go_no_go_z", "stroop_a", "stroop_a_z", "stroop_a_errors", "stroop_a_errors_z",
                     "stroop_b", "stroop_b_z", "stroop_b_errors", "stroop_b_errors_z",
                     "stroop_c", "stroop_c_z", "stroop_c_errors", "stroop_c_errors_z",
                     "interference", "fdt_reading", "fdt_reading_z", "fdt_reading_errors",
                     "fdt_reading_errors_z", "fdt_counting", "fdt_counting_z", "fdt_counting_errors",
                     "fdt_counting_errors_z", "fdt_choosing", "fdt_choosing_z", "fdt_choosing_errors",
                     "fdt_choosing_errors_z", "fdt_shifting", "fdt_shifting_z", "fdt_shifting_errors",
                     "fdt_shifting_errors_z", "fdt_inhibition", "fdt_inhibition_z", "fdt_flexibility",
                     "fdt_flexibility_z")

df_non_clinical <- df_non_clinical %>%
  mutate(across(all_of(vars_to_convert), ~ round(as.numeric(.), 2)))

5.4 Imputation of missing values using the mean

#df_non_clinical[variaveis] <- lapply(df_non_clinical[variaveis], function(x) {
  #ifelse(is.na(x), mean(x, na.rm = TRUE), x)
#})

5.5 Rename - Sex

df_non_clinical <- df_non_clinical %>%
  dplyr::mutate(
    sex = dplyr::recode_factor(sex, 
                               `1` = "Feminine", 
                               `2` = "Masculine")
  )
df_non_clinical <- df_non_clinical %>%
  dplyr::mutate(
    sex = as.factor(sex),
    education_level = as.factor(education_level)
  )
df_non_clinical <- df_non_clinical %>%
  mutate_all(~ replace(., . == 999, NA))

5.6 Check - participants characteristics

df_non_clinical %>%
  dplyr::select(age, sex,education_level, iq, verbal_index, performance_index, go_no_go_z,stroop_a_z, stroop_b_z, stroop_c_z,fdt_inhibition_z, fdt_flexibility_z) %>%
  arsenal::tableby(~ ., digits = 2, data = .) %>% summary(text= T) %>% 
  as.data.frame()
df_selected_2 <- df_non_clinical %>%
  dplyr::select("go_no_go_z", "stroop_a_z", "stroop_b_z", "stroop_c_z", "fdt_inhibition_z")
df_selected_2 <- df_selected_2 %>%
  mutate_all(~ ifelse(is.na(.), mean(., na.rm = TRUE), .))

5.7 Clustering (traditional)

5.7.1 How many classes?

fviz_nbclust(df_selected_2, kmeans, method = "wss")+
  geom_vline(xintercept = 4, linetype = 2) # incialmente sugerem quatro 

set.seed(123)
km.res <- kmeans(df_selected_2, 3, nstart = 25)

palette <- c("#255293", "#db0a16", "#f8c72d")


fviz_cluster(km.res, data = df_selected_2,
             ellipse.type = "convex",
             #palette = palette,
             ggtheme = theme_minimal())


fviz_cluster(km.res, data=df_selected_2,
             palette = c("#2E9FDF", "#00AFBB", "#E7B800", "#FC4E07"),
             ellipse.type="euclid",
             star.plot=TRUE,
             repel=TRUE,
             ggtheme=theme_minimal()
             )

mod_lap_2 = estimate_profiles(df_selected_2, n_profiles = 2)
get_fit(mod_lap)
get_estimates(mod_lap_2)
df_cluster_2 = get_data(mod_lap_2)
tabyl(df_cluster_2$Class)
 df_cluster_2$Class  n   percent
                  1 34 0.7391304
                  2 12 0.2608696

5.7.2 Plot fit

prof_estimates <- get_estimates(mod_lap_2)
prof_estimates %>%
  filter(Category == "Means") %>%
  mutate(Class = str_replace_all(Class, "^", "Profile "),
         Parameter = str_remove_all(Parameter, "_centered")) %>%
  mutate(Parameter = str_remove_all(Parameter, "_zscore")) %>%
  mutate(Parameter = str_remove_all(Parameter, "(total)")) %>%
  mutate(Parameter = str_remove_all(Parameter, "\\(.*")) %>%
  ggplot(aes(x = Class, y = Estimate, group = Parameter, fill = Parameter)) +
  geom_bar(stat = "summary", position = "dodge") +
  theme_light() +
  theme(legend.position = "bottom") +
  scale_fill_grey(start = 0, end = .9) +
  scale_y_continuous(limits = c(NA, 2), breaks = scales::pretty_breaks(n = 5))

df_non_clinical<- bind_cols(
  df_non_clinical,
  df_cluster_2 %>% dplyr::select("Class")
)
rm(res)
res<-compareGroups(Class ~ age + sex + iq + verbal_index + performance_index + fdt_flexibility_z + working_memory_index + processing_speed_index, data=df_non_clinical)
Warning: Aproximação do qui-quadrado pode estar incorreta
createTable(res)

--------Summary descriptives table by 'Class'---------

__________________________________________________________ 
                            1            2       p.overall 
                           N=34         N=12               
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ 
age                    8.09 (1.31)  9.08 (1.31)    0.036   
sex:                                               0.513   
    Feminine            13 (38.2%)   6 (50.0%)             
    Masculine           21 (61.8%)   6 (50.0%)             
iq                     87.9 (13.6)  89.0 (16.7)    0.833   
verbal_index           82.8 (16.1)  80.6 (21.7)    0.796   
performance_index      93.2 (13.4)  99.8 (16.8)    0.333   
fdt_flexibility_z      -1.26 (1.75) -0.82 (1.06)   0.321   
working_memory_index   91.5 (13.6)  88.2 (10.2)    0.604   
processing_speed_index  100 (13.3)   101 (8.81)    0.954   
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ 

5.8 Getting to Know the People in the Clusters

df_non_clinical %>% 
  dplyr::select(age, sex,education_level, iq, verbal_index, performance_index, go_no_go_z,stroop_a_z, stroop_b_z, stroop_c_z,fdt_inhibition_z, fdt_flexibility_z, working_memory_index, processing_speed_index, cdi_classification,z_inattention, z_hyperactivity_impulsivity, z_general_anxiety) %>%
  arsenal::tableby(df_non_clinical $Class ~ .,  digits=2, data = .) %>% summary(text= T)%>% as.data.frame()

6 Comparing Groups (ASD vs Non Clinical Profiles)

6.1 Fixing the database

6.1.1 Create Group variable

df_non_clinical <- df_non_clinical %>%
  mutate(group = "non clinical")

df_asd <- df_asd %>%
  mutate(group = "asd")
df_combined <- bind_rows(df_non_clinical, df_asd)
df_combined %>% 
  dplyr::select(age, sex,education_level, iq, verbal_index, performance_index, go_no_go_z,stroop_a_z, stroop_b_z, stroop_c_z,fdt_inhibition_z, fdt_flexibility_z, working_memory_index, processing_speed_index, stroop_a_errors_z, stroop_b_errors_z, stroop_c_errors_z) %>%
  arsenal::tableby(df_combined $group ~ .,  digits=2, data = .) %>% summary(text= T)%>% as.data.frame()

6.2 ANCOVA

ancova_go_nc <- aov(go_no_go_z ~ group + iq + age, data = df_combined)
ancova_stroop_a_nc <- aov(stroop_a_z ~ group + iq + age + education_level, data = df_combined)
ancova_stroop_b_nc <- aov(stroop_b_z ~ group + iq + age + education_level, data = df_combined)
ancova_stroop_c_nc <- aov(stroop_c_z ~ group + iq + age + education_level, data = df_combined)
ancova_fdt_nc <- aov(fdt_inhibition_z ~ group + iq + age + education_level, data = df_combined)

# Resumo dos resultados
summary(ancova_go_nc)
            Df Sum Sq Mean Sq F value Pr(>F)   
group        1    5.2    5.20   1.230 0.2704   
iq           1    0.7    0.75   0.177 0.6750   
age          1   33.3   33.33   7.886 0.0061 **
Residuals   91  384.6    4.23                  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
4 observations deleted due to missingness
summary(ancova_stroop_a_nc)
                Df Sum Sq Mean Sq F value Pr(>F)
group            1   2.52   2.522   0.735  0.394
iq               1   1.39   1.391   0.405  0.526
age              1   5.49   5.488   1.599  0.210
education_level 10  30.20   3.020   0.880  0.556
Residuals       80 274.65   3.433               
5 observations deleted due to missingness
summary(ancova_stroop_b_nc)
                Df Sum Sq Mean Sq F value Pr(>F)
group            1   0.53  0.5342   0.266  0.608
iq               1   0.45  0.4541   0.226  0.636
age              1   0.06  0.0581   0.029  0.865
education_level 10  20.82  2.0815   1.036  0.422
Residuals       80 160.75  2.0094               
5 observations deleted due to missingness
summary(ancova_stroop_c_nc)
                Df Sum Sq Mean Sq F value Pr(>F)
group            1   0.98   0.979   0.389  0.535
iq               1   0.12   0.116   0.046  0.830
age              1   4.96   4.960   1.970  0.164
education_level 10  23.35   2.335   0.927  0.513
Residuals       80 201.46   2.518               
5 observations deleted due to missingness
summary(ancova_fdt_nc)
                Df Sum Sq Mean Sq F value Pr(>F)  
group            1   0.02   0.021   0.007 0.9337  
iq               1   5.40   5.398   1.779 0.1860  
age              1   9.91   9.908   3.265 0.0745 .
education_level 10  28.17   2.817   0.928 0.5118  
Residuals       81 245.78   3.034                 
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
4 observations deleted due to missingness

6.3 ETA

eta_squared_go_nc <- etaSquared(ancova_go_nc)
eta_squared_stroop_a_nc <- etaSquared(ancova_stroop_a_nc)
eta_squared_stroop_b_nc <- etaSquared(ancova_stroop_b_nc)
eta_squared_stroop_c_nc <- etaSquared(ancova_stroop_c_nc)
eta_squared_fdt_nc <- etaSquared(ancova_fdt_nc)

# Exibir os resultados
eta_squared_go_nc
           eta.sq eta.sq.part
group 0.043201204  0.04544874
iq    0.009285187  0.01012968
age   0.078628401  0.07974684
eta_squared_stroop_a_nc
                      eta.sq  eta.sq.part
group           0.0110564752 0.0124926747
iq              0.0063720345 0.0072380512
age             0.0001255695 0.0001436548
education_level 0.0961047500 0.0990683862
eta_squared_stroop_b_nc
                      eta.sq  eta.sq.part
group           6.121838e-03 0.0069063647
iq              7.568578e-04 0.0008590502
age             8.782064e-05 0.0000997541
education_level 1.139865e-01 0.1146434307
eta_squared_stroop_c_nc
                      eta.sq  eta.sq.part
group           1.909123e-02 0.0214098140
iq              9.447366e-05 0.0001082535
age             9.810698e-03 0.0111178928
education_level 1.011577e-01 0.1038824582
eta_squared_fdt_nc
                      eta.sq  eta.sq.part
group           1.254345e-04 0.0001476127
iq              3.837007e-02 0.0432095896
age             9.344139e-05 0.0001099670
education_level 9.738935e-02 0.1028378823
df_long <- df_combined %>%
  pivot_longer(cols = c(go_no_go_z, stroop_a_z, stroop_b_z, stroop_c_z, fdt_inhibition_z),
               names_to = "variable",
               values_to = "value")

6.4 Plot - ASD x non clinical

# Reordene os níveis do fator para garantir que "asd" fique na frente
df_long$group <- factor(df_long$group, levels = c("non clinical", "asd"))

# Gráfico de densidade com marcadores em -1 e +1
ggplot(df_long, aes(x = value, fill = group)) +
  geom_density(alpha = 0.6, position = "identity") + # Curvas sobrepostas
  # Linhas verticais nos pontos -1 e +1
  geom_vline(xintercept = c(-1, 1), linetype = "dashed", color = "black", size = 0.8, alpha = 0.7, show.legend = FALSE) + # Linhas em -1 e +1
  facet_wrap(~ variable, scales = "free") +          # Uma curva para cada variável
  labs(title = "Distribution of Variables by Group",
       subtitle = "Score Z",
       x = "Standard-Distribuition",
       y = "Standard-Distribuition",
       fill = "Groups") +
  theme_minimal(base_size = 14) +
  theme(
    plot.title = element_text(hjust = 0.5, face = "bold"),
    plot.subtitle = element_text(hjust = 0.5, size = 12),
    legend.position = "top"
  ) +
  scale_fill_manual(values = c("#1f78b4", "#e31a1c")) + # Ajuste das cores dos grupos
  scale_x_continuous(breaks = seq(-5, 5, by = 1), limits = c(-5, 5)) # Ajuste dos marcadores do eixo X

NA
NA

7 The end

LS0tDQp0aXRsZTogIk1TIDIgLSBpbmhpYml0b3J5IGNvbnRyb2wiDQpEYXRlOiAwNi8xMi8yMDI0DQpvdXRwdXQ6DQogIGh0bWxfbm90ZWJvb2s6DQogICAgY3NzOiBlc3RpbG8uY3NzDQogICAgY29kZV9mb2xkaW5nOiBoaWRlDQogICAgdGhlbWU6IHNhbmRzdG9uZQ0KICAgIHRvYzogdHJ1ZQ0KICAgIHRvY19mbG9hdDoNCiAgICAgIGNvbGxhcHNlZDogdHJ1ZQ0KICAgICAgc21vb3RoX3Njcm9sbDogZmFsc2UNCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUNCiAgICBmaWdfY2FwdGlvbjogdHJ1ZQ0KICAgIGhpZ2hsaWdodDogdGFuZ28NCiAgaHRtbF9kb2N1bWVudDoNCiAgICB0b2M6IHRydWUNCiAgcGRmX2RvY3VtZW50Og0KICAgIHRvYzogdHJ1ZQ0KLS0tDQoNCg0KIyBBU0QgR3JvdXANCg0KIyBEYXRhIHByb2Nlc3NpbmcNCg0KIyMgUGFja2FnZXMNCg0KYGBge3J9DQpwYWNtYW46OnBfbG9hZCh0aWR5dmVyc2UsIHJlYWR4bCwgZWZmc2l6ZSwgamFuaXRvciwgaXJyLCBkcGx5ciwgdGlkeXIsIGdncGxvdDIsIG9wZW54bHN4LCBSQ29sb3JCcmV3ZXIsIGNhciwgc2VtUGxvdCxyZXNoYXBlMiwgbWVkaWF0aW9uLCBhZmV4LCBleiwgbGF2YWFuLCB0aWR5TFBBLCBjb21wYXJlR3JvdXBzLCBjYXIsIGVtbWVhbnMsIGFyc2VuYWwsIEhtaXNjLCBmYWN0b2V4dHJhLCBib290LCBsc3IpDQpgYGANCg0KIyMgRGF0YSAtIEFTRCBncm91cA0KYGBge3J9DQpkZl9hc2QgPC0gcmVhZF9leGNlbCgiQzovVXNlcnMvbG91aXMvT25lRHJpdmUvw4FyZWEgZGUgVHJhYmFsaG8vQXJ0aWdvIDIgLSBNZXN0cmFkby9kZl9hc2QueGxzeCIpDQpgYGANCg0KIyMgQ2hlY2sgTkEncw0KYGBge3J9DQp2YXJpYXZlaXMgPC0gYygiZ29fbm9fZ28iLCAiZ29fbm9fZ29feiIsICJzdHJvb3BfYSIsICJzdHJvb3BfYV96IiwgInN0cm9vcF9hX2Vycm9ycyIsICJzdHJvb3BfYV9lcnJvcnNfeiIsICJzdHJvb3BfYiIsICJzdHJvb3BfYl96IiwgICAgICAgICAgICAgICAgInN0cm9vcF9iX2Vycm9ycyIsICJzdHJvb3BfYl9lcnJvcnNfeiIsICJzdHJvb3BfYyIsICJzdHJvb3BfY196IiwgInN0cm9vcF9jX2Vycm9ycyIsDQogICAgICAgICAgICAgICAic3Ryb29wX2NfZXJyb3JzX3oiLCAiaW50ZXJmZXJlbmNlIiwgImZkdF9yZWFkaW5nIiwgImZkdF9yZWFkaW5nX3oiLA0KICAgICAgICAgICAgICAgImZkdF9yZWFkaW5nX2Vycm9ycyIsICJmZHRfcmVhZGluZ19lcnJvcnNfeiIsICJmZHRfY291bnRpbmciLCAiZmR0X2NvdW50aW5nX3oiLA0KICAgICAgICAgICAgICAgImZkdF9jb3VudGluZ19lcnJvcnMiLCAiZmR0X2NvdW50aW5nX2Vycm9yc196IiwgImZkdF9jaG9vc2luZyIsICJmZHRfY2hvb3NpbmdfeiIsDQogICAgICAgICAgICAgICAiZmR0X2Nob29zaW5nX2Vycm9ycyIsICJmZHRfY2hvb3NpbmdfZXJyb3JzX3oiLCAiZmR0X3NoaWZ0aW5nIiwgImZkdF9zaGlmdGluZ196IiwNCiAgICAgICAgICAgICAgICJmZHRfc2hpZnRpbmdfZXJyb3JzIiwgImZkdF9zaGlmdGluZ19lcnJvcnNfeiIsICJmZHRfaW5oaWJpdGlvbiIsICJmZHRfaW5oaWJpdGlvbl96IiwNCiAgICAgICAgICAgICAgICJmZHRfZmxleGliaWxpdHkiLCAiZmR0X2ZsZXhpYmlsaXR5X3oiKQ0KDQoNCnNhcHBseShkZl9hc2RbdmFyaWF2ZWlzXSwgZnVuY3Rpb24oeCkgc3VtKGlzLm5hKHgpKSkNCg0KYGBgDQoNCg0KIyMgSW1wdXRhdGlvbiBvZiBtaXNzaW5nIHZhbHVlcyB1c2luZyB0aGUgbWVhbg0KYGBge3J9DQpkZl9hc2RbdmFyaWF2ZWlzXSA8LSBsYXBwbHkoZGZfYXNkW3ZhcmlhdmVpc10sIGZ1bmN0aW9uKHgpIHsNCiAgaWZlbHNlKGlzLm5hKHgpLCBtZWFuKHgsIG5hLnJtID0gVFJVRSksIHgpDQp9KQ0KYGBgDQoNCiMjIFRyYW5zZm9ybSAtIFNvY2lvZGVtb2dyYXBoaWMgdmFyaWFibGVzDQpgYGB7cn0NCmRmX2FzZCA8LSBkZl9hc2QgJT4lDQogIGRwbHlyOjptdXRhdGUoDQogICAgc2V4ID0gYXMuZmFjdG9yKHNleCksDQogICAgZWR1Y2F0aW9uX2xldmVsID0gYXMuZmFjdG9yKGVkdWNhdGlvbl9sZXZlbCksDQogICAgY29tb3JiaWRpdGllcyA9IGFzLmZhY3Rvcihjb21vcmJpZGl0aWVzKSwNCiAgICBkaWFnbm9zaXMgPSBhcy5mYWN0b3IoZGlhZ25vc2lzKQ0KICApDQpgYGANCg0KIyMgUmVuYW1lIC0gU2V4IA0KDQpgYGB7cn0NCmRmX2FzZCA8LSBkZl9hc2QgJT4lDQogIGRwbHlyOjptdXRhdGUoDQogICAgc2V4ID0gZHBseXI6OnJlY29kZV9mYWN0b3Ioc2V4LCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgMWAgPSAiRmVtaW5pbmUiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgMmAgPSAiTWFzY3VsaW5lIikNCiAgKQ0KYGBgDQoNCg0KIyMgVHJhbnNmb3JtIGluIG51bWVyaWMNCg0KYGBge3J9DQp2YXJzX3RvX2NvbnZlcnQgPC0gYygiZ29fbm9fZ28iLCAiZ29fbm9fZ29feiIsICJzdHJvb3BfYSIsICJzdHJvb3BfYV96IiwgInN0cm9vcF9hX2Vycm9ycyIsICJzdHJvb3BfYV9lcnJvcnNfeiIsDQogICAgICAgICAgICAgICAgICAgICAic3Ryb29wX2IiLCAic3Ryb29wX2JfeiIsICJzdHJvb3BfYl9lcnJvcnMiLCAic3Ryb29wX2JfZXJyb3JzX3oiLA0KICAgICAgICAgICAgICAgICAgICAgInN0cm9vcF9jIiwgInN0cm9vcF9jX3oiLCAic3Ryb29wX2NfZXJyb3JzIiwgInN0cm9vcF9jX2Vycm9yc196IiwNCiAgICAgICAgICAgICAgICAgICAgICJpbnRlcmZlcmVuY2UiLCAiZmR0X3JlYWRpbmciLCAiZmR0X3JlYWRpbmdfeiIsICJmZHRfcmVhZGluZ19lcnJvcnMiLA0KICAgICAgICAgICAgICAgICAgICAgImZkdF9yZWFkaW5nX2Vycm9yc196IiwgImZkdF9jb3VudGluZyIsICJmZHRfY291bnRpbmdfeiIsICJmZHRfY291bnRpbmdfZXJyb3JzIiwNCiAgICAgICAgICAgICAgICAgICAgICJmZHRfY291bnRpbmdfZXJyb3JzX3oiLCAiZmR0X2Nob29zaW5nIiwgImZkdF9jaG9vc2luZ196IiwgImZkdF9jaG9vc2luZ19lcnJvcnMiLA0KICAgICAgICAgICAgICAgICAgICAgImZkdF9jaG9vc2luZ19lcnJvcnNfeiIsICJmZHRfc2hpZnRpbmciLCAiZmR0X3NoaWZ0aW5nX3oiLCAiZmR0X3NoaWZ0aW5nX2Vycm9ycyIsDQogICAgICAgICAgICAgICAgICAgICAiZmR0X3NoaWZ0aW5nX2Vycm9yc196IiwgImZkdF9pbmhpYml0aW9uIiwgImZkdF9pbmhpYml0aW9uX3oiLCAiZmR0X2ZsZXhpYmlsaXR5IiwNCiAgICAgICAgICAgICAgICAgICAgICJmZHRfZmxleGliaWxpdHlfeiIpDQoNCmRmX2FzZCA8LSBkZl9hc2QgJT4lDQogIG11dGF0ZShhY3Jvc3MoYWxsX29mKHZhcnNfdG9fY29udmVydCksIH4gcm91bmQoYXMubnVtZXJpYyguKSwgMikpKQ0KDQpgYGANCg0KDQojIyBDcmVhdGluZyBtZWRpY2F0aW9uIHN1Ymdyb3Vwcw0KYGBge3J9DQpkZl9hc2QgPC0gZGZfYXNkICU+JQ0KICBkcGx5cjo6bXV0YXRlKA0KICAgIG1lZGljYXRpb25fY2xhc3MgPSBjYXNlX3doZW4oDQogICAgICAhaXMubmEoaW5pdGlhbF9tZWRpY2F0aW9uKSAmIGluaXRpYWxfbWVkaWNhdGlvbiAlaW4lIGMoIlJpdGFsaW5hIikgfiAiUHN5Y2hvc3RpbXVsYW50cyIsDQogICAgICAhaXMubmEoaW5pdGlhbF9tZWRpY2F0aW9uKSAmIGluaXRpYWxfbWVkaWNhdGlvbiAlaW4lIGMoIkF0ZW50YWgiKSB+ICJOb24tc3RpbXVsYW50cyAoQURIRCkiLA0KICAgICAgIWlzLm5hKGluaXRpYWxfbWVkaWNhdGlvbikgJiBpbml0aWFsX21lZGljYXRpb24gJWluJSBjKCJSaXNwZXJkYWwiLCAiUmlzcGVyaWRvbmEiLCAiUmlzcGVyaWRvbmEgZSBFc2NpdGFsb3ByYW0iLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUmlzcGVyaWRvbmEgZSBRdWV0aWFwaW5hIiwgIk5ldWxlcHRpbCIsICJuZXVsZXB0aWwiLCAiTmVvemluZSIpIH4gIkFudGlwc3ljaG90aWNzIiwNCiAgICAgICFpcy5uYShpbml0aWFsX21lZGljYXRpb24pICYgaW5pdGlhbF9tZWRpY2F0aW9uICVpbiUgYygiRmx1b3hldGluYSIsICJTZXJ0cmFsaW5hIiwgIkRhZm9yaW4iLCAiRXNjaXRhbG9wcmFtIikgfiAiQW50aWRlcHJlc3NhbnRzIiwNCiAgICAgICFpcy5uYShpbml0aWFsX21lZGljYXRpb24pICYgaW5pdGlhbF9tZWRpY2F0aW9uICVpbiUgYygiVG9waXJhbWF0byIpIH4gIk1vb2Qgc3RhYmlsaXplcnMiLA0KICAgICAgIWlzLm5hKGluaXRpYWxfbWVkaWNhdGlvbikgJiBpbml0aWFsX21lZGljYXRpb24gJWluJSBjKCJ3aXRob3V0IG1lZGljYXRpb24iLCAiTi1NaXNzIikgfiAiTm8gbWVkaWNhdGlvbiIsDQogICAgICBGQUxTRSB+ICJPdGhlcnMiIA0KICAgICkNCiAgKQ0KDQpgYGANCg0KDQpgYGB7cn0NCmRmX2FzZCA8LSBkZl9hc2QgJT4lDQogIGRwbHlyOjptdXRhdGUoDQogICAgc2V4ID0gYXMuZmFjdG9yKHNleCksDQogICAgZWR1Y2F0aW9uX2xldmVsID0gYXMuZmFjdG9yKGVkdWNhdGlvbl9sZXZlbCksDQogICAgY29tb3JiaWRpdGllcyA9IGFzLmZhY3Rvcihjb21vcmJpZGl0aWVzKSwNCiAgICBkaWFnbm9zaXMgPSBhcy5mYWN0b3IoZGlhZ25vc2lzKQ0KICApDQpgYGANCg0KDQpgYGB7cn0NCmRmX2FzZCA8LSBkZl9hc2QgJT4lDQogIGRwbHlyOjptdXRhdGUoDQogICAgcHN5Y2hvbW90b3JfYWdpdGF0aW9uID0gYXMuZmFjdG9yKHBzeWNob21vdG9yX2FnaXRhdGlvbiksDQogICAgcmVzdGxlc3NuZXNzID0gYXMuZmFjdG9yKHJlc3RsZXNzbmVzcyksDQogICAgaW1wdWxzaXZlbmVzcyA9IGFzLmZhY3RvcihpbXB1bHNpdmVuZXNzKSwNCiAgICBpbmF0dGVudGlvbiA9IGFzLmZhY3RvcihpbmF0dGVudGlvbiksDQogICAgdmVyYmFsX2FnZ3Jlc3NpdmVuZXNzID0gYXMuZmFjdG9yKHZlcmJhbF9hZ2dyZXNzaXZlbmVzcyksDQogICAgcGh5c2ljYWxfYWdncmVzc2l2ZW5lc3MgPSBhcy5mYWN0b3IocGh5c2ljYWxfYWdncmVzc2l2ZW5lc3MpLA0KICAgIGRpZmZpY3VsdHlfd2l0aF9mcnVzdHJhdGlvbiA9IGFzLmZhY3RvcihkaWZmaWN1bHR5X3dpdGhfZnJ1c3RyYXRpb24pLA0KICAgIHJlc3RyaWN0ZWRfcGF0dGVybnMgPSBhcy5mYWN0b3IocmVzdHJpY3RlZF9wYXR0ZXJucyksDQogICAgYmVoYXZpb3JhbF9pbmZsZXhpYmlsaXR5ID0gYXMuZmFjdG9yKGJlaGF2aW9yYWxfaW5mbGV4aWJpbGl0eSksDQogICAgcmVwZXRpdGl2ZV9wYXR0ZXJucyA9IGFzLmZhY3RvcihyZXBldGl0aXZlX3BhdHRlcm5zKSwNCiAgICBzb2NpYWxfZGlmZmljdWx0eSA9IGFzLmZhY3Rvcihzb2NpYWxfZGlmZmljdWx0eSksDQogICAgc3BlZWNoX2RlbGF5ID0gYXMuZmFjdG9yKHNwZWVjaF9kZWxheSksDQogICAgZGVwcmVzc2lvbl9zeW1wdG9tcyA9IGFzLmZhY3RvcihkZXByZXNzaW9uX3N5bXB0b21zKSwNCiAgICBhbnhpZXR5X3N5bXB0b21zID0gYXMuZmFjdG9yKGFueGlldHlfc3ltcHRvbXMpDQogICkNCmBgYA0KDQoNCg0KIyBEYXRhIEFuYWx5c2lzDQoNCiMjIENoZWNrIC0gcGFydGljaXBhbnRzIGNoYXJhY3RlcmlzdGljcyANCmBgYHtyfQ0KZGZfYXNkICU+JQ0KICBkcGx5cjo6c2VsZWN0KGFnZSwgc2V4LGVkdWNhdGlvbl9sZXZlbCwgY29tb3JiaWRpdGllcywgZGlhZ25vc2lzLCBpcSwgdmVyYmFsX2luZGV4LCBwZXJmb3JtYW5jZV9pbmRleCwgZ29fbm9fZ29feixzdHJvb3BfYV96LCBzdHJvb3BfYl96LCBzdHJvb3BfY196LGZkdF9pbmhpYml0aW9uX3osIGZkdF9mbGV4aWJpbGl0eV96KSAlPiUNCiAgYXJzZW5hbDo6dGFibGVieSh+IC4sIGRpZ2l0cyA9IDIsIGRhdGEgPSAuKSAlPiUgc3VtbWFyeSh0ZXh0PSBUKSAlPiUgDQogIGFzLmRhdGEuZnJhbWUoKQ0KYGBgDQoNCg0KIyMgSG93IG1hbnkgcGFydGljaXBhbnRzIGhhcyBhIElRIDw3MD8NCmBgYHtyfQ0KIGRmX2FzZCAlPiUNCiAgZHBseXI6OmZpbHRlcihpcSA8IDcwKSAlPiUNCiAgZHBseXI6OnN1bW1hcmlzZShjb3VudCA9IG4oKSkgIyBTw6NvIDgsIHNlbmRvIHF1ZSA4IHRpdmVyYW0gbyBkaWFnbsOzc3RpY28gZGUgVEVBIGUgREkNCmBgYA0KDQojIyBTZWxlY3QgZGF0YQ0KDQpgYGB7cn0NCmRmX3NlbGVjdGVkIDwtIGRmX2FzZCAlPiUNCiAgZHBseXI6OnNlbGVjdCgiZ29fbm9fZ29feiIsICJzdHJvb3BfYV96IiwgInN0cm9vcF9iX3oiLCAic3Ryb29wX2NfeiIsICJmZHRfaW5oaWJpdGlvbl96IikNCmBgYA0KDQoNCiMjIENsdXN0ZXJpbmcgKHRyYWRpdGlvbmFsKQ0KDQojIyMgSG93IG1hbnkgY2xhc3Nlcz8NCg0KYGBge3J9DQpmdml6X25iY2x1c3QoZGZfc2VsZWN0ZWQsIGttZWFucywgbWV0aG9kID0gIndzcyIpKw0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSA0LCBsaW5ldHlwZSA9IDIpICMgaW5jaWFsbWVudGUgc3VnZXJlbSBxdWF0cm8gDQpgYGANCg0KDQpgYGB7cn0NCnNldC5zZWVkKDEyMykNCmttLnJlcyA8LSBrbWVhbnMoZGZfc2VsZWN0ZWQsIDMsIG5zdGFydCA9IDI1KQ0KDQpwYWxldHRlIDwtIGMoIiMyNTUyOTMiLCAiI2RiMGExNiIsICIjZjhjNzJkIikNCg0KIyBWaXN1YWxpemUNCmxpYnJhcnkoZmFjdG9leHRyYSkNCg0KZnZpel9jbHVzdGVyKGttLnJlcywgZGF0YSA9IGRmX3NlbGVjdGVkLA0KICAgICAgICAgICAgIGVsbGlwc2UudHlwZSA9ICJjb252ZXgiLA0KICAgICAgICAgICAgICNwYWxldHRlID0gcGFsZXR0ZSwNCiAgICAgICAgICAgICBnZ3RoZW1lID0gdGhlbWVfbWluaW1hbCgpKQ0KDQpmdml6X2NsdXN0ZXIoa20ucmVzLCBkYXRhPWRmX3NlbGVjdGVkLA0KICAgICAgICAgICAgIHBhbGV0dGUgPSBjKCIjMkU5RkRGIiwgIiMwMEFGQkIiLCAiI0U3QjgwMCIsICIjRkM0RTA3IiksDQogICAgICAgICAgICAgZWxsaXBzZS50eXBlPSJldWNsaWQiLA0KICAgICAgICAgICAgIHN0YXIucGxvdD1UUlVFLA0KICAgICAgICAgICAgIHJlcGVsPVRSVUUsDQogICAgICAgICAgICAgZ2d0aGVtZT10aGVtZV9taW5pbWFsKCkNCiAgICAgICAgICAgICApDQpgYGANCg0KIyMjIEZpbmFsIG1vZGVsDQoNCmBgYHtyfQ0KI3NldC5zZWVkKDEyMykNCiNscGFfZXhwbG9yYXRvcnkgPSBlc3RpbWF0ZV9wcm9maWxlcyhkZl9zZWxlY3RlZCwxOjUsIHBhY2thZ2UgPSAiTXBsdXNBdXRvbWF0aW9uIiwNCiAgICAgICAgICAgICAgICAgICAgICMgdmFyaWFuY2VzID0gYygiZXF1YWwiLCAidmFyeWluZyIpLA0KICAgICAgICAgICAgICAgICAgICAgIyBjb3ZhcmlhbmNlcyA9IGMoInplcm8iLCAidmFyeWluZyIpKQ0KI2NvbXBhcmVfc29sdXRpb25zKGxwYV9leHBsb3JhdG9yeSxzdGF0aXN0aWNzID0gYygiTG9nTGlrIiwiQVdFIiwgIkFJQyIsICJCSUMiLCAiU0FCSUMiLCAiQkxSVF92YWwiLCAiQkxSVF9wIiwiRW50cm9weSIpKQ0KDQpgYGANCg0KDQpOb3cgSSdsbCBydW4gdGhpcyBzb2x1dGlvbg0KDQpgYGB7cn0NCm1vZF9sYXAgPSBlc3RpbWF0ZV9wcm9maWxlcyhkZl9zZWxlY3RlZCwgbl9wcm9maWxlcyA9IDMpDQpgYGANCg0KYGBge3J9DQpnZXRfZml0KG1vZF9sYXApDQpgYGANCg0KYGBge3J9DQpnZXRfZXN0aW1hdGVzKG1vZF9sYXApDQpgYGANCg0KYGBge3J9DQpkZl9jbHVzdGVyID0gZ2V0X2RhdGEobW9kX2xhcCkNCmBgYA0KDQpgYGB7cn0NCnRhYnlsKGRmX2NsdXN0ZXIkQ2xhc3MpDQpgYGANCg0KIyMjIFBsb3QgZml0DQoNCmBgYHtyfQ0KcHJvZl9lc3RpbWF0ZXMgPC0gZ2V0X2VzdGltYXRlcyhtb2RfbGFwKQ0KYGBgDQoNCmBgYHtyfQ0KcHJvZl9lc3RpbWF0ZXMgJT4lDQogIGZpbHRlcihDYXRlZ29yeSA9PSAiTWVhbnMiKSAlPiUNCiAgbXV0YXRlKENsYXNzID0gc3RyX3JlcGxhY2VfYWxsKENsYXNzLCAiXiIsICJQcm9maWxlICIpLA0KICAgICAgICAgUGFyYW1ldGVyID0gc3RyX3JlbW92ZV9hbGwoUGFyYW1ldGVyLCAiX2NlbnRlcmVkIikpICU+JQ0KICBtdXRhdGUoUGFyYW1ldGVyID0gc3RyX3JlbW92ZV9hbGwoUGFyYW1ldGVyLCAiX3pzY29yZSIpKSAlPiUNCiAgbXV0YXRlKFBhcmFtZXRlciA9IHN0cl9yZW1vdmVfYWxsKFBhcmFtZXRlciwgIih0b3RhbCkiKSkgJT4lDQogIG11dGF0ZShQYXJhbWV0ZXIgPSBzdHJfcmVtb3ZlX2FsbChQYXJhbWV0ZXIsICJcXCguKiIpKSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gQ2xhc3MsIHkgPSBFc3RpbWF0ZSwgZ3JvdXAgPSBQYXJhbWV0ZXIsIGZpbGwgPSBQYXJhbWV0ZXIpKSArDQogIGdlb21fYmFyKHN0YXQgPSAic3VtbWFyeSIsIHBvc2l0aW9uID0gImRvZGdlIikgKw0KICB0aGVtZV9saWdodCgpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICsNCiAgc2NhbGVfZmlsbF9ncmV5KHN0YXJ0ID0gMCwgZW5kID0gLjkpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoTkEsIDIpLCBicmVha3MgPSBzY2FsZXM6OnByZXR0eV9icmVha3MobiA9IDUpKQ0KYGBgDQoNCmBgYHtyfQ0KYmluZF9jb2xzKA0KICBkZl9hc2QgJT4lIGRwbHlyOjpzZWxlY3QoImRpYWdub3NpcyIpLA0KICBkZl9jbHVzdGVyDQopDQpgYGANCg0KDQoNCmBgYHtyfQ0KIGJpbmRfY29scygNCiAgZGZfYXNkICU+JSBkcGx5cjo6c2VsZWN0KGRpYWdub3NpcyksDQogIGRmX2NsdXN0ZXINCikgJT4lIA0KICB0YWJ5bChkaWFnbm9zaXMsIENsYXNzLCBzaG93X25hID0gRkFMU0UpICU+JSANCiAgYWRvcm5fcGVyY2VudGFnZXMoInJvdyIpICU+JSANCiAgYWRvcm5fcGN0X2Zvcm1hdHRpbmcoZGlnaXRzID0gMSkgJT4lIA0KICBhZG9ybl9ucygpDQpgYGANCiMgUHJlZGljdG9ycyANCg0KYGBge3J9DQpkZl9hc2QgPC0gYmluZF9jb2xzKA0KICBkZl9hc2QsDQogIGRmX2NsdXN0ZXIgJT4lIGRwbHlyOjpzZWxlY3QoIkNsYXNzIikNCikNCmBgYA0KDQoNCmBgYHtyfQ0Kcm0ocmVzKQ0KcmVzPC1jb21wYXJlR3JvdXBzKENsYXNzIH4gYWdlICsgc2V4ICsgaXEgKyB2ZXJiYWxfaW5kZXggKyBwZXJmb3JtYW5jZV9pbmRleCArIGZkdF9mbGV4aWJpbGl0eV96ICsgd29ya2luZ19tZW1vcnlfaW5kZXggKyBwcm9jZXNzaW5nX3NwZWVkX2luZGV4LCBkYXRhPWRmX2FzZCkNCmNyZWF0ZVRhYmxlKHJlcykNCmBgYA0KDQojIyBHZXR0aW5nIHRvIEtub3cgdGhlIFBlb3BsZSBpbiB0aGUgQ2x1c3RlcnMNCmBgYHtyfQ0KZGZfYXNkICU+JSANCiAgZHBseXI6OnNlbGVjdChhZ2UsIHNleCxlZHVjYXRpb25fbGV2ZWwsIGNvbW9yYmlkaXRpZXMsIGRpYWdub3NpcywgaXEsIHZlcmJhbF9pbmRleCwgcGVyZm9ybWFuY2VfaW5kZXgsIGdvX25vX2dvX3osc3Ryb29wX2Ffeiwgc3Ryb29wX2Jfeiwgc3Ryb29wX2NfeixmZHRfaW5oaWJpdGlvbl96LCBmZHRfZmxleGliaWxpdHlfeiwgd29ya2luZ19tZW1vcnlfaW5kZXgsIHByb2Nlc3Npbmdfc3BlZWRfaW5kZXgpICU+JQ0KICBhcnNlbmFsOjp0YWJsZWJ5KGRmX2FzZCAkQ2xhc3MgfiAuLCAgZGlnaXRzPTIsIGRhdGEgPSAuKSAlPiUgc3VtbWFyeSh0ZXh0PSBUKSU+JSBhcy5kYXRhLmZyYW1lKCkNCmBgYA0KDQoNCiMjIE1lZGljYXRpb24gdXNlDQoNCmBgYHtyfQ0KZGZfYXNkICU+JSANCiAgZHBseXI6OnNlbGVjdChtZWRpY2F0aW9uX2NsYXNzKSAlPiUNCiAgYXJzZW5hbDo6dGFibGVieShkZl9hc2QgJENsYXNzIH4gLiwgIGRpZ2l0cz0yLCBkYXRhID0gLikgJT4lIHN1bW1hcnkodGV4dD0gVCklPiUgYXMuZGF0YS5mcmFtZSgpDQpgYGANCg0KDQojIyBQbG90IC0gTWVkaWNhdGlvbiB1c2UNCmBgYHtyfQ0KZGZfcGl6emEgPC0gZGZfYXNkICU+JQ0KICBmaWx0ZXIoIWlzLm5hKG1lZGljYXRpb25fY2xhc3MpICYgbWVkaWNhdGlvbl9jbGFzcyAhPSAiT3RoZXJzIikgJT4lICAjIFJlbW92ZSBOQXMgZSAiT3RoZXJzIg0KICBncm91cF9ieShDbGFzcywgbWVkaWNhdGlvbl9jbGFzcykgJT4lDQogIHN1bW1hcmlzZShjb3VudCA9IG4oKSkgJT4lDQogIG11dGF0ZShwZXJjZW50YWdlID0gY291bnQgLyBzdW0oY291bnQpICogMTAwKQ0KDQpnZ3Bsb3QoZGZfcGl6emEsIGFlcyh4ID0gIiIsIHkgPSBwZXJjZW50YWdlLCBmaWxsID0gbWVkaWNhdGlvbl9jbGFzcykpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHdpZHRoID0gMSwgY29sb3IgPSAid2hpdGUiKSArDQogIGNvb3JkX3BvbGFyKHRoZXRhID0gInkiKSArDQogIGZhY2V0X3dyYXAofiBDbGFzcywgbmNvbCA9IDMpICsgICMgQ29sb2NhIG9zIGdyw6FmaWNvcyBsYWRvIGEgbGFkbyAoMyBjb2x1bmFzKQ0KICBsYWJzKA0KICAgIHRpdGxlID0gIkRpc3RyaWJ1dGlvbiBvZiBNZWRpY2F0aW9uIENsYXNzZXMgYnkgQ2xhc3MiLA0KICAgIGZpbGwgPSAiTWVkaWNhdGlvbiBDbGFzcyIsDQogICAgeSA9ICIiLA0KICAgIHggPSAiIg0KICApICsNCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHBhc3RlMChyb3VuZChwZXJjZW50YWdlLCAxKSwgIiUiKSksIA0KICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9zdGFjayh2anVzdCA9IDAuNSksIA0KICAgICAgICAgICAgc2l6ZSA9IDQsIGNvbG9yID0gImJsYWNrIikgKyAjIFLDs3R1bG9zIGRlIHBvcmNlbnRhZ2VtIG5vIGNlbnRybyBkYXMgZmF0aWFzDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKA0KICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2LCBmYWNlID0gImJvbGQiLCBoanVzdCA9IDAuNSksICMgQ2VudHJhbGl6YSBlIGF1bWVudGEgbyB0w610dWxvDQogICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTQsIGZhY2UgPSAiYm9sZCIpLCAjIEF1bWVudGEgbyB0ZXh0byBkYXMgZmFjZXRhcw0KICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLA0KICAgIHBhbmVsLmdyaWQgPSBlbGVtZW50X2JsYW5rKCksDQogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgZmFjZSA9ICJib2xkIiksICMgQWp1c3RhIG8gdGFtYW5obyBkbyB0w610dWxvIGRhIGxlZ2VuZGENCiAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLA0KICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iICAjIE1vdmUgYSBsZWdlbmRhIHBhcmEgYmFpeG8NCiAgKSArDQogIGd1aWRlcyhmaWxsID0gZ3VpZGVfbGVnZW5kKHRpdGxlLnBvc2l0aW9uID0gInRvcCIsIHRpdGxlLmhqdXN0ID0gMC41KSkgIyBDZW50cmFsaXphIG8gdMOtdHVsbyBkYSBsZWdlbmRhDQoNCg0KYGBgDQoNCg0KIyMgQmVoYXZpb3JhbCBpbmZvcm1hdGlvbg0KDQpgYGB7cn0NCmRmX2FzZCAlPiUNCiAgZHBseXI6OnNlbGVjdCgNCiAgICBwc3ljaG9tb3Rvcl9hZ2l0YXRpb24sIHJlc3RsZXNzbmVzcywgaW1wdWxzaXZlbmVzcywgaW5hdHRlbnRpb24sIHZlcmJhbF9hZ2dyZXNzaXZlbmVzcywgDQogICAgcGh5c2ljYWxfYWdncmVzc2l2ZW5lc3MsIGRpZmZpY3VsdHlfd2l0aF9mcnVzdHJhdGlvbiwgcmVzdHJpY3RlZF9wYXR0ZXJucywgYmVoYXZpb3JhbF9pbmZsZXhpYmlsaXR5LCANCiAgICByZXBldGl0aXZlX3BhdHRlcm5zLCBzb2NpYWxfZGlmZmljdWx0eSwgc3BlZWNoX2RlbGF5LCBkZXByZXNzaW9uX3N5bXB0b21zLCBhbnhpZXR5X3N5bXB0b21zDQogICkgJT4lDQogIGFyc2VuYWw6OnRhYmxlYnkoZGZfYXNkJENsYXNzIH4gLiwgZGlnaXRzID0gMiwgZGF0YSA9IC4pICU+JQ0KICBzdW1tYXJ5KHRleHQgPSBUUlVFKSAlPiUNCiAgYXMuZGF0YS5mcmFtZSgpDQpgYGANCg0KYGBge3J9DQpkZl9waXp6YV8yIDwtIGRmX2FzZCAlPiUNCiAgZHBseXI6OnNlbGVjdCgNCiAgICBwc3ljaG9tb3Rvcl9hZ2l0YXRpb24sIHJlc3RsZXNzbmVzcywgaW1wdWxzaXZlbmVzcywgaW5hdHRlbnRpb24sIHZlcmJhbF9hZ2dyZXNzaXZlbmVzcywgDQogICAgcGh5c2ljYWxfYWdncmVzc2l2ZW5lc3MsIGRpZmZpY3VsdHlfd2l0aF9mcnVzdHJhdGlvbiwgcmVzdHJpY3RlZF9wYXR0ZXJucywgYmVoYXZpb3JhbF9pbmZsZXhpYmlsaXR5LCANCiAgICByZXBldGl0aXZlX3BhdHRlcm5zLCBzb2NpYWxfZGlmZmljdWx0eSwgc3BlZWNoX2RlbGF5LCBkZXByZXNzaW9uX3N5bXB0b21zLCBhbnhpZXR5X3N5bXB0b21zLCBDbGFzcw0KICApICU+JQ0KICBnYXRoZXIoa2V5ID0gImJlaGF2aW9yIiwgdmFsdWUgPSAic2NvcmUiLCAtQ2xhc3MpICU+JQ0KICBtdXRhdGUoc2NvcmUgPSBhcy5udW1lcmljKHNjb3JlKSkgJT4lICAjIEdhcmFudGlyIHF1ZSAnc2NvcmUnIHNlamEgbnVtw6lyaWNvDQogIGdyb3VwX2J5KENsYXNzLCBiZWhhdmlvcikgJT4lDQogIHN1bW1hcmlzZSh0b3RhbF9zY29yZSA9IHN1bShzY29yZSwgbmEucm0gPSBUUlVFKSkgJT4lDQogIGdyb3VwX2J5KENsYXNzKSAlPiUNCiAgbXV0YXRlKHBlcmNlbnRhZ2UgPSB0b3RhbF9zY29yZSAvIHN1bSh0b3RhbF9zY29yZSkgKiAxMDApDQoNCmBgYA0KDQoNCg0KYGBge3J9DQpjdXN0b21fY29sb3JzIDwtIGMoDQogICIjNjZjMmE1IiwgIiNmYzhkNjIiLCAiIzhkYTBjYiIsICIjZTc4YWMzIiwgIiNhNmQ4NTQiLA0KICAiI2ZmZDkyZiIsICIjZTVjNDk0IiwgIiNiM2IzYjMiLCAiI2E2Y2VlMyIsICIjMWY3OGI0IiwNCiAgIiNiMmRmOGEiLCAiIzMzYTAyYyIsICIjZmI5YTk5IiwgIiNlMzFhMWMiLCAiI2ZkYmY2ZiINCikNCg0Kb3B0aW9ucyhyZXByLnBsb3Qud2lkdGggPSAxMiwgcmVwci5wbG90LmhlaWdodCA9IDgpDQoNCmdncGxvdChkZl9waXp6YV8yLCBhZXMoeCA9IENsYXNzLCB5ID0gcGVyY2VudGFnZSwgZmlsbCA9IGJlaGF2aW9yKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSAiZG9kZ2UiLCBjb2xvciA9ICJncmF5ODAiKSArDQogIGxhYnMoDQogICAgdGl0bGUgPSAiRGlzdHJpYnV0aW9uIG9mIFN5bXB0b21zIGJ5IEdyb3VwcyIsDQogICAgZmlsbCA9ICJTeW1wdG9tIiwNCiAgICB5ID0gIlBlcmNlbnRhZ2UiLA0KICAgIHggPSAiQ2xhc3MiDQogICkgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGFzdGUwKHJvdW5kKHBlcmNlbnRhZ2UsIDEpLCAiJSIpKSwgDQogICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC44KSwgDQogICAgICAgICAgICBzaXplID0gMy41LCBjb2xvciA9ICJibGFjayIpICsNCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxNCkgKw0KICB0aGVtZSgNCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxOCwgZmFjZSA9ICJib2xkIiwgaGp1c3QgPSAwLjUpLA0KICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgZmFjZSA9ICJib2xkIiksDQogICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwNCiAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE0LCBmYWNlID0gImJvbGQiKSwNCiAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLA0KICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLA0KICAgIGxlZ2VuZC5rZXkuc2l6ZSA9IHVuaXQoMC44LCAiY20iKQ0KICApICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY3VzdG9tX2NvbG9ycykgKyAjIEFwbGljYW5kbyBjb3JlcyBwZXJzb25hbGl6YWRhcw0KICBndWlkZXMoZmlsbCA9IGd1aWRlX2xlZ2VuZChucm93ID0gMiwgYnlyb3cgPSBUUlVFKSkNCmBgYA0KDQoNCiMjIEFOT1ZBIC0gU3Ryb29wDQpgYGB7cn0NCmFub3ZhX3N0cm9vcF9hIDwtIGFvdihzdHJvb3BfYV96IH4gQ2xhc3MsIGRhdGEgPSBkZl9hc2QpDQphbm92YV9zdHJvb3BfYiA8LSBhb3Yoc3Ryb29wX2JfeiB+IENsYXNzLCBkYXRhID0gZGZfYXNkKQ0KYW5vdmFfc3Ryb29wX2MgPC0gYW92KHN0cm9vcF9jX3ogfiBDbGFzcywgZGF0YSA9IGRmX2FzZCkNCg0KIyBSZXN1bW8gZG9zIHJlc3VsdGFkb3MNCnN1bW1hcnkoYW5vdmFfc3Ryb29wX2EpDQpzdW1tYXJ5KGFub3ZhX3N0cm9vcF9iKSAjIGRpZmVyZW7Dp2Egc2lnbmlmaWNhdGl2YQ0Kc3VtbWFyeShhbm92YV9zdHJvb3BfYykgIyBkaWZlcmVuw6dhIHNpZ25pZmljYXRpdmEgDQoNCiMgUG9zdC1ob2MgdXNhbmRvIFR1a2V5IEhTRCBwYXJhIHVtYSBkYXMgdmFyacOhdmVpcw0KcG9zdGhvY19hIDwtIGVtbWVhbnMoYW5vdmFfc3Ryb29wX2EsIHBhaXJ3aXNlIH4gQ2xhc3MpDQpwb3N0aG9jX2ENCmBgYA0KYGBge3J9DQojIEFOT1ZBIHBhcmEgY2FkYSB2YXJpw6F2ZWwNCmFub3ZhX2dvX25vX2dvIDwtIGFvdihnb19ub19nb196IH4gQ2xhc3MsIGRhdGEgPSBkZl9hc2QpDQoNCiMgUmVzdW1vIGRvcyByZXN1bHRhZG9zDQpzdW1tYXJ5KGFub3ZhX2dvX25vX2dvKQ0KDQojIFBvc3QtaG9jIHVzYW5kbyBUdWtleSBIU0QgcGFyYSB1bWEgZGFzIHZhcmnDoXZlaXMNCnBvc3Rob2NfZ28gPC0gZW1tZWFucyhhbm92YV9nb19ub19nbywgcGFpcndpc2UgfiBDbGFzcykNCnBvc3Rob2NfZ28NCmBgYA0KYGBge3J9DQojIEFOT1ZBIHBhcmEgY2FkYSB2YXJpw6F2ZWwNCmFub3ZhX2ZkdCAgPC0gYW92KGZkdF9pbmhpYml0aW9uX3ogfiBDbGFzcywgZGF0YSA9IGRmX2FzZCkNCg0KIyBSZXN1bW8gZG9zIHJlc3VsdGFkb3MNCnN1bW1hcnkoYW5vdmFfZmR0KQ0KDQojIFBvc3QtaG9jIHVzYW5kbyBUdWtleSBIU0QgcGFyYSB1bWEgZGFzIHZhcmnDoXZlaXMNCnBvc3Rob2NfZmR0IDwtIGVtbWVhbnMoYW5vdmFfZmR0LCBwYWlyd2lzZSB+IENsYXNzKQ0KcG9zdGhvY19mZHQNCmBgYA0KIyMgQ29ycmVsYXRpb24NCmBgYHtyfQ0KIyBTZWxlY2lvbmFyIHZhcmnDoXZlaXMNCmNvcnJlbGF0aW9uX2RhdGEgPC0gZGZfYXNkICU+JQ0KICBkcGx5cjo6c2VsZWN0KGdvX25vX2dvX3osIHN0cm9vcF9hX3osIHN0cm9vcF9iX3osIHN0cm9vcF9jX3osIGZkdF9pbmhpYml0aW9uX3osIA0KICAgICAgICAgICAgICAgIGZkdF9mbGV4aWJpbGl0eV96LCBwZXJmb3JtYW5jZV9pbmRleCwgd29ya2luZ19tZW1vcnlfaW5kZXgpDQoNCiMgTWF0cml6IGRlIGNvcnJlbGHDp8Ojbw0KY29ycmVsYXRpb25fbWF0cml4IDwtIGNvcihjb3JyZWxhdGlvbl9kYXRhLCB1c2UgPSAicGFpcndpc2UuY29tcGxldGUub2JzIiwgbWV0aG9kID0gInBlYXJzb24iKQ0KDQojIFZpc3VhbGl6YcOnw6NvIGRhIG1hdHJpeg0KbGlicmFyeShjb3JycGxvdCkNCmNvcnJwbG90Ojpjb3JycGxvdChjb3JyZWxhdGlvbl9tYXRyaXgsIG1ldGhvZCA9ICJjb2xvciIsIHR5cGUgPSAidXBwZXIiLCBhZGRDb2VmLmNvbCA9ICJibGFjayIsIHRsLmNvbCA9ICJibGFjayIpDQpgYGANCg0KYGBge3J9DQojIE9idGVyIG1hdHJpeiBkZSBjb3JyZWxhw6fDtWVzIGUgdmFsb3Jlcy1wDQpjb3JfcmVzdWx0cyA8LSBIbWlzYzo6cmNvcnIoYXMubWF0cml4KGNvcnJlbGF0aW9uX2RhdGEpLCB0eXBlID0gInBlYXJzb24iKQ0KDQojIE1hdHJpeiBkZSBjb3JyZWxhw6fDtWVzDQpjb3JfbWF0cml4IDwtIGNvcl9yZXN1bHRzJHINCg0KIyBNYXRyaXogZGUgdmFsb3Jlcy1wDQpwX21hdHJpeCA8LSBjb3JfcmVzdWx0cyRQDQoNCiMgQ3JpYXIgbWF0cml6IGNvbWJpbmFkYSBjb20gY29ycmVsYcOnw6NvIGUgdmFsb3Jlcy1wDQpjb21iaW5lZF9tYXRyaXggPC0gcGFzdGUwKA0KICBmb3JtYXQocm91bmQoY29yX21hdHJpeCwgMiksIG5zbWFsbCA9IDIpLCAgIyBDb2VmaWNpZW50ZSBkZSBjb3JyZWxhw6fDo28NCiAgIiAocD0iLCBmb3JtYXQocm91bmQocF9tYXRyaXgsIDMpLCBuc21hbGwgPSAzKSwgIikiICAjIFZhbG9yLXANCikNCg0KIyBSZWZvcm1hdGFyIGVtIGZvcm1hdG8gZGUgbWF0cml6DQpkaW0oY29tYmluZWRfbWF0cml4KSA8LSBkaW0oY29yX21hdHJpeCkNCnJvd25hbWVzKGNvbWJpbmVkX21hdHJpeCkgPC0gcm93bmFtZXMoY29yX21hdHJpeCkNCmNvbG5hbWVzKGNvbWJpbmVkX21hdHJpeCkgPC0gY29sbmFtZXMoY29yX21hdHJpeCkNCg0KIyBWaXN1YWxpemFyIG1hdHJpeiBjb21iaW5hZGENCnByaW50KGNvbWJpbmVkX21hdHJpeCwgcXVvdGUgPSBGQUxTRSkNCmBgYA0KDQojIE5vbi1DbGluaWNhbCBHcm91cCANCg0KIyMgRGF0YQ0KYGBge3J9DQpkZl9ub25fY2xpbmljYWwgPC0gcmVhZF9leGNlbCgiQzovVXNlcnMvbG91aXMvRG93bmxvYWRzL0NvbnRyb2xlIC0gZXNjb2xpbmhhIChMb3Vpc2UpLnhsc3giKQ0KYGBgDQoNCg0KIyMgQ2hlY2sgTkEncw0KYGBge3J9DQp2YXJpYXZlaXMgPC0gYygiZ29fbm9fZ28iLCAiZ29fbm9fZ29feiIsICJzdHJvb3BfYSIsICJzdHJvb3BfYV96IiwgInN0cm9vcF9hX2Vycm9ycyIsICJzdHJvb3BfYV9lcnJvcnNfeiIsICJzdHJvb3BfYiIsICJzdHJvb3BfYl96IiwgICAgICAgICAgICAgICAgInN0cm9vcF9iX2Vycm9ycyIsICJzdHJvb3BfYl9lcnJvcnNfeiIsICJzdHJvb3BfYyIsICJzdHJvb3BfY196IiwgInN0cm9vcF9jX2Vycm9ycyIsDQogICAgICAgICAgICAgICAic3Ryb29wX2NfZXJyb3JzX3oiLCAiaW50ZXJmZXJlbmNlIiwgImZkdF9yZWFkaW5nIiwgImZkdF9yZWFkaW5nX3oiLA0KICAgICAgICAgICAgICAgImZkdF9yZWFkaW5nX2Vycm9ycyIsICJmZHRfcmVhZGluZ19lcnJvcnNfeiIsICJmZHRfY291bnRpbmciLCAiZmR0X2NvdW50aW5nX3oiLA0KICAgICAgICAgICAgICAgImZkdF9jb3VudGluZ19lcnJvcnMiLCAiZmR0X2NvdW50aW5nX2Vycm9yc196IiwgImZkdF9jaG9vc2luZyIsICJmZHRfY2hvb3NpbmdfeiIsDQogICAgICAgICAgICAgICAiZmR0X2Nob29zaW5nX2Vycm9ycyIsICJmZHRfY2hvb3NpbmdfZXJyb3JzX3oiLCAiZmR0X3NoaWZ0aW5nIiwgImZkdF9zaGlmdGluZ196IiwNCiAgICAgICAgICAgICAgICJmZHRfc2hpZnRpbmdfZXJyb3JzIiwgImZkdF9zaGlmdGluZ19lcnJvcnNfeiIsICJmZHRfaW5oaWJpdGlvbiIsICJmZHRfaW5oaWJpdGlvbl96IiwNCiAgICAgICAgICAgICAgICJmZHRfZmxleGliaWxpdHkiLCAiZmR0X2ZsZXhpYmlsaXR5X3oiKQ0KDQoNCnNhcHBseShkZl9ub25fY2xpbmljYWxbdmFyaWF2ZWlzXSwgZnVuY3Rpb24oeCkgc3VtKGlzLm5hKHgpKSkNCg0KYGBgDQoNCiMjIFRyYW5zZm9ybSBpbiBudW1lcmljDQoNCmBgYHtyfQ0KdmFyc190b19jb252ZXJ0IDwtIGMoImdvX25vX2dvIiwgImdvX25vX2dvX3oiLCAic3Ryb29wX2EiLCAic3Ryb29wX2FfeiIsICJzdHJvb3BfYV9lcnJvcnMiLCAic3Ryb29wX2FfZXJyb3JzX3oiLA0KICAgICAgICAgICAgICAgICAgICAgInN0cm9vcF9iIiwgInN0cm9vcF9iX3oiLCAic3Ryb29wX2JfZXJyb3JzIiwgInN0cm9vcF9iX2Vycm9yc196IiwNCiAgICAgICAgICAgICAgICAgICAgICJzdHJvb3BfYyIsICJzdHJvb3BfY196IiwgInN0cm9vcF9jX2Vycm9ycyIsICJzdHJvb3BfY19lcnJvcnNfeiIsDQogICAgICAgICAgICAgICAgICAgICAiaW50ZXJmZXJlbmNlIiwgImZkdF9yZWFkaW5nIiwgImZkdF9yZWFkaW5nX3oiLCAiZmR0X3JlYWRpbmdfZXJyb3JzIiwNCiAgICAgICAgICAgICAgICAgICAgICJmZHRfcmVhZGluZ19lcnJvcnNfeiIsICJmZHRfY291bnRpbmciLCAiZmR0X2NvdW50aW5nX3oiLCAiZmR0X2NvdW50aW5nX2Vycm9ycyIsDQogICAgICAgICAgICAgICAgICAgICAiZmR0X2NvdW50aW5nX2Vycm9yc196IiwgImZkdF9jaG9vc2luZyIsICJmZHRfY2hvb3NpbmdfeiIsICJmZHRfY2hvb3NpbmdfZXJyb3JzIiwNCiAgICAgICAgICAgICAgICAgICAgICJmZHRfY2hvb3NpbmdfZXJyb3JzX3oiLCAiZmR0X3NoaWZ0aW5nIiwgImZkdF9zaGlmdGluZ196IiwgImZkdF9zaGlmdGluZ19lcnJvcnMiLA0KICAgICAgICAgICAgICAgICAgICAgImZkdF9zaGlmdGluZ19lcnJvcnNfeiIsICJmZHRfaW5oaWJpdGlvbiIsICJmZHRfaW5oaWJpdGlvbl96IiwgImZkdF9mbGV4aWJpbGl0eSIsDQogICAgICAgICAgICAgICAgICAgICAiZmR0X2ZsZXhpYmlsaXR5X3oiKQ0KDQpkZl9ub25fY2xpbmljYWwgPC0gZGZfbm9uX2NsaW5pY2FsICU+JQ0KICBtdXRhdGUoYWNyb3NzKGFsbF9vZih2YXJzX3RvX2NvbnZlcnQpLCB+IHJvdW5kKGFzLm51bWVyaWMoLiksIDIpKSkNCg0KYGBgDQoNCg0KIyMgSW1wdXRhdGlvbiBvZiBtaXNzaW5nIHZhbHVlcyB1c2luZyB0aGUgbWVhbg0KYGBge3J9DQojZGZfbm9uX2NsaW5pY2FsW3ZhcmlhdmVpc10gPC0gbGFwcGx5KGRmX25vbl9jbGluaWNhbFt2YXJpYXZlaXNdLCBmdW5jdGlvbih4KSB7DQogICNpZmVsc2UoaXMubmEoeCksIG1lYW4oeCwgbmEucm0gPSBUUlVFKSwgeCkNCiN9KQ0KYGBgDQoNCiMjIFJlbmFtZSAtIFNleCANCg0KYGBge3J9DQpkZl9ub25fY2xpbmljYWwgPC0gZGZfbm9uX2NsaW5pY2FsICU+JQ0KICBkcGx5cjo6bXV0YXRlKA0KICAgIHNleCA9IGRwbHlyOjpyZWNvZGVfZmFjdG9yKHNleCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYDFgID0gIkZlbWluaW5lIiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYDJgID0gIk1hc2N1bGluZSIpDQogICkNCmBgYA0KDQpgYGB7cn0NCmRmX25vbl9jbGluaWNhbCA8LSBkZl9ub25fY2xpbmljYWwgJT4lDQogIGRwbHlyOjptdXRhdGUoDQogICAgc2V4ID0gYXMuZmFjdG9yKHNleCksDQogICAgZWR1Y2F0aW9uX2xldmVsID0gYXMuZmFjdG9yKGVkdWNhdGlvbl9sZXZlbCkNCiAgKQ0KYGBgDQoNCg0KYGBge3J9DQpkZl9ub25fY2xpbmljYWwgPC0gZGZfbm9uX2NsaW5pY2FsICU+JQ0KICBtdXRhdGVfYWxsKH4gcmVwbGFjZSguLCAuID09IDk5OSwgTkEpKQ0KYGBgDQoNCg0KIyMgQ2hlY2sgLSBwYXJ0aWNpcGFudHMgY2hhcmFjdGVyaXN0aWNzIA0KYGBge3J9DQpkZl9ub25fY2xpbmljYWwgJT4lDQogIGRwbHlyOjpzZWxlY3QoYWdlLCBzZXgsZWR1Y2F0aW9uX2xldmVsLCBpcSwgdmVyYmFsX2luZGV4LCBwZXJmb3JtYW5jZV9pbmRleCwgZ29fbm9fZ29feixzdHJvb3BfYV96LCBzdHJvb3BfYl96LCBzdHJvb3BfY196LGZkdF9pbmhpYml0aW9uX3osIGZkdF9mbGV4aWJpbGl0eV96KSAlPiUNCiAgYXJzZW5hbDo6dGFibGVieSh+IC4sIGRpZ2l0cyA9IDIsIGRhdGEgPSAuKSAlPiUgc3VtbWFyeSh0ZXh0PSBUKSAlPiUgDQogIGFzLmRhdGEuZnJhbWUoKQ0KYGBgDQoNCmBgYHtyfQ0KZGZfc2VsZWN0ZWRfMiA8LSBkZl9ub25fY2xpbmljYWwgJT4lDQogIGRwbHlyOjpzZWxlY3QoImdvX25vX2dvX3oiLCAic3Ryb29wX2FfeiIsICJzdHJvb3BfYl96IiwgInN0cm9vcF9jX3oiLCAiZmR0X2luaGliaXRpb25feiIpDQpgYGANCg0KYGBge3J9DQpkZl9zZWxlY3RlZF8yIDwtIGRmX3NlbGVjdGVkXzIgJT4lDQogIG11dGF0ZV9hbGwofiBpZmVsc2UoaXMubmEoLiksIG1lYW4oLiwgbmEucm0gPSBUUlVFKSwgLikpDQpgYGANCg0KDQojIyBDbHVzdGVyaW5nICh0cmFkaXRpb25hbCkNCg0KIyMjIEhvdyBtYW55IGNsYXNzZXM/DQoNCmBgYHtyfQ0KZnZpel9uYmNsdXN0KGRmX3NlbGVjdGVkXzIsIGttZWFucywgbWV0aG9kID0gIndzcyIpKw0KICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSA0LCBsaW5ldHlwZSA9IDIpICMgaW5jaWFsbWVudGUgc3VnZXJlbSBxdWF0cm8gDQpgYGANCmBgYHtyfQ0Kc2V0LnNlZWQoMTIzKQ0Ka20ucmVzIDwtIGttZWFucyhkZl9zZWxlY3RlZF8yLCAzLCBuc3RhcnQgPSAyNSkNCg0KcGFsZXR0ZSA8LSBjKCIjMjU1MjkzIiwgIiNkYjBhMTYiLCAiI2Y4YzcyZCIpDQoNCg0KZnZpel9jbHVzdGVyKGttLnJlcywgZGF0YSA9IGRmX3NlbGVjdGVkXzIsDQogICAgICAgICAgICAgZWxsaXBzZS50eXBlID0gImNvbnZleCIsDQogICAgICAgICAgICAgI3BhbGV0dGUgPSBwYWxldHRlLA0KICAgICAgICAgICAgIGdndGhlbWUgPSB0aGVtZV9taW5pbWFsKCkpDQoNCmZ2aXpfY2x1c3RlcihrbS5yZXMsIGRhdGE9ZGZfc2VsZWN0ZWRfMiwNCiAgICAgICAgICAgICBwYWxldHRlID0gYygiIzJFOUZERiIsICIjMDBBRkJCIiwgIiNFN0I4MDAiLCAiI0ZDNEUwNyIpLA0KICAgICAgICAgICAgIGVsbGlwc2UudHlwZT0iZXVjbGlkIiwNCiAgICAgICAgICAgICBzdGFyLnBsb3Q9VFJVRSwNCiAgICAgICAgICAgICByZXBlbD1UUlVFLA0KICAgICAgICAgICAgIGdndGhlbWU9dGhlbWVfbWluaW1hbCgpDQogICAgICAgICAgICAgKQ0KYGBgDQoNCmBgYHtyfQ0KbW9kX2xhcF8yID0gZXN0aW1hdGVfcHJvZmlsZXMoZGZfc2VsZWN0ZWRfMiwgbl9wcm9maWxlcyA9IDIpDQpgYGANCg0KYGBge3J9DQpnZXRfZml0KG1vZF9sYXApDQpgYGANCg0KYGBge3J9DQpnZXRfZXN0aW1hdGVzKG1vZF9sYXBfMikNCmBgYA0KDQpgYGB7cn0NCmRmX2NsdXN0ZXJfMiA9IGdldF9kYXRhKG1vZF9sYXBfMikNCmBgYA0KDQpgYGB7cn0NCnRhYnlsKGRmX2NsdXN0ZXJfMiRDbGFzcykNCmBgYA0KDQojIyMgUGxvdCBmaXQNCg0KYGBge3J9DQpwcm9mX2VzdGltYXRlcyA8LSBnZXRfZXN0aW1hdGVzKG1vZF9sYXBfMikNCmBgYA0KDQpgYGB7cn0NCnByb2ZfZXN0aW1hdGVzICU+JQ0KICBmaWx0ZXIoQ2F0ZWdvcnkgPT0gIk1lYW5zIikgJT4lDQogIG11dGF0ZShDbGFzcyA9IHN0cl9yZXBsYWNlX2FsbChDbGFzcywgIl4iLCAiUHJvZmlsZSAiKSwNCiAgICAgICAgIFBhcmFtZXRlciA9IHN0cl9yZW1vdmVfYWxsKFBhcmFtZXRlciwgIl9jZW50ZXJlZCIpKSAlPiUNCiAgbXV0YXRlKFBhcmFtZXRlciA9IHN0cl9yZW1vdmVfYWxsKFBhcmFtZXRlciwgIl96c2NvcmUiKSkgJT4lDQogIG11dGF0ZShQYXJhbWV0ZXIgPSBzdHJfcmVtb3ZlX2FsbChQYXJhbWV0ZXIsICIodG90YWwpIikpICU+JQ0KICBtdXRhdGUoUGFyYW1ldGVyID0gc3RyX3JlbW92ZV9hbGwoUGFyYW1ldGVyLCAiXFwoLioiKSkgJT4lDQogIGdncGxvdChhZXMoeCA9IENsYXNzLCB5ID0gRXN0aW1hdGUsIGdyb3VwID0gUGFyYW1ldGVyLCBmaWxsID0gUGFyYW1ldGVyKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gInN1bW1hcnkiLCBwb3NpdGlvbiA9ICJkb2RnZSIpICsNCiAgdGhlbWVfbGlnaHQoKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKSArDQogIHNjYWxlX2ZpbGxfZ3JleShzdGFydCA9IDAsIGVuZCA9IC45KSArDQogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKE5BLCAyKSwgYnJlYWtzID0gc2NhbGVzOjpwcmV0dHlfYnJlYWtzKG4gPSA1KSkNCmBgYA0KDQpgYGB7cn0NCmRmX25vbl9jbGluaWNhbDwtIGJpbmRfY29scygNCiAgZGZfbm9uX2NsaW5pY2FsLA0KICBkZl9jbHVzdGVyXzIgJT4lIGRwbHlyOjpzZWxlY3QoIkNsYXNzIikNCikNCmBgYA0KDQpgYGB7cn0NCnJtKHJlcykNCnJlczwtY29tcGFyZUdyb3VwcyhDbGFzcyB+IGFnZSArIHNleCArIGlxICsgdmVyYmFsX2luZGV4ICsgcGVyZm9ybWFuY2VfaW5kZXggKyBmZHRfZmxleGliaWxpdHlfeiArIHdvcmtpbmdfbWVtb3J5X2luZGV4ICsgcHJvY2Vzc2luZ19zcGVlZF9pbmRleCwgZGF0YT1kZl9ub25fY2xpbmljYWwpDQpjcmVhdGVUYWJsZShyZXMpDQpgYGANCiMjIEdldHRpbmcgdG8gS25vdyB0aGUgUGVvcGxlIGluIHRoZSBDbHVzdGVycw0KYGBge3J9DQpkZl9ub25fY2xpbmljYWwgJT4lIA0KICBkcGx5cjo6c2VsZWN0KGFnZSwgc2V4LGVkdWNhdGlvbl9sZXZlbCwgaXEsIHZlcmJhbF9pbmRleCwgcGVyZm9ybWFuY2VfaW5kZXgsIGdvX25vX2dvX3osc3Ryb29wX2Ffeiwgc3Ryb29wX2Jfeiwgc3Ryb29wX2NfeixmZHRfaW5oaWJpdGlvbl96LCBmZHRfZmxleGliaWxpdHlfeiwgd29ya2luZ19tZW1vcnlfaW5kZXgsIHByb2Nlc3Npbmdfc3BlZWRfaW5kZXgsIGNkaV9jbGFzc2lmaWNhdGlvbix6X2luYXR0ZW50aW9uLCB6X2h5cGVyYWN0aXZpdHlfaW1wdWxzaXZpdHksIHpfZ2VuZXJhbF9hbnhpZXR5KSAlPiUNCiAgYXJzZW5hbDo6dGFibGVieShkZl9ub25fY2xpbmljYWwgJENsYXNzIH4gLiwgIGRpZ2l0cz0yLCBkYXRhID0gLikgJT4lIHN1bW1hcnkodGV4dD0gVCklPiUgYXMuZGF0YS5mcmFtZSgpDQpgYGANCg0KDQoNCiMgQ29tcGFyaW5nIEdyb3VwcyAoQVNEIHZzIE5vbiBDbGluaWNhbCBQcm9maWxlcykNCg0KIyMgRml4aW5nIHRoZSBkYXRhYmFzZQ0KDQojIyMgQ3JlYXRlIEdyb3VwIHZhcmlhYmxlDQpgYGB7cn0NCmRmX25vbl9jbGluaWNhbCA8LSBkZl9ub25fY2xpbmljYWwgJT4lDQogIG11dGF0ZShncm91cCA9ICJub24gY2xpbmljYWwiKQ0KDQpkZl9hc2QgPC0gZGZfYXNkICU+JQ0KICBtdXRhdGUoZ3JvdXAgPSAiYXNkIikNCmBgYA0KDQpgYGB7cn0NCmRmX2NvbWJpbmVkIDwtIGJpbmRfcm93cyhkZl9ub25fY2xpbmljYWwsIGRmX2FzZCkNCmBgYA0KDQpgYGB7cn0NCmRmX2NvbWJpbmVkICU+JSANCiAgZHBseXI6OnNlbGVjdChhZ2UsIHNleCxlZHVjYXRpb25fbGV2ZWwsIGlxLCB2ZXJiYWxfaW5kZXgsIHBlcmZvcm1hbmNlX2luZGV4LCBnb19ub19nb196LHN0cm9vcF9hX3osIHN0cm9vcF9iX3osIHN0cm9vcF9jX3osZmR0X2luaGliaXRpb25feiwgZmR0X2ZsZXhpYmlsaXR5X3osIHdvcmtpbmdfbWVtb3J5X2luZGV4LCBwcm9jZXNzaW5nX3NwZWVkX2luZGV4LCBzdHJvb3BfYV9lcnJvcnNfeiwgc3Ryb29wX2JfZXJyb3JzX3osIHN0cm9vcF9jX2Vycm9yc196KSAlPiUNCiAgYXJzZW5hbDo6dGFibGVieShkZl9jb21iaW5lZCAkZ3JvdXAgfiAuLCAgZGlnaXRzPTIsIGRhdGEgPSAuKSAlPiUgc3VtbWFyeSh0ZXh0PSBUKSU+JSBhcy5kYXRhLmZyYW1lKCkNCmBgYA0KDQoNCiMjIEFOQ09WQQ0KYGBge3J9DQphbmNvdmFfZ29fbmMgPC0gYW92KGdvX25vX2dvX3ogfiBncm91cCArIGlxICsgYWdlLCBkYXRhID0gZGZfY29tYmluZWQpDQphbmNvdmFfc3Ryb29wX2FfbmMgPC0gYW92KHN0cm9vcF9hX3ogfiBncm91cCArIGlxICsgYWdlICsgZWR1Y2F0aW9uX2xldmVsLCBkYXRhID0gZGZfY29tYmluZWQpDQphbmNvdmFfc3Ryb29wX2JfbmMgPC0gYW92KHN0cm9vcF9iX3ogfiBncm91cCArIGlxICsgYWdlICsgZWR1Y2F0aW9uX2xldmVsLCBkYXRhID0gZGZfY29tYmluZWQpDQphbmNvdmFfc3Ryb29wX2NfbmMgPC0gYW92KHN0cm9vcF9jX3ogfiBncm91cCArIGlxICsgYWdlICsgZWR1Y2F0aW9uX2xldmVsLCBkYXRhID0gZGZfY29tYmluZWQpDQphbmNvdmFfZmR0X25jIDwtIGFvdihmZHRfaW5oaWJpdGlvbl96IH4gZ3JvdXAgKyBpcSArIGFnZSArIGVkdWNhdGlvbl9sZXZlbCwgZGF0YSA9IGRmX2NvbWJpbmVkKQ0KDQojIFJlc3VtbyBkb3MgcmVzdWx0YWRvcw0Kc3VtbWFyeShhbmNvdmFfZ29fbmMpDQpzdW1tYXJ5KGFuY292YV9zdHJvb3BfYV9uYykNCnN1bW1hcnkoYW5jb3ZhX3N0cm9vcF9iX25jKQ0Kc3VtbWFyeShhbmNvdmFfc3Ryb29wX2NfbmMpDQpzdW1tYXJ5KGFuY292YV9mZHRfbmMpDQoNCmBgYA0KIyMgRVRBDQpgYGB7cn0NCmV0YV9zcXVhcmVkX2dvX25jIDwtIGV0YVNxdWFyZWQoYW5jb3ZhX2dvX25jKQ0KZXRhX3NxdWFyZWRfc3Ryb29wX2FfbmMgPC0gZXRhU3F1YXJlZChhbmNvdmFfc3Ryb29wX2FfbmMpDQpldGFfc3F1YXJlZF9zdHJvb3BfYl9uYyA8LSBldGFTcXVhcmVkKGFuY292YV9zdHJvb3BfYl9uYykNCmV0YV9zcXVhcmVkX3N0cm9vcF9jX25jIDwtIGV0YVNxdWFyZWQoYW5jb3ZhX3N0cm9vcF9jX25jKQ0KZXRhX3NxdWFyZWRfZmR0X25jIDwtIGV0YVNxdWFyZWQoYW5jb3ZhX2ZkdF9uYykNCg0KIyBFeGliaXIgb3MgcmVzdWx0YWRvcw0KZXRhX3NxdWFyZWRfZ29fbmMNCmV0YV9zcXVhcmVkX3N0cm9vcF9hX25jDQpldGFfc3F1YXJlZF9zdHJvb3BfYl9uYw0KZXRhX3NxdWFyZWRfc3Ryb29wX2NfbmMNCmV0YV9zcXVhcmVkX2ZkdF9uYw0KYGBgDQoNCg0KDQpgYGB7cn0NCmRmX2xvbmcgPC0gZGZfY29tYmluZWQgJT4lDQogIHBpdm90X2xvbmdlcihjb2xzID0gYyhnb19ub19nb196LCBzdHJvb3BfYV96LCBzdHJvb3BfYl96LCBzdHJvb3BfY196LCBmZHRfaW5oaWJpdGlvbl96KSwNCiAgICAgICAgICAgICAgIG5hbWVzX3RvID0gInZhcmlhYmxlIiwNCiAgICAgICAgICAgICAgIHZhbHVlc190byA9ICJ2YWx1ZSIpDQoNCmBgYA0KDQojIyBQbG90IC0gQVNEIHggbm9uIGNsaW5pY2FsIA0KYGBge3J9DQojIFJlb3JkZW5lIG9zIG7DrXZlaXMgZG8gZmF0b3IgcGFyYSBnYXJhbnRpciBxdWUgImFzZCIgZmlxdWUgbmEgZnJlbnRlDQpkZl9sb25nJGdyb3VwIDwtIGZhY3RvcihkZl9sb25nJGdyb3VwLCBsZXZlbHMgPSBjKCJub24gY2xpbmljYWwiLCAiYXNkIikpDQoNCiMgR3LDoWZpY28gZGUgZGVuc2lkYWRlIGNvbSBtYXJjYWRvcmVzIGVtIC0xIGUgKzENCmdncGxvdChkZl9sb25nLCBhZXMoeCA9IHZhbHVlLCBmaWxsID0gZ3JvdXApKSArDQogIGdlb21fZGVuc2l0eShhbHBoYSA9IDAuNiwgcG9zaXRpb24gPSAiaWRlbnRpdHkiKSArICMgQ3VydmFzIHNvYnJlcG9zdGFzDQogICMgTGluaGFzIHZlcnRpY2FpcyBub3MgcG9udG9zIC0xIGUgKzENCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gYygtMSwgMSksIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IDAuOCwgYWxwaGEgPSAwLjcsIHNob3cubGVnZW5kID0gRkFMU0UpICsgIyBMaW5oYXMgZW0gLTEgZSArMQ0KICBmYWNldF93cmFwKH4gdmFyaWFibGUsIHNjYWxlcyA9ICJmcmVlIikgKyAgICAgICAgICAjIFVtYSBjdXJ2YSBwYXJhIGNhZGEgdmFyacOhdmVsDQogIGxhYnModGl0bGUgPSAiRGlzdHJpYnV0aW9uIG9mIFZhcmlhYmxlcyBieSBHcm91cCIsDQogICAgICAgc3VidGl0bGUgPSAiU2NvcmUgWiIsDQogICAgICAgeCA9ICJTdGFuZGFyZC1EaXN0cmlidWl0aW9uIiwNCiAgICAgICB5ID0gIlN0YW5kYXJkLURpc3RyaWJ1aXRpb24iLA0KICAgICAgIGZpbGwgPSAiR3JvdXBzIikgKw0KICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDE0KSArDQogIHRoZW1lKA0KICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIGZhY2UgPSAiYm9sZCIpLA0KICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIHNpemUgPSAxMiksDQogICAgbGVnZW5kLnBvc2l0aW9uID0gInRvcCINCiAgKSArDQogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiMxZjc4YjQiLCAiI2UzMWExYyIpKSArICMgQWp1c3RlIGRhcyBjb3JlcyBkb3MgZ3J1cG9zDQogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSBzZXEoLTUsIDUsIGJ5ID0gMSksIGxpbWl0cyA9IGMoLTUsIDUpKSAjIEFqdXN0ZSBkb3MgbWFyY2Fkb3JlcyBkbyBlaXhvIFgNCg0KDQpgYGANCg0KDQoNCg0KIyBUaGUgZW5kDQoNCg0K