Installing libraries and loading data

library(ggplot2)
Warning: package ‘ggplot2’ was built under R version 4.4.3
library(dplyr)
Warning: package ‘dplyr’ was built under R version 4.4.3

Attaching package: ‘dplyr’

The following objects are masked from ‘package:stats’:

    filter, lag

The following objects are masked from ‘package:base’:

    intersect, setdiff, setequal, union
library(tidyr)
Warning: package ‘tidyr’ was built under R version 4.4.3
library(readr)
Warning: package ‘readr’ was built under R version 4.4.3
library(haven)
Warning: package ‘haven’ was built under R version 4.4.3
datapath <- "C:/Users/jerek/Documents/My Library/OPETUS/Kultut_Ope/_Tutkimus & kirjoitus/legitrel/OHJELMAT 2023/Pol-o_multinom_R/SS_Ref2/ohjelmat_SS_R2.sav"
data <- read_sav(datapath)

Visualizing Predicted Probabilities

data_long <- data %>%
  pivot_longer(cols = starts_with("EST"), 
               names_to = "category", 
               values_to = "probability")

# Get variable labels from SPSS attributes
labels <- sapply(data[ , startsWith(names(data), "EST")], function(x) attr(x, "label"))

# Add variable label column
data_long <- data_long %>%
  mutate(variable_label = labels[as.character(category)])

# Plot
ggplot(data_long, aes(x = Zgaltan_y, y = probability, color = variable_label)) +
  geom_smooth(se = FALSE, method = "loess", span = 0.8) +
  theme_minimal() +
  labs(
    x = "GAL–TAN Scale (Standardized)", 
    y = "Predicted Probability", 
    color = "Legitimation Frame",
    title = "Predicted Probabilities by GAL–TAN Position"
  )
`geom_smooth()` using formula = 'y ~ x'

Moving forward: including all varibles in the model

Recalculating new variable for plotting

data$lr_combined = (data$lrgen_y + data$lrecon_y) / 2

Definitions

library(ggplot2)
library(dplyr)
library(tidyr)
library(patchwork)
Warning: package ‘patchwork’ was built under R version 4.4.3
# OLD
#predictors <- c("Zp_age", "Zgaltan_y", "Zseat_y", "Zlr_combined", 
#                "Zp_age_x_Zgaltan_y", "Zp_age_x_Zseat_y", "Zgaltan_y_x_Zseat_y")

#var_labels <- c(
#  "Zp_age" = "Party Age (Z-score)",
#  "Zgaltan_y" = "GAL-TAN (Z-score)",
#  "Zseat_y" = "Share of Seats (Z-score)",
#  "Zlr_combined" = "Left-Right (combined, Z-sc.)",
#  "Zp_age_x_Zgaltan_y" = "Party Age x GAL-TAN (Z-sc.)",
#  "Zp_age_x_Zseat_y" = "Party Age x Share of Seats (Z-sc.)",
#  "Zgaltan_y_x_Zseat_y" = "GAL-TAN x Share of Seats (Z-sc.)"
#  )

# NEW
predictors <- c("p_age", 
                "galtan_y", 
                "seat_y", 
                "lr_combined",
                "Zp_age_x_Zseat_y",
                "Zlr_combined_x_Zp_age",
                "Zgaltan_y_x_Zseat_y",
                "Zlr_combined_x_Zgaltan_y")

var_labels <- c("p_age" = "Party Age (years)", 
                "galtan_y" = "GAL-TAN", 
                "seat_y" = "Share of Seats (%)", 
                "lr_combined" = "Left-Right (combined)",
                "Zp_age_x_Zseat_y" = "Party Age x Share of Seats (Z-sc.)",
                "Zlr_combined_x_Zp_age" = "Left-Right (comb.) x Party Age (Z-sc.)",
                "Zgaltan_y_x_Zseat_y" = "GAL-TAN x Share of Seats (Z-sc.)",
                "Zlr_combined_x_Zgaltan_y" = "Left-Right (comb.) x GAL-TAN (Z-sc.)")

Pivoting and mutating dataset

# Assuming predicted probability columns start with "EST"
data_long <- data %>%
  pivot_longer(cols = starts_with("EST"), 
               names_to = "category", 
               values_to = "probability")

# Get variable labels from SPSS attributes
labels <- sapply(data[ , startsWith(names(data), "EST")], function(x) attr(x, "label"))

# Attach human-readable category labels
data_long <- data_long %>%
  mutate(variable_label = labels[as.character(category)])

Building the plot, including interactions

# Find global y-axis range
ymin <- min(data_long$probability, na.rm = TRUE)
ymax <- max(data_long$probability, na.rm = TRUE)

# Create an empty list to store plots
plot_list <- list()

# Loop through predictors
for (pred in predictors) {
  # If interaction term, create it on the fly
  if (grepl("_x_", pred)) {
    parts <- unlist(strsplit(pred, "_x_"))
    data_long[[pred]] <- data_long[[parts[1]]] * data_long[[parts[2]]]
  }

  # Create the plot
  p <- ggplot(data_long, aes_string(x = pred, y = "probability", color = "variable_label")) +
    geom_smooth(se = FALSE, method = "loess", span = 0.8) +
    theme_minimal(base_size = 20) +
    coord_cartesian(ylim = c(ymin, ymax)) +
    labs(
      x = var_labels[pred],
      y = "Predicted Probability",
      color = "Legitimation Frame"
    )

  # Add plot to list
  plot_list[[pred]] <- p
}
Warning: `aes_string()` was deprecated in ggplot2 3.0.0.
ℹ Please use tidy evaluation idioms with `aes()`.
ℹ See also `vignette("ggplot2-in-packages")` for more information.
This warning is displayed once every 8 hours.
Call `lifecycle::last_lifecycle_warnings()` to see where this warning was generated.

Displaying the plot

library(patchwork)

#heights_vector <- c(4,4,4,4,4,4,4)  # Adjust as needed



combined_plot <- wrap_plots(plot_list, ncol = 3,  guides = "collect") &
  theme(
    legend.position = "right",
    legend.box.margin = margin(t = 10, l=2, r = 2),
    legend.key.spacing = unit(0.2, "lines"),
    legend.title = element_text(size = 8),
    legend.text = element_text(size = 6),
    
    plot.margin = margin(t=27,r=1,l=5,b=5),
    plot.title = element_text(size = 10, face = "bold"),
    axis.title = element_text(size = 6),
    axis.text = element_text(size = 6)
  ) & coord_cartesian(ylim = c(0,.8))
Coordinate system already present. Adding new coordinate system, which will replace the existing one.
Coordinate system already present. Adding new coordinate system, which will replace the existing one.
Coordinate system already present. Adding new coordinate system, which will replace the existing one.
Coordinate system already present. Adding new coordinate system, which will replace the existing one.
Coordinate system already present. Adding new coordinate system, which will replace the existing one.
Coordinate system already present. Adding new coordinate system, which will replace the existing one.
Coordinate system already present. Adding new coordinate system, which will replace the existing one.
Coordinate system already present. Adding new coordinate system, which will replace the existing one.
combined_plot <- combined_plot +
  plot_annotation(title = "Predicted Probabilities by Explanatory Variable",
                  theme = theme(plot.title = element_text(hjust = 0.5)))

# Show plot
combined_plot
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'

Saving plot

ggsave(combined_plot, 
       filename = "C:/Users/jerek/Documents/My Library/OPETUS/Kultut_Ope/_Tutkimus & kirjoitus/legitrel/OHJELMAT 2023/Pol-o_multinom_R/SS_Ref2/combined_plot_new2.tiff",
       device = "tiff",
       height = 6, 
       width = 8, 
       units = "in")
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'

Highlighting significant covariates

library(tibble)
library(dplyr)
library(ggplot2)
library(patchwork)
library(colorspace) # for lighten()

# Manual significance mapping
sig_map <- tribble(
  ~variable_label,                      ~predictor,
  "Equality", "p_age", 
  "Equality", "galtan_y", 
  "Equality", "seat_y", 
  "Equality", "lr_combined",
  "Equality", "Zp_age_x_Zseat_y",
  "Equality", "Zlr_combined_x_Zp_age",
  "Equality", "Zgaltan_y_x_Zseat_y",
  "Equality", "Zlr_combined_x_Zgaltan_y",
  "Denying special status", "galtan_y",
  "Denying special status", "Zlr_combined_x_Zp_age",
  "Denying special status", "Zgaltan_y_x_Zseat_y",
  "Protecting special status", "galtan_y",
  "Protecting special status", "Zgaltan_y_x_Zseat_y",
  "Public utility", "galtan_y",
  "Public utility", "lr_combined",
  "Public utility", "Zgaltan_y_x_Zseat_y",
  "Public utility", "Zlr_combined_x_Zgaltan_y",
  "Threats and governance", "galtan_y",
  "Threats and governance", "seat_y",
  "Threats and governance", "Zp_age_x_Zseat_y",
  "Values and culture", "lr_combined",
  "Values and culture", "p_age_y",
  "Values and culture", "Zlr_combined_x_Zp_age"
)

# Pick a base color palette for frames
frame_colors <- RColorBrewer::brewer.pal(n = length(unique(data_long$variable_label)), "Set2")
names(frame_colors) <- unique(data_long$variable_label)

# Find y-axis range
ymin <- min(data_long$probability, na.rm = TRUE)
ymax <- max(data_long$probability, na.rm = TRUE)

plot_list <- list()

for (pred in predictors) {
  
  # Create interaction variable if needed
  if (grepl("_x_", pred)) {
    parts <- unlist(strsplit(pred, "_x_"))
    data_long[[pred]] <- data_long[[parts[1]]] * data_long[[parts[2]]]
  }
  
  df_plot <- data_long %>%
    mutate(
      significance = ifelse(
        variable_label %in% (sig_map %>% filter(predictor == pred) %>% pull(variable_label)),
        "significant", "nonsignificant"
      )
    )
  
  p <- ggplot() +
    
    # Significant lines — solid original color
    geom_smooth(
      data = subset(df_plot, significance == "significant"),
      aes_string(x = pred, y = "probability", color = "variable_label", group = "variable_label"),
      se = FALSE, method = "loess", span = 0.8, size = 1
    ) +
    
    # Non-significant lines — lighter shade of the same color + dashed
    geom_smooth(
      data = subset(df_plot, significance == "nonsignificant"),
      aes_string(x = pred, y = "probability", group = "variable_label", color = "variable_label"),
      se = FALSE, method = "loess", span = 0.8, size = 0.8, linetype = "dashed",
      show.legend = FALSE
    ) +
    
    scale_color_manual(values = frame_colors) +
    
    theme_minimal(base_size = 20) +
    coord_cartesian(ylim = c(ymin, ymax)) +
    labs(
      x = var_labels[pred],
      y = "Predicted Probability",
      color = "Legitimation Frame"
    ) +
    guides(color = guide_legend(override.aes = list(linetype = "solid", size = 1)))
  
  # Lighten the non-significant lines after plotting
  p <- p +
    scale_color_manual(
      values = setNames(
        frame_colors,
        names(frame_colors)
      ),
      guide = guide_legend(override.aes = list(linetype = "solid", size = 1))
    ) +
    theme(legend.position = "right")
  
  plot_list[[pred]] <- p
}
Scale for colour is already present.
Adding another scale for colour, which will replace the existing scale.
Scale for colour is already present.
Adding another scale for colour, which will replace the existing scale.
Scale for colour is already present.
Adding another scale for colour, which will replace the existing scale.
Scale for colour is already present.
Adding another scale for colour, which will replace the existing scale.
Scale for colour is already present.
Adding another scale for colour, which will replace the existing scale.
Scale for colour is already present.
Adding another scale for colour, which will replace the existing scale.
Scale for colour is already present.
Adding another scale for colour, which will replace the existing scale.
Scale for colour is already present.
Adding another scale for colour, which will replace the existing scale.
# Combine all predictor plots
combined_plot <- wrap_plots(plot_list, ncol = 3, guides = "collect") &
  theme(
    legend.position = "right",
    legend.box.margin = margin(t = 10, l = 2, r = 2),
    legend.key.spacing = unit(0.2, "lines"),
    legend.title = element_text(size = 8),
    legend.text = element_text(size = 6),
    plot.margin = margin(t = 27, r = 1, l = 5, b = 5),
    plot.title = element_text(size = 10, face = "bold"),
    axis.title = element_text(size = 6),
    axis.text = element_text(size = 6)
  ) & coord_cartesian(ylim = c(0, .8))
Coordinate system already present. Adding new coordinate system, which will replace the existing one.
Coordinate system already present. Adding new coordinate system, which will replace the existing one.
Coordinate system already present. Adding new coordinate system, which will replace the existing one.
Coordinate system already present. Adding new coordinate system, which will replace the existing one.
Coordinate system already present. Adding new coordinate system, which will replace the existing one.
Coordinate system already present. Adding new coordinate system, which will replace the existing one.
Coordinate system already present. Adding new coordinate system, which will replace the existing one.
Coordinate system already present. Adding new coordinate system, which will replace the existing one.
combined_plot <- combined_plot +
  plot_annotation(title = "Predicted Probabilities by Predictor (Solid = Reference or Significant, Dashed = Not Significant)",
                  theme = theme(plot.title = element_text(hjust = 0.5)))

combined_plot
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'

ggsave(combined_plot, 
       filename = "C:/Users/jerek/Documents/My Library/OPETUS/Kultut_Ope/_Tutkimus & kirjoitus/legitrel/OHJELMAT 2023/Pol-o_multinom_R/SS_Ref2/pred_prob_legend.tiff",
       device = "tiff",
       height = 6, 
       width = 8, 
       units = "in")
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
`geom_smooth()` using formula = 'y ~ x'
LS0tDQp0aXRsZTogIlZpc3VhbGl6aW5nIFByZWRpY3RlZCBwcm9iYWJpbGl0aWVzIg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KIyBJbnN0YWxsaW5nIGxpYnJhcmllcyBhbmQgbG9hZGluZyBkYXRhDQoNCmBgYHtyfQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkodGlkeXIpDQpsaWJyYXJ5KHJlYWRyKQ0KbGlicmFyeShoYXZlbikNCg0KYGBgDQpgYGB7cn0NCmRhdGFwYXRoIDwtICJDOi9maWxlMi5zYXYiDQpkYXRhIDwtIHJlYWRfc2F2KGRhdGFwYXRoKQ0KDQpgYGANCiMgVmlzdWFsaXppbmcgUHJlZGljdGVkIFByb2JhYmlsaXRpZXMNCg0KYGBge3J9DQpkYXRhX2xvbmcgPC0gZGF0YSAlPiUNCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBzdGFydHNfd2l0aCgiRVNUIiksIA0KICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAiY2F0ZWdvcnkiLCANCiAgICAgICAgICAgICAgIHZhbHVlc190byA9ICJwcm9iYWJpbGl0eSIpDQoNCiMgR2V0IHZhcmlhYmxlIGxhYmVscyBmcm9tIFNQU1MgYXR0cmlidXRlcw0KbGFiZWxzIDwtIHNhcHBseShkYXRhWyAsIHN0YXJ0c1dpdGgobmFtZXMoZGF0YSksICJFU1QiKV0sIGZ1bmN0aW9uKHgpIGF0dHIoeCwgImxhYmVsIikpDQoNCiMgQWRkIHZhcmlhYmxlIGxhYmVsIGNvbHVtbg0KZGF0YV9sb25nIDwtIGRhdGFfbG9uZyAlPiUNCiAgbXV0YXRlKHZhcmlhYmxlX2xhYmVsID0gbGFiZWxzW2FzLmNoYXJhY3RlcihjYXRlZ29yeSldKQ0KDQojIFBsb3QNCmdncGxvdChkYXRhX2xvbmcsIGFlcyh4ID0gWmdhbHRhbl95LCB5ID0gcHJvYmFiaWxpdHksIGNvbG9yID0gdmFyaWFibGVfbGFiZWwpKSArDQogIGdlb21fc21vb3RoKHNlID0gRkFMU0UsIG1ldGhvZCA9ICJsb2VzcyIsIHNwYW4gPSAwLjgpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgbGFicygNCiAgICB4ID0gIkdBTOKAk1RBTiBTY2FsZSAoU3RhbmRhcmRpemVkKSIsIA0KICAgIHkgPSAiUHJlZGljdGVkIFByb2JhYmlsaXR5IiwgDQogICAgY29sb3IgPSAiTGVnaXRpbWF0aW9uIEZyYW1lIiwNCiAgICB0aXRsZSA9ICJQcmVkaWN0ZWQgUHJvYmFiaWxpdGllcyBieSBHQUzigJNUQU4gUG9zaXRpb24iDQogICkNCmBgYA0KDQojIE1vdmluZyBmb3J3YXJkOiBpbmNsdWRpbmcgYWxsIHZhcmlibGVzIGluIHRoZSBtb2RlbA0KDQojIyBSZWNhbGN1bGF0aW5nIG5ldyB2YXJpYWJsZSBmb3IgcGxvdHRpbmcNCg0KYGBge3J9DQpkYXRhJGxyX2NvbWJpbmVkID0gKGRhdGEkbHJnZW5feSArIGRhdGEkbHJlY29uX3kpIC8gMg0KYGBgDQoNCg0KIyMgRGVmaW5pdGlvbnMNCg0KYGBge3J9DQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeSh0aWR5cikNCmxpYnJhcnkocGF0Y2h3b3JrKQ0KDQojIE9MRA0KI3ByZWRpY3RvcnMgPC0gYygiWnBfYWdlIiwgIlpnYWx0YW5feSIsICJac2VhdF95IiwgIlpscl9jb21iaW5lZCIsIA0KIyAgICAgICAgICAgICAgICAiWnBfYWdlX3hfWmdhbHRhbl95IiwgIlpwX2FnZV94X1pzZWF0X3kiLCAiWmdhbHRhbl95X3hfWnNlYXRfeSIpDQoNCiN2YXJfbGFiZWxzIDwtIGMoDQojICAiWnBfYWdlIiA9ICJQYXJ0eSBBZ2UgKFotc2NvcmUpIiwNCiMgICJaZ2FsdGFuX3kiID0gIkdBTC1UQU4gKFotc2NvcmUpIiwNCiMgICJac2VhdF95IiA9ICJTaGFyZSBvZiBTZWF0cyAoWi1zY29yZSkiLA0KIyAgIlpscl9jb21iaW5lZCIgPSAiTGVmdC1SaWdodCAoY29tYmluZWQsIFotc2MuKSIsDQojICAiWnBfYWdlX3hfWmdhbHRhbl95IiA9ICJQYXJ0eSBBZ2UgeCBHQUwtVEFOIChaLXNjLikiLA0KIyAgIlpwX2FnZV94X1pzZWF0X3kiID0gIlBhcnR5IEFnZSB4IFNoYXJlIG9mIFNlYXRzIChaLXNjLikiLA0KIyAgIlpnYWx0YW5feV94X1pzZWF0X3kiID0gIkdBTC1UQU4geCBTaGFyZSBvZiBTZWF0cyAoWi1zYy4pIg0KIyAgKQ0KDQojIE5FVw0KcHJlZGljdG9ycyA8LSBjKCJwX2FnZSIsIA0KICAgICAgICAgICAgICAgICJnYWx0YW5feSIsIA0KICAgICAgICAgICAgICAgICJzZWF0X3kiLCANCiAgICAgICAgICAgICAgICAibHJfY29tYmluZWQiLA0KICAgICAgICAgICAgICAgICJacF9hZ2VfeF9ac2VhdF95IiwNCiAgICAgICAgICAgICAgICAiWmxyX2NvbWJpbmVkX3hfWnBfYWdlIiwNCiAgICAgICAgICAgICAgICAiWmdhbHRhbl95X3hfWnNlYXRfeSIsDQogICAgICAgICAgICAgICAgIlpscl9jb21iaW5lZF94X1pnYWx0YW5feSIpDQoNCnZhcl9sYWJlbHMgPC0gYygicF9hZ2UiID0gIlBhcnR5IEFnZSAoeWVhcnMpIiwgDQogICAgICAgICAgICAgICAgImdhbHRhbl95IiA9ICJHQUwtVEFOIiwgDQogICAgICAgICAgICAgICAgInNlYXRfeSIgPSAiU2hhcmUgb2YgU2VhdHMgKCUpIiwgDQogICAgICAgICAgICAgICAgImxyX2NvbWJpbmVkIiA9ICJMZWZ0LVJpZ2h0IChjb21iaW5lZCkiLA0KICAgICAgICAgICAgICAgICJacF9hZ2VfeF9ac2VhdF95IiA9ICJQYXJ0eSBBZ2UgeCBTaGFyZSBvZiBTZWF0cyAoWi1zYy4pIiwNCiAgICAgICAgICAgICAgICAiWmxyX2NvbWJpbmVkX3hfWnBfYWdlIiA9ICJMZWZ0LVJpZ2h0IChjb21iLikgeCBQYXJ0eSBBZ2UgKFotc2MuKSIsDQogICAgICAgICAgICAgICAgIlpnYWx0YW5feV94X1pzZWF0X3kiID0gIkdBTC1UQU4geCBTaGFyZSBvZiBTZWF0cyAoWi1zYy4pIiwNCiAgICAgICAgICAgICAgICAiWmxyX2NvbWJpbmVkX3hfWmdhbHRhbl95IiA9ICJMZWZ0LVJpZ2h0IChjb21iLikgeCBHQUwtVEFOIChaLXNjLikiKQ0KDQpgYGANCiMjIFBpdm90aW5nIGFuZCBtdXRhdGluZyBkYXRhc2V0DQoNCmBgYHtyfQ0KIyBBc3N1bWluZyBwcmVkaWN0ZWQgcHJvYmFiaWxpdHkgY29sdW1ucyBzdGFydCB3aXRoICJFU1QiDQpkYXRhX2xvbmcgPC0gZGF0YSAlPiUNCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSBzdGFydHNfd2l0aCgiRVNUIiksIA0KICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAiY2F0ZWdvcnkiLCANCiAgICAgICAgICAgICAgIHZhbHVlc190byA9ICJwcm9iYWJpbGl0eSIpDQoNCiMgR2V0IHZhcmlhYmxlIGxhYmVscyBmcm9tIFNQU1MgYXR0cmlidXRlcw0KbGFiZWxzIDwtIHNhcHBseShkYXRhWyAsIHN0YXJ0c1dpdGgobmFtZXMoZGF0YSksICJFU1QiKV0sIGZ1bmN0aW9uKHgpIGF0dHIoeCwgImxhYmVsIikpDQoNCiMgQXR0YWNoIGh1bWFuLXJlYWRhYmxlIGNhdGVnb3J5IGxhYmVscw0KZGF0YV9sb25nIDwtIGRhdGFfbG9uZyAlPiUNCiAgbXV0YXRlKHZhcmlhYmxlX2xhYmVsID0gbGFiZWxzW2FzLmNoYXJhY3RlcihjYXRlZ29yeSldKQ0KYGBgDQoNCiMjIEJ1aWxkaW5nIHRoZSBwbG90LCBpbmNsdWRpbmcgaW50ZXJhY3Rpb25zDQoNCmBgYHtyfQ0KIyBGaW5kIGdsb2JhbCB5LWF4aXMgcmFuZ2UNCnltaW4gPC0gbWluKGRhdGFfbG9uZyRwcm9iYWJpbGl0eSwgbmEucm0gPSBUUlVFKQ0KeW1heCA8LSBtYXgoZGF0YV9sb25nJHByb2JhYmlsaXR5LCBuYS5ybSA9IFRSVUUpDQoNCiMgQ3JlYXRlIGFuIGVtcHR5IGxpc3QgdG8gc3RvcmUgcGxvdHMNCnBsb3RfbGlzdCA8LSBsaXN0KCkNCg0KIyBMb29wIHRocm91Z2ggcHJlZGljdG9ycw0KZm9yIChwcmVkIGluIHByZWRpY3RvcnMpIHsNCiAgIyBJZiBpbnRlcmFjdGlvbiB0ZXJtLCBjcmVhdGUgaXQgb24gdGhlIGZseQ0KICBpZiAoZ3JlcGwoIl94XyIsIHByZWQpKSB7DQogICAgcGFydHMgPC0gdW5saXN0KHN0cnNwbGl0KHByZWQsICJfeF8iKSkNCiAgICBkYXRhX2xvbmdbW3ByZWRdXSA8LSBkYXRhX2xvbmdbW3BhcnRzWzFdXV0gKiBkYXRhX2xvbmdbW3BhcnRzWzJdXV0NCiAgfQ0KDQogICMgQ3JlYXRlIHRoZSBwbG90DQogIHAgPC0gZ2dwbG90KGRhdGFfbG9uZywgYWVzX3N0cmluZyh4ID0gcHJlZCwgeSA9ICJwcm9iYWJpbGl0eSIsIGNvbG9yID0gInZhcmlhYmxlX2xhYmVsIikpICsNCiAgICBnZW9tX3Ntb290aChzZSA9IEZBTFNFLCBtZXRob2QgPSAibG9lc3MiLCBzcGFuID0gMC44KSArDQogICAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAyMCkgKw0KICAgIGNvb3JkX2NhcnRlc2lhbih5bGltID0gYyh5bWluLCB5bWF4KSkgKw0KICAgIGxhYnMoDQogICAgICB4ID0gdmFyX2xhYmVsc1twcmVkXSwNCiAgICAgIHkgPSAiUHJlZGljdGVkIFByb2JhYmlsaXR5IiwNCiAgICAgIGNvbG9yID0gIkxlZ2l0aW1hdGlvbiBGcmFtZSINCiAgICApDQoNCiAgIyBBZGQgcGxvdCB0byBsaXN0DQogIHBsb3RfbGlzdFtbcHJlZF1dIDwtIHANCn0NCmBgYA0KDQoNCg0KIyBEaXNwbGF5aW5nIHRoZSBwbG90DQpsaWJyYXJ5KHBhdGNod29yaykNCg0KYGBge3J9DQojaGVpZ2h0c192ZWN0b3IgPC0gYyg0LDQsNCw0LDQsNCw0KSAgIyBBZGp1c3QgYXMgbmVlZGVkDQoNCg0KDQpjb21iaW5lZF9wbG90IDwtIHdyYXBfcGxvdHMocGxvdF9saXN0LCBuY29sID0gMywgIGd1aWRlcyA9ICJjb2xsZWN0IikgJg0KICB0aGVtZSgNCiAgICBsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiLA0KICAgIGxlZ2VuZC5ib3gubWFyZ2luID0gbWFyZ2luKHQgPSAxMCwgbD0yLCByID0gMiksDQogICAgbGVnZW5kLmtleS5zcGFjaW5nID0gdW5pdCgwLjIsICJsaW5lcyIpLA0KICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gOCksDQogICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYpLA0KICAgIA0KICAgIHBsb3QubWFyZ2luID0gbWFyZ2luKHQ9Mjcscj0xLGw9NSxiPTUpLA0KICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwLCBmYWNlID0gImJvbGQiKSwNCiAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA2KSwNCiAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYpDQogICkgJiBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoMCwuOCkpDQoNCmNvbWJpbmVkX3Bsb3QgPC0gY29tYmluZWRfcGxvdCArDQogIHBsb3RfYW5ub3RhdGlvbih0aXRsZSA9ICJQcmVkaWN0ZWQgUHJvYmFiaWxpdGllcyBieSBFeHBsYW5hdG9yeSBWYXJpYWJsZSIsDQogICAgICAgICAgICAgICAgICB0aGVtZSA9IHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKSkNCg0KIyBTaG93IHBsb3QNCmNvbWJpbmVkX3Bsb3QNCmBgYA0KIyMgU2F2aW5nIHBsb3QNCg0KYGBge3J9DQpnZ3NhdmUoY29tYmluZWRfcGxvdCwgDQogICAgICAgZmlsZW5hbWUgPSAiQzovVXNlcnMvamVyZWsvRG9jdW1lbnRzL015IExpYnJhcnkvT1BFVFVTL0t1bHR1dF9PcGUvX1R1dGtpbXVzICYga2lyam9pdHVzL2xlZ2l0cmVsL09ISkVMTUFUIDIwMjMvUG9sLW9fbXVsdGlub21fUi9TU19SZWYyL2NvbWJpbmVkX3Bsb3RfbmV3Mi50aWZmIiwNCiAgICAgICBkZXZpY2UgPSAidGlmZiIsDQogICAgICAgaGVpZ2h0ID0gNiwgDQogICAgICAgd2lkdGggPSA4LCANCiAgICAgICB1bml0cyA9ICJpbiIpDQoNCg0KYGBgDQoNCiMjIEhpZ2hsaWdodGluZyBzaWduaWZpY2FudCBjb3ZhcmlhdGVzDQoNCg0KDQpgYGB7cn0NCmxpYnJhcnkodGliYmxlKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkocGF0Y2h3b3JrKQ0KbGlicmFyeShjb2xvcnNwYWNlKSAjIGZvciBsaWdodGVuKCkNCg0KIyBNYW51YWwgc2lnbmlmaWNhbmNlIG1hcHBpbmcNCnNpZ19tYXAgPC0gdHJpYmJsZSgNCiAgfnZhcmlhYmxlX2xhYmVsLCAgICAgICAgICAgICAgICAgICAgICB+cHJlZGljdG9yLA0KICAiRXF1YWxpdHkiLCAicF9hZ2UiLCANCiAgIkVxdWFsaXR5IiwgImdhbHRhbl95IiwgDQogICJFcXVhbGl0eSIsICJzZWF0X3kiLCANCiAgIkVxdWFsaXR5IiwgImxyX2NvbWJpbmVkIiwNCiAgIkVxdWFsaXR5IiwgIlpwX2FnZV94X1pzZWF0X3kiLA0KICAiRXF1YWxpdHkiLCAiWmxyX2NvbWJpbmVkX3hfWnBfYWdlIiwNCiAgIkVxdWFsaXR5IiwgIlpnYWx0YW5feV94X1pzZWF0X3kiLA0KICAiRXF1YWxpdHkiLCAiWmxyX2NvbWJpbmVkX3hfWmdhbHRhbl95IiwNCiAgIkRlbnlpbmcgc3BlY2lhbCBzdGF0dXMiLCAiZ2FsdGFuX3kiLA0KICAiRGVueWluZyBzcGVjaWFsIHN0YXR1cyIsICJabHJfY29tYmluZWRfeF9acF9hZ2UiLA0KICAiRGVueWluZyBzcGVjaWFsIHN0YXR1cyIsICJaZ2FsdGFuX3lfeF9ac2VhdF95IiwNCiAgIlByb3RlY3Rpbmcgc3BlY2lhbCBzdGF0dXMiLCAiZ2FsdGFuX3kiLA0KICAiUHJvdGVjdGluZyBzcGVjaWFsIHN0YXR1cyIsICJaZ2FsdGFuX3lfeF9ac2VhdF95IiwNCiAgIlB1YmxpYyB1dGlsaXR5IiwgImdhbHRhbl95IiwNCiAgIlB1YmxpYyB1dGlsaXR5IiwgImxyX2NvbWJpbmVkIiwNCiAgIlB1YmxpYyB1dGlsaXR5IiwgIlpnYWx0YW5feV94X1pzZWF0X3kiLA0KICAiUHVibGljIHV0aWxpdHkiLCAiWmxyX2NvbWJpbmVkX3hfWmdhbHRhbl95IiwNCiAgIlRocmVhdHMgYW5kIGdvdmVybmFuY2UiLCAiZ2FsdGFuX3kiLA0KICAiVGhyZWF0cyBhbmQgZ292ZXJuYW5jZSIsICJzZWF0X3kiLA0KICAiVGhyZWF0cyBhbmQgZ292ZXJuYW5jZSIsICJacF9hZ2VfeF9ac2VhdF95IiwNCiAgIlZhbHVlcyBhbmQgY3VsdHVyZSIsICJscl9jb21iaW5lZCIsDQogICJWYWx1ZXMgYW5kIGN1bHR1cmUiLCAicF9hZ2VfeSIsDQogICJWYWx1ZXMgYW5kIGN1bHR1cmUiLCAiWmxyX2NvbWJpbmVkX3hfWnBfYWdlIg0KKQ0KDQojIFBpY2sgYSBiYXNlIGNvbG9yIHBhbGV0dGUgZm9yIGZyYW1lcw0KZnJhbWVfY29sb3JzIDwtIFJDb2xvckJyZXdlcjo6YnJld2VyLnBhbChuID0gbGVuZ3RoKHVuaXF1ZShkYXRhX2xvbmckdmFyaWFibGVfbGFiZWwpKSwgIlNldDIiKQ0KbmFtZXMoZnJhbWVfY29sb3JzKSA8LSB1bmlxdWUoZGF0YV9sb25nJHZhcmlhYmxlX2xhYmVsKQ0KDQojIEZpbmQgeS1heGlzIHJhbmdlDQp5bWluIDwtIG1pbihkYXRhX2xvbmckcHJvYmFiaWxpdHksIG5hLnJtID0gVFJVRSkNCnltYXggPC0gbWF4KGRhdGFfbG9uZyRwcm9iYWJpbGl0eSwgbmEucm0gPSBUUlVFKQ0KDQpwbG90X2xpc3QgPC0gbGlzdCgpDQoNCmZvciAocHJlZCBpbiBwcmVkaWN0b3JzKSB7DQogIA0KICAjIENyZWF0ZSBpbnRlcmFjdGlvbiB2YXJpYWJsZSBpZiBuZWVkZWQNCiAgaWYgKGdyZXBsKCJfeF8iLCBwcmVkKSkgew0KICAgIHBhcnRzIDwtIHVubGlzdChzdHJzcGxpdChwcmVkLCAiX3hfIikpDQogICAgZGF0YV9sb25nW1twcmVkXV0gPC0gZGF0YV9sb25nW1twYXJ0c1sxXV1dICogZGF0YV9sb25nW1twYXJ0c1syXV1dDQogIH0NCiAgDQogIGRmX3Bsb3QgPC0gZGF0YV9sb25nICU+JQ0KICAgIG11dGF0ZSgNCiAgICAgIHNpZ25pZmljYW5jZSA9IGlmZWxzZSgNCiAgICAgICAgdmFyaWFibGVfbGFiZWwgJWluJSAoc2lnX21hcCAlPiUgZmlsdGVyKHByZWRpY3RvciA9PSBwcmVkKSAlPiUgcHVsbCh2YXJpYWJsZV9sYWJlbCkpLA0KICAgICAgICAic2lnbmlmaWNhbnQiLCAibm9uc2lnbmlmaWNhbnQiDQogICAgICApDQogICAgKQ0KICANCiAgcCA8LSBnZ3Bsb3QoKSArDQogICAgDQogICAgIyBTaWduaWZpY2FudCBsaW5lcyDigJQgc29saWQgb3JpZ2luYWwgY29sb3INCiAgICBnZW9tX3Ntb290aCgNCiAgICAgIGRhdGEgPSBzdWJzZXQoZGZfcGxvdCwgc2lnbmlmaWNhbmNlID09ICJzaWduaWZpY2FudCIpLA0KICAgICAgYWVzX3N0cmluZyh4ID0gcHJlZCwgeSA9ICJwcm9iYWJpbGl0eSIsIGNvbG9yID0gInZhcmlhYmxlX2xhYmVsIiwgZ3JvdXAgPSAidmFyaWFibGVfbGFiZWwiKSwNCiAgICAgIHNlID0gRkFMU0UsIG1ldGhvZCA9ICJsb2VzcyIsIHNwYW4gPSAwLjgsIHNpemUgPSAxDQogICAgKSArDQogICAgDQogICAgIyBOb24tc2lnbmlmaWNhbnQgbGluZXMg4oCUIGxpZ2h0ZXIgc2hhZGUgb2YgdGhlIHNhbWUgY29sb3IgKyBkYXNoZWQNCiAgICBnZW9tX3Ntb290aCgNCiAgICAgIGRhdGEgPSBzdWJzZXQoZGZfcGxvdCwgc2lnbmlmaWNhbmNlID09ICJub25zaWduaWZpY2FudCIpLA0KICAgICAgYWVzX3N0cmluZyh4ID0gcHJlZCwgeSA9ICJwcm9iYWJpbGl0eSIsIGdyb3VwID0gInZhcmlhYmxlX2xhYmVsIiwgY29sb3IgPSAidmFyaWFibGVfbGFiZWwiKSwNCiAgICAgIHNlID0gRkFMU0UsIG1ldGhvZCA9ICJsb2VzcyIsIHNwYW4gPSAwLjgsIHNpemUgPSAwLjgsIGxpbmV0eXBlID0gImRhc2hlZCIsDQogICAgICBzaG93LmxlZ2VuZCA9IEZBTFNFDQogICAgKSArDQogICAgDQogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGZyYW1lX2NvbG9ycykgKw0KICAgIA0KICAgIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMjApICsNCiAgICBjb29yZF9jYXJ0ZXNpYW4oeWxpbSA9IGMoeW1pbiwgeW1heCkpICsNCiAgICBsYWJzKA0KICAgICAgeCA9IHZhcl9sYWJlbHNbcHJlZF0sDQogICAgICB5ID0gIlByZWRpY3RlZCBQcm9iYWJpbGl0eSIsDQogICAgICBjb2xvciA9ICJMZWdpdGltYXRpb24gRnJhbWUiDQogICAgKSArDQogICAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3QobGluZXR5cGUgPSAic29saWQiLCBzaXplID0gMSkpKQ0KICANCiAgIyBMaWdodGVuIHRoZSBub24tc2lnbmlmaWNhbnQgbGluZXMgYWZ0ZXIgcGxvdHRpbmcNCiAgcCA8LSBwICsNCiAgICBzY2FsZV9jb2xvcl9tYW51YWwoDQogICAgICB2YWx1ZXMgPSBzZXROYW1lcygNCiAgICAgICAgZnJhbWVfY29sb3JzLA0KICAgICAgICBuYW1lcyhmcmFtZV9jb2xvcnMpDQogICAgICApLA0KICAgICAgZ3VpZGUgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChsaW5ldHlwZSA9ICJzb2xpZCIsIHNpemUgPSAxKSkNCiAgICApICsNCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiKQ0KICANCiAgcGxvdF9saXN0W1twcmVkXV0gPC0gcA0KfQ0KDQojIENvbWJpbmUgYWxsIHByZWRpY3RvciBwbG90cw0KY29tYmluZWRfcGxvdCA8LSB3cmFwX3Bsb3RzKHBsb3RfbGlzdCwgbmNvbCA9IDMsIGd1aWRlcyA9ICJjb2xsZWN0IikgJg0KICB0aGVtZSgNCiAgICBsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiLA0KICAgIGxlZ2VuZC5ib3gubWFyZ2luID0gbWFyZ2luKHQgPSAxMCwgbCA9IDIsIHIgPSAyKSwNCiAgICBsZWdlbmQua2V5LnNwYWNpbmcgPSB1bml0KDAuMiwgImxpbmVzIiksDQogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA4KSwNCiAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gNiksDQogICAgcGxvdC5tYXJnaW4gPSBtYXJnaW4odCA9IDI3LCByID0gMSwgbCA9IDUsIGIgPSA1KSwNCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMCwgZmFjZSA9ICJib2xkIiksDQogICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gNiksDQogICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA2KQ0KICApICYgY29vcmRfY2FydGVzaWFuKHlsaW0gPSBjKDAsIC44KSkNCg0KY29tYmluZWRfcGxvdCA8LSBjb21iaW5lZF9wbG90ICsNCiAgcGxvdF9hbm5vdGF0aW9uKHRpdGxlID0gIkZpZ3VyZSAzLiBQcmVkaWN0ZWQgUHJvYmFiaWxpdGllcyBieSBQcmVkaWN0b3IgKFNvbGlkID0gUmVmZXJlbmNlIG9yIFNpZ25pZmljYW50LCBEYXNoZWQgPSBOb3QgU2lnbmlmaWNhbnQpIiwNCiAgICAgICAgICAgICAgICAgIHRoZW1lID0gdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpKQ0KDQpjb21iaW5lZF9wbG90DQpgYGANCg0KYGBge3J9DQpnZ3NhdmUoY29tYmluZWRfcGxvdCwgDQogICAgICAgZmlsZW5hbWUgPSAiQzovUEFUSC9wcmVkX3Byb2JfbGVnZW5kLnRpZmYiLA0KICAgICAgIGRldmljZSA9ICJ0aWZmIiwNCiAgICAgICBoZWlnaHQgPSA2LCANCiAgICAgICB3aWR0aCA9IDgsIA0KICAgICAgIHVuaXRzID0gImluIikNCg0KDQpgYGANCg0KDQo=